ghc (empty) → 8.2.1
raw patch · 527 files changed
+340738/−0 lines, 527 filesdep +Win32dep +arraydep +basesetup-changed
Dependencies added: Win32, array, base, binary, bytestring, containers, deepseq, directory, filepath, ghc-boot, ghc-boot-th, ghci, hoopl, hpc, process, template-haskell, terminfo, time, transformers, unix
Files
- HsVersions.h +69/−0
- LICENSE +31/−0
- Setup.hs +2/−0
- Unique.h +5/−0
- autogen/CodeGen.Platform.hs +1137/−0
- autogen/Config.hs +64/−0
- autogen/GHCConstantsHaskellExports.hs +125/−0
- autogen/GHCConstantsHaskellType.hs +134/−0
- autogen/GHCConstantsHaskellWrappers.hs +250/−0
- autogen/ghc_boot_platform.h +33/−0
- autogen/primop-can-fail.hs-incl +178/−0
- autogen/primop-code-size.hs-incl +48/−0
- autogen/primop-commutable.hs-incl +28/−0
- autogen/primop-data-decl.hs-incl +451/−0
- autogen/primop-fixity.hs-incl +20/−0
- autogen/primop-has-side-effects.hs-incl +211/−0
- autogen/primop-list.hs-incl +1070/−0
- autogen/primop-out-of-line.hs-incl +99/−0
- autogen/primop-primop-info.hs-incl +1069/−0
- autogen/primop-strictness.hs-incl +22/−0
- autogen/primop-tag.hs-incl +1072/−0
- autogen/primop-vector-tycons.hs-incl +30/−0
- autogen/primop-vector-tys-exports.hs-incl +30/−0
- autogen/primop-vector-tys.hs-incl +180/−0
- autogen/primop-vector-uniques.hs-incl +60/−0
- backpack/BkpSyn.hs +83/−0
- backpack/DriverBkp.hs +823/−0
- backpack/NameShape.hs +266/−0
- backpack/RnModIface.hs +707/−0
- basicTypes/Avail.hs +262/−0
- basicTypes/BasicTypes.hs +1511/−0
- basicTypes/ConLike.hs +192/−0
- basicTypes/ConLike.hs-boot +9/−0
- basicTypes/DataCon.hs +1324/−0
- basicTypes/DataCon.hs-boot +32/−0
- basicTypes/Demand.hs +2173/−0
- basicTypes/FieldLabel.hs +128/−0
- basicTypes/Id.hs +946/−0
- basicTypes/IdInfo.hs +622/−0
- basicTypes/IdInfo.hs-boot +10/−0
- basicTypes/Lexeme.hs +238/−0
- basicTypes/Literal.hs +603/−0
- basicTypes/MkId.hs +1570/−0
- basicTypes/MkId.hs-boot +15/−0
- basicTypes/Module.hs +1275/−0
- basicTypes/Module.hs-boot +12/−0
- basicTypes/Name.hs +710/−0
- basicTypes/Name.hs-boot +3/−0
- basicTypes/NameCache.hs +118/−0
- basicTypes/NameEnv.hs +151/−0
- basicTypes/NameSet.hs +212/−0
- basicTypes/OccName.hs +959/−0
- basicTypes/OccName.hs-boot +3/−0
- basicTypes/PatSyn.hs +429/−0
- basicTypes/PatSyn.hs-boot +13/−0
- basicTypes/RdrName.hs +1243/−0
- basicTypes/SrcLoc.hs +587/−0
- basicTypes/UniqSupply.hs +232/−0
- basicTypes/Unique.hs +436/−0
- basicTypes/Var.hs +643/−0
- basicTypes/VarEnv.hs +598/−0
- basicTypes/VarSet.hs +340/−0
- cbits/genSym.c +40/−0
- cmm/Bitmap.hs +136/−0
- cmm/BlockId.hs +51/−0
- cmm/CLabel.hs +1332/−0
- cmm/Cmm.hs +218/−0
- cmm/CmmBuildInfoTables.hs +379/−0
- cmm/CmmCallConv.hs +220/−0
- cmm/CmmCommonBlockElim.hs +302/−0
- cmm/CmmContFlowOpt.hs +415/−0
- cmm/CmmExpr.hs +585/−0
- cmm/CmmImplementSwitchPlans.hs +90/−0
- cmm/CmmInfo.hs +557/−0
- cmm/CmmLayoutStack.hs +1146/−0
- cmm/CmmLex.x +363/−0
- cmm/CmmLint.hs +257/−0
- cmm/CmmLive.hs +88/−0
- cmm/CmmMachOp.hs +619/−0
- cmm/CmmMonad.hs +58/−0
- cmm/CmmNode.hs +700/−0
- cmm/CmmOpt.hs +392/−0
- cmm/CmmParse.y +1419/−0
- cmm/CmmPipeline.hs +365/−0
- cmm/CmmProcPoint.hs +490/−0
- cmm/CmmSink.hs +790/−0
- cmm/CmmSwitch.hs +433/−0
- cmm/CmmType.hs +439/−0
- cmm/CmmUtils.hs +568/−0
- cmm/Debug.hs +459/−0
- cmm/Hoopl.hs +29/−0
- cmm/Hoopl/Dataflow.hs +323/−0
- cmm/MkGraph.hs +415/−0
- cmm/PprC.hs +1313/−0
- cmm/PprCmm.hs +306/−0
- cmm/PprCmmDecl.hs +174/−0
- cmm/PprCmmExpr.hs +279/−0
- cmm/SMRep.hs +574/−0
- codeGen/CgUtils.hs +181/−0
- codeGen/CodeGen/Platform.hs +116/−0
- codeGen/CodeGen/Platform/ARM.hs +8/−0
- codeGen/CodeGen/Platform/ARM64.hs +8/−0
- codeGen/CodeGen/Platform/NoRegs.hs +7/−0
- codeGen/CodeGen/Platform/PPC.hs +8/−0
- codeGen/CodeGen/Platform/PPC_Darwin.hs +9/−0
- codeGen/CodeGen/Platform/SPARC.hs +8/−0
- codeGen/CodeGen/Platform/X86.hs +8/−0
- codeGen/CodeGen/Platform/X86_64.hs +8/−0
- codeGen/StgCmm.hs +284/−0
- codeGen/StgCmmArgRep.hs +152/−0
- codeGen/StgCmmBind.hs +755/−0
- codeGen/StgCmmBind.hs-boot +6/−0
- codeGen/StgCmmClosure.hs +1086/−0
- codeGen/StgCmmCon.hs +279/−0
- codeGen/StgCmmEnv.hs +206/−0
- codeGen/StgCmmExpr.hs +943/−0
- codeGen/StgCmmExtCode.hs +251/−0
- codeGen/StgCmmForeign.hs +553/−0
- codeGen/StgCmmHeap.hs +698/−0
- codeGen/StgCmmHpc.hs +46/−0
- codeGen/StgCmmLayout.hs +552/−0
- codeGen/StgCmmMonad.hs +900/−0
- codeGen/StgCmmPrim.hs +2242/−0
- codeGen/StgCmmProf.hs +366/−0
- codeGen/StgCmmTicky.hs +675/−0
- codeGen/StgCmmUtils.hs +620/−0
- coreSyn/CoreArity.hs +1200/−0
- coreSyn/CoreFVs.hs +825/−0
- coreSyn/CoreLint.hs +2478/−0
- coreSyn/CoreOpt.hs +1176/−0
- coreSyn/CorePrep.hs +1587/−0
- coreSyn/CoreSeq.hs +111/−0
- coreSyn/CoreStats.hs +141/−0
- coreSyn/CoreSubst.hs +762/−0
- coreSyn/CoreSyn.hs +2161/−0
- coreSyn/CoreTidy.hs +287/−0
- coreSyn/CoreUnfold.hs +1492/−0
- coreSyn/CoreUtils.hs +2329/−0
- coreSyn/MkCore.hs +772/−0
- coreSyn/PprCore.hs +622/−0
- coreSyn/TrieMap.hs +1129/−0
- deSugar/Check.hs +1859/−0
- deSugar/Coverage.hs +1354/−0
- deSugar/Desugar.hs +567/−0
- deSugar/DsArrows.hs +1230/−0
- deSugar/DsBinds.hs +1387/−0
- deSugar/DsCCall.hs +377/−0
- deSugar/DsExpr.hs +1066/−0
- deSugar/DsExpr.hs-boot +10/−0
- deSugar/DsForeign.hs +805/−0
- deSugar/DsGRHSs.hs +163/−0
- deSugar/DsListComp.hs +883/−0
- deSugar/DsMeta.hs +2513/−0
- deSugar/DsMonad.hs +733/−0
- deSugar/DsUsage.hs +224/−0
- deSugar/DsUtils.hs +1008/−0
- deSugar/Match.hs +1135/−0
- deSugar/Match.hs-boot +34/−0
- deSugar/MatchCon.hs +287/−0
- deSugar/MatchLit.hs +456/−0
- deSugar/PmExpr.hs +449/−0
- deSugar/TmOracle.hs +257/−0
- ghc.cabal +640/−0
- ghci/ByteCodeAsm.hs +538/−0
- ghci/ByteCodeGen.hs +1798/−0
- ghci/ByteCodeInstr.hs +315/−0
- ghci/ByteCodeItbls.hs +74/−0
- ghci/ByteCodeLink.hs +195/−0
- ghci/ByteCodeTypes.hs +182/−0
- ghci/Debugger.hs +238/−0
- ghci/DebuggerUtils.hs +132/−0
- ghci/GHCi.hsc +677/−0
- ghci/Linker.hs +1475/−0
- ghci/RtClosureInspect.hs +1281/−0
- ghci/keepCAFsForGHCi.c +15/−0
- hsSyn/Convert.hs +1721/−0
- hsSyn/HsBinds.hs +1193/−0
- hsSyn/HsDecls.hs +2104/−0
- hsSyn/HsDoc.hs +30/−0
- hsSyn/HsDumpAst.hs +206/−0
- hsSyn/HsExpr.hs +2556/−0
- hsSyn/HsExpr.hs-boot +57/−0
- hsSyn/HsImpExp.hs +310/−0
- hsSyn/HsLit.hs +216/−0
- hsSyn/HsPat.hs +698/−0
- hsSyn/HsPat.hs-boot +20/−0
- hsSyn/HsSyn.hs +145/−0
- hsSyn/HsTypes.hs +1349/−0
- hsSyn/HsUtils.hs +1251/−0
- hsSyn/PlaceHolder.hs +144/−0
- iface/BinFingerprint.hs +47/−0
- iface/BinIface.hs +390/−0
- iface/BuildTyCl.hs +476/−0
- iface/FlagChecker.hs +98/−0
- iface/IfaceEnv.hs +272/−0
- iface/IfaceEnv.hs-boot +9/−0
- iface/IfaceSyn.hs +2220/−0
- iface/IfaceType.hs +1552/−0
- iface/IfaceType.hs-boot +37/−0
- iface/LoadIface.hs +1184/−0
- iface/LoadIface.hs-boot +7/−0
- iface/MkIface.hs +1815/−0
- iface/TcIface.hs +1875/−0
- iface/TcIface.hs-boot +20/−0
- iface/ToIface.hs +602/−0
- iface/ToIface.hs-boot +17/−0
- llvmGen/Llvm.hs +64/−0
- llvmGen/Llvm/AbsSyn.hs +350/−0
- llvmGen/Llvm/MetaData.hs +93/−0
- llvmGen/Llvm/PpLlvm.hs +497/−0
- llvmGen/Llvm/Types.hs +886/−0
- llvmGen/LlvmCodeGen.hs +223/−0
- llvmGen/LlvmCodeGen/Base.hs +550/−0
- llvmGen/LlvmCodeGen/CodeGen.hs +1912/−0
- llvmGen/LlvmCodeGen/Data.hs +162/−0
- llvmGen/LlvmCodeGen/Ppr.hs +160/−0
- llvmGen/LlvmCodeGen/Regs.hs +134/−0
- llvmGen/LlvmMangler.hs +127/−0
- main/Annotations.hs +132/−0
- main/CmdLineParser.hs +314/−0
- main/CodeOutput.hs +281/−0
- main/Constants.hs +40/−0
- main/DriverMkDepend.hs +406/−0
- main/DriverPhases.hs +375/−0
- main/DriverPipeline.hs +2411/−0
- main/DynFlags.hs +5335/−0
- main/DynFlags.hs-boot +17/−0
- main/DynamicLoading.hs +269/−0
- main/Elf.hs +471/−0
- main/ErrUtils.hs +675/−0
- main/ErrUtils.hs-boot +25/−0
- main/Finder.hs +776/−0
- main/GHC.hs +1541/−0
- main/GhcMake.hs +2258/−0
- main/GhcMonad.hs +207/−0
- main/GhcPlugins.hs +84/−0
- main/HeaderInfo.hs +338/−0
- main/Hooks.hs +96/−0
- main/Hooks.hs-boot +5/−0
- main/HscMain.hs +1784/−0
- main/HscStats.hs +180/−0
- main/HscTypes.hs +3115/−0
- main/InteractiveEval.hs +937/−0
- main/InteractiveEvalTypes.hs +93/−0
- main/PackageConfig.hs +152/−0
- main/PackageConfig.hs-boot +7/−0
- main/Packages.hs +2042/−0
- main/Packages.hs-boot +10/−0
- main/PipelineMonad.hs +107/−0
- main/PlatformConstants.hs +15/−0
- main/Plugins.hs +48/−0
- main/PprTyThing.hs +171/−0
- main/StaticPtrTable.hs +290/−0
- main/SysTools.hs +1784/−0
- main/SysTools/Terminal.hs +150/−0
- main/TidyPgm.hs +1492/−0
- nativeGen/AsmCodeGen.hs +1227/−0
- nativeGen/CPrim.hs +101/−0
- nativeGen/Dwarf.hs +259/−0
- nativeGen/Dwarf/Constants.hs +225/−0
- nativeGen/Dwarf/Types.hs +602/−0
- nativeGen/Format.hs +104/−0
- nativeGen/Instruction.hs +201/−0
- nativeGen/NCG.h +14/−0
- nativeGen/NCGMonad.hs +211/−0
- nativeGen/PIC.hs +898/−0
- nativeGen/PPC/CodeGen.hs +2307/−0
- nativeGen/PPC/Cond.hs +61/−0
- nativeGen/PPC/Instr.hs +686/−0
- nativeGen/PPC/Ppr.hs +1041/−0
- nativeGen/PPC/RegInfo.hs +74/−0
- nativeGen/PPC/Regs.hs +342/−0
- nativeGen/PprBase.hs +153/−0
- nativeGen/Reg.hs +239/−0
- nativeGen/RegAlloc/Graph/ArchBase.hs +159/−0
- nativeGen/RegAlloc/Graph/ArchX86.hs +146/−0
- nativeGen/RegAlloc/Graph/Coalesce.hs +99/−0
- nativeGen/RegAlloc/Graph/Main.hs +453/−0
- nativeGen/RegAlloc/Graph/Spill.hs +379/−0
- nativeGen/RegAlloc/Graph/SpillClean.hs +612/−0
- nativeGen/RegAlloc/Graph/SpillCost.hs +291/−0
- nativeGen/RegAlloc/Graph/Stats.hs +348/−0
- nativeGen/RegAlloc/Graph/TrivColorable.hs +283/−0
- nativeGen/RegAlloc/Linear/Base.hs +132/−0
- nativeGen/RegAlloc/Linear/FreeRegs.hs +86/−0
- nativeGen/RegAlloc/Linear/JoinToTargets.hs +368/−0
- nativeGen/RegAlloc/Linear/Main.hs +907/−0
- nativeGen/RegAlloc/Linear/PPC/FreeRegs.hs +60/−0
- nativeGen/RegAlloc/Linear/SPARC/FreeRegs.hs +186/−0
- nativeGen/RegAlloc/Linear/StackMap.hs +59/−0
- nativeGen/RegAlloc/Linear/State.hs +161/−0
- nativeGen/RegAlloc/Linear/Stats.hs +86/−0
- nativeGen/RegAlloc/Linear/X86/FreeRegs.hs +52/−0
- nativeGen/RegAlloc/Linear/X86_64/FreeRegs.hs +53/−0
- nativeGen/RegAlloc/Liveness.hs +1009/−0
- nativeGen/RegClass.hs +33/−0
- nativeGen/SPARC/AddrMode.hs +42/−0
- nativeGen/SPARC/Base.hs +75/−0
- nativeGen/SPARC/CodeGen.hs +674/−0
- nativeGen/SPARC/CodeGen/Amode.hs +72/−0
- nativeGen/SPARC/CodeGen/Base.hs +117/−0
- nativeGen/SPARC/CodeGen/CondCode.hs +108/−0
- nativeGen/SPARC/CodeGen/Expand.hs +153/−0
- nativeGen/SPARC/CodeGen/Gen32.hs +690/−0
- nativeGen/SPARC/CodeGen/Gen32.hs-boot +16/−0
- nativeGen/SPARC/CodeGen/Gen64.hs +196/−0
- nativeGen/SPARC/CodeGen/Sanity.hs +67/−0
- nativeGen/SPARC/Cond.hs +52/−0
- nativeGen/SPARC/Imm.hs +65/−0
- nativeGen/SPARC/Instr.hs +483/−0
- nativeGen/SPARC/Ppr.hs +647/−0
- nativeGen/SPARC/Regs.hs +259/−0
- nativeGen/SPARC/ShortcutJump.hs +69/−0
- nativeGen/SPARC/Stack.hs +57/−0
- nativeGen/TargetReg.hs +130/−0
- nativeGen/X86/CodeGen.hs +3121/−0
- nativeGen/X86/Cond.hs +68/−0
- nativeGen/X86/Instr.hs +1059/−0
- nativeGen/X86/Ppr.hs +1303/−0
- nativeGen/X86/RegInfo.hs +67/−0
- nativeGen/X86/Regs.hs +449/−0
- parser/ApiAnnotation.hs +362/−0
- parser/Ctype.hs +216/−0
- parser/HaddockUtils.hs +32/−0
- parser/Lexer.x +2968/−0
- parser/Parser.y +3723/−0
- parser/RdrHsSyn.hs +1562/−0
- parser/cutils.c +47/−0
- parser/cutils.h +15/−0
- prelude/ForeignCall.hs +346/−0
- prelude/KnownUniques.hs +175/−0
- prelude/KnownUniques.hs-boot +17/−0
- prelude/PrelInfo.hs +266/−0
- prelude/PrelNames.hs +2457/−0
- prelude/PrelNames.hs-boot +8/−0
- prelude/PrelRules.hs +1477/−0
- prelude/PrimOp.hs +629/−0
- prelude/PrimOp.hs-boot +3/−0
- prelude/THNames.hs +1088/−0
- prelude/TysPrim.hs +1003/−0
- prelude/TysWiredIn.hs +1652/−0
- prelude/TysWiredIn.hs-boot +37/−0
- profiling/CostCentre.hs +326/−0
- profiling/ProfInit.hs +46/−0
- profiling/SCCfinal.hs +285/−0
- rename/RnBinds.hs +1234/−0
- rename/RnEnv.hs +2350/−0
- rename/RnExpr.hs +2064/−0
- rename/RnExpr.hs-boot +18/−0
- rename/RnHsDoc.hs +23/−0
- rename/RnNames.hs +1627/−0
- rename/RnPat.hs +861/−0
- rename/RnSource.hs +2285/−0
- rename/RnSplice.hs +866/−0
- rename/RnSplice.hs-boot +17/−0
- rename/RnTypes.hs +1741/−0
- simplCore/CSE.hs +601/−0
- simplCore/CallArity.hs +739/−0
- simplCore/CoreMonad.hs +814/−0
- simplCore/FloatIn.hs +659/−0
- simplCore/FloatOut.hs +755/−0
- simplCore/LiberateCase.hs +422/−0
- simplCore/OccurAnal.hs +2772/−0
- simplCore/SAT.hs +431/−0
- simplCore/SetLevels.hs +1643/−0
- simplCore/SimplCore.hs +1061/−0
- simplCore/SimplEnv.hs +838/−0
- simplCore/SimplMonad.hs +218/−0
- simplCore/SimplUtils.hs +2048/−0
- simplCore/Simplify.hs +3461/−0
- simplStg/RepType.hs +365/−0
- simplStg/SimplStg.hs +117/−0
- simplStg/StgCse.hs +430/−0
- simplStg/StgStats.hs +175/−0
- simplStg/UnariseStg.hs +761/−0
- specialise/Rules.hs +1256/−0
- specialise/SpecConstr.hs +2256/−0
- specialise/Specialise.hs +2456/−0
- stgSyn/CoreToStg.hs +1025/−0
- stgSyn/StgLint.hs +537/−0
- stgSyn/StgSyn.hs +820/−0
- stranal/DmdAnal.hs +1482/−0
- stranal/WorkWrap.hs +661/−0
- stranal/WwLib.hs +952/−0
- typecheck/FamInst.hs +918/−0
- typecheck/FunDeps.hs +666/−0
- typecheck/Inst.hs +830/−0
- typecheck/TcAnnotations.hs +74/−0
- typecheck/TcArrows.hs +427/−0
- typecheck/TcBackpack.hs +903/−0
- typecheck/TcBinds.hs +1730/−0
- typecheck/TcCanonical.hs +1949/−0
- typecheck/TcClassDcl.hs +524/−0
- typecheck/TcDefaults.hs +104/−0
- typecheck/TcDeriv.hs +1843/−0
- typecheck/TcDerivInfer.hs +876/−0
- typecheck/TcDerivUtils.hs +669/−0
- typecheck/TcEnv.hs +1023/−0
- typecheck/TcEnv.hs-boot +6/−0
- typecheck/TcErrors.hs +2843/−0
- typecheck/TcEvidence.hs +946/−0
- typecheck/TcExpr.hs +2727/−0
- typecheck/TcExpr.hs-boot +40/−0
- typecheck/TcFlatten.hs +1647/−0
- typecheck/TcForeign.hs +562/−0
- typecheck/TcGenDeriv.hs +2155/−0
- typecheck/TcGenFunctor.hs +1023/−0
- typecheck/TcGenGenerics.hs +1010/−0
- typecheck/TcHsSyn.hs +1700/−0
- typecheck/TcHsType.hs +2161/−0
- typecheck/TcInstDcls.hs +1840/−0
- typecheck/TcInstDcls.hs-boot +16/−0
- typecheck/TcInteract.hs +2665/−0
- typecheck/TcMType.hs +1703/−0
- typecheck/TcMatches.hs +1135/−0
- typecheck/TcMatches.hs-boot +16/−0
- typecheck/TcPat.hs +1175/−0
- typecheck/TcPatSyn.hs +849/−0
- typecheck/TcPatSyn.hs-boot +19/−0
- typecheck/TcPluginM.hs +191/−0
- typecheck/TcRnDriver.hs +2640/−0
- typecheck/TcRnDriver.hs-boot +12/−0
- typecheck/TcRnExports.hs +878/−0
- typecheck/TcRnMonad.hs +1855/−0
- typecheck/TcRnTypes.hs +3499/−0
- typecheck/TcRules.hs +365/−0
- typecheck/TcSMonad.hs +3122/−0
- typecheck/TcSigs.hs +773/−0
- typecheck/TcSimplify.hs +2229/−0
- typecheck/TcSplice.hs +2002/−0
- typecheck/TcSplice.hs-boot +40/−0
- typecheck/TcTyClsDecls.hs +3092/−0
- typecheck/TcTyDecls.hs +1007/−0
- typecheck/TcType.hs +2576/−0
- typecheck/TcType.hs-boot +8/−0
- typecheck/TcTypeNats.hs +757/−0
- typecheck/TcTypeNats.hs-boot +5/−0
- typecheck/TcTypeable.hs +701/−0
- typecheck/TcUnify.hs +2116/−0
- typecheck/TcUnify.hs-boot +14/−0
- typecheck/TcValidity.hs +2040/−0
- types/Class.hs +360/−0
- types/CoAxiom.hs +517/−0
- types/Coercion.hs +1961/−0
- types/Coercion.hs-boot +51/−0
- types/FamInstEnv.hs +1724/−0
- types/InstEnv.hs +996/−0
- types/Kind.hs +192/−0
- types/OptCoercion.hs +968/−0
- types/TyCoRep.hs +2866/−0
- types/TyCoRep.hs-boot +23/−0
- types/TyCon.hs +2433/−0
- types/TyCon.hs-boot +7/−0
- types/Type.hs +2464/−0
- types/Type.hs-boot +26/−0
- types/Unify.hs +1344/−0
- utils/Bag.hs +332/−0
- utils/Binary.hs +1194/−0
- utils/BooleanFormula.hs +260/−0
- utils/BufWrite.hs +116/−0
- utils/Digraph.hs +502/−0
- utils/Encoding.hs +448/−0
- utils/Exception.hs +81/−0
- utils/FV.hs +199/−0
- utils/FastFunctions.hs +19/−0
- utils/FastMutInt.hs +59/−0
- utils/FastString.hs +620/−0
- utils/FastStringEnv.hs +98/−0
- utils/Fingerprint.hsc +46/−0
- utils/FiniteMap.hs +29/−0
- utils/GraphBase.hs +105/−0
- utils/GraphColor.hs +371/−0
- utils/GraphOps.hs +678/−0
- utils/GraphPpr.hs +171/−0
- utils/IOEnv.hs +227/−0
- utils/Json.hs +54/−0
- utils/ListSetOps.hs +155/−0
- utils/ListT.hs +71/−0
- utils/Maybes.hs +108/−0
- utils/MonadUtils.hs +204/−0
- utils/OrdList.hs +128/−0
- utils/Outputable.hs +1194/−0
- utils/Outputable.hs-boot +5/−0
- utils/Pair.hs +54/−0
- utils/Panic.hs +298/−0
- utils/Platform.hs +172/−0
- utils/PprColour.hs +95/−0
- utils/Pretty.hs +1050/−0
- utils/State.hs +46/−0
- utils/Stream.hs +104/−0
- utils/StringBuffer.hs +310/−0
- utils/UnVarGraph.hs +136/−0
- utils/UniqDFM.hs +398/−0
- utils/UniqDSet.hs +103/−0
- utils/UniqFM.hs +411/−0
- utils/UniqSet.hs +206/−0
- utils/Util.hs +1371/−0
- utils/md5.h +24/−0
- vectorise/Vectorise.hs +356/−0
- vectorise/Vectorise/Builtins.hs +35/−0
- vectorise/Vectorise/Builtins/Base.hs +217/−0
- vectorise/Vectorise/Builtins/Initialise.hs +232/−0
- vectorise/Vectorise/Convert.hs +105/−0
- vectorise/Vectorise/Env.hs +238/−0
- vectorise/Vectorise/Exp.hs +1257/−0
- vectorise/Vectorise/Generic/Description.hs +292/−0
- vectorise/Vectorise/Generic/PADict.hs +126/−0
- vectorise/Vectorise/Generic/PAMethods.hs +584/−0
- vectorise/Vectorise/Generic/PData.hs +168/−0
- vectorise/Vectorise/Monad.hs +195/−0
- vectorise/Vectorise/Monad/Base.hs +243/−0
- vectorise/Vectorise/Monad/Global.hs +237/−0
- vectorise/Vectorise/Monad/InstEnv.hs +80/−0
- vectorise/Vectorise/Monad/Local.hs +100/−0
- vectorise/Vectorise/Monad/Naming.hs +130/−0
- vectorise/Vectorise/Type/Classify.hs +128/−0
- vectorise/Vectorise/Type/Env.hs +455/−0
- vectorise/Vectorise/Type/TyConDecl.hs +214/−0
- vectorise/Vectorise/Type/Type.hs +87/−0
- vectorise/Vectorise/Utils.hs +165/−0
- vectorise/Vectorise/Utils/Base.hs +262/−0
- vectorise/Vectorise/Utils/Closure.hs +161/−0
- vectorise/Vectorise/Utils/Hoisting.hs +98/−0
- vectorise/Vectorise/Utils/PADict.hs +229/−0
- vectorise/Vectorise/Utils/Poly.hs +72/−0
- vectorise/Vectorise/Var.hs +103/−0
- vectorise/Vectorise/Vect.hs +126/−0
+ HsVersions.h view
@@ -0,0 +1,69 @@+#ifndef HSVERSIONS_H+#define HSVERSIONS_H++#if 0++IMPORTANT! If you put extra tabs/spaces in these macro definitions,+you will screw up the layout where they are used in case expressions!++(This is cpp-dependent, of course)++#endif++/* Useful in the headers that we share with the RTS */+#define COMPILING_GHC 1++/* Pull in all the platform defines for this build (foo_TARGET_ARCH etc.) */+#include "ghc_boot_platform.h"++/* Pull in the autoconf defines (HAVE_FOO), but don't include+ * ghcconfig.h, because that will include ghcplatform.h which has the+ * wrong platform settings for the compiler (it has the platform+ * settings for the target plat instead). */+#include "ghcautoconf.h"++#define GLOBAL_VAR(name,value,ty) \+{-# NOINLINE name #-}; \+name :: IORef (ty); \+name = Util.global (value);++#define GLOBAL_VAR_M(name,value,ty) \+{-# NOINLINE name #-}; \+name :: IORef (ty); \+name = Util.globalM (value);+++#define SHARED_GLOBAL_VAR(name,accessor,saccessor,value,ty) \+{-# NOINLINE name #-}; \+name :: IORef (ty); \+name = Util.sharedGlobal (value) (accessor); \+foreign import ccall unsafe saccessor \+ accessor :: Ptr (IORef a) -> IO (Ptr (IORef a));++#define SHARED_GLOBAL_VAR_M(name,accessor,saccessor,value,ty) \+{-# NOINLINE name #-}; \+name :: IORef (ty); \+name = Util.sharedGlobalM (value) (accessor); \+foreign import ccall unsafe saccessor \+ accessor :: Ptr (IORef a) -> IO (Ptr (IORef a));+++#define ASSERT(e) if debugIsOn && not (e) then (assertPanic __FILE__ __LINE__) else+#define ASSERT2(e,msg) if debugIsOn && not (e) then (assertPprPanic __FILE__ __LINE__ (msg)) else+#define WARN( e, msg ) (warnPprTrace (e) __FILE__ __LINE__ (msg)) $++-- Examples: Assuming flagSet :: String -> m Bool+--+-- do { c <- getChar; MASSERT( isUpper c ); ... }+-- do { c <- getChar; MASSERT2( isUpper c, text "Bad" ); ... }+-- do { str <- getStr; ASSERTM( flagSet str ); .. }+-- do { str <- getStr; ASSERTM2( flagSet str, text "Bad" ); .. }+-- do { str <- getStr; WARNM2( flagSet str, text "Flag is set" ); .. }+#define MASSERT(e) ASSERT(e) return ()+#define MASSERT2(e,msg) ASSERT2(e,msg) return ()+#define ASSERTM(e) do { bool <- e; MASSERT(bool) }+#define ASSERTM2(e,msg) do { bool <- e; MASSERT2(bool,msg) }+#define WARNM2(e,msg) do { bool <- e; WARN(bool, msg) return () }++#endif /* HsVersions.h */+
+ LICENSE view
@@ -0,0 +1,31 @@+The Glasgow Haskell Compiler License++Copyright 2002, The University Court of the University of Glasgow. +All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++- Redistributions of source code must retain the above copyright notice,+this list of conditions and the following disclaimer.+ +- Redistributions in binary form must reproduce the above copyright notice,+this list of conditions and the following disclaimer in the documentation+and/or other materials provided with the distribution.+ +- Neither name of the University nor the names of its contributors may be+used to endorse or promote products derived from this software without+specific prior written permission. ++THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF+GLASGOW AND THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH+DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Unique.h view
@@ -0,0 +1,5 @@+/* unique has the following structure:+ * HsInt unique =+ * (unique_tag << (sizeof (HsInt) - UNIQUE_TAG_BITS)) | unique_number+ */+#define UNIQUE_TAG_BITS 8
+ autogen/CodeGen.Platform.hs view
@@ -0,0 +1,1137 @@++import CmmExpr+#if !(MACHREGS_i386 || MACHREGS_x86_64 || MACHREGS_sparc || MACHREGS_powerpc)+import Panic+#endif+import Reg++#include "ghcautoconf.h"+#include "stg/MachRegs.h"++#if MACHREGS_i386 || MACHREGS_x86_64++# if MACHREGS_i386+# define eax 0+# define ebx 1+# define ecx 2+# define edx 3+# define esi 4+# define edi 5+# define ebp 6+# define esp 7+# endif++# if MACHREGS_x86_64+# define rax 0+# define rbx 1+# define rcx 2+# define rdx 3+# define rsi 4+# define rdi 5+# define rbp 6+# define rsp 7+# define r8 8+# define r9 9+# define r10 10+# define r11 11+# define r12 12+# define r13 13+# define r14 14+# define r15 15+# endif++# define fake0 16+# define fake1 17+# define fake2 18+# define fake3 19+# define fake4 20+# define fake5 21++# define xmm0 24+# define xmm1 25+# define xmm2 26+# define xmm3 27+# define xmm4 28+# define xmm5 29+# define xmm6 30+# define xmm7 31+# define xmm8 32+# define xmm9 33+# define xmm10 34+# define xmm11 35+# define xmm12 36+# define xmm13 37+# define xmm14 38+# define xmm15 39++# define ymm0 40+# define ymm1 41+# define ymm2 42+# define ymm3 43+# define ymm4 44+# define ymm5 45+# define ymm6 46+# define ymm7 47+# define ymm8 48+# define ymm9 49+# define ymm10 50+# define ymm11 51+# define ymm12 52+# define ymm13 53+# define ymm14 54+# define ymm15 55++# define zmm0 56+# define zmm1 57+# define zmm2 58+# define zmm3 59+# define zmm4 60+# define zmm5 61+# define zmm6 62+# define zmm7 63+# define zmm8 64+# define zmm9 65+# define zmm10 66+# define zmm11 67+# define zmm12 68+# define zmm13 69+# define zmm14 70+# define zmm15 71++-- Note: these are only needed for ARM/ARM64 because globalRegMaybe is now used in CmmSink.hs.+-- Since it's only used to check 'isJust', the actual values don't matter, thus+-- I'm not sure if these are the correct numberings.+-- Normally, the register names are just stringified as part of the REG() macro++#elif MACHREGS_powerpc || MACHREGS_arm || MACHREGS_aarch64++# define r0 0+# define r1 1+# define r2 2+# define r3 3+# define r4 4+# define r5 5+# define r6 6+# define r7 7+# define r8 8+# define r9 9+# define r10 10+# define r11 11+# define r12 12+# define r13 13+# define r14 14+# define r15 15+# define r16 16+# define r17 17+# define r18 18+# define r19 19+# define r20 20+# define r21 21+# define r22 22+# define r23 23+# define r24 24+# define r25 25+# define r26 26+# define r27 27+# define r28 28+# define r29 29+# define r30 30+# define r31 31++-- See note above. These aren't actually used for anything except satisfying the compiler for globalRegMaybe+-- so I'm unsure if they're the correct numberings, should they ever be attempted to be used in the NCG. +#if MACHREGS_aarch64 || MACHREGS_arm+# define s0 32+# define s1 33+# define s2 34+# define s3 35+# define s4 36+# define s5 37+# define s6 38+# define s7 39+# define s8 40+# define s9 41+# define s10 42+# define s11 43+# define s12 44+# define s13 45+# define s14 46+# define s15 47+# define s16 48+# define s17 49+# define s18 50+# define s19 51+# define s20 52+# define s21 53+# define s22 54+# define s23 55+# define s24 56+# define s25 57+# define s26 58+# define s27 59+# define s28 60+# define s29 61+# define s30 62+# define s31 63++# define d0 32+# define d1 33+# define d2 34+# define d3 35+# define d4 36+# define d5 37+# define d6 38+# define d7 39+# define d8 40+# define d9 41+# define d10 42+# define d11 43+# define d12 44+# define d13 45+# define d14 46+# define d15 47+# define d16 48+# define d17 49+# define d18 50+# define d19 51+# define d20 52+# define d21 53+# define d22 54+# define d23 55+# define d24 56+# define d25 57+# define d26 58+# define d27 59+# define d28 60+# define d29 61+# define d30 62+# define d31 63+#endif++# if MACHREGS_darwin+# define f0 32+# define f1 33+# define f2 34+# define f3 35+# define f4 36+# define f5 37+# define f6 38+# define f7 39+# define f8 40+# define f9 41+# define f10 42+# define f11 43+# define f12 44+# define f13 45+# define f14 46+# define f15 47+# define f16 48+# define f17 49+# define f18 50+# define f19 51+# define f20 52+# define f21 53+# define f22 54+# define f23 55+# define f24 56+# define f25 57+# define f26 58+# define f27 59+# define f28 60+# define f29 61+# define f30 62+# define f31 63+# else+# define fr0 32+# define fr1 33+# define fr2 34+# define fr3 35+# define fr4 36+# define fr5 37+# define fr6 38+# define fr7 39+# define fr8 40+# define fr9 41+# define fr10 42+# define fr11 43+# define fr12 44+# define fr13 45+# define fr14 46+# define fr15 47+# define fr16 48+# define fr17 49+# define fr18 50+# define fr19 51+# define fr20 52+# define fr21 53+# define fr22 54+# define fr23 55+# define fr24 56+# define fr25 57+# define fr26 58+# define fr27 59+# define fr28 60+# define fr29 61+# define fr30 62+# define fr31 63+# endif++#elif MACHREGS_sparc++# define g0 0+# define g1 1+# define g2 2+# define g3 3+# define g4 4+# define g5 5+# define g6 6+# define g7 7++# define o0 8+# define o1 9+# define o2 10+# define o3 11+# define o4 12+# define o5 13+# define o6 14+# define o7 15++# define l0 16+# define l1 17+# define l2 18+# define l3 19+# define l4 20+# define l5 21+# define l6 22+# define l7 23++# define i0 24+# define i1 25+# define i2 26+# define i3 27+# define i4 28+# define i5 29+# define i6 30+# define i7 31++# define f0 32+# define f1 33+# define f2 34+# define f3 35+# define f4 36+# define f5 37+# define f6 38+# define f7 39+# define f8 40+# define f9 41+# define f10 42+# define f11 43+# define f12 44+# define f13 45+# define f14 46+# define f15 47+# define f16 48+# define f17 49+# define f18 50+# define f19 51+# define f20 52+# define f21 53+# define f22 54+# define f23 55+# define f24 56+# define f25 57+# define f26 58+# define f27 59+# define f28 60+# define f29 61+# define f30 62+# define f31 63++#endif++callerSaves :: GlobalReg -> Bool+#ifdef CALLER_SAVES_Base+callerSaves BaseReg = True+#endif+#ifdef CALLER_SAVES_R1+callerSaves (VanillaReg 1 _) = True+#endif+#ifdef CALLER_SAVES_R2+callerSaves (VanillaReg 2 _) = True+#endif+#ifdef CALLER_SAVES_R3+callerSaves (VanillaReg 3 _) = True+#endif+#ifdef CALLER_SAVES_R4+callerSaves (VanillaReg 4 _) = True+#endif+#ifdef CALLER_SAVES_R5+callerSaves (VanillaReg 5 _) = True+#endif+#ifdef CALLER_SAVES_R6+callerSaves (VanillaReg 6 _) = True+#endif+#ifdef CALLER_SAVES_R7+callerSaves (VanillaReg 7 _) = True+#endif+#ifdef CALLER_SAVES_R8+callerSaves (VanillaReg 8 _) = True+#endif+#ifdef CALLER_SAVES_R9+callerSaves (VanillaReg 9 _) = True+#endif+#ifdef CALLER_SAVES_R10+callerSaves (VanillaReg 10 _) = True+#endif+#ifdef CALLER_SAVES_F1+callerSaves (FloatReg 1) = True+#endif+#ifdef CALLER_SAVES_F2+callerSaves (FloatReg 2) = True+#endif+#ifdef CALLER_SAVES_F3+callerSaves (FloatReg 3) = True+#endif+#ifdef CALLER_SAVES_F4+callerSaves (FloatReg 4) = True+#endif+#ifdef CALLER_SAVES_F5+callerSaves (FloatReg 5) = True+#endif+#ifdef CALLER_SAVES_F6+callerSaves (FloatReg 6) = True+#endif+#ifdef CALLER_SAVES_D1+callerSaves (DoubleReg 1) = True+#endif+#ifdef CALLER_SAVES_D2+callerSaves (DoubleReg 2) = True+#endif+#ifdef CALLER_SAVES_D3+callerSaves (DoubleReg 3) = True+#endif+#ifdef CALLER_SAVES_D4+callerSaves (DoubleReg 4) = True+#endif+#ifdef CALLER_SAVES_D5+callerSaves (DoubleReg 5) = True+#endif+#ifdef CALLER_SAVES_D6+callerSaves (DoubleReg 6) = True+#endif+#ifdef CALLER_SAVES_L1+callerSaves (LongReg 1) = True+#endif+#ifdef CALLER_SAVES_Sp+callerSaves Sp = True+#endif+#ifdef CALLER_SAVES_SpLim+callerSaves SpLim = True+#endif+#ifdef CALLER_SAVES_Hp+callerSaves Hp = True+#endif+#ifdef CALLER_SAVES_HpLim+callerSaves HpLim = True+#endif+#ifdef CALLER_SAVES_CCCS+callerSaves CCCS = True+#endif+#ifdef CALLER_SAVES_CurrentTSO+callerSaves CurrentTSO = True+#endif+#ifdef CALLER_SAVES_CurrentNursery+callerSaves CurrentNursery = True+#endif+callerSaves _ = False++activeStgRegs :: [GlobalReg]+activeStgRegs = [+#ifdef REG_Base+ BaseReg+#endif+#ifdef REG_Sp+ ,Sp+#endif+#ifdef REG_Hp+ ,Hp+#endif+#ifdef REG_R1+ ,VanillaReg 1 VGcPtr+#endif+#ifdef REG_R2+ ,VanillaReg 2 VGcPtr+#endif+#ifdef REG_R3+ ,VanillaReg 3 VGcPtr+#endif+#ifdef REG_R4+ ,VanillaReg 4 VGcPtr+#endif+#ifdef REG_R5+ ,VanillaReg 5 VGcPtr+#endif+#ifdef REG_R6+ ,VanillaReg 6 VGcPtr+#endif+#ifdef REG_R7+ ,VanillaReg 7 VGcPtr+#endif+#ifdef REG_R8+ ,VanillaReg 8 VGcPtr+#endif+#ifdef REG_R9+ ,VanillaReg 9 VGcPtr+#endif+#ifdef REG_R10+ ,VanillaReg 10 VGcPtr+#endif+#ifdef REG_SpLim+ ,SpLim+#endif+#if MAX_REAL_XMM_REG != 0+#ifdef REG_F1+ ,FloatReg 1+#endif+#ifdef REG_D1+ ,DoubleReg 1+#endif+#ifdef REG_XMM1+ ,XmmReg 1+#endif+#ifdef REG_YMM1+ ,YmmReg 1+#endif+#ifdef REG_ZMM1+ ,ZmmReg 1+#endif+#ifdef REG_F2+ ,FloatReg 2+#endif+#ifdef REG_D2+ ,DoubleReg 2+#endif+#ifdef REG_XMM2+ ,XmmReg 2+#endif+#ifdef REG_YMM2+ ,YmmReg 2+#endif+#ifdef REG_ZMM2+ ,ZmmReg 2+#endif+#ifdef REG_F3+ ,FloatReg 3+#endif+#ifdef REG_D3+ ,DoubleReg 3+#endif+#ifdef REG_XMM3+ ,XmmReg 3+#endif+#ifdef REG_YMM3+ ,YmmReg 3+#endif+#ifdef REG_ZMM3+ ,ZmmReg 3+#endif+#ifdef REG_F4+ ,FloatReg 4+#endif+#ifdef REG_D4+ ,DoubleReg 4+#endif+#ifdef REG_XMM4+ ,XmmReg 4+#endif+#ifdef REG_YMM4+ ,YmmReg 4+#endif+#ifdef REG_ZMM4+ ,ZmmReg 4+#endif+#ifdef REG_F5+ ,FloatReg 5+#endif+#ifdef REG_D5+ ,DoubleReg 5+#endif+#ifdef REG_XMM5+ ,XmmReg 5+#endif+#ifdef REG_YMM5+ ,YmmReg 5+#endif+#ifdef REG_ZMM5+ ,ZmmReg 5+#endif+#ifdef REG_F6+ ,FloatReg 6+#endif+#ifdef REG_D6+ ,DoubleReg 6+#endif+#ifdef REG_XMM6+ ,XmmReg 6+#endif+#ifdef REG_YMM6+ ,YmmReg 6+#endif+#ifdef REG_ZMM6+ ,ZmmReg 6+#endif+#else /* MAX_REAL_XMM_REG == 0 */+#ifdef REG_F1+ ,FloatReg 1+#endif+#ifdef REG_F2+ ,FloatReg 2+#endif+#ifdef REG_F3+ ,FloatReg 3+#endif+#ifdef REG_F4+ ,FloatReg 4+#endif+#ifdef REG_F5+ ,FloatReg 5+#endif+#ifdef REG_F6+ ,FloatReg 6+#endif+#ifdef REG_D1+ ,DoubleReg 1+#endif+#ifdef REG_D2+ ,DoubleReg 2+#endif+#ifdef REG_D3+ ,DoubleReg 3+#endif+#ifdef REG_D4+ ,DoubleReg 4+#endif+#ifdef REG_D5+ ,DoubleReg 5+#endif+#ifdef REG_D6+ ,DoubleReg 6+#endif+#endif /* MAX_REAL_XMM_REG == 0 */+ ]++haveRegBase :: Bool+#ifdef REG_Base+haveRegBase = True+#else+haveRegBase = False+#endif++-- | Returns 'Nothing' if this global register is not stored+-- in a real machine register, otherwise returns @'Just' reg@, where+-- reg is the machine register it is stored in.+globalRegMaybe :: GlobalReg -> Maybe RealReg+#if MACHREGS_i386 || MACHREGS_x86_64 || MACHREGS_sparc || MACHREGS_powerpc || MACHREGS_arm || MACHREGS_aarch64+# ifdef REG_Base+globalRegMaybe BaseReg = Just (RealRegSingle REG_Base)+# endif+# ifdef REG_R1+globalRegMaybe (VanillaReg 1 _) = Just (RealRegSingle REG_R1)+# endif+# ifdef REG_R2+globalRegMaybe (VanillaReg 2 _) = Just (RealRegSingle REG_R2)+# endif+# ifdef REG_R3+globalRegMaybe (VanillaReg 3 _) = Just (RealRegSingle REG_R3)+# endif+# ifdef REG_R4+globalRegMaybe (VanillaReg 4 _) = Just (RealRegSingle REG_R4)+# endif+# ifdef REG_R5+globalRegMaybe (VanillaReg 5 _) = Just (RealRegSingle REG_R5)+# endif+# ifdef REG_R6+globalRegMaybe (VanillaReg 6 _) = Just (RealRegSingle REG_R6)+# endif+# ifdef REG_R7+globalRegMaybe (VanillaReg 7 _) = Just (RealRegSingle REG_R7)+# endif+# ifdef REG_R8+globalRegMaybe (VanillaReg 8 _) = Just (RealRegSingle REG_R8)+# endif+# ifdef REG_R9+globalRegMaybe (VanillaReg 9 _) = Just (RealRegSingle REG_R9)+# endif+# ifdef REG_R10+globalRegMaybe (VanillaReg 10 _) = Just (RealRegSingle REG_R10)+# endif+# ifdef REG_F1+globalRegMaybe (FloatReg 1) = Just (RealRegSingle REG_F1)+# endif+# ifdef REG_F2+globalRegMaybe (FloatReg 2) = Just (RealRegSingle REG_F2)+# endif+# ifdef REG_F3+globalRegMaybe (FloatReg 3) = Just (RealRegSingle REG_F3)+# endif+# ifdef REG_F4+globalRegMaybe (FloatReg 4) = Just (RealRegSingle REG_F4)+# endif+# ifdef REG_F5+globalRegMaybe (FloatReg 5) = Just (RealRegSingle REG_F5)+# endif+# ifdef REG_F6+globalRegMaybe (FloatReg 6) = Just (RealRegSingle REG_F6)+# endif+# ifdef REG_D1+globalRegMaybe (DoubleReg 1) =+# if MACHREGS_sparc+ Just (RealRegPair REG_D1 (REG_D1 + 1))+# else+ Just (RealRegSingle REG_D1)+# endif+# endif+# ifdef REG_D2+globalRegMaybe (DoubleReg 2) =+# if MACHREGS_sparc+ Just (RealRegPair REG_D2 (REG_D2 + 1))+# else+ Just (RealRegSingle REG_D2)+# endif+# endif+# ifdef REG_D3+globalRegMaybe (DoubleReg 3) =+# if MACHREGS_sparc+ Just (RealRegPair REG_D3 (REG_D3 + 1))+# else+ Just (RealRegSingle REG_D3)+# endif+# endif+# ifdef REG_D4+globalRegMaybe (DoubleReg 4) =+# if MACHREGS_sparc+ Just (RealRegPair REG_D4 (REG_D4 + 1))+# else+ Just (RealRegSingle REG_D4)+# endif+# endif+# ifdef REG_D5+globalRegMaybe (DoubleReg 5) =+# if MACHREGS_sparc+ Just (RealRegPair REG_D5 (REG_D5 + 1))+# else+ Just (RealRegSingle REG_D5)+# endif+# endif+# ifdef REG_D6+globalRegMaybe (DoubleReg 6) =+# if MACHREGS_sparc+ Just (RealRegPair REG_D6 (REG_D6 + 1))+# else+ Just (RealRegSingle REG_D6)+# endif+# endif+# if MAX_REAL_XMM_REG != 0+# ifdef REG_XMM1+globalRegMaybe (XmmReg 1) = Just (RealRegSingle REG_XMM1)+# endif+# ifdef REG_XMM2+globalRegMaybe (XmmReg 2) = Just (RealRegSingle REG_XMM2)+# endif+# ifdef REG_XMM3+globalRegMaybe (XmmReg 3) = Just (RealRegSingle REG_XMM3)+# endif+# ifdef REG_XMM4+globalRegMaybe (XmmReg 4) = Just (RealRegSingle REG_XMM4)+# endif+# ifdef REG_XMM5+globalRegMaybe (XmmReg 5) = Just (RealRegSingle REG_XMM5)+# endif+# ifdef REG_XMM6+globalRegMaybe (XmmReg 6) = Just (RealRegSingle REG_XMM6)+# endif+# endif+# if MAX_REAL_YMM_REG != 0+# ifdef REG_YMM1+globalRegMaybe (YmmReg 1) = Just (RealRegSingle REG_YMM1)+# endif+# ifdef REG_YMM2+globalRegMaybe (YmmReg 2) = Just (RealRegSingle REG_YMM2)+# endif+# ifdef REG_YMM3+globalRegMaybe (YmmReg 3) = Just (RealRegSingle REG_YMM3)+# endif+# ifdef REG_YMM4+globalRegMaybe (YmmReg 4) = Just (RealRegSingle REG_YMM4)+# endif+# ifdef REG_YMM5+globalRegMaybe (YmmReg 5) = Just (RealRegSingle REG_YMM5)+# endif+# ifdef REG_YMM6+globalRegMaybe (YmmReg 6) = Just (RealRegSingle REG_YMM6)+# endif+# endif+# if MAX_REAL_ZMM_REG != 0+# ifdef REG_ZMM1+globalRegMaybe (ZmmReg 1) = Just (RealRegSingle REG_ZMM1)+# endif+# ifdef REG_ZMM2+globalRegMaybe (ZmmReg 2) = Just (RealRegSingle REG_ZMM2)+# endif+# ifdef REG_ZMM3+globalRegMaybe (ZmmReg 3) = Just (RealRegSingle REG_ZMM3)+# endif+# ifdef REG_ZMM4+globalRegMaybe (ZmmReg 4) = Just (RealRegSingle REG_ZMM4)+# endif+# ifdef REG_ZMM5+globalRegMaybe (ZmmReg 5) = Just (RealRegSingle REG_ZMM5)+# endif+# ifdef REG_ZMM6+globalRegMaybe (ZmmReg 6) = Just (RealRegSingle REG_ZMM6)+# endif+# endif+# ifdef REG_Sp+globalRegMaybe Sp = Just (RealRegSingle REG_Sp)+# endif+# ifdef REG_Lng1+globalRegMaybe (LongReg 1) = Just (RealRegSingle REG_Lng1)+# endif+# ifdef REG_Lng2+globalRegMaybe (LongReg 2) = Just (RealRegSingle REG_Lng2)+# endif+# ifdef REG_SpLim+globalRegMaybe SpLim = Just (RealRegSingle REG_SpLim)+# endif+# ifdef REG_Hp+globalRegMaybe Hp = Just (RealRegSingle REG_Hp)+# endif+# ifdef REG_HpLim+globalRegMaybe HpLim = Just (RealRegSingle REG_HpLim)+# endif+# ifdef REG_CurrentTSO+globalRegMaybe CurrentTSO = Just (RealRegSingle REG_CurrentTSO)+# endif+# ifdef REG_CurrentNursery+globalRegMaybe CurrentNursery = Just (RealRegSingle REG_CurrentNursery)+# endif+# ifdef REG_MachSp+globalRegMaybe MachSp = Just (RealRegSingle REG_MachSp)+# endif+globalRegMaybe _ = Nothing+#elif MACHREGS_NO_REGS+globalRegMaybe _ = Nothing+#else+globalRegMaybe = panic "globalRegMaybe not defined for this platform"+#endif++freeReg :: RegNo -> Bool++#if MACHREGS_i386 || MACHREGS_x86_64++# if MACHREGS_i386+freeReg esp = False -- %esp is the C stack pointer+freeReg esi = False -- Note [esi/edi not allocatable]+freeReg edi = False+# endif+# if MACHREGS_x86_64+freeReg rsp = False -- %rsp is the C stack pointer+# endif++{-+Note [esi/edi not allocatable]++%esi is mapped to R1, so %esi would normally be allocatable while it+is not being used for R1. However, %esi has no 8-bit version on x86,+and the linear register allocator is not sophisticated enough to+handle this irregularity (we need more RegClasses). The+graph-colouring allocator also cannot handle this - it was designed+with more flexibility in mind, but the current implementation is+restricted to the same set of classes as the linear allocator.++Hence, on x86 esi and edi are treated as not allocatable.+-}++-- split patterns in two functions to prevent overlaps+freeReg r = freeRegBase r++freeRegBase :: RegNo -> Bool+# ifdef REG_Base+freeRegBase REG_Base = False+# endif+# ifdef REG_Sp+freeRegBase REG_Sp = False+# endif+# ifdef REG_SpLim+freeRegBase REG_SpLim = False+# endif+# ifdef REG_Hp+freeRegBase REG_Hp = False+# endif+# ifdef REG_HpLim+freeRegBase REG_HpLim = False+# endif+-- All other regs are considered to be "free", because we can track+-- their liveness accurately.+freeRegBase _ = True++#elif MACHREGS_powerpc++freeReg 0 = False -- Used by code setting the back chain pointer+ -- in stack reallocations on Linux+ -- r0 is not usable in all insns so also reserved+ -- on Darwin.+freeReg 1 = False -- The Stack Pointer+# if !MACHREGS_darwin+-- most non-darwin powerpc OSes use r2 as a TOC pointer or something like that+freeReg 2 = False+freeReg 13 = False -- reserved for system thread ID on 64 bit+-- at least linux in -fPIC relies on r30 in PLT stubs+freeReg 30 = False+{- TODO: reserve r13 on 64 bit systems only and r30 on 32 bit respectively.+ For now we use r30 on 64 bit and r13 on 32 bit as a temporary register+ in stack handling code. See compiler/nativeGen/PPC/Ppr.hs.++ Later we might want to reserve r13 and r30 only where it is required.+ Then use r12 as temporary register, which is also what the C ABI does.+-}++# endif+# ifdef REG_Base+freeReg REG_Base = False+# endif+# ifdef REG_R1+freeReg REG_R1 = False+# endif+# ifdef REG_R2+freeReg REG_R2 = False+# endif+# ifdef REG_R3+freeReg REG_R3 = False+# endif+# ifdef REG_R4+freeReg REG_R4 = False+# endif+# ifdef REG_R5+freeReg REG_R5 = False+# endif+# ifdef REG_R6+freeReg REG_R6 = False+# endif+# ifdef REG_R7+freeReg REG_R7 = False+# endif+# ifdef REG_R8+freeReg REG_R8 = False+# endif+# ifdef REG_R9+freeReg REG_R9 = False+# endif+# ifdef REG_R10+freeReg REG_R10 = False+# endif+# ifdef REG_F1+freeReg REG_F1 = False+# endif+# ifdef REG_F2+freeReg REG_F2 = False+# endif+# ifdef REG_F3+freeReg REG_F3 = False+# endif+# ifdef REG_F4+freeReg REG_F4 = False+# endif+# ifdef REG_F5+freeReg REG_F5 = False+# endif+# ifdef REG_F6+freeReg REG_F6 = False+# endif+# ifdef REG_D1+freeReg REG_D1 = False+# endif+# ifdef REG_D2+freeReg REG_D2 = False+# endif+# ifdef REG_D3+freeReg REG_D3 = False+# endif+# ifdef REG_D4+freeReg REG_D4 = False+# endif+# ifdef REG_D5+freeReg REG_D5 = False+# endif+# ifdef REG_D6+freeReg REG_D6 = False+# endif+# ifdef REG_Sp+freeReg REG_Sp = False+# endif+# ifdef REG_Su+freeReg REG_Su = False+# endif+# ifdef REG_SpLim+freeReg REG_SpLim = False+# endif+# ifdef REG_Hp+freeReg REG_Hp = False+# endif+# ifdef REG_HpLim+freeReg REG_HpLim = False+# endif+freeReg _ = True++#elif MACHREGS_sparc++-- SPARC regs used by the OS / ABI+-- %g0(r0) is always zero+freeReg g0 = False++-- %g5(r5) - %g7(r7)+-- are reserved for the OS+freeReg g5 = False+freeReg g6 = False+freeReg g7 = False++-- %o6(r14)+-- is the C stack pointer+freeReg o6 = False++-- %o7(r15)+-- holds the C return address+freeReg o7 = False++-- %i6(r30)+-- is the C frame pointer+freeReg i6 = False++-- %i7(r31)+-- is used for C return addresses+freeReg i7 = False++-- %f0(r32) - %f1(r32)+-- are C floating point return regs+freeReg f0 = False+freeReg f1 = False++{-+freeReg regNo+ -- don't release high half of double regs+ | regNo >= f0+ , regNo < NCG_FirstFloatReg+ , regNo `mod` 2 /= 0+ = False+-}++# ifdef REG_Base+freeReg REG_Base = False+# endif+# ifdef REG_R1+freeReg REG_R1 = False+# endif+# ifdef REG_R2+freeReg REG_R2 = False+# endif+# ifdef REG_R3+freeReg REG_R3 = False+# endif+# ifdef REG_R4+freeReg REG_R4 = False+# endif+# ifdef REG_R5+freeReg REG_R5 = False+# endif+# ifdef REG_R6+freeReg REG_R6 = False+# endif+# ifdef REG_R7+freeReg REG_R7 = False+# endif+# ifdef REG_R8+freeReg REG_R8 = False+# endif+# ifdef REG_R9+freeReg REG_R9 = False+# endif+# ifdef REG_R10+freeReg REG_R10 = False+# endif+# ifdef REG_F1+freeReg REG_F1 = False+# endif+# ifdef REG_F2+freeReg REG_F2 = False+# endif+# ifdef REG_F3+freeReg REG_F3 = False+# endif+# ifdef REG_F4+freeReg REG_F4 = False+# endif+# ifdef REG_F5+freeReg REG_F5 = False+# endif+# ifdef REG_F6+freeReg REG_F6 = False+# endif+# ifdef REG_D1+freeReg REG_D1 = False+# endif+# ifdef REG_D1_2+freeReg REG_D1_2 = False+# endif+# ifdef REG_D2+freeReg REG_D2 = False+# endif+# ifdef REG_D2_2+freeReg REG_D2_2 = False+# endif+# ifdef REG_D3+freeReg REG_D3 = False+# endif+# ifdef REG_D3_2+freeReg REG_D3_2 = False+# endif+# ifdef REG_D4+freeReg REG_D4 = False+# endif+# ifdef REG_D4_2+freeReg REG_D4_2 = False+# endif+# ifdef REG_D5+freeReg REG_D5 = False+# endif+# ifdef REG_D5_2+freeReg REG_D5_2 = False+# endif+# ifdef REG_D6+freeReg REG_D6 = False+# endif+# ifdef REG_D6_2+freeReg REG_D6_2 = False+# endif+# ifdef REG_Sp+freeReg REG_Sp = False+# endif+# ifdef REG_Su+freeReg REG_Su = False+# endif+# ifdef REG_SpLim+freeReg REG_SpLim = False+# endif+# ifdef REG_Hp+freeReg REG_Hp = False+# endif+# ifdef REG_HpLim+freeReg REG_HpLim = False+# endif+freeReg _ = True++#else++freeReg = panic "freeReg not defined for this platform"++#endif+
+ autogen/Config.hs view
@@ -0,0 +1,64 @@+{-# LANGUAGE CPP #-}+module Config where++#include "ghc_boot_platform.h"++data IntegerLibrary = IntegerGMP+ | IntegerSimple+ deriving Eq++cBuildPlatformString :: String+cBuildPlatformString = BuildPlatform_NAME+cHostPlatformString :: String+cHostPlatformString = HostPlatform_NAME+cTargetPlatformString :: String+cTargetPlatformString = TargetPlatform_NAME++cProjectName :: String+cProjectName = "The Glorious Glasgow Haskell Compilation System"+cProjectGitCommitId :: String+cProjectGitCommitId = "0cee25253f9f2cb4f19f021fd974bdad3c26a80b"+cProjectVersion :: String+cProjectVersion = "8.2.1"+cProjectVersionInt :: String+cProjectVersionInt = "802"+cProjectPatchLevel :: String+cProjectPatchLevel = "1"+cProjectPatchLevel1 :: String+cProjectPatchLevel1 = "1"+cProjectPatchLevel2 :: String+cProjectPatchLevel2 = ""+cBooterVersion :: String+cBooterVersion = "8.0.2"+cStage :: String+cStage = show (STAGE :: Int)+cIntegerLibrary :: String+cIntegerLibrary = "integer-gmp"+cIntegerLibraryType :: IntegerLibrary+cIntegerLibraryType = IntegerGMP+cSupportsSplitObjs :: String+cSupportsSplitObjs = "YES"+cGhcWithInterpreter :: String+cGhcWithInterpreter = "YES"+cGhcWithNativeCodeGen :: String+cGhcWithNativeCodeGen = "YES"+cGhcWithSMP :: String+cGhcWithSMP = "YES"+cGhcRTSWays :: String+cGhcRTSWays = "l debug thr thr_debug thr_l dyn debug_dyn thr_dyn thr_debug_dyn l_dyn thr_l_dyn"+cGhcRtsWithLibdw :: Bool+cGhcRtsWithLibdw = False+cGhcEnableTablesNextToCode :: String+cGhcEnableTablesNextToCode = "YES"+cLeadingUnderscore :: String+cLeadingUnderscore = "NO"+cGHC_UNLIT_PGM :: String+cGHC_UNLIT_PGM = "unlit"+cGHC_SPLIT_PGM :: String+cGHC_SPLIT_PGM = "ghc-split"+cLibFFI :: Bool+cLibFFI = False+cGhcThreaded :: Bool+cGhcThreaded = True+cGhcDebugged :: Bool+cGhcDebugged = False
+ autogen/GHCConstantsHaskellExports.hs view
@@ -0,0 +1,125 @@+ cONTROL_GROUP_CONST_291,+ sTD_HDR_SIZE,+ pROF_HDR_SIZE,+ bLOCK_SIZE,+ bLOCKS_PER_MBLOCK,+ tICKY_BIN_COUNT,+ oFFSET_StgRegTable_rR1,+ oFFSET_StgRegTable_rR2,+ oFFSET_StgRegTable_rR3,+ oFFSET_StgRegTable_rR4,+ oFFSET_StgRegTable_rR5,+ oFFSET_StgRegTable_rR6,+ oFFSET_StgRegTable_rR7,+ oFFSET_StgRegTable_rR8,+ oFFSET_StgRegTable_rR9,+ oFFSET_StgRegTable_rR10,+ oFFSET_StgRegTable_rF1,+ oFFSET_StgRegTable_rF2,+ oFFSET_StgRegTable_rF3,+ oFFSET_StgRegTable_rF4,+ oFFSET_StgRegTable_rF5,+ oFFSET_StgRegTable_rF6,+ oFFSET_StgRegTable_rD1,+ oFFSET_StgRegTable_rD2,+ oFFSET_StgRegTable_rD3,+ oFFSET_StgRegTable_rD4,+ oFFSET_StgRegTable_rD5,+ oFFSET_StgRegTable_rD6,+ oFFSET_StgRegTable_rXMM1,+ oFFSET_StgRegTable_rXMM2,+ oFFSET_StgRegTable_rXMM3,+ oFFSET_StgRegTable_rXMM4,+ oFFSET_StgRegTable_rXMM5,+ oFFSET_StgRegTable_rXMM6,+ oFFSET_StgRegTable_rYMM1,+ oFFSET_StgRegTable_rYMM2,+ oFFSET_StgRegTable_rYMM3,+ oFFSET_StgRegTable_rYMM4,+ oFFSET_StgRegTable_rYMM5,+ oFFSET_StgRegTable_rYMM6,+ oFFSET_StgRegTable_rZMM1,+ oFFSET_StgRegTable_rZMM2,+ oFFSET_StgRegTable_rZMM3,+ oFFSET_StgRegTable_rZMM4,+ oFFSET_StgRegTable_rZMM5,+ oFFSET_StgRegTable_rZMM6,+ oFFSET_StgRegTable_rL1,+ oFFSET_StgRegTable_rSp,+ oFFSET_StgRegTable_rSpLim,+ oFFSET_StgRegTable_rHp,+ oFFSET_StgRegTable_rHpLim,+ oFFSET_StgRegTable_rCCCS,+ oFFSET_StgRegTable_rCurrentTSO,+ oFFSET_StgRegTable_rCurrentNursery,+ oFFSET_StgRegTable_rHpAlloc,+ oFFSET_stgEagerBlackholeInfo,+ oFFSET_stgGCEnter1,+ oFFSET_stgGCFun,+ oFFSET_Capability_r,+ oFFSET_bdescr_start,+ oFFSET_bdescr_free,+ oFFSET_bdescr_blocks,+ oFFSET_bdescr_flags,+ sIZEOF_CostCentreStack,+ oFFSET_CostCentreStack_mem_alloc,+ oFFSET_CostCentreStack_scc_count,+ oFFSET_StgHeader_ccs,+ oFFSET_StgHeader_ldvw,+ sIZEOF_StgSMPThunkHeader,+ oFFSET_StgEntCounter_allocs,+ oFFSET_StgEntCounter_allocd,+ oFFSET_StgEntCounter_registeredp,+ oFFSET_StgEntCounter_link,+ oFFSET_StgEntCounter_entry_count,+ sIZEOF_StgUpdateFrame_NoHdr,+ sIZEOF_StgMutArrPtrs_NoHdr,+ oFFSET_StgMutArrPtrs_ptrs,+ oFFSET_StgMutArrPtrs_size,+ sIZEOF_StgSmallMutArrPtrs_NoHdr,+ oFFSET_StgSmallMutArrPtrs_ptrs,+ sIZEOF_StgArrBytes_NoHdr,+ oFFSET_StgArrBytes_bytes,+ oFFSET_StgTSO_alloc_limit,+ oFFSET_StgTSO_cccs,+ oFFSET_StgTSO_stackobj,+ oFFSET_StgStack_sp,+ oFFSET_StgStack_stack,+ oFFSET_StgUpdateFrame_updatee,+ oFFSET_StgFunInfoExtraFwd_arity,+ sIZEOF_StgFunInfoExtraRev,+ oFFSET_StgFunInfoExtraRev_arity,+ mAX_SPEC_SELECTEE_SIZE,+ mAX_SPEC_AP_SIZE,+ mIN_PAYLOAD_SIZE,+ mIN_INTLIKE,+ mAX_INTLIKE,+ mIN_CHARLIKE,+ mAX_CHARLIKE,+ mUT_ARR_PTRS_CARD_BITS,+ mAX_Vanilla_REG,+ mAX_Float_REG,+ mAX_Double_REG,+ mAX_Long_REG,+ mAX_XMM_REG,+ mAX_Real_Vanilla_REG,+ mAX_Real_Float_REG,+ mAX_Real_Double_REG,+ mAX_Real_XMM_REG,+ mAX_Real_Long_REG,+ rESERVED_C_STACK_BYTES,+ rESERVED_STACK_WORDS,+ aP_STACK_SPLIM,+ wORD_SIZE,+ dOUBLE_SIZE,+ cINT_SIZE,+ cLONG_SIZE,+ cLONG_LONG_SIZE,+ bITMAP_BITS_SHIFT,+ tAG_BITS,+ wORDS_BIGENDIAN,+ dYNAMIC_BY_DEFAULT,+ lDV_SHIFT,+ iLDV_CREATE_MASK,+ iLDV_STATE_CREATE,+ iLDV_STATE_USE,
+ autogen/GHCConstantsHaskellType.hs view
@@ -0,0 +1,134 @@+data PlatformConstants = PlatformConstants {+ pc_platformConstants :: ()+ , pc_CONTROL_GROUP_CONST_291 :: Int+ , pc_STD_HDR_SIZE :: Int+ , pc_PROF_HDR_SIZE :: Int+ , pc_BLOCK_SIZE :: Int+ , pc_BLOCKS_PER_MBLOCK :: Int+ , pc_TICKY_BIN_COUNT :: Int+ , pc_OFFSET_StgRegTable_rR1 :: Int+ , pc_OFFSET_StgRegTable_rR2 :: Int+ , pc_OFFSET_StgRegTable_rR3 :: Int+ , pc_OFFSET_StgRegTable_rR4 :: Int+ , pc_OFFSET_StgRegTable_rR5 :: Int+ , pc_OFFSET_StgRegTable_rR6 :: Int+ , pc_OFFSET_StgRegTable_rR7 :: Int+ , pc_OFFSET_StgRegTable_rR8 :: Int+ , pc_OFFSET_StgRegTable_rR9 :: Int+ , pc_OFFSET_StgRegTable_rR10 :: Int+ , pc_OFFSET_StgRegTable_rF1 :: Int+ , pc_OFFSET_StgRegTable_rF2 :: Int+ , pc_OFFSET_StgRegTable_rF3 :: Int+ , pc_OFFSET_StgRegTable_rF4 :: Int+ , pc_OFFSET_StgRegTable_rF5 :: Int+ , pc_OFFSET_StgRegTable_rF6 :: Int+ , pc_OFFSET_StgRegTable_rD1 :: Int+ , pc_OFFSET_StgRegTable_rD2 :: Int+ , pc_OFFSET_StgRegTable_rD3 :: Int+ , pc_OFFSET_StgRegTable_rD4 :: Int+ , pc_OFFSET_StgRegTable_rD5 :: Int+ , pc_OFFSET_StgRegTable_rD6 :: Int+ , pc_OFFSET_StgRegTable_rXMM1 :: Int+ , pc_OFFSET_StgRegTable_rXMM2 :: Int+ , pc_OFFSET_StgRegTable_rXMM3 :: Int+ , pc_OFFSET_StgRegTable_rXMM4 :: Int+ , pc_OFFSET_StgRegTable_rXMM5 :: Int+ , pc_OFFSET_StgRegTable_rXMM6 :: Int+ , pc_OFFSET_StgRegTable_rYMM1 :: Int+ , pc_OFFSET_StgRegTable_rYMM2 :: Int+ , pc_OFFSET_StgRegTable_rYMM3 :: Int+ , pc_OFFSET_StgRegTable_rYMM4 :: Int+ , pc_OFFSET_StgRegTable_rYMM5 :: Int+ , pc_OFFSET_StgRegTable_rYMM6 :: Int+ , pc_OFFSET_StgRegTable_rZMM1 :: Int+ , pc_OFFSET_StgRegTable_rZMM2 :: Int+ , pc_OFFSET_StgRegTable_rZMM3 :: Int+ , pc_OFFSET_StgRegTable_rZMM4 :: Int+ , pc_OFFSET_StgRegTable_rZMM5 :: Int+ , pc_OFFSET_StgRegTable_rZMM6 :: Int+ , pc_OFFSET_StgRegTable_rL1 :: Int+ , pc_OFFSET_StgRegTable_rSp :: Int+ , pc_OFFSET_StgRegTable_rSpLim :: Int+ , pc_OFFSET_StgRegTable_rHp :: Int+ , pc_OFFSET_StgRegTable_rHpLim :: Int+ , pc_OFFSET_StgRegTable_rCCCS :: Int+ , pc_OFFSET_StgRegTable_rCurrentTSO :: Int+ , pc_OFFSET_StgRegTable_rCurrentNursery :: Int+ , pc_OFFSET_StgRegTable_rHpAlloc :: Int+ , pc_OFFSET_stgEagerBlackholeInfo :: Int+ , pc_OFFSET_stgGCEnter1 :: Int+ , pc_OFFSET_stgGCFun :: Int+ , pc_OFFSET_Capability_r :: Int+ , pc_OFFSET_bdescr_start :: Int+ , pc_OFFSET_bdescr_free :: Int+ , pc_OFFSET_bdescr_blocks :: Int+ , pc_OFFSET_bdescr_flags :: Int+ , pc_SIZEOF_CostCentreStack :: Int+ , pc_OFFSET_CostCentreStack_mem_alloc :: Int+ , pc_REP_CostCentreStack_mem_alloc :: Int+ , pc_OFFSET_CostCentreStack_scc_count :: Int+ , pc_REP_CostCentreStack_scc_count :: Int+ , pc_OFFSET_StgHeader_ccs :: Int+ , pc_OFFSET_StgHeader_ldvw :: Int+ , pc_SIZEOF_StgSMPThunkHeader :: Int+ , pc_OFFSET_StgEntCounter_allocs :: Int+ , pc_REP_StgEntCounter_allocs :: Int+ , pc_OFFSET_StgEntCounter_allocd :: Int+ , pc_REP_StgEntCounter_allocd :: Int+ , pc_OFFSET_StgEntCounter_registeredp :: Int+ , pc_OFFSET_StgEntCounter_link :: Int+ , pc_OFFSET_StgEntCounter_entry_count :: Int+ , pc_SIZEOF_StgUpdateFrame_NoHdr :: Int+ , pc_SIZEOF_StgMutArrPtrs_NoHdr :: Int+ , pc_OFFSET_StgMutArrPtrs_ptrs :: Int+ , pc_OFFSET_StgMutArrPtrs_size :: Int+ , pc_SIZEOF_StgSmallMutArrPtrs_NoHdr :: Int+ , pc_OFFSET_StgSmallMutArrPtrs_ptrs :: Int+ , pc_SIZEOF_StgArrBytes_NoHdr :: Int+ , pc_OFFSET_StgArrBytes_bytes :: Int+ , pc_OFFSET_StgTSO_alloc_limit :: Int+ , pc_OFFSET_StgTSO_cccs :: Int+ , pc_OFFSET_StgTSO_stackobj :: Int+ , pc_OFFSET_StgStack_sp :: Int+ , pc_OFFSET_StgStack_stack :: Int+ , pc_OFFSET_StgUpdateFrame_updatee :: Int+ , pc_OFFSET_StgFunInfoExtraFwd_arity :: Int+ , pc_REP_StgFunInfoExtraFwd_arity :: Int+ , pc_SIZEOF_StgFunInfoExtraRev :: Int+ , pc_OFFSET_StgFunInfoExtraRev_arity :: Int+ , pc_REP_StgFunInfoExtraRev_arity :: Int+ , pc_MAX_SPEC_SELECTEE_SIZE :: Int+ , pc_MAX_SPEC_AP_SIZE :: Int+ , pc_MIN_PAYLOAD_SIZE :: Int+ , pc_MIN_INTLIKE :: Int+ , pc_MAX_INTLIKE :: Int+ , pc_MIN_CHARLIKE :: Int+ , pc_MAX_CHARLIKE :: Int+ , pc_MUT_ARR_PTRS_CARD_BITS :: Int+ , pc_MAX_Vanilla_REG :: Int+ , pc_MAX_Float_REG :: Int+ , pc_MAX_Double_REG :: Int+ , pc_MAX_Long_REG :: Int+ , pc_MAX_XMM_REG :: Int+ , pc_MAX_Real_Vanilla_REG :: Int+ , pc_MAX_Real_Float_REG :: Int+ , pc_MAX_Real_Double_REG :: Int+ , pc_MAX_Real_XMM_REG :: Int+ , pc_MAX_Real_Long_REG :: Int+ , pc_RESERVED_C_STACK_BYTES :: Int+ , pc_RESERVED_STACK_WORDS :: Int+ , pc_AP_STACK_SPLIM :: Int+ , pc_WORD_SIZE :: Int+ , pc_DOUBLE_SIZE :: Int+ , pc_CINT_SIZE :: Int+ , pc_CLONG_SIZE :: Int+ , pc_CLONG_LONG_SIZE :: Int+ , pc_BITMAP_BITS_SHIFT :: Int+ , pc_TAG_BITS :: Int+ , pc_WORDS_BIGENDIAN :: Bool+ , pc_DYNAMIC_BY_DEFAULT :: Bool+ , pc_LDV_SHIFT :: Int+ , pc_ILDV_CREATE_MASK :: Integer+ , pc_ILDV_STATE_CREATE :: Integer+ , pc_ILDV_STATE_USE :: Integer+ } deriving Read
+ autogen/GHCConstantsHaskellWrappers.hs view
@@ -0,0 +1,250 @@+cONTROL_GROUP_CONST_291 :: DynFlags -> Int+cONTROL_GROUP_CONST_291 dflags = pc_CONTROL_GROUP_CONST_291 (sPlatformConstants (settings dflags))+sTD_HDR_SIZE :: DynFlags -> Int+sTD_HDR_SIZE dflags = pc_STD_HDR_SIZE (sPlatformConstants (settings dflags))+pROF_HDR_SIZE :: DynFlags -> Int+pROF_HDR_SIZE dflags = pc_PROF_HDR_SIZE (sPlatformConstants (settings dflags))+bLOCK_SIZE :: DynFlags -> Int+bLOCK_SIZE dflags = pc_BLOCK_SIZE (sPlatformConstants (settings dflags))+bLOCKS_PER_MBLOCK :: DynFlags -> Int+bLOCKS_PER_MBLOCK dflags = pc_BLOCKS_PER_MBLOCK (sPlatformConstants (settings dflags))+tICKY_BIN_COUNT :: DynFlags -> Int+tICKY_BIN_COUNT dflags = pc_TICKY_BIN_COUNT (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR1 :: DynFlags -> Int+oFFSET_StgRegTable_rR1 dflags = pc_OFFSET_StgRegTable_rR1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR2 :: DynFlags -> Int+oFFSET_StgRegTable_rR2 dflags = pc_OFFSET_StgRegTable_rR2 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR3 :: DynFlags -> Int+oFFSET_StgRegTable_rR3 dflags = pc_OFFSET_StgRegTable_rR3 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR4 :: DynFlags -> Int+oFFSET_StgRegTable_rR4 dflags = pc_OFFSET_StgRegTable_rR4 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR5 :: DynFlags -> Int+oFFSET_StgRegTable_rR5 dflags = pc_OFFSET_StgRegTable_rR5 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR6 :: DynFlags -> Int+oFFSET_StgRegTable_rR6 dflags = pc_OFFSET_StgRegTable_rR6 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR7 :: DynFlags -> Int+oFFSET_StgRegTable_rR7 dflags = pc_OFFSET_StgRegTable_rR7 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR8 :: DynFlags -> Int+oFFSET_StgRegTable_rR8 dflags = pc_OFFSET_StgRegTable_rR8 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR9 :: DynFlags -> Int+oFFSET_StgRegTable_rR9 dflags = pc_OFFSET_StgRegTable_rR9 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rR10 :: DynFlags -> Int+oFFSET_StgRegTable_rR10 dflags = pc_OFFSET_StgRegTable_rR10 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rF1 :: DynFlags -> Int+oFFSET_StgRegTable_rF1 dflags = pc_OFFSET_StgRegTable_rF1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rF2 :: DynFlags -> Int+oFFSET_StgRegTable_rF2 dflags = pc_OFFSET_StgRegTable_rF2 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rF3 :: DynFlags -> Int+oFFSET_StgRegTable_rF3 dflags = pc_OFFSET_StgRegTable_rF3 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rF4 :: DynFlags -> Int+oFFSET_StgRegTable_rF4 dflags = pc_OFFSET_StgRegTable_rF4 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rF5 :: DynFlags -> Int+oFFSET_StgRegTable_rF5 dflags = pc_OFFSET_StgRegTable_rF5 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rF6 :: DynFlags -> Int+oFFSET_StgRegTable_rF6 dflags = pc_OFFSET_StgRegTable_rF6 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rD1 :: DynFlags -> Int+oFFSET_StgRegTable_rD1 dflags = pc_OFFSET_StgRegTable_rD1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rD2 :: DynFlags -> Int+oFFSET_StgRegTable_rD2 dflags = pc_OFFSET_StgRegTable_rD2 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rD3 :: DynFlags -> Int+oFFSET_StgRegTable_rD3 dflags = pc_OFFSET_StgRegTable_rD3 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rD4 :: DynFlags -> Int+oFFSET_StgRegTable_rD4 dflags = pc_OFFSET_StgRegTable_rD4 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rD5 :: DynFlags -> Int+oFFSET_StgRegTable_rD5 dflags = pc_OFFSET_StgRegTable_rD5 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rD6 :: DynFlags -> Int+oFFSET_StgRegTable_rD6 dflags = pc_OFFSET_StgRegTable_rD6 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rXMM1 :: DynFlags -> Int+oFFSET_StgRegTable_rXMM1 dflags = pc_OFFSET_StgRegTable_rXMM1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rXMM2 :: DynFlags -> Int+oFFSET_StgRegTable_rXMM2 dflags = pc_OFFSET_StgRegTable_rXMM2 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rXMM3 :: DynFlags -> Int+oFFSET_StgRegTable_rXMM3 dflags = pc_OFFSET_StgRegTable_rXMM3 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rXMM4 :: DynFlags -> Int+oFFSET_StgRegTable_rXMM4 dflags = pc_OFFSET_StgRegTable_rXMM4 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rXMM5 :: DynFlags -> Int+oFFSET_StgRegTable_rXMM5 dflags = pc_OFFSET_StgRegTable_rXMM5 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rXMM6 :: DynFlags -> Int+oFFSET_StgRegTable_rXMM6 dflags = pc_OFFSET_StgRegTable_rXMM6 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rYMM1 :: DynFlags -> Int+oFFSET_StgRegTable_rYMM1 dflags = pc_OFFSET_StgRegTable_rYMM1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rYMM2 :: DynFlags -> Int+oFFSET_StgRegTable_rYMM2 dflags = pc_OFFSET_StgRegTable_rYMM2 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rYMM3 :: DynFlags -> Int+oFFSET_StgRegTable_rYMM3 dflags = pc_OFFSET_StgRegTable_rYMM3 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rYMM4 :: DynFlags -> Int+oFFSET_StgRegTable_rYMM4 dflags = pc_OFFSET_StgRegTable_rYMM4 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rYMM5 :: DynFlags -> Int+oFFSET_StgRegTable_rYMM5 dflags = pc_OFFSET_StgRegTable_rYMM5 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rYMM6 :: DynFlags -> Int+oFFSET_StgRegTable_rYMM6 dflags = pc_OFFSET_StgRegTable_rYMM6 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rZMM1 :: DynFlags -> Int+oFFSET_StgRegTable_rZMM1 dflags = pc_OFFSET_StgRegTable_rZMM1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rZMM2 :: DynFlags -> Int+oFFSET_StgRegTable_rZMM2 dflags = pc_OFFSET_StgRegTable_rZMM2 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rZMM3 :: DynFlags -> Int+oFFSET_StgRegTable_rZMM3 dflags = pc_OFFSET_StgRegTable_rZMM3 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rZMM4 :: DynFlags -> Int+oFFSET_StgRegTable_rZMM4 dflags = pc_OFFSET_StgRegTable_rZMM4 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rZMM5 :: DynFlags -> Int+oFFSET_StgRegTable_rZMM5 dflags = pc_OFFSET_StgRegTable_rZMM5 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rZMM6 :: DynFlags -> Int+oFFSET_StgRegTable_rZMM6 dflags = pc_OFFSET_StgRegTable_rZMM6 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rL1 :: DynFlags -> Int+oFFSET_StgRegTable_rL1 dflags = pc_OFFSET_StgRegTable_rL1 (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rSp :: DynFlags -> Int+oFFSET_StgRegTable_rSp dflags = pc_OFFSET_StgRegTable_rSp (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rSpLim :: DynFlags -> Int+oFFSET_StgRegTable_rSpLim dflags = pc_OFFSET_StgRegTable_rSpLim (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rHp :: DynFlags -> Int+oFFSET_StgRegTable_rHp dflags = pc_OFFSET_StgRegTable_rHp (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rHpLim :: DynFlags -> Int+oFFSET_StgRegTable_rHpLim dflags = pc_OFFSET_StgRegTable_rHpLim (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rCCCS :: DynFlags -> Int+oFFSET_StgRegTable_rCCCS dflags = pc_OFFSET_StgRegTable_rCCCS (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rCurrentTSO :: DynFlags -> Int+oFFSET_StgRegTable_rCurrentTSO dflags = pc_OFFSET_StgRegTable_rCurrentTSO (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rCurrentNursery :: DynFlags -> Int+oFFSET_StgRegTable_rCurrentNursery dflags = pc_OFFSET_StgRegTable_rCurrentNursery (sPlatformConstants (settings dflags))+oFFSET_StgRegTable_rHpAlloc :: DynFlags -> Int+oFFSET_StgRegTable_rHpAlloc dflags = pc_OFFSET_StgRegTable_rHpAlloc (sPlatformConstants (settings dflags))+oFFSET_stgEagerBlackholeInfo :: DynFlags -> Int+oFFSET_stgEagerBlackholeInfo dflags = pc_OFFSET_stgEagerBlackholeInfo (sPlatformConstants (settings dflags))+oFFSET_stgGCEnter1 :: DynFlags -> Int+oFFSET_stgGCEnter1 dflags = pc_OFFSET_stgGCEnter1 (sPlatformConstants (settings dflags))+oFFSET_stgGCFun :: DynFlags -> Int+oFFSET_stgGCFun dflags = pc_OFFSET_stgGCFun (sPlatformConstants (settings dflags))+oFFSET_Capability_r :: DynFlags -> Int+oFFSET_Capability_r dflags = pc_OFFSET_Capability_r (sPlatformConstants (settings dflags))+oFFSET_bdescr_start :: DynFlags -> Int+oFFSET_bdescr_start dflags = pc_OFFSET_bdescr_start (sPlatformConstants (settings dflags))+oFFSET_bdescr_free :: DynFlags -> Int+oFFSET_bdescr_free dflags = pc_OFFSET_bdescr_free (sPlatformConstants (settings dflags))+oFFSET_bdescr_blocks :: DynFlags -> Int+oFFSET_bdescr_blocks dflags = pc_OFFSET_bdescr_blocks (sPlatformConstants (settings dflags))+oFFSET_bdescr_flags :: DynFlags -> Int+oFFSET_bdescr_flags dflags = pc_OFFSET_bdescr_flags (sPlatformConstants (settings dflags))+sIZEOF_CostCentreStack :: DynFlags -> Int+sIZEOF_CostCentreStack dflags = pc_SIZEOF_CostCentreStack (sPlatformConstants (settings dflags))+oFFSET_CostCentreStack_mem_alloc :: DynFlags -> Int+oFFSET_CostCentreStack_mem_alloc dflags = pc_OFFSET_CostCentreStack_mem_alloc (sPlatformConstants (settings dflags))+oFFSET_CostCentreStack_scc_count :: DynFlags -> Int+oFFSET_CostCentreStack_scc_count dflags = pc_OFFSET_CostCentreStack_scc_count (sPlatformConstants (settings dflags))+oFFSET_StgHeader_ccs :: DynFlags -> Int+oFFSET_StgHeader_ccs dflags = pc_OFFSET_StgHeader_ccs (sPlatformConstants (settings dflags))+oFFSET_StgHeader_ldvw :: DynFlags -> Int+oFFSET_StgHeader_ldvw dflags = pc_OFFSET_StgHeader_ldvw (sPlatformConstants (settings dflags))+sIZEOF_StgSMPThunkHeader :: DynFlags -> Int+sIZEOF_StgSMPThunkHeader dflags = pc_SIZEOF_StgSMPThunkHeader (sPlatformConstants (settings dflags))+oFFSET_StgEntCounter_allocs :: DynFlags -> Int+oFFSET_StgEntCounter_allocs dflags = pc_OFFSET_StgEntCounter_allocs (sPlatformConstants (settings dflags))+oFFSET_StgEntCounter_allocd :: DynFlags -> Int+oFFSET_StgEntCounter_allocd dflags = pc_OFFSET_StgEntCounter_allocd (sPlatformConstants (settings dflags))+oFFSET_StgEntCounter_registeredp :: DynFlags -> Int+oFFSET_StgEntCounter_registeredp dflags = pc_OFFSET_StgEntCounter_registeredp (sPlatformConstants (settings dflags))+oFFSET_StgEntCounter_link :: DynFlags -> Int+oFFSET_StgEntCounter_link dflags = pc_OFFSET_StgEntCounter_link (sPlatformConstants (settings dflags))+oFFSET_StgEntCounter_entry_count :: DynFlags -> Int+oFFSET_StgEntCounter_entry_count dflags = pc_OFFSET_StgEntCounter_entry_count (sPlatformConstants (settings dflags))+sIZEOF_StgUpdateFrame_NoHdr :: DynFlags -> Int+sIZEOF_StgUpdateFrame_NoHdr dflags = pc_SIZEOF_StgUpdateFrame_NoHdr (sPlatformConstants (settings dflags))+sIZEOF_StgMutArrPtrs_NoHdr :: DynFlags -> Int+sIZEOF_StgMutArrPtrs_NoHdr dflags = pc_SIZEOF_StgMutArrPtrs_NoHdr (sPlatformConstants (settings dflags))+oFFSET_StgMutArrPtrs_ptrs :: DynFlags -> Int+oFFSET_StgMutArrPtrs_ptrs dflags = pc_OFFSET_StgMutArrPtrs_ptrs (sPlatformConstants (settings dflags))+oFFSET_StgMutArrPtrs_size :: DynFlags -> Int+oFFSET_StgMutArrPtrs_size dflags = pc_OFFSET_StgMutArrPtrs_size (sPlatformConstants (settings dflags))+sIZEOF_StgSmallMutArrPtrs_NoHdr :: DynFlags -> Int+sIZEOF_StgSmallMutArrPtrs_NoHdr dflags = pc_SIZEOF_StgSmallMutArrPtrs_NoHdr (sPlatformConstants (settings dflags))+oFFSET_StgSmallMutArrPtrs_ptrs :: DynFlags -> Int+oFFSET_StgSmallMutArrPtrs_ptrs dflags = pc_OFFSET_StgSmallMutArrPtrs_ptrs (sPlatformConstants (settings dflags))+sIZEOF_StgArrBytes_NoHdr :: DynFlags -> Int+sIZEOF_StgArrBytes_NoHdr dflags = pc_SIZEOF_StgArrBytes_NoHdr (sPlatformConstants (settings dflags))+oFFSET_StgArrBytes_bytes :: DynFlags -> Int+oFFSET_StgArrBytes_bytes dflags = pc_OFFSET_StgArrBytes_bytes (sPlatformConstants (settings dflags))+oFFSET_StgTSO_alloc_limit :: DynFlags -> Int+oFFSET_StgTSO_alloc_limit dflags = pc_OFFSET_StgTSO_alloc_limit (sPlatformConstants (settings dflags))+oFFSET_StgTSO_cccs :: DynFlags -> Int+oFFSET_StgTSO_cccs dflags = pc_OFFSET_StgTSO_cccs (sPlatformConstants (settings dflags))+oFFSET_StgTSO_stackobj :: DynFlags -> Int+oFFSET_StgTSO_stackobj dflags = pc_OFFSET_StgTSO_stackobj (sPlatformConstants (settings dflags))+oFFSET_StgStack_sp :: DynFlags -> Int+oFFSET_StgStack_sp dflags = pc_OFFSET_StgStack_sp (sPlatformConstants (settings dflags))+oFFSET_StgStack_stack :: DynFlags -> Int+oFFSET_StgStack_stack dflags = pc_OFFSET_StgStack_stack (sPlatformConstants (settings dflags))+oFFSET_StgUpdateFrame_updatee :: DynFlags -> Int+oFFSET_StgUpdateFrame_updatee dflags = pc_OFFSET_StgUpdateFrame_updatee (sPlatformConstants (settings dflags))+oFFSET_StgFunInfoExtraFwd_arity :: DynFlags -> Int+oFFSET_StgFunInfoExtraFwd_arity dflags = pc_OFFSET_StgFunInfoExtraFwd_arity (sPlatformConstants (settings dflags))+sIZEOF_StgFunInfoExtraRev :: DynFlags -> Int+sIZEOF_StgFunInfoExtraRev dflags = pc_SIZEOF_StgFunInfoExtraRev (sPlatformConstants (settings dflags))+oFFSET_StgFunInfoExtraRev_arity :: DynFlags -> Int+oFFSET_StgFunInfoExtraRev_arity dflags = pc_OFFSET_StgFunInfoExtraRev_arity (sPlatformConstants (settings dflags))+mAX_SPEC_SELECTEE_SIZE :: DynFlags -> Int+mAX_SPEC_SELECTEE_SIZE dflags = pc_MAX_SPEC_SELECTEE_SIZE (sPlatformConstants (settings dflags))+mAX_SPEC_AP_SIZE :: DynFlags -> Int+mAX_SPEC_AP_SIZE dflags = pc_MAX_SPEC_AP_SIZE (sPlatformConstants (settings dflags))+mIN_PAYLOAD_SIZE :: DynFlags -> Int+mIN_PAYLOAD_SIZE dflags = pc_MIN_PAYLOAD_SIZE (sPlatformConstants (settings dflags))+mIN_INTLIKE :: DynFlags -> Int+mIN_INTLIKE dflags = pc_MIN_INTLIKE (sPlatformConstants (settings dflags))+mAX_INTLIKE :: DynFlags -> Int+mAX_INTLIKE dflags = pc_MAX_INTLIKE (sPlatformConstants (settings dflags))+mIN_CHARLIKE :: DynFlags -> Int+mIN_CHARLIKE dflags = pc_MIN_CHARLIKE (sPlatformConstants (settings dflags))+mAX_CHARLIKE :: DynFlags -> Int+mAX_CHARLIKE dflags = pc_MAX_CHARLIKE (sPlatformConstants (settings dflags))+mUT_ARR_PTRS_CARD_BITS :: DynFlags -> Int+mUT_ARR_PTRS_CARD_BITS dflags = pc_MUT_ARR_PTRS_CARD_BITS (sPlatformConstants (settings dflags))+mAX_Vanilla_REG :: DynFlags -> Int+mAX_Vanilla_REG dflags = pc_MAX_Vanilla_REG (sPlatformConstants (settings dflags))+mAX_Float_REG :: DynFlags -> Int+mAX_Float_REG dflags = pc_MAX_Float_REG (sPlatformConstants (settings dflags))+mAX_Double_REG :: DynFlags -> Int+mAX_Double_REG dflags = pc_MAX_Double_REG (sPlatformConstants (settings dflags))+mAX_Long_REG :: DynFlags -> Int+mAX_Long_REG dflags = pc_MAX_Long_REG (sPlatformConstants (settings dflags))+mAX_XMM_REG :: DynFlags -> Int+mAX_XMM_REG dflags = pc_MAX_XMM_REG (sPlatformConstants (settings dflags))+mAX_Real_Vanilla_REG :: DynFlags -> Int+mAX_Real_Vanilla_REG dflags = pc_MAX_Real_Vanilla_REG (sPlatformConstants (settings dflags))+mAX_Real_Float_REG :: DynFlags -> Int+mAX_Real_Float_REG dflags = pc_MAX_Real_Float_REG (sPlatformConstants (settings dflags))+mAX_Real_Double_REG :: DynFlags -> Int+mAX_Real_Double_REG dflags = pc_MAX_Real_Double_REG (sPlatformConstants (settings dflags))+mAX_Real_XMM_REG :: DynFlags -> Int+mAX_Real_XMM_REG dflags = pc_MAX_Real_XMM_REG (sPlatformConstants (settings dflags))+mAX_Real_Long_REG :: DynFlags -> Int+mAX_Real_Long_REG dflags = pc_MAX_Real_Long_REG (sPlatformConstants (settings dflags))+rESERVED_C_STACK_BYTES :: DynFlags -> Int+rESERVED_C_STACK_BYTES dflags = pc_RESERVED_C_STACK_BYTES (sPlatformConstants (settings dflags))+rESERVED_STACK_WORDS :: DynFlags -> Int+rESERVED_STACK_WORDS dflags = pc_RESERVED_STACK_WORDS (sPlatformConstants (settings dflags))+aP_STACK_SPLIM :: DynFlags -> Int+aP_STACK_SPLIM dflags = pc_AP_STACK_SPLIM (sPlatformConstants (settings dflags))+wORD_SIZE :: DynFlags -> Int+wORD_SIZE dflags = pc_WORD_SIZE (sPlatformConstants (settings dflags))+dOUBLE_SIZE :: DynFlags -> Int+dOUBLE_SIZE dflags = pc_DOUBLE_SIZE (sPlatformConstants (settings dflags))+cINT_SIZE :: DynFlags -> Int+cINT_SIZE dflags = pc_CINT_SIZE (sPlatformConstants (settings dflags))+cLONG_SIZE :: DynFlags -> Int+cLONG_SIZE dflags = pc_CLONG_SIZE (sPlatformConstants (settings dflags))+cLONG_LONG_SIZE :: DynFlags -> Int+cLONG_LONG_SIZE dflags = pc_CLONG_LONG_SIZE (sPlatformConstants (settings dflags))+bITMAP_BITS_SHIFT :: DynFlags -> Int+bITMAP_BITS_SHIFT dflags = pc_BITMAP_BITS_SHIFT (sPlatformConstants (settings dflags))+tAG_BITS :: DynFlags -> Int+tAG_BITS dflags = pc_TAG_BITS (sPlatformConstants (settings dflags))+wORDS_BIGENDIAN :: DynFlags -> Bool+wORDS_BIGENDIAN dflags = pc_WORDS_BIGENDIAN (sPlatformConstants (settings dflags))+dYNAMIC_BY_DEFAULT :: DynFlags -> Bool+dYNAMIC_BY_DEFAULT dflags = pc_DYNAMIC_BY_DEFAULT (sPlatformConstants (settings dflags))+lDV_SHIFT :: DynFlags -> Int+lDV_SHIFT dflags = pc_LDV_SHIFT (sPlatformConstants (settings dflags))+iLDV_CREATE_MASK :: DynFlags -> Integer+iLDV_CREATE_MASK dflags = pc_ILDV_CREATE_MASK (sPlatformConstants (settings dflags))+iLDV_STATE_CREATE :: DynFlags -> Integer+iLDV_STATE_CREATE dflags = pc_ILDV_STATE_CREATE (sPlatformConstants (settings dflags))+iLDV_STATE_USE :: DynFlags -> Integer+iLDV_STATE_USE dflags = pc_ILDV_STATE_USE (sPlatformConstants (settings dflags))
+ autogen/ghc_boot_platform.h view
@@ -0,0 +1,33 @@+#ifndef __PLATFORM_H__+#define __PLATFORM_H__++#define BuildPlatform_NAME "x86_64-unknown-linux"+#define HostPlatform_NAME "x86_64-unknown-linux"+#define TargetPlatform_NAME "x86_64-unknown-linux"++#define x86_64_unknown_linux_BUILD 1+#define x86_64_unknown_linux_HOST 1+#define x86_64_unknown_linux_TARGET 1++#define x86_64_BUILD_ARCH 1+#define x86_64_HOST_ARCH 1+#define x86_64_TARGET_ARCH 1+#define BUILD_ARCH "x86_64"+#define HOST_ARCH "x86_64"+#define TARGET_ARCH "x86_64"++#define linux_BUILD_OS 1+#define linux_HOST_OS 1+#define linux_TARGET_OS 1+#define BUILD_OS "linux"+#define HOST_OS "linux"+#define TARGET_OS "linux"++#define unknown_BUILD_VENDOR 1+#define unknown_HOST_VENDOR 1+#define unknown_TARGET_VENDOR 1+#define BUILD_VENDOR "unknown"+#define HOST_VENDOR "unknown"+#define TARGET_VENDOR "unknown"++#endif /* __PLATFORM_H__ */
+ autogen/primop-can-fail.hs-incl view
@@ -0,0 +1,178 @@+primOpCanFail IntQuotOp = True+primOpCanFail IntRemOp = True+primOpCanFail IntQuotRemOp = True+primOpCanFail WordQuotOp = True+primOpCanFail WordRemOp = True+primOpCanFail WordQuotRemOp = True+primOpCanFail WordQuotRem2Op = True+primOpCanFail DoubleDivOp = True+primOpCanFail DoubleLogOp = True+primOpCanFail DoubleAsinOp = True+primOpCanFail DoubleAcosOp = True+primOpCanFail FloatDivOp = True+primOpCanFail FloatLogOp = True+primOpCanFail FloatAsinOp = True+primOpCanFail FloatAcosOp = True+primOpCanFail ReadArrayOp = True+primOpCanFail WriteArrayOp = True+primOpCanFail IndexArrayOp = True+primOpCanFail CopyArrayOp = True+primOpCanFail CopyMutableArrayOp = True+primOpCanFail CloneArrayOp = True+primOpCanFail CloneMutableArrayOp = True+primOpCanFail FreezeArrayOp = True+primOpCanFail ThawArrayOp = True+primOpCanFail ReadSmallArrayOp = True+primOpCanFail WriteSmallArrayOp = True+primOpCanFail IndexSmallArrayOp = True+primOpCanFail CopySmallArrayOp = True+primOpCanFail CopySmallMutableArrayOp = True+primOpCanFail CloneSmallArrayOp = True+primOpCanFail CloneSmallMutableArrayOp = True+primOpCanFail FreezeSmallArrayOp = True+primOpCanFail ThawSmallArrayOp = True+primOpCanFail IndexByteArrayOp_Char = True+primOpCanFail IndexByteArrayOp_WideChar = True+primOpCanFail IndexByteArrayOp_Int = True+primOpCanFail IndexByteArrayOp_Word = True+primOpCanFail IndexByteArrayOp_Addr = True+primOpCanFail IndexByteArrayOp_Float = True+primOpCanFail IndexByteArrayOp_Double = True+primOpCanFail IndexByteArrayOp_StablePtr = True+primOpCanFail IndexByteArrayOp_Int8 = True+primOpCanFail IndexByteArrayOp_Int16 = True+primOpCanFail IndexByteArrayOp_Int32 = True+primOpCanFail IndexByteArrayOp_Int64 = True+primOpCanFail IndexByteArrayOp_Word8 = True+primOpCanFail IndexByteArrayOp_Word16 = True+primOpCanFail IndexByteArrayOp_Word32 = True+primOpCanFail IndexByteArrayOp_Word64 = True+primOpCanFail ReadByteArrayOp_Char = True+primOpCanFail ReadByteArrayOp_WideChar = True+primOpCanFail ReadByteArrayOp_Int = True+primOpCanFail ReadByteArrayOp_Word = True+primOpCanFail ReadByteArrayOp_Addr = True+primOpCanFail ReadByteArrayOp_Float = True+primOpCanFail ReadByteArrayOp_Double = True+primOpCanFail ReadByteArrayOp_StablePtr = True+primOpCanFail ReadByteArrayOp_Int8 = True+primOpCanFail ReadByteArrayOp_Int16 = True+primOpCanFail ReadByteArrayOp_Int32 = True+primOpCanFail ReadByteArrayOp_Int64 = True+primOpCanFail ReadByteArrayOp_Word8 = True+primOpCanFail ReadByteArrayOp_Word16 = True+primOpCanFail ReadByteArrayOp_Word32 = True+primOpCanFail ReadByteArrayOp_Word64 = True+primOpCanFail WriteByteArrayOp_Char = True+primOpCanFail WriteByteArrayOp_WideChar = True+primOpCanFail WriteByteArrayOp_Int = True+primOpCanFail WriteByteArrayOp_Word = True+primOpCanFail WriteByteArrayOp_Addr = True+primOpCanFail WriteByteArrayOp_Float = True+primOpCanFail WriteByteArrayOp_Double = True+primOpCanFail WriteByteArrayOp_StablePtr = True+primOpCanFail WriteByteArrayOp_Int8 = True+primOpCanFail WriteByteArrayOp_Int16 = True+primOpCanFail WriteByteArrayOp_Int32 = True+primOpCanFail WriteByteArrayOp_Int64 = True+primOpCanFail WriteByteArrayOp_Word8 = True+primOpCanFail WriteByteArrayOp_Word16 = True+primOpCanFail WriteByteArrayOp_Word32 = True+primOpCanFail WriteByteArrayOp_Word64 = True+primOpCanFail CopyByteArrayOp = True+primOpCanFail CopyMutableByteArrayOp = True+primOpCanFail CopyByteArrayToAddrOp = True+primOpCanFail CopyMutableByteArrayToAddrOp = True+primOpCanFail CopyAddrToByteArrayOp = True+primOpCanFail SetByteArrayOp = True+primOpCanFail AtomicReadByteArrayOp_Int = True+primOpCanFail AtomicWriteByteArrayOp_Int = True+primOpCanFail CasByteArrayOp_Int = True+primOpCanFail FetchAddByteArrayOp_Int = True+primOpCanFail FetchSubByteArrayOp_Int = True+primOpCanFail FetchAndByteArrayOp_Int = True+primOpCanFail FetchNandByteArrayOp_Int = True+primOpCanFail FetchOrByteArrayOp_Int = True+primOpCanFail FetchXorByteArrayOp_Int = True+primOpCanFail IndexArrayArrayOp_ByteArray = True+primOpCanFail IndexArrayArrayOp_ArrayArray = True+primOpCanFail ReadArrayArrayOp_ByteArray = True+primOpCanFail ReadArrayArrayOp_MutableByteArray = True+primOpCanFail ReadArrayArrayOp_ArrayArray = True+primOpCanFail ReadArrayArrayOp_MutableArrayArray = True+primOpCanFail WriteArrayArrayOp_ByteArray = True+primOpCanFail WriteArrayArrayOp_MutableByteArray = True+primOpCanFail WriteArrayArrayOp_ArrayArray = True+primOpCanFail WriteArrayArrayOp_MutableArrayArray = True+primOpCanFail CopyArrayArrayOp = True+primOpCanFail CopyMutableArrayArrayOp = True+primOpCanFail IndexOffAddrOp_Char = True+primOpCanFail IndexOffAddrOp_WideChar = True+primOpCanFail IndexOffAddrOp_Int = True+primOpCanFail IndexOffAddrOp_Word = True+primOpCanFail IndexOffAddrOp_Addr = True+primOpCanFail IndexOffAddrOp_Float = True+primOpCanFail IndexOffAddrOp_Double = True+primOpCanFail IndexOffAddrOp_StablePtr = True+primOpCanFail IndexOffAddrOp_Int8 = True+primOpCanFail IndexOffAddrOp_Int16 = True+primOpCanFail IndexOffAddrOp_Int32 = True+primOpCanFail IndexOffAddrOp_Int64 = True+primOpCanFail IndexOffAddrOp_Word8 = True+primOpCanFail IndexOffAddrOp_Word16 = True+primOpCanFail IndexOffAddrOp_Word32 = True+primOpCanFail IndexOffAddrOp_Word64 = True+primOpCanFail ReadOffAddrOp_Char = True+primOpCanFail ReadOffAddrOp_WideChar = True+primOpCanFail ReadOffAddrOp_Int = True+primOpCanFail ReadOffAddrOp_Word = True+primOpCanFail ReadOffAddrOp_Addr = True+primOpCanFail ReadOffAddrOp_Float = True+primOpCanFail ReadOffAddrOp_Double = True+primOpCanFail ReadOffAddrOp_StablePtr = True+primOpCanFail ReadOffAddrOp_Int8 = True+primOpCanFail ReadOffAddrOp_Int16 = True+primOpCanFail ReadOffAddrOp_Int32 = True+primOpCanFail ReadOffAddrOp_Int64 = True+primOpCanFail ReadOffAddrOp_Word8 = True+primOpCanFail ReadOffAddrOp_Word16 = True+primOpCanFail ReadOffAddrOp_Word32 = True+primOpCanFail ReadOffAddrOp_Word64 = True+primOpCanFail WriteOffAddrOp_Char = True+primOpCanFail WriteOffAddrOp_WideChar = True+primOpCanFail WriteOffAddrOp_Int = True+primOpCanFail WriteOffAddrOp_Word = True+primOpCanFail WriteOffAddrOp_Addr = True+primOpCanFail WriteOffAddrOp_Float = True+primOpCanFail WriteOffAddrOp_Double = True+primOpCanFail WriteOffAddrOp_StablePtr = True+primOpCanFail WriteOffAddrOp_Int8 = True+primOpCanFail WriteOffAddrOp_Int16 = True+primOpCanFail WriteOffAddrOp_Int32 = True+primOpCanFail WriteOffAddrOp_Int64 = True+primOpCanFail WriteOffAddrOp_Word8 = True+primOpCanFail WriteOffAddrOp_Word16 = True+primOpCanFail WriteOffAddrOp_Word32 = True+primOpCanFail WriteOffAddrOp_Word64 = True+primOpCanFail ReadMutVarOp = True+primOpCanFail WriteMutVarOp = True+primOpCanFail AtomicModifyMutVarOp = True+primOpCanFail ReallyUnsafePtrEqualityOp = True+primOpCanFail DataToTagOp = True+primOpCanFail (VecInsertOp _ _ _) = True+primOpCanFail (VecDivOp _ _ _) = True+primOpCanFail (VecQuotOp _ _ _) = True+primOpCanFail (VecRemOp _ _ _) = True+primOpCanFail (VecIndexByteArrayOp _ _ _) = True+primOpCanFail (VecReadByteArrayOp _ _ _) = True+primOpCanFail (VecWriteByteArrayOp _ _ _) = True+primOpCanFail (VecIndexOffAddrOp _ _ _) = True+primOpCanFail (VecReadOffAddrOp _ _ _) = True+primOpCanFail (VecWriteOffAddrOp _ _ _) = True+primOpCanFail (VecIndexScalarByteArrayOp _ _ _) = True+primOpCanFail (VecReadScalarByteArrayOp _ _ _) = True+primOpCanFail (VecWriteScalarByteArrayOp _ _ _) = True+primOpCanFail (VecIndexScalarOffAddrOp _ _ _) = True+primOpCanFail (VecReadScalarOffAddrOp _ _ _) = True+primOpCanFail (VecWriteScalarOffAddrOp _ _ _) = True+primOpCanFail _ = False
+ autogen/primop-code-size.hs-incl view
@@ -0,0 +1,48 @@+primOpCodeSize OrdOp = 0+primOpCodeSize IntAddCOp = 2+primOpCodeSize IntSubCOp = 2+primOpCodeSize ChrOp = 0+primOpCodeSize Int2WordOp = 0+primOpCodeSize Word2IntOp = 0+primOpCodeSize DoubleExpOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleLogOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleSqrtOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleSinOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleCosOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleTanOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleAsinOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleAcosOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleAtanOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleSinhOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleCoshOp = primOpCodeSizeForeignCall +primOpCodeSize DoubleTanhOp = primOpCodeSizeForeignCall +primOpCodeSize DoublePowerOp = primOpCodeSizeForeignCall +primOpCodeSize FloatExpOp = primOpCodeSizeForeignCall +primOpCodeSize FloatLogOp = primOpCodeSizeForeignCall +primOpCodeSize FloatSqrtOp = primOpCodeSizeForeignCall +primOpCodeSize FloatSinOp = primOpCodeSizeForeignCall +primOpCodeSize FloatCosOp = primOpCodeSizeForeignCall +primOpCodeSize FloatTanOp = primOpCodeSizeForeignCall +primOpCodeSize FloatAsinOp = primOpCodeSizeForeignCall +primOpCodeSize FloatAcosOp = primOpCodeSizeForeignCall +primOpCodeSize FloatAtanOp = primOpCodeSizeForeignCall +primOpCodeSize FloatSinhOp = primOpCodeSizeForeignCall +primOpCodeSize FloatCoshOp = primOpCodeSizeForeignCall +primOpCodeSize FloatTanhOp = primOpCodeSizeForeignCall +primOpCodeSize FloatPowerOp = primOpCodeSizeForeignCall +primOpCodeSize WriteArrayOp = 2+primOpCodeSize CopyByteArrayOp = primOpCodeSizeForeignCall + 4+primOpCodeSize CopyMutableByteArrayOp = primOpCodeSizeForeignCall + 4 +primOpCodeSize CopyByteArrayToAddrOp = primOpCodeSizeForeignCall + 4+primOpCodeSize CopyMutableByteArrayToAddrOp = primOpCodeSizeForeignCall + 4+primOpCodeSize CopyAddrToByteArrayOp = primOpCodeSizeForeignCall + 4+primOpCodeSize SetByteArrayOp = primOpCodeSizeForeignCall + 4 +primOpCodeSize Addr2IntOp = 0+primOpCodeSize Int2AddrOp = 0+primOpCodeSize WriteMutVarOp = primOpCodeSizeForeignCall +primOpCodeSize TouchOp = 0 +primOpCodeSize ParOp = primOpCodeSizeForeignCall +primOpCodeSize SparkOp = primOpCodeSizeForeignCall +primOpCodeSize AddrToAnyOp = 0+primOpCodeSize AnyToAddrOp = 0+primOpCodeSize _ = primOpCodeSizeDefault
+ autogen/primop-commutable.hs-incl view
@@ -0,0 +1,28 @@+commutableOp CharEqOp = True+commutableOp CharNeOp = True+commutableOp IntAddOp = True+commutableOp IntMulOp = True+commutableOp IntMulMayOfloOp = True+commutableOp AndIOp = True+commutableOp OrIOp = True+commutableOp XorIOp = True+commutableOp IntEqOp = True+commutableOp IntNeOp = True+commutableOp WordAddOp = True+commutableOp WordAdd2Op = True+commutableOp WordMulOp = True+commutableOp WordMul2Op = True+commutableOp AndOp = True+commutableOp OrOp = True+commutableOp XorOp = True+commutableOp DoubleEqOp = True+commutableOp DoubleNeOp = True+commutableOp DoubleAddOp = True+commutableOp DoubleMulOp = True+commutableOp FloatEqOp = True+commutableOp FloatNeOp = True+commutableOp FloatAddOp = True+commutableOp FloatMulOp = True+commutableOp (VecAddOp _ _ _) = True+commutableOp (VecMulOp _ _ _) = True+commutableOp _ = False
+ autogen/primop-data-decl.hs-incl view
@@ -0,0 +1,451 @@+data PrimOp+ = CharGtOp+ | CharGeOp+ | CharEqOp+ | CharNeOp+ | CharLtOp+ | CharLeOp+ | OrdOp+ | IntAddOp+ | IntSubOp+ | IntMulOp+ | IntMulMayOfloOp+ | IntQuotOp+ | IntRemOp+ | IntQuotRemOp+ | AndIOp+ | OrIOp+ | XorIOp+ | NotIOp+ | IntNegOp+ | IntAddCOp+ | IntSubCOp+ | IntGtOp+ | IntGeOp+ | IntEqOp+ | IntNeOp+ | IntLtOp+ | IntLeOp+ | ChrOp+ | Int2WordOp+ | Int2FloatOp+ | Int2DoubleOp+ | Word2FloatOp+ | Word2DoubleOp+ | ISllOp+ | ISraOp+ | ISrlOp+ | WordAddOp+ | WordSubCOp+ | WordAdd2Op+ | WordSubOp+ | WordMulOp+ | WordMul2Op+ | WordQuotOp+ | WordRemOp+ | WordQuotRemOp+ | WordQuotRem2Op+ | AndOp+ | OrOp+ | XorOp+ | NotOp+ | SllOp+ | SrlOp+ | Word2IntOp+ | WordGtOp+ | WordGeOp+ | WordEqOp+ | WordNeOp+ | WordLtOp+ | WordLeOp+ | PopCnt8Op+ | PopCnt16Op+ | PopCnt32Op+ | PopCnt64Op+ | PopCntOp+ | Clz8Op+ | Clz16Op+ | Clz32Op+ | Clz64Op+ | ClzOp+ | Ctz8Op+ | Ctz16Op+ | Ctz32Op+ | Ctz64Op+ | CtzOp+ | BSwap16Op+ | BSwap32Op+ | BSwap64Op+ | BSwapOp+ | Narrow8IntOp+ | Narrow16IntOp+ | Narrow32IntOp+ | Narrow8WordOp+ | Narrow16WordOp+ | Narrow32WordOp+ | DoubleGtOp+ | DoubleGeOp+ | DoubleEqOp+ | DoubleNeOp+ | DoubleLtOp+ | DoubleLeOp+ | DoubleAddOp+ | DoubleSubOp+ | DoubleMulOp+ | DoubleDivOp+ | DoubleNegOp+ | DoubleFabsOp+ | Double2IntOp+ | Double2FloatOp+ | DoubleExpOp+ | DoubleLogOp+ | DoubleSqrtOp+ | DoubleSinOp+ | DoubleCosOp+ | DoubleTanOp+ | DoubleAsinOp+ | DoubleAcosOp+ | DoubleAtanOp+ | DoubleSinhOp+ | DoubleCoshOp+ | DoubleTanhOp+ | DoublePowerOp+ | DoubleDecode_2IntOp+ | DoubleDecode_Int64Op+ | FloatGtOp+ | FloatGeOp+ | FloatEqOp+ | FloatNeOp+ | FloatLtOp+ | FloatLeOp+ | FloatAddOp+ | FloatSubOp+ | FloatMulOp+ | FloatDivOp+ | FloatNegOp+ | FloatFabsOp+ | Float2IntOp+ | FloatExpOp+ | FloatLogOp+ | FloatSqrtOp+ | FloatSinOp+ | FloatCosOp+ | FloatTanOp+ | FloatAsinOp+ | FloatAcosOp+ | FloatAtanOp+ | FloatSinhOp+ | FloatCoshOp+ | FloatTanhOp+ | FloatPowerOp+ | Float2DoubleOp+ | FloatDecode_IntOp+ | NewArrayOp+ | SameMutableArrayOp+ | ReadArrayOp+ | WriteArrayOp+ | SizeofArrayOp+ | SizeofMutableArrayOp+ | IndexArrayOp+ | UnsafeFreezeArrayOp+ | UnsafeThawArrayOp+ | CopyArrayOp+ | CopyMutableArrayOp+ | CloneArrayOp+ | CloneMutableArrayOp+ | FreezeArrayOp+ | ThawArrayOp+ | CasArrayOp+ | NewSmallArrayOp+ | SameSmallMutableArrayOp+ | ReadSmallArrayOp+ | WriteSmallArrayOp+ | SizeofSmallArrayOp+ | SizeofSmallMutableArrayOp+ | IndexSmallArrayOp+ | UnsafeFreezeSmallArrayOp+ | UnsafeThawSmallArrayOp+ | CopySmallArrayOp+ | CopySmallMutableArrayOp+ | CloneSmallArrayOp+ | CloneSmallMutableArrayOp+ | FreezeSmallArrayOp+ | ThawSmallArrayOp+ | CasSmallArrayOp+ | NewByteArrayOp_Char+ | NewPinnedByteArrayOp_Char+ | NewAlignedPinnedByteArrayOp_Char+ | MutableByteArrayIsPinnedOp+ | ByteArrayIsPinnedOp+ | ByteArrayContents_Char+ | SameMutableByteArrayOp+ | ShrinkMutableByteArrayOp_Char+ | ResizeMutableByteArrayOp_Char+ | UnsafeFreezeByteArrayOp+ | SizeofByteArrayOp+ | SizeofMutableByteArrayOp+ | GetSizeofMutableByteArrayOp+ | IndexByteArrayOp_Char+ | IndexByteArrayOp_WideChar+ | IndexByteArrayOp_Int+ | IndexByteArrayOp_Word+ | IndexByteArrayOp_Addr+ | IndexByteArrayOp_Float+ | IndexByteArrayOp_Double+ | IndexByteArrayOp_StablePtr+ | IndexByteArrayOp_Int8+ | IndexByteArrayOp_Int16+ | IndexByteArrayOp_Int32+ | IndexByteArrayOp_Int64+ | IndexByteArrayOp_Word8+ | IndexByteArrayOp_Word16+ | IndexByteArrayOp_Word32+ | IndexByteArrayOp_Word64+ | ReadByteArrayOp_Char+ | ReadByteArrayOp_WideChar+ | ReadByteArrayOp_Int+ | ReadByteArrayOp_Word+ | ReadByteArrayOp_Addr+ | ReadByteArrayOp_Float+ | ReadByteArrayOp_Double+ | ReadByteArrayOp_StablePtr+ | ReadByteArrayOp_Int8+ | ReadByteArrayOp_Int16+ | ReadByteArrayOp_Int32+ | ReadByteArrayOp_Int64+ | ReadByteArrayOp_Word8+ | ReadByteArrayOp_Word16+ | ReadByteArrayOp_Word32+ | ReadByteArrayOp_Word64+ | WriteByteArrayOp_Char+ | WriteByteArrayOp_WideChar+ | WriteByteArrayOp_Int+ | WriteByteArrayOp_Word+ | WriteByteArrayOp_Addr+ | WriteByteArrayOp_Float+ | WriteByteArrayOp_Double+ | WriteByteArrayOp_StablePtr+ | WriteByteArrayOp_Int8+ | WriteByteArrayOp_Int16+ | WriteByteArrayOp_Int32+ | WriteByteArrayOp_Int64+ | WriteByteArrayOp_Word8+ | WriteByteArrayOp_Word16+ | WriteByteArrayOp_Word32+ | WriteByteArrayOp_Word64+ | CopyByteArrayOp+ | CopyMutableByteArrayOp+ | CopyByteArrayToAddrOp+ | CopyMutableByteArrayToAddrOp+ | CopyAddrToByteArrayOp+ | SetByteArrayOp+ | AtomicReadByteArrayOp_Int+ | AtomicWriteByteArrayOp_Int+ | CasByteArrayOp_Int+ | FetchAddByteArrayOp_Int+ | FetchSubByteArrayOp_Int+ | FetchAndByteArrayOp_Int+ | FetchNandByteArrayOp_Int+ | FetchOrByteArrayOp_Int+ | FetchXorByteArrayOp_Int+ | NewArrayArrayOp+ | SameMutableArrayArrayOp+ | UnsafeFreezeArrayArrayOp+ | SizeofArrayArrayOp+ | SizeofMutableArrayArrayOp+ | IndexArrayArrayOp_ByteArray+ | IndexArrayArrayOp_ArrayArray+ | ReadArrayArrayOp_ByteArray+ | ReadArrayArrayOp_MutableByteArray+ | ReadArrayArrayOp_ArrayArray+ | ReadArrayArrayOp_MutableArrayArray+ | WriteArrayArrayOp_ByteArray+ | WriteArrayArrayOp_MutableByteArray+ | WriteArrayArrayOp_ArrayArray+ | WriteArrayArrayOp_MutableArrayArray+ | CopyArrayArrayOp+ | CopyMutableArrayArrayOp+ | AddrAddOp+ | AddrSubOp+ | AddrRemOp+ | Addr2IntOp+ | Int2AddrOp+ | AddrGtOp+ | AddrGeOp+ | AddrEqOp+ | AddrNeOp+ | AddrLtOp+ | AddrLeOp+ | IndexOffAddrOp_Char+ | IndexOffAddrOp_WideChar+ | IndexOffAddrOp_Int+ | IndexOffAddrOp_Word+ | IndexOffAddrOp_Addr+ | IndexOffAddrOp_Float+ | IndexOffAddrOp_Double+ | IndexOffAddrOp_StablePtr+ | IndexOffAddrOp_Int8+ | IndexOffAddrOp_Int16+ | IndexOffAddrOp_Int32+ | IndexOffAddrOp_Int64+ | IndexOffAddrOp_Word8+ | IndexOffAddrOp_Word16+ | IndexOffAddrOp_Word32+ | IndexOffAddrOp_Word64+ | ReadOffAddrOp_Char+ | ReadOffAddrOp_WideChar+ | ReadOffAddrOp_Int+ | ReadOffAddrOp_Word+ | ReadOffAddrOp_Addr+ | ReadOffAddrOp_Float+ | ReadOffAddrOp_Double+ | ReadOffAddrOp_StablePtr+ | ReadOffAddrOp_Int8+ | ReadOffAddrOp_Int16+ | ReadOffAddrOp_Int32+ | ReadOffAddrOp_Int64+ | ReadOffAddrOp_Word8+ | ReadOffAddrOp_Word16+ | ReadOffAddrOp_Word32+ | ReadOffAddrOp_Word64+ | WriteOffAddrOp_Char+ | WriteOffAddrOp_WideChar+ | WriteOffAddrOp_Int+ | WriteOffAddrOp_Word+ | WriteOffAddrOp_Addr+ | WriteOffAddrOp_Float+ | WriteOffAddrOp_Double+ | WriteOffAddrOp_StablePtr+ | WriteOffAddrOp_Int8+ | WriteOffAddrOp_Int16+ | WriteOffAddrOp_Int32+ | WriteOffAddrOp_Int64+ | WriteOffAddrOp_Word8+ | WriteOffAddrOp_Word16+ | WriteOffAddrOp_Word32+ | WriteOffAddrOp_Word64+ | NewMutVarOp+ | ReadMutVarOp+ | WriteMutVarOp+ | SameMutVarOp+ | AtomicModifyMutVarOp+ | CasMutVarOp+ | CatchOp+ | RaiseOp+ | RaiseIOOp+ | MaskAsyncExceptionsOp+ | MaskUninterruptibleOp+ | UnmaskAsyncExceptionsOp+ | MaskStatus+ | AtomicallyOp+ | RetryOp+ | CatchRetryOp+ | CatchSTMOp+ | Check+ | NewTVarOp+ | ReadTVarOp+ | ReadTVarIOOp+ | WriteTVarOp+ | SameTVarOp+ | NewMVarOp+ | TakeMVarOp+ | TryTakeMVarOp+ | PutMVarOp+ | TryPutMVarOp+ | ReadMVarOp+ | TryReadMVarOp+ | SameMVarOp+ | IsEmptyMVarOp+ | DelayOp+ | WaitReadOp+ | WaitWriteOp+ | ForkOp+ | ForkOnOp+ | KillThreadOp+ | YieldOp+ | MyThreadIdOp+ | LabelThreadOp+ | IsCurrentThreadBoundOp+ | NoDuplicateOp+ | ThreadStatusOp+ | MkWeakOp+ | MkWeakNoFinalizerOp+ | AddCFinalizerToWeakOp+ | DeRefWeakOp+ | FinalizeWeakOp+ | TouchOp+ | MakeStablePtrOp+ | DeRefStablePtrOp+ | EqStablePtrOp+ | MakeStableNameOp+ | EqStableNameOp+ | StableNameToIntOp+ | CompactNewOp+ | CompactResizeOp+ | CompactContainsOp+ | CompactContainsAnyOp+ | CompactGetFirstBlockOp+ | CompactGetNextBlockOp+ | CompactAllocateBlockOp+ | CompactFixupPointersOp+ | CompactAdd+ | CompactAddWithSharing+ | CompactSize+ | ReallyUnsafePtrEqualityOp+ | ParOp+ | SparkOp+ | SeqOp+ | GetSparkOp+ | NumSparks+ | DataToTagOp+ | TagToEnumOp+ | AddrToAnyOp+ | AnyToAddrOp+ | MkApUpd0_Op+ | NewBCOOp+ | UnpackClosureOp+ | GetApStackValOp+ | GetCCSOfOp+ | GetCurrentCCSOp+ | ClearCCSOp+ | TraceEventOp+ | TraceMarkerOp+ | VecBroadcastOp PrimOpVecCat Length Width+ | VecPackOp PrimOpVecCat Length Width+ | VecUnpackOp PrimOpVecCat Length Width+ | VecInsertOp PrimOpVecCat Length Width+ | VecAddOp PrimOpVecCat Length Width+ | VecSubOp PrimOpVecCat Length Width+ | VecMulOp PrimOpVecCat Length Width+ | VecDivOp PrimOpVecCat Length Width+ | VecQuotOp PrimOpVecCat Length Width+ | VecRemOp PrimOpVecCat Length Width+ | VecNegOp PrimOpVecCat Length Width+ | VecIndexByteArrayOp PrimOpVecCat Length Width+ | VecReadByteArrayOp PrimOpVecCat Length Width+ | VecWriteByteArrayOp PrimOpVecCat Length Width+ | VecIndexOffAddrOp PrimOpVecCat Length Width+ | VecReadOffAddrOp PrimOpVecCat Length Width+ | VecWriteOffAddrOp PrimOpVecCat Length Width+ | VecIndexScalarByteArrayOp PrimOpVecCat Length Width+ | VecReadScalarByteArrayOp PrimOpVecCat Length Width+ | VecWriteScalarByteArrayOp PrimOpVecCat Length Width+ | VecIndexScalarOffAddrOp PrimOpVecCat Length Width+ | VecReadScalarOffAddrOp PrimOpVecCat Length Width+ | VecWriteScalarOffAddrOp PrimOpVecCat Length Width+ | PrefetchByteArrayOp3+ | PrefetchMutableByteArrayOp3+ | PrefetchAddrOp3+ | PrefetchValueOp3+ | PrefetchByteArrayOp2+ | PrefetchMutableByteArrayOp2+ | PrefetchAddrOp2+ | PrefetchValueOp2+ | PrefetchByteArrayOp1+ | PrefetchMutableByteArrayOp1+ | PrefetchAddrOp1+ | PrefetchValueOp1+ | PrefetchByteArrayOp0+ | PrefetchMutableByteArrayOp0+ | PrefetchAddrOp0+ | PrefetchValueOp0
+ autogen/primop-fixity.hs-incl view
@@ -0,0 +1,20 @@+primOpFixity IntAddOp = Just (Fixity NoSourceText 6 InfixL)+primOpFixity IntSubOp = Just (Fixity NoSourceText 6 InfixL)+primOpFixity IntMulOp = Just (Fixity NoSourceText 7 InfixL)+primOpFixity IntGtOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity IntGeOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity IntEqOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity IntNeOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity IntLtOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity IntLeOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleGtOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleGeOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleEqOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleNeOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleLtOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleLeOp = Just (Fixity NoSourceText 4 InfixN)+primOpFixity DoubleAddOp = Just (Fixity NoSourceText 6 InfixL)+primOpFixity DoubleSubOp = Just (Fixity NoSourceText 6 InfixL)+primOpFixity DoubleMulOp = Just (Fixity NoSourceText 7 InfixL)+primOpFixity DoubleDivOp = Just (Fixity NoSourceText 7 InfixL)+primOpFixity _ = Nothing
+ autogen/primop-has-side-effects.hs-incl view
@@ -0,0 +1,211 @@+primOpHasSideEffects NewArrayOp = True+primOpHasSideEffects ReadArrayOp = True+primOpHasSideEffects WriteArrayOp = True+primOpHasSideEffects UnsafeFreezeArrayOp = True+primOpHasSideEffects UnsafeThawArrayOp = True+primOpHasSideEffects CopyArrayOp = True+primOpHasSideEffects CopyMutableArrayOp = True+primOpHasSideEffects CloneArrayOp = True+primOpHasSideEffects CloneMutableArrayOp = True+primOpHasSideEffects FreezeArrayOp = True+primOpHasSideEffects ThawArrayOp = True+primOpHasSideEffects CasArrayOp = True+primOpHasSideEffects NewSmallArrayOp = True+primOpHasSideEffects ReadSmallArrayOp = True+primOpHasSideEffects WriteSmallArrayOp = True+primOpHasSideEffects UnsafeFreezeSmallArrayOp = True+primOpHasSideEffects UnsafeThawSmallArrayOp = True+primOpHasSideEffects CopySmallArrayOp = True+primOpHasSideEffects CopySmallMutableArrayOp = True+primOpHasSideEffects CloneSmallArrayOp = True+primOpHasSideEffects CloneSmallMutableArrayOp = True+primOpHasSideEffects FreezeSmallArrayOp = True+primOpHasSideEffects ThawSmallArrayOp = True+primOpHasSideEffects CasSmallArrayOp = True+primOpHasSideEffects NewByteArrayOp_Char = True+primOpHasSideEffects NewPinnedByteArrayOp_Char = True+primOpHasSideEffects NewAlignedPinnedByteArrayOp_Char = True+primOpHasSideEffects ShrinkMutableByteArrayOp_Char = True+primOpHasSideEffects ResizeMutableByteArrayOp_Char = True+primOpHasSideEffects UnsafeFreezeByteArrayOp = True+primOpHasSideEffects ReadByteArrayOp_Char = True+primOpHasSideEffects ReadByteArrayOp_WideChar = True+primOpHasSideEffects ReadByteArrayOp_Int = True+primOpHasSideEffects ReadByteArrayOp_Word = True+primOpHasSideEffects ReadByteArrayOp_Addr = True+primOpHasSideEffects ReadByteArrayOp_Float = True+primOpHasSideEffects ReadByteArrayOp_Double = True+primOpHasSideEffects ReadByteArrayOp_StablePtr = True+primOpHasSideEffects ReadByteArrayOp_Int8 = True+primOpHasSideEffects ReadByteArrayOp_Int16 = True+primOpHasSideEffects ReadByteArrayOp_Int32 = True+primOpHasSideEffects ReadByteArrayOp_Int64 = True+primOpHasSideEffects ReadByteArrayOp_Word8 = True+primOpHasSideEffects ReadByteArrayOp_Word16 = True+primOpHasSideEffects ReadByteArrayOp_Word32 = True+primOpHasSideEffects ReadByteArrayOp_Word64 = True+primOpHasSideEffects WriteByteArrayOp_Char = True+primOpHasSideEffects WriteByteArrayOp_WideChar = True+primOpHasSideEffects WriteByteArrayOp_Int = True+primOpHasSideEffects WriteByteArrayOp_Word = True+primOpHasSideEffects WriteByteArrayOp_Addr = True+primOpHasSideEffects WriteByteArrayOp_Float = True+primOpHasSideEffects WriteByteArrayOp_Double = True+primOpHasSideEffects WriteByteArrayOp_StablePtr = True+primOpHasSideEffects WriteByteArrayOp_Int8 = True+primOpHasSideEffects WriteByteArrayOp_Int16 = True+primOpHasSideEffects WriteByteArrayOp_Int32 = True+primOpHasSideEffects WriteByteArrayOp_Int64 = True+primOpHasSideEffects WriteByteArrayOp_Word8 = True+primOpHasSideEffects WriteByteArrayOp_Word16 = True+primOpHasSideEffects WriteByteArrayOp_Word32 = True+primOpHasSideEffects WriteByteArrayOp_Word64 = True+primOpHasSideEffects CopyByteArrayOp = True+primOpHasSideEffects CopyMutableByteArrayOp = True+primOpHasSideEffects CopyByteArrayToAddrOp = True+primOpHasSideEffects CopyMutableByteArrayToAddrOp = True+primOpHasSideEffects CopyAddrToByteArrayOp = True+primOpHasSideEffects SetByteArrayOp = True+primOpHasSideEffects AtomicReadByteArrayOp_Int = True+primOpHasSideEffects AtomicWriteByteArrayOp_Int = True+primOpHasSideEffects CasByteArrayOp_Int = True+primOpHasSideEffects FetchAddByteArrayOp_Int = True+primOpHasSideEffects FetchSubByteArrayOp_Int = True+primOpHasSideEffects FetchAndByteArrayOp_Int = True+primOpHasSideEffects FetchNandByteArrayOp_Int = True+primOpHasSideEffects FetchOrByteArrayOp_Int = True+primOpHasSideEffects FetchXorByteArrayOp_Int = True+primOpHasSideEffects NewArrayArrayOp = True+primOpHasSideEffects UnsafeFreezeArrayArrayOp = True+primOpHasSideEffects ReadArrayArrayOp_ByteArray = True+primOpHasSideEffects ReadArrayArrayOp_MutableByteArray = True+primOpHasSideEffects ReadArrayArrayOp_ArrayArray = True+primOpHasSideEffects ReadArrayArrayOp_MutableArrayArray = True+primOpHasSideEffects WriteArrayArrayOp_ByteArray = True+primOpHasSideEffects WriteArrayArrayOp_MutableByteArray = True+primOpHasSideEffects WriteArrayArrayOp_ArrayArray = True+primOpHasSideEffects WriteArrayArrayOp_MutableArrayArray = True+primOpHasSideEffects CopyArrayArrayOp = True+primOpHasSideEffects CopyMutableArrayArrayOp = True+primOpHasSideEffects ReadOffAddrOp_Char = True+primOpHasSideEffects ReadOffAddrOp_WideChar = True+primOpHasSideEffects ReadOffAddrOp_Int = True+primOpHasSideEffects ReadOffAddrOp_Word = True+primOpHasSideEffects ReadOffAddrOp_Addr = True+primOpHasSideEffects ReadOffAddrOp_Float = True+primOpHasSideEffects ReadOffAddrOp_Double = True+primOpHasSideEffects ReadOffAddrOp_StablePtr = True+primOpHasSideEffects ReadOffAddrOp_Int8 = True+primOpHasSideEffects ReadOffAddrOp_Int16 = True+primOpHasSideEffects ReadOffAddrOp_Int32 = True+primOpHasSideEffects ReadOffAddrOp_Int64 = True+primOpHasSideEffects ReadOffAddrOp_Word8 = True+primOpHasSideEffects ReadOffAddrOp_Word16 = True+primOpHasSideEffects ReadOffAddrOp_Word32 = True+primOpHasSideEffects ReadOffAddrOp_Word64 = True+primOpHasSideEffects WriteOffAddrOp_Char = True+primOpHasSideEffects WriteOffAddrOp_WideChar = True+primOpHasSideEffects WriteOffAddrOp_Int = True+primOpHasSideEffects WriteOffAddrOp_Word = True+primOpHasSideEffects WriteOffAddrOp_Addr = True+primOpHasSideEffects WriteOffAddrOp_Float = True+primOpHasSideEffects WriteOffAddrOp_Double = True+primOpHasSideEffects WriteOffAddrOp_StablePtr = True+primOpHasSideEffects WriteOffAddrOp_Int8 = True+primOpHasSideEffects WriteOffAddrOp_Int16 = True+primOpHasSideEffects WriteOffAddrOp_Int32 = True+primOpHasSideEffects WriteOffAddrOp_Int64 = True+primOpHasSideEffects WriteOffAddrOp_Word8 = True+primOpHasSideEffects WriteOffAddrOp_Word16 = True+primOpHasSideEffects WriteOffAddrOp_Word32 = True+primOpHasSideEffects WriteOffAddrOp_Word64 = True+primOpHasSideEffects NewMutVarOp = True+primOpHasSideEffects ReadMutVarOp = True+primOpHasSideEffects WriteMutVarOp = True+primOpHasSideEffects AtomicModifyMutVarOp = True+primOpHasSideEffects CasMutVarOp = True+primOpHasSideEffects CatchOp = True+primOpHasSideEffects RaiseOp = True+primOpHasSideEffects RaiseIOOp = True+primOpHasSideEffects MaskAsyncExceptionsOp = True+primOpHasSideEffects MaskUninterruptibleOp = True+primOpHasSideEffects UnmaskAsyncExceptionsOp = True+primOpHasSideEffects MaskStatus = True+primOpHasSideEffects AtomicallyOp = True+primOpHasSideEffects RetryOp = True+primOpHasSideEffects CatchRetryOp = True+primOpHasSideEffects CatchSTMOp = True+primOpHasSideEffects Check = True+primOpHasSideEffects NewTVarOp = True+primOpHasSideEffects ReadTVarOp = True+primOpHasSideEffects ReadTVarIOOp = True+primOpHasSideEffects WriteTVarOp = True+primOpHasSideEffects NewMVarOp = True+primOpHasSideEffects TakeMVarOp = True+primOpHasSideEffects TryTakeMVarOp = True+primOpHasSideEffects PutMVarOp = True+primOpHasSideEffects TryPutMVarOp = True+primOpHasSideEffects ReadMVarOp = True+primOpHasSideEffects TryReadMVarOp = True+primOpHasSideEffects IsEmptyMVarOp = True+primOpHasSideEffects DelayOp = True+primOpHasSideEffects WaitReadOp = True+primOpHasSideEffects WaitWriteOp = True+primOpHasSideEffects ForkOp = True+primOpHasSideEffects ForkOnOp = True+primOpHasSideEffects KillThreadOp = True+primOpHasSideEffects YieldOp = True+primOpHasSideEffects MyThreadIdOp = True+primOpHasSideEffects LabelThreadOp = True+primOpHasSideEffects IsCurrentThreadBoundOp = True+primOpHasSideEffects NoDuplicateOp = True+primOpHasSideEffects ThreadStatusOp = True+primOpHasSideEffects MkWeakOp = True+primOpHasSideEffects MkWeakNoFinalizerOp = True+primOpHasSideEffects AddCFinalizerToWeakOp = True+primOpHasSideEffects DeRefWeakOp = True+primOpHasSideEffects FinalizeWeakOp = True+primOpHasSideEffects TouchOp = True+primOpHasSideEffects MakeStablePtrOp = True+primOpHasSideEffects DeRefStablePtrOp = True+primOpHasSideEffects EqStablePtrOp = True+primOpHasSideEffects MakeStableNameOp = True+primOpHasSideEffects CompactNewOp = True+primOpHasSideEffects CompactResizeOp = True+primOpHasSideEffects CompactAllocateBlockOp = True+primOpHasSideEffects CompactFixupPointersOp = True+primOpHasSideEffects CompactAdd = True+primOpHasSideEffects CompactAddWithSharing = True+primOpHasSideEffects CompactSize = True+primOpHasSideEffects ParOp = True+primOpHasSideEffects SparkOp = True+primOpHasSideEffects GetSparkOp = True+primOpHasSideEffects NumSparks = True+primOpHasSideEffects NewBCOOp = True+primOpHasSideEffects TraceEventOp = True+primOpHasSideEffects TraceMarkerOp = True+primOpHasSideEffects (VecReadByteArrayOp _ _ _) = True+primOpHasSideEffects (VecWriteByteArrayOp _ _ _) = True+primOpHasSideEffects (VecReadOffAddrOp _ _ _) = True+primOpHasSideEffects (VecWriteOffAddrOp _ _ _) = True+primOpHasSideEffects (VecReadScalarByteArrayOp _ _ _) = True+primOpHasSideEffects (VecWriteScalarByteArrayOp _ _ _) = True+primOpHasSideEffects (VecReadScalarOffAddrOp _ _ _) = True+primOpHasSideEffects (VecWriteScalarOffAddrOp _ _ _) = True+primOpHasSideEffects PrefetchByteArrayOp3 = True+primOpHasSideEffects PrefetchMutableByteArrayOp3 = True+primOpHasSideEffects PrefetchAddrOp3 = True+primOpHasSideEffects PrefetchValueOp3 = True+primOpHasSideEffects PrefetchByteArrayOp2 = True+primOpHasSideEffects PrefetchMutableByteArrayOp2 = True+primOpHasSideEffects PrefetchAddrOp2 = True+primOpHasSideEffects PrefetchValueOp2 = True+primOpHasSideEffects PrefetchByteArrayOp1 = True+primOpHasSideEffects PrefetchMutableByteArrayOp1 = True+primOpHasSideEffects PrefetchAddrOp1 = True+primOpHasSideEffects PrefetchValueOp1 = True+primOpHasSideEffects PrefetchByteArrayOp0 = True+primOpHasSideEffects PrefetchMutableByteArrayOp0 = True+primOpHasSideEffects PrefetchAddrOp0 = True+primOpHasSideEffects PrefetchValueOp0 = True+primOpHasSideEffects _ = False
+ autogen/primop-list.hs-incl view
@@ -0,0 +1,1070 @@+ [CharGtOp+ , CharGeOp+ , CharEqOp+ , CharNeOp+ , CharLtOp+ , CharLeOp+ , OrdOp+ , IntAddOp+ , IntSubOp+ , IntMulOp+ , IntMulMayOfloOp+ , IntQuotOp+ , IntRemOp+ , IntQuotRemOp+ , AndIOp+ , OrIOp+ , XorIOp+ , NotIOp+ , IntNegOp+ , IntAddCOp+ , IntSubCOp+ , IntGtOp+ , IntGeOp+ , IntEqOp+ , IntNeOp+ , IntLtOp+ , IntLeOp+ , ChrOp+ , Int2WordOp+ , Int2FloatOp+ , Int2DoubleOp+ , Word2FloatOp+ , Word2DoubleOp+ , ISllOp+ , ISraOp+ , ISrlOp+ , WordAddOp+ , WordSubCOp+ , WordAdd2Op+ , WordSubOp+ , WordMulOp+ , WordMul2Op+ , WordQuotOp+ , WordRemOp+ , WordQuotRemOp+ , WordQuotRem2Op+ , AndOp+ , OrOp+ , XorOp+ , NotOp+ , SllOp+ , SrlOp+ , Word2IntOp+ , WordGtOp+ , WordGeOp+ , WordEqOp+ , WordNeOp+ , WordLtOp+ , WordLeOp+ , PopCnt8Op+ , PopCnt16Op+ , PopCnt32Op+ , PopCnt64Op+ , PopCntOp+ , Clz8Op+ , Clz16Op+ , Clz32Op+ , Clz64Op+ , ClzOp+ , Ctz8Op+ , Ctz16Op+ , Ctz32Op+ , Ctz64Op+ , CtzOp+ , BSwap16Op+ , BSwap32Op+ , BSwap64Op+ , BSwapOp+ , Narrow8IntOp+ , Narrow16IntOp+ , Narrow32IntOp+ , Narrow8WordOp+ , Narrow16WordOp+ , Narrow32WordOp+ , DoubleGtOp+ , DoubleGeOp+ , DoubleEqOp+ , DoubleNeOp+ , DoubleLtOp+ , DoubleLeOp+ , DoubleAddOp+ , DoubleSubOp+ , DoubleMulOp+ , DoubleDivOp+ , DoubleNegOp+ , DoubleFabsOp+ , Double2IntOp+ , Double2FloatOp+ , DoubleExpOp+ , DoubleLogOp+ , DoubleSqrtOp+ , DoubleSinOp+ , DoubleCosOp+ , DoubleTanOp+ , DoubleAsinOp+ , DoubleAcosOp+ , DoubleAtanOp+ , DoubleSinhOp+ , DoubleCoshOp+ , DoubleTanhOp+ , DoublePowerOp+ , DoubleDecode_2IntOp+ , DoubleDecode_Int64Op+ , FloatGtOp+ , FloatGeOp+ , FloatEqOp+ , FloatNeOp+ , FloatLtOp+ , FloatLeOp+ , FloatAddOp+ , FloatSubOp+ , FloatMulOp+ , FloatDivOp+ , FloatNegOp+ , FloatFabsOp+ , Float2IntOp+ , FloatExpOp+ , FloatLogOp+ , FloatSqrtOp+ , FloatSinOp+ , FloatCosOp+ , FloatTanOp+ , FloatAsinOp+ , FloatAcosOp+ , FloatAtanOp+ , FloatSinhOp+ , FloatCoshOp+ , FloatTanhOp+ , FloatPowerOp+ , Float2DoubleOp+ , FloatDecode_IntOp+ , NewArrayOp+ , SameMutableArrayOp+ , ReadArrayOp+ , WriteArrayOp+ , SizeofArrayOp+ , SizeofMutableArrayOp+ , IndexArrayOp+ , UnsafeFreezeArrayOp+ , UnsafeThawArrayOp+ , CopyArrayOp+ , CopyMutableArrayOp+ , CloneArrayOp+ , CloneMutableArrayOp+ , FreezeArrayOp+ , ThawArrayOp+ , CasArrayOp+ , NewSmallArrayOp+ , SameSmallMutableArrayOp+ , ReadSmallArrayOp+ , WriteSmallArrayOp+ , SizeofSmallArrayOp+ , SizeofSmallMutableArrayOp+ , IndexSmallArrayOp+ , UnsafeFreezeSmallArrayOp+ , UnsafeThawSmallArrayOp+ , CopySmallArrayOp+ , CopySmallMutableArrayOp+ , CloneSmallArrayOp+ , CloneSmallMutableArrayOp+ , FreezeSmallArrayOp+ , ThawSmallArrayOp+ , CasSmallArrayOp+ , NewByteArrayOp_Char+ , NewPinnedByteArrayOp_Char+ , NewAlignedPinnedByteArrayOp_Char+ , MutableByteArrayIsPinnedOp+ , ByteArrayIsPinnedOp+ , ByteArrayContents_Char+ , SameMutableByteArrayOp+ , ShrinkMutableByteArrayOp_Char+ , ResizeMutableByteArrayOp_Char+ , UnsafeFreezeByteArrayOp+ , SizeofByteArrayOp+ , SizeofMutableByteArrayOp+ , GetSizeofMutableByteArrayOp+ , IndexByteArrayOp_Char+ , IndexByteArrayOp_WideChar+ , IndexByteArrayOp_Int+ , IndexByteArrayOp_Word+ , IndexByteArrayOp_Addr+ , IndexByteArrayOp_Float+ , IndexByteArrayOp_Double+ , IndexByteArrayOp_StablePtr+ , IndexByteArrayOp_Int8+ , IndexByteArrayOp_Int16+ , IndexByteArrayOp_Int32+ , IndexByteArrayOp_Int64+ , IndexByteArrayOp_Word8+ , IndexByteArrayOp_Word16+ , IndexByteArrayOp_Word32+ , IndexByteArrayOp_Word64+ , ReadByteArrayOp_Char+ , ReadByteArrayOp_WideChar+ , ReadByteArrayOp_Int+ , ReadByteArrayOp_Word+ , ReadByteArrayOp_Addr+ , ReadByteArrayOp_Float+ , ReadByteArrayOp_Double+ , ReadByteArrayOp_StablePtr+ , ReadByteArrayOp_Int8+ , ReadByteArrayOp_Int16+ , ReadByteArrayOp_Int32+ , ReadByteArrayOp_Int64+ , ReadByteArrayOp_Word8+ , ReadByteArrayOp_Word16+ , ReadByteArrayOp_Word32+ , ReadByteArrayOp_Word64+ , WriteByteArrayOp_Char+ , WriteByteArrayOp_WideChar+ , WriteByteArrayOp_Int+ , WriteByteArrayOp_Word+ , WriteByteArrayOp_Addr+ , WriteByteArrayOp_Float+ , WriteByteArrayOp_Double+ , WriteByteArrayOp_StablePtr+ , WriteByteArrayOp_Int8+ , WriteByteArrayOp_Int16+ , WriteByteArrayOp_Int32+ , WriteByteArrayOp_Int64+ , WriteByteArrayOp_Word8+ , WriteByteArrayOp_Word16+ , WriteByteArrayOp_Word32+ , WriteByteArrayOp_Word64+ , CopyByteArrayOp+ , CopyMutableByteArrayOp+ , CopyByteArrayToAddrOp+ , CopyMutableByteArrayToAddrOp+ , CopyAddrToByteArrayOp+ , SetByteArrayOp+ , AtomicReadByteArrayOp_Int+ , AtomicWriteByteArrayOp_Int+ , CasByteArrayOp_Int+ , FetchAddByteArrayOp_Int+ , FetchSubByteArrayOp_Int+ , FetchAndByteArrayOp_Int+ , FetchNandByteArrayOp_Int+ , FetchOrByteArrayOp_Int+ , FetchXorByteArrayOp_Int+ , NewArrayArrayOp+ , SameMutableArrayArrayOp+ , UnsafeFreezeArrayArrayOp+ , SizeofArrayArrayOp+ , SizeofMutableArrayArrayOp+ , IndexArrayArrayOp_ByteArray+ , IndexArrayArrayOp_ArrayArray+ , ReadArrayArrayOp_ByteArray+ , ReadArrayArrayOp_MutableByteArray+ , ReadArrayArrayOp_ArrayArray+ , ReadArrayArrayOp_MutableArrayArray+ , WriteArrayArrayOp_ByteArray+ , WriteArrayArrayOp_MutableByteArray+ , WriteArrayArrayOp_ArrayArray+ , WriteArrayArrayOp_MutableArrayArray+ , CopyArrayArrayOp+ , CopyMutableArrayArrayOp+ , AddrAddOp+ , AddrSubOp+ , AddrRemOp+ , Addr2IntOp+ , Int2AddrOp+ , AddrGtOp+ , AddrGeOp+ , AddrEqOp+ , AddrNeOp+ , AddrLtOp+ , AddrLeOp+ , IndexOffAddrOp_Char+ , IndexOffAddrOp_WideChar+ , IndexOffAddrOp_Int+ , IndexOffAddrOp_Word+ , IndexOffAddrOp_Addr+ , IndexOffAddrOp_Float+ , IndexOffAddrOp_Double+ , IndexOffAddrOp_StablePtr+ , IndexOffAddrOp_Int8+ , IndexOffAddrOp_Int16+ , IndexOffAddrOp_Int32+ , IndexOffAddrOp_Int64+ , IndexOffAddrOp_Word8+ , IndexOffAddrOp_Word16+ , IndexOffAddrOp_Word32+ , IndexOffAddrOp_Word64+ , ReadOffAddrOp_Char+ , ReadOffAddrOp_WideChar+ , ReadOffAddrOp_Int+ , ReadOffAddrOp_Word+ , ReadOffAddrOp_Addr+ , ReadOffAddrOp_Float+ , ReadOffAddrOp_Double+ , ReadOffAddrOp_StablePtr+ , ReadOffAddrOp_Int8+ , ReadOffAddrOp_Int16+ , ReadOffAddrOp_Int32+ , ReadOffAddrOp_Int64+ , ReadOffAddrOp_Word8+ , ReadOffAddrOp_Word16+ , ReadOffAddrOp_Word32+ , ReadOffAddrOp_Word64+ , WriteOffAddrOp_Char+ , WriteOffAddrOp_WideChar+ , WriteOffAddrOp_Int+ , WriteOffAddrOp_Word+ , WriteOffAddrOp_Addr+ , WriteOffAddrOp_Float+ , WriteOffAddrOp_Double+ , WriteOffAddrOp_StablePtr+ , WriteOffAddrOp_Int8+ , WriteOffAddrOp_Int16+ , WriteOffAddrOp_Int32+ , WriteOffAddrOp_Int64+ , WriteOffAddrOp_Word8+ , WriteOffAddrOp_Word16+ , WriteOffAddrOp_Word32+ , WriteOffAddrOp_Word64+ , NewMutVarOp+ , ReadMutVarOp+ , WriteMutVarOp+ , SameMutVarOp+ , AtomicModifyMutVarOp+ , CasMutVarOp+ , CatchOp+ , RaiseOp+ , RaiseIOOp+ , MaskAsyncExceptionsOp+ , MaskUninterruptibleOp+ , UnmaskAsyncExceptionsOp+ , MaskStatus+ , AtomicallyOp+ , RetryOp+ , CatchRetryOp+ , CatchSTMOp+ , Check+ , NewTVarOp+ , ReadTVarOp+ , ReadTVarIOOp+ , WriteTVarOp+ , SameTVarOp+ , NewMVarOp+ , TakeMVarOp+ , TryTakeMVarOp+ , PutMVarOp+ , TryPutMVarOp+ , ReadMVarOp+ , TryReadMVarOp+ , SameMVarOp+ , IsEmptyMVarOp+ , DelayOp+ , WaitReadOp+ , WaitWriteOp+ , ForkOp+ , ForkOnOp+ , KillThreadOp+ , YieldOp+ , MyThreadIdOp+ , LabelThreadOp+ , IsCurrentThreadBoundOp+ , NoDuplicateOp+ , ThreadStatusOp+ , MkWeakOp+ , MkWeakNoFinalizerOp+ , AddCFinalizerToWeakOp+ , DeRefWeakOp+ , FinalizeWeakOp+ , TouchOp+ , MakeStablePtrOp+ , DeRefStablePtrOp+ , EqStablePtrOp+ , MakeStableNameOp+ , EqStableNameOp+ , StableNameToIntOp+ , CompactNewOp+ , CompactResizeOp+ , CompactContainsOp+ , CompactContainsAnyOp+ , CompactGetFirstBlockOp+ , CompactGetNextBlockOp+ , CompactAllocateBlockOp+ , CompactFixupPointersOp+ , CompactAdd+ , CompactAddWithSharing+ , CompactSize+ , ReallyUnsafePtrEqualityOp+ , ParOp+ , SparkOp+ , SeqOp+ , GetSparkOp+ , NumSparks+ , DataToTagOp+ , TagToEnumOp+ , AddrToAnyOp+ , AnyToAddrOp+ , MkApUpd0_Op+ , NewBCOOp+ , UnpackClosureOp+ , GetApStackValOp+ , GetCCSOfOp+ , GetCurrentCCSOp+ , ClearCCSOp+ , TraceEventOp+ , TraceMarkerOp+ , (VecBroadcastOp IntVec 16 W8)+ , (VecBroadcastOp IntVec 8 W16)+ , (VecBroadcastOp IntVec 4 W32)+ , (VecBroadcastOp IntVec 2 W64)+ , (VecBroadcastOp IntVec 32 W8)+ , (VecBroadcastOp IntVec 16 W16)+ , (VecBroadcastOp IntVec 8 W32)+ , (VecBroadcastOp IntVec 4 W64)+ , (VecBroadcastOp IntVec 64 W8)+ , (VecBroadcastOp IntVec 32 W16)+ , (VecBroadcastOp IntVec 16 W32)+ , (VecBroadcastOp IntVec 8 W64)+ , (VecBroadcastOp WordVec 16 W8)+ , (VecBroadcastOp WordVec 8 W16)+ , (VecBroadcastOp WordVec 4 W32)+ , (VecBroadcastOp WordVec 2 W64)+ , (VecBroadcastOp WordVec 32 W8)+ , (VecBroadcastOp WordVec 16 W16)+ , (VecBroadcastOp WordVec 8 W32)+ , (VecBroadcastOp WordVec 4 W64)+ , (VecBroadcastOp WordVec 64 W8)+ , (VecBroadcastOp WordVec 32 W16)+ , (VecBroadcastOp WordVec 16 W32)+ , (VecBroadcastOp WordVec 8 W64)+ , (VecBroadcastOp FloatVec 4 W32)+ , (VecBroadcastOp FloatVec 2 W64)+ , (VecBroadcastOp FloatVec 8 W32)+ , (VecBroadcastOp FloatVec 4 W64)+ , (VecBroadcastOp FloatVec 16 W32)+ , (VecBroadcastOp FloatVec 8 W64)+ , (VecPackOp IntVec 16 W8)+ , (VecPackOp IntVec 8 W16)+ , (VecPackOp IntVec 4 W32)+ , (VecPackOp IntVec 2 W64)+ , (VecPackOp IntVec 32 W8)+ , (VecPackOp IntVec 16 W16)+ , (VecPackOp IntVec 8 W32)+ , (VecPackOp IntVec 4 W64)+ , (VecPackOp IntVec 64 W8)+ , (VecPackOp IntVec 32 W16)+ , (VecPackOp IntVec 16 W32)+ , (VecPackOp IntVec 8 W64)+ , (VecPackOp WordVec 16 W8)+ , (VecPackOp WordVec 8 W16)+ , (VecPackOp WordVec 4 W32)+ , (VecPackOp WordVec 2 W64)+ , (VecPackOp WordVec 32 W8)+ , (VecPackOp WordVec 16 W16)+ , (VecPackOp WordVec 8 W32)+ , (VecPackOp WordVec 4 W64)+ , (VecPackOp WordVec 64 W8)+ , (VecPackOp WordVec 32 W16)+ , (VecPackOp WordVec 16 W32)+ , (VecPackOp WordVec 8 W64)+ , (VecPackOp FloatVec 4 W32)+ , (VecPackOp FloatVec 2 W64)+ , (VecPackOp FloatVec 8 W32)+ , (VecPackOp FloatVec 4 W64)+ , (VecPackOp FloatVec 16 W32)+ , (VecPackOp FloatVec 8 W64)+ , (VecUnpackOp IntVec 16 W8)+ , (VecUnpackOp IntVec 8 W16)+ , (VecUnpackOp IntVec 4 W32)+ , (VecUnpackOp IntVec 2 W64)+ , (VecUnpackOp IntVec 32 W8)+ , (VecUnpackOp IntVec 16 W16)+ , (VecUnpackOp IntVec 8 W32)+ , (VecUnpackOp IntVec 4 W64)+ , (VecUnpackOp IntVec 64 W8)+ , (VecUnpackOp IntVec 32 W16)+ , (VecUnpackOp IntVec 16 W32)+ , (VecUnpackOp IntVec 8 W64)+ , (VecUnpackOp WordVec 16 W8)+ , (VecUnpackOp WordVec 8 W16)+ , (VecUnpackOp WordVec 4 W32)+ , (VecUnpackOp WordVec 2 W64)+ , (VecUnpackOp WordVec 32 W8)+ , (VecUnpackOp WordVec 16 W16)+ , (VecUnpackOp WordVec 8 W32)+ , (VecUnpackOp WordVec 4 W64)+ , (VecUnpackOp WordVec 64 W8)+ , (VecUnpackOp WordVec 32 W16)+ , (VecUnpackOp WordVec 16 W32)+ , (VecUnpackOp WordVec 8 W64)+ , (VecUnpackOp FloatVec 4 W32)+ , (VecUnpackOp FloatVec 2 W64)+ , (VecUnpackOp FloatVec 8 W32)+ , (VecUnpackOp FloatVec 4 W64)+ , (VecUnpackOp FloatVec 16 W32)+ , (VecUnpackOp FloatVec 8 W64)+ , (VecInsertOp IntVec 16 W8)+ , (VecInsertOp IntVec 8 W16)+ , (VecInsertOp IntVec 4 W32)+ , (VecInsertOp IntVec 2 W64)+ , (VecInsertOp IntVec 32 W8)+ , (VecInsertOp IntVec 16 W16)+ , (VecInsertOp IntVec 8 W32)+ , (VecInsertOp IntVec 4 W64)+ , (VecInsertOp IntVec 64 W8)+ , (VecInsertOp IntVec 32 W16)+ , (VecInsertOp IntVec 16 W32)+ , (VecInsertOp IntVec 8 W64)+ , (VecInsertOp WordVec 16 W8)+ , (VecInsertOp WordVec 8 W16)+ , (VecInsertOp WordVec 4 W32)+ , (VecInsertOp WordVec 2 W64)+ , (VecInsertOp WordVec 32 W8)+ , (VecInsertOp WordVec 16 W16)+ , (VecInsertOp WordVec 8 W32)+ , (VecInsertOp WordVec 4 W64)+ , (VecInsertOp WordVec 64 W8)+ , (VecInsertOp WordVec 32 W16)+ , (VecInsertOp WordVec 16 W32)+ , (VecInsertOp WordVec 8 W64)+ , (VecInsertOp FloatVec 4 W32)+ , (VecInsertOp FloatVec 2 W64)+ , (VecInsertOp FloatVec 8 W32)+ , (VecInsertOp FloatVec 4 W64)+ , (VecInsertOp FloatVec 16 W32)+ , (VecInsertOp FloatVec 8 W64)+ , (VecAddOp IntVec 16 W8)+ , (VecAddOp IntVec 8 W16)+ , (VecAddOp IntVec 4 W32)+ , (VecAddOp IntVec 2 W64)+ , (VecAddOp IntVec 32 W8)+ , (VecAddOp IntVec 16 W16)+ , (VecAddOp IntVec 8 W32)+ , (VecAddOp IntVec 4 W64)+ , (VecAddOp IntVec 64 W8)+ , (VecAddOp IntVec 32 W16)+ , (VecAddOp IntVec 16 W32)+ , (VecAddOp IntVec 8 W64)+ , (VecAddOp WordVec 16 W8)+ , (VecAddOp WordVec 8 W16)+ , (VecAddOp WordVec 4 W32)+ , (VecAddOp WordVec 2 W64)+ , (VecAddOp WordVec 32 W8)+ , (VecAddOp WordVec 16 W16)+ , (VecAddOp WordVec 8 W32)+ , (VecAddOp WordVec 4 W64)+ , (VecAddOp WordVec 64 W8)+ , (VecAddOp WordVec 32 W16)+ , (VecAddOp WordVec 16 W32)+ , (VecAddOp WordVec 8 W64)+ , (VecAddOp FloatVec 4 W32)+ , (VecAddOp FloatVec 2 W64)+ , (VecAddOp FloatVec 8 W32)+ , (VecAddOp FloatVec 4 W64)+ , (VecAddOp FloatVec 16 W32)+ , (VecAddOp FloatVec 8 W64)+ , (VecSubOp IntVec 16 W8)+ , (VecSubOp IntVec 8 W16)+ , (VecSubOp IntVec 4 W32)+ , (VecSubOp IntVec 2 W64)+ , (VecSubOp IntVec 32 W8)+ , (VecSubOp IntVec 16 W16)+ , (VecSubOp IntVec 8 W32)+ , (VecSubOp IntVec 4 W64)+ , (VecSubOp IntVec 64 W8)+ , (VecSubOp IntVec 32 W16)+ , (VecSubOp IntVec 16 W32)+ , (VecSubOp IntVec 8 W64)+ , (VecSubOp WordVec 16 W8)+ , (VecSubOp WordVec 8 W16)+ , (VecSubOp WordVec 4 W32)+ , (VecSubOp WordVec 2 W64)+ , (VecSubOp WordVec 32 W8)+ , (VecSubOp WordVec 16 W16)+ , (VecSubOp WordVec 8 W32)+ , (VecSubOp WordVec 4 W64)+ , (VecSubOp WordVec 64 W8)+ , (VecSubOp WordVec 32 W16)+ , (VecSubOp WordVec 16 W32)+ , (VecSubOp WordVec 8 W64)+ , (VecSubOp FloatVec 4 W32)+ , (VecSubOp FloatVec 2 W64)+ , (VecSubOp FloatVec 8 W32)+ , (VecSubOp FloatVec 4 W64)+ , (VecSubOp FloatVec 16 W32)+ , (VecSubOp FloatVec 8 W64)+ , (VecMulOp IntVec 16 W8)+ , (VecMulOp IntVec 8 W16)+ , (VecMulOp IntVec 4 W32)+ , (VecMulOp IntVec 2 W64)+ , (VecMulOp IntVec 32 W8)+ , (VecMulOp IntVec 16 W16)+ , (VecMulOp IntVec 8 W32)+ , (VecMulOp IntVec 4 W64)+ , (VecMulOp IntVec 64 W8)+ , (VecMulOp IntVec 32 W16)+ , (VecMulOp IntVec 16 W32)+ , (VecMulOp IntVec 8 W64)+ , (VecMulOp WordVec 16 W8)+ , (VecMulOp WordVec 8 W16)+ , (VecMulOp WordVec 4 W32)+ , (VecMulOp WordVec 2 W64)+ , (VecMulOp WordVec 32 W8)+ , (VecMulOp WordVec 16 W16)+ , (VecMulOp WordVec 8 W32)+ , (VecMulOp WordVec 4 W64)+ , (VecMulOp WordVec 64 W8)+ , (VecMulOp WordVec 32 W16)+ , (VecMulOp WordVec 16 W32)+ , (VecMulOp WordVec 8 W64)+ , (VecMulOp FloatVec 4 W32)+ , (VecMulOp FloatVec 2 W64)+ , (VecMulOp FloatVec 8 W32)+ , (VecMulOp FloatVec 4 W64)+ , (VecMulOp FloatVec 16 W32)+ , (VecMulOp FloatVec 8 W64)+ , (VecDivOp FloatVec 4 W32)+ , (VecDivOp FloatVec 2 W64)+ , (VecDivOp FloatVec 8 W32)+ , (VecDivOp FloatVec 4 W64)+ , (VecDivOp FloatVec 16 W32)+ , (VecDivOp FloatVec 8 W64)+ , (VecQuotOp IntVec 16 W8)+ , (VecQuotOp IntVec 8 W16)+ , (VecQuotOp IntVec 4 W32)+ , (VecQuotOp IntVec 2 W64)+ , (VecQuotOp IntVec 32 W8)+ , (VecQuotOp IntVec 16 W16)+ , (VecQuotOp IntVec 8 W32)+ , (VecQuotOp IntVec 4 W64)+ , (VecQuotOp IntVec 64 W8)+ , (VecQuotOp IntVec 32 W16)+ , (VecQuotOp IntVec 16 W32)+ , (VecQuotOp IntVec 8 W64)+ , (VecQuotOp WordVec 16 W8)+ , (VecQuotOp WordVec 8 W16)+ , (VecQuotOp WordVec 4 W32)+ , (VecQuotOp WordVec 2 W64)+ , (VecQuotOp WordVec 32 W8)+ , (VecQuotOp WordVec 16 W16)+ , (VecQuotOp WordVec 8 W32)+ , (VecQuotOp WordVec 4 W64)+ , (VecQuotOp WordVec 64 W8)+ , (VecQuotOp WordVec 32 W16)+ , (VecQuotOp WordVec 16 W32)+ , (VecQuotOp WordVec 8 W64)+ , (VecRemOp IntVec 16 W8)+ , (VecRemOp IntVec 8 W16)+ , (VecRemOp IntVec 4 W32)+ , (VecRemOp IntVec 2 W64)+ , (VecRemOp IntVec 32 W8)+ , (VecRemOp IntVec 16 W16)+ , (VecRemOp IntVec 8 W32)+ , (VecRemOp IntVec 4 W64)+ , (VecRemOp IntVec 64 W8)+ , (VecRemOp IntVec 32 W16)+ , (VecRemOp IntVec 16 W32)+ , (VecRemOp IntVec 8 W64)+ , (VecRemOp WordVec 16 W8)+ , (VecRemOp WordVec 8 W16)+ , (VecRemOp WordVec 4 W32)+ , (VecRemOp WordVec 2 W64)+ , (VecRemOp WordVec 32 W8)+ , (VecRemOp WordVec 16 W16)+ , (VecRemOp WordVec 8 W32)+ , (VecRemOp WordVec 4 W64)+ , (VecRemOp WordVec 64 W8)+ , (VecRemOp WordVec 32 W16)+ , (VecRemOp WordVec 16 W32)+ , (VecRemOp WordVec 8 W64)+ , (VecNegOp IntVec 16 W8)+ , (VecNegOp IntVec 8 W16)+ , (VecNegOp IntVec 4 W32)+ , (VecNegOp IntVec 2 W64)+ , (VecNegOp IntVec 32 W8)+ , (VecNegOp IntVec 16 W16)+ , (VecNegOp IntVec 8 W32)+ , (VecNegOp IntVec 4 W64)+ , (VecNegOp IntVec 64 W8)+ , (VecNegOp IntVec 32 W16)+ , (VecNegOp IntVec 16 W32)+ , (VecNegOp IntVec 8 W64)+ , (VecNegOp FloatVec 4 W32)+ , (VecNegOp FloatVec 2 W64)+ , (VecNegOp FloatVec 8 W32)+ , (VecNegOp FloatVec 4 W64)+ , (VecNegOp FloatVec 16 W32)+ , (VecNegOp FloatVec 8 W64)+ , (VecIndexByteArrayOp IntVec 16 W8)+ , (VecIndexByteArrayOp IntVec 8 W16)+ , (VecIndexByteArrayOp IntVec 4 W32)+ , (VecIndexByteArrayOp IntVec 2 W64)+ , (VecIndexByteArrayOp IntVec 32 W8)+ , (VecIndexByteArrayOp IntVec 16 W16)+ , (VecIndexByteArrayOp IntVec 8 W32)+ , (VecIndexByteArrayOp IntVec 4 W64)+ , (VecIndexByteArrayOp IntVec 64 W8)+ , (VecIndexByteArrayOp IntVec 32 W16)+ , (VecIndexByteArrayOp IntVec 16 W32)+ , (VecIndexByteArrayOp IntVec 8 W64)+ , (VecIndexByteArrayOp WordVec 16 W8)+ , (VecIndexByteArrayOp WordVec 8 W16)+ , (VecIndexByteArrayOp WordVec 4 W32)+ , (VecIndexByteArrayOp WordVec 2 W64)+ , (VecIndexByteArrayOp WordVec 32 W8)+ , (VecIndexByteArrayOp WordVec 16 W16)+ , (VecIndexByteArrayOp WordVec 8 W32)+ , (VecIndexByteArrayOp WordVec 4 W64)+ , (VecIndexByteArrayOp WordVec 64 W8)+ , (VecIndexByteArrayOp WordVec 32 W16)+ , (VecIndexByteArrayOp WordVec 16 W32)+ , (VecIndexByteArrayOp WordVec 8 W64)+ , (VecIndexByteArrayOp FloatVec 4 W32)+ , (VecIndexByteArrayOp FloatVec 2 W64)+ , (VecIndexByteArrayOp FloatVec 8 W32)+ , (VecIndexByteArrayOp FloatVec 4 W64)+ , (VecIndexByteArrayOp FloatVec 16 W32)+ , (VecIndexByteArrayOp FloatVec 8 W64)+ , (VecReadByteArrayOp IntVec 16 W8)+ , (VecReadByteArrayOp IntVec 8 W16)+ , (VecReadByteArrayOp IntVec 4 W32)+ , (VecReadByteArrayOp IntVec 2 W64)+ , (VecReadByteArrayOp IntVec 32 W8)+ , (VecReadByteArrayOp IntVec 16 W16)+ , (VecReadByteArrayOp IntVec 8 W32)+ , (VecReadByteArrayOp IntVec 4 W64)+ , (VecReadByteArrayOp IntVec 64 W8)+ , (VecReadByteArrayOp IntVec 32 W16)+ , (VecReadByteArrayOp IntVec 16 W32)+ , (VecReadByteArrayOp IntVec 8 W64)+ , (VecReadByteArrayOp WordVec 16 W8)+ , (VecReadByteArrayOp WordVec 8 W16)+ , (VecReadByteArrayOp WordVec 4 W32)+ , (VecReadByteArrayOp WordVec 2 W64)+ , (VecReadByteArrayOp WordVec 32 W8)+ , (VecReadByteArrayOp WordVec 16 W16)+ , (VecReadByteArrayOp WordVec 8 W32)+ , (VecReadByteArrayOp WordVec 4 W64)+ , (VecReadByteArrayOp WordVec 64 W8)+ , (VecReadByteArrayOp WordVec 32 W16)+ , (VecReadByteArrayOp WordVec 16 W32)+ , (VecReadByteArrayOp WordVec 8 W64)+ , (VecReadByteArrayOp FloatVec 4 W32)+ , (VecReadByteArrayOp FloatVec 2 W64)+ , (VecReadByteArrayOp FloatVec 8 W32)+ , (VecReadByteArrayOp FloatVec 4 W64)+ , (VecReadByteArrayOp FloatVec 16 W32)+ , (VecReadByteArrayOp FloatVec 8 W64)+ , (VecWriteByteArrayOp IntVec 16 W8)+ , (VecWriteByteArrayOp IntVec 8 W16)+ , (VecWriteByteArrayOp IntVec 4 W32)+ , (VecWriteByteArrayOp IntVec 2 W64)+ , (VecWriteByteArrayOp IntVec 32 W8)+ , (VecWriteByteArrayOp IntVec 16 W16)+ , (VecWriteByteArrayOp IntVec 8 W32)+ , (VecWriteByteArrayOp IntVec 4 W64)+ , (VecWriteByteArrayOp IntVec 64 W8)+ , (VecWriteByteArrayOp IntVec 32 W16)+ , (VecWriteByteArrayOp IntVec 16 W32)+ , (VecWriteByteArrayOp IntVec 8 W64)+ , (VecWriteByteArrayOp WordVec 16 W8)+ , (VecWriteByteArrayOp WordVec 8 W16)+ , (VecWriteByteArrayOp WordVec 4 W32)+ , (VecWriteByteArrayOp WordVec 2 W64)+ , (VecWriteByteArrayOp WordVec 32 W8)+ , (VecWriteByteArrayOp WordVec 16 W16)+ , (VecWriteByteArrayOp WordVec 8 W32)+ , (VecWriteByteArrayOp WordVec 4 W64)+ , (VecWriteByteArrayOp WordVec 64 W8)+ , (VecWriteByteArrayOp WordVec 32 W16)+ , (VecWriteByteArrayOp WordVec 16 W32)+ , (VecWriteByteArrayOp WordVec 8 W64)+ , (VecWriteByteArrayOp FloatVec 4 W32)+ , (VecWriteByteArrayOp FloatVec 2 W64)+ , (VecWriteByteArrayOp FloatVec 8 W32)+ , (VecWriteByteArrayOp FloatVec 4 W64)+ , (VecWriteByteArrayOp FloatVec 16 W32)+ , (VecWriteByteArrayOp FloatVec 8 W64)+ , (VecIndexOffAddrOp IntVec 16 W8)+ , (VecIndexOffAddrOp IntVec 8 W16)+ , (VecIndexOffAddrOp IntVec 4 W32)+ , (VecIndexOffAddrOp IntVec 2 W64)+ , (VecIndexOffAddrOp IntVec 32 W8)+ , (VecIndexOffAddrOp IntVec 16 W16)+ , (VecIndexOffAddrOp IntVec 8 W32)+ , (VecIndexOffAddrOp IntVec 4 W64)+ , (VecIndexOffAddrOp IntVec 64 W8)+ , (VecIndexOffAddrOp IntVec 32 W16)+ , (VecIndexOffAddrOp IntVec 16 W32)+ , (VecIndexOffAddrOp IntVec 8 W64)+ , (VecIndexOffAddrOp WordVec 16 W8)+ , (VecIndexOffAddrOp WordVec 8 W16)+ , (VecIndexOffAddrOp WordVec 4 W32)+ , (VecIndexOffAddrOp WordVec 2 W64)+ , (VecIndexOffAddrOp WordVec 32 W8)+ , (VecIndexOffAddrOp WordVec 16 W16)+ , (VecIndexOffAddrOp WordVec 8 W32)+ , (VecIndexOffAddrOp WordVec 4 W64)+ , (VecIndexOffAddrOp WordVec 64 W8)+ , (VecIndexOffAddrOp WordVec 32 W16)+ , (VecIndexOffAddrOp WordVec 16 W32)+ , (VecIndexOffAddrOp WordVec 8 W64)+ , (VecIndexOffAddrOp FloatVec 4 W32)+ , (VecIndexOffAddrOp FloatVec 2 W64)+ , (VecIndexOffAddrOp FloatVec 8 W32)+ , (VecIndexOffAddrOp FloatVec 4 W64)+ , (VecIndexOffAddrOp FloatVec 16 W32)+ , (VecIndexOffAddrOp FloatVec 8 W64)+ , (VecReadOffAddrOp IntVec 16 W8)+ , (VecReadOffAddrOp IntVec 8 W16)+ , (VecReadOffAddrOp IntVec 4 W32)+ , (VecReadOffAddrOp IntVec 2 W64)+ , (VecReadOffAddrOp IntVec 32 W8)+ , (VecReadOffAddrOp IntVec 16 W16)+ , (VecReadOffAddrOp IntVec 8 W32)+ , (VecReadOffAddrOp IntVec 4 W64)+ , (VecReadOffAddrOp IntVec 64 W8)+ , (VecReadOffAddrOp IntVec 32 W16)+ , (VecReadOffAddrOp IntVec 16 W32)+ , (VecReadOffAddrOp IntVec 8 W64)+ , (VecReadOffAddrOp WordVec 16 W8)+ , (VecReadOffAddrOp WordVec 8 W16)+ , (VecReadOffAddrOp WordVec 4 W32)+ , (VecReadOffAddrOp WordVec 2 W64)+ , (VecReadOffAddrOp WordVec 32 W8)+ , (VecReadOffAddrOp WordVec 16 W16)+ , (VecReadOffAddrOp WordVec 8 W32)+ , (VecReadOffAddrOp WordVec 4 W64)+ , (VecReadOffAddrOp WordVec 64 W8)+ , (VecReadOffAddrOp WordVec 32 W16)+ , (VecReadOffAddrOp WordVec 16 W32)+ , (VecReadOffAddrOp WordVec 8 W64)+ , (VecReadOffAddrOp FloatVec 4 W32)+ , (VecReadOffAddrOp FloatVec 2 W64)+ , (VecReadOffAddrOp FloatVec 8 W32)+ , (VecReadOffAddrOp FloatVec 4 W64)+ , (VecReadOffAddrOp FloatVec 16 W32)+ , (VecReadOffAddrOp FloatVec 8 W64)+ , (VecWriteOffAddrOp IntVec 16 W8)+ , (VecWriteOffAddrOp IntVec 8 W16)+ , (VecWriteOffAddrOp IntVec 4 W32)+ , (VecWriteOffAddrOp IntVec 2 W64)+ , (VecWriteOffAddrOp IntVec 32 W8)+ , (VecWriteOffAddrOp IntVec 16 W16)+ , (VecWriteOffAddrOp IntVec 8 W32)+ , (VecWriteOffAddrOp IntVec 4 W64)+ , (VecWriteOffAddrOp IntVec 64 W8)+ , (VecWriteOffAddrOp IntVec 32 W16)+ , (VecWriteOffAddrOp IntVec 16 W32)+ , (VecWriteOffAddrOp IntVec 8 W64)+ , (VecWriteOffAddrOp WordVec 16 W8)+ , (VecWriteOffAddrOp WordVec 8 W16)+ , (VecWriteOffAddrOp WordVec 4 W32)+ , (VecWriteOffAddrOp WordVec 2 W64)+ , (VecWriteOffAddrOp WordVec 32 W8)+ , (VecWriteOffAddrOp WordVec 16 W16)+ , (VecWriteOffAddrOp WordVec 8 W32)+ , (VecWriteOffAddrOp WordVec 4 W64)+ , (VecWriteOffAddrOp WordVec 64 W8)+ , (VecWriteOffAddrOp WordVec 32 W16)+ , (VecWriteOffAddrOp WordVec 16 W32)+ , (VecWriteOffAddrOp WordVec 8 W64)+ , (VecWriteOffAddrOp FloatVec 4 W32)+ , (VecWriteOffAddrOp FloatVec 2 W64)+ , (VecWriteOffAddrOp FloatVec 8 W32)+ , (VecWriteOffAddrOp FloatVec 4 W64)+ , (VecWriteOffAddrOp FloatVec 16 W32)+ , (VecWriteOffAddrOp FloatVec 8 W64)+ , (VecIndexScalarByteArrayOp IntVec 16 W8)+ , (VecIndexScalarByteArrayOp IntVec 8 W16)+ , (VecIndexScalarByteArrayOp IntVec 4 W32)+ , (VecIndexScalarByteArrayOp IntVec 2 W64)+ , (VecIndexScalarByteArrayOp IntVec 32 W8)+ , (VecIndexScalarByteArrayOp IntVec 16 W16)+ , (VecIndexScalarByteArrayOp IntVec 8 W32)+ , (VecIndexScalarByteArrayOp IntVec 4 W64)+ , (VecIndexScalarByteArrayOp IntVec 64 W8)+ , (VecIndexScalarByteArrayOp IntVec 32 W16)+ , (VecIndexScalarByteArrayOp IntVec 16 W32)+ , (VecIndexScalarByteArrayOp IntVec 8 W64)+ , (VecIndexScalarByteArrayOp WordVec 16 W8)+ , (VecIndexScalarByteArrayOp WordVec 8 W16)+ , (VecIndexScalarByteArrayOp WordVec 4 W32)+ , (VecIndexScalarByteArrayOp WordVec 2 W64)+ , (VecIndexScalarByteArrayOp WordVec 32 W8)+ , (VecIndexScalarByteArrayOp WordVec 16 W16)+ , (VecIndexScalarByteArrayOp WordVec 8 W32)+ , (VecIndexScalarByteArrayOp WordVec 4 W64)+ , (VecIndexScalarByteArrayOp WordVec 64 W8)+ , (VecIndexScalarByteArrayOp WordVec 32 W16)+ , (VecIndexScalarByteArrayOp WordVec 16 W32)+ , (VecIndexScalarByteArrayOp WordVec 8 W64)+ , (VecIndexScalarByteArrayOp FloatVec 4 W32)+ , (VecIndexScalarByteArrayOp FloatVec 2 W64)+ , (VecIndexScalarByteArrayOp FloatVec 8 W32)+ , (VecIndexScalarByteArrayOp FloatVec 4 W64)+ , (VecIndexScalarByteArrayOp FloatVec 16 W32)+ , (VecIndexScalarByteArrayOp FloatVec 8 W64)+ , (VecReadScalarByteArrayOp IntVec 16 W8)+ , (VecReadScalarByteArrayOp IntVec 8 W16)+ , (VecReadScalarByteArrayOp IntVec 4 W32)+ , (VecReadScalarByteArrayOp IntVec 2 W64)+ , (VecReadScalarByteArrayOp IntVec 32 W8)+ , (VecReadScalarByteArrayOp IntVec 16 W16)+ , (VecReadScalarByteArrayOp IntVec 8 W32)+ , (VecReadScalarByteArrayOp IntVec 4 W64)+ , (VecReadScalarByteArrayOp IntVec 64 W8)+ , (VecReadScalarByteArrayOp IntVec 32 W16)+ , (VecReadScalarByteArrayOp IntVec 16 W32)+ , (VecReadScalarByteArrayOp IntVec 8 W64)+ , (VecReadScalarByteArrayOp WordVec 16 W8)+ , (VecReadScalarByteArrayOp WordVec 8 W16)+ , (VecReadScalarByteArrayOp WordVec 4 W32)+ , (VecReadScalarByteArrayOp WordVec 2 W64)+ , (VecReadScalarByteArrayOp WordVec 32 W8)+ , (VecReadScalarByteArrayOp WordVec 16 W16)+ , (VecReadScalarByteArrayOp WordVec 8 W32)+ , (VecReadScalarByteArrayOp WordVec 4 W64)+ , (VecReadScalarByteArrayOp WordVec 64 W8)+ , (VecReadScalarByteArrayOp WordVec 32 W16)+ , (VecReadScalarByteArrayOp WordVec 16 W32)+ , (VecReadScalarByteArrayOp WordVec 8 W64)+ , (VecReadScalarByteArrayOp FloatVec 4 W32)+ , (VecReadScalarByteArrayOp FloatVec 2 W64)+ , (VecReadScalarByteArrayOp FloatVec 8 W32)+ , (VecReadScalarByteArrayOp FloatVec 4 W64)+ , (VecReadScalarByteArrayOp FloatVec 16 W32)+ , (VecReadScalarByteArrayOp FloatVec 8 W64)+ , (VecWriteScalarByteArrayOp IntVec 16 W8)+ , (VecWriteScalarByteArrayOp IntVec 8 W16)+ , (VecWriteScalarByteArrayOp IntVec 4 W32)+ , (VecWriteScalarByteArrayOp IntVec 2 W64)+ , (VecWriteScalarByteArrayOp IntVec 32 W8)+ , (VecWriteScalarByteArrayOp IntVec 16 W16)+ , (VecWriteScalarByteArrayOp IntVec 8 W32)+ , (VecWriteScalarByteArrayOp IntVec 4 W64)+ , (VecWriteScalarByteArrayOp IntVec 64 W8)+ , (VecWriteScalarByteArrayOp IntVec 32 W16)+ , (VecWriteScalarByteArrayOp IntVec 16 W32)+ , (VecWriteScalarByteArrayOp IntVec 8 W64)+ , (VecWriteScalarByteArrayOp WordVec 16 W8)+ , (VecWriteScalarByteArrayOp WordVec 8 W16)+ , (VecWriteScalarByteArrayOp WordVec 4 W32)+ , (VecWriteScalarByteArrayOp WordVec 2 W64)+ , (VecWriteScalarByteArrayOp WordVec 32 W8)+ , (VecWriteScalarByteArrayOp WordVec 16 W16)+ , (VecWriteScalarByteArrayOp WordVec 8 W32)+ , (VecWriteScalarByteArrayOp WordVec 4 W64)+ , (VecWriteScalarByteArrayOp WordVec 64 W8)+ , (VecWriteScalarByteArrayOp WordVec 32 W16)+ , (VecWriteScalarByteArrayOp WordVec 16 W32)+ , (VecWriteScalarByteArrayOp WordVec 8 W64)+ , (VecWriteScalarByteArrayOp FloatVec 4 W32)+ , (VecWriteScalarByteArrayOp FloatVec 2 W64)+ , (VecWriteScalarByteArrayOp FloatVec 8 W32)+ , (VecWriteScalarByteArrayOp FloatVec 4 W64)+ , (VecWriteScalarByteArrayOp FloatVec 16 W32)+ , (VecWriteScalarByteArrayOp FloatVec 8 W64)+ , (VecIndexScalarOffAddrOp IntVec 16 W8)+ , (VecIndexScalarOffAddrOp IntVec 8 W16)+ , (VecIndexScalarOffAddrOp IntVec 4 W32)+ , (VecIndexScalarOffAddrOp IntVec 2 W64)+ , (VecIndexScalarOffAddrOp IntVec 32 W8)+ , (VecIndexScalarOffAddrOp IntVec 16 W16)+ , (VecIndexScalarOffAddrOp IntVec 8 W32)+ , (VecIndexScalarOffAddrOp IntVec 4 W64)+ , (VecIndexScalarOffAddrOp IntVec 64 W8)+ , (VecIndexScalarOffAddrOp IntVec 32 W16)+ , (VecIndexScalarOffAddrOp IntVec 16 W32)+ , (VecIndexScalarOffAddrOp IntVec 8 W64)+ , (VecIndexScalarOffAddrOp WordVec 16 W8)+ , (VecIndexScalarOffAddrOp WordVec 8 W16)+ , (VecIndexScalarOffAddrOp WordVec 4 W32)+ , (VecIndexScalarOffAddrOp WordVec 2 W64)+ , (VecIndexScalarOffAddrOp WordVec 32 W8)+ , (VecIndexScalarOffAddrOp WordVec 16 W16)+ , (VecIndexScalarOffAddrOp WordVec 8 W32)+ , (VecIndexScalarOffAddrOp WordVec 4 W64)+ , (VecIndexScalarOffAddrOp WordVec 64 W8)+ , (VecIndexScalarOffAddrOp WordVec 32 W16)+ , (VecIndexScalarOffAddrOp WordVec 16 W32)+ , (VecIndexScalarOffAddrOp WordVec 8 W64)+ , (VecIndexScalarOffAddrOp FloatVec 4 W32)+ , (VecIndexScalarOffAddrOp FloatVec 2 W64)+ , (VecIndexScalarOffAddrOp FloatVec 8 W32)+ , (VecIndexScalarOffAddrOp FloatVec 4 W64)+ , (VecIndexScalarOffAddrOp FloatVec 16 W32)+ , (VecIndexScalarOffAddrOp FloatVec 8 W64)+ , (VecReadScalarOffAddrOp IntVec 16 W8)+ , (VecReadScalarOffAddrOp IntVec 8 W16)+ , (VecReadScalarOffAddrOp IntVec 4 W32)+ , (VecReadScalarOffAddrOp IntVec 2 W64)+ , (VecReadScalarOffAddrOp IntVec 32 W8)+ , (VecReadScalarOffAddrOp IntVec 16 W16)+ , (VecReadScalarOffAddrOp IntVec 8 W32)+ , (VecReadScalarOffAddrOp IntVec 4 W64)+ , (VecReadScalarOffAddrOp IntVec 64 W8)+ , (VecReadScalarOffAddrOp IntVec 32 W16)+ , (VecReadScalarOffAddrOp IntVec 16 W32)+ , (VecReadScalarOffAddrOp IntVec 8 W64)+ , (VecReadScalarOffAddrOp WordVec 16 W8)+ , (VecReadScalarOffAddrOp WordVec 8 W16)+ , (VecReadScalarOffAddrOp WordVec 4 W32)+ , (VecReadScalarOffAddrOp WordVec 2 W64)+ , (VecReadScalarOffAddrOp WordVec 32 W8)+ , (VecReadScalarOffAddrOp WordVec 16 W16)+ , (VecReadScalarOffAddrOp WordVec 8 W32)+ , (VecReadScalarOffAddrOp WordVec 4 W64)+ , (VecReadScalarOffAddrOp WordVec 64 W8)+ , (VecReadScalarOffAddrOp WordVec 32 W16)+ , (VecReadScalarOffAddrOp WordVec 16 W32)+ , (VecReadScalarOffAddrOp WordVec 8 W64)+ , (VecReadScalarOffAddrOp FloatVec 4 W32)+ , (VecReadScalarOffAddrOp FloatVec 2 W64)+ , (VecReadScalarOffAddrOp FloatVec 8 W32)+ , (VecReadScalarOffAddrOp FloatVec 4 W64)+ , (VecReadScalarOffAddrOp FloatVec 16 W32)+ , (VecReadScalarOffAddrOp FloatVec 8 W64)+ , (VecWriteScalarOffAddrOp IntVec 16 W8)+ , (VecWriteScalarOffAddrOp IntVec 8 W16)+ , (VecWriteScalarOffAddrOp IntVec 4 W32)+ , (VecWriteScalarOffAddrOp IntVec 2 W64)+ , (VecWriteScalarOffAddrOp IntVec 32 W8)+ , (VecWriteScalarOffAddrOp IntVec 16 W16)+ , (VecWriteScalarOffAddrOp IntVec 8 W32)+ , (VecWriteScalarOffAddrOp IntVec 4 W64)+ , (VecWriteScalarOffAddrOp IntVec 64 W8)+ , (VecWriteScalarOffAddrOp IntVec 32 W16)+ , (VecWriteScalarOffAddrOp IntVec 16 W32)+ , (VecWriteScalarOffAddrOp IntVec 8 W64)+ , (VecWriteScalarOffAddrOp WordVec 16 W8)+ , (VecWriteScalarOffAddrOp WordVec 8 W16)+ , (VecWriteScalarOffAddrOp WordVec 4 W32)+ , (VecWriteScalarOffAddrOp WordVec 2 W64)+ , (VecWriteScalarOffAddrOp WordVec 32 W8)+ , (VecWriteScalarOffAddrOp WordVec 16 W16)+ , (VecWriteScalarOffAddrOp WordVec 8 W32)+ , (VecWriteScalarOffAddrOp WordVec 4 W64)+ , (VecWriteScalarOffAddrOp WordVec 64 W8)+ , (VecWriteScalarOffAddrOp WordVec 32 W16)+ , (VecWriteScalarOffAddrOp WordVec 16 W32)+ , (VecWriteScalarOffAddrOp WordVec 8 W64)+ , (VecWriteScalarOffAddrOp FloatVec 4 W32)+ , (VecWriteScalarOffAddrOp FloatVec 2 W64)+ , (VecWriteScalarOffAddrOp FloatVec 8 W32)+ , (VecWriteScalarOffAddrOp FloatVec 4 W64)+ , (VecWriteScalarOffAddrOp FloatVec 16 W32)+ , (VecWriteScalarOffAddrOp FloatVec 8 W64)+ , PrefetchByteArrayOp3+ , PrefetchMutableByteArrayOp3+ , PrefetchAddrOp3+ , PrefetchValueOp3+ , PrefetchByteArrayOp2+ , PrefetchMutableByteArrayOp2+ , PrefetchAddrOp2+ , PrefetchValueOp2+ , PrefetchByteArrayOp1+ , PrefetchMutableByteArrayOp1+ , PrefetchAddrOp1+ , PrefetchValueOp1+ , PrefetchByteArrayOp0+ , PrefetchMutableByteArrayOp0+ , PrefetchAddrOp0+ , PrefetchValueOp0+ ]
+ autogen/primop-out-of-line.hs-incl view
@@ -0,0 +1,99 @@+primOpOutOfLine DoubleDecode_2IntOp = True+primOpOutOfLine DoubleDecode_Int64Op = True+primOpOutOfLine FloatDecode_IntOp = True+primOpOutOfLine NewArrayOp = True+primOpOutOfLine UnsafeThawArrayOp = True+primOpOutOfLine CopyArrayOp = True+primOpOutOfLine CopyMutableArrayOp = True+primOpOutOfLine CloneArrayOp = True+primOpOutOfLine CloneMutableArrayOp = True+primOpOutOfLine FreezeArrayOp = True+primOpOutOfLine ThawArrayOp = True+primOpOutOfLine CasArrayOp = True+primOpOutOfLine NewSmallArrayOp = True+primOpOutOfLine UnsafeThawSmallArrayOp = True+primOpOutOfLine CopySmallArrayOp = True+primOpOutOfLine CopySmallMutableArrayOp = True+primOpOutOfLine CloneSmallArrayOp = True+primOpOutOfLine CloneSmallMutableArrayOp = True+primOpOutOfLine FreezeSmallArrayOp = True+primOpOutOfLine ThawSmallArrayOp = True+primOpOutOfLine CasSmallArrayOp = True+primOpOutOfLine NewByteArrayOp_Char = True+primOpOutOfLine NewPinnedByteArrayOp_Char = True+primOpOutOfLine NewAlignedPinnedByteArrayOp_Char = True+primOpOutOfLine MutableByteArrayIsPinnedOp = True+primOpOutOfLine ByteArrayIsPinnedOp = True+primOpOutOfLine ShrinkMutableByteArrayOp_Char = True+primOpOutOfLine ResizeMutableByteArrayOp_Char = True+primOpOutOfLine NewArrayArrayOp = True+primOpOutOfLine CopyArrayArrayOp = True+primOpOutOfLine CopyMutableArrayArrayOp = True+primOpOutOfLine NewMutVarOp = True+primOpOutOfLine AtomicModifyMutVarOp = True+primOpOutOfLine CasMutVarOp = True+primOpOutOfLine CatchOp = True+primOpOutOfLine RaiseOp = True+primOpOutOfLine RaiseIOOp = True+primOpOutOfLine MaskAsyncExceptionsOp = True+primOpOutOfLine MaskUninterruptibleOp = True+primOpOutOfLine UnmaskAsyncExceptionsOp = True+primOpOutOfLine MaskStatus = True+primOpOutOfLine AtomicallyOp = True+primOpOutOfLine RetryOp = True+primOpOutOfLine CatchRetryOp = True+primOpOutOfLine CatchSTMOp = True+primOpOutOfLine Check = True+primOpOutOfLine NewTVarOp = True+primOpOutOfLine ReadTVarOp = True+primOpOutOfLine ReadTVarIOOp = True+primOpOutOfLine WriteTVarOp = True+primOpOutOfLine NewMVarOp = True+primOpOutOfLine TakeMVarOp = True+primOpOutOfLine TryTakeMVarOp = True+primOpOutOfLine PutMVarOp = True+primOpOutOfLine TryPutMVarOp = True+primOpOutOfLine ReadMVarOp = True+primOpOutOfLine TryReadMVarOp = True+primOpOutOfLine IsEmptyMVarOp = True+primOpOutOfLine DelayOp = True+primOpOutOfLine WaitReadOp = True+primOpOutOfLine WaitWriteOp = True+primOpOutOfLine ForkOp = True+primOpOutOfLine ForkOnOp = True+primOpOutOfLine KillThreadOp = True+primOpOutOfLine YieldOp = True+primOpOutOfLine MyThreadIdOp = True+primOpOutOfLine LabelThreadOp = True+primOpOutOfLine IsCurrentThreadBoundOp = True+primOpOutOfLine NoDuplicateOp = True+primOpOutOfLine ThreadStatusOp = True+primOpOutOfLine MkWeakOp = True+primOpOutOfLine MkWeakNoFinalizerOp = True+primOpOutOfLine AddCFinalizerToWeakOp = True+primOpOutOfLine DeRefWeakOp = True+primOpOutOfLine FinalizeWeakOp = True+primOpOutOfLine MakeStablePtrOp = True+primOpOutOfLine DeRefStablePtrOp = True+primOpOutOfLine MakeStableNameOp = True+primOpOutOfLine CompactNewOp = True+primOpOutOfLine CompactResizeOp = True+primOpOutOfLine CompactContainsOp = True+primOpOutOfLine CompactContainsAnyOp = True+primOpOutOfLine CompactGetFirstBlockOp = True+primOpOutOfLine CompactGetNextBlockOp = True+primOpOutOfLine CompactAllocateBlockOp = True+primOpOutOfLine CompactFixupPointersOp = True+primOpOutOfLine CompactAdd = True+primOpOutOfLine CompactAddWithSharing = True+primOpOutOfLine CompactSize = True+primOpOutOfLine GetSparkOp = True+primOpOutOfLine NumSparks = True+primOpOutOfLine MkApUpd0_Op = True+primOpOutOfLine NewBCOOp = True+primOpOutOfLine UnpackClosureOp = True+primOpOutOfLine GetApStackValOp = True+primOpOutOfLine ClearCCSOp = True+primOpOutOfLine TraceEventOp = True+primOpOutOfLine TraceMarkerOp = True+primOpOutOfLine _ = False
+ autogen/primop-primop-info.hs-incl view
@@ -0,0 +1,1069 @@+primOpInfo CharGtOp = mkCompare (fsLit "gtChar#") charPrimTy+primOpInfo CharGeOp = mkCompare (fsLit "geChar#") charPrimTy+primOpInfo CharEqOp = mkCompare (fsLit "eqChar#") charPrimTy+primOpInfo CharNeOp = mkCompare (fsLit "neChar#") charPrimTy+primOpInfo CharLtOp = mkCompare (fsLit "ltChar#") charPrimTy+primOpInfo CharLeOp = mkCompare (fsLit "leChar#") charPrimTy+primOpInfo OrdOp = mkGenPrimOp (fsLit "ord#") [] [charPrimTy] (intPrimTy)+primOpInfo IntAddOp = mkDyadic (fsLit "+#") intPrimTy+primOpInfo IntSubOp = mkDyadic (fsLit "-#") intPrimTy+primOpInfo IntMulOp = mkDyadic (fsLit "*#") intPrimTy+primOpInfo IntMulMayOfloOp = mkDyadic (fsLit "mulIntMayOflo#") intPrimTy+primOpInfo IntQuotOp = mkDyadic (fsLit "quotInt#") intPrimTy+primOpInfo IntRemOp = mkDyadic (fsLit "remInt#") intPrimTy+primOpInfo IntQuotRemOp = mkGenPrimOp (fsLit "quotRemInt#") [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo AndIOp = mkDyadic (fsLit "andI#") intPrimTy+primOpInfo OrIOp = mkDyadic (fsLit "orI#") intPrimTy+primOpInfo XorIOp = mkDyadic (fsLit "xorI#") intPrimTy+primOpInfo NotIOp = mkMonadic (fsLit "notI#") intPrimTy+primOpInfo IntNegOp = mkMonadic (fsLit "negateInt#") intPrimTy+primOpInfo IntAddCOp = mkGenPrimOp (fsLit "addIntC#") [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo IntSubCOp = mkGenPrimOp (fsLit "subIntC#") [] [intPrimTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo IntGtOp = mkCompare (fsLit ">#") intPrimTy+primOpInfo IntGeOp = mkCompare (fsLit ">=#") intPrimTy+primOpInfo IntEqOp = mkCompare (fsLit "==#") intPrimTy+primOpInfo IntNeOp = mkCompare (fsLit "/=#") intPrimTy+primOpInfo IntLtOp = mkCompare (fsLit "<#") intPrimTy+primOpInfo IntLeOp = mkCompare (fsLit "<=#") intPrimTy+primOpInfo ChrOp = mkGenPrimOp (fsLit "chr#") [] [intPrimTy] (charPrimTy)+primOpInfo Int2WordOp = mkGenPrimOp (fsLit "int2Word#") [] [intPrimTy] (wordPrimTy)+primOpInfo Int2FloatOp = mkGenPrimOp (fsLit "int2Float#") [] [intPrimTy] (floatPrimTy)+primOpInfo Int2DoubleOp = mkGenPrimOp (fsLit "int2Double#") [] [intPrimTy] (doublePrimTy)+primOpInfo Word2FloatOp = mkGenPrimOp (fsLit "word2Float#") [] [wordPrimTy] (floatPrimTy)+primOpInfo Word2DoubleOp = mkGenPrimOp (fsLit "word2Double#") [] [wordPrimTy] (doublePrimTy)+primOpInfo ISllOp = mkGenPrimOp (fsLit "uncheckedIShiftL#") [] [intPrimTy, intPrimTy] (intPrimTy)+primOpInfo ISraOp = mkGenPrimOp (fsLit "uncheckedIShiftRA#") [] [intPrimTy, intPrimTy] (intPrimTy)+primOpInfo ISrlOp = mkGenPrimOp (fsLit "uncheckedIShiftRL#") [] [intPrimTy, intPrimTy] (intPrimTy)+primOpInfo WordAddOp = mkDyadic (fsLit "plusWord#") wordPrimTy+primOpInfo WordSubCOp = mkGenPrimOp (fsLit "subWordC#") [] [wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, intPrimTy]))+primOpInfo WordAdd2Op = mkGenPrimOp (fsLit "plusWord2#") [] [wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy]))+primOpInfo WordSubOp = mkDyadic (fsLit "minusWord#") wordPrimTy+primOpInfo WordMulOp = mkDyadic (fsLit "timesWord#") wordPrimTy+primOpInfo WordMul2Op = mkGenPrimOp (fsLit "timesWord2#") [] [wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy]))+primOpInfo WordQuotOp = mkDyadic (fsLit "quotWord#") wordPrimTy+primOpInfo WordRemOp = mkDyadic (fsLit "remWord#") wordPrimTy+primOpInfo WordQuotRemOp = mkGenPrimOp (fsLit "quotRemWord#") [] [wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy]))+primOpInfo WordQuotRem2Op = mkGenPrimOp (fsLit "quotRemWord2#") [] [wordPrimTy, wordPrimTy, wordPrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy]))+primOpInfo AndOp = mkDyadic (fsLit "and#") wordPrimTy+primOpInfo OrOp = mkDyadic (fsLit "or#") wordPrimTy+primOpInfo XorOp = mkDyadic (fsLit "xor#") wordPrimTy+primOpInfo NotOp = mkMonadic (fsLit "not#") wordPrimTy+primOpInfo SllOp = mkGenPrimOp (fsLit "uncheckedShiftL#") [] [wordPrimTy, intPrimTy] (wordPrimTy)+primOpInfo SrlOp = mkGenPrimOp (fsLit "uncheckedShiftRL#") [] [wordPrimTy, intPrimTy] (wordPrimTy)+primOpInfo Word2IntOp = mkGenPrimOp (fsLit "word2Int#") [] [wordPrimTy] (intPrimTy)+primOpInfo WordGtOp = mkCompare (fsLit "gtWord#") wordPrimTy+primOpInfo WordGeOp = mkCompare (fsLit "geWord#") wordPrimTy+primOpInfo WordEqOp = mkCompare (fsLit "eqWord#") wordPrimTy+primOpInfo WordNeOp = mkCompare (fsLit "neWord#") wordPrimTy+primOpInfo WordLtOp = mkCompare (fsLit "ltWord#") wordPrimTy+primOpInfo WordLeOp = mkCompare (fsLit "leWord#") wordPrimTy+primOpInfo PopCnt8Op = mkMonadic (fsLit "popCnt8#") wordPrimTy+primOpInfo PopCnt16Op = mkMonadic (fsLit "popCnt16#") wordPrimTy+primOpInfo PopCnt32Op = mkMonadic (fsLit "popCnt32#") wordPrimTy+primOpInfo PopCnt64Op = mkGenPrimOp (fsLit "popCnt64#") [] [wordPrimTy] (wordPrimTy)+primOpInfo PopCntOp = mkMonadic (fsLit "popCnt#") wordPrimTy+primOpInfo Clz8Op = mkMonadic (fsLit "clz8#") wordPrimTy+primOpInfo Clz16Op = mkMonadic (fsLit "clz16#") wordPrimTy+primOpInfo Clz32Op = mkMonadic (fsLit "clz32#") wordPrimTy+primOpInfo Clz64Op = mkGenPrimOp (fsLit "clz64#") [] [wordPrimTy] (wordPrimTy)+primOpInfo ClzOp = mkMonadic (fsLit "clz#") wordPrimTy+primOpInfo Ctz8Op = mkMonadic (fsLit "ctz8#") wordPrimTy+primOpInfo Ctz16Op = mkMonadic (fsLit "ctz16#") wordPrimTy+primOpInfo Ctz32Op = mkMonadic (fsLit "ctz32#") wordPrimTy+primOpInfo Ctz64Op = mkGenPrimOp (fsLit "ctz64#") [] [wordPrimTy] (wordPrimTy)+primOpInfo CtzOp = mkMonadic (fsLit "ctz#") wordPrimTy+primOpInfo BSwap16Op = mkMonadic (fsLit "byteSwap16#") wordPrimTy+primOpInfo BSwap32Op = mkMonadic (fsLit "byteSwap32#") wordPrimTy+primOpInfo BSwap64Op = mkMonadic (fsLit "byteSwap64#") wordPrimTy+primOpInfo BSwapOp = mkMonadic (fsLit "byteSwap#") wordPrimTy+primOpInfo Narrow8IntOp = mkMonadic (fsLit "narrow8Int#") intPrimTy+primOpInfo Narrow16IntOp = mkMonadic (fsLit "narrow16Int#") intPrimTy+primOpInfo Narrow32IntOp = mkMonadic (fsLit "narrow32Int#") intPrimTy+primOpInfo Narrow8WordOp = mkMonadic (fsLit "narrow8Word#") wordPrimTy+primOpInfo Narrow16WordOp = mkMonadic (fsLit "narrow16Word#") wordPrimTy+primOpInfo Narrow32WordOp = mkMonadic (fsLit "narrow32Word#") wordPrimTy+primOpInfo DoubleGtOp = mkCompare (fsLit ">##") doublePrimTy+primOpInfo DoubleGeOp = mkCompare (fsLit ">=##") doublePrimTy+primOpInfo DoubleEqOp = mkCompare (fsLit "==##") doublePrimTy+primOpInfo DoubleNeOp = mkCompare (fsLit "/=##") doublePrimTy+primOpInfo DoubleLtOp = mkCompare (fsLit "<##") doublePrimTy+primOpInfo DoubleLeOp = mkCompare (fsLit "<=##") doublePrimTy+primOpInfo DoubleAddOp = mkDyadic (fsLit "+##") doublePrimTy+primOpInfo DoubleSubOp = mkDyadic (fsLit "-##") doublePrimTy+primOpInfo DoubleMulOp = mkDyadic (fsLit "*##") doublePrimTy+primOpInfo DoubleDivOp = mkDyadic (fsLit "/##") doublePrimTy+primOpInfo DoubleNegOp = mkMonadic (fsLit "negateDouble#") doublePrimTy+primOpInfo DoubleFabsOp = mkMonadic (fsLit "fabsDouble#") doublePrimTy+primOpInfo Double2IntOp = mkGenPrimOp (fsLit "double2Int#") [] [doublePrimTy] (intPrimTy)+primOpInfo Double2FloatOp = mkGenPrimOp (fsLit "double2Float#") [] [doublePrimTy] (floatPrimTy)+primOpInfo DoubleExpOp = mkMonadic (fsLit "expDouble#") doublePrimTy+primOpInfo DoubleLogOp = mkMonadic (fsLit "logDouble#") doublePrimTy+primOpInfo DoubleSqrtOp = mkMonadic (fsLit "sqrtDouble#") doublePrimTy+primOpInfo DoubleSinOp = mkMonadic (fsLit "sinDouble#") doublePrimTy+primOpInfo DoubleCosOp = mkMonadic (fsLit "cosDouble#") doublePrimTy+primOpInfo DoubleTanOp = mkMonadic (fsLit "tanDouble#") doublePrimTy+primOpInfo DoubleAsinOp = mkMonadic (fsLit "asinDouble#") doublePrimTy+primOpInfo DoubleAcosOp = mkMonadic (fsLit "acosDouble#") doublePrimTy+primOpInfo DoubleAtanOp = mkMonadic (fsLit "atanDouble#") doublePrimTy+primOpInfo DoubleSinhOp = mkMonadic (fsLit "sinhDouble#") doublePrimTy+primOpInfo DoubleCoshOp = mkMonadic (fsLit "coshDouble#") doublePrimTy+primOpInfo DoubleTanhOp = mkMonadic (fsLit "tanhDouble#") doublePrimTy+primOpInfo DoublePowerOp = mkDyadic (fsLit "**##") doublePrimTy+primOpInfo DoubleDecode_2IntOp = mkGenPrimOp (fsLit "decodeDouble_2Int#") [] [doublePrimTy] ((mkTupleTy Unboxed [intPrimTy, wordPrimTy, wordPrimTy, intPrimTy]))+primOpInfo DoubleDecode_Int64Op = mkGenPrimOp (fsLit "decodeDouble_Int64#") [] [doublePrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo FloatGtOp = mkCompare (fsLit "gtFloat#") floatPrimTy+primOpInfo FloatGeOp = mkCompare (fsLit "geFloat#") floatPrimTy+primOpInfo FloatEqOp = mkCompare (fsLit "eqFloat#") floatPrimTy+primOpInfo FloatNeOp = mkCompare (fsLit "neFloat#") floatPrimTy+primOpInfo FloatLtOp = mkCompare (fsLit "ltFloat#") floatPrimTy+primOpInfo FloatLeOp = mkCompare (fsLit "leFloat#") floatPrimTy+primOpInfo FloatAddOp = mkDyadic (fsLit "plusFloat#") floatPrimTy+primOpInfo FloatSubOp = mkDyadic (fsLit "minusFloat#") floatPrimTy+primOpInfo FloatMulOp = mkDyadic (fsLit "timesFloat#") floatPrimTy+primOpInfo FloatDivOp = mkDyadic (fsLit "divideFloat#") floatPrimTy+primOpInfo FloatNegOp = mkMonadic (fsLit "negateFloat#") floatPrimTy+primOpInfo FloatFabsOp = mkMonadic (fsLit "fabsFloat#") floatPrimTy+primOpInfo Float2IntOp = mkGenPrimOp (fsLit "float2Int#") [] [floatPrimTy] (intPrimTy)+primOpInfo FloatExpOp = mkMonadic (fsLit "expFloat#") floatPrimTy+primOpInfo FloatLogOp = mkMonadic (fsLit "logFloat#") floatPrimTy+primOpInfo FloatSqrtOp = mkMonadic (fsLit "sqrtFloat#") floatPrimTy+primOpInfo FloatSinOp = mkMonadic (fsLit "sinFloat#") floatPrimTy+primOpInfo FloatCosOp = mkMonadic (fsLit "cosFloat#") floatPrimTy+primOpInfo FloatTanOp = mkMonadic (fsLit "tanFloat#") floatPrimTy+primOpInfo FloatAsinOp = mkMonadic (fsLit "asinFloat#") floatPrimTy+primOpInfo FloatAcosOp = mkMonadic (fsLit "acosFloat#") floatPrimTy+primOpInfo FloatAtanOp = mkMonadic (fsLit "atanFloat#") floatPrimTy+primOpInfo FloatSinhOp = mkMonadic (fsLit "sinhFloat#") floatPrimTy+primOpInfo FloatCoshOp = mkMonadic (fsLit "coshFloat#") floatPrimTy+primOpInfo FloatTanhOp = mkMonadic (fsLit "tanhFloat#") floatPrimTy+primOpInfo FloatPowerOp = mkDyadic (fsLit "powerFloat#") floatPrimTy+primOpInfo Float2DoubleOp = mkGenPrimOp (fsLit "float2Double#") [] [floatPrimTy] (doublePrimTy)+primOpInfo FloatDecode_IntOp = mkGenPrimOp (fsLit "decodeFloat_Int#") [] [floatPrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo NewArrayOp = mkGenPrimOp (fsLit "newArray#") [alphaTyVar, deltaTyVar] [intPrimTy, alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo SameMutableArrayOp = mkGenPrimOp (fsLit "sameMutableArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, mkMutableArrayPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo ReadArrayOp = mkGenPrimOp (fsLit "readArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo WriteArrayOp = mkGenPrimOp (fsLit "writeArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo SizeofArrayOp = mkGenPrimOp (fsLit "sizeofArray#") [alphaTyVar] [mkArrayPrimTy alphaTy] (intPrimTy)+primOpInfo SizeofMutableArrayOp = mkGenPrimOp (fsLit "sizeofMutableArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo IndexArrayOp = mkGenPrimOp (fsLit "indexArray#") [alphaTyVar] [mkArrayPrimTy alphaTy, intPrimTy] ((mkTupleTy Unboxed [alphaTy]))+primOpInfo UnsafeFreezeArrayOp = mkGenPrimOp (fsLit "unsafeFreezeArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkArrayPrimTy alphaTy]))+primOpInfo UnsafeThawArrayOp = mkGenPrimOp (fsLit "unsafeThawArray#") [alphaTyVar, deltaTyVar] [mkArrayPrimTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo CopyArrayOp = mkGenPrimOp (fsLit "copyArray#") [alphaTyVar, deltaTyVar] [mkArrayPrimTy alphaTy, intPrimTy, mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyMutableArrayOp = mkGenPrimOp (fsLit "copyMutableArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CloneArrayOp = mkGenPrimOp (fsLit "cloneArray#") [alphaTyVar] [mkArrayPrimTy alphaTy, intPrimTy, intPrimTy] (mkArrayPrimTy alphaTy)+primOpInfo CloneMutableArrayOp = mkGenPrimOp (fsLit "cloneMutableArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo FreezeArrayOp = mkGenPrimOp (fsLit "freezeArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkArrayPrimTy alphaTy]))+primOpInfo ThawArrayOp = mkGenPrimOp (fsLit "thawArray#") [alphaTyVar, deltaTyVar] [mkArrayPrimTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo CasArrayOp = mkGenPrimOp (fsLit "casArray#") [deltaTyVar, alphaTyVar] [mkMutableArrayPrimTy deltaTy alphaTy, intPrimTy, alphaTy, alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy, alphaTy]))+primOpInfo NewSmallArrayOp = mkGenPrimOp (fsLit "newSmallArray#") [alphaTyVar, deltaTyVar] [intPrimTy, alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkSmallMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo SameSmallMutableArrayOp = mkGenPrimOp (fsLit "sameSmallMutableArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, mkSmallMutableArrayPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo ReadSmallArrayOp = mkGenPrimOp (fsLit "readSmallArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo WriteSmallArrayOp = mkGenPrimOp (fsLit "writeSmallArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo SizeofSmallArrayOp = mkGenPrimOp (fsLit "sizeofSmallArray#") [alphaTyVar] [mkSmallArrayPrimTy alphaTy] (intPrimTy)+primOpInfo SizeofSmallMutableArrayOp = mkGenPrimOp (fsLit "sizeofSmallMutableArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo IndexSmallArrayOp = mkGenPrimOp (fsLit "indexSmallArray#") [alphaTyVar] [mkSmallArrayPrimTy alphaTy, intPrimTy] ((mkTupleTy Unboxed [alphaTy]))+primOpInfo UnsafeFreezeSmallArrayOp = mkGenPrimOp (fsLit "unsafeFreezeSmallArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkSmallArrayPrimTy alphaTy]))+primOpInfo UnsafeThawSmallArrayOp = mkGenPrimOp (fsLit "unsafeThawSmallArray#") [alphaTyVar, deltaTyVar] [mkSmallArrayPrimTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkSmallMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo CopySmallArrayOp = mkGenPrimOp (fsLit "copySmallArray#") [alphaTyVar, deltaTyVar] [mkSmallArrayPrimTy alphaTy, intPrimTy, mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopySmallMutableArrayOp = mkGenPrimOp (fsLit "copySmallMutableArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CloneSmallArrayOp = mkGenPrimOp (fsLit "cloneSmallArray#") [alphaTyVar] [mkSmallArrayPrimTy alphaTy, intPrimTy, intPrimTy] (mkSmallArrayPrimTy alphaTy)+primOpInfo CloneSmallMutableArrayOp = mkGenPrimOp (fsLit "cloneSmallMutableArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkSmallMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo FreezeSmallArrayOp = mkGenPrimOp (fsLit "freezeSmallArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkSmallArrayPrimTy alphaTy]))+primOpInfo ThawSmallArrayOp = mkGenPrimOp (fsLit "thawSmallArray#") [alphaTyVar, deltaTyVar] [mkSmallArrayPrimTy alphaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkSmallMutableArrayPrimTy deltaTy alphaTy]))+primOpInfo CasSmallArrayOp = mkGenPrimOp (fsLit "casSmallArray#") [deltaTyVar, alphaTyVar] [mkSmallMutableArrayPrimTy deltaTy alphaTy, intPrimTy, alphaTy, alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy, alphaTy]))+primOpInfo NewByteArrayOp_Char = mkGenPrimOp (fsLit "newByteArray#") [deltaTyVar] [intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableByteArrayPrimTy deltaTy]))+primOpInfo NewPinnedByteArrayOp_Char = mkGenPrimOp (fsLit "newPinnedByteArray#") [deltaTyVar] [intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableByteArrayPrimTy deltaTy]))+primOpInfo NewAlignedPinnedByteArrayOp_Char = mkGenPrimOp (fsLit "newAlignedPinnedByteArray#") [deltaTyVar] [intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableByteArrayPrimTy deltaTy]))+primOpInfo MutableByteArrayIsPinnedOp = mkGenPrimOp (fsLit "isMutableByteArrayPinned#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy] (intPrimTy)+primOpInfo ByteArrayIsPinnedOp = mkGenPrimOp (fsLit "isByteArrayPinned#") [] [byteArrayPrimTy] (intPrimTy)+primOpInfo ByteArrayContents_Char = mkGenPrimOp (fsLit "byteArrayContents#") [] [byteArrayPrimTy] (addrPrimTy)+primOpInfo SameMutableByteArrayOp = mkGenPrimOp (fsLit "sameMutableByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, mkMutableByteArrayPrimTy deltaTy] (intPrimTy)+primOpInfo ShrinkMutableByteArrayOp_Char = mkGenPrimOp (fsLit "shrinkMutableByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo ResizeMutableByteArrayOp_Char = mkGenPrimOp (fsLit "resizeMutableByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableByteArrayPrimTy deltaTy]))+primOpInfo UnsafeFreezeByteArrayOp = mkGenPrimOp (fsLit "unsafeFreezeByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, byteArrayPrimTy]))+primOpInfo SizeofByteArrayOp = mkGenPrimOp (fsLit "sizeofByteArray#") [] [byteArrayPrimTy] (intPrimTy)+primOpInfo SizeofMutableByteArrayOp = mkGenPrimOp (fsLit "sizeofMutableByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy] (intPrimTy)+primOpInfo GetSizeofMutableByteArrayOp = mkGenPrimOp (fsLit "getSizeofMutableByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo IndexByteArrayOp_Char = mkGenPrimOp (fsLit "indexCharArray#") [] [byteArrayPrimTy, intPrimTy] (charPrimTy)+primOpInfo IndexByteArrayOp_WideChar = mkGenPrimOp (fsLit "indexWideCharArray#") [] [byteArrayPrimTy, intPrimTy] (charPrimTy)+primOpInfo IndexByteArrayOp_Int = mkGenPrimOp (fsLit "indexIntArray#") [] [byteArrayPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexByteArrayOp_Word = mkGenPrimOp (fsLit "indexWordArray#") [] [byteArrayPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexByteArrayOp_Addr = mkGenPrimOp (fsLit "indexAddrArray#") [] [byteArrayPrimTy, intPrimTy] (addrPrimTy)+primOpInfo IndexByteArrayOp_Float = mkGenPrimOp (fsLit "indexFloatArray#") [] [byteArrayPrimTy, intPrimTy] (floatPrimTy)+primOpInfo IndexByteArrayOp_Double = mkGenPrimOp (fsLit "indexDoubleArray#") [] [byteArrayPrimTy, intPrimTy] (doublePrimTy)+primOpInfo IndexByteArrayOp_StablePtr = mkGenPrimOp (fsLit "indexStablePtrArray#") [alphaTyVar] [byteArrayPrimTy, intPrimTy] (mkStablePtrPrimTy alphaTy)+primOpInfo IndexByteArrayOp_Int8 = mkGenPrimOp (fsLit "indexInt8Array#") [] [byteArrayPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexByteArrayOp_Int16 = mkGenPrimOp (fsLit "indexInt16Array#") [] [byteArrayPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexByteArrayOp_Int32 = mkGenPrimOp (fsLit "indexInt32Array#") [] [byteArrayPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexByteArrayOp_Int64 = mkGenPrimOp (fsLit "indexInt64Array#") [] [byteArrayPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexByteArrayOp_Word8 = mkGenPrimOp (fsLit "indexWord8Array#") [] [byteArrayPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexByteArrayOp_Word16 = mkGenPrimOp (fsLit "indexWord16Array#") [] [byteArrayPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexByteArrayOp_Word32 = mkGenPrimOp (fsLit "indexWord32Array#") [] [byteArrayPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexByteArrayOp_Word64 = mkGenPrimOp (fsLit "indexWord64Array#") [] [byteArrayPrimTy, intPrimTy] (wordPrimTy)+primOpInfo ReadByteArrayOp_Char = mkGenPrimOp (fsLit "readCharArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, charPrimTy]))+primOpInfo ReadByteArrayOp_WideChar = mkGenPrimOp (fsLit "readWideCharArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, charPrimTy]))+primOpInfo ReadByteArrayOp_Int = mkGenPrimOp (fsLit "readIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadByteArrayOp_Word = mkGenPrimOp (fsLit "readWordArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadByteArrayOp_Addr = mkGenPrimOp (fsLit "readAddrArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, addrPrimTy]))+primOpInfo ReadByteArrayOp_Float = mkGenPrimOp (fsLit "readFloatArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatPrimTy]))+primOpInfo ReadByteArrayOp_Double = mkGenPrimOp (fsLit "readDoubleArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doublePrimTy]))+primOpInfo ReadByteArrayOp_StablePtr = mkGenPrimOp (fsLit "readStablePtrArray#") [deltaTyVar, alphaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkStablePtrPrimTy alphaTy]))+primOpInfo ReadByteArrayOp_Int8 = mkGenPrimOp (fsLit "readInt8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadByteArrayOp_Int16 = mkGenPrimOp (fsLit "readInt16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadByteArrayOp_Int32 = mkGenPrimOp (fsLit "readInt32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadByteArrayOp_Int64 = mkGenPrimOp (fsLit "readInt64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadByteArrayOp_Word8 = mkGenPrimOp (fsLit "readWord8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadByteArrayOp_Word16 = mkGenPrimOp (fsLit "readWord16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadByteArrayOp_Word32 = mkGenPrimOp (fsLit "readWord32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadByteArrayOp_Word64 = mkGenPrimOp (fsLit "readWord64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo WriteByteArrayOp_Char = mkGenPrimOp (fsLit "writeCharArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, charPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_WideChar = mkGenPrimOp (fsLit "writeWideCharArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, charPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Int = mkGenPrimOp (fsLit "writeIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Word = mkGenPrimOp (fsLit "writeWordArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Addr = mkGenPrimOp (fsLit "writeAddrArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, addrPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Float = mkGenPrimOp (fsLit "writeFloatArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Double = mkGenPrimOp (fsLit "writeDoubleArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doublePrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_StablePtr = mkGenPrimOp (fsLit "writeStablePtrArray#") [deltaTyVar, alphaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStablePtrPrimTy alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Int8 = mkGenPrimOp (fsLit "writeInt8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Int16 = mkGenPrimOp (fsLit "writeInt16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Int32 = mkGenPrimOp (fsLit "writeInt32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Int64 = mkGenPrimOp (fsLit "writeInt64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Word8 = mkGenPrimOp (fsLit "writeWord8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Word16 = mkGenPrimOp (fsLit "writeWord16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Word32 = mkGenPrimOp (fsLit "writeWord32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteByteArrayOp_Word64 = mkGenPrimOp (fsLit "writeWord64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyByteArrayOp = mkGenPrimOp (fsLit "copyByteArray#") [deltaTyVar] [byteArrayPrimTy, intPrimTy, mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyMutableByteArrayOp = mkGenPrimOp (fsLit "copyMutableByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyByteArrayToAddrOp = mkGenPrimOp (fsLit "copyByteArrayToAddr#") [deltaTyVar] [byteArrayPrimTy, intPrimTy, addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyMutableByteArrayToAddrOp = mkGenPrimOp (fsLit "copyMutableByteArrayToAddr#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyAddrToByteArrayOp = mkGenPrimOp (fsLit "copyAddrToByteArray#") [deltaTyVar] [addrPrimTy, mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo SetByteArrayOp = mkGenPrimOp (fsLit "setByteArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo AtomicReadByteArrayOp_Int = mkGenPrimOp (fsLit "atomicReadIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo AtomicWriteByteArrayOp_Int = mkGenPrimOp (fsLit "atomicWriteIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CasByteArrayOp_Int = mkGenPrimOp (fsLit "casIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo FetchAddByteArrayOp_Int = mkGenPrimOp (fsLit "fetchAddIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo FetchSubByteArrayOp_Int = mkGenPrimOp (fsLit "fetchSubIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo FetchAndByteArrayOp_Int = mkGenPrimOp (fsLit "fetchAndIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo FetchNandByteArrayOp_Int = mkGenPrimOp (fsLit "fetchNandIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo FetchOrByteArrayOp_Int = mkGenPrimOp (fsLit "fetchOrIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo FetchXorByteArrayOp_Int = mkGenPrimOp (fsLit "fetchXorIntArray#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo NewArrayArrayOp = mkGenPrimOp (fsLit "newArrayArray#") [deltaTyVar] [intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableArrayArrayPrimTy deltaTy]))+primOpInfo SameMutableArrayArrayOp = mkGenPrimOp (fsLit "sameMutableArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, mkMutableArrayArrayPrimTy deltaTy] (intPrimTy)+primOpInfo UnsafeFreezeArrayArrayOp = mkGenPrimOp (fsLit "unsafeFreezeArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkArrayArrayPrimTy]))+primOpInfo SizeofArrayArrayOp = mkGenPrimOp (fsLit "sizeofArrayArray#") [] [mkArrayArrayPrimTy] (intPrimTy)+primOpInfo SizeofMutableArrayArrayOp = mkGenPrimOp (fsLit "sizeofMutableArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy] (intPrimTy)+primOpInfo IndexArrayArrayOp_ByteArray = mkGenPrimOp (fsLit "indexByteArrayArray#") [] [mkArrayArrayPrimTy, intPrimTy] (byteArrayPrimTy)+primOpInfo IndexArrayArrayOp_ArrayArray = mkGenPrimOp (fsLit "indexArrayArrayArray#") [] [mkArrayArrayPrimTy, intPrimTy] (mkArrayArrayPrimTy)+primOpInfo ReadArrayArrayOp_ByteArray = mkGenPrimOp (fsLit "readByteArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, byteArrayPrimTy]))+primOpInfo ReadArrayArrayOp_MutableByteArray = mkGenPrimOp (fsLit "readMutableByteArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableByteArrayPrimTy deltaTy]))+primOpInfo ReadArrayArrayOp_ArrayArray = mkGenPrimOp (fsLit "readArrayArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkArrayArrayPrimTy]))+primOpInfo ReadArrayArrayOp_MutableArrayArray = mkGenPrimOp (fsLit "readMutableArrayArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutableArrayArrayPrimTy deltaTy]))+primOpInfo WriteArrayArrayOp_ByteArray = mkGenPrimOp (fsLit "writeByteArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, byteArrayPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteArrayArrayOp_MutableByteArray = mkGenPrimOp (fsLit "writeMutableByteArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkMutableByteArrayPrimTy deltaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteArrayArrayOp_ArrayArray = mkGenPrimOp (fsLit "writeArrayArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkArrayArrayPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteArrayArrayOp_MutableArrayArray = mkGenPrimOp (fsLit "writeMutableArrayArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkMutableArrayArrayPrimTy deltaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyArrayArrayOp = mkGenPrimOp (fsLit "copyArrayArray#") [deltaTyVar] [mkArrayArrayPrimTy, intPrimTy, mkMutableArrayArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo CopyMutableArrayArrayOp = mkGenPrimOp (fsLit "copyMutableArrayArray#") [deltaTyVar] [mkMutableArrayArrayPrimTy deltaTy, intPrimTy, mkMutableArrayArrayPrimTy deltaTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo AddrAddOp = mkGenPrimOp (fsLit "plusAddr#") [] [addrPrimTy, intPrimTy] (addrPrimTy)+primOpInfo AddrSubOp = mkGenPrimOp (fsLit "minusAddr#") [] [addrPrimTy, addrPrimTy] (intPrimTy)+primOpInfo AddrRemOp = mkGenPrimOp (fsLit "remAddr#") [] [addrPrimTy, intPrimTy] (intPrimTy)+primOpInfo Addr2IntOp = mkGenPrimOp (fsLit "addr2Int#") [] [addrPrimTy] (intPrimTy)+primOpInfo Int2AddrOp = mkGenPrimOp (fsLit "int2Addr#") [] [intPrimTy] (addrPrimTy)+primOpInfo AddrGtOp = mkCompare (fsLit "gtAddr#") addrPrimTy+primOpInfo AddrGeOp = mkCompare (fsLit "geAddr#") addrPrimTy+primOpInfo AddrEqOp = mkCompare (fsLit "eqAddr#") addrPrimTy+primOpInfo AddrNeOp = mkCompare (fsLit "neAddr#") addrPrimTy+primOpInfo AddrLtOp = mkCompare (fsLit "ltAddr#") addrPrimTy+primOpInfo AddrLeOp = mkCompare (fsLit "leAddr#") addrPrimTy+primOpInfo IndexOffAddrOp_Char = mkGenPrimOp (fsLit "indexCharOffAddr#") [] [addrPrimTy, intPrimTy] (charPrimTy)+primOpInfo IndexOffAddrOp_WideChar = mkGenPrimOp (fsLit "indexWideCharOffAddr#") [] [addrPrimTy, intPrimTy] (charPrimTy)+primOpInfo IndexOffAddrOp_Int = mkGenPrimOp (fsLit "indexIntOffAddr#") [] [addrPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexOffAddrOp_Word = mkGenPrimOp (fsLit "indexWordOffAddr#") [] [addrPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexOffAddrOp_Addr = mkGenPrimOp (fsLit "indexAddrOffAddr#") [] [addrPrimTy, intPrimTy] (addrPrimTy)+primOpInfo IndexOffAddrOp_Float = mkGenPrimOp (fsLit "indexFloatOffAddr#") [] [addrPrimTy, intPrimTy] (floatPrimTy)+primOpInfo IndexOffAddrOp_Double = mkGenPrimOp (fsLit "indexDoubleOffAddr#") [] [addrPrimTy, intPrimTy] (doublePrimTy)+primOpInfo IndexOffAddrOp_StablePtr = mkGenPrimOp (fsLit "indexStablePtrOffAddr#") [alphaTyVar] [addrPrimTy, intPrimTy] (mkStablePtrPrimTy alphaTy)+primOpInfo IndexOffAddrOp_Int8 = mkGenPrimOp (fsLit "indexInt8OffAddr#") [] [addrPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexOffAddrOp_Int16 = mkGenPrimOp (fsLit "indexInt16OffAddr#") [] [addrPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexOffAddrOp_Int32 = mkGenPrimOp (fsLit "indexInt32OffAddr#") [] [addrPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexOffAddrOp_Int64 = mkGenPrimOp (fsLit "indexInt64OffAddr#") [] [addrPrimTy, intPrimTy] (intPrimTy)+primOpInfo IndexOffAddrOp_Word8 = mkGenPrimOp (fsLit "indexWord8OffAddr#") [] [addrPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexOffAddrOp_Word16 = mkGenPrimOp (fsLit "indexWord16OffAddr#") [] [addrPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexOffAddrOp_Word32 = mkGenPrimOp (fsLit "indexWord32OffAddr#") [] [addrPrimTy, intPrimTy] (wordPrimTy)+primOpInfo IndexOffAddrOp_Word64 = mkGenPrimOp (fsLit "indexWord64OffAddr#") [] [addrPrimTy, intPrimTy] (wordPrimTy)+primOpInfo ReadOffAddrOp_Char = mkGenPrimOp (fsLit "readCharOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, charPrimTy]))+primOpInfo ReadOffAddrOp_WideChar = mkGenPrimOp (fsLit "readWideCharOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, charPrimTy]))+primOpInfo ReadOffAddrOp_Int = mkGenPrimOp (fsLit "readIntOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadOffAddrOp_Word = mkGenPrimOp (fsLit "readWordOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadOffAddrOp_Addr = mkGenPrimOp (fsLit "readAddrOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, addrPrimTy]))+primOpInfo ReadOffAddrOp_Float = mkGenPrimOp (fsLit "readFloatOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatPrimTy]))+primOpInfo ReadOffAddrOp_Double = mkGenPrimOp (fsLit "readDoubleOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doublePrimTy]))+primOpInfo ReadOffAddrOp_StablePtr = mkGenPrimOp (fsLit "readStablePtrOffAddr#") [deltaTyVar, alphaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkStablePtrPrimTy alphaTy]))+primOpInfo ReadOffAddrOp_Int8 = mkGenPrimOp (fsLit "readInt8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadOffAddrOp_Int16 = mkGenPrimOp (fsLit "readInt16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadOffAddrOp_Int32 = mkGenPrimOp (fsLit "readInt32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadOffAddrOp_Int64 = mkGenPrimOp (fsLit "readInt64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadOffAddrOp_Word8 = mkGenPrimOp (fsLit "readWord8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadOffAddrOp_Word16 = mkGenPrimOp (fsLit "readWord16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadOffAddrOp_Word32 = mkGenPrimOp (fsLit "readWord32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo ReadOffAddrOp_Word64 = mkGenPrimOp (fsLit "readWord64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, wordPrimTy]))+primOpInfo WriteOffAddrOp_Char = mkGenPrimOp (fsLit "writeCharOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, charPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_WideChar = mkGenPrimOp (fsLit "writeWideCharOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, charPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Int = mkGenPrimOp (fsLit "writeIntOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Word = mkGenPrimOp (fsLit "writeWordOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Addr = mkGenPrimOp (fsLit "writeAddrOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, addrPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Float = mkGenPrimOp (fsLit "writeFloatOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, floatPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Double = mkGenPrimOp (fsLit "writeDoubleOffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, doublePrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_StablePtr = mkGenPrimOp (fsLit "writeStablePtrOffAddr#") [alphaTyVar, deltaTyVar] [addrPrimTy, intPrimTy, mkStablePtrPrimTy alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Int8 = mkGenPrimOp (fsLit "writeInt8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Int16 = mkGenPrimOp (fsLit "writeInt16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Int32 = mkGenPrimOp (fsLit "writeInt32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Int64 = mkGenPrimOp (fsLit "writeInt64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Word8 = mkGenPrimOp (fsLit "writeWord8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Word16 = mkGenPrimOp (fsLit "writeWord16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Word32 = mkGenPrimOp (fsLit "writeWord32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WriteOffAddrOp_Word64 = mkGenPrimOp (fsLit "writeWord64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, wordPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo NewMutVarOp = mkGenPrimOp (fsLit "newMutVar#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMutVarPrimTy deltaTy alphaTy]))+primOpInfo ReadMutVarOp = mkGenPrimOp (fsLit "readMutVar#") [deltaTyVar, alphaTyVar] [mkMutVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo WriteMutVarOp = mkGenPrimOp (fsLit "writeMutVar#") [deltaTyVar, alphaTyVar] [mkMutVarPrimTy deltaTy alphaTy, alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo SameMutVarOp = mkGenPrimOp (fsLit "sameMutVar#") [deltaTyVar, alphaTyVar] [mkMutVarPrimTy deltaTy alphaTy, mkMutVarPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo AtomicModifyMutVarOp = mkGenPrimOp (fsLit "atomicModifyMutVar#") [deltaTyVar, alphaTyVar, betaTyVar, gammaTyVar] [mkMutVarPrimTy deltaTy alphaTy, (mkFunTy (alphaTy) (betaTy)), mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, gammaTy]))+primOpInfo CasMutVarOp = mkGenPrimOp (fsLit "casMutVar#") [deltaTyVar, alphaTyVar] [mkMutVarPrimTy deltaTy alphaTy, alphaTy, alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy, alphaTy]))+primOpInfo CatchOp = mkGenPrimOp (fsLit "catch#") [alphaTyVar, betaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), (mkFunTy (betaTy) ((mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo RaiseOp = mkGenPrimOp (fsLit "raise#") [betaTyVar, runtimeRep1TyVar, openAlphaTyVar] [betaTy] (openAlphaTy)+primOpInfo RaiseIOOp = mkGenPrimOp (fsLit "raiseIO#") [alphaTyVar, betaTyVar] [alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, betaTy]))+primOpInfo MaskAsyncExceptionsOp = mkGenPrimOp (fsLit "maskAsyncExceptions#") [alphaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo MaskUninterruptibleOp = mkGenPrimOp (fsLit "maskUninterruptible#") [alphaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo UnmaskAsyncExceptionsOp = mkGenPrimOp (fsLit "unmaskAsyncExceptions#") [alphaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo MaskStatus = mkGenPrimOp (fsLit "getMaskingState#") [] [mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy]))+primOpInfo AtomicallyOp = mkGenPrimOp (fsLit "atomically#") [alphaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo RetryOp = mkGenPrimOp (fsLit "retry#") [alphaTyVar] [mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo CatchRetryOp = mkGenPrimOp (fsLit "catchRetry#") [alphaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), (mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo CatchSTMOp = mkGenPrimOp (fsLit "catchSTM#") [alphaTyVar, betaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), (mkFunTy (betaTy) ((mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo Check = mkGenPrimOp (fsLit "check#") [alphaTyVar] [(mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))), mkStatePrimTy realWorldTy] (mkStatePrimTy realWorldTy)+primOpInfo NewTVarOp = mkGenPrimOp (fsLit "newTVar#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkTVarPrimTy deltaTy alphaTy]))+primOpInfo ReadTVarOp = mkGenPrimOp (fsLit "readTVar#") [deltaTyVar, alphaTyVar] [mkTVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo ReadTVarIOOp = mkGenPrimOp (fsLit "readTVarIO#") [deltaTyVar, alphaTyVar] [mkTVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo WriteTVarOp = mkGenPrimOp (fsLit "writeTVar#") [deltaTyVar, alphaTyVar] [mkTVarPrimTy deltaTy alphaTy, alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo SameTVarOp = mkGenPrimOp (fsLit "sameTVar#") [deltaTyVar, alphaTyVar] [mkTVarPrimTy deltaTy alphaTy, mkTVarPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo NewMVarOp = mkGenPrimOp (fsLit "newMVar#") [deltaTyVar, alphaTyVar] [mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, mkMVarPrimTy deltaTy alphaTy]))+primOpInfo TakeMVarOp = mkGenPrimOp (fsLit "takeMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo TryTakeMVarOp = mkGenPrimOp (fsLit "tryTakeMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy, alphaTy]))+primOpInfo PutMVarOp = mkGenPrimOp (fsLit "putMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo TryPutMVarOp = mkGenPrimOp (fsLit "tryPutMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo ReadMVarOp = mkGenPrimOp (fsLit "readMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo TryReadMVarOp = mkGenPrimOp (fsLit "tryReadMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy, alphaTy]))+primOpInfo SameMVarOp = mkGenPrimOp (fsLit "sameMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, mkMVarPrimTy deltaTy alphaTy] (intPrimTy)+primOpInfo IsEmptyMVarOp = mkGenPrimOp (fsLit "isEmptyMVar#") [deltaTyVar, alphaTyVar] [mkMVarPrimTy deltaTy alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo DelayOp = mkGenPrimOp (fsLit "delay#") [deltaTyVar] [intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WaitReadOp = mkGenPrimOp (fsLit "waitRead#") [deltaTyVar] [intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo WaitWriteOp = mkGenPrimOp (fsLit "waitWrite#") [deltaTyVar] [intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo ForkOp = mkGenPrimOp (fsLit "fork#") [alphaTyVar] [alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, threadIdPrimTy]))+primOpInfo ForkOnOp = mkGenPrimOp (fsLit "forkOn#") [alphaTyVar] [intPrimTy, alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, threadIdPrimTy]))+primOpInfo KillThreadOp = mkGenPrimOp (fsLit "killThread#") [alphaTyVar] [threadIdPrimTy, alphaTy, mkStatePrimTy realWorldTy] (mkStatePrimTy realWorldTy)+primOpInfo YieldOp = mkGenPrimOp (fsLit "yield#") [] [mkStatePrimTy realWorldTy] (mkStatePrimTy realWorldTy)+primOpInfo MyThreadIdOp = mkGenPrimOp (fsLit "myThreadId#") [] [mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, threadIdPrimTy]))+primOpInfo LabelThreadOp = mkGenPrimOp (fsLit "labelThread#") [] [threadIdPrimTy, addrPrimTy, mkStatePrimTy realWorldTy] (mkStatePrimTy realWorldTy)+primOpInfo IsCurrentThreadBoundOp = mkGenPrimOp (fsLit "isCurrentThreadBound#") [] [mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy]))+primOpInfo NoDuplicateOp = mkGenPrimOp (fsLit "noDuplicate#") [deltaTyVar] [mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo ThreadStatusOp = mkGenPrimOp (fsLit "threadStatus#") [] [threadIdPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo MkWeakOp = mkGenPrimOp (fsLit "mkWeak#") [runtimeRep1TyVar, openAlphaTyVar, betaTyVar, gammaTyVar] [openAlphaTy, betaTy, (mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, gammaTy]))), mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, mkWeakPrimTy betaTy]))+primOpInfo MkWeakNoFinalizerOp = mkGenPrimOp (fsLit "mkWeakNoFinalizer#") [runtimeRep1TyVar, openAlphaTyVar, betaTyVar] [openAlphaTy, betaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, mkWeakPrimTy betaTy]))+primOpInfo AddCFinalizerToWeakOp = mkGenPrimOp (fsLit "addCFinalizerToWeak#") [betaTyVar] [addrPrimTy, addrPrimTy, intPrimTy, addrPrimTy, mkWeakPrimTy betaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy]))+primOpInfo DeRefWeakOp = mkGenPrimOp (fsLit "deRefWeak#") [alphaTyVar] [mkWeakPrimTy alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy, alphaTy]))+primOpInfo FinalizeWeakOp = mkGenPrimOp (fsLit "finalizeWeak#") [alphaTyVar, betaTyVar] [mkWeakPrimTy alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy, (mkFunTy (mkStatePrimTy realWorldTy) ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, betaTy])))]))+primOpInfo TouchOp = mkGenPrimOp (fsLit "touch#") [runtimeRep1TyVar, openAlphaTyVar] [openAlphaTy, mkStatePrimTy realWorldTy] (mkStatePrimTy realWorldTy)+primOpInfo MakeStablePtrOp = mkGenPrimOp (fsLit "makeStablePtr#") [alphaTyVar] [alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, mkStablePtrPrimTy alphaTy]))+primOpInfo DeRefStablePtrOp = mkGenPrimOp (fsLit "deRefStablePtr#") [alphaTyVar] [mkStablePtrPrimTy alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo EqStablePtrOp = mkGenPrimOp (fsLit "eqStablePtr#") [alphaTyVar] [mkStablePtrPrimTy alphaTy, mkStablePtrPrimTy alphaTy] (intPrimTy)+primOpInfo MakeStableNameOp = mkGenPrimOp (fsLit "makeStableName#") [alphaTyVar] [alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, mkStableNamePrimTy alphaTy]))+primOpInfo EqStableNameOp = mkGenPrimOp (fsLit "eqStableName#") [alphaTyVar, betaTyVar] [mkStableNamePrimTy alphaTy, mkStableNamePrimTy betaTy] (intPrimTy)+primOpInfo StableNameToIntOp = mkGenPrimOp (fsLit "stableNameToInt#") [alphaTyVar] [mkStableNamePrimTy alphaTy] (intPrimTy)+primOpInfo CompactNewOp = mkGenPrimOp (fsLit "compactNew#") [] [wordPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, compactPrimTy]))+primOpInfo CompactResizeOp = mkGenPrimOp (fsLit "compactResize#") [] [compactPrimTy, wordPrimTy, mkStatePrimTy realWorldTy] (mkStatePrimTy realWorldTy)+primOpInfo CompactContainsOp = mkGenPrimOp (fsLit "compactContains#") [alphaTyVar] [compactPrimTy, alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy]))+primOpInfo CompactContainsAnyOp = mkGenPrimOp (fsLit "compactContainsAny#") [alphaTyVar] [alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, intPrimTy]))+primOpInfo CompactGetFirstBlockOp = mkGenPrimOp (fsLit "compactGetFirstBlock#") [] [compactPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, addrPrimTy, wordPrimTy]))+primOpInfo CompactGetNextBlockOp = mkGenPrimOp (fsLit "compactGetNextBlock#") [] [compactPrimTy, addrPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, addrPrimTy, wordPrimTy]))+primOpInfo CompactAllocateBlockOp = mkGenPrimOp (fsLit "compactAllocateBlock#") [] [wordPrimTy, addrPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, addrPrimTy]))+primOpInfo CompactFixupPointersOp = mkGenPrimOp (fsLit "compactFixupPointers#") [] [addrPrimTy, addrPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, compactPrimTy, addrPrimTy]))+primOpInfo CompactAdd = mkGenPrimOp (fsLit "compactAdd#") [alphaTyVar] [compactPrimTy, alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo CompactAddWithSharing = mkGenPrimOp (fsLit "compactAddWithSharing#") [alphaTyVar] [compactPrimTy, alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, alphaTy]))+primOpInfo CompactSize = mkGenPrimOp (fsLit "compactSize#") [] [compactPrimTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, wordPrimTy]))+primOpInfo ReallyUnsafePtrEqualityOp = mkGenPrimOp (fsLit "reallyUnsafePtrEquality#") [alphaTyVar] [alphaTy, alphaTy] (intPrimTy)+primOpInfo ParOp = mkGenPrimOp (fsLit "par#") [alphaTyVar] [alphaTy] (intPrimTy)+primOpInfo SparkOp = mkGenPrimOp (fsLit "spark#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo SeqOp = mkGenPrimOp (fsLit "seq#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo GetSparkOp = mkGenPrimOp (fsLit "getSpark#") [deltaTyVar, alphaTyVar] [mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy, alphaTy]))+primOpInfo NumSparks = mkGenPrimOp (fsLit "numSparks#") [deltaTyVar] [mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, intPrimTy]))+primOpInfo DataToTagOp = mkGenPrimOp (fsLit "dataToTag#") [alphaTyVar] [alphaTy] (intPrimTy)+primOpInfo TagToEnumOp = mkGenPrimOp (fsLit "tagToEnum#") [alphaTyVar] [intPrimTy] (alphaTy)+primOpInfo AddrToAnyOp = mkGenPrimOp (fsLit "addrToAny#") [alphaTyVar] [addrPrimTy] ((mkTupleTy Unboxed [alphaTy]))+primOpInfo AnyToAddrOp = mkGenPrimOp (fsLit "anyToAddr#") [alphaTyVar] [alphaTy, mkStatePrimTy realWorldTy] ((mkTupleTy Unboxed [mkStatePrimTy realWorldTy, addrPrimTy]))+primOpInfo MkApUpd0_Op = mkGenPrimOp (fsLit "mkApUpd0#") [alphaTyVar] [bcoPrimTy] ((mkTupleTy Unboxed [alphaTy]))+primOpInfo NewBCOOp = mkGenPrimOp (fsLit "newBCO#") [alphaTyVar, deltaTyVar] [byteArrayPrimTy, byteArrayPrimTy, mkArrayPrimTy alphaTy, intPrimTy, byteArrayPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, bcoPrimTy]))+primOpInfo UnpackClosureOp = mkGenPrimOp (fsLit "unpackClosure#") [alphaTyVar, betaTyVar] [alphaTy] ((mkTupleTy Unboxed [addrPrimTy, mkArrayPrimTy betaTy, byteArrayPrimTy]))+primOpInfo GetApStackValOp = mkGenPrimOp (fsLit "getApStackVal#") [alphaTyVar, betaTyVar] [alphaTy, intPrimTy] ((mkTupleTy Unboxed [intPrimTy, betaTy]))+primOpInfo GetCCSOfOp = mkGenPrimOp (fsLit "getCCSOf#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, addrPrimTy]))+primOpInfo GetCurrentCCSOp = mkGenPrimOp (fsLit "getCurrentCCS#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, addrPrimTy]))+primOpInfo ClearCCSOp = mkGenPrimOp (fsLit "clearCCS#") [deltaTyVar, alphaTyVar] [(mkFunTy (mkStatePrimTy deltaTy) ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))), mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, alphaTy]))+primOpInfo TraceEventOp = mkGenPrimOp (fsLit "traceEvent#") [deltaTyVar] [addrPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo TraceMarkerOp = mkGenPrimOp (fsLit "traceMarker#") [deltaTyVar] [addrPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecBroadcastOp IntVec 16 W8) = mkGenPrimOp (fsLit "broadcastInt8X16#") [] [intPrimTy] (int8X16PrimTy)+primOpInfo (VecBroadcastOp IntVec 8 W16) = mkGenPrimOp (fsLit "broadcastInt16X8#") [] [intPrimTy] (int16X8PrimTy)+primOpInfo (VecBroadcastOp IntVec 4 W32) = mkGenPrimOp (fsLit "broadcastInt32X4#") [] [intPrimTy] (int32X4PrimTy)+primOpInfo (VecBroadcastOp IntVec 2 W64) = mkGenPrimOp (fsLit "broadcastInt64X2#") [] [intPrimTy] (int64X2PrimTy)+primOpInfo (VecBroadcastOp IntVec 32 W8) = mkGenPrimOp (fsLit "broadcastInt8X32#") [] [intPrimTy] (int8X32PrimTy)+primOpInfo (VecBroadcastOp IntVec 16 W16) = mkGenPrimOp (fsLit "broadcastInt16X16#") [] [intPrimTy] (int16X16PrimTy)+primOpInfo (VecBroadcastOp IntVec 8 W32) = mkGenPrimOp (fsLit "broadcastInt32X8#") [] [intPrimTy] (int32X8PrimTy)+primOpInfo (VecBroadcastOp IntVec 4 W64) = mkGenPrimOp (fsLit "broadcastInt64X4#") [] [intPrimTy] (int64X4PrimTy)+primOpInfo (VecBroadcastOp IntVec 64 W8) = mkGenPrimOp (fsLit "broadcastInt8X64#") [] [intPrimTy] (int8X64PrimTy)+primOpInfo (VecBroadcastOp IntVec 32 W16) = mkGenPrimOp (fsLit "broadcastInt16X32#") [] [intPrimTy] (int16X32PrimTy)+primOpInfo (VecBroadcastOp IntVec 16 W32) = mkGenPrimOp (fsLit "broadcastInt32X16#") [] [intPrimTy] (int32X16PrimTy)+primOpInfo (VecBroadcastOp IntVec 8 W64) = mkGenPrimOp (fsLit "broadcastInt64X8#") [] [intPrimTy] (int64X8PrimTy)+primOpInfo (VecBroadcastOp WordVec 16 W8) = mkGenPrimOp (fsLit "broadcastWord8X16#") [] [wordPrimTy] (word8X16PrimTy)+primOpInfo (VecBroadcastOp WordVec 8 W16) = mkGenPrimOp (fsLit "broadcastWord16X8#") [] [wordPrimTy] (word16X8PrimTy)+primOpInfo (VecBroadcastOp WordVec 4 W32) = mkGenPrimOp (fsLit "broadcastWord32X4#") [] [wordPrimTy] (word32X4PrimTy)+primOpInfo (VecBroadcastOp WordVec 2 W64) = mkGenPrimOp (fsLit "broadcastWord64X2#") [] [wordPrimTy] (word64X2PrimTy)+primOpInfo (VecBroadcastOp WordVec 32 W8) = mkGenPrimOp (fsLit "broadcastWord8X32#") [] [wordPrimTy] (word8X32PrimTy)+primOpInfo (VecBroadcastOp WordVec 16 W16) = mkGenPrimOp (fsLit "broadcastWord16X16#") [] [wordPrimTy] (word16X16PrimTy)+primOpInfo (VecBroadcastOp WordVec 8 W32) = mkGenPrimOp (fsLit "broadcastWord32X8#") [] [wordPrimTy] (word32X8PrimTy)+primOpInfo (VecBroadcastOp WordVec 4 W64) = mkGenPrimOp (fsLit "broadcastWord64X4#") [] [wordPrimTy] (word64X4PrimTy)+primOpInfo (VecBroadcastOp WordVec 64 W8) = mkGenPrimOp (fsLit "broadcastWord8X64#") [] [wordPrimTy] (word8X64PrimTy)+primOpInfo (VecBroadcastOp WordVec 32 W16) = mkGenPrimOp (fsLit "broadcastWord16X32#") [] [wordPrimTy] (word16X32PrimTy)+primOpInfo (VecBroadcastOp WordVec 16 W32) = mkGenPrimOp (fsLit "broadcastWord32X16#") [] [wordPrimTy] (word32X16PrimTy)+primOpInfo (VecBroadcastOp WordVec 8 W64) = mkGenPrimOp (fsLit "broadcastWord64X8#") [] [wordPrimTy] (word64X8PrimTy)+primOpInfo (VecBroadcastOp FloatVec 4 W32) = mkGenPrimOp (fsLit "broadcastFloatX4#") [] [floatPrimTy] (floatX4PrimTy)+primOpInfo (VecBroadcastOp FloatVec 2 W64) = mkGenPrimOp (fsLit "broadcastDoubleX2#") [] [doublePrimTy] (doubleX2PrimTy)+primOpInfo (VecBroadcastOp FloatVec 8 W32) = mkGenPrimOp (fsLit "broadcastFloatX8#") [] [floatPrimTy] (floatX8PrimTy)+primOpInfo (VecBroadcastOp FloatVec 4 W64) = mkGenPrimOp (fsLit "broadcastDoubleX4#") [] [doublePrimTy] (doubleX4PrimTy)+primOpInfo (VecBroadcastOp FloatVec 16 W32) = mkGenPrimOp (fsLit "broadcastFloatX16#") [] [floatPrimTy] (floatX16PrimTy)+primOpInfo (VecBroadcastOp FloatVec 8 W64) = mkGenPrimOp (fsLit "broadcastDoubleX8#") [] [doublePrimTy] (doubleX8PrimTy)+primOpInfo (VecPackOp IntVec 16 W8) = mkGenPrimOp (fsLit "packInt8X16#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int8X16PrimTy)+primOpInfo (VecPackOp IntVec 8 W16) = mkGenPrimOp (fsLit "packInt16X8#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int16X8PrimTy)+primOpInfo (VecPackOp IntVec 4 W32) = mkGenPrimOp (fsLit "packInt32X4#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int32X4PrimTy)+primOpInfo (VecPackOp IntVec 2 W64) = mkGenPrimOp (fsLit "packInt64X2#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy])] (int64X2PrimTy)+primOpInfo (VecPackOp IntVec 32 W8) = mkGenPrimOp (fsLit "packInt8X32#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int8X32PrimTy)+primOpInfo (VecPackOp IntVec 16 W16) = mkGenPrimOp (fsLit "packInt16X16#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int16X16PrimTy)+primOpInfo (VecPackOp IntVec 8 W32) = mkGenPrimOp (fsLit "packInt32X8#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int32X8PrimTy)+primOpInfo (VecPackOp IntVec 4 W64) = mkGenPrimOp (fsLit "packInt64X4#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int64X4PrimTy)+primOpInfo (VecPackOp IntVec 64 W8) = mkGenPrimOp (fsLit "packInt8X64#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int8X64PrimTy)+primOpInfo (VecPackOp IntVec 32 W16) = mkGenPrimOp (fsLit "packInt16X32#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int16X32PrimTy)+primOpInfo (VecPackOp IntVec 16 W32) = mkGenPrimOp (fsLit "packInt32X16#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int32X16PrimTy)+primOpInfo (VecPackOp IntVec 8 W64) = mkGenPrimOp (fsLit "packInt64X8#") [] [(mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy])] (int64X8PrimTy)+primOpInfo (VecPackOp WordVec 16 W8) = mkGenPrimOp (fsLit "packWord8X16#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word8X16PrimTy)+primOpInfo (VecPackOp WordVec 8 W16) = mkGenPrimOp (fsLit "packWord16X8#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word16X8PrimTy)+primOpInfo (VecPackOp WordVec 4 W32) = mkGenPrimOp (fsLit "packWord32X4#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word32X4PrimTy)+primOpInfo (VecPackOp WordVec 2 W64) = mkGenPrimOp (fsLit "packWord64X2#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy])] (word64X2PrimTy)+primOpInfo (VecPackOp WordVec 32 W8) = mkGenPrimOp (fsLit "packWord8X32#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word8X32PrimTy)+primOpInfo (VecPackOp WordVec 16 W16) = mkGenPrimOp (fsLit "packWord16X16#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word16X16PrimTy)+primOpInfo (VecPackOp WordVec 8 W32) = mkGenPrimOp (fsLit "packWord32X8#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word32X8PrimTy)+primOpInfo (VecPackOp WordVec 4 W64) = mkGenPrimOp (fsLit "packWord64X4#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word64X4PrimTy)+primOpInfo (VecPackOp WordVec 64 W8) = mkGenPrimOp (fsLit "packWord8X64#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word8X64PrimTy)+primOpInfo (VecPackOp WordVec 32 W16) = mkGenPrimOp (fsLit "packWord16X32#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word16X32PrimTy)+primOpInfo (VecPackOp WordVec 16 W32) = mkGenPrimOp (fsLit "packWord32X16#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word32X16PrimTy)+primOpInfo (VecPackOp WordVec 8 W64) = mkGenPrimOp (fsLit "packWord64X8#") [] [(mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy])] (word64X8PrimTy)+primOpInfo (VecPackOp FloatVec 4 W32) = mkGenPrimOp (fsLit "packFloatX4#") [] [(mkTupleTy Unboxed [floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy])] (floatX4PrimTy)+primOpInfo (VecPackOp FloatVec 2 W64) = mkGenPrimOp (fsLit "packDoubleX2#") [] [(mkTupleTy Unboxed [doublePrimTy, doublePrimTy])] (doubleX2PrimTy)+primOpInfo (VecPackOp FloatVec 8 W32) = mkGenPrimOp (fsLit "packFloatX8#") [] [(mkTupleTy Unboxed [floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy])] (floatX8PrimTy)+primOpInfo (VecPackOp FloatVec 4 W64) = mkGenPrimOp (fsLit "packDoubleX4#") [] [(mkTupleTy Unboxed [doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy])] (doubleX4PrimTy)+primOpInfo (VecPackOp FloatVec 16 W32) = mkGenPrimOp (fsLit "packFloatX16#") [] [(mkTupleTy Unboxed [floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy])] (floatX16PrimTy)+primOpInfo (VecPackOp FloatVec 8 W64) = mkGenPrimOp (fsLit "packDoubleX8#") [] [(mkTupleTy Unboxed [doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy])] (doubleX8PrimTy)+primOpInfo (VecUnpackOp IntVec 16 W8) = mkGenPrimOp (fsLit "unpackInt8X16#") [] [int8X16PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 8 W16) = mkGenPrimOp (fsLit "unpackInt16X8#") [] [int16X8PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 4 W32) = mkGenPrimOp (fsLit "unpackInt32X4#") [] [int32X4PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 2 W64) = mkGenPrimOp (fsLit "unpackInt64X2#") [] [int64X2PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 32 W8) = mkGenPrimOp (fsLit "unpackInt8X32#") [] [int8X32PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 16 W16) = mkGenPrimOp (fsLit "unpackInt16X16#") [] [int16X16PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 8 W32) = mkGenPrimOp (fsLit "unpackInt32X8#") [] [int32X8PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 4 W64) = mkGenPrimOp (fsLit "unpackInt64X4#") [] [int64X4PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 64 W8) = mkGenPrimOp (fsLit "unpackInt8X64#") [] [int8X64PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 32 W16) = mkGenPrimOp (fsLit "unpackInt16X32#") [] [int16X32PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 16 W32) = mkGenPrimOp (fsLit "unpackInt32X16#") [] [int32X16PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp IntVec 8 W64) = mkGenPrimOp (fsLit "unpackInt64X8#") [] [int64X8PrimTy] ((mkTupleTy Unboxed [intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy, intPrimTy]))+primOpInfo (VecUnpackOp WordVec 16 W8) = mkGenPrimOp (fsLit "unpackWord8X16#") [] [word8X16PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 8 W16) = mkGenPrimOp (fsLit "unpackWord16X8#") [] [word16X8PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 4 W32) = mkGenPrimOp (fsLit "unpackWord32X4#") [] [word32X4PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 2 W64) = mkGenPrimOp (fsLit "unpackWord64X2#") [] [word64X2PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 32 W8) = mkGenPrimOp (fsLit "unpackWord8X32#") [] [word8X32PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 16 W16) = mkGenPrimOp (fsLit "unpackWord16X16#") [] [word16X16PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 8 W32) = mkGenPrimOp (fsLit "unpackWord32X8#") [] [word32X8PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 4 W64) = mkGenPrimOp (fsLit "unpackWord64X4#") [] [word64X4PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 64 W8) = mkGenPrimOp (fsLit "unpackWord8X64#") [] [word8X64PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 32 W16) = mkGenPrimOp (fsLit "unpackWord16X32#") [] [word16X32PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 16 W32) = mkGenPrimOp (fsLit "unpackWord32X16#") [] [word32X16PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp WordVec 8 W64) = mkGenPrimOp (fsLit "unpackWord64X8#") [] [word64X8PrimTy] ((mkTupleTy Unboxed [wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy, wordPrimTy]))+primOpInfo (VecUnpackOp FloatVec 4 W32) = mkGenPrimOp (fsLit "unpackFloatX4#") [] [floatX4PrimTy] ((mkTupleTy Unboxed [floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy]))+primOpInfo (VecUnpackOp FloatVec 2 W64) = mkGenPrimOp (fsLit "unpackDoubleX2#") [] [doubleX2PrimTy] ((mkTupleTy Unboxed [doublePrimTy, doublePrimTy]))+primOpInfo (VecUnpackOp FloatVec 8 W32) = mkGenPrimOp (fsLit "unpackFloatX8#") [] [floatX8PrimTy] ((mkTupleTy Unboxed [floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy]))+primOpInfo (VecUnpackOp FloatVec 4 W64) = mkGenPrimOp (fsLit "unpackDoubleX4#") [] [doubleX4PrimTy] ((mkTupleTy Unboxed [doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy]))+primOpInfo (VecUnpackOp FloatVec 16 W32) = mkGenPrimOp (fsLit "unpackFloatX16#") [] [floatX16PrimTy] ((mkTupleTy Unboxed [floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy, floatPrimTy]))+primOpInfo (VecUnpackOp FloatVec 8 W64) = mkGenPrimOp (fsLit "unpackDoubleX8#") [] [doubleX8PrimTy] ((mkTupleTy Unboxed [doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy, doublePrimTy]))+primOpInfo (VecInsertOp IntVec 16 W8) = mkGenPrimOp (fsLit "insertInt8X16#") [] [int8X16PrimTy, intPrimTy, intPrimTy] (int8X16PrimTy)+primOpInfo (VecInsertOp IntVec 8 W16) = mkGenPrimOp (fsLit "insertInt16X8#") [] [int16X8PrimTy, intPrimTy, intPrimTy] (int16X8PrimTy)+primOpInfo (VecInsertOp IntVec 4 W32) = mkGenPrimOp (fsLit "insertInt32X4#") [] [int32X4PrimTy, intPrimTy, intPrimTy] (int32X4PrimTy)+primOpInfo (VecInsertOp IntVec 2 W64) = mkGenPrimOp (fsLit "insertInt64X2#") [] [int64X2PrimTy, intPrimTy, intPrimTy] (int64X2PrimTy)+primOpInfo (VecInsertOp IntVec 32 W8) = mkGenPrimOp (fsLit "insertInt8X32#") [] [int8X32PrimTy, intPrimTy, intPrimTy] (int8X32PrimTy)+primOpInfo (VecInsertOp IntVec 16 W16) = mkGenPrimOp (fsLit "insertInt16X16#") [] [int16X16PrimTy, intPrimTy, intPrimTy] (int16X16PrimTy)+primOpInfo (VecInsertOp IntVec 8 W32) = mkGenPrimOp (fsLit "insertInt32X8#") [] [int32X8PrimTy, intPrimTy, intPrimTy] (int32X8PrimTy)+primOpInfo (VecInsertOp IntVec 4 W64) = mkGenPrimOp (fsLit "insertInt64X4#") [] [int64X4PrimTy, intPrimTy, intPrimTy] (int64X4PrimTy)+primOpInfo (VecInsertOp IntVec 64 W8) = mkGenPrimOp (fsLit "insertInt8X64#") [] [int8X64PrimTy, intPrimTy, intPrimTy] (int8X64PrimTy)+primOpInfo (VecInsertOp IntVec 32 W16) = mkGenPrimOp (fsLit "insertInt16X32#") [] [int16X32PrimTy, intPrimTy, intPrimTy] (int16X32PrimTy)+primOpInfo (VecInsertOp IntVec 16 W32) = mkGenPrimOp (fsLit "insertInt32X16#") [] [int32X16PrimTy, intPrimTy, intPrimTy] (int32X16PrimTy)+primOpInfo (VecInsertOp IntVec 8 W64) = mkGenPrimOp (fsLit "insertInt64X8#") [] [int64X8PrimTy, intPrimTy, intPrimTy] (int64X8PrimTy)+primOpInfo (VecInsertOp WordVec 16 W8) = mkGenPrimOp (fsLit "insertWord8X16#") [] [word8X16PrimTy, wordPrimTy, intPrimTy] (word8X16PrimTy)+primOpInfo (VecInsertOp WordVec 8 W16) = mkGenPrimOp (fsLit "insertWord16X8#") [] [word16X8PrimTy, wordPrimTy, intPrimTy] (word16X8PrimTy)+primOpInfo (VecInsertOp WordVec 4 W32) = mkGenPrimOp (fsLit "insertWord32X4#") [] [word32X4PrimTy, wordPrimTy, intPrimTy] (word32X4PrimTy)+primOpInfo (VecInsertOp WordVec 2 W64) = mkGenPrimOp (fsLit "insertWord64X2#") [] [word64X2PrimTy, wordPrimTy, intPrimTy] (word64X2PrimTy)+primOpInfo (VecInsertOp WordVec 32 W8) = mkGenPrimOp (fsLit "insertWord8X32#") [] [word8X32PrimTy, wordPrimTy, intPrimTy] (word8X32PrimTy)+primOpInfo (VecInsertOp WordVec 16 W16) = mkGenPrimOp (fsLit "insertWord16X16#") [] [word16X16PrimTy, wordPrimTy, intPrimTy] (word16X16PrimTy)+primOpInfo (VecInsertOp WordVec 8 W32) = mkGenPrimOp (fsLit "insertWord32X8#") [] [word32X8PrimTy, wordPrimTy, intPrimTy] (word32X8PrimTy)+primOpInfo (VecInsertOp WordVec 4 W64) = mkGenPrimOp (fsLit "insertWord64X4#") [] [word64X4PrimTy, wordPrimTy, intPrimTy] (word64X4PrimTy)+primOpInfo (VecInsertOp WordVec 64 W8) = mkGenPrimOp (fsLit "insertWord8X64#") [] [word8X64PrimTy, wordPrimTy, intPrimTy] (word8X64PrimTy)+primOpInfo (VecInsertOp WordVec 32 W16) = mkGenPrimOp (fsLit "insertWord16X32#") [] [word16X32PrimTy, wordPrimTy, intPrimTy] (word16X32PrimTy)+primOpInfo (VecInsertOp WordVec 16 W32) = mkGenPrimOp (fsLit "insertWord32X16#") [] [word32X16PrimTy, wordPrimTy, intPrimTy] (word32X16PrimTy)+primOpInfo (VecInsertOp WordVec 8 W64) = mkGenPrimOp (fsLit "insertWord64X8#") [] [word64X8PrimTy, wordPrimTy, intPrimTy] (word64X8PrimTy)+primOpInfo (VecInsertOp FloatVec 4 W32) = mkGenPrimOp (fsLit "insertFloatX4#") [] [floatX4PrimTy, floatPrimTy, intPrimTy] (floatX4PrimTy)+primOpInfo (VecInsertOp FloatVec 2 W64) = mkGenPrimOp (fsLit "insertDoubleX2#") [] [doubleX2PrimTy, doublePrimTy, intPrimTy] (doubleX2PrimTy)+primOpInfo (VecInsertOp FloatVec 8 W32) = mkGenPrimOp (fsLit "insertFloatX8#") [] [floatX8PrimTy, floatPrimTy, intPrimTy] (floatX8PrimTy)+primOpInfo (VecInsertOp FloatVec 4 W64) = mkGenPrimOp (fsLit "insertDoubleX4#") [] [doubleX4PrimTy, doublePrimTy, intPrimTy] (doubleX4PrimTy)+primOpInfo (VecInsertOp FloatVec 16 W32) = mkGenPrimOp (fsLit "insertFloatX16#") [] [floatX16PrimTy, floatPrimTy, intPrimTy] (floatX16PrimTy)+primOpInfo (VecInsertOp FloatVec 8 W64) = mkGenPrimOp (fsLit "insertDoubleX8#") [] [doubleX8PrimTy, doublePrimTy, intPrimTy] (doubleX8PrimTy)+primOpInfo (VecAddOp IntVec 16 W8) = mkDyadic (fsLit "plusInt8X16#") int8X16PrimTy+primOpInfo (VecAddOp IntVec 8 W16) = mkDyadic (fsLit "plusInt16X8#") int16X8PrimTy+primOpInfo (VecAddOp IntVec 4 W32) = mkDyadic (fsLit "plusInt32X4#") int32X4PrimTy+primOpInfo (VecAddOp IntVec 2 W64) = mkDyadic (fsLit "plusInt64X2#") int64X2PrimTy+primOpInfo (VecAddOp IntVec 32 W8) = mkDyadic (fsLit "plusInt8X32#") int8X32PrimTy+primOpInfo (VecAddOp IntVec 16 W16) = mkDyadic (fsLit "plusInt16X16#") int16X16PrimTy+primOpInfo (VecAddOp IntVec 8 W32) = mkDyadic (fsLit "plusInt32X8#") int32X8PrimTy+primOpInfo (VecAddOp IntVec 4 W64) = mkDyadic (fsLit "plusInt64X4#") int64X4PrimTy+primOpInfo (VecAddOp IntVec 64 W8) = mkDyadic (fsLit "plusInt8X64#") int8X64PrimTy+primOpInfo (VecAddOp IntVec 32 W16) = mkDyadic (fsLit "plusInt16X32#") int16X32PrimTy+primOpInfo (VecAddOp IntVec 16 W32) = mkDyadic (fsLit "plusInt32X16#") int32X16PrimTy+primOpInfo (VecAddOp IntVec 8 W64) = mkDyadic (fsLit "plusInt64X8#") int64X8PrimTy+primOpInfo (VecAddOp WordVec 16 W8) = mkDyadic (fsLit "plusWord8X16#") word8X16PrimTy+primOpInfo (VecAddOp WordVec 8 W16) = mkDyadic (fsLit "plusWord16X8#") word16X8PrimTy+primOpInfo (VecAddOp WordVec 4 W32) = mkDyadic (fsLit "plusWord32X4#") word32X4PrimTy+primOpInfo (VecAddOp WordVec 2 W64) = mkDyadic (fsLit "plusWord64X2#") word64X2PrimTy+primOpInfo (VecAddOp WordVec 32 W8) = mkDyadic (fsLit "plusWord8X32#") word8X32PrimTy+primOpInfo (VecAddOp WordVec 16 W16) = mkDyadic (fsLit "plusWord16X16#") word16X16PrimTy+primOpInfo (VecAddOp WordVec 8 W32) = mkDyadic (fsLit "plusWord32X8#") word32X8PrimTy+primOpInfo (VecAddOp WordVec 4 W64) = mkDyadic (fsLit "plusWord64X4#") word64X4PrimTy+primOpInfo (VecAddOp WordVec 64 W8) = mkDyadic (fsLit "plusWord8X64#") word8X64PrimTy+primOpInfo (VecAddOp WordVec 32 W16) = mkDyadic (fsLit "plusWord16X32#") word16X32PrimTy+primOpInfo (VecAddOp WordVec 16 W32) = mkDyadic (fsLit "plusWord32X16#") word32X16PrimTy+primOpInfo (VecAddOp WordVec 8 W64) = mkDyadic (fsLit "plusWord64X8#") word64X8PrimTy+primOpInfo (VecAddOp FloatVec 4 W32) = mkDyadic (fsLit "plusFloatX4#") floatX4PrimTy+primOpInfo (VecAddOp FloatVec 2 W64) = mkDyadic (fsLit "plusDoubleX2#") doubleX2PrimTy+primOpInfo (VecAddOp FloatVec 8 W32) = mkDyadic (fsLit "plusFloatX8#") floatX8PrimTy+primOpInfo (VecAddOp FloatVec 4 W64) = mkDyadic (fsLit "plusDoubleX4#") doubleX4PrimTy+primOpInfo (VecAddOp FloatVec 16 W32) = mkDyadic (fsLit "plusFloatX16#") floatX16PrimTy+primOpInfo (VecAddOp FloatVec 8 W64) = mkDyadic (fsLit "plusDoubleX8#") doubleX8PrimTy+primOpInfo (VecSubOp IntVec 16 W8) = mkDyadic (fsLit "minusInt8X16#") int8X16PrimTy+primOpInfo (VecSubOp IntVec 8 W16) = mkDyadic (fsLit "minusInt16X8#") int16X8PrimTy+primOpInfo (VecSubOp IntVec 4 W32) = mkDyadic (fsLit "minusInt32X4#") int32X4PrimTy+primOpInfo (VecSubOp IntVec 2 W64) = mkDyadic (fsLit "minusInt64X2#") int64X2PrimTy+primOpInfo (VecSubOp IntVec 32 W8) = mkDyadic (fsLit "minusInt8X32#") int8X32PrimTy+primOpInfo (VecSubOp IntVec 16 W16) = mkDyadic (fsLit "minusInt16X16#") int16X16PrimTy+primOpInfo (VecSubOp IntVec 8 W32) = mkDyadic (fsLit "minusInt32X8#") int32X8PrimTy+primOpInfo (VecSubOp IntVec 4 W64) = mkDyadic (fsLit "minusInt64X4#") int64X4PrimTy+primOpInfo (VecSubOp IntVec 64 W8) = mkDyadic (fsLit "minusInt8X64#") int8X64PrimTy+primOpInfo (VecSubOp IntVec 32 W16) = mkDyadic (fsLit "minusInt16X32#") int16X32PrimTy+primOpInfo (VecSubOp IntVec 16 W32) = mkDyadic (fsLit "minusInt32X16#") int32X16PrimTy+primOpInfo (VecSubOp IntVec 8 W64) = mkDyadic (fsLit "minusInt64X8#") int64X8PrimTy+primOpInfo (VecSubOp WordVec 16 W8) = mkDyadic (fsLit "minusWord8X16#") word8X16PrimTy+primOpInfo (VecSubOp WordVec 8 W16) = mkDyadic (fsLit "minusWord16X8#") word16X8PrimTy+primOpInfo (VecSubOp WordVec 4 W32) = mkDyadic (fsLit "minusWord32X4#") word32X4PrimTy+primOpInfo (VecSubOp WordVec 2 W64) = mkDyadic (fsLit "minusWord64X2#") word64X2PrimTy+primOpInfo (VecSubOp WordVec 32 W8) = mkDyadic (fsLit "minusWord8X32#") word8X32PrimTy+primOpInfo (VecSubOp WordVec 16 W16) = mkDyadic (fsLit "minusWord16X16#") word16X16PrimTy+primOpInfo (VecSubOp WordVec 8 W32) = mkDyadic (fsLit "minusWord32X8#") word32X8PrimTy+primOpInfo (VecSubOp WordVec 4 W64) = mkDyadic (fsLit "minusWord64X4#") word64X4PrimTy+primOpInfo (VecSubOp WordVec 64 W8) = mkDyadic (fsLit "minusWord8X64#") word8X64PrimTy+primOpInfo (VecSubOp WordVec 32 W16) = mkDyadic (fsLit "minusWord16X32#") word16X32PrimTy+primOpInfo (VecSubOp WordVec 16 W32) = mkDyadic (fsLit "minusWord32X16#") word32X16PrimTy+primOpInfo (VecSubOp WordVec 8 W64) = mkDyadic (fsLit "minusWord64X8#") word64X8PrimTy+primOpInfo (VecSubOp FloatVec 4 W32) = mkDyadic (fsLit "minusFloatX4#") floatX4PrimTy+primOpInfo (VecSubOp FloatVec 2 W64) = mkDyadic (fsLit "minusDoubleX2#") doubleX2PrimTy+primOpInfo (VecSubOp FloatVec 8 W32) = mkDyadic (fsLit "minusFloatX8#") floatX8PrimTy+primOpInfo (VecSubOp FloatVec 4 W64) = mkDyadic (fsLit "minusDoubleX4#") doubleX4PrimTy+primOpInfo (VecSubOp FloatVec 16 W32) = mkDyadic (fsLit "minusFloatX16#") floatX16PrimTy+primOpInfo (VecSubOp FloatVec 8 W64) = mkDyadic (fsLit "minusDoubleX8#") doubleX8PrimTy+primOpInfo (VecMulOp IntVec 16 W8) = mkDyadic (fsLit "timesInt8X16#") int8X16PrimTy+primOpInfo (VecMulOp IntVec 8 W16) = mkDyadic (fsLit "timesInt16X8#") int16X8PrimTy+primOpInfo (VecMulOp IntVec 4 W32) = mkDyadic (fsLit "timesInt32X4#") int32X4PrimTy+primOpInfo (VecMulOp IntVec 2 W64) = mkDyadic (fsLit "timesInt64X2#") int64X2PrimTy+primOpInfo (VecMulOp IntVec 32 W8) = mkDyadic (fsLit "timesInt8X32#") int8X32PrimTy+primOpInfo (VecMulOp IntVec 16 W16) = mkDyadic (fsLit "timesInt16X16#") int16X16PrimTy+primOpInfo (VecMulOp IntVec 8 W32) = mkDyadic (fsLit "timesInt32X8#") int32X8PrimTy+primOpInfo (VecMulOp IntVec 4 W64) = mkDyadic (fsLit "timesInt64X4#") int64X4PrimTy+primOpInfo (VecMulOp IntVec 64 W8) = mkDyadic (fsLit "timesInt8X64#") int8X64PrimTy+primOpInfo (VecMulOp IntVec 32 W16) = mkDyadic (fsLit "timesInt16X32#") int16X32PrimTy+primOpInfo (VecMulOp IntVec 16 W32) = mkDyadic (fsLit "timesInt32X16#") int32X16PrimTy+primOpInfo (VecMulOp IntVec 8 W64) = mkDyadic (fsLit "timesInt64X8#") int64X8PrimTy+primOpInfo (VecMulOp WordVec 16 W8) = mkDyadic (fsLit "timesWord8X16#") word8X16PrimTy+primOpInfo (VecMulOp WordVec 8 W16) = mkDyadic (fsLit "timesWord16X8#") word16X8PrimTy+primOpInfo (VecMulOp WordVec 4 W32) = mkDyadic (fsLit "timesWord32X4#") word32X4PrimTy+primOpInfo (VecMulOp WordVec 2 W64) = mkDyadic (fsLit "timesWord64X2#") word64X2PrimTy+primOpInfo (VecMulOp WordVec 32 W8) = mkDyadic (fsLit "timesWord8X32#") word8X32PrimTy+primOpInfo (VecMulOp WordVec 16 W16) = mkDyadic (fsLit "timesWord16X16#") word16X16PrimTy+primOpInfo (VecMulOp WordVec 8 W32) = mkDyadic (fsLit "timesWord32X8#") word32X8PrimTy+primOpInfo (VecMulOp WordVec 4 W64) = mkDyadic (fsLit "timesWord64X4#") word64X4PrimTy+primOpInfo (VecMulOp WordVec 64 W8) = mkDyadic (fsLit "timesWord8X64#") word8X64PrimTy+primOpInfo (VecMulOp WordVec 32 W16) = mkDyadic (fsLit "timesWord16X32#") word16X32PrimTy+primOpInfo (VecMulOp WordVec 16 W32) = mkDyadic (fsLit "timesWord32X16#") word32X16PrimTy+primOpInfo (VecMulOp WordVec 8 W64) = mkDyadic (fsLit "timesWord64X8#") word64X8PrimTy+primOpInfo (VecMulOp FloatVec 4 W32) = mkDyadic (fsLit "timesFloatX4#") floatX4PrimTy+primOpInfo (VecMulOp FloatVec 2 W64) = mkDyadic (fsLit "timesDoubleX2#") doubleX2PrimTy+primOpInfo (VecMulOp FloatVec 8 W32) = mkDyadic (fsLit "timesFloatX8#") floatX8PrimTy+primOpInfo (VecMulOp FloatVec 4 W64) = mkDyadic (fsLit "timesDoubleX4#") doubleX4PrimTy+primOpInfo (VecMulOp FloatVec 16 W32) = mkDyadic (fsLit "timesFloatX16#") floatX16PrimTy+primOpInfo (VecMulOp FloatVec 8 W64) = mkDyadic (fsLit "timesDoubleX8#") doubleX8PrimTy+primOpInfo (VecDivOp FloatVec 4 W32) = mkDyadic (fsLit "divideFloatX4#") floatX4PrimTy+primOpInfo (VecDivOp FloatVec 2 W64) = mkDyadic (fsLit "divideDoubleX2#") doubleX2PrimTy+primOpInfo (VecDivOp FloatVec 8 W32) = mkDyadic (fsLit "divideFloatX8#") floatX8PrimTy+primOpInfo (VecDivOp FloatVec 4 W64) = mkDyadic (fsLit "divideDoubleX4#") doubleX4PrimTy+primOpInfo (VecDivOp FloatVec 16 W32) = mkDyadic (fsLit "divideFloatX16#") floatX16PrimTy+primOpInfo (VecDivOp FloatVec 8 W64) = mkDyadic (fsLit "divideDoubleX8#") doubleX8PrimTy+primOpInfo (VecQuotOp IntVec 16 W8) = mkDyadic (fsLit "quotInt8X16#") int8X16PrimTy+primOpInfo (VecQuotOp IntVec 8 W16) = mkDyadic (fsLit "quotInt16X8#") int16X8PrimTy+primOpInfo (VecQuotOp IntVec 4 W32) = mkDyadic (fsLit "quotInt32X4#") int32X4PrimTy+primOpInfo (VecQuotOp IntVec 2 W64) = mkDyadic (fsLit "quotInt64X2#") int64X2PrimTy+primOpInfo (VecQuotOp IntVec 32 W8) = mkDyadic (fsLit "quotInt8X32#") int8X32PrimTy+primOpInfo (VecQuotOp IntVec 16 W16) = mkDyadic (fsLit "quotInt16X16#") int16X16PrimTy+primOpInfo (VecQuotOp IntVec 8 W32) = mkDyadic (fsLit "quotInt32X8#") int32X8PrimTy+primOpInfo (VecQuotOp IntVec 4 W64) = mkDyadic (fsLit "quotInt64X4#") int64X4PrimTy+primOpInfo (VecQuotOp IntVec 64 W8) = mkDyadic (fsLit "quotInt8X64#") int8X64PrimTy+primOpInfo (VecQuotOp IntVec 32 W16) = mkDyadic (fsLit "quotInt16X32#") int16X32PrimTy+primOpInfo (VecQuotOp IntVec 16 W32) = mkDyadic (fsLit "quotInt32X16#") int32X16PrimTy+primOpInfo (VecQuotOp IntVec 8 W64) = mkDyadic (fsLit "quotInt64X8#") int64X8PrimTy+primOpInfo (VecQuotOp WordVec 16 W8) = mkDyadic (fsLit "quotWord8X16#") word8X16PrimTy+primOpInfo (VecQuotOp WordVec 8 W16) = mkDyadic (fsLit "quotWord16X8#") word16X8PrimTy+primOpInfo (VecQuotOp WordVec 4 W32) = mkDyadic (fsLit "quotWord32X4#") word32X4PrimTy+primOpInfo (VecQuotOp WordVec 2 W64) = mkDyadic (fsLit "quotWord64X2#") word64X2PrimTy+primOpInfo (VecQuotOp WordVec 32 W8) = mkDyadic (fsLit "quotWord8X32#") word8X32PrimTy+primOpInfo (VecQuotOp WordVec 16 W16) = mkDyadic (fsLit "quotWord16X16#") word16X16PrimTy+primOpInfo (VecQuotOp WordVec 8 W32) = mkDyadic (fsLit "quotWord32X8#") word32X8PrimTy+primOpInfo (VecQuotOp WordVec 4 W64) = mkDyadic (fsLit "quotWord64X4#") word64X4PrimTy+primOpInfo (VecQuotOp WordVec 64 W8) = mkDyadic (fsLit "quotWord8X64#") word8X64PrimTy+primOpInfo (VecQuotOp WordVec 32 W16) = mkDyadic (fsLit "quotWord16X32#") word16X32PrimTy+primOpInfo (VecQuotOp WordVec 16 W32) = mkDyadic (fsLit "quotWord32X16#") word32X16PrimTy+primOpInfo (VecQuotOp WordVec 8 W64) = mkDyadic (fsLit "quotWord64X8#") word64X8PrimTy+primOpInfo (VecRemOp IntVec 16 W8) = mkDyadic (fsLit "remInt8X16#") int8X16PrimTy+primOpInfo (VecRemOp IntVec 8 W16) = mkDyadic (fsLit "remInt16X8#") int16X8PrimTy+primOpInfo (VecRemOp IntVec 4 W32) = mkDyadic (fsLit "remInt32X4#") int32X4PrimTy+primOpInfo (VecRemOp IntVec 2 W64) = mkDyadic (fsLit "remInt64X2#") int64X2PrimTy+primOpInfo (VecRemOp IntVec 32 W8) = mkDyadic (fsLit "remInt8X32#") int8X32PrimTy+primOpInfo (VecRemOp IntVec 16 W16) = mkDyadic (fsLit "remInt16X16#") int16X16PrimTy+primOpInfo (VecRemOp IntVec 8 W32) = mkDyadic (fsLit "remInt32X8#") int32X8PrimTy+primOpInfo (VecRemOp IntVec 4 W64) = mkDyadic (fsLit "remInt64X4#") int64X4PrimTy+primOpInfo (VecRemOp IntVec 64 W8) = mkDyadic (fsLit "remInt8X64#") int8X64PrimTy+primOpInfo (VecRemOp IntVec 32 W16) = mkDyadic (fsLit "remInt16X32#") int16X32PrimTy+primOpInfo (VecRemOp IntVec 16 W32) = mkDyadic (fsLit "remInt32X16#") int32X16PrimTy+primOpInfo (VecRemOp IntVec 8 W64) = mkDyadic (fsLit "remInt64X8#") int64X8PrimTy+primOpInfo (VecRemOp WordVec 16 W8) = mkDyadic (fsLit "remWord8X16#") word8X16PrimTy+primOpInfo (VecRemOp WordVec 8 W16) = mkDyadic (fsLit "remWord16X8#") word16X8PrimTy+primOpInfo (VecRemOp WordVec 4 W32) = mkDyadic (fsLit "remWord32X4#") word32X4PrimTy+primOpInfo (VecRemOp WordVec 2 W64) = mkDyadic (fsLit "remWord64X2#") word64X2PrimTy+primOpInfo (VecRemOp WordVec 32 W8) = mkDyadic (fsLit "remWord8X32#") word8X32PrimTy+primOpInfo (VecRemOp WordVec 16 W16) = mkDyadic (fsLit "remWord16X16#") word16X16PrimTy+primOpInfo (VecRemOp WordVec 8 W32) = mkDyadic (fsLit "remWord32X8#") word32X8PrimTy+primOpInfo (VecRemOp WordVec 4 W64) = mkDyadic (fsLit "remWord64X4#") word64X4PrimTy+primOpInfo (VecRemOp WordVec 64 W8) = mkDyadic (fsLit "remWord8X64#") word8X64PrimTy+primOpInfo (VecRemOp WordVec 32 W16) = mkDyadic (fsLit "remWord16X32#") word16X32PrimTy+primOpInfo (VecRemOp WordVec 16 W32) = mkDyadic (fsLit "remWord32X16#") word32X16PrimTy+primOpInfo (VecRemOp WordVec 8 W64) = mkDyadic (fsLit "remWord64X8#") word64X8PrimTy+primOpInfo (VecNegOp IntVec 16 W8) = mkMonadic (fsLit "negateInt8X16#") int8X16PrimTy+primOpInfo (VecNegOp IntVec 8 W16) = mkMonadic (fsLit "negateInt16X8#") int16X8PrimTy+primOpInfo (VecNegOp IntVec 4 W32) = mkMonadic (fsLit "negateInt32X4#") int32X4PrimTy+primOpInfo (VecNegOp IntVec 2 W64) = mkMonadic (fsLit "negateInt64X2#") int64X2PrimTy+primOpInfo (VecNegOp IntVec 32 W8) = mkMonadic (fsLit "negateInt8X32#") int8X32PrimTy+primOpInfo (VecNegOp IntVec 16 W16) = mkMonadic (fsLit "negateInt16X16#") int16X16PrimTy+primOpInfo (VecNegOp IntVec 8 W32) = mkMonadic (fsLit "negateInt32X8#") int32X8PrimTy+primOpInfo (VecNegOp IntVec 4 W64) = mkMonadic (fsLit "negateInt64X4#") int64X4PrimTy+primOpInfo (VecNegOp IntVec 64 W8) = mkMonadic (fsLit "negateInt8X64#") int8X64PrimTy+primOpInfo (VecNegOp IntVec 32 W16) = mkMonadic (fsLit "negateInt16X32#") int16X32PrimTy+primOpInfo (VecNegOp IntVec 16 W32) = mkMonadic (fsLit "negateInt32X16#") int32X16PrimTy+primOpInfo (VecNegOp IntVec 8 W64) = mkMonadic (fsLit "negateInt64X8#") int64X8PrimTy+primOpInfo (VecNegOp FloatVec 4 W32) = mkMonadic (fsLit "negateFloatX4#") floatX4PrimTy+primOpInfo (VecNegOp FloatVec 2 W64) = mkMonadic (fsLit "negateDoubleX2#") doubleX2PrimTy+primOpInfo (VecNegOp FloatVec 8 W32) = mkMonadic (fsLit "negateFloatX8#") floatX8PrimTy+primOpInfo (VecNegOp FloatVec 4 W64) = mkMonadic (fsLit "negateDoubleX4#") doubleX4PrimTy+primOpInfo (VecNegOp FloatVec 16 W32) = mkMonadic (fsLit "negateFloatX16#") floatX16PrimTy+primOpInfo (VecNegOp FloatVec 8 W64) = mkMonadic (fsLit "negateDoubleX8#") doubleX8PrimTy+primOpInfo (VecIndexByteArrayOp IntVec 16 W8) = mkGenPrimOp (fsLit "indexInt8X16Array#") [] [byteArrayPrimTy, intPrimTy] (int8X16PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 8 W16) = mkGenPrimOp (fsLit "indexInt16X8Array#") [] [byteArrayPrimTy, intPrimTy] (int16X8PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 4 W32) = mkGenPrimOp (fsLit "indexInt32X4Array#") [] [byteArrayPrimTy, intPrimTy] (int32X4PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 2 W64) = mkGenPrimOp (fsLit "indexInt64X2Array#") [] [byteArrayPrimTy, intPrimTy] (int64X2PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 32 W8) = mkGenPrimOp (fsLit "indexInt8X32Array#") [] [byteArrayPrimTy, intPrimTy] (int8X32PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 16 W16) = mkGenPrimOp (fsLit "indexInt16X16Array#") [] [byteArrayPrimTy, intPrimTy] (int16X16PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 8 W32) = mkGenPrimOp (fsLit "indexInt32X8Array#") [] [byteArrayPrimTy, intPrimTy] (int32X8PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 4 W64) = mkGenPrimOp (fsLit "indexInt64X4Array#") [] [byteArrayPrimTy, intPrimTy] (int64X4PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 64 W8) = mkGenPrimOp (fsLit "indexInt8X64Array#") [] [byteArrayPrimTy, intPrimTy] (int8X64PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 32 W16) = mkGenPrimOp (fsLit "indexInt16X32Array#") [] [byteArrayPrimTy, intPrimTy] (int16X32PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 16 W32) = mkGenPrimOp (fsLit "indexInt32X16Array#") [] [byteArrayPrimTy, intPrimTy] (int32X16PrimTy)+primOpInfo (VecIndexByteArrayOp IntVec 8 W64) = mkGenPrimOp (fsLit "indexInt64X8Array#") [] [byteArrayPrimTy, intPrimTy] (int64X8PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 16 W8) = mkGenPrimOp (fsLit "indexWord8X16Array#") [] [byteArrayPrimTy, intPrimTy] (word8X16PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 8 W16) = mkGenPrimOp (fsLit "indexWord16X8Array#") [] [byteArrayPrimTy, intPrimTy] (word16X8PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 4 W32) = mkGenPrimOp (fsLit "indexWord32X4Array#") [] [byteArrayPrimTy, intPrimTy] (word32X4PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 2 W64) = mkGenPrimOp (fsLit "indexWord64X2Array#") [] [byteArrayPrimTy, intPrimTy] (word64X2PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 32 W8) = mkGenPrimOp (fsLit "indexWord8X32Array#") [] [byteArrayPrimTy, intPrimTy] (word8X32PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 16 W16) = mkGenPrimOp (fsLit "indexWord16X16Array#") [] [byteArrayPrimTy, intPrimTy] (word16X16PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 8 W32) = mkGenPrimOp (fsLit "indexWord32X8Array#") [] [byteArrayPrimTy, intPrimTy] (word32X8PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 4 W64) = mkGenPrimOp (fsLit "indexWord64X4Array#") [] [byteArrayPrimTy, intPrimTy] (word64X4PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 64 W8) = mkGenPrimOp (fsLit "indexWord8X64Array#") [] [byteArrayPrimTy, intPrimTy] (word8X64PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 32 W16) = mkGenPrimOp (fsLit "indexWord16X32Array#") [] [byteArrayPrimTy, intPrimTy] (word16X32PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 16 W32) = mkGenPrimOp (fsLit "indexWord32X16Array#") [] [byteArrayPrimTy, intPrimTy] (word32X16PrimTy)+primOpInfo (VecIndexByteArrayOp WordVec 8 W64) = mkGenPrimOp (fsLit "indexWord64X8Array#") [] [byteArrayPrimTy, intPrimTy] (word64X8PrimTy)+primOpInfo (VecIndexByteArrayOp FloatVec 4 W32) = mkGenPrimOp (fsLit "indexFloatX4Array#") [] [byteArrayPrimTy, intPrimTy] (floatX4PrimTy)+primOpInfo (VecIndexByteArrayOp FloatVec 2 W64) = mkGenPrimOp (fsLit "indexDoubleX2Array#") [] [byteArrayPrimTy, intPrimTy] (doubleX2PrimTy)+primOpInfo (VecIndexByteArrayOp FloatVec 8 W32) = mkGenPrimOp (fsLit "indexFloatX8Array#") [] [byteArrayPrimTy, intPrimTy] (floatX8PrimTy)+primOpInfo (VecIndexByteArrayOp FloatVec 4 W64) = mkGenPrimOp (fsLit "indexDoubleX4Array#") [] [byteArrayPrimTy, intPrimTy] (doubleX4PrimTy)+primOpInfo (VecIndexByteArrayOp FloatVec 16 W32) = mkGenPrimOp (fsLit "indexFloatX16Array#") [] [byteArrayPrimTy, intPrimTy] (floatX16PrimTy)+primOpInfo (VecIndexByteArrayOp FloatVec 8 W64) = mkGenPrimOp (fsLit "indexDoubleX8Array#") [] [byteArrayPrimTy, intPrimTy] (doubleX8PrimTy)+primOpInfo (VecReadByteArrayOp IntVec 16 W8) = mkGenPrimOp (fsLit "readInt8X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X16PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 8 W16) = mkGenPrimOp (fsLit "readInt16X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X8PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 4 W32) = mkGenPrimOp (fsLit "readInt32X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X4PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 2 W64) = mkGenPrimOp (fsLit "readInt64X2Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X2PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 32 W8) = mkGenPrimOp (fsLit "readInt8X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X32PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 16 W16) = mkGenPrimOp (fsLit "readInt16X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X16PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 8 W32) = mkGenPrimOp (fsLit "readInt32X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X8PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 4 W64) = mkGenPrimOp (fsLit "readInt64X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X4PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 64 W8) = mkGenPrimOp (fsLit "readInt8X64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X64PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 32 W16) = mkGenPrimOp (fsLit "readInt16X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X32PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 16 W32) = mkGenPrimOp (fsLit "readInt32X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X16PrimTy]))+primOpInfo (VecReadByteArrayOp IntVec 8 W64) = mkGenPrimOp (fsLit "readInt64X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X8PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 16 W8) = mkGenPrimOp (fsLit "readWord8X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X16PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 8 W16) = mkGenPrimOp (fsLit "readWord16X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X8PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 4 W32) = mkGenPrimOp (fsLit "readWord32X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X4PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 2 W64) = mkGenPrimOp (fsLit "readWord64X2Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X2PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 32 W8) = mkGenPrimOp (fsLit "readWord8X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X32PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 16 W16) = mkGenPrimOp (fsLit "readWord16X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X16PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 8 W32) = mkGenPrimOp (fsLit "readWord32X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X8PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 4 W64) = mkGenPrimOp (fsLit "readWord64X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X4PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 64 W8) = mkGenPrimOp (fsLit "readWord8X64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X64PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 32 W16) = mkGenPrimOp (fsLit "readWord16X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X32PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 16 W32) = mkGenPrimOp (fsLit "readWord32X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X16PrimTy]))+primOpInfo (VecReadByteArrayOp WordVec 8 W64) = mkGenPrimOp (fsLit "readWord64X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X8PrimTy]))+primOpInfo (VecReadByteArrayOp FloatVec 4 W32) = mkGenPrimOp (fsLit "readFloatX4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX4PrimTy]))+primOpInfo (VecReadByteArrayOp FloatVec 2 W64) = mkGenPrimOp (fsLit "readDoubleX2Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX2PrimTy]))+primOpInfo (VecReadByteArrayOp FloatVec 8 W32) = mkGenPrimOp (fsLit "readFloatX8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX8PrimTy]))+primOpInfo (VecReadByteArrayOp FloatVec 4 W64) = mkGenPrimOp (fsLit "readDoubleX4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX4PrimTy]))+primOpInfo (VecReadByteArrayOp FloatVec 16 W32) = mkGenPrimOp (fsLit "readFloatX16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX16PrimTy]))+primOpInfo (VecReadByteArrayOp FloatVec 8 W64) = mkGenPrimOp (fsLit "readDoubleX8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX8PrimTy]))+primOpInfo (VecWriteByteArrayOp IntVec 16 W8) = mkGenPrimOp (fsLit "writeInt8X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 8 W16) = mkGenPrimOp (fsLit "writeInt16X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 4 W32) = mkGenPrimOp (fsLit "writeInt32X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 2 W64) = mkGenPrimOp (fsLit "writeInt64X2Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 32 W8) = mkGenPrimOp (fsLit "writeInt8X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 16 W16) = mkGenPrimOp (fsLit "writeInt16X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 8 W32) = mkGenPrimOp (fsLit "writeInt32X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 4 W64) = mkGenPrimOp (fsLit "writeInt64X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 64 W8) = mkGenPrimOp (fsLit "writeInt8X64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 32 W16) = mkGenPrimOp (fsLit "writeInt16X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 16 W32) = mkGenPrimOp (fsLit "writeInt32X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp IntVec 8 W64) = mkGenPrimOp (fsLit "writeInt64X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 16 W8) = mkGenPrimOp (fsLit "writeWord8X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 8 W16) = mkGenPrimOp (fsLit "writeWord16X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 4 W32) = mkGenPrimOp (fsLit "writeWord32X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 2 W64) = mkGenPrimOp (fsLit "writeWord64X2Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 32 W8) = mkGenPrimOp (fsLit "writeWord8X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 16 W16) = mkGenPrimOp (fsLit "writeWord16X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 8 W32) = mkGenPrimOp (fsLit "writeWord32X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 4 W64) = mkGenPrimOp (fsLit "writeWord64X4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 64 W8) = mkGenPrimOp (fsLit "writeWord8X64Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 32 W16) = mkGenPrimOp (fsLit "writeWord16X32Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 16 W32) = mkGenPrimOp (fsLit "writeWord32X16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp WordVec 8 W64) = mkGenPrimOp (fsLit "writeWord64X8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp FloatVec 4 W32) = mkGenPrimOp (fsLit "writeFloatX4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp FloatVec 2 W64) = mkGenPrimOp (fsLit "writeDoubleX2Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doubleX2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp FloatVec 8 W32) = mkGenPrimOp (fsLit "writeFloatX8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp FloatVec 4 W64) = mkGenPrimOp (fsLit "writeDoubleX4Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doubleX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp FloatVec 16 W32) = mkGenPrimOp (fsLit "writeFloatX16Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatX16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteByteArrayOp FloatVec 8 W64) = mkGenPrimOp (fsLit "writeDoubleX8Array#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doubleX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecIndexOffAddrOp IntVec 16 W8) = mkGenPrimOp (fsLit "indexInt8X16OffAddr#") [] [addrPrimTy, intPrimTy] (int8X16PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 8 W16) = mkGenPrimOp (fsLit "indexInt16X8OffAddr#") [] [addrPrimTy, intPrimTy] (int16X8PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 4 W32) = mkGenPrimOp (fsLit "indexInt32X4OffAddr#") [] [addrPrimTy, intPrimTy] (int32X4PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 2 W64) = mkGenPrimOp (fsLit "indexInt64X2OffAddr#") [] [addrPrimTy, intPrimTy] (int64X2PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 32 W8) = mkGenPrimOp (fsLit "indexInt8X32OffAddr#") [] [addrPrimTy, intPrimTy] (int8X32PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 16 W16) = mkGenPrimOp (fsLit "indexInt16X16OffAddr#") [] [addrPrimTy, intPrimTy] (int16X16PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 8 W32) = mkGenPrimOp (fsLit "indexInt32X8OffAddr#") [] [addrPrimTy, intPrimTy] (int32X8PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 4 W64) = mkGenPrimOp (fsLit "indexInt64X4OffAddr#") [] [addrPrimTy, intPrimTy] (int64X4PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 64 W8) = mkGenPrimOp (fsLit "indexInt8X64OffAddr#") [] [addrPrimTy, intPrimTy] (int8X64PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 32 W16) = mkGenPrimOp (fsLit "indexInt16X32OffAddr#") [] [addrPrimTy, intPrimTy] (int16X32PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 16 W32) = mkGenPrimOp (fsLit "indexInt32X16OffAddr#") [] [addrPrimTy, intPrimTy] (int32X16PrimTy)+primOpInfo (VecIndexOffAddrOp IntVec 8 W64) = mkGenPrimOp (fsLit "indexInt64X8OffAddr#") [] [addrPrimTy, intPrimTy] (int64X8PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 16 W8) = mkGenPrimOp (fsLit "indexWord8X16OffAddr#") [] [addrPrimTy, intPrimTy] (word8X16PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 8 W16) = mkGenPrimOp (fsLit "indexWord16X8OffAddr#") [] [addrPrimTy, intPrimTy] (word16X8PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 4 W32) = mkGenPrimOp (fsLit "indexWord32X4OffAddr#") [] [addrPrimTy, intPrimTy] (word32X4PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 2 W64) = mkGenPrimOp (fsLit "indexWord64X2OffAddr#") [] [addrPrimTy, intPrimTy] (word64X2PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 32 W8) = mkGenPrimOp (fsLit "indexWord8X32OffAddr#") [] [addrPrimTy, intPrimTy] (word8X32PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 16 W16) = mkGenPrimOp (fsLit "indexWord16X16OffAddr#") [] [addrPrimTy, intPrimTy] (word16X16PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 8 W32) = mkGenPrimOp (fsLit "indexWord32X8OffAddr#") [] [addrPrimTy, intPrimTy] (word32X8PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 4 W64) = mkGenPrimOp (fsLit "indexWord64X4OffAddr#") [] [addrPrimTy, intPrimTy] (word64X4PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 64 W8) = mkGenPrimOp (fsLit "indexWord8X64OffAddr#") [] [addrPrimTy, intPrimTy] (word8X64PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 32 W16) = mkGenPrimOp (fsLit "indexWord16X32OffAddr#") [] [addrPrimTy, intPrimTy] (word16X32PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 16 W32) = mkGenPrimOp (fsLit "indexWord32X16OffAddr#") [] [addrPrimTy, intPrimTy] (word32X16PrimTy)+primOpInfo (VecIndexOffAddrOp WordVec 8 W64) = mkGenPrimOp (fsLit "indexWord64X8OffAddr#") [] [addrPrimTy, intPrimTy] (word64X8PrimTy)+primOpInfo (VecIndexOffAddrOp FloatVec 4 W32) = mkGenPrimOp (fsLit "indexFloatX4OffAddr#") [] [addrPrimTy, intPrimTy] (floatX4PrimTy)+primOpInfo (VecIndexOffAddrOp FloatVec 2 W64) = mkGenPrimOp (fsLit "indexDoubleX2OffAddr#") [] [addrPrimTy, intPrimTy] (doubleX2PrimTy)+primOpInfo (VecIndexOffAddrOp FloatVec 8 W32) = mkGenPrimOp (fsLit "indexFloatX8OffAddr#") [] [addrPrimTy, intPrimTy] (floatX8PrimTy)+primOpInfo (VecIndexOffAddrOp FloatVec 4 W64) = mkGenPrimOp (fsLit "indexDoubleX4OffAddr#") [] [addrPrimTy, intPrimTy] (doubleX4PrimTy)+primOpInfo (VecIndexOffAddrOp FloatVec 16 W32) = mkGenPrimOp (fsLit "indexFloatX16OffAddr#") [] [addrPrimTy, intPrimTy] (floatX16PrimTy)+primOpInfo (VecIndexOffAddrOp FloatVec 8 W64) = mkGenPrimOp (fsLit "indexDoubleX8OffAddr#") [] [addrPrimTy, intPrimTy] (doubleX8PrimTy)+primOpInfo (VecReadOffAddrOp IntVec 16 W8) = mkGenPrimOp (fsLit "readInt8X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X16PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 8 W16) = mkGenPrimOp (fsLit "readInt16X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X8PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 4 W32) = mkGenPrimOp (fsLit "readInt32X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X4PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 2 W64) = mkGenPrimOp (fsLit "readInt64X2OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X2PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 32 W8) = mkGenPrimOp (fsLit "readInt8X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X32PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 16 W16) = mkGenPrimOp (fsLit "readInt16X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X16PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 8 W32) = mkGenPrimOp (fsLit "readInt32X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X8PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 4 W64) = mkGenPrimOp (fsLit "readInt64X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X4PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 64 W8) = mkGenPrimOp (fsLit "readInt8X64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X64PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 32 W16) = mkGenPrimOp (fsLit "readInt16X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X32PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 16 W32) = mkGenPrimOp (fsLit "readInt32X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X16PrimTy]))+primOpInfo (VecReadOffAddrOp IntVec 8 W64) = mkGenPrimOp (fsLit "readInt64X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X8PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 16 W8) = mkGenPrimOp (fsLit "readWord8X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X16PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 8 W16) = mkGenPrimOp (fsLit "readWord16X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X8PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 4 W32) = mkGenPrimOp (fsLit "readWord32X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X4PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 2 W64) = mkGenPrimOp (fsLit "readWord64X2OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X2PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 32 W8) = mkGenPrimOp (fsLit "readWord8X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X32PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 16 W16) = mkGenPrimOp (fsLit "readWord16X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X16PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 8 W32) = mkGenPrimOp (fsLit "readWord32X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X8PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 4 W64) = mkGenPrimOp (fsLit "readWord64X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X4PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 64 W8) = mkGenPrimOp (fsLit "readWord8X64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X64PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 32 W16) = mkGenPrimOp (fsLit "readWord16X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X32PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 16 W32) = mkGenPrimOp (fsLit "readWord32X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X16PrimTy]))+primOpInfo (VecReadOffAddrOp WordVec 8 W64) = mkGenPrimOp (fsLit "readWord64X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X8PrimTy]))+primOpInfo (VecReadOffAddrOp FloatVec 4 W32) = mkGenPrimOp (fsLit "readFloatX4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX4PrimTy]))+primOpInfo (VecReadOffAddrOp FloatVec 2 W64) = mkGenPrimOp (fsLit "readDoubleX2OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX2PrimTy]))+primOpInfo (VecReadOffAddrOp FloatVec 8 W32) = mkGenPrimOp (fsLit "readFloatX8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX8PrimTy]))+primOpInfo (VecReadOffAddrOp FloatVec 4 W64) = mkGenPrimOp (fsLit "readDoubleX4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX4PrimTy]))+primOpInfo (VecReadOffAddrOp FloatVec 16 W32) = mkGenPrimOp (fsLit "readFloatX16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX16PrimTy]))+primOpInfo (VecReadOffAddrOp FloatVec 8 W64) = mkGenPrimOp (fsLit "readDoubleX8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX8PrimTy]))+primOpInfo (VecWriteOffAddrOp IntVec 16 W8) = mkGenPrimOp (fsLit "writeInt8X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 8 W16) = mkGenPrimOp (fsLit "writeInt16X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 4 W32) = mkGenPrimOp (fsLit "writeInt32X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 2 W64) = mkGenPrimOp (fsLit "writeInt64X2OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 32 W8) = mkGenPrimOp (fsLit "writeInt8X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 16 W16) = mkGenPrimOp (fsLit "writeInt16X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 8 W32) = mkGenPrimOp (fsLit "writeInt32X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 4 W64) = mkGenPrimOp (fsLit "writeInt64X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 64 W8) = mkGenPrimOp (fsLit "writeInt8X64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 32 W16) = mkGenPrimOp (fsLit "writeInt16X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 16 W32) = mkGenPrimOp (fsLit "writeInt32X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp IntVec 8 W64) = mkGenPrimOp (fsLit "writeInt64X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, int64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 16 W8) = mkGenPrimOp (fsLit "writeWord8X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 8 W16) = mkGenPrimOp (fsLit "writeWord16X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 4 W32) = mkGenPrimOp (fsLit "writeWord32X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 2 W64) = mkGenPrimOp (fsLit "writeWord64X2OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 32 W8) = mkGenPrimOp (fsLit "writeWord8X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 16 W16) = mkGenPrimOp (fsLit "writeWord16X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 8 W32) = mkGenPrimOp (fsLit "writeWord32X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 4 W64) = mkGenPrimOp (fsLit "writeWord64X4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 64 W8) = mkGenPrimOp (fsLit "writeWord8X64OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 32 W16) = mkGenPrimOp (fsLit "writeWord16X32OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 16 W32) = mkGenPrimOp (fsLit "writeWord32X16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp WordVec 8 W64) = mkGenPrimOp (fsLit "writeWord64X8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, word64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp FloatVec 4 W32) = mkGenPrimOp (fsLit "writeFloatX4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, floatX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp FloatVec 2 W64) = mkGenPrimOp (fsLit "writeDoubleX2OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, doubleX2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp FloatVec 8 W32) = mkGenPrimOp (fsLit "writeFloatX8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, floatX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp FloatVec 4 W64) = mkGenPrimOp (fsLit "writeDoubleX4OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, doubleX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp FloatVec 16 W32) = mkGenPrimOp (fsLit "writeFloatX16OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, floatX16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteOffAddrOp FloatVec 8 W64) = mkGenPrimOp (fsLit "writeDoubleX8OffAddr#") [deltaTyVar] [addrPrimTy, intPrimTy, doubleX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 16 W8) = mkGenPrimOp (fsLit "indexInt8ArrayAsInt8X16#") [] [byteArrayPrimTy, intPrimTy] (int8X16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 8 W16) = mkGenPrimOp (fsLit "indexInt16ArrayAsInt16X8#") [] [byteArrayPrimTy, intPrimTy] (int16X8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 4 W32) = mkGenPrimOp (fsLit "indexInt32ArrayAsInt32X4#") [] [byteArrayPrimTy, intPrimTy] (int32X4PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 2 W64) = mkGenPrimOp (fsLit "indexInt64ArrayAsInt64X2#") [] [byteArrayPrimTy, intPrimTy] (int64X2PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 32 W8) = mkGenPrimOp (fsLit "indexInt8ArrayAsInt8X32#") [] [byteArrayPrimTy, intPrimTy] (int8X32PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 16 W16) = mkGenPrimOp (fsLit "indexInt16ArrayAsInt16X16#") [] [byteArrayPrimTy, intPrimTy] (int16X16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 8 W32) = mkGenPrimOp (fsLit "indexInt32ArrayAsInt32X8#") [] [byteArrayPrimTy, intPrimTy] (int32X8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 4 W64) = mkGenPrimOp (fsLit "indexInt64ArrayAsInt64X4#") [] [byteArrayPrimTy, intPrimTy] (int64X4PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 64 W8) = mkGenPrimOp (fsLit "indexInt8ArrayAsInt8X64#") [] [byteArrayPrimTy, intPrimTy] (int8X64PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 32 W16) = mkGenPrimOp (fsLit "indexInt16ArrayAsInt16X32#") [] [byteArrayPrimTy, intPrimTy] (int16X32PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 16 W32) = mkGenPrimOp (fsLit "indexInt32ArrayAsInt32X16#") [] [byteArrayPrimTy, intPrimTy] (int32X16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp IntVec 8 W64) = mkGenPrimOp (fsLit "indexInt64ArrayAsInt64X8#") [] [byteArrayPrimTy, intPrimTy] (int64X8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 16 W8) = mkGenPrimOp (fsLit "indexWord8ArrayAsWord8X16#") [] [byteArrayPrimTy, intPrimTy] (word8X16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 8 W16) = mkGenPrimOp (fsLit "indexWord16ArrayAsWord16X8#") [] [byteArrayPrimTy, intPrimTy] (word16X8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 4 W32) = mkGenPrimOp (fsLit "indexWord32ArrayAsWord32X4#") [] [byteArrayPrimTy, intPrimTy] (word32X4PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 2 W64) = mkGenPrimOp (fsLit "indexWord64ArrayAsWord64X2#") [] [byteArrayPrimTy, intPrimTy] (word64X2PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 32 W8) = mkGenPrimOp (fsLit "indexWord8ArrayAsWord8X32#") [] [byteArrayPrimTy, intPrimTy] (word8X32PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 16 W16) = mkGenPrimOp (fsLit "indexWord16ArrayAsWord16X16#") [] [byteArrayPrimTy, intPrimTy] (word16X16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 8 W32) = mkGenPrimOp (fsLit "indexWord32ArrayAsWord32X8#") [] [byteArrayPrimTy, intPrimTy] (word32X8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 4 W64) = mkGenPrimOp (fsLit "indexWord64ArrayAsWord64X4#") [] [byteArrayPrimTy, intPrimTy] (word64X4PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 64 W8) = mkGenPrimOp (fsLit "indexWord8ArrayAsWord8X64#") [] [byteArrayPrimTy, intPrimTy] (word8X64PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 32 W16) = mkGenPrimOp (fsLit "indexWord16ArrayAsWord16X32#") [] [byteArrayPrimTy, intPrimTy] (word16X32PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 16 W32) = mkGenPrimOp (fsLit "indexWord32ArrayAsWord32X16#") [] [byteArrayPrimTy, intPrimTy] (word32X16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp WordVec 8 W64) = mkGenPrimOp (fsLit "indexWord64ArrayAsWord64X8#") [] [byteArrayPrimTy, intPrimTy] (word64X8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp FloatVec 4 W32) = mkGenPrimOp (fsLit "indexFloatArrayAsFloatX4#") [] [byteArrayPrimTy, intPrimTy] (floatX4PrimTy)+primOpInfo (VecIndexScalarByteArrayOp FloatVec 2 W64) = mkGenPrimOp (fsLit "indexDoubleArrayAsDoubleX2#") [] [byteArrayPrimTy, intPrimTy] (doubleX2PrimTy)+primOpInfo (VecIndexScalarByteArrayOp FloatVec 8 W32) = mkGenPrimOp (fsLit "indexFloatArrayAsFloatX8#") [] [byteArrayPrimTy, intPrimTy] (floatX8PrimTy)+primOpInfo (VecIndexScalarByteArrayOp FloatVec 4 W64) = mkGenPrimOp (fsLit "indexDoubleArrayAsDoubleX4#") [] [byteArrayPrimTy, intPrimTy] (doubleX4PrimTy)+primOpInfo (VecIndexScalarByteArrayOp FloatVec 16 W32) = mkGenPrimOp (fsLit "indexFloatArrayAsFloatX16#") [] [byteArrayPrimTy, intPrimTy] (floatX16PrimTy)+primOpInfo (VecIndexScalarByteArrayOp FloatVec 8 W64) = mkGenPrimOp (fsLit "indexDoubleArrayAsDoubleX8#") [] [byteArrayPrimTy, intPrimTy] (doubleX8PrimTy)+primOpInfo (VecReadScalarByteArrayOp IntVec 16 W8) = mkGenPrimOp (fsLit "readInt8ArrayAsInt8X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 8 W16) = mkGenPrimOp (fsLit "readInt16ArrayAsInt16X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 4 W32) = mkGenPrimOp (fsLit "readInt32ArrayAsInt32X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X4PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 2 W64) = mkGenPrimOp (fsLit "readInt64ArrayAsInt64X2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X2PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 32 W8) = mkGenPrimOp (fsLit "readInt8ArrayAsInt8X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X32PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 16 W16) = mkGenPrimOp (fsLit "readInt16ArrayAsInt16X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 8 W32) = mkGenPrimOp (fsLit "readInt32ArrayAsInt32X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 4 W64) = mkGenPrimOp (fsLit "readInt64ArrayAsInt64X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X4PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 64 W8) = mkGenPrimOp (fsLit "readInt8ArrayAsInt8X64#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X64PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 32 W16) = mkGenPrimOp (fsLit "readInt16ArrayAsInt16X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X32PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 16 W32) = mkGenPrimOp (fsLit "readInt32ArrayAsInt32X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp IntVec 8 W64) = mkGenPrimOp (fsLit "readInt64ArrayAsInt64X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 16 W8) = mkGenPrimOp (fsLit "readWord8ArrayAsWord8X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 8 W16) = mkGenPrimOp (fsLit "readWord16ArrayAsWord16X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 4 W32) = mkGenPrimOp (fsLit "readWord32ArrayAsWord32X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X4PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 2 W64) = mkGenPrimOp (fsLit "readWord64ArrayAsWord64X2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X2PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 32 W8) = mkGenPrimOp (fsLit "readWord8ArrayAsWord8X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X32PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 16 W16) = mkGenPrimOp (fsLit "readWord16ArrayAsWord16X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 8 W32) = mkGenPrimOp (fsLit "readWord32ArrayAsWord32X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 4 W64) = mkGenPrimOp (fsLit "readWord64ArrayAsWord64X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X4PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 64 W8) = mkGenPrimOp (fsLit "readWord8ArrayAsWord8X64#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X64PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 32 W16) = mkGenPrimOp (fsLit "readWord16ArrayAsWord16X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X32PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 16 W32) = mkGenPrimOp (fsLit "readWord32ArrayAsWord32X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp WordVec 8 W64) = mkGenPrimOp (fsLit "readWord64ArrayAsWord64X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp FloatVec 4 W32) = mkGenPrimOp (fsLit "readFloatArrayAsFloatX4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX4PrimTy]))+primOpInfo (VecReadScalarByteArrayOp FloatVec 2 W64) = mkGenPrimOp (fsLit "readDoubleArrayAsDoubleX2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX2PrimTy]))+primOpInfo (VecReadScalarByteArrayOp FloatVec 8 W32) = mkGenPrimOp (fsLit "readFloatArrayAsFloatX8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX8PrimTy]))+primOpInfo (VecReadScalarByteArrayOp FloatVec 4 W64) = mkGenPrimOp (fsLit "readDoubleArrayAsDoubleX4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX4PrimTy]))+primOpInfo (VecReadScalarByteArrayOp FloatVec 16 W32) = mkGenPrimOp (fsLit "readFloatArrayAsFloatX16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX16PrimTy]))+primOpInfo (VecReadScalarByteArrayOp FloatVec 8 W64) = mkGenPrimOp (fsLit "readDoubleArrayAsDoubleX8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX8PrimTy]))+primOpInfo (VecWriteScalarByteArrayOp IntVec 16 W8) = mkGenPrimOp (fsLit "writeInt8ArrayAsInt8X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 8 W16) = mkGenPrimOp (fsLit "writeInt16ArrayAsInt16X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 4 W32) = mkGenPrimOp (fsLit "writeInt32ArrayAsInt32X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 2 W64) = mkGenPrimOp (fsLit "writeInt64ArrayAsInt64X2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 32 W8) = mkGenPrimOp (fsLit "writeInt8ArrayAsInt8X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 16 W16) = mkGenPrimOp (fsLit "writeInt16ArrayAsInt16X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 8 W32) = mkGenPrimOp (fsLit "writeInt32ArrayAsInt32X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 4 W64) = mkGenPrimOp (fsLit "writeInt64ArrayAsInt64X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 64 W8) = mkGenPrimOp (fsLit "writeInt8ArrayAsInt8X64#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 32 W16) = mkGenPrimOp (fsLit "writeInt16ArrayAsInt16X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 16 W32) = mkGenPrimOp (fsLit "writeInt32ArrayAsInt32X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp IntVec 8 W64) = mkGenPrimOp (fsLit "writeInt64ArrayAsInt64X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, int64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 16 W8) = mkGenPrimOp (fsLit "writeWord8ArrayAsWord8X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 8 W16) = mkGenPrimOp (fsLit "writeWord16ArrayAsWord16X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 4 W32) = mkGenPrimOp (fsLit "writeWord32ArrayAsWord32X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 2 W64) = mkGenPrimOp (fsLit "writeWord64ArrayAsWord64X2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 32 W8) = mkGenPrimOp (fsLit "writeWord8ArrayAsWord8X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 16 W16) = mkGenPrimOp (fsLit "writeWord16ArrayAsWord16X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 8 W32) = mkGenPrimOp (fsLit "writeWord32ArrayAsWord32X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 4 W64) = mkGenPrimOp (fsLit "writeWord64ArrayAsWord64X4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 64 W8) = mkGenPrimOp (fsLit "writeWord8ArrayAsWord8X64#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 32 W16) = mkGenPrimOp (fsLit "writeWord16ArrayAsWord16X32#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 16 W32) = mkGenPrimOp (fsLit "writeWord32ArrayAsWord32X16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp WordVec 8 W64) = mkGenPrimOp (fsLit "writeWord64ArrayAsWord64X8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, word64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp FloatVec 4 W32) = mkGenPrimOp (fsLit "writeFloatArrayAsFloatX4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp FloatVec 2 W64) = mkGenPrimOp (fsLit "writeDoubleArrayAsDoubleX2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doubleX2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp FloatVec 8 W32) = mkGenPrimOp (fsLit "writeFloatArrayAsFloatX8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp FloatVec 4 W64) = mkGenPrimOp (fsLit "writeDoubleArrayAsDoubleX4#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doubleX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp FloatVec 16 W32) = mkGenPrimOp (fsLit "writeFloatArrayAsFloatX16#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, floatX16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarByteArrayOp FloatVec 8 W64) = mkGenPrimOp (fsLit "writeDoubleArrayAsDoubleX8#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, doubleX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 16 W8) = mkGenPrimOp (fsLit "indexInt8OffAddrAsInt8X16#") [] [addrPrimTy, intPrimTy] (int8X16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 8 W16) = mkGenPrimOp (fsLit "indexInt16OffAddrAsInt16X8#") [] [addrPrimTy, intPrimTy] (int16X8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 4 W32) = mkGenPrimOp (fsLit "indexInt32OffAddrAsInt32X4#") [] [addrPrimTy, intPrimTy] (int32X4PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 2 W64) = mkGenPrimOp (fsLit "indexInt64OffAddrAsInt64X2#") [] [addrPrimTy, intPrimTy] (int64X2PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 32 W8) = mkGenPrimOp (fsLit "indexInt8OffAddrAsInt8X32#") [] [addrPrimTy, intPrimTy] (int8X32PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 16 W16) = mkGenPrimOp (fsLit "indexInt16OffAddrAsInt16X16#") [] [addrPrimTy, intPrimTy] (int16X16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 8 W32) = mkGenPrimOp (fsLit "indexInt32OffAddrAsInt32X8#") [] [addrPrimTy, intPrimTy] (int32X8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 4 W64) = mkGenPrimOp (fsLit "indexInt64OffAddrAsInt64X4#") [] [addrPrimTy, intPrimTy] (int64X4PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 64 W8) = mkGenPrimOp (fsLit "indexInt8OffAddrAsInt8X64#") [] [addrPrimTy, intPrimTy] (int8X64PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 32 W16) = mkGenPrimOp (fsLit "indexInt16OffAddrAsInt16X32#") [] [addrPrimTy, intPrimTy] (int16X32PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 16 W32) = mkGenPrimOp (fsLit "indexInt32OffAddrAsInt32X16#") [] [addrPrimTy, intPrimTy] (int32X16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp IntVec 8 W64) = mkGenPrimOp (fsLit "indexInt64OffAddrAsInt64X8#") [] [addrPrimTy, intPrimTy] (int64X8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 16 W8) = mkGenPrimOp (fsLit "indexWord8OffAddrAsWord8X16#") [] [addrPrimTy, intPrimTy] (word8X16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 8 W16) = mkGenPrimOp (fsLit "indexWord16OffAddrAsWord16X8#") [] [addrPrimTy, intPrimTy] (word16X8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 4 W32) = mkGenPrimOp (fsLit "indexWord32OffAddrAsWord32X4#") [] [addrPrimTy, intPrimTy] (word32X4PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 2 W64) = mkGenPrimOp (fsLit "indexWord64OffAddrAsWord64X2#") [] [addrPrimTy, intPrimTy] (word64X2PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 32 W8) = mkGenPrimOp (fsLit "indexWord8OffAddrAsWord8X32#") [] [addrPrimTy, intPrimTy] (word8X32PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 16 W16) = mkGenPrimOp (fsLit "indexWord16OffAddrAsWord16X16#") [] [addrPrimTy, intPrimTy] (word16X16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 8 W32) = mkGenPrimOp (fsLit "indexWord32OffAddrAsWord32X8#") [] [addrPrimTy, intPrimTy] (word32X8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 4 W64) = mkGenPrimOp (fsLit "indexWord64OffAddrAsWord64X4#") [] [addrPrimTy, intPrimTy] (word64X4PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 64 W8) = mkGenPrimOp (fsLit "indexWord8OffAddrAsWord8X64#") [] [addrPrimTy, intPrimTy] (word8X64PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 32 W16) = mkGenPrimOp (fsLit "indexWord16OffAddrAsWord16X32#") [] [addrPrimTy, intPrimTy] (word16X32PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 16 W32) = mkGenPrimOp (fsLit "indexWord32OffAddrAsWord32X16#") [] [addrPrimTy, intPrimTy] (word32X16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp WordVec 8 W64) = mkGenPrimOp (fsLit "indexWord64OffAddrAsWord64X8#") [] [addrPrimTy, intPrimTy] (word64X8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp FloatVec 4 W32) = mkGenPrimOp (fsLit "indexFloatOffAddrAsFloatX4#") [] [addrPrimTy, intPrimTy] (floatX4PrimTy)+primOpInfo (VecIndexScalarOffAddrOp FloatVec 2 W64) = mkGenPrimOp (fsLit "indexDoubleOffAddrAsDoubleX2#") [] [addrPrimTy, intPrimTy] (doubleX2PrimTy)+primOpInfo (VecIndexScalarOffAddrOp FloatVec 8 W32) = mkGenPrimOp (fsLit "indexFloatOffAddrAsFloatX8#") [] [addrPrimTy, intPrimTy] (floatX8PrimTy)+primOpInfo (VecIndexScalarOffAddrOp FloatVec 4 W64) = mkGenPrimOp (fsLit "indexDoubleOffAddrAsDoubleX4#") [] [addrPrimTy, intPrimTy] (doubleX4PrimTy)+primOpInfo (VecIndexScalarOffAddrOp FloatVec 16 W32) = mkGenPrimOp (fsLit "indexFloatOffAddrAsFloatX16#") [] [addrPrimTy, intPrimTy] (floatX16PrimTy)+primOpInfo (VecIndexScalarOffAddrOp FloatVec 8 W64) = mkGenPrimOp (fsLit "indexDoubleOffAddrAsDoubleX8#") [] [addrPrimTy, intPrimTy] (doubleX8PrimTy)+primOpInfo (VecReadScalarOffAddrOp IntVec 16 W8) = mkGenPrimOp (fsLit "readInt8OffAddrAsInt8X16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 8 W16) = mkGenPrimOp (fsLit "readInt16OffAddrAsInt16X8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 4 W32) = mkGenPrimOp (fsLit "readInt32OffAddrAsInt32X4#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X4PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 2 W64) = mkGenPrimOp (fsLit "readInt64OffAddrAsInt64X2#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X2PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 32 W8) = mkGenPrimOp (fsLit "readInt8OffAddrAsInt8X32#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X32PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 16 W16) = mkGenPrimOp (fsLit "readInt16OffAddrAsInt16X16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 8 W32) = mkGenPrimOp (fsLit "readInt32OffAddrAsInt32X8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 4 W64) = mkGenPrimOp (fsLit "readInt64OffAddrAsInt64X4#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X4PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 64 W8) = mkGenPrimOp (fsLit "readInt8OffAddrAsInt8X64#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int8X64PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 32 W16) = mkGenPrimOp (fsLit "readInt16OffAddrAsInt16X32#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int16X32PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 16 W32) = mkGenPrimOp (fsLit "readInt32OffAddrAsInt32X16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int32X16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp IntVec 8 W64) = mkGenPrimOp (fsLit "readInt64OffAddrAsInt64X8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, int64X8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 16 W8) = mkGenPrimOp (fsLit "readWord8OffAddrAsWord8X16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 8 W16) = mkGenPrimOp (fsLit "readWord16OffAddrAsWord16X8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 4 W32) = mkGenPrimOp (fsLit "readWord32OffAddrAsWord32X4#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X4PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 2 W64) = mkGenPrimOp (fsLit "readWord64OffAddrAsWord64X2#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X2PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 32 W8) = mkGenPrimOp (fsLit "readWord8OffAddrAsWord8X32#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X32PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 16 W16) = mkGenPrimOp (fsLit "readWord16OffAddrAsWord16X16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 8 W32) = mkGenPrimOp (fsLit "readWord32OffAddrAsWord32X8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 4 W64) = mkGenPrimOp (fsLit "readWord64OffAddrAsWord64X4#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X4PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 64 W8) = mkGenPrimOp (fsLit "readWord8OffAddrAsWord8X64#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word8X64PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 32 W16) = mkGenPrimOp (fsLit "readWord16OffAddrAsWord16X32#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word16X32PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 16 W32) = mkGenPrimOp (fsLit "readWord32OffAddrAsWord32X16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word32X16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp WordVec 8 W64) = mkGenPrimOp (fsLit "readWord64OffAddrAsWord64X8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, word64X8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp FloatVec 4 W32) = mkGenPrimOp (fsLit "readFloatOffAddrAsFloatX4#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX4PrimTy]))+primOpInfo (VecReadScalarOffAddrOp FloatVec 2 W64) = mkGenPrimOp (fsLit "readDoubleOffAddrAsDoubleX2#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX2PrimTy]))+primOpInfo (VecReadScalarOffAddrOp FloatVec 8 W32) = mkGenPrimOp (fsLit "readFloatOffAddrAsFloatX8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX8PrimTy]))+primOpInfo (VecReadScalarOffAddrOp FloatVec 4 W64) = mkGenPrimOp (fsLit "readDoubleOffAddrAsDoubleX4#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX4PrimTy]))+primOpInfo (VecReadScalarOffAddrOp FloatVec 16 W32) = mkGenPrimOp (fsLit "readFloatOffAddrAsFloatX16#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, floatX16PrimTy]))+primOpInfo (VecReadScalarOffAddrOp FloatVec 8 W64) = mkGenPrimOp (fsLit "readDoubleOffAddrAsDoubleX8#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] ((mkTupleTy Unboxed [mkStatePrimTy deltaTy, doubleX8PrimTy]))+primOpInfo (VecWriteScalarOffAddrOp IntVec 16 W8) = mkGenPrimOp (fsLit "writeInt8OffAddrAsInt8X16#") [deltaTyVar] [addrPrimTy, intPrimTy, int8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 8 W16) = mkGenPrimOp (fsLit "writeInt16OffAddrAsInt16X8#") [deltaTyVar] [addrPrimTy, intPrimTy, int16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 4 W32) = mkGenPrimOp (fsLit "writeInt32OffAddrAsInt32X4#") [deltaTyVar] [addrPrimTy, intPrimTy, int32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 2 W64) = mkGenPrimOp (fsLit "writeInt64OffAddrAsInt64X2#") [deltaTyVar] [addrPrimTy, intPrimTy, int64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 32 W8) = mkGenPrimOp (fsLit "writeInt8OffAddrAsInt8X32#") [deltaTyVar] [addrPrimTy, intPrimTy, int8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 16 W16) = mkGenPrimOp (fsLit "writeInt16OffAddrAsInt16X16#") [deltaTyVar] [addrPrimTy, intPrimTy, int16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 8 W32) = mkGenPrimOp (fsLit "writeInt32OffAddrAsInt32X8#") [deltaTyVar] [addrPrimTy, intPrimTy, int32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 4 W64) = mkGenPrimOp (fsLit "writeInt64OffAddrAsInt64X4#") [deltaTyVar] [addrPrimTy, intPrimTy, int64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 64 W8) = mkGenPrimOp (fsLit "writeInt8OffAddrAsInt8X64#") [deltaTyVar] [addrPrimTy, intPrimTy, int8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 32 W16) = mkGenPrimOp (fsLit "writeInt16OffAddrAsInt16X32#") [deltaTyVar] [addrPrimTy, intPrimTy, int16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 16 W32) = mkGenPrimOp (fsLit "writeInt32OffAddrAsInt32X16#") [deltaTyVar] [addrPrimTy, intPrimTy, int32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp IntVec 8 W64) = mkGenPrimOp (fsLit "writeInt64OffAddrAsInt64X8#") [deltaTyVar] [addrPrimTy, intPrimTy, int64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 16 W8) = mkGenPrimOp (fsLit "writeWord8OffAddrAsWord8X16#") [deltaTyVar] [addrPrimTy, intPrimTy, word8X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 8 W16) = mkGenPrimOp (fsLit "writeWord16OffAddrAsWord16X8#") [deltaTyVar] [addrPrimTy, intPrimTy, word16X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 4 W32) = mkGenPrimOp (fsLit "writeWord32OffAddrAsWord32X4#") [deltaTyVar] [addrPrimTy, intPrimTy, word32X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 2 W64) = mkGenPrimOp (fsLit "writeWord64OffAddrAsWord64X2#") [deltaTyVar] [addrPrimTy, intPrimTy, word64X2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 32 W8) = mkGenPrimOp (fsLit "writeWord8OffAddrAsWord8X32#") [deltaTyVar] [addrPrimTy, intPrimTy, word8X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 16 W16) = mkGenPrimOp (fsLit "writeWord16OffAddrAsWord16X16#") [deltaTyVar] [addrPrimTy, intPrimTy, word16X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 8 W32) = mkGenPrimOp (fsLit "writeWord32OffAddrAsWord32X8#") [deltaTyVar] [addrPrimTy, intPrimTy, word32X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 4 W64) = mkGenPrimOp (fsLit "writeWord64OffAddrAsWord64X4#") [deltaTyVar] [addrPrimTy, intPrimTy, word64X4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 64 W8) = mkGenPrimOp (fsLit "writeWord8OffAddrAsWord8X64#") [deltaTyVar] [addrPrimTy, intPrimTy, word8X64PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 32 W16) = mkGenPrimOp (fsLit "writeWord16OffAddrAsWord16X32#") [deltaTyVar] [addrPrimTy, intPrimTy, word16X32PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 16 W32) = mkGenPrimOp (fsLit "writeWord32OffAddrAsWord32X16#") [deltaTyVar] [addrPrimTy, intPrimTy, word32X16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp WordVec 8 W64) = mkGenPrimOp (fsLit "writeWord64OffAddrAsWord64X8#") [deltaTyVar] [addrPrimTy, intPrimTy, word64X8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp FloatVec 4 W32) = mkGenPrimOp (fsLit "writeFloatOffAddrAsFloatX4#") [deltaTyVar] [addrPrimTy, intPrimTy, floatX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp FloatVec 2 W64) = mkGenPrimOp (fsLit "writeDoubleOffAddrAsDoubleX2#") [deltaTyVar] [addrPrimTy, intPrimTy, doubleX2PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp FloatVec 8 W32) = mkGenPrimOp (fsLit "writeFloatOffAddrAsFloatX8#") [deltaTyVar] [addrPrimTy, intPrimTy, floatX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp FloatVec 4 W64) = mkGenPrimOp (fsLit "writeDoubleOffAddrAsDoubleX4#") [deltaTyVar] [addrPrimTy, intPrimTy, doubleX4PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp FloatVec 16 W32) = mkGenPrimOp (fsLit "writeFloatOffAddrAsFloatX16#") [deltaTyVar] [addrPrimTy, intPrimTy, floatX16PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo (VecWriteScalarOffAddrOp FloatVec 8 W64) = mkGenPrimOp (fsLit "writeDoubleOffAddrAsDoubleX8#") [deltaTyVar] [addrPrimTy, intPrimTy, doubleX8PrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchByteArrayOp3 = mkGenPrimOp (fsLit "prefetchByteArray3#") [deltaTyVar] [byteArrayPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchMutableByteArrayOp3 = mkGenPrimOp (fsLit "prefetchMutableByteArray3#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchAddrOp3 = mkGenPrimOp (fsLit "prefetchAddr3#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchValueOp3 = mkGenPrimOp (fsLit "prefetchValue3#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchByteArrayOp2 = mkGenPrimOp (fsLit "prefetchByteArray2#") [deltaTyVar] [byteArrayPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchMutableByteArrayOp2 = mkGenPrimOp (fsLit "prefetchMutableByteArray2#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchAddrOp2 = mkGenPrimOp (fsLit "prefetchAddr2#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchValueOp2 = mkGenPrimOp (fsLit "prefetchValue2#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchByteArrayOp1 = mkGenPrimOp (fsLit "prefetchByteArray1#") [deltaTyVar] [byteArrayPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchMutableByteArrayOp1 = mkGenPrimOp (fsLit "prefetchMutableByteArray1#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchAddrOp1 = mkGenPrimOp (fsLit "prefetchAddr1#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchValueOp1 = mkGenPrimOp (fsLit "prefetchValue1#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchByteArrayOp0 = mkGenPrimOp (fsLit "prefetchByteArray0#") [deltaTyVar] [byteArrayPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchMutableByteArrayOp0 = mkGenPrimOp (fsLit "prefetchMutableByteArray0#") [deltaTyVar] [mkMutableByteArrayPrimTy deltaTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchAddrOp0 = mkGenPrimOp (fsLit "prefetchAddr0#") [deltaTyVar] [addrPrimTy, intPrimTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)+primOpInfo PrefetchValueOp0 = mkGenPrimOp (fsLit "prefetchValue0#") [alphaTyVar, deltaTyVar] [alphaTy, mkStatePrimTy deltaTy] (mkStatePrimTy deltaTy)
+ autogen/primop-strictness.hs-incl view
@@ -0,0 +1,22 @@+primOpStrictness CatchOp = \ _arity -> mkClosedStrictSig [ lazyApply1Dmd+ , lazyApply2Dmd+ , topDmd] topRes +primOpStrictness RaiseOp = \ _arity -> mkClosedStrictSig [topDmd] exnRes +primOpStrictness RaiseIOOp = \ _arity -> mkClosedStrictSig [topDmd, topDmd] exnRes +primOpStrictness MaskAsyncExceptionsOp = \ _arity -> mkClosedStrictSig [strictApply1Dmd,topDmd] topRes +primOpStrictness MaskUninterruptibleOp = \ _arity -> mkClosedStrictSig [strictApply1Dmd,topDmd] topRes +primOpStrictness UnmaskAsyncExceptionsOp = \ _arity -> mkClosedStrictSig [strictApply1Dmd,topDmd] topRes +primOpStrictness AtomicallyOp = \ _arity -> mkClosedStrictSig [strictApply1Dmd,topDmd] topRes +primOpStrictness RetryOp = \ _arity -> mkClosedStrictSig [topDmd] botRes +primOpStrictness CatchRetryOp = \ _arity -> mkClosedStrictSig [ catchArgDmd+ , lazyApply1Dmd+ , topDmd ] topRes +primOpStrictness CatchSTMOp = \ _arity -> mkClosedStrictSig [ lazyApply1Dmd+ , lazyApply2Dmd+ , topDmd ] topRes +primOpStrictness DataToTagOp = \ _arity -> mkClosedStrictSig [evalDmd] topRes +primOpStrictness PrefetchValueOp3 = \ _arity -> mkClosedStrictSig [botDmd, topDmd] topRes +primOpStrictness PrefetchValueOp2 = \ _arity -> mkClosedStrictSig [botDmd, topDmd] topRes +primOpStrictness PrefetchValueOp1 = \ _arity -> mkClosedStrictSig [botDmd, topDmd] topRes +primOpStrictness PrefetchValueOp0 = \ _arity -> mkClosedStrictSig [botDmd, topDmd] topRes +primOpStrictness _ = \ arity -> mkClosedStrictSig (replicate arity topDmd) topRes
+ autogen/primop-tag.hs-incl view
@@ -0,0 +1,1072 @@+maxPrimOpTag :: Int+maxPrimOpTag = 1069+primOpTag :: PrimOp -> Int+primOpTag CharGtOp = 1+primOpTag CharGeOp = 2+primOpTag CharEqOp = 3+primOpTag CharNeOp = 4+primOpTag CharLtOp = 5+primOpTag CharLeOp = 6+primOpTag OrdOp = 7+primOpTag IntAddOp = 8+primOpTag IntSubOp = 9+primOpTag IntMulOp = 10+primOpTag IntMulMayOfloOp = 11+primOpTag IntQuotOp = 12+primOpTag IntRemOp = 13+primOpTag IntQuotRemOp = 14+primOpTag AndIOp = 15+primOpTag OrIOp = 16+primOpTag XorIOp = 17+primOpTag NotIOp = 18+primOpTag IntNegOp = 19+primOpTag IntAddCOp = 20+primOpTag IntSubCOp = 21+primOpTag IntGtOp = 22+primOpTag IntGeOp = 23+primOpTag IntEqOp = 24+primOpTag IntNeOp = 25+primOpTag IntLtOp = 26+primOpTag IntLeOp = 27+primOpTag ChrOp = 28+primOpTag Int2WordOp = 29+primOpTag Int2FloatOp = 30+primOpTag Int2DoubleOp = 31+primOpTag Word2FloatOp = 32+primOpTag Word2DoubleOp = 33+primOpTag ISllOp = 34+primOpTag ISraOp = 35+primOpTag ISrlOp = 36+primOpTag WordAddOp = 37+primOpTag WordSubCOp = 38+primOpTag WordAdd2Op = 39+primOpTag WordSubOp = 40+primOpTag WordMulOp = 41+primOpTag WordMul2Op = 42+primOpTag WordQuotOp = 43+primOpTag WordRemOp = 44+primOpTag WordQuotRemOp = 45+primOpTag WordQuotRem2Op = 46+primOpTag AndOp = 47+primOpTag OrOp = 48+primOpTag XorOp = 49+primOpTag NotOp = 50+primOpTag SllOp = 51+primOpTag SrlOp = 52+primOpTag Word2IntOp = 53+primOpTag WordGtOp = 54+primOpTag WordGeOp = 55+primOpTag WordEqOp = 56+primOpTag WordNeOp = 57+primOpTag WordLtOp = 58+primOpTag WordLeOp = 59+primOpTag PopCnt8Op = 60+primOpTag PopCnt16Op = 61+primOpTag PopCnt32Op = 62+primOpTag PopCnt64Op = 63+primOpTag PopCntOp = 64+primOpTag Clz8Op = 65+primOpTag Clz16Op = 66+primOpTag Clz32Op = 67+primOpTag Clz64Op = 68+primOpTag ClzOp = 69+primOpTag Ctz8Op = 70+primOpTag Ctz16Op = 71+primOpTag Ctz32Op = 72+primOpTag Ctz64Op = 73+primOpTag CtzOp = 74+primOpTag BSwap16Op = 75+primOpTag BSwap32Op = 76+primOpTag BSwap64Op = 77+primOpTag BSwapOp = 78+primOpTag Narrow8IntOp = 79+primOpTag Narrow16IntOp = 80+primOpTag Narrow32IntOp = 81+primOpTag Narrow8WordOp = 82+primOpTag Narrow16WordOp = 83+primOpTag Narrow32WordOp = 84+primOpTag DoubleGtOp = 85+primOpTag DoubleGeOp = 86+primOpTag DoubleEqOp = 87+primOpTag DoubleNeOp = 88+primOpTag DoubleLtOp = 89+primOpTag DoubleLeOp = 90+primOpTag DoubleAddOp = 91+primOpTag DoubleSubOp = 92+primOpTag DoubleMulOp = 93+primOpTag DoubleDivOp = 94+primOpTag DoubleNegOp = 95+primOpTag DoubleFabsOp = 96+primOpTag Double2IntOp = 97+primOpTag Double2FloatOp = 98+primOpTag DoubleExpOp = 99+primOpTag DoubleLogOp = 100+primOpTag DoubleSqrtOp = 101+primOpTag DoubleSinOp = 102+primOpTag DoubleCosOp = 103+primOpTag DoubleTanOp = 104+primOpTag DoubleAsinOp = 105+primOpTag DoubleAcosOp = 106+primOpTag DoubleAtanOp = 107+primOpTag DoubleSinhOp = 108+primOpTag DoubleCoshOp = 109+primOpTag DoubleTanhOp = 110+primOpTag DoublePowerOp = 111+primOpTag DoubleDecode_2IntOp = 112+primOpTag DoubleDecode_Int64Op = 113+primOpTag FloatGtOp = 114+primOpTag FloatGeOp = 115+primOpTag FloatEqOp = 116+primOpTag FloatNeOp = 117+primOpTag FloatLtOp = 118+primOpTag FloatLeOp = 119+primOpTag FloatAddOp = 120+primOpTag FloatSubOp = 121+primOpTag FloatMulOp = 122+primOpTag FloatDivOp = 123+primOpTag FloatNegOp = 124+primOpTag FloatFabsOp = 125+primOpTag Float2IntOp = 126+primOpTag FloatExpOp = 127+primOpTag FloatLogOp = 128+primOpTag FloatSqrtOp = 129+primOpTag FloatSinOp = 130+primOpTag FloatCosOp = 131+primOpTag FloatTanOp = 132+primOpTag FloatAsinOp = 133+primOpTag FloatAcosOp = 134+primOpTag FloatAtanOp = 135+primOpTag FloatSinhOp = 136+primOpTag FloatCoshOp = 137+primOpTag FloatTanhOp = 138+primOpTag FloatPowerOp = 139+primOpTag Float2DoubleOp = 140+primOpTag FloatDecode_IntOp = 141+primOpTag NewArrayOp = 142+primOpTag SameMutableArrayOp = 143+primOpTag ReadArrayOp = 144+primOpTag WriteArrayOp = 145+primOpTag SizeofArrayOp = 146+primOpTag SizeofMutableArrayOp = 147+primOpTag IndexArrayOp = 148+primOpTag UnsafeFreezeArrayOp = 149+primOpTag UnsafeThawArrayOp = 150+primOpTag CopyArrayOp = 151+primOpTag CopyMutableArrayOp = 152+primOpTag CloneArrayOp = 153+primOpTag CloneMutableArrayOp = 154+primOpTag FreezeArrayOp = 155+primOpTag ThawArrayOp = 156+primOpTag CasArrayOp = 157+primOpTag NewSmallArrayOp = 158+primOpTag SameSmallMutableArrayOp = 159+primOpTag ReadSmallArrayOp = 160+primOpTag WriteSmallArrayOp = 161+primOpTag SizeofSmallArrayOp = 162+primOpTag SizeofSmallMutableArrayOp = 163+primOpTag IndexSmallArrayOp = 164+primOpTag UnsafeFreezeSmallArrayOp = 165+primOpTag UnsafeThawSmallArrayOp = 166+primOpTag CopySmallArrayOp = 167+primOpTag CopySmallMutableArrayOp = 168+primOpTag CloneSmallArrayOp = 169+primOpTag CloneSmallMutableArrayOp = 170+primOpTag FreezeSmallArrayOp = 171+primOpTag ThawSmallArrayOp = 172+primOpTag CasSmallArrayOp = 173+primOpTag NewByteArrayOp_Char = 174+primOpTag NewPinnedByteArrayOp_Char = 175+primOpTag NewAlignedPinnedByteArrayOp_Char = 176+primOpTag MutableByteArrayIsPinnedOp = 177+primOpTag ByteArrayIsPinnedOp = 178+primOpTag ByteArrayContents_Char = 179+primOpTag SameMutableByteArrayOp = 180+primOpTag ShrinkMutableByteArrayOp_Char = 181+primOpTag ResizeMutableByteArrayOp_Char = 182+primOpTag UnsafeFreezeByteArrayOp = 183+primOpTag SizeofByteArrayOp = 184+primOpTag SizeofMutableByteArrayOp = 185+primOpTag GetSizeofMutableByteArrayOp = 186+primOpTag IndexByteArrayOp_Char = 187+primOpTag IndexByteArrayOp_WideChar = 188+primOpTag IndexByteArrayOp_Int = 189+primOpTag IndexByteArrayOp_Word = 190+primOpTag IndexByteArrayOp_Addr = 191+primOpTag IndexByteArrayOp_Float = 192+primOpTag IndexByteArrayOp_Double = 193+primOpTag IndexByteArrayOp_StablePtr = 194+primOpTag IndexByteArrayOp_Int8 = 195+primOpTag IndexByteArrayOp_Int16 = 196+primOpTag IndexByteArrayOp_Int32 = 197+primOpTag IndexByteArrayOp_Int64 = 198+primOpTag IndexByteArrayOp_Word8 = 199+primOpTag IndexByteArrayOp_Word16 = 200+primOpTag IndexByteArrayOp_Word32 = 201+primOpTag IndexByteArrayOp_Word64 = 202+primOpTag ReadByteArrayOp_Char = 203+primOpTag ReadByteArrayOp_WideChar = 204+primOpTag ReadByteArrayOp_Int = 205+primOpTag ReadByteArrayOp_Word = 206+primOpTag ReadByteArrayOp_Addr = 207+primOpTag ReadByteArrayOp_Float = 208+primOpTag ReadByteArrayOp_Double = 209+primOpTag ReadByteArrayOp_StablePtr = 210+primOpTag ReadByteArrayOp_Int8 = 211+primOpTag ReadByteArrayOp_Int16 = 212+primOpTag ReadByteArrayOp_Int32 = 213+primOpTag ReadByteArrayOp_Int64 = 214+primOpTag ReadByteArrayOp_Word8 = 215+primOpTag ReadByteArrayOp_Word16 = 216+primOpTag ReadByteArrayOp_Word32 = 217+primOpTag ReadByteArrayOp_Word64 = 218+primOpTag WriteByteArrayOp_Char = 219+primOpTag WriteByteArrayOp_WideChar = 220+primOpTag WriteByteArrayOp_Int = 221+primOpTag WriteByteArrayOp_Word = 222+primOpTag WriteByteArrayOp_Addr = 223+primOpTag WriteByteArrayOp_Float = 224+primOpTag WriteByteArrayOp_Double = 225+primOpTag WriteByteArrayOp_StablePtr = 226+primOpTag WriteByteArrayOp_Int8 = 227+primOpTag WriteByteArrayOp_Int16 = 228+primOpTag WriteByteArrayOp_Int32 = 229+primOpTag WriteByteArrayOp_Int64 = 230+primOpTag WriteByteArrayOp_Word8 = 231+primOpTag WriteByteArrayOp_Word16 = 232+primOpTag WriteByteArrayOp_Word32 = 233+primOpTag WriteByteArrayOp_Word64 = 234+primOpTag CopyByteArrayOp = 235+primOpTag CopyMutableByteArrayOp = 236+primOpTag CopyByteArrayToAddrOp = 237+primOpTag CopyMutableByteArrayToAddrOp = 238+primOpTag CopyAddrToByteArrayOp = 239+primOpTag SetByteArrayOp = 240+primOpTag AtomicReadByteArrayOp_Int = 241+primOpTag AtomicWriteByteArrayOp_Int = 242+primOpTag CasByteArrayOp_Int = 243+primOpTag FetchAddByteArrayOp_Int = 244+primOpTag FetchSubByteArrayOp_Int = 245+primOpTag FetchAndByteArrayOp_Int = 246+primOpTag FetchNandByteArrayOp_Int = 247+primOpTag FetchOrByteArrayOp_Int = 248+primOpTag FetchXorByteArrayOp_Int = 249+primOpTag NewArrayArrayOp = 250+primOpTag SameMutableArrayArrayOp = 251+primOpTag UnsafeFreezeArrayArrayOp = 252+primOpTag SizeofArrayArrayOp = 253+primOpTag SizeofMutableArrayArrayOp = 254+primOpTag IndexArrayArrayOp_ByteArray = 255+primOpTag IndexArrayArrayOp_ArrayArray = 256+primOpTag ReadArrayArrayOp_ByteArray = 257+primOpTag ReadArrayArrayOp_MutableByteArray = 258+primOpTag ReadArrayArrayOp_ArrayArray = 259+primOpTag ReadArrayArrayOp_MutableArrayArray = 260+primOpTag WriteArrayArrayOp_ByteArray = 261+primOpTag WriteArrayArrayOp_MutableByteArray = 262+primOpTag WriteArrayArrayOp_ArrayArray = 263+primOpTag WriteArrayArrayOp_MutableArrayArray = 264+primOpTag CopyArrayArrayOp = 265+primOpTag CopyMutableArrayArrayOp = 266+primOpTag AddrAddOp = 267+primOpTag AddrSubOp = 268+primOpTag AddrRemOp = 269+primOpTag Addr2IntOp = 270+primOpTag Int2AddrOp = 271+primOpTag AddrGtOp = 272+primOpTag AddrGeOp = 273+primOpTag AddrEqOp = 274+primOpTag AddrNeOp = 275+primOpTag AddrLtOp = 276+primOpTag AddrLeOp = 277+primOpTag IndexOffAddrOp_Char = 278+primOpTag IndexOffAddrOp_WideChar = 279+primOpTag IndexOffAddrOp_Int = 280+primOpTag IndexOffAddrOp_Word = 281+primOpTag IndexOffAddrOp_Addr = 282+primOpTag IndexOffAddrOp_Float = 283+primOpTag IndexOffAddrOp_Double = 284+primOpTag IndexOffAddrOp_StablePtr = 285+primOpTag IndexOffAddrOp_Int8 = 286+primOpTag IndexOffAddrOp_Int16 = 287+primOpTag IndexOffAddrOp_Int32 = 288+primOpTag IndexOffAddrOp_Int64 = 289+primOpTag IndexOffAddrOp_Word8 = 290+primOpTag IndexOffAddrOp_Word16 = 291+primOpTag IndexOffAddrOp_Word32 = 292+primOpTag IndexOffAddrOp_Word64 = 293+primOpTag ReadOffAddrOp_Char = 294+primOpTag ReadOffAddrOp_WideChar = 295+primOpTag ReadOffAddrOp_Int = 296+primOpTag ReadOffAddrOp_Word = 297+primOpTag ReadOffAddrOp_Addr = 298+primOpTag ReadOffAddrOp_Float = 299+primOpTag ReadOffAddrOp_Double = 300+primOpTag ReadOffAddrOp_StablePtr = 301+primOpTag ReadOffAddrOp_Int8 = 302+primOpTag ReadOffAddrOp_Int16 = 303+primOpTag ReadOffAddrOp_Int32 = 304+primOpTag ReadOffAddrOp_Int64 = 305+primOpTag ReadOffAddrOp_Word8 = 306+primOpTag ReadOffAddrOp_Word16 = 307+primOpTag ReadOffAddrOp_Word32 = 308+primOpTag ReadOffAddrOp_Word64 = 309+primOpTag WriteOffAddrOp_Char = 310+primOpTag WriteOffAddrOp_WideChar = 311+primOpTag WriteOffAddrOp_Int = 312+primOpTag WriteOffAddrOp_Word = 313+primOpTag WriteOffAddrOp_Addr = 314+primOpTag WriteOffAddrOp_Float = 315+primOpTag WriteOffAddrOp_Double = 316+primOpTag WriteOffAddrOp_StablePtr = 317+primOpTag WriteOffAddrOp_Int8 = 318+primOpTag WriteOffAddrOp_Int16 = 319+primOpTag WriteOffAddrOp_Int32 = 320+primOpTag WriteOffAddrOp_Int64 = 321+primOpTag WriteOffAddrOp_Word8 = 322+primOpTag WriteOffAddrOp_Word16 = 323+primOpTag WriteOffAddrOp_Word32 = 324+primOpTag WriteOffAddrOp_Word64 = 325+primOpTag NewMutVarOp = 326+primOpTag ReadMutVarOp = 327+primOpTag WriteMutVarOp = 328+primOpTag SameMutVarOp = 329+primOpTag AtomicModifyMutVarOp = 330+primOpTag CasMutVarOp = 331+primOpTag CatchOp = 332+primOpTag RaiseOp = 333+primOpTag RaiseIOOp = 334+primOpTag MaskAsyncExceptionsOp = 335+primOpTag MaskUninterruptibleOp = 336+primOpTag UnmaskAsyncExceptionsOp = 337+primOpTag MaskStatus = 338+primOpTag AtomicallyOp = 339+primOpTag RetryOp = 340+primOpTag CatchRetryOp = 341+primOpTag CatchSTMOp = 342+primOpTag Check = 343+primOpTag NewTVarOp = 344+primOpTag ReadTVarOp = 345+primOpTag ReadTVarIOOp = 346+primOpTag WriteTVarOp = 347+primOpTag SameTVarOp = 348+primOpTag NewMVarOp = 349+primOpTag TakeMVarOp = 350+primOpTag TryTakeMVarOp = 351+primOpTag PutMVarOp = 352+primOpTag TryPutMVarOp = 353+primOpTag ReadMVarOp = 354+primOpTag TryReadMVarOp = 355+primOpTag SameMVarOp = 356+primOpTag IsEmptyMVarOp = 357+primOpTag DelayOp = 358+primOpTag WaitReadOp = 359+primOpTag WaitWriteOp = 360+primOpTag ForkOp = 361+primOpTag ForkOnOp = 362+primOpTag KillThreadOp = 363+primOpTag YieldOp = 364+primOpTag MyThreadIdOp = 365+primOpTag LabelThreadOp = 366+primOpTag IsCurrentThreadBoundOp = 367+primOpTag NoDuplicateOp = 368+primOpTag ThreadStatusOp = 369+primOpTag MkWeakOp = 370+primOpTag MkWeakNoFinalizerOp = 371+primOpTag AddCFinalizerToWeakOp = 372+primOpTag DeRefWeakOp = 373+primOpTag FinalizeWeakOp = 374+primOpTag TouchOp = 375+primOpTag MakeStablePtrOp = 376+primOpTag DeRefStablePtrOp = 377+primOpTag EqStablePtrOp = 378+primOpTag MakeStableNameOp = 379+primOpTag EqStableNameOp = 380+primOpTag StableNameToIntOp = 381+primOpTag CompactNewOp = 382+primOpTag CompactResizeOp = 383+primOpTag CompactContainsOp = 384+primOpTag CompactContainsAnyOp = 385+primOpTag CompactGetFirstBlockOp = 386+primOpTag CompactGetNextBlockOp = 387+primOpTag CompactAllocateBlockOp = 388+primOpTag CompactFixupPointersOp = 389+primOpTag CompactAdd = 390+primOpTag CompactAddWithSharing = 391+primOpTag CompactSize = 392+primOpTag ReallyUnsafePtrEqualityOp = 393+primOpTag ParOp = 394+primOpTag SparkOp = 395+primOpTag SeqOp = 396+primOpTag GetSparkOp = 397+primOpTag NumSparks = 398+primOpTag DataToTagOp = 399+primOpTag TagToEnumOp = 400+primOpTag AddrToAnyOp = 401+primOpTag AnyToAddrOp = 402+primOpTag MkApUpd0_Op = 403+primOpTag NewBCOOp = 404+primOpTag UnpackClosureOp = 405+primOpTag GetApStackValOp = 406+primOpTag GetCCSOfOp = 407+primOpTag GetCurrentCCSOp = 408+primOpTag ClearCCSOp = 409+primOpTag TraceEventOp = 410+primOpTag TraceMarkerOp = 411+primOpTag (VecBroadcastOp IntVec 16 W8) = 412+primOpTag (VecBroadcastOp IntVec 8 W16) = 413+primOpTag (VecBroadcastOp IntVec 4 W32) = 414+primOpTag (VecBroadcastOp IntVec 2 W64) = 415+primOpTag (VecBroadcastOp IntVec 32 W8) = 416+primOpTag (VecBroadcastOp IntVec 16 W16) = 417+primOpTag (VecBroadcastOp IntVec 8 W32) = 418+primOpTag (VecBroadcastOp IntVec 4 W64) = 419+primOpTag (VecBroadcastOp IntVec 64 W8) = 420+primOpTag (VecBroadcastOp IntVec 32 W16) = 421+primOpTag (VecBroadcastOp IntVec 16 W32) = 422+primOpTag (VecBroadcastOp IntVec 8 W64) = 423+primOpTag (VecBroadcastOp WordVec 16 W8) = 424+primOpTag (VecBroadcastOp WordVec 8 W16) = 425+primOpTag (VecBroadcastOp WordVec 4 W32) = 426+primOpTag (VecBroadcastOp WordVec 2 W64) = 427+primOpTag (VecBroadcastOp WordVec 32 W8) = 428+primOpTag (VecBroadcastOp WordVec 16 W16) = 429+primOpTag (VecBroadcastOp WordVec 8 W32) = 430+primOpTag (VecBroadcastOp WordVec 4 W64) = 431+primOpTag (VecBroadcastOp WordVec 64 W8) = 432+primOpTag (VecBroadcastOp WordVec 32 W16) = 433+primOpTag (VecBroadcastOp WordVec 16 W32) = 434+primOpTag (VecBroadcastOp WordVec 8 W64) = 435+primOpTag (VecBroadcastOp FloatVec 4 W32) = 436+primOpTag (VecBroadcastOp FloatVec 2 W64) = 437+primOpTag (VecBroadcastOp FloatVec 8 W32) = 438+primOpTag (VecBroadcastOp FloatVec 4 W64) = 439+primOpTag (VecBroadcastOp FloatVec 16 W32) = 440+primOpTag (VecBroadcastOp FloatVec 8 W64) = 441+primOpTag (VecPackOp IntVec 16 W8) = 442+primOpTag (VecPackOp IntVec 8 W16) = 443+primOpTag (VecPackOp IntVec 4 W32) = 444+primOpTag (VecPackOp IntVec 2 W64) = 445+primOpTag (VecPackOp IntVec 32 W8) = 446+primOpTag (VecPackOp IntVec 16 W16) = 447+primOpTag (VecPackOp IntVec 8 W32) = 448+primOpTag (VecPackOp IntVec 4 W64) = 449+primOpTag (VecPackOp IntVec 64 W8) = 450+primOpTag (VecPackOp IntVec 32 W16) = 451+primOpTag (VecPackOp IntVec 16 W32) = 452+primOpTag (VecPackOp IntVec 8 W64) = 453+primOpTag (VecPackOp WordVec 16 W8) = 454+primOpTag (VecPackOp WordVec 8 W16) = 455+primOpTag (VecPackOp WordVec 4 W32) = 456+primOpTag (VecPackOp WordVec 2 W64) = 457+primOpTag (VecPackOp WordVec 32 W8) = 458+primOpTag (VecPackOp WordVec 16 W16) = 459+primOpTag (VecPackOp WordVec 8 W32) = 460+primOpTag (VecPackOp WordVec 4 W64) = 461+primOpTag (VecPackOp WordVec 64 W8) = 462+primOpTag (VecPackOp WordVec 32 W16) = 463+primOpTag (VecPackOp WordVec 16 W32) = 464+primOpTag (VecPackOp WordVec 8 W64) = 465+primOpTag (VecPackOp FloatVec 4 W32) = 466+primOpTag (VecPackOp FloatVec 2 W64) = 467+primOpTag (VecPackOp FloatVec 8 W32) = 468+primOpTag (VecPackOp FloatVec 4 W64) = 469+primOpTag (VecPackOp FloatVec 16 W32) = 470+primOpTag (VecPackOp FloatVec 8 W64) = 471+primOpTag (VecUnpackOp IntVec 16 W8) = 472+primOpTag (VecUnpackOp IntVec 8 W16) = 473+primOpTag (VecUnpackOp IntVec 4 W32) = 474+primOpTag (VecUnpackOp IntVec 2 W64) = 475+primOpTag (VecUnpackOp IntVec 32 W8) = 476+primOpTag (VecUnpackOp IntVec 16 W16) = 477+primOpTag (VecUnpackOp IntVec 8 W32) = 478+primOpTag (VecUnpackOp IntVec 4 W64) = 479+primOpTag (VecUnpackOp IntVec 64 W8) = 480+primOpTag (VecUnpackOp IntVec 32 W16) = 481+primOpTag (VecUnpackOp IntVec 16 W32) = 482+primOpTag (VecUnpackOp IntVec 8 W64) = 483+primOpTag (VecUnpackOp WordVec 16 W8) = 484+primOpTag (VecUnpackOp WordVec 8 W16) = 485+primOpTag (VecUnpackOp WordVec 4 W32) = 486+primOpTag (VecUnpackOp WordVec 2 W64) = 487+primOpTag (VecUnpackOp WordVec 32 W8) = 488+primOpTag (VecUnpackOp WordVec 16 W16) = 489+primOpTag (VecUnpackOp WordVec 8 W32) = 490+primOpTag (VecUnpackOp WordVec 4 W64) = 491+primOpTag (VecUnpackOp WordVec 64 W8) = 492+primOpTag (VecUnpackOp WordVec 32 W16) = 493+primOpTag (VecUnpackOp WordVec 16 W32) = 494+primOpTag (VecUnpackOp WordVec 8 W64) = 495+primOpTag (VecUnpackOp FloatVec 4 W32) = 496+primOpTag (VecUnpackOp FloatVec 2 W64) = 497+primOpTag (VecUnpackOp FloatVec 8 W32) = 498+primOpTag (VecUnpackOp FloatVec 4 W64) = 499+primOpTag (VecUnpackOp FloatVec 16 W32) = 500+primOpTag (VecUnpackOp FloatVec 8 W64) = 501+primOpTag (VecInsertOp IntVec 16 W8) = 502+primOpTag (VecInsertOp IntVec 8 W16) = 503+primOpTag (VecInsertOp IntVec 4 W32) = 504+primOpTag (VecInsertOp IntVec 2 W64) = 505+primOpTag (VecInsertOp IntVec 32 W8) = 506+primOpTag (VecInsertOp IntVec 16 W16) = 507+primOpTag (VecInsertOp IntVec 8 W32) = 508+primOpTag (VecInsertOp IntVec 4 W64) = 509+primOpTag (VecInsertOp IntVec 64 W8) = 510+primOpTag (VecInsertOp IntVec 32 W16) = 511+primOpTag (VecInsertOp IntVec 16 W32) = 512+primOpTag (VecInsertOp IntVec 8 W64) = 513+primOpTag (VecInsertOp WordVec 16 W8) = 514+primOpTag (VecInsertOp WordVec 8 W16) = 515+primOpTag (VecInsertOp WordVec 4 W32) = 516+primOpTag (VecInsertOp WordVec 2 W64) = 517+primOpTag (VecInsertOp WordVec 32 W8) = 518+primOpTag (VecInsertOp WordVec 16 W16) = 519+primOpTag (VecInsertOp WordVec 8 W32) = 520+primOpTag (VecInsertOp WordVec 4 W64) = 521+primOpTag (VecInsertOp WordVec 64 W8) = 522+primOpTag (VecInsertOp WordVec 32 W16) = 523+primOpTag (VecInsertOp WordVec 16 W32) = 524+primOpTag (VecInsertOp WordVec 8 W64) = 525+primOpTag (VecInsertOp FloatVec 4 W32) = 526+primOpTag (VecInsertOp FloatVec 2 W64) = 527+primOpTag (VecInsertOp FloatVec 8 W32) = 528+primOpTag (VecInsertOp FloatVec 4 W64) = 529+primOpTag (VecInsertOp FloatVec 16 W32) = 530+primOpTag (VecInsertOp FloatVec 8 W64) = 531+primOpTag (VecAddOp IntVec 16 W8) = 532+primOpTag (VecAddOp IntVec 8 W16) = 533+primOpTag (VecAddOp IntVec 4 W32) = 534+primOpTag (VecAddOp IntVec 2 W64) = 535+primOpTag (VecAddOp IntVec 32 W8) = 536+primOpTag (VecAddOp IntVec 16 W16) = 537+primOpTag (VecAddOp IntVec 8 W32) = 538+primOpTag (VecAddOp IntVec 4 W64) = 539+primOpTag (VecAddOp IntVec 64 W8) = 540+primOpTag (VecAddOp IntVec 32 W16) = 541+primOpTag (VecAddOp IntVec 16 W32) = 542+primOpTag (VecAddOp IntVec 8 W64) = 543+primOpTag (VecAddOp WordVec 16 W8) = 544+primOpTag (VecAddOp WordVec 8 W16) = 545+primOpTag (VecAddOp WordVec 4 W32) = 546+primOpTag (VecAddOp WordVec 2 W64) = 547+primOpTag (VecAddOp WordVec 32 W8) = 548+primOpTag (VecAddOp WordVec 16 W16) = 549+primOpTag (VecAddOp WordVec 8 W32) = 550+primOpTag (VecAddOp WordVec 4 W64) = 551+primOpTag (VecAddOp WordVec 64 W8) = 552+primOpTag (VecAddOp WordVec 32 W16) = 553+primOpTag (VecAddOp WordVec 16 W32) = 554+primOpTag (VecAddOp WordVec 8 W64) = 555+primOpTag (VecAddOp FloatVec 4 W32) = 556+primOpTag (VecAddOp FloatVec 2 W64) = 557+primOpTag (VecAddOp FloatVec 8 W32) = 558+primOpTag (VecAddOp FloatVec 4 W64) = 559+primOpTag (VecAddOp FloatVec 16 W32) = 560+primOpTag (VecAddOp FloatVec 8 W64) = 561+primOpTag (VecSubOp IntVec 16 W8) = 562+primOpTag (VecSubOp IntVec 8 W16) = 563+primOpTag (VecSubOp IntVec 4 W32) = 564+primOpTag (VecSubOp IntVec 2 W64) = 565+primOpTag (VecSubOp IntVec 32 W8) = 566+primOpTag (VecSubOp IntVec 16 W16) = 567+primOpTag (VecSubOp IntVec 8 W32) = 568+primOpTag (VecSubOp IntVec 4 W64) = 569+primOpTag (VecSubOp IntVec 64 W8) = 570+primOpTag (VecSubOp IntVec 32 W16) = 571+primOpTag (VecSubOp IntVec 16 W32) = 572+primOpTag (VecSubOp IntVec 8 W64) = 573+primOpTag (VecSubOp WordVec 16 W8) = 574+primOpTag (VecSubOp WordVec 8 W16) = 575+primOpTag (VecSubOp WordVec 4 W32) = 576+primOpTag (VecSubOp WordVec 2 W64) = 577+primOpTag (VecSubOp WordVec 32 W8) = 578+primOpTag (VecSubOp WordVec 16 W16) = 579+primOpTag (VecSubOp WordVec 8 W32) = 580+primOpTag (VecSubOp WordVec 4 W64) = 581+primOpTag (VecSubOp WordVec 64 W8) = 582+primOpTag (VecSubOp WordVec 32 W16) = 583+primOpTag (VecSubOp WordVec 16 W32) = 584+primOpTag (VecSubOp WordVec 8 W64) = 585+primOpTag (VecSubOp FloatVec 4 W32) = 586+primOpTag (VecSubOp FloatVec 2 W64) = 587+primOpTag (VecSubOp FloatVec 8 W32) = 588+primOpTag (VecSubOp FloatVec 4 W64) = 589+primOpTag (VecSubOp FloatVec 16 W32) = 590+primOpTag (VecSubOp FloatVec 8 W64) = 591+primOpTag (VecMulOp IntVec 16 W8) = 592+primOpTag (VecMulOp IntVec 8 W16) = 593+primOpTag (VecMulOp IntVec 4 W32) = 594+primOpTag (VecMulOp IntVec 2 W64) = 595+primOpTag (VecMulOp IntVec 32 W8) = 596+primOpTag (VecMulOp IntVec 16 W16) = 597+primOpTag (VecMulOp IntVec 8 W32) = 598+primOpTag (VecMulOp IntVec 4 W64) = 599+primOpTag (VecMulOp IntVec 64 W8) = 600+primOpTag (VecMulOp IntVec 32 W16) = 601+primOpTag (VecMulOp IntVec 16 W32) = 602+primOpTag (VecMulOp IntVec 8 W64) = 603+primOpTag (VecMulOp WordVec 16 W8) = 604+primOpTag (VecMulOp WordVec 8 W16) = 605+primOpTag (VecMulOp WordVec 4 W32) = 606+primOpTag (VecMulOp WordVec 2 W64) = 607+primOpTag (VecMulOp WordVec 32 W8) = 608+primOpTag (VecMulOp WordVec 16 W16) = 609+primOpTag (VecMulOp WordVec 8 W32) = 610+primOpTag (VecMulOp WordVec 4 W64) = 611+primOpTag (VecMulOp WordVec 64 W8) = 612+primOpTag (VecMulOp WordVec 32 W16) = 613+primOpTag (VecMulOp WordVec 16 W32) = 614+primOpTag (VecMulOp WordVec 8 W64) = 615+primOpTag (VecMulOp FloatVec 4 W32) = 616+primOpTag (VecMulOp FloatVec 2 W64) = 617+primOpTag (VecMulOp FloatVec 8 W32) = 618+primOpTag (VecMulOp FloatVec 4 W64) = 619+primOpTag (VecMulOp FloatVec 16 W32) = 620+primOpTag (VecMulOp FloatVec 8 W64) = 621+primOpTag (VecDivOp FloatVec 4 W32) = 622+primOpTag (VecDivOp FloatVec 2 W64) = 623+primOpTag (VecDivOp FloatVec 8 W32) = 624+primOpTag (VecDivOp FloatVec 4 W64) = 625+primOpTag (VecDivOp FloatVec 16 W32) = 626+primOpTag (VecDivOp FloatVec 8 W64) = 627+primOpTag (VecQuotOp IntVec 16 W8) = 628+primOpTag (VecQuotOp IntVec 8 W16) = 629+primOpTag (VecQuotOp IntVec 4 W32) = 630+primOpTag (VecQuotOp IntVec 2 W64) = 631+primOpTag (VecQuotOp IntVec 32 W8) = 632+primOpTag (VecQuotOp IntVec 16 W16) = 633+primOpTag (VecQuotOp IntVec 8 W32) = 634+primOpTag (VecQuotOp IntVec 4 W64) = 635+primOpTag (VecQuotOp IntVec 64 W8) = 636+primOpTag (VecQuotOp IntVec 32 W16) = 637+primOpTag (VecQuotOp IntVec 16 W32) = 638+primOpTag (VecQuotOp IntVec 8 W64) = 639+primOpTag (VecQuotOp WordVec 16 W8) = 640+primOpTag (VecQuotOp WordVec 8 W16) = 641+primOpTag (VecQuotOp WordVec 4 W32) = 642+primOpTag (VecQuotOp WordVec 2 W64) = 643+primOpTag (VecQuotOp WordVec 32 W8) = 644+primOpTag (VecQuotOp WordVec 16 W16) = 645+primOpTag (VecQuotOp WordVec 8 W32) = 646+primOpTag (VecQuotOp WordVec 4 W64) = 647+primOpTag (VecQuotOp WordVec 64 W8) = 648+primOpTag (VecQuotOp WordVec 32 W16) = 649+primOpTag (VecQuotOp WordVec 16 W32) = 650+primOpTag (VecQuotOp WordVec 8 W64) = 651+primOpTag (VecRemOp IntVec 16 W8) = 652+primOpTag (VecRemOp IntVec 8 W16) = 653+primOpTag (VecRemOp IntVec 4 W32) = 654+primOpTag (VecRemOp IntVec 2 W64) = 655+primOpTag (VecRemOp IntVec 32 W8) = 656+primOpTag (VecRemOp IntVec 16 W16) = 657+primOpTag (VecRemOp IntVec 8 W32) = 658+primOpTag (VecRemOp IntVec 4 W64) = 659+primOpTag (VecRemOp IntVec 64 W8) = 660+primOpTag (VecRemOp IntVec 32 W16) = 661+primOpTag (VecRemOp IntVec 16 W32) = 662+primOpTag (VecRemOp IntVec 8 W64) = 663+primOpTag (VecRemOp WordVec 16 W8) = 664+primOpTag (VecRemOp WordVec 8 W16) = 665+primOpTag (VecRemOp WordVec 4 W32) = 666+primOpTag (VecRemOp WordVec 2 W64) = 667+primOpTag (VecRemOp WordVec 32 W8) = 668+primOpTag (VecRemOp WordVec 16 W16) = 669+primOpTag (VecRemOp WordVec 8 W32) = 670+primOpTag (VecRemOp WordVec 4 W64) = 671+primOpTag (VecRemOp WordVec 64 W8) = 672+primOpTag (VecRemOp WordVec 32 W16) = 673+primOpTag (VecRemOp WordVec 16 W32) = 674+primOpTag (VecRemOp WordVec 8 W64) = 675+primOpTag (VecNegOp IntVec 16 W8) = 676+primOpTag (VecNegOp IntVec 8 W16) = 677+primOpTag (VecNegOp IntVec 4 W32) = 678+primOpTag (VecNegOp IntVec 2 W64) = 679+primOpTag (VecNegOp IntVec 32 W8) = 680+primOpTag (VecNegOp IntVec 16 W16) = 681+primOpTag (VecNegOp IntVec 8 W32) = 682+primOpTag (VecNegOp IntVec 4 W64) = 683+primOpTag (VecNegOp IntVec 64 W8) = 684+primOpTag (VecNegOp IntVec 32 W16) = 685+primOpTag (VecNegOp IntVec 16 W32) = 686+primOpTag (VecNegOp IntVec 8 W64) = 687+primOpTag (VecNegOp FloatVec 4 W32) = 688+primOpTag (VecNegOp FloatVec 2 W64) = 689+primOpTag (VecNegOp FloatVec 8 W32) = 690+primOpTag (VecNegOp FloatVec 4 W64) = 691+primOpTag (VecNegOp FloatVec 16 W32) = 692+primOpTag (VecNegOp FloatVec 8 W64) = 693+primOpTag (VecIndexByteArrayOp IntVec 16 W8) = 694+primOpTag (VecIndexByteArrayOp IntVec 8 W16) = 695+primOpTag (VecIndexByteArrayOp IntVec 4 W32) = 696+primOpTag (VecIndexByteArrayOp IntVec 2 W64) = 697+primOpTag (VecIndexByteArrayOp IntVec 32 W8) = 698+primOpTag (VecIndexByteArrayOp IntVec 16 W16) = 699+primOpTag (VecIndexByteArrayOp IntVec 8 W32) = 700+primOpTag (VecIndexByteArrayOp IntVec 4 W64) = 701+primOpTag (VecIndexByteArrayOp IntVec 64 W8) = 702+primOpTag (VecIndexByteArrayOp IntVec 32 W16) = 703+primOpTag (VecIndexByteArrayOp IntVec 16 W32) = 704+primOpTag (VecIndexByteArrayOp IntVec 8 W64) = 705+primOpTag (VecIndexByteArrayOp WordVec 16 W8) = 706+primOpTag (VecIndexByteArrayOp WordVec 8 W16) = 707+primOpTag (VecIndexByteArrayOp WordVec 4 W32) = 708+primOpTag (VecIndexByteArrayOp WordVec 2 W64) = 709+primOpTag (VecIndexByteArrayOp WordVec 32 W8) = 710+primOpTag (VecIndexByteArrayOp WordVec 16 W16) = 711+primOpTag (VecIndexByteArrayOp WordVec 8 W32) = 712+primOpTag (VecIndexByteArrayOp WordVec 4 W64) = 713+primOpTag (VecIndexByteArrayOp WordVec 64 W8) = 714+primOpTag (VecIndexByteArrayOp WordVec 32 W16) = 715+primOpTag (VecIndexByteArrayOp WordVec 16 W32) = 716+primOpTag (VecIndexByteArrayOp WordVec 8 W64) = 717+primOpTag (VecIndexByteArrayOp FloatVec 4 W32) = 718+primOpTag (VecIndexByteArrayOp FloatVec 2 W64) = 719+primOpTag (VecIndexByteArrayOp FloatVec 8 W32) = 720+primOpTag (VecIndexByteArrayOp FloatVec 4 W64) = 721+primOpTag (VecIndexByteArrayOp FloatVec 16 W32) = 722+primOpTag (VecIndexByteArrayOp FloatVec 8 W64) = 723+primOpTag (VecReadByteArrayOp IntVec 16 W8) = 724+primOpTag (VecReadByteArrayOp IntVec 8 W16) = 725+primOpTag (VecReadByteArrayOp IntVec 4 W32) = 726+primOpTag (VecReadByteArrayOp IntVec 2 W64) = 727+primOpTag (VecReadByteArrayOp IntVec 32 W8) = 728+primOpTag (VecReadByteArrayOp IntVec 16 W16) = 729+primOpTag (VecReadByteArrayOp IntVec 8 W32) = 730+primOpTag (VecReadByteArrayOp IntVec 4 W64) = 731+primOpTag (VecReadByteArrayOp IntVec 64 W8) = 732+primOpTag (VecReadByteArrayOp IntVec 32 W16) = 733+primOpTag (VecReadByteArrayOp IntVec 16 W32) = 734+primOpTag (VecReadByteArrayOp IntVec 8 W64) = 735+primOpTag (VecReadByteArrayOp WordVec 16 W8) = 736+primOpTag (VecReadByteArrayOp WordVec 8 W16) = 737+primOpTag (VecReadByteArrayOp WordVec 4 W32) = 738+primOpTag (VecReadByteArrayOp WordVec 2 W64) = 739+primOpTag (VecReadByteArrayOp WordVec 32 W8) = 740+primOpTag (VecReadByteArrayOp WordVec 16 W16) = 741+primOpTag (VecReadByteArrayOp WordVec 8 W32) = 742+primOpTag (VecReadByteArrayOp WordVec 4 W64) = 743+primOpTag (VecReadByteArrayOp WordVec 64 W8) = 744+primOpTag (VecReadByteArrayOp WordVec 32 W16) = 745+primOpTag (VecReadByteArrayOp WordVec 16 W32) = 746+primOpTag (VecReadByteArrayOp WordVec 8 W64) = 747+primOpTag (VecReadByteArrayOp FloatVec 4 W32) = 748+primOpTag (VecReadByteArrayOp FloatVec 2 W64) = 749+primOpTag (VecReadByteArrayOp FloatVec 8 W32) = 750+primOpTag (VecReadByteArrayOp FloatVec 4 W64) = 751+primOpTag (VecReadByteArrayOp FloatVec 16 W32) = 752+primOpTag (VecReadByteArrayOp FloatVec 8 W64) = 753+primOpTag (VecWriteByteArrayOp IntVec 16 W8) = 754+primOpTag (VecWriteByteArrayOp IntVec 8 W16) = 755+primOpTag (VecWriteByteArrayOp IntVec 4 W32) = 756+primOpTag (VecWriteByteArrayOp IntVec 2 W64) = 757+primOpTag (VecWriteByteArrayOp IntVec 32 W8) = 758+primOpTag (VecWriteByteArrayOp IntVec 16 W16) = 759+primOpTag (VecWriteByteArrayOp IntVec 8 W32) = 760+primOpTag (VecWriteByteArrayOp IntVec 4 W64) = 761+primOpTag (VecWriteByteArrayOp IntVec 64 W8) = 762+primOpTag (VecWriteByteArrayOp IntVec 32 W16) = 763+primOpTag (VecWriteByteArrayOp IntVec 16 W32) = 764+primOpTag (VecWriteByteArrayOp IntVec 8 W64) = 765+primOpTag (VecWriteByteArrayOp WordVec 16 W8) = 766+primOpTag (VecWriteByteArrayOp WordVec 8 W16) = 767+primOpTag (VecWriteByteArrayOp WordVec 4 W32) = 768+primOpTag (VecWriteByteArrayOp WordVec 2 W64) = 769+primOpTag (VecWriteByteArrayOp WordVec 32 W8) = 770+primOpTag (VecWriteByteArrayOp WordVec 16 W16) = 771+primOpTag (VecWriteByteArrayOp WordVec 8 W32) = 772+primOpTag (VecWriteByteArrayOp WordVec 4 W64) = 773+primOpTag (VecWriteByteArrayOp WordVec 64 W8) = 774+primOpTag (VecWriteByteArrayOp WordVec 32 W16) = 775+primOpTag (VecWriteByteArrayOp WordVec 16 W32) = 776+primOpTag (VecWriteByteArrayOp WordVec 8 W64) = 777+primOpTag (VecWriteByteArrayOp FloatVec 4 W32) = 778+primOpTag (VecWriteByteArrayOp FloatVec 2 W64) = 779+primOpTag (VecWriteByteArrayOp FloatVec 8 W32) = 780+primOpTag (VecWriteByteArrayOp FloatVec 4 W64) = 781+primOpTag (VecWriteByteArrayOp FloatVec 16 W32) = 782+primOpTag (VecWriteByteArrayOp FloatVec 8 W64) = 783+primOpTag (VecIndexOffAddrOp IntVec 16 W8) = 784+primOpTag (VecIndexOffAddrOp IntVec 8 W16) = 785+primOpTag (VecIndexOffAddrOp IntVec 4 W32) = 786+primOpTag (VecIndexOffAddrOp IntVec 2 W64) = 787+primOpTag (VecIndexOffAddrOp IntVec 32 W8) = 788+primOpTag (VecIndexOffAddrOp IntVec 16 W16) = 789+primOpTag (VecIndexOffAddrOp IntVec 8 W32) = 790+primOpTag (VecIndexOffAddrOp IntVec 4 W64) = 791+primOpTag (VecIndexOffAddrOp IntVec 64 W8) = 792+primOpTag (VecIndexOffAddrOp IntVec 32 W16) = 793+primOpTag (VecIndexOffAddrOp IntVec 16 W32) = 794+primOpTag (VecIndexOffAddrOp IntVec 8 W64) = 795+primOpTag (VecIndexOffAddrOp WordVec 16 W8) = 796+primOpTag (VecIndexOffAddrOp WordVec 8 W16) = 797+primOpTag (VecIndexOffAddrOp WordVec 4 W32) = 798+primOpTag (VecIndexOffAddrOp WordVec 2 W64) = 799+primOpTag (VecIndexOffAddrOp WordVec 32 W8) = 800+primOpTag (VecIndexOffAddrOp WordVec 16 W16) = 801+primOpTag (VecIndexOffAddrOp WordVec 8 W32) = 802+primOpTag (VecIndexOffAddrOp WordVec 4 W64) = 803+primOpTag (VecIndexOffAddrOp WordVec 64 W8) = 804+primOpTag (VecIndexOffAddrOp WordVec 32 W16) = 805+primOpTag (VecIndexOffAddrOp WordVec 16 W32) = 806+primOpTag (VecIndexOffAddrOp WordVec 8 W64) = 807+primOpTag (VecIndexOffAddrOp FloatVec 4 W32) = 808+primOpTag (VecIndexOffAddrOp FloatVec 2 W64) = 809+primOpTag (VecIndexOffAddrOp FloatVec 8 W32) = 810+primOpTag (VecIndexOffAddrOp FloatVec 4 W64) = 811+primOpTag (VecIndexOffAddrOp FloatVec 16 W32) = 812+primOpTag (VecIndexOffAddrOp FloatVec 8 W64) = 813+primOpTag (VecReadOffAddrOp IntVec 16 W8) = 814+primOpTag (VecReadOffAddrOp IntVec 8 W16) = 815+primOpTag (VecReadOffAddrOp IntVec 4 W32) = 816+primOpTag (VecReadOffAddrOp IntVec 2 W64) = 817+primOpTag (VecReadOffAddrOp IntVec 32 W8) = 818+primOpTag (VecReadOffAddrOp IntVec 16 W16) = 819+primOpTag (VecReadOffAddrOp IntVec 8 W32) = 820+primOpTag (VecReadOffAddrOp IntVec 4 W64) = 821+primOpTag (VecReadOffAddrOp IntVec 64 W8) = 822+primOpTag (VecReadOffAddrOp IntVec 32 W16) = 823+primOpTag (VecReadOffAddrOp IntVec 16 W32) = 824+primOpTag (VecReadOffAddrOp IntVec 8 W64) = 825+primOpTag (VecReadOffAddrOp WordVec 16 W8) = 826+primOpTag (VecReadOffAddrOp WordVec 8 W16) = 827+primOpTag (VecReadOffAddrOp WordVec 4 W32) = 828+primOpTag (VecReadOffAddrOp WordVec 2 W64) = 829+primOpTag (VecReadOffAddrOp WordVec 32 W8) = 830+primOpTag (VecReadOffAddrOp WordVec 16 W16) = 831+primOpTag (VecReadOffAddrOp WordVec 8 W32) = 832+primOpTag (VecReadOffAddrOp WordVec 4 W64) = 833+primOpTag (VecReadOffAddrOp WordVec 64 W8) = 834+primOpTag (VecReadOffAddrOp WordVec 32 W16) = 835+primOpTag (VecReadOffAddrOp WordVec 16 W32) = 836+primOpTag (VecReadOffAddrOp WordVec 8 W64) = 837+primOpTag (VecReadOffAddrOp FloatVec 4 W32) = 838+primOpTag (VecReadOffAddrOp FloatVec 2 W64) = 839+primOpTag (VecReadOffAddrOp FloatVec 8 W32) = 840+primOpTag (VecReadOffAddrOp FloatVec 4 W64) = 841+primOpTag (VecReadOffAddrOp FloatVec 16 W32) = 842+primOpTag (VecReadOffAddrOp FloatVec 8 W64) = 843+primOpTag (VecWriteOffAddrOp IntVec 16 W8) = 844+primOpTag (VecWriteOffAddrOp IntVec 8 W16) = 845+primOpTag (VecWriteOffAddrOp IntVec 4 W32) = 846+primOpTag (VecWriteOffAddrOp IntVec 2 W64) = 847+primOpTag (VecWriteOffAddrOp IntVec 32 W8) = 848+primOpTag (VecWriteOffAddrOp IntVec 16 W16) = 849+primOpTag (VecWriteOffAddrOp IntVec 8 W32) = 850+primOpTag (VecWriteOffAddrOp IntVec 4 W64) = 851+primOpTag (VecWriteOffAddrOp IntVec 64 W8) = 852+primOpTag (VecWriteOffAddrOp IntVec 32 W16) = 853+primOpTag (VecWriteOffAddrOp IntVec 16 W32) = 854+primOpTag (VecWriteOffAddrOp IntVec 8 W64) = 855+primOpTag (VecWriteOffAddrOp WordVec 16 W8) = 856+primOpTag (VecWriteOffAddrOp WordVec 8 W16) = 857+primOpTag (VecWriteOffAddrOp WordVec 4 W32) = 858+primOpTag (VecWriteOffAddrOp WordVec 2 W64) = 859+primOpTag (VecWriteOffAddrOp WordVec 32 W8) = 860+primOpTag (VecWriteOffAddrOp WordVec 16 W16) = 861+primOpTag (VecWriteOffAddrOp WordVec 8 W32) = 862+primOpTag (VecWriteOffAddrOp WordVec 4 W64) = 863+primOpTag (VecWriteOffAddrOp WordVec 64 W8) = 864+primOpTag (VecWriteOffAddrOp WordVec 32 W16) = 865+primOpTag (VecWriteOffAddrOp WordVec 16 W32) = 866+primOpTag (VecWriteOffAddrOp WordVec 8 W64) = 867+primOpTag (VecWriteOffAddrOp FloatVec 4 W32) = 868+primOpTag (VecWriteOffAddrOp FloatVec 2 W64) = 869+primOpTag (VecWriteOffAddrOp FloatVec 8 W32) = 870+primOpTag (VecWriteOffAddrOp FloatVec 4 W64) = 871+primOpTag (VecWriteOffAddrOp FloatVec 16 W32) = 872+primOpTag (VecWriteOffAddrOp FloatVec 8 W64) = 873+primOpTag (VecIndexScalarByteArrayOp IntVec 16 W8) = 874+primOpTag (VecIndexScalarByteArrayOp IntVec 8 W16) = 875+primOpTag (VecIndexScalarByteArrayOp IntVec 4 W32) = 876+primOpTag (VecIndexScalarByteArrayOp IntVec 2 W64) = 877+primOpTag (VecIndexScalarByteArrayOp IntVec 32 W8) = 878+primOpTag (VecIndexScalarByteArrayOp IntVec 16 W16) = 879+primOpTag (VecIndexScalarByteArrayOp IntVec 8 W32) = 880+primOpTag (VecIndexScalarByteArrayOp IntVec 4 W64) = 881+primOpTag (VecIndexScalarByteArrayOp IntVec 64 W8) = 882+primOpTag (VecIndexScalarByteArrayOp IntVec 32 W16) = 883+primOpTag (VecIndexScalarByteArrayOp IntVec 16 W32) = 884+primOpTag (VecIndexScalarByteArrayOp IntVec 8 W64) = 885+primOpTag (VecIndexScalarByteArrayOp WordVec 16 W8) = 886+primOpTag (VecIndexScalarByteArrayOp WordVec 8 W16) = 887+primOpTag (VecIndexScalarByteArrayOp WordVec 4 W32) = 888+primOpTag (VecIndexScalarByteArrayOp WordVec 2 W64) = 889+primOpTag (VecIndexScalarByteArrayOp WordVec 32 W8) = 890+primOpTag (VecIndexScalarByteArrayOp WordVec 16 W16) = 891+primOpTag (VecIndexScalarByteArrayOp WordVec 8 W32) = 892+primOpTag (VecIndexScalarByteArrayOp WordVec 4 W64) = 893+primOpTag (VecIndexScalarByteArrayOp WordVec 64 W8) = 894+primOpTag (VecIndexScalarByteArrayOp WordVec 32 W16) = 895+primOpTag (VecIndexScalarByteArrayOp WordVec 16 W32) = 896+primOpTag (VecIndexScalarByteArrayOp WordVec 8 W64) = 897+primOpTag (VecIndexScalarByteArrayOp FloatVec 4 W32) = 898+primOpTag (VecIndexScalarByteArrayOp FloatVec 2 W64) = 899+primOpTag (VecIndexScalarByteArrayOp FloatVec 8 W32) = 900+primOpTag (VecIndexScalarByteArrayOp FloatVec 4 W64) = 901+primOpTag (VecIndexScalarByteArrayOp FloatVec 16 W32) = 902+primOpTag (VecIndexScalarByteArrayOp FloatVec 8 W64) = 903+primOpTag (VecReadScalarByteArrayOp IntVec 16 W8) = 904+primOpTag (VecReadScalarByteArrayOp IntVec 8 W16) = 905+primOpTag (VecReadScalarByteArrayOp IntVec 4 W32) = 906+primOpTag (VecReadScalarByteArrayOp IntVec 2 W64) = 907+primOpTag (VecReadScalarByteArrayOp IntVec 32 W8) = 908+primOpTag (VecReadScalarByteArrayOp IntVec 16 W16) = 909+primOpTag (VecReadScalarByteArrayOp IntVec 8 W32) = 910+primOpTag (VecReadScalarByteArrayOp IntVec 4 W64) = 911+primOpTag (VecReadScalarByteArrayOp IntVec 64 W8) = 912+primOpTag (VecReadScalarByteArrayOp IntVec 32 W16) = 913+primOpTag (VecReadScalarByteArrayOp IntVec 16 W32) = 914+primOpTag (VecReadScalarByteArrayOp IntVec 8 W64) = 915+primOpTag (VecReadScalarByteArrayOp WordVec 16 W8) = 916+primOpTag (VecReadScalarByteArrayOp WordVec 8 W16) = 917+primOpTag (VecReadScalarByteArrayOp WordVec 4 W32) = 918+primOpTag (VecReadScalarByteArrayOp WordVec 2 W64) = 919+primOpTag (VecReadScalarByteArrayOp WordVec 32 W8) = 920+primOpTag (VecReadScalarByteArrayOp WordVec 16 W16) = 921+primOpTag (VecReadScalarByteArrayOp WordVec 8 W32) = 922+primOpTag (VecReadScalarByteArrayOp WordVec 4 W64) = 923+primOpTag (VecReadScalarByteArrayOp WordVec 64 W8) = 924+primOpTag (VecReadScalarByteArrayOp WordVec 32 W16) = 925+primOpTag (VecReadScalarByteArrayOp WordVec 16 W32) = 926+primOpTag (VecReadScalarByteArrayOp WordVec 8 W64) = 927+primOpTag (VecReadScalarByteArrayOp FloatVec 4 W32) = 928+primOpTag (VecReadScalarByteArrayOp FloatVec 2 W64) = 929+primOpTag (VecReadScalarByteArrayOp FloatVec 8 W32) = 930+primOpTag (VecReadScalarByteArrayOp FloatVec 4 W64) = 931+primOpTag (VecReadScalarByteArrayOp FloatVec 16 W32) = 932+primOpTag (VecReadScalarByteArrayOp FloatVec 8 W64) = 933+primOpTag (VecWriteScalarByteArrayOp IntVec 16 W8) = 934+primOpTag (VecWriteScalarByteArrayOp IntVec 8 W16) = 935+primOpTag (VecWriteScalarByteArrayOp IntVec 4 W32) = 936+primOpTag (VecWriteScalarByteArrayOp IntVec 2 W64) = 937+primOpTag (VecWriteScalarByteArrayOp IntVec 32 W8) = 938+primOpTag (VecWriteScalarByteArrayOp IntVec 16 W16) = 939+primOpTag (VecWriteScalarByteArrayOp IntVec 8 W32) = 940+primOpTag (VecWriteScalarByteArrayOp IntVec 4 W64) = 941+primOpTag (VecWriteScalarByteArrayOp IntVec 64 W8) = 942+primOpTag (VecWriteScalarByteArrayOp IntVec 32 W16) = 943+primOpTag (VecWriteScalarByteArrayOp IntVec 16 W32) = 944+primOpTag (VecWriteScalarByteArrayOp IntVec 8 W64) = 945+primOpTag (VecWriteScalarByteArrayOp WordVec 16 W8) = 946+primOpTag (VecWriteScalarByteArrayOp WordVec 8 W16) = 947+primOpTag (VecWriteScalarByteArrayOp WordVec 4 W32) = 948+primOpTag (VecWriteScalarByteArrayOp WordVec 2 W64) = 949+primOpTag (VecWriteScalarByteArrayOp WordVec 32 W8) = 950+primOpTag (VecWriteScalarByteArrayOp WordVec 16 W16) = 951+primOpTag (VecWriteScalarByteArrayOp WordVec 8 W32) = 952+primOpTag (VecWriteScalarByteArrayOp WordVec 4 W64) = 953+primOpTag (VecWriteScalarByteArrayOp WordVec 64 W8) = 954+primOpTag (VecWriteScalarByteArrayOp WordVec 32 W16) = 955+primOpTag (VecWriteScalarByteArrayOp WordVec 16 W32) = 956+primOpTag (VecWriteScalarByteArrayOp WordVec 8 W64) = 957+primOpTag (VecWriteScalarByteArrayOp FloatVec 4 W32) = 958+primOpTag (VecWriteScalarByteArrayOp FloatVec 2 W64) = 959+primOpTag (VecWriteScalarByteArrayOp FloatVec 8 W32) = 960+primOpTag (VecWriteScalarByteArrayOp FloatVec 4 W64) = 961+primOpTag (VecWriteScalarByteArrayOp FloatVec 16 W32) = 962+primOpTag (VecWriteScalarByteArrayOp FloatVec 8 W64) = 963+primOpTag (VecIndexScalarOffAddrOp IntVec 16 W8) = 964+primOpTag (VecIndexScalarOffAddrOp IntVec 8 W16) = 965+primOpTag (VecIndexScalarOffAddrOp IntVec 4 W32) = 966+primOpTag (VecIndexScalarOffAddrOp IntVec 2 W64) = 967+primOpTag (VecIndexScalarOffAddrOp IntVec 32 W8) = 968+primOpTag (VecIndexScalarOffAddrOp IntVec 16 W16) = 969+primOpTag (VecIndexScalarOffAddrOp IntVec 8 W32) = 970+primOpTag (VecIndexScalarOffAddrOp IntVec 4 W64) = 971+primOpTag (VecIndexScalarOffAddrOp IntVec 64 W8) = 972+primOpTag (VecIndexScalarOffAddrOp IntVec 32 W16) = 973+primOpTag (VecIndexScalarOffAddrOp IntVec 16 W32) = 974+primOpTag (VecIndexScalarOffAddrOp IntVec 8 W64) = 975+primOpTag (VecIndexScalarOffAddrOp WordVec 16 W8) = 976+primOpTag (VecIndexScalarOffAddrOp WordVec 8 W16) = 977+primOpTag (VecIndexScalarOffAddrOp WordVec 4 W32) = 978+primOpTag (VecIndexScalarOffAddrOp WordVec 2 W64) = 979+primOpTag (VecIndexScalarOffAddrOp WordVec 32 W8) = 980+primOpTag (VecIndexScalarOffAddrOp WordVec 16 W16) = 981+primOpTag (VecIndexScalarOffAddrOp WordVec 8 W32) = 982+primOpTag (VecIndexScalarOffAddrOp WordVec 4 W64) = 983+primOpTag (VecIndexScalarOffAddrOp WordVec 64 W8) = 984+primOpTag (VecIndexScalarOffAddrOp WordVec 32 W16) = 985+primOpTag (VecIndexScalarOffAddrOp WordVec 16 W32) = 986+primOpTag (VecIndexScalarOffAddrOp WordVec 8 W64) = 987+primOpTag (VecIndexScalarOffAddrOp FloatVec 4 W32) = 988+primOpTag (VecIndexScalarOffAddrOp FloatVec 2 W64) = 989+primOpTag (VecIndexScalarOffAddrOp FloatVec 8 W32) = 990+primOpTag (VecIndexScalarOffAddrOp FloatVec 4 W64) = 991+primOpTag (VecIndexScalarOffAddrOp FloatVec 16 W32) = 992+primOpTag (VecIndexScalarOffAddrOp FloatVec 8 W64) = 993+primOpTag (VecReadScalarOffAddrOp IntVec 16 W8) = 994+primOpTag (VecReadScalarOffAddrOp IntVec 8 W16) = 995+primOpTag (VecReadScalarOffAddrOp IntVec 4 W32) = 996+primOpTag (VecReadScalarOffAddrOp IntVec 2 W64) = 997+primOpTag (VecReadScalarOffAddrOp IntVec 32 W8) = 998+primOpTag (VecReadScalarOffAddrOp IntVec 16 W16) = 999+primOpTag (VecReadScalarOffAddrOp IntVec 8 W32) = 1000+primOpTag (VecReadScalarOffAddrOp IntVec 4 W64) = 1001+primOpTag (VecReadScalarOffAddrOp IntVec 64 W8) = 1002+primOpTag (VecReadScalarOffAddrOp IntVec 32 W16) = 1003+primOpTag (VecReadScalarOffAddrOp IntVec 16 W32) = 1004+primOpTag (VecReadScalarOffAddrOp IntVec 8 W64) = 1005+primOpTag (VecReadScalarOffAddrOp WordVec 16 W8) = 1006+primOpTag (VecReadScalarOffAddrOp WordVec 8 W16) = 1007+primOpTag (VecReadScalarOffAddrOp WordVec 4 W32) = 1008+primOpTag (VecReadScalarOffAddrOp WordVec 2 W64) = 1009+primOpTag (VecReadScalarOffAddrOp WordVec 32 W8) = 1010+primOpTag (VecReadScalarOffAddrOp WordVec 16 W16) = 1011+primOpTag (VecReadScalarOffAddrOp WordVec 8 W32) = 1012+primOpTag (VecReadScalarOffAddrOp WordVec 4 W64) = 1013+primOpTag (VecReadScalarOffAddrOp WordVec 64 W8) = 1014+primOpTag (VecReadScalarOffAddrOp WordVec 32 W16) = 1015+primOpTag (VecReadScalarOffAddrOp WordVec 16 W32) = 1016+primOpTag (VecReadScalarOffAddrOp WordVec 8 W64) = 1017+primOpTag (VecReadScalarOffAddrOp FloatVec 4 W32) = 1018+primOpTag (VecReadScalarOffAddrOp FloatVec 2 W64) = 1019+primOpTag (VecReadScalarOffAddrOp FloatVec 8 W32) = 1020+primOpTag (VecReadScalarOffAddrOp FloatVec 4 W64) = 1021+primOpTag (VecReadScalarOffAddrOp FloatVec 16 W32) = 1022+primOpTag (VecReadScalarOffAddrOp FloatVec 8 W64) = 1023+primOpTag (VecWriteScalarOffAddrOp IntVec 16 W8) = 1024+primOpTag (VecWriteScalarOffAddrOp IntVec 8 W16) = 1025+primOpTag (VecWriteScalarOffAddrOp IntVec 4 W32) = 1026+primOpTag (VecWriteScalarOffAddrOp IntVec 2 W64) = 1027+primOpTag (VecWriteScalarOffAddrOp IntVec 32 W8) = 1028+primOpTag (VecWriteScalarOffAddrOp IntVec 16 W16) = 1029+primOpTag (VecWriteScalarOffAddrOp IntVec 8 W32) = 1030+primOpTag (VecWriteScalarOffAddrOp IntVec 4 W64) = 1031+primOpTag (VecWriteScalarOffAddrOp IntVec 64 W8) = 1032+primOpTag (VecWriteScalarOffAddrOp IntVec 32 W16) = 1033+primOpTag (VecWriteScalarOffAddrOp IntVec 16 W32) = 1034+primOpTag (VecWriteScalarOffAddrOp IntVec 8 W64) = 1035+primOpTag (VecWriteScalarOffAddrOp WordVec 16 W8) = 1036+primOpTag (VecWriteScalarOffAddrOp WordVec 8 W16) = 1037+primOpTag (VecWriteScalarOffAddrOp WordVec 4 W32) = 1038+primOpTag (VecWriteScalarOffAddrOp WordVec 2 W64) = 1039+primOpTag (VecWriteScalarOffAddrOp WordVec 32 W8) = 1040+primOpTag (VecWriteScalarOffAddrOp WordVec 16 W16) = 1041+primOpTag (VecWriteScalarOffAddrOp WordVec 8 W32) = 1042+primOpTag (VecWriteScalarOffAddrOp WordVec 4 W64) = 1043+primOpTag (VecWriteScalarOffAddrOp WordVec 64 W8) = 1044+primOpTag (VecWriteScalarOffAddrOp WordVec 32 W16) = 1045+primOpTag (VecWriteScalarOffAddrOp WordVec 16 W32) = 1046+primOpTag (VecWriteScalarOffAddrOp WordVec 8 W64) = 1047+primOpTag (VecWriteScalarOffAddrOp FloatVec 4 W32) = 1048+primOpTag (VecWriteScalarOffAddrOp FloatVec 2 W64) = 1049+primOpTag (VecWriteScalarOffAddrOp FloatVec 8 W32) = 1050+primOpTag (VecWriteScalarOffAddrOp FloatVec 4 W64) = 1051+primOpTag (VecWriteScalarOffAddrOp FloatVec 16 W32) = 1052+primOpTag (VecWriteScalarOffAddrOp FloatVec 8 W64) = 1053+primOpTag PrefetchByteArrayOp3 = 1054+primOpTag PrefetchMutableByteArrayOp3 = 1055+primOpTag PrefetchAddrOp3 = 1056+primOpTag PrefetchValueOp3 = 1057+primOpTag PrefetchByteArrayOp2 = 1058+primOpTag PrefetchMutableByteArrayOp2 = 1059+primOpTag PrefetchAddrOp2 = 1060+primOpTag PrefetchValueOp2 = 1061+primOpTag PrefetchByteArrayOp1 = 1062+primOpTag PrefetchMutableByteArrayOp1 = 1063+primOpTag PrefetchAddrOp1 = 1064+primOpTag PrefetchValueOp1 = 1065+primOpTag PrefetchByteArrayOp0 = 1066+primOpTag PrefetchMutableByteArrayOp0 = 1067+primOpTag PrefetchAddrOp0 = 1068+primOpTag PrefetchValueOp0 = 1069
+ autogen/primop-vector-tycons.hs-incl view
@@ -0,0 +1,30 @@+ , int8X16PrimTyCon+ , int16X8PrimTyCon+ , int32X4PrimTyCon+ , int64X2PrimTyCon+ , int8X32PrimTyCon+ , int16X16PrimTyCon+ , int32X8PrimTyCon+ , int64X4PrimTyCon+ , int8X64PrimTyCon+ , int16X32PrimTyCon+ , int32X16PrimTyCon+ , int64X8PrimTyCon+ , word8X16PrimTyCon+ , word16X8PrimTyCon+ , word32X4PrimTyCon+ , word64X2PrimTyCon+ , word8X32PrimTyCon+ , word16X16PrimTyCon+ , word32X8PrimTyCon+ , word64X4PrimTyCon+ , word8X64PrimTyCon+ , word16X32PrimTyCon+ , word32X16PrimTyCon+ , word64X8PrimTyCon+ , floatX4PrimTyCon+ , doubleX2PrimTyCon+ , floatX8PrimTyCon+ , doubleX4PrimTyCon+ , floatX16PrimTyCon+ , doubleX8PrimTyCon
+ autogen/primop-vector-tys-exports.hs-incl view
@@ -0,0 +1,30 @@+ int8X16PrimTy, int8X16PrimTyCon,+ int16X8PrimTy, int16X8PrimTyCon,+ int32X4PrimTy, int32X4PrimTyCon,+ int64X2PrimTy, int64X2PrimTyCon,+ int8X32PrimTy, int8X32PrimTyCon,+ int16X16PrimTy, int16X16PrimTyCon,+ int32X8PrimTy, int32X8PrimTyCon,+ int64X4PrimTy, int64X4PrimTyCon,+ int8X64PrimTy, int8X64PrimTyCon,+ int16X32PrimTy, int16X32PrimTyCon,+ int32X16PrimTy, int32X16PrimTyCon,+ int64X8PrimTy, int64X8PrimTyCon,+ word8X16PrimTy, word8X16PrimTyCon,+ word16X8PrimTy, word16X8PrimTyCon,+ word32X4PrimTy, word32X4PrimTyCon,+ word64X2PrimTy, word64X2PrimTyCon,+ word8X32PrimTy, word8X32PrimTyCon,+ word16X16PrimTy, word16X16PrimTyCon,+ word32X8PrimTy, word32X8PrimTyCon,+ word64X4PrimTy, word64X4PrimTyCon,+ word8X64PrimTy, word8X64PrimTyCon,+ word16X32PrimTy, word16X32PrimTyCon,+ word32X16PrimTy, word32X16PrimTyCon,+ word64X8PrimTy, word64X8PrimTyCon,+ floatX4PrimTy, floatX4PrimTyCon,+ doubleX2PrimTy, doubleX2PrimTyCon,+ floatX8PrimTy, floatX8PrimTyCon,+ doubleX4PrimTy, doubleX4PrimTyCon,+ floatX16PrimTy, floatX16PrimTyCon,+ doubleX8PrimTy, doubleX8PrimTyCon,
+ autogen/primop-vector-tys.hs-incl view
@@ -0,0 +1,180 @@+int8X16PrimTyConName :: Name+int8X16PrimTyConName = mkPrimTc (fsLit "Int8X16#") int8X16PrimTyConKey int8X16PrimTyCon+int8X16PrimTy :: Type+int8X16PrimTy = mkTyConTy int8X16PrimTyCon+int8X16PrimTyCon :: TyCon+int8X16PrimTyCon = pcPrimTyCon0 int8X16PrimTyConName (VecRep 16 Int8ElemRep)+int16X8PrimTyConName :: Name+int16X8PrimTyConName = mkPrimTc (fsLit "Int16X8#") int16X8PrimTyConKey int16X8PrimTyCon+int16X8PrimTy :: Type+int16X8PrimTy = mkTyConTy int16X8PrimTyCon+int16X8PrimTyCon :: TyCon+int16X8PrimTyCon = pcPrimTyCon0 int16X8PrimTyConName (VecRep 8 Int16ElemRep)+int32X4PrimTyConName :: Name+int32X4PrimTyConName = mkPrimTc (fsLit "Int32X4#") int32X4PrimTyConKey int32X4PrimTyCon+int32X4PrimTy :: Type+int32X4PrimTy = mkTyConTy int32X4PrimTyCon+int32X4PrimTyCon :: TyCon+int32X4PrimTyCon = pcPrimTyCon0 int32X4PrimTyConName (VecRep 4 Int32ElemRep)+int64X2PrimTyConName :: Name+int64X2PrimTyConName = mkPrimTc (fsLit "Int64X2#") int64X2PrimTyConKey int64X2PrimTyCon+int64X2PrimTy :: Type+int64X2PrimTy = mkTyConTy int64X2PrimTyCon+int64X2PrimTyCon :: TyCon+int64X2PrimTyCon = pcPrimTyCon0 int64X2PrimTyConName (VecRep 2 Int64ElemRep)+int8X32PrimTyConName :: Name+int8X32PrimTyConName = mkPrimTc (fsLit "Int8X32#") int8X32PrimTyConKey int8X32PrimTyCon+int8X32PrimTy :: Type+int8X32PrimTy = mkTyConTy int8X32PrimTyCon+int8X32PrimTyCon :: TyCon+int8X32PrimTyCon = pcPrimTyCon0 int8X32PrimTyConName (VecRep 32 Int8ElemRep)+int16X16PrimTyConName :: Name+int16X16PrimTyConName = mkPrimTc (fsLit "Int16X16#") int16X16PrimTyConKey int16X16PrimTyCon+int16X16PrimTy :: Type+int16X16PrimTy = mkTyConTy int16X16PrimTyCon+int16X16PrimTyCon :: TyCon+int16X16PrimTyCon = pcPrimTyCon0 int16X16PrimTyConName (VecRep 16 Int16ElemRep)+int32X8PrimTyConName :: Name+int32X8PrimTyConName = mkPrimTc (fsLit "Int32X8#") int32X8PrimTyConKey int32X8PrimTyCon+int32X8PrimTy :: Type+int32X8PrimTy = mkTyConTy int32X8PrimTyCon+int32X8PrimTyCon :: TyCon+int32X8PrimTyCon = pcPrimTyCon0 int32X8PrimTyConName (VecRep 8 Int32ElemRep)+int64X4PrimTyConName :: Name+int64X4PrimTyConName = mkPrimTc (fsLit "Int64X4#") int64X4PrimTyConKey int64X4PrimTyCon+int64X4PrimTy :: Type+int64X4PrimTy = mkTyConTy int64X4PrimTyCon+int64X4PrimTyCon :: TyCon+int64X4PrimTyCon = pcPrimTyCon0 int64X4PrimTyConName (VecRep 4 Int64ElemRep)+int8X64PrimTyConName :: Name+int8X64PrimTyConName = mkPrimTc (fsLit "Int8X64#") int8X64PrimTyConKey int8X64PrimTyCon+int8X64PrimTy :: Type+int8X64PrimTy = mkTyConTy int8X64PrimTyCon+int8X64PrimTyCon :: TyCon+int8X64PrimTyCon = pcPrimTyCon0 int8X64PrimTyConName (VecRep 64 Int8ElemRep)+int16X32PrimTyConName :: Name+int16X32PrimTyConName = mkPrimTc (fsLit "Int16X32#") int16X32PrimTyConKey int16X32PrimTyCon+int16X32PrimTy :: Type+int16X32PrimTy = mkTyConTy int16X32PrimTyCon+int16X32PrimTyCon :: TyCon+int16X32PrimTyCon = pcPrimTyCon0 int16X32PrimTyConName (VecRep 32 Int16ElemRep)+int32X16PrimTyConName :: Name+int32X16PrimTyConName = mkPrimTc (fsLit "Int32X16#") int32X16PrimTyConKey int32X16PrimTyCon+int32X16PrimTy :: Type+int32X16PrimTy = mkTyConTy int32X16PrimTyCon+int32X16PrimTyCon :: TyCon+int32X16PrimTyCon = pcPrimTyCon0 int32X16PrimTyConName (VecRep 16 Int32ElemRep)+int64X8PrimTyConName :: Name+int64X8PrimTyConName = mkPrimTc (fsLit "Int64X8#") int64X8PrimTyConKey int64X8PrimTyCon+int64X8PrimTy :: Type+int64X8PrimTy = mkTyConTy int64X8PrimTyCon+int64X8PrimTyCon :: TyCon+int64X8PrimTyCon = pcPrimTyCon0 int64X8PrimTyConName (VecRep 8 Int64ElemRep)+word8X16PrimTyConName :: Name+word8X16PrimTyConName = mkPrimTc (fsLit "Word8X16#") word8X16PrimTyConKey word8X16PrimTyCon+word8X16PrimTy :: Type+word8X16PrimTy = mkTyConTy word8X16PrimTyCon+word8X16PrimTyCon :: TyCon+word8X16PrimTyCon = pcPrimTyCon0 word8X16PrimTyConName (VecRep 16 Word8ElemRep)+word16X8PrimTyConName :: Name+word16X8PrimTyConName = mkPrimTc (fsLit "Word16X8#") word16X8PrimTyConKey word16X8PrimTyCon+word16X8PrimTy :: Type+word16X8PrimTy = mkTyConTy word16X8PrimTyCon+word16X8PrimTyCon :: TyCon+word16X8PrimTyCon = pcPrimTyCon0 word16X8PrimTyConName (VecRep 8 Word16ElemRep)+word32X4PrimTyConName :: Name+word32X4PrimTyConName = mkPrimTc (fsLit "Word32X4#") word32X4PrimTyConKey word32X4PrimTyCon+word32X4PrimTy :: Type+word32X4PrimTy = mkTyConTy word32X4PrimTyCon+word32X4PrimTyCon :: TyCon+word32X4PrimTyCon = pcPrimTyCon0 word32X4PrimTyConName (VecRep 4 Word32ElemRep)+word64X2PrimTyConName :: Name+word64X2PrimTyConName = mkPrimTc (fsLit "Word64X2#") word64X2PrimTyConKey word64X2PrimTyCon+word64X2PrimTy :: Type+word64X2PrimTy = mkTyConTy word64X2PrimTyCon+word64X2PrimTyCon :: TyCon+word64X2PrimTyCon = pcPrimTyCon0 word64X2PrimTyConName (VecRep 2 Word64ElemRep)+word8X32PrimTyConName :: Name+word8X32PrimTyConName = mkPrimTc (fsLit "Word8X32#") word8X32PrimTyConKey word8X32PrimTyCon+word8X32PrimTy :: Type+word8X32PrimTy = mkTyConTy word8X32PrimTyCon+word8X32PrimTyCon :: TyCon+word8X32PrimTyCon = pcPrimTyCon0 word8X32PrimTyConName (VecRep 32 Word8ElemRep)+word16X16PrimTyConName :: Name+word16X16PrimTyConName = mkPrimTc (fsLit "Word16X16#") word16X16PrimTyConKey word16X16PrimTyCon+word16X16PrimTy :: Type+word16X16PrimTy = mkTyConTy word16X16PrimTyCon+word16X16PrimTyCon :: TyCon+word16X16PrimTyCon = pcPrimTyCon0 word16X16PrimTyConName (VecRep 16 Word16ElemRep)+word32X8PrimTyConName :: Name+word32X8PrimTyConName = mkPrimTc (fsLit "Word32X8#") word32X8PrimTyConKey word32X8PrimTyCon+word32X8PrimTy :: Type+word32X8PrimTy = mkTyConTy word32X8PrimTyCon+word32X8PrimTyCon :: TyCon+word32X8PrimTyCon = pcPrimTyCon0 word32X8PrimTyConName (VecRep 8 Word32ElemRep)+word64X4PrimTyConName :: Name+word64X4PrimTyConName = mkPrimTc (fsLit "Word64X4#") word64X4PrimTyConKey word64X4PrimTyCon+word64X4PrimTy :: Type+word64X4PrimTy = mkTyConTy word64X4PrimTyCon+word64X4PrimTyCon :: TyCon+word64X4PrimTyCon = pcPrimTyCon0 word64X4PrimTyConName (VecRep 4 Word64ElemRep)+word8X64PrimTyConName :: Name+word8X64PrimTyConName = mkPrimTc (fsLit "Word8X64#") word8X64PrimTyConKey word8X64PrimTyCon+word8X64PrimTy :: Type+word8X64PrimTy = mkTyConTy word8X64PrimTyCon+word8X64PrimTyCon :: TyCon+word8X64PrimTyCon = pcPrimTyCon0 word8X64PrimTyConName (VecRep 64 Word8ElemRep)+word16X32PrimTyConName :: Name+word16X32PrimTyConName = mkPrimTc (fsLit "Word16X32#") word16X32PrimTyConKey word16X32PrimTyCon+word16X32PrimTy :: Type+word16X32PrimTy = mkTyConTy word16X32PrimTyCon+word16X32PrimTyCon :: TyCon+word16X32PrimTyCon = pcPrimTyCon0 word16X32PrimTyConName (VecRep 32 Word16ElemRep)+word32X16PrimTyConName :: Name+word32X16PrimTyConName = mkPrimTc (fsLit "Word32X16#") word32X16PrimTyConKey word32X16PrimTyCon+word32X16PrimTy :: Type+word32X16PrimTy = mkTyConTy word32X16PrimTyCon+word32X16PrimTyCon :: TyCon+word32X16PrimTyCon = pcPrimTyCon0 word32X16PrimTyConName (VecRep 16 Word32ElemRep)+word64X8PrimTyConName :: Name+word64X8PrimTyConName = mkPrimTc (fsLit "Word64X8#") word64X8PrimTyConKey word64X8PrimTyCon+word64X8PrimTy :: Type+word64X8PrimTy = mkTyConTy word64X8PrimTyCon+word64X8PrimTyCon :: TyCon+word64X8PrimTyCon = pcPrimTyCon0 word64X8PrimTyConName (VecRep 8 Word64ElemRep)+floatX4PrimTyConName :: Name+floatX4PrimTyConName = mkPrimTc (fsLit "FloatX4#") floatX4PrimTyConKey floatX4PrimTyCon+floatX4PrimTy :: Type+floatX4PrimTy = mkTyConTy floatX4PrimTyCon+floatX4PrimTyCon :: TyCon+floatX4PrimTyCon = pcPrimTyCon0 floatX4PrimTyConName (VecRep 4 FloatElemRep)+doubleX2PrimTyConName :: Name+doubleX2PrimTyConName = mkPrimTc (fsLit "DoubleX2#") doubleX2PrimTyConKey doubleX2PrimTyCon+doubleX2PrimTy :: Type+doubleX2PrimTy = mkTyConTy doubleX2PrimTyCon+doubleX2PrimTyCon :: TyCon+doubleX2PrimTyCon = pcPrimTyCon0 doubleX2PrimTyConName (VecRep 2 DoubleElemRep)+floatX8PrimTyConName :: Name+floatX8PrimTyConName = mkPrimTc (fsLit "FloatX8#") floatX8PrimTyConKey floatX8PrimTyCon+floatX8PrimTy :: Type+floatX8PrimTy = mkTyConTy floatX8PrimTyCon+floatX8PrimTyCon :: TyCon+floatX8PrimTyCon = pcPrimTyCon0 floatX8PrimTyConName (VecRep 8 FloatElemRep)+doubleX4PrimTyConName :: Name+doubleX4PrimTyConName = mkPrimTc (fsLit "DoubleX4#") doubleX4PrimTyConKey doubleX4PrimTyCon+doubleX4PrimTy :: Type+doubleX4PrimTy = mkTyConTy doubleX4PrimTyCon+doubleX4PrimTyCon :: TyCon+doubleX4PrimTyCon = pcPrimTyCon0 doubleX4PrimTyConName (VecRep 4 DoubleElemRep)+floatX16PrimTyConName :: Name+floatX16PrimTyConName = mkPrimTc (fsLit "FloatX16#") floatX16PrimTyConKey floatX16PrimTyCon+floatX16PrimTy :: Type+floatX16PrimTy = mkTyConTy floatX16PrimTyCon+floatX16PrimTyCon :: TyCon+floatX16PrimTyCon = pcPrimTyCon0 floatX16PrimTyConName (VecRep 16 FloatElemRep)+doubleX8PrimTyConName :: Name+doubleX8PrimTyConName = mkPrimTc (fsLit "DoubleX8#") doubleX8PrimTyConKey doubleX8PrimTyCon+doubleX8PrimTy :: Type+doubleX8PrimTy = mkTyConTy doubleX8PrimTyCon+doubleX8PrimTyCon :: TyCon+doubleX8PrimTyCon = pcPrimTyCon0 doubleX8PrimTyConName (VecRep 8 DoubleElemRep)
+ autogen/primop-vector-uniques.hs-incl view
@@ -0,0 +1,60 @@+int8X16PrimTyConKey :: Unique+int8X16PrimTyConKey = mkPreludeTyConUnique 300+int16X8PrimTyConKey :: Unique+int16X8PrimTyConKey = mkPreludeTyConUnique 301+int32X4PrimTyConKey :: Unique+int32X4PrimTyConKey = mkPreludeTyConUnique 302+int64X2PrimTyConKey :: Unique+int64X2PrimTyConKey = mkPreludeTyConUnique 303+int8X32PrimTyConKey :: Unique+int8X32PrimTyConKey = mkPreludeTyConUnique 304+int16X16PrimTyConKey :: Unique+int16X16PrimTyConKey = mkPreludeTyConUnique 305+int32X8PrimTyConKey :: Unique+int32X8PrimTyConKey = mkPreludeTyConUnique 306+int64X4PrimTyConKey :: Unique+int64X4PrimTyConKey = mkPreludeTyConUnique 307+int8X64PrimTyConKey :: Unique+int8X64PrimTyConKey = mkPreludeTyConUnique 308+int16X32PrimTyConKey :: Unique+int16X32PrimTyConKey = mkPreludeTyConUnique 309+int32X16PrimTyConKey :: Unique+int32X16PrimTyConKey = mkPreludeTyConUnique 310+int64X8PrimTyConKey :: Unique+int64X8PrimTyConKey = mkPreludeTyConUnique 311+word8X16PrimTyConKey :: Unique+word8X16PrimTyConKey = mkPreludeTyConUnique 312+word16X8PrimTyConKey :: Unique+word16X8PrimTyConKey = mkPreludeTyConUnique 313+word32X4PrimTyConKey :: Unique+word32X4PrimTyConKey = mkPreludeTyConUnique 314+word64X2PrimTyConKey :: Unique+word64X2PrimTyConKey = mkPreludeTyConUnique 315+word8X32PrimTyConKey :: Unique+word8X32PrimTyConKey = mkPreludeTyConUnique 316+word16X16PrimTyConKey :: Unique+word16X16PrimTyConKey = mkPreludeTyConUnique 317+word32X8PrimTyConKey :: Unique+word32X8PrimTyConKey = mkPreludeTyConUnique 318+word64X4PrimTyConKey :: Unique+word64X4PrimTyConKey = mkPreludeTyConUnique 319+word8X64PrimTyConKey :: Unique+word8X64PrimTyConKey = mkPreludeTyConUnique 320+word16X32PrimTyConKey :: Unique+word16X32PrimTyConKey = mkPreludeTyConUnique 321+word32X16PrimTyConKey :: Unique+word32X16PrimTyConKey = mkPreludeTyConUnique 322+word64X8PrimTyConKey :: Unique+word64X8PrimTyConKey = mkPreludeTyConUnique 323+floatX4PrimTyConKey :: Unique+floatX4PrimTyConKey = mkPreludeTyConUnique 324+doubleX2PrimTyConKey :: Unique+doubleX2PrimTyConKey = mkPreludeTyConUnique 325+floatX8PrimTyConKey :: Unique+floatX8PrimTyConKey = mkPreludeTyConUnique 326+doubleX4PrimTyConKey :: Unique+doubleX4PrimTyConKey = mkPreludeTyConUnique 327+floatX16PrimTyConKey :: Unique+floatX16PrimTyConKey = mkPreludeTyConUnique 328+doubleX8PrimTyConKey :: Unique+doubleX8PrimTyConKey = mkPreludeTyConUnique 329
+ backpack/BkpSyn.hs view
@@ -0,0 +1,83 @@+-- | This is the syntax for bkp files which are parsed in 'ghc --backpack'+-- mode. This syntax is used purely for testing purposes.++module BkpSyn (+ -- * Backpack abstract syntax+ HsUnitId(..),+ LHsUnitId,+ HsModuleSubst,+ LHsModuleSubst,+ HsModuleId(..),+ LHsModuleId,+ HsComponentId(..),+ LHsUnit, HsUnit(..),+ LHsUnitDecl, HsUnitDecl(..),+ HsDeclType(..),+ IncludeDecl(..),+ LRenaming, Renaming(..),+ ) where++import HsSyn+import RdrName+import SrcLoc+import Outputable+import Module+import PackageConfig++{-+************************************************************************+* *+ User syntax+* *+************************************************************************+-}++data HsComponentId = HsComponentId {+ hsPackageName :: PackageName,+ hsComponentId :: ComponentId+ }++instance Outputable HsComponentId where+ ppr (HsComponentId _pn cid) = ppr cid -- todo debug with pn++data HsUnitId n = HsUnitId (Located n) [LHsModuleSubst n]+type LHsUnitId n = Located (HsUnitId n)++type HsModuleSubst n = (Located ModuleName, LHsModuleId n)+type LHsModuleSubst n = Located (HsModuleSubst n)++data HsModuleId n = HsModuleVar (Located ModuleName)+ | HsModuleId (LHsUnitId n) (Located ModuleName)+type LHsModuleId n = Located (HsModuleId n)++-- | Top level @unit@ declaration in a Backpack file.+data HsUnit n = HsUnit {+ hsunitName :: Located n,+ hsunitBody :: [LHsUnitDecl n]+ }+type LHsUnit n = Located (HsUnit n)++-- | A declaration in a package, e.g. a module or signature definition,+-- or an include.+data HsDeclType = ModuleD | SignatureD+data HsUnitDecl n+ = DeclD HsDeclType (Located ModuleName) (Maybe (Located (HsModule RdrName)))+ | IncludeD (IncludeDecl n)+type LHsUnitDecl n = Located (HsUnitDecl n)++-- | An include of another unit+data IncludeDecl n = IncludeDecl {+ idUnitId :: LHsUnitId n,+ idModRenaming :: Maybe [ LRenaming ],+ -- | Is this a @dependency signature@ include? If so,+ -- we don't compile this include when we instantiate this+ -- unit (as there should not be any modules brought into+ -- scope.)+ idSignatureInclude :: Bool+ }++-- | Rename a module from one name to another. The identity renaming+-- means that the module should be brought into scope.+data Renaming = Renaming { renameFrom :: Located ModuleName+ , renameTo :: Maybe (Located ModuleName) }+type LRenaming = Located Renaming
+ backpack/DriverBkp.hs view
@@ -0,0 +1,823 @@+{-# LANGUAGE NondecreasingIndentation #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE CPP #-}++-- | This is the driver for the 'ghc --backpack' mode, which+-- is a reimplementation of the "package manager" bits of+-- Backpack directly in GHC. The basic method of operation+-- is to compile packages and then directly insert them into+-- GHC's in memory database.+--+-- The compilation products of this mode aren't really suitable+-- for Cabal, because GHC makes up component IDs for the things+-- it builds and doesn't serialize out the database contents.+-- But it's still handy for constructing tests.++module DriverBkp (doBackpack) where++#include "HsVersions.h"++-- In a separate module because it hooks into the parser.+import BkpSyn++import GHC hiding (Failed, Succeeded)+import Packages+import Parser+import Lexer+import GhcMonad+import DynFlags+import TcRnMonad+import TcRnDriver+import Module+import HscTypes+import StringBuffer+import FastString+import ErrUtils+import SrcLoc+import HscMain+import UniqFM+import UniqDFM+import Outputable+import Maybes+import HeaderInfo+import MkIface+import GhcMake+import UniqDSet+import PrelNames+import BasicTypes hiding (SuccessFlag(..))+import Finder+import Util++import qualified GHC.LanguageExtensions as LangExt++import Panic+import Data.List+import System.Exit+import Control.Monad+import System.FilePath+import Data.Version++-- for the unification+import Data.IORef+import Data.Map (Map)+import qualified Data.Map as Map++-- | Entry point to compile a Backpack file.+doBackpack :: [FilePath] -> Ghc ()+doBackpack [src_filename] = do+ -- Apply options from file to dflags+ dflags0 <- getDynFlags+ let dflags1 = dflags0+ src_opts <- liftIO $ getOptionsFromFile dflags1 src_filename+ (dflags, unhandled_flags, warns) <- liftIO $ parseDynamicFilePragma dflags1 src_opts+ modifySession (\hsc_env -> hsc_env {hsc_dflags = dflags})+ -- Cribbed from: preprocessFile / DriverPipeline+ liftIO $ checkProcessArgsResult dflags unhandled_flags+ liftIO $ handleFlagWarnings dflags warns+ -- TODO: Preprocessing not implemented++ buf <- liftIO $ hGetStringBuffer src_filename+ let loc = mkRealSrcLoc (mkFastString src_filename) 1 1 -- TODO: not great+ case unP parseBackpack (mkPState dflags buf loc) of+ PFailed span err -> do+ liftIO $ throwOneError (mkPlainErrMsg dflags span err)+ POk _ pkgname_bkp -> do+ -- OK, so we have an LHsUnit PackageName, but we want an+ -- LHsUnit HsComponentId. So let's rename it.+ let bkp = renameHsUnits dflags (packageNameMap pkgname_bkp) pkgname_bkp+ initBkpM src_filename bkp $+ forM_ (zip [1..] bkp) $ \(i, lunit) -> do+ let comp_name = unLoc (hsunitName (unLoc lunit))+ msgTopPackage (i,length bkp) comp_name+ innerBkpM $ do+ let (cid, insts) = computeUnitId lunit+ if null insts+ then if cid == ComponentId (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 -> (ComponentId, [(ModuleName, Module)])+computeUnitId (L _ unit) = (cid, [ (r, mkHoleModule r) | r <- reqs ])+ where+ cid = hsComponentId (unLoc (hsunitName unit))+ reqs = uniqDSetToList (unionManyUniqDSets (map (get_reqs . unLoc) (hsunitBody unit)))+ get_reqs (DeclD SignatureD (L _ modname) _) = unitUniqDSet modname+ get_reqs (DeclD ModuleD _ _) = emptyUniqDSet+ get_reqs (IncludeD (IncludeDecl (L _ hsuid) _ _)) =+ unitIdFreeHoles (convertHsUnitId hsuid)++-- | Tiny enum for all types of Backpack operations we may do.+data SessionType+ -- | A compilation operation which will result in a+ -- runnable executable being produced.+ = ExeSession+ -- | A type-checking operation which produces only+ -- interface files, no object files.+ | TcSession+ -- | A compilation operation which produces both+ -- interface files and object files.+ | CompSession+ deriving (Eq)++-- | Create a temporary Session to do some sort of type checking or+-- compilation.+withBkpSession :: ComponentId+ -> [(ModuleName, Module)]+ -> [(UnitId, ModRenaming)]+ -> SessionType -- what kind of session are we doing+ -> BkpM a -- actual action to run+ -> BkpM a+withBkpSession cid insts deps session_type do_this = do+ dflags <- getDynFlags+ let (ComponentId cid_fs) = cid+ is_primary = False+ uid_str = unpackFS (hashUnitId cid insts)+ cid_str = unpackFS cid_fs+ -- There are multiple units in a single Backpack file, so we+ -- need to separate out the results in those cases. Right now,+ -- we follow this hierarchy:+ -- $outputdir/$compid --> typecheck results+ -- $outputdir/$compid/$unitid --> compile results+ key_base p | Just f <- p dflags = f+ | otherwise = "."+ sub_comp p | is_primary = p+ | otherwise = p </> cid_str+ outdir p | CompSession <- session_type+ -- Special case when package is definite+ , not (null insts) = sub_comp (key_base p) </> uid_str+ | otherwise = sub_comp (key_base p)+ withTempSession (overHscDynFlags (\dflags ->+ -- If we're type-checking an indefinite package, we want to+ -- turn on interface writing. However, if the user also+ -- explicitly passed in `-fno-code`, we DON'T want to write+ -- interfaces unless the user also asked for `-fwrite-interface`.+ (case session_type of+ -- Make sure to write interfaces when we are type-checking+ -- indefinite packages.+ TcSession | hscTarget dflags /= HscNothing+ -> flip gopt_set Opt_WriteInterface+ | otherwise -> id+ CompSession -> id+ ExeSession -> id) $+ dflags {+ hscTarget = case session_type of+ TcSession -> HscNothing+ _ -> hscTarget dflags,+ thisUnitIdInsts_ = Just insts,+ thisComponentId_ = Just cid,+ thisInstalledUnitId =+ case session_type of+ TcSession -> newInstalledUnitId cid Nothing+ -- No hash passed if no instances+ _ | null insts -> newInstalledUnitId cid Nothing+ | otherwise -> newInstalledUnitId cid (Just (hashUnitId cid insts)),+ -- Setup all of the output directories according to our hierarchy+ objectDir = Just (outdir objectDir),+ hiDir = Just (outdir hiDir),+ stubDir = Just (outdir stubDir),+ -- Unset output-file for non exe builds+ outputFile = if session_type == ExeSession+ then outputFile dflags+ else Nothing,+ -- Clear the import path so we don't accidentally grab anything+ importPaths = [],+ -- Synthesized the flags+ packageFlags = packageFlags dflags ++ map (\(uid0, rn) ->+ let uid = unwireUnitId dflags (improveUnitId (getPackageConfigMap dflags) $ renameHoleUnitId dflags (listToUFM insts) uid0)+ in ExposePackage+ (showSDoc dflags+ (text "-unit-id" <+> ppr uid <+> ppr rn))+ (UnitIdArg uid) rn) deps+ } )) $ do+ dflags <- getSessionDynFlags+ -- pprTrace "flags" (ppr insts <> ppr deps) $ return ()+ -- Calls initPackages+ _ <- setSessionDynFlags dflags+ do_this++withBkpExeSession :: [(UnitId, ModRenaming)] -> BkpM a -> BkpM a+withBkpExeSession deps do_this = do+ withBkpSession (ComponentId (fsLit "main")) [] deps ExeSession do_this++getSource :: ComponentId -> 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 :: ComponentId -> [(ModuleName, Module)] -> BkpM ()+typecheckUnit cid insts = do+ lunit <- getSource cid+ buildUnit TcSession cid insts lunit++compileUnit :: ComponentId -> [(ModuleName, Module)] -> BkpM ()+compileUnit cid insts = do+ -- Let everyone know we're building this unit ID+ msgUnitId (newUnitId cid insts)+ lunit <- getSource cid+ buildUnit CompSession cid insts lunit++-- | Compute the dependencies with instantiations of a syntactic+-- HsUnit; e.g., wherever you see @dependency p[A=<A>]@ in a+-- unit file, return the 'UnitId' corresponding to @p[A=<A>]@.+-- The @include_sigs@ parameter controls whether or not we also+-- include @dependency signature@ declarations in this calculation.+--+-- Invariant: this NEVER returns InstalledUnitId.+hsunitDeps :: Bool {- include sigs -} -> HsUnit HsComponentId -> [(UnitId, ModRenaming)]+hsunitDeps include_sigs unit = concatMap get_dep (hsunitBody unit)+ where+ get_dep (L _ (IncludeD (IncludeDecl (L _ hsuid) mb_lrn is_sig)))+ | include_sigs || not is_sig = [(convertHsUnitId hsuid, go mb_lrn)]+ | otherwise = []+ where+ go Nothing = ModRenaming True []+ go (Just lrns) = ModRenaming False (map convRn lrns)+ where+ convRn (L _ (Renaming (L _ from) Nothing)) = (from, from)+ convRn (L _ (Renaming (L _ from) (Just (L _ to)))) = (from, to)+ get_dep _ = []++buildUnit :: SessionType -> ComponentId -> [(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+ -- compile a signature since it isn't going to produce+ -- any object files.+ let deps_w_rns = hsunitDeps (session == TcSession) (unLoc lunit)+ raw_deps = map fst deps_w_rns+ dflags <- getDynFlags+ -- The compilation dependencies are just the appropriately filled+ -- in unit IDs which must be compiled before we can compile.+ let hsubst = listToUFM insts+ deps0 = map (renameHoleUnitId dflags hsubst) raw_deps++ -- Build dependencies OR make sure they make sense. BUT NOTE,+ -- we can only check the ones that are fully filled; the rest+ -- we have to defer until we've typechecked our local signature.+ -- TODO: work this into GhcMake!!+ forM_ (zip [1..] deps0) $ \(i, dep) ->+ case session of+ TcSession -> return ()+ _ -> compileInclude (length deps0) (i, dep)++ dflags <- getDynFlags+ -- IMPROVE IT+ let deps = map (improveUnitId (getPackageConfigMap dflags)) deps0++ mb_old_eps <- case session of+ TcSession -> fmap Just getEpsGhc+ _ -> return Nothing++ conf <- withBkpSession cid insts deps_w_rns session $ do++ dflags <- getDynFlags+ mod_graph <- hsunitModuleGraph dflags (unLoc lunit)+ -- pprTrace "mod_graph" (ppr mod_graph) $ return ()++ msg <- mkBackpackMsg+ ok <- load' LoadAllTargets (Just msg) mod_graph+ when (failed ok) (liftIO $ exitWith (ExitFailure 1))++ let hi_dir = expectJust (panic "hiDir Backpack") $ hiDir dflags+ export_mod ms = (ms_mod_name ms, ms_mod ms)+ -- Export everything!+ mods = [ export_mod ms | ms <- mod_graph, ms_hsc_src ms == HsSrcFile ]++ -- Compile relevant only+ hsc_env <- getSession+ let home_mod_infos = eltsUDFM (hsc_HPT hsc_env)+ linkables = map (expectJust "bkp link" . hm_linkable)+ . filter ((==HsSrcFile) . mi_hsc_src . hm_iface)+ $ home_mod_infos+ getOfiles (LM _ _ us) = map nameOfObject (filter isObject us)+ obj_files = concatMap getOfiles linkables++ let compat_fs = (case cid of ComponentId fs -> fs)+ compat_pn = PackageName compat_fs++ return InstalledPackageInfo {+ -- Stub data+ abiHash = "",+ sourcePackageId = SourcePackageId compat_fs,+ packageName = compat_pn,+ packageVersion = makeVersion [0],+ unitId = toInstalledUnitId (thisPackage dflags),+ sourceLibName = Nothing,+ componentId = cid,+ instantiatedWith = insts,+ -- Slight inefficiency here haha+ exposedModules = map (\(m,n) -> (m,Just n)) mods,+ hiddenModules = [], -- TODO: doc only+ depends = case session of+ -- Technically, we should state that we depend+ -- on all the indefinite libraries we used to+ -- typecheck this. However, this field isn't+ -- really used for anything, so we leave it+ -- blank for now.+ TcSession -> []+ _ -> map (toInstalledUnitId . unwireUnitId dflags)+ $ deps ++ [ moduleUnitId mod+ | (_, mod) <- insts+ , not (isHoleModule mod) ],+ abiDepends = [],+ ldOptions = case session of+ TcSession -> []+ _ -> obj_files,+ importDirs = [ hi_dir ],+ exposed = False,+ indefinite = case session of+ TcSession -> True+ _ -> False,+ -- nope+ hsLibraries = [],+ extraLibraries = [],+ extraGHCiLibraries = [],+ libraryDynDirs = [],+ libraryDirs = [],+ frameworks = [],+ frameworkDirs = [],+ ccOptions = [],+ includes = [],+ includeDirs = [],+ haddockInterfaces = [],+ haddockHTMLs = [],+ trusted = False+ }+++ addPackage conf+ case mb_old_eps of+ Just old_eps -> updateEpsGhc_ (const old_eps)+ _ -> return ()++compileExe :: LHsUnit HsComponentId -> BkpM ()+compileExe lunit = do+ msgUnitId mainUnitId+ let deps_w_rns = hsunitDeps False (unLoc lunit)+ deps = map fst deps_w_rns+ -- no renaming necessary+ forM_ (zip [1..] deps) $ \(i, dep) ->+ compileInclude (length deps) (i, dep)+ withBkpExeSession deps_w_rns $ do+ dflags <- getDynFlags+ mod_graph <- hsunitModuleGraph dflags (unLoc lunit)+ msg <- mkBackpackMsg+ ok <- load' LoadAllTargets (Just msg) mod_graph+ when (failed ok) (liftIO $ exitWith (ExitFailure 1))++addPackage :: GhcMonad m => PackageConfig -> m ()+addPackage pkg = do+ dflags0 <- GHC.getSessionDynFlags+ case pkgDatabase dflags0 of+ Nothing -> panic "addPackage: called too early"+ Just pkgs -> do let dflags = dflags0 { pkgDatabase =+ Just (pkgs ++ [("(in memory " ++ showSDoc dflags0 (ppr (unitId pkg)) ++ ")", [pkg])]) }+ _ <- GHC.setSessionDynFlags dflags+ -- By this time, the global ref has probably already+ -- been forced, in which case doing this isn't actually+ -- going to do you any good.+ -- dflags <- GHC.getSessionDynFlags+ -- liftIO $ setUnsafeGlobalDynFlags dflags+ return ()++-- Precondition: UnitId is NOT InstalledUnitId+compileInclude :: Int -> (Int, UnitId) -> BkpM ()+compileInclude n (i, uid) = do+ hsc_env <- getSession+ let dflags = hsc_dflags hsc_env+ msgInclude (i, n) uid+ -- Check if we've compiled it already+ case lookupPackage dflags uid of+ Nothing -> do+ case splitUnitIdInsts uid of+ (_, Just indef) ->+ innerBkpM $ compileUnit (indefUnitIdComponentId indef)+ (indefUnitIdInsts indef)+ _ -> return ()+ Just _ -> return ()++-- ----------------------------------------------------------------------------+-- Backpack monad++-- | Backpack monad is a 'GhcMonad' which also maintains a little extra state+-- beyond the 'Session', c.f. 'BkpEnv'.+type BkpM = IOEnv BkpEnv++-- | Backpack environment. NB: this has a 'Session' and not an 'HscEnv',+-- because we are going to update the 'HscEnv' as we go.+data BkpEnv+ = BkpEnv {+ -- | The session+ bkp_session :: Session,+ -- | 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 ComponentId (LHsUnit HsComponentId),+ -- | When a package we are compiling includes another package+ -- which has not been compiled, we bump the level and compile+ -- that.+ bkp_level :: Int+ }++-- Blah, to get rid of the default instance for IOEnv+-- TODO: just make a proper new monad for BkpM, rather than use IOEnv+instance {-# OVERLAPPING #-} HasDynFlags BkpM where+ getDynFlags = fmap hsc_dflags getSession++instance GhcMonad BkpM where+ getSession = do+ Session s <- fmap bkp_session getEnv+ readMutVar s+ setSession hsc_env = do+ Session s <- fmap bkp_session getEnv+ writeMutVar s hsc_env++-- | Get the current 'BkpEnv'.+getBkpEnv :: BkpM BkpEnv+getBkpEnv = getEnv++-- | Get the nesting level, when recursively compiling modules.+getBkpLevel :: BkpM Int+getBkpLevel = bkp_level `fmap` getBkpEnv++-- | Apply a function on 'DynFlags' on an 'HscEnv'+overHscDynFlags :: (DynFlags -> DynFlags) -> HscEnv -> HscEnv+overHscDynFlags f hsc_env = hsc_env { hsc_dflags = f (hsc_dflags hsc_env) }++-- | Run a 'BkpM' computation, with the nesting level bumped one.+innerBkpM :: BkpM a -> BkpM a+innerBkpM do_this = do+ -- NB: withTempSession mutates, so we don't have to worry+ -- about bkp_session being stale.+ updEnv (\env -> env { bkp_level = bkp_level env + 1 }) do_this++-- | Update the EPS from a 'GhcMonad'. TODO move to appropriate library spot.+updateEpsGhc_ :: GhcMonad m => (ExternalPackageState -> ExternalPackageState) -> m ()+updateEpsGhc_ f = do+ hsc_env <- getSession+ liftIO $ atomicModifyIORef' (hsc_EPS hsc_env) (\x -> (f x, ()))++-- | Get the EPS from a 'GhcMonad'.+getEpsGhc :: GhcMonad m => m ExternalPackageState+getEpsGhc = do+ hsc_env <- getSession+ liftIO $ readIORef (hsc_EPS hsc_env)++-- | Run 'BkpM' in 'Ghc'.+initBkpM :: FilePath -> [LHsUnit HsComponentId] -> BkpM a -> Ghc a+initBkpM file bkp m = do+ reifyGhc $ \session -> do+ let env = BkpEnv {+ bkp_session = session,+ bkp_table = Map.fromList [(hsComponentId (unLoc (hsunitName (unLoc u))), u) | u <- bkp],+ bkp_filename = file,+ bkp_level = 0+ }+ runIOEnv env m++-- ----------------------------------------------------------------------------+-- Messaging++-- | Print a compilation progress message, but with indentation according+-- to @level@ (for nested compilation).+backpackProgressMsg :: Int -> DynFlags -> String -> IO ()+backpackProgressMsg level dflags msg =+ compilationProgressMsg dflags $ replicate (level * 2) ' ' ++ msg++-- | Creates a 'Messager' for Backpack compilation; this is basically+-- a carbon copy of 'batchMsg' but calling 'backpackProgressMsg', which+-- handles indentation.+mkBackpackMsg :: BkpM Messager+mkBackpackMsg = do+ level <- getBkpLevel+ return $ \hsc_env mod_index recomp mod_summary ->+ let dflags = hsc_dflags hsc_env+ showMsg msg reason =+ backpackProgressMsg level dflags $+ showModuleIndex mod_index +++ msg ++ showModMsg dflags (hscTarget dflags)+ (recompileRequired recomp) mod_summary+ ++ reason+ in case recomp of+ MustCompile -> showMsg "Compiling " ""+ UpToDate+ | verbosity (hsc_dflags hsc_env) >= 2 -> showMsg "Skipping " ""+ | otherwise -> return ()+ RecompBecause reason -> showMsg "Compiling " (" [" ++ reason ++ "]")++-- | 'PprStyle' for Backpack messages; here we usually want the module to+-- be qualified (so we can tell how it was instantiated.) But we try not+-- to qualify packages so we can use simple names for them.+backpackStyle :: DynFlags -> PprStyle+backpackStyle dflags =+ mkUserStyle dflags+ (QueryQualify neverQualifyNames+ alwaysQualifyModules+ neverQualifyPackages) AllTheWay++-- | Message when we initially process a Backpack unit.+msgTopPackage :: (Int,Int) -> HsComponentId -> BkpM ()+msgTopPackage (i,n) (HsComponentId (PackageName fs_pn) _) = do+ dflags <- getDynFlags+ level <- getBkpLevel+ liftIO . backpackProgressMsg level dflags+ $ showModuleIndex (i, n) ++ "Processing " ++ unpackFS fs_pn++-- | Message when we instantiate a Backpack unit.+msgUnitId :: UnitId -> BkpM ()+msgUnitId pk = do+ dflags <- getDynFlags+ level <- getBkpLevel+ liftIO . backpackProgressMsg level dflags+ $ "Instantiating " ++ renderWithStyle dflags (ppr pk)+ (backpackStyle dflags)++-- | Message when we include a Backpack unit.+msgInclude :: (Int,Int) -> UnitId -> BkpM ()+msgInclude (i,n) uid = do+ dflags <- getDynFlags+ level <- getBkpLevel+ liftIO . backpackProgressMsg level dflags+ $ showModuleIndex (i, n) ++ "Including " +++ renderWithStyle dflags (ppr uid) (backpackStyle dflags)++-- ----------------------------------------------------------------------------+-- Conversion from PackageName to HsComponentId++type PackageNameMap a = Map PackageName a++-- For now, something really simple, since we're not actually going+-- to use this for anything+unitDefines :: LHsUnit PackageName -> (PackageName, HsComponentId)+unitDefines (L _ HsUnit{ hsunitName = L _ pn@(PackageName fs) })+ = (pn, HsComponentId pn (ComponentId fs))++packageNameMap :: [LHsUnit PackageName] -> PackageNameMap HsComponentId+packageNameMap units = Map.fromList (map unitDefines units)++renameHsUnits :: DynFlags -> PackageNameMap HsComponentId -> [LHsUnit PackageName] -> [LHsUnit HsComponentId]+renameHsUnits dflags m units = map (fmap renameHsUnit) units+ where++ renamePackageName :: PackageName -> HsComponentId+ renamePackageName pn =+ case Map.lookup pn m of+ Nothing ->+ case lookupPackageName dflags pn of+ Nothing -> error "no package name"+ Just cid -> HsComponentId pn cid+ Just hscid -> hscid++ renameHsUnit :: HsUnit PackageName -> HsUnit HsComponentId+ renameHsUnit u =+ HsUnit {+ hsunitName = fmap renamePackageName (hsunitName u),+ hsunitBody = map (fmap renameHsUnitDecl) (hsunitBody u)+ }++ renameHsUnitDecl :: HsUnitDecl PackageName -> HsUnitDecl HsComponentId+ renameHsUnitDecl (DeclD a b c) = DeclD a b c+ renameHsUnitDecl (IncludeD idecl) =+ IncludeD IncludeDecl {+ idUnitId = fmap renameHsUnitId (idUnitId idecl),+ idModRenaming = idModRenaming idecl,+ idSignatureInclude = idSignatureInclude idecl+ }++ renameHsUnitId :: HsUnitId PackageName -> HsUnitId HsComponentId+ renameHsUnitId (HsUnitId ln subst)+ = HsUnitId (fmap renamePackageName ln) (map (fmap renameHsModuleSubst) subst)++ renameHsModuleSubst :: HsModuleSubst PackageName -> HsModuleSubst HsComponentId+ renameHsModuleSubst (lk, lm)+ = (lk, fmap renameHsModuleId lm)++ renameHsModuleId :: HsModuleId PackageName -> HsModuleId HsComponentId+ renameHsModuleId (HsModuleVar lm) = HsModuleVar lm+ renameHsModuleId (HsModuleId luid lm) = HsModuleId (fmap renameHsUnitId luid) lm++convertHsUnitId :: HsUnitId HsComponentId -> UnitId+convertHsUnitId (HsUnitId (L _ hscid) subst)+ = newUnitId (hsComponentId hscid) (map (convertHsModuleSubst . unLoc) subst)++convertHsModuleSubst :: HsModuleSubst HsComponentId -> (ModuleName, Module)+convertHsModuleSubst (L _ modname, L _ m) = (modname, convertHsModuleId m)++convertHsModuleId :: HsModuleId HsComponentId -> Module+convertHsModuleId (HsModuleVar (L _ modname)) = mkHoleModule modname+convertHsModuleId (HsModuleId (L _ hsuid) (L _ modname)) = mkModule (convertHsUnitId hsuid) modname++++{-+************************************************************************+* *+ Module graph construction+* *+************************************************************************+-}++-- | This is our version of GhcMake.downsweep, but with a few modifications:+--+-- 1. Every module is required to be mentioned, so we don't do any funny+-- business with targets or recursively grabbing dependencies. (We+-- could support this in principle).+-- 2. We support inline modules, whose summary we have to synthesize ourself.+--+-- We don't bother trying to support GhcMake for now, it's more trouble+-- than it's worth for inline modules.+hsunitModuleGraph :: DynFlags -> HsUnit HsComponentId -> BkpM ModuleGraph+hsunitModuleGraph dflags unit = do+ let decls = hsunitBody unit+ pn = hsPackageName (unLoc (hsunitName unit))++ -- 1. Create a HsSrcFile/HsigFile summary for every+ -- explicitly mentioned module/signature.+ let get_decl (L _ (DeclD dt lmodname mb_hsmod)) = do+ let hsc_src = case dt of+ ModuleD -> HsSrcFile+ SignatureD -> HsigFile+ Just `fmap` summariseDecl pn hsc_src lmodname mb_hsmod+ get_decl _ = return Nothing+ nodes <- catMaybes `fmap` mapM get_decl decls++ -- 2. For each hole which does not already have an hsig file,+ -- create an "empty" hsig file to induce compilation for the+ -- requirement.+ let node_map = Map.fromList [ ((ms_mod_name n, ms_hsc_src n == HsigFile), n)+ | n <- nodes ]+ req_nodes <- fmap catMaybes . forM (thisUnitIdInsts dflags) $ \(mod_name, _) ->+ let has_local = Map.member (mod_name, True) node_map+ in if has_local+ then return Nothing+ else fmap Just $ summariseRequirement pn mod_name++ -- 3. Return the kaboodle+ return (nodes ++ req_nodes)++summariseRequirement :: PackageName -> ModuleName -> BkpM ModSummary+summariseRequirement pn mod_name = do+ hsc_env <- getSession+ let dflags = hsc_dflags hsc_env++ let PackageName pn_fs = pn+ location <- liftIO $ mkHomeModLocation2 dflags mod_name+ (unpackFS pn_fs </> moduleNameSlashes mod_name) "hsig"++ env <- getBkpEnv+ time <- liftIO $ getModificationUTCTime (bkp_filename env)+ hi_timestamp <- liftIO $ modificationTimeIfExists (ml_hi_file location)+ let loc = srcLocSpan (mkSrcLoc (mkFastString (bkp_filename env)) 1 1)++ mod <- liftIO $ addHomeModuleToFinder hsc_env mod_name location++ extra_sig_imports <- liftIO $ findExtraSigImports hsc_env HsigFile mod_name++ return ModSummary {+ ms_mod = mod,+ ms_hsc_src = HsigFile,+ ms_location = location,+ ms_hs_date = time,+ ms_obj_date = Nothing,+ ms_iface_date = hi_timestamp,+ ms_srcimps = [],+ ms_textual_imps = extra_sig_imports,+ ms_parsed_mod = Just (HsParsedModule {+ hpm_module = L loc (HsModule {+ hsmodName = Just (L loc mod_name),+ hsmodExports = Nothing,+ hsmodImports = [],+ hsmodDecls = [],+ hsmodDeprecMessage = Nothing,+ hsmodHaddockModHeader = Nothing+ }),+ hpm_src_files = [],+ hpm_annotations = (Map.empty, Map.empty)+ }),+ ms_hspp_file = "", -- none, it came inline+ ms_hspp_opts = dflags,+ ms_hspp_buf = Nothing+ }++summariseDecl :: PackageName+ -> HscSource+ -> Located ModuleName+ -> Maybe (Located (HsModule RdrName))+ -> BkpM ModSummary+summariseDecl pn hsc_src (L _ modname) (Just hsmod) = hsModuleToModSummary pn hsc_src modname hsmod+summariseDecl _pn hsc_src lmodname@(L loc modname) Nothing+ = do hsc_env <- getSession+ let dflags = hsc_dflags hsc_env+ -- TODO: this looks for modules in the wrong place+ r <- liftIO $ summariseModule hsc_env+ Map.empty -- GHC API recomp not supported+ (hscSourceToIsBoot hsc_src)+ lmodname+ True -- Target lets you disallow, but not here+ Nothing -- GHC API buffer support not supported+ [] -- No exclusions+ case r of+ Nothing -> throwOneError (mkPlainErrMsg dflags loc (text "module" <+> ppr modname <+> text "was not found"))+ Just (Left err) -> throwOneError err+ Just (Right summary) -> return summary++-- | Up until now, GHC has assumed a single compilation target per source file.+-- Backpack files with inline modules break this model, since a single file+-- may generate multiple output files. How do we decide to name these files?+-- Should there only be one output file? This function our current heuristic,+-- which is we make a "fake" module and use that.+hsModuleToModSummary :: PackageName+ -> HscSource+ -> ModuleName+ -> Located (HsModule RdrName)+ -> BkpM ModSummary+hsModuleToModSummary pn hsc_src modname+ hsmod = do+ let imps = hsmodImports (unLoc hsmod)+ loc = getLoc hsmod+ hsc_env <- getSession+ -- Sort of the same deal as in DriverPipeline's getLocation+ -- Use the PACKAGE NAME to find the location+ let PackageName unit_fs = pn+ dflags = hsc_dflags hsc_env+ -- Unfortunately, we have to define a "fake" location in+ -- order to appease the various code which uses the file+ -- name to figure out where to put, e.g. object files.+ -- 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 dflags modname+ (unpackFS unit_fs </>+ moduleNameSlashes modname)+ (case hsc_src of+ HsigFile -> "hsig"+ HsBootFile -> "hs-boot"+ HsSrcFile -> "hs")+ -- DANGEROUS: bootifying can POISON the module finder cache+ let location = case hsc_src of+ HsBootFile -> addBootSuffixLocn location0+ _ -> location0+ -- This duplicates a pile of logic in GhcMake+ env <- getBkpEnv+ time <- liftIO $ getModificationUTCTime (bkp_filename env)+ hi_timestamp <- liftIO $ modificationTimeIfExists (ml_hi_file location)++ -- Also copied from 'getImports'+ let (src_idecls, ord_idecls) = partition (ideclSource.unLoc) imps++ -- GHC.Prim doesn't exist physically, so don't go looking for it.+ ordinary_imps = filter ((/= moduleName gHC_PRIM) . unLoc . ideclName . unLoc)+ ord_idecls++ implicit_prelude = xopt LangExt.ImplicitPrelude dflags+ implicit_imports = mkPrelImports modname loc+ implicit_prelude imps+ convImport (L _ i) = (fmap sl_fs (ideclPkgQual i), ideclName i)++ extra_sig_imports <- liftIO $ findExtraSigImports hsc_env hsc_src modname++ let normal_imports = map convImport (implicit_imports ++ ordinary_imps)+ required_by_imports <- liftIO $ implicitRequirements hsc_env normal_imports++ -- So that Finder can find it, even though it doesn't exist...+ this_mod <- liftIO $ addHomeModuleToFinder hsc_env modname location+ return ModSummary {+ ms_mod = this_mod,+ ms_hsc_src = hsc_src,+ ms_location = location,+ ms_hspp_file = (case hiDir dflags of+ Nothing -> ""+ Just d -> d) </> ".." </> moduleNameSlashes modname <.> "hi",+ ms_hspp_opts = dflags,+ ms_hspp_buf = Nothing,+ ms_srcimps = map convImport src_idecls,+ ms_textual_imps = normal_imports+ -- We have to do something special here:+ -- due to merging, requirements may end up with+ -- extra imports+ ++ extra_sig_imports+ ++ required_by_imports,+ -- This is our hack to get the parse tree to the right spot+ ms_parsed_mod = Just (HsParsedModule {+ hpm_module = hsmod,+ hpm_src_files = [], -- TODO if we preprocessed it+ hpm_annotations = (Map.empty, Map.empty) -- BOGUS+ }),+ ms_hs_date = time,+ ms_obj_date = Nothing, -- TODO do this, but problem: hi_timestamp is BOGUS+ ms_iface_date = hi_timestamp+ }++-- | Create a new, externally provided hashed unit id from+-- a hash.+newInstalledUnitId :: ComponentId -> Maybe FastString -> InstalledUnitId+newInstalledUnitId (ComponentId cid_fs) (Just fs)+ = InstalledUnitId (cid_fs `appendFS` mkFastString "+" `appendFS` fs)+newInstalledUnitId (ComponentId cid_fs) Nothing+ = InstalledUnitId cid_fs
+ backpack/NameShape.hs view
@@ -0,0 +1,266 @@+{-# LANGUAGE CPP #-}++module NameShape(+ NameShape(..),+ emptyNameShape,+ mkNameShape,+ extendNameShape,+ nameShapeExports,+ substNameShape,+ maybeSubstNameShape,+ ) where++#include "HsVersions.h"++import Outputable+import HscTypes+import Module+import UniqFM+import Avail+import FieldLabel++import Name+import NameEnv+import TcRnMonad+import Util+import IfaceEnv++import Control.Monad++-- Note [NameShape]+-- ~~~~~~~~~~~~~~~~+-- When we write a declaration in a signature, e.g., data T, we+-- ascribe to it a *name variable*, e.g., {m.T}. This+-- name variable may be substituted with an actual original+-- name when the signature is implemented (or even if we+-- merge the signature with one which reexports this entity+-- from another module).++-- When we instantiate a signature m with a module M,+-- we also need to substitute over names. To do so, we must+-- compute the *name substitution* induced by the *exports*+-- of the module in question. A NameShape represents+-- such a name substitution for a single module instantiation.+-- The "shape" in the name comes from the fact that the computation+-- of a name substitution is essentially the *shaping pass* from+-- Backpack'14, but in a far more restricted form.++-- The name substitution for an export list is easy to explain. If we are+-- filling the module variable <m>, given an export N of the form+-- M.n or {m'.n} (where n is an OccName), the induced name+-- substitution is from {m.n} to N. So, for example, if we have+-- A=impl:B, and the exports of impl:B are impl:B.f and+-- impl:C.g, then our name substitution is {A.f} to impl:B.f+-- and {A.g} to impl:C.g+++++-- The 'NameShape' type is defined in TcRnTypes, because TcRnTypes+-- needs to refer to NameShape, and having TcRnTypes import+-- NameShape (even by SOURCE) would cause a large number of+-- modules to be pulled into the DynFlags cycle.+{-+data NameShape = NameShape {+ ns_mod_name :: ModuleName,+ ns_exports :: [AvailInfo],+ ns_map :: OccEnv Name+ }+-}++-- NB: substitution functions need 'HscEnv' since they need the name cache+-- to allocate new names if we change the 'Module' of a 'Name'++-- | Create an empty 'NameShape' (i.e., the renaming that+-- would occur with an implementing module with no exports)+-- for a specific hole @mod_name@.+emptyNameShape :: ModuleName -> NameShape+emptyNameShape mod_name = NameShape mod_name [] emptyOccEnv++-- | Create a 'NameShape' corresponding to an implementing+-- module for the hole @mod_name@ that exports a list of 'AvailInfo's.+mkNameShape :: ModuleName -> [AvailInfo] -> NameShape+mkNameShape mod_name as =+ NameShape mod_name as $ mkOccEnv $ do+ a <- as+ n <- availName a : availNamesWithSelectors a+ return (occName n, n)++-- | Given an existing 'NameShape', merge it with a list of 'AvailInfo's+-- with Backpack style mix-in linking. This is used solely when merging+-- signatures together: we successively merge the exports of each+-- signature until we have the final, full exports of the merged signature.+--+-- What makes this operation nontrivial is what we are supposed to do when+-- we want to merge in an export for M.T when we already have an existing+-- export {H.T}. What should happen in this case is that {H.T} should be+-- unified with @M.T@: we've determined a more *precise* identity for the+-- export at 'OccName' @T@.+--+-- Note that we don't do unrestricted unification: only name holes from+-- @ns_mod_name ns@ are flexible. This is because we have a much more+-- restricted notion of shaping than in Backpack'14: we do shaping+-- *as* we do type-checking. Thus, once we shape a signature, its+-- exports are *final* and we're not allowed to refine them further,+extendNameShape :: HscEnv -> NameShape -> [AvailInfo] -> IO (Either SDoc NameShape)+extendNameShape hsc_env ns as =+ case uAvailInfos (ns_mod_name ns) (ns_exports ns) as of+ Left err -> return (Left err)+ Right nsubst -> do+ as1 <- mapM (liftIO . substNameAvailInfo hsc_env nsubst) (ns_exports ns)+ as2 <- mapM (liftIO . substNameAvailInfo hsc_env nsubst) as+ let new_avails = mergeAvails as1 as2+ return . Right $ ns {+ ns_exports = new_avails,+ -- TODO: stop repeatedly rebuilding the OccEnv+ ns_map = mkOccEnv $ do+ a <- new_avails+ n <- availName a : availNames a+ return (occName n, n)+ }++-- | The export list associated with this 'NameShape' (i.e., what+-- the exports of an implementing module which induces this 'NameShape'+-- would be.)+nameShapeExports :: NameShape -> [AvailInfo]+nameShapeExports = ns_exports++-- | Given a 'Name', substitute it according to the 'NameShape' implied+-- substitution, i.e. map @{A.T}@ to @M.T@, if the implementing module+-- exports @M.T@.+substNameShape :: NameShape -> Name -> Name+substNameShape ns n | nameModule n == ns_module ns+ , Just n' <- lookupOccEnv (ns_map ns) (occName n)+ = n'+ | otherwise+ = n++-- | Like 'substNameShape', but returns @Nothing@ if no substitution+-- works.+maybeSubstNameShape :: NameShape -> Name -> Maybe Name+maybeSubstNameShape ns n+ | nameModule n == ns_module ns+ = lookupOccEnv (ns_map ns) (occName n)+ | otherwise+ = Nothing++-- | The 'Module' of any 'Name's a 'NameShape' has action over.+ns_module :: NameShape -> Module+ns_module = mkHoleModule . ns_mod_name++{-+************************************************************************+* *+ Name substitutions+* *+************************************************************************+-}++-- | Substitution on @{A.T}@. We enforce the invariant that the+-- 'nameModule' of keys of this map have 'moduleUnitId' @hole@+-- (meaning that if we have a hole substitution, the keys of the map+-- are never affected.) Alternately, this is isomorphic to+-- @Map ('ModuleName', 'OccName') 'Name'@.+type ShNameSubst = NameEnv Name++-- NB: In this module, we actually only ever construct 'ShNameSubst'+-- at a single 'ModuleName'. But 'ShNameSubst' is more convenient to+-- work with.++-- | Substitute names in a 'Name'.+substName :: ShNameSubst -> Name -> Name+substName env n | Just n' <- lookupNameEnv env n = n'+ | otherwise = n++-- | Substitute names in an 'AvailInfo'. This has special behavior+-- for type constructors, where it is sufficient to substitute the 'availName'+-- to induce a substitution on 'availNames'.+substNameAvailInfo :: HscEnv -> ShNameSubst -> AvailInfo -> IO AvailInfo+substNameAvailInfo _ env (Avail n) = return (Avail (substName env n))+substNameAvailInfo hsc_env env (AvailTC n ns fs) =+ let mb_mod = fmap nameModule (lookupNameEnv env n)+ in AvailTC (substName env n)+ <$> mapM (initIfaceLoad hsc_env . setNameModule mb_mod) ns+ <*> mapM (setNameFieldSelector hsc_env mb_mod) fs++-- | Set the 'Module' of a 'FieldSelector'+setNameFieldSelector :: HscEnv -> Maybe Module -> FieldLabel -> IO FieldLabel+setNameFieldSelector _ Nothing f = return f+setNameFieldSelector hsc_env mb_mod (FieldLabel l b sel) = do+ sel' <- initIfaceLoad hsc_env $ setNameModule mb_mod sel+ return (FieldLabel l b sel')++{-+************************************************************************+* *+ AvailInfo merging+* *+************************************************************************+-}++-- | Merges to 'AvailInfo' lists together, assuming the 'AvailInfo's have+-- already been unified ('uAvailInfos').+mergeAvails :: [AvailInfo] -> [AvailInfo] -> [AvailInfo]+mergeAvails as1 as2 =+ let mkNE as = mkNameEnv [(availName a, a) | a <- as]+ in nameEnvElts (plusNameEnv_C plusAvail (mkNE as1) (mkNE as2))++{-+************************************************************************+* *+ AvailInfo unification+* *+************************************************************************+-}++-- | Unify two lists of 'AvailInfo's, given an existing substitution @subst@,+-- with only name holes from @flexi@ unifiable (all other name holes rigid.)+uAvailInfos :: ModuleName -> [AvailInfo] -> [AvailInfo] -> Either SDoc ShNameSubst+uAvailInfos flexi as1 as2 = -- pprTrace "uAvailInfos" (ppr as1 $$ ppr as2) $+ let mkOE as = listToUFM $ do a <- as+ n <- availNames a+ return (nameOccName n, a)+ in foldM (\subst (a1, a2) -> uAvailInfo flexi subst a1 a2) emptyNameEnv+ (eltsUFM (intersectUFM_C (,) (mkOE as1) (mkOE as2)))+ -- Edward: I have to say, this is pretty clever.++-- | Unify two 'AvailInfo's, given an existing substitution @subst@,+-- with only name holes from @flexi@ unifiable (all other name holes rigid.)+uAvailInfo :: ModuleName -> ShNameSubst -> AvailInfo -> AvailInfo+ -> Either SDoc ShNameSubst+uAvailInfo flexi subst (Avail n1) (Avail n2) = uName flexi subst n1 n2+uAvailInfo flexi subst (AvailTC n1 _ _) (AvailTC n2 _ _) = uName flexi subst n1 n2+uAvailInfo _ _ a1 a2 = Left $ text "While merging export lists, could not combine"+ <+> ppr a1 <+> text "with" <+> ppr a2+ <+> parens (text "one is a type, the other is a plain identifier")++-- | Unify two 'Name's, given an existing substitution @subst@,+-- with only name holes from @flexi@ unifiable (all other name holes rigid.)+uName :: ModuleName -> ShNameSubst -> Name -> Name -> Either SDoc ShNameSubst+uName flexi subst n1 n2+ | n1 == n2 = Right subst+ | isFlexi n1 = uHoleName flexi subst n1 n2+ | isFlexi n2 = uHoleName flexi subst n2 n1+ | otherwise = Left (text "While merging export lists, could not unify"+ <+> ppr n1 <+> text "with" <+> ppr n2 $$ extra)+ where+ isFlexi n = isHoleName n && moduleName (nameModule n) == flexi+ extra | isHoleName n1 || isHoleName n2+ = text "Neither name variable originates from the current signature."+ | otherwise+ = empty++-- | Unify a name @h@ which 'isHoleName' with another name, given an existing+-- substitution @subst@, with only name holes from @flexi@ unifiable (all+-- other name holes rigid.)+uHoleName :: ModuleName -> ShNameSubst -> Name {- hole name -} -> Name+ -> Either SDoc ShNameSubst+uHoleName flexi subst h n =+ ASSERT( isHoleName h )+ case lookupNameEnv subst h of+ Just n' -> uName flexi subst n' n+ -- Do a quick check if the other name is substituted.+ Nothing | Just n' <- lookupNameEnv subst n ->+ ASSERT( isHoleName n ) uName flexi subst h n'+ | otherwise ->+ Right (extendNameEnv subst h n)
+ backpack/RnModIface.hs view
@@ -0,0 +1,707 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}++-- | This module implements interface renaming, which is+-- used to rewrite interface files on the fly when we+-- are doing indefinite typechecking and need instantiations+-- of modules which do not necessarily exist yet.++module RnModIface(+ rnModIface,+ rnModExports,+ tcRnModIface,+ tcRnModExports,+ ) where++#include "HsVersions.h"++import SrcLoc+import Outputable+import HscTypes+import Module+import UniqFM+import Avail+import IfaceSyn+import FieldLabel+import Var+import ErrUtils++import Name+import TcRnMonad+import Util+import Fingerprint+import BasicTypes++-- a bit vexing+import {-# SOURCE #-} LoadIface+import DynFlags++import qualified Data.Traversable as T++import Bag+import Data.IORef+import NameShape+import IfaceEnv++tcRnMsgMaybe :: IO (Either ErrorMessages a) -> TcM a+tcRnMsgMaybe do_this = do+ r <- liftIO $ do_this+ case r of+ Left errs -> do+ addMessages (emptyBag, errs)+ failM+ Right x -> return x++tcRnModIface :: [(ModuleName, Module)] -> Maybe NameShape -> ModIface -> TcM ModIface+tcRnModIface x y z = do+ hsc_env <- getTopEnv+ tcRnMsgMaybe $ rnModIface hsc_env x y z++tcRnModExports :: [(ModuleName, Module)] -> ModIface -> TcM [AvailInfo]+tcRnModExports x y = do+ hsc_env <- getTopEnv+ tcRnMsgMaybe $ rnModExports hsc_env x y++failWithRn :: SDoc -> ShIfM a+failWithRn doc = do+ errs_var <- fmap sh_if_errs getGblEnv+ dflags <- getDynFlags+ errs <- readTcRef errs_var+ -- TODO: maybe associate this with a source location?+ writeTcRef errs_var (errs `snocBag` mkPlainErrMsg dflags noSrcSpan doc)+ failM++-- | What we have is a generalized ModIface, which corresponds to+-- a module that looks like p[A=<A>]:B. We need a *specific* ModIface, e.g.+-- p[A=q():A]:B (or maybe even p[A=<B>]:B) which we load+-- up (either to merge it, or to just use during typechecking).+--+-- Suppose we have:+--+-- p[A=<A>]:M ==> p[A=q():A]:M+--+-- Substitute all occurrences of <A> with q():A (renameHoleModule).+-- Then, for any Name of form {A.T}, replace the Name with+-- the Name according to the exports of the implementing module.+-- This works even for p[A=<B>]:M, since we just read in the+-- exports of B.hi, which is assumed to be ready now.+--+-- This function takes an optional 'NameShape', which can be used+-- to further refine the identities in this interface: suppose+-- we read a declaration for {H.T} but we actually know that this+-- should be Foo.T; then we'll also rename this (this is used+-- when loading an interface to merge it into a requirement.)+rnModIface :: HscEnv -> [(ModuleName, Module)] -> Maybe NameShape+ -> ModIface -> IO (Either ErrorMessages ModIface)+rnModIface hsc_env insts nsubst iface = do+ initRnIface hsc_env iface insts nsubst $ do+ mod <- rnModule (mi_module iface)+ sig_of <- case mi_sig_of iface of+ Nothing -> return Nothing+ Just x -> fmap Just (rnModule x)+ exports <- mapM rnAvailInfo (mi_exports iface)+ decls <- mapM rnIfaceDecl' (mi_decls iface)+ insts <- mapM rnIfaceClsInst (mi_insts iface)+ fams <- mapM rnIfaceFamInst (mi_fam_insts iface)+ deps <- rnDependencies (mi_deps iface)+ -- TODO:+ -- mi_rules+ -- mi_vect_info (LOW PRIORITY)+ return iface { mi_module = mod+ , mi_sig_of = sig_of+ , mi_insts = insts+ , mi_fam_insts = fams+ , mi_exports = exports+ , mi_decls = decls+ , mi_deps = deps }++-- | Rename just the exports of a 'ModIface'. Useful when we're doing+-- shaping prior to signature merging.+rnModExports :: HscEnv -> [(ModuleName, Module)] -> ModIface -> IO (Either ErrorMessages [AvailInfo])+rnModExports hsc_env insts iface+ = initRnIface hsc_env iface insts Nothing+ $ mapM rnAvailInfo (mi_exports iface)++rnDependencies :: Rename Dependencies+rnDependencies deps = do+ orphs <- rnDepModules dep_orphs deps+ finsts <- rnDepModules dep_finsts deps+ return deps { dep_orphs = orphs, dep_finsts = finsts }++rnDepModules :: (Dependencies -> [Module]) -> Dependencies -> ShIfM [Module]+rnDepModules sel deps = do+ hsc_env <- getTopEnv+ hmap <- getHoleSubst+ -- NB: It's not necessary to test if we're doing signature renaming,+ -- because ModIface will never contain module reference for itself+ -- in these dependencies.+ fmap (nubSort . concat) . T.forM (sel deps) $ \mod -> do+ dflags <- getDynFlags+ let mod' = renameHoleModule dflags hmap mod+ iface <- liftIO . initIfaceCheck (text "rnDepModule") hsc_env+ $ loadSysInterface (text "rnDepModule") mod'+ return (mod' : sel (mi_deps iface))++{-+************************************************************************+* *+ ModIface substitution+* *+************************************************************************+-}++-- | Run a computation in the 'ShIfM' monad.+initRnIface :: HscEnv -> ModIface -> [(ModuleName, Module)] -> Maybe NameShape+ -> ShIfM a -> IO (Either ErrorMessages a)+initRnIface hsc_env iface insts nsubst do_this = do+ errs_var <- newIORef emptyBag+ let dflags = hsc_dflags hsc_env+ hsubst = listToUFM insts+ rn_mod = renameHoleModule dflags hsubst+ env = ShIfEnv {+ sh_if_module = rn_mod (mi_module iface),+ sh_if_semantic_module = rn_mod (mi_semantic_module iface),+ sh_if_hole_subst = listToUFM insts,+ sh_if_shape = nsubst,+ sh_if_errs = errs_var+ }+ -- Modeled off of 'initTc'+ res <- initTcRnIf 'c' hsc_env env () $ tryM do_this+ msgs <- readIORef errs_var+ case res of+ Left _ -> return (Left msgs)+ Right r | not (isEmptyBag msgs) -> return (Left msgs)+ | otherwise -> return (Right r)++-- | Environment for 'ShIfM' monads.+data ShIfEnv = ShIfEnv {+ -- What we are renaming the ModIface to. It assumed that+ -- the original mi_module of the ModIface is+ -- @generalizeModule (mi_module iface)@.+ sh_if_module :: Module,+ -- The semantic module that we are renaming to+ sh_if_semantic_module :: Module,+ -- Cached hole substitution, e.g.+ -- @sh_if_hole_subst == listToUFM . unitIdInsts . moduleUnitId . sh_if_module@+ sh_if_hole_subst :: ShHoleSubst,+ -- An optional name substitution to be applied when renaming+ -- the names in the interface. If this is 'Nothing', then+ -- we just load the target interface and look at the export+ -- list to determine the renaming.+ sh_if_shape :: Maybe NameShape,+ -- Mutable reference to keep track of errors (similar to 'tcl_errs')+ sh_if_errs :: IORef ErrorMessages+ }++getHoleSubst :: ShIfM ShHoleSubst+getHoleSubst = fmap sh_if_hole_subst getGblEnv++type ShIfM = TcRnIf ShIfEnv ()+type Rename a = a -> ShIfM a+++rnModule :: Rename Module+rnModule mod = do+ hmap <- getHoleSubst+ dflags <- getDynFlags+ return (renameHoleModule dflags hmap mod)++rnAvailInfo :: Rename AvailInfo+rnAvailInfo (Avail n) = Avail <$> rnIfaceGlobal n+rnAvailInfo (AvailTC n ns fs) = do+ -- Why don't we rnIfaceGlobal the availName itself? It may not+ -- actually be exported by the module it putatively is from, in+ -- which case we won't be able to tell what the name actually+ -- is. But for the availNames they MUST be exported, so they+ -- will rename fine.+ ns' <- mapM rnIfaceGlobal ns+ fs' <- mapM rnFieldLabel fs+ case ns' ++ map flSelector fs' of+ [] -> panic "rnAvailInfoEmpty AvailInfo"+ (rep:rest) -> ASSERT2( all ((== nameModule rep) . nameModule) rest, ppr rep $$ hcat (map ppr rest) ) do+ n' <- setNameModule (Just (nameModule rep)) n+ return (AvailTC n' ns' fs')++rnFieldLabel :: Rename FieldLabel+rnFieldLabel (FieldLabel l b sel) = do+ sel' <- rnIfaceGlobal sel+ return (FieldLabel l b sel')+++++-- | The key function. This gets called on every Name embedded+-- inside a ModIface. Our job is to take a Name from some+-- generalized unit ID p[A=<A>, B=<B>], and change+-- it to the correct name for a (partially) instantiated unit+-- ID, e.g. p[A=q[]:A, B=<B>].+--+-- There are two important things to do:+--+-- If a hole is substituted with a real module implementation,+-- we need to look at that actual implementation to determine what+-- the true identity of this name should be. We'll do this by+-- loading that module's interface and looking at the mi_exports.+--+-- However, there is one special exception: when we are loading+-- the interface of a requirement. In this case, we may not have+-- the "implementing" interface, because we are reading this+-- interface precisely to "merge it in".+--+-- External case:+-- p[A=<B>]:A (and thisUnitId is something else)+-- We are loading this in order to determine B.hi! So+-- don't load B.hi to find the exports.+--+-- Local case:+-- p[A=<A>]:A (and thisUnitId is p[A=<A>])+-- This should not happen, because the rename is not necessary+-- in this case, but if it does we shouldn't load A.hi!+--+-- Compare me with 'tcIfaceGlobal'!++-- In effect, this function needs compute the name substitution on the+-- fly. What it has is the name that we would like to substitute.+-- If the name is not a hole name {M.x} (e.g. isHoleModule) then+-- no renaming can take place (although the inner hole structure must+-- be updated to account for the hole module renaming.)+rnIfaceGlobal :: Name -> ShIfM Name+rnIfaceGlobal n = do+ hsc_env <- getTopEnv+ let dflags = hsc_dflags hsc_env+ iface_semantic_mod <- fmap sh_if_semantic_module getGblEnv+ mb_nsubst <- fmap sh_if_shape getGblEnv+ hmap <- getHoleSubst+ let m = nameModule n+ m' = renameHoleModule dflags hmap m+ case () of+ -- Did we encounter {A.T} while renaming p[A=<B>]:A? If so,+ -- do NOT assume B.hi is available.+ -- In this case, rename {A.T} to {B.T} but don't look up exports.+ _ | m' == iface_semantic_mod+ , isHoleModule m'+ -- NB: this could be Nothing for computeExports, we have+ -- nothing to say.+ -> do n' <- setNameModule (Just m') n+ case mb_nsubst of+ Nothing -> return n'+ Just nsubst ->+ case maybeSubstNameShape nsubst n' of+ -- TODO: would love to have context+ -- TODO: This will give an unpleasant message if n'+ -- is a constructor; then we'll suggest adding T+ -- but it won't work.+ Nothing -> failWithRn $ vcat [+ text "The identifier" <+> ppr (occName n') <+>+ text "does not exist in the local signature.",+ parens (text "Try adding it to the export list of the hsig file.")+ ]+ Just n'' -> return n''+ -- Fastpath: we are renaming p[H=<H>]:A.T, in which case the+ -- export list is irrelevant.+ | not (isHoleModule m)+ -> setNameModule (Just m') n+ -- The substitution was from <A> to p[]:A.+ -- But this does not mean {A.T} goes to p[]:A.T:+ -- p[]:A may reexport T from somewhere else. Do the name+ -- substitution. Furthermore, we need+ -- to make sure we pick the accurate name NOW,+ -- or we might accidentally reject a merge.+ | otherwise+ -> do -- Make sure we look up the local interface if substitution+ -- went from <A> to <B>.+ let m'' = if isHoleModule m'+ -- Pull out the local guy!!+ then mkModule (thisPackage dflags) (moduleName m')+ else m'+ iface <- liftIO . initIfaceCheck (text "rnIfaceGlobal") hsc_env+ $ loadSysInterface (text "rnIfaceGlobal") m''+ let nsubst = mkNameShape (moduleName m) (mi_exports iface)+ case maybeSubstNameShape nsubst n of+ Nothing -> failWithRn $ vcat [+ text "The identifier" <+> ppr (occName n) <+>+ -- NB: report m' because it's more user-friendly+ text "does not exist in the signature for" <+> ppr m',+ parens (text "Try adding it to the export list in that hsig file.")+ ]+ Just n' -> return n'++-- | Rename an implicit name, e.g., a DFun or coercion axiom.+-- Here is where we ensure that DFuns have the correct module as described in+-- Note [rnIfaceNeverExported].+rnIfaceNeverExported :: Name -> ShIfM Name+rnIfaceNeverExported name = do+ hmap <- getHoleSubst+ dflags <- getDynFlags+ iface_semantic_mod <- fmap sh_if_semantic_module getGblEnv+ let m = renameHoleModule dflags hmap $ nameModule name+ -- Doublecheck that this DFun/coercion axiom was, indeed, locally defined.+ MASSERT2( iface_semantic_mod == m, ppr iface_semantic_mod <+> ppr m )+ setNameModule (Just m) name++-- Note [rnIfaceNeverExported]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- For the high-level overview, see+-- Note [Handling never-exported TyThings under Backpack]+--+-- When we see a reference to an entity that was defined in a signature,+-- 'rnIfaceGlobal' relies on the identifier in question being part of the+-- exports of the implementing 'ModIface', so that we can use the exports to+-- decide how to rename the identifier. Unfortunately, references to 'DFun's+-- and 'CoAxiom's will run into trouble under this strategy, because they are+-- never exported.+--+-- Let us consider first what should happen in the absence of promotion. In+-- this setting, a reference to a 'DFun' or a 'CoAxiom' can only occur inside+-- the signature *that is defining it* (as there are no Core terms in+-- typechecked-only interface files, there's no way for a reference to occur+-- besides from the defining 'ClsInst' or closed type family). Thus,+-- it doesn't really matter what names we give the DFun/CoAxiom, as long+-- as it's consistent between the declaration site and the use site.+--+-- We have to make sure that these bogus names don't get propagated,+-- but it is fine: see Note [Signature merging DFuns] for the fixups+-- to the names we do before writing out the merged interface.+-- (It's even easier for instantiation, since the DFuns all get+-- dropped entirely; the instances are reexported implicitly.)+--+-- Unfortunately, this strategy is not enough in the presence of promotion+-- (see bug #13149), where modules which import the signature may make+-- reference to their coercions. It's not altogether clear how to+-- fix this case, but it is definitely a bug!++-- PILES AND PILES OF BOILERPLATE++-- | Rename an 'IfaceClsInst', with special handling for an associated+-- dictionary function.+rnIfaceClsInst :: Rename IfaceClsInst+rnIfaceClsInst cls_inst = do+ n <- rnIfaceGlobal (ifInstCls cls_inst)+ tys <- mapM rnMaybeIfaceTyCon (ifInstTys cls_inst)++ dfun <- rnIfaceNeverExported (ifDFun cls_inst)+ return cls_inst { ifInstCls = n+ , ifInstTys = tys+ , ifDFun = dfun+ }++rnMaybeIfaceTyCon :: Rename (Maybe IfaceTyCon)+rnMaybeIfaceTyCon Nothing = return Nothing+rnMaybeIfaceTyCon (Just tc) = Just <$> rnIfaceTyCon tc++rnIfaceFamInst :: Rename IfaceFamInst+rnIfaceFamInst d = do+ fam <- rnIfaceGlobal (ifFamInstFam d)+ tys <- mapM rnMaybeIfaceTyCon (ifFamInstTys d)+ axiom <- rnIfaceGlobal (ifFamInstAxiom d)+ return d { ifFamInstFam = fam, ifFamInstTys = tys, ifFamInstAxiom = axiom }++rnIfaceDecl' :: Rename (Fingerprint, IfaceDecl)+rnIfaceDecl' (fp, decl) = (,) fp <$> rnIfaceDecl decl++rnIfaceDecl :: Rename IfaceDecl+rnIfaceDecl d@IfaceId{} = do+ name <- case ifIdDetails d of+ IfDFunId -> rnIfaceNeverExported (ifName d)+ _ | isDefaultMethodOcc (occName (ifName d))+ -> rnIfaceNeverExported (ifName d)+ -- Typeable bindings. See Note [Grand plan for Typeable].+ _ | isTypeableBindOcc (occName (ifName d))+ -> rnIfaceNeverExported (ifName d)+ | otherwise -> rnIfaceGlobal (ifName d)+ ty <- rnIfaceType (ifType d)+ details <- rnIfaceIdDetails (ifIdDetails d)+ info <- rnIfaceIdInfo (ifIdInfo d)+ return d { ifName = name+ , ifType = ty+ , ifIdDetails = details+ , ifIdInfo = info+ }+rnIfaceDecl d@IfaceData{} = do+ name <- rnIfaceGlobal (ifName d)+ binders <- mapM rnIfaceTyConBinder (ifBinders d)+ ctxt <- mapM rnIfaceType (ifCtxt d)+ cons <- rnIfaceConDecls (ifCons d)+ parent <- rnIfaceTyConParent (ifParent d)+ return d { ifName = name+ , ifBinders = binders+ , ifCtxt = ctxt+ , ifCons = cons+ , ifParent = parent+ }+rnIfaceDecl d@IfaceSynonym{} = do+ name <- rnIfaceGlobal (ifName d)+ binders <- mapM rnIfaceTyConBinder (ifBinders d)+ syn_kind <- rnIfaceType (ifResKind d)+ syn_rhs <- rnIfaceType (ifSynRhs d)+ return d { ifName = name+ , ifBinders = binders+ , ifResKind = syn_kind+ , ifSynRhs = syn_rhs+ }+rnIfaceDecl d@IfaceFamily{} = do+ name <- rnIfaceGlobal (ifName d)+ binders <- mapM rnIfaceTyConBinder (ifBinders d)+ fam_kind <- rnIfaceType (ifResKind d)+ fam_flav <- rnIfaceFamTyConFlav (ifFamFlav d)+ return d { ifName = name+ , ifBinders = binders+ , ifResKind = fam_kind+ , ifFamFlav = fam_flav+ }+rnIfaceDecl d@IfaceClass{} = do+ name <- rnIfaceGlobal (ifName d)+ binders <- mapM rnIfaceTyConBinder (ifBinders d)+ body <- rnIfaceClassBody (ifBody d)+ return d { ifName = name+ , ifBinders = binders+ , ifBody = body+ }+rnIfaceDecl d@IfaceAxiom{} = do+ name <- rnIfaceNeverExported (ifName d)+ tycon <- rnIfaceTyCon (ifTyCon d)+ ax_branches <- mapM rnIfaceAxBranch (ifAxBranches d)+ return d { ifName = name+ , ifTyCon = tycon+ , ifAxBranches = ax_branches+ }+rnIfaceDecl d@IfacePatSyn{} = do+ name <- rnIfaceGlobal (ifName d)+ let rnPat (n, b) = (,) <$> rnIfaceGlobal n <*> pure b+ pat_matcher <- rnPat (ifPatMatcher d)+ pat_builder <- T.traverse rnPat (ifPatBuilder d)+ pat_univ_bndrs <- mapM rnIfaceForAllBndr (ifPatUnivBndrs d)+ pat_ex_bndrs <- mapM rnIfaceForAllBndr (ifPatExBndrs d)+ pat_prov_ctxt <- mapM rnIfaceType (ifPatProvCtxt d)+ pat_req_ctxt <- mapM rnIfaceType (ifPatReqCtxt d)+ pat_args <- mapM rnIfaceType (ifPatArgs d)+ pat_ty <- rnIfaceType (ifPatTy d)+ return d { ifName = name+ , ifPatMatcher = pat_matcher+ , ifPatBuilder = pat_builder+ , ifPatUnivBndrs = pat_univ_bndrs+ , ifPatExBndrs = pat_ex_bndrs+ , ifPatProvCtxt = pat_prov_ctxt+ , ifPatReqCtxt = pat_req_ctxt+ , ifPatArgs = pat_args+ , ifPatTy = pat_ty+ }++rnIfaceClassBody :: Rename IfaceClassBody+rnIfaceClassBody IfAbstractClass = return IfAbstractClass+rnIfaceClassBody d@IfConcreteClass{} = do+ ctxt <- mapM rnIfaceType (ifClassCtxt d)+ ats <- mapM rnIfaceAT (ifATs d)+ sigs <- mapM rnIfaceClassOp (ifSigs d)+ return d { ifClassCtxt = ctxt, ifATs = ats, ifSigs = sigs }++rnIfaceFamTyConFlav :: Rename IfaceFamTyConFlav+rnIfaceFamTyConFlav (IfaceClosedSynFamilyTyCon (Just (n, axs)))+ = IfaceClosedSynFamilyTyCon . Just <$> ((,) <$> rnIfaceNeverExported n+ <*> mapM rnIfaceAxBranch axs)+rnIfaceFamTyConFlav flav = pure flav++rnIfaceAT :: Rename IfaceAT+rnIfaceAT (IfaceAT decl mb_ty)+ = IfaceAT <$> rnIfaceDecl decl <*> T.traverse rnIfaceType mb_ty++rnIfaceTyConParent :: Rename IfaceTyConParent+rnIfaceTyConParent (IfDataInstance n tc args)+ = IfDataInstance <$> rnIfaceGlobal n+ <*> rnIfaceTyCon tc+ <*> rnIfaceTcArgs args+rnIfaceTyConParent IfNoParent = pure IfNoParent++rnIfaceConDecls :: Rename IfaceConDecls+rnIfaceConDecls (IfDataTyCon ds)+ = IfDataTyCon <$> mapM rnIfaceConDecl ds+rnIfaceConDecls (IfNewTyCon d) = IfNewTyCon <$> rnIfaceConDecl d+rnIfaceConDecls IfAbstractTyCon = pure IfAbstractTyCon++rnIfaceConDecl :: Rename IfaceConDecl+rnIfaceConDecl d = do+ con_name <- rnIfaceGlobal (ifConName d)+ con_ex_tvs <- mapM rnIfaceForAllBndr (ifConExTvs d)+ let rnIfConEqSpec (n,t) = (,) n <$> rnIfaceType t+ con_eq_spec <- mapM rnIfConEqSpec (ifConEqSpec d)+ con_ctxt <- mapM rnIfaceType (ifConCtxt d)+ con_arg_tys <- mapM rnIfaceType (ifConArgTys d)+ con_fields <- mapM rnFieldLabel (ifConFields d)+ let rnIfaceBang (IfUnpackCo co) = IfUnpackCo <$> rnIfaceCo co+ rnIfaceBang bang = pure bang+ con_stricts <- mapM rnIfaceBang (ifConStricts d)+ return d { ifConName = con_name+ , ifConExTvs = con_ex_tvs+ , ifConEqSpec = con_eq_spec+ , ifConCtxt = con_ctxt+ , ifConArgTys = con_arg_tys+ , ifConFields = con_fields+ , ifConStricts = con_stricts+ }++rnIfaceClassOp :: Rename IfaceClassOp+rnIfaceClassOp (IfaceClassOp n ty dm) =+ IfaceClassOp <$> rnIfaceGlobal n+ <*> rnIfaceType ty+ <*> rnMaybeDefMethSpec dm++rnMaybeDefMethSpec :: Rename (Maybe (DefMethSpec IfaceType))+rnMaybeDefMethSpec (Just (GenericDM ty)) = Just . GenericDM <$> rnIfaceType ty+rnMaybeDefMethSpec mb = return mb++rnIfaceAxBranch :: Rename IfaceAxBranch+rnIfaceAxBranch d = do+ ty_vars <- mapM rnIfaceTvBndr (ifaxbTyVars d)+ lhs <- rnIfaceTcArgs (ifaxbLHS d)+ rhs <- rnIfaceType (ifaxbRHS d)+ return d { ifaxbTyVars = ty_vars+ , ifaxbLHS = lhs+ , ifaxbRHS = rhs }++rnIfaceIdInfo :: Rename IfaceIdInfo+rnIfaceIdInfo NoInfo = pure NoInfo+rnIfaceIdInfo (HasInfo is) = HasInfo <$> mapM rnIfaceInfoItem is++rnIfaceInfoItem :: Rename IfaceInfoItem+rnIfaceInfoItem (HsUnfold lb if_unf)+ = HsUnfold lb <$> rnIfaceUnfolding if_unf+rnIfaceInfoItem i+ = pure i++rnIfaceUnfolding :: Rename IfaceUnfolding+rnIfaceUnfolding (IfCoreUnfold stable if_expr)+ = IfCoreUnfold stable <$> rnIfaceExpr if_expr+rnIfaceUnfolding (IfCompulsory if_expr)+ = IfCompulsory <$> rnIfaceExpr if_expr+rnIfaceUnfolding (IfInlineRule arity unsat_ok boring_ok if_expr)+ = IfInlineRule arity unsat_ok boring_ok <$> rnIfaceExpr if_expr+rnIfaceUnfolding (IfDFunUnfold bs ops)+ = IfDFunUnfold <$> rnIfaceBndrs bs <*> mapM rnIfaceExpr ops++rnIfaceExpr :: Rename IfaceExpr+rnIfaceExpr (IfaceLcl name) = pure (IfaceLcl name)+rnIfaceExpr (IfaceExt gbl) = IfaceExt <$> rnIfaceGlobal gbl+rnIfaceExpr (IfaceType ty) = IfaceType <$> rnIfaceType ty+rnIfaceExpr (IfaceCo co) = IfaceCo <$> rnIfaceCo co+rnIfaceExpr (IfaceTuple sort args) = IfaceTuple sort <$> rnIfaceExprs args+rnIfaceExpr (IfaceLam lam_bndr expr)+ = IfaceLam <$> rnIfaceLamBndr lam_bndr <*> rnIfaceExpr expr+rnIfaceExpr (IfaceApp fun arg)+ = IfaceApp <$> rnIfaceExpr fun <*> rnIfaceExpr arg+rnIfaceExpr (IfaceCase scrut case_bndr alts)+ = IfaceCase <$> rnIfaceExpr scrut+ <*> pure case_bndr+ <*> mapM rnIfaceAlt alts+rnIfaceExpr (IfaceECase scrut ty)+ = IfaceECase <$> rnIfaceExpr scrut <*> rnIfaceType ty+rnIfaceExpr (IfaceLet (IfaceNonRec bndr rhs) body)+ = IfaceLet <$> (IfaceNonRec <$> rnIfaceLetBndr bndr <*> rnIfaceExpr rhs)+ <*> rnIfaceExpr body+rnIfaceExpr (IfaceLet (IfaceRec pairs) body)+ = IfaceLet <$> (IfaceRec <$> mapM (\(bndr, rhs) ->+ (,) <$> rnIfaceLetBndr bndr+ <*> rnIfaceExpr rhs) pairs)+ <*> rnIfaceExpr body+rnIfaceExpr (IfaceCast expr co)+ = IfaceCast <$> rnIfaceExpr expr <*> rnIfaceCo co+rnIfaceExpr (IfaceLit lit) = pure (IfaceLit lit)+rnIfaceExpr (IfaceFCall cc ty) = IfaceFCall cc <$> rnIfaceType ty+rnIfaceExpr (IfaceTick tickish expr) = IfaceTick tickish <$> rnIfaceExpr expr++rnIfaceBndrs :: Rename [IfaceBndr]+rnIfaceBndrs = mapM rnIfaceBndr++rnIfaceBndr :: Rename IfaceBndr+rnIfaceBndr (IfaceIdBndr (fs, ty)) = IfaceIdBndr <$> ((,) fs <$> rnIfaceType ty)+rnIfaceBndr (IfaceTvBndr tv_bndr) = IfaceIdBndr <$> rnIfaceTvBndr tv_bndr++rnIfaceTvBndr :: Rename IfaceTvBndr+rnIfaceTvBndr (fs, kind) = (,) fs <$> rnIfaceType kind++rnIfaceTyConBinder :: Rename IfaceTyConBinder+rnIfaceTyConBinder (TvBndr tv vis) = TvBndr <$> rnIfaceTvBndr tv <*> pure vis++rnIfaceAlt :: Rename IfaceAlt+rnIfaceAlt (conalt, names, rhs)+ = (,,) <$> rnIfaceConAlt conalt <*> pure names <*> rnIfaceExpr rhs++rnIfaceConAlt :: Rename IfaceConAlt+rnIfaceConAlt (IfaceDataAlt data_occ) = IfaceDataAlt <$> rnIfaceGlobal data_occ+rnIfaceConAlt alt = pure alt++rnIfaceLetBndr :: Rename IfaceLetBndr+rnIfaceLetBndr (IfLetBndr fs ty info jpi)+ = IfLetBndr fs <$> rnIfaceType ty <*> rnIfaceIdInfo info <*> pure jpi++rnIfaceLamBndr :: Rename IfaceLamBndr+rnIfaceLamBndr (bndr, oneshot) = (,) <$> rnIfaceBndr bndr <*> pure oneshot++rnIfaceCo :: Rename IfaceCoercion+rnIfaceCo (IfaceReflCo role ty) = IfaceReflCo role <$> rnIfaceType ty+rnIfaceCo (IfaceFunCo role co1 co2)+ = IfaceFunCo role <$> rnIfaceCo co1 <*> rnIfaceCo co2+rnIfaceCo (IfaceTyConAppCo role tc cos)+ = IfaceTyConAppCo role <$> rnIfaceTyCon tc <*> mapM rnIfaceCo cos+rnIfaceCo (IfaceAppCo co1 co2)+ = IfaceAppCo <$> rnIfaceCo co1 <*> rnIfaceCo co2+rnIfaceCo (IfaceForAllCo bndr co1 co2)+ = IfaceForAllCo <$> rnIfaceTvBndr bndr <*> rnIfaceCo co1 <*> rnIfaceCo co2+rnIfaceCo (IfaceCoVarCo lcl) = IfaceCoVarCo <$> pure lcl+rnIfaceCo (IfaceAxiomInstCo n i cs)+ = IfaceAxiomInstCo <$> rnIfaceGlobal n <*> pure i <*> mapM rnIfaceCo cs+rnIfaceCo (IfaceUnivCo s r t1 t2)+ = IfaceUnivCo s r <$> rnIfaceType t1 <*> rnIfaceType t2+rnIfaceCo (IfaceSymCo c)+ = IfaceSymCo <$> rnIfaceCo c+rnIfaceCo (IfaceTransCo c1 c2)+ = IfaceTransCo <$> rnIfaceCo c1 <*> rnIfaceCo c2+rnIfaceCo (IfaceInstCo c1 c2)+ = IfaceInstCo <$> rnIfaceCo c1 <*> rnIfaceCo c2+rnIfaceCo (IfaceNthCo d c) = IfaceNthCo d <$> rnIfaceCo c+rnIfaceCo (IfaceLRCo lr c) = IfaceLRCo lr <$> rnIfaceCo c+rnIfaceCo (IfaceSubCo c) = IfaceSubCo <$> rnIfaceCo c+rnIfaceCo (IfaceAxiomRuleCo ax cos)+ = IfaceAxiomRuleCo ax <$> mapM rnIfaceCo cos+rnIfaceCo (IfaceKindCo c) = IfaceKindCo <$> rnIfaceCo c+rnIfaceCo (IfaceCoherenceCo c1 c2) = IfaceCoherenceCo <$> rnIfaceCo c1 <*> rnIfaceCo c2++rnIfaceTyCon :: Rename IfaceTyCon+rnIfaceTyCon (IfaceTyCon n info)+ = IfaceTyCon <$> rnIfaceGlobal n <*> pure info++rnIfaceExprs :: Rename [IfaceExpr]+rnIfaceExprs = mapM rnIfaceExpr++rnIfaceIdDetails :: Rename IfaceIdDetails+rnIfaceIdDetails (IfRecSelId (Left tc) b) = IfRecSelId <$> fmap Left (rnIfaceTyCon tc) <*> pure b+rnIfaceIdDetails (IfRecSelId (Right decl) b) = IfRecSelId <$> fmap Right (rnIfaceDecl decl) <*> pure b+rnIfaceIdDetails details = pure details++rnIfaceType :: Rename IfaceType+rnIfaceType (IfaceFreeTyVar n) = pure (IfaceFreeTyVar n)+rnIfaceType (IfaceTyVar n) = pure (IfaceTyVar n)+rnIfaceType (IfaceAppTy t1 t2)+ = IfaceAppTy <$> rnIfaceType t1 <*> rnIfaceType t2+rnIfaceType (IfaceLitTy l) = return (IfaceLitTy l)+rnIfaceType (IfaceFunTy t1 t2)+ = IfaceFunTy <$> rnIfaceType t1 <*> rnIfaceType t2+rnIfaceType (IfaceDFunTy t1 t2)+ = IfaceDFunTy <$> rnIfaceType t1 <*> rnIfaceType t2+rnIfaceType (IfaceTupleTy s i tks)+ = IfaceTupleTy s i <$> rnIfaceTcArgs tks+rnIfaceType (IfaceTyConApp tc tks)+ = IfaceTyConApp <$> rnIfaceTyCon tc <*> rnIfaceTcArgs tks+rnIfaceType (IfaceForAllTy tv t)+ = IfaceForAllTy <$> rnIfaceForAllBndr tv <*> rnIfaceType t+rnIfaceType (IfaceCoercionTy co)+ = IfaceCoercionTy <$> rnIfaceCo co+rnIfaceType (IfaceCastTy ty co)+ = IfaceCastTy <$> rnIfaceType ty <*> rnIfaceCo co++rnIfaceForAllBndr :: Rename IfaceForAllBndr+rnIfaceForAllBndr (TvBndr tv vis) = TvBndr <$> rnIfaceTvBndr tv <*> pure vis++rnIfaceTcArgs :: Rename IfaceTcArgs+rnIfaceTcArgs (ITC_Invis t ts) = ITC_Invis <$> rnIfaceType t <*> rnIfaceTcArgs ts+rnIfaceTcArgs (ITC_Vis t ts) = ITC_Vis <$> rnIfaceType t <*> rnIfaceTcArgs ts+rnIfaceTcArgs ITC_Nil = pure ITC_Nil
+ basicTypes/Avail.hs view
@@ -0,0 +1,262 @@+{-# LANGUAGE CPP #-}+--+-- (c) The University of Glasgow+--++#include "HsVersions.h"++module Avail (+ Avails,+ AvailInfo(..),+ avail,+ availsToNameSet,+ availsToNameSetWithSelectors,+ availsToNameEnv,+ availName, availNames, availNonFldNames,+ availNamesWithSelectors,+ availFlds,+ stableAvailCmp,+ plusAvail,+ trimAvail,+ filterAvail,+ filterAvails,+ nubAvails+++ ) where++import Name+import NameEnv+import NameSet++import FieldLabel+import Binary+import ListSetOps+import Outputable+import Util++import Data.List ( find )+import Data.Function++-- -----------------------------------------------------------------------------+-- The AvailInfo type++-- | Records what things are "available", i.e. in scope+data AvailInfo = Avail Name -- ^ An ordinary identifier in scope+ | AvailTC Name+ [Name]+ [FieldLabel]+ -- ^ A type or class in scope. Parameters:+ --+ -- 1) The name of the type or class+ -- 2) The available pieces of type or class,+ -- excluding field selectors.+ -- 3) The record fields of the type+ -- (see Note [Representing fields in AvailInfo]).+ --+ -- The AvailTC Invariant:+ -- * If the type or class is itself+ -- to be in scope, it must be+ -- *first* in this list. Thus,+ -- typically: @AvailTC Eq [Eq, ==, \/=]@+ deriving( Eq )+ -- Equality used when deciding if the+ -- interface has changed++-- | A collection of 'AvailInfo' - several things that are \"available\"+type Avails = [AvailInfo]++{-+Note [Representing fields in AvailInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When -XDuplicateRecordFields is disabled (the normal case), a+datatype like++ data T = MkT { foo :: Int }++gives rise to the AvailInfo++ AvailTC T [T, MkT] [FieldLabel "foo" False foo],++whereas if -XDuplicateRecordFields is enabled it gives++ AvailTC T [T, MkT] [FieldLabel "foo" True $sel:foo:MkT]++since the label does not match the selector name.++The labels in a field list are not necessarily unique:+data families allow the same parent (the family tycon) to have+multiple distinct fields with the same label. For example,++ data family F a+ data instance F Int = MkFInt { foo :: Int }+ data instance F Bool = MkFBool { foo :: Bool}++gives rise to++ AvailTC F [F, MkFInt, MkFBool]+ [FieldLabel "foo" True $sel:foo:MkFInt, FieldLabel "foo" True $sel:foo:MkFBool].++Moreover, note that the flIsOverloaded flag need not be the same for+all the elements of the list. In the example above, this occurs if+the two data instances are defined in different modules, one with+`-XDuplicateRecordFields` enabled and one with it disabled. Thus it+is possible to have++ AvailTC F [F, MkFInt, MkFBool]+ [FieldLabel "foo" True $sel:foo:MkFInt, FieldLabel "foo" False foo].++If the two data instances are defined in different modules, both+without `-XDuplicateRecordFields`, it will be impossible to export+them from the same module (even with `-XDuplicateRecordfields`+enabled), because they would be represented identically. The+workaround here is to enable `-XDuplicateRecordFields` on the defining+modules.+-}++-- | Compare lexicographically+stableAvailCmp :: AvailInfo -> AvailInfo -> Ordering+stableAvailCmp (Avail n1) (Avail n2) = n1 `stableNameCmp` n2+stableAvailCmp (Avail {}) (AvailTC {}) = LT+stableAvailCmp (AvailTC n ns nfs) (AvailTC m ms mfs) =+ (n `stableNameCmp` m) `thenCmp`+ (cmpList stableNameCmp ns ms) `thenCmp`+ (cmpList (stableNameCmp `on` flSelector) nfs mfs)+stableAvailCmp (AvailTC {}) (Avail {}) = GT++avail :: Name -> AvailInfo+avail n = Avail n++-- -----------------------------------------------------------------------------+-- Operations on AvailInfo++availsToNameSet :: [AvailInfo] -> NameSet+availsToNameSet avails = foldr add emptyNameSet avails+ where add avail set = extendNameSetList set (availNames avail)++availsToNameSetWithSelectors :: [AvailInfo] -> NameSet+availsToNameSetWithSelectors avails = foldr add emptyNameSet avails+ where add avail set = extendNameSetList set (availNamesWithSelectors avail)++availsToNameEnv :: [AvailInfo] -> NameEnv AvailInfo+availsToNameEnv avails = foldr add emptyNameEnv avails+ where add avail env = extendNameEnvList env+ (zip (availNames avail) (repeat avail))++-- | Just the main name made available, i.e. not the available pieces+-- of type or class brought into scope by the 'GenAvailInfo'+availName :: AvailInfo -> Name+availName (Avail n) = n+availName (AvailTC n _ _) = n++-- | All names made available by the availability information (excluding overloaded selectors)+availNames :: AvailInfo -> [Name]+availNames (Avail n) = [n]+availNames (AvailTC _ ns fs) = ns ++ [ flSelector f | f <- fs, not (flIsOverloaded f) ]++-- | All names made available by the availability information (including overloaded selectors)+availNamesWithSelectors :: AvailInfo -> [Name]+availNamesWithSelectors (Avail n) = [n]+availNamesWithSelectors (AvailTC _ ns fs) = ns ++ map flSelector fs++-- | Names for non-fields made available by the availability information+availNonFldNames :: AvailInfo -> [Name]+availNonFldNames (Avail n) = [n]+availNonFldNames (AvailTC _ ns _) = ns++-- | Fields made available by the availability information+availFlds :: AvailInfo -> [FieldLabel]+availFlds (AvailTC _ _ fs) = fs+availFlds _ = []+++-- -----------------------------------------------------------------------------+-- Utility++plusAvail :: AvailInfo -> AvailInfo -> AvailInfo+plusAvail a1 a2+ | debugIsOn && availName a1 /= availName a2+ = pprPanic "RnEnv.plusAvail names differ" (hsep [ppr a1,ppr a2])+plusAvail a1@(Avail {}) (Avail {}) = a1+plusAvail (AvailTC _ [] []) a2@(AvailTC {}) = a2+plusAvail a1@(AvailTC {}) (AvailTC _ [] []) = a1+plusAvail (AvailTC n1 (s1:ss1) fs1) (AvailTC n2 (s2:ss2) fs2)+ = case (n1==s1, n2==s2) of -- Maintain invariant the parent is first+ (True,True) -> AvailTC n1 (s1 : (ss1 `unionLists` ss2))+ (fs1 `unionLists` fs2)+ (True,False) -> AvailTC n1 (s1 : (ss1 `unionLists` (s2:ss2)))+ (fs1 `unionLists` fs2)+ (False,True) -> AvailTC n1 (s2 : ((s1:ss1) `unionLists` ss2))+ (fs1 `unionLists` fs2)+ (False,False) -> AvailTC n1 ((s1:ss1) `unionLists` (s2:ss2))+ (fs1 `unionLists` fs2)+plusAvail (AvailTC n1 ss1 fs1) (AvailTC _ [] fs2)+ = AvailTC n1 ss1 (fs1 `unionLists` fs2)+plusAvail (AvailTC n1 [] fs1) (AvailTC _ ss2 fs2)+ = AvailTC n1 ss2 (fs1 `unionLists` fs2)+plusAvail a1 a2 = pprPanic "RnEnv.plusAvail" (hsep [ppr a1,ppr a2])++-- | trims an 'AvailInfo' to keep only a single name+trimAvail :: AvailInfo -> Name -> AvailInfo+trimAvail (Avail n) _ = Avail n+trimAvail (AvailTC n ns fs) m = case find ((== m) . flSelector) fs of+ Just x -> AvailTC n [] [x]+ Nothing -> ASSERT( m `elem` ns ) AvailTC n [m] []++-- | filters 'AvailInfo's by the given predicate+filterAvails :: (Name -> Bool) -> [AvailInfo] -> [AvailInfo]+filterAvails keep avails = foldr (filterAvail keep) [] avails++-- | filters an 'AvailInfo' by the given predicate+filterAvail :: (Name -> Bool) -> AvailInfo -> [AvailInfo] -> [AvailInfo]+filterAvail keep ie rest =+ case ie of+ Avail n | keep n -> ie : rest+ | otherwise -> rest+ AvailTC tc ns fs ->+ let ns' = filter keep ns+ fs' = filter (keep . flSelector) fs in+ if null ns' && null fs' then rest else AvailTC tc ns' fs' : rest+++-- | Combines 'AvailInfo's from the same family+-- 'avails' may have several items with the same availName+-- E.g import Ix( Ix(..), index )+-- will give Ix(Ix,index,range) and Ix(index)+-- We want to combine these; addAvail does that+nubAvails :: [AvailInfo] -> [AvailInfo]+nubAvails avails = nameEnvElts (foldl add emptyNameEnv avails)+ where+ add env avail = extendNameEnv_C plusAvail env (availName avail) avail++-- -----------------------------------------------------------------------------+-- Printing++instance Outputable AvailInfo where+ ppr = pprAvail++pprAvail :: AvailInfo -> SDoc+pprAvail (Avail n)+ = ppr n+pprAvail (AvailTC n ns fs)+ = ppr n <> braces (sep [ fsep (punctuate comma (map ppr ns)) <> semi+ , fsep (punctuate comma (map (ppr . flLabel) fs))])++instance Binary AvailInfo where+ put_ bh (Avail aa) = do+ putByte bh 0+ put_ bh aa+ put_ bh (AvailTC ab ac ad) = do+ putByte bh 1+ put_ bh ab+ put_ bh ac+ put_ bh ad+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do aa <- get bh+ return (Avail aa)+ _ -> do ab <- get bh+ ac <- get bh+ ad <- get bh+ return (AvailTC ab ac ad)
+ basicTypes/BasicTypes.hs view
@@ -0,0 +1,1511 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1997-1998++\section[BasicTypes]{Miscellanous types}++This module defines a miscellaneously collection of very simple+types that++\begin{itemize}+\item have no other obvious home+\item don't depend on any other complicated types+\item are used in more than one "part" of the compiler+\end{itemize}+-}++{-# LANGUAGE DeriveDataTypeable #-}++module BasicTypes(+ Version, bumpVersion, initialVersion,++ LeftOrRight(..),+ pickLR,++ ConTag, ConTagZ, fIRST_TAG,++ Arity, RepArity, JoinArity,++ Alignment,++ FunctionOrData(..),++ WarningTxt(..), pprWarningTxtForMsg, StringLiteral(..),++ Fixity(..), FixityDirection(..),+ defaultFixity, maxPrecedence, minPrecedence,+ negateFixity, funTyFixity,+ compareFixity,+ LexicalFixity(..),++ RecFlag(..), isRec, isNonRec, boolToRecFlag,+ Origin(..), isGenerated,++ RuleName, pprRuleName,++ TopLevelFlag(..), isTopLevel, isNotTopLevel,++ DerivStrategy(..),++ OverlapFlag(..), OverlapMode(..), setOverlapModeMaybe,+ hasOverlappingFlag, hasOverlappableFlag, hasIncoherentFlag,++ Boxity(..), isBoxed,++ TyPrec(..), maybeParen,++ TupleSort(..), tupleSortBoxity, boxityTupleSort,+ tupleParens,++ sumParens, pprAlternative,++ -- ** The OneShotInfo type+ OneShotInfo(..),+ noOneShotInfo, hasNoOneShotInfo, isOneShotInfo,+ bestOneShot, worstOneShot,++ OccInfo(..), noOccInfo, seqOccInfo, zapFragileOcc, isOneOcc,+ isDeadOcc, isStrongLoopBreaker, isWeakLoopBreaker, isManyOccs,+ strongLoopBreaker, weakLoopBreaker,++ InsideLam, insideLam, notInsideLam,+ OneBranch, oneBranch, notOneBranch,+ InterestingCxt,+ TailCallInfo(..), tailCallInfo, zapOccTailCallInfo,+ isAlwaysTailCalled,++ EP(..),++ DefMethSpec(..),+ SwapFlag(..), flipSwap, unSwap, isSwapped,++ CompilerPhase(..), PhaseNum,++ Activation(..), isActive, isActiveIn, competesWith,+ isNeverActive, isAlwaysActive, isEarlyActive,++ RuleMatchInfo(..), isConLike, isFunLike,+ InlineSpec(..), isEmptyInlineSpec,+ InlinePragma(..), defaultInlinePragma, alwaysInlinePragma,+ neverInlinePragma, dfunInlinePragma,+ isDefaultInlinePragma,+ isInlinePragma, isInlinablePragma, isAnyInlinePragma,+ inlinePragmaSpec, inlinePragmaSat,+ inlinePragmaActivation, inlinePragmaRuleMatchInfo,+ setInlinePragmaActivation, setInlinePragmaRuleMatchInfo,+ pprInline, pprInlineDebug,++ SuccessFlag(..), succeeded, failed, successIf,++ FractionalLit(..), negateFractionalLit, integralFractionalLit,++ SourceText(..), pprWithSourceText,++ IntWithInf, infinity, treatZeroAsInf, mkIntWithInf, intGtLimit,++ SpliceExplicitFlag(..)+ ) where++import FastString+import Outputable+import SrcLoc ( Located,unLoc )+import Data.Data hiding (Fixity, Prefix, Infix)+import Data.Function (on)++{-+************************************************************************+* *+ Binary choice+* *+************************************************************************+-}++data LeftOrRight = CLeft | CRight+ deriving( Eq, Data )++pickLR :: LeftOrRight -> (a,a) -> a+pickLR CLeft (l,_) = l+pickLR CRight (_,r) = r++instance Outputable LeftOrRight where+ ppr CLeft = text "Left"+ ppr CRight = text "Right"++{-+************************************************************************+* *+\subsection[Arity]{Arity}+* *+************************************************************************+-}++-- | The number of value arguments that can be applied to a value before it does+-- "real work". So:+-- fib 100 has arity 0+-- \x -> fib x has arity 1+-- See also Note [Definition of arity] in CoreArity+type Arity = Int++-- | Representation Arity+--+-- The number of represented arguments that can be applied to a value before it does+-- "real work". So:+-- fib 100 has representation arity 0+-- \x -> fib x has representation arity 1+-- \(# x, y #) -> fib (x + y) has representation arity 2+type RepArity = Int++-- | The number of arguments that a join point takes. Unlike the arity of a+-- function, this is a purely syntactic property and is fixed when the join+-- point is created (or converted from a value). Both type and value arguments+-- are counted.+type JoinArity = Int++{-+************************************************************************+* *+ Constructor tags+* *+************************************************************************+-}++-- | Constructor Tag+--+-- Type of the tags associated with each constructor possibility or superclass+-- selector+type ConTag = Int++-- | A *zero-indexed* constructor tag+type ConTagZ = Int++fIRST_TAG :: ConTag+-- ^ Tags are allocated from here for real constructors+-- or for superclass selectors+fIRST_TAG = 1++{-+************************************************************************+* *+\subsection[Alignment]{Alignment}+* *+************************************************************************+-}++type Alignment = Int -- align to next N-byte boundary (N must be a power of 2).++{-+************************************************************************+* *+ One-shot information+* *+************************************************************************+-}++-- | If the 'Id' is a lambda-bound variable then it may have lambda-bound+-- variable info. Sometimes we know whether the lambda binding this variable+-- is a \"one-shot\" lambda; that is, whether it is applied at most once.+--+-- This information may be useful in optimisation, as computations may+-- safely be floated inside such a lambda without risk of duplicating+-- work.+data OneShotInfo+ = NoOneShotInfo -- ^ No information+ | OneShotLam -- ^ The lambda is applied at most once.+ deriving (Eq)++-- | It is always safe to assume that an 'Id' has no lambda-bound variable information+noOneShotInfo :: OneShotInfo+noOneShotInfo = NoOneShotInfo++isOneShotInfo, hasNoOneShotInfo :: OneShotInfo -> Bool+isOneShotInfo OneShotLam = True+isOneShotInfo _ = False++hasNoOneShotInfo NoOneShotInfo = True+hasNoOneShotInfo _ = False++worstOneShot, bestOneShot :: OneShotInfo -> OneShotInfo -> OneShotInfo+worstOneShot NoOneShotInfo _ = NoOneShotInfo+worstOneShot OneShotLam os = os++bestOneShot NoOneShotInfo os = os+bestOneShot OneShotLam _ = OneShotLam++pprOneShotInfo :: OneShotInfo -> SDoc+pprOneShotInfo NoOneShotInfo = empty+pprOneShotInfo OneShotLam = text "OneShot"++instance Outputable OneShotInfo where+ ppr = pprOneShotInfo++{-+************************************************************************+* *+ Swap flag+* *+************************************************************************+-}++data SwapFlag+ = NotSwapped -- Args are: actual, expected+ | IsSwapped -- Args are: expected, actual++instance Outputable SwapFlag where+ ppr IsSwapped = text "Is-swapped"+ ppr NotSwapped = text "Not-swapped"++flipSwap :: SwapFlag -> SwapFlag+flipSwap IsSwapped = NotSwapped+flipSwap NotSwapped = IsSwapped++isSwapped :: SwapFlag -> Bool+isSwapped IsSwapped = True+isSwapped NotSwapped = False++unSwap :: SwapFlag -> (a->a->b) -> a -> a -> b+unSwap NotSwapped f a b = f a b+unSwap IsSwapped f a b = f b a++{-+************************************************************************+* *+\subsection[FunctionOrData]{FunctionOrData}+* *+************************************************************************+-}++data FunctionOrData = IsFunction | IsData+ deriving (Eq, Ord, Data)++instance Outputable FunctionOrData where+ ppr IsFunction = text "(function)"+ ppr IsData = text "(data)"++{-+************************************************************************+* *+\subsection[Version]{Module and identifier version numbers}+* *+************************************************************************+-}++type Version = Int++bumpVersion :: Version -> Version+bumpVersion v = v+1++initialVersion :: Version+initialVersion = 1++{-+************************************************************************+* *+ Deprecations+* *+************************************************************************+-}++-- | A String Literal in the source, including its original raw format for use by+-- source to source manipulation tools.+data StringLiteral = StringLiteral+ { sl_st :: SourceText, -- literal raw source.+ -- See not [Literal source text]+ sl_fs :: FastString -- literal string value+ } deriving Data++instance Eq StringLiteral where+ (StringLiteral _ a) == (StringLiteral _ b) = a == b++instance Outputable StringLiteral where+ ppr sl = pprWithSourceText (sl_st sl) (ftext $ sl_fs sl)++-- | Warning Text+--+-- reason/explanation from a WARNING or DEPRECATED pragma+data WarningTxt = WarningTxt (Located SourceText)+ [Located StringLiteral]+ | DeprecatedTxt (Located SourceText)+ [Located StringLiteral]+ deriving (Eq, Data)++instance Outputable WarningTxt where+ ppr (WarningTxt lsrc ws)+ = case unLoc lsrc of+ NoSourceText -> pp_ws ws+ SourceText src -> text src <+> pp_ws ws <+> text "#-}"++ ppr (DeprecatedTxt lsrc ds)+ = case unLoc lsrc of+ NoSourceText -> pp_ws ds+ SourceText src -> text src <+> pp_ws ds <+> text "#-}"++pp_ws :: [Located StringLiteral] -> SDoc+pp_ws [l] = ppr $ unLoc l+pp_ws ws+ = text "["+ <+> vcat (punctuate comma (map (ppr . unLoc) ws))+ <+> text "]"+++pprWarningTxtForMsg :: WarningTxt -> SDoc+pprWarningTxtForMsg (WarningTxt _ ws)+ = doubleQuotes (vcat (map (ftext . sl_fs . unLoc) ws))+pprWarningTxtForMsg (DeprecatedTxt _ ds)+ = text "Deprecated:" <+>+ doubleQuotes (vcat (map (ftext . sl_fs . unLoc) ds))++{-+************************************************************************+* *+ Rules+* *+************************************************************************+-}++type RuleName = FastString++pprRuleName :: RuleName -> SDoc+pprRuleName rn = doubleQuotes (ftext rn)++{-+************************************************************************+* *+\subsection[Fixity]{Fixity info}+* *+************************************************************************+-}++------------------------+data Fixity = Fixity SourceText Int FixityDirection+ -- Note [Pragma source text]+ deriving Data++instance Outputable Fixity where+ ppr (Fixity _ prec dir) = hcat [ppr dir, space, int prec]++instance Eq Fixity where -- Used to determine if two fixities conflict+ (Fixity _ p1 dir1) == (Fixity _ p2 dir2) = p1==p2 && dir1 == dir2++------------------------+data FixityDirection = InfixL | InfixR | InfixN+ deriving (Eq, Data)++instance Outputable FixityDirection where+ ppr InfixL = text "infixl"+ ppr InfixR = text "infixr"+ ppr InfixN = text "infix"++------------------------+maxPrecedence, minPrecedence :: Int+maxPrecedence = 9+minPrecedence = 0++defaultFixity :: Fixity+defaultFixity = Fixity NoSourceText maxPrecedence InfixL++negateFixity, funTyFixity :: Fixity+-- Wired-in fixities+negateFixity = Fixity NoSourceText 6 InfixL -- Fixity of unary negate+funTyFixity = Fixity NoSourceText 0 InfixR -- Fixity of '->'++{-+Consider++\begin{verbatim}+ a `op1` b `op2` c+\end{verbatim}+@(compareFixity op1 op2)@ tells which way to arrange application, or+whether there's an error.+-}++compareFixity :: Fixity -> Fixity+ -> (Bool, -- Error please+ Bool) -- Associate to the right: a op1 (b op2 c)+compareFixity (Fixity _ prec1 dir1) (Fixity _ prec2 dir2)+ = case prec1 `compare` prec2 of+ GT -> left+ LT -> right+ EQ -> case (dir1, dir2) of+ (InfixR, InfixR) -> right+ (InfixL, InfixL) -> left+ _ -> error_please+ where+ right = (False, True)+ left = (False, False)+ error_please = (True, False)++-- |Captures the fixity of declarations as they are parsed. This is not+-- necessarily the same as the fixity declaration, as the normal fixity may be+-- overridden using parens or backticks.+data LexicalFixity = Prefix | Infix deriving (Typeable,Data,Eq)++instance Outputable LexicalFixity where+ ppr Prefix = text "Prefix"+ ppr Infix = text "Infix"++{-+************************************************************************+* *+\subsection[Top-level/local]{Top-level/not-top level flag}+* *+************************************************************************+-}++data TopLevelFlag+ = TopLevel+ | NotTopLevel++isTopLevel, isNotTopLevel :: TopLevelFlag -> Bool++isNotTopLevel NotTopLevel = True+isNotTopLevel TopLevel = False++isTopLevel TopLevel = True+isTopLevel NotTopLevel = False++instance Outputable TopLevelFlag where+ ppr TopLevel = text "<TopLevel>"+ ppr NotTopLevel = text "<NotTopLevel>"++{-+************************************************************************+* *+ Boxity flag+* *+************************************************************************+-}++data Boxity+ = Boxed+ | Unboxed+ deriving( Eq, Data )++isBoxed :: Boxity -> Bool+isBoxed Boxed = True+isBoxed Unboxed = False++instance Outputable Boxity where+ ppr Boxed = text "Boxed"+ ppr Unboxed = text "Unboxed"++{-+************************************************************************+* *+ Recursive/Non-Recursive flag+* *+************************************************************************+-}++-- | Recursivity Flag+data RecFlag = Recursive+ | NonRecursive+ deriving( Eq, Data )++isRec :: RecFlag -> Bool+isRec Recursive = True+isRec NonRecursive = False++isNonRec :: RecFlag -> Bool+isNonRec Recursive = False+isNonRec NonRecursive = True++boolToRecFlag :: Bool -> RecFlag+boolToRecFlag True = Recursive+boolToRecFlag False = NonRecursive++instance Outputable RecFlag where+ ppr Recursive = text "Recursive"+ ppr NonRecursive = text "NonRecursive"++{-+************************************************************************+* *+ Code origin+* *+************************************************************************+-}++data Origin = FromSource+ | Generated+ deriving( Eq, Data )++isGenerated :: Origin -> Bool+isGenerated Generated = True+isGenerated FromSource = False++instance Outputable Origin where+ ppr FromSource = text "FromSource"+ ppr Generated = text "Generated"++{-+************************************************************************+* *+ Deriving strategies+* *+************************************************************************+-}++-- | Which technique the user explicitly requested when deriving an instance.+data DerivStrategy+ -- See Note [Deriving strategies] in TcDeriv+ = StockStrategy -- ^ GHC's \"standard\" strategy, which is to implement a+ -- custom instance for the data type. This only works+ -- for certain types that GHC knows about (e.g., 'Eq',+ -- 'Show', 'Functor' when @-XDeriveFunctor@ is enabled,+ -- etc.)+ | AnyclassStrategy -- ^ @-XDeriveAnyClass@+ | NewtypeStrategy -- ^ @-XGeneralizedNewtypeDeriving@+ deriving (Eq, Data)++instance Outputable DerivStrategy where+ ppr StockStrategy = text "stock"+ ppr AnyclassStrategy = text "anyclass"+ ppr NewtypeStrategy = text "newtype"++{-+************************************************************************+* *+ Instance overlap flag+* *+************************************************************************+-}++-- | The semantics allowed for overlapping instances for a particular+-- instance. See Note [Safe Haskell isSafeOverlap] (in `InstEnv.hs`) for a+-- explanation of the `isSafeOverlap` field.+--+-- - 'ApiAnnotation.AnnKeywordId' :+-- 'ApiAnnotation.AnnOpen' @'\{-\# OVERLAPPABLE'@ or+-- @'\{-\# OVERLAPPING'@ or+-- @'\{-\# OVERLAPS'@ or+-- @'\{-\# INCOHERENT'@,+-- 'ApiAnnotation.AnnClose' @`\#-\}`@,++-- For details on above see note [Api annotations] in ApiAnnotation+data OverlapFlag = OverlapFlag+ { overlapMode :: OverlapMode+ , isSafeOverlap :: Bool+ } deriving (Eq, Data)++setOverlapModeMaybe :: OverlapFlag -> Maybe OverlapMode -> OverlapFlag+setOverlapModeMaybe f Nothing = f+setOverlapModeMaybe f (Just m) = f { overlapMode = m }++hasIncoherentFlag :: OverlapMode -> Bool+hasIncoherentFlag mode =+ case mode of+ Incoherent _ -> True+ _ -> False++hasOverlappableFlag :: OverlapMode -> Bool+hasOverlappableFlag mode =+ case mode of+ Overlappable _ -> True+ Overlaps _ -> True+ Incoherent _ -> True+ _ -> False++hasOverlappingFlag :: OverlapMode -> Bool+hasOverlappingFlag mode =+ case mode of+ Overlapping _ -> True+ Overlaps _ -> True+ Incoherent _ -> True+ _ -> False++data OverlapMode -- See Note [Rules for instance lookup] in InstEnv+ = NoOverlap SourceText+ -- See Note [Pragma source text]+ -- ^ This instance must not overlap another `NoOverlap` instance.+ -- However, it may be overlapped by `Overlapping` instances,+ -- and it may overlap `Overlappable` instances.+++ | Overlappable SourceText+ -- See Note [Pragma source text]+ -- ^ Silently ignore this instance if you find a+ -- more specific one that matches the constraint+ -- you are trying to resolve+ --+ -- Example: constraint (Foo [Int])+ -- instance Foo [Int]+ -- instance {-# OVERLAPPABLE #-} Foo [a]+ --+ -- Since the second instance has the Overlappable flag,+ -- the first instance will be chosen (otherwise+ -- its ambiguous which to choose)+++ | Overlapping SourceText+ -- See Note [Pragma source text]+ -- ^ Silently ignore any more general instances that may be+ -- used to solve the constraint.+ --+ -- Example: constraint (Foo [Int])+ -- instance {-# OVERLAPPING #-} Foo [Int]+ -- instance Foo [a]+ --+ -- Since the first instance has the Overlapping flag,+ -- the second---more general---instance will be ignored (otherwise+ -- it is ambiguous which to choose)+++ | Overlaps SourceText+ -- See Note [Pragma source text]+ -- ^ Equivalent to having both `Overlapping` and `Overlappable` flags.++ | Incoherent SourceText+ -- See Note [Pragma source text]+ -- ^ Behave like Overlappable and Overlapping, and in addition pick+ -- an an arbitrary one if there are multiple matching candidates, and+ -- don't worry about later instantiation+ --+ -- Example: constraint (Foo [b])+ -- instance {-# INCOHERENT -} Foo [Int]+ -- instance Foo [a]+ -- Without the Incoherent flag, we'd complain that+ -- instantiating 'b' would change which instance+ -- was chosen. See also note [Incoherent instances] in InstEnv++ deriving (Eq, Data)+++instance Outputable OverlapFlag where+ ppr flag = ppr (overlapMode flag) <+> pprSafeOverlap (isSafeOverlap flag)++instance Outputable OverlapMode where+ ppr (NoOverlap _) = empty+ ppr (Overlappable _) = text "[overlappable]"+ ppr (Overlapping _) = text "[overlapping]"+ ppr (Overlaps _) = text "[overlap ok]"+ ppr (Incoherent _) = text "[incoherent]"++pprSafeOverlap :: Bool -> SDoc+pprSafeOverlap True = text "[safe]"+pprSafeOverlap False = empty++{-+************************************************************************+* *+ Type precedence+* *+************************************************************************+-}++data TyPrec -- See Note [Precedence in types] in TyCoRep.hs+ = TopPrec -- No parens+ | FunPrec -- Function args; no parens for tycon apps+ | TyOpPrec -- Infix operator+ | TyConPrec -- Tycon args; no parens for atomic+ deriving( Eq, Ord )++maybeParen :: TyPrec -> TyPrec -> SDoc -> SDoc+maybeParen ctxt_prec inner_prec pretty+ | ctxt_prec < inner_prec = pretty+ | otherwise = parens pretty++{-+************************************************************************+* *+ Tuples+* *+************************************************************************+-}++data TupleSort+ = BoxedTuple+ | UnboxedTuple+ | ConstraintTuple+ deriving( Eq, Data )++tupleSortBoxity :: TupleSort -> Boxity+tupleSortBoxity BoxedTuple = Boxed+tupleSortBoxity UnboxedTuple = Unboxed+tupleSortBoxity ConstraintTuple = Boxed++boxityTupleSort :: Boxity -> TupleSort+boxityTupleSort Boxed = BoxedTuple+boxityTupleSort Unboxed = UnboxedTuple++tupleParens :: TupleSort -> SDoc -> SDoc+tupleParens BoxedTuple p = parens p+tupleParens UnboxedTuple p = text "(#" <+> p <+> ptext (sLit "#)")+tupleParens ConstraintTuple p -- In debug-style write (% Eq a, Ord b %)+ = sdocWithPprDebug $ \dbg -> if dbg+ then text "(%" <+> p <+> ptext (sLit "%)")+ else parens p++{-+************************************************************************+* *+ Sums+* *+************************************************************************+-}++sumParens :: SDoc -> SDoc+sumParens p = ptext (sLit "(#") <+> p <+> ptext (sLit "#)")++-- | Pretty print an alternative in an unboxed sum e.g. "| a | |".+pprAlternative :: (a -> SDoc) -- ^ The pretty printing function to use+ -> a -- ^ The things to be pretty printed+ -> ConTag -- ^ Alternative (one-based)+ -> Arity -- ^ Arity+ -> SDoc -- ^ 'SDoc' where the alternative havs been pretty+ -- printed and finally packed into a paragraph.+pprAlternative pp x alt arity =+ fsep (replicate (alt - 1) vbar ++ [pp x] ++ replicate (arity - alt) vbar)++{-+************************************************************************+* *+\subsection[Generic]{Generic flag}+* *+************************************************************************++This is the "Embedding-Projection pair" datatype, it contains+two pieces of code (normally either RenamedExpr's or Id's)+If we have a such a pair (EP from to), the idea is that 'from' and 'to'+represents functions of type++ from :: T -> Tring+ to :: Tring -> T++And we should have++ to (from x) = x++T and Tring are arbitrary, but typically T is the 'main' type while+Tring is the 'representation' type. (This just helps us remember+whether to use 'from' or 'to'.+-}++-- | Embedding Projection pair+data EP a = EP { fromEP :: a, -- :: T -> Tring+ toEP :: a } -- :: Tring -> T++{-+Embedding-projection pairs are used in several places:++First of all, each type constructor has an EP associated with it, the+code in EP converts (datatype T) from T to Tring and back again.++Secondly, when we are filling in Generic methods (in the typechecker,+tcMethodBinds), we are constructing bimaps by induction on the structure+of the type of the method signature.+++************************************************************************+* *+\subsection{Occurrence information}+* *+************************************************************************++This data type is used exclusively by the simplifier, but it appears in a+SubstResult, which is currently defined in VarEnv, which is pretty near+the base of the module hierarchy. So it seemed simpler to put the+defn of OccInfo here, safely at the bottom+-}++-- | identifier Occurrence Information+data OccInfo+ = ManyOccs { occ_tail :: !TailCallInfo }+ -- ^ There are many occurrences, or unknown occurrences++ | IAmDead -- ^ Marks unused variables. Sometimes useful for+ -- lambda and case-bound variables.++ | OneOcc { occ_in_lam :: !InsideLam+ , occ_one_br :: !OneBranch+ , occ_int_cxt :: !InterestingCxt+ , occ_tail :: !TailCallInfo }+ -- ^ Occurs exactly once (per branch), not inside a rule++ -- | This identifier breaks a loop of mutually recursive functions. The field+ -- marks whether it is only a loop breaker due to a reference in a rule+ | IAmALoopBreaker { occ_rules_only :: !RulesOnly+ , occ_tail :: !TailCallInfo }+ -- Note [LoopBreaker OccInfo]++ deriving (Eq)++type RulesOnly = Bool++{-+Note [LoopBreaker OccInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~~+ IAmALoopBreaker True <=> A "weak" or rules-only loop breaker+ Do not preInlineUnconditionally++ IAmALoopBreaker False <=> A "strong" loop breaker+ Do not inline at all++See OccurAnal Note [Weak loop breakers]+-}++noOccInfo :: OccInfo+noOccInfo = ManyOccs { occ_tail = NoTailCallInfo }++isManyOccs :: OccInfo -> Bool+isManyOccs ManyOccs{} = True+isManyOccs _ = False++seqOccInfo :: OccInfo -> ()+seqOccInfo occ = occ `seq` ()++-----------------+-- | Interesting Context+type InterestingCxt = Bool -- True <=> Function: is applied+ -- Data value: scrutinised by a case with+ -- at least one non-DEFAULT branch++-----------------+-- | Inside Lambda+type InsideLam = Bool -- True <=> Occurs inside a non-linear lambda+ -- Substituting a redex for this occurrence is+ -- dangerous because it might duplicate work.+insideLam, notInsideLam :: InsideLam+insideLam = True+notInsideLam = False++-----------------+type OneBranch = Bool -- True <=> Occurs in only one case branch+ -- so no code-duplication issue to worry about+oneBranch, notOneBranch :: OneBranch+oneBranch = True+notOneBranch = False++-----------------+data TailCallInfo = AlwaysTailCalled JoinArity -- See Note [TailCallInfo]+ | NoTailCallInfo+ deriving (Eq)++tailCallInfo :: OccInfo -> TailCallInfo+tailCallInfo IAmDead = NoTailCallInfo+tailCallInfo other = occ_tail other++zapOccTailCallInfo :: OccInfo -> OccInfo+zapOccTailCallInfo IAmDead = IAmDead+zapOccTailCallInfo occ = occ { occ_tail = NoTailCallInfo }++isAlwaysTailCalled :: OccInfo -> Bool+isAlwaysTailCalled occ+ = case tailCallInfo occ of AlwaysTailCalled{} -> True+ NoTailCallInfo -> False++instance Outputable TailCallInfo where+ ppr (AlwaysTailCalled ar) = sep [ text "Tail", int ar ]+ ppr _ = empty++-----------------+strongLoopBreaker, weakLoopBreaker :: OccInfo+strongLoopBreaker = IAmALoopBreaker False NoTailCallInfo+weakLoopBreaker = IAmALoopBreaker True NoTailCallInfo++isWeakLoopBreaker :: OccInfo -> Bool+isWeakLoopBreaker (IAmALoopBreaker{}) = True+isWeakLoopBreaker _ = False++isStrongLoopBreaker :: OccInfo -> Bool+isStrongLoopBreaker (IAmALoopBreaker { occ_rules_only = False }) = True+ -- Loop-breaker that breaks a non-rule cycle+isStrongLoopBreaker _ = False++isDeadOcc :: OccInfo -> Bool+isDeadOcc IAmDead = True+isDeadOcc _ = False++isOneOcc :: OccInfo -> Bool+isOneOcc (OneOcc {}) = True+isOneOcc _ = False++zapFragileOcc :: OccInfo -> OccInfo+-- Keep only the most robust data: deadness, loop-breaker-hood+zapFragileOcc (OneOcc {}) = noOccInfo+zapFragileOcc occ = zapOccTailCallInfo occ++instance Outputable OccInfo where+ -- only used for debugging; never parsed. KSW 1999-07+ ppr (ManyOccs tails) = pprShortTailCallInfo tails+ ppr IAmDead = text "Dead"+ ppr (IAmALoopBreaker rule_only tails)+ = text "LoopBreaker" <> pp_ro <> pprShortTailCallInfo tails+ where+ pp_ro | rule_only = char '!'+ | otherwise = empty+ ppr (OneOcc inside_lam one_branch int_cxt tail_info)+ = text "Once" <> pp_lam <> pp_br <> pp_args <> pp_tail+ where+ pp_lam | inside_lam = char 'L'+ | otherwise = empty+ pp_br | one_branch = empty+ | otherwise = char '*'+ pp_args | int_cxt = char '!'+ | otherwise = empty+ pp_tail = pprShortTailCallInfo tail_info++pprShortTailCallInfo :: TailCallInfo -> SDoc+pprShortTailCallInfo (AlwaysTailCalled ar) = char 'T' <> brackets (int ar)+pprShortTailCallInfo NoTailCallInfo = empty++{-+Note [TailCallInfo]+~~~~~~~~~~~~~~~~~~~+The occurrence analyser determines what can be made into a join point, but it+doesn't change the binder into a JoinId because then it would be inconsistent+with the occurrences. Thus it's left to the simplifier (or to simpleOptExpr) to+change the IdDetails.++The AlwaysTailCalled marker actually means slightly more than simply that the+function is always tail-called. See Note [Invariants on join points].++This info is quite fragile and should not be relied upon unless the occurrence+analyser has *just* run. Use 'Id.isJoinId_maybe' for the permanent state of+the join-point-hood of a binder; a join id itself will not be marked+AlwaysTailCalled.++Note that there is a 'TailCallInfo' on a 'ManyOccs' value. One might expect that+being tail-called would mean that the variable could only appear once per branch+(thus getting a `OneOcc { occ_one_br = True }` occurrence info), but a join+point can also be invoked from other join points, not just from case branches:++ let j1 x = ...+ j2 y = ... j1 z {- tail call -} ...+ in case w of+ A -> j1 v+ B -> j2 u+ C -> j2 q++Here both 'j1' and 'j2' will get marked AlwaysTailCalled, but j1 will get+ManyOccs and j2 will get `OneOcc { occ_one_br = True }`.++************************************************************************+* *+ Default method specification+* *+************************************************************************++The DefMethSpec enumeration just indicates what sort of default method+is used for a class. It is generated from source code, and present in+interface files; it is converted to Class.DefMethInfo before begin put in a+Class object.+-}++-- | Default Method Specification+data DefMethSpec ty+ = VanillaDM -- Default method given with polymorphic code+ | GenericDM ty -- Default method given with code of this type++instance Outputable (DefMethSpec ty) where+ ppr VanillaDM = text "{- Has default method -}"+ ppr (GenericDM {}) = text "{- Has generic default method -}"++{-+************************************************************************+* *+\subsection{Success flag}+* *+************************************************************************+-}++data SuccessFlag = Succeeded | Failed++instance Outputable SuccessFlag where+ ppr Succeeded = text "Succeeded"+ ppr Failed = text "Failed"++successIf :: Bool -> SuccessFlag+successIf True = Succeeded+successIf False = Failed++succeeded, failed :: SuccessFlag -> Bool+succeeded Succeeded = True+succeeded Failed = False++failed Succeeded = False+failed Failed = True++{-+************************************************************************+* *+\subsection{Source Text}+* *+************************************************************************+Keeping Source Text for source to source conversions++Note [Pragma source text]+~~~~~~~~~~~~~~~~~~~~~~~~~+The lexer does a case-insensitive match for pragmas, as well as+accepting both UK and US spelling variants.++So++ {-# SPECIALISE #-}+ {-# SPECIALIZE #-}+ {-# Specialize #-}++will all generate ITspec_prag token for the start of the pragma.++In order to be able to do source to source conversions, the original+source text for the token needs to be preserved, hence the+`SourceText` field.++So the lexer will then generate++ ITspec_prag "{ -# SPECIALISE"+ ITspec_prag "{ -# SPECIALIZE"+ ITspec_prag "{ -# Specialize"++for the cases above.+ [without the space between '{' and '-', otherwise this comment won't parse]+++Note [Literal source text]+~~~~~~~~~~~~~~~~~~~~~~~~~~+The lexer/parser converts literals from their original source text+versions to an appropriate internal representation. This is a problem+for tools doing source to source conversions, so the original source+text is stored in literals where this can occur.++Motivating examples for HsLit++ HsChar '\n' == '\x20`+ HsCharPrim '\x41`# == `A`+ HsString "\x20\x41" == " A"+ HsStringPrim "\x20"# == " "#+ HsInt 001 == 1+ HsIntPrim 002# == 2#+ HsWordPrim 003## == 3##+ HsInt64Prim 004## == 4##+ HsWord64Prim 005## == 5##+ HsInteger 006 == 6++For OverLitVal++ HsIntegral 003 == 0x003+ HsIsString "\x41nd" == "And"+-}++ -- Note [Literal source text],[Pragma source text]+data SourceText = SourceText String+ | NoSourceText -- ^ For when code is generated, e.g. TH,+ -- deriving. The pretty printer will then make+ -- its own representation of the item.+ deriving (Data, Show, Eq )++instance Outputable SourceText where+ ppr (SourceText s) = text "SourceText" <+> text s+ ppr NoSourceText = text "NoSourceText"++-- | Special combinator for showing string literals.+pprWithSourceText :: SourceText -> SDoc -> SDoc+pprWithSourceText NoSourceText d = d+pprWithSourceText (SourceText src) _ = text src++{-+************************************************************************+* *+\subsection{Activation}+* *+************************************************************************++When a rule or inlining is active+-}++-- | Phase Number+type PhaseNum = Int -- Compilation phase+ -- Phases decrease towards zero+ -- Zero is the last phase++data CompilerPhase+ = Phase PhaseNum+ | InitialPhase -- The first phase -- number = infinity!++instance Outputable CompilerPhase where+ ppr (Phase n) = int n+ ppr InitialPhase = text "InitialPhase"++-- See note [Pragma source text]+data Activation = NeverActive+ | AlwaysActive+ | ActiveBefore SourceText PhaseNum+ -- Active only *strictly before* this phase+ | ActiveAfter SourceText PhaseNum+ -- Active in this phase and later+ deriving( Eq, Data )+ -- Eq used in comparing rules in HsDecls++-- | Rule Match Information+data RuleMatchInfo = ConLike -- See Note [CONLIKE pragma]+ | FunLike+ deriving( Eq, Data, Show )+ -- Show needed for Lexer.x++data InlinePragma -- Note [InlinePragma]+ = InlinePragma+ { inl_src :: SourceText -- Note [Pragma source text]+ , inl_inline :: InlineSpec -- See Note [inl_inline and inl_act]++ , inl_sat :: Maybe Arity -- Just n <=> Inline only when applied to n+ -- explicit (non-type, non-dictionary) args+ -- That is, inl_sat describes the number of *source-code*+ -- arguments the thing must be applied to. We add on the+ -- number of implicit, dictionary arguments when making+ -- the Unfolding, and don't look at inl_sat further++ , inl_act :: Activation -- Says during which phases inlining is allowed+ -- See Note [inl_inline and inl_act]++ , inl_rule :: RuleMatchInfo -- Should the function be treated like a constructor?+ } deriving( Eq, Data )++-- | Inline Specification+data InlineSpec -- What the user's INLINE pragma looked like+ = Inline+ | Inlinable+ | NoInline+ | EmptyInlineSpec -- Used in a place-holder InlinePragma in SpecPrag or IdInfo,+ -- where there isn't any real inline pragma at all+ deriving( Eq, Data, Show )+ -- Show needed for Lexer.x++{- Note [InlinePragma]+~~~~~~~~~~~~~~~~~~~~~~+This data type mirrors what you can write in an INLINE or NOINLINE pragma in+the source program.++If you write nothing at all, you get defaultInlinePragma:+ inl_inline = EmptyInlineSpec+ inl_act = AlwaysActive+ inl_rule = FunLike++It's not possible to get that combination by *writing* something, so+if an Id has defaultInlinePragma it means the user didn't specify anything.++If inl_inline = Inline or Inlineable, then the Id should have an InlineRule unfolding.++If you want to know where InlinePragmas take effect: Look in DsBinds.makeCorePair++Note [inl_inline and inl_act]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* inl_inline says what the user wrote: did she say INLINE, NOINLINE,+ INLINABLE, or nothing at all++* inl_act says in what phases the unfolding is active or inactive+ E.g If you write INLINE[1] then inl_act will be set to ActiveAfter 1+ If you write NOINLINE[1] then inl_act will be set to ActiveBefore 1+ If you write NOINLINE[~1] then inl_act will be set to ActiveAfter 1+ So note that inl_act does not say what pragma you wrote: it just+ expresses its consequences++* inl_act just says when the unfolding is active; it doesn't say what+ to inline. If you say INLINE f, then f's inl_act will be AlwaysActive,+ but in addition f will get a "stable unfolding" with UnfoldingGuidance+ that tells the inliner to be pretty eager about it.++Note [CONLIKE pragma]+~~~~~~~~~~~~~~~~~~~~~+The ConLike constructor of a RuleMatchInfo is aimed at the following.+Consider first+ {-# RULE "r/cons" forall a as. r (a:as) = f (a+1) #-}+ g b bs = let x = b:bs in ..x...x...(r x)...+Now, the rule applies to the (r x) term, because GHC "looks through"+the definition of 'x' to see that it is (b:bs).++Now consider+ {-# RULE "r/f" forall v. r (f v) = f (v+1) #-}+ g v = let x = f v in ..x...x...(r x)...+Normally the (r x) would *not* match the rule, because GHC would be+scared about duplicating the redex (f v), so it does not "look+through" the bindings.++However the CONLIKE modifier says to treat 'f' like a constructor in+this situation, and "look through" the unfolding for x. So (r x)+fires, yielding (f (v+1)).++This is all controlled with a user-visible pragma:+ {-# NOINLINE CONLIKE [1] f #-}++The main effects of CONLIKE are:++ - The occurrence analyser (OccAnal) and simplifier (Simplify) treat+ CONLIKE thing like constructors, by ANF-ing them++ - New function coreUtils.exprIsExpandable is like exprIsCheap, but+ additionally spots applications of CONLIKE functions++ - A CoreUnfolding has a field that caches exprIsExpandable++ - The rule matcher consults this field. See+ Note [Expanding variables] in Rules.hs.+-}++isConLike :: RuleMatchInfo -> Bool+isConLike ConLike = True+isConLike _ = False++isFunLike :: RuleMatchInfo -> Bool+isFunLike FunLike = True+isFunLike _ = False++isEmptyInlineSpec :: InlineSpec -> Bool+isEmptyInlineSpec EmptyInlineSpec = True+isEmptyInlineSpec _ = False++defaultInlinePragma, alwaysInlinePragma, neverInlinePragma, dfunInlinePragma+ :: InlinePragma+defaultInlinePragma = InlinePragma { inl_src = SourceText "{-# INLINE"+ , inl_act = AlwaysActive+ , inl_rule = FunLike+ , inl_inline = EmptyInlineSpec+ , inl_sat = Nothing }++alwaysInlinePragma = defaultInlinePragma { inl_inline = Inline }+neverInlinePragma = defaultInlinePragma { inl_act = NeverActive }++inlinePragmaSpec :: InlinePragma -> InlineSpec+inlinePragmaSpec = inl_inline++-- A DFun has an always-active inline activation so that+-- exprIsConApp_maybe can "see" its unfolding+-- (However, its actual Unfolding is a DFunUnfolding, which is+-- never inlined other than via exprIsConApp_maybe.)+dfunInlinePragma = defaultInlinePragma { inl_act = AlwaysActive+ , inl_rule = ConLike }++isDefaultInlinePragma :: InlinePragma -> Bool+isDefaultInlinePragma (InlinePragma { inl_act = activation+ , inl_rule = match_info+ , inl_inline = inline })+ = isEmptyInlineSpec inline && isAlwaysActive activation && isFunLike match_info++isInlinePragma :: InlinePragma -> Bool+isInlinePragma prag = case inl_inline prag of+ Inline -> True+ _ -> False++isInlinablePragma :: InlinePragma -> Bool+isInlinablePragma prag = case inl_inline prag of+ Inlinable -> True+ _ -> False++isAnyInlinePragma :: InlinePragma -> Bool+-- INLINE or INLINABLE+isAnyInlinePragma prag = case inl_inline prag of+ Inline -> True+ Inlinable -> True+ _ -> False++inlinePragmaSat :: InlinePragma -> Maybe Arity+inlinePragmaSat = inl_sat++inlinePragmaActivation :: InlinePragma -> Activation+inlinePragmaActivation (InlinePragma { inl_act = activation }) = activation++inlinePragmaRuleMatchInfo :: InlinePragma -> RuleMatchInfo+inlinePragmaRuleMatchInfo (InlinePragma { inl_rule = info }) = info++setInlinePragmaActivation :: InlinePragma -> Activation -> InlinePragma+setInlinePragmaActivation prag activation = prag { inl_act = activation }++setInlinePragmaRuleMatchInfo :: InlinePragma -> RuleMatchInfo -> InlinePragma+setInlinePragmaRuleMatchInfo prag info = prag { inl_rule = info }++instance Outputable Activation where+ ppr AlwaysActive = empty+ ppr NeverActive = brackets (text "~")+ ppr (ActiveBefore _ n) = brackets (char '~' <> int n)+ ppr (ActiveAfter _ n) = brackets (int n)++instance Outputable RuleMatchInfo where+ ppr ConLike = text "CONLIKE"+ ppr FunLike = text "FUNLIKE"++instance Outputable InlineSpec where+ ppr Inline = text "INLINE"+ ppr NoInline = text "NOINLINE"+ ppr Inlinable = text "INLINABLE"+ ppr EmptyInlineSpec = empty++instance Outputable InlinePragma where+ ppr = pprInline++pprInline :: InlinePragma -> SDoc+pprInline = pprInline' True++pprInlineDebug :: InlinePragma -> SDoc+pprInlineDebug = pprInline' False++pprInline' :: Bool -> InlinePragma -> SDoc+pprInline' emptyInline (InlinePragma { inl_inline = inline, inl_act = activation+ , inl_rule = info, inl_sat = mb_arity })+ = pp_inl inline <> pp_act inline activation <+> pp_sat <+> pp_info+ where+ pp_inl x = if emptyInline then empty else ppr x++ pp_act Inline AlwaysActive = empty+ pp_act NoInline NeverActive = empty+ pp_act _ act = ppr act++ pp_sat | Just ar <- mb_arity = parens (text "sat-args=" <> int ar)+ | otherwise = empty+ pp_info | isFunLike info = empty+ | otherwise = ppr info++isActive :: CompilerPhase -> Activation -> Bool+isActive InitialPhase AlwaysActive = True+isActive InitialPhase (ActiveBefore {}) = True+isActive InitialPhase _ = False+isActive (Phase p) act = isActiveIn p act++isActiveIn :: PhaseNum -> Activation -> Bool+isActiveIn _ NeverActive = False+isActiveIn _ AlwaysActive = True+isActiveIn p (ActiveAfter _ n) = p <= n+isActiveIn p (ActiveBefore _ n) = p > n++competesWith :: Activation -> Activation -> Bool+-- See Note [Activation competition]+competesWith NeverActive _ = False+competesWith _ NeverActive = False+competesWith AlwaysActive _ = True++competesWith (ActiveBefore {}) AlwaysActive = True+competesWith (ActiveBefore {}) (ActiveBefore {}) = True+competesWith (ActiveBefore _ a) (ActiveAfter _ b) = a < b++competesWith (ActiveAfter {}) AlwaysActive = False+competesWith (ActiveAfter {}) (ActiveBefore {}) = False+competesWith (ActiveAfter _ a) (ActiveAfter _ b) = a >= b++{- Note [Competing activations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Sometimes a RULE and an inlining may compete, or two RULES.+See Note [Rules and inlining/other rules] in Desugar.++We say that act1 "competes with" act2 iff+ act1 is active in the phase when act2 *becomes* active+NB: remember that phases count *down*: 2, 1, 0!++It's too conservative to ensure that the two are never simultaneously+active. For example, a rule might be always active, and an inlining+might switch on in phase 2. We could switch off the rule, but it does+no harm.+-}++isNeverActive, isAlwaysActive, isEarlyActive :: Activation -> Bool+isNeverActive NeverActive = True+isNeverActive _ = False++isAlwaysActive AlwaysActive = True+isAlwaysActive _ = False++isEarlyActive AlwaysActive = True+isEarlyActive (ActiveBefore {}) = True+isEarlyActive _ = False++-- | Fractional Literal+--+-- Used (instead of Rational) to represent exactly the floating point literal that we+-- encountered in the user's source program. This allows us to pretty-print exactly what+-- the user wrote, which is important e.g. for floating point numbers that can't represented+-- as Doubles (we used to via Double for pretty-printing). See also #2245.+data FractionalLit+ = FL { fl_text :: String -- How the value was written in the source+ , fl_value :: Rational -- Numeric value of the literal+ }+ deriving (Data, Show)+ -- The Show instance is required for the derived Lexer.x:Token instance when DEBUG is on++negateFractionalLit :: FractionalLit -> FractionalLit+negateFractionalLit (FL { fl_text = '-':text, fl_value = value }) = FL { fl_text = text, fl_value = negate value }+negateFractionalLit (FL { fl_text = text, fl_value = value }) = FL { fl_text = '-':text, fl_value = negate value }++integralFractionalLit :: Integer -> FractionalLit+integralFractionalLit i = FL { fl_text = show i, fl_value = fromInteger i }++-- Comparison operations are needed when grouping literals+-- for compiling pattern-matching (module MatchLit)++instance Eq FractionalLit where+ (==) = (==) `on` fl_value++instance Ord FractionalLit where+ compare = compare `on` fl_value++instance Outputable FractionalLit where+ ppr = text . fl_text++{-+************************************************************************+* *+ IntWithInf+* *+************************************************************************++Represents an integer or positive infinity++-}++-- | An integer or infinity+data IntWithInf = Int {-# UNPACK #-} !Int+ | Infinity+ deriving Eq++-- | A representation of infinity+infinity :: IntWithInf+infinity = Infinity++instance Ord IntWithInf where+ compare Infinity Infinity = EQ+ compare (Int _) Infinity = LT+ compare Infinity (Int _) = GT+ compare (Int a) (Int b) = a `compare` b++instance Outputable IntWithInf where+ ppr Infinity = char '∞'+ ppr (Int n) = int n++instance Num IntWithInf where+ (+) = plusWithInf+ (*) = mulWithInf++ abs Infinity = Infinity+ abs (Int n) = Int (abs n)++ signum Infinity = Int 1+ signum (Int n) = Int (signum n)++ fromInteger = Int . fromInteger++ (-) = panic "subtracting IntWithInfs"++intGtLimit :: Int -> IntWithInf -> Bool+intGtLimit _ Infinity = False+intGtLimit n (Int m) = n > m++-- | Add two 'IntWithInf's+plusWithInf :: IntWithInf -> IntWithInf -> IntWithInf+plusWithInf Infinity _ = Infinity+plusWithInf _ Infinity = Infinity+plusWithInf (Int a) (Int b) = Int (a + b)++-- | Multiply two 'IntWithInf's+mulWithInf :: IntWithInf -> IntWithInf -> IntWithInf+mulWithInf Infinity _ = Infinity+mulWithInf _ Infinity = Infinity+mulWithInf (Int a) (Int b) = Int (a * b)++-- | Turn a positive number into an 'IntWithInf', where 0 represents infinity+treatZeroAsInf :: Int -> IntWithInf+treatZeroAsInf 0 = Infinity+treatZeroAsInf n = Int n++-- | Inject any integer into an 'IntWithInf'+mkIntWithInf :: Int -> IntWithInf+mkIntWithInf = Int++data SpliceExplicitFlag+ = ExplicitSplice | -- ^ <=> $(f x y)+ ImplicitSplice -- ^ <=> f x y, i.e. a naked top level expression+ deriving Data
+ basicTypes/ConLike.hs view
@@ -0,0 +1,192 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1998++\section[ConLike]{@ConLike@: Constructor-like things}+-}++{-# LANGUAGE CPP #-}++module ConLike (+ ConLike(..)+ , conLikeArity+ , conLikeFieldLabels+ , conLikeInstOrigArgTys+ , conLikeExTyVars+ , conLikeName+ , conLikeStupidTheta+ , conLikeWrapId_maybe+ , conLikeImplBangs+ , conLikeFullSig+ , conLikeResTy+ , conLikeFieldType+ , conLikesWithFields+ , conLikeIsInfix+ ) where++#include "HsVersions.h"++import DataCon+import PatSyn+import Outputable+import Unique+import Util+import Name+import BasicTypes+import TyCoRep (Type, ThetaType)+import Var+import Type (mkTyConApp)++import qualified Data.Data as Data++{-+************************************************************************+* *+\subsection{Constructor-like things}+* *+************************************************************************+-}++-- | A constructor-like thing+data ConLike = RealDataCon DataCon+ | PatSynCon PatSyn++{-+************************************************************************+* *+\subsection{Instances}+* *+************************************************************************+-}++instance Eq ConLike where+ (==) = eqConLike++eqConLike :: ConLike -> ConLike -> Bool+eqConLike x y = getUnique x == getUnique y++-- There used to be an Ord ConLike instance here that used Unique for ordering.+-- It was intentionally removed to prevent determinism problems.+-- See Note [Unique Determinism] in Unique.++instance Uniquable ConLike where+ getUnique (RealDataCon dc) = getUnique dc+ getUnique (PatSynCon ps) = getUnique ps++instance NamedThing ConLike where+ getName (RealDataCon dc) = getName dc+ getName (PatSynCon ps) = getName ps++instance Outputable ConLike where+ ppr (RealDataCon dc) = ppr dc+ ppr (PatSynCon ps) = ppr ps++instance OutputableBndr ConLike where+ pprInfixOcc (RealDataCon dc) = pprInfixOcc dc+ pprInfixOcc (PatSynCon ps) = pprInfixOcc ps+ pprPrefixOcc (RealDataCon dc) = pprPrefixOcc dc+ pprPrefixOcc (PatSynCon ps) = pprPrefixOcc ps++instance Data.Data ConLike where+ -- don't traverse?+ toConstr _ = abstractConstr "ConLike"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "ConLike"++-- | Number of arguments+conLikeArity :: ConLike -> Arity+conLikeArity (RealDataCon data_con) = dataConSourceArity data_con+conLikeArity (PatSynCon pat_syn) = patSynArity pat_syn++-- | Names of fields used for selectors+conLikeFieldLabels :: ConLike -> [FieldLabel]+conLikeFieldLabels (RealDataCon data_con) = dataConFieldLabels data_con+conLikeFieldLabels (PatSynCon pat_syn) = patSynFieldLabels pat_syn++-- | Returns just the instantiated /value/ argument types of a 'ConLike',+-- (excluding dictionary args)+conLikeInstOrigArgTys :: ConLike -> [Type] -> [Type]+conLikeInstOrigArgTys (RealDataCon data_con) tys =+ dataConInstOrigArgTys data_con tys+conLikeInstOrigArgTys (PatSynCon pat_syn) tys =+ patSynInstArgTys pat_syn tys++-- | Existentially quantified type variables+conLikeExTyVars :: ConLike -> [TyVar]+conLikeExTyVars (RealDataCon dcon1) = dataConExTyVars dcon1+conLikeExTyVars (PatSynCon psyn1) = patSynExTyVars psyn1++conLikeName :: ConLike -> Name+conLikeName (RealDataCon data_con) = dataConName data_con+conLikeName (PatSynCon pat_syn) = patSynName pat_syn++-- | The \"stupid theta\" of the 'ConLike', such as @data Eq a@ in:+--+-- > data Eq a => T a = ...+-- It is empty for `PatSynCon` as they do not allow such contexts.+conLikeStupidTheta :: ConLike -> ThetaType+conLikeStupidTheta (RealDataCon data_con) = dataConStupidTheta data_con+conLikeStupidTheta (PatSynCon {}) = []++-- | Returns the `Id` of the wrapper. This is also known as the builder in+-- some contexts. The value is Nothing only in the case of unidirectional+-- pattern synonyms.+conLikeWrapId_maybe :: ConLike -> Maybe Id+conLikeWrapId_maybe (RealDataCon data_con) = Just $ dataConWrapId data_con+conLikeWrapId_maybe (PatSynCon pat_syn) = fst <$> patSynBuilder pat_syn++-- | Returns the strictness information for each constructor+conLikeImplBangs :: ConLike -> [HsImplBang]+conLikeImplBangs (RealDataCon data_con) = dataConImplBangs data_con+conLikeImplBangs (PatSynCon pat_syn) =+ replicate (patSynArity pat_syn) HsLazy++-- | Returns the type of the whole pattern+conLikeResTy :: ConLike -> [Type] -> Type+conLikeResTy (RealDataCon con) tys = mkTyConApp (dataConTyCon con) tys+conLikeResTy (PatSynCon ps) tys = patSynInstResTy ps tys++-- | The \"full signature\" of the 'ConLike' returns, in order:+--+-- 1) The universally quantified type variables+--+-- 2) The existentially quantified type variables+--+-- 3) The equality specification+--+-- 4) The provided theta (the constraints provided by a match)+--+-- 5) The required theta (the constraints required for a match)+--+-- 6) The original argument types (i.e. before+-- any change of the representation of the type)+--+-- 7) The original result type+conLikeFullSig :: ConLike+ -> ([TyVar], [TyVar], [EqSpec]+ , ThetaType, ThetaType, [Type], Type)+conLikeFullSig (RealDataCon con) =+ let (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, res_ty) = dataConFullSig con+ -- Required theta is empty as normal data cons require no additional+ -- constraints for a match+ in (univ_tvs, ex_tvs, eq_spec, theta, [], arg_tys, res_ty)+conLikeFullSig (PatSynCon pat_syn) =+ let (univ_tvs, req, ex_tvs, prov, arg_tys, res_ty) = patSynSig pat_syn+ -- eqSpec is empty+ in (univ_tvs, ex_tvs, [], prov, req, arg_tys, res_ty)++-- | Extract the type for any given labelled field of the 'ConLike'+conLikeFieldType :: ConLike -> FieldLabelString -> Type+conLikeFieldType (PatSynCon ps) label = patSynFieldType ps label+conLikeFieldType (RealDataCon dc) label = dataConFieldType dc label+++-- | The ConLikes that have *all* the given fields+conLikesWithFields :: [ConLike] -> [FieldLabelString] -> [ConLike]+conLikesWithFields con_likes lbls = filter has_flds con_likes+ where has_flds dc = all (has_fld dc) lbls+ has_fld dc lbl = any (\ fl -> flLabel fl == lbl) (conLikeFieldLabels dc)++conLikeIsInfix :: ConLike -> Bool+conLikeIsInfix (RealDataCon dc) = dataConIsInfix dc+conLikeIsInfix (PatSynCon ps) = patSynIsInfix ps
+ basicTypes/ConLike.hs-boot view
@@ -0,0 +1,9 @@+module ConLike where+import {-# SOURCE #-} DataCon (DataCon)+import {-# SOURCE #-} PatSyn (PatSyn)+import Name ( Name )++data ConLike = RealDataCon DataCon+ | PatSynCon PatSyn++conLikeName :: ConLike -> Name
+ basicTypes/DataCon.hs view
@@ -0,0 +1,1324 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1998++\section[DataCon]{@DataCon@: Data Constructors}+-}++{-# LANGUAGE CPP, DeriveDataTypeable #-}++module DataCon (+ -- * Main data types+ DataCon, DataConRep(..),+ SrcStrictness(..), SrcUnpackedness(..),+ HsSrcBang(..), HsImplBang(..),+ StrictnessMark(..),+ ConTag,++ -- ** Equality specs+ EqSpec, mkEqSpec, eqSpecTyVar, eqSpecType,+ eqSpecPair, eqSpecPreds,+ substEqSpec, filterEqSpec,++ -- ** Field labels+ FieldLbl(..), FieldLabel, FieldLabelString,++ -- ** Type construction+ mkDataCon, buildAlgTyCon, buildSynTyCon, fIRST_TAG,++ -- ** Type deconstruction+ dataConRepType, dataConSig, dataConInstSig, dataConFullSig,+ dataConName, dataConIdentity, dataConTag, dataConTyCon,+ dataConOrigTyCon, dataConUserType,+ dataConUnivTyVars, dataConUnivTyVarBinders,+ dataConExTyVars, dataConExTyVarBinders,+ dataConAllTyVars,+ dataConEqSpec, dataConTheta,+ dataConStupidTheta,+ dataConInstArgTys, dataConOrigArgTys, dataConOrigResTy,+ dataConInstOrigArgTys, dataConRepArgTys,+ dataConFieldLabels, dataConFieldType, dataConFieldType_maybe,+ dataConSrcBangs,+ dataConSourceArity, dataConRepArity,+ dataConIsInfix,+ dataConWorkId, dataConWrapId, dataConWrapId_maybe,+ dataConImplicitTyThings,+ dataConRepStrictness, dataConImplBangs, dataConBoxer,++ splitDataProductType_maybe,++ -- ** Predicates on DataCons+ isNullarySrcDataCon, isNullaryRepDataCon, isTupleDataCon, isUnboxedTupleCon,+ isUnboxedSumCon,+ isVanillaDataCon, classDataCon, dataConCannotMatch,+ isBanged, isMarkedStrict, eqHsBang, isSrcStrict, isSrcUnpacked,+ specialPromotedDc, isLegacyPromotableDataCon, isLegacyPromotableTyCon,++ -- ** Promotion related functions+ promoteDataCon+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} MkId( DataConBoxer )+import Type+import ForeignCall ( CType )+import Coercion+import Unify+import TyCon+import FieldLabel+import Class+import Name+import PrelNames+import Var+import Outputable+import ListSetOps+import Util+import BasicTypes+import FastString+import Module+import Binary+import UniqSet+import Unique( mkAlphaTyVarUnique )++import qualified Data.Data as Data+import Data.Char+import Data.Word+import Data.List( mapAccumL, find )++{-+Data constructor representation+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the following Haskell data type declaration++ data T = T !Int ![Int]++Using the strictness annotations, GHC will represent this as++ data T = T Int# [Int]++That is, the Int has been unboxed. Furthermore, the Haskell source construction++ T e1 e2++is translated to++ case e1 of { I# x ->+ case e2 of { r ->+ T x r }}++That is, the first argument is unboxed, and the second is evaluated. Finally,+pattern matching is translated too:++ case e of { T a b -> ... }++becomes++ case e of { T a' b -> let a = I# a' in ... }++To keep ourselves sane, we name the different versions of the data constructor+differently, as follows.+++Note [Data Constructor Naming]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Each data constructor C has two, and possibly up to four, Names associated with it:++ OccName Name space Name of Notes+ ---------------------------------------------------------------------------+ The "data con itself" C DataName DataCon In dom( GlobalRdrEnv )+ The "worker data con" C VarName Id The worker+ The "wrapper data con" $WC VarName Id The wrapper+ The "newtype coercion" :CoT TcClsName TyCon++EVERY data constructor (incl for newtypes) has the former two (the+data con itself, and its worker. But only some data constructors have a+wrapper (see Note [The need for a wrapper]).++Each of these three has a distinct Unique. The "data con itself" name+appears in the output of the renamer, and names the Haskell-source+data constructor. The type checker translates it into either the wrapper Id+(if it exists) or worker Id (otherwise).++The data con has one or two Ids associated with it:++The "worker Id", is the actual data constructor.+* Every data constructor (newtype or data type) has a worker++* The worker is very like a primop, in that it has no binding.++* For a *data* type, the worker *is* the data constructor;+ it has no unfolding++* For a *newtype*, the worker has a compulsory unfolding which+ does a cast, e.g.+ newtype T = MkT Int+ The worker for MkT has unfolding+ \\(x:Int). x `cast` sym CoT+ Here CoT is the type constructor, witnessing the FC axiom+ axiom CoT : T = Int++The "wrapper Id", \$WC, goes as follows++* Its type is exactly what it looks like in the source program.++* It is an ordinary function, and it gets a top-level binding+ like any other function.++* The wrapper Id isn't generated for a data type if there is+ nothing for the wrapper to do. That is, if its defn would be+ \$wC = C++Note [The need for a wrapper]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Why might the wrapper have anything to do? Two reasons:++* Unboxing strict fields (with -funbox-strict-fields)+ data T = MkT !(Int,Int)+ \$wMkT :: (Int,Int) -> T+ \$wMkT (x,y) = MkT x y+ Notice that the worker has two fields where the wapper has+ just one. That is, the worker has type+ MkT :: Int -> Int -> T++* Equality constraints for GADTs+ data T a where { MkT :: a -> T [a] }++ The worker gets a type with explicit equality+ constraints, thus:+ MkT :: forall a b. (a=[b]) => b -> T a++ The wrapper has the programmer-specified type:+ \$wMkT :: a -> T [a]+ \$wMkT a x = MkT [a] a [a] x+ The third argument is a coercion+ [a] :: [a]~[a]++INVARIANT: the dictionary constructor for a class+ never has a wrapper.+++A note about the stupid context+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Data types can have a context:++ data (Eq a, Ord b) => T a b = T1 a b | T2 a++and that makes the constructors have a context too+(notice that T2's context is "thinned"):++ T1 :: (Eq a, Ord b) => a -> b -> T a b+ T2 :: (Eq a) => a -> T a b++Furthermore, this context pops up when pattern matching+(though GHC hasn't implemented this, but it is in H98, and+I've fixed GHC so that it now does):++ f (T2 x) = x+gets inferred type+ f :: Eq a => T a b -> a++I say the context is "stupid" because the dictionaries passed+are immediately discarded -- they do nothing and have no benefit.+It's a flaw in the language.++ Up to now [March 2002] I have put this stupid context into the+ type of the "wrapper" constructors functions, T1 and T2, but+ that turned out to be jolly inconvenient for generics, and+ record update, and other functions that build values of type T+ (because they don't have suitable dictionaries available).++ So now I've taken the stupid context out. I simply deal with+ it separately in the type checker on occurrences of a+ constructor, either in an expression or in a pattern.++ [May 2003: actually I think this decision could evasily be+ reversed now, and probably should be. Generics could be+ disabled for types with a stupid context; record updates now+ (H98) needs the context too; etc. It's an unforced change, so+ I'm leaving it for now --- but it does seem odd that the+ wrapper doesn't include the stupid context.]++[July 04] With the advent of generalised data types, it's less obvious+what the "stupid context" is. Consider+ C :: forall a. Ord a => a -> a -> T (Foo a)+Does the C constructor in Core contain the Ord dictionary? Yes, it must:++ f :: T b -> Ordering+ f = /\b. \x:T b.+ case x of+ C a (d:Ord a) (p:a) (q:a) -> compare d p q++Note that (Foo a) might not be an instance of Ord.++************************************************************************+* *+\subsection{Data constructors}+* *+************************************************************************+-}++-- | A data constructor+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+-- 'ApiAnnotation.AnnClose','ApiAnnotation.AnnComma'++-- For details on above see note [Api annotations] in ApiAnnotation+data DataCon+ = MkData {+ dcName :: Name, -- This is the name of the *source data con*+ -- (see "Note [Data Constructor Naming]" above)+ dcUnique :: Unique, -- Cached from Name+ dcTag :: ConTag, -- ^ Tag, used for ordering 'DataCon's++ -- Running example:+ --+ -- *** As declared by the user+ -- data T a where+ -- MkT :: forall x y. (x~y,Ord x) => x -> y -> T (x,y)++ -- *** As represented internally+ -- data T a where+ -- MkT :: forall a. forall x y. (a~(x,y),x~y,Ord x) => x -> y -> T a+ --+ -- The next six fields express the type of the constructor, in pieces+ -- e.g.+ --+ -- dcUnivTyVars = [a]+ -- dcExTyVars = [x,y]+ -- dcEqSpec = [a~(x,y)]+ -- dcOtherTheta = [x~y, Ord x]+ -- dcOrigArgTys = [x,y]+ -- dcRepTyCon = T++ -- In general, the dcUnivTyVars are NOT NECESSARILY THE SAME AS THE TYVARS+ -- FOR THE PARENT TyCon. (This is a change (Oct05): previously, vanilla+ -- datacons guaranteed to have the same type variables as their parent TyCon,+ -- but that seems ugly.)++ dcVanilla :: Bool, -- True <=> This is a vanilla Haskell 98 data constructor+ -- Its type is of form+ -- forall a1..an . t1 -> ... tm -> T a1..an+ -- No existentials, no coercions, nothing.+ -- That is: dcExTyVars = dcEqSpec = dcOtherTheta = []+ -- NB 1: newtypes always have a vanilla data con+ -- NB 2: a vanilla constructor can still be declared in GADT-style+ -- syntax, provided its type looks like the above.+ -- The declaration format is held in the TyCon (algTcGadtSyntax)++ -- Universally-quantified type vars [a,b,c]+ -- INVARIANT: length matches arity of the dcRepTyCon+ -- INVARIANT: result type of data con worker is exactly (T a b c)+ dcUnivTyVars :: [TyVarBinder],++ -- Existentially-quantified type vars [x,y]+ dcExTyVars :: [TyVarBinder],++ -- INVARIANT: the UnivTyVars and ExTyVars all have distinct OccNames+ -- Reason: less confusing, and easier to generate IfaceSyn++ dcEqSpec :: [EqSpec], -- Equalities derived from the result type,+ -- _as written by the programmer_++ -- This field allows us to move conveniently between the two ways+ -- of representing a GADT constructor's type:+ -- MkT :: forall a b. (a ~ [b]) => b -> T a+ -- MkT :: forall b. b -> T [b]+ -- Each equality is of the form (a ~ ty), where 'a' is one of+ -- the universally quantified type variables++ -- The next two fields give the type context of the data constructor+ -- (aside from the GADT constraints,+ -- which are given by the dcExpSpec)+ -- In GADT form, this is *exactly* what the programmer writes, even if+ -- the context constrains only universally quantified variables+ -- MkT :: forall a b. (a ~ b, Ord b) => a -> T a b+ dcOtherTheta :: ThetaType, -- The other constraints in the data con's type+ -- other than those in the dcEqSpec++ dcStupidTheta :: ThetaType, -- The context of the data type declaration+ -- data Eq a => T a = ...+ -- or, rather, a "thinned" version thereof+ -- "Thinned", because the Report says+ -- to eliminate any constraints that don't mention+ -- tyvars free in the arg types for this constructor+ --+ -- INVARIANT: the free tyvars of dcStupidTheta are a subset of dcUnivTyVars+ -- Reason: dcStupidTeta is gotten by thinning the stupid theta from the tycon+ --+ -- "Stupid", because the dictionaries aren't used for anything.+ -- Indeed, [as of March 02] they are no longer in the type of+ -- the wrapper Id, because that makes it harder to use the wrap-id+ -- to rebuild values after record selection or in generics.++ dcOrigArgTys :: [Type], -- Original argument types+ -- (before unboxing and flattening of strict fields)+ dcOrigResTy :: Type, -- Original result type, as seen by the user+ -- NB: for a data instance, the original user result type may+ -- differ from the DataCon's representation TyCon. Example+ -- data instance T [a] where MkT :: a -> T [a]+ -- The OrigResTy is T [a], but the dcRepTyCon might be :T123++ -- Now the strictness annotations and field labels of the constructor+ dcSrcBangs :: [HsSrcBang],+ -- See Note [Bangs on data constructor arguments]+ --+ -- The [HsSrcBang] as written by the programmer.+ --+ -- Matches 1-1 with dcOrigArgTys+ -- Hence length = dataConSourceArity dataCon++ dcFields :: [FieldLabel],+ -- Field labels for this constructor, in the+ -- same order as the dcOrigArgTys;+ -- length = 0 (if not a record) or dataConSourceArity.++ -- The curried worker function that corresponds to the constructor:+ -- It doesn't have an unfolding; the code generator saturates these Ids+ -- and allocates a real constructor when it finds one.+ dcWorkId :: Id,++ -- Constructor representation+ dcRep :: DataConRep,++ -- Cached; see Note [DataCon arities]+ -- INVARIANT: dcRepArity == length dataConRepArgTys+ -- INVARIANT: dcSourceArity == length dcOrigArgTys+ dcRepArity :: Arity,+ dcSourceArity :: Arity,++ -- Result type of constructor is T t1..tn+ dcRepTyCon :: TyCon, -- Result tycon, T++ dcRepType :: Type, -- Type of the constructor+ -- forall a x y. (a~(x,y), x~y, Ord x) =>+ -- x -> y -> T a+ -- (this is *not* of the constructor wrapper Id:+ -- see Note [Data con representation] below)+ -- Notice that the existential type parameters come *second*.+ -- Reason: in a case expression we may find:+ -- case (e :: T t) of+ -- MkT x y co1 co2 (d:Ord x) (v:r) (w:F s) -> ...+ -- It's convenient to apply the rep-type of MkT to 't', to get+ -- forall x y. (t~(x,y), x~y, Ord x) => x -> y -> T t+ -- and use that to check the pattern. Mind you, this is really only+ -- used in CoreLint.+++ dcInfix :: Bool, -- True <=> declared infix+ -- Used for Template Haskell and 'deriving' only+ -- The actual fixity is stored elsewhere++ dcPromoted :: TyCon -- The promoted TyCon+ -- See Note [Promoted data constructors] in TyCon+ }+++{- Note [TyVarBinders in DataCons]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For the TyVarBinders in a DataCon and PatSyn:++ * Each argument flag is Inferred or Specified.+ None are Required. (A DataCon is a term-level function; see+ Note [No Required TyBinder in terms] in TyCoRep.)++Why do we need the TyVarBinders, rather than just the TyVars? So that+we can construct the right type for the DataCon with its foralls+attributed the correce visiblity. That in turn governs whether you+can use visible type application at a call of the data constructor.++Note [DataCon arities]+~~~~~~~~~~~~~~~~~~~~~~+dcSourceArity does not take constraints into account,+but dcRepArity does. For example:+ MkT :: Ord a => a -> T a+ dcSourceArity = 1+ dcRepArity = 2+-}++-- | Data Constructor Representation+data DataConRep+ = NoDataConRep -- No wrapper++ | DCR { dcr_wrap_id :: Id -- Takes src args, unboxes/flattens,+ -- and constructs the representation++ , dcr_boxer :: DataConBoxer++ , dcr_arg_tys :: [Type] -- Final, representation argument types,+ -- after unboxing and flattening,+ -- and *including* all evidence args++ , dcr_stricts :: [StrictnessMark] -- 1-1 with dcr_arg_tys+ -- See also Note [Data-con worker strictness] in MkId.hs++ , dcr_bangs :: [HsImplBang] -- The actual decisions made (including failures)+ -- about the original arguments; 1-1 with orig_arg_tys+ -- See Note [Bangs on data constructor arguments]++ }+-- Algebraic data types always have a worker, and+-- may or may not have a wrapper, depending on whether+-- the wrapper does anything.+--+-- Data types have a worker with no unfolding+-- Newtypes just have a worker, which has a compulsory unfolding (just a cast)++-- _Neither_ the worker _nor_ the wrapper take the dcStupidTheta dicts as arguments++-- The wrapper (if it exists) takes dcOrigArgTys as its arguments+-- The worker takes dataConRepArgTys as its arguments+-- If the worker is absent, dataConRepArgTys is the same as dcOrigArgTys++-- The 'NoDataConRep' case is important+-- Not only is this efficient,+-- but it also ensures that the wrapper is replaced+-- by the worker (because it *is* the worker)+-- even when there are no args. E.g. in+-- f (:) x+-- the (:) *is* the worker.+-- This is really important in rule matching,+-- (We could match on the wrappers,+-- but that makes it less likely that rules will match+-- when we bring bits of unfoldings together.)++-------------------------++-- | Haskell Source Bang+--+-- Bangs on data constructor arguments as the user wrote them in the+-- source code.+--+-- @(HsSrcBang _ SrcUnpack SrcLazy)@ and+-- @(HsSrcBang _ SrcUnpack NoSrcStrict)@ (without StrictData) makes no sense, we+-- emit a warning (in checkValidDataCon) and treat it like+-- @(HsSrcBang _ NoSrcUnpack SrcLazy)@+data HsSrcBang =+ HsSrcBang SourceText -- Note [Pragma source text] in BasicTypes+ SrcUnpackedness+ SrcStrictness+ deriving Data.Data++-- | Haskell Implementation Bang+--+-- Bangs of data constructor arguments as generated by the compiler+-- after consulting HsSrcBang, flags, etc.+data HsImplBang+ = HsLazy -- ^ Lazy field+ | HsStrict -- ^ Strict but not unpacked field+ | HsUnpack (Maybe Coercion)+ -- ^ Strict and unpacked field+ -- co :: arg-ty ~ product-ty HsBang+ deriving Data.Data++-- | Source Strictness+--+-- What strictness annotation the user wrote+data SrcStrictness = SrcLazy -- ^ Lazy, ie '~'+ | SrcStrict -- ^ Strict, ie '!'+ | NoSrcStrict -- ^ no strictness annotation+ deriving (Eq, Data.Data)++-- | Source Unpackedness+--+-- What unpackedness the user requested+data SrcUnpackedness = SrcUnpack -- ^ {-# UNPACK #-} specified+ | SrcNoUnpack -- ^ {-# NOUNPACK #-} specified+ | NoSrcUnpack -- ^ no unpack pragma+ deriving (Eq, Data.Data)++++-------------------------+-- StrictnessMark is internal only, used to indicate strictness+-- of the DataCon *worker* fields+data StrictnessMark = MarkedStrict | NotMarkedStrict++-- | An 'EqSpec' is a tyvar/type pair representing an equality made in+-- rejigging a GADT constructor+data EqSpec = EqSpec TyVar+ Type++-- | Make an 'EqSpec'+mkEqSpec :: TyVar -> Type -> EqSpec+mkEqSpec tv ty = EqSpec tv ty++eqSpecTyVar :: EqSpec -> TyVar+eqSpecTyVar (EqSpec tv _) = tv++eqSpecType :: EqSpec -> Type+eqSpecType (EqSpec _ ty) = ty++eqSpecPair :: EqSpec -> (TyVar, Type)+eqSpecPair (EqSpec tv ty) = (tv, ty)++eqSpecPreds :: [EqSpec] -> ThetaType+eqSpecPreds spec = [ mkPrimEqPred (mkTyVarTy tv) ty+ | EqSpec tv ty <- spec ]++-- | Substitute in an 'EqSpec'. Precondition: if the LHS of the EqSpec+-- is mapped in the substitution, it is mapped to a type variable, not+-- a full type.+substEqSpec :: TCvSubst -> EqSpec -> EqSpec+substEqSpec subst (EqSpec tv ty)+ = EqSpec tv' (substTy subst ty)+ where+ tv' = getTyVar "substEqSpec" (substTyVar subst tv)++-- | Filter out any TyBinders mentioned in an EqSpec+filterEqSpec :: [EqSpec] -> [TyVarBinder] -> [TyVarBinder]+filterEqSpec eq_spec+ = filter not_in_eq_spec+ where+ not_in_eq_spec bndr = let var = binderVar bndr in+ all (not . (== var) . eqSpecTyVar) eq_spec++instance Outputable EqSpec where+ ppr (EqSpec tv ty) = ppr (tv, ty)++{- Note [Bangs on data constructor arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T = MkT !Int {-# UNPACK #-} !Int Bool++When compiling the module, GHC will decide how to represent+MkT, depending on the optimisation level, and settings of+flags like -funbox-small-strict-fields.++Terminology:+ * HsSrcBang: What the user wrote+ Constructors: HsSrcBang++ * HsImplBang: What GHC decided+ Constructors: HsLazy, HsStrict, HsUnpack++* If T was defined in this module, MkT's dcSrcBangs field+ records the [HsSrcBang] of what the user wrote; in the example+ [ HsSrcBang _ NoSrcUnpack SrcStrict+ , HsSrcBang _ SrcUnpack SrcStrict+ , HsSrcBang _ NoSrcUnpack NoSrcStrictness]++* However, if T was defined in an imported module, the importing module+ must follow the decisions made in the original module, regardless of+ the flag settings in the importing module.+ Also see Note [Bangs on imported data constructors] in MkId++* The dcr_bangs field of the dcRep field records the [HsImplBang]+ If T was defined in this module, Without -O the dcr_bangs might be+ [HsStrict, HsStrict, HsLazy]+ With -O it might be+ [HsStrict, HsUnpack _, HsLazy]+ With -funbox-small-strict-fields it might be+ [HsUnpack, HsUnpack _, HsLazy]+ With -XStrictData it might be+ [HsStrict, HsUnpack _, HsStrict]++Note [Data con representation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The dcRepType field contains the type of the representation of a constructor+This may differ from the type of the constructor *Id* (built+by MkId.mkDataConId) for two reasons:+ a) the constructor Id may be overloaded, but the dictionary isn't stored+ e.g. data Eq a => T a = MkT a a++ b) the constructor may store an unboxed version of a strict field.++Here's an example illustrating both:+ data Ord a => T a = MkT Int! a+Here+ T :: Ord a => Int -> a -> T a+but the rep type is+ Trep :: Int# -> a -> T a+Actually, the unboxed part isn't implemented yet!++++************************************************************************+* *+\subsection{Instances}+* *+************************************************************************+-}++instance Eq DataCon where+ a == b = getUnique a == getUnique b+ a /= b = getUnique a /= getUnique b++instance Uniquable DataCon where+ getUnique = dcUnique++instance NamedThing DataCon where+ getName = dcName++instance Outputable DataCon where+ ppr con = ppr (dataConName con)++instance OutputableBndr DataCon where+ pprInfixOcc con = pprInfixName (dataConName con)+ pprPrefixOcc con = pprPrefixName (dataConName con)++instance Data.Data DataCon where+ -- don't traverse?+ toConstr _ = abstractConstr "DataCon"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "DataCon"++instance Outputable HsSrcBang where+ ppr (HsSrcBang _ prag mark) = ppr prag <+> ppr mark++instance Outputable HsImplBang where+ ppr HsLazy = text "Lazy"+ ppr (HsUnpack Nothing) = text "Unpacked"+ ppr (HsUnpack (Just co)) = text "Unpacked" <> parens (ppr co)+ ppr HsStrict = text "StrictNotUnpacked"++instance Outputable SrcStrictness where+ ppr SrcLazy = char '~'+ ppr SrcStrict = char '!'+ ppr NoSrcStrict = empty++instance Outputable SrcUnpackedness where+ ppr SrcUnpack = text "{-# UNPACK #-}"+ ppr SrcNoUnpack = text "{-# NOUNPACK #-}"+ ppr NoSrcUnpack = empty++instance Outputable StrictnessMark where+ ppr MarkedStrict = text "!"+ ppr NotMarkedStrict = empty++instance Binary SrcStrictness where+ put_ bh SrcLazy = putByte bh 0+ put_ bh SrcStrict = putByte bh 1+ put_ bh NoSrcStrict = putByte bh 2++ get bh =+ do h <- getByte bh+ case h of+ 0 -> return SrcLazy+ 1 -> return SrcStrict+ _ -> return NoSrcStrict++instance Binary SrcUnpackedness where+ put_ bh SrcNoUnpack = putByte bh 0+ put_ bh SrcUnpack = putByte bh 1+ put_ bh NoSrcUnpack = putByte bh 2++ get bh =+ do h <- getByte bh+ case h of+ 0 -> return SrcNoUnpack+ 1 -> return SrcUnpack+ _ -> return NoSrcUnpack++-- | Compare strictness annotations+eqHsBang :: HsImplBang -> HsImplBang -> Bool+eqHsBang HsLazy HsLazy = True+eqHsBang HsStrict HsStrict = True+eqHsBang (HsUnpack Nothing) (HsUnpack Nothing) = True+eqHsBang (HsUnpack (Just c1)) (HsUnpack (Just c2))+ = eqType (coercionType c1) (coercionType c2)+eqHsBang _ _ = False++isBanged :: HsImplBang -> Bool+isBanged (HsUnpack {}) = True+isBanged (HsStrict {}) = True+isBanged HsLazy = False++isSrcStrict :: SrcStrictness -> Bool+isSrcStrict SrcStrict = True+isSrcStrict _ = False++isSrcUnpacked :: SrcUnpackedness -> Bool+isSrcUnpacked SrcUnpack = True+isSrcUnpacked _ = False++isMarkedStrict :: StrictnessMark -> Bool+isMarkedStrict NotMarkedStrict = False+isMarkedStrict _ = True -- All others are strict++{- *********************************************************************+* *+\subsection{Construction}+* *+********************************************************************* -}++-- | Build a new data constructor+mkDataCon :: Name+ -> Bool -- ^ Is the constructor declared infix?+ -> TyConRepName -- ^ TyConRepName for the promoted TyCon+ -> [HsSrcBang] -- ^ Strictness/unpack annotations, from user+ -> [FieldLabel] -- ^ Field labels for the constructor,+ -- if it is a record, otherwise empty+ -> [TyVarBinder] -- ^ Universals. See Note [TyVarBinders in DataCons]+ -> [TyVarBinder] -- ^ Existentials.+ -- (These last two must be Named and Inferred/Specified)+ -> [EqSpec] -- ^ GADT equalities+ -> ThetaType -- ^ Theta-type occuring before the arguments proper+ -> [Type] -- ^ Original argument types+ -> Type -- ^ Original result type+ -> RuntimeRepInfo -- ^ See comments on 'TyCon.RuntimeRepInfo'+ -> TyCon -- ^ Representation type constructor+ -> ThetaType -- ^ The "stupid theta", context of the data+ -- declaration e.g. @data Eq a => T a ...@+ -> Id -- ^ Worker Id+ -> DataConRep -- ^ Representation+ -> DataCon+ -- Can get the tag from the TyCon++mkDataCon name declared_infix prom_info+ arg_stricts -- Must match orig_arg_tys 1-1+ fields+ univ_tvs ex_tvs+ eq_spec theta+ orig_arg_tys orig_res_ty rep_info rep_tycon+ stupid_theta work_id rep+-- Warning: mkDataCon is not a good place to check invariants.+-- If the programmer writes the wrong result type in the decl, thus:+-- data T a where { MkT :: S }+-- then it's possible that the univ_tvs may hit an assertion failure+-- if you pull on univ_tvs. This case is checked by checkValidDataCon,+-- so the error is detected properly... it's just that asaertions here+-- are a little dodgy.++ = con+ where+ is_vanilla = null ex_tvs && null eq_spec && null theta+ con = MkData {dcName = name, dcUnique = nameUnique name,+ dcVanilla = is_vanilla, dcInfix = declared_infix,+ dcUnivTyVars = univ_tvs,+ dcExTyVars = ex_tvs,+ dcEqSpec = eq_spec,+ dcOtherTheta = theta,+ dcStupidTheta = stupid_theta,+ dcOrigArgTys = orig_arg_tys, dcOrigResTy = orig_res_ty,+ dcRepTyCon = rep_tycon,+ dcSrcBangs = arg_stricts,+ dcFields = fields, dcTag = tag, dcRepType = rep_ty,+ dcWorkId = work_id,+ dcRep = rep,+ dcSourceArity = length orig_arg_tys,+ dcRepArity = length rep_arg_tys,+ dcPromoted = promoted }++ -- The 'arg_stricts' passed to mkDataCon are simply those for the+ -- source-language arguments. We add extra ones for the+ -- dictionary arguments right here.++ tag = assoc "mkDataCon" (tyConDataCons rep_tycon `zip` [fIRST_TAG..]) con+ rep_arg_tys = dataConRepArgTys con++ rep_ty = mkForAllTys univ_tvs $ mkForAllTys ex_tvs $+ mkFunTys rep_arg_tys $+ mkTyConApp rep_tycon (mkTyVarTys (binderVars univ_tvs))++ -- See Note [Promoted data constructors] in TyCon+ prom_tv_bndrs = [ mkNamedTyConBinder vis tv+ | TvBndr tv vis <- filterEqSpec eq_spec univ_tvs ++ ex_tvs ]++ prom_arg_bndrs = mkCleanAnonTyConBinders prom_tv_bndrs (theta ++ orig_arg_tys)+ prom_res_kind = orig_res_ty+ promoted = mkPromotedDataCon con name prom_info+ (prom_tv_bndrs ++ prom_arg_bndrs)+ prom_res_kind roles rep_info++ roles = map (const Nominal) (univ_tvs ++ ex_tvs) +++ map (const Representational) orig_arg_tys++mkCleanAnonTyConBinders :: [TyConBinder] -> [Type] -> [TyConBinder]+-- Make sure that the "anonymous" tyvars don't clash in+-- name or unique with the universal/existential ones.+-- Tiresome! And unnecessary because these tyvars are never looked at+mkCleanAnonTyConBinders tc_bndrs tys+ = [ mkAnonTyConBinder (mkTyVar name ty)+ | (name, ty) <- fresh_names `zip` tys ]+ where+ fresh_names = freshNames (map getName (binderVars tc_bndrs))++freshNames :: [Name] -> [Name]+-- Make names whose Uniques and OccNames differ from+-- those in the 'avoid' list+freshNames avoids+ = [ mkSystemName uniq occ+ | n <- [0..]+ , let uniq = mkAlphaTyVarUnique n+ occ = mkTyVarOccFS (mkFastString ('x' : show n))++ , not (uniq `elementOfUniqSet` avoid_uniqs)+ , not (occ `elemOccSet` avoid_occs) ]++ where+ avoid_uniqs :: UniqSet Unique+ avoid_uniqs = mkUniqSet (map getUnique avoids)++ avoid_occs :: OccSet+ avoid_occs = mkOccSet (map getOccName avoids)++-- | The 'Name' of the 'DataCon', giving it a unique, rooted identification+dataConName :: DataCon -> Name+dataConName = dcName++-- | The tag used for ordering 'DataCon's+dataConTag :: DataCon -> ConTag+dataConTag = dcTag++-- | The type constructor that we are building via this data constructor+dataConTyCon :: DataCon -> TyCon+dataConTyCon = dcRepTyCon++-- | The original type constructor used in the definition of this data+-- constructor. In case of a data family instance, that will be the family+-- type constructor.+dataConOrigTyCon :: DataCon -> TyCon+dataConOrigTyCon dc+ | Just (tc, _) <- tyConFamInst_maybe (dcRepTyCon dc) = tc+ | otherwise = dcRepTyCon dc++-- | The representation type of the data constructor, i.e. the sort+-- type that will represent values of this type at runtime+dataConRepType :: DataCon -> Type+dataConRepType = dcRepType++-- | Should the 'DataCon' be presented infix?+dataConIsInfix :: DataCon -> Bool+dataConIsInfix = dcInfix++-- | The universally-quantified type variables of the constructor+dataConUnivTyVars :: DataCon -> [TyVar]+dataConUnivTyVars (MkData { dcUnivTyVars = tvbs }) = binderVars tvbs++-- | 'TyBinder's for the universally-quantified type variables+dataConUnivTyVarBinders :: DataCon -> [TyVarBinder]+dataConUnivTyVarBinders = dcUnivTyVars++-- | The existentially-quantified type variables of the constructor+dataConExTyVars :: DataCon -> [TyVar]+dataConExTyVars (MkData { dcExTyVars = tvbs }) = binderVars tvbs++-- | 'TyBinder's for the existentially-quantified type variables+dataConExTyVarBinders :: DataCon -> [TyVarBinder]+dataConExTyVarBinders = dcExTyVars++-- | Both the universal and existentiatial type variables of the constructor+dataConAllTyVars :: DataCon -> [TyVar]+dataConAllTyVars (MkData { dcUnivTyVars = univ_tvs, dcExTyVars = ex_tvs })+ = binderVars (univ_tvs ++ ex_tvs)++-- | Equalities derived from the result type of the data constructor, as written+-- by the programmer in any GADT declaration. This includes *all* GADT-like+-- equalities, including those written in by hand by the programmer.+dataConEqSpec :: DataCon -> [EqSpec]+dataConEqSpec (MkData { dcEqSpec = eq_spec, dcOtherTheta = theta })+ = eq_spec +++ [ spec -- heterogeneous equality+ | Just (tc, [_k1, _k2, ty1, ty2]) <- map splitTyConApp_maybe theta+ , tc `hasKey` heqTyConKey+ , spec <- case (getTyVar_maybe ty1, getTyVar_maybe ty2) of+ (Just tv1, _) -> [mkEqSpec tv1 ty2]+ (_, Just tv2) -> [mkEqSpec tv2 ty1]+ _ -> []+ ] +++ [ spec -- homogeneous equality+ | Just (tc, [_k, ty1, ty2]) <- map splitTyConApp_maybe theta+ , tc `hasKey` eqTyConKey+ , spec <- case (getTyVar_maybe ty1, getTyVar_maybe ty2) of+ (Just tv1, _) -> [mkEqSpec tv1 ty2]+ (_, Just tv2) -> [mkEqSpec tv2 ty1]+ _ -> []+ ]+++-- | The *full* constraints on the constructor type.+dataConTheta :: DataCon -> ThetaType+dataConTheta (MkData { dcEqSpec = eq_spec, dcOtherTheta = theta })+ = eqSpecPreds eq_spec ++ theta++-- | Get the Id of the 'DataCon' worker: a function that is the "actual"+-- constructor and has no top level binding in the program. The type may+-- be different from the obvious one written in the source program. Panics+-- if there is no such 'Id' for this 'DataCon'+dataConWorkId :: DataCon -> Id+dataConWorkId dc = dcWorkId dc++-- | Get the Id of the 'DataCon' wrapper: a function that wraps the "actual"+-- constructor so it has the type visible in the source program: c.f. 'dataConWorkId'.+-- Returns Nothing if there is no wrapper, which occurs for an algebraic data constructor+-- and also for a newtype (whose constructor is inlined compulsorily)+dataConWrapId_maybe :: DataCon -> Maybe Id+dataConWrapId_maybe dc = case dcRep dc of+ NoDataConRep -> Nothing+ DCR { dcr_wrap_id = wrap_id } -> Just wrap_id++-- | Returns an Id which looks like the Haskell-source constructor by using+-- the wrapper if it exists (see 'dataConWrapId_maybe') and failing over to+-- the worker (see 'dataConWorkId')+dataConWrapId :: DataCon -> Id+dataConWrapId dc = case dcRep dc of+ NoDataConRep-> dcWorkId dc -- worker=wrapper+ DCR { dcr_wrap_id = wrap_id } -> wrap_id++-- | Find all the 'Id's implicitly brought into scope by the data constructor. Currently,+-- the union of the 'dataConWorkId' and the 'dataConWrapId'+dataConImplicitTyThings :: DataCon -> [TyThing]+dataConImplicitTyThings (MkData { dcWorkId = work, dcRep = rep })+ = [AnId work] ++ wrap_ids+ where+ wrap_ids = case rep of+ NoDataConRep -> []+ DCR { dcr_wrap_id = wrap } -> [AnId wrap]++-- | The labels for the fields of this particular 'DataCon'+dataConFieldLabels :: DataCon -> [FieldLabel]+dataConFieldLabels = dcFields++-- | Extract the type for any given labelled field of the 'DataCon'+dataConFieldType :: DataCon -> FieldLabelString -> Type+dataConFieldType con label = case dataConFieldType_maybe con label of+ Just (_, ty) -> ty+ Nothing -> pprPanic "dataConFieldType" (ppr con <+> ppr label)++-- | Extract the label and type for any given labelled field of the+-- 'DataCon', or return 'Nothing' if the field does not belong to it+dataConFieldType_maybe :: DataCon -> FieldLabelString+ -> Maybe (FieldLabel, Type)+dataConFieldType_maybe con label+ = find ((== label) . flLabel . fst) (dcFields con `zip` dcOrigArgTys con)++-- | Strictness/unpack annotations, from user; or, for imported+-- DataCons, from the interface file+-- The list is in one-to-one correspondence with the arity of the 'DataCon'++dataConSrcBangs :: DataCon -> [HsSrcBang]+dataConSrcBangs = dcSrcBangs++-- | Source-level arity of the data constructor+dataConSourceArity :: DataCon -> Arity+dataConSourceArity (MkData { dcSourceArity = arity }) = arity++-- | Gives the number of actual fields in the /representation/ of the+-- data constructor. This may be more than appear in the source code;+-- the extra ones are the existentially quantified dictionaries+dataConRepArity :: DataCon -> Arity+dataConRepArity (MkData { dcRepArity = arity }) = arity++-- | Return whether there are any argument types for this 'DataCon's original source type+-- See Note [DataCon arities]+isNullarySrcDataCon :: DataCon -> Bool+isNullarySrcDataCon dc = dataConSourceArity dc == 0++-- | Return whether there are any argument types for this 'DataCon's runtime representation type+-- See Note [DataCon arities]+isNullaryRepDataCon :: DataCon -> Bool+isNullaryRepDataCon dc = dataConRepArity dc == 0++dataConRepStrictness :: DataCon -> [StrictnessMark]+-- ^ Give the demands on the arguments of a+-- Core constructor application (Con dc args)+dataConRepStrictness dc = case dcRep dc of+ NoDataConRep -> [NotMarkedStrict | _ <- dataConRepArgTys dc]+ DCR { dcr_stricts = strs } -> strs++dataConImplBangs :: DataCon -> [HsImplBang]+-- The implementation decisions about the strictness/unpack of each+-- source program argument to the data constructor+dataConImplBangs dc+ = case dcRep dc of+ NoDataConRep -> replicate (dcSourceArity dc) HsLazy+ DCR { dcr_bangs = bangs } -> bangs++dataConBoxer :: DataCon -> Maybe DataConBoxer+dataConBoxer (MkData { dcRep = DCR { dcr_boxer = boxer } }) = Just boxer+dataConBoxer _ = Nothing++-- | The \"signature\" of the 'DataCon' returns, in order:+--+-- 1) The result of 'dataConAllTyVars',+--+-- 2) All the 'ThetaType's relating to the 'DataCon' (coercion, dictionary, implicit+-- parameter - whatever)+--+-- 3) The type arguments to the constructor+--+-- 4) The /original/ result type of the 'DataCon'+dataConSig :: DataCon -> ([TyVar], ThetaType, [Type], Type)+dataConSig con@(MkData {dcOrigArgTys = arg_tys, dcOrigResTy = res_ty})+ = (dataConAllTyVars con, dataConTheta con, arg_tys, res_ty)++dataConInstSig+ :: DataCon+ -> [Type] -- Instantiate the *universal* tyvars with these types+ -> ([TyVar], ThetaType, [Type]) -- Return instantiated existentials+ -- theta and arg tys+-- ^ Instantantiate the universal tyvars of a data con,+-- returning the instantiated existentials, constraints, and args+dataConInstSig (MkData { dcUnivTyVars = univ_tvs, dcExTyVars = ex_tvs+ , dcEqSpec = eq_spec, dcOtherTheta = theta+ , dcOrigArgTys = arg_tys })+ univ_tys+ = ( ex_tvs'+ , substTheta subst (eqSpecPreds eq_spec ++ theta)+ , substTys subst arg_tys)+ where+ univ_subst = zipTvSubst (binderVars univ_tvs) univ_tys+ (subst, ex_tvs') = mapAccumL Type.substTyVarBndr univ_subst $+ binderVars ex_tvs+++-- | The \"full signature\" of the 'DataCon' returns, in order:+--+-- 1) The result of 'dataConUnivTyVars'+--+-- 2) The result of 'dataConExTyVars'+--+-- 3) The GADT equalities+--+-- 4) The result of 'dataConDictTheta'+--+-- 5) The original argument types to the 'DataCon' (i.e. before+-- any change of the representation of the type)+--+-- 6) The original result type of the 'DataCon'+dataConFullSig :: DataCon+ -> ([TyVar], [TyVar], [EqSpec], ThetaType, [Type], Type)+dataConFullSig (MkData {dcUnivTyVars = univ_tvs, dcExTyVars = ex_tvs,+ dcEqSpec = eq_spec, dcOtherTheta = theta,+ dcOrigArgTys = arg_tys, dcOrigResTy = res_ty})+ = (binderVars univ_tvs, binderVars ex_tvs, eq_spec, theta, arg_tys, res_ty)++dataConOrigResTy :: DataCon -> Type+dataConOrigResTy dc = dcOrigResTy dc++-- | The \"stupid theta\" of the 'DataCon', such as @data Eq a@ in:+--+-- > data Eq a => T a = ...+dataConStupidTheta :: DataCon -> ThetaType+dataConStupidTheta dc = dcStupidTheta dc++dataConUserType :: DataCon -> Type+-- ^ The user-declared type of the data constructor+-- in the nice-to-read form:+--+-- > T :: forall a b. a -> b -> T [a]+--+-- rather than:+--+-- > T :: forall a c. forall b. (c~[a]) => a -> b -> T c+--+-- NB: If the constructor is part of a data instance, the result type+-- mentions the family tycon, not the internal one.+dataConUserType (MkData { dcUnivTyVars = univ_tvs,+ dcExTyVars = ex_tvs, dcEqSpec = eq_spec,+ dcOtherTheta = theta, dcOrigArgTys = arg_tys,+ dcOrigResTy = res_ty })+ = mkForAllTys (filterEqSpec eq_spec univ_tvs) $+ mkForAllTys ex_tvs $+ mkFunTys theta $+ mkFunTys arg_tys $+ res_ty++-- | Finds the instantiated types of the arguments required to construct a 'DataCon' representation+-- NB: these INCLUDE any dictionary args+-- but EXCLUDE the data-declaration context, which is discarded+-- It's all post-flattening etc; this is a representation type+dataConInstArgTys :: DataCon -- ^ A datacon with no existentials or equality constraints+ -- However, it can have a dcTheta (notably it can be a+ -- class dictionary, with superclasses)+ -> [Type] -- ^ Instantiated at these types+ -> [Type]+dataConInstArgTys dc@(MkData {dcUnivTyVars = univ_tvs,+ dcExTyVars = ex_tvs}) inst_tys+ = ASSERT2( length univ_tvs == length inst_tys+ , text "dataConInstArgTys" <+> ppr dc $$ ppr univ_tvs $$ ppr inst_tys)+ ASSERT2( null ex_tvs, ppr dc )+ map (substTyWith (binderVars univ_tvs) inst_tys) (dataConRepArgTys dc)++-- | Returns just the instantiated /value/ argument types of a 'DataCon',+-- (excluding dictionary args)+dataConInstOrigArgTys+ :: DataCon -- Works for any DataCon+ -> [Type] -- Includes existential tyvar args, but NOT+ -- equality constraints or dicts+ -> [Type]+-- For vanilla datacons, it's all quite straightforward+-- But for the call in MatchCon, we really do want just the value args+dataConInstOrigArgTys dc@(MkData {dcOrigArgTys = arg_tys,+ dcUnivTyVars = univ_tvs,+ dcExTyVars = ex_tvs}) inst_tys+ = ASSERT2( length tyvars == length inst_tys+ , text "dataConInstOrigArgTys" <+> ppr dc $$ ppr tyvars $$ ppr inst_tys )+ map (substTyWith tyvars inst_tys) arg_tys+ where+ tyvars = binderVars (univ_tvs ++ ex_tvs)++-- | Returns the argument types of the wrapper, excluding all dictionary arguments+-- and without substituting for any type variables+dataConOrigArgTys :: DataCon -> [Type]+dataConOrigArgTys dc = dcOrigArgTys dc++-- | Returns the arg types of the worker, including *all*+-- evidence, after any flattening has been done and without substituting for+-- any type variables+dataConRepArgTys :: DataCon -> [Type]+dataConRepArgTys (MkData { dcRep = rep+ , dcEqSpec = eq_spec+ , dcOtherTheta = theta+ , dcOrigArgTys = orig_arg_tys })+ = case rep of+ NoDataConRep -> ASSERT( null eq_spec ) theta ++ orig_arg_tys+ DCR { dcr_arg_tys = arg_tys } -> arg_tys++-- | The string @package:module.name@ identifying a constructor, which is attached+-- to its info table and used by the GHCi debugger and the heap profiler+dataConIdentity :: DataCon -> [Word8]+-- We want this string to be UTF-8, so we get the bytes directly from the FastStrings.+dataConIdentity dc = bytesFS (unitIdFS (moduleUnitId mod)) +++ fromIntegral (ord ':') : bytesFS (moduleNameFS (moduleName mod)) +++ fromIntegral (ord '.') : bytesFS (occNameFS (nameOccName name))+ where name = dataConName dc+ mod = ASSERT( isExternalName name ) nameModule name++isTupleDataCon :: DataCon -> Bool+isTupleDataCon (MkData {dcRepTyCon = tc}) = isTupleTyCon tc++isUnboxedTupleCon :: DataCon -> Bool+isUnboxedTupleCon (MkData {dcRepTyCon = tc}) = isUnboxedTupleTyCon tc++isUnboxedSumCon :: DataCon -> Bool+isUnboxedSumCon (MkData {dcRepTyCon = tc}) = isUnboxedSumTyCon tc++-- | Vanilla 'DataCon's are those that are nice boring Haskell 98 constructors+isVanillaDataCon :: DataCon -> Bool+isVanillaDataCon dc = dcVanilla dc++-- | Should this DataCon be allowed in a type even without -XDataKinds?+-- Currently, only Lifted & Unlifted+specialPromotedDc :: DataCon -> Bool+specialPromotedDc = isKindTyCon . dataConTyCon++-- | Was this datacon promotable before GHC 8.0? That is, is it promotable+-- without -XTypeInType+isLegacyPromotableDataCon :: DataCon -> Bool+isLegacyPromotableDataCon dc+ = null (dataConEqSpec dc) -- no GADTs+ && null (dataConTheta dc) -- no context+ && not (isFamInstTyCon (dataConTyCon dc)) -- no data instance constructors+ && uniqSetAll isLegacyPromotableTyCon (tyConsOfType (dataConUserType dc))++-- | Was this tycon promotable before GHC 8.0? That is, is it promotable+-- without -XTypeInType+isLegacyPromotableTyCon :: TyCon -> Bool+isLegacyPromotableTyCon tc+ = isVanillaAlgTyCon tc ||+ -- This returns True more often than it should, but it's quite painful+ -- to make this fully accurate. And no harm is caused; we just don't+ -- require -XTypeInType every time we need to. (We'll always require+ -- -XDataKinds, though, so there's no standards-compliance issue.)+ isFunTyCon tc || isKindTyCon tc++classDataCon :: Class -> DataCon+classDataCon clas = case tyConDataCons (classTyCon clas) of+ (dict_constr:no_more) -> ASSERT( null no_more ) dict_constr+ [] -> panic "classDataCon"++dataConCannotMatch :: [Type] -> DataCon -> Bool+-- Returns True iff the data con *definitely cannot* match a+-- scrutinee of type (T tys)+-- where T is the dcRepTyCon for the data con+dataConCannotMatch tys con+ | null inst_theta = False -- Common+ | all isTyVarTy tys = False -- Also common+ | otherwise = typesCantMatch (concatMap predEqs inst_theta)+ where+ (_, inst_theta, _) = dataConInstSig con tys++ -- TODO: could gather equalities from superclasses too+ predEqs pred = case classifyPredType pred of+ EqPred NomEq ty1 ty2 -> [(ty1, ty2)]+ ClassPred eq [_, ty1, ty2]+ | eq `hasKey` eqTyConKey -> [(ty1, ty2)]+ _ -> []++{-+%************************************************************************+%* *+ Promoting of data types to the kind level+* *+************************************************************************++-}++promoteDataCon :: DataCon -> TyCon+promoteDataCon (MkData { dcPromoted = tc }) = tc++{-+************************************************************************+* *+\subsection{Splitting products}+* *+************************************************************************+-}++-- | Extract the type constructor, type argument, data constructor and it's+-- /representation/ argument types from a type if it is a product type.+--+-- Precisely, we return @Just@ for any type that is all of:+--+-- * Concrete (i.e. constructors visible)+--+-- * Single-constructor+--+-- * Not existentially quantified+--+-- Whether the type is a @data@ type or a @newtype@+splitDataProductType_maybe+ :: Type -- ^ A product type, perhaps+ -> Maybe (TyCon, -- The type constructor+ [Type], -- Type args of the tycon+ DataCon, -- The data constructor+ [Type]) -- Its /representation/ arg types++ -- Rejecting existentials is conservative. Maybe some things+ -- could be made to work with them, but I'm not going to sweat+ -- it through till someone finds it's important.++splitDataProductType_maybe ty+ | Just (tycon, ty_args) <- splitTyConApp_maybe ty+ , Just con <- isDataProductTyCon_maybe tycon+ = Just (tycon, ty_args, con, dataConInstArgTys con ty_args)+ | otherwise+ = Nothing++{-+************************************************************************+* *+ Building an algebraic data type+* *+************************************************************************++buildAlgTyCon is here because it is called from TysWiredIn, which can+depend on this module, but not on BuildTyCl.+-}++buildAlgTyCon :: Name+ -> [TyVar] -- ^ Kind variables and type variables+ -> [Role]+ -> Maybe CType+ -> ThetaType -- ^ Stupid theta+ -> AlgTyConRhs+ -> Bool -- ^ True <=> was declared in GADT syntax+ -> AlgTyConFlav+ -> TyCon++buildAlgTyCon tc_name ktvs roles cType stupid_theta rhs+ gadt_syn parent+ = mkAlgTyCon tc_name binders liftedTypeKind roles cType stupid_theta+ rhs parent gadt_syn+ where+ binders = mkTyConBindersPreferAnon ktvs liftedTypeKind++buildSynTyCon :: Name -> [TyConBinder] -> Kind -- ^ /result/ kind+ -> [Role] -> Type -> TyCon+buildSynTyCon name binders res_kind roles rhs+ = mkSynonymTyCon name binders res_kind roles rhs is_tau is_fam_free+ where+ is_tau = isTauTy rhs+ is_fam_free = isFamFreeTy rhs
+ basicTypes/DataCon.hs-boot view
@@ -0,0 +1,32 @@+module DataCon where+import Var( TyVar, TyVarBinder )+import Name( Name, NamedThing )+import {-# SOURCE #-} TyCon( TyCon )+import FieldLabel ( FieldLabel )+import Unique ( Uniquable )+import Outputable ( Outputable, OutputableBndr )+import BasicTypes (Arity)+import {-# SOURCE #-} TyCoRep ( Type, ThetaType )++data DataCon+data DataConRep+data EqSpec+filterEqSpec :: [EqSpec] -> [TyVarBinder] -> [TyVarBinder]++dataConName :: DataCon -> Name+dataConTyCon :: DataCon -> TyCon+dataConUnivTyVarBinders :: DataCon -> [TyVarBinder]+dataConExTyVars :: DataCon -> [TyVar]+dataConExTyVarBinders :: DataCon -> [TyVarBinder]+dataConSourceArity :: DataCon -> Arity+dataConFieldLabels :: DataCon -> [FieldLabel]+dataConInstOrigArgTys :: DataCon -> [Type] -> [Type]+dataConStupidTheta :: DataCon -> ThetaType+dataConFullSig :: DataCon+ -> ([TyVar], [TyVar], [EqSpec], ThetaType, [Type], Type)++instance Eq DataCon+instance Uniquable DataCon+instance NamedThing DataCon+instance Outputable DataCon+instance OutputableBndr DataCon
+ basicTypes/Demand.hs view
@@ -0,0 +1,2173 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[Demand]{@Demand@: A decoupled implementation of a demand domain}+-}++{-# LANGUAGE CPP, FlexibleInstances, TypeSynonymInstances, RecordWildCards #-}++module Demand (+ StrDmd, UseDmd(..), Count,++ Demand, CleanDemand, getStrDmd, getUseDmd,+ mkProdDmd, mkOnceUsedDmd, mkManyUsedDmd, mkHeadStrict, oneifyDmd,+ toCleanDmd,+ absDmd, topDmd, botDmd, seqDmd,+ lubDmd, bothDmd,+ lazyApply1Dmd, lazyApply2Dmd, strictApply1Dmd,+ catchArgDmd,+ isTopDmd, isAbsDmd, isSeqDmd,+ peelUseCall, cleanUseDmd_maybe, strictenDmd, bothCleanDmd,+ addCaseBndrDmd,++ DmdType(..), dmdTypeDepth, lubDmdType, bothDmdType,+ nopDmdType, botDmdType, mkDmdType,+ addDemand, removeDmdTyArgs,+ BothDmdArg, mkBothDmdArg, toBothDmdArg,++ DmdEnv, emptyDmdEnv,+ peelFV, findIdDemand,++ DmdResult, CPRResult,+ isBotRes, isTopRes,+ topRes, botRes, exnRes, cprProdRes,+ vanillaCprProdRes, cprSumRes,+ appIsBottom, isBottomingSig, pprIfaceStrictSig,+ trimCPRInfo, returnsCPR_maybe,+ StrictSig(..), mkStrictSig, mkClosedStrictSig,+ nopSig, botSig, exnSig, cprProdSig,+ isTopSig, hasDemandEnvSig,+ splitStrictSig, strictSigDmdEnv,+ increaseStrictSigArity,++ seqDemand, seqDemandList, seqDmdType, seqStrictSig,++ evalDmd, cleanEvalDmd, cleanEvalProdDmd, isStrictDmd,+ splitDmdTy, splitFVs,+ deferAfterIO,+ postProcessUnsat, postProcessDmdType,++ splitProdDmd_maybe, peelCallDmd, mkCallDmd, mkWorkerDemand,+ dmdTransformSig, dmdTransformDataConSig, dmdTransformDictSelSig,+ argOneShots, argsOneShots, saturatedByOneShots,+ trimToType, TypeShape(..),++ useCount, isUsedOnce, reuseEnv,+ killUsageDemand, killUsageSig, zapUsageDemand, zapUsageEnvSig,+ zapUsedOnceDemand, zapUsedOnceSig,+ strictifyDictDmd++ ) where++#include "HsVersions.h"++import DynFlags+import Outputable+import Var ( Var )+import VarEnv+import UniqFM+import Util+import BasicTypes+import Binary+import Maybes ( orElse )++import Type ( Type, isUnliftedType )+import TyCon ( isNewTyCon, isClassTyCon )+import DataCon ( splitDataProductType_maybe )++{-+************************************************************************+* *+ Joint domain for Strictness and Absence+* *+************************************************************************+-}++data JointDmd s u = JD { sd :: s, ud :: u }+ deriving ( Eq, Show )++getStrDmd :: JointDmd s u -> s+getStrDmd = sd++getUseDmd :: JointDmd s u -> u+getUseDmd = ud++-- Pretty-printing+instance (Outputable s, Outputable u) => Outputable (JointDmd s u) where+ ppr (JD {sd = s, ud = u}) = angleBrackets (ppr s <> char ',' <> ppr u)++-- Well-formedness preserving constructors for the joint domain+mkJointDmd :: s -> u -> JointDmd s u+mkJointDmd s u = JD { sd = s, ud = u }++mkJointDmds :: [s] -> [u] -> [JointDmd s u]+mkJointDmds ss as = zipWithEqual "mkJointDmds" mkJointDmd ss as+++{-+************************************************************************+* *+ Strictness domain+* *+************************************************************************++ Lazy+ |+ ExnStr x -+ |+ HeadStr+ / \+ SCall SProd+ \ /+ HyperStr++Note [Exceptions and strictness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Exceptions need rather careful treatment, especially because of 'catch'+('catch#'), 'catchSTM' ('catchSTM#'), and 'orElse' ('catchRetry#').+See Trac #11555, #10712 and #13330, and for some more background, #11222.++There are three main pieces.++* The Termination type includes ThrowsExn, meaning "under the given+ demand this expression either diverges or throws an exception".++ This is relatively uncontroversial. The primops raise# and+ raiseIO# both return ThrowsExn; nothing else does.++* An ArgStr has an ExnStr flag to say how to process the Termination+ result of the argument. If the ExnStr flag is ExnStr, we squash+ ThrowsExn to topRes. (This is done in postProcessDmdResult.)++Here is the key example++ catchRetry# (\s -> retry# s) blah++We analyse the argument (\s -> retry# s) with demand+ Str ExnStr (SCall HeadStr)+i.e. with the ExnStr flag set.+ - First we analyse the argument with the "clean-demand" (SCall+ HeadStr), getting a DmdResult of ThrowsExn from the saturated+ application of retry#.+ - Then we apply the post-processing for the shell, squashing the+ ThrowsExn to topRes.++This also applies uniformly to free variables. Consider++ let r = \st -> retry# st+ in catchRetry# (\s -> ...(r s')..) handler st++If we give the first argument of catch a strict signature, we'll get a demand+'C(S)' for 'r'; that is, 'r' is definitely called with one argument, which+indeed it is. But when we post-process the free-var demands on catchRetry#'s+argument (in postProcessDmdEnv), we'll give 'r' a demand of (Str ExnStr (SCall+HeadStr)); and if we feed that into r's RHS (which would be reasonable) we'll+squash the retry just as if we'd inlined 'r'.++* We don't try to get clever about 'catch#' and 'catchSTM#' at the moment. We+previously (#11222) tried to take advantage of the fact that 'catch#' calls its+first argument eagerly. See especially commit+9915b6564403a6d17651e9969e9ea5d7d7e78e7f. We analyzed that first argument with+a strict demand, and then performed a post-processing step at the end to change+ThrowsExn to TopRes. The trouble, I believe, is that to use this approach+correctly, we'd need somewhat different information about that argument.+Diverges, ThrowsExn (i.e., diverges or throws an exception), and Dunno are the+wrong split here. In order to evaluate part of the argument speculatively,+we'd need to know that it *does not throw an exception*. That is, that it+either diverges or succeeds. But we don't currently have a way to talk about+that. Abstractly and approximately,++catch# m f s = case ORACLE m s of+ DivergesOrSucceeds -> m s+ Fails exc -> f exc s++where the magical ORACLE determines whether or not (m s) throws an exception+when run, and if so which one. If we want, we can safely consider (catch# m f s)+strict in anything that both branches are strict in (by performing demand+analysis for 'catch#' in the same way we do for case). We could also safely+consider it strict in anything demanded by (m s) that is guaranteed not to+throw an exception under that demand, but I don't know if we have the means+to express that.++My mind keeps turning to this model (not as an actual change to the type, but+as a way to think about what's going on in the analysis):++newtype IO a = IO {unIO :: State# s -> (# s, (# SomeException | a #) #)}+instance Monad IO where+ return a = IO $ \s -> (# s, (# | a #) #)+ IO m >>= f = IO $ \s -> case m s of+ (# s', (# e | #) #) -> (# s', e #)+ (# s', (# | a #) #) -> unIO (f a) s+raiseIO# e s = (# s, (# e | #) #)+catch# m f s = case m s of+ (# s', (# e | #) #) -> f e s'+ res -> res++Thinking about it this way seems likely to be productive for analyzing IO+exception behavior, but imprecise exceptions and asynchronous exceptions remain+quite slippery beasts. Can we incorporate them? I think we can. We can imagine+applying 'seq#' to evaluate @m s@, determining whether it throws an imprecise+or asynchronous exception or whether it succeeds or throws an IO exception.+This confines the peculiarities to 'seq#', which is indeed rather essentially+peculiar.+-}++-- Vanilla strictness domain+data StrDmd+ = HyperStr -- Hyper-strict+ -- Bottom of the lattice+ -- Note [HyperStr and Use demands]++ | SCall StrDmd -- Call demand+ -- Used only for values of function type++ | SProd [ArgStr] -- Product+ -- Used only for values of product type+ -- Invariant: not all components are HyperStr (use HyperStr)+ -- not all components are Lazy (use HeadStr)++ | HeadStr -- Head-Strict+ -- A polymorphic demand: used for values of all types,+ -- including a type variable++ deriving ( Eq, Show )++type ArgStr = Str StrDmd++data Str s = Lazy -- Lazy+ -- Top of the lattice+ | Str ExnStr s+ deriving ( Eq, Show )++data ExnStr -- See Note [Exceptions and strictness]+ = VanStr -- "Vanilla" case, ordinary strictness++ | ExnStr -- (Str ExnStr d) means be strict like 'd' but then degrade+ -- the Termination info ThrowsExn to Dunno+ deriving( Eq, Show )++-- Well-formedness preserving constructors for the Strictness domain+strBot, strTop :: ArgStr+strBot = Str VanStr HyperStr+strTop = Lazy++mkSCall :: StrDmd -> StrDmd+mkSCall HyperStr = HyperStr+mkSCall s = SCall s++mkSProd :: [ArgStr] -> StrDmd+mkSProd sx+ | any isHyperStr sx = HyperStr+ | all isLazy sx = HeadStr+ | otherwise = SProd sx++isLazy :: ArgStr -> Bool+isLazy Lazy = True+isLazy (Str {}) = False++isHyperStr :: ArgStr -> Bool+isHyperStr (Str _ HyperStr) = True+isHyperStr _ = False++-- Pretty-printing+instance Outputable StrDmd where+ ppr HyperStr = char 'B'+ ppr (SCall s) = char 'C' <> parens (ppr s)+ ppr HeadStr = char 'S'+ ppr (SProd sx) = char 'S' <> parens (hcat (map ppr sx))++instance Outputable ArgStr where+ ppr (Str x s) = (case x of VanStr -> empty; ExnStr -> char 'x')+ <> ppr s+ ppr Lazy = char 'L'++lubArgStr :: ArgStr -> ArgStr -> ArgStr+lubArgStr Lazy _ = Lazy+lubArgStr _ Lazy = Lazy+lubArgStr (Str x1 s1) (Str x2 s2) = Str (x1 `lubExnStr` x2) (s1 `lubStr` s2)++lubExnStr :: ExnStr -> ExnStr -> ExnStr+lubExnStr VanStr VanStr = VanStr+lubExnStr _ _ = ExnStr -- ExnStr is lazier++lubStr :: StrDmd -> StrDmd -> StrDmd+lubStr HyperStr s = s+lubStr (SCall s1) HyperStr = SCall s1+lubStr (SCall _) HeadStr = HeadStr+lubStr (SCall s1) (SCall s2) = SCall (s1 `lubStr` s2)+lubStr (SCall _) (SProd _) = HeadStr+lubStr (SProd sx) HyperStr = SProd sx+lubStr (SProd _) HeadStr = HeadStr+lubStr (SProd s1) (SProd s2)+ | length s1 == length s2 = mkSProd (zipWith lubArgStr s1 s2)+ | otherwise = HeadStr+lubStr (SProd _) (SCall _) = HeadStr+lubStr HeadStr _ = HeadStr++bothArgStr :: ArgStr -> ArgStr -> ArgStr+bothArgStr Lazy s = s+bothArgStr s Lazy = s+bothArgStr (Str x1 s1) (Str x2 s2) = Str (x1 `bothExnStr` x2) (s1 `bothStr` s2)++bothExnStr :: ExnStr -> ExnStr -> ExnStr+bothExnStr ExnStr ExnStr = ExnStr+bothExnStr _ _ = VanStr++bothStr :: StrDmd -> StrDmd -> StrDmd+bothStr HyperStr _ = HyperStr+bothStr HeadStr s = s+bothStr (SCall _) HyperStr = HyperStr+bothStr (SCall s1) HeadStr = SCall s1+bothStr (SCall s1) (SCall s2) = SCall (s1 `bothStr` s2)+bothStr (SCall _) (SProd _) = HyperStr -- Weird++bothStr (SProd _) HyperStr = HyperStr+bothStr (SProd s1) HeadStr = SProd s1+bothStr (SProd s1) (SProd s2)+ | length s1 == length s2 = mkSProd (zipWith bothArgStr s1 s2)+ | otherwise = HyperStr -- Weird+bothStr (SProd _) (SCall _) = HyperStr++-- utility functions to deal with memory leaks+seqStrDmd :: StrDmd -> ()+seqStrDmd (SProd ds) = seqStrDmdList ds+seqStrDmd (SCall s) = seqStrDmd s+seqStrDmd _ = ()++seqStrDmdList :: [ArgStr] -> ()+seqStrDmdList [] = ()+seqStrDmdList (d:ds) = seqArgStr d `seq` seqStrDmdList ds++seqArgStr :: ArgStr -> ()+seqArgStr Lazy = ()+seqArgStr (Str x s) = x `seq` seqStrDmd s++-- Splitting polymorphic demands+splitArgStrProdDmd :: Int -> ArgStr -> Maybe [ArgStr]+splitArgStrProdDmd n Lazy = Just (replicate n Lazy)+splitArgStrProdDmd n (Str _ s) = splitStrProdDmd n s++splitStrProdDmd :: Int -> StrDmd -> Maybe [ArgStr]+splitStrProdDmd n HyperStr = Just (replicate n strBot)+splitStrProdDmd n HeadStr = Just (replicate n strTop)+splitStrProdDmd n (SProd ds) = WARN( not (ds `lengthIs` n),+ text "splitStrProdDmd" $$ ppr n $$ ppr ds )+ Just ds+splitStrProdDmd _ (SCall {}) = Nothing+ -- This can happen when the programmer uses unsafeCoerce,+ -- and we don't then want to crash the compiler (Trac #9208)++{-+************************************************************************+* *+ Absence domain+* *+************************************************************************++ Used+ / \+ UCall UProd+ \ /+ UHead+ |+ Count x -+ |+ Abs+-}++-- Domain for genuine usage+data UseDmd+ = UCall Count UseDmd -- Call demand for absence+ -- Used only for values of function type++ | UProd [ArgUse] -- Product+ -- Used only for values of product type+ -- See Note [Don't optimise UProd(Used) to Used]+ -- [Invariant] Not all components are Abs+ -- (in that case, use UHead)++ | UHead -- May be used; but its sub-components are+ -- definitely *not* used. Roughly U(AAA)+ -- Eg the usage of x in x `seq` e+ -- A polymorphic demand: used for values of all types,+ -- including a type variable+ -- Since (UCall _ Abs) is ill-typed, UHead doesn't+ -- make sense for lambdas++ | Used -- May be used; and its sub-components may be used+ -- Top of the lattice+ deriving ( Eq, Show )++-- Extended usage demand for absence and counting+type ArgUse = Use UseDmd++data Use u+ = Abs -- Definitely unused+ -- Bottom of the lattice++ | Use Count u -- May be used with some cardinality+ deriving ( Eq, Show )++-- Abstract counting of usages+data Count = One | Many+ deriving ( Eq, Show )++-- Pretty-printing+instance Outputable ArgUse where+ ppr Abs = char 'A'+ ppr (Use Many a) = ppr a+ ppr (Use One a) = char '1' <> char '*' <> ppr a++instance Outputable UseDmd where+ ppr Used = char 'U'+ ppr (UCall c a) = char 'C' <> ppr c <> parens (ppr a)+ ppr UHead = char 'H'+ ppr (UProd as) = char 'U' <> parens (hcat (punctuate (char ',') (map ppr as)))++instance Outputable Count where+ ppr One = char '1'+ ppr Many = text ""++useBot, useTop :: ArgUse+useBot = Abs+useTop = Use Many Used++mkUCall :: Count -> UseDmd -> UseDmd+--mkUCall c Used = Used c+mkUCall c a = UCall c a++mkUProd :: [ArgUse] -> UseDmd+mkUProd ux+ | all (== Abs) ux = UHead+ | otherwise = UProd ux++lubCount :: Count -> Count -> Count+lubCount _ Many = Many+lubCount Many _ = Many+lubCount x _ = x++lubArgUse :: ArgUse -> ArgUse -> ArgUse+lubArgUse Abs x = x+lubArgUse x Abs = x+lubArgUse (Use c1 a1) (Use c2 a2) = Use (lubCount c1 c2) (lubUse a1 a2)++lubUse :: UseDmd -> UseDmd -> UseDmd+lubUse UHead u = u+lubUse (UCall c u) UHead = UCall c u+lubUse (UCall c1 u1) (UCall c2 u2) = UCall (lubCount c1 c2) (lubUse u1 u2)+lubUse (UCall _ _) _ = Used+lubUse (UProd ux) UHead = UProd ux+lubUse (UProd ux1) (UProd ux2)+ | length ux1 == length ux2 = UProd $ zipWith lubArgUse ux1 ux2+ | otherwise = Used+lubUse (UProd {}) (UCall {}) = Used+-- lubUse (UProd {}) Used = Used+lubUse (UProd ux) Used = UProd (map (`lubArgUse` useTop) ux)+lubUse Used (UProd ux) = UProd (map (`lubArgUse` useTop) ux)+lubUse Used _ = Used -- Note [Used should win]++-- `both` is different from `lub` in its treatment of counting; if+-- `both` is computed for two used, the result always has+-- cardinality `Many` (except for the inner demands of UCall demand -- [TODO] explain).+-- Also, x `bothUse` x /= x (for anything but Abs).++bothArgUse :: ArgUse -> ArgUse -> ArgUse+bothArgUse Abs x = x+bothArgUse x Abs = x+bothArgUse (Use _ a1) (Use _ a2) = Use Many (bothUse a1 a2)+++bothUse :: UseDmd -> UseDmd -> UseDmd+bothUse UHead u = u+bothUse (UCall c u) UHead = UCall c u++-- Exciting special treatment of inner demand for call demands:+-- use `lubUse` instead of `bothUse`!+bothUse (UCall _ u1) (UCall _ u2) = UCall Many (u1 `lubUse` u2)++bothUse (UCall {}) _ = Used+bothUse (UProd ux) UHead = UProd ux+bothUse (UProd ux1) (UProd ux2)+ | length ux1 == length ux2 = UProd $ zipWith bothArgUse ux1 ux2+ | otherwise = Used+bothUse (UProd {}) (UCall {}) = Used+-- bothUse (UProd {}) Used = Used -- Note [Used should win]+bothUse Used (UProd ux) = UProd (map (`bothArgUse` useTop) ux)+bothUse (UProd ux) Used = UProd (map (`bothArgUse` useTop) ux)+bothUse Used _ = Used -- Note [Used should win]++peelUseCall :: UseDmd -> Maybe (Count, UseDmd)+peelUseCall (UCall c u) = Just (c,u)+peelUseCall _ = Nothing++addCaseBndrDmd :: Demand -- On the case binder+ -> [Demand] -- On the components of the constructor+ -> [Demand] -- Final demands for the components of the constructor+-- See Note [Demand on case-alternative binders]+addCaseBndrDmd (JD { sd = ms, ud = mu }) alt_dmds+ = case mu of+ Abs -> alt_dmds+ Use _ u -> zipWith bothDmd alt_dmds (mkJointDmds ss us)+ where+ Just ss = splitArgStrProdDmd arity ms -- Guaranteed not to be a call+ Just us = splitUseProdDmd arity u -- Ditto+ where+ arity = length alt_dmds++{- 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 Trac #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:+ f = \ (x_an1 [Dmd=<S(SL),1*U(U,1*U)>] :: (Bool, Bool)) ->+ case x_an1+ of wild_X7 [Dmd=<L,1*U(1*U,1*U)>]+ { (p_an2 [Dmd=<S,1*U>], ds_dnz [Dmd=<L,A>]) ->+ case p_an2 of _ {+ False -> GHC.Types.True;+ True -> foo wild_X7 }++It's true that ds_dnz is *itself* absent, but the use of wild_X7 means+that it is very much alive and demanded. See Trac #10148 for how the+consequences play out.++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 [Don't optimise UProd(Used) to Used]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+These two UseDmds:+ UProd [Used, Used] and Used+are semantically equivalent, but we do not turn the former into+the latter, for a regrettable-subtle reason. Suppose we did.+then+ f (x,y) = (y,x)+would get+ StrDmd = Str = SProd [Lazy, Lazy]+ UseDmd = Used = UProd [Used, Used]+But with the joint demand of <Str, Used> doesn't convey any clue+that there is a product involved, and so the worthSplittingFun+will not fire. (We'd need to use the type as well to make it fire.)+Moreover, consider+ g h p@(_,_) = h p+This too would get <Str, Used>, but this time there really isn't any+point in w/w since the components of the pair are not used at all.++So the solution is: don't aggressively collapse UProd [Used,Used] to+Used; intead leave it as-is. In effect we are using the UseDmd to do a+little bit of boxity analysis. Not very nice.++Note [Used should win]+~~~~~~~~~~~~~~~~~~~~~~+Both in lubUse and bothUse we want (Used `both` UProd us) to be Used.+Why? Because Used carries the implication the whole thing is used,+box and all, so we don't want to w/w it. If we use it both boxed and+unboxed, then we are definitely using the box, and so we are quite+likely to pay a reboxing cost. So we make Used win here.++Example is in the Buffer argument of GHC.IO.Handle.Internals.writeCharBuffer++Baseline: (A) Not making Used win (UProd wins)+Compare with: (B) making Used win for lub and both++ Min -0.3% -5.6% -10.7% -11.0% -33.3%+ Max +0.3% +45.6% +11.5% +11.5% +6.9%+ Geometric Mean -0.0% +0.5% +0.3% +0.2% -0.8%++Baseline: (B) Making Used win for both lub and both+Compare with: (C) making Used win for both, but UProd win for lub++ Min -0.1% -0.3% -7.9% -8.0% -6.5%+ Max +0.1% +1.0% +21.0% +21.0% +0.5%+ Geometric Mean +0.0% +0.0% -0.0% -0.1% -0.1%+-}++-- If a demand is used multiple times (i.e. reused), than any use-once+-- mentioned there, that is not protected by a UCall, can happen many times.+markReusedDmd :: ArgUse -> ArgUse+markReusedDmd Abs = Abs+markReusedDmd (Use _ a) = Use Many (markReused a)++markReused :: UseDmd -> UseDmd+markReused (UCall _ u) = UCall Many u -- No need to recurse here+markReused (UProd ux) = UProd (map markReusedDmd ux)+markReused u = u++isUsedMU :: ArgUse -> Bool+-- True <=> markReusedDmd d = d+isUsedMU Abs = True+isUsedMU (Use One _) = False+isUsedMU (Use Many u) = isUsedU u++isUsedU :: UseDmd -> Bool+-- True <=> markReused d = d+isUsedU Used = True+isUsedU UHead = True+isUsedU (UProd us) = all isUsedMU us+isUsedU (UCall One _) = False+isUsedU (UCall Many _) = True -- No need to recurse++-- Squashing usage demand demands+seqUseDmd :: UseDmd -> ()+seqUseDmd (UProd ds) = seqArgUseList ds+seqUseDmd (UCall c d) = c `seq` seqUseDmd d+seqUseDmd _ = ()++seqArgUseList :: [ArgUse] -> ()+seqArgUseList [] = ()+seqArgUseList (d:ds) = seqArgUse d `seq` seqArgUseList ds++seqArgUse :: ArgUse -> ()+seqArgUse (Use c u) = c `seq` seqUseDmd u+seqArgUse _ = ()++-- Splitting polymorphic Maybe-Used demands+splitUseProdDmd :: Int -> UseDmd -> Maybe [ArgUse]+splitUseProdDmd n Used = Just (replicate n useTop)+splitUseProdDmd n UHead = Just (replicate n Abs)+splitUseProdDmd n (UProd ds) = WARN( not (ds `lengthIs` n),+ text "splitUseProdDmd" $$ ppr n+ $$ ppr ds )+ Just ds+splitUseProdDmd _ (UCall _ _) = Nothing+ -- This can happen when the programmer uses unsafeCoerce,+ -- and we don't then want to crash the compiler (Trac #9208)++useCount :: Use u -> Count+useCount Abs = One+useCount (Use One _) = One+useCount _ = Many+++{-+************************************************************************+* *+ Clean demand for Strictness and Usage+* *+************************************************************************++This domain differst from JointDemand in the sence that pure absence+is taken away, i.e., we deal *only* with non-absent demands.++Note [Strict demands]+~~~~~~~~~~~~~~~~~~~~~+isStrictDmd returns true only of demands that are+ both strict+ and used+In particular, it is False for <HyperStr, Abs>, which can and does+arise in, say (Trac #7319)+ f x = raise# <some exception>+Then 'x' is not used, so f gets strictness <HyperStr,Abs> -> .+Now the w/w generates+ fx = let x <HyperStr,Abs> = absentError "unused"+ in raise <some exception>+At this point we really don't want to convert to+ fx = case absentError "unused" of x -> raise <some exception>+Since the program is going to diverge, this swaps one error for another,+but it's really a bad idea to *ever* evaluate an absent argument.+In Trac #7319 we get+ T7319.exe: Oops! Entered absent arg w_s1Hd{v} [lid] [base:GHC.Base.String{tc 36u}]++Note [Dealing with call demands]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Call demands are constructed and deconstructed coherently for+strictness and absence. For instance, the strictness signature for the+following function++f :: (Int -> (Int, Int)) -> (Int, Bool)+f g = (snd (g 3), True)++should be: <L,C(U(AU))>m+-}++type CleanDemand = JointDmd StrDmd UseDmd+ -- A demand that is at least head-strict++bothCleanDmd :: CleanDemand -> CleanDemand -> CleanDemand+bothCleanDmd (JD { sd = s1, ud = a1}) (JD { sd = s2, ud = a2})+ = JD { sd = s1 `bothStr` s2, ud = a1 `bothUse` a2 }++mkHeadStrict :: CleanDemand -> CleanDemand+mkHeadStrict cd = cd { sd = HeadStr }++mkOnceUsedDmd, mkManyUsedDmd :: CleanDemand -> Demand+mkOnceUsedDmd (JD {sd = s,ud = a}) = JD { sd = Str VanStr s, ud = Use One a }+mkManyUsedDmd (JD {sd = s,ud = a}) = JD { sd = Str VanStr s, ud = Use Many a }++evalDmd :: Demand+-- Evaluated strictly, and used arbitrarily deeply+evalDmd = JD { sd = Str VanStr HeadStr, ud = useTop }++mkProdDmd :: [Demand] -> CleanDemand+mkProdDmd dx+ = JD { sd = mkSProd $ map getStrDmd dx+ , ud = mkUProd $ map getUseDmd dx }++mkCallDmd :: CleanDemand -> CleanDemand+mkCallDmd (JD {sd = d, ud = u})+ = JD { sd = mkSCall d, ud = mkUCall One u }++-- See Note [Demand on the worker] in WorkWrap+mkWorkerDemand :: Int -> Demand+mkWorkerDemand n = JD { sd = Lazy, ud = Use One (go n) }+ where go 0 = Used+ go n = mkUCall One $ go (n-1)++cleanEvalDmd :: CleanDemand+cleanEvalDmd = JD { sd = HeadStr, ud = Used }++cleanEvalProdDmd :: Arity -> CleanDemand+cleanEvalProdDmd n = JD { sd = HeadStr, ud = UProd (replicate n useTop) }+++{-+************************************************************************+* *+ Demand: combining stricness and usage+* *+************************************************************************+-}++type Demand = JointDmd ArgStr ArgUse++lubDmd :: Demand -> Demand -> Demand+lubDmd (JD {sd = s1, ud = a1}) (JD {sd = s2, ud = a2})+ = JD { sd = s1 `lubArgStr` s2+ , ud = a1 `lubArgUse` a2 }++bothDmd :: Demand -> Demand -> Demand+bothDmd (JD {sd = s1, ud = a1}) (JD {sd = s2, ud = a2})+ = JD { sd = s1 `bothArgStr` s2+ , ud = a1 `bothArgUse` a2 }++lazyApply1Dmd, lazyApply2Dmd, strictApply1Dmd, catchArgDmd :: Demand++strictApply1Dmd = JD { sd = Str VanStr (SCall HeadStr)+ , ud = Use Many (UCall One Used) }++-- First argument of catchRetry# and catchSTM#:+-- uses its arg once, applies it once+-- and catches exceptions (the ExnStr) part+catchArgDmd = JD { sd = Str ExnStr (SCall HeadStr)+ , ud = Use One (UCall One Used) }++lazyApply1Dmd = JD { sd = Lazy+ , ud = Use One (UCall One Used) }++-- Second argument of catch#:+-- uses its arg at most once, applies it once+-- but is lazy (might not be called at all)+lazyApply2Dmd = JD { sd = Lazy+ , ud = Use One (UCall One (UCall One Used)) }++absDmd :: Demand+absDmd = JD { sd = Lazy, ud = Abs }++topDmd :: Demand+topDmd = JD { sd = Lazy, ud = useTop }++botDmd :: Demand+botDmd = JD { sd = strBot, ud = useBot }++seqDmd :: Demand+seqDmd = JD { sd = Str VanStr HeadStr, ud = Use One UHead }++oneifyDmd :: Demand -> Demand+oneifyDmd (JD { sd = s, ud = Use _ a }) = JD { sd = s, ud = Use One a }+oneifyDmd jd = jd++isTopDmd :: Demand -> Bool+-- Used to suppress pretty-printing of an uninformative demand+isTopDmd (JD {sd = Lazy, ud = Use Many Used}) = True+isTopDmd _ = False++isAbsDmd :: Demand -> Bool+isAbsDmd (JD {ud = Abs}) = True -- The strictness part can be HyperStr+isAbsDmd _ = False -- for a bottom demand++isSeqDmd :: Demand -> Bool+isSeqDmd (JD {sd = Str VanStr HeadStr, ud = Use _ UHead}) = True+isSeqDmd _ = False++isUsedOnce :: Demand -> Bool+isUsedOnce (JD { ud = a }) = case useCount a of+ One -> True+ Many -> False++-- More utility functions for strictness+seqDemand :: Demand -> ()+seqDemand (JD {sd = s, ud = u}) = seqArgStr s `seq` seqArgUse u++seqDemandList :: [Demand] -> ()+seqDemandList [] = ()+seqDemandList (d:ds) = seqDemand d `seq` seqDemandList ds++isStrictDmd :: Demand -> Bool+-- See Note [Strict demands]+isStrictDmd (JD {ud = Abs}) = False+isStrictDmd (JD {sd = Lazy}) = False+isStrictDmd _ = True++isWeakDmd :: Demand -> Bool+isWeakDmd (JD {sd = s, ud = a}) = isLazy s && isUsedMU a++cleanUseDmd_maybe :: Demand -> Maybe UseDmd+cleanUseDmd_maybe (JD { ud = Use _ u }) = Just u+cleanUseDmd_maybe _ = Nothing++splitFVs :: Bool -- Thunk+ -> DmdEnv -> (DmdEnv, DmdEnv)+splitFVs is_thunk rhs_fvs+ | is_thunk = nonDetFoldUFM_Directly add (emptyVarEnv, emptyVarEnv) rhs_fvs+ -- It's OK to use nonDetFoldUFM_Directly because we+ -- immediately forget the ordering by putting the elements+ -- in the envs again+ | otherwise = partitionVarEnv isWeakDmd rhs_fvs+ where+ add uniq dmd@(JD { sd = s, ud = u }) (lazy_fv, sig_fv)+ | Lazy <- s = (addToUFM_Directly lazy_fv uniq dmd, sig_fv)+ | otherwise = ( addToUFM_Directly lazy_fv uniq (JD { sd = Lazy, ud = u })+ , addToUFM_Directly sig_fv uniq (JD { sd = s, ud = Abs }) )++data TypeShape = TsFun TypeShape+ | TsProd [TypeShape]+ | TsUnk++instance Outputable TypeShape where+ ppr TsUnk = text "TsUnk"+ ppr (TsFun ts) = text "TsFun" <> parens (ppr ts)+ ppr (TsProd tss) = parens (hsep $ punctuate comma $ map ppr tss)++trimToType :: Demand -> TypeShape -> Demand+-- See Note [Trimming a demand to a type]+trimToType (JD { sd = ms, ud = mu }) ts+ = JD (go_ms ms ts) (go_mu mu ts)+ where+ go_ms :: ArgStr -> TypeShape -> ArgStr+ go_ms Lazy _ = Lazy+ go_ms (Str x s) ts = Str x (go_s s ts)++ go_s :: StrDmd -> TypeShape -> StrDmd+ go_s HyperStr _ = HyperStr+ go_s (SCall s) (TsFun ts) = SCall (go_s s ts)+ go_s (SProd mss) (TsProd tss)+ | equalLength mss tss = SProd (zipWith go_ms mss tss)+ go_s _ _ = HeadStr++ go_mu :: ArgUse -> TypeShape -> ArgUse+ go_mu Abs _ = Abs+ go_mu (Use c u) ts = Use c (go_u u ts)++ go_u :: UseDmd -> TypeShape -> UseDmd+ go_u UHead _ = UHead+ go_u (UCall c u) (TsFun ts) = UCall c (go_u u ts)+ go_u (UProd mus) (TsProd tss)+ | equalLength mus tss = UProd (zipWith go_mu mus tss)+ go_u _ _ = Used++{-+Note [Trimming a demand to a type]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:++ f :: a -> Bool+ f x = case ... of+ A g1 -> case (x |> g1) of (p,q) -> ...+ B -> error "urk"++where A,B are the constructors of a GADT. We'll get a U(U,U) demand+on x from the A branch, but that's a stupid demand for x itself, which+has type 'a'. Indeed we get ASSERTs going off (notably in+splitUseProdDmd, Trac #8569).++Bottom line: we really don't want to have a binder whose demand is more+deeply-nested than its type. There are various ways to tackle this.+When processing (x |> g1), we could "trim" the incoming demand U(U,U)+to match x's type. But I'm currently doing so just at the moment when+we pin a demand on a binder, in DmdAnal.findBndrDmd.+++Note [Threshold demands]+~~~~~~~~~~~~~~~~~~~~~~~~+Threshold usage demand is generated to figure out if+cardinality-instrumented demands of a binding's free variables should+be unleashed. See also [Aggregated demand for cardinality].++Note [Replicating polymorphic demands]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Some demands can be considered as polymorphic. Generally, it is+applicable to such beasts as tops, bottoms as well as Head-Used and+Head-stricts demands. For instance,++S ~ S(L, ..., L)++Also, when top or bottom is occurred as a result demand, it in fact+can be expanded to saturate a callee's arity.+-}++splitProdDmd_maybe :: Demand -> Maybe [Demand]+-- Split a product into its components, iff there is any+-- useful information to be extracted thereby+-- The demand is not necessarily strict!+splitProdDmd_maybe (JD { sd = s, ud = u })+ = case (s,u) of+ (Str _ (SProd sx), Use _ u) | Just ux <- splitUseProdDmd (length sx) u+ -> Just (mkJointDmds sx ux)+ (Str _ s, Use _ (UProd ux)) | Just sx <- splitStrProdDmd (length ux) s+ -> Just (mkJointDmds sx ux)+ (Lazy, Use _ (UProd ux)) -> Just (mkJointDmds (replicate (length ux) Lazy) ux)+ _ -> Nothing++{-+************************************************************************+* *+ Demand results+* *+************************************************************************+++DmdResult: Dunno CPRResult+ /+ ThrowsExn+ /+ Diverges+++CPRResult: NoCPR+ / \+ RetProd RetSum ConTag+++Product constructors return (Dunno (RetProd rs))+In a fixpoint iteration, start from Diverges+We have lubs, but not glbs; but that is ok.+-}++------------------------------------------------------------------------+-- Constructed Product Result+------------------------------------------------------------------------++data Termination r+ = Diverges -- Definitely diverges+ | ThrowsExn -- Definitely throws an exception or diverges+ | Dunno r -- Might diverge or converge+ deriving( Eq, Show )++type DmdResult = Termination CPRResult++data CPRResult = NoCPR -- Top of the lattice+ | RetProd -- Returns a constructor from a product type+ | RetSum ConTag -- Returns a constructor from a data type+ deriving( Eq, Show )++lubCPR :: CPRResult -> CPRResult -> CPRResult+lubCPR (RetSum t1) (RetSum t2)+ | t1 == t2 = RetSum t1+lubCPR RetProd RetProd = RetProd+lubCPR _ _ = NoCPR++lubDmdResult :: DmdResult -> DmdResult -> DmdResult+lubDmdResult Diverges r = r+lubDmdResult ThrowsExn Diverges = ThrowsExn+lubDmdResult ThrowsExn r = r+lubDmdResult (Dunno c1) Diverges = Dunno c1+lubDmdResult (Dunno c1) ThrowsExn = Dunno c1+lubDmdResult (Dunno c1) (Dunno c2) = Dunno (c1 `lubCPR` c2)+-- This needs to commute with defaultDmd, i.e.+-- defaultDmd (r1 `lubDmdResult` r2) = defaultDmd r1 `lubDmd` defaultDmd r2+-- (See Note [Default demand on free variables] for why)++bothDmdResult :: DmdResult -> Termination () -> DmdResult+-- See Note [Asymmetry of 'both' for DmdType and DmdResult]+bothDmdResult _ Diverges = Diverges+bothDmdResult r ThrowsExn = case r of { Diverges -> r; _ -> ThrowsExn }+bothDmdResult r (Dunno {}) = r+-- This needs to commute with defaultDmd, i.e.+-- defaultDmd (r1 `bothDmdResult` r2) = defaultDmd r1 `bothDmd` defaultDmd r2+-- (See Note [Default demand on free variables] for why)++instance Outputable r => Outputable (Termination r) where+ ppr Diverges = char 'b'+ ppr ThrowsExn = char 'x'+ ppr (Dunno c) = ppr c++instance Outputable CPRResult where+ ppr NoCPR = empty+ ppr (RetSum n) = char 'm' <> int n+ ppr RetProd = char 'm'++seqDmdResult :: DmdResult -> ()+seqDmdResult Diverges = ()+seqDmdResult ThrowsExn = ()+seqDmdResult (Dunno c) = seqCPRResult c++seqCPRResult :: CPRResult -> ()+seqCPRResult NoCPR = ()+seqCPRResult (RetSum n) = n `seq` ()+seqCPRResult RetProd = ()+++------------------------------------------------------------------------+-- Combined demand result --+------------------------------------------------------------------------++-- [cprRes] lets us switch off CPR analysis+-- by making sure that everything uses TopRes+topRes, exnRes, botRes :: DmdResult+topRes = Dunno NoCPR+exnRes = ThrowsExn+botRes = Diverges++cprSumRes :: ConTag -> DmdResult+cprSumRes tag = Dunno $ RetSum tag++cprProdRes :: [DmdType] -> DmdResult+cprProdRes _arg_tys = Dunno $ RetProd++vanillaCprProdRes :: Arity -> DmdResult+vanillaCprProdRes _arity = Dunno $ RetProd++isTopRes :: DmdResult -> Bool+isTopRes (Dunno NoCPR) = True+isTopRes _ = False++isBotRes :: DmdResult -> Bool+-- True if the result diverges or throws an exception+isBotRes Diverges = True+isBotRes ThrowsExn = True+isBotRes (Dunno {}) = False++trimCPRInfo :: Bool -> Bool -> DmdResult -> DmdResult+trimCPRInfo trim_all trim_sums res+ = trimR res+ where+ trimR (Dunno c) = Dunno (trimC c)+ trimR res = res++ trimC (RetSum n) | trim_all || trim_sums = NoCPR+ | otherwise = RetSum n+ trimC RetProd | trim_all = NoCPR+ | otherwise = RetProd+ trimC NoCPR = NoCPR++returnsCPR_maybe :: DmdResult -> Maybe ConTag+returnsCPR_maybe (Dunno c) = retCPR_maybe c+returnsCPR_maybe _ = Nothing++retCPR_maybe :: CPRResult -> Maybe ConTag+retCPR_maybe (RetSum t) = Just t+retCPR_maybe RetProd = Just fIRST_TAG+retCPR_maybe NoCPR = Nothing++-- See Notes [Default demand on free variables]+-- and [defaultDmd vs. resTypeArgDmd]+defaultDmd :: Termination r -> Demand+defaultDmd (Dunno {}) = absDmd+defaultDmd _ = botDmd -- Diverges or ThrowsExn++resTypeArgDmd :: Termination r -> Demand+-- TopRes and BotRes are polymorphic, so that+-- BotRes === (Bot -> BotRes) === ...+-- TopRes === (Top -> TopRes) === ...+-- This function makes that concrete+-- Also see Note [defaultDmd vs. resTypeArgDmd]+resTypeArgDmd (Dunno _) = topDmd+resTypeArgDmd _ = botDmd -- Diverges or ThrowsExn++{-+Note [defaultDmd and resTypeArgDmd]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++These functions are similar: They express the demand on something not+explicitly mentioned in the environment resp. the argument list. Yet they are+different:+ * Variables not mentioned in the free variables environment are definitely+ unused, so we can use absDmd there.+ * Further arguments *can* be used, of course. Hence topDmd is used.++Note [Worthy functions for Worker-Wrapper split]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For non-bottoming functions a worker-wrapper transformation takes into+account several possibilities to decide if the function is worthy for+splitting:++1. The result is of product type and the function is strict in some+(or even all) of its arguments. The check that the argument is used is+more of sanity nature, since strictness implies usage. Example:++f :: (Int, Int) -> Int+f p = (case p of (a,b) -> a) + 1++should be splitted to++f :: (Int, Int) -> Int+f p = case p of (a,b) -> $wf a++$wf :: Int -> Int+$wf a = a + 1++2. Sometimes it also makes sense to perform a WW split if the+strictness analysis cannot say for sure if the function is strict in+components of its argument. Then we reason according to the inferred+usage information: if the function uses its product argument's+components, the WW split can be beneficial. Example:++g :: Bool -> (Int, Int) -> Int+g c p = case p of (a,b) ->+ if c then a else b++The function g is strict in is argument p and lazy in its+components. However, both components are used in the RHS. The idea is+since some of the components (both in this case) are used in the+right-hand side, the product must presumable be taken apart.++Therefore, the WW transform splits the function g to++g :: Bool -> (Int, Int) -> Int+g c p = case p of (a,b) -> $wg c a b++$wg :: Bool -> Int -> Int -> Int+$wg c a b = if c then a else b++3. If an argument is absent, it would be silly to pass it to a+function, hence the worker with reduced arity is generated.+++Note [Worker-wrapper for bottoming functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We used not to split if the result is bottom.+[Justification: there's no efficiency to be gained.]++But it's sometimes bad not to make a wrapper. Consider+ fw = \x# -> let x = I# x# in case e of+ p1 -> error_fn x+ p2 -> error_fn x+ p3 -> the real stuff+The re-boxing code won't go away unless error_fn gets a wrapper too.+[We don't do reboxing now, but in general it's better to pass an+unboxed thing to f, and have it reboxed in the error cases....]++However we *don't* want to do this when the argument is not actually+taken apart in the function at all. Otherwise we risk decomposing a+massive tuple which is barely used. Example:++ f :: ((Int,Int) -> String) -> (Int,Int) -> a+ f g pr = error (g pr)++ main = print (f fst (1, error "no"))++Here, f does not take 'pr' apart, and it's stupid to do so.+Imagine that it had millions of fields. This actually happened+in GHC itself where the tuple was DynFlags+++************************************************************************+* *+ Demand environments and types+* *+************************************************************************+-}++type DmdEnv = VarEnv Demand -- See Note [Default demand on free variables]++data DmdType = DmdType+ DmdEnv -- Demand on explicitly-mentioned+ -- free variables+ [Demand] -- Demand on arguments+ DmdResult -- See [Nature of result demand]++{-+Note [Nature of result demand]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A DmdResult contains information about termination (currently distinguishing+definite divergence and no information; it is possible to include definite+convergence here), and CPR information about the result.++The semantics of this depends on whether we are looking at a DmdType, i.e. the+demand put on by an expression _under a specific incoming demand_ on its+environment, or at a StrictSig describing a demand transformer.++For a+ * DmdType, the termination information is true given the demand it was+ generated with, while for+ * a StrictSig it holds after applying enough arguments.++The CPR information, though, is valid after the number of arguments mentioned+in the type is given. Therefore, when forgetting the demand on arguments, as in+dmdAnalRhs, this needs to be considere (via removeDmdTyArgs).++Consider+ b2 x y = x `seq` y `seq` error (show x)+this has a strictness signature of+ <S><S>b+meaning that "b2 `seq` ()" and "b2 1 `seq` ()" might well terminate, but+for "b2 1 2 `seq` ()" we get definite divergence.++For comparison,+ b1 x = x `seq` error (show x)+has a strictness signature of+ <S>b+and "b1 1 `seq` ()" is known to terminate.++Now consider a function h with signature "<C(S)>", and the expression+ e1 = h b1+now h puts a demand of <C(S)> onto its argument, and the demand transformer+turns it into+ <S>b+Now the DmdResult "b" does apply to us, even though "b1 `seq` ()" does not+diverge, and we do not anything being passed to b.++Note [Asymmetry of 'both' for DmdType and DmdResult]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+'both' for DmdTypes is *asymmetrical*, because there is only one+result! For example, given (e1 e2), we get a DmdType dt1 for e1, use+its arg demand to analyse e2 giving dt2, and then do (dt1 `bothType` dt2).+Similarly with+ case e of { p -> rhs }+we get dt_scrut from the scrutinee and dt_rhs from the RHS, and then+compute (dt_rhs `bothType` dt_scrut).++We+ 1. combine the information on the free variables,+ 2. take the demand on arguments from the first argument+ 3. combine the termination results, but+ 4. take CPR info from the first argument.++3 and 4 are implementd in bothDmdResult.+-}++-- Equality needed for fixpoints in DmdAnal+instance Eq DmdType where+ (==) (DmdType fv1 ds1 res1)+ (DmdType fv2 ds2 res2) = nonDetUFMToList fv1 == nonDetUFMToList fv2+ -- It's OK to use nonDetUFMToList here because we're testing for+ -- equality and even though the lists will be in some arbitrary+ -- Unique order, it is the same order for both+ && ds1 == ds2 && res1 == res2++lubDmdType :: DmdType -> DmdType -> DmdType+lubDmdType d1 d2+ = DmdType lub_fv lub_ds lub_res+ where+ n = max (dmdTypeDepth d1) (dmdTypeDepth d2)+ (DmdType fv1 ds1 r1) = ensureArgs n d1+ (DmdType fv2 ds2 r2) = ensureArgs n d2++ lub_fv = plusVarEnv_CD lubDmd fv1 (defaultDmd r1) fv2 (defaultDmd r2)+ lub_ds = zipWithEqual "lubDmdType" lubDmd ds1 ds2+ lub_res = lubDmdResult r1 r2++{-+Note [The need for BothDmdArg]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Previously, the right argument to bothDmdType, as well as the return value of+dmdAnalStar via postProcessDmdType, was a DmdType. But bothDmdType only needs+to know about the free variables and termination information, but nothing about+the demand put on arguments, nor cpr information. So we make that explicit by+only passing the relevant information.+-}++type BothDmdArg = (DmdEnv, Termination ())++mkBothDmdArg :: DmdEnv -> BothDmdArg+mkBothDmdArg env = (env, Dunno ())++toBothDmdArg :: DmdType -> BothDmdArg+toBothDmdArg (DmdType fv _ r) = (fv, go r)+ where+ go (Dunno {}) = Dunno ()+ go ThrowsExn = ThrowsExn+ go Diverges = Diverges++bothDmdType :: DmdType -> BothDmdArg -> DmdType+bothDmdType (DmdType fv1 ds1 r1) (fv2, t2)+ -- See Note [Asymmetry of 'both' for DmdType and DmdResult]+ -- 'both' takes the argument/result info from its *first* arg,+ -- using its second arg just for its free-var info.+ = DmdType (plusVarEnv_CD bothDmd fv1 (defaultDmd r1) fv2 (defaultDmd t2))+ ds1+ (r1 `bothDmdResult` t2)++instance Outputable DmdType where+ ppr (DmdType fv ds res)+ = hsep [hcat (map ppr ds) <> ppr res,+ if null fv_elts then empty+ else braces (fsep (map pp_elt fv_elts))]+ where+ pp_elt (uniq, dmd) = ppr uniq <> text "->" <> ppr dmd+ fv_elts = nonDetUFMToList fv+ -- It's OK to use nonDetUFMToList here because we only do it for+ -- pretty printing++emptyDmdEnv :: VarEnv Demand+emptyDmdEnv = emptyVarEnv++-- nopDmdType is the demand of doing nothing+-- (lazy, absent, no CPR information, no termination information).+-- Note that it is ''not'' the top of the lattice (which would be "may use everything"),+-- so it is (no longer) called topDmd+nopDmdType, botDmdType, exnDmdType :: DmdType+nopDmdType = DmdType emptyDmdEnv [] topRes+botDmdType = DmdType emptyDmdEnv [] botRes+exnDmdType = DmdType emptyDmdEnv [] exnRes++cprProdDmdType :: Arity -> DmdType+cprProdDmdType arity+ = DmdType emptyDmdEnv [] (vanillaCprProdRes arity)++isTopDmdType :: DmdType -> Bool+isTopDmdType (DmdType env [] res)+ | isTopRes res && isEmptyVarEnv env = True+isTopDmdType _ = False++mkDmdType :: DmdEnv -> [Demand] -> DmdResult -> DmdType+mkDmdType fv ds res = DmdType fv ds res++dmdTypeDepth :: DmdType -> Arity+dmdTypeDepth (DmdType _ ds _) = length ds++-- Remove any demand on arguments. This is used in dmdAnalRhs on the body+removeDmdTyArgs :: DmdType -> DmdType+removeDmdTyArgs = ensureArgs 0++-- This makes sure we can use the demand type with n arguments,+-- It extends the argument list with the correct resTypeArgDmd+-- It also adjusts the DmdResult: Divergence survives additional arguments,+-- CPR information does not (and definite converge also would not).+ensureArgs :: Arity -> DmdType -> DmdType+ensureArgs n d | n == depth = d+ | otherwise = DmdType fv ds' r'+ where depth = dmdTypeDepth d+ DmdType fv ds r = d++ ds' = take n (ds ++ repeat (resTypeArgDmd r))+ r' = case r of -- See [Nature of result demand]+ Dunno _ -> topRes+ _ -> r+++seqDmdType :: DmdType -> ()+seqDmdType (DmdType env ds res) =+ seqDmdEnv env `seq` seqDemandList ds `seq` seqDmdResult res `seq` ()++seqDmdEnv :: DmdEnv -> ()+seqDmdEnv env = seqEltsUFM seqDemandList env++splitDmdTy :: DmdType -> (Demand, DmdType)+-- Split off one function argument+-- We already have a suitable demand on all+-- free vars, so no need to add more!+splitDmdTy (DmdType fv (dmd:dmds) res_ty) = (dmd, DmdType fv dmds res_ty)+splitDmdTy ty@(DmdType _ [] res_ty) = (resTypeArgDmd res_ty, ty)++-- When e is evaluated after executing an IO action, and d is e's demand, then+-- what of this demand should we consider, given that the IO action can cleanly+-- exit?+-- * We have to kill all strictness demands (i.e. lub with a lazy demand)+-- * We can keep usage information (i.e. lub with an absent demand)+-- * We have to kill definite divergence+-- * We can keep CPR information.+-- See Note [IO hack in the demand analyser] in DmdAnal+deferAfterIO :: DmdType -> DmdType+deferAfterIO d@(DmdType _ _ res) =+ case d `lubDmdType` nopDmdType of+ DmdType fv ds _ -> DmdType fv ds (defer_res res)+ where+ defer_res r@(Dunno {}) = r+ defer_res _ = topRes -- Diverges and ThrowsExn++strictenDmd :: Demand -> CleanDemand+strictenDmd (JD { sd = s, ud = u})+ = JD { sd = poke_s s, ud = poke_u u }+ where+ poke_s Lazy = HeadStr+ poke_s (Str _ s) = s+ poke_u Abs = UHead+ poke_u (Use _ u) = u++-- Deferring and peeling++type DmdShell -- Describes the "outer shell"+ -- of a Demand+ = JointDmd (Str ()) (Use ())++toCleanDmd :: Demand -> Type -> (DmdShell, CleanDemand)+-- Splits a Demand into its "shell" and the inner "clean demand"+toCleanDmd (JD { sd = s, ud = u }) expr_ty+ = (JD { sd = ss, ud = us }, JD { sd = s', ud = u' })+ -- See Note [Analyzing with lazy demand and lambdas]+ where+ (ss, s') = case s of+ Str x s' -> (Str x (), s')+ Lazy | is_unlifted -> (Str VanStr (), HeadStr)+ | otherwise -> (Lazy, HeadStr)++ (us, u') = case u of+ Use c u' -> (Use c (), u')+ Abs | is_unlifted -> (Use One (), Used)+ | otherwise -> (Abs, Used)++ is_unlifted = isUnliftedType expr_ty+ -- See Note [Analysing with absent demand]+++-- This is used in dmdAnalStar when post-processing+-- a function's argument demand. So we only care about what+-- does to free variables, and whether it terminates.+-- see Note [The need for BothDmdArg]+postProcessDmdType :: DmdShell -> DmdType -> BothDmdArg+postProcessDmdType du@(JD { sd = ss }) (DmdType fv _ res_ty)+ = (postProcessDmdEnv du fv, term_info)+ where+ term_info = case postProcessDmdResult ss res_ty of+ Dunno _ -> Dunno ()+ ThrowsExn -> ThrowsExn+ Diverges -> Diverges++postProcessDmdResult :: Str () -> DmdResult -> DmdResult+postProcessDmdResult Lazy _ = topRes+postProcessDmdResult (Str ExnStr _) ThrowsExn = topRes -- Key point!+postProcessDmdResult _ res = res++postProcessDmdEnv :: DmdShell -> DmdEnv -> DmdEnv+postProcessDmdEnv ds@(JD { sd = ss, ud = us }) env+ | Abs <- us = emptyDmdEnv+ -- In this case (postProcessDmd ds) == id; avoid a redundant rebuild+ -- of the environment. Be careful, bad things will happen if this doesn't+ -- match postProcessDmd (see #13977).+ | Str VanStr _ <- ss+ , Use One _ <- us = env+ | otherwise = mapVarEnv (postProcessDmd ds) env+ -- For the Absent case just discard all usage information+ -- We only processed the thing at all to analyse the body+ -- See Note [Always analyse in virgin pass]++reuseEnv :: DmdEnv -> DmdEnv+reuseEnv = mapVarEnv (postProcessDmd+ (JD { sd = Str VanStr (), ud = Use Many () }))++postProcessUnsat :: DmdShell -> DmdType -> DmdType+postProcessUnsat ds@(JD { sd = ss }) (DmdType fv args res_ty)+ = DmdType (postProcessDmdEnv ds fv)+ (map (postProcessDmd ds) args)+ (postProcessDmdResult ss res_ty)++postProcessDmd :: DmdShell -> Demand -> Demand+postProcessDmd (JD { sd = ss, ud = us }) (JD { sd = s, ud = a})+ = JD { sd = s', ud = a' }+ where+ s' = case ss of+ Lazy -> Lazy+ Str ExnStr _ -> markExnStr s+ Str VanStr _ -> s+ a' = case us of+ Abs -> Abs+ Use Many _ -> markReusedDmd a+ Use One _ -> a++markExnStr :: ArgStr -> ArgStr+markExnStr (Str VanStr s) = Str ExnStr s+markExnStr s = s++-- Peels one call level from the demand, and also returns+-- whether it was unsaturated (separately for strictness and usage)+peelCallDmd :: CleanDemand -> (CleanDemand, DmdShell)+-- Exploiting the fact that+-- on the strictness side C(B) = B+-- and on the usage side C(U) = U+peelCallDmd (JD {sd = s, ud = u})+ = (JD { sd = s', ud = u' }, JD { sd = ss, ud = us })+ where+ (s', ss) = case s of+ SCall s' -> (s', Str VanStr ())+ HyperStr -> (HyperStr, Str VanStr ())+ _ -> (HeadStr, Lazy)+ (u', us) = case u of+ UCall c u' -> (u', Use c ())+ _ -> (Used, Use Many ())+ -- The _ cases for usage includes UHead which seems a bit wrong+ -- because the body isn't used at all!+ -- c.f. the Abs case in toCleanDmd++-- Peels that multiple nestings of calls clean demand and also returns+-- whether it was unsaturated (separately for strictness and usage+-- see Note [Demands from unsaturated function calls]+peelManyCalls :: Int -> CleanDemand -> DmdShell+peelManyCalls n (JD { sd = str, ud = abs })+ = JD { sd = go_str n str, ud = go_abs n abs }+ where+ go_str :: Int -> StrDmd -> Str () -- True <=> unsaturated, defer+ go_str 0 _ = Str VanStr ()+ go_str _ HyperStr = Str VanStr () -- == go_str (n-1) HyperStr, as HyperStr = Call(HyperStr)+ go_str n (SCall d') = go_str (n-1) d'+ go_str _ _ = Lazy++ go_abs :: Int -> UseDmd -> Use () -- Many <=> unsaturated, or at least+ go_abs 0 _ = Use One () -- one UCall Many in the demand+ go_abs n (UCall One d') = go_abs (n-1) d'+ go_abs _ _ = Use Many ()++{-+Note [Demands from unsaturated function calls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Consider a demand transformer d1 -> d2 -> r for f.+If a sufficiently detailed demand is fed into this transformer,+e.g <C(C(S)), C1(C1(S))> arising from "f x1 x2" in a strict, use-once context,+then d1 and d2 is precisely the demand unleashed onto x1 and x2 (similar for+the free variable environment) and furthermore the result information r is the+one we want to use.++An anonymous lambda is also an unsaturated function all (needs one argument,+none given), so this applies to that case as well.++But the demand fed into f might be less than <C(C(S)), C1(C1(S))>. There are a few cases:+ * Not enough demand on the strictness side:+ - In that case, we need to zap all strictness in the demand on arguments and+ free variables.+ - Furthermore, we remove CPR information. It could be left, but given the incoming+ demand is not enough to evaluate so far we just do not bother.+ - And finally termination information: If r says that f diverges for sure,+ then this holds when the demand guarantees that two arguments are going to+ be passed. If the demand is lower, we may just as well converge.+ If we were tracking definite convegence, than that would still hold under+ a weaker demand than expected by the demand transformer.+ * Not enough demand from the usage side: The missing usage can be expanded+ using UCall Many, therefore this is subsumed by the third case:+ * At least one of the uses has a cardinality of Many.+ - Even if f puts a One demand on any of its argument or free variables, if+ we call f multiple times, we may evaluate this argument or free variable+ multiple times. So forget about any occurrence of "One" in the demand.++In dmdTransformSig, we call peelManyCalls to find out if we are in any of these+cases, and then call postProcessUnsat to reduce the demand appropriately.++Similarly, dmdTransformDictSelSig and dmdAnal, when analyzing a Lambda, use+peelCallDmd, which peels only one level, but also returns the demand put on the+body of the function.+-}++peelFV :: DmdType -> Var -> (DmdType, Demand)+peelFV (DmdType fv ds res) id = -- pprTrace "rfv" (ppr id <+> ppr dmd $$ ppr fv)+ (DmdType fv' ds res, dmd)+ where+ fv' = fv `delVarEnv` id+ -- See Note [Default demand on free variables]+ dmd = lookupVarEnv fv id `orElse` defaultDmd res++addDemand :: Demand -> DmdType -> DmdType+addDemand dmd (DmdType fv ds res) = DmdType fv (dmd:ds) res++findIdDemand :: DmdType -> Var -> Demand+findIdDemand (DmdType fv _ res) id+ = lookupVarEnv fv id `orElse` defaultDmd res++{-+Note [Default demand on free variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the variable is not mentioned in the environment of a demand type,+its demand is taken to be a result demand of the type.+ For the stricness component,+ if the result demand is a Diverges, then we use HyperStr+ else we use Lazy+ For the usage component, we use Absent.+So we use either absDmd or botDmd.++Also note the equations for lubDmdResult (resp. bothDmdResult) noted there.++Note [Always analyse in virgin pass]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Tricky point: make sure that we analyse in the 'virgin' pass. Consider+ rec { f acc x True = f (...rec { g y = ...g... }...)+ f acc x False = acc }+In the virgin pass for 'f' we'll give 'f' a very strict (bottom) type.+That might mean that we analyse the sub-expression containing the+E = "...rec g..." stuff in a bottom demand. Suppose we *didn't analyse*+E, but just returned botType.++Then in the *next* (non-virgin) iteration for 'f', we might analyse E+in a weaker demand, and that will trigger doing a fixpoint iteration+for g. But *because it's not the virgin pass* we won't start g's+iteration at bottom. Disaster. (This happened in $sfibToList' of+nofib/spectral/fibheaps.)++So in the virgin pass we make sure that we do analyse the expression+at least once, to initialise its signatures.++Note [Analyzing with lazy demand and lambdas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The insight for analyzing lambdas follows from the fact that for+strictness S = C(L). This polymorphic expansion is critical for+cardinality analysis of the following example:++{-# NOINLINE build #-}+build g = (g (:) [], g (:) [])++h c z = build (\x ->+ let z1 = z ++ z+ in if c+ then \y -> x (y ++ z1)+ else \y -> x (z1 ++ y))++One can see that `build` assigns to `g` demand <L,C(C1(U))>.+Therefore, when analyzing the lambda `(\x -> ...)`, we+expect each lambda \y -> ... to be annotated as "one-shot"+one. Therefore (\x -> \y -> x (y ++ z)) should be analyzed with a+demand <C(C(..), C(C1(U))>.++This is achieved by, first, converting the lazy demand L into the+strict S by the second clause of the analysis.++Note [Analysing with absent demand]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we analyse an expression with demand <L,A>. The "A" means+"absent", so this expression will never be needed. What should happen?+There are several wrinkles:++* We *do* want to analyse the expression regardless.+ Reason: Note [Always analyse in virgin pass]++ But we can post-process the results to ignore all the usage+ demands coming back. This is done by postProcessDmdType.++* But in the case of an *unlifted type* we must be extra careful,+ because unlifted values are evaluated even if they are not used.+ Example (see Trac #9254):+ f :: (() -> (# Int#, () #)) -> ()+ -- Strictness signature is+ -- <C(S(LS)), 1*C1(U(A,1*U()))>+ -- I.e. calls k, but discards first component of result+ f k = case k () of (# _, r #) -> r++ g :: Int -> ()+ g y = f (\n -> (# case y of I# y2 -> y2, n #))++ Here f's strictness signature says (correctly) that it calls its+ argument function and ignores the first component of its result.+ This is correct in the sense that it'd be fine to (say) modify the+ function so that always returned 0# in the first component.++ But in function g, we *will* evaluate the 'case y of ...', because+ it has type Int#. So 'y' will be evaluated. So we must record this+ usage of 'y', else 'g' will say 'y' is absent, and will w/w so that+ 'y' is bound to an aBSENT_ERROR thunk.++ An alternative would be to replace the 'case y of ...' with (say) 0#,+ but I have not tried that. It's not a common situation, but it is+ not theoretical: unsafePerformIO's implementation is very very like+ 'f' above.+++************************************************************************+* *+ Demand signatures+* *+************************************************************************++In a let-bound Id we record its strictness info.+In principle, this strictness info is a demand transformer, mapping+a demand on the Id into a DmdType, which gives+ a) the free vars of the Id's value+ b) the Id's arguments+ c) an indication of the result of applying+ the Id to its arguments++However, in fact we store in the Id an extremely emascuated demand+transfomer, namely++ a single DmdType+(Nevertheless we dignify StrictSig as a distinct type.)++This DmdType gives the demands unleashed by the Id when it is applied+to as many arguments as are given in by the arg demands in the DmdType.+Also see Note [Nature of result demand] for the meaning of a DmdResult in a+strictness signature.++If an Id is applied to less arguments than its arity, it means that+the demand on the function at a call site is weaker than the vanilla+call demand, used for signature inference. Therefore we place a top+demand on all arguments. Otherwise, the demand is specified by Id's+signature.++For example, the demand transformer described by the demand signature+ StrictSig (DmdType {x -> <S,1*U>} <L,A><L,U(U,U)>m)+says that when the function is applied to two arguments, it+unleashes demand <S,1*U> on the free var x, <L,A> on the first arg,+and <L,U(U,U)> on the second, then returning a constructor.++If this same function is applied to one arg, all we can say is that it+uses x with <L,U>, and its arg with demand <L,U>.+-}++newtype StrictSig = StrictSig DmdType+ deriving( Eq )++instance Outputable StrictSig where+ ppr (StrictSig ty) = ppr ty++-- Used for printing top-level strictness pragmas in interface files+pprIfaceStrictSig :: StrictSig -> SDoc+pprIfaceStrictSig (StrictSig (DmdType _ dmds res))+ = hcat (map ppr dmds) <> ppr res++mkStrictSig :: DmdType -> StrictSig+mkStrictSig dmd_ty = StrictSig dmd_ty++mkClosedStrictSig :: [Demand] -> DmdResult -> StrictSig+mkClosedStrictSig ds res = mkStrictSig (DmdType emptyDmdEnv ds res)++splitStrictSig :: StrictSig -> ([Demand], DmdResult)+splitStrictSig (StrictSig (DmdType _ dmds res)) = (dmds, res)++increaseStrictSigArity :: Int -> StrictSig -> StrictSig+-- Add extra arguments to a strictness signature+increaseStrictSigArity arity_increase (StrictSig (DmdType env dmds res))+ = StrictSig (DmdType env (replicate arity_increase topDmd ++ dmds) res)++isTopSig :: StrictSig -> Bool+isTopSig (StrictSig ty) = isTopDmdType ty++hasDemandEnvSig :: StrictSig -> Bool+hasDemandEnvSig (StrictSig (DmdType env _ _)) = not (isEmptyVarEnv env)++strictSigDmdEnv :: StrictSig -> DmdEnv+strictSigDmdEnv (StrictSig (DmdType env _ _)) = env++isBottomingSig :: StrictSig -> Bool+-- True if the signature diverges or throws an exception+isBottomingSig (StrictSig (DmdType _ _ res)) = isBotRes res++nopSig, botSig, exnSig :: StrictSig+nopSig = StrictSig nopDmdType+botSig = StrictSig botDmdType+exnSig = StrictSig exnDmdType++cprProdSig :: Arity -> StrictSig+cprProdSig arity = StrictSig (cprProdDmdType arity)++seqStrictSig :: StrictSig -> ()+seqStrictSig (StrictSig ty) = seqDmdType ty++dmdTransformSig :: StrictSig -> CleanDemand -> DmdType+-- (dmdTransformSig fun_sig dmd) considers a call to a function whose+-- signature is fun_sig, with demand dmd. We return the demand+-- that the function places on its context (eg its args)+dmdTransformSig (StrictSig dmd_ty@(DmdType _ arg_ds _)) cd+ = postProcessUnsat (peelManyCalls (length arg_ds) cd) dmd_ty+ -- see Note [Demands from unsaturated function calls]++dmdTransformDataConSig :: Arity -> StrictSig -> CleanDemand -> DmdType+-- Same as dmdTransformSig but for a data constructor (worker),+-- which has a special kind of demand transformer.+-- If the constructor is saturated, we feed the demand on+-- the result into the constructor arguments.+dmdTransformDataConSig arity (StrictSig (DmdType _ _ con_res))+ (JD { sd = str, ud = abs })+ | Just str_dmds <- go_str arity str+ , Just abs_dmds <- go_abs arity abs+ = DmdType emptyDmdEnv (mkJointDmds str_dmds abs_dmds) con_res+ -- Must remember whether it's a product, hence con_res, not TopRes++ | otherwise -- Not saturated+ = nopDmdType+ where+ go_str 0 dmd = splitStrProdDmd arity dmd+ go_str n (SCall s') = go_str (n-1) s'+ go_str n HyperStr = go_str (n-1) HyperStr+ go_str _ _ = Nothing++ go_abs 0 dmd = splitUseProdDmd arity dmd+ go_abs n (UCall One u') = go_abs (n-1) u'+ go_abs _ _ = Nothing++dmdTransformDictSelSig :: StrictSig -> CleanDemand -> DmdType+-- Like dmdTransformDataConSig, we have a special demand transformer+-- for dictionary selectors. If the selector is saturated (ie has one+-- argument: the dictionary), we feed the demand on the result into+-- the indicated dictionary component.+dmdTransformDictSelSig (StrictSig (DmdType _ [dict_dmd] _)) cd+ | (cd',defer_use) <- peelCallDmd cd+ , Just jds <- splitProdDmd_maybe dict_dmd+ = postProcessUnsat defer_use $+ DmdType emptyDmdEnv [mkOnceUsedDmd $ mkProdDmd $ map (enhance cd') jds] topRes+ | otherwise+ = nopDmdType -- See Note [Demand transformer for a dictionary selector]+ where+ enhance cd old | isAbsDmd old = old+ | otherwise = mkOnceUsedDmd cd -- This is the one!++dmdTransformDictSelSig _ _ = panic "dmdTransformDictSelSig: no args"++{-+Note [Demand transformer for a dictionary selector]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we evaluate (op dict-expr) under demand 'd', then we can push the demand 'd'+into the appropriate field of the dictionary. What *is* the appropriate field?+We just look at the strictness signature of the class op, which will be+something like: U(AAASAAAAA). Then replace the 'S' by the demand 'd'.++For single-method classes, which are represented by newtypes the signature+of 'op' won't look like U(...), so the splitProdDmd_maybe will fail.+That's fine: if we are doing strictness analysis we are also doing inlining,+so we'll have inlined 'op' into a cast. So we can bale out in a conservative+way, returning nopDmdType.++It is (just.. Trac #8329) possible to be running strictness analysis *without*+having inlined class ops from single-method classes. Suppose you are using+ghc --make; and the first module has a local -O0 flag. So you may load a class+without interface pragmas, ie (currently) without an unfolding for the class+ops. Now if a subsequent module in the --make sweep has a local -O flag+you might do strictness analysis, but there is no inlining for the class op.+This is weird, so I'm not worried about whether this optimises brilliantly; but+it should not fall over.+-}++argsOneShots :: StrictSig -> Arity -> [[OneShotInfo]]+-- See Note [Computing one-shot info]+argsOneShots (StrictSig (DmdType _ arg_ds _)) n_val_args+ | unsaturated_call = []+ | otherwise = go arg_ds+ where+ unsaturated_call = arg_ds `lengthExceeds` n_val_args++ go [] = []+ go (arg_d : arg_ds) = argOneShots arg_d `cons` go arg_ds++ -- Avoid list tail like [ [], [], [] ]+ cons [] [] = []+ cons a as = a:as++-- saturatedByOneShots n C1(C1(...)) = True,+-- <=>+-- there are at least n nested C1(..) calls+-- See Note [Demand on the worker] in WorkWrap+saturatedByOneShots :: Int -> Demand -> Bool+saturatedByOneShots n (JD { ud = usg })+ = case usg of+ Use _ arg_usg -> go n arg_usg+ _ -> False+ where+ go 0 _ = True+ go n (UCall One u) = go (n-1) u+ go _ _ = False++argOneShots :: Demand -- depending on saturation+ -> [OneShotInfo]+argOneShots (JD { ud = usg })+ = case usg of+ Use _ arg_usg -> go arg_usg+ _ -> []+ where+ go (UCall One u) = OneShotLam : go u+ go (UCall Many u) = NoOneShotInfo : go u+ go _ = []++{- Note [Computing one-shot info]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider a call+ f (\pqr. e1) (\xyz. e2) e3+where f has usage signature+ C1(C(C1(U))) C1(U) U+Then argsOneShots returns a [[OneShotInfo]] of+ [[OneShot,NoOneShotInfo,OneShot], [OneShot]]+The occurrence analyser propagates this one-shot infor to the+binders \pqr and \xyz; see Note [Use one-shot information] in OccurAnal.+-}++-- appIsBottom returns true if an application to n args+-- would diverge or throw an exception+-- See Note [Unsaturated applications]+appIsBottom :: StrictSig -> Int -> Bool+appIsBottom (StrictSig (DmdType _ ds res)) n+ | isBotRes res = not $ lengthExceeds ds n+appIsBottom _ _ = False++{-+Note [Unsaturated applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If a function having bottom as its demand result is applied to a less+number of arguments than its syntactic arity, we cannot say for sure+that it is going to diverge. This is the reason why we use the+function appIsBottom, which, given a strictness signature and a number+of arguments, says conservatively if the function is going to diverge+or not.++Zap absence or one-shot information, under control of flags++Note [Killing usage information]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The flags -fkill-one-shot and -fkill-absence let you switch off the generation+of absence or one-shot information altogether. This is only used for performance+tests, to see how important they are.+-}++zapUsageEnvSig :: StrictSig -> StrictSig+-- Remove the usage environment from the demand+zapUsageEnvSig (StrictSig (DmdType _ ds r)) = mkClosedStrictSig ds r++zapUsageDemand :: Demand -> Demand+-- Remove the usage info, but not the strictness info, from the demand+zapUsageDemand = kill_usage $ KillFlags+ { kf_abs = True+ , kf_used_once = True+ , kf_called_once = True+ }++-- | Remove all 1* information (but not C1 information) from the demand+zapUsedOnceDemand :: Demand -> Demand+zapUsedOnceDemand = kill_usage $ KillFlags+ { kf_abs = False+ , kf_used_once = True+ , kf_called_once = False+ }++-- | Remove all 1* information (but not C1 information) from the strictness+-- signature+zapUsedOnceSig :: StrictSig -> StrictSig+zapUsedOnceSig (StrictSig (DmdType env ds r))+ = StrictSig (DmdType env (map zapUsedOnceDemand ds) r)++killUsageDemand :: DynFlags -> Demand -> Demand+-- See Note [Killing usage information]+killUsageDemand dflags dmd+ | Just kfs <- killFlags dflags = kill_usage kfs dmd+ | otherwise = dmd++killUsageSig :: DynFlags -> StrictSig -> StrictSig+-- See Note [Killing usage information]+killUsageSig dflags sig@(StrictSig (DmdType env ds r))+ | Just kfs <- killFlags dflags = StrictSig (DmdType env (map (kill_usage kfs) ds) r)+ | otherwise = sig++data KillFlags = KillFlags+ { kf_abs :: Bool+ , kf_used_once :: Bool+ , kf_called_once :: Bool+ }++killFlags :: DynFlags -> Maybe KillFlags+-- See Note [Killing usage information]+killFlags dflags+ | not kf_abs && not kf_used_once = Nothing+ | otherwise = Just (KillFlags {..})+ where+ kf_abs = gopt Opt_KillAbsence dflags+ kf_used_once = gopt Opt_KillOneShot dflags+ kf_called_once = kf_used_once++kill_usage :: KillFlags -> Demand -> Demand+kill_usage kfs (JD {sd = s, ud = u}) = JD {sd = s, ud = zap_musg kfs u}++zap_musg :: KillFlags -> ArgUse -> ArgUse+zap_musg kfs Abs+ | kf_abs kfs = useTop+ | otherwise = Abs+zap_musg kfs (Use c u)+ | kf_used_once kfs = Use Many (zap_usg kfs u)+ | otherwise = Use c (zap_usg kfs u)++zap_usg :: KillFlags -> UseDmd -> UseDmd+zap_usg kfs (UCall c u)+ | kf_called_once kfs = UCall Many (zap_usg kfs u)+ | otherwise = UCall c (zap_usg kfs u)+zap_usg kfs (UProd us) = UProd (map (zap_musg kfs) us)+zap_usg _ u = u++-- If the argument is a used non-newtype dictionary, give it strict+-- demand. Also split the product type & demand and recur in order to+-- similarly strictify the argument's contained used non-newtype+-- superclass dictionaries. We use the demand as our recursive measure+-- to guarantee termination.+strictifyDictDmd :: Type -> Demand -> Demand+strictifyDictDmd ty dmd = case getUseDmd dmd of+ Use n _ |+ Just (tycon, _arg_tys, _data_con, inst_con_arg_tys)+ <- splitDataProductType_maybe ty,+ not (isNewTyCon tycon), isClassTyCon tycon -- is a non-newtype dictionary+ -> seqDmd `bothDmd` -- main idea: ensure it's strict+ case splitProdDmd_maybe dmd of+ -- superclass cycles should not be a problem, since the demand we are+ -- consuming would also have to be infinite in order for us to diverge+ Nothing -> dmd -- no components have interesting demand, so stop+ -- looking for superclass dicts+ Just dmds+ | all (not . isAbsDmd) dmds -> evalDmd+ -- abstract to strict w/ arbitrary component use, since this+ -- smells like reboxing; results in CBV boxed+ --+ -- TODO revisit this if we ever do boxity analysis+ | otherwise -> case mkProdDmd $ zipWith strictifyDictDmd inst_con_arg_tys dmds of+ JD {sd = s,ud = a} -> JD (Str VanStr s) (Use n a)+ -- TODO could optimize with an aborting variant of zipWith since+ -- the superclass dicts are always a prefix+ _ -> dmd -- unused or not a dictionary++{-+Note [HyperStr and Use demands]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The information "HyperStr" needs to be in the strictness signature, and not in+the demand signature, because we still want to know about the demand on things. Consider++ f (x,y) True = error (show x)+ f (x,y) False = x+1++The signature of f should be <S(SL),1*U(1*U(U),A)><S,1*U>m. If we were not+distinguishing the uses on x and y in the True case, we could either not figure+out how deeply we can unpack x, or that we do not have to pass y.+++************************************************************************+* *+ Serialisation+* *+************************************************************************+-}++instance Binary StrDmd where+ put_ bh HyperStr = do putByte bh 0+ put_ bh HeadStr = do putByte bh 1+ put_ bh (SCall s) = do putByte bh 2+ put_ bh s+ put_ bh (SProd sx) = do putByte bh 3+ put_ bh sx+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return HyperStr+ 1 -> do return HeadStr+ 2 -> do s <- get bh+ return (SCall s)+ _ -> do sx <- get bh+ return (SProd sx)++instance Binary ExnStr where+ put_ bh VanStr = putByte bh 0+ put_ bh ExnStr = putByte bh 1++ get bh = do h <- getByte bh+ return (case h of+ 0 -> VanStr+ _ -> ExnStr)++instance Binary ArgStr where+ put_ bh Lazy = do+ putByte bh 0+ put_ bh (Str x s) = do+ putByte bh 1+ put_ bh x+ put_ bh s++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return Lazy+ _ -> do x <- get bh+ s <- get bh+ return $ Str x s++instance Binary Count where+ put_ bh One = do putByte bh 0+ put_ bh Many = do putByte bh 1++ get bh = do h <- getByte bh+ case h of+ 0 -> return One+ _ -> return Many++instance Binary ArgUse where+ put_ bh Abs = do+ putByte bh 0+ put_ bh (Use c u) = do+ putByte bh 1+ put_ bh c+ put_ bh u++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return Abs+ _ -> do c <- get bh+ u <- get bh+ return $ Use c u++instance Binary UseDmd where+ put_ bh Used = do+ putByte bh 0+ put_ bh UHead = do+ putByte bh 1+ put_ bh (UCall c u) = do+ putByte bh 2+ put_ bh c+ put_ bh u+ put_ bh (UProd ux) = do+ putByte bh 3+ put_ bh ux++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return $ Used+ 1 -> return $ UHead+ 2 -> do c <- get bh+ u <- get bh+ return (UCall c u)+ _ -> do ux <- get bh+ return (UProd ux)++instance (Binary s, Binary u) => Binary (JointDmd s u) where+ put_ bh (JD { sd = x, ud = y }) = do put_ bh x; put_ bh y+ get bh = do+ x <- get bh+ y <- get bh+ return $ JD { sd = x, ud = y }++instance Binary StrictSig where+ put_ bh (StrictSig aa) = do+ put_ bh aa+ get bh = do+ aa <- get bh+ return (StrictSig aa)++instance Binary DmdType where+ -- Ignore DmdEnv when spitting out the DmdType+ put_ bh (DmdType _ ds dr)+ = do put_ bh ds+ put_ bh dr+ get bh+ = do ds <- get bh+ dr <- get bh+ return (DmdType emptyDmdEnv ds dr)++instance Binary DmdResult where+ put_ bh (Dunno c) = do { putByte bh 0; put_ bh c }+ put_ bh ThrowsExn = putByte bh 1+ put_ bh Diverges = putByte bh 2++ get bh = do { h <- getByte bh+ ; case h of+ 0 -> do { c <- get bh; return (Dunno c) }+ 1 -> return ThrowsExn+ _ -> return Diverges }++instance Binary CPRResult where+ put_ bh (RetSum n) = do { putByte bh 0; put_ bh n }+ put_ bh RetProd = putByte bh 1+ put_ bh NoCPR = putByte bh 2++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do { n <- get bh; return (RetSum n) }+ 1 -> return RetProd+ _ -> return NoCPR
+ basicTypes/FieldLabel.hs view
@@ -0,0 +1,128 @@+{-+%+% (c) Adam Gundry 2013-2015+%++This module defines the representation of FieldLabels as stored in+TyCons. As well as a selector name, these have some extra structure+to support the DuplicateRecordFields extension.++In the normal case (with NoDuplicateRecordFields), a datatype like++ data T = MkT { foo :: Int }++has++ FieldLabel { flLabel = "foo"+ , flIsOverloaded = False+ , flSelector = foo }.++In particular, the Name of the selector has the same string+representation as the label. If DuplicateRecordFields+is enabled, however, the same declaration instead gives++ FieldLabel { flLabel = "foo"+ , flIsOverloaded = True+ , flSelector = $sel:foo:MkT }.++Now the name of the selector ($sel:foo:MkT) does not match the label of+the field (foo). We must be careful not to show the selector name to+the user! The point of mangling the selector name is to allow a+module to define the same field label in different datatypes:++ data T = MkT { foo :: Int }+ data U = MkU { foo :: Bool }++Now there will be two FieldLabel values for 'foo', one in T and one in+U. They share the same label (FieldLabelString), but the selector+functions differ.++See also Note [Representing fields in AvailInfo] in Avail.++Note [Why selector names include data constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++As explained above, a selector name includes the name of the first+data constructor in the type, so that the same label can appear+multiple times in the same module. (This is irrespective of whether+the first constructor has that field, for simplicity.)++We use a data constructor name, rather than the type constructor name,+because data family instances do not have a representation type+constructor name generated until relatively late in the typechecking+process.++Of course, datatypes with no constructors cannot have any fields.++-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE StandaloneDeriving #-}++module FieldLabel ( FieldLabelString+ , FieldLabelEnv+ , FieldLbl(..)+ , FieldLabel+ , mkFieldLabelOccs+ ) where++import OccName+import Name++import FastString+import FastStringEnv+import Outputable+import Binary++import Data.Data++-- | Field labels are just represented as strings;+-- they are not necessarily unique (even within a module)+type FieldLabelString = FastString++-- | A map from labels to all the auxiliary information+type FieldLabelEnv = DFastStringEnv FieldLabel+++type FieldLabel = FieldLbl Name++-- | Fields in an algebraic record type+data FieldLbl a = FieldLabel {+ flLabel :: FieldLabelString, -- ^ User-visible label of the field+ flIsOverloaded :: Bool, -- ^ Was DuplicateRecordFields on+ -- in the defining module for this datatype?+ flSelector :: a -- ^ Record selector function+ }+ deriving (Eq, Functor, Foldable, Traversable)+deriving instance Data a => Data (FieldLbl a)++instance Outputable a => Outputable (FieldLbl a) where+ ppr fl = ppr (flLabel fl) <> braces (ppr (flSelector fl))++instance Binary a => Binary (FieldLbl a) where+ put_ bh (FieldLabel aa ab ac) = do+ put_ bh aa+ put_ bh ab+ put_ bh ac+ get bh = do+ ab <- get bh+ ac <- get bh+ ad <- get bh+ return (FieldLabel ab ac ad)+++-- | Record selector OccNames are built from the underlying field name+-- and the name of the first data constructor of the type, to support+-- duplicate record field names.+-- See Note [Why selector names include data constructors].+mkFieldLabelOccs :: FieldLabelString -> OccName -> Bool -> FieldLbl OccName+mkFieldLabelOccs lbl dc is_overloaded+ = FieldLabel { flLabel = lbl, flIsOverloaded = is_overloaded+ , flSelector = sel_occ }+ where+ str = ":" ++ unpackFS lbl ++ ":" ++ occNameString dc+ sel_occ | is_overloaded = mkRecFldSelOcc str+ | otherwise = mkVarOccFS lbl
+ basicTypes/Id.hs view
@@ -0,0 +1,946 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[Id]{@Ids@: Value and constructor identifiers}+-}++{-# LANGUAGE ImplicitParams, CPP #-}++-- |+-- #name_types#+-- GHC uses several kinds of name internally:+--+-- * 'OccName.OccName': see "OccName#name_types"+--+-- * 'RdrName.RdrName': see "RdrName#name_types"+--+-- * 'Name.Name': see "Name#name_types"+--+-- * 'Id.Id' represents names that not only have a 'Name.Name' but also a 'TyCoRep.Type' and some additional+-- details (a 'IdInfo.IdInfo' and one of 'Var.LocalIdDetails' or 'IdInfo.GlobalIdDetails') that+-- are added, modified and inspected by various compiler passes. These 'Var.Var' names may either+-- be global or local, see "Var#globalvslocal"+--+-- * 'Var.Var': see "Var#name_types"++module Id (+ -- * The main types+ Var, Id, isId,++ -- * In and Out variants+ InVar, InId,+ OutVar, OutId,++ -- ** Simple construction+ mkGlobalId, mkVanillaGlobal, mkVanillaGlobalWithInfo,+ mkLocalId, mkLocalCoVar, mkLocalIdOrCoVar,+ mkLocalIdOrCoVarWithInfo,+ mkLocalIdWithInfo, mkExportedLocalId, mkExportedVanillaId,+ mkSysLocal, mkSysLocalM, mkSysLocalOrCoVar, mkSysLocalOrCoVarM,+ mkUserLocal, mkUserLocalOrCoVar,+ mkTemplateLocals, mkTemplateLocalsNum, mkTemplateLocal,+ mkWorkerId,++ -- ** Taking an Id apart+ idName, idType, idUnique, idInfo, idDetails,+ recordSelectorTyCon,++ -- ** Modifying an Id+ setIdName, setIdUnique, Id.setIdType,+ setIdExported, setIdNotExported,+ globaliseId, localiseId,+ setIdInfo, lazySetIdInfo, modifyIdInfo, maybeModifyIdInfo,+ zapLamIdInfo, zapIdDemandInfo, zapIdUsageInfo, zapIdUsageEnvInfo,+ zapIdUsedOnceInfo, zapIdTailCallInfo,+ zapFragileIdInfo, zapIdStrictness,+ transferPolyIdInfo,++ -- ** Predicates on Ids+ isImplicitId, isDeadBinder,+ isStrictId,+ isExportedId, isLocalId, isGlobalId,+ isRecordSelector, isNaughtyRecordSelector,+ isPatSynRecordSelector,+ isDataConRecordSelector,+ isClassOpId_maybe, isDFunId,+ isPrimOpId, isPrimOpId_maybe,+ isFCallId, isFCallId_maybe,+ isDataConWorkId, isDataConWorkId_maybe, isDataConId_maybe, idDataCon,+ isConLikeId, isBottomingId, idIsFrom,+ hasNoBinding,++ -- ** Evidence variables+ DictId, isDictId, isEvVar,++ -- ** Join variables+ JoinId, isJoinId, isJoinId_maybe, idJoinArity,+ asJoinId, asJoinId_maybe, zapJoinId,++ -- ** Inline pragma stuff+ idInlinePragma, setInlinePragma, modifyInlinePragma,+ idInlineActivation, setInlineActivation, idRuleMatchInfo,++ -- ** One-shot lambdas+ isOneShotBndr, isProbablyOneShotLambda,+ setOneShotLambda, clearOneShotLambda,+ updOneShotInfo, setIdOneShotInfo,+ isStateHackType, stateHackOneShot, typeOneShot,++ -- ** Reading 'IdInfo' fields+ idArity,+ idCallArity, idFunRepArity,+ idUnfolding, realIdUnfolding,+ idSpecialisation, idCoreRules, idHasRules,+ idCafInfo,+ idOneShotInfo, idStateHackOneShotInfo,+ idOccInfo,+ isNeverLevPolyId,++ -- ** Writing 'IdInfo' fields+ setIdUnfolding, setCaseBndrEvald,+ setIdArity,+ setIdCallArity,++ setIdSpecialisation,+ setIdCafInfo,+ setIdOccInfo, zapIdOccInfo,++ setIdDemandInfo,+ setIdStrictness,++ idDemandInfo,+ idStrictness,++ ) where++#include "HsVersions.h"++import DynFlags+import CoreSyn ( CoreRule, evaldUnfolding, Unfolding( NoUnfolding ) )++import IdInfo+import BasicTypes++-- Imported and re-exported+import Var( Id, CoVar, DictId, JoinId,+ InId, InVar,+ OutId, OutVar,+ idInfo, idDetails, setIdDetails, globaliseId, varType,+ isId, isLocalId, isGlobalId, isExportedId )+import qualified Var++import Type+import RepType+import TysPrim+import DataCon+import Demand+import Name+import Module+import Class+import {-# SOURCE #-} PrimOp (PrimOp)+import ForeignCall+import Maybes+import SrcLoc+import Outputable+import Unique+import UniqSupply+import FastString+import Util++-- infixl so you can say (id `set` a `set` b)+infixl 1 `setIdUnfolding`,+ `setIdArity`,+ `setIdCallArity`,+ `setIdOccInfo`,+ `setIdOneShotInfo`,++ `setIdSpecialisation`,+ `setInlinePragma`,+ `setInlineActivation`,+ `idCafInfo`,++ `setIdDemandInfo`,+ `setIdStrictness`,++ `asJoinId`,+ `asJoinId_maybe`++{-+************************************************************************+* *+\subsection{Basic Id manipulation}+* *+************************************************************************+-}++idName :: Id -> Name+idName = Var.varName++idUnique :: Id -> Unique+idUnique = Var.varUnique++idType :: Id -> Kind+idType = Var.varType++setIdName :: Id -> Name -> Id+setIdName = Var.setVarName++setIdUnique :: Id -> Unique -> Id+setIdUnique = Var.setVarUnique++-- | Not only does this set the 'Id' 'Type', it also evaluates the type to try and+-- reduce space usage+setIdType :: Id -> Type -> Id+setIdType id ty = seqType ty `seq` Var.setVarType id ty++setIdExported :: Id -> Id+setIdExported = Var.setIdExported++setIdNotExported :: Id -> Id+setIdNotExported = Var.setIdNotExported++localiseId :: Id -> Id+-- Make an with the same unique and type as the+-- incoming Id, but with an *Internal* Name and *LocalId* flavour+localiseId id+ | ASSERT( isId id ) isLocalId id && isInternalName name+ = id+ | otherwise+ = Var.mkLocalVar (idDetails id) (localiseName name) (idType id) (idInfo id)+ where+ name = idName id++lazySetIdInfo :: Id -> IdInfo -> Id+lazySetIdInfo = Var.lazySetIdInfo++setIdInfo :: Id -> IdInfo -> Id+setIdInfo id info = info `seq` (lazySetIdInfo id info)+ -- Try to avoid spack leaks by seq'ing++modifyIdInfo :: (IdInfo -> IdInfo) -> Id -> Id+modifyIdInfo fn id = setIdInfo id (fn (idInfo id))++-- maybeModifyIdInfo tries to avoid unnecessary thrashing+maybeModifyIdInfo :: Maybe IdInfo -> Id -> Id+maybeModifyIdInfo (Just new_info) id = lazySetIdInfo id new_info+maybeModifyIdInfo Nothing id = id++{-+************************************************************************+* *+\subsection{Simple Id construction}+* *+************************************************************************++Absolutely all Ids are made by mkId. It is just like Var.mkId,+but in addition it pins free-tyvar-info onto the Id's type,+where it can easily be found.++Note [Free type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~+At one time we cached the free type variables of the type of an Id+at the root of the type in a TyNote. The idea was to avoid repeating+the free-type-variable calculation. But it turned out to slow down+the compiler overall. I don't quite know why; perhaps finding free+type variables of an Id isn't all that common whereas applying a+substitution (which changes the free type variables) is more common.+Anyway, we removed it in March 2008.+-}++-- | For an explanation of global vs. local 'Id's, see "Var#globalvslocal"+mkGlobalId :: IdDetails -> Name -> Type -> IdInfo -> Id+mkGlobalId = Var.mkGlobalVar++-- | Make a global 'Id' without any extra information at all+mkVanillaGlobal :: Name -> Type -> Id+mkVanillaGlobal name ty = mkVanillaGlobalWithInfo name ty vanillaIdInfo++-- | Make a global 'Id' with no global information but some generic 'IdInfo'+mkVanillaGlobalWithInfo :: Name -> Type -> IdInfo -> Id+mkVanillaGlobalWithInfo = mkGlobalId VanillaId+++-- | For an explanation of global vs. local 'Id's, see "Var#globalvslocal"+mkLocalId :: Name -> Type -> Id+mkLocalId name ty = mkLocalIdWithInfo name ty vanillaIdInfo+ -- It's tempting to ASSERT( not (isCoercionType ty) ), but don't. Sometimes,+ -- the type is a panic. (Search invented_id)++-- | Make a local CoVar+mkLocalCoVar :: Name -> Type -> CoVar+mkLocalCoVar name ty+ = ASSERT( isCoercionType ty )+ Var.mkLocalVar CoVarId name ty vanillaIdInfo++-- | Like 'mkLocalId', but checks the type to see if it should make a covar+mkLocalIdOrCoVar :: Name -> Type -> Id+mkLocalIdOrCoVar name ty+ | isCoercionType ty = mkLocalCoVar name ty+ | otherwise = mkLocalId name ty++-- | Make a local id, with the IdDetails set to CoVarId if the type indicates+-- so.+mkLocalIdOrCoVarWithInfo :: Name -> Type -> IdInfo -> Id+mkLocalIdOrCoVarWithInfo name ty info+ = Var.mkLocalVar details name ty info+ where+ details | isCoercionType ty = CoVarId+ | otherwise = VanillaId++ -- proper ids only; no covars!+mkLocalIdWithInfo :: Name -> Type -> IdInfo -> Id+mkLocalIdWithInfo name ty info = Var.mkLocalVar VanillaId name ty info+ -- Note [Free type variables]++-- | Create a local 'Id' that is marked as exported.+-- This prevents things attached to it from being removed as dead code.+-- See Note [Exported LocalIds]+mkExportedLocalId :: IdDetails -> Name -> Type -> Id+mkExportedLocalId details name ty = Var.mkExportedLocalVar details name ty vanillaIdInfo+ -- Note [Free type variables]++mkExportedVanillaId :: Name -> Type -> Id+mkExportedVanillaId name ty = Var.mkExportedLocalVar VanillaId name ty vanillaIdInfo+ -- Note [Free type variables]+++-- | Create a system local 'Id'. These are local 'Id's (see "Var#globalvslocal")+-- that are created by the compiler out of thin air+mkSysLocal :: FastString -> Unique -> Type -> Id+mkSysLocal fs uniq ty = ASSERT( not (isCoercionType ty) )+ mkLocalId (mkSystemVarName uniq fs) ty++-- | Like 'mkSysLocal', but checks to see if we have a covar type+mkSysLocalOrCoVar :: FastString -> Unique -> Type -> Id+mkSysLocalOrCoVar fs uniq ty+ = mkLocalIdOrCoVar (mkSystemVarName uniq fs) ty++mkSysLocalM :: MonadUnique m => FastString -> Type -> m Id+mkSysLocalM fs ty = getUniqueM >>= (\uniq -> return (mkSysLocal fs uniq ty))++mkSysLocalOrCoVarM :: MonadUnique m => FastString -> Type -> m Id+mkSysLocalOrCoVarM fs ty+ = getUniqueM >>= (\uniq -> return (mkSysLocalOrCoVar fs uniq ty))++-- | Create a user local 'Id'. These are local 'Id's (see "Var#globalvslocal") with a name and location that the user might recognize+mkUserLocal :: OccName -> Unique -> Type -> SrcSpan -> Id+mkUserLocal occ uniq ty loc = ASSERT( not (isCoercionType ty) )+ mkLocalId (mkInternalName uniq occ loc) ty++-- | Like 'mkUserLocal', but checks if we have a coercion type+mkUserLocalOrCoVar :: OccName -> Unique -> Type -> SrcSpan -> Id+mkUserLocalOrCoVar occ uniq ty loc+ = mkLocalIdOrCoVar (mkInternalName uniq occ loc) ty++{-+Make some local @Ids@ for a template @CoreExpr@. These have bogus+@Uniques@, but that's OK because the templates are supposed to be+instantiated before use.+-}++-- | Workers get local names. "CoreTidy" will externalise these if necessary+mkWorkerId :: Unique -> Id -> Type -> Id+mkWorkerId uniq unwrkr ty+ = mkLocalIdOrCoVar (mkDerivedInternalName mkWorkerOcc uniq (getName unwrkr)) ty++-- | Create a /template local/: a family of system local 'Id's in bijection with @Int@s, typically used in unfoldings+mkTemplateLocal :: Int -> Type -> Id+mkTemplateLocal i ty = mkSysLocalOrCoVar (fsLit "v") (mkBuiltinUnique i) ty++-- | Create a template local for a series of types+mkTemplateLocals :: [Type] -> [Id]+mkTemplateLocals = mkTemplateLocalsNum 1++-- | Create a template local for a series of type, but start from a specified template local+mkTemplateLocalsNum :: Int -> [Type] -> [Id]+mkTemplateLocalsNum n tys = zipWith mkTemplateLocal [n..] tys++{- Note [Exported LocalIds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We use mkExportedLocalId for things like+ - Dictionary functions (DFunId)+ - Wrapper and matcher Ids for pattern synonyms+ - Default methods for classes+ - Pattern-synonym matcher and builder Ids+ - etc++They marked as "exported" in the sense that they should be kept alive+even if apparently unused in other bindings, and not dropped as dead+code by the occurrence analyser. (But "exported" here does not mean+"brought into lexical scope by an import declaration". Indeed these+things are always internal Ids that the user never sees.)++It's very important that they are *LocalIds*, not GlobalIds, for lots+of reasons:++ * We want to treat them as free variables for the purpose of+ dependency analysis (e.g. CoreFVs.exprFreeVars).++ * Look them up in the current substitution when we come across+ occurrences of them (in Subst.lookupIdSubst). Lacking this we+ can get an out-of-date unfolding, which can in turn make the+ simplifier go into an infinite loop (Trac #9857)++ * Ensure that for dfuns that the specialiser does not float dict uses+ above their defns, which would prevent good simplifications happening.++ * The strictness analyser treats a occurrence of a GlobalId as+ imported and assumes it contains strictness in its IdInfo, which+ isn't true if the thing is bound in the same module as the+ occurrence.++In CoreTidy we must make all these LocalIds into GlobalIds, so that in+importing modules (in --make mode) we treat them as properly global.+That is what is happening in, say tidy_insts in TidyPgm.++************************************************************************+* *+\subsection{Special Ids}+* *+************************************************************************+-}++-- | If the 'Id' is that for a record selector, extract the 'sel_tycon'. Panic otherwise.+recordSelectorTyCon :: Id -> RecSelParent+recordSelectorTyCon id+ = case Var.idDetails id of+ RecSelId { sel_tycon = parent } -> parent+ _ -> panic "recordSelectorTyCon"+++isRecordSelector :: Id -> Bool+isNaughtyRecordSelector :: Id -> Bool+isPatSynRecordSelector :: Id -> Bool+isDataConRecordSelector :: Id -> Bool+isPrimOpId :: Id -> Bool+isFCallId :: Id -> Bool+isDataConWorkId :: Id -> Bool+isDFunId :: Id -> Bool++isClassOpId_maybe :: Id -> Maybe Class+isPrimOpId_maybe :: Id -> Maybe PrimOp+isFCallId_maybe :: Id -> Maybe ForeignCall+isDataConWorkId_maybe :: Id -> Maybe DataCon++isRecordSelector id = case Var.idDetails id of+ RecSelId {} -> True+ _ -> False++isDataConRecordSelector id = case Var.idDetails id of+ RecSelId {sel_tycon = RecSelData _} -> True+ _ -> False++isPatSynRecordSelector id = case Var.idDetails id of+ RecSelId {sel_tycon = RecSelPatSyn _} -> True+ _ -> False++isNaughtyRecordSelector id = case Var.idDetails id of+ RecSelId { sel_naughty = n } -> n+ _ -> False++isClassOpId_maybe id = case Var.idDetails id of+ ClassOpId cls -> Just cls+ _other -> Nothing++isPrimOpId id = case Var.idDetails id of+ PrimOpId _ -> True+ _ -> False++isDFunId id = case Var.idDetails id of+ DFunId {} -> True+ _ -> False++isPrimOpId_maybe id = case Var.idDetails id of+ PrimOpId op -> Just op+ _ -> Nothing++isFCallId id = case Var.idDetails id of+ FCallId _ -> True+ _ -> False++isFCallId_maybe id = case Var.idDetails id of+ FCallId call -> Just call+ _ -> Nothing++isDataConWorkId id = case Var.idDetails id of+ DataConWorkId _ -> True+ _ -> False++isDataConWorkId_maybe id = case Var.idDetails id of+ DataConWorkId con -> Just con+ _ -> Nothing++isDataConId_maybe :: Id -> Maybe DataCon+isDataConId_maybe id = case Var.idDetails id of+ DataConWorkId con -> Just con+ DataConWrapId con -> Just con+ _ -> Nothing++isJoinId :: Var -> Bool+-- It is convenient in SetLevels.lvlMFE to apply isJoinId+-- to the free vars of an expression, so it's convenient+-- if it returns False for type variables+isJoinId id+ | isId id = case Var.idDetails id of+ JoinId {} -> True+ _ -> False+ | otherwise = False++isJoinId_maybe :: Var -> Maybe JoinArity+isJoinId_maybe id+ | isId id = ASSERT2( isId id, ppr id )+ case Var.idDetails id of+ JoinId arity -> Just arity+ _ -> Nothing+ | otherwise = Nothing++idDataCon :: Id -> DataCon+-- ^ Get from either the worker or the wrapper 'Id' to the 'DataCon'. Currently used only in the desugarer.+--+-- INVARIANT: @idDataCon (dataConWrapId d) = d@: remember, 'dataConWrapId' can return either the wrapper or the worker+idDataCon id = isDataConId_maybe id `orElse` pprPanic "idDataCon" (ppr id)++hasNoBinding :: Id -> Bool+-- ^ Returns @True@ of an 'Id' which may not have a+-- binding, even though it is defined in this module.++-- Data constructor workers used to be things of this kind, but+-- they aren't any more. Instead, we inject a binding for+-- them at the CorePrep stage.+-- EXCEPT: unboxed tuples, which definitely have no binding+hasNoBinding id = case Var.idDetails id of+ PrimOpId _ -> True -- See Note [Primop wrappers]+ FCallId _ -> True+ DataConWorkId dc -> isUnboxedTupleCon dc || isUnboxedSumCon dc+ _ -> False++isImplicitId :: Id -> Bool+-- ^ 'isImplicitId' tells whether an 'Id's info is implied by other+-- declarations, so we don't need to put its signature in an interface+-- file, even if it's mentioned in some other interface unfolding.+isImplicitId id+ = case Var.idDetails id of+ FCallId {} -> True+ ClassOpId {} -> True+ PrimOpId {} -> True+ DataConWorkId {} -> True+ DataConWrapId {} -> True+ -- These are implied by their type or class decl;+ -- remember that all type and class decls appear in the interface file.+ -- The dfun id is not an implicit Id; it must *not* be omitted, because+ -- it carries version info for the instance decl+ _ -> False++idIsFrom :: Module -> Id -> Bool+idIsFrom mod id = nameIsLocalOrFrom mod (idName id)++{-+Note [Primop wrappers]+~~~~~~~~~~~~~~~~~~~~~~+Currently hasNoBinding claims that PrimOpIds don't have a curried+function definition. But actually they do, in GHC.PrimopWrappers,+which is auto-generated from prelude/primops.txt.pp. So actually, hasNoBinding+could return 'False' for PrimOpIds.++But we'd need to add something in CoreToStg to swizzle any unsaturated+applications of GHC.Prim.plusInt# to GHC.PrimopWrappers.plusInt#.++Nota Bene: GHC.PrimopWrappers is needed *regardless*, because it's+used by GHCi, which does not implement primops direct at all.+-}++isDeadBinder :: Id -> Bool+isDeadBinder bndr | isId bndr = isDeadOcc (idOccInfo bndr)+ | otherwise = False -- TyVars count as not dead++{-+************************************************************************+* *+ Evidence variables+* *+************************************************************************+-}++isEvVar :: Var -> Bool+isEvVar var = isPredTy (varType var)++isDictId :: Id -> Bool+isDictId id = isDictTy (idType id)++{-+************************************************************************+* *+ Join variables+* *+************************************************************************+-}++idJoinArity :: JoinId -> JoinArity+idJoinArity id = isJoinId_maybe id `orElse` pprPanic "idJoinArity" (ppr id)++asJoinId :: Id -> JoinArity -> JoinId+asJoinId id arity = WARN(not (isLocalId id),+ text "global id being marked as join var:" <+> ppr id)+ WARN(not (is_vanilla_or_join id),+ ppr id <+> pprIdDetails (idDetails id))+ id `setIdDetails` JoinId arity+ where+ is_vanilla_or_join id = case Var.idDetails id of+ VanillaId -> True+ JoinId {} -> True+ _ -> False++zapJoinId :: Id -> Id+-- May be a regular id already+zapJoinId jid | isJoinId jid = zapIdTailCallInfo (jid `setIdDetails` VanillaId)+ -- Core Lint may complain if still marked+ -- as AlwaysTailCalled+ | otherwise = jid++asJoinId_maybe :: Id -> Maybe JoinArity -> Id+asJoinId_maybe id (Just arity) = asJoinId id arity+asJoinId_maybe id Nothing = zapJoinId id++{-+************************************************************************+* *+\subsection{IdInfo stuff}+* *+************************************************************************+-}++ ---------------------------------+ -- ARITY+idArity :: Id -> Arity+idArity id = arityInfo (idInfo id)++setIdArity :: Id -> Arity -> Id+setIdArity id arity = modifyIdInfo (`setArityInfo` arity) id++idCallArity :: Id -> Arity+idCallArity id = callArityInfo (idInfo id)++setIdCallArity :: Id -> Arity -> Id+setIdCallArity id arity = modifyIdInfo (`setCallArityInfo` arity) id++idFunRepArity :: Id -> RepArity+idFunRepArity x = countFunRepArgs (idArity x) (idType x)++-- | Returns true if an application to n args would diverge+isBottomingId :: Var -> Bool+isBottomingId v+ | isId v = isBottomingSig (idStrictness v)+ | otherwise = False++idStrictness :: Id -> StrictSig+idStrictness id = strictnessInfo (idInfo id)++setIdStrictness :: Id -> StrictSig -> Id+setIdStrictness id sig = modifyIdInfo (`setStrictnessInfo` sig) id++zapIdStrictness :: Id -> Id+zapIdStrictness id = modifyIdInfo (`setStrictnessInfo` nopSig) id++-- | This predicate says whether the 'Id' has a strict demand placed on it or+-- has a type such that it can always be evaluated strictly (i.e an+-- unlifted type, as of GHC 7.6). We need to+-- check separately whether the 'Id' has a so-called \"strict type\" because if+-- the demand for the given @id@ hasn't been computed yet but @id@ has a strict+-- type, we still want @isStrictId id@ to be @True@.+isStrictId :: Id -> Bool+isStrictId id+ = ASSERT2( isId id, text "isStrictId: not an id: " <+> ppr id )+ not (isJoinId id) && (+ (isStrictType (idType id)) ||+ -- Take the best of both strictnesses - old and new+ (isStrictDmd (idDemandInfo id))+ )++ ---------------------------------+ -- UNFOLDING+idUnfolding :: Id -> Unfolding+-- Do not expose the unfolding of a loop breaker!+idUnfolding id+ | isStrongLoopBreaker (occInfo info) = NoUnfolding+ | otherwise = unfoldingInfo info+ where+ info = idInfo id++realIdUnfolding :: Id -> Unfolding+-- Expose the unfolding if there is one, including for loop breakers+realIdUnfolding id = unfoldingInfo (idInfo id)++setIdUnfolding :: Id -> Unfolding -> Id+setIdUnfolding id unfolding = modifyIdInfo (`setUnfoldingInfo` unfolding) id++idDemandInfo :: Id -> Demand+idDemandInfo id = demandInfo (idInfo id)++setIdDemandInfo :: Id -> Demand -> Id+setIdDemandInfo id dmd = modifyIdInfo (`setDemandInfo` dmd) id++setCaseBndrEvald :: StrictnessMark -> Id -> Id+-- Used for variables bound by a case expressions, both the case-binder+-- itself, and any pattern-bound variables that are argument of a+-- strict constructor. It just marks the variable as already-evaluated,+-- so that (for example) a subsequent 'seq' can be dropped+setCaseBndrEvald str id+ | isMarkedStrict str = id `setIdUnfolding` evaldUnfolding+ | otherwise = id++ ---------------------------------+ -- SPECIALISATION++-- See Note [Specialisations and RULES in IdInfo] in IdInfo.hs++idSpecialisation :: Id -> RuleInfo+idSpecialisation id = ruleInfo (idInfo id)++idCoreRules :: Id -> [CoreRule]+idCoreRules id = ruleInfoRules (idSpecialisation id)++idHasRules :: Id -> Bool+idHasRules id = not (isEmptyRuleInfo (idSpecialisation id))++setIdSpecialisation :: Id -> RuleInfo -> Id+setIdSpecialisation id spec_info = modifyIdInfo (`setRuleInfo` spec_info) id++ ---------------------------------+ -- CAF INFO+idCafInfo :: Id -> CafInfo+idCafInfo id = cafInfo (idInfo id)++setIdCafInfo :: Id -> CafInfo -> Id+setIdCafInfo id caf_info = modifyIdInfo (`setCafInfo` caf_info) id++ ---------------------------------+ -- Occcurrence INFO+idOccInfo :: Id -> OccInfo+idOccInfo id = occInfo (idInfo id)++setIdOccInfo :: Id -> OccInfo -> Id+setIdOccInfo id occ_info = modifyIdInfo (`setOccInfo` occ_info) id++zapIdOccInfo :: Id -> Id+zapIdOccInfo b = b `setIdOccInfo` noOccInfo++{-+ ---------------------------------+ -- INLINING+The inline pragma tells us to be very keen to inline this Id, but it's still+OK not to if optimisation is switched off.+-}++idInlinePragma :: Id -> InlinePragma+idInlinePragma id = inlinePragInfo (idInfo id)++setInlinePragma :: Id -> InlinePragma -> Id+setInlinePragma id prag = modifyIdInfo (`setInlinePragInfo` prag) id++modifyInlinePragma :: Id -> (InlinePragma -> InlinePragma) -> Id+modifyInlinePragma id fn = modifyIdInfo (\info -> info `setInlinePragInfo` (fn (inlinePragInfo info))) id++idInlineActivation :: Id -> Activation+idInlineActivation id = inlinePragmaActivation (idInlinePragma id)++setInlineActivation :: Id -> Activation -> Id+setInlineActivation id act = modifyInlinePragma id (\prag -> setInlinePragmaActivation prag act)++idRuleMatchInfo :: Id -> RuleMatchInfo+idRuleMatchInfo id = inlinePragmaRuleMatchInfo (idInlinePragma id)++isConLikeId :: Id -> Bool+isConLikeId id = isDataConWorkId id || isConLike (idRuleMatchInfo id)++{-+ ---------------------------------+ -- ONE-SHOT LAMBDAS+-}++idOneShotInfo :: Id -> OneShotInfo+idOneShotInfo id = oneShotInfo (idInfo id)++-- | Like 'idOneShotInfo', but taking the Horrible State Hack in to account+-- See Note [The state-transformer hack] in CoreArity+idStateHackOneShotInfo :: Id -> OneShotInfo+idStateHackOneShotInfo id+ | isStateHackType (idType id) = stateHackOneShot+ | otherwise = idOneShotInfo id++-- | Returns whether the lambda associated with the 'Id' is certainly applied at most once+-- This one is the "business end", called externally.+-- It works on type variables as well as Ids, returning True+-- Its main purpose is to encapsulate the Horrible State Hack+-- See Note [The state-transformer hack] in CoreArity+isOneShotBndr :: Var -> Bool+isOneShotBndr var+ | isTyVar var = True+ | OneShotLam <- idStateHackOneShotInfo var = True+ | otherwise = False++-- | Should we apply the state hack to values of this 'Type'?+stateHackOneShot :: OneShotInfo+stateHackOneShot = OneShotLam++typeOneShot :: Type -> OneShotInfo+typeOneShot ty+ | isStateHackType ty = stateHackOneShot+ | otherwise = NoOneShotInfo++isStateHackType :: Type -> Bool+isStateHackType ty+ | hasNoStateHack unsafeGlobalDynFlags+ = False+ | otherwise+ = case tyConAppTyCon_maybe ty of+ Just tycon -> tycon == statePrimTyCon+ _ -> False+ -- This is a gross hack. It claims that+ -- every function over realWorldStatePrimTy is a one-shot+ -- function. This is pretty true in practice, and makes a big+ -- difference. For example, consider+ -- a `thenST` \ r -> ...E...+ -- The early full laziness pass, if it doesn't know that r is one-shot+ -- will pull out E (let's say it doesn't mention r) to give+ -- let lvl = E in a `thenST` \ r -> ...lvl...+ -- When `thenST` gets inlined, we end up with+ -- let lvl = E in \s -> case a s of (r, s') -> ...lvl...+ -- and we don't re-inline E.+ --+ -- It would be better to spot that r was one-shot to start with, but+ -- I don't want to rely on that.+ --+ -- Another good example is in fill_in in PrelPack.hs. We should be able to+ -- spot that fill_in has arity 2 (and when Keith is done, we will) but we can't yet.++isProbablyOneShotLambda :: Id -> Bool+isProbablyOneShotLambda id = case idStateHackOneShotInfo id of+ OneShotLam -> True+ NoOneShotInfo -> False++setOneShotLambda :: Id -> Id+setOneShotLambda id = modifyIdInfo (`setOneShotInfo` OneShotLam) id++clearOneShotLambda :: Id -> Id+clearOneShotLambda id = modifyIdInfo (`setOneShotInfo` NoOneShotInfo) id++setIdOneShotInfo :: Id -> OneShotInfo -> Id+setIdOneShotInfo id one_shot = modifyIdInfo (`setOneShotInfo` one_shot) id++updOneShotInfo :: Id -> OneShotInfo -> Id+-- Combine the info in the Id with new info+updOneShotInfo id one_shot+ | do_upd = setIdOneShotInfo id one_shot+ | otherwise = id+ where+ do_upd = case (idOneShotInfo id, one_shot) of+ (NoOneShotInfo, _) -> True+ (OneShotLam, _) -> False++-- The OneShotLambda functions simply fiddle with the IdInfo flag+-- But watch out: this may change the type of something else+-- f = \x -> e+-- If we change the one-shot-ness of x, f's type changes++zapInfo :: (IdInfo -> Maybe IdInfo) -> Id -> Id+zapInfo zapper id = maybeModifyIdInfo (zapper (idInfo id)) id++zapLamIdInfo :: Id -> Id+zapLamIdInfo = zapInfo zapLamInfo++zapFragileIdInfo :: Id -> Id+zapFragileIdInfo = zapInfo zapFragileInfo++zapIdDemandInfo :: Id -> Id+zapIdDemandInfo = zapInfo zapDemandInfo++zapIdUsageInfo :: Id -> Id+zapIdUsageInfo = zapInfo zapUsageInfo++zapIdUsageEnvInfo :: Id -> Id+zapIdUsageEnvInfo = zapInfo zapUsageEnvInfo++zapIdUsedOnceInfo :: Id -> Id+zapIdUsedOnceInfo = zapInfo zapUsedOnceInfo++zapIdTailCallInfo :: Id -> Id+zapIdTailCallInfo = zapInfo zapTailCallInfo++{-+Note [transferPolyIdInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~+This transfer is used in two places:+ FloatOut (long-distance let-floating)+ SimplUtils.abstractFloats (short-distance let-floating)++Consider the short-distance let-floating:++ f = /\a. let g = rhs in ...++Then if we float thus++ g' = /\a. rhs+ f = /\a. ...[g' a/g]....++we *do not* want to lose g's+ * strictness information+ * arity+ * inline pragma (though that is bit more debatable)+ * occurrence info++Mostly this is just an optimisation, but it's *vital* to+transfer the occurrence info. Consider++ NonRec { f = /\a. let Rec { g* = ..g.. } in ... }++where the '*' means 'LoopBreaker'. Then if we float we must get++ Rec { g'* = /\a. ...(g' a)... }+ NonRec { f = /\a. ...[g' a/g]....}++where g' is also marked as LoopBreaker. If not, terrible things+can happen if we re-simplify the binding (and the Simplifier does+sometimes simplify a term twice); see Trac #4345.++It's not so simple to retain+ * worker info+ * rules+so we simply discard those. Sooner or later this may bite us.++If we abstract wrt one or more *value* binders, we must modify the+arity and strictness info before transferring it. E.g.+ f = \x. e+-->+ g' = \y. \x. e+ + substitute (g' y) for g+Notice that g' has an arity one more than the original g+-}++transferPolyIdInfo :: Id -- Original Id+ -> [Var] -- Abstract wrt these variables+ -> Id -- New Id+ -> Id+transferPolyIdInfo old_id abstract_wrt new_id+ = modifyIdInfo transfer new_id+ where+ arity_increase = count isId abstract_wrt -- Arity increases by the+ -- number of value binders++ old_info = idInfo old_id+ old_arity = arityInfo old_info+ old_inline_prag = inlinePragInfo old_info+ old_occ_info = occInfo old_info+ new_arity = old_arity + arity_increase+ new_occ_info = zapOccTailCallInfo old_occ_info++ old_strictness = strictnessInfo old_info+ new_strictness = increaseStrictSigArity arity_increase old_strictness++ transfer new_info = new_info `setArityInfo` new_arity+ `setInlinePragInfo` old_inline_prag+ `setOccInfo` new_occ_info+ `setStrictnessInfo` new_strictness++isNeverLevPolyId :: Id -> Bool+isNeverLevPolyId = isNeverLevPolyIdInfo . idInfo
+ basicTypes/IdInfo.hs view
@@ -0,0 +1,622 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[IdInfo]{@IdInfos@: Non-essential information about @Ids@}++(And a pretty good illustration of quite a few things wrong with+Haskell. [WDP 94/11])+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}++module IdInfo (+ -- * The IdDetails type+ IdDetails(..), pprIdDetails, coVarDetails, isCoVarDetails,+ JoinArity, isJoinIdDetails_maybe,+ RecSelParent(..),++ -- * The IdInfo type+ IdInfo, -- Abstract+ vanillaIdInfo, noCafIdInfo,++ -- ** The OneShotInfo type+ OneShotInfo(..),+ oneShotInfo, noOneShotInfo, hasNoOneShotInfo,+ setOneShotInfo,++ -- ** Zapping various forms of Info+ zapLamInfo, zapFragileInfo,+ zapDemandInfo, zapUsageInfo, zapUsageEnvInfo, zapUsedOnceInfo,+ zapTailCallInfo, zapCallArityInfo,++ -- ** The ArityInfo type+ ArityInfo,+ unknownArity,+ arityInfo, setArityInfo, ppArityInfo,++ callArityInfo, setCallArityInfo,++ -- ** Demand and strictness Info+ strictnessInfo, setStrictnessInfo,+ demandInfo, setDemandInfo, pprStrictness,++ -- ** Unfolding Info+ unfoldingInfo, setUnfoldingInfo,++ -- ** The InlinePragInfo type+ InlinePragInfo,+ inlinePragInfo, setInlinePragInfo,++ -- ** The OccInfo type+ OccInfo(..),+ isDeadOcc, isStrongLoopBreaker, isWeakLoopBreaker,+ occInfo, setOccInfo,++ InsideLam, OneBranch,+ insideLam, notInsideLam, oneBranch, notOneBranch,++ TailCallInfo(..),+ tailCallInfo, isAlwaysTailCalled,++ -- ** The RuleInfo type+ RuleInfo(..),+ emptyRuleInfo,+ isEmptyRuleInfo, ruleInfoFreeVars,+ ruleInfoRules, setRuleInfoHead,+ ruleInfo, setRuleInfo,++ -- ** The CAFInfo type+ CafInfo(..),+ ppCafInfo, mayHaveCafRefs,+ cafInfo, setCafInfo,++ -- ** Tick-box Info+ TickBoxOp(..), TickBoxId,++ -- ** Levity info+ LevityInfo, levityInfo, setNeverLevPoly, setLevityInfoWithType,+ isNeverLevPolyIdInfo+ ) where++#include "HsVersions.h"++import CoreSyn++import Class+import {-# SOURCE #-} PrimOp (PrimOp)+import Name+import VarSet+import BasicTypes+import DataCon+import TyCon+import PatSyn+import Type+import ForeignCall+import Outputable+import Module+import Demand+import Util++-- infixl so you can say (id `set` a `set` b)+infixl 1 `setRuleInfo`,+ `setArityInfo`,+ `setInlinePragInfo`,+ `setUnfoldingInfo`,+ `setOneShotInfo`,+ `setOccInfo`,+ `setCafInfo`,+ `setStrictnessInfo`,+ `setDemandInfo`,+ `setNeverLevPoly`,+ `setLevityInfoWithType`++{-+************************************************************************+* *+ IdDetails+* *+************************************************************************+-}++-- | Identifier Details+--+-- The 'IdDetails' of an 'Id' give stable, and necessary,+-- information about the Id.+data IdDetails+ = VanillaId++ -- | The 'Id' for a record selector+ | RecSelId+ { sel_tycon :: RecSelParent+ , sel_naughty :: Bool -- True <=> a "naughty" selector which can't actually exist, for example @x@ in:+ -- data T = forall a. MkT { x :: a }+ } -- See Note [Naughty record selectors] in TcTyClsDecls++ | DataConWorkId DataCon -- ^ The 'Id' is for a data constructor /worker/+ | DataConWrapId DataCon -- ^ The 'Id' is for a data constructor /wrapper/++ -- [the only reasons we need to know is so that+ -- a) to support isImplicitId+ -- b) when desugaring a RecordCon we can get+ -- from the Id back to the data con]+ | ClassOpId Class -- ^ The 'Id' is a superclass selector,+ -- or class operation of a class++ | PrimOpId PrimOp -- ^ The 'Id' is for a primitive operator+ | FCallId ForeignCall -- ^ The 'Id' is for a foreign call.+ -- Type will be simple: no type families, newtypes, etc++ | TickBoxOpId TickBoxOp -- ^ The 'Id' is for a HPC tick box (both traditional and binary)++ | DFunId Bool -- ^ A dictionary function.+ -- Bool = True <=> the class has only one method, so may be+ -- implemented with a newtype, so it might be bad+ -- to be strict on this dictionary++ | CoVarId -- ^ A coercion variable+ -- This only covers /un-lifted/ coercions, of type+ -- (t1 ~# t2) or (t1 ~R# t2), not their lifted variants+ | JoinId JoinArity -- ^ An 'Id' for a join point taking n arguments+ -- Note [Join points] in CoreSyn++-- | Recursive Selector Parent+data RecSelParent = RecSelData TyCon | RecSelPatSyn PatSyn deriving Eq+ -- Either `TyCon` or `PatSyn` depending+ -- on the origin of the record selector.+ -- For a data type family, this is the+ -- /instance/ 'TyCon' not the family 'TyCon'++instance Outputable RecSelParent where+ ppr p = case p of+ RecSelData ty_con -> ppr ty_con+ RecSelPatSyn ps -> ppr ps++-- | Just a synonym for 'CoVarId'. Written separately so it can be+-- exported in the hs-boot file.+coVarDetails :: IdDetails+coVarDetails = CoVarId++-- | Check if an 'IdDetails' says 'CoVarId'.+isCoVarDetails :: IdDetails -> Bool+isCoVarDetails CoVarId = True+isCoVarDetails _ = False++isJoinIdDetails_maybe :: IdDetails -> Maybe JoinArity+isJoinIdDetails_maybe (JoinId join_arity) = Just join_arity+isJoinIdDetails_maybe _ = Nothing++instance Outputable IdDetails where+ ppr = pprIdDetails++pprIdDetails :: IdDetails -> SDoc+pprIdDetails VanillaId = empty+pprIdDetails other = brackets (pp other)+ where+ pp VanillaId = panic "pprIdDetails"+ pp (DataConWorkId _) = text "DataCon"+ pp (DataConWrapId _) = text "DataConWrapper"+ pp (ClassOpId {}) = text "ClassOp"+ pp (PrimOpId _) = text "PrimOp"+ pp (FCallId _) = text "ForeignCall"+ pp (TickBoxOpId _) = text "TickBoxOp"+ pp (DFunId nt) = text "DFunId" <> ppWhen nt (text "(nt)")+ pp (RecSelId { sel_naughty = is_naughty })+ = brackets $ text "RecSel" <>+ ppWhen is_naughty (text "(naughty)")+ pp CoVarId = text "CoVarId"+ pp (JoinId arity) = text "JoinId" <> parens (int arity)++{-+************************************************************************+* *+\subsection{The main IdInfo type}+* *+************************************************************************+-}++-- | Identifier Information+--+-- An 'IdInfo' gives /optional/ information about an 'Id'. If+-- present it never lies, but it may not be present, in which case there+-- is always a conservative assumption which can be made.+--+-- Two 'Id's may have different info even though they have the same+-- 'Unique' (and are hence the same 'Id'); for example, one might lack+-- the properties attached to the other.+--+-- Most of the 'IdInfo' gives information about the value, or definition, of+-- the 'Id', independent of its usage. Exceptions to this+-- are 'demandInfo', 'occInfo', 'oneShotInfo' and 'callArityInfo'.+--+-- Performance note: when we update 'IdInfo', we have to reallocate this+-- entire record, so it is a good idea not to let this data structure get+-- too big.+data IdInfo+ = IdInfo {+ arityInfo :: !ArityInfo, -- ^ 'Id' arity+ ruleInfo :: RuleInfo, -- ^ Specialisations of the 'Id's function which exist+ -- See Note [Specialisations and RULES in IdInfo]+ unfoldingInfo :: Unfolding, -- ^ The 'Id's unfolding+ cafInfo :: CafInfo, -- ^ 'Id' CAF info+ oneShotInfo :: OneShotInfo, -- ^ Info about a lambda-bound variable, if the 'Id' is one+ inlinePragInfo :: InlinePragma, -- ^ Any inline pragma atached to the 'Id'+ occInfo :: OccInfo, -- ^ How the 'Id' occurs in the program++ strictnessInfo :: StrictSig, -- ^ A strictness signature++ demandInfo :: Demand, -- ^ ID demand information+ callArityInfo :: !ArityInfo, -- ^ How this is called.+ -- n <=> all calls have at least n arguments++ levityInfo :: LevityInfo -- ^ when applied, will this Id ever have a levity-polymorphic type?+ }++-- Setters++setRuleInfo :: IdInfo -> RuleInfo -> IdInfo+setRuleInfo info sp = sp `seq` info { ruleInfo = sp }+setInlinePragInfo :: IdInfo -> InlinePragma -> IdInfo+setInlinePragInfo info pr = pr `seq` info { inlinePragInfo = pr }+setOccInfo :: IdInfo -> OccInfo -> IdInfo+setOccInfo info oc = oc `seq` info { occInfo = oc }+ -- Try to avoid spack leaks by seq'ing++setUnfoldingInfo :: IdInfo -> Unfolding -> IdInfo+setUnfoldingInfo info uf+ = -- We don't seq the unfolding, as we generate intermediate+ -- unfoldings which are just thrown away, so evaluating them is a+ -- waste of time.+ -- seqUnfolding uf `seq`+ info { unfoldingInfo = uf }++setArityInfo :: IdInfo -> ArityInfo -> IdInfo+setArityInfo info ar = info { arityInfo = ar }+setCallArityInfo :: IdInfo -> ArityInfo -> IdInfo+setCallArityInfo info ar = info { callArityInfo = ar }+setCafInfo :: IdInfo -> CafInfo -> IdInfo+setCafInfo info caf = info { cafInfo = caf }++setOneShotInfo :: IdInfo -> OneShotInfo -> IdInfo+setOneShotInfo info lb = {-lb `seq`-} info { oneShotInfo = lb }++setDemandInfo :: IdInfo -> Demand -> IdInfo+setDemandInfo info dd = dd `seq` info { demandInfo = dd }++setStrictnessInfo :: IdInfo -> StrictSig -> IdInfo+setStrictnessInfo info dd = dd `seq` info { strictnessInfo = dd }++-- | Basic 'IdInfo' that carries no useful information whatsoever+vanillaIdInfo :: IdInfo+vanillaIdInfo+ = IdInfo {+ cafInfo = vanillaCafInfo,+ arityInfo = unknownArity,+ ruleInfo = emptyRuleInfo,+ unfoldingInfo = noUnfolding,+ oneShotInfo = NoOneShotInfo,+ inlinePragInfo = defaultInlinePragma,+ occInfo = noOccInfo,+ demandInfo = topDmd,+ strictnessInfo = nopSig,+ callArityInfo = unknownArity,+ levityInfo = NoLevityInfo+ }++-- | More informative 'IdInfo' we can use when we know the 'Id' has no CAF references+noCafIdInfo :: IdInfo+noCafIdInfo = vanillaIdInfo `setCafInfo` NoCafRefs+ -- Used for built-in type Ids in MkId.++{-+************************************************************************+* *+\subsection[arity-IdInfo]{Arity info about an @Id@}+* *+************************************************************************++For locally-defined Ids, the code generator maintains its own notion+of their arities; so it should not be asking... (but other things+besides the code-generator need arity info!)+-}++-- | Arity Information+--+-- An 'ArityInfo' of @n@ tells us that partial application of this+-- 'Id' to up to @n-1@ value arguments does essentially no work.+--+-- That is not necessarily the same as saying that it has @n@ leading+-- lambdas, because coerces may get in the way.+--+-- The arity might increase later in the compilation process, if+-- an extra lambda floats up to the binding site.+type ArityInfo = Arity++-- | It is always safe to assume that an 'Id' has an arity of 0+unknownArity :: Arity+unknownArity = 0++ppArityInfo :: Int -> SDoc+ppArityInfo 0 = empty+ppArityInfo n = hsep [text "Arity", int n]++{-+************************************************************************+* *+\subsection{Inline-pragma information}+* *+************************************************************************+-}++-- | Inline Pragma Information+--+-- Tells when the inlining is active.+-- When it is active the thing may be inlined, depending on how+-- big it is.+--+-- If there was an @INLINE@ pragma, then as a separate matter, the+-- RHS will have been made to look small with a Core inline 'Note'+--+-- The default 'InlinePragInfo' is 'AlwaysActive', so the info serves+-- entirely as a way to inhibit inlining until we want it+type InlinePragInfo = InlinePragma++{-+************************************************************************+* *+ Strictness+* *+************************************************************************+-}++pprStrictness :: StrictSig -> SDoc+pprStrictness sig = ppr sig++{-+************************************************************************+* *+ RuleInfo+* *+************************************************************************++Note [Specialisations and RULES in IdInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Generally speaking, a GlobalId has an *empty* RuleInfo. All their+RULES are contained in the globally-built rule-base. In principle,+one could attach the to M.f the RULES for M.f that are defined in M.+But we don't do that for instance declarations and so we just treat+them all uniformly.++The EXCEPTION is PrimOpIds, which do have rules in their IdInfo. That is+jsut for convenience really.++However, LocalIds may have non-empty RuleInfo. We treat them+differently because:+ a) they might be nested, in which case a global table won't work+ b) the RULE might mention free variables, which we use to keep things alive++In TidyPgm, when the LocalId becomes a GlobalId, its RULES are stripped off+and put in the global list.+-}++-- | Rule Information+--+-- Records the specializations of this 'Id' that we know about+-- in the form of rewrite 'CoreRule's that target them+data RuleInfo+ = RuleInfo+ [CoreRule]+ DVarSet -- Locally-defined free vars of *both* LHS and RHS+ -- of rules. I don't think it needs to include the+ -- ru_fn though.+ -- Note [Rule dependency info] in OccurAnal++-- | Assume that no specilizations exist: always safe+emptyRuleInfo :: RuleInfo+emptyRuleInfo = RuleInfo [] emptyDVarSet++isEmptyRuleInfo :: RuleInfo -> Bool+isEmptyRuleInfo (RuleInfo rs _) = null rs++-- | Retrieve the locally-defined free variables of both the left and+-- right hand sides of the specialization rules+ruleInfoFreeVars :: RuleInfo -> DVarSet+ruleInfoFreeVars (RuleInfo _ fvs) = fvs++ruleInfoRules :: RuleInfo -> [CoreRule]+ruleInfoRules (RuleInfo rules _) = rules++-- | Change the name of the function the rule is keyed on on all of the 'CoreRule's+setRuleInfoHead :: Name -> RuleInfo -> RuleInfo+setRuleInfoHead fn (RuleInfo rules fvs)+ = RuleInfo (map (setRuleIdName fn) rules) fvs++{-+************************************************************************+* *+\subsection[CG-IdInfo]{Code generator-related information}+* *+************************************************************************+-}++-- CafInfo is used to build Static Reference Tables (see simplStg/SRT.hs).++-- | Constant applicative form Information+--+-- Records whether an 'Id' makes Constant Applicative Form references+data CafInfo+ = MayHaveCafRefs -- ^ Indicates that the 'Id' is for either:+ --+ -- 1. A function or static constructor+ -- that refers to one or more CAFs, or+ --+ -- 2. A real live CAF++ | NoCafRefs -- ^ A function or static constructor+ -- that refers to no CAFs.+ deriving (Eq, Ord)++-- | Assumes that the 'Id' has CAF references: definitely safe+vanillaCafInfo :: CafInfo+vanillaCafInfo = MayHaveCafRefs++mayHaveCafRefs :: CafInfo -> Bool+mayHaveCafRefs MayHaveCafRefs = True+mayHaveCafRefs _ = False++instance Outputable CafInfo where+ ppr = ppCafInfo++ppCafInfo :: CafInfo -> SDoc+ppCafInfo NoCafRefs = text "NoCafRefs"+ppCafInfo MayHaveCafRefs = empty++{-+************************************************************************+* *+\subsection{Bulk operations on IdInfo}+* *+************************************************************************+-}++-- | This is used to remove information on lambda binders that we have+-- setup as part of a lambda group, assuming they will be applied all at once,+-- but turn out to be part of an unsaturated lambda as in e.g:+--+-- > (\x1. \x2. e) arg1+zapLamInfo :: IdInfo -> Maybe IdInfo+zapLamInfo info@(IdInfo {occInfo = occ, demandInfo = demand})+ | is_safe_occ occ && is_safe_dmd demand+ = Nothing+ | otherwise+ = Just (info {occInfo = safe_occ, demandInfo = topDmd})+ where+ -- The "unsafe" occ info is the ones that say I'm not in a lambda+ -- because that might not be true for an unsaturated lambda+ is_safe_occ occ | isAlwaysTailCalled occ = False+ is_safe_occ (OneOcc { occ_in_lam = in_lam }) = in_lam+ is_safe_occ _other = True++ safe_occ = case occ of+ OneOcc{} -> occ { occ_in_lam = True+ , occ_tail = NoTailCallInfo }+ IAmALoopBreaker{}+ -> occ { occ_tail = NoTailCallInfo }+ _other -> occ++ is_safe_dmd dmd = not (isStrictDmd dmd)++-- | Remove all demand info on the 'IdInfo'+zapDemandInfo :: IdInfo -> Maybe IdInfo+zapDemandInfo info = Just (info {demandInfo = topDmd})++-- | Remove usage (but not strictness) info on the 'IdInfo'+zapUsageInfo :: IdInfo -> Maybe IdInfo+zapUsageInfo info = Just (info {demandInfo = zapUsageDemand (demandInfo info)})++-- | Remove usage environment info from the strictness signature on the 'IdInfo'+zapUsageEnvInfo :: IdInfo -> Maybe IdInfo+zapUsageEnvInfo info+ | hasDemandEnvSig (strictnessInfo info)+ = Just (info {strictnessInfo = zapUsageEnvSig (strictnessInfo info)})+ | otherwise+ = Nothing++zapUsedOnceInfo :: IdInfo -> Maybe IdInfo+zapUsedOnceInfo info+ = Just $ info { strictnessInfo = zapUsedOnceSig (strictnessInfo info)+ , demandInfo = zapUsedOnceDemand (demandInfo info) }++zapFragileInfo :: IdInfo -> Maybe IdInfo+-- ^ Zap info that depends on free variables+zapFragileInfo info@(IdInfo { occInfo = occ, unfoldingInfo = unf })+ = new_unf `seq` -- The unfolding field is not (currently) strict, so we+ -- force it here to avoid a (zapFragileUnfolding unf) thunk+ -- which might leak space+ Just (info `setRuleInfo` emptyRuleInfo+ `setUnfoldingInfo` new_unf+ `setOccInfo` zapFragileOcc occ)+ where+ new_unf = zapFragileUnfolding unf++zapFragileUnfolding :: Unfolding -> Unfolding+zapFragileUnfolding unf+ | isFragileUnfolding unf = noUnfolding+ | otherwise = unf++zapTailCallInfo :: IdInfo -> Maybe IdInfo+zapTailCallInfo info+ = case occInfo info of+ occ | isAlwaysTailCalled occ -> Just (info `setOccInfo` safe_occ)+ | otherwise -> Nothing+ where+ safe_occ = occ { occ_tail = NoTailCallInfo }++zapCallArityInfo :: IdInfo -> IdInfo+zapCallArityInfo info = setCallArityInfo info 0++{-+************************************************************************+* *+\subsection{TickBoxOp}+* *+************************************************************************+-}++type TickBoxId = Int++-- | Tick box for Hpc-style coverage+data TickBoxOp+ = TickBox Module {-# UNPACK #-} !TickBoxId++instance Outputable TickBoxOp where+ ppr (TickBox mod n) = text "tick" <+> ppr (mod,n)++{-+************************************************************************+* *+ Levity+* *+************************************************************************++Note [Levity info]+~~~~~~~~~~~~~~~~~~++Ids store whether or not they can be levity-polymorphic at any amount+of saturation. This is helpful in optimizing the levity-polymorphism check+done in the desugarer, where we can usually learn that something is not+levity-polymorphic without actually figuring out its type. See+isExprLevPoly in CoreUtils for where this info is used. Storing+this is required to prevent perf/compiler/T5631 from blowing up.++-}++-- See Note [Levity info]+data LevityInfo = NoLevityInfo -- always safe+ | NeverLevityPolymorphic+ deriving Eq++instance Outputable LevityInfo where+ ppr NoLevityInfo = text "NoLevityInfo"+ ppr NeverLevityPolymorphic = text "NeverLevityPolymorphic"++-- | Marks an IdInfo describing an Id that is never levity polymorphic (even when+-- applied). The Type is only there for checking that it's really never levity+-- polymorphic+setNeverLevPoly :: HasDebugCallStack => IdInfo -> Type -> IdInfo+setNeverLevPoly info ty+ = ASSERT2( not (resultIsLevPoly ty), ppr ty )+ info { levityInfo = NeverLevityPolymorphic }++setLevityInfoWithType :: IdInfo -> Type -> IdInfo+setLevityInfoWithType info ty+ | not (resultIsLevPoly ty)+ = info { levityInfo = NeverLevityPolymorphic }+ | otherwise+ = info++isNeverLevPolyIdInfo :: IdInfo -> Bool+isNeverLevPolyIdInfo info+ | NeverLevityPolymorphic <- levityInfo info = True+ | otherwise = False
+ basicTypes/IdInfo.hs-boot view
@@ -0,0 +1,10 @@+module IdInfo where+import Outputable+data IdInfo+data IdDetails++vanillaIdInfo :: IdInfo+coVarDetails :: IdDetails+isCoVarDetails :: IdDetails -> Bool+pprIdDetails :: IdDetails -> SDoc+
+ basicTypes/Lexeme.hs view
@@ -0,0 +1,238 @@+-- (c) The GHC Team+--+-- Functions to evaluate whether or not a string is a valid identifier.+-- There is considerable overlap between the logic here and the logic+-- in Lexer.x, but sadly there seems to be way to merge them.++module Lexeme (+ -- * Lexical characteristics of Haskell names++ -- | Use these functions to figure what kind of name a 'FastString'+ -- represents; these functions do /not/ check that the identifier+ -- is valid.++ isLexCon, isLexVar, isLexId, isLexSym,+ isLexConId, isLexConSym, isLexVarId, isLexVarSym,+ startsVarSym, startsVarId, startsConSym, startsConId,++ -- * Validating identifiers++ -- | These functions (working over plain old 'String's) check+ -- to make sure that the identifier is valid.+ okVarOcc, okConOcc, okTcOcc,+ okVarIdOcc, okVarSymOcc, okConIdOcc, okConSymOcc++ -- Some of the exports above are not used within GHC, but may+ -- be of value to GHC API users.++ ) where++import FastString++import Data.Char+import qualified Data.Set as Set++import GHC.Lexeme++{-++************************************************************************+* *+ Lexical categories+* *+************************************************************************++These functions test strings to see if they fit the lexical categories+defined in the Haskell report.++Note [Classification of generated names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Some names generated for internal use can show up in debugging output,+e.g. when using -ddump-simpl. These generated names start with a $+but should still be pretty-printed using prefix notation. We make sure+this is the case in isLexVarSym by only classifying a name as a symbol+if all its characters are symbols, not just its first one.+-}++isLexCon, isLexVar, isLexId, isLexSym :: FastString -> Bool+isLexConId, isLexConSym, isLexVarId, isLexVarSym :: FastString -> Bool++isLexCon cs = isLexConId cs || isLexConSym cs+isLexVar cs = isLexVarId cs || isLexVarSym cs++isLexId cs = isLexConId cs || isLexVarId cs+isLexSym cs = isLexConSym cs || isLexVarSym cs++-------------+isLexConId cs -- Prefix type or data constructors+ | nullFS cs = False -- e.g. "Foo", "[]", "(,)"+ | cs == (fsLit "[]") = True+ | otherwise = startsConId (headFS cs)++isLexVarId cs -- Ordinary prefix identifiers+ | nullFS cs = False -- e.g. "x", "_x"+ | otherwise = startsVarId (headFS cs)++isLexConSym cs -- Infix type or data constructors+ | nullFS cs = False -- e.g. ":-:", ":", "->"+ | cs == (fsLit "->") = True+ | otherwise = startsConSym (headFS cs)++isLexVarSym fs -- Infix identifiers e.g. "+"+ | fs == (fsLit "~R#") = True+ | otherwise+ = case (if nullFS fs then [] else unpackFS fs) of+ [] -> False+ (c:cs) -> startsVarSym c && all isVarSymChar cs+ -- See Note [Classification of generated names]++{-++************************************************************************+* *+ Detecting valid names for Template Haskell+* *+************************************************************************++-}++----------------------+-- External interface+----------------------++-- | Is this an acceptable variable name?+okVarOcc :: String -> Bool+okVarOcc str@(c:_)+ | startsVarId c+ = okVarIdOcc str+ | startsVarSym c+ = okVarSymOcc str+okVarOcc _ = False++-- | Is this an acceptable constructor name?+okConOcc :: String -> Bool+okConOcc str@(c:_)+ | startsConId c+ = okConIdOcc str+ | startsConSym c+ = okConSymOcc str+ | str == "[]"+ = True+okConOcc _ = False++-- | Is this an acceptable type name?+okTcOcc :: String -> Bool+okTcOcc "[]" = True+okTcOcc "->" = True+okTcOcc "~" = True+okTcOcc str@(c:_)+ | startsConId c+ = okConIdOcc str+ | startsConSym c+ = okConSymOcc str+ | startsVarSym c+ = okVarSymOcc str+okTcOcc _ = False++-- | Is this an acceptable alphanumeric variable name, assuming it starts+-- with an acceptable letter?+okVarIdOcc :: String -> Bool+okVarIdOcc str = okIdOcc str &&+ -- admit "_" as a valid identifier. Required to support typed+ -- holes in Template Haskell. See #10267+ (str == "_" || not (str `Set.member` reservedIds))++-- | Is this an acceptable symbolic variable name, assuming it starts+-- with an acceptable character?+okVarSymOcc :: String -> Bool+okVarSymOcc str = all okSymChar str &&+ not (str `Set.member` reservedOps) &&+ not (isDashes str)++-- | Is this an acceptable alphanumeric constructor name, assuming it+-- starts with an acceptable letter?+okConIdOcc :: String -> Bool+okConIdOcc str = okIdOcc str ||+ is_tuple_name1 True str ||+ -- Is it a boxed tuple...+ is_tuple_name1 False str ||+ -- ...or an unboxed tuple (Trac #12407)...+ is_sum_name1 str+ -- ...or an unboxed sum (Trac #12514)?+ where+ -- check for tuple name, starting at the beginning+ is_tuple_name1 True ('(' : rest) = is_tuple_name2 True rest+ is_tuple_name1 False ('(' : '#' : rest) = is_tuple_name2 False rest+ is_tuple_name1 _ _ = False++ -- check for tuple tail+ is_tuple_name2 True ")" = True+ is_tuple_name2 False "#)" = True+ is_tuple_name2 boxed (',' : rest) = is_tuple_name2 boxed rest+ is_tuple_name2 boxed (ws : rest)+ | isSpace ws = is_tuple_name2 boxed rest+ is_tuple_name2 _ _ = False++ -- check for sum name, starting at the beginning+ is_sum_name1 ('(' : '#' : rest) = is_sum_name2 False rest+ is_sum_name1 _ = False++ -- check for sum tail, only allowing at most one underscore+ is_sum_name2 _ "#)" = True+ is_sum_name2 underscore ('|' : rest) = is_sum_name2 underscore rest+ is_sum_name2 False ('_' : rest) = is_sum_name2 True rest+ is_sum_name2 underscore (ws : rest)+ | isSpace ws = is_sum_name2 underscore rest+ is_sum_name2 _ _ = False++-- | Is this an acceptable symbolic constructor name, assuming it+-- starts with an acceptable character?+okConSymOcc :: String -> Bool+okConSymOcc ":" = True+okConSymOcc str = all okSymChar str &&+ not (str `Set.member` reservedOps)++----------------------+-- Internal functions+----------------------++-- | Is this string an acceptable id, possibly with a suffix of hashes,+-- but not worrying about case or clashing with reserved words?+okIdOcc :: String -> Bool+okIdOcc str+ = let hashes = dropWhile okIdChar str in+ all (== '#') hashes -- -XMagicHash allows a suffix of hashes+ -- of course, `all` says "True" to an empty list++-- | Is this character acceptable in an identifier (after the first letter)?+-- See alexGetByte in Lexer.x+okIdChar :: Char -> Bool+okIdChar c = case generalCategory c of+ UppercaseLetter -> True+ LowercaseLetter -> True+ TitlecaseLetter -> True+ ModifierLetter -> True -- See #10196+ OtherLetter -> True -- See #1103+ NonSpacingMark -> True -- See #7650+ DecimalNumber -> True+ OtherNumber -> True -- See #4373+ _ -> c == '\'' || c == '_'++-- | All reserved identifiers. Taken from section 2.4 of the 2010 Report.+reservedIds :: Set.Set String+reservedIds = Set.fromList [ "case", "class", "data", "default", "deriving"+ , "do", "else", "foreign", "if", "import", "in"+ , "infix", "infixl", "infixr", "instance", "let"+ , "module", "newtype", "of", "then", "type", "where"+ , "_" ]++-- | All reserved operators. Taken from section 2.4 of the 2010 Report.+reservedOps :: Set.Set String+reservedOps = Set.fromList [ "..", ":", "::", "=", "\\", "|", "<-", "->"+ , "@", "~", "=>" ]++-- | Does this string contain only dashes and has at least 2 of them?+isDashes :: String -> Bool+isDashes ('-' : '-' : rest) = all (== '-') rest+isDashes _ = False
+ basicTypes/Literal.hs view
@@ -0,0 +1,603 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1998++\section[Literal]{@Literal@: Machine literals (unboxed, of course)}+-}++{-# LANGUAGE CPP, DeriveDataTypeable #-}++module Literal+ (+ -- * Main data type+ Literal(..) -- Exported to ParseIface++ -- ** Creating Literals+ , mkMachInt, mkMachIntWrap+ , mkMachWord, mkMachWordWrap+ , mkMachInt64, mkMachInt64Wrap+ , mkMachWord64, mkMachWord64Wrap+ , mkMachFloat, mkMachDouble+ , mkMachChar, mkMachString+ , mkLitInteger++ -- ** Operations on Literals+ , literalType+ , absentLiteralOf+ , pprLiteral++ -- ** Predicates on Literals and their contents+ , litIsDupable, litIsTrivial, litIsLifted+ , inIntRange, inWordRange, tARGET_MAX_INT, inCharRange+ , isZeroLit+ , litFitsInChar+ , litValue, isLitValue, isLitValue_maybe, mapLitValue++ -- ** Coercions+ , word2IntLit, int2WordLit+ , narrow8IntLit, narrow16IntLit, narrow32IntLit+ , narrow8WordLit, narrow16WordLit, narrow32WordLit+ , char2IntLit, int2CharLit+ , float2IntLit, int2FloatLit, double2IntLit, int2DoubleLit+ , nullAddrLit, float2DoubleLit, double2FloatLit+ ) where++#include "HsVersions.h"++import TysPrim+import PrelNames+import Type+import TyCon+import Outputable+import FastString+import BasicTypes+import Binary+import Constants+import DynFlags+import Platform+import UniqFM+import Util++import Data.ByteString (ByteString)+import Data.Int+import Data.Word+import Data.Char+import Data.Maybe ( isJust )+import Data.Data ( Data )+import Numeric ( fromRat )++{-+************************************************************************+* *+\subsection{Literals}+* *+************************************************************************+-}++-- | So-called 'Literal's are one of:+--+-- * An unboxed (/machine/) literal ('MachInt', 'MachFloat', etc.),+-- which is presumed to be surrounded by appropriate constructors+-- (@Int#@, etc.), so that the overall thing makes sense.+--+-- We maintain the invariant that the 'Integer' the Mach{Int,Word}*+-- constructors are actually in the (possibly target-dependent) range.+-- The mkMach{Int,Word}*Wrap smart constructors ensure this by applying+-- the target machine's wrapping semantics. Use these in situations+-- where you know the wrapping semantics are correct.+--+-- * The literal derived from the label mentioned in a \"foreign label\"+-- declaration ('MachLabel')+data Literal+ = ------------------+ -- First the primitive guys+ MachChar Char -- ^ @Char#@ - at least 31 bits. Create with 'mkMachChar'++ | MachStr ByteString -- ^ A string-literal: stored and emitted+ -- UTF-8 encoded, we'll arrange to decode it+ -- at runtime. Also emitted with a @'\0'@+ -- terminator. Create with 'mkMachString'++ | MachNullAddr -- ^ The @NULL@ pointer, the only pointer value+ -- that can be represented as a Literal. Create+ -- with 'nullAddrLit'++ | MachInt Integer -- ^ @Int#@ - according to target machine+ | MachInt64 Integer -- ^ @Int64#@ - exactly 64 bits+ | MachWord Integer -- ^ @Word#@ - according to target machine+ | MachWord64 Integer -- ^ @Word64#@ - exactly 64 bits++ | MachFloat Rational -- ^ @Float#@. Create with 'mkMachFloat'+ | MachDouble Rational -- ^ @Double#@. Create with 'mkMachDouble'++ | MachLabel FastString+ (Maybe Int)+ FunctionOrData+ -- ^ A label literal. Parameters:+ --+ -- 1) The name of the symbol mentioned in the declaration+ --+ -- 2) The size (in bytes) of the arguments+ -- the label expects. Only applicable with+ -- @stdcall@ labels. @Just x@ => @\<x\>@ will+ -- be appended to label name when emitting assembly.++ | LitInteger Integer Type -- ^ Integer literals+ -- See Note [Integer literals]+ deriving Data++{-+Note [Integer literals]+~~~~~~~~~~~~~~~~~~~~~~~+An Integer literal is represented using, well, an Integer, to make it+easier to write RULEs for them. They also contain the Integer type, so+that e.g. literalType can return the right Type for them.++They only get converted into real Core,+ mkInteger [c1, c2, .., cn]+during the CorePrep phase, although TidyPgm looks ahead at what the+core will be, so that it can see whether it involves CAFs.++When we initally build an Integer literal, notably when+deserialising it from an interface file (see the Binary instance+below), we don't have convenient access to the mkInteger Id. So we+just use an error thunk, and fill in the real Id when we do tcIfaceLit+in TcIface.+++Binary instance+-}++instance Binary Literal where+ put_ bh (MachChar aa) = do putByte bh 0; put_ bh aa+ put_ bh (MachStr ab) = do putByte bh 1; put_ bh ab+ put_ bh (MachNullAddr) = do putByte bh 2+ put_ bh (MachInt ad) = do putByte bh 3; put_ bh ad+ put_ bh (MachInt64 ae) = do putByte bh 4; put_ bh ae+ put_ bh (MachWord af) = do putByte bh 5; put_ bh af+ put_ bh (MachWord64 ag) = do putByte bh 6; put_ bh ag+ put_ bh (MachFloat ah) = do putByte bh 7; put_ bh ah+ put_ bh (MachDouble ai) = do putByte bh 8; put_ bh ai+ put_ bh (MachLabel aj mb fod)+ = do putByte bh 9+ put_ bh aj+ put_ bh mb+ put_ bh fod+ put_ bh (LitInteger i _) = do putByte bh 10; put_ bh i+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do+ aa <- get bh+ return (MachChar aa)+ 1 -> do+ ab <- get bh+ return (MachStr ab)+ 2 -> do+ return (MachNullAddr)+ 3 -> do+ ad <- get bh+ return (MachInt ad)+ 4 -> do+ ae <- get bh+ return (MachInt64 ae)+ 5 -> do+ af <- get bh+ return (MachWord af)+ 6 -> do+ ag <- get bh+ return (MachWord64 ag)+ 7 -> do+ ah <- get bh+ return (MachFloat ah)+ 8 -> do+ ai <- get bh+ return (MachDouble ai)+ 9 -> do+ aj <- get bh+ mb <- get bh+ fod <- get bh+ return (MachLabel aj mb fod)+ _ -> do+ i <- get bh+ -- See Note [Integer literals]+ return $ mkLitInteger i (panic "Evaluated the place holder for mkInteger")++instance Outputable Literal where+ ppr lit = pprLiteral (\d -> d) lit++instance Eq Literal where+ a == b = case (a `compare` b) of { EQ -> True; _ -> False }+ a /= b = case (a `compare` b) of { EQ -> False; _ -> True }++instance Ord Literal where+ a <= b = case (a `compare` b) of { LT -> True; EQ -> True; GT -> False }+ a < b = case (a `compare` b) of { LT -> True; EQ -> False; GT -> False }+ a >= b = case (a `compare` b) of { LT -> False; EQ -> True; GT -> True }+ a > b = case (a `compare` b) of { LT -> False; EQ -> False; GT -> True }+ compare a b = cmpLit a b++{-+ Construction+ ~~~~~~~~~~~~+-}++-- | Creates a 'Literal' of type @Int#@+mkMachInt :: DynFlags -> Integer -> Literal+mkMachInt dflags x = ASSERT2( inIntRange dflags x, integer x )+ MachInt x++-- | Creates a 'Literal' of type @Int#@.+-- If the argument is out of the (target-dependent) range, it is wrapped.+mkMachIntWrap :: DynFlags -> Integer -> Literal+mkMachIntWrap dflags i+ = MachInt $ case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (fromIntegral i :: Int32)+ 8 -> toInteger (fromIntegral i :: Int64)+ w -> panic ("toIntRange: Unknown platformWordSize: " ++ show w)++-- | Creates a 'Literal' of type @Word#@+mkMachWord :: DynFlags -> Integer -> Literal+mkMachWord dflags x = ASSERT2( inWordRange dflags x, integer x )+ MachWord x++-- | Creates a 'Literal' of type @Word#@.+-- If the argument is out of the (target-dependent) range, it is wrapped.+mkMachWordWrap :: DynFlags -> Integer -> Literal+mkMachWordWrap dflags i+ = MachWord $ case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (fromInteger i :: Word32)+ 8 -> toInteger (fromInteger i :: Word64)+ w -> panic ("toWordRange: Unknown platformWordSize: " ++ show w)++-- | Creates a 'Literal' of type @Int64#@+mkMachInt64 :: Integer -> Literal+mkMachInt64 x = ASSERT2( inInt64Range x, integer x )+ MachInt64 x++-- | Creates a 'Literal' of type @Int64#@.+-- If the argument is out of the range, it is wrapped.+mkMachInt64Wrap :: Integer -> Literal+mkMachInt64Wrap i = MachInt64 (toInteger (fromIntegral i :: Int64))++-- | Creates a 'Literal' of type @Word64#@+mkMachWord64 :: Integer -> Literal+mkMachWord64 x = ASSERT2( inWord64Range x, integer x )+ MachWord64 x++-- | Creates a 'Literal' of type @Word64#@.+-- If the argument is out of the range, it is wrapped.+mkMachWord64Wrap :: Integer -> Literal+mkMachWord64Wrap i = MachWord64 (toInteger (fromIntegral i :: Word64))++-- | Creates a 'Literal' of type @Float#@+mkMachFloat :: Rational -> Literal+mkMachFloat = MachFloat++-- | Creates a 'Literal' of type @Double#@+mkMachDouble :: Rational -> Literal+mkMachDouble = MachDouble++-- | Creates a 'Literal' of type @Char#@+mkMachChar :: Char -> Literal+mkMachChar = MachChar++-- | Creates a 'Literal' of type @Addr#@, which is appropriate for passing to+-- e.g. some of the \"error\" functions in GHC.Err such as @GHC.Err.runtimeError@+mkMachString :: String -> Literal+-- stored UTF-8 encoded+mkMachString s = MachStr (fastStringToByteString $ mkFastString s)++mkLitInteger :: Integer -> Type -> Literal+mkLitInteger = LitInteger++inIntRange, inWordRange :: DynFlags -> Integer -> Bool+inIntRange dflags x = x >= tARGET_MIN_INT dflags && x <= tARGET_MAX_INT dflags+inWordRange dflags x = x >= 0 && x <= tARGET_MAX_WORD dflags++inInt64Range, inWord64Range :: Integer -> Bool+inInt64Range x = x >= toInteger (minBound :: Int64) &&+ x <= toInteger (maxBound :: Int64)+inWord64Range x = x >= toInteger (minBound :: Word64) &&+ x <= toInteger (maxBound :: Word64)++inCharRange :: Char -> Bool+inCharRange c = c >= '\0' && c <= chr tARGET_MAX_CHAR++-- | Tests whether the literal represents a zero of whatever type it is+isZeroLit :: Literal -> Bool+isZeroLit (MachInt 0) = True+isZeroLit (MachInt64 0) = True+isZeroLit (MachWord 0) = True+isZeroLit (MachWord64 0) = True+isZeroLit (MachFloat 0) = True+isZeroLit (MachDouble 0) = True+isZeroLit _ = False++-- | Returns the 'Integer' contained in the 'Literal', for when that makes+-- sense, i.e. for 'Char', 'Int', 'Word' and 'LitInteger'.+litValue :: Literal -> Integer+litValue l = case isLitValue_maybe l of+ Just x -> x+ Nothing -> pprPanic "litValue" (ppr l)++-- | Returns the 'Integer' contained in the 'Literal', for when that makes+-- sense, i.e. for 'Char', 'Int', 'Word' and 'LitInteger'.+isLitValue_maybe :: Literal -> Maybe Integer+isLitValue_maybe (MachChar c) = Just $ toInteger $ ord c+isLitValue_maybe (MachInt i) = Just i+isLitValue_maybe (MachInt64 i) = Just i+isLitValue_maybe (MachWord i) = Just i+isLitValue_maybe (MachWord64 i) = Just i+isLitValue_maybe (LitInteger i _) = Just i+isLitValue_maybe _ = Nothing++-- | Apply a function to the 'Integer' contained in the 'Literal', for when that+-- makes sense, e.g. for 'Char', 'Int', 'Word' and 'LitInteger'. For+-- fixed-size integral literals, the result will be wrapped in+-- accordance with the semantics of the target type.+mapLitValue :: DynFlags -> (Integer -> Integer) -> Literal -> Literal+mapLitValue _ f (MachChar c) = mkMachChar (fchar c)+ where fchar = chr . fromInteger . f . toInteger . ord+mapLitValue dflags f (MachInt i) = mkMachIntWrap dflags (f i)+mapLitValue _ f (MachInt64 i) = mkMachInt64Wrap (f i)+mapLitValue dflags f (MachWord i) = mkMachWordWrap dflags (f i)+mapLitValue _ f (MachWord64 i) = mkMachWord64Wrap (f i)+mapLitValue _ f (LitInteger i t) = mkLitInteger (f i) t+mapLitValue _ _ l = pprPanic "mapLitValue" (ppr l)++-- | Indicate if the `Literal` contains an 'Integer' value, e.g. 'Char',+-- 'Int', 'Word' and 'LitInteger'.+isLitValue :: Literal -> Bool+isLitValue = isJust . isLitValue_maybe++{-+ Coercions+ ~~~~~~~~~+-}++narrow8IntLit, narrow16IntLit, narrow32IntLit,+ narrow8WordLit, narrow16WordLit, narrow32WordLit,+ char2IntLit, int2CharLit,+ float2IntLit, int2FloatLit, double2IntLit, int2DoubleLit,+ float2DoubleLit, double2FloatLit+ :: Literal -> Literal++word2IntLit, int2WordLit :: DynFlags -> Literal -> Literal+word2IntLit dflags (MachWord w)+ | w > tARGET_MAX_INT dflags = MachInt (w - tARGET_MAX_WORD dflags - 1)+ | otherwise = MachInt w+word2IntLit _ l = pprPanic "word2IntLit" (ppr l)++int2WordLit dflags (MachInt i)+ | i < 0 = MachWord (1 + tARGET_MAX_WORD dflags + i) -- (-1) ---> tARGET_MAX_WORD+ | otherwise = MachWord i+int2WordLit _ l = pprPanic "int2WordLit" (ppr l)++narrow8IntLit (MachInt i) = MachInt (toInteger (fromInteger i :: Int8))+narrow8IntLit l = pprPanic "narrow8IntLit" (ppr l)+narrow16IntLit (MachInt i) = MachInt (toInteger (fromInteger i :: Int16))+narrow16IntLit l = pprPanic "narrow16IntLit" (ppr l)+narrow32IntLit (MachInt i) = MachInt (toInteger (fromInteger i :: Int32))+narrow32IntLit l = pprPanic "narrow32IntLit" (ppr l)+narrow8WordLit (MachWord w) = MachWord (toInteger (fromInteger w :: Word8))+narrow8WordLit l = pprPanic "narrow8WordLit" (ppr l)+narrow16WordLit (MachWord w) = MachWord (toInteger (fromInteger w :: Word16))+narrow16WordLit l = pprPanic "narrow16WordLit" (ppr l)+narrow32WordLit (MachWord w) = MachWord (toInteger (fromInteger w :: Word32))+narrow32WordLit l = pprPanic "narrow32WordLit" (ppr l)++char2IntLit (MachChar c) = MachInt (toInteger (ord c))+char2IntLit l = pprPanic "char2IntLit" (ppr l)+int2CharLit (MachInt i) = MachChar (chr (fromInteger i))+int2CharLit l = pprPanic "int2CharLit" (ppr l)++float2IntLit (MachFloat f) = MachInt (truncate f)+float2IntLit l = pprPanic "float2IntLit" (ppr l)+int2FloatLit (MachInt i) = MachFloat (fromInteger i)+int2FloatLit l = pprPanic "int2FloatLit" (ppr l)++double2IntLit (MachDouble f) = MachInt (truncate f)+double2IntLit l = pprPanic "double2IntLit" (ppr l)+int2DoubleLit (MachInt i) = MachDouble (fromInteger i)+int2DoubleLit l = pprPanic "int2DoubleLit" (ppr l)++float2DoubleLit (MachFloat f) = MachDouble f+float2DoubleLit l = pprPanic "float2DoubleLit" (ppr l)+double2FloatLit (MachDouble d) = MachFloat d+double2FloatLit l = pprPanic "double2FloatLit" (ppr l)++nullAddrLit :: Literal+nullAddrLit = MachNullAddr++{-+ Predicates+ ~~~~~~~~~~+-}++-- | True if there is absolutely no penalty to duplicating the literal.+-- False principally of strings.+--+-- "Why?", you say? I'm glad you asked. Well, for one duplicating strings would+-- blow up code sizes. Not only this, it's also unsafe.+--+-- Consider a program that wants to traverse a string. One way it might do this+-- is to first compute the Addr# pointing to the end of the string, and then,+-- starting from the beginning, bump a pointer using eqAddr# to determine the+-- end. For instance,+--+-- @+-- -- Given pointers to the start and end of a string, count how many zeros+-- -- the string contains.+-- countZeros :: Addr# -> Addr# -> -> Int+-- countZeros start end = go start 0+-- where+-- go off n+-- | off `addrEq#` end = n+-- | otherwise = go (off `plusAddr#` 1) n'+-- where n' | isTrue# (indexInt8OffAddr# off 0# ==# 0#) = n + 1+-- | otherwise = n+-- @+--+-- Consider what happens if we considered strings to be trivial (and therefore+-- duplicable) and emitted a call like @countZeros "hello"# ("hello"#+-- `plusAddr`# 5)@. The beginning and end pointers do not belong to the same+-- string, meaning that an iteration like the above would blow up terribly.+-- This is what happened in #12757.+--+-- Ultimately the solution here is to make primitive strings a bit more+-- structured, ensuring that the compiler can't inline in ways that will break+-- user code. One approach to this is described in #8472.+litIsTrivial :: Literal -> Bool+-- c.f. CoreUtils.exprIsTrivial+litIsTrivial (MachStr _) = False+litIsTrivial (LitInteger {}) = False+litIsTrivial _ = True++-- | True if code space does not go bad if we duplicate this literal+-- Currently we treat it just like 'litIsTrivial'+litIsDupable :: DynFlags -> Literal -> Bool+-- c.f. CoreUtils.exprIsDupable+litIsDupable _ (MachStr _) = False+litIsDupable dflags (LitInteger i _) = inIntRange dflags i+litIsDupable _ _ = True++litFitsInChar :: Literal -> Bool+litFitsInChar (MachInt i) = i >= toInteger (ord minBound)+ && i <= toInteger (ord maxBound)+litFitsInChar _ = False++litIsLifted :: Literal -> Bool+litIsLifted (LitInteger {}) = True+litIsLifted _ = False++{-+ Types+ ~~~~~+-}++-- | Find the Haskell 'Type' the literal occupies+literalType :: Literal -> Type+literalType MachNullAddr = addrPrimTy+literalType (MachChar _) = charPrimTy+literalType (MachStr _) = addrPrimTy+literalType (MachInt _) = intPrimTy+literalType (MachWord _) = wordPrimTy+literalType (MachInt64 _) = int64PrimTy+literalType (MachWord64 _) = word64PrimTy+literalType (MachFloat _) = floatPrimTy+literalType (MachDouble _) = doublePrimTy+literalType (MachLabel _ _ _) = addrPrimTy+literalType (LitInteger _ t) = t++absentLiteralOf :: TyCon -> Maybe Literal+-- Return a literal of the appropriate primtive+-- TyCon, to use as a placeholder when it doesn't matter+absentLiteralOf tc = lookupUFM absent_lits (tyConName tc)++absent_lits :: UniqFM Literal+absent_lits = listToUFM [ (addrPrimTyConKey, MachNullAddr)+ , (charPrimTyConKey, MachChar 'x')+ , (intPrimTyConKey, MachInt 0)+ , (int64PrimTyConKey, MachInt64 0)+ , (floatPrimTyConKey, MachFloat 0)+ , (doublePrimTyConKey, MachDouble 0)+ , (wordPrimTyConKey, MachWord 0)+ , (word64PrimTyConKey, MachWord64 0) ]++{-+ Comparison+ ~~~~~~~~~~+-}++cmpLit :: Literal -> Literal -> Ordering+cmpLit (MachChar a) (MachChar b) = a `compare` b+cmpLit (MachStr a) (MachStr b) = a `compare` b+cmpLit (MachNullAddr) (MachNullAddr) = EQ+cmpLit (MachInt a) (MachInt b) = a `compare` b+cmpLit (MachWord a) (MachWord b) = a `compare` b+cmpLit (MachInt64 a) (MachInt64 b) = a `compare` b+cmpLit (MachWord64 a) (MachWord64 b) = a `compare` b+cmpLit (MachFloat a) (MachFloat b) = a `compare` b+cmpLit (MachDouble a) (MachDouble b) = a `compare` b+cmpLit (MachLabel a _ _) (MachLabel b _ _) = a `compare` b+cmpLit (LitInteger a _) (LitInteger b _) = a `compare` b+cmpLit lit1 lit2 | litTag lit1 < litTag lit2 = LT+ | otherwise = GT++litTag :: Literal -> Int+litTag (MachChar _) = 1+litTag (MachStr _) = 2+litTag (MachNullAddr) = 3+litTag (MachInt _) = 4+litTag (MachWord _) = 5+litTag (MachInt64 _) = 6+litTag (MachWord64 _) = 7+litTag (MachFloat _) = 8+litTag (MachDouble _) = 9+litTag (MachLabel _ _ _) = 10+litTag (LitInteger {}) = 11++{-+ Printing+ ~~~~~~~~+* See Note [Printing of literals in Core]+-}++pprLiteral :: (SDoc -> SDoc) -> Literal -> SDoc+pprLiteral _ (MachChar c) = pprPrimChar c+pprLiteral _ (MachStr s) = pprHsBytes s+pprLiteral _ (MachNullAddr) = text "__NULL"+pprLiteral _ (MachInt i) = pprPrimInt i+pprLiteral _ (MachInt64 i) = pprPrimInt64 i+pprLiteral _ (MachWord w) = pprPrimWord w+pprLiteral _ (MachWord64 w) = pprPrimWord64 w+pprLiteral _ (MachFloat f) = float (fromRat f) <> primFloatSuffix+pprLiteral _ (MachDouble d) = double (fromRat d) <> primDoubleSuffix+pprLiteral add_par (LitInteger i _) = pprIntegerVal add_par i+pprLiteral add_par (MachLabel l mb fod) = add_par (text "__label" <+> b <+> ppr fod)+ where b = case mb of+ Nothing -> pprHsString l+ Just x -> doubleQuotes (text (unpackFS l ++ '@':show x))++pprIntegerVal :: (SDoc -> SDoc) -> Integer -> SDoc+-- See Note [Printing of literals in Core].+pprIntegerVal add_par i | i < 0 = add_par (integer i)+ | otherwise = integer i++{-+Note [Printing of literals in Core]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The function `add_par` is used to wrap parenthesis around negative integers+(`LitInteger`) and labels (`MachLabel`), if they occur in a context requiring+an atomic thing (for example function application).++Although not all Core literals would be valid Haskell, we are trying to stay+as close as possible to Haskell syntax in the printing of Core, to make it+easier for a Haskell user to read Core.++To that end:+ * We do print parenthesis around negative `LitInteger`, because we print+ `LitInteger` using plain number literals (no prefix or suffix), and plain+ number literals in Haskell require parenthesis in contexts like function+ application (i.e. `1 - -1` is not valid Haskell).++ * We don't print parenthesis around other (negative) literals, because they+ aren't needed in GHC/Haskell either (i.e. `1# -# -1#` is accepted by GHC's+ parser).++Literal Output Output if context requires+ an atom (if different)+------- ------- ----------------------+MachChar 'a'#+MachStr "aaa"#+MachNullAddr "__NULL"+MachInt -1#+MachInt64 -1L#+MachWord 1##+MachWord64 1L##+MachFloat -1.0#+MachDouble -1.0##+LitInteger -1 (-1)+MachLabel "__label" ... ("__label" ...)+-}
+ basicTypes/MkId.hs view
@@ -0,0 +1,1570 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1998+++This module contains definitions for the IdInfo for things that+have a standard form, namely:++- data constructors+- record selectors+- method and superclass selectors+- primitive operations+-}++{-# LANGUAGE CPP #-}++module MkId (+ mkDictFunId, mkDictFunTy, mkDictSelId, mkDictSelRhs,++ mkPrimOpId, mkFCallId,++ wrapNewTypeBody, unwrapNewTypeBody,+ wrapFamInstBody, unwrapFamInstScrut,+ wrapTypeUnbranchedFamInstBody, unwrapTypeUnbranchedFamInstScrut,++ DataConBoxer(..), mkDataConRep, mkDataConWorkId,++ -- And some particular Ids; see below for why they are wired in+ wiredInIds, ghcPrimIds,+ unsafeCoerceName, unsafeCoerceId, realWorldPrimId,+ voidPrimId, voidArgId,+ nullAddrId, seqId, lazyId, lazyIdKey, runRWId,+ coercionTokenId, magicDictId, coerceId,+ proxyHashId, noinlineId, noinlineIdName,++ -- Re-export error Ids+ module PrelRules+ ) where++#include "HsVersions.h"++import Rules+import TysPrim+import TysWiredIn+import PrelRules+import Type+import FamInstEnv+import Coercion+import TcType+import MkCore+import CoreUtils ( exprType, mkCast )+import CoreUnfold+import Literal+import TyCon+import CoAxiom+import Class+import NameSet+import Name+import PrimOp+import ForeignCall+import DataCon+import Id+import IdInfo+import Demand+import CoreSyn+import Unique+import UniqSupply+import PrelNames+import BasicTypes hiding ( SuccessFlag(..) )+import Util+import Pair+import DynFlags+import Outputable+import FastString+import ListSetOps+import qualified GHC.LanguageExtensions as LangExt++import Data.Maybe ( maybeToList )++{-+************************************************************************+* *+\subsection{Wired in Ids}+* *+************************************************************************++Note [Wired-in Ids]+~~~~~~~~~~~~~~~~~~~+There are several reasons why an Id might appear in the wiredInIds:++(1) The ghcPrimIds are wired in because they can't be defined in+ Haskell at all, although the can be defined in Core. They have+ compulsory unfoldings, so they are always inlined and they have+ no definition site. Their home module is GHC.Prim, so they+ also have a description in primops.txt.pp, where they are called+ 'pseudoops'.++(2) The 'error' function, eRROR_ID, is wired in because we don't yet have+ a way to express in an interface file that the result type variable+ is 'open'; that is can be unified with an unboxed type++ [The interface file format now carry such information, but there's+ no way yet of expressing at the definition site for these+ error-reporting functions that they have an 'open'+ result type. -- sof 1/99]++(3) Other error functions (rUNTIME_ERROR_ID) are wired in (a) because+ the desugarer generates code that mentions them directly, and+ (b) for the same reason as eRROR_ID++(4) lazyId is wired in because the wired-in version overrides the+ strictness of the version defined in GHC.Base++(5) noinlineId is wired in because when we serialize to interfaces+ we may insert noinline statements.++In cases (2-4), the function has a definition in a library module, and+can be called; but the wired-in version means that the details are+never read from that module's interface file; instead, the full definition+is right here.+-}++wiredInIds :: [Id]+wiredInIds+ = [lazyId, dollarId, oneShotId, runRWId, noinlineId]+ ++ errorIds -- Defined in MkCore+ ++ ghcPrimIds++-- These Ids are exported from GHC.Prim+ghcPrimIds :: [Id]+ghcPrimIds+ = [ -- These can't be defined in Haskell, but they have+ -- perfectly reasonable unfoldings in Core+ realWorldPrimId,+ voidPrimId,+ unsafeCoerceId,+ nullAddrId,+ seqId,+ magicDictId,+ coerceId,+ proxyHashId+ ]++{-+************************************************************************+* *+\subsection{Data constructors}+* *+************************************************************************++The wrapper for a constructor is an ordinary top-level binding that evaluates+any strict args, unboxes any args that are going to be flattened, and calls+the worker.++We're going to build a constructor that looks like:++ data (Data a, C b) => T a b = T1 !a !Int b++ T1 = /\ a b ->+ \d1::Data a, d2::C b ->+ \p q r -> case p of { p ->+ case q of { q ->+ Con T1 [a,b] [p,q,r]}}++Notice that++* d2 is thrown away --- a context in a data decl is used to make sure+ one *could* construct dictionaries at the site the constructor+ is used, but the dictionary isn't actually used.++* We have to check that we can construct Data dictionaries for+ the types a and Int. Once we've done that we can throw d1 away too.++* We use (case p of q -> ...) to evaluate p, rather than "seq" because+ all that matters is that the arguments are evaluated. "seq" is+ very careful to preserve evaluation order, which we don't need+ to be here.++ You might think that we could simply give constructors some strictness+ info, like PrimOps, and let CoreToStg do the let-to-case transformation.+ But we don't do that because in the case of primops and functions strictness+ is a *property* not a *requirement*. In the case of constructors we need to+ do something active to evaluate the argument.++ Making an explicit case expression allows the simplifier to eliminate+ it in the (common) case where the constructor arg is already evaluated.++Note [Wrappers for data instance tycons]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the case of data instances, the wrapper also applies the coercion turning+the representation type into the family instance type to cast the result of+the wrapper. For example, consider the declarations++ data family Map k :: * -> *+ data instance Map (a, b) v = MapPair (Map a (Pair b v))++The tycon to which the datacon MapPair belongs gets a unique internal+name of the form :R123Map, and we call it the representation tycon.+In contrast, Map is the family tycon (accessible via+tyConFamInst_maybe). A coercion allows you to move between+representation and family type. It is accessible from :R123Map via+tyConFamilyCoercion_maybe and has kind++ Co123Map a b v :: {Map (a, b) v ~ :R123Map a b v}++The wrapper and worker of MapPair get the types++ -- Wrapper+ $WMapPair :: forall a b v. Map a (Map a b v) -> Map (a, b) v+ $WMapPair a b v = MapPair a b v `cast` sym (Co123Map a b v)++ -- Worker+ MapPair :: forall a b v. Map a (Map a b v) -> :R123Map a b v++This coercion is conditionally applied by wrapFamInstBody.++It's a bit more complicated if the data instance is a GADT as well!++ data instance T [a] where+ T1 :: forall b. b -> T [Maybe b]++Hence we translate to++ -- Wrapper+ $WT1 :: forall b. b -> T [Maybe b]+ $WT1 b v = T1 (Maybe b) b (Maybe b) v+ `cast` sym (Co7T (Maybe b))++ -- Worker+ T1 :: forall c b. (c ~ Maybe b) => b -> :R7T c++ -- Coercion from family type to representation type+ Co7T a :: T [a] ~ :R7T a++Note [Newtype datacons]+~~~~~~~~~~~~~~~~~~~~~~~+The "data constructor" for a newtype should always be vanilla. At one+point this wasn't true, because the newtype arising from+ class C a => D a+looked like+ newtype T:D a = D:D (C a)+so the data constructor for T:C had a single argument, namely the+predicate (C a). But now we treat that as an ordinary argument, not+part of the theta-type, so all is well.+++************************************************************************+* *+\subsection{Dictionary selectors}+* *+************************************************************************++Selecting a field for a dictionary. If there is just one field, then+there's nothing to do.++Dictionary selectors may get nested forall-types. Thus:++ class Foo a where+ op :: forall b. Ord b => a -> b -> b++Then the top-level type for op is++ op :: forall a. Foo a =>+ forall b. Ord b =>+ a -> b -> b++-}++mkDictSelId :: Name -- Name of one of the *value* selectors+ -- (dictionary superclass or method)+ -> Class -> Id+mkDictSelId name clas+ = mkGlobalId (ClassOpId clas) name sel_ty info+ where+ tycon = classTyCon clas+ sel_names = map idName (classAllSelIds clas)+ new_tycon = isNewTyCon tycon+ [data_con] = tyConDataCons tycon+ tyvars = dataConUnivTyVarBinders data_con+ n_ty_args = length tyvars+ arg_tys = dataConRepArgTys data_con -- Includes the dictionary superclasses+ val_index = assoc "MkId.mkDictSelId" (sel_names `zip` [0..]) name++ sel_ty = mkForAllTys tyvars $+ mkFunTy (mkClassPred clas (mkTyVarTys (binderVars tyvars))) $+ getNth arg_tys val_index++ base_info = noCafIdInfo+ `setArityInfo` 1+ `setStrictnessInfo` strict_sig+ `setLevityInfoWithType` sel_ty++ info | new_tycon+ = base_info `setInlinePragInfo` alwaysInlinePragma+ `setUnfoldingInfo` mkInlineUnfoldingWithArity 1+ (mkDictSelRhs clas val_index)+ -- See Note [Single-method classes] in TcInstDcls+ -- for why alwaysInlinePragma++ | otherwise+ = base_info `setRuleInfo` mkRuleInfo [rule]+ -- Add a magic BuiltinRule, but no unfolding+ -- so that the rule is always available to fire.+ -- See Note [ClassOp/DFun selection] in TcInstDcls++ -- This is the built-in rule that goes+ -- op (dfT d1 d2) ---> opT d1 d2+ rule = BuiltinRule { ru_name = fsLit "Class op " `appendFS`+ occNameFS (getOccName name)+ , ru_fn = name+ , ru_nargs = n_ty_args + 1+ , ru_try = dictSelRule val_index n_ty_args }++ -- The strictness signature is of the form U(AAAVAAAA) -> T+ -- where the V depends on which item we are selecting+ -- It's worth giving one, so that absence info etc is generated+ -- even if the selector isn't inlined++ strict_sig = mkClosedStrictSig [arg_dmd] topRes+ arg_dmd | new_tycon = evalDmd+ | otherwise = mkManyUsedDmd $+ mkProdDmd [ if name == sel_name then evalDmd else absDmd+ | sel_name <- sel_names ]++mkDictSelRhs :: Class+ -> Int -- 0-indexed selector among (superclasses ++ methods)+ -> CoreExpr+mkDictSelRhs clas val_index+ = mkLams tyvars (Lam dict_id rhs_body)+ where+ tycon = classTyCon clas+ new_tycon = isNewTyCon tycon+ [data_con] = tyConDataCons tycon+ tyvars = dataConUnivTyVars data_con+ arg_tys = dataConRepArgTys data_con -- Includes the dictionary superclasses++ the_arg_id = getNth arg_ids val_index+ pred = mkClassPred clas (mkTyVarTys tyvars)+ dict_id = mkTemplateLocal 1 pred+ arg_ids = mkTemplateLocalsNum 2 arg_tys++ rhs_body | new_tycon = unwrapNewTypeBody tycon (mkTyVarTys tyvars) (Var dict_id)+ | otherwise = Case (Var dict_id) dict_id (idType the_arg_id)+ [(DataAlt data_con, arg_ids, varToCoreExpr the_arg_id)]+ -- varToCoreExpr needed for equality superclass selectors+ -- sel a b d = case x of { MkC _ (g:a~b) _ -> CO g }++dictSelRule :: Int -> Arity -> RuleFun+-- Tries to persuade the argument to look like a constructor+-- application, using exprIsConApp_maybe, and then selects+-- from it+-- sel_i t1..tk (D t1..tk op1 ... opm) = opi+--+dictSelRule val_index n_ty_args _ id_unf _ args+ | (dict_arg : _) <- drop n_ty_args args+ , Just (_, _, con_args) <- exprIsConApp_maybe id_unf dict_arg+ = Just (getNth con_args val_index)+ | otherwise+ = Nothing++{-+************************************************************************+* *+ Data constructors+* *+************************************************************************+-}++mkDataConWorkId :: Name -> DataCon -> Id+mkDataConWorkId wkr_name data_con+ | isNewTyCon tycon+ = mkGlobalId (DataConWrapId data_con) wkr_name nt_wrap_ty nt_work_info+ | otherwise+ = mkGlobalId (DataConWorkId data_con) wkr_name alg_wkr_ty wkr_info++ where+ tycon = dataConTyCon data_con++ ----------- Workers for data types --------------+ alg_wkr_ty = dataConRepType data_con+ wkr_arity = dataConRepArity data_con+ wkr_info = noCafIdInfo+ `setArityInfo` wkr_arity+ `setStrictnessInfo` wkr_sig+ `setUnfoldingInfo` evaldUnfolding -- Record that it's evaluated,+ -- even if arity = 0+ `setLevityInfoWithType` alg_wkr_ty+ -- NB: unboxed tuples have workers, so we can't use+ -- setNeverLevPoly++ wkr_sig = mkClosedStrictSig (replicate wkr_arity topDmd) (dataConCPR data_con)+ -- Note [Data-con worker strictness]+ -- Notice that we do *not* say the worker is strict+ -- even if the data constructor is declared strict+ -- e.g. data T = MkT !(Int,Int)+ -- Why? Because the *wrapper* is strict (and its unfolding has case+ -- expressions that do the evals) but the *worker* itself is not.+ -- If we pretend it is strict then when we see+ -- case x of y -> $wMkT y+ -- the simplifier thinks that y is "sure to be evaluated" (because+ -- $wMkT is strict) and drops the case. No, $wMkT is not strict.+ --+ -- When the simplifier sees a pattern+ -- case e of MkT x -> ...+ -- it uses the dataConRepStrictness of MkT to mark x as evaluated;+ -- but that's fine... dataConRepStrictness comes from the data con+ -- not from the worker Id.++ ----------- Workers for newtypes --------------+ (nt_tvs, _, nt_arg_tys, _) = dataConSig data_con+ res_ty_args = mkTyVarTys nt_tvs+ nt_wrap_ty = dataConUserType data_con+ nt_work_info = noCafIdInfo -- The NoCaf-ness is set by noCafIdInfo+ `setArityInfo` 1 -- Arity 1+ `setInlinePragInfo` alwaysInlinePragma+ `setUnfoldingInfo` newtype_unf+ `setLevityInfoWithType` nt_wrap_ty+ id_arg1 = mkTemplateLocal 1 (head nt_arg_tys)+ newtype_unf = ASSERT2( isVanillaDataCon data_con &&+ isSingleton nt_arg_tys, ppr data_con )+ -- Note [Newtype datacons]+ mkCompulsoryUnfolding $+ mkLams nt_tvs $ Lam id_arg1 $+ wrapNewTypeBody tycon res_ty_args (Var id_arg1)++dataConCPR :: DataCon -> DmdResult+dataConCPR con+ | isDataTyCon tycon -- Real data types only; that is,+ -- not unboxed tuples or newtypes+ , null (dataConExTyVars con) -- No existentials+ , wkr_arity > 0+ , wkr_arity <= mAX_CPR_SIZE+ = if is_prod then vanillaCprProdRes (dataConRepArity con)+ else cprSumRes (dataConTag con)+ | otherwise+ = topRes+ where+ is_prod = isProductTyCon tycon+ tycon = dataConTyCon con+ wkr_arity = dataConRepArity con++ mAX_CPR_SIZE :: Arity+ mAX_CPR_SIZE = 10+ -- We do not treat very big tuples as CPR-ish:+ -- a) for a start we get into trouble because there aren't+ -- "enough" unboxed tuple types (a tiresome restriction,+ -- but hard to fix),+ -- b) more importantly, big unboxed tuples get returned mainly+ -- on the stack, and are often then allocated in the heap+ -- by the caller. So doing CPR for them may in fact make+ -- things worse.++{-+-------------------------------------------------+-- Data constructor representation+--+-- This is where we decide how to wrap/unwrap the+-- constructor fields+--+--------------------------------------------------+-}++type Unboxer = Var -> UniqSM ([Var], CoreExpr -> CoreExpr)+ -- Unbox: bind rep vars by decomposing src var++data Boxer = UnitBox | Boxer (TCvSubst -> UniqSM ([Var], CoreExpr))+ -- Box: build src arg using these rep vars++-- | Data Constructor Boxer+newtype DataConBoxer = DCB ([Type] -> [Var] -> UniqSM ([Var], [CoreBind]))+ -- Bind these src-level vars, returning the+ -- rep-level vars to bind in the pattern++{-+Note [Inline partially-applied constructor wrappers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We allow the wrapper to inline when partially applied to avoid+boxing values unnecessarily. For example, consider++ data Foo a = Foo !Int a++ instance Traversable Foo where+ traverse f (Foo i a) = Foo i <$> f a++This desugars to++ traverse f foo = case foo of+ Foo i# a -> let i = I# i#+ in map ($WFoo i) (f a)++If the wrapper `$WFoo` is not inlined, we get a fruitless reboxing of `i`.+But if we inline the wrapper, we get++ map (\a. case i of I# i# a -> Foo i# a) (f a)++and now case-of-known-constructor eliminates the redundant allocation.+-}++mkDataConRep :: DynFlags+ -> FamInstEnvs+ -> Name+ -> Maybe [HsImplBang]+ -- See Note [Bangs on imported data constructors]+ -> DataCon+ -> UniqSM DataConRep+mkDataConRep dflags fam_envs wrap_name mb_bangs data_con+ | not wrapper_reqd+ = return NoDataConRep++ | otherwise+ = do { wrap_args <- mapM newLocal wrap_arg_tys+ ; wrap_body <- mk_rep_app (wrap_args `zip` dropList eq_spec unboxers)+ initial_wrap_app++ ; let wrap_id = mkGlobalId (DataConWrapId data_con) wrap_name wrap_ty wrap_info+ wrap_info = noCafIdInfo+ `setArityInfo` wrap_arity+ -- It's important to specify the arity, so that partial+ -- applications are treated as values+ `setInlinePragInfo` wrap_prag+ `setUnfoldingInfo` wrap_unf+ `setStrictnessInfo` wrap_sig+ -- We need to get the CAF info right here because TidyPgm+ -- does not tidy the IdInfo of implicit bindings (like the wrapper)+ -- so it not make sure that the CAF info is sane+ `setNeverLevPoly` wrap_ty++ wrap_sig = mkClosedStrictSig wrap_arg_dmds (dataConCPR data_con)++ wrap_arg_dmds = map mk_dmd arg_ibangs+ mk_dmd str | isBanged str = evalDmd+ | otherwise = topDmd++ wrap_prag = alwaysInlinePragma `setInlinePragmaActivation`+ ActiveAfter NoSourceText 2+ -- See Note [Activation for data constructor wrappers]++ -- The wrapper will usually be inlined (see wrap_unf), so its+ -- strictness and CPR info is usually irrelevant. But this is+ -- not always the case; GHC may choose not to inline it. In+ -- particular, the wrapper constructor is not inlined inside+ -- an INLINE rhs or when it is not applied to any arguments.+ -- See Note [Inline partially-applied constructor wrappers]+ -- Passing Nothing here allows the wrapper to inline when+ -- unsaturated.+ wrap_unf = mkInlineUnfolding wrap_rhs+ wrap_tvs = (univ_tvs `minusList` map eqSpecTyVar eq_spec) ++ ex_tvs+ wrap_rhs = mkLams wrap_tvs $+ mkLams wrap_args $+ wrapFamInstBody tycon res_ty_args $+ wrap_body++ ; return (DCR { dcr_wrap_id = wrap_id+ , dcr_boxer = mk_boxer boxers+ , dcr_arg_tys = rep_tys+ , dcr_stricts = rep_strs+ , dcr_bangs = arg_ibangs }) }++ where+ (univ_tvs, ex_tvs, eq_spec, theta, orig_arg_tys, _orig_res_ty)+ = dataConFullSig data_con+ res_ty_args = substTyVars (mkTvSubstPrs (map eqSpecPair eq_spec)) univ_tvs++ tycon = dataConTyCon data_con -- The representation TyCon (not family)+ wrap_ty = dataConUserType data_con+ ev_tys = eqSpecPreds eq_spec ++ theta+ all_arg_tys = ev_tys ++ orig_arg_tys+ ev_ibangs = map (const HsLazy) ev_tys+ orig_bangs = dataConSrcBangs data_con++ wrap_arg_tys = theta ++ orig_arg_tys+ wrap_arity = length wrap_arg_tys+ -- The wrap_args are the arguments *other than* the eq_spec+ -- Because we are going to apply the eq_spec args manually in the+ -- wrapper++ arg_ibangs =+ case mb_bangs of+ Nothing -> zipWith (dataConSrcToImplBang dflags fam_envs)+ orig_arg_tys orig_bangs+ Just bangs -> bangs++ (rep_tys_w_strs, wrappers)+ = unzip (zipWith dataConArgRep all_arg_tys (ev_ibangs ++ arg_ibangs))++ (unboxers, boxers) = unzip wrappers+ (rep_tys, rep_strs) = unzip (concat rep_tys_w_strs)++ wrapper_reqd = not (isNewTyCon tycon) -- Newtypes have only a worker+ && (any isBanged (ev_ibangs ++ arg_ibangs)+ -- Some forcing/unboxing (includes eq_spec)+ || isFamInstTyCon tycon -- Cast result+ || (not $ null eq_spec)) -- GADT++ initial_wrap_app = Var (dataConWorkId data_con)+ `mkTyApps` res_ty_args+ `mkVarApps` ex_tvs+ `mkCoApps` map (mkReflCo Nominal . eqSpecType) eq_spec++ mk_boxer :: [Boxer] -> DataConBoxer+ mk_boxer boxers = DCB (\ ty_args src_vars ->+ do { let (ex_vars, term_vars) = splitAtList ex_tvs src_vars+ subst1 = zipTvSubst univ_tvs ty_args+ subst2 = extendTvSubstList subst1 ex_tvs+ (mkTyVarTys ex_vars)+ ; (rep_ids, binds) <- go subst2 boxers term_vars+ ; return (ex_vars ++ rep_ids, binds) } )++ go _ [] src_vars = ASSERT2( null src_vars, ppr data_con ) return ([], [])+ go subst (UnitBox : boxers) (src_var : src_vars)+ = do { (rep_ids2, binds) <- go subst boxers src_vars+ ; return (src_var : rep_ids2, binds) }+ go subst (Boxer boxer : boxers) (src_var : src_vars)+ = do { (rep_ids1, arg) <- boxer subst+ ; (rep_ids2, binds) <- go subst boxers src_vars+ ; return (rep_ids1 ++ rep_ids2, NonRec src_var arg : binds) }+ go _ (_:_) [] = pprPanic "mk_boxer" (ppr data_con)++ mk_rep_app :: [(Id,Unboxer)] -> CoreExpr -> UniqSM CoreExpr+ mk_rep_app [] con_app+ = return con_app+ mk_rep_app ((wrap_arg, unboxer) : prs) con_app+ = do { (rep_ids, unbox_fn) <- unboxer wrap_arg+ ; expr <- mk_rep_app prs (mkVarApps con_app rep_ids)+ ; return (unbox_fn expr) }++{- Note [Activation for data constructor wrappers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The Activation on a data constructor wrapper allows it to inline in+Phase 2 and later (1, 0). But not in the InitialPhase. That gives+rewrite rules a chance to fire (in the InitialPhase) if they mention+a data constructor on the left+ RULE "foo" f (K a b) = ...+Since the LHS of rules are simplified with InitialPhase, we won't+inline the wrapper on the LHS either.++People have asked for this before, but now that even the InitialPhase+does some inlining, it has become important.+++Note [Bangs on imported data constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We pass Maybe [HsImplBang] to mkDataConRep to make use of HsImplBangs+from imported modules.++- Nothing <=> use HsSrcBangs+- Just bangs <=> use HsImplBangs++For imported types we can't work it all out from the HsSrcBangs,+because we want to be very sure to follow what the original module+(where the data type was declared) decided, and that depends on what+flags were enabled when it was compiled. So we record the decisions in+the interface file.++The HsImplBangs passed are in 1-1 correspondence with the+dataConOrigArgTys of the DataCon.++-}++-------------------------+newLocal :: Type -> UniqSM Var+newLocal ty = do { uniq <- getUniqueM+ ; return (mkSysLocalOrCoVar (fsLit "dt") uniq ty) }++-- | Unpack/Strictness decisions from source module+dataConSrcToImplBang+ :: DynFlags+ -> FamInstEnvs+ -> Type+ -> HsSrcBang+ -> HsImplBang++dataConSrcToImplBang dflags fam_envs arg_ty+ (HsSrcBang ann unpk NoSrcStrict)+ | xopt LangExt.StrictData dflags -- StrictData => strict field+ = dataConSrcToImplBang dflags fam_envs arg_ty+ (HsSrcBang ann unpk SrcStrict)+ | otherwise -- no StrictData => lazy field+ = HsLazy++dataConSrcToImplBang _ _ _ (HsSrcBang _ _ SrcLazy)+ = HsLazy++dataConSrcToImplBang dflags fam_envs arg_ty+ (HsSrcBang _ unpk_prag SrcStrict)+ | not (gopt Opt_OmitInterfacePragmas dflags) -- Don't unpack if -fomit-iface-pragmas+ -- Don't unpack if we aren't optimising; rather arbitrarily,+ -- we use -fomit-iface-pragmas as the indication+ , let mb_co = topNormaliseType_maybe fam_envs arg_ty+ -- Unwrap type families and newtypes+ arg_ty' = case mb_co of { Just (_,ty) -> ty; Nothing -> arg_ty }+ , isUnpackableType dflags fam_envs arg_ty'+ , (rep_tys, _) <- dataConArgUnpack arg_ty'+ , case unpk_prag of+ NoSrcUnpack ->+ gopt Opt_UnboxStrictFields dflags+ || (gopt Opt_UnboxSmallStrictFields dflags+ && length rep_tys <= 1) -- See Note [Unpack one-wide fields]+ srcUnpack -> isSrcUnpacked srcUnpack+ = case mb_co of+ Nothing -> HsUnpack Nothing+ Just (co,_) -> HsUnpack (Just co)++ | otherwise -- Record the strict-but-no-unpack decision+ = HsStrict+++-- | Wrappers/Workers and representation following Unpack/Strictness+-- decisions+dataConArgRep+ :: Type+ -> HsImplBang+ -> ([(Type,StrictnessMark)] -- Rep types+ ,(Unboxer,Boxer))++dataConArgRep arg_ty HsLazy+ = ([(arg_ty, NotMarkedStrict)], (unitUnboxer, unitBoxer))++dataConArgRep arg_ty HsStrict+ = ([(arg_ty, MarkedStrict)], (seqUnboxer, unitBoxer))++dataConArgRep arg_ty (HsUnpack Nothing)+ | (rep_tys, wrappers) <- dataConArgUnpack arg_ty+ = (rep_tys, wrappers)++dataConArgRep _ (HsUnpack (Just co))+ | let co_rep_ty = pSnd (coercionKind co)+ , (rep_tys, wrappers) <- dataConArgUnpack co_rep_ty+ = (rep_tys, wrapCo co co_rep_ty wrappers)+++-------------------------+wrapCo :: Coercion -> Type -> (Unboxer, Boxer) -> (Unboxer, Boxer)+wrapCo co rep_ty (unbox_rep, box_rep) -- co :: arg_ty ~ rep_ty+ = (unboxer, boxer)+ where+ unboxer arg_id = do { rep_id <- newLocal rep_ty+ ; (rep_ids, rep_fn) <- unbox_rep rep_id+ ; let co_bind = NonRec rep_id (Var arg_id `Cast` co)+ ; return (rep_ids, Let co_bind . rep_fn) }+ boxer = Boxer $ \ subst ->+ do { (rep_ids, rep_expr)+ <- case box_rep of+ UnitBox -> do { rep_id <- newLocal (TcType.substTy subst rep_ty)+ ; return ([rep_id], Var rep_id) }+ Boxer boxer -> boxer subst+ ; let sco = substCoUnchecked subst co+ ; return (rep_ids, rep_expr `Cast` mkSymCo sco) }++------------------------+seqUnboxer :: Unboxer+seqUnboxer v = return ([v], \e -> Case (Var v) v (exprType e) [(DEFAULT, [], e)])++unitUnboxer :: Unboxer+unitUnboxer v = return ([v], \e -> e)++unitBoxer :: Boxer+unitBoxer = UnitBox++-------------------------+dataConArgUnpack+ :: Type+ -> ( [(Type, StrictnessMark)] -- Rep types+ , (Unboxer, Boxer) )++dataConArgUnpack arg_ty+ | Just (tc, tc_args) <- splitTyConApp_maybe arg_ty+ , Just con <- tyConSingleAlgDataCon_maybe tc+ -- NB: check for an *algebraic* data type+ -- A recursive newtype might mean that+ -- 'arg_ty' is a newtype+ , let rep_tys = dataConInstArgTys con tc_args+ = ASSERT( isVanillaDataCon con )+ ( rep_tys `zip` dataConRepStrictness con+ ,( \ arg_id ->+ do { rep_ids <- mapM newLocal rep_tys+ ; let unbox_fn body+ = Case (Var arg_id) arg_id (exprType body)+ [(DataAlt con, rep_ids, body)]+ ; return (rep_ids, unbox_fn) }+ , Boxer $ \ subst ->+ do { rep_ids <- mapM (newLocal . TcType.substTyUnchecked subst) rep_tys+ ; return (rep_ids, Var (dataConWorkId con)+ `mkTyApps` (substTysUnchecked subst tc_args)+ `mkVarApps` rep_ids ) } ) )+ | otherwise+ = pprPanic "dataConArgUnpack" (ppr arg_ty)+ -- An interface file specified Unpacked, but we couldn't unpack it++isUnpackableType :: DynFlags -> FamInstEnvs -> Type -> Bool+-- True if we can unpack the UNPACK the argument type+-- See Note [Recursive unboxing]+-- We look "deeply" inside rather than relying on the DataCons+-- we encounter on the way, because otherwise we might well+-- end up relying on ourselves!+isUnpackableType dflags fam_envs ty+ | Just (tc, _) <- splitTyConApp_maybe ty+ , Just con <- tyConSingleAlgDataCon_maybe tc+ , isVanillaDataCon con+ = ok_con_args (unitNameSet (getName tc)) con+ | otherwise+ = False+ where+ ok_arg tcs (ty, bang) = not (attempt_unpack bang) || ok_ty tcs norm_ty+ where+ norm_ty = topNormaliseType fam_envs ty+ ok_ty tcs ty+ | Just (tc, _) <- splitTyConApp_maybe ty+ , let tc_name = getName tc+ = not (tc_name `elemNameSet` tcs)+ && case tyConSingleAlgDataCon_maybe tc of+ Just con | isVanillaDataCon con+ -> ok_con_args (tcs `extendNameSet` getName tc) con+ _ -> True+ | otherwise+ = True++ ok_con_args tcs con+ = all (ok_arg tcs) (dataConOrigArgTys con `zip` dataConSrcBangs con)+ -- NB: dataConSrcBangs gives the *user* request;+ -- We'd get a black hole if we used dataConImplBangs++ attempt_unpack (HsSrcBang _ SrcUnpack NoSrcStrict)+ = xopt LangExt.StrictData dflags+ attempt_unpack (HsSrcBang _ SrcUnpack SrcStrict)+ = True+ attempt_unpack (HsSrcBang _ NoSrcUnpack SrcStrict)+ = True -- Be conservative+ attempt_unpack (HsSrcBang _ NoSrcUnpack NoSrcStrict)+ = xopt LangExt.StrictData dflags -- Be conservative+ attempt_unpack _ = False++{-+Note [Unpack one-wide fields]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The flag UnboxSmallStrictFields ensures that any field that can+(safely) be unboxed to a word-sized unboxed field, should be so unboxed.+For example:++ data A = A Int#+ newtype B = B A+ data C = C !B+ data D = D !C+ data E = E !()+ data F = F !D+ data G = G !F !F++All of these should have an Int# as their representation, except+G which should have two Int#s.++However++ data T = T !(S Int)+ data S = S !a++Here we can represent T with an Int#.++Note [Recursive unboxing]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data R = MkR {-# UNPACK #-} !S Int+ data S = MkS {-# UNPACK #-} !Int+The representation arguments of MkR are the *representation* arguments+of S (plus Int); the rep args of MkS are Int#. This is all fine.++But be careful not to try to unbox this!+ data T = MkT {-# UNPACK #-} !T Int+Because then we'd get an infinite number of arguments.++Here is a more complicated case:+ data S = MkS {-# UNPACK #-} !T Int+ data T = MkT {-# UNPACK #-} !S Int+Each of S and T must decide independently whether to unpack+and they had better not both say yes. So they must both say no.++Also behave conservatively when there is no UNPACK pragma+ data T = MkS !T Int+with -funbox-strict-fields or -funbox-small-strict-fields+we need to behave as if there was an UNPACK pragma there.++But it's the *argument* type that matters. This is fine:+ data S = MkS S !Int+because Int is non-recursive.++************************************************************************+* *+ Wrapping and unwrapping newtypes and type families+* *+************************************************************************+-}++wrapNewTypeBody :: TyCon -> [Type] -> CoreExpr -> CoreExpr+-- The wrapper for the data constructor for a newtype looks like this:+-- newtype T a = MkT (a,Int)+-- MkT :: forall a. (a,Int) -> T a+-- MkT = /\a. \(x:(a,Int)). x `cast` sym (CoT a)+-- where CoT is the coercion TyCon associated with the newtype+--+-- The call (wrapNewTypeBody T [a] e) returns the+-- body of the wrapper, namely+-- e `cast` (CoT [a])+--+-- If a coercion constructor is provided in the newtype, then we use+-- it, otherwise the wrap/unwrap are both no-ops+--+-- If the we are dealing with a newtype *instance*, we have a second coercion+-- identifying the family instance with the constructor of the newtype+-- instance. This coercion is applied in any case (ie, composed with the+-- coercion constructor of the newtype or applied by itself).++wrapNewTypeBody tycon args result_expr+ = ASSERT( isNewTyCon tycon )+ wrapFamInstBody tycon args $+ mkCast result_expr (mkSymCo co)+ where+ co = mkUnbranchedAxInstCo Representational (newTyConCo tycon) args []++-- When unwrapping, we do *not* apply any family coercion, because this will+-- be done via a CoPat by the type checker. We have to do it this way as+-- computing the right type arguments for the coercion requires more than just+-- a spliting operation (cf, TcPat.tcConPat).++unwrapNewTypeBody :: TyCon -> [Type] -> CoreExpr -> CoreExpr+unwrapNewTypeBody tycon args result_expr+ = ASSERT( isNewTyCon tycon )+ mkCast result_expr (mkUnbranchedAxInstCo Representational (newTyConCo tycon) args [])++-- If the type constructor is a representation type of a data instance, wrap+-- the expression into a cast adjusting the expression type, which is an+-- instance of the representation type, to the corresponding instance of the+-- family instance type.+-- See Note [Wrappers for data instance tycons]+wrapFamInstBody :: TyCon -> [Type] -> CoreExpr -> CoreExpr+wrapFamInstBody tycon args body+ | Just co_con <- tyConFamilyCoercion_maybe tycon+ = mkCast body (mkSymCo (mkUnbranchedAxInstCo Representational co_con args []))+ | otherwise+ = body++-- Same as `wrapFamInstBody`, but for type family instances, which are+-- represented by a `CoAxiom`, and not a `TyCon`+wrapTypeFamInstBody :: CoAxiom br -> Int -> [Type] -> [Coercion]+ -> CoreExpr -> CoreExpr+wrapTypeFamInstBody axiom ind args cos body+ = mkCast body (mkSymCo (mkAxInstCo Representational axiom ind args cos))++wrapTypeUnbranchedFamInstBody :: CoAxiom Unbranched -> [Type] -> [Coercion]+ -> CoreExpr -> CoreExpr+wrapTypeUnbranchedFamInstBody axiom+ = wrapTypeFamInstBody axiom 0++unwrapFamInstScrut :: TyCon -> [Type] -> CoreExpr -> CoreExpr+unwrapFamInstScrut tycon args scrut+ | Just co_con <- tyConFamilyCoercion_maybe tycon+ = mkCast scrut (mkUnbranchedAxInstCo Representational co_con args []) -- data instances only+ | otherwise+ = scrut++unwrapTypeFamInstScrut :: CoAxiom br -> Int -> [Type] -> [Coercion]+ -> CoreExpr -> CoreExpr+unwrapTypeFamInstScrut axiom ind args cos scrut+ = mkCast scrut (mkAxInstCo Representational axiom ind args cos)++unwrapTypeUnbranchedFamInstScrut :: CoAxiom Unbranched -> [Type] -> [Coercion]+ -> CoreExpr -> CoreExpr+unwrapTypeUnbranchedFamInstScrut axiom+ = unwrapTypeFamInstScrut axiom 0++{-+************************************************************************+* *+\subsection{Primitive operations}+* *+************************************************************************+-}++mkPrimOpId :: PrimOp -> Id+mkPrimOpId prim_op+ = id+ where+ (tyvars,arg_tys,res_ty, arity, strict_sig) = primOpSig prim_op+ ty = mkSpecForAllTys tyvars (mkFunTys arg_tys res_ty)+ name = mkWiredInName gHC_PRIM (primOpOcc prim_op)+ (mkPrimOpIdUnique (primOpTag prim_op))+ (AnId id) UserSyntax+ id = mkGlobalId (PrimOpId prim_op) name ty info++ info = noCafIdInfo+ `setRuleInfo` mkRuleInfo (maybeToList $ primOpRules name prim_op)+ `setArityInfo` arity+ `setStrictnessInfo` strict_sig+ `setInlinePragInfo` neverInlinePragma+ `setLevityInfoWithType` res_ty+ -- We give PrimOps a NOINLINE pragma so that we don't+ -- get silly warnings from Desugar.dsRule (the inline_shadows_rule+ -- test) about a RULE conflicting with a possible inlining+ -- cf Trac #7287++-- For each ccall we manufacture a separate CCallOpId, giving it+-- a fresh unique, a type that is correct for this particular ccall,+-- and a CCall structure that gives the correct details about calling+-- convention etc.+--+-- The *name* of this Id is a local name whose OccName gives the full+-- details of the ccall, type and all. This means that the interface+-- file reader can reconstruct a suitable Id++mkFCallId :: DynFlags -> Unique -> ForeignCall -> Type -> Id+mkFCallId dflags uniq fcall ty+ = ASSERT( noFreeVarsOfType ty )+ -- A CCallOpId should have no free type variables;+ -- when doing substitutions won't substitute over it+ mkGlobalId (FCallId fcall) name ty info+ where+ occ_str = showSDoc dflags (braces (ppr fcall <+> ppr ty))+ -- The "occurrence name" of a ccall is the full info about the+ -- ccall; it is encoded, but may have embedded spaces etc!++ name = mkFCallName uniq occ_str++ info = noCafIdInfo+ `setArityInfo` arity+ `setStrictnessInfo` strict_sig+ `setLevityInfoWithType` ty++ (bndrs, _) = tcSplitPiTys ty+ arity = count isAnonTyBinder bndrs+ strict_sig = mkClosedStrictSig (replicate arity topDmd) topRes+ -- the call does not claim to be strict in its arguments, since they+ -- may be lifted (foreign import prim) and the called code doesn't+ -- necessarily force them. See Trac #11076.+{-+************************************************************************+* *+\subsection{DictFuns and default methods}+* *+************************************************************************++Note [Dict funs and default methods]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Dict funs and default methods are *not* ImplicitIds. Their definition+involves user-written code, so we can't figure out their strictness etc+based on fixed info, as we can for constructors and record selectors (say).++NB: See also Note [Exported LocalIds] in Id+-}++mkDictFunId :: Name -- Name to use for the dict fun;+ -> [TyVar]+ -> ThetaType+ -> Class+ -> [Type]+ -> Id+-- Implements the DFun Superclass Invariant (see TcInstDcls)+-- See Note [Dict funs and default methods]++mkDictFunId dfun_name tvs theta clas tys+ = mkExportedLocalId (DFunId is_nt)+ dfun_name+ dfun_ty+ where+ is_nt = isNewTyCon (classTyCon clas)+ dfun_ty = mkDictFunTy tvs theta clas tys++mkDictFunTy :: [TyVar] -> ThetaType -> Class -> [Type] -> Type+mkDictFunTy tvs theta clas tys+ = mkSpecSigmaTy tvs theta (mkClassPred clas tys)++{-+************************************************************************+* *+\subsection{Un-definable}+* *+************************************************************************++These Ids can't be defined in Haskell. They could be defined in+unfoldings in the wired-in GHC.Prim interface file, but we'd have to+ensure that they were definitely, definitely inlined, because there is+no curried identifier for them. That's what mkCompulsoryUnfolding+does. If we had a way to get a compulsory unfolding from an interface+file, we could do that, but we don't right now.++unsafeCoerce# isn't so much a PrimOp as a phantom identifier, that+just gets expanded into a type coercion wherever it occurs. Hence we+add it as a built-in Id with an unfolding here.++The type variables we use here are "open" type variables: this means+they can unify with both unlifted and lifted types. Hence we provide+another gun with which to shoot yourself in the foot.+-}++lazyIdName, unsafeCoerceName, nullAddrName, seqName,+ realWorldName, voidPrimIdName, coercionTokenName,+ magicDictName, coerceName, proxyName, dollarName, oneShotName,+ runRWName, noinlineIdName :: Name+unsafeCoerceName = mkWiredInIdName gHC_PRIM (fsLit "unsafeCoerce#") unsafeCoerceIdKey unsafeCoerceId+nullAddrName = mkWiredInIdName gHC_PRIM (fsLit "nullAddr#") nullAddrIdKey nullAddrId+seqName = mkWiredInIdName gHC_PRIM (fsLit "seq") seqIdKey seqId+realWorldName = mkWiredInIdName gHC_PRIM (fsLit "realWorld#") realWorldPrimIdKey realWorldPrimId+voidPrimIdName = mkWiredInIdName gHC_PRIM (fsLit "void#") voidPrimIdKey voidPrimId+lazyIdName = mkWiredInIdName gHC_MAGIC (fsLit "lazy") lazyIdKey lazyId+coercionTokenName = mkWiredInIdName gHC_PRIM (fsLit "coercionToken#") coercionTokenIdKey coercionTokenId+magicDictName = mkWiredInIdName gHC_PRIM (fsLit "magicDict") magicDictKey magicDictId+coerceName = mkWiredInIdName gHC_PRIM (fsLit "coerce") coerceKey coerceId+proxyName = mkWiredInIdName gHC_PRIM (fsLit "proxy#") proxyHashKey proxyHashId+dollarName = mkWiredInIdName gHC_BASE (fsLit "$") dollarIdKey dollarId+oneShotName = mkWiredInIdName gHC_MAGIC (fsLit "oneShot") oneShotKey oneShotId+runRWName = mkWiredInIdName gHC_MAGIC (fsLit "runRW#") runRWKey runRWId+noinlineIdName = mkWiredInIdName gHC_MAGIC (fsLit "noinline") noinlineIdKey noinlineId++dollarId :: Id -- Note [dollarId magic]+dollarId = pcMiscPrelId dollarName ty+ (noCafIdInfo `setUnfoldingInfo` unf)+ where+ fun_ty = mkFunTy alphaTy openBetaTy+ ty = mkSpecForAllTys [runtimeRep2TyVar, alphaTyVar, openBetaTyVar] $+ mkFunTy fun_ty fun_ty+ unf = mkInlineUnfoldingWithArity 2 rhs+ [f,x] = mkTemplateLocals [fun_ty, alphaTy]+ rhs = mkLams [runtimeRep2TyVar, alphaTyVar, openBetaTyVar, f, x] $+ App (Var f) (Var x)++------------------------------------------------+proxyHashId :: Id+proxyHashId+ = pcMiscPrelId proxyName ty+ (noCafIdInfo `setUnfoldingInfo` evaldUnfolding -- Note [evaldUnfoldings]+ `setNeverLevPoly` ty )+ where+ -- proxy# :: forall k (a:k). Proxy# k a+ bndrs = mkTemplateKiTyVars [liftedTypeKind] (\ks -> ks)+ [k,t] = mkTyVarTys bndrs+ ty = mkSpecForAllTys bndrs (mkProxyPrimTy k t)++------------------------------------------------+unsafeCoerceId :: Id+unsafeCoerceId+ = pcMiscPrelId unsafeCoerceName ty info+ where+ info = noCafIdInfo `setInlinePragInfo` alwaysInlinePragma+ `setUnfoldingInfo` mkCompulsoryUnfolding rhs++ -- unsafeCoerce# :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep)+ -- (a :: TYPE r1) (b :: TYPE r2).+ -- a -> b+ bndrs = mkTemplateKiTyVars [runtimeRepTy, runtimeRepTy]+ (\ks -> map tYPE ks)++ [_, _, a, b] = mkTyVarTys bndrs++ ty = mkSpecForAllTys bndrs (mkFunTy a b)++ [x] = mkTemplateLocals [a]+ rhs = mkLams (bndrs ++ [x]) $+ Cast (Var x) (mkUnsafeCo Representational a b)++------------------------------------------------+nullAddrId :: Id+-- nullAddr# :: Addr#+-- The reason it is here is because we don't provide+-- a way to write this literal in Haskell.+nullAddrId = pcMiscPrelId nullAddrName addrPrimTy info+ where+ info = noCafIdInfo `setInlinePragInfo` alwaysInlinePragma+ `setUnfoldingInfo` mkCompulsoryUnfolding (Lit nullAddrLit)+ `setNeverLevPoly` addrPrimTy++------------------------------------------------+seqId :: Id -- See Note [seqId magic]+seqId = pcMiscPrelId seqName ty info+ where+ info = noCafIdInfo `setInlinePragInfo` inline_prag+ `setUnfoldingInfo` mkCompulsoryUnfolding rhs+ `setNeverLevPoly` ty++ inline_prag+ = alwaysInlinePragma `setInlinePragmaActivation` ActiveAfter+ NoSourceText 0+ -- Make 'seq' not inline-always, so that simpleOptExpr+ -- (see CoreSubst.simple_app) won't inline 'seq' on the+ -- LHS of rules. That way we can have rules for 'seq';+ -- see Note [seqId magic]++ ty = mkSpecForAllTys [alphaTyVar,betaTyVar]+ (mkFunTy alphaTy (mkFunTy betaTy betaTy))++ [x,y] = mkTemplateLocals [alphaTy, betaTy]+ rhs = mkLams [alphaTyVar,betaTyVar,x,y] (Case (Var x) x betaTy [(DEFAULT, [], Var y)])++------------------------------------------------+lazyId :: Id -- See Note [lazyId magic]+lazyId = pcMiscPrelId lazyIdName ty info+ where+ info = noCafIdInfo `setNeverLevPoly` ty+ ty = mkSpecForAllTys [alphaTyVar] (mkFunTy alphaTy alphaTy)++noinlineId :: Id -- See Note [noinlineId magic]+noinlineId = pcMiscPrelId noinlineIdName ty info+ where+ info = noCafIdInfo `setNeverLevPoly` ty+ ty = mkSpecForAllTys [alphaTyVar] (mkFunTy alphaTy alphaTy)++oneShotId :: Id -- See Note [The oneShot function]+oneShotId = pcMiscPrelId oneShotName ty info+ where+ info = noCafIdInfo `setInlinePragInfo` alwaysInlinePragma+ `setUnfoldingInfo` mkCompulsoryUnfolding rhs+ ty = mkSpecForAllTys [ runtimeRep1TyVar, runtimeRep2TyVar+ , openAlphaTyVar, openBetaTyVar ]+ (mkFunTy fun_ty fun_ty)+ fun_ty = mkFunTy openAlphaTy openBetaTy+ [body, x] = mkTemplateLocals [fun_ty, openAlphaTy]+ x' = setOneShotLambda x+ rhs = mkLams [ runtimeRep1TyVar, runtimeRep2TyVar+ , openAlphaTyVar, openBetaTyVar+ , body, x'] $+ Var body `App` Var x++runRWId :: Id -- See Note [runRW magic] in this module+runRWId = pcMiscPrelId runRWName ty info+ where+ info = noCafIdInfo `setInlinePragInfo` neverInlinePragma+ `setStrictnessInfo` strict_sig+ `setArityInfo` 1+ strict_sig = mkClosedStrictSig [strictApply1Dmd] topRes+ -- Important to express its strictness,+ -- since it is not inlined until CorePrep+ -- Also see Note [runRW arg] in CorePrep++ -- State# RealWorld+ stateRW = mkTyConApp statePrimTyCon [realWorldTy]+ -- o+ ret_ty = openAlphaTy+ -- State# RealWorld -> o+ arg_ty = stateRW `mkFunTy` ret_ty+ -- (State# RealWorld -> o) -> o+ ty = mkSpecForAllTys [runtimeRep1TyVar, openAlphaTyVar] $+ arg_ty `mkFunTy` ret_ty++--------------------------------------------------------------------------------+magicDictId :: Id -- See Note [magicDictId magic]+magicDictId = pcMiscPrelId magicDictName ty info+ where+ info = noCafIdInfo `setInlinePragInfo` neverInlinePragma+ `setNeverLevPoly` ty+ ty = mkSpecForAllTys [alphaTyVar] alphaTy++--------------------------------------------------------------------------------++coerceId :: Id+coerceId = pcMiscPrelId coerceName ty info+ where+ info = noCafIdInfo `setInlinePragInfo` alwaysInlinePragma+ `setUnfoldingInfo` mkCompulsoryUnfolding rhs+ `setNeverLevPoly` ty+ eqRTy = mkTyConApp coercibleTyCon [ liftedTypeKind+ , alphaTy, betaTy ]+ eqRPrimTy = mkTyConApp eqReprPrimTyCon [ liftedTypeKind+ , liftedTypeKind+ , alphaTy, betaTy ]+ ty = mkSpecForAllTys [alphaTyVar, betaTyVar] $+ mkFunTys [eqRTy, alphaTy] betaTy++ [eqR,x,eq] = mkTemplateLocals [eqRTy, alphaTy, eqRPrimTy]+ rhs = mkLams [alphaTyVar, betaTyVar, eqR, x] $+ mkWildCase (Var eqR) eqRTy betaTy $+ [(DataAlt coercibleDataCon, [eq], Cast (Var x) (mkCoVarCo eq))]++{-+Note [dollarId magic]+~~~~~~~~~~~~~~~~~~~~~+The only reason that ($) is wired in is so that its type can be+ forall (a:*, b:Open). (a->b) -> a -> b+That is, the return type can be unboxed. E.g. this is OK+ foo $ True where foo :: Bool -> Int#+because ($) doesn't inspect or move the result of the call to foo.+See Trac #8739.++There is a special typing rule for ($) in TcExpr, so the type of ($)+isn't looked at there, BUT Lint subsequently (and rightly) complains+if sees ($) applied to Int# (say), unless we give it a wired-in type+as we do here.++Note [Unsafe coerce magic]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We define a *primitive*+ GHC.Prim.unsafeCoerce#+and then in the base library we define the ordinary function+ Unsafe.Coerce.unsafeCoerce :: forall (a:*) (b:*). a -> b+ unsafeCoerce x = unsafeCoerce# x++Notice that unsafeCoerce has a civilized (albeit still dangerous)+polymorphic type, whose type args have kind *. So you can't use it on+unboxed values (unsafeCoerce 3#).++In contrast unsafeCoerce# is even more dangerous because you *can* use+it on unboxed things, (unsafeCoerce# 3#) :: Int. Its type is+ forall (r1 :: RuntimeRep) (r2 :: RuntimeRep) (a: TYPE r1) (b: TYPE r2). a -> b++Note [seqId magic]+~~~~~~~~~~~~~~~~~~+'GHC.Prim.seq' is special in several ways.++a) In source Haskell its second arg can have an unboxed type+ x `seq` (v +# w)+ But see Note [Typing rule for seq] in TcExpr, which+ explains why we give seq itself an ordinary type+ seq :: forall a b. a -> b -> b+ and treat it as a language construct from a typing point of view.++b) Its fixity is set in LoadIface.ghcPrimIface++c) It has quite a bit of desugaring magic.+ See DsUtils.hs Note [Desugaring seq (1)] and (2) and (3)++d) There is some special rule handing: Note [User-defined RULES for seq]++Note [User-defined RULES for seq]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Roman found situations where he had+ case (f n) of _ -> e+where he knew that f (which was strict in n) would terminate if n did.+Notice that the result of (f n) is discarded. So it makes sense to+transform to+ case n of _ -> e++Rather than attempt some general analysis to support this, I've added+enough support that you can do this using a rewrite rule:++ RULE "f/seq" forall n. seq (f n) = seq n++You write that rule. When GHC sees a case expression that discards+its result, it mentally transforms it to a call to 'seq' and looks for+a RULE. (This is done in Simplify.trySeqRules.) As usual, the+correctness of the rule is up to you.++VERY IMPORTANT: to make this work, we give the RULE an arity of 1, not 2.+If we wrote+ RULE "f/seq" forall n e. seq (f n) e = seq n e+with rule arity 2, then two bad things would happen:++ - The magical desugaring done in Note [seqId magic] item (c)+ for saturated application of 'seq' would turn the LHS into+ a case expression!++ - The code in Simplify.rebuildCase would need to actually supply+ the value argument, which turns out to be awkward.++Note [lazyId magic]+~~~~~~~~~~~~~~~~~~~+lazy :: forall a?. a? -> a? (i.e. works for unboxed types too)++'lazy' is used to make sure that a sub-expression, and its free variables,+are truly used call-by-need, with no code motion. Key examples:++* pseq: pseq a b = a `seq` lazy b+ We want to make sure that the free vars of 'b' are not evaluated+ before 'a', even though the expression is plainly strict in 'b'.++* catch: catch a b = catch# (lazy a) b+ Again, it's clear that 'a' will be evaluated strictly (and indeed+ applied to a state token) but we want to make sure that any exceptions+ arising from the evaluation of 'a' are caught by the catch (see+ Trac #11555).++Implementing 'lazy' is a bit tricky:++* It must not have a strictness signature: by being a built-in Id,+ all the info about lazyId comes from here, not from GHC.Base.hi.+ This is important, because the strictness analyser will spot it as+ strict!++* It must not have an unfolding: it gets "inlined" by a HACK in+ CorePrep. It's very important to do this inlining *after* unfoldings+ are exposed in the interface file. Otherwise, the unfolding for+ (say) pseq in the interface file will not mention 'lazy', so if we+ inline 'pseq' we'll totally miss the very thing that 'lazy' was+ there for in the first place. See Trac #3259 for a real world+ example.++* Suppose CorePrep sees (catch# (lazy e) b). At all costs we must+ avoid using call by value here:+ case e of r -> catch# r b+ Avoiding that is the whole point of 'lazy'. So in CorePrep (which+ generate the 'case' expression for a call-by-value call) we must+ spot the 'lazy' on the arg (in CorePrep.cpeApp), and build a 'let'+ instead.++* lazyId is defined in GHC.Base, so we don't *have* to inline it. If it+ appears un-applied, we'll end up just calling it.++Note [noinlineId magic]+~~~~~~~~~~~~~~~~~~~~~~~+noinline :: forall a. a -> a++'noinline' is used to make sure that a function f is never inlined,+e.g., as in 'noinline f x'. Ordinarily, the identity function with NOINLINE+could be used to achieve this effect; however, this has the unfortunate+result of leaving a (useless) call to noinline at runtime. So we have+a little bit of magic to optimize away 'noinline' after we are done+running the simplifier.++'noinline' needs to be wired-in because it gets inserted automatically+when we serialize an expression to the interface format, and we DON'T+want use its fingerprints.+++Note [runRW magic]+~~~~~~~~~~~~~~~~~~+Some definitions, for instance @runST@, must have careful control over float out+of the bindings in their body. Consider this use of @runST@,++ f x = runST ( \ s -> let (a, s') = newArray# 100 [] s+ (_, s'') = fill_in_array_or_something a x s'+ in freezeArray# a s'' )++If we inline @runST@, we'll get:++ f x = let (a, s') = newArray# 100 [] realWorld#{-NB-}+ (_, s'') = fill_in_array_or_something a x s'+ in freezeArray# a s''++And now if we allow the @newArray#@ binding to float out to become a CAF,+we end up with a result that is totally and utterly wrong:++ f = let (a, s') = newArray# 100 [] realWorld#{-NB-} -- YIKES!!!+ in \ x ->+ let (_, s'') = fill_in_array_or_something a x s'+ in freezeArray# a s''++All calls to @f@ will share a {\em single} array! Clearly this is nonsense and+must be prevented.++This is what @runRW#@ gives us: by being inlined extremely late in the+optimization (right before lowering to STG, in CorePrep), we can ensure that+no further floating will occur. This allows us to safely inline things like+@runST@, which are otherwise needlessly expensive (see #10678 and #5916).++While the definition of @GHC.Magic.runRW#@, we override its type in @MkId@+to be open-kinded,++ runRW# :: forall (r1 :: RuntimeRep). (o :: TYPE r)+ => (State# RealWorld -> (# State# RealWorld, o #))+ -> (# State# RealWorld, o #)+++Note [The oneShot function]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the context of making left-folds fuse somewhat okish (see ticket #7994+and Note [Left folds via right fold]) it was determined that it would be useful+if library authors could explicitly tell the compiler that a certain lambda is+called at most once. The oneShot function allows that.++'oneShot' is open kinded, i.e. the type variables can refer to unlifted+types as well (Trac #10744); e.g.+ oneShot (\x:Int# -> x +# 1#)++Like most magic functions it has a compulsary unfolding, so there is no need+for a real definition somewhere. We have one in GHC.Magic for the convenience+of putting the documentation there.++It uses `setOneShotLambda` on the lambda's binder. That is the whole magic:++A typical call looks like+ oneShot (\y. e)+after unfolding the definition `oneShot = \f \x[oneshot]. f x` we get+ (\f \x[oneshot]. f x) (\y. e)+ --> \x[oneshot]. ((\y.e) x)+ --> \x[oneshot] e[x/y]+which is what we want.++It is only effective if the one-shot info survives as long as possible; in+particular it must make it into the interface in unfoldings. See Note [Preserve+OneShotInfo] in CoreTidy.++Also see https://ghc.haskell.org/trac/ghc/wiki/OneShot.+++Note [magicDictId magic]+~~~~~~~~~~~~~~~~~~~~~~~~~+The identifier `magicDict` is just a place-holder, which is used to+implement a primitve that we cannot define in Haskell but we can write+in Core. It is declared with a place-holder type:++ magicDict :: forall a. a++The intention is that the identifier will be used in a very specific way,+to create dictionaries for classes with a single method. Consider a class+like this:++ class C a where+ f :: T a++We are going to use `magicDict`, in conjunction with a built-in Prelude+rule, to cast values of type `T a` into dictionaries for `C a`. To do+this, we define a function like this in the library:++ data WrapC a b = WrapC (C a => Proxy a -> b)++ withT :: (C a => Proxy a -> b)+ -> T a -> Proxy a -> b+ withT f x y = magicDict (WrapC f) x y++The purpose of `WrapC` is to avoid having `f` instantiated.+Also, it avoids impredicativity, because `magicDict`'s type+cannot be instantiated with a forall. The field of `WrapC` contains+a `Proxy` parameter which is used to link the type of the constraint,+`C a`, with the type of the `Wrap` value being made.++Next, we add a built-in Prelude rule (see prelude/PrelRules.hs),+which will replace the RHS of this definition with the appropriate+definition in Core. The rewrite rule works as follows:++ magicDict @t (wrap @a @b f) x y+---->+ f (x `cast` co a) y++The `co` coercion is the newtype-coercion extracted from the type-class.+The type class is obtain by looking at the type of wrap.+++-------------------------------------------------------------+@realWorld#@ used to be a magic literal, \tr{void#}. If things get+nasty as-is, change it back to a literal (@Literal@).++voidArgId is a Local Id used simply as an argument in functions+where we just want an arg to avoid having a thunk of unlifted type.+E.g.+ x = \ void :: Void# -> (# p, q #)++This comes up in strictness analysis++Note [evaldUnfoldings]+~~~~~~~~~~~~~~~~~~~~~~+The evaldUnfolding makes it look that some primitive value is+evaluated, which in turn makes Simplify.interestingArg return True,+which in turn makes INLINE things applied to said value likely to be+inlined.+-}++realWorldPrimId :: Id -- :: State# RealWorld+realWorldPrimId = pcMiscPrelId realWorldName realWorldStatePrimTy+ (noCafIdInfo `setUnfoldingInfo` evaldUnfolding -- Note [evaldUnfoldings]+ `setOneShotInfo` stateHackOneShot+ `setNeverLevPoly` realWorldStatePrimTy)++voidPrimId :: Id -- Global constant :: Void#+voidPrimId = pcMiscPrelId voidPrimIdName voidPrimTy+ (noCafIdInfo `setUnfoldingInfo` evaldUnfolding -- Note [evaldUnfoldings]+ `setNeverLevPoly` voidPrimTy)++voidArgId :: Id -- Local lambda-bound :: Void#+voidArgId = mkSysLocal (fsLit "void") voidArgIdKey voidPrimTy++coercionTokenId :: Id -- :: () ~ ()+coercionTokenId -- Used to replace Coercion terms when we go to STG+ = pcMiscPrelId coercionTokenName+ (mkTyConApp eqPrimTyCon [liftedTypeKind, liftedTypeKind, unitTy, unitTy])+ noCafIdInfo++pcMiscPrelId :: Name -> Type -> IdInfo -> Id+pcMiscPrelId name ty info+ = mkVanillaGlobalWithInfo name ty info+ -- We lie and say the thing is imported; otherwise, we get into+ -- a mess with dependency analysis; e.g., core2stg may heave in+ -- random calls to GHCbase.unpackPS__. If GHCbase is the module+ -- being compiled, then it's just a matter of luck if the definition+ -- will be in "the right place" to be in scope.
+ basicTypes/MkId.hs-boot view
@@ -0,0 +1,15 @@+module MkId where+import Name( Name )+import Var( Id )+import Class( Class )+import {-# SOURCE #-} DataCon( DataCon )+import {-# SOURCE #-} PrimOp( PrimOp )++data DataConBoxer++mkDataConWorkId :: Name -> DataCon -> Id+mkDictSelId :: Name -> Class -> Id++mkPrimOpId :: PrimOp -> Id++magicDictId :: Id
+ basicTypes/Module.hs view
@@ -0,0 +1,1275 @@+{-+(c) The University of Glasgow, 2004-2006+++Module+~~~~~~~~~~+Simply the name of a module, represented as a FastString.+These are Uniquable, hence we can build Maps with Modules as+the keys.+-}++{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Module+ (+ -- * The ModuleName type+ ModuleName,+ pprModuleName,+ moduleNameFS,+ moduleNameString,+ moduleNameSlashes, moduleNameColons,+ moduleStableString,+ moduleFreeHoles,+ moduleIsDefinite,+ mkModuleName,+ mkModuleNameFS,+ stableModuleNameCmp,++ -- * The UnitId type+ ComponentId(..),+ UnitId(..),+ unitIdFS,+ unitIdKey,+ IndefUnitId(..),+ IndefModule(..),+ indefUnitIdToUnitId,+ indefModuleToModule,+ InstalledUnitId(..),+ toInstalledUnitId,+ ShHoleSubst,++ unitIdIsDefinite,+ unitIdString,+ unitIdFreeHoles,++ newUnitId,+ newIndefUnitId,+ newSimpleUnitId,+ hashUnitId,+ fsToUnitId,+ stringToUnitId,+ stableUnitIdCmp,++ -- * HOLE renaming+ renameHoleUnitId,+ renameHoleModule,+ renameHoleUnitId',+ renameHoleModule',++ -- * Generalization+ splitModuleInsts,+ splitUnitIdInsts,+ generalizeIndefUnitId,+ generalizeIndefModule,++ -- * Parsers+ parseModuleName,+ parseUnitId,+ parseComponentId,+ parseModuleId,+ parseModSubst,++ -- * Wired-in UnitIds+ -- $wired_in_packages+ primUnitId,+ integerUnitId,+ baseUnitId,+ rtsUnitId,+ thUnitId,+ dphSeqUnitId,+ dphParUnitId,+ mainUnitId,+ thisGhcUnitId,+ isHoleModule,+ interactiveUnitId, isInteractiveModule,+ wiredInUnitIds,++ -- * The Module type+ Module(Module),+ moduleUnitId, moduleName,+ pprModule,+ mkModule,+ mkHoleModule,+ stableModuleCmp,+ HasModule(..),+ ContainsModule(..),++ -- * Installed unit ids and modules+ InstalledModule(..),+ InstalledModuleEnv,+ installedModuleEq,+ installedUnitIdEq,+ installedUnitIdString,+ fsToInstalledUnitId,+ componentIdToInstalledUnitId,+ stringToInstalledUnitId,+ emptyInstalledModuleEnv,+ lookupInstalledModuleEnv,+ extendInstalledModuleEnv,+ filterInstalledModuleEnv,+ delInstalledModuleEnv,+ DefUnitId(..),++ -- * The ModuleLocation type+ ModLocation(..),+ addBootSuffix, addBootSuffix_maybe, addBootSuffixLocn,++ -- * Module mappings+ ModuleEnv,+ elemModuleEnv, extendModuleEnv, extendModuleEnvList,+ extendModuleEnvList_C, plusModuleEnv_C,+ delModuleEnvList, delModuleEnv, plusModuleEnv, lookupModuleEnv,+ lookupWithDefaultModuleEnv, mapModuleEnv, mkModuleEnv, emptyModuleEnv,+ moduleEnvKeys, moduleEnvElts, moduleEnvToList,+ unitModuleEnv, isEmptyModuleEnv,+ extendModuleEnvWith, filterModuleEnv,++ -- * ModuleName mappings+ ModuleNameEnv, DModuleNameEnv,++ -- * Sets of Modules+ ModuleSet,+ emptyModuleSet, mkModuleSet, moduleSetElts, extendModuleSet, elemModuleSet+ ) where++import Config+import Outputable+import Unique+import UniqFM+import UniqDFM+import UniqDSet+import FastString+import Binary+import Util+import Data.List+import Data.Ord+import GHC.PackageDb (BinaryStringRep(..), DbUnitIdModuleRep(..), DbModule(..), DbUnitId(..))++import qualified Data.ByteString as BS+import qualified Data.ByteString.Unsafe as BS+import qualified Data.ByteString.Char8 as BS.Char8+import System.IO.Unsafe+import Foreign.Ptr (castPtr)+import GHC.Fingerprint+import Encoding++import qualified Text.ParserCombinators.ReadP as Parse+import Text.ParserCombinators.ReadP (ReadP, (<++))+import Data.Char (isAlphaNum)+import Control.DeepSeq+import Data.Coerce+import Data.Data+import Data.Function+import Data.Map (Map)+import Data.Set (Set)+import qualified Data.Map as Map+import qualified Data.Set as Set+import qualified FiniteMap as Map+import System.FilePath++import {-# SOURCE #-} DynFlags (DynFlags)+import {-# SOURCE #-} Packages (componentIdString, improveUnitId, PackageConfigMap, getPackageConfigMap, displayInstalledUnitId)++-- Note [The identifier lexicon]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Unit IDs, installed package IDs, ABI hashes, package names,+-- versions, there are a *lot* of different identifiers for closely+-- related things. What do they all mean? Here's what. (See also+-- https://ghc.haskell.org/trac/ghc/wiki/Commentary/Packages/Concepts )+--+-- THE IMPORTANT ONES+--+-- ComponentId: An opaque identifier provided by Cabal, which should+-- uniquely identify such things as the package name, the package+-- version, the name of the component, the hash of the source code+-- tarball, the selected Cabal flags, GHC flags, direct dependencies of+-- the component. These are very similar to InstalledPackageId, but+-- an 'InstalledPackageId' implies that it identifies a package, while+-- a package may install multiple components with different+-- 'ComponentId's.+-- - Same as Distribution.Package.ComponentId+--+-- UnitId/InstalledUnitId: A ComponentId + a mapping from hole names+-- (ModuleName) to Modules. This is how the compiler identifies instantiated+-- components, and also is the main identifier by which GHC identifies things.+-- - When Backpack is not being used, UnitId = ComponentId.+-- this means a useful fiction for end-users is that there are+-- only ever ComponentIds, and some ComponentIds happen to have+-- more information (UnitIds).+-- - Same as Language.Haskell.TH.Syntax:PkgName, see+-- https://ghc.haskell.org/trac/ghc/ticket/10279+-- - The same as PackageKey in GHC 7.10 (we renamed it because+-- they don't necessarily identify packages anymore.)+-- - Same as -this-package-key/-package-name flags+-- - An InstalledUnitId corresponds to an actual package which+-- we have installed on disk. It could be definite or indefinite,+-- but if it's indefinite, it has nothing instantiated (we+-- never install partially instantiated units.)+--+-- Module/InstalledModule: A UnitId/InstalledUnitId + ModuleName. This is how+-- the compiler identifies modules (e.g. a Name is a Module + OccName)+-- - Same as Language.Haskell.TH.Syntax:Module+--+-- THE LESS IMPORTANT ONES+--+-- PackageName: The "name" field in a Cabal file, something like "lens".+-- - Same as Distribution.Package.PackageName+-- - DIFFERENT FROM Language.Haskell.TH.Syntax:PkgName, see+-- https://ghc.haskell.org/trac/ghc/ticket/10279+-- - DIFFERENT FROM -package-name flag+-- - DIFFERENT FROM the 'name' field in an installed package+-- information. This field could more accurately be described+-- as a munged package name: when it's for the main library+-- it is the same as the package name, but if it's an internal+-- library it's a munged combination of the package name and+-- the component name.+--+-- LEGACY ONES+--+-- InstalledPackageId: This is what we used to call ComponentId.+-- It's a still pretty useful concept for packages that have only+-- one library; in that case the logical InstalledPackageId =+-- ComponentId. Also, the Cabal nix-local-build continues to+-- compute an InstalledPackageId which is then forcibly used+-- for all components in a package. This means that if a dependency+-- from one component in a package changes, the InstalledPackageId+-- changes: you don't get as fine-grained dependency tracking,+-- but it means your builds are hermetic. Eventually, Cabal will+-- deal completely in components and we can get rid of this.+--+-- PackageKey: This is what we used to call UnitId. We ditched+-- "Package" from the name when we realized that you might want to+-- assign different "PackageKeys" to components from the same package.+-- (For a brief, non-released period of time, we also called these+-- UnitKeys).++{-+************************************************************************+* *+\subsection{Module locations}+* *+************************************************************************+-}++-- | Module Location+--+-- Where a module lives on the file system: the actual locations+-- of the .hs, .hi and .o files, if we have them+data ModLocation+ = ModLocation {+ ml_hs_file :: Maybe FilePath,+ -- The source file, if we have one. Package modules+ -- probably don't have source files.++ ml_hi_file :: FilePath,+ -- Where the .hi file is, whether or not it exists+ -- yet. Always of form foo.hi, even if there is an+ -- hi-boot file (we add the -boot suffix later)++ ml_obj_file :: FilePath+ -- Where the .o file is, whether or not it exists yet.+ -- (might not exist either because the module hasn't+ -- been compiled yet, or because it is part of a+ -- package with a .a file)+ } deriving Show++instance Outputable ModLocation where+ ppr = text . show++{-+For a module in another package, the hs_file and obj_file+components of ModLocation are undefined.++The locations specified by a ModLocation may or may not+correspond to actual files yet: for example, even if the object+file doesn't exist, the ModLocation still contains the path to+where the object file will reside if/when it is created.+-}++addBootSuffix :: FilePath -> FilePath+-- ^ Add the @-boot@ suffix to .hs, .hi and .o files+addBootSuffix path = path ++ "-boot"++addBootSuffix_maybe :: Bool -> FilePath -> FilePath+-- ^ Add the @-boot@ suffix if the @Bool@ argument is @True@+addBootSuffix_maybe is_boot path+ | is_boot = addBootSuffix path+ | otherwise = path++addBootSuffixLocn :: ModLocation -> ModLocation+-- ^ Add the @-boot@ suffix to all file paths associated with the module+addBootSuffixLocn locn+ = locn { ml_hs_file = fmap addBootSuffix (ml_hs_file locn)+ , ml_hi_file = addBootSuffix (ml_hi_file locn)+ , ml_obj_file = addBootSuffix (ml_obj_file locn) }++{-+************************************************************************+* *+\subsection{The name of a module}+* *+************************************************************************+-}++-- | A ModuleName is essentially a simple string, e.g. @Data.List@.+newtype ModuleName = ModuleName FastString++instance Uniquable ModuleName where+ getUnique (ModuleName nm) = getUnique nm++instance Eq ModuleName where+ nm1 == nm2 = getUnique nm1 == getUnique nm2++instance Ord ModuleName where+ nm1 `compare` nm2 = stableModuleNameCmp nm1 nm2++instance Outputable ModuleName where+ ppr = pprModuleName++instance Binary ModuleName where+ put_ bh (ModuleName fs) = put_ bh fs+ get bh = do fs <- get bh; return (ModuleName fs)++instance BinaryStringRep ModuleName where+ fromStringRep = mkModuleNameFS . mkFastStringByteString+ toStringRep = fastStringToByteString . moduleNameFS++instance Data ModuleName where+ -- don't traverse?+ toConstr _ = abstractConstr "ModuleName"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "ModuleName"++instance NFData ModuleName where+ rnf x = x `seq` ()++stableModuleNameCmp :: ModuleName -> ModuleName -> Ordering+-- ^ Compares module names lexically, rather than by their 'Unique's+stableModuleNameCmp n1 n2 = moduleNameFS n1 `compare` moduleNameFS n2++pprModuleName :: ModuleName -> SDoc+pprModuleName (ModuleName nm) =+ getPprStyle $ \ sty ->+ if codeStyle sty+ then ztext (zEncodeFS nm)+ else ftext nm++moduleNameFS :: ModuleName -> FastString+moduleNameFS (ModuleName mod) = mod++moduleNameString :: ModuleName -> String+moduleNameString (ModuleName mod) = unpackFS mod++-- | Get a string representation of a 'Module' that's unique and stable+-- across recompilations.+-- eg. "$aeson_70dylHtv1FFGeai1IoxcQr$Data.Aeson.Types.Internal"+moduleStableString :: Module -> String+moduleStableString Module{..} =+ "$" ++ unitIdString moduleUnitId ++ "$" ++ moduleNameString moduleName++mkModuleName :: String -> ModuleName+mkModuleName s = ModuleName (mkFastString s)++mkModuleNameFS :: FastString -> ModuleName+mkModuleNameFS s = ModuleName s++-- |Returns the string version of the module name, with dots replaced by slashes.+--+moduleNameSlashes :: ModuleName -> String+moduleNameSlashes = dots_to_slashes . moduleNameString+ where dots_to_slashes = map (\c -> if c == '.' then pathSeparator else c)++-- |Returns the string version of the module name, with dots replaced by colons.+--+moduleNameColons :: ModuleName -> String+moduleNameColons = dots_to_colons . moduleNameString+ where dots_to_colons = map (\c -> if c == '.' then ':' else c)++{-+************************************************************************+* *+\subsection{A fully qualified module}+* *+************************************************************************+-}++-- | A Module is a pair of a 'UnitId' and a 'ModuleName'.+--+-- Module variables (i.e. @<H>@) which can be instantiated to a+-- specific module at some later point in time are represented+-- with 'moduleUnitId' set to 'holeUnitId' (this allows us to+-- avoid having to make 'moduleUnitId' a partial operation.)+--+data Module = Module {+ moduleUnitId :: !UnitId, -- pkg-1.0+ moduleName :: !ModuleName -- A.B.C+ }+ deriving (Eq, Ord)++-- | Calculate the free holes of a 'Module'. If this set is non-empty,+-- this module was defined in an indefinite library that had required+-- signatures.+--+-- If a module has free holes, that means that substitutions can operate on it;+-- if it has no free holes, substituting over a module has no effect.+moduleFreeHoles :: Module -> UniqDSet ModuleName+moduleFreeHoles m+ | isHoleModule m = unitUniqDSet (moduleName m)+ | otherwise = unitIdFreeHoles (moduleUnitId m)++-- | A 'Module' is definite if it has no free holes.+moduleIsDefinite :: Module -> Bool+moduleIsDefinite = isEmptyUniqDSet . moduleFreeHoles++-- | Create a module variable at some 'ModuleName'.+-- See Note [Representation of module/name variables]+mkHoleModule :: ModuleName -> Module+mkHoleModule = mkModule holeUnitId++instance Uniquable Module where+ getUnique (Module p n) = getUnique (unitIdFS p `appendFS` moduleNameFS n)++instance Outputable Module where+ ppr = pprModule++instance Binary Module where+ put_ bh (Module p n) = put_ bh p >> put_ bh n+ get bh = do p <- get bh; n <- get bh; return (Module p n)++instance Data Module where+ -- don't traverse?+ toConstr _ = abstractConstr "Module"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "Module"++instance NFData Module where+ rnf x = x `seq` ()++-- | This gives a stable ordering, as opposed to the Ord instance which+-- gives an ordering based on the 'Unique's of the components, which may+-- not be stable from run to run of the compiler.+stableModuleCmp :: Module -> Module -> Ordering+stableModuleCmp (Module p1 n1) (Module p2 n2)+ = (p1 `stableUnitIdCmp` p2) `thenCmp`+ (n1 `stableModuleNameCmp` n2)++mkModule :: UnitId -> ModuleName -> Module+mkModule = Module++pprModule :: Module -> SDoc+pprModule mod@(Module p n) = getPprStyle doc+ where+ doc sty+ | codeStyle sty =+ (if p == mainUnitId+ then empty -- never qualify the main package in code+ else ztext (zEncodeFS (unitIdFS p)) <> char '_')+ <> pprModuleName n+ | qualModule sty mod =+ if isHoleModule mod+ then angleBrackets (pprModuleName n)+ else ppr (moduleUnitId mod) <> char ':' <> pprModuleName n+ | otherwise =+ pprModuleName n++class ContainsModule t where+ extractModule :: t -> Module++class HasModule m where+ getModule :: m Module++instance DbUnitIdModuleRep InstalledUnitId ComponentId UnitId ModuleName Module where+ fromDbModule (DbModule uid mod_name) = mkModule uid mod_name+ fromDbModule (DbModuleVar mod_name) = mkHoleModule mod_name+ fromDbUnitId (DbUnitId cid insts) = newUnitId cid insts+ fromDbUnitId (DbInstalledUnitId iuid) = DefiniteUnitId (DefUnitId iuid)+ -- GHC never writes to the database, so it's not needed+ toDbModule = error "toDbModule: not implemented"+ toDbUnitId = error "toDbUnitId: not implemented"++{-+************************************************************************+* *+\subsection{ComponentId}+* *+************************************************************************+-}++-- | A 'ComponentId' consists of the package name, package version, component+-- ID, the transitive dependencies of the component, and other information to+-- uniquely identify the source code and build configuration of a component.+--+-- This used to be known as an 'InstalledPackageId', but a package can contain+-- multiple components and a 'ComponentId' uniquely identifies a component+-- within a package. When a package only has one component, the 'ComponentId'+-- coincides with the 'InstalledPackageId'+newtype ComponentId = ComponentId FastString deriving (Eq, Ord)++instance BinaryStringRep ComponentId where+ fromStringRep = ComponentId . mkFastStringByteString+ toStringRep (ComponentId s) = fastStringToByteString s++instance Uniquable ComponentId where+ getUnique (ComponentId n) = getUnique n++instance Outputable ComponentId where+ ppr cid@(ComponentId fs) =+ getPprStyle $ \sty ->+ sdocWithDynFlags $ \dflags ->+ case componentIdString dflags cid of+ Just str | not (debugStyle sty) -> text str+ _ -> ftext fs++{-+************************************************************************+* *+\subsection{UnitId}+* *+************************************************************************+-}++-- | A unit identifier identifies a (possibly partially) instantiated+-- library. It is primarily used as part of 'Module', which in turn+-- is used in 'Name', which is used to give names to entities when+-- typechecking.+--+-- There are two possible forms for a 'UnitId'. It can be a+-- 'DefiniteUnitId', in which case we just have a string that uniquely+-- identifies some fully compiled, installed library we have on disk.+-- However, when we are typechecking a library with missing holes,+-- we may need to instantiate a library on the fly (in which case+-- we don't have any on-disk representation.) In that case, you+-- have an 'IndefiniteUnitId', which explicitly records the+-- instantiation, so that we can substitute over it.+data UnitId+ = IndefiniteUnitId {-# UNPACK #-} !IndefUnitId+ | DefiniteUnitId {-# UNPACK #-} !DefUnitId+ deriving (Typeable)++unitIdFS :: UnitId -> FastString+unitIdFS (IndefiniteUnitId x) = indefUnitIdFS x+unitIdFS (DefiniteUnitId (DefUnitId x)) = installedUnitIdFS x++unitIdKey :: UnitId -> Unique+unitIdKey (IndefiniteUnitId x) = indefUnitIdKey x+unitIdKey (DefiniteUnitId (DefUnitId x)) = installedUnitIdKey x++-- | A unit identifier which identifies an indefinite+-- library (with holes) that has been *on-the-fly* instantiated+-- with a substitution 'indefUnitIdInsts'. In fact, an indefinite+-- unit identifier could have no holes, but we haven't gotten+-- around to compiling the actual library yet.+--+-- An indefinite unit identifier pretty-prints to something like+-- @p[H=<H>,A=aimpl:A>]@ (@p@ is the 'ComponentId', and the+-- brackets enclose the module substitution).+data IndefUnitId+ = IndefUnitId {+ -- | A private, uniquely identifying representation of+ -- a UnitId. This string is completely private to GHC+ -- and is just used to get a unique; in particular, we don't use it for+ -- symbols (indefinite libraries are not compiled).+ indefUnitIdFS :: FastString,+ -- | Cached unique of 'unitIdFS'.+ indefUnitIdKey :: Unique,+ -- | The component identity of the indefinite library that+ -- is being instantiated.+ indefUnitIdComponentId :: !ComponentId,+ -- | The sorted (by 'ModuleName') instantiations of this library.+ indefUnitIdInsts :: ![(ModuleName, Module)],+ -- | A cache of the free module variables of 'unitIdInsts'.+ -- This lets us efficiently tell if a 'UnitId' has been+ -- fully instantiated (free module variables are empty)+ -- and whether or not a substitution can have any effect.+ indefUnitIdFreeHoles :: UniqDSet ModuleName+ } deriving (Typeable)++instance Eq IndefUnitId where+ u1 == u2 = indefUnitIdKey u1 == indefUnitIdKey u2++instance Ord IndefUnitId where+ u1 `compare` u2 = indefUnitIdFS u1 `compare` indefUnitIdFS u2++instance Binary IndefUnitId where+ put_ bh indef = do+ put_ bh (indefUnitIdComponentId indef)+ put_ bh (indefUnitIdInsts indef)+ get bh = do+ cid <- get bh+ insts <- get bh+ let fs = hashUnitId cid insts+ return IndefUnitId {+ indefUnitIdComponentId = cid,+ indefUnitIdInsts = insts,+ indefUnitIdFreeHoles = unionManyUniqDSets (map (moduleFreeHoles.snd) insts),+ indefUnitIdFS = fs,+ indefUnitIdKey = getUnique fs+ }++-- | Create a new 'IndefUnitId' given an explicit module substitution.+newIndefUnitId :: ComponentId -> [(ModuleName, Module)] -> IndefUnitId+newIndefUnitId cid insts =+ IndefUnitId {+ indefUnitIdComponentId = cid,+ indefUnitIdInsts = sorted_insts,+ indefUnitIdFreeHoles = unionManyUniqDSets (map (moduleFreeHoles.snd) insts),+ indefUnitIdFS = fs,+ indefUnitIdKey = getUnique fs+ }+ where+ fs = hashUnitId cid sorted_insts+ sorted_insts = sortBy (stableModuleNameCmp `on` fst) insts++-- | Injects an 'IndefUnitId' (indefinite library which+-- was on-the-fly instantiated) to a 'UnitId' (either+-- an indefinite or definite library).+indefUnitIdToUnitId :: DynFlags -> IndefUnitId -> UnitId+indefUnitIdToUnitId dflags iuid =+ -- NB: suppose that we want to compare the indefinite+ -- unit id p[H=impl:H] against p+abcd (where p+abcd+ -- happens to be the existing, installed version of+ -- p[H=impl:H]. If we *only* wrap in p[H=impl:H]+ -- IndefiniteUnitId, they won't compare equal; only+ -- after improvement will the equality hold.+ improveUnitId (getPackageConfigMap dflags) $+ IndefiniteUnitId iuid++data IndefModule = IndefModule {+ indefModuleUnitId :: IndefUnitId,+ indefModuleName :: ModuleName+ } deriving (Typeable, Eq, Ord)++instance Outputable IndefModule where+ ppr (IndefModule uid m) =+ ppr uid <> char ':' <> ppr m++-- | Injects an 'IndefModule' to 'Module' (see also+-- 'indefUnitIdToUnitId'.+indefModuleToModule :: DynFlags -> IndefModule -> Module+indefModuleToModule dflags (IndefModule iuid mod_name) =+ mkModule (indefUnitIdToUnitId dflags iuid) mod_name++-- | An installed unit identifier identifies a library which has+-- been installed to the package database. These strings are+-- provided to us via the @-this-unit-id@ flag. The library+-- in question may be definite or indefinite; if it is indefinite,+-- none of the holes have been filled (we never install partially+-- instantiated libraries.) Put another way, an installed unit id+-- is either fully instantiated, or not instantiated at all.+--+-- Installed unit identifiers look something like @p+af23SAj2dZ219@,+-- or maybe just @p@ if they don't use Backpack.+newtype InstalledUnitId =+ InstalledUnitId {+ -- | The full hashed unit identifier, including the component id+ -- and the hash.+ installedUnitIdFS :: FastString+ }+ deriving (Typeable)++instance Binary InstalledUnitId where+ put_ bh (InstalledUnitId fs) = put_ bh fs+ get bh = do fs <- get bh; return (InstalledUnitId fs)++instance BinaryStringRep InstalledUnitId where+ fromStringRep bs = InstalledUnitId (mkFastStringByteString bs)+ -- GHC doesn't write to database+ toStringRep = error "BinaryStringRep InstalledUnitId: not implemented"++instance Eq InstalledUnitId where+ uid1 == uid2 = installedUnitIdKey uid1 == installedUnitIdKey uid2++instance Ord InstalledUnitId where+ u1 `compare` u2 = installedUnitIdFS u1 `compare` installedUnitIdFS u2++instance Uniquable InstalledUnitId where+ getUnique = installedUnitIdKey++instance Outputable InstalledUnitId where+ ppr uid@(InstalledUnitId fs) =+ getPprStyle $ \sty ->+ sdocWithDynFlags $ \dflags ->+ case displayInstalledUnitId dflags uid of+ Just str | not (debugStyle sty) -> text str+ _ -> ftext fs++installedUnitIdKey :: InstalledUnitId -> Unique+installedUnitIdKey = getUnique . installedUnitIdFS++-- | Lossy conversion to the on-disk 'InstalledUnitId' for a component.+toInstalledUnitId :: UnitId -> InstalledUnitId+toInstalledUnitId (DefiniteUnitId (DefUnitId iuid)) = iuid+toInstalledUnitId (IndefiniteUnitId indef) =+ componentIdToInstalledUnitId (indefUnitIdComponentId indef)++installedUnitIdString :: InstalledUnitId -> String+installedUnitIdString = unpackFS . installedUnitIdFS++instance Outputable IndefUnitId where+ ppr uid =+ -- getPprStyle $ \sty ->+ ppr cid <>+ (if not (null insts) -- pprIf+ then+ brackets (hcat+ (punctuate comma $+ [ ppr modname <> text "=" <> ppr m+ | (modname, m) <- insts]))+ else empty)+ where+ cid = indefUnitIdComponentId uid+ insts = indefUnitIdInsts uid++-- | A 'InstalledModule' is a 'Module' which contains a 'InstalledUnitId'.+data InstalledModule = InstalledModule {+ installedModuleUnitId :: !InstalledUnitId,+ installedModuleName :: !ModuleName+ }+ deriving (Eq, Ord)++instance Outputable InstalledModule where+ ppr (InstalledModule p n) =+ ppr p <> char ':' <> pprModuleName n++fsToInstalledUnitId :: FastString -> InstalledUnitId+fsToInstalledUnitId fs = InstalledUnitId fs++componentIdToInstalledUnitId :: ComponentId -> InstalledUnitId+componentIdToInstalledUnitId (ComponentId fs) = fsToInstalledUnitId fs++stringToInstalledUnitId :: String -> InstalledUnitId+stringToInstalledUnitId = fsToInstalledUnitId . mkFastString++-- | Test if a 'Module' corresponds to a given 'InstalledModule',+-- modulo instantiation.+installedModuleEq :: InstalledModule -> Module -> Bool+installedModuleEq imod mod =+ fst (splitModuleInsts mod) == imod++-- | Test if a 'UnitId' corresponds to a given 'InstalledUnitId',+-- modulo instantiation.+installedUnitIdEq :: InstalledUnitId -> UnitId -> Bool+installedUnitIdEq iuid uid =+ fst (splitUnitIdInsts uid) == iuid++-- | A 'DefUnitId' is an 'InstalledUnitId' with the invariant that+-- it only refers to a definite library; i.e., one we have generated+-- code for.+newtype DefUnitId = DefUnitId { unDefUnitId :: InstalledUnitId }+ deriving (Eq, Ord, Typeable)++instance Outputable DefUnitId where+ ppr (DefUnitId uid) = ppr uid++instance Binary DefUnitId where+ put_ bh (DefUnitId uid) = put_ bh uid+ get bh = do uid <- get bh; return (DefUnitId uid)++-- | A map keyed off of 'InstalledModule'+newtype InstalledModuleEnv elt = InstalledModuleEnv (Map InstalledModule elt)++emptyInstalledModuleEnv :: InstalledModuleEnv a+emptyInstalledModuleEnv = InstalledModuleEnv Map.empty++lookupInstalledModuleEnv :: InstalledModuleEnv a -> InstalledModule -> Maybe a+lookupInstalledModuleEnv (InstalledModuleEnv e) m = Map.lookup m e++extendInstalledModuleEnv :: InstalledModuleEnv a -> InstalledModule -> a -> InstalledModuleEnv a+extendInstalledModuleEnv (InstalledModuleEnv e) m x = InstalledModuleEnv (Map.insert m x e)++filterInstalledModuleEnv :: (InstalledModule -> a -> Bool) -> InstalledModuleEnv a -> InstalledModuleEnv a+filterInstalledModuleEnv f (InstalledModuleEnv e) =+ InstalledModuleEnv (Map.filterWithKey f e)++delInstalledModuleEnv :: InstalledModuleEnv a -> InstalledModule -> InstalledModuleEnv a+delInstalledModuleEnv (InstalledModuleEnv e) m = InstalledModuleEnv (Map.delete m e)++-- Note [UnitId to InstalledUnitId improvement]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Just because a UnitId is definite (has no holes) doesn't+-- mean it's necessarily a InstalledUnitId; it could just be+-- that over the course of renaming UnitIds on the fly+-- while typechecking an indefinite library, we+-- ended up with a fully instantiated unit id with no hash,+-- since we haven't built it yet. This is fine.+--+-- However, if there is a hashed unit id for this instantiation+-- in the package database, we *better use it*, because+-- that hashed unit id may be lurking in another interface,+-- and chaos will ensue if we attempt to compare the two+-- (the unitIdFS for a UnitId never corresponds to a Cabal-provided+-- hash of a compiled instantiated library).+--+-- There is one last niggle: improvement based on the package database means+-- that we might end up developing on a package that is not transitively+-- depended upon by the packages the user specified directly via command line+-- flags. This could lead to strange and difficult to understand bugs if those+-- instantiations are out of date. The solution is to only improve a+-- unit id if the new unit id is part of the 'preloadClosure'; i.e., the+-- closure of all the packages which were explicitly specified.++-- | Retrieve the set of free holes of a 'UnitId'.+unitIdFreeHoles :: UnitId -> UniqDSet ModuleName+unitIdFreeHoles (IndefiniteUnitId x) = indefUnitIdFreeHoles x+-- Hashed unit ids are always fully instantiated+unitIdFreeHoles (DefiniteUnitId _) = emptyUniqDSet++instance Show UnitId where+ show = unitIdString++-- | A 'UnitId' is definite if it has no free holes.+unitIdIsDefinite :: UnitId -> Bool+unitIdIsDefinite = isEmptyUniqDSet . unitIdFreeHoles++-- | Generate a uniquely identifying 'FastString' for a unit+-- identifier. This is a one-way function. You can rely on one special+-- property: if a unit identifier is in most general form, its 'FastString'+-- coincides with its 'ComponentId'. This hash is completely internal+-- to GHC and is not used for symbol names or file paths.+hashUnitId :: ComponentId -> [(ModuleName, Module)] -> FastString+hashUnitId cid sorted_holes =+ mkFastStringByteString+ . fingerprintUnitId (toStringRep cid)+ $ rawHashUnitId sorted_holes++-- | Generate a hash for a sorted module substitution.+rawHashUnitId :: [(ModuleName, Module)] -> Fingerprint+rawHashUnitId sorted_holes =+ fingerprintByteString+ . BS.concat $ do+ (m, b) <- sorted_holes+ [ toStringRep m, BS.Char8.singleton ' ',+ fastStringToByteString (unitIdFS (moduleUnitId b)), BS.Char8.singleton ':',+ toStringRep (moduleName b), BS.Char8.singleton '\n']++fingerprintByteString :: BS.ByteString -> Fingerprint+fingerprintByteString bs = unsafePerformIO+ . BS.unsafeUseAsCStringLen bs+ $ \(p,l) -> fingerprintData (castPtr p) l++fingerprintUnitId :: BS.ByteString -> Fingerprint -> BS.ByteString+fingerprintUnitId prefix (Fingerprint a b)+ = BS.concat+ $ [ prefix+ , BS.Char8.singleton '-'+ , BS.Char8.pack (toBase62Padded a)+ , BS.Char8.pack (toBase62Padded b) ]++-- | Create a new, un-hashed unit identifier.+newUnitId :: ComponentId -> [(ModuleName, Module)] -> UnitId+newUnitId cid [] = newSimpleUnitId cid -- TODO: this indicates some latent bug...+newUnitId cid insts = IndefiniteUnitId $ newIndefUnitId cid insts++pprUnitId :: UnitId -> SDoc+pprUnitId (DefiniteUnitId uid) = ppr uid+pprUnitId (IndefiniteUnitId uid) = ppr uid++instance Eq UnitId where+ uid1 == uid2 = unitIdKey uid1 == unitIdKey uid2++instance Uniquable UnitId where+ getUnique = unitIdKey++instance Ord UnitId where+ nm1 `compare` nm2 = stableUnitIdCmp nm1 nm2++instance Data UnitId where+ -- don't traverse?+ toConstr _ = abstractConstr "UnitId"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "UnitId"++instance NFData UnitId where+ rnf x = x `seq` ()++stableUnitIdCmp :: UnitId -> UnitId -> Ordering+-- ^ Compares package ids lexically, rather than by their 'Unique's+stableUnitIdCmp p1 p2 = unitIdFS p1 `compare` unitIdFS p2++instance Outputable UnitId where+ ppr pk = pprUnitId pk++-- Performance: would prefer to have a NameCache like thing+instance Binary UnitId where+ put_ bh (DefiniteUnitId def_uid) = do+ putByte bh 0+ put_ bh def_uid+ put_ bh (IndefiniteUnitId indef_uid) = do+ putByte bh 1+ put_ bh indef_uid+ get bh = do b <- getByte bh+ case b of+ 0 -> fmap DefiniteUnitId (get bh)+ _ -> fmap IndefiniteUnitId (get bh)++instance Binary ComponentId where+ put_ bh (ComponentId fs) = put_ bh fs+ get bh = do { fs <- get bh; return (ComponentId fs) }++-- | Create a new simple unit identifier (no holes) from a 'ComponentId'.+newSimpleUnitId :: ComponentId -> UnitId+newSimpleUnitId (ComponentId fs) = fsToUnitId fs++-- | Create a new simple unit identifier from a 'FastString'. Internally,+-- this is primarily used to specify wired-in unit identifiers.+fsToUnitId :: FastString -> UnitId+fsToUnitId = DefiniteUnitId . DefUnitId . InstalledUnitId++stringToUnitId :: String -> UnitId+stringToUnitId = fsToUnitId . mkFastString++unitIdString :: UnitId -> String+unitIdString = unpackFS . unitIdFS++{-+************************************************************************+* *+ Hole substitutions+* *+************************************************************************+-}++-- | Substitution on module variables, mapping module names to module+-- identifiers.+type ShHoleSubst = ModuleNameEnv Module++-- | Substitutes holes in a 'Module'. NOT suitable for being called+-- directly on a 'nameModule', see Note [Representation of module/name variable].+-- @p[A=<A>]:B@ maps to @p[A=q():A]:B@ with @A=q():A@;+-- similarly, @<A>@ maps to @q():A@.+renameHoleModule :: DynFlags -> ShHoleSubst -> Module -> Module+renameHoleModule dflags = renameHoleModule' (getPackageConfigMap dflags)++-- | Substitutes holes in a 'UnitId', suitable for renaming when+-- an include occurs; see Note [Representation of module/name variable].+--+-- @p[A=<A>]@ maps to @p[A=<B>]@ with @A=<B>@.+renameHoleUnitId :: DynFlags -> ShHoleSubst -> UnitId -> UnitId+renameHoleUnitId dflags = renameHoleUnitId' (getPackageConfigMap dflags)++-- | Like 'renameHoleModule', but requires only 'PackageConfigMap'+-- so it can be used by "Packages".+renameHoleModule' :: PackageConfigMap -> ShHoleSubst -> Module -> Module+renameHoleModule' pkg_map env m+ | not (isHoleModule m) =+ let uid = renameHoleUnitId' pkg_map env (moduleUnitId m)+ in mkModule uid (moduleName m)+ | Just m' <- lookupUFM env (moduleName m) = m'+ -- NB m = <Blah>, that's what's in scope.+ | otherwise = m++-- | Like 'renameHoleUnitId, but requires only 'PackageConfigMap'+-- so it can be used by "Packages".+renameHoleUnitId' :: PackageConfigMap -> ShHoleSubst -> UnitId -> UnitId+renameHoleUnitId' pkg_map env uid =+ case uid of+ (IndefiniteUnitId+ IndefUnitId{ indefUnitIdComponentId = cid+ , indefUnitIdInsts = insts+ , indefUnitIdFreeHoles = fh })+ -> if isNullUFM (intersectUFM_C const (udfmToUfm fh) env)+ then uid+ -- Functorially apply the substitution to the instantiation,+ -- then check the 'PackageConfigMap' to see if there is+ -- a compiled version of this 'UnitId' we can improve to.+ -- See Note [UnitId to InstalledUnitId] improvement+ else improveUnitId pkg_map $+ newUnitId cid+ (map (\(k,v) -> (k, renameHoleModule' pkg_map env v)) insts)+ _ -> uid++-- | Given a possibly on-the-fly instantiated module, split it into+-- a 'Module' that we definitely can find on-disk, as well as an+-- instantiation if we need to instantiate it on the fly. If the+-- instantiation is @Nothing@ no on-the-fly renaming is needed.+splitModuleInsts :: Module -> (InstalledModule, Maybe IndefModule)+splitModuleInsts m =+ let (uid, mb_iuid) = splitUnitIdInsts (moduleUnitId m)+ in (InstalledModule uid (moduleName m),+ fmap (\iuid -> IndefModule iuid (moduleName m)) mb_iuid)++-- | See 'splitModuleInsts'.+splitUnitIdInsts :: UnitId -> (InstalledUnitId, Maybe IndefUnitId)+splitUnitIdInsts (IndefiniteUnitId iuid) =+ (componentIdToInstalledUnitId (indefUnitIdComponentId iuid), Just iuid)+splitUnitIdInsts (DefiniteUnitId (DefUnitId uid)) = (uid, Nothing)++generalizeIndefUnitId :: IndefUnitId -> IndefUnitId+generalizeIndefUnitId IndefUnitId{ indefUnitIdComponentId = cid+ , indefUnitIdInsts = insts } =+ newIndefUnitId cid (map (\(m,_) -> (m, mkHoleModule m)) insts)++generalizeIndefModule :: IndefModule -> IndefModule+generalizeIndefModule (IndefModule uid n) = IndefModule (generalizeIndefUnitId uid) n++parseModuleName :: ReadP ModuleName+parseModuleName = fmap mkModuleName+ $ Parse.munch1 (\c -> isAlphaNum c || c `elem` "_.")++parseUnitId :: ReadP UnitId+parseUnitId = parseFullUnitId <++ parseDefiniteUnitId <++ parseSimpleUnitId+ where+ parseFullUnitId = do+ cid <- parseComponentId+ insts <- parseModSubst+ return (newUnitId cid insts)+ parseDefiniteUnitId = do+ s <- Parse.munch1 (\c -> isAlphaNum c || c `elem` "-_.+")+ return (stringToUnitId s)+ parseSimpleUnitId = do+ cid <- parseComponentId+ return (newSimpleUnitId cid)++parseComponentId :: ReadP ComponentId+parseComponentId = (ComponentId . mkFastString) `fmap` Parse.munch1 abi_char+ where abi_char c = isAlphaNum c || c `elem` "-_."++parseModuleId :: ReadP Module+parseModuleId = parseModuleVar <++ parseModule+ where+ parseModuleVar = do+ _ <- Parse.char '<'+ modname <- parseModuleName+ _ <- Parse.char '>'+ return (mkHoleModule modname)+ parseModule = do+ uid <- parseUnitId+ _ <- Parse.char ':'+ modname <- parseModuleName+ return (mkModule uid modname)++parseModSubst :: ReadP [(ModuleName, Module)]+parseModSubst = Parse.between (Parse.char '[') (Parse.char ']')+ . flip Parse.sepBy (Parse.char ',')+ $ do k <- parseModuleName+ _ <- Parse.char '='+ v <- parseModuleId+ return (k, v)+++-- -----------------------------------------------------------------------------+-- $wired_in_packages+-- Certain packages are known to the compiler, in that we know about certain+-- entities that reside in these packages, and the compiler needs to+-- declare static Modules and Names that refer to these packages. Hence+-- the wired-in packages can't include version numbers, since we don't want+-- to bake the version numbers of these packages into GHC.+--+-- So here's the plan. Wired-in packages are still versioned as+-- normal in the packages database, and you can still have multiple+-- versions of them installed. However, for each invocation of GHC,+-- only a single instance of each wired-in package will be recognised+-- (the desired one is selected via @-package@\/@-hide-package@), and GHC+-- will use the unversioned 'UnitId' below when referring to it,+-- including in .hi files and object file symbols. Unselected+-- versions of wired-in packages will be ignored, as will any other+-- package that depends directly or indirectly on it (much as if you+-- had used @-ignore-package@).++-- Make sure you change 'Packages.findWiredInPackages' if you add an entry here++integerUnitId, primUnitId,+ baseUnitId, rtsUnitId,+ thUnitId, dphSeqUnitId, dphParUnitId,+ mainUnitId, thisGhcUnitId, interactiveUnitId :: UnitId+primUnitId = fsToUnitId (fsLit "ghc-prim")+integerUnitId = fsToUnitId (fsLit n)+ where+ n = case cIntegerLibraryType of+ IntegerGMP -> "integer-gmp"+ IntegerSimple -> "integer-simple"+baseUnitId = fsToUnitId (fsLit "base")+rtsUnitId = fsToUnitId (fsLit "rts")+thUnitId = fsToUnitId (fsLit "template-haskell")+dphSeqUnitId = fsToUnitId (fsLit "dph-seq")+dphParUnitId = fsToUnitId (fsLit "dph-par")+thisGhcUnitId = fsToUnitId (fsLit "ghc")+interactiveUnitId = fsToUnitId (fsLit "interactive")++-- | This is the package Id for the current program. It is the default+-- package Id if you don't specify a package name. We don't add this prefix+-- to symbol names, since there can be only one main package per program.+mainUnitId = fsToUnitId (fsLit "main")++-- | This is a fake package id used to provide identities to any un-implemented+-- signatures. The set of hole identities is global over an entire compilation.+-- Don't use this directly: use 'mkHoleModule' or 'isHoleModule' instead.+-- See Note [Representation of module/name variables]+holeUnitId :: UnitId+holeUnitId = fsToUnitId (fsLit "hole")++isInteractiveModule :: Module -> Bool+isInteractiveModule mod = moduleUnitId mod == interactiveUnitId++-- Note [Representation of module/name variables]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- In our ICFP'16, we use <A> to represent module holes, and {A.T} to represent+-- name holes. This could have been represented by adding some new cases+-- to the core data types, but this would have made the existing 'nameModule'+-- and 'moduleUnitId' partial, which would have required a lot of modifications+-- to existing code.+--+-- Instead, we adopted the following encoding scheme:+--+-- <A> ===> hole:A+-- {A.T} ===> hole:A.T+--+-- This encoding is quite convenient, but it is also a bit dangerous too,+-- because if you have a 'hole:A' you need to know if it's actually a+-- 'Module' or just a module stored in a 'Name'; these two cases must be+-- treated differently when doing substitutions. 'renameHoleModule'+-- and 'renameHoleUnitId' assume they are NOT operating on a+-- 'Name'; 'NameShape' handles name substitutions exclusively.++isHoleModule :: Module -> Bool+isHoleModule mod = moduleUnitId mod == holeUnitId++wiredInUnitIds :: [UnitId]+wiredInUnitIds = [ primUnitId,+ integerUnitId,+ baseUnitId,+ rtsUnitId,+ thUnitId,+ thisGhcUnitId,+ dphSeqUnitId,+ dphParUnitId ]++{-+************************************************************************+* *+\subsection{@ModuleEnv@s}+* *+************************************************************************+-}++-- | A map keyed off of 'Module's+newtype ModuleEnv elt = ModuleEnv (Map NDModule elt)++{-+Note [ModuleEnv performance and determinism]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To prevent accidental reintroduction of nondeterminism the Ord instance+for Module was changed to not depend on Unique ordering and to use the+lexicographic order. This is potentially expensive, but when measured+there was no difference in performance.++To be on the safe side and not pessimize ModuleEnv uses nondeterministic+ordering on Module and normalizes by doing the lexicographic sort when+turning the env to a list.+See Note [Unique Determinism] for more information about the source of+nondeterminismand and Note [Deterministic UniqFM] for explanation of why+it matters for maps.+-}++newtype NDModule = NDModule { unNDModule :: Module }+ deriving Eq+ -- A wrapper for Module with faster nondeterministic Ord.+ -- Don't export, See [ModuleEnv performance and determinism]++instance Ord NDModule where+ compare (NDModule (Module p1 n1)) (NDModule (Module p2 n2)) =+ (getUnique p1 `nonDetCmpUnique` getUnique p2) `thenCmp`+ (getUnique n1 `nonDetCmpUnique` getUnique n2)++filterModuleEnv :: (Module -> a -> Bool) -> ModuleEnv a -> ModuleEnv a+filterModuleEnv f (ModuleEnv e) =+ ModuleEnv (Map.filterWithKey (f . unNDModule) e)++elemModuleEnv :: Module -> ModuleEnv a -> Bool+elemModuleEnv m (ModuleEnv e) = Map.member (NDModule m) e++extendModuleEnv :: ModuleEnv a -> Module -> a -> ModuleEnv a+extendModuleEnv (ModuleEnv e) m x = ModuleEnv (Map.insert (NDModule m) x e)++extendModuleEnvWith :: (a -> a -> a) -> ModuleEnv a -> Module -> a+ -> ModuleEnv a+extendModuleEnvWith f (ModuleEnv e) m x =+ ModuleEnv (Map.insertWith f (NDModule m) x e)++extendModuleEnvList :: ModuleEnv a -> [(Module, a)] -> ModuleEnv a+extendModuleEnvList (ModuleEnv e) xs =+ ModuleEnv (Map.insertList [(NDModule k, v) | (k,v) <- xs] e)++extendModuleEnvList_C :: (a -> a -> a) -> ModuleEnv a -> [(Module, a)]+ -> ModuleEnv a+extendModuleEnvList_C f (ModuleEnv e) xs =+ ModuleEnv (Map.insertListWith f [(NDModule k, v) | (k,v) <- xs] e)++plusModuleEnv_C :: (a -> a -> a) -> ModuleEnv a -> ModuleEnv a -> ModuleEnv a+plusModuleEnv_C f (ModuleEnv e1) (ModuleEnv e2) =+ ModuleEnv (Map.unionWith f e1 e2)++delModuleEnvList :: ModuleEnv a -> [Module] -> ModuleEnv a+delModuleEnvList (ModuleEnv e) ms =+ ModuleEnv (Map.deleteList (map NDModule ms) e)++delModuleEnv :: ModuleEnv a -> Module -> ModuleEnv a+delModuleEnv (ModuleEnv e) m = ModuleEnv (Map.delete (NDModule m) e)++plusModuleEnv :: ModuleEnv a -> ModuleEnv a -> ModuleEnv a+plusModuleEnv (ModuleEnv e1) (ModuleEnv e2) = ModuleEnv (Map.union e1 e2)++lookupModuleEnv :: ModuleEnv a -> Module -> Maybe a+lookupModuleEnv (ModuleEnv e) m = Map.lookup (NDModule m) e++lookupWithDefaultModuleEnv :: ModuleEnv a -> a -> Module -> a+lookupWithDefaultModuleEnv (ModuleEnv e) x m =+ Map.findWithDefault x (NDModule m) e++mapModuleEnv :: (a -> b) -> ModuleEnv a -> ModuleEnv b+mapModuleEnv f (ModuleEnv e) = ModuleEnv (Map.mapWithKey (\_ v -> f v) e)++mkModuleEnv :: [(Module, a)] -> ModuleEnv a+mkModuleEnv xs = ModuleEnv (Map.fromList [(NDModule k, v) | (k,v) <- xs])++emptyModuleEnv :: ModuleEnv a+emptyModuleEnv = ModuleEnv Map.empty++moduleEnvKeys :: ModuleEnv a -> [Module]+moduleEnvKeys (ModuleEnv e) = sort $ map unNDModule $ Map.keys e+ -- See Note [ModuleEnv performance and determinism]++moduleEnvElts :: ModuleEnv a -> [a]+moduleEnvElts e = map snd $ moduleEnvToList e+ -- See Note [ModuleEnv performance and determinism]++moduleEnvToList :: ModuleEnv a -> [(Module, a)]+moduleEnvToList (ModuleEnv e) =+ sortBy (comparing fst) [(m, v) | (NDModule m, v) <- Map.toList e]+ -- See Note [ModuleEnv performance and determinism]++unitModuleEnv :: Module -> a -> ModuleEnv a+unitModuleEnv m x = ModuleEnv (Map.singleton (NDModule m) x)++isEmptyModuleEnv :: ModuleEnv a -> Bool+isEmptyModuleEnv (ModuleEnv e) = Map.null e++-- | A set of 'Module's+type ModuleSet = Set NDModule++mkModuleSet :: [Module] -> ModuleSet+extendModuleSet :: ModuleSet -> Module -> ModuleSet+emptyModuleSet :: ModuleSet+moduleSetElts :: ModuleSet -> [Module]+elemModuleSet :: Module -> ModuleSet -> Bool++emptyModuleSet = Set.empty+mkModuleSet = Set.fromList . coerce+extendModuleSet s m = Set.insert (NDModule m) s+moduleSetElts = sort . coerce . Set.toList+elemModuleSet = Set.member . coerce++{-+A ModuleName has a Unique, so we can build mappings of these using+UniqFM.+-}++-- | A map keyed off of 'ModuleName's (actually, their 'Unique's)+type ModuleNameEnv elt = UniqFM elt+++-- | A map keyed off of 'ModuleName's (actually, their 'Unique's)+-- Has deterministic folds and can be deterministically converted to a list+type DModuleNameEnv elt = UniqDFM elt
+ basicTypes/Module.hs-boot view
@@ -0,0 +1,12 @@+module Module where+import FastString++data Module+data ModuleName+data UnitId+data InstalledUnitId+newtype ComponentId = ComponentId FastString++moduleName :: Module -> ModuleName+moduleUnitId :: Module -> UnitId+unitIdString :: UnitId -> String
+ basicTypes/Name.hs view
@@ -0,0 +1,710 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[Name]{@Name@: to transmit name info from renamer to typechecker}+-}++{-# LANGUAGE RecordWildCards #-}++-- |+-- #name_types#+-- GHC uses several kinds of name internally:+--+-- * 'OccName.OccName': see "OccName#name_types"+--+-- * 'RdrName.RdrName': see "RdrName#name_types"+--+-- * 'Name.Name' is the type of names that have had their scoping and binding resolved. They+-- have an 'OccName.OccName' but also a 'Unique.Unique' that disambiguates Names that have+-- the same 'OccName.OccName' and indeed is used for all 'Name.Name' comparison. Names+-- also contain information about where they originated from, see "Name#name_sorts"+--+-- * 'Id.Id': see "Id#name_types"+--+-- * 'Var.Var': see "Var#name_types"+--+-- #name_sorts#+-- Names are one of:+--+-- * External, if they name things declared in other modules. Some external+-- Names are wired in, i.e. they name primitives defined in the compiler itself+--+-- * Internal, if they name things in the module being compiled. Some internal+-- Names are system names, if they are names manufactured by the compiler++module Name (+ -- * The main types+ Name, -- Abstract+ BuiltInSyntax(..),++ -- ** Creating 'Name's+ mkSystemName, mkSystemNameAt,+ mkInternalName, mkClonedInternalName, mkDerivedInternalName,+ mkSystemVarName, mkSysTvName,+ mkFCallName,+ mkExternalName, mkWiredInName,++ -- ** Manipulating and deconstructing 'Name's+ nameUnique, setNameUnique,+ nameOccName, nameModule, nameModule_maybe,+ setNameLoc,+ tidyNameOcc,+ localiseName,+ mkLocalisedOccName,++ nameSrcLoc, nameSrcSpan, pprNameDefnLoc, pprDefinedAt,++ -- ** Predicates on 'Name's+ isSystemName, isInternalName, isExternalName,+ isTyVarName, isTyConName, isDataConName,+ isValName, isVarName,+ isWiredInName, isBuiltInSyntax,+ isHoleName,+ wiredInNameTyThing_maybe,+ nameIsLocalOrFrom, nameIsHomePackage,+ nameIsHomePackageImport, nameIsFromExternalPackage,+ stableNameCmp,++ -- * Class 'NamedThing' and overloaded friends+ NamedThing(..),+ getSrcLoc, getSrcSpan, getOccString, getOccFS,++ pprInfixName, pprPrefixName, pprModulePrefix,+ nameStableString,++ -- Re-export the OccName stuff+ module OccName+ ) where++import {-# SOURCE #-} TyCoRep( TyThing )+import {-# SOURCE #-} PrelNames( starKindTyConKey, unicodeStarKindTyConKey )++import OccName+import Module+import SrcLoc+import Unique+import Util+import Maybes+import Binary+import DynFlags+import FastString+import Outputable++import Control.DeepSeq+import Data.Data++{-+************************************************************************+* *+\subsection[Name-datatype]{The @Name@ datatype, and name construction}+* *+************************************************************************+-}++-- | A unique, unambiguous name for something, containing information about where+-- that thing originated.+data Name = Name {+ n_sort :: NameSort, -- What sort of name it is+ n_occ :: !OccName, -- Its occurrence name+ n_uniq :: {-# UNPACK #-} !Int,+ n_loc :: !SrcSpan -- Definition site+ }++-- NOTE: we make the n_loc field strict to eliminate some potential+-- (and real!) space leaks, due to the fact that we don't look at+-- the SrcLoc in a Name all that often.++data NameSort+ = External Module++ | WiredIn Module TyThing BuiltInSyntax+ -- A variant of External, for wired-in things++ | Internal -- A user-defined Id or TyVar+ -- defined in the module being compiled++ | System -- A system-defined Id or TyVar. Typically the+ -- OccName is very uninformative (like 's')++instance Outputable NameSort where+ ppr (External _) = text "external"+ ppr (WiredIn _ _ _) = text "wired-in"+ ppr Internal = text "internal"+ ppr System = text "system"++instance NFData Name where+ rnf Name{..} = rnf n_sort++instance NFData NameSort where+ rnf (External m) = rnf m+ rnf (WiredIn m t b) = rnf m `seq` t `seq` b `seq` ()+ -- XXX this is a *lie*, we're not going to rnf the TyThing, but+ -- since the TyThings for WiredIn Names are all static they can't+ -- be hiding space leaks or errors.+ rnf Internal = ()+ rnf System = ()++-- | BuiltInSyntax is for things like @(:)@, @[]@ and tuples,+-- which have special syntactic forms. They aren't in scope+-- as such.+data BuiltInSyntax = BuiltInSyntax | UserSyntax++{-+Notes about the NameSorts:++1. Initially, top-level Ids (including locally-defined ones) get External names,+ and all other local Ids get Internal names++2. In any invocation of GHC, an External Name for "M.x" has one and only one+ unique. This unique association is ensured via the Name Cache;+ see Note [The Name Cache] in IfaceEnv.++3. Things with a External name are given C static labels, so they finally+ appear in the .o file's symbol table. They appear in the symbol table+ in the form M.n. If originally-local things have this property they+ must be made @External@ first.++4. In the tidy-core phase, a External that is not visible to an importer+ is changed to Internal, and a Internal that is visible is changed to External++5. A System Name differs in the following ways:+ a) has unique attached when printing dumps+ b) unifier eliminates sys tyvars in favour of user provs where possible++ Before anything gets printed in interface files or output code, it's+ fed through a 'tidy' processor, which zaps the OccNames to have+ unique names; and converts all sys-locals to user locals+ If any desugarer sys-locals have survived that far, they get changed to+ "ds1", "ds2", etc.++Built-in syntax => It's a syntactic form, not "in scope" (e.g. [])++Wired-in thing => The thing (Id, TyCon) is fully known to the compiler,+ not read from an interface file.+ E.g. Bool, True, Int, Float, and many others++All built-in syntax is for wired-in things.+-}++instance HasOccName Name where+ occName = nameOccName++nameUnique :: Name -> Unique+nameOccName :: Name -> OccName+nameModule :: Name -> Module+nameSrcLoc :: Name -> SrcLoc+nameSrcSpan :: Name -> SrcSpan++nameUnique name = mkUniqueGrimily (n_uniq name)+nameOccName name = n_occ name+nameSrcLoc name = srcSpanStart (n_loc name)+nameSrcSpan name = n_loc name++{-+************************************************************************+* *+\subsection{Predicates on names}+* *+************************************************************************+-}++isInternalName :: Name -> Bool+isExternalName :: Name -> Bool+isSystemName :: Name -> Bool+isWiredInName :: Name -> Bool++isWiredInName (Name {n_sort = WiredIn _ _ _}) = True+isWiredInName _ = False++wiredInNameTyThing_maybe :: Name -> Maybe TyThing+wiredInNameTyThing_maybe (Name {n_sort = WiredIn _ thing _}) = Just thing+wiredInNameTyThing_maybe _ = Nothing++isBuiltInSyntax :: Name -> Bool+isBuiltInSyntax (Name {n_sort = WiredIn _ _ BuiltInSyntax}) = True+isBuiltInSyntax _ = False++isExternalName (Name {n_sort = External _}) = True+isExternalName (Name {n_sort = WiredIn _ _ _}) = True+isExternalName _ = False++isInternalName name = not (isExternalName name)++isHoleName :: Name -> Bool+isHoleName = isHoleModule . nameModule++nameModule name =+ nameModule_maybe name `orElse`+ pprPanic "nameModule" (ppr (n_sort name) <+> ppr name)++nameModule_maybe :: Name -> Maybe Module+nameModule_maybe (Name { n_sort = External mod}) = Just mod+nameModule_maybe (Name { n_sort = WiredIn mod _ _}) = Just mod+nameModule_maybe _ = Nothing++nameIsLocalOrFrom :: Module -> Name -> Bool+-- ^ Returns True if the name is+-- (a) Internal+-- (b) External but from the specified module+-- (c) External but from the 'interactive' package+--+-- The key idea is that+-- False means: the entity is defined in some other module+-- you can find the details (type, fixity, instances)+-- in some interface file+-- those details will be stored in the EPT or HPT+--+-- True means: the entity is defined in this module or earlier in+-- the GHCi session+-- you can find details (type, fixity, instances) in the+-- TcGblEnv or TcLclEnv+--+-- The isInteractiveModule part is because successive interactions of a GCHi session+-- each give rise to a fresh module (Ghci1, Ghci2, etc), but they all come+-- from the magic 'interactive' package; and all the details are kept in the+-- TcLclEnv, TcGblEnv, NOT in the HPT or EPT.+-- See Note [The interactive package] in HscTypes++nameIsLocalOrFrom from name+ | Just mod <- nameModule_maybe name = from == mod || isInteractiveModule mod+ | otherwise = True++nameIsHomePackage :: Module -> Name -> Bool+-- True if the Name is defined in module of this package+nameIsHomePackage this_mod+ = \nm -> case n_sort nm of+ External nm_mod -> moduleUnitId nm_mod == this_pkg+ WiredIn nm_mod _ _ -> moduleUnitId nm_mod == this_pkg+ Internal -> True+ System -> False+ where+ this_pkg = moduleUnitId this_mod++nameIsHomePackageImport :: Module -> Name -> Bool+-- True if the Name is defined in module of this package+-- /other than/ the this_mod+nameIsHomePackageImport this_mod+ = \nm -> case nameModule_maybe nm of+ Nothing -> False+ Just nm_mod -> nm_mod /= this_mod+ && moduleUnitId nm_mod == this_pkg+ where+ this_pkg = moduleUnitId this_mod++-- | Returns True if the Name comes from some other package: neither this+-- pacakge nor the interactive package.+nameIsFromExternalPackage :: UnitId -> Name -> Bool+nameIsFromExternalPackage this_pkg name+ | Just mod <- nameModule_maybe name+ , moduleUnitId mod /= this_pkg -- Not this package+ , not (isInteractiveModule mod) -- Not the 'interactive' package+ = True+ | otherwise+ = False++isTyVarName :: Name -> Bool+isTyVarName name = isTvOcc (nameOccName name)++isTyConName :: Name -> Bool+isTyConName name = isTcOcc (nameOccName name)++isDataConName :: Name -> Bool+isDataConName name = isDataOcc (nameOccName name)++isValName :: Name -> Bool+isValName name = isValOcc (nameOccName name)++isVarName :: Name -> Bool+isVarName = isVarOcc . nameOccName++isSystemName (Name {n_sort = System}) = True+isSystemName _ = False++{-+************************************************************************+* *+\subsection{Making names}+* *+************************************************************************+-}++-- | Create a name which is (for now at least) local to the current module and hence+-- does not need a 'Module' to disambiguate it from other 'Name's+mkInternalName :: Unique -> OccName -> SrcSpan -> Name+mkInternalName uniq occ loc = Name { n_uniq = getKey uniq+ , n_sort = Internal+ , n_occ = occ+ , n_loc = loc }+ -- NB: You might worry that after lots of huffing and+ -- puffing we might end up with two local names with distinct+ -- uniques, but the same OccName. Indeed we can, but that's ok+ -- * the insides of the compiler don't care: they use the Unique+ -- * when printing for -ddump-xxx you can switch on -dppr-debug to get the+ -- uniques if you get confused+ -- * for interface files we tidyCore first, which makes+ -- the OccNames distinct when they need to be++mkClonedInternalName :: Unique -> Name -> Name+mkClonedInternalName uniq (Name { n_occ = occ, n_loc = loc })+ = Name { n_uniq = getKey uniq, n_sort = Internal+ , n_occ = occ, n_loc = loc }++mkDerivedInternalName :: (OccName -> OccName) -> Unique -> Name -> Name+mkDerivedInternalName derive_occ uniq (Name { n_occ = occ, n_loc = loc })+ = Name { n_uniq = getKey uniq, n_sort = Internal+ , n_occ = derive_occ occ, n_loc = loc }++-- | Create a name which definitely originates in the given module+mkExternalName :: Unique -> Module -> OccName -> SrcSpan -> Name+-- WATCH OUT! External Names should be in the Name Cache+-- (see Note [The Name Cache] in IfaceEnv), so don't just call mkExternalName+-- with some fresh unique without populating the Name Cache+mkExternalName uniq mod occ loc+ = Name { n_uniq = getKey uniq, n_sort = External mod,+ n_occ = occ, n_loc = loc }++-- | Create a name which is actually defined by the compiler itself+mkWiredInName :: Module -> OccName -> Unique -> TyThing -> BuiltInSyntax -> Name+mkWiredInName mod occ uniq thing built_in+ = Name { n_uniq = getKey uniq,+ n_sort = WiredIn mod thing built_in,+ n_occ = occ, n_loc = wiredInSrcSpan }++-- | Create a name brought into being by the compiler+mkSystemName :: Unique -> OccName -> Name+mkSystemName uniq occ = mkSystemNameAt uniq occ noSrcSpan++mkSystemNameAt :: Unique -> OccName -> SrcSpan -> Name+mkSystemNameAt uniq occ loc = Name { n_uniq = getKey uniq, n_sort = System+ , n_occ = occ, n_loc = loc }++mkSystemVarName :: Unique -> FastString -> Name+mkSystemVarName uniq fs = mkSystemName uniq (mkVarOccFS fs)++mkSysTvName :: Unique -> FastString -> Name+mkSysTvName uniq fs = mkSystemName uniq (mkOccNameFS tvName fs)++-- | Make a name for a foreign call+mkFCallName :: Unique -> String -> Name+mkFCallName uniq str = mkInternalName uniq (mkVarOcc str) noSrcSpan+ -- The encoded string completely describes the ccall++-- When we renumber/rename things, we need to be+-- able to change a Name's Unique to match the cached+-- one in the thing it's the name of. If you know what I mean.+setNameUnique :: Name -> Unique -> Name+setNameUnique name uniq = name {n_uniq = getKey uniq}++-- This is used for hsigs: we want to use the name of the originally exported+-- entity, but edit the location to refer to the reexport site+setNameLoc :: Name -> SrcSpan -> Name+setNameLoc name loc = name {n_loc = loc}++tidyNameOcc :: Name -> OccName -> Name+-- We set the OccName of a Name when tidying+-- In doing so, we change System --> Internal, so that when we print+-- it we don't get the unique by default. It's tidy now!+tidyNameOcc name@(Name { n_sort = System }) occ = name { n_occ = occ, n_sort = Internal}+tidyNameOcc name occ = name { n_occ = occ }++-- | Make the 'Name' into an internal name, regardless of what it was to begin with+localiseName :: Name -> Name+localiseName n = n { n_sort = Internal }++-- |Create a localised variant of a name.+--+-- If the name is external, encode the original's module name to disambiguate.+-- SPJ says: this looks like a rather odd-looking function; but it seems to+-- be used only during vectorisation, so I'm not going to worry+mkLocalisedOccName :: Module -> (Maybe String -> OccName -> OccName) -> Name -> OccName+mkLocalisedOccName this_mod mk_occ name = mk_occ origin (nameOccName name)+ where+ origin+ | nameIsLocalOrFrom this_mod name = Nothing+ | otherwise = Just (moduleNameColons . moduleName . nameModule $ name)++{-+************************************************************************+* *+\subsection{Hashing and comparison}+* *+************************************************************************+-}++cmpName :: Name -> Name -> Ordering+cmpName n1 n2 = n_uniq n1 `compare` n_uniq n2++-- | Compare Names lexicographically+-- This only works for Names that originate in the source code or have been+-- tidied.+stableNameCmp :: Name -> Name -> Ordering+stableNameCmp (Name { n_sort = s1, n_occ = occ1 })+ (Name { n_sort = s2, n_occ = occ2 })+ = (s1 `sort_cmp` s2) `thenCmp` (occ1 `compare` occ2)+ -- The ordinary compare on OccNames is lexicographic+ where+ -- Later constructors are bigger+ sort_cmp (External m1) (External m2) = m1 `stableModuleCmp` m2+ sort_cmp (External {}) _ = LT+ sort_cmp (WiredIn {}) (External {}) = GT+ sort_cmp (WiredIn m1 _ _) (WiredIn m2 _ _) = m1 `stableModuleCmp` m2+ sort_cmp (WiredIn {}) _ = LT+ sort_cmp Internal (External {}) = GT+ sort_cmp Internal (WiredIn {}) = GT+ sort_cmp Internal Internal = EQ+ sort_cmp Internal System = LT+ sort_cmp System System = EQ+ sort_cmp System _ = GT++{-+************************************************************************+* *+\subsection[Name-instances]{Instance declarations}+* *+************************************************************************+-}++instance Eq Name where+ a == b = case (a `compare` b) of { EQ -> True; _ -> False }+ a /= b = case (a `compare` b) of { EQ -> False; _ -> True }++instance Ord Name where+ a <= b = case (a `compare` b) of { LT -> True; EQ -> True; GT -> False }+ a < b = case (a `compare` b) of { LT -> True; EQ -> False; GT -> False }+ a >= b = case (a `compare` b) of { LT -> False; EQ -> True; GT -> True }+ a > b = case (a `compare` b) of { LT -> False; EQ -> False; GT -> True }+ compare a b = cmpName a b++instance Uniquable Name where+ getUnique = nameUnique++instance NamedThing Name where+ getName n = n++instance Data Name where+ -- don't traverse?+ toConstr _ = abstractConstr "Name"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "Name"++{-+************************************************************************+* *+\subsection{Binary}+* *+************************************************************************+-}++-- | Assumes that the 'Name' is a non-binding one. See+-- 'IfaceSyn.putIfaceTopBndr' and 'IfaceSyn.getIfaceTopBndr' for serializing+-- binding 'Name's. See 'UserData' for the rationale for this distinction.+instance Binary Name where+ put_ bh name =+ case getUserData bh of+ UserData{ ud_put_nonbinding_name = put_name } -> put_name bh name++ get bh =+ case getUserData bh of+ UserData { ud_get_name = get_name } -> get_name bh++{-+************************************************************************+* *+\subsection{Pretty printing}+* *+************************************************************************+-}++instance Outputable Name where+ ppr name = pprName name++instance OutputableBndr Name where+ pprBndr _ name = pprName name+ pprInfixOcc = pprInfixName+ pprPrefixOcc = pprPrefixName++pprName :: Name -> SDoc+pprName (Name {n_sort = sort, n_uniq = u, n_occ = occ})+ = getPprStyle $ \ sty ->+ case sort of+ WiredIn mod _ builtin -> pprExternal sty uniq mod occ True builtin+ External mod -> pprExternal sty uniq mod occ False UserSyntax+ System -> pprSystem sty uniq occ+ Internal -> pprInternal sty uniq occ+ where uniq = mkUniqueGrimily u++pprExternal :: PprStyle -> Unique -> Module -> OccName -> Bool -> BuiltInSyntax -> SDoc+pprExternal sty uniq mod occ is_wired is_builtin+ | codeStyle sty = ppr mod <> char '_' <> ppr_z_occ_name occ+ -- In code style, always qualify+ -- ToDo: maybe we could print all wired-in things unqualified+ -- in code style, to reduce symbol table bloat?+ | debugStyle sty = pp_mod <> ppr_occ_name occ+ <> braces (hsep [if is_wired then text "(w)" else empty,+ pprNameSpaceBrief (occNameSpace occ),+ pprUnique uniq])+ | BuiltInSyntax <- is_builtin = ppr_occ_name occ -- Never qualify builtin syntax+ | otherwise =+ if isHoleModule mod+ then case qualName sty mod occ of+ NameUnqual -> ppr_occ_name occ+ _ -> braces (ppr (moduleName mod) <> dot <> ppr_occ_name occ)+ else pprModulePrefix sty mod occ <> ppr_occ_name occ+ where+ pp_mod = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressModulePrefixes dflags+ then empty+ else ppr mod <> dot++pprInternal :: PprStyle -> Unique -> OccName -> SDoc+pprInternal sty uniq occ+ | codeStyle sty = pprUniqueAlways uniq+ | debugStyle sty = ppr_occ_name occ <> braces (hsep [pprNameSpaceBrief (occNameSpace occ),+ pprUnique uniq])+ | dumpStyle sty = ppr_occ_name occ <> ppr_underscore_unique uniq+ -- For debug dumps, we're not necessarily dumping+ -- tidied code, so we need to print the uniques.+ | otherwise = ppr_occ_name occ -- User style++-- Like Internal, except that we only omit the unique in Iface style+pprSystem :: PprStyle -> Unique -> OccName -> SDoc+pprSystem sty uniq occ+ | codeStyle sty = pprUniqueAlways uniq+ | debugStyle sty = ppr_occ_name occ <> ppr_underscore_unique uniq+ <> braces (pprNameSpaceBrief (occNameSpace occ))+ | otherwise = ppr_occ_name occ <> ppr_underscore_unique uniq+ -- If the tidy phase hasn't run, the OccName+ -- is unlikely to be informative (like 's'),+ -- so print the unique+++pprModulePrefix :: PprStyle -> Module -> OccName -> SDoc+-- Print the "M." part of a name, based on whether it's in scope or not+-- See Note [Printing original names] in HscTypes+pprModulePrefix sty mod occ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressModulePrefixes dflags+ then empty+ else+ case qualName sty mod occ of -- See Outputable.QualifyName:+ NameQual modname -> ppr modname <> dot -- Name is in scope+ NameNotInScope1 -> ppr mod <> dot -- Not in scope+ NameNotInScope2 -> ppr (moduleUnitId mod) <> colon -- Module not in+ <> ppr (moduleName mod) <> dot -- scope either+ NameUnqual -> empty -- In scope unqualified++pprUnique :: Unique -> SDoc+-- Print a unique unless we are suppressing them+pprUnique uniq+ = sdocWithDynFlags $ \dflags ->+ ppUnless (gopt Opt_SuppressUniques dflags) $+ pprUniqueAlways uniq++ppr_underscore_unique :: Unique -> SDoc+-- Print an underscore separating the name from its unique+-- But suppress it if we aren't printing the uniques anyway+ppr_underscore_unique uniq+ = sdocWithDynFlags $ \dflags ->+ ppUnless (gopt Opt_SuppressUniques dflags) $+ char '_' <> pprUniqueAlways uniq++ppr_occ_name :: OccName -> SDoc+ppr_occ_name occ = ftext (occNameFS occ)+ -- Don't use pprOccName; instead, just print the string of the OccName;+ -- we print the namespace in the debug stuff above++-- In code style, we Z-encode the strings. The results of Z-encoding each FastString are+-- cached behind the scenes in the FastString implementation.+ppr_z_occ_name :: OccName -> SDoc+ppr_z_occ_name occ = ztext (zEncodeFS (occNameFS occ))++-- Prints (if mod information is available) "Defined at <loc>" or+-- "Defined in <mod>" information for a Name.+pprDefinedAt :: Name -> SDoc+pprDefinedAt name = text "Defined" <+> pprNameDefnLoc name++pprNameDefnLoc :: Name -> SDoc+-- Prints "at <loc>" or+-- or "in <mod>" depending on what info is available+pprNameDefnLoc name+ = case nameSrcLoc name of+ -- nameSrcLoc rather than nameSrcSpan+ -- It seems less cluttered to show a location+ -- rather than a span for the definition point+ RealSrcLoc s -> text "at" <+> ppr s+ UnhelpfulLoc s+ | isInternalName name || isSystemName name+ -> text "at" <+> ftext s+ | otherwise+ -> text "in" <+> quotes (ppr (nameModule name))+++-- | Get a string representation of a 'Name' that's unique and stable+-- across recompilations. Used for deterministic generation of binds for+-- derived instances.+-- eg. "$aeson_70dylHtv1FFGeai1IoxcQr$Data.Aeson.Types.Internal$String"+nameStableString :: Name -> String+nameStableString Name{..} =+ nameSortStableString n_sort ++ "$" ++ occNameString n_occ++nameSortStableString :: NameSort -> String+nameSortStableString System = "$_sys"+nameSortStableString Internal = "$_in"+nameSortStableString (External mod) = moduleStableString mod+nameSortStableString (WiredIn mod _ _) = moduleStableString mod++{-+************************************************************************+* *+\subsection{Overloaded functions related to Names}+* *+************************************************************************+-}++-- | A class allowing convenient access to the 'Name' of various datatypes+class NamedThing a where+ getOccName :: a -> OccName+ getName :: a -> Name++ getOccName n = nameOccName (getName n) -- Default method++instance NamedThing e => NamedThing (GenLocated l e) where+ getName = getName . unLoc++getSrcLoc :: NamedThing a => a -> SrcLoc+getSrcSpan :: NamedThing a => a -> SrcSpan+getOccString :: NamedThing a => a -> String+getOccFS :: NamedThing a => a -> FastString++getSrcLoc = nameSrcLoc . getName+getSrcSpan = nameSrcSpan . getName+getOccString = occNameString . getOccName+getOccFS = occNameFS . getOccName++pprInfixName :: (Outputable a, NamedThing a) => a -> SDoc+-- See Outputable.pprPrefixVar, pprInfixVar;+-- add parens or back-quotes as appropriate+pprInfixName n = pprInfixVar (isSymOcc (getOccName n)) (ppr n)++pprPrefixName :: NamedThing a => a -> SDoc+pprPrefixName thing+ | name `hasKey` starKindTyConKey || name `hasKey` unicodeStarKindTyConKey+ = ppr name -- See Note [Special treatment for kind *]+ | otherwise+ = pprPrefixVar (isSymOcc (nameOccName name)) (ppr name)+ where+ name = getName thing++{-+Note [Special treatment for kind *]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Do not put parens around the kind '*'. Even though it looks like+an operator, it is really a special case.++This pprPrefixName stuff is really only used when printing HsSyn,+which has to be polymorphic in the name type, and hence has to go via+the overloaded function pprPrefixOcc. It's easier where we know the+type being pretty printed; eg the pretty-printing code in TyCoRep.++See Trac #7645, which led to this.+-}
+ basicTypes/Name.hs-boot view
@@ -0,0 +1,3 @@+module Name where++data Name
+ basicTypes/NameCache.hs view
@@ -0,0 +1,118 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE RankNTypes #-}++-- | The Name Cache+module NameCache+ ( lookupOrigNameCache+ , extendOrigNameCache+ , extendNameCache+ , initNameCache+ , NameCache(..), OrigNameCache+ ) where++import Module+import Name+import UniqSupply+import TysWiredIn+import Util+import Outputable+import PrelNames++#include "HsVersions.h"++{-++Note [The Name Cache]+~~~~~~~~~~~~~~~~~~~~~+The Name Cache makes sure that, during any invocation of GHC, each+External Name "M.x" has one, and only one globally-agreed Unique.++* The first time we come across M.x we make up a Unique and record that+ association in the Name Cache.++* When we come across "M.x" again, we look it up in the Name Cache,+ and get a hit.++The functions newGlobalBinder, allocateGlobalBinder do the main work.+When you make an External name, you should probably be calling one+of them.+++Note [Built-in syntax and the OrigNameCache]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Built-in syntax like tuples and unboxed sums are quite ubiquitous. To lower+their cost we use two tricks,++ a. We specially encode tuple and sum Names in interface files' symbol tables+ to avoid having to look up their names while loading interface files.+ Namely these names are encoded as by their Uniques. We know how to get from+ a Unique back to the Name which it represents via the mapping defined in+ the SumTupleUniques module. See Note [Symbol table representation of names]+ in BinIface and for details.++ b. We don't include them in the Orig name cache but instead parse their+ OccNames (in isBuiltInOcc_maybe) to avoid bloating the name cache with+ them.++Why is the second measure necessary? Good question; afterall, 1) the parser+emits built-in syntax directly as Exact RdrNames, and 2) built-in syntax never+needs to looked-up during interface loading due to (a). It turns out that there+are two reasons why we might look up an Orig RdrName for built-in syntax,++ * If you use setRdrNameSpace on an Exact RdrName it may be+ turned into an Orig RdrName.++ * Template Haskell turns a BuiltInSyntax Name into a TH.NameG+ (DsMeta.globalVar), and parses a NameG into an Orig RdrName+ (Convert.thRdrName). So, e.g. $(do { reify '(,); ... }) will+ go this route (Trac #8954).++-}++-- | Per-module cache of original 'OccName's given 'Name's+type OrigNameCache = ModuleEnv (OccEnv Name)++lookupOrigNameCache :: OrigNameCache -> Module -> OccName -> Maybe Name+lookupOrigNameCache nc mod occ+ | mod == gHC_TYPES || mod == gHC_PRIM || mod == gHC_TUPLE+ , Just name <- isBuiltInOcc_maybe occ+ = -- See Note [Known-key names], 3(c) in PrelNames+ -- Special case for tuples; there are too many+ -- of them to pre-populate the original-name cache+ Just name++ | otherwise+ = case lookupModuleEnv nc mod of+ Nothing -> Nothing+ Just occ_env -> lookupOccEnv occ_env occ++extendOrigNameCache :: OrigNameCache -> Name -> OrigNameCache+extendOrigNameCache nc name+ = ASSERT2( isExternalName name, ppr name )+ extendNameCache nc (nameModule name) (nameOccName name) name++extendNameCache :: OrigNameCache -> Module -> OccName -> Name -> OrigNameCache+extendNameCache nc mod occ name+ = extendModuleEnvWith combine nc mod (unitOccEnv occ name)+ where+ combine _ occ_env = extendOccEnv occ_env occ name++-- | The NameCache makes sure that there is just one Unique assigned for+-- each original name; i.e. (module-name, occ-name) pair and provides+-- something of a lookup mechanism for those names.+data NameCache+ = NameCache { nsUniqs :: !UniqSupply,+ -- ^ Supply of uniques+ nsNames :: !OrigNameCache+ -- ^ Ensures that one original name gets one unique+ }++-- | Return a function to atomically update the name cache.+initNameCache :: UniqSupply -> [Name] -> NameCache+initNameCache us names+ = NameCache { nsUniqs = us,+ nsNames = initOrigNames names }++initOrigNames :: [Name] -> OrigNameCache+initOrigNames names = foldl extendOrigNameCache emptyModuleEnv names
+ basicTypes/NameEnv.hs view
@@ -0,0 +1,151 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[NameEnv]{@NameEnv@: name environments}+-}++{-# LANGUAGE CPP #-}+module NameEnv (+ -- * Var, Id and TyVar environments (maps)+ NameEnv,++ -- ** Manipulating these environments+ mkNameEnv,+ emptyNameEnv, isEmptyNameEnv,+ unitNameEnv, nameEnvElts,+ extendNameEnv_C, extendNameEnv_Acc, extendNameEnv,+ extendNameEnvList, extendNameEnvList_C,+ filterNameEnv, anyNameEnv,+ plusNameEnv, plusNameEnv_C, alterNameEnv,+ lookupNameEnv, lookupNameEnv_NF, delFromNameEnv, delListFromNameEnv,+ elemNameEnv, mapNameEnv, disjointNameEnv,++ DNameEnv,++ emptyDNameEnv,+ lookupDNameEnv,+ mapDNameEnv,+ alterDNameEnv,+ -- ** Dependency analysis+ depAnal+ ) where++#include "HsVersions.h"++import Digraph+import Name+import UniqFM+import UniqDFM+import Maybes++{-+************************************************************************+* *+\subsection{Name environment}+* *+************************************************************************+-}++{-+Note [depAnal determinism]+~~~~~~~~~~~~~~~~~~~~~~~~~~+depAnal is deterministic provided it gets the nodes in a deterministic order.+The order of lists that get_defs and get_uses return doesn't matter, as these+are only used to construct the edges, and stronglyConnCompFromEdgedVertices is+deterministic even when the edges are not in deterministic order as explained+in Note [Deterministic SCC] in Digraph.+-}++depAnal :: (node -> [Name]) -- Defs+ -> (node -> [Name]) -- Uses+ -> [node]+ -> [SCC node]+-- Peform dependency analysis on a group of definitions,+-- where each definition may define more than one Name+--+-- The get_defs and get_uses functions are called only once per node+depAnal get_defs get_uses nodes+ = stronglyConnCompFromEdgedVerticesUniq (map mk_node keyed_nodes)+ where+ keyed_nodes = nodes `zip` [(1::Int)..]+ mk_node (node, key) = (node, key, mapMaybe (lookupNameEnv key_map) (get_uses node))++ key_map :: NameEnv Int -- Maps a Name to the key of the decl that defines it+ key_map = mkNameEnv [(name,key) | (node, key) <- keyed_nodes, name <- get_defs node]++{-+************************************************************************+* *+\subsection{Name environment}+* *+************************************************************************+-}++-- | Name Environment+type NameEnv a = UniqFM a -- Domain is Name++emptyNameEnv :: NameEnv a+isEmptyNameEnv :: NameEnv a -> Bool+mkNameEnv :: [(Name,a)] -> NameEnv a+nameEnvElts :: NameEnv a -> [a]+alterNameEnv :: (Maybe a-> Maybe a) -> NameEnv a -> Name -> NameEnv a+extendNameEnv_C :: (a->a->a) -> NameEnv a -> Name -> a -> NameEnv a+extendNameEnv_Acc :: (a->b->b) -> (a->b) -> NameEnv b -> Name -> a -> NameEnv b+extendNameEnv :: NameEnv a -> Name -> a -> NameEnv a+plusNameEnv :: NameEnv a -> NameEnv a -> NameEnv a+plusNameEnv_C :: (a->a->a) -> NameEnv a -> NameEnv a -> NameEnv a+extendNameEnvList :: NameEnv a -> [(Name,a)] -> NameEnv a+extendNameEnvList_C :: (a->a->a) -> NameEnv a -> [(Name,a)] -> NameEnv a+delFromNameEnv :: NameEnv a -> Name -> NameEnv a+delListFromNameEnv :: NameEnv a -> [Name] -> NameEnv a+elemNameEnv :: Name -> NameEnv a -> Bool+unitNameEnv :: Name -> a -> NameEnv a+lookupNameEnv :: NameEnv a -> Name -> Maybe a+lookupNameEnv_NF :: NameEnv a -> Name -> a+filterNameEnv :: (elt -> Bool) -> NameEnv elt -> NameEnv elt+anyNameEnv :: (elt -> Bool) -> NameEnv elt -> Bool+mapNameEnv :: (elt1 -> elt2) -> NameEnv elt1 -> NameEnv elt2+disjointNameEnv :: NameEnv a -> NameEnv a -> Bool++nameEnvElts x = eltsUFM x+emptyNameEnv = emptyUFM+isEmptyNameEnv = isNullUFM+unitNameEnv x y = unitUFM x y+extendNameEnv x y z = addToUFM x y z+extendNameEnvList x l = addListToUFM x l+lookupNameEnv x y = lookupUFM x y+alterNameEnv = alterUFM+mkNameEnv l = listToUFM l+elemNameEnv x y = elemUFM x y+plusNameEnv x y = plusUFM x y+plusNameEnv_C f x y = plusUFM_C f x y+extendNameEnv_C f x y z = addToUFM_C f x y z+mapNameEnv f x = mapUFM f x+extendNameEnv_Acc x y z a b = addToUFM_Acc x y z a b+extendNameEnvList_C x y z = addListToUFM_C x y z+delFromNameEnv x y = delFromUFM x y+delListFromNameEnv x y = delListFromUFM x y+filterNameEnv x y = filterUFM x y+anyNameEnv f x = foldUFM ((||) . f) False x+disjointNameEnv x y = isNullUFM (intersectUFM x y)++lookupNameEnv_NF env n = expectJust "lookupNameEnv_NF" (lookupNameEnv env n)++-- | Deterministic Name Environment+--+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why we need+-- DNameEnv.+type DNameEnv a = UniqDFM a++emptyDNameEnv :: DNameEnv a+emptyDNameEnv = emptyUDFM++lookupDNameEnv :: DNameEnv a -> Name -> Maybe a+lookupDNameEnv = lookupUDFM++mapDNameEnv :: (a -> b) -> DNameEnv a -> DNameEnv b+mapDNameEnv = mapUDFM++alterDNameEnv :: (Maybe a -> Maybe a) -> DNameEnv a -> Name -> DNameEnv a+alterDNameEnv = alterUDFM
+ basicTypes/NameSet.hs view
@@ -0,0 +1,212 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1998+-}++{-# LANGUAGE CPP #-}+module NameSet (+ -- * Names set type+ NameSet,++ -- ** Manipulating these sets+ emptyNameSet, unitNameSet, mkNameSet, unionNameSet, unionNameSets,+ minusNameSet, elemNameSet, extendNameSet, extendNameSetList,+ delFromNameSet, delListFromNameSet, isEmptyNameSet, filterNameSet,+ intersectsNameSet, intersectNameSet,+ nameSetAny, nameSetAll, nameSetElemsStable,++ -- * Free variables+ FreeVars,++ -- ** Manipulating sets of free variables+ isEmptyFVs, emptyFVs, plusFVs, plusFV,+ mkFVs, addOneFV, unitFV, delFV, delFVs,+ intersectFVs,++ -- * Defs and uses+ Defs, Uses, DefUse, DefUses,++ -- ** Manipulating defs and uses+ emptyDUs, usesOnly, mkDUs, plusDU,+ findUses, duDefs, duUses, allUses+ ) where++#include "HsVersions.h"++import Name+import UniqSet+import Data.List (sortBy)++{-+************************************************************************+* *+\subsection[Sets of names}+* *+************************************************************************+-}++type NameSet = UniqSet Name++emptyNameSet :: NameSet+unitNameSet :: Name -> NameSet+extendNameSetList :: NameSet -> [Name] -> NameSet+extendNameSet :: NameSet -> Name -> NameSet+mkNameSet :: [Name] -> NameSet+unionNameSet :: NameSet -> NameSet -> NameSet+unionNameSets :: [NameSet] -> NameSet+minusNameSet :: NameSet -> NameSet -> NameSet+elemNameSet :: Name -> NameSet -> Bool+isEmptyNameSet :: NameSet -> Bool+delFromNameSet :: NameSet -> Name -> NameSet+delListFromNameSet :: NameSet -> [Name] -> NameSet+filterNameSet :: (Name -> Bool) -> NameSet -> NameSet+intersectNameSet :: NameSet -> NameSet -> NameSet+intersectsNameSet :: NameSet -> NameSet -> Bool+-- ^ True if there is a non-empty intersection.+-- @s1 `intersectsNameSet` s2@ doesn't compute @s2@ if @s1@ is empty++isEmptyNameSet = isEmptyUniqSet+emptyNameSet = emptyUniqSet+unitNameSet = unitUniqSet+mkNameSet = mkUniqSet+extendNameSetList = addListToUniqSet+extendNameSet = addOneToUniqSet+unionNameSet = unionUniqSets+unionNameSets = unionManyUniqSets+minusNameSet = minusUniqSet+elemNameSet = elementOfUniqSet+delFromNameSet = delOneFromUniqSet+filterNameSet = filterUniqSet+intersectNameSet = intersectUniqSets++delListFromNameSet set ns = foldl delFromNameSet set ns++intersectsNameSet s1 s2 = not (isEmptyNameSet (s1 `intersectNameSet` s2))++nameSetAny :: (Name -> Bool) -> NameSet -> Bool+nameSetAny = uniqSetAny++nameSetAll :: (Name -> Bool) -> NameSet -> Bool+nameSetAll = uniqSetAll++-- | Get the elements of a NameSet with some stable ordering.+-- This only works for Names that originate in the source code or have been+-- tidied.+-- See Note [Deterministic UniqFM] to learn about nondeterminism+nameSetElemsStable :: NameSet -> [Name]+nameSetElemsStable ns =+ sortBy stableNameCmp $ nonDetEltsUniqSet ns+ -- It's OK to use nonDetEltsUniqSet here because we immediately sort+ -- with stableNameCmp++{-+************************************************************************+* *+\subsection{Free variables}+* *+************************************************************************++These synonyms are useful when we are thinking of free variables+-}++type FreeVars = NameSet++plusFV :: FreeVars -> FreeVars -> FreeVars+addOneFV :: FreeVars -> Name -> FreeVars+unitFV :: Name -> FreeVars+emptyFVs :: FreeVars+plusFVs :: [FreeVars] -> FreeVars+mkFVs :: [Name] -> FreeVars+delFV :: Name -> FreeVars -> FreeVars+delFVs :: [Name] -> FreeVars -> FreeVars+intersectFVs :: FreeVars -> FreeVars -> FreeVars++isEmptyFVs :: NameSet -> Bool+isEmptyFVs = isEmptyNameSet+emptyFVs = emptyNameSet+plusFVs = unionNameSets+plusFV = unionNameSet+mkFVs = mkNameSet+addOneFV = extendNameSet+unitFV = unitNameSet+delFV n s = delFromNameSet s n+delFVs ns s = delListFromNameSet s ns+intersectFVs = intersectNameSet++{-+************************************************************************+* *+ Defs and uses+* *+************************************************************************+-}++-- | A set of names that are defined somewhere+type Defs = NameSet++-- | A set of names that are used somewhere+type Uses = NameSet++-- | @(Just ds, us) =>@ The use of any member of the @ds@+-- implies that all the @us@ are used too.+-- Also, @us@ may mention @ds@.+--+-- @Nothing =>@ Nothing is defined in this group, but+-- nevertheless all the uses are essential.+-- Used for instance declarations, for example+type DefUse = (Maybe Defs, Uses)++-- | A number of 'DefUse's in dependency order: earlier 'Defs' scope over later 'Uses'+-- In a single (def, use) pair, the defs also scope over the uses+type DefUses = [DefUse]++emptyDUs :: DefUses+emptyDUs = []++usesOnly :: Uses -> DefUses+usesOnly uses = [(Nothing, uses)]++mkDUs :: [(Defs,Uses)] -> DefUses+mkDUs pairs = [(Just defs, uses) | (defs,uses) <- pairs]++plusDU :: DefUses -> DefUses -> DefUses+plusDU = (++)++duDefs :: DefUses -> Defs+duDefs dus = foldr get emptyNameSet dus+ where+ get (Nothing, _u1) d2 = d2+ get (Just d1, _u1) d2 = d1 `unionNameSet` d2++allUses :: DefUses -> Uses+-- ^ Just like 'duUses', but 'Defs' are not eliminated from the 'Uses' returned+allUses dus = foldr get emptyNameSet dus+ where+ get (_d1, u1) u2 = u1 `unionNameSet` u2++duUses :: DefUses -> Uses+-- ^ Collect all 'Uses', regardless of whether the group is itself used,+-- but remove 'Defs' on the way+duUses dus = foldr get emptyNameSet dus+ where+ get (Nothing, rhs_uses) uses = rhs_uses `unionNameSet` uses+ get (Just defs, rhs_uses) uses = (rhs_uses `unionNameSet` uses)+ `minusNameSet` defs++findUses :: DefUses -> Uses -> Uses+-- ^ Given some 'DefUses' and some 'Uses', find all the uses, transitively.+-- The result is a superset of the input 'Uses'; and includes things defined+-- in the input 'DefUses' (but only if they are used)+findUses dus uses+ = foldr get uses dus+ where+ get (Nothing, rhs_uses) uses+ = rhs_uses `unionNameSet` uses+ get (Just defs, rhs_uses) uses+ | defs `intersectsNameSet` uses -- Used+ || nameSetAny (startsWithUnderscore . nameOccName) defs+ -- At least one starts with an "_",+ -- so treat the group as used+ = rhs_uses `unionNameSet` uses+ | otherwise -- No def is used+ = uses
+ basicTypes/OccName.hs view
@@ -0,0 +1,959 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- #name_types#+-- GHC uses several kinds of name internally:+--+-- * 'OccName.OccName' represents names as strings with just a little more information:+-- the \"namespace\" that the name came from, e.g. the namespace of value, type constructors or+-- data constructors+--+-- * 'RdrName.RdrName': see "RdrName#name_types"+--+-- * 'Name.Name': see "Name#name_types"+--+-- * 'Id.Id': see "Id#name_types"+--+-- * 'Var.Var': see "Var#name_types"++module OccName (+ -- * The 'NameSpace' type+ NameSpace, -- Abstract++ nameSpacesRelated,++ -- ** Construction+ -- $real_vs_source_data_constructors+ tcName, clsName, tcClsName, dataName, varName,+ tvName, srcDataName,++ -- ** Pretty Printing+ pprNameSpace, pprNonVarNameSpace, pprNameSpaceBrief,++ -- * The 'OccName' type+ OccName, -- Abstract, instance of Outputable+ pprOccName,++ -- ** Construction+ mkOccName, mkOccNameFS,+ mkVarOcc, mkVarOccFS,+ mkDataOcc, mkDataOccFS,+ mkTyVarOcc, mkTyVarOccFS,+ mkTcOcc, mkTcOccFS,+ mkClsOcc, mkClsOccFS,+ mkDFunOcc,+ setOccNameSpace,+ demoteOccName,+ HasOccName(..),++ -- ** Derived 'OccName's+ isDerivedOccName,+ mkDataConWrapperOcc, mkWorkerOcc,+ mkMatcherOcc, mkBuilderOcc,+ mkDefaultMethodOcc, isDefaultMethodOcc, isTypeableBindOcc,+ mkNewTyCoOcc, mkClassOpAuxOcc,+ mkCon2TagOcc, mkTag2ConOcc, mkMaxTagOcc,+ mkClassDataConOcc, mkDictOcc, mkIPOcc,+ mkSpecOcc, mkForeignExportOcc, mkRepEqOcc,+ mkGenR, mkGen1R,+ mkDataTOcc, mkDataCOcc, mkDataConWorkerOcc,+ mkSuperDictSelOcc, mkSuperDictAuxOcc,+ mkLocalOcc, mkMethodOcc, mkInstTyTcOcc,+ mkInstTyCoOcc, mkEqPredCoOcc,+ mkVectOcc, mkVectTyConOcc, mkVectDataConOcc, mkVectIsoOcc,+ mkPDataTyConOcc, mkPDataDataConOcc,+ mkPDatasTyConOcc, mkPDatasDataConOcc,+ mkPReprTyConOcc,+ mkPADFunOcc,+ mkRecFldSelOcc,+ mkTyConRepOcc,++ -- ** Deconstruction+ occNameFS, occNameString, occNameSpace,++ isVarOcc, isTvOcc, isTcOcc, isDataOcc, isDataSymOcc, isSymOcc, isValOcc,+ parenSymOcc, startsWithUnderscore,++ isTcClsNameSpace, isTvNameSpace, isDataConNameSpace, isVarNameSpace, isValNameSpace,++ -- * The 'OccEnv' type+ OccEnv, emptyOccEnv, unitOccEnv, extendOccEnv, mapOccEnv,+ lookupOccEnv, mkOccEnv, mkOccEnv_C, extendOccEnvList, elemOccEnv,+ occEnvElts, foldOccEnv, plusOccEnv, plusOccEnv_C, extendOccEnv_C,+ extendOccEnv_Acc, filterOccEnv, delListFromOccEnv, delFromOccEnv,+ alterOccEnv, pprOccEnv,++ -- * The 'OccSet' type+ OccSet, emptyOccSet, unitOccSet, mkOccSet, extendOccSet,+ extendOccSetList,+ unionOccSets, unionManyOccSets, minusOccSet, elemOccSet,+ isEmptyOccSet, intersectOccSet, intersectsOccSet,+ filterOccSet,++ -- * Tidying up+ TidyOccEnv, emptyTidyOccEnv, initTidyOccEnv,+ tidyOccName,+ tidyOccNames, avoidClashesOccEnv,++ -- FsEnv+ FastStringEnv, emptyFsEnv, lookupFsEnv, extendFsEnv, mkFsEnv+ ) where++import Util+import Unique+import DynFlags+import UniqFM+import UniqSet+import FastString+import FastStringEnv+import Outputable+import Lexeme+import Binary+import Control.DeepSeq+import Data.List (mapAccumL)+import Data.Char+import Data.Data++{-+************************************************************************+* *+\subsection{Name space}+* *+************************************************************************+-}++data NameSpace = VarName -- Variables, including "real" data constructors+ | DataName -- "Source" data constructors+ | TvName -- Type variables+ | TcClsName -- Type constructors and classes; Haskell has them+ -- in the same name space for now.+ deriving( Eq, Ord )++-- Note [Data Constructors]+-- see also: Note [Data Constructor Naming] in DataCon.hs+--+-- $real_vs_source_data_constructors+-- There are two forms of data constructor:+--+-- [Source data constructors] The data constructors mentioned in Haskell source code+--+-- [Real data constructors] The data constructors of the representation type, which may not be the same as the source type+--+-- For example:+--+-- > data T = T !(Int, Int)+--+-- The source datacon has type @(Int, Int) -> T@+-- The real datacon has type @Int -> Int -> T@+--+-- GHC chooses a representation based on the strictness etc.++tcName, clsName, tcClsName :: NameSpace+dataName, srcDataName :: NameSpace+tvName, varName :: NameSpace++-- Though type constructors and classes are in the same name space now,+-- the NameSpace type is abstract, so we can easily separate them later+tcName = TcClsName -- Type constructors+clsName = TcClsName -- Classes+tcClsName = TcClsName -- Not sure which!++dataName = DataName+srcDataName = DataName -- Haskell-source data constructors should be+ -- in the Data name space++tvName = TvName+varName = VarName++isDataConNameSpace :: NameSpace -> Bool+isDataConNameSpace DataName = True+isDataConNameSpace _ = False++isTcClsNameSpace :: NameSpace -> Bool+isTcClsNameSpace TcClsName = True+isTcClsNameSpace _ = False++isTvNameSpace :: NameSpace -> Bool+isTvNameSpace TvName = True+isTvNameSpace _ = False++isVarNameSpace :: NameSpace -> Bool -- Variables or type variables, but not constructors+isVarNameSpace TvName = True+isVarNameSpace VarName = True+isVarNameSpace _ = False++isValNameSpace :: NameSpace -> Bool+isValNameSpace DataName = True+isValNameSpace VarName = True+isValNameSpace _ = False++pprNameSpace :: NameSpace -> SDoc+pprNameSpace DataName = text "data constructor"+pprNameSpace VarName = text "variable"+pprNameSpace TvName = text "type variable"+pprNameSpace TcClsName = text "type constructor or class"++pprNonVarNameSpace :: NameSpace -> SDoc+pprNonVarNameSpace VarName = empty+pprNonVarNameSpace ns = pprNameSpace ns++pprNameSpaceBrief :: NameSpace -> SDoc+pprNameSpaceBrief DataName = char 'd'+pprNameSpaceBrief VarName = char 'v'+pprNameSpaceBrief TvName = text "tv"+pprNameSpaceBrief TcClsName = text "tc"++-- demoteNameSpace lowers the NameSpace if possible. We can not know+-- in advance, since a TvName can appear in an HsTyVar.+-- See Note [Demotion] in RnEnv+demoteNameSpace :: NameSpace -> Maybe NameSpace+demoteNameSpace VarName = Nothing+demoteNameSpace DataName = Nothing+demoteNameSpace TvName = Nothing+demoteNameSpace TcClsName = Just DataName++{-+************************************************************************+* *+\subsection[Name-pieces-datatypes]{The @OccName@ datatypes}+* *+************************************************************************+-}++-- | Occurrence Name+--+-- In this context that means:+-- "classified (i.e. as a type name, value name, etc) but not qualified+-- and not yet resolved"+data OccName = OccName+ { occNameSpace :: !NameSpace+ , occNameFS :: !FastString+ }++instance Eq OccName where+ (OccName sp1 s1) == (OccName sp2 s2) = s1 == s2 && sp1 == sp2++instance Ord OccName where+ -- Compares lexicographically, *not* by Unique of the string+ compare (OccName sp1 s1) (OccName sp2 s2)+ = (s1 `compare` s2) `thenCmp` (sp1 `compare` sp2)++instance Data OccName where+ -- don't traverse?+ toConstr _ = abstractConstr "OccName"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "OccName"++instance HasOccName OccName where+ occName = id++instance NFData OccName where+ rnf x = x `seq` ()++{-+************************************************************************+* *+\subsection{Printing}+* *+************************************************************************+-}++instance Outputable OccName where+ ppr = pprOccName++instance OutputableBndr OccName where+ pprBndr _ = ppr+ pprInfixOcc n = pprInfixVar (isSymOcc n) (ppr n)+ pprPrefixOcc n = pprPrefixVar (isSymOcc n) (ppr n)++pprOccName :: OccName -> SDoc+pprOccName (OccName sp occ)+ = getPprStyle $ \ sty ->+ if codeStyle sty+ then ztext (zEncodeFS occ)+ else pp_occ <> pp_debug sty+ where+ pp_debug sty | debugStyle sty = braces (pprNameSpaceBrief sp)+ | otherwise = empty++ pp_occ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressUniques dflags+ then text (strip_th_unique (unpackFS occ))+ else ftext occ++ -- See Note [Suppressing uniques in OccNames]+ strip_th_unique ('[' : c : _) | isAlphaNum c = []+ strip_th_unique (c : cs) = c : strip_th_unique cs+ strip_th_unique [] = []++{-+Note [Suppressing uniques in OccNames]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This is a hack to de-wobblify the OccNames that contain uniques from+Template Haskell that have been turned into a string in the OccName.+See Note [Unique OccNames from Template Haskell] in Convert.hs++************************************************************************+* *+\subsection{Construction}+* *+************************************************************************+-}++mkOccName :: NameSpace -> String -> OccName+mkOccName occ_sp str = OccName occ_sp (mkFastString str)++mkOccNameFS :: NameSpace -> FastString -> OccName+mkOccNameFS occ_sp fs = OccName occ_sp fs++mkVarOcc :: String -> OccName+mkVarOcc s = mkOccName varName s++mkVarOccFS :: FastString -> OccName+mkVarOccFS fs = mkOccNameFS varName fs++mkDataOcc :: String -> OccName+mkDataOcc = mkOccName dataName++mkDataOccFS :: FastString -> OccName+mkDataOccFS = mkOccNameFS dataName++mkTyVarOcc :: String -> OccName+mkTyVarOcc = mkOccName tvName++mkTyVarOccFS :: FastString -> OccName+mkTyVarOccFS fs = mkOccNameFS tvName fs++mkTcOcc :: String -> OccName+mkTcOcc = mkOccName tcName++mkTcOccFS :: FastString -> OccName+mkTcOccFS = mkOccNameFS tcName++mkClsOcc :: String -> OccName+mkClsOcc = mkOccName clsName++mkClsOccFS :: FastString -> OccName+mkClsOccFS = mkOccNameFS clsName++-- demoteOccName lowers the Namespace of OccName.+-- see Note [Demotion]+demoteOccName :: OccName -> Maybe OccName+demoteOccName (OccName space name) = do+ space' <- demoteNameSpace space+ return $ OccName space' name++-- Name spaces are related if there is a chance to mean the one when one writes+-- the other, i.e. variables <-> data constructors and type variables <-> type constructors+nameSpacesRelated :: NameSpace -> NameSpace -> Bool+nameSpacesRelated ns1 ns2 = ns1 == ns2 || otherNameSpace ns1 == ns2++otherNameSpace :: NameSpace -> NameSpace+otherNameSpace VarName = DataName+otherNameSpace DataName = VarName+otherNameSpace TvName = TcClsName+otherNameSpace TcClsName = TvName++++{- | Other names in the compiler add additional information to an OccName.+This class provides a consistent way to access the underlying OccName. -}+class HasOccName name where+ occName :: name -> OccName++{-+************************************************************************+* *+ Environments+* *+************************************************************************++OccEnvs are used mainly for the envts in ModIfaces.++Note [The Unique of an OccName]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+They are efficient, because FastStrings have unique Int# keys. We assume+this key is less than 2^24, and indeed FastStrings are allocated keys+sequentially starting at 0.++So we can make a Unique using+ mkUnique ns key :: Unique+where 'ns' is a Char representing the name space. This in turn makes it+easy to build an OccEnv.+-}++instance Uniquable OccName where+ -- See Note [The Unique of an OccName]+ getUnique (OccName VarName fs) = mkVarOccUnique fs+ getUnique (OccName DataName fs) = mkDataOccUnique fs+ getUnique (OccName TvName fs) = mkTvOccUnique fs+ getUnique (OccName TcClsName fs) = mkTcOccUnique fs++newtype OccEnv a = A (UniqFM a)+ deriving Data++emptyOccEnv :: OccEnv a+unitOccEnv :: OccName -> a -> OccEnv a+extendOccEnv :: OccEnv a -> OccName -> a -> OccEnv a+extendOccEnvList :: OccEnv a -> [(OccName, a)] -> OccEnv a+lookupOccEnv :: OccEnv a -> OccName -> Maybe a+mkOccEnv :: [(OccName,a)] -> OccEnv a+mkOccEnv_C :: (a -> a -> a) -> [(OccName,a)] -> OccEnv a+elemOccEnv :: OccName -> OccEnv a -> Bool+foldOccEnv :: (a -> b -> b) -> b -> OccEnv a -> b+occEnvElts :: OccEnv a -> [a]+extendOccEnv_C :: (a->a->a) -> OccEnv a -> OccName -> a -> OccEnv a+extendOccEnv_Acc :: (a->b->b) -> (a->b) -> OccEnv b -> OccName -> a -> OccEnv b+plusOccEnv :: OccEnv a -> OccEnv a -> OccEnv a+plusOccEnv_C :: (a->a->a) -> OccEnv a -> OccEnv a -> OccEnv a+mapOccEnv :: (a->b) -> OccEnv a -> OccEnv b+delFromOccEnv :: OccEnv a -> OccName -> OccEnv a+delListFromOccEnv :: OccEnv a -> [OccName] -> OccEnv a+filterOccEnv :: (elt -> Bool) -> OccEnv elt -> OccEnv elt+alterOccEnv :: (Maybe elt -> Maybe elt) -> OccEnv elt -> OccName -> OccEnv elt++emptyOccEnv = A emptyUFM+unitOccEnv x y = A $ unitUFM x y+extendOccEnv (A x) y z = A $ addToUFM x y z+extendOccEnvList (A x) l = A $ addListToUFM x l+lookupOccEnv (A x) y = lookupUFM x y+mkOccEnv l = A $ listToUFM l+elemOccEnv x (A y) = elemUFM x y+foldOccEnv a b (A c) = foldUFM a b c+occEnvElts (A x) = eltsUFM x+plusOccEnv (A x) (A y) = A $ plusUFM x y+plusOccEnv_C f (A x) (A y) = A $ plusUFM_C f x y+extendOccEnv_C f (A x) y z = A $ addToUFM_C f x y z+extendOccEnv_Acc f g (A x) y z = A $ addToUFM_Acc f g x y z+mapOccEnv f (A x) = A $ mapUFM f x+mkOccEnv_C comb l = A $ addListToUFM_C comb emptyUFM l+delFromOccEnv (A x) y = A $ delFromUFM x y+delListFromOccEnv (A x) y = A $ delListFromUFM x y+filterOccEnv x (A y) = A $ filterUFM x y+alterOccEnv fn (A y) k = A $ alterUFM fn y k++instance Outputable a => Outputable (OccEnv a) where+ ppr x = pprOccEnv ppr x++pprOccEnv :: (a -> SDoc) -> OccEnv a -> SDoc+pprOccEnv ppr_elt (A env) = pprUniqFM ppr_elt env++type OccSet = UniqSet OccName++emptyOccSet :: OccSet+unitOccSet :: OccName -> OccSet+mkOccSet :: [OccName] -> OccSet+extendOccSet :: OccSet -> OccName -> OccSet+extendOccSetList :: OccSet -> [OccName] -> OccSet+unionOccSets :: OccSet -> OccSet -> OccSet+unionManyOccSets :: [OccSet] -> OccSet+minusOccSet :: OccSet -> OccSet -> OccSet+elemOccSet :: OccName -> OccSet -> Bool+isEmptyOccSet :: OccSet -> Bool+intersectOccSet :: OccSet -> OccSet -> OccSet+intersectsOccSet :: OccSet -> OccSet -> Bool+filterOccSet :: (OccName -> Bool) -> OccSet -> OccSet++emptyOccSet = emptyUniqSet+unitOccSet = unitUniqSet+mkOccSet = mkUniqSet+extendOccSet = addOneToUniqSet+extendOccSetList = addListToUniqSet+unionOccSets = unionUniqSets+unionManyOccSets = unionManyUniqSets+minusOccSet = minusUniqSet+elemOccSet = elementOfUniqSet+isEmptyOccSet = isEmptyUniqSet+intersectOccSet = intersectUniqSets+intersectsOccSet s1 s2 = not (isEmptyOccSet (s1 `intersectOccSet` s2))+filterOccSet = filterUniqSet++{-+************************************************************************+* *+\subsection{Predicates and taking them apart}+* *+************************************************************************+-}++occNameString :: OccName -> String+occNameString (OccName _ s) = unpackFS s++setOccNameSpace :: NameSpace -> OccName -> OccName+setOccNameSpace sp (OccName _ occ) = OccName sp occ++isVarOcc, isTvOcc, isTcOcc, isDataOcc :: OccName -> Bool++isVarOcc (OccName VarName _) = True+isVarOcc _ = False++isTvOcc (OccName TvName _) = True+isTvOcc _ = False++isTcOcc (OccName TcClsName _) = True+isTcOcc _ = False++-- | /Value/ 'OccNames's are those that are either in+-- the variable or data constructor namespaces+isValOcc :: OccName -> Bool+isValOcc (OccName VarName _) = True+isValOcc (OccName DataName _) = True+isValOcc _ = False++isDataOcc (OccName DataName _) = True+isDataOcc _ = False++-- | Test if the 'OccName' is a data constructor that starts with+-- a symbol (e.g. @:@, or @[]@)+isDataSymOcc :: OccName -> Bool+isDataSymOcc (OccName DataName s) = isLexConSym s+isDataSymOcc _ = False+-- Pretty inefficient!++-- | Test if the 'OccName' is that for any operator (whether+-- it is a data constructor or variable or whatever)+isSymOcc :: OccName -> Bool+isSymOcc (OccName DataName s) = isLexConSym s+isSymOcc (OccName TcClsName s) = isLexSym s+isSymOcc (OccName VarName s) = isLexSym s+isSymOcc (OccName TvName s) = isLexSym s+-- Pretty inefficient!++parenSymOcc :: OccName -> SDoc -> SDoc+-- ^ Wrap parens around an operator+parenSymOcc occ doc | isSymOcc occ = parens doc+ | otherwise = doc++startsWithUnderscore :: OccName -> Bool+-- ^ Haskell 98 encourages compilers to suppress warnings about unsed+-- names in a pattern if they start with @_@: this implements that test+startsWithUnderscore occ = headFS (occNameFS occ) == '_'++{-+************************************************************************+* *+\subsection{Making system names}+* *+************************************************************************++Here's our convention for splitting up the interface file name space:++ d... dictionary identifiers+ (local variables, so no name-clash worries)++All of these other OccNames contain a mixture of alphabetic+and symbolic characters, and hence cannot possibly clash with+a user-written type or function name++ $f... Dict-fun identifiers (from inst decls)+ $dmop Default method for 'op'+ $pnC n'th superclass selector for class C+ $wf Worker for function 'f'+ $sf.. Specialised version of f+ D:C Data constructor for dictionary for class C+ NTCo:T Coercion connecting newtype T with its representation type+ TFCo:R Coercion connecting a data family to its representation type R++In encoded form these appear as Zdfxxx etc++ :... keywords (export:, letrec: etc.)+--- I THINK THIS IS WRONG!++This knowledge is encoded in the following functions.++@mk_deriv@ generates an @OccName@ from the prefix and a string.+NB: The string must already be encoded!+-}++-- | Build an 'OccName' derived from another 'OccName'.+--+-- Note that the pieces of the name are passed in as a @[FastString]@ so that+-- the whole name can be constructed with a single 'concatFS', minimizing+-- unnecessary intermediate allocations.+mk_deriv :: NameSpace+ -> FastString -- ^ A prefix which distinguishes one sort of+ -- derived name from another+ -> [FastString] -- ^ The name we are deriving from in pieces which+ -- will be concatenated.+ -> OccName+mk_deriv occ_sp sys_prefix str =+ mkOccNameFS occ_sp (concatFS $ sys_prefix : str)++isDerivedOccName :: OccName -> Bool+-- ^ Test for definitions internally generated by GHC. This predicte+-- is used to suppress printing of internal definitions in some debug prints+isDerivedOccName occ =+ case occNameString occ of+ '$':c:_ | isAlphaNum c -> True -- E.g. $wfoo+ c:':':_ | isAlphaNum c -> True -- E.g. N:blah newtype coercions+ _other -> False++isDefaultMethodOcc :: OccName -> Bool+isDefaultMethodOcc occ =+ case occNameString occ of+ '$':'d':'m':_ -> True+ _ -> False++-- | Is an 'OccName' one of a Typeable @TyCon@ or @Module@ binding?+-- This is needed as these bindings are renamed differently.+-- See Note [Grand plan for Typeable] in TcTypeable.+isTypeableBindOcc :: OccName -> Bool+isTypeableBindOcc occ =+ case occNameString occ of+ '$':'t':'c':_ -> True -- mkTyConRepOcc+ '$':'t':'r':_ -> True -- Module binding+ _ -> False++mkDataConWrapperOcc, mkWorkerOcc,+ mkMatcherOcc, mkBuilderOcc,+ mkDefaultMethodOcc,+ mkClassDataConOcc, mkDictOcc,+ mkIPOcc, mkSpecOcc, mkForeignExportOcc, mkRepEqOcc,+ mkGenR, mkGen1R,+ mkDataConWorkerOcc, mkNewTyCoOcc,+ mkInstTyCoOcc, mkEqPredCoOcc, mkClassOpAuxOcc,+ mkCon2TagOcc, mkTag2ConOcc, mkMaxTagOcc,+ mkTyConRepOcc+ :: OccName -> OccName++-- These derived variables have a prefix that no Haskell value could have+mkDataConWrapperOcc = mk_simple_deriv varName "$W"+mkWorkerOcc = mk_simple_deriv varName "$w"+mkMatcherOcc = mk_simple_deriv varName "$m"+mkBuilderOcc = mk_simple_deriv varName "$b"+mkDefaultMethodOcc = mk_simple_deriv varName "$dm"+mkClassOpAuxOcc = mk_simple_deriv varName "$c"+mkDictOcc = mk_simple_deriv varName "$d"+mkIPOcc = mk_simple_deriv varName "$i"+mkSpecOcc = mk_simple_deriv varName "$s"+mkForeignExportOcc = mk_simple_deriv varName "$f"+mkRepEqOcc = mk_simple_deriv tvName "$r" -- In RULES involving Coercible+mkClassDataConOcc = mk_simple_deriv dataName "C:" -- Data con for a class+mkNewTyCoOcc = mk_simple_deriv tcName "N:" -- Coercion for newtypes+mkInstTyCoOcc = mk_simple_deriv tcName "D:" -- Coercion for type functions+mkEqPredCoOcc = mk_simple_deriv tcName "$co"++-- Used in derived instances+mkCon2TagOcc = mk_simple_deriv varName "$con2tag_"+mkTag2ConOcc = mk_simple_deriv varName "$tag2con_"+mkMaxTagOcc = mk_simple_deriv varName "$maxtag_"++-- TyConRepName stuff; see Note [Grand plan for Typeable] in TcTypeable+mkTyConRepOcc occ = mk_simple_deriv varName prefix occ+ where+ prefix | isDataOcc occ = "$tc'"+ | otherwise = "$tc"++-- Generic deriving mechanism+mkGenR = mk_simple_deriv tcName "Rep_"+mkGen1R = mk_simple_deriv tcName "Rep1_"++-- Vectorisation+mkVectOcc, mkVectTyConOcc, mkVectDataConOcc, mkVectIsoOcc,+ mkPADFunOcc, mkPReprTyConOcc,+ mkPDataTyConOcc, mkPDataDataConOcc,+ mkPDatasTyConOcc, mkPDatasDataConOcc+ :: Maybe String -> OccName -> OccName+mkVectOcc = mk_simple_deriv_with varName "$v"+mkVectTyConOcc = mk_simple_deriv_with tcName "V:"+mkVectDataConOcc = mk_simple_deriv_with dataName "VD:"+mkVectIsoOcc = mk_simple_deriv_with varName "$vi"+mkPADFunOcc = mk_simple_deriv_with varName "$pa"+mkPReprTyConOcc = mk_simple_deriv_with tcName "VR:"+mkPDataTyConOcc = mk_simple_deriv_with tcName "VP:"+mkPDatasTyConOcc = mk_simple_deriv_with tcName "VPs:"+mkPDataDataConOcc = mk_simple_deriv_with dataName "VPD:"+mkPDatasDataConOcc = mk_simple_deriv_with dataName "VPDs:"++-- Overloaded record field selectors+mkRecFldSelOcc :: String -> OccName+mkRecFldSelOcc s = mk_deriv varName "$sel" [fsLit s]++mk_simple_deriv :: NameSpace -> FastString -> OccName -> OccName+mk_simple_deriv sp px occ = mk_deriv sp px [occNameFS occ]++mk_simple_deriv_with :: NameSpace -- ^ the namespace+ -> FastString -- ^ an identifying prefix+ -> Maybe String -- ^ another optional prefix+ -> OccName -- ^ the 'OccName' to derive from+ -> OccName+mk_simple_deriv_with sp px Nothing occ = mk_deriv sp px [occNameFS occ]+mk_simple_deriv_with sp px (Just with) occ =+ mk_deriv sp px [fsLit with, fsLit "_", occNameFS occ]++-- Data constructor workers are made by setting the name space+-- of the data constructor OccName (which should be a DataName)+-- to VarName+mkDataConWorkerOcc datacon_occ = setOccNameSpace varName datacon_occ++mkSuperDictAuxOcc :: Int -> OccName -> OccName+mkSuperDictAuxOcc index cls_tc_occ+ = mk_deriv varName "$cp" [fsLit $ show index, occNameFS cls_tc_occ]++mkSuperDictSelOcc :: Int -- ^ Index of superclass, e.g. 3+ -> OccName -- ^ Class, e.g. @Ord@+ -> OccName -- ^ Derived 'Occname', e.g. @$p3Ord@+mkSuperDictSelOcc index cls_tc_occ+ = mk_deriv varName "$p" [fsLit $ show index, occNameFS cls_tc_occ]++mkLocalOcc :: Unique -- ^ Unique to combine with the 'OccName'+ -> OccName -- ^ Local name, e.g. @sat@+ -> OccName -- ^ Nice unique version, e.g. @$L23sat@+mkLocalOcc uniq occ+ = mk_deriv varName "$L" [fsLit $ show uniq, occNameFS occ]+ -- The Unique might print with characters+ -- that need encoding (e.g. 'z'!)++-- | Derive a name for the representation type constructor of a+-- @data@\/@newtype@ instance.+mkInstTyTcOcc :: String -- ^ Family name, e.g. @Map@+ -> OccSet -- ^ avoid these Occs+ -> OccName -- ^ @R:Map@+mkInstTyTcOcc str = chooseUniqueOcc tcName ('R' : ':' : str)++mkDFunOcc :: String -- ^ Typically the class and type glommed together e.g. @OrdMaybe@.+ -- Only used in debug mode, for extra clarity+ -> Bool -- ^ Is this a hs-boot instance DFun?+ -> OccSet -- ^ avoid these Occs+ -> OccName -- ^ E.g. @$f3OrdMaybe@++-- In hs-boot files we make dict funs like $fx7ClsTy, which get bound to the real+-- thing when we compile the mother module. Reason: we don't know exactly+-- what the mother module will call it.++mkDFunOcc info_str is_boot set+ = chooseUniqueOcc VarName (prefix ++ info_str) set+ where+ prefix | is_boot = "$fx"+ | otherwise = "$f"++mkDataTOcc, mkDataCOcc+ :: OccName -- ^ TyCon or data con string+ -> OccSet -- ^ avoid these Occs+ -> OccName -- ^ E.g. @$f3OrdMaybe@+-- data T = MkT ... deriving( Data ) needs definitions for+-- $tT :: Data.Generics.Basics.DataType+-- $cMkT :: Data.Generics.Basics.Constr+mkDataTOcc occ = chooseUniqueOcc VarName ("$t" ++ occNameString occ)+mkDataCOcc occ = chooseUniqueOcc VarName ("$c" ++ occNameString occ)++{-+Sometimes we need to pick an OccName that has not already been used,+given a set of in-use OccNames.+-}++chooseUniqueOcc :: NameSpace -> String -> OccSet -> OccName+chooseUniqueOcc ns str set = loop (mkOccName ns str) (0::Int)+ where+ loop occ n+ | occ `elemOccSet` set = loop (mkOccName ns (str ++ show n)) (n+1)+ | otherwise = occ++{-+We used to add a '$m' to indicate a method, but that gives rise to bad+error messages from the type checker when we print the function name or pattern+of an instance-decl binding. Why? Because the binding is zapped+to use the method name in place of the selector name.+(See TcClassDcl.tcMethodBind)++The way it is now, -ddump-xx output may look confusing, but+you can always say -dppr-debug to get the uniques.++However, we *do* have to zap the first character to be lower case,+because overloaded constructors (blarg) generate methods too.+And convert to VarName space++e.g. a call to constructor MkFoo where+ data (Ord a) => Foo a = MkFoo a++If this is necessary, we do it by prefixing '$m'. These+guys never show up in error messages. What a hack.+-}++mkMethodOcc :: OccName -> OccName+mkMethodOcc occ@(OccName VarName _) = occ+mkMethodOcc occ = mk_simple_deriv varName "$m" occ++{-+************************************************************************+* *+\subsection{Tidying them up}+* *+************************************************************************++Before we print chunks of code we like to rename it so that+we don't have to print lots of silly uniques in it. But we mustn't+accidentally introduce name clashes! So the idea is that we leave the+OccName alone unless it accidentally clashes with one that is already+in scope; if so, we tack on '1' at the end and try again, then '2', and+so on till we find a unique one.++There's a wrinkle for operators. Consider '>>='. We can't use '>>=1'+because that isn't a single lexeme. So we encode it to 'lle' and *then*+tack on the '1', if necessary.++Note [TidyOccEnv]+~~~~~~~~~~~~~~~~~+type TidyOccEnv = UniqFM Int++* Domain = The OccName's FastString. These FastStrings are "taken";+ make sure that we don't re-use++* Int, n = A plausible starting point for new guesses+ There is no guarantee that "FSn" is available;+ you must look that up in the TidyOccEnv. But+ it's a good place to start looking.++* When looking for a renaming for "foo2" we strip off the "2" and start+ with "foo". Otherwise if we tidy twice we get silly names like foo23.++ However, if it started with digits at the end, we always make a name+ with digits at the end, rather than shortening "foo2" to just "foo",+ even if "foo" is unused. Reasons:+ - Plain "foo" might be used later+ - We use trailing digits to subtly indicate a unification variable+ in typechecker error message; see TypeRep.tidyTyVarBndr++We have to take care though! Consider a machine-generated module (Trac #10370)+ module Foo where+ a1 = e1+ a2 = e2+ ...+ a2000 = e2000+Then "a1", "a2" etc are all marked taken. But now if we come across "a7" again,+we have to do a linear search to find a free one, "a2001". That might just be+acceptable once. But if we now come across "a8" again, we don't want to repeat+that search.++So we use the TidyOccEnv mapping for "a" (not "a7" or "a8") as our base for+starting the search; and we make sure to update the starting point for "a"+after we allocate a new one.+++Node [Tidying multiple names at once]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Consider++ > :t (id,id,id)++Every id contributes a type variable to the type signature, and all of them are+"a". If we tidy them one by one, we get++ (id,id,id) :: (a2 -> a2, a1 -> a1, a -> a)++which is a bit unfortunate, as it unfairly renames only one of them. What we+would like to see is++ (id,id,id) :: (a3 -> a3, a2 -> a2, a1 -> a1)++This is achieved in tidyOccNames. It still uses tidyOccName to rename each name+on its own, but it prepares the TidyEnv (using avoidClashesOccEnv), by “blocking” every+name that occurs twice in the map. This way, none of the "a"s will get the+priviledge of keeping this name, and all of them will get a suitable numbery by+tidyOccName.++It may be inappropriate to use tidyOccNames if the caller needs access to the+intermediate environments (e.g. to tidy the tyVarKind of a type variable). In that+case, avoidClashesOccEnv should be used directly, and tidyOccName afterwards.++This is #12382.++-}++type TidyOccEnv = UniqFM Int -- The in-scope OccNames+ -- See Note [TidyOccEnv]++emptyTidyOccEnv :: TidyOccEnv+emptyTidyOccEnv = emptyUFM++initTidyOccEnv :: [OccName] -> TidyOccEnv -- Initialise with names to avoid!+initTidyOccEnv = foldl add emptyUFM+ where+ add env (OccName _ fs) = addToUFM env fs 1++-- see Note [Tidying multiple names at once]+tidyOccNames :: TidyOccEnv -> [OccName] -> (TidyOccEnv, [OccName])+tidyOccNames env occs = mapAccumL tidyOccName env' occs+ where+ env' = avoidClashesOccEnv env occs++avoidClashesOccEnv :: TidyOccEnv -> [OccName] -> TidyOccEnv+avoidClashesOccEnv env occs = go env emptyUFM occs+ where+ go env _ [] = env+ go env seenOnce ((OccName _ fs):occs)+ | fs `elemUFM` env = go env seenOnce occs+ | fs `elemUFM` seenOnce = go (addToUFM env fs 1) seenOnce occs+ | otherwise = go env (addToUFM seenOnce fs ()) occs++tidyOccName :: TidyOccEnv -> OccName -> (TidyOccEnv, OccName)+tidyOccName env occ@(OccName occ_sp fs)+ | not (fs `elemUFM` env)+ = (addToUFM env fs 1, occ) -- Desired OccName is free+ | otherwise+ = case lookupUFM env base1 of+ Nothing -> (addToUFM env base1 2, OccName occ_sp base1)+ Just n -> find 1 n+ where+ base :: String -- Drop trailing digits (see Note [TidyOccEnv])+ base = dropWhileEndLE isDigit (unpackFS fs)+ base1 = mkFastString (base ++ "1")++ find !k !n+ = case lookupUFM env new_fs of+ Just {} -> find (k+1 :: Int) (n+k)+ -- By using n+k, the n argument to find goes+ -- 1, add 1, add 2, add 3, etc which+ -- moves at quadratic speed through a dense patch++ Nothing -> (new_env, OccName occ_sp new_fs)+ where+ new_fs = mkFastString (base ++ show n)+ new_env = addToUFM (addToUFM env new_fs 1) base1 (n+1)+ -- Update: base1, so that next time we'll start where we left off+ -- new_fs, so that we know it is taken+ -- If they are the same (n==1), the former wins+ -- See Note [TidyOccEnv]++{-+************************************************************************+* *+ Binary instance+ Here rather than BinIface because OccName is abstract+* *+************************************************************************+-}++instance Binary NameSpace where+ put_ bh VarName = do+ putByte bh 0+ put_ bh DataName = do+ putByte bh 1+ put_ bh TvName = do+ putByte bh 2+ put_ bh TcClsName = do+ putByte bh 3+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return VarName+ 1 -> do return DataName+ 2 -> do return TvName+ _ -> do return TcClsName++instance Binary OccName where+ put_ bh (OccName aa ab) = do+ put_ bh aa+ put_ bh ab+ get bh = do+ aa <- get bh+ ab <- get bh+ return (OccName aa ab)
+ basicTypes/OccName.hs-boot view
@@ -0,0 +1,3 @@+module OccName where++data OccName
+ basicTypes/PatSyn.hs view
@@ -0,0 +1,429 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1998++\section[PatSyn]{@PatSyn@: Pattern synonyms}+-}++{-# LANGUAGE CPP #-}++module PatSyn (+ -- * Main data types+ PatSyn, mkPatSyn,++ -- ** Type deconstruction+ patSynName, patSynArity, patSynIsInfix,+ patSynArgs,+ patSynMatcher, patSynBuilder,+ patSynUnivTyVarBinders, patSynExTyVars, patSynExTyVarBinders, patSynSig,+ patSynInstArgTys, patSynInstResTy, patSynFieldLabels,+ patSynFieldType,++ tidyPatSynIds, pprPatSynType+ ) where++#include "HsVersions.h"++import Type+import Name+import Outputable+import Unique+import Util+import BasicTypes+import Var+import FieldLabel++import qualified Data.Data as Data+import Data.Function+import Data.List++{-+************************************************************************+* *+\subsection{Pattern synonyms}+* *+************************************************************************+-}++-- | Pattern Synonym+--+-- See Note [Pattern synonym representation]+-- See Note [Pattern synonym signature contexts]+data PatSyn+ = MkPatSyn {+ psName :: Name,+ psUnique :: Unique, -- Cached from Name++ psArgs :: [Type],+ psArity :: Arity, -- == length psArgs+ psInfix :: Bool, -- True <=> declared infix+ psFieldLabels :: [FieldLabel], -- List of fields for a+ -- record pattern synonym+ -- INVARIANT: either empty if no+ -- record pat syn or same length as+ -- psArgs++ -- Universially-quantified type variables+ psUnivTyVars :: [TyVarBinder],++ -- Required dictionaries (may mention psUnivTyVars)+ psReqTheta :: ThetaType,++ -- Existentially-quantified type vars+ psExTyVars :: [TyVarBinder],++ -- Provided dictionaries (may mention psUnivTyVars or psExTyVars)+ psProvTheta :: ThetaType,++ -- Result type+ psOrigResTy :: Type, -- Mentions only psUnivTyVars++ -- See Note [Matchers and builders for pattern synonyms]+ psMatcher :: (Id, Bool),+ -- Matcher function.+ -- If Bool is True then prov_theta and arg_tys are empty+ -- and type is+ -- forall (p :: RuntimeRep) (r :: TYPE p) univ_tvs.+ -- req_theta+ -- => res_ty+ -- -> (forall ex_tvs. Void# -> r)+ -- -> (Void# -> r)+ -- -> r+ --+ -- Otherwise type is+ -- forall (p :: RuntimeRep) (r :: TYPE r) univ_tvs.+ -- req_theta+ -- => res_ty+ -- -> (forall ex_tvs. prov_theta => arg_tys -> r)+ -- -> (Void# -> r)+ -- -> r++ psBuilder :: Maybe (Id, Bool)+ -- Nothing => uni-directional pattern synonym+ -- Just (builder, is_unlifted) => bi-directional+ -- Builder function, of type+ -- forall univ_tvs, ex_tvs. (req_theta, prov_theta)+ -- => arg_tys -> res_ty+ -- See Note [Builder for pattern synonyms with unboxed type]+ }++{- Note [Pattern synonym signature contexts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a pattern synonym signature we write+ pattern P :: req => prov => t1 -> ... tn -> res_ty++Note that the "required" context comes first, then the "provided"+context. Moreover, the "required" context must not mention+existentially-bound type variables; that is, ones not mentioned in+res_ty. See lots of discussion in Trac #10928.++If there is no "provided" context, you can omit it; but you+can't omit the "required" part (unless you omit both).++Example 1:+ pattern P1 :: (Num a, Eq a) => b -> Maybe (a,b)+ pattern P1 x = Just (3,x)++ We require (Num a, Eq a) to match the 3; there is no provided+ context.++Example 2:+ data T2 where+ MkT2 :: (Num a, Eq a) => a -> a -> T2++ pattern P2 :: () => (Num a, Eq a) => a -> T2+ pattern P2 x = MkT2 3 x++ When we match against P2 we get a Num dictionary provided.+ We can use that to check the match against 3.++Example 3:+ pattern P3 :: Eq a => a -> b -> T3 b++ This signature is illegal because the (Eq a) is a required+ constraint, but it mentions the existentially-bound variable 'a'.+ You can see it's existential because it doesn't appear in the+ result type (T3 b).++Note [Pattern synonym representation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the following pattern synonym declaration++ pattern P x = MkT [x] (Just 42)++where+ data T a where+ MkT :: (Show a, Ord b) => [b] -> a -> T a++so pattern P has type++ b -> T (Maybe t)++with the following typeclass constraints:++ requires: (Eq t, Num t)+ provides: (Show (Maybe t), Ord b)++In this case, the fields of MkPatSyn will be set as follows:++ psArgs = [b]+ psArity = 1+ psInfix = False++ psUnivTyVars = [t]+ psExTyVars = [b]+ psProvTheta = (Show (Maybe t), Ord b)+ psReqTheta = (Eq t, Num t)+ psOrigResTy = T (Maybe t)++Note [Matchers and builders for pattern synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For each pattern synonym P, we generate++ * a "matcher" function, used to desugar uses of P in patterns,+ which implements pattern matching++ * A "builder" function (for bidirectional pattern synonyms only),+ used to desugar uses of P in expressions, which constructs P-values.++For the above example, the matcher function has type:++ $mP :: forall (r :: ?) t. (Eq t, Num t)+ => T (Maybe t)+ -> (forall b. (Show (Maybe t), Ord b) => b -> r)+ -> (Void# -> r)+ -> r++with the following implementation:++ $mP @r @t $dEq $dNum scrut cont fail+ = case scrut of+ MkT @b $dShow $dOrd [x] (Just 42) -> cont @b $dShow $dOrd x+ _ -> fail Void#++Notice that the return type 'r' has an open kind, so that it can+be instantiated by an unboxed type; for example where we see+ f (P x) = 3#++The extra Void# argument for the failure continuation is needed so that+it is lazy even when the result type is unboxed.++For the same reason, if the pattern has no arguments, an extra Void#+argument is added to the success continuation as well.++For *bidirectional* pattern synonyms, we also generate a "builder"+function which implements the pattern synonym in an expression+context. For our running example, it will be:++ $bP :: forall t b. (Eq t, Num t, Show (Maybe t), Ord b)+ => b -> T (Maybe t)+ $bP x = MkT [x] (Just 42)++NB: the existential/universal and required/provided split does not+apply to the builder since you are only putting stuff in, not getting+stuff out.++Injectivity of bidirectional pattern synonyms is checked in+tcPatToExpr which walks the pattern and returns its corresponding+expression when available.++Note [Builder for pattern synonyms with unboxed type]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For bidirectional pattern synonyms that have no arguments and have an+unboxed type, we add an extra Void# argument to the builder, else it+would be a top-level declaration with an unboxed type.++ pattern P = 0#++ $bP :: Void# -> Int#+ $bP _ = 0#++This means that when typechecking an occurrence of P in an expression,+we must remember that the builder has this void argument. This is+done by TcPatSyn.patSynBuilderOcc.++Note [Pattern synonyms and the data type Type]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The type of a pattern synonym is of the form (See Note+[Pattern synonym signatures]):++ forall univ_tvs. req => forall ex_tvs. prov => ...++We cannot in general represent this by a value of type Type:++ - if ex_tvs is empty, then req and prov cannot be distinguished from+ each other+ - if req is empty, then univ_tvs and ex_tvs cannot be distinguished+ from each other, and moreover, prov is seen as the "required" context+ (as it is the only context)+++************************************************************************+* *+\subsection{Instances}+* *+************************************************************************+-}++instance Eq PatSyn where+ (==) = (==) `on` getUnique+ (/=) = (/=) `on` getUnique++instance Uniquable PatSyn where+ getUnique = psUnique++instance NamedThing PatSyn where+ getName = patSynName++instance Outputable PatSyn where+ ppr = ppr . getName++instance OutputableBndr PatSyn where+ pprInfixOcc = pprInfixName . getName+ pprPrefixOcc = pprPrefixName . getName++instance Data.Data PatSyn where+ -- don't traverse?+ toConstr _ = abstractConstr "PatSyn"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "PatSyn"++{-+************************************************************************+* *+\subsection{Construction}+* *+************************************************************************+-}++-- | Build a new pattern synonym+mkPatSyn :: Name+ -> Bool -- ^ Is the pattern synonym declared infix?+ -> ([TyVarBinder], ThetaType) -- ^ Universially-quantified type variables+ -- and required dicts+ -> ([TyVarBinder], ThetaType) -- ^ Existentially-quantified type variables+ -- and provided dicts+ -> [Type] -- ^ Original arguments+ -> Type -- ^ Original result type+ -> (Id, Bool) -- ^ Name of matcher+ -> Maybe (Id, Bool) -- ^ Name of builder+ -> [FieldLabel] -- ^ Names of fields for+ -- a record pattern synonym+ -> PatSyn+ -- NB: The univ and ex vars are both in TyBinder form and TyVar form for+ -- convenience. All the TyBinders should be Named!+mkPatSyn name declared_infix+ (univ_tvs, req_theta)+ (ex_tvs, prov_theta)+ orig_args+ orig_res_ty+ matcher builder field_labels+ = MkPatSyn {psName = name, psUnique = getUnique name,+ psUnivTyVars = univ_tvs,+ psExTyVars = ex_tvs,+ psProvTheta = prov_theta, psReqTheta = req_theta,+ psInfix = declared_infix,+ psArgs = orig_args,+ psArity = length orig_args,+ psOrigResTy = orig_res_ty,+ psMatcher = matcher,+ psBuilder = builder,+ psFieldLabels = field_labels+ }++-- | The 'Name' of the 'PatSyn', giving it a unique, rooted identification+patSynName :: PatSyn -> Name+patSynName = psName++-- | Should the 'PatSyn' be presented infix?+patSynIsInfix :: PatSyn -> Bool+patSynIsInfix = psInfix++-- | Arity of the pattern synonym+patSynArity :: PatSyn -> Arity+patSynArity = psArity++patSynArgs :: PatSyn -> [Type]+patSynArgs = psArgs++patSynFieldLabels :: PatSyn -> [FieldLabel]+patSynFieldLabels = psFieldLabels++-- | Extract the type for any given labelled field of the 'DataCon'+patSynFieldType :: PatSyn -> FieldLabelString -> Type+patSynFieldType ps label+ = case find ((== label) . flLabel . fst) (psFieldLabels ps `zip` psArgs ps) of+ Just (_, ty) -> ty+ Nothing -> pprPanic "dataConFieldType" (ppr ps <+> ppr label)++patSynUnivTyVarBinders :: PatSyn -> [TyVarBinder]+patSynUnivTyVarBinders = psUnivTyVars++patSynExTyVars :: PatSyn -> [TyVar]+patSynExTyVars ps = binderVars (psExTyVars ps)++patSynExTyVarBinders :: PatSyn -> [TyVarBinder]+patSynExTyVarBinders = psExTyVars++patSynSig :: PatSyn -> ([TyVar], ThetaType, [TyVar], ThetaType, [Type], Type)+patSynSig (MkPatSyn { psUnivTyVars = univ_tvs, psExTyVars = ex_tvs+ , psProvTheta = prov, psReqTheta = req+ , psArgs = arg_tys, psOrigResTy = res_ty })+ = (binderVars univ_tvs, req, binderVars ex_tvs, prov, arg_tys, res_ty)++patSynMatcher :: PatSyn -> (Id,Bool)+patSynMatcher = psMatcher++patSynBuilder :: PatSyn -> Maybe (Id, Bool)+patSynBuilder = psBuilder++tidyPatSynIds :: (Id -> Id) -> PatSyn -> PatSyn+tidyPatSynIds tidy_fn ps@(MkPatSyn { psMatcher = matcher, psBuilder = builder })+ = ps { psMatcher = tidy_pr matcher, psBuilder = fmap tidy_pr builder }+ where+ tidy_pr (id, dummy) = (tidy_fn id, dummy)++patSynInstArgTys :: PatSyn -> [Type] -> [Type]+-- Return the types of the argument patterns+-- e.g. data D a = forall b. MkD a b (b->a)+-- pattern P f x y = MkD (x,True) y f+-- D :: forall a. forall b. a -> b -> (b->a) -> D a+-- P :: forall c. forall b. (b->(c,Bool)) -> c -> b -> P c+-- patSynInstArgTys P [Int,bb] = [bb->(Int,Bool), Int, bb]+-- NB: the inst_tys should be both universal and existential+patSynInstArgTys (MkPatSyn { psName = name, psUnivTyVars = univ_tvs+ , psExTyVars = ex_tvs, psArgs = arg_tys })+ inst_tys+ = ASSERT2( length tyvars == length inst_tys+ , text "patSynInstArgTys" <+> ppr name $$ ppr tyvars $$ ppr inst_tys )+ map (substTyWith tyvars inst_tys) arg_tys+ where+ tyvars = binderVars (univ_tvs ++ ex_tvs)++patSynInstResTy :: PatSyn -> [Type] -> Type+-- Return the type of whole pattern+-- E.g. pattern P x y = Just (x,x,y)+-- P :: a -> b -> Just (a,a,b)+-- (patSynInstResTy P [Int,Bool] = Maybe (Int,Int,Bool)+-- NB: unlikepatSynInstArgTys, the inst_tys should be just the *universal* tyvars+patSynInstResTy (MkPatSyn { psName = name, psUnivTyVars = univ_tvs+ , psOrigResTy = res_ty })+ inst_tys+ = ASSERT2( length univ_tvs == length inst_tys+ , text "patSynInstResTy" <+> ppr name $$ ppr univ_tvs $$ ppr inst_tys )+ substTyWith (binderVars univ_tvs) inst_tys res_ty++-- | Print the type of a pattern synonym. The foralls are printed explicitly+pprPatSynType :: PatSyn -> SDoc+pprPatSynType (MkPatSyn { psUnivTyVars = univ_tvs, psReqTheta = req_theta+ , psExTyVars = ex_tvs, psProvTheta = prov_theta+ , psArgs = orig_args, psOrigResTy = orig_res_ty })+ = sep [ pprForAll univ_tvs+ , pprThetaArrowTy req_theta+ , ppWhen insert_empty_ctxt $ parens empty <+> darrow+ , pprType sigma_ty ]+ where+ sigma_ty = mkForAllTys ex_tvs $+ mkFunTys prov_theta $+ mkFunTys orig_args orig_res_ty+ insert_empty_ctxt = null req_theta && not (null prov_theta && null ex_tvs)
+ basicTypes/PatSyn.hs-boot view
@@ -0,0 +1,13 @@+module PatSyn where++import BasicTypes (Arity)+import {-# SOURCE #-} TyCoRep (Type)+import Var (TyVar)+import Name (Name)++data PatSyn++patSynArity :: PatSyn -> Arity+patSynInstArgTys :: PatSyn -> [Type] -> [Type]+patSynExTyVars :: PatSyn -> [TyVar]+patSynName :: PatSyn -> Name
+ basicTypes/RdrName.hs view
@@ -0,0 +1,1243 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP, DeriveDataTypeable #-}++-- |+-- #name_types#+-- GHC uses several kinds of name internally:+--+-- * 'OccName.OccName': see "OccName#name_types"+--+-- * 'RdrName.RdrName' is the type of names that come directly from the parser. They+-- have not yet had their scoping and binding resolved by the renamer and can be+-- thought of to a first approximation as an 'OccName.OccName' with an optional module+-- qualifier+--+-- * 'Name.Name': see "Name#name_types"+--+-- * 'Id.Id': see "Id#name_types"+--+-- * 'Var.Var': see "Var#name_types"++module RdrName (+ -- * The main type+ RdrName(..), -- Constructors exported only to BinIface++ -- ** Construction+ mkRdrUnqual, mkRdrQual,+ mkUnqual, mkVarUnqual, mkQual, mkOrig,+ nameRdrName, getRdrName,++ -- ** Destruction+ rdrNameOcc, rdrNameSpace, demoteRdrName,+ isRdrDataCon, isRdrTyVar, isRdrTc, isQual, isQual_maybe, isUnqual,+ isOrig, isOrig_maybe, isExact, isExact_maybe, isSrcRdrName,++ -- * Local mapping of 'RdrName' to 'Name.Name'+ LocalRdrEnv, emptyLocalRdrEnv, extendLocalRdrEnv, extendLocalRdrEnvList,+ lookupLocalRdrEnv, lookupLocalRdrOcc,+ elemLocalRdrEnv, inLocalRdrEnvScope,+ localRdrEnvElts, delLocalRdrEnvList,++ -- * Global mapping of 'RdrName' to 'GlobalRdrElt's+ GlobalRdrEnv, emptyGlobalRdrEnv, mkGlobalRdrEnv, plusGlobalRdrEnv,+ lookupGlobalRdrEnv, extendGlobalRdrEnv, greOccName, shadowNames,+ pprGlobalRdrEnv, globalRdrEnvElts,+ lookupGRE_RdrName, lookupGRE_Name, lookupGRE_FieldLabel,+ getGRE_NameQualifier_maybes,+ transformGREs, pickGREs, pickGREsModExp,++ -- * GlobalRdrElts+ gresFromAvails, gresFromAvail, localGREsFromAvail, availFromGRE,+ greUsedRdrName, greRdrNames, greSrcSpan, greQualModName,+ gresToAvailInfo,++ -- ** Global 'RdrName' mapping elements: 'GlobalRdrElt', 'Provenance', 'ImportSpec'+ GlobalRdrElt(..), isLocalGRE, isRecFldGRE, greLabel,+ unQualOK, qualSpecOK, unQualSpecOK,+ pprNameProvenance,+ Parent(..),+ ImportSpec(..), ImpDeclSpec(..), ImpItemSpec(..),+ importSpecLoc, importSpecModule, isExplicitItem, bestImport+ ) where++#include "HsVersions.h"++import Module+import Name+import Avail+import NameSet+import Maybes+import SrcLoc+import FastString+import FieldLabel+import Outputable+import Unique+import UniqFM+import UniqSet+import Util+import NameEnv++import Data.Data+import Data.List( sortBy, foldl', nub )++{-+************************************************************************+* *+\subsection{The main data type}+* *+************************************************************************+-}++-- | Reader Name+--+-- Do not use the data constructors of RdrName directly: prefer the family+-- of functions that creates them, such as 'mkRdrUnqual'+--+-- - Note: A Located RdrName will only have API Annotations if it is a+-- compound one,+-- e.g.+--+-- > `bar`+-- > ( ~ )+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnType',+-- 'ApiAnnotation.AnnOpen' @'('@ or @'['@ or @'[:'@,+-- 'ApiAnnotation.AnnClose' @')'@ or @']'@ or @':]'@,,+-- 'ApiAnnotation.AnnBackquote' @'`'@,+-- 'ApiAnnotation.AnnVal','ApiAnnotation.AnnTildehsh',+-- 'ApiAnnotation.AnnTilde',++-- For details on above see note [Api annotations] in ApiAnnotation+data RdrName+ = Unqual OccName+ -- ^ Unqualified name+ --+ -- Used for ordinary, unqualified occurrences, e.g. @x@, @y@ or @Foo@.+ -- Create such a 'RdrName' with 'mkRdrUnqual'++ | Qual ModuleName OccName+ -- ^ Qualified name+ --+ -- A qualified name written by the user in+ -- /source/ code. The module isn't necessarily+ -- the module where the thing is defined;+ -- just the one from which it is imported.+ -- Examples are @Bar.x@, @Bar.y@ or @Bar.Foo@.+ -- Create such a 'RdrName' with 'mkRdrQual'++ | Orig Module OccName+ -- ^ Original name+ --+ -- An original name; the module is the /defining/ module.+ -- This is used when GHC generates code that will be fed+ -- into the renamer (e.g. from deriving clauses), but where+ -- we want to say \"Use Prelude.map dammit\". One of these+ -- can be created with 'mkOrig'++ | Exact Name+ -- ^ Exact name+ --+ -- We know exactly the 'Name'. This is used:+ --+ -- (1) When the parser parses built-in syntax like @[]@+ -- and @(,)@, but wants a 'RdrName' from it+ --+ -- (2) By Template Haskell, when TH has generated a unique name+ --+ -- Such a 'RdrName' can be created by using 'getRdrName' on a 'Name'+ deriving Data++{-+************************************************************************+* *+\subsection{Simple functions}+* *+************************************************************************+-}++instance HasOccName RdrName where+ occName = rdrNameOcc++rdrNameOcc :: RdrName -> OccName+rdrNameOcc (Qual _ occ) = occ+rdrNameOcc (Unqual occ) = occ+rdrNameOcc (Orig _ occ) = occ+rdrNameOcc (Exact name) = nameOccName name++rdrNameSpace :: RdrName -> NameSpace+rdrNameSpace = occNameSpace . rdrNameOcc++-- demoteRdrName lowers the NameSpace of RdrName.+-- see Note [Demotion] in OccName+demoteRdrName :: RdrName -> Maybe RdrName+demoteRdrName (Unqual occ) = fmap Unqual (demoteOccName occ)+demoteRdrName (Qual m occ) = fmap (Qual m) (demoteOccName occ)+demoteRdrName (Orig _ _) = panic "demoteRdrName"+demoteRdrName (Exact _) = panic "demoteRdrName"++ -- These two are the basic constructors+mkRdrUnqual :: OccName -> RdrName+mkRdrUnqual occ = Unqual occ++mkRdrQual :: ModuleName -> OccName -> RdrName+mkRdrQual mod occ = Qual mod occ++mkOrig :: Module -> OccName -> RdrName+mkOrig mod occ = Orig mod occ++---------------+ -- These two are used when parsing source files+ -- They do encode the module and occurrence names+mkUnqual :: NameSpace -> FastString -> RdrName+mkUnqual sp n = Unqual (mkOccNameFS sp n)++mkVarUnqual :: FastString -> RdrName+mkVarUnqual n = Unqual (mkVarOccFS n)++-- | Make a qualified 'RdrName' in the given namespace and where the 'ModuleName' and+-- the 'OccName' are taken from the first and second elements of the tuple respectively+mkQual :: NameSpace -> (FastString, FastString) -> RdrName+mkQual sp (m, n) = Qual (mkModuleNameFS m) (mkOccNameFS sp n)++getRdrName :: NamedThing thing => thing -> RdrName+getRdrName name = nameRdrName (getName name)++nameRdrName :: Name -> RdrName+nameRdrName name = Exact name+-- Keep the Name even for Internal names, so that the+-- unique is still there for debug printing, particularly+-- of Types (which are converted to IfaceTypes before printing)++nukeExact :: Name -> RdrName+nukeExact n+ | isExternalName n = Orig (nameModule n) (nameOccName n)+ | otherwise = Unqual (nameOccName n)++isRdrDataCon :: RdrName -> Bool+isRdrTyVar :: RdrName -> Bool+isRdrTc :: RdrName -> Bool++isRdrDataCon rn = isDataOcc (rdrNameOcc rn)+isRdrTyVar rn = isTvOcc (rdrNameOcc rn)+isRdrTc rn = isTcOcc (rdrNameOcc rn)++isSrcRdrName :: RdrName -> Bool+isSrcRdrName (Unqual _) = True+isSrcRdrName (Qual _ _) = True+isSrcRdrName _ = False++isUnqual :: RdrName -> Bool+isUnqual (Unqual _) = True+isUnqual _ = False++isQual :: RdrName -> Bool+isQual (Qual _ _) = True+isQual _ = False++isQual_maybe :: RdrName -> Maybe (ModuleName, OccName)+isQual_maybe (Qual m n) = Just (m,n)+isQual_maybe _ = Nothing++isOrig :: RdrName -> Bool+isOrig (Orig _ _) = True+isOrig _ = False++isOrig_maybe :: RdrName -> Maybe (Module, OccName)+isOrig_maybe (Orig m n) = Just (m,n)+isOrig_maybe _ = Nothing++isExact :: RdrName -> Bool+isExact (Exact _) = True+isExact _ = False++isExact_maybe :: RdrName -> Maybe Name+isExact_maybe (Exact n) = Just n+isExact_maybe _ = Nothing++{-+************************************************************************+* *+\subsection{Instances}+* *+************************************************************************+-}++instance Outputable RdrName where+ ppr (Exact name) = ppr name+ ppr (Unqual occ) = ppr occ+ ppr (Qual mod occ) = ppr mod <> dot <> ppr occ+ ppr (Orig mod occ) = getPprStyle (\sty -> pprModulePrefix sty mod occ <> ppr occ)++instance OutputableBndr RdrName where+ pprBndr _ n+ | isTvOcc (rdrNameOcc n) = char '@' <+> ppr n+ | otherwise = ppr n++ pprInfixOcc rdr = pprInfixVar (isSymOcc (rdrNameOcc rdr)) (ppr rdr)+ pprPrefixOcc rdr+ | Just name <- isExact_maybe rdr = pprPrefixName name+ -- pprPrefixName has some special cases, so+ -- we delegate to them rather than reproduce them+ | otherwise = pprPrefixVar (isSymOcc (rdrNameOcc rdr)) (ppr rdr)++instance Eq RdrName where+ (Exact n1) == (Exact n2) = n1==n2+ -- Convert exact to orig+ (Exact n1) == r2@(Orig _ _) = nukeExact n1 == r2+ r1@(Orig _ _) == (Exact n2) = r1 == nukeExact n2++ (Orig m1 o1) == (Orig m2 o2) = m1==m2 && o1==o2+ (Qual m1 o1) == (Qual m2 o2) = m1==m2 && o1==o2+ (Unqual o1) == (Unqual o2) = o1==o2+ _ == _ = False++instance Ord RdrName where+ a <= b = case (a `compare` b) of { LT -> True; EQ -> True; GT -> False }+ a < b = case (a `compare` b) of { LT -> True; EQ -> False; GT -> False }+ a >= b = case (a `compare` b) of { LT -> False; EQ -> True; GT -> True }+ a > b = case (a `compare` b) of { LT -> False; EQ -> False; GT -> True }++ -- Exact < Unqual < Qual < Orig+ -- [Note: Apr 2004] We used to use nukeExact to convert Exact to Orig+ -- before comparing so that Prelude.map == the exact Prelude.map, but+ -- that meant that we reported duplicates when renaming bindings+ -- generated by Template Haskell; e.g+ -- do { n1 <- newName "foo"; n2 <- newName "foo";+ -- <decl involving n1,n2> }+ -- I think we can do without this conversion+ compare (Exact n1) (Exact n2) = n1 `compare` n2+ compare (Exact _) _ = LT++ compare (Unqual _) (Exact _) = GT+ compare (Unqual o1) (Unqual o2) = o1 `compare` o2+ compare (Unqual _) _ = LT++ compare (Qual _ _) (Exact _) = GT+ compare (Qual _ _) (Unqual _) = GT+ compare (Qual m1 o1) (Qual m2 o2) = (o1 `compare` o2) `thenCmp` (m1 `compare` m2)+ compare (Qual _ _) (Orig _ _) = LT++ compare (Orig m1 o1) (Orig m2 o2) = (o1 `compare` o2) `thenCmp` (m1 `compare` m2)+ compare (Orig _ _) _ = GT++{-+************************************************************************+* *+ LocalRdrEnv+* *+************************************************************************+-}++-- | Local Reader Environment+--+-- This environment is used to store local bindings+-- (@let@, @where@, lambda, @case@).+-- It is keyed by OccName, because we never use it for qualified names+-- We keep the current mapping, *and* the set of all Names in scope+-- Reason: see Note [Splicing Exact names] in RnEnv+data LocalRdrEnv = LRE { lre_env :: OccEnv Name+ , lre_in_scope :: NameSet }++instance Outputable LocalRdrEnv where+ ppr (LRE {lre_env = env, lre_in_scope = ns})+ = hang (text "LocalRdrEnv {")+ 2 (vcat [ text "env =" <+> pprOccEnv ppr_elt env+ , text "in_scope ="+ <+> pprUFM (getUniqSet ns) (braces . pprWithCommas ppr)+ ] <+> char '}')+ where+ ppr_elt name = parens (ppr (getUnique (nameOccName name))) <+> ppr name+ -- So we can see if the keys line up correctly++emptyLocalRdrEnv :: LocalRdrEnv+emptyLocalRdrEnv = LRE { lre_env = emptyOccEnv+ , lre_in_scope = emptyNameSet }++extendLocalRdrEnv :: LocalRdrEnv -> Name -> LocalRdrEnv+-- The Name should be a non-top-level thing+extendLocalRdrEnv lre@(LRE { lre_env = env, lre_in_scope = ns }) name+ = WARN( isExternalName name, ppr name )+ lre { lre_env = extendOccEnv env (nameOccName name) name+ , lre_in_scope = extendNameSet ns name }++extendLocalRdrEnvList :: LocalRdrEnv -> [Name] -> LocalRdrEnv+extendLocalRdrEnvList lre@(LRE { lre_env = env, lre_in_scope = ns }) names+ = WARN( any isExternalName names, ppr names )+ lre { lre_env = extendOccEnvList env [(nameOccName n, n) | n <- names]+ , lre_in_scope = extendNameSetList ns names }++lookupLocalRdrEnv :: LocalRdrEnv -> RdrName -> Maybe Name+lookupLocalRdrEnv (LRE { lre_env = env, lre_in_scope = ns }) rdr+ | Unqual occ <- rdr+ = lookupOccEnv env occ++ -- See Note [Local bindings with Exact Names]+ | Exact name <- rdr+ , name `elemNameSet` ns+ = Just name++ | otherwise+ = Nothing++lookupLocalRdrOcc :: LocalRdrEnv -> OccName -> Maybe Name+lookupLocalRdrOcc (LRE { lre_env = env }) occ = lookupOccEnv env occ++elemLocalRdrEnv :: RdrName -> LocalRdrEnv -> Bool+elemLocalRdrEnv rdr_name (LRE { lre_env = env, lre_in_scope = ns })+ = case rdr_name of+ Unqual occ -> occ `elemOccEnv` env+ Exact name -> name `elemNameSet` ns -- See Note [Local bindings with Exact Names]+ Qual {} -> False+ Orig {} -> False++localRdrEnvElts :: LocalRdrEnv -> [Name]+localRdrEnvElts (LRE { lre_env = env }) = occEnvElts env++inLocalRdrEnvScope :: Name -> LocalRdrEnv -> Bool+-- This is the point of the NameSet+inLocalRdrEnvScope name (LRE { lre_in_scope = ns }) = name `elemNameSet` ns++delLocalRdrEnvList :: LocalRdrEnv -> [OccName] -> LocalRdrEnv+delLocalRdrEnvList lre@(LRE { lre_env = env }) occs+ = lre { lre_env = delListFromOccEnv env occs }++{-+Note [Local bindings with Exact Names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+With Template Haskell we can make local bindings that have Exact Names.+Computing shadowing etc may use elemLocalRdrEnv (at least it certainly+does so in RnTpes.bindHsQTyVars), so for an Exact Name we must consult+the in-scope-name-set.+++************************************************************************+* *+ GlobalRdrEnv+* *+************************************************************************+-}++-- | Global Reader Environment+type GlobalRdrEnv = OccEnv [GlobalRdrElt]+-- ^ Keyed by 'OccName'; when looking up a qualified name+-- we look up the 'OccName' part, and then check the 'Provenance'+-- to see if the appropriate qualification is valid. This+-- saves routinely doubling the size of the env by adding both+-- qualified and unqualified names to the domain.+--+-- The list in the codomain is required because there may be name clashes+-- These only get reported on lookup, not on construction+--+-- INVARIANT 1: All the members of the list have distinct+-- 'gre_name' fields; that is, no duplicate Names+--+-- INVARIANT 2: Imported provenance => Name is an ExternalName+-- However LocalDefs can have an InternalName. This+-- happens only when type-checking a [d| ... |] Template+-- Haskell quotation; see this note in RnNames+-- Note [Top-level Names in Template Haskell decl quotes]+--+-- INVARIANT 3: If the GlobalRdrEnv maps [occ -> gre], then+-- greOccName gre = occ+--+-- NB: greOccName gre is usually the same as+-- nameOccName (gre_name gre), but not always in the+-- case of record seectors; see greOccName++-- | Global Reader Element+--+-- An element of the 'GlobalRdrEnv'+data GlobalRdrElt+ = GRE { gre_name :: Name+ , gre_par :: Parent+ , gre_lcl :: Bool -- ^ True <=> the thing was defined locally+ , gre_imp :: [ImportSpec] -- ^ In scope through these imports+ } deriving (Data, Eq)+ -- INVARIANT: either gre_lcl = True or gre_imp is non-empty+ -- See Note [GlobalRdrElt provenance]++-- | The children of a Name are the things that are abbreviated by the ".."+-- notation in export lists. See Note [Parents]+data Parent = NoParent+ | ParentIs { par_is :: Name }+ | FldParent { par_is :: Name, par_lbl :: Maybe FieldLabelString }+ -- ^ See Note [Parents for record fields]+ deriving (Eq, Data, Typeable)++instance Outputable Parent where+ ppr NoParent = empty+ ppr (ParentIs n) = text "parent:" <> ppr n+ ppr (FldParent n f) = text "fldparent:"+ <> ppr n <> colon <> ppr f++plusParent :: Parent -> Parent -> Parent+-- See Note [Combining parents]+plusParent p1@(ParentIs _) p2 = hasParent p1 p2+plusParent p1@(FldParent _ _) p2 = hasParent p1 p2+plusParent p1 p2@(ParentIs _) = hasParent p2 p1+plusParent p1 p2@(FldParent _ _) = hasParent p2 p1+plusParent _ _ = NoParent++hasParent :: Parent -> Parent -> Parent+#ifdef DEBUG+hasParent p NoParent = p+hasParent p p'+ | p /= p' = pprPanic "hasParent" (ppr p <+> ppr p') -- Parents should agree+#endif+hasParent p _ = p+++{- Note [GlobalRdrElt provenance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The gre_lcl and gre_imp fields of a GlobalRdrElt describe its "provenance",+i.e. how the Name came to be in scope. It can be in scope two ways:+ - gre_lcl = True: it is bound in this module+ - gre_imp: a list of all the imports that brought it into scope++It's an INVARIANT that you have one or the other; that is, either+gre_lcl is True, or gre_imp is non-empty.++It is just possible to have *both* if there is a module loop: a Name+is defined locally in A, and also brought into scope by importing a+module that SOURCE-imported A. Exapmle (Trac #7672):++ A.hs-boot module A where+ data T++ B.hs module B(Decl.T) where+ import {-# SOURCE #-} qualified A as Decl++ A.hs module A where+ import qualified B+ data T = Z | S B.T++In A.hs, 'T' is locally bound, *and* imported as B.T.++Note [Parents]+~~~~~~~~~~~~~~~~~+ Parent Children+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ data T Data constructors+ Record-field ids++ data family T Data constructors and record-field ids+ of all visible data instances of T++ class C Class operations+ Associated type constructors++~~~~~~~~~~~~~~~~~~~~~~~~~+ Constructor Meaning+ ~~~~~~~~~~~~~~~~~~~~~~~~+ NoParent Can not be bundled with a type constructor.+ ParentIs n Can be bundled with the type constructor corresponding to+ n.+ FldParent See Note [Parents for record fields]+++++Note [Parents for record fields]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For record fields, in addition to the Name of the type constructor+(stored in par_is), we use FldParent to store the field label. This+extra information is used for identifying overloaded record fields+during renaming.++In a definition arising from a normal module (without+-XDuplicateRecordFields), par_lbl will be Nothing, meaning that the+field's label is the same as the OccName of the selector's Name. The+GlobalRdrEnv will contain an entry like this:++ "x" |-> GRE x (FldParent T Nothing) LocalDef++When -XDuplicateRecordFields is enabled for the module that contains+T, the selector's Name will be mangled (see comments in FieldLabel).+Thus we store the actual field label in par_lbl, and the GlobalRdrEnv+entry looks like this:++ "x" |-> GRE $sel:x:MkT (FldParent T (Just "x")) LocalDef++Note that the OccName used when adding a GRE to the environment+(greOccName) now depends on the parent field: for FldParent it is the+field label, if present, rather than the selector name.++~~++Record pattern synonym selectors are treated differently. Their parent+information is `NoParent` in the module in which they are defined. This is because+a pattern synonym `P` has no parent constructor either.++However, if `f` is bundled with a type constructor `T` then whenever `f` is+imported the parent will use the `Parent` constructor so the parent of `f` is+now `T`.+++Note [Combining parents]+~~~~~~~~~~~~~~~~~~~~~~~~+With an associated type we might have+ module M where+ class C a where+ data T a+ op :: T a -> a+ instance C Int where+ data T Int = TInt+ instance C Bool where+ data T Bool = TBool++Then: C is the parent of T+ T is the parent of TInt and TBool+So: in an export list+ C(..) is short for C( op, T )+ T(..) is short for T( TInt, TBool )++Module M exports everything, so its exports will be+ AvailTC C [C,T,op]+ AvailTC T [T,TInt,TBool]+On import we convert to GlobalRdrElt and then combine+those. For T that will mean we have+ one GRE with Parent C+ one GRE with NoParent+That's why plusParent picks the "best" case.+-}++-- | make a 'GlobalRdrEnv' where all the elements point to the same+-- Provenance (useful for "hiding" imports, or imports with no details).+gresFromAvails :: Maybe ImportSpec -> [AvailInfo] -> [GlobalRdrElt]+-- prov = Nothing => locally bound+-- Just spec => imported as described by spec+gresFromAvails prov avails+ = concatMap (gresFromAvail (const prov)) avails++localGREsFromAvail :: AvailInfo -> [GlobalRdrElt]+-- Turn an Avail into a list of LocalDef GlobalRdrElts+localGREsFromAvail = gresFromAvail (const Nothing)++gresFromAvail :: (Name -> Maybe ImportSpec) -> AvailInfo -> [GlobalRdrElt]+gresFromAvail prov_fn avail+ = map mk_gre (availNonFldNames avail) ++ map mk_fld_gre (availFlds avail)+ where+ mk_gre n+ = case prov_fn n of -- Nothing => bound locally+ -- Just is => imported from 'is'+ Nothing -> GRE { gre_name = n, gre_par = mkParent n avail+ , gre_lcl = True, gre_imp = [] }+ Just is -> GRE { gre_name = n, gre_par = mkParent n avail+ , gre_lcl = False, gre_imp = [is] }++ mk_fld_gre (FieldLabel { flLabel = lbl, flIsOverloaded = is_overloaded+ , flSelector = n })+ = case prov_fn n of -- Nothing => bound locally+ -- Just is => imported from 'is'+ Nothing -> GRE { gre_name = n, gre_par = FldParent (availName avail) mb_lbl+ , gre_lcl = True, gre_imp = [] }+ Just is -> GRE { gre_name = n, gre_par = FldParent (availName avail) mb_lbl+ , gre_lcl = False, gre_imp = [is] }+ where+ mb_lbl | is_overloaded = Just lbl+ | otherwise = Nothing+++greQualModName :: GlobalRdrElt -> ModuleName+-- Get a suitable module qualifier for the GRE+-- (used in mkPrintUnqualified)+-- Prerecondition: the gre_name is always External+greQualModName gre@(GRE { gre_name = name, gre_lcl = lcl, gre_imp = iss })+ | lcl, Just mod <- nameModule_maybe name = moduleName mod+ | (is:_) <- iss = is_as (is_decl is)+ | otherwise = pprPanic "greQualModName" (ppr gre)++greUsedRdrName :: GlobalRdrElt -> RdrName+-- For imported things, return a RdrName to add to the used-RdrName+-- set, which is used to generate unused-import-decl warnings.+-- Return a Qual RdrName if poss, so that identifies the most+-- specific ImportSpec. See Trac #10890 for some good examples.+greUsedRdrName gre@GRE{ gre_name = name, gre_lcl = lcl, gre_imp = iss }+ | lcl, Just mod <- nameModule_maybe name = Qual (moduleName mod) occ+ | not (null iss), is <- bestImport iss = Qual (is_as (is_decl is)) occ+ | otherwise = pprTrace "greUsedRdrName" (ppr gre) (Unqual occ)+ where+ occ = greOccName gre++greRdrNames :: GlobalRdrElt -> [RdrName]+greRdrNames gre@GRE{ gre_lcl = lcl, gre_imp = iss }+ = (if lcl then [unqual] else []) ++ concatMap do_spec (map is_decl iss)+ where+ occ = greOccName gre+ unqual = Unqual occ+ do_spec decl_spec+ | is_qual decl_spec = [qual]+ | otherwise = [unqual,qual]+ where qual = Qual (is_as decl_spec) occ++-- the SrcSpan that pprNameProvenance prints out depends on whether+-- the Name is defined locally or not: for a local definition the+-- definition site is used, otherwise the location of the import+-- declaration. We want to sort the export locations in+-- exportClashErr by this SrcSpan, we need to extract it:+greSrcSpan :: GlobalRdrElt -> SrcSpan+greSrcSpan gre@(GRE { gre_name = name, gre_lcl = lcl, gre_imp = iss } )+ | lcl = nameSrcSpan name+ | (is:_) <- iss = is_dloc (is_decl is)+ | otherwise = pprPanic "greSrcSpan" (ppr gre)++mkParent :: Name -> AvailInfo -> Parent+mkParent _ (Avail _) = NoParent+mkParent n (AvailTC m _ _) | n == m = NoParent+ | otherwise = ParentIs m++greParentName :: GlobalRdrElt -> Maybe Name+greParentName gre = case gre_par gre of+ NoParent -> Nothing+ ParentIs n -> Just n+ FldParent n _ -> Just n++-- | Takes a list of distinct GREs and folds them+-- into AvailInfos. This is more efficient than mapping each individual+-- GRE to an AvailInfo and the folding using `plusAvail` but needs the+-- uniqueness assumption.+gresToAvailInfo :: [GlobalRdrElt] -> [AvailInfo]+gresToAvailInfo gres+ = ASSERT( nub gres == gres ) nameEnvElts avail_env+ where+ avail_env :: NameEnv AvailInfo -- keyed by the parent+ avail_env = foldl' add emptyNameEnv gres++ add :: NameEnv AvailInfo -> GlobalRdrElt -> NameEnv AvailInfo+ add env gre = extendNameEnv_Acc comb availFromGRE env+ (fromMaybe (gre_name gre)+ (greParentName gre)) gre++ where+ -- We want to insert the child `k` into a list of children but+ -- need to maintain the invariant that the parent is first.+ --+ -- We also use the invariant that `k` is not already in `ns`.+ insertChildIntoChildren :: Name -> [Name] -> Name -> [Name]+ insertChildIntoChildren _ [] k = [k]+ insertChildIntoChildren p (n:ns) k+ | p == k = k:n:ns+ | otherwise = n:k:ns++ comb :: GlobalRdrElt -> AvailInfo -> AvailInfo+ comb _ (Avail n) = Avail n -- Duplicated name+ comb gre (AvailTC m ns fls) =+ let n = gre_name gre+ in case gre_par gre of+ NoParent -> AvailTC m (n:ns) fls -- Not sure this ever happens+ ParentIs {} -> AvailTC m (insertChildIntoChildren m ns n) fls+ FldParent _ mb_lbl -> AvailTC m ns (mkFieldLabel n mb_lbl : fls)++availFromGRE :: GlobalRdrElt -> AvailInfo+availFromGRE (GRE { gre_name = me, gre_par = parent })+ = case parent of+ ParentIs p -> AvailTC p [me] []+ NoParent | isTyConName me -> AvailTC me [me] []+ | otherwise -> avail me+ FldParent p mb_lbl -> AvailTC p [] [mkFieldLabel me mb_lbl]++mkFieldLabel :: Name -> Maybe FastString -> FieldLabel+mkFieldLabel me mb_lbl =+ case mb_lbl of+ Nothing -> FieldLabel { flLabel = occNameFS (nameOccName me)+ , flIsOverloaded = False+ , flSelector = me }+ Just lbl -> FieldLabel { flLabel = lbl+ , flIsOverloaded = True+ , flSelector = me }++emptyGlobalRdrEnv :: GlobalRdrEnv+emptyGlobalRdrEnv = emptyOccEnv++globalRdrEnvElts :: GlobalRdrEnv -> [GlobalRdrElt]+globalRdrEnvElts env = foldOccEnv (++) [] env++instance Outputable GlobalRdrElt where+ ppr gre = hang (ppr (gre_name gre) <+> ppr (gre_par gre))+ 2 (pprNameProvenance gre)++pprGlobalRdrEnv :: Bool -> GlobalRdrEnv -> SDoc+pprGlobalRdrEnv locals_only env+ = vcat [ text "GlobalRdrEnv" <+> ppWhen locals_only (ptext (sLit "(locals only)"))+ <+> lbrace+ , nest 2 (vcat [ pp (remove_locals gre_list) | gre_list <- occEnvElts env ]+ <+> rbrace) ]+ where+ remove_locals gres | locals_only = filter isLocalGRE gres+ | otherwise = gres+ pp [] = empty+ pp gres = hang (ppr occ+ <+> parens (text "unique" <+> ppr (getUnique occ))+ <> colon)+ 2 (vcat (map ppr gres))+ where+ occ = nameOccName (gre_name (head gres))++lookupGlobalRdrEnv :: GlobalRdrEnv -> OccName -> [GlobalRdrElt]+lookupGlobalRdrEnv env occ_name = case lookupOccEnv env occ_name of+ Nothing -> []+ Just gres -> gres++greOccName :: GlobalRdrElt -> OccName+greOccName (GRE{gre_par = FldParent{par_lbl = Just lbl}}) = mkVarOccFS lbl+greOccName gre = nameOccName (gre_name gre)++lookupGRE_RdrName :: RdrName -> GlobalRdrEnv -> [GlobalRdrElt]+lookupGRE_RdrName rdr_name env+ = case lookupOccEnv env (rdrNameOcc rdr_name) of+ Nothing -> []+ Just gres -> pickGREs rdr_name gres++lookupGRE_Name :: GlobalRdrEnv -> Name -> Maybe GlobalRdrElt+-- ^ Look for precisely this 'Name' in the environment. This tests+-- whether it is in scope, ignoring anything else that might be in+-- scope with the same 'OccName'.+lookupGRE_Name env name+ = lookupGRE_Name_OccName env name (nameOccName name)++lookupGRE_FieldLabel :: GlobalRdrEnv -> FieldLabel -> Maybe GlobalRdrElt+-- ^ Look for a particular record field selector in the environment, where the+-- selector name and field label may be different: the GlobalRdrEnv is keyed on+-- the label. See Note [Parents for record fields] for why this happens.+lookupGRE_FieldLabel env fl+ = lookupGRE_Name_OccName env (flSelector fl) (mkVarOccFS (flLabel fl))++lookupGRE_Name_OccName :: GlobalRdrEnv -> Name -> OccName -> Maybe GlobalRdrElt+-- ^ Look for precisely this 'Name' in the environment, but with an 'OccName'+-- that might differ from that of the 'Name'. See 'lookupGRE_FieldLabel' and+-- Note [Parents for record fields].+lookupGRE_Name_OccName env name occ+ = case [ gre | gre <- lookupGlobalRdrEnv env occ+ , gre_name gre == name ] of+ [] -> Nothing+ [gre] -> Just gre+ gres -> pprPanic "lookupGRE_Name_OccName"+ (ppr name $$ ppr occ $$ ppr gres)+ -- See INVARIANT 1 on GlobalRdrEnv+++getGRE_NameQualifier_maybes :: GlobalRdrEnv -> Name -> [Maybe [ModuleName]]+-- Returns all the qualifiers by which 'x' is in scope+-- Nothing means "the unqualified version is in scope"+-- [] means the thing is not in scope at all+getGRE_NameQualifier_maybes env name+ = case lookupGRE_Name env name of+ Just gre -> [qualifier_maybe gre]+ Nothing -> []+ where+ qualifier_maybe (GRE { gre_lcl = lcl, gre_imp = iss })+ | lcl = Nothing+ | otherwise = Just $ map (is_as . is_decl) iss++isLocalGRE :: GlobalRdrElt -> Bool+isLocalGRE (GRE {gre_lcl = lcl }) = lcl++isRecFldGRE :: GlobalRdrElt -> Bool+isRecFldGRE (GRE {gre_par = FldParent{}}) = True+isRecFldGRE _ = False++-- Returns the field label of this GRE, if it has one+greLabel :: GlobalRdrElt -> Maybe FieldLabelString+greLabel (GRE{gre_par = FldParent{par_lbl = Just lbl}}) = Just lbl+greLabel (GRE{gre_name = n, gre_par = FldParent{}}) = Just (occNameFS (nameOccName n))+greLabel _ = Nothing++unQualOK :: GlobalRdrElt -> Bool+-- ^ Test if an unqualified version of this thing would be in scope+unQualOK (GRE {gre_lcl = lcl, gre_imp = iss })+ | lcl = True+ | otherwise = any unQualSpecOK iss++{- Note [GRE filtering]+~~~~~~~~~~~~~~~~~~~~~~~+(pickGREs rdr gres) takes a list of GREs which have the same OccName+as 'rdr', say "x". It does two things:++(a) filters the GREs to a subset that are in scope+ * Qualified, as 'M.x' if want_qual is Qual M _+ * Unqualified, as 'x' if want_unqual is Unqual _++(b) for that subset, filter the provenance field (gre_lcl and gre_imp)+ to ones that brought it into scope qualified or unqualified resp.++Example:+ module A ( f ) where+ import qualified Foo( f )+ import Baz( f )+ f = undefined++Let's suppose that Foo.f and Baz.f are the same entity really, but the local+'f' is different, so there will be two GREs matching "f":+ gre1: gre_lcl = True, gre_imp = []+ gre2: gre_lcl = False, gre_imp = [ imported from Foo, imported from Bar ]++The use of "f" in the export list is ambiguous because it's in scope+from the local def and the import Baz(f); but *not* the import qualified Foo.+pickGREs returns two GRE+ gre1: gre_lcl = True, gre_imp = []+ gre2: gre_lcl = False, gre_imp = [ imported from Bar ]++Now the the "ambiguous occurrence" message can correctly report how the+ambiguity arises.+-}++pickGREs :: RdrName -> [GlobalRdrElt] -> [GlobalRdrElt]+-- ^ Takes a list of GREs which have the right OccName 'x'+-- Pick those GREs that are are in scope+-- * Qualified, as 'M.x' if want_qual is Qual M _+-- * Unqualified, as 'x' if want_unqual is Unqual _+--+-- Return each such GRE, with its ImportSpecs filtered, to reflect+-- how it is in scope qualified or unqualified respectively.+-- See Note [GRE filtering]+pickGREs (Unqual {}) gres = mapMaybe pickUnqualGRE gres+pickGREs (Qual mod _) gres = mapMaybe (pickQualGRE mod) gres+pickGREs _ _ = [] -- I don't think this actually happens++pickUnqualGRE :: GlobalRdrElt -> Maybe GlobalRdrElt+pickUnqualGRE gre@(GRE { gre_lcl = lcl, gre_imp = iss })+ | not lcl, null iss' = Nothing+ | otherwise = Just (gre { gre_imp = iss' })+ where+ iss' = filter unQualSpecOK iss++pickQualGRE :: ModuleName -> GlobalRdrElt -> Maybe GlobalRdrElt+pickQualGRE mod gre@(GRE { gre_name = n, gre_lcl = lcl, gre_imp = iss })+ | not lcl', null iss' = Nothing+ | otherwise = Just (gre { gre_lcl = lcl', gre_imp = iss' })+ where+ iss' = filter (qualSpecOK mod) iss+ lcl' = lcl && name_is_from mod n++ name_is_from :: ModuleName -> Name -> Bool+ name_is_from mod name = case nameModule_maybe name of+ Just n_mod -> moduleName n_mod == mod+ Nothing -> False++pickGREsModExp :: ModuleName -> [GlobalRdrElt] -> [(GlobalRdrElt,GlobalRdrElt)]+-- ^ Pick GREs that are in scope *both* qualified *and* unqualified+-- Return each GRE that is, as a pair+-- (qual_gre, unqual_gre)+-- These two GREs are the original GRE with imports filtered to express how+-- it is in scope qualified an unqualified respectively+--+-- Used only for the 'module M' item in export list;+-- see RnNames.exports_from_avail+pickGREsModExp mod gres = mapMaybe (pickBothGRE mod) gres++pickBothGRE :: ModuleName -> GlobalRdrElt -> Maybe (GlobalRdrElt, GlobalRdrElt)+pickBothGRE mod gre@(GRE { gre_name = n })+ | isBuiltInSyntax n = Nothing+ | Just gre1 <- pickQualGRE mod gre+ , Just gre2 <- pickUnqualGRE gre = Just (gre1, gre2)+ | otherwise = Nothing+ where+ -- isBuiltInSyntax filter out names for built-in syntax They+ -- just clutter up the environment (esp tuples), and the+ -- parser will generate Exact RdrNames for them, so the+ -- cluttered envt is no use. Really, it's only useful for+ -- GHC.Base and GHC.Tuple.++-- Building GlobalRdrEnvs++plusGlobalRdrEnv :: GlobalRdrEnv -> GlobalRdrEnv -> GlobalRdrEnv+plusGlobalRdrEnv env1 env2 = plusOccEnv_C (foldr insertGRE) env1 env2++mkGlobalRdrEnv :: [GlobalRdrElt] -> GlobalRdrEnv+mkGlobalRdrEnv gres+ = foldr add emptyGlobalRdrEnv gres+ where+ add gre env = extendOccEnv_Acc insertGRE singleton env+ (greOccName gre)+ gre++insertGRE :: GlobalRdrElt -> [GlobalRdrElt] -> [GlobalRdrElt]+insertGRE new_g [] = [new_g]+insertGRE new_g (old_g : old_gs)+ | gre_name new_g == gre_name old_g+ = new_g `plusGRE` old_g : old_gs+ | otherwise+ = old_g : insertGRE new_g old_gs++plusGRE :: GlobalRdrElt -> GlobalRdrElt -> GlobalRdrElt+-- Used when the gre_name fields match+plusGRE g1 g2+ = GRE { gre_name = gre_name g1+ , gre_lcl = gre_lcl g1 || gre_lcl g2+ , gre_imp = gre_imp g1 ++ gre_imp g2+ , gre_par = gre_par g1 `plusParent` gre_par g2 }++transformGREs :: (GlobalRdrElt -> GlobalRdrElt)+ -> [OccName]+ -> GlobalRdrEnv -> GlobalRdrEnv+-- ^ Apply a transformation function to the GREs for these OccNames+transformGREs trans_gre occs rdr_env+ = foldr trans rdr_env occs+ where+ trans occ env+ = case lookupOccEnv env occ of+ Just gres -> extendOccEnv env occ (map trans_gre gres)+ Nothing -> env++extendGlobalRdrEnv :: GlobalRdrEnv -> GlobalRdrElt -> GlobalRdrEnv+extendGlobalRdrEnv env gre+ = extendOccEnv_Acc insertGRE singleton env+ (greOccName gre) gre++shadowNames :: GlobalRdrEnv -> [Name] -> GlobalRdrEnv+shadowNames = foldl shadowName++{- Note [GlobalRdrEnv shadowing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Before adding new names to the GlobalRdrEnv we nuke some existing entries;+this is "shadowing". The actual work is done by RdrEnv.shadowNames.+There are two reasons for shadowing:++* The GHCi REPL++ - Ids bought into scope on the command line (eg let x = True) have+ External Names, like Ghci4.x. We want a new binding for 'x' (say)+ to override the existing binding for 'x'.+ See Note [Interactively-bound Ids in GHCi] in HscTypes++ - Data types also have Extenal Names, like Ghci4.T; but we still want+ 'T' to mean the newly-declared 'T', not an old one.++* Nested Template Haskell declaration brackets+ See Note [Top-level Names in Template Haskell decl quotes] in RnNames++ Consider a TH decl quote:+ module M where+ f x = h [d| f = 3 |]+ We must shadow the outer declaration of 'f', else we'll get a+ complaint when extending the GlobalRdrEnv, saying that there are two+ bindings for 'f'. There are several tricky points:++ - This shadowing applies even if the binding for 'f' is in a+ where-clause, and hence is in the *local* RdrEnv not the *global*+ RdrEnv. This is done in lcl_env_TH in extendGlobalRdrEnvRn.++ - The External Name M.f from the enclosing module must certainly+ still be available. So we don't nuke it entirely; we just make+ it seem like qualified import.++ - We only shadow *External* names (which come from the main module),+ or from earlier GHCi commands. Do not shadow *Internal* names+ because in the bracket+ [d| class C a where f :: a+ f = 4 |]+ rnSrcDecls will first call extendGlobalRdrEnvRn with C[f] from the+ class decl, and *separately* extend the envt with the value binding.+ At that stage, the class op 'f' will have an Internal name.+-}++shadowName :: GlobalRdrEnv -> Name -> GlobalRdrEnv+-- Remove certain old GREs that share the same OccName as this new Name.+-- See Note [GlobalRdrEnv shadowing] for details+shadowName env name+ = alterOccEnv (fmap alter_fn) env (nameOccName name)+ where+ alter_fn :: [GlobalRdrElt] -> [GlobalRdrElt]+ alter_fn gres = mapMaybe (shadow_with name) gres++ shadow_with :: Name -> GlobalRdrElt -> Maybe GlobalRdrElt+ shadow_with new_name+ old_gre@(GRE { gre_name = old_name, gre_lcl = lcl, gre_imp = iss })+ = case nameModule_maybe old_name of+ Nothing -> Just old_gre -- Old name is Internal; do not shadow+ Just old_mod+ | Just new_mod <- nameModule_maybe new_name+ , new_mod == old_mod -- Old name same as new name; shadow completely+ -> Nothing++ | null iss' -- Nothing remains+ -> Nothing++ | otherwise+ -> Just (old_gre { gre_lcl = False, gre_imp = iss' })++ where+ iss' = lcl_imp ++ mapMaybe (shadow_is new_name) iss+ lcl_imp | lcl = [mk_fake_imp_spec old_name old_mod]+ | otherwise = []++ mk_fake_imp_spec old_name old_mod -- Urgh!+ = ImpSpec id_spec ImpAll+ where+ old_mod_name = moduleName old_mod+ id_spec = ImpDeclSpec { is_mod = old_mod_name+ , is_as = old_mod_name+ , is_qual = True+ , is_dloc = nameSrcSpan old_name }++ shadow_is :: Name -> ImportSpec -> Maybe ImportSpec+ shadow_is new_name is@(ImpSpec { is_decl = id_spec })+ | Just new_mod <- nameModule_maybe new_name+ , is_as id_spec == moduleName new_mod+ = Nothing -- Shadow both qualified and unqualified+ | otherwise -- Shadow unqualified only+ = Just (is { is_decl = id_spec { is_qual = True } })+++{-+************************************************************************+* *+ ImportSpec+* *+************************************************************************+-}++-- | Import Specification+--+-- The 'ImportSpec' of something says how it came to be imported+-- It's quite elaborate so that we can give accurate unused-name warnings.+data ImportSpec = ImpSpec { is_decl :: ImpDeclSpec,+ is_item :: ImpItemSpec }+ deriving( Eq, Ord, Data )++-- | Import Declaration Specification+--+-- Describes a particular import declaration and is+-- shared among all the 'Provenance's for that decl+data ImpDeclSpec+ = ImpDeclSpec {+ is_mod :: ModuleName, -- ^ Module imported, e.g. @import Muggle@+ -- Note the @Muggle@ may well not be+ -- the defining module for this thing!++ -- TODO: either should be Module, or there+ -- should be a Maybe UnitId here too.+ is_as :: ModuleName, -- ^ Import alias, e.g. from @as M@ (or @Muggle@ if there is no @as@ clause)+ is_qual :: Bool, -- ^ Was this import qualified?+ is_dloc :: SrcSpan -- ^ The location of the entire import declaration+ } deriving Data++-- | Import Item Specification+--+-- Describes import info a particular Name+data ImpItemSpec+ = ImpAll -- ^ The import had no import list,+ -- or had a hiding list++ | ImpSome {+ is_explicit :: Bool,+ is_iloc :: SrcSpan -- Location of the import item+ } -- ^ The import had an import list.+ -- The 'is_explicit' field is @True@ iff the thing was named+ -- /explicitly/ in the import specs rather+ -- than being imported as part of a "..." group. Consider:+ --+ -- > import C( T(..) )+ --+ -- Here the constructors of @T@ are not named explicitly;+ -- only @T@ is named explicitly.+ deriving Data++instance Eq ImpDeclSpec where+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False++instance Ord ImpDeclSpec where+ compare is1 is2 = (is_mod is1 `compare` is_mod is2) `thenCmp`+ (is_dloc is1 `compare` is_dloc is2)++instance Eq ImpItemSpec where+ p1 == p2 = case p1 `compare` p2 of EQ -> True; _ -> False++instance Ord ImpItemSpec where+ compare is1 is2 =+ case (is1, is2) of+ (ImpAll, ImpAll) -> EQ+ (ImpAll, _) -> GT+ (_, ImpAll) -> LT+ (ImpSome _ l1, ImpSome _ l2) -> l1 `compare` l2+++bestImport :: [ImportSpec] -> ImportSpec+-- Given a non-empty bunch of ImportSpecs, return the one that+-- imported the item most specifically (e.g. by name), using+-- textually-first as a tie breaker. This is used when reporting+-- redundant imports+bestImport iss+ = case sortBy best iss of+ (is:_) -> is+ [] -> pprPanic "bestImport" (ppr iss)+ where+ best :: ImportSpec -> ImportSpec -> Ordering+ -- Less means better+ best (ImpSpec { is_item = item1, is_decl = d1 })+ (ImpSpec { is_item = item2, is_decl = d2 })+ = best_item item1 item2 `thenCmp` (is_dloc d1 `compare` is_dloc d2)++ best_item :: ImpItemSpec -> ImpItemSpec -> Ordering+ best_item ImpAll ImpAll = EQ+ best_item ImpAll (ImpSome {}) = GT+ best_item (ImpSome {}) ImpAll = LT+ best_item (ImpSome { is_explicit = e1 })+ (ImpSome { is_explicit = e2 }) = e2 `compare` e1+ -- False < True, so if e1 is explicit and e2 is not, we get LT++unQualSpecOK :: ImportSpec -> Bool+-- ^ Is in scope unqualified?+unQualSpecOK is = not (is_qual (is_decl is))++qualSpecOK :: ModuleName -> ImportSpec -> Bool+-- ^ Is in scope qualified with the given module?+qualSpecOK mod is = mod == is_as (is_decl is)++importSpecLoc :: ImportSpec -> SrcSpan+importSpecLoc (ImpSpec decl ImpAll) = is_dloc decl+importSpecLoc (ImpSpec _ item) = is_iloc item++importSpecModule :: ImportSpec -> ModuleName+importSpecModule is = is_mod (is_decl is)++isExplicitItem :: ImpItemSpec -> Bool+isExplicitItem ImpAll = False+isExplicitItem (ImpSome {is_explicit = exp}) = exp++pprNameProvenance :: GlobalRdrElt -> SDoc+-- ^ Print out one place where the name was define/imported+-- (With -dppr-debug, print them all)+pprNameProvenance (GRE { gre_name = name, gre_lcl = lcl, gre_imp = iss })+ = sdocWithPprDebug $ \dbg -> if dbg+ then vcat pp_provs+ else head pp_provs+ where+ pp_provs = pp_lcl ++ map pp_is iss+ pp_lcl = if lcl then [text "defined at" <+> ppr (nameSrcLoc name)]+ else []+ pp_is is = sep [ppr is, ppr_defn_site is name]++-- If we know the exact definition point (which we may do with GHCi)+-- then show that too. But not if it's just "imported from X".+ppr_defn_site :: ImportSpec -> Name -> SDoc+ppr_defn_site imp_spec name+ | same_module && not (isGoodSrcSpan loc)+ = empty -- Nothing interesting to say+ | otherwise+ = parens $ hang (text "and originally defined" <+> pp_mod)+ 2 (pprLoc loc)+ where+ loc = nameSrcSpan name+ defining_mod = ASSERT2( isExternalName name, ppr name ) nameModule name+ same_module = importSpecModule imp_spec == moduleName defining_mod+ pp_mod | same_module = empty+ | otherwise = text "in" <+> quotes (ppr defining_mod)+++instance Outputable ImportSpec where+ ppr imp_spec+ = text "imported" <+> qual+ <+> text "from" <+> quotes (ppr (importSpecModule imp_spec))+ <+> pprLoc (importSpecLoc imp_spec)+ where+ qual | is_qual (is_decl imp_spec) = text "qualified"+ | otherwise = empty++pprLoc :: SrcSpan -> SDoc+pprLoc (RealSrcSpan s) = text "at" <+> ppr s+pprLoc (UnhelpfulSpan {}) = empty
+ basicTypes/SrcLoc.hs view
@@ -0,0 +1,587 @@+-- (c) The University of Glasgow, 1992-2006++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RecordWildCards #-}+{-# OPTIONS_GHC -fno-omit-interface-pragmas #-}+ -- Workaround for Trac #5252 crashes the bootstrap compiler without -O+ -- When the earliest compiler we want to boostrap with is+ -- GHC 7.2, we can make RealSrcLoc properly abstract++-- | This module contains types that relate to the positions of things+-- in source files, and allow tagging of those things with locations+module SrcLoc (+ -- * SrcLoc+ RealSrcLoc, -- Abstract+ SrcLoc(..),++ -- ** Constructing SrcLoc+ mkSrcLoc, mkRealSrcLoc, mkGeneralSrcLoc,++ noSrcLoc, -- "I'm sorry, I haven't a clue"+ generatedSrcLoc, -- Code generated within the compiler+ interactiveSrcLoc, -- Code from an interactive session++ advanceSrcLoc,++ -- ** Unsafely deconstructing SrcLoc+ -- These are dubious exports, because they crash on some inputs+ srcLocFile, -- return the file name part+ srcLocLine, -- return the line part+ srcLocCol, -- return the column part++ -- * SrcSpan+ RealSrcSpan, -- Abstract+ SrcSpan(..),++ -- ** Constructing SrcSpan+ mkGeneralSrcSpan, mkSrcSpan, mkRealSrcSpan,+ noSrcSpan,+ wiredInSrcSpan, -- Something wired into the compiler+ interactiveSrcSpan,+ srcLocSpan, realSrcLocSpan,+ combineSrcSpans,+ srcSpanFirstCharacter,++ -- ** Deconstructing SrcSpan+ srcSpanStart, srcSpanEnd,+ realSrcSpanStart, realSrcSpanEnd,+ srcSpanFileName_maybe,+ pprUserRealSpan,++ -- ** Unsafely deconstructing SrcSpan+ -- These are dubious exports, because they crash on some inputs+ srcSpanFile,+ srcSpanStartLine, srcSpanEndLine,+ srcSpanStartCol, srcSpanEndCol,++ -- ** Predicates on SrcSpan+ isGoodSrcSpan, isOneLineSpan,+ containsSpan,++ -- * Located+ Located,+ RealLocated,+ GenLocated(..),++ -- ** Constructing Located+ noLoc,+ mkGeneralLocated,++ -- ** Deconstructing Located+ getLoc, unLoc,++ -- ** Combining and comparing Located values+ eqLocated, cmpLocated, combineLocs, addCLoc,+ leftmost_smallest, leftmost_largest, rightmost,+ spans, isSubspanOf, sortLocated+ ) where++import Util+import Json+import Outputable+import FastString++import Control.DeepSeq+import Data.Bits+import Data.Data+import Data.List+import Data.Ord++{-+************************************************************************+* *+\subsection[SrcLoc-SrcLocations]{Source-location information}+* *+************************************************************************++We keep information about the {\em definition} point for each entity;+this is the obvious stuff:+-}++-- | Real Source Location+--+-- Represents a single point within a file+data RealSrcLoc+ = SrcLoc FastString -- A precise location (file name)+ {-# UNPACK #-} !Int -- line number, begins at 1+ {-# UNPACK #-} !Int -- column number, begins at 1+ deriving (Eq, Ord)++-- | Source Location+data SrcLoc+ = RealSrcLoc {-# UNPACK #-}!RealSrcLoc+ | UnhelpfulLoc FastString -- Just a general indication+ deriving (Eq, Ord, Show)++{-+************************************************************************+* *+\subsection[SrcLoc-access-fns]{Access functions}+* *+************************************************************************+-}++mkSrcLoc :: FastString -> Int -> Int -> SrcLoc+mkSrcLoc x line col = RealSrcLoc (mkRealSrcLoc x line col)++mkRealSrcLoc :: FastString -> Int -> Int -> RealSrcLoc+mkRealSrcLoc x line col = SrcLoc x line col++-- | Built-in "bad" 'SrcLoc' values for particular locations+noSrcLoc, generatedSrcLoc, interactiveSrcLoc :: SrcLoc+noSrcLoc = UnhelpfulLoc (fsLit "<no location info>")+generatedSrcLoc = UnhelpfulLoc (fsLit "<compiler-generated code>")+interactiveSrcLoc = UnhelpfulLoc (fsLit "<interactive>")++-- | Creates a "bad" 'SrcLoc' that has no detailed information about its location+mkGeneralSrcLoc :: FastString -> SrcLoc+mkGeneralSrcLoc = UnhelpfulLoc++-- | Gives the filename of the 'RealSrcLoc'+srcLocFile :: RealSrcLoc -> FastString+srcLocFile (SrcLoc fname _ _) = fname++-- | Raises an error when used on a "bad" 'SrcLoc'+srcLocLine :: RealSrcLoc -> Int+srcLocLine (SrcLoc _ l _) = l++-- | Raises an error when used on a "bad" 'SrcLoc'+srcLocCol :: RealSrcLoc -> Int+srcLocCol (SrcLoc _ _ c) = c++-- | Move the 'SrcLoc' down by one line if the character is a newline,+-- to the next 8-char tabstop if it is a tab, and across by one+-- character in any other case+advanceSrcLoc :: RealSrcLoc -> Char -> RealSrcLoc+advanceSrcLoc (SrcLoc f l _) '\n' = SrcLoc f (l + 1) 1+advanceSrcLoc (SrcLoc f l c) '\t' = SrcLoc f l (((((c - 1) `shiftR` 3) + 1)+ `shiftL` 3) + 1)+advanceSrcLoc (SrcLoc f l c) _ = SrcLoc f l (c + 1)++{-+************************************************************************+* *+\subsection[SrcLoc-instances]{Instance declarations for various names}+* *+************************************************************************+-}++sortLocated :: [Located a] -> [Located a]+sortLocated things = sortBy (comparing getLoc) things++instance Outputable RealSrcLoc where+ ppr (SrcLoc src_path src_line src_col)+ = hcat [ pprFastFilePath src_path <> colon+ , int src_line <> colon+ , int src_col ]++-- I don't know why there is this style-based difference+-- if userStyle sty || debugStyle sty then+-- hcat [ pprFastFilePath src_path, char ':',+-- int src_line,+-- char ':', int src_col+-- ]+-- else+-- hcat [text "{-# LINE ", int src_line, space,+-- char '\"', pprFastFilePath src_path, text " #-}"]++instance Outputable SrcLoc where+ ppr (RealSrcLoc l) = ppr l+ ppr (UnhelpfulLoc s) = ftext s++instance Data RealSrcSpan where+ -- don't traverse?+ toConstr _ = abstractConstr "RealSrcSpan"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "RealSrcSpan"++instance Data SrcSpan where+ -- don't traverse?+ toConstr _ = abstractConstr "SrcSpan"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "SrcSpan"++{-+************************************************************************+* *+\subsection[SrcSpan]{Source Spans}+* *+************************************************************************+-}++{- |+A 'RealSrcSpan' delimits a portion of a text file. It could be represented+by a pair of (line,column) coordinates, but in fact we optimise+slightly by using more compact representations for single-line and+zero-length spans, both of which are quite common.++The end position is defined to be the column /after/ the end of the+span. That is, a span of (1,1)-(1,2) is one character long, and a+span of (1,1)-(1,1) is zero characters long.+-}++-- | Real Source Span+data RealSrcSpan+ = RealSrcSpan'+ { srcSpanFile :: !FastString,+ srcSpanSLine :: {-# UNPACK #-} !Int,+ srcSpanSCol :: {-# UNPACK #-} !Int,+ srcSpanELine :: {-# UNPACK #-} !Int,+ srcSpanECol :: {-# UNPACK #-} !Int+ }+ deriving Eq++-- | Source Span+--+-- A 'SrcSpan' identifies either a specific portion of a text file+-- or a human-readable description of a location.+data SrcSpan =+ RealSrcSpan !RealSrcSpan+ | UnhelpfulSpan !FastString -- Just a general indication+ -- also used to indicate an empty span++ deriving (Eq, Ord, Show) -- Show is used by Lexer.x, because we+ -- derive Show for Token++instance ToJson SrcSpan where+ json (UnhelpfulSpan {} ) = JSNull --JSObject [( "type", "unhelpful")]+ json (RealSrcSpan rss) = json rss++instance ToJson RealSrcSpan where+ json (RealSrcSpan'{..}) = JSObject [ ("file", JSString (unpackFS srcSpanFile))+ , ("startLine", JSInt srcSpanSLine)+ , ("startCol", JSInt srcSpanSCol)+ , ("endLine", JSInt srcSpanELine)+ , ("endCol", JSInt srcSpanECol)+ ]++instance NFData SrcSpan where+ rnf x = x `seq` ()++-- | Built-in "bad" 'SrcSpan's for common sources of location uncertainty+noSrcSpan, wiredInSrcSpan, interactiveSrcSpan :: SrcSpan+noSrcSpan = UnhelpfulSpan (fsLit "<no location info>")+wiredInSrcSpan = UnhelpfulSpan (fsLit "<wired into compiler>")+interactiveSrcSpan = UnhelpfulSpan (fsLit "<interactive>")++-- | Create a "bad" 'SrcSpan' that has not location information+mkGeneralSrcSpan :: FastString -> SrcSpan+mkGeneralSrcSpan = UnhelpfulSpan++-- | Create a 'SrcSpan' corresponding to a single point+srcLocSpan :: SrcLoc -> SrcSpan+srcLocSpan (UnhelpfulLoc str) = UnhelpfulSpan str+srcLocSpan (RealSrcLoc l) = RealSrcSpan (realSrcLocSpan l)++realSrcLocSpan :: RealSrcLoc -> RealSrcSpan+realSrcLocSpan (SrcLoc file line col) = RealSrcSpan' file line col line col++-- | Create a 'SrcSpan' between two points in a file+mkRealSrcSpan :: RealSrcLoc -> RealSrcLoc -> RealSrcSpan+mkRealSrcSpan loc1 loc2 = RealSrcSpan' file line1 col1 line2 col2+ where+ line1 = srcLocLine loc1+ line2 = srcLocLine loc2+ col1 = srcLocCol loc1+ col2 = srcLocCol loc2+ file = srcLocFile loc1++-- | 'True' if the span is known to straddle only one line.+isOneLineRealSpan :: RealSrcSpan -> Bool+isOneLineRealSpan (RealSrcSpan' _ line1 _ line2 _)+ = line1 == line2++-- | 'True' if the span is a single point+isPointRealSpan :: RealSrcSpan -> Bool+isPointRealSpan (RealSrcSpan' _ line1 col1 line2 col2)+ = line1 == line2 && col1 == col2++-- | Create a 'SrcSpan' between two points in a file+mkSrcSpan :: SrcLoc -> SrcLoc -> SrcSpan+mkSrcSpan (UnhelpfulLoc str) _ = UnhelpfulSpan str+mkSrcSpan _ (UnhelpfulLoc str) = UnhelpfulSpan str+mkSrcSpan (RealSrcLoc loc1) (RealSrcLoc loc2)+ = RealSrcSpan (mkRealSrcSpan loc1 loc2)++-- | Combines two 'SrcSpan' into one that spans at least all the characters+-- within both spans. Assumes the "file" part is the same in both inputs+combineSrcSpans :: SrcSpan -> SrcSpan -> SrcSpan+combineSrcSpans (UnhelpfulSpan _) r = r -- this seems more useful+combineSrcSpans l (UnhelpfulSpan _) = l+combineSrcSpans (RealSrcSpan span1) (RealSrcSpan span2)+ = RealSrcSpan (combineRealSrcSpans span1 span2)++-- | Combines two 'SrcSpan' into one that spans at least all the characters+-- within both spans. Assumes the "file" part is the same in both inputs+combineRealSrcSpans :: RealSrcSpan -> RealSrcSpan -> RealSrcSpan+combineRealSrcSpans span1 span2+ = RealSrcSpan' file line_start col_start line_end col_end+ where+ (line_start, col_start) = min (srcSpanStartLine span1, srcSpanStartCol span1)+ (srcSpanStartLine span2, srcSpanStartCol span2)+ (line_end, col_end) = max (srcSpanEndLine span1, srcSpanEndCol span1)+ (srcSpanEndLine span2, srcSpanEndCol span2)+ file = srcSpanFile span1++-- | Convert a SrcSpan into one that represents only its first character+srcSpanFirstCharacter :: SrcSpan -> SrcSpan+srcSpanFirstCharacter l@(UnhelpfulSpan {}) = l+srcSpanFirstCharacter (RealSrcSpan span) = RealSrcSpan $ mkRealSrcSpan loc1 loc2+ where+ loc1@(SrcLoc f l c) = realSrcSpanStart span+ loc2 = SrcLoc f l (c+1)+{-+************************************************************************+* *+\subsection[SrcSpan-predicates]{Predicates}+* *+************************************************************************+-}++-- | Test if a 'SrcSpan' is "good", i.e. has precise location information+isGoodSrcSpan :: SrcSpan -> Bool+isGoodSrcSpan (RealSrcSpan _) = True+isGoodSrcSpan (UnhelpfulSpan _) = False++isOneLineSpan :: SrcSpan -> Bool+-- ^ True if the span is known to straddle only one line.+-- For "bad" 'SrcSpan', it returns False+isOneLineSpan (RealSrcSpan s) = srcSpanStartLine s == srcSpanEndLine s+isOneLineSpan (UnhelpfulSpan _) = False++-- | Tests whether the first span "contains" the other span, meaning+-- that it covers at least as much source code. True where spans are equal.+containsSpan :: RealSrcSpan -> RealSrcSpan -> Bool+containsSpan s1 s2+ = (srcSpanStartLine s1, srcSpanStartCol s1)+ <= (srcSpanStartLine s2, srcSpanStartCol s2)+ && (srcSpanEndLine s1, srcSpanEndCol s1)+ >= (srcSpanEndLine s2, srcSpanEndCol s2)+ && (srcSpanFile s1 == srcSpanFile s2)+ -- We check file equality last because it is (presumably?) least+ -- likely to fail.+{-+%************************************************************************+%* *+\subsection[SrcSpan-unsafe-access-fns]{Unsafe access functions}+* *+************************************************************************+-}++srcSpanStartLine :: RealSrcSpan -> Int+srcSpanEndLine :: RealSrcSpan -> Int+srcSpanStartCol :: RealSrcSpan -> Int+srcSpanEndCol :: RealSrcSpan -> Int++srcSpanStartLine RealSrcSpan'{ srcSpanSLine=l } = l+srcSpanEndLine RealSrcSpan'{ srcSpanELine=l } = l+srcSpanStartCol RealSrcSpan'{ srcSpanSCol=l } = l+srcSpanEndCol RealSrcSpan'{ srcSpanECol=c } = c++{-+************************************************************************+* *+\subsection[SrcSpan-access-fns]{Access functions}+* *+************************************************************************+-}++-- | Returns the location at the start of the 'SrcSpan' or a "bad" 'SrcSpan' if that is unavailable+srcSpanStart :: SrcSpan -> SrcLoc+srcSpanStart (UnhelpfulSpan str) = UnhelpfulLoc str+srcSpanStart (RealSrcSpan s) = RealSrcLoc (realSrcSpanStart s)++-- | Returns the location at the end of the 'SrcSpan' or a "bad" 'SrcSpan' if that is unavailable+srcSpanEnd :: SrcSpan -> SrcLoc+srcSpanEnd (UnhelpfulSpan str) = UnhelpfulLoc str+srcSpanEnd (RealSrcSpan s) = RealSrcLoc (realSrcSpanEnd s)++realSrcSpanStart :: RealSrcSpan -> RealSrcLoc+realSrcSpanStart s = mkRealSrcLoc (srcSpanFile s)+ (srcSpanStartLine s)+ (srcSpanStartCol s)++realSrcSpanEnd :: RealSrcSpan -> RealSrcLoc+realSrcSpanEnd s = mkRealSrcLoc (srcSpanFile s)+ (srcSpanEndLine s)+ (srcSpanEndCol s)++-- | Obtains the filename for a 'SrcSpan' if it is "good"+srcSpanFileName_maybe :: SrcSpan -> Maybe FastString+srcSpanFileName_maybe (RealSrcSpan s) = Just (srcSpanFile s)+srcSpanFileName_maybe (UnhelpfulSpan _) = Nothing++{-+************************************************************************+* *+\subsection[SrcSpan-instances]{Instances}+* *+************************************************************************+-}++-- We want to order RealSrcSpans first by the start point, then by the+-- end point.+instance Ord RealSrcSpan where+ a `compare` b =+ (realSrcSpanStart a `compare` realSrcSpanStart b) `thenCmp`+ (realSrcSpanEnd a `compare` realSrcSpanEnd b)++instance Show RealSrcLoc where+ show (SrcLoc filename row col)+ = "SrcLoc " ++ show filename ++ " " ++ show row ++ " " ++ show col++-- Show is used by Lexer.x, because we derive Show for Token+instance Show RealSrcSpan where+ show span@(RealSrcSpan' file sl sc el ec)+ | isPointRealSpan span+ = "SrcSpanPoint " ++ show file ++ " " ++ intercalate " " (map show [sl,sc])++ | isOneLineRealSpan span+ = "SrcSpanOneLine " ++ show file ++ " "+ ++ intercalate " " (map show [sl,sc,ec])++ | otherwise+ = "SrcSpanMultiLine " ++ show file ++ " "+ ++ intercalate " " (map show [sl,sc,el,ec])+++instance Outputable RealSrcSpan where+ ppr span = pprUserRealSpan True span++-- I don't know why there is this style-based difference+-- = getPprStyle $ \ sty ->+-- if userStyle sty || debugStyle sty then+-- text (showUserRealSpan True span)+-- else+-- hcat [text "{-# LINE ", int (srcSpanStartLine span), space,+-- char '\"', pprFastFilePath $ srcSpanFile span, text " #-}"]++instance Outputable SrcSpan where+ ppr span = pprUserSpan True span++-- I don't know why there is this style-based difference+-- = getPprStyle $ \ sty ->+-- if userStyle sty || debugStyle sty then+-- pprUserSpan True span+-- else+-- case span of+-- UnhelpfulSpan _ -> panic "Outputable UnhelpfulSpan"+-- RealSrcSpan s -> ppr s++pprUserSpan :: Bool -> SrcSpan -> SDoc+pprUserSpan _ (UnhelpfulSpan s) = ftext s+pprUserSpan show_path (RealSrcSpan s) = pprUserRealSpan show_path s++pprUserRealSpan :: Bool -> RealSrcSpan -> SDoc+pprUserRealSpan show_path span@(RealSrcSpan' src_path line col _ _)+ | isPointRealSpan span+ = hcat [ ppWhen show_path (pprFastFilePath src_path <> colon)+ , int line <> colon+ , int col ]++pprUserRealSpan show_path span@(RealSrcSpan' src_path line scol _ ecol)+ | isOneLineRealSpan span+ = hcat [ ppWhen show_path (pprFastFilePath src_path <> colon)+ , int line <> colon+ , int scol+ , ppUnless (ecol - scol <= 1) (char '-' <> int (ecol - 1)) ]+ -- For single-character or point spans, we just+ -- output the starting column number++pprUserRealSpan show_path (RealSrcSpan' src_path sline scol eline ecol)+ = hcat [ ppWhen show_path (pprFastFilePath src_path <> colon)+ , parens (int sline <> comma <> int scol)+ , char '-'+ , parens (int eline <> comma <> int ecol') ]+ where+ ecol' = if ecol == 0 then ecol else ecol - 1++{-+************************************************************************+* *+\subsection[Located]{Attaching SrcSpans to things}+* *+************************************************************************+-}++-- | We attach SrcSpans to lots of things, so let's have a datatype for it.+data GenLocated l e = L l e+ deriving (Eq, Ord, Data, Functor, Foldable, Traversable)++type Located e = GenLocated SrcSpan e+type RealLocated e = GenLocated RealSrcSpan e++unLoc :: GenLocated l e -> e+unLoc (L _ e) = e++getLoc :: GenLocated l e -> l+getLoc (L l _) = l++noLoc :: e -> Located e+noLoc e = L noSrcSpan e++mkGeneralLocated :: String -> e -> Located e+mkGeneralLocated s e = L (mkGeneralSrcSpan (fsLit s)) e++combineLocs :: Located a -> Located b -> SrcSpan+combineLocs a b = combineSrcSpans (getLoc a) (getLoc b)++-- | Combine locations from two 'Located' things and add them to a third thing+addCLoc :: Located a -> Located b -> c -> Located c+addCLoc a b c = L (combineSrcSpans (getLoc a) (getLoc b)) c++-- not clear whether to add a general Eq instance, but this is useful sometimes:++-- | Tests whether the two located things are equal+eqLocated :: Eq a => Located a -> Located a -> Bool+eqLocated a b = unLoc a == unLoc b++-- not clear whether to add a general Ord instance, but this is useful sometimes:++-- | Tests the ordering of the two located things+cmpLocated :: Ord a => Located a -> Located a -> Ordering+cmpLocated a b = unLoc a `compare` unLoc b++instance (Outputable l, Outputable e) => Outputable (GenLocated l e) where+ ppr (L l e) = -- TODO: We can't do this since Located was refactored into+ -- GenLocated:+ -- Print spans without the file name etc+ -- ifPprDebug (braces (pprUserSpan False l))+ ifPprDebug (braces (ppr l))+ $$ ppr e++{-+************************************************************************+* *+\subsection{Ordering SrcSpans for InteractiveUI}+* *+************************************************************************+-}++-- | Alternative strategies for ordering 'SrcSpan's+leftmost_smallest, leftmost_largest, rightmost :: SrcSpan -> SrcSpan -> Ordering+rightmost = flip compare+leftmost_smallest = compare+leftmost_largest a b = (srcSpanStart a `compare` srcSpanStart b)+ `thenCmp`+ (srcSpanEnd b `compare` srcSpanEnd a)++-- | Determines whether a span encloses a given line and column index+spans :: SrcSpan -> (Int, Int) -> Bool+spans (UnhelpfulSpan _) _ = panic "spans UnhelpfulSpan"+spans (RealSrcSpan span) (l,c) = realSrcSpanStart span <= loc && loc <= realSrcSpanEnd span+ where loc = mkRealSrcLoc (srcSpanFile span) l c++-- | Determines whether a span is enclosed by another one+isSubspanOf :: SrcSpan -- ^ The span that may be enclosed by the other+ -> SrcSpan -- ^ The span it may be enclosed by+ -> Bool+isSubspanOf src parent+ | srcSpanFileName_maybe parent /= srcSpanFileName_maybe src = False+ | otherwise = srcSpanStart parent <= srcSpanStart src &&+ srcSpanEnd parent >= srcSpanEnd src
+ basicTypes/UniqSupply.hs view
@@ -0,0 +1,232 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP, UnboxedTuples #-}++module UniqSupply (+ -- * Main data type+ UniqSupply, -- Abstractly++ -- ** Operations on supplies+ uniqFromSupply, uniqsFromSupply, -- basic ops+ takeUniqFromSupply,++ mkSplitUniqSupply,+ splitUniqSupply, listSplitUniqSupply,+ splitUniqSupply3, splitUniqSupply4,++ -- * Unique supply monad and its abstraction+ UniqSM, MonadUnique(..), liftUs,++ -- ** Operations on the monad+ initUs, initUs_,+ lazyThenUs, lazyMapUs,+ getUniqueSupplyM3,++ -- * Set supply strategy+ initUniqSupply+ ) where++import Unique++import GHC.IO++import MonadUtils+import Control.Monad+import Data.Bits+import Data.Char++#include "Unique.h"++{-+************************************************************************+* *+\subsection{Splittable Unique supply: @UniqSupply@}+* *+************************************************************************+-}++-- | Unique Supply+--+-- A value of type 'UniqSupply' is unique, and it can+-- supply /one/ distinct 'Unique'. Also, from the supply, one can+-- also manufacture an arbitrary number of further 'UniqueSupply' values,+-- which will be distinct from the first and from all others.+data UniqSupply+ = MkSplitUniqSupply {-# UNPACK #-} !Int -- make the Unique with this+ UniqSupply UniqSupply+ -- when split => these two supplies++mkSplitUniqSupply :: Char -> IO UniqSupply+-- ^ Create a unique supply out of thin air. The character given must+-- be distinct from those of all calls to this function in the compiler+-- for the values generated to be truly unique.++splitUniqSupply :: UniqSupply -> (UniqSupply, UniqSupply)+-- ^ Build two 'UniqSupply' from a single one, each of which+-- can supply its own 'Unique'.+listSplitUniqSupply :: UniqSupply -> [UniqSupply]+-- ^ Create an infinite list of 'UniqSupply' from a single one+uniqFromSupply :: UniqSupply -> Unique+-- ^ Obtain the 'Unique' from this particular 'UniqSupply'+uniqsFromSupply :: UniqSupply -> [Unique] -- Infinite+-- ^ Obtain an infinite list of 'Unique' that can be generated by constant splitting of the supply+takeUniqFromSupply :: UniqSupply -> (Unique, UniqSupply)+-- ^ Obtain the 'Unique' from this particular 'UniqSupply', and a new supply++mkSplitUniqSupply c+ = case ord c `shiftL` uNIQUE_BITS of+ mask -> let+ -- here comes THE MAGIC:++ -- This is one of the most hammered bits in the whole compiler+ mk_supply+ -- NB: Use unsafeInterleaveIO for thread-safety.+ = unsafeInterleaveIO (+ genSym >>= \ u ->+ mk_supply >>= \ s1 ->+ mk_supply >>= \ s2 ->+ return (MkSplitUniqSupply (mask .|. u) s1 s2)+ )+ in+ mk_supply++foreign import ccall unsafe "genSym" genSym :: IO Int+foreign import ccall unsafe "initGenSym" initUniqSupply :: Int -> Int -> IO ()++splitUniqSupply (MkSplitUniqSupply _ s1 s2) = (s1, s2)+listSplitUniqSupply (MkSplitUniqSupply _ s1 s2) = s1 : listSplitUniqSupply s2++uniqFromSupply (MkSplitUniqSupply n _ _) = mkUniqueGrimily n+uniqsFromSupply (MkSplitUniqSupply n _ s2) = mkUniqueGrimily n : uniqsFromSupply s2+takeUniqFromSupply (MkSplitUniqSupply n s1 _) = (mkUniqueGrimily n, s1)++-- | Build three 'UniqSupply' from a single one,+-- each of which can supply its own unique+splitUniqSupply3 :: UniqSupply -> (UniqSupply, UniqSupply, UniqSupply)+splitUniqSupply3 us = (us1, us2, us3)+ where+ (us1, us') = splitUniqSupply us+ (us2, us3) = splitUniqSupply us'++-- | Build four 'UniqSupply' from a single one,+-- each of which can supply its own unique+splitUniqSupply4 :: UniqSupply -> (UniqSupply, UniqSupply, UniqSupply, UniqSupply)+splitUniqSupply4 us = (us1, us2, us3, us4)+ where+ (us1, us2, us') = splitUniqSupply3 us+ (us3, us4) = splitUniqSupply us'++{-+************************************************************************+* *+\subsubsection[UniqSupply-monad]{@UniqSupply@ monad: @UniqSM@}+* *+************************************************************************+-}++-- | A monad which just gives the ability to obtain 'Unique's+newtype UniqSM result = USM { unUSM :: UniqSupply -> (# result, UniqSupply #) }++instance Monad UniqSM where+ (>>=) = thenUs+ (>>) = (*>)++instance Functor UniqSM where+ fmap f (USM x) = USM (\us -> case x us of+ (# r, us' #) -> (# f r, us' #))++instance Applicative UniqSM where+ pure = returnUs+ (USM f) <*> (USM x) = USM $ \us -> case f us of+ (# ff, us' #) -> case x us' of+ (# xx, us'' #) -> (# ff xx, us'' #)+ (*>) = thenUs_++-- | Run the 'UniqSM' action, returning the final 'UniqSupply'+initUs :: UniqSupply -> UniqSM a -> (a, UniqSupply)+initUs init_us m = case unUSM m init_us of { (# r, us #) -> (r,us) }++-- | Run the 'UniqSM' action, discarding the final 'UniqSupply'+initUs_ :: UniqSupply -> UniqSM a -> a+initUs_ init_us m = case unUSM m init_us of { (# r, _ #) -> r }++{-# INLINE thenUs #-}+{-# INLINE lazyThenUs #-}+{-# INLINE returnUs #-}+{-# INLINE splitUniqSupply #-}++-- @thenUs@ is where we split the @UniqSupply@.++liftUSM :: UniqSM a -> UniqSupply -> (a, UniqSupply)+liftUSM (USM m) us = case m us of (# a, us' #) -> (a, us')++instance MonadFix UniqSM where+ mfix m = USM (\us -> let (r,us') = liftUSM (m r) us in (# r,us' #))++thenUs :: UniqSM a -> (a -> UniqSM b) -> UniqSM b+thenUs (USM expr) cont+ = USM (\us -> case (expr us) of+ (# result, us' #) -> unUSM (cont result) us')++lazyThenUs :: UniqSM a -> (a -> UniqSM b) -> UniqSM b+lazyThenUs expr cont+ = USM (\us -> let (result, us') = liftUSM expr us in unUSM (cont result) us')++thenUs_ :: UniqSM a -> UniqSM b -> UniqSM b+thenUs_ (USM expr) (USM cont)+ = USM (\us -> case (expr us) of { (# _, us' #) -> cont us' })++returnUs :: a -> UniqSM a+returnUs result = USM (\us -> (# result, us #))++getUs :: UniqSM UniqSupply+getUs = USM (\us -> case splitUniqSupply us of (us1,us2) -> (# us1, us2 #))++-- | A monad for generating unique identifiers+class Monad m => MonadUnique m where+ -- | Get a new UniqueSupply+ getUniqueSupplyM :: m UniqSupply+ -- | Get a new unique identifier+ getUniqueM :: m Unique+ -- | Get an infinite list of new unique identifiers+ getUniquesM :: m [Unique]++ -- This default definition of getUniqueM, while correct, is not as+ -- efficient as it could be since it needlessly generates and throws away+ -- an extra Unique. For your instances consider providing an explicit+ -- definition for 'getUniqueM' which uses 'takeUniqFromSupply' directly.+ getUniqueM = liftM uniqFromSupply getUniqueSupplyM+ getUniquesM = liftM uniqsFromSupply getUniqueSupplyM++instance MonadUnique UniqSM where+ getUniqueSupplyM = getUs+ getUniqueM = getUniqueUs+ getUniquesM = getUniquesUs++getUniqueSupplyM3 :: MonadUnique m => m (UniqSupply, UniqSupply, UniqSupply)+getUniqueSupplyM3 = liftM3 (,,) getUniqueSupplyM getUniqueSupplyM getUniqueSupplyM++liftUs :: MonadUnique m => UniqSM a -> m a+liftUs m = getUniqueSupplyM >>= return . flip initUs_ m++getUniqueUs :: UniqSM Unique+getUniqueUs = USM (\us -> case takeUniqFromSupply us of+ (u,us') -> (# u, us' #))++getUniquesUs :: UniqSM [Unique]+getUniquesUs = USM (\us -> case splitUniqSupply us of+ (us1,us2) -> (# uniqsFromSupply us1, us2 #))++-- {-# SPECIALIZE mapM :: (a -> UniqSM b) -> [a] -> UniqSM [b] #-}+-- {-# SPECIALIZE mapAndUnzipM :: (a -> UniqSM (b,c)) -> [a] -> UniqSM ([b],[c]) #-}+-- {-# SPECIALIZE mapAndUnzip3M :: (a -> UniqSM (b,c,d)) -> [a] -> UniqSM ([b],[c],[d]) #-}++lazyMapUs :: (a -> UniqSM b) -> [a] -> UniqSM [b]+lazyMapUs _ [] = returnUs []+lazyMapUs f (x:xs)+ = f x `lazyThenUs` \ r ->+ lazyMapUs f xs `lazyThenUs` \ rs ->+ returnUs (r:rs)
+ basicTypes/Unique.hs view
@@ -0,0 +1,436 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++@Uniques@ are used to distinguish entities in the compiler (@Ids@,+@Classes@, etc.) from each other. Thus, @Uniques@ are the basic+comparison key in the compiler.++If there is any single operation that needs to be fast, it is @Unique@++comparison. Unsurprisingly, there is quite a bit of huff-and-puff+directed to that end.++Some of the other hair in this code is to be able to use a+``splittable @UniqueSupply@'' if requested/possible (not standard+Haskell).+-}++{-# LANGUAGE CPP, BangPatterns, MagicHash #-}++module Unique (+ -- * Main data types+ Unique, Uniquable(..),+ uNIQUE_BITS,++ -- ** Constructors, destructors and operations on 'Unique's+ hasKey,++ pprUniqueAlways,++ mkUniqueGrimily, -- Used in UniqSupply only!+ getKey, -- Used in Var, UniqFM, Name only!+ mkUnique, unpkUnique, -- Used in BinIface only++ deriveUnique, -- Ditto+ newTagUnique, -- Used in CgCase+ initTyVarUnique,+ nonDetCmpUnique,+ isValidKnownKeyUnique, -- Used in PrelInfo.knownKeyNamesOkay++ -- ** Making built-in uniques++ -- now all the built-in Uniques (and functions to make them)+ -- [the Oh-So-Wonderful Haskell module system wins again...]+ mkAlphaTyVarUnique,+ mkPrimOpIdUnique,+ mkPreludeMiscIdUnique, mkPreludeDataConUnique,+ mkPreludeTyConUnique, mkPreludeClassUnique,+ mkPArrDataConUnique, mkCoVarUnique,++ mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique,+ mkRegSingleUnique, mkRegPairUnique, mkRegClassUnique, mkRegSubUnique,+ mkCostCentreUnique,++ mkBuiltinUnique,+ mkPseudoUniqueD,+ mkPseudoUniqueE,+ mkPseudoUniqueH,++ -- ** Deriving uniques+ -- *** From TyCon name uniques+ tyConRepNameUnique,+ -- *** From DataCon name uniques+ dataConWorkerUnique, dataConRepNameUnique+ ) where++#include "HsVersions.h"+#include "Unique.h"++import BasicTypes+import FastString+import Outputable+import Util++-- just for implementing a fast [0,61) -> Char function+import GHC.Exts (indexCharOffAddr#, Char(..), Int(..))++import Data.Char ( chr, ord )+import Data.Bits++{-+************************************************************************+* *+\subsection[Unique-type]{@Unique@ type and operations}+* *+************************************************************************++The @Chars@ are ``tag letters'' that identify the @UniqueSupply@.+Fast comparison is everything on @Uniques@:+-}++-- | Unique identifier.+--+-- The type of unique identifiers that are used in many places in GHC+-- for fast ordering and equality tests. You should generate these with+-- the functions from the 'UniqSupply' module+--+-- These are sometimes also referred to as \"keys\" in comments in GHC.+newtype Unique = MkUnique Int++{-# INLINE uNIQUE_BITS #-}+uNIQUE_BITS :: Int+uNIQUE_BITS = finiteBitSize (0 :: Int) - UNIQUE_TAG_BITS++{-+Now come the functions which construct uniques from their pieces, and vice versa.+The stuff about unique *supplies* is handled further down this module.+-}++unpkUnique :: Unique -> (Char, Int) -- The reverse++mkUniqueGrimily :: Int -> Unique -- A trap-door for UniqSupply+getKey :: Unique -> Int -- for Var++incrUnique :: Unique -> Unique+stepUnique :: Unique -> Int -> Unique+deriveUnique :: Unique -> Int -> Unique+newTagUnique :: Unique -> Char -> Unique++mkUniqueGrimily = MkUnique++{-# INLINE getKey #-}+getKey (MkUnique x) = x++incrUnique (MkUnique i) = MkUnique (i + 1)+stepUnique (MkUnique i) n = MkUnique (i + n)++-- deriveUnique uses an 'X' tag so that it won't clash with+-- any of the uniques produced any other way+-- SPJ says: this looks terribly smelly to me!+deriveUnique (MkUnique i) delta = mkUnique 'X' (i + delta)++-- newTagUnique changes the "domain" of a unique to a different char+newTagUnique u c = mkUnique c i where (_,i) = unpkUnique u++-- | How many bits are devoted to the unique index (as opposed to the class+-- character).+uniqueMask :: Int+uniqueMask = (1 `shiftL` uNIQUE_BITS) - 1++-- pop the Char in the top 8 bits of the Unique(Supply)++-- No 64-bit bugs here, as long as we have at least 32 bits. --JSM++-- and as long as the Char fits in 8 bits, which we assume anyway!++mkUnique :: Char -> Int -> Unique -- Builds a unique from pieces+-- NOT EXPORTED, so that we can see all the Chars that+-- are used in this one module+mkUnique c i+ = MkUnique (tag .|. bits)+ where+ tag = ord c `shiftL` uNIQUE_BITS+ bits = i .&. uniqueMask++unpkUnique (MkUnique u)+ = let+ -- as long as the Char may have its eighth bit set, we+ -- really do need the logical right-shift here!+ tag = chr (u `shiftR` uNIQUE_BITS)+ i = u .&. uniqueMask+ in+ (tag, i)++-- | The interface file symbol-table encoding assumes that known-key uniques fit+-- in 30-bits; verify this.+--+-- See Note [Symbol table representation of names] in BinIface for details.+isValidKnownKeyUnique :: Unique -> Bool+isValidKnownKeyUnique u =+ case unpkUnique u of+ (c, x) -> ord c < 0xff && x <= (1 `shiftL` 22)++{-+************************************************************************+* *+\subsection[Uniquable-class]{The @Uniquable@ class}+* *+************************************************************************+-}++-- | Class of things that we can obtain a 'Unique' from+class Uniquable a where+ getUnique :: a -> Unique++hasKey :: Uniquable a => a -> Unique -> Bool+x `hasKey` k = getUnique x == k++instance Uniquable FastString where+ getUnique fs = mkUniqueGrimily (uniqueOfFS fs)++instance Uniquable Int where+ getUnique i = mkUniqueGrimily i++{-+************************************************************************+* *+\subsection[Unique-instances]{Instance declarations for @Unique@}+* *+************************************************************************++And the whole point (besides uniqueness) is fast equality. We don't+use `deriving' because we want {\em precise} control of ordering+(equality on @Uniques@ is v common).+-}++-- Note [Unique Determinism]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~+-- The order of allocated @Uniques@ is not stable across rebuilds.+-- The main reason for that is that typechecking interface files pulls+-- @Uniques@ from @UniqSupply@ and the interface file for the module being+-- currently compiled can, but doesn't have to exist.+--+-- It gets more complicated if you take into account that the interface+-- files are loaded lazily and that building multiple files at once has to+-- work for any subset of interface files present. When you add parallelism+-- this makes @Uniques@ hopelessly random.+--+-- As such, to get deterministic builds, the order of the allocated+-- @Uniques@ should not affect the final result.+-- see also wiki/DeterministicBuilds+--+-- Note [Unique Determinism and code generation]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- The goal of the deterministic builds (wiki/DeterministicBuilds, #4012)+-- is to get ABI compatible binaries given the same inputs and environment.+-- The motivation behind that is that if the ABI doesn't change the+-- binaries can be safely reused.+-- Note that this is weaker than bit-for-bit identical binaries and getting+-- bit-for-bit identical binaries is not a goal for now.+-- This means that we don't care about nondeterminism that happens after+-- the interface files are created, in particular we don't care about+-- register allocation and code generation.+-- To track progress on bit-for-bit determinism see #12262.++eqUnique :: Unique -> Unique -> Bool+eqUnique (MkUnique u1) (MkUnique u2) = u1 == u2++-- Provided here to make it explicit at the call-site that it can+-- introduce non-determinism.+-- See Note [Unique Determinism]+-- See Note [No Ord for Unique]+nonDetCmpUnique :: Unique -> Unique -> Ordering+nonDetCmpUnique (MkUnique u1) (MkUnique u2)+ = if u1 == u2 then EQ else if u1 < u2 then LT else GT++{-+Note [No Ord for Unique]+~~~~~~~~~~~~~~~~~~~~~~~~~~+As explained in Note [Unique Determinism] the relative order of Uniques+is nondeterministic. To prevent from accidental use the Ord Unique+instance has been removed.+This makes it easier to maintain deterministic builds, but comes with some+drawbacks.+The biggest drawback is that Maps keyed by Uniques can't directly be used.+The alternatives are:++ 1) Use UniqFM or UniqDFM, see Note [Deterministic UniqFM] to decide which+ 2) Create a newtype wrapper based on Unique ordering where nondeterminism+ is controlled. See Module.ModuleEnv+ 3) Change the algorithm to use nonDetCmpUnique and document why it's still+ deterministic+ 4) Use TrieMap as done in CmmCommonBlockElim.groupByLabel+-}++instance Eq Unique where+ a == b = eqUnique a b+ a /= b = not (eqUnique a b)++instance Uniquable Unique where+ getUnique u = u++-- We do sometimes make strings with @Uniques@ in them:++showUnique :: Unique -> String+showUnique uniq+ = case unpkUnique uniq of+ (tag, u) -> finish_show tag u (iToBase62 u)++finish_show :: Char -> Int -> String -> String+finish_show 't' u _pp_u | u < 26+ = -- Special case to make v common tyvars, t1, t2, ...+ -- come out as a, b, ... (shorter, easier to read)+ [chr (ord 'a' + u)]+finish_show tag _ pp_u = tag : pp_u++pprUniqueAlways :: Unique -> SDoc+-- The "always" means regardless of -dsuppress-uniques+-- It replaces the old pprUnique to remind callers that+-- they should consider whether they want to consult+-- Opt_SuppressUniques+pprUniqueAlways u+ = text (showUnique u)++instance Outputable Unique where+ ppr = pprUniqueAlways++instance Show Unique where+ show uniq = showUnique uniq++{-+************************************************************************+* *+\subsection[Utils-base62]{Base-62 numbers}+* *+************************************************************************++A character-stingy way to read/write numbers (notably Uniques).+The ``62-its'' are \tr{[0-9a-zA-Z]}. We don't handle negative Ints.+Code stolen from Lennart.+-}++iToBase62 :: Int -> String+iToBase62 n_+ = ASSERT(n_ >= 0) go n_ ""+ where+ go n cs | n < 62+ = let !c = chooseChar62 n in c : cs+ | otherwise+ = go q (c : cs) where (q, r) = quotRem n 62+ !c = chooseChar62 r++ chooseChar62 :: Int -> Char+ {-# INLINE chooseChar62 #-}+ chooseChar62 (I# n) = C# (indexCharOffAddr# chars62 n)+ chars62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"#++{-+************************************************************************+* *+\subsection[Uniques-prelude]{@Uniques@ for wired-in Prelude things}+* *+************************************************************************++Allocation of unique supply characters:+ v,t,u : for renumbering value-, type- and usage- vars.+ B: builtin+ C-E: pseudo uniques (used in native-code generator)+ X: uniques derived by deriveUnique+ _: unifiable tyvars (above)+ 0-9: prelude things below+ (no numbers left any more..)+ :: (prelude) parallel array data constructors++ other a-z: lower case chars for unique supplies. Used so far:++ d desugarer+ f AbsC flattener+ g SimplStg+ k constraint tuple tycons+ m constraint tuple datacons+ n Native codegen+ r Hsc name cache+ s simplifier+ z anonymous sums+-}++mkAlphaTyVarUnique :: Int -> Unique+mkPreludeClassUnique :: Int -> Unique+mkPreludeTyConUnique :: Int -> Unique+mkPreludeDataConUnique :: Arity -> Unique+mkPrimOpIdUnique :: Int -> Unique+mkPreludeMiscIdUnique :: Int -> Unique+mkPArrDataConUnique :: Int -> Unique+mkCoVarUnique :: Int -> Unique++mkAlphaTyVarUnique i = mkUnique '1' i+mkCoVarUnique i = mkUnique 'g' i+mkPreludeClassUnique i = mkUnique '2' i++--------------------------------------------------+-- Wired-in type constructor keys occupy *two* slots:+-- * u: the TyCon itself+-- * u+1: the TyConRepName of the TyCon+mkPreludeTyConUnique i = mkUnique '3' (2*i)++tyConRepNameUnique :: Unique -> Unique+tyConRepNameUnique u = incrUnique u++-- Data constructor keys occupy *two* slots. The first is used for the+-- data constructor itself and its wrapper function (the function that+-- evaluates arguments as necessary and calls the worker). The second is+-- used for the worker function (the function that builds the constructor+-- representation).++--------------------------------------------------+-- Wired-in data constructor keys occupy *three* slots:+-- * u: the DataCon itself+-- * u+1: its worker Id+-- * u+2: the TyConRepName of the promoted TyCon+-- Prelude data constructors are too simple to need wrappers.++mkPreludeDataConUnique i = mkUnique '6' (3*i) -- Must be alphabetic++--------------------------------------------------+dataConRepNameUnique, dataConWorkerUnique :: Unique -> Unique+dataConWorkerUnique u = incrUnique u+dataConRepNameUnique u = stepUnique u 2++--------------------------------------------------+mkPrimOpIdUnique op = mkUnique '9' op+mkPreludeMiscIdUnique i = mkUnique '0' i++-- No numbers left anymore, so I pick something different for the character tag+mkPArrDataConUnique a = mkUnique ':' (2*a)++-- The "tyvar uniques" print specially nicely: a, b, c, etc.+-- See pprUnique for details++initTyVarUnique :: Unique+initTyVarUnique = mkUnique 't' 0++mkPseudoUniqueD, mkPseudoUniqueE, mkPseudoUniqueH,+ mkBuiltinUnique :: Int -> Unique++mkBuiltinUnique i = mkUnique 'B' i+mkPseudoUniqueD i = mkUnique 'D' i -- used in NCG for getUnique on RealRegs+mkPseudoUniqueE i = mkUnique 'E' i -- used in NCG spiller to create spill VirtualRegs+mkPseudoUniqueH i = mkUnique 'H' i -- used in NCG spiller to create spill VirtualRegs++mkRegSingleUnique, mkRegPairUnique, mkRegSubUnique, mkRegClassUnique :: Int -> Unique+mkRegSingleUnique = mkUnique 'R'+mkRegSubUnique = mkUnique 'S'+mkRegPairUnique = mkUnique 'P'+mkRegClassUnique = mkUnique 'L'++mkCostCentreUnique :: Int -> Unique+mkCostCentreUnique = mkUnique 'C'++mkVarOccUnique, mkDataOccUnique, mkTvOccUnique, mkTcOccUnique :: FastString -> Unique+-- See Note [The Unique of an OccName] in OccName+mkVarOccUnique fs = mkUnique 'i' (uniqueOfFS fs)+mkDataOccUnique fs = mkUnique 'd' (uniqueOfFS fs)+mkTvOccUnique fs = mkUnique 'v' (uniqueOfFS fs)+mkTcOccUnique fs = mkUnique 'c' (uniqueOfFS fs)
+ basicTypes/Var.hs view
@@ -0,0 +1,643 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section{@Vars@: Variables}+-}++{-# LANGUAGE CPP, FlexibleContexts, MultiWayIf, FlexibleInstances, DeriveDataTypeable #-}++-- |+-- #name_types#+-- GHC uses several kinds of name internally:+--+-- * 'OccName.OccName': see "OccName#name_types"+--+-- * 'RdrName.RdrName': see "RdrName#name_types"+--+-- * 'Name.Name': see "Name#name_types"+--+-- * 'Id.Id': see "Id#name_types"+--+-- * 'Var.Var' is a synonym for the 'Id.Id' type but it may additionally+-- potentially contain type variables, which have a 'TyCoRep.Kind'+-- rather than a 'TyCoRep.Type' and only contain some extra+-- details during typechecking.+--+-- These 'Var.Var' names may either be global or local, see "Var#globalvslocal"+--+-- #globalvslocal#+-- Global 'Id's and 'Var's are those that are imported or correspond+-- to a data constructor, primitive operation, or record selectors.+-- Local 'Id's and 'Var's are those bound within an expression+-- (e.g. by a lambda) or at the top level of the module being compiled.++module Var (+ -- * The main data type and synonyms+ Var, CoVar, Id, NcId, DictId, DFunId, EvVar, EqVar, EvId, IpId, JoinId,+ TyVar, TypeVar, KindVar, TKVar, TyCoVar,++ -- * In and Out variants+ InVar, InCoVar, InId, InTyVar,+ OutVar, OutCoVar, OutId, OutTyVar,++ -- ** Taking 'Var's apart+ varName, varUnique, varType,++ -- ** Modifying 'Var's+ setVarName, setVarUnique, setVarType, updateVarType,+ updateVarTypeM,++ -- ** Constructing, taking apart, modifying 'Id's+ mkGlobalVar, mkLocalVar, mkExportedLocalVar, mkCoVar,+ idInfo, idDetails,+ lazySetIdInfo, setIdDetails, globaliseId,+ setIdExported, setIdNotExported,++ -- ** Predicates+ isId, isTyVar, isTcTyVar,+ isLocalVar, isLocalId, isCoVar, isNonCoVarId, isTyCoVar,+ isGlobalId, isExportedId,+ mustHaveLocalBinding,++ -- * TyVar's+ TyVarBndr(..), ArgFlag(..), TyVarBinder,+ binderVar, binderVars, binderArgFlag, binderKind,+ isVisibleArgFlag, isInvisibleArgFlag, sameVis,++ -- ** Constructing TyVar's+ mkTyVar, mkTcTyVar,++ -- ** Taking 'TyVar's apart+ tyVarName, tyVarKind, tcTyVarDetails, setTcTyVarDetails,++ -- ** Modifying 'TyVar's+ setTyVarName, setTyVarUnique, setTyVarKind, updateTyVarKind,+ updateTyVarKindM,++ nonDetCmpVar++ ) where++#include "HsVersions.h"++import {-# SOURCE #-} TyCoRep( Type, Kind, pprKind )+import {-# SOURCE #-} TcType( TcTyVarDetails, pprTcTyVarDetails, vanillaSkolemTv )+import {-# SOURCE #-} IdInfo( IdDetails, IdInfo, coVarDetails, isCoVarDetails,+ vanillaIdInfo, pprIdDetails )++import Name hiding (varName)+import Unique ( Uniquable, Unique, getKey, getUnique+ , mkUniqueGrimily, nonDetCmpUnique )+import Util+import Binary+import DynFlags+import Outputable++import Data.Data++{-+************************************************************************+* *+ Synonyms+* *+************************************************************************+-- These synonyms are here and not in Id because otherwise we need a very+-- large number of SOURCE imports of Id.hs :-(+-}++-- | Identifier+type Id = Var -- A term-level identifier+ -- predicate: isId++-- | Coercion Variable+type CoVar = Id -- See Note [Evidence: EvIds and CoVars]+ -- predicate: isCoVar++-- |+type NcId = Id -- A term-level (value) variable that is+ -- /not/ an (unlifted) coercion+ -- predicate: isNonCoVarId++-- | Type or kind Variable+type TyVar = Var -- Type *or* kind variable (historical)++-- | Type or Kind Variable+type TKVar = Var -- Type *or* kind variable (historical)++-- | Type Variable+type TypeVar = Var -- Definitely a type variable++-- | Kind Variable+type KindVar = Var -- Definitely a kind variable+ -- See Note [Kind and type variables]++-- See Note [Evidence: EvIds and CoVars]+-- | Evidence Identifier+type EvId = Id -- Term-level evidence: DictId, IpId, or EqVar++-- | Evidence Variable+type EvVar = EvId -- ...historical name for EvId++-- | Dictionary Function Identifier+type DFunId = Id -- A dictionary function++-- | Dictionary Identifier+type DictId = EvId -- A dictionary variable++-- | Implicit parameter Identifier+type IpId = EvId -- A term-level implicit parameter++-- | Equality Variable+type EqVar = EvId -- Boxed equality evidence+type JoinId = Id -- A join variable++-- | Type or Coercion Variable+type TyCoVar = Id -- Type, *or* coercion variable+ -- predicate: isTyCoVar+++{- Many passes apply a substitution, and it's very handy to have type+ synonyms to remind us whether or not the subsitution has been applied -}++type InVar = Var+type InTyVar = TyVar+type InCoVar = CoVar+type InId = Id+type OutVar = Var+type OutTyVar = TyVar+type OutCoVar = CoVar+type OutId = Id++++{- Note [Evidence: EvIds and CoVars]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* An EvId (evidence Id) is a term-level evidence variable+ (dictionary, implicit parameter, or equality). Could be boxed or unboxed.++* DictId, IpId, and EqVar are synonyms when we know what kind of+ evidence we are talking about. For example, an EqVar has type (t1 ~ t2).++* A CoVar is always an un-lifted coercion, of type (t1 ~# t2) or (t1 ~R# t2)++Note [Kind and type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Before kind polymorphism, TyVar were used to mean type variables. Now+they are use to mean kind *or* type variables. KindVar is used when we+know for sure that it is a kind variable. In future, we might want to+go over the whole compiler code to use:+ - TKVar to mean kind or type variables+ - TypeVar to mean type variables only+ - KindVar to mean kind variables+++************************************************************************+* *+\subsection{The main data type declarations}+* *+************************************************************************+++Every @Var@ has a @Unique@, to uniquify it and for fast comparison, a+@Type@, and an @IdInfo@ (non-essential info about it, e.g.,+strictness). The essential info about different kinds of @Vars@ is+in its @VarDetails@.+-}++-- | Variable+--+-- Essentially a typed 'Name', that may also contain some additional information+-- about the 'Var' and it's use sites.+data Var+ = TyVar { -- Type and kind variables+ -- see Note [Kind and type variables]+ varName :: !Name,+ realUnique :: {-# UNPACK #-} !Int,+ -- ^ Key for fast comparison+ -- Identical to the Unique in the name,+ -- cached here for speed+ varType :: Kind -- ^ The type or kind of the 'Var' in question+ }++ | TcTyVar { -- Used only during type inference+ -- Used for kind variables during+ -- inference, as well+ varName :: !Name,+ realUnique :: {-# UNPACK #-} !Int,+ varType :: Kind,+ tc_tv_details :: TcTyVarDetails+ }++ | Id {+ varName :: !Name,+ realUnique :: {-# UNPACK #-} !Int,+ varType :: Type,+ idScope :: IdScope,+ id_details :: IdDetails, -- Stable, doesn't change+ id_info :: IdInfo } -- Unstable, updated by simplifier++-- | Identifier Scope+data IdScope -- See Note [GlobalId/LocalId]+ = GlobalId+ | LocalId ExportFlag++data ExportFlag -- See Note [ExportFlag on binders]+ = NotExported -- ^ Not exported: may be discarded as dead code.+ | Exported -- ^ Exported: kept alive++{- Note [ExportFlag on binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+An ExportFlag of "Exported" on a top-level binder says "keep this+binding alive; do not drop it as dead code". This transitively+keeps alive all the other top-level bindings that this binding refers+to. This property is persisted all the way down the pipeline, so that+the binding will be compiled all the way to object code, and its+symbols will appear in the linker symbol table.++However, note that this use of "exported" is quite different to the+export list on a Haskell module. Setting the ExportFlag on an Id does+/not/ mean that if you import the module (in Haskell source code) you+will see this Id. Of course, things that appear in the export list+of the source Haskell module do indeed have their ExportFlag set.+But many other things, such as dictionary functions, are kept alive+by having their ExportFlag set, even though they are not exported+in the source-code sense.++We should probably use a different term for ExportFlag, like+KeepAlive.++Note [GlobalId/LocalId]+~~~~~~~~~~~~~~~~~~~~~~~+A GlobalId is+ * always a constant (top-level)+ * imported, or data constructor, or primop, or record selector+ * has a Unique that is globally unique across the whole+ GHC invocation (a single invocation may compile multiple modules)+ * never treated as a candidate by the free-variable finder;+ it's a constant!++A LocalId is+ * bound within an expression (lambda, case, local let(rec))+ * or defined at top level in the module being compiled+ * always treated as a candidate by the free-variable finder++After CoreTidy, top-level LocalIds are turned into GlobalIds+-}++instance Outputable Var where+ ppr var = sdocWithDynFlags $ \dflags ->+ getPprStyle $ \ppr_style ->+ if | debugStyle ppr_style && (not (gopt Opt_SuppressVarKinds dflags))+ -> parens (ppr (varName var) <+> ppr_debug var ppr_style <+>+ dcolon <+> pprKind (tyVarKind var))+ | otherwise+ -> ppr (varName var) <> ppr_debug var ppr_style++ppr_debug :: Var -> PprStyle -> SDoc+ppr_debug (TyVar {}) sty+ | debugStyle sty = brackets (text "tv")+ppr_debug (TcTyVar {tc_tv_details = d}) sty+ | dumpStyle sty || debugStyle sty = brackets (pprTcTyVarDetails d)+ppr_debug (Id { idScope = s, id_details = d }) sty+ | debugStyle sty = brackets (ppr_id_scope s <> pprIdDetails d)+ppr_debug _ _ = empty++ppr_id_scope :: IdScope -> SDoc+ppr_id_scope GlobalId = text "gid"+ppr_id_scope (LocalId Exported) = text "lidx"+ppr_id_scope (LocalId NotExported) = text "lid"++instance NamedThing Var where+ getName = varName++instance Uniquable Var where+ getUnique = varUnique++instance Eq Var where+ a == b = realUnique a == realUnique b++instance Ord Var where+ a <= b = realUnique a <= realUnique b+ a < b = realUnique a < realUnique b+ a >= b = realUnique a >= realUnique b+ a > b = realUnique a > realUnique b+ a `compare` b = a `nonDetCmpVar` b++-- | Compare Vars by their Uniques.+-- This is what Ord Var does, provided here to make it explicit at the+-- call-site that it can introduce non-determinism.+-- See Note [Unique Determinism]+nonDetCmpVar :: Var -> Var -> Ordering+nonDetCmpVar a b = varUnique a `nonDetCmpUnique` varUnique b++instance Data Var where+ -- don't traverse?+ toConstr _ = abstractConstr "Var"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "Var"++instance HasOccName Var where+ occName = nameOccName . varName++varUnique :: Var -> Unique+varUnique var = mkUniqueGrimily (realUnique var)++setVarUnique :: Var -> Unique -> Var+setVarUnique var uniq+ = var { realUnique = getKey uniq,+ varName = setNameUnique (varName var) uniq }++setVarName :: Var -> Name -> Var+setVarName var new_name+ = var { realUnique = getKey (getUnique new_name),+ varName = new_name }++setVarType :: Id -> Type -> Id+setVarType id ty = id { varType = ty }++updateVarType :: (Type -> Type) -> Id -> Id+updateVarType f id = id { varType = f (varType id) }++updateVarTypeM :: Monad m => (Type -> m Type) -> Id -> m Id+updateVarTypeM f id = do { ty' <- f (varType id)+ ; return (id { varType = ty' }) }++{- *********************************************************************+* *+* ArgFlag+* *+********************************************************************* -}++-- | Argument Flag+--+-- Is something required to appear in source Haskell ('Required'),+-- permitted by request ('Specified') (visible type application), or+-- prohibited entirely from appearing in source Haskell ('Inferred')?+-- See Note [TyBinders and ArgFlags] in TyCoRep+data ArgFlag = Required | Specified | Inferred+ deriving (Eq, Data)++-- | Does this 'ArgFlag' classify an argument that is written in Haskell?+isVisibleArgFlag :: ArgFlag -> Bool+isVisibleArgFlag Required = True+isVisibleArgFlag _ = False++-- | Does this 'ArgFlag' classify an argument that is not written in Haskell?+isInvisibleArgFlag :: ArgFlag -> Bool+isInvisibleArgFlag = not . isVisibleArgFlag++-- | Do these denote the same level of visibility? 'Required'+-- arguments are visible, others are not. So this function+-- equates 'Specified' and 'Inferred'. Used for printing.+sameVis :: ArgFlag -> ArgFlag -> Bool+sameVis Required Required = True+sameVis Required _ = False+sameVis _ Required = False+sameVis _ _ = True++{- *********************************************************************+* *+* TyVarBndr, TyVarBinder+* *+********************************************************************* -}++-- Type Variable Binder+--+-- TyVarBndr is polymorphic in both tyvar and visiblity fields:+-- * tyvar can be TyVar or IfaceTv+-- * argf can be ArgFlag or TyConBndrVis+data TyVarBndr tyvar argf = TvBndr tyvar argf+ deriving( Data )++-- | Type Variable Binder+--+-- A 'TyVarBinder' is the binder of a ForAllTy+-- It's convenient to define this synonym here rather its natural+-- home in TyCoRep, because it's used in DataCon.hs-boot+type TyVarBinder = TyVarBndr TyVar ArgFlag++binderVar :: TyVarBndr tv argf -> tv+binderVar (TvBndr v _) = v++binderVars :: [TyVarBndr tv argf] -> [tv]+binderVars tvbs = map binderVar tvbs++binderArgFlag :: TyVarBndr tv argf -> argf+binderArgFlag (TvBndr _ argf) = argf++binderKind :: TyVarBndr TyVar argf -> Kind+binderKind (TvBndr tv _) = tyVarKind tv++{-+************************************************************************+* *+* Type and kind variables *+* *+************************************************************************+-}++tyVarName :: TyVar -> Name+tyVarName = varName++tyVarKind :: TyVar -> Kind+tyVarKind = varType++setTyVarUnique :: TyVar -> Unique -> TyVar+setTyVarUnique = setVarUnique++setTyVarName :: TyVar -> Name -> TyVar+setTyVarName = setVarName++setTyVarKind :: TyVar -> Kind -> TyVar+setTyVarKind tv k = tv {varType = k}++updateTyVarKind :: (Kind -> Kind) -> TyVar -> TyVar+updateTyVarKind update tv = tv {varType = update (tyVarKind tv)}++updateTyVarKindM :: (Monad m) => (Kind -> m Kind) -> TyVar -> m TyVar+updateTyVarKindM update tv+ = do { k' <- update (tyVarKind tv)+ ; return $ tv {varType = k'} }++mkTyVar :: Name -> Kind -> TyVar+mkTyVar name kind = TyVar { varName = name+ , realUnique = getKey (nameUnique name)+ , varType = kind+ }++mkTcTyVar :: Name -> Kind -> TcTyVarDetails -> TyVar+mkTcTyVar name kind details+ = -- NB: 'kind' may be a coercion kind; cf, 'TcMType.newMetaCoVar'+ TcTyVar { varName = name,+ realUnique = getKey (nameUnique name),+ varType = kind,+ tc_tv_details = details+ }++tcTyVarDetails :: TyVar -> TcTyVarDetails+-- See Note [TcTyVars in the typechecker] in TcType+tcTyVarDetails (TcTyVar { tc_tv_details = details }) = details+tcTyVarDetails (TyVar {}) = vanillaSkolemTv+tcTyVarDetails var = pprPanic "tcTyVarDetails" (ppr var <+> dcolon <+> pprKind (tyVarKind var))++setTcTyVarDetails :: TyVar -> TcTyVarDetails -> TyVar+setTcTyVarDetails tv details = tv { tc_tv_details = details }++-------------------------------------+instance Outputable tv => Outputable (TyVarBndr tv ArgFlag) where+ ppr (TvBndr v Required) = ppr v+ ppr (TvBndr v Specified) = char '@' <> ppr v+ ppr (TvBndr v Inferred) = braces (ppr v)++instance Outputable ArgFlag where+ ppr Required = text "[req]"+ ppr Specified = text "[spec]"+ ppr Inferred = text "[infrd]"++instance (Binary tv, Binary vis) => Binary (TyVarBndr tv vis) where+ put_ bh (TvBndr tv vis) = do { put_ bh tv; put_ bh vis }++ get bh = do { tv <- get bh; vis <- get bh; return (TvBndr tv vis) }+++instance Binary ArgFlag where+ put_ bh Required = putByte bh 0+ put_ bh Specified = putByte bh 1+ put_ bh Inferred = putByte bh 2++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return Required+ 1 -> return Specified+ _ -> return Inferred++{-+%************************************************************************+%* *+\subsection{Ids}+* *+************************************************************************+-}++idInfo :: HasDebugCallStack => Id -> IdInfo+idInfo (Id { id_info = info }) = info+idInfo other = pprPanic "idInfo" (ppr other)++idDetails :: Id -> IdDetails+idDetails (Id { id_details = details }) = details+idDetails other = pprPanic "idDetails" (ppr other)++-- The next three have a 'Var' suffix even though they always build+-- Ids, because Id.hs uses 'mkGlobalId' etc with different types+mkGlobalVar :: IdDetails -> Name -> Type -> IdInfo -> Id+mkGlobalVar details name ty info+ = mk_id name ty GlobalId details info++mkLocalVar :: IdDetails -> Name -> Type -> IdInfo -> Id+mkLocalVar details name ty info+ = mk_id name ty (LocalId NotExported) details info++mkCoVar :: Name -> Type -> CoVar+-- Coercion variables have no IdInfo+mkCoVar name ty = mk_id name ty (LocalId NotExported) coVarDetails vanillaIdInfo++-- | Exported 'Var's will not be removed as dead code+mkExportedLocalVar :: IdDetails -> Name -> Type -> IdInfo -> Id+mkExportedLocalVar details name ty info+ = mk_id name ty (LocalId Exported) details info++mk_id :: Name -> Type -> IdScope -> IdDetails -> IdInfo -> Id+mk_id name ty scope details info+ = Id { varName = name,+ realUnique = getKey (nameUnique name),+ varType = ty,+ idScope = scope,+ id_details = details,+ id_info = info }++-------------------+lazySetIdInfo :: Id -> IdInfo -> Var+lazySetIdInfo id info = id { id_info = info }++setIdDetails :: Id -> IdDetails -> Id+setIdDetails id details = id { id_details = details }++globaliseId :: Id -> Id+-- ^ If it's a local, make it global+globaliseId id = id { idScope = GlobalId }++setIdExported :: Id -> Id+-- ^ Exports the given local 'Id'. Can also be called on global 'Id's, such as data constructors+-- and class operations, which are born as global 'Id's and automatically exported+setIdExported id@(Id { idScope = LocalId {} }) = id { idScope = LocalId Exported }+setIdExported id@(Id { idScope = GlobalId }) = id+setIdExported tv = pprPanic "setIdExported" (ppr tv)++setIdNotExported :: Id -> Id+-- ^ We can only do this to LocalIds+setIdNotExported id = ASSERT( isLocalId id )+ id { idScope = LocalId NotExported }++{-+************************************************************************+* *+\subsection{Predicates over variables}+* *+************************************************************************+-}++isTyVar :: Var -> Bool -- True of both TyVar and TcTyVar+isTyVar (TyVar {}) = True+isTyVar (TcTyVar {}) = True+isTyVar _ = False++isTcTyVar :: Var -> Bool -- True of TcTyVar only+isTcTyVar (TcTyVar {}) = True+isTcTyVar _ = False++isTyCoVar :: Var -> Bool+isTyCoVar v = isTyVar v || isCoVar v++isId :: Var -> Bool+isId (Id {}) = True+isId _ = False++isCoVar :: Var -> Bool+-- A coercion variable+isCoVar (Id { id_details = details }) = isCoVarDetails details+isCoVar _ = False++isNonCoVarId :: Var -> Bool+-- A term variable (Id) that is /not/ a coercion variable+isNonCoVarId (Id { id_details = details }) = not (isCoVarDetails details)+isNonCoVarId _ = False++isLocalId :: Var -> Bool+isLocalId (Id { idScope = LocalId _ }) = True+isLocalId _ = False++-- | 'isLocalVar' returns @True@ for type variables as well as local 'Id's+-- These are the variables that we need to pay attention to when finding free+-- variables, or doing dependency analysis.+isLocalVar :: Var -> Bool+isLocalVar v = not (isGlobalId v)++isGlobalId :: Var -> Bool+isGlobalId (Id { idScope = GlobalId }) = True+isGlobalId _ = False++-- | 'mustHaveLocalBinding' returns @True@ of 'Id's and 'TyVar's+-- that must have a binding in this module. The converse+-- is not quite right: there are some global 'Id's that must have+-- bindings, such as record selectors. But that doesn't matter,+-- because it's only used for assertions+mustHaveLocalBinding :: Var -> Bool+mustHaveLocalBinding var = isLocalVar var++-- | 'isExportedIdVar' means \"don't throw this away\"+isExportedId :: Var -> Bool+isExportedId (Id { idScope = GlobalId }) = True+isExportedId (Id { idScope = LocalId Exported}) = True+isExportedId _ = False
+ basicTypes/VarEnv.hs view
@@ -0,0 +1,598 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++module VarEnv (+ -- * Var, Id and TyVar environments (maps)+ VarEnv, IdEnv, TyVarEnv, CoVarEnv, TyCoVarEnv,++ -- ** Manipulating these environments+ emptyVarEnv, unitVarEnv, mkVarEnv, mkVarEnv_Directly,+ elemVarEnv, disjointVarEnv,+ extendVarEnv, extendVarEnv_C, extendVarEnv_Acc, extendVarEnv_Directly,+ extendVarEnvList,+ plusVarEnv, plusVarEnv_C, plusVarEnv_CD, plusMaybeVarEnv_C,+ plusVarEnvList, alterVarEnv,+ delVarEnvList, delVarEnv, delVarEnv_Directly,+ minusVarEnv, intersectsVarEnv,+ lookupVarEnv, lookupVarEnv_NF, lookupWithDefaultVarEnv,+ mapVarEnv, zipVarEnv,+ modifyVarEnv, modifyVarEnv_Directly,+ isEmptyVarEnv,+ elemVarEnvByKey, lookupVarEnv_Directly,+ filterVarEnv, filterVarEnv_Directly, restrictVarEnv,+ partitionVarEnv,++ -- * Deterministic Var environments (maps)+ DVarEnv, DIdEnv, DTyVarEnv,++ -- ** Manipulating these environments+ emptyDVarEnv, mkDVarEnv,+ dVarEnvElts,+ extendDVarEnv, extendDVarEnv_C,+ extendDVarEnvList,+ lookupDVarEnv, elemDVarEnv,+ isEmptyDVarEnv, foldDVarEnv,+ mapDVarEnv,+ modifyDVarEnv,+ alterDVarEnv,+ plusDVarEnv, plusDVarEnv_C,+ unitDVarEnv,+ delDVarEnv,+ delDVarEnvList,+ minusDVarEnv,+ partitionDVarEnv,+ anyDVarEnv,++ -- * The InScopeSet type+ InScopeSet,++ -- ** Operations on InScopeSets+ emptyInScopeSet, mkInScopeSet, delInScopeSet,+ extendInScopeSet, extendInScopeSetList, extendInScopeSetSet,+ getInScopeVars, lookupInScope, lookupInScope_Directly,+ unionInScope, elemInScopeSet, uniqAway,+ varSetInScope,++ -- * The RnEnv2 type+ RnEnv2,++ -- ** Operations on RnEnv2s+ mkRnEnv2, rnBndr2, rnBndrs2, rnBndr2_var,+ rnOccL, rnOccR, inRnEnvL, inRnEnvR, rnOccL_maybe, rnOccR_maybe,+ rnBndrL, rnBndrR, nukeRnEnvL, nukeRnEnvR, rnSwap,+ delBndrL, delBndrR, delBndrsL, delBndrsR,+ addRnInScopeSet,+ rnEtaL, rnEtaR,+ rnInScope, rnInScopeSet, lookupRnInScope,+ rnEnvL, rnEnvR,++ -- * TidyEnv and its operation+ TidyEnv,+ emptyTidyEnv+ ) where++import OccName+import Var+import VarSet+import UniqSet+import UniqFM+import UniqDFM+import Unique+import Util+import Maybes+import Outputable++{-+************************************************************************+* *+ In-scope sets+* *+************************************************************************+-}++-- | A set of variables that are in scope at some point+-- "Secrets of the Glasgow Haskell Compiler inliner" Section 3.2 provides+-- the motivation for this abstraction.+data InScopeSet = InScope VarSet {-# UNPACK #-} !Int+ -- We store a VarSet here, but we use this for lookups rather than+ -- just membership tests. Typically the InScopeSet contains the+ -- canonical version of the variable (e.g. with an informative+ -- unfolding), so this lookup is useful.+ --+ -- The Int is a kind of hash-value used by uniqAway+ -- For example, it might be the size of the set+ -- INVARIANT: it's not zero; we use it as a multiplier in uniqAway++instance Outputable InScopeSet where+ ppr (InScope s _) =+ text "InScope" <+>+ braces (fsep (map (ppr . Var.varName) (nonDetEltsUniqSet s)))+ -- It's OK to use nonDetEltsUniqSet here because it's+ -- only for pretty printing+ -- In-scope sets get big, and with -dppr-debug+ -- the output is overwhelming++emptyInScopeSet :: InScopeSet+emptyInScopeSet = InScope emptyVarSet 1++getInScopeVars :: InScopeSet -> VarSet+getInScopeVars (InScope vs _) = vs++mkInScopeSet :: VarSet -> InScopeSet+mkInScopeSet in_scope = InScope in_scope 1++extendInScopeSet :: InScopeSet -> Var -> InScopeSet+extendInScopeSet (InScope in_scope n) v+ = InScope (extendVarSet in_scope v) (n + 1)++extendInScopeSetList :: InScopeSet -> [Var] -> InScopeSet+extendInScopeSetList (InScope in_scope n) vs+ = InScope (foldl (\s v -> extendVarSet s v) in_scope vs)+ (n + length vs)++extendInScopeSetSet :: InScopeSet -> VarSet -> InScopeSet+extendInScopeSetSet (InScope in_scope n) vs+ = InScope (in_scope `unionVarSet` vs) (n + sizeUniqSet vs)++delInScopeSet :: InScopeSet -> Var -> InScopeSet+delInScopeSet (InScope in_scope n) v = InScope (in_scope `delVarSet` v) n++elemInScopeSet :: Var -> InScopeSet -> Bool+elemInScopeSet v (InScope in_scope _) = v `elemVarSet` in_scope++-- | Look up a variable the 'InScopeSet'. This lets you map from+-- the variable's identity (unique) to its full value.+lookupInScope :: InScopeSet -> Var -> Maybe Var+lookupInScope (InScope in_scope _) v = lookupVarSet in_scope v++lookupInScope_Directly :: InScopeSet -> Unique -> Maybe Var+lookupInScope_Directly (InScope in_scope _) uniq+ = lookupVarSet_Directly in_scope uniq++unionInScope :: InScopeSet -> InScopeSet -> InScopeSet+unionInScope (InScope s1 _) (InScope s2 n2)+ = InScope (s1 `unionVarSet` s2) n2++varSetInScope :: VarSet -> InScopeSet -> Bool+varSetInScope vars (InScope s1 _) = vars `subVarSet` s1++-- | @uniqAway in_scope v@ finds a unique that is not used in the+-- in-scope set, and gives that to v.+uniqAway :: InScopeSet -> Var -> Var+-- It starts with v's current unique, of course, in the hope that it won't+-- have to change, and thereafter uses a combination of that and the hash-code+-- found in the in-scope set+uniqAway in_scope var+ | var `elemInScopeSet` in_scope = uniqAway' in_scope var -- Make a new one+ | otherwise = var -- Nothing to do++uniqAway' :: InScopeSet -> Var -> Var+-- This one *always* makes up a new variable+uniqAway' (InScope set n) var+ = try 1+ where+ orig_unique = getUnique var+ try k+ | debugIsOn && (k > 1000)+ = pprPanic "uniqAway loop:" msg+ | uniq `elemVarSetByKey` set = try (k + 1)+ | k > 3+ = pprTraceDebug "uniqAway:" msg+ setVarUnique var uniq+ | otherwise = setVarUnique var uniq+ where+ msg = ppr k <+> text "tries" <+> ppr var <+> int n+ uniq = deriveUnique orig_unique (n * k)++{-+************************************************************************+* *+ Dual renaming+* *+************************************************************************+-}++-- | Rename Environment 2+--+-- When we are comparing (or matching) types or terms, we are faced with+-- \"going under\" corresponding binders. E.g. when comparing:+--+-- > \x. e1 ~ \y. e2+--+-- Basically we want to rename [@x@ -> @y@] or [@y@ -> @x@], but there are lots of+-- things we must be careful of. In particular, @x@ might be free in @e2@, or+-- y in @e1@. So the idea is that we come up with a fresh binder that is free+-- in neither, and rename @x@ and @y@ respectively. That means we must maintain:+--+-- 1. A renaming for the left-hand expression+--+-- 2. A renaming for the right-hand expressions+--+-- 3. An in-scope set+--+-- Furthermore, when matching, we want to be able to have an 'occurs check',+-- to prevent:+--+-- > \x. f ~ \y. y+--+-- matching with [@f@ -> @y@]. So for each expression we want to know that set of+-- locally-bound variables. That is precisely the domain of the mappings 1.+-- and 2., but we must ensure that we always extend the mappings as we go in.+--+-- All of this information is bundled up in the 'RnEnv2'+data RnEnv2+ = RV2 { envL :: VarEnv Var -- Renaming for Left term+ , envR :: VarEnv Var -- Renaming for Right term+ , in_scope :: InScopeSet } -- In scope in left or right terms++-- The renamings envL and envR are *guaranteed* to contain a binding+-- for every variable bound as we go into the term, even if it is not+-- renamed. That way we can ask what variables are locally bound+-- (inRnEnvL, inRnEnvR)++mkRnEnv2 :: InScopeSet -> RnEnv2+mkRnEnv2 vars = RV2 { envL = emptyVarEnv+ , envR = emptyVarEnv+ , in_scope = vars }++addRnInScopeSet :: RnEnv2 -> VarSet -> RnEnv2+addRnInScopeSet env vs+ | isEmptyVarSet vs = env+ | otherwise = env { in_scope = extendInScopeSetSet (in_scope env) vs }++rnInScope :: Var -> RnEnv2 -> Bool+rnInScope x env = x `elemInScopeSet` in_scope env++rnInScopeSet :: RnEnv2 -> InScopeSet+rnInScopeSet = in_scope++-- | Retrieve the left mapping+rnEnvL :: RnEnv2 -> VarEnv Var+rnEnvL = envL++-- | Retrieve the right mapping+rnEnvR :: RnEnv2 -> VarEnv Var+rnEnvR = envR++rnBndrs2 :: RnEnv2 -> [Var] -> [Var] -> RnEnv2+-- ^ Applies 'rnBndr2' to several variables: the two variable lists must be of equal length+rnBndrs2 env bsL bsR = foldl2 rnBndr2 env bsL bsR++rnBndr2 :: RnEnv2 -> Var -> Var -> RnEnv2+-- ^ @rnBndr2 env bL bR@ goes under a binder @bL@ in the Left term,+-- and binder @bR@ in the Right term.+-- It finds a new binder, @new_b@,+-- and returns an environment mapping @bL -> new_b@ and @bR -> new_b@+rnBndr2 env bL bR = fst $ rnBndr2_var env bL bR++rnBndr2_var :: RnEnv2 -> Var -> Var -> (RnEnv2, Var)+-- ^ Similar to 'rnBndr2' but returns the new variable as well as the+-- new environment+rnBndr2_var (RV2 { envL = envL, envR = envR, in_scope = in_scope }) bL bR+ = (RV2 { envL = extendVarEnv envL bL new_b -- See Note+ , envR = extendVarEnv envR bR new_b -- [Rebinding]+ , in_scope = extendInScopeSet in_scope new_b }, new_b)+ where+ -- Find a new binder not in scope in either term+ new_b | not (bL `elemInScopeSet` in_scope) = bL+ | not (bR `elemInScopeSet` in_scope) = bR+ | otherwise = uniqAway' in_scope bL++ -- Note [Rebinding]+ -- If the new var is the same as the old one, note that+ -- the extendVarEnv *deletes* any current renaming+ -- E.g. (\x. \x. ...) ~ (\y. \z. ...)+ --+ -- Inside \x \y { [x->y], [y->y], {y} }+ -- \x \z { [x->x], [y->y, z->x], {y,x} }++rnBndrL :: RnEnv2 -> Var -> (RnEnv2, Var)+-- ^ Similar to 'rnBndr2' but used when there's a binder on the left+-- side only.+rnBndrL (RV2 { envL = envL, envR = envR, in_scope = in_scope }) bL+ = (RV2 { envL = extendVarEnv envL bL new_b+ , envR = envR+ , in_scope = extendInScopeSet in_scope new_b }, new_b)+ where+ new_b = uniqAway in_scope bL++rnBndrR :: RnEnv2 -> Var -> (RnEnv2, Var)+-- ^ Similar to 'rnBndr2' but used when there's a binder on the right+-- side only.+rnBndrR (RV2 { envL = envL, envR = envR, in_scope = in_scope }) bR+ = (RV2 { envR = extendVarEnv envR bR new_b+ , envL = envL+ , in_scope = extendInScopeSet in_scope new_b }, new_b)+ where+ new_b = uniqAway in_scope bR++rnEtaL :: RnEnv2 -> Var -> (RnEnv2, Var)+-- ^ Similar to 'rnBndrL' but used for eta expansion+-- See Note [Eta expansion]+rnEtaL (RV2 { envL = envL, envR = envR, in_scope = in_scope }) bL+ = (RV2 { envL = extendVarEnv envL bL new_b+ , envR = extendVarEnv envR new_b new_b -- Note [Eta expansion]+ , in_scope = extendInScopeSet in_scope new_b }, new_b)+ where+ new_b = uniqAway in_scope bL++rnEtaR :: RnEnv2 -> Var -> (RnEnv2, Var)+-- ^ Similar to 'rnBndr2' but used for eta expansion+-- See Note [Eta expansion]+rnEtaR (RV2 { envL = envL, envR = envR, in_scope = in_scope }) bR+ = (RV2 { envL = extendVarEnv envL new_b new_b -- Note [Eta expansion]+ , envR = extendVarEnv envR bR new_b+ , in_scope = extendInScopeSet in_scope new_b }, new_b)+ where+ new_b = uniqAway in_scope bR++delBndrL, delBndrR :: RnEnv2 -> Var -> RnEnv2+delBndrL rn@(RV2 { envL = env, in_scope = in_scope }) v+ = rn { envL = env `delVarEnv` v, in_scope = in_scope `extendInScopeSet` v }+delBndrR rn@(RV2 { envR = env, in_scope = in_scope }) v+ = rn { envR = env `delVarEnv` v, in_scope = in_scope `extendInScopeSet` v }++delBndrsL, delBndrsR :: RnEnv2 -> [Var] -> RnEnv2+delBndrsL rn@(RV2 { envL = env, in_scope = in_scope }) v+ = rn { envL = env `delVarEnvList` v, in_scope = in_scope `extendInScopeSetList` v }+delBndrsR rn@(RV2 { envR = env, in_scope = in_scope }) v+ = rn { envR = env `delVarEnvList` v, in_scope = in_scope `extendInScopeSetList` v }++rnOccL, rnOccR :: RnEnv2 -> Var -> Var+-- ^ Look up the renaming of an occurrence in the left or right term+rnOccL (RV2 { envL = env }) v = lookupVarEnv env v `orElse` v+rnOccR (RV2 { envR = env }) v = lookupVarEnv env v `orElse` v++rnOccL_maybe, rnOccR_maybe :: RnEnv2 -> Var -> Maybe Var+-- ^ Look up the renaming of an occurrence in the left or right term+rnOccL_maybe (RV2 { envL = env }) v = lookupVarEnv env v+rnOccR_maybe (RV2 { envR = env }) v = lookupVarEnv env v++inRnEnvL, inRnEnvR :: RnEnv2 -> Var -> Bool+-- ^ Tells whether a variable is locally bound+inRnEnvL (RV2 { envL = env }) v = v `elemVarEnv` env+inRnEnvR (RV2 { envR = env }) v = v `elemVarEnv` env++lookupRnInScope :: RnEnv2 -> Var -> Var+lookupRnInScope env v = lookupInScope (in_scope env) v `orElse` v++nukeRnEnvL, nukeRnEnvR :: RnEnv2 -> RnEnv2+-- ^ Wipe the left or right side renaming+nukeRnEnvL env = env { envL = emptyVarEnv }+nukeRnEnvR env = env { envR = emptyVarEnv }++rnSwap :: RnEnv2 -> RnEnv2+-- ^ swap the meaning of left and right+rnSwap (RV2 { envL = envL, envR = envR, in_scope = in_scope })+ = RV2 { envL = envR, envR = envL, in_scope = in_scope }++{-+Note [Eta expansion]+~~~~~~~~~~~~~~~~~~~~+When matching+ (\x.M) ~ N+we rename x to x' with, where x' is not in scope in+either term. Then we want to behave as if we'd seen+ (\x'.M) ~ (\x'.N x')+Since x' isn't in scope in N, the form (\x'. N x') doesn't+capture any variables in N. But we must nevertheless extend+the envR with a binding [x' -> x'], to support the occurs check.+For example, if we don't do this, we can get silly matches like+ forall a. (\y.a) ~ v+succeeding with [a -> v y], which is bogus of course.+++************************************************************************+* *+ Tidying+* *+************************************************************************+-}++-- | Tidy Environment+--+-- When tidying up print names, we keep a mapping of in-scope occ-names+-- (the 'TidyOccEnv') and a Var-to-Var of the current renamings+type TidyEnv = (TidyOccEnv, VarEnv Var)++emptyTidyEnv :: TidyEnv+emptyTidyEnv = (emptyTidyOccEnv, emptyVarEnv)++{-+************************************************************************+* *+\subsection{@VarEnv@s}+* *+************************************************************************+-}++-- | Variable Environment+type VarEnv elt = UniqFM elt++-- | Identifier Environment+type IdEnv elt = VarEnv elt++-- | Type Variable Environment+type TyVarEnv elt = VarEnv elt++-- | Type or Coercion Variable Environment+type TyCoVarEnv elt = VarEnv elt++-- | Coercion Variable Environment+type CoVarEnv elt = VarEnv elt++emptyVarEnv :: VarEnv a+mkVarEnv :: [(Var, a)] -> VarEnv a+mkVarEnv_Directly :: [(Unique, a)] -> VarEnv a+zipVarEnv :: [Var] -> [a] -> VarEnv a+unitVarEnv :: Var -> a -> VarEnv a+alterVarEnv :: (Maybe a -> Maybe a) -> VarEnv a -> Var -> VarEnv a+extendVarEnv :: VarEnv a -> Var -> a -> VarEnv a+extendVarEnv_C :: (a->a->a) -> VarEnv a -> Var -> a -> VarEnv a+extendVarEnv_Acc :: (a->b->b) -> (a->b) -> VarEnv b -> Var -> a -> VarEnv b+extendVarEnv_Directly :: VarEnv a -> Unique -> a -> VarEnv a+plusVarEnv :: VarEnv a -> VarEnv a -> VarEnv a+plusVarEnvList :: [VarEnv a] -> VarEnv a+extendVarEnvList :: VarEnv a -> [(Var, a)] -> VarEnv a++lookupVarEnv_Directly :: VarEnv a -> Unique -> Maybe a+filterVarEnv_Directly :: (Unique -> a -> Bool) -> VarEnv a -> VarEnv a+delVarEnv_Directly :: VarEnv a -> Unique -> VarEnv a+partitionVarEnv :: (a -> Bool) -> VarEnv a -> (VarEnv a, VarEnv a)+restrictVarEnv :: VarEnv a -> VarSet -> VarEnv a+delVarEnvList :: VarEnv a -> [Var] -> VarEnv a+delVarEnv :: VarEnv a -> Var -> VarEnv a+minusVarEnv :: VarEnv a -> VarEnv b -> VarEnv a+intersectsVarEnv :: VarEnv a -> VarEnv a -> Bool+plusVarEnv_C :: (a -> a -> a) -> VarEnv a -> VarEnv a -> VarEnv a+plusVarEnv_CD :: (a -> a -> a) -> VarEnv a -> a -> VarEnv a -> a -> VarEnv a+plusMaybeVarEnv_C :: (a -> a -> Maybe a) -> VarEnv a -> VarEnv a -> VarEnv a+mapVarEnv :: (a -> b) -> VarEnv a -> VarEnv b+modifyVarEnv :: (a -> a) -> VarEnv a -> Var -> VarEnv a++isEmptyVarEnv :: VarEnv a -> Bool+lookupVarEnv :: VarEnv a -> Var -> Maybe a+filterVarEnv :: (a -> Bool) -> VarEnv a -> VarEnv a+lookupVarEnv_NF :: VarEnv a -> Var -> a+lookupWithDefaultVarEnv :: VarEnv a -> a -> Var -> a+elemVarEnv :: Var -> VarEnv a -> Bool+elemVarEnvByKey :: Unique -> VarEnv a -> Bool+disjointVarEnv :: VarEnv a -> VarEnv a -> Bool++elemVarEnv = elemUFM+elemVarEnvByKey = elemUFM_Directly+disjointVarEnv = disjointUFM+alterVarEnv = alterUFM+extendVarEnv = addToUFM+extendVarEnv_C = addToUFM_C+extendVarEnv_Acc = addToUFM_Acc+extendVarEnv_Directly = addToUFM_Directly+extendVarEnvList = addListToUFM+plusVarEnv_C = plusUFM_C+plusVarEnv_CD = plusUFM_CD+plusMaybeVarEnv_C = plusMaybeUFM_C+delVarEnvList = delListFromUFM+delVarEnv = delFromUFM+minusVarEnv = minusUFM+intersectsVarEnv e1 e2 = not (isEmptyVarEnv (e1 `intersectUFM` e2))+plusVarEnv = plusUFM+plusVarEnvList = plusUFMList+lookupVarEnv = lookupUFM+filterVarEnv = filterUFM+lookupWithDefaultVarEnv = lookupWithDefaultUFM+mapVarEnv = mapUFM+mkVarEnv = listToUFM+mkVarEnv_Directly= listToUFM_Directly+emptyVarEnv = emptyUFM+unitVarEnv = unitUFM+isEmptyVarEnv = isNullUFM+lookupVarEnv_Directly = lookupUFM_Directly+filterVarEnv_Directly = filterUFM_Directly+delVarEnv_Directly = delFromUFM_Directly+partitionVarEnv = partitionUFM++restrictVarEnv env vs = filterVarEnv_Directly keep env+ where+ keep u _ = u `elemVarSetByKey` vs++zipVarEnv tyvars tys = mkVarEnv (zipEqual "zipVarEnv" tyvars tys)+lookupVarEnv_NF env id = case lookupVarEnv env id of+ Just xx -> xx+ Nothing -> panic "lookupVarEnv_NF: Nothing"++{-+@modifyVarEnv@: Look up a thing in the VarEnv,+then mash it with the modify function, and put it back.+-}++modifyVarEnv mangle_fn env key+ = case (lookupVarEnv env key) of+ Nothing -> env+ Just xx -> extendVarEnv env key (mangle_fn xx)++modifyVarEnv_Directly :: (a -> a) -> UniqFM a -> Unique -> UniqFM a+modifyVarEnv_Directly mangle_fn env key+ = case (lookupUFM_Directly env key) of+ Nothing -> env+ Just xx -> addToUFM_Directly env key (mangle_fn xx)++-- Deterministic VarEnv+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why we need+-- DVarEnv.++-- | Deterministic Variable Environment+type DVarEnv elt = UniqDFM elt++-- | Deterministic Identifier Environment+type DIdEnv elt = DVarEnv elt++-- | Deterministic Type Variable Environment+type DTyVarEnv elt = DVarEnv elt++emptyDVarEnv :: DVarEnv a+emptyDVarEnv = emptyUDFM++dVarEnvElts :: DVarEnv a -> [a]+dVarEnvElts = eltsUDFM++mkDVarEnv :: [(Var, a)] -> DVarEnv a+mkDVarEnv = listToUDFM++extendDVarEnv :: DVarEnv a -> Var -> a -> DVarEnv a+extendDVarEnv = addToUDFM++minusDVarEnv :: DVarEnv a -> DVarEnv a' -> DVarEnv a+minusDVarEnv = minusUDFM++lookupDVarEnv :: DVarEnv a -> Var -> Maybe a+lookupDVarEnv = lookupUDFM++foldDVarEnv :: (a -> b -> b) -> b -> DVarEnv a -> b+foldDVarEnv = foldUDFM++mapDVarEnv :: (a -> b) -> DVarEnv a -> DVarEnv b+mapDVarEnv = mapUDFM++alterDVarEnv :: (Maybe a -> Maybe a) -> DVarEnv a -> Var -> DVarEnv a+alterDVarEnv = alterUDFM++plusDVarEnv :: DVarEnv a -> DVarEnv a -> DVarEnv a+plusDVarEnv = plusUDFM++plusDVarEnv_C :: (a -> a -> a) -> DVarEnv a -> DVarEnv a -> DVarEnv a+plusDVarEnv_C = plusUDFM_C++unitDVarEnv :: Var -> a -> DVarEnv a+unitDVarEnv = unitUDFM++delDVarEnv :: DVarEnv a -> Var -> DVarEnv a+delDVarEnv = delFromUDFM++delDVarEnvList :: DVarEnv a -> [Var] -> DVarEnv a+delDVarEnvList = delListFromUDFM++isEmptyDVarEnv :: DVarEnv a -> Bool+isEmptyDVarEnv = isNullUDFM++elemDVarEnv :: Var -> DVarEnv a -> Bool+elemDVarEnv = elemUDFM++extendDVarEnv_C :: (a -> a -> a) -> DVarEnv a -> Var -> a -> DVarEnv a+extendDVarEnv_C = addToUDFM_C++modifyDVarEnv :: (a -> a) -> DVarEnv a -> Var -> DVarEnv a+modifyDVarEnv mangle_fn env key+ = case (lookupDVarEnv env key) of+ Nothing -> env+ Just xx -> extendDVarEnv env key (mangle_fn xx)++partitionDVarEnv :: (a -> Bool) -> DVarEnv a -> (DVarEnv a, DVarEnv a)+partitionDVarEnv = partitionUDFM++extendDVarEnvList :: DVarEnv a -> [(Var, a)] -> DVarEnv a+extendDVarEnvList = addListToUDFM++anyDVarEnv :: (a -> Bool) -> DVarEnv a -> Bool+anyDVarEnv = anyUDFM
+ basicTypes/VarSet.hs view
@@ -0,0 +1,340 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP #-}++module VarSet (+ -- * Var, Id and TyVar set types+ VarSet, IdSet, TyVarSet, CoVarSet, TyCoVarSet,++ -- ** Manipulating these sets+ emptyVarSet, unitVarSet, mkVarSet,+ extendVarSet, extendVarSetList,+ elemVarSet, subVarSet,+ unionVarSet, unionVarSets, mapUnionVarSet,+ intersectVarSet, intersectsVarSet, disjointVarSet,+ isEmptyVarSet, delVarSet, delVarSetList, delVarSetByKey,+ minusVarSet, filterVarSet,+ anyVarSet, allVarSet,+ transCloVarSet, fixVarSet,+ lookupVarSet_Directly, lookupVarSet, lookupVarSetByName,+ sizeVarSet, seqVarSet,+ elemVarSetByKey, partitionVarSet,+ pluralVarSet, pprVarSet,++ -- * Deterministic Var set types+ DVarSet, DIdSet, DTyVarSet, DTyCoVarSet,++ -- ** Manipulating these sets+ emptyDVarSet, unitDVarSet, mkDVarSet,+ extendDVarSet, extendDVarSetList,+ elemDVarSet, dVarSetElems, subDVarSet,+ unionDVarSet, unionDVarSets, mapUnionDVarSet,+ intersectDVarSet, intersectsDVarSet, disjointDVarSet,+ isEmptyDVarSet, delDVarSet, delDVarSetList,+ minusDVarSet, foldDVarSet, filterDVarSet,+ dVarSetMinusVarSet, anyDVarSet, allDVarSet,+ transCloDVarSet,+ sizeDVarSet, seqDVarSet,+ partitionDVarSet,+ dVarSetToVarSet,+ ) where++#include "HsVersions.h"++import Var ( Var, TyVar, CoVar, TyCoVar, Id )+import Unique+import Name ( Name )+import UniqSet+import UniqDSet+import UniqFM( disjointUFM, pluralUFM, pprUFM )+import UniqDFM( disjointUDFM, udfmToUfm, anyUDFM, allUDFM )+import Outputable (SDoc)++-- | A non-deterministic Variable Set+--+-- A non-deterministic set of variables.+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why it's not+-- deterministic and why it matters. Use DVarSet if the set eventually+-- gets converted into a list or folded over in a way where the order+-- changes the generated code, for example when abstracting variables.+type VarSet = UniqSet Var++-- | Identifier Set+type IdSet = UniqSet Id++-- | Type Variable Set+type TyVarSet = UniqSet TyVar++-- | Coercion Variable Set+type CoVarSet = UniqSet CoVar++-- | Type or Coercion Variable Set+type TyCoVarSet = UniqSet TyCoVar++emptyVarSet :: VarSet+intersectVarSet :: VarSet -> VarSet -> VarSet+unionVarSet :: VarSet -> VarSet -> VarSet+unionVarSets :: [VarSet] -> VarSet++mapUnionVarSet :: (a -> VarSet) -> [a] -> VarSet+-- ^ map the function over the list, and union the results++unitVarSet :: Var -> VarSet+extendVarSet :: VarSet -> Var -> VarSet+extendVarSetList:: VarSet -> [Var] -> VarSet+elemVarSet :: Var -> VarSet -> Bool+delVarSet :: VarSet -> Var -> VarSet+delVarSetList :: VarSet -> [Var] -> VarSet+minusVarSet :: VarSet -> VarSet -> VarSet+isEmptyVarSet :: VarSet -> Bool+mkVarSet :: [Var] -> VarSet+lookupVarSet_Directly :: VarSet -> Unique -> Maybe Var+lookupVarSet :: VarSet -> Var -> Maybe Var+ -- Returns the set element, which may be+ -- (==) to the argument, but not the same as+lookupVarSetByName :: VarSet -> Name -> Maybe Var+sizeVarSet :: VarSet -> Int+filterVarSet :: (Var -> Bool) -> VarSet -> VarSet++delVarSetByKey :: VarSet -> Unique -> VarSet+elemVarSetByKey :: Unique -> VarSet -> Bool+partitionVarSet :: (Var -> Bool) -> VarSet -> (VarSet, VarSet)++emptyVarSet = emptyUniqSet+unitVarSet = unitUniqSet+extendVarSet = addOneToUniqSet+extendVarSetList= addListToUniqSet+intersectVarSet = intersectUniqSets++intersectsVarSet:: VarSet -> VarSet -> Bool -- True if non-empty intersection+disjointVarSet :: VarSet -> VarSet -> Bool -- True if empty intersection+subVarSet :: VarSet -> VarSet -> Bool -- True if first arg is subset of second+ -- (s1 `intersectsVarSet` s2) doesn't compute s2 if s1 is empty;+ -- ditto disjointVarSet, subVarSet++unionVarSet = unionUniqSets+unionVarSets = unionManyUniqSets+elemVarSet = elementOfUniqSet+minusVarSet = minusUniqSet+delVarSet = delOneFromUniqSet+delVarSetList = delListFromUniqSet+isEmptyVarSet = isEmptyUniqSet+mkVarSet = mkUniqSet+lookupVarSet_Directly = lookupUniqSet_Directly+lookupVarSet = lookupUniqSet+lookupVarSetByName = lookupUniqSet+sizeVarSet = sizeUniqSet+filterVarSet = filterUniqSet+delVarSetByKey = delOneFromUniqSet_Directly+elemVarSetByKey = elemUniqSet_Directly+partitionVarSet = partitionUniqSet++mapUnionVarSet get_set xs = foldr (unionVarSet . get_set) emptyVarSet xs++-- See comments with type signatures+intersectsVarSet s1 s2 = not (s1 `disjointVarSet` s2)+disjointVarSet s1 s2 = disjointUFM (getUniqSet s1) (getUniqSet s2)+subVarSet s1 s2 = isEmptyVarSet (s1 `minusVarSet` s2)++anyVarSet :: (Var -> Bool) -> VarSet -> Bool+anyVarSet = uniqSetAny++allVarSet :: (Var -> Bool) -> VarSet -> Bool+allVarSet = uniqSetAll++-- There used to exist mapVarSet, see Note [Unsound mapUniqSet] in UniqSet for+-- why it got removed.++fixVarSet :: (VarSet -> VarSet) -- Map the current set to a new set+ -> VarSet -> VarSet+-- (fixVarSet f s) repeatedly applies f to the set s,+-- until it reaches a fixed point.+fixVarSet fn vars+ | new_vars `subVarSet` vars = vars+ | otherwise = fixVarSet fn new_vars+ where+ new_vars = fn vars++transCloVarSet :: (VarSet -> VarSet)+ -- Map some variables in the set to+ -- extra variables that should be in it+ -> VarSet -> VarSet+-- (transCloVarSet f s) repeatedly applies f to new candidates, adding any+-- new variables to s that it finds thereby, until it reaches a fixed point.+--+-- The function fn could be (Var -> VarSet), but we use (VarSet -> VarSet)+-- for efficiency, so that the test can be batched up.+-- It's essential that fn will work fine if given new candidates+-- one at at time; ie fn {v1,v2} = fn v1 `union` fn v2+-- Use fixVarSet if the function needs to see the whole set all at once+transCloVarSet fn seeds+ = go seeds seeds+ where+ go :: VarSet -- Accumulating result+ -> VarSet -- Work-list; un-processed subset of accumulating result+ -> VarSet+ -- Specification: go acc vs = acc `union` transClo fn vs++ go acc candidates+ | isEmptyVarSet new_vs = acc+ | otherwise = go (acc `unionVarSet` new_vs) new_vs+ where+ new_vs = fn candidates `minusVarSet` acc++seqVarSet :: VarSet -> ()+seqVarSet s = sizeVarSet s `seq` ()++-- | Determines the pluralisation suffix appropriate for the length of a set+-- in the same way that plural from Outputable does for lists.+pluralVarSet :: VarSet -> SDoc+pluralVarSet = pluralUFM . getUniqSet++-- | Pretty-print a non-deterministic set.+-- The order of variables is non-deterministic and for pretty-printing that+-- shouldn't be a problem.+-- Having this function helps contain the non-determinism created with+-- nonDetEltsUFM.+-- Passing a list to the pretty-printing function allows the caller+-- to decide on the order of Vars (eg. toposort them) without them having+-- to use nonDetEltsUFM at the call site. This prevents from let-binding+-- non-deterministically ordered lists and reusing them where determinism+-- matters.+pprVarSet :: VarSet -- ^ The things to be pretty printed+ -> ([Var] -> SDoc) -- ^ The pretty printing function to use on the+ -- elements+ -> SDoc -- ^ 'SDoc' where the things have been pretty+ -- printed+pprVarSet = pprUFM . getUniqSet++-- Deterministic VarSet+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why we need+-- DVarSet.++-- | Deterministic Variable Set+type DVarSet = UniqDSet Var++-- | Deterministic Identifier Set+type DIdSet = UniqDSet Id++-- | Deterministic Type Variable Set+type DTyVarSet = UniqDSet TyVar++-- | Deterministic Type or Coercion Variable Set+type DTyCoVarSet = UniqDSet TyCoVar++emptyDVarSet :: DVarSet+emptyDVarSet = emptyUniqDSet++unitDVarSet :: Var -> DVarSet+unitDVarSet = unitUniqDSet++mkDVarSet :: [Var] -> DVarSet+mkDVarSet = mkUniqDSet++extendDVarSet :: DVarSet -> Var -> DVarSet+extendDVarSet = addOneToUniqDSet++elemDVarSet :: Var -> DVarSet -> Bool+elemDVarSet = elementOfUniqDSet++dVarSetElems :: DVarSet -> [Var]+dVarSetElems = uniqDSetToList++subDVarSet :: DVarSet -> DVarSet -> Bool+subDVarSet s1 s2 = isEmptyDVarSet (s1 `minusDVarSet` s2)++unionDVarSet :: DVarSet -> DVarSet -> DVarSet+unionDVarSet = unionUniqDSets++unionDVarSets :: [DVarSet] -> DVarSet+unionDVarSets = unionManyUniqDSets++-- | Map the function over the list, and union the results+mapUnionDVarSet :: (a -> DVarSet) -> [a] -> DVarSet+mapUnionDVarSet get_set xs = foldr (unionDVarSet . get_set) emptyDVarSet xs++intersectDVarSet :: DVarSet -> DVarSet -> DVarSet+intersectDVarSet = intersectUniqDSets++-- | True if empty intersection+disjointDVarSet :: DVarSet -> DVarSet -> Bool+disjointDVarSet s1 s2 = disjointUDFM s1 s2++-- | True if non-empty intersection+intersectsDVarSet :: DVarSet -> DVarSet -> Bool+intersectsDVarSet s1 s2 = not (s1 `disjointDVarSet` s2)++isEmptyDVarSet :: DVarSet -> Bool+isEmptyDVarSet = isEmptyUniqDSet++delDVarSet :: DVarSet -> Var -> DVarSet+delDVarSet = delOneFromUniqDSet++minusDVarSet :: DVarSet -> DVarSet -> DVarSet+minusDVarSet = minusUniqDSet++dVarSetMinusVarSet :: DVarSet -> VarSet -> DVarSet+dVarSetMinusVarSet = uniqDSetMinusUniqSet++foldDVarSet :: (Var -> a -> a) -> a -> DVarSet -> a+foldDVarSet = foldUniqDSet++anyDVarSet :: (Var -> Bool) -> DVarSet -> Bool+anyDVarSet = anyUDFM++allDVarSet :: (Var -> Bool) -> DVarSet -> Bool+allDVarSet = allUDFM++filterDVarSet :: (Var -> Bool) -> DVarSet -> DVarSet+filterDVarSet = filterUniqDSet++sizeDVarSet :: DVarSet -> Int+sizeDVarSet = sizeUniqDSet++-- | Partition DVarSet according to the predicate given+partitionDVarSet :: (Var -> Bool) -> DVarSet -> (DVarSet, DVarSet)+partitionDVarSet = partitionUniqDSet++-- | Delete a list of variables from DVarSet+delDVarSetList :: DVarSet -> [Var] -> DVarSet+delDVarSetList = delListFromUniqDSet++seqDVarSet :: DVarSet -> ()+seqDVarSet s = sizeDVarSet s `seq` ()++-- | Add a list of variables to DVarSet+extendDVarSetList :: DVarSet -> [Var] -> DVarSet+extendDVarSetList = addListToUniqDSet++-- | Convert a DVarSet to a VarSet by forgeting the order of insertion+dVarSetToVarSet :: DVarSet -> VarSet+dVarSetToVarSet = unsafeUFMToUniqSet . udfmToUfm++-- | transCloVarSet for DVarSet+transCloDVarSet :: (DVarSet -> DVarSet)+ -- Map some variables in the set to+ -- extra variables that should be in it+ -> DVarSet -> DVarSet+-- (transCloDVarSet f s) repeatedly applies f to new candidates, adding any+-- new variables to s that it finds thereby, until it reaches a fixed point.+--+-- The function fn could be (Var -> DVarSet), but we use (DVarSet -> DVarSet)+-- for efficiency, so that the test can be batched up.+-- It's essential that fn will work fine if given new candidates+-- one at at time; ie fn {v1,v2} = fn v1 `union` fn v2+transCloDVarSet fn seeds+ = go seeds seeds+ where+ go :: DVarSet -- Accumulating result+ -> DVarSet -- Work-list; un-processed subset of accumulating result+ -> DVarSet+ -- Specification: go acc vs = acc `union` transClo fn vs++ go acc candidates+ | isEmptyDVarSet new_vs = acc+ | otherwise = go (acc `unionDVarSet` new_vs) new_vs+ where+ new_vs = fn candidates `minusDVarSet` acc
+ cbits/genSym.c view
@@ -0,0 +1,40 @@+#include <assert.h>+#include "Rts.h"+#include "Unique.h"++static HsInt GenSymCounter = 0;+static HsInt GenSymInc = 1;++#define UNIQUE_BITS (sizeof (HsInt) * 8 - UNIQUE_TAG_BITS)+#define UNIQUE_MASK ((1ULL << UNIQUE_BITS) - 1)++STATIC_INLINE void checkUniqueRange(HsInt u STG_UNUSED) {+#if DEBUG+ // Uh oh! We will overflow next time a unique is requested.+ assert(u != UNIQUE_MASK);+#endif+}++HsInt genSym(void) {+#if defined(THREADED_RTS)+ if (n_capabilities == 1) {+ GenSymCounter = (GenSymCounter + GenSymInc) & UNIQUE_MASK;+ checkUniqueRange(GenSymCounter);+ return GenSymCounter;+ } else {+ HsInt n = atomic_inc((StgWord *)&GenSymCounter, GenSymInc)+ & UNIQUE_MASK;+ checkUniqueRange(n);+ return n;+ }+#else+ GenSymCounter = (GenSymCounter + GenSymInc) & UNIQUE_MASK;+ checkUniqueRange(GenSymCounter);+ return GenSymCounter;+#endif+}++void initGenSym(HsInt NewGenSymCounter, HsInt NewGenSymInc) {+ GenSymCounter = NewGenSymCounter;+ GenSymInc = NewGenSymInc;+}
+ cmm/Bitmap.hs view
@@ -0,0 +1,136 @@+{-# LANGUAGE CPP, BangPatterns #-}++--+-- (c) The University of Glasgow 2003-2006+--++-- Functions for constructing bitmaps, which are used in various+-- places in generated code (stack frame liveness masks, function+-- argument liveness masks, SRT bitmaps).++module Bitmap (+ Bitmap, mkBitmap,+ intsToBitmap, intsToReverseBitmap,+ mAX_SMALL_BITMAP_SIZE,+ seqBitmap,+ ) where++#include "HsVersions.h"+#include "MachDeps.h"++import SMRep+import DynFlags+import Util++import Data.Foldable (foldl')+import Data.Bits++{-|+A bitmap represented by a sequence of 'StgWord's on the /target/+architecture. These are used for bitmaps in info tables and other+generated code which need to be emitted as sequences of StgWords.+-}+type Bitmap = [StgWord]++-- | Make a bitmap from a sequence of bits+mkBitmap :: DynFlags -> [Bool] -> Bitmap+mkBitmap _ [] = []+mkBitmap dflags stuff = chunkToBitmap dflags chunk : mkBitmap dflags rest+ where (chunk, rest) = splitAt (wORD_SIZE_IN_BITS dflags) stuff++chunkToBitmap :: DynFlags -> [Bool] -> StgWord+chunkToBitmap dflags chunk =+ foldl' (.|.) (toStgWord dflags 0) [ oneAt n | (True,n) <- zip chunk [0..] ]+ where+ oneAt :: Int -> StgWord+ oneAt i = toStgWord dflags 1 `shiftL` i++-- | Make a bitmap where the slots specified are the /ones/ in the bitmap.+-- eg. @[0,1,3], size 4 ==> 0xb@.+--+-- The list of @Int@s /must/ be already sorted.+intsToBitmap :: DynFlags+ -> Int -- ^ size in bits+ -> [Int] -- ^ sorted indices of ones+ -> Bitmap+intsToBitmap dflags size = go 0+ where+ word_sz = wORD_SIZE_IN_BITS dflags+ oneAt :: Int -> StgWord+ oneAt i = toStgWord dflags 1 `shiftL` i++ -- It is important that we maintain strictness here.+ -- See Note [Strictness when building Bitmaps].+ go :: Int -> [Int] -> Bitmap+ go !pos slots+ | size <= pos = []+ | otherwise =+ (foldl' (.|.) (toStgWord dflags 0) (map (\i->oneAt (i - pos)) these)) :+ go (pos + word_sz) rest+ where+ (these,rest) = span (< (pos + word_sz)) slots++-- | Make a bitmap where the slots specified are the /zeros/ in the bitmap.+-- eg. @[0,1,3], size 4 ==> 0x4@ (we leave any bits outside the size as zero,+-- just to make the bitmap easier to read).+--+-- The list of @Int@s /must/ be already sorted and duplicate-free.+intsToReverseBitmap :: DynFlags+ -> Int -- ^ size in bits+ -> [Int] -- ^ sorted indices of zeros free of duplicates+ -> Bitmap+intsToReverseBitmap dflags size = go 0+ where+ word_sz = wORD_SIZE_IN_BITS dflags+ oneAt :: Int -> StgWord+ oneAt i = toStgWord dflags 1 `shiftL` i++ -- It is important that we maintain strictness here.+ -- See Note [Strictness when building Bitmaps].+ go :: Int -> [Int] -> Bitmap+ go !pos slots+ | size <= pos = []+ | otherwise =+ (foldl' xor (toStgWord dflags init) (map (\i->oneAt (i - pos)) these)) :+ go (pos + word_sz) rest+ where+ (these,rest) = span (< (pos + word_sz)) slots+ remain = size - pos+ init+ | remain >= word_sz = -1+ | otherwise = (1 `shiftL` remain) - 1++{-++Note [Strictness when building Bitmaps]+========================================++One of the places where @Bitmap@ is used is in in building Static Reference+Tables (SRTs) (in @CmmBuildInfoTables.procpointSRT@). In #7450 it was noticed+that some test cases (particularly those whose C-- have large numbers of CAFs)+produced large quantities of allocations from this function.++The source traced back to 'intsToBitmap', which was lazily subtracting the word+size from the elements of the tail of the @slots@ list and recursively invoking+itself with the result. This resulted in large numbers of subtraction thunks+being built up. Here we take care to avoid passing new thunks to the recursive+call. Instead we pass the unmodified tail along with an explicit position+accumulator, which get subtracted in the fold when we compute the Word.++-}++{- |+Magic number, must agree with @BITMAP_BITS_SHIFT@ in InfoTables.h.+Some kinds of bitmap pack a size\/bitmap into a single word if+possible, or fall back to an external pointer when the bitmap is too+large. This value represents the largest size of bitmap that can be+packed into a single word.+-}+mAX_SMALL_BITMAP_SIZE :: DynFlags -> Int+mAX_SMALL_BITMAP_SIZE dflags+ | wORD_SIZE dflags == 4 = 27+ | otherwise = 58++seqBitmap :: Bitmap -> a -> a+seqBitmap = seqList+
+ cmm/BlockId.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{- BlockId module should probably go away completely, being superseded by Label -}+module BlockId+ ( BlockId, mkBlockId -- ToDo: BlockId should be abstract, but it isn't yet+ , newBlockId+ , blockLbl, infoTblLbl+ ) where++import CLabel+import IdInfo+import Name+import Outputable+import Unique+import UniqSupply++import Compiler.Hoopl as Hoopl hiding (Unique)+import Compiler.Hoopl.Internals (uniqueToLbl, lblToUnique)++----------------------------------------------------------------+--- Block Ids, their environments, and their sets++{- Note [Unique BlockId]+~~~~~~~~~~~~~~~~~~~~~~~~+Although a 'BlockId' is a local label, for reasons of implementation,+'BlockId's must be unique within an entire compilation unit. The reason+is that each local label is mapped to an assembly-language label, and in+most assembly languages allow, a label is visible throughout the entire+compilation unit in which it appears.+-}++type BlockId = Hoopl.Label++instance Uniquable BlockId where+ getUnique label = getUnique (lblToUnique label)++instance Outputable BlockId where+ ppr label = ppr (getUnique label)++mkBlockId :: Unique -> BlockId+mkBlockId unique = uniqueToLbl $ intToUnique $ getKey unique++newBlockId :: MonadUnique m => m BlockId+newBlockId = mkBlockId <$> getUniqueM++blockLbl :: BlockId -> CLabel+blockLbl label = mkEntryLabel (mkFCallName (getUnique label) "block") NoCafRefs++infoTblLbl :: BlockId -> CLabel+infoTblLbl label = mkInfoTableLabel (mkFCallName (getUnique label) "block") NoCafRefs
+ cmm/CLabel.hs view
@@ -0,0 +1,1332 @@+-----------------------------------------------------------------------------+--+-- Object-file symbols (called CLabel for histerical raisins).+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++{-# LANGUAGE CPP #-}++module CLabel (+ CLabel, -- abstract type+ ForeignLabelSource(..),+ pprDebugCLabel,++ mkClosureLabel,+ mkSRTLabel,+ mkTopSRTLabel,+ mkInfoTableLabel,+ mkEntryLabel,+ mkSlowEntryLabel,+ mkConEntryLabel,+ mkRednCountsLabel,+ mkConInfoTableLabel,+ mkLargeSRTLabel,+ mkApEntryLabel,+ mkApInfoTableLabel,+ mkClosureTableLabel,+ mkBytesLabel,++ mkLocalClosureLabel,+ mkLocalInfoTableLabel,+ mkLocalEntryLabel,+ mkLocalConEntryLabel,+ mkLocalConInfoTableLabel,+ mkLocalClosureTableLabel,++ mkReturnPtLabel,+ mkReturnInfoLabel,+ mkAltLabel,+ mkDefaultLabel,+ mkBitmapLabel,+ mkStringLitLabel,++ mkAsmTempLabel,+ mkAsmTempDerivedLabel,+ mkAsmTempEndLabel,+ mkAsmTempDieLabel,++ mkPlainModuleInitLabel,++ mkSplitMarkerLabel,+ mkDirty_MUT_VAR_Label,+ mkUpdInfoLabel,+ mkBHUpdInfoLabel,+ mkIndStaticInfoLabel,+ mkMainCapabilityLabel,+ mkMAP_FROZEN_infoLabel,+ mkMAP_FROZEN0_infoLabel,+ mkMAP_DIRTY_infoLabel,+ mkSMAP_FROZEN_infoLabel,+ mkSMAP_FROZEN0_infoLabel,+ mkSMAP_DIRTY_infoLabel,+ mkEMPTY_MVAR_infoLabel,+ mkArrWords_infoLabel,++ mkTopTickyCtrLabel,+ mkCAFBlackHoleInfoTableLabel,+ mkCAFBlackHoleEntryLabel,+ mkRtsPrimOpLabel,+ mkRtsSlowFastTickyCtrLabel,++ mkSelectorInfoLabel,+ mkSelectorEntryLabel,++ mkCmmInfoLabel,+ mkCmmEntryLabel,+ mkCmmRetInfoLabel,+ mkCmmRetLabel,+ mkCmmCodeLabel,+ mkCmmDataLabel,+ mkCmmClosureLabel,++ mkRtsApFastLabel,++ mkPrimCallLabel,++ mkForeignLabel,+ addLabelSize,++ foreignLabelStdcallInfo,+ isBytesLabel,+ isForeignLabel,+ mkCCLabel, mkCCSLabel,++ DynamicLinkerLabelInfo(..),+ mkDynamicLinkerLabel,+ dynamicLinkerLabelInfo,++ mkPicBaseLabel,+ mkDeadStripPreventer,++ mkHpcTicksLabel,++ hasCAF,+ needsCDecl, maybeAsmTemp, externallyVisibleCLabel,+ isMathFun,+ isCFunctionLabel, isGcPtrLabel, labelDynamic,++ -- * Conversions+ toClosureLbl, toSlowEntryLbl, toEntryLbl, toInfoLbl, toRednCountsLbl, hasHaskellName,++ pprCLabel+ ) where++#include "HsVersions.h"++import IdInfo+import BasicTypes+import Packages+import Module+import Name+import Unique+import PrimOp+import Config+import CostCentre+import Outputable+import FastString+import DynFlags+import Platform+import UniqSet+import Util+import PprCore ( {- instances -} )++-- -----------------------------------------------------------------------------+-- The CLabel type++{-+ | CLabel is an abstract type that supports the following operations:++ - Pretty printing++ - In a C file, does it need to be declared before use? (i.e. is it+ guaranteed to be already in scope in the places we need to refer to it?)++ - If it needs to be declared, what type (code or data) should it be+ declared to have?++ - Is it visible outside this object file or not?++ - Is it "dynamic" (see details below)++ - Eq and Ord, so that we can make sets of CLabels (currently only+ used in outputting C as far as I can tell, to avoid generating+ more than one declaration for any given label).++ - Converting an info table label into an entry label.+-}++data CLabel+ = -- | A label related to the definition of a particular Id or Con in a .hs file.+ IdLabel+ Name+ CafInfo+ IdLabelInfo -- encodes the suffix of the label++ -- | A label from a .cmm file that is not associated with a .hs level Id.+ | CmmLabel+ UnitId -- what package the label belongs to.+ FastString -- identifier giving the prefix of the label+ CmmLabelInfo -- encodes the suffix of the label++ -- | A label with a baked-in \/ algorithmically generated name that definitely+ -- comes from the RTS. The code for it must compile into libHSrts.a \/ libHSrts.so+ -- If it doesn't have an algorithmically generated name then use a CmmLabel+ -- instead and give it an appropriate UnitId argument.+ | RtsLabel+ RtsLabelInfo++ -- | A 'C' (or otherwise foreign) label.+ --+ | ForeignLabel+ FastString -- name of the imported label.++ (Maybe Int) -- possible '@n' suffix for stdcall functions+ -- When generating C, the '@n' suffix is omitted, but when+ -- generating assembler we must add it to the label.++ ForeignLabelSource -- what package the foreign label is in.++ FunctionOrData++ -- | A family of labels related to a particular case expression.+ | CaseLabel+ {-# UNPACK #-} !Unique -- Unique says which case expression+ CaseLabelInfo++ | AsmTempLabel+ {-# UNPACK #-} !Unique++ | AsmTempDerivedLabel+ CLabel+ FastString -- suffix++ | StringLitLabel+ {-# UNPACK #-} !Unique++ | PlainModuleInitLabel -- without the version & way info+ Module++ | CC_Label CostCentre+ | CCS_Label CostCentreStack+++ -- | These labels are generated and used inside the NCG only.+ -- They are special variants of a label used for dynamic linking+ -- see module PositionIndependentCode for details.+ | DynamicLinkerLabel DynamicLinkerLabelInfo CLabel++ -- | This label is generated and used inside the NCG only.+ -- It is used as a base for PIC calculations on some platforms.+ -- It takes the form of a local numeric assembler label '1'; and+ -- is pretty-printed as 1b, referring to the previous definition+ -- of 1: in the assembler source file.+ | PicBaseLabel++ -- | A label before an info table to prevent excessive dead-stripping on darwin+ | DeadStripPreventer CLabel+++ -- | Per-module table of tick locations+ | HpcTicksLabel Module++ -- | Static reference table+ | SRTLabel !Unique++ -- | Label of an StgLargeSRT+ | LargeSRTLabel+ {-# UNPACK #-} !Unique++ -- | A bitmap (function or case return)+ | LargeBitmapLabel+ {-# UNPACK #-} !Unique++ deriving Eq++-- This is laborious, but necessary. We can't derive Ord because+-- Unique doesn't have an Ord instance. Note nonDetCmpUnique in the+-- implementation. See Note [No Ord for Unique]+-- This is non-deterministic but we do not currently support deterministic+-- code-generation. See Note [Unique Determinism and code generation]+instance Ord CLabel where+ compare (IdLabel a1 b1 c1) (IdLabel a2 b2 c2) =+ compare a1 a2 `thenCmp`+ compare b1 b2 `thenCmp`+ compare c1 c2+ compare (CmmLabel a1 b1 c1) (CmmLabel a2 b2 c2) =+ compare a1 a2 `thenCmp`+ compare b1 b2 `thenCmp`+ compare c1 c2+ compare (RtsLabel a1) (RtsLabel a2) = compare a1 a2+ compare (ForeignLabel a1 b1 c1 d1) (ForeignLabel a2 b2 c2 d2) =+ compare a1 a2 `thenCmp`+ compare b1 b2 `thenCmp`+ compare c1 c2 `thenCmp`+ compare d1 d2+ compare (CaseLabel u1 a1) (CaseLabel u2 a2) =+ nonDetCmpUnique u1 u2 `thenCmp`+ compare a1 a2+ compare (AsmTempLabel u1) (AsmTempLabel u2) = nonDetCmpUnique u1 u2+ compare (AsmTempDerivedLabel a1 b1) (AsmTempDerivedLabel a2 b2) =+ compare a1 a2 `thenCmp`+ compare b1 b2+ compare (StringLitLabel u1) (StringLitLabel u2) =+ nonDetCmpUnique u1 u2+ compare (PlainModuleInitLabel a1) (PlainModuleInitLabel a2) =+ compare a1 a2+ compare (CC_Label a1) (CC_Label a2) =+ compare a1 a2+ compare (CCS_Label a1) (CCS_Label a2) =+ compare a1 a2+ compare (DynamicLinkerLabel a1 b1) (DynamicLinkerLabel a2 b2) =+ compare a1 a2 `thenCmp`+ compare b1 b2+ compare PicBaseLabel PicBaseLabel = EQ+ compare (DeadStripPreventer a1) (DeadStripPreventer a2) =+ compare a1 a2+ compare (HpcTicksLabel a1) (HpcTicksLabel a2) =+ compare a1 a2+ compare (SRTLabel u1) (SRTLabel u2) =+ nonDetCmpUnique u1 u2+ compare (LargeSRTLabel u1) (LargeSRTLabel u2) =+ nonDetCmpUnique u1 u2+ compare (LargeBitmapLabel u1) (LargeBitmapLabel u2) =+ nonDetCmpUnique u1 u2+ compare IdLabel{} _ = LT+ compare _ IdLabel{} = GT+ compare CmmLabel{} _ = LT+ compare _ CmmLabel{} = GT+ compare RtsLabel{} _ = LT+ compare _ RtsLabel{} = GT+ compare ForeignLabel{} _ = LT+ compare _ ForeignLabel{} = GT+ compare CaseLabel{} _ = LT+ compare _ CaseLabel{} = GT+ compare AsmTempLabel{} _ = LT+ compare _ AsmTempLabel{} = GT+ compare AsmTempDerivedLabel{} _ = LT+ compare _ AsmTempDerivedLabel{} = GT+ compare StringLitLabel{} _ = LT+ compare _ StringLitLabel{} = GT+ compare PlainModuleInitLabel{} _ = LT+ compare _ PlainModuleInitLabel{} = GT+ compare CC_Label{} _ = LT+ compare _ CC_Label{} = GT+ compare CCS_Label{} _ = LT+ compare _ CCS_Label{} = GT+ compare DynamicLinkerLabel{} _ = LT+ compare _ DynamicLinkerLabel{} = GT+ compare PicBaseLabel{} _ = LT+ compare _ PicBaseLabel{} = GT+ compare DeadStripPreventer{} _ = LT+ compare _ DeadStripPreventer{} = GT+ compare HpcTicksLabel{} _ = LT+ compare _ HpcTicksLabel{} = GT+ compare SRTLabel{} _ = LT+ compare _ SRTLabel{} = GT+ compare LargeSRTLabel{} _ = LT+ compare _ LargeSRTLabel{} = GT++-- | Record where a foreign label is stored.+data ForeignLabelSource++ -- | Label is in a named package+ = ForeignLabelInPackage UnitId++ -- | Label is in some external, system package that doesn't also+ -- contain compiled Haskell code, and is not associated with any .hi files.+ -- We don't have to worry about Haskell code being inlined from+ -- external packages. It is safe to treat the RTS package as "external".+ | ForeignLabelInExternalPackage++ -- | Label is in the package currenly being compiled.+ -- This is only used for creating hacky tmp labels during code generation.+ -- Don't use it in any code that might be inlined across a package boundary+ -- (ie, core code) else the information will be wrong relative to the+ -- destination module.+ | ForeignLabelInThisPackage++ deriving (Eq, Ord)+++-- | For debugging problems with the CLabel representation.+-- We can't make a Show instance for CLabel because lots of its components don't have instances.+-- The regular Outputable instance only shows the label name, and not its other info.+--+pprDebugCLabel :: CLabel -> SDoc+pprDebugCLabel lbl+ = case lbl of+ IdLabel{} -> ppr lbl <> (parens $ text "IdLabel")+ CmmLabel pkg _name _info+ -> ppr lbl <> (parens $ text "CmmLabel" <+> ppr pkg)++ RtsLabel{} -> ppr lbl <> (parens $ text "RtsLabel")++ ForeignLabel _name mSuffix src funOrData+ -> ppr lbl <> (parens $ text "ForeignLabel"+ <+> ppr mSuffix+ <+> ppr src+ <+> ppr funOrData)++ _ -> ppr lbl <> (parens $ text "other CLabel)")+++data IdLabelInfo+ = Closure -- ^ Label for closure+ | SRT -- ^ Static reference table (TODO: could be removed+ -- with the old code generator, but might be needed+ -- when we implement the New SRT Plan)+ | InfoTable -- ^ Info tables for closures; always read-only+ | Entry -- ^ Entry point+ | Slow -- ^ Slow entry point++ | LocalInfoTable -- ^ Like InfoTable but not externally visible+ | LocalEntry -- ^ Like Entry but not externally visible++ | RednCounts -- ^ Label of place to keep Ticky-ticky info for this Id++ | ConEntry -- ^ Constructor entry point+ | ConInfoTable -- ^ Corresponding info table++ | ClosureTable -- ^ Table of closures for Enum tycons++ | Bytes -- ^ Content of a string literal. See+ -- Note [Bytes label].++ deriving (Eq, Ord)+++data CaseLabelInfo+ = CaseReturnPt+ | CaseReturnInfo+ | CaseAlt ConTag+ | CaseDefault+ deriving (Eq, Ord)+++data RtsLabelInfo+ = RtsSelectorInfoTable Bool{-updatable-} Int{-offset-} -- ^ Selector thunks+ | RtsSelectorEntry Bool{-updatable-} Int{-offset-}++ | RtsApInfoTable Bool{-updatable-} Int{-arity-} -- ^ AP thunks+ | RtsApEntry Bool{-updatable-} Int{-arity-}++ | RtsPrimOp PrimOp+ | RtsApFast FastString -- ^ _fast versions of generic apply+ | RtsSlowFastTickyCtr String++ deriving (Eq, Ord)+ -- NOTE: Eq on LitString compares the pointer only, so this isn't+ -- a real equality.+++-- | What type of Cmm label we're dealing with.+-- Determines the suffix appended to the name when a CLabel.CmmLabel+-- is pretty printed.+data CmmLabelInfo+ = CmmInfo -- ^ misc rts info tabless, suffix _info+ | CmmEntry -- ^ misc rts entry points, suffix _entry+ | CmmRetInfo -- ^ misc rts ret info tables, suffix _info+ | CmmRet -- ^ misc rts return points, suffix _ret+ | CmmData -- ^ misc rts data bits, eg CHARLIKE_closure+ | CmmCode -- ^ misc rts code+ | CmmClosure -- ^ closures eg CHARLIKE_closure+ | CmmPrimCall -- ^ a prim call to some hand written Cmm code+ deriving (Eq, Ord)++data DynamicLinkerLabelInfo+ = CodeStub -- MachO: Lfoo$stub, ELF: foo@plt+ | SymbolPtr -- MachO: Lfoo$non_lazy_ptr, Windows: __imp_foo+ | GotSymbolPtr -- ELF: foo@got+ | GotSymbolOffset -- ELF: foo@gotoff++ deriving (Eq, Ord)+++-- -----------------------------------------------------------------------------+-- Constructing CLabels+-- -----------------------------------------------------------------------------++-- Constructing IdLabels+-- These are always local:+mkSlowEntryLabel :: Name -> CafInfo -> CLabel+mkSlowEntryLabel name c = IdLabel name c Slow++mkTopSRTLabel :: Unique -> CLabel+mkTopSRTLabel u = SRTLabel u++mkSRTLabel :: Name -> CafInfo -> CLabel+mkRednCountsLabel :: Name -> CLabel+mkSRTLabel name c = IdLabel name c SRT+mkRednCountsLabel name =+ IdLabel name NoCafRefs RednCounts -- Note [ticky for LNE]++-- These have local & (possibly) external variants:+mkLocalClosureLabel :: Name -> CafInfo -> CLabel+mkLocalInfoTableLabel :: Name -> CafInfo -> CLabel+mkLocalEntryLabel :: Name -> CafInfo -> CLabel+mkLocalClosureTableLabel :: Name -> CafInfo -> CLabel+mkLocalClosureLabel name c = IdLabel name c Closure+mkLocalInfoTableLabel name c = IdLabel name c LocalInfoTable+mkLocalEntryLabel name c = IdLabel name c LocalEntry+mkLocalClosureTableLabel name c = IdLabel name c ClosureTable++mkClosureLabel :: Name -> CafInfo -> CLabel+mkInfoTableLabel :: Name -> CafInfo -> CLabel+mkEntryLabel :: Name -> CafInfo -> CLabel+mkClosureTableLabel :: Name -> CafInfo -> CLabel+mkLocalConInfoTableLabel :: CafInfo -> Name -> CLabel+mkLocalConEntryLabel :: CafInfo -> Name -> CLabel+mkConInfoTableLabel :: Name -> CafInfo -> CLabel+mkBytesLabel :: Name -> CLabel+mkClosureLabel name c = IdLabel name c Closure+mkInfoTableLabel name c = IdLabel name c InfoTable+mkEntryLabel name c = IdLabel name c Entry+mkClosureTableLabel name c = IdLabel name c ClosureTable+mkLocalConInfoTableLabel c con = IdLabel con c ConInfoTable+mkLocalConEntryLabel c con = IdLabel con c ConEntry+mkConInfoTableLabel name c = IdLabel name c ConInfoTable+mkBytesLabel name = IdLabel name NoCafRefs Bytes++mkConEntryLabel :: Name -> CafInfo -> CLabel+mkConEntryLabel name c = IdLabel name c ConEntry++-- Constructing Cmm Labels+mkDirty_MUT_VAR_Label, mkSplitMarkerLabel, mkUpdInfoLabel,+ mkBHUpdInfoLabel, mkIndStaticInfoLabel, mkMainCapabilityLabel,+ mkMAP_FROZEN_infoLabel, mkMAP_FROZEN0_infoLabel, mkMAP_DIRTY_infoLabel,+ mkEMPTY_MVAR_infoLabel, mkTopTickyCtrLabel,+ mkCAFBlackHoleInfoTableLabel, mkCAFBlackHoleEntryLabel,+ mkArrWords_infoLabel, mkSMAP_FROZEN_infoLabel, mkSMAP_FROZEN0_infoLabel,+ mkSMAP_DIRTY_infoLabel :: CLabel+mkDirty_MUT_VAR_Label = mkForeignLabel (fsLit "dirty_MUT_VAR") Nothing ForeignLabelInExternalPackage IsFunction+mkSplitMarkerLabel = CmmLabel rtsUnitId (fsLit "__stg_split_marker") CmmCode+mkUpdInfoLabel = CmmLabel rtsUnitId (fsLit "stg_upd_frame") CmmInfo+mkBHUpdInfoLabel = CmmLabel rtsUnitId (fsLit "stg_bh_upd_frame" ) CmmInfo+mkIndStaticInfoLabel = CmmLabel rtsUnitId (fsLit "stg_IND_STATIC") CmmInfo+mkMainCapabilityLabel = CmmLabel rtsUnitId (fsLit "MainCapability") CmmData+mkMAP_FROZEN_infoLabel = CmmLabel rtsUnitId (fsLit "stg_MUT_ARR_PTRS_FROZEN") CmmInfo+mkMAP_FROZEN0_infoLabel = CmmLabel rtsUnitId (fsLit "stg_MUT_ARR_PTRS_FROZEN0") CmmInfo+mkMAP_DIRTY_infoLabel = CmmLabel rtsUnitId (fsLit "stg_MUT_ARR_PTRS_DIRTY") CmmInfo+mkEMPTY_MVAR_infoLabel = CmmLabel rtsUnitId (fsLit "stg_EMPTY_MVAR") CmmInfo+mkTopTickyCtrLabel = CmmLabel rtsUnitId (fsLit "top_ct") CmmData+mkCAFBlackHoleInfoTableLabel = CmmLabel rtsUnitId (fsLit "stg_CAF_BLACKHOLE") CmmInfo+mkCAFBlackHoleEntryLabel = CmmLabel rtsUnitId (fsLit "stg_CAF_BLACKHOLE") CmmEntry+mkArrWords_infoLabel = CmmLabel rtsUnitId (fsLit "stg_ARR_WORDS") CmmInfo+mkSMAP_FROZEN_infoLabel = CmmLabel rtsUnitId (fsLit "stg_SMALL_MUT_ARR_PTRS_FROZEN") CmmInfo+mkSMAP_FROZEN0_infoLabel = CmmLabel rtsUnitId (fsLit "stg_SMALL_MUT_ARR_PTRS_FROZEN0") CmmInfo+mkSMAP_DIRTY_infoLabel = CmmLabel rtsUnitId (fsLit "stg_SMALL_MUT_ARR_PTRS_DIRTY") CmmInfo++-----+mkCmmInfoLabel, mkCmmEntryLabel, mkCmmRetInfoLabel, mkCmmRetLabel,+ mkCmmCodeLabel, mkCmmDataLabel, mkCmmClosureLabel+ :: UnitId -> FastString -> CLabel++mkCmmInfoLabel pkg str = CmmLabel pkg str CmmInfo+mkCmmEntryLabel pkg str = CmmLabel pkg str CmmEntry+mkCmmRetInfoLabel pkg str = CmmLabel pkg str CmmRetInfo+mkCmmRetLabel pkg str = CmmLabel pkg str CmmRet+mkCmmCodeLabel pkg str = CmmLabel pkg str CmmCode+mkCmmDataLabel pkg str = CmmLabel pkg str CmmData+mkCmmClosureLabel pkg str = CmmLabel pkg str CmmClosure+++-- Constructing RtsLabels+mkRtsPrimOpLabel :: PrimOp -> CLabel+mkRtsPrimOpLabel primop = RtsLabel (RtsPrimOp primop)++mkSelectorInfoLabel :: Bool -> Int -> CLabel+mkSelectorEntryLabel :: Bool -> Int -> CLabel+mkSelectorInfoLabel upd off = RtsLabel (RtsSelectorInfoTable upd off)+mkSelectorEntryLabel upd off = RtsLabel (RtsSelectorEntry upd off)++mkApInfoTableLabel :: Bool -> Int -> CLabel+mkApEntryLabel :: Bool -> Int -> CLabel+mkApInfoTableLabel upd off = RtsLabel (RtsApInfoTable upd off)+mkApEntryLabel upd off = RtsLabel (RtsApEntry upd off)+++-- A call to some primitive hand written Cmm code+mkPrimCallLabel :: PrimCall -> CLabel+mkPrimCallLabel (PrimCall str pkg)+ = CmmLabel pkg str CmmPrimCall+++-- Constructing ForeignLabels++-- | Make a foreign label+mkForeignLabel+ :: FastString -- name+ -> Maybe Int -- size prefix+ -> ForeignLabelSource -- what package it's in+ -> FunctionOrData+ -> CLabel++mkForeignLabel str mb_sz src fod+ = ForeignLabel str mb_sz src fod+++-- | Update the label size field in a ForeignLabel+addLabelSize :: CLabel -> Int -> CLabel+addLabelSize (ForeignLabel str _ src fod) sz+ = ForeignLabel str (Just sz) src fod+addLabelSize label _+ = label++-- | Whether label is a top-level string literal+isBytesLabel :: CLabel -> Bool+isBytesLabel (IdLabel _ _ Bytes) = True+isBytesLabel _lbl = False++-- | Whether label is a non-haskell label (defined in C code)+isForeignLabel :: CLabel -> Bool+isForeignLabel (ForeignLabel _ _ _ _) = True+isForeignLabel _lbl = False++-- | Get the label size field from a ForeignLabel+foreignLabelStdcallInfo :: CLabel -> Maybe Int+foreignLabelStdcallInfo (ForeignLabel _ info _ _) = info+foreignLabelStdcallInfo _lbl = Nothing+++-- Constructing Large*Labels+mkLargeSRTLabel :: Unique -> CLabel+mkBitmapLabel :: Unique -> CLabel+mkLargeSRTLabel uniq = LargeSRTLabel uniq+mkBitmapLabel uniq = LargeBitmapLabel uniq+++-- Constructin CaseLabels+mkReturnPtLabel :: Unique -> CLabel+mkReturnInfoLabel :: Unique -> CLabel+mkAltLabel :: Unique -> ConTag -> CLabel+mkDefaultLabel :: Unique -> CLabel+mkReturnPtLabel uniq = CaseLabel uniq CaseReturnPt+mkReturnInfoLabel uniq = CaseLabel uniq CaseReturnInfo+mkAltLabel uniq tag = CaseLabel uniq (CaseAlt tag)+mkDefaultLabel uniq = CaseLabel uniq CaseDefault++-- Constructing Cost Center Labels+mkCCLabel :: CostCentre -> CLabel+mkCCSLabel :: CostCentreStack -> CLabel+mkCCLabel cc = CC_Label cc+mkCCSLabel ccs = CCS_Label ccs++mkRtsApFastLabel :: FastString -> CLabel+mkRtsApFastLabel str = RtsLabel (RtsApFast str)++mkRtsSlowFastTickyCtrLabel :: String -> CLabel+mkRtsSlowFastTickyCtrLabel pat = RtsLabel (RtsSlowFastTickyCtr pat)+++-- Constructing Code Coverage Labels+mkHpcTicksLabel :: Module -> CLabel+mkHpcTicksLabel = HpcTicksLabel+++-- Constructing labels used for dynamic linking+mkDynamicLinkerLabel :: DynamicLinkerLabelInfo -> CLabel -> CLabel+mkDynamicLinkerLabel = DynamicLinkerLabel++dynamicLinkerLabelInfo :: CLabel -> Maybe (DynamicLinkerLabelInfo, CLabel)+dynamicLinkerLabelInfo (DynamicLinkerLabel info lbl) = Just (info, lbl)+dynamicLinkerLabelInfo _ = Nothing++mkPicBaseLabel :: CLabel+mkPicBaseLabel = PicBaseLabel+++-- Constructing miscellaneous other labels+mkDeadStripPreventer :: CLabel -> CLabel+mkDeadStripPreventer lbl = DeadStripPreventer lbl++mkStringLitLabel :: Unique -> CLabel+mkStringLitLabel = StringLitLabel++mkAsmTempLabel :: Uniquable a => a -> CLabel+mkAsmTempLabel a = AsmTempLabel (getUnique a)++mkAsmTempDerivedLabel :: CLabel -> FastString -> CLabel+mkAsmTempDerivedLabel = AsmTempDerivedLabel++mkAsmTempEndLabel :: CLabel -> CLabel+mkAsmTempEndLabel l = mkAsmTempDerivedLabel l (fsLit "_end")+mkPlainModuleInitLabel :: Module -> CLabel+mkPlainModuleInitLabel mod = PlainModuleInitLabel mod++-- | Construct a label for a DWARF Debug Information Entity (DIE)+-- describing another symbol.+mkAsmTempDieLabel :: CLabel -> CLabel+mkAsmTempDieLabel l = mkAsmTempDerivedLabel l (fsLit "_die")++-- -----------------------------------------------------------------------------+-- Convert between different kinds of label++toClosureLbl :: CLabel -> CLabel+toClosureLbl (IdLabel n c _) = IdLabel n c Closure+toClosureLbl (CmmLabel m str _) = CmmLabel m str CmmClosure+toClosureLbl l = pprPanic "toClosureLbl" (ppr l)++toSlowEntryLbl :: CLabel -> CLabel+toSlowEntryLbl (IdLabel n c _) = IdLabel n c Slow+toSlowEntryLbl l = pprPanic "toSlowEntryLbl" (ppr l)++toEntryLbl :: CLabel -> CLabel+toEntryLbl (IdLabel n c LocalInfoTable) = IdLabel n c LocalEntry+toEntryLbl (IdLabel n c ConInfoTable) = IdLabel n c ConEntry+toEntryLbl (IdLabel n c _) = IdLabel n c Entry+toEntryLbl (CaseLabel n CaseReturnInfo) = CaseLabel n CaseReturnPt+toEntryLbl (CmmLabel m str CmmInfo) = CmmLabel m str CmmEntry+toEntryLbl (CmmLabel m str CmmRetInfo) = CmmLabel m str CmmRet+toEntryLbl l = pprPanic "toEntryLbl" (ppr l)++toInfoLbl :: CLabel -> CLabel+toInfoLbl (IdLabel n c Entry) = IdLabel n c InfoTable+toInfoLbl (IdLabel n c LocalEntry) = IdLabel n c LocalInfoTable+toInfoLbl (IdLabel n c ConEntry) = IdLabel n c ConInfoTable+toInfoLbl (IdLabel n c _) = IdLabel n c InfoTable+toInfoLbl (CaseLabel n CaseReturnPt) = CaseLabel n CaseReturnInfo+toInfoLbl (CmmLabel m str CmmEntry) = CmmLabel m str CmmInfo+toInfoLbl (CmmLabel m str CmmRet) = CmmLabel m str CmmRetInfo+toInfoLbl l = pprPanic "CLabel.toInfoLbl" (ppr l)++toRednCountsLbl :: CLabel -> Maybe CLabel+toRednCountsLbl = fmap mkRednCountsLabel . hasHaskellName++hasHaskellName :: CLabel -> Maybe Name+hasHaskellName (IdLabel n _ _) = Just n+hasHaskellName _ = Nothing++-- -----------------------------------------------------------------------------+-- Does a CLabel's referent itself refer to a CAF?+hasCAF :: CLabel -> Bool+hasCAF (IdLabel _ _ RednCounts) = False -- Note [ticky for LNE]+hasCAF (IdLabel _ MayHaveCafRefs _) = True+hasCAF _ = False++-- Note [ticky for LNE]+-- ~~~~~~~~~~~~~~~~~~~~~++-- Until 14 Feb 2013, every ticky counter was associated with a+-- closure. Thus, ticky labels used IdLabel. It is odd that+-- CmmBuildInfoTables.cafTransfers would consider such a ticky label+-- reason to add the name to the CAFEnv (and thus eventually the SRT),+-- but it was harmless because the ticky was only used if the closure+-- was also.+--+-- Since we now have ticky counters for LNEs, it is no longer the case+-- that every ticky counter has an actual closure. So I changed the+-- generation of ticky counters' CLabels to not result in their+-- associated id ending up in the SRT.+--+-- NB IdLabel is still appropriate for ticky ids (as opposed to+-- CmmLabel) because the LNE's counter is still related to an .hs Id,+-- that Id just isn't for a proper closure.++-- -----------------------------------------------------------------------------+-- Does a CLabel need declaring before use or not?+--+-- See wiki:Commentary/Compiler/Backends/PprC#Prototypes++needsCDecl :: CLabel -> Bool+ -- False <=> it's pre-declared; don't bother+ -- don't bother declaring Bitmap labels, we always make sure+ -- they are defined before use.+needsCDecl (SRTLabel _) = True+needsCDecl (LargeSRTLabel _) = False+needsCDecl (LargeBitmapLabel _) = False+needsCDecl (IdLabel _ _ _) = True+needsCDecl (CaseLabel _ _) = True+needsCDecl (PlainModuleInitLabel _) = True++needsCDecl (StringLitLabel _) = False+needsCDecl (AsmTempLabel _) = False+needsCDecl (AsmTempDerivedLabel _ _) = False+needsCDecl (RtsLabel _) = False++needsCDecl (CmmLabel pkgId _ _)+ -- Prototypes for labels defined in the runtime system are imported+ -- into HC files via includes/Stg.h.+ | pkgId == rtsUnitId = False++ -- For other labels we inline one into the HC file directly.+ | otherwise = True++needsCDecl l@(ForeignLabel{}) = not (isMathFun l)+needsCDecl (CC_Label _) = True+needsCDecl (CCS_Label _) = True+needsCDecl (HpcTicksLabel _) = True+needsCDecl (DynamicLinkerLabel {}) = panic "needsCDecl DynamicLinkerLabel"+needsCDecl PicBaseLabel = panic "needsCDecl PicBaseLabel"+needsCDecl (DeadStripPreventer {}) = panic "needsCDecl DeadStripPreventer"++-- | If a label is a local temporary used for native code generation+-- then return just its unique, otherwise nothing.+maybeAsmTemp :: CLabel -> Maybe Unique+maybeAsmTemp (AsmTempLabel uq) = Just uq+maybeAsmTemp _ = Nothing+++-- | Check whether a label corresponds to a C function that has+-- a prototype in a system header somehere, or is built-in+-- to the C compiler. For these labels we avoid generating our+-- own C prototypes.+isMathFun :: CLabel -> Bool+isMathFun (ForeignLabel fs _ _ _) = fs `elementOfUniqSet` math_funs+isMathFun _ = False++math_funs :: UniqSet FastString+math_funs = mkUniqSet [+ -- _ISOC99_SOURCE+ (fsLit "acos"), (fsLit "acosf"), (fsLit "acosh"),+ (fsLit "acoshf"), (fsLit "acoshl"), (fsLit "acosl"),+ (fsLit "asin"), (fsLit "asinf"), (fsLit "asinl"),+ (fsLit "asinh"), (fsLit "asinhf"), (fsLit "asinhl"),+ (fsLit "atan"), (fsLit "atanf"), (fsLit "atanl"),+ (fsLit "atan2"), (fsLit "atan2f"), (fsLit "atan2l"),+ (fsLit "atanh"), (fsLit "atanhf"), (fsLit "atanhl"),+ (fsLit "cbrt"), (fsLit "cbrtf"), (fsLit "cbrtl"),+ (fsLit "ceil"), (fsLit "ceilf"), (fsLit "ceill"),+ (fsLit "copysign"), (fsLit "copysignf"), (fsLit "copysignl"),+ (fsLit "cos"), (fsLit "cosf"), (fsLit "cosl"),+ (fsLit "cosh"), (fsLit "coshf"), (fsLit "coshl"),+ (fsLit "erf"), (fsLit "erff"), (fsLit "erfl"),+ (fsLit "erfc"), (fsLit "erfcf"), (fsLit "erfcl"),+ (fsLit "exp"), (fsLit "expf"), (fsLit "expl"),+ (fsLit "exp2"), (fsLit "exp2f"), (fsLit "exp2l"),+ (fsLit "expm1"), (fsLit "expm1f"), (fsLit "expm1l"),+ (fsLit "fabs"), (fsLit "fabsf"), (fsLit "fabsl"),+ (fsLit "fdim"), (fsLit "fdimf"), (fsLit "fdiml"),+ (fsLit "floor"), (fsLit "floorf"), (fsLit "floorl"),+ (fsLit "fma"), (fsLit "fmaf"), (fsLit "fmal"),+ (fsLit "fmax"), (fsLit "fmaxf"), (fsLit "fmaxl"),+ (fsLit "fmin"), (fsLit "fminf"), (fsLit "fminl"),+ (fsLit "fmod"), (fsLit "fmodf"), (fsLit "fmodl"),+ (fsLit "frexp"), (fsLit "frexpf"), (fsLit "frexpl"),+ (fsLit "hypot"), (fsLit "hypotf"), (fsLit "hypotl"),+ (fsLit "ilogb"), (fsLit "ilogbf"), (fsLit "ilogbl"),+ (fsLit "ldexp"), (fsLit "ldexpf"), (fsLit "ldexpl"),+ (fsLit "lgamma"), (fsLit "lgammaf"), (fsLit "lgammal"),+ (fsLit "llrint"), (fsLit "llrintf"), (fsLit "llrintl"),+ (fsLit "llround"), (fsLit "llroundf"), (fsLit "llroundl"),+ (fsLit "log"), (fsLit "logf"), (fsLit "logl"),+ (fsLit "log10l"), (fsLit "log10"), (fsLit "log10f"),+ (fsLit "log1pl"), (fsLit "log1p"), (fsLit "log1pf"),+ (fsLit "log2"), (fsLit "log2f"), (fsLit "log2l"),+ (fsLit "logb"), (fsLit "logbf"), (fsLit "logbl"),+ (fsLit "lrint"), (fsLit "lrintf"), (fsLit "lrintl"),+ (fsLit "lround"), (fsLit "lroundf"), (fsLit "lroundl"),+ (fsLit "modf"), (fsLit "modff"), (fsLit "modfl"),+ (fsLit "nan"), (fsLit "nanf"), (fsLit "nanl"),+ (fsLit "nearbyint"), (fsLit "nearbyintf"), (fsLit "nearbyintl"),+ (fsLit "nextafter"), (fsLit "nextafterf"), (fsLit "nextafterl"),+ (fsLit "nexttoward"), (fsLit "nexttowardf"), (fsLit "nexttowardl"),+ (fsLit "pow"), (fsLit "powf"), (fsLit "powl"),+ (fsLit "remainder"), (fsLit "remainderf"), (fsLit "remainderl"),+ (fsLit "remquo"), (fsLit "remquof"), (fsLit "remquol"),+ (fsLit "rint"), (fsLit "rintf"), (fsLit "rintl"),+ (fsLit "round"), (fsLit "roundf"), (fsLit "roundl"),+ (fsLit "scalbln"), (fsLit "scalblnf"), (fsLit "scalblnl"),+ (fsLit "scalbn"), (fsLit "scalbnf"), (fsLit "scalbnl"),+ (fsLit "sin"), (fsLit "sinf"), (fsLit "sinl"),+ (fsLit "sinh"), (fsLit "sinhf"), (fsLit "sinhl"),+ (fsLit "sqrt"), (fsLit "sqrtf"), (fsLit "sqrtl"),+ (fsLit "tan"), (fsLit "tanf"), (fsLit "tanl"),+ (fsLit "tanh"), (fsLit "tanhf"), (fsLit "tanhl"),+ (fsLit "tgamma"), (fsLit "tgammaf"), (fsLit "tgammal"),+ (fsLit "trunc"), (fsLit "truncf"), (fsLit "truncl"),+ -- ISO C 99 also defines these function-like macros in math.h:+ -- fpclassify, isfinite, isinf, isnormal, signbit, isgreater,+ -- isgreaterequal, isless, islessequal, islessgreater, isunordered++ -- additional symbols from _BSD_SOURCE+ (fsLit "drem"), (fsLit "dremf"), (fsLit "dreml"),+ (fsLit "finite"), (fsLit "finitef"), (fsLit "finitel"),+ (fsLit "gamma"), (fsLit "gammaf"), (fsLit "gammal"),+ (fsLit "isinf"), (fsLit "isinff"), (fsLit "isinfl"),+ (fsLit "isnan"), (fsLit "isnanf"), (fsLit "isnanl"),+ (fsLit "j0"), (fsLit "j0f"), (fsLit "j0l"),+ (fsLit "j1"), (fsLit "j1f"), (fsLit "j1l"),+ (fsLit "jn"), (fsLit "jnf"), (fsLit "jnl"),+ (fsLit "lgamma_r"), (fsLit "lgammaf_r"), (fsLit "lgammal_r"),+ (fsLit "scalb"), (fsLit "scalbf"), (fsLit "scalbl"),+ (fsLit "significand"), (fsLit "significandf"), (fsLit "significandl"),+ (fsLit "y0"), (fsLit "y0f"), (fsLit "y0l"),+ (fsLit "y1"), (fsLit "y1f"), (fsLit "y1l"),+ (fsLit "yn"), (fsLit "ynf"), (fsLit "ynl"),++ -- These functions are described in IEEE Std 754-2008 -+ -- Standard for Floating-Point Arithmetic and ISO/IEC TS 18661+ (fsLit "nextup"), (fsLit "nextupf"), (fsLit "nextupl"),+ (fsLit "nextdown"), (fsLit "nextdownf"), (fsLit "nextdownl")+ ]++-- -----------------------------------------------------------------------------+-- | Is a CLabel visible outside this object file or not?+-- From the point of view of the code generator, a name is+-- externally visible if it has to be declared as exported+-- in the .o file's symbol table; that is, made non-static.+externallyVisibleCLabel :: CLabel -> Bool -- not C "static"+externallyVisibleCLabel (CaseLabel _ _) = False+externallyVisibleCLabel (StringLitLabel _) = False+externallyVisibleCLabel (AsmTempLabel _) = False+externallyVisibleCLabel (AsmTempDerivedLabel _ _)= False+externallyVisibleCLabel (PlainModuleInitLabel _)= True+externallyVisibleCLabel (RtsLabel _) = True+externallyVisibleCLabel (CmmLabel _ _ _) = True+externallyVisibleCLabel (ForeignLabel{}) = True+externallyVisibleCLabel (IdLabel name _ info) = isExternalName name && externallyVisibleIdLabel info+externallyVisibleCLabel (CC_Label _) = True+externallyVisibleCLabel (CCS_Label _) = True+externallyVisibleCLabel (DynamicLinkerLabel _ _) = False+externallyVisibleCLabel (HpcTicksLabel _) = True+externallyVisibleCLabel (LargeBitmapLabel _) = False+externallyVisibleCLabel (SRTLabel _) = False+externallyVisibleCLabel (LargeSRTLabel _) = False+externallyVisibleCLabel (PicBaseLabel {}) = panic "externallyVisibleCLabel PicBaseLabel"+externallyVisibleCLabel (DeadStripPreventer {}) = panic "externallyVisibleCLabel DeadStripPreventer"++externallyVisibleIdLabel :: IdLabelInfo -> Bool+externallyVisibleIdLabel SRT = False+externallyVisibleIdLabel LocalInfoTable = False+externallyVisibleIdLabel LocalEntry = False+externallyVisibleIdLabel _ = True++-- -----------------------------------------------------------------------------+-- Finding the "type" of a CLabel++-- For generating correct types in label declarations:++data CLabelType+ = CodeLabel -- Address of some executable instructions+ | DataLabel -- Address of data, not a GC ptr+ | GcPtrLabel -- Address of a (presumably static) GC object++isCFunctionLabel :: CLabel -> Bool+isCFunctionLabel lbl = case labelType lbl of+ CodeLabel -> True+ _other -> False++isGcPtrLabel :: CLabel -> Bool+isGcPtrLabel lbl = case labelType lbl of+ GcPtrLabel -> True+ _other -> False+++-- | Work out the general type of data at the address of this label+-- whether it be code, data, or static GC object.+labelType :: CLabel -> CLabelType+labelType (CmmLabel _ _ CmmData) = DataLabel+labelType (CmmLabel _ _ CmmClosure) = GcPtrLabel+labelType (CmmLabel _ _ CmmCode) = CodeLabel+labelType (CmmLabel _ _ CmmInfo) = DataLabel+labelType (CmmLabel _ _ CmmEntry) = CodeLabel+labelType (CmmLabel _ _ CmmPrimCall) = CodeLabel+labelType (CmmLabel _ _ CmmRetInfo) = DataLabel+labelType (CmmLabel _ _ CmmRet) = CodeLabel+labelType (RtsLabel (RtsSelectorInfoTable _ _)) = DataLabel+labelType (RtsLabel (RtsApInfoTable _ _)) = DataLabel+labelType (RtsLabel (RtsApFast _)) = CodeLabel+labelType (CaseLabel _ CaseReturnInfo) = DataLabel+labelType (CaseLabel _ _) = CodeLabel+labelType (PlainModuleInitLabel _) = CodeLabel+labelType (SRTLabel _) = DataLabel+labelType (LargeSRTLabel _) = DataLabel+labelType (LargeBitmapLabel _) = DataLabel+labelType (ForeignLabel _ _ _ IsFunction) = CodeLabel+labelType (IdLabel _ _ info) = idInfoLabelType info+labelType _ = DataLabel++idInfoLabelType :: IdLabelInfo -> CLabelType+idInfoLabelType info =+ case info of+ InfoTable -> DataLabel+ LocalInfoTable -> DataLabel+ Closure -> GcPtrLabel+ ConInfoTable -> DataLabel+ ClosureTable -> DataLabel+ RednCounts -> DataLabel+ Bytes -> DataLabel+ _ -> CodeLabel+++-- -----------------------------------------------------------------------------+-- Does a CLabel need dynamic linkage?++-- When referring to data in code, we need to know whether+-- that data resides in a DLL or not. [Win32 only.]+-- @labelDynamic@ returns @True@ if the label is located+-- in a DLL, be it a data reference or not.++labelDynamic :: DynFlags -> Module -> CLabel -> Bool+labelDynamic dflags this_mod lbl =+ case lbl of+ -- is the RTS in a DLL or not?+ RtsLabel _ -> (WayDyn `elem` ways dflags) && (this_pkg /= rtsUnitId)++ IdLabel n _ _ -> isDllName dflags this_mod n++ -- When compiling in the "dyn" way, each package is to be linked into+ -- its own shared library.+ CmmLabel pkg _ _+ | os == OSMinGW32 ->+ (WayDyn `elem` ways dflags) && (this_pkg /= pkg)+ | otherwise ->+ True++ ForeignLabel _ _ source _ ->+ if os == OSMinGW32+ then case source of+ -- Foreign label is in some un-named foreign package (or DLL).+ ForeignLabelInExternalPackage -> True++ -- Foreign label is linked into the same package as the+ -- source file currently being compiled.+ ForeignLabelInThisPackage -> False++ -- Foreign label is in some named package.+ -- When compiling in the "dyn" way, each package is to be+ -- linked into its own DLL.+ ForeignLabelInPackage pkgId ->+ (WayDyn `elem` ways dflags) && (this_pkg /= pkgId)++ else -- On Mac OS X and on ELF platforms, false positives are OK,+ -- so we claim that all foreign imports come from dynamic+ -- libraries+ True++ PlainModuleInitLabel m -> (WayDyn `elem` ways dflags) && this_pkg /= (moduleUnitId m)++ HpcTicksLabel m -> (WayDyn `elem` ways dflags) && this_mod /= m++ -- Note that DynamicLinkerLabels do NOT require dynamic linking themselves.+ _ -> False+ where+ os = platformOS (targetPlatform dflags)+ this_pkg = moduleUnitId this_mod+++-----------------------------------------------------------------------------+-- Printing out CLabels.++{-+Convention:++ <name>_<type>++where <name> is <Module>_<name> for external names and <unique> for+internal names. <type> is one of the following:++ info Info table+ srt Static reference table+ srtd Static reference table descriptor+ entry Entry code (function, closure)+ slow Slow entry code (if any)+ ret Direct return address+ vtbl Vector table+ <n>_alt Case alternative (tag n)+ dflt Default case alternative+ btm Large bitmap vector+ closure Static closure+ con_entry Dynamic Constructor entry code+ con_info Dynamic Constructor info table+ static_entry Static Constructor entry code+ static_info Static Constructor info table+ sel_info Selector info table+ sel_entry Selector entry code+ cc Cost centre+ ccs Cost centre stack++Many of these distinctions are only for documentation reasons. For+example, _ret is only distinguished from _entry to make it easy to+tell whether a code fragment is a return point or a closure/function+entry.++Note [Closure and info labels]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For a function 'foo, we have:+ foo_info : Points to the info table describing foo's closure+ (and entry code for foo with tables next to code)+ foo_closure : Static (no-free-var) closure only:+ points to the statically-allocated closure++For a data constructor (such as Just or Nothing), we have:+ Just_con_info: Info table for the data constructor itself+ the first word of a heap-allocated Just+ Just_info: Info table for the *worker function*, an+ ordinary Haskell function of arity 1 that+ allocates a (Just x) box:+ Just = \x -> Just x+ Just_closure: The closure for this worker++ Nothing_closure: a statically allocated closure for Nothing+ Nothing_static_info: info table for Nothing_closure++All these must be exported symbol, EXCEPT Just_info. We don't need to+export this because in other modules we either have+ * A reference to 'Just'; use Just_closure+ * A saturated call 'Just x'; allocate using Just_con_info+Not exporting these Just_info labels reduces the number of symbols+somewhat.++Note [Bytes label]+~~~~~~~~~~~~~~~~~~+For a top-level string literal 'foo', we have just one symbol 'foo_bytes', which+points to a static data block containing the content of the literal.+-}++instance Outputable CLabel where+ ppr c = sdocWithPlatform $ \platform -> pprCLabel platform c++pprCLabel :: Platform -> CLabel -> SDoc++pprCLabel platform (AsmTempLabel u)+ | cGhcWithNativeCodeGen == "YES"+ = getPprStyle $ \ sty ->+ if asmStyle sty then+ ptext (asmTempLabelPrefix platform) <> pprUniqueAlways u+ else+ char '_' <> pprUniqueAlways u++pprCLabel platform (AsmTempDerivedLabel l suf)+ | cGhcWithNativeCodeGen == "YES"+ = ptext (asmTempLabelPrefix platform)+ <> case l of AsmTempLabel u -> pprUniqueAlways u+ _other -> pprCLabel platform l+ <> ftext suf++pprCLabel platform (DynamicLinkerLabel info lbl)+ | cGhcWithNativeCodeGen == "YES"+ = pprDynamicLinkerAsmLabel platform info lbl++pprCLabel _ PicBaseLabel+ | cGhcWithNativeCodeGen == "YES"+ = text "1b"++pprCLabel platform (DeadStripPreventer lbl)+ | cGhcWithNativeCodeGen == "YES"+ = pprCLabel platform lbl <> text "_dsp"++pprCLabel _ (StringLitLabel u)+ | cGhcWithNativeCodeGen == "YES"+ = pprUniqueAlways u <> ptext (sLit "_str")++pprCLabel platform lbl+ = getPprStyle $ \ sty ->+ if cGhcWithNativeCodeGen == "YES" && asmStyle sty+ then maybe_underscore (pprAsmCLbl platform lbl)+ else pprCLbl lbl++maybe_underscore :: SDoc -> SDoc+maybe_underscore doc+ | underscorePrefix = pp_cSEP <> doc+ | otherwise = doc++pprAsmCLbl :: Platform -> CLabel -> SDoc+pprAsmCLbl platform (ForeignLabel fs (Just sz) _ _)+ | platformOS platform == OSMinGW32+ -- In asm mode, we need to put the suffix on a stdcall ForeignLabel.+ -- (The C compiler does this itself).+ = ftext fs <> char '@' <> int sz+pprAsmCLbl _ lbl+ = pprCLbl lbl++pprCLbl :: CLabel -> SDoc+pprCLbl (StringLitLabel u)+ = pprUniqueAlways u <> text "_str"++pprCLbl (CaseLabel u CaseReturnPt)+ = hcat [pprUniqueAlways u, text "_ret"]+pprCLbl (CaseLabel u CaseReturnInfo)+ = hcat [pprUniqueAlways u, text "_info"]+pprCLbl (CaseLabel u (CaseAlt tag))+ = hcat [pprUniqueAlways u, pp_cSEP, int tag, text "_alt"]+pprCLbl (CaseLabel u CaseDefault)+ = hcat [pprUniqueAlways u, text "_dflt"]++pprCLbl (SRTLabel u)+ = pprUniqueAlways u <> pp_cSEP <> text "srt"++pprCLbl (LargeSRTLabel u) = pprUniqueAlways u <> pp_cSEP <> text "srtd"+pprCLbl (LargeBitmapLabel u) = text "b" <> pprUniqueAlways u <> pp_cSEP <> text "btm"+-- Some bitsmaps for tuple constructors have a numeric tag (e.g. '7')+-- until that gets resolved we'll just force them to start+-- with a letter so the label will be legal assmbly code.+++pprCLbl (CmmLabel _ str CmmCode) = ftext str+pprCLbl (CmmLabel _ str CmmData) = ftext str+pprCLbl (CmmLabel _ str CmmPrimCall) = ftext str++pprCLbl (RtsLabel (RtsApFast str)) = ftext str <> text "_fast"++pprCLbl (RtsLabel (RtsSelectorInfoTable upd_reqd offset))+ = sdocWithDynFlags $ \dflags ->+ ASSERT(offset >= 0 && offset <= mAX_SPEC_SELECTEE_SIZE dflags)+ hcat [text "stg_sel_", text (show offset),+ ptext (if upd_reqd+ then (sLit "_upd_info")+ else (sLit "_noupd_info"))+ ]++pprCLbl (RtsLabel (RtsSelectorEntry upd_reqd offset))+ = sdocWithDynFlags $ \dflags ->+ ASSERT(offset >= 0 && offset <= mAX_SPEC_SELECTEE_SIZE dflags)+ hcat [text "stg_sel_", text (show offset),+ ptext (if upd_reqd+ then (sLit "_upd_entry")+ else (sLit "_noupd_entry"))+ ]++pprCLbl (RtsLabel (RtsApInfoTable upd_reqd arity))+ = sdocWithDynFlags $ \dflags ->+ ASSERT(arity > 0 && arity <= mAX_SPEC_AP_SIZE dflags)+ hcat [text "stg_ap_", text (show arity),+ ptext (if upd_reqd+ then (sLit "_upd_info")+ else (sLit "_noupd_info"))+ ]++pprCLbl (RtsLabel (RtsApEntry upd_reqd arity))+ = sdocWithDynFlags $ \dflags ->+ ASSERT(arity > 0 && arity <= mAX_SPEC_AP_SIZE dflags)+ hcat [text "stg_ap_", text (show arity),+ ptext (if upd_reqd+ then (sLit "_upd_entry")+ else (sLit "_noupd_entry"))+ ]++pprCLbl (CmmLabel _ fs CmmInfo)+ = ftext fs <> text "_info"++pprCLbl (CmmLabel _ fs CmmEntry)+ = ftext fs <> text "_entry"++pprCLbl (CmmLabel _ fs CmmRetInfo)+ = ftext fs <> text "_info"++pprCLbl (CmmLabel _ fs CmmRet)+ = ftext fs <> text "_ret"++pprCLbl (CmmLabel _ fs CmmClosure)+ = ftext fs <> text "_closure"++pprCLbl (RtsLabel (RtsPrimOp primop))+ = text "stg_" <> ppr primop++pprCLbl (RtsLabel (RtsSlowFastTickyCtr pat))+ = text "SLOW_CALL_fast_" <> text pat <> ptext (sLit "_ctr")++pprCLbl (ForeignLabel str _ _ _)+ = ftext str++pprCLbl (IdLabel name _cafs flavor) = ppr name <> ppIdFlavor flavor++pprCLbl (CC_Label cc) = ppr cc+pprCLbl (CCS_Label ccs) = ppr ccs++pprCLbl (PlainModuleInitLabel mod)+ = text "__stginit_" <> ppr mod++pprCLbl (HpcTicksLabel mod)+ = text "_hpc_tickboxes_" <> ppr mod <> ptext (sLit "_hpc")++pprCLbl (AsmTempLabel {}) = panic "pprCLbl AsmTempLabel"+pprCLbl (AsmTempDerivedLabel {})= panic "pprCLbl AsmTempDerivedLabel"+pprCLbl (DynamicLinkerLabel {}) = panic "pprCLbl DynamicLinkerLabel"+pprCLbl (PicBaseLabel {}) = panic "pprCLbl PicBaseLabel"+pprCLbl (DeadStripPreventer {}) = panic "pprCLbl DeadStripPreventer"++ppIdFlavor :: IdLabelInfo -> SDoc+ppIdFlavor x = pp_cSEP <>+ (case x of+ Closure -> text "closure"+ SRT -> text "srt"+ InfoTable -> text "info"+ LocalInfoTable -> text "info"+ Entry -> text "entry"+ LocalEntry -> text "entry"+ Slow -> text "slow"+ RednCounts -> text "ct"+ ConEntry -> text "con_entry"+ ConInfoTable -> text "con_info"+ ClosureTable -> text "closure_tbl"+ Bytes -> text "bytes"+ )+++pp_cSEP :: SDoc+pp_cSEP = char '_'+++instance Outputable ForeignLabelSource where+ ppr fs+ = case fs of+ ForeignLabelInPackage pkgId -> parens $ text "package: " <> ppr pkgId+ ForeignLabelInThisPackage -> parens $ text "this package"+ ForeignLabelInExternalPackage -> parens $ text "external package"++-- -----------------------------------------------------------------------------+-- Machine-dependent knowledge about labels.++underscorePrefix :: Bool -- leading underscore on assembler labels?+underscorePrefix = (cLeadingUnderscore == "YES")++asmTempLabelPrefix :: Platform -> LitString -- for formatting labels+asmTempLabelPrefix platform = case platformOS platform of+ OSDarwin -> sLit "L"+ OSAIX -> sLit "__L" -- follow IBM XL C's convention+ _ -> sLit ".L"++pprDynamicLinkerAsmLabel :: Platform -> DynamicLinkerLabelInfo -> CLabel -> SDoc+pprDynamicLinkerAsmLabel platform dllInfo lbl+ = if platformOS platform == OSDarwin+ then if platformArch platform == ArchX86_64+ then case dllInfo of+ CodeStub -> char 'L' <> ppr lbl <> text "$stub"+ SymbolPtr -> char 'L' <> ppr lbl <> text "$non_lazy_ptr"+ GotSymbolPtr -> ppr lbl <> text "@GOTPCREL"+ GotSymbolOffset -> ppr lbl+ else case dllInfo of+ CodeStub -> char 'L' <> ppr lbl <> text "$stub"+ SymbolPtr -> char 'L' <> ppr lbl <> text "$non_lazy_ptr"+ _ -> panic "pprDynamicLinkerAsmLabel"++ else if platformOS platform == OSAIX+ then case dllInfo of+ SymbolPtr -> text "LC.." <> ppr lbl -- GCC's naming convention+ _ -> panic "pprDynamicLinkerAsmLabel"++ else if osElfTarget (platformOS platform)+ then if platformArch platform == ArchPPC+ then case dllInfo of+ CodeStub -> -- See Note [.LCTOC1 in PPC PIC code]+ ppr lbl <> text "+32768@plt"+ SymbolPtr -> text ".LC_" <> ppr lbl+ _ -> panic "pprDynamicLinkerAsmLabel"+ else if platformArch platform == ArchX86_64+ then case dllInfo of+ CodeStub -> ppr lbl <> text "@plt"+ GotSymbolPtr -> ppr lbl <> text "@gotpcrel"+ GotSymbolOffset -> ppr lbl+ SymbolPtr -> text ".LC_" <> ppr lbl+ else if platformArch platform == ArchPPC_64 ELF_V1+ || platformArch platform == ArchPPC_64 ELF_V2+ then case dllInfo of+ GotSymbolPtr -> text ".LC_" <> ppr lbl+ <> text "@toc"+ GotSymbolOffset -> ppr lbl+ SymbolPtr -> text ".LC_" <> ppr lbl+ _ -> panic "pprDynamicLinkerAsmLabel"+ else case dllInfo of+ CodeStub -> ppr lbl <> text "@plt"+ SymbolPtr -> text ".LC_" <> ppr lbl+ GotSymbolPtr -> ppr lbl <> text "@got"+ GotSymbolOffset -> ppr lbl <> text "@gotoff"+ else if platformOS platform == OSMinGW32+ then case dllInfo of+ SymbolPtr -> text "__imp_" <> ppr lbl+ _ -> panic "pprDynamicLinkerAsmLabel"+ else panic "pprDynamicLinkerAsmLabel"+
+ cmm/Cmm.hs view
@@ -0,0 +1,218 @@+-- Cmm representations using Hoopl's Graph CmmNode e x.+{-# LANGUAGE CPP, GADTs #-}++module Cmm (+ -- * Cmm top-level datatypes+ CmmProgram, CmmGroup, GenCmmGroup,+ CmmDecl, GenCmmDecl(..),+ CmmGraph, GenCmmGraph(..),+ CmmBlock,+ RawCmmDecl, RawCmmGroup,+ Section(..), SectionType(..), CmmStatics(..), CmmStatic(..),++ -- ** Blocks containing lists+ GenBasicBlock(..), blockId,+ ListGraph(..), pprBBlock,++ -- * Cmm graphs+ CmmReplGraph, GenCmmReplGraph, CmmFwdRewrite, CmmBwdRewrite,++ -- * Info Tables+ CmmTopInfo(..), CmmStackInfo(..), CmmInfoTable(..), topInfoTable,+ ClosureTypeInfo(..),+ C_SRT(..), needsSRT,+ ProfilingInfo(..), ConstrDescription,++ -- * Statements, expressions and types+ module CmmNode,+ module CmmExpr,+ ) where++import CLabel+import BlockId+import CmmNode+import SMRep+import CmmExpr+import UniqSupply+import Compiler.Hoopl+import Outputable++import Data.Word ( Word8 )++#include "HsVersions.h"++-----------------------------------------------------------------------------+-- Cmm, GenCmm+-----------------------------------------------------------------------------++-- A CmmProgram is a list of CmmGroups+-- A CmmGroup is a list of top-level declarations++-- When object-splitting is on, each group is compiled into a separate+-- .o file. So typically we put closely related stuff in a CmmGroup.+-- Section-splitting follows suit and makes one .text subsection for each+-- CmmGroup.++type CmmProgram = [CmmGroup]++type GenCmmGroup d h g = [GenCmmDecl d h g]+type CmmGroup = GenCmmGroup CmmStatics CmmTopInfo CmmGraph+type RawCmmGroup = GenCmmGroup CmmStatics (LabelMap CmmStatics) CmmGraph++-----------------------------------------------------------------------------+-- CmmDecl, GenCmmDecl+-----------------------------------------------------------------------------++-- GenCmmDecl is abstracted over+-- d, the type of static data elements in CmmData+-- h, the static info preceding the code of a CmmProc+-- g, the control-flow graph of a CmmProc+--+-- We expect there to be two main instances of this type:+-- (a) C--, i.e. populated with various C-- constructs+-- (b) Native code, populated with data/instructions++-- | A top-level chunk, abstracted over the type of the contents of+-- the basic blocks (Cmm or instructions are the likely instantiations).+data GenCmmDecl d h g+ = CmmProc -- A procedure+ h -- Extra header such as the info table+ CLabel -- Entry label+ [GlobalReg] -- Registers live on entry. Note that the set of live+ -- registers will be correct in generated C-- code, but+ -- not in hand-written C-- code. However,+ -- splitAtProcPoints calculates correct liveness+ -- information for CmmProcs.+ g -- Control-flow graph for the procedure's code++ | CmmData -- Static data+ Section+ d++type CmmDecl = GenCmmDecl CmmStatics CmmTopInfo CmmGraph++type RawCmmDecl+ = GenCmmDecl+ CmmStatics+ (LabelMap CmmStatics)+ CmmGraph++-----------------------------------------------------------------------------+-- Graphs+-----------------------------------------------------------------------------++type CmmGraph = GenCmmGraph CmmNode+data GenCmmGraph n = CmmGraph { g_entry :: BlockId, g_graph :: Graph n C C }+type CmmBlock = Block CmmNode C C++type CmmReplGraph e x = GenCmmReplGraph CmmNode e x+type GenCmmReplGraph n e x = UniqSM (Maybe (Graph n e x))+type CmmFwdRewrite f = FwdRewrite UniqSM CmmNode f+type CmmBwdRewrite f = BwdRewrite UniqSM CmmNode f++-----------------------------------------------------------------------------+-- Info Tables+-----------------------------------------------------------------------------++data CmmTopInfo = TopInfo { info_tbls :: LabelMap CmmInfoTable+ , stack_info :: CmmStackInfo }++topInfoTable :: GenCmmDecl a CmmTopInfo (GenCmmGraph n) -> Maybe CmmInfoTable+topInfoTable (CmmProc infos _ _ g) = mapLookup (g_entry g) (info_tbls infos)+topInfoTable _ = Nothing++data CmmStackInfo+ = StackInfo {+ arg_space :: ByteOff,+ -- number of bytes of arguments on the stack on entry to the+ -- the proc. This is filled in by StgCmm.codeGen, and used+ -- by the stack allocator later.+ updfr_space :: Maybe ByteOff,+ -- XXX: this never contains anything useful, but it should.+ -- See comment in CmmLayoutStack.+ do_layout :: Bool+ -- Do automatic stack layout for this proc. This is+ -- True for all code generated by the code generator,+ -- but is occasionally False for hand-written Cmm where+ -- we want to do the stack manipulation manually.+ }++-- | Info table as a haskell data type+data CmmInfoTable+ = CmmInfoTable {+ cit_lbl :: CLabel, -- Info table label+ cit_rep :: SMRep,+ cit_prof :: ProfilingInfo,+ cit_srt :: C_SRT+ }++data ProfilingInfo+ = NoProfilingInfo+ | ProfilingInfo [Word8] [Word8] -- closure_type, closure_desc++-- C_SRT is what StgSyn.SRT gets translated to...+-- we add a label for the table, and expect only the 'offset/length' form++data C_SRT = NoC_SRT+ | C_SRT !CLabel !WordOff !StgHalfWord {-bitmap or escape-}+ deriving (Eq)++needsSRT :: C_SRT -> Bool+needsSRT NoC_SRT = False+needsSRT (C_SRT _ _ _) = True++-----------------------------------------------------------------------------+-- Static Data+-----------------------------------------------------------------------------++data SectionType+ = Text+ | Data+ | ReadOnlyData+ | RelocatableReadOnlyData+ | UninitialisedData+ | ReadOnlyData16 -- .rodata.cst16 on x86_64, 16-byte aligned+ | CString+ | OtherSection String+ deriving (Show)++data Section = Section SectionType CLabel++data CmmStatic+ = CmmStaticLit CmmLit+ -- a literal value, size given by cmmLitRep of the literal.+ | CmmUninitialised Int+ -- uninitialised data, N bytes long+ | CmmString [Word8]+ -- string of 8-bit values only, not zero terminated.++data CmmStatics+ = Statics+ CLabel -- Label of statics+ [CmmStatic] -- The static data itself++-- -----------------------------------------------------------------------------+-- Basic blocks consisting of lists++-- These are used by the LLVM and NCG backends, when populating Cmm+-- with lists of instructions.++data GenBasicBlock i = BasicBlock BlockId [i]++-- | The branch block id is that of the first block in+-- the branch, which is that branch's entry point+blockId :: GenBasicBlock i -> BlockId+blockId (BasicBlock blk_id _ ) = blk_id++newtype ListGraph i = ListGraph [GenBasicBlock i]++instance Outputable instr => Outputable (ListGraph instr) where+ ppr (ListGraph blocks) = vcat (map ppr blocks)++instance Outputable instr => Outputable (GenBasicBlock instr) where+ ppr = pprBBlock++pprBBlock :: Outputable stmt => GenBasicBlock stmt -> SDoc+pprBBlock (BasicBlock ident stmts) =+ hang (ppr ident <> colon) 4 (vcat (map ppr stmts))+
+ cmm/CmmBuildInfoTables.hs view
@@ -0,0 +1,379 @@+{-# LANGUAGE BangPatterns, CPP, GADTs #-}++module CmmBuildInfoTables+ ( CAFSet, CAFEnv, cafAnal+ , doSRTs, TopSRT, emptySRT, isEmptySRT, srtToData )+where++#include "HsVersions.h"++import Hoopl+import Digraph+import Bitmap+import CLabel+import PprCmmDecl ()+import Cmm+import CmmUtils+import CmmInfo+import Data.List+import DynFlags+import Maybes+import Outputable+import SMRep+import UniqSupply+import Util++import PprCmm()+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Set (Set)+import qualified Data.Set as Set+import Control.Monad++import qualified Prelude as P+import Prelude hiding (succ)++foldSet :: (a -> b -> b) -> b -> Set a -> b+foldSet = Set.foldr++-----------------------------------------------------------------------+-- SRTs++{- EXAMPLE++f = \x. ... g ...+ where+ g = \y. ... h ... c1 ...+ h = \z. ... c2 ...++c1 & c2 are CAFs++g and h are local functions, but they have no static closures. When+we generate code for f, we start with a CmmGroup of four CmmDecls:++ [ f_closure, f_entry, g_entry, h_entry ]++we process each CmmDecl separately in cpsTop, giving us a list of+CmmDecls. e.g. for f_entry, we might end up with++ [ f_entry, f1_ret, f2_proc ]++where f1_ret is a return point, and f2_proc is a proc-point. We have+a CAFSet for each of these CmmDecls, let's suppose they are++ [ f_entry{g_closure}, f1_ret{g_closure}, f2_proc{} ]+ [ g_entry{h_closure, c1_closure} ]+ [ h_entry{c2_closure} ]++Now, note that we cannot use g_closure and h_closure in an SRT,+because there are no static closures corresponding to these functions.+So we have to flatten out the structure, replacing g_closure and+h_closure with their contents:++ [ f_entry{c2_closure, c1_closure}, f1_ret{c2_closure,c1_closure}, f2_proc{} ]+ [ g_entry{c2_closure, c1_closure} ]+ [ h_entry{c2_closure} ]++This is what flattenCAFSets is doing.++-}++-----------------------------------------------------------------------+-- Finding the CAFs used by a procedure++type CAFSet = Set CLabel+type CAFEnv = LabelMap CAFSet++cafLattice :: DataflowLattice CAFSet+cafLattice = DataflowLattice Set.empty add+ where+ add (OldFact old) (NewFact new) =+ let !new' = old `Set.union` new+ in changedIf (Set.size new' > Set.size old) new'++cafTransfers :: TransferFun CAFSet+cafTransfers (BlockCC eNode middle xNode) fBase =+ let joined = cafsInNode xNode $! joinOutFacts cafLattice xNode fBase+ !result = foldNodesBwdOO cafsInNode middle joined+ in mapSingleton (entryLabel eNode) result++cafsInNode :: CmmNode e x -> CAFSet -> CAFSet+cafsInNode node set = foldExpDeep addCaf node set+ where+ addCaf expr !set =+ case expr of+ CmmLit (CmmLabel c) -> add c set+ CmmLit (CmmLabelOff c _) -> add c set+ CmmLit (CmmLabelDiffOff c1 c2 _) -> add c1 $! add c2 set+ _ -> set+ add l s | hasCAF l = Set.insert (toClosureLbl l) s+ | otherwise = s++-- | An analysis to find live CAFs.+cafAnal :: CmmGraph -> CAFEnv+cafAnal cmmGraph = analyzeCmmBwd cafLattice cafTransfers cmmGraph mapEmpty++-----------------------------------------------------------------------+-- Building the SRTs++-- Description of the SRT for a given module.+-- Note that this SRT may grow as we greedily add new CAFs to it.+data TopSRT = TopSRT { lbl :: CLabel+ , next_elt :: Int -- the next entry in the table+ , rev_elts :: [CLabel]+ , elt_map :: Map CLabel Int }+ -- map: CLabel -> its last entry in the table+instance Outputable TopSRT where+ ppr (TopSRT lbl next elts eltmap) =+ text "TopSRT:" <+> ppr lbl+ <+> ppr next+ <+> ppr elts+ <+> ppr eltmap++emptySRT :: MonadUnique m => m TopSRT+emptySRT =+ do top_lbl <- getUniqueM >>= \ u -> return $ mkTopSRTLabel u+ return TopSRT { lbl = top_lbl, next_elt = 0, rev_elts = [], elt_map = Map.empty }++isEmptySRT :: TopSRT -> Bool+isEmptySRT srt = null (rev_elts srt)++cafMember :: TopSRT -> CLabel -> Bool+cafMember srt lbl = Map.member lbl (elt_map srt)++cafOffset :: TopSRT -> CLabel -> Maybe Int+cafOffset srt lbl = Map.lookup lbl (elt_map srt)++addCAF :: CLabel -> TopSRT -> TopSRT+addCAF caf srt =+ srt { next_elt = last + 1+ , rev_elts = caf : rev_elts srt+ , elt_map = Map.insert caf last (elt_map srt) }+ where last = next_elt srt++srtToData :: TopSRT -> CmmGroup+srtToData srt = [CmmData sec (Statics (lbl srt) tbl)]+ where tbl = map (CmmStaticLit . CmmLabel) (reverse (rev_elts srt))+ sec = Section RelocatableReadOnlyData (lbl srt)++-- Once we have found the CAFs, we need to do two things:+-- 1. Build a table of all the CAFs used in the procedure.+-- 2. Compute the C_SRT describing the subset of CAFs live at each procpoint.+--+-- When building the local view of the SRT, we first make sure that all the CAFs are+-- in the SRT. Then, if the number of CAFs is small enough to fit in a bitmap,+-- we make sure they're all close enough to the bottom of the table that the+-- bitmap will be able to cover all of them.+buildSRT :: DynFlags -> TopSRT -> CAFSet -> UniqSM (TopSRT, Maybe CmmDecl, C_SRT)+buildSRT dflags topSRT cafs =+ do let+ -- For each label referring to a function f without a static closure,+ -- replace it with the CAFs that are reachable from f.+ sub_srt topSRT localCafs =+ let cafs = Set.elems localCafs+ mkSRT topSRT =+ do localSRTs <- procpointSRT dflags (lbl topSRT) (elt_map topSRT) cafs+ return (topSRT, localSRTs)+ in if length cafs > maxBmpSize dflags then+ mkSRT (foldl add_if_missing topSRT cafs)+ else -- make sure all the cafs are near the bottom of the srt+ mkSRT (add_if_too_far topSRT cafs)+ add_if_missing srt caf =+ if cafMember srt caf then srt else addCAF caf srt+ -- If a CAF is more than maxBmpSize entries from the young end of the+ -- SRT, then we add it to the SRT again.+ -- (Note: Not in the SRT => infinitely far.)+ add_if_too_far srt@(TopSRT {elt_map = m}) cafs =+ add srt (sortBy farthestFst cafs)+ where+ farthestFst x y = case (Map.lookup x m, Map.lookup y m) of+ (Nothing, Nothing) -> EQ+ (Nothing, Just _) -> LT+ (Just _, Nothing) -> GT+ (Just d, Just d') -> compare d' d+ add srt [] = srt+ add srt@(TopSRT {next_elt = next}) (caf : rst) =+ case cafOffset srt caf of+ Just ix -> if next - ix > maxBmpSize dflags then+ add (addCAF caf srt) rst+ else srt+ Nothing -> add (addCAF caf srt) rst+ (topSRT, subSRTs) <- sub_srt topSRT cafs+ let (sub_tbls, blockSRTs) = subSRTs+ return (topSRT, sub_tbls, blockSRTs)++-- Construct an SRT bitmap.+-- Adapted from simpleStg/SRT.hs, which expects Id's.+procpointSRT :: DynFlags -> CLabel -> Map CLabel Int -> [CLabel] ->+ UniqSM (Maybe CmmDecl, C_SRT)+procpointSRT _ _ _ [] =+ return (Nothing, NoC_SRT)+procpointSRT dflags top_srt top_table entries =+ do (top, srt) <- bitmap `seq` to_SRT dflags top_srt offset len bitmap+ return (top, srt)+ where+ ints = map (expectJust "constructSRT" . flip Map.lookup top_table) entries+ sorted_ints = sort ints+ offset = head sorted_ints+ bitmap_entries = map (subtract offset) sorted_ints+ len = P.last bitmap_entries + 1+ bitmap = intsToBitmap dflags len bitmap_entries++maxBmpSize :: DynFlags -> Int+maxBmpSize dflags = widthInBits (wordWidth dflags) `div` 2++-- Adapted from codeGen/StgCmmUtils, which converts from SRT to C_SRT.+to_SRT :: DynFlags -> CLabel -> Int -> Int -> Bitmap -> UniqSM (Maybe CmmDecl, C_SRT)+to_SRT dflags top_srt off len bmp+ | len > maxBmpSize dflags || bmp == [toStgWord dflags (fromStgHalfWord (srtEscape dflags))]+ = do id <- getUniqueM+ let srt_desc_lbl = mkLargeSRTLabel id+ section = Section RelocatableReadOnlyData srt_desc_lbl+ tbl = CmmData section $+ Statics srt_desc_lbl $ map CmmStaticLit+ ( cmmLabelOffW dflags top_srt off+ : mkWordCLit dflags (fromIntegral len)+ : map (mkStgWordCLit dflags) bmp)+ return (Just tbl, C_SRT srt_desc_lbl 0 (srtEscape dflags))+ | otherwise+ = return (Nothing, C_SRT top_srt off (toStgHalfWord dflags (fromStgWord (head bmp))))+ -- The fromIntegral converts to StgHalfWord++-- Gather CAF info for a procedure, but only if the procedure+-- doesn't have a static closure.+-- (If it has a static closure, it will already have an SRT to+-- keep its CAFs live.)+-- Any procedure referring to a non-static CAF c must keep live+-- any CAF that is reachable from c.+localCAFInfo :: CAFEnv -> CmmDecl -> (CAFSet, Maybe CLabel)+localCAFInfo _ (CmmData _ _) = (Set.empty, Nothing)+localCAFInfo cafEnv proc@(CmmProc _ top_l _ (CmmGraph {g_entry=entry})) =+ case topInfoTable proc of+ Just (CmmInfoTable { cit_rep = rep })+ | not (isStaticRep rep) && not (isStackRep rep)+ -> (cafs, Just (toClosureLbl top_l))+ _other -> (cafs, Nothing)+ where+ cafs = expectJust "maybeBindCAFs" $ mapLookup entry cafEnv++-- Once we have the local CAF sets for some (possibly) mutually+-- recursive functions, we can create an environment mapping+-- each function to its set of CAFs. Note that a CAF may+-- be a reference to a function. If that function f does not have+-- a static closure, then we need to refer specifically+-- to the set of CAFs used by f. Of course, the set of CAFs+-- used by f must be included in the local CAF sets that are input to+-- this function. To minimize lookup time later, we return+-- the environment with every reference to f replaced by its set of CAFs.+-- To do this replacement efficiently, we gather strongly connected+-- components, then we sort the components in topological order.+mkTopCAFInfo :: [(CAFSet, Maybe CLabel)] -> Map CLabel CAFSet+mkTopCAFInfo localCAFs = foldl addToTop Map.empty g+ where+ addToTop env (AcyclicSCC (l, cafset)) =+ Map.insert l (flatten env cafset) env+ addToTop env (CyclicSCC nodes) =+ let (lbls, cafsets) = unzip nodes+ cafset = foldr Set.delete (foldl Set.union Set.empty cafsets) lbls+ in foldl (\env l -> Map.insert l (flatten env cafset) env) env lbls++ g = stronglyConnCompFromEdgedVerticesOrd+ [ ((l,cafs), l, Set.elems cafs) | (cafs, Just l) <- localCAFs ]++flatten :: Map CLabel CAFSet -> CAFSet -> CAFSet+flatten env cafset = foldSet (lookup env) Set.empty cafset+ where+ lookup env caf cafset' =+ case Map.lookup caf env of+ Just cafs -> foldSet Set.insert cafset' cafs+ Nothing -> Set.insert caf cafset'++bundle :: Map CLabel CAFSet+ -> (CAFEnv, CmmDecl)+ -> (CAFSet, Maybe CLabel)+ -> (LabelMap CAFSet, CmmDecl)+bundle flatmap (env, decl@(CmmProc infos _lbl _ g)) (closure_cafs, mb_lbl)+ = ( mapMapWithKey get_cafs (info_tbls infos), decl )+ where+ entry = g_entry g++ entry_cafs+ | Just l <- mb_lbl = expectJust "bundle" $ Map.lookup l flatmap+ | otherwise = flatten flatmap closure_cafs++ get_cafs l _+ | l == entry = entry_cafs+ | Just info <- mapLookup l env = flatten flatmap info+ | otherwise = Set.empty+ -- the label might not be in the env if the code corresponding to+ -- this info table was optimised away (perhaps because it was+ -- unreachable). In this case it doesn't matter what SRT we+ -- infer, since the info table will not appear in the generated+ -- code. See #9329.++bundle _flatmap (_, decl) _+ = ( mapEmpty, decl )+++flattenCAFSets :: [(CAFEnv, [CmmDecl])] -> [(LabelMap CAFSet, CmmDecl)]+flattenCAFSets cpsdecls = zipWith (bundle flatmap) zipped localCAFs+ where+ zipped = [ (env,decl) | (env,decls) <- cpsdecls, decl <- decls ]+ localCAFs = unzipWith localCAFInfo zipped+ flatmap = mkTopCAFInfo localCAFs -- transitive closure of localCAFs++doSRTs :: DynFlags+ -> TopSRT+ -> [(CAFEnv, [CmmDecl])]+ -> IO (TopSRT, [CmmDecl])++doSRTs dflags topSRT tops+ = do+ let caf_decls = flattenCAFSets tops+ us <- mkSplitUniqSupply 'u'+ let (topSRT', gs') = initUs_ us $ foldM setSRT (topSRT, []) caf_decls+ return (topSRT', reverse gs' {- Note [reverse gs] -})+ where+ setSRT (topSRT, rst) (caf_map, decl@(CmmProc{})) = do+ (topSRT, srt_tables, srt_env) <- buildSRTs dflags topSRT caf_map+ let decl' = updInfoSRTs srt_env decl+ return (topSRT, decl': srt_tables ++ rst)+ setSRT (topSRT, rst) (_, decl) =+ return (topSRT, decl : rst)++buildSRTs :: DynFlags -> TopSRT -> LabelMap CAFSet+ -> UniqSM (TopSRT, [CmmDecl], LabelMap C_SRT)+buildSRTs dflags top_srt caf_map+ = foldM doOne (top_srt, [], mapEmpty) (mapToList caf_map)+ where+ doOne (top_srt, decls, srt_env) (l, cafs)+ = do (top_srt, mb_decl, srt) <- buildSRT dflags top_srt cafs+ return ( top_srt, maybeToList mb_decl ++ decls+ , mapInsert l srt srt_env )++{-+- In each CmmDecl there is a mapping from BlockId -> CmmInfoTable+- The one corresponding to g_entry is the closure info table, the+ rest are continuations.+- Each one needs an SRT.+- We get the CAFSet for each one from the CAFEnv+- flatten gives us+ [(LabelMap CAFSet, CmmDecl)]+-+-}+++{- Note [reverse gs]++ It is important to keep the code blocks in the same order,+ otherwise binary sizes get slightly bigger. I'm not completely+ sure why this is, perhaps the assembler generates bigger jump+ instructions for forward refs. --SDM+-}++updInfoSRTs :: LabelMap C_SRT -> CmmDecl -> CmmDecl+updInfoSRTs srt_env (CmmProc top_info top_l live g) =+ CmmProc (top_info {info_tbls = mapMapWithKey updInfoTbl (info_tbls top_info)}) top_l live g+ where updInfoTbl l info_tbl+ = info_tbl { cit_srt = expectJust "updInfo" $ mapLookup l srt_env }+updInfoSRTs _ t = t
+ cmm/CmmCallConv.hs view
@@ -0,0 +1,220 @@+{-# LANGUAGE CPP #-}++module CmmCallConv (+ ParamLocation(..),+ assignArgumentsPos,+ assignStack,+ realArgRegsCover+) where++#include "HsVersions.h"++import CmmExpr+import SMRep+import Cmm (Convention(..))+import PprCmm ()++import DynFlags+import Platform+import Outputable++-- Calculate the 'GlobalReg' or stack locations for function call+-- parameters as used by the Cmm calling convention.++data ParamLocation+ = RegisterParam GlobalReg+ | StackParam ByteOff++instance Outputable ParamLocation where+ ppr (RegisterParam g) = ppr g+ ppr (StackParam p) = ppr p++-- |+-- Given a list of arguments, and a function that tells their types,+-- return a list showing where each argument is passed+--+assignArgumentsPos :: DynFlags+ -> ByteOff -- stack offset to start with+ -> Convention+ -> (a -> CmmType) -- how to get a type from an arg+ -> [a] -- args+ -> (+ ByteOff -- bytes of stack args+ , [(a, ParamLocation)] -- args and locations+ )++assignArgumentsPos dflags off conv arg_ty reps = (stk_off, assignments)+ where+ regs = case (reps, conv) of+ (_, NativeNodeCall) -> getRegsWithNode dflags+ (_, NativeDirectCall) -> getRegsWithoutNode dflags+ ([_], NativeReturn) -> allRegs dflags+ (_, NativeReturn) -> getRegsWithNode dflags+ -- GC calling convention *must* put values in registers+ (_, GC) -> allRegs dflags+ (_, Slow) -> nodeOnly+ -- The calling conventions first assign arguments to registers,+ -- then switch to the stack when we first run out of registers+ -- (even if there are still available registers for args of a+ -- different type). When returning an unboxed tuple, we also+ -- separate the stack arguments by pointerhood.+ (reg_assts, stk_args) = assign_regs [] reps regs+ (stk_off, stk_assts) = assignStack dflags off arg_ty stk_args+ assignments = reg_assts ++ stk_assts++ assign_regs assts [] _ = (assts, [])+ assign_regs assts (r:rs) regs | isVecType ty = vec+ | isFloatType ty = float+ | otherwise = int+ where vec = case (w, regs) of+ (W128, (vs, fs, ds, ls, s:ss))+ | passVectorInReg W128 dflags -> k (RegisterParam (XmmReg s), (vs, fs, ds, ls, ss))+ (W256, (vs, fs, ds, ls, s:ss))+ | passVectorInReg W256 dflags -> k (RegisterParam (YmmReg s), (vs, fs, ds, ls, ss))+ (W512, (vs, fs, ds, ls, s:ss))+ | passVectorInReg W512 dflags -> k (RegisterParam (ZmmReg s), (vs, fs, ds, ls, ss))+ _ -> (assts, (r:rs))+ float = case (w, regs) of+ (W32, (vs, fs, ds, ls, s:ss))+ | passFloatInXmm -> k (RegisterParam (FloatReg s), (vs, fs, ds, ls, ss))+ (W32, (vs, f:fs, ds, ls, ss))+ | not passFloatInXmm -> k (RegisterParam f, (vs, fs, ds, ls, ss))+ (W64, (vs, fs, ds, ls, s:ss))+ | passFloatInXmm -> k (RegisterParam (DoubleReg s), (vs, fs, ds, ls, ss))+ (W64, (vs, fs, d:ds, ls, ss))+ | not passFloatInXmm -> k (RegisterParam d, (vs, fs, ds, ls, ss))+ (W80, _) -> panic "F80 unsupported register type"+ _ -> (assts, (r:rs))+ int = case (w, regs) of+ (W128, _) -> panic "W128 unsupported register type"+ (_, (v:vs, fs, ds, ls, ss)) | widthInBits w <= widthInBits (wordWidth dflags)+ -> k (RegisterParam (v gcp), (vs, fs, ds, ls, ss))+ (_, (vs, fs, ds, l:ls, ss)) | widthInBits w > widthInBits (wordWidth dflags)+ -> k (RegisterParam l, (vs, fs, ds, ls, ss))+ _ -> (assts, (r:rs))+ k (asst, regs') = assign_regs ((r, asst) : assts) rs regs'+ ty = arg_ty r+ w = typeWidth ty+ gcp | isGcPtrType ty = VGcPtr+ | otherwise = VNonGcPtr+ passFloatInXmm = passFloatArgsInXmm dflags++passFloatArgsInXmm :: DynFlags -> Bool+passFloatArgsInXmm dflags = case platformArch (targetPlatform dflags) of+ ArchX86_64 -> True+ _ -> False++-- On X86_64, we always pass 128-bit-wide vectors in registers. On 32-bit X86+-- and for all larger vector sizes on X86_64, LLVM's GHC calling convention+-- does not currently pass vectors in registers. The patch to update the GHC+-- calling convention to support passing SIMD vectors in registers is small and+-- well-contained, so it may make it into LLVM 3.4. The hidden+-- -fllvm-pass-vectors-in-regs flag will generate LLVM code that attempts to+-- pass vectors in registers, but it must only be used with a version of LLVM+-- that has an updated GHC calling convention.+passVectorInReg :: Width -> DynFlags -> Bool+passVectorInReg W128 dflags = case platformArch (targetPlatform dflags) of+ ArchX86_64 -> True+ _ -> gopt Opt_LlvmPassVectorsInRegisters dflags+passVectorInReg _ dflags = gopt Opt_LlvmPassVectorsInRegisters dflags++assignStack :: DynFlags -> ByteOff -> (a -> CmmType) -> [a]+ -> (+ ByteOff -- bytes of stack args+ , [(a, ParamLocation)] -- args and locations+ )+assignStack dflags offset arg_ty args = assign_stk offset [] (reverse args)+ where+ assign_stk offset assts [] = (offset, assts)+ assign_stk offset assts (r:rs)+ = assign_stk off' ((r, StackParam off') : assts) rs+ where w = typeWidth (arg_ty r)+ size = (((widthInBytes w - 1) `div` word_size) + 1) * word_size+ off' = offset + size+ word_size = wORD_SIZE dflags++-----------------------------------------------------------------------------+-- Local information about the registers available++type AvailRegs = ( [VGcPtr -> GlobalReg] -- available vanilla regs.+ , [GlobalReg] -- floats+ , [GlobalReg] -- doubles+ , [GlobalReg] -- longs (int64 and word64)+ , [Int] -- XMM (floats and doubles)+ )++-- Vanilla registers can contain pointers, Ints, Chars.+-- Floats and doubles have separate register supplies.+--+-- We take these register supplies from the *real* registers, i.e. those+-- that are guaranteed to map to machine registers.++getRegsWithoutNode, getRegsWithNode :: DynFlags -> AvailRegs+getRegsWithoutNode dflags =+ ( filter (\r -> r VGcPtr /= node) (realVanillaRegs dflags)+ , realFloatRegs dflags+ , realDoubleRegs dflags+ , realLongRegs dflags+ , realXmmRegNos dflags)++-- getRegsWithNode uses R1/node even if it isn't a register+getRegsWithNode dflags =+ ( if null (realVanillaRegs dflags)+ then [VanillaReg 1]+ else realVanillaRegs dflags+ , realFloatRegs dflags+ , realDoubleRegs dflags+ , realLongRegs dflags+ , realXmmRegNos dflags)++allFloatRegs, allDoubleRegs, allLongRegs :: DynFlags -> [GlobalReg]+allVanillaRegs :: DynFlags -> [VGcPtr -> GlobalReg]+allXmmRegs :: DynFlags -> [Int]++allVanillaRegs dflags = map VanillaReg $ regList (mAX_Vanilla_REG dflags)+allFloatRegs dflags = map FloatReg $ regList (mAX_Float_REG dflags)+allDoubleRegs dflags = map DoubleReg $ regList (mAX_Double_REG dflags)+allLongRegs dflags = map LongReg $ regList (mAX_Long_REG dflags)+allXmmRegs dflags = regList (mAX_XMM_REG dflags)++realFloatRegs, realDoubleRegs, realLongRegs :: DynFlags -> [GlobalReg]+realVanillaRegs :: DynFlags -> [VGcPtr -> GlobalReg]+realXmmRegNos :: DynFlags -> [Int]++realVanillaRegs dflags = map VanillaReg $ regList (mAX_Real_Vanilla_REG dflags)+realFloatRegs dflags = map FloatReg $ regList (mAX_Real_Float_REG dflags)+realDoubleRegs dflags = map DoubleReg $ regList (mAX_Real_Double_REG dflags)+realLongRegs dflags = map LongReg $ regList (mAX_Real_Long_REG dflags)++realXmmRegNos dflags+ | isSse2Enabled dflags = regList (mAX_Real_XMM_REG dflags)+ | otherwise = []++regList :: Int -> [Int]+regList n = [1 .. n]++allRegs :: DynFlags -> AvailRegs+allRegs dflags = (allVanillaRegs dflags,+ allFloatRegs dflags,+ allDoubleRegs dflags,+ allLongRegs dflags,+ allXmmRegs dflags)++nodeOnly :: AvailRegs+nodeOnly = ([VanillaReg 1], [], [], [], [])++-- This returns the set of global registers that *cover* the machine registers+-- used for argument passing. On platforms where registers can overlap---right+-- now just x86-64, where Float and Double registers overlap---passing this set+-- of registers is guaranteed to preserve the contents of all live registers. We+-- only use this functionality in hand-written C-- code in the RTS.+realArgRegsCover :: DynFlags -> [GlobalReg]+realArgRegsCover dflags+ | passFloatArgsInXmm dflags = map ($VGcPtr) (realVanillaRegs dflags) +++ realLongRegs dflags +++ map XmmReg (realXmmRegNos dflags)+ | otherwise = map ($VGcPtr) (realVanillaRegs dflags) +++ realFloatRegs dflags +++ realDoubleRegs dflags +++ realLongRegs dflags +++ map XmmReg (realXmmRegNos dflags)
+ cmm/CmmCommonBlockElim.hs view
@@ -0,0 +1,302 @@+{-# LANGUAGE GADTs, BangPatterns #-}+module CmmCommonBlockElim+ ( elimCommonBlocks+ )+where+++import BlockId+import Cmm+import CmmUtils+import CmmSwitch (eqSwitchTargetWith)+import CmmContFlowOpt+-- import PprCmm ()+import Prelude hiding (iterate, succ, unzip, zip)++import Hoopl hiding (ChangeFlag)+import Data.Bits+import Data.Maybe (mapMaybe)+import qualified Data.List as List+import Data.Word+import qualified Data.Map as M+import Outputable+import UniqFM+import UniqDFM+import qualified TrieMap as TM+import Unique+import Control.Arrow (first, second)++-- -----------------------------------------------------------------------------+-- Eliminate common blocks++-- If two blocks are identical except for the label on the first node,+-- then we can eliminate one of the blocks. To ensure that the semantics+-- of the program are preserved, we have to rewrite each predecessor of the+-- eliminated block to proceed with the block we keep.++-- The algorithm iterates over the blocks in the graph,+-- checking whether it has seen another block that is equal modulo labels.+-- If so, then it adds an entry in a map indicating that the new block+-- is made redundant by the old block.+-- Otherwise, it is added to the useful blocks.++-- To avoid comparing every block with every other block repeatedly, we group+-- them by+-- * a hash of the block, ignoring labels (explained below)+-- * the list of outgoing labels+-- The hash is invariant under relabeling, so we only ever compare within+-- the same group of blocks.+--+-- The list of outgoing labels is updated as we merge blocks (that is why they+-- are not included in the hash, which we want to calculate only once).+--+-- All in all, two blocks should never be compared if they have different+-- hashes, and at most once otherwise. Previously, we were slower, and people+-- rightfully complained: #10397++-- TODO: Use optimization fuel+elimCommonBlocks :: CmmGraph -> CmmGraph+elimCommonBlocks g = replaceLabels env $ copyTicks env g+ where+ env = iterate mapEmpty blocks_with_key+ groups = groupByInt hash_block (postorderDfs g)+ blocks_with_key = [ [ (successors b, [b]) | b <- bs] | bs <- groups]++-- Invariant: The blocks in the list are pairwise distinct+-- (so avoid comparing them again)+type DistinctBlocks = [CmmBlock]+type Key = [Label]+type Subst = LabelMap BlockId++-- The outer list groups by hash. We retain this grouping throughout.+iterate :: Subst -> [[(Key, DistinctBlocks)]] -> Subst+iterate subst blocks+ | mapNull new_substs = subst+ | otherwise = iterate subst' updated_blocks+ where+ grouped_blocks :: [[(Key, [DistinctBlocks])]]+ grouped_blocks = map groupByLabel blocks++ merged_blocks :: [[(Key, DistinctBlocks)]]+ (new_substs, merged_blocks) = List.mapAccumL (List.mapAccumL go) mapEmpty grouped_blocks+ where+ go !new_subst1 (k,dbs) = (new_subst1 `mapUnion` new_subst2, (k,db))+ where+ (new_subst2, db) = mergeBlockList subst dbs++ subst' = subst `mapUnion` new_substs+ updated_blocks = map (map (first (map (lookupBid subst')))) merged_blocks++mergeBlocks :: Subst -> DistinctBlocks -> DistinctBlocks -> (Subst, DistinctBlocks)+mergeBlocks subst existing new = go new+ where+ go [] = (mapEmpty, existing)+ go (b:bs) = case List.find (eqBlockBodyWith (eqBid subst) b) existing of+ -- This block is a duplicate. Drop it, and add it to the substitution+ Just b' -> first (mapInsert (entryLabel b) (entryLabel b')) $ go bs+ -- This block is not a duplicate, keep it.+ Nothing -> second (b:) $ go bs++mergeBlockList :: Subst -> [DistinctBlocks] -> (Subst, DistinctBlocks)+mergeBlockList _ [] = pprPanic "mergeBlockList" empty+mergeBlockList subst (b:bs) = go mapEmpty b bs+ where+ go !new_subst1 b [] = (new_subst1, b)+ go !new_subst1 b1 (b2:bs) = go new_subst b bs+ where+ (new_subst2, b) = mergeBlocks subst b1 b2+ new_subst = new_subst1 `mapUnion` new_subst2+++-- -----------------------------------------------------------------------------+-- Hashing and equality on blocks++-- Below here is mostly boilerplate: hashing blocks ignoring labels,+-- and comparing blocks modulo a label mapping.++-- To speed up comparisons, we hash each basic block modulo jump labels.+-- The hashing is a bit arbitrary (the numbers are completely arbitrary),+-- but it should be fast and good enough.++-- We want to get as many small buckets as possible, as comparing blocks is+-- expensive. So include as much as possible in the hash. Ideally everything+-- that is compared with (==) in eqBlockBodyWith.++type HashCode = Int++hash_block :: CmmBlock -> HashCode+hash_block block =+ fromIntegral (foldBlockNodesB3 (hash_fst, hash_mid, hash_lst) block (0 :: Word32) .&. (0x7fffffff :: Word32))+ -- UniqFM doesn't like negative Ints+ where hash_fst _ h = h+ hash_mid m h = hash_node m + h `shiftL` 1+ hash_lst m h = hash_node m + h `shiftL` 1++ hash_node :: CmmNode O x -> Word32+ hash_node n | dont_care n = 0 -- don't care+ hash_node (CmmAssign r e) = hash_reg r + hash_e e+ hash_node (CmmStore e e') = hash_e e + hash_e e'+ hash_node (CmmUnsafeForeignCall t _ as) = hash_tgt t + hash_list hash_e as+ hash_node (CmmBranch _) = 23 -- NB. ignore the label+ hash_node (CmmCondBranch p _ _ _) = hash_e p+ hash_node (CmmCall e _ _ _ _ _) = hash_e e+ hash_node (CmmForeignCall t _ _ _ _ _ _) = hash_tgt t+ hash_node (CmmSwitch e _) = hash_e e+ hash_node _ = error "hash_node: unknown Cmm node!"++ hash_reg :: CmmReg -> Word32+ hash_reg (CmmLocal localReg) = hash_unique localReg -- important for performance, see #10397+ hash_reg (CmmGlobal _) = 19++ hash_e :: CmmExpr -> Word32+ hash_e (CmmLit l) = hash_lit l+ hash_e (CmmLoad e _) = 67 + hash_e e+ hash_e (CmmReg r) = hash_reg r+ hash_e (CmmMachOp _ es) = hash_list hash_e es -- pessimal - no operator check+ hash_e (CmmRegOff r i) = hash_reg r + cvt i+ hash_e (CmmStackSlot _ _) = 13++ hash_lit :: CmmLit -> Word32+ hash_lit (CmmInt i _) = fromInteger i+ hash_lit (CmmFloat r _) = truncate r+ hash_lit (CmmVec ls) = hash_list hash_lit ls+ hash_lit (CmmLabel _) = 119 -- ugh+ hash_lit (CmmLabelOff _ i) = cvt $ 199 + i+ hash_lit (CmmLabelDiffOff _ _ i) = cvt $ 299 + i+ hash_lit (CmmBlock _) = 191 -- ugh+ hash_lit (CmmHighStackMark) = cvt 313++ hash_tgt (ForeignTarget e _) = hash_e e+ hash_tgt (PrimTarget _) = 31 -- lots of these++ hash_list f = foldl (\z x -> f x + z) (0::Word32)++ cvt = fromInteger . toInteger++ hash_unique :: Uniquable a => a -> Word32+ hash_unique = cvt . getKey . getUnique++-- | Ignore these node types for equality+dont_care :: CmmNode O x -> Bool+dont_care CmmComment {} = True+dont_care CmmTick {} = True+dont_care CmmUnwind {} = True+dont_care _other = False++-- Utilities: equality and substitution on the graph.++-- Given a map ``subst'' from BlockID -> BlockID, we define equality.+eqBid :: LabelMap BlockId -> BlockId -> BlockId -> Bool+eqBid subst bid bid' = lookupBid subst bid == lookupBid subst bid'+lookupBid :: LabelMap BlockId -> BlockId -> BlockId+lookupBid subst bid = case mapLookup bid subst of+ Just bid -> lookupBid subst bid+ Nothing -> bid++-- Middle nodes and expressions can contain BlockIds, in particular in+-- CmmStackSlot and CmmBlock, so we have to use a special equality for+-- these.+--+eqMiddleWith :: (BlockId -> BlockId -> Bool)+ -> CmmNode O O -> CmmNode O O -> Bool+eqMiddleWith eqBid (CmmAssign r1 e1) (CmmAssign r2 e2)+ = r1 == r2 && eqExprWith eqBid e1 e2+eqMiddleWith eqBid (CmmStore l1 r1) (CmmStore l2 r2)+ = eqExprWith eqBid l1 l2 && eqExprWith eqBid r1 r2+eqMiddleWith eqBid (CmmUnsafeForeignCall t1 r1 a1)+ (CmmUnsafeForeignCall t2 r2 a2)+ = t1 == t2 && r1 == r2 && and (zipWith (eqExprWith eqBid) a1 a2)+eqMiddleWith _ _ _ = False++eqExprWith :: (BlockId -> BlockId -> Bool)+ -> CmmExpr -> CmmExpr -> Bool+eqExprWith eqBid = eq+ where+ CmmLit l1 `eq` CmmLit l2 = eqLit l1 l2+ CmmLoad e1 _ `eq` CmmLoad e2 _ = e1 `eq` e2+ CmmReg r1 `eq` CmmReg r2 = r1==r2+ CmmRegOff r1 i1 `eq` CmmRegOff r2 i2 = r1==r2 && i1==i2+ CmmMachOp op1 es1 `eq` CmmMachOp op2 es2 = op1==op2 && es1 `eqs` es2+ CmmStackSlot a1 i1 `eq` CmmStackSlot a2 i2 = eqArea a1 a2 && i1==i2+ _e1 `eq` _e2 = False++ xs `eqs` ys = and (zipWith eq xs ys)++ eqLit (CmmBlock id1) (CmmBlock id2) = eqBid id1 id2+ eqLit l1 l2 = l1 == l2++ eqArea Old Old = True+ eqArea (Young id1) (Young id2) = eqBid id1 id2+ eqArea _ _ = False++-- Equality on the body of a block, modulo a function mapping block+-- IDs to block IDs.+eqBlockBodyWith :: (BlockId -> BlockId -> Bool) -> CmmBlock -> CmmBlock -> Bool+eqBlockBodyWith eqBid block block'+ {-+ | equal = pprTrace "equal" (vcat [ppr block, ppr block']) True+ | otherwise = pprTrace "not equal" (vcat [ppr block, ppr block']) False+ -}+ = equal+ where (_,m,l) = blockSplit block+ nodes = filter (not . dont_care) (blockToList m)+ (_,m',l') = blockSplit block'+ nodes' = filter (not . dont_care) (blockToList m')++ equal = and (zipWith (eqMiddleWith eqBid) nodes nodes') &&+ eqLastWith eqBid l l'+++eqLastWith :: (BlockId -> BlockId -> Bool) -> CmmNode O C -> CmmNode O C -> Bool+eqLastWith eqBid (CmmBranch bid1) (CmmBranch bid2) = eqBid bid1 bid2+eqLastWith eqBid (CmmCondBranch c1 t1 f1 l1) (CmmCondBranch c2 t2 f2 l2) =+ c1 == c2 && l1 == l2 && eqBid t1 t2 && eqBid f1 f2+eqLastWith eqBid (CmmCall t1 c1 g1 a1 r1 u1) (CmmCall t2 c2 g2 a2 r2 u2) =+ t1 == t2 && eqMaybeWith eqBid c1 c2 && a1 == a2 && r1 == r2 && u1 == u2 && g1 == g2+eqLastWith eqBid (CmmSwitch e1 ids1) (CmmSwitch e2 ids2) =+ e1 == e2 && eqSwitchTargetWith eqBid ids1 ids2+eqLastWith _ _ _ = False++eqMaybeWith :: (a -> b -> Bool) -> Maybe a -> Maybe b -> Bool+eqMaybeWith eltEq (Just e) (Just e') = eltEq e e'+eqMaybeWith _ Nothing Nothing = True+eqMaybeWith _ _ _ = False++-- | Given a block map, ensure that all "target" blocks are covered by+-- the same ticks as the respective "source" blocks. This not only+-- means copying ticks, but also adjusting tick scopes where+-- necessary.+copyTicks :: LabelMap BlockId -> CmmGraph -> CmmGraph+copyTicks env g+ | mapNull env = g+ | otherwise = ofBlockMap (g_entry g) $ mapMap copyTo blockMap+ where -- Reverse block merge map+ blockMap = toBlockMap g+ revEnv = mapFoldWithKey insertRev M.empty env+ insertRev k x = M.insertWith (const (k:)) x [k]+ -- Copy ticks and scopes into the given block+ copyTo block = case M.lookup (entryLabel block) revEnv of+ Nothing -> block+ Just ls -> foldr copy block $ mapMaybe (flip mapLookup blockMap) ls+ copy from to =+ let ticks = blockTicks from+ CmmEntry _ scp0 = firstNode from+ (CmmEntry lbl scp1, code) = blockSplitHead to+ in CmmEntry lbl (combineTickScopes scp0 scp1) `blockJoinHead`+ foldr blockCons code (map CmmTick ticks)++-- Group by [Label]+groupByLabel :: [(Key, a)] -> [(Key, [a])]+groupByLabel = go (TM.emptyTM :: TM.ListMap UniqDFM a)+ where+ go !m [] = TM.foldTM (:) m []+ go !m ((k,v) : entries) = go (TM.alterTM k' adjust m) entries+ where k' = map getUnique k+ adjust Nothing = Just (k,[v])+ adjust (Just (_,vs)) = Just (k,v:vs)+++groupByInt :: (a -> Int) -> [a] -> [[a]]+groupByInt f xs = nonDetEltsUFM $ List.foldl' go emptyUFM xs+ -- See Note [Unique Determinism and code generation]+ where go m x = alterUFM (Just . maybe [x] (x:)) m (f x)
+ cmm/CmmContFlowOpt.hs view
@@ -0,0 +1,415 @@+{-# LANGUAGE GADTs #-}+{-# OPTIONS_GHC -fno-warn-incomplete-patterns #-}+module CmmContFlowOpt+ ( cmmCfgOpts+ , cmmCfgOptsProc+ , removeUnreachableBlocksProc+ , replaceLabels+ )+where++import Hoopl+import BlockId+import Cmm+import CmmUtils+import CmmSwitch (mapSwitchTargets)+import Maybes+import Panic++import Control.Monad+import Prelude hiding (succ, unzip, zip)+++-- Note [What is shortcutting]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Consider this Cmm code:+--+-- L1: ...+-- goto L2;+-- L2: goto L3;+-- L3: ...+--+-- Here L2 is an empty block and contains only an unconditional branch+-- to L3. In this situation any block that jumps to L2 can jump+-- directly to L3:+--+-- L1: ...+-- goto L3;+-- L2: goto L3;+-- L3: ...+--+-- In this situation we say that we shortcut L2 to L3. One of+-- consequences of shortcutting is that some blocks of code may become+-- unreachable (in the example above this is true for L2).+++-- Note [Control-flow optimisations]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- This optimisation does three things:+--+-- - If a block finishes in an unconditonal branch to another block+-- and that is the only jump to that block we concatenate the+-- destination block at the end of the current one.+--+-- - If a block finishes in a call whose continuation block is a+-- goto, then we can shortcut the destination, making the+-- continuation block the destination of the goto - but see Note+-- [Shortcut call returns].+--+-- - For any block that is not a call we try to shortcut the+-- destination(s). Additionally, if a block ends with a+-- conditional branch we try to invert the condition.+--+-- Blocks are processed using postorder DFS traversal. A side effect+-- of determining traversal order with a graph search is elimination+-- of any blocks that are unreachable.+--+-- Transformations are improved by working from the end of the graph+-- towards the beginning, because we may be able to perform many+-- shortcuts in one go.+++-- Note [Shortcut call returns]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- We are going to maintain the "current" graph (LabelMap CmmBlock) as+-- we go, and also a mapping from BlockId to BlockId, representing+-- continuation labels that we have renamed. This latter mapping is+-- important because we might shortcut a CmmCall continuation. For+-- example:+--+-- Sp[0] = L+-- call g returns to L+-- L: goto M+-- M: ...+--+-- So when we shortcut the L block, we need to replace not only+-- the continuation of the call, but also references to L in the+-- code (e.g. the assignment Sp[0] = L):+--+-- Sp[0] = M+-- call g returns to M+-- M: ...+--+-- So we keep track of which labels we have renamed and apply the mapping+-- at the end with replaceLabels.+++-- Note [Shortcut call returns and proc-points]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Consider this code that you might get from a recursive+-- let-no-escape:+--+-- goto L1+-- L1:+-- if (Hp > HpLim) then L2 else L3+-- L2:+-- call stg_gc_noregs returns to L4+-- L4:+-- goto L1+-- L3:+-- ...+-- goto L1+--+-- Then the control-flow optimiser shortcuts L4. But that turns L1+-- into the call-return proc point, and every iteration of the loop+-- has to shuffle variables to and from the stack. So we must *not*+-- shortcut L4.+--+-- Moreover not shortcutting call returns is probably fine. If L4 can+-- concat with its branch target then it will still do so. And we+-- save some compile time because we don't have to traverse all the+-- code in replaceLabels.+--+-- However, we probably do want to do this if we are splitting proc+-- points, because L1 will be a proc-point anyway, so merging it with+-- L4 reduces the number of proc points. Unfortunately recursive+-- let-no-escapes won't generate very good code with proc-point+-- splitting on - we should probably compile them to explicitly use+-- the native calling convention instead.++cmmCfgOpts :: Bool -> CmmGraph -> CmmGraph+cmmCfgOpts split g = fst (blockConcat split g)++cmmCfgOptsProc :: Bool -> CmmDecl -> CmmDecl+cmmCfgOptsProc split (CmmProc info lbl live g) = CmmProc info' lbl live g'+ where (g', env) = blockConcat split g+ info' = info{ info_tbls = new_info_tbls }+ new_info_tbls = mapFromList (map upd_info (mapToList (info_tbls info)))++ -- If we changed any labels, then we have to update the info tables+ -- too, except for the top-level info table because that might be+ -- referred to by other procs.+ upd_info (k,info)+ | Just k' <- mapLookup k env+ = (k', if k' == g_entry g'+ then info+ else info{ cit_lbl = infoTblLbl k' })+ | otherwise+ = (k,info)+cmmCfgOptsProc _ top = top+++blockConcat :: Bool -> CmmGraph -> (CmmGraph, LabelMap BlockId)+blockConcat splitting_procs g@CmmGraph { g_entry = entry_id }+ = (replaceLabels shortcut_map $ ofBlockMap new_entry new_blocks, shortcut_map')+ where+ -- We might be able to shortcut the entry BlockId itself.+ -- Remember to update the shortcut_map, since we also have to+ -- update the info_tbls mapping now.+ (new_entry, shortcut_map')+ | Just entry_blk <- mapLookup entry_id new_blocks+ , Just dest <- canShortcut entry_blk+ = (dest, mapInsert entry_id dest shortcut_map)+ | otherwise+ = (entry_id, shortcut_map)++ -- blocks is a list of blocks in DFS postorder, while blockmap is+ -- a map of blocks. We process each element from blocks and update+ -- blockmap accordingly+ blocks = postorderDfs g+ blockmap = foldr addBlock emptyBody blocks++ -- Accumulator contains three components:+ -- * map of blocks in a graph+ -- * map of shortcut labels. See Note [Shortcut call returns]+ -- * map containing number of predecessors for each block. We discard+ -- it after we process all blocks.+ (new_blocks, shortcut_map, _) =+ foldr maybe_concat (blockmap, mapEmpty, initialBackEdges) blocks++ -- Map of predecessors for initial graph. We increase number of+ -- predecessors for entry block by one to denote that it is+ -- target of a jump, even if no block in the current graph jumps+ -- to it.+ initialBackEdges = incPreds entry_id (predMap blocks)++ maybe_concat :: CmmBlock+ -> (LabelMap CmmBlock, LabelMap BlockId, LabelMap Int)+ -> (LabelMap CmmBlock, LabelMap BlockId, LabelMap Int)+ maybe_concat block (blocks, shortcut_map, backEdges)+ -- If:+ -- (1) current block ends with unconditional branch to b' and+ -- (2) it has exactly one predecessor (namely, current block)+ --+ -- Then:+ -- (1) append b' block at the end of current block+ -- (2) remove b' from the map of blocks+ -- (3) remove information about b' from predecessors map+ --+ -- Since we know that the block has only one predecessor we call+ -- mapDelete directly instead of calling decPreds.+ --+ -- Note that we always maintain an up-to-date list of predecessors, so+ -- we can ignore the contents of shortcut_map+ | CmmBranch b' <- last+ , hasOnePredecessor b'+ , Just blk' <- mapLookup b' blocks+ = let bid' = entryLabel blk'+ in ( mapDelete bid' $ mapInsert bid (splice head blk') blocks+ , shortcut_map+ , mapDelete b' backEdges )++ -- If:+ -- (1) we are splitting proc points (see Note+ -- [Shortcut call returns and proc-points]) and+ -- (2) current block is a CmmCall or CmmForeignCall with+ -- continuation b' and+ -- (3) we can shortcut that continuation to dest+ -- Then:+ -- (1) we change continuation to point to b'+ -- (2) create mapping from b' to dest+ -- (3) increase number of predecessors of dest by 1+ -- (4) decrease number of predecessors of b' by 1+ --+ -- Later we will use replaceLabels to substitute all occurrences of b'+ -- with dest.+ | splitting_procs+ , Just b' <- callContinuation_maybe last+ , Just blk' <- mapLookup b' blocks+ , Just dest <- canShortcut blk'+ = ( mapInsert bid (blockJoinTail head (update_cont dest)) blocks+ , mapInsert b' dest shortcut_map+ , decPreds b' $ incPreds dest backEdges )++ -- If:+ -- (1) a block does not end with a call+ -- Then:+ -- (1) if it ends with a conditional attempt to invert the+ -- conditional+ -- (2) attempt to shortcut all destination blocks+ -- (3) if new successors of a block are different from the old ones+ -- update the of predecessors accordingly+ --+ -- A special case of this is a situation when a block ends with an+ -- unconditional jump to a block that can be shortcut.+ | Nothing <- callContinuation_maybe last+ = let oldSuccs = successors last+ newSuccs = successors swapcond_last+ in ( mapInsert bid (blockJoinTail head swapcond_last) blocks+ , shortcut_map+ , if oldSuccs == newSuccs+ then backEdges+ else foldr incPreds (foldr decPreds backEdges oldSuccs) newSuccs )++ -- Otherwise don't do anything+ | otherwise+ = ( blocks, shortcut_map, backEdges )+ where+ (head, last) = blockSplitTail block+ bid = entryLabel block++ -- Changes continuation of a call to a specified label+ update_cont dest =+ case last of+ CmmCall{} -> last { cml_cont = Just dest }+ CmmForeignCall{} -> last { succ = dest }+ _ -> panic "Can't shortcut continuation."++ -- Attempts to shortcut successors of last node+ shortcut_last = mapSuccessors shortcut last+ where+ shortcut l =+ case mapLookup l blocks of+ Just b | Just dest <- canShortcut b -> dest+ _otherwise -> l++ -- For a conditional, we invert the conditional if that would make it+ -- more likely that the branch-not-taken case becomes a fallthrough.+ -- This helps the native codegen a little bit, and probably has no+ -- effect on LLVM. It's convenient to do it here, where we have the+ -- information about predecessors.+ swapcond_last+ | CmmCondBranch cond t f l <- shortcut_last+ , likelyFalse l+ , numPreds f > 1+ , hasOnePredecessor t+ , Just cond' <- maybeInvertCmmExpr cond+ = CmmCondBranch cond' f t (invertLikeliness l)++ | otherwise+ = shortcut_last++ likelyFalse (Just False) = True+ likelyFalse Nothing = True+ likelyFalse _ = False++ invertLikeliness (Just b) = Just (not b)+ invertLikeliness Nothing = Nothing++ -- Number of predecessors for a block+ numPreds bid = mapLookup bid backEdges `orElse` 0++ hasOnePredecessor b = numPreds b == 1++-- Functions for incrementing and decrementing number of predecessors. If+-- decrementing would set the predecessor count to 0, we remove entry from the+-- map.+-- Invariant: if a block has no predecessors it should be dropped from the+-- graph because it is unreachable. maybe_concat is constructed to maintain+-- that invariant, but calling replaceLabels may introduce unreachable blocks.+-- We rely on subsequent passes in the Cmm pipeline to remove unreachable+-- blocks.+incPreds, decPreds :: BlockId -> LabelMap Int -> LabelMap Int+incPreds bid edges = mapInsertWith (+) bid 1 edges+decPreds bid edges = case mapLookup bid edges of+ Just preds | preds > 1 -> mapInsert bid (preds - 1) edges+ Just _ -> mapDelete bid edges+ _ -> edges+++-- Checks if a block consists only of "goto dest". If it does than we return+-- "Just dest" label. See Note [What is shortcutting]+canShortcut :: CmmBlock -> Maybe BlockId+canShortcut block+ | (_, middle, CmmBranch dest) <- blockSplit block+ , all dont_care $ blockToList middle+ = Just dest+ | otherwise+ = Nothing+ where dont_care CmmComment{} = True+ dont_care CmmTick{} = True+ dont_care _other = False++-- Concatenates two blocks. First one is assumed to be open on exit, the second+-- is assumed to be closed on entry (i.e. it has a label attached to it, which+-- the splice function removes by calling snd on result of blockSplitHead).+splice :: Block CmmNode C O -> CmmBlock -> CmmBlock+splice head rest = entry `blockJoinHead` code0 `blockAppend` code1+ where (CmmEntry lbl sc0, code0) = blockSplitHead head+ (CmmEntry _ sc1, code1) = blockSplitHead rest+ entry = CmmEntry lbl (combineTickScopes sc0 sc1)++-- If node is a call with continuation call return Just label of that+-- continuation. Otherwise return Nothing.+callContinuation_maybe :: CmmNode O C -> Maybe BlockId+callContinuation_maybe (CmmCall { cml_cont = Just b }) = Just b+callContinuation_maybe (CmmForeignCall { succ = b }) = Just b+callContinuation_maybe _ = Nothing+++-- Map over the CmmGraph, replacing each label with its mapping in the+-- supplied LabelMap.+replaceLabels :: LabelMap BlockId -> CmmGraph -> CmmGraph+replaceLabels env g+ | mapNull env = g+ | otherwise = replace_eid $ mapGraphNodes1 txnode g+ where+ replace_eid g = g {g_entry = lookup (g_entry g)}+ lookup id = mapLookup id env `orElse` id++ txnode :: CmmNode e x -> CmmNode e x+ txnode (CmmBranch bid) = CmmBranch (lookup bid)+ txnode (CmmCondBranch p t f l) =+ mkCmmCondBranch (exp p) (lookup t) (lookup f) l+ txnode (CmmSwitch e ids) =+ CmmSwitch (exp e) (mapSwitchTargets lookup ids)+ txnode (CmmCall t k rg a res r) =+ CmmCall (exp t) (liftM lookup k) rg a res r+ txnode fc@CmmForeignCall{} =+ fc{ args = map exp (args fc), succ = lookup (succ fc) }+ txnode other = mapExpDeep exp other++ exp :: CmmExpr -> CmmExpr+ exp (CmmLit (CmmBlock bid)) = CmmLit (CmmBlock (lookup bid))+ exp (CmmStackSlot (Young id) i) = CmmStackSlot (Young (lookup id)) i+ exp e = e++mkCmmCondBranch :: CmmExpr -> Label -> Label -> Maybe Bool -> CmmNode O C+mkCmmCondBranch p t f l =+ if t == f then CmmBranch t else CmmCondBranch p t f l++-- Build a map from a block to its set of predecessors.+predMap :: [CmmBlock] -> LabelMap Int+predMap blocks = foldr add_preds mapEmpty blocks+ where+ add_preds block env = foldr add env (successors block)+ where add lbl env = mapInsertWith (+) lbl 1 env++-- Removing unreachable blocks+removeUnreachableBlocksProc :: CmmDecl -> CmmDecl+removeUnreachableBlocksProc proc@(CmmProc info lbl live g)+ | length used_blocks < mapSize (toBlockMap g)+ = CmmProc info' lbl live g'+ | otherwise+ = proc+ where+ g' = ofBlockList (g_entry g) used_blocks+ info' = info { info_tbls = keep_used (info_tbls info) }+ -- Remove any info_tbls for unreachable++ keep_used :: LabelMap CmmInfoTable -> LabelMap CmmInfoTable+ keep_used bs = mapFoldWithKey keep mapEmpty bs++ keep :: Label -> CmmInfoTable -> LabelMap CmmInfoTable -> LabelMap CmmInfoTable+ keep l i env | l `setMember` used_lbls = mapInsert l i env+ | otherwise = env++ used_blocks :: [CmmBlock]+ used_blocks = postorderDfs g++ used_lbls :: LabelSet+ used_lbls = foldr (setInsert . entryLabel) setEmpty used_blocks
+ cmm/CmmExpr.hs view
@@ -0,0 +1,585 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UndecidableInstances #-}++module CmmExpr+ ( CmmExpr(..), cmmExprType, cmmExprWidth, maybeInvertCmmExpr+ , CmmReg(..), cmmRegType+ , CmmLit(..), cmmLitType+ , LocalReg(..), localRegType+ , GlobalReg(..), isArgReg, globalRegType, spReg, hpReg, spLimReg, nodeReg, node, baseReg+ , VGcPtr(..)++ , DefinerOfRegs, UserOfRegs+ , foldRegsDefd, foldRegsUsed+ , foldLocalRegsDefd, foldLocalRegsUsed++ , RegSet, LocalRegSet, GlobalRegSet+ , emptyRegSet, elemRegSet, extendRegSet, deleteFromRegSet, mkRegSet+ , plusRegSet, minusRegSet, timesRegSet, sizeRegSet, nullRegSet+ , regSetToList++ , Area(..)+ , module CmmMachOp+ , module CmmType+ )+where++import BlockId+import CLabel+import CmmMachOp+import CmmType+import DynFlags+import Outputable (panic)+import Unique++import Data.Set (Set)+import Data.List+import qualified Data.Set as Set++-----------------------------------------------------------------------------+-- CmmExpr+-- An expression. Expressions have no side effects.+-----------------------------------------------------------------------------++data CmmExpr+ = CmmLit CmmLit -- Literal+ | CmmLoad !CmmExpr !CmmType -- Read memory location+ | CmmReg !CmmReg -- Contents of register+ | CmmMachOp MachOp [CmmExpr] -- Machine operation (+, -, *, etc.)+ | CmmStackSlot Area {-# UNPACK #-} !Int+ -- addressing expression of a stack slot+ -- See Note [CmmStackSlot aliasing]+ | CmmRegOff !CmmReg Int+ -- CmmRegOff reg i+ -- ** is shorthand only, meaning **+ -- CmmMachOp (MO_Add rep) [x, CmmLit (CmmInt (fromIntegral i) rep)]+ -- where rep = typeWidth (cmmRegType reg)++instance Eq CmmExpr where -- Equality ignores the types+ CmmLit l1 == CmmLit l2 = l1==l2+ CmmLoad e1 _ == CmmLoad e2 _ = e1==e2+ CmmReg r1 == CmmReg r2 = r1==r2+ CmmRegOff r1 i1 == CmmRegOff r2 i2 = r1==r2 && i1==i2+ CmmMachOp op1 es1 == CmmMachOp op2 es2 = op1==op2 && es1==es2+ CmmStackSlot a1 i1 == CmmStackSlot a2 i2 = a1==a2 && i1==i2+ _e1 == _e2 = False++data CmmReg+ = CmmLocal {-# UNPACK #-} !LocalReg+ | CmmGlobal GlobalReg+ deriving( Eq, Ord )++-- | A stack area is either the stack slot where a variable is spilled+-- or the stack space where function arguments and results are passed.+data Area+ = Old -- See Note [Old Area]+ | Young {-# UNPACK #-} !BlockId -- Invariant: must be a continuation BlockId+ -- See Note [Continuation BlockId] in CmmNode.+ deriving (Eq, Ord)++{- Note [Old Area]+~~~~~~~~~~~~~~~~~~+There is a single call area 'Old', allocated at the extreme old+end of the stack frame (ie just younger than the return address)+which holds:+ * incoming (overflow) parameters,+ * outgoing (overflow) parameter to tail calls,+ * outgoing (overflow) result values+ * the update frame (if any)++Its size is the max of all these requirements. On entry, the stack+pointer will point to the youngest incoming parameter, which is not+necessarily at the young end of the Old area.++End of note -}+++{- Note [CmmStackSlot aliasing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When do two CmmStackSlots alias?++ - T[old+N] aliases with U[young(L)+M] for all T, U, L, N and M+ - T[old+N] aliases with U[old+M] only if the areas actually overlap++Or more informally, different Areas may overlap with each other.++An alternative semantics, that we previously had, was that different+Areas do not overlap. The problem that lead to redefining the+semantics of stack areas is described below.++e.g. if we had++ x = Sp[old + 8]+ y = Sp[old + 16]++ Sp[young(L) + 8] = L+ Sp[young(L) + 16] = y+ Sp[young(L) + 24] = x+ call f() returns to L++if areas semantically do not overlap, then we might optimise this to++ Sp[young(L) + 8] = L+ Sp[young(L) + 16] = Sp[old + 8]+ Sp[young(L) + 24] = Sp[old + 16]+ call f() returns to L++and now young(L) cannot be allocated at the same place as old, and we+are doomed to use more stack.++ - old+8 conflicts with young(L)+8+ - old+16 conflicts with young(L)+16 and young(L)+8++so young(L)+8 == old+24 and we get++ Sp[-8] = L+ Sp[-16] = Sp[8]+ Sp[-24] = Sp[0]+ Sp -= 24+ call f() returns to L++However, if areas are defined to be "possibly overlapping" in the+semantics, then we cannot commute any loads/stores of old with+young(L), and we will be able to re-use both old+8 and old+16 for+young(L).++ x = Sp[8]+ y = Sp[0]++ Sp[8] = L+ Sp[0] = y+ Sp[-8] = x+ Sp = Sp - 8+ call f() returns to L++Now, the assignments of y go away,++ x = Sp[8]+ Sp[8] = L+ Sp[-8] = x+ Sp = Sp - 8+ call f() returns to L+-}++data CmmLit+ = CmmInt !Integer Width+ -- Interpretation: the 2's complement representation of the value+ -- is truncated to the specified size. This is easier than trying+ -- to keep the value within range, because we don't know whether+ -- it will be used as a signed or unsigned value (the CmmType doesn't+ -- distinguish between signed & unsigned).+ | CmmFloat Rational Width+ | CmmVec [CmmLit] -- Vector literal+ | CmmLabel CLabel -- Address of label+ | CmmLabelOff CLabel Int -- Address of label + byte offset++ -- Due to limitations in the C backend, the following+ -- MUST ONLY be used inside the info table indicated by label2+ -- (label2 must be the info label), and label1 must be an+ -- SRT, a slow entrypoint or a large bitmap (see the Mangler)+ -- Don't use it at all unless tablesNextToCode.+ -- It is also used inside the NCG during when generating+ -- position-independent code.+ | CmmLabelDiffOff CLabel CLabel Int -- label1 - label2 + offset++ | CmmBlock {-# UNPACK #-} !BlockId -- Code label+ -- Invariant: must be a continuation BlockId+ -- See Note [Continuation BlockId] in CmmNode.++ | CmmHighStackMark -- A late-bound constant that stands for the max+ -- #bytes of stack space used during a procedure.+ -- During the stack-layout pass, CmmHighStackMark+ -- is replaced by a CmmInt for the actual number+ -- of bytes used+ deriving Eq++cmmExprType :: DynFlags -> CmmExpr -> CmmType+cmmExprType dflags (CmmLit lit) = cmmLitType dflags lit+cmmExprType _ (CmmLoad _ rep) = rep+cmmExprType dflags (CmmReg reg) = cmmRegType dflags reg+cmmExprType dflags (CmmMachOp op args) = machOpResultType dflags op (map (cmmExprType dflags) args)+cmmExprType dflags (CmmRegOff reg _) = cmmRegType dflags reg+cmmExprType dflags (CmmStackSlot _ _) = bWord dflags -- an address+-- Careful though: what is stored at the stack slot may be bigger than+-- an address++cmmLitType :: DynFlags -> CmmLit -> CmmType+cmmLitType _ (CmmInt _ width) = cmmBits width+cmmLitType _ (CmmFloat _ width) = cmmFloat width+cmmLitType _ (CmmVec []) = panic "cmmLitType: CmmVec []"+cmmLitType cflags (CmmVec (l:ls)) = let ty = cmmLitType cflags l+ in if all (`cmmEqType` ty) (map (cmmLitType cflags) ls)+ then cmmVec (1+length ls) ty+ else panic "cmmLitType: CmmVec"+cmmLitType dflags (CmmLabel lbl) = cmmLabelType dflags lbl+cmmLitType dflags (CmmLabelOff lbl _) = cmmLabelType dflags lbl+cmmLitType dflags (CmmLabelDiffOff {}) = bWord dflags+cmmLitType dflags (CmmBlock _) = bWord dflags+cmmLitType dflags (CmmHighStackMark) = bWord dflags++cmmLabelType :: DynFlags -> CLabel -> CmmType+cmmLabelType dflags lbl+ | isGcPtrLabel lbl = gcWord dflags+ | otherwise = bWord dflags++cmmExprWidth :: DynFlags -> CmmExpr -> Width+cmmExprWidth dflags e = typeWidth (cmmExprType dflags e)++--------+--- Negation for conditional branches++maybeInvertCmmExpr :: CmmExpr -> Maybe CmmExpr+maybeInvertCmmExpr (CmmMachOp op args) = do op' <- maybeInvertComparison op+ return (CmmMachOp op' args)+maybeInvertCmmExpr _ = Nothing++-----------------------------------------------------------------------------+-- Local registers+-----------------------------------------------------------------------------++data LocalReg+ = LocalReg {-# UNPACK #-} !Unique CmmType+ -- ^ Parameters:+ -- 1. Identifier+ -- 2. Type++instance Eq LocalReg where+ (LocalReg u1 _) == (LocalReg u2 _) = u1 == u2++-- This is non-deterministic but we do not currently support deterministic+-- code-generation. See Note [Unique Determinism and code generation]+-- See Note [No Ord for Unique]+instance Ord LocalReg where+ compare (LocalReg u1 _) (LocalReg u2 _) = nonDetCmpUnique u1 u2++instance Uniquable LocalReg where+ getUnique (LocalReg uniq _) = uniq++cmmRegType :: DynFlags -> CmmReg -> CmmType+cmmRegType _ (CmmLocal reg) = localRegType reg+cmmRegType dflags (CmmGlobal reg) = globalRegType dflags reg++localRegType :: LocalReg -> CmmType+localRegType (LocalReg _ rep) = rep++-----------------------------------------------------------------------------+-- Register-use information for expressions and other types+-----------------------------------------------------------------------------++-- | Sets of registers++-- These are used for dataflow facts, and a common operation is taking+-- the union of two RegSets and then asking whether the union is the+-- same as one of the inputs. UniqSet isn't good here, because+-- sizeUniqSet is O(n) whereas Set.size is O(1), so we use ordinary+-- Sets.++type RegSet r = Set r+type LocalRegSet = RegSet LocalReg+type GlobalRegSet = RegSet GlobalReg++emptyRegSet :: RegSet r+nullRegSet :: RegSet r -> Bool+elemRegSet :: Ord r => r -> RegSet r -> Bool+extendRegSet :: Ord r => RegSet r -> r -> RegSet r+deleteFromRegSet :: Ord r => RegSet r -> r -> RegSet r+mkRegSet :: Ord r => [r] -> RegSet r+minusRegSet, plusRegSet, timesRegSet :: Ord r => RegSet r -> RegSet r -> RegSet r+sizeRegSet :: RegSet r -> Int+regSetToList :: RegSet r -> [r]++emptyRegSet = Set.empty+nullRegSet = Set.null+elemRegSet = Set.member+extendRegSet = flip Set.insert+deleteFromRegSet = flip Set.delete+mkRegSet = Set.fromList+minusRegSet = Set.difference+plusRegSet = Set.union+timesRegSet = Set.intersection+sizeRegSet = Set.size+regSetToList = Set.toList++class Ord r => UserOfRegs r a where+ foldRegsUsed :: DynFlags -> (b -> r -> b) -> b -> a -> b++foldLocalRegsUsed :: UserOfRegs LocalReg a+ => DynFlags -> (b -> LocalReg -> b) -> b -> a -> b+foldLocalRegsUsed = foldRegsUsed++class Ord r => DefinerOfRegs r a where+ foldRegsDefd :: DynFlags -> (b -> r -> b) -> b -> a -> b++foldLocalRegsDefd :: DefinerOfRegs LocalReg a+ => DynFlags -> (b -> LocalReg -> b) -> b -> a -> b+foldLocalRegsDefd = foldRegsDefd++instance UserOfRegs LocalReg CmmReg where+ foldRegsUsed _ f z (CmmLocal reg) = f z reg+ foldRegsUsed _ _ z (CmmGlobal _) = z++instance DefinerOfRegs LocalReg CmmReg where+ foldRegsDefd _ f z (CmmLocal reg) = f z reg+ foldRegsDefd _ _ z (CmmGlobal _) = z++instance UserOfRegs GlobalReg CmmReg where+ foldRegsUsed _ _ z (CmmLocal _) = z+ foldRegsUsed _ f z (CmmGlobal reg) = f z reg++instance DefinerOfRegs GlobalReg CmmReg where+ foldRegsDefd _ _ z (CmmLocal _) = z+ foldRegsDefd _ f z (CmmGlobal reg) = f z reg++instance Ord r => UserOfRegs r r where+ foldRegsUsed _ f z r = f z r++instance Ord r => DefinerOfRegs r r where+ foldRegsDefd _ f z r = f z r++instance (Ord r, UserOfRegs r CmmReg) => UserOfRegs r CmmExpr where+ -- The (Ord r) in the context is necessary here+ -- See Note [Recursive superclasses] in TcInstDcls+ foldRegsUsed dflags f !z e = expr z e+ where expr z (CmmLit _) = z+ expr z (CmmLoad addr _) = foldRegsUsed dflags f z addr+ expr z (CmmReg r) = foldRegsUsed dflags f z r+ expr z (CmmMachOp _ exprs) = foldRegsUsed dflags f z exprs+ expr z (CmmRegOff r _) = foldRegsUsed dflags f z r+ expr z (CmmStackSlot _ _) = z++instance UserOfRegs r a => UserOfRegs r [a] where+ foldRegsUsed dflags f set as = foldl' (foldRegsUsed dflags f) set as+ {-# INLINABLE foldRegsUsed #-}++instance DefinerOfRegs r a => DefinerOfRegs r [a] where+ foldRegsDefd dflags f set as = foldl' (foldRegsDefd dflags f) set as+ {-# INLINABLE foldRegsDefd #-}++-----------------------------------------------------------------------------+-- Global STG registers+-----------------------------------------------------------------------------++data VGcPtr = VGcPtr | VNonGcPtr deriving( Eq, Show )++-----------------------------------------------------------------------------+-- Global STG registers+-----------------------------------------------------------------------------+{-+Note [Overlapping global registers]++The backend might not faithfully implement the abstraction of the STG+machine with independent registers for different values of type+GlobalReg. Specifically, certain pairs of registers (r1, r2) may+overlap in the sense that a store to r1 invalidates the value in r2,+and vice versa.++Currently this occurs only on the x86_64 architecture where FloatReg n+and DoubleReg n are assigned the same microarchitectural register, in+order to allow functions to receive more Float# or Double# arguments+in registers (as opposed to on the stack).++There are no specific rules about which registers might overlap with+which other registers, but presumably it's safe to assume that nothing+will overlap with special registers like Sp or BaseReg.++Use CmmUtils.regsOverlap to determine whether two GlobalRegs overlap+on a particular platform. The instance Eq GlobalReg is syntactic+equality of STG registers and does not take overlap into+account. However it is still used in UserOfRegs/DefinerOfRegs and+there are likely still bugs there, beware!+-}++data GlobalReg+ -- Argument and return registers+ = VanillaReg -- pointers, unboxed ints and chars+ {-# UNPACK #-} !Int -- its number+ VGcPtr++ | FloatReg -- single-precision floating-point registers+ {-# UNPACK #-} !Int -- its number++ | DoubleReg -- double-precision floating-point registers+ {-# UNPACK #-} !Int -- its number++ | LongReg -- long int registers (64-bit, really)+ {-# UNPACK #-} !Int -- its number++ | XmmReg -- 128-bit SIMD vector register+ {-# UNPACK #-} !Int -- its number++ | YmmReg -- 256-bit SIMD vector register+ {-# UNPACK #-} !Int -- its number++ | ZmmReg -- 512-bit SIMD vector register+ {-# UNPACK #-} !Int -- its number++ -- STG registers+ | Sp -- Stack ptr; points to last occupied stack location.+ | SpLim -- Stack limit+ | Hp -- Heap ptr; points to last occupied heap location.+ | HpLim -- Heap limit register+ | CCCS -- Current cost-centre stack+ | CurrentTSO -- pointer to current thread's TSO+ | CurrentNursery -- pointer to allocation area+ | HpAlloc -- allocation count for heap check failure++ -- We keep the address of some commonly-called+ -- functions in the register table, to keep code+ -- size down:+ | EagerBlackholeInfo -- stg_EAGER_BLACKHOLE_info+ | GCEnter1 -- stg_gc_enter_1+ | GCFun -- stg_gc_fun++ -- Base offset for the register table, used for accessing registers+ -- which do not have real registers assigned to them. This register+ -- will only appear after we have expanded GlobalReg into memory accesses+ -- (where necessary) in the native code generator.+ | BaseReg++ -- The register used by the platform for the C stack pointer. This is+ -- a break in the STG abstraction used exclusively to setup stack unwinding+ -- information.+ | MachSp++ -- The is a dummy register used to indicate to the stack unwinder where+ -- a routine would return to.+ | UnwindReturnReg++ -- Base Register for PIC (position-independent code) calculations+ -- Only used inside the native code generator. It's exact meaning differs+ -- from platform to platform (see module PositionIndependentCode).+ | PicBaseReg++ deriving( Show )++instance Eq GlobalReg where+ VanillaReg i _ == VanillaReg j _ = i==j -- Ignore type when seeking clashes+ FloatReg i == FloatReg j = i==j+ DoubleReg i == DoubleReg j = i==j+ LongReg i == LongReg j = i==j+ XmmReg i == XmmReg j = i==j+ YmmReg i == YmmReg j = i==j+ ZmmReg i == ZmmReg j = i==j+ Sp == Sp = True+ SpLim == SpLim = True+ Hp == Hp = True+ HpLim == HpLim = True+ CCCS == CCCS = True+ CurrentTSO == CurrentTSO = True+ CurrentNursery == CurrentNursery = True+ HpAlloc == HpAlloc = True+ EagerBlackholeInfo == EagerBlackholeInfo = True+ GCEnter1 == GCEnter1 = True+ GCFun == GCFun = True+ BaseReg == BaseReg = True+ MachSp == MachSp = True+ UnwindReturnReg == UnwindReturnReg = True+ PicBaseReg == PicBaseReg = True+ _r1 == _r2 = False++instance Ord GlobalReg where+ compare (VanillaReg i _) (VanillaReg j _) = compare i j+ -- Ignore type when seeking clashes+ compare (FloatReg i) (FloatReg j) = compare i j+ compare (DoubleReg i) (DoubleReg j) = compare i j+ compare (LongReg i) (LongReg j) = compare i j+ compare (XmmReg i) (XmmReg j) = compare i j+ compare (YmmReg i) (YmmReg j) = compare i j+ compare (ZmmReg i) (ZmmReg j) = compare i j+ compare Sp Sp = EQ+ compare SpLim SpLim = EQ+ compare Hp Hp = EQ+ compare HpLim HpLim = EQ+ compare CCCS CCCS = EQ+ compare CurrentTSO CurrentTSO = EQ+ compare CurrentNursery CurrentNursery = EQ+ compare HpAlloc HpAlloc = EQ+ compare EagerBlackholeInfo EagerBlackholeInfo = EQ+ compare GCEnter1 GCEnter1 = EQ+ compare GCFun GCFun = EQ+ compare BaseReg BaseReg = EQ+ compare MachSp MachSp = EQ+ compare UnwindReturnReg UnwindReturnReg = EQ+ compare PicBaseReg PicBaseReg = EQ+ compare (VanillaReg _ _) _ = LT+ compare _ (VanillaReg _ _) = GT+ compare (FloatReg _) _ = LT+ compare _ (FloatReg _) = GT+ compare (DoubleReg _) _ = LT+ compare _ (DoubleReg _) = GT+ compare (LongReg _) _ = LT+ compare _ (LongReg _) = GT+ compare (XmmReg _) _ = LT+ compare _ (XmmReg _) = GT+ compare (YmmReg _) _ = LT+ compare _ (YmmReg _) = GT+ compare (ZmmReg _) _ = LT+ compare _ (ZmmReg _) = GT+ compare Sp _ = LT+ compare _ Sp = GT+ compare SpLim _ = LT+ compare _ SpLim = GT+ compare Hp _ = LT+ compare _ Hp = GT+ compare HpLim _ = LT+ compare _ HpLim = GT+ compare CCCS _ = LT+ compare _ CCCS = GT+ compare CurrentTSO _ = LT+ compare _ CurrentTSO = GT+ compare CurrentNursery _ = LT+ compare _ CurrentNursery = GT+ compare HpAlloc _ = LT+ compare _ HpAlloc = GT+ compare GCEnter1 _ = LT+ compare _ GCEnter1 = GT+ compare GCFun _ = LT+ compare _ GCFun = GT+ compare BaseReg _ = LT+ compare _ BaseReg = GT+ compare MachSp _ = LT+ compare _ MachSp = GT+ compare UnwindReturnReg _ = LT+ compare _ UnwindReturnReg = GT+ compare EagerBlackholeInfo _ = LT+ compare _ EagerBlackholeInfo = GT++-- convenient aliases+baseReg, spReg, hpReg, spLimReg, nodeReg :: CmmReg+baseReg = CmmGlobal BaseReg+spReg = CmmGlobal Sp+hpReg = CmmGlobal Hp+spLimReg = CmmGlobal SpLim+nodeReg = CmmGlobal node++node :: GlobalReg+node = VanillaReg 1 VGcPtr++globalRegType :: DynFlags -> GlobalReg -> CmmType+globalRegType dflags (VanillaReg _ VGcPtr) = gcWord dflags+globalRegType dflags (VanillaReg _ VNonGcPtr) = bWord dflags+globalRegType _ (FloatReg _) = cmmFloat W32+globalRegType _ (DoubleReg _) = cmmFloat W64+globalRegType _ (LongReg _) = cmmBits W64+globalRegType _ (XmmReg _) = cmmVec 4 (cmmBits W32)+globalRegType _ (YmmReg _) = cmmVec 8 (cmmBits W32)+globalRegType _ (ZmmReg _) = cmmVec 16 (cmmBits W32)++globalRegType dflags Hp = gcWord dflags+ -- The initialiser for all+ -- dynamically allocated closures+globalRegType dflags _ = bWord dflags++isArgReg :: GlobalReg -> Bool+isArgReg (VanillaReg {}) = True+isArgReg (FloatReg {}) = True+isArgReg (DoubleReg {}) = True+isArgReg (LongReg {}) = True+isArgReg (XmmReg {}) = True+isArgReg (YmmReg {}) = True+isArgReg (ZmmReg {}) = True+isArgReg _ = False
+ cmm/CmmImplementSwitchPlans.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE GADTs #-}+module CmmImplementSwitchPlans+ ( cmmImplementSwitchPlans+ )+where++import Hoopl+import BlockId+import Cmm+import CmmUtils+import CmmSwitch+import UniqSupply+import DynFlags++--+-- This module replaces Switch statements as generated by the Stg -> Cmm+-- transformation, which might be huge and sparse and hence unsuitable for+-- assembly code, by proper constructs (if-then-else trees, dense jump tables).+--+-- The actual, abstract strategy is determined by createSwitchPlan in+-- CmmSwitch and returned as a SwitchPlan; here is just the implementation in+-- terms of Cmm code. See Note [Cmm Switches, the general plan] in CmmSwitch.+--+-- This division into different modules is both to clearly separte concerns,+-- but also because createSwitchPlan needs access to the constructors of+-- SwitchTargets, a data type exported abstractly by CmmSwitch.+--++-- | Traverses the 'CmmGraph', making sure that 'CmmSwitch' are suitable for+-- code generation.+cmmImplementSwitchPlans :: DynFlags -> CmmGraph -> UniqSM CmmGraph+cmmImplementSwitchPlans dflags g+ | targetSupportsSwitch (hscTarget dflags) = return g+ | otherwise = do+ blocks' <- concat `fmap` mapM (visitSwitches dflags) (toBlockList g)+ return $ ofBlockList (g_entry g) blocks'++visitSwitches :: DynFlags -> CmmBlock -> UniqSM [CmmBlock]+visitSwitches dflags block+ | (entry@(CmmEntry _ scope), middle, CmmSwitch expr ids) <- blockSplit block+ = do+ let plan = createSwitchPlan ids++ (newTail, newBlocks) <- implementSwitchPlan dflags scope expr plan++ let block' = entry `blockJoinHead` middle `blockAppend` newTail++ return $ block' : newBlocks++ | otherwise+ = return [block]+++-- Implementing a switch plan (returning a tail block)+implementSwitchPlan :: DynFlags -> CmmTickScope -> CmmExpr -> SwitchPlan -> UniqSM (Block CmmNode O C, [CmmBlock])+implementSwitchPlan dflags scope expr = go+ where+ go (Unconditionally l)+ = return (emptyBlock `blockJoinTail` CmmBranch l, [])+ go (JumpTable ids)+ = return (emptyBlock `blockJoinTail` CmmSwitch expr ids, [])+ go (IfLT signed i ids1 ids2)+ = do+ (bid1, newBlocks1) <- go' ids1+ (bid2, newBlocks2) <- go' ids2++ let lt | signed = cmmSLtWord+ | otherwise = cmmULtWord+ scrut = lt dflags expr $ CmmLit $ mkWordCLit dflags i+ lastNode = CmmCondBranch scrut bid1 bid2 Nothing+ lastBlock = emptyBlock `blockJoinTail` lastNode+ return (lastBlock, newBlocks1++newBlocks2)+ go (IfEqual i l ids2)+ = do+ (bid2, newBlocks2) <- go' ids2++ let scrut = cmmNeWord dflags expr $ CmmLit $ mkWordCLit dflags i+ lastNode = CmmCondBranch scrut bid2 l Nothing+ lastBlock = emptyBlock `blockJoinTail` lastNode+ return (lastBlock, newBlocks2)++ -- Same but returning a label to branch to+ go' (Unconditionally l)+ = return (l, [])+ go' p+ = do+ bid <- mkBlockId `fmap` getUniqueM+ (last, newBlocks) <- go p+ let block = CmmEntry bid scope `blockJoinHead` last+ return (bid, block: newBlocks)
+ cmm/CmmInfo.hs view
@@ -0,0 +1,557 @@+{-# LANGUAGE CPP #-}+module CmmInfo (+ mkEmptyContInfoTable,+ cmmToRawCmm,+ mkInfoTable,+ srtEscape,++ -- info table accessors+ closureInfoPtr,+ entryCode,+ getConstrTag,+ cmmGetClosureType,+ infoTable,+ infoTableConstrTag,+ infoTableSrtBitmap,+ infoTableClosureType,+ infoTablePtrs,+ infoTableNonPtrs,+ funInfoTable,+ funInfoArity,++ -- info table sizes and offsets+ stdInfoTableSizeW,+ fixedInfoTableSizeW,+ profInfoTableSizeW,+ maxStdInfoTableSizeW,+ maxRetInfoTableSizeW,+ stdInfoTableSizeB,+ conInfoTableSizeB,+ stdSrtBitmapOffset,+ stdClosureTypeOffset,+ stdPtrsOffset, stdNonPtrsOffset,+) where++#include "HsVersions.h"++import Cmm+import CmmUtils+import CLabel+import SMRep+import Bitmap+import Stream (Stream)+import qualified Stream+import Hoopl++import Maybes+import DynFlags+import Panic+import UniqSupply+import MonadUtils+import Util+import Outputable++import Data.Bits+import Data.Word++-- When we split at proc points, we need an empty info table.+mkEmptyContInfoTable :: CLabel -> CmmInfoTable+mkEmptyContInfoTable info_lbl+ = CmmInfoTable { cit_lbl = info_lbl+ , cit_rep = mkStackRep []+ , cit_prof = NoProfilingInfo+ , cit_srt = NoC_SRT }++cmmToRawCmm :: DynFlags -> Stream IO CmmGroup ()+ -> IO (Stream IO RawCmmGroup ())+cmmToRawCmm dflags cmms+ = do { uniqs <- mkSplitUniqSupply 'i'+ ; let do_one uniqs cmm = do+ case initUs uniqs $ concatMapM (mkInfoTable dflags) cmm of+ (b,uniqs') -> return (uniqs',b)+ -- NB. strictness fixes a space leak. DO NOT REMOVE.+ ; return (Stream.mapAccumL do_one uniqs cmms >> return ())+ }++-- Make a concrete info table, represented as a list of CmmStatic+-- (it can't be simply a list of Word, because the SRT field is+-- represented by a label+offset expression).+--+-- With tablesNextToCode, the layout is+-- <reversed variable part>+-- <normal forward StgInfoTable, but without+-- an entry point at the front>+-- <code>+--+-- Without tablesNextToCode, the layout of an info table is+-- <entry label>+-- <normal forward rest of StgInfoTable>+-- <forward variable part>+--+-- See includes/rts/storage/InfoTables.h+--+-- For return-points these are as follows+--+-- Tables next to code:+--+-- <srt slot>+-- <standard info table>+-- ret-addr --> <entry code (if any)>+--+-- Not tables-next-to-code:+--+-- ret-addr --> <ptr to entry code>+-- <standard info table>+-- <srt slot>+--+-- * The SRT slot is only there if there is SRT info to record++mkInfoTable :: DynFlags -> CmmDecl -> UniqSM [RawCmmDecl]+mkInfoTable _ (CmmData sec dat)+ = return [CmmData sec dat]++mkInfoTable dflags proc@(CmmProc infos entry_lbl live blocks)+ --+ -- in the non-tables-next-to-code case, procs can have at most a+ -- single info table associated with the entry label of the proc.+ --+ | not (tablesNextToCode dflags)+ = case topInfoTable proc of -- must be at most one+ -- no info table+ Nothing ->+ return [CmmProc mapEmpty entry_lbl live blocks]++ Just info@CmmInfoTable { cit_lbl = info_lbl } -> do+ (top_decls, (std_info, extra_bits)) <-+ mkInfoTableContents dflags info Nothing+ let+ rel_std_info = map (makeRelativeRefTo dflags info_lbl) std_info+ rel_extra_bits = map (makeRelativeRefTo dflags info_lbl) extra_bits+ --+ -- Separately emit info table (with the function entry+ -- point as first entry) and the entry code+ --+ return (top_decls +++ [CmmProc mapEmpty entry_lbl live blocks,+ mkDataLits (Section Data info_lbl) info_lbl+ (CmmLabel entry_lbl : rel_std_info ++ rel_extra_bits)])++ --+ -- With tables-next-to-code, we can have many info tables,+ -- associated with some of the BlockIds of the proc. For each info+ -- table we need to turn it into CmmStatics, and collect any new+ -- CmmDecls that arise from doing so.+ --+ | otherwise+ = do+ (top_declss, raw_infos) <-+ unzip `fmap` mapM do_one_info (mapToList (info_tbls infos))+ return (concat top_declss +++ [CmmProc (mapFromList raw_infos) entry_lbl live blocks])++ where+ do_one_info (lbl,itbl) = do+ (top_decls, (std_info, extra_bits)) <-+ mkInfoTableContents dflags itbl Nothing+ let+ info_lbl = cit_lbl itbl+ rel_std_info = map (makeRelativeRefTo dflags info_lbl) std_info+ rel_extra_bits = map (makeRelativeRefTo dflags info_lbl) extra_bits+ --+ return (top_decls, (lbl, Statics info_lbl $ map CmmStaticLit $+ reverse rel_extra_bits ++ rel_std_info))++-----------------------------------------------------+type InfoTableContents = ( [CmmLit] -- The standard part+ , [CmmLit] ) -- The "extra bits"+-- These Lits have *not* had mkRelativeTo applied to them++mkInfoTableContents :: DynFlags+ -> CmmInfoTable+ -> Maybe Int -- Override default RTS type tag?+ -> UniqSM ([RawCmmDecl], -- Auxiliary top decls+ InfoTableContents) -- Info tbl + extra bits++mkInfoTableContents dflags+ info@(CmmInfoTable { cit_lbl = info_lbl+ , cit_rep = smrep+ , cit_prof = prof+ , cit_srt = srt })+ mb_rts_tag+ | RTSRep rts_tag rep <- smrep+ = mkInfoTableContents dflags info{cit_rep = rep} (Just rts_tag)+ -- Completely override the rts_tag that mkInfoTableContents would+ -- otherwise compute, with the rts_tag stored in the RTSRep+ -- (which in turn came from a handwritten .cmm file)++ | StackRep frame <- smrep+ = do { (prof_lits, prof_data) <- mkProfLits dflags prof+ ; let (srt_label, srt_bitmap) = mkSRTLit dflags srt+ ; (liveness_lit, liveness_data) <- mkLivenessBits dflags frame+ ; let+ std_info = mkStdInfoTable dflags prof_lits rts_tag srt_bitmap liveness_lit+ rts_tag | Just tag <- mb_rts_tag = tag+ | null liveness_data = rET_SMALL -- Fits in extra_bits+ | otherwise = rET_BIG -- Does not; extra_bits is+ -- a label+ ; return (prof_data ++ liveness_data, (std_info, srt_label)) }++ | HeapRep _ ptrs nonptrs closure_type <- smrep+ = do { let layout = packIntsCLit dflags ptrs nonptrs+ ; (prof_lits, prof_data) <- mkProfLits dflags prof+ ; let (srt_label, srt_bitmap) = mkSRTLit dflags srt+ ; (mb_srt_field, mb_layout, extra_bits, ct_data)+ <- mk_pieces closure_type srt_label+ ; let std_info = mkStdInfoTable dflags prof_lits+ (mb_rts_tag `orElse` rtsClosureType smrep)+ (mb_srt_field `orElse` srt_bitmap)+ (mb_layout `orElse` layout)+ ; return (prof_data ++ ct_data, (std_info, extra_bits)) }+ where+ mk_pieces :: ClosureTypeInfo -> [CmmLit]+ -> UniqSM ( Maybe StgHalfWord -- Override the SRT field with this+ , Maybe CmmLit -- Override the layout field with this+ , [CmmLit] -- "Extra bits" for info table+ , [RawCmmDecl]) -- Auxiliary data decls+ mk_pieces (Constr con_tag con_descr) _no_srt -- A data constructor+ = do { (descr_lit, decl) <- newStringLit con_descr+ ; return ( Just (toStgHalfWord dflags (fromIntegral con_tag))+ , Nothing, [descr_lit], [decl]) }++ mk_pieces Thunk srt_label+ = return (Nothing, Nothing, srt_label, [])++ mk_pieces (ThunkSelector offset) _no_srt+ = return (Just (toStgHalfWord dflags 0), Just (mkWordCLit dflags (fromIntegral offset)), [], [])+ -- Layout known (one free var); we use the layout field for offset++ mk_pieces (Fun arity (ArgSpec fun_type)) srt_label+ = do { let extra_bits = packIntsCLit dflags fun_type arity : srt_label+ ; return (Nothing, Nothing, extra_bits, []) }++ mk_pieces (Fun arity (ArgGen arg_bits)) srt_label+ = do { (liveness_lit, liveness_data) <- mkLivenessBits dflags arg_bits+ ; let fun_type | null liveness_data = aRG_GEN+ | otherwise = aRG_GEN_BIG+ extra_bits = [ packIntsCLit dflags fun_type arity+ , srt_lit, liveness_lit, slow_entry ]+ ; return (Nothing, Nothing, extra_bits, liveness_data) }+ where+ slow_entry = CmmLabel (toSlowEntryLbl info_lbl)+ srt_lit = case srt_label of+ [] -> mkIntCLit dflags 0+ (lit:_rest) -> ASSERT( null _rest ) lit++ mk_pieces other _ = pprPanic "mk_pieces" (ppr other)++mkInfoTableContents _ _ _ = panic "mkInfoTableContents" -- NonInfoTable dealt with earlier++packIntsCLit :: DynFlags -> Int -> Int -> CmmLit+packIntsCLit dflags a b = packHalfWordsCLit dflags+ (toStgHalfWord dflags (fromIntegral a))+ (toStgHalfWord dflags (fromIntegral b))+++mkSRTLit :: DynFlags+ -> C_SRT+ -> ([CmmLit], -- srt_label, if any+ StgHalfWord) -- srt_bitmap+mkSRTLit dflags NoC_SRT = ([], toStgHalfWord dflags 0)+mkSRTLit dflags (C_SRT lbl off bitmap) = ([cmmLabelOffW dflags lbl off], bitmap)+++-------------------------------------------------------------------------+--+-- Lay out the info table and handle relative offsets+--+-------------------------------------------------------------------------++-- This function takes+-- * the standard info table portion (StgInfoTable)+-- * the "extra bits" (StgFunInfoExtraRev etc.)+-- * the entry label+-- * the code+-- and lays them out in memory, producing a list of RawCmmDecl++-------------------------------------------------------------------------+--+-- Position independent code+--+-------------------------------------------------------------------------+-- In order to support position independent code, we mustn't put absolute+-- references into read-only space. Info tables in the tablesNextToCode+-- case must be in .text, which is read-only, so we doctor the CmmLits+-- to use relative offsets instead.++-- Note that this is done even when the -fPIC flag is not specified,+-- as we want to keep binary compatibility between PIC and non-PIC.++makeRelativeRefTo :: DynFlags -> CLabel -> CmmLit -> CmmLit++makeRelativeRefTo dflags info_lbl (CmmLabel lbl)+ | tablesNextToCode dflags+ = CmmLabelDiffOff lbl info_lbl 0+makeRelativeRefTo dflags info_lbl (CmmLabelOff lbl off)+ | tablesNextToCode dflags+ = CmmLabelDiffOff lbl info_lbl off+makeRelativeRefTo _ _ lit = lit+++-------------------------------------------------------------------------+--+-- Build a liveness mask for the stack layout+--+-------------------------------------------------------------------------++-- There are four kinds of things on the stack:+--+-- - pointer variables (bound in the environment)+-- - non-pointer variables (bound in the environment)+-- - free slots (recorded in the stack free list)+-- - non-pointer data slots (recorded in the stack free list)+--+-- The first two are represented with a 'Just' of a 'LocalReg'.+-- The last two with one or more 'Nothing' constructors.+-- Each 'Nothing' represents one used word.+--+-- The head of the stack layout is the top of the stack and+-- the least-significant bit.++mkLivenessBits :: DynFlags -> Liveness -> UniqSM (CmmLit, [RawCmmDecl])+ -- ^ Returns:+ -- 1. The bitmap (literal value or label)+ -- 2. Large bitmap CmmData if needed++mkLivenessBits dflags liveness+ | n_bits > mAX_SMALL_BITMAP_SIZE dflags -- does not fit in one word+ = do { uniq <- getUniqueM+ ; let bitmap_lbl = mkBitmapLabel uniq+ ; return (CmmLabel bitmap_lbl,+ [mkRODataLits bitmap_lbl lits]) }++ | otherwise -- Fits in one word+ = return (mkStgWordCLit dflags bitmap_word, [])+ where+ n_bits = length liveness++ bitmap :: Bitmap+ bitmap = mkBitmap dflags liveness++ small_bitmap = case bitmap of+ [] -> toStgWord dflags 0+ [b] -> b+ _ -> panic "mkLiveness"+ bitmap_word = toStgWord dflags (fromIntegral n_bits)+ .|. (small_bitmap `shiftL` bITMAP_BITS_SHIFT dflags)++ lits = mkWordCLit dflags (fromIntegral n_bits)+ : map (mkStgWordCLit dflags) bitmap+ -- The first word is the size. The structure must match+ -- StgLargeBitmap in includes/rts/storage/InfoTable.h++-------------------------------------------------------------------------+--+-- Generating a standard info table+--+-------------------------------------------------------------------------++-- The standard bits of an info table. This part of the info table+-- corresponds to the StgInfoTable type defined in+-- includes/rts/storage/InfoTables.h.+--+-- Its shape varies with ticky/profiling/tables next to code etc+-- so we can't use constant offsets from Constants++mkStdInfoTable+ :: DynFlags+ -> (CmmLit,CmmLit) -- Closure type descr and closure descr (profiling)+ -> Int -- Closure RTS tag+ -> StgHalfWord -- SRT length+ -> CmmLit -- layout field+ -> [CmmLit]++mkStdInfoTable dflags (type_descr, closure_descr) cl_type srt_len layout_lit+ = -- Parallel revertible-black hole field+ prof_info+ -- Ticky info (none at present)+ -- Debug info (none at present)+ ++ [layout_lit, type_lit]++ where+ prof_info+ | gopt Opt_SccProfilingOn dflags = [type_descr, closure_descr]+ | otherwise = []++ type_lit = packHalfWordsCLit dflags (toStgHalfWord dflags (fromIntegral cl_type)) srt_len++-------------------------------------------------------------------------+--+-- Making string literals+--+-------------------------------------------------------------------------++mkProfLits :: DynFlags -> ProfilingInfo -> UniqSM ((CmmLit,CmmLit), [RawCmmDecl])+mkProfLits dflags NoProfilingInfo = return ((zeroCLit dflags, zeroCLit dflags), [])+mkProfLits _ (ProfilingInfo td cd)+ = do { (td_lit, td_decl) <- newStringLit td+ ; (cd_lit, cd_decl) <- newStringLit cd+ ; return ((td_lit,cd_lit), [td_decl,cd_decl]) }++newStringLit :: [Word8] -> UniqSM (CmmLit, GenCmmDecl CmmStatics info stmt)+newStringLit bytes+ = do { uniq <- getUniqueM+ ; return (mkByteStringCLit (mkStringLitLabel uniq) bytes) }+++-- Misc utils++-- | Value of the srt field of an info table when using an StgLargeSRT+srtEscape :: DynFlags -> StgHalfWord+srtEscape dflags = toStgHalfWord dflags (-1)++-------------------------------------------------------------------------+--+-- Accessing fields of an info table+--+-------------------------------------------------------------------------++closureInfoPtr :: DynFlags -> CmmExpr -> CmmExpr+-- Takes a closure pointer and returns the info table pointer+closureInfoPtr dflags e = CmmLoad e (bWord dflags)++entryCode :: DynFlags -> CmmExpr -> CmmExpr+-- Takes an info pointer (the first word of a closure)+-- and returns its entry code+entryCode dflags e+ | tablesNextToCode dflags = e+ | otherwise = CmmLoad e (bWord dflags)++getConstrTag :: DynFlags -> CmmExpr -> CmmExpr+-- Takes a closure pointer, and return the *zero-indexed*+-- constructor tag obtained from the info table+-- This lives in the SRT field of the info table+-- (constructors don't need SRTs).+getConstrTag dflags closure_ptr+ = CmmMachOp (MO_UU_Conv (halfWordWidth dflags) (wordWidth dflags)) [infoTableConstrTag dflags info_table]+ where+ info_table = infoTable dflags (closureInfoPtr dflags closure_ptr)++cmmGetClosureType :: DynFlags -> CmmExpr -> CmmExpr+-- Takes a closure pointer, and return the closure type+-- obtained from the info table+cmmGetClosureType dflags closure_ptr+ = CmmMachOp (MO_UU_Conv (halfWordWidth dflags) (wordWidth dflags)) [infoTableClosureType dflags info_table]+ where+ info_table = infoTable dflags (closureInfoPtr dflags closure_ptr)++infoTable :: DynFlags -> CmmExpr -> CmmExpr+-- Takes an info pointer (the first word of a closure)+-- and returns a pointer to the first word of the standard-form+-- info table, excluding the entry-code word (if present)+infoTable dflags info_ptr+ | tablesNextToCode dflags = cmmOffsetB dflags info_ptr (- stdInfoTableSizeB dflags)+ | otherwise = cmmOffsetW dflags info_ptr 1 -- Past the entry code pointer++infoTableConstrTag :: DynFlags -> CmmExpr -> CmmExpr+-- Takes an info table pointer (from infoTable) and returns the constr tag+-- field of the info table (same as the srt_bitmap field)+infoTableConstrTag = infoTableSrtBitmap++infoTableSrtBitmap :: DynFlags -> CmmExpr -> CmmExpr+-- Takes an info table pointer (from infoTable) and returns the srt_bitmap+-- field of the info table+infoTableSrtBitmap dflags info_tbl+ = CmmLoad (cmmOffsetB dflags info_tbl (stdSrtBitmapOffset dflags)) (bHalfWord dflags)++infoTableClosureType :: DynFlags -> CmmExpr -> CmmExpr+-- Takes an info table pointer (from infoTable) and returns the closure type+-- field of the info table.+infoTableClosureType dflags info_tbl+ = CmmLoad (cmmOffsetB dflags info_tbl (stdClosureTypeOffset dflags)) (bHalfWord dflags)++infoTablePtrs :: DynFlags -> CmmExpr -> CmmExpr+infoTablePtrs dflags info_tbl+ = CmmLoad (cmmOffsetB dflags info_tbl (stdPtrsOffset dflags)) (bHalfWord dflags)++infoTableNonPtrs :: DynFlags -> CmmExpr -> CmmExpr+infoTableNonPtrs dflags info_tbl+ = CmmLoad (cmmOffsetB dflags info_tbl (stdNonPtrsOffset dflags)) (bHalfWord dflags)++funInfoTable :: DynFlags -> CmmExpr -> CmmExpr+-- Takes the info pointer of a function,+-- and returns a pointer to the first word of the StgFunInfoExtra struct+-- in the info table.+funInfoTable dflags info_ptr+ | tablesNextToCode dflags+ = cmmOffsetB dflags info_ptr (- stdInfoTableSizeB dflags - sIZEOF_StgFunInfoExtraRev dflags)+ | otherwise+ = cmmOffsetW dflags info_ptr (1 + stdInfoTableSizeW dflags)+ -- Past the entry code pointer++-- Takes the info pointer of a function, returns the function's arity+funInfoArity :: DynFlags -> CmmExpr -> CmmExpr+funInfoArity dflags iptr+ = cmmToWord dflags (cmmLoadIndex dflags rep fun_info (offset `div` rep_bytes))+ where+ fun_info = funInfoTable dflags iptr+ rep = cmmBits (widthFromBytes rep_bytes)++ (rep_bytes, offset)+ | tablesNextToCode dflags = ( pc_REP_StgFunInfoExtraRev_arity pc+ , oFFSET_StgFunInfoExtraRev_arity dflags )+ | otherwise = ( pc_REP_StgFunInfoExtraFwd_arity pc+ , oFFSET_StgFunInfoExtraFwd_arity dflags )++ pc = sPlatformConstants (settings dflags)++-----------------------------------------------------------------------------+--+-- Info table sizes & offsets+--+-----------------------------------------------------------------------------++stdInfoTableSizeW :: DynFlags -> WordOff+-- The size of a standard info table varies with profiling/ticky etc,+-- so we can't get it from Constants+-- It must vary in sync with mkStdInfoTable+stdInfoTableSizeW dflags+ = fixedInfoTableSizeW+ + if gopt Opt_SccProfilingOn dflags+ then profInfoTableSizeW+ else 0++fixedInfoTableSizeW :: WordOff+fixedInfoTableSizeW = 2 -- layout, type++profInfoTableSizeW :: WordOff+profInfoTableSizeW = 2++maxStdInfoTableSizeW :: WordOff+maxStdInfoTableSizeW =+ 1 {- entry, when !tablesNextToCode -}+ + fixedInfoTableSizeW+ + profInfoTableSizeW++maxRetInfoTableSizeW :: WordOff+maxRetInfoTableSizeW =+ maxStdInfoTableSizeW+ + 1 {- srt label -}++stdInfoTableSizeB :: DynFlags -> ByteOff+stdInfoTableSizeB dflags = stdInfoTableSizeW dflags * wORD_SIZE dflags++stdSrtBitmapOffset :: DynFlags -> ByteOff+-- Byte offset of the SRT bitmap half-word which is+-- in the *higher-addressed* part of the type_lit+stdSrtBitmapOffset dflags = stdInfoTableSizeB dflags - hALF_WORD_SIZE dflags++stdClosureTypeOffset :: DynFlags -> ByteOff+-- Byte offset of the closure type half-word+stdClosureTypeOffset dflags = stdInfoTableSizeB dflags - wORD_SIZE dflags++stdPtrsOffset, stdNonPtrsOffset :: DynFlags -> ByteOff+stdPtrsOffset dflags = stdInfoTableSizeB dflags - 2 * wORD_SIZE dflags+stdNonPtrsOffset dflags = stdInfoTableSizeB dflags - 2 * wORD_SIZE dflags + hALF_WORD_SIZE dflags++conInfoTableSizeB :: DynFlags -> Int+conInfoTableSizeB dflags = stdInfoTableSizeB dflags + wORD_SIZE dflags
+ cmm/CmmLayoutStack.hs view
@@ -0,0 +1,1146 @@+{-# LANGUAGE CPP, RecordWildCards, GADTs #-}+module CmmLayoutStack (+ cmmLayoutStack, setInfoTableStackMap+ ) where++import StgCmmUtils ( callerSaveVolatileRegs ) -- XXX layering violation+import StgCmmForeign ( saveThreadState, loadThreadState ) -- XXX layering violation++import BasicTypes+import Cmm+import CmmInfo+import BlockId+import CLabel+import CmmUtils+import MkGraph+import ForeignCall+import CmmLive+import CmmProcPoint+import SMRep+import Hoopl+import UniqSupply+import StgCmmUtils ( newTemp )+import Maybes+import UniqFM+import Util++import DynFlags+import FastString+import Outputable hiding ( isEmpty )+import qualified Data.Set as Set+import Control.Monad.Fix+import Data.Array as Array+import Data.Bits+import Data.List (nub)++import Prelude hiding ((<*>))++#include "HsVersions.h"++{- Note [Stack Layout]++The job of this pass is to++ - replace references to abstract stack Areas with fixed offsets from Sp.++ - replace the CmmHighStackMark constant used in the stack check with+ the maximum stack usage of the proc.++ - save any variables that are live across a call, and reload them as+ necessary.++Before stack allocation, local variables remain live across native+calls (CmmCall{ cmm_cont = Just _ }), and after stack allocation local+variables are clobbered by native calls.++We want to do stack allocation so that as far as possible+ - stack use is minimized, and+ - unnecessary stack saves and loads are avoided.++The algorithm we use is a variant of linear-scan register allocation,+where the stack is our register file.++ - First, we do a liveness analysis, which annotates every block with+ the variables live on entry to the block.++ - We traverse blocks in reverse postorder DFS; that is, we visit at+ least one predecessor of a block before the block itself. The+ stack layout flowing from the predecessor of the block will+ determine the stack layout on entry to the block.++ - We maintain a data structure++ Map Label StackMap++ which describes the contents of the stack and the stack pointer on+ entry to each block that is a successor of a block that we have+ visited.++ - For each block we visit:++ - Look up the StackMap for this block.++ - If this block is a proc point (or a call continuation, if we+ aren't splitting proc points), emit instructions to reload all+ the live variables from the stack, according to the StackMap.++ - Walk forwards through the instructions:+ - At an assignment x = Sp[loc]+ - Record the fact that Sp[loc] contains x, so that we won't+ need to save x if it ever needs to be spilled.+ - At an assignment x = E+ - If x was previously on the stack, it isn't any more+ - At the last node, if it is a call or a jump to a proc point+ - Lay out the stack frame for the call (see setupStackFrame)+ - emit instructions to save all the live variables+ - Remember the StackMaps for all the successors+ - emit an instruction to adjust Sp+ - If the last node is a branch, then the current StackMap is the+ StackMap for the successors.++ - Manifest Sp: replace references to stack areas in this block+ with real Sp offsets. We cannot do this until we have laid out+ the stack area for the successors above.++ In this phase we also eliminate redundant stores to the stack;+ see elimStackStores.++ - There is one important gotcha: sometimes we'll encounter a control+ transfer to a block that we've already processed (a join point),+ and in that case we might need to rearrange the stack to match+ what the block is expecting. (exactly the same as in linear-scan+ register allocation, except here we have the luxury of an infinite+ supply of temporary variables).++ - Finally, we update the magic CmmHighStackMark constant with the+ stack usage of the function, and eliminate the whole stack check+ if there was no stack use. (in fact this is done as part of the+ main traversal, by feeding the high-water-mark output back in as+ an input. I hate cyclic programming, but it's just too convenient+ sometimes.)++There are plenty of tricky details: update frames, proc points, return+addresses, foreign calls, and some ad-hoc optimisations that are+convenient to do here and effective in common cases. Comments in the+code below explain these.++-}+++-- All stack locations are expressed as positive byte offsets from the+-- "base", which is defined to be the address above the return address+-- on the stack on entry to this CmmProc.+--+-- Lower addresses have higher StackLocs.+--+type StackLoc = ByteOff++{-+ A StackMap describes the stack at any given point. At a continuation+ it has a particular layout, like this:++ | | <- base+ |-------------|+ | ret0 | <- base + 8+ |-------------|+ . upd frame . <- base + sm_ret_off+ |-------------|+ | |+ . vars .+ . (live/dead) .+ | | <- base + sm_sp - sm_args+ |-------------|+ | ret1 |+ . ret vals . <- base + sm_sp (<--- Sp points here)+ |-------------|++Why do we include the final return address (ret0) in our stack map? I+have absolutely no idea, but it seems to be done that way consistently+in the rest of the code generator, so I played along here. --SDM++Note that we will be constructing an info table for the continuation+(ret1), which needs to describe the stack down to, but not including,+the update frame (or ret0, if there is no update frame).+-}++data StackMap = StackMap+ { sm_sp :: StackLoc+ -- ^ the offset of Sp relative to the base on entry+ -- to this block.+ , sm_args :: ByteOff+ -- ^ the number of bytes of arguments in the area for this block+ -- Defn: the offset of young(L) relative to the base is given by+ -- (sm_sp - sm_args) of the StackMap for block L.+ , sm_ret_off :: ByteOff+ -- ^ Number of words of stack that we do not describe with an info+ -- table, because it contains an update frame.+ , sm_regs :: UniqFM (LocalReg,StackLoc)+ -- ^ regs on the stack+ }++instance Outputable StackMap where+ ppr StackMap{..} =+ text "Sp = " <> int sm_sp $$+ text "sm_args = " <> int sm_args $$+ text "sm_ret_off = " <> int sm_ret_off $$+ text "sm_regs = " <> pprUFM sm_regs ppr+++cmmLayoutStack :: DynFlags -> ProcPointSet -> ByteOff -> CmmGraph+ -> UniqSM (CmmGraph, LabelMap StackMap)+cmmLayoutStack dflags procpoints entry_args+ graph@(CmmGraph { g_entry = entry })+ = do+ -- We need liveness info. Dead assignments are removed later+ -- by the sinking pass.+ let liveness = cmmLocalLiveness dflags graph+ blocks = postorderDfs graph++ (final_stackmaps, _final_high_sp, new_blocks) <-+ mfix $ \ ~(rec_stackmaps, rec_high_sp, _new_blocks) ->+ layout dflags procpoints liveness entry entry_args+ rec_stackmaps rec_high_sp blocks++ new_blocks' <- mapM (lowerSafeForeignCall dflags) new_blocks+ return (ofBlockList entry new_blocks', final_stackmaps)+++layout :: DynFlags+ -> LabelSet -- proc points+ -> LabelMap CmmLocalLive -- liveness+ -> BlockId -- entry+ -> ByteOff -- stack args on entry++ -> LabelMap StackMap -- [final] stack maps+ -> ByteOff -- [final] Sp high water mark++ -> [CmmBlock] -- [in] blocks++ -> UniqSM+ ( LabelMap StackMap -- [out] stack maps+ , ByteOff -- [out] Sp high water mark+ , [CmmBlock] -- [out] new blocks+ )++layout dflags procpoints liveness entry entry_args final_stackmaps final_sp_high blocks+ = go blocks init_stackmap entry_args []+ where+ (updfr, cont_info) = collectContInfo blocks++ init_stackmap = mapSingleton entry StackMap{ sm_sp = entry_args+ , sm_args = entry_args+ , sm_ret_off = updfr+ , sm_regs = emptyUFM+ }++ go [] acc_stackmaps acc_hwm acc_blocks+ = return (acc_stackmaps, acc_hwm, acc_blocks)++ go (b0 : bs) acc_stackmaps acc_hwm acc_blocks+ = do+ let (entry0@(CmmEntry entry_lbl tscope), middle0, last0) = blockSplit b0++ let stack0@StackMap { sm_sp = sp0 }+ = mapFindWithDefault+ (pprPanic "no stack map for" (ppr entry_lbl))+ entry_lbl acc_stackmaps++ -- (a) Update the stack map to include the effects of+ -- assignments in this block+ let stack1 = foldBlockNodesF (procMiddle acc_stackmaps) middle0 stack0++ -- (b) Insert assignments to reload all the live variables if this+ -- block is a proc point+ let middle1 = if entry_lbl `setMember` procpoints+ then foldr blockCons middle0 (insertReloads stack0)+ else middle0++ -- (c) Look at the last node and if we are making a call or+ -- jumping to a proc point, we must save the live+ -- variables, adjust Sp, and construct the StackMaps for+ -- each of the successor blocks. See handleLastNode for+ -- details.+ (middle2, sp_off, last1, fixup_blocks, out)+ <- handleLastNode dflags procpoints liveness cont_info+ acc_stackmaps stack1 tscope middle0 last0++ -- (d) Manifest Sp: run over the nodes in the block and replace+ -- CmmStackSlot with CmmLoad from Sp with a concrete offset.+ --+ -- our block:+ -- middle1 -- the original middle nodes+ -- middle2 -- live variable saves from handleLastNode+ -- Sp = Sp + sp_off -- Sp adjustment goes here+ -- last1 -- the last node+ --+ let middle_pre = blockToList $ foldl blockSnoc middle1 middle2++ let final_blocks =+ manifestSp dflags final_stackmaps stack0 sp0 final_sp_high+ entry0 middle_pre sp_off last1 fixup_blocks++ let acc_stackmaps' = mapUnion acc_stackmaps out++ -- If this block jumps to the GC, then we do not take its+ -- stack usage into account for the high-water mark.+ -- Otherwise, if the only stack usage is in the stack-check+ -- failure block itself, we will do a redundant stack+ -- check. The stack has a buffer designed to accommodate+ -- the largest amount of stack needed for calling the GC.+ --+ this_sp_hwm | isGcJump last0 = 0+ | otherwise = sp0 - sp_off++ hwm' = maximum (acc_hwm : this_sp_hwm : map sm_sp (mapElems out))++ go bs acc_stackmaps' hwm' (final_blocks ++ acc_blocks)+++-- -----------------------------------------------------------------------------++-- Not foolproof, but GCFun is the culprit we most want to catch+isGcJump :: CmmNode O C -> Bool+isGcJump (CmmCall { cml_target = CmmReg (CmmGlobal l) })+ = l == GCFun || l == GCEnter1+isGcJump _something_else = False++-- -----------------------------------------------------------------------------++-- This doesn't seem right somehow. We need to find out whether this+-- proc will push some update frame material at some point, so that we+-- can avoid using that area of the stack for spilling. The+-- updfr_space field of the CmmProc *should* tell us, but it doesn't+-- (I think maybe it gets filled in later when we do proc-point+-- splitting).+--+-- So we'll just take the max of all the cml_ret_offs. This could be+-- unnecessarily pessimistic, but probably not in the code we+-- generate.++collectContInfo :: [CmmBlock] -> (ByteOff, LabelMap ByteOff)+collectContInfo blocks+ = (maximum ret_offs, mapFromList (catMaybes mb_argss))+ where+ (mb_argss, ret_offs) = mapAndUnzip get_cont blocks++ get_cont :: Block CmmNode x C -> (Maybe (Label, ByteOff), ByteOff)+ get_cont b =+ case lastNode b of+ CmmCall { cml_cont = Just l, .. }+ -> (Just (l, cml_ret_args), cml_ret_off)+ CmmForeignCall { .. }+ -> (Just (succ, ret_args), ret_off)+ _other -> (Nothing, 0)+++-- -----------------------------------------------------------------------------+-- Updating the StackMap from middle nodes++-- Look for loads from stack slots, and update the StackMap. This is+-- purely for optimisation reasons, so that we can avoid saving a+-- variable back to a different stack slot if it is already on the+-- stack.+--+-- This happens a lot: for example when function arguments are passed+-- on the stack and need to be immediately saved across a call, we+-- want to just leave them where they are on the stack.+--+procMiddle :: LabelMap StackMap -> CmmNode e x -> StackMap -> StackMap+procMiddle stackmaps node sm+ = case node of+ CmmAssign (CmmLocal r) (CmmLoad (CmmStackSlot area off) _)+ -> sm { sm_regs = addToUFM (sm_regs sm) r (r,loc) }+ where loc = getStackLoc area off stackmaps+ CmmAssign (CmmLocal r) _other+ -> sm { sm_regs = delFromUFM (sm_regs sm) r }+ _other+ -> sm++getStackLoc :: Area -> ByteOff -> LabelMap StackMap -> StackLoc+getStackLoc Old n _ = n+getStackLoc (Young l) n stackmaps =+ case mapLookup l stackmaps of+ Nothing -> pprPanic "getStackLoc" (ppr l)+ Just sm -> sm_sp sm - sm_args sm + n+++-- -----------------------------------------------------------------------------+-- Handling stack allocation for a last node++-- We take a single last node and turn it into:+--+-- C1 (some statements)+-- Sp = Sp + N+-- C2 (some more statements)+-- call f() -- the actual last node+--+-- plus possibly some more blocks (we may have to add some fixup code+-- between the last node and the continuation).+--+-- C1: is the code for saving the variables across this last node onto+-- the stack, if the continuation is a call or jumps to a proc point.+--+-- C2: if the last node is a safe foreign call, we have to inject some+-- extra code that goes *after* the Sp adjustment.++handleLastNode+ :: DynFlags -> ProcPointSet -> LabelMap CmmLocalLive -> LabelMap ByteOff+ -> LabelMap StackMap -> StackMap -> CmmTickScope+ -> Block CmmNode O O+ -> CmmNode O C+ -> UniqSM+ ( [CmmNode O O] -- nodes to go *before* the Sp adjustment+ , ByteOff -- amount to adjust Sp+ , CmmNode O C -- new last node+ , [CmmBlock] -- new blocks+ , LabelMap StackMap -- stackmaps for the continuations+ )++handleLastNode dflags procpoints liveness cont_info stackmaps+ stack0@StackMap { sm_sp = sp0 } tscp middle last+ = case last of+ -- At each return / tail call,+ -- adjust Sp to point to the last argument pushed, which+ -- is cml_args, after popping any other junk from the stack.+ CmmCall{ cml_cont = Nothing, .. } -> do+ let sp_off = sp0 - cml_args+ return ([], sp_off, last, [], mapEmpty)++ -- At each CmmCall with a continuation:+ CmmCall{ cml_cont = Just cont_lbl, .. } ->+ return $ lastCall cont_lbl cml_args cml_ret_args cml_ret_off++ CmmForeignCall{ succ = cont_lbl, .. } -> do+ return $ lastCall cont_lbl (wORD_SIZE dflags) ret_args ret_off+ -- one word of args: the return address++ CmmBranch {} -> handleBranches+ CmmCondBranch {} -> handleBranches+ CmmSwitch {} -> handleBranches++ where+ -- Calls and ForeignCalls are handled the same way:+ lastCall :: BlockId -> ByteOff -> ByteOff -> ByteOff+ -> ( [CmmNode O O]+ , ByteOff+ , CmmNode O C+ , [CmmBlock]+ , LabelMap StackMap+ )+ lastCall lbl cml_args cml_ret_args cml_ret_off+ = ( assignments+ , spOffsetForCall sp0 cont_stack cml_args+ , last+ , [] -- no new blocks+ , mapSingleton lbl cont_stack )+ where+ (assignments, cont_stack) = prepareStack lbl cml_ret_args cml_ret_off+++ prepareStack lbl cml_ret_args cml_ret_off+ | Just cont_stack <- mapLookup lbl stackmaps+ -- If we have already seen this continuation before, then+ -- we just have to make the stack look the same:+ = (fixupStack stack0 cont_stack, cont_stack)+ -- Otherwise, we have to allocate the stack frame+ | otherwise+ = (save_assignments, new_cont_stack)+ where+ (new_cont_stack, save_assignments)+ = setupStackFrame dflags lbl liveness cml_ret_off cml_ret_args stack0+++ -- For other last nodes (branches), if any of the targets is a+ -- proc point, we have to set up the stack to match what the proc+ -- point is expecting.+ --+ handleBranches :: UniqSM ( [CmmNode O O]+ , ByteOff+ , CmmNode O C+ , [CmmBlock]+ , LabelMap StackMap )++ handleBranches+ -- Note [diamond proc point]+ | Just l <- futureContinuation middle+ , (nub $ filter (`setMember` procpoints) $ successors last) == [l]+ = do+ let cont_args = mapFindWithDefault 0 l cont_info+ (assigs, cont_stack) = prepareStack l cont_args (sm_ret_off stack0)+ out = mapFromList [ (l', cont_stack)+ | l' <- successors last ]+ return ( assigs+ , spOffsetForCall sp0 cont_stack (wORD_SIZE dflags)+ , last+ , []+ , out)++ | otherwise = do+ pps <- mapM handleBranch (successors last)+ let lbl_map :: LabelMap Label+ lbl_map = mapFromList [ (l,tmp) | (l,tmp,_,_) <- pps ]+ fix_lbl l = mapFindWithDefault l l lbl_map+ return ( []+ , 0+ , mapSuccessors fix_lbl last+ , concat [ blk | (_,_,_,blk) <- pps ]+ , mapFromList [ (l, sm) | (l,_,sm,_) <- pps ] )++ -- For each successor of this block+ handleBranch :: BlockId -> UniqSM (BlockId, BlockId, StackMap, [CmmBlock])+ handleBranch l+ -- (a) if the successor already has a stackmap, we need to+ -- shuffle the current stack to make it look the same.+ -- We have to insert a new block to make this happen.+ | Just stack2 <- mapLookup l stackmaps+ = do+ let assigs = fixupStack stack0 stack2+ (tmp_lbl, block) <- makeFixupBlock dflags sp0 l stack2 tscp assigs+ return (l, tmp_lbl, stack2, block)++ -- (b) if the successor is a proc point, save everything+ -- on the stack.+ | l `setMember` procpoints+ = do+ let cont_args = mapFindWithDefault 0 l cont_info+ (stack2, assigs) =+ setupStackFrame dflags l liveness (sm_ret_off stack0)+ cont_args stack0+ (tmp_lbl, block) <- makeFixupBlock dflags sp0 l stack2 tscp assigs+ return (l, tmp_lbl, stack2, block)++ -- (c) otherwise, the current StackMap is the StackMap for+ -- the continuation. But we must remember to remove any+ -- variables from the StackMap that are *not* live at+ -- the destination, because this StackMap might be used+ -- by fixupStack if this is a join point.+ | otherwise = return (l, l, stack1, [])+ where live = mapFindWithDefault (panic "handleBranch") l liveness+ stack1 = stack0 { sm_regs = filterUFM is_live (sm_regs stack0) }+ is_live (r,_) = r `elemRegSet` live+++makeFixupBlock :: DynFlags -> ByteOff -> Label -> StackMap+ -> CmmTickScope -> [CmmNode O O]+ -> UniqSM (Label, [CmmBlock])+makeFixupBlock dflags sp0 l stack tscope assigs+ | null assigs && sp0 == sm_sp stack = return (l, [])+ | otherwise = do+ tmp_lbl <- newBlockId+ let sp_off = sp0 - sm_sp stack+ maybeAddUnwind block+ | debugLevel dflags > 0+ = block `blockSnoc` CmmUnwind [(Sp, Just unwind_val)]+ | otherwise+ = block+ where unwind_val = cmmOffset dflags (CmmReg spReg) (sm_sp stack)+ block = blockJoin (CmmEntry tmp_lbl tscope)+ ( maybeAddSpAdj dflags sp_off+ $ maybeAddUnwind+ $ blockFromList assigs )+ (CmmBranch l)+ return (tmp_lbl, [block])+++-- Sp is currently pointing to current_sp,+-- we want it to point to+-- (sm_sp cont_stack - sm_args cont_stack + args)+-- so the difference is+-- sp0 - (sm_sp cont_stack - sm_args cont_stack + args)+spOffsetForCall :: ByteOff -> StackMap -> ByteOff -> ByteOff+spOffsetForCall current_sp cont_stack args+ = current_sp - (sm_sp cont_stack - sm_args cont_stack + args)+++-- | create a sequence of assignments to establish the new StackMap,+-- given the old StackMap.+fixupStack :: StackMap -> StackMap -> [CmmNode O O]+fixupStack old_stack new_stack = concatMap move new_locs+ where+ old_map = sm_regs old_stack+ new_locs = stackSlotRegs new_stack++ move (r,n)+ | Just (_,m) <- lookupUFM old_map r, n == m = []+ | otherwise = [CmmStore (CmmStackSlot Old n)+ (CmmReg (CmmLocal r))]++++setupStackFrame+ :: DynFlags+ -> BlockId -- label of continuation+ -> LabelMap CmmLocalLive -- liveness+ -> ByteOff -- updfr+ -> ByteOff -- bytes of return values on stack+ -> StackMap -- current StackMap+ -> (StackMap, [CmmNode O O])++setupStackFrame dflags lbl liveness updfr_off ret_args stack0+ = (cont_stack, assignments)+ where+ -- get the set of LocalRegs live in the continuation+ live = mapFindWithDefault Set.empty lbl liveness++ -- the stack from the base to updfr_off is off-limits.+ -- our new stack frame contains:+ -- * saved live variables+ -- * the return address [young(C) + 8]+ -- * the args for the call,+ -- which are replaced by the return values at the return+ -- point.++ -- everything up to updfr_off is off-limits+ -- stack1 contains updfr_off, plus everything we need to save+ (stack1, assignments) = allocate dflags updfr_off live stack0++ -- And the Sp at the continuation is:+ -- sm_sp stack1 + ret_args+ cont_stack = stack1{ sm_sp = sm_sp stack1 + ret_args+ , sm_args = ret_args+ , sm_ret_off = updfr_off+ }+++-- -----------------------------------------------------------------------------+-- Note [diamond proc point]+--+-- This special case looks for the pattern we get from a typical+-- tagged case expression:+--+-- Sp[young(L1)] = L1+-- if (R1 & 7) != 0 goto L1 else goto L2+-- L2:+-- call [R1] returns to L1+-- L1: live: {y}+-- x = R1+--+-- If we let the generic case handle this, we get+--+-- Sp[-16] = L1+-- if (R1 & 7) != 0 goto L1a else goto L2+-- L2:+-- Sp[-8] = y+-- Sp = Sp - 16+-- call [R1] returns to L1+-- L1a:+-- Sp[-8] = y+-- Sp = Sp - 16+-- goto L1+-- L1:+-- x = R1+--+-- The code for saving the live vars is duplicated in each branch, and+-- furthermore there is an extra jump in the fast path (assuming L1 is+-- a proc point, which it probably is if there is a heap check).+--+-- So to fix this we want to set up the stack frame before the+-- conditional jump. How do we know when to do this, and when it is+-- safe? The basic idea is, when we see the assignment+--+-- Sp[young(L)] = L+--+-- we know that+-- * we are definitely heading for L+-- * there can be no more reads from another stack area, because young(L)+-- overlaps with it.+--+-- We don't necessarily know that everything live at L is live now+-- (some might be assigned between here and the jump to L). So we+-- simplify and only do the optimisation when we see+--+-- (1) a block containing an assignment of a return address L+-- (2) ending in a branch where one (and only) continuation goes to L,+-- and no other continuations go to proc points.+--+-- then we allocate the stack frame for L at the end of the block,+-- before the branch.+--+-- We could generalise (2), but that would make it a bit more+-- complicated to handle, and this currently catches the common case.++futureContinuation :: Block CmmNode O O -> Maybe BlockId+futureContinuation middle = foldBlockNodesB f middle Nothing+ where f :: CmmNode a b -> Maybe BlockId -> Maybe BlockId+ f (CmmStore (CmmStackSlot (Young l) _) (CmmLit (CmmBlock _))) _+ = Just l+ f _ r = r++-- -----------------------------------------------------------------------------+-- Saving live registers++-- | Given a set of live registers and a StackMap, save all the registers+-- on the stack and return the new StackMap and the assignments to do+-- the saving.+--+allocate :: DynFlags -> ByteOff -> LocalRegSet -> StackMap+ -> (StackMap, [CmmNode O O])+allocate dflags ret_off live stackmap@StackMap{ sm_sp = sp0+ , sm_regs = regs0 }+ =+ -- we only have to save regs that are not already in a slot+ let to_save = filter (not . (`elemUFM` regs0)) (Set.elems live)+ regs1 = filterUFM (\(r,_) -> elemRegSet r live) regs0+ in++ -- make a map of the stack+ let stack = reverse $ Array.elems $+ accumArray (\_ x -> x) Empty (1, toWords dflags (max sp0 ret_off)) $+ ret_words ++ live_words+ where ret_words =+ [ (x, Occupied)+ | x <- [ 1 .. toWords dflags ret_off] ]+ live_words =+ [ (toWords dflags x, Occupied)+ | (r,off) <- nonDetEltsUFM regs1,+ -- See Note [Unique Determinism and code generation]+ let w = localRegBytes dflags r,+ x <- [ off, off - wORD_SIZE dflags .. off - w + 1] ]+ in++ -- Pass over the stack: find slots to save all the new live variables,+ -- choosing the oldest slots first (hence a foldr).+ let+ save slot ([], stack, n, assigs, regs) -- no more regs to save+ = ([], slot:stack, plusW dflags n 1, assigs, regs)+ save slot (to_save, stack, n, assigs, regs)+ = case slot of+ Occupied -> (to_save, Occupied:stack, plusW dflags n 1, assigs, regs)+ Empty+ | Just (stack', r, to_save') <-+ select_save to_save (slot:stack)+ -> let assig = CmmStore (CmmStackSlot Old n')+ (CmmReg (CmmLocal r))+ n' = plusW dflags n 1+ in+ (to_save', stack', n', assig : assigs, (r,(r,n')):regs)++ | otherwise+ -> (to_save, slot:stack, plusW dflags n 1, assigs, regs)++ -- we should do better here: right now we'll fit the smallest first,+ -- but it would make more sense to fit the biggest first.+ select_save :: [LocalReg] -> [StackSlot]+ -> Maybe ([StackSlot], LocalReg, [LocalReg])+ select_save regs stack = go regs []+ where go [] _no_fit = Nothing+ go (r:rs) no_fit+ | Just rest <- dropEmpty words stack+ = Just (replicate words Occupied ++ rest, r, rs++no_fit)+ | otherwise+ = go rs (r:no_fit)+ where words = localRegWords dflags r++ -- fill in empty slots as much as possible+ (still_to_save, save_stack, n, save_assigs, save_regs)+ = foldr save (to_save, [], 0, [], []) stack++ -- push any remaining live vars on the stack+ (push_sp, push_assigs, push_regs)+ = foldr push (n, [], []) still_to_save+ where+ push r (n, assigs, regs)+ = (n', assig : assigs, (r,(r,n')) : regs)+ where+ n' = n + localRegBytes dflags r+ assig = CmmStore (CmmStackSlot Old n')+ (CmmReg (CmmLocal r))++ trim_sp+ | not (null push_regs) = push_sp+ | otherwise+ = plusW dflags n (- length (takeWhile isEmpty save_stack))++ final_regs = regs1 `addListToUFM` push_regs+ `addListToUFM` save_regs++ in+ -- XXX should be an assert+ if ( n /= max sp0 ret_off ) then pprPanic "allocate" (ppr n <+> ppr sp0 <+> ppr ret_off) else++ if (trim_sp .&. (wORD_SIZE dflags - 1)) /= 0 then pprPanic "allocate2" (ppr trim_sp <+> ppr final_regs <+> ppr push_sp) else++ ( stackmap { sm_regs = final_regs , sm_sp = trim_sp }+ , push_assigs ++ save_assigs )+++-- -----------------------------------------------------------------------------+-- Manifesting Sp++-- | Manifest Sp: turn all the CmmStackSlots into CmmLoads from Sp. The+-- block looks like this:+--+-- middle_pre -- the middle nodes+-- Sp = Sp + sp_off -- Sp adjustment goes here+-- last -- the last node+--+-- And we have some extra blocks too (that don't contain Sp adjustments)+--+-- The adjustment for middle_pre will be different from that for+-- middle_post, because the Sp adjustment intervenes.+--+manifestSp+ :: DynFlags+ -> LabelMap StackMap -- StackMaps for other blocks+ -> StackMap -- StackMap for this block+ -> ByteOff -- Sp on entry to the block+ -> ByteOff -- SpHigh+ -> CmmNode C O -- first node+ -> [CmmNode O O] -- middle+ -> ByteOff -- sp_off+ -> CmmNode O C -- last node+ -> [CmmBlock] -- new blocks+ -> [CmmBlock] -- final blocks with Sp manifest++manifestSp dflags stackmaps stack0 sp0 sp_high+ first middle_pre sp_off last fixup_blocks+ = final_block : fixup_blocks'+ where+ area_off = getAreaOff stackmaps++ adj_pre_sp, adj_post_sp :: CmmNode e x -> CmmNode e x+ adj_pre_sp = mapExpDeep (areaToSp dflags sp0 sp_high area_off)+ adj_post_sp = mapExpDeep (areaToSp dflags (sp0 - sp_off) sp_high area_off)++ -- Add unwind pseudo-instruction at the beginning of each block to+ -- document Sp level for debugging+ add_initial_unwind block+ | debugLevel dflags > 0+ = CmmUnwind [(Sp, Just sp_unwind)] `blockCons` block+ | otherwise+ = block+ where sp_unwind = CmmRegOff spReg (sp0 - wORD_SIZE dflags)++ -- Add unwind pseudo-instruction right before the Sp adjustment+ -- if there is one.+ add_adj_unwind block+ | debugLevel dflags > 0+ , sp_off /= 0+ = block `blockSnoc` CmmUnwind [(Sp, Just sp_unwind)]+ | otherwise+ = block+ where sp_unwind = CmmRegOff spReg (sp0 - wORD_SIZE dflags - sp_off)++ final_middle = maybeAddSpAdj dflags sp_off+ . add_adj_unwind+ . add_initial_unwind+ . blockFromList+ . map adj_pre_sp+ . elimStackStores stack0 stackmaps area_off+ $ middle_pre+ final_last = optStackCheck (adj_post_sp last)++ final_block = blockJoin first final_middle final_last++ fixup_blocks' = map (mapBlock3' (id, adj_post_sp, id)) fixup_blocks+++getAreaOff :: LabelMap StackMap -> (Area -> StackLoc)+getAreaOff _ Old = 0+getAreaOff stackmaps (Young l) =+ case mapLookup l stackmaps of+ Just sm -> sm_sp sm - sm_args sm+ Nothing -> pprPanic "getAreaOff" (ppr l)+++maybeAddSpAdj :: DynFlags -> ByteOff -> Block CmmNode O O -> Block CmmNode O O+maybeAddSpAdj _ 0 block = block+maybeAddSpAdj dflags sp_off block = block `blockSnoc` adj+ where+ adj = CmmAssign spReg (cmmOffset dflags (CmmReg spReg) sp_off)++{-+Sp(L) is the Sp offset on entry to block L relative to the base of the+OLD area.++SpArgs(L) is the size of the young area for L, i.e. the number of+arguments.++ - in block L, each reference to [old + N] turns into+ [Sp + Sp(L) - N]++ - in block L, each reference to [young(L') + N] turns into+ [Sp + Sp(L) - Sp(L') + SpArgs(L') - N]++ - be careful with the last node of each block: Sp has already been adjusted+ to be Sp + Sp(L) - Sp(L')+-}++areaToSp :: DynFlags -> ByteOff -> ByteOff -> (Area -> StackLoc) -> CmmExpr -> CmmExpr++areaToSp dflags sp_old _sp_hwm area_off (CmmStackSlot area n)+ = cmmOffset dflags (CmmReg spReg) (sp_old - area_off area - n)+ -- Replace (CmmStackSlot area n) with an offset from Sp++areaToSp dflags _ sp_hwm _ (CmmLit CmmHighStackMark)+ = mkIntExpr dflags sp_hwm+ -- Replace CmmHighStackMark with the number of bytes of stack used,+ -- the sp_hwm. See Note [Stack usage] in StgCmmHeap++areaToSp dflags _ _ _ (CmmMachOp (MO_U_Lt _) args)+ | falseStackCheck args+ = zeroExpr dflags+areaToSp dflags _ _ _ (CmmMachOp (MO_U_Ge _) args)+ | falseStackCheck args+ = mkIntExpr dflags 1+ -- Replace a stack-overflow test that cannot fail with a no-op+ -- See Note [Always false stack check]++areaToSp _ _ _ _ other = other++-- | Determine whether a stack check cannot fail.+falseStackCheck :: [CmmExpr] -> Bool+falseStackCheck [ CmmMachOp (MO_Sub _)+ [ CmmRegOff (CmmGlobal Sp) x_off+ , CmmLit (CmmInt y_lit _)]+ , CmmReg (CmmGlobal SpLim)]+ = fromIntegral x_off >= y_lit+falseStackCheck _ = False++-- Note [Always false stack check]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- We can optimise stack checks of the form+--+-- if ((Sp + x) - y < SpLim) then .. else ..+--+-- where are non-negative integer byte offsets. Since we know that+-- SpLim <= Sp (remember the stack grows downwards), this test must+-- yield False if (x >= y), so we can rewrite the comparison to False.+-- A subsequent sinking pass will later drop the dead code.+-- Optimising this away depends on knowing that SpLim <= Sp, so it is+-- really the job of the stack layout algorithm, hence we do it now.+--+-- The control flow optimiser may negate a conditional to increase+-- the likelihood of a fallthrough if the branch is not taken. But+-- not every conditional is inverted as the control flow optimiser+-- places some requirements on the predecessors of both branch targets.+-- So we better look for the inverted comparison too.++optStackCheck :: CmmNode O C -> CmmNode O C+optStackCheck n = -- Note [Always false stack check]+ case n of+ CmmCondBranch (CmmLit (CmmInt 0 _)) _true false _ -> CmmBranch false+ CmmCondBranch (CmmLit (CmmInt _ _)) true _false _ -> CmmBranch true+ other -> other+++-- -----------------------------------------------------------------------------++-- | Eliminate stores of the form+--+-- Sp[area+n] = r+--+-- when we know that r is already in the same slot as Sp[area+n]. We+-- could do this in a later optimisation pass, but that would involve+-- a separate analysis and we already have the information to hand+-- here. It helps clean up some extra stack stores in common cases.+--+-- Note that we may have to modify the StackMap as we walk through the+-- code using procMiddle, since an assignment to a variable in the+-- StackMap will invalidate its mapping there.+--+elimStackStores :: StackMap+ -> LabelMap StackMap+ -> (Area -> ByteOff)+ -> [CmmNode O O]+ -> [CmmNode O O]+elimStackStores stackmap stackmaps area_off nodes+ = go stackmap nodes+ where+ go _stackmap [] = []+ go stackmap (n:ns)+ = case n of+ CmmStore (CmmStackSlot area m) (CmmReg (CmmLocal r))+ | Just (_,off) <- lookupUFM (sm_regs stackmap) r+ , area_off area + m == off+ -> go stackmap ns+ _otherwise+ -> n : go (procMiddle stackmaps n stackmap) ns+++-- -----------------------------------------------------------------------------+-- Update info tables to include stack liveness+++setInfoTableStackMap :: DynFlags -> LabelMap StackMap -> CmmDecl -> CmmDecl+setInfoTableStackMap dflags stackmaps (CmmProc top_info@TopInfo{..} l v g)+ = CmmProc top_info{ info_tbls = mapMapWithKey fix_info info_tbls } l v g+ where+ fix_info lbl info_tbl@CmmInfoTable{ cit_rep = StackRep _ } =+ info_tbl { cit_rep = StackRep (get_liveness lbl) }+ fix_info _ other = other++ get_liveness :: BlockId -> Liveness+ get_liveness lbl+ = case mapLookup lbl stackmaps of+ Nothing -> pprPanic "setInfoTableStackMap" (ppr lbl <+> ppr info_tbls)+ Just sm -> stackMapToLiveness dflags sm++setInfoTableStackMap _ _ d = d+++stackMapToLiveness :: DynFlags -> StackMap -> Liveness+stackMapToLiveness dflags StackMap{..} =+ reverse $ Array.elems $+ accumArray (\_ x -> x) True (toWords dflags sm_ret_off + 1,+ toWords dflags (sm_sp - sm_args)) live_words+ where+ live_words = [ (toWords dflags off, False)+ | (r,off) <- nonDetEltsUFM sm_regs+ , isGcPtrType (localRegType r) ]+ -- See Note [Unique Determinism and code generation]+++-- -----------------------------------------------------------------------------+-- Lowering safe foreign calls++{-+Note [Lower safe foreign calls]++We start with++ Sp[young(L1)] = L1+ ,-----------------------+ | r1 = foo(x,y,z) returns to L1+ '-----------------------+ L1:+ R1 = r1 -- copyIn, inserted by mkSafeCall+ ...++the stack layout algorithm will arrange to save and reload everything+live across the call. Our job now is to expand the call so we get++ Sp[young(L1)] = L1+ ,-----------------------+ | SAVE_THREAD_STATE()+ | token = suspendThread(BaseReg, interruptible)+ | r = foo(x,y,z)+ | BaseReg = resumeThread(token)+ | LOAD_THREAD_STATE()+ | R1 = r -- copyOut+ | jump Sp[0]+ '-----------------------+ L1:+ r = R1 -- copyIn, inserted by mkSafeCall+ ...++Note the copyOut, which saves the results in the places that L1 is+expecting them (see Note [safe foreign call convention]). Note also+that safe foreign call is replace by an unsafe one in the Cmm graph.+-}++lowerSafeForeignCall :: DynFlags -> CmmBlock -> UniqSM CmmBlock+lowerSafeForeignCall dflags block+ | (entry@(CmmEntry _ tscp), middle, CmmForeignCall { .. }) <- blockSplit block+ = do+ -- Both 'id' and 'new_base' are KindNonPtr because they're+ -- RTS-only objects and are not subject to garbage collection+ id <- newTemp (bWord dflags)+ new_base <- newTemp (cmmRegType dflags (CmmGlobal BaseReg))+ let (caller_save, caller_load) = callerSaveVolatileRegs dflags+ save_state_code <- saveThreadState dflags+ load_state_code <- loadThreadState dflags+ let suspend = save_state_code <*>+ caller_save <*>+ mkMiddle (callSuspendThread dflags id intrbl)+ midCall = mkUnsafeCall tgt res args+ resume = mkMiddle (callResumeThread new_base id) <*>+ -- Assign the result to BaseReg: we+ -- might now have a different Capability!+ mkAssign (CmmGlobal BaseReg) (CmmReg (CmmLocal new_base)) <*>+ caller_load <*>+ load_state_code++ (_, regs, copyout) =+ copyOutOflow dflags NativeReturn Jump (Young succ)+ (map (CmmReg . CmmLocal) res)+ ret_off []++ -- NB. after resumeThread returns, the top-of-stack probably contains+ -- the stack frame for succ, but it might not: if the current thread+ -- received an exception during the call, then the stack might be+ -- different. Hence we continue by jumping to the top stack frame,+ -- not by jumping to succ.+ jump = CmmCall { cml_target = entryCode dflags $+ CmmLoad (CmmReg spReg) (bWord dflags)+ , cml_cont = Just succ+ , cml_args_regs = regs+ , cml_args = widthInBytes (wordWidth dflags)+ , cml_ret_args = ret_args+ , cml_ret_off = ret_off }++ graph' <- lgraphOfAGraph ( suspend <*>+ midCall <*>+ resume <*>+ copyout <*>+ mkLast jump, tscp)++ case toBlockList graph' of+ [one] -> let (_, middle', last) = blockSplit one+ in return (blockJoin entry (middle `blockAppend` middle') last)+ _ -> panic "lowerSafeForeignCall0"++ -- Block doesn't end in a safe foreign call:+ | otherwise = return block+++foreignLbl :: FastString -> CmmExpr+foreignLbl name = CmmLit (CmmLabel (mkForeignLabel name Nothing ForeignLabelInExternalPackage IsFunction))++callSuspendThread :: DynFlags -> LocalReg -> Bool -> CmmNode O O+callSuspendThread dflags id intrbl =+ CmmUnsafeForeignCall+ (ForeignTarget (foreignLbl (fsLit "suspendThread"))+ (ForeignConvention CCallConv [AddrHint, NoHint] [AddrHint] CmmMayReturn))+ [id] [CmmReg (CmmGlobal BaseReg), mkIntExpr dflags (fromEnum intrbl)]++callResumeThread :: LocalReg -> LocalReg -> CmmNode O O+callResumeThread new_base id =+ CmmUnsafeForeignCall+ (ForeignTarget (foreignLbl (fsLit "resumeThread"))+ (ForeignConvention CCallConv [AddrHint] [AddrHint] CmmMayReturn))+ [new_base] [CmmReg (CmmLocal id)]++-- -----------------------------------------------------------------------------++plusW :: DynFlags -> ByteOff -> WordOff -> ByteOff+plusW dflags b w = b + w * wORD_SIZE dflags++data StackSlot = Occupied | Empty+ -- Occupied: a return address or part of an update frame++instance Outputable StackSlot where+ ppr Occupied = text "XXX"+ ppr Empty = text "---"++dropEmpty :: WordOff -> [StackSlot] -> Maybe [StackSlot]+dropEmpty 0 ss = Just ss+dropEmpty n (Empty : ss) = dropEmpty (n-1) ss+dropEmpty _ _ = Nothing++isEmpty :: StackSlot -> Bool+isEmpty Empty = True+isEmpty _ = False++localRegBytes :: DynFlags -> LocalReg -> ByteOff+localRegBytes dflags r+ = roundUpToWords dflags (widthInBytes (typeWidth (localRegType r)))++localRegWords :: DynFlags -> LocalReg -> WordOff+localRegWords dflags = toWords dflags . localRegBytes dflags++toWords :: DynFlags -> ByteOff -> WordOff+toWords dflags x = x `quot` wORD_SIZE dflags+++insertReloads :: StackMap -> [CmmNode O O]+insertReloads stackmap =+ [ CmmAssign (CmmLocal r) (CmmLoad (CmmStackSlot Old sp)+ (localRegType r))+ | (r,sp) <- stackSlotRegs stackmap+ ]+++stackSlotRegs :: StackMap -> [(LocalReg, StackLoc)]+stackSlotRegs sm = nonDetEltsUFM (sm_regs sm)+ -- See Note [Unique Determinism and code generation]
+ cmm/CmmLex.x view
@@ -0,0 +1,363 @@+-----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2004-2006+--+-- Lexer for concrete Cmm. We try to stay close to the C-- spec, but there+-- are a few minor differences:+--+-- * extra keywords for our macros, and float32/float64 types+-- * global registers (Sp,Hp, etc.)+--+-----------------------------------------------------------------------------++{+-- See Note [Warnings in code generated by Alex] in compiler/parser/Lexer.x+{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++module CmmLex (+ CmmToken(..), cmmlex,+ ) where++import CmmExpr++import Lexer+import CmmMonad+import SrcLoc+import UniqFM+import StringBuffer+import FastString+import Ctype+import Util+--import TRACE++import Data.Word+import Data.Char+}++$whitechar = [\ \t\n\r\f\v\xa0] -- \xa0 is Unicode no-break space+$white_no_nl = $whitechar # \n++$ascdigit = 0-9+$unidigit = \x01 -- Trick Alex into handling Unicode. See alexGetChar.+$digit = [$ascdigit $unidigit]+$octit = 0-7+$hexit = [$digit A-F a-f]++$unilarge = \x03 -- Trick Alex into handling Unicode. See alexGetChar.+$asclarge = [A-Z \xc0-\xd6 \xd8-\xde]+$large = [$asclarge $unilarge]++$unismall = \x04 -- Trick Alex into handling Unicode. See alexGetChar.+$ascsmall = [a-z \xdf-\xf6 \xf8-\xff]+$small = [$ascsmall $unismall \_]++$namebegin = [$large $small \. \$ \@]+$namechar = [$namebegin $digit]++@decimal = $digit++@octal = $octit++@hexadecimal = $hexit++@exponent = [eE] [\-\+]? @decimal++@floating_point = @decimal \. @decimal @exponent? | @decimal @exponent++@escape = \\ ([abfnrt\\\'\"\?] | x $hexit{1,2} | $octit{1,3})+@strchar = ($printable # [\"\\]) | @escape++cmm :-++$white_no_nl+ ;+^\# pragma .* \n ; -- Apple GCC 3.3 CPP generates pragmas in its output++^\# (line)? { begin line_prag }++-- single-line line pragmas, of the form+-- # <line> "<file>" <extra-stuff> \n+<line_prag> $digit+ { setLine line_prag1 }+<line_prag1> \" [^\"]* \" { setFile line_prag2 }+<line_prag2> .* { pop }++<0> {+ \n ;++ [\:\;\{\}\[\]\(\)\=\`\~\/\*\%\-\+\&\^\|\>\<\,\!] { special_char }++ ".." { kw CmmT_DotDot }+ "::" { kw CmmT_DoubleColon }+ ">>" { kw CmmT_Shr }+ "<<" { kw CmmT_Shl }+ ">=" { kw CmmT_Ge }+ "<=" { kw CmmT_Le }+ "==" { kw CmmT_Eq }+ "!=" { kw CmmT_Ne }+ "&&" { kw CmmT_BoolAnd }+ "||" { kw CmmT_BoolOr }++ P@decimal { global_regN (\n -> VanillaReg n VGcPtr) }+ R@decimal { global_regN (\n -> VanillaReg n VNonGcPtr) }+ F@decimal { global_regN FloatReg }+ D@decimal { global_regN DoubleReg }+ L@decimal { global_regN LongReg }+ Sp { global_reg Sp }+ SpLim { global_reg SpLim }+ Hp { global_reg Hp }+ HpLim { global_reg HpLim }+ CCCS { global_reg CCCS }+ CurrentTSO { global_reg CurrentTSO }+ CurrentNursery { global_reg CurrentNursery }+ HpAlloc { global_reg HpAlloc }+ BaseReg { global_reg BaseReg }+ MachSp { global_reg MachSp }+ UnwindReturnReg { global_reg UnwindReturnReg }++ $namebegin $namechar* { name }++ 0 @octal { tok_octal }+ @decimal { tok_decimal }+ 0[xX] @hexadecimal { tok_hexadecimal }+ @floating_point { strtoken tok_float }++ \" @strchar* \" { strtoken tok_string }+}++{+data CmmToken+ = CmmT_SpecChar Char+ | CmmT_DotDot+ | CmmT_DoubleColon+ | CmmT_Shr+ | CmmT_Shl+ | CmmT_Ge+ | CmmT_Le+ | CmmT_Eq+ | CmmT_Ne+ | CmmT_BoolAnd+ | CmmT_BoolOr+ | CmmT_CLOSURE+ | CmmT_INFO_TABLE+ | CmmT_INFO_TABLE_RET+ | CmmT_INFO_TABLE_FUN+ | CmmT_INFO_TABLE_CONSTR+ | CmmT_INFO_TABLE_SELECTOR+ | CmmT_else+ | CmmT_export+ | CmmT_section+ | CmmT_goto+ | CmmT_if+ | CmmT_call+ | CmmT_jump+ | CmmT_foreign+ | CmmT_never+ | CmmT_prim+ | CmmT_reserve+ | CmmT_return+ | CmmT_returns+ | CmmT_import+ | CmmT_switch+ | CmmT_case+ | CmmT_default+ | CmmT_push+ | CmmT_unwind+ | CmmT_bits8+ | CmmT_bits16+ | CmmT_bits32+ | CmmT_bits64+ | CmmT_bits128+ | CmmT_bits256+ | CmmT_bits512+ | CmmT_float32+ | CmmT_float64+ | CmmT_gcptr+ | CmmT_GlobalReg GlobalReg+ | CmmT_Name FastString+ | CmmT_String String+ | CmmT_Int Integer+ | CmmT_Float Rational+ | CmmT_EOF+ deriving (Show)++-- -----------------------------------------------------------------------------+-- Lexer actions++type Action = RealSrcSpan -> StringBuffer -> Int -> PD (RealLocated CmmToken)++begin :: Int -> Action+begin code _span _str _len = do liftP (pushLexState code); lexToken++pop :: Action+pop _span _buf _len = liftP popLexState >> lexToken++special_char :: Action+special_char span buf _len = return (L span (CmmT_SpecChar (currentChar buf)))++kw :: CmmToken -> Action+kw tok span _buf _len = return (L span tok)++global_regN :: (Int -> GlobalReg) -> Action+global_regN con span buf len+ = return (L span (CmmT_GlobalReg (con (fromIntegral n))))+ where buf' = stepOn buf+ n = parseUnsignedInteger buf' (len-1) 10 octDecDigit++global_reg :: GlobalReg -> Action+global_reg r span _buf _len = return (L span (CmmT_GlobalReg r))++strtoken :: (String -> CmmToken) -> Action+strtoken f span buf len =+ return (L span $! (f $! lexemeToString buf len))++name :: Action+name span buf len =+ case lookupUFM reservedWordsFM fs of+ Just tok -> return (L span tok)+ Nothing -> return (L span (CmmT_Name fs))+ where+ fs = lexemeToFastString buf len++reservedWordsFM = listToUFM $+ map (\(x, y) -> (mkFastString x, y)) [+ ( "CLOSURE", CmmT_CLOSURE ),+ ( "INFO_TABLE", CmmT_INFO_TABLE ),+ ( "INFO_TABLE_RET", CmmT_INFO_TABLE_RET ),+ ( "INFO_TABLE_FUN", CmmT_INFO_TABLE_FUN ),+ ( "INFO_TABLE_CONSTR", CmmT_INFO_TABLE_CONSTR ),+ ( "INFO_TABLE_SELECTOR",CmmT_INFO_TABLE_SELECTOR ),+ ( "else", CmmT_else ),+ ( "export", CmmT_export ),+ ( "section", CmmT_section ),+ ( "goto", CmmT_goto ),+ ( "if", CmmT_if ),+ ( "call", CmmT_call ),+ ( "jump", CmmT_jump ),+ ( "foreign", CmmT_foreign ),+ ( "never", CmmT_never ),+ ( "prim", CmmT_prim ),+ ( "reserve", CmmT_reserve ),+ ( "return", CmmT_return ),+ ( "returns", CmmT_returns ),+ ( "import", CmmT_import ),+ ( "switch", CmmT_switch ),+ ( "case", CmmT_case ),+ ( "default", CmmT_default ),+ ( "push", CmmT_push ),+ ( "unwind", CmmT_unwind ),+ ( "bits8", CmmT_bits8 ),+ ( "bits16", CmmT_bits16 ),+ ( "bits32", CmmT_bits32 ),+ ( "bits64", CmmT_bits64 ),+ ( "bits128", CmmT_bits128 ),+ ( "bits256", CmmT_bits256 ),+ ( "bits512", CmmT_bits512 ),+ ( "float32", CmmT_float32 ),+ ( "float64", CmmT_float64 ),+-- New forms+ ( "b8", CmmT_bits8 ),+ ( "b16", CmmT_bits16 ),+ ( "b32", CmmT_bits32 ),+ ( "b64", CmmT_bits64 ),+ ( "b128", CmmT_bits128 ),+ ( "b256", CmmT_bits256 ),+ ( "b512", CmmT_bits512 ),+ ( "f32", CmmT_float32 ),+ ( "f64", CmmT_float64 ),+ ( "gcptr", CmmT_gcptr )+ ]++tok_decimal span buf len+ = return (L span (CmmT_Int $! parseUnsignedInteger buf len 10 octDecDigit))++tok_octal span buf len+ = return (L span (CmmT_Int $! parseUnsignedInteger (offsetBytes 1 buf) (len-1) 8 octDecDigit))++tok_hexadecimal span buf len+ = return (L span (CmmT_Int $! parseUnsignedInteger (offsetBytes 2 buf) (len-2) 16 hexDigit))++tok_float str = CmmT_Float $! readRational str++tok_string str = CmmT_String (read str)+ -- urk, not quite right, but it'll do for now++-- -----------------------------------------------------------------------------+-- Line pragmas++setLine :: Int -> Action+setLine code span buf len = do+ let line = parseUnsignedInteger buf len 10 octDecDigit+ liftP $ do+ setSrcLoc (mkRealSrcLoc (srcSpanFile span) (fromIntegral line - 1) 1)+ -- subtract one: the line number refers to the *following* line+ -- trace ("setLine " ++ show line) $ do+ popLexState >> pushLexState code+ lexToken++setFile :: Int -> Action+setFile code span buf len = do+ let file = lexemeToFastString (stepOn buf) (len-2)+ liftP $ do+ setSrcLoc (mkRealSrcLoc file (srcSpanEndLine span) (srcSpanEndCol span))+ popLexState >> pushLexState code+ lexToken++-- -----------------------------------------------------------------------------+-- This is the top-level function: called from the parser each time a+-- new token is to be read from the input.++cmmlex :: (Located CmmToken -> PD a) -> PD a+cmmlex cont = do+ (L span tok) <- lexToken+ --trace ("token: " ++ show tok) $ do+ cont (L (RealSrcSpan span) tok)++lexToken :: PD (RealLocated CmmToken)+lexToken = do+ inp@(loc1,buf) <- getInput+ sc <- liftP getLexState+ case alexScan inp sc of+ AlexEOF -> do let span = mkRealSrcSpan loc1 loc1+ liftP (setLastToken span 0)+ return (L span CmmT_EOF)+ AlexError (loc2,_) -> liftP $ failLocMsgP loc1 loc2 "lexical error"+ AlexSkip inp2 _ -> do+ setInput inp2+ lexToken+ AlexToken inp2@(end,_buf2) len t -> do+ setInput inp2+ let span = mkRealSrcSpan loc1 end+ span `seq` liftP (setLastToken span len)+ t span buf len++-- -----------------------------------------------------------------------------+-- Monad stuff++-- Stuff that Alex needs to know about our input type:+type AlexInput = (RealSrcLoc,StringBuffer)++alexInputPrevChar :: AlexInput -> Char+alexInputPrevChar (_,s) = prevChar s '\n'++-- backwards compatibility for Alex 2.x+alexGetChar :: AlexInput -> Maybe (Char,AlexInput)+alexGetChar inp = case alexGetByte inp of+ Nothing -> Nothing+ Just (b,i) -> c `seq` Just (c,i)+ where c = chr $ fromIntegral b++alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)+alexGetByte (loc,s)+ | atEnd s = Nothing+ | otherwise = b `seq` loc' `seq` s' `seq` Just (b, (loc', s'))+ where c = currentChar s+ b = fromIntegral $ ord $ c+ loc' = advanceSrcLoc loc c+ s' = stepOn s++getInput :: PD AlexInput+getInput = PD $ \_ s@PState{ loc=l, buffer=b } -> POk s (l,b)++setInput :: AlexInput -> PD ()+setInput (l,b) = PD $ \_ s -> POk s{ loc=l, buffer=b } ()+}
+ cmm/CmmLint.hs view
@@ -0,0 +1,257 @@+-----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 2011+--+-- CmmLint: checking the correctness of Cmm statements and expressions+--+-----------------------------------------------------------------------------+{-# LANGUAGE GADTs #-}+module CmmLint (+ cmmLint, cmmLintGraph+ ) where++import Hoopl+import Cmm+import CmmUtils+import CmmLive+import CmmSwitch (switchTargetsToList)+import PprCmm ()+import Outputable+import DynFlags++import Control.Monad (liftM, ap)++-- Things to check:+-- - invariant on CmmBlock in CmmExpr (see comment there)+-- - check for branches to blocks that don't exist+-- - check types++-- -----------------------------------------------------------------------------+-- Exported entry points:++cmmLint :: (Outputable d, Outputable h)+ => DynFlags -> GenCmmGroup d h CmmGraph -> Maybe SDoc+cmmLint dflags tops = runCmmLint dflags (mapM_ (lintCmmDecl dflags)) tops++cmmLintGraph :: DynFlags -> CmmGraph -> Maybe SDoc+cmmLintGraph dflags g = runCmmLint dflags (lintCmmGraph dflags) g++runCmmLint :: Outputable a => DynFlags -> (a -> CmmLint b) -> a -> Maybe SDoc+runCmmLint dflags l p =+ case unCL (l p) dflags of+ Left err -> Just (vcat [text "Cmm lint error:",+ nest 2 err,+ text "Program was:",+ nest 2 (ppr p)])+ Right _ -> Nothing++lintCmmDecl :: DynFlags -> GenCmmDecl h i CmmGraph -> CmmLint ()+lintCmmDecl dflags (CmmProc _ lbl _ g)+ = addLintInfo (text "in proc " <> ppr lbl) $ lintCmmGraph dflags g+lintCmmDecl _ (CmmData {})+ = return ()+++lintCmmGraph :: DynFlags -> CmmGraph -> CmmLint ()+lintCmmGraph dflags g =+ cmmLocalLiveness dflags g `seq` mapM_ (lintCmmBlock labels) blocks+ -- cmmLiveness throws an error if there are registers+ -- live on entry to the graph (i.e. undefined+ -- variables)+ where+ blocks = toBlockList g+ labels = setFromList (map entryLabel blocks)+++lintCmmBlock :: LabelSet -> CmmBlock -> CmmLint ()+lintCmmBlock labels block+ = addLintInfo (text "in basic block " <> ppr (entryLabel block)) $ do+ let (_, middle, last) = blockSplit block+ mapM_ lintCmmMiddle (blockToList middle)+ lintCmmLast labels last++-- -----------------------------------------------------------------------------+-- lintCmmExpr++-- Checks whether a CmmExpr is "type-correct", and check for obvious-looking+-- byte/word mismatches.++lintCmmExpr :: CmmExpr -> CmmLint CmmType+lintCmmExpr (CmmLoad expr rep) = do+ _ <- lintCmmExpr expr+ -- Disabled, if we have the inlining phase before the lint phase,+ -- we can have funny offsets due to pointer tagging. -- EZY+ -- when (widthInBytes (typeWidth rep) >= wORD_SIZE) $+ -- cmmCheckWordAddress expr+ return rep+lintCmmExpr expr@(CmmMachOp op args) = do+ dflags <- getDynFlags+ tys <- mapM lintCmmExpr args+ if map (typeWidth . cmmExprType dflags) args == machOpArgReps dflags op+ then cmmCheckMachOp op args tys+ else cmmLintMachOpErr expr (map (cmmExprType dflags) args) (machOpArgReps dflags op)+lintCmmExpr (CmmRegOff reg offset)+ = do dflags <- getDynFlags+ let rep = typeWidth (cmmRegType dflags reg)+ lintCmmExpr (CmmMachOp (MO_Add rep)+ [CmmReg reg, CmmLit (CmmInt (fromIntegral offset) rep)])+lintCmmExpr expr =+ do dflags <- getDynFlags+ return (cmmExprType dflags expr)++-- Check for some common byte/word mismatches (eg. Sp + 1)+cmmCheckMachOp :: MachOp -> [CmmExpr] -> [CmmType] -> CmmLint CmmType+cmmCheckMachOp op [lit@(CmmLit (CmmInt { })), reg@(CmmReg _)] tys+ = cmmCheckMachOp op [reg, lit] tys+cmmCheckMachOp op _ tys+ = do dflags <- getDynFlags+ return (machOpResultType dflags op tys)++{-+isOffsetOp :: MachOp -> Bool+isOffsetOp (MO_Add _) = True+isOffsetOp (MO_Sub _) = True+isOffsetOp _ = False++-- This expression should be an address from which a word can be loaded:+-- check for funny-looking sub-word offsets.+_cmmCheckWordAddress :: CmmExpr -> CmmLint ()+_cmmCheckWordAddress e@(CmmMachOp op [arg, CmmLit (CmmInt i _)])+ | isOffsetOp op && notNodeReg arg && i `rem` fromIntegral (wORD_SIZE dflags) /= 0+ = cmmLintDubiousWordOffset e+_cmmCheckWordAddress e@(CmmMachOp op [CmmLit (CmmInt i _), arg])+ | isOffsetOp op && notNodeReg arg && i `rem` fromIntegral (wORD_SIZE dflags) /= 0+ = cmmLintDubiousWordOffset e+_cmmCheckWordAddress _+ = return ()++-- No warnings for unaligned arithmetic with the node register,+-- which is used to extract fields from tagged constructor closures.+notNodeReg :: CmmExpr -> Bool+notNodeReg (CmmReg reg) | reg == nodeReg = False+notNodeReg _ = True+-}++lintCmmMiddle :: CmmNode O O -> CmmLint ()+lintCmmMiddle node = case node of+ CmmComment _ -> return ()+ CmmTick _ -> return ()+ CmmUnwind{} -> return ()++ CmmAssign reg expr -> do+ dflags <- getDynFlags+ erep <- lintCmmExpr expr+ let reg_ty = cmmRegType dflags reg+ if (erep `cmmEqType_ignoring_ptrhood` reg_ty)+ then return ()+ else cmmLintAssignErr (CmmAssign reg expr) erep reg_ty++ CmmStore l r -> do+ _ <- lintCmmExpr l+ _ <- lintCmmExpr r+ return ()++ CmmUnsafeForeignCall target _formals actuals -> do+ lintTarget target+ mapM_ lintCmmExpr actuals+++lintCmmLast :: LabelSet -> CmmNode O C -> CmmLint ()+lintCmmLast labels node = case node of+ CmmBranch id -> checkTarget id++ CmmCondBranch e t f _ -> do+ dflags <- getDynFlags+ mapM_ checkTarget [t,f]+ _ <- lintCmmExpr e+ checkCond dflags e++ CmmSwitch e ids -> do+ dflags <- getDynFlags+ mapM_ checkTarget $ switchTargetsToList ids+ erep <- lintCmmExpr e+ if (erep `cmmEqType_ignoring_ptrhood` bWord dflags)+ then return ()+ else cmmLintErr (text "switch scrutinee is not a word: " <>+ ppr e <> text " :: " <> ppr erep)++ CmmCall { cml_target = target, cml_cont = cont } -> do+ _ <- lintCmmExpr target+ maybe (return ()) checkTarget cont++ CmmForeignCall tgt _ args succ _ _ _ -> do+ lintTarget tgt+ mapM_ lintCmmExpr args+ checkTarget succ+ where+ checkTarget id+ | setMember id labels = return ()+ | otherwise = cmmLintErr (text "Branch to nonexistent id" <+> ppr id)+++lintTarget :: ForeignTarget -> CmmLint ()+lintTarget (ForeignTarget e _) = lintCmmExpr e >> return ()+lintTarget (PrimTarget {}) = return ()+++checkCond :: DynFlags -> CmmExpr -> CmmLint ()+checkCond _ (CmmMachOp mop _) | isComparisonMachOp mop = return ()+checkCond dflags (CmmLit (CmmInt x t)) | x == 0 || x == 1, t == wordWidth dflags = return () -- constant values+checkCond _ expr+ = cmmLintErr (hang (text "expression is not a conditional:") 2+ (ppr expr))++-- -----------------------------------------------------------------------------+-- CmmLint monad++-- just a basic error monad:++newtype CmmLint a = CmmLint { unCL :: DynFlags -> Either SDoc a }++instance Functor CmmLint where+ fmap = liftM++instance Applicative CmmLint where+ pure a = CmmLint (\_ -> Right a)+ (<*>) = ap++instance Monad CmmLint where+ CmmLint m >>= k = CmmLint $ \dflags ->+ case m dflags of+ Left e -> Left e+ Right a -> unCL (k a) dflags++instance HasDynFlags CmmLint where+ getDynFlags = CmmLint (\dflags -> Right dflags)++cmmLintErr :: SDoc -> CmmLint a+cmmLintErr msg = CmmLint (\_ -> Left msg)++addLintInfo :: SDoc -> CmmLint a -> CmmLint a+addLintInfo info thing = CmmLint $ \dflags ->+ case unCL thing dflags of+ Left err -> Left (hang info 2 err)+ Right a -> Right a++cmmLintMachOpErr :: CmmExpr -> [CmmType] -> [Width] -> CmmLint a+cmmLintMachOpErr expr argsRep opExpectsRep+ = cmmLintErr (text "in MachOp application: " $$+ nest 2 (ppr expr) $$+ (text "op is expecting: " <+> ppr opExpectsRep) $$+ (text "arguments provide: " <+> ppr argsRep))++cmmLintAssignErr :: CmmNode e x -> CmmType -> CmmType -> CmmLint a+cmmLintAssignErr stmt e_ty r_ty+ = cmmLintErr (text "in assignment: " $$+ nest 2 (vcat [ppr stmt,+ text "Reg ty:" <+> ppr r_ty,+ text "Rhs ty:" <+> ppr e_ty]))+++{-+cmmLintDubiousWordOffset :: CmmExpr -> CmmLint a+cmmLintDubiousWordOffset expr+ = cmmLintErr (text "offset is not a multiple of words: " $$+ nest 2 (ppr expr))+-}+
+ cmm/CmmLive.hs view
@@ -0,0 +1,88 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE ScopedTypeVariables #-}++module CmmLive+ ( CmmLocalLive+ , cmmLocalLiveness+ , cmmGlobalLiveness+ , liveLattice+ , gen_kill+ )+where++import DynFlags+import BlockId+import Cmm+import PprCmmExpr ()+import Hoopl++import Maybes+import Outputable++-----------------------------------------------------------------------------+-- Calculating what variables are live on entry to a basic block+-----------------------------------------------------------------------------++-- | The variables live on entry to a block+type CmmLive r = RegSet r+type CmmLocalLive = CmmLive LocalReg++-- | The dataflow lattice+liveLattice :: Ord r => DataflowLattice (CmmLive r)+{-# SPECIALIZE liveLattice :: DataflowLattice (CmmLive LocalReg) #-}+{-# SPECIALIZE liveLattice :: DataflowLattice (CmmLive GlobalReg) #-}+liveLattice = DataflowLattice emptyRegSet add+ where+ add (OldFact old) (NewFact new) =+ let !join = plusRegSet old new+ in changedIf (sizeRegSet join > sizeRegSet old) join++-- | A mapping from block labels to the variables live on entry+type BlockEntryLiveness r = LabelMap (CmmLive r)++-----------------------------------------------------------------------------+-- | Calculated liveness info for a CmmGraph+-----------------------------------------------------------------------------++cmmLocalLiveness :: DynFlags -> CmmGraph -> BlockEntryLiveness LocalReg+cmmLocalLiveness dflags graph =+ check $ analyzeCmmBwd liveLattice (xferLive dflags) graph mapEmpty+ where+ entry = g_entry graph+ check facts =+ noLiveOnEntry entry (expectJust "check" $ mapLookup entry facts) facts++cmmGlobalLiveness :: DynFlags -> CmmGraph -> BlockEntryLiveness GlobalReg+cmmGlobalLiveness dflags graph =+ analyzeCmmBwd liveLattice (xferLive dflags) graph mapEmpty++-- | On entry to the procedure, there had better not be any LocalReg's live-in.+noLiveOnEntry :: BlockId -> CmmLive LocalReg -> a -> a+noLiveOnEntry bid in_fact x =+ if nullRegSet in_fact then x+ else pprPanic "LocalReg's live-in to graph" (ppr bid <+> ppr in_fact)++gen_kill+ :: (DefinerOfRegs r n, UserOfRegs r n)+ => DynFlags -> n -> CmmLive r -> CmmLive r+gen_kill dflags node set =+ let !afterKill = foldRegsDefd dflags deleteFromRegSet set node+ in foldRegsUsed dflags extendRegSet afterKill node+{-# INLINE gen_kill #-}++xferLive+ :: forall r.+ ( UserOfRegs r (CmmNode O O)+ , DefinerOfRegs r (CmmNode O O)+ , UserOfRegs r (CmmNode O C)+ , DefinerOfRegs r (CmmNode O C)+ )+ => DynFlags -> TransferFun (CmmLive r)+xferLive dflags (BlockCC eNode middle xNode) fBase =+ let joined = gen_kill dflags xNode $! joinOutFacts liveLattice xNode fBase+ !result = foldNodesBwdOO (gen_kill dflags) middle joined+ in mapSingleton (entryLabel eNode) result+{-# SPECIALIZE xferLive :: DynFlags -> TransferFun (CmmLive LocalReg) #-}+{-# SPECIALIZE xferLive :: DynFlags -> TransferFun (CmmLive GlobalReg) #-}
+ cmm/CmmMachOp.hs view
@@ -0,0 +1,619 @@+{-# LANGUAGE CPP #-}++module CmmMachOp+ ( MachOp(..)+ , pprMachOp, isCommutableMachOp, isAssociativeMachOp+ , isComparisonMachOp, maybeIntComparison, machOpResultType+ , machOpArgReps, maybeInvertComparison++ -- MachOp builders+ , mo_wordAdd, mo_wordSub, mo_wordEq, mo_wordNe,mo_wordMul, mo_wordSQuot+ , mo_wordSRem, mo_wordSNeg, mo_wordUQuot, mo_wordURem+ , mo_wordSGe, mo_wordSLe, mo_wordSGt, mo_wordSLt, mo_wordUGe+ , mo_wordULe, mo_wordUGt, mo_wordULt+ , mo_wordAnd, mo_wordOr, mo_wordXor, mo_wordNot+ , mo_wordShl, mo_wordSShr, mo_wordUShr+ , mo_u_8To32, mo_s_8To32, mo_u_16To32, mo_s_16To32+ , mo_u_8ToWord, mo_s_8ToWord, mo_u_16ToWord, mo_s_16ToWord+ , mo_u_32ToWord, mo_s_32ToWord+ , mo_32To8, mo_32To16, mo_WordTo8, mo_WordTo16, mo_WordTo32, mo_WordTo64++ -- CallishMachOp+ , CallishMachOp(..), callishMachOpHints+ , pprCallishMachOp+ , machOpMemcpyishAlign++ -- Atomic read-modify-write+ , AtomicMachOp(..)+ )+where++#include "HsVersions.h"++import CmmType+import Outputable+import DynFlags++-----------------------------------------------------------------------------+-- MachOp+-----------------------------------------------------------------------------++{- |+Machine-level primops; ones which we can reasonably delegate to the+native code generators to handle.++Most operations are parameterised by the 'Width' that they operate on.+Some operations have separate signed and unsigned versions, and float+and integer versions.+-}++data MachOp+ -- Integer operations (insensitive to signed/unsigned)+ = MO_Add Width+ | MO_Sub Width+ | MO_Eq Width+ | MO_Ne Width+ | MO_Mul Width -- low word of multiply++ -- Signed multiply/divide+ | MO_S_MulMayOflo Width -- nonzero if signed multiply overflows+ | MO_S_Quot Width -- signed / (same semantics as IntQuotOp)+ | MO_S_Rem Width -- signed % (same semantics as IntRemOp)+ | MO_S_Neg Width -- unary -++ -- Unsigned multiply/divide+ | MO_U_MulMayOflo Width -- nonzero if unsigned multiply overflows+ | MO_U_Quot Width -- unsigned / (same semantics as WordQuotOp)+ | MO_U_Rem Width -- unsigned % (same semantics as WordRemOp)++ -- Signed comparisons+ | MO_S_Ge Width+ | MO_S_Le Width+ | MO_S_Gt Width+ | MO_S_Lt Width++ -- Unsigned comparisons+ | MO_U_Ge Width+ | MO_U_Le Width+ | MO_U_Gt Width+ | MO_U_Lt Width++ -- Floating point arithmetic+ | MO_F_Add Width+ | MO_F_Sub Width+ | MO_F_Neg Width -- unary -+ | MO_F_Mul Width+ | MO_F_Quot Width++ -- Floating point comparison+ | MO_F_Eq Width+ | MO_F_Ne Width+ | MO_F_Ge Width+ | MO_F_Le Width+ | MO_F_Gt Width+ | MO_F_Lt Width++ -- Bitwise operations. Not all of these may be supported+ -- at all sizes, and only integral Widths are valid.+ | MO_And Width+ | MO_Or Width+ | MO_Xor Width+ | MO_Not Width+ | MO_Shl Width+ | MO_U_Shr Width -- unsigned shift right+ | MO_S_Shr Width -- signed shift right++ -- Conversions. Some of these will be NOPs.+ -- Floating-point conversions use the signed variant.+ | MO_SF_Conv Width Width -- Signed int -> Float+ | MO_FS_Conv Width Width -- Float -> Signed int+ | MO_SS_Conv Width Width -- Signed int -> Signed int+ | MO_UU_Conv Width Width -- unsigned int -> unsigned int+ | MO_FF_Conv Width Width -- Float -> Float++ -- Vector element insertion and extraction operations+ | MO_V_Insert Length Width -- Insert scalar into vector+ | MO_V_Extract Length Width -- Extract scalar from vector++ -- Integer vector operations+ | MO_V_Add Length Width+ | MO_V_Sub Length Width+ | MO_V_Mul Length Width++ -- Signed vector multiply/divide+ | MO_VS_Quot Length Width+ | MO_VS_Rem Length Width+ | MO_VS_Neg Length Width++ -- Unsigned vector multiply/divide+ | MO_VU_Quot Length Width+ | MO_VU_Rem Length Width++ -- Floting point vector element insertion and extraction operations+ | MO_VF_Insert Length Width -- Insert scalar into vector+ | MO_VF_Extract Length Width -- Extract scalar from vector++ -- Floating point vector operations+ | MO_VF_Add Length Width+ | MO_VF_Sub Length Width+ | MO_VF_Neg Length Width -- unary -+ | MO_VF_Mul Length Width+ | MO_VF_Quot Length Width+ deriving (Eq, Show)++pprMachOp :: MachOp -> SDoc+pprMachOp mo = text (show mo)++++-- -----------------------------------------------------------------------------+-- Some common MachReps++-- A 'wordRep' is a machine word on the target architecture+-- Specifically, it is the size of an Int#, Word#, Addr#+-- and the unit of allocation on the stack and the heap+-- Any pointer is also guaranteed to be a wordRep.++mo_wordAdd, mo_wordSub, mo_wordEq, mo_wordNe,mo_wordMul, mo_wordSQuot+ , mo_wordSRem, mo_wordSNeg, mo_wordUQuot, mo_wordURem+ , mo_wordSGe, mo_wordSLe, mo_wordSGt, mo_wordSLt, mo_wordUGe+ , mo_wordULe, mo_wordUGt, mo_wordULt+ , mo_wordAnd, mo_wordOr, mo_wordXor, mo_wordNot, mo_wordShl, mo_wordSShr, mo_wordUShr+ , mo_u_8ToWord, mo_s_8ToWord, mo_u_16ToWord, mo_s_16ToWord, mo_u_32ToWord, mo_s_32ToWord+ , mo_WordTo8, mo_WordTo16, mo_WordTo32, mo_WordTo64+ :: DynFlags -> MachOp++mo_u_8To32, mo_s_8To32, mo_u_16To32, mo_s_16To32+ , mo_32To8, mo_32To16+ :: MachOp++mo_wordAdd dflags = MO_Add (wordWidth dflags)+mo_wordSub dflags = MO_Sub (wordWidth dflags)+mo_wordEq dflags = MO_Eq (wordWidth dflags)+mo_wordNe dflags = MO_Ne (wordWidth dflags)+mo_wordMul dflags = MO_Mul (wordWidth dflags)+mo_wordSQuot dflags = MO_S_Quot (wordWidth dflags)+mo_wordSRem dflags = MO_S_Rem (wordWidth dflags)+mo_wordSNeg dflags = MO_S_Neg (wordWidth dflags)+mo_wordUQuot dflags = MO_U_Quot (wordWidth dflags)+mo_wordURem dflags = MO_U_Rem (wordWidth dflags)++mo_wordSGe dflags = MO_S_Ge (wordWidth dflags)+mo_wordSLe dflags = MO_S_Le (wordWidth dflags)+mo_wordSGt dflags = MO_S_Gt (wordWidth dflags)+mo_wordSLt dflags = MO_S_Lt (wordWidth dflags)++mo_wordUGe dflags = MO_U_Ge (wordWidth dflags)+mo_wordULe dflags = MO_U_Le (wordWidth dflags)+mo_wordUGt dflags = MO_U_Gt (wordWidth dflags)+mo_wordULt dflags = MO_U_Lt (wordWidth dflags)++mo_wordAnd dflags = MO_And (wordWidth dflags)+mo_wordOr dflags = MO_Or (wordWidth dflags)+mo_wordXor dflags = MO_Xor (wordWidth dflags)+mo_wordNot dflags = MO_Not (wordWidth dflags)+mo_wordShl dflags = MO_Shl (wordWidth dflags)+mo_wordSShr dflags = MO_S_Shr (wordWidth dflags)+mo_wordUShr dflags = MO_U_Shr (wordWidth dflags)++mo_u_8To32 = MO_UU_Conv W8 W32+mo_s_8To32 = MO_SS_Conv W8 W32+mo_u_16To32 = MO_UU_Conv W16 W32+mo_s_16To32 = MO_SS_Conv W16 W32++mo_u_8ToWord dflags = MO_UU_Conv W8 (wordWidth dflags)+mo_s_8ToWord dflags = MO_SS_Conv W8 (wordWidth dflags)+mo_u_16ToWord dflags = MO_UU_Conv W16 (wordWidth dflags)+mo_s_16ToWord dflags = MO_SS_Conv W16 (wordWidth dflags)+mo_s_32ToWord dflags = MO_SS_Conv W32 (wordWidth dflags)+mo_u_32ToWord dflags = MO_UU_Conv W32 (wordWidth dflags)++mo_WordTo8 dflags = MO_UU_Conv (wordWidth dflags) W8+mo_WordTo16 dflags = MO_UU_Conv (wordWidth dflags) W16+mo_WordTo32 dflags = MO_UU_Conv (wordWidth dflags) W32+mo_WordTo64 dflags = MO_UU_Conv (wordWidth dflags) W64++mo_32To8 = MO_UU_Conv W32 W8+mo_32To16 = MO_UU_Conv W32 W16+++-- ----------------------------------------------------------------------------+-- isCommutableMachOp++{- |+Returns 'True' if the MachOp has commutable arguments. This is used+in the platform-independent Cmm optimisations.++If in doubt, return 'False'. This generates worse code on the+native routes, but is otherwise harmless.+-}+isCommutableMachOp :: MachOp -> Bool+isCommutableMachOp mop =+ case mop of+ MO_Add _ -> True+ MO_Eq _ -> True+ MO_Ne _ -> True+ MO_Mul _ -> True+ MO_S_MulMayOflo _ -> True+ MO_U_MulMayOflo _ -> True+ MO_And _ -> True+ MO_Or _ -> True+ MO_Xor _ -> True+ MO_F_Add _ -> True+ MO_F_Mul _ -> True+ _other -> False++-- ----------------------------------------------------------------------------+-- isAssociativeMachOp++{- |+Returns 'True' if the MachOp is associative (i.e. @(x+y)+z == x+(y+z)@)+This is used in the platform-independent Cmm optimisations.++If in doubt, return 'False'. This generates worse code on the+native routes, but is otherwise harmless.+-}+isAssociativeMachOp :: MachOp -> Bool+isAssociativeMachOp mop =+ case mop of+ MO_Add {} -> True -- NB: does not include+ MO_Mul {} -> True -- floatint point!+ MO_And {} -> True+ MO_Or {} -> True+ MO_Xor {} -> True+ _other -> False+++-- ----------------------------------------------------------------------------+-- isComparisonMachOp++{- |+Returns 'True' if the MachOp is a comparison.++If in doubt, return False. This generates worse code on the+native routes, but is otherwise harmless.+-}+isComparisonMachOp :: MachOp -> Bool+isComparisonMachOp mop =+ case mop of+ MO_Eq _ -> True+ MO_Ne _ -> True+ MO_S_Ge _ -> True+ MO_S_Le _ -> True+ MO_S_Gt _ -> True+ MO_S_Lt _ -> True+ MO_U_Ge _ -> True+ MO_U_Le _ -> True+ MO_U_Gt _ -> True+ MO_U_Lt _ -> True+ MO_F_Eq {} -> True+ MO_F_Ne {} -> True+ MO_F_Ge {} -> True+ MO_F_Le {} -> True+ MO_F_Gt {} -> True+ MO_F_Lt {} -> True+ _other -> False++{- |+Returns @Just w@ if the operation is an integer comparison with width+@w@, or @Nothing@ otherwise.+-}+maybeIntComparison :: MachOp -> Maybe Width+maybeIntComparison mop =+ case mop of+ MO_Eq w -> Just w+ MO_Ne w -> Just w+ MO_S_Ge w -> Just w+ MO_S_Le w -> Just w+ MO_S_Gt w -> Just w+ MO_S_Lt w -> Just w+ MO_U_Ge w -> Just w+ MO_U_Le w -> Just w+ MO_U_Gt w -> Just w+ MO_U_Lt w -> Just w+ _ -> Nothing++-- -----------------------------------------------------------------------------+-- Inverting conditions++-- Sometimes it's useful to be able to invert the sense of a+-- condition. Not all conditional tests are invertible: in+-- particular, floating point conditionals cannot be inverted, because+-- there exist floating-point values which return False for both senses+-- of a condition (eg. !(NaN > NaN) && !(NaN /<= NaN)).++maybeInvertComparison :: MachOp -> Maybe MachOp+maybeInvertComparison op+ = case op of -- None of these Just cases include floating point+ MO_Eq r -> Just (MO_Ne r)+ MO_Ne r -> Just (MO_Eq r)+ MO_U_Lt r -> Just (MO_U_Ge r)+ MO_U_Gt r -> Just (MO_U_Le r)+ MO_U_Le r -> Just (MO_U_Gt r)+ MO_U_Ge r -> Just (MO_U_Lt r)+ MO_S_Lt r -> Just (MO_S_Ge r)+ MO_S_Gt r -> Just (MO_S_Le r)+ MO_S_Le r -> Just (MO_S_Gt r)+ MO_S_Ge r -> Just (MO_S_Lt r)+ _other -> Nothing++-- ----------------------------------------------------------------------------+-- machOpResultType++{- |+Returns the MachRep of the result of a MachOp.+-}+machOpResultType :: DynFlags -> MachOp -> [CmmType] -> CmmType+machOpResultType dflags mop tys =+ case mop of+ MO_Add {} -> ty1 -- Preserve GC-ptr-hood+ MO_Sub {} -> ty1 -- of first arg+ MO_Mul r -> cmmBits r+ MO_S_MulMayOflo r -> cmmBits r+ MO_S_Quot r -> cmmBits r+ MO_S_Rem r -> cmmBits r+ MO_S_Neg r -> cmmBits r+ MO_U_MulMayOflo r -> cmmBits r+ MO_U_Quot r -> cmmBits r+ MO_U_Rem r -> cmmBits r++ MO_Eq {} -> comparisonResultRep dflags+ MO_Ne {} -> comparisonResultRep dflags+ MO_S_Ge {} -> comparisonResultRep dflags+ MO_S_Le {} -> comparisonResultRep dflags+ MO_S_Gt {} -> comparisonResultRep dflags+ MO_S_Lt {} -> comparisonResultRep dflags++ MO_U_Ge {} -> comparisonResultRep dflags+ MO_U_Le {} -> comparisonResultRep dflags+ MO_U_Gt {} -> comparisonResultRep dflags+ MO_U_Lt {} -> comparisonResultRep dflags++ MO_F_Add r -> cmmFloat r+ MO_F_Sub r -> cmmFloat r+ MO_F_Mul r -> cmmFloat r+ MO_F_Quot r -> cmmFloat r+ MO_F_Neg r -> cmmFloat r+ MO_F_Eq {} -> comparisonResultRep dflags+ MO_F_Ne {} -> comparisonResultRep dflags+ MO_F_Ge {} -> comparisonResultRep dflags+ MO_F_Le {} -> comparisonResultRep dflags+ MO_F_Gt {} -> comparisonResultRep dflags+ MO_F_Lt {} -> comparisonResultRep dflags++ MO_And {} -> ty1 -- Used for pointer masking+ MO_Or {} -> ty1+ MO_Xor {} -> ty1+ MO_Not r -> cmmBits r+ MO_Shl r -> cmmBits r+ MO_U_Shr r -> cmmBits r+ MO_S_Shr r -> cmmBits r++ MO_SS_Conv _ to -> cmmBits to+ MO_UU_Conv _ to -> cmmBits to+ MO_FS_Conv _ to -> cmmBits to+ MO_SF_Conv _ to -> cmmFloat to+ MO_FF_Conv _ to -> cmmFloat to++ MO_V_Insert l w -> cmmVec l (cmmBits w)+ MO_V_Extract _ w -> cmmBits w++ MO_V_Add l w -> cmmVec l (cmmBits w)+ MO_V_Sub l w -> cmmVec l (cmmBits w)+ MO_V_Mul l w -> cmmVec l (cmmBits w)++ MO_VS_Quot l w -> cmmVec l (cmmBits w)+ MO_VS_Rem l w -> cmmVec l (cmmBits w)+ MO_VS_Neg l w -> cmmVec l (cmmBits w)++ MO_VU_Quot l w -> cmmVec l (cmmBits w)+ MO_VU_Rem l w -> cmmVec l (cmmBits w)++ MO_VF_Insert l w -> cmmVec l (cmmFloat w)+ MO_VF_Extract _ w -> cmmFloat w++ MO_VF_Add l w -> cmmVec l (cmmFloat w)+ MO_VF_Sub l w -> cmmVec l (cmmFloat w)+ MO_VF_Mul l w -> cmmVec l (cmmFloat w)+ MO_VF_Quot l w -> cmmVec l (cmmFloat w)+ MO_VF_Neg l w -> cmmVec l (cmmFloat w)+ where+ (ty1:_) = tys++comparisonResultRep :: DynFlags -> CmmType+comparisonResultRep = bWord -- is it?+++-- -----------------------------------------------------------------------------+-- machOpArgReps++-- | This function is used for debugging only: we can check whether an+-- application of a MachOp is "type-correct" by checking that the MachReps of+-- its arguments are the same as the MachOp expects. This is used when+-- linting a CmmExpr.++machOpArgReps :: DynFlags -> MachOp -> [Width]+machOpArgReps dflags op =+ case op of+ MO_Add r -> [r,r]+ MO_Sub r -> [r,r]+ MO_Eq r -> [r,r]+ MO_Ne r -> [r,r]+ MO_Mul r -> [r,r]+ MO_S_MulMayOflo r -> [r,r]+ MO_S_Quot r -> [r,r]+ MO_S_Rem r -> [r,r]+ MO_S_Neg r -> [r]+ MO_U_MulMayOflo r -> [r,r]+ MO_U_Quot r -> [r,r]+ MO_U_Rem r -> [r,r]++ MO_S_Ge r -> [r,r]+ MO_S_Le r -> [r,r]+ MO_S_Gt r -> [r,r]+ MO_S_Lt r -> [r,r]++ MO_U_Ge r -> [r,r]+ MO_U_Le r -> [r,r]+ MO_U_Gt r -> [r,r]+ MO_U_Lt r -> [r,r]++ MO_F_Add r -> [r,r]+ MO_F_Sub r -> [r,r]+ MO_F_Mul r -> [r,r]+ MO_F_Quot r -> [r,r]+ MO_F_Neg r -> [r]+ MO_F_Eq r -> [r,r]+ MO_F_Ne r -> [r,r]+ MO_F_Ge r -> [r,r]+ MO_F_Le r -> [r,r]+ MO_F_Gt r -> [r,r]+ MO_F_Lt r -> [r,r]++ MO_And r -> [r,r]+ MO_Or r -> [r,r]+ MO_Xor r -> [r,r]+ MO_Not r -> [r]+ MO_Shl r -> [r, wordWidth dflags]+ MO_U_Shr r -> [r, wordWidth dflags]+ MO_S_Shr r -> [r, wordWidth dflags]++ MO_SS_Conv from _ -> [from]+ MO_UU_Conv from _ -> [from]+ MO_SF_Conv from _ -> [from]+ MO_FS_Conv from _ -> [from]+ MO_FF_Conv from _ -> [from]++ MO_V_Insert l r -> [typeWidth (vec l (cmmBits r)),r,wordWidth dflags]+ MO_V_Extract l r -> [typeWidth (vec l (cmmBits r)),wordWidth dflags]++ MO_V_Add _ r -> [r,r]+ MO_V_Sub _ r -> [r,r]+ MO_V_Mul _ r -> [r,r]++ MO_VS_Quot _ r -> [r,r]+ MO_VS_Rem _ r -> [r,r]+ MO_VS_Neg _ r -> [r]++ MO_VU_Quot _ r -> [r,r]+ MO_VU_Rem _ r -> [r,r]++ MO_VF_Insert l r -> [typeWidth (vec l (cmmFloat r)),r,wordWidth dflags]+ MO_VF_Extract l r -> [typeWidth (vec l (cmmFloat r)),wordWidth dflags]++ MO_VF_Add _ r -> [r,r]+ MO_VF_Sub _ r -> [r,r]+ MO_VF_Mul _ r -> [r,r]+ MO_VF_Quot _ r -> [r,r]+ MO_VF_Neg _ r -> [r]++-----------------------------------------------------------------------------+-- CallishMachOp+-----------------------------------------------------------------------------++-- CallishMachOps tend to be implemented by foreign calls in some backends,+-- so we separate them out. In Cmm, these can only occur in a+-- statement position, in contrast to an ordinary MachOp which can occur+-- anywhere in an expression.+data CallishMachOp+ = MO_F64_Pwr+ | MO_F64_Sin+ | MO_F64_Cos+ | MO_F64_Tan+ | MO_F64_Sinh+ | MO_F64_Cosh+ | MO_F64_Tanh+ | MO_F64_Asin+ | MO_F64_Acos+ | MO_F64_Atan+ | MO_F64_Log+ | MO_F64_Exp+ | MO_F64_Fabs+ | MO_F64_Sqrt+ | MO_F32_Pwr+ | MO_F32_Sin+ | MO_F32_Cos+ | MO_F32_Tan+ | MO_F32_Sinh+ | MO_F32_Cosh+ | MO_F32_Tanh+ | MO_F32_Asin+ | MO_F32_Acos+ | MO_F32_Atan+ | MO_F32_Log+ | MO_F32_Exp+ | MO_F32_Fabs+ | MO_F32_Sqrt++ | MO_UF_Conv Width++ | MO_S_QuotRem Width+ | MO_U_QuotRem Width+ | MO_U_QuotRem2 Width+ | MO_Add2 Width+ | MO_SubWordC Width+ | MO_AddIntC Width+ | MO_SubIntC Width+ | MO_U_Mul2 Width++ | MO_WriteBarrier+ | MO_Touch -- Keep variables live (when using interior pointers)++ -- Prefetch+ | MO_Prefetch_Data Int -- Prefetch hint. May change program performance but not+ -- program behavior.+ -- the Int can be 0-3. Needs to be known at compile time+ -- to interact with code generation correctly.+ -- TODO: add support for prefetch WRITES,+ -- currently only exposes prefetch reads, which+ -- would the majority of use cases in ghc anyways+++ -- These three MachOps are parameterised by the known alignment+ -- of the destination and source (for memcpy/memmove) pointers.+ -- This information may be used for optimisation in backends.+ | MO_Memcpy Int+ | MO_Memset Int+ | MO_Memmove Int++ | MO_PopCnt Width+ | MO_Clz Width+ | MO_Ctz Width++ | MO_BSwap Width++ -- Atomic read-modify-write.+ | MO_AtomicRMW Width AtomicMachOp+ | MO_AtomicRead Width+ | MO_AtomicWrite Width+ | MO_Cmpxchg Width+ deriving (Eq, Show)++-- | The operation to perform atomically.+data AtomicMachOp =+ AMO_Add+ | AMO_Sub+ | AMO_And+ | AMO_Nand+ | AMO_Or+ | AMO_Xor+ deriving (Eq, Show)++pprCallishMachOp :: CallishMachOp -> SDoc+pprCallishMachOp mo = text (show mo)++callishMachOpHints :: CallishMachOp -> ([ForeignHint], [ForeignHint])+callishMachOpHints op = case op of+ MO_Memcpy _ -> ([], [AddrHint,AddrHint,NoHint])+ MO_Memset _ -> ([], [AddrHint,NoHint,NoHint])+ MO_Memmove _ -> ([], [AddrHint,AddrHint,NoHint])+ _ -> ([],[])+ -- empty lists indicate NoHint++-- | The alignment of a 'memcpy'-ish operation.+machOpMemcpyishAlign :: CallishMachOp -> Maybe Int+machOpMemcpyishAlign op = case op of+ MO_Memcpy align -> Just align+ MO_Memset align -> Just align+ MO_Memmove align -> Just align+ _ -> Nothing
+ cmm/CmmMonad.hs view
@@ -0,0 +1,58 @@+-----------------------------------------------------------------------------+-- A Parser monad with access to the 'DynFlags'.+--+-- The 'P' monad only has access to the subset of of 'DynFlags'+-- required for parsing Haskell.++-- The parser for C-- requires access to a lot more of the 'DynFlags',+-- so 'PD' provides access to 'DynFlags' via a 'HasDynFlags' instance.+-----------------------------------------------------------------------------+{-# LANGUAGE CPP #-}+module CmmMonad (+ PD(..)+ , liftP+ ) where++import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif++import DynFlags+import Lexer++newtype PD a = PD { unPD :: DynFlags -> PState -> ParseResult a }++instance Functor PD where+ fmap = liftM++instance Applicative PD where+ pure = returnPD+ (<*>) = ap++instance Monad PD where+ (>>=) = thenPD+ fail = failPD++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail PD where+ fail = failPD+#endif++liftP :: P a -> PD a+liftP (P f) = PD $ \_ s -> f s++returnPD :: a -> PD a+returnPD = liftP . return++thenPD :: PD a -> (a -> PD b) -> PD b+(PD m) `thenPD` k = PD $ \d s ->+ case m d s of+ POk s1 a -> unPD (k a) d s1+ PFailed span err -> PFailed span err++failPD :: String -> PD a+failPD = liftP . fail++instance HasDynFlags PD where+ getDynFlags = PD $ \d s -> POk s d
+ cmm/CmmNode.hs view
@@ -0,0 +1,700 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE ExplicitForAll #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE UndecidableInstances #-}++-- CmmNode type for representation using Hoopl graphs.++module CmmNode (+ CmmNode(..), CmmFormal, CmmActual, CmmTickish,+ UpdFrameOffset, Convention(..),+ ForeignConvention(..), ForeignTarget(..), foreignTargetHints,+ CmmReturnInfo(..),+ mapExp, mapExpDeep, wrapRecExp, foldExp, foldExpDeep, wrapRecExpf,+ mapExpM, mapExpDeepM, wrapRecExpM, mapSuccessors,++ -- * Tick scopes+ CmmTickScope(..), isTickSubScope, combineTickScopes,+ ) where++import CodeGen.Platform+import CmmExpr+import CmmSwitch+import DynFlags+import FastString+import ForeignCall+import Outputable+import SMRep+import CoreSyn (Tickish)+import qualified Unique as U++import Compiler.Hoopl+import Data.Maybe+import Data.List (tails,sortBy)+import Prelude hiding (succ)+import Unique (nonDetCmpUnique)+import Util+++------------------------+-- CmmNode++#define ULabel {-# UNPACK #-} !Label++data CmmNode e x where+ CmmEntry :: ULabel -> CmmTickScope -> CmmNode C O++ CmmComment :: FastString -> CmmNode O O++ -- Tick annotation, covering Cmm code in our tick scope. We only+ -- expect non-code @Tickish@ at this point (e.g. @SourceNote@).+ -- See Note [CmmTick scoping details]+ CmmTick :: !CmmTickish -> CmmNode O O++ -- Unwind pseudo-instruction, encoding stack unwinding+ -- instructions for a debugger. This describes how to reconstruct+ -- the "old" value of a register if we want to navigate the stack+ -- up one frame. Having unwind information for @Sp@ will allow the+ -- debugger to "walk" the stack.+ --+ -- See Note [What is this unwinding business?] in Debug+ CmmUnwind :: [(GlobalReg, Maybe CmmExpr)] -> CmmNode O O++ CmmAssign :: !CmmReg -> !CmmExpr -> CmmNode O O+ -- Assign to register++ CmmStore :: !CmmExpr -> !CmmExpr -> CmmNode O O+ -- Assign to memory location. Size is+ -- given by cmmExprType of the rhs.++ CmmUnsafeForeignCall :: -- An unsafe foreign call;+ -- see Note [Foreign calls]+ -- Like a "fat machine instruction"; can occur+ -- in the middle of a block+ ForeignTarget -> -- call target+ [CmmFormal] -> -- zero or more results+ [CmmActual] -> -- zero or more arguments+ CmmNode O O+ -- Semantics: clobbers any GlobalRegs for which callerSaves r == True+ -- See Note [Unsafe foreign calls clobber caller-save registers]+ --+ -- Invariant: the arguments and the ForeignTarget must not+ -- mention any registers for which CodeGen.Platform.callerSaves+ -- is True. See Note [Register Parameter Passing].++ CmmBranch :: ULabel -> CmmNode O C+ -- Goto another block in the same procedure++ CmmCondBranch :: { -- conditional branch+ cml_pred :: CmmExpr,+ cml_true, cml_false :: ULabel,+ cml_likely :: Maybe Bool -- likely result of the conditional,+ -- if known+ } -> CmmNode O C++ CmmSwitch+ :: CmmExpr -- Scrutinee, of some integral type+ -> SwitchTargets -- Cases. See [Note SwitchTargets]+ -> CmmNode O C++ CmmCall :: { -- A native call or tail call+ cml_target :: CmmExpr, -- never a CmmPrim to a CallishMachOp!++ cml_cont :: Maybe Label,+ -- Label of continuation (Nothing for return or tail call)+ --+ -- Note [Continuation BlockId]: these BlockIds are called+ -- Continuation BlockIds, and are the only BlockIds that can+ -- occur in CmmExprs, namely as (CmmLit (CmmBlock b)) or+ -- (CmmStackSlot (Young b) _).++ cml_args_regs :: [GlobalReg],+ -- The argument GlobalRegs (Rx, Fx, Dx, Lx) that are passed+ -- to the call. This is essential information for the+ -- native code generator's register allocator; without+ -- knowing which GlobalRegs are live it has to assume that+ -- they are all live. This list should only include+ -- GlobalRegs that are mapped to real machine registers on+ -- the target platform.++ cml_args :: ByteOff,+ -- Byte offset, from the *old* end of the Area associated with+ -- the Label (if cml_cont = Nothing, then Old area), of+ -- youngest outgoing arg. Set the stack pointer to this before+ -- transferring control.+ -- (NB: an update frame might also have been stored in the Old+ -- area, but it'll be in an older part than the args.)++ cml_ret_args :: ByteOff,+ -- For calls *only*, the byte offset for youngest returned value+ -- This is really needed at the *return* point rather than here+ -- at the call, but in practice it's convenient to record it here.++ cml_ret_off :: ByteOff+ -- For calls *only*, the byte offset of the base of the frame that+ -- must be described by the info table for the return point.+ -- The older words are an update frames, which have their own+ -- info-table and layout information++ -- From a liveness point of view, the stack words older than+ -- cml_ret_off are treated as live, even if the sequel of+ -- the call goes into a loop.+ } -> CmmNode O C++ CmmForeignCall :: { -- A safe foreign call; see Note [Foreign calls]+ -- Always the last node of a block+ tgt :: ForeignTarget, -- call target and convention+ res :: [CmmFormal], -- zero or more results+ args :: [CmmActual], -- zero or more arguments; see Note [Register parameter passing]+ succ :: ULabel, -- Label of continuation+ ret_args :: ByteOff, -- same as cml_ret_args+ ret_off :: ByteOff, -- same as cml_ret_off+ intrbl:: Bool -- whether or not the call is interruptible+ } -> CmmNode O C++{- Note [Foreign calls]+~~~~~~~~~~~~~~~~~~~~~~~+A CmmUnsafeForeignCall is used for *unsafe* foreign calls;+a CmmForeignCall call is used for *safe* foreign calls.++Unsafe ones are mostly easy: think of them as a "fat machine+instruction". In particular, they do *not* kill all live registers,+just the registers they return to (there was a bit of code in GHC that+conservatively assumed otherwise.) However, see [Register parameter passing].++Safe ones are trickier. A safe foreign call+ r = f(x)+ultimately expands to+ push "return address" -- Never used to return to;+ -- just points an info table+ save registers into TSO+ call suspendThread+ r = f(x) -- Make the call+ call resumeThread+ restore registers+ pop "return address"+We cannot "lower" a safe foreign call to this sequence of Cmms, because+after we've saved Sp all the Cmm optimiser's assumptions are broken.++Note that a safe foreign call needs an info table.++So Safe Foreign Calls must remain as last nodes until the stack is+made manifest in CmmLayoutStack, where they are lowered into the above+sequence.+-}++{- Note [Unsafe foreign calls clobber caller-save registers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++A foreign call is defined to clobber any GlobalRegs that are mapped to+caller-saves machine registers (according to the prevailing C ABI).+StgCmmUtils.callerSaves tells you which GlobalRegs are caller-saves.++This is a design choice that makes it easier to generate code later.+We could instead choose to say that foreign calls do *not* clobber+caller-saves regs, but then we would have to figure out which regs+were live across the call later and insert some saves/restores.++Furthermore when we generate code we never have any GlobalRegs live+across a call, because they are always copied-in to LocalRegs and+copied-out again before making a call/jump. So all we have to do is+avoid any code motion that would make a caller-saves GlobalReg live+across a foreign call during subsequent optimisations.+-}++{- Note [Register parameter passing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+On certain architectures, some registers are utilized for parameter+passing in the C calling convention. For example, in x86-64 Linux+convention, rdi, rsi, rdx and rcx (as well as r8 and r9) may be used for+argument passing. These are registers R3-R6, which our generated+code may also be using; as a result, it's necessary to save these+values before doing a foreign call. This is done during initial+code generation in callerSaveVolatileRegs in StgCmmUtils.hs. However,+one result of doing this is that the contents of these registers+may mysteriously change if referenced inside the arguments. This+is dangerous, so you'll need to disable inlining much in the same+way is done in cmm/CmmOpt.hs currently. We should fix this!+-}++---------------------------------------------+-- Eq instance of CmmNode++deriving instance Eq (CmmNode e x)++----------------------------------------------+-- Hoopl instances of CmmNode++instance NonLocal CmmNode where+ entryLabel (CmmEntry l _) = l++ successors (CmmBranch l) = [l]+ successors (CmmCondBranch {cml_true=t, cml_false=f}) = [f, t] -- meets layout constraint+ successors (CmmSwitch _ ids) = switchTargetsToList ids+ successors (CmmCall {cml_cont=l}) = maybeToList l+ successors (CmmForeignCall {succ=l}) = [l]+++--------------------------------------------------+-- Various helper types++type CmmActual = CmmExpr+type CmmFormal = LocalReg++type UpdFrameOffset = ByteOff++-- | A convention maps a list of values (function arguments or return+-- values) to registers or stack locations.+data Convention+ = NativeDirectCall+ -- ^ top-level Haskell functions use @NativeDirectCall@, which+ -- maps arguments to registers starting with R2, according to+ -- how many registers are available on the platform. This+ -- convention ignores R1, because for a top-level function call+ -- the function closure is implicit, and doesn't need to be passed.+ | NativeNodeCall+ -- ^ non-top-level Haskell functions, which pass the address of+ -- the function closure in R1 (regardless of whether R1 is a+ -- real register or not), and the rest of the arguments in+ -- registers or on the stack.+ | NativeReturn+ -- ^ a native return. The convention for returns depends on+ -- how many values are returned: for just one value returned,+ -- the appropriate register is used (R1, F1, etc.). regardless+ -- of whether it is a real register or not. For multiple+ -- values returned, they are mapped to registers or the stack.+ | Slow+ -- ^ Slow entry points: all args pushed on the stack+ | GC+ -- ^ Entry to the garbage collector: uses the node reg!+ -- (TODO: I don't think we need this --SDM)+ deriving( Eq )++data ForeignConvention+ = ForeignConvention+ CCallConv -- Which foreign-call convention+ [ForeignHint] -- Extra info about the args+ [ForeignHint] -- Extra info about the result+ CmmReturnInfo+ deriving Eq++data CmmReturnInfo+ = CmmMayReturn+ | CmmNeverReturns+ deriving ( Eq )++data ForeignTarget -- The target of a foreign call+ = ForeignTarget -- A foreign procedure+ CmmExpr -- Its address+ ForeignConvention -- Its calling convention+ | PrimTarget -- A possibly-side-effecting machine operation+ CallishMachOp -- Which one+ deriving Eq++foreignTargetHints :: ForeignTarget -> ([ForeignHint], [ForeignHint])+foreignTargetHints target+ = ( res_hints ++ repeat NoHint+ , arg_hints ++ repeat NoHint )+ where+ (res_hints, arg_hints) =+ case target of+ PrimTarget op -> callishMachOpHints op+ ForeignTarget _ (ForeignConvention _ arg_hints res_hints _) ->+ (res_hints, arg_hints)++--------------------------------------------------+-- Instances of register and slot users / definers++instance UserOfRegs LocalReg (CmmNode e x) where+ foldRegsUsed dflags f !z n = case n of+ CmmAssign _ expr -> fold f z expr+ CmmStore addr rval -> fold f (fold f z addr) rval+ CmmUnsafeForeignCall t _ args -> fold f (fold f z t) args+ CmmCondBranch expr _ _ _ -> fold f z expr+ CmmSwitch expr _ -> fold f z expr+ CmmCall {cml_target=tgt} -> fold f z tgt+ CmmForeignCall {tgt=tgt, args=args} -> fold f (fold f z tgt) args+ _ -> z+ where fold :: forall a b. UserOfRegs LocalReg a+ => (b -> LocalReg -> b) -> b -> a -> b+ fold f z n = foldRegsUsed dflags f z n++instance UserOfRegs GlobalReg (CmmNode e x) where+ foldRegsUsed dflags f !z n = case n of+ CmmAssign _ expr -> fold f z expr+ CmmStore addr rval -> fold f (fold f z addr) rval+ CmmUnsafeForeignCall t _ args -> fold f (fold f z t) args+ CmmCondBranch expr _ _ _ -> fold f z expr+ CmmSwitch expr _ -> fold f z expr+ CmmCall {cml_target=tgt, cml_args_regs=args} -> fold f (fold f z args) tgt+ CmmForeignCall {tgt=tgt, args=args} -> fold f (fold f z tgt) args+ _ -> z+ where fold :: forall a b. UserOfRegs GlobalReg a+ => (b -> GlobalReg -> b) -> b -> a -> b+ fold f z n = foldRegsUsed dflags f z n++instance (Ord r, UserOfRegs r CmmReg) => UserOfRegs r ForeignTarget where+ -- The (Ord r) in the context is necessary here+ -- See Note [Recursive superclasses] in TcInstDcls+ foldRegsUsed _ _ !z (PrimTarget _) = z+ foldRegsUsed dflags f !z (ForeignTarget e _) = foldRegsUsed dflags f z e++instance DefinerOfRegs LocalReg (CmmNode e x) where+ foldRegsDefd dflags f !z n = case n of+ CmmAssign lhs _ -> fold f z lhs+ CmmUnsafeForeignCall _ fs _ -> fold f z fs+ CmmForeignCall {res=res} -> fold f z res+ _ -> z+ where fold :: forall a b. DefinerOfRegs LocalReg a+ => (b -> LocalReg -> b) -> b -> a -> b+ fold f z n = foldRegsDefd dflags f z n++instance DefinerOfRegs GlobalReg (CmmNode e x) where+ foldRegsDefd dflags f !z n = case n of+ CmmAssign lhs _ -> fold f z lhs+ CmmUnsafeForeignCall tgt _ _ -> fold f z (foreignTargetRegs tgt)+ CmmCall {} -> fold f z activeRegs+ CmmForeignCall {} -> fold f z activeRegs+ -- See Note [Safe foreign calls clobber STG registers]+ _ -> z+ where fold :: forall a b. DefinerOfRegs GlobalReg a+ => (b -> GlobalReg -> b) -> b -> a -> b+ fold f z n = foldRegsDefd dflags f z n++ platform = targetPlatform dflags+ activeRegs = activeStgRegs platform+ activeCallerSavesRegs = filter (callerSaves platform) activeRegs++ foreignTargetRegs (ForeignTarget _ (ForeignConvention _ _ _ CmmNeverReturns)) = []+ foreignTargetRegs _ = activeCallerSavesRegs++-- Note [Safe foreign calls clobber STG registers]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- During stack layout phase every safe foreign call is expanded into a block+-- that contains unsafe foreign call (instead of safe foreign call) and ends+-- with a normal call (See Note [Foreign calls]). This means that we must+-- treat safe foreign call as if it was a normal call (because eventually it+-- will be). This is important if we try to run sinking pass before stack+-- layout phase. Consider this example of what might go wrong (this is cmm+-- code from stablename001 test). Here is code after common block elimination+-- (before stack layout):+--+-- c1q6:+-- _s1pf::P64 = R1;+-- _c1q8::I64 = performMajorGC;+-- I64[(young<c1q9> + 8)] = c1q9;+-- foreign call "ccall" arg hints: [] result hints: [] (_c1q8::I64)(...)+-- returns to c1q9 args: ([]) ress: ([])ret_args: 8ret_off: 8;+-- c1q9:+-- I64[(young<c1qb> + 8)] = c1qb;+-- R1 = _s1pc::P64;+-- call stg_makeStableName#(R1) returns to c1qb, args: 8, res: 8, upd: 8;+--+-- If we run sinking pass now (still before stack layout) we will get this:+--+-- c1q6:+-- I64[(young<c1q9> + 8)] = c1q9;+-- foreign call "ccall" arg hints: [] result hints: [] performMajorGC(...)+-- returns to c1q9 args: ([]) ress: ([])ret_args: 8ret_off: 8;+-- c1q9:+-- I64[(young<c1qb> + 8)] = c1qb;+-- _s1pf::P64 = R1; <------ _s1pf sunk past safe foreign call+-- R1 = _s1pc::P64;+-- call stg_makeStableName#(R1) returns to c1qb, args: 8, res: 8, upd: 8;+--+-- Notice that _s1pf was sunk past a foreign call. When we run stack layout+-- safe call to performMajorGC will be turned into:+--+-- c1q6:+-- _s1pc::P64 = P64[Sp + 8];+-- I64[Sp - 8] = c1q9;+-- Sp = Sp - 8;+-- I64[I64[CurrentTSO + 24] + 16] = Sp;+-- P64[CurrentNursery + 8] = Hp + 8;+-- (_u1qI::I64) = call "ccall" arg hints: [PtrHint,]+-- result hints: [PtrHint] suspendThread(BaseReg, 0);+-- call "ccall" arg hints: [] result hints: [] performMajorGC();+-- (_u1qJ::I64) = call "ccall" arg hints: [PtrHint]+-- result hints: [PtrHint] resumeThread(_u1qI::I64);+-- BaseReg = _u1qJ::I64;+-- _u1qK::P64 = CurrentTSO;+-- _u1qL::P64 = I64[_u1qK::P64 + 24];+-- Sp = I64[_u1qL::P64 + 16];+-- SpLim = _u1qL::P64 + 192;+-- HpAlloc = 0;+-- Hp = I64[CurrentNursery + 8] - 8;+-- HpLim = I64[CurrentNursery] + (%MO_SS_Conv_W32_W64(I32[CurrentNursery + 48]) * 4096 - 1);+-- call (I64[Sp])() returns to c1q9, args: 8, res: 8, upd: 8;+-- c1q9:+-- I64[(young<c1qb> + 8)] = c1qb;+-- _s1pf::P64 = R1; <------ INCORRECT!+-- R1 = _s1pc::P64;+-- call stg_makeStableName#(R1) returns to c1qb, args: 8, res: 8, upd: 8;+--+-- Notice that c1q6 now ends with a call. Sinking _s1pf::P64 = R1 past that+-- call is clearly incorrect. This is what would happen if we assumed that+-- safe foreign call has the same semantics as unsafe foreign call. To prevent+-- this we need to treat safe foreign call as if was normal call.++-----------------------------------+-- mapping Expr in CmmNode++mapForeignTarget :: (CmmExpr -> CmmExpr) -> ForeignTarget -> ForeignTarget+mapForeignTarget exp (ForeignTarget e c) = ForeignTarget (exp e) c+mapForeignTarget _ m@(PrimTarget _) = m++wrapRecExp :: (CmmExpr -> CmmExpr) -> CmmExpr -> CmmExpr+-- Take a transformer on expressions and apply it recursively.+-- (wrapRecExp f e) first recursively applies itself to sub-expressions of e+-- then uses f to rewrite the resulting expression+wrapRecExp f (CmmMachOp op es) = f (CmmMachOp op $ map (wrapRecExp f) es)+wrapRecExp f (CmmLoad addr ty) = f (CmmLoad (wrapRecExp f addr) ty)+wrapRecExp f e = f e++mapExp :: (CmmExpr -> CmmExpr) -> CmmNode e x -> CmmNode e x+mapExp _ f@(CmmEntry{}) = f+mapExp _ m@(CmmComment _) = m+mapExp _ m@(CmmTick _) = m+mapExp f (CmmUnwind regs) = CmmUnwind (map (fmap (fmap f)) regs)+mapExp f (CmmAssign r e) = CmmAssign r (f e)+mapExp f (CmmStore addr e) = CmmStore (f addr) (f e)+mapExp f (CmmUnsafeForeignCall tgt fs as) = CmmUnsafeForeignCall (mapForeignTarget f tgt) fs (map f as)+mapExp _ l@(CmmBranch _) = l+mapExp f (CmmCondBranch e ti fi l) = CmmCondBranch (f e) ti fi l+mapExp f (CmmSwitch e ids) = CmmSwitch (f e) ids+mapExp f n@CmmCall {cml_target=tgt} = n{cml_target = f tgt}+mapExp f (CmmForeignCall tgt fs as succ ret_args updfr intrbl) = CmmForeignCall (mapForeignTarget f tgt) fs (map f as) succ ret_args updfr intrbl++mapExpDeep :: (CmmExpr -> CmmExpr) -> CmmNode e x -> CmmNode e x+mapExpDeep f = mapExp $ wrapRecExp f++------------------------------------------------------------------------+-- mapping Expr in CmmNode, but not performing allocation if no changes++mapForeignTargetM :: (CmmExpr -> Maybe CmmExpr) -> ForeignTarget -> Maybe ForeignTarget+mapForeignTargetM f (ForeignTarget e c) = (\x -> ForeignTarget x c) `fmap` f e+mapForeignTargetM _ (PrimTarget _) = Nothing++wrapRecExpM :: (CmmExpr -> Maybe CmmExpr) -> (CmmExpr -> Maybe CmmExpr)+-- (wrapRecExpM f e) first recursively applies itself to sub-expressions of e+-- then gives f a chance to rewrite the resulting expression+wrapRecExpM f n@(CmmMachOp op es) = maybe (f n) (f . CmmMachOp op) (mapListM (wrapRecExpM f) es)+wrapRecExpM f n@(CmmLoad addr ty) = maybe (f n) (f . flip CmmLoad ty) (wrapRecExpM f addr)+wrapRecExpM f e = f e++mapExpM :: (CmmExpr -> Maybe CmmExpr) -> CmmNode e x -> Maybe (CmmNode e x)+mapExpM _ (CmmEntry{}) = Nothing+mapExpM _ (CmmComment _) = Nothing+mapExpM _ (CmmTick _) = Nothing+mapExpM f (CmmUnwind regs) = CmmUnwind `fmap` mapM (\(r,e) -> mapM f e >>= \e' -> pure (r,e')) regs+mapExpM f (CmmAssign r e) = CmmAssign r `fmap` f e+mapExpM f (CmmStore addr e) = (\[addr', e'] -> CmmStore addr' e') `fmap` mapListM f [addr, e]+mapExpM _ (CmmBranch _) = Nothing+mapExpM f (CmmCondBranch e ti fi l) = (\x -> CmmCondBranch x ti fi l) `fmap` f e+mapExpM f (CmmSwitch e tbl) = (\x -> CmmSwitch x tbl) `fmap` f e+mapExpM f (CmmCall tgt mb_id r o i s) = (\x -> CmmCall x mb_id r o i s) `fmap` f tgt+mapExpM f (CmmUnsafeForeignCall tgt fs as)+ = case mapForeignTargetM f tgt of+ Just tgt' -> Just (CmmUnsafeForeignCall tgt' fs (mapListJ f as))+ Nothing -> (\xs -> CmmUnsafeForeignCall tgt fs xs) `fmap` mapListM f as+mapExpM f (CmmForeignCall tgt fs as succ ret_args updfr intrbl)+ = case mapForeignTargetM f tgt of+ Just tgt' -> Just (CmmForeignCall tgt' fs (mapListJ f as) succ ret_args updfr intrbl)+ Nothing -> (\xs -> CmmForeignCall tgt fs xs succ ret_args updfr intrbl) `fmap` mapListM f as++-- share as much as possible+mapListM :: (a -> Maybe a) -> [a] -> Maybe [a]+mapListM f xs = let (b, r) = mapListT f xs+ in if b then Just r else Nothing++mapListJ :: (a -> Maybe a) -> [a] -> [a]+mapListJ f xs = snd (mapListT f xs)++mapListT :: (a -> Maybe a) -> [a] -> (Bool, [a])+mapListT f xs = foldr g (False, []) (zip3 (tails xs) xs (map f xs))+ where g (_, y, Nothing) (True, ys) = (True, y:ys)+ g (_, _, Just y) (True, ys) = (True, y:ys)+ g (ys', _, Nothing) (False, _) = (False, ys')+ g (_, _, Just y) (False, ys) = (True, y:ys)++mapExpDeepM :: (CmmExpr -> Maybe CmmExpr) -> CmmNode e x -> Maybe (CmmNode e x)+mapExpDeepM f = mapExpM $ wrapRecExpM f++-----------------------------------+-- folding Expr in CmmNode++foldExpForeignTarget :: (CmmExpr -> z -> z) -> ForeignTarget -> z -> z+foldExpForeignTarget exp (ForeignTarget e _) z = exp e z+foldExpForeignTarget _ (PrimTarget _) z = z++-- Take a folder on expressions and apply it recursively.+-- Specifically (wrapRecExpf f e z) deals with CmmMachOp and CmmLoad+-- itself, delegating all the other CmmExpr forms to 'f'.+wrapRecExpf :: (CmmExpr -> z -> z) -> CmmExpr -> z -> z+wrapRecExpf f e@(CmmMachOp _ es) z = foldr (wrapRecExpf f) (f e z) es+wrapRecExpf f e@(CmmLoad addr _) z = wrapRecExpf f addr (f e z)+wrapRecExpf f e z = f e z++foldExp :: (CmmExpr -> z -> z) -> CmmNode e x -> z -> z+foldExp _ (CmmEntry {}) z = z+foldExp _ (CmmComment {}) z = z+foldExp _ (CmmTick {}) z = z+foldExp f (CmmUnwind xs) z = foldr (maybe id f) z (map snd xs)+foldExp f (CmmAssign _ e) z = f e z+foldExp f (CmmStore addr e) z = f addr $ f e z+foldExp f (CmmUnsafeForeignCall t _ as) z = foldr f (foldExpForeignTarget f t z) as+foldExp _ (CmmBranch _) z = z+foldExp f (CmmCondBranch e _ _ _) z = f e z+foldExp f (CmmSwitch e _) z = f e z+foldExp f (CmmCall {cml_target=tgt}) z = f tgt z+foldExp f (CmmForeignCall {tgt=tgt, args=args}) z = foldr f (foldExpForeignTarget f tgt z) args++foldExpDeep :: (CmmExpr -> z -> z) -> CmmNode e x -> z -> z+foldExpDeep f = foldExp (wrapRecExpf f)++-- -----------------------------------------------------------------------------++mapSuccessors :: (Label -> Label) -> CmmNode O C -> CmmNode O C+mapSuccessors f (CmmBranch bid) = CmmBranch (f bid)+mapSuccessors f (CmmCondBranch p y n l) = CmmCondBranch p (f y) (f n) l+mapSuccessors f (CmmSwitch e ids) = CmmSwitch e (mapSwitchTargets f ids)+mapSuccessors _ n = n++-- -----------------------------------------------------------------------------++-- | Tickish in Cmm context (annotations only)+type CmmTickish = Tickish ()++-- | Tick scope identifier, allowing us to reason about what+-- annotations in a Cmm block should scope over. We especially take+-- care to allow optimisations to reorganise blocks without losing+-- tick association in the process.+data CmmTickScope+ = GlobalScope+ -- ^ The global scope is the "root" of the scope graph. Every+ -- scope is a sub-scope of the global scope. It doesn't make sense+ -- to add ticks to this scope. On the other hand, this means that+ -- setting this scope on a block means no ticks apply to it.++ | SubScope !U.Unique CmmTickScope+ -- ^ Constructs a new sub-scope to an existing scope. This allows+ -- us to translate Core-style scoping rules (see @tickishScoped@)+ -- into the Cmm world. Suppose the following code:+ --+ -- tick<1> case ... of+ -- A -> tick<2> ...+ -- B -> tick<3> ...+ --+ -- We want the top-level tick annotation to apply to blocks+ -- generated for the A and B alternatives. We can achieve that by+ -- generating tick<1> into a block with scope a, while the code+ -- for alternatives A and B gets generated into sub-scopes a/b and+ -- a/c respectively.++ | CombinedScope CmmTickScope CmmTickScope+ -- ^ A combined scope scopes over everything that the two given+ -- scopes cover. It is therefore a sub-scope of either scope. This+ -- is required for optimisations. Consider common block elimination:+ --+ -- A -> tick<2> case ... of+ -- C -> [common]+ -- B -> tick<3> case ... of+ -- D -> [common]+ --+ -- We will generate code for the C and D alternatives, and figure+ -- out afterwards that it's actually common code. Scoping rules+ -- dictate that the resulting common block needs to be covered by+ -- both tick<2> and tick<3>, therefore we need to construct a+ -- scope that is a child to *both* scope. Now we can do that - if+ -- we assign the scopes a/c and b/d to the common-ed up blocks,+ -- the new block could have a combined tick scope a/c+b/d, which+ -- both tick<2> and tick<3> apply to.++-- Note [CmmTick scoping details]:+--+-- The scope of a @CmmTick@ is given by the @CmmEntry@ node of the+-- same block. Note that as a result of this, optimisations making+-- tick scopes more specific can *reduce* the amount of code a tick+-- scopes over. Fixing this would require a separate @CmmTickScope@+-- field for @CmmTick@. Right now we do not do this simply because I+-- couldn't find an example where it actually mattered -- multiple+-- blocks within the same scope generally jump to each other, which+-- prevents common block elimination from happening in the first+-- place. But this is no strong reason, so if Cmm optimisations become+-- more involved in future this might have to be revisited.++-- | Output all scope paths.+scopeToPaths :: CmmTickScope -> [[U.Unique]]+scopeToPaths GlobalScope = [[]]+scopeToPaths (SubScope u s) = map (u:) (scopeToPaths s)+scopeToPaths (CombinedScope s1 s2) = scopeToPaths s1 ++ scopeToPaths s2++-- | Returns the head uniques of the scopes. This is based on the+-- assumption that the @Unique@ of @SubScope@ identifies the+-- underlying super-scope. Used for efficient equality and comparison,+-- see below.+scopeUniques :: CmmTickScope -> [U.Unique]+scopeUniques GlobalScope = []+scopeUniques (SubScope u _) = [u]+scopeUniques (CombinedScope s1 s2) = scopeUniques s1 ++ scopeUniques s2++-- Equality and order is based on the head uniques defined above. We+-- take care to short-cut the (extremly) common cases.+instance Eq CmmTickScope where+ GlobalScope == GlobalScope = True+ GlobalScope == _ = False+ _ == GlobalScope = False+ (SubScope u _) == (SubScope u' _) = u == u'+ (SubScope _ _) == _ = False+ _ == (SubScope _ _) = False+ scope == scope' =+ sortBy nonDetCmpUnique (scopeUniques scope) ==+ sortBy nonDetCmpUnique (scopeUniques scope')+ -- This is still deterministic because+ -- the order is the same for equal lists++-- This is non-deterministic but we do not currently support deterministic+-- code-generation. See Note [Unique Determinism and code generation]+-- See Note [No Ord for Unique]+instance Ord CmmTickScope where+ compare GlobalScope GlobalScope = EQ+ compare GlobalScope _ = LT+ compare _ GlobalScope = GT+ compare (SubScope u _) (SubScope u' _) = nonDetCmpUnique u u'+ compare scope scope' = cmpList nonDetCmpUnique+ (sortBy nonDetCmpUnique $ scopeUniques scope)+ (sortBy nonDetCmpUnique $ scopeUniques scope')++instance Outputable CmmTickScope where+ ppr GlobalScope = text "global"+ ppr (SubScope us GlobalScope)+ = ppr us+ ppr (SubScope us s) = ppr s <> char '/' <> ppr us+ ppr combined = parens $ hcat $ punctuate (char '+') $+ map (hcat . punctuate (char '/') . map ppr . reverse) $+ scopeToPaths combined++-- | Checks whether two tick scopes are sub-scopes of each other. True+-- if the two scopes are equal.+isTickSubScope :: CmmTickScope -> CmmTickScope -> Bool+isTickSubScope = cmp+ where cmp _ GlobalScope = True+ cmp GlobalScope _ = False+ cmp (CombinedScope s1 s2) s' = cmp s1 s' && cmp s2 s'+ cmp s (CombinedScope s1' s2') = cmp s s1' || cmp s s2'+ cmp (SubScope u s) s'@(SubScope u' _) = u == u' || cmp s s'++-- | Combine two tick scopes. The new scope should be sub-scope of+-- both parameters. We simplfy automatically if one tick scope is a+-- sub-scope of the other already.+combineTickScopes :: CmmTickScope -> CmmTickScope -> CmmTickScope+combineTickScopes s1 s2+ | s1 `isTickSubScope` s2 = s1+ | s2 `isTickSubScope` s1 = s2+ | otherwise = CombinedScope s1 s2
+ cmm/CmmOpt.hs view
@@ -0,0 +1,392 @@+{-# LANGUAGE CPP #-}++-- The default iteration limit is a bit too low for the definitions+-- in this module.+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fmax-pmcheck-iterations=10000000 #-}+#endif++-----------------------------------------------------------------------------+--+-- Cmm optimisation+--+-- (c) The University of Glasgow 2006+--+-----------------------------------------------------------------------------++module CmmOpt (+ constantFoldNode,+ constantFoldExpr,+ cmmMachOpFold,+ cmmMachOpFoldM+ ) where++#include "HsVersions.h"++import CmmUtils+import Cmm+import DynFlags+import Util++import Outputable+import Platform++import Data.Bits+import Data.Maybe+++constantFoldNode :: DynFlags -> CmmNode e x -> CmmNode e x+constantFoldNode dflags = mapExp (constantFoldExpr dflags)++constantFoldExpr :: DynFlags -> CmmExpr -> CmmExpr+constantFoldExpr dflags = wrapRecExp f+ where f (CmmMachOp op args) = cmmMachOpFold dflags op args+ f (CmmRegOff r 0) = CmmReg r+ f e = e++-- -----------------------------------------------------------------------------+-- MachOp constant folder++-- Now, try to constant-fold the MachOps. The arguments have already+-- been optimized and folded.++cmmMachOpFold+ :: DynFlags+ -> MachOp -- The operation from an CmmMachOp+ -> [CmmExpr] -- The optimized arguments+ -> CmmExpr++cmmMachOpFold dflags op args = fromMaybe (CmmMachOp op args) (cmmMachOpFoldM dflags op args)++-- Returns Nothing if no changes, useful for Hoopl, also reduces+-- allocation!+cmmMachOpFoldM+ :: DynFlags+ -> MachOp+ -> [CmmExpr]+ -> Maybe CmmExpr++cmmMachOpFoldM _ op [CmmLit (CmmInt x rep)]+ = Just $ case op of+ MO_S_Neg _ -> CmmLit (CmmInt (-x) rep)+ MO_Not _ -> CmmLit (CmmInt (complement x) rep)++ -- these are interesting: we must first narrow to the+ -- "from" type, in order to truncate to the correct size.+ -- The final narrow/widen to the destination type+ -- is implicit in the CmmLit.+ MO_SF_Conv _from to -> CmmLit (CmmFloat (fromInteger x) to)+ MO_SS_Conv from to -> CmmLit (CmmInt (narrowS from x) to)+ MO_UU_Conv from to -> CmmLit (CmmInt (narrowU from x) to)++ _ -> panic $ "cmmMachOpFoldM: unknown unary op: " ++ show op+++-- Eliminate conversion NOPs+cmmMachOpFoldM _ (MO_SS_Conv rep1 rep2) [x] | rep1 == rep2 = Just x+cmmMachOpFoldM _ (MO_UU_Conv rep1 rep2) [x] | rep1 == rep2 = Just x++-- Eliminate nested conversions where possible+cmmMachOpFoldM dflags conv_outer [CmmMachOp conv_inner [x]]+ | Just (rep1,rep2,signed1) <- isIntConversion conv_inner,+ Just (_, rep3,signed2) <- isIntConversion conv_outer+ = case () of+ -- widen then narrow to the same size is a nop+ _ | rep1 < rep2 && rep1 == rep3 -> Just x+ -- Widen then narrow to different size: collapse to single conversion+ -- but remember to use the signedness from the widening, just in case+ -- the final conversion is a widen.+ | rep1 < rep2 && rep2 > rep3 ->+ Just $ cmmMachOpFold dflags (intconv signed1 rep1 rep3) [x]+ -- Nested widenings: collapse if the signedness is the same+ | rep1 < rep2 && rep2 < rep3 && signed1 == signed2 ->+ Just $ cmmMachOpFold dflags (intconv signed1 rep1 rep3) [x]+ -- Nested narrowings: collapse+ | rep1 > rep2 && rep2 > rep3 ->+ Just $ cmmMachOpFold dflags (MO_UU_Conv rep1 rep3) [x]+ | otherwise ->+ Nothing+ where+ isIntConversion (MO_UU_Conv rep1 rep2)+ = Just (rep1,rep2,False)+ isIntConversion (MO_SS_Conv rep1 rep2)+ = Just (rep1,rep2,True)+ isIntConversion _ = Nothing++ intconv True = MO_SS_Conv+ intconv False = MO_UU_Conv++-- ToDo: a narrow of a load can be collapsed into a narrow load, right?+-- but what if the architecture only supports word-sized loads, should+-- we do the transformation anyway?++cmmMachOpFoldM dflags mop [CmmLit (CmmInt x xrep), CmmLit (CmmInt y _)]+ = case mop of+ -- for comparisons: don't forget to narrow the arguments before+ -- comparing, since they might be out of range.+ MO_Eq _ -> Just $ CmmLit (CmmInt (if x_u == y_u then 1 else 0) (wordWidth dflags))+ MO_Ne _ -> Just $ CmmLit (CmmInt (if x_u /= y_u then 1 else 0) (wordWidth dflags))++ MO_U_Gt _ -> Just $ CmmLit (CmmInt (if x_u > y_u then 1 else 0) (wordWidth dflags))+ MO_U_Ge _ -> Just $ CmmLit (CmmInt (if x_u >= y_u then 1 else 0) (wordWidth dflags))+ MO_U_Lt _ -> Just $ CmmLit (CmmInt (if x_u < y_u then 1 else 0) (wordWidth dflags))+ MO_U_Le _ -> Just $ CmmLit (CmmInt (if x_u <= y_u then 1 else 0) (wordWidth dflags))++ MO_S_Gt _ -> Just $ CmmLit (CmmInt (if x_s > y_s then 1 else 0) (wordWidth dflags))+ MO_S_Ge _ -> Just $ CmmLit (CmmInt (if x_s >= y_s then 1 else 0) (wordWidth dflags))+ MO_S_Lt _ -> Just $ CmmLit (CmmInt (if x_s < y_s then 1 else 0) (wordWidth dflags))+ MO_S_Le _ -> Just $ CmmLit (CmmInt (if x_s <= y_s then 1 else 0) (wordWidth dflags))++ MO_Add r -> Just $ CmmLit (CmmInt (x + y) r)+ MO_Sub r -> Just $ CmmLit (CmmInt (x - y) r)+ MO_Mul r -> Just $ CmmLit (CmmInt (x * y) r)+ MO_U_Quot r | y /= 0 -> Just $ CmmLit (CmmInt (x_u `quot` y_u) r)+ MO_U_Rem r | y /= 0 -> Just $ CmmLit (CmmInt (x_u `rem` y_u) r)+ MO_S_Quot r | y /= 0 -> Just $ CmmLit (CmmInt (x `quot` y) r)+ MO_S_Rem r | y /= 0 -> Just $ CmmLit (CmmInt (x `rem` y) r)++ MO_And r -> Just $ CmmLit (CmmInt (x .&. y) r)+ MO_Or r -> Just $ CmmLit (CmmInt (x .|. y) r)+ MO_Xor r -> Just $ CmmLit (CmmInt (x `xor` y) r)++ MO_Shl r -> Just $ CmmLit (CmmInt (x `shiftL` fromIntegral y) r)+ MO_U_Shr r -> Just $ CmmLit (CmmInt (x_u `shiftR` fromIntegral y) r)+ MO_S_Shr r -> Just $ CmmLit (CmmInt (x `shiftR` fromIntegral y) r)++ _ -> Nothing++ where+ x_u = narrowU xrep x+ y_u = narrowU xrep y+ x_s = narrowS xrep x+ y_s = narrowS xrep y+++-- When possible, shift the constants to the right-hand side, so that we+-- can match for strength reductions. Note that the code generator will+-- also assume that constants have been shifted to the right when+-- possible.++cmmMachOpFoldM dflags op [x@(CmmLit _), y]+ | not (isLit y) && isCommutableMachOp op+ = Just (cmmMachOpFold dflags op [y, x])++-- Turn (a+b)+c into a+(b+c) where possible. Because literals are+-- moved to the right, it is more likely that we will find+-- opportunities for constant folding when the expression is+-- right-associated.+--+-- ToDo: this appears to introduce a quadratic behaviour due to the+-- nested cmmMachOpFold. Can we fix this?+--+-- Why do we check isLit arg1? If arg1 is a lit, it means that arg2+-- is also a lit (otherwise arg1 would be on the right). If we+-- put arg1 on the left of the rearranged expression, we'll get into a+-- loop: (x1+x2)+x3 => x1+(x2+x3) => (x2+x3)+x1 => x2+(x3+x1) ...+--+-- Also don't do it if arg1 is PicBaseReg, so that we don't separate the+-- PicBaseReg from the corresponding label (or label difference).+--+cmmMachOpFoldM dflags mop1 [CmmMachOp mop2 [arg1,arg2], arg3]+ | mop2 `associates_with` mop1+ && not (isLit arg1) && not (isPicReg arg1)+ = Just (cmmMachOpFold dflags mop2 [arg1, cmmMachOpFold dflags mop1 [arg2,arg3]])+ where+ MO_Add{} `associates_with` MO_Sub{} = True+ mop1 `associates_with` mop2 =+ mop1 == mop2 && isAssociativeMachOp mop1++-- special case: (a - b) + c ==> a + (c - b)+cmmMachOpFoldM dflags mop1@(MO_Add{}) [CmmMachOp mop2@(MO_Sub{}) [arg1,arg2], arg3]+ | not (isLit arg1) && not (isPicReg arg1)+ = Just (cmmMachOpFold dflags mop1 [arg1, cmmMachOpFold dflags mop2 [arg3,arg2]])++-- special case: (PicBaseReg + lit) + N ==> PicBaseReg + (lit+N)+--+-- this is better because lit+N is a single link-time constant (e.g. a+-- CmmLabelOff), so the right-hand expression needs only one+-- instruction, whereas the left needs two. This happens when pointer+-- tagging gives us label+offset, and PIC turns the label into+-- PicBaseReg + label.+--+cmmMachOpFoldM _ MO_Add{} [ CmmMachOp op@MO_Add{} [pic, CmmLit lit]+ , CmmLit (CmmInt n rep) ]+ | isPicReg pic+ = Just $ CmmMachOp op [pic, CmmLit $ cmmOffsetLit lit off ]+ where off = fromIntegral (narrowS rep n)++-- Make a RegOff if we can+cmmMachOpFoldM _ (MO_Add _) [CmmReg reg, CmmLit (CmmInt n rep)]+ = Just $ cmmRegOff reg (fromIntegral (narrowS rep n))+cmmMachOpFoldM _ (MO_Add _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]+ = Just $ cmmRegOff reg (off + fromIntegral (narrowS rep n))+cmmMachOpFoldM _ (MO_Sub _) [CmmReg reg, CmmLit (CmmInt n rep)]+ = Just $ cmmRegOff reg (- fromIntegral (narrowS rep n))+cmmMachOpFoldM _ (MO_Sub _) [CmmRegOff reg off, CmmLit (CmmInt n rep)]+ = Just $ cmmRegOff reg (off - fromIntegral (narrowS rep n))++-- Fold label(+/-)offset into a CmmLit where possible++cmmMachOpFoldM _ (MO_Add _) [CmmLit lit, CmmLit (CmmInt i rep)]+ = Just $ CmmLit (cmmOffsetLit lit (fromIntegral (narrowU rep i)))+cmmMachOpFoldM _ (MO_Add _) [CmmLit (CmmInt i rep), CmmLit lit]+ = Just $ CmmLit (cmmOffsetLit lit (fromIntegral (narrowU rep i)))+cmmMachOpFoldM _ (MO_Sub _) [CmmLit lit, CmmLit (CmmInt i rep)]+ = Just $ CmmLit (cmmOffsetLit lit (fromIntegral (negate (narrowU rep i))))+++-- Comparison of literal with widened operand: perform the comparison+-- at the smaller width, as long as the literal is within range.++-- We can't do the reverse trick, when the operand is narrowed:+-- narrowing throws away bits from the operand, there's no way to do+-- the same comparison at the larger size.++cmmMachOpFoldM dflags cmp [CmmMachOp conv [x], CmmLit (CmmInt i _)]+ | -- powerPC NCG has a TODO for I8/I16 comparisons, so don't try+ platformArch (targetPlatform dflags) `elem` [ArchX86, ArchX86_64],+ -- if the operand is widened:+ Just (rep, signed, narrow_fn) <- maybe_conversion conv,+ -- and this is a comparison operation:+ Just narrow_cmp <- maybe_comparison cmp rep signed,+ -- and the literal fits in the smaller size:+ i == narrow_fn rep i+ -- then we can do the comparison at the smaller size+ = Just (cmmMachOpFold dflags narrow_cmp [x, CmmLit (CmmInt i rep)])+ where+ maybe_conversion (MO_UU_Conv from to)+ | to > from+ = Just (from, False, narrowU)+ maybe_conversion (MO_SS_Conv from to)+ | to > from+ = Just (from, True, narrowS)++ -- don't attempt to apply this optimisation when the source+ -- is a float; see #1916+ maybe_conversion _ = Nothing++ -- careful (#2080): if the original comparison was signed, but+ -- we were doing an unsigned widen, then we must do an+ -- unsigned comparison at the smaller size.+ maybe_comparison (MO_U_Gt _) rep _ = Just (MO_U_Gt rep)+ maybe_comparison (MO_U_Ge _) rep _ = Just (MO_U_Ge rep)+ maybe_comparison (MO_U_Lt _) rep _ = Just (MO_U_Lt rep)+ maybe_comparison (MO_U_Le _) rep _ = Just (MO_U_Le rep)+ maybe_comparison (MO_Eq _) rep _ = Just (MO_Eq rep)+ maybe_comparison (MO_S_Gt _) rep True = Just (MO_S_Gt rep)+ maybe_comparison (MO_S_Ge _) rep True = Just (MO_S_Ge rep)+ maybe_comparison (MO_S_Lt _) rep True = Just (MO_S_Lt rep)+ maybe_comparison (MO_S_Le _) rep True = Just (MO_S_Le rep)+ maybe_comparison (MO_S_Gt _) rep False = Just (MO_U_Gt rep)+ maybe_comparison (MO_S_Ge _) rep False = Just (MO_U_Ge rep)+ maybe_comparison (MO_S_Lt _) rep False = Just (MO_U_Lt rep)+ maybe_comparison (MO_S_Le _) rep False = Just (MO_U_Le rep)+ maybe_comparison _ _ _ = Nothing++-- We can often do something with constants of 0 and 1 ...++cmmMachOpFoldM dflags mop [x, y@(CmmLit (CmmInt 0 _))]+ = case mop of+ MO_Add _ -> Just x+ MO_Sub _ -> Just x+ MO_Mul _ -> Just y+ MO_And _ -> Just y+ MO_Or _ -> Just x+ MO_Xor _ -> Just x+ MO_Shl _ -> Just x+ MO_S_Shr _ -> Just x+ MO_U_Shr _ -> Just x+ MO_Ne _ | isComparisonExpr x -> Just x+ MO_Eq _ | Just x' <- maybeInvertCmmExpr x -> Just x'+ MO_U_Gt _ | isComparisonExpr x -> Just x+ MO_S_Gt _ | isComparisonExpr x -> Just x+ MO_U_Lt _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 0 (wordWidth dflags))+ MO_S_Lt _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 0 (wordWidth dflags))+ MO_U_Ge _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 1 (wordWidth dflags))+ MO_S_Ge _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 1 (wordWidth dflags))+ MO_U_Le _ | Just x' <- maybeInvertCmmExpr x -> Just x'+ MO_S_Le _ | Just x' <- maybeInvertCmmExpr x -> Just x'+ _ -> Nothing++cmmMachOpFoldM dflags mop [x, (CmmLit (CmmInt 1 rep))]+ = case mop of+ MO_Mul _ -> Just x+ MO_S_Quot _ -> Just x+ MO_U_Quot _ -> Just x+ MO_S_Rem _ -> Just $ CmmLit (CmmInt 0 rep)+ MO_U_Rem _ -> Just $ CmmLit (CmmInt 0 rep)+ MO_Ne _ | Just x' <- maybeInvertCmmExpr x -> Just x'+ MO_Eq _ | isComparisonExpr x -> Just x+ MO_U_Lt _ | Just x' <- maybeInvertCmmExpr x -> Just x'+ MO_S_Lt _ | Just x' <- maybeInvertCmmExpr x -> Just x'+ MO_U_Gt _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 0 (wordWidth dflags))+ MO_S_Gt _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 0 (wordWidth dflags))+ MO_U_Le _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 1 (wordWidth dflags))+ MO_S_Le _ | isComparisonExpr x -> Just $ CmmLit (CmmInt 1 (wordWidth dflags))+ MO_U_Ge _ | isComparisonExpr x -> Just x+ MO_S_Ge _ | isComparisonExpr x -> Just x+ _ -> Nothing++-- Now look for multiplication/division by powers of 2 (integers).++cmmMachOpFoldM dflags mop [x, (CmmLit (CmmInt n _))]+ = case mop of+ MO_Mul rep+ | Just p <- exactLog2 n ->+ Just (cmmMachOpFold dflags (MO_Shl rep) [x, CmmLit (CmmInt p rep)])+ MO_U_Quot rep+ | Just p <- exactLog2 n ->+ Just (cmmMachOpFold dflags (MO_U_Shr rep) [x, CmmLit (CmmInt p rep)])+ MO_S_Quot rep+ | Just p <- exactLog2 n,+ CmmReg _ <- x -> -- We duplicate x below, hence require+ -- it is a reg. FIXME: remove this restriction.+ -- shift right is not the same as quot, because it rounds+ -- to minus infinity, whereasq quot rounds toward zero.+ -- To fix this up, we add one less than the divisor to the+ -- dividend if it is a negative number.+ --+ -- to avoid a test/jump, we use the following sequence:+ -- x1 = x >> word_size-1 (all 1s if -ve, all 0s if +ve)+ -- x2 = y & (divisor-1)+ -- result = (x+x2) >>= log2(divisor)+ -- this could be done a bit more simply using conditional moves,+ -- but we're processor independent here.+ --+ -- we optimise the divide by 2 case slightly, generating+ -- x1 = x >> word_size-1 (unsigned)+ -- return = (x + x1) >>= log2(divisor)+ let+ bits = fromIntegral (widthInBits rep) - 1+ shr = if p == 1 then MO_U_Shr rep else MO_S_Shr rep+ x1 = CmmMachOp shr [x, CmmLit (CmmInt bits rep)]+ x2 = if p == 1 then x1 else+ CmmMachOp (MO_And rep) [x1, CmmLit (CmmInt (n-1) rep)]+ x3 = CmmMachOp (MO_Add rep) [x, x2]+ in+ Just (cmmMachOpFold dflags (MO_S_Shr rep) [x3, CmmLit (CmmInt p rep)])+ _ -> Nothing++-- ToDo (#7116): optimise floating-point multiplication, e.g. x*2.0 -> x+x+-- Unfortunately this needs a unique supply because x might not be a+-- register. See #2253 (program 6) for an example.+++-- Anything else is just too hard.++cmmMachOpFoldM _ _ _ = Nothing++-- -----------------------------------------------------------------------------+-- Utils++isLit :: CmmExpr -> Bool+isLit (CmmLit _) = True+isLit _ = False++isComparisonExpr :: CmmExpr -> Bool+isComparisonExpr (CmmMachOp op _) = isComparisonMachOp op+isComparisonExpr _ = False++isPicReg :: CmmExpr -> Bool+isPicReg (CmmReg (CmmGlobal PicBaseReg)) = True+isPicReg _ = False
+ cmm/CmmParse.y view
@@ -0,0 +1,1419 @@+-----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2004-2012+--+-- Parser for concrete Cmm.+--+-----------------------------------------------------------------------------++{- -----------------------------------------------------------------------------+Note [Syntax of .cmm files]++NOTE: You are very much on your own in .cmm. There is very little+error checking at all:++ * Type errors are detected by the (optional) -dcmm-lint pass, if you+ don't turn this on then a type error will likely result in a panic+ from the native code generator.++ * Passing the wrong number of arguments or arguments of the wrong+ type is not detected.++There are two ways to write .cmm code:++ (1) High-level Cmm code delegates the stack handling to GHC, and+ never explicitly mentions Sp or registers.++ (2) Low-level Cmm manages the stack itself, and must know about+ calling conventions.++Whether you want high-level or low-level Cmm is indicated by the+presence of an argument list on a procedure. For example:++foo ( gcptr a, bits32 b )+{+ // this is high-level cmm code++ if (b > 0) {+ // we can make tail calls passing arguments:+ jump stg_ap_0_fast(a);+ }++ push (stg_upd_frame_info, a) {+ // stack frames can be explicitly pushed++ (x,y) = call wibble(a,b,3,4);+ // calls pass arguments and return results using the native+ // Haskell calling convention. The code generator will automatically+ // construct a stack frame and an info table for the continuation.++ return (x,y);+ // we can return multiple values from the current proc+ }+}++bar+{+ // this is low-level cmm code, indicated by the fact that we did not+ // put an argument list on bar.++ x = R1; // the calling convention is explicit: better be careful+ // that this works on all platforms!++ jump %ENTRY_CODE(Sp(0))+}++Here is a list of rules for high-level and low-level code. If you+break the rules, you get a panic (for using a high-level construct in+a low-level proc), or wrong code (when using low-level code in a+high-level proc). This stuff isn't checked! (TODO!)++High-level only:++ - tail-calls with arguments, e.g.+ jump stg_fun (arg1, arg2);++ - function calls:+ (ret1,ret2) = call stg_fun (arg1, arg2);++ This makes a call with the NativeNodeCall convention, and the+ values are returned to the following code using the NativeReturn+ convention.++ - returning:+ return (ret1, ret2)++ These use the NativeReturn convention to return zero or more+ results to the caller.++ - pushing stack frames:+ push (info_ptr, field1, ..., fieldN) { ... statements ... }++ - reserving temporary stack space:++ reserve N = x { ... }++ this reserves an area of size N (words) on the top of the stack,+ and binds its address to x (a local register). Typically this is+ used for allocating temporary storage for passing to foreign+ functions.++ Note that if you make any native calls or invoke the GC in the+ scope of the reserve block, you are responsible for ensuring that+ the stack you reserved is laid out correctly with an info table.++Low-level only:++ - References to Sp, R1-R8, F1-F4 etc.++ NB. foreign calls may clobber the argument registers R1-R8, F1-F4+ etc., so ensure they are saved into variables around foreign+ calls.++ - SAVE_THREAD_STATE() and LOAD_THREAD_STATE(), which modify Sp+ directly.++Both high-level and low-level code can use a raw tail-call:++ jump stg_fun [R1,R2]++NB. you *must* specify the list of GlobalRegs that are passed via a+jump, otherwise the register allocator will assume that all the+GlobalRegs are dead at the jump.+++Calling Conventions+-------------------++High-level procedures use the NativeNode calling convention, or the+NativeReturn convention if the 'return' keyword is used (see Stack+Frames below).++Low-level procedures implement their own calling convention, so it can+be anything at all.++If a low-level procedure implements the NativeNode calling convention,+then it can be called by high-level code using an ordinary function+call. In general this is hard to arrange because the calling+convention depends on the number of physical registers available for+parameter passing, but there are two cases where the calling+convention is platform-independent:++ - Zero arguments.++ - One argument of pointer or non-pointer word type; this is always+ passed in R1 according to the NativeNode convention.++ - Returning a single value; these conventions are fixed and platform+ independent.+++Stack Frames+------------++A stack frame is written like this:++INFO_TABLE_RET ( label, FRAME_TYPE, info_ptr, field1, ..., fieldN )+ return ( arg1, ..., argM )+{+ ... code ...+}++where field1 ... fieldN are the fields of the stack frame (with types)+arg1...argN are the values returned to the stack frame (with types).+The return values are assumed to be passed according to the+NativeReturn convention.++On entry to the code, the stack frame looks like:++ |----------|+ | fieldN |+ | ... |+ | field1 |+ |----------|+ | info_ptr |+ |----------|+ | argN |+ | ... | <- Sp++and some of the args may be in registers.++We prepend the code by a copyIn of the args, and assign all the stack+frame fields to their formals. The initial "arg offset" for stack+layout purposes consists of the whole stack frame plus any args that+might be on the stack.++A tail-call may pass a stack frame to the callee using the following+syntax:++jump f (info_ptr, field1,..,fieldN) (arg1,..,argN)++where info_ptr and field1..fieldN describe the stack frame, and+arg1..argN are the arguments passed to f using the NativeNodeCall+convention. Note if a field is longer than a word (e.g. a D_ on+a 32-bit machine) then the call will push as many words as+necessary to the stack to accommodate it (e.g. 2).+++----------------------------------------------------------------------------- -}++{+module CmmParse ( parseCmmFile ) where++import StgCmmExtCode+import CmmCallConv+import StgCmmProf+import StgCmmHeap+import StgCmmMonad hiding ( getCode, getCodeR, getCodeScoped, emitLabel, emit, emitStore+ , emitAssign, emitOutOfLine, withUpdFrameOff+ , getUpdFrameOff )+import qualified StgCmmMonad as F+import StgCmmUtils+import StgCmmForeign+import StgCmmExpr+import StgCmmClosure+import StgCmmLayout hiding (ArgRep(..))+import StgCmmTicky+import StgCmmBind ( emitBlackHoleCode, emitUpdateFrame )+import CoreSyn ( Tickish(SourceNote) )++import CmmOpt+import MkGraph+import Cmm+import CmmUtils+import CmmSwitch ( mkSwitchTargets )+import CmmInfo+import BlockId+import CmmLex+import CLabel+import SMRep+import Lexer+import CmmMonad++import CostCentre+import ForeignCall+import Module+import Platform+import Literal+import Unique+import UniqFM+import SrcLoc+import DynFlags+import ErrUtils+import StringBuffer+import FastString+import Panic+import Constants+import Outputable+import BasicTypes+import Bag ( emptyBag, unitBag )+import Var++import Control.Monad+import Data.Array+import Data.Char ( ord )+import System.Exit+import Data.Maybe+import qualified Data.Map as M++#include "HsVersions.h"+}++%expect 0++%token+ ':' { L _ (CmmT_SpecChar ':') }+ ';' { L _ (CmmT_SpecChar ';') }+ '{' { L _ (CmmT_SpecChar '{') }+ '}' { L _ (CmmT_SpecChar '}') }+ '[' { L _ (CmmT_SpecChar '[') }+ ']' { L _ (CmmT_SpecChar ']') }+ '(' { L _ (CmmT_SpecChar '(') }+ ')' { L _ (CmmT_SpecChar ')') }+ '=' { L _ (CmmT_SpecChar '=') }+ '`' { L _ (CmmT_SpecChar '`') }+ '~' { L _ (CmmT_SpecChar '~') }+ '/' { L _ (CmmT_SpecChar '/') }+ '*' { L _ (CmmT_SpecChar '*') }+ '%' { L _ (CmmT_SpecChar '%') }+ '-' { L _ (CmmT_SpecChar '-') }+ '+' { L _ (CmmT_SpecChar '+') }+ '&' { L _ (CmmT_SpecChar '&') }+ '^' { L _ (CmmT_SpecChar '^') }+ '|' { L _ (CmmT_SpecChar '|') }+ '>' { L _ (CmmT_SpecChar '>') }+ '<' { L _ (CmmT_SpecChar '<') }+ ',' { L _ (CmmT_SpecChar ',') }+ '!' { L _ (CmmT_SpecChar '!') }++ '..' { L _ (CmmT_DotDot) }+ '::' { L _ (CmmT_DoubleColon) }+ '>>' { L _ (CmmT_Shr) }+ '<<' { L _ (CmmT_Shl) }+ '>=' { L _ (CmmT_Ge) }+ '<=' { L _ (CmmT_Le) }+ '==' { L _ (CmmT_Eq) }+ '!=' { L _ (CmmT_Ne) }+ '&&' { L _ (CmmT_BoolAnd) }+ '||' { L _ (CmmT_BoolOr) }++ 'CLOSURE' { L _ (CmmT_CLOSURE) }+ 'INFO_TABLE' { L _ (CmmT_INFO_TABLE) }+ 'INFO_TABLE_RET'{ L _ (CmmT_INFO_TABLE_RET) }+ 'INFO_TABLE_FUN'{ L _ (CmmT_INFO_TABLE_FUN) }+ 'INFO_TABLE_CONSTR'{ L _ (CmmT_INFO_TABLE_CONSTR) }+ 'INFO_TABLE_SELECTOR'{ L _ (CmmT_INFO_TABLE_SELECTOR) }+ 'else' { L _ (CmmT_else) }+ 'export' { L _ (CmmT_export) }+ 'section' { L _ (CmmT_section) }+ 'goto' { L _ (CmmT_goto) }+ 'if' { L _ (CmmT_if) }+ 'call' { L _ (CmmT_call) }+ 'jump' { L _ (CmmT_jump) }+ 'foreign' { L _ (CmmT_foreign) }+ 'never' { L _ (CmmT_never) }+ 'prim' { L _ (CmmT_prim) }+ 'reserve' { L _ (CmmT_reserve) }+ 'return' { L _ (CmmT_return) }+ 'returns' { L _ (CmmT_returns) }+ 'import' { L _ (CmmT_import) }+ 'switch' { L _ (CmmT_switch) }+ 'case' { L _ (CmmT_case) }+ 'default' { L _ (CmmT_default) }+ 'push' { L _ (CmmT_push) }+ 'unwind' { L _ (CmmT_unwind) }+ 'bits8' { L _ (CmmT_bits8) }+ 'bits16' { L _ (CmmT_bits16) }+ 'bits32' { L _ (CmmT_bits32) }+ 'bits64' { L _ (CmmT_bits64) }+ 'bits128' { L _ (CmmT_bits128) }+ 'bits256' { L _ (CmmT_bits256) }+ 'bits512' { L _ (CmmT_bits512) }+ 'float32' { L _ (CmmT_float32) }+ 'float64' { L _ (CmmT_float64) }+ 'gcptr' { L _ (CmmT_gcptr) }++ GLOBALREG { L _ (CmmT_GlobalReg $$) }+ NAME { L _ (CmmT_Name $$) }+ STRING { L _ (CmmT_String $$) }+ INT { L _ (CmmT_Int $$) }+ FLOAT { L _ (CmmT_Float $$) }++%monad { PD } { >>= } { return }+%lexer { cmmlex } { L _ CmmT_EOF }+%name cmmParse cmm+%tokentype { Located CmmToken }++-- C-- operator precedences, taken from the C-- spec+%right '||' -- non-std extension, called %disjoin in C--+%right '&&' -- non-std extension, called %conjoin in C--+%right '!'+%nonassoc '>=' '>' '<=' '<' '!=' '=='+%left '|'+%left '^'+%left '&'+%left '>>' '<<'+%left '-' '+'+%left '/' '*' '%'+%right '~'++%%++cmm :: { CmmParse () }+ : {- empty -} { return () }+ | cmmtop cmm { do $1; $2 }++cmmtop :: { CmmParse () }+ : cmmproc { $1 }+ | cmmdata { $1 }+ | decl { $1 } + | 'CLOSURE' '(' NAME ',' NAME lits ')' ';' + {% liftP . withThisPackage $ \pkg ->+ do lits <- sequence $6;+ staticClosure pkg $3 $5 (map getLit lits) }++-- The only static closures in the RTS are dummy closures like+-- stg_END_TSO_QUEUE_closure and stg_dummy_ret. We don't need+-- to provide the full generality of static closures here.+-- In particular:+-- * CCS can always be CCS_DONT_CARE+-- * closure is always extern+-- * payload is always empty+-- * we can derive closure and info table labels from a single NAME++cmmdata :: { CmmParse () }+ : 'section' STRING '{' data_label statics '}' + { do lbl <- $4;+ ss <- sequence $5;+ code (emitDecl (CmmData (Section (section $2) lbl) (Statics lbl $ concat ss))) }++data_label :: { CmmParse CLabel }+ : NAME ':' + {% liftP . withThisPackage $ \pkg ->+ return (mkCmmDataLabel pkg $1) }++statics :: { [CmmParse [CmmStatic]] }+ : {- empty -} { [] }+ | static statics { $1 : $2 }+ +-- Strings aren't used much in the RTS HC code, so it doesn't seem+-- worth allowing inline strings. C-- doesn't allow them anyway.+static :: { CmmParse [CmmStatic] }+ : type expr ';' { do e <- $2;+ return [CmmStaticLit (getLit e)] }+ | type ';' { return [CmmUninitialised+ (widthInBytes (typeWidth $1))] }+ | 'bits8' '[' ']' STRING ';' { return [mkString $4] }+ | 'bits8' '[' INT ']' ';' { return [CmmUninitialised + (fromIntegral $3)] }+ | typenot8 '[' INT ']' ';' { return [CmmUninitialised + (widthInBytes (typeWidth $1) * + fromIntegral $3)] }+ | 'CLOSURE' '(' NAME lits ')'+ { do { lits <- sequence $4+ ; dflags <- getDynFlags+ ; return $ map CmmStaticLit $+ mkStaticClosure dflags (mkForeignLabel $3 Nothing ForeignLabelInExternalPackage IsData)+ -- mkForeignLabel because these are only used+ -- for CHARLIKE and INTLIKE closures in the RTS.+ dontCareCCS (map getLit lits) [] [] [] } }+ -- arrays of closures required for the CHARLIKE & INTLIKE arrays++lits :: { [CmmParse CmmExpr] }+ : {- empty -} { [] }+ | ',' expr lits { $2 : $3 }++cmmproc :: { CmmParse () }+ : info maybe_conv maybe_formals maybe_body+ { do ((entry_ret_label, info, stk_formals, formals), agraph) <-+ getCodeScoped $ loopDecls $ do {+ (entry_ret_label, info, stk_formals) <- $1;+ dflags <- getDynFlags;+ formals <- sequence (fromMaybe [] $3);+ withName (showSDoc dflags (ppr entry_ret_label))+ $4;+ return (entry_ret_label, info, stk_formals, formals) }+ let do_layout = isJust $3+ code (emitProcWithStackFrame $2 info+ entry_ret_label stk_formals formals agraph+ do_layout ) }++maybe_conv :: { Convention }+ : {- empty -} { NativeNodeCall }+ | 'return' { NativeReturn }++maybe_body :: { CmmParse () }+ : ';' { return () }+ | '{' body '}' { withSourceNote $1 $3 $2 }++info :: { CmmParse (CLabel, Maybe CmmInfoTable, [LocalReg]) }+ : NAME+ {% liftP . withThisPackage $ \pkg ->+ do newFunctionName $1 pkg+ return (mkCmmCodeLabel pkg $1, Nothing, []) }+++ | 'INFO_TABLE' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'+ -- ptrs, nptrs, closure type, description, type+ {% liftP . withThisPackage $ \pkg ->+ do dflags <- getDynFlags+ let prof = profilingInfo dflags $11 $13+ rep = mkRTSRep (fromIntegral $9) $+ mkHeapRep dflags False (fromIntegral $5)+ (fromIntegral $7) Thunk+ -- not really Thunk, but that makes the info table+ -- we want.+ return (mkCmmEntryLabel pkg $3,+ Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3+ , cit_rep = rep+ , cit_prof = prof, cit_srt = NoC_SRT },+ []) }+ + | 'INFO_TABLE_FUN' '(' NAME ',' INT ',' INT ',' INT ',' STRING ',' STRING ',' INT ')'+ -- ptrs, nptrs, closure type, description, type, fun type+ {% liftP . withThisPackage $ \pkg ->+ do dflags <- getDynFlags+ let prof = profilingInfo dflags $11 $13+ ty = Fun 0 (ArgSpec (fromIntegral $15))+ -- Arity zero, arg_type $15+ rep = mkRTSRep (fromIntegral $9) $+ mkHeapRep dflags False (fromIntegral $5)+ (fromIntegral $7) ty+ return (mkCmmEntryLabel pkg $3,+ Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3+ , cit_rep = rep+ , cit_prof = prof, cit_srt = NoC_SRT },+ []) }+ -- we leave most of the fields zero here. This is only used+ -- to generate the BCO info table in the RTS at the moment.++ | 'INFO_TABLE_CONSTR' '(' NAME ',' INT ',' INT ',' INT ',' INT ',' STRING ',' STRING ')'+ -- ptrs, nptrs, tag, closure type, description, type+ {% liftP . withThisPackage $ \pkg ->+ do dflags <- getDynFlags+ let prof = profilingInfo dflags $13 $15+ ty = Constr (fromIntegral $9) -- Tag+ (stringToWord8s $13)+ rep = mkRTSRep (fromIntegral $11) $+ mkHeapRep dflags False (fromIntegral $5)+ (fromIntegral $7) ty+ return (mkCmmEntryLabel pkg $3,+ Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3+ , cit_rep = rep+ , cit_prof = prof, cit_srt = NoC_SRT },+ []) }++ -- If profiling is on, this string gets duplicated,+ -- but that's the way the old code did it we can fix it some other time.+ + | 'INFO_TABLE_SELECTOR' '(' NAME ',' INT ',' INT ',' STRING ',' STRING ')'+ -- selector, closure type, description, type+ {% liftP . withThisPackage $ \pkg ->+ do dflags <- getDynFlags+ let prof = profilingInfo dflags $9 $11+ ty = ThunkSelector (fromIntegral $5)+ rep = mkRTSRep (fromIntegral $7) $+ mkHeapRep dflags False 0 0 ty+ return (mkCmmEntryLabel pkg $3,+ Just $ CmmInfoTable { cit_lbl = mkCmmInfoLabel pkg $3+ , cit_rep = rep+ , cit_prof = prof, cit_srt = NoC_SRT },+ []) }++ | 'INFO_TABLE_RET' '(' NAME ',' INT ')'+ -- closure type (no live regs)+ {% liftP . withThisPackage $ \pkg ->+ do let prof = NoProfilingInfo+ rep = mkRTSRep (fromIntegral $5) $ mkStackRep []+ return (mkCmmRetLabel pkg $3,+ Just $ CmmInfoTable { cit_lbl = mkCmmRetInfoLabel pkg $3+ , cit_rep = rep+ , cit_prof = prof, cit_srt = NoC_SRT },+ []) }++ | 'INFO_TABLE_RET' '(' NAME ',' INT ',' formals0 ')'+ -- closure type, live regs+ {% liftP . withThisPackage $ \pkg ->+ do dflags <- getDynFlags+ live <- sequence $7+ let prof = NoProfilingInfo+ -- drop one for the info pointer+ bitmap = mkLiveness dflags (map Just (drop 1 live))+ rep = mkRTSRep (fromIntegral $5) $ mkStackRep bitmap+ return (mkCmmRetLabel pkg $3,+ Just $ CmmInfoTable { cit_lbl = mkCmmRetInfoLabel pkg $3+ , cit_rep = rep+ , cit_prof = prof, cit_srt = NoC_SRT },+ live) }++body :: { CmmParse () }+ : {- empty -} { return () }+ | decl body { do $1; $2 }+ | stmt body { do $1; $2 }++decl :: { CmmParse () }+ : type names ';' { mapM_ (newLocal $1) $2 }+ | 'import' importNames ';' { mapM_ newImport $2 }+ | 'export' names ';' { return () } -- ignore exports+++-- an imported function name, with optional packageId+importNames+ :: { [(FastString, CLabel)] }+ : importName { [$1] }+ | importName ',' importNames { $1 : $3 }++importName+ :: { (FastString, CLabel) }++ -- A label imported without an explicit packageId.+ -- These are taken to come frome some foreign, unnamed package.+ : NAME + { ($1, mkForeignLabel $1 Nothing ForeignLabelInExternalPackage IsFunction) }++ -- as previous 'NAME', but 'IsData'+ | 'CLOSURE' NAME+ { ($2, mkForeignLabel $2 Nothing ForeignLabelInExternalPackage IsData) }++ -- A label imported with an explicit packageId.+ | STRING NAME+ { ($2, mkCmmCodeLabel (fsToUnitId (mkFastString $1)) $2) }+ + +names :: { [FastString] }+ : NAME { [$1] }+ | NAME ',' names { $1 : $3 }++stmt :: { CmmParse () }+ : ';' { return () }++ | NAME ':'+ { do l <- newLabel $1; emitLabel l }++++ | lreg '=' expr ';'+ { do reg <- $1; e <- $3; withSourceNote $2 $4 (emitAssign reg e) }+ | type '[' expr ']' '=' expr ';'+ { withSourceNote $2 $7 (doStore $1 $3 $6) }++ -- Gah! We really want to say "foreign_results" but that causes+ -- a shift/reduce conflict with assignment. We either+ -- we expand out the no-result and single result cases or+ -- we tweak the syntax to avoid the conflict. The later+ -- option is taken here because the other way would require+ -- multiple levels of expanding and get unwieldy.+ | foreign_results 'foreign' STRING foreignLabel '(' cmm_hint_exprs0 ')' safety opt_never_returns ';'+ {% foreignCall $3 $1 $4 $6 $8 $9 }+ | foreign_results 'prim' '%' NAME '(' exprs0 ')' ';'+ {% primCall $1 $4 $6 }+ -- stmt-level macros, stealing syntax from ordinary C-- function calls.+ -- Perhaps we ought to use the %%-form?+ | NAME '(' exprs0 ')' ';'+ {% stmtMacro $1 $3 }+ | 'switch' maybe_range expr '{' arms default '}'+ { do as <- sequence $5; doSwitch $2 $3 as $6 }+ | 'goto' NAME ';'+ { do l <- lookupLabel $2; emit (mkBranch l) }+ | 'return' '(' exprs0 ')' ';'+ { doReturn $3 }+ | 'jump' expr vols ';'+ { doRawJump $2 $3 }+ | 'jump' expr '(' exprs0 ')' ';'+ { doJumpWithStack $2 [] $4 }+ | 'jump' expr '(' exprs0 ')' '(' exprs0 ')' ';'+ { doJumpWithStack $2 $4 $7 }+ | 'call' expr '(' exprs0 ')' ';'+ { doCall $2 [] $4 }+ | '(' formals ')' '=' 'call' expr '(' exprs0 ')' ';'+ { doCall $6 $2 $8 }+ | 'if' bool_expr 'goto' NAME+ { do l <- lookupLabel $4; cmmRawIf $2 l }+ | 'if' bool_expr '{' body '}' else + { cmmIfThenElse $2 (withSourceNote $3 $5 $4) $6 }+ | 'push' '(' exprs0 ')' maybe_body+ { pushStackFrame $3 $5 }+ | 'reserve' expr '=' lreg maybe_body+ { reserveStackFrame $2 $4 $5 }+ | 'unwind' unwind_regs ';'+ { $2 >>= code . emitUnwind }++unwind_regs+ :: { CmmParse [(GlobalReg, Maybe CmmExpr)] }+ : GLOBALREG '=' expr_or_unknown ',' unwind_regs+ { do e <- $3; rest <- $5; return (($1, e) : rest) }+ | GLOBALREG '=' expr_or_unknown+ { do e <- $3; return [($1, e)] }++-- | Used by unwind to indicate unknown unwinding values.+expr_or_unknown+ :: { CmmParse (Maybe CmmExpr) }+ : 'return'+ { do return Nothing }+ | expr+ { do e <- $1; return (Just e) }++foreignLabel :: { CmmParse CmmExpr }+ : NAME { return (CmmLit (CmmLabel (mkForeignLabel $1 Nothing ForeignLabelInThisPackage IsFunction))) }++opt_never_returns :: { CmmReturnInfo }+ : { CmmMayReturn }+ | 'never' 'returns' { CmmNeverReturns }++bool_expr :: { CmmParse BoolExpr }+ : bool_op { $1 }+ | expr { do e <- $1; return (BoolTest e) }++bool_op :: { CmmParse BoolExpr }+ : bool_expr '&&' bool_expr { do e1 <- $1; e2 <- $3; + return (BoolAnd e1 e2) }+ | bool_expr '||' bool_expr { do e1 <- $1; e2 <- $3; + return (BoolOr e1 e2) }+ | '!' bool_expr { do e <- $2; return (BoolNot e) }+ | '(' bool_op ')' { $2 }++safety :: { Safety }+ : {- empty -} { PlayRisky }+ | STRING {% parseSafety $1 }++vols :: { [GlobalReg] }+ : '[' ']' { [] }+ | '[' '*' ']' {% do df <- getDynFlags+ ; return (realArgRegsCover df) }+ -- All of them. See comment attached+ -- to realArgRegsCover+ | '[' globals ']' { $2 }++globals :: { [GlobalReg] }+ : GLOBALREG { [$1] }+ | GLOBALREG ',' globals { $1 : $3 }++maybe_range :: { Maybe (Integer,Integer) }+ : '[' INT '..' INT ']' { Just ($2, $4) }+ | {- empty -} { Nothing }++arms :: { [CmmParse ([Integer],Either BlockId (CmmParse ()))] }+ : {- empty -} { [] }+ | arm arms { $1 : $2 }++arm :: { CmmParse ([Integer],Either BlockId (CmmParse ())) }+ : 'case' ints ':' arm_body { do b <- $4; return ($2, b) }++arm_body :: { CmmParse (Either BlockId (CmmParse ())) }+ : '{' body '}' { return (Right (withSourceNote $1 $3 $2)) }+ | 'goto' NAME ';' { do l <- lookupLabel $2; return (Left l) }++ints :: { [Integer] }+ : INT { [ $1 ] }+ | INT ',' ints { $1 : $3 }++default :: { Maybe (CmmParse ()) }+ : 'default' ':' '{' body '}' { Just (withSourceNote $3 $5 $4) }+ -- taking a few liberties with the C-- syntax here; C-- doesn't have+ -- 'default' branches+ | {- empty -} { Nothing }++-- Note: OldCmm doesn't support a first class 'else' statement, though+-- CmmNode does.+else :: { CmmParse () }+ : {- empty -} { return () }+ | 'else' '{' body '}' { withSourceNote $2 $4 $3 }++-- we have to write this out longhand so that Happy's precedence rules+-- can kick in.+expr :: { CmmParse CmmExpr }+ : expr '/' expr { mkMachOp MO_U_Quot [$1,$3] }+ | expr '*' expr { mkMachOp MO_Mul [$1,$3] }+ | expr '%' expr { mkMachOp MO_U_Rem [$1,$3] }+ | expr '-' expr { mkMachOp MO_Sub [$1,$3] }+ | expr '+' expr { mkMachOp MO_Add [$1,$3] }+ | expr '>>' expr { mkMachOp MO_U_Shr [$1,$3] }+ | expr '<<' expr { mkMachOp MO_Shl [$1,$3] }+ | expr '&' expr { mkMachOp MO_And [$1,$3] }+ | expr '^' expr { mkMachOp MO_Xor [$1,$3] }+ | expr '|' expr { mkMachOp MO_Or [$1,$3] }+ | expr '>=' expr { mkMachOp MO_U_Ge [$1,$3] }+ | expr '>' expr { mkMachOp MO_U_Gt [$1,$3] }+ | expr '<=' expr { mkMachOp MO_U_Le [$1,$3] }+ | expr '<' expr { mkMachOp MO_U_Lt [$1,$3] }+ | expr '!=' expr { mkMachOp MO_Ne [$1,$3] }+ | expr '==' expr { mkMachOp MO_Eq [$1,$3] }+ | '~' expr { mkMachOp MO_Not [$2] }+ | '-' expr { mkMachOp MO_S_Neg [$2] }+ | expr0 '`' NAME '`' expr0 {% do { mo <- nameToMachOp $3 ;+ return (mkMachOp mo [$1,$5]) } }+ | expr0 { $1 }++expr0 :: { CmmParse CmmExpr }+ : INT maybe_ty { return (CmmLit (CmmInt $1 (typeWidth $2))) }+ | FLOAT maybe_ty { return (CmmLit (CmmFloat $1 (typeWidth $2))) }+ | STRING { do s <- code (newStringCLit $1); + return (CmmLit s) }+ | reg { $1 }+ | type '[' expr ']' { do e <- $3; return (CmmLoad e $1) }+ | '%' NAME '(' exprs0 ')' {% exprOp $2 $4 }+ | '(' expr ')' { $2 }+++-- leaving out the type of a literal gives you the native word size in C--+maybe_ty :: { CmmType }+ : {- empty -} {% do dflags <- getDynFlags; return $ bWord dflags }+ | '::' type { $2 }++cmm_hint_exprs0 :: { [CmmParse (CmmExpr, ForeignHint)] }+ : {- empty -} { [] }+ | cmm_hint_exprs { $1 }++cmm_hint_exprs :: { [CmmParse (CmmExpr, ForeignHint)] }+ : cmm_hint_expr { [$1] }+ | cmm_hint_expr ',' cmm_hint_exprs { $1 : $3 }++cmm_hint_expr :: { CmmParse (CmmExpr, ForeignHint) }+ : expr { do e <- $1;+ return (e, inferCmmHint e) }+ | expr STRING {% do h <- parseCmmHint $2;+ return $ do+ e <- $1; return (e, h) }++exprs0 :: { [CmmParse CmmExpr] }+ : {- empty -} { [] }+ | exprs { $1 }++exprs :: { [CmmParse CmmExpr] }+ : expr { [ $1 ] }+ | expr ',' exprs { $1 : $3 }++reg :: { CmmParse CmmExpr }+ : NAME { lookupName $1 }+ | GLOBALREG { return (CmmReg (CmmGlobal $1)) }++foreign_results :: { [CmmParse (LocalReg, ForeignHint)] }+ : {- empty -} { [] }+ | '(' foreign_formals ')' '=' { $2 }++foreign_formals :: { [CmmParse (LocalReg, ForeignHint)] }+ : foreign_formal { [$1] }+ | foreign_formal ',' { [$1] }+ | foreign_formal ',' foreign_formals { $1 : $3 }++foreign_formal :: { CmmParse (LocalReg, ForeignHint) }+ : local_lreg { do e <- $1; return (e, (inferCmmHint (CmmReg (CmmLocal e)))) }+ | STRING local_lreg {% do h <- parseCmmHint $1;+ return $ do+ e <- $2; return (e,h) }++local_lreg :: { CmmParse LocalReg }+ : NAME { do e <- lookupName $1;+ return $+ case e of + CmmReg (CmmLocal r) -> r+ other -> pprPanic "CmmParse:" (ftext $1 <> text " not a local register") }++lreg :: { CmmParse CmmReg }+ : NAME { do e <- lookupName $1;+ return $+ case e of + CmmReg r -> r+ other -> pprPanic "CmmParse:" (ftext $1 <> text " not a register") }+ | GLOBALREG { return (CmmGlobal $1) }++maybe_formals :: { Maybe [CmmParse LocalReg] }+ : {- empty -} { Nothing }+ | '(' formals0 ')' { Just $2 }++formals0 :: { [CmmParse LocalReg] }+ : {- empty -} { [] }+ | formals { $1 }++formals :: { [CmmParse LocalReg] }+ : formal ',' { [$1] }+ | formal { [$1] }+ | formal ',' formals { $1 : $3 }++formal :: { CmmParse LocalReg }+ : type NAME { newLocal $1 $2 }++type :: { CmmType }+ : 'bits8' { b8 }+ | typenot8 { $1 }++typenot8 :: { CmmType }+ : 'bits16' { b16 }+ | 'bits32' { b32 }+ | 'bits64' { b64 }+ | 'bits128' { b128 }+ | 'bits256' { b256 }+ | 'bits512' { b512 }+ | 'float32' { f32 }+ | 'float64' { f64 }+ | 'gcptr' {% do dflags <- getDynFlags; return $ gcWord dflags }++{+section :: String -> SectionType+section "text" = Text+section "data" = Data+section "rodata" = ReadOnlyData+section "relrodata" = RelocatableReadOnlyData+section "bss" = UninitialisedData+section s = OtherSection s++mkString :: String -> CmmStatic+mkString s = CmmString (map (fromIntegral.ord) s)++-- |+-- Given an info table, decide what the entry convention for the proc+-- is. That is, for an INFO_TABLE_RET we want the return convention,+-- otherwise it is a NativeNodeCall.+--+infoConv :: Maybe CmmInfoTable -> Convention+infoConv Nothing = NativeNodeCall+infoConv (Just info)+ | isStackRep (cit_rep info) = NativeReturn+ | otherwise = NativeNodeCall++-- mkMachOp infers the type of the MachOp from the type of its first+-- argument. We assume that this is correct: for MachOps that don't have+-- symmetrical args (e.g. shift ops), the first arg determines the type of+-- the op.+mkMachOp :: (Width -> MachOp) -> [CmmParse CmmExpr] -> CmmParse CmmExpr+mkMachOp fn args = do+ dflags <- getDynFlags+ arg_exprs <- sequence args+ return (CmmMachOp (fn (typeWidth (cmmExprType dflags (head arg_exprs)))) arg_exprs)++getLit :: CmmExpr -> CmmLit+getLit (CmmLit l) = l+getLit (CmmMachOp (MO_S_Neg _) [CmmLit (CmmInt i r)]) = CmmInt (negate i) r+getLit _ = panic "invalid literal" -- TODO messy failure++nameToMachOp :: FastString -> PD (Width -> MachOp)+nameToMachOp name =+ case lookupUFM machOps name of+ Nothing -> fail ("unknown primitive " ++ unpackFS name)+ Just m -> return m++exprOp :: FastString -> [CmmParse CmmExpr] -> PD (CmmParse CmmExpr)+exprOp name args_code = do+ dflags <- getDynFlags+ case lookupUFM (exprMacros dflags) name of+ Just f -> return $ do+ args <- sequence args_code+ return (f args)+ Nothing -> do+ mo <- nameToMachOp name+ return $ mkMachOp mo args_code++exprMacros :: DynFlags -> UniqFM ([CmmExpr] -> CmmExpr)+exprMacros dflags = listToUFM [+ ( fsLit "ENTRY_CODE", \ [x] -> entryCode dflags x ),+ ( fsLit "INFO_PTR", \ [x] -> closureInfoPtr dflags x ),+ ( fsLit "STD_INFO", \ [x] -> infoTable dflags x ),+ ( fsLit "FUN_INFO", \ [x] -> funInfoTable dflags x ),+ ( fsLit "GET_ENTRY", \ [x] -> entryCode dflags (closureInfoPtr dflags x) ),+ ( fsLit "GET_STD_INFO", \ [x] -> infoTable dflags (closureInfoPtr dflags x) ),+ ( fsLit "GET_FUN_INFO", \ [x] -> funInfoTable dflags (closureInfoPtr dflags x) ),+ ( fsLit "INFO_TYPE", \ [x] -> infoTableClosureType dflags x ),+ ( fsLit "INFO_PTRS", \ [x] -> infoTablePtrs dflags x ),+ ( fsLit "INFO_NPTRS", \ [x] -> infoTableNonPtrs dflags x )+ ]++-- we understand a subset of C-- primitives:+machOps = listToUFM $+ map (\(x, y) -> (mkFastString x, y)) [+ ( "add", MO_Add ),+ ( "sub", MO_Sub ),+ ( "eq", MO_Eq ),+ ( "ne", MO_Ne ),+ ( "mul", MO_Mul ),+ ( "neg", MO_S_Neg ),+ ( "quot", MO_S_Quot ),+ ( "rem", MO_S_Rem ),+ ( "divu", MO_U_Quot ),+ ( "modu", MO_U_Rem ),++ ( "ge", MO_S_Ge ),+ ( "le", MO_S_Le ),+ ( "gt", MO_S_Gt ),+ ( "lt", MO_S_Lt ),++ ( "geu", MO_U_Ge ),+ ( "leu", MO_U_Le ),+ ( "gtu", MO_U_Gt ),+ ( "ltu", MO_U_Lt ),++ ( "and", MO_And ),+ ( "or", MO_Or ),+ ( "xor", MO_Xor ),+ ( "com", MO_Not ),+ ( "shl", MO_Shl ),+ ( "shrl", MO_U_Shr ),+ ( "shra", MO_S_Shr ),++ ( "fadd", MO_F_Add ),+ ( "fsub", MO_F_Sub ),+ ( "fneg", MO_F_Neg ),+ ( "fmul", MO_F_Mul ),+ ( "fquot", MO_F_Quot ),++ ( "feq", MO_F_Eq ),+ ( "fne", MO_F_Ne ),+ ( "fge", MO_F_Ge ),+ ( "fle", MO_F_Le ),+ ( "fgt", MO_F_Gt ),+ ( "flt", MO_F_Lt ),++ ( "lobits8", flip MO_UU_Conv W8 ),+ ( "lobits16", flip MO_UU_Conv W16 ),+ ( "lobits32", flip MO_UU_Conv W32 ),+ ( "lobits64", flip MO_UU_Conv W64 ),++ ( "zx16", flip MO_UU_Conv W16 ),+ ( "zx32", flip MO_UU_Conv W32 ),+ ( "zx64", flip MO_UU_Conv W64 ),++ ( "sx16", flip MO_SS_Conv W16 ),+ ( "sx32", flip MO_SS_Conv W32 ),+ ( "sx64", flip MO_SS_Conv W64 ),++ ( "f2f32", flip MO_FF_Conv W32 ), -- TODO; rounding mode+ ( "f2f64", flip MO_FF_Conv W64 ), -- TODO; rounding mode+ ( "f2i8", flip MO_FS_Conv W8 ),+ ( "f2i16", flip MO_FS_Conv W16 ),+ ( "f2i32", flip MO_FS_Conv W32 ),+ ( "f2i64", flip MO_FS_Conv W64 ),+ ( "i2f32", flip MO_SF_Conv W32 ),+ ( "i2f64", flip MO_SF_Conv W64 )+ ]++callishMachOps :: UniqFM ([CmmExpr] -> (CallishMachOp, [CmmExpr]))+callishMachOps = listToUFM $+ map (\(x, y) -> (mkFastString x, y)) [+ ( "write_barrier", (,) MO_WriteBarrier ),+ ( "memcpy", memcpyLikeTweakArgs MO_Memcpy ),+ ( "memset", memcpyLikeTweakArgs MO_Memset ),+ ( "memmove", memcpyLikeTweakArgs MO_Memmove ),++ ("prefetch0", (,) $ MO_Prefetch_Data 0),+ ("prefetch1", (,) $ MO_Prefetch_Data 1),+ ("prefetch2", (,) $ MO_Prefetch_Data 2),+ ("prefetch3", (,) $ MO_Prefetch_Data 3),++ ( "popcnt8", (,) $ MO_PopCnt W8 ),+ ( "popcnt16", (,) $ MO_PopCnt W16 ),+ ( "popcnt32", (,) $ MO_PopCnt W32 ),+ ( "popcnt64", (,) $ MO_PopCnt W64 ),++ ( "cmpxchg8", (,) $ MO_Cmpxchg W8 ),+ ( "cmpxchg16", (,) $ MO_Cmpxchg W16 ),+ ( "cmpxchg32", (,) $ MO_Cmpxchg W32 ),+ ( "cmpxchg64", (,) $ MO_Cmpxchg W64 )++ -- ToDo: the rest, maybe+ -- edit: which rest?+ -- also: how do we tell CMM Lint how to type check callish macops?+ ]+ where+ memcpyLikeTweakArgs :: (Int -> CallishMachOp) -> [CmmExpr] -> (CallishMachOp, [CmmExpr])+ memcpyLikeTweakArgs op [] = pgmError "memcpy-like function requires at least one argument"+ memcpyLikeTweakArgs op args@(_:_) =+ (op align, args')+ where+ args' = init args+ align = case last args of+ CmmLit (CmmInt alignInteger _) -> fromInteger alignInteger+ e -> pprPgmError "Non-constant alignment in memcpy-like function:" (ppr e)+ -- The alignment of memcpy-ish operations must be a+ -- compile-time constant. We verify this here, passing it around+ -- in the MO_* constructor. In order to do this, however, we+ -- must intercept the arguments in primCall.++parseSafety :: String -> PD Safety+parseSafety "safe" = return PlaySafe+parseSafety "unsafe" = return PlayRisky+parseSafety "interruptible" = return PlayInterruptible+parseSafety str = fail ("unrecognised safety: " ++ str)++parseCmmHint :: String -> PD ForeignHint+parseCmmHint "ptr" = return AddrHint+parseCmmHint "signed" = return SignedHint+parseCmmHint str = fail ("unrecognised hint: " ++ str)++-- labels are always pointers, so we might as well infer the hint+inferCmmHint :: CmmExpr -> ForeignHint+inferCmmHint (CmmLit (CmmLabel _)) = AddrHint+inferCmmHint (CmmReg (CmmGlobal g)) | isPtrGlobalReg g = AddrHint+inferCmmHint _ = NoHint++isPtrGlobalReg Sp = True+isPtrGlobalReg SpLim = True+isPtrGlobalReg Hp = True+isPtrGlobalReg HpLim = True+isPtrGlobalReg CCCS = True+isPtrGlobalReg CurrentTSO = True+isPtrGlobalReg CurrentNursery = True+isPtrGlobalReg (VanillaReg _ VGcPtr) = True+isPtrGlobalReg _ = False++happyError :: PD a+happyError = PD $ \_ s -> unP srcParseFail s++-- -----------------------------------------------------------------------------+-- Statement-level macros++stmtMacro :: FastString -> [CmmParse CmmExpr] -> PD (CmmParse ())+stmtMacro fun args_code = do+ case lookupUFM stmtMacros fun of+ Nothing -> fail ("unknown macro: " ++ unpackFS fun)+ Just fcode -> return $ do+ args <- sequence args_code+ code (fcode args)++stmtMacros :: UniqFM ([CmmExpr] -> FCode ())+stmtMacros = listToUFM [+ ( fsLit "CCS_ALLOC", \[words,ccs] -> profAlloc words ccs ),+ ( fsLit "ENTER_CCS_THUNK", \[e] -> enterCostCentreThunk e ),++ ( fsLit "CLOSE_NURSERY", \[] -> emitCloseNursery ),+ ( fsLit "OPEN_NURSERY", \[] -> emitOpenNursery ),++ -- completely generic heap and stack checks, for use in high-level cmm.+ ( fsLit "HP_CHK_GEN", \[bytes] ->+ heapStackCheckGen Nothing (Just bytes) ),+ ( fsLit "STK_CHK_GEN", \[] ->+ heapStackCheckGen (Just (CmmLit CmmHighStackMark)) Nothing ),++ -- A stack check for a fixed amount of stack. Sounds a bit strange, but+ -- we use the stack for a bit of temporary storage in a couple of primops+ ( fsLit "STK_CHK_GEN_N", \[bytes] ->+ heapStackCheckGen (Just bytes) Nothing ),++ -- A stack check on entry to a thunk, where the argument is the thunk pointer.+ ( fsLit "STK_CHK_NP" , \[node] -> entryHeapCheck' False node 0 [] (return ())),++ ( fsLit "LOAD_THREAD_STATE", \[] -> emitLoadThreadState ),+ ( fsLit "SAVE_THREAD_STATE", \[] -> emitSaveThreadState ),++ ( fsLit "LDV_ENTER", \[e] -> ldvEnter e ),+ ( fsLit "LDV_RECORD_CREATE", \[e] -> ldvRecordCreate e ),++ ( fsLit "PUSH_UPD_FRAME", \[sp,e] -> emitPushUpdateFrame sp e ),+ ( fsLit "SET_HDR", \[ptr,info,ccs] ->+ emitSetDynHdr ptr info ccs ),+ ( fsLit "TICK_ALLOC_PRIM", \[hdr,goods,slop] ->+ tickyAllocPrim hdr goods slop ),+ ( fsLit "TICK_ALLOC_PAP", \[goods,slop] ->+ tickyAllocPAP goods slop ),+ ( fsLit "TICK_ALLOC_UP_THK", \[goods,slop] ->+ tickyAllocThunk goods slop ),+ ( fsLit "UPD_BH_UPDATABLE", \[reg] -> emitBlackHoleCode reg )+ ]++emitPushUpdateFrame :: CmmExpr -> CmmExpr -> FCode ()+emitPushUpdateFrame sp e = do+ dflags <- getDynFlags+ emitUpdateFrame dflags sp mkUpdInfoLabel e++pushStackFrame :: [CmmParse CmmExpr] -> CmmParse () -> CmmParse ()+pushStackFrame fields body = do+ dflags <- getDynFlags+ exprs <- sequence fields+ updfr_off <- getUpdFrameOff+ let (new_updfr_off, _, g) = copyOutOflow dflags NativeReturn Ret Old+ [] updfr_off exprs+ emit g+ withUpdFrameOff new_updfr_off body++reserveStackFrame+ :: CmmParse CmmExpr+ -> CmmParse CmmReg+ -> CmmParse ()+ -> CmmParse ()+reserveStackFrame psize preg body = do+ dflags <- getDynFlags+ old_updfr_off <- getUpdFrameOff+ reg <- preg+ esize <- psize+ let size = case constantFoldExpr dflags esize of+ CmmLit (CmmInt n _) -> n+ _other -> pprPanic "CmmParse: not a compile-time integer: "+ (ppr esize)+ let frame = old_updfr_off + wORD_SIZE dflags * fromIntegral size+ emitAssign reg (CmmStackSlot Old frame)+ withUpdFrameOff frame body++profilingInfo dflags desc_str ty_str+ = if not (gopt Opt_SccProfilingOn dflags)+ then NoProfilingInfo+ else ProfilingInfo (stringToWord8s desc_str)+ (stringToWord8s ty_str)++staticClosure :: UnitId -> FastString -> FastString -> [CmmLit] -> CmmParse ()+staticClosure pkg cl_label info payload+ = do dflags <- getDynFlags+ let lits = mkStaticClosure dflags (mkCmmInfoLabel pkg info) dontCareCCS payload [] [] []+ code $ emitDataLits (mkCmmDataLabel pkg cl_label) lits++foreignCall+ :: String+ -> [CmmParse (LocalReg, ForeignHint)]+ -> CmmParse CmmExpr+ -> [CmmParse (CmmExpr, ForeignHint)]+ -> Safety+ -> CmmReturnInfo+ -> PD (CmmParse ())+foreignCall conv_string results_code expr_code args_code safety ret+ = do conv <- case conv_string of+ "C" -> return CCallConv+ "stdcall" -> return StdCallConv+ _ -> fail ("unknown calling convention: " ++ conv_string)+ return $ do+ dflags <- getDynFlags+ results <- sequence results_code+ expr <- expr_code+ args <- sequence args_code+ let+ expr' = adjCallTarget dflags conv expr args+ (arg_exprs, arg_hints) = unzip args+ (res_regs, res_hints) = unzip results+ fc = ForeignConvention conv arg_hints res_hints ret+ target = ForeignTarget expr' fc+ _ <- code $ emitForeignCall safety res_regs target arg_exprs+ return ()+++doReturn :: [CmmParse CmmExpr] -> CmmParse ()+doReturn exprs_code = do+ dflags <- getDynFlags+ exprs <- sequence exprs_code+ updfr_off <- getUpdFrameOff+ emit (mkReturnSimple dflags exprs updfr_off)++mkReturnSimple :: DynFlags -> [CmmActual] -> UpdFrameOffset -> CmmAGraph+mkReturnSimple dflags actuals updfr_off =+ mkReturn dflags e actuals updfr_off+ where e = entryCode dflags (CmmLoad (CmmStackSlot Old updfr_off)+ (gcWord dflags))++doRawJump :: CmmParse CmmExpr -> [GlobalReg] -> CmmParse ()+doRawJump expr_code vols = do+ dflags <- getDynFlags+ expr <- expr_code+ updfr_off <- getUpdFrameOff+ emit (mkRawJump dflags expr updfr_off vols)++doJumpWithStack :: CmmParse CmmExpr -> [CmmParse CmmExpr]+ -> [CmmParse CmmExpr] -> CmmParse ()+doJumpWithStack expr_code stk_code args_code = do+ dflags <- getDynFlags+ expr <- expr_code+ stk_args <- sequence stk_code+ args <- sequence args_code+ updfr_off <- getUpdFrameOff+ emit (mkJumpExtra dflags NativeNodeCall expr args updfr_off stk_args)++doCall :: CmmParse CmmExpr -> [CmmParse LocalReg] -> [CmmParse CmmExpr]+ -> CmmParse ()+doCall expr_code res_code args_code = do+ dflags <- getDynFlags+ expr <- expr_code+ args <- sequence args_code+ ress <- sequence res_code+ updfr_off <- getUpdFrameOff+ c <- code $ mkCall expr (NativeNodeCall,NativeReturn) ress args updfr_off []+ emit c++adjCallTarget :: DynFlags -> CCallConv -> CmmExpr -> [(CmmExpr, ForeignHint) ]+ -> CmmExpr+-- On Windows, we have to add the '@N' suffix to the label when making+-- a call with the stdcall calling convention.+adjCallTarget dflags StdCallConv (CmmLit (CmmLabel lbl)) args+ | platformOS (targetPlatform dflags) == OSMinGW32+ = CmmLit (CmmLabel (addLabelSize lbl (sum (map size args))))+ where size (e, _) = max (wORD_SIZE dflags) (widthInBytes (typeWidth (cmmExprType dflags e)))+ -- c.f. CgForeignCall.emitForeignCall+adjCallTarget _ _ expr _+ = expr++primCall+ :: [CmmParse (CmmFormal, ForeignHint)]+ -> FastString+ -> [CmmParse CmmExpr]+ -> PD (CmmParse ())+primCall results_code name args_code+ = case lookupUFM callishMachOps name of+ Nothing -> fail ("unknown primitive " ++ unpackFS name)+ Just f -> return $ do+ results <- sequence results_code+ args <- sequence args_code+ let (p, args') = f args+ code (emitPrimCall (map fst results) p args')++doStore :: CmmType -> CmmParse CmmExpr -> CmmParse CmmExpr -> CmmParse ()+doStore rep addr_code val_code+ = do dflags <- getDynFlags+ addr <- addr_code+ val <- val_code+ -- if the specified store type does not match the type of the expr+ -- on the rhs, then we insert a coercion that will cause the type+ -- mismatch to be flagged by cmm-lint. If we don't do this, then+ -- the store will happen at the wrong type, and the error will not+ -- be noticed.+ let val_width = typeWidth (cmmExprType dflags val)+ rep_width = typeWidth rep+ let coerce_val+ | val_width /= rep_width = CmmMachOp (MO_UU_Conv val_width rep_width) [val]+ | otherwise = val+ emitStore addr coerce_val++-- -----------------------------------------------------------------------------+-- If-then-else and boolean expressions++data BoolExpr+ = BoolExpr `BoolAnd` BoolExpr+ | BoolExpr `BoolOr` BoolExpr+ | BoolNot BoolExpr+ | BoolTest CmmExpr++-- ToDo: smart constructors which simplify the boolean expression.++cmmIfThenElse cond then_part else_part = do+ then_id <- newBlockId+ join_id <- newBlockId+ c <- cond+ emitCond c then_id+ else_part+ emit (mkBranch join_id)+ emitLabel then_id+ then_part+ -- fall through to join+ emitLabel join_id++cmmRawIf cond then_id = do+ c <- cond+ emitCond c then_id++-- 'emitCond cond true_id' emits code to test whether the cond is true,+-- branching to true_id if so, and falling through otherwise.+emitCond (BoolTest e) then_id = do+ else_id <- newBlockId+ emit (mkCbranch e then_id else_id Nothing)+ emitLabel else_id+emitCond (BoolNot (BoolTest (CmmMachOp op args))) then_id+ | Just op' <- maybeInvertComparison op+ = emitCond (BoolTest (CmmMachOp op' args)) then_id+emitCond (BoolNot e) then_id = do+ else_id <- newBlockId+ emitCond e else_id+ emit (mkBranch then_id)+ emitLabel else_id+emitCond (e1 `BoolOr` e2) then_id = do+ emitCond e1 then_id+ emitCond e2 then_id+emitCond (e1 `BoolAnd` e2) then_id = do+ -- we'd like to invert one of the conditionals here to avoid an+ -- extra branch instruction, but we can't use maybeInvertComparison+ -- here because we can't look too closely at the expression since+ -- we're in a loop.+ and_id <- newBlockId+ else_id <- newBlockId+ emitCond e1 and_id+ emit (mkBranch else_id)+ emitLabel and_id+ emitCond e2 then_id+ emitLabel else_id++-- -----------------------------------------------------------------------------+-- Source code notes++-- | Generate a source note spanning from "a" to "b" (inclusive), then+-- proceed with parsing. This allows debugging tools to reason about+-- locations in Cmm code.+withSourceNote :: Located a -> Located b -> CmmParse c -> CmmParse c+withSourceNote a b parse = do+ name <- getName+ case combineSrcSpans (getLoc a) (getLoc b) of+ RealSrcSpan span -> code (emitTick (SourceNote span name)) >> parse+ _other -> parse++-- -----------------------------------------------------------------------------+-- Table jumps++-- We use a simplified form of C-- switch statements for now. A+-- switch statement always compiles to a table jump. Each arm can+-- specify a list of values (not ranges), and there can be a single+-- default branch. The range of the table is given either by the+-- optional range on the switch (eg. switch [0..7] {...}), or by+-- the minimum/maximum values from the branches.++doSwitch :: Maybe (Integer,Integer)+ -> CmmParse CmmExpr+ -> [([Integer],Either BlockId (CmmParse ()))]+ -> Maybe (CmmParse ()) -> CmmParse ()+doSwitch mb_range scrut arms deflt+ = do+ -- Compile code for the default branch+ dflt_entry <- + case deflt of+ Nothing -> return Nothing+ Just e -> do b <- forkLabelledCode e; return (Just b)++ -- Compile each case branch+ table_entries <- mapM emitArm arms+ let table = M.fromList (concat table_entries)++ dflags <- getDynFlags+ let range = fromMaybe (0, tARGET_MAX_WORD dflags) mb_range++ expr <- scrut+ -- ToDo: check for out of range and jump to default if necessary+ emit $ mkSwitch expr (mkSwitchTargets False range dflt_entry table)+ where+ emitArm :: ([Integer],Either BlockId (CmmParse ())) -> CmmParse [(Integer,BlockId)]+ emitArm (ints,Left blockid) = return [ (i,blockid) | i <- ints ]+ emitArm (ints,Right code) = do+ blockid <- forkLabelledCode code+ return [ (i,blockid) | i <- ints ]++forkLabelledCode :: CmmParse () -> CmmParse BlockId+forkLabelledCode p = do+ (_,ag) <- getCodeScoped p+ l <- newBlockId+ emitOutOfLine l ag+ return l++-- -----------------------------------------------------------------------------+-- Putting it all together++-- The initial environment: we define some constants that the compiler+-- knows about here.+initEnv :: DynFlags -> Env+initEnv dflags = listToUFM [+ ( fsLit "SIZEOF_StgHeader",+ VarN (CmmLit (CmmInt (fromIntegral (fixedHdrSize dflags)) (wordWidth dflags)) )),+ ( fsLit "SIZEOF_StgInfoTable",+ VarN (CmmLit (CmmInt (fromIntegral (stdInfoTableSizeB dflags)) (wordWidth dflags)) ))+ ]++parseCmmFile :: DynFlags -> FilePath -> IO (Messages, Maybe CmmGroup)+parseCmmFile dflags filename = withTiming (pure dflags) (text "ParseCmm"<+>brackets (text filename)) (\_ -> ()) $ do+ buf <- hGetStringBuffer filename+ let+ init_loc = mkRealSrcLoc (mkFastString filename) 1 1+ init_state = (mkPState dflags buf init_loc) { lex_state = [0] }+ -- reset the lex_state: the Lexer monad leaves some stuff+ -- in there we don't want.+ case unPD cmmParse dflags init_state of+ PFailed span err -> do+ let msg = mkPlainErrMsg dflags span err+ return ((emptyBag, unitBag msg), Nothing)+ POk pst code -> do+ st <- initC+ let fcode = getCmm $ unEC code "global" (initEnv dflags) [] >> return ()+ (cmm,_) = runC dflags no_module st fcode+ let ms = getMessages pst dflags+ if (errorsFound dflags ms)+ then return (ms, Nothing)+ else return (ms, Just cmm)+ where+ no_module = panic "parseCmmFile: no module"+}
+ cmm/CmmPipeline.hs view
@@ -0,0 +1,365 @@+{-# LANGUAGE BangPatterns #-}++module CmmPipeline (+ -- | Converts C-- with an implicit stack and native C-- calls into+ -- optimized, CPS converted and native-call-less C--. The latter+ -- C-- can be used to generate assembly.+ cmmPipeline+) where++import Cmm+import CmmLint+import CmmBuildInfoTables+import CmmCommonBlockElim+import CmmImplementSwitchPlans+import CmmProcPoint+import CmmContFlowOpt+import CmmLayoutStack+import CmmSink+import Hoopl++import UniqSupply+import DynFlags+import ErrUtils+import HscTypes+import Control.Monad+import Outputable+import Platform++-----------------------------------------------------------------------------+-- | Top level driver for C-- pipeline+-----------------------------------------------------------------------------++cmmPipeline :: HscEnv -- Compilation env including+ -- dynamic flags: -dcmm-lint -ddump-cmm-cps+ -> TopSRT -- SRT table and accumulating list of compiled procs+ -> CmmGroup -- Input C-- with Procedures+ -> IO (TopSRT, CmmGroup) -- Output CPS transformed C--++cmmPipeline hsc_env topSRT prog =+ do let dflags = hsc_dflags hsc_env++ tops <- {-# SCC "tops" #-} mapM (cpsTop hsc_env) prog++ (topSRT, cmms) <- {-# SCC "doSRTs" #-} doSRTs dflags topSRT tops+ dumpWith dflags Opt_D_dump_cmm_cps "Post CPS Cmm" (ppr cmms)++ return (topSRT, cmms)+++cpsTop :: HscEnv -> CmmDecl -> IO (CAFEnv, [CmmDecl])+cpsTop _ p@(CmmData {}) = return (mapEmpty, [p])+cpsTop hsc_env proc =+ do+ ----------- Control-flow optimisations ----------------------------------++ -- The first round of control-flow optimisation speeds up the+ -- later passes by removing lots of empty blocks, so we do it+ -- even when optimisation isn't turned on.+ --+ CmmProc h l v g <- {-# SCC "cmmCfgOpts(1)" #-}+ return $ cmmCfgOptsProc splitting_proc_points proc+ dump Opt_D_dump_cmm_cfg "Post control-flow optimisations" g++ let !TopInfo {stack_info=StackInfo { arg_space = entry_off+ , do_layout = do_layout }} = h++ ----------- Eliminate common blocks -------------------------------------+ g <- {-# SCC "elimCommonBlocks" #-}+ condPass Opt_CmmElimCommonBlocks elimCommonBlocks g+ Opt_D_dump_cmm_cbe "Post common block elimination"++ -- Any work storing block Labels must be performed _after_+ -- elimCommonBlocks++ g <- {-# SCC "createSwitchPlans" #-}+ runUniqSM $ cmmImplementSwitchPlans dflags g+ dump Opt_D_dump_cmm_switch "Post switch plan" g++ ----------- Proc points -------------------------------------------------+ let call_pps = {-# SCC "callProcPoints" #-} callProcPoints g+ proc_points <-+ if splitting_proc_points+ then do+ pp <- {-# SCC "minimalProcPointSet" #-} runUniqSM $+ minimalProcPointSet (targetPlatform dflags) call_pps g+ dumpWith dflags Opt_D_dump_cmm_proc "Proc points"+ (ppr l $$ ppr pp $$ ppr g)+ return pp+ else+ return call_pps++ ----------- Layout the stack and manifest Sp ----------------------------+ (g, stackmaps) <-+ {-# SCC "layoutStack" #-}+ if do_layout+ then runUniqSM $ cmmLayoutStack dflags proc_points entry_off g+ else return (g, mapEmpty)+ dump Opt_D_dump_cmm_sp "Layout Stack" g++ ----------- Sink and inline assignments --------------------------------+ g <- {-# SCC "sink" #-} -- See Note [Sinking after stack layout]+ condPass Opt_CmmSink (cmmSink dflags) g+ Opt_D_dump_cmm_sink "Sink assignments"++ ------------- CAF analysis ----------------------------------------------+ let cafEnv = {-# SCC "cafAnal" #-} cafAnal g+ dumpWith dflags Opt_D_dump_cmm_caf "CAFEnv" (ppr cafEnv)++ g <- if splitting_proc_points+ then do+ ------------- Split into separate procedures -----------------------+ let pp_map = {-# SCC "procPointAnalysis" #-}+ procPointAnalysis proc_points g+ dumpWith dflags Opt_D_dump_cmm_procmap "procpoint map" $+ ppr pp_map+ g <- {-# SCC "splitAtProcPoints" #-} runUniqSM $+ splitAtProcPoints dflags l call_pps proc_points pp_map+ (CmmProc h l v g)+ dumps Opt_D_dump_cmm_split "Post splitting" g+ return g+ else do+ -- attach info tables to return points+ return $ [attachContInfoTables call_pps (CmmProc h l v g)]++ ------------- Populate info tables with stack info -----------------+ g <- {-# SCC "setInfoTableStackMap" #-}+ return $ map (setInfoTableStackMap dflags stackmaps) g+ dumps Opt_D_dump_cmm_info "after setInfoTableStackMap" g++ ----------- Control-flow optimisations -----------------------------+ g <- {-# SCC "cmmCfgOpts(2)" #-}+ return $ if optLevel dflags >= 1+ then map (cmmCfgOptsProc splitting_proc_points) g+ else g+ g <- return (map removeUnreachableBlocksProc g)+ -- See Note [unreachable blocks]+ dumps Opt_D_dump_cmm_cfg "Post control-flow optimisations" g++ return (cafEnv, g)++ where dflags = hsc_dflags hsc_env+ platform = targetPlatform dflags+ dump = dumpGraph dflags++ dumps flag name+ = mapM_ (dumpWith dflags flag name . ppr)++ condPass flag pass g dumpflag dumpname =+ if gopt flag dflags+ then do+ g <- return $ pass g+ dump dumpflag dumpname g+ return g+ else return g+++ -- we don't need to split proc points for the NCG, unless+ -- tablesNextToCode is off. The latter is because we have no+ -- label to put on info tables for basic blocks that are not+ -- the entry point.+ splitting_proc_points = hscTarget dflags /= HscAsm+ || not (tablesNextToCode dflags)+ || -- Note [inconsistent-pic-reg]+ usingInconsistentPicReg+ usingInconsistentPicReg+ = case (platformArch platform, platformOS platform, gopt Opt_PIC dflags)+ of (ArchX86, OSDarwin, pic) -> pic+ (ArchPPC, OSDarwin, pic) -> pic+ _ -> False++-- Note [Sinking after stack layout]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- In the past we considered running sinking pass also before stack+-- layout, but after making some measurements we realized that:+--+-- a) running sinking only before stack layout produces slower+-- code than running sinking only before stack layout+--+-- b) running sinking both before and after stack layout produces+-- code that has the same performance as when running sinking+-- only after stack layout.+--+-- In other words sinking before stack layout doesn't buy as anything.+--+-- An interesting question is "why is it better to run sinking after+-- stack layout"? It seems that the major reason are stores and loads+-- generated by stack layout. Consider this code before stack layout:+--+-- c1E:+-- _c1C::P64 = R3;+-- _c1B::P64 = R2;+-- _c1A::P64 = R1;+-- I64[(young<c1D> + 8)] = c1D;+-- call stg_gc_noregs() returns to c1D, args: 8, res: 8, upd: 8;+-- c1D:+-- R3 = _c1C::P64;+-- R2 = _c1B::P64;+-- R1 = _c1A::P64;+-- call (P64[(old + 8)])(R3, R2, R1) args: 8, res: 0, upd: 8;+--+-- Stack layout pass will save all local variables live across a call+-- (_c1C, _c1B and _c1A in this example) on the stack just before+-- making a call and reload them from the stack after returning from a+-- call:+--+-- c1E:+-- _c1C::P64 = R3;+-- _c1B::P64 = R2;+-- _c1A::P64 = R1;+-- I64[Sp - 32] = c1D;+-- P64[Sp - 24] = _c1A::P64;+-- P64[Sp - 16] = _c1B::P64;+-- P64[Sp - 8] = _c1C::P64;+-- Sp = Sp - 32;+-- call stg_gc_noregs() returns to c1D, args: 8, res: 8, upd: 8;+-- c1D:+-- _c1A::P64 = P64[Sp + 8];+-- _c1B::P64 = P64[Sp + 16];+-- _c1C::P64 = P64[Sp + 24];+-- R3 = _c1C::P64;+-- R2 = _c1B::P64;+-- R1 = _c1A::P64;+-- Sp = Sp + 32;+-- call (P64[Sp])(R3, R2, R1) args: 8, res: 0, upd: 8;+--+-- If we don't run sinking pass after stack layout we are basically+-- left with such code. However, running sinking on this code can lead+-- to significant improvements:+--+-- c1E:+-- I64[Sp - 32] = c1D;+-- P64[Sp - 24] = R1;+-- P64[Sp - 16] = R2;+-- P64[Sp - 8] = R3;+-- Sp = Sp - 32;+-- call stg_gc_noregs() returns to c1D, args: 8, res: 8, upd: 8;+-- c1D:+-- R3 = P64[Sp + 24];+-- R2 = P64[Sp + 16];+-- R1 = P64[Sp + 8];+-- Sp = Sp + 32;+-- call (P64[Sp])(R3, R2, R1) args: 8, res: 0, upd: 8;+--+-- Now we only have 9 assignments instead of 15.+--+-- There is one case when running sinking before stack layout could+-- be beneficial. Consider this:+--+-- L1:+-- x = y+-- call f() returns L2+-- L2: ...x...y...+--+-- Since both x and y are live across a call to f, they will be stored+-- on the stack during stack layout and restored after the call:+--+-- L1:+-- x = y+-- P64[Sp - 24] = L2+-- P64[Sp - 16] = x+-- P64[Sp - 8] = y+-- Sp = Sp - 24+-- call f() returns L2+-- L2:+-- y = P64[Sp + 16]+-- x = P64[Sp + 8]+-- Sp = Sp + 24+-- ...x...y...+--+-- However, if we run sinking before stack layout we would propagate x+-- to its usage place (both x and y must be local register for this to+-- be possible - global registers cannot be floated past a call):+--+-- L1:+-- x = y+-- call f() returns L2+-- L2: ...y...y...+--+-- Thus making x dead at the call to f(). If we ran stack layout now+-- we would generate less stores and loads:+--+-- L1:+-- x = y+-- P64[Sp - 16] = L2+-- P64[Sp - 8] = y+-- Sp = Sp - 16+-- call f() returns L2+-- L2:+-- y = P64[Sp + 8]+-- Sp = Sp + 16+-- ...y...y...+--+-- But since we don't see any benefits from running sinking befroe stack+-- layout, this situation probably doesn't arise too often in practice.+--++{- Note [inconsistent-pic-reg]++On x86/Darwin, PIC is implemented by inserting a sequence like++ call 1f+ 1: popl %reg++at the proc entry point, and then referring to labels as offsets from+%reg. If we don't split proc points, then we could have many entry+points in a proc that would need this sequence, and each entry point+would then get a different value for %reg. If there are any join+points, then at the join point we don't have a consistent value for+%reg, so we don't know how to refer to labels.++Hence, on x86/Darwin, we have to split proc points, and then each proc+point will get its own PIC initialisation sequence.++The situation is the same for ppc/Darwin. We use essentially the same+sequence to load the program counter onto reg:++ bcl 20,31,1f+ 1: mflr reg++This isn't an issue on x86/ELF, where the sequence is++ call 1f+ 1: popl %reg+ addl $_GLOBAL_OFFSET_TABLE_+(.-1b), %reg++so %reg always has a consistent value: the address of+_GLOBAL_OFFSET_TABLE_, regardless of which entry point we arrived via.++-}++{- Note [unreachable blocks]++The control-flow optimiser sometimes leaves unreachable blocks behind+containing junk code. These aren't necessarily a problem, but+removing them is good because it might save time in the native code+generator later.++-}++runUniqSM :: UniqSM a -> IO a+runUniqSM m = do+ us <- mkSplitUniqSupply 'u'+ return (initUs_ us m)+++dumpGraph :: DynFlags -> DumpFlag -> String -> CmmGraph -> IO ()+dumpGraph dflags flag name g = do+ when (gopt Opt_DoCmmLinting dflags) $ do_lint g+ dumpWith dflags flag name (ppr g)+ where+ do_lint g = case cmmLintGraph dflags g of+ Just err -> do { fatalErrorMsg dflags err+ ; ghcExit dflags 1+ }+ Nothing -> return ()++dumpWith :: DynFlags -> DumpFlag -> String -> SDoc -> IO ()+dumpWith dflags flag txt sdoc = do+ -- ToDo: No easy way of say "dump all the cmm, *and* split+ -- them into files." Also, -ddump-cmm-verbose doesn't play+ -- nicely with -ddump-to-file, since the headers get omitted.+ dumpIfSet_dyn dflags flag txt sdoc+ when (not (dopt flag dflags)) $+ dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose txt sdoc
+ cmm/CmmProcPoint.hs view
@@ -0,0 +1,490 @@+{-# LANGUAGE GADTs, DisambiguateRecordFields, BangPatterns #-}++module CmmProcPoint+ ( ProcPointSet, Status(..)+ , callProcPoints, minimalProcPointSet+ , splitAtProcPoints, procPointAnalysis+ , attachContInfoTables+ )+where++import Prelude hiding (last, unzip, succ, zip)++import DynFlags+import BlockId+import CLabel+import Cmm+import PprCmm ()+import CmmUtils+import CmmInfo+import CmmLive+import CmmSwitch+import Data.List (sortBy)+import Maybes+import Control.Monad+import Outputable+import Platform+import UniqSupply+import Hoopl++-- Compute a minimal set of proc points for a control-flow graph.++-- Determine a protocol for each proc point (which live variables will+-- be passed as arguments and which will be on the stack).++{-+A proc point is a basic block that, after CPS transformation, will+start a new function. The entry block of the original function is a+proc point, as is the continuation of each function call.+A third kind of proc point arises if we want to avoid copying code.+Suppose we have code like the following:++ f() {+ if (...) { ..1..; call foo(); ..2..}+ else { ..3..; call bar(); ..4..}+ x = y + z;+ return x;+ }++The statement 'x = y + z' can be reached from two different proc+points: the continuations of foo() and bar(). We would prefer not to+put a copy in each continuation; instead we would like 'x = y + z' to+be the start of a new procedure to which the continuations can jump:++ f_cps () {+ if (...) { ..1..; push k_foo; jump foo_cps(); }+ else { ..3..; push k_bar; jump bar_cps(); }+ }+ k_foo() { ..2..; jump k_join(y, z); }+ k_bar() { ..4..; jump k_join(y, z); }+ k_join(y, z) { x = y + z; return x; }++You might think then that a criterion to make a node a proc point is+that it is directly reached by two distinct proc points. (Note+[Direct reachability].) But this criterion is a bit too simple; for+example, 'return x' is also reached by two proc points, yet there is+no point in pulling it out of k_join. A good criterion would be to+say that a node should be made a proc point if it is reached by a set+of proc points that is different than its immediate dominator. NR+believes this criterion can be shown to produce a minimum set of proc+points, and given a dominator tree, the proc points can be chosen in+time linear in the number of blocks. Lacking a dominator analysis,+however, we turn instead to an iterative solution, starting with no+proc points and adding them according to these rules:++ 1. The entry block is a proc point.+ 2. The continuation of a call is a proc point.+ 3. A node is a proc point if it is directly reached by more proc+ points than one of its predecessors.++Because we don't understand the problem very well, we apply rule 3 at+most once per iteration, then recompute the reachability information.+(See Note [No simple dataflow].) The choice of the new proc point is+arbitrary, and I don't know if the choice affects the final solution,+so I don't know if the number of proc points chosen is the+minimum---but the set will be minimal.++++Note [Proc-point analysis]+~~~~~~~~~~~~~~~~~~~~~~~~~~++Given a specified set of proc-points (a set of block-ids), "proc-point+analysis" figures out, for every block, which proc-point it belongs to.+All the blocks belonging to proc-point P will constitute a single+top-level C procedure.++A non-proc-point block B "belongs to" a proc-point P iff B is+reachable from P without going through another proc-point.++Invariant: a block B should belong to at most one proc-point; if it+belongs to two, that's a bug.++Note [Non-existing proc-points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++On some architectures it might happen that the list of proc-points+computed before stack layout pass will be invalidated by the stack+layout. This will happen if stack layout removes from the graph+blocks that were determined to be proc-points. Later on in the pipeline+we use list of proc-points to perform [Proc-point analysis], but+if a proc-point does not exist anymore then we will get compiler panic.+See #8205.+-}++type ProcPointSet = LabelSet++data Status+ = ReachedBy ProcPointSet -- set of proc points that directly reach the block+ | ProcPoint -- this block is itself a proc point++instance Outputable Status where+ ppr (ReachedBy ps)+ | setNull ps = text "<not-reached>"+ | otherwise = text "reached by" <+>+ (hsep $ punctuate comma $ map ppr $ setElems ps)+ ppr ProcPoint = text "<procpt>"++--------------------------------------------------+-- Proc point analysis++-- Once you know what the proc-points are, figure out+-- what proc-points each block is reachable from+-- See Note [Proc-point analysis]+procPointAnalysis :: ProcPointSet -> CmmGraph -> LabelMap Status+procPointAnalysis procPoints cmmGraph@(CmmGraph {g_graph = graph}) =+ analyzeCmmFwd procPointLattice procPointTransfer cmmGraph initProcPoints+ where+ initProcPoints =+ mkFactBase+ procPointLattice+ [ (id, ProcPoint)+ | id <- setElems procPoints+ -- See Note [Non-existing proc-points]+ , id `setMember` labelsInGraph+ ]+ labelsInGraph = labelsDefined graph++procPointTransfer :: TransferFun Status+procPointTransfer block facts =+ let label = entryLabel block+ !fact = case getFact procPointLattice label facts of+ ProcPoint -> ReachedBy $! setSingleton label+ f -> f+ result = map (\id -> (id, fact)) (successors block)+ in mkFactBase procPointLattice result++procPointLattice :: DataflowLattice Status+procPointLattice = DataflowLattice unreached add_to+ where+ unreached = ReachedBy setEmpty+ add_to (OldFact ProcPoint) _ = NotChanged ProcPoint+ add_to _ (NewFact ProcPoint) = Changed ProcPoint -- because of previous case+ add_to (OldFact (ReachedBy p)) (NewFact (ReachedBy p'))+ | setSize union > setSize p = Changed (ReachedBy union)+ | otherwise = NotChanged (ReachedBy p)+ where+ union = setUnion p' p++----------------------------------------------------------------------++-- It is worth distinguishing two sets of proc points: those that are+-- induced by calls in the original graph and those that are+-- introduced because they're reachable from multiple proc points.+--+-- Extract the set of Continuation BlockIds, see Note [Continuation BlockIds].+callProcPoints :: CmmGraph -> ProcPointSet+callProcPoints g = foldGraphBlocks add (setSingleton (g_entry g)) g+ where add :: CmmBlock -> LabelSet -> LabelSet+ add b set = case lastNode b of+ CmmCall {cml_cont = Just k} -> setInsert k set+ CmmForeignCall {succ=k} -> setInsert k set+ _ -> set++minimalProcPointSet :: Platform -> ProcPointSet -> CmmGraph+ -> UniqSM ProcPointSet+-- Given the set of successors of calls (which must be proc-points)+-- figure out the minimal set of necessary proc-points+minimalProcPointSet platform callProcPoints g+ = extendPPSet platform g (postorderDfs g) callProcPoints++extendPPSet+ :: Platform -> CmmGraph -> [CmmBlock] -> ProcPointSet -> UniqSM ProcPointSet+extendPPSet platform g blocks procPoints =+ let env = procPointAnalysis procPoints g+ add block pps = let id = entryLabel block+ in case mapLookup id env of+ Just ProcPoint -> setInsert id pps+ _ -> pps+ procPoints' = foldGraphBlocks add setEmpty g+ newPoints = mapMaybe ppSuccessor blocks+ newPoint = listToMaybe newPoints+ ppSuccessor b =+ let nreached id = case mapLookup id env `orElse`+ pprPanic "no ppt" (ppr id <+> ppr b) of+ ProcPoint -> 1+ ReachedBy ps -> setSize ps+ block_procpoints = nreached (entryLabel b)+ -- | Looking for a successor of b that is reached by+ -- more proc points than b and is not already a proc+ -- point. If found, it can become a proc point.+ newId succ_id = not (setMember succ_id procPoints') &&+ nreached succ_id > block_procpoints+ in listToMaybe $ filter newId $ successors b++ in case newPoint of+ Just id ->+ if setMember id procPoints'+ then panic "added old proc pt"+ else extendPPSet platform g blocks (setInsert id procPoints')+ Nothing -> return procPoints'+++-- At this point, we have found a set of procpoints, each of which should be+-- the entry point of a procedure.+-- Now, we create the procedure for each proc point,+-- which requires that we:+-- 1. build a map from proc points to the blocks reachable from the proc point+-- 2. turn each branch to a proc point into a jump+-- 3. turn calls and returns into jumps+-- 4. build info tables for the procedures -- and update the info table for+-- the SRTs in the entry procedure as well.+-- Input invariant: A block should only be reachable from a single ProcPoint.+-- ToDo: use the _ret naming convention that the old code generator+-- used. -- EZY+splitAtProcPoints :: DynFlags -> CLabel -> ProcPointSet-> ProcPointSet -> LabelMap Status ->+ CmmDecl -> UniqSM [CmmDecl]+splitAtProcPoints dflags entry_label callPPs procPoints procMap+ (CmmProc (TopInfo {info_tbls = info_tbls})+ top_l _ g@(CmmGraph {g_entry=entry})) =+ do -- Build a map from procpoints to the blocks they reach+ let addBlock+ :: CmmBlock+ -> LabelMap (LabelMap CmmBlock)+ -> LabelMap (LabelMap CmmBlock)+ addBlock b graphEnv =+ case mapLookup bid procMap of+ Just ProcPoint -> add graphEnv bid bid b+ Just (ReachedBy set) ->+ case setElems set of+ [] -> graphEnv+ [id] -> add graphEnv id bid b+ _ -> panic "Each block should be reachable from only one ProcPoint"+ Nothing -> graphEnv+ where bid = entryLabel b+ add graphEnv procId bid b = mapInsert procId graph' graphEnv+ where graph = mapLookup procId graphEnv `orElse` mapEmpty+ graph' = mapInsert bid b graph++ let liveness = cmmGlobalLiveness dflags g+ let ppLiveness pp = filter isArgReg $+ regSetToList $+ expectJust "ppLiveness" $ mapLookup pp liveness++ graphEnv <- return $ foldGraphBlocks addBlock mapEmpty g++ -- Build a map from proc point BlockId to pairs of:+ -- * Labels for their new procedures+ -- * Labels for the info tables of their new procedures (only if+ -- the proc point is a callPP)+ -- Due to common blockification, we may overestimate the set of procpoints.+ let add_label map pp = mapInsert pp lbls map+ where lbls | pp == entry = (entry_label, fmap cit_lbl (mapLookup entry info_tbls))+ | otherwise = (block_lbl, guard (setMember pp callPPs) >>+ Just (toInfoLbl block_lbl))+ where block_lbl = blockLbl pp++ procLabels :: LabelMap (CLabel, Maybe CLabel)+ procLabels = foldl add_label mapEmpty+ (filter (flip mapMember (toBlockMap g)) (setElems procPoints))++ -- In each new graph, add blocks jumping off to the new procedures,+ -- and replace branches to procpoints with branches to the jump-off blocks+ let add_jump_block+ :: (LabelMap Label, [CmmBlock])+ -> (Label, CLabel)+ -> UniqSM (LabelMap Label, [CmmBlock])+ add_jump_block (env, bs) (pp, l) =+ do bid <- liftM mkBlockId getUniqueM+ let b = blockJoin (CmmEntry bid GlobalScope) emptyBlock jump+ live = ppLiveness pp+ jump = CmmCall (CmmLit (CmmLabel l)) Nothing live 0 0 0+ return (mapInsert pp bid env, b : bs)++ add_jumps+ :: LabelMap CmmGraph+ -> (Label, LabelMap CmmBlock)+ -> UniqSM (LabelMap CmmGraph)+ add_jumps newGraphEnv (ppId, blockEnv) =+ do let needed_jumps = -- find which procpoints we currently branch to+ mapFold add_if_branch_to_pp [] blockEnv+ add_if_branch_to_pp :: CmmBlock -> [(BlockId, CLabel)] -> [(BlockId, CLabel)]+ add_if_branch_to_pp block rst =+ case lastNode block of+ CmmBranch id -> add_if_pp id rst+ CmmCondBranch _ ti fi _ -> add_if_pp ti (add_if_pp fi rst)+ CmmSwitch _ ids -> foldr add_if_pp rst $ switchTargetsToList ids+ _ -> rst++ -- when jumping to a PP that has an info table, if+ -- tablesNextToCode is off we must jump to the entry+ -- label instead.+ jump_label (Just info_lbl) _+ | tablesNextToCode dflags = info_lbl+ | otherwise = toEntryLbl info_lbl+ jump_label Nothing block_lbl = block_lbl++ add_if_pp id rst = case mapLookup id procLabels of+ Just (lbl, mb_info_lbl) -> (id, jump_label mb_info_lbl lbl) : rst+ Nothing -> rst+ (jumpEnv, jumpBlocks) <-+ foldM add_jump_block (mapEmpty, []) needed_jumps+ -- update the entry block+ let b = expectJust "block in env" $ mapLookup ppId blockEnv+ blockEnv' = mapInsert ppId b blockEnv+ -- replace branches to procpoints with branches to jumps+ blockEnv'' = toBlockMap $ replaceBranches jumpEnv $ ofBlockMap ppId blockEnv'+ -- add the jump blocks to the graph+ blockEnv''' = foldl (flip insertBlock) blockEnv'' jumpBlocks+ let g' = ofBlockMap ppId blockEnv'''+ -- pprTrace "g' pre jumps" (ppr g') $ do+ return (mapInsert ppId g' newGraphEnv)++ graphEnv <- foldM add_jumps mapEmpty $ mapToList graphEnv++ let to_proc (bid, g)+ | bid == entry+ = CmmProc (TopInfo {info_tbls = info_tbls,+ stack_info = stack_info})+ top_l live g'+ | otherwise+ = case expectJust "pp label" $ mapLookup bid procLabels of+ (lbl, Just info_lbl)+ -> CmmProc (TopInfo { info_tbls = mapSingleton (g_entry g) (mkEmptyContInfoTable info_lbl)+ , stack_info=stack_info})+ lbl live g'+ (lbl, Nothing)+ -> CmmProc (TopInfo {info_tbls = mapEmpty, stack_info=stack_info})+ lbl live g'+ where+ g' = replacePPIds g+ live = ppLiveness (g_entry g')+ stack_info = StackInfo { arg_space = 0+ , updfr_space = Nothing+ , do_layout = True }+ -- cannot use panic, this is printed by -ddump-cmm++ -- References to procpoint IDs can now be replaced with the+ -- infotable's label+ replacePPIds g = {-# SCC "replacePPIds" #-}+ mapGraphNodes (id, mapExp repl, mapExp repl) g+ where repl e@(CmmLit (CmmBlock bid)) =+ case mapLookup bid procLabels of+ Just (_, Just info_lbl) -> CmmLit (CmmLabel info_lbl)+ _ -> e+ repl e = e++ -- The C back end expects to see return continuations before the+ -- call sites. Here, we sort them in reverse order -- it gets+ -- reversed later.+ let (_, block_order) =+ foldl add_block_num (0::Int, mapEmpty :: LabelMap Int)+ (postorderDfs g)+ add_block_num (i, map) block = (i+1, mapInsert (entryLabel block) i map)+ sort_fn (bid, _) (bid', _) =+ compare (expectJust "block_order" $ mapLookup bid block_order)+ (expectJust "block_order" $ mapLookup bid' block_order)+ procs <- return $ map to_proc $ sortBy sort_fn $ mapToList graphEnv+ return -- pprTrace "procLabels" (ppr procLabels)+ -- pprTrace "splitting graphs" (ppr procs)+ procs+splitAtProcPoints _ _ _ _ _ t@(CmmData _ _) = return [t]++-- Only called from CmmProcPoint.splitAtProcPoints. NB. does a+-- recursive lookup, see comment below.+replaceBranches :: LabelMap BlockId -> CmmGraph -> CmmGraph+replaceBranches env cmmg+ = {-# SCC "replaceBranches" #-}+ ofBlockMap (g_entry cmmg) $ mapMap f $ toBlockMap cmmg+ where+ f block = replaceLastNode block $ last (lastNode block)++ last :: CmmNode O C -> CmmNode O C+ last (CmmBranch id) = CmmBranch (lookup id)+ last (CmmCondBranch e ti fi l) = CmmCondBranch e (lookup ti) (lookup fi) l+ last (CmmSwitch e ids) = CmmSwitch e (mapSwitchTargets lookup ids)+ last l@(CmmCall {}) = l { cml_cont = Nothing }+ -- NB. remove the continuation of a CmmCall, since this+ -- label will now be in a different CmmProc. Not only+ -- is this tidier, it stops CmmLint from complaining.+ last l@(CmmForeignCall {}) = l+ lookup id = fmap lookup (mapLookup id env) `orElse` id+ -- XXX: this is a recursive lookup, it follows chains+ -- until the lookup returns Nothing, at which point we+ -- return the last BlockId++-- --------------------------------------------------------------+-- Not splitting proc points: add info tables for continuations++attachContInfoTables :: ProcPointSet -> CmmDecl -> CmmDecl+attachContInfoTables call_proc_points (CmmProc top_info top_l live g)+ = CmmProc top_info{info_tbls = info_tbls'} top_l live g+ where+ info_tbls' = mapUnion (info_tbls top_info) $+ mapFromList [ (l, mkEmptyContInfoTable (infoTblLbl l))+ | l <- setElems call_proc_points+ , l /= g_entry g ]+attachContInfoTables _ other_decl+ = other_decl++----------------------------------------------------------------++{-+Note [Direct reachability]++Block B is directly reachable from proc point P iff control can flow+from P to B without passing through an intervening proc point.+-}++----------------------------------------------------------------++{-+Note [No simple dataflow]++Sadly, it seems impossible to compute the proc points using a single+dataflow pass. One might attempt to use this simple lattice:++ data Location = Unknown+ | InProc BlockId -- node is in procedure headed by the named proc point+ | ProcPoint -- node is itself a proc point++At a join, a node in two different blocks becomes a proc point.+The difficulty is that the change of information during iterative+computation may promote a node prematurely. Here's a program that+illustrates the difficulty:++ f () {+ entry:+ ....+ L1:+ if (...) { ... }+ else { ... }++ L2: if (...) { g(); goto L1; }+ return x + y;+ }++The only proc-point needed (besides the entry) is L1. But in an+iterative analysis, consider what happens to L2. On the first pass+through, it rises from Unknown to 'InProc entry', but when L1 is+promoted to a proc point (because it's the successor of g()), L1's+successors will be promoted to 'InProc L1'. The problem hits when the+new fact 'InProc L1' flows into L2 which is already bound to 'InProc entry'.+The join operation makes it a proc point when in fact it needn't be,+because its immediate dominator L1 is already a proc point and there+are no other proc points that directly reach L2.+-}++++{- Note [Separate Adams optimization]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It may be worthwhile to attempt the Adams optimization by rewriting+the graph before the assignment of proc-point protocols. Here are a+couple of rules:++ g() returns to k; g() returns to L;+ k: CopyIn c ress; goto L:+ ... ==> ...+ L: // no CopyIn node here L: CopyIn c ress;+++And when c == c' and ress == ress', this also:++ g() returns to k; g() returns to L;+ k: CopyIn c ress; goto L:+ ... ==> ...+ L: CopyIn c' ress' L: CopyIn c' ress' ;++In both cases the goal is to eliminate k.+-}
+ cmm/CmmSink.hs view
@@ -0,0 +1,790 @@+{-# LANGUAGE GADTs #-}+module CmmSink (+ cmmSink+ ) where++import Cmm+import CmmOpt+import CmmLive+import CmmUtils+import Hoopl+import CodeGen.Platform+import Platform (isARM, platformArch)++import DynFlags+import UniqFM+import PprCmm ()++import Data.List (partition)+import qualified Data.Set as Set+import Data.Maybe++-- -----------------------------------------------------------------------------+-- Sinking and inlining++-- This is an optimisation pass that+-- (a) moves assignments closer to their uses, to reduce register pressure+-- (b) pushes assignments into a single branch of a conditional if possible+-- (c) inlines assignments to registers that are mentioned only once+-- (d) discards dead assignments+--+-- This tightens up lots of register-heavy code. It is particularly+-- helpful in the Cmm generated by the Stg->Cmm code generator, in+-- which every function starts with a copyIn sequence like:+--+-- x1 = R1+-- x2 = Sp[8]+-- x3 = Sp[16]+-- if (Sp - 32 < SpLim) then L1 else L2+--+-- we really want to push the x1..x3 assignments into the L2 branch.+--+-- Algorithm:+--+-- * Start by doing liveness analysis.+--+-- * Keep a list of assignments A; earlier ones may refer to later ones.+-- Currently we only sink assignments to local registers, because we don't+-- have liveness information about global registers.+--+-- * Walk forwards through the graph, look at each node N:+--+-- * If it is a dead assignment, i.e. assignment to a register that is+-- not used after N, discard it.+--+-- * Try to inline based on current list of assignments+-- * If any assignments in A (1) occur only once in N, and (2) are+-- not live after N, inline the assignment and remove it+-- from A.+--+-- * If an assignment in A is cheap (RHS is local register), then+-- inline the assignment and keep it in A in case it is used afterwards.+--+-- * Otherwise don't inline.+--+-- * If N is assignment to a local register pick up the assignment+-- and add it to A.+--+-- * If N is not an assignment to a local register:+-- * remove any assignments from A that conflict with N, and+-- place them before N in the current block. We call this+-- "dropping" the assignments.+--+-- * An assignment conflicts with N if it:+-- - assigns to a register mentioned in N+-- - mentions a register assigned by N+-- - reads from memory written by N+-- * do this recursively, dropping dependent assignments+--+-- * At an exit node:+-- * drop any assignments that are live on more than one successor+-- and are not trivial+-- * if any successor has more than one predecessor (a join-point),+-- drop everything live in that successor. Since we only propagate+-- assignments that are not dead at the successor, we will therefore+-- eliminate all assignments dead at this point. Thus analysis of a+-- join-point will always begin with an empty list of assignments.+--+--+-- As a result of above algorithm, sinking deletes some dead assignments+-- (transitively, even). This isn't as good as removeDeadAssignments,+-- but it's much cheaper.++-- -----------------------------------------------------------------------------+-- things that we aren't optimising very well yet.+--+-- -----------+-- (1) From GHC's FastString.hashStr:+--+-- s2ay:+-- if ((_s2an::I64 == _s2ao::I64) >= 1) goto c2gn; else goto c2gp;+-- c2gn:+-- R1 = _s2au::I64;+-- call (I64[Sp])(R1) args: 8, res: 0, upd: 8;+-- c2gp:+-- _s2cO::I64 = %MO_S_Rem_W64(%MO_UU_Conv_W8_W64(I8[_s2aq::I64 + (_s2an::I64 << 0)]) + _s2au::I64 * 128,+-- 4091);+-- _s2an::I64 = _s2an::I64 + 1;+-- _s2au::I64 = _s2cO::I64;+-- goto s2ay;+--+-- a nice loop, but we didn't eliminate the silly assignment at the end.+-- See Note [dependent assignments], which would probably fix this.+-- This is #8336 on Trac.+--+-- -----------+-- (2) From stg_atomically_frame in PrimOps.cmm+--+-- We have a diamond control flow:+--+-- x = ...+-- |+-- / \+-- A B+-- \ /+-- |+-- use of x+--+-- Now x won't be sunk down to its use, because we won't push it into+-- both branches of the conditional. We certainly do have to check+-- that we can sink it past all the code in both A and B, but having+-- discovered that, we could sink it to its use.+--++-- -----------------------------------------------------------------------------++type Assignment = (LocalReg, CmmExpr, AbsMem)+ -- Assignment caches AbsMem, an abstraction of the memory read by+ -- the RHS of the assignment.++type Assignments = [Assignment]+ -- A sequence of assignments; kept in *reverse* order+ -- So the list [ x=e1, y=e2 ] means the sequence of assignments+ -- y = e2+ -- x = e1++cmmSink :: DynFlags -> CmmGraph -> CmmGraph+cmmSink dflags graph = ofBlockList (g_entry graph) $ sink mapEmpty $ blocks+ where+ liveness = cmmLocalLiveness dflags graph+ getLive l = mapFindWithDefault Set.empty l liveness++ blocks = postorderDfs graph++ join_pts = findJoinPoints blocks++ sink :: LabelMap Assignments -> [CmmBlock] -> [CmmBlock]+ sink _ [] = []+ sink sunk (b:bs) =+ -- pprTrace "sink" (ppr lbl) $+ blockJoin first final_middle final_last : sink sunk' bs+ where+ lbl = entryLabel b+ (first, middle, last) = blockSplit b++ succs = successors last++ -- Annotate the middle nodes with the registers live *after*+ -- the node. This will help us decide whether we can inline+ -- an assignment in the current node or not.+ live = Set.unions (map getLive succs)+ live_middle = gen_kill dflags last live+ ann_middles = annotate dflags live_middle (blockToList middle)++ -- Now sink and inline in this block+ (middle', assigs) = walk dflags ann_middles (mapFindWithDefault [] lbl sunk)+ fold_last = constantFoldNode dflags last+ (final_last, assigs') = tryToInline dflags live fold_last assigs++ -- We cannot sink into join points (successors with more than+ -- one predecessor), so identify the join points and the set+ -- of registers live in them.+ (joins, nonjoins) = partition (`mapMember` join_pts) succs+ live_in_joins = Set.unions (map getLive joins)++ -- We do not want to sink an assignment into multiple branches,+ -- so identify the set of registers live in multiple successors.+ -- This is made more complicated because when we sink an assignment+ -- into one branch, this might change the set of registers that are+ -- now live in multiple branches.+ init_live_sets = map getLive nonjoins+ live_in_multi live_sets r =+ case filter (Set.member r) live_sets of+ (_one:_two:_) -> True+ _ -> False++ -- Now, drop any assignments that we will not sink any further.+ (dropped_last, assigs'') = dropAssignments dflags drop_if init_live_sets assigs'++ drop_if a@(r,rhs,_) live_sets = (should_drop, live_sets')+ where+ should_drop = conflicts dflags a final_last+ || not (isTrivial dflags rhs) && live_in_multi live_sets r+ || r `Set.member` live_in_joins++ live_sets' | should_drop = live_sets+ | otherwise = map upd live_sets++ upd set | r `Set.member` set = set `Set.union` live_rhs+ | otherwise = set++ live_rhs = foldRegsUsed dflags extendRegSet emptyRegSet rhs++ final_middle = foldl blockSnoc middle' dropped_last++ sunk' = mapUnion sunk $+ mapFromList [ (l, filterAssignments dflags (getLive l) assigs'')+ | l <- succs ]++{- TODO: enable this later, when we have some good tests in place to+ measure the effect and tune it.++-- small: an expression we don't mind duplicating+isSmall :: CmmExpr -> Bool+isSmall (CmmReg (CmmLocal _)) = True --+isSmall (CmmLit _) = True+isSmall (CmmMachOp (MO_Add _) [x,y]) = isTrivial x && isTrivial y+isSmall (CmmRegOff (CmmLocal _) _) = True+isSmall _ = False+-}++--+-- We allow duplication of trivial expressions: registers (both local and+-- global) and literals.+--+isTrivial :: DynFlags -> CmmExpr -> Bool+isTrivial _ (CmmReg (CmmLocal _)) = True+isTrivial dflags (CmmReg (CmmGlobal r)) = -- see Note [Inline GlobalRegs?]+ if isARM (platformArch (targetPlatform dflags))+ then True -- CodeGen.Platform.ARM does not have globalRegMaybe+ else isJust (globalRegMaybe (targetPlatform dflags) r)+ -- GlobalRegs that are loads from BaseReg are not trivial+isTrivial _ (CmmLit _) = True+isTrivial _ _ = False++--+-- annotate each node with the set of registers live *after* the node+--+annotate :: DynFlags -> LocalRegSet -> [CmmNode O O] -> [(LocalRegSet, CmmNode O O)]+annotate dflags live nodes = snd $ foldr ann (live,[]) nodes+ where ann n (live,nodes) = (gen_kill dflags n live, (live,n) : nodes)++--+-- Find the blocks that have multiple successors (join points)+--+findJoinPoints :: [CmmBlock] -> LabelMap Int+findJoinPoints blocks = mapFilter (>1) succ_counts+ where+ all_succs = concatMap successors blocks++ succ_counts :: LabelMap Int+ succ_counts = foldr (\l -> mapInsertWith (+) l 1) mapEmpty all_succs++--+-- filter the list of assignments to remove any assignments that+-- are not live in a continuation.+--+filterAssignments :: DynFlags -> LocalRegSet -> Assignments -> Assignments+filterAssignments dflags live assigs = reverse (go assigs [])+ where go [] kept = kept+ go (a@(r,_,_):as) kept | needed = go as (a:kept)+ | otherwise = go as kept+ where+ needed = r `Set.member` live+ || any (conflicts dflags a) (map toNode kept)+ -- Note that we must keep assignments that are+ -- referred to by other assignments we have+ -- already kept.++-- -----------------------------------------------------------------------------+-- Walk through the nodes of a block, sinking and inlining assignments+-- as we go.+--+-- On input we pass in a:+-- * list of nodes in the block+-- * a list of assignments that appeared *before* this block and+-- that are being sunk.+--+-- On output we get:+-- * a new block+-- * a list of assignments that will be placed *after* that block.+--++walk :: DynFlags+ -> [(LocalRegSet, CmmNode O O)] -- nodes of the block, annotated with+ -- the set of registers live *after*+ -- this node.++ -> Assignments -- The current list of+ -- assignments we are sinking.+ -- Earlier assignments may refer+ -- to later ones.++ -> ( Block CmmNode O O -- The new block+ , Assignments -- Assignments to sink further+ )++walk dflags nodes assigs = go nodes emptyBlock assigs+ where+ go [] block as = (block, as)+ go ((live,node):ns) block as+ | shouldDiscard node live = go ns block as+ -- discard dead assignment+ | Just a <- shouldSink dflags node2 = go ns block (a : as1)+ | otherwise = go ns block' as'+ where+ node1 = constantFoldNode dflags node++ (node2, as1) = tryToInline dflags live node1 as++ (dropped, as') = dropAssignmentsSimple dflags+ (\a -> conflicts dflags a node2) as1++ block' = foldl blockSnoc block dropped `blockSnoc` node2+++--+-- Heuristic to decide whether to pick up and sink an assignment+-- Currently we pick up all assignments to local registers. It might+-- be profitable to sink assignments to global regs too, but the+-- liveness analysis doesn't track those (yet) so we can't.+--+shouldSink :: DynFlags -> CmmNode e x -> Maybe Assignment+shouldSink dflags (CmmAssign (CmmLocal r) e) | no_local_regs = Just (r, e, exprMem dflags e)+ where no_local_regs = True -- foldRegsUsed (\_ _ -> False) True e+shouldSink _ _other = Nothing++--+-- discard dead assignments. This doesn't do as good a job as+-- removeDeadAssignments, because it would need multiple passes+-- to get all the dead code, but it catches the common case of+-- superfluous reloads from the stack that the stack allocator+-- leaves behind.+--+-- Also we catch "r = r" here. You might think it would fall+-- out of inlining, but the inliner will see that r is live+-- after the instruction and choose not to inline r in the rhs.+--+shouldDiscard :: CmmNode e x -> LocalRegSet -> Bool+shouldDiscard node live+ = case node of+ CmmAssign r (CmmReg r') | r == r' -> True+ CmmAssign (CmmLocal r) _ -> not (r `Set.member` live)+ _otherwise -> False+++toNode :: Assignment -> CmmNode O O+toNode (r,rhs,_) = CmmAssign (CmmLocal r) rhs++dropAssignmentsSimple :: DynFlags -> (Assignment -> Bool) -> Assignments+ -> ([CmmNode O O], Assignments)+dropAssignmentsSimple dflags f = dropAssignments dflags (\a _ -> (f a, ())) ()++dropAssignments :: DynFlags -> (Assignment -> s -> (Bool, s)) -> s -> Assignments+ -> ([CmmNode O O], Assignments)+dropAssignments dflags should_drop state assigs+ = (dropped, reverse kept)+ where+ (dropped,kept) = go state assigs [] []++ go _ [] dropped kept = (dropped, kept)+ go state (assig : rest) dropped kept+ | conflict = go state' rest (toNode assig : dropped) kept+ | otherwise = go state' rest dropped (assig:kept)+ where+ (dropit, state') = should_drop assig state+ conflict = dropit || any (conflicts dflags assig) dropped+++-- -----------------------------------------------------------------------------+-- Try to inline assignments into a node.++tryToInline+ :: DynFlags+ -> LocalRegSet -- set of registers live after this+ -- node. We cannot inline anything+ -- that is live after the node, unless+ -- it is small enough to duplicate.+ -> CmmNode O x -- The node to inline into+ -> Assignments -- Assignments to inline+ -> (+ CmmNode O x -- New node+ , Assignments -- Remaining assignments+ )++tryToInline dflags live node assigs = go usages node [] assigs+ where+ usages :: UniqFM Int -- Maps each LocalReg to a count of how often it is used+ usages = foldLocalRegsUsed dflags addUsage emptyUFM node++ go _usages node _skipped [] = (node, [])++ go usages node skipped (a@(l,rhs,_) : rest)+ | cannot_inline = dont_inline+ | occurs_none = discard -- Note [discard during inlining]+ | occurs_once = inline_and_discard+ | isTrivial dflags rhs = inline_and_keep+ | otherwise = dont_inline+ where+ inline_and_discard = go usages' inl_node skipped rest+ where usages' = foldLocalRegsUsed dflags addUsage usages rhs++ discard = go usages node skipped rest++ dont_inline = keep node -- don't inline the assignment, keep it+ inline_and_keep = keep inl_node -- inline the assignment, keep it++ keep node' = (final_node, a : rest')+ where (final_node, rest') = go usages' node' (l:skipped) rest+ usages' = foldLocalRegsUsed dflags (\m r -> addToUFM m r 2)+ usages rhs+ -- we must not inline anything that is mentioned in the RHS+ -- of a binding that we have already skipped, so we set the+ -- usages of the regs on the RHS to 2.++ cannot_inline = skipped `regsUsedIn` rhs -- Note [dependent assignments]+ || l `elem` skipped+ || not (okToInline dflags rhs node)++ l_usages = lookupUFM usages l+ l_live = l `elemRegSet` live++ occurs_once = not l_live && l_usages == Just 1+ occurs_none = not l_live && l_usages == Nothing++ inl_node = mapExpDeep inline node+ -- mapExpDeep is where the inlining actually takes place!+ where inline (CmmReg (CmmLocal l')) | l == l' = rhs+ inline (CmmRegOff (CmmLocal l') off) | l == l'+ = cmmOffset dflags rhs off+ -- re-constant fold after inlining+ inline (CmmMachOp op args) = cmmMachOpFold dflags op args+ inline other = other++-- Note [dependent assignments]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- If our assignment list looks like+--+-- [ y = e, x = ... y ... ]+--+-- We cannot inline x. Remember this list is really in reverse order,+-- so it means x = ... y ...; y = e+--+-- Hence if we inline x, the outer assignment to y will capture the+-- reference in x's right hand side.+--+-- In this case we should rename the y in x's right-hand side,+-- i.e. change the list to [ y = e, x = ... y1 ..., y1 = y ]+-- Now we can go ahead and inline x.+--+-- For now we do nothing, because this would require putting+-- everything inside UniqSM.+--+-- One more variant of this (#7366):+--+-- [ y = e, y = z ]+--+-- If we don't want to inline y = e, because y is used many times, we+-- might still be tempted to inline y = z (because we always inline+-- trivial rhs's). But of course we can't, because y is equal to e,+-- not z.++-- Note [discard during inlining]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Opportunities to discard assignments sometimes appear after we've+-- done some inlining. Here's an example:+--+-- x = R1;+-- y = P64[x + 7];+-- z = P64[x + 15];+-- /* z is dead */+-- R1 = y & (-8);+--+-- The x assignment is trivial, so we inline it in the RHS of y, and+-- keep both x and y. z gets dropped because it is dead, then we+-- inline y, and we have a dead assignment to x. If we don't notice+-- that x is dead in tryToInline, we end up retaining it.++addUsage :: UniqFM Int -> LocalReg -> UniqFM Int+addUsage m r = addToUFM_C (+) m r 1++regsUsedIn :: [LocalReg] -> CmmExpr -> Bool+regsUsedIn [] _ = False+regsUsedIn ls e = wrapRecExpf f e False+ where f (CmmReg (CmmLocal l)) _ | l `elem` ls = True+ f (CmmRegOff (CmmLocal l) _) _ | l `elem` ls = True+ f _ z = z++-- we don't inline into CmmUnsafeForeignCall if the expression refers+-- to global registers. This is a HACK to avoid global registers+-- clashing with C argument-passing registers, really the back-end+-- ought to be able to handle it properly, but currently neither PprC+-- nor the NCG can do it. See Note [Register parameter passing]+-- See also StgCmmForeign:load_args_into_temps.+okToInline :: DynFlags -> CmmExpr -> CmmNode e x -> Bool+okToInline dflags expr node@(CmmUnsafeForeignCall{}) =+ not (globalRegistersConflict dflags expr node)+okToInline _ _ _ = True++-- -----------------------------------------------------------------------------++-- | @conflicts (r,e) node@ is @False@ if and only if the assignment+-- @r = e@ can be safely commuted past statement @node@.+conflicts :: DynFlags -> Assignment -> CmmNode O x -> Bool+conflicts dflags (r, rhs, addr) node++ -- (1) node defines registers used by rhs of assignment. This catches+ -- assignments and all three kinds of calls. See Note [Sinking and calls]+ | globalRegistersConflict dflags rhs node = True+ | localRegistersConflict dflags rhs node = True++ -- (2) node uses register defined by assignment+ | foldRegsUsed dflags (\b r' -> r == r' || b) False node = True++ -- (3) a store to an address conflicts with a read of the same memory+ | CmmStore addr' e <- node+ , memConflicts addr (loadAddr dflags addr' (cmmExprWidth dflags e)) = True++ -- (4) an assignment to Hp/Sp conflicts with a heap/stack read respectively+ | HeapMem <- addr, CmmAssign (CmmGlobal Hp) _ <- node = True+ | StackMem <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True+ | SpMem{} <- addr, CmmAssign (CmmGlobal Sp) _ <- node = True++ -- (5) foreign calls clobber heap: see Note [Foreign calls clobber heap]+ | CmmUnsafeForeignCall{} <- node, memConflicts addr AnyMem = True++ -- (6) native calls clobber any memory+ | CmmCall{} <- node, memConflicts addr AnyMem = True++ -- (7) otherwise, no conflict+ | otherwise = False++-- Returns True if node defines any global registers that are used in the+-- Cmm expression+globalRegistersConflict :: DynFlags -> CmmExpr -> CmmNode e x -> Bool+globalRegistersConflict dflags expr node =+ foldRegsDefd dflags (\b r -> b || regUsedIn dflags (CmmGlobal r) expr)+ False node++-- Returns True if node defines any local registers that are used in the+-- Cmm expression+localRegistersConflict :: DynFlags -> CmmExpr -> CmmNode e x -> Bool+localRegistersConflict dflags expr node =+ foldRegsDefd dflags (\b r -> b || regUsedIn dflags (CmmLocal r) expr)+ False node++-- Note [Sinking and calls]+-- ~~~~~~~~~~~~~~~~~~~~~~~~+--+-- We have three kinds of calls: normal (CmmCall), safe foreign (CmmForeignCall)+-- and unsafe foreign (CmmUnsafeForeignCall). We perform sinking pass after+-- stack layout (see Note [Sinking after stack layout]) which leads to two+-- invariants related to calls:+--+-- a) during stack layout phase all safe foreign calls are turned into+-- unsafe foreign calls (see Note [Lower safe foreign calls]). This+-- means that we will never encounter CmmForeignCall node when running+-- sinking after stack layout+--+-- b) stack layout saves all variables live across a call on the stack+-- just before making a call (remember we are not sinking assignments to+-- stack):+--+-- L1:+-- x = R1+-- P64[Sp - 16] = L2+-- P64[Sp - 8] = x+-- Sp = Sp - 16+-- call f() returns L2+-- L2:+--+-- We will attempt to sink { x = R1 } but we will detect conflict with+-- { P64[Sp - 8] = x } and hence we will drop { x = R1 } without even+-- checking whether it conflicts with { call f() }. In this way we will+-- never need to check any assignment conflicts with CmmCall. Remember+-- that we still need to check for potential memory conflicts.+--+-- So the result is that we only need to worry about CmmUnsafeForeignCall nodes+-- when checking conflicts (see Note [Unsafe foreign calls clobber caller-save registers]).+-- This assumption holds only when we do sinking after stack layout. If we run+-- it before stack layout we need to check for possible conflicts with all three+-- kinds of calls. Our `conflicts` function does that by using a generic+-- foldRegsDefd and foldRegsUsed functions defined in DefinerOfRegs and+-- UserOfRegs typeclasses.+--++-- An abstraction of memory read or written.+data AbsMem+ = NoMem -- no memory accessed+ | AnyMem -- arbitrary memory+ | HeapMem -- definitely heap memory+ | StackMem -- definitely stack memory+ | SpMem -- <size>[Sp+n]+ {-# UNPACK #-} !Int+ {-# UNPACK #-} !Int++-- Having SpMem is important because it lets us float loads from Sp+-- past stores to Sp as long as they don't overlap, and this helps to+-- unravel some long sequences of+-- x1 = [Sp + 8]+-- x2 = [Sp + 16]+-- ...+-- [Sp + 8] = xi+-- [Sp + 16] = xj+--+-- Note that SpMem is invalidated if Sp is changed, but the definition+-- of 'conflicts' above handles that.++-- ToDo: this won't currently fix the following commonly occurring code:+-- x1 = [R1 + 8]+-- x2 = [R1 + 16]+-- ..+-- [Hp - 8] = x1+-- [Hp - 16] = x2+-- ..++-- because [R1 + 8] and [Hp - 8] are both HeapMem. We know that+-- assignments to [Hp + n] do not conflict with any other heap memory,+-- but this is tricky to nail down. What if we had+--+-- x = Hp + n+-- [x] = ...+--+-- the store to [x] should be "new heap", not "old heap".+-- Furthermore, you could imagine that if we started inlining+-- functions in Cmm then there might well be reads of heap memory+-- that was written in the same basic block. To take advantage of+-- non-aliasing of heap memory we will have to be more clever.++-- Note [Foreign calls clobber heap]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- It is tempting to say that foreign calls clobber only+-- non-heap/stack memory, but unfortunately we break this invariant in+-- the RTS. For example, in stg_catch_retry_frame we call+-- stmCommitNestedTransaction() which modifies the contents of the+-- TRec it is passed (this actually caused incorrect code to be+-- generated).+--+-- Since the invariant is true for the majority of foreign calls,+-- perhaps we ought to have a special annotation for calls that can+-- modify heap/stack memory. For now we just use the conservative+-- definition here.+--+-- Some CallishMachOp imply a memory barrier e.g. AtomicRMW and+-- therefore we should never float any memory operations across one of+-- these calls.+++bothMems :: AbsMem -> AbsMem -> AbsMem+bothMems NoMem x = x+bothMems x NoMem = x+bothMems HeapMem HeapMem = HeapMem+bothMems StackMem StackMem = StackMem+bothMems (SpMem o1 w1) (SpMem o2 w2)+ | o1 == o2 = SpMem o1 (max w1 w2)+ | otherwise = StackMem+bothMems SpMem{} StackMem = StackMem+bothMems StackMem SpMem{} = StackMem+bothMems _ _ = AnyMem++memConflicts :: AbsMem -> AbsMem -> Bool+memConflicts NoMem _ = False+memConflicts _ NoMem = False+memConflicts HeapMem StackMem = False+memConflicts StackMem HeapMem = False+memConflicts SpMem{} HeapMem = False+memConflicts HeapMem SpMem{} = False+memConflicts (SpMem o1 w1) (SpMem o2 w2)+ | o1 < o2 = o1 + w1 > o2+ | otherwise = o2 + w2 > o1+memConflicts _ _ = True++exprMem :: DynFlags -> CmmExpr -> AbsMem+exprMem dflags (CmmLoad addr w) = bothMems (loadAddr dflags addr (typeWidth w)) (exprMem dflags addr)+exprMem dflags (CmmMachOp _ es) = foldr bothMems NoMem (map (exprMem dflags) es)+exprMem _ _ = NoMem++loadAddr :: DynFlags -> CmmExpr -> Width -> AbsMem+loadAddr dflags e w =+ case e of+ CmmReg r -> regAddr dflags r 0 w+ CmmRegOff r i -> regAddr dflags r i w+ _other | regUsedIn dflags (CmmGlobal Sp) e -> StackMem+ | otherwise -> AnyMem++regAddr :: DynFlags -> CmmReg -> Int -> Width -> AbsMem+regAddr _ (CmmGlobal Sp) i w = SpMem i (widthInBytes w)+regAddr _ (CmmGlobal Hp) _ _ = HeapMem+regAddr _ (CmmGlobal CurrentTSO) _ _ = HeapMem -- important for PrimOps+regAddr dflags r _ _ | isGcPtrType (cmmRegType dflags r) = HeapMem -- yay! GCPtr pays for itself+regAddr _ _ _ _ = AnyMem++{-+Note [Inline GlobalRegs?]++Should we freely inline GlobalRegs?++Actually it doesn't make a huge amount of difference either way, so we+*do* currently treat GlobalRegs as "trivial" and inline them+everywhere, but for what it's worth, here is what I discovered when I+(SimonM) looked into this:++Common sense says we should not inline GlobalRegs, because when we+have++ x = R1++the register allocator will coalesce this assignment, generating no+code, and simply record the fact that x is bound to $rbx (or+whatever). Furthermore, if we were to sink this assignment, then the+range of code over which R1 is live increases, and the range of code+over which x is live decreases. All things being equal, it is better+for x to be live than R1, because R1 is a fixed register whereas x can+live in any register. So we should neither sink nor inline 'x = R1'.++However, not inlining GlobalRegs can have surprising+consequences. e.g. (cgrun020)++ c3EN:+ _s3DB::P64 = R1;+ _c3ES::P64 = _s3DB::P64 & 7;+ if (_c3ES::P64 >= 2) goto c3EU; else goto c3EV;+ c3EU:+ _s3DD::P64 = P64[_s3DB::P64 + 6];+ _s3DE::P64 = P64[_s3DB::P64 + 14];+ I64[Sp - 8] = c3F0;+ R1 = _s3DE::P64;+ P64[Sp] = _s3DD::P64;++inlining the GlobalReg gives:++ c3EN:+ if (R1 & 7 >= 2) goto c3EU; else goto c3EV;+ c3EU:+ I64[Sp - 8] = c3F0;+ _s3DD::P64 = P64[R1 + 6];+ R1 = P64[R1 + 14];+ P64[Sp] = _s3DD::P64;++but if we don't inline the GlobalReg, instead we get:++ _s3DB::P64 = R1;+ if (_s3DB::P64 & 7 >= 2) goto c3EU; else goto c3EV;+ c3EU:+ I64[Sp - 8] = c3F0;+ R1 = P64[_s3DB::P64 + 14];+ P64[Sp] = P64[_s3DB::P64 + 6];++This looks better - we managed to inline _s3DD - but in fact it+generates an extra reg-reg move:++.Lc3EU:+ movq $c3F0_info,-8(%rbp)+ movq %rbx,%rax+ movq 14(%rbx),%rbx+ movq 6(%rax),%rax+ movq %rax,(%rbp)++because _s3DB is now live across the R1 assignment, we lost the+benefit of coalescing.++Who is at fault here? Perhaps if we knew that _s3DB was an alias for+R1, then we would not sink a reference to _s3DB past the R1+assignment. Or perhaps we *should* do that - we might gain by sinking+it, despite losing the coalescing opportunity.++Sometimes not inlining global registers wins by virtue of the rule+about not inlining into arguments of a foreign call, e.g. (T7163) this+is what happens when we inlined F1:++ _s3L2::F32 = F1;+ _c3O3::F32 = %MO_F_Mul_W32(F1, 10.0 :: W32);+ (_s3L7::F32) = call "ccall" arg hints: [] result hints: [] rintFloat(_c3O3::F32);++but if we don't inline F1:++ (_s3L7::F32) = call "ccall" arg hints: [] result hints: [] rintFloat(%MO_F_Mul_W32(_s3L2::F32,+ 10.0 :: W32));+-}
+ cmm/CmmSwitch.hs view
@@ -0,0 +1,433 @@+{-# LANGUAGE GADTs #-}+module CmmSwitch (+ SwitchTargets,+ mkSwitchTargets,+ switchTargetsCases, switchTargetsDefault, switchTargetsRange, switchTargetsSigned,+ mapSwitchTargets, switchTargetsToTable, switchTargetsFallThrough,+ switchTargetsToList, eqSwitchTargetWith,++ SwitchPlan(..),+ targetSupportsSwitch,+ createSwitchPlan,+ ) where++import Outputable+import DynFlags+import Compiler.Hoopl (Label)++import Data.Maybe+import Data.List (groupBy)+import Data.Function (on)+import qualified Data.Map as M++-- Note [Cmm Switches, the general plan]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Compiling a high-level switch statement, as it comes out of a STG case+-- expression, for example, allows for a surprising amount of design decisions.+-- Therefore, we cleanly separated this from the Stg → Cmm transformation, as+-- well as from the actual code generation.+--+-- The overall plan is:+-- * The Stg → Cmm transformation creates a single `SwitchTargets` in+-- emitSwitch and emitCmmLitSwitch in StgCmmUtils.hs.+-- At this stage, they are unsuitable for code generation.+-- * A dedicated Cmm transformation (CmmImplementSwitchPlans) replaces these+-- switch statements with code that is suitable for code generation, i.e.+-- a nice balanced tree of decisions with dense jump tables in the leafs.+-- The actual planning of this tree is performed in pure code in createSwitchPlan+-- in this module. See Note [createSwitchPlan].+-- * The actual code generation will not do any further processing and+-- implement each CmmSwitch with a jump tables.+--+-- When compiling to LLVM or C, CmmImplementSwitchPlans leaves the switch+-- statements alone, as we can turn a SwitchTargets value into a nice+-- switch-statement in LLVM resp. C, and leave the rest to the compiler.+--+-- See Note [CmmSwitch vs. CmmImplementSwitchPlans] why the two module are+-- separated.++-----------------------------------------------------------------------------+-- Note [Magic Constants in CmmSwitch]+--+-- There are a lot of heuristics here that depend on magic values where it is+-- hard to determine the "best" value (for whatever that means). These are the+-- magic values:++-- | Number of consecutive default values allowed in a jump table. If there are+-- more of them, the jump tables are split.+--+-- Currently 7, as it costs 7 words of additional code when a jump table is+-- split (at least on x64, determined experimentally).+maxJumpTableHole :: Integer+maxJumpTableHole = 7++-- | Minimum size of a jump table. If the number is smaller, the switch is+-- implemented using conditionals.+-- Currently 5, because an if-then-else tree of 4 values is nice and compact.+minJumpTableSize :: Int+minJumpTableSize = 5++-- | Minimum non-zero offset for a jump table. See Note [Jump Table Offset].+minJumpTableOffset :: Integer+minJumpTableOffset = 2+++-----------------------------------------------------------------------------+-- Switch Targets++-- Note [SwitchTargets]:+-- ~~~~~~~~~~~~~~~~~~~~~+--+-- The branches of a switch are stored in a SwitchTargets, which consists of an+-- (optional) default jump target, and a map from values to jump targets.+--+-- If the default jump target is absent, the behaviour of the switch outside the+-- values of the map is undefined.+--+-- We use an Integer for the keys the map so that it can be used in switches on+-- unsigned as well as signed integers.+--+-- The map may be empty (we prune out-of-range branches here, so it could be us+-- emptying it).+--+-- Before code generation, the table needs to be brought into a form where all+-- entries are non-negative, so that it can be compiled into a jump table.+-- See switchTargetsToTable.+++-- | A value of type SwitchTargets contains the alternatives for a 'CmmSwitch'+-- value, and knows whether the value is signed, the possible range, an+-- optional default value and a map from values to jump labels.+data SwitchTargets =+ SwitchTargets+ Bool -- Signed values+ (Integer, Integer) -- Range+ (Maybe Label) -- Default value+ (M.Map Integer Label) -- The branches+ deriving (Show, Eq)++-- | The smart constructr mkSwitchTargets normalises the map a bit:+-- * No entries outside the range+-- * No entries equal to the default+-- * No default if all elements have explicit values+mkSwitchTargets :: Bool -> (Integer, Integer) -> Maybe Label -> M.Map Integer Label -> SwitchTargets+mkSwitchTargets signed range@(lo,hi) mbdef ids+ = SwitchTargets signed range mbdef' ids'+ where+ ids' = dropDefault $ restrict ids+ mbdef' | defaultNeeded = mbdef+ | otherwise = Nothing++ -- Drop entries outside the range, if there is a range+ restrict = restrictMap (lo,hi)++ -- Drop entries that equal the default, if there is a default+ dropDefault | Just l <- mbdef = M.filter (/= l)+ | otherwise = id++ -- Check if the default is still needed+ defaultNeeded = fromIntegral (M.size ids') /= hi-lo+1+++-- | Changes all labels mentioned in the SwitchTargets value+mapSwitchTargets :: (Label -> Label) -> SwitchTargets -> SwitchTargets+mapSwitchTargets f (SwitchTargets signed range mbdef branches)+ = SwitchTargets signed range (fmap f mbdef) (fmap f branches)++-- | Returns the list of non-default branches of the SwitchTargets value+switchTargetsCases :: SwitchTargets -> [(Integer, Label)]+switchTargetsCases (SwitchTargets _ _ _ branches) = M.toList branches++-- | Return the default label of the SwitchTargets value+switchTargetsDefault :: SwitchTargets -> Maybe Label+switchTargetsDefault (SwitchTargets _ _ mbdef _) = mbdef++-- | Return the range of the SwitchTargets value+switchTargetsRange :: SwitchTargets -> (Integer, Integer)+switchTargetsRange (SwitchTargets _ range _ _) = range++-- | Return whether this is used for a signed value+switchTargetsSigned :: SwitchTargets -> Bool+switchTargetsSigned (SwitchTargets signed _ _ _) = signed++-- | switchTargetsToTable creates a dense jump table, usable for code generation.+--+-- Also returns an offset to add to the value; the list is 0-based on the+-- result of that addition.+--+-- The conversion from Integer to Int is a bit of a wart, as the actual+-- scrutinee might be an unsigned word, but it just works, due to wrap-around+-- arithmetic (as verified by the CmmSwitchTest test case).+switchTargetsToTable :: SwitchTargets -> (Int, [Maybe Label])+switchTargetsToTable (SwitchTargets _ (lo,hi) mbdef branches)+ = (fromIntegral (-start), [ labelFor i | i <- [start..hi] ])+ where+ labelFor i = case M.lookup i branches of Just l -> Just l+ Nothing -> mbdef+ start | lo >= 0 && lo < minJumpTableOffset = 0 -- See Note [Jump Table Offset]+ | otherwise = lo++-- Note [Jump Table Offset]+-- ~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Usually, the code for a jump table starting at x will first subtract x from+-- the value, to avoid a large amount of empty entries. But if x is very small,+-- the extra entries are no worse than the subtraction in terms of code size, and+-- not having to do the subtraction is quicker.+--+-- I.e. instead of+-- _u20N:+-- leaq -1(%r14),%rax+-- jmp *_n20R(,%rax,8)+-- _n20R:+-- .quad _c20p+-- .quad _c20q+-- do+-- _u20N:+-- jmp *_n20Q(,%r14,8)+--+-- _n20Q:+-- .quad 0+-- .quad _c20p+-- .quad _c20q+-- .quad _c20r++-- | The list of all labels occuring in the SwitchTargets value.+switchTargetsToList :: SwitchTargets -> [Label]+switchTargetsToList (SwitchTargets _ _ mbdef branches)+ = maybeToList mbdef ++ M.elems branches++-- | Groups cases with equal targets, suitable for pretty-printing to a+-- c-like switch statement with fall-through semantics.+switchTargetsFallThrough :: SwitchTargets -> ([([Integer], Label)], Maybe Label)+switchTargetsFallThrough (SwitchTargets _ _ mbdef branches) = (groups, mbdef)+ where+ groups = map (\xs -> (map fst xs, snd (head xs))) $+ groupBy ((==) `on` snd) $+ M.toList branches++-- | Custom equality helper, needed for "CmmCommonBlockElim"+eqSwitchTargetWith :: (Label -> Label -> Bool) -> SwitchTargets -> SwitchTargets -> Bool+eqSwitchTargetWith eq (SwitchTargets signed1 range1 mbdef1 ids1) (SwitchTargets signed2 range2 mbdef2 ids2) =+ signed1 == signed2 && range1 == range2 && goMB mbdef1 mbdef2 && goList (M.toList ids1) (M.toList ids2)+ where+ goMB Nothing Nothing = True+ goMB (Just l1) (Just l2) = l1 `eq` l2+ goMB _ _ = False+ goList [] [] = True+ goList ((i1,l1):ls1) ((i2,l2):ls2) = i1 == i2 && l1 `eq` l2 && goList ls1 ls2+ goList _ _ = False++-----------------------------------------------------------------------------+-- Code generation for Switches+++-- | A SwitchPlan abstractly describes how a Switch statement ought to be+-- implemented. See Note [createSwitchPlan]+data SwitchPlan+ = Unconditionally Label+ | IfEqual Integer Label SwitchPlan+ | IfLT Bool Integer SwitchPlan SwitchPlan+ | JumpTable SwitchTargets+ deriving Show+--+-- Note [createSwitchPlan]+-- ~~~~~~~~~~~~~~~~~~~~~~~+--+-- A SwitchPlan describes how a Switch statement is to be broken down into+-- smaller pieces suitable for code generation.+--+-- createSwitchPlan creates such a switch plan, in these steps:+-- 1. It splits the switch statement at segments of non-default values that+-- are too large. See splitAtHoles and Note [Magic Constants in CmmSwitch]+-- 2. Too small jump tables should be avoided, so we break up smaller pieces+-- in breakTooSmall.+-- 3. We fill in the segments between those pieces with a jump to the default+-- label (if there is one), returning a SeparatedList in mkFlatSwitchPlan+-- 4. We find and replace two less-than branches by a single equal-to-test in+-- findSingleValues+-- 5. The thus collected pieces are assembled to a balanced binary tree.+++-- | Does the target support switch out of the box? Then leave this to the+-- target!+targetSupportsSwitch :: HscTarget -> Bool+targetSupportsSwitch HscC = True+targetSupportsSwitch HscLlvm = True+targetSupportsSwitch _ = False++-- | This function creates a SwitchPlan from a SwitchTargets value, breaking it+-- down into smaller pieces suitable for code generation.+createSwitchPlan :: SwitchTargets -> SwitchPlan+-- Lets do the common case of a singleton map quicky and efficiently (#10677)+createSwitchPlan (SwitchTargets _signed _range (Just defLabel) m)+ | [(x, l)] <- M.toList m+ = IfEqual x l (Unconditionally defLabel)+-- And another common case, matching booleans+createSwitchPlan (SwitchTargets _signed (lo,hi) Nothing m)+ | [(x1, l1), (x2,l2)] <- M.toAscList m+ , x1 == lo+ , x2 == hi+ , x1 + 1 == x2+ = IfEqual x1 l1 (Unconditionally l2)+createSwitchPlan (SwitchTargets signed range mbdef m) =+ -- pprTrace "createSwitchPlan" (text (show ids) $$ text (show (range,m)) $$ text (show pieces) $$ text (show flatPlan) $$ text (show plan)) $+ plan+ where+ pieces = concatMap breakTooSmall $ splitAtHoles maxJumpTableHole m+ flatPlan = findSingleValues $ mkFlatSwitchPlan signed mbdef range pieces+ plan = buildTree signed $ flatPlan+++---+--- Step 1: Splitting at large holes+---+splitAtHoles :: Integer -> M.Map Integer a -> [M.Map Integer a]+splitAtHoles _ m | M.null m = []+splitAtHoles holeSize m = map (\range -> restrictMap range m) nonHoles+ where+ holes = filter (\(l,h) -> h - l > holeSize) $ zip (M.keys m) (tail (M.keys m))+ nonHoles = reassocTuples lo holes hi++ (lo,_) = M.findMin m+ (hi,_) = M.findMax m++---+--- Step 2: Avoid small jump tables+---+-- We do not want jump tables below a certain size. This breaks them up+-- (into singleton maps, for now).+breakTooSmall :: M.Map Integer a -> [M.Map Integer a]+breakTooSmall m+ | M.size m > minJumpTableSize = [m]+ | otherwise = [M.singleton k v | (k,v) <- M.toList m]++---+--- Step 3: Fill in the blanks+---++-- | A FlatSwitchPlan is a list of SwitchPlans, with an integer inbetween every+-- two entries, dividing the range.+-- So if we have (abusing list syntax) [plan1,n,plan2], then we use plan1 if+-- the expression is < n, and plan2 otherwise.++type FlatSwitchPlan = SeparatedList Integer SwitchPlan++mkFlatSwitchPlan :: Bool -> Maybe Label -> (Integer, Integer) -> [M.Map Integer Label] -> FlatSwitchPlan++-- If we have no default (i.e. undefined where there is no entry), we can+-- branch at the minimum of each map+mkFlatSwitchPlan _ Nothing _ [] = pprPanic "mkFlatSwitchPlan with nothing left to do" empty+mkFlatSwitchPlan signed Nothing _ (m:ms)+ = (mkLeafPlan signed Nothing m , [ (fst (M.findMin m'), mkLeafPlan signed Nothing m') | m' <- ms ])++-- If we have a default, we have to interleave segments that jump+-- to the default between the maps+mkFlatSwitchPlan signed (Just l) r ms = let ((_,p1):ps) = go r ms in (p1, ps)+ where+ go (lo,hi) []+ | lo > hi = []+ | otherwise = [(lo, Unconditionally l)]+ go (lo,hi) (m:ms)+ | lo < min+ = (lo, Unconditionally l) : go (min,hi) (m:ms)+ | lo == min+ = (lo, mkLeafPlan signed (Just l) m) : go (max+1,hi) ms+ | otherwise+ = pprPanic "mkFlatSwitchPlan" (integer lo <+> integer min)+ where+ min = fst (M.findMin m)+ max = fst (M.findMax m)+++mkLeafPlan :: Bool -> Maybe Label -> M.Map Integer Label -> SwitchPlan+mkLeafPlan signed mbdef m+ | [(_,l)] <- M.toList m -- singleton map+ = Unconditionally l+ | otherwise+ = JumpTable $ mkSwitchTargets signed (min,max) mbdef m+ where+ min = fst (M.findMin m)+ max = fst (M.findMax m)++---+--- Step 4: Reduce the number of branches using ==+---++-- A sequence of three unconditional jumps, with the outer two pointing to the+-- same value and the bounds off by exactly one can be improved+findSingleValues :: FlatSwitchPlan -> FlatSwitchPlan+findSingleValues (Unconditionally l, (i, Unconditionally l2) : (i', Unconditionally l3) : xs)+ | l == l3 && i + 1 == i'+ = findSingleValues (IfEqual i l2 (Unconditionally l), xs)+findSingleValues (p, (i,p'):xs)+ = (p,i) `consSL` findSingleValues (p', xs)+findSingleValues (p, [])+ = (p, [])++---+--- Step 5: Actually build the tree+---++-- Build a balanced tree from a separated list+buildTree :: Bool -> FlatSwitchPlan -> SwitchPlan+buildTree _ (p,[]) = p+buildTree signed sl = IfLT signed m (buildTree signed sl1) (buildTree signed sl2)+ where+ (sl1, m, sl2) = divideSL sl++++--+-- Utility data type: Non-empty lists with extra markers in between each+-- element:+--++type SeparatedList b a = (a, [(b,a)])++consSL :: (a, b) -> SeparatedList b a -> SeparatedList b a+consSL (a, b) (a', xs) = (a, (b,a'):xs)++divideSL :: SeparatedList b a -> (SeparatedList b a, b, SeparatedList b a)+divideSL (_,[]) = error "divideSL: Singleton SeparatedList"+divideSL (p,xs) = ((p, xs1), m, (p', xs2))+ where+ (xs1, (m,p'):xs2) = splitAt (length xs `div` 2) xs++--+-- Other Utilities+--++restrictMap :: (Integer,Integer) -> M.Map Integer b -> M.Map Integer b+restrictMap (lo,hi) m = mid+ where (_, mid_hi) = M.split (lo-1) m+ (mid, _) = M.split (hi+1) mid_hi++-- for example: reassocTuples a [(b,c),(d,e)] f == [(a,b),(c,d),(e,f)]+reassocTuples :: a -> [(a,a)] -> a -> [(a,a)]+reassocTuples initial [] last+ = [(initial,last)]+reassocTuples initial ((a,b):tuples) last+ = (initial,a) : reassocTuples b tuples last++-- Note [CmmSwitch vs. CmmImplementSwitchPlans]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- I (Joachim) separated the two somewhat closely related modules+--+-- - CmmSwitch, which provides the CmmSwitchTargets type and contains the strategy+-- for implementing a Cmm switch (createSwitchPlan), and+-- - CmmImplementSwitchPlans, which contains the actuall Cmm graph modification,+--+-- for these reasons:+--+-- * CmmSwitch is very low in the dependency tree, i.e. does not depend on any+-- GHC specific modules at all (with the exception of Output and Hoople+-- (Literal)). CmmImplementSwitchPlans is the Cmm transformation and hence very+-- high in the dependency tree.+-- * CmmSwitch provides the CmmSwitchTargets data type, which is abstract, but+-- used in CmmNodes.+-- * Because CmmSwitch is low in the dependency tree, the separation allows+-- for more parallelism when building GHC.+-- * The interaction between the modules is very explicit and easy to+-- understand, due to the small and simple interface.
+ cmm/CmmType.hs view
@@ -0,0 +1,439 @@+{-# LANGUAGE CPP #-}++module CmmType+ ( CmmType -- Abstract+ , b8, b16, b32, b64, b128, b256, b512, f32, f64, bWord, bHalfWord, gcWord+ , cInt+ , cmmBits, cmmFloat+ , typeWidth, cmmEqType, cmmEqType_ignoring_ptrhood+ , isFloatType, isGcPtrType, isWord32, isWord64, isFloat64, isFloat32++ , Width(..)+ , widthInBits, widthInBytes, widthInLog, widthFromBytes+ , wordWidth, halfWordWidth, cIntWidth+ , halfWordMask+ , narrowU, narrowS+ , rEP_CostCentreStack_mem_alloc+ , rEP_CostCentreStack_scc_count+ , rEP_StgEntCounter_allocs+ , rEP_StgEntCounter_allocd++ , ForeignHint(..)++ , Length+ , vec, vec2, vec4, vec8, vec16+ , vec2f64, vec2b64, vec4f32, vec4b32, vec8b16, vec16b8+ , cmmVec+ , vecLength, vecElemType+ , isVecType+ )+where++#include "HsVersions.h"++import DynFlags+import FastString+import Outputable++import Data.Word+import Data.Int++-----------------------------------------------------------------------------+-- CmmType+-----------------------------------------------------------------------------++ -- NOTE: CmmType is an abstract type, not exported from this+ -- module so you can easily change its representation+ --+ -- However Width is exported in a concrete way,+ -- and is used extensively in pattern-matching++data CmmType -- The important one!+ = CmmType CmmCat Width++data CmmCat -- "Category" (not exported)+ = GcPtrCat -- GC pointer+ | BitsCat -- Non-pointer+ | FloatCat -- Float+ | VecCat Length CmmCat -- Vector+ deriving( Eq )+ -- See Note [Signed vs unsigned] at the end++instance Outputable CmmType where+ ppr (CmmType cat wid) = ppr cat <> ppr (widthInBits wid)++instance Outputable CmmCat where+ ppr FloatCat = text "F"+ ppr GcPtrCat = text "P"+ ppr BitsCat = text "I"+ ppr (VecCat n cat) = ppr cat <> text "x" <> ppr n <> text "V"++-- Why is CmmType stratified? For native code generation,+-- most of the time you just want to know what sort of register+-- to put the thing in, and for this you need to know how+-- many bits thing has and whether it goes in a floating-point+-- register. By contrast, the distinction between GcPtr and+-- GcNonPtr is of interest to only a few parts of the code generator.++-------- Equality on CmmType --------------+-- CmmType is *not* an instance of Eq; sometimes we care about the+-- Gc/NonGc distinction, and sometimes we don't+-- So we use an explicit function to force you to think about it+cmmEqType :: CmmType -> CmmType -> Bool -- Exact equality+cmmEqType (CmmType c1 w1) (CmmType c2 w2) = c1==c2 && w1==w2++cmmEqType_ignoring_ptrhood :: CmmType -> CmmType -> Bool+ -- This equality is temporary; used in CmmLint+ -- but the RTS files are not yet well-typed wrt pointers+cmmEqType_ignoring_ptrhood (CmmType c1 w1) (CmmType c2 w2)+ = c1 `weak_eq` c2 && w1==w2+ where+ weak_eq :: CmmCat -> CmmCat -> Bool+ FloatCat `weak_eq` FloatCat = True+ FloatCat `weak_eq` _other = False+ _other `weak_eq` FloatCat = False+ (VecCat l1 cat1) `weak_eq` (VecCat l2 cat2) = l1 == l2+ && cat1 `weak_eq` cat2+ (VecCat {}) `weak_eq` _other = False+ _other `weak_eq` (VecCat {}) = False+ _word1 `weak_eq` _word2 = True -- Ignores GcPtr++--- Simple operations on CmmType -----+typeWidth :: CmmType -> Width+typeWidth (CmmType _ w) = w++cmmBits, cmmFloat :: Width -> CmmType+cmmBits = CmmType BitsCat+cmmFloat = CmmType FloatCat++-------- Common CmmTypes ------------+-- Floats and words of specific widths+b8, b16, b32, b64, b128, b256, b512, f32, f64 :: CmmType+b8 = cmmBits W8+b16 = cmmBits W16+b32 = cmmBits W32+b64 = cmmBits W64+b128 = cmmBits W128+b256 = cmmBits W256+b512 = cmmBits W512+f32 = cmmFloat W32+f64 = cmmFloat W64++-- CmmTypes of native word widths+bWord :: DynFlags -> CmmType+bWord dflags = cmmBits (wordWidth dflags)++bHalfWord :: DynFlags -> CmmType+bHalfWord dflags = cmmBits (halfWordWidth dflags)++gcWord :: DynFlags -> CmmType+gcWord dflags = CmmType GcPtrCat (wordWidth dflags)++cInt :: DynFlags -> CmmType+cInt dflags = cmmBits (cIntWidth dflags)++------------ Predicates ----------------+isFloatType, isGcPtrType :: CmmType -> Bool+isFloatType (CmmType FloatCat _) = True+isFloatType _other = False++isGcPtrType (CmmType GcPtrCat _) = True+isGcPtrType _other = False++isWord32, isWord64, isFloat32, isFloat64 :: CmmType -> Bool+-- isWord64 is true of 64-bit non-floats (both gc-ptrs and otherwise)+-- isFloat32 and 64 are obvious++isWord64 (CmmType BitsCat W64) = True+isWord64 (CmmType GcPtrCat W64) = True+isWord64 _other = False++isWord32 (CmmType BitsCat W32) = True+isWord32 (CmmType GcPtrCat W32) = True+isWord32 _other = False++isFloat32 (CmmType FloatCat W32) = True+isFloat32 _other = False++isFloat64 (CmmType FloatCat W64) = True+isFloat64 _other = False++-----------------------------------------------------------------------------+-- Width+-----------------------------------------------------------------------------++data Width = W8 | W16 | W32 | W64+ | W80 -- Extended double-precision float,+ -- used in x86 native codegen only.+ -- (we use Ord, so it'd better be in this order)+ | W128+ | W256+ | W512+ deriving (Eq, Ord, Show)++instance Outputable Width where+ ppr rep = ptext (mrStr rep)++mrStr :: Width -> LitString+mrStr W8 = sLit("W8")+mrStr W16 = sLit("W16")+mrStr W32 = sLit("W32")+mrStr W64 = sLit("W64")+mrStr W128 = sLit("W128")+mrStr W256 = sLit("W256")+mrStr W512 = sLit("W512")+mrStr W80 = sLit("W80")+++-------- Common Widths ------------+wordWidth :: DynFlags -> Width+wordWidth dflags+ | wORD_SIZE dflags == 4 = W32+ | wORD_SIZE dflags == 8 = W64+ | otherwise = panic "MachOp.wordRep: Unknown word size"++halfWordWidth :: DynFlags -> Width+halfWordWidth dflags+ | wORD_SIZE dflags == 4 = W16+ | wORD_SIZE dflags == 8 = W32+ | otherwise = panic "MachOp.halfWordRep: Unknown word size"++halfWordMask :: DynFlags -> Integer+halfWordMask dflags+ | wORD_SIZE dflags == 4 = 0xFFFF+ | wORD_SIZE dflags == 8 = 0xFFFFFFFF+ | otherwise = panic "MachOp.halfWordMask: Unknown word size"++-- cIntRep is the Width for a C-language 'int'+cIntWidth :: DynFlags -> Width+cIntWidth dflags = case cINT_SIZE dflags of+ 4 -> W32+ 8 -> W64+ s -> panic ("cIntWidth: Unknown cINT_SIZE: " ++ show s)++widthInBits :: Width -> Int+widthInBits W8 = 8+widthInBits W16 = 16+widthInBits W32 = 32+widthInBits W64 = 64+widthInBits W128 = 128+widthInBits W256 = 256+widthInBits W512 = 512+widthInBits W80 = 80++widthInBytes :: Width -> Int+widthInBytes W8 = 1+widthInBytes W16 = 2+widthInBytes W32 = 4+widthInBytes W64 = 8+widthInBytes W128 = 16+widthInBytes W256 = 32+widthInBytes W512 = 64+widthInBytes W80 = 10++widthFromBytes :: Int -> Width+widthFromBytes 1 = W8+widthFromBytes 2 = W16+widthFromBytes 4 = W32+widthFromBytes 8 = W64+widthFromBytes 16 = W128+widthFromBytes 32 = W256+widthFromBytes 64 = W512+widthFromBytes 10 = W80+widthFromBytes n = pprPanic "no width for given number of bytes" (ppr n)++-- log_2 of the width in bytes, useful for generating shifts.+widthInLog :: Width -> Int+widthInLog W8 = 0+widthInLog W16 = 1+widthInLog W32 = 2+widthInLog W64 = 3+widthInLog W128 = 4+widthInLog W256 = 5+widthInLog W512 = 6+widthInLog W80 = panic "widthInLog: F80"++-- widening / narrowing++narrowU :: Width -> Integer -> Integer+narrowU W8 x = fromIntegral (fromIntegral x :: Word8)+narrowU W16 x = fromIntegral (fromIntegral x :: Word16)+narrowU W32 x = fromIntegral (fromIntegral x :: Word32)+narrowU W64 x = fromIntegral (fromIntegral x :: Word64)+narrowU _ _ = panic "narrowTo"++narrowS :: Width -> Integer -> Integer+narrowS W8 x = fromIntegral (fromIntegral x :: Int8)+narrowS W16 x = fromIntegral (fromIntegral x :: Int16)+narrowS W32 x = fromIntegral (fromIntegral x :: Int32)+narrowS W64 x = fromIntegral (fromIntegral x :: Int64)+narrowS _ _ = panic "narrowTo"++-----------------------------------------------------------------------------+-- SIMD+-----------------------------------------------------------------------------++type Length = Int++vec :: Length -> CmmType -> CmmType+vec l (CmmType cat w) = CmmType (VecCat l cat) vecw+ where+ vecw :: Width+ vecw = widthFromBytes (l*widthInBytes w)++vec2, vec4, vec8, vec16 :: CmmType -> CmmType+vec2 = vec 2+vec4 = vec 4+vec8 = vec 8+vec16 = vec 16++vec2f64, vec2b64, vec4f32, vec4b32, vec8b16, vec16b8 :: CmmType+vec2f64 = vec 2 f64+vec2b64 = vec 2 b64+vec4f32 = vec 4 f32+vec4b32 = vec 4 b32+vec8b16 = vec 8 b16+vec16b8 = vec 16 b8++cmmVec :: Int -> CmmType -> CmmType+cmmVec n (CmmType cat w) =+ CmmType (VecCat n cat) (widthFromBytes (n*widthInBytes w))++vecLength :: CmmType -> Length+vecLength (CmmType (VecCat l _) _) = l+vecLength _ = panic "vecLength: not a vector"++vecElemType :: CmmType -> CmmType+vecElemType (CmmType (VecCat l cat) w) = CmmType cat scalw+ where+ scalw :: Width+ scalw = widthFromBytes (widthInBytes w `div` l)+vecElemType _ = panic "vecElemType: not a vector"++isVecType :: CmmType -> Bool+isVecType (CmmType (VecCat {}) _) = True+isVecType _ = False++-------------------------------------------------------------------------+-- Hints++-- Hints are extra type information we attach to the arguments and+-- results of a foreign call, where more type information is sometimes+-- needed by the ABI to make the correct kind of call.++data ForeignHint+ = NoHint | AddrHint | SignedHint+ deriving( Eq )+ -- Used to give extra per-argument or per-result+ -- information needed by foreign calling conventions++-------------------------------------------------------------------------++-- These don't really belong here, but I don't know where is best to+-- put them.++rEP_CostCentreStack_mem_alloc :: DynFlags -> CmmType+rEP_CostCentreStack_mem_alloc dflags+ = cmmBits (widthFromBytes (pc_REP_CostCentreStack_mem_alloc pc))+ where pc = sPlatformConstants (settings dflags)++rEP_CostCentreStack_scc_count :: DynFlags -> CmmType+rEP_CostCentreStack_scc_count dflags+ = cmmBits (widthFromBytes (pc_REP_CostCentreStack_scc_count pc))+ where pc = sPlatformConstants (settings dflags)++rEP_StgEntCounter_allocs :: DynFlags -> CmmType+rEP_StgEntCounter_allocs dflags+ = cmmBits (widthFromBytes (pc_REP_StgEntCounter_allocs pc))+ where pc = sPlatformConstants (settings dflags)++rEP_StgEntCounter_allocd :: DynFlags -> CmmType+rEP_StgEntCounter_allocd dflags+ = cmmBits (widthFromBytes (pc_REP_StgEntCounter_allocd pc))+ where pc = sPlatformConstants (settings dflags)++-------------------------------------------------------------------------+{- Note [Signed vs unsigned]+ ~~~~~~~~~~~~~~~~~~~~~~~~~+Should a CmmType include a signed vs. unsigned distinction?++This is very much like a "hint" in C-- terminology: it isn't necessary+in order to generate correct code, but it might be useful in that the+compiler can generate better code if it has access to higher-level+hints about data. This is important at call boundaries, because the+definition of a function is not visible at all of its call sites, so+the compiler cannot infer the hints.++Here in Cmm, we're taking a slightly different approach. We include+the int vs. float hint in the CmmType, because (a) the majority of+platforms have a strong distinction between float and int registers,+and (b) we don't want to do any heavyweight hint-inference in the+native code backend in order to get good code. We're treating the+hint more like a type: our Cmm is always completely consistent with+respect to hints. All coercions between float and int are explicit.++What about the signed vs. unsigned hint? This information might be+useful if we want to keep sub-word-sized values in word-size+registers, which we must do if we only have word-sized registers.++On such a system, there are two straightforward conventions for+representing sub-word-sized values:++(a) Leave the upper bits undefined. Comparison operations must+ sign- or zero-extend both operands before comparing them,+ depending on whether the comparison is signed or unsigned.++(b) Always keep the values sign- or zero-extended as appropriate.+ Arithmetic operations must narrow the result to the appropriate+ size.++A clever compiler might not use either (a) or (b) exclusively, instead+it would attempt to minimize the coercions by analysis: the same kind+of analysis that propagates hints around. In Cmm we don't want to+have to do this, so we plump for having richer types and keeping the+type information consistent.++If signed/unsigned hints are missing from CmmType, then the only+choice we have is (a), because we don't know whether the result of an+operation should be sign- or zero-extended.++Many architectures have extending load operations, which work well+with (b). To make use of them with (a), you need to know whether the+value is going to be sign- or zero-extended by an enclosing comparison+(for example), which involves knowing above the context. This is+doable but more complex.++Further complicating the issue is foreign calls: a foreign calling+convention can specify that signed 8-bit quantities are passed as+sign-extended 32 bit quantities, for example (this is the case on the+PowerPC). So we *do* need sign information on foreign call arguments.++Pros for adding signed vs. unsigned to CmmType:++ - It would let us use convention (b) above, and get easier+ code generation for extending loads.++ - Less information required on foreign calls.++ - MachOp type would be simpler++Cons:++ - More complexity++ - What is the CmmType for a VanillaReg? Currently it is+ always wordRep, but now we have to decide whether it is+ signed or unsigned. The same VanillaReg can thus have+ different CmmType in different parts of the program.++ - Extra coercions cluttering up expressions.++Currently for GHC, the foreign call point is moot, because we do our+own promotion of sub-word-sized values to word-sized values. The Int8+type is represented by an Int# which is kept sign-extended at all times+(this is slightly naughty, because we're making assumptions about the+C calling convention rather early on in the compiler). However, given+this, the cons outweigh the pros.++-}+
+ cmm/CmmUtils.hs view
@@ -0,0 +1,568 @@+{-# LANGUAGE CPP, GADTs, RankNTypes #-}++-----------------------------------------------------------------------------+--+-- Cmm utilities.+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module CmmUtils(+ -- CmmType+ primRepCmmType, slotCmmType, slotForeignHint,+ typeCmmType, typeForeignHint, primRepForeignHint,++ -- CmmLit+ zeroCLit, mkIntCLit,+ mkWordCLit, packHalfWordsCLit,+ mkByteStringCLit,+ mkDataLits, mkRODataLits,+ mkStgWordCLit,++ -- CmmExpr+ mkIntExpr, zeroExpr,+ mkLblExpr,+ cmmRegOff, cmmOffset, cmmLabelOff, cmmOffsetLit, cmmOffsetExpr,+ cmmRegOffB, cmmOffsetB, cmmLabelOffB, cmmOffsetLitB, cmmOffsetExprB,+ cmmRegOffW, cmmOffsetW, cmmLabelOffW, cmmOffsetLitW, cmmOffsetExprW,+ cmmIndex, cmmIndexExpr, cmmLoadIndex, cmmLoadIndexW,+ cmmNegate,+ cmmULtWord, cmmUGeWord, cmmUGtWord, cmmUShrWord,+ cmmSLtWord,+ cmmNeWord, cmmEqWord,+ cmmOrWord, cmmAndWord,+ cmmSubWord, cmmAddWord, cmmMulWord, cmmQuotWord,+ cmmToWord,++ isTrivialCmmExpr, hasNoGlobalRegs,++ -- Statics+ blankWord,++ -- Tagging+ cmmTagMask, cmmPointerMask, cmmUntag, cmmIsTagged,+ cmmConstrTag1,++ -- Overlap and usage+ regsOverlap, regUsedIn,++ -- Liveness and bitmaps+ mkLiveness,++ -- * Operations that probably don't belong here+ modifyGraph,++ ofBlockMap, toBlockMap, insertBlock,+ ofBlockList, toBlockList, bodyToBlockList,+ toBlockListEntryFirst, toBlockListEntryFirstFalseFallthrough,+ foldGraphBlocks, mapGraphNodes, postorderDfs, mapGraphNodes1,++ -- * Ticks+ blockTicks+ ) where++#include "HsVersions.h"++import TyCon ( PrimRep(..), PrimElemRep(..) )+import RepType ( UnaryType, SlotTy (..), typePrimRep1 )++import SMRep+import Cmm+import BlockId+import CLabel+import Outputable+import DynFlags+import Util+import CodeGen.Platform++import Data.Word+import Data.Maybe+import Data.Bits+import Hoopl++---------------------------------------------------+--+-- CmmTypes+--+---------------------------------------------------++primRepCmmType :: DynFlags -> PrimRep -> CmmType+primRepCmmType _ VoidRep = panic "primRepCmmType:VoidRep"+primRepCmmType dflags LiftedRep = gcWord dflags+primRepCmmType dflags UnliftedRep = gcWord dflags+primRepCmmType dflags IntRep = bWord dflags+primRepCmmType dflags WordRep = bWord dflags+primRepCmmType _ Int64Rep = b64+primRepCmmType _ Word64Rep = b64+primRepCmmType dflags AddrRep = bWord dflags+primRepCmmType _ FloatRep = f32+primRepCmmType _ DoubleRep = f64+primRepCmmType _ (VecRep len rep) = vec len (primElemRepCmmType rep)++slotCmmType :: DynFlags -> SlotTy -> CmmType+slotCmmType dflags PtrSlot = gcWord dflags+slotCmmType dflags WordSlot = bWord dflags+slotCmmType _ Word64Slot = b64+slotCmmType _ FloatSlot = f32+slotCmmType _ DoubleSlot = f64++primElemRepCmmType :: PrimElemRep -> CmmType+primElemRepCmmType Int8ElemRep = b8+primElemRepCmmType Int16ElemRep = b16+primElemRepCmmType Int32ElemRep = b32+primElemRepCmmType Int64ElemRep = b64+primElemRepCmmType Word8ElemRep = b8+primElemRepCmmType Word16ElemRep = b16+primElemRepCmmType Word32ElemRep = b32+primElemRepCmmType Word64ElemRep = b64+primElemRepCmmType FloatElemRep = f32+primElemRepCmmType DoubleElemRep = f64++typeCmmType :: DynFlags -> UnaryType -> CmmType+typeCmmType dflags ty = primRepCmmType dflags (typePrimRep1 ty)++primRepForeignHint :: PrimRep -> ForeignHint+primRepForeignHint VoidRep = panic "primRepForeignHint:VoidRep"+primRepForeignHint LiftedRep = AddrHint+primRepForeignHint UnliftedRep = AddrHint+primRepForeignHint IntRep = SignedHint+primRepForeignHint WordRep = NoHint+primRepForeignHint Int64Rep = SignedHint+primRepForeignHint Word64Rep = NoHint+primRepForeignHint AddrRep = AddrHint -- NB! AddrHint, but NonPtrArg+primRepForeignHint FloatRep = NoHint+primRepForeignHint DoubleRep = NoHint+primRepForeignHint (VecRep {}) = NoHint++slotForeignHint :: SlotTy -> ForeignHint+slotForeignHint PtrSlot = AddrHint+slotForeignHint WordSlot = NoHint+slotForeignHint Word64Slot = NoHint+slotForeignHint FloatSlot = NoHint+slotForeignHint DoubleSlot = NoHint++typeForeignHint :: UnaryType -> ForeignHint+typeForeignHint = primRepForeignHint . typePrimRep1++---------------------------------------------------+--+-- CmmLit+--+---------------------------------------------------++-- XXX: should really be Integer, since Int doesn't necessarily cover+-- the full range of target Ints.+mkIntCLit :: DynFlags -> Int -> CmmLit+mkIntCLit dflags i = CmmInt (toInteger i) (wordWidth dflags)++mkIntExpr :: DynFlags -> Int -> CmmExpr+mkIntExpr dflags i = CmmLit $! mkIntCLit dflags i++zeroCLit :: DynFlags -> CmmLit+zeroCLit dflags = CmmInt 0 (wordWidth dflags)++zeroExpr :: DynFlags -> CmmExpr+zeroExpr dflags = CmmLit (zeroCLit dflags)++mkWordCLit :: DynFlags -> Integer -> CmmLit+mkWordCLit dflags wd = CmmInt wd (wordWidth dflags)++mkByteStringCLit+ :: CLabel -> [Word8] -> (CmmLit, GenCmmDecl CmmStatics info stmt)+-- We have to make a top-level decl for the string,+-- and return a literal pointing to it+mkByteStringCLit lbl bytes+ = (CmmLabel lbl, CmmData (Section sec lbl) $ Statics lbl [CmmString bytes])+ where+ -- This can not happen for String literals (as there \NUL is replaced by+ -- C0 80). However, it can happen with Addr# literals.+ sec = if 0 `elem` bytes then ReadOnlyData else CString++mkDataLits :: Section -> CLabel -> [CmmLit] -> GenCmmDecl CmmStatics info stmt+-- Build a data-segment data block+mkDataLits section lbl lits+ = CmmData section (Statics lbl $ map CmmStaticLit lits)++mkRODataLits :: CLabel -> [CmmLit] -> GenCmmDecl CmmStatics info stmt+-- Build a read-only data block+mkRODataLits lbl lits+ = mkDataLits section lbl lits+ where+ section | any needsRelocation lits = Section RelocatableReadOnlyData lbl+ | otherwise = Section ReadOnlyData lbl+ needsRelocation (CmmLabel _) = True+ needsRelocation (CmmLabelOff _ _) = True+ needsRelocation _ = False++mkStgWordCLit :: DynFlags -> StgWord -> CmmLit+mkStgWordCLit dflags wd = CmmInt (fromStgWord wd) (wordWidth dflags)++packHalfWordsCLit :: DynFlags -> StgHalfWord -> StgHalfWord -> CmmLit+-- Make a single word literal in which the lower_half_word is+-- at the lower address, and the upper_half_word is at the+-- higher address+-- ToDo: consider using half-word lits instead+-- but be careful: that's vulnerable when reversed+packHalfWordsCLit dflags lower_half_word upper_half_word+ = if wORDS_BIGENDIAN dflags+ then mkWordCLit dflags ((l `shiftL` hALF_WORD_SIZE_IN_BITS dflags) .|. u)+ else mkWordCLit dflags (l .|. (u `shiftL` hALF_WORD_SIZE_IN_BITS dflags))+ where l = fromStgHalfWord lower_half_word+ u = fromStgHalfWord upper_half_word++---------------------------------------------------+--+-- CmmExpr+--+---------------------------------------------------++mkLblExpr :: CLabel -> CmmExpr+mkLblExpr lbl = CmmLit (CmmLabel lbl)++cmmOffsetExpr :: DynFlags -> CmmExpr -> CmmExpr -> CmmExpr+-- assumes base and offset have the same CmmType+cmmOffsetExpr dflags e (CmmLit (CmmInt n _)) = cmmOffset dflags e (fromInteger n)+cmmOffsetExpr dflags e byte_off = CmmMachOp (MO_Add (cmmExprWidth dflags e)) [e, byte_off]++cmmOffset :: DynFlags -> CmmExpr -> Int -> CmmExpr+cmmOffset _ e 0 = e+cmmOffset _ (CmmReg reg) byte_off = cmmRegOff reg byte_off+cmmOffset _ (CmmRegOff reg m) byte_off = cmmRegOff reg (m+byte_off)+cmmOffset _ (CmmLit lit) byte_off = CmmLit (cmmOffsetLit lit byte_off)+cmmOffset _ (CmmStackSlot area off) byte_off+ = CmmStackSlot area (off - byte_off)+ -- note stack area offsets increase towards lower addresses+cmmOffset _ (CmmMachOp (MO_Add rep) [expr, CmmLit (CmmInt byte_off1 _rep)]) byte_off2+ = CmmMachOp (MO_Add rep)+ [expr, CmmLit (CmmInt (byte_off1 + toInteger byte_off2) rep)]+cmmOffset dflags expr byte_off+ = CmmMachOp (MO_Add width) [expr, CmmLit (CmmInt (toInteger byte_off) width)]+ where+ width = cmmExprWidth dflags expr++-- Smart constructor for CmmRegOff. Same caveats as cmmOffset above.+cmmRegOff :: CmmReg -> Int -> CmmExpr+cmmRegOff reg 0 = CmmReg reg+cmmRegOff reg byte_off = CmmRegOff reg byte_off++cmmOffsetLit :: CmmLit -> Int -> CmmLit+cmmOffsetLit (CmmLabel l) byte_off = cmmLabelOff l byte_off+cmmOffsetLit (CmmLabelOff l m) byte_off = cmmLabelOff l (m+byte_off)+cmmOffsetLit (CmmLabelDiffOff l1 l2 m) byte_off+ = CmmLabelDiffOff l1 l2 (m+byte_off)+cmmOffsetLit (CmmInt m rep) byte_off = CmmInt (m + fromIntegral byte_off) rep+cmmOffsetLit _ byte_off = pprPanic "cmmOffsetLit" (ppr byte_off)++cmmLabelOff :: CLabel -> Int -> CmmLit+-- Smart constructor for CmmLabelOff+cmmLabelOff lbl 0 = CmmLabel lbl+cmmLabelOff lbl byte_off = CmmLabelOff lbl byte_off++-- | Useful for creating an index into an array, with a statically known offset.+-- The type is the element type; used for making the multiplier+cmmIndex :: DynFlags+ -> Width -- Width w+ -> CmmExpr -- Address of vector of items of width w+ -> Int -- Which element of the vector (0 based)+ -> CmmExpr -- Address of i'th element+cmmIndex dflags width base idx = cmmOffset dflags base (idx * widthInBytes width)++-- | Useful for creating an index into an array, with an unknown offset.+cmmIndexExpr :: DynFlags+ -> Width -- Width w+ -> CmmExpr -- Address of vector of items of width w+ -> CmmExpr -- Which element of the vector (0 based)+ -> CmmExpr -- Address of i'th element+cmmIndexExpr dflags width base (CmmLit (CmmInt n _)) = cmmIndex dflags width base (fromInteger n)+cmmIndexExpr dflags width base idx =+ cmmOffsetExpr dflags base byte_off+ where+ idx_w = cmmExprWidth dflags idx+ byte_off = CmmMachOp (MO_Shl idx_w) [idx, mkIntExpr dflags (widthInLog width)]++cmmLoadIndex :: DynFlags -> CmmType -> CmmExpr -> Int -> CmmExpr+cmmLoadIndex dflags ty expr ix = CmmLoad (cmmIndex dflags (typeWidth ty) expr ix) ty++-- The "B" variants take byte offsets+cmmRegOffB :: CmmReg -> ByteOff -> CmmExpr+cmmRegOffB = cmmRegOff++cmmOffsetB :: DynFlags -> CmmExpr -> ByteOff -> CmmExpr+cmmOffsetB = cmmOffset++cmmOffsetExprB :: DynFlags -> CmmExpr -> CmmExpr -> CmmExpr+cmmOffsetExprB = cmmOffsetExpr++cmmLabelOffB :: CLabel -> ByteOff -> CmmLit+cmmLabelOffB = cmmLabelOff++cmmOffsetLitB :: CmmLit -> ByteOff -> CmmLit+cmmOffsetLitB = cmmOffsetLit++-----------------------+-- The "W" variants take word offsets++cmmOffsetExprW :: DynFlags -> CmmExpr -> CmmExpr -> CmmExpr+-- The second arg is a *word* offset; need to change it to bytes+cmmOffsetExprW dflags e (CmmLit (CmmInt n _)) = cmmOffsetW dflags e (fromInteger n)+cmmOffsetExprW dflags e wd_off = cmmIndexExpr dflags (wordWidth dflags) e wd_off++cmmOffsetW :: DynFlags -> CmmExpr -> WordOff -> CmmExpr+cmmOffsetW dflags e n = cmmOffsetB dflags e (wordsToBytes dflags n)++cmmRegOffW :: DynFlags -> CmmReg -> WordOff -> CmmExpr+cmmRegOffW dflags reg wd_off = cmmRegOffB reg (wordsToBytes dflags wd_off)++cmmOffsetLitW :: DynFlags -> CmmLit -> WordOff -> CmmLit+cmmOffsetLitW dflags lit wd_off = cmmOffsetLitB lit (wordsToBytes dflags wd_off)++cmmLabelOffW :: DynFlags -> CLabel -> WordOff -> CmmLit+cmmLabelOffW dflags lbl wd_off = cmmLabelOffB lbl (wordsToBytes dflags wd_off)++cmmLoadIndexW :: DynFlags -> CmmExpr -> Int -> CmmType -> CmmExpr+cmmLoadIndexW dflags base off ty = CmmLoad (cmmOffsetW dflags base off) ty++-----------------------+cmmULtWord, cmmUGeWord, cmmUGtWord, cmmUShrWord,+ cmmSLtWord,+ cmmNeWord, cmmEqWord,+ cmmOrWord, cmmAndWord,+ cmmSubWord, cmmAddWord, cmmMulWord, cmmQuotWord+ :: DynFlags -> CmmExpr -> CmmExpr -> CmmExpr+cmmOrWord dflags e1 e2 = CmmMachOp (mo_wordOr dflags) [e1, e2]+cmmAndWord dflags e1 e2 = CmmMachOp (mo_wordAnd dflags) [e1, e2]+cmmNeWord dflags e1 e2 = CmmMachOp (mo_wordNe dflags) [e1, e2]+cmmEqWord dflags e1 e2 = CmmMachOp (mo_wordEq dflags) [e1, e2]+cmmULtWord dflags e1 e2 = CmmMachOp (mo_wordULt dflags) [e1, e2]+cmmUGeWord dflags e1 e2 = CmmMachOp (mo_wordUGe dflags) [e1, e2]+cmmUGtWord dflags e1 e2 = CmmMachOp (mo_wordUGt dflags) [e1, e2]+--cmmShlWord dflags e1 e2 = CmmMachOp (mo_wordShl dflags) [e1, e2]+cmmSLtWord dflags e1 e2 = CmmMachOp (mo_wordSLt dflags) [e1, e2]+cmmUShrWord dflags e1 e2 = CmmMachOp (mo_wordUShr dflags) [e1, e2]+cmmAddWord dflags e1 e2 = CmmMachOp (mo_wordAdd dflags) [e1, e2]+cmmSubWord dflags e1 e2 = CmmMachOp (mo_wordSub dflags) [e1, e2]+cmmMulWord dflags e1 e2 = CmmMachOp (mo_wordMul dflags) [e1, e2]+cmmQuotWord dflags e1 e2 = CmmMachOp (mo_wordUQuot dflags) [e1, e2]++cmmNegate :: DynFlags -> CmmExpr -> CmmExpr+cmmNegate _ (CmmLit (CmmInt n rep)) = CmmLit (CmmInt (-n) rep)+cmmNegate dflags e = CmmMachOp (MO_S_Neg (cmmExprWidth dflags e)) [e]++blankWord :: DynFlags -> CmmStatic+blankWord dflags = CmmUninitialised (wORD_SIZE dflags)++cmmToWord :: DynFlags -> CmmExpr -> CmmExpr+cmmToWord dflags e+ | w == word = e+ | otherwise = CmmMachOp (MO_UU_Conv w word) [e]+ where+ w = cmmExprWidth dflags e+ word = wordWidth dflags++---------------------------------------------------+--+-- CmmExpr predicates+--+---------------------------------------------------++isTrivialCmmExpr :: CmmExpr -> Bool+isTrivialCmmExpr (CmmLoad _ _) = False+isTrivialCmmExpr (CmmMachOp _ _) = False+isTrivialCmmExpr (CmmLit _) = True+isTrivialCmmExpr (CmmReg _) = True+isTrivialCmmExpr (CmmRegOff _ _) = True+isTrivialCmmExpr (CmmStackSlot _ _) = panic "isTrivialCmmExpr CmmStackSlot"++hasNoGlobalRegs :: CmmExpr -> Bool+hasNoGlobalRegs (CmmLoad e _) = hasNoGlobalRegs e+hasNoGlobalRegs (CmmMachOp _ es) = all hasNoGlobalRegs es+hasNoGlobalRegs (CmmLit _) = True+hasNoGlobalRegs (CmmReg (CmmLocal _)) = True+hasNoGlobalRegs (CmmRegOff (CmmLocal _) _) = True+hasNoGlobalRegs _ = False++---------------------------------------------------+--+-- Tagging+--+---------------------------------------------------++-- Tag bits mask+--cmmTagBits = CmmLit (mkIntCLit tAG_BITS)+cmmTagMask, cmmPointerMask :: DynFlags -> CmmExpr+cmmTagMask dflags = mkIntExpr dflags (tAG_MASK dflags)+cmmPointerMask dflags = mkIntExpr dflags (complement (tAG_MASK dflags))++-- Used to untag a possibly tagged pointer+-- A static label need not be untagged+cmmUntag :: DynFlags -> CmmExpr -> CmmExpr+cmmUntag _ e@(CmmLit (CmmLabel _)) = e+-- Default case+cmmUntag dflags e = cmmAndWord dflags e (cmmPointerMask dflags)++-- Test if a closure pointer is untagged+cmmIsTagged :: DynFlags -> CmmExpr -> CmmExpr+cmmIsTagged dflags e = cmmNeWord dflags (cmmAndWord dflags e (cmmTagMask dflags)) (zeroExpr dflags)++cmmConstrTag1 :: DynFlags -> CmmExpr -> CmmExpr+-- Get constructor tag, but one based.+cmmConstrTag1 dflags e = cmmAndWord dflags e (cmmTagMask dflags)+++-----------------------------------------------------------------------------+-- Overlap and usage++-- | Returns True if the two STG registers overlap on the specified+-- platform, in the sense that writing to one will clobber the+-- other. This includes the case that the two registers are the same+-- STG register. See Note [Overlapping global registers] for details.+regsOverlap :: DynFlags -> CmmReg -> CmmReg -> Bool+regsOverlap dflags (CmmGlobal g) (CmmGlobal g')+ | Just real <- globalRegMaybe (targetPlatform dflags) g,+ Just real' <- globalRegMaybe (targetPlatform dflags) g',+ real == real'+ = True+regsOverlap _ reg reg' = reg == reg'++-- | Returns True if the STG register is used by the expression, in+-- the sense that a store to the register might affect the value of+-- the expression.+--+-- We must check for overlapping registers and not just equal+-- registers here, otherwise CmmSink may incorrectly reorder+-- assignments that conflict due to overlap. See Trac #10521 and Note+-- [Overlapping global registers].+regUsedIn :: DynFlags -> CmmReg -> CmmExpr -> Bool+regUsedIn dflags = regUsedIn_ where+ _ `regUsedIn_` CmmLit _ = False+ reg `regUsedIn_` CmmLoad e _ = reg `regUsedIn_` e+ reg `regUsedIn_` CmmReg reg' = regsOverlap dflags reg reg'+ reg `regUsedIn_` CmmRegOff reg' _ = regsOverlap dflags reg reg'+ reg `regUsedIn_` CmmMachOp _ es = any (reg `regUsedIn_`) es+ _ `regUsedIn_` CmmStackSlot _ _ = False++--------------------------------------------+--+-- mkLiveness+--+---------------------------------------------++mkLiveness :: DynFlags -> [Maybe LocalReg] -> Liveness+mkLiveness _ [] = []+mkLiveness dflags (reg:regs)+ = take sizeW bits ++ mkLiveness dflags regs+ where+ sizeW = case reg of+ Nothing -> 1+ Just r -> (widthInBytes (typeWidth (localRegType r)) + wORD_SIZE dflags - 1)+ `quot` wORD_SIZE dflags+ -- number of words, rounded up+ bits = repeat $ is_non_ptr reg -- True <=> Non Ptr++ is_non_ptr Nothing = True+ is_non_ptr (Just reg) = not $ isGcPtrType (localRegType reg)+++-- ============================================== -+-- ============================================== -+-- ============================================== -++---------------------------------------------------+--+-- Manipulating CmmGraphs+--+---------------------------------------------------++modifyGraph :: (Graph n C C -> Graph n' C C) -> GenCmmGraph n -> GenCmmGraph n'+modifyGraph f g = CmmGraph {g_entry=g_entry g, g_graph=f (g_graph g)}++toBlockMap :: CmmGraph -> LabelMap CmmBlock+toBlockMap (CmmGraph {g_graph=GMany NothingO body NothingO}) = body++ofBlockMap :: BlockId -> LabelMap CmmBlock -> CmmGraph+ofBlockMap entry bodyMap = CmmGraph {g_entry=entry, g_graph=GMany NothingO bodyMap NothingO}++insertBlock :: CmmBlock -> LabelMap CmmBlock -> LabelMap CmmBlock+insertBlock block map =+ ASSERT(isNothing $ mapLookup id map)+ mapInsert id block map+ where id = entryLabel block++toBlockList :: CmmGraph -> [CmmBlock]+toBlockList g = mapElems $ toBlockMap g++-- | like 'toBlockList', but the entry block always comes first+toBlockListEntryFirst :: CmmGraph -> [CmmBlock]+toBlockListEntryFirst g+ | mapNull m = []+ | otherwise = entry_block : others+ where+ m = toBlockMap g+ entry_id = g_entry g+ Just entry_block = mapLookup entry_id m+ others = filter ((/= entry_id) . entryLabel) (mapElems m)++-- | Like 'toBlockListEntryFirst', but we strive to ensure that we order blocks+-- so that the false case of a conditional jumps to the next block in the output+-- list of blocks. This matches the way OldCmm blocks were output since in+-- OldCmm the false case was a fallthrough, whereas in Cmm conditional branches+-- have both true and false successors. Block ordering can make a big difference+-- in performance in the LLVM backend. Note that we rely crucially on the order+-- of successors returned for CmmCondBranch by the NonLocal instance for CmmNode+-- defind in cmm/CmmNode.hs. -GBM+toBlockListEntryFirstFalseFallthrough :: CmmGraph -> [CmmBlock]+toBlockListEntryFirstFalseFallthrough g+ | mapNull m = []+ | otherwise = dfs setEmpty [entry_block]+ where+ m = toBlockMap g+ entry_id = g_entry g+ Just entry_block = mapLookup entry_id m++ dfs :: LabelSet -> [CmmBlock] -> [CmmBlock]+ dfs _ [] = []+ dfs visited (block:bs)+ | id `setMember` visited = dfs visited bs+ | otherwise = block : dfs (setInsert id visited) bs'+ where id = entryLabel block+ bs' = foldr add_id bs (successors block)+ add_id id bs = case mapLookup id m of+ Just b -> b : bs+ Nothing -> bs++ofBlockList :: BlockId -> [CmmBlock] -> CmmGraph+ofBlockList entry blocks = CmmGraph { g_entry = entry+ , g_graph = GMany NothingO body NothingO }+ where body = foldr addBlock emptyBody blocks++bodyToBlockList :: Body CmmNode -> [CmmBlock]+bodyToBlockList body = mapElems body++mapGraphNodes :: ( CmmNode C O -> CmmNode C O+ , CmmNode O O -> CmmNode O O+ , CmmNode O C -> CmmNode O C)+ -> CmmGraph -> CmmGraph+mapGraphNodes funs@(mf,_,_) g =+ ofBlockMap (entryLabel $ mf $ CmmEntry (g_entry g) GlobalScope) $+ mapMap (mapBlock3' funs) $ toBlockMap g++mapGraphNodes1 :: (forall e x. CmmNode e x -> CmmNode e x) -> CmmGraph -> CmmGraph+mapGraphNodes1 f = modifyGraph (mapGraph f)+++foldGraphBlocks :: (CmmBlock -> a -> a) -> a -> CmmGraph -> a+foldGraphBlocks k z g = mapFold k z $ toBlockMap g++postorderDfs :: CmmGraph -> [CmmBlock]+postorderDfs g = {-# SCC "postorderDfs" #-} postorder_dfs_from (toBlockMap g) (g_entry g)++-------------------------------------------------+-- Tick utilities++-- | Extract all tick annotations from the given block+blockTicks :: Block CmmNode C C -> [CmmTickish]+blockTicks b = reverse $ foldBlockNodesF goStmt b []+ where goStmt :: CmmNode e x -> [CmmTickish] -> [CmmTickish]+ goStmt (CmmTick t) ts = t:ts+ goStmt _other ts = ts
+ cmm/Debug.hs view
@@ -0,0 +1,459 @@+{-# LANGUAGE GADTs #-}++-----------------------------------------------------------------------------+--+-- Debugging data+--+-- Association of debug data on the Cmm level, with methods to encode it in+-- event log format for later inclusion in profiling event logs.+--+-----------------------------------------------------------------------------++module Debug (++ DebugBlock(..), dblIsEntry,+ cmmDebugGen,+ cmmDebugLabels,+ cmmDebugLink,+ debugToMap,++ -- * Unwinding information+ UnwindTable, UnwindPoint(..),+ UnwindExpr(..), toUnwindExpr+ ) where++import BlockId+import CLabel+import Cmm+import CmmUtils+import CoreSyn+import FastString ( nilFS, mkFastString )+import Module+import Outputable+import PprCore ()+import PprCmmExpr ( pprExpr )+import SrcLoc+import Util++import Compiler.Hoopl++import Data.Maybe+import Data.List ( minimumBy, nubBy )+import Data.Ord ( comparing )+import qualified Data.Map as Map++-- | Debug information about a block of code. Ticks scope over nested+-- blocks.+data DebugBlock =+ DebugBlock+ { dblProcedure :: !Label -- ^ Entry label of containing proc+ , dblLabel :: !Label -- ^ Hoopl label+ , dblCLabel :: !CLabel -- ^ Output label+ , dblHasInfoTbl :: !Bool -- ^ Has an info table?+ , dblParent :: !(Maybe DebugBlock)+ -- ^ The parent of this proc. See Note [Splitting DebugBlocks]+ , dblTicks :: ![CmmTickish] -- ^ Ticks defined in this block+ , dblSourceTick+ :: !(Maybe CmmTickish) -- ^ Best source tick covering block+ , dblPosition :: !(Maybe Int) -- ^ Output position relative to+ -- other blocks. @Nothing@ means+ -- the block was optimized out+ , dblUnwind :: [UnwindPoint]+ , dblBlocks :: ![DebugBlock] -- ^ Nested blocks+ }++-- | Is this the entry block?+dblIsEntry :: DebugBlock -> Bool+dblIsEntry blk = dblProcedure blk == dblLabel blk++instance Outputable DebugBlock where+ ppr blk = (if dblProcedure blk == dblLabel blk+ then text "proc "+ else if dblHasInfoTbl blk+ then text "pp-blk "+ else text "blk ") <>+ ppr (dblLabel blk) <+> parens (ppr (dblCLabel blk)) <+>+ (maybe empty ppr (dblSourceTick blk)) <+>+ (maybe (text "removed") ((text "pos " <>) . ppr)+ (dblPosition blk)) <+>+ (ppr (dblUnwind blk)) <+>+ (if null (dblBlocks blk) then empty else ppr (dblBlocks blk))++-- | Intermediate data structure holding debug-relevant context information+-- about a block.+type BlockContext = (CmmBlock, RawCmmDecl)++-- | Extract debug data from a group of procedures. We will prefer+-- source notes that come from the given module (presumably the module+-- that we are currently compiling).+cmmDebugGen :: ModLocation -> RawCmmGroup -> [DebugBlock]+cmmDebugGen modLoc decls = map (blocksForScope Nothing) topScopes+ where+ blockCtxs :: Map.Map CmmTickScope [BlockContext]+ blockCtxs = blockContexts decls++ -- Analyse tick scope structure: Each one is either a top-level+ -- tick scope, or the child of another.+ (topScopes, childScopes)+ = splitEithers $ map (\a -> findP a a) $ Map.keys blockCtxs+ findP tsc GlobalScope = Left tsc -- top scope+ findP tsc scp | scp' `Map.member` blockCtxs = Right (scp', tsc)+ | otherwise = findP tsc scp'+ where -- Note that we only following the left parent of+ -- combined scopes. This loses us ticks, which we will+ -- recover by copying ticks below.+ scp' | SubScope _ scp' <- scp = scp'+ | CombinedScope scp' _ <- scp = scp'+ | otherwise = panic "findP impossible"++ scopeMap = foldr (uncurry insertMulti) Map.empty childScopes++ -- This allows us to recover ticks that we lost by flattening+ -- the graph. Basically, if the parent is A but the child is+ -- CBA, we know that there is no BA, because it would have taken+ -- priority - but there might be a B scope, with ticks that+ -- would not be associated with our child anymore. Note however+ -- that there might be other childs (DB), which we have to+ -- filter out.+ --+ -- We expect this to be called rarely, which is why we are not+ -- trying too hard to be efficient here. In many cases we won't+ -- have to construct blockCtxsU in the first place.+ ticksToCopy :: CmmTickScope -> [CmmTickish]+ ticksToCopy (CombinedScope scp s) = go s+ where go s | scp `isTickSubScope` s = [] -- done+ | SubScope _ s' <- s = ticks ++ go s'+ | CombinedScope s1 s2 <- s = ticks ++ go s1 ++ go s2+ | otherwise = panic "ticksToCopy impossible"+ where ticks = bCtxsTicks $ fromMaybe [] $ Map.lookup s blockCtxs+ ticksToCopy _ = []+ bCtxsTicks = concatMap (blockTicks . fst)++ -- Finding the "best" source tick is somewhat arbitrary -- we+ -- select the first source span, while preferring source ticks+ -- from the same source file. Furthermore, dumps take priority+ -- (if we generated one, we probably want debug information to+ -- refer to it).+ bestSrcTick = minimumBy (comparing rangeRating)+ rangeRating (SourceNote span _)+ | srcSpanFile span == thisFile = 1+ | otherwise = 2 :: Int+ rangeRating note = pprPanic "rangeRating" (ppr note)+ thisFile = maybe nilFS mkFastString $ ml_hs_file modLoc++ -- Returns block tree for this scope as well as all nested+ -- scopes. Note that if there are multiple blocks in the (exact)+ -- same scope we elect one as the "branch" node and add the rest+ -- as children.+ blocksForScope :: Maybe CmmTickish -> CmmTickScope -> DebugBlock+ blocksForScope cstick scope = mkBlock True (head bctxs)+ where bctxs = fromJust $ Map.lookup scope blockCtxs+ nested = fromMaybe [] $ Map.lookup scope scopeMap+ childs = map (mkBlock False) (tail bctxs) +++ map (blocksForScope stick) nested++ mkBlock :: Bool -> BlockContext -> DebugBlock+ mkBlock top (block, prc)+ = DebugBlock { dblProcedure = g_entry graph+ , dblLabel = label+ , dblCLabel = case info of+ Just (Statics infoLbl _) -> infoLbl+ Nothing+ | g_entry graph == label -> entryLbl+ | otherwise -> blockLbl label+ , dblHasInfoTbl = isJust info+ , dblParent = Nothing+ , dblTicks = ticks+ , dblPosition = Nothing -- see cmmDebugLink+ , dblSourceTick = stick+ , dblBlocks = blocks+ , dblUnwind = []+ }+ where (CmmProc infos entryLbl _ graph) = prc+ label = entryLabel block+ info = mapLookup label infos+ blocks | top = seqList childs childs+ | otherwise = []++ -- A source tick scopes over all nested blocks. However+ -- their source ticks might take priority.+ isSourceTick SourceNote {} = True+ isSourceTick _ = False+ -- Collect ticks from all blocks inside the tick scope.+ -- We attempt to filter out duplicates while we're at it.+ ticks = nubBy (flip tickishContains) $+ bCtxsTicks bctxs ++ ticksToCopy scope+ stick = case filter isSourceTick ticks of+ [] -> cstick+ sticks -> Just $! bestSrcTick (sticks ++ maybeToList cstick)++-- | Build a map of blocks sorted by their tick scopes+--+-- This involves a pre-order traversal, as we want blocks in rough+-- control flow order (so ticks have a chance to be sorted in the+-- right order).+blockContexts :: RawCmmGroup -> Map.Map CmmTickScope [BlockContext]+blockContexts decls = Map.map reverse $ foldr walkProc Map.empty decls+ where walkProc :: RawCmmDecl+ -> Map.Map CmmTickScope [BlockContext]+ -> Map.Map CmmTickScope [BlockContext]+ walkProc CmmData{} m = m+ walkProc prc@(CmmProc _ _ _ graph) m+ | mapNull blocks = m+ | otherwise = snd $ walkBlock prc entry (emptyLbls, m)+ where blocks = toBlockMap graph+ entry = [mapFind (g_entry graph) blocks]+ emptyLbls = setEmpty :: LabelSet++ walkBlock :: RawCmmDecl -> [Block CmmNode C C]+ -> (LabelSet, Map.Map CmmTickScope [BlockContext])+ -> (LabelSet, Map.Map CmmTickScope [BlockContext])+ walkBlock _ [] c = c+ walkBlock prc (block:blocks) (visited, m)+ | lbl `setMember` visited+ = walkBlock prc blocks (visited, m)+ | otherwise+ = walkBlock prc blocks $+ walkBlock prc succs+ (lbl `setInsert` visited,+ insertMulti scope (block, prc) m)+ where CmmEntry lbl scope = firstNode block+ (CmmProc _ _ _ graph) = prc+ succs = map (flip mapFind (toBlockMap graph))+ (successors (lastNode block))+ mapFind = mapFindWithDefault (error "contextTree: block not found!")++insertMulti :: Ord k => k -> a -> Map.Map k [a] -> Map.Map k [a]+insertMulti k v = Map.insertWith (const (v:)) k [v]++cmmDebugLabels :: (i -> Bool) -> GenCmmGroup d g (ListGraph i) -> [Label]+cmmDebugLabels isMeta nats = seqList lbls lbls+ where -- Find order in which procedures will be generated by the+ -- back-end (that actually matters for DWARF generation).+ --+ -- Note that we might encounter blocks that are missing or only+ -- consist of meta instructions -- we will declare them missing,+ -- which will skip debug data generation without messing up the+ -- block hierarchy.+ lbls = map blockId $ filter (not . allMeta) $ concatMap getBlocks nats+ getBlocks (CmmProc _ _ _ (ListGraph bs)) = bs+ getBlocks _other = []+ allMeta (BasicBlock _ instrs) = all isMeta instrs++-- | Sets position and unwind table fields in the debug block tree according to+-- native generated code.+cmmDebugLink :: [Label] -> LabelMap [UnwindPoint]+ -> [DebugBlock] -> [DebugBlock]+cmmDebugLink labels unwindPts blocks = map link blocks+ where blockPos :: LabelMap Int+ blockPos = mapFromList $ flip zip [0..] labels+ link block = block { dblPosition = mapLookup (dblLabel block) blockPos+ , dblBlocks = map link (dblBlocks block)+ , dblUnwind = fromMaybe mempty+ $ mapLookup (dblLabel block) unwindPts+ }++-- | Converts debug blocks into a label map for easier lookups+debugToMap :: [DebugBlock] -> LabelMap DebugBlock+debugToMap = mapUnions . map go+ where go b = mapInsert (dblLabel b) b $ mapUnions $ map go (dblBlocks b)++{-+Note [What is this unwinding business?]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Unwinding tables are a variety of debugging information used by debugging tools+to reconstruct the execution history of a program at runtime. These tables+consist of sets of "instructions", one set for every instruction in the program,+which describe how to reconstruct the state of the machine at the point where+the current procedure was called. For instance, consider the following annotated+pseudo-code,++ a_fun:+ add rsp, 8 -- unwind: rsp = rsp - 8+ mov rax, 1 -- unwind: rax = unknown+ call another_block+ sub rsp, 8 -- unwind: rsp = rsp++We see that attached to each instruction there is an "unwind" annotation, which+provides a relationship between each updated register and its value at the+time of entry to a_fun. This is the sort of information that allows gdb to give+you a stack backtrace given the execution state of your program. This+unwinding information is captured in various ways by various debug information+formats; in the case of DWARF (the only format supported by GHC) it is known as+Call Frame Information (CFI) and can be found in the .debug.frames section of+your object files.++Currently we only bother to produce unwinding information for registers which+are necessary to reconstruct flow-of-execution. On x86_64 this includes $rbp+(which is the STG stack pointer) and $rsp (the C stack pointer).++Let's consider how GHC would annotate a C-- program with unwinding information+with a typical C-- procedure as would come from the STG-to-Cmm code generator,++ entry()+ { c2fe:+ v :: P64 = R2;+ if ((Sp + 8) - 32 < SpLim) (likely: False) goto c2ff; else goto c2fg;+ c2ff:+ R2 = v :: P64;+ R1 = test_closure;+ call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8;+ c2fg:+ I64[Sp - 8] = c2dD;+ R1 = v :: P64;+ Sp = Sp - 8; // Sp updated here+ if (R1 & 7 != 0) goto c2dD; else goto c2dE;+ c2dE:+ call (I64[R1])(R1) returns to c2dD, args: 8, res: 8, upd: 8;+ c2dD:+ w :: P64 = R1;+ Hp = Hp + 48;+ if (Hp > HpLim) (likely: False) goto c2fj; else goto c2fi;+ ...+ },++Let's consider how this procedure will be decorated with unwind information+(largely by CmmLayoutStack). Naturally, when we enter the procedure `entry` the+value of Sp is no different from what it was at its call site. Therefore we will+add an `unwind` statement saying this at the beginning of its unwind-annotated+code,++ entry()+ { c2fe:+ unwind Sp = Just Sp + 0;+ v :: P64 = R2;+ if ((Sp + 8) - 32 < SpLim) (likely: False) goto c2ff; else goto c2fg;++After c2fe we we may pass to either c2ff or c2fg; let's first consider the+former. In this case there is nothing in particular that we need to do other+than reiterate what we already know about Sp,++ c2ff:+ unwind Sp = Just Sp + 0;+ R2 = v :: P64;+ R1 = test_closure;+ call (stg_gc_fun)(R2, R1) args: 8, res: 0, upd: 8;++In contrast, c2fg updates Sp midway through its body. To ensure that unwinding+can happen correctly after this point we must include an unwind statement there,+in addition to the usual beginning-of-block statement,++ c2fg:+ unwind Sp = Just Sp + 0;+ I64[Sp - 8] = c2dD;+ R1 = v :: P64;+ unwind Sp = Just Sp + 8;+ Sp = Sp - 8;+ if (R1 & 7 != 0) goto c2dD; else goto c2dE;++The remaining blocks are simple,++ c2dE:+ unwind Sp = Just Sp + 8;+ call (I64[R1])(R1) returns to c2dD, args: 8, res: 8, upd: 8;+ c2dD:+ unwind Sp = Just Sp + 8;+ w :: P64 = R1;+ Hp = Hp + 48;+ if (Hp > HpLim) (likely: False) goto c2fj; else goto c2fi;+ ...+ },+++The flow of unwinding information through the compiler is a bit convoluted:++ * C-- begins life in StgCmm without any unwind information. This is because we+ haven't actually done any register assignment or stack layout yet, so there+ is no need for unwind information.++ * CmmLayoutStack figures out how to layout each procedure's stack, and produces+ appropriate unwinding nodes for each adjustment of the STG Sp register.++ * The unwind nodes are carried through the sinking pass. Currently this is+ guaranteed not to invalidate unwind information since it won't touch stores+ to Sp, but this will need revisiting if CmmSink gets smarter in the future.++ * Eventually we make it to the native code generator backend which can then+ preserve the unwind nodes in its machine-specific instructions. In so doing+ the backend can also modify or add unwinding information; this is necessary,+ for instance, in the case of x86-64, where adjustment of $rsp may be+ necessary during calls to native foreign code due to the native calling+ convention.++ * The NCG then retrieves the final unwinding table for each block from the+ backend with extractUnwindPoints.++ * This unwind information is converted to DebugBlocks by Debug.cmmDebugGen++ * These DebugBlcosk are then converted to, e.g., DWARF unwinding tables+ (by the Dwarf module) and emitted in the final object.++See also: Note [Unwinding information in the NCG] in AsmCodeGen.+-}++-- | A label associated with an 'UnwindTable'+data UnwindPoint = UnwindPoint !CLabel !UnwindTable++instance Outputable UnwindPoint where+ ppr (UnwindPoint lbl uws) =+ braces $ ppr lbl<>colon+ <+> hsep (punctuate comma $ map pprUw $ Map.toList uws)+ where+ pprUw (g, expr) = ppr g <> char '=' <> ppr expr++-- | Maps registers to expressions that yield their "old" values+-- further up the stack. Most interesting for the stack pointer @Sp@,+-- but might be useful to document saved registers, too. Note that a+-- register's value will be 'Nothing' when the register's previous+-- value cannot be reconstructed.+type UnwindTable = Map.Map GlobalReg (Maybe UnwindExpr)++-- | Expressions, used for unwind information+data UnwindExpr = UwConst !Int -- ^ literal value+ | UwReg !GlobalReg !Int -- ^ register plus offset+ | UwDeref UnwindExpr -- ^ pointer dereferencing+ | UwLabel CLabel+ | UwPlus UnwindExpr UnwindExpr+ | UwMinus UnwindExpr UnwindExpr+ | UwTimes UnwindExpr UnwindExpr+ deriving (Eq)++instance Outputable UnwindExpr where+ pprPrec _ (UwConst i) = ppr i+ pprPrec _ (UwReg g 0) = ppr g+ pprPrec p (UwReg g x) = pprPrec p (UwPlus (UwReg g 0) (UwConst x))+ pprPrec _ (UwDeref e) = char '*' <> pprPrec 3 e+ pprPrec _ (UwLabel l) = pprPrec 3 l+ pprPrec p (UwPlus e0 e1) | p <= 0+ = pprPrec 0 e0 <> char '+' <> pprPrec 0 e1+ pprPrec p (UwMinus e0 e1) | p <= 0+ = pprPrec 1 e0 <> char '-' <> pprPrec 1 e1+ pprPrec p (UwTimes e0 e1) | p <= 1+ = pprPrec 2 e0 <> char '*' <> pprPrec 2 e1+ pprPrec _ other = parens (pprPrec 0 other)++-- | Conversion of Cmm expressions to unwind expressions. We check for+-- unsupported operator usages and simplify the expression as far as+-- possible.+toUnwindExpr :: CmmExpr -> UnwindExpr+toUnwindExpr (CmmLit (CmmInt i _)) = UwConst (fromIntegral i)+toUnwindExpr (CmmLit (CmmLabel l)) = UwLabel l+toUnwindExpr (CmmRegOff (CmmGlobal g) i) = UwReg g i+toUnwindExpr (CmmReg (CmmGlobal g)) = UwReg g 0+toUnwindExpr (CmmLoad e _) = UwDeref (toUnwindExpr e)+toUnwindExpr e@(CmmMachOp op [e1, e2]) =+ case (op, toUnwindExpr e1, toUnwindExpr e2) of+ (MO_Add{}, UwReg r x, UwConst y) -> UwReg r (x + y)+ (MO_Sub{}, UwReg r x, UwConst y) -> UwReg r (x - y)+ (MO_Add{}, UwConst x, UwReg r y) -> UwReg r (x + y)+ (MO_Add{}, UwConst x, UwConst y) -> UwConst (x + y)+ (MO_Sub{}, UwConst x, UwConst y) -> UwConst (x - y)+ (MO_Mul{}, UwConst x, UwConst y) -> UwConst (x * y)+ (MO_Add{}, u1, u2 ) -> UwPlus u1 u2+ (MO_Sub{}, u1, u2 ) -> UwMinus u1 u2+ (MO_Mul{}, u1, u2 ) -> UwTimes u1 u2+ _otherwise -> pprPanic "Unsupported operator in unwind expression!"+ (pprExpr e)+toUnwindExpr e+ = pprPanic "Unsupported unwind expression!" (ppr e)
+ cmm/Hoopl.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE RankNTypes, ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Hoopl (+ module Compiler.Hoopl,+ module Hoopl.Dataflow,+ ) where++import Compiler.Hoopl hiding+ ( (<*>), mkLabel, mkBranch, mkMiddle, mkLast, -- clashes with our MkGraph+ DataflowLattice, OldFact, NewFact, JoinFun,+ fact_bot, fact_join, joinOutFacts, mkFactBase,+ Unique,+ FwdTransfer(..), FwdRewrite(..), FwdPass(..),+ BwdTransfer(..), BwdRewrite(..), BwdPass(..),+ mkFactBase, Fact,+ mkBRewrite3, mkBTransfer3,+ mkFRewrite3, mkFTransfer3,++ )++import Hoopl.Dataflow+import Outputable++instance Outputable LabelSet where+ ppr = ppr . setElems++instance Outputable a => Outputable (LabelMap a) where+ ppr = ppr . mapToList
+ cmm/Hoopl/Dataflow.hs view
@@ -0,0 +1,323 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}+{-# OPTIONS_GHC -fprof-auto-top #-}++--+-- Copyright (c) 2010, João Dias, Simon Marlow, Simon Peyton Jones,+-- and Norman Ramsey+--+-- Modifications copyright (c) The University of Glasgow 2012+--+-- This module is a specialised and optimised version of+-- Compiler.Hoopl.Dataflow in the hoopl package. In particular it is+-- specialised to the UniqSM monad.+--++module Hoopl.Dataflow+ ( C, O, Block+ , lastNode, entryLabel+ , foldNodesBwdOO+ , DataflowLattice(..), OldFact(..), NewFact(..), JoinedFact(..), TransferFun+ , Fact, FactBase+ , getFact, mkFactBase+ , analyzeCmmFwd, analyzeCmmBwd+ , changedIf+ , joinOutFacts+ )+where++import Cmm++import Data.Array+import Data.List+import Data.Maybe++-- Hide definitions from Hoopl's Dataflow module.+import Compiler.Hoopl hiding ( DataflowLattice, OldFact, NewFact, JoinFun+ , fact_bot, fact_join, joinOutFacts, mkFactBase+ )++newtype OldFact a = OldFact a++newtype NewFact a = NewFact a++-- | The result of joining OldFact and NewFact.+data JoinedFact a+ = Changed !a -- ^ Result is different than OldFact.+ | NotChanged !a -- ^ Result is the same as OldFact.++getJoined :: JoinedFact a -> a+getJoined (Changed a) = a+getJoined (NotChanged a) = a++changedIf :: Bool -> a -> JoinedFact a+changedIf True = Changed+changedIf False = NotChanged++type JoinFun a = OldFact a -> NewFact a -> JoinedFact a++data DataflowLattice a = DataflowLattice+ { fact_bot :: a+ , fact_join :: JoinFun a+ }++data Direction = Fwd | Bwd++type TransferFun f = CmmBlock -> FactBase f -> FactBase f++analyzeCmmBwd, analyzeCmmFwd+ :: DataflowLattice f+ -> TransferFun f+ -> CmmGraph+ -> FactBase f+ -> FactBase f+analyzeCmmBwd = analyzeCmm Bwd+analyzeCmmFwd = analyzeCmm Fwd++analyzeCmm+ :: Direction+ -> DataflowLattice f+ -> TransferFun f+ -> CmmGraph+ -> FactBase f+ -> FactBase f+analyzeCmm dir lattice transfer cmmGraph initFact =+ let entry = g_entry cmmGraph+ hooplGraph = g_graph cmmGraph+ blockMap =+ case hooplGraph of+ GMany NothingO bm NothingO -> bm+ entries = if mapNull initFact then [entry] else mapKeys initFact+ in fixpointAnalysis dir lattice transfer entries blockMap initFact++-- Fixpoint algorithm.+fixpointAnalysis+ :: forall f.+ Direction+ -> DataflowLattice f+ -> TransferFun f+ -> [Label]+ -> LabelMap CmmBlock+ -> FactBase f+ -> FactBase f+fixpointAnalysis direction lattice do_block entries blockmap = loop start+ where+ -- Sorting the blocks helps to minimize the number of times we need to+ -- process blocks. For instance, for forward analysis we want to look at+ -- blocks in reverse postorder. Also, see comments for sortBlocks.+ blocks = sortBlocks direction entries blockmap+ num_blocks = length blocks+ block_arr = {-# SCC "block_arr" #-} listArray (0, num_blocks - 1) blocks+ start = {-# SCC "start" #-} [0 .. num_blocks - 1]+ dep_blocks = {-# SCC "dep_blocks" #-} mkDepBlocks direction blocks+ join = fact_join lattice++ loop+ :: IntHeap -- ^ Worklist, i.e., blocks to process+ -> FactBase f -- ^ Current result (increases monotonically)+ -> FactBase f+ loop [] !fbase1 = fbase1+ loop (index : todo1) !fbase1 =+ let block = block_arr ! index+ out_facts = {-# SCC "do_block" #-} do_block block fbase1+ -- For each of the outgoing edges, we join it with the current+ -- information in fbase1 and (if something changed) we update it+ -- and add the affected blocks to the worklist.+ (todo2, fbase2) = {-# SCC "mapFoldWithKey" #-}+ mapFoldWithKey+ (updateFact join dep_blocks) (todo1, fbase1) out_facts+ in loop todo2 fbase2++++{-+Note [Unreachable blocks]+~~~~~~~~~~~~~~~~~~~~~~~~~+A block that is not in the domain of tfb_fbase is "currently unreachable".+A currently-unreachable block is not even analyzed. Reason: consider+constant prop and this graph, with entry point L1:+ L1: x:=3; goto L4+ L2: x:=4; goto L4+ L4: if x>3 goto L2 else goto L5+Here L2 is actually unreachable, but if we process it with bottom input fact,+we'll propagate (x=4) to L4, and nuke the otherwise-good rewriting of L4.++* If a currently-unreachable block is not analyzed, then its rewritten+ graph will not be accumulated in tfb_rg. And that is good:+ unreachable blocks simply do not appear in the output.++* Note that clients must be careful to provide a fact (even if bottom)+ for each entry point. Otherwise useful blocks may be garbage collected.++* Note that updateFact must set the change-flag if a label goes from+ not-in-fbase to in-fbase, even if its fact is bottom. In effect the+ real fact lattice is+ UNR+ bottom+ the points above bottom++* Even if the fact is going from UNR to bottom, we still call the+ client's fact_join function because it might give the client+ some useful debugging information.++* All of this only applies for *forward* ixpoints. For the backward+ case we must treat every block as reachable; it might finish with a+ 'return', and therefore have no successors, for example.+-}+++-----------------------------------------------------------------------------+-- Pieces that are shared by fixpoint and fixpoint_anal+-----------------------------------------------------------------------------++-- | Sort the blocks into the right order for analysis. This means reverse+-- postorder for a forward analysis. For the backward one, we simply reverse+-- that (see Note [Backward vs forward analysis]).+--+-- Note: We're using Hoopl's confusingly named `postorder_dfs_from` but AFAICS+-- it returns the *reverse* postorder of the blocks (it visits blocks in the+-- postorder and uses (:) to collect them, which gives the reverse of the+-- visitation order).+sortBlocks+ :: NonLocal n+ => Direction -> [Label] -> LabelMap (Block n C C) -> [Block n C C]+sortBlocks direction entries blockmap =+ case direction of+ Fwd -> fwd+ Bwd -> reverse fwd+ where+ fwd = postorder_dfs_from blockmap entries++-- Note [Backward vs forward analysis]+--+-- The forward and backward cases are not dual. In the forward case, the entry+-- points are known, and one simply traverses the body blocks from those points.+-- In the backward case, something is known about the exit points, but a+-- backward analysis must also include reachable blocks that don't reach the+-- exit, as in a procedure that loops forever and has side effects.)+-- For instance, let E be the entry and X the exit blocks (arrows indicate+-- control flow)+-- E -> X+-- E -> B+-- B -> C+-- C -> B+-- We do need to include B and C even though they're unreachable in the+-- *reverse* graph (that we could use for backward analysis):+-- E <- X+-- E <- B+-- B <- C+-- C <- B+-- So when sorting the blocks for the backward analysis, we simply take the+-- reverse of what is used for the forward one.+++-- | construct a mapping from L -> block indices. If the fact for L+-- changes, re-analyse the given blocks.+mkDepBlocks :: NonLocal n => Direction -> [Block n C C] -> LabelMap [Int]+mkDepBlocks Fwd blocks = go blocks 0 mapEmpty+ where go [] !_ m = m+ go (b:bs) !n m = go bs (n+1) $! mapInsert (entryLabel b) [n] m+mkDepBlocks Bwd blocks = go blocks 0 mapEmpty+ where go [] !_ m = m+ go (b:bs) !n m = go bs (n+1) $! go' (successors b) m+ where go' [] m = m+ go' (l:ls) m = go' ls (mapInsertWith (++) l [n] m)+++-- | After some new facts have been generated by analysing a block, we+-- fold this function over them to generate (a) a list of block+-- indices to (re-)analyse, and (b) the new FactBase.+--+updateFact :: JoinFun f -> LabelMap [Int]+ -> Label -> f -- out fact+ -> (IntHeap, FactBase f)+ -> (IntHeap, FactBase f)++updateFact fact_join dep_blocks lbl new_fact (todo, fbase)+ = case lookupFact lbl fbase of+ Nothing -> let !z = mapInsert lbl new_fact fbase in (changed, z)+ -- Note [no old fact]+ Just old_fact ->+ case fact_join (OldFact old_fact) (NewFact new_fact) of+ (NotChanged _) -> (todo, fbase)+ (Changed f) -> let !z = mapInsert lbl f fbase in (changed, z)+ where+ changed = foldr insertIntHeap todo $+ mapFindWithDefault [] lbl dep_blocks++{-+Note [no old fact]++We know that the new_fact is >= _|_, so we don't need to join. However,+if the new fact is also _|_, and we have already analysed its block,+we don't need to record a change. So there's a tradeoff here. It turns+out that always recording a change is faster.+-}++----------------------------------------------------------------+-- Utilities+----------------------------------------------------------------++-- Fact lookup: the fact `orelse` bottom+getFact :: DataflowLattice f -> Label -> FactBase f -> f+getFact lat l fb = case lookupFact l fb of Just f -> f+ Nothing -> fact_bot lat++-- | Returns the result of joining the facts from all the successors of the+-- provided node or block.+joinOutFacts :: (NonLocal n) => DataflowLattice f -> n e C -> FactBase f -> f+joinOutFacts lattice nonLocal fact_base = foldl' join (fact_bot lattice) facts+ where+ join new old = getJoined $ fact_join lattice (OldFact old) (NewFact new)+ facts =+ [ fromJust fact+ | s <- successors nonLocal+ , let fact = lookupFact s fact_base+ , isJust fact+ ]++-- | Returns the joined facts for each label.+mkFactBase :: DataflowLattice f -> [(Label, f)] -> FactBase f+mkFactBase lattice = foldl' add mapEmpty+ where+ join = fact_join lattice++ add result (l, f1) =+ let !newFact =+ case mapLookup l result of+ Nothing -> f1+ Just f2 -> getJoined $ join (OldFact f1) (NewFact f2)+ in mapInsert l newFact result++-- | Folds backward over all nodes of an open-open block.+-- Strict in the accumulator.+foldNodesBwdOO :: (CmmNode O O -> f -> f) -> Block CmmNode O O -> f -> f+foldNodesBwdOO funOO = go+ where+ go (BCat b1 b2) f = go b1 $! go b2 f+ go (BSnoc h n) f = go h $! funOO n f+ go (BCons n t) f = funOO n $! go t f+ go (BMiddle n) f = funOO n f+ go BNil f = f+{-# INLINABLE foldNodesBwdOO #-}++-- -----------------------------------------------------------------------------+-- a Heap of Int++-- We should really use a proper Heap here, but my attempts to make+-- one have not succeeded in beating the simple ordered list. Another+-- alternative is IntSet (using deleteFindMin), but that was also+-- slower than the ordered list in my experiments --SDM 25/1/2012++type IntHeap = [Int] -- ordered++insertIntHeap :: Int -> [Int] -> [Int]+insertIntHeap x [] = [x]+insertIntHeap x (y:ys)+ | x < y = x : y : ys+ | x == y = x : ys+ | otherwise = y : insertIntHeap x ys
+ cmm/MkGraph.hs view
@@ -0,0 +1,415 @@+{-# LANGUAGE BangPatterns, CPP, GADTs #-}++module MkGraph+ ( CmmAGraph, CmmAGraphScoped, CgStmt(..)+ , (<*>), catAGraphs+ , mkLabel, mkMiddle, mkLast, outOfLine+ , lgraphOfAGraph, labelAGraph++ , stackStubExpr+ , mkNop, mkAssign, mkStore+ , mkUnsafeCall, mkFinalCall, mkCallReturnsTo+ , mkJumpReturnsTo+ , mkJump, mkJumpExtra+ , mkRawJump+ , mkCbranch, mkSwitch+ , mkReturn, mkComment, mkCallEntry, mkBranch+ , mkUnwind+ , copyInOflow, copyOutOflow+ , noExtraStack+ , toCall, Transfer(..)+ )+where++import BlockId+import Cmm+import CmmCallConv+import CmmSwitch (SwitchTargets)++import Compiler.Hoopl hiding (Unique, (<*>), mkFirst, mkMiddle, mkLast, mkLabel, mkBranch, Shape(..))+import DynFlags+import FastString+import ForeignCall+import OrdList+import SMRep (ByteOff)+import UniqSupply++import Control.Monad+import Data.List+import Data.Maybe+import Prelude (($),Int,Bool,Eq(..)) -- avoid importing (<*>)++#include "HsVersions.h"+++-----------------------------------------------------------------------------+-- Building Graphs+++-- | CmmAGraph is a chunk of code consisting of:+--+-- * ordinary statements (assignments, stores etc.)+-- * jumps+-- * labels+-- * out-of-line labelled blocks+--+-- The semantics is that control falls through labels and out-of-line+-- blocks. Everything after a jump up to the next label is by+-- definition unreachable code, and will be discarded.+--+-- Two CmmAGraphs can be stuck together with <*>, with the meaning that+-- control flows from the first to the second.+--+-- A 'CmmAGraph' can be turned into a 'CmmGraph' (closed at both ends)+-- by providing a label for the entry point and a tick scope; see+-- 'labelAGraph'.+type CmmAGraph = OrdList CgStmt+-- | Unlabeled graph with tick scope+type CmmAGraphScoped = (CmmAGraph, CmmTickScope)++data CgStmt+ = CgLabel BlockId CmmTickScope+ | CgStmt (CmmNode O O)+ | CgLast (CmmNode O C)+ | CgFork BlockId CmmAGraph CmmTickScope++flattenCmmAGraph :: BlockId -> CmmAGraphScoped -> CmmGraph+flattenCmmAGraph id (stmts_t, tscope) =+ CmmGraph { g_entry = id,+ g_graph = GMany NothingO body NothingO }+ where+ body = foldr addBlock emptyBody $ flatten id stmts_t tscope []++ --+ -- flatten: given an entry label and a CmmAGraph, make a list of blocks.+ --+ -- NB. avoid the quadratic-append trap by passing in the tail of the+ -- list. This is important for Very Long Functions (e.g. in T783).+ --+ flatten :: Label -> CmmAGraph -> CmmTickScope -> [Block CmmNode C C]+ -> [Block CmmNode C C]+ flatten id g tscope blocks+ = flatten1 (fromOL g) block' blocks+ where !block' = blockJoinHead (CmmEntry id tscope) emptyBlock+ --+ -- flatten0: we are outside a block at this point: any code before+ -- the first label is unreachable, so just drop it.+ --+ flatten0 :: [CgStmt] -> [Block CmmNode C C] -> [Block CmmNode C C]+ flatten0 [] blocks = blocks++ flatten0 (CgLabel id tscope : stmts) blocks+ = flatten1 stmts block blocks+ where !block = blockJoinHead (CmmEntry id tscope) emptyBlock++ flatten0 (CgFork fork_id stmts_t tscope : rest) blocks+ = flatten fork_id stmts_t tscope $ flatten0 rest blocks++ flatten0 (CgLast _ : stmts) blocks = flatten0 stmts blocks+ flatten0 (CgStmt _ : stmts) blocks = flatten0 stmts blocks++ --+ -- flatten1: we have a partial block, collect statements until the+ -- next last node to make a block, then call flatten0 to get the rest+ -- of the blocks+ --+ flatten1 :: [CgStmt] -> Block CmmNode C O+ -> [Block CmmNode C C] -> [Block CmmNode C C]++ -- The current block falls through to the end of a function or fork:+ -- this code should not be reachable, but it may be referenced by+ -- other code that is not reachable. We'll remove it later with+ -- dead-code analysis, but for now we have to keep the graph+ -- well-formed, so we terminate the block with a branch to the+ -- beginning of the current block.+ flatten1 [] block blocks+ = blockJoinTail block (CmmBranch (entryLabel block)) : blocks++ flatten1 (CgLast stmt : stmts) block blocks+ = block' : flatten0 stmts blocks+ where !block' = blockJoinTail block stmt++ flatten1 (CgStmt stmt : stmts) block blocks+ = flatten1 stmts block' blocks+ where !block' = blockSnoc block stmt++ flatten1 (CgFork fork_id stmts_t tscope : rest) block blocks+ = flatten fork_id stmts_t tscope $ flatten1 rest block blocks++ -- a label here means that we should start a new block, and the+ -- current block should fall through to the new block.+ flatten1 (CgLabel id tscp : stmts) block blocks+ = blockJoinTail block (CmmBranch id) :+ flatten1 stmts (blockJoinHead (CmmEntry id tscp) emptyBlock) blocks++++---------- AGraph manipulation++(<*>) :: CmmAGraph -> CmmAGraph -> CmmAGraph+(<*>) = appOL++catAGraphs :: [CmmAGraph] -> CmmAGraph+catAGraphs = concatOL++-- | created a sequence "goto id; id:" as an AGraph+mkLabel :: BlockId -> CmmTickScope -> CmmAGraph+mkLabel bid scp = unitOL (CgLabel bid scp)++-- | creates an open AGraph from a given node+mkMiddle :: CmmNode O O -> CmmAGraph+mkMiddle middle = unitOL (CgStmt middle)++-- | created a closed AGraph from a given node+mkLast :: CmmNode O C -> CmmAGraph+mkLast last = unitOL (CgLast last)++-- | A labelled code block; should end in a last node+outOfLine :: BlockId -> CmmAGraphScoped -> CmmAGraph+outOfLine l (c,s) = unitOL (CgFork l c s)++-- | allocate a fresh label for the entry point+lgraphOfAGraph :: CmmAGraphScoped -> UniqSM CmmGraph+lgraphOfAGraph g = do+ u <- getUniqueM+ return (labelAGraph (mkBlockId u) g)++-- | use the given BlockId as the label of the entry point+labelAGraph :: BlockId -> CmmAGraphScoped -> CmmGraph+labelAGraph lbl ag = flattenCmmAGraph lbl ag++---------- No-ops+mkNop :: CmmAGraph+mkNop = nilOL++mkComment :: FastString -> CmmAGraph+#ifdef DEBUG+-- SDM: generating all those comments takes time, this saved about 4% for me+mkComment fs = mkMiddle $ CmmComment fs+#else+mkComment _ = nilOL+#endif++---------- Assignment and store+mkAssign :: CmmReg -> CmmExpr -> CmmAGraph+mkAssign l (CmmReg r) | l == r = mkNop+mkAssign l r = mkMiddle $ CmmAssign l r++mkStore :: CmmExpr -> CmmExpr -> CmmAGraph+mkStore l r = mkMiddle $ CmmStore l r++---------- Control transfer+mkJump :: DynFlags -> Convention -> CmmExpr+ -> [CmmExpr]+ -> UpdFrameOffset+ -> CmmAGraph+mkJump dflags conv e actuals updfr_off =+ lastWithArgs dflags Jump Old conv actuals updfr_off $+ toCall e Nothing updfr_off 0++-- | A jump where the caller says what the live GlobalRegs are. Used+-- for low-level hand-written Cmm.+mkRawJump :: DynFlags -> CmmExpr -> UpdFrameOffset -> [GlobalReg]+ -> CmmAGraph+mkRawJump dflags e updfr_off vols =+ lastWithArgs dflags Jump Old NativeNodeCall [] updfr_off $+ \arg_space _ -> toCall e Nothing updfr_off 0 arg_space vols+++mkJumpExtra :: DynFlags -> Convention -> CmmExpr -> [CmmExpr]+ -> UpdFrameOffset -> [CmmExpr]+ -> CmmAGraph+mkJumpExtra dflags conv e actuals updfr_off extra_stack =+ lastWithArgsAndExtraStack dflags Jump Old conv actuals updfr_off extra_stack $+ toCall e Nothing updfr_off 0++mkCbranch :: CmmExpr -> BlockId -> BlockId -> Maybe Bool -> CmmAGraph+mkCbranch pred ifso ifnot likely =+ mkLast (CmmCondBranch pred ifso ifnot likely)++mkSwitch :: CmmExpr -> SwitchTargets -> CmmAGraph+mkSwitch e tbl = mkLast $ CmmSwitch e tbl++mkReturn :: DynFlags -> CmmExpr -> [CmmExpr] -> UpdFrameOffset+ -> CmmAGraph+mkReturn dflags e actuals updfr_off =+ lastWithArgs dflags Ret Old NativeReturn actuals updfr_off $+ toCall e Nothing updfr_off 0++mkBranch :: BlockId -> CmmAGraph+mkBranch bid = mkLast (CmmBranch bid)++mkFinalCall :: DynFlags+ -> CmmExpr -> CCallConv -> [CmmExpr] -> UpdFrameOffset+ -> CmmAGraph+mkFinalCall dflags f _ actuals updfr_off =+ lastWithArgs dflags Call Old NativeDirectCall actuals updfr_off $+ toCall f Nothing updfr_off 0++mkCallReturnsTo :: DynFlags -> CmmExpr -> Convention -> [CmmExpr]+ -> BlockId+ -> ByteOff+ -> UpdFrameOffset+ -> [CmmExpr]+ -> CmmAGraph+mkCallReturnsTo dflags f callConv actuals ret_lbl ret_off updfr_off extra_stack = do+ lastWithArgsAndExtraStack dflags Call (Young ret_lbl) callConv actuals+ updfr_off extra_stack $+ toCall f (Just ret_lbl) updfr_off ret_off++-- Like mkCallReturnsTo, but does not push the return address (it is assumed to be+-- already on the stack).+mkJumpReturnsTo :: DynFlags -> CmmExpr -> Convention -> [CmmExpr]+ -> BlockId+ -> ByteOff+ -> UpdFrameOffset+ -> CmmAGraph+mkJumpReturnsTo dflags f callConv actuals ret_lbl ret_off updfr_off = do+ lastWithArgs dflags JumpRet (Young ret_lbl) callConv actuals updfr_off $+ toCall f (Just ret_lbl) updfr_off ret_off++mkUnsafeCall :: ForeignTarget -> [CmmFormal] -> [CmmActual] -> CmmAGraph+mkUnsafeCall t fs as = mkMiddle $ CmmUnsafeForeignCall t fs as++-- | Construct a 'CmmUnwind' node for the given register and unwinding+-- expression.+mkUnwind :: GlobalReg -> CmmExpr -> CmmAGraph+mkUnwind r e = mkMiddle $ CmmUnwind [(r, Just e)]++--------------------------------------------------------------------------+++++-- Why are we inserting extra blocks that simply branch to the successors?+-- Because in addition to the branch instruction, @mkBranch@ will insert+-- a necessary adjustment to the stack pointer.+++-- For debugging purposes, we can stub out dead stack slots:+stackStubExpr :: Width -> CmmExpr+stackStubExpr w = CmmLit (CmmInt 0 w)++-- When we copy in parameters, we usually want to put overflow+-- parameters on the stack, but sometimes we want to pass the+-- variables in their spill slots. Therefore, for copying arguments+-- and results, we provide different functions to pass the arguments+-- in an overflow area and to pass them in spill slots.+copyInOflow :: DynFlags -> Convention -> Area+ -> [CmmFormal]+ -> [CmmFormal]+ -> (Int, [GlobalReg], CmmAGraph)++copyInOflow dflags conv area formals extra_stk+ = (offset, gregs, catAGraphs $ map mkMiddle nodes)+ where (offset, gregs, nodes) = copyIn dflags conv area formals extra_stk++-- Return the number of bytes used for copying arguments, as well as the+-- instructions to copy the arguments.+copyIn :: DynFlags -> Convention -> Area+ -> [CmmFormal]+ -> [CmmFormal]+ -> (ByteOff, [GlobalReg], [CmmNode O O])+copyIn dflags conv area formals extra_stk+ = (stk_size, [r | (_, RegisterParam r) <- args], map ci (stk_args ++ args))+ where+ ci (reg, RegisterParam r) =+ CmmAssign (CmmLocal reg) (CmmReg (CmmGlobal r))+ ci (reg, StackParam off) =+ CmmAssign (CmmLocal reg) (CmmLoad (CmmStackSlot area off) ty)+ where ty = localRegType reg++ init_offset = widthInBytes (wordWidth dflags) -- infotable++ (stk_off, stk_args) = assignStack dflags init_offset localRegType extra_stk++ (stk_size, args) = assignArgumentsPos dflags stk_off conv+ localRegType formals++-- Factoring out the common parts of the copyout functions yielded something+-- more complicated:++data Transfer = Call | JumpRet | Jump | Ret deriving Eq++copyOutOflow :: DynFlags -> Convention -> Transfer -> Area -> [CmmExpr]+ -> UpdFrameOffset+ -> [CmmExpr] -- extra stack args+ -> (Int, [GlobalReg], CmmAGraph)++-- Generate code to move the actual parameters into the locations+-- required by the calling convention. This includes a store for the+-- return address.+--+-- The argument layout function ignores the pointer to the info table,+-- so we slot that in here. When copying-out to a young area, we set+-- the info table for return and adjust the offsets of the other+-- parameters. If this is a call instruction, we adjust the offsets+-- of the other parameters.+copyOutOflow dflags conv transfer area actuals updfr_off extra_stack_stuff+ = (stk_size, regs, graph)+ where+ (regs, graph) = foldr co ([], mkNop) (setRA ++ args ++ stack_params)++ co (v, RegisterParam r) (rs, ms)+ = (r:rs, mkAssign (CmmGlobal r) v <*> ms)+ co (v, StackParam off) (rs, ms)+ = (rs, mkStore (CmmStackSlot area off) v <*> ms)++ (setRA, init_offset) =+ case area of+ Young id -> -- Generate a store instruction for+ -- the return address if making a call+ case transfer of+ Call ->+ ([(CmmLit (CmmBlock id), StackParam init_offset)],+ widthInBytes (wordWidth dflags))+ JumpRet ->+ ([],+ widthInBytes (wordWidth dflags))+ _other ->+ ([], 0)+ Old -> ([], updfr_off)++ (extra_stack_off, stack_params) =+ assignStack dflags init_offset (cmmExprType dflags) extra_stack_stuff++ args :: [(CmmExpr, ParamLocation)] -- The argument and where to put it+ (stk_size, args) = assignArgumentsPos dflags extra_stack_off conv+ (cmmExprType dflags) actuals++++mkCallEntry :: DynFlags -> Convention -> [CmmFormal] -> [CmmFormal]+ -> (Int, [GlobalReg], CmmAGraph)+mkCallEntry dflags conv formals extra_stk+ = copyInOflow dflags conv Old formals extra_stk++lastWithArgs :: DynFlags -> Transfer -> Area -> Convention -> [CmmExpr]+ -> UpdFrameOffset+ -> (ByteOff -> [GlobalReg] -> CmmAGraph)+ -> CmmAGraph+lastWithArgs dflags transfer area conv actuals updfr_off last =+ lastWithArgsAndExtraStack dflags transfer area conv actuals+ updfr_off noExtraStack last++lastWithArgsAndExtraStack :: DynFlags+ -> Transfer -> Area -> Convention -> [CmmExpr]+ -> UpdFrameOffset -> [CmmExpr]+ -> (ByteOff -> [GlobalReg] -> CmmAGraph)+ -> CmmAGraph+lastWithArgsAndExtraStack dflags transfer area conv actuals updfr_off+ extra_stack last =+ copies <*> last outArgs regs+ where+ (outArgs, regs, copies) = copyOutOflow dflags conv transfer area actuals+ updfr_off extra_stack+++noExtraStack :: [CmmExpr]+noExtraStack = []++toCall :: CmmExpr -> Maybe BlockId -> UpdFrameOffset -> ByteOff+ -> ByteOff -> [GlobalReg]+ -> CmmAGraph+toCall e cont updfr_off res_space arg_space regs =+ mkLast $ CmmCall e cont regs arg_space res_space updfr_off
+ cmm/PprC.hs view
@@ -0,0 +1,1313 @@+{-# LANGUAGE CPP, GADTs #-}++-----------------------------------------------------------------------------+--+-- Pretty-printing of Cmm as C, suitable for feeding gcc+--+-- (c) The University of Glasgow 2004-2006+--+-- Print Cmm as real C, for -fvia-C+--+-- See wiki:Commentary/Compiler/Backends/PprC+--+-- This is simpler than the old PprAbsC, because Cmm is "macro-expanded"+-- relative to the old AbstractC, and many oddities/decorations have+-- disappeared from the data type.+--+-- This code generator is only supported in unregisterised mode.+--+-----------------------------------------------------------------------------++module PprC (+ writeCs,+ pprStringInCStyle+ ) where++#include "HsVersions.h"++-- Cmm stuff+import BlockId+import CLabel+import ForeignCall+import Cmm hiding (pprBBlock)+import PprCmm ()+import Hoopl+import CmmUtils+import CmmSwitch++-- Utils+import CPrim+import DynFlags+import FastString+import Outputable+import Platform+import UniqSet+import UniqFM+import Unique+import Util++-- The rest+import Control.Monad.ST+import Data.Bits+import Data.Char+import Data.List+import Data.Map (Map)+import Data.Word+import System.IO+import qualified Data.Map as Map+import Control.Monad (liftM, ap)+import qualified Data.Array.Unsafe as U ( castSTUArray )+import Data.Array.ST++-- --------------------------------------------------------------------------+-- Top level++pprCs :: DynFlags -> [RawCmmGroup] -> SDoc+pprCs dflags cmms+ = pprCode CStyle (vcat $ map (\c -> split_marker $$ pprC c) cmms)+ where+ split_marker+ | gopt Opt_SplitObjs dflags = text "__STG_SPLIT_MARKER"+ | otherwise = empty++writeCs :: DynFlags -> Handle -> [RawCmmGroup] -> IO ()+writeCs dflags handle cmms+ = printForC dflags handle (pprCs dflags cmms)++-- --------------------------------------------------------------------------+-- Now do some real work+--+-- for fun, we could call cmmToCmm over the tops...+--++pprC :: RawCmmGroup -> SDoc+pprC tops = vcat $ intersperse blankLine $ map pprTop tops++--+-- top level procs+--+pprTop :: RawCmmDecl -> SDoc+pprTop (CmmProc infos clbl _ graph) =++ (case mapLookup (g_entry graph) infos of+ Nothing -> empty+ Just (Statics info_clbl info_dat) -> pprDataExterns info_dat $$+ pprWordArray info_clbl info_dat) $$+ (vcat [+ blankLine,+ extern_decls,+ (if (externallyVisibleCLabel clbl)+ then mkFN_ else mkIF_) (ppr clbl) <+> lbrace,+ nest 8 temp_decls,+ vcat (map pprBBlock blocks),+ rbrace ]+ )+ where+ blocks = toBlockListEntryFirst graph+ (temp_decls, extern_decls) = pprTempAndExternDecls blocks+++-- Chunks of static data.++-- We only handle (a) arrays of word-sized things and (b) strings.++pprTop (CmmData _section (Statics lbl [CmmString str])) =+ hcat [+ pprLocalness lbl, text "char ", ppr lbl,+ text "[] = ", pprStringInCStyle str, semi+ ]++pprTop (CmmData _section (Statics lbl [CmmUninitialised size])) =+ hcat [+ pprLocalness lbl, text "char ", ppr lbl,+ brackets (int size), semi+ ]++pprTop (CmmData _section (Statics lbl lits)) =+ pprDataExterns lits $$+ pprWordArray lbl lits++-- --------------------------------------------------------------------------+-- BasicBlocks are self-contained entities: they always end in a jump.+--+-- Like nativeGen/AsmCodeGen, we could probably reorder blocks to turn+-- as many jumps as possible into fall throughs.+--++pprBBlock :: CmmBlock -> SDoc+pprBBlock block =+ nest 4 (pprBlockId (entryLabel block) <> colon) $$+ nest 8 (vcat (map pprStmt (blockToList nodes)) $$ pprStmt last)+ where+ (_, nodes, last) = blockSplit block++-- --------------------------------------------------------------------------+-- Info tables. Just arrays of words.+-- See codeGen/ClosureInfo, and nativeGen/PprMach++pprWordArray :: CLabel -> [CmmStatic] -> SDoc+pprWordArray lbl ds+ = sdocWithDynFlags $ \dflags ->+ hcat [ pprLocalness lbl, text "StgWord"+ , space, ppr lbl, text "[]"+ -- See Note [StgWord alignment]+ , pprAlignment (wordWidth dflags)+ , text "= {" ]+ $$ nest 8 (commafy (pprStatics dflags ds))+ $$ text "};"++pprAlignment :: Width -> SDoc+pprAlignment words =+ text "__attribute__((aligned(" <> int (widthInBytes words) <> text ")))"++-- Note [StgWord alignment]+-- C codegen builds static closures as StgWord C arrays (pprWordArray).+-- Their real C type is 'StgClosure'. Macros like UNTAG_CLOSURE assume+-- pointers to 'StgClosure' are aligned at pointer size boundary:+-- 4 byte boundary on 32 systems+-- and 8 bytes on 64-bit systems+-- see TAG_MASK and TAG_BITS definition and usage.+--+-- It's a reasonable assumption also known as natural alignment.+-- Although some architectures have different alignment rules.+-- One of known exceptions is m68k (Trac #11395, comment:16) where:+-- __alignof__(StgWord) == 2, sizeof(StgWord) == 4+--+-- Thus we explicitly increase alignment by using+-- __attribute__((aligned(4)))+-- declaration.++--+-- has to be static, if it isn't globally visible+--+pprLocalness :: CLabel -> SDoc+pprLocalness lbl | not $ externallyVisibleCLabel lbl = text "static "+ | otherwise = empty++-- --------------------------------------------------------------------------+-- Statements.+--++pprStmt :: CmmNode e x -> SDoc++pprStmt stmt =+ sdocWithDynFlags $ \dflags ->+ case stmt of+ CmmEntry{} -> empty+ CmmComment _ -> empty -- (hang (text "/*") 3 (ftext s)) $$ ptext (sLit "*/")+ -- XXX if the string contains "*/", we need to fix it+ -- XXX we probably want to emit these comments when+ -- some debugging option is on. They can get quite+ -- large.++ CmmTick _ -> empty+ CmmUnwind{} -> empty++ CmmAssign dest src -> pprAssign dflags dest src++ CmmStore dest src+ | typeWidth rep == W64 && wordWidth dflags /= W64+ -> (if isFloatType rep then text "ASSIGN_DBL"+ else ptext (sLit ("ASSIGN_Word64"))) <>+ parens (mkP_ <> pprExpr1 dest <> comma <> pprExpr src) <> semi++ | otherwise+ -> hsep [ pprExpr (CmmLoad dest rep), equals, pprExpr src <> semi ]+ where+ rep = cmmExprType dflags src++ CmmUnsafeForeignCall target@(ForeignTarget fn conv) results args ->+ fnCall+ where+ (res_hints, arg_hints) = foreignTargetHints target+ hresults = zip results res_hints+ hargs = zip args arg_hints++ ForeignConvention cconv _ _ ret = conv++ cast_fn = parens (cCast (pprCFunType (char '*') cconv hresults hargs) fn)++ -- See wiki:Commentary/Compiler/Backends/PprC#Prototypes+ fnCall =+ case fn of+ CmmLit (CmmLabel lbl)+ | StdCallConv <- cconv ->+ pprCall (ppr lbl) cconv hresults hargs+ -- stdcall functions must be declared with+ -- a function type, otherwise the C compiler+ -- doesn't add the @n suffix to the label. We+ -- can't add the @n suffix ourselves, because+ -- it isn't valid C.+ | CmmNeverReturns <- ret ->+ pprCall cast_fn cconv hresults hargs <> semi+ | not (isMathFun lbl) ->+ pprForeignCall (ppr lbl) cconv hresults hargs+ _ ->+ pprCall cast_fn cconv hresults hargs <> semi+ -- for a dynamic call, no declaration is necessary.++ CmmUnsafeForeignCall (PrimTarget MO_Touch) _results _args -> empty+ CmmUnsafeForeignCall (PrimTarget (MO_Prefetch_Data _)) _results _args -> empty++ CmmUnsafeForeignCall target@(PrimTarget op) results args ->+ fn_call+ where+ cconv = CCallConv+ fn = pprCallishMachOp_for_C op++ (res_hints, arg_hints) = foreignTargetHints target+ hresults = zip results res_hints+ hargs = zip args arg_hints++ fn_call+ -- The mem primops carry an extra alignment arg.+ -- We could maybe emit an alignment directive using this info.+ -- We also need to cast mem primops to prevent conflicts with GCC+ -- builtins (see bug #5967).+ | Just _align <- machOpMemcpyishAlign op+ = (text ";EFF_(" <> fn <> char ')' <> semi) $$+ pprForeignCall fn cconv hresults hargs+ | otherwise+ = pprCall fn cconv hresults hargs++ CmmBranch ident -> pprBranch ident+ CmmCondBranch expr yes no _ -> pprCondBranch expr yes no+ CmmCall { cml_target = expr } -> mkJMP_ (pprExpr expr) <> semi+ CmmSwitch arg ids -> sdocWithDynFlags $ \dflags ->+ pprSwitch dflags arg ids++ _other -> pprPanic "PprC.pprStmt" (ppr stmt)++type Hinted a = (a, ForeignHint)++pprForeignCall :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual]+ -> SDoc+pprForeignCall fn cconv results args = fn_call+ where+ fn_call = braces (+ pprCFunType (char '*' <> text "ghcFunPtr") cconv results args <> semi+ $$ text "ghcFunPtr" <+> equals <+> cast_fn <> semi+ $$ pprCall (text "ghcFunPtr") cconv results args <> semi+ )+ cast_fn = parens (parens (pprCFunType (char '*') cconv results args) <> fn)++pprCFunType :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc+pprCFunType ppr_fn cconv ress args+ = sdocWithDynFlags $ \dflags ->+ let res_type [] = text "void"+ res_type [(one, hint)] = machRepHintCType (localRegType one) hint+ res_type _ = panic "pprCFunType: only void or 1 return value supported"++ arg_type (expr, hint) = machRepHintCType (cmmExprType dflags expr) hint+ in res_type ress <+>+ parens (ccallConvAttribute cconv <> ppr_fn) <>+ parens (commafy (map arg_type args))++-- ---------------------------------------------------------------------+-- unconditional branches+pprBranch :: BlockId -> SDoc+pprBranch ident = text "goto" <+> pprBlockId ident <> semi+++-- ---------------------------------------------------------------------+-- conditional branches to local labels+pprCondBranch :: CmmExpr -> BlockId -> BlockId -> SDoc+pprCondBranch expr yes no+ = hsep [ text "if" , parens(pprExpr expr) ,+ text "goto", pprBlockId yes <> semi,+ text "else goto", pprBlockId no <> semi ]++-- ---------------------------------------------------------------------+-- a local table branch+--+-- we find the fall-through cases+--+pprSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> SDoc+pprSwitch dflags e ids+ = (hang (text "switch" <+> parens ( pprExpr e ) <+> lbrace)+ 4 (vcat ( map caseify pairs ) $$ def)) $$ rbrace+ where+ (pairs, mbdef) = switchTargetsFallThrough ids++ -- fall through case+ caseify (ix:ixs, ident) = vcat (map do_fallthrough ixs) $$ final_branch ix+ where+ do_fallthrough ix =+ hsep [ text "case" , pprHexVal ix (wordWidth dflags) <> colon ,+ text "/* fall through */" ]++ final_branch ix =+ hsep [ text "case" , pprHexVal ix (wordWidth dflags) <> colon ,+ text "goto" , (pprBlockId ident) <> semi ]++ caseify (_ , _ ) = panic "pprSwitch: switch with no cases!"++ def | Just l <- mbdef = text "default: goto" <+> pprBlockId l <> semi+ | otherwise = empty++-- ---------------------------------------------------------------------+-- Expressions.+--++-- C Types: the invariant is that the C expression generated by+--+-- pprExpr e+--+-- has a type in C which is also given by+--+-- machRepCType (cmmExprType e)+--+-- (similar invariants apply to the rest of the pretty printer).++pprExpr :: CmmExpr -> SDoc+pprExpr e = case e of+ CmmLit lit -> pprLit lit+++ CmmLoad e ty -> sdocWithDynFlags $ \dflags -> pprLoad dflags e ty+ CmmReg reg -> pprCastReg reg+ CmmRegOff reg 0 -> pprCastReg reg++ CmmRegOff reg i+ | i < 0 && negate_ok -> pprRegOff (char '-') (-i)+ | otherwise -> pprRegOff (char '+') i+ where+ pprRegOff op i' = pprCastReg reg <> op <> int i'+ negate_ok = negate (fromIntegral i :: Integer) <+ fromIntegral (maxBound::Int)+ -- overflow is undefined; see #7620++ CmmMachOp mop args -> pprMachOpApp mop args++ CmmStackSlot _ _ -> panic "pprExpr: CmmStackSlot not supported!"+++pprLoad :: DynFlags -> CmmExpr -> CmmType -> SDoc+pprLoad dflags e ty+ | width == W64, wordWidth dflags /= W64+ = (if isFloatType ty then text "PK_DBL"+ else text "PK_Word64")+ <> parens (mkP_ <> pprExpr1 e)++ | otherwise+ = case e of+ CmmReg r | isPtrReg r && width == wordWidth dflags && not (isFloatType ty)+ -> char '*' <> pprAsPtrReg r++ CmmRegOff r 0 | isPtrReg r && width == wordWidth dflags && not (isFloatType ty)+ -> char '*' <> pprAsPtrReg r++ CmmRegOff r off | isPtrReg r && width == wordWidth dflags+ , off `rem` wORD_SIZE dflags == 0 && not (isFloatType ty)+ -- ToDo: check that the offset is a word multiple?+ -- (For tagging to work, I had to avoid unaligned loads. --ARY)+ -> pprAsPtrReg r <> brackets (ppr (off `shiftR` wordShift dflags))++ _other -> cLoad e ty+ where+ width = typeWidth ty++pprExpr1 :: CmmExpr -> SDoc+pprExpr1 (CmmLit lit) = pprLit1 lit+pprExpr1 e@(CmmReg _reg) = pprExpr e+pprExpr1 other = parens (pprExpr other)++-- --------------------------------------------------------------------------+-- MachOp applications++pprMachOpApp :: MachOp -> [CmmExpr] -> SDoc++pprMachOpApp op args+ | isMulMayOfloOp op+ = text "mulIntMayOflo" <> parens (commafy (map pprExpr args))+ where isMulMayOfloOp (MO_U_MulMayOflo _) = True+ isMulMayOfloOp (MO_S_MulMayOflo _) = True+ isMulMayOfloOp _ = False++pprMachOpApp mop args+ | Just ty <- machOpNeedsCast mop+ = ty <> parens (pprMachOpApp' mop args)+ | otherwise+ = pprMachOpApp' mop args++-- Comparisons in C have type 'int', but we want type W_ (this is what+-- resultRepOfMachOp says). The other C operations inherit their type+-- from their operands, so no casting is required.+machOpNeedsCast :: MachOp -> Maybe SDoc+machOpNeedsCast mop+ | isComparisonMachOp mop = Just mkW_+ | otherwise = Nothing++pprMachOpApp' :: MachOp -> [CmmExpr] -> SDoc+pprMachOpApp' mop args+ = case args of+ -- dyadic+ [x,y] -> pprArg x <+> pprMachOp_for_C mop <+> pprArg y++ -- unary+ [x] -> pprMachOp_for_C mop <> parens (pprArg x)++ _ -> panic "PprC.pprMachOp : machop with wrong number of args"++ where+ -- Cast needed for signed integer ops+ pprArg e | signedOp mop = sdocWithDynFlags $ \dflags ->+ cCast (machRep_S_CType (typeWidth (cmmExprType dflags e))) e+ | needsFCasts mop = sdocWithDynFlags $ \dflags ->+ cCast (machRep_F_CType (typeWidth (cmmExprType dflags e))) e+ | otherwise = pprExpr1 e+ needsFCasts (MO_F_Eq _) = False+ needsFCasts (MO_F_Ne _) = False+ needsFCasts (MO_F_Neg _) = True+ needsFCasts (MO_F_Quot _) = True+ needsFCasts mop = floatComparison mop++-- --------------------------------------------------------------------------+-- Literals++pprLit :: CmmLit -> SDoc+pprLit lit = case lit of+ CmmInt i rep -> pprHexVal i rep++ CmmFloat f w -> parens (machRep_F_CType w) <> str+ where d = fromRational f :: Double+ str | isInfinite d && d < 0 = text "-INFINITY"+ | isInfinite d = text "INFINITY"+ | isNaN d = text "NAN"+ | otherwise = text (show d)+ -- these constants come from <math.h>+ -- see #1861++ CmmVec {} -> panic "PprC printing vector literal"++ CmmBlock bid -> mkW_ <> pprCLabelAddr (infoTblLbl bid)+ CmmHighStackMark -> panic "PprC printing high stack mark"+ CmmLabel clbl -> mkW_ <> pprCLabelAddr clbl+ CmmLabelOff clbl i -> mkW_ <> pprCLabelAddr clbl <> char '+' <> int i+ CmmLabelDiffOff clbl1 _ i+ -- WARNING:+ -- * the lit must occur in the info table clbl2+ -- * clbl1 must be an SRT, a slow entry point or a large bitmap+ -> mkW_ <> pprCLabelAddr clbl1 <> char '+' <> int i++ where+ pprCLabelAddr lbl = char '&' <> ppr lbl++pprLit1 :: CmmLit -> SDoc+pprLit1 lit@(CmmLabelOff _ _) = parens (pprLit lit)+pprLit1 lit@(CmmLabelDiffOff _ _ _) = parens (pprLit lit)+pprLit1 lit@(CmmFloat _ _) = parens (pprLit lit)+pprLit1 other = pprLit other++-- ---------------------------------------------------------------------------+-- Static data++pprStatics :: DynFlags -> [CmmStatic] -> [SDoc]+pprStatics _ [] = []+pprStatics dflags (CmmStaticLit (CmmFloat f W32) : rest)+ -- floats are padded to a word by padLitToWord, see #1852+ | wORD_SIZE dflags == 8, CmmStaticLit (CmmInt 0 W32) : rest' <- rest+ = pprLit1 (floatToWord dflags f) : pprStatics dflags rest'+ | wORD_SIZE dflags == 4+ = pprLit1 (floatToWord dflags f) : pprStatics dflags rest+ | otherwise+ = pprPanic "pprStatics: float" (vcat (map ppr' rest))+ where ppr' (CmmStaticLit l) = sdocWithDynFlags $ \dflags ->+ ppr (cmmLitType dflags l)+ ppr' _other = text "bad static!"+pprStatics dflags (CmmStaticLit (CmmFloat f W64) : rest)+ = map pprLit1 (doubleToWords dflags f) ++ pprStatics dflags rest++pprStatics dflags (CmmStaticLit (CmmInt i W64) : rest)+ | wordWidth dflags == W32+ = if wORDS_BIGENDIAN dflags+ then pprStatics dflags (CmmStaticLit (CmmInt q W32) :+ CmmStaticLit (CmmInt r W32) : rest)+ else pprStatics dflags (CmmStaticLit (CmmInt r W32) :+ CmmStaticLit (CmmInt q W32) : rest)+ where r = i .&. 0xffffffff+ q = i `shiftR` 32+pprStatics dflags (CmmStaticLit (CmmInt _ w) : _)+ | w /= wordWidth dflags+ = panic "pprStatics: cannot emit a non-word-sized static literal"+pprStatics dflags (CmmStaticLit lit : rest)+ = pprLit1 lit : pprStatics dflags rest+pprStatics _ (other : _)+ = pprPanic "pprWord" (pprStatic other)++pprStatic :: CmmStatic -> SDoc+pprStatic s = case s of++ CmmStaticLit lit -> nest 4 (pprLit lit)+ CmmUninitialised i -> nest 4 (mkC_ <> brackets (int i))++ -- these should be inlined, like the old .hc+ CmmString s' -> nest 4 (mkW_ <> parens(pprStringInCStyle s'))+++-- ---------------------------------------------------------------------------+-- Block Ids++pprBlockId :: BlockId -> SDoc+pprBlockId b = char '_' <> ppr (getUnique b)++-- --------------------------------------------------------------------------+-- Print a MachOp in a way suitable for emitting via C.+--++pprMachOp_for_C :: MachOp -> SDoc++pprMachOp_for_C mop = case mop of++ -- Integer operations+ MO_Add _ -> char '+'+ MO_Sub _ -> char '-'+ MO_Eq _ -> text "=="+ MO_Ne _ -> text "!="+ MO_Mul _ -> char '*'++ MO_S_Quot _ -> char '/'+ MO_S_Rem _ -> char '%'+ MO_S_Neg _ -> char '-'++ MO_U_Quot _ -> char '/'+ MO_U_Rem _ -> char '%'++ -- & Floating-point operations+ MO_F_Add _ -> char '+'+ MO_F_Sub _ -> char '-'+ MO_F_Neg _ -> char '-'+ MO_F_Mul _ -> char '*'+ MO_F_Quot _ -> char '/'++ -- Signed comparisons+ MO_S_Ge _ -> text ">="+ MO_S_Le _ -> text "<="+ MO_S_Gt _ -> char '>'+ MO_S_Lt _ -> char '<'++ -- & Unsigned comparisons+ MO_U_Ge _ -> text ">="+ MO_U_Le _ -> text "<="+ MO_U_Gt _ -> char '>'+ MO_U_Lt _ -> char '<'++ -- & Floating-point comparisons+ MO_F_Eq _ -> text "=="+ MO_F_Ne _ -> text "!="+ MO_F_Ge _ -> text ">="+ MO_F_Le _ -> text "<="+ MO_F_Gt _ -> char '>'+ MO_F_Lt _ -> char '<'++ -- Bitwise operations. Not all of these may be supported at all+ -- sizes, and only integral MachReps are valid.+ MO_And _ -> char '&'+ MO_Or _ -> char '|'+ MO_Xor _ -> char '^'+ MO_Not _ -> char '~'+ MO_Shl _ -> text "<<"+ MO_U_Shr _ -> text ">>" -- unsigned shift right+ MO_S_Shr _ -> text ">>" -- signed shift right++-- Conversions. Some of these will be NOPs, but never those that convert+-- between ints and floats.+-- Floating-point conversions use the signed variant.+-- We won't know to generate (void*) casts here, but maybe from+-- context elsewhere++-- noop casts+ MO_UU_Conv from to | from == to -> empty+ MO_UU_Conv _from to -> parens (machRep_U_CType to)++ MO_SS_Conv from to | from == to -> empty+ MO_SS_Conv _from to -> parens (machRep_S_CType to)++ MO_FF_Conv from to | from == to -> empty+ MO_FF_Conv _from to -> parens (machRep_F_CType to)++ MO_SF_Conv _from to -> parens (machRep_F_CType to)+ MO_FS_Conv _from to -> parens (machRep_S_CType to)++ MO_S_MulMayOflo _ -> pprTrace "offending mop:"+ (text "MO_S_MulMayOflo")+ (panic $ "PprC.pprMachOp_for_C: MO_S_MulMayOflo"+ ++ " should have been handled earlier!")+ MO_U_MulMayOflo _ -> pprTrace "offending mop:"+ (text "MO_U_MulMayOflo")+ (panic $ "PprC.pprMachOp_for_C: MO_U_MulMayOflo"+ ++ " should have been handled earlier!")++ MO_V_Insert {} -> pprTrace "offending mop:"+ (text "MO_V_Insert")+ (panic $ "PprC.pprMachOp_for_C: MO_V_Insert"+ ++ " should have been handled earlier!")+ MO_V_Extract {} -> pprTrace "offending mop:"+ (text "MO_V_Extract")+ (panic $ "PprC.pprMachOp_for_C: MO_V_Extract"+ ++ " should have been handled earlier!")++ MO_V_Add {} -> pprTrace "offending mop:"+ (text "MO_V_Add")+ (panic $ "PprC.pprMachOp_for_C: MO_V_Add"+ ++ " should have been handled earlier!")+ MO_V_Sub {} -> pprTrace "offending mop:"+ (text "MO_V_Sub")+ (panic $ "PprC.pprMachOp_for_C: MO_V_Sub"+ ++ " should have been handled earlier!")+ MO_V_Mul {} -> pprTrace "offending mop:"+ (text "MO_V_Mul")+ (panic $ "PprC.pprMachOp_for_C: MO_V_Mul"+ ++ " should have been handled earlier!")++ MO_VS_Quot {} -> pprTrace "offending mop:"+ (text "MO_VS_Quot")+ (panic $ "PprC.pprMachOp_for_C: MO_VS_Quot"+ ++ " should have been handled earlier!")+ MO_VS_Rem {} -> pprTrace "offending mop:"+ (text "MO_VS_Rem")+ (panic $ "PprC.pprMachOp_for_C: MO_VS_Rem"+ ++ " should have been handled earlier!")+ MO_VS_Neg {} -> pprTrace "offending mop:"+ (text "MO_VS_Neg")+ (panic $ "PprC.pprMachOp_for_C: MO_VS_Neg"+ ++ " should have been handled earlier!")++ MO_VU_Quot {} -> pprTrace "offending mop:"+ (text "MO_VU_Quot")+ (panic $ "PprC.pprMachOp_for_C: MO_VU_Quot"+ ++ " should have been handled earlier!")+ MO_VU_Rem {} -> pprTrace "offending mop:"+ (text "MO_VU_Rem")+ (panic $ "PprC.pprMachOp_for_C: MO_VU_Rem"+ ++ " should have been handled earlier!")++ MO_VF_Insert {} -> pprTrace "offending mop:"+ (text "MO_VF_Insert")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Insert"+ ++ " should have been handled earlier!")+ MO_VF_Extract {} -> pprTrace "offending mop:"+ (text "MO_VF_Extract")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Extract"+ ++ " should have been handled earlier!")++ MO_VF_Add {} -> pprTrace "offending mop:"+ (text "MO_VF_Add")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Add"+ ++ " should have been handled earlier!")+ MO_VF_Sub {} -> pprTrace "offending mop:"+ (text "MO_VF_Sub")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Sub"+ ++ " should have been handled earlier!")+ MO_VF_Neg {} -> pprTrace "offending mop:"+ (text "MO_VF_Neg")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Neg"+ ++ " should have been handled earlier!")+ MO_VF_Mul {} -> pprTrace "offending mop:"+ (text "MO_VF_Mul")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Mul"+ ++ " should have been handled earlier!")+ MO_VF_Quot {} -> pprTrace "offending mop:"+ (text "MO_VF_Quot")+ (panic $ "PprC.pprMachOp_for_C: MO_VF_Quot"+ ++ " should have been handled earlier!")++signedOp :: MachOp -> Bool -- Argument type(s) are signed ints+signedOp (MO_S_Quot _) = True+signedOp (MO_S_Rem _) = True+signedOp (MO_S_Neg _) = True+signedOp (MO_S_Ge _) = True+signedOp (MO_S_Le _) = True+signedOp (MO_S_Gt _) = True+signedOp (MO_S_Lt _) = True+signedOp (MO_S_Shr _) = True+signedOp (MO_SS_Conv _ _) = True+signedOp (MO_SF_Conv _ _) = True+signedOp _ = False++floatComparison :: MachOp -> Bool -- comparison between float args+floatComparison (MO_F_Eq _) = True+floatComparison (MO_F_Ne _) = True+floatComparison (MO_F_Ge _) = True+floatComparison (MO_F_Le _) = True+floatComparison (MO_F_Gt _) = True+floatComparison (MO_F_Lt _) = True+floatComparison _ = False++-- ---------------------------------------------------------------------+-- tend to be implemented by foreign calls++pprCallishMachOp_for_C :: CallishMachOp -> SDoc++pprCallishMachOp_for_C mop+ = case mop of+ MO_F64_Pwr -> text "pow"+ MO_F64_Sin -> text "sin"+ MO_F64_Cos -> text "cos"+ MO_F64_Tan -> text "tan"+ MO_F64_Sinh -> text "sinh"+ MO_F64_Cosh -> text "cosh"+ MO_F64_Tanh -> text "tanh"+ MO_F64_Asin -> text "asin"+ MO_F64_Acos -> text "acos"+ MO_F64_Atan -> text "atan"+ MO_F64_Log -> text "log"+ MO_F64_Exp -> text "exp"+ MO_F64_Sqrt -> text "sqrt"+ MO_F64_Fabs -> text "fabs"+ MO_F32_Pwr -> text "powf"+ MO_F32_Sin -> text "sinf"+ MO_F32_Cos -> text "cosf"+ MO_F32_Tan -> text "tanf"+ MO_F32_Sinh -> text "sinhf"+ MO_F32_Cosh -> text "coshf"+ MO_F32_Tanh -> text "tanhf"+ MO_F32_Asin -> text "asinf"+ MO_F32_Acos -> text "acosf"+ MO_F32_Atan -> text "atanf"+ MO_F32_Log -> text "logf"+ MO_F32_Exp -> text "expf"+ MO_F32_Sqrt -> text "sqrtf"+ MO_F32_Fabs -> text "fabsf"+ MO_WriteBarrier -> text "write_barrier"+ MO_Memcpy _ -> text "memcpy"+ MO_Memset _ -> text "memset"+ MO_Memmove _ -> text "memmove"+ (MO_BSwap w) -> ptext (sLit $ bSwapLabel w)+ (MO_PopCnt w) -> ptext (sLit $ popCntLabel w)+ (MO_Clz w) -> ptext (sLit $ clzLabel w)+ (MO_Ctz w) -> ptext (sLit $ ctzLabel w)+ (MO_AtomicRMW w amop) -> ptext (sLit $ atomicRMWLabel w amop)+ (MO_Cmpxchg w) -> ptext (sLit $ cmpxchgLabel w)+ (MO_AtomicRead w) -> ptext (sLit $ atomicReadLabel w)+ (MO_AtomicWrite w) -> ptext (sLit $ atomicWriteLabel w)+ (MO_UF_Conv w) -> ptext (sLit $ word2FloatLabel w)++ MO_S_QuotRem {} -> unsupported+ MO_U_QuotRem {} -> unsupported+ MO_U_QuotRem2 {} -> unsupported+ MO_Add2 {} -> unsupported+ MO_SubWordC {} -> unsupported+ MO_AddIntC {} -> unsupported+ MO_SubIntC {} -> unsupported+ MO_U_Mul2 {} -> unsupported+ MO_Touch -> unsupported+ (MO_Prefetch_Data _ ) -> unsupported+ --- we could support prefetch via "__builtin_prefetch"+ --- Not adding it for now+ where unsupported = panic ("pprCallishMachOp_for_C: " ++ show mop+ ++ " not supported!")++-- ---------------------------------------------------------------------+-- Useful #defines+--++mkJMP_, mkFN_, mkIF_ :: SDoc -> SDoc++mkJMP_ i = text "JMP_" <> parens i+mkFN_ i = text "FN_" <> parens i -- externally visible function+mkIF_ i = text "IF_" <> parens i -- locally visible++-- from includes/Stg.h+--+mkC_,mkW_,mkP_ :: SDoc++mkC_ = text "(C_)" -- StgChar+mkW_ = text "(W_)" -- StgWord+mkP_ = text "(P_)" -- StgWord*++-- ---------------------------------------------------------------------+--+-- Assignments+--+-- Generating assignments is what we're all about, here+--+pprAssign :: DynFlags -> CmmReg -> CmmExpr -> SDoc++-- dest is a reg, rhs is a reg+pprAssign _ r1 (CmmReg r2)+ | isPtrReg r1 && isPtrReg r2+ = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, semi ]++-- dest is a reg, rhs is a CmmRegOff+pprAssign dflags r1 (CmmRegOff r2 off)+ | isPtrReg r1 && isPtrReg r2 && (off `rem` wORD_SIZE dflags == 0)+ = hcat [ pprAsPtrReg r1, equals, pprAsPtrReg r2, op, int off', semi ]+ where+ off1 = off `shiftR` wordShift dflags++ (op,off') | off >= 0 = (char '+', off1)+ | otherwise = (char '-', -off1)++-- dest is a reg, rhs is anything.+-- We can't cast the lvalue, so we have to cast the rhs if necessary. Casting+-- the lvalue elicits a warning from new GCC versions (3.4+).+pprAssign _ r1 r2+ | isFixedPtrReg r1 = mkAssign (mkP_ <> pprExpr1 r2)+ | Just ty <- strangeRegType r1 = mkAssign (parens ty <> pprExpr1 r2)+ | otherwise = mkAssign (pprExpr r2)+ where mkAssign x = if r1 == CmmGlobal BaseReg+ then text "ASSIGN_BaseReg" <> parens x <> semi+ else pprReg r1 <> text " = " <> x <> semi++-- ---------------------------------------------------------------------+-- Registers++pprCastReg :: CmmReg -> SDoc+pprCastReg reg+ | isStrangeTypeReg reg = mkW_ <> pprReg reg+ | otherwise = pprReg reg++-- True if (pprReg reg) will give an expression with type StgPtr. We+-- need to take care with pointer arithmetic on registers with type+-- StgPtr.+isFixedPtrReg :: CmmReg -> Bool+isFixedPtrReg (CmmLocal _) = False+isFixedPtrReg (CmmGlobal r) = isFixedPtrGlobalReg r++-- True if (pprAsPtrReg reg) will give an expression with type StgPtr+-- JD: THIS IS HORRIBLE AND SHOULD BE RENAMED, AT THE VERY LEAST.+-- THE GARBAGE WITH THE VNonGcPtr HELPS MATCH THE OLD CODE GENERATOR'S OUTPUT;+-- I'M NOT SURE IF IT SHOULD REALLY STAY THAT WAY.+isPtrReg :: CmmReg -> Bool+isPtrReg (CmmLocal _) = False+isPtrReg (CmmGlobal (VanillaReg _ VGcPtr)) = True -- if we print via pprAsPtrReg+isPtrReg (CmmGlobal (VanillaReg _ VNonGcPtr)) = False -- if we print via pprAsPtrReg+isPtrReg (CmmGlobal reg) = isFixedPtrGlobalReg reg++-- True if this global reg has type StgPtr+isFixedPtrGlobalReg :: GlobalReg -> Bool+isFixedPtrGlobalReg Sp = True+isFixedPtrGlobalReg Hp = True+isFixedPtrGlobalReg HpLim = True+isFixedPtrGlobalReg SpLim = True+isFixedPtrGlobalReg _ = False++-- True if in C this register doesn't have the type given by+-- (machRepCType (cmmRegType reg)), so it has to be cast.+isStrangeTypeReg :: CmmReg -> Bool+isStrangeTypeReg (CmmLocal _) = False+isStrangeTypeReg (CmmGlobal g) = isStrangeTypeGlobal g++isStrangeTypeGlobal :: GlobalReg -> Bool+isStrangeTypeGlobal CCCS = True+isStrangeTypeGlobal CurrentTSO = True+isStrangeTypeGlobal CurrentNursery = True+isStrangeTypeGlobal BaseReg = True+isStrangeTypeGlobal r = isFixedPtrGlobalReg r++strangeRegType :: CmmReg -> Maybe SDoc+strangeRegType (CmmGlobal CCCS) = Just (text "struct CostCentreStack_ *")+strangeRegType (CmmGlobal CurrentTSO) = Just (text "struct StgTSO_ *")+strangeRegType (CmmGlobal CurrentNursery) = Just (text "struct bdescr_ *")+strangeRegType (CmmGlobal BaseReg) = Just (text "struct StgRegTable_ *")+strangeRegType _ = Nothing++-- pprReg just prints the register name.+--+pprReg :: CmmReg -> SDoc+pprReg r = case r of+ CmmLocal local -> pprLocalReg local+ CmmGlobal global -> pprGlobalReg global++pprAsPtrReg :: CmmReg -> SDoc+pprAsPtrReg (CmmGlobal (VanillaReg n gcp))+ = WARN( gcp /= VGcPtr, ppr n ) char 'R' <> int n <> text ".p"+pprAsPtrReg other_reg = pprReg other_reg++pprGlobalReg :: GlobalReg -> SDoc+pprGlobalReg gr = case gr of+ VanillaReg n _ -> char 'R' <> int n <> text ".w"+ -- pprGlobalReg prints a VanillaReg as a .w regardless+ -- Example: R1.w = R1.w & (-0x8UL);+ -- JMP_(*R1.p);+ FloatReg n -> char 'F' <> int n+ DoubleReg n -> char 'D' <> int n+ LongReg n -> char 'L' <> int n+ Sp -> text "Sp"+ SpLim -> text "SpLim"+ Hp -> text "Hp"+ HpLim -> text "HpLim"+ CCCS -> text "CCCS"+ CurrentTSO -> text "CurrentTSO"+ CurrentNursery -> text "CurrentNursery"+ HpAlloc -> text "HpAlloc"+ BaseReg -> text "BaseReg"+ EagerBlackholeInfo -> text "stg_EAGER_BLACKHOLE_info"+ GCEnter1 -> text "stg_gc_enter_1"+ GCFun -> text "stg_gc_fun"+ other -> panic $ "pprGlobalReg: Unsupported register: " ++ show other++pprLocalReg :: LocalReg -> SDoc+pprLocalReg (LocalReg uniq _) = char '_' <> ppr uniq++-- -----------------------------------------------------------------------------+-- Foreign Calls++pprCall :: SDoc -> CCallConv -> [Hinted CmmFormal] -> [Hinted CmmActual] -> SDoc+pprCall ppr_fn cconv results args+ | not (is_cishCC cconv)+ = panic $ "pprCall: unknown calling convention"++ | otherwise+ =+ ppr_assign results (ppr_fn <> parens (commafy (map pprArg args))) <> semi+ where+ ppr_assign [] rhs = rhs+ ppr_assign [(one,hint)] rhs+ = pprLocalReg one <> text " = "+ <> pprUnHint hint (localRegType one) <> rhs+ ppr_assign _other _rhs = panic "pprCall: multiple results"++ pprArg (expr, AddrHint)+ = cCast (text "void *") expr+ -- see comment by machRepHintCType below+ pprArg (expr, SignedHint)+ = sdocWithDynFlags $ \dflags ->+ cCast (machRep_S_CType $ typeWidth $ cmmExprType dflags expr) expr+ pprArg (expr, _other)+ = pprExpr expr++ pprUnHint AddrHint rep = parens (machRepCType rep)+ pprUnHint SignedHint rep = parens (machRepCType rep)+ pprUnHint _ _ = empty++-- Currently we only have these two calling conventions, but this might+-- change in the future...+is_cishCC :: CCallConv -> Bool+is_cishCC CCallConv = True+is_cishCC CApiConv = True+is_cishCC StdCallConv = True+is_cishCC PrimCallConv = False+is_cishCC JavaScriptCallConv = False++-- ---------------------------------------------------------------------+-- Find and print local and external declarations for a list of+-- Cmm statements.+--+pprTempAndExternDecls :: [CmmBlock] -> (SDoc{-temps-}, SDoc{-externs-})+pprTempAndExternDecls stmts+ = (pprUFM (getUniqSet temps) (vcat . map pprTempDecl),+ vcat (map (pprExternDecl False{-ToDo-}) (Map.keys lbls)))+ where (temps, lbls) = runTE (mapM_ te_BB stmts)++pprDataExterns :: [CmmStatic] -> SDoc+pprDataExterns statics+ = vcat (map (pprExternDecl False{-ToDo-}) (Map.keys lbls))+ where (_, lbls) = runTE (mapM_ te_Static statics)++pprTempDecl :: LocalReg -> SDoc+pprTempDecl l@(LocalReg _ rep)+ = hcat [ machRepCType rep, space, pprLocalReg l, semi ]++pprExternDecl :: Bool -> CLabel -> SDoc+pprExternDecl _in_srt lbl+ -- do not print anything for "known external" things+ | not (needsCDecl lbl) = empty+ | Just sz <- foreignLabelStdcallInfo lbl = stdcall_decl sz+ | otherwise =+ hcat [ visibility, label_type lbl,+ lparen, ppr lbl, text ");" ]+ where+ label_type lbl | isBytesLabel lbl = text "B_"+ | isForeignLabel lbl && isCFunctionLabel lbl = text "FF_"+ | isCFunctionLabel lbl = text "F_"+ | otherwise = text "I_"++ visibility+ | externallyVisibleCLabel lbl = char 'E'+ | otherwise = char 'I'++ -- If the label we want to refer to is a stdcall function (on Windows) then+ -- we must generate an appropriate prototype for it, so that the C compiler will+ -- add the @n suffix to the label (#2276)+ stdcall_decl sz = sdocWithDynFlags $ \dflags ->+ text "extern __attribute__((stdcall)) void " <> ppr lbl+ <> parens (commafy (replicate (sz `quot` wORD_SIZE dflags) (machRep_U_CType (wordWidth dflags))))+ <> semi++type TEState = (UniqSet LocalReg, Map CLabel ())+newtype TE a = TE { unTE :: TEState -> (a, TEState) }++instance Functor TE where+ fmap = liftM++instance Applicative TE where+ pure a = TE $ \s -> (a, s)+ (<*>) = ap++instance Monad TE where+ TE m >>= k = TE $ \s -> case m s of (a, s') -> unTE (k a) s'++te_lbl :: CLabel -> TE ()+te_lbl lbl = TE $ \(temps,lbls) -> ((), (temps, Map.insert lbl () lbls))++te_temp :: LocalReg -> TE ()+te_temp r = TE $ \(temps,lbls) -> ((), (addOneToUniqSet temps r, lbls))++runTE :: TE () -> TEState+runTE (TE m) = snd (m (emptyUniqSet, Map.empty))++te_Static :: CmmStatic -> TE ()+te_Static (CmmStaticLit lit) = te_Lit lit+te_Static _ = return ()++te_BB :: CmmBlock -> TE ()+te_BB block = mapM_ te_Stmt (blockToList mid) >> te_Stmt last+ where (_, mid, last) = blockSplit block++te_Lit :: CmmLit -> TE ()+te_Lit (CmmLabel l) = te_lbl l+te_Lit (CmmLabelOff l _) = te_lbl l+te_Lit (CmmLabelDiffOff l1 _ _) = te_lbl l1+te_Lit _ = return ()++te_Stmt :: CmmNode e x -> TE ()+te_Stmt (CmmAssign r e) = te_Reg r >> te_Expr e+te_Stmt (CmmStore l r) = te_Expr l >> te_Expr r+te_Stmt (CmmUnsafeForeignCall target rs es)+ = do te_Target target+ mapM_ te_temp rs+ mapM_ te_Expr es+te_Stmt (CmmCondBranch e _ _ _) = te_Expr e+te_Stmt (CmmSwitch e _) = te_Expr e+te_Stmt (CmmCall { cml_target = e }) = te_Expr e+te_Stmt _ = return ()++te_Target :: ForeignTarget -> TE ()+te_Target (ForeignTarget e _) = te_Expr e+te_Target (PrimTarget{}) = return ()++te_Expr :: CmmExpr -> TE ()+te_Expr (CmmLit lit) = te_Lit lit+te_Expr (CmmLoad e _) = te_Expr e+te_Expr (CmmReg r) = te_Reg r+te_Expr (CmmMachOp _ es) = mapM_ te_Expr es+te_Expr (CmmRegOff r _) = te_Reg r+te_Expr (CmmStackSlot _ _) = panic "te_Expr: CmmStackSlot not supported!"++te_Reg :: CmmReg -> TE ()+te_Reg (CmmLocal l) = te_temp l+te_Reg _ = return ()+++-- ---------------------------------------------------------------------+-- C types for MachReps++cCast :: SDoc -> CmmExpr -> SDoc+cCast ty expr = parens ty <> pprExpr1 expr++cLoad :: CmmExpr -> CmmType -> SDoc+cLoad expr rep+ = sdocWithPlatform $ \platform ->+ if bewareLoadStoreAlignment (platformArch platform)+ then let decl = machRepCType rep <+> text "x" <> semi+ struct = text "struct" <+> braces (decl)+ packed_attr = text "__attribute__((packed))"+ cast = parens (struct <+> packed_attr <> char '*')+ in parens (cast <+> pprExpr1 expr) <> text "->x"+ else char '*' <> parens (cCast (machRepPtrCType rep) expr)+ where -- On these platforms, unaligned loads are known to cause problems+ bewareLoadStoreAlignment ArchAlpha = True+ bewareLoadStoreAlignment ArchMipseb = True+ bewareLoadStoreAlignment ArchMipsel = True+ bewareLoadStoreAlignment (ArchARM {}) = True+ bewareLoadStoreAlignment ArchARM64 = True+ bewareLoadStoreAlignment ArchSPARC = True+ bewareLoadStoreAlignment ArchSPARC64 = True+ -- Pessimistically assume that they will also cause problems+ -- on unknown arches+ bewareLoadStoreAlignment ArchUnknown = True+ bewareLoadStoreAlignment _ = False++isCmmWordType :: DynFlags -> CmmType -> Bool+-- True of GcPtrReg/NonGcReg of native word size+isCmmWordType dflags ty = not (isFloatType ty)+ && typeWidth ty == wordWidth dflags++-- This is for finding the types of foreign call arguments. For a pointer+-- argument, we always cast the argument to (void *), to avoid warnings from+-- the C compiler.+machRepHintCType :: CmmType -> ForeignHint -> SDoc+machRepHintCType _ AddrHint = text "void *"+machRepHintCType rep SignedHint = machRep_S_CType (typeWidth rep)+machRepHintCType rep _other = machRepCType rep++machRepPtrCType :: CmmType -> SDoc+machRepPtrCType r+ = sdocWithDynFlags $ \dflags ->+ if isCmmWordType dflags r then text "P_"+ else machRepCType r <> char '*'++machRepCType :: CmmType -> SDoc+machRepCType ty | isFloatType ty = machRep_F_CType w+ | otherwise = machRep_U_CType w+ where+ w = typeWidth ty++machRep_F_CType :: Width -> SDoc+machRep_F_CType W32 = text "StgFloat" -- ToDo: correct?+machRep_F_CType W64 = text "StgDouble"+machRep_F_CType _ = panic "machRep_F_CType"++machRep_U_CType :: Width -> SDoc+machRep_U_CType w+ = sdocWithDynFlags $ \dflags ->+ case w of+ _ | w == wordWidth dflags -> text "W_"+ W8 -> text "StgWord8"+ W16 -> text "StgWord16"+ W32 -> text "StgWord32"+ W64 -> text "StgWord64"+ _ -> panic "machRep_U_CType"++machRep_S_CType :: Width -> SDoc+machRep_S_CType w+ = sdocWithDynFlags $ \dflags ->+ case w of+ _ | w == wordWidth dflags -> text "I_"+ W8 -> text "StgInt8"+ W16 -> text "StgInt16"+ W32 -> text "StgInt32"+ W64 -> text "StgInt64"+ _ -> panic "machRep_S_CType"+++-- ---------------------------------------------------------------------+-- print strings as valid C strings++pprStringInCStyle :: [Word8] -> SDoc+pprStringInCStyle s = doubleQuotes (text (concatMap charToC s))++-- ---------------------------------------------------------------------------+-- Initialising static objects with floating-point numbers. We can't+-- just emit the floating point number, because C will cast it to an int+-- by rounding it. We want the actual bit-representation of the float.+--+-- Consider a concrete C example:+-- double d = 2.5e-10;+-- float f = 2.5e-10f;+--+-- int * i2 = &d; printf ("i2: %08X %08X\n", i2[0], i2[1]);+-- long long * l = &d; printf (" l: %016llX\n", l[0]);+-- int * i = &f; printf (" i: %08X\n", i[0]);+-- Result on 64-bit LE (x86_64):+-- i2: E826D695 3DF12E0B+-- l: 3DF12E0BE826D695+-- i: 2F89705F+-- Result on 32-bit BE (m68k):+-- i2: 3DF12E0B E826D695+-- l: 3DF12E0BE826D695+-- i: 2F89705F+--+-- The trick here is to notice that binary representation does not+-- change much: only Word32 values get swapped on LE hosts / targets.++-- This is a hack to turn the floating point numbers into ints that we+-- can safely initialise to static locations.++castFloatToWord32Array :: STUArray s Int Float -> ST s (STUArray s Int Word32)+castFloatToWord32Array = U.castSTUArray++castDoubleToWord64Array :: STUArray s Int Double -> ST s (STUArray s Int Word64)+castDoubleToWord64Array = U.castSTUArray++floatToWord :: DynFlags -> Rational -> CmmLit+floatToWord dflags r+ = runST (do+ arr <- newArray_ ((0::Int),0)+ writeArray arr 0 (fromRational r)+ arr' <- castFloatToWord32Array arr+ w32 <- readArray arr' 0+ return (CmmInt (toInteger w32 `shiftL` wo) (wordWidth dflags))+ )+ where wo | wordWidth dflags == W64+ , wORDS_BIGENDIAN dflags = 32+ | otherwise = 0++doubleToWords :: DynFlags -> Rational -> [CmmLit]+doubleToWords dflags r+ = runST (do+ arr <- newArray_ ((0::Int),1)+ writeArray arr 0 (fromRational r)+ arr' <- castDoubleToWord64Array arr+ w64 <- readArray arr' 0+ return (pprWord64 w64)+ )+ where targetWidth = wordWidth dflags+ targetBE = wORDS_BIGENDIAN dflags+ pprWord64 w64+ | targetWidth == W64 =+ [ CmmInt (toInteger w64) targetWidth ]+ | targetWidth == W32 =+ [ CmmInt (toInteger targetW1) targetWidth+ , CmmInt (toInteger targetW2) targetWidth+ ]+ | otherwise = panic "doubleToWords.pprWord64"+ where (targetW1, targetW2)+ | targetBE = (wHi, wLo)+ | otherwise = (wLo, wHi)+ wHi = w64 `shiftR` 32+ wLo = w64 .&. 0xFFFFffff++-- ---------------------------------------------------------------------------+-- Utils++wordShift :: DynFlags -> Int+wordShift dflags = widthInLog (wordWidth dflags)++commafy :: [SDoc] -> SDoc+commafy xs = hsep $ punctuate comma xs++-- Print in C hex format: 0x13fa+pprHexVal :: Integer -> Width -> SDoc+pprHexVal w rep+ | w < 0 = parens (char '-' <>+ text "0x" <> intToDoc (-w) <> repsuffix rep)+ | otherwise = text "0x" <> intToDoc w <> repsuffix rep+ where+ -- type suffix for literals:+ -- Integer literals are unsigned in Cmm/C. We explicitly cast to+ -- signed values for doing signed operations, but at all other+ -- times values are unsigned. This also helps eliminate occasional+ -- warnings about integer overflow from gcc.++ repsuffix W64 = sdocWithDynFlags $ \dflags ->+ if cINT_SIZE dflags == 8 then char 'U'+ else if cLONG_SIZE dflags == 8 then text "UL"+ else if cLONG_LONG_SIZE dflags == 8 then text "ULL"+ else panic "pprHexVal: Can't find a 64-bit type"+ repsuffix _ = char 'U'++ intToDoc :: Integer -> SDoc+ intToDoc i = case truncInt i of+ 0 -> char '0'+ v -> go v++ -- We need to truncate value as Cmm backend does not drop+ -- redundant bits to ease handling of negative values.+ -- Thus the following Cmm code on 64-bit arch, like amd64:+ -- CInt v;+ -- v = {something};+ -- if (v == %lobits32(-1)) { ...+ -- leads to the following C code:+ -- StgWord64 v = (StgWord32)({something});+ -- if (v == 0xFFFFffffFFFFffffU) { ...+ -- Such code is incorrect as it promotes both operands to StgWord64+ -- and the whole condition is always false.+ truncInt :: Integer -> Integer+ truncInt i =+ case rep of+ W8 -> i `rem` (2^(8 :: Int))+ W16 -> i `rem` (2^(16 :: Int))+ W32 -> i `rem` (2^(32 :: Int))+ W64 -> i `rem` (2^(64 :: Int))+ _ -> panic ("pprHexVal/truncInt: C backend can't encode "+ ++ show rep ++ " literals")++ go 0 = empty+ go w' = go q <> dig+ where+ (q,r) = w' `quotRem` 16+ dig | r < 10 = char (chr (fromInteger r + ord '0'))+ | otherwise = char (chr (fromInteger r - 10 + ord 'a'))
+ cmm/PprCmm.hs view
@@ -0,0 +1,306 @@+{-# LANGUAGE GADTs, TypeFamilies, FlexibleContexts, FlexibleInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++----------------------------------------------------------------------------+--+-- Pretty-printing of Cmm as (a superset of) C--+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------+--+-- This is where we walk over CmmNode emitting an external representation,+-- suitable for parsing, in a syntax strongly reminiscent of C--. This+-- is the "External Core" for the Cmm layer.+--+-- As such, this should be a well-defined syntax: we want it to look nice.+-- Thus, we try wherever possible to use syntax defined in [1],+-- "The C-- Reference Manual", http://www.cminusminus.org/. We differ+-- slightly, in some cases. For one, we use I8 .. I64 for types, rather+-- than C--'s bits8 .. bits64.+--+-- We try to ensure that all information available in the abstract+-- syntax is reproduced, or reproducible, in the concrete syntax.+-- Data that is not in printed out can be reconstructed according to+-- conventions used in the pretty printer. There are at least two such+-- cases:+-- 1) if a value has wordRep type, the type is not appended in the+-- output.+-- 2) MachOps that operate over wordRep type are printed in a+-- C-style, rather than as their internal MachRep name.+--+-- These conventions produce much more readable Cmm output.+--+-- A useful example pass over Cmm is in nativeGen/MachCodeGen.hs++module PprCmm+ ( module PprCmmDecl+ , module PprCmmExpr+ )+where++import BlockId ()+import CLabel+import Cmm+import CmmUtils+import CmmSwitch+import DynFlags+import FastString+import Outputable+import PprCmmDecl+import PprCmmExpr+import Util+import PprCore ()++import BasicTypes+import Compiler.Hoopl+import Data.List+import Prelude hiding (succ)++-------------------------------------------------+-- Outputable instances++instance Outputable CmmStackInfo where+ ppr = pprStackInfo++instance Outputable CmmTopInfo where+ ppr = pprTopInfo+++instance Outputable (CmmNode e x) where+ ppr = pprNode++instance Outputable Convention where+ ppr = pprConvention++instance Outputable ForeignConvention where+ ppr = pprForeignConvention++instance Outputable ForeignTarget where+ ppr = pprForeignTarget++instance Outputable CmmReturnInfo where+ ppr = pprReturnInfo++instance Outputable (Block CmmNode C C) where+ ppr = pprBlock+instance Outputable (Block CmmNode C O) where+ ppr = pprBlock+instance Outputable (Block CmmNode O C) where+ ppr = pprBlock+instance Outputable (Block CmmNode O O) where+ ppr = pprBlock++instance Outputable (Graph CmmNode e x) where+ ppr = pprGraph++instance Outputable CmmGraph where+ ppr = pprCmmGraph++----------------------------------------------------------+-- Outputting types Cmm contains++pprStackInfo :: CmmStackInfo -> SDoc+pprStackInfo (StackInfo {arg_space=arg_space, updfr_space=updfr_space}) =+ text "arg_space: " <> ppr arg_space <+>+ text "updfr_space: " <> ppr updfr_space++pprTopInfo :: CmmTopInfo -> SDoc+pprTopInfo (TopInfo {info_tbls=info_tbl, stack_info=stack_info}) =+ vcat [text "info_tbl: " <> ppr info_tbl,+ text "stack_info: " <> ppr stack_info]++----------------------------------------------------------+-- Outputting blocks and graphs++pprBlock :: IndexedCO x SDoc SDoc ~ SDoc+ => Block CmmNode e x -> IndexedCO e SDoc SDoc+pprBlock block+ = foldBlockNodesB3 ( ($$) . ppr+ , ($$) . (nest 4) . ppr+ , ($$) . (nest 4) . ppr+ )+ block+ empty++pprGraph :: Graph CmmNode e x -> SDoc+pprGraph GNil = empty+pprGraph (GUnit block) = ppr block+pprGraph (GMany entry body exit)+ = text "{"+ $$ nest 2 (pprMaybeO entry $$ (vcat $ map ppr $ bodyToBlockList body) $$ pprMaybeO exit)+ $$ text "}"+ where pprMaybeO :: Outputable (Block CmmNode e x)+ => MaybeO ex (Block CmmNode e x) -> SDoc+ pprMaybeO NothingO = empty+ pprMaybeO (JustO block) = ppr block++pprCmmGraph :: CmmGraph -> SDoc+pprCmmGraph g+ = text "{" <> text "offset"+ $$ nest 2 (vcat $ map ppr blocks)+ $$ text "}"+ where blocks = postorderDfs g+ -- postorderDfs has the side-effect of discarding unreachable code,+ -- so pretty-printed Cmm will omit any unreachable blocks. This can+ -- sometimes be confusing.++---------------------------------------------+-- Outputting CmmNode and types which it contains++pprConvention :: Convention -> SDoc+pprConvention (NativeNodeCall {}) = text "<native-node-call-convention>"+pprConvention (NativeDirectCall {}) = text "<native-direct-call-convention>"+pprConvention (NativeReturn {}) = text "<native-ret-convention>"+pprConvention Slow = text "<slow-convention>"+pprConvention GC = text "<gc-convention>"++pprForeignConvention :: ForeignConvention -> SDoc+pprForeignConvention (ForeignConvention c args res ret) =+ doubleQuotes (ppr c) <+> text "arg hints: " <+> ppr args <+> text " result hints: " <+> ppr res <+> ppr ret++pprReturnInfo :: CmmReturnInfo -> SDoc+pprReturnInfo CmmMayReturn = empty+pprReturnInfo CmmNeverReturns = text "never returns"++pprForeignTarget :: ForeignTarget -> SDoc+pprForeignTarget (ForeignTarget fn c) = ppr c <+> ppr_target fn+ where+ ppr_target :: CmmExpr -> SDoc+ ppr_target t@(CmmLit _) = ppr t+ ppr_target fn' = parens (ppr fn')++pprForeignTarget (PrimTarget op)+ -- HACK: We're just using a ForeignLabel to get this printed, the label+ -- might not really be foreign.+ = ppr+ (CmmLabel (mkForeignLabel+ (mkFastString (show op))+ Nothing ForeignLabelInThisPackage IsFunction))++pprNode :: CmmNode e x -> SDoc+pprNode node = pp_node <+> pp_debug+ where+ pp_node :: SDoc+ pp_node = sdocWithDynFlags $ \dflags -> case node of+ -- label:+ CmmEntry id tscope -> ppr id <> colon <+>+ (sdocWithDynFlags $ \dflags ->+ ppUnless (gopt Opt_SuppressTicks dflags) (text "//" <+> ppr tscope))++ -- // text+ CmmComment s -> text "//" <+> ftext s++ -- //tick bla<...>+ CmmTick t -> ppUnless (gopt Opt_SuppressTicks dflags) $+ text "//tick" <+> ppr t++ -- unwind reg = expr;+ CmmUnwind regs ->+ text "unwind "+ <> commafy (map (\(r,e) -> ppr r <+> char '=' <+> ppr e) regs) <> semi++ -- reg = expr;+ CmmAssign reg expr -> ppr reg <+> equals <+> ppr expr <> semi++ -- rep[lv] = expr;+ CmmStore lv expr -> rep <> brackets(ppr lv) <+> equals <+> ppr expr <> semi+ where+ rep = sdocWithDynFlags $ \dflags ->+ ppr ( cmmExprType dflags expr )++ -- call "ccall" foo(x, y)[r1, r2];+ -- ToDo ppr volatile+ CmmUnsafeForeignCall target results args ->+ hsep [ ppUnless (null results) $+ parens (commafy $ map ppr results) <+> equals,+ text "call",+ ppr target <> parens (commafy $ map ppr args) <> semi]++ -- goto label;+ CmmBranch ident -> text "goto" <+> ppr ident <> semi++ -- if (expr) goto t; else goto f;+ CmmCondBranch expr t f l ->+ hsep [ text "if"+ , parens(ppr expr)+ , case l of+ Nothing -> empty+ Just b -> parens (text "likely:" <+> ppr b)+ , text "goto"+ , ppr t <> semi+ , text "else goto"+ , ppr f <> semi+ ]++ CmmSwitch expr ids ->+ hang (hsep [ text "switch"+ , range+ , if isTrivialCmmExpr expr+ then ppr expr+ else parens (ppr expr)+ , text "{"+ ])+ 4 (vcat (map ppCase cases) $$ def) $$ rbrace+ where+ (cases, mbdef) = switchTargetsFallThrough ids+ ppCase (is,l) = hsep+ [ text "case"+ , commafy $ map integer is+ , text ": goto"+ , ppr l <> semi+ ]+ def | Just l <- mbdef = hsep+ [ text "default: goto"+ , ppr l <> semi+ ]+ | otherwise = empty++ range = brackets $ hsep [integer lo, text "..", integer hi]+ where (lo,hi) = switchTargetsRange ids++ CmmCall tgt k regs out res updfr_off ->+ hcat [ text "call", space+ , pprFun tgt, parens (interpp'SP regs), space+ , returns <+>+ text "args: " <> ppr out <> comma <+>+ text "res: " <> ppr res <> comma <+>+ text "upd: " <> ppr updfr_off+ , semi ]+ where pprFun f@(CmmLit _) = ppr f+ pprFun f = parens (ppr f)++ returns+ | Just r <- k = text "returns to" <+> ppr r <> comma+ | otherwise = empty++ CmmForeignCall {tgt=t, res=rs, args=as, succ=s, ret_args=a, ret_off=u, intrbl=i} ->+ hcat $ if i then [text "interruptible", space] else [] +++ [ text "foreign call", space+ , ppr t, text "(...)", space+ , text "returns to" <+> ppr s+ <+> text "args:" <+> parens (ppr as)+ <+> text "ress:" <+> parens (ppr rs)+ , text "ret_args:" <+> ppr a+ , text "ret_off:" <+> ppr u+ , semi ]++ pp_debug :: SDoc+ pp_debug =+ if not debugIsOn then empty+ else case node of+ CmmEntry {} -> empty -- Looks terrible with text " // CmmEntry"+ CmmComment {} -> empty -- Looks also terrible with text " // CmmComment"+ CmmTick {} -> empty+ CmmUnwind {} -> text " // CmmUnwind"+ CmmAssign {} -> text " // CmmAssign"+ CmmStore {} -> text " // CmmStore"+ CmmUnsafeForeignCall {} -> text " // CmmUnsafeForeignCall"+ CmmBranch {} -> text " // CmmBranch"+ CmmCondBranch {} -> text " // CmmCondBranch"+ CmmSwitch {} -> text " // CmmSwitch"+ CmmCall {} -> text " // CmmCall"+ CmmForeignCall {} -> text " // CmmForeignCall"++ commafy :: [SDoc] -> SDoc+ commafy xs = hsep $ punctuate comma xs
+ cmm/PprCmmDecl.hs view
@@ -0,0 +1,174 @@+{-# LANGUAGE CPP #-}++----------------------------------------------------------------------------+--+-- Pretty-printing of common Cmm types+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++--+-- This is where we walk over Cmm emitting an external representation,+-- suitable for parsing, in a syntax strongly reminiscent of C--. This+-- is the "External Core" for the Cmm layer.+--+-- As such, this should be a well-defined syntax: we want it to look nice.+-- Thus, we try wherever possible to use syntax defined in [1],+-- "The C-- Reference Manual", http://www.cminusminus.org/. We differ+-- slightly, in some cases. For one, we use I8 .. I64 for types, rather+-- than C--'s bits8 .. bits64.+--+-- We try to ensure that all information available in the abstract+-- syntax is reproduced, or reproducible, in the concrete syntax.+-- Data that is not in printed out can be reconstructed according to+-- conventions used in the pretty printer. There are at least two such+-- cases:+-- 1) if a value has wordRep type, the type is not appended in the+-- output.+-- 2) MachOps that operate over wordRep type are printed in a+-- C-style, rather than as their internal MachRep name.+--+-- These conventions produce much more readable Cmm output.+--+-- A useful example pass over Cmm is in nativeGen/MachCodeGen.hs+--++{-# OPTIONS_GHC -fno-warn-orphans #-}+module PprCmmDecl+ ( writeCmms, pprCmms, pprCmmGroup, pprSection, pprStatic+ )+where++import PprCmmExpr+import Cmm++import DynFlags+import Outputable+import FastString++import Data.List+import System.IO++-- Temp Jan08+import SMRep+#include "rts/storage/FunTypes.h"+++pprCmms :: (Outputable info, Outputable g)+ => [GenCmmGroup CmmStatics info g] -> SDoc+pprCmms cmms = pprCode CStyle (vcat (intersperse separator $ map ppr cmms))+ where+ separator = space $$ text "-------------------" $$ space++writeCmms :: (Outputable info, Outputable g)+ => DynFlags -> Handle -> [GenCmmGroup CmmStatics info g] -> IO ()+writeCmms dflags handle cmms = printForC dflags handle (pprCmms cmms)++-----------------------------------------------------------------------------++instance (Outputable d, Outputable info, Outputable i)+ => Outputable (GenCmmDecl d info i) where+ ppr t = pprTop t++instance Outputable CmmStatics where+ ppr = pprStatics++instance Outputable CmmStatic where+ ppr = pprStatic++instance Outputable CmmInfoTable where+ ppr = pprInfoTable+++-----------------------------------------------------------------------------++pprCmmGroup :: (Outputable d, Outputable info, Outputable g)+ => GenCmmGroup d info g -> SDoc+pprCmmGroup tops+ = vcat $ intersperse blankLine $ map pprTop tops++-- --------------------------------------------------------------------------+-- Top level `procedure' blocks.+--+pprTop :: (Outputable d, Outputable info, Outputable i)+ => GenCmmDecl d info i -> SDoc++pprTop (CmmProc info lbl live graph)++ = vcat [ ppr lbl <> lparen <> rparen <+> text "// " <+> ppr live+ , nest 8 $ lbrace <+> ppr info $$ rbrace+ , nest 4 $ ppr graph+ , rbrace ]++-- --------------------------------------------------------------------------+-- We follow [1], 4.5+--+-- section "data" { ... }+--+pprTop (CmmData section ds) =+ (hang (pprSection section <+> lbrace) 4 (ppr ds))+ $$ rbrace++-- --------------------------------------------------------------------------+-- Info tables.++pprInfoTable :: CmmInfoTable -> SDoc+pprInfoTable (CmmInfoTable { cit_lbl = lbl, cit_rep = rep+ , cit_prof = prof_info+ , cit_srt = _srt })+ = vcat [ text "label:" <+> ppr lbl+ , text "rep:" <> ppr rep+ , case prof_info of+ NoProfilingInfo -> empty+ ProfilingInfo ct cd -> vcat [ text "type:" <+> pprWord8String ct+ , text "desc: " <> pprWord8String cd ] ]++instance Outputable C_SRT where+ ppr NoC_SRT = text "_no_srt_"+ ppr (C_SRT label off bitmap)+ = parens (ppr label <> comma <> ppr off <> comma <> ppr bitmap)++instance Outputable ForeignHint where+ ppr NoHint = empty+ ppr SignedHint = quotes(text "signed")+-- ppr AddrHint = quotes(text "address")+-- Temp Jan08+ ppr AddrHint = (text "PtrHint")++-- --------------------------------------------------------------------------+-- Static data.+-- Strings are printed as C strings, and we print them as I8[],+-- following C--+--+pprStatics :: CmmStatics -> SDoc+pprStatics (Statics lbl ds) = vcat ((ppr lbl <> colon) : map ppr ds)++pprStatic :: CmmStatic -> SDoc+pprStatic s = case s of+ CmmStaticLit lit -> nest 4 $ text "const" <+> pprLit lit <> semi+ CmmUninitialised i -> nest 4 $ text "I8" <> brackets (int i)+ CmmString s' -> nest 4 $ text "I8[]" <+> text (show s')++-- --------------------------------------------------------------------------+-- data sections+--+pprSection :: Section -> SDoc+pprSection (Section t suffix) =+ section <+> doubleQuotes (pprSectionType t <+> char '.' <+> ppr suffix)+ where+ section = text "section"++pprSectionType :: SectionType -> SDoc+pprSectionType s = doubleQuotes (ptext t)+ where+ t = case s of+ Text -> sLit "text"+ Data -> sLit "data"+ ReadOnlyData -> sLit "readonly"+ ReadOnlyData16 -> sLit "readonly16"+ RelocatableReadOnlyData+ -> sLit "relreadonly"+ UninitialisedData -> sLit "uninitialised"+ CString -> sLit "cstring"+ OtherSection s' -> sLit s' -- Not actually a literal though.
+ cmm/PprCmmExpr.hs view
@@ -0,0 +1,279 @@+----------------------------------------------------------------------------+--+-- Pretty-printing of common Cmm types+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++--+-- This is where we walk over Cmm emitting an external representation,+-- suitable for parsing, in a syntax strongly reminiscent of C--. This+-- is the "External Core" for the Cmm layer.+--+-- As such, this should be a well-defined syntax: we want it to look nice.+-- Thus, we try wherever possible to use syntax defined in [1],+-- "The C-- Reference Manual", http://www.cminusminus.org/. We differ+-- slightly, in some cases. For one, we use I8 .. I64 for types, rather+-- than C--'s bits8 .. bits64.+--+-- We try to ensure that all information available in the abstract+-- syntax is reproduced, or reproducible, in the concrete syntax.+-- Data that is not in printed out can be reconstructed according to+-- conventions used in the pretty printer. There are at least two such+-- cases:+-- 1) if a value has wordRep type, the type is not appended in the+-- output.+-- 2) MachOps that operate over wordRep type are printed in a+-- C-style, rather than as their internal MachRep name.+--+-- These conventions produce much more readable Cmm output.+--+-- A useful example pass over Cmm is in nativeGen/MachCodeGen.hs+--++{-# OPTIONS_GHC -fno-warn-orphans #-}+module PprCmmExpr+ ( pprExpr, pprLit+ )+where++import CmmExpr++import Outputable++import Data.Maybe+import Numeric ( fromRat )++-----------------------------------------------------------------------------++instance Outputable CmmExpr where+ ppr e = pprExpr e++instance Outputable CmmReg where+ ppr e = pprReg e++instance Outputable CmmLit where+ ppr l = pprLit l++instance Outputable LocalReg where+ ppr e = pprLocalReg e++instance Outputable Area where+ ppr e = pprArea e++instance Outputable GlobalReg where+ ppr e = pprGlobalReg e++-- --------------------------------------------------------------------------+-- Expressions+--++pprExpr :: CmmExpr -> SDoc+pprExpr e+ = sdocWithDynFlags $ \dflags ->+ case e of+ CmmRegOff reg i ->+ pprExpr (CmmMachOp (MO_Add rep)+ [CmmReg reg, CmmLit (CmmInt (fromIntegral i) rep)])+ where rep = typeWidth (cmmRegType dflags reg)+ CmmLit lit -> pprLit lit+ _other -> pprExpr1 e++-- Here's the precedence table from CmmParse.y:+-- %nonassoc '>=' '>' '<=' '<' '!=' '=='+-- %left '|'+-- %left '^'+-- %left '&'+-- %left '>>' '<<'+-- %left '-' '+'+-- %left '/' '*' '%'+-- %right '~'++-- We just cope with the common operators for now, the rest will get+-- a default conservative behaviour.++-- %nonassoc '>=' '>' '<=' '<' '!=' '=='+pprExpr1, pprExpr7, pprExpr8 :: CmmExpr -> SDoc+pprExpr1 (CmmMachOp op [x,y]) | Just doc <- infixMachOp1 op+ = pprExpr7 x <+> doc <+> pprExpr7 y+pprExpr1 e = pprExpr7 e++infixMachOp1, infixMachOp7, infixMachOp8 :: MachOp -> Maybe SDoc++infixMachOp1 (MO_Eq _) = Just (text "==")+infixMachOp1 (MO_Ne _) = Just (text "!=")+infixMachOp1 (MO_Shl _) = Just (text "<<")+infixMachOp1 (MO_U_Shr _) = Just (text ">>")+infixMachOp1 (MO_U_Ge _) = Just (text ">=")+infixMachOp1 (MO_U_Le _) = Just (text "<=")+infixMachOp1 (MO_U_Gt _) = Just (char '>')+infixMachOp1 (MO_U_Lt _) = Just (char '<')+infixMachOp1 _ = Nothing++-- %left '-' '+'+pprExpr7 (CmmMachOp (MO_Add rep1) [x, CmmLit (CmmInt i rep2)]) | i < 0+ = pprExpr7 (CmmMachOp (MO_Sub rep1) [x, CmmLit (CmmInt (negate i) rep2)])+pprExpr7 (CmmMachOp op [x,y]) | Just doc <- infixMachOp7 op+ = pprExpr7 x <+> doc <+> pprExpr8 y+pprExpr7 e = pprExpr8 e++infixMachOp7 (MO_Add _) = Just (char '+')+infixMachOp7 (MO_Sub _) = Just (char '-')+infixMachOp7 _ = Nothing++-- %left '/' '*' '%'+pprExpr8 (CmmMachOp op [x,y]) | Just doc <- infixMachOp8 op+ = pprExpr8 x <+> doc <+> pprExpr9 y+pprExpr8 e = pprExpr9 e++infixMachOp8 (MO_U_Quot _) = Just (char '/')+infixMachOp8 (MO_Mul _) = Just (char '*')+infixMachOp8 (MO_U_Rem _) = Just (char '%')+infixMachOp8 _ = Nothing++pprExpr9 :: CmmExpr -> SDoc+pprExpr9 e =+ case e of+ CmmLit lit -> pprLit1 lit+ CmmLoad expr rep -> ppr rep <> brackets (ppr expr)+ CmmReg reg -> ppr reg+ CmmRegOff reg off -> parens (ppr reg <+> char '+' <+> int off)+ CmmStackSlot a off -> parens (ppr a <+> char '+' <+> int off)+ CmmMachOp mop args -> genMachOp mop args++genMachOp :: MachOp -> [CmmExpr] -> SDoc+genMachOp mop args+ | Just doc <- infixMachOp mop = case args of+ -- dyadic+ [x,y] -> pprExpr9 x <+> doc <+> pprExpr9 y++ -- unary+ [x] -> doc <> pprExpr9 x++ _ -> pprTrace "PprCmm.genMachOp: machop with strange number of args"+ (pprMachOp mop <+>+ parens (hcat $ punctuate comma (map pprExpr args)))+ empty++ | isJust (infixMachOp1 mop)+ || isJust (infixMachOp7 mop)+ || isJust (infixMachOp8 mop) = parens (pprExpr (CmmMachOp mop args))++ | otherwise = char '%' <> ppr_op <> parens (commafy (map pprExpr args))+ where ppr_op = text (map (\c -> if c == ' ' then '_' else c)+ (show mop))+ -- replace spaces in (show mop) with underscores,++--+-- Unsigned ops on the word size of the machine get nice symbols.+-- All else get dumped in their ugly format.+--+infixMachOp :: MachOp -> Maybe SDoc+infixMachOp mop+ = case mop of+ MO_And _ -> Just $ char '&'+ MO_Or _ -> Just $ char '|'+ MO_Xor _ -> Just $ char '^'+ MO_Not _ -> Just $ char '~'+ MO_S_Neg _ -> Just $ char '-' -- there is no unsigned neg :)+ _ -> Nothing++-- --------------------------------------------------------------------------+-- Literals.+-- To minimise line noise we adopt the convention that if the literal+-- has the natural machine word size, we do not append the type+--+pprLit :: CmmLit -> SDoc+pprLit lit = sdocWithDynFlags $ \dflags ->+ case lit of+ CmmInt i rep ->+ hcat [ (if i < 0 then parens else id)(integer i)+ , ppUnless (rep == wordWidth dflags) $+ space <> dcolon <+> ppr rep ]++ CmmFloat f rep -> hsep [ double (fromRat f), dcolon, ppr rep ]+ CmmVec lits -> char '<' <> commafy (map pprLit lits) <> char '>'+ CmmLabel clbl -> ppr clbl+ CmmLabelOff clbl i -> ppr clbl <> ppr_offset i+ CmmLabelDiffOff clbl1 clbl2 i -> ppr clbl1 <> char '-'+ <> ppr clbl2 <> ppr_offset i+ CmmBlock id -> ppr id+ CmmHighStackMark -> text "<highSp>"++pprLit1 :: CmmLit -> SDoc+pprLit1 lit@(CmmLabelOff {}) = parens (pprLit lit)+pprLit1 lit = pprLit lit++ppr_offset :: Int -> SDoc+ppr_offset i+ | i==0 = empty+ | i>=0 = char '+' <> int i+ | otherwise = char '-' <> int (-i)++-- --------------------------------------------------------------------------+-- Registers, whether local (temps) or global+--+pprReg :: CmmReg -> SDoc+pprReg r+ = case r of+ CmmLocal local -> pprLocalReg local+ CmmGlobal global -> pprGlobalReg global++--+-- We only print the type of the local reg if it isn't wordRep+--+pprLocalReg :: LocalReg -> SDoc+pprLocalReg (LocalReg uniq rep)+-- = ppr rep <> char '_' <> ppr uniq+-- Temp Jan08+ = char '_' <> ppr uniq <>+ (if isWord32 rep -- && not (isGcPtrType rep) -- Temp Jan08 -- sigh+ then dcolon <> ptr <> ppr rep+ else dcolon <> ptr <> ppr rep)+ where+ ptr = empty+ --if isGcPtrType rep+ -- then doubleQuotes (text "ptr")+ -- else empty++-- Stack areas+pprArea :: Area -> SDoc+pprArea Old = text "old"+pprArea (Young id) = hcat [ text "young<", ppr id, text ">" ]++-- needs to be kept in syn with CmmExpr.hs.GlobalReg+--+pprGlobalReg :: GlobalReg -> SDoc+pprGlobalReg gr+ = case gr of+ VanillaReg n _ -> char 'R' <> int n+-- Temp Jan08+-- VanillaReg n VNonGcPtr -> char 'R' <> int n+-- VanillaReg n VGcPtr -> char 'P' <> int n+ FloatReg n -> char 'F' <> int n+ DoubleReg n -> char 'D' <> int n+ LongReg n -> char 'L' <> int n+ XmmReg n -> text "XMM" <> int n+ YmmReg n -> text "YMM" <> int n+ ZmmReg n -> text "ZMM" <> int n+ Sp -> text "Sp"+ SpLim -> text "SpLim"+ Hp -> text "Hp"+ HpLim -> text "HpLim"+ MachSp -> text "MachSp"+ UnwindReturnReg-> text "UnwindReturnReg"+ CCCS -> text "CCCS"+ CurrentTSO -> text "CurrentTSO"+ CurrentNursery -> text "CurrentNursery"+ HpAlloc -> text "HpAlloc"+ EagerBlackholeInfo -> text "stg_EAGER_BLACKHOLE_info"+ GCEnter1 -> text "stg_gc_enter_1"+ GCFun -> text "stg_gc_fun"+ BaseReg -> text "BaseReg"+ PicBaseReg -> text "PicBaseReg"++-----------------------------------------------------------------------------++commafy :: [SDoc] -> SDoc+commafy xs = fsep $ punctuate comma xs
+ cmm/SMRep.hs view
@@ -0,0 +1,574 @@+-- (c) The University of Glasgow 2006+-- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998+--+-- Storage manager representation of closures++{-# LANGUAGE CPP,GeneralizedNewtypeDeriving #-}++module SMRep (+ -- * Words and bytes+ WordOff, ByteOff,+ wordsToBytes, bytesToWordsRoundUp,+ roundUpToWords,++ StgWord, fromStgWord, toStgWord,+ StgHalfWord, fromStgHalfWord, toStgHalfWord,+ hALF_WORD_SIZE, hALF_WORD_SIZE_IN_BITS,++ -- * Closure repesentation+ SMRep(..), -- CmmInfo sees the rep; no one else does+ IsStatic,+ ClosureTypeInfo(..), ArgDescr(..), Liveness,+ ConstrDescription,++ -- ** Construction+ mkHeapRep, blackHoleRep, indStaticRep, mkStackRep, mkRTSRep, arrPtrsRep,+ smallArrPtrsRep, arrWordsRep,++ -- ** Predicates+ isStaticRep, isConRep, isThunkRep, isFunRep, isStaticNoCafCon,+ isStackRep,++ -- ** Size-related things+ heapClosureSizeW,+ fixedHdrSizeW, arrWordsHdrSize, arrWordsHdrSizeW, arrPtrsHdrSize,+ arrPtrsHdrSizeW, profHdrSize, thunkHdrSize, nonHdrSize, nonHdrSizeW,+ smallArrPtrsHdrSize, smallArrPtrsHdrSizeW, hdrSize, hdrSizeW,+ fixedHdrSize,++ -- ** RTS closure types+ rtsClosureType, rET_SMALL, rET_BIG,+ aRG_GEN, aRG_GEN_BIG,++ -- ** Arrays+ card, cardRoundUp, cardTableSizeB, cardTableSizeW,++ -- * Operations over [Word8] strings that don't belong here+ pprWord8String, stringToWord8s+ ) where++#include "../HsVersions.h"+#include "MachDeps.h"++import DynFlags+import Outputable+import Platform+import FastString++import Data.Char( ord )+import Data.Word+import Data.Bits++{-+************************************************************************+* *+ Words and bytes+* *+************************************************************************+-}++-- | Word offset, or word count+type WordOff = Int++-- | Byte offset, or byte count+type ByteOff = Int++-- | Round up the given byte count to the next byte count that's a+-- multiple of the machine's word size.+roundUpToWords :: DynFlags -> ByteOff -> ByteOff+roundUpToWords dflags n =+ (n + (wORD_SIZE dflags - 1)) .&. (complement (wORD_SIZE dflags - 1))++-- | Convert the given number of words to a number of bytes.+--+-- This function morally has type @WordOff -> ByteOff@, but uses @Num+-- a@ to allow for overloading.+wordsToBytes :: Num a => DynFlags -> a -> a+wordsToBytes dflags n = fromIntegral (wORD_SIZE dflags) * n+{-# SPECIALIZE wordsToBytes :: DynFlags -> Int -> Int #-}+{-# SPECIALIZE wordsToBytes :: DynFlags -> Word -> Word #-}+{-# SPECIALIZE wordsToBytes :: DynFlags -> Integer -> Integer #-}++-- | First round the given byte count up to a multiple of the+-- machine's word size and then convert the result to words.+bytesToWordsRoundUp :: DynFlags -> ByteOff -> WordOff+bytesToWordsRoundUp dflags n = (n + word_size - 1) `quot` word_size+ where word_size = wORD_SIZE dflags+-- StgWord is a type representing an StgWord on the target platform.+-- A Word64 is large enough to hold a Word for either a 32bit or 64bit platform+newtype StgWord = StgWord Word64+ deriving (Eq, Bits)++fromStgWord :: StgWord -> Integer+fromStgWord (StgWord i) = toInteger i++toStgWord :: DynFlags -> Integer -> StgWord+toStgWord dflags i+ = case platformWordSize (targetPlatform dflags) of+ -- These conversions mean that things like toStgWord (-1)+ -- do the right thing+ 4 -> StgWord (fromIntegral (fromInteger i :: Word32))+ 8 -> StgWord (fromInteger i :: Word64)+ w -> panic ("toStgWord: Unknown platformWordSize: " ++ show w)++instance Outputable StgWord where+ ppr (StgWord i) = integer (toInteger i)++--++-- A Word32 is large enough to hold half a Word for either a 32bit or+-- 64bit platform+newtype StgHalfWord = StgHalfWord Word32+ deriving Eq++fromStgHalfWord :: StgHalfWord -> Integer+fromStgHalfWord (StgHalfWord w) = toInteger w++toStgHalfWord :: DynFlags -> Integer -> StgHalfWord+toStgHalfWord dflags i+ = case platformWordSize (targetPlatform dflags) of+ -- These conversions mean that things like toStgHalfWord (-1)+ -- do the right thing+ 4 -> StgHalfWord (fromIntegral (fromInteger i :: Word16))+ 8 -> StgHalfWord (fromInteger i :: Word32)+ w -> panic ("toStgHalfWord: Unknown platformWordSize: " ++ show w)++instance Outputable StgHalfWord where+ ppr (StgHalfWord w) = integer (toInteger w)++hALF_WORD_SIZE :: DynFlags -> ByteOff+hALF_WORD_SIZE dflags = platformWordSize (targetPlatform dflags) `shiftR` 1+hALF_WORD_SIZE_IN_BITS :: DynFlags -> Int+hALF_WORD_SIZE_IN_BITS dflags = platformWordSize (targetPlatform dflags) `shiftL` 2++{-+************************************************************************+* *+\subsubsection[SMRep-datatype]{@SMRep@---storage manager representation}+* *+************************************************************************+-}++-- | A description of the layout of a closure. Corresponds directly+-- to the closure types in includes/rts/storage/ClosureTypes.h.+data SMRep+ = HeapRep -- GC routines consult sizes in info tbl+ IsStatic+ !WordOff -- # ptr words+ !WordOff -- # non-ptr words INCLUDING SLOP (see mkHeapRep below)+ ClosureTypeInfo -- type-specific info++ | ArrayPtrsRep+ !WordOff -- # ptr words+ !WordOff -- # card table words++ | SmallArrayPtrsRep+ !WordOff -- # ptr words++ | ArrayWordsRep+ !WordOff -- # bytes expressed in words, rounded up++ | StackRep -- Stack frame (RET_SMALL or RET_BIG)+ Liveness++ | RTSRep -- The RTS needs to declare info tables with specific+ Int -- type tags, so this form lets us override the default+ SMRep -- tag for an SMRep.++-- | True <=> This is a static closure. Affects how we garbage-collect it.+-- Static closure have an extra static link field at the end.+-- Constructors do not have a static variant; see Note [static constructors]+type IsStatic = Bool++-- From an SMRep you can get to the closure type defined in+-- includes/rts/storage/ClosureTypes.h. Described by the function+-- rtsClosureType below.++data ClosureTypeInfo+ = Constr ConstrTag ConstrDescription+ | Fun FunArity ArgDescr+ | Thunk+ | ThunkSelector SelectorOffset+ | BlackHole+ | IndStatic++type ConstrTag = Int+type ConstrDescription = [Word8] -- result of dataConIdentity+type FunArity = Int+type SelectorOffset = Int++-------------------------+-- We represent liveness bitmaps as a Bitmap (whose internal+-- representation really is a bitmap). These are pinned onto case return+-- vectors to indicate the state of the stack for the garbage collector.+--+-- In the compiled program, liveness bitmaps that fit inside a single+-- word (StgWord) are stored as a single word, while larger bitmaps are+-- stored as a pointer to an array of words.++type Liveness = [Bool] -- One Bool per word; True <=> non-ptr or dead+ -- False <=> ptr++-------------------------+-- An ArgDescr describes the argument pattern of a function++data ArgDescr+ = ArgSpec -- Fits one of the standard patterns+ !Int -- RTS type identifier ARG_P, ARG_N, ...++ | ArgGen -- General case+ Liveness -- Details about the arguments+++-----------------------------------------------------------------------------+-- Construction++mkHeapRep :: DynFlags -> IsStatic -> WordOff -> WordOff -> ClosureTypeInfo+ -> SMRep+mkHeapRep dflags is_static ptr_wds nonptr_wds cl_type_info+ = HeapRep is_static+ ptr_wds+ (nonptr_wds + slop_wds)+ cl_type_info+ where+ slop_wds+ | is_static = 0+ | otherwise = max 0 (minClosureSize dflags - (hdr_size + payload_size))++ hdr_size = closureTypeHdrSize dflags cl_type_info+ payload_size = ptr_wds + nonptr_wds++mkRTSRep :: Int -> SMRep -> SMRep+mkRTSRep = RTSRep++mkStackRep :: [Bool] -> SMRep+mkStackRep liveness = StackRep liveness++blackHoleRep :: SMRep+blackHoleRep = HeapRep False 0 0 BlackHole++indStaticRep :: SMRep+indStaticRep = HeapRep True 1 0 IndStatic++arrPtrsRep :: DynFlags -> WordOff -> SMRep+arrPtrsRep dflags elems = ArrayPtrsRep elems (cardTableSizeW dflags elems)++smallArrPtrsRep :: WordOff -> SMRep+smallArrPtrsRep elems = SmallArrayPtrsRep elems++arrWordsRep :: DynFlags -> ByteOff -> SMRep+arrWordsRep dflags bytes = ArrayWordsRep (bytesToWordsRoundUp dflags bytes)++-----------------------------------------------------------------------------+-- Predicates++isStaticRep :: SMRep -> IsStatic+isStaticRep (HeapRep is_static _ _ _) = is_static+isStaticRep (RTSRep _ rep) = isStaticRep rep+isStaticRep _ = False++isStackRep :: SMRep -> Bool+isStackRep StackRep{} = True+isStackRep (RTSRep _ rep) = isStackRep rep+isStackRep _ = False++isConRep :: SMRep -> Bool+isConRep (HeapRep _ _ _ Constr{}) = True+isConRep _ = False++isThunkRep :: SMRep -> Bool+isThunkRep (HeapRep _ _ _ Thunk{}) = True+isThunkRep (HeapRep _ _ _ ThunkSelector{}) = True+isThunkRep (HeapRep _ _ _ BlackHole{}) = True+isThunkRep (HeapRep _ _ _ IndStatic{}) = True+isThunkRep _ = False++isFunRep :: SMRep -> Bool+isFunRep (HeapRep _ _ _ Fun{}) = True+isFunRep _ = False++isStaticNoCafCon :: SMRep -> Bool+-- This should line up exactly with CONSTR_NOCAF below+-- See Note [Static NoCaf constructors]+isStaticNoCafCon (HeapRep _ 0 _ Constr{}) = True+isStaticNoCafCon _ = False+++-----------------------------------------------------------------------------+-- Size-related things++fixedHdrSize :: DynFlags -> ByteOff+fixedHdrSize dflags = wordsToBytes dflags (fixedHdrSizeW dflags)++-- | Size of a closure header (StgHeader in includes/rts/storage/Closures.h)+fixedHdrSizeW :: DynFlags -> WordOff+fixedHdrSizeW dflags = sTD_HDR_SIZE dflags + profHdrSize dflags++-- | Size of the profiling part of a closure header+-- (StgProfHeader in includes/rts/storage/Closures.h)+profHdrSize :: DynFlags -> WordOff+profHdrSize dflags+ | gopt Opt_SccProfilingOn dflags = pROF_HDR_SIZE dflags+ | otherwise = 0++-- | The garbage collector requires that every closure is at least as+-- big as this.+minClosureSize :: DynFlags -> WordOff+minClosureSize dflags = fixedHdrSizeW dflags + mIN_PAYLOAD_SIZE dflags++arrWordsHdrSize :: DynFlags -> ByteOff+arrWordsHdrSize dflags+ = fixedHdrSize dflags + sIZEOF_StgArrBytes_NoHdr dflags++arrWordsHdrSizeW :: DynFlags -> WordOff+arrWordsHdrSizeW dflags =+ fixedHdrSizeW dflags ++ (sIZEOF_StgArrBytes_NoHdr dflags `quot` wORD_SIZE dflags)++arrPtrsHdrSize :: DynFlags -> ByteOff+arrPtrsHdrSize dflags+ = fixedHdrSize dflags + sIZEOF_StgMutArrPtrs_NoHdr dflags++arrPtrsHdrSizeW :: DynFlags -> WordOff+arrPtrsHdrSizeW dflags =+ fixedHdrSizeW dflags ++ (sIZEOF_StgMutArrPtrs_NoHdr dflags `quot` wORD_SIZE dflags)++smallArrPtrsHdrSize :: DynFlags -> ByteOff+smallArrPtrsHdrSize dflags+ = fixedHdrSize dflags + sIZEOF_StgSmallMutArrPtrs_NoHdr dflags++smallArrPtrsHdrSizeW :: DynFlags -> WordOff+smallArrPtrsHdrSizeW dflags =+ fixedHdrSizeW dflags ++ (sIZEOF_StgSmallMutArrPtrs_NoHdr dflags `quot` wORD_SIZE dflags)++-- Thunks have an extra header word on SMP, so the update doesn't+-- splat the payload.+thunkHdrSize :: DynFlags -> WordOff+thunkHdrSize dflags = fixedHdrSizeW dflags + smp_hdr+ where smp_hdr = sIZEOF_StgSMPThunkHeader dflags `quot` wORD_SIZE dflags++hdrSize :: DynFlags -> SMRep -> ByteOff+hdrSize dflags rep = wordsToBytes dflags (hdrSizeW dflags rep)++hdrSizeW :: DynFlags -> SMRep -> WordOff+hdrSizeW dflags (HeapRep _ _ _ ty) = closureTypeHdrSize dflags ty+hdrSizeW dflags (ArrayPtrsRep _ _) = arrPtrsHdrSizeW dflags+hdrSizeW dflags (SmallArrayPtrsRep _) = smallArrPtrsHdrSizeW dflags+hdrSizeW dflags (ArrayWordsRep _) = arrWordsHdrSizeW dflags+hdrSizeW _ _ = panic "SMRep.hdrSizeW"++nonHdrSize :: DynFlags -> SMRep -> ByteOff+nonHdrSize dflags rep = wordsToBytes dflags (nonHdrSizeW rep)++nonHdrSizeW :: SMRep -> WordOff+nonHdrSizeW (HeapRep _ p np _) = p + np+nonHdrSizeW (ArrayPtrsRep elems ct) = elems + ct+nonHdrSizeW (SmallArrayPtrsRep elems) = elems+nonHdrSizeW (ArrayWordsRep words) = words+nonHdrSizeW (StackRep bs) = length bs+nonHdrSizeW (RTSRep _ rep) = nonHdrSizeW rep++-- | The total size of the closure, in words.+heapClosureSizeW :: DynFlags -> SMRep -> WordOff+heapClosureSizeW dflags (HeapRep _ p np ty)+ = closureTypeHdrSize dflags ty + p + np+heapClosureSizeW dflags (ArrayPtrsRep elems ct)+ = arrPtrsHdrSizeW dflags + elems + ct+heapClosureSizeW dflags (SmallArrayPtrsRep elems)+ = smallArrPtrsHdrSizeW dflags + elems+heapClosureSizeW dflags (ArrayWordsRep words)+ = arrWordsHdrSizeW dflags + words+heapClosureSizeW _ _ = panic "SMRep.heapClosureSize"++closureTypeHdrSize :: DynFlags -> ClosureTypeInfo -> WordOff+closureTypeHdrSize dflags ty = case ty of+ Thunk{} -> thunkHdrSize dflags+ ThunkSelector{} -> thunkHdrSize dflags+ BlackHole{} -> thunkHdrSize dflags+ IndStatic{} -> thunkHdrSize dflags+ _ -> fixedHdrSizeW dflags+ -- All thunks use thunkHdrSize, even if they are non-updatable.+ -- this is because we don't have separate closure types for+ -- updatable vs. non-updatable thunks, so the GC can't tell the+ -- difference. If we ever have significant numbers of non-+ -- updatable thunks, it might be worth fixing this.++-- ---------------------------------------------------------------------------+-- Arrays++-- | The byte offset into the card table of the card for a given element+card :: DynFlags -> Int -> Int+card dflags i = i `shiftR` mUT_ARR_PTRS_CARD_BITS dflags++-- | Convert a number of elements to a number of cards, rounding up+cardRoundUp :: DynFlags -> Int -> Int+cardRoundUp dflags i =+ card dflags (i + ((1 `shiftL` mUT_ARR_PTRS_CARD_BITS dflags) - 1))++-- | The size of a card table, in bytes+cardTableSizeB :: DynFlags -> Int -> ByteOff+cardTableSizeB dflags elems = cardRoundUp dflags elems++-- | The size of a card table, in words+cardTableSizeW :: DynFlags -> Int -> WordOff+cardTableSizeW dflags elems =+ bytesToWordsRoundUp dflags (cardTableSizeB dflags elems)++-----------------------------------------------------------------------------+-- deriving the RTS closure type from an SMRep++#include "rts/storage/ClosureTypes.h"+#include "rts/storage/FunTypes.h"+-- Defines CONSTR, CONSTR_1_0 etc++-- | Derives the RTS closure type from an 'SMRep'+rtsClosureType :: SMRep -> Int+rtsClosureType rep+ = case rep of+ RTSRep ty _ -> ty++ -- See Note [static constructors]+ HeapRep _ 1 0 Constr{} -> CONSTR_1_0+ HeapRep _ 0 1 Constr{} -> CONSTR_0_1+ HeapRep _ 2 0 Constr{} -> CONSTR_2_0+ HeapRep _ 1 1 Constr{} -> CONSTR_1_1+ HeapRep _ 0 2 Constr{} -> CONSTR_0_2+ HeapRep _ 0 _ Constr{} -> CONSTR_NOCAF+ -- See Note [Static NoCaf constructors]+ HeapRep _ _ _ Constr{} -> CONSTR++ HeapRep False 1 0 Fun{} -> FUN_1_0+ HeapRep False 0 1 Fun{} -> FUN_0_1+ HeapRep False 2 0 Fun{} -> FUN_2_0+ HeapRep False 1 1 Fun{} -> FUN_1_1+ HeapRep False 0 2 Fun{} -> FUN_0_2+ HeapRep False _ _ Fun{} -> FUN++ HeapRep False 1 0 Thunk{} -> THUNK_1_0+ HeapRep False 0 1 Thunk{} -> THUNK_0_1+ HeapRep False 2 0 Thunk{} -> THUNK_2_0+ HeapRep False 1 1 Thunk{} -> THUNK_1_1+ HeapRep False 0 2 Thunk{} -> THUNK_0_2+ HeapRep False _ _ Thunk{} -> THUNK++ HeapRep False _ _ ThunkSelector{} -> THUNK_SELECTOR++ HeapRep True _ _ Fun{} -> FUN_STATIC+ HeapRep True _ _ Thunk{} -> THUNK_STATIC++ HeapRep False _ _ BlackHole{} -> BLACKHOLE++ HeapRep False _ _ IndStatic{} -> IND_STATIC++ _ -> panic "rtsClosureType"++-- We export these ones+rET_SMALL, rET_BIG, aRG_GEN, aRG_GEN_BIG :: Int+rET_SMALL = RET_SMALL+rET_BIG = RET_BIG+aRG_GEN = ARG_GEN+aRG_GEN_BIG = ARG_GEN_BIG++{-+Note [static constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~++We used to have a CONSTR_STATIC closure type, and each constructor had+two info tables: one with CONSTR (or CONSTR_1_0 etc.), and one with+CONSTR_STATIC.++This distinction was removed, because when copying a data structure+into a compact region, we must copy static constructors into the+compact region too. If we didn't do this, we would need to track the+references from the compact region out to the static constructors,+because they might (indirectly) refer to CAFs.++Since static constructors will be copied to the heap, if we wanted to+use different info tables for static and dynamic constructors, we+would have to switch the info pointer when copying the constructor+into the compact region, which means we would need an extra field of+the static info table to point to the dynamic one.++However, since the distinction between static and dynamic closure+types is never actually needed (other than for assertions), we can+just drop the distinction and use the same info table for both.++The GC *does* need to distinguish between static and dynamic closures,+but it does this using the HEAP_ALLOCED() macro which checks whether+the address of the closure resides within the dynamic heap.+HEAP_ALLOCED() doesn't read the closure's info table.++Note [Static NoCaf constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we know that a top-level binding 'x' is not Caffy (ie no CAFs are+reachable from 'x'), then a statically allocated constructor (Just x)+is also not Caffy, and the garbage collector need not follow its+argument fields. Exploiting this would require two static info tables+for Just, for the two cases where the argument was Caffy or non-Caffy.++Currently we don't do this; instead we treat nullary constructors+as non-Caffy, and the others as potentially Caffy.+++************************************************************************+* *+ Pretty printing of SMRep and friends+* *+************************************************************************+-}++instance Outputable ClosureTypeInfo where+ ppr = pprTypeInfo++instance Outputable SMRep where+ ppr (HeapRep static ps nps tyinfo)+ = hang (header <+> lbrace) 2 (ppr tyinfo <+> rbrace)+ where+ header = text "HeapRep"+ <+> if static then text "static" else empty+ <+> pp_n "ptrs" ps <+> pp_n "nonptrs" nps+ pp_n :: String -> Int -> SDoc+ pp_n _ 0 = empty+ pp_n s n = int n <+> text s++ ppr (ArrayPtrsRep size _) = text "ArrayPtrsRep" <+> ppr size++ ppr (SmallArrayPtrsRep size) = text "SmallArrayPtrsRep" <+> ppr size++ ppr (ArrayWordsRep words) = text "ArrayWordsRep" <+> ppr words++ ppr (StackRep bs) = text "StackRep" <+> ppr bs++ ppr (RTSRep ty rep) = text "tag:" <> ppr ty <+> ppr rep++instance Outputable ArgDescr where+ ppr (ArgSpec n) = text "ArgSpec" <+> ppr n+ ppr (ArgGen ls) = text "ArgGen" <+> ppr ls++pprTypeInfo :: ClosureTypeInfo -> SDoc+pprTypeInfo (Constr tag descr)+ = text "Con" <+>+ braces (sep [ text "tag:" <+> ppr tag+ , text "descr:" <> text (show descr) ])++pprTypeInfo (Fun arity args)+ = text "Fun" <+>+ braces (sep [ text "arity:" <+> ppr arity+ , ptext (sLit ("fun_type:")) <+> ppr args ])++pprTypeInfo (ThunkSelector offset)+ = text "ThunkSel" <+> ppr offset++pprTypeInfo Thunk = text "Thunk"+pprTypeInfo BlackHole = text "BlackHole"+pprTypeInfo IndStatic = text "IndStatic"++-- XXX Does not belong here!!+stringToWord8s :: String -> [Word8]+stringToWord8s s = map (fromIntegral . ord) s++pprWord8String :: [Word8] -> SDoc+-- Debug printing. Not very clever right now.+pprWord8String ws = text (show ws)
+ codeGen/CgUtils.hs view
@@ -0,0 +1,181 @@+{-# LANGUAGE CPP, GADTs #-}++-----------------------------------------------------------------------------+--+-- Code generator utilities; mostly monadic+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module CgUtils ( fixStgRegisters ) where++#include "HsVersions.h"++import CodeGen.Platform+import Cmm+import Hoopl+import CmmUtils+import CLabel+import DynFlags+import Outputable++-- -----------------------------------------------------------------------------+-- Information about global registers++baseRegOffset :: DynFlags -> GlobalReg -> Int++baseRegOffset dflags (VanillaReg 1 _) = oFFSET_StgRegTable_rR1 dflags+baseRegOffset dflags (VanillaReg 2 _) = oFFSET_StgRegTable_rR2 dflags+baseRegOffset dflags (VanillaReg 3 _) = oFFSET_StgRegTable_rR3 dflags+baseRegOffset dflags (VanillaReg 4 _) = oFFSET_StgRegTable_rR4 dflags+baseRegOffset dflags (VanillaReg 5 _) = oFFSET_StgRegTable_rR5 dflags+baseRegOffset dflags (VanillaReg 6 _) = oFFSET_StgRegTable_rR6 dflags+baseRegOffset dflags (VanillaReg 7 _) = oFFSET_StgRegTable_rR7 dflags+baseRegOffset dflags (VanillaReg 8 _) = oFFSET_StgRegTable_rR8 dflags+baseRegOffset dflags (VanillaReg 9 _) = oFFSET_StgRegTable_rR9 dflags+baseRegOffset dflags (VanillaReg 10 _) = oFFSET_StgRegTable_rR10 dflags+baseRegOffset _ (VanillaReg n _) = panic ("Registers above R10 are not supported (tried to use R" ++ show n ++ ")")+baseRegOffset dflags (FloatReg 1) = oFFSET_StgRegTable_rF1 dflags+baseRegOffset dflags (FloatReg 2) = oFFSET_StgRegTable_rF2 dflags+baseRegOffset dflags (FloatReg 3) = oFFSET_StgRegTable_rF3 dflags+baseRegOffset dflags (FloatReg 4) = oFFSET_StgRegTable_rF4 dflags+baseRegOffset dflags (FloatReg 5) = oFFSET_StgRegTable_rF5 dflags+baseRegOffset dflags (FloatReg 6) = oFFSET_StgRegTable_rF6 dflags+baseRegOffset _ (FloatReg n) = panic ("Registers above F6 are not supported (tried to use F" ++ show n ++ ")")+baseRegOffset dflags (DoubleReg 1) = oFFSET_StgRegTable_rD1 dflags+baseRegOffset dflags (DoubleReg 2) = oFFSET_StgRegTable_rD2 dflags+baseRegOffset dflags (DoubleReg 3) = oFFSET_StgRegTable_rD3 dflags+baseRegOffset dflags (DoubleReg 4) = oFFSET_StgRegTable_rD4 dflags+baseRegOffset dflags (DoubleReg 5) = oFFSET_StgRegTable_rD5 dflags+baseRegOffset dflags (DoubleReg 6) = oFFSET_StgRegTable_rD6 dflags+baseRegOffset _ (DoubleReg n) = panic ("Registers above D6 are not supported (tried to use D" ++ show n ++ ")")+baseRegOffset dflags (XmmReg 1) = oFFSET_StgRegTable_rXMM1 dflags+baseRegOffset dflags (XmmReg 2) = oFFSET_StgRegTable_rXMM2 dflags+baseRegOffset dflags (XmmReg 3) = oFFSET_StgRegTable_rXMM3 dflags+baseRegOffset dflags (XmmReg 4) = oFFSET_StgRegTable_rXMM4 dflags+baseRegOffset dflags (XmmReg 5) = oFFSET_StgRegTable_rXMM5 dflags+baseRegOffset dflags (XmmReg 6) = oFFSET_StgRegTable_rXMM6 dflags+baseRegOffset _ (XmmReg n) = panic ("Registers above XMM6 are not supported (tried to use XMM" ++ show n ++ ")")+baseRegOffset dflags (YmmReg 1) = oFFSET_StgRegTable_rYMM1 dflags+baseRegOffset dflags (YmmReg 2) = oFFSET_StgRegTable_rYMM2 dflags+baseRegOffset dflags (YmmReg 3) = oFFSET_StgRegTable_rYMM3 dflags+baseRegOffset dflags (YmmReg 4) = oFFSET_StgRegTable_rYMM4 dflags+baseRegOffset dflags (YmmReg 5) = oFFSET_StgRegTable_rYMM5 dflags+baseRegOffset dflags (YmmReg 6) = oFFSET_StgRegTable_rYMM6 dflags+baseRegOffset _ (YmmReg n) = panic ("Registers above YMM6 are not supported (tried to use YMM" ++ show n ++ ")")+baseRegOffset dflags (ZmmReg 1) = oFFSET_StgRegTable_rZMM1 dflags+baseRegOffset dflags (ZmmReg 2) = oFFSET_StgRegTable_rZMM2 dflags+baseRegOffset dflags (ZmmReg 3) = oFFSET_StgRegTable_rZMM3 dflags+baseRegOffset dflags (ZmmReg 4) = oFFSET_StgRegTable_rZMM4 dflags+baseRegOffset dflags (ZmmReg 5) = oFFSET_StgRegTable_rZMM5 dflags+baseRegOffset dflags (ZmmReg 6) = oFFSET_StgRegTable_rZMM6 dflags+baseRegOffset _ (ZmmReg n) = panic ("Registers above ZMM6 are not supported (tried to use ZMM" ++ show n ++ ")")+baseRegOffset dflags Sp = oFFSET_StgRegTable_rSp dflags+baseRegOffset dflags SpLim = oFFSET_StgRegTable_rSpLim dflags+baseRegOffset dflags (LongReg 1) = oFFSET_StgRegTable_rL1 dflags+baseRegOffset _ (LongReg n) = panic ("Registers above L1 are not supported (tried to use L" ++ show n ++ ")")+baseRegOffset dflags Hp = oFFSET_StgRegTable_rHp dflags+baseRegOffset dflags HpLim = oFFSET_StgRegTable_rHpLim dflags+baseRegOffset dflags CCCS = oFFSET_StgRegTable_rCCCS dflags+baseRegOffset dflags CurrentTSO = oFFSET_StgRegTable_rCurrentTSO dflags+baseRegOffset dflags CurrentNursery = oFFSET_StgRegTable_rCurrentNursery dflags+baseRegOffset dflags HpAlloc = oFFSET_StgRegTable_rHpAlloc dflags+baseRegOffset dflags EagerBlackholeInfo = oFFSET_stgEagerBlackholeInfo dflags+baseRegOffset dflags GCEnter1 = oFFSET_stgGCEnter1 dflags+baseRegOffset dflags GCFun = oFFSET_stgGCFun dflags+baseRegOffset _ BaseReg = panic "CgUtils.baseRegOffset:BaseReg"+baseRegOffset _ PicBaseReg = panic "CgUtils.baseRegOffset:PicBaseReg"+baseRegOffset _ MachSp = panic "CgUtils.baseRegOffset:MachSp"+baseRegOffset _ UnwindReturnReg = panic "CgUtils.baseRegOffset:UnwindReturnReg"+++-- -----------------------------------------------------------------------------+--+-- STG/Cmm GlobalReg+--+-- -----------------------------------------------------------------------------++-- | We map STG registers onto appropriate CmmExprs. Either they map+-- to real machine registers or stored as offsets from BaseReg. Given+-- a GlobalReg, get_GlobalReg_addr always produces the+-- register table address for it.+get_GlobalReg_addr :: DynFlags -> GlobalReg -> CmmExpr+get_GlobalReg_addr dflags BaseReg = regTableOffset dflags 0+get_GlobalReg_addr dflags mid+ = get_Regtable_addr_from_offset dflags+ (globalRegType dflags mid) (baseRegOffset dflags mid)++-- Calculate a literal representing an offset into the register table.+-- Used when we don't have an actual BaseReg to offset from.+regTableOffset :: DynFlags -> Int -> CmmExpr+regTableOffset dflags n =+ CmmLit (CmmLabelOff mkMainCapabilityLabel (oFFSET_Capability_r dflags + n))++get_Regtable_addr_from_offset :: DynFlags -> CmmType -> Int -> CmmExpr+get_Regtable_addr_from_offset dflags _ offset =+ if haveRegBase (targetPlatform dflags)+ then CmmRegOff (CmmGlobal BaseReg) offset+ else regTableOffset dflags offset++-- | Fixup global registers so that they assign to locations within the+-- RegTable if they aren't pinned for the current target.+fixStgRegisters :: DynFlags -> RawCmmDecl -> RawCmmDecl+fixStgRegisters _ top@(CmmData _ _) = top++fixStgRegisters dflags (CmmProc info lbl live graph) =+ let graph' = modifyGraph (mapGraphBlocks (fixStgRegBlock dflags)) graph+ in CmmProc info lbl live graph'++fixStgRegBlock :: DynFlags -> Block CmmNode e x -> Block CmmNode e x+fixStgRegBlock dflags block = mapBlock (fixStgRegStmt dflags) block++fixStgRegStmt :: DynFlags -> CmmNode e x -> CmmNode e x+fixStgRegStmt dflags stmt = fixAssign $ mapExpDeep fixExpr stmt+ where+ platform = targetPlatform dflags++ fixAssign stmt =+ case stmt of+ CmmAssign (CmmGlobal reg) src+ -- MachSp isn't an STG register; it's merely here for tracking unwind+ -- information+ | reg == MachSp -> stmt+ | otherwise ->+ let baseAddr = get_GlobalReg_addr dflags reg+ in case reg `elem` activeStgRegs (targetPlatform dflags) of+ True -> CmmAssign (CmmGlobal reg) src+ False -> CmmStore baseAddr src+ other_stmt -> other_stmt++ fixExpr expr = case expr of+ -- MachSp isn't an STG; it's merely here for tracking unwind information+ CmmReg (CmmGlobal MachSp) -> expr+ CmmReg (CmmGlobal reg) ->+ -- Replace register leaves with appropriate StixTrees for+ -- the given target. MagicIds which map to a reg on this+ -- arch are left unchanged. For the rest, BaseReg is taken+ -- to mean the address of the reg table in MainCapability,+ -- and for all others we generate an indirection to its+ -- location in the register table.+ case reg `elem` activeStgRegs platform of+ True -> expr+ False ->+ let baseAddr = get_GlobalReg_addr dflags reg+ in case reg of+ BaseReg -> baseAddr+ _other -> CmmLoad baseAddr (globalRegType dflags reg)++ CmmRegOff (CmmGlobal reg) offset ->+ -- RegOf leaves are just a shorthand form. If the reg maps+ -- to a real reg, we keep the shorthand, otherwise, we just+ -- expand it and defer to the above code.+ case reg `elem` activeStgRegs platform of+ True -> expr+ False -> CmmMachOp (MO_Add (wordWidth dflags)) [+ fixExpr (CmmReg (CmmGlobal reg)),+ CmmLit (CmmInt (fromIntegral offset)+ (wordWidth dflags))]++ other_expr -> other_expr+
+ codeGen/CodeGen/Platform.hs view
@@ -0,0 +1,116 @@++module CodeGen.Platform+ (callerSaves, activeStgRegs, haveRegBase, globalRegMaybe, freeReg)+ where++import CmmExpr+import Platform+import Reg++import qualified CodeGen.Platform.ARM as ARM+import qualified CodeGen.Platform.ARM64 as ARM64+import qualified CodeGen.Platform.PPC as PPC+import qualified CodeGen.Platform.PPC_Darwin as PPC_Darwin+import qualified CodeGen.Platform.SPARC as SPARC+import qualified CodeGen.Platform.X86 as X86+import qualified CodeGen.Platform.X86_64 as X86_64+import qualified CodeGen.Platform.NoRegs as NoRegs++-- | Returns 'True' if this global register is stored in a caller-saves+-- machine register.++callerSaves :: Platform -> GlobalReg -> Bool+callerSaves platform+ | platformUnregisterised platform = NoRegs.callerSaves+ | otherwise+ = case platformArch platform of+ ArchX86 -> X86.callerSaves+ ArchX86_64 -> X86_64.callerSaves+ ArchSPARC -> SPARC.callerSaves+ ArchARM {} -> ARM.callerSaves+ ArchARM64 -> ARM64.callerSaves+ arch+ | arch `elem` [ArchPPC, ArchPPC_64 ELF_V1, ArchPPC_64 ELF_V2] ->+ case platformOS platform of+ OSDarwin -> PPC_Darwin.callerSaves+ _ -> PPC.callerSaves++ | otherwise -> NoRegs.callerSaves++-- | Here is where the STG register map is defined for each target arch.+-- The order matters (for the llvm backend anyway)! We must make sure to+-- maintain the order here with the order used in the LLVM calling conventions.+-- Note that also, this isn't all registers, just the ones that are currently+-- possbily mapped to real registers.+activeStgRegs :: Platform -> [GlobalReg]+activeStgRegs platform+ | platformUnregisterised platform = NoRegs.activeStgRegs+ | otherwise+ = case platformArch platform of+ ArchX86 -> X86.activeStgRegs+ ArchX86_64 -> X86_64.activeStgRegs+ ArchSPARC -> SPARC.activeStgRegs+ ArchARM {} -> ARM.activeStgRegs+ ArchARM64 -> ARM64.activeStgRegs+ arch+ | arch `elem` [ArchPPC, ArchPPC_64 ELF_V1, ArchPPC_64 ELF_V2] ->+ case platformOS platform of+ OSDarwin -> PPC_Darwin.activeStgRegs+ _ -> PPC.activeStgRegs++ | otherwise -> NoRegs.activeStgRegs++haveRegBase :: Platform -> Bool+haveRegBase platform+ | platformUnregisterised platform = NoRegs.haveRegBase+ | otherwise+ = case platformArch platform of+ ArchX86 -> X86.haveRegBase+ ArchX86_64 -> X86_64.haveRegBase+ ArchSPARC -> SPARC.haveRegBase+ ArchARM {} -> ARM.haveRegBase+ ArchARM64 -> ARM64.haveRegBase+ arch+ | arch `elem` [ArchPPC, ArchPPC_64 ELF_V1, ArchPPC_64 ELF_V2] ->+ case platformOS platform of+ OSDarwin -> PPC_Darwin.haveRegBase+ _ -> PPC.haveRegBase++ | otherwise -> NoRegs.haveRegBase++globalRegMaybe :: Platform -> GlobalReg -> Maybe RealReg+globalRegMaybe platform+ | platformUnregisterised platform = NoRegs.globalRegMaybe+ | otherwise+ = case platformArch platform of+ ArchX86 -> X86.globalRegMaybe+ ArchX86_64 -> X86_64.globalRegMaybe+ ArchSPARC -> SPARC.globalRegMaybe+ ArchARM {} -> ARM.globalRegMaybe+ ArchARM64 -> ARM64.globalRegMaybe+ arch+ | arch `elem` [ArchPPC, ArchPPC_64 ELF_V1, ArchPPC_64 ELF_V2] ->+ case platformOS platform of+ OSDarwin -> PPC_Darwin.globalRegMaybe+ _ -> PPC.globalRegMaybe++ | otherwise -> NoRegs.globalRegMaybe++freeReg :: Platform -> RegNo -> Bool+freeReg platform+ | platformUnregisterised platform = NoRegs.freeReg+ | otherwise+ = case platformArch platform of+ ArchX86 -> X86.freeReg+ ArchX86_64 -> X86_64.freeReg+ ArchSPARC -> SPARC.freeReg+ ArchARM {} -> ARM.freeReg+ ArchARM64 -> ARM64.freeReg+ arch+ | arch `elem` [ArchPPC, ArchPPC_64 ELF_V1, ArchPPC_64 ELF_V2] ->+ case platformOS platform of+ OSDarwin -> PPC_Darwin.freeReg+ _ -> PPC.freeReg++ | otherwise -> NoRegs.freeReg+
+ codeGen/CodeGen/Platform/ARM.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.ARM where++#define MACHREGS_NO_REGS 0+#define MACHREGS_arm 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/ARM64.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.ARM64 where++#define MACHREGS_NO_REGS 0+#define MACHREGS_aarch64 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/NoRegs.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.NoRegs where++#define MACHREGS_NO_REGS 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/PPC.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.PPC where++#define MACHREGS_NO_REGS 0+#define MACHREGS_powerpc 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/PPC_Darwin.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.PPC_Darwin where++#define MACHREGS_NO_REGS 0+#define MACHREGS_powerpc 1+#define MACHREGS_darwin 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/SPARC.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.SPARC where++#define MACHREGS_NO_REGS 0+#define MACHREGS_sparc 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/X86.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.X86 where++#define MACHREGS_NO_REGS 0+#define MACHREGS_i386 1+#include "CodeGen.Platform.hs"+
+ codeGen/CodeGen/Platform/X86_64.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE CPP #-}++module CodeGen.Platform.X86_64 where++#define MACHREGS_NO_REGS 0+#define MACHREGS_x86_64 1+#include "CodeGen.Platform.hs"+
+ codeGen/StgCmm.hs view
@@ -0,0 +1,284 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Stg to C-- code generation+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmm ( codeGen ) where++#include "HsVersions.h"++import StgCmmProf (initCostCentres, ldvEnter)+import StgCmmMonad+import StgCmmEnv+import StgCmmBind+import StgCmmCon+import StgCmmLayout+import StgCmmUtils+import StgCmmClosure+import StgCmmHpc+import StgCmmTicky++import Cmm+import CmmUtils+import CLabel++import StgSyn+import DynFlags++import HscTypes+import CostCentre+import Id+import IdInfo+import RepType+import DataCon+import Name+import TyCon+import Module+import Outputable+import Stream+import BasicTypes++import OrdList+import MkGraph++import qualified Data.ByteString as BS+import Data.IORef+import Control.Monad (when,void)+import Util++codeGen :: DynFlags+ -> Module+ -> [TyCon]+ -> CollectedCCs -- (Local/global) cost-centres needing declaring/registering.+ -> [StgTopBinding] -- Bindings to convert+ -> HpcInfo+ -> Stream IO CmmGroup () -- Output as a stream, so codegen can+ -- be interleaved with output++codeGen dflags this_mod data_tycons+ cost_centre_info stg_binds hpc_info+ = do { -- cg: run the code generator, and yield the resulting CmmGroup+ -- Using an IORef to store the state is a bit crude, but otherwise+ -- we would need to add a state monad layer.+ ; cgref <- liftIO $ newIORef =<< initC+ ; let cg :: FCode () -> Stream IO CmmGroup ()+ cg fcode = do+ cmm <- liftIO $ do+ st <- readIORef cgref+ let (a,st') = runC dflags this_mod st (getCmm fcode)++ -- NB. stub-out cgs_tops and cgs_stmts. This fixes+ -- a big space leak. DO NOT REMOVE!+ writeIORef cgref $! st'{ cgs_tops = nilOL,+ cgs_stmts = mkNop }+ return a+ yield cmm++ -- Note [codegen-split-init] the cmm_init block must come+ -- FIRST. This is because when -split-objs is on we need to+ -- combine this block with its initialisation routines; see+ -- Note [pipeline-split-init].+ ; cg (mkModuleInit cost_centre_info this_mod hpc_info)++ ; mapM_ (cg . cgTopBinding dflags) stg_binds++ -- Put datatype_stuff after code_stuff, because the+ -- datatype closure table (for enumeration types) to+ -- (say) PrelBase_True_closure, which is defined in+ -- code_stuff+ ; let do_tycon tycon = do+ -- Generate a table of static closures for an+ -- enumeration type Note that the closure pointers are+ -- tagged.+ when (isEnumerationTyCon tycon) $ cg (cgEnumerationTyCon tycon)+ mapM_ (cg . cgDataCon) (tyConDataCons tycon)++ ; mapM_ do_tycon data_tycons+ }++---------------------------------------------------------------+-- Top-level bindings+---------------------------------------------------------------++{- 'cgTopBinding' is only used for top-level bindings, since they need+to be allocated statically (not in the heap) and need to be labelled.+No unboxed bindings can happen at top level.++In the code below, the static bindings are accumulated in the+@MkCgState@, and transferred into the ``statics'' slot by @forkStatics@.+This is so that we can write the top level processing in a compositional+style, with the increasing static environment being plumbed as a state+variable. -}++cgTopBinding :: DynFlags -> StgTopBinding -> FCode ()+cgTopBinding dflags (StgTopLifted (StgNonRec id rhs))+ = do { id' <- maybeExternaliseId dflags id+ ; let (info, fcode) = cgTopRhs dflags NonRecursive id' rhs+ ; fcode+ ; addBindC info -- Add the *un-externalised* Id to the envt,+ -- so we find it when we look up occurrences+ }++cgTopBinding dflags (StgTopLifted (StgRec pairs))+ = do { let (bndrs, rhss) = unzip pairs+ ; bndrs' <- Prelude.mapM (maybeExternaliseId dflags) bndrs+ ; let pairs' = zip bndrs' rhss+ r = unzipWith (cgTopRhs dflags Recursive) pairs'+ (infos, fcodes) = unzip r+ ; addBindsC infos+ ; sequence_ fcodes+ }++cgTopBinding dflags (StgTopStringLit id str)+ = do { id' <- maybeExternaliseId dflags id+ ; let label = mkBytesLabel (idName id')+ ; let (lit, decl) = mkByteStringCLit label (BS.unpack str)+ ; emitDecl decl+ ; addBindC (litIdInfo dflags id' mkLFStringLit lit)+ }++cgTopRhs :: DynFlags -> RecFlag -> Id -> StgRhs -> (CgIdInfo, FCode ())+ -- The Id is passed along for setting up a binding...+ -- It's already been externalised if necessary++cgTopRhs dflags _rec bndr (StgRhsCon _cc con args)+ = cgTopRhsCon dflags bndr con (assertNonVoidStgArgs args)+ -- con args are always non-void,+ -- see Note [Post-unarisation invariants] in UnariseStg++cgTopRhs dflags rec bndr (StgRhsClosure cc bi fvs upd_flag args body)+ = ASSERT(null fvs) -- There should be no free variables+ cgTopRhsClosure dflags rec bndr cc bi upd_flag args body+++---------------------------------------------------------------+-- Module initialisation code+---------------------------------------------------------------++{- The module initialisation code looks like this, roughly:++ FN(__stginit_Foo) {+ JMP_(__stginit_Foo_1_p)+ }++ FN(__stginit_Foo_1_p) {+ ...+ }++ We have one version of the init code with a module version and the+ 'way' attached to it. The version number helps to catch cases+ where modules are not compiled in dependency order before being+ linked: if a module has been compiled since any modules which depend on+ it, then the latter modules will refer to a different version in their+ init blocks and a link error will ensue.++ The 'way' suffix helps to catch cases where modules compiled in different+ ways are linked together (eg. profiled and non-profiled).++ We provide a plain, unadorned, version of the module init code+ which just jumps to the version with the label and way attached. The+ reason for this is that when using foreign exports, the caller of+ startupHaskell() must supply the name of the init function for the "top"+ module in the program, and we don't want to require that this name+ has the version and way info appended to it.++We initialise the module tree by keeping a work-stack,+ * pointed to by Sp+ * that grows downward+ * Sp points to the last occupied slot+-}++mkModuleInit+ :: CollectedCCs -- cost centre info+ -> Module+ -> HpcInfo+ -> FCode ()++mkModuleInit cost_centre_info this_mod hpc_info+ = do { initHpc this_mod hpc_info+ ; initCostCentres cost_centre_info+ -- For backwards compatibility: user code may refer to this+ -- label for calling hs_add_root().+ ; let lbl = mkPlainModuleInitLabel this_mod+ ; emitDecl (CmmData (Section Data lbl) (Statics lbl []))+ }+++---------------------------------------------------------------+-- Generating static stuff for algebraic data types+---------------------------------------------------------------+++cgEnumerationTyCon :: TyCon -> FCode ()+cgEnumerationTyCon tycon+ = do dflags <- getDynFlags+ emitRODataLits (mkLocalClosureTableLabel (tyConName tycon) NoCafRefs)+ [ CmmLabelOff (mkLocalClosureLabel (dataConName con) NoCafRefs)+ (tagForCon dflags con)+ | con <- tyConDataCons tycon]+++cgDataCon :: DataCon -> FCode ()+-- Generate the entry code, info tables, and (for niladic constructor)+-- the static closure, for a constructor.+cgDataCon data_con+ = do { dflags <- getDynFlags+ ; let+ (tot_wds, -- #ptr_wds + #nonptr_wds+ ptr_wds) -- #ptr_wds+ = mkVirtConstrSizes dflags arg_reps++ nonptr_wds = tot_wds - ptr_wds++ dyn_info_tbl =+ mkDataConInfoTable dflags data_con False ptr_wds nonptr_wds++ -- We're generating info tables, so we don't know and care about+ -- what the actual arguments are. Using () here as the place holder.+ arg_reps :: [NonVoid PrimRep]+ arg_reps = [ NonVoid rep_ty+ | ty <- dataConRepArgTys data_con+ , rep_ty <- typePrimRep ty+ , not (isVoidRep rep_ty) ]++ ; emitClosureAndInfoTable dyn_info_tbl NativeDirectCall [] $+ -- NB: the closure pointer is assumed *untagged* on+ -- entry to a constructor. If the pointer is tagged,+ -- then we should not be entering it. This assumption+ -- is used in ldvEnter and when tagging the pointer to+ -- return it.+ -- NB 2: We don't set CC when entering data (WDP 94/06)+ do { tickyEnterDynCon+ ; ldvEnter (CmmReg nodeReg)+ ; tickyReturnOldCon (length arg_reps)+ ; void $ emitReturn [cmmOffsetB dflags (CmmReg nodeReg) (tagForCon dflags data_con)]+ }+ -- The case continuation code expects a tagged pointer+ }++---------------------------------------------------------------+-- Stuff to support splitting+---------------------------------------------------------------++maybeExternaliseId :: DynFlags -> Id -> FCode Id+maybeExternaliseId dflags id+ | gopt Opt_SplitObjs dflags, -- See Note [Externalise when splitting]+ -- in StgCmmMonad+ isInternalName name = do { mod <- getModuleName+ ; returnFC (setIdName id (externalise mod)) }+ | otherwise = returnFC id+ where+ externalise mod = mkExternalName uniq mod new_occ loc+ name = idName id+ uniq = nameUnique name+ new_occ = mkLocalOcc uniq (nameOccName name)+ loc = nameSrcSpan name+ -- We want to conjure up a name that can't clash with any+ -- existing name. So we generate+ -- Mod_$L243foo+ -- where 243 is the unique.
+ codeGen/StgCmmArgRep.hs view
@@ -0,0 +1,152 @@+-----------------------------------------------------------------------------+--+-- Argument representations used in StgCmmLayout.+--+-- (c) The University of Glasgow 2013+--+-----------------------------------------------------------------------------++module StgCmmArgRep (+ ArgRep(..), toArgRep, argRepSizeW,++ argRepString, isNonV, idArgRep,++ slowCallPattern,++ ) where++import StgCmmClosure ( idPrimRep )++import SMRep ( WordOff )+import Id ( Id )+import TyCon ( PrimRep(..), primElemRepSizeB )+import BasicTypes ( RepArity )+import Constants ( wORD64_SIZE )+import DynFlags++import Outputable+import FastString++-- I extricated this code as this new module in order to avoid a+-- cyclic dependency between StgCmmLayout and StgCmmTicky.+--+-- NSF 18 Feb 2013++-------------------------------------------------------------------------+-- Classifying arguments: ArgRep+-------------------------------------------------------------------------++-- ArgRep is re-exported by StgCmmLayout, but only for use in the+-- byte-code generator which also needs to know about the+-- classification of arguments.++data ArgRep = P -- GC Ptr+ | N -- Word-sized non-ptr+ | L -- 64-bit non-ptr (long)+ | V -- Void+ | F -- Float+ | D -- Double+ | V16 -- 16-byte (128-bit) vectors of Float/Double/Int8/Word32/etc.+ | V32 -- 32-byte (256-bit) vectors of Float/Double/Int8/Word32/etc.+ | V64 -- 64-byte (512-bit) vectors of Float/Double/Int8/Word32/etc.+instance Outputable ArgRep where ppr = text . argRepString++argRepString :: ArgRep -> String+argRepString P = "P"+argRepString N = "N"+argRepString L = "L"+argRepString V = "V"+argRepString F = "F"+argRepString D = "D"+argRepString V16 = "V16"+argRepString V32 = "V32"+argRepString V64 = "V64"++toArgRep :: PrimRep -> ArgRep+toArgRep VoidRep = V+toArgRep LiftedRep = P+toArgRep UnliftedRep = P+toArgRep IntRep = N+toArgRep WordRep = N+toArgRep AddrRep = N+toArgRep Int64Rep = L+toArgRep Word64Rep = L+toArgRep FloatRep = F+toArgRep DoubleRep = D+toArgRep (VecRep len elem) = case len*primElemRepSizeB elem of+ 16 -> V16+ 32 -> V32+ 64 -> V64+ _ -> error "toArgRep: bad vector primrep"++isNonV :: ArgRep -> Bool+isNonV V = False+isNonV _ = True++argRepSizeW :: DynFlags -> ArgRep -> WordOff -- Size in words+argRepSizeW _ N = 1+argRepSizeW _ P = 1+argRepSizeW _ F = 1+argRepSizeW dflags L = wORD64_SIZE `quot` wORD_SIZE dflags+argRepSizeW dflags D = dOUBLE_SIZE dflags `quot` wORD_SIZE dflags+argRepSizeW _ V = 0+argRepSizeW dflags V16 = 16 `quot` wORD_SIZE dflags+argRepSizeW dflags V32 = 32 `quot` wORD_SIZE dflags+argRepSizeW dflags V64 = 64 `quot` wORD_SIZE dflags++idArgRep :: Id -> ArgRep+idArgRep = toArgRep . idPrimRep++-- This list of argument patterns should be kept in sync with at least+-- the following:+--+-- * StgCmmLayout.stdPattern maybe to some degree?+--+-- * the RTS_RET(stg_ap_*) and RTS_FUN_DECL(stg_ap_*_fast)+-- declarations in includes/stg/MiscClosures.h+--+-- * the SLOW_CALL_*_ctr declarations in includes/stg/Ticky.h,+--+-- * the TICK_SLOW_CALL_*() #defines in includes/Cmm.h,+--+-- * the PR_CTR(SLOW_CALL_*_ctr) calls in rts/Ticky.c,+--+-- * and the SymI_HasProto(stg_ap_*_{ret,info,fast}) calls and+-- SymI_HasProto(SLOW_CALL_*_ctr) calls in rts/Linker.c+--+-- There may be more places that I haven't found; I merely igrep'd for+-- pppppp and excluded things that seemed ghci-specific.+--+-- Also, it seems at the moment that ticky counters with void+-- arguments will never be bumped, but I'm still declaring those+-- counters, defensively.+--+-- NSF 6 Mar 2013++slowCallPattern :: [ArgRep] -> (FastString, RepArity)+-- Returns the generic apply function and arity+--+-- The first batch of cases match (some) specialised entries+-- The last group deals exhaustively with the cases for the first argument+-- (and the zero-argument case)+--+-- In 99% of cases this function will match *all* the arguments in one batch++slowCallPattern (P: P: P: P: P: P: _) = (fsLit "stg_ap_pppppp", 6)+slowCallPattern (P: P: P: P: P: _) = (fsLit "stg_ap_ppppp", 5)+slowCallPattern (P: P: P: P: _) = (fsLit "stg_ap_pppp", 4)+slowCallPattern (P: P: P: V: _) = (fsLit "stg_ap_pppv", 4)+slowCallPattern (P: P: P: _) = (fsLit "stg_ap_ppp", 3)+slowCallPattern (P: P: V: _) = (fsLit "stg_ap_ppv", 3)+slowCallPattern (P: P: _) = (fsLit "stg_ap_pp", 2)+slowCallPattern (P: V: _) = (fsLit "stg_ap_pv", 2)+slowCallPattern (P: _) = (fsLit "stg_ap_p", 1)+slowCallPattern (V: _) = (fsLit "stg_ap_v", 1)+slowCallPattern (N: _) = (fsLit "stg_ap_n", 1)+slowCallPattern (F: _) = (fsLit "stg_ap_f", 1)+slowCallPattern (D: _) = (fsLit "stg_ap_d", 1)+slowCallPattern (L: _) = (fsLit "stg_ap_l", 1)+slowCallPattern (V16: _) = (fsLit "stg_ap_v16", 1)+slowCallPattern (V32: _) = (fsLit "stg_ap_v32", 1)+slowCallPattern (V64: _) = (fsLit "stg_ap_v64", 1)+slowCallPattern [] = (fsLit "stg_ap_0", 0)
+ codeGen/StgCmmBind.hs view
@@ -0,0 +1,755 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Stg to C-- code generation: bindings+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmBind (+ cgTopRhsClosure,+ cgBind,+ emitBlackHoleCode,+ pushUpdateFrame, emitUpdateFrame+ ) where++#include "HsVersions.h"++import StgCmmExpr+import StgCmmMonad+import StgCmmEnv+import StgCmmCon+import StgCmmHeap+import StgCmmProf (curCCS, ldvEnterClosure, enterCostCentreFun, enterCostCentreThunk,+ initUpdFrameProf)+import StgCmmTicky+import StgCmmLayout+import StgCmmUtils+import StgCmmClosure+import StgCmmForeign (emitPrimCall)++import MkGraph+import CoreSyn ( AltCon(..), tickishIsCode )+import BlockId+import SMRep+import Cmm+import CmmInfo+import CmmUtils+import CLabel+import StgSyn+import CostCentre+import Id+import IdInfo+import Name+import Module+import ListSetOps+import Util+import BasicTypes+import Outputable+import FastString+import DynFlags++import Control.Monad++import Prelude hiding ((<*>))++------------------------------------------------------------------------+-- Top-level bindings+------------------------------------------------------------------------++-- For closures bound at top level, allocate in static space.+-- They should have no free variables.++cgTopRhsClosure :: DynFlags+ -> RecFlag -- member of a recursive group?+ -> Id+ -> CostCentreStack -- Optional cost centre annotation+ -> StgBinderInfo+ -> UpdateFlag+ -> [Id] -- Args+ -> StgExpr+ -> (CgIdInfo, FCode ())++cgTopRhsClosure dflags rec id ccs _ upd_flag args body =+ let closure_label = mkLocalClosureLabel (idName id) (idCafInfo id)+ cg_id_info = litIdInfo dflags id lf_info (CmmLabel closure_label)+ lf_info = mkClosureLFInfo dflags id TopLevel [] upd_flag args+ in (cg_id_info, gen_code dflags lf_info closure_label)+ where+ -- special case for a indirection (f = g). We create an IND_STATIC+ -- closure pointing directly to the indirectee. This is exactly+ -- what the CAF will eventually evaluate to anyway, we're just+ -- shortcutting the whole process, and generating a lot less code+ -- (#7308)+ --+ -- Note: we omit the optimisation when this binding is part of a+ -- recursive group, because the optimisation would inhibit the black+ -- hole detection from working in that case. Test+ -- concurrent/should_run/4030 fails, for instance.+ --+ gen_code dflags _ closure_label+ | StgApp f [] <- body, null args, isNonRec rec+ = do+ cg_info <- getCgIdInfo f+ let closure_rep = mkStaticClosureFields dflags+ indStaticInfoTable ccs MayHaveCafRefs+ [unLit (idInfoToAmode cg_info)]+ emitDataLits closure_label closure_rep+ return ()++ gen_code dflags lf_info closure_label+ = do { -- LAY OUT THE OBJECT+ let name = idName id+ ; mod_name <- getModuleName+ ; let descr = closureDescription dflags mod_name name+ closure_info = mkClosureInfo dflags True id lf_info 0 0 descr++ caffy = idCafInfo id+ info_tbl = mkCmmInfo closure_info -- XXX short-cut+ closure_rep = mkStaticClosureFields dflags info_tbl ccs caffy []++ -- BUILD THE OBJECT, AND GENERATE INFO TABLE (IF NECESSARY)+ ; emitDataLits closure_label closure_rep+ ; let fv_details :: [(NonVoid Id, VirtualHpOffset)]+ (_, _, fv_details) = mkVirtHeapOffsets dflags (isLFThunk lf_info) []+ -- Don't drop the non-void args until the closure info has been made+ ; forkClosureBody (closureCodeBody True id closure_info ccs+ (nonVoidIds args) (length args) body fv_details)++ ; return () }++ unLit (CmmLit l) = l+ unLit _ = panic "unLit"++------------------------------------------------------------------------+-- Non-top-level bindings+------------------------------------------------------------------------++cgBind :: StgBinding -> FCode ()+cgBind (StgNonRec name rhs)+ = do { (info, fcode) <- cgRhs name rhs+ ; addBindC info+ ; init <- fcode+ ; emit init }+ -- init cannot be used in body, so slightly better to sink it eagerly++cgBind (StgRec pairs)+ = do { r <- sequence $ unzipWith cgRhs pairs+ ; let (id_infos, fcodes) = unzip r+ ; addBindsC id_infos+ ; (inits, body) <- getCodeR $ sequence fcodes+ ; emit (catAGraphs inits <*> body) }++{- Note [cgBind rec]++ Recursive let-bindings are tricky.+ Consider the following pseudocode:++ let x = \_ -> ... y ...+ y = \_ -> ... z ...+ z = \_ -> ... x ...+ in ...++ For each binding, we need to allocate a closure, and each closure must+ capture the address of the other closures.+ We want to generate the following C-- code:+ // Initialization Code+ x = hp - 24; // heap address of x's closure+ y = hp - 40; // heap address of x's closure+ z = hp - 64; // heap address of x's closure+ // allocate and initialize x+ m[hp-8] = ...+ m[hp-16] = y // the closure for x captures y+ m[hp-24] = x_info;+ // allocate and initialize y+ m[hp-32] = z; // the closure for y captures z+ m[hp-40] = y_info;+ // allocate and initialize z+ ...++ For each closure, we must generate not only the code to allocate and+ initialize the closure itself, but also some initialization Code that+ sets a variable holding the closure pointer.++ We could generate a pair of the (init code, body code), but since+ the bindings are recursive we also have to initialise the+ environment with the CgIdInfo for all the bindings before compiling+ anything. So we do this in 3 stages:++ 1. collect all the CgIdInfos and initialise the environment+ 2. compile each binding into (init, body) code+ 3. emit all the inits, and then all the bodies++ We'd rather not have separate functions to do steps 1 and 2 for+ each binding, since in pratice they share a lot of code. So we+ have just one function, cgRhs, that returns a pair of the CgIdInfo+ for step 1, and a monadic computation to generate the code in step+ 2.++ The alternative to separating things in this way is to use a+ fixpoint. That's what we used to do, but it introduces a+ maintenance nightmare because there is a subtle dependency on not+ being too strict everywhere. Doing things this way means that the+ FCode monad can be strict, for example.+ -}++cgRhs :: Id+ -> StgRhs+ -> FCode (+ CgIdInfo -- The info for this binding+ , FCode CmmAGraph -- A computation which will generate the+ -- code for the binding, and return an+ -- assignent of the form "x = Hp - n"+ -- (see above)+ )++cgRhs id (StgRhsCon cc con args)+ = withNewTickyCounterCon (idName id) $+ buildDynCon id True cc con (assertNonVoidStgArgs args)+ -- con args are always non-void,+ -- see Note [Post-unarisation invariants] in UnariseStg++{- See Note [GC recovery] in compiler/codeGen/StgCmmClosure.hs -}+cgRhs id (StgRhsClosure cc bi fvs upd_flag args body)+ = do dflags <- getDynFlags+ mkRhsClosure dflags id cc bi (nonVoidIds fvs) upd_flag args body++------------------------------------------------------------------------+-- Non-constructor right hand sides+------------------------------------------------------------------------++mkRhsClosure :: DynFlags -> Id -> CostCentreStack -> StgBinderInfo+ -> [NonVoid Id] -- Free vars+ -> UpdateFlag+ -> [Id] -- Args+ -> StgExpr+ -> FCode (CgIdInfo, FCode CmmAGraph)++{- mkRhsClosure looks for two special forms of the right-hand side:+ a) selector thunks+ b) AP thunks++If neither happens, it just calls mkClosureLFInfo. You might think+that mkClosureLFInfo should do all this, but it seems wrong for the+latter to look at the structure of an expression++Note [Selectors]+~~~~~~~~~~~~~~~~+We look at the body of the closure to see if it's a selector---turgid,+but nothing deep. We are looking for a closure of {\em exactly} the+form:++... = [the_fv] \ u [] ->+ case the_fv of+ con a_1 ... a_n -> a_i++Note [Ap thunks]+~~~~~~~~~~~~~~~~+A more generic AP thunk of the form++ x = [ x_1...x_n ] \.. [] -> x_1 ... x_n++A set of these is compiled statically into the RTS, so we just use+those. We could extend the idea to thunks where some of the x_i are+global ids (and hence not free variables), but this would entail+generating a larger thunk. It might be an option for non-optimising+compilation, though.++We only generate an Ap thunk if all the free variables are pointers,+for semi-obvious reasons.++-}++---------- Note [Selectors] ------------------+mkRhsClosure dflags bndr _cc _bi+ [NonVoid the_fv] -- Just one free var+ upd_flag -- Updatable thunk+ [] -- A thunk+ expr+ | let strip = snd . stripStgTicksTop (not . tickishIsCode)+ , StgCase (StgApp scrutinee [{-no args-}])+ _ -- ignore bndr+ (AlgAlt _)+ [(DataAlt _, params, sel_expr)] <- strip expr+ , StgApp selectee [{-no args-}] <- strip sel_expr+ , the_fv == scrutinee -- Scrutinee is the only free variable++ , let (_, _, params_w_offsets) = mkVirtConstrOffsets dflags (addIdReps (assertNonVoidIds params))+ -- pattern binders are always non-void,+ -- see Note [Post-unarisation invariants] in UnariseStg+ , Just the_offset <- assocMaybe params_w_offsets (NonVoid selectee)++ , let offset_into_int = bytesToWordsRoundUp dflags the_offset+ - fixedHdrSizeW dflags+ , offset_into_int <= mAX_SPEC_SELECTEE_SIZE dflags -- Offset is small enough+ = -- NOT TRUE: ASSERT(is_single_constructor)+ -- The simplifier may have statically determined that the single alternative+ -- is the only possible case and eliminated the others, even if there are+ -- other constructors in the datatype. It's still ok to make a selector+ -- thunk in this case, because we *know* which constructor the scrutinee+ -- will evaluate to.+ --+ -- srt is discarded; it must be empty+ let lf_info = mkSelectorLFInfo bndr offset_into_int (isUpdatable upd_flag)+ in cgRhsStdThunk bndr lf_info [StgVarArg the_fv]++---------- Note [Ap thunks] ------------------+mkRhsClosure dflags bndr _cc _bi+ fvs+ upd_flag+ [] -- No args; a thunk+ (StgApp fun_id args)++ -- We are looking for an "ApThunk"; see data con ApThunk in StgCmmClosure+ -- of form (x1 x2 .... xn), where all the xi are locals (not top-level)+ -- So the xi will all be free variables+ | args `lengthIs` (n_fvs-1) -- This happens only if the fun_id and+ -- args are all distinct local variables+ -- The "-1" is for fun_id+ -- Missed opportunity: (f x x) is not detected+ , all (isGcPtrRep . idPrimRep . fromNonVoid) fvs+ , isUpdatable upd_flag+ , n_fvs <= mAX_SPEC_AP_SIZE dflags+ , not (gopt Opt_SccProfilingOn dflags)+ -- not when profiling: we don't want to+ -- lose information about this particular+ -- thunk (e.g. its type) (#949)++ -- Ha! an Ap thunk+ = cgRhsStdThunk bndr lf_info payload++ where+ n_fvs = length fvs+ lf_info = mkApLFInfo bndr upd_flag n_fvs+ -- the payload has to be in the correct order, hence we can't+ -- just use the fvs.+ payload = StgVarArg fun_id : args++---------- Default case ------------------+mkRhsClosure dflags bndr cc _ fvs upd_flag args body+ = do { let lf_info = mkClosureLFInfo dflags bndr NotTopLevel fvs upd_flag args+ ; (id_info, reg) <- rhsIdInfo bndr lf_info+ ; return (id_info, gen_code lf_info reg) }+ where+ gen_code lf_info reg+ = do { -- LAY OUT THE OBJECT+ -- If the binder is itself a free variable, then don't store+ -- it in the closure. Instead, just bind it to Node on entry.+ -- NB we can be sure that Node will point to it, because we+ -- haven't told mkClosureLFInfo about this; so if the binder+ -- _was_ a free var of its RHS, mkClosureLFInfo thinks it *is*+ -- stored in the closure itself, so it will make sure that+ -- Node points to it...+ ; let reduced_fvs = filter (NonVoid bndr /=) fvs++ -- MAKE CLOSURE INFO FOR THIS CLOSURE+ ; mod_name <- getModuleName+ ; dflags <- getDynFlags+ ; let name = idName bndr+ descr = closureDescription dflags mod_name name+ fv_details :: [(NonVoid Id, ByteOff)]+ (tot_wds, ptr_wds, fv_details)+ = mkVirtHeapOffsets dflags (isLFThunk lf_info)+ (addIdReps reduced_fvs)+ closure_info = mkClosureInfo dflags False -- Not static+ bndr lf_info tot_wds ptr_wds+ descr++ -- BUILD ITS INFO TABLE AND CODE+ ; forkClosureBody $+ -- forkClosureBody: (a) ensure that bindings in here are not seen elsewhere+ -- (b) ignore Sequel from context; use empty Sequel+ -- And compile the body+ closureCodeBody False bndr closure_info cc (nonVoidIds args)+ (length args) body fv_details++ -- BUILD THE OBJECT+-- ; (use_cc, blame_cc) <- chooseDynCostCentres cc args body+ ; let use_cc = curCCS; blame_cc = curCCS+ ; emit (mkComment $ mkFastString "calling allocDynClosure")+ ; let toVarArg (NonVoid a, off) = (NonVoid (StgVarArg a), off)+ ; let info_tbl = mkCmmInfo closure_info+ ; hp_plus_n <- allocDynClosure (Just bndr) info_tbl lf_info use_cc blame_cc+ (map toVarArg fv_details)++ -- RETURN+ ; return (mkRhsInit dflags reg lf_info hp_plus_n) }++-------------------------+cgRhsStdThunk+ :: Id+ -> LambdaFormInfo+ -> [StgArg] -- payload+ -> FCode (CgIdInfo, FCode CmmAGraph)++cgRhsStdThunk bndr lf_info payload+ = do { (id_info, reg) <- rhsIdInfo bndr lf_info+ ; return (id_info, gen_code reg)+ }+ where+ gen_code reg -- AHA! A STANDARD-FORM THUNK+ = withNewTickyCounterStdThunk (lfUpdatable lf_info) (idName bndr) $+ do+ { -- LAY OUT THE OBJECT+ mod_name <- getModuleName+ ; dflags <- getDynFlags+ ; let (tot_wds, ptr_wds, payload_w_offsets)+ = mkVirtHeapOffsets dflags (isLFThunk lf_info)+ (addArgReps (nonVoidStgArgs payload))++ descr = closureDescription dflags mod_name (idName bndr)+ closure_info = mkClosureInfo dflags False -- Not static+ bndr lf_info tot_wds ptr_wds+ descr++-- ; (use_cc, blame_cc) <- chooseDynCostCentres cc [{- no args-}] body+ ; let use_cc = curCCS; blame_cc = curCCS+++ -- BUILD THE OBJECT+ ; let info_tbl = mkCmmInfo closure_info+ ; hp_plus_n <- allocDynClosure (Just bndr) info_tbl lf_info+ use_cc blame_cc payload_w_offsets++ -- RETURN+ ; return (mkRhsInit dflags reg lf_info hp_plus_n) }+++mkClosureLFInfo :: DynFlags+ -> Id -- The binder+ -> TopLevelFlag -- True of top level+ -> [NonVoid Id] -- Free vars+ -> UpdateFlag -- Update flag+ -> [Id] -- Args+ -> LambdaFormInfo+mkClosureLFInfo dflags bndr top fvs upd_flag args+ | null args =+ mkLFThunk (idType bndr) top (map fromNonVoid fvs) upd_flag+ | otherwise =+ mkLFReEntrant top (map fromNonVoid fvs) args (mkArgDescr dflags args)+++------------------------------------------------------------------------+-- The code for closures+------------------------------------------------------------------------++closureCodeBody :: Bool -- whether this is a top-level binding+ -> Id -- the closure's name+ -> ClosureInfo -- Lots of information about this closure+ -> CostCentreStack -- Optional cost centre attached to closure+ -> [NonVoid Id] -- incoming args to the closure+ -> Int -- arity, including void args+ -> StgExpr+ -> [(NonVoid Id, ByteOff)] -- the closure's free vars+ -> FCode ()++{- There are two main cases for the code for closures.++* If there are *no arguments*, then the closure is a thunk, and not in+ normal form. So it should set up an update frame (if it is+ shared). NB: Thunks cannot have a primitive type!++* If there is *at least one* argument, then this closure is in+ normal form, so there is no need to set up an update frame.+-}++closureCodeBody top_lvl bndr cl_info cc _args arity body fv_details+ | arity == 0 -- No args i.e. thunk+ = withNewTickyCounterThunk+ (isStaticClosure cl_info)+ (closureUpdReqd cl_info)+ (closureName cl_info) $+ emitClosureProcAndInfoTable top_lvl bndr lf_info info_tbl [] $+ \(_, node, _) -> thunkCode cl_info fv_details cc node arity body+ where+ lf_info = closureLFInfo cl_info+ info_tbl = mkCmmInfo cl_info++closureCodeBody top_lvl bndr cl_info cc args arity body fv_details+ = -- Note: args may be [], if all args are Void+ withNewTickyCounterFun+ (closureSingleEntry cl_info)+ (closureName cl_info)+ args $ do {++ ; let+ lf_info = closureLFInfo cl_info+ info_tbl = mkCmmInfo cl_info++ -- Emit the main entry code+ ; emitClosureProcAndInfoTable top_lvl bndr lf_info info_tbl args $+ \(_offset, node, arg_regs) -> do+ -- Emit slow-entry code (for entering a closure through a PAP)+ { mkSlowEntryCode bndr cl_info arg_regs+ ; dflags <- getDynFlags+ ; let node_points = nodeMustPointToIt dflags lf_info+ node' = if node_points then Just node else Nothing+ ; loop_header_id <- newBlockId+ -- Extend reader monad with information that+ -- self-recursive tail calls can be optimized into local+ -- jumps. See Note [Self-recursive tail calls] in StgCmmExpr.+ ; withSelfLoop (bndr, loop_header_id, arg_regs) $ do+ {+ -- Main payload+ ; entryHeapCheck cl_info node' arity arg_regs $ do+ { -- emit LDV code when profiling+ when node_points (ldvEnterClosure cl_info (CmmLocal node))+ -- ticky after heap check to avoid double counting+ ; tickyEnterFun cl_info+ ; enterCostCentreFun cc+ (CmmMachOp (mo_wordSub dflags)+ [ CmmReg (CmmLocal node) -- See [NodeReg clobbered with loopification]+ , mkIntExpr dflags (funTag dflags cl_info) ])+ ; fv_bindings <- mapM bind_fv fv_details+ -- Load free vars out of closure *after*+ -- heap check, to reduce live vars over check+ ; when node_points $ load_fvs node lf_info fv_bindings+ ; void $ cgExpr body+ }}}++ }++-- Note [NodeReg clobbered with loopification]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Previously we used to pass nodeReg (aka R1) here. With profiling, upon+-- entering a closure, enterFunCCS was called with R1 passed to it. But since R1+-- may get clobbered inside the body of a closure, and since a self-recursive+-- tail call does not restore R1, a subsequent call to enterFunCCS received a+-- possibly bogus value from R1. The solution is to not pass nodeReg (aka R1) to+-- enterFunCCS. Instead, we pass node, the callee-saved temporary that stores+-- the original value of R1. This way R1 may get modified but loopification will+-- not care.++-- A function closure pointer may be tagged, so we+-- must take it into account when accessing the free variables.+bind_fv :: (NonVoid Id, ByteOff) -> FCode (LocalReg, ByteOff)+bind_fv (id, off) = do { reg <- rebindToReg id; return (reg, off) }++load_fvs :: LocalReg -> LambdaFormInfo -> [(LocalReg, ByteOff)] -> FCode ()+load_fvs node lf_info = mapM_ (\ (reg, off) ->+ do dflags <- getDynFlags+ let tag = lfDynTag dflags lf_info+ emit $ mkTaggedObjectLoad dflags reg node off tag)++-----------------------------------------+-- The "slow entry" code for a function. This entry point takes its+-- arguments on the stack. It loads the arguments into registers+-- according to the calling convention, and jumps to the function's+-- normal entry point. The function's closure is assumed to be in+-- R1/node.+--+-- The slow entry point is used for unknown calls: eg. stg_PAP_entry++mkSlowEntryCode :: Id -> ClosureInfo -> [LocalReg] -> FCode ()+-- If this function doesn't have a specialised ArgDescr, we need+-- to generate the function's arg bitmap and slow-entry code.+-- Here, we emit the slow-entry code.+mkSlowEntryCode bndr cl_info arg_regs -- function closure is already in `Node'+ | Just (_, ArgGen _) <- closureFunInfo cl_info+ = do dflags <- getDynFlags+ let node = idToReg dflags (NonVoid bndr)+ slow_lbl = closureSlowEntryLabel cl_info+ fast_lbl = closureLocalEntryLabel dflags cl_info+ -- mkDirectJump does not clobber `Node' containing function closure+ jump = mkJump dflags NativeNodeCall+ (mkLblExpr fast_lbl)+ (map (CmmReg . CmmLocal) (node : arg_regs))+ (initUpdFrameOff dflags)+ tscope <- getTickScope+ emitProcWithConvention Slow Nothing slow_lbl+ (node : arg_regs) (jump, tscope)+ | otherwise = return ()++-----------------------------------------+thunkCode :: ClosureInfo -> [(NonVoid Id, ByteOff)] -> CostCentreStack+ -> LocalReg -> Int -> StgExpr -> FCode ()+thunkCode cl_info fv_details _cc node arity body+ = do { dflags <- getDynFlags+ ; let node_points = nodeMustPointToIt dflags (closureLFInfo cl_info)+ node' = if node_points then Just node else Nothing+ ; ldvEnterClosure cl_info (CmmLocal node) -- NB: Node always points when profiling++ -- Heap overflow check+ ; entryHeapCheck cl_info node' arity [] $ do+ { -- Overwrite with black hole if necessary+ -- but *after* the heap-overflow check+ ; tickyEnterThunk cl_info+ ; when (blackHoleOnEntry cl_info && node_points)+ (blackHoleIt node)++ -- Push update frame+ ; setupUpdate cl_info node $+ -- We only enter cc after setting up update so+ -- that cc of enclosing scope will be recorded+ -- in update frame CAF/DICT functions will be+ -- subsumed by this enclosing cc+ do { enterCostCentreThunk (CmmReg nodeReg)+ ; let lf_info = closureLFInfo cl_info+ ; fv_bindings <- mapM bind_fv fv_details+ ; load_fvs node lf_info fv_bindings+ ; void $ cgExpr body }}}+++------------------------------------------------------------------------+-- Update and black-hole wrappers+------------------------------------------------------------------------++blackHoleIt :: LocalReg -> FCode ()+-- Only called for closures with no args+-- Node points to the closure+blackHoleIt node_reg+ = emitBlackHoleCode (CmmReg (CmmLocal node_reg))++emitBlackHoleCode :: CmmExpr -> FCode ()+emitBlackHoleCode node = do+ dflags <- getDynFlags++ -- Eager blackholing is normally disabled, but can be turned on with+ -- -feager-blackholing. When it is on, we replace the info pointer+ -- of the thunk with stg_EAGER_BLACKHOLE_info on entry.++ -- If we wanted to do eager blackholing with slop filling, we'd need+ -- to do it at the *end* of a basic block, otherwise we overwrite+ -- the free variables in the thunk that we still need. We have a+ -- patch for this from Andy Cheadle, but not incorporated yet. --SDM+ -- [6/2004]+ --+ -- Previously, eager blackholing was enabled when ticky-ticky was+ -- on. But it didn't work, and it wasn't strictly necessary to bring+ -- back minimal ticky-ticky, so now EAGER_BLACKHOLING is+ -- unconditionally disabled. -- krc 1/2007++ -- Note the eager-blackholing check is here rather than in blackHoleOnEntry,+ -- because emitBlackHoleCode is called from CmmParse.++ let eager_blackholing = not (gopt Opt_SccProfilingOn dflags)+ && gopt Opt_EagerBlackHoling dflags+ -- Profiling needs slop filling (to support LDV+ -- profiling), so currently eager blackholing doesn't+ -- work with profiling.++ when eager_blackholing $ do+ emitStore (cmmOffsetW dflags node (fixedHdrSizeW dflags))+ (CmmReg (CmmGlobal CurrentTSO))+ emitPrimCall [] MO_WriteBarrier []+ emitStore node (CmmReg (CmmGlobal EagerBlackholeInfo))++setupUpdate :: ClosureInfo -> LocalReg -> FCode () -> FCode ()+ -- Nota Bene: this function does not change Node (even if it's a CAF),+ -- so that the cost centre in the original closure can still be+ -- extracted by a subsequent enterCostCentre+setupUpdate closure_info node body+ | not (lfUpdatable (closureLFInfo closure_info))+ = body++ | not (isStaticClosure closure_info)+ = if not (closureUpdReqd closure_info)+ then do tickyUpdateFrameOmitted; body+ else do+ tickyPushUpdateFrame+ dflags <- getDynFlags+ let+ bh = blackHoleOnEntry closure_info &&+ not (gopt Opt_SccProfilingOn dflags) &&+ gopt Opt_EagerBlackHoling dflags++ lbl | bh = mkBHUpdInfoLabel+ | otherwise = mkUpdInfoLabel++ pushUpdateFrame lbl (CmmReg (CmmLocal node)) body++ | otherwise -- A static closure+ = do { tickyUpdateBhCaf closure_info++ ; if closureUpdReqd closure_info+ then do -- Blackhole the (updatable) CAF:+ { upd_closure <- link_caf node True+ ; pushUpdateFrame mkBHUpdInfoLabel upd_closure body }+ else do {tickyUpdateFrameOmitted; body}+ }++-----------------------------------------------------------------------------+-- Setting up update frames++-- Push the update frame on the stack in the Entry area,+-- leaving room for the return address that is already+-- at the old end of the area.+--+pushUpdateFrame :: CLabel -> CmmExpr -> FCode () -> FCode ()+pushUpdateFrame lbl updatee body+ = do+ updfr <- getUpdFrameOff+ dflags <- getDynFlags+ let+ hdr = fixedHdrSize dflags+ frame = updfr + hdr + sIZEOF_StgUpdateFrame_NoHdr dflags+ --+ emitUpdateFrame dflags (CmmStackSlot Old frame) lbl updatee+ withUpdFrameOff frame body++emitUpdateFrame :: DynFlags -> CmmExpr -> CLabel -> CmmExpr -> FCode ()+emitUpdateFrame dflags frame lbl updatee = do+ let+ hdr = fixedHdrSize dflags+ off_updatee = hdr + oFFSET_StgUpdateFrame_updatee dflags+ --+ emitStore frame (mkLblExpr lbl)+ emitStore (cmmOffset dflags frame off_updatee) updatee+ initUpdFrameProf frame++-----------------------------------------------------------------------------+-- Entering a CAF+--+-- See Note [CAF management] in rts/sm/Storage.c++link_caf :: LocalReg -- pointer to the closure+ -> Bool -- True <=> updatable, False <=> single-entry+ -> FCode CmmExpr -- Returns amode for closure to be updated+-- This function returns the address of the black hole, so it can be+-- updated with the new value when available.+link_caf node _is_upd = do+ { dflags <- getDynFlags+ -- Call the RTS function newCAF, returning the newly-allocated+ -- blackhole indirection closure+ ; let newCAF_lbl = mkForeignLabel (fsLit "newCAF") Nothing+ ForeignLabelInExternalPackage IsFunction+ ; bh <- newTemp (bWord dflags)+ ; emitRtsCallGen [(bh,AddrHint)] newCAF_lbl+ [ (CmmReg (CmmGlobal BaseReg), AddrHint),+ (CmmReg (CmmLocal node), AddrHint) ]+ False++ -- see Note [atomic CAF entry] in rts/sm/Storage.c+ ; updfr <- getUpdFrameOff+ ; let target = entryCode dflags (closureInfoPtr dflags (CmmReg (CmmLocal node)))+ ; emit =<< mkCmmIfThen+ (cmmEqWord dflags (CmmReg (CmmLocal bh)) (zeroExpr dflags))+ -- re-enter the CAF+ (mkJump dflags NativeNodeCall target [] updfr)++ ; return (CmmReg (CmmLocal bh)) }++------------------------------------------------------------------------+-- Profiling+------------------------------------------------------------------------++-- For "global" data constructors the description is simply occurrence+-- name of the data constructor itself. Otherwise it is determined by+-- @closureDescription@ from the let binding information.++closureDescription :: DynFlags+ -> Module -- Module+ -> Name -- Id of closure binding+ -> String+ -- Not called for StgRhsCon which have global info tables built in+ -- CgConTbls.hs with a description generated from the data constructor+closureDescription dflags mod_name name+ = showSDocDump dflags (char '<' <>+ (if isExternalName name+ then ppr name -- ppr will include the module name prefix+ else pprModule mod_name <> char '.' <> ppr name) <>+ char '>')+ -- showSDocDump, because we want to see the unique on the Name.
+ codeGen/StgCmmBind.hs-boot view
@@ -0,0 +1,6 @@+module StgCmmBind where++import StgCmmMonad( FCode )+import StgSyn( StgBinding )++cgBind :: StgBinding -> FCode ()
+ codeGen/StgCmmClosure.hs view
@@ -0,0 +1,1086 @@+{-# LANGUAGE CPP, RecordWildCards #-}++-----------------------------------------------------------------------------+--+-- Stg to C-- code generation:+--+-- The types LambdaFormInfo+-- ClosureInfo+--+-- Nothing monadic in here!+--+-----------------------------------------------------------------------------++module StgCmmClosure (+ DynTag, tagForCon, isSmallFamily,+ ConTagZ, dataConTagZ,++ idPrimRep, isVoidRep, isGcPtrRep, addIdReps, addArgReps,+ argPrimRep,++ NonVoid(..), fromNonVoid, nonVoidIds, nonVoidStgArgs,+ assertNonVoidIds, assertNonVoidStgArgs,++ -- * LambdaFormInfo+ LambdaFormInfo, -- Abstract+ StandardFormInfo, -- ...ditto...+ mkLFThunk, mkLFReEntrant, mkConLFInfo, mkSelectorLFInfo,+ mkApLFInfo, mkLFImported, mkLFArgument, mkLFLetNoEscape,+ mkLFStringLit,+ lfDynTag,+ maybeIsLFCon, isLFThunk, isLFReEntrant, lfUpdatable,++ -- * Used by other modules+ CgLoc(..), SelfLoopInfo, CallMethod(..),+ nodeMustPointToIt, isKnownFun, funTag, tagForArity, getCallMethod,++ -- * ClosureInfo+ ClosureInfo,+ mkClosureInfo,+ mkCmmInfo,++ -- ** Inspection+ closureLFInfo, closureName,++ -- ** Labels+ -- These just need the info table label+ closureInfoLabel, staticClosureLabel,+ closureSlowEntryLabel, closureLocalEntryLabel,++ -- ** Predicates+ -- These are really just functions on LambdaFormInfo+ closureUpdReqd, closureSingleEntry,+ closureReEntrant, closureFunInfo,+ isToplevClosure,++ blackHoleOnEntry, -- Needs LambdaFormInfo and SMRep+ isStaticClosure, -- Needs SMPre++ -- * InfoTables+ mkDataConInfoTable,+ cafBlackHoleInfoTable,+ indStaticInfoTable,+ staticClosureNeedsLink,+ ) where++#include "MachDeps.h"++#include "HsVersions.h"++import StgSyn+import SMRep+import Cmm+import PprCmmExpr()++import BlockId+import CLabel+import Id+import IdInfo+import DataCon+import Name+import Type+import TyCoRep+import TcType+import TyCon+import RepType+import BasicTypes+import Outputable+import DynFlags+import Util++import Data.Coerce (coerce)++-----------------------------------------------------------------------------+-- Data types and synonyms+-----------------------------------------------------------------------------++-- These data types are mostly used by other modules, especially StgCmmMonad,+-- but we define them here because some functions in this module need to+-- have access to them as well++data CgLoc+ = CmmLoc CmmExpr -- A stable CmmExpr; that is, one not mentioning+ -- Hp, so that it remains valid across calls++ | LneLoc BlockId [LocalReg] -- A join point+ -- A join point (= let-no-escape) should only+ -- be tail-called, and in a saturated way.+ -- To tail-call it, assign to these locals,+ -- and branch to the block id++instance Outputable CgLoc where+ ppr (CmmLoc e) = text "cmm" <+> ppr e+ ppr (LneLoc b rs) = text "lne" <+> ppr b <+> ppr rs++type SelfLoopInfo = (Id, BlockId, [LocalReg])++-- used by ticky profiling+isKnownFun :: LambdaFormInfo -> Bool+isKnownFun LFReEntrant{} = True+isKnownFun LFLetNoEscape = True+isKnownFun _ = False+++-------------------------------------+-- Non-void types+-------------------------------------+-- We frequently need the invariant that an Id or a an argument+-- is of a non-void type. This type is a witness to the invariant.++newtype NonVoid a = NonVoid a+ deriving (Eq, Show)++fromNonVoid :: NonVoid a -> a+fromNonVoid (NonVoid a) = a++instance (Outputable a) => Outputable (NonVoid a) where+ ppr (NonVoid a) = ppr a++nonVoidIds :: [Id] -> [NonVoid Id]+nonVoidIds ids = [NonVoid id | id <- ids, not (isVoidTy (idType id))]++-- | Used in places where some invariant ensures that all these Ids are+-- non-void; e.g. constructor field binders in case expressions.+-- See Note [Post-unarisation invariants] in UnariseStg.+assertNonVoidIds :: [Id] -> [NonVoid Id]+assertNonVoidIds ids = ASSERT(not (any (isVoidTy . idType) ids))+ coerce ids++nonVoidStgArgs :: [StgArg] -> [NonVoid StgArg]+nonVoidStgArgs args = [NonVoid arg | arg <- args, not (isVoidTy (stgArgType arg))]++-- | Used in places where some invariant ensures that all these arguments are+-- non-void; e.g. constructor arguments.+-- See Note [Post-unarisation invariants] in UnariseStg.+assertNonVoidStgArgs :: [StgArg] -> [NonVoid StgArg]+assertNonVoidStgArgs args = ASSERT(not (any (isVoidTy . stgArgType) args))+ coerce args+++-----------------------------------------------------------------------------+-- Representations+-----------------------------------------------------------------------------++-- Why are these here?++idPrimRep :: Id -> PrimRep+idPrimRep id = typePrimRep1 (idType id)+ -- NB: typePrimRep1 fails on unboxed tuples,+ -- but by StgCmm no Ids have unboxed tuple type++addIdReps :: [NonVoid Id] -> [NonVoid (PrimRep, Id)]+addIdReps = map (\id -> let id' = fromNonVoid id+ in NonVoid (idPrimRep id', id'))++addArgReps :: [NonVoid StgArg] -> [NonVoid (PrimRep, StgArg)]+addArgReps = map (\arg -> let arg' = fromNonVoid arg+ in NonVoid (argPrimRep arg', arg'))++argPrimRep :: StgArg -> PrimRep+argPrimRep arg = typePrimRep1 (stgArgType arg)+++-----------------------------------------------------------------------------+-- LambdaFormInfo+-----------------------------------------------------------------------------++-- Information about an identifier, from the code generator's point of+-- view. Every identifier is bound to a LambdaFormInfo in the+-- environment, which gives the code generator enough info to be able to+-- tail call or return that identifier.++data LambdaFormInfo+ = LFReEntrant -- Reentrant closure (a function)+ TopLevelFlag -- True if top level+ OneShotInfo+ !RepArity -- Arity. Invariant: always > 0+ !Bool -- True <=> no fvs+ ArgDescr -- Argument descriptor (should really be in ClosureInfo)++ | LFThunk -- Thunk (zero arity)+ TopLevelFlag+ !Bool -- True <=> no free vars+ !Bool -- True <=> updatable (i.e., *not* single-entry)+ StandardFormInfo+ !Bool -- True <=> *might* be a function type++ | LFCon -- A saturated constructor application+ DataCon -- The constructor++ | LFUnknown -- Used for function arguments and imported things.+ -- We know nothing about this closure.+ -- Treat like updatable "LFThunk"...+ -- Imported things which we *do* know something about use+ -- one of the other LF constructors (eg LFReEntrant for+ -- known functions)+ !Bool -- True <=> *might* be a function type+ -- The False case is good when we want to enter it,+ -- because then we know the entry code will do+ -- For a function, the entry code is the fast entry point++ | LFUnlifted -- A value of unboxed type;+ -- always a value, needs evaluation++ | LFLetNoEscape -- See LetNoEscape module for precise description+++-------------------------+-- StandardFormInfo tells whether this thunk has one of+-- a small number of standard forms++data StandardFormInfo+ = NonStandardThunk+ -- The usual case: not of the standard forms++ | SelectorThunk+ -- A SelectorThunk is of form+ -- case x of+ -- con a1,..,an -> ak+ -- and the constructor is from a single-constr type.+ WordOff -- 0-origin offset of ak within the "goods" of+ -- constructor (Recall that the a1,...,an may be laid+ -- out in the heap in a non-obvious order.)++ | ApThunk+ -- An ApThunk is of form+ -- x1 ... xn+ -- The code for the thunk just pushes x2..xn on the stack and enters x1.+ -- There are a few of these (for 1 <= n <= MAX_SPEC_AP_SIZE) pre-compiled+ -- in the RTS to save space.+ RepArity -- Arity, n+++------------------------------------------------------+-- Building LambdaFormInfo+------------------------------------------------------++mkLFArgument :: Id -> LambdaFormInfo+mkLFArgument id+ | isUnliftedType ty = LFUnlifted+ | might_be_a_function ty = LFUnknown True+ | otherwise = LFUnknown False+ where+ ty = idType id++-------------+mkLFLetNoEscape :: LambdaFormInfo+mkLFLetNoEscape = LFLetNoEscape++-------------+mkLFReEntrant :: TopLevelFlag -- True of top level+ -> [Id] -- Free vars+ -> [Id] -- Args+ -> ArgDescr -- Argument descriptor+ -> LambdaFormInfo++mkLFReEntrant _ _ [] _+ = pprPanic "mkLFReEntrant" empty+mkLFReEntrant top fvs args arg_descr+ = LFReEntrant top os_info (length args) (null fvs) arg_descr+ where os_info = idOneShotInfo (head args)++-------------+mkLFThunk :: Type -> TopLevelFlag -> [Id] -> UpdateFlag -> LambdaFormInfo+mkLFThunk thunk_ty top fvs upd_flag+ = ASSERT( not (isUpdatable upd_flag) || not (isUnliftedType thunk_ty) )+ LFThunk top (null fvs)+ (isUpdatable upd_flag)+ NonStandardThunk+ (might_be_a_function thunk_ty)++--------------+might_be_a_function :: Type -> Bool+-- Return False only if we are *sure* it's a data type+-- Look through newtypes etc as much as poss+might_be_a_function ty+ | [LiftedRep] <- typePrimRep ty+ , Just tc <- tyConAppTyCon_maybe (unwrapType ty)+ , isDataTyCon tc+ = False+ | otherwise+ = True++-------------+mkConLFInfo :: DataCon -> LambdaFormInfo+mkConLFInfo con = LFCon con++-------------+mkSelectorLFInfo :: Id -> Int -> Bool -> LambdaFormInfo+mkSelectorLFInfo id offset updatable+ = LFThunk NotTopLevel False updatable (SelectorThunk offset)+ (might_be_a_function (idType id))++-------------+mkApLFInfo :: Id -> UpdateFlag -> Arity -> LambdaFormInfo+mkApLFInfo id upd_flag arity+ = LFThunk NotTopLevel (arity == 0) (isUpdatable upd_flag) (ApThunk arity)+ (might_be_a_function (idType id))++-------------+mkLFImported :: Id -> LambdaFormInfo+mkLFImported id+ | Just con <- isDataConWorkId_maybe id+ , isNullaryRepDataCon con+ = LFCon con -- An imported nullary constructor+ -- We assume that the constructor is evaluated so that+ -- the id really does point directly to the constructor++ | arity > 0+ = LFReEntrant TopLevel noOneShotInfo arity True (panic "arg_descr")++ | otherwise+ = mkLFArgument id -- Not sure of exact arity+ where+ arity = idFunRepArity id++-------------+mkLFStringLit :: LambdaFormInfo+mkLFStringLit = LFUnlifted++-----------------------------------------------------+-- Dynamic pointer tagging+-----------------------------------------------------++type DynTag = Int -- The tag on a *pointer*+ -- (from the dynamic-tagging paper)++-- Note [Data constructor dynamic tags]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- The family size of a data type (the number of constructors+-- or the arity of a function) can be either:+-- * small, if the family size < 2**tag_bits+-- * big, otherwise.+--+-- Small families can have the constructor tag in the tag bits.+-- Big families only use the tag value 1 to represent evaluatedness.+-- We don't have very many tag bits: for example, we have 2 bits on+-- x86-32 and 3 bits on x86-64.++isSmallFamily :: DynFlags -> Int -> Bool+isSmallFamily dflags fam_size = fam_size <= mAX_PTR_TAG dflags++-- We keep the *zero-indexed* tag in the srt_len field of the info+-- table of a data constructor.+dataConTagZ :: DataCon -> ConTagZ+dataConTagZ con = dataConTag con - fIRST_TAG++tagForCon :: DynFlags -> DataCon -> DynTag+tagForCon dflags con+ | isSmallFamily dflags fam_size = con_tag + 1+ | otherwise = 1+ where+ con_tag = dataConTagZ con+ fam_size = tyConFamilySize (dataConTyCon con)++tagForArity :: DynFlags -> RepArity -> DynTag+tagForArity dflags arity+ | isSmallFamily dflags arity = arity+ | otherwise = 0++lfDynTag :: DynFlags -> LambdaFormInfo -> DynTag+-- Return the tag in the low order bits of a variable bound+-- to this LambdaForm+lfDynTag dflags (LFCon con) = tagForCon dflags con+lfDynTag dflags (LFReEntrant _ _ arity _ _) = tagForArity dflags arity+lfDynTag _ _other = 0+++-----------------------------------------------------------------------------+-- Observing LambdaFormInfo+-----------------------------------------------------------------------------++-------------+maybeIsLFCon :: LambdaFormInfo -> Maybe DataCon+maybeIsLFCon (LFCon con) = Just con+maybeIsLFCon _ = Nothing++------------+isLFThunk :: LambdaFormInfo -> Bool+isLFThunk (LFThunk {}) = True+isLFThunk _ = False++isLFReEntrant :: LambdaFormInfo -> Bool+isLFReEntrant (LFReEntrant {}) = True+isLFReEntrant _ = False++-----------------------------------------------------------------------------+-- Choosing SM reps+-----------------------------------------------------------------------------++lfClosureType :: LambdaFormInfo -> ClosureTypeInfo+lfClosureType (LFReEntrant _ _ arity _ argd) = Fun arity argd+lfClosureType (LFCon con) = Constr (dataConTagZ con)+ (dataConIdentity con)+lfClosureType (LFThunk _ _ _ is_sel _) = thunkClosureType is_sel+lfClosureType _ = panic "lfClosureType"++thunkClosureType :: StandardFormInfo -> ClosureTypeInfo+thunkClosureType (SelectorThunk off) = ThunkSelector off+thunkClosureType _ = Thunk++-- We *do* get non-updatable top-level thunks sometimes. eg. f = g+-- gets compiled to a jump to g (if g has non-zero arity), instead of+-- messing around with update frames and PAPs. We set the closure type+-- to FUN_STATIC in this case.++-----------------------------------------------------------------------------+-- nodeMustPointToIt+-----------------------------------------------------------------------------++nodeMustPointToIt :: DynFlags -> LambdaFormInfo -> Bool+-- If nodeMustPointToIt is true, then the entry convention for+-- this closure has R1 (the "Node" register) pointing to the+-- closure itself --- the "self" argument++nodeMustPointToIt _ (LFReEntrant top _ _ no_fvs _)+ = not no_fvs -- Certainly if it has fvs we need to point to it+ || isNotTopLevel top -- See Note [GC recovery]+ -- For lex_profiling we also access the cost centre for a+ -- non-inherited (i.e. non-top-level) function.+ -- The isNotTopLevel test above ensures this is ok.++nodeMustPointToIt dflags (LFThunk top no_fvs updatable NonStandardThunk _)+ = not no_fvs -- Self parameter+ || isNotTopLevel top -- Note [GC recovery]+ || updatable -- Need to push update frame+ || gopt Opt_SccProfilingOn dflags+ -- For the non-updatable (single-entry case):+ --+ -- True if has fvs (in which case we need access to them, and we+ -- should black-hole it)+ -- or profiling (in which case we need to recover the cost centre+ -- from inside it) ToDo: do we need this even for+ -- top-level thunks? If not,+ -- isNotTopLevel subsumes this++nodeMustPointToIt _ (LFThunk {}) -- Node must point to a standard-form thunk+ = True++nodeMustPointToIt _ (LFCon _) = True++ -- Strictly speaking, the above two don't need Node to point+ -- to it if the arity = 0. But this is a *really* unlikely+ -- situation. If we know it's nil (say) and we are entering+ -- it. Eg: let x = [] in x then we will certainly have inlined+ -- x, since nil is a simple atom. So we gain little by not+ -- having Node point to known zero-arity things. On the other+ -- hand, we do lose something; Patrick's code for figuring out+ -- when something has been updated but not entered relies on+ -- having Node point to the result of an update. SLPJ+ -- 27/11/92.++nodeMustPointToIt _ (LFUnknown _) = True+nodeMustPointToIt _ LFUnlifted = False+nodeMustPointToIt _ LFLetNoEscape = False++{- Note [GC recovery]+~~~~~~~~~~~~~~~~~~~~~+If we a have a local let-binding (function or thunk)+ let f = <body> in ...+AND <body> allocates, then the heap-overflow check needs to know how+to re-start the evaluation. It uses the "self" pointer to do this.+So even if there are no free variables in <body>, we still make+nodeMustPointToIt be True for non-top-level bindings.++Why do any such bindings exist? After all, let-floating should have+floated them out. Well, a clever optimiser might leave one there to+avoid a space leak, deliberately recomputing a thunk. Also (and this+really does happen occasionally) let-floating may make a function f smaller+so it can be inlined, so now (f True) may generate a local no-fv closure.+This actually happened during bootstrapping GHC itself, with f=mkRdrFunBind+in TcGenDeriv.) -}++-----------------------------------------------------------------------------+-- getCallMethod+-----------------------------------------------------------------------------++{- The entry conventions depend on the type of closure being entered,+whether or not it has free variables, and whether we're running+sequentially or in parallel.++Closure Node Argument Enter+Characteristics Par Req'd Passing Via+---------------------------------------------------------------------------+Unknown & no & yes & stack & node+Known fun (>1 arg), no fvs & no & no & registers & fast entry (enough args)+ & slow entry (otherwise)+Known fun (>1 arg), fvs & no & yes & registers & fast entry (enough args)+0 arg, no fvs \r,\s & no & no & n/a & direct entry+0 arg, no fvs \u & no & yes & n/a & node+0 arg, fvs \r,\s,selector & no & yes & n/a & node+0 arg, fvs \r,\s & no & yes & n/a & direct entry+0 arg, fvs \u & no & yes & n/a & node+Unknown & yes & yes & stack & node+Known fun (>1 arg), no fvs & yes & no & registers & fast entry (enough args)+ & slow entry (otherwise)+Known fun (>1 arg), fvs & yes & yes & registers & node+0 arg, fvs \r,\s,selector & yes & yes & n/a & node+0 arg, no fvs \r,\s & yes & no & n/a & direct entry+0 arg, no fvs \u & yes & yes & n/a & node+0 arg, fvs \r,\s & yes & yes & n/a & node+0 arg, fvs \u & yes & yes & n/a & node++When black-holing, single-entry closures could also be entered via node+(rather than directly) to catch double-entry. -}++data CallMethod+ = EnterIt -- No args, not a function++ | JumpToIt BlockId [LocalReg] -- A join point or a header of a local loop++ | ReturnIt -- It's a value (function, unboxed value,+ -- or constructor), so just return it.++ | SlowCall -- Unknown fun, or known fun with+ -- too few args.++ | DirectEntry -- Jump directly, with args in regs+ CLabel -- The code label+ RepArity -- Its arity++getCallMethod :: DynFlags+ -> Name -- Function being applied+ -> Id -- Function Id used to chech if it can refer to+ -- CAF's and whether the function is tail-calling+ -- itself+ -> LambdaFormInfo -- Its info+ -> RepArity -- Number of available arguments+ -> RepArity -- Number of them being void arguments+ -> CgLoc -- Passed in from cgIdApp so that we can+ -- handle let-no-escape bindings and self-recursive+ -- tail calls using the same data constructor,+ -- JumpToIt. This saves us one case branch in+ -- cgIdApp+ -> Maybe SelfLoopInfo -- can we perform a self-recursive tail call?+ -> CallMethod++getCallMethod dflags _ id _ n_args v_args _cg_loc+ (Just (self_loop_id, block_id, args))+ | gopt Opt_Loopification dflags+ , id == self_loop_id+ , n_args - v_args == length args+ -- If these patterns match then we know that:+ -- * loopification optimisation is turned on+ -- * function is performing a self-recursive call in a tail position+ -- * number of non-void parameters of the function matches functions arity.+ -- See Note [Self-recursive tail calls] and Note [Void arguments in+ -- self-recursive tail calls] in StgCmmExpr for more details+ = JumpToIt block_id args++getCallMethod dflags name id (LFReEntrant _ _ arity _ _) n_args _v_args _cg_loc+ _self_loop_info+ | n_args == 0 -- No args at all+ && not (gopt Opt_SccProfilingOn dflags)+ -- See Note [Evaluating functions with profiling] in rts/Apply.cmm+ = ASSERT( arity /= 0 ) ReturnIt+ | n_args < arity = SlowCall -- Not enough args+ | otherwise = DirectEntry (enterIdLabel dflags name (idCafInfo id)) arity++getCallMethod _ _name _ LFUnlifted n_args _v_args _cg_loc _self_loop_info+ = ASSERT( n_args == 0 ) ReturnIt++getCallMethod _ _name _ (LFCon _) n_args _v_args _cg_loc _self_loop_info+ = ASSERT( n_args == 0 ) ReturnIt+ -- n_args=0 because it'd be ill-typed to apply a saturated+ -- constructor application to anything++getCallMethod dflags name id (LFThunk _ _ updatable std_form_info is_fun)+ n_args _v_args _cg_loc _self_loop_info+ | is_fun -- it *might* be a function, so we must "call" it (which is always safe)+ = SlowCall -- We cannot just enter it [in eval/apply, the entry code+ -- is the fast-entry code]++ -- Since is_fun is False, we are *definitely* looking at a data value+ | updatable || gopt Opt_Ticky dflags -- to catch double entry+ {- OLD: || opt_SMP+ I decided to remove this, because in SMP mode it doesn't matter+ if we enter the same thunk multiple times, so the optimisation+ of jumping directly to the entry code is still valid. --SDM+ -}+ = EnterIt++ -- even a non-updatable selector thunk can be updated by the garbage+ -- collector, so we must enter it. (#8817)+ | SelectorThunk{} <- std_form_info+ = EnterIt++ -- We used to have ASSERT( n_args == 0 ), but actually it is+ -- possible for the optimiser to generate+ -- let bot :: Int = error Int "urk"+ -- in (bot `cast` unsafeCoerce Int (Int -> Int)) 3+ -- This happens as a result of the case-of-error transformation+ -- So the right thing to do is just to enter the thing++ | otherwise -- Jump direct to code for single-entry thunks+ = ASSERT( n_args == 0 )+ DirectEntry (thunkEntryLabel dflags name (idCafInfo id) std_form_info+ updatable) 0++getCallMethod _ _name _ (LFUnknown True) _n_arg _v_args _cg_locs _self_loop_info+ = SlowCall -- might be a function++getCallMethod _ name _ (LFUnknown False) n_args _v_args _cg_loc _self_loop_info+ = ASSERT2( n_args == 0, ppr name <+> ppr n_args )+ EnterIt -- Not a function++getCallMethod _ _name _ LFLetNoEscape _n_args _v_args (LneLoc blk_id lne_regs)+ _self_loop_info+ = JumpToIt blk_id lne_regs++getCallMethod _ _ _ _ _ _ _ _ = panic "Unknown call method"++-----------------------------------------------------------------------------+-- staticClosureRequired+-----------------------------------------------------------------------------++{- staticClosureRequired is never called (hence commented out)++ SimonMar writes (Sept 07) It's an optimisation we used to apply at+ one time, I believe, but it got lost probably in the rewrite of+ the RTS/code generator. I left that code there to remind me to+ look into whether it was worth doing sometime++{- Avoiding generating entries and info tables+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+At present, for every function we generate all of the following,+just in case. But they aren't always all needed, as noted below:++[NB1: all of this applies only to *functions*. Thunks always+have closure, info table, and entry code.]++[NB2: All are needed if the function is *exported*, just to play safe.]++* Fast-entry code ALWAYS NEEDED++* Slow-entry code+ Needed iff (a) we have any un-saturated calls to the function+ OR (b) the function is passed as an arg+ OR (c) we're in the parallel world and the function has free vars+ [Reason: in parallel world, we always enter functions+ with free vars via the closure.]++* The function closure+ Needed iff (a) we have any un-saturated calls to the function+ OR (b) the function is passed as an arg+ OR (c) if the function has free vars (ie not top level)++ Why case (a) here? Because if the arg-satis check fails,+ UpdatePAP stuffs a pointer to the function closure in the PAP.+ [Could be changed; UpdatePAP could stuff in a code ptr instead,+ but doesn't seem worth it.]++ [NB: these conditions imply that we might need the closure+ without the slow-entry code. Here's how.++ f x y = let g w = ...x..y..w...+ in+ ...(g t)...++ Here we need a closure for g which contains x and y,+ but since the calls are all saturated we just jump to the+ fast entry point for g, with R1 pointing to the closure for g.]+++* Standard info table+ Needed iff (a) we have any un-saturated calls to the function+ OR (b) the function is passed as an arg+ OR (c) the function has free vars (ie not top level)++ NB. In the sequential world, (c) is only required so that the function closure has+ an info table to point to, to keep the storage manager happy.+ If (c) alone is true we could fake up an info table by choosing+ one of a standard family of info tables, whose entry code just+ bombs out.++ [NB In the parallel world (c) is needed regardless because+ we enter functions with free vars via the closure.]++ If (c) is retained, then we'll sometimes generate an info table+ (for storage mgr purposes) without slow-entry code. Then we need+ to use an error label in the info table to substitute for the absent+ slow entry code.+-}++staticClosureRequired+ :: Name+ -> StgBinderInfo+ -> LambdaFormInfo+ -> Bool+staticClosureRequired binder bndr_info+ (LFReEntrant top_level _ _ _ _) -- It's a function+ = ASSERT( isTopLevel top_level )+ -- Assumption: it's a top-level, no-free-var binding+ not (satCallsOnly bndr_info)++staticClosureRequired binder other_binder_info other_lf_info = True+-}++-----------------------------------------------------------------------------+-- Data types for closure information+-----------------------------------------------------------------------------+++{- ClosureInfo: information about a binding++ We make a ClosureInfo for each let binding (both top level and not),+ but not bindings for data constructors: for those we build a CmmInfoTable+ directly (see mkDataConInfoTable).++ To a first approximation:+ ClosureInfo = (LambdaFormInfo, CmmInfoTable)++ A ClosureInfo has enough information+ a) to construct the info table itself, and build other things+ related to the binding (e.g. slow entry points for a function)+ b) to allocate a closure containing that info pointer (i.e.+ it knows the info table label)+-}++data ClosureInfo+ = ClosureInfo {+ closureName :: !Name, -- The thing bound to this closure+ -- we don't really need this field: it's only used in generating+ -- code for ticky and profiling, and we could pass the information+ -- around separately, but it doesn't do much harm to keep it here.++ closureLFInfo :: !LambdaFormInfo, -- NOTE: not an LFCon+ -- this tells us about what the closure contains: it's right-hand-side.++ -- the rest is just an unpacked CmmInfoTable.+ closureInfoLabel :: !CLabel,+ closureSMRep :: !SMRep, -- representation used by storage mgr+ closureProf :: !ProfilingInfo+ }++-- | Convert from 'ClosureInfo' to 'CmmInfoTable'.+mkCmmInfo :: ClosureInfo -> CmmInfoTable+mkCmmInfo ClosureInfo {..}+ = CmmInfoTable { cit_lbl = closureInfoLabel+ , cit_rep = closureSMRep+ , cit_prof = closureProf+ , cit_srt = NoC_SRT }++--------------------------------------+-- Building ClosureInfos+--------------------------------------++mkClosureInfo :: DynFlags+ -> Bool -- Is static+ -> Id+ -> LambdaFormInfo+ -> Int -> Int -- Total and pointer words+ -> String -- String descriptor+ -> ClosureInfo+mkClosureInfo dflags is_static id lf_info tot_wds ptr_wds val_descr+ = ClosureInfo { closureName = name+ , closureLFInfo = lf_info+ , closureInfoLabel = info_lbl -- These three fields are+ , closureSMRep = sm_rep -- (almost) an info table+ , closureProf = prof } -- (we don't have an SRT yet)+ where+ name = idName id+ sm_rep = mkHeapRep dflags is_static ptr_wds nonptr_wds (lfClosureType lf_info)+ prof = mkProfilingInfo dflags id val_descr+ nonptr_wds = tot_wds - ptr_wds++ info_lbl = mkClosureInfoTableLabel id lf_info++--------------------------------------+-- Other functions over ClosureInfo+--------------------------------------++-- Eager blackholing is normally disabled, but can be turned on with+-- -feager-blackholing. When it is on, we replace the info pointer of+-- the thunk with stg_EAGER_BLACKHOLE_info on entry.++-- If we wanted to do eager blackholing with slop filling,+-- we'd need to do it at the *end* of a basic block, otherwise+-- we overwrite the free variables in the thunk that we still+-- need. We have a patch for this from Andy Cheadle, but not+-- incorporated yet. --SDM [6/2004]+--+-- Previously, eager blackholing was enabled when ticky-ticky+-- was on. But it didn't work, and it wasn't strictly necessary+-- to bring back minimal ticky-ticky, so now EAGER_BLACKHOLING+-- is unconditionally disabled. -- krc 1/2007+--+-- Static closures are never themselves black-holed.++blackHoleOnEntry :: ClosureInfo -> Bool+blackHoleOnEntry cl_info+ | isStaticRep (closureSMRep cl_info)+ = False -- Never black-hole a static closure++ | otherwise+ = case closureLFInfo cl_info of+ LFReEntrant {} -> False+ LFLetNoEscape -> False+ LFThunk _ _no_fvs upd _ _ -> upd -- See Note [Black-holing non-updatable thunks]+ _other -> panic "blackHoleOnEntry"++{- Note [Black-holing non-updatable thunks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must not black-hole non-updatable (single-entry) thunks otherwise+we run into issues like Trac #10414. Specifically:++ * There is no reason to black-hole a non-updatable thunk: it should+ not be competed for by multiple threads++ * It could, conceivably, cause a space leak if we don't black-hole+ it, if there was a live but never-followed pointer pointing to it.+ Let's hope that doesn't happen.++ * It is dangerous to black-hole a non-updatable thunk because+ - is not updated (of course)+ - hence, if it is black-holed and another thread tries to evaluate+ it, that thread will block forever+ This actually happened in Trac #10414. So we do not black-hole+ non-updatable thunks.++ * How could two threads evaluate the same non-updatable (single-entry)+ thunk? See Reid Barton's example below.++ * Only eager blackholing could possibly black-hole a non-updatable+ thunk, because lazy black-holing only affects thunks with an+ update frame on the stack.++Here is and example due to Reid Barton (Trac #10414):+ x = \u [] concat [[1], []]+with the following definitions,++ concat x = case x of+ [] -> []+ (:) x xs -> (++) x (concat xs)++ (++) xs ys = case xs of+ [] -> ys+ (:) x rest -> (:) x ((++) rest ys)++Where we use the syntax @\u []@ to denote an updatable thunk and @\s []@ to+denote a single-entry (i.e. non-updatable) thunk. After a thread evaluates @x@+to WHNF and calls @(++)@ the heap will contain the following thunks,++ x = 1 : y+ y = \u [] (++) [] z+ z = \s [] concat []++Now that the stage is set, consider the follow evaluations by two racing threads+A and B,++ 1. Both threads enter @y@ before either is able to replace it with an+ indirection++ 2. Thread A does the case analysis in @(++)@ and consequently enters @z@,+ replacing it with a black-hole++ 3. At some later point thread B does the same case analysis and also attempts+ to enter @z@. However, it finds that it has been replaced with a black-hole+ so it blocks.++ 4. Thread A eventually finishes evaluating @z@ (to @[]@) and updates @y@+ accordingly. It does *not* update @z@, however, as it is single-entry. This+ leaves Thread B blocked forever on a black-hole which will never be+ updated.++To avoid this sort of condition we never black-hole non-updatable thunks.+-}++isStaticClosure :: ClosureInfo -> Bool+isStaticClosure cl_info = isStaticRep (closureSMRep cl_info)++closureUpdReqd :: ClosureInfo -> Bool+closureUpdReqd ClosureInfo{ closureLFInfo = lf_info } = lfUpdatable lf_info++lfUpdatable :: LambdaFormInfo -> Bool+lfUpdatable (LFThunk _ _ upd _ _) = upd+lfUpdatable _ = False++closureSingleEntry :: ClosureInfo -> Bool+closureSingleEntry (ClosureInfo { closureLFInfo = LFThunk _ _ upd _ _}) = not upd+closureSingleEntry (ClosureInfo { closureLFInfo = LFReEntrant _ OneShotLam _ _ _}) = True+closureSingleEntry _ = False++closureReEntrant :: ClosureInfo -> Bool+closureReEntrant (ClosureInfo { closureLFInfo = LFReEntrant {} }) = True+closureReEntrant _ = False++closureFunInfo :: ClosureInfo -> Maybe (RepArity, ArgDescr)+closureFunInfo (ClosureInfo { closureLFInfo = lf_info }) = lfFunInfo lf_info++lfFunInfo :: LambdaFormInfo -> Maybe (RepArity, ArgDescr)+lfFunInfo (LFReEntrant _ _ arity _ arg_desc) = Just (arity, arg_desc)+lfFunInfo _ = Nothing++funTag :: DynFlags -> ClosureInfo -> DynTag+funTag dflags (ClosureInfo { closureLFInfo = lf_info })+ = lfDynTag dflags lf_info++isToplevClosure :: ClosureInfo -> Bool+isToplevClosure (ClosureInfo { closureLFInfo = lf_info })+ = case lf_info of+ LFReEntrant TopLevel _ _ _ _ -> True+ LFThunk TopLevel _ _ _ _ -> True+ _other -> False++--------------------------------------+-- Label generation+--------------------------------------++staticClosureLabel :: ClosureInfo -> CLabel+staticClosureLabel = toClosureLbl . closureInfoLabel++closureSlowEntryLabel :: ClosureInfo -> CLabel+closureSlowEntryLabel = toSlowEntryLbl . closureInfoLabel++closureLocalEntryLabel :: DynFlags -> ClosureInfo -> CLabel+closureLocalEntryLabel dflags+ | tablesNextToCode dflags = toInfoLbl . closureInfoLabel+ | otherwise = toEntryLbl . closureInfoLabel++mkClosureInfoTableLabel :: Id -> LambdaFormInfo -> CLabel+mkClosureInfoTableLabel id lf_info+ = case lf_info of+ LFThunk _ _ upd_flag (SelectorThunk offset) _+ -> mkSelectorInfoLabel upd_flag offset++ LFThunk _ _ upd_flag (ApThunk arity) _+ -> mkApInfoTableLabel upd_flag arity++ LFThunk{} -> std_mk_lbl name cafs+ LFReEntrant{} -> std_mk_lbl name cafs+ _other -> panic "closureInfoTableLabel"++ where+ name = idName id++ std_mk_lbl | is_local = mkLocalInfoTableLabel+ | otherwise = mkInfoTableLabel++ cafs = idCafInfo id+ is_local = isDataConWorkId id+ -- Make the _info pointer for the implicit datacon worker+ -- binding local. The reason we can do this is that importing+ -- code always either uses the _closure or _con_info. By the+ -- invariants in CorePrep anything else gets eta expanded.+++thunkEntryLabel :: DynFlags -> Name -> CafInfo -> StandardFormInfo -> Bool -> CLabel+-- thunkEntryLabel is a local help function, not exported. It's used from+-- getCallMethod.+thunkEntryLabel dflags _thunk_id _ (ApThunk arity) upd_flag+ = enterApLabel dflags upd_flag arity+thunkEntryLabel dflags _thunk_id _ (SelectorThunk offset) upd_flag+ = enterSelectorLabel dflags upd_flag offset+thunkEntryLabel dflags thunk_id c _ _+ = enterIdLabel dflags thunk_id c++enterApLabel :: DynFlags -> Bool -> Arity -> CLabel+enterApLabel dflags is_updatable arity+ | tablesNextToCode dflags = mkApInfoTableLabel is_updatable arity+ | otherwise = mkApEntryLabel is_updatable arity++enterSelectorLabel :: DynFlags -> Bool -> WordOff -> CLabel+enterSelectorLabel dflags upd_flag offset+ | tablesNextToCode dflags = mkSelectorInfoLabel upd_flag offset+ | otherwise = mkSelectorEntryLabel upd_flag offset++enterIdLabel :: DynFlags -> Name -> CafInfo -> CLabel+enterIdLabel dflags id c+ | tablesNextToCode dflags = mkInfoTableLabel id c+ | otherwise = mkEntryLabel id c+++--------------------------------------+-- Profiling+--------------------------------------++-- Profiling requires two pieces of information to be determined for+-- each closure's info table --- description and type.++-- The description is stored directly in the @CClosureInfoTable@ when the+-- info table is built.++-- The type is determined from the type information stored with the @Id@+-- in the closure info using @closureTypeDescr@.++mkProfilingInfo :: DynFlags -> Id -> String -> ProfilingInfo+mkProfilingInfo dflags id val_descr+ | not (gopt Opt_SccProfilingOn dflags) = NoProfilingInfo+ | otherwise = ProfilingInfo ty_descr_w8 val_descr_w8+ where+ ty_descr_w8 = stringToWord8s (getTyDescription (idType id))+ val_descr_w8 = stringToWord8s val_descr++getTyDescription :: Type -> String+getTyDescription ty+ = case (tcSplitSigmaTy ty) of { (_, _, tau_ty) ->+ case tau_ty of+ TyVarTy _ -> "*"+ AppTy fun _ -> getTyDescription fun+ TyConApp tycon _ -> getOccString tycon+ FunTy _ res -> '-' : '>' : fun_result res+ ForAllTy _ ty -> getTyDescription ty+ LitTy n -> getTyLitDescription n+ CastTy ty _ -> getTyDescription ty+ CoercionTy co -> pprPanic "getTyDescription" (ppr co)+ }+ where+ fun_result (FunTy _ res) = '>' : fun_result res+ fun_result other = getTyDescription other++getTyLitDescription :: TyLit -> String+getTyLitDescription l =+ case l of+ NumTyLit n -> show n+ StrTyLit n -> show n++--------------------------------------+-- CmmInfoTable-related things+--------------------------------------++mkDataConInfoTable :: DynFlags -> DataCon -> Bool -> Int -> Int -> CmmInfoTable+mkDataConInfoTable dflags data_con is_static ptr_wds nonptr_wds+ = CmmInfoTable { cit_lbl = info_lbl+ , cit_rep = sm_rep+ , cit_prof = prof+ , cit_srt = NoC_SRT }+ where+ name = dataConName data_con+ info_lbl = mkConInfoTableLabel name NoCafRefs+ sm_rep = mkHeapRep dflags is_static ptr_wds nonptr_wds cl_type+ cl_type = Constr (dataConTagZ data_con) (dataConIdentity data_con)++ prof | not (gopt Opt_SccProfilingOn dflags) = NoProfilingInfo+ | otherwise = ProfilingInfo ty_descr val_descr++ ty_descr = stringToWord8s $ occNameString $ getOccName $ dataConTyCon data_con+ val_descr = stringToWord8s $ occNameString $ getOccName data_con++-- We need a black-hole closure info to pass to @allocDynClosure@ when we+-- want to allocate the black hole on entry to a CAF.++cafBlackHoleInfoTable :: CmmInfoTable+cafBlackHoleInfoTable+ = CmmInfoTable { cit_lbl = mkCAFBlackHoleInfoTableLabel+ , cit_rep = blackHoleRep+ , cit_prof = NoProfilingInfo+ , cit_srt = NoC_SRT }++indStaticInfoTable :: CmmInfoTable+indStaticInfoTable+ = CmmInfoTable { cit_lbl = mkIndStaticInfoLabel+ , cit_rep = indStaticRep+ , cit_prof = NoProfilingInfo+ , cit_srt = NoC_SRT }++staticClosureNeedsLink :: Bool -> CmmInfoTable -> Bool+-- A static closure needs a link field to aid the GC when traversing+-- the static closure graph. But it only needs such a field if either+-- a) it has an SRT+-- b) it's a constructor with one or more pointer fields+-- In case (b), the constructor's fields themselves play the role+-- of the SRT.+staticClosureNeedsLink has_srt CmmInfoTable{ cit_rep = smrep }+ | isConRep smrep = not (isStaticNoCafCon smrep)+ | otherwise = has_srt -- needsSRT (cit_srt info_tbl)
+ codeGen/StgCmmCon.hs view
@@ -0,0 +1,279 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Stg to C--: code generation for constructors+--+-- This module provides the support code for StgCmm to deal with with+-- constructors on the RHSs of let(rec)s.+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmCon (+ cgTopRhsCon, buildDynCon, bindConArgs+ ) where++#include "HsVersions.h"++import StgSyn+import CoreSyn ( AltCon(..) )++import StgCmmMonad+import StgCmmEnv+import StgCmmHeap+import StgCmmLayout+import StgCmmUtils+import StgCmmClosure+import StgCmmProf ( curCCS )++import CmmExpr+import CLabel+import MkGraph+import SMRep+import CostCentre+import Module+import DataCon+import DynFlags+import FastString+import Id+import RepType (countConRepArgs)+import Literal+import PrelInfo+import Outputable+import Platform+import Util+import MonadUtils (mapMaybeM)++import Control.Monad+import Data.Char++++---------------------------------------------------------------+-- Top-level constructors+---------------------------------------------------------------++cgTopRhsCon :: DynFlags+ -> Id -- Name of thing bound to this RHS+ -> DataCon -- Id+ -> [NonVoid StgArg] -- Args+ -> (CgIdInfo, FCode ())+cgTopRhsCon dflags id con args =+ let id_info = litIdInfo dflags id (mkConLFInfo con) (CmmLabel closure_label)+ in (id_info, gen_code)+ where+ name = idName id+ caffy = idCafInfo id -- any stgArgHasCafRefs args+ closure_label = mkClosureLabel name caffy++ gen_code =+ do { this_mod <- getModuleName+ ; when (platformOS (targetPlatform dflags) == OSMinGW32) $+ -- Windows DLLs have a problem with static cross-DLL refs.+ MASSERT( not (isDllConApp dflags this_mod con (map fromNonVoid args)) )+ ; ASSERT( args `lengthIs` countConRepArgs con ) return ()++ -- LAY IT OUT+ ; let+ (tot_wds, -- #ptr_wds + #nonptr_wds+ ptr_wds, -- #ptr_wds+ nv_args_w_offsets) = mkVirtConstrOffsets dflags (addArgReps args)++ nonptr_wds = tot_wds - ptr_wds++ -- we're not really going to emit an info table, so having+ -- to make a CmmInfoTable is a bit overkill, but mkStaticClosureFields+ -- needs to poke around inside it.+ info_tbl = mkDataConInfoTable dflags con True ptr_wds nonptr_wds++ get_lit (arg, _offset) = do { CmmLit lit <- getArgAmode arg+ ; return lit }++ ; payload <- mapM get_lit nv_args_w_offsets+ -- NB1: nv_args_w_offsets is sorted into ptrs then non-ptrs+ -- NB2: all the amodes should be Lits!+ -- TODO (osa): Why?++ ; let closure_rep = mkStaticClosureFields+ dflags+ info_tbl+ dontCareCCS -- Because it's static data+ caffy -- Has CAF refs+ payload++ -- BUILD THE OBJECT+ ; emitDataLits closure_label closure_rep++ ; return () }+++---------------------------------------------------------------+-- Lay out and allocate non-top-level constructors+---------------------------------------------------------------++buildDynCon :: Id -- Name of the thing to which this constr will+ -- be bound+ -> Bool -- is it genuinely bound to that name, or just+ -- for profiling?+ -> CostCentreStack -- Where to grab cost centre from;+ -- current CCS if currentOrSubsumedCCS+ -> DataCon -- The data constructor+ -> [NonVoid StgArg] -- Its args+ -> FCode (CgIdInfo, FCode CmmAGraph)+ -- Return details about how to find it and initialization code+buildDynCon binder actually_bound cc con args+ = do dflags <- getDynFlags+ buildDynCon' dflags (targetPlatform dflags) binder actually_bound cc con args+++buildDynCon' :: DynFlags+ -> Platform+ -> Id -> Bool+ -> CostCentreStack+ -> DataCon+ -> [NonVoid StgArg]+ -> FCode (CgIdInfo, FCode CmmAGraph)++{- We used to pass a boolean indicating whether all the+args were of size zero, so we could use a static+constructor; but I concluded that it just isn't worth it.+Now I/O uses unboxed tuples there just aren't any constructors+with all size-zero args.++The reason for having a separate argument, rather than looking at+the addr modes of the args is that we may be in a "knot", and+premature looking at the args will cause the compiler to black-hole!+-}+++-------- buildDynCon': Nullary constructors --------------+-- First we deal with the case of zero-arity constructors. They+-- will probably be unfolded, so we don't expect to see this case much,+-- if at all, but it does no harm, and sets the scene for characters.+--+-- In the case of zero-arity constructors, or, more accurately, those+-- which have exclusively size-zero (VoidRep) args, we generate no code+-- at all.++buildDynCon' dflags _ binder _ _cc con []+ | isNullaryRepDataCon con+ = return (litIdInfo dflags binder (mkConLFInfo con)+ (CmmLabel (mkClosureLabel (dataConName con) (idCafInfo binder))),+ return mkNop)++-------- buildDynCon': Charlike and Intlike constructors -----------+{- The following three paragraphs about @Char@-like and @Int@-like+closures are obsolete, but I don't understand the details well enough+to properly word them, sorry. I've changed the treatment of @Char@s to+be analogous to @Int@s: only a subset is preallocated, because @Char@+has now 31 bits. Only literals are handled here. -- Qrczak++Now for @Char@-like closures. We generate an assignment of the+address of the closure to a temporary. It would be possible simply to+generate no code, and record the addressing mode in the environment,+but we'd have to be careful if the argument wasn't a constant --- so+for simplicity we just always assign to a temporary.++Last special case: @Int@-like closures. We only special-case the+situation in which the argument is a literal in the range+@mIN_INTLIKE@..@mAX_INTLILKE@. NB: for @Char@-like closures we can+work with any old argument, but for @Int@-like ones the argument has+to be a literal. Reason: @Char@ like closures have an argument type+which is guaranteed in range.++Because of this, we use can safely return an addressing mode.++We don't support this optimisation when compiling into Windows DLLs yet+because they don't support cross package data references well.+-}++buildDynCon' dflags platform binder _ _cc con [arg]+ | maybeIntLikeCon con+ , platformOS platform /= OSMinGW32 || not (gopt Opt_PIC dflags)+ , NonVoid (StgLitArg (MachInt val)) <- arg+ , val <= fromIntegral (mAX_INTLIKE dflags) -- Comparisons at type Integer!+ , val >= fromIntegral (mIN_INTLIKE dflags) -- ...ditto...+ = do { let intlike_lbl = mkCmmClosureLabel rtsUnitId (fsLit "stg_INTLIKE")+ val_int = fromIntegral val :: Int+ offsetW = (val_int - mIN_INTLIKE dflags) * (fixedHdrSizeW dflags + 1)+ -- INTLIKE closures consist of a header and one word payload+ intlike_amode = cmmLabelOffW dflags intlike_lbl offsetW+ ; return ( litIdInfo dflags binder (mkConLFInfo con) intlike_amode+ , return mkNop) }++buildDynCon' dflags platform binder _ _cc con [arg]+ | maybeCharLikeCon con+ , platformOS platform /= OSMinGW32 || not (gopt Opt_PIC dflags)+ , NonVoid (StgLitArg (MachChar val)) <- arg+ , let val_int = ord val :: Int+ , val_int <= mAX_CHARLIKE dflags+ , val_int >= mIN_CHARLIKE dflags+ = do { let charlike_lbl = mkCmmClosureLabel rtsUnitId (fsLit "stg_CHARLIKE")+ offsetW = (val_int - mIN_CHARLIKE dflags) * (fixedHdrSizeW dflags + 1)+ -- CHARLIKE closures consist of a header and one word payload+ charlike_amode = cmmLabelOffW dflags charlike_lbl offsetW+ ; return ( litIdInfo dflags binder (mkConLFInfo con) charlike_amode+ , return mkNop) }++-------- buildDynCon': the general case -----------+buildDynCon' dflags _ binder actually_bound ccs con args+ = do { (id_info, reg) <- rhsIdInfo binder lf_info+ ; return (id_info, gen_code reg)+ }+ where+ lf_info = mkConLFInfo con++ gen_code reg+ = do { let (tot_wds, ptr_wds, args_w_offsets)+ = mkVirtConstrOffsets dflags (addArgReps args)+ nonptr_wds = tot_wds - ptr_wds+ info_tbl = mkDataConInfoTable dflags con False+ ptr_wds nonptr_wds+ ; let ticky_name | actually_bound = Just binder+ | otherwise = Nothing++ ; hp_plus_n <- allocDynClosure ticky_name info_tbl lf_info+ use_cc blame_cc args_w_offsets+ ; return (mkRhsInit dflags reg lf_info hp_plus_n) }+ where+ use_cc -- cost-centre to stick in the object+ | isCurrentCCS ccs = curCCS+ | otherwise = panic "buildDynCon: non-current CCS not implemented"++ blame_cc = use_cc -- cost-centre on which to blame the alloc (same)+++---------------------------------------------------------------+-- Binding constructor arguments+---------------------------------------------------------------++bindConArgs :: AltCon -> LocalReg -> [NonVoid Id] -> FCode [LocalReg]+-- bindConArgs is called from cgAlt of a case+-- (bindConArgs con args) augments the environment with bindings for the+-- binders args, assuming that we have just returned from a 'case' which+-- found a con+bindConArgs (DataAlt con) base args+ = ASSERT(not (isUnboxedTupleCon con))+ do dflags <- getDynFlags+ let (_, _, args_w_offsets) = mkVirtConstrOffsets dflags (addIdReps args)+ tag = tagForCon dflags con++ -- The binding below forces the masking out of the tag bits+ -- when accessing the constructor field.+ bind_arg :: (NonVoid Id, VirtualHpOffset) -> FCode (Maybe LocalReg)+ bind_arg (arg@(NonVoid b), offset)+ | isDeadBinder b =+ -- Do not load unused fields from objects to local variables.+ -- (CmmSink can optimize this, but it's cheap and common enough+ -- to handle here)+ return Nothing+ | otherwise = do+ emit $ mkTaggedObjectLoad dflags (idToReg dflags arg) base offset tag+ Just <$> bindArgToReg arg++ mapMaybeM bind_arg args_w_offsets++bindConArgs _other_con _base args+ = ASSERT( null args ) return []
+ codeGen/StgCmmEnv.hs view
@@ -0,0 +1,206 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Stg to C-- code generation: the binding environment+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------+module StgCmmEnv (+ CgIdInfo,++ litIdInfo, lneIdInfo, rhsIdInfo, mkRhsInit,+ idInfoToAmode,++ addBindC, addBindsC,++ bindArgsToRegs, bindToReg, rebindToReg,+ bindArgToReg, idToReg,+ getArgAmode, getNonVoidArgAmodes,+ getCgIdInfo,+ maybeLetNoEscape,+ ) where++#include "HsVersions.h"++import TyCon+import StgCmmMonad+import StgCmmUtils+import StgCmmClosure++import CLabel++import BlockId+import CmmExpr+import CmmUtils+import DynFlags+import Id+import MkGraph+import Name+import Outputable+import StgSyn+import Type+import TysPrim+import UniqFM+import Util+import VarEnv++-------------------------------------+-- Manipulating CgIdInfo+-------------------------------------++mkCgIdInfo :: Id -> LambdaFormInfo -> CmmExpr -> CgIdInfo+mkCgIdInfo id lf expr+ = CgIdInfo { cg_id = id, cg_lf = lf+ , cg_loc = CmmLoc expr }++litIdInfo :: DynFlags -> Id -> LambdaFormInfo -> CmmLit -> CgIdInfo+litIdInfo dflags id lf lit+ = CgIdInfo { cg_id = id, cg_lf = lf+ , cg_loc = CmmLoc (addDynTag dflags (CmmLit lit) tag) }+ where+ tag = lfDynTag dflags lf++lneIdInfo :: DynFlags -> Id -> [NonVoid Id] -> CgIdInfo+lneIdInfo dflags id regs+ = CgIdInfo { cg_id = id, cg_lf = lf+ , cg_loc = LneLoc blk_id (map (idToReg dflags) regs) }+ where+ lf = mkLFLetNoEscape+ blk_id = mkBlockId (idUnique id)+++rhsIdInfo :: Id -> LambdaFormInfo -> FCode (CgIdInfo, LocalReg)+rhsIdInfo id lf_info+ = do dflags <- getDynFlags+ reg <- newTemp (gcWord dflags)+ return (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)), reg)++mkRhsInit :: DynFlags -> LocalReg -> LambdaFormInfo -> CmmExpr -> CmmAGraph+mkRhsInit dflags reg lf_info expr+ = mkAssign (CmmLocal reg) (addDynTag dflags expr (lfDynTag dflags lf_info))++idInfoToAmode :: CgIdInfo -> CmmExpr+-- Returns a CmmExpr for the *tagged* pointer+idInfoToAmode (CgIdInfo { cg_loc = CmmLoc e }) = e+idInfoToAmode cg_info+ = pprPanic "idInfoToAmode" (ppr (cg_id cg_info)) -- LneLoc++addDynTag :: DynFlags -> CmmExpr -> DynTag -> CmmExpr+-- A tag adds a byte offset to the pointer+addDynTag dflags expr tag = cmmOffsetB dflags expr tag++maybeLetNoEscape :: CgIdInfo -> Maybe (BlockId, [LocalReg])+maybeLetNoEscape (CgIdInfo { cg_loc = LneLoc blk_id args}) = Just (blk_id, args)+maybeLetNoEscape _other = Nothing++++---------------------------------------------------------+-- The binding environment+--+-- There are three basic routines, for adding (addBindC),+-- modifying(modifyBindC) and looking up (getCgIdInfo) bindings.+---------------------------------------------------------++addBindC :: CgIdInfo -> FCode ()+addBindC stuff_to_bind = do+ binds <- getBinds+ setBinds $ extendVarEnv binds (cg_id stuff_to_bind) stuff_to_bind++addBindsC :: [CgIdInfo] -> FCode ()+addBindsC new_bindings = do+ binds <- getBinds+ let new_binds = foldl (\ binds info -> extendVarEnv binds (cg_id info) info)+ binds+ new_bindings+ setBinds new_binds++getCgIdInfo :: Id -> FCode CgIdInfo+getCgIdInfo id+ = do { dflags <- getDynFlags+ ; local_binds <- getBinds -- Try local bindings first+ ; case lookupVarEnv local_binds id of {+ Just info -> return info ;+ Nothing -> do {++ -- Should be imported; make up a CgIdInfo for it+ let name = idName id+ ; if isExternalName name then+ let ext_lbl+ | isUnliftedType (idType id) =+ -- An unlifted external Id must refer to a top-level+ -- string literal. See Note [Bytes label] in CLabel.+ ASSERT( idType id `eqType` addrPrimTy )+ mkBytesLabel name+ | otherwise = mkClosureLabel name $ idCafInfo id+ in return $+ litIdInfo dflags id (mkLFImported id) (CmmLabel ext_lbl)+ else+ cgLookupPanic id -- Bug+ }}}++cgLookupPanic :: Id -> FCode a+cgLookupPanic id+ = do local_binds <- getBinds+ pprPanic "StgCmmEnv: variable not found"+ (vcat [ppr id,+ text "local binds for:",+ pprUFM local_binds $ \infos ->+ vcat [ ppr (cg_id info) | info <- infos ]+ ])+++--------------------+getArgAmode :: NonVoid StgArg -> FCode CmmExpr+getArgAmode (NonVoid (StgVarArg var)) = idInfoToAmode <$> getCgIdInfo var+getArgAmode (NonVoid (StgLitArg lit)) = CmmLit <$> cgLit lit++getNonVoidArgAmodes :: [StgArg] -> FCode [CmmExpr]+-- NB: Filters out void args,+-- so the result list may be shorter than the argument list+getNonVoidArgAmodes [] = return []+getNonVoidArgAmodes (arg:args)+ | isVoidRep (argPrimRep arg) = getNonVoidArgAmodes args+ | otherwise = do { amode <- getArgAmode (NonVoid arg)+ ; amodes <- getNonVoidArgAmodes args+ ; return ( amode : amodes ) }+++------------------------------------------------------------------------+-- Interface functions for binding and re-binding names+------------------------------------------------------------------------++bindToReg :: NonVoid Id -> LambdaFormInfo -> FCode LocalReg+-- Bind an Id to a fresh LocalReg+bindToReg nvid@(NonVoid id) lf_info+ = do dflags <- getDynFlags+ let reg = idToReg dflags nvid+ addBindC (mkCgIdInfo id lf_info (CmmReg (CmmLocal reg)))+ return reg++rebindToReg :: NonVoid Id -> FCode LocalReg+-- Like bindToReg, but the Id is already in scope, so+-- get its LF info from the envt+rebindToReg nvid@(NonVoid id)+ = do { info <- getCgIdInfo id+ ; bindToReg nvid (cg_lf info) }++bindArgToReg :: NonVoid Id -> FCode LocalReg+bindArgToReg nvid@(NonVoid id) = bindToReg nvid (mkLFArgument id)++bindArgsToRegs :: [NonVoid Id] -> FCode [LocalReg]+bindArgsToRegs args = mapM bindArgToReg args++idToReg :: DynFlags -> NonVoid Id -> LocalReg+-- Make a register from an Id, typically a function argument,+-- free variable, or case binder+--+-- We re-use the Unique from the Id to make it easier to see what is going on+--+-- By now the Ids should be uniquely named; else one would worry+-- about accidental collision+idToReg dflags (NonVoid id)+ = LocalReg (idUnique id)+ (primRepCmmType dflags (idPrimRep id))
+ codeGen/StgCmmExpr.hs view
@@ -0,0 +1,943 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}++-----------------------------------------------------------------------------+--+-- Stg to C-- code generation: expressions+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmExpr ( cgExpr ) where++#include "HsVersions.h"++import {-# SOURCE #-} StgCmmBind ( cgBind )++import StgCmmMonad+import StgCmmHeap+import StgCmmEnv+import StgCmmCon+import StgCmmProf (saveCurrentCostCentre, restoreCurrentCostCentre, emitSetCCC)+import StgCmmLayout+import StgCmmPrim+import StgCmmHpc+import StgCmmTicky+import StgCmmUtils+import StgCmmClosure++import StgSyn++import MkGraph+import BlockId+import Cmm+import CmmInfo+import CoreSyn+import DataCon+import ForeignCall+import Id+import PrimOp+import TyCon+import Type ( isUnliftedType )+import RepType ( isVoidTy, countConRepArgs, primRepSlot )+import CostCentre ( CostCentreStack, currentCCS )+import Maybes+import Util+import FastString+import Outputable++import Control.Monad (unless,void)+import Control.Arrow (first)+import Data.Function ( on )++import Prelude hiding ((<*>))++------------------------------------------------------------------------+-- cgExpr: the main function+------------------------------------------------------------------------++cgExpr :: StgExpr -> FCode ReturnKind++cgExpr (StgApp fun args) = cgIdApp fun args++{- seq# a s ==> a -}+cgExpr (StgOpApp (StgPrimOp SeqOp) [StgVarArg a, _] _res_ty) =+ cgIdApp a []++cgExpr (StgOpApp op args ty) = cgOpApp op args ty+cgExpr (StgConApp con args _)= cgConApp con args+cgExpr (StgTick t e) = cgTick t >> cgExpr e+cgExpr (StgLit lit) = do cmm_lit <- cgLit lit+ emitReturn [CmmLit cmm_lit]++cgExpr (StgLet binds expr) = do { cgBind binds; cgExpr expr }+cgExpr (StgLetNoEscape binds expr) =+ do { u <- newUnique+ ; let join_id = mkBlockId u+ ; cgLneBinds join_id binds+ ; r <- cgExpr expr+ ; emitLabel join_id+ ; return r }++cgExpr (StgCase expr bndr alt_type alts) =+ cgCase expr bndr alt_type alts++cgExpr (StgLam {}) = panic "cgExpr: StgLam"++------------------------------------------------------------------------+-- Let no escape+------------------------------------------------------------------------++{- Generating code for a let-no-escape binding, aka join point is very+very similar to what we do for a case expression. The duality is+between+ let-no-escape x = b+ in e+and+ case e of ... -> b++That is, the RHS of 'x' (ie 'b') will execute *later*, just like+the alternative of the case; it needs to be compiled in an environment+in which all volatile bindings are forgotten, and the free vars are+bound only to stable things like stack locations.. The 'e' part will+execute *next*, just like the scrutinee of a case. -}++-------------------------+cgLneBinds :: BlockId -> StgBinding -> FCode ()+cgLneBinds join_id (StgNonRec bndr rhs)+ = do { local_cc <- saveCurrentCostCentre+ -- See Note [Saving the current cost centre]+ ; (info, fcode) <- cgLetNoEscapeRhs join_id local_cc bndr rhs+ ; fcode+ ; addBindC info }++cgLneBinds join_id (StgRec pairs)+ = do { local_cc <- saveCurrentCostCentre+ ; r <- sequence $ unzipWith (cgLetNoEscapeRhs join_id local_cc) pairs+ ; let (infos, fcodes) = unzip r+ ; addBindsC infos+ ; sequence_ fcodes+ }++-------------------------+cgLetNoEscapeRhs+ :: BlockId -- join point for successor of let-no-escape+ -> Maybe LocalReg -- Saved cost centre+ -> Id+ -> StgRhs+ -> FCode (CgIdInfo, FCode ())++cgLetNoEscapeRhs join_id local_cc bndr rhs =+ do { (info, rhs_code) <- cgLetNoEscapeRhsBody local_cc bndr rhs+ ; let (bid, _) = expectJust "cgLetNoEscapeRhs" $ maybeLetNoEscape info+ ; let code = do { (_, body) <- getCodeScoped rhs_code+ ; emitOutOfLine bid (first (<*> mkBranch join_id) body) }+ ; return (info, code)+ }++cgLetNoEscapeRhsBody+ :: Maybe LocalReg -- Saved cost centre+ -> Id+ -> StgRhs+ -> FCode (CgIdInfo, FCode ())+cgLetNoEscapeRhsBody local_cc bndr (StgRhsClosure cc _bi _ _upd args body)+ = cgLetNoEscapeClosure bndr local_cc cc (nonVoidIds args) body+cgLetNoEscapeRhsBody local_cc bndr (StgRhsCon cc con args)+ = cgLetNoEscapeClosure bndr local_cc cc []+ (StgConApp con args (pprPanic "cgLetNoEscapeRhsBody" $+ text "StgRhsCon doesn't have type args"))+ -- For a constructor RHS we want to generate a single chunk of+ -- code which can be jumped to from many places, which will+ -- return the constructor. It's easy; just behave as if it+ -- was an StgRhsClosure with a ConApp inside!++-------------------------+cgLetNoEscapeClosure+ :: Id -- binder+ -> Maybe LocalReg -- Slot for saved current cost centre+ -> CostCentreStack -- XXX: *** NOT USED *** why not?+ -> [NonVoid Id] -- Args (as in \ args -> body)+ -> StgExpr -- Body (as in above)+ -> FCode (CgIdInfo, FCode ())++cgLetNoEscapeClosure bndr cc_slot _unused_cc args body+ = do dflags <- getDynFlags+ return ( lneIdInfo dflags bndr args+ , code )+ where+ code = forkLneBody $ do {+ ; withNewTickyCounterLNE (idName bndr) args $ do+ ; restoreCurrentCostCentre cc_slot+ ; arg_regs <- bindArgsToRegs args+ ; void $ noEscapeHeapCheck arg_regs (tickyEnterLNE >> cgExpr body) }+++------------------------------------------------------------------------+-- Case expressions+------------------------------------------------------------------------++{- Note [Compiling case expressions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It is quite interesting to decide whether to put a heap-check at the+start of each alternative. Of course we certainly have to do so if+the case forces an evaluation, or if there is a primitive op which can+trigger GC.++A more interesting situation is this (a Plan-B situation)++ !P!;+ ...P...+ case x# of+ 0# -> !Q!; ...Q...+ default -> !R!; ...R...++where !x! indicates a possible heap-check point. The heap checks+in the alternatives *can* be omitted, in which case the topmost+heapcheck will take their worst case into account.++In favour of omitting !Q!, !R!:++ - *May* save a heap overflow test,+ if ...P... allocates anything.++ - We can use relative addressing from a single Hp to+ get at all the closures so allocated.++ - No need to save volatile vars etc across heap checks+ in !Q!, !R!++Against omitting !Q!, !R!++ - May put a heap-check into the inner loop. Suppose+ the main loop is P -> R -> P -> R...+ Q is the loop exit, and only it does allocation.+ This only hurts us if P does no allocation. If P allocates,+ then there is a heap check in the inner loop anyway.++ - May do more allocation than reqd. This sometimes bites us+ badly. For example, nfib (ha!) allocates about 30\% more space if the+ worst-casing is done, because many many calls to nfib are leaf calls+ which don't need to allocate anything.++ We can un-allocate, but that costs an instruction++Neither problem hurts us if there is only one alternative.++Suppose the inner loop is P->R->P->R etc. Then here is+how many heap checks we get in the *inner loop* under various+conditions++ Alloc Heap check in branches (!Q!, !R!)?+ P Q R yes no (absorb to !P!)+--------------------------------------+ n n n 0 0+ n y n 0 1+ n . y 1 1+ y . y 2 1+ y . n 1 1++Best choices: absorb heap checks from Q and R into !P! iff+ a) P itself does some allocation+or+ b) P does allocation, or there is exactly one alternative++We adopt (b) because that is more likely to put the heap check at the+entry to a function, when not many things are live. After a bunch of+single-branch cases, we may have lots of things live++Hence: two basic plans for++ case e of r { alts }++------ Plan A: the general case ---------++ ...save current cost centre...++ ...code for e,+ with sequel (SetLocals r)++ ...restore current cost centre...+ ...code for alts...+ ...alts do their own heap checks++------ Plan B: special case when ---------+ (i) e does not allocate or call GC+ (ii) either upstream code performs allocation+ or there is just one alternative++ Then heap allocation in the (single) case branch+ is absorbed by the upstream check.+ Very common example: primops on unboxed values++ ...code for e,+ with sequel (SetLocals r)...++ ...code for alts...+ ...no heap check...+-}++++-------------------------------------+data GcPlan+ = GcInAlts -- Put a GC check at the start the case alternatives,+ [LocalReg] -- which binds these registers+ | NoGcInAlts -- The scrutinee is a primitive value, or a call to a+ -- primitive op which does no GC. Absorb the allocation+ -- of the case alternative(s) into the upstream check++-------------------------------------+cgCase :: StgExpr -> Id -> AltType -> [StgAlt] -> FCode ReturnKind++cgCase (StgOpApp (StgPrimOp op) args _) bndr (AlgAlt tycon) alts+ | isEnumerationTyCon tycon -- Note [case on bool]+ = do { tag_expr <- do_enum_primop op args++ -- If the binder is not dead, convert the tag to a constructor+ -- and assign it.+ ; unless (isDeadBinder bndr) $ do+ { dflags <- getDynFlags+ ; tmp_reg <- bindArgToReg (NonVoid bndr)+ ; emitAssign (CmmLocal tmp_reg)+ (tagToClosure dflags tycon tag_expr) }++ ; (mb_deflt, branches) <- cgAlgAltRhss (NoGcInAlts,AssignedDirectly)+ (NonVoid bndr) alts+ ; emitSwitch tag_expr branches mb_deflt 0 (tyConFamilySize tycon - 1)+ ; return AssignedDirectly+ }+ where+ do_enum_primop :: PrimOp -> [StgArg] -> FCode CmmExpr+ do_enum_primop TagToEnumOp [arg] -- No code!+ = getArgAmode (NonVoid arg)+ do_enum_primop primop args+ = do dflags <- getDynFlags+ tmp <- newTemp (bWord dflags)+ cgPrimOp [tmp] primop args+ return (CmmReg (CmmLocal tmp))++{-+Note [case on bool]+~~~~~~~~~~~~~~~~~~~+This special case handles code like++ case a <# b of+ True ->+ False ->++--> case tagToEnum# (a <$# b) of+ True -> .. ; False -> ...++--> case (a <$# b) of r ->+ case tagToEnum# r of+ True -> .. ; False -> ...++If we let the ordinary case code handle it, we'll get something like++ tmp1 = a < b+ tmp2 = Bool_closure_tbl[tmp1]+ if (tmp2 & 7 != 0) then ... // normal tagged case++but this junk won't optimise away. What we really want is just an+inline comparison:++ if (a < b) then ...++So we add a special case to generate++ tmp1 = a < b+ if (tmp1 == 0) then ...++and later optimisations will further improve this.++Now that #6135 has been resolved it should be possible to remove that+special case. The idea behind this special case and pre-6135 implementation+of Bool-returning primops was that tagToEnum# was added implicitly in the+codegen and then optimized away. Now the call to tagToEnum# is explicit+in the source code, which allows to optimize it away at the earlier stages+of compilation (i.e. at the Core level).++Note [Scrutinising VoidRep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have this STG code:+ f = \[s : State# RealWorld] ->+ case s of _ -> blah+This is very odd. Why are we scrutinising a state token? But it+can arise with bizarre NOINLINE pragmas (Trac #9964)+ crash :: IO ()+ crash = IO (\s -> let {-# NOINLINE s' #-}+ s' = s+ in (# s', () #))++Now the trouble is that 's' has VoidRep, and we do not bind void+arguments in the environment; they don't live anywhere. See the+calls to nonVoidIds in various places. So we must not look up+'s' in the environment. Instead, just evaluate the RHS! Simple.+-}++cgCase (StgApp v []) _ (PrimAlt _) alts+ | isVoidRep (idPrimRep v) -- See Note [Scrutinising VoidRep]+ , [(DEFAULT, _, rhs)] <- alts+ = cgExpr rhs++{- Note [Dodgy unsafeCoerce 1]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ case (x :: HValue) |> co of (y :: MutVar# Int)+ DEFAULT -> ...+We want to gnerate an assignment+ y := x+We want to allow this assignment to be generated in the case when the+types are compatible, because this allows some slightly-dodgy but+occasionally-useful casts to be used, such as in RtClosureInspect+where we cast an HValue to a MutVar# so we can print out the contents+of the MutVar#. If instead we generate code that enters the HValue,+then we'll get a runtime panic, because the HValue really is a+MutVar#. The types are compatible though, so we can just generate an+assignment.+-}+cgCase (StgApp v []) bndr alt_type@(PrimAlt _) alts+ | isUnliftedType (idType v) -- Note [Dodgy unsafeCoerce 1]+ || reps_compatible+ = -- assignment suffices for unlifted types+ do { dflags <- getDynFlags+ ; unless reps_compatible $+ pprPanic "cgCase: reps do not match, perhaps a dodgy unsafeCoerce?"+ (pp_bndr v $$ pp_bndr bndr)+ ; v_info <- getCgIdInfo v+ ; emitAssign (CmmLocal (idToReg dflags (NonVoid bndr)))+ (idInfoToAmode v_info)+ ; bindArgToReg (NonVoid bndr)+ ; cgAlts (NoGcInAlts,AssignedDirectly) (NonVoid bndr) alt_type alts }+ where+ reps_compatible = ((==) `on` (primRepSlot . idPrimRep)) v bndr+ -- Must compare SlotTys, not proper PrimReps, because with unboxed sums,+ -- the types of the binders are generated from slotPrimRep and might not+ -- match. Test case:+ -- swap :: (# Int | Int #) -> (# Int | Int #)+ -- swap (# x | #) = (# | x #)+ -- swap (# | y #) = (# y | #)++ pp_bndr id = ppr id <+> dcolon <+> ppr (idType id) <+> parens (ppr (idPrimRep id))++{- Note [Dodgy unsafeCoerce 2, #3132]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In all other cases of a lifted Id being cast to an unlifted type, the+Id should be bound to bottom, otherwise this is an unsafe use of+unsafeCoerce. We can generate code to enter the Id and assume that+it will never return. Hence, we emit the usual enter/return code, and+because bottom must be untagged, it will be entered. The Sequel is a+type-correct assignment, albeit bogus. The (dead) continuation loops;+it would be better to invoke some kind of panic function here.+-}+cgCase scrut@(StgApp v []) _ (PrimAlt _) _+ = do { dflags <- getDynFlags+ ; mb_cc <- maybeSaveCostCentre True+ ; withSequel (AssignTo [idToReg dflags (NonVoid v)] False) (cgExpr scrut)+ ; restoreCurrentCostCentre mb_cc+ ; emitComment $ mkFastString "should be unreachable code"+ ; l <- newBlockId+ ; emitLabel l+ ; emit (mkBranch l) -- an infinite loop+ ; return AssignedDirectly+ }++{- Note [Handle seq#]+~~~~~~~~~~~~~~~~~~~~~+case seq# a s of v+ (# s', a' #) -> e++==>++case a of v+ (# s', a' #) -> e++(taking advantage of the fact that the return convention for (# State#, a #)+is the same as the return convention for just 'a')+-}++cgCase (StgOpApp (StgPrimOp SeqOp) [StgVarArg a, _] _) bndr alt_type alts+ = -- Note [Handle seq#]+ -- Use the same return convention as vanilla 'a'.+ cgCase (StgApp a []) bndr alt_type alts++cgCase scrut bndr alt_type alts+ = -- the general case+ do { dflags <- getDynFlags+ ; up_hp_usg <- getVirtHp -- Upstream heap usage+ ; let ret_bndrs = chooseReturnBndrs bndr alt_type alts+ alt_regs = map (idToReg dflags) ret_bndrs+ ; simple_scrut <- isSimpleScrut scrut alt_type+ ; let do_gc | not simple_scrut = True+ | isSingleton alts = False+ | up_hp_usg > 0 = False+ | otherwise = True+ -- cf Note [Compiling case expressions]+ gc_plan = if do_gc then GcInAlts alt_regs else NoGcInAlts++ ; mb_cc <- maybeSaveCostCentre simple_scrut++ ; let sequel = AssignTo alt_regs do_gc{- Note [scrut sequel] -}+ ; ret_kind <- withSequel sequel (cgExpr scrut)+ ; restoreCurrentCostCentre mb_cc+ ; _ <- bindArgsToRegs ret_bndrs+ ; cgAlts (gc_plan,ret_kind) (NonVoid bndr) alt_type alts+ }+++{-+Note [scrut sequel]++The job of the scrutinee is to assign its value(s) to alt_regs.+Additionally, if we plan to do a heap-check in the alternatives (see+Note [Compiling case expressions]), then we *must* retreat Hp to+recover any unused heap before passing control to the sequel. If we+don't do this, then any unused heap will become slop because the heap+check will reset the heap usage. Slop in the heap breaks LDV profiling+(+RTS -hb) which needs to do a linear sweep through the nursery.+++Note [Inlining out-of-line primops and heap checks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If shouldInlinePrimOp returns True when called from StgCmmExpr for the+purpose of heap check placement, we *must* inline the primop later in+StgCmmPrim. If we don't things will go wrong.+-}++-----------------+maybeSaveCostCentre :: Bool -> FCode (Maybe LocalReg)+maybeSaveCostCentre simple_scrut+ | simple_scrut = return Nothing+ | otherwise = saveCurrentCostCentre+++-----------------+isSimpleScrut :: StgExpr -> AltType -> FCode Bool+-- Simple scrutinee, does not block or allocate; hence safe to amalgamate+-- heap usage from alternatives into the stuff before the case+-- NB: if you get this wrong, and claim that the expression doesn't allocate+-- when it does, you'll deeply mess up allocation+isSimpleScrut (StgOpApp op args _) _ = isSimpleOp op args+isSimpleScrut (StgLit _) _ = return True -- case 1# of { 0# -> ..; ... }+isSimpleScrut (StgApp _ []) (PrimAlt _) = return True -- case x# of { 0# -> ..; ... }+isSimpleScrut _ _ = return False++isSimpleOp :: StgOp -> [StgArg] -> FCode Bool+-- True iff the op cannot block or allocate+isSimpleOp (StgFCallOp (CCall (CCallSpec _ _ safe)) _) _ = return $! not (playSafe safe)+isSimpleOp (StgPrimOp op) stg_args = do+ arg_exprs <- getNonVoidArgAmodes stg_args+ dflags <- getDynFlags+ -- See Note [Inlining out-of-line primops and heap checks]+ return $! isJust $ shouldInlinePrimOp dflags op arg_exprs+isSimpleOp (StgPrimCallOp _) _ = return False++-----------------+chooseReturnBndrs :: Id -> AltType -> [StgAlt] -> [NonVoid Id]+-- These are the binders of a case that are assigned by the evaluation of the+-- scrutinee.+-- They're non-void, see Note [Post-unarisation invariants] in UnariseStg.+chooseReturnBndrs bndr (PrimAlt _) _alts+ = assertNonVoidIds [bndr]++chooseReturnBndrs _bndr (MultiValAlt n) [(_, ids, _)]+ = ASSERT2(n == length ids, ppr n $$ ppr ids $$ ppr _bndr)+ assertNonVoidIds ids -- 'bndr' is not assigned!++chooseReturnBndrs bndr (AlgAlt _) _alts+ = assertNonVoidIds [bndr] -- Only 'bndr' is assigned++chooseReturnBndrs bndr PolyAlt _alts+ = assertNonVoidIds [bndr] -- Only 'bndr' is assigned++chooseReturnBndrs _ _ _ = panic "chooseReturnBndrs"+ -- MultiValAlt has only one alternative++-------------------------------------+cgAlts :: (GcPlan,ReturnKind) -> NonVoid Id -> AltType -> [StgAlt]+ -> FCode ReturnKind+-- At this point the result of the case are in the binders+cgAlts gc_plan _bndr PolyAlt [(_, _, rhs)]+ = maybeAltHeapCheck gc_plan (cgExpr rhs)++cgAlts gc_plan _bndr (MultiValAlt _) [(_, _, rhs)]+ = maybeAltHeapCheck gc_plan (cgExpr rhs)+ -- Here bndrs are *already* in scope, so don't rebind them++cgAlts gc_plan bndr (PrimAlt _) alts+ = do { dflags <- getDynFlags++ ; tagged_cmms <- cgAltRhss gc_plan bndr alts++ ; let bndr_reg = CmmLocal (idToReg dflags bndr)+ (DEFAULT,deflt) = head tagged_cmms+ -- PrimAlts always have a DEFAULT case+ -- and it always comes first++ tagged_cmms' = [(lit,code)+ | (LitAlt lit, code) <- tagged_cmms]+ ; emitCmmLitSwitch (CmmReg bndr_reg) tagged_cmms' deflt+ ; return AssignedDirectly }++cgAlts gc_plan bndr (AlgAlt tycon) alts+ = do { dflags <- getDynFlags++ ; (mb_deflt, branches) <- cgAlgAltRhss gc_plan bndr alts++ ; let fam_sz = tyConFamilySize tycon+ bndr_reg = CmmLocal (idToReg dflags bndr)++ -- Is the constructor tag in the node reg?+ ; if isSmallFamily dflags fam_sz+ then do+ let -- Yes, bndr_reg has constr. tag in ls bits+ tag_expr = cmmConstrTag1 dflags (CmmReg bndr_reg)+ branches' = [(tag+1,branch) | (tag,branch) <- branches]+ emitSwitch tag_expr branches' mb_deflt 1 fam_sz++ else -- No, get tag from info table+ do dflags <- getDynFlags+ let -- Note that ptr _always_ has tag 1+ -- when the family size is big enough+ untagged_ptr = cmmRegOffB bndr_reg (-1)+ tag_expr = getConstrTag dflags (untagged_ptr)+ emitSwitch tag_expr branches mb_deflt 0 (fam_sz - 1)++ ; return AssignedDirectly }++cgAlts _ _ _ _ = panic "cgAlts"+ -- UbxTupAlt and PolyAlt have only one alternative+++-- Note [alg-alt heap check]+--+-- In an algebraic case with more than one alternative, we will have+-- code like+--+-- L0:+-- x = R1+-- goto L1+-- L1:+-- if (x & 7 >= 2) then goto L2 else goto L3+-- L2:+-- Hp = Hp + 16+-- if (Hp > HpLim) then goto L4+-- ...+-- L4:+-- call gc() returns to L5+-- L5:+-- x = R1+-- goto L1++-------------------+cgAlgAltRhss :: (GcPlan,ReturnKind) -> NonVoid Id -> [StgAlt]+ -> FCode ( Maybe CmmAGraphScoped+ , [(ConTagZ, CmmAGraphScoped)] )+cgAlgAltRhss gc_plan bndr alts+ = do { tagged_cmms <- cgAltRhss gc_plan bndr alts++ ; let { mb_deflt = case tagged_cmms of+ ((DEFAULT,rhs) : _) -> Just rhs+ _other -> Nothing+ -- DEFAULT is always first, if present++ ; branches = [ (dataConTagZ con, cmm)+ | (DataAlt con, cmm) <- tagged_cmms ]+ }++ ; return (mb_deflt, branches)+ }+++-------------------+cgAltRhss :: (GcPlan,ReturnKind) -> NonVoid Id -> [StgAlt]+ -> FCode [(AltCon, CmmAGraphScoped)]+cgAltRhss gc_plan bndr alts = do+ dflags <- getDynFlags+ let+ base_reg = idToReg dflags bndr+ cg_alt :: StgAlt -> FCode (AltCon, CmmAGraphScoped)+ cg_alt (con, bndrs, rhs)+ = getCodeScoped $+ maybeAltHeapCheck gc_plan $+ do { _ <- bindConArgs con base_reg (assertNonVoidIds bndrs)+ -- alt binders are always non-void,+ -- see Note [Post-unarisation invariants] in UnariseStg+ ; _ <- cgExpr rhs+ ; return con }+ forkAlts (map cg_alt alts)++maybeAltHeapCheck :: (GcPlan,ReturnKind) -> FCode a -> FCode a+maybeAltHeapCheck (NoGcInAlts,_) code = code+maybeAltHeapCheck (GcInAlts regs, AssignedDirectly) code =+ altHeapCheck regs code+maybeAltHeapCheck (GcInAlts regs, ReturnedTo lret off) code =+ altHeapCheckReturnsTo regs lret off code++-----------------------------------------------------------------------------+-- Tail calls+-----------------------------------------------------------------------------++cgConApp :: DataCon -> [StgArg] -> FCode ReturnKind+cgConApp con stg_args+ | isUnboxedTupleCon con -- Unboxed tuple: assign and return+ = do { arg_exprs <- getNonVoidArgAmodes stg_args+ ; tickyUnboxedTupleReturn (length arg_exprs)+ ; emitReturn arg_exprs }++ | otherwise -- Boxed constructors; allocate and return+ = ASSERT2( stg_args `lengthIs` countConRepArgs con, ppr con <> parens (ppr (countConRepArgs con)) <+> ppr stg_args )+ do { (idinfo, fcode_init) <- buildDynCon (dataConWorkId con) False+ currentCCS con (assertNonVoidStgArgs stg_args)+ -- con args are always non-void,+ -- see Note [Post-unarisation invariants] in UnariseStg+ -- The first "con" says that the name bound to this+ -- closure is "con", which is a bit of a fudge, but+ -- it only affects profiling (hence the False)++ ; emit =<< fcode_init+ ; tickyReturnNewCon (length stg_args)+ ; emitReturn [idInfoToAmode idinfo] }++cgIdApp :: Id -> [StgArg] -> FCode ReturnKind+cgIdApp fun_id [] | isVoidTy (idType fun_id) = emitReturn []+cgIdApp fun_id args = do+ dflags <- getDynFlags+ fun_info <- getCgIdInfo fun_id+ self_loop_info <- getSelfLoop+ let cg_fun_id = cg_id fun_info+ -- NB: use (cg_id fun_info) instead of fun_id, because+ -- the former may be externalised for -split-objs.+ -- See Note [Externalise when splitting] in StgCmmMonad++ fun_arg = StgVarArg cg_fun_id+ fun_name = idName cg_fun_id+ fun = idInfoToAmode fun_info+ lf_info = cg_lf fun_info+ n_args = length args+ v_args = length $ filter (isVoidTy . stgArgType) args+ node_points dflags = nodeMustPointToIt dflags lf_info+ case getCallMethod dflags fun_name cg_fun_id lf_info n_args v_args (cg_loc fun_info) self_loop_info of++ -- A value in WHNF, so we can just return it.+ ReturnIt -> emitReturn [fun] -- ToDo: does ReturnIt guarantee tagged?++ EnterIt -> ASSERT( null args ) -- Discarding arguments+ emitEnter fun++ SlowCall -> do -- A slow function call via the RTS apply routines+ { tickySlowCall lf_info args+ ; emitComment $ mkFastString "slowCall"+ ; slowCall fun args }++ -- A direct function call (possibly with some left-over arguments)+ DirectEntry lbl arity -> do+ { tickyDirectCall arity args+ ; if node_points dflags+ then directCall NativeNodeCall lbl arity (fun_arg:args)+ else directCall NativeDirectCall lbl arity args }++ -- Let-no-escape call or self-recursive tail-call+ JumpToIt blk_id lne_regs -> do+ { adjustHpBackwards -- always do this before a tail-call+ ; cmm_args <- getNonVoidArgAmodes args+ ; emitMultiAssign lne_regs cmm_args+ ; emit (mkBranch blk_id)+ ; return AssignedDirectly }++-- Note [Self-recursive tail calls]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Self-recursive tail calls can be optimized into a local jump in the same+-- way as let-no-escape bindings (see Note [What is a non-escaping let] in+-- stgSyn/CoreToStg.hs). Consider this:+--+-- foo.info:+-- a = R1 // calling convention+-- b = R2+-- goto L1+-- L1: ...+-- ...+-- ...+-- L2: R1 = x+-- R2 = y+-- call foo(R1,R2)+--+-- Instead of putting x and y into registers (or other locations required by the+-- calling convention) and performing a call we can put them into local+-- variables a and b and perform jump to L1:+--+-- foo.info:+-- a = R1+-- b = R2+-- goto L1+-- L1: ...+-- ...+-- ...+-- L2: a = x+-- b = y+-- goto L1+--+-- This can be done only when function is calling itself in a tail position+-- and only if the call passes number of parameters equal to function's arity.+-- Note that this cannot be performed if a function calls itself with a+-- continuation.+--+-- This in fact implements optimization known as "loopification". It was+-- described in "Low-level code optimizations in the Glasgow Haskell Compiler"+-- by Krzysztof Woś, though we use different approach. Krzysztof performed his+-- optimization at the Cmm level, whereas we perform ours during code generation+-- (Stg-to-Cmm pass) essentially making sure that optimized Cmm code is+-- generated in the first place.+--+-- Implementation is spread across a couple of places in the code:+--+-- * FCode monad stores additional information in its reader environment+-- (cgd_self_loop field). This information tells us which function can+-- tail call itself in an optimized way (it is the function currently+-- being compiled), what is the label of a loop header (L1 in example above)+-- and information about local registers in which we should arguments+-- before making a call (this would be a and b in example above).+--+-- * Whenever we are compiling a function, we set that information to reflect+-- the fact that function currently being compiled can be jumped to, instead+-- of called. This is done in closureCodyBody in StgCmmBind.+--+-- * We also have to emit a label to which we will be jumping. We make sure+-- that the label is placed after a stack check but before the heap+-- check. The reason is that making a recursive tail-call does not increase+-- the stack so we only need to check once. But it may grow the heap, so we+-- have to repeat the heap check in every self-call. This is done in+-- do_checks in StgCmmHeap.+--+-- * When we begin compilation of another closure we remove the additional+-- information from the environment. This is done by forkClosureBody+-- in StgCmmMonad. Other functions that duplicate the environment -+-- forkLneBody, forkAlts, codeOnly - duplicate that information. In other+-- words, we only need to clean the environment of the self-loop information+-- when compiling right hand side of a closure (binding).+--+-- * When compiling a call (cgIdApp) we use getCallMethod to decide what kind+-- of call will be generated. getCallMethod decides to generate a self+-- recursive tail call when (a) environment stores information about+-- possible self tail-call; (b) that tail call is to a function currently+-- being compiled; (c) number of passed non-void arguments is equal to+-- function's arity. (d) loopification is turned on via -floopification+-- command-line option.+--+-- * Command line option to turn loopification on and off is implemented in+-- DynFlags.+--+--+-- Note [Void arguments in self-recursive tail calls]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- State# tokens can get in the way of the loopification optimization as seen in+-- #11372. Consider this:+--+-- foo :: [a]+-- -> (a -> State# s -> (# State s, Bool #))+-- -> State# s+-- -> (# State# s, Maybe a #)+-- foo [] f s = (# s, Nothing #)+-- foo (x:xs) f s = case f x s of+-- (# s', b #) -> case b of+-- True -> (# s', Just x #)+-- False -> foo xs f s'+--+-- We would like to compile the call to foo as a local jump instead of a call+-- (see Note [Self-recursive tail calls]). However, the generated function has+-- an arity of 2 while we apply it to 3 arguments, one of them being of void+-- type. Thus, we mustn't count arguments of void type when checking whether+-- we can turn a call into a self-recursive jump.+--++emitEnter :: CmmExpr -> FCode ReturnKind+emitEnter fun = do+ { dflags <- getDynFlags+ ; adjustHpBackwards+ ; sequel <- getSequel+ ; updfr_off <- getUpdFrameOff+ ; case sequel of+ -- For a return, we have the option of generating a tag-test or+ -- not. If the value is tagged, we can return directly, which+ -- is quicker than entering the value. This is a code+ -- size/speed trade-off: when optimising for speed rather than+ -- size we could generate the tag test.+ --+ -- Right now, we do what the old codegen did, and omit the tag+ -- test, just generating an enter.+ Return -> do+ { let entry = entryCode dflags $ closureInfoPtr dflags $ CmmReg nodeReg+ ; emit $ mkJump dflags NativeNodeCall entry+ [cmmUntag dflags fun] updfr_off+ ; return AssignedDirectly+ }++ -- The result will be scrutinised in the sequel. This is where+ -- we generate a tag-test to avoid entering the closure if+ -- possible.+ --+ -- The generated code will be something like this:+ --+ -- R1 = fun -- copyout+ -- if (fun & 7 != 0) goto Lret else goto Lcall+ -- Lcall:+ -- call [fun] returns to Lret+ -- Lret:+ -- fun' = R1 -- copyin+ -- ...+ --+ -- Note in particular that the label Lret is used as a+ -- destination by both the tag-test and the call. This is+ -- because Lret will necessarily be a proc-point, and we want to+ -- ensure that we generate only one proc-point for this+ -- sequence.+ --+ -- Furthermore, we tell the caller that we generated a native+ -- return continuation by returning (ReturnedTo Lret off), so+ -- that the continuation can be reused by the heap-check failure+ -- code in the enclosing case expression.+ --+ AssignTo res_regs _ -> do+ { lret <- newBlockId+ ; let (off, _, copyin) = copyInOflow dflags NativeReturn (Young lret) res_regs []+ ; lcall <- newBlockId+ ; updfr_off <- getUpdFrameOff+ ; let area = Young lret+ ; let (outArgs, regs, copyout) = copyOutOflow dflags NativeNodeCall Call area+ [fun] updfr_off []+ -- refer to fun via nodeReg after the copyout, to avoid having+ -- both live simultaneously; this sometimes enables fun to be+ -- inlined in the RHS of the R1 assignment.+ ; let entry = entryCode dflags (closureInfoPtr dflags (CmmReg nodeReg))+ the_call = toCall entry (Just lret) updfr_off off outArgs regs+ ; tscope <- getTickScope+ ; emit $+ copyout <*>+ mkCbranch (cmmIsTagged dflags (CmmReg nodeReg))+ lret lcall Nothing <*>+ outOfLine lcall (the_call,tscope) <*>+ mkLabel lret tscope <*>+ copyin+ ; return (ReturnedTo lret off)+ }+ }++------------------------------------------------------------------------+-- Ticks+------------------------------------------------------------------------++-- | Generate Cmm code for a tick. Depending on the type of Tickish,+-- this will either generate actual Cmm instrumentation code, or+-- simply pass on the annotation as a @CmmTickish@.+cgTick :: Tickish Id -> FCode ()+cgTick tick+ = do { dflags <- getDynFlags+ ; case tick of+ ProfNote cc t p -> emitSetCCC cc t p+ HpcTick m n -> emit (mkTickBox dflags m n)+ SourceNote s n -> emitTick $ SourceNote s n+ _other -> return () -- ignore+ }
+ codeGen/StgCmmExtCode.hs view
@@ -0,0 +1,251 @@+-- | Our extended FCode monad.++-- We add a mapping from names to CmmExpr, to support local variable names in+-- the concrete C-- code. The unique supply of the underlying FCode monad+-- is used to grab a new unique for each local variable.++-- In C--, a local variable can be declared anywhere within a proc,+-- and it scopes from the beginning of the proc to the end. Hence, we have+-- to collect declarations as we parse the proc, and feed the environment+-- back in circularly (to avoid a two-pass algorithm).++module StgCmmExtCode (+ CmmParse, unEC,+ Named(..), Env,++ loopDecls,+ getEnv,++ withName,+ getName,++ newLocal,+ newLabel,+ newBlockId,+ newFunctionName,+ newImport,+ lookupLabel,+ lookupName,++ code,+ emit, emitLabel, emitAssign, emitStore,+ getCode, getCodeR, getCodeScoped,+ emitOutOfLine,+ withUpdFrameOff, getUpdFrameOff+)++where++import qualified StgCmmMonad as F+import StgCmmMonad (FCode, newUnique)++import Cmm+import CLabel+import MkGraph++import BlockId+import DynFlags+import FastString+import Module+import UniqFM+import Unique+import UniqSupply++import Control.Monad (liftM, ap)++-- | The environment contains variable definitions or blockids.+data Named+ = VarN CmmExpr -- ^ Holds CmmLit(CmmLabel ..) which gives the label type,+ -- eg, RtsLabel, ForeignLabel, CmmLabel etc.++ | FunN UnitId -- ^ A function name from this package+ | LabelN BlockId -- ^ A blockid of some code or data.++-- | An environment of named things.+type Env = UniqFM Named++-- | Local declarations that are in scope during code generation.+type Decls = [(FastString,Named)]++-- | Does a computation in the FCode monad, with a current environment+-- and a list of local declarations. Returns the resulting list of declarations.+newtype CmmParse a+ = EC { unEC :: String -> Env -> Decls -> FCode (Decls, a) }++type ExtCode = CmmParse ()++returnExtFC :: a -> CmmParse a+returnExtFC a = EC $ \_ _ s -> return (s, a)++thenExtFC :: CmmParse a -> (a -> CmmParse b) -> CmmParse b+thenExtFC (EC m) k = EC $ \c e s -> do (s',r) <- m c e s; unEC (k r) c e s'++instance Functor CmmParse where+ fmap = liftM++instance Applicative CmmParse where+ pure = returnExtFC+ (<*>) = ap++instance Monad CmmParse where+ (>>=) = thenExtFC++instance MonadUnique CmmParse where+ getUniqueSupplyM = code getUniqueSupplyM+ getUniqueM = EC $ \_ _ decls -> do+ u <- getUniqueM+ return (decls, u)++instance HasDynFlags CmmParse where+ getDynFlags = EC (\_ _ d -> do dflags <- getDynFlags+ return (d, dflags))+++-- | Takes the variable decarations and imports from the monad+-- and makes an environment, which is looped back into the computation.+-- In this way, we can have embedded declarations that scope over the whole+-- procedure, and imports that scope over the entire module.+-- Discards the local declaration contained within decl'+--+loopDecls :: CmmParse a -> CmmParse a+loopDecls (EC fcode) =+ EC $ \c e globalDecls -> do+ (_, a) <- F.fixC $ \ ~(decls, _) ->+ fcode c (addListToUFM e decls) globalDecls+ return (globalDecls, a)+++-- | Get the current environment from the monad.+getEnv :: CmmParse Env+getEnv = EC $ \_ e s -> return (s, e)++-- | Get the current context name from the monad+getName :: CmmParse String+getName = EC $ \c _ s -> return (s, c)++-- | Set context name for a sub-parse+withName :: String -> CmmParse a -> CmmParse a+withName c' (EC fcode) = EC $ \_ e s -> fcode c' e s++addDecl :: FastString -> Named -> ExtCode+addDecl name named = EC $ \_ _ s -> return ((name, named) : s, ())+++-- | Add a new variable to the list of local declarations.+-- The CmmExpr says where the value is stored.+addVarDecl :: FastString -> CmmExpr -> ExtCode+addVarDecl var expr = addDecl var (VarN expr)++-- | Add a new label to the list of local declarations.+addLabel :: FastString -> BlockId -> ExtCode+addLabel name block_id = addDecl name (LabelN block_id)+++-- | Create a fresh local variable of a given type.+newLocal+ :: CmmType -- ^ data type+ -> FastString -- ^ name of variable+ -> CmmParse LocalReg -- ^ register holding the value++newLocal ty name = do+ u <- code newUnique+ let reg = LocalReg u ty+ addVarDecl name (CmmReg (CmmLocal reg))+ return reg+++-- | Allocate a fresh label.+newLabel :: FastString -> CmmParse BlockId+newLabel name = do+ u <- code newUnique+ addLabel name (mkBlockId u)+ return (mkBlockId u)++-- | Add add a local function to the environment.+newFunctionName+ :: FastString -- ^ name of the function+ -> UnitId -- ^ package of the current module+ -> ExtCode++newFunctionName name pkg = addDecl name (FunN pkg)+++-- | Add an imported foreign label to the list of local declarations.+-- If this is done at the start of the module the declaration will scope+-- over the whole module.+newImport+ :: (FastString, CLabel)+ -> CmmParse ()++newImport (name, cmmLabel)+ = addVarDecl name (CmmLit (CmmLabel cmmLabel))+++-- | Lookup the BlockId bound to the label with this name.+-- If one hasn't been bound yet, create a fresh one based on the+-- Unique of the name.+lookupLabel :: FastString -> CmmParse BlockId+lookupLabel name = do+ env <- getEnv+ return $+ case lookupUFM env name of+ Just (LabelN l) -> l+ _other -> mkBlockId (newTagUnique (getUnique name) 'L')+++-- | Lookup the location of a named variable.+-- Unknown names are treated as if they had been 'import'ed from the runtime system.+-- This saves us a lot of bother in the RTS sources, at the expense of+-- deferring some errors to link time.+lookupName :: FastString -> CmmParse CmmExpr+lookupName name = do+ env <- getEnv+ return $+ case lookupUFM env name of+ Just (VarN e) -> e+ Just (FunN pkg) -> CmmLit (CmmLabel (mkCmmCodeLabel pkg name))+ _other -> CmmLit (CmmLabel (mkCmmCodeLabel rtsUnitId name))+++-- | Lift an FCode computation into the CmmParse monad+code :: FCode a -> CmmParse a+code fc = EC $ \_ _ s -> do+ r <- fc+ return (s, r)++emit :: CmmAGraph -> CmmParse ()+emit = code . F.emit++emitLabel :: BlockId -> CmmParse ()+emitLabel = code . F.emitLabel++emitAssign :: CmmReg -> CmmExpr -> CmmParse ()+emitAssign l r = code (F.emitAssign l r)++emitStore :: CmmExpr -> CmmExpr -> CmmParse ()+emitStore l r = code (F.emitStore l r)++getCode :: CmmParse a -> CmmParse CmmAGraph+getCode (EC ec) = EC $ \c e s -> do+ ((s',_), gr) <- F.getCodeR (ec c e s)+ return (s', gr)++getCodeR :: CmmParse a -> CmmParse (a, CmmAGraph)+getCodeR (EC ec) = EC $ \c e s -> do+ ((s', r), gr) <- F.getCodeR (ec c e s)+ return (s', (r,gr))++getCodeScoped :: CmmParse a -> CmmParse (a, CmmAGraphScoped)+getCodeScoped (EC ec) = EC $ \c e s -> do+ ((s', r), gr) <- F.getCodeScoped (ec c e s)+ return (s', (r,gr))++emitOutOfLine :: BlockId -> CmmAGraphScoped -> CmmParse ()+emitOutOfLine l g = code (F.emitOutOfLine l g)++withUpdFrameOff :: UpdFrameOffset -> CmmParse () -> CmmParse ()+withUpdFrameOff size inner+ = EC $ \c e s -> F.withUpdFrameOff size $ (unEC inner) c e s++getUpdFrameOff :: CmmParse UpdFrameOffset+getUpdFrameOff = code $ F.getUpdFrameOff
+ codeGen/StgCmmForeign.hs view
@@ -0,0 +1,553 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Code generation for foreign calls.+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmForeign (+ cgForeignCall,+ emitPrimCall, emitCCall,+ emitForeignCall, -- For CmmParse+ emitSaveThreadState,+ saveThreadState,+ emitLoadThreadState,+ loadThreadState,+ emitOpenNursery,+ emitCloseNursery,+ ) where++#include "HsVersions.h"++import StgSyn+import StgCmmProf (storeCurCCS, ccsType, curCCS)+import StgCmmEnv+import StgCmmMonad+import StgCmmUtils+import StgCmmClosure+import StgCmmLayout++import BlockId (newBlockId)+import Cmm+import CmmUtils+import MkGraph+import Type+import RepType+import TysPrim+import CLabel+import SMRep+import ForeignCall+import DynFlags+import Maybes+import Outputable+import UniqSupply+import BasicTypes++import Control.Monad++import Prelude hiding( succ, (<*>) )++-----------------------------------------------------------------------------+-- Code generation for Foreign Calls+-----------------------------------------------------------------------------++-- | emit code for a foreign call, and return the results to the sequel.+--+cgForeignCall :: ForeignCall -- the op+ -> [StgArg] -- x,y arguments+ -> Type -- result type+ -> FCode ReturnKind++cgForeignCall (CCall (CCallSpec target cconv safety)) stg_args res_ty+ = do { dflags <- getDynFlags+ ; let -- in the stdcall calling convention, the symbol needs @size appended+ -- to it, where size is the total number of bytes of arguments. We+ -- attach this info to the CLabel here, and the CLabel pretty printer+ -- will generate the suffix when the label is printed.+ call_size args+ | StdCallConv <- cconv = Just (sum (map arg_size args))+ | otherwise = Nothing++ -- ToDo: this might not be correct for 64-bit API+ arg_size (arg, _) = max (widthInBytes $ typeWidth $ cmmExprType dflags arg)+ (wORD_SIZE dflags)+ ; cmm_args <- getFCallArgs stg_args+ ; (res_regs, res_hints) <- newUnboxedTupleRegs res_ty+ ; let ((call_args, arg_hints), cmm_target)+ = case target of+ StaticTarget _ _ _ False ->+ panic "cgForeignCall: unexpected FFI value import"+ StaticTarget _ lbl mPkgId True+ -> let labelSource+ = case mPkgId of+ Nothing -> ForeignLabelInThisPackage+ Just pkgId -> ForeignLabelInPackage pkgId+ size = call_size cmm_args+ in ( unzip cmm_args+ , CmmLit (CmmLabel+ (mkForeignLabel lbl size labelSource IsFunction)))++ DynamicTarget -> case cmm_args of+ (fn,_):rest -> (unzip rest, fn)+ [] -> panic "cgForeignCall []"+ fc = ForeignConvention cconv arg_hints res_hints CmmMayReturn+ call_target = ForeignTarget cmm_target fc++ -- we want to emit code for the call, and then emitReturn.+ -- However, if the sequel is AssignTo, we shortcut a little+ -- and generate a foreign call that assigns the results+ -- directly. Otherwise we end up generating a bunch of+ -- useless "r = r" assignments, which are not merely annoying:+ -- they prevent the common block elimination from working correctly+ -- in the case of a safe foreign call.+ -- See Note [safe foreign call convention]+ --+ ; sequel <- getSequel+ ; case sequel of+ AssignTo assign_to_these _ ->+ emitForeignCall safety assign_to_these call_target call_args++ _something_else ->+ do { _ <- emitForeignCall safety res_regs call_target call_args+ ; emitReturn (map (CmmReg . CmmLocal) res_regs)+ }+ }++{- Note [safe foreign call convention]++The simple thing to do for a safe foreign call would be the same as an+unsafe one: just++ emitForeignCall ...+ emitReturn ...++but consider what happens in this case++ case foo x y z of+ (# s, r #) -> ...++The sequel is AssignTo [r]. The call to newUnboxedTupleRegs picks [r]+as the result reg, and we generate++ r = foo(x,y,z) returns to L1 -- emitForeignCall+ L1:+ r = r -- emitReturn+ goto L2+L2:+ ...++Now L1 is a proc point (by definition, it is the continuation of the+safe foreign call). If L2 does a heap check, then L2 will also be a+proc point.++Furthermore, the stack layout algorithm has to arrange to save r+somewhere between the call and the jump to L1, which is annoying: we+would have to treat r differently from the other live variables, which+have to be saved *before* the call.++So we adopt a special convention for safe foreign calls: the results+are copied out according to the NativeReturn convention by the call,+and the continuation of the call should copyIn the results. (The+copyOut code is actually inserted when the safe foreign call is+lowered later). The result regs attached to the safe foreign call are+only used temporarily to hold the results before they are copied out.++We will now generate this:++ r = foo(x,y,z) returns to L1+ L1:+ r = R1 -- copyIn, inserted by mkSafeCall+ goto L2+ L2:+ ... r ...++And when the safe foreign call is lowered later (see Note [lower safe+foreign calls]) we get this:++ suspendThread()+ r = foo(x,y,z)+ resumeThread()+ R1 = r -- copyOut, inserted by lowerSafeForeignCall+ jump L1+ L1:+ r = R1 -- copyIn, inserted by mkSafeCall+ goto L2+ L2:+ ... r ...++Now consider what happens if L2 does a heap check: the Adams+optimisation kicks in and commons up L1 with the heap-check+continuation, resulting in just one proc point instead of two. Yay!+-}+++emitCCall :: [(CmmFormal,ForeignHint)]+ -> CmmExpr+ -> [(CmmActual,ForeignHint)]+ -> FCode ()+emitCCall hinted_results fn hinted_args+ = void $ emitForeignCall PlayRisky results target args+ where+ (args, arg_hints) = unzip hinted_args+ (results, result_hints) = unzip hinted_results+ target = ForeignTarget fn fc+ fc = ForeignConvention CCallConv arg_hints result_hints CmmMayReturn+++emitPrimCall :: [CmmFormal] -> CallishMachOp -> [CmmActual] -> FCode ()+emitPrimCall res op args+ = void $ emitForeignCall PlayRisky res (PrimTarget op) args++-- alternative entry point, used by CmmParse+emitForeignCall+ :: Safety+ -> [CmmFormal] -- where to put the results+ -> ForeignTarget -- the op+ -> [CmmActual] -- arguments+ -> FCode ReturnKind+emitForeignCall safety results target args+ | not (playSafe safety) = do+ dflags <- getDynFlags+ let (caller_save, caller_load) = callerSaveVolatileRegs dflags+ emit caller_save+ target' <- load_target_into_temp target+ args' <- mapM maybe_assign_temp args+ emit $ mkUnsafeCall target' results args'+ emit caller_load+ return AssignedDirectly++ | otherwise = do+ dflags <- getDynFlags+ updfr_off <- getUpdFrameOff+ target' <- load_target_into_temp target+ args' <- mapM maybe_assign_temp args+ k <- newBlockId+ let (off, _, copyout) = copyInOflow dflags NativeReturn (Young k) results []+ -- see Note [safe foreign call convention]+ tscope <- getTickScope+ emit $+ ( mkStore (CmmStackSlot (Young k) (widthInBytes (wordWidth dflags)))+ (CmmLit (CmmBlock k))+ <*> mkLast (CmmForeignCall { tgt = target'+ , res = results+ , args = args'+ , succ = k+ , ret_args = off+ , ret_off = updfr_off+ , intrbl = playInterruptible safety })+ <*> mkLabel k tscope+ <*> copyout+ )+ return (ReturnedTo k off)++load_target_into_temp :: ForeignTarget -> FCode ForeignTarget+load_target_into_temp (ForeignTarget expr conv) = do+ tmp <- maybe_assign_temp expr+ return (ForeignTarget tmp conv)+load_target_into_temp other_target@(PrimTarget _) =+ return other_target++-- What we want to do here is create a new temporary for the foreign+-- call argument if it is not safe to use the expression directly,+-- because the expression mentions caller-saves GlobalRegs (see+-- Note [Register Parameter Passing]).+--+-- However, we can't pattern-match on the expression here, because+-- this is used in a loop by CmmParse, and testing the expression+-- results in a black hole. So we always create a temporary, and rely+-- on CmmSink to clean it up later. (Yuck, ToDo). The generated code+-- ends up being the same, at least for the RTS .cmm code.+--+maybe_assign_temp :: CmmExpr -> FCode CmmExpr+maybe_assign_temp e = do+ dflags <- getDynFlags+ reg <- newTemp (cmmExprType dflags e)+ emitAssign (CmmLocal reg) e+ return (CmmReg (CmmLocal reg))++-- -----------------------------------------------------------------------------+-- Save/restore the thread state in the TSO++-- This stuff can't be done in suspendThread/resumeThread, because it+-- refers to global registers which aren't available in the C world.++emitSaveThreadState :: FCode ()+emitSaveThreadState = do+ dflags <- getDynFlags+ code <- saveThreadState dflags+ emit code++-- | Produce code to save the current thread state to @CurrentTSO@+saveThreadState :: MonadUnique m => DynFlags -> m CmmAGraph+saveThreadState dflags = do+ tso <- newTemp (gcWord dflags)+ close_nursery <- closeNursery dflags tso+ pure $ catAGraphs [+ -- tso = CurrentTSO;+ mkAssign (CmmLocal tso) stgCurrentTSO,+ -- tso->stackobj->sp = Sp;+ mkStore (cmmOffset dflags+ (CmmLoad (cmmOffset dflags+ (CmmReg (CmmLocal tso))+ (tso_stackobj dflags))+ (bWord dflags))+ (stack_SP dflags))+ stgSp,+ close_nursery,+ -- and save the current cost centre stack in the TSO when profiling:+ if gopt Opt_SccProfilingOn dflags then+ mkStore (cmmOffset dflags (CmmReg (CmmLocal tso)) (tso_CCCS dflags)) curCCS+ else mkNop+ ]++emitCloseNursery :: FCode ()+emitCloseNursery = do+ dflags <- getDynFlags+ tso <- newTemp (bWord dflags)+ code <- closeNursery dflags tso+ emit $ mkAssign (CmmLocal tso) stgCurrentTSO <*> code++{- |+@closeNursery dflags tso@ produces code to close the nursery.+A local register holding the value of @CurrentTSO@ is expected for+efficiency.++Closing the nursery corresponds to the following code:++@+ tso = CurrentTSO;+ cn = CurrentNuresry;++ // Update the allocation limit for the current thread. We don't+ // check to see whether it has overflowed at this point, that check is+ // made when we run out of space in the current heap block (stg_gc_noregs)+ // and in the scheduler when context switching (schedulePostRunThread).+ tso->alloc_limit -= Hp + WDS(1) - cn->start;++ // Set cn->free to the next unoccupied word in the block+ cn->free = Hp + WDS(1);+@+-}+closeNursery :: MonadUnique m => DynFlags -> LocalReg -> m CmmAGraph+closeNursery df tso = do+ let tsoreg = CmmLocal tso+ cnreg <- CmmLocal <$> newTemp (bWord df)+ pure $ catAGraphs [+ mkAssign cnreg stgCurrentNursery,++ -- CurrentNursery->free = Hp+1;+ mkStore (nursery_bdescr_free df cnreg) (cmmOffsetW df stgHp 1),++ let alloc =+ CmmMachOp (mo_wordSub df)+ [ cmmOffsetW df stgHp 1+ , CmmLoad (nursery_bdescr_start df cnreg) (bWord df)+ ]++ alloc_limit = cmmOffset df (CmmReg tsoreg) (tso_alloc_limit df)+ in++ -- tso->alloc_limit += alloc+ mkStore alloc_limit (CmmMachOp (MO_Sub W64)+ [ CmmLoad alloc_limit b64+ , CmmMachOp (mo_WordTo64 df) [alloc] ])+ ]++emitLoadThreadState :: FCode ()+emitLoadThreadState = do+ dflags <- getDynFlags+ code <- loadThreadState dflags+ emit code++-- | Produce code to load the current thread state from @CurrentTSO@+loadThreadState :: MonadUnique m => DynFlags -> m CmmAGraph+loadThreadState dflags = do+ tso <- newTemp (gcWord dflags)+ stack <- newTemp (gcWord dflags)+ open_nursery <- openNursery dflags tso+ pure $ catAGraphs [+ -- tso = CurrentTSO;+ mkAssign (CmmLocal tso) stgCurrentTSO,+ -- stack = tso->stackobj;+ mkAssign (CmmLocal stack) (CmmLoad (cmmOffset dflags (CmmReg (CmmLocal tso)) (tso_stackobj dflags)) (bWord dflags)),+ -- Sp = stack->sp;+ mkAssign sp (CmmLoad (cmmOffset dflags (CmmReg (CmmLocal stack)) (stack_SP dflags)) (bWord dflags)),+ -- SpLim = stack->stack + RESERVED_STACK_WORDS;+ mkAssign spLim (cmmOffsetW dflags (cmmOffset dflags (CmmReg (CmmLocal stack)) (stack_STACK dflags))+ (rESERVED_STACK_WORDS dflags)),+ -- HpAlloc = 0;+ -- HpAlloc is assumed to be set to non-zero only by a failed+ -- a heap check, see HeapStackCheck.cmm:GC_GENERIC+ mkAssign hpAlloc (zeroExpr dflags),+ open_nursery,+ -- and load the current cost centre stack from the TSO when profiling:+ if gopt Opt_SccProfilingOn dflags+ then storeCurCCS+ (CmmLoad (cmmOffset dflags (CmmReg (CmmLocal tso))+ (tso_CCCS dflags)) (ccsType dflags))+ else mkNop+ ]+++emitOpenNursery :: FCode ()+emitOpenNursery = do+ dflags <- getDynFlags+ tso <- newTemp (bWord dflags)+ code <- openNursery dflags tso+ emit $ mkAssign (CmmLocal tso) stgCurrentTSO <*> code++{- |+@openNursery dflags tso@ produces code to open the nursery. A local register+holding the value of @CurrentTSO@ is expected for efficiency.++Opening the nursery corresponds to the following code:++@+ tso = CurrentTSO;+ cn = CurrentNursery;+ bdfree = CurrentNuresry->free;+ bdstart = CurrentNuresry->start;++ // We *add* the currently occupied portion of the nursery block to+ // the allocation limit, because we will subtract it again in+ // closeNursery.+ tso->alloc_limit += bdfree - bdstart;++ // Set Hp to the last occupied word of the heap block. Why not the+ // next unocupied word? Doing it this way means that we get to use+ // an offset of zero more often, which might lead to slightly smaller+ // code on some architectures.+ Hp = bdfree - WDS(1);++ // Set HpLim to the end of the current nursery block (note that this block+ // might be a block group, consisting of several adjacent blocks.+ HpLim = bdstart + CurrentNursery->blocks*BLOCK_SIZE_W - 1;+@+-}+openNursery :: MonadUnique m => DynFlags -> LocalReg -> m CmmAGraph+openNursery df tso = do+ let tsoreg = CmmLocal tso+ cnreg <- CmmLocal <$> newTemp (bWord df)+ bdfreereg <- CmmLocal <$> newTemp (bWord df)+ bdstartreg <- CmmLocal <$> newTemp (bWord df)++ -- These assignments are carefully ordered to reduce register+ -- pressure and generate not completely awful code on x86. To see+ -- what code we generate, look at the assembly for+ -- stg_returnToStackTop in rts/StgStartup.cmm.+ pure $ catAGraphs [+ mkAssign cnreg stgCurrentNursery,+ mkAssign bdfreereg (CmmLoad (nursery_bdescr_free df cnreg) (bWord df)),++ -- Hp = CurrentNursery->free - 1;+ mkAssign hp (cmmOffsetW df (CmmReg bdfreereg) (-1)),++ mkAssign bdstartreg (CmmLoad (nursery_bdescr_start df cnreg) (bWord df)),++ -- HpLim = CurrentNursery->start ++ -- CurrentNursery->blocks*BLOCK_SIZE_W - 1;+ mkAssign hpLim+ (cmmOffsetExpr df+ (CmmReg bdstartreg)+ (cmmOffset df+ (CmmMachOp (mo_wordMul df) [+ CmmMachOp (MO_SS_Conv W32 (wordWidth df))+ [CmmLoad (nursery_bdescr_blocks df cnreg) b32],+ mkIntExpr df (bLOCK_SIZE df)+ ])+ (-1)+ )+ ),++ -- alloc = bd->free - bd->start+ let alloc =+ CmmMachOp (mo_wordSub df) [CmmReg bdfreereg, CmmReg bdstartreg]++ alloc_limit = cmmOffset df (CmmReg tsoreg) (tso_alloc_limit df)+ in++ -- tso->alloc_limit += alloc+ mkStore alloc_limit (CmmMachOp (MO_Add W64)+ [ CmmLoad alloc_limit b64+ , CmmMachOp (mo_WordTo64 df) [alloc] ])++ ]++nursery_bdescr_free, nursery_bdescr_start, nursery_bdescr_blocks+ :: DynFlags -> CmmReg -> CmmExpr+nursery_bdescr_free dflags cn =+ cmmOffset dflags (CmmReg cn) (oFFSET_bdescr_free dflags)+nursery_bdescr_start dflags cn =+ cmmOffset dflags (CmmReg cn) (oFFSET_bdescr_start dflags)+nursery_bdescr_blocks dflags cn =+ cmmOffset dflags (CmmReg cn) (oFFSET_bdescr_blocks dflags)++tso_stackobj, tso_CCCS, tso_alloc_limit, stack_STACK, stack_SP :: DynFlags -> ByteOff+tso_stackobj dflags = closureField dflags (oFFSET_StgTSO_stackobj dflags)+tso_alloc_limit dflags = closureField dflags (oFFSET_StgTSO_alloc_limit dflags)+tso_CCCS dflags = closureField dflags (oFFSET_StgTSO_cccs dflags)+stack_STACK dflags = closureField dflags (oFFSET_StgStack_stack dflags)+stack_SP dflags = closureField dflags (oFFSET_StgStack_sp dflags)+++closureField :: DynFlags -> ByteOff -> ByteOff+closureField dflags off = off + fixedHdrSize dflags++stgSp, stgHp, stgCurrentTSO, stgCurrentNursery :: CmmExpr+stgSp = CmmReg sp+stgHp = CmmReg hp+stgCurrentTSO = CmmReg currentTSO+stgCurrentNursery = CmmReg currentNursery++sp, spLim, hp, hpLim, currentTSO, currentNursery, hpAlloc :: CmmReg+sp = CmmGlobal Sp+spLim = CmmGlobal SpLim+hp = CmmGlobal Hp+hpLim = CmmGlobal HpLim+currentTSO = CmmGlobal CurrentTSO+currentNursery = CmmGlobal CurrentNursery+hpAlloc = CmmGlobal HpAlloc++-- -----------------------------------------------------------------------------+-- For certain types passed to foreign calls, we adjust the actual+-- value passed to the call. For ByteArray#/Array# we pass the+-- address of the actual array, not the address of the heap object.++getFCallArgs :: [StgArg] -> FCode [(CmmExpr, ForeignHint)]+-- (a) Drop void args+-- (b) Add foreign-call shim code+-- It's (b) that makes this differ from getNonVoidArgAmodes++getFCallArgs args+ = do { mb_cmms <- mapM get args+ ; return (catMaybes mb_cmms) }+ where+ get arg | null arg_reps+ = return Nothing+ | otherwise+ = do { cmm <- getArgAmode (NonVoid arg)+ ; dflags <- getDynFlags+ ; return (Just (add_shim dflags arg_ty cmm, hint)) }+ where+ arg_ty = stgArgType arg+ arg_reps = typePrimRep arg_ty+ hint = typeForeignHint arg_ty++add_shim :: DynFlags -> Type -> CmmExpr -> CmmExpr+add_shim dflags arg_ty expr+ | tycon == arrayPrimTyCon || tycon == mutableArrayPrimTyCon+ = cmmOffsetB dflags expr (arrPtrsHdrSize dflags)++ | tycon == smallArrayPrimTyCon || tycon == smallMutableArrayPrimTyCon+ = cmmOffsetB dflags expr (smallArrPtrsHdrSize dflags)++ | tycon == byteArrayPrimTyCon || tycon == mutableByteArrayPrimTyCon+ = cmmOffsetB dflags expr (arrWordsHdrSize dflags)++ | otherwise = expr+ where+ tycon = tyConAppTyCon (unwrapType arg_ty)+ -- should be a tycon app, since this is a foreign call
+ codeGen/StgCmmHeap.hs view
@@ -0,0 +1,698 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Stg to C--: heap management functions+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmHeap (+ getVirtHp, setVirtHp, setRealHp,+ getHpRelOffset,++ entryHeapCheck, altHeapCheck, noEscapeHeapCheck, altHeapCheckReturnsTo,+ heapStackCheckGen,+ entryHeapCheck',++ mkStaticClosureFields, mkStaticClosure,++ allocDynClosure, allocDynClosureCmm, allocHeapClosure,+ emitSetDynHdr+ ) where++#include "HsVersions.h"++import StgSyn+import CLabel+import StgCmmLayout+import StgCmmUtils+import StgCmmMonad+import StgCmmProf (profDynAlloc, dynProfHdr, staticProfHdr)+import StgCmmTicky+import StgCmmClosure+import StgCmmEnv++import MkGraph++import Hoopl+import SMRep+import BlockId+import Cmm+import CmmUtils+import CostCentre+import IdInfo( CafInfo(..), mayHaveCafRefs )+import Id ( Id )+import Module+import DynFlags+import FastString( mkFastString, fsLit )+import Panic( sorry )++import Prelude hiding ((<*>))++import Control.Monad (when)+import Data.Maybe (isJust)++-----------------------------------------------------------+-- Initialise dynamic heap objects+-----------------------------------------------------------++allocDynClosure+ :: Maybe Id+ -> CmmInfoTable+ -> LambdaFormInfo+ -> CmmExpr -- Cost Centre to stick in the object+ -> CmmExpr -- Cost Centre to blame for this alloc+ -- (usually the same; sometimes "OVERHEAD")++ -> [(NonVoid StgArg, VirtualHpOffset)] -- Offsets from start of object+ -- ie Info ptr has offset zero.+ -- No void args in here+ -> FCode CmmExpr -- returns Hp+n++allocDynClosureCmm+ :: Maybe Id -> CmmInfoTable -> LambdaFormInfo -> CmmExpr -> CmmExpr+ -> [(CmmExpr, ByteOff)]+ -> FCode CmmExpr -- returns Hp+n++-- allocDynClosure allocates the thing in the heap,+-- and modifies the virtual Hp to account for this.+-- The second return value is the graph that sets the value of the+-- returned LocalReg, which should point to the closure after executing+-- the graph.++-- allocDynClosure returns an (Hp+8) CmmExpr, and hence the result is+-- only valid until Hp is changed. The caller should assign the+-- result to a LocalReg if it is required to remain live.+--+-- The reason we don't assign it to a LocalReg here is that the caller+-- is often about to call regIdInfo, which immediately assigns the+-- result of allocDynClosure to a new temp in order to add the tag.+-- So by not generating a LocalReg here we avoid a common source of+-- new temporaries and save some compile time. This can be quite+-- significant - see test T4801.+++allocDynClosure mb_id info_tbl lf_info use_cc _blame_cc args_w_offsets = do+ let (args, offsets) = unzip args_w_offsets+ cmm_args <- mapM getArgAmode args -- No void args+ allocDynClosureCmm mb_id info_tbl lf_info+ use_cc _blame_cc (zip cmm_args offsets)+++allocDynClosureCmm mb_id info_tbl lf_info use_cc _blame_cc amodes_w_offsets = do+ -- SAY WHAT WE ARE ABOUT TO DO+ let rep = cit_rep info_tbl+ tickyDynAlloc mb_id rep lf_info+ let info_ptr = CmmLit (CmmLabel (cit_lbl info_tbl))+ allocHeapClosure rep info_ptr use_cc amodes_w_offsets+++-- | Low-level heap object allocation.+allocHeapClosure+ :: SMRep -- ^ representation of the object+ -> CmmExpr -- ^ info pointer+ -> CmmExpr -- ^ cost centre+ -> [(CmmExpr,ByteOff)] -- ^ payload+ -> FCode CmmExpr -- ^ returns the address of the object+allocHeapClosure rep info_ptr use_cc payload = do+ profDynAlloc rep use_cc++ virt_hp <- getVirtHp++ -- Find the offset of the info-ptr word+ let info_offset = virt_hp + 1+ -- info_offset is the VirtualHpOffset of the first+ -- word of the new object+ -- Remember, virtHp points to last allocated word,+ -- ie 1 *before* the info-ptr word of new object.++ base <- getHpRelOffset info_offset+ emitComment $ mkFastString "allocHeapClosure"+ emitSetDynHdr base info_ptr use_cc++ -- Fill in the fields+ hpStore base payload++ -- Bump the virtual heap pointer+ dflags <- getDynFlags+ setVirtHp (virt_hp + heapClosureSizeW dflags rep)++ return base+++emitSetDynHdr :: CmmExpr -> CmmExpr -> CmmExpr -> FCode ()+emitSetDynHdr base info_ptr ccs+ = do dflags <- getDynFlags+ hpStore base (zip (header dflags) [0, wORD_SIZE dflags ..])+ where+ header :: DynFlags -> [CmmExpr]+ header dflags = [info_ptr] ++ dynProfHdr dflags ccs+ -- ToDof: Parallel stuff+ -- No ticky header++-- Store the item (expr,off) in base[off]+hpStore :: CmmExpr -> [(CmmExpr, ByteOff)] -> FCode ()+hpStore base vals = do+ dflags <- getDynFlags+ sequence_ $+ [ emitStore (cmmOffsetB dflags base off) val | (val,off) <- vals ]++-----------------------------------------------------------+-- Layout of static closures+-----------------------------------------------------------++-- Make a static closure, adding on any extra padding needed for CAFs,+-- and adding a static link field if necessary.++mkStaticClosureFields+ :: DynFlags+ -> CmmInfoTable+ -> CostCentreStack+ -> CafInfo+ -> [CmmLit] -- Payload+ -> [CmmLit] -- The full closure+mkStaticClosureFields dflags info_tbl ccs caf_refs payload+ = mkStaticClosure dflags info_lbl ccs payload padding+ static_link_field saved_info_field+ where+ info_lbl = cit_lbl info_tbl++ -- CAFs must have consistent layout, regardless of whether they+ -- are actually updatable or not. The layout of a CAF is:+ --+ -- 3 saved_info+ -- 2 static_link+ -- 1 indirectee+ -- 0 info ptr+ --+ -- the static_link and saved_info fields must always be in the+ -- same place. So we use isThunkRep rather than closureUpdReqd+ -- here:++ is_caf = isThunkRep (cit_rep info_tbl)++ padding+ | is_caf && null payload = [mkIntCLit dflags 0]+ | otherwise = []++ static_link_field+ | is_caf || staticClosureNeedsLink (mayHaveCafRefs caf_refs) info_tbl+ = [static_link_value]+ | otherwise+ = []++ saved_info_field+ | is_caf = [mkIntCLit dflags 0]+ | otherwise = []++ -- For a static constructor which has NoCafRefs, we set the+ -- static link field to a non-zero value so the garbage+ -- collector will ignore it.+ static_link_value+ | mayHaveCafRefs caf_refs = mkIntCLit dflags 0+ | otherwise = mkIntCLit dflags 3 -- No CAF refs+ -- See Note [STATIC_LINK fields]+ -- in rts/sm/Storage.h++mkStaticClosure :: DynFlags -> CLabel -> CostCentreStack -> [CmmLit]+ -> [CmmLit] -> [CmmLit] -> [CmmLit] -> [CmmLit]+mkStaticClosure dflags info_lbl ccs payload padding static_link_field saved_info_field+ = [CmmLabel info_lbl]+ ++ staticProfHdr dflags ccs+ ++ concatMap (padLitToWord dflags) payload+ ++ padding+ ++ static_link_field+ ++ saved_info_field++-- JD: Simon had ellided this padding, but without it the C back end asserts+-- failure. Maybe it's a bad assertion, and this padding is indeed unnecessary?+padLitToWord :: DynFlags -> CmmLit -> [CmmLit]+padLitToWord dflags lit = lit : padding pad_length+ where width = typeWidth (cmmLitType dflags lit)+ pad_length = wORD_SIZE dflags - widthInBytes width :: Int++ padding n | n <= 0 = []+ | n `rem` 2 /= 0 = CmmInt 0 W8 : padding (n-1)+ | n `rem` 4 /= 0 = CmmInt 0 W16 : padding (n-2)+ | n `rem` 8 /= 0 = CmmInt 0 W32 : padding (n-4)+ | otherwise = CmmInt 0 W64 : padding (n-8)++-----------------------------------------------------------+-- Heap overflow checking+-----------------------------------------------------------++{- Note [Heap checks]+ ~~~~~~~~~~~~~~~~~~+Heap checks come in various forms. We provide the following entry+points to the runtime system, all of which use the native C-- entry+convention.++ * gc() performs garbage collection and returns+ nothing to its caller++ * A series of canned entry points like+ r = gc_1p( r )+ where r is a pointer. This performs gc, and+ then returns its argument r to its caller.++ * A series of canned entry points like+ gcfun_2p( f, x, y )+ where f is a function closure of arity 2+ This performs garbage collection, keeping alive the+ three argument ptrs, and then tail-calls f(x,y)++These are used in the following circumstances++* entryHeapCheck: Function entry+ (a) With a canned GC entry sequence+ f( f_clo, x:ptr, y:ptr ) {+ Hp = Hp+8+ if Hp > HpLim goto L+ ...+ L: HpAlloc = 8+ jump gcfun_2p( f_clo, x, y ) }+ Note the tail call to the garbage collector;+ it should do no register shuffling++ (b) No canned sequence+ f( f_clo, x:ptr, y:ptr, ...etc... ) {+ T: Hp = Hp+8+ if Hp > HpLim goto L+ ...+ L: HpAlloc = 8+ call gc() -- Needs an info table+ goto T }++* altHeapCheck: Immediately following an eval+ Started as+ case f x y of r { (p,q) -> rhs }+ (a) With a canned sequence for the results of f+ (which is the very common case since+ all boxed cases return just one pointer+ ...+ r = f( x, y )+ K: -- K needs an info table+ Hp = Hp+8+ if Hp > HpLim goto L+ ...code for rhs...++ L: r = gc_1p( r )+ goto K }++ Here, the info table needed by the call+ to gc_1p should be the *same* as the+ one for the call to f; the C-- optimiser+ spots this sharing opportunity)++ (b) No canned sequence for results of f+ Note second info table+ ...+ (r1,r2,r3) = call f( x, y )+ K:+ Hp = Hp+8+ if Hp > HpLim goto L+ ...code for rhs...++ L: call gc() -- Extra info table here+ goto K++* generalHeapCheck: Anywhere else+ e.g. entry to thunk+ case branch *not* following eval,+ or let-no-escape+ Exactly the same as the previous case:++ K: -- K needs an info table+ Hp = Hp+8+ if Hp > HpLim goto L+ ...++ L: call gc()+ goto K+-}++--------------------------------------------------------------+-- A heap/stack check at a function or thunk entry point.++entryHeapCheck :: ClosureInfo+ -> Maybe LocalReg -- Function (closure environment)+ -> Int -- Arity -- not same as len args b/c of voids+ -> [LocalReg] -- Non-void args (empty for thunk)+ -> FCode ()+ -> FCode ()++entryHeapCheck cl_info nodeSet arity args code+ = entryHeapCheck' is_fastf node arity args code+ where+ node = case nodeSet of+ Just r -> CmmReg (CmmLocal r)+ Nothing -> CmmLit (CmmLabel $ staticClosureLabel cl_info)++ is_fastf = case closureFunInfo cl_info of+ Just (_, ArgGen _) -> False+ _otherwise -> True++-- | lower-level version for CmmParse+entryHeapCheck' :: Bool -- is a known function pattern+ -> CmmExpr -- expression for the closure pointer+ -> Int -- Arity -- not same as len args b/c of voids+ -> [LocalReg] -- Non-void args (empty for thunk)+ -> FCode ()+ -> FCode ()+entryHeapCheck' is_fastf node arity args code+ = do dflags <- getDynFlags+ let is_thunk = arity == 0++ args' = map (CmmReg . CmmLocal) args+ stg_gc_fun = CmmReg (CmmGlobal GCFun)+ stg_gc_enter1 = CmmReg (CmmGlobal GCEnter1)++ {- Thunks: jump stg_gc_enter_1++ Function (fast): call (NativeNode) stg_gc_fun(fun, args)++ Function (slow): call (slow) stg_gc_fun(fun, args)+ -}+ gc_call upd+ | is_thunk+ = mkJump dflags NativeNodeCall stg_gc_enter1 [node] upd++ | is_fastf+ = mkJump dflags NativeNodeCall stg_gc_fun (node : args') upd++ | otherwise+ = mkJump dflags Slow stg_gc_fun (node : args') upd++ updfr_sz <- getUpdFrameOff++ loop_id <- newBlockId+ emitLabel loop_id+ heapCheck True True (gc_call updfr_sz <*> mkBranch loop_id) code++-- ------------------------------------------------------------+-- A heap/stack check in a case alternative+++-- If there are multiple alts and we need to GC, but don't have a+-- continuation already (the scrut was simple), then we should+-- pre-generate the continuation. (if there are multiple alts it is+-- always a canned GC point).++-- altHeapCheck:+-- If we have a return continuation,+-- then if it is a canned GC pattern,+-- then we do mkJumpReturnsTo+-- else we do a normal call to stg_gc_noregs+-- else if it is a canned GC pattern,+-- then generate the continuation and do mkCallReturnsTo+-- else we do a normal call to stg_gc_noregs++altHeapCheck :: [LocalReg] -> FCode a -> FCode a+altHeapCheck regs code = altOrNoEscapeHeapCheck False regs code++altOrNoEscapeHeapCheck :: Bool -> [LocalReg] -> FCode a -> FCode a+altOrNoEscapeHeapCheck checkYield regs code = do+ dflags <- getDynFlags+ case cannedGCEntryPoint dflags regs of+ Nothing -> genericGC checkYield code+ Just gc -> do+ lret <- newBlockId+ let (off, _, copyin) = copyInOflow dflags NativeReturn (Young lret) regs []+ lcont <- newBlockId+ tscope <- getTickScope+ emitOutOfLine lret (copyin <*> mkBranch lcont, tscope)+ emitLabel lcont+ cannedGCReturnsTo checkYield False gc regs lret off code++altHeapCheckReturnsTo :: [LocalReg] -> Label -> ByteOff -> FCode a -> FCode a+altHeapCheckReturnsTo regs lret off code+ = do dflags <- getDynFlags+ case cannedGCEntryPoint dflags regs of+ Nothing -> genericGC False code+ Just gc -> cannedGCReturnsTo False True gc regs lret off code++-- noEscapeHeapCheck is implemented identically to altHeapCheck (which+-- is more efficient), but cannot be optimized away in the non-allocating+-- case because it may occur in a loop+noEscapeHeapCheck :: [LocalReg] -> FCode a -> FCode a+noEscapeHeapCheck regs code = altOrNoEscapeHeapCheck True regs code++cannedGCReturnsTo :: Bool -> Bool -> CmmExpr -> [LocalReg] -> Label -> ByteOff+ -> FCode a+ -> FCode a+cannedGCReturnsTo checkYield cont_on_stack gc regs lret off code+ = do dflags <- getDynFlags+ updfr_sz <- getUpdFrameOff+ heapCheck False checkYield (gc_call dflags gc updfr_sz) code+ where+ reg_exprs = map (CmmReg . CmmLocal) regs+ -- Note [stg_gc arguments]++ -- NB. we use the NativeReturn convention for passing arguments+ -- to the canned heap-check routines, because we are in a case+ -- alternative and hence the [LocalReg] was passed to us in the+ -- NativeReturn convention.+ gc_call dflags label sp+ | cont_on_stack+ = mkJumpReturnsTo dflags label NativeReturn reg_exprs lret off sp+ | otherwise+ = mkCallReturnsTo dflags label NativeReturn reg_exprs lret off sp []++genericGC :: Bool -> FCode a -> FCode a+genericGC checkYield code+ = do updfr_sz <- getUpdFrameOff+ lretry <- newBlockId+ emitLabel lretry+ call <- mkCall generic_gc (GC, GC) [] [] updfr_sz []+ heapCheck False checkYield (call <*> mkBranch lretry) code++cannedGCEntryPoint :: DynFlags -> [LocalReg] -> Maybe CmmExpr+cannedGCEntryPoint dflags regs+ = case map localRegType regs of+ [] -> Just (mkGcLabel "stg_gc_noregs")+ [ty]+ | isGcPtrType ty -> Just (mkGcLabel "stg_gc_unpt_r1")+ | isFloatType ty -> case width of+ W32 -> Just (mkGcLabel "stg_gc_f1")+ W64 -> Just (mkGcLabel "stg_gc_d1")+ _ -> Nothing++ | width == wordWidth dflags -> Just (mkGcLabel "stg_gc_unbx_r1")+ | width == W64 -> Just (mkGcLabel "stg_gc_l1")+ | otherwise -> Nothing+ where+ width = typeWidth ty+ [ty1,ty2]+ | isGcPtrType ty1+ && isGcPtrType ty2 -> Just (mkGcLabel "stg_gc_pp")+ [ty1,ty2,ty3]+ | isGcPtrType ty1+ && isGcPtrType ty2+ && isGcPtrType ty3 -> Just (mkGcLabel "stg_gc_ppp")+ [ty1,ty2,ty3,ty4]+ | isGcPtrType ty1+ && isGcPtrType ty2+ && isGcPtrType ty3+ && isGcPtrType ty4 -> Just (mkGcLabel "stg_gc_pppp")+ _otherwise -> Nothing++-- Note [stg_gc arguments]+-- It might seem that we could avoid passing the arguments to the+-- stg_gc function, because they are already in the right registers.+-- While this is usually the case, it isn't always. Sometimes the+-- code generator has cleverly avoided the eval in a case, e.g. in+-- ffi/should_run/4221.hs we found+--+-- case a_r1mb of z+-- FunPtr x y -> ...+--+-- where a_r1mb is bound a top-level constructor, and is known to be+-- evaluated. The codegen just assigns x, y and z, and continues;+-- R1 is never assigned.+--+-- So we'll have to rely on optimisations to eliminatethese+-- assignments where possible.+++-- | The generic GC procedure; no params, no results+generic_gc :: CmmExpr+generic_gc = mkGcLabel "stg_gc_noregs"++-- | Create a CLabel for calling a garbage collector entry point+mkGcLabel :: String -> CmmExpr+mkGcLabel s = CmmLit (CmmLabel (mkCmmCodeLabel rtsUnitId (fsLit s)))++-------------------------------+heapCheck :: Bool -> Bool -> CmmAGraph -> FCode a -> FCode a+heapCheck checkStack checkYield do_gc code+ = getHeapUsage $ \ hpHw ->+ -- Emit heap checks, but be sure to do it lazily so+ -- that the conditionals on hpHw don't cause a black hole+ do { dflags <- getDynFlags+ ; let mb_alloc_bytes+ | hpHw > mBLOCK_SIZE = sorry $ unlines+ [" Trying to allocate more than "++show mBLOCK_SIZE++" bytes.",+ "",+ "This is currently not possible due to a limitation of GHC's code generator.",+ "See http://hackage.haskell.org/trac/ghc/ticket/4505 for details.",+ "Suggestion: read data from a file instead of having large static data",+ "structures in code."]+ | hpHw > 0 = Just (mkIntExpr dflags (hpHw * (wORD_SIZE dflags)))+ | otherwise = Nothing+ where mBLOCK_SIZE = bLOCKS_PER_MBLOCK dflags * bLOCK_SIZE_W dflags+ stk_hwm | checkStack = Just (CmmLit CmmHighStackMark)+ | otherwise = Nothing+ ; codeOnly $ do_checks stk_hwm checkYield mb_alloc_bytes do_gc+ ; tickyAllocHeap True hpHw+ ; setRealHp hpHw+ ; code }++heapStackCheckGen :: Maybe CmmExpr -> Maybe CmmExpr -> FCode ()+heapStackCheckGen stk_hwm mb_bytes+ = do updfr_sz <- getUpdFrameOff+ lretry <- newBlockId+ emitLabel lretry+ call <- mkCall generic_gc (GC, GC) [] [] updfr_sz []+ do_checks stk_hwm False mb_bytes (call <*> mkBranch lretry)++-- Note [Single stack check]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~+-- When compiling a function we can determine how much stack space it+-- will use. We therefore need to perform only a single stack check at+-- the beginning of a function to see if we have enough stack space.+--+-- The check boils down to comparing Sp-N with SpLim, where N is the+-- amount of stack space needed (see Note [Stack usage] below). *BUT*+-- at this stage of the pipeline we are not supposed to refer to Sp+-- itself, because the stack is not yet manifest, so we don't quite+-- know where Sp pointing.++-- So instead of referring directly to Sp - as we used to do in the+-- past - the code generator uses (old + 0) in the stack check. That+-- is the address of the first word of the old area, so if we add N+-- we'll get the address of highest used word.+--+-- This makes the check robust. For example, while we need to perform+-- only one stack check for each function, we could in theory place+-- more stack checks later in the function. They would be redundant,+-- but not incorrect (in a sense that they should not change program+-- behaviour). We need to make sure however that a stack check+-- inserted after incrementing the stack pointer checks for a+-- respectively smaller stack space. This would not be the case if the+-- code generator produced direct references to Sp. By referencing+-- (old + 0) we make sure that we always check for a correct amount of+-- stack: when converting (old + 0) to Sp the stack layout phase takes+-- into account changes already made to stack pointer. The idea for+-- this change came from observations made while debugging #8275.++-- Note [Stack usage]+-- ~~~~~~~~~~~~~~~~~~+-- At the moment we convert from STG to Cmm we don't know N, the+-- number of bytes of stack that the function will use, so we use a+-- special late-bound CmmLit, namely+-- CmmHighStackMark+-- to stand for the number of bytes needed. When the stack is made+-- manifest, the number of bytes needed is calculated, and used to+-- replace occurrences of CmmHighStackMark+--+-- The (Maybe CmmExpr) passed to do_checks is usually+-- Just (CmmLit CmmHighStackMark)+-- but can also (in certain hand-written RTS functions)+-- Just (CmmLit 8) or some other fixed valuet+-- If it is Nothing, we don't generate a stack check at all.++do_checks :: Maybe CmmExpr -- Should we check the stack?+ -- See Note [Stack usage]+ -> Bool -- Should we check for preemption?+ -> Maybe CmmExpr -- Heap headroom (bytes)+ -> CmmAGraph -- What to do on failure+ -> FCode ()+do_checks mb_stk_hwm checkYield mb_alloc_lit do_gc = do+ dflags <- getDynFlags+ gc_id <- newBlockId++ let+ Just alloc_lit = mb_alloc_lit++ bump_hp = cmmOffsetExprB dflags (CmmReg hpReg) alloc_lit++ -- Sp overflow if ((old + 0) - CmmHighStack < SpLim)+ -- At the beginning of a function old + 0 = Sp+ -- See Note [Single stack check]+ sp_oflo sp_hwm =+ CmmMachOp (mo_wordULt dflags)+ [CmmMachOp (MO_Sub (typeWidth (cmmRegType dflags spReg)))+ [CmmStackSlot Old 0, sp_hwm],+ CmmReg spLimReg]++ -- Hp overflow if (Hp > HpLim)+ -- (Hp has been incremented by now)+ -- HpLim points to the LAST WORD of valid allocation space.+ hp_oflo = CmmMachOp (mo_wordUGt dflags)+ [CmmReg hpReg, CmmReg (CmmGlobal HpLim)]++ alloc_n = mkAssign (CmmGlobal HpAlloc) alloc_lit++ case mb_stk_hwm of+ Nothing -> return ()+ Just stk_hwm -> tickyStackCheck+ >> (emit =<< mkCmmIfGoto' (sp_oflo stk_hwm) gc_id (Just False) )++ -- Emit new label that might potentially be a header+ -- of a self-recursive tail call.+ -- See Note [Self-recursive loop header].+ self_loop_info <- getSelfLoop+ case self_loop_info of+ Just (_, loop_header_id, _)+ | checkYield && isJust mb_stk_hwm -> emitLabel loop_header_id+ _otherwise -> return ()++ if (isJust mb_alloc_lit)+ then do+ tickyHeapCheck+ emitAssign hpReg bump_hp+ emit =<< mkCmmIfThen' hp_oflo (alloc_n <*> mkBranch gc_id) (Just False)+ else do+ when (checkYield && not (gopt Opt_OmitYields dflags)) $ do+ -- Yielding if HpLim == 0+ let yielding = CmmMachOp (mo_wordEq dflags)+ [CmmReg (CmmGlobal HpLim),+ CmmLit (zeroCLit dflags)]+ emit =<< mkCmmIfGoto' yielding gc_id (Just False)++ tscope <- getTickScope+ emitOutOfLine gc_id+ (do_gc, tscope) -- this is expected to jump back somewhere++ -- Test for stack pointer exhaustion, then+ -- bump heap pointer, and test for heap exhaustion+ -- Note that we don't move the heap pointer unless the+ -- stack check succeeds. Otherwise we might end up+ -- with slop at the end of the current block, which can+ -- confuse the LDV profiler.++-- Note [Self-recursive loop header]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Self-recursive loop header is required by loopification optimization (See+-- Note [Self-recursive tail calls] in StgCmmExpr). We emit it if:+--+-- 1. There is information about self-loop in the FCode environment. We don't+-- check the binder (first component of the self_loop_info) because we are+-- certain that if the self-loop info is present then we are compiling the+-- binder body. Reason: the only possible way to get here with the+-- self_loop_info present is from closureCodeBody.+--+-- 2. checkYield && isJust mb_stk_hwm. checkYield tells us that it is possible+-- to preempt the heap check (see #367 for motivation behind this check). It+-- is True for heap checks placed at the entry to a function and+-- let-no-escape heap checks but false for other heap checks (eg. in case+-- alternatives or created from hand-written high-level Cmm). The second+-- check (isJust mb_stk_hwm) is true for heap checks at the entry to a+-- function and some heap checks created in hand-written Cmm. Otherwise it+-- is Nothing. In other words the only situation when both conditions are+-- true is when compiling stack and heap checks at the entry to a+-- function. This is the only situation when we want to emit a self-loop+-- label.
+ codeGen/StgCmmHpc.hs view
@@ -0,0 +1,46 @@+-----------------------------------------------------------------------------+--+-- Code generation for coverage+--+-- (c) Galois Connections, Inc. 2006+--+-----------------------------------------------------------------------------++module StgCmmHpc ( initHpc, mkTickBox ) where++import StgCmmMonad++import MkGraph+import CmmExpr+import CLabel+import Module+import CmmUtils+import StgCmmUtils+import HscTypes+import DynFlags++import Control.Monad++mkTickBox :: DynFlags -> Module -> Int -> CmmAGraph+mkTickBox dflags mod n+ = mkStore tick_box (CmmMachOp (MO_Add W64)+ [ CmmLoad tick_box b64+ , CmmLit (CmmInt 1 W64)+ ])+ where+ tick_box = cmmIndex dflags W64+ (CmmLit $ CmmLabel $ mkHpcTicksLabel $ mod)+ n++initHpc :: Module -> HpcInfo -> FCode ()+-- Emit top-level tables for HPC and return code to initialise+initHpc _ (NoHpcInfo {})+ = return ()+initHpc this_mod (HpcInfo tickCount _hashNo)+ = do dflags <- getDynFlags+ when (gopt Opt_Hpc dflags) $+ do emitDataLits (mkHpcTicksLabel this_mod)+ [ (CmmInt 0 W64)+ | _ <- take tickCount [0 :: Int ..]+ ]+
+ codeGen/StgCmmLayout.hs view
@@ -0,0 +1,552 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Building info tables.+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmLayout (+ mkArgDescr,+ emitCall, emitReturn, adjustHpBackwards,++ emitClosureProcAndInfoTable,+ emitClosureAndInfoTable,++ slowCall, directCall,++ mkVirtHeapOffsets, mkVirtConstrOffsets, mkVirtConstrSizes, getHpRelOffset,++ ArgRep(..), toArgRep, argRepSizeW -- re-exported from StgCmmArgRep+ ) where+++#include "HsVersions.h"++import Prelude hiding ((<*>))++import StgCmmClosure+import StgCmmEnv+import StgCmmArgRep -- notably: ( slowCallPattern )+import StgCmmTicky+import StgCmmMonad+import StgCmmUtils+import StgCmmProf (curCCS)++import MkGraph+import SMRep+import BlockId+import Cmm+import CmmUtils+import CmmInfo+import CLabel+import StgSyn+import Id+import TyCon ( PrimRep(..) )+import BasicTypes ( RepArity )+import DynFlags+import Module++import Util+import Data.List+import Outputable+import FastString+import Control.Monad++------------------------------------------------------------------------+-- Call and return sequences+------------------------------------------------------------------------++-- | Return multiple values to the sequel+--+-- If the sequel is @Return@+--+-- > return (x,y)+--+-- If the sequel is @AssignTo [p,q]@+--+-- > p=x; q=y;+--+emitReturn :: [CmmExpr] -> FCode ReturnKind+emitReturn results+ = do { dflags <- getDynFlags+ ; sequel <- getSequel+ ; updfr_off <- getUpdFrameOff+ ; case sequel of+ Return ->+ do { adjustHpBackwards+ ; let e = CmmLoad (CmmStackSlot Old updfr_off) (gcWord dflags)+ ; emit (mkReturn dflags (entryCode dflags e) results updfr_off)+ }+ AssignTo regs adjust ->+ do { when adjust adjustHpBackwards+ ; emitMultiAssign regs results }+ ; return AssignedDirectly+ }+++-- | @emitCall conv fun args@ makes a call to the entry-code of @fun@,+-- using the call/return convention @conv@, passing @args@, and+-- returning the results to the current sequel.+--+emitCall :: (Convention, Convention) -> CmmExpr -> [CmmExpr] -> FCode ReturnKind+emitCall convs fun args+ = emitCallWithExtraStack convs fun args noExtraStack+++-- | @emitCallWithExtraStack conv fun args stack@ makes a call to the+-- entry-code of @fun@, using the call/return convention @conv@,+-- passing @args@, pushing some extra stack frames described by+-- @stack@, and returning the results to the current sequel.+--+emitCallWithExtraStack+ :: (Convention, Convention) -> CmmExpr -> [CmmExpr]+ -> [CmmExpr] -> FCode ReturnKind+emitCallWithExtraStack (callConv, retConv) fun args extra_stack+ = do { dflags <- getDynFlags+ ; adjustHpBackwards+ ; sequel <- getSequel+ ; updfr_off <- getUpdFrameOff+ ; case sequel of+ Return -> do+ emit $ mkJumpExtra dflags callConv fun args updfr_off extra_stack+ return AssignedDirectly+ AssignTo res_regs _ -> do+ k <- newBlockId+ let area = Young k+ (off, _, copyin) = copyInOflow dflags retConv area res_regs []+ copyout = mkCallReturnsTo dflags fun callConv args k off updfr_off+ extra_stack+ tscope <- getTickScope+ emit (copyout <*> mkLabel k tscope <*> copyin)+ return (ReturnedTo k off)+ }+++adjustHpBackwards :: FCode ()+-- This function adjusts the heap pointer just before a tail call or+-- return. At a call or return, the virtual heap pointer may be less+-- than the real Hp, because the latter was advanced to deal with+-- the worst-case branch of the code, and we may be in a better-case+-- branch. In that case, move the real Hp *back* and retract some+-- ticky allocation count.+--+-- It *does not* deal with high-water-mark adjustment. That's done by+-- functions which allocate heap.+adjustHpBackwards+ = do { hp_usg <- getHpUsage+ ; let rHp = realHp hp_usg+ vHp = virtHp hp_usg+ adjust_words = vHp -rHp+ ; new_hp <- getHpRelOffset vHp++ ; emit (if adjust_words == 0+ then mkNop+ else mkAssign hpReg new_hp) -- Generates nothing when vHp==rHp++ ; tickyAllocHeap False adjust_words -- ...ditto++ ; setRealHp vHp+ }+++-------------------------------------------------------------------------+-- Making calls: directCall and slowCall+-------------------------------------------------------------------------++-- General plan is:+-- - we'll make *one* fast call, either to the function itself+-- (directCall) or to stg_ap_<pat>_fast (slowCall)+-- Any left-over arguments will be pushed on the stack,+--+-- e.g. Sp[old+8] = arg1+-- Sp[old+16] = arg2+-- Sp[old+32] = stg_ap_pp_info+-- R2 = arg3+-- R3 = arg4+-- call f() return to Nothing updfr_off: 32+++directCall :: Convention -> CLabel -> RepArity -> [StgArg] -> FCode ReturnKind+-- (directCall f n args)+-- calls f(arg1, ..., argn), and applies the result to the remaining args+-- The function f has arity n, and there are guaranteed at least n args+-- Both arity and args include void args+directCall conv lbl arity stg_args+ = do { argreps <- getArgRepsAmodes stg_args+ ; direct_call "directCall" conv lbl arity argreps }+++slowCall :: CmmExpr -> [StgArg] -> FCode ReturnKind+-- (slowCall fun args) applies fun to args, returning the results to Sequel+slowCall fun stg_args+ = do dflags <- getDynFlags+ argsreps <- getArgRepsAmodes stg_args+ let (rts_fun, arity) = slowCallPattern (map fst argsreps)++ (r, slow_code) <- getCodeR $ do+ r <- direct_call "slow_call" NativeNodeCall+ (mkRtsApFastLabel rts_fun) arity ((P,Just fun):argsreps)+ emitComment $ mkFastString ("slow_call for " +++ showSDoc dflags (ppr fun) +++ " with pat " ++ unpackFS rts_fun)+ return r++ -- Note [avoid intermediate PAPs]+ let n_args = length stg_args+ if n_args > arity && optLevel dflags >= 2+ then do+ funv <- (CmmReg . CmmLocal) `fmap` assignTemp fun+ fun_iptr <- (CmmReg . CmmLocal) `fmap`+ assignTemp (closureInfoPtr dflags (cmmUntag dflags funv))++ -- ToDo: we could do slightly better here by reusing the+ -- continuation from the slow call, which we have in r.+ -- Also we'd like to push the continuation on the stack+ -- before the branch, so that we only get one copy of the+ -- code that saves all the live variables across the+ -- call, but that might need some improvements to the+ -- special case in the stack layout code to handle this+ -- (see Note [diamond proc point]).++ fast_code <- getCode $+ emitCall (NativeNodeCall, NativeReturn)+ (entryCode dflags fun_iptr)+ (nonVArgs ((P,Just funv):argsreps))++ slow_lbl <- newBlockId+ fast_lbl <- newBlockId+ is_tagged_lbl <- newBlockId+ end_lbl <- newBlockId++ let correct_arity = cmmEqWord dflags (funInfoArity dflags fun_iptr)+ (mkIntExpr dflags n_args)++ tscope <- getTickScope+ emit (mkCbranch (cmmIsTagged dflags funv)+ is_tagged_lbl slow_lbl (Just True)+ <*> mkLabel is_tagged_lbl tscope+ <*> mkCbranch correct_arity fast_lbl slow_lbl (Just True)+ <*> mkLabel fast_lbl tscope+ <*> fast_code+ <*> mkBranch end_lbl+ <*> mkLabel slow_lbl tscope+ <*> slow_code+ <*> mkLabel end_lbl tscope)+ return r++ else do+ emit slow_code+ return r+++-- Note [avoid intermediate PAPs]+--+-- A slow call which needs multiple generic apply patterns will be+-- almost guaranteed to create one or more intermediate PAPs when+-- applied to a function that takes the correct number of arguments.+-- We try to avoid this situation by generating code to test whether+-- we are calling a function with the correct number of arguments+-- first, i.e.:+--+-- if (TAG(f) != 0} { // f is not a thunk+-- if (f->info.arity == n) {+-- ... make a fast call to f ...+-- }+-- }+-- ... otherwise make the slow call ...+--+-- We *only* do this when the call requires multiple generic apply+-- functions, which requires pushing extra stack frames and probably+-- results in intermediate PAPs. (I say probably, because it might be+-- that we're over-applying a function, but that seems even less+-- likely).+--+-- This very rarely applies, but if it does happen in an inner loop it+-- can have a severe impact on performance (#6084).+++--------------+direct_call :: String+ -> Convention -- e.g. NativeNodeCall or NativeDirectCall+ -> CLabel -> RepArity+ -> [(ArgRep,Maybe CmmExpr)] -> FCode ReturnKind+direct_call caller call_conv lbl arity args+ | debugIsOn && real_arity > length args -- Too few args+ = do -- Caller should ensure that there enough args!+ pprPanic "direct_call" $+ text caller <+> ppr arity <+>+ ppr lbl <+> ppr (length args) <+>+ ppr (map snd args) <+> ppr (map fst args)++ | null rest_args -- Precisely the right number of arguments+ = emitCall (call_conv, NativeReturn) target (nonVArgs args)++ | otherwise -- Note [over-saturated calls]+ = do dflags <- getDynFlags+ emitCallWithExtraStack (call_conv, NativeReturn)+ target+ (nonVArgs fast_args)+ (nonVArgs (stack_args dflags))+ where+ target = CmmLit (CmmLabel lbl)+ (fast_args, rest_args) = splitAt real_arity args+ stack_args dflags = slowArgs dflags rest_args+ real_arity = case call_conv of+ NativeNodeCall -> arity+1+ _ -> arity+++-- When constructing calls, it is easier to keep the ArgReps and the+-- CmmExprs zipped together. However, a void argument has no+-- representation, so we need to use Maybe CmmExpr (the alternative of+-- using zeroCLit or even undefined would work, but would be ugly).+--+getArgRepsAmodes :: [StgArg] -> FCode [(ArgRep, Maybe CmmExpr)]+getArgRepsAmodes = mapM getArgRepAmode+ where getArgRepAmode arg+ | V <- rep = return (V, Nothing)+ | otherwise = do expr <- getArgAmode (NonVoid arg)+ return (rep, Just expr)+ where rep = toArgRep (argPrimRep arg)++nonVArgs :: [(ArgRep, Maybe CmmExpr)] -> [CmmExpr]+nonVArgs [] = []+nonVArgs ((_,Nothing) : args) = nonVArgs args+nonVArgs ((_,Just arg) : args) = arg : nonVArgs args++{-+Note [over-saturated calls]++The natural thing to do for an over-saturated call would be to call+the function with the correct number of arguments, and then apply the+remaining arguments to the value returned, e.g.++ f a b c d (where f has arity 2)+ -->+ r = call f(a,b)+ call r(c,d)++but this entails+ - saving c and d on the stack+ - making a continuation info table+ - at the continuation, loading c and d off the stack into regs+ - finally, call r++Note that since there are a fixed number of different r's+(e.g. stg_ap_pp_fast), we can also pre-compile continuations+that correspond to each of them, rather than generating a fresh+one for each over-saturated call.++Not only does this generate much less code, it is faster too. We will+generate something like:++Sp[old+16] = c+Sp[old+24] = d+Sp[old+32] = stg_ap_pp_info+call f(a,b) -- usual calling convention++For the purposes of the CmmCall node, we count this extra stack as+just more arguments that we are passing on the stack (cml_args).+-}++-- | 'slowArgs' takes a list of function arguments and prepares them for+-- pushing on the stack for "extra" arguments to a function which requires+-- fewer arguments than we currently have.+slowArgs :: DynFlags -> [(ArgRep, Maybe CmmExpr)] -> [(ArgRep, Maybe CmmExpr)]+slowArgs _ [] = []+slowArgs dflags args -- careful: reps contains voids (V), but args does not+ | gopt Opt_SccProfilingOn dflags+ = save_cccs ++ this_pat ++ slowArgs dflags rest_args+ | otherwise = this_pat ++ slowArgs dflags rest_args+ where+ (arg_pat, n) = slowCallPattern (map fst args)+ (call_args, rest_args) = splitAt n args++ stg_ap_pat = mkCmmRetInfoLabel rtsUnitId arg_pat+ this_pat = (N, Just (mkLblExpr stg_ap_pat)) : call_args+ save_cccs = [(N, Just (mkLblExpr save_cccs_lbl)), (N, Just curCCS)]+ save_cccs_lbl = mkCmmRetInfoLabel rtsUnitId (fsLit "stg_restore_cccs")++-------------------------------------------------------------------------+---- Laying out objects on the heap and stack+-------------------------------------------------------------------------++-- The heap always grows upwards, so hpRel is easy to compute+hpRel :: VirtualHpOffset -- virtual offset of Hp+ -> VirtualHpOffset -- virtual offset of The Thing+ -> WordOff -- integer word offset+hpRel hp off = off - hp++getHpRelOffset :: VirtualHpOffset -> FCode CmmExpr+-- See Note [Virtual and real heap pointers] in StgCmmMonad+getHpRelOffset virtual_offset+ = do dflags <- getDynFlags+ hp_usg <- getHpUsage+ return (cmmRegOffW dflags hpReg (hpRel (realHp hp_usg) virtual_offset))++mkVirtHeapOffsets+ :: DynFlags+ -> Bool -- True <=> is a thunk+ -> [NonVoid (PrimRep,a)] -- Things to make offsets for+ -> (WordOff, -- _Total_ number of words allocated+ WordOff, -- Number of words allocated for *pointers*+ [(NonVoid a, ByteOff)])++-- Things with their offsets from start of object in order of+-- increasing offset; BUT THIS MAY BE DIFFERENT TO INPUT ORDER+-- First in list gets lowest offset, which is initial offset + 1.+--+-- mkVirtHeapOffsets always returns boxed things with smaller offsets+-- than the unboxed things++mkVirtHeapOffsets dflags is_thunk things+ = ASSERT(not (any (isVoidRep . fst . fromNonVoid) things))+ ( bytesToWordsRoundUp dflags tot_bytes+ , bytesToWordsRoundUp dflags bytes_of_ptrs+ , ptrs_w_offsets ++ non_ptrs_w_offsets+ )+ where+ hdr_words | is_thunk = thunkHdrSize dflags+ | otherwise = fixedHdrSizeW dflags+ hdr_bytes = wordsToBytes dflags hdr_words++ (ptrs, non_ptrs) = partition (isGcPtrRep . fst . fromNonVoid) things++ (bytes_of_ptrs, ptrs_w_offsets) =+ mapAccumL computeOffset 0 ptrs+ (tot_bytes, non_ptrs_w_offsets) =+ mapAccumL computeOffset bytes_of_ptrs non_ptrs++ computeOffset bytes_so_far nv_thing+ = (bytes_so_far + wordsToBytes dflags (argRepSizeW dflags (toArgRep rep)),+ (NonVoid thing, hdr_bytes + bytes_so_far))+ where (rep,thing) = fromNonVoid nv_thing++-- | Just like mkVirtHeapOffsets, but for constructors+mkVirtConstrOffsets+ :: DynFlags -> [NonVoid (PrimRep, a)]+ -> (WordOff, WordOff, [(NonVoid a, ByteOff)])+mkVirtConstrOffsets dflags = mkVirtHeapOffsets dflags False++-- | Just like mkVirtConstrOffsets, but used when we don't have the actual+-- arguments. Useful when e.g. generating info tables; we just need to know+-- sizes of pointer and non-pointer fields.+mkVirtConstrSizes :: DynFlags -> [NonVoid PrimRep] -> (WordOff, WordOff)+mkVirtConstrSizes dflags field_reps+ = (tot_wds, ptr_wds)+ where+ (tot_wds, ptr_wds, _) =+ mkVirtConstrOffsets dflags+ (map (\nv_rep -> NonVoid (fromNonVoid nv_rep, ())) field_reps)++-------------------------------------------------------------------------+--+-- Making argument descriptors+--+-- An argument descriptor describes the layout of args on the stack,+-- both for * GC (stack-layout) purposes, and+-- * saving/restoring registers when a heap-check fails+--+-- Void arguments aren't important, therefore (contrast constructSlowCall)+--+-------------------------------------------------------------------------++-- bring in ARG_P, ARG_N, etc.+#include "rts/storage/FunTypes.h"++mkArgDescr :: DynFlags -> [Id] -> ArgDescr+mkArgDescr dflags args+ = let arg_bits = argBits dflags arg_reps+ arg_reps = filter isNonV (map idArgRep args)+ -- Getting rid of voids eases matching of standard patterns+ in case stdPattern arg_reps of+ Just spec_id -> ArgSpec spec_id+ Nothing -> ArgGen arg_bits++argBits :: DynFlags -> [ArgRep] -> [Bool] -- True for non-ptr, False for ptr+argBits _ [] = []+argBits dflags (P : args) = False : argBits dflags args+argBits dflags (arg : args) = take (argRepSizeW dflags arg) (repeat True)+ ++ argBits dflags args++----------------------+stdPattern :: [ArgRep] -> Maybe Int+stdPattern reps+ = case reps of+ [] -> Just ARG_NONE -- just void args, probably+ [N] -> Just ARG_N+ [P] -> Just ARG_P+ [F] -> Just ARG_F+ [D] -> Just ARG_D+ [L] -> Just ARG_L+ [V16] -> Just ARG_V16+ [V32] -> Just ARG_V32+ [V64] -> Just ARG_V64++ [N,N] -> Just ARG_NN+ [N,P] -> Just ARG_NP+ [P,N] -> Just ARG_PN+ [P,P] -> Just ARG_PP++ [N,N,N] -> Just ARG_NNN+ [N,N,P] -> Just ARG_NNP+ [N,P,N] -> Just ARG_NPN+ [N,P,P] -> Just ARG_NPP+ [P,N,N] -> Just ARG_PNN+ [P,N,P] -> Just ARG_PNP+ [P,P,N] -> Just ARG_PPN+ [P,P,P] -> Just ARG_PPP++ [P,P,P,P] -> Just ARG_PPPP+ [P,P,P,P,P] -> Just ARG_PPPPP+ [P,P,P,P,P,P] -> Just ARG_PPPPPP++ _ -> Nothing++-------------------------------------------------------------------------+--+-- Generating the info table and code for a closure+--+-------------------------------------------------------------------------++-- Here we make an info table of type 'CmmInfo'. The concrete+-- representation as a list of 'CmmAddr' is handled later+-- in the pipeline by 'cmmToRawCmm'.+-- When loading the free variables, a function closure pointer may be tagged,+-- so we must take it into account.++emitClosureProcAndInfoTable :: Bool -- top-level?+ -> Id -- name of the closure+ -> LambdaFormInfo+ -> CmmInfoTable+ -> [NonVoid Id] -- incoming arguments+ -> ((Int, LocalReg, [LocalReg]) -> FCode ()) -- function body+ -> FCode ()+emitClosureProcAndInfoTable top_lvl bndr lf_info info_tbl args body+ = do { dflags <- getDynFlags+ -- Bind the binder itself, but only if it's not a top-level+ -- binding. We need non-top let-bindings to refer to the+ -- top-level binding, which this binding would incorrectly shadow.+ ; node <- if top_lvl then return $ idToReg dflags (NonVoid bndr)+ else bindToReg (NonVoid bndr) lf_info+ ; let node_points = nodeMustPointToIt dflags lf_info+ ; arg_regs <- bindArgsToRegs args+ ; let args' = if node_points then (node : arg_regs) else arg_regs+ conv = if nodeMustPointToIt dflags lf_info then NativeNodeCall+ else NativeDirectCall+ (offset, _, _) = mkCallEntry dflags conv args' []+ ; emitClosureAndInfoTable info_tbl conv args' $ body (offset, node, arg_regs)+ }++-- Data constructors need closures, but not with all the argument handling+-- needed for functions. The shared part goes here.+emitClosureAndInfoTable ::+ CmmInfoTable -> Convention -> [LocalReg] -> FCode () -> FCode ()+emitClosureAndInfoTable info_tbl conv args body+ = do { (_, blks) <- getCodeScoped body+ ; let entry_lbl = toEntryLbl (cit_lbl info_tbl)+ ; emitProcWithConvention conv (Just info_tbl) entry_lbl args blks+ }
+ codeGen/StgCmmMonad.hs view
@@ -0,0 +1,900 @@+{-# LANGUAGE CPP, GADTs, UnboxedTuples #-}++-----------------------------------------------------------------------------+--+-- Monad for Stg to C-- code generation+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmMonad (+ FCode, -- type++ initC, runC, thenC, thenFC, listCs,+ returnFC, fixC,+ newUnique, newUniqSupply,++ emitLabel,++ emit, emitDecl, emitProc,+ emitProcWithConvention, emitProcWithStackFrame,+ emitOutOfLine, emitAssign, emitStore,+ emitComment, emitTick, emitUnwind,++ getCmm, aGraphToGraph,+ getCodeR, getCode, getCodeScoped, getHeapUsage,++ mkCmmIfThenElse, mkCmmIfThen, mkCmmIfGoto,+ mkCmmIfThenElse', mkCmmIfThen', mkCmmIfGoto',++ mkCall, mkCmmCall,++ forkClosureBody, forkLneBody, forkAlts, codeOnly,++ ConTagZ,++ Sequel(..), ReturnKind(..),+ withSequel, getSequel,++ setTickyCtrLabel, getTickyCtrLabel,+ tickScope, getTickScope,++ withUpdFrameOff, getUpdFrameOff, initUpdFrameOff,++ HeapUsage(..), VirtualHpOffset, initHpUsage,+ getHpUsage, setHpUsage, heapHWM,+ setVirtHp, getVirtHp, setRealHp,++ getModuleName,++ -- ideally we wouldn't export these, but some other modules access internal state+ getState, setState, getSelfLoop, withSelfLoop, getInfoDown, getDynFlags, getThisPackage,++ -- more localised access to monad state+ CgIdInfo(..),+ getBinds, setBinds,++ -- out of general friendliness, we also export ...+ CgInfoDownwards(..), CgState(..) -- non-abstract+ ) where++#include "HsVersions.h"++import Cmm+import StgCmmClosure+import DynFlags+import Hoopl+import Maybes+import MkGraph+import BlockId+import CLabel+import SMRep+import Module+import Id+import VarEnv+import OrdList+import Unique+import UniqSupply+import FastString+import Outputable++import Control.Monad+import Data.List+import Prelude hiding( sequence, succ )++infixr 9 `thenC` -- Right-associative!+infixr 9 `thenFC`+++--------------------------------------------------------+-- The FCode monad and its types+--+-- FCode is the monad plumbed through the Stg->Cmm code generator, and+-- the Cmm parser. It contains the following things:+--+-- - A writer monad, collecting:+-- - code for the current function, in the form of a CmmAGraph.+-- The function "emit" appends more code to this.+-- - the top-level CmmDecls accumulated so far+--+-- - A state monad with:+-- - the local bindings in scope+-- - the current heap usage+-- - a UniqSupply+--+-- - A reader monad, for CgInfoDownwards, containing+-- - DynFlags,+-- - the current Module+-- - the update-frame offset+-- - the ticky counter label+-- - the Sequel (the continuation to return to)+-- - the self-recursive tail call information++--------------------------------------------------------++newtype FCode a = FCode (CgInfoDownwards -> CgState -> (# a, CgState #))++instance Functor FCode where+ fmap f (FCode g) = FCode $ \i s -> case g i s of (# a, s' #) -> (# f a, s' #)++instance Applicative FCode where+ pure = returnFC+ (<*>) = ap++instance Monad FCode where+ (>>=) = thenFC++{-# INLINE thenC #-}+{-# INLINE thenFC #-}+{-# INLINE returnFC #-}++instance MonadUnique FCode where+ getUniqueSupplyM = cgs_uniqs <$> getState+ getUniqueM = FCode $ \_ st ->+ let (u, us') = takeUniqFromSupply (cgs_uniqs st)+ in (# u, st { cgs_uniqs = us' } #)++initC :: IO CgState+initC = do { uniqs <- mkSplitUniqSupply 'c'+ ; return (initCgState uniqs) }++runC :: DynFlags -> Module -> CgState -> FCode a -> (a,CgState)+runC dflags mod st fcode = doFCode fcode (initCgInfoDown dflags mod) st++returnFC :: a -> FCode a+returnFC val = FCode (\_info_down state -> (# val, state #))++thenC :: FCode () -> FCode a -> FCode a+thenC (FCode m) (FCode k) =+ FCode $ \info_down state -> case m info_down state of+ (# _,new_state #) -> k info_down new_state++listCs :: [FCode ()] -> FCode ()+listCs [] = return ()+listCs (fc:fcs) = do+ fc+ listCs fcs++thenFC :: FCode a -> (a -> FCode c) -> FCode c+thenFC (FCode m) k = FCode $+ \info_down state ->+ case m info_down state of+ (# m_result, new_state #) ->+ case k m_result of+ FCode kcode -> kcode info_down new_state++fixC :: (a -> FCode a) -> FCode a+fixC fcode = FCode (+ \info_down state ->+ let+ (v,s) = doFCode (fcode v) info_down state+ in+ (# v, s #)+ )++--------------------------------------------------------+-- The code generator environment+--------------------------------------------------------++-- This monadery has some information that it only passes+-- *downwards*, as well as some ``state'' which is modified+-- as we go along.++data CgInfoDownwards -- information only passed *downwards* by the monad+ = MkCgInfoDown {+ cgd_dflags :: DynFlags,+ cgd_mod :: Module, -- Module being compiled+ cgd_updfr_off :: UpdFrameOffset, -- Size of current update frame+ cgd_ticky :: CLabel, -- Current destination for ticky counts+ cgd_sequel :: Sequel, -- What to do at end of basic block+ cgd_self_loop :: Maybe SelfLoopInfo,-- Which tail calls can be compiled+ -- as local jumps? See Note+ -- [Self-recursive tail calls] in+ -- StgCmmExpr+ cgd_tick_scope:: CmmTickScope -- Tick scope for new blocks & ticks+ }++type CgBindings = IdEnv CgIdInfo++data CgIdInfo+ = CgIdInfo+ { cg_id :: Id -- Id that this is the info for+ -- Can differ from the Id at occurrence sites by+ -- virtue of being externalised, for splittable C+ -- See Note [Externalise when splitting]+ , cg_lf :: LambdaFormInfo+ , cg_loc :: CgLoc -- CmmExpr for the *tagged* value+ }++-- Note [Externalise when splitting]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- If we're splitting the object with -fsplit-objs, we need to+-- externalise *all* the top-level names, and then make sure we only+-- use the externalised one in any C label we use which refers to this+-- name.++instance Outputable CgIdInfo where+ ppr (CgIdInfo { cg_id = id, cg_loc = loc })+ = ppr id <+> text "-->" <+> ppr loc++-- Sequel tells what to do with the result of this expression+data Sequel+ = Return -- Return result(s) to continuation found on the stack.++ | AssignTo+ [LocalReg] -- Put result(s) in these regs and fall through+ -- NB: no void arguments here+ --+ Bool -- Should we adjust the heap pointer back to+ -- recover space that's unused on this path?+ -- We need to do this only if the expression+ -- may allocate (e.g. it's a foreign call or+ -- allocating primOp)++instance Outputable Sequel where+ ppr Return = text "Return"+ ppr (AssignTo regs b) = text "AssignTo" <+> ppr regs <+> ppr b++-- See Note [sharing continuations] below+data ReturnKind+ = AssignedDirectly+ | ReturnedTo BlockId ByteOff++-- Note [sharing continuations]+--+-- ReturnKind says how the expression being compiled returned its+-- results: either by assigning directly to the registers specified+-- by the Sequel, or by returning to a continuation that does the+-- assignments. The point of this is we might be able to re-use the+-- continuation in a subsequent heap-check. Consider:+--+-- case f x of z+-- True -> <True code>+-- False -> <False code>+--+-- Naively we would generate+--+-- R2 = x -- argument to f+-- Sp[young(L1)] = L1+-- call f returns to L1+-- L1:+-- z = R1+-- if (z & 1) then Ltrue else Lfalse+-- Ltrue:+-- Hp = Hp + 24+-- if (Hp > HpLim) then L4 else L7+-- L4:+-- HpAlloc = 24+-- goto L5+-- L5:+-- R1 = z+-- Sp[young(L6)] = L6+-- call stg_gc_unpt_r1 returns to L6+-- L6:+-- z = R1+-- goto L1+-- L7:+-- <True code>+-- Lfalse:+-- <False code>+--+-- We want the gc call in L4 to return to L1, and discard L6. Note+-- that not only can we share L1 and L6, but the assignment of the+-- return address in L4 is unnecessary because the return address for+-- L1 is already on the stack. We used to catch the sharing of L1 and+-- L6 in the common-block-eliminator, but not the unnecessary return+-- address assignment.+--+-- Since this case is so common I decided to make it more explicit and+-- robust by programming the sharing directly, rather than relying on+-- the common-block elimiantor to catch it. This makes+-- common-block-elimianteion an optional optimisation, and furthermore+-- generates less code in the first place that we have to subsequently+-- clean up.+--+-- There are some rarer cases of common blocks that we don't catch+-- this way, but that's ok. Common-block-elimination is still available+-- to catch them when optimisation is enabled. Some examples are:+--+-- - when both the True and False branches do a heap check, we+-- can share the heap-check failure code L4a and maybe L4+--+-- - in a case-of-case, there might be multiple continuations that+-- we can common up.+--+-- It is always safe to use AssignedDirectly. Expressions that jump+-- to the continuation from multiple places (e.g. case expressions)+-- fall back to AssignedDirectly.+--+++initCgInfoDown :: DynFlags -> Module -> CgInfoDownwards+initCgInfoDown dflags mod+ = MkCgInfoDown { cgd_dflags = dflags+ , cgd_mod = mod+ , cgd_updfr_off = initUpdFrameOff dflags+ , cgd_ticky = mkTopTickyCtrLabel+ , cgd_sequel = initSequel+ , cgd_self_loop = Nothing+ , cgd_tick_scope= GlobalScope }++initSequel :: Sequel+initSequel = Return++initUpdFrameOff :: DynFlags -> UpdFrameOffset+initUpdFrameOff dflags = widthInBytes (wordWidth dflags) -- space for the RA+++--------------------------------------------------------+-- The code generator state+--------------------------------------------------------++data CgState+ = MkCgState {+ cgs_stmts :: CmmAGraph, -- Current procedure++ cgs_tops :: OrdList CmmDecl,+ -- Other procedures and data blocks in this compilation unit+ -- Both are ordered only so that we can+ -- reduce forward references, when it's easy to do so++ cgs_binds :: CgBindings,++ cgs_hp_usg :: HeapUsage,++ cgs_uniqs :: UniqSupply }++data HeapUsage -- See Note [Virtual and real heap pointers]+ = HeapUsage {+ virtHp :: VirtualHpOffset, -- Virtual offset of highest-allocated word+ -- Incremented whenever we allocate+ realHp :: VirtualHpOffset -- realHp: Virtual offset of real heap ptr+ -- Used in instruction addressing modes+ }++type VirtualHpOffset = WordOff+++{- Note [Virtual and real heap pointers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The code generator can allocate one or more objects contiguously, performing+one heap check to cover allocation of all the objects at once. Let's call+this little chunk of heap space an "allocation chunk". The code generator+will emit code to+ * Perform a heap-exhaustion check+ * Move the heap pointer to the end of the allocation chunk+ * Allocate multiple objects within the chunk++The code generator uses VirtualHpOffsets to address words within a+single allocation chunk; these start at one and increase positively.+The first word of the chunk has VirtualHpOffset=1, the second has+VirtualHpOffset=2, and so on.++ * The field realHp tracks (the VirtualHpOffset) where the real Hp+ register is pointing. Typically it'll be pointing to the end of the+ allocation chunk.++ * The field virtHp gives the VirtualHpOffset of the highest-allocated+ word so far. It starts at zero (meaning no word has been allocated),+ and increases whenever an object is allocated.++The difference between realHp and virtHp gives the offset from the+real Hp register of a particular word in the allocation chunk. This+is what getHpRelOffset does. Since the returned offset is relative+to the real Hp register, it is valid only until you change the real+Hp register. (Changing virtHp doesn't matter.)+-}+++initCgState :: UniqSupply -> CgState+initCgState uniqs+ = MkCgState { cgs_stmts = mkNop+ , cgs_tops = nilOL+ , cgs_binds = emptyVarEnv+ , cgs_hp_usg = initHpUsage+ , cgs_uniqs = uniqs }++stateIncUsage :: CgState -> CgState -> CgState+-- stateIncUsage@ e1 e2 incorporates in e1+-- the heap high water mark found in e2.+stateIncUsage s1 s2@(MkCgState { cgs_hp_usg = hp_usg })+ = s1 { cgs_hp_usg = cgs_hp_usg s1 `maxHpHw` virtHp hp_usg }+ `addCodeBlocksFrom` s2++addCodeBlocksFrom :: CgState -> CgState -> CgState+-- Add code blocks from the latter to the former+-- (The cgs_stmts will often be empty, but not always; see codeOnly)+s1 `addCodeBlocksFrom` s2+ = s1 { cgs_stmts = cgs_stmts s1 MkGraph.<*> cgs_stmts s2,+ cgs_tops = cgs_tops s1 `appOL` cgs_tops s2 }+++-- The heap high water mark is the larger of virtHp and hwHp. The latter is+-- only records the high water marks of forked-off branches, so to find the+-- heap high water mark you have to take the max of virtHp and hwHp. Remember,+-- virtHp never retreats!+--+-- Note Jan 04: ok, so why do we only look at the virtual Hp??++heapHWM :: HeapUsage -> VirtualHpOffset+heapHWM = virtHp++initHpUsage :: HeapUsage+initHpUsage = HeapUsage { virtHp = 0, realHp = 0 }++maxHpHw :: HeapUsage -> VirtualHpOffset -> HeapUsage+hp_usg `maxHpHw` hw = hp_usg { virtHp = virtHp hp_usg `max` hw }++--------------------------------------------------------+-- Operators for getting and setting the state and "info_down".+--------------------------------------------------------++getState :: FCode CgState+getState = FCode $ \_info_down state -> (# state, state #)++setState :: CgState -> FCode ()+setState state = FCode $ \_info_down _ -> (# (), state #)++getHpUsage :: FCode HeapUsage+getHpUsage = do+ state <- getState+ return $ cgs_hp_usg state++setHpUsage :: HeapUsage -> FCode ()+setHpUsage new_hp_usg = do+ state <- getState+ setState $ state {cgs_hp_usg = new_hp_usg}++setVirtHp :: VirtualHpOffset -> FCode ()+setVirtHp new_virtHp+ = do { hp_usage <- getHpUsage+ ; setHpUsage (hp_usage {virtHp = new_virtHp}) }++getVirtHp :: FCode VirtualHpOffset+getVirtHp+ = do { hp_usage <- getHpUsage+ ; return (virtHp hp_usage) }++setRealHp :: VirtualHpOffset -> FCode ()+setRealHp new_realHp+ = do { hp_usage <- getHpUsage+ ; setHpUsage (hp_usage {realHp = new_realHp}) }++getBinds :: FCode CgBindings+getBinds = do+ state <- getState+ return $ cgs_binds state++setBinds :: CgBindings -> FCode ()+setBinds new_binds = do+ state <- getState+ setState $ state {cgs_binds = new_binds}++withState :: FCode a -> CgState -> FCode (a,CgState)+withState (FCode fcode) newstate = FCode $ \info_down state ->+ case fcode info_down newstate of+ (# retval, state2 #) -> (# (retval,state2), state #)++newUniqSupply :: FCode UniqSupply+newUniqSupply = do+ state <- getState+ let (us1, us2) = splitUniqSupply (cgs_uniqs state)+ setState $ state { cgs_uniqs = us1 }+ return us2++newUnique :: FCode Unique+newUnique = do+ state <- getState+ let (u,us') = takeUniqFromSupply (cgs_uniqs state)+ setState $ state { cgs_uniqs = us' }+ return u++------------------+getInfoDown :: FCode CgInfoDownwards+getInfoDown = FCode $ \info_down state -> (# info_down,state #)++getSelfLoop :: FCode (Maybe SelfLoopInfo)+getSelfLoop = do+ info_down <- getInfoDown+ return $ cgd_self_loop info_down++withSelfLoop :: SelfLoopInfo -> FCode a -> FCode a+withSelfLoop self_loop code = do+ info_down <- getInfoDown+ withInfoDown code (info_down {cgd_self_loop = Just self_loop})++instance HasDynFlags FCode where+ getDynFlags = liftM cgd_dflags getInfoDown++getThisPackage :: FCode UnitId+getThisPackage = liftM thisPackage getDynFlags++withInfoDown :: FCode a -> CgInfoDownwards -> FCode a+withInfoDown (FCode fcode) info_down = FCode $ \_ state -> fcode info_down state++doFCode :: FCode a -> CgInfoDownwards -> CgState -> (a,CgState)+doFCode (FCode fcode) info_down state =+ case fcode info_down state of+ (# a, s #) -> ( a, s )++-- ----------------------------------------------------------------------------+-- Get the current module name++getModuleName :: FCode Module+getModuleName = do { info <- getInfoDown; return (cgd_mod info) }++-- ----------------------------------------------------------------------------+-- Get/set the end-of-block info++withSequel :: Sequel -> FCode a -> FCode a+withSequel sequel code+ = do { info <- getInfoDown+ ; withInfoDown code (info {cgd_sequel = sequel, cgd_self_loop = Nothing }) }++getSequel :: FCode Sequel+getSequel = do { info <- getInfoDown+ ; return (cgd_sequel info) }++-- ----------------------------------------------------------------------------+-- Get/set the size of the update frame++-- We keep track of the size of the update frame so that we+-- can set the stack pointer to the proper address on return+-- (or tail call) from the closure.+-- There should be at most one update frame for each closure.+-- Note: I'm including the size of the original return address+-- in the size of the update frame -- hence the default case on `get'.++withUpdFrameOff :: UpdFrameOffset -> FCode a -> FCode a+withUpdFrameOff size code+ = do { info <- getInfoDown+ ; withInfoDown code (info {cgd_updfr_off = size }) }++getUpdFrameOff :: FCode UpdFrameOffset+getUpdFrameOff+ = do { info <- getInfoDown+ ; return $ cgd_updfr_off info }++-- ----------------------------------------------------------------------------+-- Get/set the current ticky counter label++getTickyCtrLabel :: FCode CLabel+getTickyCtrLabel = do+ info <- getInfoDown+ return (cgd_ticky info)++setTickyCtrLabel :: CLabel -> FCode a -> FCode a+setTickyCtrLabel ticky code = do+ info <- getInfoDown+ withInfoDown code (info {cgd_ticky = ticky})++-- ----------------------------------------------------------------------------+-- Manage tick scopes++-- | The current tick scope. We will assign this to generated blocks.+getTickScope :: FCode CmmTickScope+getTickScope = do+ info <- getInfoDown+ return (cgd_tick_scope info)++-- | Places blocks generated by the given code into a fresh+-- (sub-)scope. This will make sure that Cmm annotations in our scope+-- will apply to the Cmm blocks generated therein - but not the other+-- way around.+tickScope :: FCode a -> FCode a+tickScope code = do+ info <- getInfoDown+ if debugLevel (cgd_dflags info) == 0 then code else do+ u <- newUnique+ let scope' = SubScope u (cgd_tick_scope info)+ withInfoDown code info{ cgd_tick_scope = scope' }+++--------------------------------------------------------+-- Forking+--------------------------------------------------------++forkClosureBody :: FCode () -> FCode ()+-- forkClosureBody compiles body_code in environment where:+-- - sequel, update stack frame and self loop info are+-- set to fresh values+-- - state is set to a fresh value, except for local bindings+-- that are passed in unchanged. It's up to the enclosed code to+-- re-bind the free variables to a field of the closure.++forkClosureBody body_code+ = do { dflags <- getDynFlags+ ; info <- getInfoDown+ ; us <- newUniqSupply+ ; state <- getState+ ; let body_info_down = info { cgd_sequel = initSequel+ , cgd_updfr_off = initUpdFrameOff dflags+ , cgd_self_loop = Nothing }+ fork_state_in = (initCgState us) { cgs_binds = cgs_binds state }+ ((),fork_state_out) = doFCode body_code body_info_down fork_state_in+ ; setState $ state `addCodeBlocksFrom` fork_state_out }++forkLneBody :: FCode a -> FCode a+-- 'forkLneBody' takes a body of let-no-escape binding and compiles+-- it in the *current* environment, returning the graph thus constructed.+--+-- The current environment is passed on completely unchanged to+-- the successor. In particular, any heap usage from the enclosed+-- code is discarded; it should deal with its own heap consumption.+forkLneBody body_code+ = do { info_down <- getInfoDown+ ; us <- newUniqSupply+ ; state <- getState+ ; let fork_state_in = (initCgState us) { cgs_binds = cgs_binds state }+ (result, fork_state_out) = doFCode body_code info_down fork_state_in+ ; setState $ state `addCodeBlocksFrom` fork_state_out+ ; return result }++codeOnly :: FCode () -> FCode ()+-- Emit any code from the inner thing into the outer thing+-- Do not affect anything else in the outer state+-- Used in almost-circular code to prevent false loop dependencies+codeOnly body_code+ = do { info_down <- getInfoDown+ ; us <- newUniqSupply+ ; state <- getState+ ; let fork_state_in = (initCgState us) { cgs_binds = cgs_binds state+ , cgs_hp_usg = cgs_hp_usg state }+ ((), fork_state_out) = doFCode body_code info_down fork_state_in+ ; setState $ state `addCodeBlocksFrom` fork_state_out }++forkAlts :: [FCode a] -> FCode [a]+-- (forkAlts' bs d) takes fcodes 'bs' for the branches of a 'case', and+-- an fcode for the default case 'd', and compiles each in the current+-- environment. The current environment is passed on unmodified, except+-- that the virtual Hp is moved on to the worst virtual Hp for the branches++forkAlts branch_fcodes+ = do { info_down <- getInfoDown+ ; us <- newUniqSupply+ ; state <- getState+ ; let compile us branch+ = (us2, doFCode branch info_down branch_state)+ where+ (us1,us2) = splitUniqSupply us+ branch_state = (initCgState us1) {+ cgs_binds = cgs_binds state+ , cgs_hp_usg = cgs_hp_usg state }+ (_us, results) = mapAccumL compile us branch_fcodes+ (branch_results, branch_out_states) = unzip results+ ; setState $ foldl stateIncUsage state branch_out_states+ -- NB foldl. state is the *left* argument to stateIncUsage+ ; return branch_results }++-- collect the code emitted by an FCode computation+getCodeR :: FCode a -> FCode (a, CmmAGraph)+getCodeR fcode+ = do { state1 <- getState+ ; (a, state2) <- withState fcode (state1 { cgs_stmts = mkNop })+ ; setState $ state2 { cgs_stmts = cgs_stmts state1 }+ ; return (a, cgs_stmts state2) }++getCode :: FCode a -> FCode CmmAGraph+getCode fcode = do { (_,stmts) <- getCodeR fcode; return stmts }++-- | Generate code into a fresh tick (sub-)scope and gather generated code+getCodeScoped :: FCode a -> FCode (a, CmmAGraphScoped)+getCodeScoped fcode+ = do { state1 <- getState+ ; ((a, tscope), state2) <-+ tickScope $+ flip withState state1 { cgs_stmts = mkNop } $+ do { a <- fcode+ ; scp <- getTickScope+ ; return (a, scp) }+ ; setState $ state2 { cgs_stmts = cgs_stmts state1 }+ ; return (a, (cgs_stmts state2, tscope)) }+++-- 'getHeapUsage' applies a function to the amount of heap that it uses.+-- It initialises the heap usage to zeros, and passes on an unchanged+-- heap usage.+--+-- It is usually a prelude to performing a GC check, so everything must+-- be in a tidy and consistent state.+--+-- Note the slightly subtle fixed point behaviour needed here++getHeapUsage :: (VirtualHpOffset -> FCode a) -> FCode a+getHeapUsage fcode+ = do { info_down <- getInfoDown+ ; state <- getState+ ; let fstate_in = state { cgs_hp_usg = initHpUsage }+ (r, fstate_out) = doFCode (fcode hp_hw) info_down fstate_in+ hp_hw = heapHWM (cgs_hp_usg fstate_out) -- Loop here!++ ; setState $ fstate_out { cgs_hp_usg = cgs_hp_usg state }+ ; return r }++-- ----------------------------------------------------------------------------+-- Combinators for emitting code++emitCgStmt :: CgStmt -> FCode ()+emitCgStmt stmt+ = do { state <- getState+ ; setState $ state { cgs_stmts = cgs_stmts state `snocOL` stmt }+ }++emitLabel :: BlockId -> FCode ()+emitLabel id = do tscope <- getTickScope+ emitCgStmt (CgLabel id tscope)++emitComment :: FastString -> FCode ()+#if 0 /* def DEBUG */+emitComment s = emitCgStmt (CgStmt (CmmComment s))+#else+emitComment _ = return ()+#endif++emitTick :: CmmTickish -> FCode ()+emitTick = emitCgStmt . CgStmt . CmmTick++emitUnwind :: [(GlobalReg, Maybe CmmExpr)] -> FCode ()+emitUnwind regs = do+ dflags <- getDynFlags+ when (debugLevel dflags > 0) $ do+ emitCgStmt $ CgStmt $ CmmUnwind regs++emitAssign :: CmmReg -> CmmExpr -> FCode ()+emitAssign l r = emitCgStmt (CgStmt (CmmAssign l r))++emitStore :: CmmExpr -> CmmExpr -> FCode ()+emitStore l r = emitCgStmt (CgStmt (CmmStore l r))++emit :: CmmAGraph -> FCode ()+emit ag+ = do { state <- getState+ ; setState $ state { cgs_stmts = cgs_stmts state MkGraph.<*> ag } }++emitDecl :: CmmDecl -> FCode ()+emitDecl decl+ = do { state <- getState+ ; setState $ state { cgs_tops = cgs_tops state `snocOL` decl } }++emitOutOfLine :: BlockId -> CmmAGraphScoped -> FCode ()+emitOutOfLine l (stmts, tscope) = emitCgStmt (CgFork l stmts tscope)++emitProcWithStackFrame+ :: Convention -- entry convention+ -> Maybe CmmInfoTable -- info table?+ -> CLabel -- label for the proc+ -> [CmmFormal] -- stack frame+ -> [CmmFormal] -- arguments+ -> CmmAGraphScoped -- code+ -> Bool -- do stack layout?+ -> FCode ()++emitProcWithStackFrame _conv mb_info lbl _stk_args [] blocks False+ = do { dflags <- getDynFlags+ ; emitProc_ mb_info lbl [] blocks (widthInBytes (wordWidth dflags)) False+ }+emitProcWithStackFrame conv mb_info lbl stk_args args (graph, tscope) True+ -- do layout+ = do { dflags <- getDynFlags+ ; let (offset, live, entry) = mkCallEntry dflags conv args stk_args+ graph' = entry MkGraph.<*> graph+ ; emitProc_ mb_info lbl live (graph', tscope) offset True+ }+emitProcWithStackFrame _ _ _ _ _ _ _ = panic "emitProcWithStackFrame"++emitProcWithConvention :: Convention -> Maybe CmmInfoTable -> CLabel+ -> [CmmFormal]+ -> CmmAGraphScoped+ -> FCode ()+emitProcWithConvention conv mb_info lbl args blocks+ = emitProcWithStackFrame conv mb_info lbl [] args blocks True++emitProc :: Maybe CmmInfoTable -> CLabel -> [GlobalReg] -> CmmAGraphScoped+ -> Int -> FCode ()+emitProc mb_info lbl live blocks offset+ = emitProc_ mb_info lbl live blocks offset True++emitProc_ :: Maybe CmmInfoTable -> CLabel -> [GlobalReg] -> CmmAGraphScoped+ -> Int -> Bool -> FCode ()+emitProc_ mb_info lbl live blocks offset do_layout+ = do { dflags <- getDynFlags+ ; l <- newBlockId+ ; let+ blks = labelAGraph l blocks++ infos | Just info <- mb_info = mapSingleton (g_entry blks) info+ | otherwise = mapEmpty++ sinfo = StackInfo { arg_space = offset+ , updfr_space = Just (initUpdFrameOff dflags)+ , do_layout = do_layout }++ tinfo = TopInfo { info_tbls = infos+ , stack_info=sinfo}++ proc_block = CmmProc tinfo lbl live blks++ ; state <- getState+ ; setState $ state { cgs_tops = cgs_tops state `snocOL` proc_block } }++getCmm :: FCode () -> FCode CmmGroup+-- Get all the CmmTops (there should be no stmts)+-- Return a single Cmm which may be split from other Cmms by+-- object splitting (at a later stage)+getCmm code+ = do { state1 <- getState+ ; ((), state2) <- withState code (state1 { cgs_tops = nilOL })+ ; setState $ state2 { cgs_tops = cgs_tops state1 }+ ; return (fromOL (cgs_tops state2)) }+++mkCmmIfThenElse :: CmmExpr -> CmmAGraph -> CmmAGraph -> FCode CmmAGraph+mkCmmIfThenElse e tbranch fbranch = mkCmmIfThenElse' e tbranch fbranch Nothing++mkCmmIfThenElse' :: CmmExpr -> CmmAGraph -> CmmAGraph+ -> Maybe Bool -> FCode CmmAGraph+mkCmmIfThenElse' e tbranch fbranch likely = do+ tscp <- getTickScope+ endif <- newBlockId+ tid <- newBlockId+ fid <- newBlockId++ let+ (test, then_, else_, likely') = case likely of+ Just False | Just e' <- maybeInvertCmmExpr e+ -- currently NCG doesn't know about likely+ -- annotations. We manually switch then and+ -- else branch so the likely false branch+ -- becomes a fallthrough.+ -> (e', fbranch, tbranch, Just True)+ _ -> (e, tbranch, fbranch, likely)++ return $ catAGraphs [ mkCbranch test tid fid likely'+ , mkLabel tid tscp, then_, mkBranch endif+ , mkLabel fid tscp, else_, mkLabel endif tscp ]++mkCmmIfGoto :: CmmExpr -> BlockId -> FCode CmmAGraph+mkCmmIfGoto e tid = mkCmmIfGoto' e tid Nothing++mkCmmIfGoto' :: CmmExpr -> BlockId -> Maybe Bool -> FCode CmmAGraph+mkCmmIfGoto' e tid l = do+ endif <- newBlockId+ tscp <- getTickScope+ return $ catAGraphs [ mkCbranch e tid endif l, mkLabel endif tscp ]++mkCmmIfThen :: CmmExpr -> CmmAGraph -> FCode CmmAGraph+mkCmmIfThen e tbranch = mkCmmIfThen' e tbranch Nothing++mkCmmIfThen' :: CmmExpr -> CmmAGraph -> Maybe Bool -> FCode CmmAGraph+mkCmmIfThen' e tbranch l = do+ endif <- newBlockId+ tid <- newBlockId+ tscp <- getTickScope+ return $ catAGraphs [ mkCbranch e tid endif l+ , mkLabel tid tscp, tbranch, mkLabel endif tscp ]++mkCall :: CmmExpr -> (Convention, Convention) -> [CmmFormal] -> [CmmExpr]+ -> UpdFrameOffset -> [CmmExpr] -> FCode CmmAGraph+mkCall f (callConv, retConv) results actuals updfr_off extra_stack = do+ dflags <- getDynFlags+ k <- newBlockId+ tscp <- getTickScope+ let area = Young k+ (off, _, copyin) = copyInOflow dflags retConv area results []+ copyout = mkCallReturnsTo dflags f callConv actuals k off updfr_off extra_stack+ return $ catAGraphs [copyout, mkLabel k tscp, copyin]++mkCmmCall :: CmmExpr -> [CmmFormal] -> [CmmExpr] -> UpdFrameOffset+ -> FCode CmmAGraph+mkCmmCall f results actuals updfr_off+ = mkCall f (NativeDirectCall, NativeReturn) results actuals updfr_off []+++-- ----------------------------------------------------------------------------+-- turn CmmAGraph into CmmGraph, for making a new proc.++aGraphToGraph :: CmmAGraphScoped -> FCode CmmGraph+aGraphToGraph stmts+ = do { l <- newBlockId+ ; return (labelAGraph l stmts) }
+ codeGen/StgCmmPrim.hs view
@@ -0,0 +1,2242 @@+{-# LANGUAGE CPP #-}++----------------------------------------------------------------------------+--+-- Stg to C--: primitive operations+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmPrim (+ cgOpApp,+ cgPrimOp, -- internal(ish), used by cgCase to get code for a+ -- comparison without also turning it into a Bool.+ shouldInlinePrimOp+ ) where++#include "HsVersions.h"++import StgCmmLayout+import StgCmmForeign+import StgCmmEnv+import StgCmmMonad+import StgCmmUtils+import StgCmmTicky+import StgCmmHeap+import StgCmmProf ( costCentreFrom, curCCS )++import DynFlags+import Platform+import BasicTypes+import BlockId+import MkGraph+import StgSyn+import Cmm+import CmmInfo+import Type ( Type, tyConAppTyCon )+import TyCon+import CLabel+import CmmUtils+import PrimOp+import SMRep+import FastString+import Outputable+import Util++import Prelude hiding ((<*>))++import Data.Bits ((.&.), bit)+import Control.Monad (liftM, when)++------------------------------------------------------------------------+-- Primitive operations and foreign calls+------------------------------------------------------------------------++{- Note [Foreign call results]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~+A foreign call always returns an unboxed tuple of results, one+of which is the state token. This seems to happen even for pure+calls.++Even if we returned a single result for pure calls, it'd still be+right to wrap it in a singleton unboxed tuple, because the result+might be a Haskell closure pointer, we don't want to evaluate it. -}++----------------------------------+cgOpApp :: StgOp -- The op+ -> [StgArg] -- Arguments+ -> Type -- Result type (always an unboxed tuple)+ -> FCode ReturnKind++-- Foreign calls+cgOpApp (StgFCallOp fcall _) stg_args res_ty+ = cgForeignCall fcall stg_args res_ty+ -- Note [Foreign call results]++-- tagToEnum# is special: we need to pull the constructor+-- out of the table, and perform an appropriate return.++cgOpApp (StgPrimOp TagToEnumOp) [arg] res_ty+ = ASSERT(isEnumerationTyCon tycon)+ do { dflags <- getDynFlags+ ; args' <- getNonVoidArgAmodes [arg]+ ; let amode = case args' of [amode] -> amode+ _ -> panic "TagToEnumOp had void arg"+ ; emitReturn [tagToClosure dflags tycon amode] }+ where+ -- If you're reading this code in the attempt to figure+ -- out why the compiler panic'ed here, it is probably because+ -- you used tagToEnum# in a non-monomorphic setting, e.g.,+ -- intToTg :: Enum a => Int -> a ; intToTg (I# x#) = tagToEnum# x#+ -- That won't work.+ tycon = tyConAppTyCon res_ty++cgOpApp (StgPrimOp primop) args res_ty = do+ dflags <- getDynFlags+ cmm_args <- getNonVoidArgAmodes args+ case shouldInlinePrimOp dflags primop cmm_args of+ Nothing -> do -- out-of-line+ let fun = CmmLit (CmmLabel (mkRtsPrimOpLabel primop))+ emitCall (NativeNodeCall, NativeReturn) fun cmm_args++ Just f -- inline+ | ReturnsPrim VoidRep <- result_info+ -> do f []+ emitReturn []++ | ReturnsPrim rep <- result_info+ -> do dflags <- getDynFlags+ res <- newTemp (primRepCmmType dflags rep)+ f [res]+ emitReturn [CmmReg (CmmLocal res)]++ | ReturnsAlg tycon <- result_info, isUnboxedTupleTyCon tycon+ -> do (regs, _hints) <- newUnboxedTupleRegs res_ty+ f regs+ emitReturn (map (CmmReg . CmmLocal) regs)++ | otherwise -> panic "cgPrimop"+ where+ result_info = getPrimOpResultInfo primop++cgOpApp (StgPrimCallOp primcall) args _res_ty+ = do { cmm_args <- getNonVoidArgAmodes args+ ; let fun = CmmLit (CmmLabel (mkPrimCallLabel primcall))+ ; emitCall (NativeNodeCall, NativeReturn) fun cmm_args }++-- | Interpret the argument as an unsigned value, assuming the value+-- is given in two-complement form in the given width.+--+-- Example: @asUnsigned W64 (-1)@ is 18446744073709551615.+--+-- This function is used to work around the fact that many array+-- primops take Int# arguments, but we interpret them as unsigned+-- quantities in the code gen. This means that we have to be careful+-- every time we work on e.g. a CmmInt literal that corresponds to the+-- array size, as it might contain a negative Integer value if the+-- user passed a value larger than 2^(wORD_SIZE_IN_BITS-1) as the Int#+-- literal.+asUnsigned :: Width -> Integer -> Integer+asUnsigned w n = n .&. (bit (widthInBits w) - 1)++-- TODO: Several primop implementations (e.g. 'doNewByteArrayOp') use+-- ByteOff (or some other fixed width signed type) to represent+-- array sizes or indices. This means that these will overflow for+-- large enough sizes.++-- | Decide whether an out-of-line primop should be replaced by an+-- inline implementation. This might happen e.g. if there's enough+-- static information, such as statically know arguments, to emit a+-- more efficient implementation inline.+--+-- Returns 'Nothing' if this primop should use its out-of-line+-- implementation (defined elsewhere) and 'Just' together with a code+-- generating function that takes the output regs as arguments+-- otherwise.+shouldInlinePrimOp :: DynFlags+ -> PrimOp -- ^ The primop+ -> [CmmExpr] -- ^ The primop arguments+ -> Maybe ([LocalReg] -> FCode ())++shouldInlinePrimOp dflags NewByteArrayOp_Char [(CmmLit (CmmInt n w))]+ | asUnsigned w n <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> doNewByteArrayOp res (fromInteger n)++shouldInlinePrimOp dflags NewArrayOp [(CmmLit (CmmInt n w)), init]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] ->+ doNewArrayOp res (arrPtrsRep dflags (fromInteger n)) mkMAP_DIRTY_infoLabel+ [ (mkIntExpr dflags (fromInteger n),+ fixedHdrSize dflags + oFFSET_StgMutArrPtrs_ptrs dflags)+ , (mkIntExpr dflags (nonHdrSizeW (arrPtrsRep dflags (fromInteger n))),+ fixedHdrSize dflags + oFFSET_StgMutArrPtrs_size dflags)+ ]+ (fromInteger n) init++shouldInlinePrimOp _ CopyArrayOp+ [src, src_off, dst, dst_off, (CmmLit (CmmInt n _))] =+ Just $ \ [] -> doCopyArrayOp src src_off dst dst_off (fromInteger n)++shouldInlinePrimOp _ CopyMutableArrayOp+ [src, src_off, dst, dst_off, (CmmLit (CmmInt n _))] =+ Just $ \ [] -> doCopyMutableArrayOp src src_off dst dst_off (fromInteger n)++shouldInlinePrimOp _ CopyArrayArrayOp+ [src, src_off, dst, dst_off, (CmmLit (CmmInt n _))] =+ Just $ \ [] -> doCopyArrayOp src src_off dst dst_off (fromInteger n)++shouldInlinePrimOp _ CopyMutableArrayArrayOp+ [src, src_off, dst, dst_off, (CmmLit (CmmInt n _))] =+ Just $ \ [] -> doCopyMutableArrayOp src src_off dst dst_off (fromInteger n)++shouldInlinePrimOp dflags CloneArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneArray mkMAP_FROZEN_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags CloneMutableArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneArray mkMAP_DIRTY_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags FreezeArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneArray mkMAP_FROZEN_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags ThawArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneArray mkMAP_DIRTY_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags NewSmallArrayOp [(CmmLit (CmmInt n w)), init]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] ->+ doNewArrayOp res (smallArrPtrsRep (fromInteger n)) mkSMAP_DIRTY_infoLabel+ [ (mkIntExpr dflags (fromInteger n),+ fixedHdrSize dflags + oFFSET_StgSmallMutArrPtrs_ptrs dflags)+ ]+ (fromInteger n) init++shouldInlinePrimOp _ CopySmallArrayOp+ [src, src_off, dst, dst_off, (CmmLit (CmmInt n _))] =+ Just $ \ [] -> doCopySmallArrayOp src src_off dst dst_off (fromInteger n)++shouldInlinePrimOp _ CopySmallMutableArrayOp+ [src, src_off, dst, dst_off, (CmmLit (CmmInt n _))] =+ Just $ \ [] -> doCopySmallMutableArrayOp src src_off dst dst_off (fromInteger n)++shouldInlinePrimOp dflags CloneSmallArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneSmallArray mkSMAP_FROZEN_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags CloneSmallMutableArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneSmallArray mkSMAP_DIRTY_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags FreezeSmallArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneSmallArray mkSMAP_FROZEN_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags ThawSmallArrayOp [src, src_off, (CmmLit (CmmInt n w))]+ | wordsToBytes dflags (asUnsigned w n) <= fromIntegral (maxInlineAllocSize dflags) =+ Just $ \ [res] -> emitCloneSmallArray mkSMAP_DIRTY_infoLabel res src src_off (fromInteger n)++shouldInlinePrimOp dflags primop args+ | primOpOutOfLine primop = Nothing+ | otherwise = Just $ \ regs -> emitPrimOp dflags regs primop args++-- TODO: Several primops, such as 'copyArray#', only have an inline+-- implementation (below) but could possibly have both an inline+-- implementation and an out-of-line implementation, just like+-- 'newArray#'. This would lower the amount of code generated,+-- hopefully without a performance impact (needs to be measured).++---------------------------------------------------+cgPrimOp :: [LocalReg] -- where to put the results+ -> PrimOp -- the op+ -> [StgArg] -- arguments+ -> FCode ()++cgPrimOp results op args+ = do dflags <- getDynFlags+ arg_exprs <- getNonVoidArgAmodes args+ emitPrimOp dflags results op arg_exprs+++------------------------------------------------------------------------+-- Emitting code for a primop+------------------------------------------------------------------------++emitPrimOp :: DynFlags+ -> [LocalReg] -- where to put the results+ -> PrimOp -- the op+ -> [CmmExpr] -- arguments+ -> FCode ()++-- First we handle various awkward cases specially. The remaining+-- easy cases are then handled by translateOp, defined below.++emitPrimOp _ [res] ParOp [arg]+ =+ -- for now, just implement this in a C function+ -- later, we might want to inline it.+ emitCCall+ [(res,NoHint)]+ (CmmLit (CmmLabel (mkForeignLabel (fsLit "newSpark") Nothing ForeignLabelInExternalPackage IsFunction)))+ [(CmmReg (CmmGlobal BaseReg), AddrHint), (arg,AddrHint)]++emitPrimOp dflags [res] SparkOp [arg]+ = do+ -- returns the value of arg in res. We're going to therefore+ -- refer to arg twice (once to pass to newSpark(), and once to+ -- assign to res), so put it in a temporary.+ tmp <- assignTemp arg+ tmp2 <- newTemp (bWord dflags)+ emitCCall+ [(tmp2,NoHint)]+ (CmmLit (CmmLabel (mkForeignLabel (fsLit "newSpark") Nothing ForeignLabelInExternalPackage IsFunction)))+ [(CmmReg (CmmGlobal BaseReg), AddrHint), ((CmmReg (CmmLocal tmp)), AddrHint)]+ emitAssign (CmmLocal res) (CmmReg (CmmLocal tmp))++emitPrimOp dflags [res] GetCCSOfOp [arg]+ = emitAssign (CmmLocal res) val+ where+ val+ | gopt Opt_SccProfilingOn dflags = costCentreFrom dflags (cmmUntag dflags arg)+ | otherwise = CmmLit (zeroCLit dflags)++emitPrimOp _ [res] GetCurrentCCSOp [_dummy_arg]+ = emitAssign (CmmLocal res) curCCS++emitPrimOp dflags [res] ReadMutVarOp [mutv]+ = emitAssign (CmmLocal res) (cmmLoadIndexW dflags mutv (fixedHdrSizeW dflags) (gcWord dflags))++emitPrimOp dflags res@[] WriteMutVarOp [mutv,var]+ = do -- Without this write barrier, other CPUs may see this pointer before+ -- the writes for the closure it points to have occurred.+ emitPrimCall res MO_WriteBarrier []+ emitStore (cmmOffsetW dflags mutv (fixedHdrSizeW dflags)) var+ emitCCall+ [{-no results-}]+ (CmmLit (CmmLabel mkDirty_MUT_VAR_Label))+ [(CmmReg (CmmGlobal BaseReg), AddrHint), (mutv,AddrHint)]++-- #define sizzeofByteArrayzh(r,a) \+-- r = ((StgArrBytes *)(a))->bytes+emitPrimOp dflags [res] SizeofByteArrayOp [arg]+ = emit $ mkAssign (CmmLocal res) (cmmLoadIndexW dflags arg (fixedHdrSizeW dflags) (bWord dflags))++-- #define sizzeofMutableByteArrayzh(r,a) \+-- r = ((StgArrBytes *)(a))->bytes+emitPrimOp dflags [res] SizeofMutableByteArrayOp [arg]+ = emitPrimOp dflags [res] SizeofByteArrayOp [arg]++-- #define getSizzeofMutableByteArrayzh(r,a) \+-- r = ((StgArrBytes *)(a))->bytes+emitPrimOp dflags [res] GetSizeofMutableByteArrayOp [arg]+ = emitAssign (CmmLocal res) (cmmLoadIndexW dflags arg (fixedHdrSizeW dflags) (bWord dflags))+++-- #define touchzh(o) /* nothing */+emitPrimOp _ res@[] TouchOp args@[_arg]+ = do emitPrimCall res MO_Touch args++-- #define byteArrayContentszh(r,a) r = BYTE_ARR_CTS(a)+emitPrimOp dflags [res] ByteArrayContents_Char [arg]+ = emitAssign (CmmLocal res) (cmmOffsetB dflags arg (arrWordsHdrSize dflags))++-- #define stableNameToIntzh(r,s) (r = ((StgStableName *)s)->sn)+emitPrimOp dflags [res] StableNameToIntOp [arg]+ = emitAssign (CmmLocal res) (cmmLoadIndexW dflags arg (fixedHdrSizeW dflags) (bWord dflags))++-- #define eqStableNamezh(r,sn1,sn2) \+-- (r = (((StgStableName *)sn1)->sn == ((StgStableName *)sn2)->sn))+emitPrimOp dflags [res] EqStableNameOp [arg1,arg2]+ = emitAssign (CmmLocal res) (CmmMachOp (mo_wordEq dflags) [+ cmmLoadIndexW dflags arg1 (fixedHdrSizeW dflags) (bWord dflags),+ cmmLoadIndexW dflags arg2 (fixedHdrSizeW dflags) (bWord dflags)+ ])++emitPrimOp dflags [res] ReallyUnsafePtrEqualityOp [arg1,arg2]+ = emitAssign (CmmLocal res) (CmmMachOp (mo_wordEq dflags) [arg1,arg2])++-- #define addrToHValuezh(r,a) r=(P_)a+emitPrimOp _ [res] AddrToAnyOp [arg]+ = emitAssign (CmmLocal res) arg++-- #define hvalueToAddrzh(r, a) r=(W_)a+emitPrimOp _ [res] AnyToAddrOp [arg]+ = emitAssign (CmmLocal res) arg++-- #define dataToTagzh(r,a) r=(GET_TAG(((StgClosure *)a)->header.info))+-- Note: argument may be tagged!+emitPrimOp dflags [res] DataToTagOp [arg]+ = emitAssign (CmmLocal res) (getConstrTag dflags (cmmUntag dflags arg))++{- Freezing arrays-of-ptrs requires changing an info table, for the+ benefit of the generational collector. It needs to scavenge mutable+ objects, even if they are in old space. When they become immutable,+ they can be removed from this scavenge list. -}++-- #define unsafeFreezzeArrayzh(r,a)+-- {+-- SET_INFO((StgClosure *)a,&stg_MUT_ARR_PTRS_FROZEN0_info);+-- r = a;+-- }+emitPrimOp _ [res] UnsafeFreezeArrayOp [arg]+ = emit $ catAGraphs+ [ setInfo arg (CmmLit (CmmLabel mkMAP_FROZEN0_infoLabel)),+ mkAssign (CmmLocal res) arg ]+emitPrimOp _ [res] UnsafeFreezeArrayArrayOp [arg]+ = emit $ catAGraphs+ [ setInfo arg (CmmLit (CmmLabel mkMAP_FROZEN0_infoLabel)),+ mkAssign (CmmLocal res) arg ]+emitPrimOp _ [res] UnsafeFreezeSmallArrayOp [arg]+ = emit $ catAGraphs+ [ setInfo arg (CmmLit (CmmLabel mkSMAP_FROZEN0_infoLabel)),+ mkAssign (CmmLocal res) arg ]++-- #define unsafeFreezzeByteArrayzh(r,a) r=(a)+emitPrimOp _ [res] UnsafeFreezeByteArrayOp [arg]+ = emitAssign (CmmLocal res) arg++-- Reading/writing pointer arrays++emitPrimOp _ [res] ReadArrayOp [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [res] IndexArrayOp [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [] WriteArrayOp [obj,ix,v] = doWritePtrArrayOp obj ix v++emitPrimOp _ [res] IndexArrayArrayOp_ByteArray [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [res] IndexArrayArrayOp_ArrayArray [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [res] ReadArrayArrayOp_ByteArray [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [res] ReadArrayArrayOp_MutableByteArray [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [res] ReadArrayArrayOp_ArrayArray [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [res] ReadArrayArrayOp_MutableArrayArray [obj,ix] = doReadPtrArrayOp res obj ix+emitPrimOp _ [] WriteArrayArrayOp_ByteArray [obj,ix,v] = doWritePtrArrayOp obj ix v+emitPrimOp _ [] WriteArrayArrayOp_MutableByteArray [obj,ix,v] = doWritePtrArrayOp obj ix v+emitPrimOp _ [] WriteArrayArrayOp_ArrayArray [obj,ix,v] = doWritePtrArrayOp obj ix v+emitPrimOp _ [] WriteArrayArrayOp_MutableArrayArray [obj,ix,v] = doWritePtrArrayOp obj ix v++emitPrimOp _ [res] ReadSmallArrayOp [obj,ix] = doReadSmallPtrArrayOp res obj ix+emitPrimOp _ [res] IndexSmallArrayOp [obj,ix] = doReadSmallPtrArrayOp res obj ix+emitPrimOp _ [] WriteSmallArrayOp [obj,ix,v] = doWriteSmallPtrArrayOp obj ix v++-- Getting the size of pointer arrays++emitPrimOp dflags [res] SizeofArrayOp [arg]+ = emit $ mkAssign (CmmLocal res) (cmmLoadIndexW dflags arg+ (fixedHdrSizeW dflags + bytesToWordsRoundUp dflags (oFFSET_StgMutArrPtrs_ptrs dflags))+ (bWord dflags))+emitPrimOp dflags [res] SizeofMutableArrayOp [arg]+ = emitPrimOp dflags [res] SizeofArrayOp [arg]+emitPrimOp dflags [res] SizeofArrayArrayOp [arg]+ = emitPrimOp dflags [res] SizeofArrayOp [arg]+emitPrimOp dflags [res] SizeofMutableArrayArrayOp [arg]+ = emitPrimOp dflags [res] SizeofArrayOp [arg]++emitPrimOp dflags [res] SizeofSmallArrayOp [arg] =+ emit $ mkAssign (CmmLocal res)+ (cmmLoadIndexW dflags arg+ (fixedHdrSizeW dflags + bytesToWordsRoundUp dflags (oFFSET_StgSmallMutArrPtrs_ptrs dflags))+ (bWord dflags))+emitPrimOp dflags [res] SizeofSmallMutableArrayOp [arg] =+ emitPrimOp dflags [res] SizeofSmallArrayOp [arg]++-- IndexXXXoffAddr++emitPrimOp dflags res IndexOffAddrOp_Char args = doIndexOffAddrOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res IndexOffAddrOp_WideChar args = doIndexOffAddrOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp dflags res IndexOffAddrOp_Int args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res IndexOffAddrOp_Word args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res IndexOffAddrOp_Addr args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp _ res IndexOffAddrOp_Float args = doIndexOffAddrOp Nothing f32 res args+emitPrimOp _ res IndexOffAddrOp_Double args = doIndexOffAddrOp Nothing f64 res args+emitPrimOp dflags res IndexOffAddrOp_StablePtr args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res IndexOffAddrOp_Int8 args = doIndexOffAddrOp (Just (mo_s_8ToWord dflags)) b8 res args+emitPrimOp dflags res IndexOffAddrOp_Int16 args = doIndexOffAddrOp (Just (mo_s_16ToWord dflags)) b16 res args+emitPrimOp dflags res IndexOffAddrOp_Int32 args = doIndexOffAddrOp (Just (mo_s_32ToWord dflags)) b32 res args+emitPrimOp _ res IndexOffAddrOp_Int64 args = doIndexOffAddrOp Nothing b64 res args+emitPrimOp dflags res IndexOffAddrOp_Word8 args = doIndexOffAddrOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res IndexOffAddrOp_Word16 args = doIndexOffAddrOp (Just (mo_u_16ToWord dflags)) b16 res args+emitPrimOp dflags res IndexOffAddrOp_Word32 args = doIndexOffAddrOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp _ res IndexOffAddrOp_Word64 args = doIndexOffAddrOp Nothing b64 res args++-- ReadXXXoffAddr, which are identical, for our purposes, to IndexXXXoffAddr.++emitPrimOp dflags res ReadOffAddrOp_Char args = doIndexOffAddrOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res ReadOffAddrOp_WideChar args = doIndexOffAddrOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp dflags res ReadOffAddrOp_Int args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res ReadOffAddrOp_Word args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res ReadOffAddrOp_Addr args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp _ res ReadOffAddrOp_Float args = doIndexOffAddrOp Nothing f32 res args+emitPrimOp _ res ReadOffAddrOp_Double args = doIndexOffAddrOp Nothing f64 res args+emitPrimOp dflags res ReadOffAddrOp_StablePtr args = doIndexOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res ReadOffAddrOp_Int8 args = doIndexOffAddrOp (Just (mo_s_8ToWord dflags)) b8 res args+emitPrimOp dflags res ReadOffAddrOp_Int16 args = doIndexOffAddrOp (Just (mo_s_16ToWord dflags)) b16 res args+emitPrimOp dflags res ReadOffAddrOp_Int32 args = doIndexOffAddrOp (Just (mo_s_32ToWord dflags)) b32 res args+emitPrimOp _ res ReadOffAddrOp_Int64 args = doIndexOffAddrOp Nothing b64 res args+emitPrimOp dflags res ReadOffAddrOp_Word8 args = doIndexOffAddrOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res ReadOffAddrOp_Word16 args = doIndexOffAddrOp (Just (mo_u_16ToWord dflags)) b16 res args+emitPrimOp dflags res ReadOffAddrOp_Word32 args = doIndexOffAddrOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp _ res ReadOffAddrOp_Word64 args = doIndexOffAddrOp Nothing b64 res args++-- IndexXXXArray++emitPrimOp dflags res IndexByteArrayOp_Char args = doIndexByteArrayOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res IndexByteArrayOp_WideChar args = doIndexByteArrayOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp dflags res IndexByteArrayOp_Int args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res IndexByteArrayOp_Word args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res IndexByteArrayOp_Addr args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp _ res IndexByteArrayOp_Float args = doIndexByteArrayOp Nothing f32 res args+emitPrimOp _ res IndexByteArrayOp_Double args = doIndexByteArrayOp Nothing f64 res args+emitPrimOp dflags res IndexByteArrayOp_StablePtr args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res IndexByteArrayOp_Int8 args = doIndexByteArrayOp (Just (mo_s_8ToWord dflags)) b8 res args+emitPrimOp dflags res IndexByteArrayOp_Int16 args = doIndexByteArrayOp (Just (mo_s_16ToWord dflags)) b16 res args+emitPrimOp dflags res IndexByteArrayOp_Int32 args = doIndexByteArrayOp (Just (mo_s_32ToWord dflags)) b32 res args+emitPrimOp _ res IndexByteArrayOp_Int64 args = doIndexByteArrayOp Nothing b64 res args+emitPrimOp dflags res IndexByteArrayOp_Word8 args = doIndexByteArrayOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res IndexByteArrayOp_Word16 args = doIndexByteArrayOp (Just (mo_u_16ToWord dflags)) b16 res args+emitPrimOp dflags res IndexByteArrayOp_Word32 args = doIndexByteArrayOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp _ res IndexByteArrayOp_Word64 args = doIndexByteArrayOp Nothing b64 res args++-- ReadXXXArray, identical to IndexXXXArray.++emitPrimOp dflags res ReadByteArrayOp_Char args = doIndexByteArrayOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res ReadByteArrayOp_WideChar args = doIndexByteArrayOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp dflags res ReadByteArrayOp_Int args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res ReadByteArrayOp_Word args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res ReadByteArrayOp_Addr args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp _ res ReadByteArrayOp_Float args = doIndexByteArrayOp Nothing f32 res args+emitPrimOp _ res ReadByteArrayOp_Double args = doIndexByteArrayOp Nothing f64 res args+emitPrimOp dflags res ReadByteArrayOp_StablePtr args = doIndexByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res ReadByteArrayOp_Int8 args = doIndexByteArrayOp (Just (mo_s_8ToWord dflags)) b8 res args+emitPrimOp dflags res ReadByteArrayOp_Int16 args = doIndexByteArrayOp (Just (mo_s_16ToWord dflags)) b16 res args+emitPrimOp dflags res ReadByteArrayOp_Int32 args = doIndexByteArrayOp (Just (mo_s_32ToWord dflags)) b32 res args+emitPrimOp _ res ReadByteArrayOp_Int64 args = doIndexByteArrayOp Nothing b64 res args+emitPrimOp dflags res ReadByteArrayOp_Word8 args = doIndexByteArrayOp (Just (mo_u_8ToWord dflags)) b8 res args+emitPrimOp dflags res ReadByteArrayOp_Word16 args = doIndexByteArrayOp (Just (mo_u_16ToWord dflags)) b16 res args+emitPrimOp dflags res ReadByteArrayOp_Word32 args = doIndexByteArrayOp (Just (mo_u_32ToWord dflags)) b32 res args+emitPrimOp _ res ReadByteArrayOp_Word64 args = doIndexByteArrayOp Nothing b64 res args++-- WriteXXXoffAddr++emitPrimOp dflags res WriteOffAddrOp_Char args = doWriteOffAddrOp (Just (mo_WordTo8 dflags)) b8 res args+emitPrimOp dflags res WriteOffAddrOp_WideChar args = doWriteOffAddrOp (Just (mo_WordTo32 dflags)) b32 res args+emitPrimOp dflags res WriteOffAddrOp_Int args = doWriteOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res WriteOffAddrOp_Word args = doWriteOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res WriteOffAddrOp_Addr args = doWriteOffAddrOp Nothing (bWord dflags) res args+emitPrimOp _ res WriteOffAddrOp_Float args = doWriteOffAddrOp Nothing f32 res args+emitPrimOp _ res WriteOffAddrOp_Double args = doWriteOffAddrOp Nothing f64 res args+emitPrimOp dflags res WriteOffAddrOp_StablePtr args = doWriteOffAddrOp Nothing (bWord dflags) res args+emitPrimOp dflags res WriteOffAddrOp_Int8 args = doWriteOffAddrOp (Just (mo_WordTo8 dflags)) b8 res args+emitPrimOp dflags res WriteOffAddrOp_Int16 args = doWriteOffAddrOp (Just (mo_WordTo16 dflags)) b16 res args+emitPrimOp dflags res WriteOffAddrOp_Int32 args = doWriteOffAddrOp (Just (mo_WordTo32 dflags)) b32 res args+emitPrimOp _ res WriteOffAddrOp_Int64 args = doWriteOffAddrOp Nothing b64 res args+emitPrimOp dflags res WriteOffAddrOp_Word8 args = doWriteOffAddrOp (Just (mo_WordTo8 dflags)) b8 res args+emitPrimOp dflags res WriteOffAddrOp_Word16 args = doWriteOffAddrOp (Just (mo_WordTo16 dflags)) b16 res args+emitPrimOp dflags res WriteOffAddrOp_Word32 args = doWriteOffAddrOp (Just (mo_WordTo32 dflags)) b32 res args+emitPrimOp _ res WriteOffAddrOp_Word64 args = doWriteOffAddrOp Nothing b64 res args++-- WriteXXXArray++emitPrimOp dflags res WriteByteArrayOp_Char args = doWriteByteArrayOp (Just (mo_WordTo8 dflags)) b8 res args+emitPrimOp dflags res WriteByteArrayOp_WideChar args = doWriteByteArrayOp (Just (mo_WordTo32 dflags)) b32 res args+emitPrimOp dflags res WriteByteArrayOp_Int args = doWriteByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res WriteByteArrayOp_Word args = doWriteByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res WriteByteArrayOp_Addr args = doWriteByteArrayOp Nothing (bWord dflags) res args+emitPrimOp _ res WriteByteArrayOp_Float args = doWriteByteArrayOp Nothing f32 res args+emitPrimOp _ res WriteByteArrayOp_Double args = doWriteByteArrayOp Nothing f64 res args+emitPrimOp dflags res WriteByteArrayOp_StablePtr args = doWriteByteArrayOp Nothing (bWord dflags) res args+emitPrimOp dflags res WriteByteArrayOp_Int8 args = doWriteByteArrayOp (Just (mo_WordTo8 dflags)) b8 res args+emitPrimOp dflags res WriteByteArrayOp_Int16 args = doWriteByteArrayOp (Just (mo_WordTo16 dflags)) b16 res args+emitPrimOp dflags res WriteByteArrayOp_Int32 args = doWriteByteArrayOp (Just (mo_WordTo32 dflags)) b32 res args+emitPrimOp _ res WriteByteArrayOp_Int64 args = doWriteByteArrayOp Nothing b64 res args+emitPrimOp dflags res WriteByteArrayOp_Word8 args = doWriteByteArrayOp (Just (mo_WordTo8 dflags)) b8 res args+emitPrimOp dflags res WriteByteArrayOp_Word16 args = doWriteByteArrayOp (Just (mo_WordTo16 dflags)) b16 res args+emitPrimOp dflags res WriteByteArrayOp_Word32 args = doWriteByteArrayOp (Just (mo_WordTo32 dflags)) b32 res args+emitPrimOp _ res WriteByteArrayOp_Word64 args = doWriteByteArrayOp Nothing b64 res args++-- Copying and setting byte arrays+emitPrimOp _ [] CopyByteArrayOp [src,src_off,dst,dst_off,n] =+ doCopyByteArrayOp src src_off dst dst_off n+emitPrimOp _ [] CopyMutableByteArrayOp [src,src_off,dst,dst_off,n] =+ doCopyMutableByteArrayOp src src_off dst dst_off n+emitPrimOp _ [] CopyByteArrayToAddrOp [src,src_off,dst,n] =+ doCopyByteArrayToAddrOp src src_off dst n+emitPrimOp _ [] CopyMutableByteArrayToAddrOp [src,src_off,dst,n] =+ doCopyMutableByteArrayToAddrOp src src_off dst n+emitPrimOp _ [] CopyAddrToByteArrayOp [src,dst,dst_off,n] =+ doCopyAddrToByteArrayOp src dst dst_off n+emitPrimOp _ [] SetByteArrayOp [ba,off,len,c] =+ doSetByteArrayOp ba off len c++emitPrimOp _ [res] BSwap16Op [w] = emitBSwapCall res w W16+emitPrimOp _ [res] BSwap32Op [w] = emitBSwapCall res w W32+emitPrimOp _ [res] BSwap64Op [w] = emitBSwapCall res w W64+emitPrimOp dflags [res] BSwapOp [w] = emitBSwapCall res w (wordWidth dflags)++-- Population count+emitPrimOp _ [res] PopCnt8Op [w] = emitPopCntCall res w W8+emitPrimOp _ [res] PopCnt16Op [w] = emitPopCntCall res w W16+emitPrimOp _ [res] PopCnt32Op [w] = emitPopCntCall res w W32+emitPrimOp _ [res] PopCnt64Op [w] = emitPopCntCall res w W64+emitPrimOp dflags [res] PopCntOp [w] = emitPopCntCall res w (wordWidth dflags)++-- count leading zeros+emitPrimOp _ [res] Clz8Op [w] = emitClzCall res w W8+emitPrimOp _ [res] Clz16Op [w] = emitClzCall res w W16+emitPrimOp _ [res] Clz32Op [w] = emitClzCall res w W32+emitPrimOp _ [res] Clz64Op [w] = emitClzCall res w W64+emitPrimOp dflags [res] ClzOp [w] = emitClzCall res w (wordWidth dflags)++-- count trailing zeros+emitPrimOp _ [res] Ctz8Op [w] = emitCtzCall res w W8+emitPrimOp _ [res] Ctz16Op [w] = emitCtzCall res w W16+emitPrimOp _ [res] Ctz32Op [w] = emitCtzCall res w W32+emitPrimOp _ [res] Ctz64Op [w] = emitCtzCall res w W64+emitPrimOp dflags [res] CtzOp [w] = emitCtzCall res w (wordWidth dflags)++-- Unsigned int to floating point conversions+emitPrimOp _ [res] Word2FloatOp [w] = emitPrimCall [res]+ (MO_UF_Conv W32) [w]+emitPrimOp _ [res] Word2DoubleOp [w] = emitPrimCall [res]+ (MO_UF_Conv W64) [w]++-- SIMD primops+emitPrimOp dflags [res] (VecBroadcastOp vcat n w) [e] = do+ checkVecCompatibility dflags vcat n w+ doVecPackOp (vecElemInjectCast dflags vcat w) ty zeros (replicate n e) res+ where+ zeros :: CmmExpr+ zeros = CmmLit $ CmmVec (replicate n zero)++ zero :: CmmLit+ zero = case vcat of+ IntVec -> CmmInt 0 w+ WordVec -> CmmInt 0 w+ FloatVec -> CmmFloat 0 w++ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags [res] (VecPackOp vcat n w) es = do+ checkVecCompatibility dflags vcat n w+ when (length es /= n) $+ panic "emitPrimOp: VecPackOp has wrong number of arguments"+ doVecPackOp (vecElemInjectCast dflags vcat w) ty zeros es res+ where+ zeros :: CmmExpr+ zeros = CmmLit $ CmmVec (replicate n zero)++ zero :: CmmLit+ zero = case vcat of+ IntVec -> CmmInt 0 w+ WordVec -> CmmInt 0 w+ FloatVec -> CmmFloat 0 w++ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecUnpackOp vcat n w) [arg] = do+ checkVecCompatibility dflags vcat n w+ when (length res /= n) $+ panic "emitPrimOp: VecUnpackOp has wrong number of results"+ doVecUnpackOp (vecElemProjectCast dflags vcat w) ty arg res+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags [res] (VecInsertOp vcat n w) [v,e,i] = do+ checkVecCompatibility dflags vcat n w+ doVecInsertOp (vecElemInjectCast dflags vcat w) ty v e i res+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecIndexByteArrayOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexByteArrayOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecReadByteArrayOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexByteArrayOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecWriteByteArrayOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doWriteByteArrayOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecIndexOffAddrOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexOffAddrOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecReadOffAddrOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexOffAddrOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecWriteOffAddrOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doWriteOffAddrOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecVmmType vcat n w++emitPrimOp dflags res (VecIndexScalarByteArrayOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexByteArrayOpAs Nothing vecty ty res args+ where+ vecty :: CmmType+ vecty = vecVmmType vcat n w++ ty :: CmmType+ ty = vecCmmCat vcat w++emitPrimOp dflags res (VecReadScalarByteArrayOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexByteArrayOpAs Nothing vecty ty res args+ where+ vecty :: CmmType+ vecty = vecVmmType vcat n w++ ty :: CmmType+ ty = vecCmmCat vcat w++emitPrimOp dflags res (VecWriteScalarByteArrayOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doWriteByteArrayOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecCmmCat vcat w++emitPrimOp dflags res (VecIndexScalarOffAddrOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexOffAddrOpAs Nothing vecty ty res args+ where+ vecty :: CmmType+ vecty = vecVmmType vcat n w++ ty :: CmmType+ ty = vecCmmCat vcat w++emitPrimOp dflags res (VecReadScalarOffAddrOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doIndexOffAddrOpAs Nothing vecty ty res args+ where+ vecty :: CmmType+ vecty = vecVmmType vcat n w++ ty :: CmmType+ ty = vecCmmCat vcat w++emitPrimOp dflags res (VecWriteScalarOffAddrOp vcat n w) args = do+ checkVecCompatibility dflags vcat n w+ doWriteOffAddrOp Nothing ty res args+ where+ ty :: CmmType+ ty = vecCmmCat vcat w++-- Prefetch+emitPrimOp _ [] PrefetchByteArrayOp3 args = doPrefetchByteArrayOp 3 args+emitPrimOp _ [] PrefetchMutableByteArrayOp3 args = doPrefetchMutableByteArrayOp 3 args+emitPrimOp _ [] PrefetchAddrOp3 args = doPrefetchAddrOp 3 args+emitPrimOp _ [] PrefetchValueOp3 args = doPrefetchValueOp 3 args++emitPrimOp _ [] PrefetchByteArrayOp2 args = doPrefetchByteArrayOp 2 args+emitPrimOp _ [] PrefetchMutableByteArrayOp2 args = doPrefetchMutableByteArrayOp 2 args+emitPrimOp _ [] PrefetchAddrOp2 args = doPrefetchAddrOp 2 args+emitPrimOp _ [] PrefetchValueOp2 args = doPrefetchValueOp 2 args++emitPrimOp _ [] PrefetchByteArrayOp1 args = doPrefetchByteArrayOp 1 args+emitPrimOp _ [] PrefetchMutableByteArrayOp1 args = doPrefetchMutableByteArrayOp 1 args+emitPrimOp _ [] PrefetchAddrOp1 args = doPrefetchAddrOp 1 args+emitPrimOp _ [] PrefetchValueOp1 args = doPrefetchValueOp 1 args++emitPrimOp _ [] PrefetchByteArrayOp0 args = doPrefetchByteArrayOp 0 args+emitPrimOp _ [] PrefetchMutableByteArrayOp0 args = doPrefetchMutableByteArrayOp 0 args+emitPrimOp _ [] PrefetchAddrOp0 args = doPrefetchAddrOp 0 args+emitPrimOp _ [] PrefetchValueOp0 args = doPrefetchValueOp 0 args++-- Atomic read-modify-write+emitPrimOp dflags [res] FetchAddByteArrayOp_Int [mba, ix, n] =+ doAtomicRMW res AMO_Add mba ix (bWord dflags) n+emitPrimOp dflags [res] FetchSubByteArrayOp_Int [mba, ix, n] =+ doAtomicRMW res AMO_Sub mba ix (bWord dflags) n+emitPrimOp dflags [res] FetchAndByteArrayOp_Int [mba, ix, n] =+ doAtomicRMW res AMO_And mba ix (bWord dflags) n+emitPrimOp dflags [res] FetchNandByteArrayOp_Int [mba, ix, n] =+ doAtomicRMW res AMO_Nand mba ix (bWord dflags) n+emitPrimOp dflags [res] FetchOrByteArrayOp_Int [mba, ix, n] =+ doAtomicRMW res AMO_Or mba ix (bWord dflags) n+emitPrimOp dflags [res] FetchXorByteArrayOp_Int [mba, ix, n] =+ doAtomicRMW res AMO_Xor mba ix (bWord dflags) n+emitPrimOp dflags [res] AtomicReadByteArrayOp_Int [mba, ix] =+ doAtomicReadByteArray res mba ix (bWord dflags)+emitPrimOp dflags [] AtomicWriteByteArrayOp_Int [mba, ix, val] =+ doAtomicWriteByteArray mba ix (bWord dflags) val+emitPrimOp dflags [res] CasByteArrayOp_Int [mba, ix, old, new] =+ doCasByteArray res mba ix (bWord dflags) old new++-- The rest just translate straightforwardly+emitPrimOp dflags [res] op [arg]+ | nopOp op+ = emitAssign (CmmLocal res) arg++ | Just (mop,rep) <- narrowOp op+ = emitAssign (CmmLocal res) $+ CmmMachOp (mop rep (wordWidth dflags)) [CmmMachOp (mop (wordWidth dflags) rep) [arg]]++emitPrimOp dflags r@[res] op args+ | Just prim <- callishOp op+ = do emitPrimCall r prim args++ | Just mop <- translateOp dflags op+ = let stmt = mkAssign (CmmLocal res) (CmmMachOp mop args) in+ emit stmt++emitPrimOp dflags results op args+ = case callishPrimOpSupported dflags op of+ Left op -> emit $ mkUnsafeCall (PrimTarget op) results args+ Right gen -> gen results args++type GenericOp = [CmmFormal] -> [CmmActual] -> FCode ()++callishPrimOpSupported :: DynFlags -> PrimOp -> Either CallishMachOp GenericOp+callishPrimOpSupported dflags op+ = case op of+ IntQuotRemOp | ncg && (x86ish+ || ppc) -> Left (MO_S_QuotRem (wordWidth dflags))+ | otherwise -> Right (genericIntQuotRemOp dflags)++ WordQuotRemOp | ncg && (x86ish+ || ppc) -> Left (MO_U_QuotRem (wordWidth dflags))+ | otherwise -> Right (genericWordQuotRemOp dflags)++ WordQuotRem2Op | (ncg && (x86ish+ || ppc))+ || llvm -> Left (MO_U_QuotRem2 (wordWidth dflags))+ | otherwise -> Right (genericWordQuotRem2Op dflags)++ WordAdd2Op | (ncg && (x86ish+ || ppc))+ || llvm -> Left (MO_Add2 (wordWidth dflags))+ | otherwise -> Right genericWordAdd2Op++ WordSubCOp | (ncg && (x86ish+ || ppc))+ || llvm -> Left (MO_SubWordC (wordWidth dflags))+ | otherwise -> Right genericWordSubCOp++ IntAddCOp | (ncg && (x86ish+ || ppc))+ || llvm -> Left (MO_AddIntC (wordWidth dflags))+ | otherwise -> Right genericIntAddCOp++ IntSubCOp | (ncg && (x86ish+ || ppc))+ || llvm -> Left (MO_SubIntC (wordWidth dflags))+ | otherwise -> Right genericIntSubCOp++ WordMul2Op | ncg && (x86ish+ || ppc)+ || llvm -> Left (MO_U_Mul2 (wordWidth dflags))+ | otherwise -> Right genericWordMul2Op+ FloatFabsOp | (ncg && x86ish+ || ppc)+ || llvm -> Left MO_F32_Fabs+ | otherwise -> Right $ genericFabsOp W32+ DoubleFabsOp | (ncg && x86ish+ || ppc)+ || llvm -> Left MO_F64_Fabs+ | otherwise -> Right $ genericFabsOp W64++ _ -> pprPanic "emitPrimOp: can't translate PrimOp " (ppr op)+ where+ ncg = case hscTarget dflags of+ HscAsm -> True+ _ -> False+ llvm = case hscTarget dflags of+ HscLlvm -> True+ _ -> False+ x86ish = case platformArch (targetPlatform dflags) of+ ArchX86 -> True+ ArchX86_64 -> True+ _ -> False+ ppc = case platformArch (targetPlatform dflags) of+ ArchPPC -> True+ ArchPPC_64 _ -> True+ _ -> False++genericIntQuotRemOp :: DynFlags -> GenericOp+genericIntQuotRemOp dflags [res_q, res_r] [arg_x, arg_y]+ = emit $ mkAssign (CmmLocal res_q)+ (CmmMachOp (MO_S_Quot (wordWidth dflags)) [arg_x, arg_y]) <*>+ mkAssign (CmmLocal res_r)+ (CmmMachOp (MO_S_Rem (wordWidth dflags)) [arg_x, arg_y])+genericIntQuotRemOp _ _ _ = panic "genericIntQuotRemOp"++genericWordQuotRemOp :: DynFlags -> GenericOp+genericWordQuotRemOp dflags [res_q, res_r] [arg_x, arg_y]+ = emit $ mkAssign (CmmLocal res_q)+ (CmmMachOp (MO_U_Quot (wordWidth dflags)) [arg_x, arg_y]) <*>+ mkAssign (CmmLocal res_r)+ (CmmMachOp (MO_U_Rem (wordWidth dflags)) [arg_x, arg_y])+genericWordQuotRemOp _ _ _ = panic "genericWordQuotRemOp"++genericWordQuotRem2Op :: DynFlags -> GenericOp+genericWordQuotRem2Op dflags [res_q, res_r] [arg_x_high, arg_x_low, arg_y]+ = emit =<< f (widthInBits (wordWidth dflags)) zero arg_x_high arg_x_low+ where ty = cmmExprType dflags arg_x_high+ shl x i = CmmMachOp (MO_Shl (wordWidth dflags)) [x, i]+ shr x i = CmmMachOp (MO_U_Shr (wordWidth dflags)) [x, i]+ or x y = CmmMachOp (MO_Or (wordWidth dflags)) [x, y]+ ge x y = CmmMachOp (MO_U_Ge (wordWidth dflags)) [x, y]+ ne x y = CmmMachOp (MO_Ne (wordWidth dflags)) [x, y]+ minus x y = CmmMachOp (MO_Sub (wordWidth dflags)) [x, y]+ times x y = CmmMachOp (MO_Mul (wordWidth dflags)) [x, y]+ zero = lit 0+ one = lit 1+ negone = lit (fromIntegral (widthInBits (wordWidth dflags)) - 1)+ lit i = CmmLit (CmmInt i (wordWidth dflags))++ f :: Int -> CmmExpr -> CmmExpr -> CmmExpr -> FCode CmmAGraph+ f 0 acc high _ = return (mkAssign (CmmLocal res_q) acc <*>+ mkAssign (CmmLocal res_r) high)+ f i acc high low =+ do roverflowedBit <- newTemp ty+ rhigh' <- newTemp ty+ rhigh'' <- newTemp ty+ rlow' <- newTemp ty+ risge <- newTemp ty+ racc' <- newTemp ty+ let high' = CmmReg (CmmLocal rhigh')+ isge = CmmReg (CmmLocal risge)+ overflowedBit = CmmReg (CmmLocal roverflowedBit)+ let this = catAGraphs+ [mkAssign (CmmLocal roverflowedBit)+ (shr high negone),+ mkAssign (CmmLocal rhigh')+ (or (shl high one) (shr low negone)),+ mkAssign (CmmLocal rlow')+ (shl low one),+ mkAssign (CmmLocal risge)+ (or (overflowedBit `ne` zero)+ (high' `ge` arg_y)),+ mkAssign (CmmLocal rhigh'')+ (high' `minus` (arg_y `times` isge)),+ mkAssign (CmmLocal racc')+ (or (shl acc one) isge)]+ rest <- f (i - 1) (CmmReg (CmmLocal racc'))+ (CmmReg (CmmLocal rhigh''))+ (CmmReg (CmmLocal rlow'))+ return (this <*> rest)+genericWordQuotRem2Op _ _ _ = panic "genericWordQuotRem2Op"++genericWordAdd2Op :: GenericOp+genericWordAdd2Op [res_h, res_l] [arg_x, arg_y]+ = do dflags <- getDynFlags+ r1 <- newTemp (cmmExprType dflags arg_x)+ r2 <- newTemp (cmmExprType dflags arg_x)+ let topHalf x = CmmMachOp (MO_U_Shr (wordWidth dflags)) [x, hww]+ toTopHalf x = CmmMachOp (MO_Shl (wordWidth dflags)) [x, hww]+ bottomHalf x = CmmMachOp (MO_And (wordWidth dflags)) [x, hwm]+ add x y = CmmMachOp (MO_Add (wordWidth dflags)) [x, y]+ or x y = CmmMachOp (MO_Or (wordWidth dflags)) [x, y]+ hww = CmmLit (CmmInt (fromIntegral (widthInBits (halfWordWidth dflags)))+ (wordWidth dflags))+ hwm = CmmLit (CmmInt (halfWordMask dflags) (wordWidth dflags))+ emit $ catAGraphs+ [mkAssign (CmmLocal r1)+ (add (bottomHalf arg_x) (bottomHalf arg_y)),+ mkAssign (CmmLocal r2)+ (add (topHalf (CmmReg (CmmLocal r1)))+ (add (topHalf arg_x) (topHalf arg_y))),+ mkAssign (CmmLocal res_h)+ (topHalf (CmmReg (CmmLocal r2))),+ mkAssign (CmmLocal res_l)+ (or (toTopHalf (CmmReg (CmmLocal r2)))+ (bottomHalf (CmmReg (CmmLocal r1))))]+genericWordAdd2Op _ _ = panic "genericWordAdd2Op"++genericWordSubCOp :: GenericOp+genericWordSubCOp [res_r, res_c] [aa, bb] = do+ dflags <- getDynFlags+ emit $ catAGraphs+ [ -- Put the result into 'res_r'.+ mkAssign (CmmLocal res_r) $+ CmmMachOp (mo_wordSub dflags) [aa, bb]+ -- Set 'res_c' to 1 if 'bb > aa' and to 0 otherwise.+ , mkAssign (CmmLocal res_c) $+ CmmMachOp (mo_wordUGt dflags) [bb, aa]+ ]+genericWordSubCOp _ _ = panic "genericWordSubCOp"++genericIntAddCOp :: GenericOp+genericIntAddCOp [res_r, res_c] [aa, bb]+{-+ With some bit-twiddling, we can define int{Add,Sub}Czh portably in+ C, and without needing any comparisons. This may not be the+ fastest way to do it - if you have better code, please send it! --SDM++ Return : r = a + b, c = 0 if no overflow, 1 on overflow.++ We currently don't make use of the r value if c is != 0 (i.e.+ overflow), we just convert to big integers and try again. This+ could be improved by making r and c the correct values for+ plugging into a new J#.++ { r = ((I_)(a)) + ((I_)(b)); \+ c = ((StgWord)(~(((I_)(a))^((I_)(b))) & (((I_)(a))^r))) \+ >> (BITS_IN (I_) - 1); \+ }+ Wading through the mass of bracketry, it seems to reduce to:+ c = ( (~(a^b)) & (a^r) ) >>unsigned (BITS_IN(I_)-1)++-}+ = do dflags <- getDynFlags+ emit $ catAGraphs [+ mkAssign (CmmLocal res_r) (CmmMachOp (mo_wordAdd dflags) [aa,bb]),+ mkAssign (CmmLocal res_c) $+ CmmMachOp (mo_wordUShr dflags) [+ CmmMachOp (mo_wordAnd dflags) [+ CmmMachOp (mo_wordNot dflags) [CmmMachOp (mo_wordXor dflags) [aa,bb]],+ CmmMachOp (mo_wordXor dflags) [aa, CmmReg (CmmLocal res_r)]+ ],+ mkIntExpr dflags (wORD_SIZE_IN_BITS dflags - 1)+ ]+ ]+genericIntAddCOp _ _ = panic "genericIntAddCOp"++genericIntSubCOp :: GenericOp+genericIntSubCOp [res_r, res_c] [aa, bb]+{- Similarly:+ #define subIntCzh(r,c,a,b) \+ { r = ((I_)(a)) - ((I_)(b)); \+ c = ((StgWord)((((I_)(a))^((I_)(b))) & (((I_)(a))^r))) \+ >> (BITS_IN (I_) - 1); \+ }++ c = ((a^b) & (a^r)) >>unsigned (BITS_IN(I_)-1)+-}+ = do dflags <- getDynFlags+ emit $ catAGraphs [+ mkAssign (CmmLocal res_r) (CmmMachOp (mo_wordSub dflags) [aa,bb]),+ mkAssign (CmmLocal res_c) $+ CmmMachOp (mo_wordUShr dflags) [+ CmmMachOp (mo_wordAnd dflags) [+ CmmMachOp (mo_wordXor dflags) [aa,bb],+ CmmMachOp (mo_wordXor dflags) [aa, CmmReg (CmmLocal res_r)]+ ],+ mkIntExpr dflags (wORD_SIZE_IN_BITS dflags - 1)+ ]+ ]+genericIntSubCOp _ _ = panic "genericIntSubCOp"++genericWordMul2Op :: GenericOp+genericWordMul2Op [res_h, res_l] [arg_x, arg_y]+ = do dflags <- getDynFlags+ let t = cmmExprType dflags arg_x+ xlyl <- liftM CmmLocal $ newTemp t+ xlyh <- liftM CmmLocal $ newTemp t+ xhyl <- liftM CmmLocal $ newTemp t+ r <- liftM CmmLocal $ newTemp t+ -- This generic implementation is very simple and slow. We might+ -- well be able to do better, but for now this at least works.+ let topHalf x = CmmMachOp (MO_U_Shr (wordWidth dflags)) [x, hww]+ toTopHalf x = CmmMachOp (MO_Shl (wordWidth dflags)) [x, hww]+ bottomHalf x = CmmMachOp (MO_And (wordWidth dflags)) [x, hwm]+ add x y = CmmMachOp (MO_Add (wordWidth dflags)) [x, y]+ sum = foldl1 add+ mul x y = CmmMachOp (MO_Mul (wordWidth dflags)) [x, y]+ or x y = CmmMachOp (MO_Or (wordWidth dflags)) [x, y]+ hww = CmmLit (CmmInt (fromIntegral (widthInBits (halfWordWidth dflags)))+ (wordWidth dflags))+ hwm = CmmLit (CmmInt (halfWordMask dflags) (wordWidth dflags))+ emit $ catAGraphs+ [mkAssign xlyl+ (mul (bottomHalf arg_x) (bottomHalf arg_y)),+ mkAssign xlyh+ (mul (bottomHalf arg_x) (topHalf arg_y)),+ mkAssign xhyl+ (mul (topHalf arg_x) (bottomHalf arg_y)),+ mkAssign r+ (sum [topHalf (CmmReg xlyl),+ bottomHalf (CmmReg xhyl),+ bottomHalf (CmmReg xlyh)]),+ mkAssign (CmmLocal res_l)+ (or (bottomHalf (CmmReg xlyl))+ (toTopHalf (CmmReg r))),+ mkAssign (CmmLocal res_h)+ (sum [mul (topHalf arg_x) (topHalf arg_y),+ topHalf (CmmReg xhyl),+ topHalf (CmmReg xlyh),+ topHalf (CmmReg r)])]+genericWordMul2Op _ _ = panic "genericWordMul2Op"++-- This replicates what we had in libraries/base/GHC/Float.hs:+--+-- abs x | x == 0 = 0 -- handles (-0.0)+-- | x > 0 = x+-- | otherwise = negateFloat x+genericFabsOp :: Width -> GenericOp+genericFabsOp w [res_r] [aa]+ = do dflags <- getDynFlags+ let zero = CmmLit (CmmFloat 0 w)++ eq x y = CmmMachOp (MO_F_Eq w) [x, y]+ gt x y = CmmMachOp (MO_F_Gt w) [x, y]++ neg x = CmmMachOp (MO_F_Neg w) [x]++ g1 = catAGraphs [mkAssign (CmmLocal res_r) zero]+ g2 = catAGraphs [mkAssign (CmmLocal res_r) aa]++ res_t <- CmmLocal <$> newTemp (cmmExprType dflags aa)+ let g3 = catAGraphs [mkAssign res_t aa,+ mkAssign (CmmLocal res_r) (neg (CmmReg res_t))]++ g4 <- mkCmmIfThenElse (gt aa zero) g2 g3++ emit =<< mkCmmIfThenElse (eq aa zero) g1 g4++genericFabsOp _ _ _ = panic "genericFabsOp"++-- These PrimOps are NOPs in Cmm++nopOp :: PrimOp -> Bool+nopOp Int2WordOp = True+nopOp Word2IntOp = True+nopOp Int2AddrOp = True+nopOp Addr2IntOp = True+nopOp ChrOp = True -- Int# and Char# are rep'd the same+nopOp OrdOp = True+nopOp _ = False++-- These PrimOps turn into double casts++narrowOp :: PrimOp -> Maybe (Width -> Width -> MachOp, Width)+narrowOp Narrow8IntOp = Just (MO_SS_Conv, W8)+narrowOp Narrow16IntOp = Just (MO_SS_Conv, W16)+narrowOp Narrow32IntOp = Just (MO_SS_Conv, W32)+narrowOp Narrow8WordOp = Just (MO_UU_Conv, W8)+narrowOp Narrow16WordOp = Just (MO_UU_Conv, W16)+narrowOp Narrow32WordOp = Just (MO_UU_Conv, W32)+narrowOp _ = Nothing++-- Native word signless ops++translateOp :: DynFlags -> PrimOp -> Maybe MachOp+translateOp dflags IntAddOp = Just (mo_wordAdd dflags)+translateOp dflags IntSubOp = Just (mo_wordSub dflags)+translateOp dflags WordAddOp = Just (mo_wordAdd dflags)+translateOp dflags WordSubOp = Just (mo_wordSub dflags)+translateOp dflags AddrAddOp = Just (mo_wordAdd dflags)+translateOp dflags AddrSubOp = Just (mo_wordSub dflags)++translateOp dflags IntEqOp = Just (mo_wordEq dflags)+translateOp dflags IntNeOp = Just (mo_wordNe dflags)+translateOp dflags WordEqOp = Just (mo_wordEq dflags)+translateOp dflags WordNeOp = Just (mo_wordNe dflags)+translateOp dflags AddrEqOp = Just (mo_wordEq dflags)+translateOp dflags AddrNeOp = Just (mo_wordNe dflags)++translateOp dflags AndOp = Just (mo_wordAnd dflags)+translateOp dflags OrOp = Just (mo_wordOr dflags)+translateOp dflags XorOp = Just (mo_wordXor dflags)+translateOp dflags NotOp = Just (mo_wordNot dflags)+translateOp dflags SllOp = Just (mo_wordShl dflags)+translateOp dflags SrlOp = Just (mo_wordUShr dflags)++translateOp dflags AddrRemOp = Just (mo_wordURem dflags)++-- Native word signed ops++translateOp dflags IntMulOp = Just (mo_wordMul dflags)+translateOp dflags IntMulMayOfloOp = Just (MO_S_MulMayOflo (wordWidth dflags))+translateOp dflags IntQuotOp = Just (mo_wordSQuot dflags)+translateOp dflags IntRemOp = Just (mo_wordSRem dflags)+translateOp dflags IntNegOp = Just (mo_wordSNeg dflags)+++translateOp dflags IntGeOp = Just (mo_wordSGe dflags)+translateOp dflags IntLeOp = Just (mo_wordSLe dflags)+translateOp dflags IntGtOp = Just (mo_wordSGt dflags)+translateOp dflags IntLtOp = Just (mo_wordSLt dflags)++translateOp dflags AndIOp = Just (mo_wordAnd dflags)+translateOp dflags OrIOp = Just (mo_wordOr dflags)+translateOp dflags XorIOp = Just (mo_wordXor dflags)+translateOp dflags NotIOp = Just (mo_wordNot dflags)+translateOp dflags ISllOp = Just (mo_wordShl dflags)+translateOp dflags ISraOp = Just (mo_wordSShr dflags)+translateOp dflags ISrlOp = Just (mo_wordUShr dflags)++-- Native word unsigned ops++translateOp dflags WordGeOp = Just (mo_wordUGe dflags)+translateOp dflags WordLeOp = Just (mo_wordULe dflags)+translateOp dflags WordGtOp = Just (mo_wordUGt dflags)+translateOp dflags WordLtOp = Just (mo_wordULt dflags)++translateOp dflags WordMulOp = Just (mo_wordMul dflags)+translateOp dflags WordQuotOp = Just (mo_wordUQuot dflags)+translateOp dflags WordRemOp = Just (mo_wordURem dflags)++translateOp dflags AddrGeOp = Just (mo_wordUGe dflags)+translateOp dflags AddrLeOp = Just (mo_wordULe dflags)+translateOp dflags AddrGtOp = Just (mo_wordUGt dflags)+translateOp dflags AddrLtOp = Just (mo_wordULt dflags)++-- Char# ops++translateOp dflags CharEqOp = Just (MO_Eq (wordWidth dflags))+translateOp dflags CharNeOp = Just (MO_Ne (wordWidth dflags))+translateOp dflags CharGeOp = Just (MO_U_Ge (wordWidth dflags))+translateOp dflags CharLeOp = Just (MO_U_Le (wordWidth dflags))+translateOp dflags CharGtOp = Just (MO_U_Gt (wordWidth dflags))+translateOp dflags CharLtOp = Just (MO_U_Lt (wordWidth dflags))++-- Double ops++translateOp _ DoubleEqOp = Just (MO_F_Eq W64)+translateOp _ DoubleNeOp = Just (MO_F_Ne W64)+translateOp _ DoubleGeOp = Just (MO_F_Ge W64)+translateOp _ DoubleLeOp = Just (MO_F_Le W64)+translateOp _ DoubleGtOp = Just (MO_F_Gt W64)+translateOp _ DoubleLtOp = Just (MO_F_Lt W64)++translateOp _ DoubleAddOp = Just (MO_F_Add W64)+translateOp _ DoubleSubOp = Just (MO_F_Sub W64)+translateOp _ DoubleMulOp = Just (MO_F_Mul W64)+translateOp _ DoubleDivOp = Just (MO_F_Quot W64)+translateOp _ DoubleNegOp = Just (MO_F_Neg W64)++-- Float ops++translateOp _ FloatEqOp = Just (MO_F_Eq W32)+translateOp _ FloatNeOp = Just (MO_F_Ne W32)+translateOp _ FloatGeOp = Just (MO_F_Ge W32)+translateOp _ FloatLeOp = Just (MO_F_Le W32)+translateOp _ FloatGtOp = Just (MO_F_Gt W32)+translateOp _ FloatLtOp = Just (MO_F_Lt W32)++translateOp _ FloatAddOp = Just (MO_F_Add W32)+translateOp _ FloatSubOp = Just (MO_F_Sub W32)+translateOp _ FloatMulOp = Just (MO_F_Mul W32)+translateOp _ FloatDivOp = Just (MO_F_Quot W32)+translateOp _ FloatNegOp = Just (MO_F_Neg W32)++-- Vector ops++translateOp _ (VecAddOp FloatVec n w) = Just (MO_VF_Add n w)+translateOp _ (VecSubOp FloatVec n w) = Just (MO_VF_Sub n w)+translateOp _ (VecMulOp FloatVec n w) = Just (MO_VF_Mul n w)+translateOp _ (VecDivOp FloatVec n w) = Just (MO_VF_Quot n w)+translateOp _ (VecNegOp FloatVec n w) = Just (MO_VF_Neg n w)++translateOp _ (VecAddOp IntVec n w) = Just (MO_V_Add n w)+translateOp _ (VecSubOp IntVec n w) = Just (MO_V_Sub n w)+translateOp _ (VecMulOp IntVec n w) = Just (MO_V_Mul n w)+translateOp _ (VecQuotOp IntVec n w) = Just (MO_VS_Quot n w)+translateOp _ (VecRemOp IntVec n w) = Just (MO_VS_Rem n w)+translateOp _ (VecNegOp IntVec n w) = Just (MO_VS_Neg n w)++translateOp _ (VecAddOp WordVec n w) = Just (MO_V_Add n w)+translateOp _ (VecSubOp WordVec n w) = Just (MO_V_Sub n w)+translateOp _ (VecMulOp WordVec n w) = Just (MO_V_Mul n w)+translateOp _ (VecQuotOp WordVec n w) = Just (MO_VU_Quot n w)+translateOp _ (VecRemOp WordVec n w) = Just (MO_VU_Rem n w)++-- Conversions++translateOp dflags Int2DoubleOp = Just (MO_SF_Conv (wordWidth dflags) W64)+translateOp dflags Double2IntOp = Just (MO_FS_Conv W64 (wordWidth dflags))++translateOp dflags Int2FloatOp = Just (MO_SF_Conv (wordWidth dflags) W32)+translateOp dflags Float2IntOp = Just (MO_FS_Conv W32 (wordWidth dflags))++translateOp _ Float2DoubleOp = Just (MO_FF_Conv W32 W64)+translateOp _ Double2FloatOp = Just (MO_FF_Conv W64 W32)++-- Word comparisons masquerading as more exotic things.++translateOp dflags SameMutVarOp = Just (mo_wordEq dflags)+translateOp dflags SameMVarOp = Just (mo_wordEq dflags)+translateOp dflags SameMutableArrayOp = Just (mo_wordEq dflags)+translateOp dflags SameMutableByteArrayOp = Just (mo_wordEq dflags)+translateOp dflags SameMutableArrayArrayOp= Just (mo_wordEq dflags)+translateOp dflags SameSmallMutableArrayOp= Just (mo_wordEq dflags)+translateOp dflags SameTVarOp = Just (mo_wordEq dflags)+translateOp dflags EqStablePtrOp = Just (mo_wordEq dflags)++translateOp _ _ = Nothing++-- These primops are implemented by CallishMachOps, because they sometimes+-- turn into foreign calls depending on the backend.++callishOp :: PrimOp -> Maybe CallishMachOp+callishOp DoublePowerOp = Just MO_F64_Pwr+callishOp DoubleSinOp = Just MO_F64_Sin+callishOp DoubleCosOp = Just MO_F64_Cos+callishOp DoubleTanOp = Just MO_F64_Tan+callishOp DoubleSinhOp = Just MO_F64_Sinh+callishOp DoubleCoshOp = Just MO_F64_Cosh+callishOp DoubleTanhOp = Just MO_F64_Tanh+callishOp DoubleAsinOp = Just MO_F64_Asin+callishOp DoubleAcosOp = Just MO_F64_Acos+callishOp DoubleAtanOp = Just MO_F64_Atan+callishOp DoubleLogOp = Just MO_F64_Log+callishOp DoubleExpOp = Just MO_F64_Exp+callishOp DoubleSqrtOp = Just MO_F64_Sqrt++callishOp FloatPowerOp = Just MO_F32_Pwr+callishOp FloatSinOp = Just MO_F32_Sin+callishOp FloatCosOp = Just MO_F32_Cos+callishOp FloatTanOp = Just MO_F32_Tan+callishOp FloatSinhOp = Just MO_F32_Sinh+callishOp FloatCoshOp = Just MO_F32_Cosh+callishOp FloatTanhOp = Just MO_F32_Tanh+callishOp FloatAsinOp = Just MO_F32_Asin+callishOp FloatAcosOp = Just MO_F32_Acos+callishOp FloatAtanOp = Just MO_F32_Atan+callishOp FloatLogOp = Just MO_F32_Log+callishOp FloatExpOp = Just MO_F32_Exp+callishOp FloatSqrtOp = Just MO_F32_Sqrt++callishOp _ = Nothing++------------------------------------------------------------------------------+-- Helpers for translating various minor variants of array indexing.++doIndexOffAddrOp :: Maybe MachOp+ -> CmmType+ -> [LocalReg]+ -> [CmmExpr]+ -> FCode ()+doIndexOffAddrOp maybe_post_read_cast rep [res] [addr,idx]+ = mkBasicIndexedRead 0 maybe_post_read_cast rep res addr rep idx+doIndexOffAddrOp _ _ _ _+ = panic "StgCmmPrim: doIndexOffAddrOp"++doIndexOffAddrOpAs :: Maybe MachOp+ -> CmmType+ -> CmmType+ -> [LocalReg]+ -> [CmmExpr]+ -> FCode ()+doIndexOffAddrOpAs maybe_post_read_cast rep idx_rep [res] [addr,idx]+ = mkBasicIndexedRead 0 maybe_post_read_cast rep res addr idx_rep idx+doIndexOffAddrOpAs _ _ _ _ _+ = panic "StgCmmPrim: doIndexOffAddrOpAs"++doIndexByteArrayOp :: Maybe MachOp+ -> CmmType+ -> [LocalReg]+ -> [CmmExpr]+ -> FCode ()+doIndexByteArrayOp maybe_post_read_cast rep [res] [addr,idx]+ = do dflags <- getDynFlags+ mkBasicIndexedRead (arrWordsHdrSize dflags) maybe_post_read_cast rep res addr rep idx+doIndexByteArrayOp _ _ _ _+ = panic "StgCmmPrim: doIndexByteArrayOp"++doIndexByteArrayOpAs :: Maybe MachOp+ -> CmmType+ -> CmmType+ -> [LocalReg]+ -> [CmmExpr]+ -> FCode ()+doIndexByteArrayOpAs maybe_post_read_cast rep idx_rep [res] [addr,idx]+ = do dflags <- getDynFlags+ mkBasicIndexedRead (arrWordsHdrSize dflags) maybe_post_read_cast rep res addr idx_rep idx+doIndexByteArrayOpAs _ _ _ _ _+ = panic "StgCmmPrim: doIndexByteArrayOpAs"++doReadPtrArrayOp :: LocalReg+ -> CmmExpr+ -> CmmExpr+ -> FCode ()+doReadPtrArrayOp res addr idx+ = do dflags <- getDynFlags+ mkBasicIndexedRead (arrPtrsHdrSize dflags) Nothing (gcWord dflags) res addr (gcWord dflags) idx++doWriteOffAddrOp :: Maybe MachOp+ -> CmmType+ -> [LocalReg]+ -> [CmmExpr]+ -> FCode ()+doWriteOffAddrOp maybe_pre_write_cast idx_ty [] [addr,idx,val]+ = mkBasicIndexedWrite 0 maybe_pre_write_cast addr idx_ty idx val+doWriteOffAddrOp _ _ _ _+ = panic "StgCmmPrim: doWriteOffAddrOp"++doWriteByteArrayOp :: Maybe MachOp+ -> CmmType+ -> [LocalReg]+ -> [CmmExpr]+ -> FCode ()+doWriteByteArrayOp maybe_pre_write_cast idx_ty [] [addr,idx,val]+ = do dflags <- getDynFlags+ mkBasicIndexedWrite (arrWordsHdrSize dflags) maybe_pre_write_cast addr idx_ty idx val+doWriteByteArrayOp _ _ _ _+ = panic "StgCmmPrim: doWriteByteArrayOp"++doWritePtrArrayOp :: CmmExpr+ -> CmmExpr+ -> CmmExpr+ -> FCode ()+doWritePtrArrayOp addr idx val+ = do dflags <- getDynFlags+ let ty = cmmExprType dflags val+ -- This write barrier is to ensure that the heap writes to the object+ -- referred to by val have happened before we write val into the array.+ -- See #12469 for details.+ emitPrimCall [] MO_WriteBarrier []+ mkBasicIndexedWrite (arrPtrsHdrSize dflags) Nothing addr ty idx val+ emit (setInfo addr (CmmLit (CmmLabel mkMAP_DIRTY_infoLabel)))+ -- the write barrier. We must write a byte into the mark table:+ -- bits8[a + header_size + StgMutArrPtrs_size(a) + x >> N]+ emit $ mkStore (+ cmmOffsetExpr dflags+ (cmmOffsetExprW dflags (cmmOffsetB dflags addr (arrPtrsHdrSize dflags))+ (loadArrPtrsSize dflags addr))+ (CmmMachOp (mo_wordUShr dflags) [idx,+ mkIntExpr dflags (mUT_ARR_PTRS_CARD_BITS dflags)])+ ) (CmmLit (CmmInt 1 W8))++loadArrPtrsSize :: DynFlags -> CmmExpr -> CmmExpr+loadArrPtrsSize dflags addr = CmmLoad (cmmOffsetB dflags addr off) (bWord dflags)+ where off = fixedHdrSize dflags + oFFSET_StgMutArrPtrs_ptrs dflags++mkBasicIndexedRead :: ByteOff -- Initial offset in bytes+ -> Maybe MachOp -- Optional result cast+ -> CmmType -- Type of element we are accessing+ -> LocalReg -- Destination+ -> CmmExpr -- Base address+ -> CmmType -- Type of element by which we are indexing+ -> CmmExpr -- Index+ -> FCode ()+mkBasicIndexedRead off Nothing ty res base idx_ty idx+ = do dflags <- getDynFlags+ emitAssign (CmmLocal res) (cmmLoadIndexOffExpr dflags off ty base idx_ty idx)+mkBasicIndexedRead off (Just cast) ty res base idx_ty idx+ = do dflags <- getDynFlags+ emitAssign (CmmLocal res) (CmmMachOp cast [+ cmmLoadIndexOffExpr dflags off ty base idx_ty idx])++mkBasicIndexedWrite :: ByteOff -- Initial offset in bytes+ -> Maybe MachOp -- Optional value cast+ -> CmmExpr -- Base address+ -> CmmType -- Type of element by which we are indexing+ -> CmmExpr -- Index+ -> CmmExpr -- Value to write+ -> FCode ()+mkBasicIndexedWrite off Nothing base idx_ty idx val+ = do dflags <- getDynFlags+ emitStore (cmmIndexOffExpr dflags off (typeWidth idx_ty) base idx) val+mkBasicIndexedWrite off (Just cast) base idx_ty idx val+ = mkBasicIndexedWrite off Nothing base idx_ty idx (CmmMachOp cast [val])++-- ----------------------------------------------------------------------------+-- Misc utils++cmmIndexOffExpr :: DynFlags+ -> ByteOff -- Initial offset in bytes+ -> Width -- Width of element by which we are indexing+ -> CmmExpr -- Base address+ -> CmmExpr -- Index+ -> CmmExpr+cmmIndexOffExpr dflags off width base idx+ = cmmIndexExpr dflags width (cmmOffsetB dflags base off) idx++cmmLoadIndexOffExpr :: DynFlags+ -> ByteOff -- Initial offset in bytes+ -> CmmType -- Type of element we are accessing+ -> CmmExpr -- Base address+ -> CmmType -- Type of element by which we are indexing+ -> CmmExpr -- Index+ -> CmmExpr+cmmLoadIndexOffExpr dflags off ty base idx_ty idx+ = CmmLoad (cmmIndexOffExpr dflags off (typeWidth idx_ty) base idx) ty++setInfo :: CmmExpr -> CmmExpr -> CmmAGraph+setInfo closure_ptr info_ptr = mkStore closure_ptr info_ptr++------------------------------------------------------------------------------+-- Helpers for translating vector primops.++vecVmmType :: PrimOpVecCat -> Length -> Width -> CmmType+vecVmmType pocat n w = vec n (vecCmmCat pocat w)++vecCmmCat :: PrimOpVecCat -> Width -> CmmType+vecCmmCat IntVec = cmmBits+vecCmmCat WordVec = cmmBits+vecCmmCat FloatVec = cmmFloat++vecElemInjectCast :: DynFlags -> PrimOpVecCat -> Width -> Maybe MachOp+vecElemInjectCast _ FloatVec _ = Nothing+vecElemInjectCast dflags IntVec W8 = Just (mo_WordTo8 dflags)+vecElemInjectCast dflags IntVec W16 = Just (mo_WordTo16 dflags)+vecElemInjectCast dflags IntVec W32 = Just (mo_WordTo32 dflags)+vecElemInjectCast _ IntVec W64 = Nothing+vecElemInjectCast dflags WordVec W8 = Just (mo_WordTo8 dflags)+vecElemInjectCast dflags WordVec W16 = Just (mo_WordTo16 dflags)+vecElemInjectCast dflags WordVec W32 = Just (mo_WordTo32 dflags)+vecElemInjectCast _ WordVec W64 = Nothing+vecElemInjectCast _ _ _ = Nothing++vecElemProjectCast :: DynFlags -> PrimOpVecCat -> Width -> Maybe MachOp+vecElemProjectCast _ FloatVec _ = Nothing+vecElemProjectCast dflags IntVec W8 = Just (mo_s_8ToWord dflags)+vecElemProjectCast dflags IntVec W16 = Just (mo_s_16ToWord dflags)+vecElemProjectCast dflags IntVec W32 = Just (mo_s_32ToWord dflags)+vecElemProjectCast _ IntVec W64 = Nothing+vecElemProjectCast dflags WordVec W8 = Just (mo_u_8ToWord dflags)+vecElemProjectCast dflags WordVec W16 = Just (mo_u_16ToWord dflags)+vecElemProjectCast dflags WordVec W32 = Just (mo_u_32ToWord dflags)+vecElemProjectCast _ WordVec W64 = Nothing+vecElemProjectCast _ _ _ = Nothing++-- Check to make sure that we can generate code for the specified vector type+-- given the current set of dynamic flags.+checkVecCompatibility :: DynFlags -> PrimOpVecCat -> Length -> Width -> FCode ()+checkVecCompatibility dflags vcat l w = do+ when (hscTarget dflags /= HscLlvm) $ do+ sorry $ unlines ["SIMD vector instructions require the LLVM back-end."+ ,"Please use -fllvm."]+ check vecWidth vcat l w+ where+ check :: Width -> PrimOpVecCat -> Length -> Width -> FCode ()+ check W128 FloatVec 4 W32 | not (isSseEnabled dflags) =+ sorry $ "128-bit wide single-precision floating point " +++ "SIMD vector instructions require at least -msse."+ check W128 _ _ _ | not (isSse2Enabled dflags) =+ sorry $ "128-bit wide integer and double precision " +++ "SIMD vector instructions require at least -msse2."+ check W256 FloatVec _ _ | not (isAvxEnabled dflags) =+ sorry $ "256-bit wide floating point " +++ "SIMD vector instructions require at least -mavx."+ check W256 _ _ _ | not (isAvx2Enabled dflags) =+ sorry $ "256-bit wide integer " +++ "SIMD vector instructions require at least -mavx2."+ check W512 _ _ _ | not (isAvx512fEnabled dflags) =+ sorry $ "512-bit wide " +++ "SIMD vector instructions require -mavx512f."+ check _ _ _ _ = return ()++ vecWidth = typeWidth (vecVmmType vcat l w)++------------------------------------------------------------------------------+-- Helpers for translating vector packing and unpacking.++doVecPackOp :: Maybe MachOp -- Cast from element to vector component+ -> CmmType -- Type of vector+ -> CmmExpr -- Initial vector+ -> [CmmExpr] -- Elements+ -> CmmFormal -- Destination for result+ -> FCode ()+doVecPackOp maybe_pre_write_cast ty z es res = do+ dst <- newTemp ty+ emitAssign (CmmLocal dst) z+ vecPack dst es 0+ where+ vecPack :: CmmFormal -> [CmmExpr] -> Int -> FCode ()+ vecPack src [] _ =+ emitAssign (CmmLocal res) (CmmReg (CmmLocal src))++ vecPack src (e : es) i = do+ dst <- newTemp ty+ if isFloatType (vecElemType ty)+ then emitAssign (CmmLocal dst) (CmmMachOp (MO_VF_Insert len wid)+ [CmmReg (CmmLocal src), cast e, iLit])+ else emitAssign (CmmLocal dst) (CmmMachOp (MO_V_Insert len wid)+ [CmmReg (CmmLocal src), cast e, iLit])+ vecPack dst es (i + 1)+ where+ -- vector indices are always 32-bits+ iLit = CmmLit (CmmInt (toInteger i) W32)++ cast :: CmmExpr -> CmmExpr+ cast val = case maybe_pre_write_cast of+ Nothing -> val+ Just cast -> CmmMachOp cast [val]++ len :: Length+ len = vecLength ty++ wid :: Width+ wid = typeWidth (vecElemType ty)++doVecUnpackOp :: Maybe MachOp -- Cast from vector component to element result+ -> CmmType -- Type of vector+ -> CmmExpr -- Vector+ -> [CmmFormal] -- Element results+ -> FCode ()+doVecUnpackOp maybe_post_read_cast ty e res =+ vecUnpack res 0+ where+ vecUnpack :: [CmmFormal] -> Int -> FCode ()+ vecUnpack [] _ =+ return ()++ vecUnpack (r : rs) i = do+ if isFloatType (vecElemType ty)+ then emitAssign (CmmLocal r) (cast (CmmMachOp (MO_VF_Extract len wid)+ [e, iLit]))+ else emitAssign (CmmLocal r) (cast (CmmMachOp (MO_V_Extract len wid)+ [e, iLit]))+ vecUnpack rs (i + 1)+ where+ -- vector indices are always 32-bits+ iLit = CmmLit (CmmInt (toInteger i) W32)++ cast :: CmmExpr -> CmmExpr+ cast val = case maybe_post_read_cast of+ Nothing -> val+ Just cast -> CmmMachOp cast [val]++ len :: Length+ len = vecLength ty++ wid :: Width+ wid = typeWidth (vecElemType ty)++doVecInsertOp :: Maybe MachOp -- Cast from element to vector component+ -> CmmType -- Vector type+ -> CmmExpr -- Source vector+ -> CmmExpr -- Element+ -> CmmExpr -- Index at which to insert element+ -> CmmFormal -- Destination for result+ -> FCode ()+doVecInsertOp maybe_pre_write_cast ty src e idx res = do+ dflags <- getDynFlags+ -- vector indices are always 32-bits+ let idx' :: CmmExpr+ idx' = CmmMachOp (MO_SS_Conv (wordWidth dflags) W32) [idx]+ if isFloatType (vecElemType ty)+ then emitAssign (CmmLocal res) (CmmMachOp (MO_VF_Insert len wid) [src, cast e, idx'])+ else emitAssign (CmmLocal res) (CmmMachOp (MO_V_Insert len wid) [src, cast e, idx'])+ where+ cast :: CmmExpr -> CmmExpr+ cast val = case maybe_pre_write_cast of+ Nothing -> val+ Just cast -> CmmMachOp cast [val]++ len :: Length+ len = vecLength ty++ wid :: Width+ wid = typeWidth (vecElemType ty)++------------------------------------------------------------------------------+-- Helpers for translating prefetching.+++-- | Translate byte array prefetch operations into proper primcalls.+doPrefetchByteArrayOp :: Int+ -> [CmmExpr]+ -> FCode ()+doPrefetchByteArrayOp locality [addr,idx]+ = do dflags <- getDynFlags+ mkBasicPrefetch locality (arrWordsHdrSize dflags) addr idx+doPrefetchByteArrayOp _ _+ = panic "StgCmmPrim: doPrefetchByteArrayOp"++-- | Translate mutable byte array prefetch operations into proper primcalls.+doPrefetchMutableByteArrayOp :: Int+ -> [CmmExpr]+ -> FCode ()+doPrefetchMutableByteArrayOp locality [addr,idx]+ = do dflags <- getDynFlags+ mkBasicPrefetch locality (arrWordsHdrSize dflags) addr idx+doPrefetchMutableByteArrayOp _ _+ = panic "StgCmmPrim: doPrefetchByteArrayOp"++-- | Translate address prefetch operations into proper primcalls.+doPrefetchAddrOp ::Int+ -> [CmmExpr]+ -> FCode ()+doPrefetchAddrOp locality [addr,idx]+ = mkBasicPrefetch locality 0 addr idx+doPrefetchAddrOp _ _+ = panic "StgCmmPrim: doPrefetchAddrOp"++-- | Translate value prefetch operations into proper primcalls.+doPrefetchValueOp :: Int+ -> [CmmExpr]+ -> FCode ()+doPrefetchValueOp locality [addr]+ = do dflags <- getDynFlags+ mkBasicPrefetch locality 0 addr (CmmLit (CmmInt 0 (wordWidth dflags)))+doPrefetchValueOp _ _+ = panic "StgCmmPrim: doPrefetchValueOp"++-- | helper to generate prefetch primcalls+mkBasicPrefetch :: Int -- Locality level 0-3+ -> ByteOff -- Initial offset in bytes+ -> CmmExpr -- Base address+ -> CmmExpr -- Index+ -> FCode ()+mkBasicPrefetch locality off base idx+ = do dflags <- getDynFlags+ emitPrimCall [] (MO_Prefetch_Data locality) [cmmIndexExpr dflags W8 (cmmOffsetB dflags base off) idx]+ return ()++-- ----------------------------------------------------------------------------+-- Allocating byte arrays++-- | Takes a register to return the newly allocated array in and the+-- size of the new array in bytes. Allocates a new+-- 'MutableByteArray#'.+doNewByteArrayOp :: CmmFormal -> ByteOff -> FCode ()+doNewByteArrayOp res_r n = do+ dflags <- getDynFlags++ let info_ptr = mkLblExpr mkArrWords_infoLabel+ rep = arrWordsRep dflags n++ tickyAllocPrim (mkIntExpr dflags (arrWordsHdrSize dflags))+ (mkIntExpr dflags (nonHdrSize dflags rep))+ (zeroExpr dflags)++ let hdr_size = fixedHdrSize dflags++ base <- allocHeapClosure rep info_ptr curCCS+ [ (mkIntExpr dflags n,+ hdr_size + oFFSET_StgArrBytes_bytes dflags)+ ]++ emit $ mkAssign (CmmLocal res_r) base++-- ----------------------------------------------------------------------------+-- Copying byte arrays++-- | Takes a source 'ByteArray#', an offset in the source array, a+-- destination 'MutableByteArray#', an offset into the destination+-- array, and the number of bytes to copy. Copies the given number of+-- bytes from the source array to the destination array.+doCopyByteArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr+ -> FCode ()+doCopyByteArrayOp = emitCopyByteArray copy+ where+ -- Copy data (we assume the arrays aren't overlapping since+ -- they're of different types)+ copy _src _dst dst_p src_p bytes =+ emitMemcpyCall dst_p src_p bytes 1++-- | Takes a source 'MutableByteArray#', an offset in the source+-- array, a destination 'MutableByteArray#', an offset into the+-- destination array, and the number of bytes to copy. Copies the+-- given number of bytes from the source array to the destination+-- array.+doCopyMutableByteArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr+ -> FCode ()+doCopyMutableByteArrayOp = emitCopyByteArray copy+ where+ -- The only time the memory might overlap is when the two arrays+ -- we were provided are the same array!+ -- TODO: Optimize branch for common case of no aliasing.+ copy src dst dst_p src_p bytes = do+ dflags <- getDynFlags+ [moveCall, cpyCall] <- forkAlts [+ getCode $ emitMemmoveCall dst_p src_p bytes 1,+ getCode $ emitMemcpyCall dst_p src_p bytes 1+ ]+ emit =<< mkCmmIfThenElse (cmmEqWord dflags src dst) moveCall cpyCall++emitCopyByteArray :: (CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr+ -> FCode ())+ -> CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr+ -> FCode ()+emitCopyByteArray copy src src_off dst dst_off n = do+ dflags <- getDynFlags+ dst_p <- assignTempE $ cmmOffsetExpr dflags (cmmOffsetB dflags dst (arrWordsHdrSize dflags)) dst_off+ src_p <- assignTempE $ cmmOffsetExpr dflags (cmmOffsetB dflags src (arrWordsHdrSize dflags)) src_off+ copy src dst dst_p src_p n++-- | Takes a source 'ByteArray#', an offset in the source array, a+-- destination 'Addr#', and the number of bytes to copy. Copies the given+-- number of bytes from the source array to the destination memory region.+doCopyByteArrayToAddrOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> FCode ()+doCopyByteArrayToAddrOp src src_off dst_p bytes = do+ -- Use memcpy (we are allowed to assume the arrays aren't overlapping)+ dflags <- getDynFlags+ src_p <- assignTempE $ cmmOffsetExpr dflags (cmmOffsetB dflags src (arrWordsHdrSize dflags)) src_off+ emitMemcpyCall dst_p src_p bytes 1++-- | Takes a source 'MutableByteArray#', an offset in the source array, a+-- destination 'Addr#', and the number of bytes to copy. Copies the given+-- number of bytes from the source array to the destination memory region.+doCopyMutableByteArrayToAddrOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr+ -> FCode ()+doCopyMutableByteArrayToAddrOp = doCopyByteArrayToAddrOp++-- | Takes a source 'Addr#', a destination 'MutableByteArray#', an offset into+-- the destination array, and the number of bytes to copy. Copies the given+-- number of bytes from the source memory region to the destination array.+doCopyAddrToByteArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> FCode ()+doCopyAddrToByteArrayOp src_p dst dst_off bytes = do+ -- Use memcpy (we are allowed to assume the arrays aren't overlapping)+ dflags <- getDynFlags+ dst_p <- assignTempE $ cmmOffsetExpr dflags (cmmOffsetB dflags dst (arrWordsHdrSize dflags)) dst_off+ emitMemcpyCall dst_p src_p bytes 1+++-- ----------------------------------------------------------------------------+-- Setting byte arrays++-- | Takes a 'MutableByteArray#', an offset into the array, a length,+-- and a byte, and sets each of the selected bytes in the array to the+-- character.+doSetByteArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr+ -> FCode ()+doSetByteArrayOp ba off len c+ = do dflags <- getDynFlags+ p <- assignTempE $ cmmOffsetExpr dflags (cmmOffsetB dflags ba (arrWordsHdrSize dflags)) off+ emitMemsetCall p c len 1++-- ----------------------------------------------------------------------------+-- Allocating arrays++-- | Allocate a new array.+doNewArrayOp :: CmmFormal -- ^ return register+ -> SMRep -- ^ representation of the array+ -> CLabel -- ^ info pointer+ -> [(CmmExpr, ByteOff)] -- ^ header payload+ -> WordOff -- ^ array size+ -> CmmExpr -- ^ initial element+ -> FCode ()+doNewArrayOp res_r rep info payload n init = do+ dflags <- getDynFlags++ let info_ptr = mkLblExpr info++ tickyAllocPrim (mkIntExpr dflags (hdrSize dflags rep))+ (mkIntExpr dflags (nonHdrSize dflags rep))+ (zeroExpr dflags)++ base <- allocHeapClosure rep info_ptr curCCS payload++ arr <- CmmLocal `fmap` newTemp (bWord dflags)+ emit $ mkAssign arr base++ -- Initialise all elements of the the array+ p <- assignTemp $ cmmOffsetB dflags (CmmReg arr) (hdrSize dflags rep)+ for <- newBlockId+ emitLabel for+ let loopBody =+ [ mkStore (CmmReg (CmmLocal p)) init+ , mkAssign (CmmLocal p) (cmmOffsetW dflags (CmmReg (CmmLocal p)) 1)+ , mkBranch for ]+ emit =<< mkCmmIfThen+ (cmmULtWord dflags (CmmReg (CmmLocal p))+ (cmmOffsetW dflags (CmmReg arr)+ (hdrSizeW dflags rep + n)))+ (catAGraphs loopBody)++ emit $ mkAssign (CmmLocal res_r) (CmmReg arr)++-- ----------------------------------------------------------------------------+-- Copying pointer arrays++-- EZY: This code has an unusually high amount of assignTemp calls, seen+-- nowhere else in the code generator. This is mostly because these+-- "primitive" ops result in a surprisingly large amount of code. It+-- will likely be worthwhile to optimize what is emitted here, so that+-- our optimization passes don't waste time repeatedly optimizing the+-- same bits of code.++-- More closely imitates 'assignTemp' from the old code generator, which+-- returns a CmmExpr rather than a LocalReg.+assignTempE :: CmmExpr -> FCode CmmExpr+assignTempE e = do+ t <- assignTemp e+ return (CmmReg (CmmLocal t))++-- | Takes a source 'Array#', an offset in the source array, a+-- destination 'MutableArray#', an offset into the destination array,+-- and the number of elements to copy. Copies the given number of+-- elements from the source array to the destination array.+doCopyArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> WordOff+ -> FCode ()+doCopyArrayOp = emitCopyArray copy+ where+ -- Copy data (we assume the arrays aren't overlapping since+ -- they're of different types)+ copy _src _dst dst_p src_p bytes =+ do dflags <- getDynFlags+ emitMemcpyCall dst_p src_p (mkIntExpr dflags bytes)+ (wORD_SIZE dflags)+++-- | Takes a source 'MutableArray#', an offset in the source array, a+-- destination 'MutableArray#', an offset into the destination array,+-- and the number of elements to copy. Copies the given number of+-- elements from the source array to the destination array.+doCopyMutableArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> WordOff+ -> FCode ()+doCopyMutableArrayOp = emitCopyArray copy+ where+ -- The only time the memory might overlap is when the two arrays+ -- we were provided are the same array!+ -- TODO: Optimize branch for common case of no aliasing.+ copy src dst dst_p src_p bytes = do+ dflags <- getDynFlags+ [moveCall, cpyCall] <- forkAlts [+ getCode $ emitMemmoveCall dst_p src_p (mkIntExpr dflags bytes)+ (wORD_SIZE dflags),+ getCode $ emitMemcpyCall dst_p src_p (mkIntExpr dflags bytes)+ (wORD_SIZE dflags)+ ]+ emit =<< mkCmmIfThenElse (cmmEqWord dflags src dst) moveCall cpyCall++emitCopyArray :: (CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> ByteOff+ -> FCode ()) -- ^ copy function+ -> CmmExpr -- ^ source array+ -> CmmExpr -- ^ offset in source array+ -> CmmExpr -- ^ destination array+ -> CmmExpr -- ^ offset in destination array+ -> WordOff -- ^ number of elements to copy+ -> FCode ()+emitCopyArray copy src0 src_off dst0 dst_off0 n = do+ dflags <- getDynFlags+ when (n /= 0) $ do+ -- Passed as arguments (be careful)+ src <- assignTempE src0+ dst <- assignTempE dst0+ dst_off <- assignTempE dst_off0++ -- Set the dirty bit in the header.+ emit (setInfo dst (CmmLit (CmmLabel mkMAP_DIRTY_infoLabel)))++ dst_elems_p <- assignTempE $ cmmOffsetB dflags dst+ (arrPtrsHdrSize dflags)+ dst_p <- assignTempE $ cmmOffsetExprW dflags dst_elems_p dst_off+ src_p <- assignTempE $ cmmOffsetExprW dflags+ (cmmOffsetB dflags src (arrPtrsHdrSize dflags)) src_off+ let bytes = wordsToBytes dflags n++ copy src dst dst_p src_p bytes++ -- The base address of the destination card table+ dst_cards_p <- assignTempE $ cmmOffsetExprW dflags dst_elems_p+ (loadArrPtrsSize dflags dst)++ emitSetCards dst_off dst_cards_p n++doCopySmallArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> WordOff+ -> FCode ()+doCopySmallArrayOp = emitCopySmallArray copy+ where+ -- Copy data (we assume the arrays aren't overlapping since+ -- they're of different types)+ copy _src _dst dst_p src_p bytes =+ do dflags <- getDynFlags+ emitMemcpyCall dst_p src_p (mkIntExpr dflags bytes)+ (wORD_SIZE dflags)+++doCopySmallMutableArrayOp :: CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> WordOff+ -> FCode ()+doCopySmallMutableArrayOp = emitCopySmallArray copy+ where+ -- The only time the memory might overlap is when the two arrays+ -- we were provided are the same array!+ -- TODO: Optimize branch for common case of no aliasing.+ copy src dst dst_p src_p bytes = do+ dflags <- getDynFlags+ [moveCall, cpyCall] <- forkAlts+ [ getCode $ emitMemmoveCall dst_p src_p (mkIntExpr dflags bytes)+ (wORD_SIZE dflags)+ , getCode $ emitMemcpyCall dst_p src_p (mkIntExpr dflags bytes)+ (wORD_SIZE dflags)+ ]+ emit =<< mkCmmIfThenElse (cmmEqWord dflags src dst) moveCall cpyCall++emitCopySmallArray :: (CmmExpr -> CmmExpr -> CmmExpr -> CmmExpr -> ByteOff+ -> FCode ()) -- ^ copy function+ -> CmmExpr -- ^ source array+ -> CmmExpr -- ^ offset in source array+ -> CmmExpr -- ^ destination array+ -> CmmExpr -- ^ offset in destination array+ -> WordOff -- ^ number of elements to copy+ -> FCode ()+emitCopySmallArray copy src0 src_off dst0 dst_off n = do+ dflags <- getDynFlags++ -- Passed as arguments (be careful)+ src <- assignTempE src0+ dst <- assignTempE dst0++ -- Set the dirty bit in the header.+ emit (setInfo dst (CmmLit (CmmLabel mkSMAP_DIRTY_infoLabel)))++ dst_p <- assignTempE $ cmmOffsetExprW dflags+ (cmmOffsetB dflags dst (smallArrPtrsHdrSize dflags)) dst_off+ src_p <- assignTempE $ cmmOffsetExprW dflags+ (cmmOffsetB dflags src (smallArrPtrsHdrSize dflags)) src_off+ let bytes = wordsToBytes dflags n++ copy src dst dst_p src_p bytes++-- | Takes an info table label, a register to return the newly+-- allocated array in, a source array, an offset in the source array,+-- and the number of elements to copy. Allocates a new array and+-- initializes it from the source array.+emitCloneArray :: CLabel -> CmmFormal -> CmmExpr -> CmmExpr -> WordOff+ -> FCode ()+emitCloneArray info_p res_r src src_off n = do+ dflags <- getDynFlags++ let info_ptr = mkLblExpr info_p+ rep = arrPtrsRep dflags n++ tickyAllocPrim (mkIntExpr dflags (arrPtrsHdrSize dflags))+ (mkIntExpr dflags (nonHdrSize dflags rep))+ (zeroExpr dflags)++ let hdr_size = fixedHdrSize dflags++ base <- allocHeapClosure rep info_ptr curCCS+ [ (mkIntExpr dflags n,+ hdr_size + oFFSET_StgMutArrPtrs_ptrs dflags)+ , (mkIntExpr dflags (nonHdrSizeW rep),+ hdr_size + oFFSET_StgMutArrPtrs_size dflags)+ ]++ arr <- CmmLocal `fmap` newTemp (bWord dflags)+ emit $ mkAssign arr base++ dst_p <- assignTempE $ cmmOffsetB dflags (CmmReg arr)+ (arrPtrsHdrSize dflags)+ src_p <- assignTempE $ cmmOffsetExprW dflags src+ (cmmAddWord dflags+ (mkIntExpr dflags (arrPtrsHdrSizeW dflags)) src_off)++ emitMemcpyCall dst_p src_p (mkIntExpr dflags (wordsToBytes dflags n))+ (wORD_SIZE dflags)++ emit $ mkAssign (CmmLocal res_r) (CmmReg arr)++-- | Takes an info table label, a register to return the newly+-- allocated array in, a source array, an offset in the source array,+-- and the number of elements to copy. Allocates a new array and+-- initializes it from the source array.+emitCloneSmallArray :: CLabel -> CmmFormal -> CmmExpr -> CmmExpr -> WordOff+ -> FCode ()+emitCloneSmallArray info_p res_r src src_off n = do+ dflags <- getDynFlags++ let info_ptr = mkLblExpr info_p+ rep = smallArrPtrsRep n++ tickyAllocPrim (mkIntExpr dflags (smallArrPtrsHdrSize dflags))+ (mkIntExpr dflags (nonHdrSize dflags rep))+ (zeroExpr dflags)++ let hdr_size = fixedHdrSize dflags++ base <- allocHeapClosure rep info_ptr curCCS+ [ (mkIntExpr dflags n,+ hdr_size + oFFSET_StgSmallMutArrPtrs_ptrs dflags)+ ]++ arr <- CmmLocal `fmap` newTemp (bWord dflags)+ emit $ mkAssign arr base++ dst_p <- assignTempE $ cmmOffsetB dflags (CmmReg arr)+ (smallArrPtrsHdrSize dflags)+ src_p <- assignTempE $ cmmOffsetExprW dflags src+ (cmmAddWord dflags+ (mkIntExpr dflags (smallArrPtrsHdrSizeW dflags)) src_off)++ emitMemcpyCall dst_p src_p (mkIntExpr dflags (wordsToBytes dflags n))+ (wORD_SIZE dflags)++ emit $ mkAssign (CmmLocal res_r) (CmmReg arr)++-- | Takes and offset in the destination array, the base address of+-- the card table, and the number of elements affected (*not* the+-- number of cards). The number of elements may not be zero.+-- Marks the relevant cards as dirty.+emitSetCards :: CmmExpr -> CmmExpr -> WordOff -> FCode ()+emitSetCards dst_start dst_cards_start n = do+ dflags <- getDynFlags+ start_card <- assignTempE $ cardCmm dflags dst_start+ let end_card = cardCmm dflags+ (cmmSubWord dflags+ (cmmAddWord dflags dst_start (mkIntExpr dflags n))+ (mkIntExpr dflags 1))+ emitMemsetCall (cmmAddWord dflags dst_cards_start start_card)+ (mkIntExpr dflags 1)+ (cmmAddWord dflags (cmmSubWord dflags end_card start_card) (mkIntExpr dflags 1))+ 1 -- no alignment (1 byte)++-- Convert an element index to a card index+cardCmm :: DynFlags -> CmmExpr -> CmmExpr+cardCmm dflags i =+ cmmUShrWord dflags i (mkIntExpr dflags (mUT_ARR_PTRS_CARD_BITS dflags))++------------------------------------------------------------------------------+-- SmallArray PrimOp implementations++doReadSmallPtrArrayOp :: LocalReg+ -> CmmExpr+ -> CmmExpr+ -> FCode ()+doReadSmallPtrArrayOp res addr idx = do+ dflags <- getDynFlags+ mkBasicIndexedRead (smallArrPtrsHdrSize dflags) Nothing (gcWord dflags) res addr+ (gcWord dflags) idx++doWriteSmallPtrArrayOp :: CmmExpr+ -> CmmExpr+ -> CmmExpr+ -> FCode ()+doWriteSmallPtrArrayOp addr idx val = do+ dflags <- getDynFlags+ let ty = cmmExprType dflags val+ mkBasicIndexedWrite (smallArrPtrsHdrSize dflags) Nothing addr ty idx val+ emit (setInfo addr (CmmLit (CmmLabel mkSMAP_DIRTY_infoLabel)))++------------------------------------------------------------------------------+-- Atomic read-modify-write++-- | Emit an atomic modification to a byte array element. The result+-- reg contains that previous value of the element. Implies a full+-- memory barrier.+doAtomicRMW :: LocalReg -- ^ Result reg+ -> AtomicMachOp -- ^ Atomic op (e.g. add)+ -> CmmExpr -- ^ MutableByteArray#+ -> CmmExpr -- ^ Index+ -> CmmType -- ^ Type of element by which we are indexing+ -> CmmExpr -- ^ Op argument (e.g. amount to add)+ -> FCode ()+doAtomicRMW res amop mba idx idx_ty n = do+ dflags <- getDynFlags+ let width = typeWidth idx_ty+ addr = cmmIndexOffExpr dflags (arrWordsHdrSize dflags)+ width mba idx+ emitPrimCall+ [ res ]+ (MO_AtomicRMW width amop)+ [ addr, n ]++-- | Emit an atomic read to a byte array that acts as a memory barrier.+doAtomicReadByteArray+ :: LocalReg -- ^ Result reg+ -> CmmExpr -- ^ MutableByteArray#+ -> CmmExpr -- ^ Index+ -> CmmType -- ^ Type of element by which we are indexing+ -> FCode ()+doAtomicReadByteArray res mba idx idx_ty = do+ dflags <- getDynFlags+ let width = typeWidth idx_ty+ addr = cmmIndexOffExpr dflags (arrWordsHdrSize dflags)+ width mba idx+ emitPrimCall+ [ res ]+ (MO_AtomicRead width)+ [ addr ]++-- | Emit an atomic write to a byte array that acts as a memory barrier.+doAtomicWriteByteArray+ :: CmmExpr -- ^ MutableByteArray#+ -> CmmExpr -- ^ Index+ -> CmmType -- ^ Type of element by which we are indexing+ -> CmmExpr -- ^ Value to write+ -> FCode ()+doAtomicWriteByteArray mba idx idx_ty val = do+ dflags <- getDynFlags+ let width = typeWidth idx_ty+ addr = cmmIndexOffExpr dflags (arrWordsHdrSize dflags)+ width mba idx+ emitPrimCall+ [ {- no results -} ]+ (MO_AtomicWrite width)+ [ addr, val ]++doCasByteArray+ :: LocalReg -- ^ Result reg+ -> CmmExpr -- ^ MutableByteArray#+ -> CmmExpr -- ^ Index+ -> CmmType -- ^ Type of element by which we are indexing+ -> CmmExpr -- ^ Old value+ -> CmmExpr -- ^ New value+ -> FCode ()+doCasByteArray res mba idx idx_ty old new = do+ dflags <- getDynFlags+ let width = (typeWidth idx_ty)+ addr = cmmIndexOffExpr dflags (arrWordsHdrSize dflags)+ width mba idx+ emitPrimCall+ [ res ]+ (MO_Cmpxchg width)+ [ addr, old, new ]++------------------------------------------------------------------------------+-- Helpers for emitting function calls++-- | Emit a call to @memcpy@.+emitMemcpyCall :: CmmExpr -> CmmExpr -> CmmExpr -> Int -> FCode ()+emitMemcpyCall dst src n align = do+ emitPrimCall+ [ {-no results-} ]+ (MO_Memcpy align)+ [ dst, src, n ]++-- | Emit a call to @memmove@.+emitMemmoveCall :: CmmExpr -> CmmExpr -> CmmExpr -> Int -> FCode ()+emitMemmoveCall dst src n align = do+ emitPrimCall+ [ {- no results -} ]+ (MO_Memmove align)+ [ dst, src, n ]++-- | Emit a call to @memset@. The second argument must fit inside an+-- unsigned char.+emitMemsetCall :: CmmExpr -> CmmExpr -> CmmExpr -> Int -> FCode ()+emitMemsetCall dst c n align = do+ emitPrimCall+ [ {- no results -} ]+ (MO_Memset align)+ [ dst, c, n ]++emitBSwapCall :: LocalReg -> CmmExpr -> Width -> FCode ()+emitBSwapCall res x width = do+ emitPrimCall+ [ res ]+ (MO_BSwap width)+ [ x ]++emitPopCntCall :: LocalReg -> CmmExpr -> Width -> FCode ()+emitPopCntCall res x width = do+ emitPrimCall+ [ res ]+ (MO_PopCnt width)+ [ x ]++emitClzCall :: LocalReg -> CmmExpr -> Width -> FCode ()+emitClzCall res x width = do+ emitPrimCall+ [ res ]+ (MO_Clz width)+ [ x ]++emitCtzCall :: LocalReg -> CmmExpr -> Width -> FCode ()+emitCtzCall res x width = do+ emitPrimCall+ [ res ]+ (MO_Ctz width)+ [ x ]
+ codeGen/StgCmmProf.hs view
@@ -0,0 +1,366 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Code generation for profiling+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmProf (+ initCostCentres, ccType, ccsType,+ mkCCostCentre, mkCCostCentreStack,++ -- Cost-centre Profiling+ dynProfHdr, profDynAlloc, profAlloc, staticProfHdr, initUpdFrameProf,+ enterCostCentreThunk, enterCostCentreFun,+ costCentreFrom,+ curCCS, storeCurCCS,+ emitSetCCC,++ saveCurrentCostCentre, restoreCurrentCostCentre,++ -- Lag/drag/void stuff+ ldvEnter, ldvEnterClosure, ldvRecordCreate+ ) where++#include "HsVersions.h"++import StgCmmClosure+import StgCmmUtils+import StgCmmMonad+import SMRep++import MkGraph+import Cmm+import CmmUtils+import CLabel++import qualified Module+import CostCentre+import DynFlags+import FastString+import Module+import Outputable++import Control.Monad+import Data.Char (ord)++-----------------------------------------------------------------------------+--+-- Cost-centre-stack Profiling+--+-----------------------------------------------------------------------------++-- Expression representing the current cost centre stack+ccsType :: DynFlags -> CmmType -- Type of a cost-centre stack+ccsType = bWord++ccType :: DynFlags -> CmmType -- Type of a cost centre+ccType = bWord++curCCS :: CmmExpr+curCCS = CmmReg (CmmGlobal CCCS)++storeCurCCS :: CmmExpr -> CmmAGraph+storeCurCCS e = mkAssign (CmmGlobal CCCS) e++mkCCostCentre :: CostCentre -> CmmLit+mkCCostCentre cc = CmmLabel (mkCCLabel cc)++mkCCostCentreStack :: CostCentreStack -> CmmLit+mkCCostCentreStack ccs = CmmLabel (mkCCSLabel ccs)++costCentreFrom :: DynFlags+ -> CmmExpr -- A closure pointer+ -> CmmExpr -- The cost centre from that closure+costCentreFrom dflags cl = CmmLoad (cmmOffsetB dflags cl (oFFSET_StgHeader_ccs dflags)) (ccsType dflags)++-- | The profiling header words in a static closure+staticProfHdr :: DynFlags -> CostCentreStack -> [CmmLit]+staticProfHdr dflags ccs+ = ifProfilingL dflags [mkCCostCentreStack ccs, staticLdvInit dflags]++-- | Profiling header words in a dynamic closure+dynProfHdr :: DynFlags -> CmmExpr -> [CmmExpr]+dynProfHdr dflags ccs = ifProfilingL dflags [ccs, dynLdvInit dflags]++-- | Initialise the profiling field of an update frame+initUpdFrameProf :: CmmExpr -> FCode ()+initUpdFrameProf frame+ = ifProfiling $ -- frame->header.prof.ccs = CCCS+ do dflags <- getDynFlags+ emitStore (cmmOffset dflags frame (oFFSET_StgHeader_ccs dflags)) curCCS+ -- frame->header.prof.hp.rs = NULL (or frame-header.prof.hp.ldvw = 0)+ -- is unnecessary because it is not used anyhow.++---------------------------------------------------------------------------+-- Saving and restoring the current cost centre+---------------------------------------------------------------------------++{- Note [Saving the current cost centre]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The current cost centre is like a global register. Like other+global registers, it's a caller-saves one. But consider+ case (f x) of (p,q) -> rhs+Since 'f' may set the cost centre, we must restore it+before resuming rhs. So we want code like this:+ local_cc = CCC -- save+ r = f( x )+ CCC = local_cc -- restore+That is, we explicitly "save" the current cost centre in+a LocalReg, local_cc; and restore it after the call. The+C-- infrastructure will arrange to save local_cc across the+call.++The same goes for join points;+ let j x = join-stuff+ in blah-blah+We want this kind of code:+ local_cc = CCC -- save+ blah-blah+ J:+ CCC = local_cc -- restore+-}++saveCurrentCostCentre :: FCode (Maybe LocalReg)+ -- Returns Nothing if profiling is off+saveCurrentCostCentre+ = do dflags <- getDynFlags+ if not (gopt Opt_SccProfilingOn dflags)+ then return Nothing+ else do local_cc <- newTemp (ccType dflags)+ emitAssign (CmmLocal local_cc) curCCS+ return (Just local_cc)++restoreCurrentCostCentre :: Maybe LocalReg -> FCode ()+restoreCurrentCostCentre Nothing+ = return ()+restoreCurrentCostCentre (Just local_cc)+ = emit (storeCurCCS (CmmReg (CmmLocal local_cc)))+++-------------------------------------------------------------------------------+-- Recording allocation in a cost centre+-------------------------------------------------------------------------------++-- | Record the allocation of a closure. The CmmExpr is the cost+-- centre stack to which to attribute the allocation.+profDynAlloc :: SMRep -> CmmExpr -> FCode ()+profDynAlloc rep ccs+ = ifProfiling $+ do dflags <- getDynFlags+ profAlloc (mkIntExpr dflags (heapClosureSizeW dflags rep)) ccs++-- | Record the allocation of a closure (size is given by a CmmExpr)+-- The size must be in words, because the allocation counter in a CCS counts+-- in words.+profAlloc :: CmmExpr -> CmmExpr -> FCode ()+profAlloc words ccs+ = ifProfiling $+ do dflags <- getDynFlags+ let alloc_rep = rEP_CostCentreStack_mem_alloc dflags+ emit (addToMemE alloc_rep+ (cmmOffsetB dflags ccs (oFFSET_CostCentreStack_mem_alloc dflags))+ (CmmMachOp (MO_UU_Conv (wordWidth dflags) (typeWidth alloc_rep)) $+ [CmmMachOp (mo_wordSub dflags) [words,+ mkIntExpr dflags (profHdrSize dflags)]]))+ -- subtract the "profiling overhead", which is the+ -- profiling header in a closure.++-- -----------------------------------------------------------------------+-- Setting the current cost centre on entry to a closure++enterCostCentreThunk :: CmmExpr -> FCode ()+enterCostCentreThunk closure =+ ifProfiling $ do+ dflags <- getDynFlags+ emit $ storeCurCCS (costCentreFrom dflags closure)++enterCostCentreFun :: CostCentreStack -> CmmExpr -> FCode ()+enterCostCentreFun ccs closure =+ ifProfiling $ do+ if isCurrentCCS ccs+ then do dflags <- getDynFlags+ emitRtsCall rtsUnitId (fsLit "enterFunCCS")+ [(CmmReg (CmmGlobal BaseReg), AddrHint),+ (costCentreFrom dflags closure, AddrHint)] False+ else return () -- top-level function, nothing to do++ifProfiling :: FCode () -> FCode ()+ifProfiling code+ = do dflags <- getDynFlags+ if gopt Opt_SccProfilingOn dflags+ then code+ else return ()++ifProfilingL :: DynFlags -> [a] -> [a]+ifProfilingL dflags xs+ | gopt Opt_SccProfilingOn dflags = xs+ | otherwise = []+++---------------------------------------------------------------+-- Initialising Cost Centres & CCSs+---------------------------------------------------------------++initCostCentres :: CollectedCCs -> FCode ()+-- Emit the declarations+initCostCentres (local_CCs, ___extern_CCs, singleton_CCSs)+ = do dflags <- getDynFlags+ when (gopt Opt_SccProfilingOn dflags) $+ do mapM_ emitCostCentreDecl local_CCs+ mapM_ emitCostCentreStackDecl singleton_CCSs+++emitCostCentreDecl :: CostCentre -> FCode ()+emitCostCentreDecl cc = do+ { dflags <- getDynFlags+ ; let is_caf | isCafCC cc = mkIntCLit dflags (ord 'c') -- 'c' == is a CAF+ | otherwise = zero dflags+ -- NB. bytesFS: we want the UTF-8 bytes here (#5559)+ ; label <- newByteStringCLit (bytesFS $ costCentreUserNameFS cc)+ ; modl <- newByteStringCLit (bytesFS $ Module.moduleNameFS+ $ Module.moduleName+ $ cc_mod cc)+ ; loc <- newByteStringCLit $ bytesFS $ mkFastString $+ showPpr dflags (costCentreSrcSpan cc)+ -- XXX going via FastString to get UTF-8 encoding is silly+ ; let+ lits = [ zero dflags, -- StgInt ccID,+ label, -- char *label,+ modl, -- char *module,+ loc, -- char *srcloc,+ zero64, -- StgWord64 mem_alloc+ zero dflags, -- StgWord time_ticks+ is_caf, -- StgInt is_caf+ zero dflags -- struct _CostCentre *link+ ]+ ; emitDataLits (mkCCLabel cc) lits+ }++emitCostCentreStackDecl :: CostCentreStack -> FCode ()+emitCostCentreStackDecl ccs+ = case maybeSingletonCCS ccs of+ Just cc ->+ do dflags <- getDynFlags+ let mk_lits cc = zero dflags :+ mkCCostCentre cc :+ replicate (sizeof_ccs_words dflags - 2) (zero dflags)+ -- Note: to avoid making any assumptions about how the+ -- C compiler (that compiles the RTS, in particular) does+ -- layouts of structs containing long-longs, simply+ -- pad out the struct with zero words until we hit the+ -- size of the overall struct (which we get via DerivedConstants.h)+ emitDataLits (mkCCSLabel ccs) (mk_lits cc)+ Nothing -> pprPanic "emitCostCentreStackDecl" (ppr ccs)++zero :: DynFlags -> CmmLit+zero dflags = mkIntCLit dflags 0+zero64 :: CmmLit+zero64 = CmmInt 0 W64++sizeof_ccs_words :: DynFlags -> Int+sizeof_ccs_words dflags+ -- round up to the next word.+ | ms == 0 = ws+ | otherwise = ws + 1+ where+ (ws,ms) = sIZEOF_CostCentreStack dflags `divMod` wORD_SIZE dflags++-- ---------------------------------------------------------------------------+-- Set the current cost centre stack++emitSetCCC :: CostCentre -> Bool -> Bool -> FCode ()+emitSetCCC cc tick push+ = do dflags <- getDynFlags+ if not (gopt Opt_SccProfilingOn dflags)+ then return ()+ else do tmp <- newTemp (ccsType dflags)+ pushCostCentre tmp curCCS cc+ when tick $ emit (bumpSccCount dflags (CmmReg (CmmLocal tmp)))+ when push $ emit (storeCurCCS (CmmReg (CmmLocal tmp)))++pushCostCentre :: LocalReg -> CmmExpr -> CostCentre -> FCode ()+pushCostCentre result ccs cc+ = emitRtsCallWithResult result AddrHint+ rtsUnitId+ (fsLit "pushCostCentre") [(ccs,AddrHint),+ (CmmLit (mkCCostCentre cc), AddrHint)]+ False++bumpSccCount :: DynFlags -> CmmExpr -> CmmAGraph+bumpSccCount dflags ccs+ = addToMem (rEP_CostCentreStack_scc_count dflags)+ (cmmOffsetB dflags ccs (oFFSET_CostCentreStack_scc_count dflags)) 1++-----------------------------------------------------------------------------+--+-- Lag/drag/void stuff+--+-----------------------------------------------------------------------------++--+-- Initial value for the LDV field in a static closure+--+staticLdvInit :: DynFlags -> CmmLit+staticLdvInit = zeroCLit++--+-- Initial value of the LDV field in a dynamic closure+--+dynLdvInit :: DynFlags -> CmmExpr+dynLdvInit dflags = -- (era << LDV_SHIFT) | LDV_STATE_CREATE+ CmmMachOp (mo_wordOr dflags) [+ CmmMachOp (mo_wordShl dflags) [loadEra dflags, mkIntExpr dflags (lDV_SHIFT dflags)],+ CmmLit (mkWordCLit dflags (iLDV_STATE_CREATE dflags))+ ]++--+-- Initialise the LDV word of a new closure+--+ldvRecordCreate :: CmmExpr -> FCode ()+ldvRecordCreate closure = do+ dflags <- getDynFlags+ emit $ mkStore (ldvWord dflags closure) (dynLdvInit dflags)++--+-- | Called when a closure is entered, marks the closure as having+-- been "used". The closure is not an "inherently used" one. The+-- closure is not @IND@ because that is not considered for LDV profiling.+--+ldvEnterClosure :: ClosureInfo -> CmmReg -> FCode ()+ldvEnterClosure closure_info node_reg = do+ dflags <- getDynFlags+ let tag = funTag dflags closure_info+ -- don't forget to substract node's tag+ ldvEnter (cmmOffsetB dflags (CmmReg node_reg) (-tag))++ldvEnter :: CmmExpr -> FCode ()+-- Argument is a closure pointer+ldvEnter cl_ptr = do+ dflags <- getDynFlags+ let -- don't forget to substract node's tag+ ldv_wd = ldvWord dflags cl_ptr+ new_ldv_wd = cmmOrWord dflags (cmmAndWord dflags (CmmLoad ldv_wd (bWord dflags))+ (CmmLit (mkWordCLit dflags (iLDV_CREATE_MASK dflags))))+ (cmmOrWord dflags (loadEra dflags) (CmmLit (mkWordCLit dflags (iLDV_STATE_USE dflags))))+ ifProfiling $+ -- if (era > 0) {+ -- LDVW((c)) = (LDVW((c)) & LDV_CREATE_MASK) |+ -- era | LDV_STATE_USE }+ emit =<< mkCmmIfThenElse (CmmMachOp (mo_wordUGt dflags) [loadEra dflags, CmmLit (zeroCLit dflags)])+ (mkStore ldv_wd new_ldv_wd)+ mkNop++loadEra :: DynFlags -> CmmExpr+loadEra dflags = CmmMachOp (MO_UU_Conv (cIntWidth dflags) (wordWidth dflags))+ [CmmLoad (mkLblExpr (mkCmmDataLabel rtsUnitId (fsLit "era")))+ (cInt dflags)]++ldvWord :: DynFlags -> CmmExpr -> CmmExpr+-- Takes the address of a closure, and returns+-- the address of the LDV word in the closure+ldvWord dflags closure_ptr+ = cmmOffsetB dflags closure_ptr (oFFSET_StgHeader_ldvw dflags)
+ codeGen/StgCmmTicky.hs view
@@ -0,0 +1,675 @@+{-# LANGUAGE BangPatterns, CPP #-}++-----------------------------------------------------------------------------+--+-- Code generation for ticky-ticky profiling+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++{- OVERVIEW: ticky ticky profiling++Please see+http://ghc.haskell.org/trac/ghc/wiki/Debugging/TickyTicky and also+edit it and the rest of this comment to keep them up-to-date if you+change ticky-ticky. Thanks!++ *** All allocation ticky numbers are in bytes. ***++Some of the relevant source files:++ ***not necessarily an exhaustive list***++ * some codeGen/ modules import this one++ * this module imports cmm/CLabel.hs to manage labels++ * cmm/CmmParse.y expands some macros using generators defined in+ this module++ * includes/stg/Ticky.h declares all of the global counters++ * includes/rts/Ticky.h declares the C data type for an+ STG-declaration's counters++ * some macros defined in includes/Cmm.h (and used within the RTS's+ CMM code) update the global ticky counters++ * at the end of execution rts/Ticky.c generates the final report+ +RTS -r<report-file> -RTS++The rts/Ticky.c function that generates the report includes an+STG-declaration's ticky counters if++ * that declaration was entered, or++ * it was allocated (if -ticky-allocd)++On either of those events, the counter is "registered" by adding it to+a linked list; cf the CMM generated by registerTickyCtr.++Ticky-ticky profiling has evolved over many years. Many of the+counters from its most sophisticated days are no longer+active/accurate. As the RTS has changed, sometimes the ticky code for+relevant counters was not accordingly updated. Unfortunately, neither+were the comments.++As of March 2013, there still exist deprecated code and comments in+the code generator as well as the RTS because:++ * I don't know what is out-of-date versus merely commented out for+ momentary convenience, and++ * someone else might know how to repair it!++-}++module StgCmmTicky (+ withNewTickyCounterFun,+ withNewTickyCounterLNE,+ withNewTickyCounterThunk,+ withNewTickyCounterStdThunk,+ withNewTickyCounterCon,++ tickyDynAlloc,+ tickyAllocHeap,++ tickyAllocPrim,+ tickyAllocThunk,+ tickyAllocPAP,+ tickyHeapCheck,+ tickyStackCheck,++ tickyUnknownCall, tickyDirectCall,++ tickyPushUpdateFrame,+ tickyUpdateFrameOmitted,++ tickyEnterDynCon,+ tickyEnterStaticCon,+ tickyEnterViaNode,++ tickyEnterFun,+ tickyEnterThunk, tickyEnterStdThunk, -- dynamic non-value+ -- thunks only+ tickyEnterLNE,++ tickyUpdateBhCaf,+ tickyBlackHole,+ tickyUnboxedTupleReturn,+ tickyReturnOldCon, tickyReturnNewCon,++ tickyKnownCallTooFewArgs, tickyKnownCallExact, tickyKnownCallExtraArgs,+ tickySlowCall, tickySlowCallPat,+ ) where++#include "HsVersions.h"++import StgCmmArgRep ( slowCallPattern , toArgRep , argRepString )+import StgCmmClosure+import StgCmmUtils+import StgCmmMonad++import StgSyn+import CmmExpr+import MkGraph+import CmmUtils+import CLabel+import SMRep++import Module+import Name+import Id+import BasicTypes+import FastString+import Outputable++import DynFlags++-- Turgid imports for showTypeCategory+import PrelNames+import TcType+import Type+import TyCon++import Data.Maybe+import qualified Data.Char+import Control.Monad ( unless, when )++-----------------------------------------------------------------------------+--+-- Ticky-ticky profiling+--+-----------------------------------------------------------------------------++data TickyClosureType+ = TickyFun+ Bool -- True <-> single entry+ | TickyCon+ | TickyThunk+ Bool -- True <-> updateable+ Bool -- True <-> standard thunk (AP or selector), has no entry counter+ | TickyLNE++withNewTickyCounterFun :: Bool -> Name -> [NonVoid Id] -> FCode a -> FCode a+withNewTickyCounterFun single_entry = withNewTickyCounter (TickyFun single_entry)++withNewTickyCounterLNE :: Name -> [NonVoid Id] -> FCode a -> FCode a+withNewTickyCounterLNE nm args code = do+ b <- tickyLNEIsOn+ if not b then code else withNewTickyCounter TickyLNE nm args code++withNewTickyCounterThunk+ :: Bool -- ^ static+ -> Bool -- ^ updateable+ -> Name+ -> FCode a+ -> FCode a+withNewTickyCounterThunk isStatic isUpdatable name code = do+ b <- tickyDynThunkIsOn+ if isStatic || not b -- ignore static thunks+ then code+ else withNewTickyCounter (TickyThunk isUpdatable False) name [] code++withNewTickyCounterStdThunk+ :: Bool -- ^ updateable+ -> Name+ -> FCode a+ -> FCode a+withNewTickyCounterStdThunk isUpdatable name code = do+ b <- tickyDynThunkIsOn+ if not b+ then code+ else withNewTickyCounter (TickyThunk isUpdatable True) name [] code++withNewTickyCounterCon+ :: Name+ -> FCode a+ -> FCode a+withNewTickyCounterCon name code = do+ b <- tickyDynThunkIsOn+ if not b+ then code+ else withNewTickyCounter TickyCon name [] code++-- args does not include the void arguments+withNewTickyCounter :: TickyClosureType -> Name -> [NonVoid Id] -> FCode a -> FCode a+withNewTickyCounter cloType name args m = do+ lbl <- emitTickyCounter cloType name args+ setTickyCtrLabel lbl m++emitTickyCounter :: TickyClosureType -> Name -> [NonVoid Id] -> FCode CLabel+emitTickyCounter cloType name args+ = let ctr_lbl = mkRednCountsLabel name in+ (>> return ctr_lbl) $+ ifTicky $ do+ { dflags <- getDynFlags+ ; parent <- getTickyCtrLabel+ ; mod_name <- getModuleName++ -- When printing the name of a thing in a ticky file, we+ -- want to give the module name even for *local* things. We+ -- print just "x (M)" rather that "M.x" to distinguish them+ -- from the global kind.+ ; let ppr_for_ticky_name :: SDoc+ ppr_for_ticky_name =+ let n = ppr name+ ext = case cloType of+ TickyFun single_entry -> parens $ hcat $ punctuate comma $+ [text "fun"] ++ [text "se"|single_entry]+ TickyCon -> parens (text "con")+ TickyThunk upd std -> parens $ hcat $ punctuate comma $+ [text "thk"] ++ [text "se"|not upd] ++ [text "std"|std]+ TickyLNE | isInternalName name -> parens (text "LNE")+ | otherwise -> panic "emitTickyCounter: how is this an external LNE?"+ p = case hasHaskellName parent of+ -- NB the default "top" ticky ctr does not+ -- have a Haskell name+ Just pname -> text "in" <+> ppr (nameUnique pname)+ _ -> empty+ in if isInternalName name+ then n <+> parens (ppr mod_name) <+> ext <+> p+ else n <+> ext <+> p++ ; fun_descr_lit <- newStringCLit $ showSDocDebug dflags ppr_for_ticky_name+ ; arg_descr_lit <- newStringCLit $ map (showTypeCategory . idType . fromNonVoid) args+ ; emitDataLits ctr_lbl+ -- Must match layout of includes/rts/Ticky.h's StgEntCounter+ --+ -- krc: note that all the fields are I32 now; some were I16+ -- before, but the code generator wasn't handling that+ -- properly and it led to chaos, panic and disorder.+ [ mkIntCLit dflags 0, -- registered?+ mkIntCLit dflags (length args), -- Arity+ mkIntCLit dflags 0, -- Heap allocated for this thing+ fun_descr_lit,+ arg_descr_lit,+ zeroCLit dflags, -- Entries into this thing+ zeroCLit dflags, -- Heap allocated by this thing+ zeroCLit dflags -- Link to next StgEntCounter+ ]+ }++-- -----------------------------------------------------------------------------+-- Ticky stack frames++tickyPushUpdateFrame, tickyUpdateFrameOmitted :: FCode ()+tickyPushUpdateFrame = ifTicky $ bumpTickyCounter (fsLit "UPDF_PUSHED_ctr")+tickyUpdateFrameOmitted = ifTicky $ bumpTickyCounter (fsLit "UPDF_OMITTED_ctr")++-- -----------------------------------------------------------------------------+-- Ticky entries++-- NB the name-specific entries are only available for names that have+-- dedicated Cmm code. As far as I know, this just rules out+-- constructor thunks. For them, there is no CMM code block to put the+-- bump of name-specific ticky counter into. On the other hand, we can+-- still track allocation their allocation.++tickyEnterDynCon, tickyEnterStaticCon, tickyEnterViaNode :: FCode ()+tickyEnterDynCon = ifTicky $ bumpTickyCounter (fsLit "ENT_DYN_CON_ctr")+tickyEnterStaticCon = ifTicky $ bumpTickyCounter (fsLit "ENT_STATIC_CON_ctr")+tickyEnterViaNode = ifTicky $ bumpTickyCounter (fsLit "ENT_VIA_NODE_ctr")++tickyEnterThunk :: ClosureInfo -> FCode ()+tickyEnterThunk cl_info+ = ifTicky $ do+ { bumpTickyCounter ctr+ ; unless static $ do+ ticky_ctr_lbl <- getTickyCtrLabel+ registerTickyCtrAtEntryDyn ticky_ctr_lbl+ bumpTickyEntryCount ticky_ctr_lbl }+ where+ updatable = closureSingleEntry cl_info+ static = isStaticClosure cl_info++ ctr | static = if updatable then fsLit "ENT_STATIC_THK_SINGLE_ctr"+ else fsLit "ENT_STATIC_THK_MANY_ctr"+ | otherwise = if updatable then fsLit "ENT_DYN_THK_SINGLE_ctr"+ else fsLit "ENT_DYN_THK_MANY_ctr"++tickyEnterStdThunk :: ClosureInfo -> FCode ()+tickyEnterStdThunk = tickyEnterThunk++tickyBlackHole :: Bool{-updatable-} -> FCode ()+tickyBlackHole updatable+ = ifTicky (bumpTickyCounter ctr)+ where+ ctr | updatable = (fsLit "UPD_BH_SINGLE_ENTRY_ctr")+ | otherwise = (fsLit "UPD_BH_UPDATABLE_ctr")++tickyUpdateBhCaf :: ClosureInfo -> FCode ()+tickyUpdateBhCaf cl_info+ = ifTicky (bumpTickyCounter ctr)+ where+ ctr | closureUpdReqd cl_info = (fsLit "UPD_CAF_BH_SINGLE_ENTRY_ctr")+ | otherwise = (fsLit "UPD_CAF_BH_UPDATABLE_ctr")++tickyEnterFun :: ClosureInfo -> FCode ()+tickyEnterFun cl_info = ifTicky $ do+ ctr_lbl <- getTickyCtrLabel++ if isStaticClosure cl_info+ then do bumpTickyCounter (fsLit "ENT_STATIC_FUN_DIRECT_ctr")+ registerTickyCtr ctr_lbl+ else do bumpTickyCounter (fsLit "ENT_DYN_FUN_DIRECT_ctr")+ registerTickyCtrAtEntryDyn ctr_lbl++ bumpTickyEntryCount ctr_lbl++tickyEnterLNE :: FCode ()+tickyEnterLNE = ifTicky $ do+ bumpTickyCounter (fsLit "ENT_LNE_ctr")+ ifTickyLNE $ do+ ctr_lbl <- getTickyCtrLabel+ registerTickyCtr ctr_lbl+ bumpTickyEntryCount ctr_lbl++-- needn't register a counter upon entry if+--+-- 1) it's for a dynamic closure, and+--+-- 2) -ticky-allocd is on+--+-- since the counter was registered already upon being alloc'd+registerTickyCtrAtEntryDyn :: CLabel -> FCode ()+registerTickyCtrAtEntryDyn ctr_lbl = do+ already_registered <- tickyAllocdIsOn+ when (not already_registered) $ registerTickyCtr ctr_lbl++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+ dflags <- getDynFlags+ let+ -- krc: code generator doesn't handle Not, so we test for Eq 0 instead+ test = CmmMachOp (MO_Eq (wordWidth dflags))+ [CmmLoad (CmmLit (cmmLabelOffB ctr_lbl+ (oFFSET_StgEntCounter_registeredp dflags))) (bWord dflags),+ zeroExpr dflags]+ register_stmts+ = [ mkStore (CmmLit (cmmLabelOffB ctr_lbl (oFFSET_StgEntCounter_link dflags)))+ (CmmLoad ticky_entry_ctrs (bWord dflags))+ , mkStore ticky_entry_ctrs (mkLblExpr ctr_lbl)+ , mkStore (CmmLit (cmmLabelOffB ctr_lbl+ (oFFSET_StgEntCounter_registeredp dflags)))+ (mkIntExpr dflags 1) ]+ ticky_entry_ctrs = mkLblExpr (mkCmmDataLabel rtsUnitId (fsLit "ticky_entry_ctrs"))+ emit =<< mkCmmIfThen test (catAGraphs register_stmts)++tickyReturnOldCon, tickyReturnNewCon :: RepArity -> FCode ()+tickyReturnOldCon arity+ = ifTicky $ do { bumpTickyCounter (fsLit "RET_OLD_ctr")+ ; bumpHistogram (fsLit "RET_OLD_hst") arity }+tickyReturnNewCon arity+ = ifTicky $ do { bumpTickyCounter (fsLit "RET_NEW_ctr")+ ; bumpHistogram (fsLit "RET_NEW_hst") arity }++tickyUnboxedTupleReturn :: RepArity -> FCode ()+tickyUnboxedTupleReturn arity+ = ifTicky $ do { bumpTickyCounter (fsLit "RET_UNBOXED_TUP_ctr")+ ; bumpHistogram (fsLit "RET_UNBOXED_TUP_hst") arity }++-- -----------------------------------------------------------------------------+-- Ticky calls++-- Ticks at a *call site*:+tickyDirectCall :: RepArity -> [StgArg] -> FCode ()+tickyDirectCall arity args+ | arity == length args = tickyKnownCallExact+ | otherwise = do tickyKnownCallExtraArgs+ tickySlowCallPat (map argPrimRep (drop arity args))++tickyKnownCallTooFewArgs :: FCode ()+tickyKnownCallTooFewArgs = ifTicky $ bumpTickyCounter (fsLit "KNOWN_CALL_TOO_FEW_ARGS_ctr")++tickyKnownCallExact :: FCode ()+tickyKnownCallExact = ifTicky $ bumpTickyCounter (fsLit "KNOWN_CALL_ctr")++tickyKnownCallExtraArgs :: FCode ()+tickyKnownCallExtraArgs = ifTicky $ bumpTickyCounter (fsLit "KNOWN_CALL_EXTRA_ARGS_ctr")++tickyUnknownCall :: FCode ()+tickyUnknownCall = ifTicky $ bumpTickyCounter (fsLit "UNKNOWN_CALL_ctr")++-- Tick for the call pattern at slow call site (i.e. in addition to+-- tickyUnknownCall, tickyKnownCallExtraArgs, etc.)+tickySlowCall :: LambdaFormInfo -> [StgArg] -> FCode ()+tickySlowCall _ [] = return ()+tickySlowCall lf_info args = do+ -- see Note [Ticky for slow calls]+ if isKnownFun lf_info+ then tickyKnownCallTooFewArgs+ else tickyUnknownCall+ tickySlowCallPat (map argPrimRep args)++tickySlowCallPat :: [PrimRep] -> FCode ()+tickySlowCallPat args = ifTicky $+ let argReps = map toArgRep args+ (_, n_matched) = slowCallPattern argReps+ in if n_matched > 0 && n_matched == length args+ then bumpTickyLbl $ mkRtsSlowFastTickyCtrLabel $ concatMap (map Data.Char.toLower . argRepString) argReps+ else bumpTickyCounter $ fsLit "VERY_SLOW_CALL_ctr"++{-++Note [Ticky for slow calls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Terminology is unfortunately a bit mixed up for these calls. codeGen+uses "slow call" to refer to unknown calls and under-saturated known+calls.++Nowadays, though (ie as of the eval/apply paper), the significantly+slower calls are actually just a subset of these: the ones with no+built-in argument pattern (cf StgCmmArgRep.slowCallPattern)++So for ticky profiling, we split slow calls into+"SLOW_CALL_fast_<pattern>_ctr" (those matching a built-in pattern) and+VERY_SLOW_CALL_ctr (those without a built-in pattern; these are very+bad for both space and time).++-}++-- -----------------------------------------------------------------------------+-- Ticky allocation++tickyDynAlloc :: Maybe Id -> SMRep -> LambdaFormInfo -> FCode ()+-- Called when doing a dynamic heap allocation; the LambdaFormInfo+-- used to distinguish between closure types+--+-- TODO what else to count while we're here?+tickyDynAlloc mb_id rep lf = ifTicky $ getDynFlags >>= \dflags ->+ let bytes = wORD_SIZE dflags * heapClosureSizeW dflags rep++ countGlobal tot ctr = do+ bumpTickyCounterBy tot bytes+ bumpTickyCounter ctr+ countSpecific = ifTickyAllocd $ case mb_id of+ Nothing -> return ()+ Just id -> do+ let ctr_lbl = mkRednCountsLabel (idName id)+ registerTickyCtr ctr_lbl+ bumpTickyAllocd ctr_lbl bytes++ -- TODO are we still tracking "good stuff" (_gds) versus+ -- administrative (_adm) versus slop (_slp)? I'm going with all _gds+ -- for now, since I don't currently know neither if we do nor how to+ -- distinguish. NSF Mar 2013++ in case () of+ _ | isConRep rep ->+ ifTickyDynThunk countSpecific >>+ countGlobal (fsLit "ALLOC_CON_gds") (fsLit "ALLOC_CON_ctr")+ | isThunkRep rep ->+ ifTickyDynThunk countSpecific >>+ if lfUpdatable lf+ then countGlobal (fsLit "ALLOC_THK_gds") (fsLit "ALLOC_UP_THK_ctr")+ else countGlobal (fsLit "ALLOC_THK_gds") (fsLit "ALLOC_SE_THK_ctr")+ | isFunRep rep ->+ countSpecific >>+ countGlobal (fsLit "ALLOC_FUN_gds") (fsLit "ALLOC_FUN_ctr")+ | otherwise -> panic "How is this heap object not a con, thunk, or fun?"++++tickyAllocHeap ::+ Bool -> -- is this a genuine allocation? As opposed to+ -- StgCmmLayout.adjustHpBackwards+ VirtualHpOffset -> FCode ()+-- Called when doing a heap check [TICK_ALLOC_HEAP]+-- Must be lazy in the amount of allocation!+tickyAllocHeap genuine hp+ = ifTicky $+ do { dflags <- getDynFlags+ ; ticky_ctr <- getTickyCtrLabel+ ; emit $ catAGraphs $+ -- only test hp from within the emit so that the monadic+ -- computation itself is not strict in hp (cf knot in+ -- StgCmmMonad.getHeapUsage)+ if hp == 0 then []+ else let !bytes = wORD_SIZE dflags * hp in [+ -- Bump the allocation total in the closure's StgEntCounter+ addToMem (rEP_StgEntCounter_allocs dflags)+ (CmmLit (cmmLabelOffB ticky_ctr (oFFSET_StgEntCounter_allocs dflags)))+ bytes,+ -- Bump the global allocation total ALLOC_HEAP_tot+ addToMemLbl (bWord dflags)+ (mkCmmDataLabel rtsUnitId (fsLit "ALLOC_HEAP_tot"))+ bytes,+ -- Bump the global allocation counter ALLOC_HEAP_ctr+ if not genuine then mkNop+ else addToMemLbl (bWord dflags)+ (mkCmmDataLabel rtsUnitId (fsLit "ALLOC_HEAP_ctr"))+ 1+ ]}+++--------------------------------------------------------------------------------+-- these three are only called from CmmParse.y (ie ultimately from the RTS)++-- the units are bytes++tickyAllocPrim :: CmmExpr -- ^ size of the full header, in bytes+ -> CmmExpr -- ^ size of the payload, in bytes+ -> CmmExpr -> FCode ()+tickyAllocPrim _hdr _goods _slop = ifTicky $ do+ bumpTickyCounter (fsLit "ALLOC_PRIM_ctr")+ bumpTickyCounterByE (fsLit "ALLOC_PRIM_adm") _hdr+ bumpTickyCounterByE (fsLit "ALLOC_PRIM_gds") _goods+ bumpTickyCounterByE (fsLit "ALLOC_PRIM_slp") _slop++tickyAllocThunk :: CmmExpr -> CmmExpr -> FCode ()+tickyAllocThunk _goods _slop = ifTicky $ do+ -- TODO is it ever called with a Single-Entry thunk?+ bumpTickyCounter (fsLit "ALLOC_UP_THK_ctr")+ bumpTickyCounterByE (fsLit "ALLOC_THK_gds") _goods+ bumpTickyCounterByE (fsLit "ALLOC_THK_slp") _slop++tickyAllocPAP :: CmmExpr -> CmmExpr -> FCode ()+tickyAllocPAP _goods _slop = ifTicky $ do+ bumpTickyCounter (fsLit "ALLOC_PAP_ctr")+ bumpTickyCounterByE (fsLit "ALLOC_PAP_gds") _goods+ bumpTickyCounterByE (fsLit "ALLOC_PAP_slp") _slop++tickyHeapCheck :: FCode ()+tickyHeapCheck = ifTicky $ bumpTickyCounter (fsLit "HEAP_CHK_ctr")++tickyStackCheck :: FCode ()+tickyStackCheck = ifTicky $ bumpTickyCounter (fsLit "STK_CHK_ctr")++-- -----------------------------------------------------------------------------+-- Ticky utils++ifTicky :: FCode () -> FCode ()+ifTicky code =+ getDynFlags >>= \dflags -> when (gopt Opt_Ticky dflags) code++tickyAllocdIsOn :: FCode Bool+tickyAllocdIsOn = gopt Opt_Ticky_Allocd `fmap` getDynFlags++tickyLNEIsOn :: FCode Bool+tickyLNEIsOn = gopt Opt_Ticky_LNE `fmap` getDynFlags++tickyDynThunkIsOn :: FCode Bool+tickyDynThunkIsOn = gopt Opt_Ticky_Dyn_Thunk `fmap` getDynFlags++ifTickyAllocd :: FCode () -> FCode ()+ifTickyAllocd code = tickyAllocdIsOn >>= \b -> when b code++ifTickyLNE :: FCode () -> FCode ()+ifTickyLNE code = tickyLNEIsOn >>= \b -> when b code++ifTickyDynThunk :: FCode () -> FCode ()+ifTickyDynThunk code = tickyDynThunkIsOn >>= \b -> when b code++bumpTickyCounter :: FastString -> FCode ()+bumpTickyCounter lbl = bumpTickyLbl (mkCmmDataLabel rtsUnitId lbl)++bumpTickyCounterBy :: FastString -> Int -> FCode ()+bumpTickyCounterBy lbl = bumpTickyLblBy (mkCmmDataLabel rtsUnitId lbl)++bumpTickyCounterByE :: FastString -> CmmExpr -> FCode ()+bumpTickyCounterByE lbl = bumpTickyLblByE (mkCmmDataLabel rtsUnitId lbl)++bumpTickyEntryCount :: CLabel -> FCode ()+bumpTickyEntryCount lbl = do+ dflags <- getDynFlags+ bumpTickyLit (cmmLabelOffB lbl (oFFSET_StgEntCounter_entry_count dflags))++bumpTickyAllocd :: CLabel -> Int -> FCode ()+bumpTickyAllocd lbl bytes = do+ dflags <- getDynFlags+ bumpTickyLitBy (cmmLabelOffB lbl (oFFSET_StgEntCounter_allocd dflags)) bytes++bumpTickyLbl :: CLabel -> FCode ()+bumpTickyLbl lhs = bumpTickyLitBy (cmmLabelOffB lhs 0) 1++bumpTickyLblBy :: CLabel -> Int -> FCode ()+bumpTickyLblBy lhs = bumpTickyLitBy (cmmLabelOffB lhs 0)++bumpTickyLblByE :: CLabel -> CmmExpr -> FCode ()+bumpTickyLblByE lhs = bumpTickyLitByE (cmmLabelOffB lhs 0)++bumpTickyLit :: CmmLit -> FCode ()+bumpTickyLit lhs = bumpTickyLitBy lhs 1++bumpTickyLitBy :: CmmLit -> Int -> FCode ()+bumpTickyLitBy lhs n = do+ dflags <- getDynFlags+ emit (addToMem (bWord dflags) (CmmLit lhs) n)++bumpTickyLitByE :: CmmLit -> CmmExpr -> FCode ()+bumpTickyLitByE lhs e = do+ dflags <- getDynFlags+ emit (addToMemE (bWord dflags) (CmmLit lhs) e)++bumpHistogram :: FastString -> Int -> FCode ()+bumpHistogram lbl n = do+ dflags <- getDynFlags+ let offset = n `min` (tICKY_BIN_COUNT dflags - 1)+ emit (addToMem (bWord dflags)+ (cmmIndexExpr dflags+ (wordWidth dflags)+ (CmmLit (CmmLabel (mkCmmDataLabel rtsUnitId lbl)))+ (CmmLit (CmmInt (fromIntegral offset) (wordWidth dflags))))+ 1)++------------------------------------------------------------------+-- Showing the "type category" for ticky-ticky profiling++showTypeCategory :: Type -> Char+ {-+ + dictionary++ > function++ {C,I,F,D,W} char, int, float, double, word+ {c,i,f,d,w} unboxed ditto++ T tuple++ P other primitive type+ p unboxed ditto++ L list+ E enumeration type+ S other single-constructor type+ M other multi-constructor data-con type++ . other type++ - reserved for others to mark as "uninteresting"++ Accurate as of Mar 2013, but I eliminated the Array category instead+ of updating it, for simplicity. It's in P/p, I think --NSF++ -}+showTypeCategory ty+ | isDictTy ty = '+'+ | otherwise = case tcSplitTyConApp_maybe ty of+ Nothing -> '.'+ Just (tycon, _) ->+ (if isUnliftedTyCon tycon then Data.Char.toLower else id) $+ let anyOf us = getUnique tycon `elem` us in+ case () of+ _ | anyOf [funTyConKey] -> '>'+ | anyOf [charPrimTyConKey, charTyConKey] -> 'C'+ | anyOf [doublePrimTyConKey, doubleTyConKey] -> 'D'+ | anyOf [floatPrimTyConKey, floatTyConKey] -> 'F'+ | anyOf [intPrimTyConKey, int32PrimTyConKey, int64PrimTyConKey,+ intTyConKey, int8TyConKey, int16TyConKey, int32TyConKey, int64TyConKey+ ] -> 'I'+ | anyOf [wordPrimTyConKey, word32PrimTyConKey, word64PrimTyConKey, wordTyConKey,+ word8TyConKey, word16TyConKey, word32TyConKey, word64TyConKey+ ] -> 'W'+ | anyOf [listTyConKey] -> 'L'+ | isTupleTyCon tycon -> 'T'+ | isPrimTyCon tycon -> 'P'+ | isEnumerationTyCon tycon -> 'E'+ | isJust (tyConSingleDataCon_maybe tycon) -> 'S'+ | otherwise -> 'M' -- oh, well...
+ codeGen/StgCmmUtils.hs view
@@ -0,0 +1,620 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Code generator utilities; mostly monadic+--+-- (c) The University of Glasgow 2004-2006+--+-----------------------------------------------------------------------------++module StgCmmUtils (+ cgLit, mkSimpleLit,+ emitDataLits, mkDataLits,+ emitRODataLits, mkRODataLits,+ emitRtsCall, emitRtsCallWithResult, emitRtsCallGen,+ assignTemp, newTemp,++ newUnboxedTupleRegs,++ emitMultiAssign, emitCmmLitSwitch, emitSwitch,++ tagToClosure, mkTaggedObjectLoad,++ callerSaves, callerSaveVolatileRegs, get_GlobalReg_addr,++ cmmAndWord, cmmOrWord, cmmNegate, cmmEqWord, cmmNeWord,+ cmmUGtWord, cmmSubWord, cmmMulWord, cmmAddWord, cmmUShrWord,+ cmmOffsetExprW, cmmOffsetExprB,+ cmmRegOffW, cmmRegOffB,+ cmmLabelOffW, cmmLabelOffB,+ cmmOffsetW, cmmOffsetB,+ cmmOffsetLitW, cmmOffsetLitB,+ cmmLoadIndexW,+ cmmConstrTag1,++ cmmUntag, cmmIsTagged,++ addToMem, addToMemE, addToMemLblE, addToMemLbl,+ mkWordCLit,+ newStringCLit, newByteStringCLit,+ blankWord,+ ) where++#include "HsVersions.h"++import StgCmmMonad+import StgCmmClosure+import Cmm+import BlockId+import MkGraph+import CodeGen.Platform+import CLabel+import CmmUtils+import CmmSwitch++import ForeignCall+import IdInfo+import Type+import TyCon+import SMRep+import Module+import Literal+import Digraph+import Util+import Unique+import UniqSupply (MonadUnique(..))+import DynFlags+import FastString+import Outputable+import RepType++import qualified Data.ByteString as BS+import qualified Data.Map as M+import Data.Char+import Data.List+import Data.Ord+import Data.Word+++-------------------------------------------------------------------------+--+-- Literals+--+-------------------------------------------------------------------------++cgLit :: Literal -> FCode CmmLit+cgLit (MachStr s) = newByteStringCLit (BS.unpack s)+ -- not unpackFS; we want the UTF-8 byte stream.+cgLit other_lit = do dflags <- getDynFlags+ return (mkSimpleLit dflags other_lit)++mkSimpleLit :: DynFlags -> Literal -> CmmLit+mkSimpleLit dflags (MachChar c) = CmmInt (fromIntegral (ord c)) (wordWidth dflags)+mkSimpleLit dflags MachNullAddr = zeroCLit dflags+mkSimpleLit dflags (MachInt i) = CmmInt i (wordWidth dflags)+mkSimpleLit _ (MachInt64 i) = CmmInt i W64+mkSimpleLit dflags (MachWord i) = CmmInt i (wordWidth dflags)+mkSimpleLit _ (MachWord64 i) = CmmInt i W64+mkSimpleLit _ (MachFloat r) = CmmFloat r W32+mkSimpleLit _ (MachDouble r) = CmmFloat r W64+mkSimpleLit _ (MachLabel fs ms fod)+ = CmmLabel (mkForeignLabel fs ms labelSrc fod)+ where+ -- TODO: Literal labels might not actually be in the current package...+ labelSrc = ForeignLabelInThisPackage+mkSimpleLit _ other = pprPanic "mkSimpleLit" (ppr other)++--------------------------------------------------------------------------+--+-- Incrementing a memory location+--+--------------------------------------------------------------------------++addToMemLbl :: CmmType -> CLabel -> Int -> CmmAGraph+addToMemLbl rep lbl n = addToMem rep (CmmLit (CmmLabel lbl)) n++addToMemLblE :: CmmType -> CLabel -> CmmExpr -> CmmAGraph+addToMemLblE rep lbl = addToMemE rep (CmmLit (CmmLabel lbl))++addToMem :: CmmType -- rep of the counter+ -> CmmExpr -- Address+ -> Int -- What to add (a word)+ -> CmmAGraph+addToMem rep ptr n = addToMemE rep ptr (CmmLit (CmmInt (toInteger n) (typeWidth rep)))++addToMemE :: CmmType -- rep of the counter+ -> CmmExpr -- Address+ -> CmmExpr -- What to add (a word-typed expression)+ -> CmmAGraph+addToMemE rep ptr n+ = mkStore ptr (CmmMachOp (MO_Add (typeWidth rep)) [CmmLoad ptr rep, n])+++-------------------------------------------------------------------------+--+-- Loading a field from an object,+-- where the object pointer is itself tagged+--+-------------------------------------------------------------------------++mkTaggedObjectLoad+ :: DynFlags -> LocalReg -> LocalReg -> ByteOff -> DynTag -> CmmAGraph+-- (loadTaggedObjectField reg base off tag) generates assignment+-- reg = bitsK[ base + off - tag ]+-- where K is fixed by 'reg'+mkTaggedObjectLoad dflags reg base offset tag+ = mkAssign (CmmLocal reg)+ (CmmLoad (cmmOffsetB dflags+ (CmmReg (CmmLocal base))+ (offset - tag))+ (localRegType reg))++-------------------------------------------------------------------------+--+-- Converting a closure tag to a closure for enumeration types+-- (this is the implementation of tagToEnum#).+--+-------------------------------------------------------------------------++tagToClosure :: DynFlags -> TyCon -> CmmExpr -> CmmExpr+tagToClosure dflags tycon tag+ = CmmLoad (cmmOffsetExprW dflags closure_tbl tag) (bWord dflags)+ where closure_tbl = CmmLit (CmmLabel lbl)+ lbl = mkClosureTableLabel (tyConName tycon) NoCafRefs++-------------------------------------------------------------------------+--+-- Conditionals and rts calls+--+-------------------------------------------------------------------------++emitRtsCall :: UnitId -> FastString -> [(CmmExpr,ForeignHint)] -> Bool -> FCode ()+emitRtsCall pkg fun args safe = emitRtsCallGen [] (mkCmmCodeLabel pkg fun) args safe++emitRtsCallWithResult :: LocalReg -> ForeignHint -> UnitId -> FastString+ -> [(CmmExpr,ForeignHint)] -> Bool -> FCode ()+emitRtsCallWithResult res hint pkg fun args safe+ = emitRtsCallGen [(res,hint)] (mkCmmCodeLabel pkg fun) args safe++-- Make a call to an RTS C procedure+emitRtsCallGen+ :: [(LocalReg,ForeignHint)]+ -> CLabel+ -> [(CmmExpr,ForeignHint)]+ -> Bool -- True <=> CmmSafe call+ -> FCode ()+emitRtsCallGen res lbl args safe+ = do { dflags <- getDynFlags+ ; updfr_off <- getUpdFrameOff+ ; let (caller_save, caller_load) = callerSaveVolatileRegs dflags+ ; emit caller_save+ ; call updfr_off+ ; emit caller_load }+ where+ call updfr_off =+ if safe then+ emit =<< mkCmmCall fun_expr res' args' updfr_off+ else do+ let conv = ForeignConvention CCallConv arg_hints res_hints CmmMayReturn+ emit $ mkUnsafeCall (ForeignTarget fun_expr conv) res' args'+ (args', arg_hints) = unzip args+ (res', res_hints) = unzip res+ fun_expr = mkLblExpr lbl+++-----------------------------------------------------------------------------+--+-- Caller-Save Registers+--+-----------------------------------------------------------------------------++-- Here we generate the sequence of saves/restores required around a+-- foreign call instruction.++-- TODO: reconcile with includes/Regs.h+-- * Regs.h claims that BaseReg should be saved last and loaded first+-- * This might not have been tickled before since BaseReg is callee save+-- * Regs.h saves SparkHd, ParkT1, SparkBase and SparkLim+--+-- This code isn't actually used right now, because callerSaves+-- only ever returns true in the current universe for registers NOT in+-- system_regs (just do a grep for CALLER_SAVES in+-- includes/stg/MachRegs.h). It's all one giant no-op, and for+-- good reason: having to save system registers on every foreign call+-- would be very expensive, so we avoid assigning them to those+-- registers when we add support for an architecture.+--+-- Note that the old code generator actually does more work here: it+-- also saves other global registers. We can't (nor want) to do that+-- here, as we don't have liveness information. And really, we+-- shouldn't be doing the workaround at this point in the pipeline, see+-- Note [Register parameter passing] and the ToDo on CmmCall in+-- cmm/CmmNode.hs. Right now the workaround is to avoid inlining across+-- unsafe foreign calls in rewriteAssignments, but this is strictly+-- temporary.+callerSaveVolatileRegs :: DynFlags -> (CmmAGraph, CmmAGraph)+callerSaveVolatileRegs dflags = (caller_save, caller_load)+ where+ platform = targetPlatform dflags++ caller_save = catAGraphs (map callerSaveGlobalReg regs_to_save)+ caller_load = catAGraphs (map callerRestoreGlobalReg regs_to_save)++ system_regs = [ Sp,SpLim,Hp,HpLim,CCCS,CurrentTSO,CurrentNursery+ {- ,SparkHd,SparkTl,SparkBase,SparkLim -}+ , BaseReg ]++ regs_to_save = filter (callerSaves platform) system_regs++ callerSaveGlobalReg reg+ = mkStore (get_GlobalReg_addr dflags reg) (CmmReg (CmmGlobal reg))++ callerRestoreGlobalReg reg+ = mkAssign (CmmGlobal reg)+ (CmmLoad (get_GlobalReg_addr dflags reg) (globalRegType dflags reg))++-- -----------------------------------------------------------------------------+-- Global registers++-- We map STG registers onto appropriate CmmExprs. Either they map+-- to real machine registers or stored as offsets from BaseReg. Given+-- a GlobalReg, get_GlobalReg_addr always produces the+-- register table address for it.+-- (See also get_GlobalReg_reg_or_addr in MachRegs)++get_GlobalReg_addr :: DynFlags -> GlobalReg -> CmmExpr+get_GlobalReg_addr dflags BaseReg = regTableOffset dflags 0+get_GlobalReg_addr dflags mid+ = get_Regtable_addr_from_offset dflags+ (globalRegType dflags mid) (baseRegOffset dflags mid)++-- Calculate a literal representing an offset into the register table.+-- Used when we don't have an actual BaseReg to offset from.+regTableOffset :: DynFlags -> Int -> CmmExpr+regTableOffset dflags n =+ CmmLit (CmmLabelOff mkMainCapabilityLabel (oFFSET_Capability_r dflags + n))++get_Regtable_addr_from_offset :: DynFlags -> CmmType -> Int -> CmmExpr+get_Regtable_addr_from_offset dflags _rep offset =+ if haveRegBase (targetPlatform dflags)+ then CmmRegOff (CmmGlobal BaseReg) offset+ else regTableOffset dflags offset+++-- -----------------------------------------------------------------------------+-- Information about global registers++baseRegOffset :: DynFlags -> GlobalReg -> Int++baseRegOffset dflags Sp = oFFSET_StgRegTable_rSp dflags+baseRegOffset dflags SpLim = oFFSET_StgRegTable_rSpLim dflags+baseRegOffset dflags (LongReg 1) = oFFSET_StgRegTable_rL1 dflags+baseRegOffset dflags Hp = oFFSET_StgRegTable_rHp dflags+baseRegOffset dflags HpLim = oFFSET_StgRegTable_rHpLim dflags+baseRegOffset dflags CCCS = oFFSET_StgRegTable_rCCCS dflags+baseRegOffset dflags CurrentTSO = oFFSET_StgRegTable_rCurrentTSO dflags+baseRegOffset dflags CurrentNursery = oFFSET_StgRegTable_rCurrentNursery dflags+baseRegOffset dflags HpAlloc = oFFSET_StgRegTable_rHpAlloc dflags+baseRegOffset dflags GCEnter1 = oFFSET_stgGCEnter1 dflags+baseRegOffset dflags GCFun = oFFSET_stgGCFun dflags+baseRegOffset _ reg = pprPanic "StgCmmUtils.baseRegOffset:" (ppr reg)++-------------------------------------------------------------------------+--+-- Strings generate a top-level data block+--+-------------------------------------------------------------------------++emitDataLits :: CLabel -> [CmmLit] -> FCode ()+-- Emit a data-segment data block+emitDataLits lbl lits = emitDecl (mkDataLits (Section Data lbl) lbl lits)++emitRODataLits :: CLabel -> [CmmLit] -> FCode ()+-- Emit a read-only data block+emitRODataLits lbl lits = emitDecl (mkRODataLits lbl lits)++newStringCLit :: String -> FCode CmmLit+-- Make a global definition for the string,+-- and return its label+newStringCLit str = newByteStringCLit (map (fromIntegral . ord) str)++newByteStringCLit :: [Word8] -> FCode CmmLit+newByteStringCLit bytes+ = do { uniq <- newUnique+ ; let (lit, decl) = mkByteStringCLit (mkStringLitLabel uniq) bytes+ ; emitDecl decl+ ; return lit }++-------------------------------------------------------------------------+--+-- Assigning expressions to temporaries+--+-------------------------------------------------------------------------++assignTemp :: CmmExpr -> FCode LocalReg+-- Make sure the argument is in a local register.+-- We don't bother being particularly aggressive with avoiding+-- unnecessary local registers, since we can rely on a later+-- optimization pass to inline as necessary (and skipping out+-- on things like global registers can be a little dangerous+-- due to them being trashed on foreign calls--though it means+-- the optimization pass doesn't have to do as much work)+assignTemp (CmmReg (CmmLocal reg)) = return reg+assignTemp e = do { dflags <- getDynFlags+ ; uniq <- newUnique+ ; let reg = LocalReg uniq (cmmExprType dflags e)+ ; emitAssign (CmmLocal reg) e+ ; return reg }++newTemp :: MonadUnique m => CmmType -> m LocalReg+newTemp rep = do { uniq <- getUniqueM+ ; return (LocalReg uniq rep) }++newUnboxedTupleRegs :: Type -> FCode ([LocalReg], [ForeignHint])+-- Choose suitable local regs to use for the components+-- of an unboxed tuple that we are about to return to+-- the Sequel. If the Sequel is a join point, using the+-- regs it wants will save later assignments.+newUnboxedTupleRegs res_ty+ = ASSERT( isUnboxedTupleType res_ty )+ do { dflags <- getDynFlags+ ; sequel <- getSequel+ ; regs <- choose_regs dflags sequel+ ; ASSERT( regs `equalLength` reps )+ return (regs, map primRepForeignHint reps) }+ where+ reps = typePrimRep res_ty+ choose_regs _ (AssignTo regs _) = return regs+ choose_regs dflags _ = mapM (newTemp . primRepCmmType dflags) reps++++-------------------------------------------------------------------------+-- emitMultiAssign+-------------------------------------------------------------------------++emitMultiAssign :: [LocalReg] -> [CmmExpr] -> FCode ()+-- Emit code to perform the assignments in the+-- input simultaneously, using temporary variables when necessary.++type Key = Int+type Vrtx = (Key, Stmt) -- Give each vertex a unique number,+ -- for fast comparison+type Stmt = (LocalReg, CmmExpr) -- r := e++-- We use the strongly-connected component algorithm, in which+-- * the vertices are the statements+-- * an edge goes from s1 to s2 iff+-- s1 assigns to something s2 uses+-- that is, if s1 should *follow* s2 in the final order++emitMultiAssign [] [] = return ()+emitMultiAssign [reg] [rhs] = emitAssign (CmmLocal reg) rhs+emitMultiAssign regs rhss = do+ dflags <- getDynFlags+ ASSERT2( equalLength regs rhss, ppr regs $$ ppr rhss )+ unscramble dflags ([1..] `zip` (regs `zip` rhss))++unscramble :: DynFlags -> [Vrtx] -> FCode ()+unscramble dflags vertices = mapM_ do_component components+ where+ edges :: [ (Vrtx, Key, [Key]) ]+ edges = [ (vertex, key1, edges_from stmt1)+ | vertex@(key1, stmt1) <- vertices ]++ edges_from :: Stmt -> [Key]+ edges_from stmt1 = [ key2 | (key2, stmt2) <- vertices,+ stmt1 `mustFollow` stmt2 ]++ components :: [SCC Vrtx]+ components = stronglyConnCompFromEdgedVerticesUniq edges++ -- do_components deal with one strongly-connected component+ -- Not cyclic, or singleton? Just do it+ do_component :: SCC Vrtx -> FCode ()+ do_component (AcyclicSCC (_,stmt)) = mk_graph stmt+ do_component (CyclicSCC []) = panic "do_component"+ do_component (CyclicSCC [(_,stmt)]) = mk_graph stmt++ -- Cyclic? Then go via temporaries. Pick one to+ -- break the loop and try again with the rest.+ do_component (CyclicSCC ((_,first_stmt) : rest)) = do+ dflags <- getDynFlags+ u <- newUnique+ let (to_tmp, from_tmp) = split dflags u first_stmt+ mk_graph to_tmp+ unscramble dflags rest+ mk_graph from_tmp++ split :: DynFlags -> Unique -> Stmt -> (Stmt, Stmt)+ split dflags uniq (reg, rhs)+ = ((tmp, rhs), (reg, CmmReg (CmmLocal tmp)))+ where+ rep = cmmExprType dflags rhs+ tmp = LocalReg uniq rep++ mk_graph :: Stmt -> FCode ()+ mk_graph (reg, rhs) = emitAssign (CmmLocal reg) rhs++ mustFollow :: Stmt -> Stmt -> Bool+ (reg, _) `mustFollow` (_, rhs) = regUsedIn dflags (CmmLocal reg) rhs++-------------------------------------------------------------------------+-- mkSwitch+-------------------------------------------------------------------------+++emitSwitch :: CmmExpr -- Tag to switch on+ -> [(ConTagZ, CmmAGraphScoped)] -- Tagged branches+ -> Maybe CmmAGraphScoped -- Default branch (if any)+ -> ConTagZ -> ConTagZ -- Min and Max possible values;+ -- behaviour outside this range is+ -- undefined+ -> FCode ()++-- First, two rather common cases in which there is no work to do+emitSwitch _ [] (Just code) _ _ = emit (fst code)+emitSwitch _ [(_,code)] Nothing _ _ = emit (fst code)++-- Right, off we go+emitSwitch tag_expr branches mb_deflt lo_tag hi_tag = do+ join_lbl <- newBlockId+ mb_deflt_lbl <- label_default join_lbl mb_deflt+ branches_lbls <- label_branches join_lbl branches+ tag_expr' <- assignTemp' tag_expr++ -- Sort the branches before calling mk_discrete_switch+ let branches_lbls' = [ (fromIntegral i, l) | (i,l) <- sortBy (comparing fst) branches_lbls ]+ let range = (fromIntegral lo_tag, fromIntegral hi_tag)++ emit $ mk_discrete_switch False tag_expr' branches_lbls' mb_deflt_lbl range++ emitLabel join_lbl++mk_discrete_switch :: Bool -- ^ Use signed comparisons+ -> CmmExpr+ -> [(Integer, BlockId)]+ -> Maybe BlockId+ -> (Integer, Integer)+ -> CmmAGraph++-- SINGLETON TAG RANGE: no case analysis to do+mk_discrete_switch _ _tag_expr [(tag, lbl)] _ (lo_tag, hi_tag)+ | lo_tag == hi_tag+ = ASSERT( tag == lo_tag )+ mkBranch lbl++-- SINGLETON BRANCH, NO DEFAULT: no case analysis to do+mk_discrete_switch _ _tag_expr [(_tag,lbl)] Nothing _+ = mkBranch lbl+ -- The simplifier might have eliminated a case+ -- so we may have e.g. case xs of+ -- [] -> e+ -- In that situation we can be sure the (:) case+ -- can't happen, so no need to test++-- SOMETHING MORE COMPLICATED: defer to CmmImplementSwitchPlans+-- See Note [Cmm Switches, the general plan] in CmmSwitch+mk_discrete_switch signed tag_expr branches mb_deflt range+ = mkSwitch tag_expr $ mkSwitchTargets signed range mb_deflt (M.fromList branches)++divideBranches :: Ord a => [(a,b)] -> ([(a,b)], a, [(a,b)])+divideBranches branches = (lo_branches, mid, hi_branches)+ where+ -- 2 branches => n_branches `div` 2 = 1+ -- => branches !! 1 give the *second* tag+ -- There are always at least 2 branches here+ (mid,_) = branches !! (length branches `div` 2)+ (lo_branches, hi_branches) = span is_lo branches+ is_lo (t,_) = t < mid++--------------+emitCmmLitSwitch :: CmmExpr -- Tag to switch on+ -> [(Literal, CmmAGraphScoped)] -- Tagged branches+ -> CmmAGraphScoped -- Default branch (always)+ -> FCode () -- Emit the code+emitCmmLitSwitch _scrut [] deflt = emit $ fst deflt+emitCmmLitSwitch scrut branches deflt = do+ scrut' <- assignTemp' scrut+ join_lbl <- newBlockId+ deflt_lbl <- label_code join_lbl deflt+ branches_lbls <- label_branches join_lbl branches++ dflags <- getDynFlags+ let cmm_ty = cmmExprType dflags scrut+ rep = typeWidth cmm_ty++ -- We find the necessary type information in the literals in the branches+ let signed = case head branches of+ (MachInt _, _) -> True+ (MachInt64 _, _) -> True+ _ -> False++ let range | signed = (tARGET_MIN_INT dflags, tARGET_MAX_INT dflags)+ | otherwise = (0, tARGET_MAX_WORD dflags)++ if isFloatType cmm_ty+ then emit =<< mk_float_switch rep scrut' deflt_lbl noBound branches_lbls+ else emit $ mk_discrete_switch+ signed+ scrut'+ [(litValue lit,l) | (lit,l) <- branches_lbls]+ (Just deflt_lbl)+ range+ emitLabel join_lbl++-- | lower bound (inclusive), upper bound (exclusive)+type LitBound = (Maybe Literal, Maybe Literal)++noBound :: LitBound+noBound = (Nothing, Nothing)++mk_float_switch :: Width -> CmmExpr -> BlockId+ -> LitBound+ -> [(Literal,BlockId)]+ -> FCode CmmAGraph+mk_float_switch rep scrut deflt _bounds [(lit,blk)]+ = do dflags <- getDynFlags+ return $ mkCbranch (cond dflags) deflt blk Nothing+ where+ cond dflags = CmmMachOp ne [scrut, CmmLit cmm_lit]+ where+ cmm_lit = mkSimpleLit dflags lit+ ne = MO_F_Ne rep++mk_float_switch rep scrut deflt_blk_id (lo_bound, hi_bound) branches+ = do dflags <- getDynFlags+ lo_blk <- mk_float_switch rep scrut deflt_blk_id bounds_lo lo_branches+ hi_blk <- mk_float_switch rep scrut deflt_blk_id bounds_hi hi_branches+ mkCmmIfThenElse (cond dflags) lo_blk hi_blk+ where+ (lo_branches, mid_lit, hi_branches) = divideBranches branches++ bounds_lo = (lo_bound, Just mid_lit)+ bounds_hi = (Just mid_lit, hi_bound)++ cond dflags = CmmMachOp lt [scrut, CmmLit cmm_lit]+ where+ cmm_lit = mkSimpleLit dflags mid_lit+ lt = MO_F_Lt rep+++--------------+label_default :: BlockId -> Maybe CmmAGraphScoped -> FCode (Maybe BlockId)+label_default _ Nothing+ = return Nothing+label_default join_lbl (Just code)+ = do lbl <- label_code join_lbl code+ return (Just lbl)++--------------+label_branches :: BlockId -> [(a,CmmAGraphScoped)] -> FCode [(a,BlockId)]+label_branches _join_lbl []+ = return []+label_branches join_lbl ((tag,code):branches)+ = do lbl <- label_code join_lbl code+ branches' <- label_branches join_lbl branches+ return ((tag,lbl):branches')++--------------+label_code :: BlockId -> CmmAGraphScoped -> FCode BlockId+-- label_code J code+-- generates+-- [L: code; goto J]+-- and returns L+label_code join_lbl (code,tsc) = do+ lbl <- newBlockId+ emitOutOfLine lbl (code MkGraph.<*> mkBranch join_lbl, tsc)+ return lbl++--------------+assignTemp' :: CmmExpr -> FCode CmmExpr+assignTemp' e+ | isTrivialCmmExpr e = return e+ | otherwise = do+ dflags <- getDynFlags+ lreg <- newTemp (cmmExprType dflags e)+ let reg = CmmLocal lreg+ emitAssign reg e+ return (CmmReg reg)
+ coreSyn/CoreArity.hs view
@@ -0,0 +1,1200 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++ Arity and eta expansion+-}++{-# LANGUAGE CPP #-}++-- | Arity and eta expansion+module CoreArity (+ manifestArity, joinRhsArity, exprArity, typeArity,+ exprEtaExpandArity, findRhsArity, CheapFun, etaExpand,+ etaExpandToJoinPoint, etaExpandToJoinPointRule,+ exprBotStrictness_maybe+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreFVs+import CoreUtils+import CoreSubst+import Demand+import Var+import VarEnv+import Id+import Type+import TyCon ( initRecTc, checkRecTc )+import Coercion+import BasicTypes+import Unique+import DynFlags ( DynFlags, GeneralFlag(..), gopt )+import Outputable+import FastString+import Pair+import Util ( debugIsOn )++{-+************************************************************************+* *+ manifestArity and exprArity+* *+************************************************************************++exprArity is a cheap-and-cheerful version of exprEtaExpandArity.+It tells how many things the expression can be applied to before doing+any work. It doesn't look inside cases, lets, etc. The idea is that+exprEtaExpandArity will do the hard work, leaving something that's easy+for exprArity to grapple with. In particular, Simplify uses exprArity to+compute the ArityInfo for the Id.++Originally I thought that it was enough just to look for top-level lambdas, but+it isn't. I've seen this++ foo = PrelBase.timesInt++We want foo to get arity 2 even though the eta-expander will leave it+unchanged, in the expectation that it'll be inlined. But occasionally it+isn't, because foo is blacklisted (used in a rule).++Similarly, see the ok_note check in exprEtaExpandArity. So+ f = __inline_me (\x -> e)+won't be eta-expanded.++And in any case it seems more robust to have exprArity be a bit more intelligent.+But note that (\x y z -> f x y z)+should have arity 3, regardless of f's arity.+-}++manifestArity :: CoreExpr -> Arity+-- ^ manifestArity sees how many leading value lambdas there are,+-- after looking through casts+manifestArity (Lam v e) | isId v = 1 + manifestArity e+ | otherwise = manifestArity e+manifestArity (Tick t e) | not (tickishIsCode t) = manifestArity e+manifestArity (Cast e _) = manifestArity e+manifestArity _ = 0++joinRhsArity :: CoreExpr -> JoinArity+-- Join points are supposed to have manifestly-visible+-- lambdas at the top: no ticks, no casts, nothing+-- Moreover, type lambdas count in JoinArity+joinRhsArity (Lam _ e) = 1 + joinRhsArity e+joinRhsArity _ = 0+++---------------+exprArity :: CoreExpr -> Arity+-- ^ An approximate, fast, version of 'exprEtaExpandArity'+exprArity e = go e+ where+ go (Var v) = idArity v+ go (Lam x e) | isId x = go e + 1+ | otherwise = go e+ go (Tick t e) | not (tickishIsCode t) = go e+ go (Cast e co) = trim_arity (go e) (pSnd (coercionKind co))+ -- Note [exprArity invariant]+ go (App e (Type _)) = go e+ go (App f a) | exprIsTrivial a = (go f - 1) `max` 0+ -- See Note [exprArity for applications]+ -- NB: coercions count as a value argument++ go _ = 0++ trim_arity :: Arity -> Type -> Arity+ trim_arity arity ty = arity `min` length (typeArity ty)++---------------+typeArity :: Type -> [OneShotInfo]+-- How many value arrows are visible in the type?+-- We look through foralls, and newtypes+-- See Note [exprArity invariant]+typeArity ty+ = go initRecTc ty+ where+ go rec_nts ty+ | Just (_, ty') <- splitForAllTy_maybe ty+ = go rec_nts ty'++ | Just (arg,res) <- splitFunTy_maybe ty+ = typeOneShot arg : go rec_nts res++ | Just (tc,tys) <- splitTyConApp_maybe ty+ , Just (ty', _) <- instNewTyCon_maybe tc tys+ , Just rec_nts' <- checkRecTc rec_nts tc -- See Note [Expanding newtypes]+ -- in TyCon+-- , not (isClassTyCon tc) -- Do not eta-expand through newtype classes+-- -- See Note [Newtype classes and eta expansion]+-- (no longer required)+ = go rec_nts' ty'+ -- Important to look through non-recursive newtypes, so that, eg+ -- (f x) where f has arity 2, f :: Int -> IO ()+ -- Here we want to get arity 1 for the result!+ --+ -- AND through a layer of recursive newtypes+ -- e.g. newtype Stream m a b = Stream (m (Either b (a, Stream m a b)))++ | otherwise+ = []++---------------+exprBotStrictness_maybe :: CoreExpr -> Maybe (Arity, StrictSig)+-- A cheap and cheerful function that identifies bottoming functions+-- and gives them a suitable strictness signatures. It's used during+-- float-out+exprBotStrictness_maybe e+ = case getBotArity (arityType env e) of+ Nothing -> Nothing+ Just ar -> Just (ar, sig ar)+ where+ env = AE { ae_ped_bot = True, ae_cheap_fn = \ _ _ -> False }+ sig ar = mkClosedStrictSig (replicate ar topDmd) exnRes+ -- For this purpose we can be very simple+ -- exnRes is a bit less aggressive than botRes++{-+Note [exprArity invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~+exprArity has the following invariant:++ (1) If typeArity (exprType e) = n,+ then manifestArity (etaExpand e n) = n++ That is, etaExpand can always expand as much as typeArity says+ So the case analysis in etaExpand and in typeArity must match++ (2) exprArity e <= typeArity (exprType e)++ (3) Hence if (exprArity e) = n, then manifestArity (etaExpand e n) = n++ That is, if exprArity says "the arity is n" then etaExpand really+ can get "n" manifest lambdas to the top.++Why is this important? Because+ - In TidyPgm we use exprArity to fix the *final arity* of+ each top-level Id, and in+ - In CorePrep we use etaExpand on each rhs, so that the visible lambdas+ actually match that arity, which in turn means+ that the StgRhs has the right number of lambdas++An alternative would be to do the eta-expansion in TidyPgm, at least+for top-level bindings, in which case we would not need the trim_arity+in exprArity. That is a less local change, so I'm going to leave it for today!++Note [Newtype classes and eta expansion]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ NB: this nasty special case is no longer required, because+ for newtype classes we don't use the class-op rule mechanism+ at all. See Note [Single-method classes] in TcInstDcls. SLPJ May 2013++-------- Old out of date comments, just for interest -----------+We have to be careful when eta-expanding through newtypes. In general+it's a good idea, but annoyingly it interacts badly with the class-op+rule mechanism. Consider++ class C a where { op :: a -> a }+ instance C b => C [b] where+ op x = ...++These translate to++ co :: forall a. (a->a) ~ C a++ $copList :: C b -> [b] -> [b]+ $copList d x = ...++ $dfList :: C b -> C [b]+ {-# DFunUnfolding = [$copList] #-}+ $dfList d = $copList d |> co@[b]++Now suppose we have:++ dCInt :: C Int++ blah :: [Int] -> [Int]+ blah = op ($dfList dCInt)++Now we want the built-in op/$dfList rule will fire to give+ blah = $copList dCInt++But with eta-expansion 'blah' might (and in Trac #3772, which is+slightly more complicated, does) turn into++ blah = op (\eta. ($dfList dCInt |> sym co) eta)++and now it is *much* harder for the op/$dfList rule to fire, because+exprIsConApp_maybe won't hold of the argument to op. I considered+trying to *make* it hold, but it's tricky and I gave up.++The test simplCore/should_compile/T3722 is an excellent example.+-------- End of old out of date comments, just for interest -----------+++Note [exprArity for applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we come to an application we check that the arg is trivial.+ eg f (fac x) does not have arity 2,+ even if f has arity 3!++* We require that is trivial rather merely cheap. Suppose f has arity 2.+ Then f (Just y)+ has arity 0, because if we gave it arity 1 and then inlined f we'd get+ let v = Just y in \w. <f-body>+ which has arity 0. And we try to maintain the invariant that we don't+ have arity decreases.++* The `max 0` is important! (\x y -> f x) has arity 2, even if f is+ unknown, hence arity 0+++************************************************************************+* *+ Computing the "arity" of an expression+* *+************************************************************************++Note [Definition of arity]+~~~~~~~~~~~~~~~~~~~~~~~~~~+The "arity" of an expression 'e' is n if+ applying 'e' to *fewer* than n *value* arguments+ converges rapidly++Or, to put it another way++ there is no work lost in duplicating the partial+ application (e x1 .. x(n-1))++In the divegent case, no work is lost by duplicating because if the thing+is evaluated once, that's the end of the program.++Or, to put it another way, in any context C++ C[ (\x1 .. xn. e x1 .. xn) ]+ is as efficient as+ C[ e ]++It's all a bit more subtle than it looks:++Note [One-shot lambdas]+~~~~~~~~~~~~~~~~~~~~~~~+Consider one-shot lambdas+ let x = expensive in \y z -> E+We want this to have arity 1 if the \y-abstraction is a 1-shot lambda.++Note [Dealing with bottom]+~~~~~~~~~~~~~~~~~~~~~~~~~~+A Big Deal with computing arities is expressions like++ f = \x -> case x of+ True -> \s -> e1+ False -> \s -> e2++This happens all the time when f :: Bool -> IO ()+In this case we do eta-expand, in order to get that \s to the+top, and give f arity 2.++This isn't really right in the presence of seq. Consider+ (f bot) `seq` 1++This should diverge! But if we eta-expand, it won't. We ignore this+"problem" (unless -fpedantic-bottoms is on), because being scrupulous+would lose an important transformation for many programs. (See+Trac #5587 for an example.)++Consider also+ f = \x -> error "foo"+Here, arity 1 is fine. But if it is+ f = \x -> case x of+ True -> error "foo"+ False -> \y -> x+y+then we want to get arity 2. Technically, this isn't quite right, because+ (f True) `seq` 1+should diverge, but it'll converge if we eta-expand f. Nevertheless, we+do so; it improves some programs significantly, and increasing convergence+isn't a bad thing. Hence the ABot/ATop in ArityType.++So these two transformations aren't always the Right Thing, and we+have several tickets reporting unexpected bahaviour resulting from+this transformation. So we try to limit it as much as possible:++ (1) Do NOT move a lambda outside a known-bottom case expression+ case undefined of { (a,b) -> \y -> e }+ This showed up in Trac #5557++ (2) Do NOT move a lambda outside a case if all the branches of+ the case are known to return bottom.+ case x of { (a,b) -> \y -> error "urk" }+ This case is less important, but the idea is that if the fn is+ going to diverge eventually anyway then getting the best arity+ isn't an issue, so we might as well play safe++ (3) Do NOT move a lambda outside a case unless+ (a) The scrutinee is ok-for-speculation, or+ (b) more liberally: the scrutinee is cheap (e.g. a variable), and+ -fpedantic-bottoms is not enforced (see Trac #2915 for an example)++Of course both (1) and (2) are readily defeated by disguising the bottoms.++4. Note [Newtype arity]+~~~~~~~~~~~~~~~~~~~~~~~~+Non-recursive newtypes are transparent, and should not get in the way.+We do (currently) eta-expand recursive newtypes too. So if we have, say++ newtype T = MkT ([T] -> Int)++Suppose we have+ e = coerce T f+where f has arity 1. Then: etaExpandArity e = 1;+that is, etaExpandArity looks through the coerce.++When we eta-expand e to arity 1: eta_expand 1 e T+we want to get: coerce T (\x::[T] -> (coerce ([T]->Int) e) x)++ HOWEVER, note that if you use coerce bogusly you can ge+ coerce Int negate+ And since negate has arity 2, you might try to eta expand. But you can't+ decopose Int to a function type. Hence the final case in eta_expand.++Note [The state-transformer hack]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+ f = e+where e has arity n. Then, if we know from the context that f has+a usage type like+ t1 -> ... -> tn -1-> t(n+1) -1-> ... -1-> tm -> ...+then we can expand the arity to m. This usage type says that+any application (x e1 .. en) will be applied to uniquely to (m-n) more args+Consider f = \x. let y = <expensive>+ in case x of+ True -> foo+ False -> \(s:RealWorld) -> e+where foo has arity 1. Then we want the state hack to+apply to foo too, so we can eta expand the case.++Then we expect that if f is applied to one arg, it'll be applied to two+(that's the hack -- we don't really know, and sometimes it's false)+See also Id.isOneShotBndr.++Note [State hack and bottoming functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's a terrible idea to use the state hack on a bottoming function.+Here's what happens (Trac #2861):++ f :: String -> IO T+ f = \p. error "..."++Eta-expand, using the state hack:++ f = \p. (\s. ((error "...") |> g1) s) |> g2+ g1 :: IO T ~ (S -> (S,T))+ g2 :: (S -> (S,T)) ~ IO T++Extrude the g2++ f' = \p. \s. ((error "...") |> g1) s+ f = f' |> (String -> g2)++Discard args for bottomming function++ f' = \p. \s. ((error "...") |> g1 |> g3+ g3 :: (S -> (S,T)) ~ (S,T)++Extrude g1.g3++ f'' = \p. \s. (error "...")+ f' = f'' |> (String -> S -> g1.g3)++And now we can repeat the whole loop. Aargh! The bug is in applying the+state hack to a function which then swallows the argument.++This arose in another guise in Trac #3959. Here we had++ catch# (throw exn >> return ())++Note that (throw :: forall a e. Exn e => e -> a) is called with [a = IO ()].+After inlining (>>) we get++ catch# (\_. throw {IO ()} exn)++We must *not* eta-expand to++ catch# (\_ _. throw {...} exn)++because 'catch#' expects to get a (# _,_ #) after applying its argument to+a State#, not another function!++In short, we use the state hack to allow us to push let inside a lambda,+but not to introduce a new lambda.+++Note [ArityType]+~~~~~~~~~~~~~~~~+ArityType is the result of a compositional analysis on expressions,+from which we can decide the real arity of the expression (extracted+with function exprEtaExpandArity).++Here is what the fields mean. If an arbitrary expression 'f' has+ArityType 'at', then++ * If at = ABot n, then (f x1..xn) definitely diverges. Partial+ applications to fewer than n args may *or may not* diverge.++ We allow ourselves to eta-expand bottoming functions, even+ if doing so may lose some `seq` sharing,+ let x = <expensive> in \y. error (g x y)+ ==> \y. let x = <expensive> in error (g x y)++ * If at = ATop as, and n=length as,+ then expanding 'f' to (\x1..xn. f x1 .. xn) loses no sharing,+ assuming the calls of f respect the one-shot-ness of+ its definition.++ NB 'f' is an arbitrary expression, eg (f = g e1 e2). This 'f'+ can have ArityType as ATop, with length as > 0, only if e1 e2 are+ themselves.++ * In both cases, f, (f x1), ... (f x1 ... f(n-1)) are definitely+ really functions, or bottom, but *not* casts from a data type, in+ at least one case branch. (If it's a function in one case branch but+ an unsafe cast from a data type in another, the program is bogus.)+ So eta expansion is dynamically ok; see Note [State hack and+ bottoming functions], the part about catch#++Example:+ f = \x\y. let v = <expensive> in+ \s(one-shot) \t(one-shot). blah+ 'f' has ArityType [ManyShot,ManyShot,OneShot,OneShot]+ The one-shot-ness means we can, in effect, push that+ 'let' inside the \st.+++Suppose f = \xy. x+y+Then f :: AT [False,False] ATop+ f v :: AT [False] ATop+ f <expensive> :: AT [] ATop++-------------------- Main arity code ----------------------------+-}++-- See Note [ArityType]+data ArityType = ATop [OneShotInfo] | ABot Arity+ -- There is always an explicit lambda+ -- to justify the [OneShot], or the Arity++vanillaArityType :: ArityType+vanillaArityType = ATop [] -- Totally uninformative++-- ^ The Arity returned is the number of value args the+-- expression can be applied to without doing much work+exprEtaExpandArity :: DynFlags -> CoreExpr -> Arity+-- exprEtaExpandArity is used when eta expanding+-- e ==> \xy -> e x y+exprEtaExpandArity dflags e+ = case (arityType env e) of+ ATop oss -> length oss+ ABot n -> n+ where+ env = AE { ae_cheap_fn = mk_cheap_fn dflags isCheapApp+ , ae_ped_bot = gopt Opt_PedanticBottoms dflags }++getBotArity :: ArityType -> Maybe Arity+-- Arity of a divergent function+getBotArity (ABot n) = Just n+getBotArity _ = Nothing++mk_cheap_fn :: DynFlags -> CheapAppFun -> CheapFun+mk_cheap_fn dflags cheap_app+ | not (gopt Opt_DictsCheap dflags)+ = \e _ -> exprIsOk cheap_app e+ | otherwise+ = \e mb_ty -> exprIsOk cheap_app e+ || case mb_ty of+ Nothing -> False+ Just ty -> isDictLikeTy ty+++----------------------+findRhsArity :: DynFlags -> Id -> CoreExpr -> Arity -> Arity+-- This implements the fixpoint loop for arity analysis+-- See Note [Arity analysis]+findRhsArity dflags bndr rhs old_arity+ = go (rhsEtaExpandArity dflags init_cheap_app rhs)+ -- We always call exprEtaExpandArity once, but usually+ -- that produces a result equal to old_arity, and then+ -- we stop right away (since arities should not decrease)+ -- Result: the common case is that there is just one iteration+ where+ init_cheap_app :: CheapAppFun+ init_cheap_app fn n_val_args+ | fn == bndr = True -- On the first pass, this binder gets infinite arity+ | otherwise = isCheapApp fn n_val_args++ go :: Arity -> Arity+ go cur_arity+ | cur_arity <= old_arity = cur_arity+ | new_arity == cur_arity = cur_arity+ | otherwise = ASSERT( new_arity < cur_arity )+#ifdef DEBUG+ pprTrace "Exciting arity"+ (vcat [ ppr bndr <+> ppr cur_arity <+> ppr new_arity+ , ppr rhs])+#endif+ go new_arity+ where+ new_arity = rhsEtaExpandArity dflags cheap_app rhs++ cheap_app :: CheapAppFun+ cheap_app fn n_val_args+ | fn == bndr = n_val_args < cur_arity+ | otherwise = isCheapApp fn n_val_args++-- ^ The Arity returned is the number of value args the+-- expression can be applied to without doing much work+rhsEtaExpandArity :: DynFlags -> CheapAppFun -> CoreExpr -> Arity+-- exprEtaExpandArity is used when eta expanding+-- e ==> \xy -> e x y+rhsEtaExpandArity dflags cheap_app e+ = case (arityType env e) of+ ATop (os:oss)+ | isOneShotInfo os || has_lam e -> 1 + length oss+ -- Don't expand PAPs/thunks+ -- Note [Eta expanding thunks]+ | otherwise -> 0+ ATop [] -> 0+ ABot n -> n+ where+ env = AE { ae_cheap_fn = mk_cheap_fn dflags cheap_app+ , ae_ped_bot = gopt Opt_PedanticBottoms dflags }++ has_lam (Tick _ e) = has_lam e+ has_lam (Lam b e) = isId b || has_lam e+ has_lam _ = False++{-+Note [Arity analysis]+~~~~~~~~~~~~~~~~~~~~~+The motivating example for arity analysis is this:++ f = \x. let g = f (x+1)+ in \y. ...g...++What arity does f have? Really it should have arity 2, but a naive+look at the RHS won't see that. You need a fixpoint analysis which+says it has arity "infinity" the first time round.++This example happens a lot; it first showed up in Andy Gill's thesis,+fifteen years ago! It also shows up in the code for 'rnf' on lists+in Trac #4138.++The analysis is easy to achieve because exprEtaExpandArity takes an+argument+ type CheapFun = CoreExpr -> Maybe Type -> Bool+used to decide if an expression is cheap enough to push inside a+lambda. And exprIsCheap' in turn takes an argument+ type CheapAppFun = Id -> Int -> Bool+which tells when an application is cheap. This makes it easy to+write the analysis loop.++The analysis is cheap-and-cheerful because it doesn't deal with+mutual recursion. But the self-recursive case is the important one.+++Note [Eta expanding through dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the experimental -fdicts-cheap flag is on, we eta-expand through+dictionary bindings. This improves arities. Thereby, it also+means that full laziness is less prone to floating out the+application of a function to its dictionary arguments, which+can thereby lose opportunities for fusion. Example:+ foo :: Ord a => a -> ...+ foo = /\a \(d:Ord a). let d' = ...d... in \(x:a). ....+ -- So foo has arity 1++ f = \x. foo dInt $ bar x++The (foo DInt) is floated out, and makes ineffective a RULE+ foo (bar x) = ...++One could go further and make exprIsCheap reply True to any+dictionary-typed expression, but that's more work.++See Note [Dictionary-like types] in TcType.hs for why we use+isDictLikeTy here rather than isDictTy++Note [Eta expanding thunks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't eta-expand+ * Trivial RHSs x = y+ * PAPs x = map g+ * Thunks f = case y of p -> \x -> blah++When we see+ f = case y of p -> \x -> blah+should we eta-expand it? Well, if 'x' is a one-shot state token+then 'yes' because 'f' will only be applied once. But otherwise+we (conservatively) say no. My main reason is to avoid expanding+PAPSs+ f = g d ==> f = \x. g d x+because that might in turn make g inline (if it has an inline pragma),+which we might not want. After all, INLINE pragmas say "inline only+when saturated" so we don't want to be too gung-ho about saturating!+-}++arityLam :: Id -> ArityType -> ArityType+arityLam id (ATop as) = ATop (idStateHackOneShotInfo id : as)+arityLam _ (ABot n) = ABot (n+1)++floatIn :: Bool -> ArityType -> ArityType+-- We have something like (let x = E in b),+-- where b has the given arity type.+floatIn _ (ABot n) = ABot n+floatIn True (ATop as) = ATop as+floatIn False (ATop as) = ATop (takeWhile isOneShotInfo as)+ -- If E is not cheap, keep arity only for one-shots++arityApp :: ArityType -> Bool -> ArityType+-- Processing (fun arg) where at is the ArityType of fun,+-- Knock off an argument and behave like 'let'+arityApp (ABot 0) _ = ABot 0+arityApp (ABot n) _ = ABot (n-1)+arityApp (ATop []) _ = ATop []+arityApp (ATop (_:as)) cheap = floatIn cheap (ATop as)++andArityType :: ArityType -> ArityType -> ArityType -- Used for branches of a 'case'+andArityType (ABot n1) (ABot n2) = ABot (n1 `max` n2) -- Note [ABot branches: use max]+andArityType (ATop as) (ABot _) = ATop as+andArityType (ABot _) (ATop bs) = ATop bs+andArityType (ATop as) (ATop bs) = ATop (as `combine` bs)+ where -- See Note [Combining case branches]+ combine (a:as) (b:bs) = (a `bestOneShot` b) : combine as bs+ combine [] bs = takeWhile isOneShotInfo bs+ combine as [] = takeWhile isOneShotInfo as++{- Note [ABot branches: use max]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider case x of+ True -> \x. error "urk"+ False -> \xy. error "urk2"++Remember: ABot n means "if you apply to n args, it'll definitely diverge".+So we need (ABot 2) for the whole thing, the /max/ of the ABot arities.++Note [Combining case branches]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ go = \x. let z = go e0+ go2 = \x. case x of+ True -> z+ False -> \s(one-shot). e1+ in go2 x+We *really* want to eta-expand go and go2.+When combining the barnches of the case we have+ ATop [] `andAT` ATop [OneShotLam]+and we want to get ATop [OneShotLam]. But if the inner+lambda wasn't one-shot we don't want to do this.+(We need a proper arity analysis to justify that.)++So we combine the best of the two branches, on the (slightly dodgy)+basis that if we know one branch is one-shot, then they all must be.+-}++---------------------------+type CheapFun = CoreExpr -> Maybe Type -> Bool+ -- How to decide if an expression is cheap+ -- If the Maybe is Just, the type is the type+ -- of the expression; Nothing means "don't know"++data ArityEnv+ = AE { ae_cheap_fn :: CheapFun+ , ae_ped_bot :: Bool -- True <=> be pedantic about bottoms+ }++arityType :: ArityEnv -> CoreExpr -> ArityType++arityType env (Cast e co)+ = case arityType env e of+ ATop os -> ATop (take co_arity os)+ ABot n -> ABot (n `min` co_arity)+ where+ co_arity = length (typeArity (pSnd (coercionKind co)))+ -- See Note [exprArity invariant] (2); must be true of+ -- arityType too, since that is how we compute the arity+ -- of variables, and they in turn affect result of exprArity+ -- Trac #5441 is a nice demo+ -- However, do make sure that ATop -> ATop and ABot -> ABot!+ -- Casts don't affect that part. Getting this wrong provoked #5475++arityType _ (Var v)+ | strict_sig <- idStrictness v+ , not $ isTopSig strict_sig+ , (ds, res) <- splitStrictSig strict_sig+ , let arity = length ds+ = if isBotRes res then ABot arity+ else ATop (take arity one_shots)+ | otherwise+ = ATop (take (idArity v) one_shots)+ where+ one_shots :: [OneShotInfo] -- One-shot-ness derived from the type+ one_shots = typeArity (idType v)++ -- Lambdas; increase arity+arityType env (Lam x e)+ | isId x = arityLam x (arityType env e)+ | otherwise = arityType env e++ -- Applications; decrease arity, except for types+arityType env (App fun (Type _))+ = arityType env fun+arityType env (App fun arg )+ = arityApp (arityType env fun) (ae_cheap_fn env arg Nothing)++ -- Case/Let; keep arity if either the expression is cheap+ -- or it's a 1-shot lambda+ -- The former is not really right for Haskell+ -- f x = case x of { (a,b) -> \y. e }+ -- ===>+ -- f x y = case x of { (a,b) -> e }+ -- The difference is observable using 'seq'+ --+arityType env (Case scrut _ _ alts)+ | exprIsBottom scrut || null alts+ = ABot 0 -- Do not eta expand+ -- See Note [Dealing with bottom (1)]+ | otherwise+ = case alts_type of+ ABot n | n>0 -> ATop [] -- Don't eta expand+ | otherwise -> ABot 0 -- if RHS is bottomming+ -- See Note [Dealing with bottom (2)]++ ATop as | not (ae_ped_bot env) -- See Note [Dealing with bottom (3)]+ , ae_cheap_fn env scrut Nothing -> ATop as+ | exprOkForSpeculation scrut -> ATop as+ | otherwise -> ATop (takeWhile isOneShotInfo as)+ where+ alts_type = foldr1 andArityType [arityType env rhs | (_,_,rhs) <- alts]++arityType env (Let b e)+ = floatIn (cheap_bind b) (arityType env e)+ where+ cheap_bind (NonRec b e) = is_cheap (b,e)+ cheap_bind (Rec prs) = all is_cheap prs+ is_cheap (b,e) = ae_cheap_fn env e (Just (idType b))++arityType env (Tick t e)+ | not (tickishIsCode t) = arityType env e++arityType _ _ = vanillaArityType++{-+%************************************************************************+%* *+ The main eta-expander+%* *+%************************************************************************++We go for:+ f = \x1..xn -> N ==> f = \x1..xn y1..ym -> N y1..ym+ (n >= 0)++where (in both cases)++ * The xi can include type variables++ * The yi are all value variables++ * N is a NORMAL FORM (i.e. no redexes anywhere)+ wanting a suitable number of extra args.++The biggest reason for doing this is for cases like++ f = \x -> case x of+ True -> \y -> e1+ False -> \y -> e2++Here we want to get the lambdas together. A good example is the nofib+program fibheaps, which gets 25% more allocation if you don't do this+eta-expansion.++We may have to sandwich some coerces between the lambdas+to make the types work. exprEtaExpandArity looks through coerces+when computing arity; and etaExpand adds the coerces as necessary when+actually computing the expansion.++Note [No crap in eta-expanded code]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The eta expander is careful not to introduce "crap". In particular,+given a CoreExpr satisfying the 'CpeRhs' invariant (in CorePrep), it+returns a CoreExpr satisfying the same invariant. See Note [Eta+expansion and the CorePrep invariants] in CorePrep.++This means the eta-expander has to do a bit of on-the-fly+simplification but it's not too hard. The alernative, of relying on+a subsequent clean-up phase of the Simplifier to de-crapify the result,+means you can't really use it in CorePrep, which is painful.++Note [Eta expansion and SCCs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note that SCCs are not treated specially by etaExpand. If we have+ etaExpand 2 (\x -> scc "foo" e)+ = (\xy -> (scc "foo" e) y)+So the costs of evaluating 'e' (not 'e y') are attributed to "foo"++Note [Eta expansion and source notes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+CorePrep puts floatable ticks outside of value applications, but not+type applications. As a result we might be trying to eta-expand an+expression like++ (src<...> v) @a++which we want to lead to code like++ \x -> src<...> v @a x++This means that we need to look through type applications and be ready+to re-add floats on the top.++-}++-- | @etaExpand n e@ returns an expression with+-- the same meaning as @e@, but with arity @n@.+--+-- Given:+--+-- > e' = etaExpand n e+--+-- We should have that:+--+-- > ty = exprType e = exprType e'+etaExpand :: Arity -- ^ Result should have this number of value args+ -> CoreExpr -- ^ Expression to expand+ -> CoreExpr+-- etaExpand arity e = res+-- Then 'res' has at least 'arity' lambdas at the top+--+-- etaExpand deals with for-alls. For example:+-- etaExpand 1 E+-- where E :: forall a. a -> a+-- would return+-- (/\b. \y::a -> E b y)+--+-- It deals with coerces too, though they are now rare+-- so perhaps the extra code isn't worth it++etaExpand n orig_expr+ = go n orig_expr+ where+ -- Strip off existing lambdas and casts+ -- Note [Eta expansion and SCCs]+ go 0 expr = expr+ go n (Lam v body) | isTyVar v = Lam v (go n body)+ | otherwise = Lam v (go (n-1) body)+ go n (Cast expr co) = Cast (go n expr) co+ go n expr+ = -- pprTrace "ee" (vcat [ppr orig_expr, ppr expr, ppr etas]) $+ retick $ etaInfoAbs etas (etaInfoApp subst' sexpr etas)+ where+ in_scope = mkInScopeSet (exprFreeVars expr)+ (in_scope', etas) = mkEtaWW n orig_expr in_scope (exprType expr)+ subst' = mkEmptySubst in_scope'++ -- Find ticks behind type apps.+ -- See Note [Eta expansion and source notes]+ (expr', args) = collectArgs expr+ (ticks, expr'') = stripTicksTop tickishFloatable expr'+ sexpr = foldl App expr'' args+ retick expr = foldr mkTick expr ticks++ -- Wrapper Unwrapper+--------------+data EtaInfo = EtaVar Var -- /\a. [], [] a+ -- \x. [], [] x+ | EtaCo Coercion -- [] |> co, [] |> (sym co)++instance Outputable EtaInfo where+ ppr (EtaVar v) = text "EtaVar" <+> ppr v+ ppr (EtaCo co) = text "EtaCo" <+> ppr co++pushCoercion :: Coercion -> [EtaInfo] -> [EtaInfo]+pushCoercion co1 (EtaCo co2 : eis)+ | isReflCo co = eis+ | otherwise = EtaCo co : eis+ where+ co = co1 `mkTransCo` co2++pushCoercion co eis = EtaCo co : eis++--------------+etaInfoAbs :: [EtaInfo] -> CoreExpr -> CoreExpr+etaInfoAbs [] expr = expr+etaInfoAbs (EtaVar v : eis) expr = Lam v (etaInfoAbs eis expr)+etaInfoAbs (EtaCo co : eis) expr = Cast (etaInfoAbs eis expr) (mkSymCo co)++--------------+etaInfoApp :: Subst -> CoreExpr -> [EtaInfo] -> CoreExpr+-- (etaInfoApp s e eis) returns something equivalent to+-- ((substExpr s e) `appliedto` eis)++etaInfoApp subst (Lam v1 e) (EtaVar v2 : eis)+ = etaInfoApp (CoreSubst.extendSubstWithVar subst v1 v2) e eis++etaInfoApp subst (Cast e co1) eis+ = etaInfoApp subst e (pushCoercion co' eis)+ where+ co' = CoreSubst.substCo subst co1++etaInfoApp subst (Case e b ty alts) eis+ = Case (subst_expr subst e) b1 (mk_alts_ty (CoreSubst.substTy subst ty) eis) alts'+ where+ (subst1, b1) = substBndr subst b+ alts' = map subst_alt alts+ subst_alt (con, bs, rhs) = (con, bs', etaInfoApp subst2 rhs eis)+ where+ (subst2,bs') = substBndrs subst1 bs++ mk_alts_ty ty [] = ty+ mk_alts_ty ty (EtaVar v : eis) = mk_alts_ty (applyTypeToArg ty (varToCoreExpr v)) eis+ mk_alts_ty _ (EtaCo co : eis) = mk_alts_ty (pSnd (coercionKind co)) eis++etaInfoApp subst (Let b e) eis+ = Let b' (etaInfoApp subst' e eis)+ where+ (subst', b') = etaInfoAppBind subst b eis++etaInfoApp subst (Tick t e) eis+ = Tick (substTickish subst t) (etaInfoApp subst e eis)++etaInfoApp subst expr _+ | (Var fun, _) <- collectArgs expr+ , Var fun' <- lookupIdSubst (text "etaInfoApp" <+> ppr fun) subst fun+ , isJoinId fun'+ = subst_expr subst expr++etaInfoApp subst e eis+ = go (subst_expr subst e) eis+ where+ go e [] = e+ go e (EtaVar v : eis) = go (App e (varToCoreExpr v)) eis+ go e (EtaCo co : eis) = go (Cast e co) eis++--------------+-- | Apply the eta info to a local binding. Mostly delegates to+-- `etaInfoAppLocalBndr` and `etaInfoAppRhs`.+etaInfoAppBind :: Subst -> CoreBind -> [EtaInfo] -> (Subst, CoreBind)+etaInfoAppBind subst (NonRec bndr rhs) eis+ = (subst', NonRec bndr' rhs')+ where+ bndr_w_new_type = etaInfoAppLocalBndr bndr eis+ (subst', bndr1) = substBndr subst bndr_w_new_type+ rhs' = etaInfoAppRhs subst bndr1 rhs eis+ bndr' | isJoinId bndr = bndr1 `setIdArity` manifestArity rhs'+ -- Arity may have changed+ -- (see etaInfoAppRhs example)+ | otherwise = bndr1+etaInfoAppBind subst (Rec pairs) eis+ = (subst', Rec (bndrs' `zip` rhss'))+ where+ (bndrs, rhss) = unzip pairs+ bndrs_w_new_types = map (\bndr -> etaInfoAppLocalBndr bndr eis) bndrs+ (subst', bndrs1) = substRecBndrs subst bndrs_w_new_types+ rhss' = zipWith process bndrs1 rhss+ process bndr' rhs = etaInfoAppRhs subst' bndr' rhs eis+ bndrs' | isJoinId (head bndrs)+ = [ bndr1 `setIdArity` manifestArity rhs'+ | (bndr1, rhs') <- bndrs1 `zip` rhss' ]+ -- Arities may have changed+ -- (see etaInfoAppRhs example)+ | otherwise+ = bndrs1++--------------+-- | Apply the eta info to a binder's RHS. Only interesting for a join point,+-- where we might have this:+-- join j :: a -> [a] -> [a]+-- j x = \xs -> x : xs in jump j z+-- Eta-expanding produces this:+-- \ys -> (join j :: a -> [a] -> [a]+-- j x = \xs -> x : xs in jump j z) ys+-- Now when we push the application to ys inward (see Note [No crap in+-- eta-expanded code]), it goes to the body of the RHS of the join point (after+-- the lambda x!):+-- \ys -> join j :: a -> [a]+-- j x = x : ys in jump j z+-- Note that the type and arity of j have both changed.+etaInfoAppRhs :: Subst -> CoreBndr -> CoreExpr -> [EtaInfo] -> CoreExpr+etaInfoAppRhs subst bndr expr eis+ | Just arity <- isJoinId_maybe bndr+ = do_join_point arity+ | otherwise+ = subst_expr subst expr+ where+ do_join_point arity = mkLams join_bndrs' join_body'+ where+ (join_bndrs, join_body) = collectNBinders arity expr+ (subst', join_bndrs') = substBndrs subst join_bndrs+ join_body' = etaInfoApp subst' join_body eis+++--------------+-- | Apply the eta info to a local binder. A join point will have the EtaInfos+-- applied to its RHS, so its type may change. See comment on etaInfoAppRhs for+-- an example. See Note [No crap in eta-expanded code] for why all this is+-- necessary.+etaInfoAppLocalBndr :: CoreBndr -> [EtaInfo] -> CoreBndr+etaInfoAppLocalBndr bndr orig_eis+ = case isJoinId_maybe bndr of+ Just arity -> bndr `setIdType` modifyJoinResTy arity (app orig_eis) ty+ Nothing -> bndr+ where+ ty = idType bndr++ -- | Apply the given EtaInfos to the result type of the join point.+ app :: [EtaInfo] -- To apply+ -> Type -- Result type of join point+ -> Type -- New result type+ app [] ty+ = ty+ app (EtaVar v : eis) ty+ | isId v = app eis (funResultTy ty)+ | otherwise = app eis (piResultTy ty (mkTyVarTy v))+ app (EtaCo co : eis) ty+ = ASSERT2(from_ty `eqType` ty, fsep ([text "can't apply", ppr orig_eis,+ text "to", ppr bndr <+> dcolon <+>+ ppr (idType bndr)]))+ app eis to_ty+ where+ Pair from_ty to_ty = coercionKind co++--------------+mkEtaWW :: Arity -> CoreExpr -> InScopeSet -> Type+ -> (InScopeSet, [EtaInfo])+ -- EtaInfo contains fresh variables,+ -- not free in the incoming CoreExpr+ -- Outgoing InScopeSet includes the EtaInfo vars+ -- and the original free vars++mkEtaWW orig_n orig_expr in_scope orig_ty+ = go orig_n empty_subst orig_ty []+ where+ empty_subst = mkEmptyTCvSubst in_scope++ go n subst ty eis -- See Note [exprArity invariant]+ | n == 0+ = (getTCvInScope subst, reverse eis)++ | Just (tv,ty') <- splitForAllTy_maybe ty+ , let (subst', tv') = Type.substTyVarBndr subst tv+ -- Avoid free vars of the original expression+ = go n subst' ty' (EtaVar tv' : eis)++ | Just (arg_ty, res_ty) <- splitFunTy_maybe ty+ , not (isTypeLevPoly arg_ty)+ -- See Note [Levity polymorphism invariants] in CoreSyn+ -- See also test case typecheck/should_run/EtaExpandLevPoly++ , let (subst', eta_id') = freshEtaId n subst arg_ty+ -- Avoid free vars of the original expression+ = go (n-1) subst' res_ty (EtaVar eta_id' : eis)++ | Just (co, ty') <- topNormaliseNewType_maybe ty+ = -- Given this:+ -- newtype T = MkT ([T] -> Int)+ -- Consider eta-expanding this+ -- eta_expand 1 e T+ -- We want to get+ -- coerce T (\x::[T] -> (coerce ([T]->Int) e) x)+ go n subst ty' (EtaCo co : eis)++ | otherwise -- We have an expression of arity > 0,+ -- but its type isn't a function, or a binder+ -- is levity-polymorphic+ = WARN( True, (ppr orig_n <+> ppr orig_ty) $$ ppr orig_expr )+ (getTCvInScope subst, reverse eis)+ -- This *can* legitmately happen:+ -- e.g. coerce Int (\x. x) Essentially the programmer is+ -- playing fast and loose with types (Happy does this a lot).+ -- So we simply decline to eta-expand. Otherwise we'd end up+ -- with an explicit lambda having a non-function type++++--------------+-- Don't use short-cutting substitution - we may be changing the types of join+-- points, so applying the in-scope set is necessary+-- TODO Check if we actually *are* changing any join points' types++subst_expr :: Subst -> CoreExpr -> CoreExpr+subst_expr = substExpr (text "CoreArity:substExpr")+++--------------++-- | Split an expression into the given number of binders and a body,+-- eta-expanding if necessary. Counts value *and* type binders.+etaExpandToJoinPoint :: JoinArity -> CoreExpr -> ([CoreBndr], CoreExpr)+etaExpandToJoinPoint join_arity expr+ = go join_arity [] expr+ where+ go 0 rev_bs e = (reverse rev_bs, e)+ go n rev_bs (Lam b e) = go (n-1) (b : rev_bs) e+ go n rev_bs e = case etaBodyForJoinPoint n e of+ (bs, e') -> (reverse rev_bs ++ bs, e')++etaExpandToJoinPointRule :: JoinArity -> CoreRule -> CoreRule+etaExpandToJoinPointRule _ rule@(BuiltinRule {})+ = WARN(True, (sep [text "Can't eta-expand built-in rule:", ppr rule]))+ -- How did a local binding get a built-in rule anyway? Probably a plugin.+ rule+etaExpandToJoinPointRule join_arity rule@(Rule { ru_bndrs = bndrs, ru_rhs = rhs+ , ru_args = args })+ | need_args == 0+ = rule+ | need_args < 0+ = pprPanic "etaExpandToJoinPointRule" (ppr join_arity $$ ppr rule)+ | otherwise+ = rule { ru_bndrs = bndrs ++ new_bndrs, ru_args = args ++ new_args+ , ru_rhs = new_rhs }+ where+ need_args = join_arity - length args+ (new_bndrs, new_rhs) = etaBodyForJoinPoint need_args rhs+ new_args = varsToCoreExprs new_bndrs++-- Adds as many binders as asked for; assumes expr is not a lambda+etaBodyForJoinPoint :: Int -> CoreExpr -> ([CoreBndr], CoreExpr)+etaBodyForJoinPoint need_args body+ = go need_args (exprType body) (init_subst body) [] body+ where+ go 0 _ _ rev_bs e+ = (reverse rev_bs, e)+ go n ty subst rev_bs e+ | Just (tv, res_ty) <- splitForAllTy_maybe ty+ , let (subst', tv') = Type.substTyVarBndr subst tv+ = go (n-1) res_ty subst' (tv' : rev_bs) (e `App` Type (mkTyVarTy tv'))+ | Just (arg_ty, res_ty) <- splitFunTy_maybe ty+ , let (subst', b) = freshEtaId n subst arg_ty+ = go (n-1) res_ty subst' (b : rev_bs) (e `App` Var b)+ | otherwise+ = pprPanic "etaBodyForJoinPoint" $ int need_args $$+ ppr body $$ ppr (exprType body)++ init_subst e = mkEmptyTCvSubst (mkInScopeSet (exprFreeVars e))++--------------+freshEtaId :: Int -> TCvSubst -> Type -> (TCvSubst, Id)+-- Make a fresh Id, with specified type (after applying substitution)+-- It should be "fresh" in the sense that it's not in the in-scope set+-- of the TvSubstEnv; and it should itself then be added to the in-scope+-- set of the TvSubstEnv+--+-- The Int is just a reasonable starting point for generating a unique;+-- it does not necessarily have to be unique itself.+freshEtaId n subst ty+ = (subst', eta_id')+ where+ ty' = Type.substTy subst ty+ eta_id' = uniqAway (getTCvInScope subst) $+ mkSysLocalOrCoVar (fsLit "eta") (mkBuiltinUnique n) ty'+ subst' = extendTCvInScope subst eta_id'
+ coreSyn/CoreFVs.hs view
@@ -0,0 +1,825 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++Taken quite directly from the Peyton Jones/Lester paper.+-}++{-# LANGUAGE CPP #-}++-- | A module concerned with finding the free variables of an expression.+module CoreFVs (+ -- * Free variables of expressions and binding groups+ exprFreeVars,+ exprFreeVarsDSet,+ exprFreeVarsList,+ exprFreeIds,+ exprFreeIdsDSet,+ exprFreeIdsList,+ exprsFreeIdsDSet,+ exprsFreeIdsList,+ exprsFreeVars,+ exprsFreeVarsList,+ bindFreeVars,++ -- * Selective free variables of expressions+ InterestingVarFun,+ exprSomeFreeVars, exprsSomeFreeVars,+ exprSomeFreeVarsList, exprsSomeFreeVarsList,++ -- * Free variables of Rules, Vars and Ids+ varTypeTyCoVars,+ varTypeTyCoFVs,+ idUnfoldingVars, idFreeVars, dIdFreeVars,+ bndrRuleAndUnfoldingVarsDSet,+ idFVs,+ idRuleVars, idRuleRhsVars, stableUnfoldingVars,+ ruleRhsFreeVars, ruleFreeVars, rulesFreeVars,+ rulesFreeVarsDSet,+ ruleLhsFreeIds, ruleLhsFreeIdsList,+ vectsFreeVars,++ expr_fvs,++ -- * Orphan names+ orphNamesOfType, orphNamesOfCo, orphNamesOfAxiom,+ orphNamesOfTypes, orphNamesOfCoCon,+ exprsOrphNames, orphNamesOfFamInst,++ -- * Core syntax tree annotation with free variables+ FVAnn, -- annotation, abstract+ CoreExprWithFVs, -- = AnnExpr Id FVAnn+ CoreExprWithFVs', -- = AnnExpr' Id FVAnn+ CoreBindWithFVs, -- = AnnBind Id FVAnn+ CoreAltWithFVs, -- = AnnAlt Id FVAnn+ freeVars, -- CoreExpr -> CoreExprWithFVs+ freeVarsBind, -- CoreBind -> DVarSet -> (DVarSet, CoreBindWithFVs)+ freeVarsOf, -- CoreExprWithFVs -> DIdSet+ freeVarsOfType, -- CoreExprWithFVs -> TyCoVarSet+ freeVarsOfAnn, freeVarsOfTypeAnn,+ exprTypeFV -- CoreExprWithFVs -> Type+ ) where++#include "HsVersions.h"++import CoreSyn+import Id+import IdInfo+import NameSet+import UniqSet+import Unique (Uniquable (..))+import Literal ( literalType )+import Name+import VarSet+import Var+import Type+import TyCoRep+import TyCon+import CoAxiom+import FamInstEnv+import TysPrim( funTyConName )+import Coercion+import Maybes( orElse )+import Util+import BasicTypes( Activation )+import Outputable+import FV++{-+************************************************************************+* *+\section{Finding the free variables of an expression}+* *+************************************************************************++This function simply finds the free variables of an expression.+So far as type variables are concerned, it only finds tyvars that are++ * free in type arguments,+ * free in the type of a binder,++but not those that are free in the type of variable occurrence.+-}++-- | Find all locally-defined free Ids or type variables in an expression+-- returning a non-deterministic set.+exprFreeVars :: CoreExpr -> VarSet+exprFreeVars = fvVarSet . exprFVs++-- | Find all locally-defined free Ids or type variables in an expression+-- returning a composable FV computation. See Note [FV naming conventions] in FV+-- for why export it.+exprFVs :: CoreExpr -> FV+exprFVs = filterFV isLocalVar . expr_fvs++-- | Find all locally-defined free Ids or type variables in an expression+-- returning a deterministic set.+exprFreeVarsDSet :: CoreExpr -> DVarSet+exprFreeVarsDSet = fvDVarSet . exprFVs++-- | Find all locally-defined free Ids or type variables in an expression+-- returning a deterministically ordered list.+exprFreeVarsList :: CoreExpr -> [Var]+exprFreeVarsList = fvVarList . exprFVs++-- | Find all locally-defined free Ids in an expression+exprFreeIds :: CoreExpr -> IdSet -- Find all locally-defined free Ids+exprFreeIds = exprSomeFreeVars isLocalId++-- | Find all locally-defined free Ids in an expression+-- returning a deterministic set.+exprFreeIdsDSet :: CoreExpr -> DIdSet -- Find all locally-defined free Ids+exprFreeIdsDSet = exprSomeFreeVarsDSet isLocalId++-- | Find all locally-defined free Ids in an expression+-- returning a deterministically ordered list.+exprFreeIdsList :: CoreExpr -> [Id] -- Find all locally-defined free Ids+exprFreeIdsList = exprSomeFreeVarsList isLocalId++-- | Find all locally-defined free Ids in several expressions+-- returning a deterministic set.+exprsFreeIdsDSet :: [CoreExpr] -> DIdSet -- Find all locally-defined free Ids+exprsFreeIdsDSet = exprsSomeFreeVarsDSet isLocalId++-- | Find all locally-defined free Ids in several expressions+-- returning a deterministically ordered list.+exprsFreeIdsList :: [CoreExpr] -> [Id] -- Find all locally-defined free Ids+exprsFreeIdsList = exprsSomeFreeVarsList isLocalId++-- | Find all locally-defined free Ids or type variables in several expressions+-- returning a non-deterministic set.+exprsFreeVars :: [CoreExpr] -> VarSet+exprsFreeVars = fvVarSet . exprsFVs++-- | Find all locally-defined free Ids or type variables in several expressions+-- returning a composable FV computation. See Note [FV naming conventions] in FV+-- for why export it.+exprsFVs :: [CoreExpr] -> FV+exprsFVs exprs = mapUnionFV exprFVs exprs++-- | Find all locally-defined free Ids or type variables in several expressions+-- returning a deterministically ordered list.+exprsFreeVarsList :: [CoreExpr] -> [Var]+exprsFreeVarsList = fvVarList . exprsFVs++-- | Find all locally defined free Ids in a binding group+bindFreeVars :: CoreBind -> VarSet+bindFreeVars (NonRec b r) = fvVarSet $ filterFV isLocalVar $ rhs_fvs (b,r)+bindFreeVars (Rec prs) = fvVarSet $ filterFV isLocalVar $+ addBndrs (map fst prs)+ (mapUnionFV rhs_fvs prs)++-- | Finds free variables in an expression selected by a predicate+exprSomeFreeVars :: InterestingVarFun -- ^ Says which 'Var's are interesting+ -> CoreExpr+ -> VarSet+exprSomeFreeVars fv_cand e = fvVarSet $ filterFV fv_cand $ expr_fvs e++-- | Finds free variables in an expression selected by a predicate+-- returning a deterministically ordered list.+exprSomeFreeVarsList :: InterestingVarFun -- ^ Says which 'Var's are interesting+ -> CoreExpr+ -> [Var]+exprSomeFreeVarsList fv_cand e = fvVarList $ filterFV fv_cand $ expr_fvs e++-- | Finds free variables in an expression selected by a predicate+-- returning a deterministic set.+exprSomeFreeVarsDSet :: InterestingVarFun -- ^ Says which 'Var's are interesting+ -> CoreExpr+ -> DVarSet+exprSomeFreeVarsDSet fv_cand e = fvDVarSet $ filterFV fv_cand $ expr_fvs e++-- | Finds free variables in several expressions selected by a predicate+exprsSomeFreeVars :: InterestingVarFun -- Says which 'Var's are interesting+ -> [CoreExpr]+ -> VarSet+exprsSomeFreeVars fv_cand es =+ fvVarSet $ filterFV fv_cand $ mapUnionFV expr_fvs es++-- | Finds free variables in several expressions selected by a predicate+-- returning a deterministically ordered list.+exprsSomeFreeVarsList :: InterestingVarFun -- Says which 'Var's are interesting+ -> [CoreExpr]+ -> [Var]+exprsSomeFreeVarsList fv_cand es =+ fvVarList $ filterFV fv_cand $ mapUnionFV expr_fvs es++-- | Finds free variables in several expressions selected by a predicate+-- returning a deterministic set.+exprsSomeFreeVarsDSet :: InterestingVarFun -- ^ Says which 'Var's are interesting+ -> [CoreExpr]+ -> DVarSet+exprsSomeFreeVarsDSet fv_cand e =+ fvDVarSet $ filterFV fv_cand $ mapUnionFV expr_fvs e++-- Comment about obselete code+-- We used to gather the free variables the RULES at a variable occurrence+-- with the following cryptic comment:+-- "At a variable occurrence, add in any free variables of its rule rhss+-- Curiously, we gather the Id's free *type* variables from its binding+-- site, but its free *rule-rhs* variables from its usage sites. This+-- is a little weird. The reason is that the former is more efficient,+-- but the latter is more fine grained, and a makes a difference when+-- a variable mentions itself one of its own rule RHSs"+-- Not only is this "weird", but it's also pretty bad because it can make+-- a function seem more recursive than it is. Suppose+-- f = ...g...+-- g = ...+-- RULE g x = ...f...+-- Then f is not mentioned in its own RHS, and needn't be a loop breaker+-- (though g may be). But if we collect the rule fvs from g's occurrence,+-- it looks as if f mentions itself. (This bites in the eftInt/eftIntFB+-- code in GHC.Enum.)+--+-- Anyway, it seems plain wrong. The RULE is like an extra RHS for the+-- function, so its free variables belong at the definition site.+--+-- Deleted code looked like+-- foldVarSet add_rule_var var_itself_set (idRuleVars var)+-- add_rule_var var set | keep_it fv_cand in_scope var = extendVarSet set var+-- | otherwise = set+-- SLPJ Feb06++addBndr :: CoreBndr -> FV -> FV+addBndr bndr fv fv_cand in_scope acc+ = (varTypeTyCoFVs bndr `unionFV`+ -- Include type variables in the binder's type+ -- (not just Ids; coercion variables too!)+ FV.delFV bndr fv) fv_cand in_scope acc++addBndrs :: [CoreBndr] -> FV -> FV+addBndrs bndrs fv = foldr addBndr fv bndrs++expr_fvs :: CoreExpr -> FV+expr_fvs (Type ty) fv_cand in_scope acc =+ tyCoFVsOfType ty fv_cand in_scope acc+expr_fvs (Coercion co) fv_cand in_scope acc =+ tyCoFVsOfCo co fv_cand in_scope acc+expr_fvs (Var var) fv_cand in_scope acc = FV.unitFV var fv_cand in_scope acc+expr_fvs (Lit _) fv_cand in_scope acc = emptyFV fv_cand in_scope acc+expr_fvs (Tick t expr) fv_cand in_scope acc =+ (tickish_fvs t `unionFV` expr_fvs expr) fv_cand in_scope acc+expr_fvs (App fun arg) fv_cand in_scope acc =+ (expr_fvs fun `unionFV` expr_fvs arg) fv_cand in_scope acc+expr_fvs (Lam bndr body) fv_cand in_scope acc =+ addBndr bndr (expr_fvs body) fv_cand in_scope acc+expr_fvs (Cast expr co) fv_cand in_scope acc =+ (expr_fvs expr `unionFV` tyCoFVsOfCo co) fv_cand in_scope acc++expr_fvs (Case scrut bndr ty alts) fv_cand in_scope acc+ = (expr_fvs scrut `unionFV` tyCoFVsOfType ty `unionFV` addBndr bndr+ (mapUnionFV alt_fvs alts)) fv_cand in_scope acc+ where+ alt_fvs (_, bndrs, rhs) = addBndrs bndrs (expr_fvs rhs)++expr_fvs (Let (NonRec bndr rhs) body) fv_cand in_scope acc+ = (rhs_fvs (bndr, rhs) `unionFV` addBndr bndr (expr_fvs body))+ fv_cand in_scope acc++expr_fvs (Let (Rec pairs) body) fv_cand in_scope acc+ = addBndrs (map fst pairs)+ (mapUnionFV rhs_fvs pairs `unionFV` expr_fvs body)+ fv_cand in_scope acc++---------+rhs_fvs :: (Id, CoreExpr) -> FV+rhs_fvs (bndr, rhs) = expr_fvs rhs `unionFV`+ bndrRuleAndUnfoldingFVs bndr+ -- Treat any RULES as extra RHSs of the binding++---------+exprs_fvs :: [CoreExpr] -> FV+exprs_fvs exprs = mapUnionFV expr_fvs exprs++tickish_fvs :: Tickish Id -> FV+tickish_fvs (Breakpoint _ ids) = FV.mkFVs ids+tickish_fvs _ = emptyFV++{-+************************************************************************+* *+\section{Free names}+* *+************************************************************************+-}++-- | Finds the free /external/ names of an expression, notably+-- including the names of type constructors (which of course do not show+-- up in 'exprFreeVars').+exprOrphNames :: CoreExpr -> NameSet+-- There's no need to delete local binders, because they will all+-- be /internal/ names.+exprOrphNames e+ = go e+ where+ go (Var v)+ | isExternalName n = unitNameSet n+ | otherwise = emptyNameSet+ where n = idName v+ go (Lit _) = emptyNameSet+ go (Type ty) = orphNamesOfType ty -- Don't need free tyvars+ go (Coercion co) = orphNamesOfCo co+ go (App e1 e2) = go e1 `unionNameSet` go e2+ go (Lam v e) = go e `delFromNameSet` idName v+ go (Tick _ e) = go e+ go (Cast e co) = go e `unionNameSet` orphNamesOfCo co+ go (Let (NonRec _ r) e) = go e `unionNameSet` go r+ go (Let (Rec prs) e) = exprsOrphNames (map snd prs) `unionNameSet` go e+ go (Case e _ ty as) = go e `unionNameSet` orphNamesOfType ty+ `unionNameSet` unionNameSets (map go_alt as)++ go_alt (_,_,r) = go r++-- | Finds the free /external/ names of several expressions: see 'exprOrphNames' for details+exprsOrphNames :: [CoreExpr] -> NameSet+exprsOrphNames es = foldr (unionNameSet . exprOrphNames) emptyNameSet es+++{- **********************************************************************+%* *+ orphNamesXXX++%* *+%********************************************************************* -}++orphNamesOfTyCon :: TyCon -> NameSet+orphNamesOfTyCon tycon = unitNameSet (getName tycon) `unionNameSet` case tyConClass_maybe tycon of+ Nothing -> emptyNameSet+ Just cls -> unitNameSet (getName cls)++orphNamesOfType :: Type -> NameSet+orphNamesOfType ty | Just ty' <- coreView ty = orphNamesOfType ty'+ -- Look through type synonyms (Trac #4912)+orphNamesOfType (TyVarTy _) = emptyNameSet+orphNamesOfType (LitTy {}) = emptyNameSet+orphNamesOfType (TyConApp tycon tys) = orphNamesOfTyCon tycon+ `unionNameSet` orphNamesOfTypes tys+orphNamesOfType (ForAllTy bndr res) = orphNamesOfType (binderKind bndr)+ `unionNameSet` orphNamesOfType res+orphNamesOfType (FunTy arg res) = unitNameSet funTyConName -- NB! See Trac #8535+ `unionNameSet` orphNamesOfType arg+ `unionNameSet` orphNamesOfType res+orphNamesOfType (AppTy fun arg) = orphNamesOfType fun `unionNameSet` orphNamesOfType arg+orphNamesOfType (CastTy ty co) = orphNamesOfType ty `unionNameSet` orphNamesOfCo co+orphNamesOfType (CoercionTy co) = orphNamesOfCo co++orphNamesOfThings :: (a -> NameSet) -> [a] -> NameSet+orphNamesOfThings f = foldr (unionNameSet . f) emptyNameSet++orphNamesOfTypes :: [Type] -> NameSet+orphNamesOfTypes = orphNamesOfThings orphNamesOfType++orphNamesOfCo :: Coercion -> NameSet+orphNamesOfCo (Refl _ ty) = orphNamesOfType ty+orphNamesOfCo (TyConAppCo _ tc cos) = unitNameSet (getName tc) `unionNameSet` orphNamesOfCos cos+orphNamesOfCo (AppCo co1 co2) = orphNamesOfCo co1 `unionNameSet` orphNamesOfCo co2+orphNamesOfCo (ForAllCo _ kind_co co)+ = orphNamesOfCo kind_co `unionNameSet` orphNamesOfCo co+orphNamesOfCo (FunCo _ co1 co2) = orphNamesOfCo co1 `unionNameSet` orphNamesOfCo co2+orphNamesOfCo (CoVarCo _) = emptyNameSet+orphNamesOfCo (AxiomInstCo con _ cos) = orphNamesOfCoCon con `unionNameSet` orphNamesOfCos cos+orphNamesOfCo (UnivCo p _ t1 t2) = orphNamesOfProv p `unionNameSet` orphNamesOfType t1 `unionNameSet` orphNamesOfType t2+orphNamesOfCo (SymCo co) = orphNamesOfCo co+orphNamesOfCo (TransCo co1 co2) = orphNamesOfCo co1 `unionNameSet` orphNamesOfCo co2+orphNamesOfCo (NthCo _ co) = orphNamesOfCo co+orphNamesOfCo (LRCo _ co) = orphNamesOfCo co+orphNamesOfCo (InstCo co arg) = orphNamesOfCo co `unionNameSet` orphNamesOfCo arg+orphNamesOfCo (CoherenceCo co1 co2) = orphNamesOfCo co1 `unionNameSet` orphNamesOfCo co2+orphNamesOfCo (KindCo co) = orphNamesOfCo co+orphNamesOfCo (SubCo co) = orphNamesOfCo co+orphNamesOfCo (AxiomRuleCo _ cs) = orphNamesOfCos cs++orphNamesOfProv :: UnivCoProvenance -> NameSet+orphNamesOfProv UnsafeCoerceProv = emptyNameSet+orphNamesOfProv (PhantomProv co) = orphNamesOfCo co+orphNamesOfProv (ProofIrrelProv co) = orphNamesOfCo co+orphNamesOfProv (PluginProv _) = emptyNameSet+orphNamesOfProv (HoleProv _) = emptyNameSet++orphNamesOfCos :: [Coercion] -> NameSet+orphNamesOfCos = orphNamesOfThings orphNamesOfCo++orphNamesOfCoCon :: CoAxiom br -> NameSet+orphNamesOfCoCon (CoAxiom { co_ax_tc = tc, co_ax_branches = branches })+ = orphNamesOfTyCon tc `unionNameSet` orphNamesOfCoAxBranches branches++orphNamesOfAxiom :: CoAxiom br -> NameSet+orphNamesOfAxiom axiom+ = orphNamesOfTypes (concatMap coAxBranchLHS $ fromBranches $ coAxiomBranches axiom)+ `extendNameSet` getName (coAxiomTyCon axiom)++orphNamesOfCoAxBranches :: Branches br -> NameSet+orphNamesOfCoAxBranches+ = foldr (unionNameSet . orphNamesOfCoAxBranch) emptyNameSet . fromBranches++orphNamesOfCoAxBranch :: CoAxBranch -> NameSet+orphNamesOfCoAxBranch (CoAxBranch { cab_lhs = lhs, cab_rhs = rhs })+ = orphNamesOfTypes lhs `unionNameSet` orphNamesOfType rhs++-- | orphNamesOfAxiom collects the names of the concrete types and+-- type constructors that make up the LHS of a type family instance,+-- including the family name itself.+--+-- For instance, given `type family Foo a b`:+-- `type instance Foo (F (G (H a))) b = ...` would yield [Foo,F,G,H]+--+-- Used in the implementation of ":info" in GHCi.+orphNamesOfFamInst :: FamInst -> NameSet+orphNamesOfFamInst fam_inst = orphNamesOfAxiom (famInstAxiom fam_inst)++{-+************************************************************************+* *+\section[freevars-everywhere]{Attaching free variables to every sub-expression}+* *+************************************************************************+-}++-- | Those variables free in the right hand side of a rule returned as a+-- non-deterministic set+ruleRhsFreeVars :: CoreRule -> VarSet+ruleRhsFreeVars (BuiltinRule {}) = noFVs+ruleRhsFreeVars (Rule { ru_fn = _, ru_bndrs = bndrs, ru_rhs = rhs })+ = fvVarSet $ filterFV isLocalVar $ addBndrs bndrs (expr_fvs rhs)+ -- See Note [Rule free var hack]++-- | Those variables free in the both the left right hand sides of a rule+-- returned as a non-deterministic set+ruleFreeVars :: CoreRule -> VarSet+ruleFreeVars = fvVarSet . ruleFVs++-- | Those variables free in the both the left right hand sides of a rule+-- returned as FV computation+ruleFVs :: CoreRule -> FV+ruleFVs (BuiltinRule {}) = emptyFV+ruleFVs (Rule { ru_fn = _do_not_include+ -- See Note [Rule free var hack]+ , ru_bndrs = bndrs+ , ru_rhs = rhs, ru_args = args })+ = filterFV isLocalVar $ addBndrs bndrs (exprs_fvs (rhs:args))++-- | Those variables free in the both the left right hand sides of rules+-- returned as FV computation+rulesFVs :: [CoreRule] -> FV+rulesFVs = mapUnionFV ruleFVs++-- | Those variables free in the both the left right hand sides of rules+-- returned as a deterministic set+rulesFreeVarsDSet :: [CoreRule] -> DVarSet+rulesFreeVarsDSet rules = fvDVarSet $ rulesFVs rules++idRuleRhsVars :: (Activation -> Bool) -> Id -> VarSet+-- Just the variables free on the *rhs* of a rule+idRuleRhsVars is_active id+ = mapUnionVarSet get_fvs (idCoreRules id)+ where+ get_fvs (Rule { ru_fn = fn, ru_bndrs = bndrs+ , ru_rhs = rhs, ru_act = act })+ | is_active act+ -- See Note [Finding rule RHS free vars] in OccAnal.hs+ = delOneFromUniqSet_Directly fvs (getUnique fn)+ -- Note [Rule free var hack]+ where+ fvs = fvVarSet $ filterFV isLocalVar $ addBndrs bndrs (expr_fvs rhs)+ get_fvs _ = noFVs++-- | Those variables free in the right hand side of several rules+rulesFreeVars :: [CoreRule] -> VarSet+rulesFreeVars rules = mapUnionVarSet ruleFreeVars rules++ruleLhsFreeIds :: CoreRule -> VarSet+-- ^ This finds all locally-defined free Ids on the left hand side of a rule+-- and returns them as a non-deterministic set+ruleLhsFreeIds = fvVarSet . ruleLhsFVIds++ruleLhsFreeIdsList :: CoreRule -> [Var]+-- ^ This finds all locally-defined free Ids on the left hand side of a rule+-- and returns them as a determinisitcally ordered list+ruleLhsFreeIdsList = fvVarList . ruleLhsFVIds++ruleLhsFVIds :: CoreRule -> FV+-- ^ This finds all locally-defined free Ids on the left hand side of a rule+-- and returns an FV computation+ruleLhsFVIds (BuiltinRule {}) = emptyFV+ruleLhsFVIds (Rule { ru_bndrs = bndrs, ru_args = args })+ = filterFV isLocalId $ addBndrs bndrs (exprs_fvs args)++{-+Note [Rule free var hack] (Not a hack any more)+~~~~~~~~~~~~~~~~~~~~~~~~~+We used not to include the Id in its own rhs free-var set.+Otherwise the occurrence analyser makes bindings recursive:+ f x y = x+y+ RULE: f (f x y) z ==> f x (f y z)+However, the occurrence analyser distinguishes "non-rule loop breakers"+from "rule-only loop breakers" (see BasicTypes.OccInfo). So it will+put this 'f' in a Rec block, but will mark the binding as a non-rule loop+breaker, which is perfectly inlinable.+-}++-- |Free variables of a vectorisation declaration+vectsFreeVars :: [CoreVect] -> VarSet+vectsFreeVars = mapUnionVarSet vectFreeVars+ where+ vectFreeVars (Vect _ rhs) = fvVarSet $ filterFV isLocalId $ expr_fvs rhs+ vectFreeVars (NoVect _) = noFVs+ vectFreeVars (VectType _ _ _) = noFVs+ vectFreeVars (VectClass _) = noFVs+ vectFreeVars (VectInst _) = noFVs+ -- this function is only concerned with values, not types++{-+************************************************************************+* *+\section[freevars-everywhere]{Attaching free variables to every sub-expression}+* *+************************************************************************++The free variable pass annotates every node in the expression with its+NON-GLOBAL free variables and type variables.+-}++data FVAnn = FVAnn { fva_fvs :: DVarSet -- free in expression+ , fva_ty_fvs :: DVarSet -- free only in expression's type+ , fva_ty :: Type -- expression's type+ }++-- | Every node in a binding group annotated with its+-- (non-global) free variables, both Ids and TyVars, and type.+type CoreBindWithFVs = AnnBind Id FVAnn+-- | Every node in an expression annotated with its+-- (non-global) free variables, both Ids and TyVars, and type.+type CoreExprWithFVs = AnnExpr Id FVAnn+type CoreExprWithFVs' = AnnExpr' Id FVAnn++-- | Every node in an expression annotated with its+-- (non-global) free variables, both Ids and TyVars, and type.+type CoreAltWithFVs = AnnAlt Id FVAnn++freeVarsOf :: CoreExprWithFVs -> DIdSet+-- ^ Inverse function to 'freeVars'+freeVarsOf (FVAnn { fva_fvs = fvs }, _) = fvs++-- | Extract the vars free in an annotated expression's type+freeVarsOfType :: CoreExprWithFVs -> DTyCoVarSet+freeVarsOfType (FVAnn { fva_ty_fvs = ty_fvs }, _) = ty_fvs++-- | Extract the type of an annotated expression. (This is cheap.)+exprTypeFV :: CoreExprWithFVs -> Type+exprTypeFV (FVAnn { fva_ty = ty }, _) = ty++-- | Extract the vars reported in a FVAnn+freeVarsOfAnn :: FVAnn -> DIdSet+freeVarsOfAnn = fva_fvs++-- | Extract the type-level vars reported in a FVAnn+freeVarsOfTypeAnn :: FVAnn -> DTyCoVarSet+freeVarsOfTypeAnn = fva_ty_fvs++noFVs :: VarSet+noFVs = emptyVarSet++aFreeVar :: Var -> DVarSet+aFreeVar = unitDVarSet++unionFVs :: DVarSet -> DVarSet -> DVarSet+unionFVs = unionDVarSet++unionFVss :: [DVarSet] -> DVarSet+unionFVss = unionDVarSets++delBindersFV :: [Var] -> DVarSet -> DVarSet+delBindersFV bs fvs = foldr delBinderFV fvs bs++delBinderFV :: Var -> DVarSet -> DVarSet+-- This way round, so we can do it multiple times using foldr++-- (b `delBinderFV` s) removes the binder b from the free variable set s,+-- but *adds* to s+--+-- the free variables of b's type+--+-- This is really important for some lambdas:+-- In (\x::a -> x) the only mention of "a" is in the binder.+--+-- Also in+-- let x::a = b in ...+-- we should really note that "a" is free in this expression.+-- It'll be pinned inside the /\a by the binding for b, but+-- it seems cleaner to make sure that a is in the free-var set+-- when it is mentioned.+--+-- This also shows up in recursive bindings. Consider:+-- /\a -> letrec x::a = x in E+-- Now, there are no explicit free type variables in the RHS of x,+-- but nevertheless "a" is free in its definition. So we add in+-- the free tyvars of the types of the binders, and include these in the+-- free vars of the group, attached to the top level of each RHS.+--+-- This actually happened in the defn of errorIO in IOBase.hs:+-- errorIO (ST io) = case (errorIO# io) of+-- _ -> bottom+-- where+-- bottom = bottom -- Never evaluated++delBinderFV b s = (s `delDVarSet` b) `unionFVs` dVarTypeTyCoVars b+ -- Include coercion variables too!++varTypeTyCoVars :: Var -> TyCoVarSet+-- Find the type/kind variables free in the type of the id/tyvar+varTypeTyCoVars var = fvVarSet $ varTypeTyCoFVs var++dVarTypeTyCoVars :: Var -> DTyCoVarSet+-- Find the type/kind/coercion variables free in the type of the id/tyvar+dVarTypeTyCoVars var = fvDVarSet $ varTypeTyCoFVs var++varTypeTyCoFVs :: Var -> FV+varTypeTyCoFVs var = tyCoFVsOfType (varType var)++idFreeVars :: Id -> VarSet+idFreeVars id = ASSERT( isId id) fvVarSet $ idFVs id++dIdFreeVars :: Id -> DVarSet+dIdFreeVars id = fvDVarSet $ idFVs id++idFVs :: Id -> FV+-- Type variables, rule variables, and inline variables+idFVs id = ASSERT( isId id)+ varTypeTyCoFVs id `unionFV`+ bndrRuleAndUnfoldingFVs id++bndrRuleAndUnfoldingVarsDSet :: Id -> DVarSet+bndrRuleAndUnfoldingVarsDSet id = fvDVarSet $ bndrRuleAndUnfoldingFVs id++bndrRuleAndUnfoldingFVs :: Id -> FV+bndrRuleAndUnfoldingFVs id+ | isId id = idRuleFVs id `unionFV` idUnfoldingFVs id+ | otherwise = emptyFV++idRuleVars ::Id -> VarSet -- Does *not* include CoreUnfolding vars+idRuleVars id = fvVarSet $ idRuleFVs id++idRuleFVs :: Id -> FV+idRuleFVs id = ASSERT( isId id)+ FV.mkFVs (dVarSetElems $ ruleInfoFreeVars (idSpecialisation id))++idUnfoldingVars :: Id -> VarSet+-- Produce free vars for an unfolding, but NOT for an ordinary+-- (non-inline) unfolding, since it is a dup of the rhs+-- and we'll get exponential behaviour if we look at both unf and rhs!+-- But do look at the *real* unfolding, even for loop breakers, else+-- we might get out-of-scope variables+idUnfoldingVars id = fvVarSet $ idUnfoldingFVs id++idUnfoldingFVs :: Id -> FV+idUnfoldingFVs id = stableUnfoldingFVs (realIdUnfolding id) `orElse` emptyFV++stableUnfoldingVars :: Unfolding -> Maybe VarSet+stableUnfoldingVars unf = fvVarSet `fmap` stableUnfoldingFVs unf++stableUnfoldingFVs :: Unfolding -> Maybe FV+stableUnfoldingFVs unf+ = case unf of+ CoreUnfolding { uf_tmpl = rhs, uf_src = src }+ | isStableSource src+ -> Just (filterFV isLocalVar $ expr_fvs rhs)+ DFunUnfolding { df_bndrs = bndrs, df_args = args }+ -> Just (filterFV isLocalVar $ FV.delFVs (mkVarSet bndrs) $ exprs_fvs args)+ -- DFuns are top level, so no fvs from types of bndrs+ _other -> Nothing+++{-+************************************************************************+* *+\subsection{Free variables (and types)}+* *+************************************************************************+-}++freeVarsBind :: CoreBind+ -> DVarSet -- Free vars of scope of binding+ -> (CoreBindWithFVs, DVarSet) -- Return free vars of binding + scope+freeVarsBind (NonRec binder rhs) body_fvs+ = ( AnnNonRec binder rhs2+ , freeVarsOf rhs2 `unionFVs` body_fvs2+ `unionFVs` bndrRuleAndUnfoldingVarsDSet binder )+ where+ rhs2 = freeVars rhs+ body_fvs2 = binder `delBinderFV` body_fvs++freeVarsBind (Rec binds) body_fvs+ = ( AnnRec (binders `zip` rhss2)+ , delBindersFV binders all_fvs )+ where+ (binders, rhss) = unzip binds+ rhss2 = map freeVars rhss+ rhs_body_fvs = foldr (unionFVs . freeVarsOf) body_fvs rhss2+ binders_fvs = fvDVarSet $ mapUnionFV bndrRuleAndUnfoldingFVs binders+ all_fvs = rhs_body_fvs `unionFVs` binders_fvs+ -- The "delBinderFV" happens after adding the idSpecVars,+ -- since the latter may add some of the binders as fvs++freeVars :: CoreExpr -> CoreExprWithFVs+-- ^ Annotate a 'CoreExpr' with its (non-global) free type and value variables at every tree node+freeVars = go+ where+ go :: CoreExpr -> CoreExprWithFVs+ go (Var v)+ = (FVAnn fvs ty_fvs (idType v), AnnVar v)+ where+ -- ToDo: insert motivating example for why we *need*+ -- to include the idSpecVars in the FV list.+ -- Actually [June 98] I don't think it's necessary+ -- fvs = fvs_v `unionVarSet` idSpecVars v++ (fvs, ty_fvs)+ | isLocalVar v = (aFreeVar v `unionFVs` ty_fvs, dVarTypeTyCoVars v)+ | otherwise = (emptyDVarSet, emptyDVarSet)++ go (Lit lit) = (FVAnn emptyDVarSet emptyDVarSet (literalType lit), AnnLit lit)+ go (Lam b body)+ = ( FVAnn { fva_fvs = b_fvs `unionFVs` (b `delBinderFV` body_fvs)+ , fva_ty_fvs = b_fvs `unionFVs` (b `delBinderFV` body_ty_fvs)+ , fva_ty = mkFunTy b_ty body_ty }+ , AnnLam b body' )+ where+ body'@(FVAnn { fva_fvs = body_fvs, fva_ty_fvs = body_ty_fvs+ , fva_ty = body_ty }, _) = go body+ b_ty = idType b+ b_fvs = tyCoVarsOfTypeDSet b_ty++ go (App fun arg)+ = ( FVAnn { fva_fvs = freeVarsOf fun' `unionFVs` freeVarsOf arg'+ , fva_ty_fvs = tyCoVarsOfTypeDSet res_ty+ , fva_ty = res_ty }+ , AnnApp fun' arg' )+ where+ fun' = go fun+ fun_ty = exprTypeFV fun'+ arg' = go arg+ res_ty = applyTypeToArg fun_ty arg++ go (Case scrut bndr ty alts)+ = ( FVAnn { fva_fvs = (bndr `delBinderFV` alts_fvs)+ `unionFVs` freeVarsOf scrut2+ `unionFVs` tyCoVarsOfTypeDSet ty+ -- don't need to look at (idType bndr)+ -- b/c that's redundant with scrut+ , fva_ty_fvs = tyCoVarsOfTypeDSet ty+ , fva_ty = ty }+ , AnnCase scrut2 bndr ty alts2 )+ where+ scrut2 = go scrut++ (alts_fvs_s, alts2) = mapAndUnzip fv_alt alts+ alts_fvs = unionFVss alts_fvs_s++ fv_alt (con,args,rhs) = (delBindersFV args (freeVarsOf rhs2),+ (con, args, rhs2))+ where+ rhs2 = go rhs++ go (Let bind body)+ = ( FVAnn { fva_fvs = bind_fvs+ , fva_ty_fvs = freeVarsOfType body2+ , fva_ty = exprTypeFV body2 }+ , AnnLet bind2 body2 )+ where+ (bind2, bind_fvs) = freeVarsBind bind (freeVarsOf body2)+ body2 = go body++ go (Cast expr co)+ = ( FVAnn (freeVarsOf expr2 `unionFVs` cfvs) (tyCoVarsOfTypeDSet to_ty) to_ty+ , AnnCast expr2 (c_ann, co) )+ where+ expr2 = go expr+ cfvs = tyCoVarsOfCoDSet co+ c_ann = FVAnn cfvs (tyCoVarsOfTypeDSet co_ki) co_ki+ co_ki = coercionType co+ Just (_, to_ty) = splitCoercionType_maybe co_ki+++ go (Tick tickish expr)+ = ( FVAnn { fva_fvs = tickishFVs tickish `unionFVs` freeVarsOf expr2+ , fva_ty_fvs = freeVarsOfType expr2+ , fva_ty = exprTypeFV expr2 }+ , AnnTick tickish expr2 )+ where+ expr2 = go expr+ tickishFVs (Breakpoint _ ids) = mkDVarSet ids+ tickishFVs _ = emptyDVarSet++ go (Type ty) = ( FVAnn (tyCoVarsOfTypeDSet ty)+ (tyCoVarsOfTypeDSet ki)+ ki+ , AnnType ty)+ where+ ki = typeKind ty++ go (Coercion co) = ( FVAnn (tyCoVarsOfCoDSet co)+ (tyCoVarsOfTypeDSet ki)+ ki+ , AnnCoercion co)+ where+ ki = coercionType co
+ coreSyn/CoreLint.hs view
@@ -0,0 +1,2478 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998+++A ``lint'' pass to check for Core correctness+-}++{-# LANGUAGE CPP #-}++module CoreLint (+ lintCoreBindings, lintUnfolding,+ lintPassResult, lintInteractiveExpr, lintExpr,+ lintAnnots,++ -- ** Debug output+ endPass, endPassIO,+ dumpPassResult,+ CoreLint.dumpIfSet,+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreFVs+import CoreUtils+import CoreStats ( coreBindsStats )+import CoreMonad+import Bag+import Literal+import DataCon+import TysWiredIn+import TysPrim+import TcType ( isFloatingTy )+import Var+import VarEnv+import VarSet+import Name+import Id+import IdInfo+import PprCore+import ErrUtils+import Coercion+import SrcLoc+import Kind+import Type+import RepType+import TyCoRep -- checks validity of types/coercions+import TyCon+import CoAxiom+import BasicTypes+import ErrUtils as Err+import ListSetOps+import PrelNames+import Outputable+import FastString+import Util+import InstEnv ( instanceDFunId )+import OptCoercion ( checkAxInstCo )+import UniqSupply+import CoreArity ( typeArity )+import Demand ( splitStrictSig, isBotRes )++import HscTypes+import DynFlags+import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif+import MonadUtils+import Data.Maybe+import Pair+import qualified GHC.LanguageExtensions as LangExt++{-+Note [GHC Formalism]+~~~~~~~~~~~~~~~~~~~~+This file implements the type-checking algorithm for System FC, the "official"+name of the Core language. Type safety of FC is heart of the claim that+executables produced by GHC do not have segmentation faults. Thus, it is+useful to be able to reason about System FC independently of reading the code.+To this purpose, there is a document core-spec.pdf built in docs/core-spec that+contains a formalism of the types and functions dealt with here. If you change+just about anything in this file or you change other types/functions throughout+the Core language (all signposted to this note), you should update that+formalism. See docs/core-spec/README for more info about how to do so.++Note [check vs lint]+~~~~~~~~~~~~~~~~~~~~+This file implements both a type checking algorithm and also general sanity+checking. For example, the "sanity checking" checks for TyConApp on the left+of an AppTy, which should never happen. These sanity checks don't really+affect any notion of type soundness. Yet, it is convenient to do the sanity+checks at the same time as the type checks. So, we use the following naming+convention:++- Functions that begin with 'lint'... are involved in type checking. These+ functions might also do some sanity checking.++- Functions that begin with 'check'... are *not* involved in type checking.+ They exist only for sanity checking.++Issues surrounding variable naming, shadowing, and such are considered *not*+to be part of type checking, as the formalism omits these details.++Summary of checks+~~~~~~~~~~~~~~~~~+Checks that a set of core bindings is well-formed. The PprStyle and String+just control what we print in the event of an error. The Bool value+indicates whether we have done any specialisation yet (in which case we do+some extra checks).++We check for+ (a) type errors+ (b) Out-of-scope type variables+ (c) Out-of-scope local variables+ (d) Ill-kinded types+ (e) Incorrect unsafe coercions++If we have done specialisation the we check that there are+ (a) No top-level bindings of primitive (unboxed type)++Outstanding issues:++ -- Things are *not* OK if:+ --+ -- * Unsaturated type app before specialisation has been done;+ --+ -- * Oversaturated type app after specialisation (eta reduction+ -- may well be happening...);+++Note [Linting function types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As described in Note [Representation of function types], all saturated+applications of funTyCon are represented with the FunTy constructor. We check+this invariant in lintType.++Note [Linting type lets]+~~~~~~~~~~~~~~~~~~~~~~~~+In the desugarer, it's very very convenient to be able to say (in effect)+ let a = Type Int in <body>+That is, use a type let. See Note [Type let] in CoreSyn.++However, when linting <body> we need to remember that a=Int, else we might+reject a correct program. So we carry a type substitution (in this example+[a -> Int]) and apply this substitution before comparing types. The functin+ lintInTy :: Type -> LintM (Type, Kind)+returns a substituted type.++When we encounter a binder (like x::a) we must apply the substitution+to the type of the binding variable. lintBinders does this.++For Ids, the type-substituted Id is added to the in_scope set (which+itself is part of the TCvSubst we are carrying down), and when we+find an occurrence of an Id, we fetch it from the in-scope set.++Note [Bad unsafe coercion]+~~~~~~~~~~~~~~~~~~~~~~~~~~+For discussion see https://ghc.haskell.org/trac/ghc/wiki/BadUnsafeCoercions+Linter introduces additional rules that checks improper coercion between+different types, called bad coercions. Following coercions are forbidden:++ (a) coercions between boxed and unboxed values;+ (b) coercions between unlifted values of the different sizes, here+ active size is checked, i.e. size of the actual value but not+ the space allocated for value;+ (c) coercions between floating and integral boxed values, this check+ is not yet supported for unboxed tuples, as no semantics were+ specified for that;+ (d) coercions from / to vector type+ (e) If types are unboxed tuples then tuple (# A_1,..,A_n #) can be+ coerced to (# B_1,..,B_m #) if n=m and for each pair A_i, B_i rules+ (a-e) holds.++Note [Join points]+~~~~~~~~~~~~~~~~~~+We check the rules listed in Note [Invariants on join points] in CoreSyn. The+only one that causes any difficulty is the first: All occurrences must be tail+calls. To this end, along with the in-scope set, we remember in le_joins the+subset of in-scope Ids that are valid join ids. For example:++ join j x = ... in+ case e of+ A -> jump j y -- good+ B -> case (jump j z) of -- BAD+ C -> join h = jump j w in ... -- good+ D -> let x = jump j v in ... -- BAD++A join point remains valid in case branches, so when checking the A+branch, j is still valid. When we check the scrutinee of the inner+case, however, we set le_joins to empty, and catch the+error. Similarly, join points can occur free in RHSes of other join+points but not the RHSes of value bindings (thunks and functions).++************************************************************************+* *+ Beginning and ending passes+* *+************************************************************************++These functions are not CoreM monad stuff, but they probably ought to+be, and it makes a conveneint place. place for them. They print out+stuff before and after core passes, and do Core Lint when necessary.+-}++endPass :: CoreToDo -> CoreProgram -> [CoreRule] -> CoreM ()+endPass pass binds rules+ = do { hsc_env <- getHscEnv+ ; print_unqual <- getPrintUnqualified+ ; liftIO $ endPassIO hsc_env print_unqual pass binds rules }++endPassIO :: HscEnv -> PrintUnqualified+ -> CoreToDo -> CoreProgram -> [CoreRule] -> IO ()+-- Used by the IO-is CorePrep too+endPassIO hsc_env print_unqual pass binds rules+ = do { dumpPassResult dflags print_unqual mb_flag+ (ppr pass) (pprPassDetails pass) binds rules+ ; lintPassResult hsc_env pass binds }+ where+ dflags = hsc_dflags hsc_env+ mb_flag = case coreDumpFlag pass of+ Just flag | dopt flag dflags -> Just flag+ | dopt Opt_D_verbose_core2core dflags -> Just flag+ _ -> Nothing++dumpIfSet :: DynFlags -> Bool -> CoreToDo -> SDoc -> SDoc -> IO ()+dumpIfSet dflags dump_me pass extra_info doc+ = Err.dumpIfSet dflags dump_me (showSDoc dflags (ppr pass <+> extra_info)) doc++dumpPassResult :: DynFlags+ -> PrintUnqualified+ -> Maybe DumpFlag -- Just df => show details in a file whose+ -- name is specified by df+ -> SDoc -- Header+ -> SDoc -- Extra info to appear after header+ -> CoreProgram -> [CoreRule]+ -> IO ()+dumpPassResult dflags unqual mb_flag hdr extra_info binds rules+ = do { forM_ mb_flag $ \flag ->+ Err.dumpSDoc dflags unqual flag (showSDoc dflags hdr) dump_doc++ -- Report result size+ -- This has the side effect of forcing the intermediate to be evaluated+ -- if it's not already forced by a -ddump flag.+ ; Err.debugTraceMsg dflags 2 size_doc+ }++ where+ size_doc = sep [text "Result size of" <+> hdr, nest 2 (equals <+> ppr (coreBindsStats binds))]++ dump_doc = vcat [ nest 2 extra_info+ , size_doc+ , blankLine+ , pprCoreBindingsWithSize binds+ , ppUnless (null rules) pp_rules ]+ pp_rules = vcat [ blankLine+ , text "------ Local rules for imported ids --------"+ , pprRules rules ]++coreDumpFlag :: CoreToDo -> Maybe DumpFlag+coreDumpFlag (CoreDoSimplify {}) = Just Opt_D_verbose_core2core+coreDumpFlag (CoreDoPluginPass {}) = Just Opt_D_verbose_core2core+coreDumpFlag CoreDoFloatInwards = Just Opt_D_verbose_core2core+coreDumpFlag (CoreDoFloatOutwards {}) = Just Opt_D_verbose_core2core+coreDumpFlag CoreLiberateCase = Just Opt_D_verbose_core2core+coreDumpFlag CoreDoStaticArgs = Just Opt_D_verbose_core2core+coreDumpFlag CoreDoCallArity = Just Opt_D_dump_call_arity+coreDumpFlag CoreDoStrictness = Just Opt_D_dump_stranal+coreDumpFlag CoreDoWorkerWrapper = Just Opt_D_dump_worker_wrapper+coreDumpFlag CoreDoSpecialising = Just Opt_D_dump_spec+coreDumpFlag CoreDoSpecConstr = Just Opt_D_dump_spec+coreDumpFlag CoreCSE = Just Opt_D_dump_cse+coreDumpFlag CoreDoVectorisation = Just Opt_D_dump_vect+coreDumpFlag CoreDesugar = Just Opt_D_dump_ds+coreDumpFlag CoreDesugarOpt = Just Opt_D_dump_ds+coreDumpFlag CoreTidy = Just Opt_D_dump_simpl+coreDumpFlag CorePrep = Just Opt_D_dump_prep+coreDumpFlag CoreOccurAnal = Just Opt_D_dump_occur_anal++coreDumpFlag CoreDoPrintCore = Nothing+coreDumpFlag (CoreDoRuleCheck {}) = Nothing+coreDumpFlag CoreDoNothing = Nothing+coreDumpFlag (CoreDoPasses {}) = Nothing++{-+************************************************************************+* *+ Top-level interfaces+* *+************************************************************************+-}++lintPassResult :: HscEnv -> CoreToDo -> CoreProgram -> IO ()+lintPassResult hsc_env pass binds+ | not (gopt Opt_DoCoreLinting dflags)+ = return ()+ | otherwise+ = do { let (warns, errs) = lintCoreBindings dflags pass (interactiveInScope hsc_env) binds+ ; Err.showPass dflags ("Core Linted result of " ++ showPpr dflags pass)+ ; displayLintResults dflags pass warns errs binds }+ where+ dflags = hsc_dflags hsc_env++displayLintResults :: DynFlags -> CoreToDo+ -> Bag Err.MsgDoc -> Bag Err.MsgDoc -> CoreProgram+ -> IO ()+displayLintResults dflags pass warns errs binds+ | not (isEmptyBag errs)+ = do { putLogMsg dflags NoReason Err.SevDump noSrcSpan+ (defaultDumpStyle dflags)+ (vcat [ lint_banner "errors" (ppr pass), Err.pprMessageBag errs+ , text "*** Offending Program ***"+ , pprCoreBindings binds+ , text "*** End of Offense ***" ])+ ; Err.ghcExit dflags 1 }++ | not (isEmptyBag warns)+ , not (hasNoDebugOutput dflags)+ , showLintWarnings pass+ = putLogMsg dflags NoReason Err.SevDump noSrcSpan+ (defaultDumpStyle dflags)+ (lint_banner "warnings" (ppr pass) $$ Err.pprMessageBag warns)++ | otherwise = return ()+ where++lint_banner :: String -> SDoc -> SDoc+lint_banner string pass = text "*** Core Lint" <+> text string+ <+> text ": in result of" <+> pass+ <+> text "***"++showLintWarnings :: CoreToDo -> Bool+-- Disable Lint warnings on the first simplifier pass, because+-- there may be some INLINE knots still tied, which is tiresomely noisy+showLintWarnings (CoreDoSimplify _ (SimplMode { sm_phase = InitialPhase })) = False+showLintWarnings _ = True++lintInteractiveExpr :: String -> HscEnv -> CoreExpr -> IO ()+lintInteractiveExpr what hsc_env expr+ | not (gopt Opt_DoCoreLinting dflags)+ = return ()+ | Just err <- lintExpr dflags (interactiveInScope hsc_env) expr+ = do { display_lint_err err+ ; Err.ghcExit dflags 1 }+ | otherwise+ = return ()+ where+ dflags = hsc_dflags hsc_env++ display_lint_err err+ = do { putLogMsg dflags NoReason Err.SevDump+ noSrcSpan (defaultDumpStyle dflags)+ (vcat [ lint_banner "errors" (text what)+ , err+ , text "*** Offending Program ***"+ , pprCoreExpr expr+ , text "*** End of Offense ***" ])+ ; Err.ghcExit dflags 1 }++interactiveInScope :: HscEnv -> [Var]+-- In GHCi we may lint expressions, or bindings arising from 'deriving'+-- clauses, that mention variables bound in the interactive context.+-- These are Local things (see Note [Interactively-bound Ids in GHCi] in HscTypes).+-- So we have to tell Lint about them, lest it reports them as out of scope.+--+-- We do this by find local-named things that may appear free in interactive+-- context. This function is pretty revolting and quite possibly not quite right.+-- When we are not in GHCi, the interactive context (hsc_IC hsc_env) is empty+-- so this is a (cheap) no-op.+--+-- See Trac #8215 for an example+interactiveInScope hsc_env+ = tyvars ++ ids+ where+ -- C.f. TcRnDriver.setInteractiveContext, Desugar.deSugarExpr+ ictxt = hsc_IC hsc_env+ (cls_insts, _fam_insts) = ic_instances ictxt+ te1 = mkTypeEnvWithImplicits (ic_tythings ictxt)+ te = extendTypeEnvWithIds te1 (map instanceDFunId cls_insts)+ ids = typeEnvIds te+ tyvars = tyCoVarsOfTypesList $ map idType ids+ -- Why the type variables? How can the top level envt have free tyvars?+ -- I think it's because of the GHCi debugger, which can bind variables+ -- f :: [t] -> [t]+ -- where t is a RuntimeUnk (see TcType)++lintCoreBindings :: DynFlags -> CoreToDo -> [Var] -> CoreProgram -> (Bag MsgDoc, Bag MsgDoc)+-- Returns (warnings, errors)+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintCoreBindings dflags pass local_in_scope binds+ = initL dflags flags in_scope_set $+ addLoc TopLevelBindings $+ lintLetBndrs TopLevel binders $+ -- Put all the top-level binders in scope at the start+ -- This is because transformation rules can bring something+ -- into use 'unexpectedly'+ do { checkL (null dups) (dupVars dups)+ ; checkL (null ext_dups) (dupExtVars ext_dups)+ ; mapM lint_bind binds }+ where+ in_scope_set = mkInScopeSet (mkVarSet local_in_scope)++ flags = LF { lf_check_global_ids = check_globals+ , lf_check_inline_loop_breakers = check_lbs+ , lf_check_static_ptrs = check_static_ptrs }++ -- See Note [Checking for global Ids]+ check_globals = case pass of+ CoreTidy -> False+ CorePrep -> False+ _ -> True++ -- See Note [Checking for INLINE loop breakers]+ check_lbs = case pass of+ CoreDesugar -> False+ CoreDesugarOpt -> False+ _ -> True++ -- See Note [Checking StaticPtrs]+ check_static_ptrs | not (xopt LangExt.StaticPointers dflags) = AllowAnywhere+ | otherwise = case pass of+ CoreDoFloatOutwards _ -> AllowAtTopLevel+ CoreTidy -> RejectEverywhere+ CorePrep -> AllowAtTopLevel+ _ -> AllowAnywhere++ binders = bindersOfBinds binds+ (_, dups) = removeDups compare binders++ -- dups_ext checks for names with different uniques+ -- but but the same External name M.n. We don't+ -- allow this at top level:+ -- M.n{r3} = ...+ -- M.n{r29} = ...+ -- because they both get the same linker symbol+ ext_dups = snd (removeDups ord_ext (map Var.varName binders))+ ord_ext n1 n2 | Just m1 <- nameModule_maybe n1+ , Just m2 <- nameModule_maybe n2+ = compare (m1, nameOccName n1) (m2, nameOccName n2)+ | otherwise = LT++ -- If you edit this function, you may need to update the GHC formalism+ -- See Note [GHC Formalism]+ lint_bind (Rec prs) = mapM_ (lintSingleBinding TopLevel Recursive) prs+ lint_bind (NonRec bndr rhs) = lintSingleBinding TopLevel NonRecursive (bndr,rhs)++{-+************************************************************************+* *+\subsection[lintUnfolding]{lintUnfolding}+* *+************************************************************************++We use this to check all unfoldings that come in from interfaces+(it is very painful to catch errors otherwise):+-}++lintUnfolding :: DynFlags+ -> SrcLoc+ -> VarSet -- Treat these as in scope+ -> CoreExpr+ -> Maybe MsgDoc -- Nothing => OK++lintUnfolding dflags locn vars expr+ | isEmptyBag errs = Nothing+ | otherwise = Just (pprMessageBag errs)+ where+ in_scope = mkInScopeSet vars+ (_warns, errs) = initL dflags defaultLintFlags in_scope linter+ linter = addLoc (ImportedUnfolding locn) $+ lintCoreExpr expr++lintExpr :: DynFlags+ -> [Var] -- Treat these as in scope+ -> CoreExpr+ -> Maybe MsgDoc -- Nothing => OK++lintExpr dflags vars expr+ | isEmptyBag errs = Nothing+ | otherwise = Just (pprMessageBag errs)+ where+ in_scope = mkInScopeSet (mkVarSet vars)+ (_warns, errs) = initL dflags defaultLintFlags in_scope linter+ linter = addLoc TopLevelBindings $+ lintCoreExpr expr++{-+************************************************************************+* *+\subsection[lintCoreBinding]{lintCoreBinding}+* *+************************************************************************++Check a core binding, returning the list of variables bound.+-}++lintSingleBinding :: TopLevelFlag -> RecFlag -> (Id, CoreExpr) -> LintM ()+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintSingleBinding top_lvl_flag rec_flag (binder,rhs)+ = addLoc (RhsOf binder) $+ -- Check the rhs+ do { ty <- lintRhs binder rhs+ ; binder_ty <- applySubstTy (idType binder)+ ; ensureEqTys binder_ty ty (mkRhsMsg binder (text "RHS") ty)++ -- Check that it's not levity-polymorphic+ -- Do this first, because otherwise isUnliftedType panics+ -- Annoyingly, this duplicates the test in lintIdBdr,+ -- because for non-rec lets we call lintSingleBinding first+ ; checkL (isJoinId binder || not (isTypeLevPoly binder_ty))+ (badBndrTyMsg binder (text "levity-polymorphic"))++ -- Check the let/app invariant+ -- See Note [CoreSyn let/app invariant] in CoreSyn+ ; checkL ( isJoinId binder+ || not (isUnliftedType binder_ty)+ || (isNonRec rec_flag && exprOkForSpeculation rhs)+ || exprIsLiteralString rhs)+ (badBndrTyMsg binder (text "unlifted"))++ -- Check that if the binder is top-level or recursive, it's not+ -- demanded. Primitive string literals are exempt as there is no+ -- computation to perform, see Note [CoreSyn top-level string literals].+ ; checkL (not (isStrictId binder)+ || (isNonRec rec_flag && not (isTopLevel top_lvl_flag))+ || exprIsLiteralString rhs)+ (mkStrictMsg binder)++ -- Check that if the binder is at the top level and has type Addr#,+ -- that it is a string literal, see+ -- Note [CoreSyn top-level string literals].+ ; checkL (not (isTopLevel top_lvl_flag && binder_ty `eqType` addrPrimTy)+ || exprIsLiteralString rhs)+ (mkTopNonLitStrMsg binder)++ ; flags <- getLintFlags++ -- Check that a join-point binder has a valid type+ -- NB: lintIdBinder has checked that it is not top-level bound+ ; case isJoinId_maybe binder of+ Nothing -> return ()+ Just arity -> checkL (isValidJoinPointType arity binder_ty)+ (mkInvalidJoinPointMsg binder binder_ty)++ ; when (lf_check_inline_loop_breakers flags+ && isStrongLoopBreaker (idOccInfo binder)+ && isInlinePragma (idInlinePragma binder))+ (addWarnL (text "INLINE binder is (non-rule) loop breaker:" <+> ppr binder))+ -- Only non-rule loop breakers inhibit inlining++ -- Check whether arity and demand type are consistent (only if demand analysis+ -- already happened)+ --+ -- Note (Apr 2014): this is actually ok. See Note [Demand analysis for trivial right-hand sides]+ -- in DmdAnal. After eta-expansion in CorePrep the rhs is no longer trivial.+ -- ; let dmdTy = idStrictness binder+ -- ; checkL (case dmdTy of+ -- StrictSig dmd_ty -> idArity binder >= dmdTypeDepth dmd_ty || exprIsTrivial rhs)+ -- (mkArityMsg binder)++ -- Check that the binder's arity is within the bounds imposed by+ -- the type and the strictness signature. See Note [exprArity invariant]+ -- and Note [Trimming arity]+ ; checkL (idArity binder <= length (typeArity (idType binder)))+ (text "idArity" <+> ppr (idArity binder) <+>+ text "exceeds typeArity" <+>+ ppr (length (typeArity (idType binder))) <> colon <+>+ ppr binder)++ ; case splitStrictSig (idStrictness binder) of+ (demands, result_info) | isBotRes result_info ->+ checkL (idArity binder <= length demands)+ (text "idArity" <+> ppr (idArity binder) <+>+ text "exceeds arity imposed by the strictness signature" <+>+ ppr (idStrictness binder) <> colon <+>+ ppr binder)+ _ -> return ()++ ; mapM_ (lintCoreRule binder binder_ty) (idCoreRules binder)+ ; lintIdUnfolding binder binder_ty (idUnfolding binder) }++ -- We should check the unfolding, if any, but this is tricky because+ -- the unfolding is a SimplifiableCoreExpr. Give up for now.++-- | Checks the RHS of bindings. It only differs from 'lintCoreExpr'+-- in that it doesn't reject occurrences of the function 'makeStatic' when they+-- appear at the top level and @lf_check_static_ptrs == AllowAtTopLevel@, and+-- for join points, it skips the outer lambdas that take arguments to the+-- join point.+--+-- See Note [Checking StaticPtrs].+lintRhs :: Id -> CoreExpr -> LintM OutType+lintRhs bndr rhs+ | Just arity <- isJoinId_maybe bndr+ = lint_join_lams arity arity True rhs+ | AlwaysTailCalled arity <- tailCallInfo (idOccInfo bndr)+ = lint_join_lams arity arity False rhs+ where+ lint_join_lams 0 _ _ rhs+ = lintCoreExpr rhs++ lint_join_lams n tot enforce (Lam var expr)+ = addLoc (LambdaBodyOf var) $+ lintBinder LambdaBind var $ \ var' ->+ do { body_ty <- lint_join_lams (n-1) tot enforce expr+ ; return $ mkLamType var' body_ty }++ lint_join_lams n tot True _other+ = failWithL $ mkBadJoinArityMsg bndr tot (tot-n)+ lint_join_lams _ _ False rhs+ = markAllJoinsBad $ lintCoreExpr rhs+ -- Future join point, not yet eta-expanded+ -- Body is not a tail position++-- Allow applications of the data constructor @StaticPtr@ at the top+-- but produce errors otherwise.+lintRhs _bndr rhs = fmap lf_check_static_ptrs getLintFlags >>= go+ where+ -- Allow occurrences of 'makeStatic' at the top-level but produce errors+ -- otherwise.+ go AllowAtTopLevel+ | (binders0, rhs') <- collectTyBinders rhs+ , Just (fun, t, info, e) <- collectMakeStaticArgs rhs'+ = markAllJoinsBad $+ foldr+ -- imitate @lintCoreExpr (Lam ...)@+ (\var loopBinders ->+ addLoc (LambdaBodyOf var) $+ lintBinder LambdaBind var $ \var' ->+ do { body_ty <- loopBinders+ ; return $ mkLamType var' body_ty }+ )+ -- imitate @lintCoreExpr (App ...)@+ (do fun_ty <- lintCoreExpr fun+ addLoc (AnExpr rhs') $ lintCoreArgs fun_ty [Type t, info, e]+ )+ binders0+ go _ = markAllJoinsBad $ lintCoreExpr rhs++lintIdUnfolding :: Id -> Type -> Unfolding -> LintM ()+lintIdUnfolding bndr bndr_ty (CoreUnfolding { uf_tmpl = rhs, uf_src = src })+ | isStableSource src+ = do { ty <- lintRhs bndr rhs+ ; ensureEqTys bndr_ty ty (mkRhsMsg bndr (text "unfolding") ty) }++lintIdUnfolding bndr bndr_ty (DFunUnfolding { df_con = con, df_bndrs = bndrs+ , df_args = args })+ = do { ty <- lintBinders LambdaBind bndrs $ \ bndrs' ->+ do { res_ty <- lintCoreArgs (dataConRepType con) args+ ; return (mkLamTypes bndrs' res_ty) }+ ; ensureEqTys bndr_ty ty (mkRhsMsg bndr (text "dfun unfolding") ty) }++lintIdUnfolding _ _ _+ = return () -- Do not Lint unstable unfoldings, because that leads+ -- to exponential behaviour; c.f. CoreFVs.idUnfoldingVars++{-+Note [Checking for INLINE loop breakers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's very suspicious if a strong loop breaker is marked INLINE.++However, the desugarer generates instance methods with INLINE pragmas+that form a mutually recursive group. Only after a round of+simplification are they unravelled. So we suppress the test for+the desugarer.++************************************************************************+* *+\subsection[lintCoreExpr]{lintCoreExpr}+* *+************************************************************************+-}++-- For OutType, OutKind, the substitution has been applied,+-- but has not been linted yet++type LintedType = Type -- Substitution applied, and type is linted+type LintedKind = Kind++lintCoreExpr :: CoreExpr -> LintM OutType+-- The returned type has the substitution from the monad+-- already applied to it:+-- lintCoreExpr e subst = exprType (subst e)+--+-- The returned "type" can be a kind, if the expression is (Type ty)++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintCoreExpr (Var var)+ = lintVarOcc var 0++lintCoreExpr (Lit lit)+ = return (literalType lit)++lintCoreExpr (Cast expr co)+ = do { expr_ty <- markAllJoinsBad $ lintCoreExpr expr+ ; co' <- applySubstCo co+ ; (_, k2, from_ty, to_ty, r) <- lintCoercion co'+ ; lintL (classifiesTypeWithValues k2)+ (text "Target of cast not # or *:" <+> ppr co)+ ; lintRole co' Representational r+ ; ensureEqTys from_ty expr_ty (mkCastErr expr co' from_ty expr_ty)+ ; return to_ty }++lintCoreExpr (Tick tickish expr)+ = do case tickish of+ Breakpoint _ ids -> forM_ ids $ \id -> do+ checkDeadIdOcc id+ lookupIdInScope id+ _ -> return ()+ markAllJoinsBadIf block_joins $ lintCoreExpr expr+ where+ block_joins = not (tickish `tickishScopesLike` SoftScope)+ -- TODO Consider whether this is the correct rule. It is consistent with+ -- the simplifier's behaviour - cost-centre-scoped ticks become part of+ -- the continuation, and thus they behave like part of an evaluation+ -- context, but soft-scoped and non-scoped ticks simply wrap the result+ -- (see Simplify.simplTick).++lintCoreExpr (Let (NonRec tv (Type ty)) body)+ | isTyVar tv+ = -- See Note [Linting type lets]+ do { ty' <- applySubstTy ty+ ; lintTyBndr tv $ \ tv' ->+ do { addLoc (RhsOf tv) $ lintTyKind tv' ty'+ -- Now extend the substitution so we+ -- take advantage of it in the body+ ; extendSubstL tv ty' $+ addLoc (BodyOfLetRec [tv]) $+ lintCoreExpr body } }++lintCoreExpr (Let (NonRec bndr rhs) body)+ | isId bndr+ = do { lintSingleBinding NotTopLevel NonRecursive (bndr,rhs)+ ; addLoc (BodyOfLetRec [bndr])+ (lintIdBndr NotTopLevel LetBind bndr $ \_ ->+ addGoodJoins [bndr] $+ lintCoreExpr body) }++ | otherwise+ = failWithL (mkLetErr bndr rhs) -- Not quite accurate++lintCoreExpr e@(Let (Rec pairs) body)+ = lintLetBndrs NotTopLevel bndrs $+ addGoodJoins bndrs $+ do { -- Check that the list of pairs is non-empty+ checkL (not (null pairs)) (emptyRec e)++ -- Check that there are no duplicated binders+ ; checkL (null dups) (dupVars dups)++ -- Check that either all the binders are joins, or none+ ; checkL (all isJoinId bndrs || all (not . isJoinId) bndrs) $+ mkInconsistentRecMsg bndrs++ ; mapM_ (lintSingleBinding NotTopLevel Recursive) pairs+ ; addLoc (BodyOfLetRec bndrs) (lintCoreExpr body) }+ where+ bndrs = map fst pairs+ (_, dups) = removeDups compare bndrs++lintCoreExpr e@(App _ _)+ = addLoc (AnExpr e) $+ do { fun_ty <- lintCoreFun fun (length args)+ ; lintCoreArgs fun_ty args }+ where+ (fun, args) = collectArgs e++lintCoreExpr (Lam var expr)+ = addLoc (LambdaBodyOf var) $+ markAllJoinsBad $+ lintBinder LambdaBind var $ \ var' ->+ do { body_ty <- lintCoreExpr expr+ ; return $ mkLamType var' body_ty }++lintCoreExpr e@(Case scrut var alt_ty alts) =+ -- Check the scrutinee+ do { let scrut_diverges = exprIsBottom scrut+ ; scrut_ty <- markAllJoinsBad $ lintCoreExpr scrut+ ; (alt_ty, _) <- lintInTy alt_ty+ ; (var_ty, _) <- lintInTy (idType var)++ -- See Note [No alternatives lint check]+ ; when (null alts) $+ do { checkL (not (exprIsHNF scrut))+ (text "No alternatives for a case scrutinee in head-normal form:" <+> ppr scrut)+ ; checkWarnL scrut_diverges+ (text "No alternatives for a case scrutinee not known to diverge for sure:" <+> ppr scrut)+ }++ -- See Note [Rules for floating-point comparisons] in PrelRules+ ; let isLitPat (LitAlt _, _ , _) = True+ isLitPat _ = False+ ; checkL (not $ isFloatingTy scrut_ty && any isLitPat alts)+ (ptext (sLit $ "Lint warning: Scrutinising floating-point " +++ "expression with literal pattern in case " +++ "analysis (see Trac #9238).")+ $$ text "scrut" <+> ppr scrut)++ ; case tyConAppTyCon_maybe (idType var) of+ Just tycon+ | debugIsOn+ , isAlgTyCon tycon+ , not (isAbstractTyCon tycon)+ , null (tyConDataCons tycon)+ , not scrut_diverges+ -> pprTrace "Lint warning: case binder's type has no constructors" (ppr var <+> ppr (idType var))+ -- This can legitimately happen for type families+ $ return ()+ _otherwise -> return ()++ -- Don't use lintIdBndr on var, because unboxed tuple is legitimate++ ; subst <- getTCvSubst+ ; ensureEqTys var_ty scrut_ty (mkScrutMsg var var_ty scrut_ty subst)++ ; lintIdBndr NotTopLevel CaseBind var $ \_ ->+ do { -- Check the alternatives+ mapM_ (lintCoreAlt scrut_ty alt_ty) alts+ ; checkCaseAlts e scrut_ty alts+ ; return alt_ty } }++-- This case can't happen; linting types in expressions gets routed through+-- lintCoreArgs+lintCoreExpr (Type ty)+ = failWithL (text "Type found as expression" <+> ppr ty)++lintCoreExpr (Coercion co)+ = do { (k1, k2, ty1, ty2, role) <- lintInCo co+ ; return (mkHeteroCoercionType role k1 k2 ty1 ty2) }++----------------------+lintVarOcc :: Var -> Int -- Number of arguments (type or value) being passed+ -> LintM Type -- returns type of the *variable*+lintVarOcc var nargs+ = do { checkL (isNonCoVarId var)+ (text "Non term variable" <+> ppr var)++ -- Cneck that the type of the occurrence is the same+ -- as the type of the binding site+ ; ty <- applySubstTy (idType var)+ ; var' <- lookupIdInScope var+ ; let ty' = idType var'+ ; ensureEqTys ty ty' $ mkBndrOccTypeMismatchMsg var' var ty' ty++ -- Check for a nested occurrence of the StaticPtr constructor.+ -- See Note [Checking StaticPtrs].+ ; lf <- getLintFlags+ ; when (nargs /= 0 && lf_check_static_ptrs lf /= AllowAnywhere) $+ checkL (idName var /= makeStaticName) $+ text "Found makeStatic nested in an expression"++ ; checkDeadIdOcc var+ ; checkJoinOcc var nargs++ ; return (idType var') }++lintCoreFun :: CoreExpr+ -> Int -- Number of arguments (type or val) being passed+ -> LintM Type -- Returns type of the *function*+lintCoreFun (Var var) nargs+ = lintVarOcc var nargs++lintCoreFun (Lam var body) nargs+ -- Act like lintCoreExpr of Lam, but *don't* call markAllJoinsBad; see+ -- Note [Beta redexes]+ | nargs /= 0+ = addLoc (LambdaBodyOf var) $+ lintBinder LambdaBind var $ \ var' ->+ do { body_ty <- lintCoreFun body (nargs - 1)+ ; return $ mkLamType var' body_ty }++lintCoreFun expr nargs+ = markAllJoinsBadIf (nargs /= 0) $+ lintCoreExpr expr++------------------+checkDeadIdOcc :: Id -> LintM ()+-- Occurrences of an Id should never be dead....+-- except when we are checking a case pattern+checkDeadIdOcc id+ | isDeadOcc (idOccInfo id)+ = do { in_case <- inCasePat+ ; checkL in_case+ (text "Occurrence of a dead Id" <+> ppr id) }+ | otherwise+ = return ()++------------------+checkJoinOcc :: Id -> JoinArity -> LintM ()+-- Check that if the occurrence is a JoinId, then so is the+-- binding site, and it's a valid join Id+checkJoinOcc var n_args+ | Just join_arity_occ <- isJoinId_maybe var+ = do { mb_join_arity_bndr <- lookupJoinId var+ ; case mb_join_arity_bndr of {+ Nothing -> -- Binder is not a join point+ addErrL (invalidJoinOcc var) ;++ Just join_arity_bndr ->++ do { checkL (join_arity_bndr == join_arity_occ) $+ -- Arity differs at binding site and occurrence+ mkJoinBndrOccMismatchMsg var join_arity_bndr join_arity_occ++ ; checkL (n_args == join_arity_occ) $+ -- Arity doesn't match #args+ mkBadJumpMsg var join_arity_occ n_args } } }++ | otherwise+ = return ()++{-+Note [No alternatives lint check]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Case expressions with no alternatives are odd beasts, and worth looking at+in the linter (cf Trac #10180). We check two things:++* exprIsHNF is false: certainly, it would be terribly wrong if the+ scrutinee was already in head normal form.++* exprIsBottom is true: we should be able to see why GHC believes the+ scrutinee is diverging for sure.++In principle, the first check is redundant: exprIsBottom == True will+always imply exprIsHNF == False. But the first check is reliable: If+exprIsHNF == True, then there definitely is a problem (exprIsHNF errs+on the right side). If the second check triggers then it may be the+case that the compiler got smarter elsewhere, and the empty case is+correct, but that exprIsBottom is unable to see it. In particular, the+empty-type check in exprIsBottom is an approximation. Therefore, this+check is not fully reliable, and we keep both around.++Note [Beta redexes]+~~~~~~~~~~~~~~~~~~~+Consider:++ join j @x y z = ... in+ (\@x y z -> jump j @x y z) @t e1 e2++This is clearly ill-typed, since the jump is inside both an application and a+lambda, either of which is enough to disqualify it as a tail call (see Note+[Invariants on join points] in CoreSyn). However, strictly from a+lambda-calculus perspective, the term doesn't go wrong---after the two beta+reductions, the jump *is* a tail call and everything is fine.++Why would we want to allow this when we have let? One reason is that a compound+beta redex (that is, one with more than one argument) has different scoping+rules: naively reducing the above example using lets will capture any free+occurrence of y in e2. More fundamentally, type lets are tricky; many passes,+such as Float Out, tacitly assume that the incoming program's type lets have+all been dealt with by the simplifier. Thus we don't want to let-bind any types+in, say, CoreSubst.simpleOptPgm, which in some circumstances can run immediately+before Float Out.++All that said, currently CoreSubst.simpleOptPgm is the only thing using this+loophole, doing so to avoid re-traversing large functions (beta-reducing a type+lambda without introducing a type let requires a substitution). TODO: Improve+simpleOptPgm so that we can forget all this ever happened.++************************************************************************+* *+\subsection[lintCoreArgs]{lintCoreArgs}+* *+************************************************************************++The basic version of these functions checks that the argument is a+subtype of the required type, as one would expect.+-}+++lintCoreArgs :: OutType -> [CoreArg] -> LintM OutType+lintCoreArgs fun_ty args = foldM lintCoreArg fun_ty args++lintCoreArg :: OutType -> CoreArg -> LintM OutType+lintCoreArg fun_ty (Type arg_ty)+ = do { checkL (not (isCoercionTy arg_ty))+ (text "Unnecessary coercion-to-type injection:"+ <+> ppr arg_ty)+ ; arg_ty' <- applySubstTy arg_ty+ ; lintTyApp fun_ty arg_ty' }++lintCoreArg fun_ty arg+ = do { arg_ty <- markAllJoinsBad $ lintCoreExpr arg+ -- See Note [Levity polymorphism invariants] in CoreSyn+ ; lintL (not (isTypeLevPoly arg_ty))+ (text "Levity-polymorphic argument:" <+>+ (ppr arg <+> dcolon <+> parens (ppr arg_ty <+> dcolon <+> ppr (typeKind arg_ty))))+ -- check for levity polymorphism first, because otherwise isUnliftedType panics++ ; checkL (not (isUnliftedType arg_ty) || exprOkForSpeculation arg)+ (mkLetAppMsg arg)+ ; lintValApp arg fun_ty arg_ty }++-----------------+lintAltBinders :: OutType -- Scrutinee type+ -> OutType -- Constructor type+ -> [OutVar] -- Binders+ -> LintM ()+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintAltBinders scrut_ty con_ty []+ = ensureEqTys con_ty scrut_ty (mkBadPatMsg con_ty scrut_ty)+lintAltBinders scrut_ty con_ty (bndr:bndrs)+ | isTyVar bndr+ = do { con_ty' <- lintTyApp con_ty (mkTyVarTy bndr)+ ; lintAltBinders scrut_ty con_ty' bndrs }+ | otherwise+ = do { con_ty' <- lintValApp (Var bndr) con_ty (idType bndr)+ ; lintAltBinders scrut_ty con_ty' bndrs }++-----------------+lintTyApp :: OutType -> OutType -> LintM OutType+lintTyApp fun_ty arg_ty+ | Just (tv,body_ty) <- splitForAllTy_maybe fun_ty+ = do { lintTyKind tv arg_ty+ ; in_scope <- getInScope+ -- substTy needs the set of tyvars in scope to avoid generating+ -- uniques that are already in scope.+ -- See Note [The substitution invariant] in TyCoRep+ ; return (substTyWithInScope in_scope [tv] [arg_ty] body_ty) }++ | otherwise+ = failWithL (mkTyAppMsg fun_ty arg_ty)++-----------------+lintValApp :: CoreExpr -> OutType -> OutType -> LintM OutType+lintValApp arg fun_ty arg_ty+ | Just (arg,res) <- splitFunTy_maybe fun_ty+ = do { ensureEqTys arg arg_ty err1+ ; return res }+ | otherwise+ = failWithL err2+ where+ err1 = mkAppMsg fun_ty arg_ty arg+ err2 = mkNonFunAppMsg fun_ty arg_ty arg++lintTyKind :: OutTyVar -> OutType -> LintM ()+-- Both args have had substitution applied++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintTyKind tyvar arg_ty+ -- Arg type might be boxed for a function with an uncommitted+ -- tyvar; notably this is used so that we can give+ -- error :: forall a:*. String -> a+ -- and then apply it to both boxed and unboxed types.+ = do { arg_kind <- lintType arg_ty+ ; unless (arg_kind `eqType` tyvar_kind)+ (addErrL (mkKindErrMsg tyvar arg_ty $$ (text "Linted Arg kind:" <+> ppr arg_kind))) }+ where+ tyvar_kind = tyVarKind tyvar++{-+************************************************************************+* *+\subsection[lintCoreAlts]{lintCoreAlts}+* *+************************************************************************+-}++checkCaseAlts :: CoreExpr -> OutType -> [CoreAlt] -> LintM ()+-- a) Check that the alts are non-empty+-- b1) Check that the DEFAULT comes first, if it exists+-- b2) Check that the others are in increasing order+-- c) Check that there's a default for infinite types+-- NB: Algebraic cases are not necessarily exhaustive, because+-- the simplifier correctly eliminates case that can't+-- possibly match.++checkCaseAlts e ty alts =+ do { checkL (all non_deflt con_alts) (mkNonDefltMsg e)+ ; checkL (increasing_tag con_alts) (mkNonIncreasingAltsMsg e)++ -- For types Int#, Word# with an infinite (well, large!) number of+ -- possible values, there should usually be a DEFAULT case+ -- But (see Note [Empty case alternatives] in CoreSyn) it's ok to+ -- have *no* case alternatives.+ -- In effect, this is a kind of partial test. I suppose it's possible+ -- that we might *know* that 'x' was 1 or 2, in which case+ -- case x of { 1 -> e1; 2 -> e2 }+ -- would be fine.+ ; checkL (isJust maybe_deflt || not is_infinite_ty || null alts)+ (nonExhaustiveAltsMsg e) }+ where+ (con_alts, maybe_deflt) = findDefault alts++ -- Check that successive alternatives have increasing tags+ increasing_tag (alt1 : rest@( alt2 : _)) = alt1 `ltAlt` alt2 && increasing_tag rest+ increasing_tag _ = True++ non_deflt (DEFAULT, _, _) = False+ non_deflt _ = True++ is_infinite_ty = case tyConAppTyCon_maybe ty of+ Nothing -> False+ Just tycon -> isPrimTyCon tycon++lintAltExpr :: CoreExpr -> OutType -> LintM ()+lintAltExpr expr ann_ty+ = do { actual_ty <- lintCoreExpr expr+ ; ensureEqTys actual_ty ann_ty (mkCaseAltMsg expr actual_ty ann_ty) }++lintCoreAlt :: OutType -- Type of scrutinee+ -> OutType -- Type of the alternative+ -> CoreAlt+ -> LintM ()+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintCoreAlt _ alt_ty (DEFAULT, args, rhs) =+ do { lintL (null args) (mkDefaultArgsMsg args)+ ; lintAltExpr rhs alt_ty }++lintCoreAlt scrut_ty alt_ty (LitAlt lit, args, rhs)+ | litIsLifted lit+ = failWithL integerScrutinisedMsg+ | otherwise+ = do { lintL (null args) (mkDefaultArgsMsg args)+ ; ensureEqTys lit_ty scrut_ty (mkBadPatMsg lit_ty scrut_ty)+ ; lintAltExpr rhs alt_ty }+ where+ lit_ty = literalType lit++lintCoreAlt scrut_ty alt_ty alt@(DataAlt con, args, rhs)+ | isNewTyCon (dataConTyCon con)+ = addErrL (mkNewTyDataConAltMsg scrut_ty alt)+ | Just (tycon, tycon_arg_tys) <- splitTyConApp_maybe scrut_ty+ = addLoc (CaseAlt alt) $ do+ { -- First instantiate the universally quantified+ -- type variables of the data constructor+ -- We've already check+ lintL (tycon == dataConTyCon con) (mkBadConMsg tycon con)+ ; let con_payload_ty = piResultTys (dataConRepType con) tycon_arg_tys++ -- And now bring the new binders into scope+ ; lintBinders CasePatBind args $ \ args' -> do+ { addLoc (CasePat alt) (lintAltBinders scrut_ty con_payload_ty args')+ ; lintAltExpr rhs alt_ty } }++ | otherwise -- Scrut-ty is wrong shape+ = addErrL (mkBadAltMsg scrut_ty alt)++{-+************************************************************************+* *+\subsection[lint-types]{Types}+* *+************************************************************************+-}++-- When we lint binders, we (one at a time and in order):+-- 1. Lint var types or kinds (possibly substituting)+-- 2. Add the binder to the in scope set, and if its a coercion var,+-- we may extend the substitution to reflect its (possibly) new kind+lintBinders :: BindingSite -> [Var] -> ([Var] -> LintM a) -> LintM a+lintBinders _ [] linterF = linterF []+lintBinders site (var:vars) linterF = lintBinder site var $ \var' ->+ lintBinders site vars $ \ vars' ->+ linterF (var':vars')++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintBinder :: BindingSite -> Var -> (Var -> LintM a) -> LintM a+lintBinder site var linterF+ | isTyVar var = lintTyBndr var linterF+ | isCoVar var = lintCoBndr var linterF+ | otherwise = lintIdBndr NotTopLevel site var linterF++lintTyBndr :: InTyVar -> (OutTyVar -> LintM a) -> LintM a+lintTyBndr tv thing_inside+ = do { subst <- getTCvSubst+ ; let (subst', tv') = substTyVarBndr subst tv+ ; lintKind (varType tv')+ ; updateTCvSubst subst' (thing_inside tv') }++lintCoBndr :: InCoVar -> (OutCoVar -> LintM a) -> LintM a+lintCoBndr cv thing_inside+ = do { subst <- getTCvSubst+ ; let (subst', cv') = substCoVarBndr subst cv+ ; lintKind (varType cv')+ ; lintL (isCoercionType (varType cv'))+ (text "CoVar with non-coercion type:" <+> pprTyVar cv)+ ; updateTCvSubst subst' (thing_inside cv') }++lintLetBndrs :: TopLevelFlag -> [Var] -> LintM a -> LintM a+lintLetBndrs top_lvl ids linterF+ = go ids+ where+ go [] = linterF+ go (id:ids) = lintIdBndr top_lvl LetBind id $ \_ ->+ go ids++lintIdBndr :: TopLevelFlag -> BindingSite+ -> InVar -> (OutVar -> LintM a) -> LintM a+-- Do substitution on the type of a binder and add the var with this+-- new type to the in-scope set of the second argument+-- ToDo: lint its rules+lintIdBndr top_lvl bind_site id linterF+ = ASSERT2( isId id, ppr id )+ do { flags <- getLintFlags+ ; checkL (not (lf_check_global_ids flags) || isLocalId id)+ (text "Non-local Id binder" <+> ppr id)+ -- See Note [Checking for global Ids]++ -- Check that if the binder is nested, it is not marked as exported+ ; checkL (not (isExportedId id) || is_top_lvl)+ (mkNonTopExportedMsg id)++ -- Check that if the binder is nested, it does not have an external name+ ; checkL (not (isExternalName (Var.varName id)) || is_top_lvl)+ (mkNonTopExternalNameMsg id)++ ; (ty, k) <- lintInTy (idType id)+ -- See Note [Levity polymorphism invariants] in CoreSyn+ ; lintL (isJoinId id || not (isKindLevPoly k))+ (text "Levity-polymorphic binder:" <+>+ (ppr id <+> dcolon <+> parens (ppr ty <+> dcolon <+> ppr k)))++ -- Check that a join-id is a not-top-level let-binding+ ; when (isJoinId id) $+ checkL (not is_top_lvl && is_let_bind) $+ mkBadJoinBindMsg id++ ; let id' = setIdType id ty+ ; addInScopeVar id' $ (linterF id') }+ where+ is_top_lvl = isTopLevel top_lvl+ is_let_bind = case bind_site of+ LetBind -> True+ _ -> False++{-+%************************************************************************+%* *+ Types+%* *+%************************************************************************+-}++lintInTy :: InType -> LintM (LintedType, LintedKind)+-- Types only, not kinds+-- Check the type, and apply the substitution to it+-- See Note [Linting type lets]+lintInTy ty+ = addLoc (InType ty) $+ do { ty' <- applySubstTy ty+ ; k <- lintType ty'+ ; lintKind k+ ; return (ty', k) }++checkTyCon :: TyCon -> LintM ()+checkTyCon tc+ = checkL (not (isTcTyCon tc)) (text "Found TcTyCon:" <+> ppr tc)++-------------------+lintType :: OutType -> LintM LintedKind+-- The returned Kind has itself been linted++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintType (TyVarTy tv)+ = do { checkL (isTyVar tv) (mkBadTyVarMsg tv)+ ; lintTyCoVarInScope tv+ ; return (tyVarKind tv) }+ -- We checked its kind when we added it to the envt++lintType ty@(AppTy t1 t2)+ | TyConApp {} <- t1+ = failWithL $ text "TyConApp to the left of AppTy:" <+> ppr ty+ | otherwise+ = do { k1 <- lintType t1+ ; k2 <- lintType t2+ ; lint_ty_app ty k1 [(t2,k2)] }++lintType ty@(TyConApp tc tys)+ | Just ty' <- coreView ty+ = lintType ty' -- Expand type synonyms, so that we do not bogusly complain+ -- about un-saturated type synonyms++ -- We should never see a saturated application of funTyCon; such applications+ -- should be represented with the FunTy constructor. See Note [Linting+ -- function types] and Note [Representation of function types].+ | isFunTyCon tc+ , length tys == 4+ = failWithL (hang (text "Saturated application of (->)") 2 (ppr ty))++ | isTypeSynonymTyCon tc || isTypeFamilyTyCon tc+ -- Also type synonyms and type families+ , length tys < tyConArity tc+ = failWithL (hang (text "Un-saturated type application") 2 (ppr ty))++ | otherwise+ = do { checkTyCon tc+ ; ks <- mapM lintType tys+ ; lint_ty_app ty (tyConKind tc) (tys `zip` ks) }++-- arrows can related *unlifted* kinds, so this has to be separate from+-- a dependent forall.+lintType ty@(FunTy t1 t2)+ = do { k1 <- lintType t1+ ; k2 <- lintType t2+ ; lintArrow (text "type or kind" <+> quotes (ppr ty)) k1 k2 }++lintType t@(ForAllTy (TvBndr tv _vis) ty)+ = do { lintL (isTyVar tv) (text "Covar bound in type:" <+> ppr t)+ ; lintTyBndr tv $ \tv' ->+ do { k <- lintType ty+ ; lintL (not (tv' `elemVarSet` tyCoVarsOfType k))+ (text "Variable escape in forall:" <+> ppr t)+ ; lintL (classifiesTypeWithValues k)+ (text "Non-* and non-# kind in forall:" <+> ppr t)+ ; return k }}++lintType ty@(LitTy l) = lintTyLit l >> return (typeKind ty)++lintType (CastTy ty co)+ = do { k1 <- lintType ty+ ; (k1', k2) <- lintStarCoercion co+ ; ensureEqTys k1 k1' (mkCastErr ty co k1' k1)+ ; return k2 }++lintType (CoercionTy co)+ = do { (k1, k2, ty1, ty2, r) <- lintCoercion co+ ; return $ mkHeteroCoercionType r k1 k2 ty1 ty2 }++lintKind :: OutKind -> LintM ()+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintKind k = do { sk <- lintType k+ ; unless (classifiesTypeWithValues sk)+ (addErrL (hang (text "Ill-kinded kind:" <+> ppr k)+ 2 (text "has kind:" <+> ppr sk))) }++-- confirms that a type is really *+lintStar :: SDoc -> OutKind -> LintM ()+lintStar doc k+ = lintL (classifiesTypeWithValues k)+ (text "Non-*-like kind when *-like expected:" <+> ppr k $$+ text "when checking" <+> doc)++lintArrow :: SDoc -> LintedKind -> LintedKind -> LintM LintedKind+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintArrow what k1 k2 -- Eg lintArrow "type or kind `blah'" k1 k2+ -- or lintarrow "coercion `blah'" k1 k2+ = do { unless (okArrowArgKind k1) (addErrL (msg (text "argument") k1))+ ; unless (okArrowResultKind k2) (addErrL (msg (text "result") k2))+ ; return liftedTypeKind }+ where+ msg ar k+ = vcat [ hang (text "Ill-kinded" <+> ar)+ 2 (text "in" <+> what)+ , what <+> text "kind:" <+> ppr k ]++lint_ty_app :: Type -> LintedKind -> [(LintedType,LintedKind)] -> LintM LintedKind+lint_ty_app ty k tys+ = lint_app (text "type" <+> quotes (ppr ty)) k tys++----------------+lint_co_app :: Coercion -> LintedKind -> [(LintedType,LintedKind)] -> LintM LintedKind+lint_co_app ty k tys+ = lint_app (text "coercion" <+> quotes (ppr ty)) k tys++----------------+lintTyLit :: TyLit -> LintM ()+lintTyLit (NumTyLit n)+ | n >= 0 = return ()+ | otherwise = failWithL msg+ where msg = text "Negative type literal:" <+> integer n+lintTyLit (StrTyLit _) = return ()++lint_app :: SDoc -> LintedKind -> [(LintedType,LintedKind)] -> LintM Kind+-- (lint_app d fun_kind arg_tys)+-- We have an application (f arg_ty1 .. arg_tyn),+-- where f :: fun_kind+-- Takes care of linting the OutTypes++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lint_app doc kfn kas+ = do { in_scope <- getInScope+ -- We need the in_scope set to satisfy the invariant in+ -- Note [The substitution invariant] in TyCoRep+ ; foldlM (go_app in_scope) kfn kas }+ where+ fail_msg = vcat [ hang (text "Kind application error in") 2 doc+ , nest 2 (text "Function kind =" <+> ppr kfn)+ , nest 2 (text "Arg kinds =" <+> ppr kas) ]++ go_app in_scope kfn ka+ | Just kfn' <- coreView kfn+ = go_app in_scope kfn' ka++ go_app _ (FunTy kfa kfb) (_,ka)+ = do { unless (ka `eqType` kfa) (addErrL fail_msg)+ ; return kfb }++ go_app in_scope (ForAllTy (TvBndr kv _vis) kfn) (ta,ka)+ = do { unless (ka `eqType` tyVarKind kv) (addErrL fail_msg)+ ; return (substTyWithInScope in_scope [kv] [ta] kfn) }++ go_app _ _ _ = failWithL fail_msg++{- *********************************************************************+* *+ Linting rules+* *+********************************************************************* -}++lintCoreRule :: OutVar -> OutType -> CoreRule -> LintM ()+lintCoreRule _ _ (BuiltinRule {})+ = return () -- Don't bother++lintCoreRule fun fun_ty rule@(Rule { ru_name = name, ru_bndrs = bndrs+ , ru_args = args, ru_rhs = rhs })+ = lintBinders LambdaBind bndrs $ \ _ ->+ do { lhs_ty <- foldM lintCoreArg fun_ty args+ ; rhs_ty <- case isJoinId_maybe fun of+ Just join_arity+ -> do { checkL (args `lengthIs` join_arity) $+ mkBadJoinPointRuleMsg fun join_arity rule+ -- See Note [Rules for join points]+ ; lintCoreExpr rhs }+ _ -> markAllJoinsBad $ lintCoreExpr rhs+ ; ensureEqTys lhs_ty rhs_ty $+ (rule_doc <+> vcat [ text "lhs type:" <+> ppr lhs_ty+ , text "rhs type:" <+> ppr rhs_ty ])+ ; let bad_bndrs = filterOut (`elemVarSet` exprsFreeVars args) $+ filter (`elemVarSet` exprFreeVars rhs) $+ bndrs++ ; checkL (null bad_bndrs)+ (rule_doc <+> text "unbound" <+> ppr bad_bndrs)+ -- See Note [Linting rules]+ }+ where+ rule_doc = text "Rule" <+> doubleQuotes (ftext name) <> colon++{- Note [Linting rules]+~~~~~~~~~~~~~~~~~~~~~~~+It's very bad if simplifying a rule means that one of the template+variables (ru_bndrs) that /is/ mentioned on the RHS becomes+not-mentioned in the LHS (ru_args). How can that happen? Well, in+Trac #10602, SpecConstr stupidly constructed a rule like++ forall x,c1,c2.+ f (x |> c1 |> c2) = ....++But simplExpr collapses those coercions into one. (Indeed in+Trac #10602, it collapsed to the identity and was removed altogether.)++We don't have a great story for what to do here, but at least+this check will nail it.++NB (Trac #11643): it's possible that a variable listed in the+binders becomes not-mentioned on both LHS and RHS. Here's a silly+example:+ RULE forall x y. f (g x y) = g (x+1 (y-1)+And suppose worker/wrapper decides that 'x' is Absent. Then+we'll end up with+ RULE forall x y. f ($gw y) = $gw (x+1)+This seems sufficiently obscure that there isn't enough payoff to+try to trim the forall'd binder list.++Note [Rules for join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++A join point cannot be partially applied. However, the left-hand side of a rule+for a join point is effectively a *pattern*, not a piece of code, so there's an+argument to be made for allowing a situation like this:++ join $sj :: Int -> Int -> String+ $sj n m = ...+ j :: forall a. Eq a => a -> a -> String+ {-# RULES "SPEC j" jump j @ Int $dEq = jump $sj #-}+ j @a $dEq x y = ...++Applying this rule can't turn a well-typed program into an ill-typed one, so+conceivably we could allow it. But we can always eta-expand such an+"undersaturated" rule (see 'CoreArity.etaExpandToJoinPointRule'), and in fact+the simplifier would have to in order to deal with the RHS. So we take a+conservative view and don't allow undersaturated rules for join points. See+Note [Rules and join points] in OccurAnal for further discussion.+-}++{-+************************************************************************+* *+ Linting coercions+* *+************************************************************************+-}++lintInCo :: InCoercion -> LintM (LintedKind, LintedKind, LintedType, LintedType, Role)+-- Check the coercion, and apply the substitution to it+-- See Note [Linting type lets]+lintInCo co+ = addLoc (InCo co) $+ do { co' <- applySubstCo co+ ; lintCoercion co' }++-- lints a coercion, confirming that its lh kind and its rh kind are both *+-- also ensures that the role is Nominal+lintStarCoercion :: OutCoercion -> LintM (LintedType, LintedType)+lintStarCoercion g+ = do { (k1, k2, t1, t2, r) <- lintCoercion g+ ; lintStar (text "the kind of the left type in" <+> ppr g) k1+ ; lintStar (text "the kind of the right type in" <+> ppr g) k2+ ; lintRole g Nominal r+ ; return (t1, t2) }++lintCoercion :: OutCoercion -> LintM (LintedKind, LintedKind, LintedType, LintedType, Role)+-- Check the kind of a coercion term, returning the kind+-- Post-condition: the returned OutTypes are lint-free+--+-- If lintCoercion co = (k1, k2, s1, s2, r)+-- then co :: s1 ~r s2+-- s1 :: k2+-- s2 :: k2++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism]+lintCoercion (Refl r ty)+ = do { k <- lintType ty+ ; return (k, k, ty, ty, r) }++lintCoercion co@(TyConAppCo r tc cos)+ | tc `hasKey` funTyConKey+ , [_rep1,_rep2,_co1,_co2] <- cos+ = do { failWithL (text "Saturated TyConAppCo (->):" <+> ppr co)+ } -- All saturated TyConAppCos should be FunCos++ | Just {} <- synTyConDefn_maybe tc+ = failWithL (text "Synonym in TyConAppCo:" <+> ppr co)++ | otherwise+ = do { checkTyCon tc+ ; (k's, ks, ss, ts, rs) <- mapAndUnzip5M lintCoercion cos+ ; k' <- lint_co_app co (tyConKind tc) (ss `zip` k's)+ ; k <- lint_co_app co (tyConKind tc) (ts `zip` ks)+ ; _ <- zipWith3M lintRole cos (tyConRolesX r tc) rs+ ; return (k', k, mkTyConApp tc ss, mkTyConApp tc ts, r) }++lintCoercion co@(AppCo co1 co2)+ | TyConAppCo {} <- co1+ = failWithL (text "TyConAppCo to the left of AppCo:" <+> ppr co)+ | Refl _ (TyConApp {}) <- co1+ = failWithL (text "Refl (TyConApp ...) to the left of AppCo:" <+> ppr co)+ | otherwise+ = do { (k1, k2, s1, s2, r1) <- lintCoercion co1+ ; (k'1, k'2, t1, t2, r2) <- lintCoercion co2+ ; k3 <- lint_co_app co k1 [(t1,k'1)]+ ; k4 <- lint_co_app co k2 [(t2,k'2)]+ ; if r1 == Phantom+ then lintL (r2 == Phantom || r2 == Nominal)+ (text "Second argument in AppCo cannot be R:" $$+ ppr co)+ else lintRole co Nominal r2+ ; return (k3, k4, mkAppTy s1 t1, mkAppTy s2 t2, r1) }++----------+lintCoercion (ForAllCo tv1 kind_co co)+ = do { (_, k2) <- lintStarCoercion kind_co+ ; let tv2 = setTyVarKind tv1 k2+ ; addInScopeVar tv1 $+ do {+ ; (k3, k4, t1, t2, r) <- lintCoercion co+ ; in_scope <- getInScope+ ; let tyl = mkInvForAllTy tv1 t1+ subst = mkTvSubst in_scope $+ -- We need both the free vars of the `t2` and the+ -- free vars of the range of the substitution in+ -- scope. All the free vars of `t2` and `kind_co` should+ -- already be in `in_scope`, because they've been+ -- linted and `tv2` has the same unique as `tv1`.+ -- See Note [The substitution invariant]+ unitVarEnv tv1 (TyVarTy tv2 `mkCastTy` mkSymCo kind_co)+ tyr = mkInvForAllTy tv2 $+ substTy subst t2+ ; return (k3, k4, tyl, tyr, r) } }++lintCoercion co@(FunCo r co1 co2)+ = do { (k1,k'1,s1,t1,r1) <- lintCoercion co1+ ; (k2,k'2,s2,t2,r2) <- lintCoercion co2+ ; k <- lintArrow (text "coercion" <+> quotes (ppr co)) k1 k2+ ; k' <- lintArrow (text "coercion" <+> quotes (ppr co)) k'1 k'2+ ; lintRole co1 r r1+ ; lintRole co2 r r2+ ; return (k, k', mkFunTy s1 s2, mkFunTy t1 t2, r) }++lintCoercion (CoVarCo cv)+ | not (isCoVar cv)+ = failWithL (hang (text "Bad CoVarCo:" <+> ppr cv)+ 2 (text "With offending type:" <+> ppr (varType cv)))+ | otherwise+ = do { lintTyCoVarInScope cv+ ; cv' <- lookupIdInScope cv+ ; lintUnliftedCoVar cv+ ; return $ coVarKindsTypesRole cv' }++-- See Note [Bad unsafe coercion]+lintCoercion co@(UnivCo prov r ty1 ty2)+ = do { k1 <- lintType ty1+ ; k2 <- lintType ty2+ ; case prov of+ UnsafeCoerceProv -> return () -- no extra checks++ PhantomProv kco -> do { lintRole co Phantom r+ ; check_kinds kco k1 k2 }++ ProofIrrelProv kco -> do { lintL (isCoercionTy ty1) $+ mkBadProofIrrelMsg ty1 co+ ; lintL (isCoercionTy ty2) $+ mkBadProofIrrelMsg ty2 co+ ; check_kinds kco k1 k2 }++ PluginProv _ -> return () -- no extra checks+ HoleProv h -> addErrL $+ text "Unfilled coercion hole:" <+> ppr h++ ; when (r /= Phantom && classifiesTypeWithValues k1+ && classifiesTypeWithValues k2)+ (checkTypes ty1 ty2)+ ; return (k1, k2, ty1, ty2, r) }+ where+ report s = hang (text $ "Unsafe coercion between " ++ s)+ 2 (vcat [ text "From:" <+> ppr ty1+ , text " To:" <+> ppr ty2])+ isUnBoxed :: PrimRep -> Bool+ isUnBoxed = not . isGcPtrRep++ -- see #9122 for discussion of these checks+ checkTypes t1 t2+ = do { checkWarnL (reps1 `equalLength` reps2)+ (report "values with different # of reps")+ ; zipWithM_ validateCoercion reps1 reps2 }+ where+ reps1 = typePrimRep t1+ reps2 = typePrimRep t2++ validateCoercion :: PrimRep -> PrimRep -> LintM ()+ validateCoercion rep1 rep2+ = do { dflags <- getDynFlags+ ; checkWarnL (isUnBoxed rep1 == isUnBoxed rep2)+ (report "unboxed and boxed value")+ ; checkWarnL (TyCon.primRepSizeW dflags rep1+ == TyCon.primRepSizeW dflags rep2)+ (report "unboxed values of different size")+ ; let fl = liftM2 (==) (TyCon.primRepIsFloat rep1)+ (TyCon.primRepIsFloat rep2)+ ; case fl of+ Nothing -> addWarnL (report "vector types")+ Just False -> addWarnL (report "float and integral values")+ _ -> return ()+ }++ check_kinds kco k1 k2 = do { (k1', k2') <- lintStarCoercion kco+ ; ensureEqTys k1 k1' (mkBadUnivCoMsg CLeft co)+ ; ensureEqTys k2 k2' (mkBadUnivCoMsg CRight co) }+++lintCoercion (SymCo co)+ = do { (k1, k2, ty1, ty2, r) <- lintCoercion co+ ; return (k2, k1, ty2, ty1, r) }++lintCoercion co@(TransCo co1 co2)+ = do { (k1a, _k1b, ty1a, ty1b, r1) <- lintCoercion co1+ ; (_k2a, k2b, ty2a, ty2b, r2) <- lintCoercion co2+ ; ensureEqTys ty1b ty2a+ (hang (text "Trans coercion mis-match:" <+> ppr co)+ 2 (vcat [ppr ty1a, ppr ty1b, ppr ty2a, ppr ty2b]))+ ; lintRole co r1 r2+ ; return (k1a, k2b, ty1a, ty2b, r1) }++lintCoercion the_co@(NthCo n co)+ = do { (_, _, s, t, r) <- lintCoercion co+ ; case (splitForAllTy_maybe s, splitForAllTy_maybe t) of+ { (Just (tv_s, _ty_s), Just (tv_t, _ty_t))+ | n == 0+ -> return (ks, kt, ts, tt, Nominal)+ where+ ts = tyVarKind tv_s+ tt = tyVarKind tv_t+ ks = typeKind ts+ kt = typeKind tt++ ; _ -> case (splitTyConApp_maybe s, splitTyConApp_maybe t) of+ { (Just (tc_s, tys_s), Just (tc_t, tys_t))+ | tc_s == tc_t+ , isInjectiveTyCon tc_s r+ -- see Note [NthCo and newtypes] in TyCoRep+ , tys_s `equalLength` tys_t+ , n < length tys_s+ -> return (ks, kt, ts, tt, tr)+ where+ ts = getNth tys_s n+ tt = getNth tys_t n+ tr = nthRole r tc_s n+ ks = typeKind ts+ kt = typeKind tt++ ; _ -> failWithL (hang (text "Bad getNth:")+ 2 (ppr the_co $$ ppr s $$ ppr t)) }}}++lintCoercion the_co@(LRCo lr co)+ = do { (_,_,s,t,r) <- lintCoercion co+ ; lintRole co Nominal r+ ; case (splitAppTy_maybe s, splitAppTy_maybe t) of+ (Just s_pr, Just t_pr)+ -> return (ks_pick, kt_pick, s_pick, t_pick, Nominal)+ where+ s_pick = pickLR lr s_pr+ t_pick = pickLR lr t_pr+ ks_pick = typeKind s_pick+ kt_pick = typeKind t_pick++ _ -> failWithL (hang (text "Bad LRCo:")+ 2 (ppr the_co $$ ppr s $$ ppr t)) }++lintCoercion (InstCo co arg)+ = do { (k3, k4, t1',t2', r) <- lintCoercion co+ ; (k1',k2',s1,s2, r') <- lintCoercion arg+ ; lintRole arg Nominal r'+ ; in_scope <- getInScope+ ; case (splitForAllTy_maybe t1', splitForAllTy_maybe t2') of+ (Just (tv1,t1), Just (tv2,t2))+ | k1' `eqType` tyVarKind tv1+ , k2' `eqType` tyVarKind tv2+ -> return (k3, k4,+ substTyWithInScope in_scope [tv1] [s1] t1,+ substTyWithInScope in_scope [tv2] [s2] t2, r)+ | otherwise+ -> failWithL (text "Kind mis-match in inst coercion")+ _ -> failWithL (text "Bad argument of inst") }++lintCoercion co@(AxiomInstCo con ind cos)+ = do { unless (0 <= ind && ind < numBranches (coAxiomBranches con))+ (bad_ax (text "index out of range"))+ ; let CoAxBranch { cab_tvs = ktvs+ , cab_cvs = cvs+ , cab_roles = roles+ , cab_lhs = lhs+ , cab_rhs = rhs } = coAxiomNthBranch con ind+ ; unless (length ktvs + length cvs == length cos) $+ bad_ax (text "lengths")+ ; subst <- getTCvSubst+ ; let empty_subst = zapTCvSubst subst+ ; (subst_l, subst_r) <- foldlM check_ki+ (empty_subst, empty_subst)+ (zip3 (ktvs ++ cvs) roles cos)+ ; let lhs' = substTys subst_l lhs+ rhs' = substTy subst_r rhs+ ; case checkAxInstCo co of+ Just bad_branch -> bad_ax $ text "inconsistent with" <+>+ pprCoAxBranch con bad_branch+ Nothing -> return ()+ ; let s2 = mkTyConApp (coAxiomTyCon con) lhs'+ ; return (typeKind s2, typeKind rhs', s2, rhs', coAxiomRole con) }+ where+ bad_ax what = addErrL (hang (text "Bad axiom application" <+> parens what)+ 2 (ppr co))++ check_ki (subst_l, subst_r) (ktv, role, arg)+ = do { (k', k'', s', t', r) <- lintCoercion arg+ ; lintRole arg role r+ ; let ktv_kind_l = substTy subst_l (tyVarKind ktv)+ ktv_kind_r = substTy subst_r (tyVarKind ktv)+ ; unless (k' `eqType` ktv_kind_l)+ (bad_ax (text "check_ki1" <+> vcat [ ppr co, ppr k', ppr ktv, ppr ktv_kind_l ] ))+ ; unless (k'' `eqType` ktv_kind_r)+ (bad_ax (text "check_ki2" <+> vcat [ ppr co, ppr k'', ppr ktv, ppr ktv_kind_r ] ))+ ; return (extendTCvSubst subst_l ktv s',+ extendTCvSubst subst_r ktv t') }++lintCoercion (CoherenceCo co1 co2)+ = do { (_, k2, t1, t2, r) <- lintCoercion co1+ ; let lhsty = mkCastTy t1 co2+ ; k1' <- lintType lhsty+ ; return (k1', k2, lhsty, t2, r) }++lintCoercion (KindCo co)+ = do { (k1, k2, _, _, _) <- lintCoercion co+ ; return (liftedTypeKind, liftedTypeKind, k1, k2, Nominal) }++lintCoercion (SubCo co')+ = do { (k1,k2,s,t,r) <- lintCoercion co'+ ; lintRole co' Nominal r+ ; return (k1,k2,s,t,Representational) }++lintCoercion this@(AxiomRuleCo co cs)+ = do { eqs <- mapM lintCoercion cs+ ; lintRoles 0 (coaxrAsmpRoles co) eqs+ ; case coaxrProves co [ Pair l r | (_,_,l,r,_) <- eqs ] of+ Nothing -> err "Malformed use of AxiomRuleCo" [ ppr this ]+ Just (Pair l r) ->+ return (typeKind l, typeKind r, l, r, coaxrRole co) }+ where+ err m xs = failWithL $+ hang (text m) 2 $ vcat (text "Rule:" <+> ppr (coaxrName co) : xs)++ lintRoles n (e : es) ((_,_,_,_,r) : rs)+ | e == r = lintRoles (n+1) es rs+ | otherwise = err "Argument roles mismatch"+ [ text "In argument:" <+> int (n+1)+ , text "Expected:" <+> ppr e+ , text "Found:" <+> ppr r ]+ lintRoles _ [] [] = return ()+ lintRoles n [] rs = err "Too many coercion arguments"+ [ text "Expected:" <+> int n+ , text "Provided:" <+> int (n + length rs) ]++ lintRoles n es [] = err "Not enough coercion arguments"+ [ text "Expected:" <+> int (n + length es)+ , text "Provided:" <+> int n ]++----------+lintUnliftedCoVar :: CoVar -> LintM ()+lintUnliftedCoVar cv+ = when (not (isUnliftedType (coVarKind cv))) $+ failWithL (text "Bad lifted equality:" <+> ppr cv+ <+> dcolon <+> ppr (coVarKind cv))++{-+************************************************************************+* *+\subsection[lint-monad]{The Lint monad}+* *+************************************************************************+-}++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism]+data LintEnv+ = LE { le_flags :: LintFlags -- Linting the result of this pass+ , le_loc :: [LintLocInfo] -- Locations+ , le_subst :: TCvSubst -- Current type substitution; we also use this+ -- to keep track of all the variables in scope,+ -- both Ids and TyVars+ , le_joins :: IdSet -- Join points in scope that are valid+ -- A subset of teh InScopeSet in le_subst+ -- See Note [Join points]+ , le_dynflags :: DynFlags -- DynamicFlags+ }++data LintFlags+ = LF { lf_check_global_ids :: Bool -- See Note [Checking for global Ids]+ , lf_check_inline_loop_breakers :: Bool -- See Note [Checking for INLINE loop breakers]+ , lf_check_static_ptrs :: StaticPtrCheck+ -- ^ See Note [Checking StaticPtrs]+ }++-- See Note [Checking StaticPtrs]+data StaticPtrCheck+ = AllowAnywhere+ -- ^ Allow 'makeStatic' to occur anywhere.+ | AllowAtTopLevel+ -- ^ Allow 'makeStatic' calls at the top-level only.+ | RejectEverywhere+ -- ^ Reject any 'makeStatic' occurrence.+ deriving Eq++defaultLintFlags :: LintFlags+defaultLintFlags = LF { lf_check_global_ids = False+ , lf_check_inline_loop_breakers = True+ , lf_check_static_ptrs = AllowAnywhere+ }++newtype LintM a =+ LintM { unLintM ::+ LintEnv ->+ WarnsAndErrs -> -- Error and warning messages so far+ (Maybe a, WarnsAndErrs) } -- Result and messages (if any)++type WarnsAndErrs = (Bag MsgDoc, Bag MsgDoc)++{- Note [Checking for global Ids]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Before CoreTidy, all locally-bound Ids must be LocalIds, even+top-level ones. See Note [Exported LocalIds] and Trac #9857.++Note [Checking StaticPtrs]+~~~~~~~~~~~~~~~~~~~~~~~~~~+See Note [Grand plan for static forms] in StaticPtrTable for an overview.++Every occurrence of the function 'makeStatic' should be moved to the+top level by the FloatOut pass. It's vital that we don't have nested+'makeStatic' occurrences after CorePrep, because we populate the Static+Pointer Table from the top-level bindings. See SimplCore Note [Grand+plan for static forms].++The linter checks that no occurrence is left behind, nested within an+expression. The check is enabled only after the FloatOut, CorePrep,+and CoreTidy passes and only if the module uses the StaticPointers+language extension. Checking more often doesn't help since the condition+doesn't hold until after the first FloatOut pass.++Note [Type substitution]+~~~~~~~~~~~~~~~~~~~~~~~~+Why do we need a type substitution? Consider+ /\(a:*). \(x:a). /\(a:*). id a x+This is ill typed, because (renaming variables) it is really+ /\(a:*). \(x:a). /\(b:*). id b x+Hence, when checking an application, we can't naively compare x's type+(at its binding site) with its expected type (at a use site). So we+rename type binders as we go, maintaining a substitution.++The same substitution also supports let-type, current expressed as+ (/\(a:*). body) ty+Here we substitute 'ty' for 'a' in 'body', on the fly.+-}++instance Functor LintM where+ fmap = liftM++instance Applicative LintM where+ pure x = LintM $ \ _ errs -> (Just x, errs)+ (<*>) = ap++instance Monad LintM where+ fail err = failWithL (text err)+ m >>= k = LintM (\ env errs ->+ let (res, errs') = unLintM m env errs in+ case res of+ Just r -> unLintM (k r) env errs'+ Nothing -> (Nothing, errs'))++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail LintM where+ fail err = failWithL (text err)+#endif++instance HasDynFlags LintM where+ getDynFlags = LintM (\ e errs -> (Just (le_dynflags e), errs))++data LintLocInfo+ = RhsOf Id -- The variable bound+ | LambdaBodyOf Id -- The lambda-binder+ | BodyOfLetRec [Id] -- One of the binders+ | CaseAlt CoreAlt -- Case alternative+ | CasePat CoreAlt -- The *pattern* of the case alternative+ | AnExpr CoreExpr -- Some expression+ | ImportedUnfolding SrcLoc -- Some imported unfolding (ToDo: say which)+ | TopLevelBindings+ | InType Type -- Inside a type+ | InCo Coercion -- Inside a coercion++initL :: DynFlags -> LintFlags -> InScopeSet+ -> LintM a -> WarnsAndErrs -- Errors and warnings+initL dflags flags in_scope m+ = case unLintM m env (emptyBag, emptyBag) of+ (_, errs) -> errs+ where+ env = LE { le_flags = flags+ , le_subst = mkEmptyTCvSubst in_scope+ , le_joins = emptyVarSet+ , le_loc = []+ , le_dynflags = dflags }++getLintFlags :: LintM LintFlags+getLintFlags = LintM $ \ env errs -> (Just (le_flags env), errs)++checkL :: Bool -> MsgDoc -> LintM ()+checkL True _ = return ()+checkL False msg = failWithL msg++-- like checkL, but relevant to type checking+lintL :: Bool -> MsgDoc -> LintM ()+lintL = checkL++checkWarnL :: Bool -> MsgDoc -> LintM ()+checkWarnL True _ = return ()+checkWarnL False msg = addWarnL msg++failWithL :: MsgDoc -> LintM a+failWithL msg = LintM $ \ env (warns,errs) ->+ (Nothing, (warns, addMsg env errs msg))++addErrL :: MsgDoc -> LintM ()+addErrL msg = LintM $ \ env (warns,errs) ->+ (Just (), (warns, addMsg env errs msg))++addWarnL :: MsgDoc -> LintM ()+addWarnL msg = LintM $ \ env (warns,errs) ->+ (Just (), (addMsg env warns msg, errs))++addMsg :: LintEnv -> Bag MsgDoc -> MsgDoc -> Bag MsgDoc+addMsg env msgs msg+ = ASSERT( notNull locs )+ msgs `snocBag` mk_msg msg+ where+ locs = le_loc env+ (loc, cxt1) = dumpLoc (head locs)+ cxts = [snd (dumpLoc loc) | loc <- locs]+ context = sdocWithPprDebug $ \dbg -> if dbg+ then vcat (reverse cxts) $$ cxt1 $$+ text "Substitution:" <+> ppr (le_subst env)+ else cxt1++ mk_msg msg = mkLocMessage SevWarning (mkSrcSpan loc loc) (context $$ msg)++addLoc :: LintLocInfo -> LintM a -> LintM a+addLoc extra_loc m+ = LintM $ \ env errs ->+ unLintM m (env { le_loc = extra_loc : le_loc env }) errs++inCasePat :: LintM Bool -- A slight hack; see the unique call site+inCasePat = LintM $ \ env errs -> (Just (is_case_pat env), errs)+ where+ is_case_pat (LE { le_loc = CasePat {} : _ }) = True+ is_case_pat _other = False++addInScopeVar :: Var -> LintM a -> LintM a+addInScopeVar var m+ = LintM $ \ env errs ->+ unLintM m (env { le_subst = extendTCvInScope (le_subst env) var+ , le_joins = delVarSet (le_joins env) var+ }) errs++extendSubstL :: TyVar -> Type -> LintM a -> LintM a+extendSubstL tv ty m+ = LintM $ \ env errs ->+ unLintM m (env { le_subst = Type.extendTvSubst (le_subst env) tv ty }) errs++updateTCvSubst :: TCvSubst -> LintM a -> LintM a+updateTCvSubst subst' m+ = LintM $ \ env errs -> unLintM m (env { le_subst = subst' }) errs++markAllJoinsBad :: LintM a -> LintM a+markAllJoinsBad m+ = LintM $ \ env errs -> unLintM m (env { le_joins = emptyVarSet }) errs++markAllJoinsBadIf :: Bool -> LintM a -> LintM a+markAllJoinsBadIf True m = markAllJoinsBad m+markAllJoinsBadIf False m = m++addGoodJoins :: [Var] -> LintM a -> LintM a+addGoodJoins vars thing_inside+ | null join_ids+ = thing_inside+ | otherwise+ = LintM $ \ env errs -> unLintM thing_inside (add_joins env) errs+ where+ add_joins env = env { le_joins = le_joins env `extendVarSetList` join_ids }+ join_ids = filter isJoinId vars++getValidJoins :: LintM IdSet+getValidJoins = LintM (\ env errs -> (Just (le_joins env), errs))++getTCvSubst :: LintM TCvSubst+getTCvSubst = LintM (\ env errs -> (Just (le_subst env), errs))++getInScope :: LintM InScopeSet+getInScope = LintM (\ env errs -> (Just (getTCvInScope $ le_subst env), errs))++applySubstTy :: InType -> LintM OutType+applySubstTy ty = do { subst <- getTCvSubst; return (substTy subst ty) }++applySubstCo :: InCoercion -> LintM OutCoercion+applySubstCo co = do { subst <- getTCvSubst; return (substCo subst co) }++lookupIdInScope :: Id -> LintM Id+lookupIdInScope id+ | not (mustHaveLocalBinding id)+ = return id -- An imported Id+ | otherwise+ = do { subst <- getTCvSubst+ ; case lookupInScope (getTCvInScope subst) id of+ Just v -> return v+ Nothing -> do { addErrL out_of_scope+ ; return id } }+ where+ out_of_scope = pprBndr LetBind id <+> text "is out of scope"++lookupJoinId :: Id -> LintM (Maybe JoinArity)+-- Look up an Id which should be a join point, valid here+-- If so, return its arity, if not return Nothing+lookupJoinId id+ = do { join_set <- getValidJoins+ ; case lookupVarSet join_set id of+ Just id' -> return (isJoinId_maybe id')+ Nothing -> return Nothing }++lintTyCoVarInScope :: Var -> LintM ()+lintTyCoVarInScope v = lintInScope (text "is out of scope") v++lintInScope :: SDoc -> Var -> LintM ()+lintInScope loc_msg var =+ do { subst <- getTCvSubst+ ; lintL (not (mustHaveLocalBinding var) || (var `isInScope` subst))+ (hsep [pprBndr LetBind var, loc_msg]) }++ensureEqTys :: OutType -> OutType -> MsgDoc -> LintM ()+-- check ty2 is subtype of ty1 (ie, has same structure but usage+-- annotations need only be consistent, not equal)+-- Assumes ty1,ty2 are have already had the substitution applied+ensureEqTys ty1 ty2 msg = lintL (ty1 `eqType` ty2) msg++lintRole :: Outputable thing+ => thing -- where the role appeared+ -> Role -- expected+ -> Role -- actual+ -> LintM ()+lintRole co r1 r2+ = lintL (r1 == r2)+ (text "Role incompatibility: expected" <+> ppr r1 <> comma <+>+ text "got" <+> ppr r2 $$+ text "in" <+> ppr co)++{-+************************************************************************+* *+\subsection{Error messages}+* *+************************************************************************+-}++dumpLoc :: LintLocInfo -> (SrcLoc, SDoc)++dumpLoc (RhsOf v)+ = (getSrcLoc v, brackets (text "RHS of" <+> pp_binders [v]))++dumpLoc (LambdaBodyOf b)+ = (getSrcLoc b, brackets (text "in body of lambda with binder" <+> pp_binder b))++dumpLoc (BodyOfLetRec [])+ = (noSrcLoc, brackets (text "In body of a letrec with no binders"))++dumpLoc (BodyOfLetRec bs@(_:_))+ = ( getSrcLoc (head bs), brackets (text "in body of letrec with binders" <+> pp_binders bs))++dumpLoc (AnExpr e)+ = (noSrcLoc, text "In the expression:" <+> ppr e)++dumpLoc (CaseAlt (con, args, _))+ = (noSrcLoc, text "In a case alternative:" <+> parens (ppr con <+> pp_binders args))++dumpLoc (CasePat (con, args, _))+ = (noSrcLoc, text "In the pattern of a case alternative:" <+> parens (ppr con <+> pp_binders args))++dumpLoc (ImportedUnfolding locn)+ = (locn, brackets (text "in an imported unfolding"))+dumpLoc TopLevelBindings+ = (noSrcLoc, Outputable.empty)+dumpLoc (InType ty)+ = (noSrcLoc, text "In the type" <+> quotes (ppr ty))+dumpLoc (InCo co)+ = (noSrcLoc, text "In the coercion" <+> quotes (ppr co))++pp_binders :: [Var] -> SDoc+pp_binders bs = sep (punctuate comma (map pp_binder bs))++pp_binder :: Var -> SDoc+pp_binder b | isId b = hsep [ppr b, dcolon, ppr (idType b)]+ | otherwise = hsep [ppr b, dcolon, ppr (tyVarKind b)]++------------------------------------------------------+-- Messages for case expressions++mkDefaultArgsMsg :: [Var] -> MsgDoc+mkDefaultArgsMsg args+ = hang (text "DEFAULT case with binders")+ 4 (ppr args)++mkCaseAltMsg :: CoreExpr -> Type -> Type -> MsgDoc+mkCaseAltMsg e ty1 ty2+ = hang (text "Type of case alternatives not the same as the annotation on case:")+ 4 (vcat [ text "Actual type:" <+> ppr ty1,+ text "Annotation on case:" <+> ppr ty2,+ text "Alt Rhs:" <+> ppr e ])++mkScrutMsg :: Id -> Type -> Type -> TCvSubst -> MsgDoc+mkScrutMsg var var_ty scrut_ty subst+ = vcat [text "Result binder in case doesn't match scrutinee:" <+> ppr var,+ text "Result binder type:" <+> ppr var_ty,--(idType var),+ text "Scrutinee type:" <+> ppr scrut_ty,+ hsep [text "Current TCv subst", ppr subst]]++mkNonDefltMsg, mkNonIncreasingAltsMsg :: CoreExpr -> MsgDoc+mkNonDefltMsg e+ = hang (text "Case expression with DEFAULT not at the beginnning") 4 (ppr e)+mkNonIncreasingAltsMsg e+ = hang (text "Case expression with badly-ordered alternatives") 4 (ppr e)++nonExhaustiveAltsMsg :: CoreExpr -> MsgDoc+nonExhaustiveAltsMsg e+ = hang (text "Case expression with non-exhaustive alternatives") 4 (ppr e)++mkBadConMsg :: TyCon -> DataCon -> MsgDoc+mkBadConMsg tycon datacon+ = vcat [+ text "In a case alternative, data constructor isn't in scrutinee type:",+ text "Scrutinee type constructor:" <+> ppr tycon,+ text "Data con:" <+> ppr datacon+ ]++mkBadPatMsg :: Type -> Type -> MsgDoc+mkBadPatMsg con_result_ty scrut_ty+ = vcat [+ text "In a case alternative, pattern result type doesn't match scrutinee type:",+ text "Pattern result type:" <+> ppr con_result_ty,+ text "Scrutinee type:" <+> ppr scrut_ty+ ]++integerScrutinisedMsg :: MsgDoc+integerScrutinisedMsg+ = text "In a LitAlt, the literal is lifted (probably Integer)"++mkBadAltMsg :: Type -> CoreAlt -> MsgDoc+mkBadAltMsg scrut_ty alt+ = vcat [ text "Data alternative when scrutinee is not a tycon application",+ text "Scrutinee type:" <+> ppr scrut_ty,+ text "Alternative:" <+> pprCoreAlt alt ]++mkNewTyDataConAltMsg :: Type -> CoreAlt -> MsgDoc+mkNewTyDataConAltMsg scrut_ty alt+ = vcat [ text "Data alternative for newtype datacon",+ text "Scrutinee type:" <+> ppr scrut_ty,+ text "Alternative:" <+> pprCoreAlt alt ]+++------------------------------------------------------+-- Other error messages++mkAppMsg :: Type -> Type -> CoreExpr -> MsgDoc+mkAppMsg fun_ty arg_ty arg+ = vcat [text "Argument value doesn't match argument type:",+ hang (text "Fun type:") 4 (ppr fun_ty),+ hang (text "Arg type:") 4 (ppr arg_ty),+ hang (text "Arg:") 4 (ppr arg)]++mkNonFunAppMsg :: Type -> Type -> CoreExpr -> MsgDoc+mkNonFunAppMsg fun_ty arg_ty arg+ = vcat [text "Non-function type in function position",+ hang (text "Fun type:") 4 (ppr fun_ty),+ hang (text "Arg type:") 4 (ppr arg_ty),+ hang (text "Arg:") 4 (ppr arg)]++mkLetErr :: TyVar -> CoreExpr -> MsgDoc+mkLetErr bndr rhs+ = vcat [text "Bad `let' binding:",+ hang (text "Variable:")+ 4 (ppr bndr <+> dcolon <+> ppr (varType bndr)),+ hang (text "Rhs:")+ 4 (ppr rhs)]++mkTyAppMsg :: Type -> Type -> MsgDoc+mkTyAppMsg ty arg_ty+ = vcat [text "Illegal type application:",+ hang (text "Exp type:")+ 4 (ppr ty <+> dcolon <+> ppr (typeKind ty)),+ hang (text "Arg type:")+ 4 (ppr arg_ty <+> dcolon <+> ppr (typeKind arg_ty))]++emptyRec :: CoreExpr -> MsgDoc+emptyRec e = hang (text "Empty Rec binding:") 2 (ppr e)++mkRhsMsg :: Id -> SDoc -> Type -> MsgDoc+mkRhsMsg binder what ty+ = vcat+ [hsep [text "The type of this binder doesn't match the type of its" <+> what <> colon,+ ppr binder],+ hsep [text "Binder's type:", ppr (idType binder)],+ hsep [text "Rhs type:", ppr ty]]++mkLetAppMsg :: CoreExpr -> MsgDoc+mkLetAppMsg e+ = hang (text "This argument does not satisfy the let/app invariant:")+ 2 (ppr e)++badBndrTyMsg :: Id -> SDoc -> MsgDoc+badBndrTyMsg binder what+ = vcat [ text "The type of this binder is" <+> what <> colon <+> ppr binder+ , text "Binder's type:" <+> ppr (idType binder) ]++mkStrictMsg :: Id -> MsgDoc+mkStrictMsg binder+ = vcat [hsep [text "Recursive or top-level binder has strict demand info:",+ ppr binder],+ hsep [text "Binder's demand info:", ppr (idDemandInfo binder)]+ ]++mkNonTopExportedMsg :: Id -> MsgDoc+mkNonTopExportedMsg binder+ = hsep [text "Non-top-level binder is marked as exported:", ppr binder]++mkNonTopExternalNameMsg :: Id -> MsgDoc+mkNonTopExternalNameMsg binder+ = hsep [text "Non-top-level binder has an external name:", ppr binder]++mkTopNonLitStrMsg :: Id -> MsgDoc+mkTopNonLitStrMsg binder+ = hsep [text "Top-level Addr# binder has a non-literal rhs:", ppr binder]++mkKindErrMsg :: TyVar -> Type -> MsgDoc+mkKindErrMsg tyvar arg_ty+ = vcat [text "Kinds don't match in type application:",+ hang (text "Type variable:")+ 4 (ppr tyvar <+> dcolon <+> ppr (tyVarKind tyvar)),+ hang (text "Arg type:")+ 4 (ppr arg_ty <+> dcolon <+> ppr (typeKind arg_ty))]++{- Not needed now+mkArityMsg :: Id -> MsgDoc+mkArityMsg binder+ = vcat [hsep [text "Demand type has",+ ppr (dmdTypeDepth dmd_ty),+ text "arguments, rhs has",+ ppr (idArity binder),+ text "arguments,",+ ppr binder],+ hsep [text "Binder's strictness signature:", ppr dmd_ty]++ ]+ where (StrictSig dmd_ty) = idStrictness binder+-}+mkCastErr :: Outputable casted => casted -> Coercion -> Type -> Type -> MsgDoc+mkCastErr expr co from_ty expr_ty+ = vcat [text "From-type of Cast differs from type of enclosed expression",+ text "From-type:" <+> ppr from_ty,+ text "Type of enclosed expr:" <+> ppr expr_ty,+ text "Actual enclosed expr:" <+> ppr expr,+ text "Coercion used in cast:" <+> ppr co+ ]++mkBadUnivCoMsg :: LeftOrRight -> Coercion -> SDoc+mkBadUnivCoMsg lr co+ = text "Kind mismatch on the" <+> pprLeftOrRight lr <+>+ text "side of a UnivCo:" <+> ppr co++mkBadProofIrrelMsg :: Type -> Coercion -> SDoc+mkBadProofIrrelMsg ty co+ = hang (text "Found a non-coercion in a proof-irrelevance UnivCo:")+ 2 (vcat [ text "type:" <+> ppr ty+ , text "co:" <+> ppr co ])++mkBadTyVarMsg :: Var -> SDoc+mkBadTyVarMsg tv+ = text "Non-tyvar used in TyVarTy:"+ <+> ppr tv <+> dcolon <+> ppr (varType tv)++mkBadJoinBindMsg :: Var -> SDoc+mkBadJoinBindMsg var+ = vcat [ text "Bad join point binding:" <+> ppr var+ , text "Join points can be bound only by a non-top-level let" ]++mkInvalidJoinPointMsg :: Var -> Type -> SDoc+mkInvalidJoinPointMsg var ty+ = hang (text "Join point has invalid type:")+ 2 (ppr var <+> dcolon <+> ppr ty)++mkBadJoinArityMsg :: Var -> Int -> Int -> SDoc+mkBadJoinArityMsg var ar nlams+ = vcat [ text "Join point has too few lambdas",+ text "Join var:" <+> ppr var,+ text "Join arity:" <+> ppr ar,+ text "Number of lambdas:" <+> ppr nlams ]++invalidJoinOcc :: Var -> SDoc+invalidJoinOcc var+ = vcat [ text "Invalid occurrence of a join variable:" <+> ppr var+ , text "The binder is either not a join point, or not valid here" ]++mkBadJumpMsg :: Var -> Int -> Int -> SDoc+mkBadJumpMsg var ar nargs+ = vcat [ text "Join point invoked with wrong number of arguments",+ text "Join var:" <+> ppr var,+ text "Join arity:" <+> ppr ar,+ text "Number of arguments:" <+> int nargs ]++mkInconsistentRecMsg :: [Var] -> SDoc+mkInconsistentRecMsg bndrs+ = vcat [ text "Recursive let binders mix values and join points",+ text "Binders:" <+> hsep (map ppr_with_details bndrs) ]+ where+ ppr_with_details bndr = ppr bndr <> ppr (idDetails bndr)++mkJoinBndrOccMismatchMsg :: Var -> JoinArity -> JoinArity -> SDoc+mkJoinBndrOccMismatchMsg bndr join_arity_bndr join_arity_occ+ = vcat [ text "Mismatch in join point arity between binder and occurrence"+ , text "Var:" <+> ppr bndr+ , text "Arity at binding site:" <+> ppr join_arity_bndr+ , text "Arity at occurrence: " <+> ppr join_arity_occ ]++mkBndrOccTypeMismatchMsg :: Var -> Var -> OutType -> OutType -> SDoc+mkBndrOccTypeMismatchMsg bndr var bndr_ty var_ty+ = vcat [ text "Mismatch in type between binder and occurrence"+ , text "Var:" <+> ppr bndr+ , text "Binder type:" <+> ppr bndr_ty+ , text "Occurrence type:" <+> ppr var_ty+ , text " Before subst:" <+> ppr (idType var) ]++mkBadJoinPointRuleMsg :: JoinId -> JoinArity -> CoreRule -> SDoc+mkBadJoinPointRuleMsg bndr join_arity rule+ = vcat [ text "Join point has rule with wrong number of arguments"+ , text "Var:" <+> ppr bndr+ , text "Join arity:" <+> ppr join_arity+ , text "Rule:" <+> ppr rule ]++pprLeftOrRight :: LeftOrRight -> MsgDoc+pprLeftOrRight CLeft = text "left"+pprLeftOrRight CRight = text "right"++dupVars :: [[Var]] -> MsgDoc+dupVars vars+ = hang (text "Duplicate variables brought into scope")+ 2 (ppr vars)++dupExtVars :: [[Name]] -> MsgDoc+dupExtVars vars+ = hang (text "Duplicate top-level variables with the same qualified name")+ 2 (ppr vars)++{-+************************************************************************+* *+\subsection{Annotation Linting}+* *+************************************************************************+-}++-- | This checks whether a pass correctly looks through debug+-- annotations (@SourceNote@). This works a bit different from other+-- consistency checks: We check this by running the given task twice,+-- noting all differences between the results.+lintAnnots :: SDoc -> (ModGuts -> CoreM ModGuts) -> ModGuts -> CoreM ModGuts+lintAnnots pname pass guts = do+ -- Run the pass as we normally would+ dflags <- getDynFlags+ when (gopt Opt_DoAnnotationLinting dflags) $+ liftIO $ Err.showPass dflags "Annotation linting - first run"+ nguts <- pass guts+ -- If appropriate re-run it without debug annotations to make sure+ -- that they made no difference.+ when (gopt Opt_DoAnnotationLinting dflags) $ do+ liftIO $ Err.showPass dflags "Annotation linting - second run"+ nguts' <- withoutAnnots pass guts+ -- Finally compare the resulting bindings+ liftIO $ Err.showPass dflags "Annotation linting - comparison"+ let binds = flattenBinds $ mg_binds nguts+ binds' = flattenBinds $ mg_binds nguts'+ (diffs,_) = diffBinds True (mkRnEnv2 emptyInScopeSet) binds binds'+ when (not (null diffs)) $ CoreMonad.putMsg $ vcat+ [ lint_banner "warning" pname+ , text "Core changes with annotations:"+ , withPprStyle (defaultDumpStyle dflags) $ nest 2 $ vcat diffs+ ]+ -- Return actual new guts+ return nguts++-- | Run the given pass without annotations. This means that we both+-- set the debugLevel setting to 0 in the environment as well as all+-- annotations from incoming modules.+withoutAnnots :: (ModGuts -> CoreM ModGuts) -> ModGuts -> CoreM ModGuts+withoutAnnots pass guts = do+ -- Remove debug flag from environment.+ dflags <- getDynFlags+ let removeFlag env = env{ hsc_dflags = dflags{ debugLevel = 0} }+ withoutFlag corem =+ liftIO =<< runCoreM <$> fmap removeFlag getHscEnv <*> getRuleBase <*>+ getUniqueSupplyM <*> getModule <*>+ getVisibleOrphanMods <*>+ getPrintUnqualified <*> getSrcSpanM <*>+ pure corem+ -- Nuke existing ticks in module.+ -- TODO: Ticks in unfoldings. Maybe change unfolding so it removes+ -- them in absence of debugLevel > 0.+ let nukeTicks = stripTicksE (not . tickishIsCode)+ nukeAnnotsBind :: CoreBind -> CoreBind+ nukeAnnotsBind bind = case bind of+ Rec bs -> Rec $ map (\(b,e) -> (b, nukeTicks e)) bs+ NonRec b e -> NonRec b $ nukeTicks e+ nukeAnnotsMod mg@ModGuts{mg_binds=binds}+ = mg{mg_binds = map nukeAnnotsBind binds}+ -- Perform pass with all changes applied+ fmap fst $ withoutFlag $ pass (nukeAnnotsMod guts)
+ coreSyn/CoreOpt.hs view
@@ -0,0 +1,1176 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP #-}+module CoreOpt (+ -- ** Simple expression optimiser+ simpleOptPgm, simpleOptExpr, simpleOptExprWith,++ -- ** Join points+ joinPointBinding_maybe, joinPointBindings_maybe,++ -- ** Predicates on expressions+ exprIsConApp_maybe, exprIsLiteral_maybe, exprIsLambda_maybe,++ -- ** Coercions and casts+ pushCoArg, pushCoValArg, pushCoTyArg, collectBindersPushingCo+ ) where++#include "HsVersions.h"++import CoreArity( joinRhsArity, etaExpandToJoinPoint )++import CoreSyn+import CoreSubst+import CoreUtils+import CoreFVs+import PprCore ( pprCoreBindings, pprRules )+import OccurAnal( occurAnalyseExpr, occurAnalysePgm )+import Literal ( Literal(MachStr) )+import Id+import Var ( varType )+import VarSet+import VarEnv+import DataCon+import OptCoercion ( optCoercion )+import Type hiding ( substTy, extendTvSubst, extendCvSubst, extendTvSubstList+ , isInScope, substTyVarBndr, cloneTyVarBndr )+import Coercion hiding ( substCo, substCoVarBndr )+import TyCon ( tyConArity )+import TysWiredIn+import PrelNames+import BasicTypes+import Module ( Module )+import ErrUtils+import DynFlags+import Outputable+import Pair+import Util+import Maybes ( orElse )+import FastString+import Data.List+import qualified Data.ByteString as BS++{-+************************************************************************+* *+ The Simple Optimiser+* *+************************************************************************++Note [The simple optimiser]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+The simple optimiser is a lightweight, pure (non-monadic) function+that rapidly does a lot of simple optimisations, including++ - inlining things that occur just once,+ or whose RHS turns out to be trivial+ - beta reduction+ - case of known constructor+ - dead code elimination++It does NOT do any call-site inlining; it only inlines a function if+it can do so unconditionally, dropping the binding. It thereby+guarantees to leave no un-reduced beta-redexes.++It is careful to follow the guidance of "Secrets of the GHC inliner",+and in particular the pre-inline-unconditionally and+post-inline-unconditionally story, to do effective beta reduction on+functions called precisely once, without repeatedly optimising the same+expression. In fact, the simple optimiser is a good example of this+little dance in action; the full Simplifier is a lot more complicated.++-}++simpleOptExpr :: CoreExpr -> CoreExpr+-- See Note [The simple optimiser]+-- Do simple optimisation on an expression+-- The optimisation is very straightforward: just+-- inline non-recursive bindings that are used only once,+-- or where the RHS is trivial+--+-- We also inline bindings that bind a Eq# box: see+-- See Note [Getting the map/coerce RULE to work].+--+-- Also we convert functions to join points where possible (as+-- the occurrence analyser does most of the work anyway).+--+-- The result is NOT guaranteed occurrence-analysed, because+-- in (let x = y in ....) we substitute for x; so y's occ-info+-- may change radically++simpleOptExpr expr+ = -- pprTrace "simpleOptExpr" (ppr init_subst $$ ppr expr)+ simpleOptExprWith init_subst expr+ where+ init_subst = mkEmptySubst (mkInScopeSet (exprFreeVars expr))+ -- It's potentially important to make a proper in-scope set+ -- Consider let x = ..y.. in \y. ...x...+ -- Then we should remember to clone y before substituting+ -- for x. It's very unlikely to occur, because we probably+ -- won't *be* substituting for x if it occurs inside a+ -- lambda.+ --+ -- It's a bit painful to call exprFreeVars, because it makes+ -- three passes instead of two (occ-anal, and go)++simpleOptExprWith :: Subst -> InExpr -> OutExpr+-- See Note [The simple optimiser]+simpleOptExprWith subst expr+ = simple_opt_expr init_env (occurAnalyseExpr expr)+ where+ init_env = SOE { soe_inl = emptyVarEnv, soe_subst = subst }++----------------------+simpleOptPgm :: DynFlags -> Module+ -> CoreProgram -> [CoreRule] -> [CoreVect]+ -> IO (CoreProgram, [CoreRule], [CoreVect])+-- See Note [The simple optimiser]+simpleOptPgm dflags this_mod binds rules vects+ = do { dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"+ (pprCoreBindings occ_anald_binds $$ pprRules rules );++ ; return (reverse binds', rules', vects') }+ where+ occ_anald_binds = occurAnalysePgm this_mod (\_ -> False) {- No rules active -}+ rules vects emptyVarSet binds++ (final_env, binds') = foldl do_one (emptyEnv, []) occ_anald_binds+ final_subst = soe_subst final_env++ rules' = substRulesForImportedIds final_subst rules+ vects' = substVects final_subst vects+ -- We never unconditionally inline into rules,+ -- hence pasing just a substitution++ do_one (env, binds') bind+ = case simple_opt_bind env bind of+ (env', Nothing) -> (env', binds')+ (env', Just bind') -> (env', bind':binds')++-- In these functions the substitution maps InVar -> OutExpr++----------------------+type SimpleClo = (SimpleOptEnv, InExpr)++data SimpleOptEnv+ = SOE { soe_inl :: IdEnv SimpleClo+ -- Deals with preInlineUnconditionally; things+ -- that occur exactly once and are inlined+ -- without having first been simplified++ , soe_subst :: Subst+ -- Deals with cloning; includes the InScopeSet+ }++instance Outputable SimpleOptEnv where+ ppr (SOE { soe_inl = inl, soe_subst = subst })+ = text "SOE {" <+> vcat [ text "soe_inl =" <+> ppr inl+ , text "soe_subst =" <+> ppr subst ]+ <+> text "}"++emptyEnv :: SimpleOptEnv+emptyEnv = SOE { soe_inl = emptyVarEnv+ , soe_subst = emptySubst }++soeZapSubst :: SimpleOptEnv -> SimpleOptEnv+soeZapSubst (SOE { soe_subst = subst })+ = SOE { soe_inl = emptyVarEnv, soe_subst = zapSubstEnv subst }++soeSetInScope :: SimpleOptEnv -> SimpleOptEnv -> SimpleOptEnv+-- Take in-scope set from env1, and the rest from env2+soeSetInScope (SOE { soe_subst = subst1 })+ env2@(SOE { soe_subst = subst2 })+ = env2 { soe_subst = setInScope subst2 (substInScope subst1) }++---------------+simple_opt_clo :: SimpleOptEnv -> SimpleClo -> OutExpr+simple_opt_clo env (e_env, e)+ = simple_opt_expr (soeSetInScope env e_env) e++simple_opt_expr :: SimpleOptEnv -> InExpr -> OutExpr+simple_opt_expr env expr+ = go expr+ where+ subst = soe_subst env+ in_scope = substInScope subst+ in_scope_env = (in_scope, simpleUnfoldingFun)++ go (Var v)+ | Just clo <- lookupVarEnv (soe_inl env) v+ = simple_opt_clo env clo+ | otherwise+ = lookupIdSubst (text "simpleOptExpr") (soe_subst env) v++ go (App e1 e2) = simple_app env e1 [(env,e2)]+ go (Type ty) = Type (substTy subst ty)+ go (Coercion co) = Coercion (optCoercion (getTCvSubst subst) co)+ go (Lit lit) = Lit lit+ go (Tick tickish e) = mkTick (substTickish subst tickish) (go e)+ go (Cast e co) | isReflCo co' = go e+ | otherwise = Cast (go e) co'+ where+ co' = optCoercion (getTCvSubst subst) co++ go (Let bind body) = case simple_opt_bind env bind of+ (env', Nothing) -> simple_opt_expr env' body+ (env', Just bind) -> Let bind (simple_opt_expr env' body)++ go lam@(Lam {}) = go_lam env [] lam+ go (Case e b ty as)+ -- See Note [Getting the map/coerce RULE to work]+ | isDeadBinder b+ , Just (con, _tys, es) <- exprIsConApp_maybe in_scope_env e'+ , Just (altcon, bs, rhs) <- findAlt (DataAlt con) as+ = case altcon of+ DEFAULT -> go rhs+ _ -> foldr wrapLet (simple_opt_expr env' rhs) mb_prs+ where+ (env', mb_prs) = mapAccumL simple_out_bind env $+ zipEqual "simpleOptExpr" bs es++ -- Note [Getting the map/coerce RULE to work]+ | isDeadBinder b+ , [(DEFAULT, _, rhs)] <- as+ , isCoercionType (varType b)+ , (Var fun, _args) <- collectArgs e+ , fun `hasKey` coercibleSCSelIdKey+ -- without this last check, we get #11230+ = go rhs++ | otherwise+ = Case e' b' (substTy subst ty)+ (map (go_alt env') as)+ where+ e' = go e+ (env', b') = subst_opt_bndr env b++ ----------------------+ go_alt env (con, bndrs, rhs)+ = (con, bndrs', simple_opt_expr env' rhs)+ where+ (env', bndrs') = subst_opt_bndrs env bndrs++ ----------------------+ -- go_lam tries eta reduction+ go_lam env bs' (Lam b e)+ = go_lam env' (b':bs') e+ where+ (env', b') = subst_opt_bndr env b+ go_lam env bs' e+ | Just etad_e <- tryEtaReduce bs e' = etad_e+ | otherwise = mkLams bs e'+ where+ bs = reverse bs'+ e' = simple_opt_expr env e++----------------------+-- simple_app collects arguments for beta reduction+simple_app :: SimpleOptEnv -> InExpr -> [SimpleClo] -> CoreExpr++simple_app env (Var v) as+ | Just (env', e) <- lookupVarEnv (soe_inl env) v+ = simple_app (soeSetInScope env env') e as++ | let unf = idUnfolding v+ , isCompulsoryUnfolding (idUnfolding v)+ , isAlwaysActive (idInlineActivation v)+ -- See Note [Unfold compulsory unfoldings in LHSs]+ = simple_app (soeZapSubst env) (unfoldingTemplate unf) as++ | otherwise+ , let out_fn = lookupIdSubst (text "simple_app") (soe_subst env) v+ = finish_app env out_fn as++simple_app env (App e1 e2) as+ = simple_app env e1 ((env, e2) : as)++simple_app env (Lam b e) (a:as)+ = wrapLet mb_pr (simple_app env' e as)+ where+ (env', mb_pr) = simple_bind_pair env b Nothing a++simple_app env (Tick t e) as+ -- Okay to do "(Tick t e) x ==> Tick t (e x)"?+ | t `tickishScopesLike` SoftScope+ = mkTick t $ simple_app env e as++simple_app env e as+ = finish_app env (simple_opt_expr env e) as++finish_app :: SimpleOptEnv -> OutExpr -> [SimpleClo] -> OutExpr+finish_app _ fun []+ = fun+finish_app env fun (arg:args)+ = finish_app env (App fun (simple_opt_clo env arg)) args++----------------------+simple_opt_bind :: SimpleOptEnv -> InBind+ -> (SimpleOptEnv, Maybe OutBind)+simple_opt_bind env (NonRec b r)+ = (env', case mb_pr of+ Nothing -> Nothing+ Just (b,r) -> Just (NonRec b r))+ where+ (b', r') = joinPointBinding_maybe b r `orElse` (b, r)+ (env', mb_pr) = simple_bind_pair env b' Nothing (env,r')++simple_opt_bind env (Rec prs)+ = (env'', res_bind)+ where+ res_bind = Just (Rec (reverse rev_prs'))+ prs' = joinPointBindings_maybe prs `orElse` prs+ (env', bndrs') = subst_opt_bndrs env (map fst prs')+ (env'', rev_prs') = foldl do_pr (env', []) (prs' `zip` bndrs')+ do_pr (env, prs) ((b,r), b')+ = (env', case mb_pr of+ Just pr -> pr : prs+ Nothing -> prs)+ where+ (env', mb_pr) = simple_bind_pair env b (Just b') (env,r)++----------------------+simple_bind_pair :: SimpleOptEnv+ -> InVar -> Maybe OutVar+ -> SimpleClo+ -> (SimpleOptEnv, Maybe (OutVar, OutExpr))+ -- (simple_bind_pair subst in_var out_rhs)+ -- either extends subst with (in_var -> out_rhs)+ -- or returns Nothing+simple_bind_pair env@(SOE { soe_inl = inl_env, soe_subst = subst })+ in_bndr mb_out_bndr clo@(rhs_env, in_rhs)+ | Type ty <- in_rhs -- let a::* = TYPE ty in <body>+ , let out_ty = substTy (soe_subst rhs_env) ty+ = ASSERT( isTyVar in_bndr )+ (env { soe_subst = extendTvSubst subst in_bndr out_ty }, Nothing)++ | Coercion co <- in_rhs+ , let out_co = optCoercion (getTCvSubst (soe_subst rhs_env)) co+ = ASSERT( isCoVar in_bndr )+ (env { soe_subst = extendCvSubst subst in_bndr out_co }, Nothing)++ | pre_inline_unconditionally+ = (env { soe_inl = extendVarEnv inl_env in_bndr clo }, Nothing)++ | otherwise+ = simple_out_bind_pair env in_bndr mb_out_bndr+ (simple_opt_clo env clo)+ occ active stable_unf+ where+ stable_unf = isStableUnfolding (idUnfolding in_bndr)+ active = isAlwaysActive (idInlineActivation in_bndr)+ occ = idOccInfo in_bndr++ pre_inline_unconditionally :: Bool+ pre_inline_unconditionally+ | isCoVar in_bndr = False -- See Note [Do not inline CoVars unconditionally]+ | isExportedId in_bndr = False -- in SimplUtils+ | stable_unf = False+ | not active = False -- Note [Inline prag in simplOpt]+ | not (safe_to_inline occ) = False+ | otherwise = True++ -- Unconditionally safe to inline+ safe_to_inline :: OccInfo -> Bool+ safe_to_inline (IAmALoopBreaker {}) = False+ safe_to_inline IAmDead = True+ safe_to_inline occ@(OneOcc {}) = not (occ_in_lam occ)+ && occ_one_br occ+ safe_to_inline (ManyOccs {}) = False++-------------------+simple_out_bind :: SimpleOptEnv -> (InVar, OutExpr)+ -> (SimpleOptEnv, Maybe (OutVar, OutExpr))+simple_out_bind env@(SOE { soe_subst = subst }) (in_bndr, out_rhs)+ | Type out_ty <- out_rhs+ = ASSERT( isTyVar in_bndr )+ (env { soe_subst = extendTvSubst subst in_bndr out_ty }, Nothing)++ | Coercion out_co <- out_rhs+ = ASSERT( isCoVar in_bndr )+ (env { soe_subst = extendCvSubst subst in_bndr out_co }, Nothing)++ | otherwise+ = simple_out_bind_pair env in_bndr Nothing out_rhs+ (idOccInfo in_bndr) True False++-------------------+simple_out_bind_pair :: SimpleOptEnv+ -> InId -> Maybe OutId -> OutExpr+ -> OccInfo -> Bool -> Bool+ -> (SimpleOptEnv, Maybe (OutVar, OutExpr))+simple_out_bind_pair env in_bndr mb_out_bndr out_rhs+ occ_info active stable_unf+ | post_inline_unconditionally+ = ( env' { soe_subst = extendIdSubst (soe_subst env) in_bndr out_rhs }+ , Nothing)++ | otherwise+ = ( env', Just (out_bndr, out_rhs) )+ where+ (env', bndr1) = case mb_out_bndr of+ Just out_bndr -> (env, out_bndr)+ Nothing -> subst_opt_bndr env in_bndr+ out_bndr = add_info env' in_bndr bndr1++ post_inline_unconditionally :: Bool+ post_inline_unconditionally+ | not active = False+ | isWeakLoopBreaker occ_info = False -- If it's a loop-breaker of any kind, don't inline+ -- because it might be referred to "earlier"+ | stable_unf = False -- Note [Stable unfoldings and postInlineUnconditionally]+ | isExportedId in_bndr = False -- Note [Exported Ids and trivial RHSs]+ | exprIsTrivial out_rhs = True+ | coercible_hack = True+ | otherwise = False++ -- See Note [Getting the map/coerce RULE to work]+ coercible_hack | (Var fun, args) <- collectArgs out_rhs+ , Just dc <- isDataConWorkId_maybe fun+ , dc `hasKey` heqDataConKey || dc `hasKey` coercibleDataConKey+ = all exprIsTrivial args+ | otherwise+ = False++{- Note [Exported Ids and trivial RHSs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We obviously do not want to unconditionally inline an Id that is exported.+In SimplUtils, Note [Top level and postInlineUnconditionally], we+explain why we don't inline /any/ top-level things unconditionally, even+trivial ones. But we do here! Why? In the simple optimiser++ * We do no rule rewrites+ * We do no call-site inlining++Those differences obviate the reasons for not inlining a trivial rhs,+and increase the benefit for doing so. So we unconditionally inline trivial+rhss here.+-}++----------------------+subst_opt_bndrs :: SimpleOptEnv -> [InVar] -> (SimpleOptEnv, [OutVar])+subst_opt_bndrs env bndrs = mapAccumL subst_opt_bndr env bndrs++subst_opt_bndr :: SimpleOptEnv -> InVar -> (SimpleOptEnv, OutVar)+subst_opt_bndr env bndr+ | isTyVar bndr = (env { soe_subst = subst_tv }, tv')+ | isCoVar bndr = (env { soe_subst = subst_cv }, cv')+ | otherwise = subst_opt_id_bndr env bndr+ where+ subst = soe_subst env+ (subst_tv, tv') = substTyVarBndr subst bndr+ (subst_cv, cv') = substCoVarBndr subst bndr++subst_opt_id_bndr :: SimpleOptEnv -> InId -> (SimpleOptEnv, OutId)+-- Nuke all fragile IdInfo, unfolding, and RULES;+-- it gets added back later by add_info+-- Rather like SimplEnv.substIdBndr+--+-- It's important to zap fragile OccInfo (which CoreSubst.substIdBndr+-- carefully does not do) because simplOptExpr invalidates it++subst_opt_id_bndr (SOE { soe_subst = subst, soe_inl = inl }) old_id+ = (SOE { soe_subst = new_subst, soe_inl = new_inl }, new_id)+ where+ Subst in_scope id_subst tv_subst cv_subst = subst++ id1 = uniqAway in_scope old_id+ id2 = setIdType id1 (substTy subst (idType old_id))+ new_id = zapFragileIdInfo id2+ -- Zaps rules, worker-info, unfolding, and fragile OccInfo+ -- The unfolding and rules will get added back later, by add_info++ new_in_scope = in_scope `extendInScopeSet` new_id++ no_change = new_id == old_id++ -- Extend the substitution if the unique has changed,+ -- See the notes with substTyVarBndr for the delSubstEnv+ new_id_subst+ | no_change = delVarEnv id_subst old_id+ | otherwise = extendVarEnv id_subst old_id (Var new_id)++ new_subst = Subst new_in_scope new_id_subst tv_subst cv_subst+ new_inl = delVarEnv inl old_id++----------------------+add_info :: SimpleOptEnv -> InVar -> OutVar -> OutVar+add_info env old_bndr new_bndr+ | isTyVar old_bndr = new_bndr+ | otherwise = maybeModifyIdInfo mb_new_info new_bndr+ where+ subst = soe_subst env+ mb_new_info = substIdInfo subst new_bndr (idInfo old_bndr)++simpleUnfoldingFun :: IdUnfoldingFun+simpleUnfoldingFun id+ | isAlwaysActive (idInlineActivation id) = idUnfolding id+ | otherwise = noUnfolding++wrapLet :: Maybe (Id,CoreExpr) -> CoreExpr -> CoreExpr+wrapLet Nothing body = body+wrapLet (Just (b,r)) body = Let (NonRec b r) body++------------------+substVects :: Subst -> [CoreVect] -> [CoreVect]+substVects subst = map (substVect subst)++------------------+substVect :: Subst -> CoreVect -> CoreVect+substVect subst (Vect v rhs) = Vect v (simpleOptExprWith subst rhs)+substVect _subst vd@(NoVect _) = vd+substVect _subst vd@(VectType _ _ _) = vd+substVect _subst vd@(VectClass _) = vd+substVect _subst vd@(VectInst _) = vd++{-+Note [Inline prag in simplOpt]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If there's an INLINE/NOINLINE pragma that restricts the phase in+which the binder can be inlined, we don't inline here; after all,+we don't know what phase we're in. Here's an example++ foo :: Int -> Int -> Int+ {-# INLINE foo #-}+ foo m n = inner m+ where+ {-# INLINE [1] inner #-}+ inner m = m+n++ bar :: Int -> Int+ bar n = foo n 1++When inlining 'foo' in 'bar' we want the let-binding for 'inner'+to remain visible until Phase 1++Note [Unfold compulsory unfoldings in LHSs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When the user writes `RULES map coerce = coerce` as a rule, the rule+will only ever match if simpleOptExpr replaces coerce by its unfolding+on the LHS, because that is the core that the rule matching engine+will find. So do that for everything that has a compulsory+unfolding. Also see Note [Desugaring coerce as cast] in Desugar.++However, we don't want to inline 'seq', which happens to also have a+compulsory unfolding, so we only do this unfolding only for things+that are always-active. See Note [User-defined RULES for seq] in MkId.++Note [Getting the map/coerce RULE to work]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We wish to allow the "map/coerce" RULE to fire:++ {-# RULES "map/coerce" map coerce = coerce #-}++The naive core produced for this is++ forall a b (dict :: Coercible * a b).+ map @a @b (coerce @a @b @dict) = coerce @[a] @[b] @dict'++ where dict' :: Coercible [a] [b]+ dict' = ...++This matches literal uses of `map coerce` in code, but that's not what we+want. We want it to match, say, `map MkAge` (where newtype Age = MkAge Int)+too. Some of this is addressed by compulsorily unfolding coerce on the LHS,+yielding++ forall a b (dict :: Coercible * a b).+ map @a @b (\(x :: a) -> case dict of+ MkCoercible (co :: a ~R# b) -> x |> co) = ...++Getting better. But this isn't exactly what gets produced. This is because+Coercible essentially has ~R# as a superclass, and superclasses get eagerly+extracted during solving. So we get this:++ forall a b (dict :: Coercible * a b).+ case Coercible_SCSel @* @a @b dict of+ _ [Dead] -> map @a @b (\(x :: a) -> case dict of+ MkCoercible (co :: a ~R# b) -> x |> co) = ...++Unfortunately, this still abstracts over a Coercible dictionary. We really+want it to abstract over the ~R# evidence. So, we have Desugar.unfold_coerce,+which transforms the above to (see also Note [Desugaring coerce as cast] in+Desugar)++ forall a b (co :: a ~R# b).+ let dict = MkCoercible @* @a @b co in+ case Coercible_SCSel @* @a @b dict of+ _ [Dead] -> map @a @b (\(x :: a) -> case dict of+ MkCoercible (co :: a ~R# b) -> x |> co) = let dict = ... in ...++Now, we need simpleOptExpr to fix this up. It does so by taking three+separate actions:+ 1. Inline certain non-recursive bindings. The choice whether to inline+ is made in simple_bind_pair. Note the rather specific check for+ MkCoercible in there.++ 2. Stripping case expressions like the Coercible_SCSel one.+ See the `Case` case of simple_opt_expr's `go` function.++ 3. Look for case expressions that unpack something that was+ just packed and inline them. This is also done in simple_opt_expr's+ `go` function.++This is all a fair amount of special-purpose hackery, but it's for+a good cause. And it won't hurt other RULES and such that it comes across.+++************************************************************************+* *+ Join points+* *+************************************************************************+-}++-- | Returns Just (bndr,rhs) if the binding is a join point:+-- If it's a JoinId, just return it+-- If it's not yet a JoinId but is always tail-called,+-- make it into a JoinId and return it.+-- In the latter case, eta-expand the RHS if necessary, to make the+-- lambdas explicit, as is required for join points+--+-- Precondition: the InBndr has been occurrence-analysed,+-- so its OccInfo is valid+joinPointBinding_maybe :: InBndr -> InExpr -> Maybe (InBndr, InExpr)+joinPointBinding_maybe bndr rhs+ | not (isId bndr)+ = Nothing++ | isJoinId bndr+ = Just (bndr, rhs)++ | AlwaysTailCalled join_arity <- tailCallInfo (idOccInfo bndr)+ , not (bad_unfolding join_arity (idUnfolding bndr))+ , (bndrs, body) <- etaExpandToJoinPoint join_arity rhs+ = Just (bndr `asJoinId` join_arity, mkLams bndrs body)++ | otherwise+ = Nothing++ where+ -- bad_unfolding returns True if we should /not/ convert a non-join-id+ -- into a join-id, even though it is AlwaysTailCalled+ -- See Note [Join points and INLINE pragmas]+ bad_unfolding join_arity (CoreUnfolding { uf_src = src, uf_tmpl = rhs })+ = isStableSource src && join_arity > joinRhsArity rhs+ bad_unfolding _ (DFunUnfolding {})+ = True+ bad_unfolding _ _+ = False++joinPointBindings_maybe :: [(InBndr, InExpr)] -> Maybe [(InBndr, InExpr)]+joinPointBindings_maybe bndrs+ = mapM (uncurry joinPointBinding_maybe) bndrs+++{- Note [Join points and INLINE pragmas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f x = let g = \x. not -- Arity 1+ {-# INLINE g #-}+ in case x of+ A -> g True True+ B -> g True False+ C -> blah2++Here 'g' is always tail-called applied to 2 args, but the stable+unfolding captured by the INLINE pragma has arity 1. If we try to+convert g to be a join point, its unfolding will still have arity 1+(since it is stable, and we don't meddle with stable unfoldings), and+Lint will complain (see Note [Invariants on join points], (2a), in+CoreSyn. Trac #13413.++Moreover, since g is going to be inlined anyway, there is no benefit+from making it a join point.++If it is recursive, and uselessly marked INLINE, this will stop us+making it a join point, which is a annoying. But occasionally+(notably in class methods; see Note [Instances and loop breakers] in+TcInstDcls) we mark recurive things as INLINE but the recursion+unravels; so ignoring INLINE pragmas on recursive things isn't good+either.+++************************************************************************+* *+ exprIsConApp_maybe+* *+************************************************************************++Note [exprIsConApp_maybe]+~~~~~~~~~~~~~~~~~~~~~~~~~+exprIsConApp_maybe is a very important function. There are two principal+uses:+ * case e of { .... }+ * cls_op e, where cls_op is a class operation++In both cases you want to know if e is of form (C e1..en) where C is+a data constructor.++However e might not *look* as if+++Note [exprIsConApp_maybe on literal strings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See #9400 and #13317.++Conceptually, a string literal "abc" is just ('a':'b':'c':[]), but in Core+they are represented as unpackCString# "abc"# by MkCore.mkStringExprFS, or+unpackCStringUtf8# when the literal contains multi-byte UTF8 characters.++For optimizations we want to be able to treat it as a list, so they can be+decomposed when used in a case-statement. exprIsConApp_maybe detects those+calls to unpackCString# and returns:++Just (':', [Char], ['a', unpackCString# "bc"]).++We need to be careful about UTF8 strings here. ""# contains a ByteString, so+we must parse it back into a FastString to split off the first character.+That way we can treat unpackCString# and unpackCStringUtf8# in the same way.++We must also be caeful about+ lvl = "foo"#+ ...(unpackCString# lvl)...+to ensure that we see through the let-binding for 'lvl'. Hence the+(exprIsLiteral_maybe .. arg) in the guard before the call to+dealWithStringLiteral.++Note [Push coercions in exprIsConApp_maybe]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In Trac #13025 I found a case where we had+ op (df @t1 @t2) -- op is a ClassOp+where+ df = (/\a b. K e1 e2) |> g++To get this to come out we need to simplify on the fly+ ((/\a b. K e1 e2) |> g) @t1 @t2++Hence the use of pushCoArgs.+-}++data ConCont = CC [CoreExpr] Coercion+ -- Substitution already applied++-- | Returns @Just (dc, [t1..tk], [x1..xn])@ if the argument expression is+-- a *saturated* constructor application of the form @dc t1..tk x1 .. xn@,+-- where t1..tk are the *universally-qantified* type args of 'dc'+exprIsConApp_maybe :: InScopeEnv -> CoreExpr -> Maybe (DataCon, [Type], [CoreExpr])+exprIsConApp_maybe (in_scope, id_unf) expr+ = go (Left in_scope) expr (CC [] (mkRepReflCo (exprType expr)))+ where+ go :: Either InScopeSet Subst+ -- Left in-scope means "empty substitution"+ -- Right subst means "apply this substitution to the CoreExpr"+ -> CoreExpr -> ConCont+ -> Maybe (DataCon, [Type], [CoreExpr])+ go subst (Tick t expr) cont+ | not (tickishIsCode t) = go subst expr cont+ go subst (Cast expr co1) (CC args co2)+ | Just (args', co1') <- pushCoArgs (subst_co subst co1) args+ -- See Note [Push coercions in exprIsConApp_maybe]+ = go subst expr (CC args' (co1' `mkTransCo` co2))+ go subst (App fun arg) (CC args co)+ = go subst fun (CC (subst_arg subst arg : args) co)+ go subst (Lam var body) (CC (arg:args) co)+ | exprIsTrivial arg -- Don't duplicate stuff!+ = go (extend subst var arg) body (CC args co)+ go (Right sub) (Var v) cont+ = go (Left (substInScope sub))+ (lookupIdSubst (text "exprIsConApp" <+> ppr expr) sub v)+ cont++ go (Left in_scope) (Var fun) cont@(CC args co)++ | Just con <- isDataConWorkId_maybe fun+ , count isValArg args == idArity fun+ = pushCoDataCon con args co++ -- Look through dictionary functions; see Note [Unfolding DFuns]+ | DFunUnfolding { df_bndrs = bndrs, df_con = con, df_args = dfun_args } <- unfolding+ , bndrs `equalLength` args -- See Note [DFun arity check]+ , let subst = mkOpenSubst in_scope (bndrs `zip` args)+ = pushCoDataCon con (map (substExpr (text "exprIsConApp1") subst) dfun_args) co++ -- Look through unfoldings, but only arity-zero one;+ -- if arity > 0 we are effectively inlining a function call,+ -- and that is the business of callSiteInline.+ -- In practice, without this test, most of the "hits" were+ -- CPR'd workers getting inlined back into their wrappers,+ | idArity fun == 0+ , Just rhs <- expandUnfolding_maybe unfolding+ , let in_scope' = extendInScopeSetSet in_scope (exprFreeVars rhs)+ = go (Left in_scope') rhs cont++ -- See Note [exprIsConApp_maybe on literal strings]+ | (fun `hasKey` unpackCStringIdKey) ||+ (fun `hasKey` unpackCStringUtf8IdKey)+ , [arg] <- args+ , Just (MachStr str) <- exprIsLiteral_maybe (in_scope, id_unf) arg+ = dealWithStringLiteral fun str co+ where+ unfolding = id_unf fun++ go _ _ _ = Nothing++ ----------------------------+ -- Operations on the (Either InScopeSet CoreSubst)+ -- The Left case is wildly dominant+ subst_co (Left {}) co = co+ subst_co (Right s) co = CoreSubst.substCo s co++ subst_arg (Left {}) e = e+ subst_arg (Right s) e = substExpr (text "exprIsConApp2") s e++ extend (Left in_scope) v e = Right (extendSubst (mkEmptySubst in_scope) v e)+ extend (Right s) v e = Right (extendSubst s v e)+++-- See Note [exprIsConApp_maybe on literal strings]+dealWithStringLiteral :: Var -> BS.ByteString -> Coercion+ -> Maybe (DataCon, [Type], [CoreExpr])++-- This is not possible with user-supplied empty literals, MkCore.mkStringExprFS+-- turns those into [] automatically, but just in case something else in GHC+-- generates a string literal directly.+dealWithStringLiteral _ str co+ | BS.null str+ = pushCoDataCon nilDataCon [Type charTy] co++dealWithStringLiteral fun str co+ = let strFS = mkFastStringByteString str++ char = mkConApp charDataCon [mkCharLit (headFS strFS)]+ charTail = fastStringToByteString (tailFS strFS)++ -- In singleton strings, just add [] instead of unpackCstring# ""#.+ rest = if BS.null charTail+ then mkConApp nilDataCon [Type charTy]+ else App (Var fun)+ (Lit (MachStr charTail))++ in pushCoDataCon consDataCon [Type charTy, char, rest] co++{-+Note [Unfolding DFuns]+~~~~~~~~~~~~~~~~~~~~~~+DFuns look like++ df :: forall a b. (Eq a, Eq b) -> Eq (a,b)+ df a b d_a d_b = MkEqD (a,b) ($c1 a b d_a d_b)+ ($c2 a b d_a d_b)++So to split it up we just need to apply the ops $c1, $c2 etc+to the very same args as the dfun. It takes a little more work+to compute the type arguments to the dictionary constructor.++Note [DFun arity check]+~~~~~~~~~~~~~~~~~~~~~~~+Here we check that the total number of supplied arguments (inclding+type args) matches what the dfun is expecting. This may be *less*+than the ordinary arity of the dfun: see Note [DFun unfoldings] in CoreSyn+-}++exprIsLiteral_maybe :: InScopeEnv -> CoreExpr -> Maybe Literal+-- Same deal as exprIsConApp_maybe, but much simpler+-- Nevertheless we do need to look through unfoldings for+-- Integer and string literals, which are vigorously hoisted to top level+-- and not subsequently inlined+exprIsLiteral_maybe env@(_, id_unf) e+ = case e of+ Lit l -> Just l+ Tick _ e' -> exprIsLiteral_maybe env e' -- dubious?+ Var v | Just rhs <- expandUnfolding_maybe (id_unf v)+ -> exprIsLiteral_maybe env rhs+ _ -> Nothing++{-+Note [exprIsLambda_maybe]+~~~~~~~~~~~~~~~~~~~~~~~~~~+exprIsLambda_maybe will, given an expression `e`, try to turn it into the form+`Lam v e'` (returned as `Just (v,e')`). Besides using lambdas, it looks through+casts (using the Push rule), and it unfolds function calls if the unfolding+has a greater arity than arguments are present.++Currently, it is used in Rules.match, and is required to make+"map coerce = coerce" match.+-}++exprIsLambda_maybe :: InScopeEnv -> CoreExpr+ -> Maybe (Var, CoreExpr,[Tickish Id])+ -- See Note [exprIsLambda_maybe]++-- The simple case: It is a lambda already+exprIsLambda_maybe _ (Lam x e)+ = Just (x, e, [])++-- Still straightforward: Ticks that we can float out of the way+exprIsLambda_maybe (in_scope_set, id_unf) (Tick t e)+ | tickishFloatable t+ , Just (x, e, ts) <- exprIsLambda_maybe (in_scope_set, id_unf) e+ = Just (x, e, t:ts)++-- Also possible: A casted lambda. Push the coercion inside+exprIsLambda_maybe (in_scope_set, id_unf) (Cast casted_e co)+ | Just (x, e,ts) <- exprIsLambda_maybe (in_scope_set, id_unf) casted_e+ -- Only do value lambdas.+ -- this implies that x is not in scope in gamma (makes this code simpler)+ , not (isTyVar x) && not (isCoVar x)+ , ASSERT( not $ x `elemVarSet` tyCoVarsOfCo co) True+ , Just (x',e') <- pushCoercionIntoLambda in_scope_set x e co+ , let res = Just (x',e',ts)+ = --pprTrace "exprIsLambda_maybe:Cast" (vcat [ppr casted_e,ppr co,ppr res)])+ res++-- Another attempt: See if we find a partial unfolding+exprIsLambda_maybe (in_scope_set, id_unf) e+ | (Var f, as, ts) <- collectArgsTicks tickishFloatable e+ , idArity f > count isValArg as+ -- Make sure there is hope to get a lambda+ , Just rhs <- expandUnfolding_maybe (id_unf f)+ -- Optimize, for beta-reduction+ , let e' = simpleOptExprWith (mkEmptySubst in_scope_set) (rhs `mkApps` as)+ -- Recurse, because of possible casts+ , Just (x', e'', ts') <- exprIsLambda_maybe (in_scope_set, id_unf) e'+ , let res = Just (x', e'', ts++ts')+ = -- pprTrace "exprIsLambda_maybe:Unfold" (vcat [ppr e, ppr (x',e'')])+ res++exprIsLambda_maybe _ _e+ = -- pprTrace "exprIsLambda_maybe:Fail" (vcat [ppr _e])+ Nothing+++{- *********************************************************************+* *+ The "push rules"+* *+************************************************************************++Here we implement the "push rules" from FC papers:++* The push-argument rules, where we can move a coercion past an argument.+ We have+ (fun |> co) arg+ and we want to transform it to+ (fun arg') |> co'+ for some suitable co' and tranformed arg'.++* The PushK rule for data constructors. We have+ (K e1 .. en) |> co+ and we want to tranform to+ (K e1' .. en')+ by pushing the coercion into the oarguments+-}++pushCoArgs :: Coercion -> [CoreArg] -> Maybe ([CoreArg], Coercion)+pushCoArgs co [] = return ([], co)+pushCoArgs co (arg:args) = do { (arg', co1) <- pushCoArg co arg+ ; (args', co2) <- pushCoArgs co1 args+ ; return (arg':args', co2) }++pushCoArg :: Coercion -> CoreArg -> Maybe (CoreArg, Coercion)+-- We have (fun |> co) arg, and we want to transform it to+-- (fun arg) |> co+-- This may fail, e.g. if (fun :: N) where N is a newtype+-- C.f. simplCast in Simplify.hs+-- 'co' is always Representational++pushCoArg co (Type ty) = do { (ty', co') <- pushCoTyArg co ty+ ; return (Type ty', co') }+pushCoArg co val_arg = do { (arg_co, co') <- pushCoValArg co+ ; return (mkCast val_arg arg_co, co') }++pushCoTyArg :: Coercion -> Type -> Maybe (Type, Coercion)+-- We have (fun |> co) @ty+-- Push the coercion through to return+-- (fun @ty') |> co'+-- 'co' is always Representational+pushCoTyArg co ty+ | tyL `eqType` tyR+ = Just (ty, mkRepReflCo (piResultTy tyR ty))++ | isForAllTy tyL+ = ASSERT2( isForAllTy tyR, ppr co $$ ppr ty )+ Just (ty `mkCastTy` mkSymCo co1, co2)++ | otherwise+ = Nothing+ where+ Pair tyL tyR = coercionKind co+ -- co :: tyL ~ tyR+ -- tyL = forall (a1 :: k1). ty1+ -- tyR = forall (a2 :: k2). ty2++ co1 = mkNthCo 0 co+ -- co1 :: k1 ~ k2+ -- Note that NthCo can extract an equality between the kinds+ -- of the types related by a coercion between forall-types.+ -- See the NthCo case in CoreLint.++ co2 = mkInstCo co (mkCoherenceLeftCo (mkNomReflCo ty) co1)+ -- co2 :: ty1[ (ty|>co1)/a1 ] ~ ty2[ ty/a2 ]+ -- Arg of mkInstCo is always nominal, hence mkNomReflCo++pushCoValArg :: Coercion -> Maybe (Coercion, Coercion)+-- We have (fun |> co) arg+-- Push the coercion through to return+-- (fun (arg |> co_arg)) |> co_res+-- 'co' is always Representational+pushCoValArg co+ | tyL `eqType` tyR+ = Just (mkRepReflCo arg, mkRepReflCo res)++ | isFunTy tyL+ , (co1, co2) <- decomposeFunCo co+ -- If co :: (tyL1 -> tyL2) ~ (tyR1 -> tyR2)+ -- then co1 :: tyL1 ~ tyR1+ -- co2 :: tyL2 ~ tyR2+ = ASSERT2( isFunTy tyR, ppr co $$ ppr arg )+ Just (mkSymCo co1, co2)++ | otherwise+ = Nothing+ where+ (arg, res) = splitFunTy tyR+ Pair tyL tyR = coercionKind co++pushCoercionIntoLambda+ :: InScopeSet -> Var -> CoreExpr -> Coercion -> Maybe (Var, CoreExpr)+-- This implements the Push rule from the paper on coercions+-- (\x. e) |> co+-- ===>+-- (\x'. e |> co')+pushCoercionIntoLambda in_scope x e co+ | ASSERT(not (isTyVar x) && not (isCoVar x)) True+ , Pair s1s2 t1t2 <- coercionKind co+ , Just (_s1,_s2) <- splitFunTy_maybe s1s2+ , Just (t1,_t2) <- splitFunTy_maybe t1t2+ = let (co1, co2) = decomposeFunCo co+ -- Should we optimize the coercions here?+ -- Otherwise they might not match too well+ x' = x `setIdType` t1+ in_scope' = in_scope `extendInScopeSet` x'+ subst = extendIdSubst (mkEmptySubst in_scope')+ x+ (mkCast (Var x') co1)+ in Just (x', substExpr (text "pushCoercionIntoLambda") subst e `mkCast` co2)+ | otherwise+ = pprTrace "exprIsLambda_maybe: Unexpected lambda in case" (ppr (Lam x e))+ Nothing++pushCoDataCon :: DataCon -> [CoreExpr] -> Coercion+ -> Maybe (DataCon+ , [Type] -- Universal type args+ , [CoreExpr]) -- All other args incl existentials+-- Implement the KPush reduction rule as described in "Down with kinds"+-- The transformation applies iff we have+-- (C e1 ... en) `cast` co+-- where co :: (T t1 .. tn) ~ to_ty+-- The left-hand one must be a T, because exprIsConApp returned True+-- but the right-hand one might not be. (Though it usually will.)+pushCoDataCon dc dc_args co+ | isReflCo co || from_ty `eqType` to_ty -- try cheap test first+ , let (univ_ty_args, rest_args) = splitAtList (dataConUnivTyVars dc) dc_args+ = Just (dc, map exprToType univ_ty_args, rest_args)++ | Just (to_tc, to_tc_arg_tys) <- splitTyConApp_maybe to_ty+ , to_tc == dataConTyCon dc+ -- These two tests can fail; we might see+ -- (C x y) `cast` (g :: T a ~ S [a]),+ -- where S is a type function. In fact, exprIsConApp+ -- will probably not be called in such circumstances,+ -- but there't nothing wrong with it++ = let+ tc_arity = tyConArity to_tc+ dc_univ_tyvars = dataConUnivTyVars dc+ dc_ex_tyvars = dataConExTyVars dc+ arg_tys = dataConRepArgTys dc++ non_univ_args = dropList dc_univ_tyvars dc_args+ (ex_args, val_args) = splitAtList dc_ex_tyvars non_univ_args++ -- Make the "Psi" from the paper+ omegas = decomposeCo tc_arity co+ (psi_subst, to_ex_arg_tys)+ = liftCoSubstWithEx Representational+ dc_univ_tyvars+ omegas+ dc_ex_tyvars+ (map exprToType ex_args)++ -- Cast the value arguments (which include dictionaries)+ new_val_args = zipWith cast_arg arg_tys val_args+ cast_arg arg_ty arg = mkCast arg (psi_subst arg_ty)++ to_ex_args = map Type to_ex_arg_tys++ dump_doc = vcat [ppr dc, ppr dc_univ_tyvars, ppr dc_ex_tyvars,+ ppr arg_tys, ppr dc_args,+ ppr ex_args, ppr val_args, ppr co, ppr from_ty, ppr to_ty, ppr to_tc ]+ in+ ASSERT2( eqType from_ty (mkTyConApp to_tc (map exprToType $ takeList dc_univ_tyvars dc_args)), dump_doc )+ ASSERT2( equalLength val_args arg_tys, dump_doc )+ Just (dc, to_tc_arg_tys, to_ex_args ++ new_val_args)++ | otherwise+ = Nothing++ where+ Pair from_ty to_ty = coercionKind co++collectBindersPushingCo :: CoreExpr -> ([Var], CoreExpr)+-- Collect lambda binders, pushing coercions inside if possible+-- E.g. (\x.e) |> g g :: <Int> -> blah+-- = (\x. e |> Nth 1 g)+--+-- That is,+--+-- collectBindersPushingCo ((\x.e) |> g) === ([x], e |> Nth 1 g)+collectBindersPushingCo e+ = go [] e+ where+ -- Peel off lambdas until we hit a cast.+ go :: [Var] -> CoreExpr -> ([Var], CoreExpr)+ -- The accumulator is in reverse order+ go bs (Lam b e) = go (b:bs) e+ go bs (Cast e co) = go_c bs e co+ go bs e = (reverse bs, e)++ -- We are in a cast; peel off casts until we hit a lambda.+ go_c :: [Var] -> CoreExpr -> Coercion -> ([Var], CoreExpr)+ -- (go_c bs e c) is same as (go bs e (e |> c))+ go_c bs (Cast e co1) co2 = go_c bs e (co1 `mkTransCo` co2)+ go_c bs (Lam b e) co = go_lam bs b e co+ go_c bs e co = (reverse bs, mkCast e co)++ -- We are in a lambda under a cast; peel off lambdas and build a+ -- new coercion for the body.+ go_lam :: [Var] -> Var -> CoreExpr -> Coercion -> ([Var], CoreExpr)+ -- (go_lam bs b e c) is same as (go_c bs (\b.e) c)+ go_lam bs b e co+ | isTyVar b+ , let Pair tyL tyR = coercionKind co+ , ASSERT( isForAllTy tyL )+ isForAllTy tyR+ , isReflCo (mkNthCo 0 co) -- See Note [collectBindersPushingCo]+ = go_c (b:bs) e (mkInstCo co (mkNomReflCo (mkTyVarTy b)))++ | isId b+ , let Pair tyL tyR = coercionKind co+ , ASSERT( isFunTy tyL) isFunTy tyR+ , (co_arg, co_res) <- decomposeFunCo co+ , isReflCo co_arg -- See Note [collectBindersPushingCo]+ = go_c (b:bs) e co_res++ | otherwise = (reverse bs, mkCast (Lam b e) co)++{- Note [collectBindersPushingCo]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We just look for coercions of form+ <type> -> blah+(and similarly for foralls) to keep this function simple. We could do+more elaborate stuff, but it'd involve substitution etc.+-}
+ coreSyn/CorePrep.hs view
@@ -0,0 +1,1587 @@+{-+(c) The University of Glasgow, 1994-2006+++Core pass to saturate constructors and PrimOps+-}++{-# LANGUAGE BangPatterns, CPP, MultiWayIf #-}++module CorePrep (+ corePrepPgm, corePrepExpr, cvtLitInteger,+ lookupMkIntegerName, lookupIntegerSDataConName+ ) where++#include "HsVersions.h"++import OccurAnal++import HscTypes+import PrelNames+import MkId ( realWorldPrimId )+import CoreUtils+import CoreArity+import CoreFVs+import CoreMonad ( CoreToDo(..) )+import CoreLint ( endPassIO )+import CoreSyn+import CoreSubst+import MkCore hiding( FloatBind(..) ) -- We use our own FloatBind here+import Type+import Literal+import Coercion+import TcEnv+import TyCon+import Demand+import Var+import VarSet+import VarEnv+import Id+import IdInfo+import TysWiredIn+import DataCon+import PrimOp+import BasicTypes+import Module+import UniqSupply+import Maybes+import OrdList+import ErrUtils+import DynFlags+import Util+import Pair+import Outputable+import Platform+import FastString+import Config+import Name ( NamedThing(..), nameSrcSpan )+import SrcLoc ( SrcSpan(..), realSrcLocSpan, mkRealSrcLoc )+import Data.Bits+import MonadUtils ( mapAccumLM )+import Data.List ( mapAccumL )+import Control.Monad++{-+-- ---------------------------------------------------------------------------+-- Overview+-- ---------------------------------------------------------------------------++The goal of this pass is to prepare for code generation.++1. Saturate constructor and primop applications.++2. Convert to A-normal form; that is, function arguments+ are always variables.++ * Use case for strict arguments:+ f E ==> case E of x -> f x+ (where f is strict)++ * Use let for non-trivial lazy arguments+ f E ==> let x = E in f x+ (were f is lazy and x is non-trivial)++3. Similarly, convert any unboxed lets into cases.+ [I'm experimenting with leaving 'ok-for-speculation'+ rhss in let-form right up to this point.]++4. Ensure that *value* lambdas only occur as the RHS of a binding+ (The code generator can't deal with anything else.)+ Type lambdas are ok, however, because the code gen discards them.++5. [Not any more; nuked Jun 2002] Do the seq/par munging.++6. Clone all local Ids.+ This means that all such Ids are unique, rather than the+ weaker guarantee of no clashes which the simplifier provides.+ And that is what the code generator needs.++ We don't clone TyVars or CoVars. The code gen doesn't need that,+ and doing so would be tiresome because then we'd need+ to substitute in types and coercions.++7. Give each dynamic CCall occurrence a fresh unique; this is+ rather like the cloning step above.++8. Inject bindings for the "implicit" Ids:+ * Constructor wrappers+ * Constructor workers+ We want curried definitions for all of these in case they+ aren't inlined by some caller.++9. Replace (lazy e) by e. See Note [lazyId magic] in MkId.hs+ Also replace (noinline e) by e.++10. Convert (LitInteger i t) into the core representation+ for the Integer i. Normally this uses mkInteger, but if+ we are using the integer-gmp implementation then there is a+ special case where we use the S# constructor for Integers that+ are in the range of Int.++11. Uphold tick consistency while doing this: We move ticks out of+ (non-type) applications where we can, and make sure that we+ annotate according to scoping rules when floating.++This is all done modulo type applications and abstractions, so that+when type erasure is done for conversion to STG, we don't end up with+any trivial or useless bindings.+++Note [CorePrep invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is the syntax of the Core produced by CorePrep:++ Trivial expressions+ arg ::= lit | var+ | arg ty | /\a. arg+ | truv co | /\c. arg | arg |> co++ Applications+ app ::= lit | var | app arg | app ty | app co | app |> co++ Expressions+ body ::= app+ | let(rec) x = rhs in body -- Boxed only+ | case body of pat -> body+ | /\a. body | /\c. body+ | body |> co++ Right hand sides (only place where value lambdas can occur)+ rhs ::= /\a.rhs | \x.rhs | body++We define a synonym for each of these non-terminals. Functions+with the corresponding name produce a result in that syntax.+-}++type CpeArg = CoreExpr -- Non-terminal 'arg'+type CpeApp = CoreExpr -- Non-terminal 'app'+type CpeBody = CoreExpr -- Non-terminal 'body'+type CpeRhs = CoreExpr -- Non-terminal 'rhs'++{-+************************************************************************+* *+ Top level stuff+* *+************************************************************************+-}++corePrepPgm :: HscEnv -> Module -> ModLocation -> CoreProgram -> [TyCon]+ -> IO CoreProgram+corePrepPgm hsc_env this_mod mod_loc binds data_tycons =+ withTiming (pure dflags)+ (text "CorePrep"<+>brackets (ppr this_mod))+ (const ()) $ do+ us <- mkSplitUniqSupply 's'+ initialCorePrepEnv <- mkInitialCorePrepEnv dflags hsc_env++ let implicit_binds = mkDataConWorkers dflags mod_loc data_tycons+ -- NB: we must feed mkImplicitBinds through corePrep too+ -- so that they are suitably cloned and eta-expanded++ binds_out = initUs_ us $ do+ floats1 <- corePrepTopBinds initialCorePrepEnv binds+ floats2 <- corePrepTopBinds initialCorePrepEnv implicit_binds+ return (deFloatTop (floats1 `appendFloats` floats2))++ endPassIO hsc_env alwaysQualify CorePrep binds_out []+ return binds_out+ where+ dflags = hsc_dflags hsc_env++corePrepExpr :: DynFlags -> HscEnv -> CoreExpr -> IO CoreExpr+corePrepExpr dflags hsc_env expr =+ withTiming (pure dflags) (text "CorePrep [expr]") (const ()) $ do+ us <- mkSplitUniqSupply 's'+ initialCorePrepEnv <- mkInitialCorePrepEnv dflags hsc_env+ let new_expr = initUs_ us (cpeBodyNF initialCorePrepEnv expr)+ dumpIfSet_dyn dflags Opt_D_dump_prep "CorePrep" (ppr new_expr)+ return new_expr++corePrepTopBinds :: CorePrepEnv -> [CoreBind] -> UniqSM Floats+-- Note [Floating out of top level bindings]+corePrepTopBinds initialCorePrepEnv binds+ = go initialCorePrepEnv binds+ where+ go _ [] = return emptyFloats+ go env (bind : binds) = do (env', floats, maybe_new_bind)+ <- cpeBind TopLevel env bind+ MASSERT(isNothing maybe_new_bind)+ -- Only join points get returned this way by+ -- cpeBind, and no join point may float to top+ floatss <- go env' binds+ return (floats `appendFloats` floatss)++mkDataConWorkers :: DynFlags -> ModLocation -> [TyCon] -> [CoreBind]+-- See Note [Data constructor workers]+-- c.f. Note [Injecting implicit bindings] in TidyPgm+mkDataConWorkers dflags mod_loc data_tycons+ = [ NonRec id (tick_it (getName data_con) (Var id))+ -- The ice is thin here, but it works+ | tycon <- data_tycons, -- CorePrep will eta-expand it+ data_con <- tyConDataCons tycon,+ let id = dataConWorkId data_con+ ]+ where+ -- If we want to generate debug info, we put a source note on the+ -- worker. This is useful, especially for heap profiling.+ tick_it name+ | debugLevel dflags == 0 = id+ | RealSrcSpan span <- nameSrcSpan name = tick span+ | Just file <- ml_hs_file mod_loc = tick (span1 file)+ | otherwise = tick (span1 "???")+ where tick span = Tick (SourceNote span $ showSDoc dflags (ppr name))+ span1 file = realSrcLocSpan $ mkRealSrcLoc (mkFastString file) 1 1++{-+Note [Floating out of top level bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+NB: we do need to float out of top-level bindings+Consider x = length [True,False]+We want to get+ s1 = False : []+ s2 = True : s1+ x = length s2++We return a *list* of bindings, because we may start with+ x* = f (g y)+where x is demanded, in which case we want to finish with+ a = g y+ x* = f a+And then x will actually end up case-bound++Note [CafInfo and floating]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+What happens when we try to float bindings to the top level? At this+point all the CafInfo is supposed to be correct, and we must make certain+that is true of the new top-level bindings. There are two cases+to consider++a) The top-level binding is marked asCafRefs. In that case we are+ basically fine. The floated bindings had better all be lazy lets,+ so they can float to top level, but they'll all have HasCafRefs+ (the default) which is safe.++b) The top-level binding is marked NoCafRefs. This really happens+ Example. CoreTidy produces+ $fApplicativeSTM [NoCafRefs] = D:Alternative retry# ...blah...+ Now CorePrep has to eta-expand to+ $fApplicativeSTM = let sat = \xy. retry x y+ in D:Alternative sat ...blah...+ So what we *want* is+ sat [NoCafRefs] = \xy. retry x y+ $fApplicativeSTM [NoCafRefs] = D:Alternative sat ...blah...++ So, gruesomely, we must set the NoCafRefs flag on the sat bindings,+ *and* substitute the modified 'sat' into the old RHS.++ It should be the case that 'sat' is itself [NoCafRefs] (a value, no+ cafs) else the original top-level binding would not itself have been+ marked [NoCafRefs]. The DEBUG check in CoreToStg for+ consistentCafInfo will find this.++This is all very gruesome and horrible. It would be better to figure+out CafInfo later, after CorePrep. We'll do that in due course.+Meanwhile this horrible hack works.++Note [Join points and floating]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Join points can float out of other join points but not out of value bindings:++ let z =+ let w = ... in -- can float+ join k = ... in -- can't float+ ... jump k ...+ join j x1 ... xn =+ let y = ... in -- can float (but don't want to)+ join h = ... in -- can float (but not much point)+ ... jump h ...+ in ...++Here, the jump to h remains valid if h is floated outward, but the jump to k+does not.++We don't float *out* of join points. It would only be safe to float out of+nullary join points (or ones where the arguments are all either type arguments+or dead binders). Nullary join points aren't ever recursive, so they're always+effectively one-shot functions, which we don't float out of. We *could* float+join points from nullary join points, but there's no clear benefit at this+stage.++Note [Data constructor workers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Create any necessary "implicit" bindings for data con workers. We+create the rather strange (non-recursive!) binding++ $wC = \x y -> $wC x y++i.e. a curried constructor that allocates. This means that we can+treat the worker for a constructor like any other function in the rest+of the compiler. The point here is that CoreToStg will generate a+StgConApp for the RHS, rather than a call to the worker (which would+give a loop). As Lennart says: the ice is thin here, but it works.++Hmm. Should we create bindings for dictionary constructors? They are+always fully applied, and the bindings are just there to support+partial applications. But it's easier to let them through.+++Note [Dead code in CorePrep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Imagine that we got an input program like this (see Trac #4962):++ f :: Show b => Int -> (Int, b -> Maybe Int -> Int)+ f x = (g True (Just x) + g () (Just x), g)+ where+ g :: Show a => a -> Maybe Int -> Int+ g _ Nothing = x+ g y (Just z) = if z > 100 then g y (Just (z + length (show y))) else g y unknown++After specialisation and SpecConstr, we would get something like this:++ f :: Show b => Int -> (Int, b -> Maybe Int -> Int)+ f x = (g$Bool_True_Just x + g$Unit_Unit_Just x, g)+ where+ {-# RULES g $dBool = g$Bool+ g $dUnit = g$Unit #-}+ g = ...+ {-# RULES forall x. g$Bool True (Just x) = g$Bool_True_Just x #-}+ g$Bool = ...+ {-# RULES forall x. g$Unit () (Just x) = g$Unit_Unit_Just x #-}+ g$Unit = ...+ g$Bool_True_Just = ...+ g$Unit_Unit_Just = ...++Note that the g$Bool and g$Unit functions are actually dead code: they+are only kept alive by the occurrence analyser because they are+referred to by the rules of g, which is being kept alive by the fact+that it is used (unspecialised) in the returned pair.++However, at the CorePrep stage there is no way that the rules for g+will ever fire, and it really seems like a shame to produce an output+program that goes to the trouble of allocating a closure for the+unreachable g$Bool and g$Unit functions.++The way we fix this is to:+ * In cloneBndr, drop all unfoldings/rules++ * In deFloatTop, run a simple dead code analyser on each top-level+ RHS to drop the dead local bindings. For that call to OccAnal, we+ disable the binder swap, else the occurrence analyser sometimes+ introduces new let bindings for cased binders, which lead to the bug+ in #5433.++The reason we don't just OccAnal the whole output of CorePrep is that+the tidier ensures that all top-level binders are GlobalIds, so they+don't show up in the free variables any longer. So if you run the+occurrence analyser on the output of CoreTidy (or later) you e.g. turn+this program:++ Rec {+ f = ... f ...+ }++Into this one:++ f = ... f ...++(Since f is not considered to be free in its own RHS.)+++************************************************************************+* *+ The main code+* *+************************************************************************+-}++cpeBind :: TopLevelFlag -> CorePrepEnv -> CoreBind+ -> UniqSM (CorePrepEnv,+ Floats, -- Floating value bindings+ Maybe CoreBind) -- Just bind' <=> returned new bind; no float+ -- Nothing <=> added bind' to floats instead+cpeBind top_lvl env (NonRec bndr rhs)+ | not (isJoinId bndr)+ = do { (_, bndr1) <- cpCloneBndr env bndr+ ; let dmd = idDemandInfo bndr+ is_unlifted = isUnliftedType (idType bndr)+ ; (floats, bndr2, rhs2) <- cpePair top_lvl NonRecursive+ dmd+ is_unlifted+ env bndr1 rhs+ -- See Note [Inlining in CorePrep]+ ; if exprIsTrivial rhs2 && isNotTopLevel top_lvl+ then return (extendCorePrepEnvExpr env bndr rhs2, floats, Nothing)+ else do {++ ; let new_float = mkFloat dmd is_unlifted bndr2 rhs2++ -- We want bndr'' in the envt, because it records+ -- the evaluated-ness of the binder+ ; return (extendCorePrepEnv env bndr bndr2,+ addFloat floats new_float,+ Nothing) }}+ | otherwise -- See Note [Join points and floating]+ = ASSERT(not (isTopLevel top_lvl)) -- can't have top-level join point+ do { (_, bndr1) <- cpCloneBndr env bndr+ ; (bndr2, rhs1) <- cpeJoinPair env bndr1 rhs+ ; return (extendCorePrepEnv env bndr bndr2,+ emptyFloats,+ Just (NonRec bndr2 rhs1)) }++cpeBind top_lvl env (Rec pairs)+ | not (isJoinId (head bndrs))+ = do { (env', bndrs1) <- cpCloneBndrs env bndrs+ ; stuff <- zipWithM (cpePair top_lvl Recursive topDmd False env') bndrs1 rhss++ ; let (floats_s, bndrs2, rhss2) = unzip3 stuff+ all_pairs = foldrOL add_float (bndrs2 `zip` rhss2)+ (concatFloats floats_s)+ ; return (extendCorePrepEnvList env (bndrs `zip` bndrs2),+ unitFloat (FloatLet (Rec all_pairs)),+ Nothing) }+ | otherwise -- See Note [Join points and floating]+ = do { (env', bndrs1) <- cpCloneBndrs env bndrs+ ; pairs1 <- zipWithM (cpeJoinPair env') bndrs1 rhss++ ; let bndrs2 = map fst pairs1+ ; return (extendCorePrepEnvList env' (bndrs `zip` bndrs2),+ emptyFloats,+ Just (Rec pairs1)) }+ where+ (bndrs, rhss) = unzip pairs++ -- Flatten all the floats, and the current+ -- group into a single giant Rec+ add_float (FloatLet (NonRec b r)) prs2 = (b,r) : prs2+ add_float (FloatLet (Rec prs1)) prs2 = prs1 ++ prs2+ add_float b _ = pprPanic "cpeBind" (ppr b)++---------------+cpePair :: TopLevelFlag -> RecFlag -> Demand -> Bool+ -> CorePrepEnv -> Id -> CoreExpr+ -> UniqSM (Floats, Id, CpeRhs)+-- Used for all bindings+cpePair top_lvl is_rec dmd is_unlifted env bndr rhs+ = ASSERT(not (isJoinId bndr)) -- those should use cpeJoinPair+ do { (floats1, rhs1) <- cpeRhsE env rhs++ -- See if we are allowed to float this stuff out of the RHS+ ; (floats2, rhs2) <- float_from_rhs floats1 rhs1++ -- Make the arity match up+ ; (floats3, rhs3)+ <- if manifestArity rhs1 <= arity+ then return (floats2, cpeEtaExpand arity rhs2)+ else WARN(True, text "CorePrep: silly extra arguments:" <+> ppr bndr)+ -- Note [Silly extra arguments]+ (do { v <- newVar (idType bndr)+ ; let float = mkFloat topDmd False v rhs2+ ; return ( addFloat floats2 float+ , cpeEtaExpand arity (Var v)) })++ -- Wrap floating ticks+ ; let (floats4, rhs4) = wrapTicks floats3 rhs3++ -- Record if the binder is evaluated+ -- and otherwise trim off the unfolding altogether+ -- It's not used by the code generator; getting rid of it reduces+ -- heap usage and, since we may be changing uniques, we'd have+ -- to substitute to keep it right+ ; let bndr' | exprIsHNF rhs3 = bndr `setIdUnfolding` evaldUnfolding+ | otherwise = bndr `setIdUnfolding` noUnfolding++ ; return (floats4, bndr', rhs4) }+ where+ platform = targetPlatform (cpe_dynFlags env)++ arity = idArity bndr -- We must match this arity++ ---------------------+ float_from_rhs floats rhs+ | isEmptyFloats floats = return (emptyFloats, rhs)+ | isTopLevel top_lvl = float_top floats rhs+ | otherwise = float_nested floats rhs++ ---------------------+ float_nested floats rhs+ | wantFloatNested is_rec dmd is_unlifted floats rhs+ = return (floats, rhs)+ | otherwise = dontFloat floats rhs++ ---------------------+ float_top floats rhs -- Urhgh! See Note [CafInfo and floating]+ | mayHaveCafRefs (idCafInfo bndr)+ , allLazyTop floats+ = return (floats, rhs)++ -- So the top-level binding is marked NoCafRefs+ | Just (floats', rhs') <- canFloatFromNoCaf platform floats rhs+ = return (floats', rhs')++ | otherwise+ = dontFloat floats rhs++dontFloat :: Floats -> CpeRhs -> UniqSM (Floats, CpeBody)+-- Non-empty floats, but do not want to float from rhs+-- So wrap the rhs in the floats+-- But: rhs1 might have lambdas, and we can't+-- put them inside a wrapBinds+dontFloat floats1 rhs+ = do { (floats2, body) <- rhsToBody rhs+ ; return (emptyFloats, wrapBinds floats1 $+ wrapBinds floats2 body) }++{- Note [Silly extra arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we had this+ f{arity=1} = \x\y. e+We *must* match the arity on the Id, so we have to generate+ f' = \x\y. e+ f = \x. f' x++It's a bizarre case: why is the arity on the Id wrong? Reason+(in the days of __inline_me__):+ f{arity=0} = __inline_me__ (let v = expensive in \xy. e)+When InlineMe notes go away this won't happen any more. But+it seems good for CorePrep to be robust.+-}++---------------+cpeJoinPair :: CorePrepEnv -> JoinId -> CoreExpr+ -> UniqSM (JoinId, CpeRhs)+-- Used for all join bindings+cpeJoinPair env bndr rhs+ = ASSERT(isJoinId bndr)+ do { let Just join_arity = isJoinId_maybe bndr+ (bndrs, body) = collectNBinders join_arity rhs++ ; (env', bndrs') <- cpCloneBndrs env bndrs++ ; body' <- cpeBodyNF env' body -- Will let-bind the body if it starts+ -- with a lambda++ ; let rhs' = mkCoreLams bndrs' body'+ bndr' = bndr `setIdUnfolding` evaldUnfolding+ `setIdArity` count isId bndrs+ -- See Note [Arity and join points]++ ; return (bndr', rhs') }++{-+Note [Arity and join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Up to now, we've allowed a join point to have an arity greater than its join+arity (minus type arguments), since this is what's useful for eta expansion.+However, for code gen purposes, its arity must be exactly the number of value+arguments it will be called with, and it must have exactly that many value+lambdas. Hence if there are extra lambdas we must let-bind the body of the RHS:++ join j x y z = \w -> ... in ...+ =>+ join j x y z = (let f = \w -> ... in f) in ...++This is also what happens with Note [Silly extra arguments]. Note that it's okay+for us to mess with the arity because a join point is never exported.+-}++-- ---------------------------------------------------------------------------+-- CpeRhs: produces a result satisfying CpeRhs+-- ---------------------------------------------------------------------------++cpeRhsE :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)+-- If+-- e ===> (bs, e')+-- then+-- e = let bs in e' (semantically, that is!)+--+-- For example+-- f (g x) ===> ([v = g x], f v)++cpeRhsE _env expr@(Type {}) = return (emptyFloats, expr)+cpeRhsE _env expr@(Coercion {}) = return (emptyFloats, expr)+cpeRhsE env (Lit (LitInteger i _))+ = cpeRhsE env (cvtLitInteger (cpe_dynFlags env) (getMkIntegerId env)+ (cpe_integerSDataCon env) i)+cpeRhsE _env expr@(Lit {}) = return (emptyFloats, expr)+cpeRhsE env expr@(Var {}) = cpeApp env expr+cpeRhsE env expr@(App {}) = cpeApp env expr++cpeRhsE env (Let bind body)+ = do { (env', bind_floats, maybe_bind') <- cpeBind NotTopLevel env bind+ ; (body_floats, body') <- cpeRhsE env' body+ ; let expr' = case maybe_bind' of Just bind' -> Let bind' body'+ Nothing -> body'+ ; return (bind_floats `appendFloats` body_floats, expr') }++cpeRhsE env (Tick tickish expr)+ | tickishPlace tickish == PlaceNonLam && tickish `tickishScopesLike` SoftScope+ = do { (floats, body) <- cpeRhsE env expr+ -- See [Floating Ticks in CorePrep]+ ; return (unitFloat (FloatTick tickish) `appendFloats` floats, body) }+ | otherwise+ = do { body <- cpeBodyNF env expr+ ; return (emptyFloats, mkTick tickish' body) }+ where+ tickish' | Breakpoint n fvs <- tickish+ -- See also 'substTickish'+ = Breakpoint n (map (getIdFromTrivialExpr . lookupCorePrepEnv env) fvs)+ | otherwise+ = tickish++cpeRhsE env (Cast expr co)+ = do { (floats, expr') <- cpeRhsE env expr+ ; return (floats, Cast expr' co) }++cpeRhsE env expr@(Lam {})+ = do { let (bndrs,body) = collectBinders expr+ ; (env', bndrs') <- cpCloneBndrs env bndrs+ ; body' <- cpeBodyNF env' body+ ; return (emptyFloats, mkLams bndrs' body') }++cpeRhsE env (Case scrut bndr ty alts)+ = do { (floats, scrut') <- cpeBody env scrut+ ; let bndr1 = bndr `setIdUnfolding` evaldUnfolding+ -- Record that the case binder is evaluated in the alternatives+ ; (env', bndr2) <- cpCloneBndr env bndr1+ ; alts' <- mapM (sat_alt env') alts+ ; return (floats, Case scrut' bndr2 ty alts') }+ where+ sat_alt env (con, bs, rhs)+ = do { (env2, bs') <- cpCloneBndrs env bs+ ; rhs' <- cpeBodyNF env2 rhs+ ; return (con, bs', rhs') }++cvtLitInteger :: DynFlags -> Id -> Maybe DataCon -> Integer -> CoreExpr+-- Here we convert a literal Integer to the low-level+-- representation. Exactly how we do this depends on the+-- library that implements Integer. If it's GMP we+-- use the S# data constructor for small literals.+-- See Note [Integer literals] in Literal+cvtLitInteger dflags _ (Just sdatacon) i+ | inIntRange dflags i -- Special case for small integers+ = mkConApp sdatacon [Lit (mkMachInt dflags i)]++cvtLitInteger dflags mk_integer _ i+ = mkApps (Var mk_integer) [isNonNegative, ints]+ where isNonNegative = if i < 0 then mkConApp falseDataCon []+ else mkConApp trueDataCon []+ ints = mkListExpr intTy (f (abs i))+ f 0 = []+ f x = let low = x .&. mask+ high = x `shiftR` bits+ in mkConApp intDataCon [Lit (mkMachInt dflags low)] : f high+ bits = 31+ mask = 2 ^ bits - 1++-- ---------------------------------------------------------------------------+-- CpeBody: produces a result satisfying CpeBody+-- ---------------------------------------------------------------------------++-- | Convert a 'CoreExpr' so it satisfies 'CpeBody', without+-- producing any floats (any generated floats are immediately+-- let-bound using 'wrapBinds'). Generally you want this, esp.+-- when you've reached a binding form (e.g., a lambda) and+-- floating any further would be incorrect.+cpeBodyNF :: CorePrepEnv -> CoreExpr -> UniqSM CpeBody+cpeBodyNF env expr+ = do { (floats, body) <- cpeBody env expr+ ; return (wrapBinds floats body) }++-- | Convert a 'CoreExpr' so it satisfies 'CpeBody'; also produce+-- a list of 'Floats' which are being propagated upwards. In+-- fact, this function is used in only two cases: to+-- implement 'cpeBodyNF' (which is what you usually want),+-- and in the case when a let-binding is in a case scrutinee--here,+-- we can always float out:+--+-- case (let x = y in z) of ...+-- ==> let x = y in case z of ...+--+cpeBody :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeBody)+cpeBody env expr+ = do { (floats1, rhs) <- cpeRhsE env expr+ ; (floats2, body) <- rhsToBody rhs+ ; return (floats1 `appendFloats` floats2, body) }++--------+rhsToBody :: CpeRhs -> UniqSM (Floats, CpeBody)+-- Remove top level lambdas by let-binding++rhsToBody (Tick t expr)+ | tickishScoped t == NoScope -- only float out of non-scoped annotations+ = do { (floats, expr') <- rhsToBody expr+ ; return (floats, mkTick t expr') }++rhsToBody (Cast e co)+ -- You can get things like+ -- case e of { p -> coerce t (\s -> ...) }+ = do { (floats, e') <- rhsToBody e+ ; return (floats, Cast e' co) }++rhsToBody expr@(Lam {})+ | Just no_lam_result <- tryEtaReducePrep bndrs body+ = return (emptyFloats, no_lam_result)+ | all isTyVar bndrs -- Type lambdas are ok+ = return (emptyFloats, expr)+ | otherwise -- Some value lambdas+ = do { fn <- newVar (exprType expr)+ ; let rhs = cpeEtaExpand (exprArity expr) expr+ float = FloatLet (NonRec fn rhs)+ ; return (unitFloat float, Var fn) }+ where+ (bndrs,body) = collectBinders expr++rhsToBody expr = return (emptyFloats, expr)++++-- ---------------------------------------------------------------------------+-- CpeApp: produces a result satisfying CpeApp+-- ---------------------------------------------------------------------------++data ArgInfo = CpeApp CoreArg+ | CpeCast Coercion+ | CpeTick (Tickish Id)++{- Note [runRW arg]+~~~~~~~~~~~~~~~~~~~+If we got, say+ runRW# (case bot of {})+which happened in Trac #11291, we do /not/ want to turn it into+ (case bot of {}) realWorldPrimId#+because that gives a panic in CoreToStg.myCollectArgs, which expects+only variables in function position. But if we are sure to make+runRW# strict (which we do in MkId), this can't happen+-}++cpeApp :: CorePrepEnv -> CoreExpr -> UniqSM (Floats, CpeRhs)+-- May return a CpeRhs because of saturating primops+cpeApp top_env expr+ = do { let (terminal, args, depth) = collect_args expr+ ; cpe_app top_env terminal args depth+ }++ where+ -- We have a nested data structure of the form+ -- e `App` a1 `App` a2 ... `App` an, convert it into+ -- (e, [CpeApp a1, CpeApp a2, ..., CpeApp an], depth)+ -- We use 'ArgInfo' because we may also need to+ -- record casts and ticks. Depth counts the number+ -- of arguments that would consume strictness information+ -- (so, no type or coercion arguments.)+ collect_args :: CoreExpr -> (CoreExpr, [ArgInfo], Int)+ collect_args e = go e [] 0+ where+ go (App fun arg) as !depth+ = go fun (CpeApp arg : as)+ (if isTyCoArg arg then depth else depth + 1)+ go (Cast fun co) as depth+ = go fun (CpeCast co : as) depth+ go (Tick tickish fun) as depth+ | tickishPlace tickish == PlaceNonLam+ && tickish `tickishScopesLike` SoftScope+ = go fun (CpeTick tickish : as) depth+ go terminal as depth = (terminal, as, depth)++ cpe_app :: CorePrepEnv+ -> CoreExpr+ -> [ArgInfo]+ -> Int+ -> UniqSM (Floats, CpeRhs)+ cpe_app env (Var f) (CpeApp Type{} : CpeApp arg : args) depth+ | f `hasKey` lazyIdKey -- Replace (lazy a) with a, and+ || f `hasKey` noinlineIdKey -- Replace (noinline a) with a+ -- Consider the code:+ --+ -- lazy (f x) y+ --+ -- We need to make sure that we need to recursively collect arguments on+ -- "f x", otherwise we'll float "f x" out (it's not a variable) and+ -- end up with this awful -ddump-prep:+ --+ -- case f x of f_x {+ -- __DEFAULT -> f_x y+ -- }+ --+ -- rather than the far superior "f x y". Test case is par01.+ = let (terminal, args', depth') = collect_args arg+ in cpe_app env terminal (args' ++ args) (depth + depth' - 1)+ cpe_app env (Var f) [CpeApp _runtimeRep@Type{}, CpeApp _type@Type{}, CpeApp arg] 1+ | f `hasKey` runRWKey+ -- Replace (runRW# f) by (f realWorld#), beta reducing if possible (this+ -- is why we return a CorePrepEnv as well)+ = case arg of+ Lam s body -> cpe_app (extendCorePrepEnv env s realWorldPrimId) body [] 0+ _ -> cpe_app env arg [CpeApp (Var realWorldPrimId)] 1+ cpe_app env (Var v) args depth+ = do { v1 <- fiddleCCall v+ ; let e2 = lookupCorePrepEnv env v1+ hd = getIdFromTrivialExpr_maybe e2+ -- NB: depth from collect_args is right, because e2 is a trivial expression+ -- and thus its embedded Id *must* be at the same depth as any+ -- Apps it is under are type applications only (c.f.+ -- exprIsTrivial). But note that we need the type of the+ -- expression, not the id.+ ; (app, floats) <- rebuild_app args e2 (exprType e2) emptyFloats stricts+ ; mb_saturate hd app floats depth }+ where+ stricts = case idStrictness v of+ StrictSig (DmdType _ demands _)+ | listLengthCmp demands depth /= GT -> demands+ -- length demands <= depth+ | otherwise -> []+ -- If depth < length demands, then we have too few args to+ -- satisfy strictness info so we have to ignore all the+ -- strictness info, e.g. + (error "urk")+ -- Here, we can't evaluate the arg strictly, because this+ -- partial application might be seq'd++ -- We inlined into something that's not a var and has no args.+ -- Bounce it back up to cpeRhsE.+ cpe_app env fun [] _ = cpeRhsE env fun++ -- N-variable fun, better let-bind it+ cpe_app env fun args depth+ = do { (fun_floats, fun') <- cpeArg env evalDmd fun ty+ -- The evalDmd says that it's sure to be evaluated,+ -- so we'll end up case-binding it+ ; (app, floats) <- rebuild_app args fun' ty fun_floats []+ ; mb_saturate Nothing app floats depth }+ where+ ty = exprType fun++ -- Saturate if necessary+ mb_saturate head app floats depth =+ case head of+ Just fn_id -> do { sat_app <- maybeSaturate fn_id app depth+ ; return (floats, sat_app) }+ _other -> return (floats, app)++ -- Deconstruct and rebuild the application, floating any non-atomic+ -- arguments to the outside. We collect the type of the expression,+ -- the head of the application, and the number of actual value arguments,+ -- all of which are used to possibly saturate this application if it+ -- has a constructor or primop at the head.+ rebuild_app+ :: [ArgInfo] -- The arguments (inner to outer)+ -> CpeApp+ -> Type+ -> Floats+ -> [Demand]+ -> UniqSM (CpeApp, Floats)+ rebuild_app [] app _ floats ss = do+ MASSERT(null ss) -- make sure we used all the strictness info+ return (app, floats)+ rebuild_app (a : as) fun' fun_ty floats ss = case a of+ CpeApp arg@(Type arg_ty) ->+ rebuild_app as (App fun' arg) (piResultTy fun_ty arg_ty) floats ss+ CpeApp arg@(Coercion {}) ->+ rebuild_app as (App fun' arg) (funResultTy fun_ty) floats ss+ CpeApp arg -> do+ let (ss1, ss_rest) -- See Note [lazyId magic] in MkId+ = case (ss, isLazyExpr arg) of+ (_ : ss_rest, True) -> (topDmd, ss_rest)+ (ss1 : ss_rest, False) -> (ss1, ss_rest)+ ([], _) -> (topDmd, [])+ (arg_ty, res_ty) = expectJust "cpeBody:collect_args" $+ splitFunTy_maybe fun_ty+ (fs, arg') <- cpeArg top_env ss1 arg arg_ty+ rebuild_app as (App fun' arg') res_ty (fs `appendFloats` floats) ss_rest+ CpeCast co ->+ let Pair _ty1 ty2 = coercionKind co+ in rebuild_app as (Cast fun' co) ty2 floats ss+ CpeTick tickish ->+ -- See [Floating Ticks in CorePrep]+ rebuild_app as fun' fun_ty (addFloat floats (FloatTick tickish)) ss++isLazyExpr :: CoreExpr -> Bool+-- See Note [lazyId magic] in MkId+isLazyExpr (Cast e _) = isLazyExpr e+isLazyExpr (Tick _ e) = isLazyExpr e+isLazyExpr (Var f `App` _ `App` _) = f `hasKey` lazyIdKey+isLazyExpr _ = False++-- ---------------------------------------------------------------------------+-- CpeArg: produces a result satisfying CpeArg+-- ---------------------------------------------------------------------------++{-+Note [ANF-ising literal string arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Consider a program like,++ data Foo = Foo Addr#++ foo = Foo "turtle"#++When we go to ANFise this we might think that we want to float the string+literal like we do any other non-trivial argument. This would look like,++ foo = u\ [] case "turtle"# of s { __DEFAULT__ -> Foo s }++However, this 1) isn't necessary since strings are in a sense "trivial"; and 2)+wreaks havoc on the CAF annotations that we produce here since we the result+above is caffy since it is updateable. Ideally at some point in the future we+would like to just float the literal to the top level as suggested in #11312,++ s = "turtle"#+ foo = Foo s++However, until then we simply add a special case excluding literals from the+floating done by cpeArg.+-}++-- | Is an argument okay to CPE?+okCpeArg :: CoreExpr -> Bool+-- Don't float literals. See Note [ANF-ising literal string arguments].+okCpeArg (Lit _) = False+-- Do not eta expand a trivial argument+okCpeArg expr = not (exprIsTrivial expr)++-- This is where we arrange that a non-trivial argument is let-bound+cpeArg :: CorePrepEnv -> Demand+ -> CoreArg -> Type -> UniqSM (Floats, CpeArg)+cpeArg env dmd arg arg_ty+ = do { (floats1, arg1) <- cpeRhsE env arg -- arg1 can be a lambda+ ; (floats2, arg2) <- if want_float floats1 arg1+ then return (floats1, arg1)+ else dontFloat floats1 arg1+ -- Else case: arg1 might have lambdas, and we can't+ -- put them inside a wrapBinds++ ; if okCpeArg arg2+ then do { v <- newVar arg_ty+ ; let arg3 = cpeEtaExpand (exprArity arg2) arg2+ arg_float = mkFloat dmd is_unlifted v arg3+ ; return (addFloat floats2 arg_float, varToCoreExpr v) }+ else return (floats2, arg2)+ }+ where+ is_unlifted = isUnliftedType arg_ty+ want_float = wantFloatNested NonRecursive dmd is_unlifted++{-+Note [Floating unlifted arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider C (let v* = expensive in v)++where the "*" indicates "will be demanded". Usually v will have been+inlined by now, but let's suppose it hasn't (see Trac #2756). Then we+do *not* want to get++ let v* = expensive in C v++because that has different strictness. Hence the use of 'allLazy'.+(NB: the let v* turns into a FloatCase, in mkLocalNonRec.)+++------------------------------------------------------------------------------+-- Building the saturated syntax+-- ---------------------------------------------------------------------------++maybeSaturate deals with saturating primops and constructors+The type is the type of the entire application+-}++maybeSaturate :: Id -> CpeApp -> Int -> UniqSM CpeRhs+maybeSaturate fn expr n_args+ | Just DataToTagOp <- isPrimOpId_maybe fn -- DataToTag must have an evaluated arg+ -- A gruesome special case+ = saturateDataToTag sat_expr++ | hasNoBinding fn -- There's no binding+ = return sat_expr++ | otherwise+ = return expr+ where+ fn_arity = idArity fn+ excess_arity = fn_arity - n_args+ sat_expr = cpeEtaExpand excess_arity expr++-------------+saturateDataToTag :: CpeApp -> UniqSM CpeApp+-- See Note [dataToTag magic]+saturateDataToTag sat_expr+ = do { let (eta_bndrs, eta_body) = collectBinders sat_expr+ ; eta_body' <- eval_data2tag_arg eta_body+ ; return (mkLams eta_bndrs eta_body') }+ where+ eval_data2tag_arg :: CpeApp -> UniqSM CpeBody+ eval_data2tag_arg app@(fun `App` arg)+ | exprIsHNF arg -- Includes nullary constructors+ = return app -- The arg is evaluated+ | otherwise -- Arg not evaluated, so evaluate it+ = do { arg_id <- newVar (exprType arg)+ ; let arg_id1 = setIdUnfolding arg_id evaldUnfolding+ ; return (Case arg arg_id1 (exprType app)+ [(DEFAULT, [], fun `App` Var arg_id1)]) }++ eval_data2tag_arg (Tick t app) -- Scc notes can appear+ = do { app' <- eval_data2tag_arg app+ ; return (Tick t app') }++ eval_data2tag_arg other -- Should not happen+ = pprPanic "eval_data2tag" (ppr other)++{-+Note [dataToTag magic]+~~~~~~~~~~~~~~~~~~~~~~+Horrid: we must ensure that the arg of data2TagOp is evaluated+ (data2tag x) --> (case x of y -> data2tag y)+(yuk yuk) take into account the lambdas we've now introduced++How might it not be evaluated? Well, we might have floated it out+of the scope of a `seq`, or dropped the `seq` altogether.+++************************************************************************+* *+ Simple CoreSyn operations+* *+************************************************************************+-}++{-+-- -----------------------------------------------------------------------------+-- Eta reduction+-- -----------------------------------------------------------------------------++Note [Eta expansion]+~~~~~~~~~~~~~~~~~~~~~+Eta expand to match the arity claimed by the binder Remember,+CorePrep must not change arity++Eta expansion might not have happened already, because it is done by+the simplifier only when there at least one lambda already.++NB1:we could refrain when the RHS is trivial (which can happen+ for exported things). This would reduce the amount of code+ generated (a little) and make things a little words for+ code compiled without -O. The case in point is data constructor+ wrappers.++NB2: we have to be careful that the result of etaExpand doesn't+ invalidate any of the assumptions that CorePrep is attempting+ to establish. One possible cause is eta expanding inside of+ an SCC note - we're now careful in etaExpand to make sure the+ SCC is pushed inside any new lambdas that are generated.++Note [Eta expansion and the CorePrep invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It turns out to be much much easier to do eta expansion+*after* the main CorePrep stuff. But that places constraints+on the eta expander: given a CpeRhs, it must return a CpeRhs.++For example here is what we do not want:+ f = /\a -> g (h 3) -- h has arity 2+After ANFing we get+ f = /\a -> let s = h 3 in g s+and now we do NOT want eta expansion to give+ f = /\a -> \ y -> (let s = h 3 in g s) y++Instead CoreArity.etaExpand gives+ f = /\a -> \y -> let s = h 3 in g s y+-}++cpeEtaExpand :: Arity -> CpeRhs -> CpeRhs+cpeEtaExpand arity expr+ | arity == 0 = expr+ | otherwise = etaExpand arity expr++{-+-- -----------------------------------------------------------------------------+-- Eta reduction+-- -----------------------------------------------------------------------------++Why try eta reduction? Hasn't the simplifier already done eta?+But the simplifier only eta reduces if that leaves something+trivial (like f, or f Int). But for deLam it would be enough to+get to a partial application:+ case x of { p -> \xs. map f xs }+ ==> case x of { p -> map f }+-}++tryEtaReducePrep :: [CoreBndr] -> CoreExpr -> Maybe CoreExpr+tryEtaReducePrep bndrs expr@(App _ _)+ | ok_to_eta_reduce f+ , n_remaining >= 0+ , and (zipWith ok bndrs last_args)+ , not (any (`elemVarSet` fvs_remaining) bndrs)+ , exprIsHNF remaining_expr -- Don't turn value into a non-value+ -- else the behaviour with 'seq' changes+ = Just remaining_expr+ where+ (f, args) = collectArgs expr+ remaining_expr = mkApps f remaining_args+ fvs_remaining = exprFreeVars remaining_expr+ (remaining_args, last_args) = splitAt n_remaining args+ n_remaining = length args - length bndrs++ ok bndr (Var arg) = bndr == arg+ ok _ _ = False++ -- We can't eta reduce something which must be saturated.+ ok_to_eta_reduce (Var f) = not (hasNoBinding f)+ ok_to_eta_reduce _ = False -- Safe. ToDo: generalise++tryEtaReducePrep bndrs (Let bind@(NonRec _ r) body)+ | not (any (`elemVarSet` fvs) bndrs)+ = case tryEtaReducePrep bndrs body of+ Just e -> Just (Let bind e)+ Nothing -> Nothing+ where+ fvs = exprFreeVars r++-- NB: do not attempt to eta-reduce across ticks+-- Otherwise we risk reducing+-- \x. (Tick (Breakpoint {x}) f x)+-- ==> Tick (breakpoint {x}) f+-- which is bogus (Trac #17228)+-- tryEtaReducePrep bndrs (Tick tickish e)+-- = fmap (mkTick tickish) $ tryEtaReducePrep bndrs e++tryEtaReducePrep _ _ = Nothing++{-+************************************************************************+* *+ Floats+* *+************************************************************************++Note [Pin demand info on floats]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We pin demand info on floated lets, so that we can see the one-shot thunks.+-}++data FloatingBind+ = FloatLet CoreBind -- Rhs of bindings are CpeRhss+ -- They are always of lifted type;+ -- unlifted ones are done with FloatCase++ | FloatCase+ Id CpeBody+ Bool -- The bool indicates "ok-for-speculation"++ -- | See Note [Floating Ticks in CorePrep]+ | FloatTick (Tickish Id)++data Floats = Floats OkToSpec (OrdList FloatingBind)++instance Outputable FloatingBind where+ ppr (FloatLet b) = ppr b+ ppr (FloatCase b r ok) = brackets (ppr ok) <+> ppr b <+> equals <+> ppr r+ ppr (FloatTick t) = ppr t++instance Outputable Floats where+ ppr (Floats flag fs) = text "Floats" <> brackets (ppr flag) <+>+ braces (vcat (map ppr (fromOL fs)))++instance Outputable OkToSpec where+ ppr OkToSpec = text "OkToSpec"+ ppr IfUnboxedOk = text "IfUnboxedOk"+ ppr NotOkToSpec = text "NotOkToSpec"++-- Can we float these binds out of the rhs of a let? We cache this decision+-- to avoid having to recompute it in a non-linear way when there are+-- deeply nested lets.+data OkToSpec+ = OkToSpec -- Lazy bindings of lifted type+ | IfUnboxedOk -- A mixture of lazy lifted bindings and n+ -- ok-to-speculate unlifted bindings+ | NotOkToSpec -- Some not-ok-to-speculate unlifted bindings++mkFloat :: Demand -> Bool -> Id -> CpeRhs -> FloatingBind+mkFloat dmd is_unlifted bndr rhs+ | use_case = FloatCase bndr rhs (exprOkForSpeculation rhs)+ | is_hnf = FloatLet (NonRec bndr rhs)+ | otherwise = FloatLet (NonRec (setIdDemandInfo bndr dmd) rhs)+ -- See Note [Pin demand info on floats]+ where+ is_hnf = exprIsHNF rhs+ is_strict = isStrictDmd dmd+ use_case = is_unlifted || is_strict && not is_hnf+ -- Don't make a case for a value binding,+ -- even if it's strict. Otherwise we get+ -- case (\x -> e) of ...!++emptyFloats :: Floats+emptyFloats = Floats OkToSpec nilOL++isEmptyFloats :: Floats -> Bool+isEmptyFloats (Floats _ bs) = isNilOL bs++wrapBinds :: Floats -> CpeBody -> CpeBody+wrapBinds (Floats _ binds) body+ = foldrOL mk_bind body binds+ where+ mk_bind (FloatCase bndr rhs _) body = Case rhs bndr (exprType body) [(DEFAULT, [], body)]+ mk_bind (FloatLet bind) body = Let bind body+ mk_bind (FloatTick tickish) body = mkTick tickish body++addFloat :: Floats -> FloatingBind -> Floats+addFloat (Floats ok_to_spec floats) new_float+ = Floats (combine ok_to_spec (check new_float)) (floats `snocOL` new_float)+ where+ check (FloatLet _) = OkToSpec+ check (FloatCase _ _ ok_for_spec)+ | ok_for_spec = IfUnboxedOk+ | otherwise = NotOkToSpec+ check FloatTick{} = OkToSpec+ -- The ok-for-speculation flag says that it's safe to+ -- float this Case out of a let, and thereby do it more eagerly+ -- We need the top-level flag because it's never ok to float+ -- an unboxed binding to the top level++unitFloat :: FloatingBind -> Floats+unitFloat = addFloat emptyFloats++appendFloats :: Floats -> Floats -> Floats+appendFloats (Floats spec1 floats1) (Floats spec2 floats2)+ = Floats (combine spec1 spec2) (floats1 `appOL` floats2)++concatFloats :: [Floats] -> OrdList FloatingBind+concatFloats = foldr (\ (Floats _ bs1) bs2 -> appOL bs1 bs2) nilOL++combine :: OkToSpec -> OkToSpec -> OkToSpec+combine NotOkToSpec _ = NotOkToSpec+combine _ NotOkToSpec = NotOkToSpec+combine IfUnboxedOk _ = IfUnboxedOk+combine _ IfUnboxedOk = IfUnboxedOk+combine _ _ = OkToSpec++deFloatTop :: Floats -> [CoreBind]+-- For top level only; we don't expect any FloatCases+deFloatTop (Floats _ floats)+ = foldrOL get [] floats+ where+ get (FloatLet b) bs = occurAnalyseRHSs b : bs+ get (FloatCase var body _) bs =+ occurAnalyseRHSs (NonRec var body) : bs+ get b _ = pprPanic "corePrepPgm" (ppr b)++ -- See Note [Dead code in CorePrep]+ occurAnalyseRHSs (NonRec x e) = NonRec x (occurAnalyseExpr_NoBinderSwap e)+ occurAnalyseRHSs (Rec xes) = Rec [(x, occurAnalyseExpr_NoBinderSwap e) | (x, e) <- xes]++---------------------------------------------------------------------------++canFloatFromNoCaf :: Platform -> Floats -> CpeRhs -> Maybe (Floats, CpeRhs)+ -- Note [CafInfo and floating]+canFloatFromNoCaf platform (Floats ok_to_spec fs) rhs+ | OkToSpec <- ok_to_spec -- Worth trying+ , Just (subst, fs') <- go (emptySubst, nilOL) (fromOL fs)+ = Just (Floats OkToSpec fs', subst_expr subst rhs)+ | otherwise+ = Nothing+ where+ subst_expr = substExpr (text "CorePrep")++ go :: (Subst, OrdList FloatingBind) -> [FloatingBind]+ -> Maybe (Subst, OrdList FloatingBind)++ go (subst, fbs_out) [] = Just (subst, fbs_out)++ go (subst, fbs_out) (FloatLet (NonRec b r) : fbs_in)+ | rhs_ok r+ = go (subst', fbs_out `snocOL` new_fb) fbs_in+ where+ (subst', b') = set_nocaf_bndr subst b+ new_fb = FloatLet (NonRec b' (subst_expr subst r))++ go (subst, fbs_out) (FloatLet (Rec prs) : fbs_in)+ | all rhs_ok rs+ = go (subst', fbs_out `snocOL` new_fb) fbs_in+ where+ (bs,rs) = unzip prs+ (subst', bs') = mapAccumL set_nocaf_bndr subst bs+ rs' = map (subst_expr subst') rs+ new_fb = FloatLet (Rec (bs' `zip` rs'))++ go (subst, fbs_out) (ft@FloatTick{} : fbs_in)+ = go (subst, fbs_out `snocOL` ft) fbs_in++ go _ _ = Nothing -- Encountered a caffy binding++ ------------+ set_nocaf_bndr subst bndr+ = (extendIdSubst subst bndr (Var bndr'), bndr')+ where+ bndr' = bndr `setIdCafInfo` NoCafRefs++ ------------+ rhs_ok :: CoreExpr -> Bool+ -- We can only float to top level from a NoCaf thing if+ -- the new binding is static. However it can't mention+ -- any non-static things or it would *already* be Caffy+ rhs_ok = rhsIsStatic platform (\_ -> False)+ (\i -> pprPanic "rhsIsStatic" (integer i))+ -- Integer literals should not show up++wantFloatNested :: RecFlag -> Demand -> Bool -> Floats -> CpeRhs -> Bool+wantFloatNested is_rec dmd is_unlifted floats rhs+ = isEmptyFloats floats+ || isStrictDmd dmd+ || is_unlifted+ || (allLazyNested is_rec floats && exprIsHNF rhs)+ -- Why the test for allLazyNested?+ -- v = f (x `divInt#` y)+ -- we don't want to float the case, even if f has arity 2,+ -- because floating the case would make it evaluated too early++allLazyTop :: Floats -> Bool+allLazyTop (Floats OkToSpec _) = True+allLazyTop _ = False++allLazyNested :: RecFlag -> Floats -> Bool+allLazyNested _ (Floats OkToSpec _) = True+allLazyNested _ (Floats NotOkToSpec _) = False+allLazyNested is_rec (Floats IfUnboxedOk _) = isNonRec is_rec++{-+************************************************************************+* *+ Cloning+* *+************************************************************************+-}++-- ---------------------------------------------------------------------------+-- The environment+-- ---------------------------------------------------------------------------++-- Note [Inlining in CorePrep]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- There is a subtle but important invariant that must be upheld in the output+-- of CorePrep: there are no "trivial" updatable thunks. Thus, this Core+-- is impermissible:+--+-- let x :: ()+-- x = y+--+-- (where y is a reference to a GLOBAL variable). Thunks like this are silly:+-- they can always be profitably replaced by inlining x with y. Consequently,+-- the code generator/runtime does not bother implementing this properly+-- (specifically, there is no implementation of stg_ap_0_upd_info, which is the+-- stack frame that would be used to update this thunk. The "0" means it has+-- zero free variables.)+--+-- In general, the inliner is good at eliminating these let-bindings. However,+-- there is one case where these trivial updatable thunks can arise: when+-- we are optimizing away 'lazy' (see Note [lazyId magic], and also+-- 'cpeRhsE'.) Then, we could have started with:+--+-- let x :: ()+-- x = lazy @ () y+--+-- which is a perfectly fine, non-trivial thunk, but then CorePrep will+-- drop 'lazy', giving us 'x = y' which is trivial and impermissible.+-- The solution is CorePrep to have a miniature inlining pass which deals+-- with cases like this. We can then drop the let-binding altogether.+--+-- Why does the removal of 'lazy' have to occur in CorePrep?+-- The gory details are in Note [lazyId magic] in MkId, but the+-- main reason is that lazy must appear in unfoldings (optimizer+-- output) and it must prevent call-by-value for catch# (which+-- is implemented by CorePrep.)+--+-- An alternate strategy for solving this problem is to have the+-- inliner treat 'lazy e' as a trivial expression if 'e' is trivial.+-- We decided not to adopt this solution to keep the definition+-- of 'exprIsTrivial' simple.+--+-- There is ONE caveat however: for top-level bindings we have+-- to preserve the binding so that we float the (hacky) non-recursive+-- binding for data constructors; see Note [Data constructor workers].+--+-- Note [CorePrep inlines trivial CoreExpr not Id]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Why does cpe_env need to be an IdEnv CoreExpr, as opposed to an+-- IdEnv Id? Naively, we might conjecture that trivial updatable thunks+-- as per Note [Inlining in CorePrep] always have the form+-- 'lazy @ SomeType gbl_id'. But this is not true: the following is+-- perfectly reasonable Core:+--+-- let x :: ()+-- x = lazy @ (forall a. a) y @ Bool+--+-- When we inline 'x' after eliminating 'lazy', we need to replace+-- occurrences of 'x' with 'y @ bool', not just 'y'. Situations like+-- this can easily arise with higher-rank types; thus, cpe_env must+-- map to CoreExprs, not Ids.++data CorePrepEnv+ = CPE { cpe_dynFlags :: DynFlags+ , cpe_env :: IdEnv CoreExpr -- Clone local Ids+ -- ^ This environment is used for three operations:+ --+ -- 1. To support cloning of local Ids so that they are+ -- all unique (see item (6) of CorePrep overview).+ --+ -- 2. To support beta-reduction of runRW, see+ -- Note [runRW magic] and Note [runRW arg].+ --+ -- 3. To let us inline trivial RHSs of non top-level let-bindings,+ -- see Note [lazyId magic], Note [Inlining in CorePrep]+ -- and Note [CorePrep inlines trivial CoreExpr not Id] (#12076)+ , cpe_mkIntegerId :: Id+ , cpe_integerSDataCon :: Maybe DataCon+ }++lookupMkIntegerName :: DynFlags -> HscEnv -> IO Id+lookupMkIntegerName dflags hsc_env+ = guardIntegerUse dflags $ liftM tyThingId $+ lookupGlobal hsc_env mkIntegerName++lookupIntegerSDataConName :: DynFlags -> HscEnv -> IO (Maybe DataCon)+lookupIntegerSDataConName dflags hsc_env = case cIntegerLibraryType of+ IntegerGMP -> guardIntegerUse dflags $ liftM (Just . tyThingDataCon) $+ lookupGlobal hsc_env integerSDataConName+ IntegerSimple -> return Nothing++-- | Helper for 'lookupMkIntegerName' and 'lookupIntegerSDataConName'+guardIntegerUse :: DynFlags -> IO a -> IO a+guardIntegerUse dflags act+ | thisPackage dflags == primUnitId+ = return $ panic "Can't use Integer in ghc-prim"+ | thisPackage dflags == integerUnitId+ = return $ panic "Can't use Integer in integer-*"+ | otherwise = act++mkInitialCorePrepEnv :: DynFlags -> HscEnv -> IO CorePrepEnv+mkInitialCorePrepEnv dflags hsc_env+ = do mkIntegerId <- lookupMkIntegerName dflags hsc_env+ integerSDataCon <- lookupIntegerSDataConName dflags hsc_env+ return $ CPE {+ cpe_dynFlags = dflags,+ cpe_env = emptyVarEnv,+ cpe_mkIntegerId = mkIntegerId,+ cpe_integerSDataCon = integerSDataCon+ }++extendCorePrepEnv :: CorePrepEnv -> Id -> Id -> CorePrepEnv+extendCorePrepEnv cpe id id'+ = cpe { cpe_env = extendVarEnv (cpe_env cpe) id (Var id') }++extendCorePrepEnvExpr :: CorePrepEnv -> Id -> CoreExpr -> CorePrepEnv+extendCorePrepEnvExpr cpe id expr+ = cpe { cpe_env = extendVarEnv (cpe_env cpe) id expr }++extendCorePrepEnvList :: CorePrepEnv -> [(Id,Id)] -> CorePrepEnv+extendCorePrepEnvList cpe prs+ = cpe { cpe_env = extendVarEnvList (cpe_env cpe)+ (map (\(id, id') -> (id, Var id')) prs) }++lookupCorePrepEnv :: CorePrepEnv -> Id -> CoreExpr+lookupCorePrepEnv cpe id+ = case lookupVarEnv (cpe_env cpe) id of+ Nothing -> Var id+ Just exp -> exp++getMkIntegerId :: CorePrepEnv -> Id+getMkIntegerId = cpe_mkIntegerId++------------------------------------------------------------------------------+-- Cloning binders+-- ---------------------------------------------------------------------------++cpCloneBndrs :: CorePrepEnv -> [Var] -> UniqSM (CorePrepEnv, [Var])+cpCloneBndrs env bs = mapAccumLM cpCloneBndr env bs++cpCloneBndr :: CorePrepEnv -> Var -> UniqSM (CorePrepEnv, Var)+cpCloneBndr env bndr+ | isLocalId bndr, not (isCoVar bndr)+ = do bndr' <- setVarUnique bndr <$> getUniqueM++ -- We are going to OccAnal soon, so drop (now-useless) rules/unfoldings+ -- so that we can drop more stuff as dead code.+ -- See also Note [Dead code in CorePrep]+ let bndr'' = bndr' `setIdUnfolding` noUnfolding+ `setIdSpecialisation` emptyRuleInfo+ return (extendCorePrepEnv env bndr bndr'', bndr'')++ | otherwise -- Top level things, which we don't want+ -- to clone, have become GlobalIds by now+ -- And we don't clone tyvars, or coercion variables+ = return (env, bndr)+++------------------------------------------------------------------------------+-- Cloning ccall Ids; each must have a unique name,+-- to give the code generator a handle to hang it on+-- ---------------------------------------------------------------------------++fiddleCCall :: Id -> UniqSM Id+fiddleCCall id+ | isFCallId id = (id `setVarUnique`) <$> getUniqueM+ | otherwise = return id++------------------------------------------------------------------------------+-- Generating new binders+-- ---------------------------------------------------------------------------++newVar :: Type -> UniqSM Id+newVar ty+ = seqType ty `seq` do+ uniq <- getUniqueM+ return (mkSysLocalOrCoVar (fsLit "sat") uniq ty)+++------------------------------------------------------------------------------+-- Floating ticks+-- ---------------------------------------------------------------------------+--+-- Note [Floating Ticks in CorePrep]+--+-- It might seem counter-intuitive to float ticks by default, given+-- that we don't actually want to move them if we can help it. On the+-- other hand, nothing gets very far in CorePrep anyway, and we want+-- to preserve the order of let bindings and tick annotations in+-- relation to each other. For example, if we just wrapped let floats+-- when they pass through ticks, we might end up performing the+-- following transformation:+--+-- src<...> let foo = bar in baz+-- ==> let foo = src<...> bar in src<...> baz+--+-- Because the let-binding would float through the tick, and then+-- immediately materialize, achieving nothing but decreasing tick+-- accuracy. The only special case is the following scenario:+--+-- let foo = src<...> (let a = b in bar) in baz+-- ==> let foo = src<...> bar; a = src<...> b in baz+--+-- Here we would not want the source tick to end up covering "baz" and+-- therefore refrain from pushing ticks outside. Instead, we copy them+-- into the floating binds (here "a") in cpePair. Note that where "b"+-- or "bar" are (value) lambdas we have to push the annotations+-- further inside in order to uphold our rules.+--+-- All of this is implemented below in @wrapTicks@.++-- | Like wrapFloats, but only wraps tick floats+wrapTicks :: Floats -> CoreExpr -> (Floats, CoreExpr)+wrapTicks (Floats flag floats0) expr =+ (Floats flag (toOL $ reverse floats1), foldr mkTick expr (reverse ticks1))+ where (floats1, ticks1) = foldlOL go ([], []) $ floats0+ -- Deeply nested constructors will produce long lists of+ -- redundant source note floats here. We need to eliminate+ -- those early, as relying on mkTick to spot it after the fact+ -- can yield O(n^3) complexity [#11095]+ go (floats, ticks) (FloatTick t)+ = ASSERT(tickishPlace t == PlaceNonLam)+ (floats, if any (flip tickishContains t) ticks+ then ticks else t:ticks)+ go (floats, ticks) f+ = (foldr wrap f (reverse ticks):floats, ticks)++ wrap t (FloatLet bind) = FloatLet (wrapBind t bind)+ wrap t (FloatCase b r ok) = FloatCase b (mkTick t r) ok+ wrap _ other = pprPanic "wrapTicks: unexpected float!"+ (ppr other)+ wrapBind t (NonRec binder rhs) = NonRec binder (mkTick t rhs)+ wrapBind t (Rec pairs) = Rec (mapSnd (mkTick t) pairs)
+ coreSyn/CoreSeq.hs view
@@ -0,0 +1,111 @@+-- |+-- Various utilities for forcing Core structures+--+-- It can often be useful to force various parts of the AST. This module+-- provides a number of @seq@-like functions to accomplish this.++module CoreSeq (+ -- * Utilities for forcing Core structures+ seqExpr, seqExprs, seqUnfolding, seqRules,+ megaSeqIdInfo, seqRuleInfo, seqBinds,+ ) where++import CoreSyn+import IdInfo+import Demand( seqDemand, seqStrictSig )+import BasicTypes( seqOccInfo )+import VarSet( seqDVarSet )+import Var( varType, tyVarKind )+import Type( seqType, isTyVar )+import Coercion( seqCo )+import Id( Id, idInfo )++-- | Evaluate all the fields of the 'IdInfo' that are generally demanded by the+-- compiler+megaSeqIdInfo :: IdInfo -> ()+megaSeqIdInfo info+ = seqRuleInfo (ruleInfo info) `seq`++-- Omitting this improves runtimes a little, presumably because+-- some unfoldings are not calculated at all+-- seqUnfolding (unfoldingInfo info) `seq`++ seqDemand (demandInfo info) `seq`+ seqStrictSig (strictnessInfo info) `seq`+ seqCaf (cafInfo info) `seq`+ seqOneShot (oneShotInfo info) `seq`+ seqOccInfo (occInfo info)++seqOneShot :: OneShotInfo -> ()+seqOneShot l = l `seq` ()++seqRuleInfo :: RuleInfo -> ()+seqRuleInfo (RuleInfo rules fvs) = seqRules rules `seq` seqDVarSet fvs++seqCaf :: CafInfo -> ()+seqCaf c = c `seq` ()++seqRules :: [CoreRule] -> ()+seqRules [] = ()+seqRules (Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs } : rules)+ = seqBndrs bndrs `seq` seqExprs (rhs:args) `seq` seqRules rules+seqRules (BuiltinRule {} : rules) = seqRules rules++seqExpr :: CoreExpr -> ()+seqExpr (Var v) = v `seq` ()+seqExpr (Lit lit) = lit `seq` ()+seqExpr (App f a) = seqExpr f `seq` seqExpr a+seqExpr (Lam b e) = seqBndr b `seq` seqExpr e+seqExpr (Let b e) = seqBind b `seq` seqExpr e+seqExpr (Case e b t as) = seqExpr e `seq` seqBndr b `seq` seqType t `seq` seqAlts as+seqExpr (Cast e co) = seqExpr e `seq` seqCo co+seqExpr (Tick n e) = seqTickish n `seq` seqExpr e+seqExpr (Type t) = seqType t+seqExpr (Coercion co) = seqCo co++seqExprs :: [CoreExpr] -> ()+seqExprs [] = ()+seqExprs (e:es) = seqExpr e `seq` seqExprs es++seqTickish :: Tickish Id -> ()+seqTickish ProfNote{ profNoteCC = cc } = cc `seq` ()+seqTickish HpcTick{} = ()+seqTickish Breakpoint{ breakpointFVs = ids } = seqBndrs ids+seqTickish SourceNote{} = ()++seqBndr :: CoreBndr -> ()+seqBndr b | isTyVar b = seqType (tyVarKind b)+ | otherwise = seqType (varType b) `seq`+ megaSeqIdInfo (idInfo b)++seqBndrs :: [CoreBndr] -> ()+seqBndrs [] = ()+seqBndrs (b:bs) = seqBndr b `seq` seqBndrs bs++seqBinds :: [Bind CoreBndr] -> ()+seqBinds bs = foldr (seq . seqBind) () bs++seqBind :: Bind CoreBndr -> ()+seqBind (NonRec b e) = seqBndr b `seq` seqExpr e+seqBind (Rec prs) = seqPairs prs++seqPairs :: [(CoreBndr, CoreExpr)] -> ()+seqPairs [] = ()+seqPairs ((b,e):prs) = seqBndr b `seq` seqExpr e `seq` seqPairs prs++seqAlts :: [CoreAlt] -> ()+seqAlts [] = ()+seqAlts ((c,bs,e):alts) = c `seq` seqBndrs bs `seq` seqExpr e `seq` seqAlts alts++seqUnfolding :: Unfolding -> ()+seqUnfolding (CoreUnfolding { uf_tmpl = e, uf_is_top = top,+ uf_is_value = b1, uf_is_work_free = b2,+ uf_expandable = b3, uf_is_conlike = b4,+ uf_guidance = g})+ = seqExpr e `seq` top `seq` b1 `seq` b2 `seq` b3 `seq` b4 `seq` seqGuidance g++seqUnfolding _ = ()++seqGuidance :: UnfoldingGuidance -> ()+seqGuidance (UnfIfGoodArgs ns n b) = n `seq` sum ns `seq` b `seq` ()+seqGuidance _ = ()
+ coreSyn/CoreStats.hs view
@@ -0,0 +1,141 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-2015+-}++-- | Functions to computing the statistics reflective of the "size"+-- of a Core expression+module CoreStats (+ -- * Expression and bindings size+ coreBindsSize, exprSize,+ CoreStats(..), coreBindsStats, exprStats,+ ) where++import BasicTypes+import CoreSyn+import Outputable+import Coercion+import Var+import Type (Type, typeSize, seqType)+import Id (idType, isJoinId)+import CoreSeq (megaSeqIdInfo)++data CoreStats = CS { cs_tm :: Int -- Terms+ , cs_ty :: Int -- Types+ , cs_co :: Int -- Coercions+ , cs_vb :: Int -- Local value bindings+ , cs_jb :: Int } -- Local join bindings+++instance Outputable CoreStats where+ ppr (CS { cs_tm = i1, cs_ty = i2, cs_co = i3, cs_vb = i4, cs_jb = i5 })+ = braces (sep [text "terms:" <+> intWithCommas i1 <> comma,+ text "types:" <+> intWithCommas i2 <> comma,+ text "coercions:" <+> intWithCommas i3 <> comma,+ text "joins:" <+> intWithCommas i5 <> char '/' <>+ intWithCommas (i4 + i5) ])++plusCS :: CoreStats -> CoreStats -> CoreStats+plusCS (CS { cs_tm = p1, cs_ty = q1, cs_co = r1, cs_vb = v1, cs_jb = j1 })+ (CS { cs_tm = p2, cs_ty = q2, cs_co = r2, cs_vb = v2, cs_jb = j2 })+ = CS { cs_tm = p1+p2, cs_ty = q1+q2, cs_co = r1+r2, cs_vb = v1+v2+ , cs_jb = j1+j2 }++zeroCS, oneTM :: CoreStats+zeroCS = CS { cs_tm = 0, cs_ty = 0, cs_co = 0, cs_vb = 0, cs_jb = 0 }+oneTM = zeroCS { cs_tm = 1 }++sumCS :: (a -> CoreStats) -> [a] -> CoreStats+sumCS f = foldr (plusCS . f) zeroCS++coreBindsStats :: [CoreBind] -> CoreStats+coreBindsStats = sumCS (bindStats TopLevel)++bindStats :: TopLevelFlag -> CoreBind -> CoreStats+bindStats top_lvl (NonRec v r) = bindingStats top_lvl v r+bindStats top_lvl (Rec prs) = sumCS (\(v,r) -> bindingStats top_lvl v r) prs++bindingStats :: TopLevelFlag -> Var -> CoreExpr -> CoreStats+bindingStats top_lvl v r = letBndrStats top_lvl v `plusCS` exprStats r++bndrStats :: Var -> CoreStats+bndrStats v = oneTM `plusCS` tyStats (varType v)++letBndrStats :: TopLevelFlag -> Var -> CoreStats+letBndrStats top_lvl v+ | isTyVar v || isTopLevel top_lvl = bndrStats v+ | isJoinId v = oneTM { cs_jb = 1 } `plusCS` ty_stats+ | otherwise = oneTM { cs_vb = 1 } `plusCS` ty_stats+ where+ ty_stats = tyStats (varType v)++exprStats :: CoreExpr -> CoreStats+exprStats (Var {}) = oneTM+exprStats (Lit {}) = oneTM+exprStats (Type t) = tyStats t+exprStats (Coercion c) = coStats c+exprStats (App f a) = exprStats f `plusCS` exprStats a+exprStats (Lam b e) = bndrStats b `plusCS` exprStats e+exprStats (Let b e) = bindStats NotTopLevel b `plusCS` exprStats e+exprStats (Case e b _ as) = exprStats e `plusCS` bndrStats b+ `plusCS` sumCS altStats as+exprStats (Cast e co) = coStats co `plusCS` exprStats e+exprStats (Tick _ e) = exprStats e++altStats :: CoreAlt -> CoreStats+altStats (_, bs, r) = altBndrStats bs `plusCS` exprStats r++altBndrStats :: [Var] -> CoreStats+-- Charge one for the alternative, not for each binder+altBndrStats vs = oneTM `plusCS` sumCS (tyStats . varType) vs++tyStats :: Type -> CoreStats+tyStats ty = zeroCS { cs_ty = typeSize ty }++coStats :: Coercion -> CoreStats+coStats co = zeroCS { cs_co = coercionSize co }++coreBindsSize :: [CoreBind] -> Int+-- We use coreBindStats for user printout+-- but this one is a quick and dirty basis for+-- the simplifier's tick limit+coreBindsSize bs = foldr ((+) . bindSize) 0 bs++exprSize :: CoreExpr -> Int+-- ^ A measure of the size of the expressions, strictly greater than 0+-- It also forces the expression pretty drastically as a side effect+-- Counts *leaves*, not internal nodes. Types and coercions are not counted.+exprSize (Var v) = v `seq` 1+exprSize (Lit lit) = lit `seq` 1+exprSize (App f a) = exprSize f + exprSize a+exprSize (Lam b e) = bndrSize b + exprSize e+exprSize (Let b e) = bindSize b + exprSize e+exprSize (Case e b t as) = seqType t `seq`+ exprSize e + bndrSize b + 1 + foldr ((+) . altSize) 0 as+exprSize (Cast e co) = (seqCo co `seq` 1) + exprSize e+exprSize (Tick n e) = tickSize n + exprSize e+exprSize (Type t) = seqType t `seq` 1+exprSize (Coercion co) = seqCo co `seq` 1++tickSize :: Tickish Id -> Int+tickSize (ProfNote cc _ _) = cc `seq` 1+tickSize _ = 1 -- the rest are strict++bndrSize :: Var -> Int+bndrSize b | isTyVar b = seqType (tyVarKind b) `seq` 1+ | otherwise = seqType (idType b) `seq`+ megaSeqIdInfo (idInfo b) `seq`+ 1++bndrsSize :: [Var] -> Int+bndrsSize = sum . map bndrSize++bindSize :: CoreBind -> Int+bindSize (NonRec b e) = bndrSize b + exprSize e+bindSize (Rec prs) = foldr ((+) . pairSize) 0 prs++pairSize :: (Var, CoreExpr) -> Int+pairSize (b,e) = bndrSize b + exprSize e++altSize :: CoreAlt -> Int+altSize (c,bs,e) = c `seq` bndrsSize bs + exprSize e
+ coreSyn/CoreSubst.hs view
@@ -0,0 +1,762 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Utility functions on @Core@ syntax+-}++{-# LANGUAGE CPP #-}+module CoreSubst (+ -- * Main data types+ Subst(..), -- Implementation exported for supercompiler's Renaming.hs only+ TvSubstEnv, IdSubstEnv, InScopeSet,++ -- ** Substituting into expressions and related types+ deShadowBinds, substSpec, substRulesForImportedIds,+ substTy, substCo, substExpr, substExprSC, substBind, substBindSC,+ substUnfolding, substUnfoldingSC,+ lookupIdSubst, lookupTCvSubst, substIdOcc,+ substTickish, substDVarSet, substIdInfo,++ -- ** Operations on substitutions+ emptySubst, mkEmptySubst, mkSubst, mkOpenSubst, substInScope, isEmptySubst,+ extendIdSubst, extendIdSubstList, extendTCvSubst, extendTvSubstList,+ extendSubst, extendSubstList, extendSubstWithVar, zapSubstEnv,+ addInScopeSet, extendInScope, extendInScopeList, extendInScopeIds,+ isInScope, setInScope, getTCvSubst, extendTvSubst, extendCvSubst,+ delBndr, delBndrs,++ -- ** Substituting and cloning binders+ substBndr, substBndrs, substRecBndrs, substTyVarBndr, substCoVarBndr,+ cloneBndr, cloneBndrs, cloneIdBndr, cloneIdBndrs, cloneRecIdBndrs,++ ) where++#include "HsVersions.h"+++import CoreSyn+import CoreFVs+import CoreSeq+import CoreUtils+import qualified Type+import qualified Coercion++ -- We are defining local versions+import Type hiding ( substTy, extendTvSubst, extendCvSubst, extendTvSubstList+ , isInScope, substTyVarBndr, cloneTyVarBndr )+import Coercion hiding ( substCo, substCoVarBndr )++import PrelNames+import VarSet+import VarEnv+import Id+import Name ( Name )+import Var+import IdInfo+import UniqSupply+import Maybes+import Util+import Outputable+import PprCore () -- Instances+import Data.List++++{-+************************************************************************+* *+\subsection{Substitutions}+* *+************************************************************************+-}++-- | A substitution environment, containing 'Id', 'TyVar', and 'CoVar'+-- substitutions.+--+-- Some invariants apply to how you use the substitution:+--+-- 1. #in_scope_invariant# The in-scope set contains at least those 'Id's and 'TyVar's that will be in scope /after/+-- applying the substitution to a term. Precisely, the in-scope set must be a superset of the free vars of the+-- substitution range that might possibly clash with locally-bound variables in the thing being substituted in.+--+-- 2. #apply_once# You may apply the substitution only /once/+--+-- There are various ways of setting up the in-scope set such that the first of these invariants hold:+--+-- * Arrange that the in-scope set really is all the things in scope+--+-- * Arrange that it's the free vars of the range of the substitution+--+-- * Make it empty, if you know that all the free vars of the substitution are fresh, and hence can't possibly clash+data Subst+ = Subst InScopeSet -- Variables in in scope (both Ids and TyVars) /after/+ -- applying the substitution+ IdSubstEnv -- Substitution from NcIds to CoreExprs+ TvSubstEnv -- Substitution from TyVars to Types+ CvSubstEnv -- Substitution from CoVars to Coercions++ -- INVARIANT 1: See #in_scope_invariant#+ -- This is what lets us deal with name capture properly+ -- It's a hard invariant to check...+ --+ -- INVARIANT 2: The substitution is apply-once; see Note [Apply once] with+ -- Types.TvSubstEnv+ --+ -- INVARIANT 3: See Note [Extending the Subst]++{-+Note [Extending the Subst]+~~~~~~~~~~~~~~~~~~~~~~~~~~+For a core Subst, which binds Ids as well, we make a different choice for Ids+than we do for TyVars.++For TyVars, see Note [Extending the TCvSubst] with Type.TvSubstEnv++For Ids, we have a different invariant+ The IdSubstEnv is extended *only* when the Unique on an Id changes+ Otherwise, we just extend the InScopeSet++In consequence:++* If all subst envs are empty, substExpr would be a+ no-op, so substExprSC ("short cut") does nothing.++ However, substExpr still goes ahead and substitutes. Reason: we may+ want to replace existing Ids with new ones from the in-scope set, to+ avoid space leaks.++* In substIdBndr, we extend the IdSubstEnv only when the unique changes++* If the CvSubstEnv, TvSubstEnv and IdSubstEnv are all empty,+ substExpr does nothing (Note that the above rule for substIdBndr+ maintains this property. If the incoming envts are both empty, then+ substituting the type and IdInfo can't change anything.)++* In lookupIdSubst, we *must* look up the Id in the in-scope set, because+ it may contain non-trivial changes. Example:+ (/\a. \x:a. ...x...) Int+ We extend the TvSubstEnv with [a |-> Int]; but x's unique does not change+ so we only extend the in-scope set. Then we must look up in the in-scope+ set when we find the occurrence of x.++* The requirement to look up the Id in the in-scope set means that we+ must NOT take no-op short cut when the IdSubst is empty.+ We must still look up every Id in the in-scope set.++* (However, we don't need to do so for expressions found in the IdSubst+ itself, whose range is assumed to be correct wrt the in-scope set.)++Why do we make a different choice for the IdSubstEnv than the+TvSubstEnv and CvSubstEnv?++* For Ids, we change the IdInfo all the time (e.g. deleting the+ unfolding), and adding it back later, so using the TyVar convention+ would entail extending the substitution almost all the time++* The simplifier wants to look up in the in-scope set anyway, in case it+ can see a better unfolding from an enclosing case expression++* For TyVars, only coercion variables can possibly change, and they are+ easy to spot+-}++-- | An environment for substituting for 'Id's+type IdSubstEnv = IdEnv CoreExpr -- Domain is NcIds, i.e. not coercions++----------------------------+isEmptySubst :: Subst -> Bool+isEmptySubst (Subst _ id_env tv_env cv_env)+ = isEmptyVarEnv id_env && isEmptyVarEnv tv_env && isEmptyVarEnv cv_env++emptySubst :: Subst+emptySubst = Subst emptyInScopeSet emptyVarEnv emptyVarEnv emptyVarEnv++mkEmptySubst :: InScopeSet -> Subst+mkEmptySubst in_scope = Subst in_scope emptyVarEnv emptyVarEnv emptyVarEnv++mkSubst :: InScopeSet -> TvSubstEnv -> CvSubstEnv -> IdSubstEnv -> Subst+mkSubst in_scope tvs cvs ids = Subst in_scope ids tvs cvs++-- | Find the in-scope set: see "CoreSubst#in_scope_invariant"+substInScope :: Subst -> InScopeSet+substInScope (Subst in_scope _ _ _) = in_scope++-- | Remove all substitutions for 'Id's and 'Var's that might have been built up+-- while preserving the in-scope set+zapSubstEnv :: Subst -> Subst+zapSubstEnv (Subst in_scope _ _ _) = Subst in_scope emptyVarEnv emptyVarEnv emptyVarEnv++-- | Add a substitution for an 'Id' to the 'Subst': you must ensure that the in-scope set is+-- such that the "CoreSubst#in_scope_invariant" is true after extending the substitution like this+extendIdSubst :: Subst -> Id -> CoreExpr -> Subst+-- ToDo: add an ASSERT that fvs(subst-result) is already in the in-scope set+extendIdSubst (Subst in_scope ids tvs cvs) v r+ = ASSERT2( isNonCoVarId v, ppr v $$ ppr r )+ Subst in_scope (extendVarEnv ids v r) tvs cvs++-- | Adds multiple 'Id' substitutions to the 'Subst': see also 'extendIdSubst'+extendIdSubstList :: Subst -> [(Id, CoreExpr)] -> Subst+extendIdSubstList (Subst in_scope ids tvs cvs) prs+ = ASSERT( all (isNonCoVarId . fst) prs )+ Subst in_scope (extendVarEnvList ids prs) tvs cvs++-- | Add a substitution for a 'TyVar' to the 'Subst'+-- The 'TyVar' *must* be a real TyVar, and not a CoVar+-- You must ensure that the in-scope set is such that+-- the "CoreSubst#in_scope_invariant" is true after extending+-- the substitution like this.+extendTvSubst :: Subst -> TyVar -> Type -> Subst+extendTvSubst (Subst in_scope ids tvs cvs) tv ty+ = ASSERT( isTyVar tv )+ Subst in_scope ids (extendVarEnv tvs tv ty) cvs++-- | Adds multiple 'TyVar' substitutions to the 'Subst': see also 'extendTvSubst'+extendTvSubstList :: Subst -> [(TyVar,Type)] -> Subst+extendTvSubstList subst vrs+ = foldl' extend subst vrs+ where+ extend subst (v, r) = extendTvSubst subst v r++-- | Add a substitution from a 'CoVar' to a 'Coercion' to the 'Subst': you must ensure that the in-scope set is+-- such that the "CoreSubst#in_scope_invariant" is true after extending the substitution like this+extendCvSubst :: Subst -> CoVar -> Coercion -> Subst+extendCvSubst (Subst in_scope ids tvs cvs) v r+ = ASSERT( isCoVar v )+ Subst in_scope ids tvs (extendVarEnv cvs v r)++-- | Add a substitution appropriate to the thing being substituted+-- (whether an expression, type, or coercion). See also+-- 'extendIdSubst', 'extendTvSubst', 'extendCvSubst'+extendSubst :: Subst -> Var -> CoreArg -> Subst+extendSubst subst var arg+ = case arg of+ Type ty -> ASSERT( isTyVar var ) extendTvSubst subst var ty+ Coercion co -> ASSERT( isCoVar var ) extendCvSubst subst var co+ _ -> ASSERT( isId var ) extendIdSubst subst var arg++extendSubstWithVar :: Subst -> Var -> Var -> Subst+extendSubstWithVar subst v1 v2+ | isTyVar v1 = ASSERT( isTyVar v2 ) extendTvSubst subst v1 (mkTyVarTy v2)+ | isCoVar v1 = ASSERT( isCoVar v2 ) extendCvSubst subst v1 (mkCoVarCo v2)+ | otherwise = ASSERT( isId v2 ) extendIdSubst subst v1 (Var v2)++-- | Add a substitution as appropriate to each of the terms being+-- substituted (whether expressions, types, or coercions). See also+-- 'extendSubst'.+extendSubstList :: Subst -> [(Var,CoreArg)] -> Subst+extendSubstList subst [] = subst+extendSubstList subst ((var,rhs):prs) = extendSubstList (extendSubst subst var rhs) prs++-- | Find the substitution for an 'Id' in the 'Subst'+lookupIdSubst :: SDoc -> Subst -> Id -> CoreExpr+lookupIdSubst doc (Subst in_scope ids _ _) v+ | not (isLocalId v) = Var v+ | Just e <- lookupVarEnv ids v = e+ | Just v' <- lookupInScope in_scope v = Var v'+ -- Vital! See Note [Extending the Subst]+ | otherwise = WARN( True, text "CoreSubst.lookupIdSubst" <+> doc <+> ppr v+ $$ ppr in_scope)+ Var v++-- | Find the substitution for a 'TyVar' in the 'Subst'+lookupTCvSubst :: Subst -> TyVar -> Type+lookupTCvSubst (Subst _ _ tvs cvs) v+ | isTyVar v+ = lookupVarEnv tvs v `orElse` Type.mkTyVarTy v+ | otherwise+ = mkCoercionTy $ lookupVarEnv cvs v `orElse` mkCoVarCo v++delBndr :: Subst -> Var -> Subst+delBndr (Subst in_scope ids tvs cvs) v+ | isCoVar v = Subst in_scope ids tvs (delVarEnv cvs v)+ | isTyVar v = Subst in_scope ids (delVarEnv tvs v) cvs+ | otherwise = Subst in_scope (delVarEnv ids v) tvs cvs++delBndrs :: Subst -> [Var] -> Subst+delBndrs (Subst in_scope ids tvs cvs) vs+ = Subst in_scope (delVarEnvList ids vs) (delVarEnvList tvs vs) (delVarEnvList cvs vs)+ -- Easiest thing is just delete all from all!++-- | Simultaneously substitute for a bunch of variables+-- No left-right shadowing+-- ie the substitution for (\x \y. e) a1 a2+-- so neither x nor y scope over a1 a2+mkOpenSubst :: InScopeSet -> [(Var,CoreArg)] -> Subst+mkOpenSubst in_scope pairs = Subst in_scope+ (mkVarEnv [(id,e) | (id, e) <- pairs, isId id])+ (mkVarEnv [(tv,ty) | (tv, Type ty) <- pairs])+ (mkVarEnv [(v,co) | (v, Coercion co) <- pairs])++------------------------------+isInScope :: Var -> Subst -> Bool+isInScope v (Subst in_scope _ _ _) = v `elemInScopeSet` in_scope++-- | Add the 'Var' to the in-scope set, but do not remove+-- any existing substitutions for it+addInScopeSet :: Subst -> VarSet -> Subst+addInScopeSet (Subst in_scope ids tvs cvs) vs+ = Subst (in_scope `extendInScopeSetSet` vs) ids tvs cvs++-- | Add the 'Var' to the in-scope set: as a side effect,+-- and remove any existing substitutions for it+extendInScope :: Subst -> Var -> Subst+extendInScope (Subst in_scope ids tvs cvs) v+ = Subst (in_scope `extendInScopeSet` v)+ (ids `delVarEnv` v) (tvs `delVarEnv` v) (cvs `delVarEnv` v)++-- | Add the 'Var's to the in-scope set: see also 'extendInScope'+extendInScopeList :: Subst -> [Var] -> Subst+extendInScopeList (Subst in_scope ids tvs cvs) vs+ = Subst (in_scope `extendInScopeSetList` vs)+ (ids `delVarEnvList` vs) (tvs `delVarEnvList` vs) (cvs `delVarEnvList` vs)++-- | Optimized version of 'extendInScopeList' that can be used if you are certain+-- all the things being added are 'Id's and hence none are 'TyVar's or 'CoVar's+extendInScopeIds :: Subst -> [Id] -> Subst+extendInScopeIds (Subst in_scope ids tvs cvs) vs+ = Subst (in_scope `extendInScopeSetList` vs)+ (ids `delVarEnvList` vs) tvs cvs++setInScope :: Subst -> InScopeSet -> Subst+setInScope (Subst _ ids tvs cvs) in_scope = Subst in_scope ids tvs cvs++-- Pretty printing, for debugging only++instance Outputable Subst where+ ppr (Subst in_scope ids tvs cvs)+ = text "<InScope =" <+> in_scope_doc+ $$ text " IdSubst =" <+> ppr ids+ $$ text " TvSubst =" <+> ppr tvs+ $$ text " CvSubst =" <+> ppr cvs+ <> char '>'+ where+ in_scope_doc = pprVarSet (getInScopeVars in_scope) (braces . fsep . map ppr)++{-+************************************************************************+* *+ Substituting expressions+* *+************************************************************************+-}++-- | Apply a substitution to an entire 'CoreExpr'. Remember, you may only+-- apply the substitution /once/: see "CoreSubst#apply_once"+--+-- Do *not* attempt to short-cut in the case of an empty substitution!+-- See Note [Extending the Subst]+substExprSC :: SDoc -> Subst -> CoreExpr -> CoreExpr+substExprSC doc subst orig_expr+ | isEmptySubst subst = orig_expr+ | otherwise = -- pprTrace "enter subst-expr" (doc $$ ppr orig_expr) $+ subst_expr doc subst orig_expr++substExpr :: SDoc -> Subst -> CoreExpr -> CoreExpr+substExpr doc subst orig_expr = subst_expr doc subst orig_expr++subst_expr :: SDoc -> Subst -> CoreExpr -> CoreExpr+subst_expr doc subst expr+ = go expr+ where+ go (Var v) = lookupIdSubst (doc $$ text "subst_expr") subst v+ go (Type ty) = Type (substTy subst ty)+ go (Coercion co) = Coercion (substCo subst co)+ go (Lit lit) = Lit lit+ go (App fun arg) = App (go fun) (go arg)+ go (Tick tickish e) = mkTick (substTickish subst tickish) (go e)+ go (Cast e co) = Cast (go e) (substCo subst co)+ -- Do not optimise even identity coercions+ -- Reason: substitution applies to the LHS of RULES, and+ -- if you "optimise" an identity coercion, you may+ -- lose a binder. We optimise the LHS of rules at+ -- construction time++ go (Lam bndr body) = Lam bndr' (subst_expr doc subst' body)+ where+ (subst', bndr') = substBndr subst bndr++ go (Let bind body) = Let bind' (subst_expr doc subst' body)+ where+ (subst', bind') = substBind subst bind++ go (Case scrut bndr ty alts) = Case (go scrut) bndr' (substTy subst ty) (map (go_alt subst') alts)+ where+ (subst', bndr') = substBndr subst bndr++ go_alt subst (con, bndrs, rhs) = (con, bndrs', subst_expr doc subst' rhs)+ where+ (subst', bndrs') = substBndrs subst bndrs++-- | Apply a substitution to an entire 'CoreBind', additionally returning an updated 'Subst'+-- that should be used by subsequent substitutions.+substBind, substBindSC :: Subst -> CoreBind -> (Subst, CoreBind)++substBindSC subst bind -- Short-cut if the substitution is empty+ | not (isEmptySubst subst)+ = substBind subst bind+ | otherwise+ = case bind of+ NonRec bndr rhs -> (subst', NonRec bndr' rhs)+ where+ (subst', bndr') = substBndr subst bndr+ Rec pairs -> (subst', Rec (bndrs' `zip` rhss'))+ where+ (bndrs, rhss) = unzip pairs+ (subst', bndrs') = substRecBndrs subst bndrs+ rhss' | isEmptySubst subst'+ = rhss+ | otherwise+ = map (subst_expr (text "substBindSC") subst') rhss++substBind subst (NonRec bndr rhs)+ = (subst', NonRec bndr' (subst_expr (text "substBind") subst rhs))+ where+ (subst', bndr') = substBndr subst bndr++substBind subst (Rec pairs)+ = (subst', Rec (bndrs' `zip` rhss'))+ where+ (bndrs, rhss) = unzip pairs+ (subst', bndrs') = substRecBndrs subst bndrs+ rhss' = map (subst_expr (text "substBind") subst') rhss++-- | De-shadowing the program is sometimes a useful pre-pass. It can be done simply+-- by running over the bindings with an empty substitution, because substitution+-- returns a result that has no-shadowing guaranteed.+--+-- (Actually, within a single /type/ there might still be shadowing, because+-- 'substTy' is a no-op for the empty substitution, but that's probably OK.)+--+-- [Aug 09] This function is not used in GHC at the moment, but seems so+-- short and simple that I'm going to leave it here+deShadowBinds :: CoreProgram -> CoreProgram+deShadowBinds binds = snd (mapAccumL substBind emptySubst binds)++{-+************************************************************************+* *+ Substituting binders+* *+************************************************************************++Remember that substBndr and friends are used when doing expression+substitution only. Their only business is substitution, so they+preserve all IdInfo (suitably substituted). For example, we *want* to+preserve occ info in rules.+-}++-- | Substitutes a 'Var' for another one according to the 'Subst' given, returning+-- the result and an updated 'Subst' that should be used by subsequent substitutions.+-- 'IdInfo' is preserved by this process, although it is substituted into appropriately.+substBndr :: Subst -> Var -> (Subst, Var)+substBndr subst bndr+ | isTyVar bndr = substTyVarBndr subst bndr+ | isCoVar bndr = substCoVarBndr subst bndr+ | otherwise = substIdBndr (text "var-bndr") subst subst bndr++-- | Applies 'substBndr' to a number of 'Var's, accumulating a new 'Subst' left-to-right+substBndrs :: Subst -> [Var] -> (Subst, [Var])+substBndrs subst bndrs = mapAccumL substBndr subst bndrs++-- | Substitute in a mutually recursive group of 'Id's+substRecBndrs :: Subst -> [Id] -> (Subst, [Id])+substRecBndrs subst bndrs+ = (new_subst, new_bndrs)+ where -- Here's the reason we need to pass rec_subst to subst_id+ (new_subst, new_bndrs) = mapAccumL (substIdBndr (text "rec-bndr") new_subst) subst bndrs++substIdBndr :: SDoc+ -> Subst -- ^ Substitution to use for the IdInfo+ -> Subst -> Id -- ^ Substitution and Id to transform+ -> (Subst, Id) -- ^ Transformed pair+ -- NB: unfolding may be zapped++substIdBndr _doc rec_subst subst@(Subst in_scope env tvs cvs) old_id+ = -- pprTrace "substIdBndr" (doc $$ ppr old_id $$ ppr in_scope) $+ (Subst (in_scope `extendInScopeSet` new_id) new_env tvs cvs, new_id)+ where+ id1 = uniqAway in_scope old_id -- id1 is cloned if necessary+ id2 | no_type_change = id1+ | otherwise = setIdType id1 (substTy subst old_ty)++ old_ty = idType old_id+ no_type_change = (isEmptyVarEnv tvs && isEmptyVarEnv cvs) ||+ noFreeVarsOfType old_ty++ -- new_id has the right IdInfo+ -- The lazy-set is because we're in a loop here, with+ -- rec_subst, when dealing with a mutually-recursive group+ new_id = maybeModifyIdInfo mb_new_info id2+ mb_new_info = substIdInfo rec_subst id2 (idInfo id2)+ -- NB: unfolding info may be zapped++ -- Extend the substitution if the unique has changed+ -- See the notes with substTyVarBndr for the delVarEnv+ new_env | no_change = delVarEnv env old_id+ | otherwise = extendVarEnv env old_id (Var new_id)++ no_change = id1 == old_id+ -- See Note [Extending the Subst]+ -- it's /not/ necessary to check mb_new_info and no_type_change++{-+Now a variant that unconditionally allocates a new unique.+It also unconditionally zaps the OccInfo.+-}++-- | Very similar to 'substBndr', but it always allocates a new 'Unique' for+-- each variable in its output. It substitutes the IdInfo though.+cloneIdBndr :: Subst -> UniqSupply -> Id -> (Subst, Id)+cloneIdBndr subst us old_id+ = clone_id subst subst (old_id, uniqFromSupply us)++-- | Applies 'cloneIdBndr' to a number of 'Id's, accumulating a final+-- substitution from left to right+cloneIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])+cloneIdBndrs subst us ids+ = mapAccumL (clone_id subst) subst (ids `zip` uniqsFromSupply us)++cloneBndrs :: Subst -> UniqSupply -> [Var] -> (Subst, [Var])+-- Works for all kinds of variables (typically case binders)+-- not just Ids+cloneBndrs subst us vs+ = mapAccumL (\subst (v, u) -> cloneBndr subst u v) subst (vs `zip` uniqsFromSupply us)++cloneBndr :: Subst -> Unique -> Var -> (Subst, Var)+cloneBndr subst uniq v+ | isTyVar v = cloneTyVarBndr subst v uniq+ | otherwise = clone_id subst subst (v,uniq) -- Works for coercion variables too++-- | Clone a mutually recursive group of 'Id's+cloneRecIdBndrs :: Subst -> UniqSupply -> [Id] -> (Subst, [Id])+cloneRecIdBndrs subst us ids+ = (subst', ids')+ where+ (subst', ids') = mapAccumL (clone_id subst') subst+ (ids `zip` uniqsFromSupply us)++-- Just like substIdBndr, except that it always makes a new unique+-- It is given the unique to use+clone_id :: Subst -- Substitution for the IdInfo+ -> Subst -> (Id, Unique) -- Substitution and Id to transform+ -> (Subst, Id) -- Transformed pair++clone_id rec_subst subst@(Subst in_scope idvs tvs cvs) (old_id, uniq)+ = (Subst (in_scope `extendInScopeSet` new_id) new_idvs tvs new_cvs, new_id)+ where+ id1 = setVarUnique old_id uniq+ id2 = substIdType subst id1+ new_id = maybeModifyIdInfo (substIdInfo rec_subst id2 (idInfo old_id)) id2+ (new_idvs, new_cvs) | isCoVar old_id = (idvs, extendVarEnv cvs old_id (mkCoVarCo new_id))+ | otherwise = (extendVarEnv idvs old_id (Var new_id), cvs)++{-+************************************************************************+* *+ Types and Coercions+* *+************************************************************************++For types and coercions we just call the corresponding functions in+Type and Coercion, but we have to repackage the substitution, from a+Subst to a TCvSubst.+-}++substTyVarBndr :: Subst -> TyVar -> (Subst, TyVar)+substTyVarBndr (Subst in_scope id_env tv_env cv_env) tv+ = case Type.substTyVarBndr (TCvSubst in_scope tv_env cv_env) tv of+ (TCvSubst in_scope' tv_env' cv_env', tv')+ -> (Subst in_scope' id_env tv_env' cv_env', tv')++cloneTyVarBndr :: Subst -> TyVar -> Unique -> (Subst, TyVar)+cloneTyVarBndr (Subst in_scope id_env tv_env cv_env) tv uniq+ = case Type.cloneTyVarBndr (TCvSubst in_scope tv_env cv_env) tv uniq of+ (TCvSubst in_scope' tv_env' cv_env', tv')+ -> (Subst in_scope' id_env tv_env' cv_env', tv')++substCoVarBndr :: Subst -> TyVar -> (Subst, TyVar)+substCoVarBndr (Subst in_scope id_env tv_env cv_env) cv+ = case Coercion.substCoVarBndr (TCvSubst in_scope tv_env cv_env) cv of+ (TCvSubst in_scope' tv_env' cv_env', cv')+ -> (Subst in_scope' id_env tv_env' cv_env', cv')++-- | See 'Type.substTy'+substTy :: Subst -> Type -> Type+substTy subst ty = Type.substTyUnchecked (getTCvSubst subst) ty++getTCvSubst :: Subst -> TCvSubst+getTCvSubst (Subst in_scope _ tenv cenv) = TCvSubst in_scope tenv cenv++-- | See 'Coercion.substCo'+substCo :: Subst -> Coercion -> Coercion+substCo subst co = Coercion.substCo (getTCvSubst subst) co++{-+************************************************************************+* *+\section{IdInfo substitution}+* *+************************************************************************+-}++substIdType :: Subst -> Id -> Id+substIdType subst@(Subst _ _ tv_env cv_env) id+ | (isEmptyVarEnv tv_env && isEmptyVarEnv cv_env) || noFreeVarsOfType old_ty = id+ | otherwise = setIdType id (substTy subst old_ty)+ -- The tyCoVarsOfType is cheaper than it looks+ -- because we cache the free tyvars of the type+ -- in a Note in the id's type itself+ where+ old_ty = idType id++------------------+-- | Substitute into some 'IdInfo' with regard to the supplied new 'Id'.+substIdInfo :: Subst -> Id -> IdInfo -> Maybe IdInfo+substIdInfo subst new_id info+ | nothing_to_do = Nothing+ | otherwise = Just (info `setRuleInfo` substSpec subst new_id old_rules+ `setUnfoldingInfo` substUnfolding subst old_unf)+ where+ old_rules = ruleInfo info+ old_unf = unfoldingInfo info+ nothing_to_do = isEmptyRuleInfo old_rules && not (isFragileUnfolding old_unf)++------------------+-- | Substitutes for the 'Id's within an unfolding+substUnfolding, substUnfoldingSC :: Subst -> Unfolding -> Unfolding+ -- Seq'ing on the returned Unfolding is enough to cause+ -- all the substitutions to happen completely++substUnfoldingSC subst unf -- Short-cut version+ | isEmptySubst subst = unf+ | otherwise = substUnfolding subst unf++substUnfolding subst df@(DFunUnfolding { df_bndrs = bndrs, df_args = args })+ = df { df_bndrs = bndrs', df_args = args' }+ where+ (subst',bndrs') = substBndrs subst bndrs+ args' = map (substExpr (text "subst-unf:dfun") subst') args++substUnfolding subst unf@(CoreUnfolding { uf_tmpl = tmpl, uf_src = src })+ -- Retain an InlineRule!+ | not (isStableSource src) -- Zap an unstable unfolding, to save substitution work+ = NoUnfolding+ | otherwise -- But keep a stable one!+ = seqExpr new_tmpl `seq`+ unf { uf_tmpl = new_tmpl }+ where+ new_tmpl = substExpr (text "subst-unf") subst tmpl++substUnfolding _ unf = unf -- NoUnfolding, OtherCon++------------------+substIdOcc :: Subst -> Id -> Id+-- These Ids should not be substituted to non-Ids+substIdOcc subst v = case lookupIdSubst (text "substIdOcc") subst v of+ Var v' -> v'+ other -> pprPanic "substIdOcc" (vcat [ppr v <+> ppr other, ppr subst])++------------------+-- | Substitutes for the 'Id's within the 'WorkerInfo' given the new function 'Id'+substSpec :: Subst -> Id -> RuleInfo -> RuleInfo+substSpec subst new_id (RuleInfo rules rhs_fvs)+ = seqRuleInfo new_spec `seq` new_spec+ where+ subst_ru_fn = const (idName new_id)+ new_spec = RuleInfo (map (substRule subst subst_ru_fn) rules)+ (substDVarSet subst rhs_fvs)++------------------+substRulesForImportedIds :: Subst -> [CoreRule] -> [CoreRule]+substRulesForImportedIds subst rules+ = map (substRule subst not_needed) rules+ where+ not_needed name = pprPanic "substRulesForImportedIds" (ppr name)++------------------+substRule :: Subst -> (Name -> Name) -> CoreRule -> CoreRule++-- The subst_ru_fn argument is applied to substitute the ru_fn field+-- of the rule:+-- - Rules for *imported* Ids never change ru_fn+-- - Rules for *local* Ids are in the IdInfo for that Id,+-- and the ru_fn field is simply replaced by the new name+-- of the Id+substRule _ _ rule@(BuiltinRule {}) = rule+substRule subst subst_ru_fn rule@(Rule { ru_bndrs = bndrs, ru_args = args+ , ru_fn = fn_name, ru_rhs = rhs+ , ru_local = is_local })+ = rule { ru_bndrs = bndrs'+ , ru_fn = if is_local+ then subst_ru_fn fn_name+ else fn_name+ , ru_args = map (substExpr doc subst') args+ , ru_rhs = substExpr (text "foo") subst' rhs }+ -- Do NOT optimise the RHS (previously we did simplOptExpr here)+ -- See Note [Substitute lazily]+ where+ doc = text "subst-rule" <+> ppr fn_name+ (subst', bndrs') = substBndrs subst bndrs++------------------+substDVarSet :: Subst -> DVarSet -> DVarSet+substDVarSet subst fvs+ = mkDVarSet $ fst $ foldr (subst_fv subst) ([], emptyVarSet) $ dVarSetElems fvs+ where+ subst_fv subst fv acc+ | isId fv = expr_fvs (lookupIdSubst (text "substDVarSet") subst fv) isLocalVar emptyVarSet $! acc+ | otherwise = tyCoFVsOfType (lookupTCvSubst subst fv) (const True) emptyVarSet $! acc++------------------+substTickish :: Subst -> Tickish Id -> Tickish Id+substTickish subst (Breakpoint n ids)+ = Breakpoint n (map do_one ids)+ where+ do_one = getIdFromTrivialExpr . lookupIdSubst (text "subst_tickish") subst+substTickish _subst other = other++{- Note [Substitute lazily]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+The functions that substitute over IdInfo must be pretty lazy, because+they are knot-tied by substRecBndrs.++One case in point was Trac #10627 in which a rule for a function 'f'+referred to 'f' (at a differnet type) on the RHS. But instead of just+substituting in the rhs of the rule, we were calling simpleOptExpr, which+looked at the idInfo for 'f'; result <<loop>>.++In any case we don't need to optimise the RHS of rules, or unfoldings,+because the simplifier will do that.+++Note [substTickish]+~~~~~~~~~~~~~~~~~~~~~~+A Breakpoint contains a list of Ids. What happens if we ever want to+substitute an expression for one of these Ids?++First, we ensure that we only ever substitute trivial expressions for+these Ids, by marking them as NoOccInfo in the occurrence analyser.+Then, when substituting for the Id, we unwrap any type applications+and abstractions to get back to an Id, with getIdFromTrivialExpr.++Second, we have to ensure that we never try to substitute a literal+for an Id in a breakpoint. We ensure this by never storing an Id with+an unlifted type in a Breakpoint - see Coverage.mkTickish.+Breakpoints can't handle free variables with unlifted types anyway.+-}++{-+Note [Worker inlining]+~~~~~~~~~~~~~~~~~~~~~~+A worker can get sustituted away entirely.+ - it might be trivial+ - it might simply be very small+We do not treat an InlWrapper as an 'occurrence' in the occurrence+analyser, so it's possible that the worker is not even in scope any more.++In all all these cases we simply drop the special case, returning to+InlVanilla. The WARN is just so I can see if it happens a lot.+-}+
+ coreSyn/CoreSyn.hs view
@@ -0,0 +1,2161 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP, DeriveDataTypeable, FlexibleContexts #-}+{-# LANGUAGE NamedFieldPuns #-}++-- | CoreSyn holds all the main data types for use by for the Glasgow Haskell Compiler midsection+module CoreSyn (+ -- * Main data types+ Expr(..), Alt, Bind(..), AltCon(..), Arg,+ Tickish(..), TickishScoping(..), TickishPlacement(..),+ CoreProgram, CoreExpr, CoreAlt, CoreBind, CoreArg, CoreBndr,+ TaggedExpr, TaggedAlt, TaggedBind, TaggedArg, TaggedBndr(..), deTagExpr,++ -- * In/Out type synonyms+ InId, InBind, InExpr, InAlt, InArg, InType, InKind,+ InBndr, InVar, InCoercion, InTyVar, InCoVar,+ OutId, OutBind, OutExpr, OutAlt, OutArg, OutType, OutKind,+ OutBndr, OutVar, OutCoercion, OutTyVar, OutCoVar,++ -- ** 'Expr' construction+ mkLet, mkLets, mkLams,+ mkApps, mkTyApps, mkCoApps, mkVarApps, mkTyArg,++ mkIntLit, mkIntLitInt,+ mkWordLit, mkWordLitWord,+ mkWord64LitWord64, mkInt64LitInt64,+ mkCharLit, mkStringLit,+ mkFloatLit, mkFloatLitFloat,+ mkDoubleLit, mkDoubleLitDouble,++ mkConApp, mkConApp2, mkTyBind, mkCoBind,+ varToCoreExpr, varsToCoreExprs,++ isId, cmpAltCon, cmpAlt, ltAlt,++ -- ** Simple 'Expr' access functions and predicates+ bindersOf, bindersOfBinds, rhssOfBind, rhssOfAlts,+ collectBinders, collectTyBinders, collectTyAndValBinders,+ collectNBinders,+ collectArgs, collectArgsTicks, flattenBinds,++ exprToType, exprToCoercion_maybe,+ applyTypeToArg,++ isValArg, isTypeArg, isTyCoArg, valArgCount, valBndrCount,+ isRuntimeArg, isRuntimeVar,++ -- * Tick-related functions+ tickishCounts, tickishScoped, tickishScopesLike, tickishFloatable,+ tickishCanSplit, mkNoCount, mkNoScope,+ tickishIsCode, tickishPlace,+ tickishContains,++ -- * Unfolding data types+ Unfolding(..), UnfoldingGuidance(..), UnfoldingSource(..),++ -- ** Constructing 'Unfolding's+ noUnfolding, bootUnfolding, evaldUnfolding, mkOtherCon,+ unSaturatedOk, needSaturated, boringCxtOk, boringCxtNotOk,++ -- ** Predicates and deconstruction on 'Unfolding'+ unfoldingTemplate, expandUnfolding_maybe,+ maybeUnfoldingTemplate, otherCons,+ isValueUnfolding, isEvaldUnfolding, isCheapUnfolding,+ isExpandableUnfolding, isConLikeUnfolding, isCompulsoryUnfolding,+ isStableUnfolding, isFragileUnfolding, hasSomeUnfolding,+ isBootUnfolding,+ canUnfold, neverUnfoldGuidance, isStableSource,++ -- * Annotated expression data types+ AnnExpr, AnnExpr'(..), AnnBind(..), AnnAlt,++ -- ** Operations on annotated expressions+ collectAnnArgs, collectAnnArgsTicks,++ -- ** Operations on annotations+ deAnnotate, deAnnotate', deAnnAlt,+ collectAnnBndrs, collectNAnnBndrs,++ -- * Orphanhood+ IsOrphan(..), isOrphan, notOrphan, chooseOrphanAnchor,++ -- * Core rule data types+ CoreRule(..), RuleBase,+ RuleName, RuleFun, IdUnfoldingFun, InScopeEnv,+ RuleEnv(..), mkRuleEnv, emptyRuleEnv,++ -- ** Operations on 'CoreRule's+ ruleArity, ruleName, ruleIdName, ruleActivation,+ setRuleIdName, ruleModule,+ isBuiltinRule, isLocalRule, isAutoRule,++ -- * Core vectorisation declarations data type+ CoreVect(..)+ ) where++#include "HsVersions.h"++import CostCentre+import VarEnv( InScopeSet )+import Var+import Type+import Coercion+import Name+import NameSet+import NameEnv( NameEnv, emptyNameEnv )+import Literal+import DataCon+import Module+import TyCon+import BasicTypes+import DynFlags+import Outputable+import Util+import UniqSet+import SrcLoc ( RealSrcSpan, containsSpan )+import Binary++import Data.Data hiding (TyCon)+import Data.Int+import Data.Word++infixl 4 `mkApps`, `mkTyApps`, `mkVarApps`, `App`, `mkCoApps`+-- Left associative, so that we can say (f `mkTyApps` xs `mkVarApps` ys)++{-+************************************************************************+* *+\subsection{The main data types}+* *+************************************************************************++These data types are the heart of the compiler+-}++-- | This is the data type that represents GHCs core intermediate language. Currently+-- GHC uses System FC <http://research.microsoft.com/~simonpj/papers/ext-f/> for this purpose,+-- which is closely related to the simpler and better known System F <http://en.wikipedia.org/wiki/System_F>.+--+-- We get from Haskell source to this Core language in a number of stages:+--+-- 1. The source code is parsed into an abstract syntax tree, which is represented+-- by the data type 'HsExpr.HsExpr' with the names being 'RdrName.RdrNames'+--+-- 2. This syntax tree is /renamed/, which attaches a 'Unique.Unique' to every 'RdrName.RdrName'+-- (yielding a 'Name.Name') to disambiguate identifiers which are lexically identical.+-- For example, this program:+--+-- @+-- f x = let f x = x + 1+-- in f (x - 2)+-- @+--+-- Would be renamed by having 'Unique's attached so it looked something like this:+--+-- @+-- f_1 x_2 = let f_3 x_4 = x_4 + 1+-- in f_3 (x_2 - 2)+-- @+-- But see Note [Shadowing] below.+--+-- 3. The resulting syntax tree undergoes type checking (which also deals with instantiating+-- type class arguments) to yield a 'HsExpr.HsExpr' type that has 'Id.Id' as it's names.+--+-- 4. Finally the syntax tree is /desugared/ from the expressive 'HsExpr.HsExpr' type into+-- this 'Expr' type, which has far fewer constructors and hence is easier to perform+-- optimization, analysis and code generation on.+--+-- The type parameter @b@ is for the type of binders in the expression tree.+--+-- The language consists of the following elements:+--+-- * Variables+--+-- * Primitive literals+--+-- * Applications: note that the argument may be a 'Type'.+-- See Note [CoreSyn let/app invariant]+-- See Note [Levity polymorphism invariants]+--+-- * Lambda abstraction+-- See Note [Levity polymorphism invariants]+--+-- * Recursive and non recursive @let@s. Operationally+-- this corresponds to allocating a thunk for the things+-- bound and then executing the sub-expression.+--+-- #top_level_invariant#+-- #letrec_invariant#+--+-- The right hand sides of all top-level and recursive @let@s+-- /must/ be of lifted type (see "Type#type_classification" for+-- the meaning of /lifted/ vs. /unlifted/). There is one exception+-- to this rule, top-level @let@s are allowed to bind primitive+-- string literals, see Note [CoreSyn top-level string literals].+--+-- See Note [CoreSyn let/app invariant]+-- See Note [Levity polymorphism invariants]+--+-- #type_let#+-- We allow a /non-recursive/ let to bind a type variable, thus:+--+-- > Let (NonRec tv (Type ty)) body+--+-- This can be very convenient for postponing type substitutions until+-- the next run of the simplifier.+--+-- At the moment, the rest of the compiler only deals with type-let+-- in a Let expression, rather than at top level. We may want to revist+-- this choice.+--+-- * Case expression. Operationally this corresponds to evaluating+-- the scrutinee (expression examined) to weak head normal form+-- and then examining at most one level of resulting constructor (i.e. you+-- cannot do nested pattern matching directly with this).+--+-- The binder gets bound to the value of the scrutinee,+-- and the 'Type' must be that of all the case alternatives+--+-- #case_invariants#+-- This is one of the more complicated elements of the Core language,+-- and comes with a number of restrictions:+--+-- 1. The list of alternatives may be empty;+-- See Note [Empty case alternatives]+--+-- 2. The 'DEFAULT' case alternative must be first in the list,+-- if it occurs at all.+--+-- 3. The remaining cases are in order of increasing+-- tag (for 'DataAlts') or+-- lit (for 'LitAlts').+-- This makes finding the relevant constructor easy,+-- and makes comparison easier too.+--+-- 4. The list of alternatives must be exhaustive. An /exhaustive/ case+-- does not necessarily mention all constructors:+--+-- @+-- data Foo = Red | Green | Blue+-- ... case x of+-- Red -> True+-- other -> f (case x of+-- Green -> ...+-- Blue -> ... ) ...+-- @+--+-- The inner case does not need a @Red@ alternative, because @x@+-- can't be @Red@ at that program point.+--+-- 5. Floating-point values must not be scrutinised against literals.+-- See Trac #9238 and Note [Rules for floating-point comparisons]+-- in PrelRules for rationale.+--+-- * Cast an expression to a particular type.+-- This is used to implement @newtype@s (a @newtype@ constructor or+-- destructor just becomes a 'Cast' in Core) and GADTs.+--+-- * Notes. These allow general information to be added to expressions+-- in the syntax tree+--+-- * A type: this should only show up at the top level of an Arg+--+-- * A coercion++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data Expr b+ = Var Id+ | Lit Literal+ | App (Expr b) (Arg b)+ | Lam b (Expr b)+ | Let (Bind b) (Expr b)+ | Case (Expr b) b Type [Alt b] -- See #case_invariants#+ | Cast (Expr b) Coercion+ | Tick (Tickish Id) (Expr b)+ | Type Type+ | Coercion Coercion+ deriving Data++-- | Type synonym for expressions that occur in function argument positions.+-- Only 'Arg' should contain a 'Type' at top level, general 'Expr' should not+type Arg b = Expr b++-- | A case split alternative. Consists of the constructor leading to the alternative,+-- the variables bound from the constructor, and the expression to be executed given that binding.+-- The default alternative is @(DEFAULT, [], rhs)@++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+type Alt b = (AltCon, [b], Expr b)++-- | A case alternative constructor (i.e. pattern match)++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data AltCon+ = DataAlt DataCon -- ^ A plain data constructor: @case e of { Foo x -> ... }@.+ -- Invariant: the 'DataCon' is always from a @data@ type, and never from a @newtype@++ | LitAlt Literal -- ^ A literal: @case e of { 1 -> ... }@+ -- Invariant: always an *unlifted* literal+ -- See Note [Literal alternatives]++ | DEFAULT -- ^ Trivial alternative: @case e of { _ -> ... }@+ deriving (Eq, Data)++-- | Binding, used for top level bindings in a module and local bindings in a @let@.++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data Bind b = NonRec b (Expr b)+ | Rec [(b, (Expr b))]+ deriving Data++{-+Note [Shadowing]+~~~~~~~~~~~~~~~~+While various passes attempt to rename on-the-fly in a manner that+avoids "shadowing" (thereby simplifying downstream optimizations),+neither the simplifier nor any other pass GUARANTEES that shadowing is+avoided. Thus, all passes SHOULD work fine even in the presence of+arbitrary shadowing in their inputs.++In particular, scrutinee variables `x` in expressions of the form+`Case e x t` are often renamed to variables with a prefix+"wild_". These "wild" variables may appear in the body of the+case-expression, and further, may be shadowed within the body.++So the Unique in an Var is not really unique at all. Still, it's very+useful to give a constant-time equality/ordering for Vars, and to give+a key that can be used to make sets of Vars (VarSet), or mappings from+Vars to other things (VarEnv). Moreover, if you do want to eliminate+shadowing, you can give a new Unique to an Id without changing its+printable name, which makes debugging easier.++Note [Literal alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Literal alternatives (LitAlt lit) are always for *un-lifted* literals.+We have one literal, a literal Integer, that is lifted, and we don't+allow in a LitAlt, because LitAlt cases don't do any evaluation. Also+(see Trac #5603) if you say+ case 3 of+ S# x -> ...+ J# _ _ -> ...+(where S#, J# are the constructors for Integer) we don't want the+simplifier calling findAlt with argument (LitAlt 3). No no. Integer+literals are an opaque encoding of an algebraic data type, not of+an unlifted literal, like all the others.++Also, we do not permit case analysis with literal patterns on floating-point+types. See Trac #9238 and Note [Rules for floating-point comparisons] in+PrelRules for the rationale for this restriction.++-------------------------- CoreSyn INVARIANTS ---------------------------++Note [CoreSyn top-level invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See #toplevel_invariant#++Note [CoreSyn letrec invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See #letrec_invariant#++Note [CoreSyn top-level string literals]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As an exception to the usual rule that top-level binders must be lifted,+we allow binding primitive string literals (of type Addr#) of type Addr# at the+top level. This allows us to share string literals earlier in the pipeline and+crucially allows other optimizations in the Core2Core pipeline to fire.+Consider,++ f n = let a::Addr# = "foo"#+ in \x -> blah++In order to be able to inline `f`, we would like to float `a` to the top.+Another option would be to inline `a`, but that would lead to duplicating string+literals, which we want to avoid. See Trac #8472.++The solution is simply to allow top-level unlifted binders. We can't allow+arbitrary unlifted expression at the top-level though, unlifted binders cannot+be thunks, so we just allow string literals.++It is important to note that top-level primitive string literals cannot be+wrapped in Ticks, as is otherwise done with lifted bindings. CoreToStg expects+to see just a plain (Lit (MachStr ...)) expression on the RHS of primitive+string bindings; anything else and things break. CoreLint checks this invariant.+To ensure that ticks don't sneak in CoreUtils.mkTick refuses to wrap any+primitve string expression with a tick.++Also see Note [Compilation plan for top-level string literals].++Note [Compilation plan for top-level string literals]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is a summary on how top-level string literals are handled by various+parts of the compilation pipeline.++* In the source language, there is no way to bind a primitive string literal+ at the top leve.++* In Core, we have a special rule that permits top-level Addr# bindings. See+ Note [CoreSyn top-level string literals]. Core-to-core passes may introduce+ new top-level string literals.++* In STG, top-level string literals are explicitly represented in the syntax+ tree.++* A top-level string literal may end up exported from a module. In this case,+ in the object file, the content of the exported literal is given a label with+ the _bytes suffix.++Note [CoreSyn let/app invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The let/app invariant+ the right hand side of a non-recursive 'Let', and+ the argument of an 'App',+ /may/ be of unlifted type, but only if+ the expression is ok-for-speculation+ or the 'Let' is for a join point.++This means that the let can be floated around+without difficulty. For example, this is OK:++ y::Int# = x +# 1#++But this is not, as it may affect termination if the+expression is floated out:++ y::Int# = fac 4#++In this situation you should use @case@ rather than a @let@. The function+'CoreUtils.needsCaseBinding' can help you determine which to generate, or+alternatively use 'MkCore.mkCoreLet' rather than this constructor directly,+which will generate a @case@ if necessary++The let/app invariant is initially enforced by mkCoreLet and mkCoreApp in+coreSyn/MkCore.++Note [CoreSyn case invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See #case_invariants#++Note [Levity polymorphism invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The levity-polymorphism invariants are these:++* The type of a term-binder must not be levity-polymorphic,+ unless it is a let(rec)-bound join point+ (see Note [Invariants on join points])++* The type of the argument of an App must not be levity-polymorphic.++A type (t::TYPE r) is "levity polymorphic" if 'r' has any free variables.++For example+ \(r::RuntimeRep). \(a::TYPE r). \(x::a). e+is illegal because x's type has kind (TYPE r), which has 'r' free.++See Note [Levity polymorphism checking] in DsMonad to see where these+invariants are established for user-written code.++Note [CoreSyn let goal]+~~~~~~~~~~~~~~~~~~~~~~~+* The simplifier tries to ensure that if the RHS of a let is a constructor+ application, its arguments are trivial, so that the constructor can be+ inlined vigorously.++Note [Type let]+~~~~~~~~~~~~~~~+See #type_let#++Note [Empty case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The alternatives of a case expression should be exhaustive. But+this exhaustive list can be empty!++* A case expression can have empty alternatives if (and only if) the+ scrutinee is bound to raise an exception or diverge. When do we know+ this? See Note [Bottoming expressions] in CoreUtils.++* The possiblity of empty alternatives is one reason we need a type on+ the case expression: if the alternatives are empty we can't get the+ type from the alternatives!++* In the case of empty types (see Note [Bottoming expressions]), say+ data T+ we do NOT want to replace+ case (x::T) of Bool {} --> error Bool "Inaccessible case"+ because x might raise an exception, and *that*'s what we want to see!+ (Trac #6067 is an example.) To preserve semantics we'd have to say+ x `seq` error Bool "Inaccessible case"+ but the 'seq' is just a case, so we are back to square 1. Or I suppose+ we could say+ x |> UnsafeCoerce T Bool+ but that loses all trace of the fact that this originated with an empty+ set of alternatives.++* We can use the empty-alternative construct to coerce error values from+ one type to another. For example++ f :: Int -> Int+ f n = error "urk"++ g :: Int -> (# Char, Bool #)+ g x = case f x of { 0 -> ..., n -> ... }++ Then if we inline f in g's RHS we get+ case (error Int "urk") of (# Char, Bool #) { ... }+ and we can discard the alternatives since the scrutinee is bottom to give+ case (error Int "urk") of (# Char, Bool #) {}++ This is nicer than using an unsafe coerce between Int ~ (# Char,Bool #),+ if for no other reason that we don't need to instantiate the (~) at an+ unboxed type.++* We treat a case expression with empty alternatives as trivial iff+ its scrutinee is (see CoreUtils.exprIsTrivial). This is actually+ important; see Note [Empty case is trivial] in CoreUtils++* An empty case is replaced by its scrutinee during the CoreToStg+ conversion; remember STG is un-typed, so there is no need for+ the empty case to do the type conversion.++Note [Join points]+~~~~~~~~~~~~~~~~~~+In Core, a *join point* is a specially tagged function whose only occurrences+are saturated tail calls. A tail call can appear in these places:++ 1. In the branches (not the scrutinee) of a case+ 2. Underneath a let (value or join point)+ 3. Inside another join point++We write a join-point declaration as+ join j @a @b x y = e1 in e2,+like a let binding but with "join" instead (or "join rec" for "let rec"). Note+that we put the parameters before the = rather than using lambdas; this is+because it's relevant how many parameters the join point takes *as a join+point.* This number is called the *join arity,* distinct from arity because it+counts types as well as values. Note that a join point may return a lambda! So+ join j x = x + 1+is different from+ join j = \x -> x + 1+The former has join arity 1, while the latter has join arity 0.++The identifier for a join point is called a join id or a *label.* An invocation+is called a *jump.* We write a jump using the jump keyword:++ jump j 3++The words *label* and *jump* are evocative of assembly code (or Cmm) for a+reason: join points are indeed compiled as labeled blocks, and jumps become+actual jumps (plus argument passing and stack adjustment). There is no closure+allocated and only a fraction of the function-call overhead. Hence we would+like as many functions as possible to become join points (see OccurAnal) and+the type rules for join points ensure we preserve the properties that make them+efficient.++In the actual AST, a join point is indicated by the IdDetails of the binder: a+local value binding gets 'VanillaId' but a join point gets a 'JoinId' with its+join arity.++For more details, see the paper:++ Luke Maurer, Paul Downen, Zena Ariola, and Simon Peyton Jones. "Compiling+ without continuations." Submitted to PLDI'17.++ https://www.microsoft.com/en-us/research/publication/compiling-without-continuations/++Note [Invariants on join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Join points must follow these invariants:++ 1. All occurrences must be tail calls. Each of these tail calls must pass the+ same number of arguments, counting both types and values; we call this the+ "join arity" (to distinguish from regular arity, which only counts values).++ 2. For join arity n, the right-hand side must begin with at least n lambdas.+ No ticks, no casts, just lambdas! C.f. CoreUtils.joinRhsArity.++ 2a. Moreover, this same constraint applies to any unfolding of the binder.+ Reason: if we want to push a continuation into the RHS we must push it+ into the unfolding as well.++ 3. If the binding is recursive, then all other bindings in the recursive group+ must also be join points.++ 4. The binding's type must not be polymorphic in its return type (as defined+ in Note [The polymorphism rule of join points]).++However, join points have simpler invariants in other ways++ 5. A join point can have an unboxed type without the RHS being+ ok-for-speculation (i.e. drop the let/app invariant)+ e.g. let j :: Int# = factorial x in ...++ 6. A join point can have a levity-polymorphic RHS+ e.g. let j :: r :: TYPE l = fail void# in ...+ This happened in an intermediate program Trac #13394++Examples:++ join j1 x = 1 + x in jump j (jump j x) -- Fails 1: non-tail call+ join j1' x = 1 + x in if even a+ then jump j1 a+ else jump j1 a b -- Fails 1: inconsistent calls+ join j2 x = flip (+) x in j2 1 2 -- Fails 2: not enough lambdas+ join j2' x = \y -> x + y in j3 1 -- Passes: extra lams ok+ join j @a (x :: a) = x -- Fails 4: polymorphic in ret type++Invariant 1 applies to left-hand sides of rewrite rules, so a rule for a join+point must have an exact call as its LHS.++Strictly speaking, invariant 3 is redundant, since a call from inside a lazy+binding isn't a tail call. Since a let-bound value can't invoke a free join+point, then, they can't be mutually recursive. (A Core binding group *can*+include spurious extra bindings if the occurrence analyser hasn't run, so+invariant 3 does still need to be checked.) For the rigorous definition of+"tail call", see Section 3 of the paper (Note [Join points]).++Invariant 4 is subtle; see Note [The polymorphism rule of join points].++Core Lint will check these invariants, anticipating that any binder whose+OccInfo is marked AlwaysTailCalled will become a join point as soon as the+simplifier (or simpleOptPgm) runs.++Note [The type of a join point]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A join point has the same type it would have as a function. That is, if it takes+an Int and a Bool and its body produces a String, its type is `Int -> Bool ->+String`. Natural as this may seem, it can be awkward. A join point shouldn't be+thought to "return" in the same sense a function does---a jump is one-way. This+is crucial for understanding how case-of-case interacts with join points:++ case (join+ j :: Int -> Bool -> String+ j x y = ...+ in+ jump j z w) of+ "" -> True+ _ -> False++The simplifier will pull the case into the join point (see Note [Case-of-case+and join points] in Simplify):++ join+ j :: Int -> Bool -> Bool -- changed!+ j x y = case ... of "" -> True+ _ -> False+ in+ jump j z w++The body of the join point now returns a Bool, so the label `j` has to have its+type updated accordingly. Inconvenient though this may be, it has the advantage+that 'CoreUtils.exprType' can still return a type for any expression, including+a jump.++This differs from the paper (see Note [Invariants on join points]). In the+paper, we instead give j the type `Int -> Bool -> forall a. a`. Then each jump+carries the "return type" as a parameter, exactly the way other non-returning+functions like `error` work:++ case (join+ j :: Int -> Bool -> forall a. a+ j x y = ...+ in+ jump j z w @String) of+ "" -> True+ _ -> False++Now we can move the case inward and we only have to change the jump:++ join+ j :: Int -> Bool -> forall a. a+ j x y = case ... of "" -> True+ _ -> False+ in+ jump j z w @Bool++(Core Lint would still check that the body of the join point has the right type;+that type would simply not be reflected in the join id.)++Note [The polymorphism rule of join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Invariant 4 of Note [Invariants on join points] forbids a join point to be+polymorphic in its return type. That is, if its type is++ forall a1 ... ak. t1 -> ... -> tn -> r++where its join arity is k+n, none of the type parameters ai may occur free in r.+The most direct explanation is that given++ join j @a1 ... @ak x1 ... xn = e1 in e2++our typing rules require `e1` and `e2` to have the same type. Therefore the type+of `e1`---the return type of the join point---must be the same as the type of+e2. Since the type variables aren't bound in `e2`, its type can't include them,+and thus neither can the type of `e1`.++There's a deeper explanation in terms of the sequent calculus in Section 5.3 of+a previous paper:++ Paul Downen, Luke Maurer, Zena Ariola, and Simon Peyton Jones. "Sequent+ calculus as a compiler intermediate language." ICFP'16.++ https://www.microsoft.com/en-us/research/wp-content/uploads/2016/04/sequent-calculus-icfp16.pdf++The quick version: Consider the CPS term (the paper uses the sequent calculus,+but we can translate readily):++ \k -> join j @a1 ... @ak x1 ... xn = e1 k in e2 k++Since `j` is a join point, it doesn't bind a continuation variable but reuses+the variable `k` from the context. But the parameters `ai` are not in `k`'s+scope, and `k`'s type determines the return type of `j`; thus the `ai`s don't+appear in the return type of `j`. (Also, since `e1` and `e2` are passed the same+continuation, they must have the same type; hence the direct explanation above.)++************************************************************************+* *+ In/Out type synonyms+* *+********************************************************************* -}++{- Many passes apply a substitution, and it's very handy to have type+ synonyms to remind us whether or not the substitution has been applied -}++-- Pre-cloning or substitution+type InBndr = CoreBndr+type InType = Type+type InKind = Kind+type InBind = CoreBind+type InExpr = CoreExpr+type InAlt = CoreAlt+type InArg = CoreArg+type InCoercion = Coercion++-- Post-cloning or substitution+type OutBndr = CoreBndr+type OutType = Type+type OutKind = Kind+type OutCoercion = Coercion+type OutBind = CoreBind+type OutExpr = CoreExpr+type OutAlt = CoreAlt+type OutArg = CoreArg+++{- *********************************************************************+* *+ Ticks+* *+************************************************************************+-}++-- | Allows attaching extra information to points in expressions++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data Tickish id =+ -- | An @{-# SCC #-}@ profiling annotation, either automatically+ -- added by the desugarer as a result of -auto-all, or added by+ -- the user.+ ProfNote {+ profNoteCC :: CostCentre, -- ^ the cost centre+ profNoteCount :: !Bool, -- ^ bump the entry count?+ profNoteScope :: !Bool -- ^ scopes over the enclosed expression+ -- (i.e. not just a tick)+ }++ -- | A "tick" used by HPC to track the execution of each+ -- subexpression in the original source code.+ | HpcTick {+ tickModule :: Module,+ tickId :: !Int+ }++ -- | A breakpoint for the GHCi debugger. This behaves like an HPC+ -- tick, but has a list of free variables which will be available+ -- for inspection in GHCi when the program stops at the breakpoint.+ --+ -- NB. we must take account of these Ids when (a) counting free variables,+ -- and (b) substituting (don't substitute for them)+ | Breakpoint+ { breakpointId :: !Int+ , breakpointFVs :: [id] -- ^ the order of this list is important:+ -- it matches the order of the lists in the+ -- appropriate entry in HscTypes.ModBreaks.+ --+ -- Careful about substitution! See+ -- Note [substTickish] in CoreSubst.+ }++ -- | A source note.+ --+ -- Source notes are pure annotations: Their presence should neither+ -- influence compilation nor execution. The semantics are given by+ -- causality: The presence of a source note means that a local+ -- change in the referenced source code span will possibly provoke+ -- the generated code to change. On the flip-side, the functionality+ -- of annotated code *must* be invariant against changes to all+ -- source code *except* the spans referenced in the source notes+ -- (see "Causality of optimized Haskell" paper for details).+ --+ -- Therefore extending the scope of any given source note is always+ -- valid. Note that it is still undesirable though, as this reduces+ -- their usefulness for debugging and profiling. Therefore we will+ -- generally try only to make use of this property where it is+ -- necessary to enable optimizations.+ | SourceNote+ { sourceSpan :: RealSrcSpan -- ^ Source covered+ , sourceName :: String -- ^ Name for source location+ -- (uses same names as CCs)+ }++ deriving (Eq, Ord, Data)++-- | A "counting tick" (where tickishCounts is True) is one that+-- counts evaluations in some way. We cannot discard a counting tick,+-- and the compiler should preserve the number of counting ticks as+-- far as possible.+--+-- However, we still allow the simplifier to increase or decrease+-- sharing, so in practice the actual number of ticks may vary, except+-- that we never change the value from zero to non-zero or vice versa.+tickishCounts :: Tickish id -> Bool+tickishCounts n@ProfNote{} = profNoteCount n+tickishCounts HpcTick{} = True+tickishCounts Breakpoint{} = True+tickishCounts _ = False+++-- | Specifies the scoping behaviour of ticks. This governs the+-- behaviour of ticks that care about the covered code and the cost+-- associated with it. Important for ticks relating to profiling.+data TickishScoping =+ -- | No scoping: The tick does not care about what code it+ -- covers. Transformations can freely move code inside as well as+ -- outside without any additional annotation obligations+ NoScope++ -- | Soft scoping: We want all code that is covered to stay+ -- covered. Note that this scope type does not forbid+ -- transformations from happening, as as long as all results of+ -- the transformations are still covered by this tick or a copy of+ -- it. For example+ --+ -- let x = tick<...> (let y = foo in bar) in baz+ -- ===>+ -- let x = tick<...> bar; y = tick<...> foo in baz+ --+ -- Is a valid transformation as far as "bar" and "foo" is+ -- concerned, because both still are scoped over by the tick.+ --+ -- Note though that one might object to the "let" not being+ -- covered by the tick any more. However, we are generally lax+ -- with this - constant costs don't matter too much, and given+ -- that the "let" was effectively merged we can view it as having+ -- lost its identity anyway.+ --+ -- Also note that this scoping behaviour allows floating a tick+ -- "upwards" in pretty much any situation. For example:+ --+ -- case foo of x -> tick<...> bar+ -- ==>+ -- tick<...> case foo of x -> bar+ --+ -- While this is always leagl, we want to make a best effort to+ -- only make us of this where it exposes transformation+ -- opportunities.+ | SoftScope++ -- | Cost centre scoping: We don't want any costs to move to other+ -- cost-centre stacks. This means we not only want no code or cost+ -- to get moved out of their cost centres, but we also object to+ -- code getting associated with new cost-centre ticks - or+ -- changing the order in which they get applied.+ --+ -- A rule of thumb is that we don't want any code to gain new+ -- annotations. However, there are notable exceptions, for+ -- example:+ --+ -- let f = \y -> foo in tick<...> ... (f x) ...+ -- ==>+ -- tick<...> ... foo[x/y] ...+ --+ -- In-lining lambdas like this is always legal, because inlining a+ -- function does not change the cost-centre stack when the+ -- function is called.+ | CostCentreScope++ deriving (Eq)++-- | Returns the intended scoping rule for a Tickish+tickishScoped :: Tickish id -> TickishScoping+tickishScoped n@ProfNote{}+ | profNoteScope n = CostCentreScope+ | otherwise = NoScope+tickishScoped HpcTick{} = NoScope+tickishScoped Breakpoint{} = CostCentreScope+ -- Breakpoints are scoped: eventually we're going to do call+ -- stacks, but also this helps prevent the simplifier from moving+ -- breakpoints around and changing their result type (see #1531).+tickishScoped SourceNote{} = SoftScope++-- | Returns whether the tick scoping rule is at least as permissive+-- as the given scoping rule.+tickishScopesLike :: Tickish id -> TickishScoping -> Bool+tickishScopesLike t scope = tickishScoped t `like` scope+ where NoScope `like` _ = True+ _ `like` NoScope = False+ SoftScope `like` _ = True+ _ `like` SoftScope = False+ CostCentreScope `like` _ = True++-- | Returns @True@ for ticks that can be floated upwards easily even+-- where it might change execution counts, such as:+--+-- Just (tick<...> foo)+-- ==>+-- tick<...> (Just foo)+--+-- This is a combination of @tickishSoftScope@ and+-- @tickishCounts@. Note that in principle splittable ticks can become+-- floatable using @mkNoTick@ -- even though there's currently no+-- tickish for which that is the case.+tickishFloatable :: Tickish id -> Bool+tickishFloatable t = t `tickishScopesLike` SoftScope && not (tickishCounts t)++-- | Returns @True@ for a tick that is both counting /and/ scoping and+-- can be split into its (tick, scope) parts using 'mkNoScope' and+-- 'mkNoTick' respectively.+tickishCanSplit :: Tickish id -> Bool+tickishCanSplit ProfNote{profNoteScope = True, profNoteCount = True}+ = True+tickishCanSplit _ = False++mkNoCount :: Tickish id -> Tickish id+mkNoCount n | not (tickishCounts n) = n+ | not (tickishCanSplit n) = panic "mkNoCount: Cannot split!"+mkNoCount n@ProfNote{} = n {profNoteCount = False}+mkNoCount _ = panic "mkNoCount: Undefined split!"++mkNoScope :: Tickish id -> Tickish id+mkNoScope n | tickishScoped n == NoScope = n+ | not (tickishCanSplit n) = panic "mkNoScope: Cannot split!"+mkNoScope n@ProfNote{} = n {profNoteScope = False}+mkNoScope _ = panic "mkNoScope: Undefined split!"++-- | Return @True@ if this source annotation compiles to some backend+-- code. Without this flag, the tickish is seen as a simple annotation+-- that does not have any associated evaluation code.+--+-- What this means that we are allowed to disregard the tick if doing+-- so means that we can skip generating any code in the first place. A+-- typical example is top-level bindings:+--+-- foo = tick<...> \y -> ...+-- ==>+-- foo = \y -> tick<...> ...+--+-- Here there is just no operational difference between the first and+-- the second version. Therefore code generation should simply+-- translate the code as if it found the latter.+tickishIsCode :: Tickish id -> Bool+tickishIsCode SourceNote{} = False+tickishIsCode _tickish = True -- all the rest for now+++-- | Governs the kind of expression that the tick gets placed on when+-- annotating for example using @mkTick@. If we find that we want to+-- put a tickish on an expression ruled out here, we try to float it+-- inwards until we find a suitable expression.+data TickishPlacement =++ -- | Place ticks exactly on run-time expressions. We can still+ -- move the tick through pure compile-time constructs such as+ -- other ticks, casts or type lambdas. This is the most+ -- restrictive placement rule for ticks, as all tickishs have in+ -- common that they want to track runtime processes. The only+ -- legal placement rule for counting ticks.+ PlaceRuntime++ -- | As @PlaceRuntime@, but we float the tick through all+ -- lambdas. This makes sense where there is little difference+ -- between annotating the lambda and annotating the lambda's code.+ | PlaceNonLam++ -- | In addition to floating through lambdas, cost-centre style+ -- tickishs can also be moved from constructors, non-function+ -- variables and literals. For example:+ --+ -- let x = scc<...> C (scc<...> y) (scc<...> 3) in ...+ --+ -- Neither the constructor application, the variable or the+ -- literal are likely to have any cost worth mentioning. And even+ -- if y names a thunk, the call would not care about the+ -- evaluation context. Therefore removing all annotations in the+ -- above example is safe.+ | PlaceCostCentre++ deriving (Eq)++-- | Placement behaviour we want for the ticks+tickishPlace :: Tickish id -> TickishPlacement+tickishPlace n@ProfNote{}+ | profNoteCount n = PlaceRuntime+ | otherwise = PlaceCostCentre+tickishPlace HpcTick{} = PlaceRuntime+tickishPlace Breakpoint{} = PlaceRuntime+tickishPlace SourceNote{} = PlaceNonLam++-- | Returns whether one tick "contains" the other one, therefore+-- making the second tick redundant.+tickishContains :: Eq b => Tickish b -> Tickish b -> Bool+tickishContains (SourceNote sp1 n1) (SourceNote sp2 n2)+ = containsSpan sp1 sp2 && n1 == n2+ -- compare the String last+tickishContains t1 t2+ = t1 == t2++{-+************************************************************************+* *+ Orphans+* *+************************************************************************+-}++-- | Is this instance an orphan? If it is not an orphan, contains an 'OccName'+-- witnessing the instance's non-orphanhood.+-- See Note [Orphans]+data IsOrphan+ = IsOrphan+ | NotOrphan OccName -- The OccName 'n' witnesses the instance's non-orphanhood+ -- In that case, the instance is fingerprinted as part+ -- of the definition of 'n's definition+ deriving Data++-- | Returns true if 'IsOrphan' is orphan.+isOrphan :: IsOrphan -> Bool+isOrphan IsOrphan = True+isOrphan _ = False++-- | Returns true if 'IsOrphan' is not an orphan.+notOrphan :: IsOrphan -> Bool+notOrphan NotOrphan{} = True+notOrphan _ = False++chooseOrphanAnchor :: NameSet -> IsOrphan+-- Something (rule, instance) is relate to all the Names in this+-- list. Choose one of them to be an "anchor" for the orphan. We make+-- the choice deterministic to avoid gratuitious changes in the ABI+-- hash (Trac #4012). Specifically, use lexicographic comparison of+-- OccName rather than comparing Uniques+--+-- NB: 'minimum' use Ord, and (Ord OccName) works lexicographically+--+chooseOrphanAnchor local_names+ | isEmptyNameSet local_names = IsOrphan+ | otherwise = NotOrphan (minimum occs)+ where+ occs = map nameOccName $ nonDetEltsUniqSet local_names+ -- It's OK to use nonDetEltsUFM here, see comments above++instance Binary IsOrphan where+ put_ bh IsOrphan = putByte bh 0+ put_ bh (NotOrphan n) = do+ putByte bh 1+ put_ bh n+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IsOrphan+ _ -> do+ n <- get bh+ return $ NotOrphan n++{-+Note [Orphans]+~~~~~~~~~~~~~~+Class instances, rules, and family instances are divided into orphans+and non-orphans. Roughly speaking, an instance/rule is an orphan if+its left hand side mentions nothing defined in this module. Orphan-hood+has two major consequences++ * A module that contains orphans is called an "orphan module". If+ the module being compiled depends (transitively) on an oprhan+ module M, then M.hi is read in regardless of whether M is oherwise+ needed. This is to ensure that we don't miss any instance decls in+ M. But it's painful, because it means we need to keep track of all+ the orphan modules below us.++ * A non-orphan is not finger-printed separately. Instead, for+ fingerprinting purposes it is treated as part of the entity it+ mentions on the LHS. For example+ data T = T1 | T2+ instance Eq T where ....+ The instance (Eq T) is incorprated as part of T's fingerprint.++ In contrast, orphans are all fingerprinted together in the+ mi_orph_hash field of the ModIface.++ See MkIface.addFingerprints.++Orphan-hood is computed+ * For class instances:+ when we make a ClsInst+ (because it is needed during instance lookup)++ * For rules and family instances:+ when we generate an IfaceRule (MkIface.coreRuleToIfaceRule)+ or IfaceFamInst (MkIface.instanceToIfaceInst)+-}++{-+************************************************************************+* *+\subsection{Transformation rules}+* *+************************************************************************++The CoreRule type and its friends are dealt with mainly in CoreRules,+but CoreFVs, Subst, PprCore, CoreTidy also inspect the representation.+-}++-- | Gathers a collection of 'CoreRule's. Maps (the name of) an 'Id' to its rules+type RuleBase = NameEnv [CoreRule]+ -- The rules are unordered;+ -- we sort out any overlaps on lookup++-- | A full rule environment which we can apply rules from. Like a 'RuleBase',+-- but it also includes the set of visible orphans we use to filter out orphan+-- rules which are not visible (even though we can see them...)+data RuleEnv+ = RuleEnv { re_base :: RuleBase+ , re_visible_orphs :: ModuleSet+ }++mkRuleEnv :: RuleBase -> [Module] -> RuleEnv+mkRuleEnv rules vis_orphs = RuleEnv rules (mkModuleSet vis_orphs)++emptyRuleEnv :: RuleEnv+emptyRuleEnv = RuleEnv emptyNameEnv emptyModuleSet++-- | A 'CoreRule' is:+--+-- * \"Local\" if the function it is a rule for is defined in the+-- same module as the rule itself.+--+-- * \"Orphan\" if nothing on the LHS is defined in the same module+-- as the rule itself+data CoreRule+ = Rule {+ ru_name :: RuleName, -- ^ Name of the rule, for communication with the user+ ru_act :: Activation, -- ^ When the rule is active++ -- Rough-matching stuff+ -- see comments with InstEnv.ClsInst( is_cls, is_rough )+ ru_fn :: Name, -- ^ Name of the 'Id.Id' at the head of this rule+ ru_rough :: [Maybe Name], -- ^ Name at the head of each argument to the left hand side++ -- Proper-matching stuff+ -- see comments with InstEnv.ClsInst( is_tvs, is_tys )+ ru_bndrs :: [CoreBndr], -- ^ Variables quantified over+ ru_args :: [CoreExpr], -- ^ Left hand side arguments++ -- And the right-hand side+ ru_rhs :: CoreExpr, -- ^ Right hand side of the rule+ -- Occurrence info is guaranteed correct+ -- See Note [OccInfo in unfoldings and rules]++ -- Locality+ ru_auto :: Bool, -- ^ @True@ <=> this rule is auto-generated+ -- (notably by Specialise or SpecConstr)+ -- @False@ <=> generated at the user's behest+ -- See Note [Trimming auto-rules] in TidyPgm+ -- for the sole purpose of this field.++ ru_origin :: !Module, -- ^ 'Module' the rule was defined in, used+ -- to test if we should see an orphan rule.++ ru_orphan :: !IsOrphan, -- ^ Whether or not the rule is an orphan.++ ru_local :: Bool -- ^ @True@ iff the fn at the head of the rule is+ -- defined in the same module as the rule+ -- and is not an implicit 'Id' (like a record selector,+ -- class operation, or data constructor). This+ -- is different from 'ru_orphan', where a rule+ -- can avoid being an orphan if *any* Name in+ -- LHS of the rule was defined in the same+ -- module as the rule.+ }++ -- | Built-in rules are used for constant folding+ -- and suchlike. They have no free variables.+ -- A built-in rule is always visible (there is no such thing as+ -- an orphan built-in rule.)+ | BuiltinRule {+ ru_name :: RuleName, -- ^ As above+ ru_fn :: Name, -- ^ As above+ ru_nargs :: Int, -- ^ Number of arguments that 'ru_try' consumes,+ -- if it fires, including type arguments+ ru_try :: RuleFun+ -- ^ This function does the rewrite. It given too many+ -- arguments, it simply discards them; the returned 'CoreExpr'+ -- is just the rewrite of 'ru_fn' applied to the first 'ru_nargs' args+ }+ -- See Note [Extra args in rule matching] in Rules.hs++type RuleFun = DynFlags -> InScopeEnv -> Id -> [CoreExpr] -> Maybe CoreExpr+type InScopeEnv = (InScopeSet, IdUnfoldingFun)++type IdUnfoldingFun = Id -> Unfolding+-- A function that embodies how to unfold an Id if you need+-- to do that in the Rule. The reason we need to pass this info in+-- is that whether an Id is unfoldable depends on the simplifier phase++isBuiltinRule :: CoreRule -> Bool+isBuiltinRule (BuiltinRule {}) = True+isBuiltinRule _ = False++isAutoRule :: CoreRule -> Bool+isAutoRule (BuiltinRule {}) = False+isAutoRule (Rule { ru_auto = is_auto }) = is_auto++-- | The number of arguments the 'ru_fn' must be applied+-- to before the rule can match on it+ruleArity :: CoreRule -> Int+ruleArity (BuiltinRule {ru_nargs = n}) = n+ruleArity (Rule {ru_args = args}) = length args++ruleName :: CoreRule -> RuleName+ruleName = ru_name++ruleModule :: CoreRule -> Maybe Module+ruleModule Rule { ru_origin } = Just ru_origin+ruleModule BuiltinRule {} = Nothing++ruleActivation :: CoreRule -> Activation+ruleActivation (BuiltinRule { }) = AlwaysActive+ruleActivation (Rule { ru_act = act }) = act++-- | The 'Name' of the 'Id.Id' at the head of the rule left hand side+ruleIdName :: CoreRule -> Name+ruleIdName = ru_fn++isLocalRule :: CoreRule -> Bool+isLocalRule = ru_local++-- | Set the 'Name' of the 'Id.Id' at the head of the rule left hand side+setRuleIdName :: Name -> CoreRule -> CoreRule+setRuleIdName nm ru = ru { ru_fn = nm }++{-+************************************************************************+* *+\subsection{Vectorisation declarations}+* *+************************************************************************++Representation of desugared vectorisation declarations that are fed to the vectoriser (via+'ModGuts').+-}++data CoreVect = Vect Id CoreExpr+ | NoVect Id+ | VectType Bool TyCon (Maybe TyCon)+ | VectClass TyCon -- class tycon+ | VectInst Id -- instance dfun (always SCALAR) !!!FIXME: should be superfluous now++{-+************************************************************************+* *+ Unfoldings+* *+************************************************************************++The @Unfolding@ type is declared here to avoid numerous loops+-}++-- | Records the /unfolding/ of an identifier, which is approximately the form the+-- identifier would have if we substituted its definition in for the identifier.+-- This type should be treated as abstract everywhere except in "CoreUnfold"+data Unfolding+ = NoUnfolding -- ^ We have no information about the unfolding.++ | BootUnfolding -- ^ We have no information about the unfolding, because+ -- this 'Id' came from an @hi-boot@ file.+ -- See Note [Inlining and hs-boot files] in ToIface+ -- for what this is used for.++ | OtherCon [AltCon] -- ^ It ain't one of these constructors.+ -- @OtherCon xs@ also indicates that something has been evaluated+ -- and hence there's no point in re-evaluating it.+ -- @OtherCon []@ is used even for non-data-type values+ -- to indicated evaluated-ness. Notably:+ --+ -- > data C = C !(Int -> Int)+ -- > case x of { C f -> ... }+ --+ -- Here, @f@ gets an @OtherCon []@ unfolding.++ | DFunUnfolding { -- The Unfolding of a DFunId+ -- See Note [DFun unfoldings]+ -- df = /\a1..am. \d1..dn. MkD t1 .. tk+ -- (op1 a1..am d1..dn)+ -- (op2 a1..am d1..dn)+ df_bndrs :: [Var], -- The bound variables [a1..m],[d1..dn]+ df_con :: DataCon, -- The dictionary data constructor (never a newtype datacon)+ df_args :: [CoreExpr] -- Args of the data con: types, superclasses and methods,+ } -- in positional order++ | CoreUnfolding { -- An unfolding for an Id with no pragma,+ -- or perhaps a NOINLINE pragma+ -- (For NOINLINE, the phase, if any, is in the+ -- InlinePragInfo for this Id.)+ uf_tmpl :: CoreExpr, -- Template; occurrence info is correct+ uf_src :: UnfoldingSource, -- Where the unfolding came from+ uf_is_top :: Bool, -- True <=> top level binding+ uf_is_value :: Bool, -- exprIsHNF template (cached); it is ok to discard+ -- a `seq` on this variable+ uf_is_conlike :: Bool, -- True <=> applicn of constructor or CONLIKE function+ -- Cached version of exprIsConLike+ uf_is_work_free :: Bool, -- True <=> doesn't waste (much) work to expand+ -- inside an inlining+ -- Cached version of exprIsCheap+ uf_expandable :: Bool, -- True <=> can expand in RULE matching+ -- Cached version of exprIsExpandable+ uf_guidance :: UnfoldingGuidance -- Tells about the *size* of the template.+ }+ -- ^ An unfolding with redundant cached information. Parameters:+ --+ -- uf_tmpl: Template used to perform unfolding;+ -- NB: Occurrence info is guaranteed correct:+ -- see Note [OccInfo in unfoldings and rules]+ --+ -- uf_is_top: Is this a top level binding?+ --+ -- uf_is_value: 'exprIsHNF' template (cached); it is ok to discard a 'seq' on+ -- this variable+ --+ -- uf_is_work_free: Does this waste only a little work if we expand it inside an inlining?+ -- Basically this is a cached version of 'exprIsWorkFree'+ --+ -- uf_guidance: Tells us about the /size/ of the unfolding template+++------------------------------------------------+data UnfoldingSource+ = -- See also Note [Historical note: unfoldings for wrappers]++ InlineRhs -- The current rhs of the function+ -- Replace uf_tmpl each time around++ | InlineStable -- From an INLINE or INLINABLE pragma+ -- INLINE if guidance is UnfWhen+ -- INLINABLE if guidance is UnfIfGoodArgs/UnfoldNever+ -- (well, technically an INLINABLE might be made+ -- UnfWhen if it was small enough, and then+ -- it will behave like INLINE outside the current+ -- module, but that is the way automatic unfoldings+ -- work so it is consistent with the intended+ -- meaning of INLINABLE).+ --+ -- uf_tmpl may change, but only as a result of+ -- gentle simplification, it doesn't get updated+ -- to the current RHS during compilation as with+ -- InlineRhs.+ --+ -- See Note [InlineStable]++ | InlineCompulsory -- Something that *has* no binding, so you *must* inline it+ -- Only a few primop-like things have this property+ -- (see MkId.hs, calls to mkCompulsoryUnfolding).+ -- Inline absolutely always, however boring the context.++++-- | 'UnfoldingGuidance' says when unfolding should take place+data UnfoldingGuidance+ = UnfWhen { -- Inline without thinking about the *size* of the uf_tmpl+ -- Used (a) for small *and* cheap unfoldings+ -- (b) for INLINE functions+ -- See Note [INLINE for small functions] in CoreUnfold+ ug_arity :: Arity, -- Number of value arguments expected++ ug_unsat_ok :: Bool, -- True <=> ok to inline even if unsaturated+ ug_boring_ok :: Bool -- True <=> ok to inline even if the context is boring+ -- So True,True means "always"+ }++ | UnfIfGoodArgs { -- Arose from a normal Id; the info here is the+ -- result of a simple analysis of the RHS++ ug_args :: [Int], -- Discount if the argument is evaluated.+ -- (i.e., a simplification will definitely+ -- be possible). One elt of the list per *value* arg.++ ug_size :: Int, -- The "size" of the unfolding.++ ug_res :: Int -- Scrutinee discount: the discount to substract if the thing is in+ } -- a context (case (thing args) of ...),+ -- (where there are the right number of arguments.)++ | UnfNever -- The RHS is big, so don't inline it+ deriving (Eq)++{-+Note [Historical note: unfoldings for wrappers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We used to have a nice clever scheme in interface files for+wrappers. A wrapper's unfolding can be reconstructed from its worker's+id and its strictness. This decreased .hi file size (sometimes+significantly, for modules like GHC.Classes with many high-arity w/w+splits) and had a slight corresponding effect on compile times.++However, when we added the second demand analysis, this scheme lead to+some Core lint errors. The second analysis could change the strictness+signatures, which sometimes resulted in a wrapper's regenerated+unfolding applying the wrapper to too many arguments.++Instead of repairing the clever .hi scheme, we abandoned it in favor+of simplicity. The .hi sizes are usually insignificant (excluding the++1M for base libraries), and compile time barely increases (~+1% for+nofib). The nicer upshot is that the UnfoldingSource no longer mentions+an Id, so, eg, substitutions need not traverse them.+++Note [DFun unfoldings]+~~~~~~~~~~~~~~~~~~~~~~+The Arity in a DFunUnfolding is total number of args (type and value)+that the DFun needs to produce a dictionary. That's not necessarily+related to the ordinary arity of the dfun Id, esp if the class has+one method, so the dictionary is represented by a newtype. Example++ class C a where { op :: a -> Int }+ instance C a -> C [a] where op xs = op (head xs)++The instance translates to++ $dfCList :: forall a. C a => C [a] -- Arity 2!+ $dfCList = /\a.\d. $copList {a} d |> co++ $copList :: forall a. C a => [a] -> Int -- Arity 2!+ $copList = /\a.\d.\xs. op {a} d (head xs)++Now we might encounter (op (dfCList {ty} d) a1 a2)+and we want the (op (dfList {ty} d)) rule to fire, because $dfCList+has all its arguments, even though its (value) arity is 2. That's+why we record the number of expected arguments in the DFunUnfolding.++Note that although it's an Arity, it's most convenient for it to give+the *total* number of arguments, both type and value. See the use+site in exprIsConApp_maybe.+-}++-- Constants for the UnfWhen constructor+needSaturated, unSaturatedOk :: Bool+needSaturated = False+unSaturatedOk = True++boringCxtNotOk, boringCxtOk :: Bool+boringCxtOk = True+boringCxtNotOk = False++------------------------------------------------+noUnfolding :: Unfolding+-- ^ There is no known 'Unfolding'+evaldUnfolding :: Unfolding+-- ^ This unfolding marks the associated thing as being evaluated++noUnfolding = NoUnfolding+evaldUnfolding = OtherCon []++-- | There is no known 'Unfolding', because this came from an+-- hi-boot file.+bootUnfolding :: Unfolding+bootUnfolding = BootUnfolding++mkOtherCon :: [AltCon] -> Unfolding+mkOtherCon = OtherCon++isStableSource :: UnfoldingSource -> Bool+-- Keep the unfolding template+isStableSource InlineCompulsory = True+isStableSource InlineStable = True+isStableSource InlineRhs = False++-- | Retrieves the template of an unfolding: panics if none is known+unfoldingTemplate :: Unfolding -> CoreExpr+unfoldingTemplate = uf_tmpl++-- | Retrieves the template of an unfolding if possible+-- maybeUnfoldingTemplate is used mainly wnen specialising, and we do+-- want to specialise DFuns, so it's important to return a template+-- for DFunUnfoldings+maybeUnfoldingTemplate :: Unfolding -> Maybe CoreExpr+maybeUnfoldingTemplate (CoreUnfolding { uf_tmpl = expr })+ = Just expr+maybeUnfoldingTemplate (DFunUnfolding { df_bndrs = bndrs, df_con = con, df_args = args })+ = Just (mkLams bndrs (mkApps (Var (dataConWorkId con)) args))+maybeUnfoldingTemplate _+ = Nothing++-- | The constructors that the unfolding could never be:+-- returns @[]@ if no information is available+otherCons :: Unfolding -> [AltCon]+otherCons (OtherCon cons) = cons+otherCons _ = []++-- | Determines if it is certainly the case that the unfolding will+-- yield a value (something in HNF): returns @False@ if unsure+isValueUnfolding :: Unfolding -> Bool+ -- Returns False for OtherCon+isValueUnfolding (CoreUnfolding { uf_is_value = is_evald }) = is_evald+isValueUnfolding _ = False++-- | Determines if it possibly the case that the unfolding will+-- yield a value. Unlike 'isValueUnfolding' it returns @True@+-- for 'OtherCon'+isEvaldUnfolding :: Unfolding -> Bool+ -- Returns True for OtherCon+isEvaldUnfolding (OtherCon _) = True+isEvaldUnfolding (CoreUnfolding { uf_is_value = is_evald }) = is_evald+isEvaldUnfolding _ = False++-- | @True@ if the unfolding is a constructor application, the application+-- of a CONLIKE function or 'OtherCon'+isConLikeUnfolding :: Unfolding -> Bool+isConLikeUnfolding (OtherCon _) = True+isConLikeUnfolding (CoreUnfolding { uf_is_conlike = con }) = con+isConLikeUnfolding _ = False++-- | Is the thing we will unfold into certainly cheap?+isCheapUnfolding :: Unfolding -> Bool+isCheapUnfolding (CoreUnfolding { uf_is_work_free = is_wf }) = is_wf+isCheapUnfolding _ = False++isExpandableUnfolding :: Unfolding -> Bool+isExpandableUnfolding (CoreUnfolding { uf_expandable = is_expable }) = is_expable+isExpandableUnfolding _ = False++expandUnfolding_maybe :: Unfolding -> Maybe CoreExpr+-- Expand an expandable unfolding; this is used in rule matching+-- See Note [Expanding variables] in Rules.hs+-- The key point here is that CONLIKE things can be expanded+expandUnfolding_maybe (CoreUnfolding { uf_expandable = True, uf_tmpl = rhs }) = Just rhs+expandUnfolding_maybe _ = Nothing++isCompulsoryUnfolding :: Unfolding -> Bool+isCompulsoryUnfolding (CoreUnfolding { uf_src = InlineCompulsory }) = True+isCompulsoryUnfolding _ = False++isStableUnfolding :: Unfolding -> Bool+-- True of unfoldings that should not be overwritten+-- by a CoreUnfolding for the RHS of a let-binding+isStableUnfolding (CoreUnfolding { uf_src = src }) = isStableSource src+isStableUnfolding (DFunUnfolding {}) = True+isStableUnfolding _ = False++-- | Only returns False if there is no unfolding information available at all+hasSomeUnfolding :: Unfolding -> Bool+hasSomeUnfolding NoUnfolding = False+hasSomeUnfolding BootUnfolding = False+hasSomeUnfolding _ = True++isBootUnfolding :: Unfolding -> Bool+isBootUnfolding BootUnfolding = True+isBootUnfolding _ = False++neverUnfoldGuidance :: UnfoldingGuidance -> Bool+neverUnfoldGuidance UnfNever = True+neverUnfoldGuidance _ = False++isFragileUnfolding :: Unfolding -> Bool+-- An unfolding is fragile if it mentions free variables or+-- is otherwise subject to change. A robust one can be kept.+-- See Note [Fragile unfoldings]+isFragileUnfolding (CoreUnfolding {}) = True+isFragileUnfolding (DFunUnfolding {}) = True+isFragileUnfolding _ = False+ -- NoUnfolding, BootUnfolding, OtherCon are all non-fragile++canUnfold :: Unfolding -> Bool+canUnfold (CoreUnfolding { uf_guidance = g }) = not (neverUnfoldGuidance g)+canUnfold _ = False++{- Note [Fragile unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+An unfolding is "fragile" if it mentions free variables (and hence would+need substitution) or might be affected by optimisation. The non-fragile+ones are++ NoUnfolding, BootUnfolding++ OtherCon {} If we know this binder (say a lambda binder) will be+ bound to an evaluated thing, we want to retain that+ info in simpleOptExpr; see Trac #13077.++We consider even a StableUnfolding as fragile, because it needs substitution.++Note [InlineStable]+~~~~~~~~~~~~~~~~~+When you say+ {-# INLINE f #-}+ f x = <rhs>+you intend that calls (f e) are replaced by <rhs>[e/x] So we+should capture (\x.<rhs>) in the Unfolding of 'f', and never meddle+with it. Meanwhile, we can optimise <rhs> to our heart's content,+leaving the original unfolding intact in Unfolding of 'f'. For example+ all xs = foldr (&&) True xs+ any p = all . map p {-# INLINE any #-}+We optimise any's RHS fully, but leave the InlineRule saying "all . map p",+which deforests well at the call site.++So INLINE pragma gives rise to an InlineRule, which captures the original RHS.++Moreover, it's only used when 'f' is applied to the+specified number of arguments; that is, the number of argument on+the LHS of the '=' sign in the original source definition.+For example, (.) is now defined in the libraries like this+ {-# INLINE (.) #-}+ (.) f g = \x -> f (g x)+so that it'll inline when applied to two arguments. If 'x' appeared+on the left, thus+ (.) f g x = f (g x)+it'd only inline when applied to three arguments. This slightly-experimental+change was requested by Roman, but it seems to make sense.++See also Note [Inlining an InlineRule] in CoreUnfold.+++Note [OccInfo in unfoldings and rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In unfoldings and rules, we guarantee that the template is occ-analysed,+so that the occurrence info on the binders is correct. This is important,+because the Simplifier does not re-analyse the template when using it. If+the occurrence info is wrong+ - We may get more simpifier iterations than necessary, because+ once-occ info isn't there+ - More seriously, we may get an infinite loop if there's a Rec+ without a loop breaker marked+++************************************************************************+* *+ AltCon+* *+************************************************************************+-}++-- The Ord is needed for the FiniteMap used in the lookForConstructor+-- in SimplEnv. If you declared that lookForConstructor *ignores*+-- constructor-applications with LitArg args, then you could get+-- rid of this Ord.++instance Outputable AltCon where+ ppr (DataAlt dc) = ppr dc+ ppr (LitAlt lit) = ppr lit+ ppr DEFAULT = text "__DEFAULT"++cmpAlt :: (AltCon, a, b) -> (AltCon, a, b) -> Ordering+cmpAlt (con1, _, _) (con2, _, _) = con1 `cmpAltCon` con2++ltAlt :: (AltCon, a, b) -> (AltCon, a, b) -> Bool+ltAlt a1 a2 = (a1 `cmpAlt` a2) == LT++cmpAltCon :: AltCon -> AltCon -> Ordering+-- ^ Compares 'AltCon's within a single list of alternatives+cmpAltCon DEFAULT DEFAULT = EQ+cmpAltCon DEFAULT _ = LT++cmpAltCon (DataAlt d1) (DataAlt d2) = dataConTag d1 `compare` dataConTag d2+cmpAltCon (DataAlt _) DEFAULT = GT+cmpAltCon (LitAlt l1) (LitAlt l2) = l1 `compare` l2+cmpAltCon (LitAlt _) DEFAULT = GT++cmpAltCon con1 con2 = WARN( True, text "Comparing incomparable AltCons" <+>+ ppr con1 <+> ppr con2 )+ LT++{-+************************************************************************+* *+\subsection{Useful synonyms}+* *+************************************************************************++Note [CoreProgram]+~~~~~~~~~~~~~~~~~~+The top level bindings of a program, a CoreProgram, are represented as+a list of CoreBind++ * Later bindings in the list can refer to earlier ones, but not vice+ versa. So this is OK+ NonRec { x = 4 }+ Rec { p = ...q...x...+ ; q = ...p...x }+ Rec { f = ...p..x..f.. }+ NonRec { g = ..f..q...x.. }+ But it would NOT be ok for 'f' to refer to 'g'.++ * The occurrence analyser does strongly-connected component analysis+ on each Rec binding, and splits it into a sequence of smaller+ bindings where possible. So the program typically starts life as a+ single giant Rec, which is then dependency-analysed into smaller+ chunks.+-}++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+type CoreProgram = [CoreBind] -- See Note [CoreProgram]++-- | The common case for the type of binders and variables when+-- we are manipulating the Core language within GHC+type CoreBndr = Var+-- | Expressions where binders are 'CoreBndr's+type CoreExpr = Expr CoreBndr+-- | Argument expressions where binders are 'CoreBndr's+type CoreArg = Arg CoreBndr+-- | Binding groups where binders are 'CoreBndr's+type CoreBind = Bind CoreBndr+-- | Case alternatives where binders are 'CoreBndr's+type CoreAlt = Alt CoreBndr++{-+************************************************************************+* *+\subsection{Tagging}+* *+************************************************************************+-}++-- | Binders are /tagged/ with a t+data TaggedBndr t = TB CoreBndr t -- TB for "tagged binder"++type TaggedBind t = Bind (TaggedBndr t)+type TaggedExpr t = Expr (TaggedBndr t)+type TaggedArg t = Arg (TaggedBndr t)+type TaggedAlt t = Alt (TaggedBndr t)++instance Outputable b => Outputable (TaggedBndr b) where+ ppr (TB b l) = char '<' <> ppr b <> comma <> ppr l <> char '>'++deTagExpr :: TaggedExpr t -> CoreExpr+deTagExpr (Var v) = Var v+deTagExpr (Lit l) = Lit l+deTagExpr (Type ty) = Type ty+deTagExpr (Coercion co) = Coercion co+deTagExpr (App e1 e2) = App (deTagExpr e1) (deTagExpr e2)+deTagExpr (Lam (TB b _) e) = Lam b (deTagExpr e)+deTagExpr (Let bind body) = Let (deTagBind bind) (deTagExpr body)+deTagExpr (Case e (TB b _) ty alts) = Case (deTagExpr e) b ty (map deTagAlt alts)+deTagExpr (Tick t e) = Tick t (deTagExpr e)+deTagExpr (Cast e co) = Cast (deTagExpr e) co++deTagBind :: TaggedBind t -> CoreBind+deTagBind (NonRec (TB b _) rhs) = NonRec b (deTagExpr rhs)+deTagBind (Rec prs) = Rec [(b, deTagExpr rhs) | (TB b _, rhs) <- prs]++deTagAlt :: TaggedAlt t -> CoreAlt+deTagAlt (con, bndrs, rhs) = (con, [b | TB b _ <- bndrs], deTagExpr rhs)++{-+************************************************************************+* *+\subsection{Core-constructing functions with checking}+* *+************************************************************************+-}++-- | Apply a list of argument expressions to a function expression in a nested fashion. Prefer to+-- use 'MkCore.mkCoreApps' if possible+mkApps :: Expr b -> [Arg b] -> Expr b+-- | Apply a list of type argument expressions to a function expression in a nested fashion+mkTyApps :: Expr b -> [Type] -> Expr b+-- | Apply a list of coercion argument expressions to a function expression in a nested fashion+mkCoApps :: Expr b -> [Coercion] -> Expr b+-- | Apply a list of type or value variables to a function expression in a nested fashion+mkVarApps :: Expr b -> [Var] -> Expr b+-- | Apply a list of argument expressions to a data constructor in a nested fashion. Prefer to+-- use 'MkCore.mkCoreConApps' if possible+mkConApp :: DataCon -> [Arg b] -> Expr b++mkApps f args = foldl App f args+mkCoApps f args = foldl (\ e a -> App e (Coercion a)) f args+mkVarApps f vars = foldl (\ e a -> App e (varToCoreExpr a)) f vars+mkConApp con args = mkApps (Var (dataConWorkId con)) args++mkTyApps f args = foldl (\ e a -> App e (mkTyArg a)) f args++mkConApp2 :: DataCon -> [Type] -> [Var] -> Expr b+mkConApp2 con tys arg_ids = Var (dataConWorkId con)+ `mkApps` map Type tys+ `mkApps` map varToCoreExpr arg_ids++mkTyArg :: Type -> Expr b+mkTyArg ty+ | Just co <- isCoercionTy_maybe ty = Coercion co+ | otherwise = Type ty++-- | Create a machine integer literal expression of type @Int#@ from an @Integer@.+-- If you want an expression of type @Int@ use 'MkCore.mkIntExpr'+mkIntLit :: DynFlags -> Integer -> Expr b+-- | Create a machine integer literal expression of type @Int#@ from an @Int@.+-- If you want an expression of type @Int@ use 'MkCore.mkIntExpr'+mkIntLitInt :: DynFlags -> Int -> Expr b++mkIntLit dflags n = Lit (mkMachInt dflags n)+mkIntLitInt dflags n = Lit (mkMachInt dflags (toInteger n))++-- | Create a machine word literal expression of type @Word#@ from an @Integer@.+-- If you want an expression of type @Word@ use 'MkCore.mkWordExpr'+mkWordLit :: DynFlags -> Integer -> Expr b+-- | Create a machine word literal expression of type @Word#@ from a @Word@.+-- If you want an expression of type @Word@ use 'MkCore.mkWordExpr'+mkWordLitWord :: DynFlags -> Word -> Expr b++mkWordLit dflags w = Lit (mkMachWord dflags w)+mkWordLitWord dflags w = Lit (mkMachWord dflags (toInteger w))++mkWord64LitWord64 :: Word64 -> Expr b+mkWord64LitWord64 w = Lit (mkMachWord64 (toInteger w))++mkInt64LitInt64 :: Int64 -> Expr b+mkInt64LitInt64 w = Lit (mkMachInt64 (toInteger w))++-- | Create a machine character literal expression of type @Char#@.+-- If you want an expression of type @Char@ use 'MkCore.mkCharExpr'+mkCharLit :: Char -> Expr b+-- | Create a machine string literal expression of type @Addr#@.+-- If you want an expression of type @String@ use 'MkCore.mkStringExpr'+mkStringLit :: String -> Expr b++mkCharLit c = Lit (mkMachChar c)+mkStringLit s = Lit (mkMachString s)++-- | Create a machine single precision literal expression of type @Float#@ from a @Rational@.+-- If you want an expression of type @Float@ use 'MkCore.mkFloatExpr'+mkFloatLit :: Rational -> Expr b+-- | Create a machine single precision literal expression of type @Float#@ from a @Float@.+-- If you want an expression of type @Float@ use 'MkCore.mkFloatExpr'+mkFloatLitFloat :: Float -> Expr b++mkFloatLit f = Lit (mkMachFloat f)+mkFloatLitFloat f = Lit (mkMachFloat (toRational f))++-- | Create a machine double precision literal expression of type @Double#@ from a @Rational@.+-- If you want an expression of type @Double@ use 'MkCore.mkDoubleExpr'+mkDoubleLit :: Rational -> Expr b+-- | Create a machine double precision literal expression of type @Double#@ from a @Double@.+-- If you want an expression of type @Double@ use 'MkCore.mkDoubleExpr'+mkDoubleLitDouble :: Double -> Expr b++mkDoubleLit d = Lit (mkMachDouble d)+mkDoubleLitDouble d = Lit (mkMachDouble (toRational d))++-- | Bind all supplied binding groups over an expression in a nested let expression. Assumes+-- that the rhs satisfies the let/app invariant. Prefer to use 'MkCore.mkCoreLets' if+-- possible, which does guarantee the invariant+mkLets :: [Bind b] -> Expr b -> Expr b+-- | Bind all supplied binders over an expression in a nested lambda expression. Prefer to+-- use 'MkCore.mkCoreLams' if possible+mkLams :: [b] -> Expr b -> Expr b++mkLams binders body = foldr Lam body binders+mkLets binds body = foldr mkLet body binds++mkLet :: Bind b -> Expr b -> Expr b+-- The desugarer sometimes generates an empty Rec group+-- which Lint rejects, so we kill it off right away+mkLet (Rec []) body = body+mkLet bind body = Let bind body++-- | Create a binding group where a type variable is bound to a type. Per "CoreSyn#type_let",+-- this can only be used to bind something in a non-recursive @let@ expression+mkTyBind :: TyVar -> Type -> CoreBind+mkTyBind tv ty = NonRec tv (Type ty)++-- | Create a binding group where a type variable is bound to a type. Per "CoreSyn#type_let",+-- this can only be used to bind something in a non-recursive @let@ expression+mkCoBind :: CoVar -> Coercion -> CoreBind+mkCoBind cv co = NonRec cv (Coercion co)++-- | Convert a binder into either a 'Var' or 'Type' 'Expr' appropriately+varToCoreExpr :: CoreBndr -> Expr b+varToCoreExpr v | isTyVar v = Type (mkTyVarTy v)+ | isCoVar v = Coercion (mkCoVarCo v)+ | otherwise = ASSERT( isId v ) Var v++varsToCoreExprs :: [CoreBndr] -> [Expr b]+varsToCoreExprs vs = map varToCoreExpr vs++{-+************************************************************************+* *+ Getting a result type+* *+************************************************************************++These are defined here to avoid a module loop between CoreUtils and CoreFVs++-}++applyTypeToArg :: Type -> CoreExpr -> Type+-- ^ Determines the type resulting from applying an expression with given type+-- to a given argument expression+applyTypeToArg fun_ty arg = piResultTy fun_ty (exprToType arg)++-- | If the expression is a 'Type', converts. Otherwise,+-- panics. NB: This does /not/ convert 'Coercion' to 'CoercionTy'.+exprToType :: CoreExpr -> Type+exprToType (Type ty) = ty+exprToType _bad = pprPanic "exprToType" empty++-- | If the expression is a 'Coercion', converts.+exprToCoercion_maybe :: CoreExpr -> Maybe Coercion+exprToCoercion_maybe (Coercion co) = Just co+exprToCoercion_maybe _ = Nothing++{-+************************************************************************+* *+\subsection{Simple access functions}+* *+************************************************************************+-}++-- | Extract every variable by this group+bindersOf :: Bind b -> [b]+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+bindersOf (NonRec binder _) = [binder]+bindersOf (Rec pairs) = [binder | (binder, _) <- pairs]++-- | 'bindersOf' applied to a list of binding groups+bindersOfBinds :: [Bind b] -> [b]+bindersOfBinds binds = foldr ((++) . bindersOf) [] binds++rhssOfBind :: Bind b -> [Expr b]+rhssOfBind (NonRec _ rhs) = [rhs]+rhssOfBind (Rec pairs) = [rhs | (_,rhs) <- pairs]++rhssOfAlts :: [Alt b] -> [Expr b]+rhssOfAlts alts = [e | (_,_,e) <- alts]++-- | Collapse all the bindings in the supplied groups into a single+-- list of lhs\/rhs pairs suitable for binding in a 'Rec' binding group+flattenBinds :: [Bind b] -> [(b, Expr b)]+flattenBinds (NonRec b r : binds) = (b,r) : flattenBinds binds+flattenBinds (Rec prs1 : binds) = prs1 ++ flattenBinds binds+flattenBinds [] = []++-- | We often want to strip off leading lambdas before getting down to+-- business. Variants are 'collectTyBinders', 'collectValBinders',+-- and 'collectTyAndValBinders'+collectBinders :: Expr b -> ([b], Expr b)+collectTyBinders :: CoreExpr -> ([TyVar], CoreExpr)+collectValBinders :: CoreExpr -> ([Id], CoreExpr)+collectTyAndValBinders :: CoreExpr -> ([TyVar], [Id], CoreExpr)+-- | Strip off exactly N leading lambdas (type or value). Good for use with+-- join points.+collectNBinders :: Int -> Expr b -> ([b], Expr b)++collectBinders expr+ = go [] expr+ where+ go bs (Lam b e) = go (b:bs) e+ go bs e = (reverse bs, e)++collectTyBinders expr+ = go [] expr+ where+ go tvs (Lam b e) | isTyVar b = go (b:tvs) e+ go tvs e = (reverse tvs, e)++collectValBinders expr+ = go [] expr+ where+ go ids (Lam b e) | isId b = go (b:ids) e+ go ids body = (reverse ids, body)++collectTyAndValBinders expr+ = (tvs, ids, body)+ where+ (tvs, body1) = collectTyBinders expr+ (ids, body) = collectValBinders body1++collectNBinders orig_n orig_expr+ = go orig_n [] orig_expr+ where+ go 0 bs expr = (reverse bs, expr)+ go n bs (Lam b e) = go (n-1) (b:bs) e+ go _ _ _ = pprPanic "collectNBinders" $ int orig_n++-- | Takes a nested application expression and returns the the function+-- being applied and the arguments to which it is applied+collectArgs :: Expr b -> (Expr b, [Arg b])+collectArgs expr+ = go expr []+ where+ go (App f a) as = go f (a:as)+ go e as = (e, as)++-- | Like @collectArgs@, but also collects looks through floatable+-- ticks if it means that we can find more arguments.+collectArgsTicks :: (Tickish Id -> Bool) -> Expr b+ -> (Expr b, [Arg b], [Tickish Id])+collectArgsTicks skipTick expr+ = go expr [] []+ where+ go (App f a) as ts = go f (a:as) ts+ go (Tick t e) as ts+ | skipTick t = go e as (t:ts)+ go e as ts = (e, as, reverse ts)+++{-+************************************************************************+* *+\subsection{Predicates}+* *+************************************************************************++At one time we optionally carried type arguments through to runtime.+@isRuntimeVar v@ returns if (Lam v _) really becomes a lambda at runtime,+i.e. if type applications are actual lambdas because types are kept around+at runtime. Similarly isRuntimeArg.+-}++-- | Will this variable exist at runtime?+isRuntimeVar :: Var -> Bool+isRuntimeVar = isId++-- | Will this argument expression exist at runtime?+isRuntimeArg :: CoreExpr -> Bool+isRuntimeArg = isValArg++-- | Returns @True@ for value arguments, false for type args+-- NB: coercions are value arguments (zero width, to be sure,+-- like State#, but still value args).+isValArg :: Expr b -> Bool+isValArg e = not (isTypeArg e)++-- | Returns @True@ iff the expression is a 'Type' or 'Coercion'+-- expression at its top level+isTyCoArg :: Expr b -> Bool+isTyCoArg (Type {}) = True+isTyCoArg (Coercion {}) = True+isTyCoArg _ = False++-- | Returns @True@ iff the expression is a 'Type' expression at its+-- top level. Note this does NOT include 'Coercion's.+isTypeArg :: Expr b -> Bool+isTypeArg (Type {}) = True+isTypeArg _ = False++-- | The number of binders that bind values rather than types+valBndrCount :: [CoreBndr] -> Int+valBndrCount = count isId++-- | The number of argument expressions that are values rather than types at their top level+valArgCount :: [Arg b] -> Int+valArgCount = count isValArg++{-+************************************************************************+* *+\subsection{Annotated core}+* *+************************************************************************+-}++-- | Annotated core: allows annotation at every node in the tree+type AnnExpr bndr annot = (annot, AnnExpr' bndr annot)++-- | A clone of the 'Expr' type but allowing annotation at every tree node+data AnnExpr' bndr annot+ = AnnVar Id+ | AnnLit Literal+ | AnnLam bndr (AnnExpr bndr annot)+ | AnnApp (AnnExpr bndr annot) (AnnExpr bndr annot)+ | AnnCase (AnnExpr bndr annot) bndr Type [AnnAlt bndr annot]+ | AnnLet (AnnBind bndr annot) (AnnExpr bndr annot)+ | AnnCast (AnnExpr bndr annot) (annot, Coercion)+ -- Put an annotation on the (root of) the coercion+ | AnnTick (Tickish Id) (AnnExpr bndr annot)+ | AnnType Type+ | AnnCoercion Coercion++-- | A clone of the 'Alt' type but allowing annotation at every tree node+type AnnAlt bndr annot = (AltCon, [bndr], AnnExpr bndr annot)++-- | A clone of the 'Bind' type but allowing annotation at every tree node+data AnnBind bndr annot+ = AnnNonRec bndr (AnnExpr bndr annot)+ | AnnRec [(bndr, AnnExpr bndr annot)]++-- | Takes a nested application expression and returns the the function+-- being applied and the arguments to which it is applied+collectAnnArgs :: AnnExpr b a -> (AnnExpr b a, [AnnExpr b a])+collectAnnArgs expr+ = go expr []+ where+ go (_, AnnApp f a) as = go f (a:as)+ go e as = (e, as)++collectAnnArgsTicks :: (Tickish Var -> Bool) -> AnnExpr b a+ -> (AnnExpr b a, [AnnExpr b a], [Tickish Var])+collectAnnArgsTicks tickishOk expr+ = go expr [] []+ where+ go (_, AnnApp f a) as ts = go f (a:as) ts+ go (_, AnnTick t e) as ts | tickishOk t+ = go e as (t:ts)+ go e as ts = (e, as, reverse ts)++deAnnotate :: AnnExpr bndr annot -> Expr bndr+deAnnotate (_, e) = deAnnotate' e++deAnnotate' :: AnnExpr' bndr annot -> Expr bndr+deAnnotate' (AnnType t) = Type t+deAnnotate' (AnnCoercion co) = Coercion co+deAnnotate' (AnnVar v) = Var v+deAnnotate' (AnnLit lit) = Lit lit+deAnnotate' (AnnLam binder body) = Lam binder (deAnnotate body)+deAnnotate' (AnnApp fun arg) = App (deAnnotate fun) (deAnnotate arg)+deAnnotate' (AnnCast e (_,co)) = Cast (deAnnotate e) co+deAnnotate' (AnnTick tick body) = Tick tick (deAnnotate body)++deAnnotate' (AnnLet bind body)+ = Let (deAnnBind bind) (deAnnotate body)+ where+ deAnnBind (AnnNonRec var rhs) = NonRec var (deAnnotate rhs)+ deAnnBind (AnnRec pairs) = Rec [(v,deAnnotate rhs) | (v,rhs) <- pairs]++deAnnotate' (AnnCase scrut v t alts)+ = Case (deAnnotate scrut) v t (map deAnnAlt alts)++deAnnAlt :: AnnAlt bndr annot -> Alt bndr+deAnnAlt (con,args,rhs) = (con,args,deAnnotate rhs)++-- | As 'collectBinders' but for 'AnnExpr' rather than 'Expr'+collectAnnBndrs :: AnnExpr bndr annot -> ([bndr], AnnExpr bndr annot)+collectAnnBndrs e+ = collect [] e+ where+ collect bs (_, AnnLam b body) = collect (b:bs) body+ collect bs body = (reverse bs, body)++-- | As 'collectNBinders' but for 'AnnExpr' rather than 'Expr'+collectNAnnBndrs :: Int -> AnnExpr bndr annot -> ([bndr], AnnExpr bndr annot)+collectNAnnBndrs orig_n e+ = collect orig_n [] e+ where+ collect 0 bs body = (reverse bs, body)+ collect n bs (_, AnnLam b body) = collect (n-1) (b:bs) body+ collect _ _ _ = pprPanic "collectNBinders" $ int orig_n
+ coreSyn/CoreTidy.hs view
@@ -0,0 +1,287 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1996-1998+++This module contains "tidying" code for *nested* expressions, bindings, rules.+The code for *top-level* bindings is in TidyPgm.+-}++{-# LANGUAGE CPP #-}+module CoreTidy (+ tidyExpr, tidyVarOcc, tidyRule, tidyRules, tidyUnfolding+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreUnfold ( mkCoreUnfolding )+import CoreArity+import Id+import IdInfo+import Demand ( zapUsageEnvSig )+import Type( tidyType, tidyTyCoVarBndr )+import Coercion( tidyCo )+import Var+import VarEnv+import UniqFM+import Name hiding (tidyNameOcc)+import SrcLoc+import Maybes+import Data.List++{-+************************************************************************+* *+\subsection{Tidying expressions, rules}+* *+************************************************************************+-}++tidyBind :: TidyEnv+ -> CoreBind+ -> (TidyEnv, CoreBind)++tidyBind env (NonRec bndr rhs)+ = tidyLetBndr env env (bndr,rhs) =: \ (env', bndr') ->+ (env', NonRec bndr' (tidyExpr env' rhs))++tidyBind env (Rec prs)+ = let+ (env', bndrs') = mapAccumL (tidyLetBndr env') env prs+ in+ map (tidyExpr env') (map snd prs) =: \ rhss' ->+ (env', Rec (zip bndrs' rhss'))+++------------ Expressions --------------+tidyExpr :: TidyEnv -> CoreExpr -> CoreExpr+tidyExpr env (Var v) = Var (tidyVarOcc env v)+tidyExpr env (Type ty) = Type (tidyType env ty)+tidyExpr env (Coercion co) = Coercion (tidyCo env co)+tidyExpr _ (Lit lit) = Lit lit+tidyExpr env (App f a) = App (tidyExpr env f) (tidyExpr env a)+tidyExpr env (Tick t e) = Tick (tidyTickish env t) (tidyExpr env e)+tidyExpr env (Cast e co) = Cast (tidyExpr env e) (tidyCo env co)++tidyExpr env (Let b e)+ = tidyBind env b =: \ (env', b') ->+ Let b' (tidyExpr env' e)++tidyExpr env (Case e b ty alts)+ = tidyBndr env b =: \ (env', b) ->+ Case (tidyExpr env e) b (tidyType env ty)+ (map (tidyAlt env') alts)++tidyExpr env (Lam b e)+ = tidyBndr env b =: \ (env', b) ->+ Lam b (tidyExpr env' e)++------------ Case alternatives --------------+tidyAlt :: TidyEnv -> CoreAlt -> CoreAlt+tidyAlt env (con, vs, rhs)+ = tidyBndrs env vs =: \ (env', vs) ->+ (con, vs, tidyExpr env' rhs)++------------ Tickish --------------+tidyTickish :: TidyEnv -> Tickish Id -> Tickish Id+tidyTickish env (Breakpoint ix ids) = Breakpoint ix (map (tidyVarOcc env) ids)+tidyTickish _ other_tickish = other_tickish++------------ Rules --------------+tidyRules :: TidyEnv -> [CoreRule] -> [CoreRule]+tidyRules _ [] = []+tidyRules env (rule : rules)+ = tidyRule env rule =: \ rule ->+ tidyRules env rules =: \ rules ->+ (rule : rules)++tidyRule :: TidyEnv -> CoreRule -> CoreRule+tidyRule _ rule@(BuiltinRule {}) = rule+tidyRule env rule@(Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs,+ ru_fn = fn, ru_rough = mb_ns })+ = tidyBndrs env bndrs =: \ (env', bndrs) ->+ map (tidyExpr env') args =: \ args ->+ rule { ru_bndrs = bndrs, ru_args = args,+ ru_rhs = tidyExpr env' rhs,+ ru_fn = tidyNameOcc env fn,+ ru_rough = map (fmap (tidyNameOcc env')) mb_ns }++{-+************************************************************************+* *+\subsection{Tidying non-top-level binders}+* *+************************************************************************+-}++tidyNameOcc :: TidyEnv -> Name -> Name+-- In rules and instances, we have Names, and we must tidy them too+-- Fortunately, we can lookup in the VarEnv with a name+tidyNameOcc (_, var_env) n = case lookupUFM var_env n of+ Nothing -> n+ Just v -> idName v++tidyVarOcc :: TidyEnv -> Var -> Var+tidyVarOcc (_, var_env) v = lookupVarEnv var_env v `orElse` v++-- tidyBndr is used for lambda and case binders+tidyBndr :: TidyEnv -> Var -> (TidyEnv, Var)+tidyBndr env var+ | isTyCoVar var = tidyTyCoVarBndr env var+ | otherwise = tidyIdBndr env var++tidyBndrs :: TidyEnv -> [Var] -> (TidyEnv, [Var])+tidyBndrs env vars = mapAccumL tidyBndr env vars++-- Non-top-level variables, not covars+tidyIdBndr :: TidyEnv -> Id -> (TidyEnv, Id)+tidyIdBndr env@(tidy_env, var_env) id+ = -- Do this pattern match strictly, otherwise we end up holding on to+ -- stuff in the OccName.+ case tidyOccName tidy_env (getOccName id) of { (tidy_env', occ') ->+ let+ -- Give the Id a fresh print-name, *and* rename its type+ -- The SrcLoc isn't important now,+ -- though we could extract it from the Id+ --+ ty' = tidyType env (idType id)+ name' = mkInternalName (idUnique id) occ' noSrcSpan+ id' = mkLocalIdWithInfo name' ty' new_info+ var_env' = extendVarEnv var_env id id'++ -- Note [Tidy IdInfo]+ new_info = vanillaIdInfo `setOccInfo` occInfo old_info+ `setUnfoldingInfo` new_unf+ -- see Note [Preserve OneShotInfo]+ `setOneShotInfo` oneShotInfo old_info+ old_info = idInfo id+ old_unf = unfoldingInfo old_info+ new_unf | isEvaldUnfolding old_unf = evaldUnfolding+ | otherwise = noUnfolding+ -- See Note [Preserve evaluatedness]+ in+ ((tidy_env', var_env'), id')+ }++tidyLetBndr :: TidyEnv -- Knot-tied version for unfoldings+ -> TidyEnv -- The one to extend+ -> (Id, CoreExpr) -> (TidyEnv, Var)+-- Used for local (non-top-level) let(rec)s+-- Just like tidyIdBndr above, but with more IdInfo+tidyLetBndr rec_tidy_env env@(tidy_env, var_env) (id,rhs)+ = case tidyOccName tidy_env (getOccName id) of { (tidy_env', occ') ->+ let+ ty' = tidyType env (idType id)+ name' = mkInternalName (idUnique id) occ' noSrcSpan+ details = idDetails id+ id' = mkLocalVar details name' ty' new_info+ var_env' = extendVarEnv var_env id id'++ -- Note [Tidy IdInfo]+ -- We need to keep around any interesting strictness and+ -- demand info because later on we may need to use it when+ -- converting to A-normal form.+ -- eg.+ -- f (g x), where f is strict in its argument, will be converted+ -- into case (g x) of z -> f z by CorePrep, but only if f still+ -- has its strictness info.+ --+ -- Similarly for the demand info - on a let binder, this tells+ -- CorePrep to turn the let into a case.+ -- But: Remove the usage demand here+ -- (See Note [Zapping DmdEnv after Demand Analyzer] in WorkWrap)+ --+ -- Similarly arity info for eta expansion in CorePrep+ --+ -- Set inline-prag info so that we preseve it across+ -- separate compilation boundaries+ old_info = idInfo id+ new_info = vanillaIdInfo+ `setOccInfo` occInfo old_info+ `setArityInfo` exprArity rhs+ `setStrictnessInfo` zapUsageEnvSig (strictnessInfo old_info)+ `setDemandInfo` demandInfo old_info+ `setInlinePragInfo` inlinePragInfo old_info+ `setUnfoldingInfo` new_unf++ new_unf | isStableUnfolding old_unf = tidyUnfolding rec_tidy_env old_unf old_unf+ | isEvaldUnfolding old_unf = evaldUnfolding+ -- See Note [Preserve evaluatedness]+ | otherwise = noUnfolding+ old_unf = unfoldingInfo old_info+ in+ ((tidy_env', var_env'), id') }++------------ Unfolding --------------+tidyUnfolding :: TidyEnv -> Unfolding -> Unfolding -> Unfolding+tidyUnfolding tidy_env df@(DFunUnfolding { df_bndrs = bndrs, df_args = args }) _+ = df { df_bndrs = bndrs', df_args = map (tidyExpr tidy_env') args }+ where+ (tidy_env', bndrs') = tidyBndrs tidy_env bndrs++tidyUnfolding tidy_env+ (CoreUnfolding { uf_tmpl = unf_rhs, uf_is_top = top_lvl+ , uf_src = src, uf_guidance = guidance })+ unf_from_rhs+ | isStableSource src+ = mkCoreUnfolding src top_lvl (tidyExpr tidy_env unf_rhs) guidance+ -- Preserves OccInfo++ -- Note that uf_is_value and friends may be a thunk containing a reference+ -- to the old template. Consequently it is important that we rebuild them,+ -- despite the fact that they won't change, to avoid a space leak (since,+ -- e.g., ToIface doesn't look at them; see #13564). This is the same+ -- approach we use in Simplify.simplUnfolding and TcIface.tcUnfolding.++ | otherwise+ = unf_from_rhs+tidyUnfolding _ unf _ = unf -- NoUnfolding or OtherCon++{-+Note [Tidy IdInfo]+~~~~~~~~~~~~~~~~~~+All nested Ids now have the same IdInfo, namely vanillaIdInfo, which+should save some space; except that we preserve occurrence info for+two reasons:++ (a) To make printing tidy core nicer++ (b) Because we tidy RULES and InlineRules, which may then propagate+ via --make into the compilation of the next module, and we want+ the benefit of that occurrence analysis when we use the rule or+ or inline the function. In particular, it's vital not to lose+ loop-breaker info, else we get an infinite inlining loop++Note that tidyLetBndr puts more IdInfo back.++Note [Preserve evaluatedness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T = MkT !Bool+ ....(case v of MkT y ->+ let z# = case y of+ True -> 1#+ False -> 2#+ in ...)++The z# binding is ok because the RHS is ok-for-speculation,+but Lint will complain unless it can *see* that. So we+preserve the evaluated-ness on 'y' in tidyBndr.++(Another alternative would be to tidy unboxed lets into cases,+but that seems more indirect and surprising.)++Note [Preserve OneShotInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We keep the OneShotInfo because we want it to propagate into the interface.+Not all OneShotInfo is determined by a compiler analysis; some is added by a+call of GHC.Exts.oneShot, which is then discarded before the end of the+optimisation pipeline, leaving only the OneShotInfo on the lambda. Hence we+must preserve this info in inlinings. See Note [The oneShot function] in MkId.++This applies to lambda binders only, hence it is stored in IfaceLamBndr.+-}++(=:) :: a -> (a -> b) -> b+m =: k = m `seq` k m
+ coreSyn/CoreUnfold.hs view
@@ -0,0 +1,1492 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1994-1998+++Core-syntax unfoldings++Unfoldings (which can travel across module boundaries) are in Core+syntax (namely @CoreExpr@s).++The type @Unfolding@ sits ``above'' simply-Core-expressions+unfoldings, capturing ``higher-level'' things we know about a binding,+usually things that the simplifier found out (e.g., ``it's a+literal''). In the corner of a @CoreUnfolding@ unfolding, you will+find, unsurprisingly, a Core expression.+-}++{-# LANGUAGE CPP #-}++module CoreUnfold (+ Unfolding, UnfoldingGuidance, -- Abstract types++ noUnfolding, mkImplicitUnfolding,+ mkUnfolding, mkCoreUnfolding,+ mkTopUnfolding, mkSimpleUnfolding, mkWorkerUnfolding,+ mkInlineUnfolding, mkInlineUnfoldingWithArity,+ mkInlinableUnfolding, mkWwInlineRule,+ mkCompulsoryUnfolding, mkDFunUnfolding,+ specUnfolding,++ ArgSummary(..),++ couldBeSmallEnoughToInline, inlineBoringOk,+ certainlyWillInline, smallEnoughToInline,++ callSiteInline, CallCtxt(..),++ -- Reexport from CoreSubst (it only live there so it can be used+ -- by the Very Simple Optimiser)+ exprIsConApp_maybe, exprIsLiteral_maybe+ ) where++#include "HsVersions.h"++import DynFlags+import CoreSyn+import PprCore () -- Instances+import OccurAnal ( occurAnalyseExpr )+import CoreOpt+import CoreArity ( manifestArity )+import CoreUtils+import Id+import Demand ( isBottomingSig )+import DataCon+import Literal+import PrimOp+import IdInfo+import BasicTypes ( Arity, InlineSpec(..), inlinePragmaSpec )+import Type+import PrelNames+import TysPrim ( realWorldStatePrimTy )+import Bag+import Util+import Outputable+import ForeignCall++import qualified Data.ByteString as BS++{-+************************************************************************+* *+\subsection{Making unfoldings}+* *+************************************************************************+-}++mkTopUnfolding :: DynFlags -> Bool -> CoreExpr -> Unfolding+mkTopUnfolding dflags is_bottoming rhs+ = mkUnfolding dflags InlineRhs True is_bottoming rhs++mkImplicitUnfolding :: DynFlags -> CoreExpr -> Unfolding+-- For implicit Ids, do a tiny bit of optimising first+mkImplicitUnfolding dflags expr+ = mkTopUnfolding dflags False (simpleOptExpr expr)++-- Note [Top-level flag on inline rules]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Slight hack: note that mk_inline_rules conservatively sets the+-- top-level flag to True. It gets set more accurately by the simplifier+-- Simplify.simplUnfolding.++mkSimpleUnfolding :: DynFlags -> CoreExpr -> Unfolding+mkSimpleUnfolding dflags rhs+ = mkUnfolding dflags InlineRhs False False rhs++mkDFunUnfolding :: [Var] -> DataCon -> [CoreExpr] -> Unfolding+mkDFunUnfolding bndrs con ops+ = DFunUnfolding { df_bndrs = bndrs+ , df_con = con+ , df_args = map occurAnalyseExpr ops }+ -- See Note [Occurrence analysis of unfoldings]++mkWwInlineRule :: CoreExpr -> Arity -> Unfolding+mkWwInlineRule expr arity+ = mkCoreUnfolding InlineStable True+ (simpleOptExpr expr)+ (UnfWhen { ug_arity = arity, ug_unsat_ok = unSaturatedOk+ , ug_boring_ok = boringCxtNotOk })++mkCompulsoryUnfolding :: CoreExpr -> Unfolding+mkCompulsoryUnfolding expr -- Used for things that absolutely must be unfolded+ = mkCoreUnfolding InlineCompulsory True+ (simpleOptExpr expr)+ (UnfWhen { ug_arity = 0 -- Arity of unfolding doesn't matter+ , ug_unsat_ok = unSaturatedOk, ug_boring_ok = boringCxtOk })++mkWorkerUnfolding :: DynFlags -> (CoreExpr -> CoreExpr) -> Unfolding -> Unfolding+-- See Note [Worker-wrapper for INLINABLE functions] in WorkWrap+mkWorkerUnfolding dflags work_fn+ (CoreUnfolding { uf_src = src, uf_tmpl = tmpl+ , uf_is_top = top_lvl })+ | isStableSource src+ = mkCoreUnfolding src top_lvl new_tmpl guidance+ where+ new_tmpl = simpleOptExpr (work_fn tmpl)+ guidance = calcUnfoldingGuidance dflags False new_tmpl++mkWorkerUnfolding _ _ _ = noUnfolding++-- | Make an unfolding that may be used unsaturated+-- (ug_unsat_ok = unSaturatedOk) and that is reported as having its+-- manifest arity (the number of outer lambdas applications will+-- resolve before doing any work).+mkInlineUnfolding :: CoreExpr -> Unfolding+mkInlineUnfolding expr+ = mkCoreUnfolding InlineStable+ True -- Note [Top-level flag on inline rules]+ expr' guide+ where+ expr' = simpleOptExpr expr+ guide = UnfWhen { ug_arity = manifestArity expr'+ , ug_unsat_ok = unSaturatedOk+ , ug_boring_ok = boring_ok }+ boring_ok = inlineBoringOk expr'++-- | Make an unfolding that will be used once the RHS has been saturated+-- to the given arity.+mkInlineUnfoldingWithArity :: Arity -> CoreExpr -> Unfolding+mkInlineUnfoldingWithArity arity expr+ = mkCoreUnfolding InlineStable+ True -- Note [Top-level flag on inline rules]+ expr' guide+ where+ expr' = simpleOptExpr expr+ guide = UnfWhen { ug_arity = arity+ , ug_unsat_ok = needSaturated+ , ug_boring_ok = boring_ok }+ boring_ok = inlineBoringOk expr'++mkInlinableUnfolding :: DynFlags -> CoreExpr -> Unfolding+mkInlinableUnfolding dflags expr+ = mkUnfolding dflags InlineStable False False expr'+ where+ expr' = simpleOptExpr expr++specUnfolding :: [Var] -> (CoreExpr -> CoreExpr) -> Arity -> Unfolding -> Unfolding+-- See Note [Specialising unfoldings]+-- specUnfolding spec_bndrs spec_app arity_decrease unf+-- = \spec_bndrs. spec_app( unf )+--+specUnfolding spec_bndrs spec_app arity_decrease+ df@(DFunUnfolding { df_bndrs = old_bndrs, df_con = con, df_args = args })+ = ASSERT2( arity_decrease == count isId old_bndrs - count isId spec_bndrs, ppr df )+ mkDFunUnfolding spec_bndrs con (map spec_arg args)+ -- There is a hard-to-check assumption here that the spec_app has+ -- enough applications to exactly saturate the old_bndrs+ -- For DFunUnfoldings we transform+ -- \old_bndrs. MkD <op1> ... <opn>+ -- to+ -- \new_bndrs. MkD (spec_app(\old_bndrs. <op1>)) ... ditto <opn>+ -- The ASSERT checks the value part of that+ where+ spec_arg arg = simpleOptExpr (spec_app (mkLams old_bndrs arg))+ -- The beta-redexes created by spec_app will be+ -- simplified away by simplOptExpr++specUnfolding spec_bndrs spec_app arity_decrease+ (CoreUnfolding { uf_src = src, uf_tmpl = tmpl+ , uf_is_top = top_lvl+ , uf_guidance = old_guidance })+ | isStableSource src -- See Note [Specialising unfoldings]+ , UnfWhen { ug_arity = old_arity+ , ug_unsat_ok = unsat_ok+ , ug_boring_ok = boring_ok } <- old_guidance+ = let guidance = UnfWhen { ug_arity = old_arity - arity_decrease+ , ug_unsat_ok = unsat_ok+ , ug_boring_ok = boring_ok }+ new_tmpl = simpleOptExpr (mkLams spec_bndrs (spec_app tmpl))+ -- The beta-redexes created by spec_app will be+ -- simplified away by simplOptExpr++ in mkCoreUnfolding src top_lvl new_tmpl guidance++specUnfolding _ _ _ _ = noUnfolding++{- Note [Specialising unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we specialise a function for some given type-class arguments, we use+specUnfolding to specialise its unfolding. Some important points:++* If the original function has a DFunUnfolding, the specialised one+ must do so too! Otherwise we lose the magic rules that make it+ interact with ClassOps++* There is a bit of hack for INLINABLE functions:+ f :: Ord a => ....+ f = <big-rhs>+ {- INLINABLE f #-}+ Now if we specialise f, should the specialised version still have+ an INLINABLE pragma? If it does, we'll capture a specialised copy+ of <big-rhs> as its unfolding, and that probaby won't inline. But+ if we don't, the specialised version of <big-rhs> might be small+ enough to inline at a call site. This happens with Control.Monad.liftM3,+ and can cause a lot more allocation as a result (nofib n-body shows this).++ Moreover, keeping the INLINABLE thing isn't much help, because+ the specialised function (probaby) isn't overloaded any more.++ Conclusion: drop the INLINEALE pragma. In practice what this means is:+ if a stable unfolding has UnfoldingGuidance of UnfWhen,+ we keep it (so the specialised thing too will always inline)+ if a stable unfolding has UnfoldingGuidance of UnfIfGoodArgs+ (which arises from INLINABLE), we discard it+-}++mkCoreUnfolding :: UnfoldingSource -> Bool -> CoreExpr+ -> UnfoldingGuidance -> Unfolding+-- Occurrence-analyses the expression before capturing it+mkCoreUnfolding src top_lvl expr guidance+ = CoreUnfolding { uf_tmpl = occurAnalyseExpr expr,+ -- See Note [Occurrence analysis of unfoldings]+ uf_src = src,+ uf_is_top = top_lvl,+ uf_is_value = exprIsHNF expr,+ uf_is_conlike = exprIsConLike expr,+ uf_is_work_free = exprIsWorkFree expr,+ uf_expandable = exprIsExpandable expr,+ uf_guidance = guidance }++mkUnfolding :: DynFlags -> UnfoldingSource+ -> Bool -- Is top-level+ -> Bool -- Definitely a bottoming binding+ -- (only relevant for top-level bindings)+ -> CoreExpr+ -> Unfolding+-- Calculates unfolding guidance+-- Occurrence-analyses the expression before capturing it+mkUnfolding dflags src is_top_lvl is_bottoming expr+ = CoreUnfolding { uf_tmpl = occurAnalyseExpr expr,+ -- See Note [Occurrence analysis of unfoldings]+ uf_src = src,+ uf_is_top = is_top_lvl,+ uf_is_value = exprIsHNF expr,+ uf_is_conlike = exprIsConLike expr,+ uf_expandable = exprIsExpandable expr,+ uf_is_work_free = exprIsWorkFree expr,+ uf_guidance = guidance }+ where+ is_top_bottoming = is_top_lvl && is_bottoming+ guidance = calcUnfoldingGuidance dflags is_top_bottoming expr+ -- NB: *not* (calcUnfoldingGuidance (occurAnalyseExpr expr))!+ -- See Note [Calculate unfolding guidance on the non-occ-anal'd expression]++{-+Note [Occurrence analysis of unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do occurrence-analysis of unfoldings once and for all, when the+unfolding is built, rather than each time we inline them.++But given this decision it's vital that we do+*always* do it. Consider this unfolding+ \x -> letrec { f = ...g...; g* = f } in body+where g* is (for some strange reason) the loop breaker. If we don't+occ-anal it when reading it in, we won't mark g as a loop breaker, and+we may inline g entirely in body, dropping its binding, and leaving+the occurrence in f out of scope. This happened in Trac #8892, where+the unfolding in question was a DFun unfolding.++But more generally, the simplifier is designed on the+basis that it is looking at occurrence-analysed expressions, so better+ensure that they acutally are.++Note [Calculate unfolding guidance on the non-occ-anal'd expression]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Notice that we give the non-occur-analysed expression to+calcUnfoldingGuidance. In some ways it'd be better to occur-analyse+first; for example, sometimes during simplification, there's a large+let-bound thing which has been substituted, and so is now dead; so+'expr' contains two copies of the thing while the occurrence-analysed+expression doesn't.++Nevertheless, we *don't* and *must not* occ-analyse before computing+the size because++a) The size computation bales out after a while, whereas occurrence+ analysis does not.++b) Residency increases sharply if you occ-anal first. I'm not+ 100% sure why, but it's a large effect. Compiling Cabal went+ from residency of 534M to over 800M with this one change.++This can occasionally mean that the guidance is very pessimistic;+it gets fixed up next round. And it should be rare, because large+let-bound things that are dead are usually caught by preInlineUnconditionally+++************************************************************************+* *+\subsection{The UnfoldingGuidance type}+* *+************************************************************************+-}++inlineBoringOk :: CoreExpr -> Bool+-- See Note [INLINE for small functions]+-- True => the result of inlining the expression is+-- no bigger than the expression itself+-- eg (\x y -> f y x)+-- This is a quick and dirty version. It doesn't attempt+-- to deal with (\x y z -> x (y z))+-- The really important one is (x `cast` c)+inlineBoringOk e+ = go 0 e+ where+ go :: Int -> CoreExpr -> Bool+ go credit (Lam x e) | isId x = go (credit+1) e+ | otherwise = go credit e+ go credit (App f (Type {})) = go credit f+ go credit (App f a) | credit > 0+ , exprIsTrivial a = go (credit-1) f+ go credit (Tick _ e) = go credit e -- dubious+ go credit (Cast e _) = go credit e+ go _ (Var {}) = boringCxtOk+ go _ _ = boringCxtNotOk++calcUnfoldingGuidance+ :: DynFlags+ -> Bool -- Definitely a top-level, bottoming binding+ -> CoreExpr -- Expression to look at+ -> UnfoldingGuidance+calcUnfoldingGuidance dflags is_top_bottoming (Tick t expr)+ | not (tickishIsCode t) -- non-code ticks don't matter for unfolding+ = calcUnfoldingGuidance dflags is_top_bottoming expr+calcUnfoldingGuidance dflags is_top_bottoming expr+ = case sizeExpr dflags bOMB_OUT_SIZE val_bndrs body of+ TooBig -> UnfNever+ SizeIs size cased_bndrs scrut_discount+ | uncondInline expr n_val_bndrs size+ -> UnfWhen { ug_unsat_ok = unSaturatedOk+ , ug_boring_ok = boringCxtOk+ , ug_arity = n_val_bndrs } -- Note [INLINE for small functions]++ | is_top_bottoming+ -> UnfNever -- See Note [Do not inline top-level bottoming functions]++ | otherwise+ -> UnfIfGoodArgs { ug_args = map (mk_discount cased_bndrs) val_bndrs+ , ug_size = size+ , ug_res = scrut_discount }++ where+ (bndrs, body) = collectBinders expr+ bOMB_OUT_SIZE = ufCreationThreshold dflags+ -- Bomb out if size gets bigger than this+ val_bndrs = filter isId bndrs+ n_val_bndrs = length val_bndrs++ mk_discount :: Bag (Id,Int) -> Id -> Int+ mk_discount cbs bndr = foldlBag combine 0 cbs+ where+ combine acc (bndr', disc)+ | bndr == bndr' = acc `plus_disc` disc+ | otherwise = acc++ plus_disc :: Int -> Int -> Int+ plus_disc | isFunTy (idType bndr) = max+ | otherwise = (+)+ -- See Note [Function and non-function discounts]++{-+Note [Computing the size of an expression]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The basic idea of sizeExpr is obvious enough: count nodes. But getting the+heuristics right has taken a long time. Here's the basic strategy:++ * Variables, literals: 0+ (Exception for string literals, see litSize.)++ * Function applications (f e1 .. en): 1 + #value args++ * Constructor applications: 1, regardless of #args++ * Let(rec): 1 + size of components++ * Note, cast: 0++Examples++ Size Term+ --------------+ 0 42#+ 0 x+ 0 True+ 2 f x+ 1 Just x+ 4 f (g x)++Notice that 'x' counts 0, while (f x) counts 2. That's deliberate: there's+a function call to account for. Notice also that constructor applications+are very cheap, because exposing them to a caller is so valuable.++[25/5/11] All sizes are now multiplied by 10, except for primops+(which have sizes like 1 or 4. This makes primops look fantastically+cheap, and seems to be almost unversally beneficial. Done partly as a+result of #4978.++Note [Do not inline top-level bottoming functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The FloatOut pass has gone to some trouble to float out calls to 'error'+and similar friends. See Note [Bottoming floats] in SetLevels.+Do not re-inline them! But we *do* still inline if they are very small+(the uncondInline stuff).++Note [INLINE for small functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider {-# INLINE f #-}+ f x = Just x+ g y = f y+Then f's RHS is no larger than its LHS, so we should inline it into+even the most boring context. In general, f the function is+sufficiently small that its body is as small as the call itself, the+inline unconditionally, regardless of how boring the context is.++Things to note:++(1) We inline *unconditionally* if inlined thing is smaller (using sizeExpr)+ than the thing it's replacing. Notice that+ (f x) --> (g 3) -- YES, unconditionally+ (f x) --> x : [] -- YES, *even though* there are two+ -- arguments to the cons+ x --> g 3 -- NO+ x --> Just v -- NO++ It's very important not to unconditionally replace a variable by+ a non-atomic term.++(2) We do this even if the thing isn't saturated, else we end up with the+ silly situation that+ f x y = x+ ...map (f 3)...+ doesn't inline. Even in a boring context, inlining without being+ saturated will give a lambda instead of a PAP, and will be more+ efficient at runtime.++(3) However, when the function's arity > 0, we do insist that it+ has at least one value argument at the call site. (This check is+ made in the UnfWhen case of callSiteInline.) Otherwise we find this:+ f = /\a \x:a. x+ d = /\b. MkD (f b)+ If we inline f here we get+ d = /\b. MkD (\x:b. x)+ and then prepareRhs floats out the argument, abstracting the type+ variables, so we end up with the original again!++(4) We must be much more cautious about arity-zero things. Consider+ let x = y +# z in ...+ In *size* terms primops look very small, because the generate a+ single instruction, but we do not want to unconditionally replace+ every occurrence of x with (y +# z). So we only do the+ unconditional-inline thing for *trivial* expressions.++ NB: you might think that PostInlineUnconditionally would do this+ but it doesn't fire for top-level things; see SimplUtils+ Note [Top level and postInlineUnconditionally]+-}++uncondInline :: CoreExpr -> Arity -> Int -> Bool+-- Inline unconditionally if there no size increase+-- Size of call is arity (+1 for the function)+-- See Note [INLINE for small functions]+uncondInline rhs arity size+ | arity > 0 = size <= 10 * (arity + 1) -- See Note [INLINE for small functions] (1)+ | otherwise = exprIsTrivial rhs -- See Note [INLINE for small functions] (4)++sizeExpr :: DynFlags+ -> Int -- Bomb out if it gets bigger than this+ -> [Id] -- Arguments; we're interested in which of these+ -- get case'd+ -> CoreExpr+ -> ExprSize++-- Note [Computing the size of an expression]++sizeExpr dflags bOMB_OUT_SIZE top_args expr+ = size_up expr+ where+ size_up (Cast e _) = size_up e+ size_up (Tick _ e) = size_up e+ size_up (Type _) = sizeZero -- Types cost nothing+ size_up (Coercion _) = sizeZero+ size_up (Lit lit) = sizeN (litSize lit)+ size_up (Var f) | isRealWorldId f = sizeZero+ -- Make sure we get constructor discounts even+ -- on nullary constructors+ | otherwise = size_up_call f [] 0++ size_up (App fun arg)+ | isTyCoArg arg = size_up fun+ | otherwise = size_up arg `addSizeNSD`+ size_up_app fun [arg] (if isRealWorldExpr arg then 1 else 0)++ size_up (Lam b e)+ | isId b && not (isRealWorldId b) = lamScrutDiscount dflags (size_up e `addSizeN` 10)+ | otherwise = size_up e++ size_up (Let (NonRec binder rhs) body)+ = size_up_rhs (binder, rhs) `addSizeNSD`+ size_up body `addSizeN`+ size_up_alloc binder++ size_up (Let (Rec pairs) body)+ = foldr (addSizeNSD . size_up_rhs)+ (size_up body `addSizeN` sum (map (size_up_alloc . fst) pairs))+ pairs++ size_up (Case e _ _ alts)+ | null alts+ = size_up e -- case e of {} never returns, so take size of scrutinee++ size_up (Case e _ _ alts)+ -- Now alts is non-empty+ | Just v <- is_top_arg e -- We are scrutinising an argument variable+ = let+ alt_sizes = map size_up_alt alts++ -- alts_size tries to compute a good discount for+ -- the case when we are scrutinising an argument variable+ alts_size (SizeIs tot tot_disc tot_scrut)+ -- Size of all alternatives+ (SizeIs max _ _)+ -- Size of biggest alternative+ = SizeIs tot (unitBag (v, 20 + tot - max)+ `unionBags` tot_disc) tot_scrut+ -- If the variable is known, we produce a+ -- discount that will take us back to 'max',+ -- the size of the largest alternative The+ -- 1+ is a little discount for reduced+ -- allocation in the caller+ --+ -- Notice though, that we return tot_disc,+ -- the total discount from all branches. I+ -- think that's right.++ alts_size tot_size _ = tot_size+ in+ alts_size (foldr1 addAltSize alt_sizes) -- alts is non-empty+ (foldr1 maxSize alt_sizes)+ -- Good to inline if an arg is scrutinised, because+ -- that may eliminate allocation in the caller+ -- And it eliminates the case itself+ where+ is_top_arg (Var v) | v `elem` top_args = Just v+ is_top_arg (Cast e _) = is_top_arg e+ is_top_arg _ = Nothing+++ size_up (Case e _ _ alts) = size_up e `addSizeNSD`+ foldr (addAltSize . size_up_alt) case_size alts+ where+ case_size+ | is_inline_scrut e, not (lengthExceeds alts 1) = sizeN (-10)+ | otherwise = sizeZero+ -- Normally we don't charge for the case itself, but+ -- we charge one per alternative (see size_up_alt,+ -- below) to account for the cost of the info table+ -- and comparisons.+ --+ -- However, in certain cases (see is_inline_scrut+ -- below), no code is generated for the case unless+ -- there are multiple alts. In these cases we+ -- subtract one, making the first alt free.+ -- e.g. case x# +# y# of _ -> ... should cost 1+ -- case touch# x# of _ -> ... should cost 0+ -- (see #4978)+ --+ -- I would like to not have the "not (lengthExceeds alts 1)"+ -- condition above, but without that some programs got worse+ -- (spectral/hartel/event and spectral/para). I don't fully+ -- understand why. (SDM 24/5/11)++ -- unboxed variables, inline primops and unsafe foreign calls+ -- are all "inline" things:+ is_inline_scrut (Var v) = isUnliftedType (idType v)+ is_inline_scrut scrut+ | (Var f, _) <- collectArgs scrut+ = case idDetails f of+ FCallId fc -> not (isSafeForeignCall fc)+ PrimOpId op -> not (primOpOutOfLine op)+ _other -> False+ | otherwise+ = False++ size_up_rhs (bndr, rhs)+ | Just join_arity <- isJoinId_maybe bndr+ -- Skip arguments to join point+ , (_bndrs, body) <- collectNBinders join_arity rhs+ = size_up body+ | otherwise+ = size_up rhs++ ------------+ -- size_up_app is used when there's ONE OR MORE value args+ size_up_app (App fun arg) args voids+ | isTyCoArg arg = size_up_app fun args voids+ | isRealWorldExpr arg = size_up_app fun (arg:args) (voids + 1)+ | otherwise = size_up arg `addSizeNSD`+ size_up_app fun (arg:args) voids+ size_up_app (Var fun) args voids = size_up_call fun args voids+ size_up_app (Tick _ expr) args voids = size_up_app expr args voids+ size_up_app (Cast expr _) args voids = size_up_app expr args voids+ size_up_app other args voids = size_up other `addSizeN`+ callSize (length args) voids+ -- if the lhs is not an App or a Var, or an invisible thing like a+ -- Tick or Cast, then we should charge for a complete call plus the+ -- size of the lhs itself.++ ------------+ size_up_call :: Id -> [CoreExpr] -> Int -> ExprSize+ size_up_call fun val_args voids+ = case idDetails fun of+ FCallId _ -> sizeN (callSize (length val_args) voids)+ DataConWorkId dc -> conSize dc (length val_args)+ PrimOpId op -> primOpSize op (length val_args)+ ClassOpId _ -> classOpSize dflags top_args val_args+ _ -> funSize dflags top_args fun (length val_args) voids++ ------------+ size_up_alt (_con, _bndrs, rhs) = size_up rhs `addSizeN` 10+ -- Don't charge for args, so that wrappers look cheap+ -- (See comments about wrappers with Case)+ --+ -- IMPORATANT: *do* charge 1 for the alternative, else we+ -- find that giant case nests are treated as practically free+ -- A good example is Foreign.C.Error.errnoToIOError++ ------------+ -- Cost to allocate binding with given binder+ size_up_alloc bndr+ | isTyVar bndr -- Doesn't exist at runtime+ || isJoinId bndr -- Not allocated at all+ || isUnliftedType (idType bndr) -- Doesn't live in heap+ = 0+ | otherwise+ = 10++ ------------+ -- These addSize things have to be here because+ -- I don't want to give them bOMB_OUT_SIZE as an argument+ addSizeN TooBig _ = TooBig+ addSizeN (SizeIs n xs d) m = mkSizeIs bOMB_OUT_SIZE (n + m) xs d++ -- addAltSize is used to add the sizes of case alternatives+ addAltSize TooBig _ = TooBig+ addAltSize _ TooBig = TooBig+ addAltSize (SizeIs n1 xs d1) (SizeIs n2 ys d2)+ = mkSizeIs bOMB_OUT_SIZE (n1 + n2)+ (xs `unionBags` ys)+ (d1 + d2) -- Note [addAltSize result discounts]++ -- This variant ignores the result discount from its LEFT argument+ -- It's used when the second argument isn't part of the result+ addSizeNSD TooBig _ = TooBig+ addSizeNSD _ TooBig = TooBig+ addSizeNSD (SizeIs n1 xs _) (SizeIs n2 ys d2)+ = mkSizeIs bOMB_OUT_SIZE (n1 + n2)+ (xs `unionBags` ys)+ d2 -- Ignore d1++ isRealWorldId id = idType id `eqType` realWorldStatePrimTy++ -- an expression of type State# RealWorld must be a variable+ isRealWorldExpr (Var id) = isRealWorldId id+ isRealWorldExpr (Tick _ e) = isRealWorldExpr e+ isRealWorldExpr _ = False++-- | Finds a nominal size of a string literal.+litSize :: Literal -> Int+-- Used by CoreUnfold.sizeExpr+litSize (LitInteger {}) = 100 -- Note [Size of literal integers]+litSize (MachStr str) = 10 + 10 * ((BS.length str + 3) `div` 4)+ -- If size could be 0 then @f "x"@ might be too small+ -- [Sept03: make literal strings a bit bigger to avoid fruitless+ -- duplication of little strings]+litSize _other = 0 -- Must match size of nullary constructors+ -- Key point: if x |-> 4, then x must inline unconditionally+ -- (eg via case binding)++classOpSize :: DynFlags -> [Id] -> [CoreExpr] -> ExprSize+-- See Note [Conlike is interesting]+classOpSize _ _ []+ = sizeZero+classOpSize dflags top_args (arg1 : other_args)+ = SizeIs size arg_discount 0+ where+ size = 20 + (10 * length other_args)+ -- If the class op is scrutinising a lambda bound dictionary then+ -- give it a discount, to encourage the inlining of this function+ -- The actual discount is rather arbitrarily chosen+ arg_discount = case arg1 of+ Var dict | dict `elem` top_args+ -> unitBag (dict, ufDictDiscount dflags)+ _other -> emptyBag++-- | The size of a function call+callSize+ :: Int -- ^ number of value args+ -> Int -- ^ number of value args that are void+ -> Int+callSize n_val_args voids = 10 * (1 + n_val_args - voids)+ -- The 1+ is for the function itself+ -- Add 1 for each non-trivial arg;+ -- the allocation cost, as in let(rec)++-- | The size of a jump to a join point+jumpSize+ :: Int -- ^ number of value args+ -> Int -- ^ number of value args that are void+ -> Int+jumpSize n_val_args voids = 2 * (1 + n_val_args - voids)+ -- A jump is 20% the size of a function call. Making jumps free reopens+ -- bug #6048, but making them any more expensive loses a 21% improvement in+ -- spectral/puzzle. TODO Perhaps adjusting the default threshold would be a+ -- better solution?++funSize :: DynFlags -> [Id] -> Id -> Int -> Int -> ExprSize+-- Size for functions that are not constructors or primops+-- Note [Function applications]+funSize dflags top_args fun n_val_args voids+ | fun `hasKey` buildIdKey = buildSize+ | fun `hasKey` augmentIdKey = augmentSize+ | otherwise = SizeIs size arg_discount res_discount+ where+ some_val_args = n_val_args > 0+ is_join = isJoinId fun++ size | is_join = jumpSize n_val_args voids+ | not some_val_args = 0+ | otherwise = callSize n_val_args voids++ -- DISCOUNTS+ -- See Note [Function and non-function discounts]+ arg_discount | some_val_args && fun `elem` top_args+ = unitBag (fun, ufFunAppDiscount dflags)+ | otherwise = emptyBag+ -- If the function is an argument and is applied+ -- to some values, give it an arg-discount++ res_discount | idArity fun > n_val_args = ufFunAppDiscount dflags+ | otherwise = 0+ -- If the function is partially applied, show a result discount+-- XXX maybe behave like ConSize for eval'd variable++conSize :: DataCon -> Int -> ExprSize+conSize dc n_val_args+ | n_val_args == 0 = SizeIs 0 emptyBag 10 -- Like variables++-- See Note [Unboxed tuple size and result discount]+ | isUnboxedTupleCon dc = SizeIs 0 emptyBag (10 * (1 + n_val_args))++-- See Note [Constructor size and result discount]+ | otherwise = SizeIs 10 emptyBag (10 * (1 + n_val_args))++-- XXX still looks to large to me++{-+Note [Constructor size and result discount]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Treat a constructors application as size 10, regardless of how many+arguments it has; we are keen to expose them (and we charge separately+for their args). We can't treat them as size zero, else we find that+(Just x) has size 0, which is the same as a lone variable; and hence+'v' will always be replaced by (Just x), where v is bound to Just x.++The "result discount" is applied if the result of the call is+scrutinised (say by a case). For a constructor application that will+mean the constructor application will disappear, so we don't need to+charge it to the function. So the discount should at least match the+cost of the constructor application, namely 10. But to give a bit+of extra incentive we give a discount of 10*(1 + n_val_args).++Simon M tried a MUCH bigger discount: (10 * (10 + n_val_args)),+and said it was an "unambiguous win", but its terribly dangerous+because a function with many many case branches, each finishing with+a constructor, can have an arbitrarily large discount. This led to+terrible code bloat: see Trac #6099.++Note [Unboxed tuple size and result discount]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+However, unboxed tuples count as size zero. I found occasions where we had+ f x y z = case op# x y z of { s -> (# s, () #) }+and f wasn't getting inlined.++I tried giving unboxed tuples a *result discount* of zero (see the+commented-out line). Why? When returned as a result they do not+allocate, so maybe we don't want to charge so much for them If you+have a non-zero discount here, we find that workers often get inlined+back into wrappers, because it look like+ f x = case $wf x of (# a,b #) -> (a,b)+and we are keener because of the case. However while this change+shrank binary sizes by 0.5% it also made spectral/boyer allocate 5%+more. All other changes were very small. So it's not a big deal but I+didn't adopt the idea.++Note [Function and non-function discounts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want a discount if the function is applied. A good example is+monadic combinators with continuation arguments, where inlining is+quite important.++But we don't want a big discount when a function is called many times+(see the detailed comments with Trac #6048) because if the function is+big it won't be inlined at its many call sites and no benefit results.+Indeed, we can get exponentially big inlinings this way; that is what+Trac #6048 is about.++On the other hand, for data-valued arguments, if there are lots of+case expressions in the body, each one will get smaller if we apply+the function to a constructor application, so we *want* a big discount+if the argument is scrutinised by many case expressions.++Conclusion:+ - For functions, take the max of the discounts+ - For data values, take the sum of the discounts+++Note [Literal integer size]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Literal integers *can* be big (mkInteger [...coefficients...]), but+need not be (S# n). We just use an arbitrary big-ish constant here+so that, in particular, we don't inline top-level defns like+ n = S# 5+There's no point in doing so -- any optimisations will see the S#+through n's unfolding. Nor will a big size inhibit unfoldings functions+that mention a literal Integer, because the float-out pass will float+all those constants to top level.+-}++primOpSize :: PrimOp -> Int -> ExprSize+primOpSize op n_val_args+ = if primOpOutOfLine op+ then sizeN (op_size + n_val_args)+ else sizeN op_size+ where+ op_size = primOpCodeSize op+++buildSize :: ExprSize+buildSize = SizeIs 0 emptyBag 40+ -- We really want to inline applications of build+ -- build t (\cn -> e) should cost only the cost of e (because build will be inlined later)+ -- Indeed, we should add a result_discount because build is+ -- very like a constructor. We don't bother to check that the+ -- build is saturated (it usually is). The "-2" discounts for the \c n,+ -- The "4" is rather arbitrary.++augmentSize :: ExprSize+augmentSize = SizeIs 0 emptyBag 40+ -- Ditto (augment t (\cn -> e) ys) should cost only the cost of+ -- e plus ys. The -2 accounts for the \cn++-- When we return a lambda, give a discount if it's used (applied)+lamScrutDiscount :: DynFlags -> ExprSize -> ExprSize+lamScrutDiscount dflags (SizeIs n vs _) = SizeIs n vs (ufFunAppDiscount dflags)+lamScrutDiscount _ TooBig = TooBig++{-+Note [addAltSize result discounts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When adding the size of alternatives, we *add* the result discounts+too, rather than take the *maximum*. For a multi-branch case, this+gives a discount for each branch that returns a constructor, making us+keener to inline. I did try using 'max' instead, but it makes nofib+'rewrite' and 'puzzle' allocate significantly more, and didn't make+binary sizes shrink significantly either.++Note [Discounts and thresholds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Constants for discounts and thesholds are defined in main/DynFlags,+all of form ufXxxx. They are:++ufCreationThreshold+ At a definition site, if the unfolding is bigger than this, we+ may discard it altogether++ufUseThreshold+ At a call site, if the unfolding, less discounts, is smaller than+ this, then it's small enough inline++ufKeenessFactor+ Factor by which the discounts are multiplied before+ subtracting from size++ufDictDiscount+ The discount for each occurrence of a dictionary argument+ as an argument of a class method. Should be pretty small+ else big functions may get inlined++ufFunAppDiscount+ Discount for a function argument that is applied. Quite+ large, because if we inline we avoid the higher-order call.++ufDearOp+ The size of a foreign call or not-dupable PrimOp++ufVeryAggressive+ If True, the compiler ignores all the thresholds and inlines very+ aggressively. It still adheres to arity, simplifier phase control and+ loop breakers.+++Note [Function applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a function application (f a b)++ - If 'f' is an argument to the function being analysed,+ and there's at least one value arg, record a FunAppDiscount for f++ - If the application if a PAP (arity > 2 in this example)+ record a *result* discount (because inlining+ with "extra" args in the call may mean that we now+ get a saturated application)++Code for manipulating sizes+-}++-- | The size of an candidate expression for unfolding+data ExprSize+ = TooBig+ | SizeIs { _es_size_is :: {-# UNPACK #-} !Int -- ^ Size found+ , _es_args :: !(Bag (Id,Int))+ -- ^ Arguments cased herein, and discount for each such+ , _es_discount :: {-# UNPACK #-} !Int+ -- ^ Size to subtract if result is scrutinised by a case+ -- expression+ }++instance Outputable ExprSize where+ ppr TooBig = text "TooBig"+ ppr (SizeIs a _ c) = brackets (int a <+> int c)++-- subtract the discount before deciding whether to bale out. eg. we+-- want to inline a large constructor application into a selector:+-- tup = (a_1, ..., a_99)+-- x = case tup of ...+--+mkSizeIs :: Int -> Int -> Bag (Id, Int) -> Int -> ExprSize+mkSizeIs max n xs d | (n - d) > max = TooBig+ | otherwise = SizeIs n xs d++maxSize :: ExprSize -> ExprSize -> ExprSize+maxSize TooBig _ = TooBig+maxSize _ TooBig = TooBig+maxSize s1@(SizeIs n1 _ _) s2@(SizeIs n2 _ _) | n1 > n2 = s1+ | otherwise = s2++sizeZero :: ExprSize+sizeN :: Int -> ExprSize++sizeZero = SizeIs 0 emptyBag 0+sizeN n = SizeIs n emptyBag 0++{-+************************************************************************+* *+\subsection[considerUnfolding]{Given all the info, do (not) do the unfolding}+* *+************************************************************************++We use 'couldBeSmallEnoughToInline' to avoid exporting inlinings that+we ``couldn't possibly use'' on the other side. Can be overridden w/+flaggery. Just the same as smallEnoughToInline, except that it has no+actual arguments.+-}++couldBeSmallEnoughToInline :: DynFlags -> Int -> CoreExpr -> Bool+couldBeSmallEnoughToInline dflags threshold rhs+ = case sizeExpr dflags threshold [] body of+ TooBig -> False+ _ -> True+ where+ (_, body) = collectBinders rhs++----------------+smallEnoughToInline :: DynFlags -> Unfolding -> Bool+smallEnoughToInline dflags (CoreUnfolding {uf_guidance = UnfIfGoodArgs {ug_size = size}})+ = size <= ufUseThreshold dflags+smallEnoughToInline _ _+ = False++----------------++certainlyWillInline :: DynFlags -> IdInfo -> Maybe Unfolding+-- Sees if the unfolding is pretty certain to inline+-- If so, return a *stable* unfolding for it, that will always inline+certainlyWillInline dflags fn_info+ = case unfoldingInfo fn_info of+ CoreUnfolding { uf_tmpl = e, uf_guidance = g }+ | loop_breaker -> Nothing -- Won't inline, so try w/w+ | otherwise -> do_cunf e g -- Depends on size, so look at that++ DFunUnfolding {} -> Just fn_unf -- Don't w/w DFuns; it never makes sense+ -- to do so, and even if it is currently a+ -- loop breaker, it may not be later++ _other_unf -> Nothing++ where+ loop_breaker = isStrongLoopBreaker (occInfo fn_info)+ fn_unf = unfoldingInfo fn_info++ do_cunf :: CoreExpr -> UnfoldingGuidance -> Maybe Unfolding+ do_cunf _ UnfNever = Nothing+ do_cunf _ (UnfWhen {}) = Just (fn_unf { uf_src = InlineStable })+ -- INLINE functions have UnfWhen++ -- The UnfIfGoodArgs case seems important. If we w/w small functions+ -- binary sizes go up by 10%! (This is with SplitObjs.)+ -- I'm not totally sure why.+ -- INLINABLE functions come via this path+ -- See Note [certainlyWillInline: INLINABLE]+ do_cunf expr (UnfIfGoodArgs { ug_size = size, ug_args = args })+ | not (null args) -- See Note [certainlyWillInline: be careful of thunks]+ , case inlinePragmaSpec (inlinePragInfo fn_info) of+ NoInline -> False -- NOINLINE; do not say certainlyWillInline!+ _ -> True -- INLINE, INLINABLE, or nothing+ , not (isBottomingSig (strictnessInfo fn_info))+ -- Do not unconditionally inline a bottoming functions even if+ -- it seems smallish. We've carefully lifted it out to top level,+ -- so we don't want to re-inline it.+ , let arity = length args+ , size - (10 * (arity + 1)) <= ufUseThreshold dflags+ = Just (fn_unf { uf_src = InlineStable+ , uf_guidance = UnfWhen { ug_arity = arity+ , ug_unsat_ok = unSaturatedOk+ , ug_boring_ok = inlineBoringOk expr } })+ -- Note the "unsaturatedOk". A function like f = \ab. a+ -- will certainly inline, even if partially applied (f e), so we'd+ -- better make sure that the transformed inlining has the same property+ | otherwise+ = Nothing++{- Note [certainlyWillInline: be careful of thunks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Don't claim that thunks will certainly inline, because that risks work+duplication. Even if the work duplication is not great (eg is_cheap+holds), it can make a big difference in an inner loop In Trac #5623 we+found that the WorkWrap phase thought that+ y = case x of F# v -> F# (v +# v)+was certainlyWillInline, so the addition got duplicated.++Note [certainlyWillInline: INLINABLE]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+certainlyWillInline /must/ return Nothing for a large INLINABLE thing,+even though we have a stable inlining, so that strictness w/w takes+place. It makes a big difference to efficiency, and the w/w pass knows+how to transfer the INLINABLE info to the worker; see WorkWrap+Note [Worker-wrapper for INLINABLE functions]++************************************************************************+* *+\subsection{callSiteInline}+* *+************************************************************************++This is the key function. It decides whether to inline a variable at a call site++callSiteInline is used at call sites, so it is a bit more generous.+It's a very important function that embodies lots of heuristics.+A non-WHNF can be inlined if it doesn't occur inside a lambda,+and occurs exactly once or+ occurs once in each branch of a case and is small++If the thing is in WHNF, there's no danger of duplicating work,+so we can inline if it occurs once, or is small++NOTE: we don't want to inline top-level functions that always diverge.+It just makes the code bigger. Tt turns out that the convenient way to prevent+them inlining is to give them a NOINLINE pragma, which we do in+StrictAnal.addStrictnessInfoToTopId+-}++callSiteInline :: DynFlags+ -> Id -- The Id+ -> Bool -- True <=> unfolding is active+ -> Bool -- True if there are no arguments at all (incl type args)+ -> [ArgSummary] -- One for each value arg; True if it is interesting+ -> CallCtxt -- True <=> continuation is interesting+ -> Maybe CoreExpr -- Unfolding, if any++data ArgSummary = TrivArg -- Nothing interesting+ | NonTrivArg -- Arg has structure+ | ValueArg -- Arg is a con-app or PAP+ -- ..or con-like. Note [Conlike is interesting]++instance Outputable ArgSummary where+ ppr TrivArg = text "TrivArg"+ ppr NonTrivArg = text "NonTrivArg"+ ppr ValueArg = text "ValueArg"++nonTriv :: ArgSummary -> Bool+nonTriv TrivArg = False+nonTriv _ = True++data CallCtxt+ = BoringCtxt+ | RhsCtxt -- Rhs of a let-binding; see Note [RHS of lets]+ | DiscArgCtxt -- Argument of a function with non-zero arg discount+ | RuleArgCtxt -- We are somewhere in the argument of a function with rules++ | ValAppCtxt -- We're applied to at least one value arg+ -- This arises when we have ((f x |> co) y)+ -- Then the (f x) has argument 'x' but in a ValAppCtxt++ | CaseCtxt -- We're the scrutinee of a case+ -- that decomposes its scrutinee++instance Outputable CallCtxt where+ ppr CaseCtxt = text "CaseCtxt"+ ppr ValAppCtxt = text "ValAppCtxt"+ ppr BoringCtxt = text "BoringCtxt"+ ppr RhsCtxt = text "RhsCtxt"+ ppr DiscArgCtxt = text "DiscArgCtxt"+ ppr RuleArgCtxt = text "RuleArgCtxt"++callSiteInline dflags id active_unfolding lone_variable arg_infos cont_info+ = case idUnfolding id of+ -- idUnfolding checks for loop-breakers, returning NoUnfolding+ -- Things with an INLINE pragma may have an unfolding *and*+ -- be a loop breaker (maybe the knot is not yet untied)+ CoreUnfolding { uf_tmpl = unf_template, uf_is_top = is_top+ , uf_is_work_free = is_wf+ , uf_guidance = guidance, uf_expandable = is_exp }+ | active_unfolding -> tryUnfolding dflags id lone_variable+ arg_infos cont_info unf_template is_top+ is_wf is_exp guidance+ | otherwise -> traceInline dflags "Inactive unfolding:" (ppr id) Nothing+ NoUnfolding -> Nothing+ BootUnfolding -> Nothing+ OtherCon {} -> Nothing+ DFunUnfolding {} -> Nothing -- Never unfold a DFun++traceInline :: DynFlags -> String -> SDoc -> a -> a+traceInline dflags str doc result+ | dopt Opt_D_dump_inlinings dflags && dopt Opt_D_verbose_core2core dflags+ = pprTrace str doc result+ | otherwise+ = result++tryUnfolding :: DynFlags -> Id -> Bool -> [ArgSummary] -> CallCtxt+ -> CoreExpr -> Bool -> Bool -> Bool -> UnfoldingGuidance+ -> Maybe CoreExpr+tryUnfolding dflags id lone_variable+ arg_infos cont_info unf_template is_top+ is_wf is_exp guidance+ = case guidance of+ UnfNever -> traceInline dflags str (text "UnfNever") Nothing++ UnfWhen { ug_arity = uf_arity, ug_unsat_ok = unsat_ok, ug_boring_ok = boring_ok }+ | enough_args && (boring_ok || some_benefit || ufVeryAggressive dflags)+ -- See Note [INLINE for small functions (3)]+ -> traceInline dflags str (mk_doc some_benefit empty True) (Just unf_template)+ | otherwise+ -> traceInline dflags str (mk_doc some_benefit empty False) Nothing+ where+ some_benefit = calc_some_benefit uf_arity+ enough_args = (n_val_args >= uf_arity) || (unsat_ok && n_val_args > 0)++ UnfIfGoodArgs { ug_args = arg_discounts, ug_res = res_discount, ug_size = size }+ | ufVeryAggressive dflags+ -> traceInline dflags str (mk_doc some_benefit extra_doc True) (Just unf_template)+ | is_wf && some_benefit && small_enough+ -> traceInline dflags str (mk_doc some_benefit extra_doc True) (Just unf_template)+ | otherwise+ -> traceInline dflags str (mk_doc some_benefit extra_doc False) Nothing+ where+ some_benefit = calc_some_benefit (length arg_discounts)+ extra_doc = text "discounted size =" <+> int discounted_size+ discounted_size = size - discount+ small_enough = discounted_size <= ufUseThreshold dflags+ discount = computeDiscount dflags arg_discounts+ res_discount arg_infos cont_info++ where+ mk_doc some_benefit extra_doc yes_or_no+ = vcat [ text "arg infos" <+> ppr arg_infos+ , text "interesting continuation" <+> ppr cont_info+ , text "some_benefit" <+> ppr some_benefit+ , text "is exp:" <+> ppr is_exp+ , text "is work-free:" <+> ppr is_wf+ , text "guidance" <+> ppr guidance+ , extra_doc+ , text "ANSWER =" <+> if yes_or_no then text "YES" else text "NO"]++ str = "Considering inlining: " ++ showSDocDump dflags (ppr id)+ n_val_args = length arg_infos++ -- some_benefit is used when the RHS is small enough+ -- and the call has enough (or too many) value+ -- arguments (ie n_val_args >= arity). But there must+ -- be *something* interesting about some argument, or the+ -- result context, to make it worth inlining+ calc_some_benefit :: Arity -> Bool -- The Arity is the number of args+ -- expected by the unfolding+ calc_some_benefit uf_arity+ | not saturated = interesting_args -- Under-saturated+ -- Note [Unsaturated applications]+ | otherwise = interesting_args -- Saturated or over-saturated+ || interesting_call+ where+ saturated = n_val_args >= uf_arity+ over_saturated = n_val_args > uf_arity+ interesting_args = any nonTriv arg_infos+ -- NB: (any nonTriv arg_infos) looks at the+ -- over-saturated args too which is "wrong";+ -- but if over-saturated we inline anyway.++ interesting_call+ | over_saturated+ = True+ | otherwise+ = case cont_info of+ CaseCtxt -> not (lone_variable && is_wf) -- Note [Lone variables]+ ValAppCtxt -> True -- Note [Cast then apply]+ RuleArgCtxt -> uf_arity > 0 -- See Note [Unfold info lazy contexts]+ DiscArgCtxt -> uf_arity > 0 --+ RhsCtxt -> uf_arity > 0 --+ _ -> not is_top && uf_arity > 0 -- Note [Nested functions]+ -- Note [Inlining in ArgCtxt]++{-+Note [Unfold into lazy contexts], Note [RHS of lets]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When the call is the argument of a function with a RULE, or the RHS of a let,+we are a little bit keener to inline. For example+ f y = (y,y,y)+ g y = let x = f y in ...(case x of (a,b,c) -> ...) ...+We'd inline 'f' if the call was in a case context, and it kind-of-is,+only we can't see it. Also+ x = f v+could be expensive whereas+ x = case v of (a,b) -> a+is patently cheap and may allow more eta expansion.+So we treat the RHS of a let as not-totally-boring.++Note [Unsaturated applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When a call is not saturated, we *still* inline if one of the+arguments has interesting structure. That's sometimes very important.+A good example is the Ord instance for Bool in Base:++ Rec {+ $fOrdBool =GHC.Classes.D:Ord+ @ Bool+ ...+ $cmin_ajX++ $cmin_ajX [Occ=LoopBreaker] :: Bool -> Bool -> Bool+ $cmin_ajX = GHC.Classes.$dmmin @ Bool $fOrdBool+ }++But the defn of GHC.Classes.$dmmin is:++ $dmmin :: forall a. GHC.Classes.Ord a => a -> a -> a+ {- Arity: 3, HasNoCafRefs, Strictness: SLL,+ Unfolding: (\ @ a $dOrd :: GHC.Classes.Ord a x :: a y :: a ->+ case @ a GHC.Classes.<= @ a $dOrd x y of wild {+ GHC.Types.False -> y GHC.Types.True -> x }) -}++We *really* want to inline $dmmin, even though it has arity 3, in+order to unravel the recursion.+++Note [Things to watch]+~~~~~~~~~~~~~~~~~~~~~~+* { y = I# 3; x = y `cast` co; ...case (x `cast` co) of ... }+ Assume x is exported, so not inlined unconditionally.+ Then we want x to inline unconditionally; no reason for it+ not to, and doing so avoids an indirection.++* { x = I# 3; ....f x.... }+ Make sure that x does not inline unconditionally!+ Lest we get extra allocation.++Note [Inlining an InlineRule]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+An InlineRules is used for+ (a) programmer INLINE pragmas+ (b) inlinings from worker/wrapper++For (a) the RHS may be large, and our contract is that we *only* inline+when the function is applied to all the arguments on the LHS of the+source-code defn. (The uf_arity in the rule.)++However for worker/wrapper it may be worth inlining even if the+arity is not satisfied (as we do in the CoreUnfolding case) so we don't+require saturation.+++Note [Nested functions]+~~~~~~~~~~~~~~~~~~~~~~~+If a function has a nested defn we also record some-benefit, on the+grounds that we are often able to eliminate the binding, and hence the+allocation, for the function altogether; this is good for join points.+But this only makes sense for *functions*; inlining a constructor+doesn't help allocation unless the result is scrutinised. UNLESS the+constructor occurs just once, albeit possibly in multiple case+branches. Then inlining it doesn't increase allocation, but it does+increase the chance that the constructor won't be allocated at all in+the branches that don't use it.++Note [Cast then apply]+~~~~~~~~~~~~~~~~~~~~~~+Consider+ myIndex = __inline_me ( (/\a. <blah>) |> co )+ co :: (forall a. a -> a) ~ (forall a. T a)+ ... /\a.\x. case ((myIndex a) |> sym co) x of { ... } ...++We need to inline myIndex to unravel this; but the actual call (myIndex a) has+no value arguments. The ValAppCtxt gives it enough incentive to inline.++Note [Inlining in ArgCtxt]+~~~~~~~~~~~~~~~~~~~~~~~~~~+The condition (arity > 0) here is very important, because otherwise+we end up inlining top-level stuff into useless places; eg+ x = I# 3#+ f = \y. g x+This can make a very big difference: it adds 16% to nofib 'integer' allocs,+and 20% to 'power'.++At one stage I replaced this condition by 'True' (leading to the above+slow-down). The motivation was test eyeball/inline1.hs; but that seems+to work ok now.++NOTE: arguably, we should inline in ArgCtxt only if the result of the+call is at least CONLIKE. At least for the cases where we use ArgCtxt+for the RHS of a 'let', we only profit from the inlining if we get a+CONLIKE thing (modulo lets).++Note [Lone variables] See also Note [Interaction of exprIsWorkFree and lone variables]+~~~~~~~~~~~~~~~~~~~~~ which appears below+The "lone-variable" case is important. I spent ages messing about+with unsatisfactory variants, but this is nice. The idea is that if a+variable appears all alone++ as an arg of lazy fn, or rhs BoringCtxt+ as scrutinee of a case CaseCtxt+ as arg of a fn ArgCtxt+AND+ it is bound to a cheap expression++then we should not inline it (unless there is some other reason,+e.g. it is the sole occurrence). That is what is happening at+the use of 'lone_variable' in 'interesting_call'.++Why? At least in the case-scrutinee situation, turning+ let x = (a,b) in case x of y -> ...+into+ let x = (a,b) in case (a,b) of y -> ...+and thence to+ let x = (a,b) in let y = (a,b) in ...+is bad if the binding for x will remain.++Another example: I discovered that strings+were getting inlined straight back into applications of 'error'+because the latter is strict.+ s = "foo"+ f = \x -> ...(error s)...++Fundamentally such contexts should not encourage inlining because the+context can ``see'' the unfolding of the variable (e.g. case or a+RULE) so there's no gain. If the thing is bound to a value.++However, watch out:++ * Consider this:+ foo = _inline_ (\n. [n])+ bar = _inline_ (foo 20)+ baz = \n. case bar of { (m:_) -> m + n }+ Here we really want to inline 'bar' so that we can inline 'foo'+ and the whole thing unravels as it should obviously do. This is+ important: in the NDP project, 'bar' generates a closure data+ structure rather than a list.++ So the non-inlining of lone_variables should only apply if the+ unfolding is regarded as cheap; because that is when exprIsConApp_maybe+ looks through the unfolding. Hence the "&& is_wf" in the+ InlineRule branch.++ * Even a type application or coercion isn't a lone variable.+ Consider+ case $fMonadST @ RealWorld of { :DMonad a b c -> c }+ We had better inline that sucker! The case won't see through it.++ For now, I'm treating treating a variable applied to types+ in a *lazy* context "lone". The motivating example was+ f = /\a. \x. BIG+ g = /\a. \y. h (f a)+ There's no advantage in inlining f here, and perhaps+ a significant disadvantage. Hence some_val_args in the Stop case++Note [Interaction of exprIsWorkFree and lone variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The lone-variable test says "don't inline if a case expression+scrutinises a lone variable whose unfolding is cheap". It's very+important that, under these circumstances, exprIsConApp_maybe+can spot a constructor application. So, for example, we don't+consider+ let x = e in (x,x)+to be cheap, and that's good because exprIsConApp_maybe doesn't+think that expression is a constructor application.++In the 'not (lone_variable && is_wf)' test, I used to test is_value+rather than is_wf, which was utterly wrong, because the above+expression responds True to exprIsHNF, which is what sets is_value.++This kind of thing can occur if you have++ {-# INLINE foo #-}+ foo = let x = e in (x,x)++which Roman did.+-}++computeDiscount :: DynFlags -> [Int] -> Int -> [ArgSummary] -> CallCtxt+ -> Int+computeDiscount dflags arg_discounts res_discount arg_infos cont_info+ -- We multiple the raw discounts (args_discount and result_discount)+ -- ty opt_UnfoldingKeenessFactor because the former have to do with+ -- *size* whereas the discounts imply that there's some extra+ -- *efficiency* to be gained (e.g. beta reductions, case reductions)+ -- by inlining.++ = 10 -- Discount of 10 because the result replaces the call+ -- so we count 10 for the function itself++ + 10 * length actual_arg_discounts+ -- Discount of 10 for each arg supplied,+ -- because the result replaces the call++ + round (ufKeenessFactor dflags *+ fromIntegral (total_arg_discount + res_discount'))+ where+ actual_arg_discounts = zipWith mk_arg_discount arg_discounts arg_infos+ total_arg_discount = sum actual_arg_discounts++ mk_arg_discount _ TrivArg = 0+ mk_arg_discount _ NonTrivArg = 10+ mk_arg_discount discount ValueArg = discount++ res_discount'+ | LT <- arg_discounts `compareLength` arg_infos+ = res_discount -- Over-saturated+ | otherwise+ = case cont_info of+ BoringCtxt -> 0+ CaseCtxt -> res_discount -- Presumably a constructor+ ValAppCtxt -> res_discount -- Presumably a function+ _ -> 40 `min` res_discount+ -- ToDo: this 40 `min` res_discount doesn't seem right+ -- for DiscArgCtxt it shouldn't matter because the function will+ -- get the arg discount for any non-triv arg+ -- for RuleArgCtxt we do want to be keener to inline; but not only+ -- constructor results+ -- for RhsCtxt I suppose that exposing a data con is good in general+ -- And 40 seems very arbitrary+ --+ -- res_discount can be very large when a function returns+ -- constructors; but we only want to invoke that large discount+ -- when there's a case continuation.+ -- Otherwise we, rather arbitrarily, threshold it. Yuk.+ -- But we want to aovid inlining large functions that return+ -- constructors into contexts that are simply "interesting"
+ coreSyn/CoreUtils.hs view
@@ -0,0 +1,2329 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Utility functions on @Core@ syntax+-}++{-# LANGUAGE CPP #-}++-- | Commonly useful utilites for manipulating the Core language+module CoreUtils (+ -- * Constructing expressions+ mkCast,+ mkTick, mkTicks, mkTickNoHNF, tickHNFArgs,+ bindNonRec, needsCaseBinding,+ mkAltExpr,++ -- * Taking expressions apart+ findDefault, addDefault, findAlt, isDefaultAlt,+ mergeAlts, trimConArgs,+ filterAlts, combineIdenticalAlts, refineDefaultAlt,++ -- * Properties of expressions+ exprType, coreAltType, coreAltsType, isExprLevPoly,+ exprIsDupable, exprIsTrivial, getIdFromTrivialExpr, exprIsBottom,+ getIdFromTrivialExpr_maybe,+ exprIsCheap, exprIsExpandable, exprIsOk, CheapAppFun,+ exprIsHNF, exprOkForSpeculation, exprOkForSideEffects, exprIsWorkFree,+ exprIsBig, exprIsConLike,+ rhsIsStatic, isCheapApp, isExpandableApp,+ exprIsLiteralString, exprIsTopLevelBindable,++ -- * Equality+ cheapEqExpr, cheapEqExpr', eqExpr,+ diffExpr, diffBinds,++ -- * Eta reduction+ tryEtaReduce,++ -- * Manipulating data constructors and types+ exprToType, exprToCoercion_maybe,+ applyTypeToArgs, applyTypeToArg,+ dataConRepInstPat, dataConRepFSInstPat,+ isEmptyTy,++ -- * Working with ticks+ stripTicksTop, stripTicksTopE, stripTicksTopT,+ stripTicksE, stripTicksT,++ -- * StaticPtr+ collectMakeStaticArgs,++ -- * Join points+ isJoinBind+ ) where++#include "HsVersions.h"++import CoreSyn+import PrelNames ( makeStaticName )+import PprCore+import CoreFVs( exprFreeVars )+import Var+import SrcLoc+import VarEnv+import VarSet+import Name+import Literal+import DataCon+import PrimOp+import Id+import IdInfo+import Type+import TyCoRep( TyBinder(..) )+import Coercion+import TyCon+import Unique+import Outputable+import TysPrim+import DynFlags+import FastString+import Maybes+import ListSetOps ( minusList )+import BasicTypes ( Arity )+import Platform+import Util+import Pair+import Data.Function ( on )+import Data.List+import Data.Ord ( comparing )+import OrdList++{-+************************************************************************+* *+\subsection{Find the type of a Core atom/expression}+* *+************************************************************************+-}++exprType :: CoreExpr -> Type+-- ^ Recover the type of a well-typed Core expression. Fails when+-- applied to the actual 'CoreSyn.Type' expression as it cannot+-- really be said to have a type+exprType (Var var) = idType var+exprType (Lit lit) = literalType lit+exprType (Coercion co) = coercionType co+exprType (Let bind body)+ | NonRec tv rhs <- bind -- See Note [Type bindings]+ , Type ty <- rhs = substTyWithUnchecked [tv] [ty] (exprType body)+ | otherwise = exprType body+exprType (Case _ _ ty _) = ty+exprType (Cast _ co) = pSnd (coercionKind co)+exprType (Tick _ e) = exprType e+exprType (Lam binder expr) = mkLamType binder (exprType expr)+exprType e@(App _ _)+ = case collectArgs e of+ (fun, args) -> applyTypeToArgs e (exprType fun) args++exprType other = pprTrace "exprType" (pprCoreExpr other) alphaTy++coreAltType :: CoreAlt -> Type+-- ^ Returns the type of the alternatives right hand side+coreAltType (_,bs,rhs)+ | any bad_binder bs = expandTypeSynonyms ty+ | otherwise = ty -- Note [Existential variables and silly type synonyms]+ where+ ty = exprType rhs+ free_tvs = tyCoVarsOfType ty+ bad_binder b = b `elemVarSet` free_tvs++coreAltsType :: [CoreAlt] -> Type+-- ^ Returns the type of the first alternative, which should be the same as for all alternatives+coreAltsType (alt:_) = coreAltType alt+coreAltsType [] = panic "corAltsType"++-- | Is this expression levity polymorphic? This should be the+-- same as saying (isKindLevPoly . typeKind . exprType) but+-- much faster.+isExprLevPoly :: CoreExpr -> Bool+isExprLevPoly = go+ where+ go (Var _) = False -- no levity-polymorphic binders+ go (Lit _) = False -- no levity-polymorphic literals+ go e@(App f _) | not (go_app f) = False+ | otherwise = check_type e+ go (Lam _ _) = False+ go (Let _ e) = go e+ go e@(Case {}) = check_type e -- checking type is fast+ go e@(Cast {}) = check_type e+ go (Tick _ e) = go e+ go e@(Type {}) = pprPanic "isExprLevPoly ty" (ppr e)+ go (Coercion {}) = False -- this case can happen in SetLevels++ check_type = isTypeLevPoly . exprType -- slow approach++ -- if the function is a variable (common case), check its+ -- levityInfo. This might mean we don't need to look up and compute+ -- on the type. Spec of these functions: return False if there is+ -- no possibility, ever, of this expression becoming levity polymorphic,+ -- no matter what it's applied to; return True otherwise.+ -- returning True is always safe. See also Note [Levity info] in+ -- IdInfo+ go_app (Var id) = not (isNeverLevPolyId id)+ go_app (Lit _) = False+ go_app (App f _) = go_app f+ go_app (Lam _ e) = go_app e+ go_app (Let _ e) = go_app e+ go_app (Case _ _ ty _) = resultIsLevPoly ty+ go_app (Cast _ co) = resultIsLevPoly (pSnd $ coercionKind co)+ go_app (Tick _ e) = go_app e+ go_app e@(Type {}) = pprPanic "isExprLevPoly app ty" (ppr e)+ go_app e@(Coercion {}) = pprPanic "isExprLevPoly app co" (ppr e)+++{-+Note [Type bindings]+~~~~~~~~~~~~~~~~~~~~+Core does allow type bindings, although such bindings are+not much used, except in the output of the desuguarer.+Example:+ let a = Int in (\x:a. x)+Given this, exprType must be careful to substitute 'a' in the+result type (Trac #8522).++Note [Existential variables and silly type synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T = forall a. T (Funny a)+ type Funny a = Bool+ f :: T -> Bool+ f (T x) = x++Now, the type of 'x' is (Funny a), where 'a' is existentially quantified.+That means that 'exprType' and 'coreAltsType' may give a result that *appears*+to mention an out-of-scope type variable. See Trac #3409 for a more real-world+example.++Various possibilities suggest themselves:++ - Ignore the problem, and make Lint not complain about such variables++ - Expand all type synonyms (or at least all those that discard arguments)+ This is tricky, because at least for top-level things we want to+ retain the type the user originally specified.++ - Expand synonyms on the fly, when the problem arises. That is what+ we are doing here. It's not too expensive, I think.++Note that there might be existentially quantified coercion variables, too.+-}++-- Not defined with applyTypeToArg because you can't print from CoreSyn.+applyTypeToArgs :: CoreExpr -> Type -> [CoreExpr] -> Type+-- ^ A more efficient version of 'applyTypeToArg' when we have several arguments.+-- The first argument is just for debugging, and gives some context+applyTypeToArgs e op_ty args+ = go op_ty args+ where+ go op_ty [] = op_ty+ go op_ty (Type ty : args) = go_ty_args op_ty [ty] args+ go op_ty (Coercion co : args) = go_ty_args op_ty [mkCoercionTy co] args+ go op_ty (_ : args) | Just (_, res_ty) <- splitFunTy_maybe op_ty+ = go res_ty args+ go _ _ = pprPanic "applyTypeToArgs" panic_msg++ -- go_ty_args: accumulate type arguments so we can+ -- instantiate all at once with piResultTys+ go_ty_args op_ty rev_tys (Type ty : args)+ = go_ty_args op_ty (ty:rev_tys) args+ go_ty_args op_ty rev_tys (Coercion co : args)+ = go_ty_args op_ty (mkCoercionTy co : rev_tys) args+ go_ty_args op_ty rev_tys args+ = go (piResultTys op_ty (reverse rev_tys)) args++ panic_msg = vcat [ text "Expression:" <+> pprCoreExpr e+ , text "Type:" <+> ppr op_ty+ , text "Args:" <+> ppr args ]+++{-+************************************************************************+* *+\subsection{Attaching notes}+* *+************************************************************************+-}++-- | Wrap the given expression in the coercion safely, dropping+-- identity coercions and coalescing nested coercions+mkCast :: CoreExpr -> Coercion -> CoreExpr+mkCast e co+ | ASSERT2( coercionRole co == Representational+ , text "coercion" <+> ppr co <+> ptext (sLit "passed to mkCast")+ <+> ppr e <+> text "has wrong role" <+> ppr (coercionRole co) )+ isReflCo co+ = e++mkCast (Coercion e_co) co+ | isCoercionType (pSnd (coercionKind co))+ -- The guard here checks that g has a (~#) on both sides,+ -- otherwise decomposeCo fails. Can in principle happen+ -- with unsafeCoerce+ = Coercion (mkCoCast e_co co)++mkCast (Cast expr co2) co+ = WARN(let { Pair from_ty _to_ty = coercionKind co;+ Pair _from_ty2 to_ty2 = coercionKind co2} in+ not (from_ty `eqType` to_ty2),+ vcat ([ text "expr:" <+> ppr expr+ , text "co2:" <+> ppr co2+ , text "co:" <+> ppr co ]) )+ mkCast expr (mkTransCo co2 co)++mkCast (Tick t expr) co+ = Tick t (mkCast expr co)++mkCast expr co+ = let Pair from_ty _to_ty = coercionKind co in+ WARN( not (from_ty `eqType` exprType expr),+ text "Trying to coerce" <+> text "(" <> ppr expr+ $$ text "::" <+> ppr (exprType expr) <> text ")"+ $$ ppr co $$ ppr (coercionType co) )+ (Cast expr co)++-- | Wraps the given expression in the source annotation, dropping the+-- annotation if possible.+mkTick :: Tickish Id -> CoreExpr -> CoreExpr+mkTick t orig_expr = mkTick' id id orig_expr+ where+ -- Some ticks (cost-centres) can be split in two, with the+ -- non-counting part having laxer placement properties.+ canSplit = tickishCanSplit t && tickishPlace (mkNoCount t) /= tickishPlace t++ mkTick' :: (CoreExpr -> CoreExpr) -- ^ apply after adding tick (float through)+ -> (CoreExpr -> CoreExpr) -- ^ apply before adding tick (float with)+ -> CoreExpr -- ^ current expression+ -> CoreExpr+ mkTick' top rest expr = case expr of++ -- Never tick primitive string literals. These should ultimately float up to+ -- the top-level where they must be unadorned. See Note+ -- [CoreSyn top-level string literals] for details.+ _ | exprIsLiteralString expr -> expr++ -- Cost centre ticks should never be reordered relative to each+ -- other. Therefore we can stop whenever two collide.+ Tick t2 e+ | ProfNote{} <- t2, ProfNote{} <- t -> top $ Tick t $ rest expr++ -- Otherwise we assume that ticks of different placements float+ -- through each other.+ | tickishPlace t2 /= tickishPlace t -> mkTick' (top . Tick t2) rest e++ -- For annotations this is where we make sure to not introduce+ -- redundant ticks.+ | tickishContains t t2 -> mkTick' top rest e+ | tickishContains t2 t -> orig_expr+ | otherwise -> mkTick' top (rest . Tick t2) e++ -- Ticks don't care about types, so we just float all ticks+ -- through them. Note that it's not enough to check for these+ -- cases top-level. While mkTick will never produce Core with type+ -- expressions below ticks, such constructs can be the result of+ -- unfoldings. We therefore make an effort to put everything into+ -- the right place no matter what we start with.+ Cast e co -> mkTick' (top . flip Cast co) rest e+ Coercion co -> Coercion co++ Lam x e+ -- Always float through type lambdas. Even for non-type lambdas,+ -- floating is allowed for all but the most strict placement rule.+ | not (isRuntimeVar x) || tickishPlace t /= PlaceRuntime+ -> mkTick' (top . Lam x) rest e++ -- If it is both counting and scoped, we split the tick into its+ -- two components, often allowing us to keep the counting tick on+ -- the outside of the lambda and push the scoped tick inside.+ -- The point of this is that the counting tick can probably be+ -- floated, and the lambda may then be in a position to be+ -- beta-reduced.+ | canSplit+ -> top $ Tick (mkNoScope t) $ rest $ Lam x $ mkTick (mkNoCount t) e++ App f arg+ -- Always float through type applications.+ | not (isRuntimeArg arg)+ -> mkTick' (top . flip App arg) rest f++ -- We can also float through constructor applications, placement+ -- permitting. Again we can split.+ | isSaturatedConApp expr && (tickishPlace t==PlaceCostCentre || canSplit)+ -> if tickishPlace t == PlaceCostCentre+ then top $ rest $ tickHNFArgs t expr+ else top $ Tick (mkNoScope t) $ rest $ tickHNFArgs (mkNoCount t) expr++ Var x+ | notFunction && tickishPlace t == PlaceCostCentre+ -> orig_expr+ | notFunction && canSplit+ -> top $ Tick (mkNoScope t) $ rest expr+ where+ -- SCCs can be eliminated on variables provided the variable+ -- is not a function. In these cases the SCC makes no difference:+ -- the cost of evaluating the variable will be attributed to its+ -- definition site. When the variable refers to a function, however,+ -- an SCC annotation on the variable affects the cost-centre stack+ -- when the function is called, so we must retain those.+ notFunction = not (isFunTy (idType x))++ Lit{}+ | tickishPlace t == PlaceCostCentre+ -> orig_expr++ -- Catch-all: Annotate where we stand+ _any -> top $ Tick t $ rest expr++mkTicks :: [Tickish Id] -> CoreExpr -> CoreExpr+mkTicks ticks expr = foldr mkTick expr ticks++isSaturatedConApp :: CoreExpr -> Bool+isSaturatedConApp e = go e []+ where go (App f a) as = go f (a:as)+ go (Var fun) args+ = isConLikeId fun && idArity fun == valArgCount args+ go (Cast f _) as = go f as+ go _ _ = False++mkTickNoHNF :: Tickish Id -> CoreExpr -> CoreExpr+mkTickNoHNF t e+ | exprIsHNF e = tickHNFArgs t e+ | otherwise = mkTick t e++-- push a tick into the arguments of a HNF (call or constructor app)+tickHNFArgs :: Tickish Id -> CoreExpr -> CoreExpr+tickHNFArgs t e = push t e+ where+ push t (App f (Type u)) = App (push t f) (Type u)+ push t (App f arg) = App (push t f) (mkTick t arg)+ push _t e = e++-- | Strip ticks satisfying a predicate from top of an expression+stripTicksTop :: (Tickish Id -> Bool) -> Expr b -> ([Tickish Id], Expr b)+stripTicksTop p = go []+ where go ts (Tick t e) | p t = go (t:ts) e+ go ts other = (reverse ts, other)++-- | Strip ticks satisfying a predicate from top of an expression,+-- returning the remaining expression+stripTicksTopE :: (Tickish Id -> Bool) -> Expr b -> Expr b+stripTicksTopE p = go+ where go (Tick t e) | p t = go e+ go other = other++-- | Strip ticks satisfying a predicate from top of an expression,+-- returning the ticks+stripTicksTopT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id]+stripTicksTopT p = go []+ where go ts (Tick t e) | p t = go (t:ts) e+ go ts _ = ts++-- | Completely strip ticks satisfying a predicate from an+-- expression. Note this is O(n) in the size of the expression!+stripTicksE :: (Tickish Id -> Bool) -> Expr b -> Expr b+stripTicksE p expr = go expr+ where go (App e a) = App (go e) (go a)+ go (Lam b e) = Lam b (go e)+ go (Let b e) = Let (go_bs b) (go e)+ go (Case e b t as) = Case (go e) b t (map go_a as)+ go (Cast e c) = Cast (go e) c+ go (Tick t e)+ | p t = go e+ | otherwise = Tick t (go e)+ go other = other+ go_bs (NonRec b e) = NonRec b (go e)+ go_bs (Rec bs) = Rec (map go_b bs)+ go_b (b, e) = (b, go e)+ go_a (c,bs,e) = (c,bs, go e)++stripTicksT :: (Tickish Id -> Bool) -> Expr b -> [Tickish Id]+stripTicksT p expr = fromOL $ go expr+ where go (App e a) = go e `appOL` go a+ go (Lam _ e) = go e+ go (Let b e) = go_bs b `appOL` go e+ go (Case e _ _ as) = go e `appOL` concatOL (map go_a as)+ go (Cast e _) = go e+ go (Tick t e)+ | p t = t `consOL` go e+ | otherwise = go e+ go _ = nilOL+ go_bs (NonRec _ e) = go e+ go_bs (Rec bs) = concatOL (map go_b bs)+ go_b (_, e) = go e+ go_a (_, _, e) = go e++{-+************************************************************************+* *+\subsection{Other expression construction}+* *+************************************************************************+-}++bindNonRec :: Id -> CoreExpr -> CoreExpr -> CoreExpr+-- ^ @bindNonRec x r b@ produces either:+--+-- > let x = r in b+--+-- or:+--+-- > case r of x { _DEFAULT_ -> b }+--+-- depending on whether we have to use a @case@ or @let@+-- binding for the expression (see 'needsCaseBinding').+-- It's used by the desugarer to avoid building bindings+-- that give Core Lint a heart attack, although actually+-- the simplifier deals with them perfectly well. See+-- also 'MkCore.mkCoreLet'+bindNonRec bndr rhs body+ | needsCaseBinding (idType bndr) rhs = Case rhs bndr (exprType body) [(DEFAULT, [], body)]+ | otherwise = Let (NonRec bndr rhs) body++-- | Tests whether we have to use a @case@ rather than @let@ binding for this expression+-- as per the invariants of 'CoreExpr': see "CoreSyn#let_app_invariant"+needsCaseBinding :: Type -> CoreExpr -> Bool+needsCaseBinding ty rhs = isUnliftedType ty && not (exprOkForSpeculation rhs)+ -- Make a case expression instead of a let+ -- These can arise either from the desugarer,+ -- or from beta reductions: (\x.e) (x +# y)++mkAltExpr :: AltCon -- ^ Case alternative constructor+ -> [CoreBndr] -- ^ Things bound by the pattern match+ -> [Type] -- ^ The type arguments to the case alternative+ -> CoreExpr+-- ^ This guy constructs the value that the scrutinee must have+-- given that you are in one particular branch of a case+mkAltExpr (DataAlt con) args inst_tys+ = mkConApp con (map Type inst_tys ++ varsToCoreExprs args)+mkAltExpr (LitAlt lit) [] []+ = Lit lit+mkAltExpr (LitAlt _) _ _ = panic "mkAltExpr LitAlt"+mkAltExpr DEFAULT _ _ = panic "mkAltExpr DEFAULT"++{-+************************************************************************+* *+ Operations oer case alternatives+* *+************************************************************************++The default alternative must be first, if it exists at all.+This makes it easy to find, though it makes matching marginally harder.+-}++-- | Extract the default case alternative+findDefault :: [(AltCon, [a], b)] -> ([(AltCon, [a], b)], Maybe b)+findDefault ((DEFAULT,args,rhs) : alts) = ASSERT( null args ) (alts, Just rhs)+findDefault alts = (alts, Nothing)++addDefault :: [(AltCon, [a], b)] -> Maybe b -> [(AltCon, [a], b)]+addDefault alts Nothing = alts+addDefault alts (Just rhs) = (DEFAULT, [], rhs) : alts++isDefaultAlt :: (AltCon, a, b) -> Bool+isDefaultAlt (DEFAULT, _, _) = True+isDefaultAlt _ = False++-- | Find the case alternative corresponding to a particular+-- constructor: panics if no such constructor exists+findAlt :: AltCon -> [(AltCon, a, b)] -> Maybe (AltCon, a, b)+ -- A "Nothing" result *is* legitmiate+ -- See Note [Unreachable code]+findAlt con alts+ = case alts of+ (deflt@(DEFAULT,_,_):alts) -> go alts (Just deflt)+ _ -> go alts Nothing+ where+ go [] deflt = deflt+ go (alt@(con1,_,_) : alts) deflt+ = case con `cmpAltCon` con1 of+ LT -> deflt -- Missed it already; the alts are in increasing order+ EQ -> Just alt+ GT -> ASSERT( not (con1 == DEFAULT) ) go alts deflt++{- Note [Unreachable code]+~~~~~~~~~~~~~~~~~~~~~~~~~~+It is possible (although unusual) for GHC to find a case expression+that cannot match. For example:++ data Col = Red | Green | Blue+ x = Red+ f v = case x of+ Red -> ...+ _ -> ...(case x of { Green -> e1; Blue -> e2 })...++Suppose that for some silly reason, x isn't substituted in the case+expression. (Perhaps there's a NOINLINE on it, or profiling SCC stuff+gets in the way; cf Trac #3118.) Then the full-lazines pass might produce+this++ x = Red+ lvl = case x of { Green -> e1; Blue -> e2 })+ f v = case x of+ Red -> ...+ _ -> ...lvl...++Now if x gets inlined, we won't be able to find a matching alternative+for 'Red'. That's because 'lvl' is unreachable. So rather than crashing+we generate (error "Inaccessible alternative").++Similar things can happen (augmented by GADTs) when the Simplifier+filters down the matching alternatives in Simplify.rebuildCase.+-}++---------------------------------+mergeAlts :: [(AltCon, a, b)] -> [(AltCon, a, b)] -> [(AltCon, a, b)]+-- ^ Merge alternatives preserving order; alternatives in+-- the first argument shadow ones in the second+mergeAlts [] as2 = as2+mergeAlts as1 [] = as1+mergeAlts (a1:as1) (a2:as2)+ = case a1 `cmpAlt` a2 of+ LT -> a1 : mergeAlts as1 (a2:as2)+ EQ -> a1 : mergeAlts as1 as2 -- Discard a2+ GT -> a2 : mergeAlts (a1:as1) as2+++---------------------------------+trimConArgs :: AltCon -> [CoreArg] -> [CoreArg]+-- ^ Given:+--+-- > case (C a b x y) of+-- > C b x y -> ...+--+-- We want to drop the leading type argument of the scrutinee+-- leaving the arguments to match against the pattern++trimConArgs DEFAULT args = ASSERT( null args ) []+trimConArgs (LitAlt _) args = ASSERT( null args ) []+trimConArgs (DataAlt dc) args = dropList (dataConUnivTyVars dc) args++filterAlts :: TyCon -- ^ Type constructor of scrutinee's type (used to prune possibilities)+ -> [Type] -- ^ And its type arguments+ -> [AltCon] -- ^ 'imposs_cons': constructors known to be impossible due to the form of the scrutinee+ -> [(AltCon, [Var], a)] -- ^ Alternatives+ -> ([AltCon], [(AltCon, [Var], a)])+ -- Returns:+ -- 1. Constructors that will never be encountered by the+ -- *default* case (if any). A superset of imposs_cons+ -- 2. The new alternatives, trimmed by+ -- a) remove imposs_cons+ -- b) remove constructors which can't match because of GADTs+ -- and with the DEFAULT expanded to a DataAlt if there is exactly+ -- remaining constructor that can match+ --+ -- NB: the final list of alternatives may be empty:+ -- This is a tricky corner case. If the data type has no constructors,+ -- which GHC allows, or if the imposs_cons covers all constructors (after taking+ -- account of GADTs), then no alternatives can match.+ --+ -- If callers need to preserve the invariant that there is always at least one branch+ -- in a "case" statement then they will need to manually add a dummy case branch that just+ -- calls "error" or similar.+filterAlts _tycon inst_tys imposs_cons alts+ = (imposs_deflt_cons, addDefault trimmed_alts maybe_deflt)+ where+ (alts_wo_default, maybe_deflt) = findDefault alts+ alt_cons = [con | (con,_,_) <- alts_wo_default]++ trimmed_alts = filterOut (impossible_alt inst_tys) alts_wo_default++ imposs_deflt_cons = nub (imposs_cons ++ alt_cons)+ -- "imposs_deflt_cons" are handled+ -- EITHER by the context,+ -- OR by a non-DEFAULT branch in this case expression.++ impossible_alt :: [Type] -> (AltCon, a, b) -> Bool+ impossible_alt _ (con, _, _) | con `elem` imposs_cons = True+ impossible_alt inst_tys (DataAlt con, _, _) = dataConCannotMatch inst_tys con+ impossible_alt _ _ = False++refineDefaultAlt :: [Unique] -> TyCon -> [Type]+ -> [AltCon] -- Constructors that cannot match the DEFAULT (if any)+ -> [CoreAlt]+ -> (Bool, [CoreAlt])+-- Refine the default alternative to a DataAlt,+-- if there is a unique way to do so+refineDefaultAlt us tycon tys imposs_deflt_cons all_alts+ | (DEFAULT,_,rhs) : rest_alts <- all_alts+ , isAlgTyCon tycon -- It's a data type, tuple, or unboxed tuples.+ , not (isNewTyCon tycon) -- We can have a newtype, if we are just doing an eval:+ -- case x of { DEFAULT -> e }+ -- and we don't want to fill in a default for them!+ , Just all_cons <- tyConDataCons_maybe tycon+ , let imposs_data_cons = [con | DataAlt con <- imposs_deflt_cons] -- We now know it's a data type+ impossible con = con `elem` imposs_data_cons || dataConCannotMatch tys con+ = case filterOut impossible all_cons of+ -- Eliminate the default alternative+ -- altogether if it can't match:+ [] -> (False, rest_alts)++ -- It matches exactly one constructor, so fill it in:+ [con] -> (True, mergeAlts rest_alts [(DataAlt con, ex_tvs ++ arg_ids, rhs)])+ -- We need the mergeAlts to keep the alternatives in the right order+ where+ (ex_tvs, arg_ids) = dataConRepInstPat us con tys++ -- It matches more than one, so do nothing+ _ -> (False, all_alts)++ | debugIsOn, isAlgTyCon tycon, null (tyConDataCons tycon)+ , not (isFamilyTyCon tycon || isAbstractTyCon tycon)+ -- Check for no data constructors+ -- This can legitimately happen for abstract types and type families,+ -- so don't report that+ = (False, all_alts)++ | otherwise -- The common case+ = (False, all_alts)++{- Note [Combine identical alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If several alternatives are identical, merge them into a single+DEFAULT alternative. I've occasionally seen this making a big+difference:++ case e of =====> case e of+ C _ -> f x D v -> ....v....+ D v -> ....v.... DEFAULT -> f x+ DEFAULT -> f x++The point is that we merge common RHSs, at least for the DEFAULT case.+[One could do something more elaborate but I've never seen it needed.]+To avoid an expensive test, we just merge branches equal to the *first*+alternative; this picks up the common cases+ a) all branches equal+ b) some branches equal to the DEFAULT (which occurs first)++The case where Combine Identical Alternatives transformation showed up+was like this (base/Foreign/C/Err/Error.hs):++ x | p `is` 1 -> e1+ | p `is` 2 -> e2+ ...etc...++where @is@ was something like++ p `is` n = p /= (-1) && p == n++This gave rise to a horrible sequence of cases++ case p of+ (-1) -> $j p+ 1 -> e1+ DEFAULT -> $j p++and similarly in cascade for all the join points!++NB: it's important that all this is done in [InAlt], *before* we work+on the alternatives themselves, because Simpify.simplAlt may zap the+occurrence info on the binders in the alternatives, which in turn+defeats combineIdenticalAlts (see Trac #7360).++Note [Care with impossible-constructors when combining alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have (Trac #10538)+ data T = A | B | C | D++ case x::T of (Imposs-default-cons {A,B})+ DEFAULT -> e1+ A -> e2+ B -> e1++When calling combineIdentialAlts, we'll have computed that the+"impossible constructors" for the DEFAULT alt is {A,B}, since if x is+A or B we'll take the other alternatives. But suppose we combine B+into the DEFAULT, to get++ case x::T of (Imposs-default-cons {A})+ DEFAULT -> e1+ A -> e2++Then we must be careful to trim the impossible constructors to just {A},+else we risk compiling 'e1' wrong!++Not only that, but we take care when there is no DEFAULT beforehand,+because we are introducing one. Consider++ case x of (Imposs-default-cons {A,B,C})+ A -> e1+ B -> e2+ C -> e1++Then when combining the A and C alternatives we get++ case x of (Imposs-default-cons {B})+ DEFAULT -> e1+ B -> e2++Note that we have a new DEFAULT branch that we didn't have before. So+we need delete from the "impossible-default-constructors" all the+known-con alternatives that we have eliminated. (In Trac #11172 we+missed the first one.)++-}++combineIdenticalAlts :: [AltCon] -- Constructors that cannot match DEFAULT+ -> [CoreAlt]+ -> (Bool, -- True <=> something happened+ [AltCon], -- New constructors that cannot match DEFAULT+ [CoreAlt]) -- New alternatives+-- See Note [Combine identical alternatives]+-- True <=> we did some combining, result is a single DEFAULT alternative+combineIdenticalAlts imposs_deflt_cons ((con1,bndrs1,rhs1) : rest_alts)+ | all isDeadBinder bndrs1 -- Remember the default+ , not (null elim_rest) -- alternative comes first+ = (True, imposs_deflt_cons', deflt_alt : filtered_rest)+ where+ (elim_rest, filtered_rest) = partition identical_to_alt1 rest_alts+ deflt_alt = (DEFAULT, [], mkTicks (concat tickss) rhs1)++ -- See Note [Care with impossible-constructors when combining alternatives]+ imposs_deflt_cons' = imposs_deflt_cons `minusList` elim_cons+ elim_cons = elim_con1 ++ map fstOf3 elim_rest+ elim_con1 = case con1 of -- Don't forget con1!+ DEFAULT -> [] -- See Note [+ _ -> [con1]++ cheapEqTicked e1 e2 = cheapEqExpr' tickishFloatable e1 e2+ identical_to_alt1 (_con,bndrs,rhs)+ = all isDeadBinder bndrs && rhs `cheapEqTicked` rhs1+ tickss = map (stripTicksT tickishFloatable . thdOf3) elim_rest++combineIdenticalAlts imposs_cons alts+ = (False, imposs_cons, alts)++{- *********************************************************************+* *+ exprIsTrivial+* *+************************************************************************++Note [exprIsTrivial]+~~~~~~~~~~~~~~~~~~~~+@exprIsTrivial@ is true of expressions we are unconditionally happy to+ duplicate; simple variables and constants, and type+ applications. Note that primop Ids aren't considered+ trivial unless++Note [Variables are trivial]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There used to be a gruesome test for (hasNoBinding v) in the+Var case:+ exprIsTrivial (Var v) | hasNoBinding v = idArity v == 0+The idea here is that a constructor worker, like \$wJust, is+really short for (\x -> \$wJust x), because \$wJust has no binding.+So it should be treated like a lambda. Ditto unsaturated primops.+But now constructor workers are not "have-no-binding" Ids. And+completely un-applied primops and foreign-call Ids are sufficiently+rare that I plan to allow them to be duplicated and put up with+saturating them.++Note [Tick trivial]+~~~~~~~~~~~~~~~~~~~+Ticks are only trivial if they are pure annotations. If we treat+"tick<n> x" as trivial, it will be inlined inside lambdas and the+entry count will be skewed, for example. Furthermore "scc<n> x" will+turn into just "x" in mkTick.++Note [Empty case is trivial]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The expression (case (x::Int) Bool of {}) is just a type-changing+case used when we are sure that 'x' will not return. See+Note [Empty case alternatives] in CoreSyn.++If the scrutinee is trivial, then so is the whole expression; and the+CoreToSTG pass in fact drops the case expression leaving only the+scrutinee.++Having more trivial expressions is good. Moreover, if we don't treat+it as trivial we may land up with let-bindings like+ let v = case x of {} in ...+and after CoreToSTG that gives+ let v = x in ...+and that confuses the code generator (Trac #11155). So best to kill+it off at source.+-}++exprIsTrivial :: CoreExpr -> Bool+exprIsTrivial (Var _) = True -- See Note [Variables are trivial]+exprIsTrivial (Type _) = True+exprIsTrivial (Coercion _) = True+exprIsTrivial (Lit lit) = litIsTrivial lit+exprIsTrivial (App e arg) = not (isRuntimeArg arg) && exprIsTrivial e+exprIsTrivial (Lam b e) = not (isRuntimeVar b) && exprIsTrivial e+exprIsTrivial (Tick t e) = not (tickishIsCode t) && exprIsTrivial e+ -- See Note [Tick trivial]+exprIsTrivial (Cast e _) = exprIsTrivial e+exprIsTrivial (Case e _ _ []) = exprIsTrivial e -- See Note [Empty case is trivial]+exprIsTrivial _ = False++{-+Note [getIdFromTrivialExpr]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+When substituting in a breakpoint we need to strip away the type cruft+from a trivial expression and get back to the Id. The invariant is+that the expression we're substituting was originally trivial+according to exprIsTrivial, AND the expression is not a literal.+See Note [substTickish] for how breakpoint substitution preserves+this extra invariant.++We also need this functionality in CorePrep to extract out Id of a+function which we are saturating. However, in this case we don't know+if the variable actually refers to a literal; thus we use+'getIdFromTrivialExpr_maybe' to handle this case. See test+T12076lit for an example where this matters.+-}++getIdFromTrivialExpr :: CoreExpr -> Id+getIdFromTrivialExpr e+ = fromMaybe (pprPanic "getIdFromTrivialExpr" (ppr e))+ (getIdFromTrivialExpr_maybe e)++getIdFromTrivialExpr_maybe :: CoreExpr -> Maybe Id+-- See Note [getIdFromTrivialExpr]+getIdFromTrivialExpr_maybe e = go e+ where go (Var v) = Just v+ go (App f t) | not (isRuntimeArg t) = go f+ go (Tick t e) | not (tickishIsCode t) = go e+ go (Cast e _) = go e+ go (Lam b e) | not (isRuntimeVar b) = go e+ go _ = Nothing++{-+exprIsBottom is a very cheap and cheerful function; it may return+False for bottoming expressions, but it never costs much to ask. See+also CoreArity.exprBotStrictness_maybe, but that's a bit more+expensive.+-}++exprIsBottom :: CoreExpr -> Bool+-- See Note [Bottoming expressions]+exprIsBottom e+ | isEmptyTy (exprType e)+ = True+ | otherwise+ = go 0 e+ where+ go n (Var v) = isBottomingId v && n >= idArity v+ go n (App e a) | isTypeArg a = go n e+ | otherwise = go (n+1) e+ go n (Tick _ e) = go n e+ go n (Cast e _) = go n e+ go n (Let _ e) = go n e+ go n (Lam v e) | isTyVar v = go n e+ go _ (Case _ _ _ alts) = null alts+ -- See Note [Empty case alternatives] in CoreSyn+ go _ _ = False++{- Note [Bottoming expressions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A bottoming expression is guaranteed to diverge, or raise an+exception. We can test for it in two different ways, and exprIsBottom+checks for both of these situations:++* Visibly-bottom computations. For example+ (error Int "Hello")+ is visibly bottom. The strictness analyser also finds out if+ a function diverges or raises an exception, and puts that info+ in its strictness signature.++* Empty types. If a type is empty, its only inhabitant is bottom.+ For example:+ data T+ f :: T -> Bool+ f = \(x:t). case x of Bool {}+ Since T has no data constructors, the case alternatives are of course+ empty. However note that 'x' is not bound to a visibly-bottom value;+ it's the *type* that tells us it's going to diverge.++A GADT may also be empty even though it has constructors:+ data T a where+ T1 :: a -> T Bool+ T2 :: T Int+ ...(case (x::T Char) of {})...+Here (T Char) is uninhabited. A more realistic case is (Int ~ Bool),+which is likewise uninhabited.+++************************************************************************+* *+ exprIsDupable+* *+************************************************************************++Note [exprIsDupable]+~~~~~~~~~~~~~~~~~~~~+@exprIsDupable@ is true of expressions that can be duplicated at a modest+ cost in code size. This will only happen in different case+ branches, so there's no issue about duplicating work.++ That is, exprIsDupable returns True of (f x) even if+ f is very very expensive to call.++ Its only purpose is to avoid fruitless let-binding+ and then inlining of case join points+-}++exprIsDupable :: DynFlags -> CoreExpr -> Bool+exprIsDupable dflags e+ = isJust (go dupAppSize e)+ where+ go :: Int -> CoreExpr -> Maybe Int+ go n (Type {}) = Just n+ go n (Coercion {}) = Just n+ go n (Var {}) = decrement n+ go n (Tick _ e) = go n e+ go n (Cast e _) = go n e+ go n (App f a) | Just n' <- go n a = go n' f+ go n (Lit lit) | litIsDupable dflags lit = decrement n+ go _ _ = Nothing++ decrement :: Int -> Maybe Int+ decrement 0 = Nothing+ decrement n = Just (n-1)++dupAppSize :: Int+dupAppSize = 8 -- Size of term we are prepared to duplicate+ -- This is *just* big enough to make test MethSharing+ -- inline enough join points. Really it should be+ -- smaller, and could be if we fixed Trac #4960.++{-+************************************************************************+* *+ exprIsCheap, exprIsExpandable+* *+************************************************************************++Note [exprIsWorkFree]+~~~~~~~~~~~~~~~~~~~~~+exprIsWorkFree is used when deciding whether to inline something; we+don't inline it if doing so might duplicate work, by peeling off a+complete copy of the expression. Here we do not want even to+duplicate a primop (Trac #5623):+ eg let x = a #+ b in x +# x+ we do not want to inline/duplicate x++Previously we were a bit more liberal, which led to the primop-duplicating+problem. However, being more conservative did lead to a big regression in+one nofib benchmark, wheel-sieve1. The situation looks like this:++ let noFactor_sZ3 :: GHC.Types.Int -> GHC.Types.Bool+ noFactor_sZ3 = case s_adJ of _ { GHC.Types.I# x_aRs ->+ case GHC.Prim.<=# x_aRs 2 of _ {+ GHC.Types.False -> notDivBy ps_adM qs_adN;+ GHC.Types.True -> lvl_r2Eb }}+ go = \x. ...(noFactor (I# y))....(go x')...++The function 'noFactor' is heap-allocated and then called. Turns out+that 'notDivBy' is strict in its THIRD arg, but that is invisible to+the caller of noFactor, which therefore cannot do w/w and+heap-allocates noFactor's argument. At the moment (May 12) we are just+going to put up with this, because the previous more aggressive inlining+(which treated 'noFactor' as work-free) was duplicating primops, which+in turn was making inner loops of array calculations runs slow (#5623)++Note [Case expressions are work-free]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Are case-expressions work-free? Consider+ let v = case x of (p,q) -> p+ go = \y -> ...case v of ...+Should we inline 'v' at its use site inside the loop? At the moment+we do. I experimented with saying that case are *not* work-free, but+that increased allocation slightly. It's a fairly small effect, and at+the moment we go for the slightly more aggressive version which treats+(case x of ....) as work-free if the alternatives are.++Moreover it improves arities of overloaded functions where+there is only dictionary selection (no construction) involved++Note [exprIsCheap] See also Note [Interaction of exprIsCheap and lone variables]+~~~~~~~~~~~~~~~~~~ in CoreUnfold.hs+@exprIsCheap@ looks at a Core expression and returns \tr{True} if+it is obviously in weak head normal form, or is cheap to get to WHNF.+[Note that that's not the same as exprIsDupable; an expression might be+big, and hence not dupable, but still cheap.]++By ``cheap'' we mean a computation we're willing to:+ push inside a lambda, or+ inline at more than one place+That might mean it gets evaluated more than once, instead of being+shared. The main examples of things which aren't WHNF but are+``cheap'' are:++ * case e of+ pi -> ei+ (where e, and all the ei are cheap)++ * let x = e in b+ (where e and b are cheap)++ * op x1 ... xn+ (where op is a cheap primitive operator)++ * error "foo"+ (because we are happy to substitute it inside a lambda)++Notice that a variable is considered 'cheap': we can push it inside a lambda,+because sharing will make sure it is only evaluated once.++Note [exprIsCheap and exprIsHNF]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note that exprIsHNF does not imply exprIsCheap. Eg+ let x = fac 20 in Just x+This responds True to exprIsHNF (you can discard a seq), but+False to exprIsCheap.++Note [exprIsExpandable]+~~~~~~~~~~~~~~~~~~~~~~~+An expression is "expandable" if we are willing to dupicate it, if doing+so might make a RULE or case-of-constructor fire. Mainly this means+data-constructor applications, but it's a bit more generous than exprIsCheap+because it is true of "CONLIKE" Ids: see Note [CONLIKE pragma] in BasicTypes.++It is used to set the uf_expandable field of an Unfolding, and that+in turn is used+ * In RULE matching+ * In exprIsConApp_maybe, exprIsLiteral_maybe, exprIsLambda_maybe++But take care: exprIsExpandable should /not/ be true of primops. I+found this in test T5623a:+ let q = /\a. Ptr a (a +# b)+ in case q @ Float of Ptr v -> ...q...++q's inlining should not be expandable, else exprIsConApp_maybe will+say that (q @ Float) expands to (Ptr a (a +# b)), and that will+duplicate the (a +# b) primop, which we should not do lightly.+(It's quite hard to trigger this bug, but T13155 does so for GHC 8.0.)+++Note [Arguments in exprIsOk]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+What predicate should we apply to the argument of an application? We+used to say "exprIsTrivial arg" due to concerns about duplicating+nested constructor applications, but see #4978. The principle here is+that+ let x = a +# b in c *# x+should behave equivalently to+ c *# (a +# b)+Since lets with cheap RHSs are accepted, so should paps with cheap arguments+-}++--------------------+exprIsCheap :: CoreExpr -> Bool+exprIsCheap = exprIsOk isCheapApp++exprIsExpandable :: CoreExpr -> Bool -- See Note [exprIsExpandable]+exprIsExpandable = exprIsOk isExpandableApp++exprIsWorkFree :: CoreExpr -> Bool -- See Note [exprIsWorkFree]+exprIsWorkFree = exprIsOk isWorkFreeApp++--------------------+exprIsOk :: CheapAppFun -> CoreExpr -> Bool+exprIsOk ok_app e+ = ok e+ where+ ok e = go 0 e++ -- n is the number of value arguments+ go n (Var v) = ok_app v n+ go _ (Lit {}) = True+ go _ (Type {}) = True+ go _ (Coercion {}) = True+ go n (Cast e _) = go n e+ go n (Case scrut _ _ alts) = foldl (&&) (ok scrut)+ [ go n rhs | (_,_,rhs) <- alts ]+ go n (Tick t e) | tickishCounts t = False+ | otherwise = go n e+ go n (Lam x e) | isRuntimeVar x = n==0 || go (n-1) e+ | otherwise = go n e+ go n (App f e) | isRuntimeArg e = go (n+1) f && ok e+ | otherwise = go n f+ go _ (Let {}) = False++ -- Case: see Note [Case expressions are work-free]+ -- App: see Note [Arguments in exprIsOk]+ -- Let: the old exprIsCheap worked through lets+++-------------------------------------+type CheapAppFun = Id -> Arity -> Bool+ -- Is an application of this function to n *value* args+ -- always cheap, assuming the arguments are cheap?+ -- True mainly of data constructors, partial applications;+ -- but with minor variations:+ -- isWorkFreeApp+ -- isCheapApp+ -- isExpandableApp++ -- NB: isCheapApp and isExpandableApp are called from outside+ -- this module, so don't be tempted to move the notRedex+ -- stuff into the call site in exprIsOk, and remove it+ -- from the CheapAppFun implementations+++notRedex :: CheapAppFun+notRedex fn n_val_args+ = n_val_args == 0 -- No value args+ || n_val_args < idArity fn -- Partial application+ || isBottomingId fn -- OK to duplicate calls to bottom;+ -- it certainly doesn't need to be shared!++isWorkFreeApp :: CheapAppFun+isWorkFreeApp fn n_val_args+ | notRedex fn n_val_args+ = True+ | otherwise+ = case idDetails fn of+ DataConWorkId {} -> True+ _ -> False++isCheapApp :: CheapAppFun+isCheapApp fn n_val_args+ | notRedex fn n_val_args+ = True+ | otherwise+ = case idDetails fn of+ DataConWorkId {} -> True+ RecSelId {} -> n_val_args == 1 -- See Note [Record selection]+ ClassOpId {} -> n_val_args == 1+ PrimOpId op -> primOpIsCheap op+ _ -> False+ -- In principle we should worry about primops+ -- that return a type variable, since the result+ -- might be applied to something, but I'm not going+ -- to bother to check the number of args++isExpandableApp :: CheapAppFun+isExpandableApp fn n_val_args+ | notRedex fn n_val_args+ = True+ | isConLikeId fn+ = True+ | otherwise+ = case idDetails fn of+ DataConWorkId {} -> True+ RecSelId {} -> n_val_args == 1 -- See Note [Record selection]+ ClassOpId {} -> n_val_args == 1+ PrimOpId {} -> False+ _ -> all_pred_args n_val_args (idType fn)++ where+ -- See if all the arguments are PredTys (implicit params or classes)+ -- If so we'll regard it as expandable; see Note [Expandable overloadings]+ all_pred_args n_val_args ty+ | n_val_args == 0+ = True++ | Just (bndr, ty) <- splitPiTy_maybe ty+ = caseBinder bndr+ (\_tv -> all_pred_args n_val_args ty)+ (\bndr_ty -> isPredTy bndr_ty && all_pred_args (n_val_args-1) ty)++ | otherwise+ = False++{- Note [Record selection]+~~~~~~~~~~~~~~~~~~~~~~~~~~+I'm experimenting with making record selection+look cheap, so we will substitute it inside a+lambda. Particularly for dictionary field selection.++BUT: Take care with (sel d x)! The (sel d) might be cheap, but+there's no guarantee that (sel d x) will be too. Hence (n_val_args == 1)++Note [Expandable overloadings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose the user wrote this+ {-# RULE forall x. foo (negate x) = h x #-}+ f x = ....(foo (negate x))....+He'd expect the rule to fire. But since negate is overloaded, we might+get this:+ f = \d -> let n = negate d in \x -> ...foo (n x)...+So we treat the application of a function (negate in this case) to a+*dictionary* as expandable. In effect, every function is CONLIKE when+it's applied only to dictionaries.+++************************************************************************+* *+ exprOkForSpeculation+* *+************************************************************************+-}++-----------------------------+-- | 'exprOkForSpeculation' returns True of an expression that is:+--+-- * Safe to evaluate even if normal order eval might not+-- evaluate the expression at all, or+--+-- * Safe /not/ to evaluate even if normal order would do so+--+-- It is usually called on arguments of unlifted type, but not always+-- In particular, Simplify.rebuildCase calls it on lifted types+-- when a 'case' is a plain 'seq'. See the example in+-- Note [exprOkForSpeculation: case expressions] below+--+-- Precisely, it returns @True@ iff:+-- a) The expression guarantees to terminate,+-- b) soon,+-- c) without causing a write side effect (e.g. writing a mutable variable)+-- d) without throwing a Haskell exception+-- e) without risking an unchecked runtime exception (array out of bounds,+-- divide by zero)+--+-- For @exprOkForSideEffects@ the list is the same, but omitting (e).+--+-- Note that+-- exprIsHNF implies exprOkForSpeculation+-- exprOkForSpeculation implies exprOkForSideEffects+--+-- See Note [PrimOp can_fail and has_side_effects] in PrimOp+-- and Note [Implementation: how can_fail/has_side_effects affect transformations]+--+-- As an example of the considerations in this test, consider:+--+-- > let x = case y# +# 1# of { r# -> I# r# }+-- > in E+--+-- being translated to:+--+-- > case y# +# 1# of { r# ->+-- > let x = I# r#+-- > in E+-- > }+--+-- We can only do this if the @y + 1@ is ok for speculation: it has no+-- side effects, and can't diverge or raise an exception.+exprOkForSpeculation, exprOkForSideEffects :: Expr b -> Bool+exprOkForSpeculation = expr_ok primOpOkForSpeculation+exprOkForSideEffects = expr_ok primOpOkForSideEffects+ -- Polymorphic in binder type+ -- There is one call at a non-Id binder type, in SetLevels++expr_ok :: (PrimOp -> Bool) -> Expr b -> Bool+expr_ok _ (Lit _) = True+expr_ok _ (Type _) = True+expr_ok _ (Coercion _) = True+expr_ok primop_ok (Var v) = app_ok primop_ok v []+expr_ok primop_ok (Cast e _) = expr_ok primop_ok e++-- Tick annotations that *tick* cannot be speculated, because these+-- are meant to identify whether or not (and how often) the particular+-- source expression was evaluated at runtime.+expr_ok primop_ok (Tick tickish e)+ | tickishCounts tickish = False+ | otherwise = expr_ok primop_ok e++expr_ok primop_ok (Case e _ _ alts)+ = expr_ok primop_ok e -- Note [exprOkForSpeculation: case expressions]+ && all (\(_,_,rhs) -> expr_ok primop_ok rhs) alts+ && altsAreExhaustive alts -- Note [Exhaustive alts]++expr_ok primop_ok other_expr+ = case collectArgs other_expr of+ (expr, args) | Var f <- stripTicksTopE (not . tickishCounts) expr+ -> app_ok primop_ok f args+ _ -> False++-----------------------------+app_ok :: (PrimOp -> Bool) -> Id -> [Expr b] -> Bool+app_ok primop_ok fun args+ = case idDetails fun of+ DFunId new_type -> not new_type+ -- DFuns terminate, unless the dict is implemented+ -- with a newtype in which case they may not++ DataConWorkId {} -> True+ -- The strictness of the constructor has already+ -- been expressed by its "wrapper", so we don't need+ -- to take the arguments into account++ PrimOpId op+ | isDivOp op+ , [arg1, Lit lit] <- args+ -> not (isZeroLit lit) && expr_ok primop_ok arg1+ -- Special case for dividing operations that fail+ -- In general they are NOT ok-for-speculation+ -- (which primop_ok will catch), but they ARE OK+ -- if the divisor is definitely non-zero.+ -- Often there is a literal divisor, and this+ -- can get rid of a thunk in an inner loop++ | otherwise+ -> primop_ok op -- Check the primop itself+ && and (zipWith arg_ok arg_tys args) -- Check the arguments++ _other -> isUnliftedType (idType fun) -- c.f. the Var case of exprIsHNF+ || idArity fun > n_val_args -- Partial apps+ || (n_val_args == 0 &&+ isEvaldUnfolding (idUnfolding fun)) -- Let-bound values+ where+ n_val_args = valArgCount args+ where+ (arg_tys, _) = splitPiTys (idType fun)++ arg_ok :: TyBinder -> Expr b -> Bool+ arg_ok (Named _) _ = True -- A type argument+ arg_ok (Anon ty) arg -- A term argument+ | isUnliftedType ty = expr_ok primop_ok arg+ | otherwise = True -- See Note [Primops with lifted arguments]++-----------------------------+altsAreExhaustive :: [Alt b] -> Bool+-- True <=> the case alternatives are definiely exhaustive+-- False <=> they may or may not be+altsAreExhaustive []+ = False -- Should not happen+altsAreExhaustive ((con1,_,_) : alts)+ = case con1 of+ DEFAULT -> True+ LitAlt {} -> False+ DataAlt c -> 1 + length alts == tyConFamilySize (dataConTyCon c)+ -- It is possible to have an exhaustive case that does not+ -- enumerate all constructors, notably in a GADT match, but+ -- we behave conservatively here -- I don't think it's important+ -- enough to deserve special treatment++-- | True of dyadic operators that can fail only if the second arg is zero!+isDivOp :: PrimOp -> Bool+-- This function probably belongs in PrimOp, or even in+-- an automagically generated file.. but it's such a+-- special case I thought I'd leave it here for now.+isDivOp IntQuotOp = True+isDivOp IntRemOp = True+isDivOp WordQuotOp = True+isDivOp WordRemOp = True+isDivOp FloatDivOp = True+isDivOp DoubleDivOp = True+isDivOp _ = False++{-+Note [exprOkForSpeculation: case expressions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's always sound for exprOkForSpeculation to return False, and we+don't want it to take too long, so it bales out on complicated-looking+terms. Notably lets, which can be stacked very deeply; and in any+case the argument of exprOkForSpeculation is usually in a strict context,+so any lets will have been floated away.++However, we keep going on case-expressions. An example like this one+showed up in DPH code (Trac #3717):+ foo :: Int -> Int+ foo 0 = 0+ foo n = (if n < 5 then 1 else 2) `seq` foo (n-1)++If exprOkForSpeculation doesn't look through case expressions, you get this:+ T.$wfoo =+ \ (ww :: GHC.Prim.Int#) ->+ case ww of ds {+ __DEFAULT -> case (case <# ds 5 of _ {+ GHC.Types.False -> lvl1;+ GHC.Types.True -> lvl})+ of _ { __DEFAULT ->+ T.$wfoo (GHC.Prim.-# ds_XkE 1) };+ 0 -> 0+ }++The inner case is redundant, and should be nuked.++Note [Exhaustive alts]+~~~~~~~~~~~~~~~~~~~~~~+We might have something like+ case x of {+ A -> ...+ _ -> ...(case x of { B -> ...; C -> ... })...+Here, the inner case is fine, because the A alternative+can't happen, but it's not ok to float the inner case outside+the outer one (even if we know x is evaluated outside), because+then it would be non-exhaustive. See Trac #5453.++Similarly, this is a valid program (albeit a slightly dodgy one)+ let v = case x of { B -> ...; C -> ... }+ in case x of+ A -> ...+ _ -> ...v...v....+But we don't want to speculate the v binding.++One could try to be clever, but the easy fix is simpy to regard+a non-exhaustive case as *not* okForSpeculation.+++Note [Primops with lifted arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Is this ok-for-speculation (see Trac #13027)?+ reallyUnsafePtrEq# a b+Well, yes. The primop accepts lifted arguments and does not+evaluate them. Indeed, in general primops are, well, primitive+and do not perform evaluation.++There is one primop, dataToTag#, which does /require/ a lifted+argument to be evaluted. To ensure this, CorePrep adds an+eval if it can't see the the argument is definitely evaluated+(see [dataToTag magic] in CorePrep).++We make no attempt to guarantee that dataToTag#'s argument is+evaluated here. Main reason: it's very fragile to test for the+evaluatedness of a lifted argument. Consider+ case x of y -> let v = dataToTag# y in ...++where x/y have type Int, say. 'y' looks evaluated (by the enclosing+case) so all is well. Now the FloatOut pass does a binder-swap (for+very good reasons), changing to+ case x of y -> let v = dataToTag# x in ...++See also Note [dataToTag#] in primops.txt.pp.++Bottom line:+ * in exprOkForSpeculation we simply ignore all lifted arguments.+++************************************************************************+* *+ exprIsHNF, exprIsConLike+* *+************************************************************************+-}++-- Note [exprIsHNF] See also Note [exprIsCheap and exprIsHNF]+-- ~~~~~~~~~~~~~~~~+-- | exprIsHNF returns true for expressions that are certainly /already/+-- evaluated to /head/ normal form. This is used to decide whether it's ok+-- to change:+--+-- > case x of _ -> e+--+-- into:+--+-- > e+--+-- and to decide whether it's safe to discard a 'seq'.+--+-- So, it does /not/ treat variables as evaluated, unless they say they are.+-- However, it /does/ treat partial applications and constructor applications+-- as values, even if their arguments are non-trivial, provided the argument+-- type is lifted. For example, both of these are values:+--+-- > (:) (f x) (map f xs)+-- > map (...redex...)+--+-- because 'seq' on such things completes immediately.+--+-- For unlifted argument types, we have to be careful:+--+-- > C (f x :: Int#)+--+-- Suppose @f x@ diverges; then @C (f x)@ is not a value. However this can't+-- happen: see "CoreSyn#let_app_invariant". This invariant states that arguments of+-- unboxed type must be ok-for-speculation (or trivial).+exprIsHNF :: CoreExpr -> Bool -- True => Value-lambda, constructor, PAP+exprIsHNF = exprIsHNFlike isDataConWorkId isEvaldUnfolding++-- | Similar to 'exprIsHNF' but includes CONLIKE functions as well as+-- data constructors. Conlike arguments are considered interesting by the+-- inliner.+exprIsConLike :: CoreExpr -> Bool -- True => lambda, conlike, PAP+exprIsConLike = exprIsHNFlike isConLikeId isConLikeUnfolding++-- | Returns true for values or value-like expressions. These are lambdas,+-- constructors / CONLIKE functions (as determined by the function argument)+-- or PAPs.+--+exprIsHNFlike :: (Var -> Bool) -> (Unfolding -> Bool) -> CoreExpr -> Bool+exprIsHNFlike is_con is_con_unf = is_hnf_like+ where+ is_hnf_like (Var v) -- NB: There are no value args at this point+ = is_con v -- Catches nullary constructors,+ -- so that [] and () are values, for example+ || idArity v > 0 -- Catches (e.g.) primops that don't have unfoldings+ || is_con_unf (idUnfolding v)+ -- Check the thing's unfolding; it might be bound to a value+ -- We don't look through loop breakers here, which is a bit conservative+ -- but otherwise I worry that if an Id's unfolding is just itself,+ -- we could get an infinite loop++ is_hnf_like (Lit _) = True+ is_hnf_like (Type _) = True -- Types are honorary Values;+ -- we don't mind copying them+ is_hnf_like (Coercion _) = True -- Same for coercions+ is_hnf_like (Lam b e) = isRuntimeVar b || is_hnf_like e+ is_hnf_like (Tick tickish e) = not (tickishCounts tickish)+ && is_hnf_like e+ -- See Note [exprIsHNF Tick]+ is_hnf_like (Cast e _) = is_hnf_like e+ is_hnf_like (App e a)+ | isValArg a = app_is_value e 1+ | otherwise = is_hnf_like e+ is_hnf_like (Let _ e) = is_hnf_like e -- Lazy let(rec)s don't affect us+ is_hnf_like _ = False++ -- There is at least one value argument+ -- 'n' is number of value args to which the expression is applied+ app_is_value :: CoreExpr -> Int -> Bool+ app_is_value (Var fun) n_val_args+ = idArity fun > n_val_args -- Under-applied function+ || is_con fun -- or constructor-like+ app_is_value (Tick _ f) nva = app_is_value f nva+ app_is_value (Cast f _) nva = app_is_value f nva+ app_is_value (App f a) nva+ | isValArg a = app_is_value f (nva + 1)+ | otherwise = app_is_value f nva+ app_is_value _ _ = False++{-+Note [exprIsHNF Tick]++We can discard source annotations on HNFs as long as they aren't+tick-like:++ scc c (\x . e) => \x . e+ scc c (C x1..xn) => C x1..xn++So we regard these as HNFs. Tick annotations that tick are not+regarded as HNF if the expression they surround is HNF, because the+tick is there to tell us that the expression was evaluated, so we+don't want to discard a seq on it.+-}++-- | Can we bind this 'CoreExpr' at the top level?+exprIsTopLevelBindable :: CoreExpr -> Type -> Bool+-- See Note [CoreSyn top-level string literals]+-- Precondition: exprType expr = ty+exprIsTopLevelBindable expr ty+ = exprIsLiteralString expr+ || not (isUnliftedType ty)++exprIsLiteralString :: CoreExpr -> Bool+exprIsLiteralString (Lit (MachStr _)) = True+exprIsLiteralString _ = False++{-+************************************************************************+* *+ Instantiating data constructors+* *+************************************************************************++These InstPat functions go here to avoid circularity between DataCon and Id+-}++dataConRepInstPat :: [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])+dataConRepFSInstPat :: [FastString] -> [Unique] -> DataCon -> [Type] -> ([TyVar], [Id])++dataConRepInstPat = dataConInstPat (repeat ((fsLit "ipv")))+dataConRepFSInstPat = dataConInstPat++dataConInstPat :: [FastString] -- A long enough list of FSs to use for names+ -> [Unique] -- An equally long list of uniques, at least one for each binder+ -> DataCon+ -> [Type] -- Types to instantiate the universally quantified tyvars+ -> ([TyVar], [Id]) -- Return instantiated variables+-- dataConInstPat arg_fun fss us con inst_tys returns a tuple+-- (ex_tvs, arg_ids),+--+-- ex_tvs are intended to be used as binders for existential type args+--+-- arg_ids are indended to be used as binders for value arguments,+-- and their types have been instantiated with inst_tys and ex_tys+-- The arg_ids include both evidence and+-- programmer-specified arguments (both after rep-ing)+--+-- Example.+-- The following constructor T1+--+-- data T a where+-- T1 :: forall b. Int -> b -> T(a,b)+-- ...+--+-- has representation type+-- forall a. forall a1. forall b. (a ~ (a1,b)) =>+-- Int -> b -> T a+--+-- dataConInstPat fss us T1 (a1',b') will return+--+-- ([a1'', b''], [c :: (a1', b')~(a1'', b''), x :: Int, y :: b''])+--+-- where the double-primed variables are created with the FastStrings and+-- Uniques given as fss and us+dataConInstPat fss uniqs con inst_tys+ = ASSERT( univ_tvs `equalLength` inst_tys )+ (ex_bndrs, arg_ids)+ where+ univ_tvs = dataConUnivTyVars con+ ex_tvs = dataConExTyVars con+ arg_tys = dataConRepArgTys con+ arg_strs = dataConRepStrictness con -- 1-1 with arg_tys+ n_ex = length ex_tvs++ -- split the Uniques and FastStrings+ (ex_uniqs, id_uniqs) = splitAt n_ex uniqs+ (ex_fss, id_fss) = splitAt n_ex fss++ -- Make the instantiating substitution for universals+ univ_subst = zipTvSubst univ_tvs inst_tys++ -- Make existential type variables, applying and extending the substitution+ (full_subst, ex_bndrs) = mapAccumL mk_ex_var univ_subst+ (zip3 ex_tvs ex_fss ex_uniqs)++ mk_ex_var :: TCvSubst -> (TyVar, FastString, Unique) -> (TCvSubst, TyVar)+ mk_ex_var subst (tv, fs, uniq) = (Type.extendTvSubstWithClone subst tv+ new_tv+ , new_tv)+ where+ new_tv = mkTyVar (mkSysTvName uniq fs) kind+ kind = Type.substTyUnchecked subst (tyVarKind tv)++ -- Make value vars, instantiating types+ arg_ids = zipWith4 mk_id_var id_uniqs id_fss arg_tys arg_strs+ mk_id_var uniq fs ty str+ = setCaseBndrEvald str $ -- See Note [Mark evaluated arguments]+ mkLocalIdOrCoVar name (Type.substTy full_subst ty)+ where+ name = mkInternalName uniq (mkVarOccFS fs) noSrcSpan++{-+Note [Mark evaluated arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When pattern matching on a constructor with strict fields, the binder+can have an 'evaldUnfolding'. Moreover, it *should* have one, so that+when loading an interface file unfolding like:+ data T = MkT !Int+ f x = case x of { MkT y -> let v::Int# = case y of I# n -> n+1+ in ... }+we don't want Lint to complain. The 'y' is evaluated, so the+case in the RHS of the binding for 'v' is fine. But only if we+*know* that 'y' is evaluated.++c.f. add_evals in Simplify.simplAlt++************************************************************************+* *+ Equality+* *+************************************************************************+-}++-- | A cheap equality test which bales out fast!+-- If it returns @True@ the arguments are definitely equal,+-- otherwise, they may or may not be equal.+--+-- See also 'exprIsBig'+cheapEqExpr :: Expr b -> Expr b -> Bool+cheapEqExpr = cheapEqExpr' (const False)++-- | Cheap expression equality test, can ignore ticks by type.+cheapEqExpr' :: (Tickish Id -> Bool) -> Expr b -> Expr b -> Bool+cheapEqExpr' ignoreTick = go_s+ where go_s = go `on` stripTicksTopE ignoreTick+ go (Var v1) (Var v2) = v1 == v2+ go (Lit lit1) (Lit lit2) = lit1 == lit2+ go (Type t1) (Type t2) = t1 `eqType` t2+ go (Coercion c1) (Coercion c2) = c1 `eqCoercion` c2++ go (App f1 a1) (App f2 a2)+ = f1 `go_s` f2 && a1 `go_s` a2++ go (Cast e1 t1) (Cast e2 t2)+ = e1 `go_s` e2 && t1 `eqCoercion` t2++ go (Tick t1 e1) (Tick t2 e2)+ = t1 == t2 && e1 `go_s` e2++ go _ _ = False+ {-# INLINE go #-}+{-# INLINE cheapEqExpr' #-}++exprIsBig :: Expr b -> Bool+-- ^ Returns @True@ of expressions that are too big to be compared by 'cheapEqExpr'+exprIsBig (Lit _) = False+exprIsBig (Var _) = False+exprIsBig (Type _) = False+exprIsBig (Coercion _) = False+exprIsBig (Lam _ e) = exprIsBig e+exprIsBig (App f a) = exprIsBig f || exprIsBig a+exprIsBig (Cast e _) = exprIsBig e -- Hopefully coercions are not too big!+exprIsBig (Tick _ e) = exprIsBig e+exprIsBig _ = True++eqExpr :: InScopeSet -> CoreExpr -> CoreExpr -> Bool+-- Compares for equality, modulo alpha+eqExpr in_scope e1 e2+ = go (mkRnEnv2 in_scope) e1 e2+ where+ go env (Var v1) (Var v2)+ | rnOccL env v1 == rnOccR env v2+ = True++ go _ (Lit lit1) (Lit lit2) = lit1 == lit2+ go env (Type t1) (Type t2) = eqTypeX env t1 t2+ go env (Coercion co1) (Coercion co2) = eqCoercionX env co1 co2+ go env (Cast e1 co1) (Cast e2 co2) = eqCoercionX env co1 co2 && go env e1 e2+ go env (App f1 a1) (App f2 a2) = go env f1 f2 && go env a1 a2+ go env (Tick n1 e1) (Tick n2 e2) = eqTickish env n1 n2 && go env e1 e2++ go env (Lam b1 e1) (Lam b2 e2)+ = eqTypeX env (varType b1) (varType b2) -- False for Id/TyVar combination+ && go (rnBndr2 env b1 b2) e1 e2++ go env (Let (NonRec v1 r1) e1) (Let (NonRec v2 r2) e2)+ = go env r1 r2 -- No need to check binder types, since RHSs match+ && go (rnBndr2 env v1 v2) e1 e2++ go env (Let (Rec ps1) e1) (Let (Rec ps2) e2)+ = length ps1 == length ps2+ && all2 (go env') rs1 rs2 && go env' e1 e2+ where+ (bs1,rs1) = unzip ps1+ (bs2,rs2) = unzip ps2+ env' = rnBndrs2 env bs1 bs2++ go env (Case e1 b1 t1 a1) (Case e2 b2 t2 a2)+ | null a1 -- See Note [Empty case alternatives] in TrieMap+ = null a2 && go env e1 e2 && eqTypeX env t1 t2+ | otherwise+ = go env e1 e2 && all2 (go_alt (rnBndr2 env b1 b2)) a1 a2++ go _ _ _ = False++ -----------+ go_alt env (c1, bs1, e1) (c2, bs2, e2)+ = c1 == c2 && go (rnBndrs2 env bs1 bs2) e1 e2++eqTickish :: RnEnv2 -> Tickish Id -> Tickish Id -> Bool+eqTickish env (Breakpoint lid lids) (Breakpoint rid rids)+ = lid == rid && map (rnOccL env) lids == map (rnOccR env) rids+eqTickish _ l r = l == r++-- | Finds differences between core expressions, modulo alpha and+-- renaming. Setting @top@ means that the @IdInfo@ of bindings will be+-- checked for differences as well.+diffExpr :: Bool -> RnEnv2 -> CoreExpr -> CoreExpr -> [SDoc]+diffExpr _ env (Var v1) (Var v2) | rnOccL env v1 == rnOccR env v2 = []+diffExpr _ _ (Lit lit1) (Lit lit2) | lit1 == lit2 = []+diffExpr _ env (Type t1) (Type t2) | eqTypeX env t1 t2 = []+diffExpr _ env (Coercion co1) (Coercion co2)+ | eqCoercionX env co1 co2 = []+diffExpr top env (Cast e1 co1) (Cast e2 co2)+ | eqCoercionX env co1 co2 = diffExpr top env e1 e2+diffExpr top env (Tick n1 e1) e2+ | not (tickishIsCode n1) = diffExpr top env e1 e2+diffExpr top env e1 (Tick n2 e2)+ | not (tickishIsCode n2) = diffExpr top env e1 e2+diffExpr top env (Tick n1 e1) (Tick n2 e2)+ | eqTickish env n1 n2 = diffExpr top env e1 e2+ -- The error message of failed pattern matches will contain+ -- generated names, which are allowed to differ.+diffExpr _ _ (App (App (Var absent) _) _)+ (App (App (Var absent2) _) _)+ | isBottomingId absent && isBottomingId absent2 = []+diffExpr top env (App f1 a1) (App f2 a2)+ = diffExpr top env f1 f2 ++ diffExpr top env a1 a2+diffExpr top env (Lam b1 e1) (Lam b2 e2)+ | eqTypeX env (varType b1) (varType b2) -- False for Id/TyVar combination+ = diffExpr top (rnBndr2 env b1 b2) e1 e2+diffExpr top env (Let bs1 e1) (Let bs2 e2)+ = let (ds, env') = diffBinds top env (flattenBinds [bs1]) (flattenBinds [bs2])+ in ds ++ diffExpr top env' e1 e2+diffExpr top env (Case e1 b1 t1 a1) (Case e2 b2 t2 a2)+ | length a1 == length a2 && not (null a1) || eqTypeX env t1 t2+ -- See Note [Empty case alternatives] in TrieMap+ = diffExpr top env e1 e2 ++ concat (zipWith diffAlt a1 a2)+ where env' = rnBndr2 env b1 b2+ diffAlt (c1, bs1, e1) (c2, bs2, e2)+ | c1 /= c2 = [text "alt-cons " <> ppr c1 <> text " /= " <> ppr c2]+ | otherwise = diffExpr top (rnBndrs2 env' bs1 bs2) e1 e2+diffExpr _ _ e1 e2+ = [fsep [ppr e1, text "/=", ppr e2]]++-- | Finds differences between core bindings, see @diffExpr@.+--+-- The main problem here is that while we expect the binds to have the+-- same order in both lists, this is not guaranteed. To do this+-- properly we'd either have to do some sort of unification or check+-- all possible mappings, which would be seriously expensive. So+-- instead we simply match single bindings as far as we can. This+-- leaves us just with mutually recursive and/or mismatching bindings,+-- which we then speculatively match by ordering them. It's by no means+-- perfect, but gets the job done well enough.+diffBinds :: Bool -> RnEnv2 -> [(Var, CoreExpr)] -> [(Var, CoreExpr)]+ -> ([SDoc], RnEnv2)+diffBinds top env binds1 = go (length binds1) env binds1+ where go _ env [] []+ = ([], env)+ go fuel env binds1 binds2+ -- No binds left to compare? Bail out early.+ | null binds1 || null binds2+ = (warn env binds1 binds2, env)+ -- Iterated over all binds without finding a match? Then+ -- try speculatively matching binders by order.+ | fuel == 0+ = if not $ env `inRnEnvL` fst (head binds1)+ then let env' = uncurry (rnBndrs2 env) $ unzip $+ zip (sort $ map fst binds1) (sort $ map fst binds2)+ in go (length binds1) env' binds1 binds2+ -- If we have already tried that, give up+ else (warn env binds1 binds2, env)+ go fuel env ((bndr1,expr1):binds1) binds2+ | let matchExpr (bndr,expr) =+ (not top || null (diffIdInfo env bndr bndr1)) &&+ null (diffExpr top (rnBndr2 env bndr1 bndr) expr1 expr)+ , (binds2l, (bndr2,_):binds2r) <- break matchExpr binds2+ = go (length binds1) (rnBndr2 env bndr1 bndr2)+ binds1 (binds2l ++ binds2r)+ | otherwise -- No match, so push back (FIXME O(n^2))+ = go (fuel-1) env (binds1++[(bndr1,expr1)]) binds2+ go _ _ _ _ = panic "diffBinds: impossible" -- GHC isn't smart enough++ -- We have tried everything, but couldn't find a good match. So+ -- now we just return the comparison results when we pair up+ -- the binds in a pseudo-random order.+ warn env binds1 binds2 =+ concatMap (uncurry (diffBind env)) (zip binds1' binds2') +++ unmatched "unmatched left-hand:" (drop l binds1') +++ unmatched "unmatched right-hand:" (drop l binds2')+ where binds1' = sortBy (comparing fst) binds1+ binds2' = sortBy (comparing fst) binds2+ l = min (length binds1') (length binds2')+ unmatched _ [] = []+ unmatched txt bs = [text txt $$ ppr (Rec bs)]+ diffBind env (bndr1,expr1) (bndr2,expr2)+ | ds@(_:_) <- diffExpr top env expr1 expr2+ = locBind "in binding" bndr1 bndr2 ds+ | otherwise+ = diffIdInfo env bndr1 bndr2++-- | Find differences in @IdInfo@. We will especially check whether+-- the unfoldings match, if present (see @diffUnfold@).+diffIdInfo :: RnEnv2 -> Var -> Var -> [SDoc]+diffIdInfo env bndr1 bndr2+ | arityInfo info1 == arityInfo info2+ && cafInfo info1 == cafInfo info2+ && oneShotInfo info1 == oneShotInfo info2+ && inlinePragInfo info1 == inlinePragInfo info2+ && occInfo info1 == occInfo info2+ && demandInfo info1 == demandInfo info2+ && callArityInfo info1 == callArityInfo info2+ && levityInfo info1 == levityInfo info2+ = locBind "in unfolding of" bndr1 bndr2 $+ diffUnfold env (unfoldingInfo info1) (unfoldingInfo info2)+ | otherwise+ = locBind "in Id info of" bndr1 bndr2+ [fsep [pprBndr LetBind bndr1, text "/=", pprBndr LetBind bndr2]]+ where info1 = idInfo bndr1; info2 = idInfo bndr2++-- | Find differences in unfoldings. Note that we will not check for+-- differences of @IdInfo@ in unfoldings, as this is generally+-- redundant, and can lead to an exponential blow-up in complexity.+diffUnfold :: RnEnv2 -> Unfolding -> Unfolding -> [SDoc]+diffUnfold _ NoUnfolding NoUnfolding = []+diffUnfold _ BootUnfolding BootUnfolding = []+diffUnfold _ (OtherCon cs1) (OtherCon cs2) | cs1 == cs2 = []+diffUnfold env (DFunUnfolding bs1 c1 a1)+ (DFunUnfolding bs2 c2 a2)+ | c1 == c2 && length bs1 == length bs2+ = concatMap (uncurry (diffExpr False env')) (zip a1 a2)+ where env' = rnBndrs2 env bs1 bs2+diffUnfold env (CoreUnfolding t1 _ _ v1 cl1 wf1 x1 g1)+ (CoreUnfolding t2 _ _ v2 cl2 wf2 x2 g2)+ | v1 == v2 && cl1 == cl2+ && wf1 == wf2 && x1 == x2 && g1 == g2+ = diffExpr False env t1 t2+diffUnfold _ uf1 uf2+ = [fsep [ppr uf1, text "/=", ppr uf2]]++-- | Add location information to diff messages+locBind :: String -> Var -> Var -> [SDoc] -> [SDoc]+locBind loc b1 b2 diffs = map addLoc diffs+ where addLoc d = d $$ nest 2 (parens (text loc <+> bindLoc))+ bindLoc | b1 == b2 = ppr b1+ | otherwise = ppr b1 <> char '/' <> ppr b2++{-+************************************************************************+* *+ Eta reduction+* *+************************************************************************++Note [Eta reduction conditions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We try for eta reduction here, but *only* if we get all the way to an+trivial expression. We don't want to remove extra lambdas unless we+are going to avoid allocating this thing altogether.++There are some particularly delicate points here:++* We want to eta-reduce if doing so leaves a trivial expression,+ *including* a cast. For example+ \x. f |> co --> f |> co+ (provided co doesn't mention x)++* Eta reduction is not valid in general:+ \x. bot /= bot+ This matters, partly for old-fashioned correctness reasons but,+ worse, getting it wrong can yield a seg fault. Consider+ f = \x.f x+ h y = case (case y of { True -> f `seq` True; False -> False }) of+ True -> ...; False -> ...++ If we (unsoundly) eta-reduce f to get f=f, the strictness analyser+ says f=bottom, and replaces the (f `seq` True) with just+ (f `cast` unsafe-co). BUT, as thing stand, 'f' got arity 1, and it+ *keeps* arity 1 (perhaps also wrongly). So CorePrep eta-expands+ the definition again, so that it does not termninate after all.+ Result: seg-fault because the boolean case actually gets a function value.+ See Trac #1947.++ So it's important to do the right thing.++* Note [Arity care]: we need to be careful if we just look at f's+ arity. Currently (Dec07), f's arity is visible in its own RHS (see+ Note [Arity robustness] in SimplEnv) so we must *not* trust the+ arity when checking that 'f' is a value. Otherwise we will+ eta-reduce+ f = \x. f x+ to+ f = f+ Which might change a terminating program (think (f `seq` e)) to a+ non-terminating one. So we check for being a loop breaker first.++ However for GlobalIds we can look at the arity; and for primops we+ must, since they have no unfolding.++* Regardless of whether 'f' is a value, we always want to+ reduce (/\a -> f a) to f+ This came up in a RULE: foldr (build (/\a -> g a))+ did not match foldr (build (/\b -> ...something complex...))+ The type checker can insert these eta-expanded versions,+ with both type and dictionary lambdas; hence the slightly+ ad-hoc isDictId++* Never *reduce* arity. For example+ f = \xy. g x y+ Then if h has arity 1 we don't want to eta-reduce because then+ f's arity would decrease, and that is bad++These delicacies are why we don't use exprIsTrivial and exprIsHNF here.+Alas.++Note [Eta reduction with casted arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ (\(x:t3). f (x |> g)) :: t3 -> t2+ where+ f :: t1 -> t2+ g :: t3 ~ t1+This should be eta-reduced to++ f |> (sym g -> t2)++So we need to accumulate a coercion, pushing it inward (past+variable arguments only) thus:+ f (x |> co_arg) |> co --> (f |> (sym co_arg -> co)) x+ f (x:t) |> co --> (f |> (t -> co)) x+ f @ a |> co --> (f |> (forall a.co)) @ a+ f @ (g:t1~t2) |> co --> (f |> (t1~t2 => co)) @ (g:t1~t2)+These are the equations for ok_arg.++It's true that we could also hope to eta reduce these:+ (\xy. (f x |> g) y)+ (\xy. (f x y) |> g)+But the simplifier pushes those casts outwards, so we don't+need to address that here.+-}++tryEtaReduce :: [Var] -> CoreExpr -> Maybe CoreExpr+tryEtaReduce bndrs body+ = go (reverse bndrs) body (mkRepReflCo (exprType body))+ where+ incoming_arity = count isId bndrs++ go :: [Var] -- Binders, innermost first, types [a3,a2,a1]+ -> CoreExpr -- Of type tr+ -> Coercion -- Of type tr ~ ts+ -> Maybe CoreExpr -- Of type a1 -> a2 -> a3 -> ts+ -- See Note [Eta reduction with casted arguments]+ -- for why we have an accumulating coercion+ go [] fun co+ | ok_fun fun+ , let used_vars = exprFreeVars fun `unionVarSet` tyCoVarsOfCo co+ , not (any (`elemVarSet` used_vars) bndrs)+ = Just (mkCast fun co) -- Check for any of the binders free in the result+ -- including the accumulated coercion++ go bs (Tick t e) co+ | tickishFloatable t+ = fmap (Tick t) $ go bs e co+ -- Float app ticks: \x -> Tick t (e x) ==> Tick t e++ go (b : bs) (App fun arg) co+ | Just (co', ticks) <- ok_arg b arg co+ = fmap (flip (foldr mkTick) ticks) $ go bs fun co'+ -- Float arg ticks: \x -> e (Tick t x) ==> Tick t e++ go _ _ _ = Nothing -- Failure!++ ---------------+ -- Note [Eta reduction conditions]+ ok_fun (App fun (Type {})) = ok_fun fun+ ok_fun (Cast fun _) = ok_fun fun+ ok_fun (Tick _ expr) = ok_fun expr+ ok_fun (Var fun_id) = ok_fun_id fun_id || all ok_lam bndrs+ ok_fun _fun = False++ ---------------+ ok_fun_id fun = fun_arity fun >= incoming_arity++ ---------------+ fun_arity fun -- See Note [Arity care]+ | isLocalId fun+ , isStrongLoopBreaker (idOccInfo fun) = 0+ | arity > 0 = arity+ | isEvaldUnfolding (idUnfolding fun) = 1+ -- See Note [Eta reduction of an eval'd function]+ | otherwise = 0+ where+ arity = idArity fun++ ---------------+ ok_lam v = isTyVar v || isEvVar v++ ---------------+ ok_arg :: Var -- Of type bndr_t+ -> CoreExpr -- Of type arg_t+ -> Coercion -- Of kind (t1~t2)+ -> Maybe (Coercion -- Of type (arg_t -> t1 ~ bndr_t -> t2)+ -- (and similarly for tyvars, coercion args)+ , [Tickish Var])+ -- See Note [Eta reduction with casted arguments]+ ok_arg bndr (Type ty) co+ | Just tv <- getTyVar_maybe ty+ , bndr == tv = Just (mkHomoForAllCos [tv] co, [])+ ok_arg bndr (Var v) co+ | bndr == v = let reflCo = mkRepReflCo (idType bndr)+ in Just (mkFunCo Representational reflCo co, [])+ ok_arg bndr (Cast e co_arg) co+ | (ticks, Var v) <- stripTicksTop tickishFloatable e+ , bndr == v+ = Just (mkFunCo Representational (mkSymCo co_arg) co, ticks)+ -- The simplifier combines multiple casts into one,+ -- so we can have a simple-minded pattern match here+ ok_arg bndr (Tick t arg) co+ | tickishFloatable t, Just (co', ticks) <- ok_arg bndr arg co+ = Just (co', t:ticks)++ ok_arg _ _ _ = Nothing++{-+Note [Eta reduction of an eval'd function]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In Haskell it is not true that f = \x. f x+because f might be bottom, and 'seq' can distinguish them.++But it *is* true that f = f `seq` \x. f x+and we'd like to simplify the latter to the former. This amounts+to the rule that+ * when there is just *one* value argument,+ * f is not bottom+we can eta-reduce \x. f x ===> f++This turned up in Trac #7542.+++************************************************************************+* *+\subsection{Determining non-updatable right-hand-sides}+* *+************************************************************************++Top-level constructor applications can usually be allocated+statically, but they can't if the constructor, or any of the+arguments, come from another DLL (because we can't refer to static+labels in other DLLs).++If this happens we simply make the RHS into an updatable thunk,+and 'execute' it rather than allocating it statically.+-}++-- | This function is called only on *top-level* right-hand sides.+-- Returns @True@ if the RHS can be allocated statically in the output,+-- with no thunks involved at all.+rhsIsStatic :: Platform+ -> (Name -> Bool) -- Which names are dynamic+ -> (Integer -> CoreExpr) -- Desugaring for integer literals (disgusting)+ -- C.f. Note [Disgusting computation of CafRefs]+ -- in TidyPgm+ -> CoreExpr -> Bool+-- It's called (i) in TidyPgm.hasCafRefs to decide if the rhs is, or+-- refers to, CAFs; (ii) in CoreToStg to decide whether to put an+-- update flag on it and (iii) in DsExpr to decide how to expand+-- list literals+--+-- The basic idea is that rhsIsStatic returns True only if the RHS is+-- (a) a value lambda+-- (b) a saturated constructor application with static args+--+-- BUT watch out for+-- (i) Any cross-DLL references kill static-ness completely+-- because they must be 'executed' not statically allocated+-- ("DLL" here really only refers to Windows DLLs, on other platforms,+-- this is not necessary)+--+-- (ii) We treat partial applications as redexes, because in fact we+-- make a thunk for them that runs and builds a PAP+-- at run-time. The only applications that are treated as+-- static are *saturated* applications of constructors.++-- We used to try to be clever with nested structures like this:+-- ys = (:) w ((:) w [])+-- on the grounds that CorePrep will flatten ANF-ise it later.+-- But supporting this special case made the function much more+-- complicated, because the special case only applies if there are no+-- enclosing type lambdas:+-- ys = /\ a -> Foo (Baz ([] a))+-- Here the nested (Baz []) won't float out to top level in CorePrep.+--+-- But in fact, even without -O, nested structures at top level are+-- flattened by the simplifier, so we don't need to be super-clever here.+--+-- Examples+--+-- f = \x::Int. x+7 TRUE+-- p = (True,False) TRUE+--+-- d = (fst p, False) FALSE because there's a redex inside+-- (this particular one doesn't happen but...)+--+-- h = D# (1.0## /## 2.0##) FALSE (redex again)+-- n = /\a. Nil a TRUE+--+-- t = /\a. (:) (case w a of ...) (Nil a) FALSE (redex)+--+--+-- This is a bit like CoreUtils.exprIsHNF, with the following differences:+-- a) scc "foo" (\x -> ...) is updatable (so we catch the right SCC)+--+-- b) (C x xs), where C is a constructor is updatable if the application is+-- dynamic+--+-- c) don't look through unfolding of f in (f x).++rhsIsStatic platform is_dynamic_name cvt_integer rhs = is_static False rhs+ where+ is_static :: Bool -- True <=> in a constructor argument; must be atomic+ -> CoreExpr -> Bool++ is_static False (Lam b e) = isRuntimeVar b || is_static False e+ is_static in_arg (Tick n e) = not (tickishIsCode n)+ && is_static in_arg e+ is_static in_arg (Cast e _) = is_static in_arg e+ is_static _ (Coercion {}) = True -- Behaves just like a literal+ is_static in_arg (Lit (LitInteger i _)) = is_static in_arg (cvt_integer i)+ is_static _ (Lit (MachLabel {})) = False+ is_static _ (Lit _) = True+ -- A MachLabel (foreign import "&foo") in an argument+ -- prevents a constructor application from being static. The+ -- reason is that it might give rise to unresolvable symbols+ -- in the object file: under Linux, references to "weak"+ -- symbols from the data segment give rise to "unresolvable+ -- relocation" errors at link time This might be due to a bug+ -- in the linker, but we'll work around it here anyway.+ -- SDM 24/2/2004++ is_static in_arg other_expr = go other_expr 0+ where+ go (Var f) n_val_args+ | (platformOS platform /= OSMinGW32) ||+ not (is_dynamic_name (idName f))+ = saturated_data_con f n_val_args+ || (in_arg && n_val_args == 0)+ -- A naked un-applied variable is *not* deemed a static RHS+ -- E.g. f = g+ -- Reason: better to update so that the indirection gets shorted+ -- out, and the true value will be seen+ -- NB: if you change this, you'll break the invariant that THUNK_STATICs+ -- are always updatable. If you do so, make sure that non-updatable+ -- ones have enough space for their static link field!++ go (App f a) n_val_args+ | isTypeArg a = go f n_val_args+ | not in_arg && is_static True a = go f (n_val_args + 1)+ -- The (not in_arg) checks that we aren't in a constructor argument;+ -- if we are, we don't allow (value) applications of any sort+ --+ -- NB. In case you wonder, args are sometimes not atomic. eg.+ -- x = D# (1.0## /## 2.0##)+ -- can't float because /## can fail.++ go (Tick n f) n_val_args = not (tickishIsCode n) && go f n_val_args+ go (Cast e _) n_val_args = go e n_val_args+ go _ _ = False++ saturated_data_con f n_val_args+ = case isDataConWorkId_maybe f of+ Just dc -> n_val_args == dataConRepArity dc+ Nothing -> False++{-+************************************************************************+* *+\subsection{Type utilities}+* *+************************************************************************+-}++-- | True if the type has no non-bottom elements, e.g. when it is an empty+-- datatype, or a GADT with non-satisfiable type parameters, e.g. Int :~: Bool.+-- See Note [Bottoming expressions]+--+-- See Note [No alternatives lint check] for another use of this function.+isEmptyTy :: Type -> Bool+isEmptyTy ty+ -- Data types where, given the particular type parameters, no data+ -- constructor matches, are empty.+ -- This includes data types with no constructors, e.g. Data.Void.Void.+ | Just (tc, inst_tys) <- splitTyConApp_maybe ty+ , Just dcs <- tyConDataCons_maybe tc+ , all (dataConCannotMatch inst_tys) dcs+ = True+ | otherwise+ = False++{-+*****************************************************+*+* StaticPtr+*+*****************************************************+-}++-- | @collectMakeStaticArgs (makeStatic t srcLoc e)@ yields+-- @Just (makeStatic, t, srcLoc, e)@.+--+-- Returns @Nothing@ for every other expression.+collectMakeStaticArgs+ :: CoreExpr -> Maybe (CoreExpr, Type, CoreExpr, CoreExpr)+collectMakeStaticArgs e+ | (fun@(Var b), [Type t, loc, arg], _) <- collectArgsTicks (const True) e+ , idName b == makeStaticName = Just (fun, t, loc, arg)+collectMakeStaticArgs _ = Nothing++{-+************************************************************************+* *+\subsection{Join points}+* *+************************************************************************+-}++-- | Does this binding bind a join point (or a recursive group of join points)?+isJoinBind :: CoreBind -> Bool+isJoinBind (NonRec b _) = isJoinId b+isJoinBind (Rec ((b, _) : _)) = isJoinId b+isJoinBind _ = False
+ coreSyn/MkCore.hs view
@@ -0,0 +1,772 @@+{-# LANGUAGE CPP #-}++-- | Handy functions for creating much Core syntax+module MkCore (+ -- * Constructing normal syntax+ mkCoreLet, mkCoreLets,+ mkCoreApp, mkCoreApps, mkCoreConApps,+ mkCoreLams, mkWildCase, mkIfThenElse,+ mkWildValBinder, mkWildEvBinder,+ sortQuantVars, castBottomExpr,++ -- * Constructing boxed literals+ mkWordExpr, mkWordExprWord,+ mkIntExpr, mkIntExprInt,+ mkIntegerExpr, mkNaturalExpr,+ mkFloatExpr, mkDoubleExpr,+ mkCharExpr, mkStringExpr, mkStringExprFS, mkStringExprFSWith,++ -- * Floats+ FloatBind(..), wrapFloat,++ -- * Constructing small tuples+ mkCoreVarTup, mkCoreVarTupTy, mkCoreTup, mkCoreUbxTup,+ mkCoreTupBoxity, unitExpr,++ -- * Constructing big tuples+ mkBigCoreVarTup, mkBigCoreVarTup1,+ mkBigCoreVarTupTy, mkBigCoreTupTy,+ mkBigCoreTup,++ -- * Deconstructing small tuples+ mkSmallTupleSelector, mkSmallTupleCase,++ -- * Deconstructing big tuples+ mkTupleSelector, mkTupleSelector1, mkTupleCase,++ -- * Constructing list expressions+ mkNilExpr, mkConsExpr, mkListExpr,+ mkFoldrExpr, mkBuildExpr,++ -- * Constructing Maybe expressions+ mkNothingExpr, mkJustExpr,++ -- * Error Ids+ mkRuntimeErrorApp, mkImpossibleExpr, errorIds,+ rEC_CON_ERROR_ID, iRREFUT_PAT_ERROR_ID, rUNTIME_ERROR_ID,+ nON_EXHAUSTIVE_GUARDS_ERROR_ID, nO_METHOD_BINDING_ERROR_ID,+ pAT_ERROR_ID, rEC_SEL_ERROR_ID, aBSENT_ERROR_ID,+ tYPE_ERROR_ID,+ ) where++#include "HsVersions.h"++import Id+import Var ( EvVar, setTyVarUnique )++import CoreSyn+import CoreUtils ( exprType, needsCaseBinding, bindNonRec )+import Literal+import HscTypes++import TysWiredIn+import PrelNames++import HsUtils ( mkChunkified, chunkify )+import TcType ( mkSpecSigmaTy )+import Type+import Coercion ( isCoVar )+import TysPrim+import DataCon ( DataCon, dataConWorkId )+import IdInfo ( vanillaIdInfo, setStrictnessInfo,+ setArityInfo )+import Demand+import Name hiding ( varName )+import Outputable+import FastString+import UniqSupply+import BasicTypes+import Util+import DynFlags+import Data.List++import Data.Char ( ord )++infixl 4 `mkCoreApp`, `mkCoreApps`++{-+************************************************************************+* *+\subsection{Basic CoreSyn construction}+* *+************************************************************************+-}+sortQuantVars :: [Var] -> [Var]+-- Sort the variables, putting type and covars first, in scoped order,+-- and then other Ids+-- It is a deterministic sort, meaining it doesn't look at the values of+-- Uniques. For explanation why it's important See Note [Unique Determinism]+-- in Unique.+sortQuantVars vs = sorted_tcvs ++ ids+ where+ (tcvs, ids) = partition (isTyVar <||> isCoVar) vs+ sorted_tcvs = toposortTyVars tcvs++-- | Bind a binding group over an expression, using a @let@ or @case@ as+-- appropriate (see "CoreSyn#let_app_invariant")+mkCoreLet :: CoreBind -> CoreExpr -> CoreExpr+mkCoreLet (NonRec bndr rhs) body -- See Note [CoreSyn let/app invariant]+ | needsCaseBinding (idType bndr) rhs+ , not (isJoinId bndr)+ = Case rhs bndr (exprType body) [(DEFAULT,[],body)]+mkCoreLet bind body+ = Let bind body++-- | Bind a list of binding groups over an expression. The leftmost binding+-- group becomes the outermost group in the resulting expression+mkCoreLets :: [CoreBind] -> CoreExpr -> CoreExpr+mkCoreLets binds body = foldr mkCoreLet body binds++-- | Construct an expression which represents the application of one expression+-- to the other+mkCoreApp :: SDoc -> CoreExpr -> CoreExpr -> CoreExpr+-- Respects the let/app invariant by building a case expression where necessary+-- See CoreSyn Note [CoreSyn let/app invariant]+mkCoreApp _ fun (Type ty) = App fun (Type ty)+mkCoreApp _ fun (Coercion co) = App fun (Coercion co)+mkCoreApp d fun arg = ASSERT2( isFunTy fun_ty, ppr fun $$ ppr arg $$ d )+ mk_val_app fun arg arg_ty res_ty+ where+ fun_ty = exprType fun+ (arg_ty, res_ty) = splitFunTy fun_ty++-- | Construct an expression which represents the application of a number of+-- expressions to another. The leftmost expression in the list is applied first+-- Respects the let/app invariant by building a case expression where necessary+-- See CoreSyn Note [CoreSyn let/app invariant]+mkCoreApps :: CoreExpr -> [CoreExpr] -> CoreExpr+-- Slightly more efficient version of (foldl mkCoreApp)+mkCoreApps orig_fun orig_args+ = go orig_fun (exprType orig_fun) orig_args+ where+ go fun _ [] = fun+ go fun fun_ty (Type ty : args) = go (App fun (Type ty)) (piResultTy fun_ty ty) args+ go fun fun_ty (arg : args) = ASSERT2( isFunTy fun_ty, ppr fun_ty $$ ppr orig_fun+ $$ ppr orig_args )+ go (mk_val_app fun arg arg_ty res_ty) res_ty args+ where+ (arg_ty, res_ty) = splitFunTy fun_ty++-- | Construct an expression which represents the application of a number of+-- expressions to that of a data constructor expression. The leftmost expression+-- in the list is applied first+mkCoreConApps :: DataCon -> [CoreExpr] -> CoreExpr+mkCoreConApps con args = mkCoreApps (Var (dataConWorkId con)) args++mk_val_app :: CoreExpr -> CoreExpr -> Type -> Type -> CoreExpr+-- Build an application (e1 e2),+-- or a strict binding (case e2 of x -> e1 x)+-- using the latter when necessary to respect the let/app invariant+-- See Note [CoreSyn let/app invariant]+mk_val_app fun arg arg_ty res_ty+ | not (needsCaseBinding arg_ty arg)+ = App fun arg -- The vastly common case++ | otherwise+ = Case arg arg_id res_ty [(DEFAULT,[],App fun (Var arg_id))]+ where+ arg_id = mkWildValBinder arg_ty+ -- Lots of shadowing, but it doesn't matter,+ -- because 'fun ' should not have a free wild-id+ --+ -- This is Dangerous. But this is the only place we play this+ -- game, mk_val_app returns an expression that does not have+ -- have a free wild-id. So the only thing that can go wrong+ -- is if you take apart this case expression, and pass a+ -- fragment of it as the fun part of a 'mk_val_app'.++-----------+mkWildEvBinder :: PredType -> EvVar+mkWildEvBinder pred = mkWildValBinder pred++-- | Make a /wildcard binder/. This is typically used when you need a binder+-- that you expect to use only at a *binding* site. Do not use it at+-- occurrence sites because it has a single, fixed unique, and it's very+-- easy to get into difficulties with shadowing. That's why it is used so little.+-- See Note [WildCard binders] in SimplEnv+mkWildValBinder :: Type -> Id+mkWildValBinder ty = mkLocalIdOrCoVar wildCardName ty++mkWildCase :: CoreExpr -> Type -> Type -> [CoreAlt] -> CoreExpr+-- Make a case expression whose case binder is unused+-- The alts should not have any occurrences of WildId+mkWildCase scrut scrut_ty res_ty alts+ = Case scrut (mkWildValBinder scrut_ty) res_ty alts++mkIfThenElse :: CoreExpr -> CoreExpr -> CoreExpr -> CoreExpr+mkIfThenElse guard then_expr else_expr+-- Not going to be refining, so okay to take the type of the "then" clause+ = mkWildCase guard boolTy (exprType then_expr)+ [ (DataAlt falseDataCon, [], else_expr), -- Increasing order of tag!+ (DataAlt trueDataCon, [], then_expr) ]++castBottomExpr :: CoreExpr -> Type -> CoreExpr+-- (castBottomExpr e ty), assuming that 'e' diverges,+-- return an expression of type 'ty'+-- See Note [Empty case alternatives] in CoreSyn+castBottomExpr e res_ty+ | e_ty `eqType` res_ty = e+ | otherwise = Case e (mkWildValBinder e_ty) res_ty []+ where+ e_ty = exprType e++{-+The functions from this point don't really do anything cleverer than+their counterparts in CoreSyn, but they are here for consistency+-}++-- | Create a lambda where the given expression has a number of variables+-- bound over it. The leftmost binder is that bound by the outermost+-- lambda in the result+mkCoreLams :: [CoreBndr] -> CoreExpr -> CoreExpr+mkCoreLams = mkLams++{-+************************************************************************+* *+\subsection{Making literals}+* *+************************************************************************+-}++-- | Create a 'CoreExpr' which will evaluate to the given @Int@+mkIntExpr :: DynFlags -> Integer -> CoreExpr -- Result = I# i :: Int+mkIntExpr dflags i = mkCoreConApps intDataCon [mkIntLit dflags i]++-- | Create a 'CoreExpr' which will evaluate to the given @Int@+mkIntExprInt :: DynFlags -> Int -> CoreExpr -- Result = I# i :: Int+mkIntExprInt dflags i = mkCoreConApps intDataCon [mkIntLitInt dflags i]++-- | Create a 'CoreExpr' which will evaluate to the a @Word@ with the given value+mkWordExpr :: DynFlags -> Integer -> CoreExpr+mkWordExpr dflags w = mkCoreConApps wordDataCon [mkWordLit dflags w]++-- | Create a 'CoreExpr' which will evaluate to the given @Word@+mkWordExprWord :: DynFlags -> Word -> CoreExpr+mkWordExprWord dflags w = mkCoreConApps wordDataCon [mkWordLitWord dflags w]++-- | Create a 'CoreExpr' which will evaluate to the given @Integer@+mkIntegerExpr :: MonadThings m => Integer -> m CoreExpr -- Result :: Integer+mkIntegerExpr i = do t <- lookupTyCon integerTyConName+ return (Lit (mkLitInteger i (mkTyConTy t)))++-- | Create a 'CoreExpr' which will evaluate to the given @Natural@+--+-- TODO: should we add LitNatural to Core?+mkNaturalExpr :: MonadThings m => Integer -> m CoreExpr -- Result :: Natural+mkNaturalExpr i = do iExpr <- mkIntegerExpr i+ fiExpr <- lookupId naturalFromIntegerName+ return (mkCoreApps (Var fiExpr) [iExpr])+++-- | Create a 'CoreExpr' which will evaluate to the given @Float@+mkFloatExpr :: Float -> CoreExpr+mkFloatExpr f = mkCoreConApps floatDataCon [mkFloatLitFloat f]++-- | Create a 'CoreExpr' which will evaluate to the given @Double@+mkDoubleExpr :: Double -> CoreExpr+mkDoubleExpr d = mkCoreConApps doubleDataCon [mkDoubleLitDouble d]+++-- | Create a 'CoreExpr' which will evaluate to the given @Char@+mkCharExpr :: Char -> CoreExpr -- Result = C# c :: Int+mkCharExpr c = mkCoreConApps charDataCon [mkCharLit c]++-- | Create a 'CoreExpr' which will evaluate to the given @String@+mkStringExpr :: MonadThings m => String -> m CoreExpr -- Result :: String++-- | Create a 'CoreExpr' which will evaluate to a string morally equivalent to the given @FastString@+mkStringExprFS :: MonadThings m => FastString -> m CoreExpr -- Result :: String++mkStringExpr str = mkStringExprFS (mkFastString str)++mkStringExprFS = mkStringExprFSWith lookupId++mkStringExprFSWith :: Monad m => (Name -> m Id) -> FastString -> m CoreExpr+mkStringExprFSWith lookupM str+ | nullFS str+ = return (mkNilExpr charTy)++ | all safeChar chars+ = do unpack_id <- lookupM unpackCStringName+ return (App (Var unpack_id) lit)++ | otherwise+ = do unpack_utf8_id <- lookupM unpackCStringUtf8Name+ return (App (Var unpack_utf8_id) lit)++ where+ chars = unpackFS str+ safeChar c = ord c >= 1 && ord c <= 0x7F+ lit = Lit (MachStr (fastStringToByteString str))++{-+************************************************************************+* *+\subsection{Tuple constructors}+* *+************************************************************************+-}++{-+Creating tuples and their types for Core expressions++@mkBigCoreVarTup@ builds a tuple; the inverse to @mkTupleSelector@.++* If it has only one element, it is the identity function.++* If there are more elements than a big tuple can have, it nests+ the tuples.++Note [Flattening one-tuples]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This family of functions creates a tuple of variables/expressions/types.+ mkCoreTup [e1,e2,e3] = (e1,e2,e3)+What if there is just one variable/expression/type in the argument?+We could do one of two things:++* Flatten it out, so that+ mkCoreTup [e1] = e1++* Built a one-tuple (see Note [One-tuples] in TysWiredIn)+ mkCoreTup1 [e1] = Unit e1+ We use a suffix "1" to indicate this.++Usually we want the former, but occasionally the latter.+-}++-- | Build a small tuple holding the specified variables+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkCoreVarTup :: [Id] -> CoreExpr+mkCoreVarTup ids = mkCoreTup (map Var ids)++-- | Build the type of a small tuple that holds the specified variables+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkCoreVarTupTy :: [Id] -> Type+mkCoreVarTupTy ids = mkBoxedTupleTy (map idType ids)++-- | Build a small tuple holding the specified expressions+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkCoreTup :: [CoreExpr] -> CoreExpr+mkCoreTup [] = Var unitDataConId+mkCoreTup [c] = c+mkCoreTup cs = mkCoreConApps (tupleDataCon Boxed (length cs))+ (map (Type . exprType) cs ++ cs)++-- | Build a small unboxed tuple holding the specified expressions,+-- with the given types. The types must be the types of the expressions.+-- Do not include the RuntimeRep specifiers; this function calculates them+-- for you.+-- Does /not/ flatten one-tuples; see Note [Flattening one-tuples]+mkCoreUbxTup :: [Type] -> [CoreExpr] -> CoreExpr+mkCoreUbxTup tys exps+ = ASSERT( tys `equalLength` exps)+ mkCoreConApps (tupleDataCon Unboxed (length tys))+ (map (Type . getRuntimeRep "mkCoreUbxTup") tys ++ map Type tys ++ exps)++-- | Make a core tuple of the given boxity+mkCoreTupBoxity :: Boxity -> [CoreExpr] -> CoreExpr+mkCoreTupBoxity Boxed exps = mkCoreTup exps+mkCoreTupBoxity Unboxed exps = mkCoreUbxTup (map exprType exps) exps++-- | Build a big tuple holding the specified variables+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkBigCoreVarTup :: [Id] -> CoreExpr+mkBigCoreVarTup ids = mkBigCoreTup (map Var ids)++mkBigCoreVarTup1 :: [Id] -> CoreExpr+-- Same as mkBigCoreVarTup, but one-tuples are NOT flattened+-- see Note [Flattening one-tuples]+mkBigCoreVarTup1 [id] = mkCoreConApps (tupleDataCon Boxed 1)+ [Type (idType id), Var id]+mkBigCoreVarTup1 ids = mkBigCoreTup (map Var ids)++-- | Build the type of a big tuple that holds the specified variables+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkBigCoreVarTupTy :: [Id] -> Type+mkBigCoreVarTupTy ids = mkBigCoreTupTy (map idType ids)++-- | Build a big tuple holding the specified expressions+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkBigCoreTup :: [CoreExpr] -> CoreExpr+mkBigCoreTup = mkChunkified mkCoreTup++-- | Build the type of a big tuple that holds the specified type of thing+-- One-tuples are flattened; see Note [Flattening one-tuples]+mkBigCoreTupTy :: [Type] -> Type+mkBigCoreTupTy = mkChunkified mkBoxedTupleTy++-- | The unit expression+unitExpr :: CoreExpr+unitExpr = Var unitDataConId++{-+************************************************************************+* *+\subsection{Tuple destructors}+* *+************************************************************************+-}++-- | Builds a selector which scrutises the given+-- expression and extracts the one name from the list given.+-- If you want the no-shadowing rule to apply, the caller+-- is responsible for making sure that none of these names+-- are in scope.+--+-- If there is just one 'Id' in the tuple, then the selector is+-- just the identity.+--+-- If necessary, we pattern match on a \"big\" tuple.+mkTupleSelector, mkTupleSelector1+ :: [Id] -- ^ The 'Id's to pattern match the tuple against+ -> Id -- ^ The 'Id' to select+ -> Id -- ^ A variable of the same type as the scrutinee+ -> CoreExpr -- ^ Scrutinee+ -> CoreExpr -- ^ Selector expression++-- mkTupleSelector [a,b,c,d] b v e+-- = case e of v {+-- (p,q) -> case p of p {+-- (a,b) -> b }}+-- We use 'tpl' vars for the p,q, since shadowing does not matter.+--+-- In fact, it's more convenient to generate it innermost first, getting+--+-- case (case e of v+-- (p,q) -> p) of p+-- (a,b) -> b+mkTupleSelector vars the_var scrut_var scrut+ = mk_tup_sel (chunkify vars) the_var+ where+ mk_tup_sel [vars] the_var = mkSmallTupleSelector vars the_var scrut_var scrut+ mk_tup_sel vars_s the_var = mkSmallTupleSelector group the_var tpl_v $+ mk_tup_sel (chunkify tpl_vs) tpl_v+ where+ tpl_tys = [mkBoxedTupleTy (map idType gp) | gp <- vars_s]+ tpl_vs = mkTemplateLocals tpl_tys+ [(tpl_v, group)] = [(tpl,gp) | (tpl,gp) <- zipEqual "mkTupleSelector" tpl_vs vars_s,+ the_var `elem` gp ]+-- ^ 'mkTupleSelector1' is like 'mkTupleSelector'+-- but one-tuples are NOT flattened (see Note [Flattening one-tuples])+mkTupleSelector1 vars the_var scrut_var scrut+ | [_] <- vars+ = mkSmallTupleSelector1 vars the_var scrut_var scrut+ | otherwise+ = mkTupleSelector vars the_var scrut_var scrut++-- | Like 'mkTupleSelector' but for tuples that are guaranteed+-- never to be \"big\".+--+-- > mkSmallTupleSelector [x] x v e = [| e |]+-- > mkSmallTupleSelector [x,y,z] x v e = [| case e of v { (x,y,z) -> x } |]+mkSmallTupleSelector, mkSmallTupleSelector1+ :: [Id] -- The tuple args+ -> Id -- The selected one+ -> Id -- A variable of the same type as the scrutinee+ -> CoreExpr -- Scrutinee+ -> CoreExpr+mkSmallTupleSelector [var] should_be_the_same_var _ scrut+ = ASSERT(var == should_be_the_same_var)+ scrut -- Special case for 1-tuples+mkSmallTupleSelector vars the_var scrut_var scrut+ = mkSmallTupleSelector1 vars the_var scrut_var scrut++-- ^ 'mkSmallTupleSelector1' is like 'mkSmallTupleSelector'+-- but one-tuples are NOT flattened (see Note [Flattening one-tuples])+mkSmallTupleSelector1 vars the_var scrut_var scrut+ = ASSERT( notNull vars )+ Case scrut scrut_var (idType the_var)+ [(DataAlt (tupleDataCon Boxed (length vars)), vars, Var the_var)]++-- | A generalization of 'mkTupleSelector', allowing the body+-- of the case to be an arbitrary expression.+--+-- To avoid shadowing, we use uniques to invent new variables.+--+-- If necessary we pattern match on a \"big\" tuple.+mkTupleCase :: UniqSupply -- ^ For inventing names of intermediate variables+ -> [Id] -- ^ The tuple identifiers to pattern match on+ -> CoreExpr -- ^ Body of the case+ -> Id -- ^ A variable of the same type as the scrutinee+ -> CoreExpr -- ^ Scrutinee+ -> CoreExpr+-- ToDo: eliminate cases where none of the variables are needed.+--+-- mkTupleCase uniqs [a,b,c,d] body v e+-- = case e of v { (p,q) ->+-- case p of p { (a,b) ->+-- case q of q { (c,d) ->+-- body }}}+mkTupleCase uniqs vars body scrut_var scrut+ = mk_tuple_case uniqs (chunkify vars) body+ where+ -- This is the case where don't need any nesting+ mk_tuple_case _ [vars] body+ = mkSmallTupleCase vars body scrut_var scrut++ -- This is the case where we must make nest tuples at least once+ mk_tuple_case us vars_s body+ = let (us', vars', body') = foldr one_tuple_case (us, [], body) vars_s+ in mk_tuple_case us' (chunkify vars') body'++ one_tuple_case chunk_vars (us, vs, body)+ = let (uniq, us') = takeUniqFromSupply us+ scrut_var = mkSysLocal (fsLit "ds") uniq+ (mkBoxedTupleTy (map idType chunk_vars))+ body' = mkSmallTupleCase chunk_vars body scrut_var (Var scrut_var)+ in (us', scrut_var:vs, body')++-- | As 'mkTupleCase', but for a tuple that is small enough to be guaranteed+-- not to need nesting.+mkSmallTupleCase+ :: [Id] -- ^ The tuple args+ -> CoreExpr -- ^ Body of the case+ -> Id -- ^ A variable of the same type as the scrutinee+ -> CoreExpr -- ^ Scrutinee+ -> CoreExpr++mkSmallTupleCase [var] body _scrut_var scrut+ = bindNonRec var scrut body+mkSmallTupleCase vars body scrut_var scrut+-- One branch no refinement?+ = Case scrut scrut_var (exprType body)+ [(DataAlt (tupleDataCon Boxed (length vars)), vars, body)]++{-+************************************************************************+* *+ Floats+* *+************************************************************************+-}++data FloatBind+ = FloatLet CoreBind+ | FloatCase CoreExpr Id AltCon [Var]+ -- case e of y { C ys -> ... }+ -- See Note [Floating cases] in SetLevels++instance Outputable FloatBind where+ ppr (FloatLet b) = text "LET" <+> ppr b+ ppr (FloatCase e b c bs) = hang (text "CASE" <+> ppr e <+> ptext (sLit "of") <+> ppr b)+ 2 (ppr c <+> ppr bs)++wrapFloat :: FloatBind -> CoreExpr -> CoreExpr+wrapFloat (FloatLet defns) body = Let defns body+wrapFloat (FloatCase e b con bs) body = Case e b (exprType body) [(con, bs, body)]++{-+************************************************************************+* *+\subsection{Common list manipulation expressions}+* *+************************************************************************++Call the constructor Ids when building explicit lists, so that they+interact well with rules.+-}++-- | Makes a list @[]@ for lists of the specified type+mkNilExpr :: Type -> CoreExpr+mkNilExpr ty = mkCoreConApps nilDataCon [Type ty]++-- | Makes a list @(:)@ for lists of the specified type+mkConsExpr :: Type -> CoreExpr -> CoreExpr -> CoreExpr+mkConsExpr ty hd tl = mkCoreConApps consDataCon [Type ty, hd, tl]++-- | Make a list containing the given expressions, where the list has the given type+mkListExpr :: Type -> [CoreExpr] -> CoreExpr+mkListExpr ty xs = foldr (mkConsExpr ty) (mkNilExpr ty) xs++-- | Make a fully applied 'foldr' expression+mkFoldrExpr :: MonadThings m+ => Type -- ^ Element type of the list+ -> Type -- ^ Fold result type+ -> CoreExpr -- ^ "Cons" function expression for the fold+ -> CoreExpr -- ^ "Nil" expression for the fold+ -> CoreExpr -- ^ List expression being folded acress+ -> m CoreExpr+mkFoldrExpr elt_ty result_ty c n list = do+ foldr_id <- lookupId foldrName+ return (Var foldr_id `App` Type elt_ty+ `App` Type result_ty+ `App` c+ `App` n+ `App` list)++-- | Make a 'build' expression applied to a locally-bound worker function+mkBuildExpr :: (MonadThings m, MonadUnique m)+ => Type -- ^ Type of list elements to be built+ -> ((Id, Type) -> (Id, Type) -> m CoreExpr) -- ^ Function that, given information about the 'Id's+ -- of the binders for the build worker function, returns+ -- the body of that worker+ -> m CoreExpr+mkBuildExpr elt_ty mk_build_inside = do+ [n_tyvar] <- newTyVars [alphaTyVar]+ let n_ty = mkTyVarTy n_tyvar+ c_ty = mkFunTys [elt_ty, n_ty] n_ty+ [c, n] <- sequence [mkSysLocalM (fsLit "c") c_ty, mkSysLocalM (fsLit "n") n_ty]++ build_inside <- mk_build_inside (c, c_ty) (n, n_ty)++ build_id <- lookupId buildName+ return $ Var build_id `App` Type elt_ty `App` mkLams [n_tyvar, c, n] build_inside+ where+ newTyVars tyvar_tmpls = do+ uniqs <- getUniquesM+ return (zipWith setTyVarUnique tyvar_tmpls uniqs)++{-+************************************************************************+* *+ Manipulating Maybe data type+* *+************************************************************************+-}+++-- | Makes a Nothing for the specified type+mkNothingExpr :: Type -> CoreExpr+mkNothingExpr ty = mkConApp nothingDataCon [Type ty]++-- | Makes a Just from a value of the specified type+mkJustExpr :: Type -> CoreExpr -> CoreExpr+mkJustExpr ty val = mkConApp justDataCon [Type ty, val]+++{-+************************************************************************+* *+ Error expressions+* *+************************************************************************+-}++mkRuntimeErrorApp+ :: Id -- Should be of type (forall a. Addr# -> a)+ -- where Addr# points to a UTF8 encoded string+ -> Type -- The type to instantiate 'a'+ -> String -- The string to print+ -> CoreExpr++mkRuntimeErrorApp err_id res_ty err_msg+ = mkApps (Var err_id) [ Type (getRuntimeRep "mkRuntimeErrorApp" res_ty)+ , Type res_ty, err_string ]+ where+ err_string = Lit (mkMachString err_msg)++mkImpossibleExpr :: Type -> CoreExpr+mkImpossibleExpr res_ty+ = mkRuntimeErrorApp rUNTIME_ERROR_ID res_ty "Impossible case alternative"++{-+************************************************************************+* *+ Error Ids+* *+************************************************************************++GHC randomly injects these into the code.++@patError@ is just a version of @error@ for pattern-matching+failures. It knows various ``codes'' which expand to longer+strings---this saves space!++@absentErr@ is a thing we put in for ``absent'' arguments. They jolly+well shouldn't be yanked on, but if one is, then you will get a+friendly message from @absentErr@ (rather than a totally random+crash).++@parError@ is a special version of @error@ which the compiler does+not know to be a bottoming Id. It is used in the @_par_@ and @_seq_@+templates, but we don't ever expect to generate code for it.+-}++errorIds :: [Id]+errorIds+ = [ rUNTIME_ERROR_ID,+ iRREFUT_PAT_ERROR_ID,+ nON_EXHAUSTIVE_GUARDS_ERROR_ID,+ nO_METHOD_BINDING_ERROR_ID,+ pAT_ERROR_ID,+ rEC_CON_ERROR_ID,+ rEC_SEL_ERROR_ID,+ aBSENT_ERROR_ID,+ tYPE_ERROR_ID -- Used with Opt_DeferTypeErrors, see #10284+ ]++recSelErrorName, runtimeErrorName, absentErrorName :: Name+irrefutPatErrorName, recConErrorName, patErrorName :: Name+nonExhaustiveGuardsErrorName, noMethodBindingErrorName :: Name+typeErrorName :: Name++recSelErrorName = err_nm "recSelError" recSelErrorIdKey rEC_SEL_ERROR_ID+absentErrorName = err_nm "absentError" absentErrorIdKey aBSENT_ERROR_ID+runtimeErrorName = err_nm "runtimeError" runtimeErrorIdKey rUNTIME_ERROR_ID+irrefutPatErrorName = err_nm "irrefutPatError" irrefutPatErrorIdKey iRREFUT_PAT_ERROR_ID+recConErrorName = err_nm "recConError" recConErrorIdKey rEC_CON_ERROR_ID+patErrorName = err_nm "patError" patErrorIdKey pAT_ERROR_ID+typeErrorName = err_nm "typeError" typeErrorIdKey tYPE_ERROR_ID++noMethodBindingErrorName = err_nm "noMethodBindingError"+ noMethodBindingErrorIdKey nO_METHOD_BINDING_ERROR_ID+nonExhaustiveGuardsErrorName = err_nm "nonExhaustiveGuardsError"+ nonExhaustiveGuardsErrorIdKey nON_EXHAUSTIVE_GUARDS_ERROR_ID++err_nm :: String -> Unique -> Id -> Name+err_nm str uniq id = mkWiredInIdName cONTROL_EXCEPTION_BASE (fsLit str) uniq id++rEC_SEL_ERROR_ID, rUNTIME_ERROR_ID, iRREFUT_PAT_ERROR_ID, rEC_CON_ERROR_ID :: Id+pAT_ERROR_ID, nO_METHOD_BINDING_ERROR_ID, nON_EXHAUSTIVE_GUARDS_ERROR_ID :: Id+tYPE_ERROR_ID, aBSENT_ERROR_ID :: Id+rEC_SEL_ERROR_ID = mkRuntimeErrorId recSelErrorName+rUNTIME_ERROR_ID = mkRuntimeErrorId runtimeErrorName+iRREFUT_PAT_ERROR_ID = mkRuntimeErrorId irrefutPatErrorName+rEC_CON_ERROR_ID = mkRuntimeErrorId recConErrorName+pAT_ERROR_ID = mkRuntimeErrorId patErrorName+nO_METHOD_BINDING_ERROR_ID = mkRuntimeErrorId noMethodBindingErrorName+nON_EXHAUSTIVE_GUARDS_ERROR_ID = mkRuntimeErrorId nonExhaustiveGuardsErrorName+aBSENT_ERROR_ID = mkRuntimeErrorId absentErrorName+tYPE_ERROR_ID = mkRuntimeErrorId typeErrorName++mkRuntimeErrorId :: Name -> Id+-- Error function+-- with type: forall (r:RuntimeRep) (a:TYPE r). Addr# -> a+-- with arity: 1+-- which diverges after being given one argument+-- The Addr# is expected to be the address of+-- a UTF8-encoded error string+mkRuntimeErrorId name+ = mkVanillaGlobalWithInfo name runtime_err_ty bottoming_info+ where+ bottoming_info = vanillaIdInfo `setStrictnessInfo` strict_sig+ `setArityInfo` 1+ -- Make arity and strictness agree++ -- Do *not* mark them as NoCafRefs, because they can indeed have+ -- CAF refs. For example, pAT_ERROR_ID calls GHC.Err.untangle,+ -- which has some CAFs+ -- In due course we may arrange that these error-y things are+ -- regarded by the GC as permanently live, in which case we+ -- can give them NoCaf info. As it is, any function that calls+ -- any pc_bottoming_Id will itself have CafRefs, which bloats+ -- SRTs.++ strict_sig = mkClosedStrictSig [evalDmd] exnRes+ -- exnRes: these throw an exception, not just diverge++ -- forall (rr :: RuntimeRep) (a :: rr). Addr# -> a+ -- See Note [Error and friends have an "open-tyvar" forall]+ runtime_err_ty = mkSpecSigmaTy [runtimeRep1TyVar, openAlphaTyVar] []+ (mkFunTy addrPrimTy openAlphaTy)++{- Note [Error and friends have an "open-tyvar" forall]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+'error' and 'undefined' have types+ error :: forall (v :: RuntimeRep) (a :: TYPE v). String -> a+ undefined :: forall (v :: RuntimeRep) (a :: TYPE v). a+Notice the runtime-representation polymorphism. This ensures that+"error" can be instantiated at unboxed as well as boxed types.+This is OK because it never returns, so the return type is irrelevant.+-}
+ coreSyn/PprCore.hs view
@@ -0,0 +1,622 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1996-1998+++Printing of Core syntax+-}++{-# LANGUAGE MultiWayIf #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module PprCore (+ pprCoreExpr, pprParendExpr,+ pprCoreBinding, pprCoreBindings, pprCoreAlt,+ pprCoreBindingWithSize, pprCoreBindingsWithSize,+ pprRules, pprOptCo+ ) where++import CoreSyn+import CoreStats (exprStats)+import Literal( pprLiteral )+import Name( pprInfixName, pprPrefixName )+import Var+import Id+import IdInfo+import Demand+import DataCon+import TyCon+import Type+import Coercion+import DynFlags+import BasicTypes+import Maybes+import Util+import Outputable+import FastString+import SrcLoc ( pprUserRealSpan )++{-+************************************************************************+* *+\subsection{Public interfaces for Core printing (excluding instances)}+* *+************************************************************************++@pprParendCoreExpr@ puts parens around non-atomic Core expressions.+-}++pprCoreBindings :: OutputableBndr b => [Bind b] -> SDoc+pprCoreBinding :: OutputableBndr b => Bind b -> SDoc+pprCoreExpr :: OutputableBndr b => Expr b -> SDoc+pprParendExpr :: OutputableBndr b => Expr b -> SDoc++pprCoreBindings = pprTopBinds noAnn+pprCoreBinding = pprTopBind noAnn++pprCoreBindingsWithSize :: [CoreBind] -> SDoc+pprCoreBindingWithSize :: CoreBind -> SDoc++pprCoreBindingsWithSize = pprTopBinds sizeAnn+pprCoreBindingWithSize = pprTopBind sizeAnn++instance OutputableBndr b => Outputable (Bind b) where+ ppr bind = ppr_bind noAnn bind++instance OutputableBndr b => Outputable (Expr b) where+ ppr expr = pprCoreExpr expr++{-+************************************************************************+* *+\subsection{The guts}+* *+************************************************************************+-}++-- | A function to produce an annotation for a given right-hand-side+type Annotation b = Expr b -> SDoc++-- | Annotate with the size of the right-hand-side+sizeAnn :: CoreExpr -> SDoc+sizeAnn e = text "-- RHS size:" <+> ppr (exprStats e)++-- | No annotation+noAnn :: Expr b -> SDoc+noAnn _ = empty++pprTopBinds :: OutputableBndr a+ => Annotation a -- ^ generate an annotation to place before the+ -- binding+ -> [Bind a] -- ^ bindings to show+ -> SDoc -- ^ the pretty result+pprTopBinds ann binds = vcat (map (pprTopBind ann) binds)++pprTopBind :: OutputableBndr a => Annotation a -> Bind a -> SDoc+pprTopBind ann (NonRec binder expr)+ = ppr_binding ann (binder,expr) $$ blankLine++pprTopBind _ (Rec [])+ = text "Rec { }"+pprTopBind ann (Rec (b:bs))+ = vcat [text "Rec {",+ ppr_binding ann b,+ vcat [blankLine $$ ppr_binding ann b | b <- bs],+ text "end Rec }",+ blankLine]++ppr_bind :: OutputableBndr b => Annotation b -> Bind b -> SDoc++ppr_bind ann (NonRec val_bdr expr) = ppr_binding ann (val_bdr, expr)+ppr_bind ann (Rec binds) = vcat (map pp binds)+ where+ pp bind = ppr_binding ann bind <> semi++ppr_binding :: OutputableBndr b => Annotation b -> (b, Expr b) -> SDoc+ppr_binding ann (val_bdr, expr)+ = ann expr $$ pprBndr LetBind val_bdr $$ pp_bind+ where+ pp_bind = case bndrIsJoin_maybe val_bdr of+ Nothing -> pp_normal_bind+ Just ar -> pp_join_bind ar++ pp_normal_bind = hang (ppr val_bdr) 2 (equals <+> pprCoreExpr expr)++ -- For a join point of join arity n, we want to print j = \x1 ... xn -> e+ -- as "j x1 ... xn = e" to differentiate when a join point returns a+ -- lambda (the first rendering looks like a nullary join point returning+ -- an n-argument function).+ pp_join_bind join_arity+ = hang (ppr val_bdr <+> sep (map (pprBndr LambdaBind) lhs_bndrs))+ 2 (equals <+> pprCoreExpr rhs)+ where+ (lhs_bndrs, rhs) = collectNBinders join_arity expr++pprParendExpr expr = ppr_expr parens expr+pprCoreExpr expr = ppr_expr noParens expr++noParens :: SDoc -> SDoc+noParens pp = pp++pprOptCo :: Coercion -> SDoc+-- Print a coercion optionally; i.e. honouring -dsuppress-coercions+pprOptCo co = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressCoercions dflags+ then angleBrackets (text "Co:" <> int (coercionSize co))+ else parens (sep [ppr co, dcolon <+> ppr (coercionType co)])++ppr_expr :: OutputableBndr b => (SDoc -> SDoc) -> Expr b -> SDoc+ -- The function adds parens in context that need+ -- an atomic value (e.g. function args)++ppr_expr add_par (Var name)+ | isJoinId name = add_par ((text "jump") <+> ppr name)+ | otherwise = ppr name+ppr_expr add_par (Type ty) = add_par (text "TYPE:" <+> ppr ty) -- Weird+ppr_expr add_par (Coercion co) = add_par (text "CO:" <+> ppr co)+ppr_expr add_par (Lit lit) = pprLiteral add_par lit++ppr_expr add_par (Cast expr co)+ = add_par $ sep [pprParendExpr expr, text "`cast`" <+> pprOptCo co]++ppr_expr add_par expr@(Lam _ _)+ = let+ (bndrs, body) = collectBinders expr+ in+ add_par $+ hang (text "\\" <+> sep (map (pprBndr LambdaBind) bndrs) <+> arrow)+ 2 (pprCoreExpr body)++ppr_expr add_par expr@(App {})+ = sdocWithDynFlags $ \dflags ->+ case collectArgs expr of { (fun, args) ->+ let+ pp_args = sep (map pprArg args)+ val_args = dropWhile isTypeArg args -- Drop the type arguments for tuples+ pp_tup_args = pprWithCommas pprCoreExpr val_args+ args'+ | gopt Opt_SuppressTypeApplications dflags = val_args+ | otherwise = args+ parens+ | null args' = id+ | otherwise = add_par+ in+ case fun of+ Var f -> case isDataConWorkId_maybe f of+ -- Notice that we print the *worker*+ -- for tuples in paren'd format.+ Just dc | saturated+ , Just sort <- tyConTuple_maybe tc+ -> tupleParens sort pp_tup_args+ where+ tc = dataConTyCon dc+ saturated = val_args `lengthIs` idArity f++ _ -> parens (hang fun_doc 2 pp_args)+ where+ fun_doc | isJoinId f = text "jump" <+> ppr f+ | otherwise = ppr f++ _ -> parens (hang (pprParendExpr fun) 2 pp_args)+ }++ppr_expr add_par (Case expr var ty [(con,args,rhs)])+ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_PprCaseAsLet dflags+ then add_par $ -- See Note [Print case as let]+ sep [ sep [ text "let! {"+ <+> ppr_case_pat con args+ <+> text "~"+ <+> ppr_bndr var+ , text "<-" <+> ppr_expr id expr+ <+> text "} in" ]+ , pprCoreExpr rhs+ ]+ else add_par $+ sep [sep [sep [ text "case" <+> pprCoreExpr expr+ , ifPprDebug (text "return" <+> ppr ty)+ , text "of" <+> ppr_bndr var+ ]+ , char '{' <+> ppr_case_pat con args <+> arrow+ ]+ , pprCoreExpr rhs+ , char '}'+ ]+ where+ ppr_bndr = pprBndr CaseBind++ppr_expr add_par (Case expr var ty alts)+ = add_par $+ sep [sep [text "case"+ <+> pprCoreExpr expr+ <+> ifPprDebug (text "return" <+> ppr ty),+ text "of" <+> ppr_bndr var <+> char '{'],+ nest 2 (vcat (punctuate semi (map pprCoreAlt alts))),+ char '}'+ ]+ where+ ppr_bndr = pprBndr CaseBind+++-- special cases: let ... in let ...+-- ("disgusting" SLPJ)++{-+ppr_expr add_par (Let bind@(NonRec val_bdr rhs@(Let _ _)) body)+ = add_par $+ vcat [+ hsep [text "let {", (pprBndr LetBind val_bdr $$ ppr val_bndr), equals],+ nest 2 (pprCoreExpr rhs),+ text "} in",+ pprCoreExpr body ]++ppr_expr add_par (Let bind@(NonRec val_bdr rhs) expr@(Let _ _))+ = add_par+ (hang (text "let {")+ 2 (hsep [ppr_binding (val_bdr,rhs),+ text "} in"])+ $$+ pprCoreExpr expr)+-}+++-- General case (recursive case, too)+ppr_expr add_par (Let bind expr)+ = add_par $+ sep [hang (keyword bind <+> char '{') 2 (ppr_bind noAnn bind <+> text "} in"),+ pprCoreExpr expr]+ where+ keyword (NonRec b _)+ | isJust (bndrIsJoin_maybe b) = text "join"+ | otherwise = text "let"+ keyword (Rec pairs)+ | ((b,_):_) <- pairs+ , isJust (bndrIsJoin_maybe b) = text "joinrec"+ | otherwise = text "letrec"++ppr_expr add_par (Tick tickish expr)+ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressTicks dflags+ then ppr_expr add_par expr+ else add_par (sep [ppr tickish, pprCoreExpr expr])++pprCoreAlt :: OutputableBndr a => (AltCon, [a] , Expr a) -> SDoc+pprCoreAlt (con, args, rhs)+ = hang (ppr_case_pat con args <+> arrow) 2 (pprCoreExpr rhs)++ppr_case_pat :: OutputableBndr a => AltCon -> [a] -> SDoc+ppr_case_pat (DataAlt dc) args+ | Just sort <- tyConTuple_maybe tc+ = tupleParens sort (pprWithCommas ppr_bndr args)+ where+ ppr_bndr = pprBndr CasePatBind+ tc = dataConTyCon dc++ppr_case_pat con args+ = ppr con <+> (fsep (map ppr_bndr args))+ where+ ppr_bndr = pprBndr CasePatBind+++-- | Pretty print the argument in a function application.+pprArg :: OutputableBndr a => Expr a -> SDoc+pprArg (Type ty)+ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressTypeApplications dflags+ then empty+ else text "@" <+> pprParendType ty+pprArg (Coercion co) = text "@~" <+> pprOptCo co+pprArg expr = pprParendExpr expr++{-+Note [Print case as let]+~~~~~~~~~~~~~~~~~~~~~~~~+Single-branch case expressions are very common:+ case x of y { I# x' ->+ case p of q { I# p' -> ... } }+These are, in effect, just strict let's, with pattern matching.+With -dppr-case-as-let we print them as such:+ let! { I# x' ~ y <- x } in+ let! { I# p' ~ q <- p } in ...+++Other printing bits-and-bobs used with the general @pprCoreBinding@+and @pprCoreExpr@ functions.+++Note [Binding-site specific printing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++pprCoreBinder and pprTypedLamBinder receive a BindingSite argument to adjust+the information printed.++Let-bound binders are printed with their full type and idInfo.++Case-bound variables (both the case binder and pattern variables) are printed+without a type and without their unfolding.++Furthermore, a dead case-binder is completely ignored, while otherwise, dead+binders are printed as "_".+-}++-- These instances are sadly orphans++instance OutputableBndr Var where+ pprBndr = pprCoreBinder+ pprInfixOcc = pprInfixName . varName+ pprPrefixOcc = pprPrefixName . varName+ bndrIsJoin_maybe = isJoinId_maybe++instance Outputable b => OutputableBndr (TaggedBndr b) where+ pprBndr _ b = ppr b -- Simple+ pprInfixOcc b = ppr b+ pprPrefixOcc b = ppr b+ bndrIsJoin_maybe (TB b _) = isJoinId_maybe b++pprCoreBinder :: BindingSite -> Var -> SDoc+pprCoreBinder LetBind binder+ | isTyVar binder = pprKindedTyVarBndr binder+ | otherwise = pprTypedLetBinder binder $$+ ppIdInfo binder (idInfo binder)++-- Lambda bound type variables are preceded by "@"+pprCoreBinder bind_site bndr+ = getPprStyle $ \ sty ->+ pprTypedLamBinder bind_site (debugStyle sty) bndr++pprUntypedBinder :: Var -> SDoc+pprUntypedBinder binder+ | isTyVar binder = text "@" <+> ppr binder -- NB: don't print kind+ | otherwise = pprIdBndr binder++pprTypedLamBinder :: BindingSite -> Bool -> Var -> SDoc+-- For lambda and case binders, show the unfolding info (usually none)+pprTypedLamBinder bind_site debug_on var+ = sdocWithDynFlags $ \dflags ->+ case () of+ _+ | not debug_on -- Show case-bound wild bilders only if debug is on+ , CaseBind <- bind_site+ , isDeadBinder var -> empty++ | not debug_on -- Even dead binders can be one-shot+ , isDeadBinder var -> char '_' <+> ppWhen (isId var)+ (pprIdBndrInfo (idInfo var))++ | not debug_on -- No parens, no kind info+ , CaseBind <- bind_site -> pprUntypedBinder var++ | not debug_on+ , CasePatBind <- bind_site -> pprUntypedBinder var++ | suppress_sigs dflags -> pprUntypedBinder var++ | isTyVar var -> parens (pprKindedTyVarBndr var)++ | otherwise -> parens (hang (pprIdBndr var)+ 2 (vcat [ dcolon <+> pprType (idType var)+ , pp_unf]))+ where+ suppress_sigs = gopt Opt_SuppressTypeSignatures++ unf_info = unfoldingInfo (idInfo var)+ pp_unf | hasSomeUnfolding unf_info = text "Unf=" <> ppr unf_info+ | otherwise = empty++pprTypedLetBinder :: Var -> SDoc+-- Print binder with a type or kind signature (not paren'd)+pprTypedLetBinder binder+ = sdocWithDynFlags $ \dflags ->+ case () of+ _+ | isTyVar binder -> pprKindedTyVarBndr binder+ | gopt Opt_SuppressTypeSignatures dflags -> pprIdBndr binder+ | otherwise -> hang (pprIdBndr binder) 2 (dcolon <+> pprType (idType binder))++pprKindedTyVarBndr :: TyVar -> SDoc+-- Print a type variable binder with its kind (but not if *)+pprKindedTyVarBndr tyvar+ = text "@" <+> pprTyVar tyvar++-- pprIdBndr does *not* print the type+-- When printing any Id binder in debug mode, we print its inline pragma and one-shot-ness+pprIdBndr :: Id -> SDoc+pprIdBndr id = ppr id <+> pprIdBndrInfo (idInfo id)++pprIdBndrInfo :: IdInfo -> SDoc+pprIdBndrInfo info+ = sdocWithDynFlags $ \dflags ->+ ppUnless (gopt Opt_SuppressIdInfo dflags) $+ info `seq` doc -- The seq is useful for poking on black holes+ where+ prag_info = inlinePragInfo info+ occ_info = occInfo info+ dmd_info = demandInfo info+ lbv_info = oneShotInfo info++ has_prag = not (isDefaultInlinePragma prag_info)+ has_occ = not (isManyOccs occ_info)+ has_dmd = not $ isTopDmd dmd_info+ has_lbv = not (hasNoOneShotInfo lbv_info)++ doc = showAttributes+ [ (has_prag, text "InlPrag=" <> pprInlineDebug prag_info)+ , (has_occ, text "Occ=" <> ppr occ_info)+ , (has_dmd, text "Dmd=" <> ppr dmd_info)+ , (has_lbv , text "OS=" <> ppr lbv_info)+ ]++{-+-----------------------------------------------------+-- IdDetails and IdInfo+-----------------------------------------------------+-}++ppIdInfo :: Id -> IdInfo -> SDoc+ppIdInfo id info+ = sdocWithDynFlags $ \dflags ->+ ppUnless (gopt Opt_SuppressIdInfo dflags) $+ showAttributes+ [ (True, pp_scope <> ppr (idDetails id))+ , (has_arity, text "Arity=" <> int arity)+ , (has_called_arity, text "CallArity=" <> int called_arity)+ , (has_caf_info, text "Caf=" <> ppr caf_info)+ , (has_str_info, text "Str=" <> pprStrictness str_info)+ , (has_unf, text "Unf=" <> ppr unf_info)+ , (not (null rules), text "RULES:" <+> vcat (map pprRule rules))+ ] -- Inline pragma, occ, demand, one-shot info+ -- printed out with all binders (when debug is on);+ -- see PprCore.pprIdBndr+ where+ pp_scope | isGlobalId id = text "GblId"+ | isExportedId id = text "LclIdX"+ | otherwise = text "LclId"++ arity = arityInfo info+ has_arity = arity /= 0++ called_arity = callArityInfo info+ has_called_arity = called_arity /= 0++ caf_info = cafInfo info+ has_caf_info = not (mayHaveCafRefs caf_info)++ str_info = strictnessInfo info+ has_str_info = not (isTopSig str_info)++ unf_info = unfoldingInfo info+ has_unf = hasSomeUnfolding unf_info++ rules = ruleInfoRules (ruleInfo info)++showAttributes :: [(Bool,SDoc)] -> SDoc+showAttributes stuff+ | null docs = empty+ | otherwise = brackets (sep (punctuate comma docs))+ where+ docs = [d | (True,d) <- stuff]++{-+-----------------------------------------------------+-- Unfolding and UnfoldingGuidance+-----------------------------------------------------+-}++instance Outputable UnfoldingGuidance where+ ppr UnfNever = text "NEVER"+ ppr (UnfWhen { ug_arity = arity, ug_unsat_ok = unsat_ok, ug_boring_ok = boring_ok })+ = text "ALWAYS_IF" <>+ parens (text "arity=" <> int arity <> comma <>+ text "unsat_ok=" <> ppr unsat_ok <> comma <>+ text "boring_ok=" <> ppr boring_ok)+ ppr (UnfIfGoodArgs { ug_args = cs, ug_size = size, ug_res = discount })+ = hsep [ text "IF_ARGS",+ brackets (hsep (map int cs)),+ int size,+ int discount ]++instance Outputable UnfoldingSource where+ ppr InlineCompulsory = text "Compulsory"+ ppr InlineStable = text "InlineStable"+ ppr InlineRhs = text "<vanilla>"++instance Outputable Unfolding where+ ppr NoUnfolding = text "No unfolding"+ ppr BootUnfolding = text "No unfolding (from boot)"+ ppr (OtherCon cs) = text "OtherCon" <+> ppr cs+ ppr (DFunUnfolding { df_bndrs = bndrs, df_con = con, df_args = args })+ = hang (text "DFun:" <+> ptext (sLit "\\")+ <+> sep (map (pprBndr LambdaBind) bndrs) <+> arrow)+ 2 (ppr con <+> sep (map ppr args))+ ppr (CoreUnfolding { uf_src = src+ , uf_tmpl=rhs, uf_is_top=top, uf_is_value=hnf+ , uf_is_conlike=conlike, uf_is_work_free=wf+ , uf_expandable=exp, uf_guidance=g })+ = text "Unf" <> braces (pp_info $$ pp_rhs)+ where+ pp_info = fsep $ punctuate comma+ [ text "Src=" <> ppr src+ , text "TopLvl=" <> ppr top+ , text "Value=" <> ppr hnf+ , text "ConLike=" <> ppr conlike+ , text "WorkFree=" <> ppr wf+ , text "Expandable=" <> ppr exp+ , text "Guidance=" <> ppr g ]+ pp_tmpl = sdocWithDynFlags $ \dflags ->+ ppUnless (gopt Opt_SuppressUnfoldings dflags) $+ text "Tmpl=" <+> ppr rhs+ pp_rhs | isStableSource src = pp_tmpl+ | otherwise = empty+ -- Don't print the RHS or we get a quadratic+ -- blowup in the size of the printout!++{-+-----------------------------------------------------+-- Rules+-----------------------------------------------------+-}++instance Outputable CoreRule where+ ppr = pprRule++pprRules :: [CoreRule] -> SDoc+pprRules rules = vcat (map pprRule rules)++pprRule :: CoreRule -> SDoc+pprRule (BuiltinRule { ru_fn = fn, ru_name = name})+ = text "Built in rule for" <+> ppr fn <> colon <+> doubleQuotes (ftext name)++pprRule (Rule { ru_name = name, ru_act = act, ru_fn = fn,+ ru_bndrs = tpl_vars, ru_args = tpl_args,+ ru_rhs = rhs })+ = hang (doubleQuotes (ftext name) <+> ppr act)+ 4 (sep [text "forall" <+>+ sep (map (pprCoreBinder LambdaBind) tpl_vars) <> dot,+ nest 2 (ppr fn <+> sep (map pprArg tpl_args)),+ nest 2 (text "=" <+> pprCoreExpr rhs)+ ])++{-+-----------------------------------------------------+-- Tickish+-----------------------------------------------------+-}++instance Outputable id => Outputable (Tickish id) where+ ppr (HpcTick modl ix) =+ hcat [text "hpc<",+ ppr modl, comma,+ ppr ix,+ text ">"]+ ppr (Breakpoint ix vars) =+ hcat [text "break<",+ ppr ix,+ text ">",+ parens (hcat (punctuate comma (map ppr vars)))]+ ppr (ProfNote { profNoteCC = cc,+ profNoteCount = tick,+ profNoteScope = scope }) =+ case (tick,scope) of+ (True,True) -> hcat [text "scctick<", ppr cc, char '>']+ (True,False) -> hcat [text "tick<", ppr cc, char '>']+ _ -> hcat [text "scc<", ppr cc, char '>']+ ppr (SourceNote span _) =+ hcat [ text "src<", pprUserRealSpan True span, char '>']++{-+-----------------------------------------------------+-- Vectorisation declarations+-----------------------------------------------------+-}++instance Outputable CoreVect where+ ppr (Vect var e) = hang (text "VECTORISE" <+> ppr var <+> char '=')+ 4 (pprCoreExpr e)+ ppr (NoVect var) = text "NOVECTORISE" <+> ppr var+ ppr (VectType False var Nothing) = text "VECTORISE type" <+> ppr var+ ppr (VectType True var Nothing) = text "VECTORISE SCALAR type" <+> ppr var+ ppr (VectType False var (Just tc)) = text "VECTORISE type" <+> ppr var <+> char '=' <+>+ ppr tc+ ppr (VectType True var (Just tc)) = text "VECTORISE SCALAR type" <+> ppr var <+>+ char '=' <+> ppr tc+ ppr (VectClass tc) = text "VECTORISE class" <+> ppr tc+ ppr (VectInst var) = text "VECTORISE SCALAR instance" <+> ppr var
+ coreSyn/TrieMap.hs view
@@ -0,0 +1,1129 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+module TrieMap(+ -- * Maps over Core expressions+ CoreMap, emptyCoreMap, extendCoreMap, lookupCoreMap, foldCoreMap,+ -- * Maps over 'Type's+ TypeMap, emptyTypeMap, extendTypeMap, lookupTypeMap, foldTypeMap,+ LooseTypeMap,+ -- ** With explicit scoping+ CmEnv, lookupCME, extendTypeMapWithScope, lookupTypeMapWithScope,+ mkDeBruijnContext,+ -- * Maps over 'Maybe' values+ MaybeMap,+ -- * Maps over 'List' values+ ListMap,+ -- * Maps over 'Literal's+ LiteralMap,+ -- * 'TrieMap' class+ TrieMap(..), insertTM, deleteTM,+ lkDFreeVar, xtDFreeVar,+ lkDNamed, xtDNamed,+ (>.>), (|>), (|>>),+ ) where++import CoreSyn+import Coercion+import Literal+import Name+import Type+import TyCoRep+import Var+import UniqDFM+import Unique( Unique )+import FastString(FastString)++import qualified Data.Map as Map+import qualified Data.IntMap as IntMap+import VarEnv+import NameEnv+import Outputable+import Control.Monad( (>=>) )++{-+This module implements TrieMaps, which are finite mappings+whose key is a structured value like a CoreExpr or Type.++The code is very regular and boilerplate-like, but there is+some neat handling of *binders*. In effect they are deBruijn+numbered on the fly.++The regular pattern for handling TrieMaps on data structures was first+described (to my knowledge) in Connelly and Morris's 1995 paper "A+generalization of the Trie Data Structure"; there is also an accessible+description of the idea in Okasaki's book "Purely Functional Data+Structures", Section 10.3.2++************************************************************************+* *+ The TrieMap class+* *+************************************************************************+-}++type XT a = Maybe a -> Maybe a -- How to alter a non-existent elt (Nothing)+ -- or an existing elt (Just)++class TrieMap m where+ type Key m :: *+ emptyTM :: m a+ lookupTM :: forall b. Key m -> m b -> Maybe b+ alterTM :: forall b. Key m -> XT b -> m b -> m b+ mapTM :: (a->b) -> m a -> m b++ foldTM :: (a -> b -> b) -> m a -> b -> b+ -- The unusual argument order here makes+ -- it easy to compose calls to foldTM;+ -- see for example fdE below++insertTM :: TrieMap m => Key m -> a -> m a -> m a+insertTM k v m = alterTM k (\_ -> Just v) m++deleteTM :: TrieMap m => Key m -> m a -> m a+deleteTM k m = alterTM k (\_ -> Nothing) m++----------------------+-- Recall that+-- Control.Monad.(>=>) :: (a -> Maybe b) -> (b -> Maybe c) -> a -> Maybe c++(>.>) :: (a -> b) -> (b -> c) -> a -> c+-- Reverse function composition (do f first, then g)+infixr 1 >.>+(f >.> g) x = g (f x)+infixr 1 |>, |>>++(|>) :: a -> (a->b) -> b -- Reverse application+x |> f = f x++----------------------+(|>>) :: TrieMap m2+ => (XT (m2 a) -> m1 (m2 a) -> m1 (m2 a))+ -> (m2 a -> m2 a)+ -> m1 (m2 a) -> m1 (m2 a)+(|>>) f g = f (Just . g . deMaybe)++deMaybe :: TrieMap m => Maybe (m a) -> m a+deMaybe Nothing = emptyTM+deMaybe (Just m) = m++{-+************************************************************************+* *+ IntMaps+* *+************************************************************************+-}++instance TrieMap IntMap.IntMap where+ type Key IntMap.IntMap = Int+ emptyTM = IntMap.empty+ lookupTM k m = IntMap.lookup k m+ alterTM = xtInt+ foldTM k m z = IntMap.foldr k z m+ mapTM f m = IntMap.map f m++xtInt :: Int -> XT a -> IntMap.IntMap a -> IntMap.IntMap a+xtInt k f m = IntMap.alter f k m++instance Ord k => TrieMap (Map.Map k) where+ type Key (Map.Map k) = k+ emptyTM = Map.empty+ lookupTM = Map.lookup+ alterTM k f m = Map.alter f k m+ foldTM k m z = Map.foldr k z m+ mapTM f m = Map.map f m+++{-+Note [foldTM determinism]+~~~~~~~~~~~~~~~~~~~~~~~~~+We want foldTM to be deterministic, which is why we have an instance of+TrieMap for UniqDFM, but not for UniqFM. Here's an example of some things that+go wrong if foldTM is nondeterministic. Consider:++ f a b = return (a <> b)++Depending on the order that the typechecker generates constraints you+get either:++ f :: (Monad m, Monoid a) => a -> a -> m a++or:++ f :: (Monoid a, Monad m) => a -> a -> m a++The generated code will be different after desugaring as the dictionaries+will be bound in different orders, leading to potential ABI incompatibility.++One way to solve this would be to notice that the typeclasses could be+sorted alphabetically.++Unfortunately that doesn't quite work with this example:++ f a b = let x = a <> a; y = b <> b in x++where you infer:++ f :: (Monoid m, Monoid m1) => m1 -> m -> m1++or:++ f :: (Monoid m1, Monoid m) => m1 -> m -> m1++Here you could decide to take the order of the type variables in the type+according to depth first traversal and use it to order the constraints.++The real trouble starts when the user enables incoherent instances and+the compiler has to make an arbitrary choice. Consider:++ class T a b where+ go :: a -> b -> String++ instance (Show b) => T Int b where+ go a b = show a ++ show b++ instance (Show a) => T a Bool where+ go a b = show a ++ show b++ f = go 10 True++GHC is free to choose either dictionary to implement f, but for the sake of+determinism we'd like it to be consistent when compiling the same sources+with the same flags.++inert_dicts :: DictMap is implemented with a TrieMap. In getUnsolvedInerts it+gets converted to a bag of (Wanted) Cts using a fold. Then in+solve_simple_wanteds it's merged with other WantedConstraints. We want the+conversion to a bag to be deterministic. For that purpose we use UniqDFM+instead of UniqFM to implement the TrieMap.++See Note [Deterministic UniqFM] in UniqDFM for more details on how it's made+deterministic.+-}++instance TrieMap UniqDFM where+ type Key UniqDFM = Unique+ emptyTM = emptyUDFM+ lookupTM k m = lookupUDFM m k+ alterTM k f m = alterUDFM f m k+ foldTM k m z = foldUDFM k z m+ mapTM f m = mapUDFM f m++{-+************************************************************************+* *+ Maybes+* *+************************************************************************++If m is a map from k -> val+then (MaybeMap m) is a map from (Maybe k) -> val+-}++data MaybeMap m a = MM { mm_nothing :: Maybe a, mm_just :: m a }++instance TrieMap m => TrieMap (MaybeMap m) where+ type Key (MaybeMap m) = Maybe (Key m)+ emptyTM = MM { mm_nothing = Nothing, mm_just = emptyTM }+ lookupTM = lkMaybe lookupTM+ alterTM = xtMaybe alterTM+ foldTM = fdMaybe+ mapTM = mapMb++mapMb :: TrieMap m => (a->b) -> MaybeMap m a -> MaybeMap m b+mapMb f (MM { mm_nothing = mn, mm_just = mj })+ = MM { mm_nothing = fmap f mn, mm_just = mapTM f mj }++lkMaybe :: (forall b. k -> m b -> Maybe b)+ -> Maybe k -> MaybeMap m a -> Maybe a+lkMaybe _ Nothing = mm_nothing+lkMaybe lk (Just x) = mm_just >.> lk x++xtMaybe :: (forall b. k -> XT b -> m b -> m b)+ -> Maybe k -> XT a -> MaybeMap m a -> MaybeMap m a+xtMaybe _ Nothing f m = m { mm_nothing = f (mm_nothing m) }+xtMaybe tr (Just x) f m = m { mm_just = mm_just m |> tr x f }++fdMaybe :: TrieMap m => (a -> b -> b) -> MaybeMap m a -> b -> b+fdMaybe k m = foldMaybe k (mm_nothing m)+ . foldTM k (mm_just m)++{-+************************************************************************+* *+ Lists+* *+************************************************************************+-}++data ListMap m a+ = LM { lm_nil :: Maybe a+ , lm_cons :: m (ListMap m a) }++instance TrieMap m => TrieMap (ListMap m) where+ type Key (ListMap m) = [Key m]+ emptyTM = LM { lm_nil = Nothing, lm_cons = emptyTM }+ lookupTM = lkList lookupTM+ alterTM = xtList alterTM+ foldTM = fdList+ mapTM = mapList++mapList :: TrieMap m => (a->b) -> ListMap m a -> ListMap m b+mapList f (LM { lm_nil = mnil, lm_cons = mcons })+ = LM { lm_nil = fmap f mnil, lm_cons = mapTM (mapTM f) mcons }++lkList :: TrieMap m => (forall b. k -> m b -> Maybe b)+ -> [k] -> ListMap m a -> Maybe a+lkList _ [] = lm_nil+lkList lk (x:xs) = lm_cons >.> lk x >=> lkList lk xs++xtList :: TrieMap m => (forall b. k -> XT b -> m b -> m b)+ -> [k] -> XT a -> ListMap m a -> ListMap m a+xtList _ [] f m = m { lm_nil = f (lm_nil m) }+xtList tr (x:xs) f m = m { lm_cons = lm_cons m |> tr x |>> xtList tr xs f }++fdList :: forall m a b. TrieMap m+ => (a -> b -> b) -> ListMap m a -> b -> b+fdList k m = foldMaybe k (lm_nil m)+ . foldTM (fdList k) (lm_cons m)++foldMaybe :: (a -> b -> b) -> Maybe a -> b -> b+foldMaybe _ Nothing b = b+foldMaybe k (Just a) b = k a b++{-+************************************************************************+* *+ Basic maps+* *+************************************************************************+-}++lkDNamed :: NamedThing n => n -> DNameEnv a -> Maybe a+lkDNamed n env = lookupDNameEnv env (getName n)++xtDNamed :: NamedThing n => n -> XT a -> DNameEnv a -> DNameEnv a+xtDNamed tc f m = alterDNameEnv f m (getName tc)++------------------------+type LiteralMap a = Map.Map Literal a++emptyLiteralMap :: LiteralMap a+emptyLiteralMap = emptyTM++lkLit :: Literal -> LiteralMap a -> Maybe a+lkLit = lookupTM++xtLit :: Literal -> XT a -> LiteralMap a -> LiteralMap a+xtLit = alterTM++{-+************************************************************************+* *+ GenMap+* *+************************************************************************++Note [Compressed TrieMap]+~~~~~~~~~~~~~~~~~~~~~~~~~++The GenMap constructor augments TrieMaps with leaf compression. This helps+solve the performance problem detailed in #9960: suppose we have a handful+H of entries in a TrieMap, each with a very large key, size K. If you fold over+such a TrieMap you'd expect time O(H). That would certainly be true of an+association list! But with TrieMap we actually have to navigate down a long+singleton structure to get to the elements, so it takes time O(K*H). This+can really hurt on many type-level computation benchmarks:+see for example T9872d.++The point of a TrieMap is that you need to navigate to the point where only one+key remains, and then things should be fast. So the point of a SingletonMap+is that, once we are down to a single (key,value) pair, we stop and+just use SingletonMap.++'EmptyMap' provides an even more basic (but essential) optimization: if there is+nothing in the map, don't bother building out the (possibly infinite) recursive+TrieMap structure!+-}++data GenMap m a+ = EmptyMap+ | SingletonMap (Key m) a+ | MultiMap (m a)++instance (Outputable a, Outputable (m a)) => Outputable (GenMap m a) where+ ppr EmptyMap = text "Empty map"+ ppr (SingletonMap _ v) = text "Singleton map" <+> ppr v+ ppr (MultiMap m) = ppr m++-- TODO undecidable instance+instance (Eq (Key m), TrieMap m) => TrieMap (GenMap m) where+ type Key (GenMap m) = Key m+ emptyTM = EmptyMap+ lookupTM = lkG+ alterTM = xtG+ foldTM = fdG+ mapTM = mapG++-- NB: Be careful about RULES and type families (#5821). So we should make sure+-- to specify @Key TypeMapX@ (and not @DeBruijn Type@, the reduced form)++{-# SPECIALIZE lkG :: Key TypeMapX -> TypeMapG a -> Maybe a #-}+{-# SPECIALIZE lkG :: Key CoercionMapX -> CoercionMapG a -> Maybe a #-}+{-# SPECIALIZE lkG :: Key CoreMapX -> CoreMapG a -> Maybe a #-}+lkG :: (Eq (Key m), TrieMap m) => Key m -> GenMap m a -> Maybe a+lkG _ EmptyMap = Nothing+lkG k (SingletonMap k' v') | k == k' = Just v'+ | otherwise = Nothing+lkG k (MultiMap m) = lookupTM k m++{-# SPECIALIZE xtG :: Key TypeMapX -> XT a -> TypeMapG a -> TypeMapG a #-}+{-# SPECIALIZE xtG :: Key CoercionMapX -> XT a -> CoercionMapG a -> CoercionMapG a #-}+{-# SPECIALIZE xtG :: Key CoreMapX -> XT a -> CoreMapG a -> CoreMapG a #-}+xtG :: (Eq (Key m), TrieMap m) => Key m -> XT a -> GenMap m a -> GenMap m a+xtG k f EmptyMap+ = case f Nothing of+ Just v -> SingletonMap k v+ Nothing -> EmptyMap+xtG k f m@(SingletonMap k' v')+ | k' == k+ -- The new key matches the (single) key already in the tree. Hence,+ -- apply @f@ to @Just v'@ and build a singleton or empty map depending+ -- on the 'Just'/'Nothing' response respectively.+ = case f (Just v') of+ Just v'' -> SingletonMap k' v''+ Nothing -> EmptyMap+ | otherwise+ -- We've hit a singleton tree for a different key than the one we are+ -- searching for. Hence apply @f@ to @Nothing@. If result is @Nothing@ then+ -- we can just return the old map. If not, we need a map with *two*+ -- entries. The easiest way to do that is to insert two items into an empty+ -- map of type @m a@.+ = case f Nothing of+ Nothing -> m+ Just v -> emptyTM |> alterTM k' (const (Just v'))+ >.> alterTM k (const (Just v))+ >.> MultiMap+xtG k f (MultiMap m) = MultiMap (alterTM k f m)++{-# SPECIALIZE mapG :: (a -> b) -> TypeMapG a -> TypeMapG b #-}+{-# SPECIALIZE mapG :: (a -> b) -> CoercionMapG a -> CoercionMapG b #-}+{-# SPECIALIZE mapG :: (a -> b) -> CoreMapG a -> CoreMapG b #-}+mapG :: TrieMap m => (a -> b) -> GenMap m a -> GenMap m b+mapG _ EmptyMap = EmptyMap+mapG f (SingletonMap k v) = SingletonMap k (f v)+mapG f (MultiMap m) = MultiMap (mapTM f m)++{-# SPECIALIZE fdG :: (a -> b -> b) -> TypeMapG a -> b -> b #-}+{-# SPECIALIZE fdG :: (a -> b -> b) -> CoercionMapG a -> b -> b #-}+{-# SPECIALIZE fdG :: (a -> b -> b) -> CoreMapG a -> b -> b #-}+fdG :: TrieMap m => (a -> b -> b) -> GenMap m a -> b -> b+fdG _ EmptyMap = \z -> z+fdG k (SingletonMap _ v) = \z -> k v z+fdG k (MultiMap m) = foldTM k m++{-+************************************************************************+* *+ CoreMap+* *+************************************************************************++Note [Binders]+~~~~~~~~~~~~~~+ * In general we check binders as late as possible because types are+ less likely to differ than expression structure. That's why+ cm_lam :: CoreMapG (TypeMapG a)+ rather than+ cm_lam :: TypeMapG (CoreMapG a)++ * We don't need to look at the type of some binders, notalby+ - the case binder in (Case _ b _ _)+ - the binders in an alternative+ because they are totally fixed by the context++Note [Empty case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* For a key (Case e b ty (alt:alts)) we don't need to look the return type+ 'ty', because every alternative has that type.++* For a key (Case e b ty []) we MUST look at the return type 'ty', because+ otherwise (Case (error () "urk") _ Int []) would compare equal to+ (Case (error () "urk") _ Bool [])+ which is utterly wrong (Trac #6097)++We could compare the return type regardless, but the wildly common case+is that it's unnecessary, so we have two fields (cm_case and cm_ecase)+for the two possibilities. Only cm_ecase looks at the type.++See also Note [Empty case alternatives] in CoreSyn.+-}++-- | @CoreMap a@ is a map from 'CoreExpr' to @a@. If you are a client, this+-- is the type you want.+newtype CoreMap a = CoreMap (CoreMapG a)++instance TrieMap CoreMap where+ type Key CoreMap = CoreExpr+ emptyTM = CoreMap emptyTM+ lookupTM k (CoreMap m) = lookupTM (deBruijnize k) m+ alterTM k f (CoreMap m) = CoreMap (alterTM (deBruijnize k) f m)+ foldTM k (CoreMap m) = foldTM k m+ mapTM f (CoreMap m) = CoreMap (mapTM f m)++-- | @CoreMapG a@ is a map from @DeBruijn CoreExpr@ to @a@. The extended+-- key makes it suitable for recursive traversal, since it can track binders,+-- but it is strictly internal to this module. If you are including a 'CoreMap'+-- inside another 'TrieMap', this is the type you want.+type CoreMapG = GenMap CoreMapX++-- | @CoreMapX a@ is the base map from @DeBruijn CoreExpr@ to @a@, but without+-- the 'GenMap' optimization.+data CoreMapX a+ = CM { cm_var :: VarMap a+ , cm_lit :: LiteralMap a+ , cm_co :: CoercionMapG a+ , cm_type :: TypeMapG a+ , cm_cast :: CoreMapG (CoercionMapG a)+ , cm_tick :: CoreMapG (TickishMap a)+ , cm_app :: CoreMapG (CoreMapG a)+ , cm_lam :: CoreMapG (BndrMap a) -- Note [Binders]+ , cm_letn :: CoreMapG (CoreMapG (BndrMap a))+ , cm_letr :: ListMap CoreMapG (CoreMapG (ListMap BndrMap a))+ , cm_case :: CoreMapG (ListMap AltMap a)+ , cm_ecase :: CoreMapG (TypeMapG a) -- Note [Empty case alternatives]+ }++instance Eq (DeBruijn CoreExpr) where+ D env1 e1 == D env2 e2 = go e1 e2 where+ go (Var v1) (Var v2) = case (lookupCME env1 v1, lookupCME env2 v2) of+ (Just b1, Just b2) -> b1 == b2+ (Nothing, Nothing) -> v1 == v2+ _ -> False+ go (Lit lit1) (Lit lit2) = lit1 == lit2+ go (Type t1) (Type t2) = D env1 t1 == D env2 t2+ go (Coercion co1) (Coercion co2) = D env1 co1 == D env2 co2+ go (Cast e1 co1) (Cast e2 co2) = D env1 co1 == D env2 co2 && go e1 e2+ go (App f1 a1) (App f2 a2) = go f1 f2 && go a1 a2+ -- This seems a bit dodgy, see 'eqTickish'+ go (Tick n1 e1) (Tick n2 e2) = n1 == n2 && go e1 e2++ go (Lam b1 e1) (Lam b2 e2)+ = D env1 (varType b1) == D env2 (varType b2)+ && D (extendCME env1 b1) e1 == D (extendCME env2 b2) e2++ go (Let (NonRec v1 r1) e1) (Let (NonRec v2 r2) e2)+ = go r1 r2+ && D (extendCME env1 v1) e1 == D (extendCME env2 v2) e2++ go (Let (Rec ps1) e1) (Let (Rec ps2) e2)+ = length ps1 == length ps2+ && D env1' rs1 == D env2' rs2+ && D env1' e1 == D env2' e2+ where+ (bs1,rs1) = unzip ps1+ (bs2,rs2) = unzip ps2+ env1' = extendCMEs env1 bs1+ env2' = extendCMEs env2 bs2++ go (Case e1 b1 t1 a1) (Case e2 b2 t2 a2)+ | null a1 -- See Note [Empty case alternatives]+ = null a2 && go e1 e2 && D env1 t1 == D env2 t2+ | otherwise+ = go e1 e2 && D (extendCME env1 b1) a1 == D (extendCME env2 b2) a2++ go _ _ = False++emptyE :: CoreMapX a+emptyE = CM { cm_var = emptyTM, cm_lit = emptyLiteralMap+ , cm_co = emptyTM, cm_type = emptyTM+ , cm_cast = emptyTM, cm_app = emptyTM+ , cm_lam = emptyTM, cm_letn = emptyTM+ , cm_letr = emptyTM, cm_case = emptyTM+ , cm_ecase = emptyTM, cm_tick = emptyTM }++instance TrieMap CoreMapX where+ type Key CoreMapX = DeBruijn CoreExpr+ emptyTM = emptyE+ lookupTM = lkE+ alterTM = xtE+ foldTM = fdE+ mapTM = mapE++--------------------------+mapE :: (a->b) -> CoreMapX a -> CoreMapX b+mapE f (CM { cm_var = cvar, cm_lit = clit+ , cm_co = cco, cm_type = ctype+ , cm_cast = ccast , cm_app = capp+ , cm_lam = clam, cm_letn = cletn+ , cm_letr = cletr, cm_case = ccase+ , cm_ecase = cecase, cm_tick = ctick })+ = CM { cm_var = mapTM f cvar, cm_lit = mapTM f clit+ , cm_co = mapTM f cco, cm_type = mapTM f ctype+ , cm_cast = mapTM (mapTM f) ccast, cm_app = mapTM (mapTM f) capp+ , cm_lam = mapTM (mapTM f) clam, cm_letn = mapTM (mapTM (mapTM f)) cletn+ , cm_letr = mapTM (mapTM (mapTM f)) cletr, cm_case = mapTM (mapTM f) ccase+ , cm_ecase = mapTM (mapTM f) cecase, cm_tick = mapTM (mapTM f) ctick }++--------------------------+lookupCoreMap :: CoreMap a -> CoreExpr -> Maybe a+lookupCoreMap cm e = lookupTM e cm++extendCoreMap :: CoreMap a -> CoreExpr -> a -> CoreMap a+extendCoreMap m e v = alterTM e (\_ -> Just v) m++foldCoreMap :: (a -> b -> b) -> b -> CoreMap a -> b+foldCoreMap k z m = foldTM k m z++emptyCoreMap :: CoreMap a+emptyCoreMap = emptyTM++instance Outputable a => Outputable (CoreMap a) where+ ppr m = text "CoreMap elts" <+> ppr (foldTM (:) m [])++-------------------------+fdE :: (a -> b -> b) -> CoreMapX a -> b -> b+fdE k m+ = foldTM k (cm_var m)+ . foldTM k (cm_lit m)+ . foldTM k (cm_co m)+ . foldTM k (cm_type m)+ . foldTM (foldTM k) (cm_cast m)+ . foldTM (foldTM k) (cm_tick m)+ . foldTM (foldTM k) (cm_app m)+ . foldTM (foldTM k) (cm_lam m)+ . foldTM (foldTM (foldTM k)) (cm_letn m)+ . foldTM (foldTM (foldTM k)) (cm_letr m)+ . foldTM (foldTM k) (cm_case m)+ . foldTM (foldTM k) (cm_ecase m)++-- lkE: lookup in trie for expressions+lkE :: DeBruijn CoreExpr -> CoreMapX a -> Maybe a+lkE (D env expr) cm = go expr cm+ where+ go (Var v) = cm_var >.> lkVar env v+ go (Lit l) = cm_lit >.> lkLit l+ go (Type t) = cm_type >.> lkG (D env t)+ go (Coercion c) = cm_co >.> lkG (D env c)+ go (Cast e c) = cm_cast >.> lkG (D env e) >=> lkG (D env c)+ go (Tick tickish e) = cm_tick >.> lkG (D env e) >=> lkTickish tickish+ go (App e1 e2) = cm_app >.> lkG (D env e2) >=> lkG (D env e1)+ go (Lam v e) = cm_lam >.> lkG (D (extendCME env v) e)+ >=> lkBndr env v+ go (Let (NonRec b r) e) = cm_letn >.> lkG (D env r)+ >=> lkG (D (extendCME env b) e) >=> lkBndr env b+ go (Let (Rec prs) e) = let (bndrs,rhss) = unzip prs+ env1 = extendCMEs env bndrs+ in cm_letr+ >.> lkList (lkG . D env1) rhss+ >=> lkG (D env1 e)+ >=> lkList (lkBndr env1) bndrs+ go (Case e b ty as) -- See Note [Empty case alternatives]+ | null as = cm_ecase >.> lkG (D env e) >=> lkG (D env ty)+ | otherwise = cm_case >.> lkG (D env e)+ >=> lkList (lkA (extendCME env b)) as++xtE :: DeBruijn CoreExpr -> XT a -> CoreMapX a -> CoreMapX a+xtE (D env (Var v)) f m = m { cm_var = cm_var m+ |> xtVar env v f }+xtE (D env (Type t)) f m = m { cm_type = cm_type m+ |> xtG (D env t) f }+xtE (D env (Coercion c)) f m = m { cm_co = cm_co m+ |> xtG (D env c) f }+xtE (D _ (Lit l)) f m = m { cm_lit = cm_lit m |> xtLit l f }+xtE (D env (Cast e c)) f m = m { cm_cast = cm_cast m |> xtG (D env e)+ |>> xtG (D env c) f }+xtE (D env (Tick t e)) f m = m { cm_tick = cm_tick m |> xtG (D env e)+ |>> xtTickish t f }+xtE (D env (App e1 e2)) f m = m { cm_app = cm_app m |> xtG (D env e2)+ |>> xtG (D env e1) f }+xtE (D env (Lam v e)) f m = m { cm_lam = cm_lam m+ |> xtG (D (extendCME env v) e)+ |>> xtBndr env v f }+xtE (D env (Let (NonRec b r) e)) f m = m { cm_letn = cm_letn m+ |> xtG (D (extendCME env b) e)+ |>> xtG (D env r)+ |>> xtBndr env b f }+xtE (D env (Let (Rec prs) e)) f m = m { cm_letr =+ let (bndrs,rhss) = unzip prs+ env1 = extendCMEs env bndrs+ in cm_letr m+ |> xtList (xtG . D env1) rhss+ |>> xtG (D env1 e)+ |>> xtList (xtBndr env1)+ bndrs f }+xtE (D env (Case e b ty as)) f m+ | null as = m { cm_ecase = cm_ecase m |> xtG (D env e)+ |>> xtG (D env ty) f }+ | otherwise = m { cm_case = cm_case m |> xtG (D env e)+ |>> let env1 = extendCME env b+ in xtList (xtA env1) as f }++-- TODO: this seems a bit dodgy, see 'eqTickish'+type TickishMap a = Map.Map (Tickish Id) a+lkTickish :: Tickish Id -> TickishMap a -> Maybe a+lkTickish = lookupTM++xtTickish :: Tickish Id -> XT a -> TickishMap a -> TickishMap a+xtTickish = alterTM++------------------------+data AltMap a -- A single alternative+ = AM { am_deflt :: CoreMapG a+ , am_data :: DNameEnv (CoreMapG a)+ , am_lit :: LiteralMap (CoreMapG a) }++instance TrieMap AltMap where+ type Key AltMap = CoreAlt+ emptyTM = AM { am_deflt = emptyTM+ , am_data = emptyDNameEnv+ , am_lit = emptyLiteralMap }+ lookupTM = lkA emptyCME+ alterTM = xtA emptyCME+ foldTM = fdA+ mapTM = mapA++instance Eq (DeBruijn CoreAlt) where+ D env1 a1 == D env2 a2 = go a1 a2 where+ go (DEFAULT, _, rhs1) (DEFAULT, _, rhs2)+ = D env1 rhs1 == D env2 rhs2+ go (LitAlt lit1, _, rhs1) (LitAlt lit2, _, rhs2)+ = lit1 == lit2 && D env1 rhs1 == D env2 rhs2+ go (DataAlt dc1, bs1, rhs1) (DataAlt dc2, bs2, rhs2)+ = dc1 == dc2 &&+ D (extendCMEs env1 bs1) rhs1 == D (extendCMEs env2 bs2) rhs2+ go _ _ = False++mapA :: (a->b) -> AltMap a -> AltMap b+mapA f (AM { am_deflt = adeflt, am_data = adata, am_lit = alit })+ = AM { am_deflt = mapTM f adeflt+ , am_data = mapTM (mapTM f) adata+ , am_lit = mapTM (mapTM f) alit }++lkA :: CmEnv -> CoreAlt -> AltMap a -> Maybe a+lkA env (DEFAULT, _, rhs) = am_deflt >.> lkG (D env rhs)+lkA env (LitAlt lit, _, rhs) = am_lit >.> lkLit lit >=> lkG (D env rhs)+lkA env (DataAlt dc, bs, rhs) = am_data >.> lkDNamed dc+ >=> lkG (D (extendCMEs env bs) rhs)++xtA :: CmEnv -> CoreAlt -> XT a -> AltMap a -> AltMap a+xtA env (DEFAULT, _, rhs) f m =+ m { am_deflt = am_deflt m |> xtG (D env rhs) f }+xtA env (LitAlt l, _, rhs) f m =+ m { am_lit = am_lit m |> xtLit l |>> xtG (D env rhs) f }+xtA env (DataAlt d, bs, rhs) f m =+ m { am_data = am_data m |> xtDNamed d+ |>> xtG (D (extendCMEs env bs) rhs) f }++fdA :: (a -> b -> b) -> AltMap a -> b -> b+fdA k m = foldTM k (am_deflt m)+ . foldTM (foldTM k) (am_data m)+ . foldTM (foldTM k) (am_lit m)++{-+************************************************************************+* *+ Coercions+* *+************************************************************************+-}++-- We should really never care about the contents of a coercion. Instead,+-- just look up the coercion's type.+newtype CoercionMap a = CoercionMap (CoercionMapG a)++instance TrieMap CoercionMap where+ type Key CoercionMap = Coercion+ emptyTM = CoercionMap emptyTM+ lookupTM k (CoercionMap m) = lookupTM (deBruijnize k) m+ alterTM k f (CoercionMap m) = CoercionMap (alterTM (deBruijnize k) f m)+ foldTM k (CoercionMap m) = foldTM k m+ mapTM f (CoercionMap m) = CoercionMap (mapTM f m)++type CoercionMapG = GenMap CoercionMapX+newtype CoercionMapX a = CoercionMapX (TypeMapX a)++instance TrieMap CoercionMapX where+ type Key CoercionMapX = DeBruijn Coercion+ emptyTM = CoercionMapX emptyTM+ lookupTM = lkC+ alterTM = xtC+ foldTM f (CoercionMapX core_tm) = foldTM f core_tm+ mapTM f (CoercionMapX core_tm) = CoercionMapX (mapTM f core_tm)++instance Eq (DeBruijn Coercion) where+ D env1 co1 == D env2 co2+ = D env1 (coercionType co1) ==+ D env2 (coercionType co2)++lkC :: DeBruijn Coercion -> CoercionMapX a -> Maybe a+lkC (D env co) (CoercionMapX core_tm) = lkT (D env $ coercionType co)+ core_tm++xtC :: DeBruijn Coercion -> XT a -> CoercionMapX a -> CoercionMapX a+xtC (D env co) f (CoercionMapX m)+ = CoercionMapX (xtT (D env $ coercionType co) f m)++{-+************************************************************************+* *+ Types+* *+************************************************************************+-}++-- | @TypeMapG a@ is a map from @DeBruijn Type@ to @a@. The extended+-- key makes it suitable for recursive traversal, since it can track binders,+-- but it is strictly internal to this module. If you are including a 'TypeMap'+-- inside another 'TrieMap', this is the type you want. Note that this+-- lookup does not do a kind-check. Thus, all keys in this map must have+-- the same kind. Also note that this map respects the distinction between+-- @Type@ and @Constraint@, despite the fact that they are equivalent type+-- synonyms in Core.+type TypeMapG = GenMap TypeMapX++-- | @TypeMapX a@ is the base map from @DeBruijn Type@ to @a@, but without the+-- 'GenMap' optimization.+data TypeMapX a+ = TM { tm_var :: VarMap a+ , tm_app :: TypeMapG (TypeMapG a)+ , tm_tycon :: DNameEnv a+ , tm_forall :: TypeMapG (BndrMap a) -- See Note [Binders]+ , tm_tylit :: TyLitMap a+ , tm_coerce :: Maybe a+ }+ -- Note that there is no tyconapp case; see Note [Equality on AppTys] in Type++-- | Squeeze out any synonyms, and change TyConApps to nested AppTys. Why the+-- last one? See Note [Equality on AppTys] in Type+--+-- Note, however, that we keep Constraint and Type apart here, despite the fact+-- that they are both synonyms of TYPE 'LiftedRep (see #11715).+trieMapView :: Type -> Maybe Type+trieMapView ty+ -- First check for TyConApps that need to be expanded to+ -- AppTy chains.+ | Just (tc, tys@(_:_)) <- tcSplitTyConApp_maybe ty+ = Just $ foldl AppTy (TyConApp tc []) tys++ -- Then resolve any remaining nullary synonyms.+ | Just ty' <- tcView ty = Just ty'+trieMapView _ = Nothing++instance TrieMap TypeMapX where+ type Key TypeMapX = DeBruijn Type+ emptyTM = emptyT+ lookupTM = lkT+ alterTM = xtT+ foldTM = fdT+ mapTM = mapT++instance Eq (DeBruijn Type) where+ env_t@(D env t) == env_t'@(D env' t')+ | Just new_t <- tcView t = D env new_t == env_t'+ | Just new_t' <- tcView t' = env_t == D env' new_t'+ | otherwise+ = case (t, t') of+ (CastTy t1 _, _) -> D env t1 == D env t'+ (_, CastTy t1' _) -> D env t == D env t1'++ (TyVarTy v, TyVarTy v')+ -> case (lookupCME env v, lookupCME env' v') of+ (Just bv, Just bv') -> bv == bv'+ (Nothing, Nothing) -> v == v'+ _ -> False+ -- See Note [Equality on AppTys] in Type+ (AppTy t1 t2, s) | Just (t1', t2') <- repSplitAppTy_maybe s+ -> D env t1 == D env' t1' && D env t2 == D env' t2'+ (s, AppTy t1' t2') | Just (t1, t2) <- repSplitAppTy_maybe s+ -> D env t1 == D env' t1' && D env t2 == D env' t2'+ (FunTy t1 t2, FunTy t1' t2')+ -> D env t1 == D env' t1' && D env t2 == D env' t2'+ (TyConApp tc tys, TyConApp tc' tys')+ -> tc == tc' && D env tys == D env' tys'+ (LitTy l, LitTy l')+ -> l == l'+ (ForAllTy (TvBndr tv _) ty, ForAllTy (TvBndr tv' _) ty')+ -> D env (tyVarKind tv) == D env' (tyVarKind tv') &&+ D (extendCME env tv) ty == D (extendCME env' tv') ty'+ (CoercionTy {}, CoercionTy {})+ -> True+ _ -> False++instance {-# OVERLAPPING #-}+ Outputable a => Outputable (TypeMapG a) where+ ppr m = text "TypeMap elts" <+> ppr (foldTM (:) m [])++emptyT :: TypeMapX a+emptyT = TM { tm_var = emptyTM+ , tm_app = EmptyMap+ , tm_tycon = emptyDNameEnv+ , tm_forall = EmptyMap+ , tm_tylit = emptyTyLitMap+ , tm_coerce = Nothing }++mapT :: (a->b) -> TypeMapX a -> TypeMapX b+mapT f (TM { tm_var = tvar, tm_app = tapp, tm_tycon = ttycon+ , tm_forall = tforall, tm_tylit = tlit+ , tm_coerce = tcoerce })+ = TM { tm_var = mapTM f tvar+ , tm_app = mapTM (mapTM f) tapp+ , tm_tycon = mapTM f ttycon+ , tm_forall = mapTM (mapTM f) tforall+ , tm_tylit = mapTM f tlit+ , tm_coerce = fmap f tcoerce }++-----------------+lkT :: DeBruijn Type -> TypeMapX a -> Maybe a+lkT (D env ty) m = go ty m+ where+ go ty | Just ty' <- trieMapView ty = go ty'+ go (TyVarTy v) = tm_var >.> lkVar env v+ go (AppTy t1 t2) = tm_app >.> lkG (D env t1)+ >=> lkG (D env t2)+ go (TyConApp tc []) = tm_tycon >.> lkDNamed tc+ go ty@(TyConApp _ (_:_)) = pprPanic "lkT TyConApp" (ppr ty)+ go (LitTy l) = tm_tylit >.> lkTyLit l+ go (ForAllTy (TvBndr tv _) ty) = tm_forall >.> lkG (D (extendCME env tv) ty)+ >=> lkBndr env tv+ go ty@(FunTy {}) = pprPanic "lkT FunTy" (ppr ty)+ go (CastTy t _) = go t+ go (CoercionTy {}) = tm_coerce++-----------------+xtT :: DeBruijn Type -> XT a -> TypeMapX a -> TypeMapX a+xtT (D env ty) f m | Just ty' <- trieMapView ty = xtT (D env ty') f m++xtT (D env (TyVarTy v)) f m = m { tm_var = tm_var m |> xtVar env v f }+xtT (D env (AppTy t1 t2)) f m = m { tm_app = tm_app m |> xtG (D env t1)+ |>> xtG (D env t2) f }+xtT (D _ (TyConApp tc [])) f m = m { tm_tycon = tm_tycon m |> xtDNamed tc f }+xtT (D _ (LitTy l)) f m = m { tm_tylit = tm_tylit m |> xtTyLit l f }+xtT (D env (CastTy t _)) f m = xtT (D env t) f m+xtT (D _ (CoercionTy {})) f m = m { tm_coerce = tm_coerce m |> f }+xtT (D env (ForAllTy (TvBndr tv _) ty)) f m+ = m { tm_forall = tm_forall m |> xtG (D (extendCME env tv) ty)+ |>> xtBndr env tv f }+xtT (D _ ty@(TyConApp _ (_:_))) _ _ = pprPanic "xtT TyConApp" (ppr ty)+xtT (D _ ty@(FunTy {})) _ _ = pprPanic "xtT FunTy" (ppr ty)++fdT :: (a -> b -> b) -> TypeMapX a -> b -> b+fdT k m = foldTM k (tm_var m)+ . foldTM (foldTM k) (tm_app m)+ . foldTM k (tm_tycon m)+ . foldTM (foldTM k) (tm_forall m)+ . foldTyLit k (tm_tylit m)+ . foldMaybe k (tm_coerce m)++------------------------+data TyLitMap a = TLM { tlm_number :: Map.Map Integer a+ , tlm_string :: Map.Map FastString a+ }++instance TrieMap TyLitMap where+ type Key TyLitMap = TyLit+ emptyTM = emptyTyLitMap+ lookupTM = lkTyLit+ alterTM = xtTyLit+ foldTM = foldTyLit+ mapTM = mapTyLit++emptyTyLitMap :: TyLitMap a+emptyTyLitMap = TLM { tlm_number = Map.empty, tlm_string = Map.empty }++mapTyLit :: (a->b) -> TyLitMap a -> TyLitMap b+mapTyLit f (TLM { tlm_number = tn, tlm_string = ts })+ = TLM { tlm_number = Map.map f tn, tlm_string = Map.map f ts }++lkTyLit :: TyLit -> TyLitMap a -> Maybe a+lkTyLit l =+ case l of+ NumTyLit n -> tlm_number >.> Map.lookup n+ StrTyLit n -> tlm_string >.> Map.lookup n++xtTyLit :: TyLit -> XT a -> TyLitMap a -> TyLitMap a+xtTyLit l f m =+ case l of+ NumTyLit n -> m { tlm_number = tlm_number m |> Map.alter f n }+ StrTyLit n -> m { tlm_string = tlm_string m |> Map.alter f n }++foldTyLit :: (a -> b -> b) -> TyLitMap a -> b -> b+foldTyLit l m = flip (Map.foldr l) (tlm_string m)+ . flip (Map.foldr l) (tlm_number m)++-------------------------------------------------+-- | @TypeMap a@ is a map from 'Type' to @a@. If you are a client, this+-- is the type you want. The keys in this map may have different kinds.+newtype TypeMap a = TypeMap (TypeMapG (TypeMapG a))++lkTT :: DeBruijn Type -> TypeMap a -> Maybe a+lkTT (D env ty) (TypeMap m) = lkG (D env $ typeKind ty) m+ >>= lkG (D env ty)++xtTT :: DeBruijn Type -> XT a -> TypeMap a -> TypeMap a+xtTT (D env ty) f (TypeMap m)+ = TypeMap (m |> xtG (D env $ typeKind ty)+ |>> xtG (D env ty) f)++-- Below are some client-oriented functions which operate on 'TypeMap'.++instance TrieMap TypeMap where+ type Key TypeMap = Type+ emptyTM = TypeMap emptyTM+ lookupTM k m = lkTT (deBruijnize k) m+ alterTM k f m = xtTT (deBruijnize k) f m+ foldTM k (TypeMap m) = foldTM (foldTM k) m+ mapTM f (TypeMap m) = TypeMap (mapTM (mapTM f) m)++foldTypeMap :: (a -> b -> b) -> b -> TypeMap a -> b+foldTypeMap k z m = foldTM k m z++emptyTypeMap :: TypeMap a+emptyTypeMap = emptyTM++lookupTypeMap :: TypeMap a -> Type -> Maybe a+lookupTypeMap cm t = lookupTM t cm++extendTypeMap :: TypeMap a -> Type -> a -> TypeMap a+extendTypeMap m t v = alterTM t (const (Just v)) m++lookupTypeMapWithScope :: TypeMap a -> CmEnv -> Type -> Maybe a+lookupTypeMapWithScope m cm t = lkTT (D cm t) m++-- | Extend a 'TypeMap' with a type in the given context.+-- @extendTypeMapWithScope m (mkDeBruijnContext [a,b,c]) t v@ is equivalent to+-- @extendTypeMap m (forall a b c. t) v@, but allows reuse of the context over+-- multiple insertions.+extendTypeMapWithScope :: TypeMap a -> CmEnv -> Type -> a -> TypeMap a+extendTypeMapWithScope m cm t v = xtTT (D cm t) (const (Just v)) m++-- | Construct a deBruijn environment with the given variables in scope.+-- e.g. @mkDeBruijnEnv [a,b,c]@ constructs a context @forall a b c.@+mkDeBruijnContext :: [Var] -> CmEnv+mkDeBruijnContext = extendCMEs emptyCME++-- | A 'LooseTypeMap' doesn't do a kind-check. Thus, when lookup up (t |> g),+-- you'll find entries inserted under (t), even if (g) is non-reflexive.+newtype LooseTypeMap a+ = LooseTypeMap (TypeMapG a)++instance TrieMap LooseTypeMap where+ type Key LooseTypeMap = Type+ emptyTM = LooseTypeMap emptyTM+ lookupTM k (LooseTypeMap m) = lookupTM (deBruijnize k) m+ alterTM k f (LooseTypeMap m) = LooseTypeMap (alterTM (deBruijnize k) f m)+ foldTM f (LooseTypeMap m) = foldTM f m+ mapTM f (LooseTypeMap m) = LooseTypeMap (mapTM f m)++{-+************************************************************************+* *+ Variables+* *+************************************************************************+-}++type BoundVar = Int -- Bound variables are deBruijn numbered+type BoundVarMap a = IntMap.IntMap a++data CmEnv = CME { cme_next :: !BoundVar+ , cme_env :: VarEnv BoundVar }++emptyCME :: CmEnv+emptyCME = CME { cme_next = 0, cme_env = emptyVarEnv }++extendCME :: CmEnv -> Var -> CmEnv+extendCME (CME { cme_next = bv, cme_env = env }) v+ = CME { cme_next = bv+1, cme_env = extendVarEnv env v bv }++extendCMEs :: CmEnv -> [Var] -> CmEnv+extendCMEs env vs = foldl extendCME env vs++lookupCME :: CmEnv -> Var -> Maybe BoundVar+lookupCME (CME { cme_env = env }) v = lookupVarEnv env v++-- | @DeBruijn a@ represents @a@ modulo alpha-renaming. This is achieved+-- by equipping the value with a 'CmEnv', which tracks an on-the-fly deBruijn+-- numbering. This allows us to define an 'Eq' instance for @DeBruijn a@, even+-- if this was not (easily) possible for @a@. Note: we purposely don't+-- export the constructor. Make a helper function if you find yourself+-- needing it.+data DeBruijn a = D CmEnv a++-- | Synthesizes a @DeBruijn a@ from an @a@, by assuming that there are no+-- bound binders (an empty 'CmEnv'). This is usually what you want if there+-- isn't already a 'CmEnv' in scope.+deBruijnize :: a -> DeBruijn a+deBruijnize = D emptyCME++instance Eq (DeBruijn a) => Eq (DeBruijn [a]) where+ D _ [] == D _ [] = True+ D env (x:xs) == D env' (x':xs') = D env x == D env' x' &&+ D env xs == D env' xs'+ _ == _ = False++--------- Variable binders -------------++-- | A 'BndrMap' is a 'TypeMapG' which allows us to distinguish between+-- binding forms whose binders have different types. For example,+-- if we are doing a 'TrieMap' lookup on @\(x :: Int) -> ()@, we should+-- not pick up an entry in the 'TrieMap' for @\(x :: Bool) -> ()@:+-- we can disambiguate this by matching on the type (or kind, if this+-- a binder in a type) of the binder.+type BndrMap = TypeMapG++-- Note [Binders]+-- ~~~~~~~~~~~~~~+-- We need to use 'BndrMap' for 'Coercion', 'CoreExpr' AND 'Type', since all+-- of these data types have binding forms.++lkBndr :: CmEnv -> Var -> BndrMap a -> Maybe a+lkBndr env v m = lkG (D env (varType v)) m++xtBndr :: CmEnv -> Var -> XT a -> BndrMap a -> BndrMap a+xtBndr env v f = xtG (D env (varType v)) f++--------- Variable occurrence -------------+data VarMap a = VM { vm_bvar :: BoundVarMap a -- Bound variable+ , vm_fvar :: DVarEnv a } -- Free variable++instance TrieMap VarMap where+ type Key VarMap = Var+ emptyTM = VM { vm_bvar = IntMap.empty, vm_fvar = emptyDVarEnv }+ lookupTM = lkVar emptyCME+ alterTM = xtVar emptyCME+ foldTM = fdVar+ mapTM = mapVar++mapVar :: (a->b) -> VarMap a -> VarMap b+mapVar f (VM { vm_bvar = bv, vm_fvar = fv })+ = VM { vm_bvar = mapTM f bv, vm_fvar = mapTM f fv }++lkVar :: CmEnv -> Var -> VarMap a -> Maybe a+lkVar env v+ | Just bv <- lookupCME env v = vm_bvar >.> lookupTM bv+ | otherwise = vm_fvar >.> lkDFreeVar v++xtVar :: CmEnv -> Var -> XT a -> VarMap a -> VarMap a+xtVar env v f m+ | Just bv <- lookupCME env v = m { vm_bvar = vm_bvar m |> alterTM bv f }+ | otherwise = m { vm_fvar = vm_fvar m |> xtDFreeVar v f }++fdVar :: (a -> b -> b) -> VarMap a -> b -> b+fdVar k m = foldTM k (vm_bvar m)+ . foldTM k (vm_fvar m)++lkDFreeVar :: Var -> DVarEnv a -> Maybe a+lkDFreeVar var env = lookupDVarEnv env var++xtDFreeVar :: Var -> XT a -> DVarEnv a -> DVarEnv a+xtDFreeVar v f m = alterDVarEnv f m v
+ deSugar/Check.hs view
@@ -0,0 +1,1859 @@+{-+Author: George Karachalias <george.karachalias@cs.kuleuven.be>++Pattern Matching Coverage Checking.+-}++{-# LANGUAGE CPP, GADTs, DataKinds, KindSignatures #-}+{-# LANGUAGE TupleSections #-}++module Check (+ -- Checking and printing+ checkSingle, checkMatches, isAnyPmCheckEnabled,++ -- See Note [Type and Term Equality Propagation]+ genCaseTmCs1, genCaseTmCs2+ ) where++#include "HsVersions.h"++import TmOracle++import DynFlags+import HsSyn+import TcHsSyn+import Id+import ConLike+import Name+import FamInstEnv+import TysWiredIn+import TyCon+import SrcLoc+import Util+import Outputable+import FastString+import DataCon+import HscTypes (CompleteMatch(..))++import DsMonad+import TcSimplify (tcCheckSatisfiability)+import TcType (toTcType, isStringTy, isIntTy, isWordTy)+import Bag+import ErrUtils+import Var (EvVar)+import Type+import UniqSupply+import DsGRHSs (isTrueLHsExpr)++import Data.List (find)+import Data.Maybe (isJust, fromMaybe)+import Control.Monad (forM, when, forM_)+import Coercion+import TcEvidence+import IOEnv++import ListT (ListT(..), fold, select)++{-+This module checks pattern matches for:+\begin{enumerate}+ \item Equations that are redundant+ \item Equations with inaccessible right-hand-side+ \item Exhaustiveness+\end{enumerate}++The algorithm is based on the paper:++ "GADTs Meet Their Match:+ Pattern-matching Warnings That Account for GADTs, Guards, and Laziness"++ http://people.cs.kuleuven.be/~george.karachalias/papers/p424-karachalias.pdf++%************************************************************************+%* *+ Pattern Match Check Types+%* *+%************************************************************************+-}++-- We use the non-determinism monad to apply the algorithm to several+-- possible sets of constructors. Users can specify complete sets of+-- constructors by using COMPLETE pragmas.+-- The algorithm only picks out constructor+-- sets deep in the bowels which makes a simpler `mapM` more difficult to+-- implement. The non-determinism is only used in one place, see the ConVar+-- case in `pmCheckHd`.++type PmM a = ListT DsM a++liftD :: DsM a -> PmM a+liftD m = ListT $ \sk fk -> m >>= \a -> sk a fk++-- Pick the first match complete covered match or otherwise the "best" match.+-- The best match is the one with the least uncovered clauses, ties broken+-- by the number of inaccessible clauses followed by number of redudant+-- clauses+getResult :: PmM PmResult -> DsM PmResult+getResult ls = do+ res <- fold ls goM (pure Nothing)+ case res of+ Nothing -> panic "getResult is empty"+ Just a -> return a+ where+ goM :: PmResult -> DsM (Maybe PmResult) -> DsM (Maybe PmResult)+ goM mpm dpm = do+ pmr <- dpm+ return $ go pmr mpm+ -- Careful not to force unecessary results+ go :: Maybe PmResult -> PmResult -> Maybe PmResult+ go Nothing rs = Just rs+ go old@(Just (PmResult prov rs (UncoveredPatterns us) is)) new+ | null us && null rs && null is = old+ | otherwise =+ let PmResult prov' rs' (UncoveredPatterns us') is' = new+ lr = length rs+ lr' = length rs'+ li = length is+ li' = length is'+ in case compare (length us) (length us')+ `mappend` (compare li li')+ `mappend` (compare lr lr')+ `mappend` (compare prov prov') of+ GT -> Just new+ EQ -> Just new+ LT -> old+ go (Just (PmResult _ _ (TypeOfUncovered _) _)) _new+ = panic "getResult: No inhabitation candidates"++data PatTy = PAT | VA -- Used only as a kind, to index PmPat++-- The *arity* of a PatVec [p1,..,pn] is+-- the number of p1..pn that are not Guards++data PmPat :: PatTy -> * where+ PmCon :: { pm_con_con :: ConLike+ , pm_con_arg_tys :: [Type]+ , pm_con_tvs :: [TyVar]+ , pm_con_dicts :: [EvVar]+ , pm_con_args :: [PmPat t] } -> PmPat t+ -- For PmCon arguments' meaning see @ConPatOut@ in hsSyn/HsPat.hs+ PmVar :: { pm_var_id :: Id } -> PmPat t+ PmLit :: { pm_lit_lit :: PmLit } -> PmPat t -- See Note [Literals in PmPat]+ PmNLit :: { pm_lit_id :: Id+ , pm_lit_not :: [PmLit] } -> PmPat 'VA+ PmGrd :: { pm_grd_pv :: PatVec+ , pm_grd_expr :: PmExpr } -> PmPat 'PAT++-- data T a where+-- MkT :: forall p q. (Eq p, Ord q) => p -> q -> T [p]+-- or MkT :: forall p q r. (Eq p, Ord q, [p] ~ r) => p -> q -> T r++type Pattern = PmPat 'PAT -- ^ Patterns+type ValAbs = PmPat 'VA -- ^ Value Abstractions++type PatVec = [Pattern] -- ^ Pattern Vectors+data ValVec = ValVec [ValAbs] Delta -- ^ Value Vector Abstractions++-- | Term and type constraints to accompany each value vector abstraction.+-- For efficiency, we store the term oracle state instead of the term+-- constraints. TODO: Do the same for the type constraints?+data Delta = MkDelta { delta_ty_cs :: Bag EvVar+ , delta_tm_cs :: TmState }++type ValSetAbs = [ValVec] -- ^ Value Set Abstractions+type Uncovered = ValSetAbs++-- Instead of keeping the whole sets in memory, we keep a boolean for both the+-- covered and the divergent set (we store the uncovered set though, since we+-- want to print it). For both the covered and the divergent we have:+--+-- True <=> The set is non-empty+--+-- hence:+-- C = True ==> Useful clause (no warning)+-- C = False, D = True ==> Clause with inaccessible RHS+-- C = False, D = False ==> Redundant clause++data Covered = Covered | NotCovered+ deriving Show++instance Outputable Covered where+ ppr (Covered) = text "Covered"+ ppr (NotCovered) = text "NotCovered"++-- Like the or monoid for booleans+-- Covered = True, Uncovered = False+instance Monoid Covered where+ mempty = NotCovered+ Covered `mappend` _ = Covered+ _ `mappend` Covered = Covered+ NotCovered `mappend` NotCovered = NotCovered++data Diverged = Diverged | NotDiverged+ deriving Show++instance Outputable Diverged where+ ppr Diverged = text "Diverged"+ ppr NotDiverged = text "NotDiverged"++instance Monoid Diverged where+ mempty = NotDiverged+ Diverged `mappend` _ = Diverged+ _ `mappend` Diverged = Diverged+ NotDiverged `mappend` NotDiverged = NotDiverged++-- | When we learned that a given match group is complete+data Provenance =+ FromBuiltin -- ^ From the original definition of the type+ -- constructor.+ | FromComplete -- ^ From a user-provided @COMPLETE@ pragma+ deriving (Show, Eq, Ord)++instance Outputable Provenance where+ ppr = text . show++instance Monoid Provenance where+ mempty = FromBuiltin+ FromComplete `mappend` _ = FromComplete+ _ `mappend` FromComplete = FromComplete+ _ `mappend` _ = FromBuiltin++data PartialResult = PartialResult {+ presultProvenence :: Provenance+ -- keep track of provenance because we don't want+ -- to warn about redundant matches if the result+ -- is contaiminated with a COMPLETE pragma+ , presultCovered :: Covered+ , presultUncovered :: Uncovered+ , presultDivergent :: Diverged }++instance Outputable PartialResult where+ ppr (PartialResult prov c vsa d)+ = text "PartialResult" <+> ppr prov <+> ppr c+ <+> ppr d <+> ppr vsa++instance Monoid PartialResult where+ mempty = PartialResult mempty mempty [] mempty+ (PartialResult prov1 cs1 vsa1 ds1)+ `mappend` (PartialResult prov2 cs2 vsa2 ds2)+ = PartialResult (prov1 `mappend` prov2)+ (cs1 `mappend` cs2)+ (vsa1 `mappend` vsa2)+ (ds1 `mappend` ds2)++-- newtype ChoiceOf a = ChoiceOf [a]++-- | Pattern check result+--+-- * Redundant clauses+-- * Not-covered clauses (or their type, if no pattern is available)+-- * Clauses with inaccessible RHS+--+-- More details about the classification of clauses into useful, redundant+-- and with inaccessible right hand side can be found here:+--+-- https://ghc.haskell.org/trac/ghc/wiki/PatternMatchCheck+--+data PmResult =+ PmResult {+ pmresultProvenance :: Provenance+ , pmresultRedundant :: [Located [LPat Id]]+ , pmresultUncovered :: UncoveredCandidates+ , pmresultInaccessible :: [Located [LPat Id]] }++-- | Either a list of patterns that are not covered, or their type, in case we+-- have no patterns at hand. Not having patterns at hand can arise when+-- handling EmptyCase expressions, in two cases:+--+-- * The type of the scrutinee is a trivially inhabited type (like Int or Char)+-- * The type of the scrutinee cannot be reduced to WHNF.+--+-- In both these cases we have no inhabitation candidates for the type at hand,+-- but we don't want to issue just a wildcard as missing. Instead, we print a+-- type annotated wildcard, so that the user knows what kind of patterns is+-- expected (e.g. (_ :: Int), or (_ :: F Int), where F Int does not reduce).+data UncoveredCandidates = UncoveredPatterns Uncovered+ | TypeOfUncovered Type++-- | The empty pattern check result+emptyPmResult :: PmResult+emptyPmResult = PmResult FromBuiltin [] (UncoveredPatterns []) []++-- | Non-exhaustive empty case with unknown/trivial inhabitants+uncoveredWithTy :: Type -> PmResult+uncoveredWithTy ty = PmResult FromBuiltin [] (TypeOfUncovered ty) []++{-+%************************************************************************+%* *+ Entry points to the checker: checkSingle and checkMatches+%* *+%************************************************************************+-}++-- | Check a single pattern binding (let)+checkSingle :: DynFlags -> DsMatchContext -> Id -> Pat Id -> DsM ()+checkSingle dflags ctxt@(DsMatchContext _ locn) var p = do+ tracePmD "checkSingle" (vcat [ppr ctxt, ppr var, ppr p])+ mb_pm_res <- tryM (getResult (checkSingle' locn var p))+ case mb_pm_res of+ Left _ -> warnPmIters dflags ctxt+ Right res -> dsPmWarn dflags ctxt res++-- | Check a single pattern binding (let)+checkSingle' :: SrcSpan -> Id -> Pat Id -> PmM PmResult+checkSingle' locn var p = do+ liftD resetPmIterDs -- set the iter-no to zero+ fam_insts <- liftD dsGetFamInstEnvs+ clause <- liftD $ translatePat fam_insts p+ missing <- mkInitialUncovered [var]+ tracePm "checkSingle: missing" (vcat (map pprValVecDebug missing))+ -- no guards+ PartialResult prov cs us ds <- runMany (pmcheckI clause []) missing+ let us' = UncoveredPatterns us+ return $ case (cs,ds) of+ (Covered, _ ) -> PmResult prov [] us' [] -- useful+ (NotCovered, NotDiverged) -> PmResult prov m us' [] -- redundant+ (NotCovered, Diverged ) -> PmResult prov [] us' m -- inaccessible rhs+ where m = [L locn [L locn p]]++-- | Check a matchgroup (case, functions, etc.)+checkMatches :: DynFlags -> DsMatchContext+ -> [Id] -> [LMatch Id (LHsExpr Id)] -> DsM ()+checkMatches dflags ctxt vars matches = do+ tracePmD "checkMatches" (hang (vcat [ppr ctxt+ , ppr vars+ , text "Matches:"])+ 2+ (vcat (map ppr matches)))+ mb_pm_res <- tryM $ getResult $ case matches of+ -- Check EmptyCase separately+ -- See Note [Checking EmptyCase Expressions]+ [] | [var] <- vars -> checkEmptyCase' var+ _normal_match -> checkMatches' vars matches+ case mb_pm_res of+ Left _ -> warnPmIters dflags ctxt+ Right res -> dsPmWarn dflags ctxt res++-- | Check a matchgroup (case, functions, etc.). To be called on a non-empty+-- list of matches. For empty case expressions, use checkEmptyCase' instead.+checkMatches' :: [Id] -> [LMatch Id (LHsExpr Id)] -> PmM PmResult+checkMatches' vars matches+ | null matches = panic "checkMatches': EmptyCase"+ | otherwise = do+ liftD resetPmIterDs -- set the iter-no to zero+ missing <- mkInitialUncovered vars+ tracePm "checkMatches: missing" (vcat (map pprValVecDebug missing))+ (prov, rs,us,ds) <- go matches missing+ return $ PmResult {+ pmresultProvenance = prov+ , pmresultRedundant = map hsLMatchToLPats rs+ , pmresultUncovered = UncoveredPatterns us+ , pmresultInaccessible = map hsLMatchToLPats ds }+ where+ go :: [LMatch Id (LHsExpr Id)] -> Uncovered+ -> PmM (Provenance+ , [LMatch Id (LHsExpr Id)]+ , Uncovered+ , [LMatch Id (LHsExpr Id)])+ go [] missing = return (mempty, [], missing, [])+ go (m:ms) missing = do+ tracePm "checMatches': go" (ppr m $$ ppr missing)+ fam_insts <- liftD dsGetFamInstEnvs+ (clause, guards) <- liftD $ translateMatch fam_insts m+ r@(PartialResult prov cs missing' ds)+ <- runMany (pmcheckI clause guards) missing+ tracePm "checMatches': go: res" (ppr r)+ (ms_prov, rs, final_u, is) <- go ms missing'+ let final_prov = prov `mappend` ms_prov+ return $ case (cs, ds) of+ -- useful+ (Covered, _ ) -> (final_prov, rs, final_u, is)+ -- redundant+ (NotCovered, NotDiverged) -> (final_prov, m:rs, final_u,is)+ -- inaccessible+ (NotCovered, Diverged ) -> (final_prov, rs, final_u, m:is)++ hsLMatchToLPats :: LMatch id body -> Located [LPat id]+ hsLMatchToLPats (L l (Match _ pats _ _)) = L l pats++-- | Check an empty case expression. Since there are no clauses to process, we+-- only compute the uncovered set. See Note [Checking EmptyCase Expressions]+-- for details.+checkEmptyCase' :: Id -> PmM PmResult+checkEmptyCase' var = do+ tm_css <- map toComplex . bagToList <$> liftD getTmCsDs+ case tmOracle initialTmState tm_css of+ Just tm_state -> do+ ty_css <- liftD getDictsDs+ fam_insts <- liftD dsGetFamInstEnvs+ mb_candidates <- inhabitationCandidates fam_insts (idType var)+ case mb_candidates of+ -- Inhabitation checking failed / the type is trivially inhabited+ Left ty -> return (uncoveredWithTy ty)++ -- A list of inhabitant candidates is available: Check for each+ -- one for the satisfiability of the constraints it gives rise to.+ Right candidates -> do+ missing_m <- flip concatMapM candidates $ \(va,tm_ct,ty_cs) -> do+ let all_ty_cs = unionBags ty_cs ty_css+ sat_ty <- tyOracle all_ty_cs+ return $ case (sat_ty, tmOracle tm_state (tm_ct:tm_css)) of+ (True, Just tm_state') -> [(va, all_ty_cs, tm_state')]+ _non_sat -> []+ let mkValVec (va,all_ty_cs,tm_state')+ = ValVec [va] (MkDelta all_ty_cs tm_state')+ uncovered = UncoveredPatterns (map mkValVec missing_m)+ return $ if null missing_m+ then emptyPmResult+ else PmResult FromBuiltin [] uncovered []+ Nothing -> return emptyPmResult++-- | Generate all inhabitation candidates for a given type. The result is+-- either (Left ty), if the type cannot be reduced to a closed algebraic type+-- (or if it's one trivially inhabited, like Int), or (Right candidates), if it+-- can. In this case, the candidates are the singnature of the tycon, each one+-- accompanied by the term- and type- constraints it gives rise to.+-- See also Note [Checking EmptyCase Expressions]+inhabitationCandidates :: FamInstEnvs -> Type+ -> PmM (Either Type [(ValAbs, ComplexEq, Bag EvVar)])+inhabitationCandidates fam_insts ty+ = case pmTopNormaliseType_maybe fam_insts ty of+ Just (src_ty, dcs, core_ty) -> alts_to_check src_ty core_ty dcs+ Nothing -> alts_to_check ty ty []+ where+ -- All these types are trivially inhabited+ trivially_inhabited = [ charTyCon, doubleTyCon, floatTyCon+ , intTyCon, wordTyCon, word8TyCon ]++ -- Note: At the moment we leave all the typing and constraint fields of+ -- PmCon empty, since we know that they are not gonna be used. Is the+ -- right-thing-to-do to actually create them, even if they are never used?+ build_tm :: ValAbs -> [DataCon] -> ValAbs+ build_tm = foldr (\dc e -> PmCon (RealDataCon dc) [] [] [] [e])++ -- Inhabitation candidates, using the result of pmTopNormaliseType_maybe+ alts_to_check :: Type -> Type -> [DataCon]+ -> PmM (Either Type [(ValAbs, ComplexEq, Bag EvVar)])+ alts_to_check src_ty core_ty dcs = case splitTyConApp_maybe core_ty of+ Just (tc, _)+ | tc `elem` trivially_inhabited -> case dcs of+ [] -> return (Left src_ty)+ (_:_) -> do var <- liftD $ mkPmId (toTcType core_ty)+ let va = build_tm (PmVar var) dcs+ return $ Right [(va, mkIdEq var, emptyBag)]+ | isClosedAlgType core_ty -> liftD $ do+ var <- mkPmId (toTcType core_ty) -- it would be wrong to unify x+ alts <- mapM (mkOneConFull var . RealDataCon) (tyConDataCons tc)+ return $ Right [(build_tm va dcs, eq, cs) | (va, eq, cs) <- alts]+ -- For other types conservatively assume that they are inhabited.+ _other -> return (Left src_ty)++{- Note [Checking EmptyCase Expressions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Empty case expressions are strict on the scrutinee. That is, `case x of {}`+will force argument `x`. Hence, `checkMatches` is not sufficient for checking+empty cases, because it assumes that the match is not strict (which is true+for all other cases, apart from EmptyCase). This gave rise to #10746. Instead,+we do the following:++1. We normalise the outermost type family redex, data family redex or newtype,+ using pmTopNormaliseType_maybe (in types/FamInstEnv.hs). This computes 3+ things:+ (a) A normalised type src_ty, which is equal to the type of the scrutinee in+ source Haskell (does not normalise newtypes or data families)+ (b) The actual normalised type core_ty, which coincides with the result+ topNormaliseType_maybe. This type is not necessarily equal to the input+ type in source Haskell. And this is precicely the reason we compute (a)+ and (c): the reasoning happens with the underlying types, but both the+ patterns and types we print should respect newtypes and also show the+ family type constructors and not the representation constructors.++ (c) A list of all newtype data constructors dcs, each one corresponding to a+ newtype rewrite performed in (b).++ For an example see also Note [Type normalisation for EmptyCase]+ in types/FamInstEnv.hs.++2. Function checkEmptyCase' performs the check:+ - If core_ty is not an algebraic type, then we cannot check for+ inhabitation, so we emit (_ :: src_ty) as missing, conservatively assuming+ that the type is inhabited.+ - If core_ty is an algebraic type, then we unfold the scrutinee to all+ possible constructor patterns, using inhabitationCandidates, and then+ check each one for constraint satisfiability, same as we for normal+ pattern match checking.++%************************************************************************+%* *+ Transform source syntax to *our* syntax+%* *+%************************************************************************+-}++-- -----------------------------------------------------------------------+-- * Utilities++nullaryConPattern :: ConLike -> Pattern+-- Nullary data constructor and nullary type constructor+nullaryConPattern con =+ PmCon { pm_con_con = con, pm_con_arg_tys = []+ , pm_con_tvs = [], pm_con_dicts = [], pm_con_args = [] }+{-# INLINE nullaryConPattern #-}++truePattern :: Pattern+truePattern = nullaryConPattern (RealDataCon trueDataCon)+{-# INLINE truePattern #-}++-- | A fake guard pattern (True <- _) used to represent cases we cannot handle+fake_pat :: Pattern+fake_pat = PmGrd { pm_grd_pv = [truePattern]+ , pm_grd_expr = PmExprOther EWildPat }+{-# INLINE fake_pat #-}++-- | Check whether a guard pattern is generated by the checker (unhandled)+isFakeGuard :: [Pattern] -> PmExpr -> Bool+isFakeGuard [PmCon { pm_con_con = RealDataCon c }] (PmExprOther EWildPat)+ | c == trueDataCon = True+ | otherwise = False+isFakeGuard _pats _e = False++-- | Generate a `canFail` pattern vector of a specific type+mkCanFailPmPat :: Type -> DsM PatVec+mkCanFailPmPat ty = do+ var <- mkPmVar ty+ return [var, fake_pat]++vanillaConPattern :: ConLike -> [Type] -> PatVec -> Pattern+-- ADT constructor pattern => no existentials, no local constraints+vanillaConPattern con arg_tys args =+ PmCon { pm_con_con = con, pm_con_arg_tys = arg_tys+ , pm_con_tvs = [], pm_con_dicts = [], pm_con_args = args }+{-# INLINE vanillaConPattern #-}++-- | Create an empty list pattern of a given type+nilPattern :: Type -> Pattern+nilPattern ty =+ PmCon { pm_con_con = RealDataCon nilDataCon, pm_con_arg_tys = [ty]+ , pm_con_tvs = [], pm_con_dicts = []+ , pm_con_args = [] }+{-# INLINE nilPattern #-}++mkListPatVec :: Type -> PatVec -> PatVec -> PatVec+mkListPatVec ty xs ys = [PmCon { pm_con_con = RealDataCon consDataCon+ , pm_con_arg_tys = [ty]+ , pm_con_tvs = [], pm_con_dicts = []+ , pm_con_args = xs++ys }]+{-# INLINE mkListPatVec #-}++-- | Create a (non-overloaded) literal pattern+mkLitPattern :: HsLit -> Pattern+mkLitPattern lit = PmLit { pm_lit_lit = PmSLit lit }+{-# INLINE mkLitPattern #-}++-- -----------------------------------------------------------------------+-- * Transform (Pat Id) into of (PmPat Id)++translatePat :: FamInstEnvs -> Pat Id -> DsM PatVec+translatePat fam_insts pat = case pat of+ WildPat ty -> mkPmVars [ty]+ VarPat id -> return [PmVar (unLoc id)]+ ParPat p -> translatePat fam_insts (unLoc p)+ LazyPat _ -> mkPmVars [hsPatType pat] -- like a variable++ -- ignore strictness annotations for now+ BangPat p -> translatePat fam_insts (unLoc p)++ AsPat lid p -> do+ -- Note [Translating As Patterns]+ ps <- translatePat fam_insts (unLoc p)+ let [e] = map vaToPmExpr (coercePatVec ps)+ g = PmGrd [PmVar (unLoc lid)] e+ return (ps ++ [g])++ SigPatOut p _ty -> translatePat fam_insts (unLoc p)++ -- See Note [Translate CoPats]+ CoPat wrapper p ty+ | isIdHsWrapper wrapper -> translatePat fam_insts p+ | WpCast co <- wrapper, isReflexiveCo co -> translatePat fam_insts p+ | otherwise -> do+ ps <- translatePat fam_insts p+ (xp,xe) <- mkPmId2Forms ty+ let g = mkGuard ps (HsWrap wrapper (unLoc xe))+ return [xp,g]++ -- (n + k) ===> x (True <- x >= k) (n <- x-k)+ NPlusKPat (L _ _n) _k1 _k2 _ge _minus ty -> mkCanFailPmPat ty++ -- (fun -> pat) ===> x (pat <- fun x)+ ViewPat lexpr lpat arg_ty -> do+ ps <- translatePat fam_insts (unLoc lpat)+ -- See Note [Guards and Approximation]+ case all cantFailPattern ps of+ True -> do+ (xp,xe) <- mkPmId2Forms arg_ty+ let g = mkGuard ps (HsApp lexpr xe)+ return [xp,g]+ False -> mkCanFailPmPat arg_ty++ -- list+ ListPat ps ty Nothing -> do+ foldr (mkListPatVec ty) [nilPattern ty]+ <$> translatePatVec fam_insts (map unLoc ps)++ -- overloaded list+ ListPat lpats elem_ty (Just (pat_ty, _to_list))+ | Just e_ty <- splitListTyConApp_maybe pat_ty+ , (_, norm_elem_ty) <- normaliseType fam_insts Nominal elem_ty+ -- elem_ty is frequently something like+ -- `Item [Int]`, but we prefer `Int`+ , norm_elem_ty `eqType` e_ty ->+ -- We have to ensure that the element types are exactly the same.+ -- Otherwise, one may give an instance IsList [Int] (more specific than+ -- the default IsList [a]) with a different implementation for `toList'+ translatePat fam_insts (ListPat lpats e_ty Nothing)+ -- See Note [Guards and Approximation]+ | otherwise -> mkCanFailPmPat pat_ty++ ConPatOut { pat_con = L _ con+ , pat_arg_tys = arg_tys+ , pat_tvs = ex_tvs+ , pat_dicts = dicts+ , pat_args = ps } -> do+ groups <- allCompleteMatches con arg_tys+ case groups of+ [] -> mkCanFailPmPat (conLikeResTy con arg_tys)+ _ -> do+ args <- translateConPatVec fam_insts arg_tys ex_tvs con ps+ return [PmCon { pm_con_con = con+ , pm_con_arg_tys = arg_tys+ , pm_con_tvs = ex_tvs+ , pm_con_dicts = dicts+ , pm_con_args = args }]++ NPat (L _ ol) mb_neg _eq ty -> translateNPat fam_insts ol mb_neg ty++ LitPat lit+ -- If it is a string then convert it to a list of characters+ | HsString src s <- lit ->+ foldr (mkListPatVec charTy) [nilPattern charTy] <$>+ translatePatVec fam_insts (map (LitPat . HsChar src) (unpackFS s))+ | otherwise -> return [mkLitPattern lit]++ PArrPat ps ty -> do+ tidy_ps <- translatePatVec fam_insts (map unLoc ps)+ let fake_con = RealDataCon (parrFakeCon (length ps))+ return [vanillaConPattern fake_con [ty] (concat tidy_ps)]++ TuplePat ps boxity tys -> do+ tidy_ps <- translatePatVec fam_insts (map unLoc ps)+ let tuple_con = RealDataCon (tupleDataCon boxity (length ps))+ return [vanillaConPattern tuple_con tys (concat tidy_ps)]++ SumPat p alt arity ty -> do+ tidy_p <- translatePat fam_insts (unLoc p)+ let sum_con = RealDataCon (sumDataCon alt arity)+ return [vanillaConPattern sum_con ty tidy_p]++ -- --------------------------------------------------------------------------+ -- Not supposed to happen+ ConPatIn {} -> panic "Check.translatePat: ConPatIn"+ SplicePat {} -> panic "Check.translatePat: SplicePat"+ SigPatIn {} -> panic "Check.translatePat: SigPatIn"++-- | Translate an overloaded literal (see `tidyNPat' in deSugar/MatchLit.hs)+translateNPat :: FamInstEnvs+ -> HsOverLit Id -> Maybe (SyntaxExpr Id) -> Type -> DsM PatVec+translateNPat fam_insts (OverLit val False _ ty) mb_neg outer_ty+ | not type_change, isStringTy ty, HsIsString src s <- val, Nothing <- mb_neg+ = translatePat fam_insts (LitPat (HsString src s))+ | not type_change, isIntTy ty, HsIntegral src i <- val+ = translatePat fam_insts (mk_num_lit HsInt src i)+ | not type_change, isWordTy ty, HsIntegral src i <- val+ = translatePat fam_insts (mk_num_lit HsWordPrim src i)+ where+ type_change = not (outer_ty `eqType` ty)+ mk_num_lit c src i = LitPat $ case mb_neg of+ Nothing -> c src i+ Just _ -> c src (-i)+translateNPat _ ol mb_neg _+ = return [PmLit { pm_lit_lit = PmOLit (isJust mb_neg) ol }]++-- | Translate a list of patterns (Note: each pattern is translated+-- to a pattern vector but we do not concatenate the results).+translatePatVec :: FamInstEnvs -> [Pat Id] -> DsM [PatVec]+translatePatVec fam_insts pats = mapM (translatePat fam_insts) pats++-- | Translate a constructor pattern+translateConPatVec :: FamInstEnvs -> [Type] -> [TyVar]+ -> ConLike -> HsConPatDetails Id -> DsM PatVec+translateConPatVec fam_insts _univ_tys _ex_tvs _ (PrefixCon ps)+ = concat <$> translatePatVec fam_insts (map unLoc ps)+translateConPatVec fam_insts _univ_tys _ex_tvs _ (InfixCon p1 p2)+ = concat <$> translatePatVec fam_insts (map unLoc [p1,p2])+translateConPatVec fam_insts univ_tys ex_tvs c (RecCon (HsRecFields fs _))+ -- Nothing matched. Make up some fresh term variables+ | null fs = mkPmVars arg_tys+ -- The data constructor was not defined using record syntax. For the+ -- pattern to be in record syntax it should be empty (e.g. Just {}).+ -- So just like the previous case.+ | null orig_lbls = ASSERT(null matched_lbls) mkPmVars arg_tys+ -- Some of the fields appear, in the original order (there may be holes).+ -- Generate a simple constructor pattern and make up fresh variables for+ -- the rest of the fields+ | matched_lbls `subsetOf` orig_lbls+ = ASSERT(length orig_lbls == length arg_tys)+ let translateOne (lbl, ty) = case lookup lbl matched_pats of+ Just p -> translatePat fam_insts p+ Nothing -> mkPmVars [ty]+ in concatMapM translateOne (zip orig_lbls arg_tys)+ -- The fields that appear are not in the correct order. Make up fresh+ -- variables for all fields and add guards after matching, to force the+ -- evaluation in the correct order.+ | otherwise = do+ arg_var_pats <- mkPmVars arg_tys+ translated_pats <- forM matched_pats $ \(x,pat) -> do+ pvec <- translatePat fam_insts pat+ return (x, pvec)++ let zipped = zip orig_lbls [ x | PmVar x <- arg_var_pats ]+ guards = map (\(name,pvec) -> case lookup name zipped of+ Just x -> PmGrd pvec (PmExprVar (idName x))+ Nothing -> panic "translateConPatVec: lookup")+ translated_pats++ return (arg_var_pats ++ guards)+ where+ -- The actual argument types (instantiated)+ arg_tys = conLikeInstOrigArgTys c (univ_tys ++ mkTyVarTys ex_tvs)++ -- Some label information+ orig_lbls = map flSelector $ conLikeFieldLabels c+ matched_pats = [ (getName (unLoc (hsRecFieldId x)), unLoc (hsRecFieldArg x))+ | L _ x <- fs]+ matched_lbls = [ name | (name, _pat) <- matched_pats ]++ subsetOf :: Eq a => [a] -> [a] -> Bool+ subsetOf [] _ = True+ subsetOf (_:_) [] = False+ subsetOf (x:xs) (y:ys)+ | x == y = subsetOf xs ys+ | otherwise = subsetOf (x:xs) ys++-- Translate a single match+translateMatch :: FamInstEnvs -> LMatch Id (LHsExpr Id) -> DsM (PatVec,[PatVec])+translateMatch fam_insts (L _ (Match _ lpats _ grhss)) = do+ pats' <- concat <$> translatePatVec fam_insts pats+ guards' <- mapM (translateGuards fam_insts) guards+ return (pats', guards')+ where+ extractGuards :: LGRHS Id (LHsExpr Id) -> [GuardStmt Id]+ extractGuards (L _ (GRHS gs _)) = map unLoc gs++ pats = map unLoc lpats+ guards = map extractGuards (grhssGRHSs grhss)++-- -----------------------------------------------------------------------+-- * Transform source guards (GuardStmt Id) to PmPats (Pattern)++-- | Translate a list of guard statements to a pattern vector+translateGuards :: FamInstEnvs -> [GuardStmt Id] -> DsM PatVec+translateGuards fam_insts guards = do+ all_guards <- concat <$> mapM (translateGuard fam_insts) guards+ return (replace_unhandled all_guards)+ -- It should have been (return all_guards) but it is too expressive.+ -- Since the term oracle does not handle all constraints we generate,+ -- we (hackily) replace all constraints the oracle cannot handle with a+ -- single one (we need to know if there is a possibility of falure).+ -- See Note [Guards and Approximation] for all guard-related approximations+ -- we implement.+ where+ replace_unhandled :: PatVec -> PatVec+ replace_unhandled gv+ | any_unhandled gv = fake_pat : [ p | p <- gv, shouldKeep p ]+ | otherwise = gv++ any_unhandled :: PatVec -> Bool+ any_unhandled gv = any (not . shouldKeep) gv++ shouldKeep :: Pattern -> Bool+ shouldKeep p+ | PmVar {} <- p = True+ | PmCon {} <- p = singleConstructor (pm_con_con p)+ && all shouldKeep (pm_con_args p)+ shouldKeep (PmGrd pv e)+ | all shouldKeep pv = True+ | isNotPmExprOther e = True -- expensive but we want it+ shouldKeep _other_pat = False -- let the rest..++-- | Check whether a pattern can fail to match+cantFailPattern :: Pattern -> Bool+cantFailPattern p+ | PmVar {} <- p = True+ | PmCon {} <- p = singleConstructor (pm_con_con p)+ && all cantFailPattern (pm_con_args p)+cantFailPattern (PmGrd pv _e)+ = all cantFailPattern pv+cantFailPattern _ = False++-- | Translate a guard statement to Pattern+translateGuard :: FamInstEnvs -> GuardStmt Id -> DsM PatVec+translateGuard fam_insts guard = case guard of+ BodyStmt e _ _ _ -> translateBoolGuard e+ LetStmt binds -> translateLet (unLoc binds)+ BindStmt p e _ _ _ -> translateBind fam_insts p e+ LastStmt {} -> panic "translateGuard LastStmt"+ ParStmt {} -> panic "translateGuard ParStmt"+ TransStmt {} -> panic "translateGuard TransStmt"+ RecStmt {} -> panic "translateGuard RecStmt"+ ApplicativeStmt {} -> panic "translateGuard ApplicativeLastStmt"++-- | Translate let-bindings+translateLet :: HsLocalBinds Id -> DsM PatVec+translateLet _binds = return []++-- | Translate a pattern guard+translateBind :: FamInstEnvs -> LPat Id -> LHsExpr Id -> DsM PatVec+translateBind fam_insts (L _ p) e = do+ ps <- translatePat fam_insts p+ return [mkGuard ps (unLoc e)]++-- | Translate a boolean guard+translateBoolGuard :: LHsExpr Id -> DsM PatVec+translateBoolGuard e+ | isJust (isTrueLHsExpr e) = return []+ -- The formal thing to do would be to generate (True <- True)+ -- but it is trivial to solve so instead we give back an empty+ -- PatVec for efficiency+ | otherwise = return [mkGuard [truePattern] (unLoc e)]++{- Note [Guards and Approximation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Even if the algorithm is really expressive, the term oracle we use is not.+Hence, several features are not translated *properly* but we approximate.+The list includes:++1. View Patterns+----------------+A view pattern @(f -> p)@ should be translated to @x (p <- f x)@. The term+oracle does not handle function applications so we know that the generated+constraints will not be handled at the end. Hence, we distinguish between two+cases:+ a) Pattern @p@ cannot fail. Then this is just a binding and we do the *right+ thing*.+ b) Pattern @p@ can fail. This means that when checking the guard, we will+ generate several cases, with no useful information. E.g.:++ h (f -> [a,b]) = ...+ h x ([a,b] <- f x) = ...++ uncovered set = { [x |> { False ~ (f x ~ []) }]+ , [x |> { False ~ (f x ~ (t1:[])) }]+ , [x |> { False ~ (f x ~ (t1:t2:t3:t4)) }] }++ So we have two problems:+ 1) Since we do not print the constraints in the general case (they may+ be too many), the warning will look like this:++ Pattern match(es) are non-exhaustive+ In an equation for `h':+ Patterns not matched:+ _+ _+ _+ Which is not short and not more useful than a single underscore.+ 2) The size of the uncovered set increases a lot, without gaining more+ expressivity in our warnings.++ Hence, in this case, we replace the guard @([a,b] <- f x)@ with a *dummy*+ @fake_pat@: @True <- _@. That is, we record that there is a possibility+ of failure but we minimize it to a True/False. This generates a single+ warning and much smaller uncovered sets.++2. Overloaded Lists+-------------------+An overloaded list @[...]@ should be translated to @x ([...] <- toList x)@. The+problem is exactly like above, as its solution. For future reference, the code+below is the *right thing to do*:++ ListPat lpats elem_ty (Just (pat_ty, to_list))+ otherwise -> do+ (xp, xe) <- mkPmId2Forms pat_ty+ ps <- translatePatVec (map unLoc lpats)+ let pats = foldr (mkListPatVec elem_ty) [nilPattern elem_ty] ps+ g = mkGuard pats (HsApp (noLoc to_list) xe)+ return [xp,g]++3. Overloaded Literals+----------------------+The case with literals is a bit different. a literal @l@ should be translated+to @x (True <- x == from l)@. Since we want to have better warnings for+overloaded literals as it is a very common feature, we treat them differently.+They are mainly covered in Note [Undecidable Equality on Overloaded Literals]+in PmExpr.++4. N+K Patterns & Pattern Synonyms+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+An n+k pattern (n+k) should be translated to @x (True <- x >= k) (n <- x-k)@.+Since the only pattern of the three that causes failure is guard @(n <- x-k)@,+and has two possible outcomes. Hence, there is no benefit in using a dummy and+we implement the proper thing. Pattern synonyms are simply not implemented yet.+Hence, to be conservative, we generate a dummy pattern, assuming that the+pattern can fail.++5. Actual Guards+----------------+During translation, boolean guards and pattern guards are translated properly.+Let bindings though are omitted by function @translateLet@. Since they are lazy+bindings, we do not actually want to generate a (strict) equality (like we do+in the pattern bind case). Hence, we safely drop them.++Additionally, top-level guard translation (performed by @translateGuards@)+replaces guards that cannot be reasoned about (like the ones we described in+1-4) with a single @fake_pat@ to record the possibility of failure to match.++Note [Translate CoPats]+~~~~~~~~~~~~~~~~~~~~~~~+The pattern match checker did not know how to handle coerced patterns `CoPat`+efficiently, which gave rise to #11276. The original approach translated+`CoPat`s:++ pat |> co ===> x (pat <- (e |> co))++Instead, we now check whether the coercion is a hole or if it is just refl, in+which case we can drop it. Unfortunately, data families generate useful+coercions so guards are still generated in these cases and checking data+families is not really efficient.++%************************************************************************+%* *+ Utilities for Pattern Match Checking+%* *+%************************************************************************+-}++-- ----------------------------------------------------------------------------+-- * Basic utilities++-- | Get the type out of a PmPat. For guard patterns (ps <- e) we use the type+-- of the first (or the single -WHEREVER IT IS- valid to use?) pattern+pmPatType :: PmPat p -> Type+pmPatType (PmCon { pm_con_con = con, pm_con_arg_tys = tys })+ = conLikeResTy con tys+pmPatType (PmVar { pm_var_id = x }) = idType x+pmPatType (PmLit { pm_lit_lit = l }) = pmLitType l+pmPatType (PmNLit { pm_lit_id = x }) = idType x+pmPatType (PmGrd { pm_grd_pv = pv })+ = ASSERT(patVecArity pv == 1) (pmPatType p)+ where Just p = find ((==1) . patternArity) pv++-- | Generate a value abstraction for a given constructor (generate+-- fresh variables of the appropriate type for arguments)+mkOneConFull :: Id -> ConLike -> DsM (ValAbs, ComplexEq, Bag EvVar)+-- * x :: T tys, where T is an algebraic data type+-- NB: in the case of a data family, T is the *representation* TyCon+-- e.g. data instance T (a,b) = T1 a b+-- leads to+-- data TPair a b = T1 a b -- The "representation" type+-- It is TPair, not T, that is given to mkOneConFull+--+-- * 'con' K is a constructor of data type T+--+-- After instantiating the universal tyvars of K we get+-- K tys :: forall bs. Q => s1 .. sn -> T tys+--+-- Results: ValAbs: K (y1::s1) .. (yn::sn)+-- ComplexEq: x ~ K y1..yn+-- [EvVar]: Q+mkOneConFull x con = do+ let -- res_ty == TyConApp (ConLikeTyCon cabs_con) cabs_arg_tys+ res_ty = idType x+ (univ_tvs, ex_tvs, eq_spec, thetas, _req_theta , arg_tys, _)+ = conLikeFullSig con+ tc_args = case splitTyConApp_maybe res_ty of+ Just (_, tys) -> tys+ Nothing -> pprPanic "mkOneConFull: Not TyConApp:" (ppr res_ty)+ subst1 = zipTvSubst univ_tvs tc_args++ (subst, ex_tvs') <- cloneTyVarBndrs subst1 ex_tvs <$> getUniqueSupplyM++ -- Fresh term variables (VAs) as arguments to the constructor+ arguments <- mapM mkPmVar (substTys subst arg_tys)+ -- All constraints bound by the constructor (alpha-renamed)+ let theta_cs = substTheta subst (eqSpecPreds eq_spec ++ thetas)+ evvars <- mapM (nameType "pm") theta_cs+ let con_abs = PmCon { pm_con_con = con+ , pm_con_arg_tys = tc_args+ , pm_con_tvs = ex_tvs'+ , pm_con_dicts = evvars+ , pm_con_args = arguments }+ return (con_abs, (PmExprVar (idName x), vaToPmExpr con_abs), listToBag evvars)++-- ----------------------------------------------------------------------------+-- * More smart constructors and fresh variable generation++-- | Create a guard pattern+mkGuard :: PatVec -> HsExpr Id -> Pattern+mkGuard pv e+ | all cantFailPattern pv = PmGrd pv expr+ | PmExprOther {} <- expr = fake_pat+ | otherwise = PmGrd pv expr+ where+ expr = hsExprToPmExpr e++-- | Create a term equality of the form: `(False ~ (x ~ lit))`+mkNegEq :: Id -> PmLit -> ComplexEq+mkNegEq x l = (falsePmExpr, PmExprVar (idName x) `PmExprEq` PmExprLit l)+{-# INLINE mkNegEq #-}++-- | Create a term equality of the form: `(x ~ lit)`+mkPosEq :: Id -> PmLit -> ComplexEq+mkPosEq x l = (PmExprVar (idName x), PmExprLit l)+{-# INLINE mkPosEq #-}++-- | Create a term equality of the form: `(x ~ x)`+-- (always discharged by the term oracle)+mkIdEq :: Id -> ComplexEq+mkIdEq x = (PmExprVar name, PmExprVar name)+ where name = idName x+{-# INLINE mkIdEq #-}++-- | Generate a variable pattern of a given type+mkPmVar :: Type -> DsM (PmPat p)+mkPmVar ty = PmVar <$> mkPmId ty+{-# INLINE mkPmVar #-}++-- | Generate many variable patterns, given a list of types+mkPmVars :: [Type] -> DsM PatVec+mkPmVars tys = mapM mkPmVar tys+{-# INLINE mkPmVars #-}++-- | Generate a fresh `Id` of a given type+mkPmId :: Type -> DsM Id+mkPmId ty = getUniqueM >>= \unique ->+ let occname = mkVarOccFS (fsLit (show unique))+ name = mkInternalName unique occname noSrcSpan+ in return (mkLocalId name ty)++-- | Generate a fresh term variable of a given and return it in two forms:+-- * A variable pattern+-- * A variable expression+mkPmId2Forms :: Type -> DsM (Pattern, LHsExpr Id)+mkPmId2Forms ty = do+ x <- mkPmId ty+ return (PmVar x, noLoc (HsVar (noLoc x)))++-- ----------------------------------------------------------------------------+-- * Converting between Value Abstractions, Patterns and PmExpr++-- | Convert a value abstraction an expression+vaToPmExpr :: ValAbs -> PmExpr+vaToPmExpr (PmCon { pm_con_con = c, pm_con_args = ps })+ = PmExprCon c (map vaToPmExpr ps)+vaToPmExpr (PmVar { pm_var_id = x }) = PmExprVar (idName x)+vaToPmExpr (PmLit { pm_lit_lit = l }) = PmExprLit l+vaToPmExpr (PmNLit { pm_lit_id = x }) = PmExprVar (idName x)++-- | Convert a pattern vector to a list of value abstractions by dropping the+-- guards (See Note [Translating As Patterns])+coercePatVec :: PatVec -> [ValAbs]+coercePatVec pv = concatMap coercePmPat pv++-- | Convert a pattern to a list of value abstractions (will be either an empty+-- list if the pattern is a guard pattern, or a singleton list in all other+-- cases) by dropping the guards (See Note [Translating As Patterns])+coercePmPat :: Pattern -> [ValAbs]+coercePmPat (PmVar { pm_var_id = x }) = [PmVar { pm_var_id = x }]+coercePmPat (PmLit { pm_lit_lit = l }) = [PmLit { pm_lit_lit = l }]+coercePmPat (PmCon { pm_con_con = con, pm_con_arg_tys = arg_tys+ , pm_con_tvs = tvs, pm_con_dicts = dicts+ , pm_con_args = args })+ = [PmCon { pm_con_con = con, pm_con_arg_tys = arg_tys+ , pm_con_tvs = tvs, pm_con_dicts = dicts+ , pm_con_args = coercePatVec args }]+coercePmPat (PmGrd {}) = [] -- drop the guards++-- | Check whether a data constructor is the only way to construct+-- a data type.+singleConstructor :: ConLike -> Bool+singleConstructor (RealDataCon dc) =+ case tyConDataCons (dataConTyCon dc) of+ [_] -> True+ _ -> False+singleConstructor _ = False++-- | For a given conlike, finds all the sets of patterns which could+-- be relevant to that conlike by consulting the result type.+--+-- These come from two places.+-- 1. From data constructors defined with the result type constructor.+-- 2. From `COMPLETE` pragmas which have the same type as the result+-- type constructor.+allCompleteMatches :: ConLike -> [Type] -> DsM [(Provenance, [ConLike])]+allCompleteMatches cl tys = do+ let fam = case cl of+ RealDataCon dc ->+ [(FromBuiltin, map RealDataCon (tyConDataCons (dataConTyCon dc)))]+ PatSynCon _ -> []++ pragmas <- case splitTyConApp_maybe (conLikeResTy cl tys) of+ Just (tc, _) -> dsGetCompleteMatches tc+ Nothing -> return []+ let fams cm = fmap (FromComplete,) $+ mapM dsLookupConLike (completeMatchConLikes cm)+ from_pragma <- mapM fams pragmas++ let final_groups = fam ++ from_pragma+ tracePmD "allCompleteMatches" (ppr final_groups)+ return final_groups++-- -----------------------------------------------------------------------+-- * Types and constraints++newEvVar :: Name -> Type -> EvVar+newEvVar name ty = mkLocalId name (toTcType ty)++nameType :: String -> Type -> DsM EvVar+nameType name ty = do+ unique <- getUniqueM+ let occname = mkVarOccFS (fsLit (name++"_"++show unique))+ idname = mkInternalName unique occname noSrcSpan+ return (newEvVar idname ty)++{-+%************************************************************************+%* *+ The type oracle+%* *+%************************************************************************+-}++-- | Check whether a set of type constraints is satisfiable.+tyOracle :: Bag EvVar -> PmM Bool+tyOracle evs+ = liftD $+ do { ((_warns, errs), res) <- initTcDsForSolver $ tcCheckSatisfiability evs+ ; case res of+ Just sat -> return sat+ Nothing -> pprPanic "tyOracle" (vcat $ pprErrMsgBagWithLoc errs) }++{-+%************************************************************************+%* *+ Sanity Checks+%* *+%************************************************************************+-}++-- | The arity of a pattern/pattern vector is the+-- number of top-level patterns that are not guards+type PmArity = Int++-- | Compute the arity of a pattern vector+patVecArity :: PatVec -> PmArity+patVecArity = sum . map patternArity++-- | Compute the arity of a pattern+patternArity :: Pattern -> PmArity+patternArity (PmGrd {}) = 0+patternArity _other_pat = 1++{-+%************************************************************************+%* *+ Heart of the algorithm: Function pmcheck+%* *+%************************************************************************++Main functions are:++* mkInitialUncovered :: [Id] -> PmM Uncovered++ Generates the initial uncovered set. Term and type constraints in scope+ are checked, if they are inconsistent, the set is empty, otherwise, the+ set contains only a vector of variables with the constraints in scope.++* pmcheck :: PatVec -> [PatVec] -> ValVec -> PmM PartialResult++ Checks redundancy, coverage and inaccessibility, using auxilary functions+ `pmcheckGuards` and `pmcheckHd`. Mainly handles the guard case which is+ common in all three checks (see paper) and calls `pmcheckGuards` when the+ whole clause is checked, or `pmcheckHd` when the pattern vector does not+ start with a guard.++* pmcheckGuards :: [PatVec] -> ValVec -> PmM PartialResult++ Processes the guards.++* pmcheckHd :: Pattern -> PatVec -> [PatVec]+ -> ValAbs -> ValVec -> PmM PartialResult++ Worker: This function implements functions `covered`, `uncovered` and+ `divergent` from the paper at once. Slightly different from the paper because+ it does not even produce the covered and uncovered sets. Since we only care+ about whether a clause covers SOMETHING or if it may forces ANY argument, we+ only store a boolean in both cases, for efficiency.+-}++-- | Lift a pattern matching action from a single value vector abstration to a+-- value set abstraction, but calling it on every vector and the combining the+-- results.+runMany :: (ValVec -> PmM PartialResult) -> (Uncovered -> PmM PartialResult)+runMany _ [] = return mempty+runMany pm (m:ms) = mappend <$> pm m <*> runMany pm ms++-- | Generate the initial uncovered set. It initializes the+-- delta with all term and type constraints in scope.+mkInitialUncovered :: [Id] -> PmM Uncovered+mkInitialUncovered vars = do+ ty_cs <- liftD getDictsDs+ tm_cs <- map toComplex . bagToList <$> liftD getTmCsDs+ sat_ty <- tyOracle ty_cs+ let initTyCs = if sat_ty then ty_cs else emptyBag+ initTmState = fromMaybe initialTmState (tmOracle initialTmState tm_cs)+ patterns = map PmVar vars+ -- If any of the term/type constraints are non+ -- satisfiable then return with the initialTmState. See #12957+ return [ValVec patterns (MkDelta initTyCs initTmState)]++-- | Increase the counter for elapsed algorithm iterations, check that the+-- limit is not exceeded and call `pmcheck`+pmcheckI :: PatVec -> [PatVec] -> ValVec -> PmM PartialResult+pmcheckI ps guards vva = do+ n <- liftD incrCheckPmIterDs+ tracePm "pmCheck" (ppr n <> colon <+> pprPatVec ps+ $$ hang (text "guards:") 2 (vcat (map pprPatVec guards))+ $$ pprValVecDebug vva)+ res <- pmcheck ps guards vva+ tracePm "pmCheckResult:" (ppr res)+ return res+{-# INLINE pmcheckI #-}++-- | Increase the counter for elapsed algorithm iterations, check that the+-- limit is not exceeded and call `pmcheckGuards`+pmcheckGuardsI :: [PatVec] -> ValVec -> PmM PartialResult+pmcheckGuardsI gvs vva = liftD incrCheckPmIterDs >> pmcheckGuards gvs vva+{-# INLINE pmcheckGuardsI #-}++-- | Increase the counter for elapsed algorithm iterations, check that the+-- limit is not exceeded and call `pmcheckHd`+pmcheckHdI :: Pattern -> PatVec -> [PatVec] -> ValAbs -> ValVec+ -> PmM PartialResult+pmcheckHdI p ps guards va vva = do+ n <- liftD incrCheckPmIterDs+ tracePm "pmCheckHdI" (ppr n <> colon <+> pprPmPatDebug p+ $$ pprPatVec ps+ $$ hang (text "guards:") 2 (vcat (map pprPatVec guards))+ $$ pprPmPatDebug va+ $$ pprValVecDebug vva)++ res <- pmcheckHd p ps guards va vva+ tracePm "pmCheckHdI: res" (ppr res)+ return res+{-# INLINE pmcheckHdI #-}++-- | Matching function: Check simultaneously a clause (takes separately the+-- patterns and the list of guards) for exhaustiveness, redundancy and+-- inaccessibility.+pmcheck :: PatVec -> [PatVec] -> ValVec -> PmM PartialResult+pmcheck [] guards vva@(ValVec [] _)+ | null guards = return $ mempty { presultCovered = Covered }+ | otherwise = pmcheckGuardsI guards vva++-- Guard+pmcheck (p@(PmGrd pv e) : ps) guards vva@(ValVec vas delta)+ -- short-circuit if the guard pattern is useless.+ -- we just have two possible outcomes: fail here or match and recurse+ -- none of the two contains any useful information about the failure+ -- though. So just have these two cases but do not do all the boilerplate+ | isFakeGuard pv e = forces . mkCons vva <$> pmcheckI ps guards vva+ | otherwise = do+ y <- liftD $ mkPmId (pmPatType p)+ let tm_state = extendSubst y e (delta_tm_cs delta)+ delta' = delta { delta_tm_cs = tm_state }+ utail <$> pmcheckI (pv ++ ps) guards (ValVec (PmVar y : vas) delta')++pmcheck [] _ (ValVec (_:_) _) = panic "pmcheck: nil-cons"+pmcheck (_:_) _ (ValVec [] _) = panic "pmcheck: cons-nil"++pmcheck (p:ps) guards (ValVec (va:vva) delta)+ = pmcheckHdI p ps guards va (ValVec vva delta)++-- | Check the list of guards+pmcheckGuards :: [PatVec] -> ValVec -> PmM PartialResult+pmcheckGuards [] vva = return (usimple [vva])+pmcheckGuards (gv:gvs) vva = do+ (PartialResult prov1 cs vsa ds) <- pmcheckI gv [] vva+ (PartialResult prov2 css vsas dss) <- runMany (pmcheckGuardsI gvs) vsa+ return $ PartialResult (prov1 `mappend` prov2)+ (cs `mappend` css)+ vsas+ (ds `mappend` dss)++-- | Worker function: Implements all cases described in the paper for all three+-- functions (`covered`, `uncovered` and `divergent`) apart from the `Guard`+-- cases which are handled by `pmcheck`+pmcheckHd :: Pattern -> PatVec -> [PatVec] -> ValAbs -> ValVec+ -> PmM PartialResult++-- Var+pmcheckHd (PmVar x) ps guards va (ValVec vva delta)+ | Just tm_state <- solveOneEq (delta_tm_cs delta)+ (PmExprVar (idName x), vaToPmExpr va)+ = ucon va <$> pmcheckI ps guards (ValVec vva (delta {delta_tm_cs = tm_state}))+ | otherwise = return mempty++-- ConCon+pmcheckHd ( p@(PmCon {pm_con_con = c1, pm_con_args = args1})) ps guards+ (va@(PmCon {pm_con_con = c2, pm_con_args = args2})) (ValVec vva delta)+ | c1 /= c2 =+ return (usimple [ValVec (va:vva) delta])+ | otherwise = kcon c1 (pm_con_arg_tys p) (pm_con_tvs p) (pm_con_dicts p)+ <$> pmcheckI (args1 ++ ps) guards (ValVec (args2 ++ vva) delta)++-- LitLit+pmcheckHd (PmLit l1) ps guards (va@(PmLit l2)) vva =+ case eqPmLit l1 l2 of+ True -> ucon va <$> pmcheckI ps guards vva+ False -> return $ ucon va (usimple [vva])++-- ConVar+pmcheckHd (p@(PmCon { pm_con_con = con, pm_con_arg_tys = tys }))+ ps guards+ (PmVar x) (ValVec vva delta) = do+ (prov, complete_match) <- select =<< liftD (allCompleteMatches con tys)++ cons_cs <- mapM (liftD . mkOneConFull x) complete_match++ inst_vsa <- flip concatMapM cons_cs $ \(va, tm_ct, ty_cs) -> do+ let ty_state = ty_cs `unionBags` delta_ty_cs delta -- not actually a state+ sat_ty <- if isEmptyBag ty_cs then return True+ else tyOracle ty_state+ return $ case (sat_ty, solveOneEq (delta_tm_cs delta) tm_ct) of+ (True, Just tm_state) -> [ValVec (va:vva) (MkDelta ty_state tm_state)]+ _ty_or_tm_failed -> []++ set_provenance prov .+ force_if (canDiverge (idName x) (delta_tm_cs delta)) <$>+ runMany (pmcheckI (p:ps) guards) inst_vsa++-- LitVar+pmcheckHd (p@(PmLit l)) ps guards (PmVar x) (ValVec vva delta)+ = force_if (canDiverge (idName x) (delta_tm_cs delta)) <$>+ mkUnion non_matched <$>+ case solveOneEq (delta_tm_cs delta) (mkPosEq x l) of+ Just tm_state -> pmcheckHdI p ps guards (PmLit l) $+ ValVec vva (delta {delta_tm_cs = tm_state})+ Nothing -> return mempty+ where+ us | Just tm_state <- solveOneEq (delta_tm_cs delta) (mkNegEq x l)+ = [ValVec (PmNLit x [l] : vva) (delta { delta_tm_cs = tm_state })]+ | otherwise = []++ non_matched = usimple us++-- LitNLit+pmcheckHd (p@(PmLit l)) ps guards+ (PmNLit { pm_lit_id = x, pm_lit_not = lits }) (ValVec vva delta)+ | all (not . eqPmLit l) lits+ , Just tm_state <- solveOneEq (delta_tm_cs delta) (mkPosEq x l)+ -- Both guards check the same so it would be sufficient to have only+ -- the second one. Nevertheless, it is much cheaper to check whether+ -- the literal is in the list so we check it first, to avoid calling+ -- the term oracle (`solveOneEq`) if possible+ = mkUnion non_matched <$>+ pmcheckHdI p ps guards (PmLit l)+ (ValVec vva (delta { delta_tm_cs = tm_state }))+ | otherwise = return non_matched+ where+ us | Just tm_state <- solveOneEq (delta_tm_cs delta) (mkNegEq x l)+ = [ValVec (PmNLit x (l:lits) : vva) (delta { delta_tm_cs = tm_state })]+ | otherwise = []++ non_matched = usimple us++-- ----------------------------------------------------------------------------+-- The following three can happen only in cases like #322 where constructors+-- and overloaded literals appear in the same match. The general strategy is+-- to replace the literal (positive/negative) by a variable and recurse. The+-- fact that the variable is equal to the literal is recorded in `delta` so+-- no information is lost++-- LitCon+pmcheckHd (PmLit l) ps guards (va@(PmCon {})) (ValVec vva delta)+ = do y <- liftD $ mkPmId (pmPatType va)+ let tm_state = extendSubst y (PmExprLit l) (delta_tm_cs delta)+ delta' = delta { delta_tm_cs = tm_state }+ pmcheckHdI (PmVar y) ps guards va (ValVec vva delta')++-- ConLit+pmcheckHd (p@(PmCon {})) ps guards (PmLit l) (ValVec vva delta)+ = do y <- liftD $ mkPmId (pmPatType p)+ let tm_state = extendSubst y (PmExprLit l) (delta_tm_cs delta)+ delta' = delta { delta_tm_cs = tm_state }+ pmcheckHdI p ps guards (PmVar y) (ValVec vva delta')++-- ConNLit+pmcheckHd (p@(PmCon {})) ps guards (PmNLit { pm_lit_id = x }) vva+ = pmcheckHdI p ps guards (PmVar x) vva++-- Impossible: handled by pmcheck+pmcheckHd (PmGrd {}) _ _ _ _ = panic "pmcheckHd: Guard"++-- ----------------------------------------------------------------------------+-- * Utilities for main checking++updateVsa :: (ValSetAbs -> ValSetAbs) -> (PartialResult -> PartialResult)+updateVsa f p@(PartialResult { presultUncovered = old })+ = p { presultUncovered = f old }+++-- | Initialise with default values for covering and divergent information.+usimple :: ValSetAbs -> PartialResult+usimple vsa = mempty { presultUncovered = vsa }++-- | Take the tail of all value vector abstractions in the uncovered set+utail :: PartialResult -> PartialResult+utail = updateVsa upd+ where upd vsa = [ ValVec vva delta | ValVec (_:vva) delta <- vsa ]++-- | Prepend a value abstraction to all value vector abstractions in the+-- uncovered set+ucon :: ValAbs -> PartialResult -> PartialResult+ucon va = updateVsa upd+ where+ upd vsa = [ ValVec (va:vva) delta | ValVec vva delta <- vsa ]++-- | Given a data constructor of arity `a` and an uncovered set containing+-- value vector abstractions of length `(a+n)`, pass the first `n` value+-- abstractions to the constructor (Hence, the resulting value vector+-- abstractions will have length `n+1`)+kcon :: ConLike -> [Type] -> [TyVar] -> [EvVar]+ -> PartialResult -> PartialResult+kcon con arg_tys ex_tvs dicts+ = let n = conLikeArity con+ upd vsa =+ [ ValVec (va:vva) delta+ | ValVec vva' delta <- vsa+ , let (args, vva) = splitAt n vva'+ , let va = PmCon { pm_con_con = con+ , pm_con_arg_tys = arg_tys+ , pm_con_tvs = ex_tvs+ , pm_con_dicts = dicts+ , pm_con_args = args } ]+ in updateVsa upd++-- | Get the union of two covered, uncovered and divergent value set+-- abstractions. Since the covered and divergent sets are represented by a+-- boolean, union means computing the logical or (at least one of the two is+-- non-empty).++mkUnion :: PartialResult -> PartialResult -> PartialResult+mkUnion = mappend++-- | Add a value vector abstraction to a value set abstraction (uncovered).+mkCons :: ValVec -> PartialResult -> PartialResult+mkCons vva = updateVsa (vva:)++-- | Set the divergent set to not empty+forces :: PartialResult -> PartialResult+forces pres = pres { presultDivergent = Diverged }++-- | Set the divergent set to non-empty if the flag is `True`+force_if :: Bool -> PartialResult -> PartialResult+force_if True pres = forces pres+force_if False pres = pres++set_provenance :: Provenance -> PartialResult -> PartialResult+set_provenance prov pr = pr { presultProvenence = prov }++-- ----------------------------------------------------------------------------+-- * Propagation of term constraints inwards when checking nested matches++{- Note [Type and Term Equality Propagation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When checking a match it would be great to have all type and term information+available so we can get more precise results. For this reason we have functions+`addDictsDs' and `addTmCsDs' in PmMonad that store in the environment type and+term constraints (respectively) as we go deeper.++The type constraints we propagate inwards are collected by `collectEvVarsPats'+in HsPat.hs. This handles bug #4139 ( see example+ https://ghc.haskell.org/trac/ghc/attachment/ticket/4139/GADTbug.hs )+where this is needed.++For term equalities we do less, we just generate equalities for HsCase. For+example we accurately give 2 redundancy warnings for the marked cases:++f :: [a] -> Bool+f x = case x of++ [] -> case x of -- brings (x ~ []) in scope+ [] -> True+ (_:_) -> False -- can't happen++ (_:_) -> case x of -- brings (x ~ (_:_)) in scope+ (_:_) -> True+ [] -> False -- can't happen++Functions `genCaseTmCs1' and `genCaseTmCs2' are responsible for generating+these constraints.+-}++-- | Generate equalities when checking a case expression:+-- case x of { p1 -> e1; ... pn -> en }+-- When we go deeper to check e.g. e1 we record two equalities:+-- (x ~ y), where y is the initial uncovered when checking (p1; .. ; pn)+-- and (x ~ p1).+genCaseTmCs2 :: Maybe (LHsExpr Id) -- Scrutinee+ -> [Pat Id] -- LHS (should have length 1)+ -> [Id] -- MatchVars (should have length 1)+ -> DsM (Bag SimpleEq)+genCaseTmCs2 Nothing _ _ = return emptyBag+genCaseTmCs2 (Just scr) [p] [var] = do+ fam_insts <- dsGetFamInstEnvs+ [e] <- map vaToPmExpr . coercePatVec <$> translatePat fam_insts p+ let scr_e = lhsExprToPmExpr scr+ return $ listToBag [(var, e), (var, scr_e)]+genCaseTmCs2 _ _ _ = panic "genCaseTmCs2: HsCase"++-- | Generate a simple equality when checking a case expression:+-- case x of { matches }+-- When checking matches we record that (x ~ y) where y is the initial+-- uncovered. All matches will have to satisfy this equality.+genCaseTmCs1 :: Maybe (LHsExpr Id) -> [Id] -> Bag SimpleEq+genCaseTmCs1 Nothing _ = emptyBag+genCaseTmCs1 (Just scr) [var] = unitBag (var, lhsExprToPmExpr scr)+genCaseTmCs1 _ _ = panic "genCaseTmCs1: HsCase"++{- Note [Literals in PmPat]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Instead of translating a literal to a variable accompanied with a guard, we+treat them like constructor patterns. The following example from+"./libraries/base/GHC/IO/Encoding.hs" shows why:++mkTextEncoding' :: CodingFailureMode -> String -> IO TextEncoding+mkTextEncoding' cfm enc = case [toUpper c | c <- enc, c /= '-'] of+ "UTF8" -> return $ UTF8.mkUTF8 cfm+ "UTF16" -> return $ UTF16.mkUTF16 cfm+ "UTF16LE" -> return $ UTF16.mkUTF16le cfm+ ...++Each clause gets translated to a list of variables with an equal number of+guards. For every guard we generate two cases (equals True/equals False) which+means that we generate 2^n cases to feed the oracle with, where n is the sum of+the length of all strings that appear in the patterns. For this particular+example this means over 2^40 cases. Instead, by representing them like with+constructor we get the following:+ 1. We exploit the common prefix with our representation of VSAs+ 2. We prune immediately non-reachable cases+ (e.g. False == (x == "U"), True == (x == "U"))++Note [Translating As Patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Instead of translating x@p as: x (p <- x)+we instead translate it as: p (x <- coercePattern p)+for performance reasons. For example:++ f x@True = 1+ f y@False = 2++Gives the following with the first translation:++ x |> {x == False, x == y, y == True}++If we use the second translation we get an empty set, independently of the+oracle. Since the pattern `p' may contain guard patterns though, it cannot be+used as an expression. That's why we call `coercePatVec' to drop the guard and+`vaToPmExpr' to transform the value abstraction to an expression in the+guard pattern (value abstractions are a subset of expressions). We keep the+guards in the first pattern `p' though.+++%************************************************************************+%* *+ Pretty printing of exhaustiveness/redundancy check warnings+%* *+%************************************************************************+-}++-- | Check whether any part of pattern match checking is enabled (does not+-- matter whether it is the redundancy check or the exhaustiveness check).+isAnyPmCheckEnabled :: DynFlags -> DsMatchContext -> Bool+isAnyPmCheckEnabled dflags (DsMatchContext kind _loc)+ = wopt Opt_WarnOverlappingPatterns dflags || exhaustive dflags kind++instance Outputable ValVec where+ ppr (ValVec vva delta)+ = let (residual_eqs, subst) = wrapUpTmState (delta_tm_cs delta)+ vector = substInValAbs subst vva+ in ppr_uncovered (vector, residual_eqs)++-- | Apply a term substitution to a value vector abstraction. All VAs are+-- transformed to PmExpr (used only before pretty printing).+substInValAbs :: PmVarEnv -> [ValAbs] -> [PmExpr]+substInValAbs subst = map (exprDeepLookup subst . vaToPmExpr)++-- | Wrap up the term oracle's state once solving is complete. Drop any+-- information about unhandled constraints (involving HsExprs) and flatten+-- (height 1) the substitution.+wrapUpTmState :: TmState -> ([ComplexEq], PmVarEnv)+wrapUpTmState (residual, (_, subst)) = (residual, flattenPmVarEnv subst)++-- | Issue all the warnings (coverage, exhaustiveness, inaccessibility)+dsPmWarn :: DynFlags -> DsMatchContext -> PmResult -> DsM ()+dsPmWarn dflags ctx@(DsMatchContext kind loc) pm_result+ = when (flag_i || flag_u) $ do+ let exists_r = flag_i && notNull redundant && onlyBuiltin+ exists_i = flag_i && notNull inaccessible && onlyBuiltin && not is_rec_upd+ exists_u = flag_u && (case uncovered of+ TypeOfUncovered _ -> True+ UncoveredPatterns u -> notNull u)++ when exists_r $ forM_ redundant $ \(L l q) -> do+ putSrcSpanDs l (warnDs (Reason Opt_WarnOverlappingPatterns)+ (pprEqn q "is redundant"))+ when exists_i $ forM_ inaccessible $ \(L l q) -> do+ putSrcSpanDs l (warnDs (Reason Opt_WarnOverlappingPatterns)+ (pprEqn q "has inaccessible right hand side"))+ when exists_u $ putSrcSpanDs loc $ warnDs flag_u_reason $+ case uncovered of+ TypeOfUncovered ty -> warnEmptyCase ty+ UncoveredPatterns candidates -> pprEqns candidates+ where+ PmResult+ { pmresultProvenance = prov+ , pmresultRedundant = redundant+ , pmresultUncovered = uncovered+ , pmresultInaccessible = inaccessible } = pm_result++ flag_i = wopt Opt_WarnOverlappingPatterns dflags+ flag_u = exhaustive dflags kind+ flag_u_reason = maybe NoReason Reason (exhaustiveWarningFlag kind)++ is_rec_upd = case kind of { RecUpd -> True; _ -> False }+ -- See Note [Inaccessible warnings for record updates]++ onlyBuiltin = prov == FromBuiltin++ maxPatterns = maxUncoveredPatterns dflags++ -- Print a single clause (for redundant/with-inaccessible-rhs)+ pprEqn q txt = pp_context True ctx (text txt) $ \f -> ppr_eqn f kind q++ -- Print several clauses (for uncovered clauses)+ pprEqns qs = pp_context False ctx (text "are non-exhaustive") $ \_ ->+ case qs of -- See #11245+ [ValVec [] _]+ -> text "Guards do not cover entire pattern space"+ _missing -> let us = map ppr qs+ in hang (text "Patterns not matched:") 4+ (vcat (take maxPatterns us)+ $$ dots maxPatterns us)++ -- Print a type-annotated wildcard (for non-exhaustive `EmptyCase`s for+ -- which we only know the type and have no inhabitants at hand)+ warnEmptyCase ty = pp_context False ctx (text "are non-exhaustive") $ \_ ->+ hang (text "Patterns not matched:") 4 (underscore <+> dcolon <+> ppr ty)++{- Note [Inaccessible warnings for record updates]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #12957)+ data T a where+ T1 :: { x :: Int } -> T Bool+ T2 :: { x :: Int } -> T a+ T3 :: T a++ f :: T Char -> T a+ f r = r { x = 3 }++The desugarer will (conservatively generate a case for T1 even though+it's impossible:+ f r = case r of+ T1 x -> T1 3 -- Inaccessible branch+ T2 x -> T2 3+ _ -> error "Missing"++We don't want to warn about the inaccessible branch because the programmer+didn't put it there! So we filter out the warning here.+-}++-- | Issue a warning when the predefined number of iterations is exceeded+-- for the pattern match checker+warnPmIters :: DynFlags -> DsMatchContext -> DsM ()+warnPmIters dflags (DsMatchContext kind loc)+ = when (flag_i || flag_u) $ do+ iters <- maxPmCheckIterations <$> getDynFlags+ putSrcSpanDs loc (warnDs NoReason (msg iters))+ where+ ctxt = pprMatchContext kind+ msg is = fsep [ text "Pattern match checker exceeded"+ , parens (ppr is), text "iterations in", ctxt <> dot+ , text "(Use -fmax-pmcheck-iterations=n"+ , text "to set the maximun number of iterations to n)" ]++ flag_i = wopt Opt_WarnOverlappingPatterns dflags+ flag_u = exhaustive dflags kind++dots :: Int -> [a] -> SDoc+dots maxPatterns qs+ | qs `lengthExceeds` maxPatterns = text "..."+ | otherwise = empty++-- | Check whether the exhaustiveness checker should run (exhaustiveness only)+exhaustive :: DynFlags -> HsMatchContext id -> Bool+exhaustive dflags = maybe False (`wopt` dflags) . exhaustiveWarningFlag++-- | Denotes whether an exhaustiveness check is supported, and if so,+-- via which 'WarningFlag' it's controlled.+-- Returns 'Nothing' if check is not supported.+exhaustiveWarningFlag :: HsMatchContext id -> Maybe WarningFlag+exhaustiveWarningFlag (FunRhs {}) = Just Opt_WarnIncompletePatterns+exhaustiveWarningFlag CaseAlt = Just Opt_WarnIncompletePatterns+exhaustiveWarningFlag IfAlt = Nothing+exhaustiveWarningFlag LambdaExpr = Just Opt_WarnIncompleteUniPatterns+exhaustiveWarningFlag PatBindRhs = Just Opt_WarnIncompleteUniPatterns+exhaustiveWarningFlag ProcExpr = Just Opt_WarnIncompleteUniPatterns+exhaustiveWarningFlag RecUpd = Just Opt_WarnIncompletePatternsRecUpd+exhaustiveWarningFlag ThPatSplice = Nothing+exhaustiveWarningFlag PatSyn = Nothing+exhaustiveWarningFlag ThPatQuote = Nothing+exhaustiveWarningFlag (StmtCtxt {}) = Nothing -- Don't warn about incomplete patterns+ -- in list comprehensions, pattern guards+ -- etc. They are often *supposed* to be+ -- incomplete++-- True <==> singular+pp_context :: Bool -> DsMatchContext -> SDoc -> ((SDoc -> SDoc) -> SDoc) -> SDoc+pp_context singular (DsMatchContext kind _loc) msg rest_of_msg_fun+ = vcat [text txt <+> msg,+ sep [ text "In" <+> ppr_match <> char ':'+ , nest 4 (rest_of_msg_fun pref)]]+ where+ txt | singular = "Pattern match"+ | otherwise = "Pattern match(es)"++ (ppr_match, pref)+ = case kind of+ FunRhs (L _ fun) _ _ -> (pprMatchContext kind,+ \ pp -> ppr fun <+> pp)+ _ -> (pprMatchContext kind, \ pp -> pp)++ppr_pats :: HsMatchContext Name -> [Pat Id] -> SDoc+ppr_pats kind pats+ = sep [sep (map ppr pats), matchSeparator kind, text "..."]++ppr_eqn :: (SDoc -> SDoc) -> HsMatchContext Name -> [LPat Id] -> SDoc+ppr_eqn prefixF kind eqn = prefixF (ppr_pats kind (map unLoc eqn))++ppr_constraint :: (SDoc,[PmLit]) -> SDoc+ppr_constraint (var, lits) = var <+> text "is not one of"+ <+> braces (pprWithCommas ppr lits)++ppr_uncovered :: ([PmExpr], [ComplexEq]) -> SDoc+ppr_uncovered (expr_vec, complex)+ | null cs = fsep vec -- there are no literal constraints+ | otherwise = hang (fsep vec) 4 $+ text "where" <+> vcat (map ppr_constraint cs)+ where+ sdoc_vec = mapM pprPmExprWithParens expr_vec+ (vec,cs) = runPmPprM sdoc_vec (filterComplex complex)++{- Note [Representation of Term Equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the paper, term constraints always take the form (x ~ e). Of course, a more+general constraint of the form (e1 ~ e1) can always be transformed to an+equivalent set of the former constraints, by introducing a fresh, intermediate+variable: { y ~ e1, y ~ e1 }. Yet, implementing this representation gave rise+to #11160 (incredibly bad performance for literal pattern matching). Two are+the main sources of this problem (the actual problem is how these two interact+with each other):++1. Pattern matching on literals generates twice as many constraints as needed.+ Consider the following (tests/ghci/should_run/ghcirun004):++ foo :: Int -> Int+ foo 1 = 0+ ...+ foo 5000 = 4999++ The covered and uncovered set *should* look like:+ U0 = { x |> {} }++ C1 = { 1 |> { x ~ 1 } }+ U1 = { x |> { False ~ (x ~ 1) } }+ ...+ C10 = { 10 |> { False ~ (x ~ 1), .., False ~ (x ~ 9), x ~ 10 } }+ U10 = { x |> { False ~ (x ~ 1), .., False ~ (x ~ 9), False ~ (x ~ 10) } }+ ...++ If we replace { False ~ (x ~ 1) } with { y ~ False, y ~ (x ~ 1) }+ we get twice as many constraints. Also note that half of them are just the+ substitution [x |-> False].++2. The term oracle (`tmOracle` in deSugar/TmOracle) uses equalities of the form+ (x ~ e) as substitutions [x |-> e]. More specifically, function+ `extendSubstAndSolve` applies such substitutions in the residual constraints+ and partitions them in the affected and non-affected ones, which are the new+ worklist. Essentially, this gives quadradic behaviour on the number of the+ residual constraints. (This would not be the case if the term oracle used+ mutable variables but, since we use it to handle disjunctions on value set+ abstractions (`Union` case), we chose a pure, incremental interface).++Now the problem becomes apparent (e.g. for clause 300):+ * Set U300 contains 300 substituting constraints [y_i |-> False] and 300+ constraints that we know that will not reduce (stay in the worklist).+ * To check for consistency, we apply the substituting constraints ONE BY ONE+ (since `tmOracle` is called incrementally, it does not have all of them+ available at once). Hence, we go through the (non-progressing) constraints+ over and over, achieving over-quadradic behaviour.++If instead we allow constraints of the form (e ~ e),+ * All uncovered sets Ui contain no substituting constraints and i+ non-progressing constraints of the form (False ~ (x ~ lit)) so the oracle+ behaves linearly.+ * All covered sets Ci contain exactly (i-1) non-progressing constraints and+ a single substituting constraint. So the term oracle goes through the+ constraints only once.++The performance improvement becomes even more important when more arguments are+involved.+-}++-- Debugging Infrastructre++tracePm :: String -> SDoc -> PmM ()+tracePm herald doc = liftD $ tracePmD herald doc+++tracePmD :: String -> SDoc -> DsM ()+tracePmD herald doc = do+ dflags <- getDynFlags+ printer <- mkPrintUnqualifiedDs+ liftIO $ dumpIfSet_dyn_printer printer dflags+ Opt_D_dump_ec_trace (text herald $$ (nest 2 doc))+++pprPmPatDebug :: PmPat a -> SDoc+pprPmPatDebug (PmCon cc _arg_tys _con_tvs _con_dicts con_args)+ = hsep [text "PmCon", ppr cc, hsep (map pprPmPatDebug con_args)]+pprPmPatDebug (PmVar vid) = text "PmVar" <+> ppr vid+pprPmPatDebug (PmLit li) = text "PmLit" <+> ppr li+pprPmPatDebug (PmNLit i nl) = text "PmNLit" <+> ppr i <+> ppr nl+pprPmPatDebug (PmGrd pv ge) = text "PmGrd" <+> hsep (map pprPmPatDebug pv)+ <+> ppr ge++pprPatVec :: PatVec -> SDoc+pprPatVec ps = hang (text "Pattern:") 2+ (brackets $ sep+ $ punctuate (comma <> char '\n') (map pprPmPatDebug ps))++pprValAbs :: [ValAbs] -> SDoc+pprValAbs ps = hang (text "ValAbs:") 2+ (brackets $ sep+ $ punctuate (comma) (map pprPmPatDebug ps))++pprValVecDebug :: ValVec -> SDoc+pprValVecDebug (ValVec vas _d) = text "ValVec" <+>+ parens (pprValAbs vas)
+ deSugar/Coverage.hs view
@@ -0,0 +1,1354 @@+{-+(c) Galois, 2006+(c) University of Glasgow, 2007+-}++{-# LANGUAGE CPP, NondecreasingIndentation, RecordWildCards #-}++module Coverage (addTicksToBinds, hpcInitCode) where++import qualified GHCi+import GHCi.RemoteTypes+import Data.Array+import ByteCodeTypes+#if MIN_VERSION_base(4,9,0)+import GHC.Stack.CCS+#else+import GHC.Stack as GHC.Stack.CCS+#endif+import Type+import HsSyn+import Module+import Outputable+import DynFlags+import ConLike+import Control.Monad+import SrcLoc+import ErrUtils+import NameSet hiding (FreeVars)+import Name+import Bag+import CostCentre+import CoreSyn+import Id+import VarSet+import Data.List+import FastString+import HscTypes+import TyCon+import UniqSupply+import BasicTypes+import MonadUtils+import Maybes+import CLabel+import Util++import Data.Time+import System.Directory++import Trace.Hpc.Mix+import Trace.Hpc.Util++import Data.Map (Map)+import qualified Data.Map as Map++{-+************************************************************************+* *+* The main function: addTicksToBinds+* *+************************************************************************+-}++addTicksToBinds+ :: HscEnv+ -> Module+ -> ModLocation -- ... off the current module+ -> NameSet -- Exported Ids. When we call addTicksToBinds,+ -- isExportedId doesn't work yet (the desugarer+ -- hasn't set it), so we have to work from this set.+ -> [TyCon] -- Type constructor in this module+ -> LHsBinds Id+ -> IO (LHsBinds Id, HpcInfo, Maybe ModBreaks)++addTicksToBinds hsc_env mod mod_loc exports tyCons binds+ | let dflags = hsc_dflags hsc_env+ passes = coveragePasses dflags, not (null passes),+ Just orig_file <- ml_hs_file mod_loc,+ not ("boot" `isSuffixOf` orig_file) = do++ us <- mkSplitUniqSupply 'C' -- for cost centres+ let orig_file2 = guessSourceFile binds orig_file++ tickPass tickish (binds,st) =+ let env = TTE+ { fileName = mkFastString orig_file2+ , declPath = []+ , tte_dflags = dflags+ , exports = exports+ , inlines = emptyVarSet+ , inScope = emptyVarSet+ , blackList = Map.fromList+ [ (getSrcSpan (tyConName tyCon),())+ | tyCon <- tyCons ]+ , density = mkDensity tickish dflags+ , this_mod = mod+ , tickishType = tickish+}+ (binds',_,st') = unTM (addTickLHsBinds binds) env st+ in (binds', st')++ initState = TT { tickBoxCount = 0+ , mixEntries = []+ , uniqSupply = us+ }++ (binds1,st) = foldr tickPass (binds, initState) passes++ let tickCount = tickBoxCount st+ entries = reverse $ mixEntries st+ hashNo <- writeMixEntries dflags mod tickCount entries orig_file2+ modBreaks <- mkModBreaks hsc_env mod tickCount entries++ when (dopt Opt_D_dump_ticked dflags) $+ putLogMsg dflags NoReason SevDump noSrcSpan+ (defaultDumpStyle dflags) (pprLHsBinds binds1)++ return (binds1, HpcInfo tickCount hashNo, Just modBreaks)++ | otherwise = return (binds, emptyHpcInfo False, Nothing)++guessSourceFile :: LHsBinds Id -> FilePath -> FilePath+guessSourceFile binds orig_file =+ -- Try look for a file generated from a .hsc file to a+ -- .hs file, by peeking ahead.+ let top_pos = catMaybes $ foldrBag (\ (L pos _) rest ->+ srcSpanFileName_maybe pos : rest) [] binds+ in+ case top_pos of+ (file_name:_) | ".hsc" `isSuffixOf` unpackFS file_name+ -> unpackFS file_name+ _ -> orig_file+++mkModBreaks :: HscEnv -> Module -> Int -> [MixEntry_] -> IO ModBreaks+mkModBreaks hsc_env mod count entries+ | HscInterpreted <- hscTarget (hsc_dflags hsc_env) = do+ breakArray <- GHCi.newBreakArray hsc_env (length entries)+ ccs <- mkCCSArray hsc_env mod count entries+ let+ locsTicks = listArray (0,count-1) [ span | (span,_,_,_) <- entries ]+ varsTicks = listArray (0,count-1) [ vars | (_,_,vars,_) <- entries ]+ declsTicks = listArray (0,count-1) [ decls | (_,decls,_,_) <- entries ]+ return emptyModBreaks+ { modBreaks_flags = breakArray+ , modBreaks_locs = locsTicks+ , modBreaks_vars = varsTicks+ , modBreaks_decls = declsTicks+ , modBreaks_ccs = ccs+ }+ | otherwise = return emptyModBreaks++mkCCSArray+ :: HscEnv -> Module -> Int -> [MixEntry_]+ -> IO (Array BreakIndex (RemotePtr GHC.Stack.CCS.CostCentre))+mkCCSArray hsc_env modul count entries = do+ if interpreterProfiled dflags+ then do+ let module_str = moduleNameString (moduleName modul)+ costcentres <- GHCi.mkCostCentres hsc_env module_str (map mk_one entries)+ return (listArray (0,count-1) costcentres)+ else do+ return (listArray (0,-1) [])+ where+ dflags = hsc_dflags hsc_env+ mk_one (srcspan, decl_path, _, _) = (name, src)+ where name = concat (intersperse "." decl_path)+ src = showSDoc dflags (ppr srcspan)+++writeMixEntries+ :: DynFlags -> Module -> Int -> [MixEntry_] -> FilePath -> IO Int+writeMixEntries dflags mod count entries filename+ | not (gopt Opt_Hpc dflags) = return 0+ | otherwise = do+ let+ hpc_dir = hpcDir dflags+ mod_name = moduleNameString (moduleName mod)++ hpc_mod_dir+ | moduleUnitId mod == mainUnitId = hpc_dir+ | otherwise = hpc_dir ++ "/" ++ unitIdString (moduleUnitId mod)++ tabStop = 8 -- <tab> counts as a normal char in GHC's+ -- location ranges.++ createDirectoryIfMissing True hpc_mod_dir+ modTime <- getModificationUTCTime filename+ let entries' = [ (hpcPos, box)+ | (span,_,_,box) <- entries, hpcPos <- [mkHpcPos span] ]+ when (length entries' /= count) $ do+ panic "the number of .mix entries are inconsistent"+ let hashNo = mixHash filename modTime tabStop entries'+ mixCreate hpc_mod_dir mod_name+ $ Mix filename modTime (toHash hashNo) tabStop entries'+ return hashNo+++-- -----------------------------------------------------------------------------+-- TickDensity: where to insert ticks++data TickDensity+ = TickForCoverage -- for Hpc+ | TickForBreakPoints -- for GHCi+ | TickAllFunctions -- for -prof-auto-all+ | TickTopFunctions -- for -prof-auto-top+ | TickExportedFunctions -- for -prof-auto-exported+ | TickCallSites -- for stack tracing+ deriving Eq++mkDensity :: TickishType -> DynFlags -> TickDensity+mkDensity tickish dflags = case tickish of+ HpcTicks -> TickForCoverage+ SourceNotes -> TickForCoverage+ Breakpoints -> TickForBreakPoints+ ProfNotes ->+ case profAuto dflags of+ ProfAutoAll -> TickAllFunctions+ ProfAutoTop -> TickTopFunctions+ ProfAutoExports -> TickExportedFunctions+ ProfAutoCalls -> TickCallSites+ _other -> panic "mkDensity"++-- | Decide whether to add a tick to a binding or not.+shouldTickBind :: TickDensity+ -> Bool -- top level?+ -> Bool -- exported?+ -> Bool -- simple pat bind?+ -> Bool -- INLINE pragma?+ -> Bool++shouldTickBind density top_lev exported _simple_pat inline+ = case density of+ TickForBreakPoints -> False+ -- we never add breakpoints to simple pattern bindings+ -- (there's always a tick on the rhs anyway).+ TickAllFunctions -> not inline+ TickTopFunctions -> top_lev && not inline+ TickExportedFunctions -> exported && not inline+ TickForCoverage -> True+ TickCallSites -> False++shouldTickPatBind :: TickDensity -> Bool -> Bool+shouldTickPatBind density top_lev+ = case density of+ TickForBreakPoints -> False+ TickAllFunctions -> True+ TickTopFunctions -> top_lev+ TickExportedFunctions -> False+ TickForCoverage -> False+ TickCallSites -> False++-- -----------------------------------------------------------------------------+-- Adding ticks to bindings++addTickLHsBinds :: LHsBinds Id -> TM (LHsBinds Id)+addTickLHsBinds = mapBagM addTickLHsBind++addTickLHsBind :: LHsBind Id -> TM (LHsBind Id)+addTickLHsBind (L pos bind@(AbsBinds { abs_binds = binds,+ abs_exports = abs_exports })) = do+ withEnv add_exports $ do+ withEnv add_inlines $ do+ binds' <- addTickLHsBinds binds+ return $ L pos $ bind { abs_binds = binds' }+ where+ -- in AbsBinds, the Id on each binding is not the actual top-level+ -- Id that we are defining, they are related by the abs_exports+ -- field of AbsBinds. So if we're doing TickExportedFunctions we need+ -- to add the local Ids to the set of exported Names so that we know to+ -- tick the right bindings.+ add_exports env =+ env{ exports = exports env `extendNameSetList`+ [ idName mid+ | ABE{ abe_poly = pid, abe_mono = mid } <- abs_exports+ , idName pid `elemNameSet` (exports env) ] }++ add_inlines env =+ env{ inlines = inlines env `extendVarSetList`+ [ mid+ | ABE{ abe_poly = pid, abe_mono = mid } <- abs_exports+ , isAnyInlinePragma (idInlinePragma pid) ] }++addTickLHsBind (L pos bind@(AbsBindsSig { abs_sig_bind = val_bind+ , abs_sig_export = poly_id }))+ | L _ FunBind { fun_id = L _ mono_id } <- val_bind+ = do withEnv (add_export mono_id) $ do+ withEnv (add_inlines mono_id) $ do+ val_bind' <- addTickLHsBind val_bind+ return $ L pos $ bind { abs_sig_bind = val_bind' }++ | otherwise+ = pprPanic "addTickLHsBind" (ppr bind)+ where+ -- see AbsBinds comments+ add_export mono_id env+ | idName poly_id `elemNameSet` exports env+ = env { exports = exports env `extendNameSet` idName mono_id }+ | otherwise+ = env++ add_inlines mono_id env+ | isAnyInlinePragma (idInlinePragma poly_id)+ = env { inlines = inlines env `extendVarSet` mono_id }+ | otherwise+ = env++addTickLHsBind (L pos (funBind@(FunBind { fun_id = (L _ id) }))) = do+ let name = getOccString id+ decl_path <- getPathEntry+ density <- getDensity++ inline_ids <- liftM inlines getEnv+ let inline = isAnyInlinePragma (idInlinePragma id)+ || id `elemVarSet` inline_ids++ -- See Note [inline sccs]+ tickish <- tickishType `liftM` getEnv+ if inline && tickish == ProfNotes then return (L pos funBind) else do++ (fvs, mg@(MG { mg_alts = matches' })) <-+ getFreeVars $+ addPathEntry name $+ addTickMatchGroup False (fun_matches funBind)++ blackListed <- isBlackListed pos+ exported_names <- liftM exports getEnv++ -- We don't want to generate code for blacklisted positions+ -- We don't want redundant ticks on simple pattern bindings+ -- We don't want to tick non-exported bindings in TickExportedFunctions+ let simple = isSimplePatBind funBind+ toplev = null decl_path+ exported = idName id `elemNameSet` exported_names++ tick <- if not blackListed &&+ shouldTickBind density toplev exported simple inline+ then+ bindTick density name pos fvs+ else+ return Nothing++ let mbCons = maybe Prelude.id (:)+ return $ L pos $ funBind { fun_matches = mg { mg_alts = matches' }+ , fun_tick = tick `mbCons` fun_tick funBind }++ where+ -- a binding is a simple pattern binding if it is a funbind with+ -- zero patterns+ isSimplePatBind :: HsBind a -> Bool+ isSimplePatBind funBind = matchGroupArity (fun_matches funBind) == 0++-- TODO: Revisit this+addTickLHsBind (L pos (pat@(PatBind { pat_lhs = lhs, pat_rhs = rhs }))) = do+ let name = "(...)"+ (fvs, rhs') <- getFreeVars $ addPathEntry name $ addTickGRHSs False False rhs+ let pat' = pat { pat_rhs = rhs'}++ -- Should create ticks here?+ density <- getDensity+ decl_path <- getPathEntry+ let top_lev = null decl_path+ if not (shouldTickPatBind density top_lev) then return (L pos pat') else do++ -- Allocate the ticks+ rhs_tick <- bindTick density name pos fvs+ let patvars = map getOccString (collectPatBinders lhs)+ patvar_ticks <- mapM (\v -> bindTick density v pos fvs) patvars++ -- Add to pattern+ let mbCons = maybe id (:)+ rhs_ticks = rhs_tick `mbCons` fst (pat_ticks pat')+ patvar_tickss = zipWith mbCons patvar_ticks+ (snd (pat_ticks pat') ++ repeat [])+ return $ L pos $ pat' { pat_ticks = (rhs_ticks, patvar_tickss) }++-- Only internal stuff, not from source, uses VarBind, so we ignore it.+addTickLHsBind var_bind@(L _ (VarBind {})) = return var_bind+addTickLHsBind patsyn_bind@(L _ (PatSynBind {})) = return patsyn_bind+++bindTick+ :: TickDensity -> String -> SrcSpan -> FreeVars -> TM (Maybe (Tickish Id))+bindTick density name pos fvs = do+ decl_path <- getPathEntry+ let+ toplev = null decl_path+ count_entries = toplev || density == TickAllFunctions+ top_only = density /= TickAllFunctions+ box_label = if toplev then TopLevelBox [name]+ else LocalBox (decl_path ++ [name])+ --+ allocATickBox box_label count_entries top_only pos fvs+++-- Note [inline sccs]+--+-- It should be reasonable to add ticks to INLINE functions; however+-- currently this tickles a bug later on because the SCCfinal pass+-- does not look inside unfoldings to find CostCentres. It would be+-- difficult to fix that, because SCCfinal currently works on STG and+-- not Core (and since it also generates CostCentres for CAFs,+-- changing this would be difficult too).+--+-- Another reason not to add ticks to INLINE functions is that this+-- sometimes handy for avoiding adding a tick to a particular function+-- (see #6131)+--+-- So for now we do not add any ticks to INLINE functions at all.++-- -----------------------------------------------------------------------------+-- Decorate an LHsExpr with ticks++-- selectively add ticks to interesting expressions+addTickLHsExpr :: LHsExpr Id -> TM (LHsExpr Id)+addTickLHsExpr e@(L pos e0) = do+ d <- getDensity+ case d of+ TickForBreakPoints | isGoodBreakExpr e0 -> tick_it+ TickForCoverage -> tick_it+ TickCallSites | isCallSite e0 -> tick_it+ _other -> dont_tick_it+ where+ tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0+ dont_tick_it = addTickLHsExprNever e++-- Add a tick to an expression which is the RHS of an equation or a binding.+-- We always consider these to be breakpoints, unless the expression is a 'let'+-- (because the body will definitely have a tick somewhere). ToDo: perhaps+-- we should treat 'case' and 'if' the same way?+addTickLHsExprRHS :: LHsExpr Id -> TM (LHsExpr Id)+addTickLHsExprRHS e@(L pos e0) = do+ d <- getDensity+ case d of+ TickForBreakPoints | HsLet{} <- e0 -> dont_tick_it+ | otherwise -> tick_it+ TickForCoverage -> tick_it+ TickCallSites | isCallSite e0 -> tick_it+ _other -> dont_tick_it+ where+ tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0+ dont_tick_it = addTickLHsExprNever e++-- The inner expression of an evaluation context:+-- let binds in [], ( [] )+-- we never tick these if we're doing HPC, but otherwise+-- we treat it like an ordinary expression.+addTickLHsExprEvalInner :: LHsExpr Id -> TM (LHsExpr Id)+addTickLHsExprEvalInner e = do+ d <- getDensity+ case d of+ TickForCoverage -> addTickLHsExprNever e+ _otherwise -> addTickLHsExpr e++-- | A let body is treated differently from addTickLHsExprEvalInner+-- above with TickForBreakPoints, because for breakpoints we always+-- want to tick the body, even if it is not a redex. See test+-- break012. This gives the user the opportunity to inspect the+-- values of the let-bound variables.+addTickLHsExprLetBody :: LHsExpr Id -> TM (LHsExpr Id)+addTickLHsExprLetBody e@(L pos e0) = do+ d <- getDensity+ case d of+ TickForBreakPoints | HsLet{} <- e0 -> dont_tick_it+ | otherwise -> tick_it+ _other -> addTickLHsExprEvalInner e+ where+ tick_it = allocTickBox (ExpBox False) False False pos $ addTickHsExpr e0+ dont_tick_it = addTickLHsExprNever e++-- version of addTick that does not actually add a tick,+-- because the scope of this tick is completely subsumed by+-- another.+addTickLHsExprNever :: LHsExpr Id -> TM (LHsExpr Id)+addTickLHsExprNever (L pos e0) = do+ e1 <- addTickHsExpr e0+ return $ L pos e1++-- general heuristic: expressions which do not denote values are good+-- break points+isGoodBreakExpr :: HsExpr Id -> Bool+isGoodBreakExpr (HsApp {}) = True+isGoodBreakExpr (HsAppTypeOut {}) = True+isGoodBreakExpr (OpApp {}) = True+isGoodBreakExpr _other = False++isCallSite :: HsExpr Id -> Bool+isCallSite HsApp{} = True+isCallSite HsAppTypeOut{} = True+isCallSite OpApp{} = True+isCallSite _ = False++addTickLHsExprOptAlt :: Bool -> LHsExpr Id -> TM (LHsExpr Id)+addTickLHsExprOptAlt oneOfMany (L pos e0)+ = ifDensity TickForCoverage+ (allocTickBox (ExpBox oneOfMany) False False pos $ addTickHsExpr e0)+ (addTickLHsExpr (L pos e0))++addBinTickLHsExpr :: (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)+addBinTickLHsExpr boxLabel (L pos e0)+ = ifDensity TickForCoverage+ (allocBinTickBox boxLabel pos $ addTickHsExpr e0)+ (addTickLHsExpr (L pos e0))+++-- -----------------------------------------------------------------------------+-- Decorate the body of an HsExpr with ticks.+-- (Whether to put a tick around the whole expression was already decided,+-- in the addTickLHsExpr family of functions.)++addTickHsExpr :: HsExpr Id -> TM (HsExpr Id)+addTickHsExpr e@(HsVar (L _ id)) = do freeVar id; return e+addTickHsExpr (HsUnboundVar {}) = panic "addTickHsExpr.HsUnboundVar"+addTickHsExpr e@(HsConLikeOut con)+ | Just id <- conLikeWrapId_maybe con = do freeVar id; return e+addTickHsExpr e@(HsIPVar _) = return e+addTickHsExpr e@(HsOverLit _) = return e+addTickHsExpr e@(HsOverLabel{}) = return e+addTickHsExpr e@(HsLit _) = return e+addTickHsExpr (HsLam matchgroup) = liftM HsLam (addTickMatchGroup True matchgroup)+addTickHsExpr (HsLamCase mgs) = liftM HsLamCase (addTickMatchGroup True mgs)+addTickHsExpr (HsApp e1 e2) = liftM2 HsApp (addTickLHsExprNever e1)+ (addTickLHsExpr e2)+addTickHsExpr (HsAppTypeOut e ty) = liftM2 HsAppTypeOut (addTickLHsExprNever e)+ (return ty)++addTickHsExpr (OpApp e1 e2 fix e3) =+ liftM4 OpApp+ (addTickLHsExpr e1)+ (addTickLHsExprNever e2)+ (return fix)+ (addTickLHsExpr e3)+addTickHsExpr (NegApp e neg) =+ liftM2 NegApp+ (addTickLHsExpr e)+ (addTickSyntaxExpr hpcSrcSpan neg)+addTickHsExpr (HsPar e) =+ liftM HsPar (addTickLHsExprEvalInner e)+addTickHsExpr (SectionL e1 e2) =+ liftM2 SectionL+ (addTickLHsExpr e1)+ (addTickLHsExprNever e2)+addTickHsExpr (SectionR e1 e2) =+ liftM2 SectionR+ (addTickLHsExprNever e1)+ (addTickLHsExpr e2)+addTickHsExpr (ExplicitTuple es boxity) =+ liftM2 ExplicitTuple+ (mapM addTickTupArg es)+ (return boxity)+addTickHsExpr (ExplicitSum tag arity e ty) = do+ e' <- addTickLHsExpr e+ return (ExplicitSum tag arity e' ty)+addTickHsExpr (HsCase e mgs) =+ liftM2 HsCase+ (addTickLHsExpr e) -- not an EvalInner; e might not necessarily+ -- be evaluated.+ (addTickMatchGroup False mgs)+addTickHsExpr (HsIf cnd e1 e2 e3) =+ liftM3 (HsIf cnd)+ (addBinTickLHsExpr (BinBox CondBinBox) e1)+ (addTickLHsExprOptAlt True e2)+ (addTickLHsExprOptAlt True e3)+addTickHsExpr (HsMultiIf ty alts)+ = do { let isOneOfMany = case alts of [_] -> False; _ -> True+ ; alts' <- mapM (liftL $ addTickGRHS isOneOfMany False) alts+ ; return $ HsMultiIf ty alts' }+addTickHsExpr (HsLet (L l binds) e) =+ bindLocals (collectLocalBinders binds) $+ liftM2 (HsLet . L l)+ (addTickHsLocalBinds binds) -- to think about: !patterns.+ (addTickLHsExprLetBody e)+addTickHsExpr (HsDo cxt (L l stmts) srcloc)+ = do { (stmts', _) <- addTickLStmts' forQual stmts (return ())+ ; return (HsDo cxt (L l stmts') srcloc) }+ where+ forQual = case cxt of+ ListComp -> Just $ BinBox QualBinBox+ _ -> Nothing+addTickHsExpr (ExplicitList ty wit es) =+ liftM3 ExplicitList+ (return ty)+ (addTickWit wit)+ (mapM (addTickLHsExpr) es)+ where addTickWit Nothing = return Nothing+ addTickWit (Just fln)+ = do fln' <- addTickSyntaxExpr hpcSrcSpan fln+ return (Just fln')+addTickHsExpr (ExplicitPArr ty es) =+ liftM2 ExplicitPArr+ (return ty)+ (mapM (addTickLHsExpr) es)++addTickHsExpr (HsStatic fvs e) = HsStatic fvs <$> addTickLHsExpr e++addTickHsExpr expr@(RecordCon { rcon_flds = rec_binds })+ = do { rec_binds' <- addTickHsRecordBinds rec_binds+ ; return (expr { rcon_flds = rec_binds' }) }++addTickHsExpr expr@(RecordUpd { rupd_expr = e, rupd_flds = flds })+ = do { e' <- addTickLHsExpr e+ ; flds' <- mapM addTickHsRecField flds+ ; return (expr { rupd_expr = e', rupd_flds = flds' }) }++addTickHsExpr (ExprWithTySig e ty) =+ liftM2 ExprWithTySig+ (addTickLHsExprNever e) -- No need to tick the inner expression+ -- for expressions with signatures+ (return ty)+addTickHsExpr (ArithSeq ty wit arith_seq) =+ liftM3 ArithSeq+ (return ty)+ (addTickWit wit)+ (addTickArithSeqInfo arith_seq)+ where addTickWit Nothing = return Nothing+ addTickWit (Just fl) = do fl' <- addTickSyntaxExpr hpcSrcSpan fl+ return (Just fl')++-- We might encounter existing ticks (multiple Coverage passes)+addTickHsExpr (HsTick t e) =+ liftM (HsTick t) (addTickLHsExprNever e)+addTickHsExpr (HsBinTick t0 t1 e) =+ liftM (HsBinTick t0 t1) (addTickLHsExprNever e)++addTickHsExpr (HsTickPragma _ _ _ (L pos e0)) = do+ e2 <- allocTickBox (ExpBox False) False False pos $+ addTickHsExpr e0+ return $ unLoc e2+addTickHsExpr (PArrSeq ty arith_seq) =+ liftM2 PArrSeq+ (return ty)+ (addTickArithSeqInfo arith_seq)+addTickHsExpr (HsSCC src nm e) =+ liftM3 HsSCC+ (return src)+ (return nm)+ (addTickLHsExpr e)+addTickHsExpr (HsCoreAnn src nm e) =+ liftM3 HsCoreAnn+ (return src)+ (return nm)+ (addTickLHsExpr e)+addTickHsExpr e@(HsBracket {}) = return e+addTickHsExpr e@(HsTcBracketOut {}) = return e+addTickHsExpr e@(HsRnBracketOut {}) = return e+addTickHsExpr e@(HsSpliceE {}) = return e+addTickHsExpr (HsProc pat cmdtop) =+ liftM2 HsProc+ (addTickLPat pat)+ (liftL (addTickHsCmdTop) cmdtop)+addTickHsExpr (HsWrap w e) =+ liftM2 HsWrap+ (return w)+ (addTickHsExpr e) -- Explicitly no tick on inside++addTickHsExpr (ExprWithTySigOut e ty) =+ liftM2 ExprWithTySigOut+ (addTickLHsExprNever e) -- No need to tick the inner expression+ (return ty) -- for expressions with signatures++-- Others should never happen in expression content.+addTickHsExpr e = pprPanic "addTickHsExpr" (ppr e)++addTickTupArg :: LHsTupArg Id -> TM (LHsTupArg Id)+addTickTupArg (L l (Present e)) = do { e' <- addTickLHsExpr e+ ; return (L l (Present e')) }+addTickTupArg (L l (Missing ty)) = return (L l (Missing ty))++addTickMatchGroup :: Bool{-is lambda-} -> MatchGroup Id (LHsExpr Id) -> TM (MatchGroup Id (LHsExpr Id))+addTickMatchGroup is_lam mg@(MG { mg_alts = L l matches }) = do+ let isOneOfMany = matchesOneOfMany matches+ matches' <- mapM (liftL (addTickMatch isOneOfMany is_lam)) matches+ return $ mg { mg_alts = L l matches' }++addTickMatch :: Bool -> Bool -> Match Id (LHsExpr Id) -> TM (Match Id (LHsExpr Id))+addTickMatch isOneOfMany isLambda (Match mf pats opSig gRHSs) =+ bindLocals (collectPatsBinders pats) $ do+ gRHSs' <- addTickGRHSs isOneOfMany isLambda gRHSs+ return $ Match mf pats opSig gRHSs'++addTickGRHSs :: Bool -> Bool -> GRHSs Id (LHsExpr Id) -> TM (GRHSs Id (LHsExpr Id))+addTickGRHSs isOneOfMany isLambda (GRHSs guarded (L l local_binds)) = do+ bindLocals binders $ do+ local_binds' <- addTickHsLocalBinds local_binds+ guarded' <- mapM (liftL (addTickGRHS isOneOfMany isLambda)) guarded+ return $ GRHSs guarded' (L l local_binds')+ where+ binders = collectLocalBinders local_binds++addTickGRHS :: Bool -> Bool -> GRHS Id (LHsExpr Id) -> TM (GRHS Id (LHsExpr Id))+addTickGRHS isOneOfMany isLambda (GRHS stmts expr) = do+ (stmts',expr') <- addTickLStmts' (Just $ BinBox $ GuardBinBox) stmts+ (addTickGRHSBody isOneOfMany isLambda expr)+ return $ GRHS stmts' expr'++addTickGRHSBody :: Bool -> Bool -> LHsExpr Id -> TM (LHsExpr Id)+addTickGRHSBody isOneOfMany isLambda expr@(L pos e0) = do+ d <- getDensity+ case d of+ TickForCoverage -> addTickLHsExprOptAlt isOneOfMany expr+ TickAllFunctions | isLambda ->+ addPathEntry "\\" $+ allocTickBox (ExpBox False) True{-count-} False{-not top-} pos $+ addTickHsExpr e0+ _otherwise ->+ addTickLHsExprRHS expr++addTickLStmts :: (Maybe (Bool -> BoxLabel)) -> [ExprLStmt Id] -> TM [ExprLStmt Id]+addTickLStmts isGuard stmts = do+ (stmts, _) <- addTickLStmts' isGuard stmts (return ())+ return stmts++addTickLStmts' :: (Maybe (Bool -> BoxLabel)) -> [ExprLStmt Id] -> TM a+ -> TM ([ExprLStmt Id], a)+addTickLStmts' isGuard lstmts res+ = bindLocals (collectLStmtsBinders lstmts) $+ do { lstmts' <- mapM (liftL (addTickStmt isGuard)) lstmts+ ; a <- res+ ; return (lstmts', a) }++addTickStmt :: (Maybe (Bool -> BoxLabel)) -> Stmt Id (LHsExpr Id) -> TM (Stmt Id (LHsExpr Id))+addTickStmt _isGuard (LastStmt e noret ret) = do+ liftM3 LastStmt+ (addTickLHsExpr e)+ (pure noret)+ (addTickSyntaxExpr hpcSrcSpan ret)+addTickStmt _isGuard (BindStmt pat e bind fail ty) = do+ liftM5 BindStmt+ (addTickLPat pat)+ (addTickLHsExprRHS e)+ (addTickSyntaxExpr hpcSrcSpan bind)+ (addTickSyntaxExpr hpcSrcSpan fail)+ (return ty)+addTickStmt isGuard (BodyStmt e bind' guard' ty) = do+ liftM4 BodyStmt+ (addTick isGuard e)+ (addTickSyntaxExpr hpcSrcSpan bind')+ (addTickSyntaxExpr hpcSrcSpan guard')+ (return ty)+addTickStmt _isGuard (LetStmt (L l binds)) = do+ liftM (LetStmt . L l)+ (addTickHsLocalBinds binds)+addTickStmt isGuard (ParStmt pairs mzipExpr bindExpr ty) = do+ liftM4 ParStmt+ (mapM (addTickStmtAndBinders isGuard) pairs)+ (unLoc <$> addTickLHsExpr (L hpcSrcSpan mzipExpr))+ (addTickSyntaxExpr hpcSrcSpan bindExpr)+ (return ty)+addTickStmt isGuard (ApplicativeStmt args mb_join body_ty) = do+ args' <- mapM (addTickApplicativeArg isGuard) args+ return (ApplicativeStmt args' mb_join body_ty)++addTickStmt isGuard stmt@(TransStmt { trS_stmts = stmts+ , trS_by = by, trS_using = using+ , trS_ret = returnExpr, trS_bind = bindExpr+ , trS_fmap = liftMExpr }) = do+ t_s <- addTickLStmts isGuard stmts+ t_y <- fmapMaybeM addTickLHsExprRHS by+ t_u <- addTickLHsExprRHS using+ t_f <- addTickSyntaxExpr hpcSrcSpan returnExpr+ t_b <- addTickSyntaxExpr hpcSrcSpan bindExpr+ L _ t_m <- addTickLHsExpr (L hpcSrcSpan liftMExpr)+ return $ stmt { trS_stmts = t_s, trS_by = t_y, trS_using = t_u+ , trS_ret = t_f, trS_bind = t_b, trS_fmap = t_m }++addTickStmt isGuard stmt@(RecStmt {})+ = do { stmts' <- addTickLStmts isGuard (recS_stmts stmt)+ ; ret' <- addTickSyntaxExpr hpcSrcSpan (recS_ret_fn stmt)+ ; mfix' <- addTickSyntaxExpr hpcSrcSpan (recS_mfix_fn stmt)+ ; bind' <- addTickSyntaxExpr hpcSrcSpan (recS_bind_fn stmt)+ ; return (stmt { recS_stmts = stmts', recS_ret_fn = ret'+ , recS_mfix_fn = mfix', recS_bind_fn = bind' }) }++addTick :: Maybe (Bool -> BoxLabel) -> LHsExpr Id -> TM (LHsExpr Id)+addTick isGuard e | Just fn <- isGuard = addBinTickLHsExpr fn e+ | otherwise = addTickLHsExprRHS e++addTickApplicativeArg+ :: Maybe (Bool -> BoxLabel) -> (SyntaxExpr Id, ApplicativeArg Id Id)+ -> TM (SyntaxExpr Id, ApplicativeArg Id Id)+addTickApplicativeArg isGuard (op, arg) =+ liftM2 (,) (addTickSyntaxExpr hpcSrcSpan op) (addTickArg arg)+ where+ addTickArg (ApplicativeArgOne pat expr) =+ ApplicativeArgOne <$> addTickLPat pat <*> addTickLHsExpr expr+ addTickArg (ApplicativeArgMany stmts ret pat) =+ ApplicativeArgMany+ <$> addTickLStmts isGuard stmts+ <*> (unLoc <$> addTickLHsExpr (L hpcSrcSpan ret))+ <*> addTickLPat pat++addTickStmtAndBinders :: Maybe (Bool -> BoxLabel) -> ParStmtBlock Id Id+ -> TM (ParStmtBlock Id Id)+addTickStmtAndBinders isGuard (ParStmtBlock stmts ids returnExpr) =+ liftM3 ParStmtBlock+ (addTickLStmts isGuard stmts)+ (return ids)+ (addTickSyntaxExpr hpcSrcSpan returnExpr)++addTickHsLocalBinds :: HsLocalBinds Id -> TM (HsLocalBinds Id)+addTickHsLocalBinds (HsValBinds binds) =+ liftM HsValBinds+ (addTickHsValBinds binds)+addTickHsLocalBinds (HsIPBinds binds) =+ liftM HsIPBinds+ (addTickHsIPBinds binds)+addTickHsLocalBinds (EmptyLocalBinds) = return EmptyLocalBinds++addTickHsValBinds :: HsValBindsLR Id a -> TM (HsValBindsLR Id b)+addTickHsValBinds (ValBindsOut binds sigs) =+ liftM2 ValBindsOut+ (mapM (\ (rec,binds') ->+ liftM2 (,)+ (return rec)+ (addTickLHsBinds binds'))+ binds)+ (return sigs)+addTickHsValBinds _ = panic "addTickHsValBinds"++addTickHsIPBinds :: HsIPBinds Id -> TM (HsIPBinds Id)+addTickHsIPBinds (IPBinds ipbinds dictbinds) =+ liftM2 IPBinds+ (mapM (liftL (addTickIPBind)) ipbinds)+ (return dictbinds)++addTickIPBind :: IPBind Id -> TM (IPBind Id)+addTickIPBind (IPBind nm e) =+ liftM2 IPBind+ (return nm)+ (addTickLHsExpr e)++-- There is no location here, so we might need to use a context location??+addTickSyntaxExpr :: SrcSpan -> SyntaxExpr Id -> TM (SyntaxExpr Id)+addTickSyntaxExpr pos syn@(SyntaxExpr { syn_expr = x }) = do+ L _ x' <- addTickLHsExpr (L pos x)+ return $ syn { syn_expr = x' }+-- we do not walk into patterns.+addTickLPat :: LPat Id -> TM (LPat Id)+addTickLPat pat = return pat++addTickHsCmdTop :: HsCmdTop Id -> TM (HsCmdTop Id)+addTickHsCmdTop (HsCmdTop cmd tys ty syntaxtable) =+ liftM4 HsCmdTop+ (addTickLHsCmd cmd)+ (return tys)+ (return ty)+ (return syntaxtable)++addTickLHsCmd :: LHsCmd Id -> TM (LHsCmd Id)+addTickLHsCmd (L pos c0) = do+ c1 <- addTickHsCmd c0+ return $ L pos c1++addTickHsCmd :: HsCmd Id -> TM (HsCmd Id)+addTickHsCmd (HsCmdLam matchgroup) =+ liftM HsCmdLam (addTickCmdMatchGroup matchgroup)+addTickHsCmd (HsCmdApp c e) =+ liftM2 HsCmdApp (addTickLHsCmd c) (addTickLHsExpr e)+{-+addTickHsCmd (OpApp e1 c2 fix c3) =+ liftM4 OpApp+ (addTickLHsExpr e1)+ (addTickLHsCmd c2)+ (return fix)+ (addTickLHsCmd c3)+-}+addTickHsCmd (HsCmdPar e) = liftM HsCmdPar (addTickLHsCmd e)+addTickHsCmd (HsCmdCase e mgs) =+ liftM2 HsCmdCase+ (addTickLHsExpr e)+ (addTickCmdMatchGroup mgs)+addTickHsCmd (HsCmdIf cnd e1 c2 c3) =+ liftM3 (HsCmdIf cnd)+ (addBinTickLHsExpr (BinBox CondBinBox) e1)+ (addTickLHsCmd c2)+ (addTickLHsCmd c3)+addTickHsCmd (HsCmdLet (L l binds) c) =+ bindLocals (collectLocalBinders binds) $+ liftM2 (HsCmdLet . L l)+ (addTickHsLocalBinds binds) -- to think about: !patterns.+ (addTickLHsCmd c)+addTickHsCmd (HsCmdDo (L l stmts) srcloc)+ = do { (stmts', _) <- addTickLCmdStmts' stmts (return ())+ ; return (HsCmdDo (L l stmts') srcloc) }++addTickHsCmd (HsCmdArrApp e1 e2 ty1 arr_ty lr) =+ liftM5 HsCmdArrApp+ (addTickLHsExpr e1)+ (addTickLHsExpr e2)+ (return ty1)+ (return arr_ty)+ (return lr)+addTickHsCmd (HsCmdArrForm e f fix cmdtop) =+ liftM4 HsCmdArrForm+ (addTickLHsExpr e)+ (return f)+ (return fix)+ (mapM (liftL (addTickHsCmdTop)) cmdtop)++addTickHsCmd (HsCmdWrap w cmd)+ = liftM2 HsCmdWrap (return w) (addTickHsCmd cmd)++-- Others should never happen in a command context.+--addTickHsCmd e = pprPanic "addTickHsCmd" (ppr e)++addTickCmdMatchGroup :: MatchGroup Id (LHsCmd Id) -> TM (MatchGroup Id (LHsCmd Id))+addTickCmdMatchGroup mg@(MG { mg_alts = L l matches }) = do+ matches' <- mapM (liftL addTickCmdMatch) matches+ return $ mg { mg_alts = L l matches' }++addTickCmdMatch :: Match Id (LHsCmd Id) -> TM (Match Id (LHsCmd Id))+addTickCmdMatch (Match mf pats opSig gRHSs) =+ bindLocals (collectPatsBinders pats) $ do+ gRHSs' <- addTickCmdGRHSs gRHSs+ return $ Match mf pats opSig gRHSs'++addTickCmdGRHSs :: GRHSs Id (LHsCmd Id) -> TM (GRHSs Id (LHsCmd Id))+addTickCmdGRHSs (GRHSs guarded (L l local_binds)) = do+ bindLocals binders $ do+ local_binds' <- addTickHsLocalBinds local_binds+ guarded' <- mapM (liftL addTickCmdGRHS) guarded+ return $ GRHSs guarded' (L l local_binds')+ where+ binders = collectLocalBinders local_binds++addTickCmdGRHS :: GRHS Id (LHsCmd Id) -> TM (GRHS Id (LHsCmd Id))+-- The *guards* are *not* Cmds, although the body is+-- C.f. addTickGRHS for the BinBox stuff+addTickCmdGRHS (GRHS stmts cmd)+ = do { (stmts',expr') <- addTickLStmts' (Just $ BinBox $ GuardBinBox)+ stmts (addTickLHsCmd cmd)+ ; return $ GRHS stmts' expr' }++addTickLCmdStmts :: [LStmt Id (LHsCmd Id)] -> TM [LStmt Id (LHsCmd Id)]+addTickLCmdStmts stmts = do+ (stmts, _) <- addTickLCmdStmts' stmts (return ())+ return stmts++addTickLCmdStmts' :: [LStmt Id (LHsCmd Id)] -> TM a -> TM ([LStmt Id (LHsCmd Id)], a)+addTickLCmdStmts' lstmts res+ = bindLocals binders $ do+ lstmts' <- mapM (liftL addTickCmdStmt) lstmts+ a <- res+ return (lstmts', a)+ where+ binders = collectLStmtsBinders lstmts++addTickCmdStmt :: Stmt Id (LHsCmd Id) -> TM (Stmt Id (LHsCmd Id))+addTickCmdStmt (BindStmt pat c bind fail ty) = do+ liftM5 BindStmt+ (addTickLPat pat)+ (addTickLHsCmd c)+ (return bind)+ (return fail)+ (return ty)+addTickCmdStmt (LastStmt c noret ret) = do+ liftM3 LastStmt+ (addTickLHsCmd c)+ (pure noret)+ (addTickSyntaxExpr hpcSrcSpan ret)+addTickCmdStmt (BodyStmt c bind' guard' ty) = do+ liftM4 BodyStmt+ (addTickLHsCmd c)+ (addTickSyntaxExpr hpcSrcSpan bind')+ (addTickSyntaxExpr hpcSrcSpan guard')+ (return ty)+addTickCmdStmt (LetStmt (L l binds)) = do+ liftM (LetStmt . L l)+ (addTickHsLocalBinds binds)+addTickCmdStmt stmt@(RecStmt {})+ = do { stmts' <- addTickLCmdStmts (recS_stmts stmt)+ ; ret' <- addTickSyntaxExpr hpcSrcSpan (recS_ret_fn stmt)+ ; mfix' <- addTickSyntaxExpr hpcSrcSpan (recS_mfix_fn stmt)+ ; bind' <- addTickSyntaxExpr hpcSrcSpan (recS_bind_fn stmt)+ ; return (stmt { recS_stmts = stmts', recS_ret_fn = ret'+ , recS_mfix_fn = mfix', recS_bind_fn = bind' }) }+addTickCmdStmt ApplicativeStmt{} =+ panic "ToDo: addTickCmdStmt ApplicativeLastStmt"++-- Others should never happen in a command context.+addTickCmdStmt stmt = pprPanic "addTickHsCmd" (ppr stmt)++addTickHsRecordBinds :: HsRecordBinds Id -> TM (HsRecordBinds Id)+addTickHsRecordBinds (HsRecFields fields dd)+ = do { fields' <- mapM addTickHsRecField fields+ ; return (HsRecFields fields' dd) }++addTickHsRecField :: LHsRecField' id (LHsExpr Id) -> TM (LHsRecField' id (LHsExpr Id))+addTickHsRecField (L l (HsRecField id expr pun))+ = do { expr' <- addTickLHsExpr expr+ ; return (L l (HsRecField id expr' pun)) }+++addTickArithSeqInfo :: ArithSeqInfo Id -> TM (ArithSeqInfo Id)+addTickArithSeqInfo (From e1) =+ liftM From+ (addTickLHsExpr e1)+addTickArithSeqInfo (FromThen e1 e2) =+ liftM2 FromThen+ (addTickLHsExpr e1)+ (addTickLHsExpr e2)+addTickArithSeqInfo (FromTo e1 e2) =+ liftM2 FromTo+ (addTickLHsExpr e1)+ (addTickLHsExpr e2)+addTickArithSeqInfo (FromThenTo e1 e2 e3) =+ liftM3 FromThenTo+ (addTickLHsExpr e1)+ (addTickLHsExpr e2)+ (addTickLHsExpr e3)++liftL :: (Monad m) => (a -> m a) -> Located a -> m (Located a)+liftL f (L loc a) = do+ a' <- f a+ return $ L loc a'++data TickTransState = TT { tickBoxCount:: Int+ , mixEntries :: [MixEntry_]+ , uniqSupply :: UniqSupply+ }++data TickTransEnv = TTE { fileName :: FastString+ , density :: TickDensity+ , tte_dflags :: DynFlags+ , exports :: NameSet+ , inlines :: VarSet+ , declPath :: [String]+ , inScope :: VarSet+ , blackList :: Map SrcSpan ()+ , this_mod :: Module+ , tickishType :: TickishType+ }++-- deriving Show++data TickishType = ProfNotes | HpcTicks | Breakpoints | SourceNotes+ deriving (Eq)++coveragePasses :: DynFlags -> [TickishType]+coveragePasses dflags =+ ifa (hscTarget dflags == HscInterpreted) Breakpoints $+ ifa (gopt Opt_Hpc dflags) HpcTicks $+ ifa (gopt Opt_SccProfilingOn dflags &&+ profAuto dflags /= NoProfAuto) ProfNotes $+ ifa (debugLevel dflags > 0) SourceNotes []+ where ifa f x xs | f = x:xs+ | otherwise = xs++-- | Tickishs that only make sense when their source code location+-- refers to the current file. This might not always be true due to+-- LINE pragmas in the code - which would confuse at least HPC.+tickSameFileOnly :: TickishType -> Bool+tickSameFileOnly HpcTicks = True+tickSameFileOnly _other = False++type FreeVars = OccEnv Id+noFVs :: FreeVars+noFVs = emptyOccEnv++-- Note [freevars]+-- For breakpoints we want to collect the free variables of an+-- expression for pinning on the HsTick. We don't want to collect+-- *all* free variables though: in particular there's no point pinning+-- on free variables that are will otherwise be in scope at the GHCi+-- prompt, which means all top-level bindings. Unfortunately detecting+-- top-level bindings isn't easy (collectHsBindsBinders on the top-level+-- bindings doesn't do it), so we keep track of a set of "in-scope"+-- variables in addition to the free variables, and the former is used+-- to filter additions to the latter. This gives us complete control+-- over what free variables we track.++data TM a = TM { unTM :: TickTransEnv -> TickTransState -> (a,FreeVars,TickTransState) }+ -- a combination of a state monad (TickTransState) and a writer+ -- monad (FreeVars).++instance Functor TM where+ fmap = liftM++instance Applicative TM where+ pure a = TM $ \ _env st -> (a,noFVs,st)+ (<*>) = ap++instance Monad TM where+ (TM m) >>= k = TM $ \ env st ->+ case m env st of+ (r1,fv1,st1) ->+ case unTM (k r1) env st1 of+ (r2,fv2,st2) ->+ (r2, fv1 `plusOccEnv` fv2, st2)++instance HasDynFlags TM where+ getDynFlags = TM $ \ env st -> (tte_dflags env, noFVs, st)++instance MonadUnique TM where+ getUniqueSupplyM = TM $ \_ st -> (uniqSupply st, noFVs, st)+ getUniqueM = TM $ \_ st -> let (u, us') = takeUniqFromSupply (uniqSupply st)+ in (u, noFVs, st { uniqSupply = us' })++getState :: TM TickTransState+getState = TM $ \ _ st -> (st, noFVs, st)++setState :: (TickTransState -> TickTransState) -> TM ()+setState f = TM $ \ _ st -> ((), noFVs, f st)++getEnv :: TM TickTransEnv+getEnv = TM $ \ env st -> (env, noFVs, st)++withEnv :: (TickTransEnv -> TickTransEnv) -> TM a -> TM a+withEnv f (TM m) = TM $ \ env st ->+ case m (f env) st of+ (a, fvs, st') -> (a, fvs, st')++getDensity :: TM TickDensity+getDensity = TM $ \env st -> (density env, noFVs, st)++ifDensity :: TickDensity -> TM a -> TM a -> TM a+ifDensity d th el = do d0 <- getDensity; if d == d0 then th else el++getFreeVars :: TM a -> TM (FreeVars, a)+getFreeVars (TM m)+ = TM $ \ env st -> case m env st of (a, fv, st') -> ((fv,a), fv, st')++freeVar :: Id -> TM ()+freeVar id = TM $ \ env st ->+ if id `elemVarSet` inScope env+ then ((), unitOccEnv (nameOccName (idName id)) id, st)+ else ((), noFVs, st)++addPathEntry :: String -> TM a -> TM a+addPathEntry nm = withEnv (\ env -> env { declPath = declPath env ++ [nm] })++getPathEntry :: TM [String]+getPathEntry = declPath `liftM` getEnv++getFileName :: TM FastString+getFileName = fileName `liftM` getEnv++isGoodSrcSpan' :: SrcSpan -> Bool+isGoodSrcSpan' pos@(RealSrcSpan _) = srcSpanStart pos /= srcSpanEnd pos+isGoodSrcSpan' (UnhelpfulSpan _) = False++isGoodTickSrcSpan :: SrcSpan -> TM Bool+isGoodTickSrcSpan pos = do+ file_name <- getFileName+ tickish <- tickishType `liftM` getEnv+ let need_same_file = tickSameFileOnly tickish+ same_file = Just file_name == srcSpanFileName_maybe pos+ return (isGoodSrcSpan' pos && (not need_same_file || same_file))++ifGoodTickSrcSpan :: SrcSpan -> TM a -> TM a -> TM a+ifGoodTickSrcSpan pos then_code else_code = do+ good <- isGoodTickSrcSpan pos+ if good then then_code else else_code++bindLocals :: [Id] -> TM a -> TM a+bindLocals new_ids (TM m)+ = TM $ \ env st ->+ case m env{ inScope = inScope env `extendVarSetList` new_ids } st of+ (r, fv, st') -> (r, fv `delListFromOccEnv` occs, st')+ where occs = [ nameOccName (idName id) | id <- new_ids ]++isBlackListed :: SrcSpan -> TM Bool+isBlackListed pos = TM $ \ env st ->+ case Map.lookup pos (blackList env) of+ Nothing -> (False,noFVs,st)+ Just () -> (True,noFVs,st)++-- the tick application inherits the source position of its+-- expression argument to support nested box allocations+allocTickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> TM (HsExpr Id)+ -> TM (LHsExpr Id)+allocTickBox boxLabel countEntries topOnly pos m =+ ifGoodTickSrcSpan pos (do+ (fvs, e) <- getFreeVars m+ env <- getEnv+ tickish <- mkTickish boxLabel countEntries topOnly pos fvs (declPath env)+ return (L pos (HsTick tickish (L pos e)))+ ) (do+ e <- m+ return (L pos e)+ )++-- the tick application inherits the source position of its+-- expression argument to support nested box allocations+allocATickBox :: BoxLabel -> Bool -> Bool -> SrcSpan -> FreeVars+ -> TM (Maybe (Tickish Id))+allocATickBox boxLabel countEntries topOnly pos fvs =+ ifGoodTickSrcSpan pos (do+ let+ mydecl_path = case boxLabel of+ TopLevelBox x -> x+ LocalBox xs -> xs+ _ -> panic "allocATickBox"+ tickish <- mkTickish boxLabel countEntries topOnly pos fvs mydecl_path+ return (Just tickish)+ ) (return Nothing)+++mkTickish :: BoxLabel -> Bool -> Bool -> SrcSpan -> OccEnv Id -> [String]+ -> TM (Tickish Id)+mkTickish boxLabel countEntries topOnly pos fvs decl_path = do++ let ids = filter (not . isUnliftedType . idType) $ occEnvElts fvs+ -- unlifted types cause two problems here:+ -- * we can't bind them at the GHCi prompt+ -- (bindLocalsAtBreakpoint already fliters them out),+ -- * the simplifier might try to substitute a literal for+ -- the Id, and we can't handle that.++ me = (pos, decl_path, map (nameOccName.idName) ids, boxLabel)++ cc_name | topOnly = head decl_path+ | otherwise = concat (intersperse "." decl_path)++ dflags <- getDynFlags+ env <- getEnv+ case tickishType env of+ HpcTicks -> do+ c <- liftM tickBoxCount getState+ setState $ \st -> st { tickBoxCount = c + 1+ , mixEntries = me : mixEntries st }+ return $ HpcTick (this_mod env) c++ ProfNotes -> do+ ccUnique <- getUniqueM+ let cc = mkUserCC (mkFastString cc_name) (this_mod env) pos ccUnique+ count = countEntries && gopt Opt_ProfCountEntries dflags+ return $ ProfNote cc count True{-scopes-}++ Breakpoints -> do+ c <- liftM tickBoxCount getState+ setState $ \st -> st { tickBoxCount = c + 1+ , mixEntries = me:mixEntries st }+ return $ Breakpoint c ids++ SourceNotes | RealSrcSpan pos' <- pos ->+ return $ SourceNote pos' cc_name++ _otherwise -> panic "mkTickish: bad source span!"+++allocBinTickBox :: (Bool -> BoxLabel) -> SrcSpan -> TM (HsExpr Id)+ -> TM (LHsExpr Id)+allocBinTickBox boxLabel pos m = do+ env <- getEnv+ case tickishType env of+ HpcTicks -> do e <- liftM (L pos) m+ ifGoodTickSrcSpan pos+ (mkBinTickBoxHpc boxLabel pos e)+ (return e)+ _other -> allocTickBox (ExpBox False) False False pos m++mkBinTickBoxHpc :: (Bool -> BoxLabel) -> SrcSpan -> LHsExpr Id+ -> TM (LHsExpr Id)+mkBinTickBoxHpc boxLabel pos e =+ TM $ \ env st ->+ let meT = (pos,declPath env, [],boxLabel True)+ meF = (pos,declPath env, [],boxLabel False)+ meE = (pos,declPath env, [],ExpBox False)+ c = tickBoxCount st+ mes = mixEntries st+ in+ ( L pos $ HsTick (HpcTick (this_mod env) c) $ L pos $ HsBinTick (c+1) (c+2) e+ -- notice that F and T are reversed,+ -- because we are building the list in+ -- reverse...+ , noFVs+ , st {tickBoxCount=c+3 , mixEntries=meF:meT:meE:mes}+ )++mkHpcPos :: SrcSpan -> HpcPos+mkHpcPos pos@(RealSrcSpan s)+ | isGoodSrcSpan' pos = toHpcPos (srcSpanStartLine s,+ srcSpanStartCol s,+ srcSpanEndLine s,+ srcSpanEndCol s - 1)+ -- the end column of a SrcSpan is one+ -- greater than the last column of the+ -- span (see SrcLoc), whereas HPC+ -- expects to the column range to be+ -- inclusive, hence we subtract one above.+mkHpcPos _ = panic "bad source span; expected such spans to be filtered out"++hpcSrcSpan :: SrcSpan+hpcSrcSpan = mkGeneralSrcSpan (fsLit "Haskell Program Coverage internals")++matchesOneOfMany :: [LMatch Id body] -> Bool+matchesOneOfMany lmatches = sum (map matchCount lmatches) > 1+ where+ matchCount (L _ (Match _ _pats _ty (GRHSs grhss _binds))) = length grhss++type MixEntry_ = (SrcSpan, [String], [OccName], BoxLabel)++-- For the hash value, we hash everything: the file name,+-- the timestamp of the original source file, the tab stop,+-- and the mix entries. We cheat, and hash the show'd string.+-- This hash only has to be hashed at Mix creation time,+-- and is for sanity checking only.++mixHash :: FilePath -> UTCTime -> Int -> [MixEntry] -> Int+mixHash file tm tabstop entries = fromIntegral $ hashString+ (show $ Mix file tm 0 tabstop entries)++{-+************************************************************************+* *+* initialisation+* *+************************************************************************++Each module compiled with -fhpc declares an initialisation function of+the form `hpc_init_<module>()`, which is emitted into the _stub.c file+and annotated with __attribute__((constructor)) so that it gets+executed at startup time.++The function's purpose is to call hs_hpc_module to register this+module with the RTS, and it looks something like this:++static void hpc_init_Main(void) __attribute__((constructor));+static void hpc_init_Main(void)+{extern StgWord64 _hpc_tickboxes_Main_hpc[];+ hs_hpc_module("Main",8,1150288664,_hpc_tickboxes_Main_hpc);}+-}++hpcInitCode :: Module -> HpcInfo -> SDoc+hpcInitCode _ (NoHpcInfo {}) = Outputable.empty+hpcInitCode this_mod (HpcInfo tickCount hashNo)+ = vcat+ [ text "static void hpc_init_" <> ppr this_mod+ <> text "(void) __attribute__((constructor));"+ , text "static void hpc_init_" <> ppr this_mod <> text "(void)"+ , braces (vcat [+ text "extern StgWord64 " <> tickboxes <>+ text "[]" <> semi,+ text "hs_hpc_module" <>+ parens (hcat (punctuate comma [+ doubleQuotes full_name_str,+ int tickCount, -- really StgWord32+ int hashNo, -- really StgWord32+ tickboxes+ ])) <> semi+ ])+ ]+ where+ tickboxes = ppr (mkHpcTicksLabel $ this_mod)++ module_name = hcat (map (text.charToC) $+ bytesFS (moduleNameFS (Module.moduleName this_mod)))+ package_name = hcat (map (text.charToC) $+ bytesFS (unitIdFS (moduleUnitId this_mod)))+ full_name_str+ | moduleUnitId this_mod == mainUnitId+ = module_name+ | otherwise+ = package_name <> char '/' <> module_name
+ deSugar/Desugar.hs view
@@ -0,0 +1,567 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++The Desugarer: turning HsSyn into Core.+-}++{-# LANGUAGE CPP #-}++module Desugar (+ -- * Desugaring operations+ deSugar, deSugarExpr+ ) where++#include "HsVersions.h"++import DsUsage+import DynFlags+import HscTypes+import HsSyn+import TcRnTypes+import TcRnMonad ( finalSafeMode, fixSafeInstances )+import TcRnDriver ( runTcInteractive )+import Id+import Name+import Type+import InstEnv+import Class+import Avail+import CoreSyn+import CoreFVs ( exprsSomeFreeVarsList )+import CoreOpt ( simpleOptPgm, simpleOptExpr )+import PprCore+import DsMonad+import DsExpr+import DsBinds+import DsForeign+import PrelNames ( coercibleTyConKey )+import TysPrim ( eqReprPrimTyCon )+import Unique ( hasKey )+import Coercion ( mkCoVarCo )+import TysWiredIn ( coercibleDataCon )+import DataCon ( dataConWrapId )+import MkCore ( mkCoreLet )+import Module+import NameSet+import NameEnv+import Rules+import BasicTypes ( Activation(.. ), competesWith, pprRuleName )+import CoreMonad ( CoreToDo(..) )+import CoreLint ( endPassIO )+import VarSet+import FastString+import ErrUtils+import Outputable+import SrcLoc+import Coverage+import Util+import MonadUtils+import OrdList++import Data.List+import Data.IORef+import Control.Monad( when )++{-+************************************************************************+* *+* The main function: deSugar+* *+************************************************************************+-}++-- | Main entry point to the desugarer.+deSugar :: HscEnv -> ModLocation -> TcGblEnv -> IO (Messages, Maybe ModGuts)+-- Can modify PCS by faulting in more declarations++deSugar hsc_env+ mod_loc+ tcg_env@(TcGblEnv { tcg_mod = id_mod,+ tcg_semantic_mod = mod,+ tcg_src = hsc_src,+ tcg_type_env = type_env,+ tcg_imports = imports,+ tcg_exports = exports,+ tcg_keep = keep_var,+ tcg_th_splice_used = tc_splice_used,+ tcg_rdr_env = rdr_env,+ tcg_fix_env = fix_env,+ tcg_inst_env = inst_env,+ tcg_fam_inst_env = fam_inst_env,+ tcg_merged = merged,+ tcg_warns = warns,+ tcg_anns = anns,+ tcg_binds = binds,+ tcg_imp_specs = imp_specs,+ tcg_dependent_files = dependent_files,+ tcg_ev_binds = ev_binds,+ tcg_th_foreign_files = th_foreign_files_var,+ tcg_fords = fords,+ tcg_rules = rules,+ tcg_vects = vects,+ tcg_patsyns = patsyns,+ tcg_tcs = tcs,+ tcg_insts = insts,+ tcg_fam_insts = fam_insts,+ tcg_hpc = other_hpc_info,+ tcg_complete_matches = complete_matches+ })++ = do { let dflags = hsc_dflags hsc_env+ print_unqual = mkPrintUnqualified dflags rdr_env+ ; withTiming (pure dflags)+ (text "Desugar"<+>brackets (ppr mod))+ (const ()) $+ do { -- Desugar the program+ ; let export_set = availsToNameSet exports+ target = hscTarget dflags+ hpcInfo = emptyHpcInfo other_hpc_info++ ; (binds_cvr, ds_hpc_info, modBreaks)+ <- if not (isHsBootOrSig hsc_src)+ then addTicksToBinds hsc_env mod mod_loc+ export_set (typeEnvTyCons type_env) binds+ else return (binds, hpcInfo, Nothing)+ ; (msgs, mb_res) <- initDs hsc_env tcg_env $+ do { ds_ev_binds <- dsEvBinds ev_binds+ ; core_prs <- dsTopLHsBinds binds_cvr+ ; (spec_prs, spec_rules) <- dsImpSpecs imp_specs+ ; (ds_fords, foreign_prs) <- dsForeigns fords+ ; ds_rules <- mapMaybeM dsRule rules+ ; ds_vects <- mapM dsVect vects+ ; let hpc_init+ | gopt Opt_Hpc dflags = hpcInitCode mod ds_hpc_info+ | otherwise = empty+ ; return ( ds_ev_binds+ , foreign_prs `appOL` core_prs `appOL` spec_prs+ , spec_rules ++ ds_rules, ds_vects+ , ds_fords `appendStubC` hpc_init) }++ ; case mb_res of {+ Nothing -> return (msgs, Nothing) ;+ Just (ds_ev_binds, all_prs, all_rules, vects0, ds_fords) ->++ do { -- Add export flags to bindings+ keep_alive <- readIORef keep_var+ ; let (rules_for_locals, rules_for_imps) = partition isLocalRule all_rules+ final_prs = addExportFlagsAndRules target export_set keep_alive+ rules_for_locals (fromOL all_prs)++ final_pgm = combineEvBinds ds_ev_binds final_prs+ -- Notice that we put the whole lot in a big Rec, even the foreign binds+ -- When compiling PrelFloat, which defines data Float = F# Float#+ -- we want F# to be in scope in the foreign marshalling code!+ -- You might think it doesn't matter, but the simplifier brings all top-level+ -- things into the in-scope set before simplifying; so we get no unfolding for F#!++#ifdef DEBUG+ -- Debug only as pre-simple-optimisation program may be really big+ ; endPassIO hsc_env print_unqual CoreDesugar final_pgm rules_for_imps+#endif+ ; (ds_binds, ds_rules_for_imps, ds_vects)+ <- simpleOptPgm dflags mod final_pgm rules_for_imps vects0+ -- The simpleOptPgm gets rid of type+ -- bindings plus any stupid dead code++ ; endPassIO hsc_env print_unqual CoreDesugarOpt ds_binds ds_rules_for_imps++ ; let used_names = mkUsedNames tcg_env+ ; deps <- mkDependencies tcg_env++ ; used_th <- readIORef tc_splice_used+ ; dep_files <- readIORef dependent_files+ ; safe_mode <- finalSafeMode dflags tcg_env+ ; usages <- mkUsageInfo hsc_env mod (imp_mods imports) used_names dep_files merged+ -- id_mod /= mod when we are processing an hsig, but hsigs+ -- never desugared and compiled (there's no code!)+ -- Consequently, this should hold for any ModGuts that make+ -- past desugaring. See Note [Identity versus semantic module].+ ; MASSERT( id_mod == mod )++ ; foreign_files <- readIORef th_foreign_files_var++ ; let mod_guts = ModGuts {+ mg_module = mod,+ mg_hsc_src = hsc_src,+ mg_loc = mkFileSrcSpan mod_loc,+ mg_exports = exports,+ mg_usages = usages,+ mg_deps = deps,+ mg_used_th = used_th,+ mg_rdr_env = rdr_env,+ mg_fix_env = fix_env,+ mg_warns = warns,+ mg_anns = anns,+ mg_tcs = tcs,+ mg_insts = fixSafeInstances safe_mode insts,+ mg_fam_insts = fam_insts,+ mg_inst_env = inst_env,+ mg_fam_inst_env = fam_inst_env,+ mg_patsyns = patsyns,+ mg_rules = ds_rules_for_imps,+ mg_binds = ds_binds,+ mg_foreign = ds_fords,+ mg_foreign_files = foreign_files,+ mg_hpc_info = ds_hpc_info,+ mg_modBreaks = modBreaks,+ mg_vect_decls = ds_vects,+ mg_vect_info = noVectInfo,+ mg_safe_haskell = safe_mode,+ mg_trust_pkg = imp_trust_own_pkg imports,+ mg_complete_sigs = complete_matches+ }+ ; return (msgs, Just mod_guts)+ }}}}++mkFileSrcSpan :: ModLocation -> SrcSpan+mkFileSrcSpan mod_loc+ = case ml_hs_file mod_loc of+ Just file_path -> mkGeneralSrcSpan (mkFastString file_path)+ Nothing -> interactiveSrcSpan -- Presumably++dsImpSpecs :: [LTcSpecPrag] -> DsM (OrdList (Id,CoreExpr), [CoreRule])+dsImpSpecs imp_specs+ = do { spec_prs <- mapMaybeM (dsSpec Nothing) imp_specs+ ; let (spec_binds, spec_rules) = unzip spec_prs+ ; return (concatOL spec_binds, spec_rules) }++combineEvBinds :: [CoreBind] -> [(Id,CoreExpr)] -> [CoreBind]+-- Top-level bindings can include coercion bindings, but not via superclasses+-- See Note [Top-level evidence]+combineEvBinds [] val_prs+ = [Rec val_prs]+combineEvBinds (NonRec b r : bs) val_prs+ | isId b = combineEvBinds bs ((b,r):val_prs)+ | otherwise = NonRec b r : combineEvBinds bs val_prs+combineEvBinds (Rec prs : bs) val_prs+ = combineEvBinds bs (prs ++ val_prs)++{-+Note [Top-level evidence]+~~~~~~~~~~~~~~~~~~~~~~~~~+Top-level evidence bindings may be mutually recursive with the top-level value+bindings, so we must put those in a Rec. But we can't put them *all* in a Rec+because the occurrence analyser doesn't teke account of type/coercion variables+when computing dependencies.++So we pull out the type/coercion variables (which are in dependency order),+and Rec the rest.+-}++deSugarExpr :: HscEnv -> LHsExpr Id -> IO (Messages, Maybe CoreExpr)++deSugarExpr hsc_env tc_expr = do {+ let dflags = hsc_dflags hsc_env++ ; showPass dflags "Desugar"++ -- Do desugaring+ ; (msgs, mb_core_expr) <- runTcInteractive hsc_env $ initDsTc $+ dsLExpr tc_expr++ ; case mb_core_expr of+ Nothing -> return ()+ Just expr -> dumpIfSet_dyn dflags Opt_D_dump_ds "Desugared"+ (pprCoreExpr expr)++ ; return (msgs, mb_core_expr) }++{-+************************************************************************+* *+* Add rules and export flags to binders+* *+************************************************************************+-}++addExportFlagsAndRules+ :: HscTarget -> NameSet -> NameSet -> [CoreRule]+ -> [(Id, t)] -> [(Id, t)]+addExportFlagsAndRules target exports keep_alive rules prs+ = mapFst add_one prs+ where+ add_one bndr = add_rules name (add_export name bndr)+ where+ name = idName bndr++ ---------- Rules --------+ -- See Note [Attach rules to local ids]+ -- NB: the binder might have some existing rules,+ -- arising from specialisation pragmas+ add_rules name bndr+ | Just rules <- lookupNameEnv rule_base name+ = bndr `addIdSpecialisations` rules+ | otherwise+ = bndr+ rule_base = extendRuleBaseList emptyRuleBase rules++ ---------- Export flag --------+ -- See Note [Adding export flags]+ add_export name bndr+ | dont_discard name = setIdExported bndr+ | otherwise = bndr++ dont_discard :: Name -> Bool+ dont_discard name = is_exported name+ || name `elemNameSet` keep_alive++ -- In interactive mode, we don't want to discard any top-level+ -- entities at all (eg. do not inline them away during+ -- simplification), and retain them all in the TypeEnv so they are+ -- available from the command line.+ --+ -- isExternalName separates the user-defined top-level names from those+ -- introduced by the type checker.+ is_exported :: Name -> Bool+ is_exported | targetRetainsAllBindings target = isExternalName+ | otherwise = (`elemNameSet` exports)++{-+Note [Adding export flags]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Set the no-discard flag if either+ a) the Id is exported+ b) it's mentioned in the RHS of an orphan rule+ c) it's in the keep-alive set++It means that the binding won't be discarded EVEN if the binding+ends up being trivial (v = w) -- the simplifier would usually just+substitute w for v throughout, but we don't apply the substitution to+the rules (maybe we should?), so this substitution would make the rule+bogus.++You might wonder why exported Ids aren't already marked as such;+it's just because the type checker is rather busy already and+I didn't want to pass in yet another mapping.++Note [Attach rules to local ids]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Find the rules for locally-defined Ids; then we can attach them+to the binders in the top-level bindings++Reason+ - It makes the rules easier to look up+ - It means that transformation rules and specialisations for+ locally defined Ids are handled uniformly+ - It keeps alive things that are referred to only from a rule+ (the occurrence analyser knows about rules attached to Ids)+ - It makes sure that, when we apply a rule, the free vars+ of the RHS are more likely to be in scope+ - The imported rules are carried in the in-scope set+ which is extended on each iteration by the new wave of+ local binders; any rules which aren't on the binding will+ thereby get dropped+++************************************************************************+* *+* Desugaring transformation rules+* *+************************************************************************+-}++dsRule :: LRuleDecl Id -> DsM (Maybe CoreRule)+dsRule (L loc (HsRule name rule_act vars lhs _tv_lhs rhs _fv_rhs))+ = putSrcSpanDs loc $+ do { let bndrs' = [var | L _ (RuleBndr (L _ var)) <- vars]++ ; lhs' <- unsetGOptM Opt_EnableRewriteRules $+ unsetWOptM Opt_WarnIdentities $+ dsLExpr lhs -- Note [Desugaring RULE left hand sides]++ ; rhs' <- dsLExpr rhs+ ; this_mod <- getModule++ ; (bndrs'', lhs'', rhs'') <- unfold_coerce bndrs' lhs' rhs'++ -- Substitute the dict bindings eagerly,+ -- and take the body apart into a (f args) form+ ; case decomposeRuleLhs bndrs'' lhs'' of {+ Left msg -> do { warnDs NoReason msg; return Nothing } ;+ Right (final_bndrs, fn_id, args) -> do++ { let is_local = isLocalId fn_id+ -- NB: isLocalId is False of implicit Ids. This is good because+ -- we don't want to attach rules to the bindings of implicit Ids,+ -- because they don't show up in the bindings until just before code gen+ fn_name = idName fn_id+ final_rhs = simpleOptExpr rhs'' -- De-crap it+ rule_name = snd (unLoc name)+ final_bndrs_set = mkVarSet final_bndrs+ arg_ids = filterOut (`elemVarSet` final_bndrs_set) $+ exprsSomeFreeVarsList isId args++ ; dflags <- getDynFlags+ ; rule <- dsMkUserRule this_mod is_local+ rule_name rule_act fn_name final_bndrs args+ final_rhs+ ; when (wopt Opt_WarnInlineRuleShadowing dflags) $+ warnRuleShadowing rule_name rule_act fn_id arg_ids++ ; return (Just rule)+ } } }+++warnRuleShadowing :: RuleName -> Activation -> Id -> [Id] -> DsM ()+-- See Note [Rules and inlining/other rules]+warnRuleShadowing rule_name rule_act fn_id arg_ids+ = do { check False fn_id -- We often have multiple rules for the same Id in a+ -- module. Maybe we should check that they don't overlap+ -- but currently we don't+ ; mapM_ (check True) arg_ids }+ where+ check check_rules_too lhs_id+ | isLocalId lhs_id || canUnfold (idUnfolding lhs_id)+ -- If imported with no unfolding, no worries+ , idInlineActivation lhs_id `competesWith` rule_act+ = warnDs (Reason Opt_WarnInlineRuleShadowing)+ (vcat [ hang (text "Rule" <+> pprRuleName rule_name+ <+> text "may never fire")+ 2 (text "because" <+> quotes (ppr lhs_id)+ <+> text "might inline first")+ , text "Probable fix: add an INLINE[n] or NOINLINE[n] pragma for"+ <+> quotes (ppr lhs_id)+ , ifPprDebug (ppr (idInlineActivation lhs_id) $$ ppr rule_act) ])++ | check_rules_too+ , bad_rule : _ <- get_bad_rules lhs_id+ = warnDs (Reason Opt_WarnInlineRuleShadowing)+ (vcat [ hang (text "Rule" <+> pprRuleName rule_name+ <+> text "may never fire")+ 2 (text "because rule" <+> pprRuleName (ruleName bad_rule)+ <+> text "for"<+> quotes (ppr lhs_id)+ <+> text "might fire first")+ , text "Probable fix: add phase [n] or [~n] to the competing rule"+ , ifPprDebug (ppr bad_rule) ])++ | otherwise+ = return ()++ get_bad_rules lhs_id+ = [ rule | rule <- idCoreRules lhs_id+ , ruleActivation rule `competesWith` rule_act ]++-- See Note [Desugaring coerce as cast]+unfold_coerce :: [Id] -> CoreExpr -> CoreExpr -> DsM ([Var], CoreExpr, CoreExpr)+unfold_coerce bndrs lhs rhs = do+ (bndrs', wrap) <- go bndrs+ return (bndrs', wrap lhs, wrap rhs)+ where+ go :: [Id] -> DsM ([Id], CoreExpr -> CoreExpr)+ go [] = return ([], id)+ go (v:vs)+ | Just (tc, [k, t1, t2]) <- splitTyConApp_maybe (idType v)+ , tc `hasKey` coercibleTyConKey = do+ u <- newUnique++ let ty' = mkTyConApp eqReprPrimTyCon [k, k, t1, t2]+ v' = mkLocalCoVar+ (mkDerivedInternalName mkRepEqOcc u (getName v)) ty'+ box = Var (dataConWrapId coercibleDataCon) `mkTyApps`+ [k, t1, t2] `App`+ Coercion (mkCoVarCo v')++ (bndrs, wrap) <- go vs+ return (v':bndrs, mkCoreLet (NonRec v box) . wrap)+ | otherwise = do+ (bndrs,wrap) <- go vs+ return (v:bndrs, wrap)++{- Note [Desugaring RULE left hand sides]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For the LHS of a RULE we do *not* want to desugar+ [x] to build (\cn. x `c` n)+We want to leave explicit lists simply as chains+of cons's. We can achieve that slightly indirectly by+switching off EnableRewriteRules. See DsExpr.dsExplicitList.++That keeps the desugaring of list comprehensions simple too.++Nor do we want to warn of conversion identities on the LHS;+the rule is precisly to optimise them:+ {-# RULES "fromRational/id" fromRational = id :: Rational -> Rational #-}++Note [Desugaring coerce as cast]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want the user to express a rule saying roughly “mapping a coercion over a+list can be replaced by a coercion”. But the cast operator of Core (▷) cannot+be written in Haskell. So we use `coerce` for that (#2110). The user writes+ map coerce = coerce+as a RULE, and this optimizes any kind of mapped' casts away, including `map+MkNewtype`.++For that we replace any forall'ed `c :: Coercible a b` value in a RULE by+corresponding `co :: a ~#R b` and wrap the LHS and the RHS in+`let c = MkCoercible co in ...`. This is later simplified to the desired form+by simpleOptExpr (for the LHS) resp. the simplifiers (for the RHS).+See also Note [Getting the map/coerce RULE to work] in CoreSubst.++Note [Rules and inlining/other rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If you have+ f x = ...+ g x = ...+ {-# RULES "rule-for-f" forall x. f (g x) = ... #-}+then there's a good chance that in a potential rule redex+ ...f (g e)...+then 'f' or 'g' will inline befor the rule can fire. Solution: add an+INLINE [n] or NOINLINE [n] pragma to 'f' and 'g'.++Note that this applies to all the free variables on the LHS, both the+main function and things in its arguments.++We also check if there are Ids on the LHS that have competing RULES.+In the above example, suppose we had+ {-# RULES "rule-for-g" forally. g [y] = ... #-}+Then "rule-for-f" and "rule-for-g" would compete. Better to add phase+control, so "rule-for-f" has a chance to fire before "rule-for-g" becomes+active; or perhpas after "rule-for-g" has become inactive. This is checked+by 'competesWith'++Class methods have a built-in RULE to select the method from the dictionary,+so you can't change the phase on this. That makes id very dubious to+match on class methods in RULE lhs's. See Trac #10595. I'm not happy+about this. For example in Control.Arrow we have++{-# RULES "compose/arr" forall f g .+ (arr f) . (arr g) = arr (f . g) #-}++and similar, which will elicit exactly these warnings, and risk never+firing. But it's not clear what to do instead. We could make the+class methocd rules inactive in phase 2, but that would delay when+subsequent transformations could fire.+++************************************************************************+* *+* Desugaring vectorisation declarations+* *+************************************************************************+-}++dsVect :: LVectDecl Id -> DsM CoreVect+dsVect (L loc (HsVect _ (L _ v) rhs))+ = putSrcSpanDs loc $+ do { rhs' <- dsLExpr rhs+ ; return $ Vect v rhs'+ }+dsVect (L _loc (HsNoVect _ (L _ v)))+ = return $ NoVect v+dsVect (L _loc (HsVectTypeOut isScalar tycon rhs_tycon))+ = return $ VectType isScalar tycon' rhs_tycon+ where+ tycon' | Just ty <- coreView $ mkTyConTy tycon+ , (tycon', []) <- splitTyConApp ty = tycon'+ | otherwise = tycon+dsVect vd@(L _ (HsVectTypeIn _ _ _ _))+ = pprPanic "Desugar.dsVect: unexpected 'HsVectTypeIn'" (ppr vd)+dsVect (L _loc (HsVectClassOut cls))+ = return $ VectClass (classTyCon cls)+dsVect vc@(L _ (HsVectClassIn _ _))+ = pprPanic "Desugar.dsVect: unexpected 'HsVectClassIn'" (ppr vc)+dsVect (L _loc (HsVectInstOut inst))+ = return $ VectInst (instanceDFunId inst)+dsVect vi@(L _ (HsVectInstIn _))+ = pprPanic "Desugar.dsVect: unexpected 'HsVectInstIn'" (ppr vi)
+ deSugar/DsArrows.hs view
@@ -0,0 +1,1230 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Desugaring arrow commands+-}++{-# LANGUAGE CPP #-}++module DsArrows ( dsProcExpr ) where++#include "HsVersions.h"++import Match+import DsUtils+import DsMonad++import HsSyn hiding (collectPatBinders, collectPatsBinders, collectLStmtsBinders, collectLStmtBinders, collectStmtBinders )+import TcHsSyn+import qualified HsUtils++-- NB: The desugarer, which straddles the source and Core worlds, sometimes+-- needs to see source types (newtypes etc), and sometimes not+-- So WATCH OUT; check each use of split*Ty functions.+-- Sigh. This is a pain.++import {-# SOURCE #-} DsExpr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds, dsSyntaxExpr )++import TcType+import Type ( splitPiTy )+import TcEvidence+import CoreSyn+import CoreFVs+import CoreUtils+import MkCore+import DsBinds (dsHsWrapper)++import Name+import Var+import Id+import ConLike+import TysWiredIn+import BasicTypes+import PrelNames+import Outputable+import Bag+import VarSet+import SrcLoc+import ListSetOps( assocMaybe )+import Data.List+import Util+import UniqDFM+import UniqSet++data DsCmdEnv = DsCmdEnv {+ arr_id, compose_id, first_id, app_id, choice_id, loop_id :: CoreExpr+ }++mkCmdEnv :: CmdSyntaxTable Id -> DsM ([CoreBind], DsCmdEnv)+-- See Note [CmdSyntaxTable] in HsExpr+mkCmdEnv tc_meths+ = do { (meth_binds, prs) <- mapAndUnzipM mk_bind tc_meths++ -- NB: Some of these lookups might fail, but that's OK if the+ -- symbol is never used. That's why we use Maybe first and then+ -- panic. An eager panic caused trouble in typecheck/should_compile/tc192+ ; let the_arr_id = assocMaybe prs arrAName+ the_compose_id = assocMaybe prs composeAName+ the_first_id = assocMaybe prs firstAName+ the_app_id = assocMaybe prs appAName+ 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),+ first_id = Var (unmaybe the_first_id firstAName),+ app_id = Var (unmaybe the_app_id appAName),+ choice_id = Var (unmaybe the_choice_id choiceAName),+ loop_id = Var (unmaybe the_loop_id loopAName)+ }) }+ where+ mk_bind (std_name, expr)+ = do { rhs <- dsExpr expr+ ; id <- newSysLocalDs (exprType rhs) -- no check needed; these are functions+ ; return (NonRec id rhs, (std_name, id)) }++ 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))+ (text "In the result of the function" <+> quotes (ppr 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]++-- (>>>) :: forall b c d. a b c -> a c d -> a b d+do_compose :: DsCmdEnv -> Type -> Type -> Type ->+ CoreExpr -> CoreExpr -> CoreExpr+do_compose ids b_ty c_ty d_ty f g+ = mkApps (compose_id ids) [Type b_ty, Type c_ty, Type d_ty, f, g]++-- first :: forall b c d. a b c -> a (b,d) (c,d)+do_first :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr+do_first ids b_ty c_ty d_ty f+ = mkApps (first_id ids) [Type b_ty, Type c_ty, Type d_ty, f]++-- app :: forall b c. a (a b c, b) c+do_app :: DsCmdEnv -> Type -> Type -> CoreExpr+do_app ids b_ty c_ty = mkApps (app_id ids) [Type b_ty, Type c_ty]++-- (|||) :: forall b d c. a b d -> a c d -> a (Either b c) d+-- note the swapping of d and c+do_choice :: DsCmdEnv -> Type -> Type -> Type ->+ CoreExpr -> CoreExpr -> CoreExpr+do_choice ids b_ty c_ty d_ty f g+ = mkApps (choice_id ids) [Type b_ty, Type d_ty, Type c_ty, f, g]++-- loop :: forall b d c. a (b,d) (c,d) -> a b c+-- note the swapping of d and c+do_loop :: DsCmdEnv -> Type -> Type -> Type -> CoreExpr -> CoreExpr+do_loop ids b_ty c_ty d_ty f+ = mkApps (loop_id ids) [Type b_ty, Type d_ty, Type c_ty, f]++-- premap :: forall b c d. (b -> c) -> a c d -> a b d+-- premap f g = arr f >>> g+do_premap :: DsCmdEnv -> Type -> Type -> Type ->+ CoreExpr -> CoreExpr -> CoreExpr+do_premap ids b_ty c_ty d_ty f g+ = do_compose ids b_ty c_ty d_ty (do_arr ids b_ty c_ty f) g++mkFailExpr :: HsMatchContext Id -> Type -> DsM CoreExpr+mkFailExpr ctxt ty+ = mkErrorAppDs pAT_ERROR_ID ty (matchContextErrString ctxt)++-- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> a+mkFstExpr :: Type -> Type -> DsM CoreExpr+mkFstExpr a_ty b_ty = do+ a_var <- newSysLocalDs a_ty+ b_var <- newSysLocalDs b_ty+ pair_var <- newSysLocalDs (mkCorePairTy a_ty b_ty)+ return (Lam pair_var+ (coreCasePair pair_var a_var b_var (Var a_var)))++-- construct CoreExpr for \ (a :: a_ty, b :: b_ty) -> b+mkSndExpr :: Type -> Type -> DsM CoreExpr+mkSndExpr a_ty b_ty = do+ a_var <- newSysLocalDs a_ty+ b_var <- newSysLocalDs b_ty+ pair_var <- newSysLocalDs (mkCorePairTy a_ty b_ty)+ return (Lam pair_var+ (coreCasePair pair_var a_var b_var (Var b_var)))++{-+Build case analysis of a tuple. This cannot be done in the DsM monad,+because the list of variables is typically not yet defined.+-}++-- coreCaseTuple [u1..] v [x1..xn] body+-- = case v of v { (x1, .., xn) -> body }+-- But the matching may be nested if the tuple is very big++coreCaseTuple :: UniqSupply -> Id -> [Id] -> CoreExpr -> CoreExpr+coreCaseTuple uniqs scrut_var vars body+ = mkTupleCase uniqs vars body scrut_var (Var scrut_var)++coreCasePair :: Id -> Id -> Id -> CoreExpr -> CoreExpr+coreCasePair scrut_var var1 var2 body+ = Case (Var scrut_var) scrut_var (exprType body)+ [(DataAlt (tupleDataCon Boxed 2), [var1, var2], body)]++mkCorePairTy :: Type -> Type -> Type+mkCorePairTy t1 t2 = mkBoxedTupleTy [t1, t2]++mkCorePairExpr :: CoreExpr -> CoreExpr -> CoreExpr+mkCorePairExpr e1 e2 = mkCoreTup [e1, e2]++mkCoreUnitExpr :: CoreExpr+mkCoreUnitExpr = mkCoreTup []++{-+The input is divided into a local environment, which is a flat tuple+(unless it's too big), and a stack, which is a right-nested pair.+In general, the input has the form++ ((x1,...,xn), (s1,...(sk,())...))++where xi are the environment values, and si the ones on the stack,+with s1 being the "top", the first one to be matched with a lambda.+-}++envStackType :: [Id] -> Type -> Type+envStackType ids stack_ty = mkCorePairTy (mkBigCoreVarTupTy ids) stack_ty++-- splitTypeAt n (t1,... (tn,t)...) = ([t1, ..., tn], t)+splitTypeAt :: Int -> Type -> ([Type], Type)+splitTypeAt n ty+ | n == 0 = ([], ty)+ | otherwise = case tcTyConAppArgs ty of+ [t, ty'] -> let (ts, ty_r) = splitTypeAt (n-1) ty' in (t:ts, ty_r)+ _ -> pprPanic "splitTypeAt" (ppr ty)++----------------------------------------------+-- buildEnvStack+--+-- ((x1,...,xn),stk)++buildEnvStack :: [Id] -> Id -> CoreExpr+buildEnvStack env_ids stack_id+ = mkCorePairExpr (mkBigCoreVarTup env_ids) (Var stack_id)++----------------------------------------------+-- matchEnvStack+--+-- \ ((x1,...,xn),stk) -> body+-- =>+-- \ pair ->+-- case pair of (tup,stk) ->+-- case tup of (x1,...,xn) ->+-- body++matchEnvStack :: [Id] -- x1..xn+ -> Id -- stk+ -> CoreExpr -- e+ -> DsM CoreExpr+matchEnvStack env_ids stack_id body = do+ uniqs <- newUniqueSupply+ tup_var <- newSysLocalDs (mkBigCoreVarTupTy env_ids)+ let match_env = coreCaseTuple uniqs tup_var env_ids body+ pair_id <- newSysLocalDs (mkCorePairTy (idType tup_var) (idType stack_id))+ return (Lam pair_id (coreCasePair pair_id tup_var stack_id match_env))++----------------------------------------------+-- matchEnv+--+-- \ (x1,...,xn) -> body+-- =>+-- \ tup ->+-- case tup of (x1,...,xn) ->+-- body++matchEnv :: [Id] -- x1..xn+ -> CoreExpr -- e+ -> DsM CoreExpr+matchEnv env_ids body = do+ uniqs <- newUniqueSupply+ tup_id <- newSysLocalDs (mkBigCoreVarTupTy env_ids)+ return (Lam tup_id (coreCaseTuple uniqs tup_id env_ids body))++----------------------------------------------+-- matchVarStack+--+-- case (x1, ...(xn, s)...) -> e+-- =>+-- case z0 of (x1,z1) ->+-- case zn-1 of (xn,s) ->+-- e+matchVarStack :: [Id] -> Id -> CoreExpr -> DsM (Id, CoreExpr)+matchVarStack [] stack_id body = return (stack_id, body)+matchVarStack (param_id:param_ids) stack_id body = do+ (tail_id, tail_code) <- matchVarStack param_ids stack_id body+ pair_id <- newSysLocalDs (mkCorePairTy (idType param_id) (idType tail_id))+ return (pair_id, coreCasePair pair_id param_id tail_id tail_code)++mkHsEnvStackExpr :: [Id] -> Id -> LHsExpr Id+mkHsEnvStackExpr env_ids stack_id+ = mkLHsTupleExpr [mkLHsVarTuple env_ids, nlHsVar stack_id]++-- Translation of arrow abstraction++-- D; xs |-a c : () --> t' ---> c'+-- --------------------------+-- D |- proc p -> c :: a t t' ---> premap (\ p -> ((xs),())) c'+--+-- where (xs) is the tuple of variables bound by p++dsProcExpr+ :: LPat Id+ -> LHsCmdTop Id+ -> DsM CoreExpr+dsProcExpr pat (L _ (HsCmdTop cmd _unitTy cmd_ty ids)) = do+ (meth_binds, meth_ids) <- mkCmdEnv ids+ let locals = mkVarSet (collectPatBinders pat)+ (core_cmd, _free_vars, env_ids) <- dsfixCmd meth_ids locals unitTy cmd_ty cmd+ 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+ var <- selectSimpleMatchVarL pat+ match_code <- matchSimply (Var var) 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)+ core_cmd+ return (mkLets meth_binds proc_code)++{-+Translation of a command judgement of the form++ D; xs |-a c : stk --> t++to an expression e such that++ D |- e :: a (xs, stk) t+-}++dsLCmd :: DsCmdEnv -> IdSet -> Type -> Type -> LHsCmd Id -> [Id]+ -> DsM (CoreExpr, DIdSet)+dsLCmd ids local_vars stk_ty res_ty cmd env_ids+ = dsCmd ids local_vars stk_ty res_ty (unLoc cmd) env_ids++dsCmd :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this command+ -> Type -- type of the stack (right-nested tuple)+ -> Type -- return type of the command+ -> HsCmd Id -- command to desugar+ -> [Id] -- list of vars in the input to this command+ -- This is typically fed back,+ -- so don't pull on it too early+ -> DsM (CoreExpr, -- desugared expression+ DIdSet) -- subset of local vars that occur free++-- D |- fun :: a t1 t2+-- D, xs |- arg :: t1+-- -----------------------------+-- D; xs |-a fun -< arg : stk --> t2+--+-- ---> premap (\ ((xs), _stk) -> arg) fun++dsCmd ids local_vars stack_ty res_ty+ (HsCmdArrApp arrow arg arrow_ty HsFirstOrderApp _)+ env_ids = do+ let+ (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty+ (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty+ core_arrow <- dsLExprNoLP arrow+ core_arg <- dsLExpr arg+ stack_id <- newSysLocalDs stack_ty+ core_make_arg <- matchEnvStack env_ids stack_id core_arg+ return (do_premap ids+ (envStackType env_ids stack_ty)+ arg_ty+ res_ty+ core_make_arg+ core_arrow,+ exprFreeIdsDSet core_arg `udfmIntersectUFM` (getUniqSet local_vars))++-- D, xs |- fun :: a t1 t2+-- D, xs |- arg :: t1+-- ------------------------------+-- D; xs |-a fun -<< arg : stk --> t2+--+-- ---> premap (\ ((xs), _stk) -> (fun, arg)) app++dsCmd ids local_vars stack_ty res_ty+ (HsCmdArrApp arrow arg arrow_ty HsHigherOrderApp _)+ env_ids = do+ let+ (a_arg_ty, _res_ty') = tcSplitAppTy arrow_ty+ (_a_ty, arg_ty) = tcSplitAppTy a_arg_ty++ core_arrow <- dsLExpr arrow+ core_arg <- dsLExpr arg+ stack_id <- newSysLocalDs stack_ty+ core_make_pair <- matchEnvStack env_ids stack_id+ (mkCorePairExpr core_arrow core_arg)++ return (do_premap ids+ (envStackType env_ids stack_ty)+ (mkCorePairTy arrow_ty arg_ty)+ res_ty+ core_make_pair+ (do_app ids arg_ty res_ty),+ (exprsFreeIdsDSet [core_arrow, core_arg])+ `udfmIntersectUFM` getUniqSet local_vars)++-- D; ys |-a cmd : (t,stk) --> t'+-- D, xs |- exp :: t+-- ------------------------+-- D; xs |-a cmd exp : stk --> t'+--+-- ---> premap (\ ((xs),stk) -> ((ys),(e,stk))) cmd++dsCmd ids local_vars stack_ty res_ty (HsCmdApp cmd arg) env_ids = do+ core_arg <- dsLExpr arg+ let+ arg_ty = exprType core_arg+ stack_ty' = mkCorePairTy arg_ty stack_ty+ (core_cmd, free_vars, env_ids')+ <- dsfixCmd ids local_vars stack_ty' res_ty cmd+ stack_id <- newSysLocalDs stack_ty+ arg_id <- newSysLocalDsNoLP arg_ty+ -- push the argument expression onto the stack+ let+ stack' = mkCorePairExpr (Var arg_id) (Var stack_id)+ core_body = bindNonRec arg_id core_arg+ (mkCorePairExpr (mkBigCoreVarTup env_ids') stack')++ -- match the environment and stack against the input+ core_map <- matchEnvStack env_ids stack_id core_body+ return (do_premap ids+ (envStackType env_ids stack_ty)+ (envStackType env_ids' stack_ty')+ res_ty+ core_map+ core_cmd,+ free_vars `unionDVarSet`+ (exprFreeIdsDSet core_arg `udfmIntersectUFM` getUniqSet local_vars))++-- D; ys |-a cmd : stk t'+-- -----------------------------------------------+-- D; xs |-a \ p1 ... pk -> cmd : (t1,...(tk,stk)...) t'+--+-- ---> premap (\ ((xs), (p1, ... (pk,stk)...)) -> ((ys),stk)) cmd++dsCmd ids local_vars stack_ty res_ty+ (HsCmdLam (MG { mg_alts = L _ [L _ (Match _ pats _+ (GRHSs [L _ (GRHS [] body)] _ ))] }))+ env_ids = do+ let pat_vars = mkVarSet (collectPatsBinders pats)+ let+ local_vars' = pat_vars `unionVarSet` local_vars+ (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 pat_tys+ stack_id' <- newSysLocalDs stack_ty'++ -- the expression is built from the inside out, so the actions+ -- are presented in reverse order++ let+ -- build a new environment, plus what's left of the stack+ core_expr = buildEnvStack env_ids' stack_id'+ in_ty = envStackType env_ids stack_ty+ in_ty' = envStackType env_ids' stack_ty'++ fail_expr <- mkFailExpr LambdaExpr in_ty'+ -- match the patterns against the parameters+ match_code <- matchSimplys (map Var param_ids) LambdaExpr 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+ -- match the old environment and stack against the input+ select_code <- matchEnvStack env_ids stack_id param_code+ return (do_premap ids in_ty in_ty' res_ty select_code core_body,+ free_vars `udfmMinusUFM` getUniqSet pat_vars)++dsCmd ids local_vars stack_ty res_ty (HsCmdPar cmd) env_ids+ = dsLCmd ids local_vars stack_ty res_ty cmd env_ids++-- D, xs |- e :: Bool+-- D; xs1 |-a c1 : stk --> t+-- D; xs2 |-a c2 : stk --> t+-- ----------------------------------------+-- D; xs |-a if e then c1 else c2 : stk --> t+--+-- ---> premap (\ ((xs),stk) ->+-- if e then Left ((xs1),stk) else Right ((xs2),stk))+-- (c1 ||| c2)++dsCmd ids local_vars stack_ty res_ty (HsCmdIf mb_fun cond then_cmd else_cmd)+ env_ids = do+ core_cond <- dsLExpr cond+ (core_then, fvs_then, then_ids) <- dsfixCmd ids local_vars stack_ty res_ty then_cmd+ (core_else, fvs_else, else_ids) <- dsfixCmd ids local_vars stack_ty res_ty else_cmd+ stack_id <- newSysLocalDs stack_ty+ either_con <- dsLookupTyCon eitherTyConName+ left_con <- dsLookupDataCon leftDataConName+ right_con <- dsLookupDataCon rightDataConName++ let mk_left_expr ty1 ty2 e = mkCoreConApps left_con [Type ty1, Type ty2, e]+ mk_right_expr ty1 ty2 e = mkCoreConApps right_con [Type ty1, Type ty2, e]++ in_ty = envStackType env_ids stack_ty+ then_ty = envStackType then_ids stack_ty+ else_ty = envStackType else_ids stack_ty+ sum_ty = mkTyConApp either_con [then_ty, else_ty]+ fvs_cond = exprFreeIdsDSet core_cond `udfmIntersectUFM` getUniqSet local_vars++ core_left = mk_left_expr then_ty else_ty (buildEnvStack then_ids stack_id)+ core_right = mk_right_expr then_ty else_ty (buildEnvStack else_ids stack_id)++ core_if <- case mb_fun of+ Just fun -> do { fun_apps <- dsSyntaxExpr fun [core_cond, core_left, core_right]+ ; matchEnvStack env_ids stack_id fun_apps }+ Nothing -> matchEnvStack env_ids stack_id $+ mkIfThenElse core_cond core_left core_right++ return (do_premap ids in_ty sum_ty res_ty+ core_if+ (do_choice ids then_ty else_ty res_ty core_then core_else),+ fvs_cond `unionDVarSet` fvs_then `unionDVarSet` fvs_else)++{-+Case commands are treated in much the same way as if commands+(see above) except that there are more alternatives. For example++ case e of { p1 -> c1; p2 -> c2; p3 -> c3 }++is translated to++ premap (\ ((xs)*ts) -> case e of+ p1 -> (Left (Left (xs1)*ts))+ p2 -> Left ((Right (xs2)*ts))+ p3 -> Right ((xs3)*ts))+ ((c1 ||| c2) ||| c3)++The idea is to extract the commands from the case, build a balanced tree+of choices, and replace the commands with expressions that build tagged+tuples, obtaining a case expression that can be desugared normally.+To build all this, we use triples describing segments of the list of+case bodies, containing the following fields:+ * a list of expressions of the form (Left|Right)* ((xs)*ts), to be put+ into the case replacing the commands+ * a sum type that is the common type of these expressions, and also the+ input type of the arrow+ * a CoreExpr for an arrow built by combining the translated command+ bodies with |||.+-}++dsCmd ids local_vars stack_ty res_ty+ (HsCmdCase exp (MG { mg_alts = L l matches, mg_arg_tys = arg_tys+ , mg_origin = origin }))+ env_ids = do+ stack_id <- newSysLocalDs stack_ty++ -- Extract and desugar the leaf commands in the case, building tuple+ -- expressions that will (after tagging) replace these leaves++ let+ leaves = concatMap leavesMatch matches+ make_branch (leaf, bound_vars) = do+ (core_leaf, _fvs, leaf_ids) <-+ dsfixCmd ids (bound_vars `unionVarSet` local_vars) stack_ty res_ty leaf+ return ([mkHsEnvStackExpr leaf_ids stack_id],+ envStackType leaf_ids stack_ty,+ core_leaf)++ branches <- mapM make_branch leaves+ either_con <- dsLookupTyCon eitherTyConName+ left_con <- dsLookupDataCon leftDataConName+ right_con <- dsLookupDataCon rightDataConName+ let+ left_id = HsConLikeOut (RealDataCon left_con)+ right_id = HsConLikeOut (RealDataCon right_con)+ left_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ HsWrap (mkWpTyApps [ty1, ty2]) left_id ) e+ right_expr ty1 ty2 e = noLoc $ HsApp (noLoc $ HsWrap (mkWpTyApps [ty1, ty2]) right_id) e++ -- Prefix each tuple with a distinct series of Left's and Right's,+ -- in a balanced way, keeping track of the types.++ merge_branches (builds1, in_ty1, core_exp1)+ (builds2, in_ty2, core_exp2)+ = (map (left_expr in_ty1 in_ty2) builds1 +++ map (right_expr in_ty1 in_ty2) builds2,+ mkTyConApp either_con [in_ty1, in_ty2],+ do_choice ids in_ty1 in_ty2 res_ty core_exp1 core_exp2)+ (leaves', sum_ty, core_choices) = foldb merge_branches branches++ -- Replace the commands in the case with these tagged tuples,+ -- yielding a HsExpr Id we can feed to dsExpr.++ (_, matches') = mapAccumL (replaceLeavesMatch res_ty) leaves' matches+ in_ty = envStackType env_ids stack_ty++ core_body <- dsExpr (HsCase exp (MG { mg_alts = L l matches'+ , mg_arg_tys = arg_tys+ , mg_res_ty = sum_ty, mg_origin = origin }))+ -- Note that we replace the HsCase result type by sum_ty,+ -- which is the type of matches'++ core_matches <- matchEnvStack env_ids stack_id core_body+ return (do_premap ids in_ty sum_ty res_ty core_matches core_choices,+ exprFreeIdsDSet core_body `udfmIntersectUFM` getUniqSet local_vars)++-- D; ys |-a cmd : stk --> t+-- ----------------------------------+-- D; xs |-a let binds in cmd : stk --> t+--+-- ---> premap (\ ((xs),stk) -> let binds in ((ys),stk)) c++dsCmd ids local_vars stack_ty res_ty (HsCmdLet lbinds@(L _ binds) body) env_ids = do+ let+ defined_vars = mkVarSet (collectLocalBinders binds)+ local_vars' = defined_vars `unionVarSet` local_vars++ (core_body, _free_vars, env_ids') <- dsfixCmd ids local_vars' stack_ty res_ty body+ stack_id <- newSysLocalDs stack_ty+ -- build a new environment, plus the stack, using the let bindings+ core_binds <- dsLocalBinds lbinds (buildEnvStack env_ids' stack_id)+ -- match the old environment and stack against the input+ core_map <- matchEnvStack env_ids stack_id core_binds+ return (do_premap ids+ (envStackType env_ids stack_ty)+ (envStackType env_ids' stack_ty)+ res_ty+ core_map+ core_body,+ exprFreeIdsDSet core_binds `udfmIntersectUFM` getUniqSet local_vars)++-- D; xs |-a ss : t+-- ----------------------------------+-- D; xs |-a do { ss } : () --> t+--+-- ---> premap (\ (env,stk) -> env) c++dsCmd ids local_vars stack_ty res_ty do_block@(HsCmdDo (L loc stmts) stmts_ty) env_ids = do+ putSrcSpanDs loc $+ dsNoLevPoly stmts_ty+ (text "In the do-command:" <+> ppr do_block)+ (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+ return (do_premap ids+ (mkCorePairTy env_ty stack_ty)+ env_ty+ res_ty+ core_fst+ core_stmts,+ env_ids')++-- D |- e :: forall e. a1 (e,stk1) t1 -> ... an (e,stkn) tn -> a (e,stk) t+-- D; xs |-a ci :: stki --> ti+-- -----------------------------------+-- D; xs |-a (|e c1 ... cn|) :: stk --> t ---> e [t_xs] c1 ... cn++dsCmd _ids local_vars _stack_ty _res_ty (HsCmdArrForm op _ _ args) env_ids = do+ let env_ty = mkBigCoreVarTupTy env_ids+ core_op <- dsLExpr op+ (core_args, fv_sets) <- mapAndUnzipM (dsTrimCmdArg local_vars env_ids) args+ return (mkApps (App core_op (Type env_ty)) core_args,+ unionDVarSets fv_sets)++dsCmd ids local_vars stack_ty res_ty (HsCmdWrap wrap cmd) env_ids = do+ (core_cmd, env_ids') <- dsCmd ids local_vars stack_ty res_ty cmd env_ids+ core_wrap <- dsHsWrapper wrap+ return (core_wrap core_cmd, env_ids')++dsCmd _ _ _ _ _ c = pprPanic "dsCmd" (ppr c)++-- D; ys |-a c : stk --> t (ys <= xs)+-- ---------------------+-- D; xs |-a c : stk --> t ---> premap (\ ((xs),stk) -> ((ys),stk)) c++dsTrimCmdArg+ :: IdSet -- set of local vars available to this command+ -> [Id] -- list of vars in the input to this command+ -> LHsCmdTop Id -- command argument to desugar+ -> DsM (CoreExpr, -- desugared expression+ DIdSet) -- subset of local vars that occur free+dsTrimCmdArg local_vars env_ids (L _ (HsCmdTop cmd stack_ty cmd_ty ids)) = do+ (meth_binds, meth_ids) <- mkCmdEnv ids+ (core_cmd, free_vars, env_ids') <- dsfixCmd meth_ids local_vars stack_ty cmd_ty cmd+ stack_id <- newSysLocalDs stack_ty+ trim_code <- matchEnvStack env_ids stack_id (buildEnvStack env_ids' stack_id)+ let+ in_ty = envStackType env_ids stack_ty+ in_ty' = envStackType env_ids' stack_ty+ arg_code = if env_ids' == env_ids then core_cmd else+ do_premap meth_ids in_ty in_ty' cmd_ty trim_code core_cmd+ return (mkLets meth_binds arg_code, free_vars)++-- Given D; xs |-a c : stk --> t, builds c with xs fed back.+-- Typically needs to be prefixed with arr (\(p, stk) -> ((xs),stk))++dsfixCmd+ :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this command+ -> Type -- type of the stack (right-nested tuple)+ -> Type -- return type of the command+ -> LHsCmd Id -- command to desugar+ -> DsM (CoreExpr, -- desugared expression+ 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 (getLoc cmd) $ dsNoLevPoly cmd_ty+ (text "When desugaring the command:" <+> ppr 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.++trimInput+ :: ([Id] -> DsM (CoreExpr, DIdSet))+ -> DsM (CoreExpr, -- desugared expression+ DIdSet, -- subset of local vars that occur free+ [Id]) -- same local vars as a list, fed back to+ -- the inner function to form the tuple of+ -- inputs to the arrow.+trimInput build_arrow+ = fixDs (\ ~(_,_,env_ids) -> do+ (core_cmd, free_vars) <- build_arrow env_ids+ return (core_cmd, free_vars, dVarSetElems free_vars))++{-+Translation of command judgements of the form++ D |-a do { ss } : t+-}++dsCmdDo :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this statement+ -> Type -- return type of the statement+ -> [CmdLStmt Id] -- statements to desugar+ -> [Id] -- list of vars in the input to this statement+ -- This is typically fed back,+ -- so don't pull on it too early+ -> DsM (CoreExpr, -- desugared expression+ DIdSet) -- subset of local vars that occur free++dsCmdDo _ _ _ [] _ = panic "dsCmdDo"++-- D; xs |-a c : () --> t+-- --------------------------+-- D; xs |-a do { c } : t+--+-- ---> premap (\ (xs) -> ((xs), ())) c++dsCmdDo ids local_vars res_ty [L loc (LastStmt body _ _)] env_ids = do+ putSrcSpanDs loc $ dsNoLevPoly res_ty+ (text "In the command:" <+> ppr body)+ (core_body, env_ids') <- dsLCmd ids local_vars unitTy res_ty body env_ids+ let env_ty = mkBigCoreVarTupTy env_ids+ env_var <- newSysLocalDs env_ty+ let core_map = Lam env_var (mkCorePairExpr (Var env_var) mkCoreUnitExpr)+ return (do_premap ids+ env_ty+ (mkCorePairTy env_ty unitTy)+ res_ty+ core_map+ core_body,+ env_ids')++dsCmdDo ids local_vars res_ty (stmt:stmts) env_ids = do+ let bound_vars = mkVarSet (collectLStmtBinders stmt)+ let local_vars' = bound_vars `unionVarSet` local_vars+ (core_stmts, _, env_ids') <- trimInput (dsCmdDo ids local_vars' res_ty stmts)+ (core_stmt, fv_stmt) <- dsCmdLStmt ids local_vars env_ids' stmt env_ids+ return (do_compose ids+ (mkBigCoreVarTupTy env_ids)+ (mkBigCoreVarTupTy env_ids')+ res_ty+ core_stmt+ core_stmts,+ fv_stmt)++{-+A statement maps one local environment to another, and is represented+as an arrow from one tuple type to another. A statement sequence is+translated to a composition of such arrows.+-}++dsCmdLStmt :: DsCmdEnv -> IdSet -> [Id] -> CmdLStmt Id -> [Id]+ -> DsM (CoreExpr, DIdSet)+dsCmdLStmt ids local_vars out_ids cmd env_ids+ = dsCmdStmt ids local_vars out_ids (unLoc cmd) env_ids++dsCmdStmt+ :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this statement+ -> [Id] -- list of vars in the output of this statement+ -> CmdStmt Id -- statement to desugar+ -> [Id] -- list of vars in the input to this statement+ -- This is typically fed back,+ -- so don't pull on it too early+ -> DsM (CoreExpr, -- desugared expression+ DIdSet) -- subset of local vars that occur free++-- D; xs1 |-a c : () --> t+-- D; xs' |-a do { ss } : t'+-- ------------------------------+-- D; xs |-a do { c; ss } : t'+--+-- ---> premap (\ ((xs)) -> (((xs1),()),(xs')))+-- (first c >>> arr snd) >>> ss++dsCmdStmt ids local_vars out_ids (BodyStmt cmd _ _ c_ty) env_ids = do+ (core_cmd, fv_cmd, env_ids1) <- dsfixCmd ids local_vars unitTy c_ty cmd+ core_mux <- matchEnv env_ids+ (mkCorePairExpr+ (mkCorePairExpr (mkBigCoreVarTup env_ids1) mkCoreUnitExpr)+ (mkBigCoreVarTup out_ids))+ let+ in_ty = mkBigCoreVarTupTy env_ids+ in_ty1 = mkCorePairTy (mkBigCoreVarTupTy env_ids1) unitTy+ out_ty = mkBigCoreVarTupTy out_ids+ before_c_ty = mkCorePairTy in_ty1 out_ty+ after_c_ty = mkCorePairTy c_ty out_ty+ dsNoLevPoly c_ty empty -- I (Richard E, Dec '16) have no idea what to say here+ 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+ (do_first ids in_ty1 c_ty out_ty core_cmd) $+ do_arr ids after_c_ty out_ty snd_fn,+ extendDVarSetList fv_cmd out_ids)++-- D; xs1 |-a c : () --> t+-- D; xs' |-a do { ss } : t' xs2 = xs' - defs(p)+-- -----------------------------------+-- D; xs |-a do { p <- c; ss } : t'+--+-- ---> premap (\ (xs) -> (((xs1),()),(xs2)))+-- (first c >>> arr (\ (p, (xs2)) -> (xs'))) >>> ss+--+-- It would be simpler and more consistent to do this using second,+-- but that's likely to be defined in terms of first.++dsCmdStmt ids local_vars out_ids (BindStmt pat cmd _ _ _) env_ids = do+ let pat_ty = hsLPatType pat+ (core_cmd, fv_cmd, env_ids1) <- dsfixCmd ids local_vars unitTy pat_ty cmd+ let pat_vars = mkVarSet (collectPatBinders pat)+ let+ env_ids2 = filterOut (`elemVarSet` pat_vars) out_ids+ env_ty2 = mkBigCoreVarTupTy env_ids2++ -- multiplexing function+ -- \ (xs) -> (((xs1),()),(xs2))++ core_mux <- matchEnv env_ids+ (mkCorePairExpr+ (mkCorePairExpr (mkBigCoreVarTup env_ids1) mkCoreUnitExpr)+ (mkBigCoreVarTup env_ids2))++ -- projection function+ -- \ (p, (xs2)) -> (zs)++ env_id <- newSysLocalDs env_ty2+ uniqs <- newUniqueSupply+ let+ after_c_ty = mkCorePairTy pat_ty env_ty2+ out_ty = mkBigCoreVarTupTy out_ids+ body_expr = coreCaseTuple uniqs env_id env_ids2 (mkBigCoreVarTup out_ids)++ fail_expr <- mkFailExpr (StmtCtxt DoExpr) out_ty+ pat_id <- selectSimpleMatchVarL pat+ match_code <- matchSimply (Var pat_id) (StmtCtxt DoExpr) pat body_expr fail_expr+ pair_id <- newSysLocalDs after_c_ty+ let+ proj_expr = Lam pair_id (coreCasePair pair_id pat_id env_id match_code)++ -- put it all together+ let+ in_ty = mkBigCoreVarTupTy env_ids+ in_ty1 = mkCorePairTy (mkBigCoreVarTupTy env_ids1) unitTy+ in_ty2 = mkBigCoreVarTupTy env_ids2+ before_c_ty = mkCorePairTy in_ty1 in_ty2+ return (do_premap ids in_ty before_c_ty out_ty core_mux $+ do_compose ids before_c_ty after_c_ty out_ty+ (do_first ids in_ty1 pat_ty in_ty2 core_cmd) $+ do_arr ids after_c_ty out_ty proj_expr,+ fv_cmd `unionDVarSet` (mkDVarSet out_ids `udfmMinusUFM` getUniqSet pat_vars))++-- D; xs' |-a do { ss } : t+-- --------------------------------------+-- D; xs |-a do { let binds; ss } : t+--+-- ---> arr (\ (xs) -> let binds in (xs')) >>> ss++dsCmdStmt ids local_vars out_ids (LetStmt binds) env_ids = do+ -- build a new environment using the let bindings+ core_binds <- dsLocalBinds binds (mkBigCoreVarTup out_ids)+ -- match the old environment against the input+ core_map <- matchEnv env_ids core_binds+ return (do_arr ids+ (mkBigCoreVarTupTy env_ids)+ (mkBigCoreVarTupTy out_ids)+ core_map,+ exprFreeIdsDSet core_binds `udfmIntersectUFM` getUniqSet local_vars)++-- D; ys |-a do { ss; returnA -< ((xs1), (ys2)) } : ...+-- D; xs' |-a do { ss' } : t+-- ------------------------------------+-- D; xs |-a do { rec ss; ss' } : t+--+-- xs1 = xs' /\ defs(ss)+-- xs2 = xs' - defs(ss)+-- ys1 = ys - defs(ss)+-- ys2 = ys /\ defs(ss)+--+-- ---> arr (\(xs) -> ((ys1),(xs2))) >>>+-- first (loop (arr (\((ys1),~(ys2)) -> (ys)) >>> ss)) >>>+-- arr (\((xs1),(xs2)) -> (xs')) >>> ss'++dsCmdStmt ids local_vars out_ids+ (RecStmt { recS_stmts = stmts+ , recS_later_ids = later_ids, recS_rec_ids = rec_ids+ , recS_later_rets = later_rets, recS_rec_rets = rec_rets })+ env_ids = do+ let+ later_ids_set = mkVarSet later_ids+ env2_ids = filterOut (`elemVarSet` later_ids_set) out_ids+ env2_id_set = mkDVarSet env2_ids+ env2_ty = mkBigCoreVarTupTy env2_ids++ -- post_loop_fn = \((later_ids),(env2_ids)) -> (out_ids)++ uniqs <- newUniqueSupply+ env2_id <- newSysLocalDs env2_ty+ let+ later_ty = mkBigCoreVarTupTy later_ids+ post_pair_ty = mkCorePairTy later_ty env2_ty+ post_loop_body = coreCaseTuple uniqs env2_id env2_ids (mkBigCoreVarTup out_ids)++ post_loop_fn <- matchEnvStack later_ids env2_id post_loop_body++ --- loop (...)++ (core_loop, env1_id_set, env1_ids)+ <- dsRecCmd ids local_vars stmts later_ids later_rets rec_ids rec_rets++ -- pre_loop_fn = \(env_ids) -> ((env1_ids),(env2_ids))++ let+ env1_ty = mkBigCoreVarTupTy env1_ids+ pre_pair_ty = mkCorePairTy env1_ty env2_ty+ pre_loop_body = mkCorePairExpr (mkBigCoreVarTup env1_ids)+ (mkBigCoreVarTup env2_ids)++ pre_loop_fn <- matchEnv env_ids pre_loop_body++ -- arr pre_loop_fn >>> first (loop (...)) >>> arr post_loop_fn++ let+ env_ty = mkBigCoreVarTupTy env_ids+ out_ty = mkBigCoreVarTupTy out_ids+ core_body = do_premap ids env_ty pre_pair_ty out_ty+ pre_loop_fn+ (do_compose ids pre_pair_ty post_pair_ty out_ty+ (do_first ids env1_ty later_ty env2_ty+ core_loop)+ (do_arr ids post_pair_ty out_ty+ post_loop_fn))++ return (core_body, env1_id_set `unionDVarSet` env2_id_set)++dsCmdStmt _ _ _ _ s = pprPanic "dsCmdStmt" (ppr s)++-- loop (premap (\ ((env1_ids), ~(rec_ids)) -> (env_ids))+-- (ss >>> arr (\ (out_ids) -> ((later_rets),(rec_rets))))) >>>++dsRecCmd+ :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this statement+ -> [CmdLStmt Id] -- list of statements inside the RecCmd+ -> [Id] -- list of vars defined here and used later+ -> [HsExpr Id] -- expressions corresponding to later_ids+ -> [Id] -- list of vars fed back through the loop+ -> [HsExpr Id] -- expressions corresponding to rec_ids+ -> DsM (CoreExpr, -- desugared statement+ DIdSet, -- subset of local vars that occur free+ [Id]) -- same local vars as a list++dsRecCmd ids local_vars stmts later_ids later_rets rec_ids rec_rets = do+ let+ later_id_set = mkVarSet later_ids+ rec_id_set = mkVarSet rec_ids+ local_vars' = rec_id_set `unionVarSet` later_id_set `unionVarSet` local_vars++ -- mk_pair_fn = \ (out_ids) -> ((later_rets),(rec_rets))++ core_later_rets <- mapM dsExpr later_rets+ core_rec_rets <- mapM dsExpr rec_rets+ let+ -- possibly polymorphic version of vars of later_ids and rec_ids+ out_ids = exprsFreeIdsList (core_later_rets ++ core_rec_rets)+ out_ty = mkBigCoreVarTupTy out_ids++ later_tuple = mkBigCoreTup core_later_rets+ later_ty = mkBigCoreVarTupTy later_ids++ rec_tuple = mkBigCoreTup core_rec_rets+ rec_ty = mkBigCoreVarTupTy rec_ids++ out_pair = mkCorePairExpr later_tuple rec_tuple+ out_pair_ty = mkCorePairTy later_ty rec_ty++ mk_pair_fn <- matchEnv out_ids out_pair++ -- ss++ (core_stmts, fv_stmts, env_ids) <- dsfixCmdStmts ids local_vars' out_ids stmts++ -- squash_pair_fn = \ ((env1_ids), ~(rec_ids)) -> (env_ids)++ rec_id <- newSysLocalDs rec_ty+ let+ env1_id_set = fv_stmts `udfmMinusUFM` getUniqSet rec_id_set+ env1_ids = dVarSetElems env1_id_set+ env1_ty = mkBigCoreVarTupTy env1_ids+ in_pair_ty = mkCorePairTy env1_ty rec_ty+ core_body = mkBigCoreTup (map selectVar env_ids)+ where+ selectVar v+ | v `elemVarSet` rec_id_set+ = mkTupleSelector rec_ids v rec_id (Var rec_id)+ | otherwise = Var v++ squash_pair_fn <- matchEnvStack env1_ids rec_id core_body++ -- loop (premap squash_pair_fn (ss >>> arr mk_pair_fn))++ let+ env_ty = mkBigCoreVarTupTy env_ids+ core_loop = do_loop ids env1_ty later_ty rec_ty+ (do_premap ids in_pair_ty env_ty out_pair_ty+ squash_pair_fn+ (do_compose ids env_ty out_ty out_pair_ty+ core_stmts+ (do_arr ids out_ty out_pair_ty mk_pair_fn)))++ return (core_loop, env1_id_set, env1_ids)++{-+A sequence of statements (as in a rec) is desugared to an arrow between+two environments (no stack)+-}++dsfixCmdStmts+ :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this statement+ -> [Id] -- output vars of these statements+ -> [CmdLStmt Id] -- statements to desugar+ -> DsM (CoreExpr, -- desugared expression+ DIdSet, -- subset of local vars that occur free+ [Id]) -- same local vars as a list++dsfixCmdStmts ids local_vars out_ids stmts+ = trimInput (dsCmdStmts ids local_vars out_ids stmts)+ -- TODO: Add levity polymorphism check for the resulting expression.+ -- But I (Richard E.) don't know enough about arrows to do so.++dsCmdStmts+ :: DsCmdEnv -- arrow combinators+ -> IdSet -- set of local vars available to this statement+ -> [Id] -- output vars of these statements+ -> [CmdLStmt Id] -- statements to desugar+ -> [Id] -- list of vars in the input to these statements+ -> DsM (CoreExpr, -- desugared expression+ DIdSet) -- subset of local vars that occur free++dsCmdStmts ids local_vars out_ids [stmt] env_ids+ = dsCmdLStmt ids local_vars out_ids stmt env_ids++dsCmdStmts ids local_vars out_ids (stmt:stmts) env_ids = do+ let bound_vars = mkVarSet (collectLStmtBinders stmt)+ let local_vars' = bound_vars `unionVarSet` local_vars+ (core_stmts, _fv_stmts, env_ids') <- dsfixCmdStmts ids local_vars' out_ids stmts+ (core_stmt, fv_stmt) <- dsCmdLStmt ids local_vars env_ids' stmt env_ids+ return (do_compose ids+ (mkBigCoreVarTupTy env_ids)+ (mkBigCoreVarTupTy env_ids')+ (mkBigCoreVarTupTy out_ids)+ core_stmt+ core_stmts,+ fv_stmt)++dsCmdStmts _ _ _ [] _ = panic "dsCmdStmts []"++-- Match a list of expressions against a list of patterns, left-to-right.++matchSimplys :: [CoreExpr] -- Scrutinees+ -> HsMatchContext Name -- Match kind+ -> [LPat Id] -- Patterns they should match+ -> CoreExpr -- Return this if they all match+ -> CoreExpr -- Return this if they don't+ -> DsM CoreExpr+matchSimplys [] _ctxt [] result_expr _fail_expr = return result_expr+matchSimplys (exp:exps) ctxt (pat:pats) result_expr fail_expr = do+ match_code <- matchSimplys exps ctxt pats result_expr fail_expr+ matchSimply exp ctxt pat match_code fail_expr+matchSimplys _ _ _ _ _ = panic "matchSimplys"++-- List of leaf expressions, with set of variables bound in each++leavesMatch :: LMatch Id (Located (body Id)) -> [(Located (body Id), IdSet)]+leavesMatch (L _ (Match _ pats _ (GRHSs grhss (L _ binds))))+ = let+ defined_vars = mkVarSet (collectPatsBinders pats)+ `unionVarSet`+ mkVarSet (collectLocalBinders binds)+ in+ [(body,+ mkVarSet (collectLStmtsBinders stmts)+ `unionVarSet` defined_vars)+ | L _ (GRHS stmts body) <- grhss]++-- Replace the leaf commands in a match++replaceLeavesMatch+ :: Type -- new result type+ -> [Located (body' Id)] -- replacement leaf expressions of that type+ -> LMatch Id (Located (body Id)) -- the matches of a case command+ -> ([Located (body' Id)], -- remaining leaf expressions+ LMatch Id (Located (body' Id))) -- updated match+replaceLeavesMatch _res_ty leaves (L loc (Match mf pat mt (GRHSs grhss binds)))+ = let+ (leaves', grhss') = mapAccumL replaceLeavesGRHS leaves grhss+ in+ (leaves', L loc (Match mf pat mt (GRHSs grhss' binds)))++replaceLeavesGRHS+ :: [Located (body' Id)] -- replacement leaf expressions of that type+ -> LGRHS Id (Located (body Id)) -- rhss of a case command+ -> ([Located (body' Id)], -- remaining leaf expressions+ LGRHS Id (Located (body' Id))) -- updated GRHS+replaceLeavesGRHS (leaf:leaves) (L loc (GRHS stmts _))+ = (leaves, L loc (GRHS stmts leaf))+replaceLeavesGRHS [] _ = panic "replaceLeavesGRHS []"++-- Balanced fold of a non-empty list.++foldb :: (a -> a -> a) -> [a] -> a+foldb _ [] = error "foldb of empty list"+foldb _ [x] = x+foldb f xs = foldb f (fold_pairs xs)+ where+ fold_pairs [] = []+ fold_pairs [x] = [x]+ fold_pairs (x1:x2:xs) = f x1 x2:fold_pairs xs++{-+Note [Dictionary binders in ConPatOut] See also same Note in HsUtils+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The following functions to collect value variables from patterns are+copied from HsUtils, with one change: we also collect the dictionary+bindings (pat_binds) from ConPatOut. We need them for cases like++h :: Arrow a => Int -> a (Int,Int) Int+h x = proc (y,z) -> case compare x y of+ GT -> returnA -< z+x++The type checker turns the case into++ case compare x y of+ GT { p77 = plusInt } -> returnA -< p77 z x++Here p77 is a local binding for the (+) operation.++See comments in HsUtils for why the other version does not include+these bindings.+-}++collectPatBinders :: LPat Id -> [Id]+collectPatBinders pat = collectl pat []++collectPatsBinders :: [LPat Id] -> [Id]+collectPatsBinders pats = foldr collectl [] pats++---------------------+collectl :: LPat Id -> [Id] -> [Id]+-- See Note [Dictionary binders in ConPatOut]+collectl (L _ pat) bndrs+ = go pat+ where+ go (VarPat (L _ var)) = var : bndrs+ go (WildPat _) = bndrs+ go (LazyPat pat) = collectl pat bndrs+ go (BangPat pat) = collectl pat bndrs+ go (AsPat (L _ a) pat) = a : collectl pat bndrs+ go (ParPat pat) = collectl pat bndrs++ go (ListPat pats _ _) = foldr collectl bndrs pats+ go (PArrPat pats _) = foldr collectl bndrs pats+ go (TuplePat pats _ _) = foldr collectl bndrs pats+ go (SumPat pat _ _ _) = collectl pat bndrs++ go (ConPatIn _ ps) = foldr collectl bndrs (hsConPatArgs ps)+ go (ConPatOut {pat_args=ps, pat_binds=ds}) =+ collectEvBinders ds+ ++ foldr collectl bndrs (hsConPatArgs ps)+ go (LitPat _) = bndrs+ go (NPat {}) = bndrs+ go (NPlusKPat (L _ n) _ _ _ _ _) = n : bndrs++ go (SigPatIn pat _) = collectl pat bndrs+ go (SigPatOut pat _) = collectl pat bndrs+ go (CoPat _ pat _) = collectl (noLoc pat) bndrs+ go (ViewPat _ pat _) = collectl pat bndrs+ go p@(SplicePat {}) = pprPanic "collectl/go" (ppr p)++collectEvBinders :: TcEvBinds -> [Id]+collectEvBinders (EvBinds bs) = foldrBag add_ev_bndr [] bs+collectEvBinders (TcEvBinds {}) = panic "ToDo: collectEvBinders"++add_ev_bndr :: EvBind -> [Id] -> [Id]+add_ev_bndr (EvBind { eb_lhs = b }) bs | isId b = b:bs+ | otherwise = bs+ -- A worry: what about coercion variable binders??++collectLStmtsBinders :: [LStmt Id body] -> [Id]+collectLStmtsBinders = concatMap collectLStmtBinders++collectLStmtBinders :: LStmt Id body -> [Id]+collectLStmtBinders = collectStmtBinders . unLoc++collectStmtBinders :: Stmt Id body -> [Id]+collectStmtBinders (RecStmt { recS_later_ids = later_ids }) = later_ids+collectStmtBinders stmt = HsUtils.collectStmtBinders stmt
+ deSugar/DsBinds.hs view
@@ -0,0 +1,1387 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Pattern-matching bindings (HsBinds and MonoBinds)++Handles @HsBinds@; those at the top level require different handling,+in that the @Rec@/@NonRec@/etc structure is thrown away (whereas at+lower levels it is preserved with @let@/@letrec@s).+-}++{-# LANGUAGE CPP #-}++module DsBinds ( dsTopLHsBinds, dsLHsBinds, decomposeRuleLhs, dsSpec,+ dsHsWrapper, dsTcEvBinds, dsTcEvBinds_s, dsEvBinds, dsMkUserRule+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} DsExpr( dsLExpr )+import {-# SOURCE #-} Match( matchWrapper )++import DsMonad+import DsGRHSs+import DsUtils++import HsSyn -- lots of things+import CoreSyn -- lots of things+import Literal ( Literal(MachStr) )+import CoreOpt ( simpleOptExpr )+import OccurAnal ( occurAnalyseExpr )+import MkCore+import CoreUtils+import CoreArity ( etaExpand )+import CoreUnfold+import CoreFVs+import Digraph++import PrelNames+import TyCon+import TcEvidence+import TcType+import Type+import Coercion+import TysWiredIn ( typeNatKind, typeSymbolKind )+import Id+import MkId(proxyHashId)+import Class+import Name+import VarSet+import Rules+import VarEnv+import Outputable+import Module+import SrcLoc+import Maybes+import OrdList+import Bag+import BasicTypes+import DynFlags+import FastString+import Util+import MonadUtils+import qualified GHC.LanguageExtensions as LangExt+import Control.Monad++{-**********************************************************************+* *+ Desugaring a MonoBinds+* *+**********************************************************************-}++-- | Desugar top level binds, strict binds are treated like normal+-- binds since there is no good time to force before first usage.+dsTopLHsBinds :: LHsBinds Id -> DsM (OrdList (Id,CoreExpr))+dsTopLHsBinds binds+ -- see Note [Strict binds checks]+ | not (isEmptyBag unlifted_binds) || not (isEmptyBag bang_binds)+ = do { mapBagM_ (top_level_err "bindings for unlifted types") unlifted_binds+ ; mapBagM_ (top_level_err "strict pattern bindings") bang_binds+ ; return nilOL }++ | otherwise+ = do { (force_vars, prs) <- dsLHsBinds binds+ ; when debugIsOn $+ do { xstrict <- xoptM LangExt.Strict+ ; MASSERT2( null force_vars || xstrict, ppr binds $$ ppr force_vars ) }+ -- with -XStrict, even top-level vars are listed as force vars.++ ; return (toOL prs) }++ where+ unlifted_binds = filterBag (isUnliftedHsBind . unLoc) binds+ bang_binds = filterBag (isBangedPatBind . unLoc) binds++ top_level_err desc (L loc bind)+ = putSrcSpanDs loc $+ errDs (hang (text "Top-level" <+> text desc <+> text "aren't allowed:")+ 2 (ppr bind))+++-- | Desugar all other kind of bindings, Ids of strict binds are returned to+-- later be forced in the binding group body, see Note [Desugar Strict binds]+dsLHsBinds :: LHsBinds Id -> DsM ([Id], [(Id,CoreExpr)])+dsLHsBinds binds+ = do { MASSERT( allBag (not . isUnliftedHsBind . unLoc) binds )+ ; ds_bs <- mapBagM dsLHsBind binds+ ; return (foldBag (\(a, a') (b, b') -> (a ++ b, a' ++ b'))+ id ([], []) ds_bs) }++------------------------+dsLHsBind :: LHsBind Id+ -> DsM ([Id], [(Id,CoreExpr)])+dsLHsBind (L loc bind) = do dflags <- getDynFlags+ putSrcSpanDs loc $ dsHsBind dflags bind++-- | Desugar a single binding (or group of recursive binds).+dsHsBind :: DynFlags+ -> HsBind Id+ -> DsM ([Id], [(Id,CoreExpr)])+ -- ^ The Ids of strict binds, to be forced in the body of the+ -- binding group see Note [Desugar Strict binds] and all+ -- bindings and their desugared right hand sides.++dsHsBind dflags+ (VarBind { var_id = var+ , var_rhs = expr+ , var_inline = inline_regardless })+ = do { core_expr <- dsLExpr expr+ -- Dictionary bindings are always VarBinds,+ -- so we only need do this here+ ; let var' | inline_regardless = var `setIdUnfolding` mkCompulsoryUnfolding core_expr+ | otherwise = var+ ; let core_bind@(id,_) = makeCorePair dflags var' False 0 core_expr+ force_var = if xopt LangExt.Strict dflags+ then [id]+ else []+ ; return (force_var, [core_bind]) }++dsHsBind dflags+ b@(FunBind { fun_id = L _ fun, fun_matches = matches+ , fun_co_fn = co_fn, fun_tick = tick })+ = do { (args, body) <- matchWrapper+ (mkPrefixFunRhs (noLoc $ idName fun))+ Nothing matches+ ; core_wrap <- dsHsWrapper co_fn+ ; let body' = mkOptTickBox tick body+ rhs = core_wrap (mkLams args body')+ core_binds@(id,_) = makeCorePair dflags fun False 0 rhs+ force_var+ -- Bindings are strict when -XStrict is enabled+ | xopt LangExt.Strict dflags+ , matchGroupArity matches == 0 -- no need to force lambdas+ = [id]+ | isBangedBind b+ = [id]+ | otherwise+ = []+ ; --pprTrace "dsHsBind" (ppr fun <+> ppr (idInlinePragma fun) $$ ppr (mg_alts matches) $$ ppr args $$ ppr core_binds) $+ return (force_var, [core_binds]) }++dsHsBind dflags+ (PatBind { pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty+ , pat_ticks = (rhs_tick, var_ticks) })+ = do { body_expr <- dsGuarded grhss ty+ ; let body' = mkOptTickBox rhs_tick body_expr+ pat' = decideBangHood dflags pat+ ; (force_var,sel_binds) <- mkSelectorBinds var_ticks pat body'+ -- We silently ignore inline pragmas; no makeCorePair+ -- Not so cool, but really doesn't matter+ ; let force_var' = if isBangedLPat pat'+ then [force_var]+ else []+ ; return (force_var', sel_binds) }++ -- A common case: one exported variable, only non-strict binds+ -- Non-recursive bindings come through this way+ -- So do self-recursive bindings+ -- Bindings with complete signatures are AbsBindsSigs, below+dsHsBind dflags+ (AbsBinds { abs_tvs = tyvars, abs_ev_vars = dicts+ , abs_exports = [export]+ , abs_ev_binds = ev_binds, abs_binds = binds })+ | ABE { abe_wrap = wrap, abe_poly = global+ , abe_mono = local, abe_prags = prags } <- export+ , not (xopt LangExt.Strict dflags) -- Handle strict binds+ , not (anyBag (isBangedBind . unLoc) binds) -- in the next case+ = -- See Note [AbsBinds wrappers] in HsBinds+ addDictsDs (toTcTypeBag (listToBag dicts)) $+ -- addDictsDs: push type constraints deeper for pattern match check+ do { (force_vars, bind_prs) <- dsLHsBinds binds+ ; let core_bind = Rec bind_prs+ ; ds_binds <- dsTcEvBinds_s ev_binds+ ; core_wrap <- dsHsWrapper wrap -- Usually the identity++ ; let rhs = core_wrap $+ mkLams tyvars $ mkLams dicts $+ mkCoreLets ds_binds $+ mkLet core_bind $+ Var local+ ; (spec_binds, rules) <- dsSpecs rhs prags++ ; let global' = addIdSpecialisations global rules+ main_bind = makeCorePair dflags global' (isDefaultMethod prags)+ (dictArity dicts) rhs++ ; ASSERT(null force_vars)+ return ([], main_bind : fromOL spec_binds) }++ -- Another common case: no tyvars, no dicts+ -- In this case we can have a much simpler desugaring+dsHsBind dflags+ (AbsBinds { abs_tvs = [], abs_ev_vars = []+ , abs_exports = exports+ , abs_ev_binds = ev_binds, abs_binds = binds })+ = do { (force_vars, bind_prs) <- dsLHsBinds binds+ ; let mk_bind (ABE { abe_wrap = wrap+ , abe_poly = global+ , abe_mono = local+ , abe_prags = prags })+ = do { core_wrap <- dsHsWrapper wrap+ ; return (makeCorePair dflags global+ (isDefaultMethod prags)+ 0 (core_wrap (Var local))) }+ ; main_binds <- mapM mk_bind exports++ ; ds_binds <- dsTcEvBinds_s ev_binds+ ; return (force_vars, flattenBinds ds_binds ++ bind_prs ++ main_binds) }++dsHsBind dflags+ (AbsBinds { abs_tvs = tyvars, abs_ev_vars = dicts+ , abs_exports = exports, abs_ev_binds = ev_binds+ , abs_binds = binds })+ -- See Note [Desugaring AbsBinds]+ = addDictsDs (toTcTypeBag (listToBag dicts)) $+ -- addDictsDs: push type constraints deeper for pattern match check+ do { (local_force_vars, bind_prs) <- dsLHsBinds binds+ ; let core_bind = Rec [ makeCorePair dflags (add_inline lcl_id) False 0 rhs+ | (lcl_id, rhs) <- bind_prs ]+ -- Monomorphic recursion possible, hence Rec+ new_force_vars = get_new_force_vars local_force_vars+ locals = map abe_mono exports+ all_locals = locals ++ new_force_vars+ tup_expr = mkBigCoreVarTup all_locals+ tup_ty = exprType tup_expr+ ; ds_binds <- dsTcEvBinds_s ev_binds+ ; let poly_tup_rhs = mkLams tyvars $ mkLams dicts $+ mkCoreLets ds_binds $+ mkLet core_bind $+ tup_expr++ ; poly_tup_id <- newSysLocalDs (exprType poly_tup_rhs)++ -- Find corresponding global or make up a new one: sometimes+ -- we need to make new export to desugar strict binds, see+ -- Note [Desugar Strict binds]+ ; (exported_force_vars, extra_exports) <- get_exports local_force_vars++ ; let mk_bind (ABE { abe_wrap = wrap+ , abe_poly = global+ , abe_mono = local, abe_prags = spec_prags })+ -- See Note [AbsBinds wrappers] in HsBinds+ = do { tup_id <- newSysLocalDs tup_ty+ ; core_wrap <- dsHsWrapper wrap+ ; let rhs = core_wrap $ mkLams tyvars $ mkLams dicts $+ mkTupleSelector all_locals local tup_id $+ mkVarApps (Var poly_tup_id) (tyvars ++ dicts)+ rhs_for_spec = Let (NonRec poly_tup_id poly_tup_rhs) rhs+ ; (spec_binds, rules) <- dsSpecs rhs_for_spec spec_prags+ ; let global' = (global `setInlinePragma` defaultInlinePragma)+ `addIdSpecialisations` rules+ -- Kill the INLINE pragma because it applies to+ -- the user written (local) function. The global+ -- Id is just the selector. Hmm.+ ; return ((global', rhs) : fromOL spec_binds) }++ ; export_binds_s <- mapM mk_bind (exports ++ extra_exports)++ ; return (exported_force_vars+ ,(poly_tup_id, poly_tup_rhs) :+ concat export_binds_s) }+ where+ inline_env :: IdEnv Id -- Maps a monomorphic local Id to one with+ -- the inline pragma from the source+ -- The type checker put the inline pragma+ -- on the *global* Id, so we need to transfer it+ inline_env+ = mkVarEnv [ (lcl_id, setInlinePragma lcl_id prag)+ | ABE { abe_mono = lcl_id, abe_poly = gbl_id } <- exports+ , let prag = idInlinePragma gbl_id ]++ add_inline :: Id -> Id -- tran+ add_inline lcl_id = lookupVarEnv inline_env lcl_id+ `orElse` lcl_id++ global_env :: IdEnv Id -- Maps local Id to its global exported Id+ global_env =+ mkVarEnv [ (local, global)+ | ABE { abe_mono = local, abe_poly = global } <- exports+ ]++ -- find variables that are not exported+ get_new_force_vars lcls =+ foldr (\lcl acc -> case lookupVarEnv global_env lcl of+ Just _ -> acc+ Nothing -> lcl:acc)+ [] lcls++ -- find exports or make up new exports for force variables+ get_exports :: [Id] -> DsM ([Id], [ABExport Id])+ get_exports lcls =+ foldM (\(glbls, exports) lcl ->+ case lookupVarEnv global_env lcl of+ Just glbl -> return (glbl:glbls, exports)+ Nothing -> do export <- mk_export lcl+ let glbl = abe_poly export+ return (glbl:glbls, export:exports))+ ([],[]) lcls++ mk_export local =+ do global <- newSysLocalDs+ (exprType (mkLams tyvars (mkLams dicts (Var local))))+ return (ABE {abe_poly = global+ ,abe_mono = local+ ,abe_wrap = WpHole+ ,abe_prags = SpecPrags []})++-- AbsBindsSig is a combination of AbsBinds and FunBind+dsHsBind dflags (AbsBindsSig { abs_tvs = tyvars, abs_ev_vars = dicts+ , abs_sig_export = global+ , abs_sig_prags = prags+ , abs_sig_ev_bind = ev_bind+ , abs_sig_bind = bind })+ | L bind_loc FunBind { fun_matches = matches+ , fun_co_fn = co_fn+ , fun_tick = tick } <- bind+ = putSrcSpanDs bind_loc $+ addDictsDs (toTcTypeBag (listToBag dicts)) $+ -- addDictsDs: push type constraints deeper for pattern match check+ do { (args, body) <- matchWrapper+ (mkPrefixFunRhs (noLoc $ idName global))+ Nothing matches+ ; core_wrap <- dsHsWrapper co_fn+ ; let body' = mkOptTickBox tick body+ fun_rhs = core_wrap (mkLams args body')+ force_vars+ | xopt LangExt.Strict dflags+ , matchGroupArity matches == 0 -- no need to force lambdas+ = [global]+ | isBangedBind (unLoc bind)+ = [global]+ | otherwise+ = []++ ; ds_binds <- dsTcEvBinds ev_bind+ ; let rhs = mkLams tyvars $+ mkLams dicts $+ mkCoreLets ds_binds $+ fun_rhs++ ; (spec_binds, rules) <- dsSpecs rhs prags+ ; let global' = addIdSpecialisations global rules+ main_bind = makeCorePair dflags global' (isDefaultMethod prags)+ (dictArity dicts) rhs++ ; return (force_vars, main_bind : fromOL spec_binds) }++ | otherwise+ = pprPanic "dsHsBind: AbsBindsSig" (ppr bind)++dsHsBind _ (PatSynBind{}) = panic "dsHsBind: PatSynBind"++++-- | This is where we apply INLINE and INLINABLE pragmas. All we need to+-- do is to attach the unfolding information to the Id.+--+-- Other decisions about whether to inline are made in+-- `calcUnfoldingGuidance` but the decision about whether to then expose+-- the unfolding in the interface file is made in `TidyPgm.addExternal`+-- using this information.+------------------------+makeCorePair :: DynFlags -> Id -> Bool -> Arity -> CoreExpr -> (Id, CoreExpr)+makeCorePair dflags gbl_id is_default_method dict_arity rhs+ | is_default_method -- Default methods are *always* inlined+ = (gbl_id `setIdUnfolding` mkCompulsoryUnfolding rhs, rhs)++ | otherwise+ = case inlinePragmaSpec inline_prag of+ EmptyInlineSpec -> (gbl_id, rhs)+ NoInline -> (gbl_id, rhs)+ Inlinable -> (gbl_id `setIdUnfolding` inlinable_unf, rhs)+ Inline -> inline_pair++ where+ inline_prag = idInlinePragma gbl_id+ inlinable_unf = mkInlinableUnfolding dflags rhs+ inline_pair+ | Just arity <- inlinePragmaSat inline_prag+ -- Add an Unfolding for an INLINE (but not for NOINLINE)+ -- And eta-expand the RHS; see Note [Eta-expanding INLINE things]+ , let real_arity = dict_arity + arity+ -- NB: The arity in the InlineRule takes account of the dictionaries+ = ( gbl_id `setIdUnfolding` mkInlineUnfoldingWithArity real_arity rhs+ , etaExpand real_arity rhs)++ | otherwise+ = pprTrace "makeCorePair: arity missing" (ppr gbl_id) $+ (gbl_id `setIdUnfolding` mkInlineUnfolding rhs, rhs)++dictArity :: [Var] -> Arity+-- Don't count coercion variables in arity+dictArity dicts = count isId dicts++{-+Note [Desugaring AbsBinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~+In the general AbsBinds case we desugar the binding to this:++ tup a (d:Num a) = let fm = ...gm...+ gm = ...fm...+ in (fm,gm)+ f a d = case tup a d of { (fm,gm) -> fm }+ g a d = case tup a d of { (fm,gm) -> fm }++Note [Rules and inlining]+~~~~~~~~~~~~~~~~~~~~~~~~~+Common special case: no type or dictionary abstraction+This is a bit less trivial than you might suppose+The naive way woudl be to desguar to something like+ f_lcl = ...f_lcl... -- The "binds" from AbsBinds+ M.f = f_lcl -- Generated from "exports"+But we don't want that, because if M.f isn't exported,+it'll be inlined unconditionally at every call site (its rhs is+trivial). That would be ok unless it has RULES, which would+thereby be completely lost. Bad, bad, bad.++Instead we want to generate+ M.f = ...f_lcl...+ f_lcl = M.f+Now all is cool. The RULES are attached to M.f (by SimplCore),+and f_lcl is rapidly inlined away.++This does not happen in the same way to polymorphic binds,+because they desugar to+ M.f = /\a. let f_lcl = ...f_lcl... in f_lcl+Although I'm a bit worried about whether full laziness might+float the f_lcl binding out and then inline M.f at its call site++Note [Specialising in no-dict case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Even if there are no tyvars or dicts, we may have specialisation pragmas.+Class methods can generate+ AbsBinds [] [] [( ... spec-prag]+ { AbsBinds [tvs] [dicts] ...blah }+So the overloading is in the nested AbsBinds. A good example is in GHC.Float:++ class (Real a, Fractional a) => RealFrac a where+ round :: (Integral b) => a -> b++ instance RealFrac Float where+ {-# SPECIALIZE round :: Float -> Int #-}++The top-level AbsBinds for $cround has no tyvars or dicts (because the+instance does not). But the method is locally overloaded!++Note [Abstracting over tyvars only]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When abstracting over type variable only (not dictionaries), we don't really need to+built a tuple and select from it, as we do in the general case. Instead we can take++ AbsBinds [a,b] [ ([a,b], fg, fl, _),+ ([b], gg, gl, _) ]+ { fl = e1+ gl = e2+ h = e3 }++and desugar it to++ fg = /\ab. let B in e1+ gg = /\b. let a = () in let B in S(e2)+ h = /\ab. let B in e3++where B is the *non-recursive* binding+ fl = fg a b+ gl = gg b+ h = h a b -- See (b); note shadowing!++Notice (a) g has a different number of type variables to f, so we must+ use the mkArbitraryType thing to fill in the gaps.+ We use a type-let to do that.++ (b) The local variable h isn't in the exports, and rather than+ clone a fresh copy we simply replace h by (h a b), where+ the two h's have different types! Shadowing happens here,+ which looks confusing but works fine.++ (c) The result is *still* quadratic-sized if there are a lot of+ small bindings. So if there are more than some small+ number (10), we filter the binding set B by the free+ variables of the particular RHS. Tiresome.++Why got to this trouble? It's a common case, and it removes the+quadratic-sized tuple desugaring. Less clutter, hopefully faster+compilation, especially in a case where there are a *lot* of+bindings.+++Note [Eta-expanding INLINE things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ foo :: Eq a => a -> a+ {-# INLINE foo #-}+ foo x = ...++If (foo d) ever gets floated out as a common sub-expression (which can+happen as a result of method sharing), there's a danger that we never+get to do the inlining, which is a Terribly Bad thing given that the+user said "inline"!++To avoid this we pre-emptively eta-expand the definition, so that foo+has the arity with which it is declared in the source code. In this+example it has arity 2 (one for the Eq and one for x). Doing this+should mean that (foo d) is a PAP and we don't share it.++Note [Nested arities]+~~~~~~~~~~~~~~~~~~~~~+For reasons that are not entirely clear, method bindings come out looking like+this:++ AbsBinds [] [] [$cfromT <= [] fromT]+ $cfromT [InlPrag=INLINE] :: T Bool -> Bool+ { AbsBinds [] [] [fromT <= [] fromT_1]+ fromT :: T Bool -> Bool+ { fromT_1 ((TBool b)) = not b } } }++Note the nested AbsBind. The arity for the InlineRule on $cfromT should be+gotten from the binding for fromT_1.++It might be better to have just one level of AbsBinds, but that requires more+thought!+++Note [Desugar Strict binds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~++Desugaring strict variable bindings looks as follows (core below ==>)++ let !x = rhs+ in body+==>+ let x = rhs+ in x `seq` body -- seq the variable++and if it is a pattern binding the desugaring looks like++ let !pat = rhs+ in body+==>+ let x = rhs -- bind the rhs to a new variable+ pat = x+ in x `seq` body -- seq the new variable++if there is no variable in the pattern desugaring looks like++ let False = rhs+ in body+==>+ let x = case rhs of {False -> (); _ -> error "Match failed"}+ in x `seq` body++In order to force the Ids in the binding group they are passed around+in the dsHsBind family of functions, and later seq'ed in DsExpr.ds_val_bind.++Consider a recursive group like this++ letrec+ f : g = rhs[f,g]+ in <body>++Without `Strict`, we get a translation like this:++ let t = /\a. letrec tm = rhs[fm,gm]+ fm = case t of fm:_ -> fm+ gm = case t of _:gm -> gm+ in+ (fm,gm)++ in let f = /\a. case t a of (fm,_) -> fm+ in let g = /\a. case t a of (_,gm) -> gm+ in <body>++Here `tm` is the monomorphic binding for `rhs`.++With `Strict`, we want to force `tm`, but NOT `fm` or `gm`.+Alas, `tm` isn't in scope in the `in <body>` part.++The simplest thing is to return it in the polymorphic+tuple `t`, thus:++ let t = /\a. letrec tm = rhs[fm,gm]+ fm = case t of fm:_ -> fm+ gm = case t of _:gm -> gm+ in+ (tm, fm, gm)++ in let f = /\a. case t a of (_,fm,_) -> fm+ in let g = /\a. case t a of (_,_,gm) -> gm+ in let tm = /\a. case t a of (tm,_,_) -> tm+ in tm `seq` <body>+++See https://ghc.haskell.org/trac/ghc/wiki/StrictPragma for a more+detailed explanation of the desugaring of strict bindings.++Note [Strict binds checks]+~~~~~~~~~~~~~~~~~~~~~~~~~~+There are several checks around properly formed strict bindings. They+all link to this Note. These checks must be here in the desugarer because+we cannot know whether or not a type is unlifted until after zonking, due+to levity polymorphism. These checks all used to be handled in the typechecker+in checkStrictBinds (before Jan '17).++We define an "unlifted bind" to be any bind that binds an unlifted id. Note that++ x :: Char+ (# True, x #) = blah++is *not* an unlifted bind. Unlifted binds are detected by HsUtils.isUnliftedHsBind.++Define a "banged bind" to have a top-level bang. Detected by HsPat.isBangedPatBind.+Define a "strict bind" to be either an unlifted bind or a banged bind.++The restrictions are:+ 1. Strict binds may not be top-level. Checked in dsTopLHsBinds.++ 2. Unlifted binds must also be banged. (There is no trouble to compile an unbanged+ unlifted bind, but an unbanged bind looks lazy, and we don't want users to be+ surprised by the strictness of an unlifted bind.) Checked in first clause+ of DsExpr.ds_val_bind.++ 3. Unlifted binds may not have polymorphism (#6078). (That is, no quantified type+ variables or constraints.) Checked in first clause+ of DsExpr.ds_val_bind.++ 4. Unlifted binds may not be recursive. Checked in second clause of ds_val_bind.++-}++------------------------+dsSpecs :: CoreExpr -- Its rhs+ -> TcSpecPrags+ -> DsM ( OrdList (Id,CoreExpr) -- Binding for specialised Ids+ , [CoreRule] ) -- Rules for the Global Ids+-- See Note [Handling SPECIALISE pragmas] in TcBinds+dsSpecs _ IsDefaultMethod = return (nilOL, [])+dsSpecs poly_rhs (SpecPrags sps)+ = do { pairs <- mapMaybeM (dsSpec (Just poly_rhs)) sps+ ; let (spec_binds_s, rules) = unzip pairs+ ; return (concatOL spec_binds_s, rules) }++dsSpec :: Maybe CoreExpr -- Just rhs => RULE is for a local binding+ -- Nothing => RULE is for an imported Id+ -- rhs is in the Id's unfolding+ -> Located TcSpecPrag+ -> DsM (Maybe (OrdList (Id,CoreExpr), CoreRule))+dsSpec mb_poly_rhs (L loc (SpecPrag poly_id spec_co spec_inl))+ | isJust (isClassOpId_maybe poly_id)+ = putSrcSpanDs loc $+ do { warnDs NoReason (text "Ignoring useless SPECIALISE pragma for class method selector"+ <+> quotes (ppr poly_id))+ ; return Nothing } -- There is no point in trying to specialise a class op+ -- Moreover, classops don't (currently) have an inl_sat arity set+ -- (it would be Just 0) and that in turn makes makeCorePair bleat++ | no_act_spec && isNeverActive rule_act+ = putSrcSpanDs loc $+ do { warnDs NoReason (text "Ignoring useless SPECIALISE pragma for NOINLINE function:"+ <+> quotes (ppr poly_id))+ ; return Nothing } -- Function is NOINLINE, and the specialiation inherits that+ -- See Note [Activation pragmas for SPECIALISE]++ | otherwise+ = putSrcSpanDs loc $+ do { uniq <- newUnique+ ; let poly_name = idName poly_id+ spec_occ = mkSpecOcc (getOccName poly_name)+ spec_name = mkInternalName uniq spec_occ (getSrcSpan poly_name)+ (spec_bndrs, spec_app) = collectHsWrapBinders spec_co+ -- spec_co looks like+ -- \spec_bndrs. [] spec_args+ -- perhaps with the body of the lambda wrapped in some WpLets+ -- E.g. /\a \(d:Eq a). let d2 = $df d in [] (Maybe a) d2++ ; core_app <- dsHsWrapper spec_app++ ; let ds_lhs = core_app (Var poly_id)+ spec_ty = mkLamTypes spec_bndrs (exprType ds_lhs)+ ; -- pprTrace "dsRule" (vcat [ text "Id:" <+> ppr poly_id+ -- , text "spec_co:" <+> ppr spec_co+ -- , text "ds_rhs:" <+> ppr ds_lhs ]) $+ case decomposeRuleLhs spec_bndrs ds_lhs of {+ Left msg -> do { warnDs NoReason msg; return Nothing } ;+ Right (rule_bndrs, _fn, args) -> do++ { dflags <- getDynFlags+ ; this_mod <- getModule+ ; let fn_unf = realIdUnfolding poly_id+ spec_unf = specUnfolding spec_bndrs core_app arity_decrease fn_unf+ spec_id = mkLocalId spec_name spec_ty+ `setInlinePragma` inl_prag+ `setIdUnfolding` spec_unf+ arity_decrease = count isValArg args - count isId spec_bndrs++ ; rule <- dsMkUserRule this_mod is_local_id+ (mkFastString ("SPEC " ++ showPpr dflags poly_name))+ rule_act poly_name+ rule_bndrs args+ (mkVarApps (Var spec_id) spec_bndrs)++ ; let spec_rhs = mkLams spec_bndrs (core_app poly_rhs)++-- Commented out: see Note [SPECIALISE on INLINE functions]+-- ; when (isInlinePragma id_inl)+-- (warnDs $ text "SPECIALISE pragma on INLINE function probably won't fire:"+-- <+> quotes (ppr poly_name))++ ; return (Just (unitOL (spec_id, spec_rhs), rule))+ -- NB: do *not* use makeCorePair on (spec_id,spec_rhs), because+ -- makeCorePair overwrites the unfolding, which we have+ -- just created using specUnfolding+ } } }+ where+ is_local_id = isJust mb_poly_rhs+ poly_rhs | Just rhs <- mb_poly_rhs+ = rhs -- Local Id; this is its rhs+ | Just unfolding <- maybeUnfoldingTemplate (realIdUnfolding poly_id)+ = unfolding -- Imported Id; this is its unfolding+ -- Use realIdUnfolding so we get the unfolding+ -- even when it is a loop breaker.+ -- We want to specialise recursive functions!+ | otherwise = pprPanic "dsImpSpecs" (ppr poly_id)+ -- The type checker has checked that it *has* an unfolding++ id_inl = idInlinePragma poly_id++ -- See Note [Activation pragmas for SPECIALISE]+ inl_prag | not (isDefaultInlinePragma spec_inl) = spec_inl+ | not is_local_id -- See Note [Specialising imported functions]+ -- in OccurAnal+ , isStrongLoopBreaker (idOccInfo poly_id) = neverInlinePragma+ | otherwise = id_inl+ -- Get the INLINE pragma from SPECIALISE declaration, or,+ -- failing that, from the original Id++ spec_prag_act = inlinePragmaActivation spec_inl++ -- See Note [Activation pragmas for SPECIALISE]+ -- no_act_spec is True if the user didn't write an explicit+ -- phase specification in the SPECIALISE pragma+ no_act_spec = case inlinePragmaSpec spec_inl of+ NoInline -> isNeverActive spec_prag_act+ _ -> isAlwaysActive spec_prag_act+ rule_act | no_act_spec = inlinePragmaActivation id_inl -- Inherit+ | otherwise = spec_prag_act -- Specified by user+++dsMkUserRule :: Module -> Bool -> RuleName -> Activation+ -> Name -> [CoreBndr] -> [CoreExpr] -> CoreExpr -> DsM CoreRule+dsMkUserRule this_mod is_local name act fn bndrs args rhs = do+ let rule = mkRule this_mod False is_local name act fn bndrs args rhs+ dflags <- getDynFlags+ when (isOrphan (ru_orphan rule) && wopt Opt_WarnOrphans dflags) $+ warnDs (Reason Opt_WarnOrphans) (ruleOrphWarn rule)+ return rule++ruleOrphWarn :: CoreRule -> SDoc+ruleOrphWarn rule = text "Orphan rule:" <+> ppr rule++{- Note [SPECIALISE on INLINE functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We used to warn that using SPECIALISE for a function marked INLINE+would be a no-op; but it isn't! Especially with worker/wrapper split+we might have+ {-# INLINE f #-}+ f :: Ord a => Int -> a -> ...+ f d x y = case x of I# x' -> $wf d x' y++We might want to specialise 'f' so that we in turn specialise '$wf'.+We can't even /name/ '$wf' in the source code, so we can't specialise+it even if we wanted to. Trac #10721 is a case in point.++Note [Activation pragmas for SPECIALISE]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+From a user SPECIALISE pragma for f, we generate+ a) A top-level binding spec_fn = rhs+ b) A RULE f dOrd = spec_fn++We need two pragma-like things:++* spec_fn's inline pragma: inherited from f's inline pragma (ignoring+ activation on SPEC), unless overriden by SPEC INLINE++* Activation of RULE: from SPECIALISE pragma (if activation given)+ otherwise from f's inline pragma++This is not obvious (see Trac #5237)!++Examples Rule activation Inline prag on spec'd fn+---------------------------------------------------------------------+SPEC [n] f :: ty [n] Always, or NOINLINE [n]+ copy f's prag++NOINLINE f+SPEC [n] f :: ty [n] NOINLINE+ copy f's prag++NOINLINE [k] f+SPEC [n] f :: ty [n] NOINLINE [k]+ copy f's prag++INLINE [k] f+SPEC [n] f :: ty [n] INLINE [k]+ copy f's prag++SPEC INLINE [n] f :: ty [n] INLINE [n]+ (ignore INLINE prag on f,+ same activation for rule and spec'd fn)++NOINLINE [k] f+SPEC f :: ty [n] INLINE [k]+++************************************************************************+* *+\subsection{Adding inline pragmas}+* *+************************************************************************+-}++decomposeRuleLhs :: [Var] -> CoreExpr -> Either SDoc ([Var], Id, [CoreExpr])+-- (decomposeRuleLhs bndrs lhs) takes apart the LHS of a RULE,+-- The 'bndrs' are the quantified binders of the rules, but decomposeRuleLhs+-- may add some extra dictionary binders (see Note [Free dictionaries])+--+-- Returns an error message if the LHS isn't of the expected shape+-- Note [Decomposing the left-hand side of a RULE]+decomposeRuleLhs orig_bndrs orig_lhs+ | not (null unbound) -- Check for things unbound on LHS+ -- See Note [Unused spec binders]+ = Left (vcat (map dead_msg unbound))+ | Var funId <- fun2+ , Just con <- isDataConId_maybe funId+ = Left (constructor_msg con) -- See Note [No RULES on datacons]+ | Just (fn_id, args) <- decompose fun2 args2+ , let extra_bndrs = mk_extra_bndrs fn_id args+ = -- pprTrace "decmposeRuleLhs" (vcat [ text "orig_bndrs:" <+> ppr orig_bndrs+ -- , text "orig_lhs:" <+> ppr orig_lhs+ -- , text "lhs1:" <+> ppr lhs1+ -- , text "extra_dict_bndrs:" <+> ppr extra_dict_bndrs+ -- , text "fn_id:" <+> ppr fn_id+ -- , text "args:" <+> ppr args]) $+ Right (orig_bndrs ++ extra_bndrs, fn_id, args)++ | otherwise+ = Left bad_shape_msg+ where+ lhs1 = drop_dicts orig_lhs+ lhs2 = simpleOptExpr lhs1 -- See Note [Simplify rule LHS]+ (fun2,args2) = collectArgs lhs2++ lhs_fvs = exprFreeVars lhs2+ unbound = filterOut (`elemVarSet` lhs_fvs) orig_bndrs++ orig_bndr_set = mkVarSet orig_bndrs++ -- Add extra tyvar binders: Note [Free tyvars in rule LHS]+ -- and extra dict binders: Note [Free dictionaries in rule LHS]+ mk_extra_bndrs fn_id args+ = toposortTyVars unbound_tvs ++ unbound_dicts+ where+ unbound_tvs = [ v | v <- unbound_vars, isTyVar v ]+ unbound_dicts = [ mkLocalId (localiseName (idName d)) (idType d)+ | d <- unbound_vars, isDictId d ]+ unbound_vars = [ v | v <- exprsFreeVarsList args+ , not (v `elemVarSet` orig_bndr_set)+ , not (v == fn_id) ]+ -- fn_id: do not quantify over the function itself, which may+ -- itself be a dictionary (in pathological cases, Trac #10251)++ decompose (Var fn_id) args+ | not (fn_id `elemVarSet` orig_bndr_set)+ = Just (fn_id, args)++ decompose _ _ = Nothing++ bad_shape_msg = hang (text "RULE left-hand side too complicated to desugar")+ 2 (vcat [ text "Optimised lhs:" <+> ppr lhs2+ , text "Orig lhs:" <+> ppr orig_lhs])+ dead_msg bndr = hang (sep [ text "Forall'd" <+> pp_bndr bndr+ , text "is not bound in RULE lhs"])+ 2 (vcat [ text "Orig bndrs:" <+> ppr orig_bndrs+ , text "Orig lhs:" <+> ppr orig_lhs+ , text "optimised lhs:" <+> ppr lhs2 ])+ pp_bndr bndr+ | isTyVar bndr = text "type variable" <+> quotes (ppr bndr)+ | Just pred <- evVarPred_maybe bndr = text "constraint" <+> quotes (ppr pred)+ | otherwise = text "variable" <+> quotes (ppr bndr)++ constructor_msg con = vcat+ [ text "A constructor," <+> ppr con <>+ text ", appears as outermost match in RULE lhs."+ , text "This rule will be ignored." ]++ drop_dicts :: CoreExpr -> CoreExpr+ drop_dicts e+ = wrap_lets needed bnds body+ where+ needed = orig_bndr_set `minusVarSet` exprFreeVars body+ (bnds, body) = split_lets (occurAnalyseExpr e)+ -- The occurAnalyseExpr drops dead bindings which is+ -- crucial to ensure that every binding is used later;+ -- which in turn makes wrap_lets work right++ split_lets :: CoreExpr -> ([(DictId,CoreExpr)], CoreExpr)+ split_lets (Let (NonRec d r) body)+ | isDictId d+ = ((d,r):bs, body')+ where (bs, body') = split_lets body++ -- handle "unlifted lets" too, needed for "map/coerce"+ split_lets (Case r d _ [(DEFAULT, _, body)])+ | isCoVar d+ = ((d,r):bs, body')+ where (bs, body') = split_lets body++ split_lets e = ([], e)++ wrap_lets :: VarSet -> [(DictId,CoreExpr)] -> CoreExpr -> CoreExpr+ wrap_lets _ [] body = body+ wrap_lets needed ((d, r) : bs) body+ | rhs_fvs `intersectsVarSet` needed = mkCoreLet (NonRec d r) (wrap_lets needed' bs body)+ | otherwise = wrap_lets needed bs body+ where+ rhs_fvs = exprFreeVars r+ needed' = (needed `minusVarSet` rhs_fvs) `extendVarSet` d++{-+Note [Decomposing the left-hand side of a RULE]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There are several things going on here.+* drop_dicts: see Note [Drop dictionary bindings on rule LHS]+* simpleOptExpr: see Note [Simplify rule LHS]+* extra_dict_bndrs: see Note [Free dictionaries]++Note [Free tyvars on rule LHS]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T a = C++ foo :: T a -> Int+ foo C = 1++ {-# RULES "myrule" foo C = 1 #-}++After type checking the LHS becomes (foo alpha (C alpha)), where alpha+is an unbound meta-tyvar. The zonker in TcHsSyn is careful not to+turn the free alpha into Any (as it usually does). Instead it turns it+into a TyVar 'a'. See TcHsSyn Note [Zonking the LHS of a RULE].++Now we must quantify over that 'a'. It's /really/ inconvenient to do that+in the zonker, because the HsExpr data type is very large. But it's /easy/+to do it here in the desugarer.++Moreover, we have to do something rather similar for dictionaries;+see Note [Free dictionaries on rule LHS]. So that's why we look for+type variables free on the LHS, and quantify over them.++Note [Free dictionaries on rule LHS]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When the LHS of a specialisation rule, (/\as\ds. f es) has a free dict,+which is presumably in scope at the function definition site, we can quantify+over it too. *Any* dict with that type will do.++So for example when you have+ f :: Eq a => a -> a+ f = <rhs>+ ... SPECIALISE f :: Int -> Int ...++Then we get the SpecPrag+ SpecPrag (f Int dInt)++And from that we want the rule++ RULE forall dInt. f Int dInt = f_spec+ f_spec = let f = <rhs> in f Int dInt++But be careful! That dInt might be GHC.Base.$fOrdInt, which is an External+Name, and you can't bind them in a lambda or forall without getting things+confused. Likewise it might have an InlineRule or something, which would be+utterly bogus. So we really make a fresh Id, with the same unique and type+as the old one, but with an Internal name and no IdInfo.++Note [Drop dictionary bindings on rule LHS]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+drop_dicts drops dictionary bindings on the LHS where possible.+ E.g. let d:Eq [Int] = $fEqList $fEqInt in f d+ --> f d+ Reasoning here is that there is only one d:Eq [Int], and so we can+ quantify over it. That makes 'd' free in the LHS, but that is later+ picked up by extra_dict_bndrs (Note [Dead spec binders]).++ NB 1: We can only drop the binding if the RHS doesn't bind+ one of the orig_bndrs, which we assume occur on RHS.+ Example+ f :: (Eq a) => b -> a -> a+ {-# SPECIALISE f :: Eq a => b -> [a] -> [a] #-}+ Here we want to end up with+ RULE forall d:Eq a. f ($dfEqList d) = f_spec d+ Of course, the ($dfEqlist d) in the pattern makes it less likely+ to match, but there is no other way to get d:Eq a++ NB 2: We do drop_dicts *before* simplOptEpxr, so that we expect all+ the evidence bindings to be wrapped around the outside of the+ LHS. (After simplOptExpr they'll usually have been inlined.)+ dsHsWrapper does dependency analysis, so that civilised ones+ will be simple NonRec bindings. We don't handle recursive+ dictionaries!++ NB3: In the common case of a non-overloaded, but perhaps-polymorphic+ specialisation, we don't need to bind *any* dictionaries for use+ in the RHS. For example (Trac #8331)+ {-# SPECIALIZE INLINE useAbstractMonad :: ReaderST s Int #-}+ useAbstractMonad :: MonadAbstractIOST m => m Int+ Here, deriving (MonadAbstractIOST (ReaderST s)) is a lot of code+ but the RHS uses no dictionaries, so we want to end up with+ RULE forall s (d :: MonadAbstractIOST (ReaderT s)).+ useAbstractMonad (ReaderT s) d = $suseAbstractMonad s++ Trac #8848 is a good example of where there are some intersting+ dictionary bindings to discard.++The drop_dicts algorithm is based on these observations:++ * Given (let d = rhs in e) where d is a DictId,+ matching 'e' will bind e's free variables.++ * So we want to keep the binding if one of the needed variables (for+ which we need a binding) is in fv(rhs) but not already in fv(e).++ * The "needed variables" are simply the orig_bndrs. Consider+ f :: (Eq a, Show b) => a -> b -> String+ ... SPECIALISE f :: (Show b) => Int -> b -> String ...+ Then orig_bndrs includes the *quantified* dictionaries of the type+ namely (dsb::Show b), but not the one for Eq Int++So we work inside out, applying the above criterion at each step.+++Note [Simplify rule LHS]+~~~~~~~~~~~~~~~~~~~~~~~~+simplOptExpr occurrence-analyses and simplifies the LHS:++ (a) Inline any remaining dictionary bindings (which hopefully+ occur just once)++ (b) Substitute trivial lets, so that they don't get in the way.+ Note that we substitute the function too; we might+ have this as a LHS: let f71 = M.f Int in f71++ (c) Do eta reduction. To see why, consider the fold/build rule,+ which without simplification looked like:+ fold k z (build (/\a. g a)) ==> ...+ This doesn't match unless you do eta reduction on the build argument.+ Similarly for a LHS like+ augment g (build h)+ we do not want to get+ augment (\a. g a) (build h)+ otherwise we don't match when given an argument like+ augment (\a. h a a) (build h)++Note [Matching seqId]+~~~~~~~~~~~~~~~~~~~+The desugarer turns (seq e r) into (case e of _ -> r), via a special-case hack+and this code turns it back into an application of seq!+See Note [Rules for seq] in MkId for the details.++Note [Unused spec binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f :: a -> a+ ... SPECIALISE f :: Eq a => a -> a ...+It's true that this *is* a more specialised type, but the rule+we get is something like this:+ f_spec d = f+ RULE: f = f_spec d+Note that the rule is bogus, because it mentions a 'd' that is+not bound on the LHS! But it's a silly specialisation anyway, because+the constraint is unused. We could bind 'd' to (error "unused")+but it seems better to reject the program because it's almost certainly+a mistake. That's what the isDeadBinder call detects.++Note [No RULES on datacons]+~~~~~~~~~~~~~~~~~~~~~~~~~~~++Previously, `RULES` like++ "JustNothing" forall x . Just x = Nothing++were allowed. Simon Peyton Jones says this seems to have been a+mistake, that such rules have never been supported intentionally,+and that he doesn't know if they can break in horrible ways.+Furthermore, Ben Gamari and Reid Barton are considering trying to+detect the presence of "static data" that the simplifier doesn't+need to traverse at all. Such rules do not play well with that.+So for now, we ban them altogether as requested by #13290. See also #7398.+++************************************************************************+* *+ Desugaring evidence+* *+************************************************************************++-}++dsHsWrapper :: HsWrapper -> DsM (CoreExpr -> CoreExpr)+dsHsWrapper WpHole = return $ \e -> e+dsHsWrapper (WpTyApp ty) = return $ \e -> App e (Type ty)+dsHsWrapper (WpEvLam ev) = return $ Lam ev+dsHsWrapper (WpTyLam tv) = return $ Lam tv+dsHsWrapper (WpLet ev_binds) = do { bs <- dsTcEvBinds ev_binds+ ; return (mkCoreLets bs) }+dsHsWrapper (WpCompose c1 c2) = do { w1 <- dsHsWrapper c1+ ; w2 <- dsHsWrapper c2+ ; return (w1 . w2) }+ -- See comments on WpFun in TcEvidence for an explanation of what+ -- the specification of this clause is+dsHsWrapper (WpFun c1 c2 t1 doc)+ = do { x <- newSysLocalDsNoLP t1+ ; w1 <- dsHsWrapper c1+ ; w2 <- dsHsWrapper c2+ ; let app f a = mkCoreAppDs (text "dsHsWrapper") f a+ arg = w1 (Var x)+ ; (_, ok) <- askNoErrsDs $ dsNoLevPolyExpr arg doc+ ; if ok+ then return (\e -> (Lam x (w2 (app e arg))))+ else return id } -- this return is irrelevant+dsHsWrapper (WpCast co) = ASSERT(coercionRole co == Representational)+ return $ \e -> mkCastDs e co+dsHsWrapper (WpEvApp tm) = do { core_tm <- dsEvTerm tm+ ; return (\e -> App e core_tm) }++--------------------------------------+dsTcEvBinds_s :: [TcEvBinds] -> DsM [CoreBind]+dsTcEvBinds_s [] = return []+dsTcEvBinds_s (b:rest) = ASSERT( null rest ) -- Zonker ensures null+ dsTcEvBinds b++dsTcEvBinds :: TcEvBinds -> DsM [CoreBind]+dsTcEvBinds (TcEvBinds {}) = panic "dsEvBinds" -- Zonker has got rid of this+dsTcEvBinds (EvBinds bs) = dsEvBinds bs++dsEvBinds :: Bag EvBind -> DsM [CoreBind]+dsEvBinds bs = mapM ds_scc (sccEvBinds bs)+ where+ ds_scc (AcyclicSCC (EvBind { eb_lhs = v, eb_rhs = r}))+ = liftM (NonRec v) (dsEvTerm r)+ ds_scc (CyclicSCC bs) = liftM Rec (mapM dsEvBind bs)++dsEvBind :: EvBind -> DsM (Id, CoreExpr)+dsEvBind (EvBind { eb_lhs = v, eb_rhs = r}) = liftM ((,) v) (dsEvTerm r)++{-**********************************************************************+* *+ Desugaring EvTerms+* *+**********************************************************************-}++dsEvTerm :: EvTerm -> DsM CoreExpr+dsEvTerm (EvId v) = return (Var v)+dsEvTerm (EvCallStack cs) = dsEvCallStack cs+dsEvTerm (EvTypeable ty ev) = dsEvTypeable ty ev+dsEvTerm (EvLit (EvNum n)) = mkNaturalExpr n+dsEvTerm (EvLit (EvStr s)) = mkStringExprFS s++dsEvTerm (EvCast tm co)+ = do { tm' <- dsEvTerm tm+ ; return $ mkCastDs tm' co }++dsEvTerm (EvDFunApp df tys tms)+ = do { tms' <- mapM dsEvTerm tms+ ; return $ Var df `mkTyApps` tys `mkApps` tms' }+ -- The use of mkApps here is OK vis-a-vis levity polymorphism because+ -- the terms are always evidence variables with types of kind Constraint++dsEvTerm (EvCoercion co) = return (Coercion co)+dsEvTerm (EvSuperClass d n)+ = do { d' <- dsEvTerm d+ ; let (cls, tys) = getClassPredTys (exprType d')+ sc_sel_id = classSCSelId cls n -- Zero-indexed+ ; return $ Var sc_sel_id `mkTyApps` tys `App` d' }++dsEvTerm (EvSelector sel_id tys tms)+ = do { tms' <- mapM dsEvTerm tms+ ; return $ Var sel_id `mkTyApps` tys `mkApps` tms' }++dsEvTerm (EvDelayedError ty msg) = return $ dsEvDelayedError ty msg++dsEvDelayedError :: Type -> FastString -> CoreExpr+dsEvDelayedError ty msg+ = Var errorId `mkTyApps` [getRuntimeRep "dsEvTerm" ty, ty] `mkApps` [litMsg]+ where+ errorId = tYPE_ERROR_ID+ litMsg = Lit (MachStr (fastStringToByteString msg))++{-**********************************************************************+* *+ Desugaring Typeable dictionaries+* *+**********************************************************************-}++dsEvTypeable :: Type -> EvTypeable -> DsM CoreExpr+-- Return a CoreExpr :: Typeable ty+-- This code is tightly coupled to the representation+-- of TypeRep, in base library Data.Typeable.Internals+dsEvTypeable ty ev+ = do { tyCl <- dsLookupTyCon typeableClassName -- Typeable+ ; let kind = typeKind ty+ Just typeable_data_con+ = tyConSingleDataCon_maybe tyCl -- "Data constructor"+ -- for Typeable++ ; rep_expr <- ds_ev_typeable ty ev -- :: TypeRep a++ -- Package up the method as `Typeable` dictionary+ ; return $ mkConApp typeable_data_con [Type kind, Type ty, rep_expr] }++type TypeRepExpr = CoreExpr++-- | Returns a @CoreExpr :: TypeRep ty@+ds_ev_typeable :: Type -> EvTypeable -> DsM CoreExpr+ds_ev_typeable ty (EvTypeableTyCon tc kind_ev)+ = do { mkTrCon <- dsLookupGlobalId mkTrConName+ -- mkTrCon :: forall k (a :: k). TyCon -> TypeRep k -> TypeRep a+ ; someTypeRepTyCon <- dsLookupTyCon someTypeRepTyConName+ ; someTypeRepDataCon <- dsLookupDataCon someTypeRepDataConName+ -- SomeTypeRep :: forall k (a :: k). TypeRep a -> SomeTypeRep++ ; tc_rep <- tyConRep tc -- :: TyCon+ ; let ks = tyConAppArgs ty+ -- Construct a SomeTypeRep+ toSomeTypeRep :: Type -> EvTerm -> DsM CoreExpr+ toSomeTypeRep t ev = do+ rep <- getRep ev t+ return $ mkCoreConApps someTypeRepDataCon [Type (typeKind t), Type t, rep]+ ; kind_arg_reps <- sequence $ zipWith toSomeTypeRep ks kind_ev -- :: TypeRep t+ ; let -- :: [SomeTypeRep]+ kind_args = mkListExpr (mkTyConTy someTypeRepTyCon) kind_arg_reps++ -- Note that we use the kind of the type, not the TyCon from which it+ -- is constructed since the latter may be kind polymorphic whereas the+ -- former we know is not (we checked in the solver).+ ; return $ mkApps (Var mkTrCon) [ Type (typeKind ty)+ , Type ty+ , tc_rep+ , kind_args ]+ }++ds_ev_typeable ty (EvTypeableTyApp ev1 ev2)+ | Just (t1,t2) <- splitAppTy_maybe ty+ = do { e1 <- getRep ev1 t1+ ; e2 <- getRep ev2 t2+ ; mkTrApp <- dsLookupGlobalId mkTrAppName+ -- mkTrApp :: forall k1 k2 (a :: k1 -> k2) (b :: k1).+ -- TypeRep a -> TypeRep b -> TypeRep (a b)+ ; let (k1, k2) = splitFunTy (typeKind t1)+ ; return $ mkApps (mkTyApps (Var mkTrApp) [ k1, k2, t1, t2 ])+ [ e1, e2 ] }++ds_ev_typeable ty (EvTypeableTrFun ev1 ev2)+ | Just (t1,t2) <- splitFunTy_maybe ty+ = do { e1 <- getRep ev1 t1+ ; e2 <- getRep ev2 t2+ ; mkTrFun <- dsLookupGlobalId mkTrFunName+ -- mkTrFun :: forall r1 r2 (a :: TYPE r1) (b :: TYPE r2).+ -- TypeRep a -> TypeRep b -> TypeRep (a -> b)+ ; let r1 = getRuntimeRep "ds_ev_typeable" t1+ r2 = getRuntimeRep "ds_ev_typeable" t2+ ; return $ mkApps (mkTyApps (Var mkTrFun) [r1, r2, t1, t2])+ [ e1, e2 ]+ }++ds_ev_typeable ty (EvTypeableTyLit ev)+ = do { fun <- dsLookupGlobalId tr_fun+ ; dict <- dsEvTerm ev -- Of type KnownNat/KnownSym+ ; let proxy = mkTyApps (Var proxyHashId) [ty_kind, ty]+ ; return (mkApps (mkTyApps (Var fun) [ty]) [ dict, proxy ]) }+ where+ ty_kind = typeKind ty++ -- tr_fun is the Name of+ -- typeNatTypeRep :: KnownNat a => Proxy# a -> TypeRep a+ -- of typeSymbolTypeRep :: KnownSymbol a => Proxy# a -> TypeRep a+ tr_fun | ty_kind `eqType` typeNatKind = typeNatTypeRepName+ | ty_kind `eqType` typeSymbolKind = typeSymbolTypeRepName+ | otherwise = panic "dsEvTypeable: unknown type lit kind"++ds_ev_typeable ty ev+ = pprPanic "dsEvTypeable" (ppr ty $$ ppr ev)++getRep :: EvTerm -- ^ EvTerm for @Typeable ty@+ -> Type -- ^ The type @ty@+ -> DsM TypeRepExpr -- ^ Return @CoreExpr :: TypeRep ty@+ -- namely @typeRep# dict@+-- Remember that+-- typeRep# :: forall k (a::k). Typeable k a -> TypeRep a+getRep ev ty+ = do { typeable_expr <- dsEvTerm ev+ ; typeRepId <- dsLookupGlobalId typeRepIdName+ ; let ty_args = [typeKind ty, ty]+ ; return (mkApps (mkTyApps (Var typeRepId) ty_args) [ typeable_expr ]) }++tyConRep :: TyCon -> DsM CoreExpr+-- Returns CoreExpr :: TyCon+tyConRep tc+ | Just tc_rep_nm <- tyConRepName_maybe tc+ = do { tc_rep_id <- dsLookupGlobalId tc_rep_nm+ ; return (Var tc_rep_id) }+ | otherwise+ = pprPanic "tyConRep" (ppr tc)++{- Note [Memoising typeOf]+~~~~~~~~~~~~~~~~~~~~~~~~~~+See #3245, #9203++IMPORTANT: we don't want to recalculate the TypeRep once per call with+the proxy argument. This is what went wrong in #3245 and #9203. So we+help GHC by manually keeping the 'rep' *outside* the lambda.+-}+++{-**********************************************************************+* *+ Desugaring EvCallStack evidence+* *+**********************************************************************-}++dsEvCallStack :: EvCallStack -> DsM CoreExpr+-- See Note [Overview of implicit CallStacks] in TcEvidence.hs+dsEvCallStack cs = do+ df <- getDynFlags+ m <- getModule+ srcLocDataCon <- dsLookupDataCon srcLocDataConName+ let mkSrcLoc l =+ liftM (mkCoreConApps srcLocDataCon)+ (sequence [ mkStringExprFS (unitIdFS $ moduleUnitId m)+ , mkStringExprFS (moduleNameFS $ moduleName m)+ , mkStringExprFS (srcSpanFile l)+ , return $ mkIntExprInt df (srcSpanStartLine l)+ , return $ mkIntExprInt df (srcSpanStartCol l)+ , return $ mkIntExprInt df (srcSpanEndLine l)+ , return $ mkIntExprInt df (srcSpanEndCol l)+ ])++ emptyCS <- Var <$> dsLookupGlobalId emptyCallStackName++ pushCSVar <- dsLookupGlobalId pushCallStackName+ let pushCS name loc rest =+ mkCoreApps (Var pushCSVar) [mkCoreTup [name, loc], rest]++ let mkPush name loc tm = do+ nameExpr <- mkStringExprFS name+ locExpr <- mkSrcLoc loc+ case tm of+ EvCallStack EvCsEmpty -> return (pushCS nameExpr locExpr emptyCS)+ _ -> do tmExpr <- dsEvTerm tm+ -- at this point tmExpr :: IP sym CallStack+ -- but we need the actual CallStack to pass to pushCS,+ -- so we use unwrapIP to strip the dictionary wrapper+ -- See Note [Overview of implicit CallStacks]+ let ip_co = unwrapIP (exprType tmExpr)+ return (pushCS nameExpr locExpr (mkCastDs tmExpr ip_co))+ case cs of+ EvCsPushCall name loc tm -> mkPush (occNameFS $ getOccName name) loc tm+ EvCsEmpty -> return emptyCS
+ deSugar/DsCCall.hs view
@@ -0,0 +1,377 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1994-1998+++Desugaring foreign calls+-}++{-# LANGUAGE CPP #-}+module DsCCall+ ( dsCCall+ , mkFCall+ , unboxArg+ , boxResult+ , resultWrapper+ ) where++#include "HsVersions.h"+++import CoreSyn++import DsMonad+import CoreUtils+import MkCore+import MkId+import ForeignCall+import DataCon+import DsUtils++import TcType+import Type+import Id ( Id )+import Coercion+import PrimOp+import TysPrim+import TyCon+import TysWiredIn+import BasicTypes+import Literal+import PrelNames+import DynFlags+import Outputable+import Util++import Data.Maybe++{-+Desugaring of @ccall@s consists of adding some state manipulation,+unboxing any boxed primitive arguments and boxing the result if+desired.++The state stuff just consists of adding in+@PrimIO (\ s -> case s of { S# s# -> ... })@ in an appropriate place.++The unboxing is straightforward, as all information needed to unbox is+available from the type. For each boxed-primitive argument, we+transform:+\begin{verbatim}+ _ccall_ foo [ r, t1, ... tm ] e1 ... em+ |+ |+ V+ case e1 of { T1# x1# ->+ ...+ case em of { Tm# xm# -> xm#+ ccall# foo [ r, t1#, ... tm# ] x1# ... xm#+ } ... }+\end{verbatim}++The reboxing of a @_ccall_@ result is a bit tricker: the types don't+contain information about the state-pairing functions so we have to+keep a list of \tr{(type, s-p-function)} pairs. We transform as+follows:+\begin{verbatim}+ ccall# foo [ r, t1#, ... tm# ] e1# ... em#+ |+ |+ V+ \ s# -> case (ccall# foo [ r, t1#, ... tm# ] s# e1# ... em#) of+ (StateAnd<r># result# state#) -> (R# result#, realWorld#)+\end{verbatim}+-}++dsCCall :: CLabelString -- C routine to invoke+ -> [CoreExpr] -- Arguments (desugared)+ -- Precondition: none have levity-polymorphic types+ -> Safety -- Safety of the call+ -> Type -- Type of the result: IO t+ -> DsM CoreExpr -- Result, of type ???++dsCCall lbl args may_gc result_ty+ = do (unboxed_args, arg_wrappers) <- mapAndUnzipM unboxArg args+ (ccall_result_ty, res_wrapper) <- boxResult result_ty+ uniq <- newUnique+ dflags <- getDynFlags+ let+ target = StaticTarget NoSourceText lbl Nothing True+ the_fcall = CCall (CCallSpec target CCallConv may_gc)+ the_prim_app = mkFCall dflags uniq the_fcall unboxed_args ccall_result_ty+ return (foldr ($) (res_wrapper the_prim_app) arg_wrappers)++mkFCall :: DynFlags -> Unique -> ForeignCall+ -> [CoreExpr] -- Args+ -> Type -- Result type+ -> CoreExpr+-- Construct the ccall. The only tricky bit is that the ccall Id should have+-- no free vars, so if any of the arg tys do we must give it a polymorphic type.+-- [I forget *why* it should have no free vars!]+-- For example:+-- mkCCall ... [s::StablePtr (a->b), x::Addr, c::Char]+--+-- Here we build a ccall thus+-- (ccallid::(forall a b. StablePtr (a -> b) -> Addr -> Char -> IO Addr))+-- a b s x c+mkFCall dflags uniq the_fcall val_args res_ty+ = ASSERT( all isTyVar tyvars ) -- this must be true because the type is top-level+ mkApps (mkVarApps (Var the_fcall_id) tyvars) val_args+ where+ arg_tys = map exprType val_args+ body_ty = (mkFunTys arg_tys res_ty)+ tyvars = tyCoVarsOfTypeWellScoped body_ty+ ty = mkInvForAllTys tyvars body_ty+ the_fcall_id = mkFCallId dflags uniq the_fcall ty++unboxArg :: CoreExpr -- The supplied argument, not levity-polymorphic+ -> DsM (CoreExpr, -- To pass as the actual argument+ CoreExpr -> CoreExpr -- Wrapper to unbox the arg+ )+-- Example: if the arg is e::Int, unboxArg will return+-- (x#::Int#, \W. case x of I# x# -> W)+-- where W is a CoreExpr that probably mentions x#++-- always returns a non-levity-polymorphic expression++unboxArg arg+ -- Primtive types: nothing to unbox+ | isPrimitiveType arg_ty+ = return (arg, \body -> body)++ -- Recursive newtypes+ | Just(co, _rep_ty) <- topNormaliseNewType_maybe arg_ty+ = unboxArg (mkCastDs arg co)++ -- Booleans+ | Just tc <- tyConAppTyCon_maybe arg_ty,+ tc `hasKey` boolTyConKey+ = do dflags <- getDynFlags+ prim_arg <- newSysLocalDs intPrimTy+ return (Var prim_arg,+ \ body -> Case (mkWildCase arg arg_ty intPrimTy+ [(DataAlt falseDataCon,[],mkIntLit dflags 0),+ (DataAlt trueDataCon, [],mkIntLit dflags 1)])+ -- In increasing tag order!+ prim_arg+ (exprType body)+ [(DEFAULT,[],body)])++ -- Data types with a single constructor, which has a single, primitive-typed arg+ -- This deals with Int, Float etc; also Ptr, ForeignPtr+ | is_product_type && data_con_arity == 1+ = ASSERT2(isUnliftedType data_con_arg_ty1, pprType arg_ty)+ -- Typechecker ensures this+ do case_bndr <- newSysLocalDs arg_ty+ prim_arg <- newSysLocalDs data_con_arg_ty1+ return (Var prim_arg,+ \ body -> Case arg case_bndr (exprType body) [(DataAlt data_con,[prim_arg],body)]+ )++ -- Byte-arrays, both mutable and otherwise; hack warning+ -- We're looking for values of type ByteArray, MutableByteArray+ -- data ByteArray ix = ByteArray ix ix ByteArray#+ -- data MutableByteArray s ix = MutableByteArray ix ix (MutableByteArray# s)+ | is_product_type &&+ data_con_arity == 3 &&+ isJust maybe_arg3_tycon &&+ (arg3_tycon == byteArrayPrimTyCon ||+ arg3_tycon == mutableByteArrayPrimTyCon)+ = do case_bndr <- newSysLocalDs arg_ty+ vars@[_l_var, _r_var, arr_cts_var] <- newSysLocalsDs data_con_arg_tys+ return (Var arr_cts_var,+ \ body -> Case arg case_bndr (exprType body) [(DataAlt data_con,vars,body)]+ )++ | otherwise+ = do l <- getSrcSpanDs+ pprPanic "unboxArg: " (ppr l <+> ppr arg_ty)+ where+ arg_ty = exprType arg+ maybe_product_type = splitDataProductType_maybe arg_ty+ is_product_type = isJust maybe_product_type+ Just (_, _, data_con, data_con_arg_tys) = maybe_product_type+ data_con_arity = dataConSourceArity data_con+ (data_con_arg_ty1 : _) = data_con_arg_tys++ (_ : _ : data_con_arg_ty3 : _) = data_con_arg_tys+ maybe_arg3_tycon = tyConAppTyCon_maybe data_con_arg_ty3+ Just arg3_tycon = maybe_arg3_tycon++boxResult :: Type+ -> DsM (Type, CoreExpr -> CoreExpr)++-- Takes the result of the user-level ccall:+-- either (IO t),+-- or maybe just t for an side-effect-free call+-- Returns a wrapper for the primitive ccall itself, along with the+-- type of the result of the primitive ccall. This result type+-- will be of the form+-- State# RealWorld -> (# State# RealWorld, t' #)+-- where t' is the unwrapped form of t. If t is simply (), then+-- the result type will be+-- State# RealWorld -> (# State# RealWorld #)++boxResult result_ty+ | Just (io_tycon, io_res_ty) <- tcSplitIOType_maybe result_ty+ -- isIOType_maybe handles the case where the type is a+ -- simple wrapping of IO. E.g.+ -- newtype Wrap a = W (IO a)+ -- No coercion necessary because its a non-recursive newtype+ -- (If we wanted to handle a *recursive* newtype too, we'd need+ -- another case, and a coercion.)+ -- The result is IO t, so wrap the result in an IO constructor+ = do { res <- resultWrapper io_res_ty+ ; let extra_result_tys+ = case res of+ (Just ty,_)+ | isUnboxedTupleType ty+ -> let Just ls = tyConAppArgs_maybe ty in tail ls+ _ -> []++ return_result state anss+ = mkCoreUbxTup+ (realWorldStatePrimTy : io_res_ty : extra_result_tys)+ (state : anss)++ ; (ccall_res_ty, the_alt) <- mk_alt return_result res++ ; state_id <- newSysLocalDs realWorldStatePrimTy+ ; let io_data_con = head (tyConDataCons io_tycon)+ toIOCon = dataConWrapId io_data_con++ wrap the_call =+ mkApps (Var toIOCon)+ [ Type io_res_ty,+ Lam state_id $+ mkWildCase (App the_call (Var state_id))+ ccall_res_ty+ (coreAltType the_alt)+ [the_alt]+ ]++ ; return (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap) }++boxResult result_ty+ = do -- It isn't IO, so do unsafePerformIO+ -- It's not conveniently available, so we inline it+ res <- resultWrapper result_ty+ (ccall_res_ty, the_alt) <- mk_alt return_result res+ let+ wrap = \ the_call -> mkWildCase (App the_call (Var realWorldPrimId))+ ccall_res_ty+ (coreAltType the_alt)+ [the_alt]+ return (realWorldStatePrimTy `mkFunTy` ccall_res_ty, wrap)+ where+ return_result _ [ans] = ans+ return_result _ _ = panic "return_result: expected single result"+++mk_alt :: (Expr Var -> [Expr Var] -> Expr Var)+ -> (Maybe Type, Expr Var -> Expr Var)+ -> DsM (Type, (AltCon, [Id], Expr Var))+mk_alt return_result (Nothing, wrap_result)+ = do -- The ccall returns ()+ state_id <- newSysLocalDs realWorldStatePrimTy+ let+ the_rhs = return_result (Var state_id)+ [wrap_result (panic "boxResult")]++ ccall_res_ty = mkTupleTy Unboxed [realWorldStatePrimTy]+ the_alt = (DataAlt (tupleDataCon Unboxed 1), [state_id], the_rhs)++ return (ccall_res_ty, the_alt)++mk_alt return_result (Just prim_res_ty, wrap_result)+ = -- The ccall returns a non-() value+ ASSERT2( isPrimitiveType prim_res_ty, ppr prim_res_ty )+ -- True because resultWrapper ensures it is so+ do { result_id <- newSysLocalDs prim_res_ty+ ; state_id <- newSysLocalDs realWorldStatePrimTy+ ; let the_rhs = return_result (Var state_id)+ [wrap_result (Var result_id)]+ ccall_res_ty = mkTupleTy Unboxed [realWorldStatePrimTy, prim_res_ty]+ the_alt = (DataAlt (tupleDataCon Unboxed 2), [state_id, result_id], the_rhs)+ ; return (ccall_res_ty, the_alt) }+++resultWrapper :: Type+ -> DsM (Maybe Type, -- Type of the expected result, if any+ CoreExpr -> CoreExpr) -- Wrapper for the result+-- resultWrapper deals with the result *value*+-- E.g. foreign import foo :: Int -> IO T+-- Then resultWrapper deals with marshalling the 'T' part+-- So if resultWrapper ty = (Just ty_rep, marshal)+-- then marshal (e :: ty_rep) :: ty+-- That is, 'marshal' wrape the result returned by the foreign call,+-- of type ty_rep, into the value Haskell expected, of type 'ty'+--+-- Invariant: ty_rep is always a primitive type+-- i.e. (isPrimitiveType ty_rep) is True++resultWrapper result_ty+ -- Base case 1: primitive types+ | isPrimitiveType result_ty+ = return (Just result_ty, \e -> e)++ -- Base case 2: the unit type ()+ | Just (tc,_) <- maybe_tc_app+ , tc `hasKey` unitTyConKey+ = return (Nothing, \_ -> Var unitDataConId)++ -- Base case 3: the boolean type+ | Just (tc,_) <- maybe_tc_app+ , tc `hasKey` boolTyConKey+ = do { dflags <- getDynFlags+ ; let marshal_bool e+ = mkWildCase e intPrimTy boolTy+ [ (DEFAULT ,[],Var trueDataConId )+ , (LitAlt (mkMachInt dflags 0),[],Var falseDataConId)]+ ; return (Just intPrimTy, marshal_bool) }++ -- Newtypes+ | Just (co, rep_ty) <- topNormaliseNewType_maybe result_ty+ = do { (maybe_ty, wrapper) <- resultWrapper rep_ty+ ; return (maybe_ty, \e -> mkCastDs (wrapper e) (mkSymCo co)) }++ -- The type might contain foralls (eg. for dummy type arguments,+ -- referring to 'Ptr a' is legal).+ | Just (tyvar, rest) <- splitForAllTy_maybe result_ty+ = do { (maybe_ty, wrapper) <- resultWrapper rest+ ; return (maybe_ty, \e -> Lam tyvar (wrapper e)) }++ -- Data types with a single constructor, which has a single arg+ -- This includes types like Ptr and ForeignPtr+ | Just (tycon, tycon_arg_tys) <- maybe_tc_app+ , Just data_con <- isDataProductTyCon_maybe tycon -- One construtor, no existentials+ , [unwrapped_res_ty] <- dataConInstOrigArgTys data_con tycon_arg_tys -- One argument+ = do { dflags <- getDynFlags+ ; (maybe_ty, wrapper) <- resultWrapper unwrapped_res_ty+ ; let narrow_wrapper = maybeNarrow dflags tycon+ marshal_con e = Var (dataConWrapId data_con)+ `mkTyApps` tycon_arg_tys+ `App` wrapper (narrow_wrapper e)+ ; return (maybe_ty, marshal_con) }++ | otherwise+ = pprPanic "resultWrapper" (ppr result_ty)+ where+ maybe_tc_app = splitTyConApp_maybe result_ty++-- When the result of a foreign call is smaller than the word size, we+-- need to sign- or zero-extend the result up to the word size. The C+-- standard appears to say that this is the responsibility of the+-- caller, not the callee.++maybeNarrow :: DynFlags -> TyCon -> (CoreExpr -> CoreExpr)+maybeNarrow dflags tycon+ | tycon `hasKey` int8TyConKey = \e -> App (Var (mkPrimOpId Narrow8IntOp)) e+ | tycon `hasKey` int16TyConKey = \e -> App (Var (mkPrimOpId Narrow16IntOp)) e+ | tycon `hasKey` int32TyConKey+ && wORD_SIZE dflags > 4 = \e -> App (Var (mkPrimOpId Narrow32IntOp)) e++ | tycon `hasKey` word8TyConKey = \e -> App (Var (mkPrimOpId Narrow8WordOp)) e+ | tycon `hasKey` word16TyConKey = \e -> App (Var (mkPrimOpId Narrow16WordOp)) e+ | tycon `hasKey` word32TyConKey+ && wORD_SIZE dflags > 4 = \e -> App (Var (mkPrimOpId Narrow32WordOp)) e+ | otherwise = id
+ deSugar/DsExpr.hs view
@@ -0,0 +1,1066 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Desugaring exporessions.+-}++{-# LANGUAGE CPP, MultiWayIf #-}++module DsExpr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds+ , dsValBinds, dsLit, dsSyntaxExpr ) where++#include "HsVersions.h"++import Match+import MatchLit+import DsBinds+import DsGRHSs+import DsListComp+import DsUtils+import DsArrows+import DsMonad+import Name+import NameEnv+import FamInstEnv( topNormaliseType )+import DsMeta+import HsSyn++-- NB: The desugarer, which straddles the source and Core worlds, sometimes+-- needs to see source types+import TcType+import TcEvidence+import TcRnMonad+import TcHsSyn+import Type+import CoreSyn+import CoreUtils+import MkCore++import DynFlags+import CostCentre+import Id+import MkId+import Module+import ConLike+import DataCon+import TysWiredIn+import PrelNames+import BasicTypes+import Maybes+import VarEnv+import SrcLoc+import Util+import Bag+import Outputable+import PatSyn++import Control.Monad++{-+************************************************************************+* *+ dsLocalBinds, dsValBinds+* *+************************************************************************+-}++dsLocalBinds :: LHsLocalBinds Id -> CoreExpr -> DsM CoreExpr+dsLocalBinds (L _ EmptyLocalBinds) body = return body+dsLocalBinds (L loc (HsValBinds binds)) body = putSrcSpanDs loc $+ dsValBinds binds body+dsLocalBinds (L _ (HsIPBinds binds)) body = dsIPBinds binds body++-------------------------+-- caller sets location+dsValBinds :: HsValBinds Id -> CoreExpr -> DsM CoreExpr+dsValBinds (ValBindsOut binds _) body = foldrM ds_val_bind body binds+dsValBinds (ValBindsIn {}) _ = panic "dsValBinds ValBindsIn"++-------------------------+dsIPBinds :: HsIPBinds Id -> CoreExpr -> DsM CoreExpr+dsIPBinds (IPBinds ip_binds ev_binds) body+ = do { ds_binds <- dsTcEvBinds ev_binds+ ; let inner = mkCoreLets ds_binds body+ -- The dict bindings may not be in+ -- dependency order; hence Rec+ ; foldrM ds_ip_bind inner ip_binds }+ where+ ds_ip_bind (L _ (IPBind ~(Right n) e)) body+ = do e' <- dsLExpr e+ return (Let (NonRec n e') body)++-------------------------+-- caller sets location+ds_val_bind :: (RecFlag, LHsBinds Id) -> CoreExpr -> DsM CoreExpr+-- Special case for bindings which bind unlifted variables+-- We need to do a case right away, rather than building+-- a tuple and doing selections.+-- Silently ignore INLINE and SPECIALISE pragmas...+ds_val_bind (NonRecursive, hsbinds) body+ | [L loc bind] <- bagToList hsbinds+ -- Non-recursive, non-overloaded bindings only come in ones+ -- ToDo: in some bizarre case it's conceivable that there+ -- could be dict binds in the 'binds'. (See the notes+ -- below. Then pattern-match would fail. Urk.)+ , isUnliftedHsBind bind+ = putSrcSpanDs loc $+ -- see Note [Strict binds checks] in DsBinds+ if is_polymorphic bind+ then errDsCoreExpr (poly_bind_err bind)+ -- data Ptr a = Ptr Addr#+ -- f x = let p@(Ptr y) = ... in ...+ -- Here the binding for 'p' is polymorphic, but does+ -- not mix with an unlifted binding for 'y'. You should+ -- use a bang pattern. Trac #6078.++ else do { when (looksLazyPatBind bind) $+ warnIfSetDs Opt_WarnUnbangedStrictPatterns (unlifted_must_be_bang bind)+ -- Complain about a binding that looks lazy+ -- e.g. let I# y = x in ...+ -- Remember, in checkStrictBinds we are going to do strict+ -- matching, so (for software engineering reasons) we insist+ -- that the strictness is manifest on each binding+ -- However, lone (unboxed) variables are ok+++ ; dsUnliftedBind bind body }+ where+ is_polymorphic (AbsBinds { abs_tvs = tvs, abs_ev_vars = evs })+ = not (null tvs && null evs)+ is_polymorphic (AbsBindsSig { abs_tvs = tvs, abs_ev_vars = evs })+ = not (null tvs && null evs)+ is_polymorphic _ = False++ unlifted_must_be_bang bind+ = hang (text "Pattern bindings containing unlifted types should use" $$+ text "an outermost bang pattern:")+ 2 (ppr bind)++ poly_bind_err bind+ = hang (text "You can't mix polymorphic and unlifted bindings:")+ 2 (ppr bind) $$+ text "Probable fix: add a type signature"++ds_val_bind (is_rec, binds) _body+ | anyBag (isUnliftedHsBind . unLoc) binds -- see Note [Strict binds checks] in DsBinds+ = ASSERT( isRec is_rec )+ errDsCoreExpr $+ hang (text "Recursive bindings for unlifted types aren't allowed:")+ 2 (vcat (map ppr (bagToList binds)))++-- Ordinary case for bindings; none should be unlifted+ds_val_bind (is_rec, binds) body+ = do { MASSERT( isRec is_rec || isSingletonBag binds )+ -- we should never produce a non-recursive list of multiple binds++ ; (force_vars,prs) <- dsLHsBinds binds+ ; let body' = foldr seqVar body force_vars+ ; ASSERT2( not (any (isUnliftedType . idType . fst) prs), ppr is_rec $$ ppr binds )+ case prs of+ [] -> return body+ _ -> return (Let (Rec prs) body') }+ -- Use a Rec regardless of is_rec.+ -- Why? Because it allows the binds to be all+ -- mixed up, which is what happens in one rare case+ -- Namely, for an AbsBind with no tyvars and no dicts,+ -- but which does have dictionary bindings.+ -- See notes with TcSimplify.inferLoop [NO TYVARS]+ -- It turned out that wrapping a Rec here was the easiest solution+ --+ -- NB The previous case dealt with unlifted bindings, so we+ -- only have to deal with lifted ones now; so Rec is ok++------------------+dsUnliftedBind :: HsBind Id -> CoreExpr -> DsM CoreExpr+dsUnliftedBind (AbsBinds { abs_tvs = [], abs_ev_vars = []+ , abs_exports = exports+ , abs_ev_binds = ev_binds+ , abs_binds = lbinds }) body+ = do { let body1 = foldr bind_export body exports+ bind_export export b = bindNonRec (abe_poly export) (Var (abe_mono export)) b+ ; body2 <- foldlBagM (\body lbind -> dsUnliftedBind (unLoc lbind) body)+ body1 lbinds+ ; ds_binds <- dsTcEvBinds_s ev_binds+ ; return (mkCoreLets ds_binds body2) }++dsUnliftedBind (AbsBindsSig { abs_tvs = []+ , abs_ev_vars = []+ , abs_sig_export = poly+ , abs_sig_ev_bind = ev_bind+ , abs_sig_bind = L _ bind }) body+ = do { ds_binds <- dsTcEvBinds ev_bind+ ; body' <- dsUnliftedBind (bind { fun_id = noLoc poly }) body+ ; return (mkCoreLets ds_binds body') }++dsUnliftedBind (FunBind { fun_id = L l fun+ , fun_matches = matches+ , fun_co_fn = co_fn+ , fun_tick = tick }) body+ -- Can't be a bang pattern (that looks like a PatBind)+ -- so must be simply unboxed+ = do { (args, rhs) <- matchWrapper (mkPrefixFunRhs (L l $ idName fun))+ Nothing matches+ ; MASSERT( null args ) -- Functions aren't lifted+ ; MASSERT( isIdHsWrapper co_fn )+ ; let rhs' = mkOptTickBox tick rhs+ ; return (bindNonRec fun rhs' body) }++dsUnliftedBind (PatBind {pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty }) body+ = -- let C x# y# = rhs in body+ -- ==> case rhs of C x# y# -> body+ do { rhs <- dsGuarded grhss ty+ ; let upat = unLoc pat+ eqn = EqnInfo { eqn_pats = [upat],+ eqn_rhs = cantFailMatchResult body }+ ; var <- selectMatchVar upat+ ; result <- matchEquations PatBindRhs [var] [eqn] (exprType body)+ ; return (bindNonRec var rhs result) }++dsUnliftedBind bind body = pprPanic "dsLet: unlifted" (ppr bind $$ ppr body)++{-+************************************************************************+* *+\subsection[DsExpr-vars-and-cons]{Variables, constructors, literals}+* *+************************************************************************+-}++dsLExpr :: LHsExpr Id -> DsM CoreExpr++dsLExpr (L loc e)+ = putSrcSpanDs loc $+ do { core_expr <- dsExpr e+ -- uncomment this check to test the hsExprType function in TcHsSyn+ -- ; MASSERT2( exprType core_expr `eqType` hsExprType e+ -- , ppr e <+> dcolon <+> ppr (hsExprType e) $$+ -- ppr core_expr <+> dcolon <+> ppr (exprType core_expr) )+ ; return core_expr }++-- | Variant of 'dsLExpr' that ensures that the result is not levity+-- polymorphic. This should be used when the resulting expression will+-- be an argument to some other function.+-- See Note [Levity polymorphism checking] in DsMonad+-- See Note [Levity polymorphism invariants] in CoreSyn+dsLExprNoLP :: LHsExpr Id -> DsM CoreExpr+dsLExprNoLP (L loc e)+ = putSrcSpanDs loc $+ do { e' <- dsExpr e+ ; dsNoLevPolyExpr e' (text "In the type of expression:" <+> ppr e)+ ; return e' }++dsExpr :: HsExpr Id -> DsM CoreExpr+dsExpr (HsPar e) = dsLExpr e+dsExpr (ExprWithTySigOut e _) = dsLExpr e+dsExpr (HsVar (L _ var)) = return (varToCoreExpr var)+ -- See Note [Desugaring vars]+dsExpr (HsUnboundVar {}) = panic "dsExpr: HsUnboundVar" -- Typechecker eliminates them+dsExpr (HsConLikeOut con) = return (dsConLike con)+dsExpr (HsIPVar _) = panic "dsExpr: HsIPVar"+dsExpr (HsOverLabel{}) = panic "dsExpr: HsOverLabel"+dsExpr (HsLit lit) = dsLit lit+dsExpr (HsOverLit lit) = dsOverLit lit++dsExpr (HsWrap co_fn e)+ = do { e' <- dsExpr e+ ; wrap' <- dsHsWrapper co_fn+ ; dflags <- getDynFlags+ ; let wrapped_e = wrap' e'+ ; warnAboutIdentities dflags e' (exprType wrapped_e)+ ; return wrapped_e }++dsExpr (NegApp (L loc (HsOverLit lit@(OverLit { ol_val = HsIntegral src i })))+ neg_expr)+ = do { expr' <- putSrcSpanDs loc $ do+ { dflags <- getDynFlags+ ; warnAboutOverflowedLiterals dflags+ (lit { ol_val = HsIntegral src (-i) })+ ; dsOverLit' dflags lit }+ ; dsSyntaxExpr neg_expr [expr'] }++dsExpr (NegApp expr neg_expr)+ = do { expr' <- dsLExpr expr+ ; dsSyntaxExpr neg_expr [expr'] }++dsExpr (HsLam a_Match)+ = uncurry mkLams <$> matchWrapper LambdaExpr Nothing a_Match++dsExpr (HsLamCase matches)+ = do { ([discrim_var], matching_code) <- matchWrapper CaseAlt Nothing matches+ ; return $ Lam discrim_var matching_code }++dsExpr e@(HsApp fun arg)+ = do { fun' <- dsLExpr fun+ ; dsWhenNoErrs (dsLExprNoLP arg)+ (\arg' -> mkCoreAppDs (text "HsApp" <+> ppr e) fun' arg') }++dsExpr (HsAppTypeOut e _)+ -- ignore type arguments here; they're in the wrappers instead at this point+ = dsLExpr e+++{-+Note [Desugaring vars]+~~~~~~~~~~~~~~~~~~~~~~+In one situation we can get a *coercion* variable in a HsVar, namely+the support method for an equality superclass:+ class (a~b) => C a b where ...+ instance (blah) => C (T a) (T b) where ..+Then we get+ $dfCT :: forall ab. blah => C (T a) (T b)+ $dfCT ab blah = MkC ($c$p1C a blah) ($cop a blah)++ $c$p1C :: forall ab. blah => (T a ~ T b)+ $c$p1C ab blah = let ...; g :: T a ~ T b = ... } in g++That 'g' in the 'in' part is an evidence variable, and when+converting to core it must become a CO.++Operator sections. At first it looks as if we can convert+\begin{verbatim}+ (expr op)+\end{verbatim}+to+\begin{verbatim}+ \x -> op expr x+\end{verbatim}++But no! expr might be a redex, and we can lose laziness badly this+way. Consider+\begin{verbatim}+ map (expr op) xs+\end{verbatim}+for example. So we convert instead to+\begin{verbatim}+ let y = expr in \x -> op y x+\end{verbatim}+If \tr{expr} is actually just a variable, say, then the simplifier+will sort it out.+-}++dsExpr e@(OpApp e1 op _ e2)+ = -- for the type of y, we need the type of op's 2nd argument+ do { op' <- dsLExpr op+ ; dsWhenNoErrs (mapM dsLExprNoLP [e1, e2])+ (\exprs' -> mkCoreAppsDs (text "opapp" <+> ppr e) op' exprs') }++dsExpr (SectionL expr op) -- Desugar (e !) to ((!) e)+ = do { op' <- dsLExpr op+ ; dsWhenNoErrs (dsLExprNoLP expr)+ (\expr' -> mkCoreAppDs (text "sectionl" <+> ppr expr) op' expr') }++-- dsLExpr (SectionR op expr) -- \ x -> op x expr+dsExpr e@(SectionR op expr) = do+ core_op <- dsLExpr op+ -- for the type of x, we need the type of op's 2nd argument+ let (x_ty:y_ty:_, _) = splitFunTys (exprType core_op)+ -- See comment with SectionL+ y_core <- dsLExpr expr+ dsWhenNoErrs (mapM newSysLocalDsNoLP [x_ty, y_ty])+ (\[x_id, y_id] -> bindNonRec y_id y_core $+ Lam x_id (mkCoreAppsDs (text "sectionr" <+> ppr e)+ core_op [Var x_id, Var y_id]))++dsExpr (ExplicitTuple tup_args boxity)+ = do { let go (lam_vars, args) (L _ (Missing ty))+ -- For every missing expression, we need+ -- another lambda in the desugaring.+ = do { lam_var <- newSysLocalDsNoLP ty+ ; return (lam_var : lam_vars, Var lam_var : args) }+ go (lam_vars, args) (L _ (Present expr))+ -- Expressions that are present don't generate+ -- lambdas, just arguments.+ = do { core_expr <- dsLExpr expr+ ; return (lam_vars, core_expr : args) }++ ; (lam_vars, args) <- foldM go ([], []) (reverse tup_args)+ -- The reverse is because foldM goes left-to-right++ ; return $ mkCoreLams lam_vars $+ mkCoreTupBoxity boxity args }++dsExpr (ExplicitSum alt arity expr types)+ = do { core_expr <- dsLExpr expr+ ; return $ mkCoreConApps (sumDataCon alt arity)+ (map (Type . getRuntimeRep "dsExpr ExplicitSum") types +++ map Type types +++ [core_expr]) }++dsExpr (HsSCC _ cc expr@(L loc _)) = do+ dflags <- getDynFlags+ if gopt Opt_SccProfilingOn dflags+ then do+ mod_name <- getModule+ count <- goptM Opt_ProfCountEntries+ uniq <- newUnique+ Tick (ProfNote (mkUserCC (sl_fs cc) mod_name loc uniq) count True)+ <$> dsLExpr expr+ else dsLExpr expr++dsExpr (HsCoreAnn _ _ expr)+ = dsLExpr expr++dsExpr (HsCase discrim matches)+ = do { core_discrim <- dsLExpr discrim+ ; ([discrim_var], matching_code) <- matchWrapper CaseAlt (Just discrim) matches+ ; return (bindNonRec discrim_var core_discrim matching_code) }++-- Pepe: The binds are in scope in the body but NOT in the binding group+-- This is to avoid silliness in breakpoints+dsExpr (HsLet binds body) = do+ body' <- dsLExpr body+ dsLocalBinds binds body'++-- We need the `ListComp' form to use `deListComp' (rather than the "do" form)+-- because the interpretation of `stmts' depends on what sort of thing it is.+--+dsExpr (HsDo ListComp (L _ stmts) res_ty) = dsListComp stmts res_ty+dsExpr (HsDo PArrComp (L _ stmts) _) = dsPArrComp (map unLoc stmts)+dsExpr (HsDo DoExpr (L _ stmts) _) = dsDo stmts+dsExpr (HsDo GhciStmtCtxt (L _ stmts) _) = dsDo stmts+dsExpr (HsDo MDoExpr (L _ stmts) _) = dsDo stmts+dsExpr (HsDo MonadComp (L _ stmts) _) = dsMonadComp stmts++dsExpr (HsIf mb_fun guard_expr then_expr else_expr)+ = do { pred <- dsLExpr guard_expr+ ; b1 <- dsLExpr then_expr+ ; b2 <- dsLExpr else_expr+ ; case mb_fun of+ Just fun -> dsSyntaxExpr fun [pred, b1, b2]+ Nothing -> return $ mkIfThenElse pred b1 b2 }++dsExpr (HsMultiIf res_ty alts)+ | null alts+ = mkErrorExpr++ | otherwise+ = do { match_result <- liftM (foldr1 combineMatchResults)+ (mapM (dsGRHS IfAlt res_ty) alts)+ ; error_expr <- mkErrorExpr+ ; extractMatchResult match_result error_expr }+ where+ mkErrorExpr = mkErrorAppDs nON_EXHAUSTIVE_GUARDS_ERROR_ID res_ty+ (text "multi-way if")++{-+\noindent+\underline{\bf Various data construction things}+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-}++dsExpr (ExplicitList elt_ty wit xs)+ = dsExplicitList elt_ty wit xs++-- We desugar [:x1, ..., xn:] as+-- singletonP x1 +:+ ... +:+ singletonP xn+--+dsExpr (ExplicitPArr ty []) = do+ emptyP <- dsDPHBuiltin emptyPVar+ return (Var emptyP `App` Type ty)+dsExpr (ExplicitPArr ty xs) = do+ singletonP <- dsDPHBuiltin singletonPVar+ appP <- dsDPHBuiltin appPVar+ xs' <- mapM dsLExprNoLP xs+ let unary fn x = mkApps (Var fn) [Type ty, x]+ binary fn x y = mkApps (Var fn) [Type ty, x, y]++ return . foldr1 (binary appP) $ map (unary singletonP) xs'++dsExpr (ArithSeq expr witness seq)+ = case witness of+ Nothing -> dsArithSeq expr seq+ Just fl -> do { newArithSeq <- dsArithSeq expr seq+ ; dsSyntaxExpr fl [newArithSeq] }++dsExpr (PArrSeq expr (FromTo from to))+ = mkApps <$> dsExpr expr <*> mapM dsLExprNoLP [from, to]++dsExpr (PArrSeq expr (FromThenTo from thn to))+ = mkApps <$> dsExpr expr <*> mapM dsLExprNoLP [from, thn, to]++dsExpr (PArrSeq _ _)+ = panic "DsExpr.dsExpr: Infinite parallel array!"+ -- the parser shouldn't have generated it and the renamer and typechecker+ -- shouldn't have let it through++{-+Static Pointers+~~~~~~~~~~~~~~~++See Note [Grand plan for static forms] in StaticPtrTable for an overview.++ g = ... static f ...+==>+ g = ... makeStatic loc f ...+-}++dsExpr (HsStatic _ expr@(L loc _)) = do+ expr_ds <- dsLExprNoLP expr+ let ty = exprType expr_ds+ makeStaticId <- dsLookupGlobalId makeStaticName++ dflags <- getDynFlags+ let (line, col) = case loc of+ RealSrcSpan r -> ( srcLocLine $ realSrcSpanStart r+ , srcLocCol $ realSrcSpanStart r+ )+ _ -> (0, 0)+ srcLoc = mkCoreConApps (tupleDataCon Boxed 2)+ [ Type intTy , Type intTy+ , mkIntExprInt dflags line, mkIntExprInt dflags col+ ]++ putSrcSpanDs loc $ return $+ mkCoreApps (Var makeStaticId) [ Type ty, srcLoc, expr_ds ]++{-+\noindent+\underline{\bf Record construction and update}+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For record construction we do this (assuming T has three arguments)+\begin{verbatim}+ T { op2 = e }+==>+ let err = /\a -> recConErr a+ T (recConErr t1 "M.hs/230/op1")+ e+ (recConErr t1 "M.hs/230/op3")+\end{verbatim}+@recConErr@ then converts its argument string into a proper message+before printing it as+\begin{verbatim}+ M.hs, line 230: missing field op1 was evaluated+\end{verbatim}++We also handle @C{}@ as valid construction syntax for an unlabelled+constructor @C@, setting all of @C@'s fields to bottom.+-}++dsExpr (RecordCon { rcon_con_expr = con_expr, rcon_flds = rbinds+ , rcon_con_like = con_like })+ = do { con_expr' <- dsExpr con_expr+ ; let+ (arg_tys, _) = tcSplitFunTys (exprType con_expr')+ -- A newtype in the corner should be opaque;+ -- hence TcType.tcSplitFunTys++ mk_arg (arg_ty, fl)+ = case findField (rec_flds rbinds) (flSelector fl) of+ (rhs:rhss) -> ASSERT( null rhss )+ dsLExprNoLP rhs+ [] -> mkErrorAppDs rEC_CON_ERROR_ID arg_ty (ppr (flLabel fl))+ unlabelled_bottom arg_ty = mkErrorAppDs rEC_CON_ERROR_ID arg_ty Outputable.empty++ labels = conLikeFieldLabels con_like++ ; con_args <- if null labels+ then mapM unlabelled_bottom arg_tys+ else mapM mk_arg (zipEqual "dsExpr:RecordCon" arg_tys labels)++ ; return (mkCoreApps con_expr' con_args) }++{-+Record update is a little harder. Suppose we have the decl:+\begin{verbatim}+ data T = T1 {op1, op2, op3 :: Int}+ | T2 {op4, op2 :: Int}+ | T3+\end{verbatim}+Then we translate as follows:+\begin{verbatim}+ r { op2 = e }+===>+ let op2 = e in+ case r of+ T1 op1 _ op3 -> T1 op1 op2 op3+ T2 op4 _ -> T2 op4 op2+ other -> recUpdError "M.hs/230"+\end{verbatim}+It's important that we use the constructor Ids for @T1@, @T2@ etc on the+RHSs, and do not generate a Core constructor application directly, because the constructor+might do some argument-evaluation first; and may have to throw away some+dictionaries.++Note [Update for GADTs]+~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T a b where+ T1 :: { f1 :: a } -> T a Int++Then the wrapper function for T1 has type+ $WT1 :: a -> T a Int+But if x::T a b, then+ x { f1 = v } :: T a b (not T a Int!)+So we need to cast (T a Int) to (T a b). Sigh.++-}++dsExpr expr@(RecordUpd { rupd_expr = record_expr, rupd_flds = fields+ , rupd_cons = cons_to_upd+ , rupd_in_tys = in_inst_tys, rupd_out_tys = out_inst_tys+ , rupd_wrap = dict_req_wrap } )+ | null fields+ = dsLExpr record_expr+ | otherwise+ = ASSERT2( notNull cons_to_upd, ppr expr )++ do { record_expr' <- dsLExpr record_expr+ ; field_binds' <- mapM ds_field fields+ ; let upd_fld_env :: NameEnv Id -- Maps field name to the LocalId of the field binding+ upd_fld_env = mkNameEnv [(f,l) | (f,l,_) <- field_binds']++ -- It's important to generate the match with matchWrapper,+ -- and the right hand sides with applications of the wrapper Id+ -- so that everything works when we are doing fancy unboxing on the+ -- constructor arguments.+ ; alts <- mapM (mk_alt upd_fld_env) cons_to_upd+ ; ([discrim_var], matching_code)+ <- matchWrapper RecUpd Nothing (MG { mg_alts = noLoc alts+ , mg_arg_tys = [in_ty]+ , mg_res_ty = out_ty, mg_origin = FromSource })+ -- FromSource is not strictly right, but we+ -- want incomplete pattern-match warnings++ ; return (add_field_binds field_binds' $+ bindNonRec discrim_var record_expr' matching_code) }+ where+ ds_field :: LHsRecUpdField Id -> DsM (Name, Id, CoreExpr)+ -- Clone the Id in the HsRecField, because its Name is that+ -- of the record selector, and we must not make that a local binder+ -- else we shadow other uses of the record selector+ -- Hence 'lcl_id'. Cf Trac #2735+ ds_field (L _ rec_field) = do { rhs <- dsLExpr (hsRecFieldArg rec_field)+ ; let fld_id = unLoc (hsRecUpdFieldId rec_field)+ ; lcl_id <- newSysLocalDs (idType fld_id)+ ; return (idName fld_id, lcl_id, rhs) }++ add_field_binds [] expr = expr+ add_field_binds ((_,b,r):bs) expr = bindNonRec b r (add_field_binds bs expr)++ -- Awkwardly, for families, the match goes+ -- from instance type to family type+ (in_ty, out_ty) =+ case (head cons_to_upd) of+ RealDataCon data_con ->+ let tycon = dataConTyCon data_con in+ (mkTyConApp tycon in_inst_tys, mkFamilyTyConApp tycon out_inst_tys)+ PatSynCon pat_syn ->+ ( patSynInstResTy pat_syn in_inst_tys+ , patSynInstResTy pat_syn out_inst_tys)+ mk_alt upd_fld_env con+ = do { let (univ_tvs, ex_tvs, eq_spec,+ prov_theta, _req_theta, arg_tys, _) = conLikeFullSig con+ subst = zipTvSubst univ_tvs in_inst_tys++ -- I'm not bothering to clone the ex_tvs+ ; eqs_vars <- mapM newPredVarDs (substTheta subst (eqSpecPreds eq_spec))+ ; theta_vars <- mapM newPredVarDs (substTheta subst prov_theta)+ ; arg_ids <- newSysLocalsDs (substTysUnchecked subst arg_tys)+ ; let field_labels = conLikeFieldLabels con+ val_args = zipWithEqual "dsExpr:RecordUpd" mk_val_arg+ field_labels arg_ids+ mk_val_arg fl pat_arg_id+ = nlHsVar (lookupNameEnv upd_fld_env (flSelector fl) `orElse` pat_arg_id)++ inst_con = noLoc $ HsWrap wrap (HsConLikeOut con)+ -- Reconstruct with the WrapId so that unpacking happens+ -- The order here is because of the order in `TcPatSyn`.+ wrap = mkWpEvVarApps theta_vars <.>+ dict_req_wrap <.>+ mkWpTyApps (mkTyVarTys ex_tvs) <.>+ mkWpTyApps [ ty+ | (tv, ty) <- univ_tvs `zip` out_inst_tys+ , not (tv `elemVarEnv` wrap_subst) ]+ rhs = foldl (\a b -> nlHsApp a b) inst_con val_args++ -- Tediously wrap the application in a cast+ -- Note [Update for GADTs]+ wrapped_rhs =+ case con of+ RealDataCon data_con ->+ let+ wrap_co =+ mkTcTyConAppCo Nominal+ (dataConTyCon data_con)+ [ lookup tv ty+ | (tv,ty) <- univ_tvs `zip` out_inst_tys ]+ lookup univ_tv ty =+ case lookupVarEnv wrap_subst univ_tv of+ Just co' -> co'+ Nothing -> mkTcReflCo Nominal ty+ in if null eq_spec+ then rhs+ else mkLHsWrap (mkWpCastN wrap_co) rhs+ -- eq_spec is always null for a PatSynCon+ PatSynCon _ -> rhs++ wrap_subst =+ mkVarEnv [ (tv, mkTcSymCo (mkTcCoVarCo eq_var))+ | (spec, eq_var) <- eq_spec `zip` eqs_vars+ , let tv = eqSpecTyVar spec ]++ req_wrap = dict_req_wrap <.> mkWpTyApps in_inst_tys++ pat = noLoc $ ConPatOut { pat_con = noLoc con+ , pat_tvs = ex_tvs+ , pat_dicts = eqs_vars ++ theta_vars+ , pat_binds = emptyTcEvBinds+ , pat_args = PrefixCon $ map nlVarPat arg_ids+ , pat_arg_tys = in_inst_tys+ , pat_wrap = req_wrap }+ ; return (mkSimpleMatch RecUpd [pat] wrapped_rhs) }++-- Here is where we desugar the Template Haskell brackets and escapes++-- Template Haskell stuff++dsExpr (HsRnBracketOut _ _) = panic "dsExpr HsRnBracketOut"+dsExpr (HsTcBracketOut x ps) = dsBracket x ps+dsExpr (HsSpliceE s) = pprPanic "dsExpr:splice" (ppr s)++-- Arrow notation extension+dsExpr (HsProc pat cmd) = dsProcExpr pat cmd++-- Hpc Support++dsExpr (HsTick tickish e) = do+ e' <- dsLExpr e+ return (Tick tickish e')++-- There is a problem here. The then and else branches+-- have no free variables, so they are open to lifting.+-- We need someway of stopping this.+-- This will make no difference to binary coverage+-- (did you go here: YES or NO), but will effect accurate+-- tick counting.++dsExpr (HsBinTick ixT ixF e) = do+ e2 <- dsLExpr e+ do { ASSERT(exprType e2 `eqType` boolTy)+ mkBinaryTickBox ixT ixF e2+ }++dsExpr (HsTickPragma _ _ _ expr) = do+ dflags <- getDynFlags+ if gopt Opt_Hpc dflags+ then panic "dsExpr:HsTickPragma"+ else dsLExpr expr++-- HsSyn constructs that just shouldn't be here:+dsExpr (ExprWithTySig {}) = panic "dsExpr:ExprWithTySig"+dsExpr (HsBracket {}) = panic "dsExpr:HsBracket"+dsExpr (HsArrApp {}) = panic "dsExpr:HsArrApp"+dsExpr (HsArrForm {}) = panic "dsExpr:HsArrForm"+dsExpr (EWildPat {}) = panic "dsExpr:EWildPat"+dsExpr (EAsPat {}) = panic "dsExpr:EAsPat"+dsExpr (EViewPat {}) = panic "dsExpr:EViewPat"+dsExpr (ELazyPat {}) = panic "dsExpr:ELazyPat"+dsExpr (HsAppType {}) = panic "dsExpr:HsAppType" -- removed by typechecker+dsExpr (HsDo {}) = panic "dsExpr:HsDo"+dsExpr (HsRecFld {}) = panic "dsExpr:HsRecFld"++------------------------------+dsSyntaxExpr :: SyntaxExpr Id -> [CoreExpr] -> DsM CoreExpr+dsSyntaxExpr (SyntaxExpr { syn_expr = expr+ , syn_arg_wraps = arg_wraps+ , syn_res_wrap = res_wrap })+ arg_exprs+ = do { fun <- dsExpr expr+ ; core_arg_wraps <- mapM dsHsWrapper arg_wraps+ ; core_res_wrap <- dsHsWrapper res_wrap+ ; let wrapped_args = zipWith ($) core_arg_wraps arg_exprs+ ; dsWhenNoErrs (zipWithM_ dsNoLevPolyExpr wrapped_args [ mk_doc n | n <- [1..] ])+ (\_ -> core_res_wrap (mkApps fun wrapped_args)) }+ where+ mk_doc n = text "In the" <+> speakNth n <+> text "argument of" <+> quotes (ppr expr)++findField :: [LHsRecField Id arg] -> Name -> [arg]+findField rbinds sel+ = [hsRecFieldArg fld | L _ fld <- rbinds+ , sel == idName (unLoc $ hsRecFieldId fld) ]++{-+%--------------------------------------------------------------------++Note [Desugaring explicit lists]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Explicit lists are desugared in a cleverer way to prevent some+fruitless allocations. Essentially, whenever we see a list literal+[x_1, ..., x_n] we generate the corresponding expression in terms of+build:++Explicit lists (literals) are desugared to allow build/foldr fusion when+beneficial. This is a bit of a trade-off,++ * build/foldr fusion can generate far larger code than the corresponding+ cons-chain (e.g. see #11707)++ * even when it doesn't produce more code, build can still fail to fuse,+ requiring that the simplifier do more work to bring the expression+ back into cons-chain form; this costs compile time++ * when it works, fusion can be a significant win. Allocations are reduced+ by up to 25% in some nofib programs. Specifically,++ Program Size Allocs Runtime CompTime+ rewrite +0.0% -26.3% 0.02 -1.8%+ ansi -0.3% -13.8% 0.00 +0.0%+ lift +0.0% -8.7% 0.00 -2.3%++At the moment we use a simple heuristic to determine whether build will be+fruitful: for small lists we assume the benefits of fusion will be worthwhile;+for long lists we assume that the benefits will be outweighted by the cost of+code duplication. This magic length threshold is @maxBuildLength@. Also, fusion+won't work at all if rewrite rules are disabled, so we don't use the build-based+desugaring in this case.++We used to have a more complex heuristic which would try to break the list into+"static" and "dynamic" parts and only build-desugar the dynamic part.+Unfortunately, determining "static-ness" reliably is a bit tricky and the+heuristic at times produced surprising behavior (see #11710) so it was dropped.+-}++{- | The longest list length which we will desugar using @build@.++This is essentially a magic number and its setting is unfortunate rather+arbitrary. The idea here, as mentioned in Note [Desugaring explicit lists],+is to avoid deforesting large static data into large(r) code. Ideally we'd+want a smaller threshold with larger consumers and vice-versa, but we have no+way of knowing what will be consuming our list in the desugaring impossible to+set generally correctly.++The effect of reducing this number will be that 'build' fusion is applied+less often. From a runtime performance perspective, applying 'build' more+liberally on "moderately" sized lists should rarely hurt and will often it can+only expose further optimization opportunities; if no fusion is possible it will+eventually get rule-rewritten back to a list). We do, however, pay in compile+time.+-}+maxBuildLength :: Int+maxBuildLength = 32++dsExplicitList :: Type -> Maybe (SyntaxExpr Id) -> [LHsExpr Id]+ -> DsM CoreExpr+-- See Note [Desugaring explicit lists]+dsExplicitList elt_ty Nothing xs+ = do { dflags <- getDynFlags+ ; xs' <- mapM dsLExprNoLP xs+ ; if length xs' > maxBuildLength+ -- Don't generate builds if the list is very long.+ || length xs' == 0+ -- Don't generate builds when the [] constructor will do+ || not (gopt Opt_EnableRewriteRules dflags) -- Rewrite rules off+ -- Don't generate a build if there are no rules to eliminate it!+ -- See Note [Desugaring RULE left hand sides] in Desugar+ then return $ mkListExpr elt_ty xs'+ else mkBuildExpr elt_ty (mk_build_list xs') }+ where+ mk_build_list xs' (cons, _) (nil, _)+ = return (foldr (App . App (Var cons)) (Var nil) xs')++dsExplicitList elt_ty (Just fln) xs+ = do { list <- dsExplicitList elt_ty Nothing xs+ ; dflags <- getDynFlags+ ; dsSyntaxExpr fln [mkIntExprInt dflags (length xs), list] }++dsArithSeq :: PostTcExpr -> (ArithSeqInfo Id) -> DsM CoreExpr+dsArithSeq expr (From from)+ = App <$> dsExpr expr <*> dsLExprNoLP from+dsArithSeq expr (FromTo from to)+ = do dflags <- getDynFlags+ warnAboutEmptyEnumerations dflags from Nothing to+ expr' <- dsExpr expr+ from' <- dsLExprNoLP from+ to' <- dsLExprNoLP to+ return $ mkApps expr' [from', to']+dsArithSeq expr (FromThen from thn)+ = mkApps <$> dsExpr expr <*> mapM dsLExprNoLP [from, thn]+dsArithSeq expr (FromThenTo from thn to)+ = do dflags <- getDynFlags+ warnAboutEmptyEnumerations dflags from (Just thn) to+ expr' <- dsExpr expr+ from' <- dsLExprNoLP from+ thn' <- dsLExprNoLP thn+ to' <- dsLExprNoLP to+ return $ mkApps expr' [from', thn', to']++{-+Desugar 'do' and 'mdo' expressions (NOT list comprehensions, they're+handled in DsListComp). Basically does the translation given in the+Haskell 98 report:+-}++dsDo :: [ExprLStmt Id] -> DsM CoreExpr+dsDo stmts+ = goL stmts+ where+ goL [] = panic "dsDo"+ goL (L loc stmt:lstmts) = putSrcSpanDs loc (go loc stmt lstmts)++ go _ (LastStmt body _ _) stmts+ = ASSERT( null stmts ) dsLExpr body+ -- The 'return' op isn't used for 'do' expressions++ go _ (BodyStmt rhs then_expr _ _) stmts+ = do { rhs2 <- dsLExpr rhs+ ; warnDiscardedDoBindings rhs (exprType rhs2)+ ; rest <- goL stmts+ ; dsSyntaxExpr then_expr [rhs2, rest] }++ go _ (LetStmt binds) stmts+ = do { rest <- goL stmts+ ; dsLocalBinds binds rest }++ go _ (BindStmt pat rhs bind_op fail_op res1_ty) stmts+ = do { body <- goL stmts+ ; rhs' <- dsLExpr rhs+ ; var <- selectSimpleMatchVarL pat+ ; match <- matchSinglePat (Var var) (StmtCtxt DoExpr) pat+ res1_ty (cantFailMatchResult body)+ ; match_code <- handle_failure pat match fail_op+ ; dsSyntaxExpr bind_op [rhs', Lam var match_code] }++ go _ (ApplicativeStmt args mb_join body_ty) stmts+ = do {+ let+ (pats, rhss) = unzip (map (do_arg . snd) args)++ do_arg (ApplicativeArgOne pat expr) =+ (pat, dsLExpr expr)+ do_arg (ApplicativeArgMany stmts ret pat) =+ (pat, dsDo (stmts ++ [noLoc $ mkLastStmt (noLoc ret)]))++ arg_tys = map hsLPatType pats++ ; rhss' <- sequence rhss++ ; let body' = noLoc $ HsDo DoExpr (noLoc stmts) body_ty++ ; let fun = L noSrcSpan $ HsLam $+ MG { mg_alts = noLoc [mkSimpleMatch LambdaExpr pats+ body']+ , mg_arg_tys = arg_tys+ , mg_res_ty = body_ty+ , mg_origin = Generated }++ ; fun' <- dsLExpr fun+ ; let mk_ap_call l (op,r) = dsSyntaxExpr op [l,r]+ ; expr <- foldlM mk_ap_call fun' (zip (map fst args) rhss')+ ; case mb_join of+ Nothing -> return expr+ Just join_op -> dsSyntaxExpr join_op [expr] }++ go loc (RecStmt { recS_stmts = rec_stmts, recS_later_ids = later_ids+ , recS_rec_ids = rec_ids, recS_ret_fn = return_op+ , recS_mfix_fn = mfix_op, recS_bind_fn = bind_op+ , recS_bind_ty = bind_ty+ , recS_rec_rets = rec_rets, recS_ret_ty = body_ty }) stmts+ = goL (new_bind_stmt : stmts) -- rec_ids can be empty; eg rec { print 'x' }+ where+ new_bind_stmt = L loc $ BindStmt (mkBigLHsPatTupId later_pats)+ mfix_app bind_op+ noSyntaxExpr -- Tuple cannot fail+ bind_ty++ tup_ids = rec_ids ++ filterOut (`elem` rec_ids) later_ids+ tup_ty = mkBigCoreTupTy (map idType tup_ids) -- Deals with singleton case+ rec_tup_pats = map nlVarPat tup_ids+ later_pats = rec_tup_pats+ rets = map noLoc rec_rets+ mfix_app = nlHsSyntaxApps mfix_op [mfix_arg]+ mfix_arg = noLoc $ HsLam+ (MG { mg_alts = noLoc [mkSimpleMatch+ LambdaExpr+ [mfix_pat] body]+ , mg_arg_tys = [tup_ty], mg_res_ty = body_ty+ , mg_origin = Generated })+ mfix_pat = noLoc $ LazyPat $ mkBigLHsPatTupId rec_tup_pats+ body = noLoc $ HsDo+ DoExpr (noLoc (rec_stmts ++ [ret_stmt])) body_ty+ ret_app = nlHsSyntaxApps return_op [mkBigLHsTupId rets]+ ret_stmt = noLoc $ mkLastStmt ret_app+ -- This LastStmt will be desugared with dsDo,+ -- which ignores the return_op in the LastStmt,+ -- so we must apply the return_op explicitly++ go _ (ParStmt {}) _ = panic "dsDo ParStmt"+ go _ (TransStmt {}) _ = panic "dsDo TransStmt"++handle_failure :: LPat Id -> MatchResult -> SyntaxExpr Id -> DsM CoreExpr+ -- In a do expression, pattern-match failure just calls+ -- the monadic 'fail' rather than throwing an exception+handle_failure pat match fail_op+ | matchCanFail match+ = do { dflags <- getDynFlags+ ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat)+ ; fail_expr <- dsSyntaxExpr fail_op [fail_msg]+ ; extractMatchResult match fail_expr }+ | otherwise+ = extractMatchResult match (error "It can't fail")++mk_fail_msg :: DynFlags -> Located e -> String+mk_fail_msg dflags pat = "Pattern match failure in do expression at " +++ showPpr dflags (getLoc pat)++{-+************************************************************************+* *+ Desugaring ConLikes+* *+************************************************************************+-}++dsConLike :: ConLike -> CoreExpr+dsConLike (RealDataCon dc) = Var (dataConWrapId dc)+dsConLike (PatSynCon ps) = case patSynBuilder ps of+ Just (id, add_void)+ | add_void -> mkCoreApp (text "dsConLike" <+> ppr ps) (Var id) (Var voidPrimId)+ | otherwise -> Var id+ _ -> pprPanic "dsConLike" (ppr ps)++{-+************************************************************************+* *+\subsection{Errors and contexts}+* *+************************************************************************+-}++-- Warn about certain types of values discarded in monadic bindings (#3263)+warnDiscardedDoBindings :: LHsExpr Id -> Type -> DsM ()+warnDiscardedDoBindings rhs rhs_ty+ | Just (m_ty, elt_ty) <- tcSplitAppTy_maybe rhs_ty+ = do { warn_unused <- woptM Opt_WarnUnusedDoBind+ ; warn_wrong <- woptM Opt_WarnWrongDoBind+ ; when (warn_unused || warn_wrong) $+ do { fam_inst_envs <- dsGetFamInstEnvs+ ; let norm_elt_ty = topNormaliseType fam_inst_envs elt_ty++ -- Warn about discarding non-() things in 'monadic' binding+ ; if warn_unused && not (isUnitTy norm_elt_ty)+ then warnDs (Reason Opt_WarnUnusedDoBind)+ (badMonadBind rhs elt_ty)+ else++ -- Warn about discarding m a things in 'monadic' binding of the same type,+ -- but only if we didn't already warn due to Opt_WarnUnusedDoBind+ when warn_wrong $+ do { case tcSplitAppTy_maybe norm_elt_ty of+ Just (elt_m_ty, _)+ | m_ty `eqType` topNormaliseType fam_inst_envs elt_m_ty+ -> warnDs (Reason Opt_WarnWrongDoBind)+ (badMonadBind rhs elt_ty)+ _ -> return () } } }++ | otherwise -- RHS does have type of form (m ty), which is weird+ = return () -- but at lesat this warning is irrelevant++badMonadBind :: LHsExpr Id -> Type -> SDoc+badMonadBind rhs elt_ty+ = vcat [ hang (text "A do-notation statement discarded a result of type")+ 2 (quotes (ppr elt_ty))+ , hang (text "Suppress this warning by saying")+ 2 (quotes $ text "_ <-" <+> ppr rhs)+ ]
+ deSugar/DsExpr.hs-boot view
@@ -0,0 +1,10 @@+module DsExpr where+import HsSyn ( HsExpr, LHsExpr, LHsLocalBinds, SyntaxExpr )+import Var ( Id )+import DsMonad ( DsM )+import CoreSyn ( CoreExpr )++dsExpr :: HsExpr Id -> DsM CoreExpr+dsLExpr, dsLExprNoLP :: LHsExpr Id -> DsM CoreExpr+dsSyntaxExpr :: SyntaxExpr Id -> [CoreExpr] -> DsM CoreExpr+dsLocalBinds :: LHsLocalBinds Id -> CoreExpr -> DsM CoreExpr
+ deSugar/DsForeign.hs view
@@ -0,0 +1,805 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1998+++Desugaring foreign declarations (see also DsCCall).+-}++{-# LANGUAGE CPP #-}++module DsForeign ( dsForeigns ) where++#include "HsVersions.h"+import TcRnMonad -- temp++import CoreSyn++import DsCCall+import DsMonad++import HsSyn+import DataCon+import CoreUnfold+import Id+import Literal+import Module+import Name+import Type+import RepType+import TyCon+import Coercion+import TcEnv+import TcType++import CmmExpr+import CmmUtils+import HscTypes+import ForeignCall+import TysWiredIn+import TysPrim+import PrelNames+import BasicTypes+import SrcLoc+import Outputable+import FastString+import DynFlags+import Platform+import Config+import OrdList+import Pair+import Util+import Hooks+import Encoding++import Data.Maybe+import Data.List++{-+Desugaring of @foreign@ declarations is naturally split up into+parts, an @import@ and an @export@ part. A @foreign import@+declaration+\begin{verbatim}+ foreign import cc nm f :: prim_args -> IO prim_res+\end{verbatim}+is the same as+\begin{verbatim}+ f :: prim_args -> IO prim_res+ f a1 ... an = _ccall_ nm cc a1 ... an+\end{verbatim}+so we reuse the desugaring code in @DsCCall@ to deal with these.+-}++type Binding = (Id, CoreExpr) -- No rec/nonrec structure;+ -- the occurrence analyser will sort it all out++dsForeigns :: [LForeignDecl Id]+ -> DsM (ForeignStubs, OrdList Binding)+dsForeigns fos = getHooked dsForeignsHook dsForeigns' >>= ($ fos)++dsForeigns' :: [LForeignDecl Id]+ -> DsM (ForeignStubs, OrdList Binding)+dsForeigns' []+ = return (NoStubs, nilOL)+dsForeigns' fos = do+ fives <- mapM do_ldecl fos+ let+ (hs, cs, idss, bindss) = unzip4 fives+ fe_ids = concat idss+ fe_init_code = map foreignExportInitialiser fe_ids+ --+ return (ForeignStubs+ (vcat hs)+ (vcat cs $$ vcat fe_init_code),+ foldr (appOL . toOL) nilOL bindss)+ where+ do_ldecl (L loc decl) = putSrcSpanDs loc (do_decl decl)++ do_decl (ForeignImport { fd_name = id, fd_co = co, fd_fi = spec }) = do+ traceIf (text "fi start" <+> ppr id)+ let id' = unLoc id+ (bs, h, c) <- dsFImport id' co spec+ traceIf (text "fi end" <+> ppr id)+ return (h, c, [], bs)++ do_decl (ForeignExport { fd_name = L _ id, fd_co = co+ , fd_fe = CExport (L _ (CExportStatic _ ext_nm cconv)) _ }) = do+ (h, c, _, _) <- dsFExport id co ext_nm cconv False+ return (h, c, [id], [])++{-+************************************************************************+* *+\subsection{Foreign import}+* *+************************************************************************++Desugaring foreign imports is just the matter of creating a binding+that on its RHS unboxes its arguments, performs the external call+(using the @CCallOp@ primop), before boxing the result up and returning it.++However, we create a worker/wrapper pair, thus:++ foreign import f :: Int -> IO Int+==>+ f x = IO ( \s -> case x of { I# x# ->+ case fw s x# of { (# s1, y# #) ->+ (# s1, I# y# #)}})++ fw s x# = ccall f s x#++The strictness/CPR analyser won't do this automatically because it doesn't look+inside returned tuples; but inlining this wrapper is a Really Good Idea+because it exposes the boxing to the call site.+-}++dsFImport :: Id+ -> Coercion+ -> ForeignImport+ -> DsM ([Binding], SDoc, SDoc)+dsFImport id co (CImport cconv safety mHeader spec _) =+ dsCImport id co spec (unLoc cconv) (unLoc safety) mHeader++dsCImport :: Id+ -> Coercion+ -> CImportSpec+ -> CCallConv+ -> Safety+ -> Maybe Header+ -> DsM ([Binding], SDoc, SDoc)+dsCImport id co (CLabel cid) cconv _ _ = do+ dflags <- getDynFlags+ let ty = pFst $ coercionKind co+ fod = case tyConAppTyCon_maybe (dropForAlls ty) of+ Just tycon+ | tyConUnique tycon == funPtrTyConKey ->+ IsFunction+ _ -> IsData+ (resTy, foRhs) <- resultWrapper ty+ ASSERT(fromJust resTy `eqType` addrPrimTy) -- typechecker ensures this+ let+ rhs = foRhs (Lit (MachLabel cid stdcall_info fod))+ rhs' = Cast rhs co+ stdcall_info = fun_type_arg_stdcall_info dflags cconv ty+ in+ return ([(id, rhs')], empty, empty)++dsCImport id co (CFunction target) cconv@PrimCallConv safety _+ = dsPrimCall id co (CCall (CCallSpec target cconv safety))+dsCImport id co (CFunction target) cconv safety mHeader+ = dsFCall id co (CCall (CCallSpec target cconv safety)) mHeader+dsCImport id co CWrapper cconv _ _+ = dsFExportDynamic id co cconv++-- For stdcall labels, if the type was a FunPtr or newtype thereof,+-- then we need to calculate the size of the arguments in order to add+-- the @n suffix to the label.+fun_type_arg_stdcall_info :: DynFlags -> CCallConv -> Type -> Maybe Int+fun_type_arg_stdcall_info dflags StdCallConv ty+ | Just (tc,[arg_ty]) <- splitTyConApp_maybe ty,+ tyConUnique tc == funPtrTyConKey+ = let+ (bndrs, _) = tcSplitPiTys arg_ty+ fe_arg_tys = mapMaybe binderRelevantType_maybe bndrs+ in Just $ sum (map (widthInBytes . typeWidth . typeCmmType dflags . getPrimTyOf) fe_arg_tys)+fun_type_arg_stdcall_info _ _other_conv _+ = Nothing++{-+************************************************************************+* *+\subsection{Foreign calls}+* *+************************************************************************+-}++dsFCall :: Id -> Coercion -> ForeignCall -> Maybe Header+ -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)+dsFCall fn_id co fcall mDeclHeader = do+ let+ ty = pFst $ coercionKind co+ (tv_bndrs, rho) = tcSplitForAllTyVarBndrs ty+ (arg_tys, io_res_ty) = tcSplitFunTys rho++ args <- newSysLocalsDs arg_tys -- no FFI levity-polymorphism+ (val_args, arg_wrappers) <- mapAndUnzipM unboxArg (map Var args)++ let+ work_arg_ids = [v | Var v <- val_args] -- All guaranteed to be vars++ (ccall_result_ty, res_wrapper) <- boxResult io_res_ty++ ccall_uniq <- newUnique+ work_uniq <- newUnique++ dflags <- getDynFlags+ (fcall', cDoc) <-+ case fcall of+ CCall (CCallSpec (StaticTarget _ cName mUnitId isFun)+ CApiConv safety) ->+ do wrapperName <- mkWrapperName "ghc_wrapper" (unpackFS cName)+ let fcall' = CCall (CCallSpec+ (StaticTarget NoSourceText+ wrapperName mUnitId+ True)+ CApiConv safety)+ c = includes+ $$ fun_proto <+> braces (cRet <> semi)+ includes = vcat [ text "#include <" <> ftext h <> text ">"+ | Header _ h <- nub headers ]+ fun_proto = cResType <+> pprCconv <+> ppr wrapperName <> parens argTypes+ cRet+ | isVoidRes = cCall+ | otherwise = text "return" <+> cCall+ cCall = if isFun+ then ppr cName <> parens argVals+ else if null arg_tys+ then ppr cName+ else panic "dsFCall: Unexpected arguments to FFI value import"+ raw_res_ty = case tcSplitIOType_maybe io_res_ty of+ Just (_ioTyCon, res_ty) -> res_ty+ Nothing -> io_res_ty+ isVoidRes = raw_res_ty `eqType` unitTy+ (mHeader, cResType)+ | isVoidRes = (Nothing, text "void")+ | otherwise = toCType raw_res_ty+ pprCconv = ccallConvAttribute CApiConv+ mHeadersArgTypeList+ = [ (header, cType <+> char 'a' <> int n)+ | (t, n) <- zip arg_tys [1..]+ , let (header, cType) = toCType t ]+ (mHeaders, argTypeList) = unzip mHeadersArgTypeList+ argTypes = if null argTypeList+ then text "void"+ else hsep $ punctuate comma argTypeList+ mHeaders' = mDeclHeader : mHeader : mHeaders+ headers = catMaybes mHeaders'+ argVals = hsep $ punctuate comma+ [ char 'a' <> int n+ | (_, n) <- zip arg_tys [1..] ]+ return (fcall', c)+ _ ->+ return (fcall, empty)+ let+ -- Build the worker+ worker_ty = mkForAllTys tv_bndrs (mkFunTys (map idType work_arg_ids) ccall_result_ty)+ tvs = map binderVar tv_bndrs+ the_ccall_app = mkFCall dflags ccall_uniq fcall' val_args ccall_result_ty+ work_rhs = mkLams tvs (mkLams work_arg_ids the_ccall_app)+ work_id = mkSysLocal (fsLit "$wccall") work_uniq worker_ty++ -- Build the wrapper+ work_app = mkApps (mkVarApps (Var work_id) tvs) val_args+ wrapper_body = foldr ($) (res_wrapper work_app) arg_wrappers+ wrap_rhs = mkLams (tvs ++ args) wrapper_body+ wrap_rhs' = Cast wrap_rhs co+ fn_id_w_inl = fn_id `setIdUnfolding` mkInlineUnfoldingWithArity+ (length args) wrap_rhs'++ return ([(work_id, work_rhs), (fn_id_w_inl, wrap_rhs')], empty, cDoc)++{-+************************************************************************+* *+\subsection{Primitive calls}+* *+************************************************************************++This is for `@foreign import prim@' declarations.++Currently, at the core level we pretend that these primitive calls are+foreign calls. It may make more sense in future to have them as a distinct+kind of Id, or perhaps to bundle them with PrimOps since semantically and+for calling convention they are really prim ops.+-}++dsPrimCall :: Id -> Coercion -> ForeignCall+ -> DsM ([(Id, Expr TyVar)], SDoc, SDoc)+dsPrimCall fn_id co fcall = do+ let+ ty = pFst $ coercionKind co+ (tvs, fun_ty) = tcSplitForAllTys ty+ (arg_tys, io_res_ty) = tcSplitFunTys fun_ty++ args <- newSysLocalsDs arg_tys -- no FFI levity-polymorphism++ ccall_uniq <- newUnique+ dflags <- getDynFlags+ let+ call_app = mkFCall dflags ccall_uniq fcall (map Var args) io_res_ty+ rhs = mkLams tvs (mkLams args call_app)+ rhs' = Cast rhs co+ return ([(fn_id, rhs')], empty, empty)++{-+************************************************************************+* *+\subsection{Foreign export}+* *+************************************************************************++The function that does most of the work for `@foreign export@' declarations.+(see below for the boilerplate code a `@foreign export@' declaration expands+ into.)++For each `@foreign export foo@' in a module M we generate:+\begin{itemize}+\item a C function `@foo@', which calls+\item a Haskell stub `@M.\$ffoo@', which calls+\end{itemize}+the user-written Haskell function `@M.foo@'.+-}++dsFExport :: Id -- Either the exported Id,+ -- or the foreign-export-dynamic constructor+ -> Coercion -- Coercion between the Haskell type callable+ -- from C, and its representation type+ -> CLabelString -- The name to export to C land+ -> CCallConv+ -> Bool -- True => foreign export dynamic+ -- so invoke IO action that's hanging off+ -- the first argument's stable pointer+ -> DsM ( SDoc -- contents of Module_stub.h+ , SDoc -- contents of Module_stub.c+ , String -- string describing type to pass to createAdj.+ , Int -- size of args to stub function+ )++dsFExport fn_id co ext_name cconv isDyn = do+ let+ ty = pSnd $ coercionKind co+ (bndrs, orig_res_ty) = tcSplitPiTys ty+ fe_arg_tys' = mapMaybe binderRelevantType_maybe bndrs+ -- We must use tcSplits here, because we want to see+ -- the (IO t) in the corner of the type!+ fe_arg_tys | isDyn = tail fe_arg_tys'+ | otherwise = fe_arg_tys'++ -- Look at the result type of the exported function, orig_res_ty+ -- If it's IO t, return (t, True)+ -- If it's plain t, return (t, False)+ (res_ty, is_IO_res_ty) = case tcSplitIOType_maybe orig_res_ty of+ -- The function already returns IO t+ Just (_ioTyCon, res_ty) -> (res_ty, True)+ -- The function returns t+ Nothing -> (orig_res_ty, False)++ dflags <- getDynFlags+ return $+ mkFExportCBits dflags ext_name+ (if isDyn then Nothing else Just fn_id)+ fe_arg_tys res_ty is_IO_res_ty cconv++{-+@foreign import "wrapper"@ (previously "foreign export dynamic") lets+you dress up Haskell IO actions of some fixed type behind an+externally callable interface (i.e., as a C function pointer). Useful+for callbacks and stuff.++\begin{verbatim}+type Fun = Bool -> Int -> IO Int+foreign import "wrapper" f :: Fun -> IO (FunPtr Fun)++-- Haskell-visible constructor, which is generated from the above:+-- SUP: No check for NULL from createAdjustor anymore???++f :: Fun -> IO (FunPtr Fun)+f cback =+ bindIO (newStablePtr cback)+ (\StablePtr sp# -> IO (\s1# ->+ case _ccall_ createAdjustor cconv sp# ``f_helper'' <arg info> s1# of+ (# s2#, a# #) -> (# s2#, A# a# #)))++foreign import "&f_helper" f_helper :: FunPtr (StablePtr Fun -> Fun)++-- and the helper in C: (approximately; see `mkFExportCBits` below)++f_helper(StablePtr s, HsBool b, HsInt i)+{+ Capability *cap;+ cap = rts_lock();+ rts_evalIO(&cap,+ rts_apply(rts_apply(deRefStablePtr(s),+ rts_mkBool(b)), rts_mkInt(i)));+ rts_unlock(cap);+}+\end{verbatim}+-}++dsFExportDynamic :: Id+ -> Coercion+ -> CCallConv+ -> DsM ([Binding], SDoc, SDoc)+dsFExportDynamic id co0 cconv = do+ mod <- getModule+ dflags <- getDynFlags+ let fe_nm = mkFastString $ zEncodeString+ (moduleStableString mod ++ "$" ++ toCName dflags id)+ -- Construct the label based on the passed id, don't use names+ -- depending on Unique. See #13807 and Note [Unique Determinism].+ cback <- newSysLocalDs arg_ty+ newStablePtrId <- dsLookupGlobalId newStablePtrName+ stable_ptr_tycon <- dsLookupTyCon stablePtrTyConName+ let+ stable_ptr_ty = mkTyConApp stable_ptr_tycon [arg_ty]+ export_ty = mkFunTy stable_ptr_ty arg_ty+ bindIOId <- dsLookupGlobalId bindIOName+ stbl_value <- newSysLocalDs stable_ptr_ty+ (h_code, c_code, typestring, args_size) <- dsFExport id (mkRepReflCo export_ty) fe_nm cconv True+ let+ {-+ The arguments to the external function which will+ create a little bit of (template) code on the fly+ for allowing the (stable pointed) Haskell closure+ to be entered using an external calling convention+ (stdcall, ccall).+ -}+ adj_args = [ mkIntLitInt dflags (ccallConvToInt cconv)+ , Var stbl_value+ , Lit (MachLabel fe_nm mb_sz_args IsFunction)+ , Lit (mkMachString typestring)+ ]+ -- name of external entry point providing these services.+ -- (probably in the RTS.)+ adjustor = fsLit "createAdjustor"++ -- Determine the number of bytes of arguments to the stub function,+ -- so that we can attach the '@N' suffix to its label if it is a+ -- stdcall on Windows.+ mb_sz_args = case cconv of+ StdCallConv -> Just args_size+ _ -> Nothing++ ccall_adj <- dsCCall adjustor adj_args PlayRisky (mkTyConApp io_tc [res_ty])+ -- PlayRisky: the adjustor doesn't allocate in the Haskell heap or do a callback++ let io_app = mkLams tvs $+ Lam cback $+ mkApps (Var bindIOId)+ [ Type stable_ptr_ty+ , Type res_ty+ , mkApps (Var newStablePtrId) [ Type arg_ty, Var cback ]+ , Lam stbl_value ccall_adj+ ]++ fed = (id `setInlineActivation` NeverActive, Cast io_app co0)+ -- Never inline the f.e.d. function, because the litlit+ -- might not be in scope in other modules.++ return ([fed], h_code, c_code)++ where+ ty = pFst (coercionKind co0)+ (tvs,sans_foralls) = tcSplitForAllTys ty+ ([arg_ty], fn_res_ty) = tcSplitFunTys sans_foralls+ Just (io_tc, res_ty) = tcSplitIOType_maybe fn_res_ty+ -- Must have an IO type; hence Just+++toCName :: DynFlags -> Id -> String+toCName dflags i = showSDoc dflags (pprCode CStyle (ppr (idName i)))++{-+*++\subsection{Generating @foreign export@ stubs}++*++For each @foreign export@ function, a C stub function is generated.+The C stub constructs the application of the exported Haskell function+using the hugs/ghc rts invocation API.+-}++mkFExportCBits :: DynFlags+ -> FastString+ -> Maybe Id -- Just==static, Nothing==dynamic+ -> [Type]+ -> Type+ -> Bool -- True <=> returns an IO type+ -> CCallConv+ -> (SDoc,+ SDoc,+ String, -- the argument reps+ Int -- total size of arguments+ )+mkFExportCBits dflags c_nm maybe_target arg_htys res_hty is_IO_res_ty cc+ = (header_bits, c_bits, type_string,+ sum [ widthInBytes (typeWidth rep) | (_,_,_,rep) <- aug_arg_info] -- all the args+ -- NB. the calculation here isn't strictly speaking correct.+ -- We have a primitive Haskell type (eg. Int#, Double#), and+ -- we want to know the size, when passed on the C stack, of+ -- the associated C type (eg. HsInt, HsDouble). We don't have+ -- this information to hand, but we know what GHC's conventions+ -- are for passing around the primitive Haskell types, so we+ -- use that instead. I hope the two coincide --SDM+ )+ where+ -- list the arguments to the C function+ arg_info :: [(SDoc, -- arg name+ SDoc, -- C type+ Type, -- Haskell type+ CmmType)] -- the CmmType+ arg_info = [ let stg_type = showStgType ty in+ (arg_cname n stg_type,+ stg_type,+ ty,+ typeCmmType dflags (getPrimTyOf ty))+ | (ty,n) <- zip arg_htys [1::Int ..] ]++ arg_cname n stg_ty+ | libffi = char '*' <> parens (stg_ty <> char '*') <>+ text "args" <> brackets (int (n-1))+ | otherwise = text ('a':show n)++ -- generate a libffi-style stub if this is a "wrapper" and libffi is enabled+ libffi = cLibFFI && isNothing maybe_target++ type_string+ -- libffi needs to know the result type too:+ | libffi = primTyDescChar dflags res_hty : arg_type_string+ | otherwise = arg_type_string++ arg_type_string = [primTyDescChar dflags ty | (_,_,ty,_) <- arg_info]+ -- just the real args++ -- add some auxiliary args; the stable ptr in the wrapper case, and+ -- a slot for the dummy return address in the wrapper + ccall case+ aug_arg_info+ | isNothing maybe_target = stable_ptr_arg : insertRetAddr dflags cc arg_info+ | otherwise = arg_info++ stable_ptr_arg =+ (text "the_stableptr", text "StgStablePtr", undefined,+ typeCmmType dflags (mkStablePtrPrimTy alphaTy))++ -- stuff to do with the return type of the C function+ res_hty_is_unit = res_hty `eqType` unitTy -- Look through any newtypes++ cResType | res_hty_is_unit = text "void"+ | otherwise = showStgType res_hty++ -- when the return type is integral and word-sized or smaller, it+ -- must be assigned as type ffi_arg (#3516). To see what type+ -- libffi is expecting here, take a look in its own testsuite, e.g.+ -- libffi/testsuite/libffi.call/cls_align_ulonglong.c+ ffi_cResType+ | is_ffi_arg_type = text "ffi_arg"+ | otherwise = cResType+ where+ res_ty_key = getUnique (getName (typeTyCon res_hty))+ is_ffi_arg_type = res_ty_key `notElem`+ [floatTyConKey, doubleTyConKey,+ int64TyConKey, word64TyConKey]++ -- Now we can cook up the prototype for the exported function.+ pprCconv = ccallConvAttribute cc++ header_bits = text "extern" <+> fun_proto <> semi++ fun_args+ | null aug_arg_info = text "void"+ | otherwise = hsep $ punctuate comma+ $ map (\(nm,ty,_,_) -> ty <+> nm) aug_arg_info++ fun_proto+ | libffi+ = text "void" <+> ftext c_nm <>+ parens (text "void *cif STG_UNUSED, void* resp, void** args, void* the_stableptr")+ | otherwise+ = cResType <+> pprCconv <+> ftext c_nm <> parens fun_args++ -- the target which will form the root of what we ask rts_evalIO to run+ the_cfun+ = case maybe_target of+ Nothing -> text "(StgClosure*)deRefStablePtr(the_stableptr)"+ Just hs_fn -> char '&' <> ppr hs_fn <> text "_closure"++ cap = text "cap" <> comma++ -- the expression we give to rts_evalIO+ expr_to_run+ = foldl appArg the_cfun arg_info -- NOT aug_arg_info+ where+ appArg acc (arg_cname, _, arg_hty, _)+ = text "rts_apply"+ <> parens (cap <> acc <> comma <> mkHObj arg_hty <> parens (cap <> arg_cname))++ -- various other bits for inside the fn+ declareResult = text "HaskellObj ret;"+ declareCResult | res_hty_is_unit = empty+ | otherwise = cResType <+> text "cret;"++ assignCResult | res_hty_is_unit = empty+ | otherwise =+ text "cret=" <> unpackHObj res_hty <> parens (text "ret") <> semi++ -- an extern decl for the fn being called+ extern_decl+ = case maybe_target of+ Nothing -> empty+ Just hs_fn -> text "extern StgClosure " <> ppr hs_fn <> text "_closure" <> semi+++ -- finally, the whole darn thing+ c_bits =+ space $$+ extern_decl $$+ fun_proto $$+ vcat+ [ lbrace+ , text "Capability *cap;"+ , declareResult+ , declareCResult+ , text "cap = rts_lock();"+ -- create the application + perform it.+ , text "rts_evalIO" <> parens (+ char '&' <> cap <>+ text "rts_apply" <> parens (+ cap <>+ text "(HaskellObj)"+ <> ptext (if is_IO_res_ty+ then (sLit "runIO_closure")+ else (sLit "runNonIO_closure"))+ <> comma+ <> expr_to_run+ ) <+> comma+ <> text "&ret"+ ) <> semi+ , text "rts_checkSchedStatus" <> parens (doubleQuotes (ftext c_nm)+ <> comma <> text "cap") <> semi+ , assignCResult+ , text "rts_unlock(cap);"+ , ppUnless res_hty_is_unit $+ if libffi+ then char '*' <> parens (ffi_cResType <> char '*') <>+ text "resp = cret;"+ else text "return cret;"+ , rbrace+ ]+++foreignExportInitialiser :: Id -> SDoc+foreignExportInitialiser hs_fn =+ -- Initialise foreign exports by registering a stable pointer from an+ -- __attribute__((constructor)) function.+ -- The alternative is to do this from stginit functions generated in+ -- codeGen/CodeGen.hs; however, stginit functions have a negative impact+ -- on binary sizes and link times because the static linker will think that+ -- all modules that are imported directly or indirectly are actually used by+ -- the program.+ -- (this is bad for big umbrella modules like Graphics.Rendering.OpenGL)+ vcat+ [ text "static void stginit_export_" <> ppr hs_fn+ <> text "() __attribute__((constructor));"+ , text "static void stginit_export_" <> ppr hs_fn <> text "()"+ , braces (text "foreignExportStablePtr"+ <> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")+ <> semi)+ ]+++mkHObj :: Type -> SDoc+mkHObj t = text "rts_mk" <> text (showFFIType t)++unpackHObj :: Type -> SDoc+unpackHObj t = text "rts_get" <> text (showFFIType t)++showStgType :: Type -> SDoc+showStgType t = text "Hs" <> text (showFFIType t)++showFFIType :: Type -> String+showFFIType t = getOccString (getName (typeTyCon t))++toCType :: Type -> (Maybe Header, SDoc)+toCType = f False+ where f voidOK t+ -- First, if we have (Ptr t) of (FunPtr t), then we need to+ -- convert t to a C type and put a * after it. If we don't+ -- know a type for t, then "void" is fine, though.+ | Just (ptr, [t']) <- splitTyConApp_maybe t+ , tyConName ptr `elem` [ptrTyConName, funPtrTyConName]+ = case f True t' of+ (mh, cType') ->+ (mh, cType' <> char '*')+ -- Otherwise, if we have a type constructor application, then+ -- see if there is a C type associated with that constructor.+ -- Note that we aren't looking through type synonyms or+ -- anything, as it may be the synonym that is annotated.+ | Just tycon <- tyConAppTyConPicky_maybe t+ , Just (CType _ mHeader (_,cType)) <- tyConCType_maybe tycon+ = (mHeader, ftext cType)+ -- If we don't know a C type for this type, then try looking+ -- through one layer of type synonym etc.+ | Just t' <- coreView t+ = f voidOK t'+ -- Otherwise we don't know the C type. If we are allowing+ -- void then return that; otherwise something has gone wrong.+ | voidOK = (Nothing, text "void")+ | otherwise+ = pprPanic "toCType" (ppr t)++typeTyCon :: Type -> TyCon+typeTyCon ty+ | Just (tc, _) <- tcSplitTyConApp_maybe (unwrapType ty)+ = tc+ | otherwise+ = pprPanic "DsForeign.typeTyCon" (ppr ty)++insertRetAddr :: DynFlags -> CCallConv+ -> [(SDoc, SDoc, Type, CmmType)]+ -> [(SDoc, SDoc, Type, CmmType)]+insertRetAddr dflags CCallConv args+ = case platformArch platform of+ ArchX86_64+ | platformOS platform == OSMinGW32 ->+ -- On other Windows x86_64 we insert the return address+ -- after the 4th argument, because this is the point+ -- at which we need to flush a register argument to the stack+ -- (See rts/Adjustor.c for details).+ let go :: Int -> [(SDoc, SDoc, Type, CmmType)]+ -> [(SDoc, SDoc, Type, CmmType)]+ go 4 args = ret_addr_arg dflags : args+ go n (arg:args) = arg : go (n+1) args+ go _ [] = []+ in go 0 args+ | otherwise ->+ -- On other x86_64 platforms we insert the return address+ -- after the 6th integer argument, because this is the point+ -- at which we need to flush a register argument to the stack+ -- (See rts/Adjustor.c for details).+ let go :: Int -> [(SDoc, SDoc, Type, CmmType)]+ -> [(SDoc, SDoc, Type, CmmType)]+ go 6 args = ret_addr_arg dflags : args+ go n (arg@(_,_,_,rep):args)+ | cmmEqType_ignoring_ptrhood rep b64 = arg : go (n+1) args+ | otherwise = arg : go n args+ go _ [] = []+ in go 0 args+ _ ->+ ret_addr_arg dflags : args+ where platform = targetPlatform dflags+insertRetAddr _ _ args = args++ret_addr_arg :: DynFlags -> (SDoc, SDoc, Type, CmmType)+ret_addr_arg dflags = (text "original_return_addr", text "void*", undefined,+ typeCmmType dflags addrPrimTy)++-- This function returns the primitive type associated with the boxed+-- type argument to a foreign export (eg. Int ==> Int#).+getPrimTyOf :: Type -> UnaryType+getPrimTyOf ty+ | isBoolTy rep_ty = intPrimTy+ -- Except for Bool, the types we are interested in have a single constructor+ -- with a single primitive-typed argument (see TcType.legalFEArgTyCon).+ | otherwise =+ case splitDataProductType_maybe rep_ty of+ Just (_, _, data_con, [prim_ty]) ->+ ASSERT(dataConSourceArity data_con == 1)+ ASSERT2(isUnliftedType prim_ty, ppr prim_ty)+ prim_ty+ _other -> pprPanic "DsForeign.getPrimTyOf" (ppr ty)+ where+ rep_ty = unwrapType ty++-- represent a primitive type as a Char, for building a string that+-- described the foreign function type. The types are size-dependent,+-- e.g. 'W' is a signed 32-bit integer.+primTyDescChar :: DynFlags -> Type -> Char+primTyDescChar dflags ty+ | ty `eqType` unitTy = 'v'+ | otherwise+ = case typePrimRep1 (getPrimTyOf ty) of+ IntRep -> signed_word+ WordRep -> unsigned_word+ Int64Rep -> 'L'+ Word64Rep -> 'l'+ AddrRep -> 'p'+ FloatRep -> 'f'+ DoubleRep -> 'd'+ _ -> pprPanic "primTyDescChar" (ppr ty)+ where+ (signed_word, unsigned_word)+ | wORD_SIZE dflags == 4 = ('W','w')+ | wORD_SIZE dflags == 8 = ('L','l')+ | otherwise = panic "primTyDescChar"
+ deSugar/DsGRHSs.hs view
@@ -0,0 +1,163 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Matching guarded right-hand-sides (GRHSs)+-}++{-# LANGUAGE CPP #-}++module DsGRHSs ( dsGuarded, dsGRHSs, dsGRHS, isTrueLHsExpr ) where++#include "HsVersions.h"++import {-# SOURCE #-} DsExpr ( dsLExpr, dsLocalBinds )+import {-# SOURCE #-} Match ( matchSinglePat )++import HsSyn+import MkCore+import CoreSyn+import Var++import DsMonad+import DsUtils+import TysWiredIn+import PrelNames+import Type ( Type )+import Module+import Name+import Util+import SrcLoc+import Outputable++{-+@dsGuarded@ is used for both @case@ expressions and pattern bindings.+It desugars:+\begin{verbatim}+ | g1 -> e1+ ...+ | gn -> en+ where binds+\end{verbatim}+producing an expression with a runtime error in the corner if+necessary. The type argument gives the type of the @ei@.+-}++dsGuarded :: GRHSs Id (LHsExpr Id) -> Type -> DsM CoreExpr++dsGuarded grhss rhs_ty = do+ match_result <- dsGRHSs PatBindRhs [] grhss rhs_ty+ error_expr <- mkErrorAppDs nON_EXHAUSTIVE_GUARDS_ERROR_ID rhs_ty empty+ extractMatchResult match_result error_expr++-- In contrast, @dsGRHSs@ produces a @MatchResult@.++dsGRHSs :: HsMatchContext Name -> [Pat Id] -- These are to build a MatchContext from+ -> GRHSs Id (LHsExpr Id) -- Guarded RHSs+ -> Type -- Type of RHS+ -> DsM MatchResult+dsGRHSs hs_ctx _ (GRHSs grhss binds) rhs_ty+ = ASSERT( notNull grhss )+ do { match_results <- mapM (dsGRHS hs_ctx rhs_ty) grhss+ ; let match_result1 = foldr1 combineMatchResults match_results+ match_result2 = adjustMatchResultDs (dsLocalBinds binds) match_result1+ -- NB: nested dsLet inside matchResult+ ; return match_result2 }++dsGRHS :: HsMatchContext Name -> Type -> LGRHS Id (LHsExpr Id) -> DsM MatchResult+dsGRHS hs_ctx rhs_ty (L _ (GRHS guards rhs))+ = matchGuards (map unLoc guards) (PatGuard hs_ctx) rhs rhs_ty++{-+************************************************************************+* *+* matchGuard : make a MatchResult from a guarded RHS *+* *+************************************************************************+-}++matchGuards :: [GuardStmt Id] -- Guard+ -> HsStmtContext Name -- Context+ -> LHsExpr Id -- RHS+ -> Type -- Type of RHS of guard+ -> DsM MatchResult++-- See comments with HsExpr.Stmt re what a BodyStmt means+-- Here we must be in a guard context (not do-expression, nor list-comp)++matchGuards [] _ rhs _+ = do { core_rhs <- dsLExpr rhs+ ; return (cantFailMatchResult core_rhs) }++ -- BodyStmts must be guards+ -- Turn an "otherwise" guard is a no-op. This ensures that+ -- you don't get a "non-exhaustive eqns" message when the guards+ -- finish in "otherwise".+ -- NB: The success of this clause depends on the typechecker not+ -- wrapping the 'otherwise' in empty HsTyApp or HsWrap constructors+ -- If it does, you'll get bogus overlap warnings+matchGuards (BodyStmt e _ _ _ : stmts) ctx rhs rhs_ty+ | Just addTicks <- isTrueLHsExpr e = do+ match_result <- matchGuards stmts ctx rhs rhs_ty+ return (adjustMatchResultDs addTicks match_result)+matchGuards (BodyStmt expr _ _ _ : stmts) ctx rhs rhs_ty = do+ match_result <- matchGuards stmts ctx rhs rhs_ty+ pred_expr <- dsLExpr expr+ return (mkGuardedMatchResult pred_expr match_result)++matchGuards (LetStmt binds : stmts) ctx rhs rhs_ty = do+ match_result <- matchGuards stmts ctx rhs rhs_ty+ return (adjustMatchResultDs (dsLocalBinds binds) match_result)+ -- NB the dsLet occurs inside the match_result+ -- Reason: dsLet takes the body expression as its argument+ -- so we can't desugar the bindings without the+ -- body expression in hand++matchGuards (BindStmt pat bind_rhs _ _ _ : stmts) ctx rhs rhs_ty = do+ match_result <- matchGuards stmts ctx rhs rhs_ty+ core_rhs <- dsLExpr bind_rhs+ matchSinglePat core_rhs (StmtCtxt ctx) pat rhs_ty match_result++matchGuards (LastStmt {} : _) _ _ _ = panic "matchGuards LastStmt"+matchGuards (ParStmt {} : _) _ _ _ = panic "matchGuards ParStmt"+matchGuards (TransStmt {} : _) _ _ _ = panic "matchGuards TransStmt"+matchGuards (RecStmt {} : _) _ _ _ = panic "matchGuards RecStmt"+matchGuards (ApplicativeStmt {} : _) _ _ _ =+ panic "matchGuards ApplicativeLastStmt"++isTrueLHsExpr :: LHsExpr Id -> Maybe (CoreExpr -> DsM CoreExpr)++-- Returns Just {..} if we're sure that the expression is True+-- I.e. * 'True' datacon+-- * 'otherwise' Id+-- * Trivial wappings of these+-- The arguments to Just are any HsTicks that we have found,+-- because we still want to tick then, even it they are always evaluated.+isTrueLHsExpr (L _ (HsVar (L _ v))) | v `hasKey` otherwiseIdKey+ || v `hasKey` getUnique trueDataConId+ = Just return+ -- trueDataConId doesn't have the same unique as trueDataCon+isTrueLHsExpr (L _ (HsConLikeOut con)) | con `hasKey` getUnique trueDataCon = Just return+isTrueLHsExpr (L _ (HsTick tickish e))+ | Just ticks <- isTrueLHsExpr e+ = Just (\x -> do wrapped <- ticks x+ return (Tick tickish wrapped))+ -- This encodes that the result is constant True for Hpc tick purposes;+ -- which is specifically what isTrueLHsExpr is trying to find out.+isTrueLHsExpr (L _ (HsBinTick ixT _ e))+ | Just ticks <- isTrueLHsExpr e+ = Just (\x -> do e <- ticks x+ this_mod <- getModule+ return (Tick (HpcTick this_mod ixT) e))++isTrueLHsExpr (L _ (HsPar e)) = isTrueLHsExpr e+isTrueLHsExpr _ = Nothing++{-+Should {\em fail} if @e@ returns @D@+\begin{verbatim}+f x | p <- e', let C y# = e, f y# = r1+ | otherwise = r2+\end{verbatim}+-}
+ deSugar/DsListComp.hs view
@@ -0,0 +1,883 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Desugaring list comprehensions, monad comprehensions and array comprehensions+-}++{-# LANGUAGE CPP, NamedFieldPuns #-}++module DsListComp ( dsListComp, dsPArrComp, dsMonadComp ) where++#include "HsVersions.h"++import {-# SOURCE #-} DsExpr ( dsExpr, dsLExpr, dsLExprNoLP, dsLocalBinds, dsSyntaxExpr )++import HsSyn+import TcHsSyn+import CoreSyn+import MkCore++import DsMonad -- the monadery used in the desugarer+import DsUtils++import DynFlags+import CoreUtils+import Id+import Type+import TysWiredIn+import Match+import PrelNames+import SrcLoc+import Outputable+import TcType+import ListSetOps( getNth )+import Util++{-+List comprehensions may be desugared in one of two ways: ``ordinary''+(as you would expect if you read SLPJ's book) and ``with foldr/build+turned on'' (if you read Gill {\em et al.}'s paper on the subject).++There will be at least one ``qualifier'' in the input.+-}++dsListComp :: [ExprLStmt Id]+ -> Type -- Type of entire list+ -> DsM CoreExpr+dsListComp lquals res_ty = do+ dflags <- getDynFlags+ let quals = map unLoc lquals+ elt_ty = case tcTyConAppArgs res_ty of+ [elt_ty] -> elt_ty+ _ -> pprPanic "dsListComp" (ppr res_ty $$ ppr lquals)++ if not (gopt Opt_EnableRewriteRules dflags) || gopt Opt_IgnoreInterfacePragmas dflags+ -- Either rules are switched off, or we are ignoring what there are;+ -- Either way foldr/build won't happen, so use the more efficient+ -- Wadler-style desugaring+ || isParallelComp quals+ -- Foldr-style desugaring can't handle parallel list comprehensions+ then deListComp quals (mkNilExpr elt_ty)+ else mkBuildExpr elt_ty (\(c, _) (n, _) -> dfListComp c n quals)+ -- Foldr/build should be enabled, so desugar+ -- into foldrs and builds++ where+ -- We must test for ParStmt anywhere, not just at the head, because an extension+ -- to list comprehensions would be to add brackets to specify the associativity+ -- of qualifier lists. This is really easy to do by adding extra ParStmts into the+ -- mix of possibly a single element in length, so we do this to leave the possibility open+ isParallelComp = any isParallelStmt++ isParallelStmt (ParStmt {}) = True+ isParallelStmt _ = False+++-- This function lets you desugar a inner list comprehension and a list of the binders+-- of that comprehension that we need in the outer comprehension into such an expression+-- and the type of the elements that it outputs (tuples of binders)+dsInnerListComp :: (ParStmtBlock Id Id) -> DsM (CoreExpr, Type)+dsInnerListComp (ParStmtBlock stmts bndrs _)+ = do { let bndrs_tuple_type = mkBigCoreVarTupTy bndrs+ list_ty = mkListTy bndrs_tuple_type++ -- really use original bndrs below!+ ; expr <- dsListComp (stmts ++ [noLoc $ mkLastStmt (mkBigLHsVarTupId bndrs)]) list_ty++ ; return (expr, bndrs_tuple_type) }++-- This function factors out commonality between the desugaring strategies for GroupStmt.+-- Given such a statement it gives you back an expression representing how to compute the transformed+-- list and the tuple that you need to bind from that list in order to proceed with your desugaring+dsTransStmt :: ExprStmt Id -> DsM (CoreExpr, LPat Id)+dsTransStmt (TransStmt { trS_form = form, trS_stmts = stmts, trS_bndrs = binderMap+ , trS_by = by, trS_using = using }) = do+ let (from_bndrs, to_bndrs) = unzip binderMap++ let from_bndrs_tys = map idType from_bndrs+ to_bndrs_tys = map idType to_bndrs++ to_bndrs_tup_ty = mkBigCoreTupTy to_bndrs_tys++ -- Desugar an inner comprehension which outputs a list of tuples of the "from" binders+ (expr', from_tup_ty) <- dsInnerListComp (ParStmtBlock stmts from_bndrs noSyntaxExpr)++ -- Work out what arguments should be supplied to that expression: i.e. is an extraction+ -- function required? If so, create that desugared function and add to arguments+ usingExpr' <- dsLExpr using+ usingArgs' <- case by of+ Nothing -> return [expr']+ Just by_e -> do { by_e' <- dsLExpr by_e+ ; lam' <- matchTuple from_bndrs by_e'+ ; return [lam', expr'] }++ -- Create an unzip function for the appropriate arity and element types and find "map"+ unzip_stuff' <- mkUnzipBind form from_bndrs_tys+ map_id <- dsLookupGlobalId mapName++ -- Generate the expressions to build the grouped list+ let -- First we apply the grouping function to the inner list+ inner_list_expr' = mkApps usingExpr' usingArgs'+ -- Then we map our "unzip" across it to turn the lists of tuples into tuples of lists+ -- We make sure we instantiate the type variable "a" to be a list of "from" tuples and+ -- the "b" to be a tuple of "to" lists!+ -- Then finally we bind the unzip function around that expression+ bound_unzipped_inner_list_expr'+ = case unzip_stuff' of+ Nothing -> inner_list_expr'+ Just (unzip_fn', unzip_rhs') ->+ Let (Rec [(unzip_fn', unzip_rhs')]) $+ mkApps (Var map_id) $+ [ Type (mkListTy from_tup_ty)+ , Type to_bndrs_tup_ty+ , Var unzip_fn'+ , inner_list_expr' ]++ dsNoLevPoly (tcFunResultTyN (length usingArgs') (exprType usingExpr'))+ (text "In the result of a" <+> quotes (text "using") <+> text "function:" <+> ppr 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 '!+ return (bound_unzipped_inner_list_expr', pat)++dsTransStmt _ = panic "dsTransStmt: Not given a TransStmt"++{-+************************************************************************+* *+\subsection[DsListComp-ordinary]{Ordinary desugaring of list comprehensions}+* *+************************************************************************++Just as in Phil's chapter~7 in SLPJ, using the rules for+optimally-compiled list comprehensions. This is what Kevin followed+as well, and I quite happily do the same. The TQ translation scheme+transforms a list of qualifiers (either boolean expressions or+generators) into a single expression which implements the list+comprehension. Because we are generating 2nd-order polymorphic+lambda-calculus, calls to NIL and CONS must be applied to a type+argument, as well as their usual value arguments.+\begin{verbatim}+TE << [ e | qs ] >> = TQ << [ e | qs ] ++ Nil (typeOf e) >>++(Rule C)+TQ << [ e | ] ++ L >> = Cons (typeOf e) TE <<e>> TE <<L>>++(Rule B)+TQ << [ e | b , qs ] ++ L >> =+ if TE << b >> then TQ << [ e | qs ] ++ L >> else TE << L >>++(Rule A')+TQ << [ e | p <- L1, qs ] ++ L2 >> =+ letrec+ h = \ u1 ->+ case u1 of+ [] -> TE << L2 >>+ (u2 : u3) ->+ (( \ TE << p >> -> ( TQ << [e | qs] ++ (h u3) >> )) u2)+ [] (h u3)+ in+ h ( TE << L1 >> )++"h", "u1", "u2", and "u3" are new variables.+\end{verbatim}++@deListComp@ is the TQ translation scheme. Roughly speaking, @dsExpr@+is the TE translation scheme. Note that we carry around the @L@ list+already desugared. @dsListComp@ does the top TE rule mentioned above.++To the above, we add an additional rule to deal with parallel list+comprehensions. The translation goes roughly as follows:+ [ e | p1 <- e11, let v1 = e12, p2 <- e13+ | q1 <- e21, let v2 = e22, q2 <- e23]+ =>+ [ e | ((x1, .., xn), (y1, ..., ym)) <-+ zip [(x1,..,xn) | p1 <- e11, let v1 = e12, p2 <- e13]+ [(y1,..,ym) | q1 <- e21, let v2 = e22, q2 <- e23]]+where (x1, .., xn) are the variables bound in p1, v1, p2+ (y1, .., ym) are the variables bound in q1, v2, q2++In the translation below, the ParStmt branch translates each parallel branch+into a sub-comprehension, and desugars each independently. The resulting lists+are fed to a zip function, we create a binding for all the variables bound in all+the comprehensions, and then we hand things off the the desugarer for bindings.+The zip function is generated here a) because it's small, and b) because then we+don't have to deal with arbitrary limits on the number of zip functions in the+prelude, nor which library the zip function came from.+The introduced tuples are Boxed, but only because I couldn't get it to work+with the Unboxed variety.+-}++deListComp :: [ExprStmt Id] -> CoreExpr -> DsM CoreExpr++deListComp [] _ = panic "deListComp"++deListComp (LastStmt body _ _ : quals) list+ = -- Figure 7.4, SLPJ, p 135, rule C above+ ASSERT( null quals )+ do { core_body <- dsLExpr body+ ; return (mkConsExpr (exprType core_body) core_body list) }++ -- Non-last: must be a guard+deListComp (BodyStmt guard _ _ _ : quals) list = do -- rule B above+ core_guard <- dsLExpr guard+ core_rest <- deListComp quals list+ return (mkIfThenElse core_guard core_rest list)++-- [e | let B, qs] = let B in [e | qs]+deListComp (LetStmt binds : quals) list = do+ core_rest <- deListComp quals list+ dsLocalBinds binds core_rest++deListComp (stmt@(TransStmt {}) : quals) list = do+ (inner_list_expr, pat) <- dsTransStmt stmt+ deBindComp pat inner_list_expr quals list++deListComp (BindStmt pat list1 _ _ _ : quals) core_list2 = do -- rule A' above+ core_list1 <- dsLExprNoLP list1+ deBindComp pat core_list1 quals core_list2++deListComp (ParStmt stmtss_w_bndrs _ _ _ : quals) list+ = do { exps_and_qual_tys <- mapM dsInnerListComp stmtss_w_bndrs+ ; let (exps, qual_tys) = unzip exps_and_qual_tys++ ; (zip_fn, zip_rhs) <- mkZipBind qual_tys++ -- Deal with [e | pat <- zip l1 .. ln] in example above+ ; deBindComp pat (Let (Rec [(zip_fn, zip_rhs)]) (mkApps (Var zip_fn) exps))+ quals list }+ where+ bndrs_s = [bs | ParStmtBlock _ bs _ <- stmtss_w_bndrs]++ -- pat is the pattern ((x1,..,xn), (y1,..,ym)) in the example above+ pat = mkBigLHsPatTupId pats+ pats = map mkBigLHsVarPatTupId bndrs_s++deListComp (RecStmt {} : _) _ = panic "deListComp RecStmt"++deListComp (ApplicativeStmt {} : _) _ =+ panic "deListComp ApplicativeStmt"++deBindComp :: OutPat Id+ -> CoreExpr+ -> [ExprStmt Id]+ -> CoreExpr+ -> DsM (Expr Id)+deBindComp pat core_list1 quals core_list2 = do+ let u3_ty@u1_ty = exprType core_list1 -- two names, same thing++ -- u1_ty is a [alpha] type, and u2_ty = alpha+ let u2_ty = hsLPatType pat++ let res_ty = exprType core_list2+ h_ty = u1_ty `mkFunTy` res_ty++ -- no levity polymorphism here, as list comprehensions don't work+ -- with RebindableSyntax. NB: These are *not* monad comps.+ [h, u1, u2, u3] <- newSysLocalsDs [h_ty, u1_ty, u2_ty, u3_ty]++ -- the "fail" value ...+ let+ core_fail = App (Var h) (Var u3)+ letrec_body = App (Var h) core_list1++ rest_expr <- deListComp quals core_fail+ core_match <- matchSimply (Var u2) (StmtCtxt ListComp) pat rest_expr core_fail++ let+ rhs = Lam u1 $+ Case (Var u1) u1 res_ty+ [(DataAlt nilDataCon, [], core_list2),+ (DataAlt consDataCon, [u2, u3], core_match)]+ -- Increasing order of tag++ return (Let (Rec [(h, rhs)]) letrec_body)++{-+************************************************************************+* *+\subsection[DsListComp-foldr-build]{Foldr/Build desugaring of list comprehensions}+* *+************************************************************************++@dfListComp@ are the rules used with foldr/build turned on:++\begin{verbatim}+TE[ e | ] c n = c e n+TE[ e | b , q ] c n = if b then TE[ e | q ] c n else n+TE[ e | p <- l , q ] c n = let+ f = \ x b -> case x of+ p -> TE[ e | q ] c b+ _ -> b+ in+ foldr f n l+\end{verbatim}+-}++dfListComp :: Id -> Id -- 'c' and 'n'+ -> [ExprStmt Id] -- the rest of the qual's+ -> DsM CoreExpr++dfListComp _ _ [] = panic "dfListComp"++dfListComp c_id n_id (LastStmt body _ _ : quals)+ = ASSERT( null quals )+ do { core_body <- dsLExprNoLP body+ ; return (mkApps (Var c_id) [core_body, Var n_id]) }++ -- Non-last: must be a guard+dfListComp c_id n_id (BodyStmt guard _ _ _ : quals) = do+ core_guard <- dsLExpr guard+ core_rest <- dfListComp c_id n_id quals+ return (mkIfThenElse core_guard core_rest (Var n_id))++dfListComp c_id n_id (LetStmt binds : quals) = do+ -- new in 1.3, local bindings+ core_rest <- dfListComp c_id n_id quals+ dsLocalBinds binds core_rest++dfListComp c_id n_id (stmt@(TransStmt {}) : quals) = do+ (inner_list_expr, pat) <- dsTransStmt stmt+ -- Anyway, we bind the newly grouped list via the generic binding function+ dfBindComp c_id n_id (pat, inner_list_expr) quals++dfListComp c_id n_id (BindStmt pat list1 _ _ _ : quals) = do+ -- evaluate the two lists+ core_list1 <- dsLExpr list1++ -- Do the rest of the work in the generic binding builder+ dfBindComp c_id n_id (pat, core_list1) quals++dfListComp _ _ (ParStmt {} : _) = panic "dfListComp ParStmt"+dfListComp _ _ (RecStmt {} : _) = panic "dfListComp RecStmt"+dfListComp _ _ (ApplicativeStmt {} : _) =+ panic "dfListComp ApplicativeStmt"++dfBindComp :: Id -> Id -- 'c' and 'n'+ -> (LPat Id, CoreExpr)+ -> [ExprStmt Id] -- the rest of the qual's+ -> DsM CoreExpr+dfBindComp c_id n_id (pat, core_list1) quals = do+ -- find the required type+ let x_ty = hsLPatType pat+ let b_ty = idType n_id++ -- create some new local id's+ b <- newSysLocalDs b_ty+ x <- newSysLocalDs x_ty++ -- build rest of the comprehesion+ core_rest <- dfListComp c_id b quals++ -- build the pattern match+ core_expr <- matchSimply (Var x) (StmtCtxt ListComp)+ pat core_rest (Var b)++ -- now build the outermost foldr, and return+ mkFoldrExpr x_ty b_ty (mkLams [x, b] core_expr) (Var n_id) core_list1++{-+************************************************************************+* *+\subsection[DsFunGeneration]{Generation of zip/unzip functions for use in desugaring}+* *+************************************************************************+-}++mkZipBind :: [Type] -> DsM (Id, CoreExpr)+-- mkZipBind [t1, t2]+-- = (zip, \as1:[t1] as2:[t2]+-- -> case as1 of+-- [] -> []+-- (a1:as'1) -> case as2 of+-- [] -> []+-- (a2:as'2) -> (a1, a2) : zip as'1 as'2)]++mkZipBind elt_tys = do+ ass <- mapM newSysLocalDs elt_list_tys+ as' <- mapM newSysLocalDs elt_tys+ as's <- mapM newSysLocalDs elt_list_tys++ zip_fn <- newSysLocalDs zip_fn_ty++ let inner_rhs = mkConsExpr elt_tuple_ty+ (mkBigCoreVarTup as')+ (mkVarApps (Var zip_fn) as's)+ zip_body = foldr mk_case inner_rhs (zip3 ass as' as's)++ return (zip_fn, mkLams ass zip_body)+ where+ elt_list_tys = map mkListTy elt_tys+ elt_tuple_ty = mkBigCoreTupTy elt_tys+ elt_tuple_list_ty = mkListTy elt_tuple_ty++ zip_fn_ty = mkFunTys elt_list_tys elt_tuple_list_ty++ mk_case (as, a', as') rest+ = Case (Var as) as elt_tuple_list_ty+ [(DataAlt nilDataCon, [], mkNilExpr elt_tuple_ty),+ (DataAlt consDataCon, [a', as'], rest)]+ -- Increasing order of tag+++mkUnzipBind :: TransForm -> [Type] -> DsM (Maybe (Id, CoreExpr))+-- mkUnzipBind [t1, t2]+-- = (unzip, \ys :: [(t1, t2)] -> foldr (\ax :: (t1, t2) axs :: ([t1], [t2])+-- -> case ax of+-- (x1, x2) -> case axs of+-- (xs1, xs2) -> (x1 : xs1, x2 : xs2))+-- ([], [])+-- ys)+--+-- We use foldr here in all cases, even if rules are turned off, because we may as well!+mkUnzipBind ThenForm _+ = return Nothing -- No unzipping for ThenForm+mkUnzipBind _ elt_tys+ = do { ax <- newSysLocalDs elt_tuple_ty+ ; axs <- newSysLocalDs elt_list_tuple_ty+ ; ys <- newSysLocalDs elt_tuple_list_ty+ ; xs <- mapM newSysLocalDs elt_tys+ ; xss <- mapM newSysLocalDs elt_list_tys++ ; unzip_fn <- newSysLocalDs unzip_fn_ty++ ; [us1, us2] <- sequence [newUniqueSupply, newUniqueSupply]++ ; let nil_tuple = mkBigCoreTup (map mkNilExpr elt_tys)+ concat_expressions = map mkConcatExpression (zip3 elt_tys (map Var xs) (map Var xss))+ tupled_concat_expression = mkBigCoreTup concat_expressions++ folder_body_inner_case = mkTupleCase us1 xss tupled_concat_expression axs (Var axs)+ folder_body_outer_case = mkTupleCase us2 xs folder_body_inner_case ax (Var ax)+ folder_body = mkLams [ax, axs] folder_body_outer_case++ ; unzip_body <- mkFoldrExpr elt_tuple_ty elt_list_tuple_ty folder_body nil_tuple (Var ys)+ ; return (Just (unzip_fn, mkLams [ys] unzip_body)) }+ where+ elt_tuple_ty = mkBigCoreTupTy elt_tys+ elt_tuple_list_ty = mkListTy elt_tuple_ty+ elt_list_tys = map mkListTy elt_tys+ elt_list_tuple_ty = mkBigCoreTupTy elt_list_tys++ unzip_fn_ty = elt_tuple_list_ty `mkFunTy` elt_list_tuple_ty++ mkConcatExpression (list_element_ty, head, tail) = mkConsExpr list_element_ty head tail++{-+************************************************************************+* *+\subsection[DsPArrComp]{Desugaring of array comprehensions}+* *+************************************************************************+-}++-- entry point for desugaring a parallel array comprehension+--+-- [:e | qss:] = <<[:e | qss:]>> () [:():]+--+dsPArrComp :: [ExprStmt Id]+ -> DsM CoreExpr++-- Special case for parallel comprehension+dsPArrComp (ParStmt qss _ _ _ : quals) = dePArrParComp qss quals++-- Special case for simple generators:+--+-- <<[:e' | p <- e, qs:]>> = <<[: e' | qs :]>> p e+--+-- if matching again p cannot fail, or else+--+-- <<[:e' | p <- e, qs:]>> =+-- <<[:e' | qs:]>> p (filterP (\x -> case x of {p -> True; _ -> False}) e)+--+dsPArrComp (BindStmt p e _ _ _ : qs) = do+ filterP <- dsDPHBuiltin filterPVar+ ce <- dsLExprNoLP e+ let ety'ce = parrElemType ce+ false = Var falseDataConId+ true = Var trueDataConId+ v <- newSysLocalDs ety'ce+ pred <- matchSimply (Var v) (StmtCtxt PArrComp) p true false+ let gen | isIrrefutableHsPat p = ce+ | otherwise = mkApps (Var filterP) [Type ety'ce, mkLams [v] pred, ce]+ dePArrComp qs p gen++dsPArrComp qs = do -- no ParStmt in `qs'+ sglP <- dsDPHBuiltin singletonPVar+ let unitArray = mkApps (Var sglP) [Type unitTy, mkCoreTup []]+ dePArrComp qs (noLoc $ WildPat unitTy) unitArray++++-- the work horse+--+dePArrComp :: [ExprStmt Id]+ -> LPat Id -- the current generator pattern+ -> CoreExpr -- the current generator expression+ -> DsM CoreExpr++dePArrComp [] _ _ = panic "dePArrComp"++--+-- <<[:e' | :]>> pa ea = mapP (\pa -> e') ea+--+dePArrComp (LastStmt e' _ _ : quals) pa cea+ = ASSERT( null quals )+ do { mapP <- dsDPHBuiltin mapPVar+ ; let ty = parrElemType cea+ ; (clam, ty'e') <- deLambda ty pa e'+ ; return $ mkApps (Var mapP) [Type ty, Type ty'e', clam, cea] }+--+-- <<[:e' | b, qs:]>> pa ea = <<[:e' | qs:]>> pa (filterP (\pa -> b) ea)+--+dePArrComp (BodyStmt b _ _ _ : qs) pa cea = do+ filterP <- dsDPHBuiltin filterPVar+ let ty = parrElemType cea+ (clam,_) <- deLambda ty pa b+ dePArrComp qs pa (mkApps (Var filterP) [Type ty, clam, cea])++--+-- <<[:e' | p <- e, qs:]>> pa ea =+-- let ef = \pa -> e+-- in+-- <<[:e' | qs:]>> (pa, p) (crossMap ea ef)+--+-- if matching again p cannot fail, or else+--+-- <<[:e' | p <- e, qs:]>> pa ea =+-- let ef = \pa -> filterP (\x -> case x of {p -> True; _ -> False}) e+-- in+-- <<[:e' | qs:]>> (pa, p) (crossMapP ea ef)+--+dePArrComp (BindStmt p e _ _ _ : qs) pa cea = do+ filterP <- dsDPHBuiltin filterPVar+ crossMapP <- dsDPHBuiltin crossMapPVar+ ce <- dsLExpr e+ let ety'cea = parrElemType cea+ ety'ce = parrElemType ce+ false = Var falseDataConId+ true = Var trueDataConId+ v <- newSysLocalDs ety'ce+ pred <- matchSimply (Var v) (StmtCtxt PArrComp) p true false+ let cef | isIrrefutableHsPat p = ce+ | otherwise = mkApps (Var filterP) [Type ety'ce, mkLams [v] pred, ce]+ (clam, _) <- mkLambda ety'cea pa cef+ let ety'cef = ety'ce -- filter doesn't change the element type+ pa' = mkLHsPatTup [pa, p]++ dePArrComp qs pa' (mkApps (Var crossMapP)+ [Type ety'cea, Type ety'cef, cea, clam])+--+-- <<[:e' | let ds, qs:]>> pa ea =+-- <<[:e' | qs:]>> (pa, (x_1, ..., x_n))+-- (mapP (\v@pa -> let ds in (v, (x_1, ..., x_n))) ea)+-- where+-- {x_1, ..., x_n} = DV (ds) -- Defined Variables+--+dePArrComp (LetStmt lds@(L _ ds) : qs) pa cea = do+ mapP <- dsDPHBuiltin mapPVar+ let xs = collectLocalBinders ds+ ty'cea = parrElemType cea+ v <- newSysLocalDs ty'cea+ clet <- dsLocalBinds lds (mkCoreTup (map Var xs))+ let'v <- newSysLocalDs (exprType clet)+ let projBody = mkCoreLet (NonRec let'v clet) $+ mkCoreTup [Var v, Var let'v]+ errTy = exprType projBody+ errMsg = text "DsListComp.dePArrComp: internal error!"+ cerr <- mkErrorAppDs pAT_ERROR_ID errTy errMsg+ ccase <- matchSimply (Var v) (StmtCtxt PArrComp) pa projBody cerr+ let pa' = mkLHsPatTup [pa, mkLHsPatTup (map nlVarPat xs)]+ proj = mkLams [v] ccase+ dePArrComp qs pa' (mkApps (Var mapP)+ [Type ty'cea, Type errTy, proj, cea])+--+-- The parser guarantees that parallel comprehensions can only appear as+-- singleton qualifier lists, which we already special case in the caller.+-- So, encountering one here is a bug.+--+dePArrComp (ParStmt {} : _) _ _ =+ panic "DsListComp.dePArrComp: malformed comprehension AST: ParStmt"+dePArrComp (TransStmt {} : _) _ _ = panic "DsListComp.dePArrComp: TransStmt"+dePArrComp (RecStmt {} : _) _ _ = panic "DsListComp.dePArrComp: RecStmt"+dePArrComp (ApplicativeStmt {} : _) _ _ =+ panic "DsListComp.dePArrComp: ApplicativeStmt"++-- <<[:e' | qs | qss:]>> pa ea =+-- <<[:e' | qss:]>> (pa, (x_1, ..., x_n))+-- (zipP ea <<[:(x_1, ..., x_n) | qs:]>>)+-- where+-- {x_1, ..., x_n} = DV (qs)+--+dePArrParComp :: [ParStmtBlock Id Id] -> [ExprStmt Id] -> DsM CoreExpr+dePArrParComp qss quals = do+ (pQss, ceQss) <- deParStmt qss+ dePArrComp quals pQss ceQss+ where+ deParStmt [] =+ -- empty parallel statement lists have no source representation+ panic "DsListComp.dePArrComp: Empty parallel list comprehension"+ deParStmt (ParStmtBlock qs xs _:qss) = do -- first statement+ let res_expr = mkLHsVarTuple xs+ cqs <- dsPArrComp (map unLoc qs ++ [mkLastStmt res_expr])+ parStmts qss (mkLHsVarPatTup xs) cqs+ ---+ parStmts [] pa cea = return (pa, cea)+ parStmts (ParStmtBlock qs xs _:qss) pa cea = do -- subsequent statements (zip'ed)+ zipP <- dsDPHBuiltin zipPVar+ let pa' = mkLHsPatTup [pa, mkLHsVarPatTup xs]+ ty'cea = parrElemType cea+ res_expr = mkLHsVarTuple xs+ cqs <- dsPArrComp (map unLoc qs ++ [mkLastStmt res_expr])+ let ty'cqs = parrElemType cqs+ cea' = mkApps (Var zipP) [Type ty'cea, Type ty'cqs, cea, cqs]+ parStmts qss pa' cea'++-- generate Core corresponding to `\p -> e'+--+deLambda :: Type -- type of the argument (not levity-polymorphic)+ -> LPat Id -- argument pattern+ -> LHsExpr Id -- body+ -> DsM (CoreExpr, Type)+deLambda ty p e =+ mkLambda ty p =<< dsLExpr e++-- generate Core for a lambda pattern match, where the body is already in Core+--+mkLambda :: Type -- type of the argument (not levity-polymorphic)+ -> LPat Id -- argument pattern+ -> CoreExpr -- desugared body+ -> DsM (CoreExpr, Type)+mkLambda ty p ce = do+ v <- newSysLocalDs ty+ let errMsg = text "DsListComp.deLambda: internal error!"+ ce'ty = exprType ce+ cerr <- mkErrorAppDs pAT_ERROR_ID ce'ty errMsg+ res <- matchSimply (Var v) (StmtCtxt PArrComp) p ce cerr+ return (mkLams [v] res, ce'ty)++-- obtain the element type of the parallel array produced by the given Core+-- expression+--+parrElemType :: CoreExpr -> Type+parrElemType e =+ case splitTyConApp_maybe (exprType e) of+ Just (tycon, [ty]) | tycon == parrTyCon -> ty+ _ -> panic+ "DsListComp.parrElemType: not a parallel array type"++-- Translation for monad comprehensions++-- Entry point for monad comprehension desugaring+dsMonadComp :: [ExprLStmt Id] -> DsM CoreExpr+dsMonadComp stmts = dsMcStmts stmts++dsMcStmts :: [ExprLStmt Id] -> DsM CoreExpr+dsMcStmts [] = panic "dsMcStmts"+dsMcStmts (L loc stmt : lstmts) = putSrcSpanDs loc (dsMcStmt stmt lstmts)++---------------+dsMcStmt :: ExprStmt Id -> [ExprLStmt Id] -> DsM CoreExpr++dsMcStmt (LastStmt body _ ret_op) stmts+ = ASSERT( null stmts )+ do { body' <- dsLExpr body+ ; dsSyntaxExpr ret_op [body'] }++-- [ .. | let binds, stmts ]+dsMcStmt (LetStmt binds) stmts+ = do { rest <- dsMcStmts stmts+ ; dsLocalBinds binds rest }++-- [ .. | a <- m, stmts ]+dsMcStmt (BindStmt pat rhs bind_op fail_op bind_ty) stmts+ = do { rhs' <- dsLExpr rhs+ ; dsMcBindStmt pat rhs' bind_op fail_op bind_ty stmts }++-- Apply `guard` to the `exp` expression+--+-- [ .. | exp, stmts ]+--+dsMcStmt (BodyStmt exp then_exp guard_exp _) stmts+ = do { exp' <- dsLExpr exp+ ; rest <- dsMcStmts stmts+ ; guard_exp' <- dsSyntaxExpr guard_exp [exp']+ ; dsSyntaxExpr then_exp [guard_exp', rest] }++-- Group statements desugar like this:+--+-- [| (q, then group by e using f); rest |]+-- ---> f {qt} (\qv -> e) [| q; return qv |] >>= \ n_tup ->+-- case unzip n_tup of qv' -> [| rest |]+--+-- where variables (v1:t1, ..., vk:tk) are bound by q+-- qv = (v1, ..., vk)+-- qt = (t1, ..., tk)+-- (>>=) :: m2 a -> (a -> m3 b) -> m3 b+-- f :: forall a. (a -> t) -> m1 a -> m2 (n a)+-- n_tup :: n qt+-- unzip :: n qt -> (n t1, ..., n tk) (needs Functor n)++dsMcStmt (TransStmt { trS_stmts = stmts, trS_bndrs = bndrs+ , trS_by = by, trS_using = using+ , trS_ret = return_op, trS_bind = bind_op+ , trS_bind_arg_ty = n_tup_ty' -- n (a,b,c)+ , trS_fmap = fmap_op, trS_form = form }) stmts_rest+ = do { let (from_bndrs, to_bndrs) = unzip bndrs++ ; let from_bndr_tys = map idType from_bndrs -- Types ty+++ -- Desugar an inner comprehension which outputs a list of tuples of the "from" binders+ ; expr' <- dsInnerMonadComp stmts from_bndrs return_op++ -- Work out what arguments should be supplied to that expression: i.e. is an extraction+ -- function required? If so, create that desugared function and add to arguments+ ; usingExpr' <- dsLExpr using+ ; usingArgs' <- case by of+ Nothing -> return [expr']+ Just by_e -> do { by_e' <- dsLExpr by_e+ ; lam' <- matchTuple from_bndrs by_e'+ ; return [lam', expr'] }++ -- Generate the expressions to build the grouped list+ -- Build a pattern that ensures the consumer binds into the NEW binders,+ -- which hold monads rather than single values+ ; let tup_n_ty' = mkBigCoreVarTupTy to_bndrs++ ; body <- dsMcStmts stmts_rest+ ; n_tup_var' <- newSysLocalDsNoLP n_tup_ty'+ ; tup_n_var' <- newSysLocalDs tup_n_ty'+ ; tup_n_expr' <- mkMcUnzipM form fmap_op n_tup_var' from_bndr_tys+ ; us <- newUniqueSupply+ ; let rhs' = mkApps usingExpr' usingArgs'+ body' = mkTupleCase us to_bndrs body tup_n_var' tup_n_expr'++ ; dsSyntaxExpr bind_op [rhs', Lam n_tup_var' body'] }++-- Parallel statements. Use `Control.Monad.Zip.mzip` to zip parallel+-- statements, for example:+--+-- [ body | qs1 | qs2 | qs3 ]+-- -> [ body | (bndrs1, (bndrs2, bndrs3))+-- <- [bndrs1 | qs1] `mzip` ([bndrs2 | qs2] `mzip` [bndrs3 | qs3]) ]+--+-- where `mzip` has type+-- mzip :: forall a b. m a -> m b -> m (a,b)+-- NB: we need a polymorphic mzip because we call it several times++dsMcStmt (ParStmt blocks mzip_op bind_op bind_ty) stmts_rest+ = do { exps_w_tys <- mapM ds_inner blocks -- Pairs (exp :: m ty, ty)+ ; mzip_op' <- dsExpr mzip_op++ ; let -- The pattern variables+ pats = [ mkBigLHsVarPatTupId bs | ParStmtBlock _ bs _ <- blocks]+ -- Pattern with tuples of variables+ -- [v1,v2,v3] => (v1, (v2, v3))+ pat = foldr1 (\p1 p2 -> mkLHsPatTup [p1, p2]) pats+ (rhs, _) = foldr1 (\(e1,t1) (e2,t2) ->+ (mkApps mzip_op' [Type t1, Type t2, e1, e2],+ mkBoxedTupleTy [t1,t2]))+ exps_w_tys++ ; dsMcBindStmt pat rhs bind_op noSyntaxExpr bind_ty stmts_rest }+ where+ ds_inner (ParStmtBlock stmts bndrs return_op)+ = do { exp <- dsInnerMonadComp stmts bndrs return_op+ ; return (exp, mkBigCoreVarTupTy bndrs) }++dsMcStmt stmt _ = pprPanic "dsMcStmt: unexpected stmt" (ppr stmt)+++matchTuple :: [Id] -> CoreExpr -> DsM CoreExpr+-- (matchTuple [a,b,c] body)+-- returns the Core term+-- \x. case x of (a,b,c) -> body+matchTuple ids body+ = do { us <- newUniqueSupply+ ; tup_id <- newSysLocalDs (mkBigCoreVarTupTy ids)+ ; return (Lam tup_id $ mkTupleCase us ids body tup_id (Var tup_id)) }++-- general `rhs' >>= \pat -> stmts` desugaring where `rhs'` is already a+-- desugared `CoreExpr`+dsMcBindStmt :: LPat Id+ -> CoreExpr -- ^ the desugared rhs of the bind statement+ -> SyntaxExpr Id+ -> SyntaxExpr Id+ -> Type -- ^ S in (>>=) :: Q -> (R -> S) -> T+ -> [ExprLStmt Id]+ -> DsM CoreExpr+dsMcBindStmt pat rhs' bind_op fail_op res1_ty stmts+ = do { body <- dsMcStmts stmts+ ; var <- selectSimpleMatchVarL pat+ ; match <- matchSinglePat (Var var) (StmtCtxt DoExpr) pat+ res1_ty (cantFailMatchResult body)+ ; match_code <- handle_failure pat match fail_op+ ; dsSyntaxExpr bind_op [rhs', Lam var match_code] }++ where+ -- In a monad comprehension expression, pattern-match failure just calls+ -- the monadic `fail` rather than throwing an exception+ handle_failure pat match fail_op+ | matchCanFail match+ = do { dflags <- getDynFlags+ ; fail_msg <- mkStringExpr (mk_fail_msg dflags pat)+ ; fail_expr <- dsSyntaxExpr fail_op [fail_msg]+ ; extractMatchResult match fail_expr }+ | otherwise+ = extractMatchResult match (error "It can't fail")++ mk_fail_msg :: DynFlags -> Located e -> String+ mk_fail_msg dflags pat+ = "Pattern match failure in monad comprehension at " +++ showPpr dflags (getLoc pat)++-- Desugar nested monad comprehensions, for example in `then..` constructs+-- dsInnerMonadComp quals [a,b,c] ret_op+-- returns the desugaring of+-- [ (a,b,c) | quals ]++dsInnerMonadComp :: [ExprLStmt Id]+ -> [Id] -- Return a tuple of these variables+ -> SyntaxExpr Id -- The monomorphic "return" operator+ -> DsM CoreExpr+dsInnerMonadComp stmts bndrs ret_op+ = dsMcStmts (stmts ++ [noLoc (LastStmt (mkBigLHsVarTupId bndrs) False ret_op)])+++-- The `unzip` function for `GroupStmt` in a monad comprehensions+--+-- unzip :: m (a,b,..) -> (m a,m b,..)+-- unzip m_tuple = ( liftM selN1 m_tuple+-- , liftM selN2 m_tuple+-- , .. )+--+-- mkMcUnzipM fmap ys [t1, t2]+-- = ( fmap (selN1 :: (t1, t2) -> t1) ys+-- , fmap (selN2 :: (t1, t2) -> t2) ys )++mkMcUnzipM :: TransForm+ -> HsExpr TcId -- fmap+ -> Id -- Of type n (a,b,c)+ -> [Type] -- [a,b,c] (not levity-polymorphic)+ -> DsM CoreExpr -- Of type (n a, n b, n c)+mkMcUnzipM ThenForm _ ys _+ = return (Var ys) -- No unzipping to do++mkMcUnzipM _ fmap_op ys elt_tys+ = do { fmap_op' <- dsExpr fmap_op+ ; xs <- mapM newSysLocalDs elt_tys+ ; let tup_ty = mkBigCoreTupTy elt_tys+ ; tup_xs <- newSysLocalDs tup_ty++ ; let mk_elt i = mkApps fmap_op' -- fmap :: forall a b. (a -> b) -> n a -> n b+ [ Type tup_ty, Type (getNth elt_tys i)+ , mk_sel i, Var ys]++ mk_sel n = Lam tup_xs $+ mkTupleSelector xs (getNth xs n) tup_xs (Var tup_xs)++ ; return (mkBigCoreTup (map mk_elt [0..length elt_tys - 1])) }
+ deSugar/DsMeta.hs view
@@ -0,0 +1,2513 @@+{-# LANGUAGE CPP, TypeFamilies #-}++-----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 2006+--+-- The purpose of this module is to transform an HsExpr into a CoreExpr which+-- when evaluated, returns a (Meta.Q Meta.Exp) computation analogous to the+-- input HsExpr. We do this in the DsM monad, which supplies access to+-- CoreExpr's of the "smart constructors" of the Meta.Exp datatype.+--+-- It also defines a bunch of knownKeyNames, in the same way as is done+-- in prelude/PrelNames. It's much more convenient to do it here, because+-- otherwise we have to recompile PrelNames whenever we add a Name, which is+-- a Royal Pain (triggers other recompilation).+-----------------------------------------------------------------------------++module DsMeta( dsBracket ) where++#include "HsVersions.h"++import {-# SOURCE #-} DsExpr ( dsExpr )++import MatchLit+import DsMonad++import qualified Language.Haskell.TH as TH++import HsSyn+import Class+import PrelNames+-- To avoid clashes with DsMeta.varName we must make a local alias for+-- OccName.varName we do this by removing varName from the import of+-- OccName above, making a qualified instance of OccName and using+-- OccNameAlias.varName where varName ws previously used in this file.+import qualified OccName( isDataOcc, isVarOcc, isTcOcc )++import Module+import Id+import Name hiding( isVarOcc, isTcOcc, varName, tcName )+import THNames+import NameEnv+import NameSet+import TcType+import TyCon+import TysWiredIn+import CoreSyn+import MkCore+import CoreUtils+import SrcLoc+import Unique+import BasicTypes+import Outputable+import Bag+import DynFlags+import FastString+import ForeignCall+import Util+import Maybes+import MonadUtils++import Data.ByteString ( unpack )+import Control.Monad+import Data.List++-----------------------------------------------------------------------------+dsBracket :: HsBracket Name -> [PendingTcSplice] -> DsM CoreExpr+-- Returns a CoreExpr of type TH.ExpQ+-- The quoted thing is parameterised over Name, even though it has+-- been type checked. We don't want all those type decorations!++dsBracket brack splices+ = dsExtendMetaEnv new_bit (do_brack brack)+ where+ new_bit = mkNameEnv [(n, DsSplice (unLoc e)) | PendingTcSplice n e <- splices]++ do_brack (VarBr _ n) = do { MkC e1 <- lookupOcc n ; return e1 }+ do_brack (ExpBr e) = do { MkC e1 <- repLE e ; return e1 }+ do_brack (PatBr p) = do { MkC p1 <- repTopP p ; return p1 }+ do_brack (TypBr t) = do { MkC t1 <- repLTy t ; return t1 }+ do_brack (DecBrG gp) = do { MkC ds1 <- repTopDs gp ; return ds1 }+ do_brack (DecBrL _) = panic "dsBracket: unexpected DecBrL"+ do_brack (TExpBr e) = do { MkC e1 <- repLE e ; return e1 }++{- -------------- Examples --------------------++ [| \x -> x |]+====>+ gensym (unpackString "x"#) `bindQ` \ x1::String ->+ lam (pvar x1) (var x1)+++ [| \x -> $(f [| x |]) |]+====>+ gensym (unpackString "x"#) `bindQ` \ x1::String ->+ lam (pvar x1) (f (var x1))+-}+++-------------------------------------------------------+-- Declarations+-------------------------------------------------------++repTopP :: LPat Name -> DsM (Core TH.PatQ)+repTopP pat = do { ss <- mkGenSyms (collectPatBinders pat)+ ; pat' <- addBinds ss (repLP pat)+ ; wrapGenSyms ss pat' }++repTopDs :: HsGroup Name -> DsM (Core (TH.Q [TH.Dec]))+repTopDs group@(HsGroup { hs_valds = valds+ , hs_splcds = splcds+ , hs_tyclds = tyclds+ , hs_derivds = derivds+ , hs_fixds = fixds+ , hs_defds = defds+ , hs_fords = fords+ , hs_warnds = warnds+ , hs_annds = annds+ , hs_ruleds = ruleds+ , hs_vects = vects+ , hs_docs = docs })+ = do { let { bndrs = hsSigTvBinders valds+ ++ hsGroupBinders group+ ++ hsPatSynSelectors valds+ ; instds = tyclds >>= group_instds } ;+ ss <- mkGenSyms bndrs ;++ -- Bind all the names mainly to avoid repeated use of explicit strings.+ -- Thus we get+ -- do { t :: String <- genSym "T" ;+ -- return (Data t [] ...more t's... }+ -- The other important reason is that the output must mention+ -- only "T", not "Foo:T" where Foo is the current module++ decls <- addBinds ss (+ do { val_ds <- rep_val_binds valds+ ; _ <- mapM no_splice splcds+ ; tycl_ds <- mapM repTyClD (tyClGroupTyClDecls tyclds)+ ; role_ds <- mapM repRoleD (concatMap group_roles tyclds)+ ; inst_ds <- mapM repInstD instds+ ; deriv_ds <- mapM repStandaloneDerivD derivds+ ; fix_ds <- mapM repFixD fixds+ ; _ <- mapM no_default_decl defds+ ; for_ds <- mapM repForD fords+ ; _ <- mapM no_warn (concatMap (wd_warnings . unLoc)+ warnds)+ ; ann_ds <- mapM repAnnD annds+ ; rule_ds <- mapM repRuleD (concatMap (rds_rules . unLoc)+ ruleds)+ ; _ <- mapM no_vect vects+ ; _ <- mapM no_doc docs++ -- more needed+ ; return (de_loc $ sort_by_loc $+ val_ds ++ catMaybes tycl_ds ++ role_ds+ ++ (concat fix_ds)+ ++ inst_ds ++ rule_ds ++ for_ds+ ++ ann_ds ++ deriv_ds) }) ;++ decl_ty <- lookupType decQTyConName ;+ let { core_list = coreList' decl_ty decls } ;++ dec_ty <- lookupType decTyConName ;+ q_decs <- repSequenceQ dec_ty core_list ;++ wrapGenSyms ss q_decs+ }+ where+ no_splice (L loc _)+ = notHandledL loc "Splices within declaration brackets" empty+ no_default_decl (L loc decl)+ = notHandledL loc "Default declarations" (ppr decl)+ no_warn (L loc (Warning thing _))+ = notHandledL loc "WARNING and DEPRECATION pragmas" $+ text "Pragma for declaration of" <+> ppr thing+ no_vect (L loc decl)+ = notHandledL loc "Vectorisation pragmas" (ppr decl)+ no_doc (L loc _)+ = notHandledL loc "Haddock documentation" empty++hsSigTvBinders :: HsValBinds Name -> [Name]+-- See Note [Scoped type variables in bindings]+hsSigTvBinders binds+ = concatMap get_scoped_tvs sigs+ where+ get_scoped_tvs :: LSig Name -> [Name]+ -- Both implicit and explicit quantified variables+ -- We need the implicit ones for f :: forall (a::k). blah+ -- here 'k' scopes too+ get_scoped_tvs (L _ (TypeSig _ sig))+ | HsIB { hsib_vars = implicit_vars+ , hsib_body = hs_ty } <- hswc_body sig+ , (explicit_vars, _) <- splitLHsForAllTy hs_ty+ = implicit_vars ++ map hsLTyVarName explicit_vars+ get_scoped_tvs _ = []++ sigs = case binds of+ ValBindsIn _ sigs -> sigs+ ValBindsOut _ sigs -> sigs++{- Notes++Note [Scoped type variables in bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f :: forall a. a -> a+ f x = x::a+Here the 'forall a' brings 'a' into scope over the binding group.+To achieve this we++ a) Gensym a binding for 'a' at the same time as we do one for 'f'+ collecting the relevant binders with hsSigTvBinders++ b) When processing the 'forall', don't gensym++The relevant places are signposted with references to this Note++Note [Binders and occurrences]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we desugar [d| data T = MkT |]+we want to get+ Data "T" [] [Con "MkT" []] []+and *not*+ Data "Foo:T" [] [Con "Foo:MkT" []] []+That is, the new data decl should fit into whatever new module it is+asked to fit in. We do *not* clone, though; no need for this:+ Data "T79" ....++But if we see this:+ data T = MkT+ foo = reifyDecl T++then we must desugar to+ foo = Data "Foo:T" [] [Con "Foo:MkT" []] []++So in repTopDs we bring the binders into scope with mkGenSyms and addBinds.+And we use lookupOcc, rather than lookupBinder+in repTyClD and repC.++Note [Don't quantify implicit type variables in quotes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If you're not careful, it's suprisingly easy to take this quoted declaration:++ [d| idProxy :: forall proxy (b :: k). proxy b -> proxy b+ idProxy x = x+ |]++and have Template Haskell turn it into this:++ idProxy :: forall k proxy (b :: k). proxy b -> proxy b+ idProxy x = x++Notice that we explicitly quantified the variable `k`! This is quite bad, as the+latter declaration requires -XTypeInType, while the former does not. Not to+mention that the latter declaration isn't even what the user wrote in the+first place.++Usually, the culprit behind these bugs is taking implicitly quantified type+variables (often from the hsib_vars field of HsImplicitBinders) and putting+them into a `ForallT` or `ForallC`. Doing so caused #13018 and #13123.+-}++-- represent associated family instances+--+repTyClD :: LTyClDecl Name -> DsM (Maybe (SrcSpan, Core TH.DecQ))++repTyClD (L loc (FamDecl { tcdFam = fam })) = liftM Just $ repFamilyDecl (L loc fam)++repTyClD (L loc (SynDecl { tcdLName = tc, tcdTyVars = tvs, tcdRhs = rhs }))+ = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences]+ ; dec <- addTyClTyVarBinds tvs $ \bndrs ->+ repSynDecl tc1 bndrs rhs+ ; return (Just (loc, dec)) }++repTyClD (L loc (DataDecl { tcdLName = tc, tcdTyVars = tvs, tcdDataDefn = defn }))+ = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences]+ ; dec <- addTyClTyVarBinds tvs $ \bndrs ->+ repDataDefn tc1 bndrs Nothing defn+ ; return (Just (loc, dec)) }++repTyClD (L loc (ClassDecl { tcdCtxt = cxt, tcdLName = cls,+ tcdTyVars = tvs, tcdFDs = fds,+ tcdSigs = sigs, tcdMeths = meth_binds,+ tcdATs = ats, tcdATDefs = atds }))+ = do { cls1 <- lookupLOcc cls -- See note [Binders and occurrences]+ ; dec <- addTyVarBinds tvs $ \bndrs ->+ do { cxt1 <- repLContext cxt+ ; sigs1 <- rep_sigs sigs+ ; binds1 <- rep_binds meth_binds+ ; fds1 <- repLFunDeps fds+ ; ats1 <- repFamilyDecls ats+ ; atds1 <- repAssocTyFamDefaults atds+ ; decls1 <- coreList decQTyConName (ats1 ++ atds1 ++ sigs1 ++ binds1)+ ; repClass cxt1 cls1 bndrs fds1 decls1+ }+ ; return $ Just (loc, dec)+ }++-------------------------+repRoleD :: LRoleAnnotDecl Name -> DsM (SrcSpan, Core TH.DecQ)+repRoleD (L loc (RoleAnnotDecl tycon roles))+ = do { tycon1 <- lookupLOcc tycon+ ; roles1 <- mapM repRole roles+ ; roles2 <- coreList roleTyConName roles1+ ; dec <- repRoleAnnotD tycon1 roles2+ ; return (loc, dec) }++-------------------------+repDataDefn :: Core TH.Name -> Core [TH.TyVarBndr]+ -> Maybe (Core [TH.TypeQ])+ -> HsDataDefn Name+ -> DsM (Core TH.DecQ)+repDataDefn tc bndrs opt_tys+ (HsDataDefn { dd_ND = new_or_data, dd_ctxt = cxt, dd_kindSig = ksig+ , dd_cons = cons, dd_derivs = mb_derivs })+ = do { cxt1 <- repLContext cxt+ ; derivs1 <- repDerivs mb_derivs+ ; case (new_or_data, cons) of+ (NewType, [con]) -> do { con' <- repC con+ ; ksig' <- repMaybeLKind ksig+ ; repNewtype cxt1 tc bndrs opt_tys ksig' con'+ derivs1 }+ (NewType, _) -> failWithDs (text "Multiple constructors for newtype:"+ <+> pprQuotedList+ (getConNames $ unLoc $ head cons))+ (DataType, _) -> do { ksig' <- repMaybeLKind ksig+ ; consL <- mapM repC cons+ ; cons1 <- coreList conQTyConName consL+ ; repData cxt1 tc bndrs opt_tys ksig' cons1+ derivs1 }+ }++repSynDecl :: Core TH.Name -> Core [TH.TyVarBndr]+ -> LHsType Name+ -> DsM (Core TH.DecQ)+repSynDecl tc bndrs ty+ = do { ty1 <- repLTy ty+ ; repTySyn tc bndrs ty1 }++repFamilyDecl :: LFamilyDecl Name -> DsM (SrcSpan, Core TH.DecQ)+repFamilyDecl decl@(L loc (FamilyDecl { fdInfo = info,+ fdLName = tc,+ fdTyVars = tvs,+ fdResultSig = L _ resultSig,+ fdInjectivityAnn = injectivity }))+ = do { tc1 <- lookupLOcc tc -- See note [Binders and occurrences]+ ; let mkHsQTvs :: [LHsTyVarBndr Name] -> LHsQTyVars Name+ mkHsQTvs tvs = HsQTvs { hsq_implicit = [], hsq_explicit = tvs+ , hsq_dependent = emptyNameSet }+ resTyVar = case resultSig of+ TyVarSig bndr -> mkHsQTvs [bndr]+ _ -> mkHsQTvs []+ ; dec <- addTyClTyVarBinds tvs $ \bndrs ->+ addTyClTyVarBinds resTyVar $ \_ ->+ case info of+ ClosedTypeFamily Nothing ->+ notHandled "abstract closed type family" (ppr decl)+ ClosedTypeFamily (Just eqns) ->+ do { eqns1 <- mapM repTyFamEqn eqns+ ; eqns2 <- coreList tySynEqnQTyConName eqns1+ ; result <- repFamilyResultSig resultSig+ ; inj <- repInjectivityAnn injectivity+ ; repClosedFamilyD tc1 bndrs result inj eqns2 }+ OpenTypeFamily ->+ do { result <- repFamilyResultSig resultSig+ ; inj <- repInjectivityAnn injectivity+ ; repOpenFamilyD tc1 bndrs result inj }+ DataFamily ->+ do { kind <- repFamilyResultSigToMaybeKind resultSig+ ; repDataFamilyD tc1 bndrs kind }+ ; return (loc, dec)+ }++-- | Represent result signature of a type family+repFamilyResultSig :: FamilyResultSig Name -> DsM (Core TH.FamilyResultSig)+repFamilyResultSig NoSig = repNoSig+repFamilyResultSig (KindSig ki) = do { ki' <- repLKind ki+ ; repKindSig ki' }+repFamilyResultSig (TyVarSig bndr) = do { bndr' <- repTyVarBndr bndr+ ; repTyVarSig bndr' }++-- | Represent result signature using a Maybe Kind. Used with data families,+-- where the result signature can be either missing or a kind but never a named+-- result variable.+repFamilyResultSigToMaybeKind :: FamilyResultSig Name+ -> DsM (Core (Maybe TH.Kind))+repFamilyResultSigToMaybeKind NoSig =+ do { coreNothing kindTyConName }+repFamilyResultSigToMaybeKind (KindSig ki) =+ do { ki' <- repLKind ki+ ; coreJust kindTyConName ki' }+repFamilyResultSigToMaybeKind _ = panic "repFamilyResultSigToMaybeKind"++-- | Represent injectivity annotation of a type family+repInjectivityAnn :: Maybe (LInjectivityAnn Name)+ -> DsM (Core (Maybe TH.InjectivityAnn))+repInjectivityAnn Nothing =+ do { coreNothing injAnnTyConName }+repInjectivityAnn (Just (L _ (InjectivityAnn lhs rhs))) =+ do { lhs' <- lookupBinder (unLoc lhs)+ ; rhs1 <- mapM (lookupBinder . unLoc) rhs+ ; rhs2 <- coreList nameTyConName rhs1+ ; injAnn <- rep2 injectivityAnnName [unC lhs', unC rhs2]+ ; coreJust injAnnTyConName injAnn }++repFamilyDecls :: [LFamilyDecl Name] -> DsM [Core TH.DecQ]+repFamilyDecls fds = liftM de_loc (mapM repFamilyDecl fds)++repAssocTyFamDefaults :: [LTyFamDefltEqn Name] -> DsM [Core TH.DecQ]+repAssocTyFamDefaults = mapM rep_deflt+ where+ -- very like repTyFamEqn, but different in the details+ rep_deflt :: LTyFamDefltEqn Name -> DsM (Core TH.DecQ)+ rep_deflt (L _ (TyFamEqn { tfe_tycon = tc+ , tfe_pats = bndrs+ , tfe_rhs = rhs }))+ = addTyClTyVarBinds bndrs $ \ _ ->+ do { tc1 <- lookupLOcc tc+ ; tys1 <- repLTys (hsLTyVarBndrsToTypes bndrs)+ ; tys2 <- coreList typeQTyConName tys1+ ; rhs1 <- repLTy rhs+ ; eqn1 <- repTySynEqn tys2 rhs1+ ; repTySynInst tc1 eqn1 }++-------------------------+-- represent fundeps+--+repLFunDeps :: [Located (FunDep (Located Name))] -> DsM (Core [TH.FunDep])+repLFunDeps fds = repList funDepTyConName repLFunDep fds++repLFunDep :: Located (FunDep (Located Name)) -> DsM (Core TH.FunDep)+repLFunDep (L _ (xs, ys))+ = do xs' <- repList nameTyConName (lookupBinder . unLoc) xs+ ys' <- repList nameTyConName (lookupBinder . unLoc) ys+ repFunDep xs' ys'++-- Represent instance declarations+--+repInstD :: LInstDecl Name -> DsM (SrcSpan, Core TH.DecQ)+repInstD (L loc (TyFamInstD { tfid_inst = fi_decl }))+ = do { dec <- repTyFamInstD fi_decl+ ; return (loc, dec) }+repInstD (L loc (DataFamInstD { dfid_inst = fi_decl }))+ = do { dec <- repDataFamInstD fi_decl+ ; return (loc, dec) }+repInstD (L loc (ClsInstD { cid_inst = cls_decl }))+ = do { dec <- repClsInstD cls_decl+ ; return (loc, dec) }++repClsInstD :: ClsInstDecl Name -> DsM (Core TH.DecQ)+repClsInstD (ClsInstDecl { cid_poly_ty = ty, cid_binds = binds+ , cid_sigs = prags, cid_tyfam_insts = ats+ , cid_datafam_insts = adts+ , cid_overlap_mode = overlap+ })+ = addSimpleTyVarBinds tvs $+ -- We must bring the type variables into scope, so their+ -- occurrences don't fail, even though the binders don't+ -- appear in the resulting data structure+ --+ -- But we do NOT bring the binders of 'binds' into scope+ -- because they are properly regarded as occurrences+ -- For example, the method names should be bound to+ -- the selector Ids, not to fresh names (Trac #5410)+ --+ do { cxt1 <- repLContext cxt+ ; inst_ty1 <- repLTy inst_ty+ ; binds1 <- rep_binds binds+ ; prags1 <- rep_sigs prags+ ; ats1 <- mapM (repTyFamInstD . unLoc) ats+ ; adts1 <- mapM (repDataFamInstD . unLoc) adts+ ; decls <- coreList decQTyConName (ats1 ++ adts1 ++ binds1 ++ prags1)+ ; rOver <- repOverlap (fmap unLoc overlap)+ ; repInst rOver cxt1 inst_ty1 decls }+ where+ (tvs, cxt, inst_ty) = splitLHsInstDeclTy ty++repStandaloneDerivD :: LDerivDecl Name -> DsM (SrcSpan, Core TH.DecQ)+repStandaloneDerivD (L loc (DerivDecl { deriv_strategy = strat+ , deriv_type = ty }))+ = do { dec <- addSimpleTyVarBinds tvs $+ do { cxt' <- repLContext cxt+ ; strat' <- repDerivStrategy strat+ ; inst_ty' <- repLTy inst_ty+ ; repDeriv strat' cxt' inst_ty' }+ ; return (loc, dec) }+ where+ (tvs, cxt, inst_ty) = splitLHsInstDeclTy ty++repTyFamInstD :: TyFamInstDecl Name -> DsM (Core TH.DecQ)+repTyFamInstD decl@(TyFamInstDecl { tfid_eqn = eqn })+ = do { let tc_name = tyFamInstDeclLName decl+ ; tc <- lookupLOcc tc_name -- See note [Binders and occurrences]+ ; eqn1 <- repTyFamEqn eqn+ ; repTySynInst tc eqn1 }++repTyFamEqn :: LTyFamInstEqn Name -> DsM (Core TH.TySynEqnQ)+repTyFamEqn (L _ (TyFamEqn { tfe_pats = HsIB { hsib_body = tys+ , hsib_vars = var_names }+ , tfe_rhs = rhs }))+ = do { let hs_tvs = HsQTvs { hsq_implicit = var_names+ , hsq_explicit = []+ , hsq_dependent = emptyNameSet } -- Yuk+ ; addTyClTyVarBinds hs_tvs $ \ _ ->+ do { tys1 <- repLTys tys+ ; tys2 <- coreList typeQTyConName tys1+ ; rhs1 <- repLTy rhs+ ; repTySynEqn tys2 rhs1 } }++repDataFamInstD :: DataFamInstDecl Name -> DsM (Core TH.DecQ)+repDataFamInstD (DataFamInstDecl { dfid_tycon = tc_name+ , dfid_pats = HsIB { hsib_body = tys, hsib_vars = var_names }+ , dfid_defn = defn })+ = do { tc <- lookupLOcc tc_name -- See note [Binders and occurrences]+ ; let hs_tvs = HsQTvs { hsq_implicit = var_names+ , hsq_explicit = []+ , hsq_dependent = emptyNameSet } -- Yuk+ ; addTyClTyVarBinds hs_tvs $ \ bndrs ->+ do { tys1 <- repList typeQTyConName repLTy tys+ ; repDataDefn tc bndrs (Just tys1) defn } }++repForD :: Located (ForeignDecl Name) -> DsM (SrcSpan, Core TH.DecQ)+repForD (L loc (ForeignImport { fd_name = name, fd_sig_ty = typ+ , fd_fi = CImport (L _ cc) (L _ s) mch cis _ }))+ = do MkC name' <- lookupLOcc name+ MkC typ' <- repHsSigType typ+ MkC cc' <- repCCallConv cc+ MkC s' <- repSafety s+ cis' <- conv_cimportspec cis+ MkC str <- coreStringLit (static ++ chStr ++ cis')+ dec <- rep2 forImpDName [cc', s', str, name', typ']+ return (loc, dec)+ where+ conv_cimportspec (CLabel cls) = notHandled "Foreign label" (doubleQuotes (ppr cls))+ conv_cimportspec (CFunction DynamicTarget) = return "dynamic"+ conv_cimportspec (CFunction (StaticTarget _ fs _ True))+ = return (unpackFS fs)+ conv_cimportspec (CFunction (StaticTarget _ _ _ False))+ = panic "conv_cimportspec: values not supported yet"+ conv_cimportspec CWrapper = return "wrapper"+ -- these calling conventions do not support headers and the static keyword+ raw_cconv = cc == PrimCallConv || cc == JavaScriptCallConv+ static = case cis of+ CFunction (StaticTarget _ _ _ _) | not raw_cconv -> "static "+ _ -> ""+ chStr = case mch of+ Just (Header _ h) | not raw_cconv -> unpackFS h ++ " "+ _ -> ""+repForD decl = notHandled "Foreign declaration" (ppr decl)++repCCallConv :: CCallConv -> DsM (Core TH.Callconv)+repCCallConv CCallConv = rep2 cCallName []+repCCallConv StdCallConv = rep2 stdCallName []+repCCallConv CApiConv = rep2 cApiCallName []+repCCallConv PrimCallConv = rep2 primCallName []+repCCallConv JavaScriptCallConv = rep2 javaScriptCallName []++repSafety :: Safety -> DsM (Core TH.Safety)+repSafety PlayRisky = rep2 unsafeName []+repSafety PlayInterruptible = rep2 interruptibleName []+repSafety PlaySafe = rep2 safeName []++repFixD :: LFixitySig Name -> DsM [(SrcSpan, Core TH.DecQ)]+repFixD (L loc (FixitySig names (Fixity _ prec dir)))+ = do { MkC prec' <- coreIntLit prec+ ; let rep_fn = case dir of+ InfixL -> infixLDName+ InfixR -> infixRDName+ InfixN -> infixNDName+ ; let do_one name+ = do { MkC name' <- lookupLOcc name+ ; dec <- rep2 rep_fn [prec', name']+ ; return (loc,dec) }+ ; mapM do_one names }++repRuleD :: LRuleDecl Name -> DsM (SrcSpan, Core TH.DecQ)+repRuleD (L loc (HsRule n act bndrs lhs _ rhs _))+ = do { let bndr_names = concatMap ruleBndrNames bndrs+ ; ss <- mkGenSyms bndr_names+ ; rule1 <- addBinds ss $+ do { bndrs' <- repList ruleBndrQTyConName repRuleBndr bndrs+ ; n' <- coreStringLit $ unpackFS $ snd $ unLoc n+ ; act' <- repPhases act+ ; lhs' <- repLE lhs+ ; rhs' <- repLE rhs+ ; repPragRule n' bndrs' lhs' rhs' act' }+ ; rule2 <- wrapGenSyms ss rule1+ ; return (loc, rule2) }++ruleBndrNames :: LRuleBndr Name -> [Name]+ruleBndrNames (L _ (RuleBndr n)) = [unLoc n]+ruleBndrNames (L _ (RuleBndrSig n sig))+ | HsWC { hswc_body = HsIB { hsib_vars = vars }} <- sig+ = unLoc n : vars++repRuleBndr :: LRuleBndr Name -> DsM (Core TH.RuleBndrQ)+repRuleBndr (L _ (RuleBndr n))+ = do { MkC n' <- lookupLBinder n+ ; rep2 ruleVarName [n'] }+repRuleBndr (L _ (RuleBndrSig n sig))+ = do { MkC n' <- lookupLBinder n+ ; MkC ty' <- repLTy (hsSigWcType sig)+ ; rep2 typedRuleVarName [n', ty'] }++repAnnD :: LAnnDecl Name -> DsM (SrcSpan, Core TH.DecQ)+repAnnD (L loc (HsAnnotation _ ann_prov (L _ exp)))+ = do { target <- repAnnProv ann_prov+ ; exp' <- repE exp+ ; dec <- repPragAnn target exp'+ ; return (loc, dec) }++repAnnProv :: AnnProvenance Name -> DsM (Core TH.AnnTarget)+repAnnProv (ValueAnnProvenance (L _ n))+ = do { MkC n' <- globalVar n -- ANNs are allowed only at top-level+ ; rep2 valueAnnotationName [ n' ] }+repAnnProv (TypeAnnProvenance (L _ n))+ = do { MkC n' <- globalVar n+ ; rep2 typeAnnotationName [ n' ] }+repAnnProv ModuleAnnProvenance+ = rep2 moduleAnnotationName []++-------------------------------------------------------+-- Constructors+-------------------------------------------------------++repC :: LConDecl Name -> DsM (Core TH.ConQ)+repC (L _ (ConDeclH98 { con_name = con+ , con_qvars = Nothing, con_cxt = Nothing+ , con_details = details }))+ = repDataCon con details++repC (L _ (ConDeclH98 { con_name = con+ , con_qvars = mcon_tvs, con_cxt = mcxt+ , con_details = details }))+ = do { let con_tvs = fromMaybe emptyLHsQTvs mcon_tvs+ ctxt = unLoc $ fromMaybe (noLoc []) mcxt+ ; addTyVarBinds con_tvs $ \ ex_bndrs ->+ do { c' <- repDataCon con details+ ; ctxt' <- repContext ctxt+ ; if isEmptyLHsQTvs con_tvs && null ctxt+ then return c'+ else rep2 forallCName ([unC ex_bndrs, unC ctxt', unC c'])+ }+ }++repC (L _ (ConDeclGADT { con_names = cons+ , con_type = res_ty@(HsIB { hsib_vars = imp_tvs })}))+ | (details, res_ty', L _ [] , []) <- gadtDetails+ , [] <- imp_tvs+ -- no implicit or explicit variables, no context = no need for a forall+ = do { let doc = text "In the constructor for " <+> ppr (head cons)+ ; (hs_details, gadt_res_ty) <-+ updateGadtResult failWithDs doc details res_ty'+ ; repGadtDataCons cons hs_details gadt_res_ty }++ | (details,res_ty',ctxt, exp_tvs) <- gadtDetails+ = do { let doc = text "In the constructor for " <+> ppr (head cons)+ con_tvs = HsQTvs { hsq_implicit = imp_tvs+ , hsq_explicit = exp_tvs+ , hsq_dependent = emptyNameSet }+ -- NB: Don't put imp_tvs into the hsq_explicit field above+ -- See Note [Don't quantify implicit type variables in quotes]+ ; addTyVarBinds con_tvs $ \ ex_bndrs -> do+ { (hs_details, gadt_res_ty) <-+ updateGadtResult failWithDs doc details res_ty'+ ; c' <- repGadtDataCons cons hs_details gadt_res_ty+ ; ctxt' <- repContext (unLoc ctxt)+ ; if null exp_tvs && null (unLoc ctxt)+ then return c'+ else rep2 forallCName ([unC ex_bndrs, unC ctxt', unC c']) } }+ where+ gadtDetails = gadtDeclDetails res_ty++repSrcUnpackedness :: SrcUnpackedness -> DsM (Core TH.SourceUnpackednessQ)+repSrcUnpackedness SrcUnpack = rep2 sourceUnpackName []+repSrcUnpackedness SrcNoUnpack = rep2 sourceNoUnpackName []+repSrcUnpackedness NoSrcUnpack = rep2 noSourceUnpackednessName []++repSrcStrictness :: SrcStrictness -> DsM (Core TH.SourceStrictnessQ)+repSrcStrictness SrcLazy = rep2 sourceLazyName []+repSrcStrictness SrcStrict = rep2 sourceStrictName []+repSrcStrictness NoSrcStrict = rep2 noSourceStrictnessName []++repBangTy :: LBangType Name -> DsM (Core (TH.BangTypeQ))+repBangTy ty = do+ MkC u <- repSrcUnpackedness su'+ MkC s <- repSrcStrictness ss'+ MkC b <- rep2 bangName [u, s]+ MkC t <- repLTy ty'+ rep2 bangTypeName [b, t]+ where+ (su', ss', ty') = case ty of+ L _ (HsBangTy (HsSrcBang _ su ss) ty) -> (su, ss, ty)+ _ -> (NoSrcUnpack, NoSrcStrict, ty)++-------------------------------------------------------+-- Deriving clauses+-------------------------------------------------------++repDerivs :: HsDeriving Name -> DsM (Core [TH.DerivClauseQ])+repDerivs (L _ clauses) = repList derivClauseQTyConName repDerivClause clauses++repDerivClause :: LHsDerivingClause Name+ -> DsM (Core TH.DerivClauseQ)+repDerivClause (L _ (HsDerivingClause { deriv_clause_strategy = dcs+ , deriv_clause_tys = L _ dct }))+ = do MkC dcs' <- repDerivStrategy dcs+ MkC dct' <- repList typeQTyConName (rep_deriv_ty . hsSigType) dct+ rep2 derivClauseName [dcs',dct']+ where+ rep_deriv_ty :: LHsType Name -> DsM (Core TH.TypeQ)+ rep_deriv_ty (L _ ty) = repTy ty++-------------------------------------------------------+-- Signatures in a class decl, or a group of bindings+-------------------------------------------------------++rep_sigs :: [LSig Name] -> DsM [Core TH.DecQ]+rep_sigs sigs = do locs_cores <- rep_sigs' sigs+ return $ de_loc $ sort_by_loc locs_cores++rep_sigs' :: [LSig Name] -> DsM [(SrcSpan, Core TH.DecQ)]+ -- We silently ignore ones we don't recognise+rep_sigs' = concatMapM rep_sig++rep_sig :: LSig Name -> DsM [(SrcSpan, Core TH.DecQ)]+rep_sig (L loc (TypeSig nms ty)) = mapM (rep_wc_ty_sig sigDName loc ty) nms+rep_sig (L loc (PatSynSig nms ty)) = mapM (rep_patsyn_ty_sig loc ty) nms+rep_sig (L loc (ClassOpSig is_deflt nms ty))+ | is_deflt = mapM (rep_ty_sig defaultSigDName loc ty) nms+ | otherwise = mapM (rep_ty_sig sigDName loc ty) nms+rep_sig d@(L _ (IdSig {})) = pprPanic "rep_sig IdSig" (ppr d)+rep_sig (L _ (FixSig {})) = return [] -- fixity sigs at top level+rep_sig (L loc (InlineSig nm ispec)) = rep_inline nm ispec loc+rep_sig (L loc (SpecSig nm tys ispec))+ = concatMapM (\t -> rep_specialise nm t ispec loc) tys+rep_sig (L loc (SpecInstSig _ ty)) = rep_specialiseInst ty loc+rep_sig (L _ (MinimalSig {})) = notHandled "MINIMAL pragmas" empty+rep_sig (L _ (SCCFunSig {})) = notHandled "SCC pragmas" empty+rep_sig (L loc (CompleteMatchSig _st cls mty)) = rep_complete_sig cls mty loc+++rep_ty_sig :: Name -> SrcSpan -> LHsSigType Name -> Located Name+ -> DsM (SrcSpan, Core TH.DecQ)+rep_ty_sig mk_sig loc sig_ty nm+ = do { nm1 <- lookupLOcc nm+ ; ty1 <- repHsSigType sig_ty+ ; sig <- repProto mk_sig nm1 ty1+ ; return (loc, sig) }++rep_patsyn_ty_sig :: SrcSpan -> LHsSigType Name -> Located Name+ -> DsM (SrcSpan, Core TH.DecQ)+-- represents a pattern synonym type signature;+-- see Note [Pattern synonym type signatures and Template Haskell] in Convert+rep_patsyn_ty_sig loc sig_ty nm+ = do { nm1 <- lookupLOcc nm+ ; ty1 <- repHsPatSynSigType sig_ty+ ; sig <- repProto patSynSigDName nm1 ty1+ ; return (loc, sig) }++rep_wc_ty_sig :: Name -> SrcSpan -> LHsSigWcType Name -> Located Name+ -> DsM (SrcSpan, Core TH.DecQ)+ -- We must special-case the top-level explicit for-all of a TypeSig+ -- See Note [Scoped type variables in bindings]+rep_wc_ty_sig mk_sig loc sig_ty nm+ | HsIB { hsib_body = hs_ty } <- hswc_body sig_ty+ , (explicit_tvs, ctxt, ty) <- splitLHsSigmaTy hs_ty+ = do { nm1 <- lookupLOcc nm+ ; let rep_in_scope_tv tv = do { name <- lookupBinder (hsLTyVarName tv)+ ; repTyVarBndrWithKind tv name }+ ; th_explicit_tvs <- repList tyVarBndrTyConName rep_in_scope_tv+ explicit_tvs+ -- NB: Don't pass any implicit type variables to repList above+ -- See Note [Don't quantify implicit type variables in quotes]++ ; th_ctxt <- repLContext ctxt+ ; th_ty <- repLTy ty+ ; ty1 <- if null explicit_tvs && null (unLoc ctxt)+ then return th_ty+ else repTForall th_explicit_tvs th_ctxt th_ty+ ; sig <- repProto mk_sig nm1 ty1+ ; return (loc, sig) }++rep_inline :: Located Name+ -> InlinePragma -- Never defaultInlinePragma+ -> SrcSpan+ -> DsM [(SrcSpan, Core TH.DecQ)]+rep_inline nm ispec loc+ = do { nm1 <- lookupLOcc nm+ ; inline <- repInline $ inl_inline ispec+ ; rm <- repRuleMatch $ inl_rule ispec+ ; phases <- repPhases $ inl_act ispec+ ; pragma <- repPragInl nm1 inline rm phases+ ; return [(loc, pragma)]+ }++rep_specialise :: Located Name -> LHsSigType Name -> InlinePragma -> SrcSpan+ -> DsM [(SrcSpan, Core TH.DecQ)]+rep_specialise nm ty ispec loc+ = do { nm1 <- lookupLOcc nm+ ; ty1 <- repHsSigType ty+ ; phases <- repPhases $ inl_act ispec+ ; let inline = inl_inline ispec+ ; pragma <- if isEmptyInlineSpec inline+ then -- SPECIALISE+ repPragSpec nm1 ty1 phases+ else -- SPECIALISE INLINE+ do { inline1 <- repInline inline+ ; repPragSpecInl nm1 ty1 inline1 phases }+ ; return [(loc, pragma)]+ }++rep_specialiseInst :: LHsSigType Name -> SrcSpan -> DsM [(SrcSpan, Core TH.DecQ)]+rep_specialiseInst ty loc+ = do { ty1 <- repHsSigType ty+ ; pragma <- repPragSpecInst ty1+ ; return [(loc, pragma)] }++repInline :: InlineSpec -> DsM (Core TH.Inline)+repInline NoInline = dataCon noInlineDataConName+repInline Inline = dataCon inlineDataConName+repInline Inlinable = dataCon inlinableDataConName+repInline spec = notHandled "repInline" (ppr spec)++repRuleMatch :: RuleMatchInfo -> DsM (Core TH.RuleMatch)+repRuleMatch ConLike = dataCon conLikeDataConName+repRuleMatch FunLike = dataCon funLikeDataConName++repPhases :: Activation -> DsM (Core TH.Phases)+repPhases (ActiveBefore _ i) = do { MkC arg <- coreIntLit i+ ; dataCon' beforePhaseDataConName [arg] }+repPhases (ActiveAfter _ i) = do { MkC arg <- coreIntLit i+ ; dataCon' fromPhaseDataConName [arg] }+repPhases _ = dataCon allPhasesDataConName++rep_complete_sig :: Located [Located Name]+ -> Maybe (Located Name)+ -> SrcSpan+ -> DsM [(SrcSpan, Core TH.DecQ)]+rep_complete_sig (L _ cls) mty loc+ = do { mty' <- rep_maybe_name mty+ ; cls' <- repList nameTyConName lookupLOcc cls+ ; sig <- repPragComplete cls' mty'+ ; return [(loc, sig)] }+ where+ rep_maybe_name Nothing = coreNothing nameTyConName+ rep_maybe_name (Just n) = do+ cn <- lookupLOcc n+ coreJust nameTyConName cn++-------------------------------------------------------+-- Types+-------------------------------------------------------++addSimpleTyVarBinds :: [Name] -- the binders to be added+ -> DsM (Core (TH.Q a)) -- action in the ext env+ -> DsM (Core (TH.Q a))+addSimpleTyVarBinds names thing_inside+ = do { fresh_names <- mkGenSyms names+ ; term <- addBinds fresh_names thing_inside+ ; wrapGenSyms fresh_names term }++addTyVarBinds :: LHsQTyVars Name -- the binders to be added+ -> (Core [TH.TyVarBndr] -> DsM (Core (TH.Q a))) -- action in the ext env+ -> DsM (Core (TH.Q a))+-- gensym a list of type variables and enter them into the meta environment;+-- the computations passed as the second argument is executed in that extended+-- meta environment and gets the *new* names on Core-level as an argument++addTyVarBinds (HsQTvs { hsq_implicit = imp_tvs, hsq_explicit = exp_tvs }) m+ = do { fresh_imp_names <- mkGenSyms imp_tvs+ ; fresh_exp_names <- mkGenSyms (map hsLTyVarName exp_tvs)+ ; let fresh_names = fresh_imp_names ++ fresh_exp_names+ ; term <- addBinds fresh_names $+ do { kbs <- repList tyVarBndrTyConName mk_tv_bndr+ (exp_tvs `zip` fresh_exp_names)+ ; m kbs }+ ; wrapGenSyms fresh_names term }+ where+ mk_tv_bndr (tv, (_,v)) = repTyVarBndrWithKind tv (coreVar v)++addTyClTyVarBinds :: LHsQTyVars Name+ -> (Core [TH.TyVarBndr] -> DsM (Core (TH.Q a)))+ -> DsM (Core (TH.Q a))++-- Used for data/newtype declarations, and family instances,+-- so that the nested type variables work right+-- instance C (T a) where+-- type W (T a) = blah+-- The 'a' in the type instance is the one bound by the instance decl+addTyClTyVarBinds tvs m+ = do { let tv_names = hsAllLTyVarNames tvs+ ; env <- dsGetMetaEnv+ ; freshNames <- mkGenSyms (filterOut (`elemNameEnv` env) tv_names)+ -- Make fresh names for the ones that are not already in scope+ -- This makes things work for family declarations++ ; term <- addBinds freshNames $+ do { kbs <- repList tyVarBndrTyConName mk_tv_bndr (hsQTvExplicit tvs)+ ; m kbs }++ ; wrapGenSyms freshNames term }+ where+ mk_tv_bndr tv = do { v <- lookupBinder (hsLTyVarName tv)+ ; repTyVarBndrWithKind tv v }++-- Produce kinded binder constructors from the Haskell tyvar binders+--+repTyVarBndrWithKind :: LHsTyVarBndr Name+ -> Core TH.Name -> DsM (Core TH.TyVarBndr)+repTyVarBndrWithKind (L _ (UserTyVar _)) nm+ = repPlainTV nm+repTyVarBndrWithKind (L _ (KindedTyVar _ ki)) nm+ = repLKind ki >>= repKindedTV nm++-- | Represent a type variable binder+repTyVarBndr :: LHsTyVarBndr Name -> DsM (Core TH.TyVarBndr)+repTyVarBndr (L _ (UserTyVar (L _ nm)) )= do { nm' <- lookupBinder nm+ ; repPlainTV nm' }+repTyVarBndr (L _ (KindedTyVar (L _ nm) ki)) = do { nm' <- lookupBinder nm+ ; ki' <- repLKind ki+ ; repKindedTV nm' ki' }++-- represent a type context+--+repLContext :: LHsContext Name -> DsM (Core TH.CxtQ)+repLContext (L _ ctxt) = repContext ctxt++repContext :: HsContext Name -> DsM (Core TH.CxtQ)+repContext ctxt = do preds <- repList typeQTyConName repLTy ctxt+ repCtxt preds++repHsSigType :: LHsSigType Name -> DsM (Core TH.TypeQ)+repHsSigType (HsIB { hsib_vars = implicit_tvs+ , hsib_body = body })+ | (explicit_tvs, ctxt, ty) <- splitLHsSigmaTy body+ = addTyVarBinds (HsQTvs { hsq_implicit = implicit_tvs+ , hsq_explicit = explicit_tvs+ , hsq_dependent = emptyNameSet })+ -- NB: Don't pass implicit_tvs to the hsq_explicit field above+ -- See Note [Don't quantify implicit type variables in quotes]+ $ \ th_explicit_tvs ->+ do { th_ctxt <- repLContext ctxt+ ; th_ty <- repLTy ty+ ; if null explicit_tvs && null (unLoc ctxt)+ then return th_ty+ else repTForall th_explicit_tvs th_ctxt th_ty }++repHsPatSynSigType :: LHsSigType Name -> DsM (Core TH.TypeQ)+repHsPatSynSigType (HsIB { hsib_vars = implicit_tvs+ , hsib_body = body })+ = addTyVarBinds (newTvs implicit_tvs univs) $ \th_univs ->+ addTyVarBinds (newTvs [] exis) $ \th_exis ->+ do { th_reqs <- repLContext reqs+ ; th_provs <- repLContext provs+ ; th_ty <- repLTy ty+ ; repTForall th_univs th_reqs =<< (repTForall th_exis th_provs th_ty) }+ where+ newTvs impl_tvs expl_tvs = HsQTvs+ { hsq_implicit = impl_tvs+ , hsq_explicit = expl_tvs+ , hsq_dependent = emptyNameSet }+ -- NB: Don't pass impl_tvs to the hsq_explicit field above+ -- See Note [Don't quantify implicit type variables in quotes]++ (univs, reqs, exis, provs, ty) = splitLHsPatSynTy body++repHsSigWcType :: LHsSigWcType Name -> DsM (Core TH.TypeQ)+repHsSigWcType (HsWC { hswc_body = sig1 })+ = repHsSigType sig1++-- yield the representation of a list of types+repLTys :: [LHsType Name] -> DsM [Core TH.TypeQ]+repLTys tys = mapM repLTy tys++-- represent a type+repLTy :: LHsType Name -> DsM (Core TH.TypeQ)+repLTy (L _ ty) = repTy ty++repForall :: HsType Name -> DsM (Core TH.TypeQ)+-- Arg of repForall is always HsForAllTy or HsQualTy+repForall ty+ | (tvs, ctxt, tau) <- splitLHsSigmaTy (noLoc ty)+ = addTyVarBinds (HsQTvs { hsq_implicit = [], hsq_explicit = tvs+ , hsq_dependent = emptyNameSet }) $ \bndrs ->+ do { ctxt1 <- repLContext ctxt+ ; ty1 <- repLTy tau+ ; repTForall bndrs ctxt1 ty1 }++repTy :: HsType Name -> DsM (Core TH.TypeQ)+repTy ty@(HsForAllTy {}) = repForall ty+repTy ty@(HsQualTy {}) = repForall ty++repTy (HsTyVar _ (L _ n))+ | isTvOcc occ = do tv1 <- lookupOcc n+ repTvar tv1+ | isDataOcc occ = do tc1 <- lookupOcc n+ repPromotedDataCon tc1+ | n == eqTyConName = repTequality+ | otherwise = do tc1 <- lookupOcc n+ repNamedTyCon tc1+ where+ occ = nameOccName n++repTy (HsAppTy f a) = do+ f1 <- repLTy f+ a1 <- repLTy a+ repTapp f1 a1+repTy (HsFunTy f a) = do+ f1 <- repLTy f+ a1 <- repLTy a+ tcon <- repArrowTyCon+ repTapps tcon [f1, a1]+repTy (HsListTy t) = do+ t1 <- repLTy t+ tcon <- repListTyCon+ repTapp tcon t1+repTy (HsPArrTy t) = do+ t1 <- repLTy t+ tcon <- repTy (HsTyVar NotPromoted+ (noLoc (tyConName parrTyCon)))+ repTapp tcon t1+repTy (HsTupleTy HsUnboxedTuple tys) = do+ tys1 <- repLTys tys+ tcon <- repUnboxedTupleTyCon (length tys)+ repTapps tcon tys1+repTy (HsTupleTy _ tys) = do tys1 <- repLTys tys+ tcon <- repTupleTyCon (length tys)+ repTapps tcon tys1+repTy (HsSumTy tys) = do tys1 <- repLTys tys+ tcon <- repUnboxedSumTyCon (length tys)+ repTapps tcon tys1+repTy (HsOpTy ty1 n ty2) = repLTy ((nlHsTyVar (unLoc n) `nlHsAppTy` ty1)+ `nlHsAppTy` ty2)+repTy (HsParTy t) = repLTy t+repTy (HsEqTy t1 t2) = do+ t1' <- repLTy t1+ t2' <- repLTy t2+ eq <- repTequality+ repTapps eq [t1', t2']+repTy (HsKindSig t k) = do+ t1 <- repLTy t+ k1 <- repLKind k+ repTSig t1 k1+repTy (HsSpliceTy splice _) = repSplice splice+repTy (HsExplicitListTy _ _ tys) = do+ tys1 <- repLTys tys+ repTPromotedList tys1+repTy (HsExplicitTupleTy _ tys) = do+ tys1 <- repLTys tys+ tcon <- repPromotedTupleTyCon (length tys)+ repTapps tcon tys1+repTy (HsTyLit lit) = do+ lit' <- repTyLit lit+ repTLit lit'+repTy (HsWildCardTy (AnonWildCard _)) = repTWildCard++repTy ty = notHandled "Exotic form of type" (ppr ty)++repTyLit :: HsTyLit -> DsM (Core TH.TyLitQ)+repTyLit (HsNumTy _ i) = do iExpr <- mkIntegerExpr i+ rep2 numTyLitName [iExpr]+repTyLit (HsStrTy _ s) = do { s' <- mkStringExprFS s+ ; rep2 strTyLitName [s']+ }++-- represent a kind+--+repLKind :: LHsKind Name -> DsM (Core TH.Kind)+repLKind ki+ = do { let (kis, ki') = splitHsFunType ki+ ; kis_rep <- mapM repLKind kis+ ; ki'_rep <- repNonArrowLKind ki'+ ; kcon <- repKArrow+ ; let f k1 k2 = repKApp kcon k1 >>= flip repKApp k2+ ; foldrM f ki'_rep kis_rep+ }++-- | Represent a kind wrapped in a Maybe+repMaybeLKind :: Maybe (LHsKind Name)+ -> DsM (Core (Maybe TH.Kind))+repMaybeLKind Nothing =+ do { coreNothing kindTyConName }+repMaybeLKind (Just ki) =+ do { ki' <- repLKind ki+ ; coreJust kindTyConName ki' }++repNonArrowLKind :: LHsKind Name -> DsM (Core TH.Kind)+repNonArrowLKind (L _ ki) = repNonArrowKind ki++repNonArrowKind :: HsKind Name -> DsM (Core TH.Kind)+repNonArrowKind (HsTyVar _ (L _ name))+ | isLiftedTypeKindTyConName name = repKStar+ | name `hasKey` constraintKindTyConKey = repKConstraint+ | isTvOcc (nameOccName name) = lookupOcc name >>= repKVar+ | otherwise = lookupOcc name >>= repKCon+repNonArrowKind (HsAppTy f a) = do { f' <- repLKind f+ ; a' <- repLKind a+ ; repKApp f' a'+ }+repNonArrowKind (HsListTy k) = do { k' <- repLKind k+ ; kcon <- repKList+ ; repKApp kcon k'+ }+repNonArrowKind (HsTupleTy _ ks) = do { ks' <- mapM repLKind ks+ ; kcon <- repKTuple (length ks)+ ; repKApps kcon ks'+ }+repNonArrowKind k = notHandled "Exotic form of kind" (ppr k)++repRole :: Located (Maybe Role) -> DsM (Core TH.Role)+repRole (L _ (Just Nominal)) = rep2 nominalRName []+repRole (L _ (Just Representational)) = rep2 representationalRName []+repRole (L _ (Just Phantom)) = rep2 phantomRName []+repRole (L _ Nothing) = rep2 inferRName []++-----------------------------------------------------------------------------+-- Splices+-----------------------------------------------------------------------------++repSplice :: HsSplice Name -> DsM (Core a)+-- See Note [How brackets and nested splices are handled] in TcSplice+-- We return a CoreExpr of any old type; the context should know+repSplice (HsTypedSplice _ n _) = rep_splice n+repSplice (HsUntypedSplice _ n _) = rep_splice n+repSplice (HsQuasiQuote n _ _ _) = rep_splice n+repSplice e@(HsSpliced _ _) = pprPanic "repSplice" (ppr e)++rep_splice :: Name -> DsM (Core a)+rep_splice splice_name+ = do { mb_val <- dsLookupMetaEnv splice_name+ ; case mb_val of+ Just (DsSplice e) -> do { e' <- dsExpr e+ ; return (MkC e') }+ _ -> pprPanic "HsSplice" (ppr splice_name) }+ -- Should not happen; statically checked++-----------------------------------------------------------------------------+-- Expressions+-----------------------------------------------------------------------------++repLEs :: [LHsExpr Name] -> DsM (Core [TH.ExpQ])+repLEs es = repList expQTyConName repLE es++-- FIXME: some of these panics should be converted into proper error messages+-- unless we can make sure that constructs, which are plainly not+-- supported in TH already lead to error messages at an earlier stage+repLE :: LHsExpr Name -> DsM (Core TH.ExpQ)+repLE (L loc e) = putSrcSpanDs loc (repE e)++repE :: HsExpr Name -> DsM (Core TH.ExpQ)+repE (HsVar (L _ x)) =+ do { mb_val <- dsLookupMetaEnv x+ ; case mb_val of+ Nothing -> do { str <- globalVar x+ ; repVarOrCon x str }+ Just (DsBound y) -> repVarOrCon x (coreVar y)+ Just (DsSplice e) -> do { e' <- dsExpr e+ ; return (MkC e') } }+repE e@(HsIPVar _) = notHandled "Implicit parameters" (ppr e)+repE e@(HsOverLabel{}) = notHandled "Overloaded labels" (ppr e)++repE e@(HsRecFld f) = case f of+ Unambiguous _ x -> repE (HsVar (noLoc x))+ Ambiguous{} -> notHandled "Ambiguous record selectors" (ppr e)++ -- Remember, we're desugaring renamer output here, so+ -- HsOverlit can definitely occur+repE (HsOverLit l) = do { a <- repOverloadedLiteral l; repLit a }+repE (HsLit l) = do { a <- repLiteral l; repLit a }+repE (HsLam (MG { mg_alts = L _ [m] })) = repLambda m+repE (HsLamCase (MG { mg_alts = L _ ms }))+ = do { ms' <- mapM repMatchTup ms+ ; core_ms <- coreList matchQTyConName ms'+ ; repLamCase core_ms }+repE (HsApp x y) = do {a <- repLE x; b <- repLE y; repApp a b}+repE (HsAppType e t) = do { a <- repLE e+ ; s <- repLTy (hswc_body t)+ ; repAppType a s }++repE (OpApp e1 op _ e2) =+ do { arg1 <- repLE e1;+ arg2 <- repLE e2;+ the_op <- repLE op ;+ repInfixApp arg1 the_op arg2 }+repE (NegApp x _) = do+ a <- repLE x+ negateVar <- lookupOcc negateName >>= repVar+ negateVar `repApp` a+repE (HsPar x) = repLE x+repE (SectionL x y) = do { a <- repLE x; b <- repLE y; repSectionL a b }+repE (SectionR x y) = do { a <- repLE x; b <- repLE y; repSectionR a b }+repE (HsCase e (MG { mg_alts = L _ ms }))+ = do { arg <- repLE e+ ; ms2 <- mapM repMatchTup ms+ ; core_ms2 <- coreList matchQTyConName ms2+ ; repCaseE arg core_ms2 }+repE (HsIf _ x y z) = do+ a <- repLE x+ b <- repLE y+ c <- repLE z+ repCond a b c+repE (HsMultiIf _ alts)+ = do { (binds, alts') <- liftM unzip $ mapM repLGRHS alts+ ; expr' <- repMultiIf (nonEmptyCoreList alts')+ ; wrapGenSyms (concat binds) expr' }+repE (HsLet (L _ bs) e) = do { (ss,ds) <- repBinds bs+ ; e2 <- addBinds ss (repLE e)+ ; z <- repLetE ds e2+ ; wrapGenSyms ss z }++-- FIXME: I haven't got the types here right yet+repE e@(HsDo ctxt (L _ sts) _)+ | case ctxt of { DoExpr -> True; GhciStmtCtxt -> True; _ -> False }+ = do { (ss,zs) <- repLSts sts;+ e' <- repDoE (nonEmptyCoreList zs);+ wrapGenSyms ss e' }++ | ListComp <- ctxt+ = do { (ss,zs) <- repLSts sts;+ e' <- repComp (nonEmptyCoreList zs);+ wrapGenSyms ss e' }++ | otherwise+ = notHandled "mdo, monad comprehension and [: :]" (ppr e)++repE (ExplicitList _ _ es) = do { xs <- repLEs es; repListExp xs }+repE e@(ExplicitPArr _ _) = notHandled "Parallel arrays" (ppr e)+repE e@(ExplicitTuple es boxed)+ | not (all tupArgPresent es) = notHandled "Tuple sections" (ppr e)+ | isBoxed boxed = do { xs <- repLEs [e | L _ (Present e) <- es]; repTup xs }+ | otherwise = do { xs <- repLEs [e | L _ (Present e) <- es]+ ; repUnboxedTup xs }++repE (ExplicitSum alt arity e _)+ = do { e1 <- repLE e+ ; repUnboxedSum e1 alt arity }++repE (RecordCon { rcon_con_name = c, rcon_flds = flds })+ = do { x <- lookupLOcc c;+ fs <- repFields flds;+ repRecCon x fs }+repE (RecordUpd { rupd_expr = e, rupd_flds = flds })+ = do { x <- repLE e;+ fs <- repUpdFields flds;+ repRecUpd x fs }++repE (ExprWithTySig e ty)+ = do { e1 <- repLE e+ ; t1 <- repHsSigWcType ty+ ; repSigExp e1 t1 }++repE (ArithSeq _ _ aseq) =+ case aseq of+ From e -> do { ds1 <- repLE e; repFrom ds1 }+ FromThen e1 e2 -> do+ ds1 <- repLE e1+ ds2 <- repLE e2+ repFromThen ds1 ds2+ FromTo e1 e2 -> do+ ds1 <- repLE e1+ ds2 <- repLE e2+ repFromTo ds1 ds2+ FromThenTo e1 e2 e3 -> do+ ds1 <- repLE e1+ ds2 <- repLE e2+ ds3 <- repLE e3+ repFromThenTo ds1 ds2 ds3++repE (HsSpliceE splice) = repSplice splice+repE (HsStatic _ e) = repLE e >>= rep2 staticEName . (:[]) . unC+repE (HsUnboundVar uv) = do+ occ <- occNameLit (unboundVarOcc uv)+ sname <- repNameS occ+ repUnboundVar sname++repE e@(PArrSeq {}) = notHandled "Parallel arrays" (ppr e)+repE e@(HsCoreAnn {}) = notHandled "Core annotations" (ppr e)+repE e@(HsSCC {}) = notHandled "Cost centres" (ppr e)+repE e@(HsTickPragma {}) = notHandled "Tick Pragma" (ppr e)+repE e@(HsTcBracketOut {}) = notHandled "TH brackets" (ppr e)+repE e = notHandled "Expression form" (ppr e)++-----------------------------------------------------------------------------+-- Building representations of auxillary structures like Match, Clause, Stmt,++repMatchTup :: LMatch Name (LHsExpr Name) -> DsM (Core TH.MatchQ)+repMatchTup (L _ (Match _ [p] _ (GRHSs guards (L _ wheres)))) =+ do { ss1 <- mkGenSyms (collectPatBinders p)+ ; addBinds ss1 $ do {+ ; p1 <- repLP p+ ; (ss2,ds) <- repBinds wheres+ ; addBinds ss2 $ do {+ ; gs <- repGuards guards+ ; match <- repMatch p1 gs ds+ ; wrapGenSyms (ss1++ss2) match }}}+repMatchTup _ = panic "repMatchTup: case alt with more than one arg"++repClauseTup :: LMatch Name (LHsExpr Name) -> DsM (Core TH.ClauseQ)+repClauseTup (L _ (Match _ ps _ (GRHSs guards (L _ wheres)))) =+ do { ss1 <- mkGenSyms (collectPatsBinders ps)+ ; addBinds ss1 $ do {+ ps1 <- repLPs ps+ ; (ss2,ds) <- repBinds wheres+ ; addBinds ss2 $ do {+ gs <- repGuards guards+ ; clause <- repClause ps1 gs ds+ ; wrapGenSyms (ss1++ss2) clause }}}++repGuards :: [LGRHS Name (LHsExpr Name)] -> DsM (Core TH.BodyQ)+repGuards [L _ (GRHS [] e)]+ = do {a <- repLE e; repNormal a }+repGuards other+ = do { zs <- mapM repLGRHS other+ ; let (xs, ys) = unzip zs+ ; gd <- repGuarded (nonEmptyCoreList ys)+ ; wrapGenSyms (concat xs) gd }++repLGRHS :: LGRHS Name (LHsExpr Name) -> DsM ([GenSymBind], (Core (TH.Q (TH.Guard, TH.Exp))))+repLGRHS (L _ (GRHS [L _ (BodyStmt e1 _ _ _)] e2))+ = do { guarded <- repLNormalGE e1 e2+ ; return ([], guarded) }+repLGRHS (L _ (GRHS ss rhs))+ = do { (gs, ss') <- repLSts ss+ ; rhs' <- addBinds gs $ repLE rhs+ ; guarded <- repPatGE (nonEmptyCoreList ss') rhs'+ ; return (gs, guarded) }++repFields :: HsRecordBinds Name -> DsM (Core [TH.Q TH.FieldExp])+repFields (HsRecFields { rec_flds = flds })+ = repList fieldExpQTyConName rep_fld flds+ where+ rep_fld :: LHsRecField Name (LHsExpr Name) -> DsM (Core (TH.Q TH.FieldExp))+ rep_fld (L _ fld) = do { fn <- lookupLOcc (hsRecFieldSel fld)+ ; e <- repLE (hsRecFieldArg fld)+ ; repFieldExp fn e }++repUpdFields :: [LHsRecUpdField Name] -> DsM (Core [TH.Q TH.FieldExp])+repUpdFields = repList fieldExpQTyConName rep_fld+ where+ rep_fld :: LHsRecUpdField Name -> DsM (Core (TH.Q TH.FieldExp))+ rep_fld (L l fld) = case unLoc (hsRecFieldLbl fld) of+ Unambiguous _ sel_name -> do { fn <- lookupLOcc (L l sel_name)+ ; e <- repLE (hsRecFieldArg fld)+ ; repFieldExp fn e }+ _ -> notHandled "Ambiguous record updates" (ppr fld)++++-----------------------------------------------------------------------------+-- Representing Stmt's is tricky, especially if bound variables+-- shadow each other. Consider: [| do { x <- f 1; x <- f x; g x } |]+-- First gensym new names for every variable in any of the patterns.+-- both static (x'1 and x'2), and dynamic ((gensym "x") and (gensym "y"))+-- if variables didn't shaddow, the static gensym wouldn't be necessary+-- and we could reuse the original names (x and x).+--+-- do { x'1 <- gensym "x"+-- ; x'2 <- gensym "x"+-- ; doE [ BindSt (pvar x'1) [| f 1 |]+-- , BindSt (pvar x'2) [| f x |]+-- , NoBindSt [| g x |]+-- ]+-- }++-- The strategy is to translate a whole list of do-bindings by building a+-- bigger environment, and a bigger set of meta bindings+-- (like: x'1 <- gensym "x" ) and then combining these with the translations+-- of the expressions within the Do++-----------------------------------------------------------------------------+-- The helper function repSts computes the translation of each sub expression+-- and a bunch of prefix bindings denoting the dynamic renaming.++repLSts :: [LStmt Name (LHsExpr Name)] -> DsM ([GenSymBind], [Core TH.StmtQ])+repLSts stmts = repSts (map unLoc stmts)++repSts :: [Stmt Name (LHsExpr Name)] -> DsM ([GenSymBind], [Core TH.StmtQ])+repSts (BindStmt p e _ _ _ : ss) =+ do { e2 <- repLE e+ ; ss1 <- mkGenSyms (collectPatBinders p)+ ; addBinds ss1 $ do {+ ; p1 <- repLP p;+ ; (ss2,zs) <- repSts ss+ ; z <- repBindSt p1 e2+ ; return (ss1++ss2, z : zs) }}+repSts (LetStmt (L _ bs) : ss) =+ do { (ss1,ds) <- repBinds bs+ ; z <- repLetSt ds+ ; (ss2,zs) <- addBinds ss1 (repSts ss)+ ; return (ss1++ss2, z : zs) }+repSts (BodyStmt e _ _ _ : ss) =+ do { e2 <- repLE e+ ; z <- repNoBindSt e2+ ; (ss2,zs) <- repSts ss+ ; return (ss2, z : zs) }+repSts (ParStmt stmt_blocks _ _ _ : ss) =+ do { (ss_s, stmt_blocks1) <- mapAndUnzipM rep_stmt_block stmt_blocks+ ; let stmt_blocks2 = nonEmptyCoreList stmt_blocks1+ ss1 = concat ss_s+ ; z <- repParSt stmt_blocks2+ ; (ss2, zs) <- addBinds ss1 (repSts ss)+ ; return (ss1++ss2, z : zs) }+ where+ rep_stmt_block :: ParStmtBlock Name Name -> DsM ([GenSymBind], Core [TH.StmtQ])+ rep_stmt_block (ParStmtBlock stmts _ _) =+ do { (ss1, zs) <- repSts (map unLoc stmts)+ ; zs1 <- coreList stmtQTyConName zs+ ; return (ss1, zs1) }+repSts [LastStmt e _ _]+ = do { e2 <- repLE e+ ; z <- repNoBindSt e2+ ; return ([], [z]) }+repSts [] = return ([],[])+repSts other = notHandled "Exotic statement" (ppr other)+++-----------------------------------------------------------+-- Bindings+-----------------------------------------------------------++repBinds :: HsLocalBinds Name -> DsM ([GenSymBind], Core [TH.DecQ])+repBinds EmptyLocalBinds+ = do { core_list <- coreList decQTyConName []+ ; return ([], core_list) }++repBinds b@(HsIPBinds _) = notHandled "Implicit parameters" (ppr b)++repBinds (HsValBinds decs)+ = do { let { bndrs = hsSigTvBinders decs ++ collectHsValBinders decs }+ -- No need to worry about detailed scopes within+ -- the binding group, because we are talking Names+ -- here, so we can safely treat it as a mutually+ -- recursive group+ -- For hsSigTvBinders see Note [Scoped type variables in bindings]+ ; ss <- mkGenSyms bndrs+ ; prs <- addBinds ss (rep_val_binds decs)+ ; core_list <- coreList decQTyConName+ (de_loc (sort_by_loc prs))+ ; return (ss, core_list) }++rep_val_binds :: HsValBinds Name -> DsM [(SrcSpan, Core TH.DecQ)]+-- Assumes: all the binders of the binding are already in the meta-env+rep_val_binds (ValBindsOut binds sigs)+ = do { core1 <- rep_binds' (unionManyBags (map snd binds))+ ; core2 <- rep_sigs' sigs+ ; return (core1 ++ core2) }+rep_val_binds (ValBindsIn _ _)+ = panic "rep_val_binds: ValBindsIn"++rep_binds :: LHsBinds Name -> DsM [Core TH.DecQ]+rep_binds binds = do { binds_w_locs <- rep_binds' binds+ ; return (de_loc (sort_by_loc binds_w_locs)) }++rep_binds' :: LHsBinds Name -> DsM [(SrcSpan, Core TH.DecQ)]+rep_binds' = mapM rep_bind . bagToList++rep_bind :: LHsBind Name -> DsM (SrcSpan, Core TH.DecQ)+-- Assumes: all the binders of the binding are already in the meta-env++-- Note GHC treats declarations of a variable (not a pattern)+-- e.g. x = g 5 as a Fun MonoBinds. This is indicated by a single match+-- with an empty list of patterns+rep_bind (L loc (FunBind+ { fun_id = fn,+ fun_matches = MG { mg_alts+ = L _ [L _ (Match _ [] _+ (GRHSs guards (L _ wheres)))] } }))+ = do { (ss,wherecore) <- repBinds wheres+ ; guardcore <- addBinds ss (repGuards guards)+ ; fn' <- lookupLBinder fn+ ; p <- repPvar fn'+ ; ans <- repVal p guardcore wherecore+ ; ans' <- wrapGenSyms ss ans+ ; return (loc, ans') }++rep_bind (L loc (FunBind { fun_id = fn+ , fun_matches = MG { mg_alts = L _ ms } }))+ = do { ms1 <- mapM repClauseTup ms+ ; fn' <- lookupLBinder fn+ ; ans <- repFun fn' (nonEmptyCoreList ms1)+ ; return (loc, ans) }++rep_bind (L loc (PatBind { pat_lhs = pat+ , pat_rhs = GRHSs guards (L _ wheres) }))+ = do { patcore <- repLP pat+ ; (ss,wherecore) <- repBinds wheres+ ; guardcore <- addBinds ss (repGuards guards)+ ; ans <- repVal patcore guardcore wherecore+ ; ans' <- wrapGenSyms ss ans+ ; return (loc, ans') }++rep_bind (L _ (VarBind { var_id = v, var_rhs = e}))+ = do { v' <- lookupBinder v+ ; e2 <- repLE e+ ; x <- repNormal e2+ ; patcore <- repPvar v'+ ; empty_decls <- coreList decQTyConName []+ ; ans <- repVal patcore x empty_decls+ ; return (srcLocSpan (getSrcLoc v), ans) }++rep_bind (L _ (AbsBinds {})) = panic "rep_bind: AbsBinds"+rep_bind (L _ (AbsBindsSig {})) = panic "rep_bind: AbsBindsSig"+rep_bind (L loc (PatSynBind (PSB { psb_id = syn+ , psb_fvs = _fvs+ , psb_args = args+ , psb_def = pat+ , psb_dir = dir })))+ = do { syn' <- lookupLBinder syn+ ; dir' <- repPatSynDir dir+ ; ss <- mkGenArgSyms args+ ; patSynD' <- addBinds ss (+ do { args' <- repPatSynArgs args+ ; pat' <- repLP pat+ ; repPatSynD syn' args' dir' pat' })+ ; patSynD'' <- wrapGenArgSyms args ss patSynD'+ ; return (loc, patSynD'') }+ where+ mkGenArgSyms :: HsPatSynDetails (Located Name) -> DsM [GenSymBind]+ -- for Record Pattern Synonyms we want to conflate the selector+ -- and the pattern-only names in order to provide a nicer TH+ -- API. Whereas inside GHC, record pattern synonym selectors and+ -- their pattern-only bound right hand sides have different names,+ -- we want to treat them the same in TH. This is the reason why we+ -- need an adjusted mkGenArgSyms in the `RecordPatSyn` case below.+ mkGenArgSyms (PrefixPatSyn args) = mkGenSyms (map unLoc args)+ mkGenArgSyms (InfixPatSyn arg1 arg2) = mkGenSyms [unLoc arg1, unLoc arg2]+ mkGenArgSyms (RecordPatSyn fields)+ = do { let pats = map (unLoc . recordPatSynPatVar) fields+ sels = map (unLoc . recordPatSynSelectorId) fields+ ; ss <- mkGenSyms sels+ ; return $ replaceNames (zip sels pats) ss }++ replaceNames selsPats genSyms+ = [ (pat, id) | (sel, id) <- genSyms, (sel', pat) <- selsPats+ , sel == sel' ]++ wrapGenArgSyms :: HsPatSynDetails (Located Name)+ -> [GenSymBind] -> Core TH.DecQ -> DsM (Core TH.DecQ)+ wrapGenArgSyms (RecordPatSyn _) _ dec = return dec+ wrapGenArgSyms _ ss dec = wrapGenSyms ss dec++repPatSynD :: Core TH.Name+ -> Core TH.PatSynArgsQ+ -> Core TH.PatSynDirQ+ -> Core TH.PatQ+ -> DsM (Core TH.DecQ)+repPatSynD (MkC syn) (MkC args) (MkC dir) (MkC pat)+ = rep2 patSynDName [syn, args, dir, pat]++repPatSynArgs :: HsPatSynDetails (Located Name) -> DsM (Core TH.PatSynArgsQ)+repPatSynArgs (PrefixPatSyn args)+ = do { args' <- repList nameTyConName lookupLOcc args+ ; repPrefixPatSynArgs args' }+repPatSynArgs (InfixPatSyn arg1 arg2)+ = do { arg1' <- lookupLOcc arg1+ ; arg2' <- lookupLOcc arg2+ ; repInfixPatSynArgs arg1' arg2' }+repPatSynArgs (RecordPatSyn fields)+ = do { sels' <- repList nameTyConName lookupLOcc sels+ ; repRecordPatSynArgs sels' }+ where sels = map recordPatSynSelectorId fields++repPrefixPatSynArgs :: Core [TH.Name] -> DsM (Core TH.PatSynArgsQ)+repPrefixPatSynArgs (MkC nms) = rep2 prefixPatSynName [nms]++repInfixPatSynArgs :: Core TH.Name -> Core TH.Name -> DsM (Core TH.PatSynArgsQ)+repInfixPatSynArgs (MkC nm1) (MkC nm2) = rep2 infixPatSynName [nm1, nm2]++repRecordPatSynArgs :: Core [TH.Name]+ -> DsM (Core TH.PatSynArgsQ)+repRecordPatSynArgs (MkC sels) = rep2 recordPatSynName [sels]++repPatSynDir :: HsPatSynDir Name -> DsM (Core TH.PatSynDirQ)+repPatSynDir Unidirectional = rep2 unidirPatSynName []+repPatSynDir ImplicitBidirectional = rep2 implBidirPatSynName []+repPatSynDir (ExplicitBidirectional (MG { mg_alts = L _ clauses }))+ = do { clauses' <- mapM repClauseTup clauses+ ; repExplBidirPatSynDir (nonEmptyCoreList clauses') }++repExplBidirPatSynDir :: Core [TH.ClauseQ] -> DsM (Core TH.PatSynDirQ)+repExplBidirPatSynDir (MkC cls) = rep2 explBidirPatSynName [cls]+++-----------------------------------------------------------------------------+-- Since everything in a Bind is mutually recursive we need rename all+-- all the variables simultaneously. For example:+-- [| AndMonoBinds (f x = x + g 2) (g x = f 1 + 2) |] would translate to+-- do { f'1 <- gensym "f"+-- ; g'2 <- gensym "g"+-- ; [ do { x'3 <- gensym "x"; fun f'1 [pvar x'3] [| x + g2 |]},+-- do { x'4 <- gensym "x"; fun g'2 [pvar x'4] [| f 1 + 2 |]}+-- ]}+-- This requires collecting the bindings (f'1 <- gensym "f"), and the+-- environment ( f |-> f'1 ) from each binding, and then unioning them+-- together. As we do this we collect GenSymBinds's which represent the renamed+-- variables bound by the Bindings. In order not to lose track of these+-- representations we build a shadow datatype MB with the same structure as+-- MonoBinds, but which has slots for the representations+++-----------------------------------------------------------------------------+-- GHC allows a more general form of lambda abstraction than specified+-- by Haskell 98. In particular it allows guarded lambda's like :+-- (\ x | even x -> 0 | odd x -> 1) at the moment we can't represent this in+-- Haskell Template's Meta.Exp type so we punt if it isn't a simple thing like+-- (\ p1 .. pn -> exp) by causing an error.++repLambda :: LMatch Name (LHsExpr Name) -> DsM (Core TH.ExpQ)+repLambda (L _ (Match _ ps _ (GRHSs [L _ (GRHS [] e)] (L _ EmptyLocalBinds))))+ = do { let bndrs = collectPatsBinders ps ;+ ; ss <- mkGenSyms bndrs+ ; lam <- addBinds ss (+ do { xs <- repLPs ps; body <- repLE e; repLam xs body })+ ; wrapGenSyms ss lam }++repLambda (L _ m) = notHandled "Guarded labmdas" (pprMatch m)+++-----------------------------------------------------------------------------+-- Patterns+-- repP deals with patterns. It assumes that we have already+-- walked over the pattern(s) once to collect the binders, and+-- have extended the environment. So every pattern-bound+-- variable should already appear in the environment.++-- Process a list of patterns+repLPs :: [LPat Name] -> DsM (Core [TH.PatQ])+repLPs ps = repList patQTyConName repLP ps++repLP :: LPat Name -> DsM (Core TH.PatQ)+repLP (L _ p) = repP p++repP :: Pat Name -> DsM (Core TH.PatQ)+repP (WildPat _) = repPwild+repP (LitPat l) = do { l2 <- repLiteral l; repPlit l2 }+repP (VarPat (L _ x)) = do { x' <- lookupBinder x; repPvar x' }+repP (LazyPat p) = do { p1 <- repLP p; repPtilde p1 }+repP (BangPat p) = do { p1 <- repLP p; repPbang p1 }+repP (AsPat x p) = do { x' <- lookupLBinder x; p1 <- repLP p; repPaspat x' p1 }+repP (ParPat p) = repLP p+repP (ListPat ps _ Nothing) = do { qs <- repLPs ps; repPlist qs }+repP (ListPat ps ty1 (Just (_,e))) = do { p <- repP (ListPat ps ty1 Nothing); e' <- repE (syn_expr e); repPview e' p}+repP (TuplePat ps boxed _)+ | isBoxed boxed = do { qs <- repLPs ps; repPtup qs }+ | otherwise = do { qs <- repLPs ps; repPunboxedTup qs }+repP (SumPat p alt arity _) = do { p1 <- repLP p; repPunboxedSum p1 alt arity }+repP (ConPatIn dc details)+ = do { con_str <- lookupLOcc dc+ ; case details of+ PrefixCon ps -> do { qs <- repLPs ps; repPcon con_str qs }+ RecCon rec -> do { fps <- repList fieldPatQTyConName rep_fld (rec_flds rec)+ ; repPrec con_str fps }+ InfixCon p1 p2 -> do { p1' <- repLP p1;+ p2' <- repLP p2;+ repPinfix p1' con_str p2' }+ }+ where+ rep_fld :: LHsRecField Name (LPat Name) -> DsM (Core (TH.Name,TH.PatQ))+ rep_fld (L _ fld) = do { MkC v <- lookupLOcc (hsRecFieldSel fld)+ ; MkC p <- repLP (hsRecFieldArg fld)+ ; rep2 fieldPatName [v,p] }++repP (NPat (L _ l) Nothing _ _) = do { a <- repOverloadedLiteral l; repPlit a }+repP (ViewPat e p _) = do { e' <- repLE e; p' <- repLP p; repPview e' p' }+repP p@(NPat _ (Just _) _ _) = notHandled "Negative overloaded patterns" (ppr p)+repP (SigPatIn p t) = do { p' <- repLP p+ ; t' <- repLTy (hsSigWcType t)+ ; repPsig p' t' }+repP (SplicePat splice) = repSplice splice++repP other = notHandled "Exotic pattern" (ppr other)++----------------------------------------------------------+-- Declaration ordering helpers++sort_by_loc :: [(SrcSpan, a)] -> [(SrcSpan, a)]+sort_by_loc xs = sortBy comp xs+ where comp x y = compare (fst x) (fst y)++de_loc :: [(a, b)] -> [b]+de_loc = map snd++----------------------------------------------------------+-- The meta-environment++-- A name/identifier association for fresh names of locally bound entities+type GenSymBind = (Name, Id) -- Gensym the string and bind it to the Id+ -- I.e. (x, x_id) means+ -- let x_id = gensym "x" in ...++-- Generate a fresh name for a locally bound entity++mkGenSyms :: [Name] -> DsM [GenSymBind]+-- We can use the existing name. For example:+-- [| \x_77 -> x_77 + x_77 |]+-- desugars to+-- do { x_77 <- genSym "x"; .... }+-- We use the same x_77 in the desugared program, but with the type Bndr+-- instead of Int+--+-- We do make it an Internal name, though (hence localiseName)+--+-- Nevertheless, it's monadic because we have to generate nameTy+mkGenSyms ns = do { var_ty <- lookupType nameTyConName+ ; return [(nm, mkLocalId (localiseName nm) var_ty) | nm <- ns] }+++addBinds :: [GenSymBind] -> DsM a -> DsM a+-- Add a list of fresh names for locally bound entities to the+-- meta environment (which is part of the state carried around+-- by the desugarer monad)+addBinds bs m = dsExtendMetaEnv (mkNameEnv [(n,DsBound id) | (n,id) <- bs]) m++-- Look up a locally bound name+--+lookupLBinder :: Located Name -> DsM (Core TH.Name)+lookupLBinder (L _ n) = lookupBinder n++lookupBinder :: Name -> DsM (Core TH.Name)+lookupBinder = lookupOcc+ -- Binders are brought into scope before the pattern or what-not is+ -- desugared. Moreover, in instance declaration the binder of a method+ -- will be the selector Id and hence a global; so we need the+ -- globalVar case of lookupOcc++-- Look up a name that is either locally bound or a global name+--+-- * If it is a global name, generate the "original name" representation (ie,+-- the <module>:<name> form) for the associated entity+--+lookupLOcc :: Located Name -> DsM (Core TH.Name)+-- Lookup an occurrence; it can't be a splice.+-- Use the in-scope bindings if they exist+lookupLOcc (L _ n) = lookupOcc n++lookupOcc :: Name -> DsM (Core TH.Name)+lookupOcc n+ = do { mb_val <- dsLookupMetaEnv n ;+ case mb_val of+ Nothing -> globalVar n+ Just (DsBound x) -> return (coreVar x)+ Just (DsSplice _) -> pprPanic "repE:lookupOcc" (ppr n)+ }++globalVar :: Name -> DsM (Core TH.Name)+-- Not bound by the meta-env+-- Could be top-level; or could be local+-- f x = $(g [| x |])+-- Here the x will be local+globalVar name+ | isExternalName name+ = do { MkC mod <- coreStringLit name_mod+ ; MkC pkg <- coreStringLit name_pkg+ ; MkC occ <- nameLit name+ ; rep2 mk_varg [pkg,mod,occ] }+ | otherwise+ = do { MkC occ <- nameLit name+ ; MkC uni <- coreIntLit (getKey (getUnique name))+ ; rep2 mkNameLName [occ,uni] }+ where+ mod = ASSERT( isExternalName name) nameModule name+ name_mod = moduleNameString (moduleName mod)+ name_pkg = unitIdString (moduleUnitId mod)+ name_occ = nameOccName name+ mk_varg | OccName.isDataOcc name_occ = mkNameG_dName+ | OccName.isVarOcc name_occ = mkNameG_vName+ | OccName.isTcOcc name_occ = mkNameG_tcName+ | otherwise = pprPanic "DsMeta.globalVar" (ppr name)++lookupType :: Name -- Name of type constructor (e.g. TH.ExpQ)+ -> DsM Type -- The type+lookupType tc_name = do { tc <- dsLookupTyCon tc_name ;+ return (mkTyConApp tc []) }++wrapGenSyms :: [GenSymBind]+ -> Core (TH.Q a) -> DsM (Core (TH.Q a))+-- wrapGenSyms [(nm1,id1), (nm2,id2)] y+-- --> bindQ (gensym nm1) (\ id1 ->+-- bindQ (gensym nm2 (\ id2 ->+-- y))++wrapGenSyms binds body@(MkC b)+ = do { var_ty <- lookupType nameTyConName+ ; go var_ty binds }+ where+ [elt_ty] = tcTyConAppArgs (exprType b)+ -- b :: Q a, so we can get the type 'a' by looking at the+ -- argument type. NB: this relies on Q being a data/newtype,+ -- not a type synonym++ go _ [] = return body+ go var_ty ((name,id) : binds)+ = do { MkC body' <- go var_ty binds+ ; lit_str <- nameLit name+ ; gensym_app <- repGensym lit_str+ ; repBindQ var_ty elt_ty+ gensym_app (MkC (Lam id body')) }++nameLit :: Name -> DsM (Core String)+nameLit n = coreStringLit (occNameString (nameOccName n))++occNameLit :: OccName -> DsM (Core String)+occNameLit name = coreStringLit (occNameString name)+++-- %*********************************************************************+-- %* *+-- Constructing code+-- %* *+-- %*********************************************************************++-----------------------------------------------------------------------------+-- PHANTOM TYPES for consistency. In order to make sure we do this correct+-- we invent a new datatype which uses phantom types.++newtype Core a = MkC CoreExpr+unC :: Core a -> CoreExpr+unC (MkC x) = x++rep2 :: Name -> [ CoreExpr ] -> DsM (Core a)+rep2 n xs = do { id <- dsLookupGlobalId n+ ; return (MkC (foldl App (Var id) xs)) }++dataCon' :: Name -> [CoreExpr] -> DsM (Core a)+dataCon' n args = do { id <- dsLookupDataCon n+ ; return $ MkC $ mkCoreConApps id args }++dataCon :: Name -> DsM (Core a)+dataCon n = dataCon' n []+++-- %*********************************************************************+-- %* *+-- The 'smart constructors'+-- %* *+-- %*********************************************************************++--------------- Patterns -----------------+repPlit :: Core TH.Lit -> DsM (Core TH.PatQ)+repPlit (MkC l) = rep2 litPName [l]++repPvar :: Core TH.Name -> DsM (Core TH.PatQ)+repPvar (MkC s) = rep2 varPName [s]++repPtup :: Core [TH.PatQ] -> DsM (Core TH.PatQ)+repPtup (MkC ps) = rep2 tupPName [ps]++repPunboxedTup :: Core [TH.PatQ] -> DsM (Core TH.PatQ)+repPunboxedTup (MkC ps) = rep2 unboxedTupPName [ps]++repPunboxedSum :: Core TH.PatQ -> TH.SumAlt -> TH.SumArity -> DsM (Core TH.PatQ)+-- Note: not Core TH.SumAlt or Core TH.SumArity; it's easier to be direct here+repPunboxedSum (MkC p) alt arity+ = do { dflags <- getDynFlags+ ; rep2 unboxedSumPName [ p+ , mkIntExprInt dflags alt+ , mkIntExprInt dflags arity ] }++repPcon :: Core TH.Name -> Core [TH.PatQ] -> DsM (Core TH.PatQ)+repPcon (MkC s) (MkC ps) = rep2 conPName [s, ps]++repPrec :: Core TH.Name -> Core [(TH.Name,TH.PatQ)] -> DsM (Core TH.PatQ)+repPrec (MkC c) (MkC rps) = rep2 recPName [c,rps]++repPinfix :: Core TH.PatQ -> Core TH.Name -> Core TH.PatQ -> DsM (Core TH.PatQ)+repPinfix (MkC p1) (MkC n) (MkC p2) = rep2 infixPName [p1, n, p2]++repPtilde :: Core TH.PatQ -> DsM (Core TH.PatQ)+repPtilde (MkC p) = rep2 tildePName [p]++repPbang :: Core TH.PatQ -> DsM (Core TH.PatQ)+repPbang (MkC p) = rep2 bangPName [p]++repPaspat :: Core TH.Name -> Core TH.PatQ -> DsM (Core TH.PatQ)+repPaspat (MkC s) (MkC p) = rep2 asPName [s, p]++repPwild :: DsM (Core TH.PatQ)+repPwild = rep2 wildPName []++repPlist :: Core [TH.PatQ] -> DsM (Core TH.PatQ)+repPlist (MkC ps) = rep2 listPName [ps]++repPview :: Core TH.ExpQ -> Core TH.PatQ -> DsM (Core TH.PatQ)+repPview (MkC e) (MkC p) = rep2 viewPName [e,p]++repPsig :: Core TH.PatQ -> Core TH.TypeQ -> DsM (Core TH.PatQ)+repPsig (MkC p) (MkC t) = rep2 sigPName [p, t]++--------------- Expressions -----------------+repVarOrCon :: Name -> Core TH.Name -> DsM (Core TH.ExpQ)+repVarOrCon vc str | isDataOcc (nameOccName vc) = repCon str+ | otherwise = repVar str++repVar :: Core TH.Name -> DsM (Core TH.ExpQ)+repVar (MkC s) = rep2 varEName [s]++repCon :: Core TH.Name -> DsM (Core TH.ExpQ)+repCon (MkC s) = rep2 conEName [s]++repLit :: Core TH.Lit -> DsM (Core TH.ExpQ)+repLit (MkC c) = rep2 litEName [c]++repApp :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repApp (MkC x) (MkC y) = rep2 appEName [x,y]++repAppType :: Core TH.ExpQ -> Core TH.TypeQ -> DsM (Core TH.ExpQ)+repAppType (MkC x) (MkC y) = rep2 appTypeEName [x,y]++repLam :: Core [TH.PatQ] -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repLam (MkC ps) (MkC e) = rep2 lamEName [ps, e]++repLamCase :: Core [TH.MatchQ] -> DsM (Core TH.ExpQ)+repLamCase (MkC ms) = rep2 lamCaseEName [ms]++repTup :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)+repTup (MkC es) = rep2 tupEName [es]++repUnboxedTup :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)+repUnboxedTup (MkC es) = rep2 unboxedTupEName [es]++repUnboxedSum :: Core TH.ExpQ -> TH.SumAlt -> TH.SumArity -> DsM (Core TH.ExpQ)+-- Note: not Core TH.SumAlt or Core TH.SumArity; it's easier to be direct here+repUnboxedSum (MkC e) alt arity+ = do { dflags <- getDynFlags+ ; rep2 unboxedSumEName [ e+ , mkIntExprInt dflags alt+ , mkIntExprInt dflags arity ] }++repCond :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repCond (MkC x) (MkC y) (MkC z) = rep2 condEName [x,y,z]++repMultiIf :: Core [TH.Q (TH.Guard, TH.Exp)] -> DsM (Core TH.ExpQ)+repMultiIf (MkC alts) = rep2 multiIfEName [alts]++repLetE :: Core [TH.DecQ] -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repLetE (MkC ds) (MkC e) = rep2 letEName [ds, e]++repCaseE :: Core TH.ExpQ -> Core [TH.MatchQ] -> DsM( Core TH.ExpQ)+repCaseE (MkC e) (MkC ms) = rep2 caseEName [e, ms]++repDoE :: Core [TH.StmtQ] -> DsM (Core TH.ExpQ)+repDoE (MkC ss) = rep2 doEName [ss]++repComp :: Core [TH.StmtQ] -> DsM (Core TH.ExpQ)+repComp (MkC ss) = rep2 compEName [ss]++repListExp :: Core [TH.ExpQ] -> DsM (Core TH.ExpQ)+repListExp (MkC es) = rep2 listEName [es]++repSigExp :: Core TH.ExpQ -> Core TH.TypeQ -> DsM (Core TH.ExpQ)+repSigExp (MkC e) (MkC t) = rep2 sigEName [e,t]++repRecCon :: Core TH.Name -> Core [TH.Q TH.FieldExp]-> DsM (Core TH.ExpQ)+repRecCon (MkC c) (MkC fs) = rep2 recConEName [c,fs]++repRecUpd :: Core TH.ExpQ -> Core [TH.Q TH.FieldExp] -> DsM (Core TH.ExpQ)+repRecUpd (MkC e) (MkC fs) = rep2 recUpdEName [e,fs]++repFieldExp :: Core TH.Name -> Core TH.ExpQ -> DsM (Core (TH.Q TH.FieldExp))+repFieldExp (MkC n) (MkC x) = rep2 fieldExpName [n,x]++repInfixApp :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repInfixApp (MkC x) (MkC y) (MkC z) = rep2 infixAppName [x,y,z]++repSectionL :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repSectionL (MkC x) (MkC y) = rep2 sectionLName [x,y]++repSectionR :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repSectionR (MkC x) (MkC y) = rep2 sectionRName [x,y]++------------ Right hand sides (guarded expressions) ----+repGuarded :: Core [TH.Q (TH.Guard, TH.Exp)] -> DsM (Core TH.BodyQ)+repGuarded (MkC pairs) = rep2 guardedBName [pairs]++repNormal :: Core TH.ExpQ -> DsM (Core TH.BodyQ)+repNormal (MkC e) = rep2 normalBName [e]++------------ Guards ----+repLNormalGE :: LHsExpr Name -> LHsExpr Name -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))+repLNormalGE g e = do g' <- repLE g+ e' <- repLE e+ repNormalGE g' e'++repNormalGE :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))+repNormalGE (MkC g) (MkC e) = rep2 normalGEName [g, e]++repPatGE :: Core [TH.StmtQ] -> Core TH.ExpQ -> DsM (Core (TH.Q (TH.Guard, TH.Exp)))+repPatGE (MkC ss) (MkC e) = rep2 patGEName [ss, e]++------------- Stmts -------------------+repBindSt :: Core TH.PatQ -> Core TH.ExpQ -> DsM (Core TH.StmtQ)+repBindSt (MkC p) (MkC e) = rep2 bindSName [p,e]++repLetSt :: Core [TH.DecQ] -> DsM (Core TH.StmtQ)+repLetSt (MkC ds) = rep2 letSName [ds]++repNoBindSt :: Core TH.ExpQ -> DsM (Core TH.StmtQ)+repNoBindSt (MkC e) = rep2 noBindSName [e]++repParSt :: Core [[TH.StmtQ]] -> DsM (Core TH.StmtQ)+repParSt (MkC sss) = rep2 parSName [sss]++-------------- Range (Arithmetic sequences) -----------+repFrom :: Core TH.ExpQ -> DsM (Core TH.ExpQ)+repFrom (MkC x) = rep2 fromEName [x]++repFromThen :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repFromThen (MkC x) (MkC y) = rep2 fromThenEName [x,y]++repFromTo :: Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repFromTo (MkC x) (MkC y) = rep2 fromToEName [x,y]++repFromThenTo :: Core TH.ExpQ -> Core TH.ExpQ -> Core TH.ExpQ -> DsM (Core TH.ExpQ)+repFromThenTo (MkC x) (MkC y) (MkC z) = rep2 fromThenToEName [x,y,z]++------------ Match and Clause Tuples -----------+repMatch :: Core TH.PatQ -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.MatchQ)+repMatch (MkC p) (MkC bod) (MkC ds) = rep2 matchName [p, bod, ds]++repClause :: Core [TH.PatQ] -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.ClauseQ)+repClause (MkC ps) (MkC bod) (MkC ds) = rep2 clauseName [ps, bod, ds]++-------------- Dec -----------------------------+repVal :: Core TH.PatQ -> Core TH.BodyQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ)+repVal (MkC p) (MkC b) (MkC ds) = rep2 valDName [p, b, ds]++repFun :: Core TH.Name -> Core [TH.ClauseQ] -> DsM (Core TH.DecQ)+repFun (MkC nm) (MkC b) = rep2 funDName [nm, b]++repData :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]+ -> Maybe (Core [TH.TypeQ]) -> Core (Maybe TH.Kind)+ -> Core [TH.ConQ] -> Core [TH.DerivClauseQ] -> DsM (Core TH.DecQ)+repData (MkC cxt) (MkC nm) (MkC tvs) Nothing (MkC ksig) (MkC cons) (MkC derivs)+ = rep2 dataDName [cxt, nm, tvs, ksig, cons, derivs]+repData (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC ksig) (MkC cons)+ (MkC derivs)+ = rep2 dataInstDName [cxt, nm, tys, ksig, cons, derivs]++repNewtype :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]+ -> Maybe (Core [TH.TypeQ]) -> Core (Maybe TH.Kind)+ -> Core TH.ConQ -> Core [TH.DerivClauseQ] -> DsM (Core TH.DecQ)+repNewtype (MkC cxt) (MkC nm) (MkC tvs) Nothing (MkC ksig) (MkC con)+ (MkC derivs)+ = rep2 newtypeDName [cxt, nm, tvs, ksig, con, derivs]+repNewtype (MkC cxt) (MkC nm) (MkC _) (Just (MkC tys)) (MkC ksig) (MkC con)+ (MkC derivs)+ = rep2 newtypeInstDName [cxt, nm, tys, ksig, con, derivs]++repTySyn :: Core TH.Name -> Core [TH.TyVarBndr]+ -> Core TH.TypeQ -> DsM (Core TH.DecQ)+repTySyn (MkC nm) (MkC tvs) (MkC rhs)+ = rep2 tySynDName [nm, tvs, rhs]++repInst :: Core (Maybe TH.Overlap) ->+ Core TH.CxtQ -> Core TH.TypeQ -> Core [TH.DecQ] -> DsM (Core TH.DecQ)+repInst (MkC o) (MkC cxt) (MkC ty) (MkC ds) = rep2 instanceWithOverlapDName+ [o, cxt, ty, ds]++repDerivStrategy :: Maybe (Located DerivStrategy)+ -> DsM (Core (Maybe TH.DerivStrategy))+repDerivStrategy mds =+ case mds of+ Nothing -> nothing+ Just (L _ ds) ->+ case ds of+ StockStrategy -> just =<< dataCon stockStrategyDataConName+ AnyclassStrategy -> just =<< dataCon anyclassStrategyDataConName+ NewtypeStrategy -> just =<< dataCon newtypeStrategyDataConName+ where+ nothing = coreNothing derivStrategyTyConName+ just = coreJust derivStrategyTyConName++repOverlap :: Maybe OverlapMode -> DsM (Core (Maybe TH.Overlap))+repOverlap mb =+ case mb of+ Nothing -> nothing+ Just o ->+ case o of+ NoOverlap _ -> nothing+ Overlappable _ -> just =<< dataCon overlappableDataConName+ Overlapping _ -> just =<< dataCon overlappingDataConName+ Overlaps _ -> just =<< dataCon overlapsDataConName+ Incoherent _ -> just =<< dataCon incoherentDataConName+ where+ nothing = coreNothing overlapTyConName+ just = coreJust overlapTyConName+++repClass :: Core TH.CxtQ -> Core TH.Name -> Core [TH.TyVarBndr]+ -> Core [TH.FunDep] -> Core [TH.DecQ]+ -> DsM (Core TH.DecQ)+repClass (MkC cxt) (MkC cls) (MkC tvs) (MkC fds) (MkC ds)+ = rep2 classDName [cxt, cls, tvs, fds, ds]++repDeriv :: Core (Maybe TH.DerivStrategy)+ -> Core TH.CxtQ -> Core TH.TypeQ+ -> DsM (Core TH.DecQ)+repDeriv (MkC ds) (MkC cxt) (MkC ty)+ = rep2 standaloneDerivWithStrategyDName [ds, cxt, ty]++repPragInl :: Core TH.Name -> Core TH.Inline -> Core TH.RuleMatch+ -> Core TH.Phases -> DsM (Core TH.DecQ)+repPragInl (MkC nm) (MkC inline) (MkC rm) (MkC phases)+ = rep2 pragInlDName [nm, inline, rm, phases]++repPragSpec :: Core TH.Name -> Core TH.TypeQ -> Core TH.Phases+ -> DsM (Core TH.DecQ)+repPragSpec (MkC nm) (MkC ty) (MkC phases)+ = rep2 pragSpecDName [nm, ty, phases]++repPragSpecInl :: Core TH.Name -> Core TH.TypeQ -> Core TH.Inline+ -> Core TH.Phases -> DsM (Core TH.DecQ)+repPragSpecInl (MkC nm) (MkC ty) (MkC inline) (MkC phases)+ = rep2 pragSpecInlDName [nm, ty, inline, phases]++repPragSpecInst :: Core TH.TypeQ -> DsM (Core TH.DecQ)+repPragSpecInst (MkC ty) = rep2 pragSpecInstDName [ty]++repPragComplete :: Core [TH.Name] -> Core (Maybe TH.Name) -> DsM (Core TH.DecQ)+repPragComplete (MkC cls) (MkC mty) = rep2 pragCompleteDName [cls, mty]++repPragRule :: Core String -> Core [TH.RuleBndrQ] -> Core TH.ExpQ+ -> Core TH.ExpQ -> Core TH.Phases -> DsM (Core TH.DecQ)+repPragRule (MkC nm) (MkC bndrs) (MkC lhs) (MkC rhs) (MkC phases)+ = rep2 pragRuleDName [nm, bndrs, lhs, rhs, phases]++repPragAnn :: Core TH.AnnTarget -> Core TH.ExpQ -> DsM (Core TH.DecQ)+repPragAnn (MkC targ) (MkC e) = rep2 pragAnnDName [targ, e]++repTySynInst :: Core TH.Name -> Core TH.TySynEqnQ -> DsM (Core TH.DecQ)+repTySynInst (MkC nm) (MkC eqn)+ = rep2 tySynInstDName [nm, eqn]++repDataFamilyD :: Core TH.Name -> Core [TH.TyVarBndr]+ -> Core (Maybe TH.Kind) -> DsM (Core TH.DecQ)+repDataFamilyD (MkC nm) (MkC tvs) (MkC kind)+ = rep2 dataFamilyDName [nm, tvs, kind]++repOpenFamilyD :: Core TH.Name+ -> Core [TH.TyVarBndr]+ -> Core TH.FamilyResultSig+ -> Core (Maybe TH.InjectivityAnn)+ -> DsM (Core TH.DecQ)+repOpenFamilyD (MkC nm) (MkC tvs) (MkC result) (MkC inj)+ = rep2 openTypeFamilyDName [nm, tvs, result, inj]++repClosedFamilyD :: Core TH.Name+ -> Core [TH.TyVarBndr]+ -> Core TH.FamilyResultSig+ -> Core (Maybe TH.InjectivityAnn)+ -> Core [TH.TySynEqnQ]+ -> DsM (Core TH.DecQ)+repClosedFamilyD (MkC nm) (MkC tvs) (MkC res) (MkC inj) (MkC eqns)+ = rep2 closedTypeFamilyDName [nm, tvs, res, inj, eqns]++repTySynEqn :: Core [TH.TypeQ] -> Core TH.TypeQ -> DsM (Core TH.TySynEqnQ)+repTySynEqn (MkC lhs) (MkC rhs)+ = rep2 tySynEqnName [lhs, rhs]++repRoleAnnotD :: Core TH.Name -> Core [TH.Role] -> DsM (Core TH.DecQ)+repRoleAnnotD (MkC n) (MkC roles) = rep2 roleAnnotDName [n, roles]++repFunDep :: Core [TH.Name] -> Core [TH.Name] -> DsM (Core TH.FunDep)+repFunDep (MkC xs) (MkC ys) = rep2 funDepName [xs, ys]++repProto :: Name -> Core TH.Name -> Core TH.TypeQ -> DsM (Core TH.DecQ)+repProto mk_sig (MkC s) (MkC ty) = rep2 mk_sig [s, ty]++repCtxt :: Core [TH.PredQ] -> DsM (Core TH.CxtQ)+repCtxt (MkC tys) = rep2 cxtName [tys]++repDataCon :: Located Name+ -> HsConDeclDetails Name+ -> DsM (Core TH.ConQ)+repDataCon con details+ = do con' <- lookupLOcc con -- See Note [Binders and occurrences]+ repConstr details Nothing [con']++repGadtDataCons :: [Located Name]+ -> HsConDeclDetails Name+ -> LHsType Name+ -> DsM (Core TH.ConQ)+repGadtDataCons cons details res_ty+ = do cons' <- mapM lookupLOcc cons -- See Note [Binders and occurrences]+ repConstr details (Just res_ty) cons'++-- Invariant:+-- * for plain H98 data constructors second argument is Nothing and third+-- argument is a singleton list+-- * for GADTs data constructors second argument is (Just return_type) and+-- third argument is a non-empty list+repConstr :: HsConDeclDetails Name+ -> Maybe (LHsType Name)+ -> [Core TH.Name]+ -> DsM (Core TH.ConQ)+repConstr (PrefixCon ps) Nothing [con]+ = do arg_tys <- repList bangTypeQTyConName repBangTy ps+ rep2 normalCName [unC con, unC arg_tys]++repConstr (PrefixCon ps) (Just (L _ res_ty)) cons+ = do arg_tys <- repList bangTypeQTyConName repBangTy ps+ res_ty' <- repTy res_ty+ rep2 gadtCName [ unC (nonEmptyCoreList cons), unC arg_tys, unC res_ty']++repConstr (RecCon (L _ ips)) resTy cons+ = do args <- concatMapM rep_ip ips+ arg_vtys <- coreList varBangTypeQTyConName args+ case resTy of+ Nothing -> rep2 recCName [unC (head cons), unC arg_vtys]+ Just (L _ res_ty) -> do+ res_ty' <- repTy res_ty+ rep2 recGadtCName [unC (nonEmptyCoreList cons), unC arg_vtys,+ unC res_ty']++ where+ rep_ip (L _ ip) = mapM (rep_one_ip (cd_fld_type ip)) (cd_fld_names ip)++ rep_one_ip :: LBangType Name -> LFieldOcc Name -> DsM (Core a)+ rep_one_ip t n = do { MkC v <- lookupOcc (selectorFieldOcc $ unLoc n)+ ; MkC ty <- repBangTy t+ ; rep2 varBangTypeName [v,ty] }++repConstr (InfixCon st1 st2) Nothing [con]+ = do arg1 <- repBangTy st1+ arg2 <- repBangTy st2+ rep2 infixCName [unC arg1, unC con, unC arg2]++repConstr (InfixCon {}) (Just _) _ =+ panic "repConstr: infix GADT constructor should be in a PrefixCon"+repConstr _ _ _ =+ panic "repConstr: invariant violated"++------------ Types -------------------++repTForall :: Core [TH.TyVarBndr] -> Core TH.CxtQ -> Core TH.TypeQ+ -> DsM (Core TH.TypeQ)+repTForall (MkC tvars) (MkC ctxt) (MkC ty)+ = rep2 forallTName [tvars, ctxt, ty]++repTvar :: Core TH.Name -> DsM (Core TH.TypeQ)+repTvar (MkC s) = rep2 varTName [s]++repTapp :: Core TH.TypeQ -> Core TH.TypeQ -> DsM (Core TH.TypeQ)+repTapp (MkC t1) (MkC t2) = rep2 appTName [t1, t2]++repTapps :: Core TH.TypeQ -> [Core TH.TypeQ] -> DsM (Core TH.TypeQ)+repTapps f [] = return f+repTapps f (t:ts) = do { f1 <- repTapp f t; repTapps f1 ts }++repTSig :: Core TH.TypeQ -> Core TH.Kind -> DsM (Core TH.TypeQ)+repTSig (MkC ty) (MkC ki) = rep2 sigTName [ty, ki]++repTequality :: DsM (Core TH.TypeQ)+repTequality = rep2 equalityTName []++repTPromotedList :: [Core TH.TypeQ] -> DsM (Core TH.TypeQ)+repTPromotedList [] = repPromotedNilTyCon+repTPromotedList (t:ts) = do { tcon <- repPromotedConsTyCon+ ; f <- repTapp tcon t+ ; t' <- repTPromotedList ts+ ; repTapp f t'+ }++repTLit :: Core TH.TyLitQ -> DsM (Core TH.TypeQ)+repTLit (MkC lit) = rep2 litTName [lit]++repTWildCard :: DsM (Core TH.TypeQ)+repTWildCard = rep2 wildCardTName []++--------- Type constructors --------------++repNamedTyCon :: Core TH.Name -> DsM (Core TH.TypeQ)+repNamedTyCon (MkC s) = rep2 conTName [s]++repTupleTyCon :: Int -> DsM (Core TH.TypeQ)+-- Note: not Core Int; it's easier to be direct here+repTupleTyCon i = do dflags <- getDynFlags+ rep2 tupleTName [mkIntExprInt dflags i]++repUnboxedTupleTyCon :: Int -> DsM (Core TH.TypeQ)+-- Note: not Core Int; it's easier to be direct here+repUnboxedTupleTyCon i = do dflags <- getDynFlags+ rep2 unboxedTupleTName [mkIntExprInt dflags i]++repUnboxedSumTyCon :: TH.SumArity -> DsM (Core TH.TypeQ)+-- Note: not Core TH.SumArity; it's easier to be direct here+repUnboxedSumTyCon arity = do dflags <- getDynFlags+ rep2 unboxedSumTName [mkIntExprInt dflags arity]++repArrowTyCon :: DsM (Core TH.TypeQ)+repArrowTyCon = rep2 arrowTName []++repListTyCon :: DsM (Core TH.TypeQ)+repListTyCon = rep2 listTName []++repPromotedDataCon :: Core TH.Name -> DsM (Core TH.TypeQ)+repPromotedDataCon (MkC s) = rep2 promotedTName [s]++repPromotedTupleTyCon :: Int -> DsM (Core TH.TypeQ)+repPromotedTupleTyCon i = do dflags <- getDynFlags+ rep2 promotedTupleTName [mkIntExprInt dflags i]++repPromotedNilTyCon :: DsM (Core TH.TypeQ)+repPromotedNilTyCon = rep2 promotedNilTName []++repPromotedConsTyCon :: DsM (Core TH.TypeQ)+repPromotedConsTyCon = rep2 promotedConsTName []++------------ Kinds -------------------++repPlainTV :: Core TH.Name -> DsM (Core TH.TyVarBndr)+repPlainTV (MkC nm) = rep2 plainTVName [nm]++repKindedTV :: Core TH.Name -> Core TH.Kind -> DsM (Core TH.TyVarBndr)+repKindedTV (MkC nm) (MkC ki) = rep2 kindedTVName [nm, ki]++repKVar :: Core TH.Name -> DsM (Core TH.Kind)+repKVar (MkC s) = rep2 varKName [s]++repKCon :: Core TH.Name -> DsM (Core TH.Kind)+repKCon (MkC s) = rep2 conKName [s]++repKTuple :: Int -> DsM (Core TH.Kind)+repKTuple i = do dflags <- getDynFlags+ rep2 tupleKName [mkIntExprInt dflags i]++repKArrow :: DsM (Core TH.Kind)+repKArrow = rep2 arrowKName []++repKList :: DsM (Core TH.Kind)+repKList = rep2 listKName []++repKApp :: Core TH.Kind -> Core TH.Kind -> DsM (Core TH.Kind)+repKApp (MkC k1) (MkC k2) = rep2 appKName [k1, k2]++repKApps :: Core TH.Kind -> [Core TH.Kind] -> DsM (Core TH.Kind)+repKApps f [] = return f+repKApps f (k:ks) = do { f' <- repKApp f k; repKApps f' ks }++repKStar :: DsM (Core TH.Kind)+repKStar = rep2 starKName []++repKConstraint :: DsM (Core TH.Kind)+repKConstraint = rep2 constraintKName []++----------------------------------------------------------+-- Type family result signature++repNoSig :: DsM (Core TH.FamilyResultSig)+repNoSig = rep2 noSigName []++repKindSig :: Core TH.Kind -> DsM (Core TH.FamilyResultSig)+repKindSig (MkC ki) = rep2 kindSigName [ki]++repTyVarSig :: Core TH.TyVarBndr -> DsM (Core TH.FamilyResultSig)+repTyVarSig (MkC bndr) = rep2 tyVarSigName [bndr]++----------------------------------------------------------+-- Literals++repLiteral :: HsLit -> DsM (Core TH.Lit)+repLiteral (HsStringPrim _ bs)+ = do dflags <- getDynFlags+ word8_ty <- lookupType word8TyConName+ let w8s = unpack bs+ w8s_expr = map (\w8 -> mkCoreConApps word8DataCon+ [mkWordLit dflags (toInteger w8)]) w8s+ rep2 stringPrimLName [mkListExpr word8_ty w8s_expr]+repLiteral lit+ = do lit' <- case lit of+ HsIntPrim _ i -> mk_integer i+ HsWordPrim _ w -> mk_integer w+ HsInt _ i -> mk_integer i+ HsFloatPrim r -> mk_rational r+ HsDoublePrim r -> mk_rational r+ HsCharPrim _ c -> mk_char c+ _ -> return lit+ lit_expr <- dsLit lit'+ case mb_lit_name of+ Just lit_name -> rep2 lit_name [lit_expr]+ Nothing -> notHandled "Exotic literal" (ppr lit)+ where+ mb_lit_name = case lit of+ HsInteger _ _ _ -> Just integerLName+ HsInt _ _ -> Just integerLName+ HsIntPrim _ _ -> Just intPrimLName+ HsWordPrim _ _ -> Just wordPrimLName+ HsFloatPrim _ -> Just floatPrimLName+ HsDoublePrim _ -> Just doublePrimLName+ HsChar _ _ -> Just charLName+ HsCharPrim _ _ -> Just charPrimLName+ HsString _ _ -> Just stringLName+ HsRat _ _ -> Just rationalLName+ _ -> Nothing++mk_integer :: Integer -> DsM HsLit+mk_integer i = do integer_ty <- lookupType integerTyConName+ return $ HsInteger NoSourceText i integer_ty+mk_rational :: FractionalLit -> DsM HsLit+mk_rational r = do rat_ty <- lookupType rationalTyConName+ return $ HsRat r rat_ty+mk_string :: FastString -> DsM HsLit+mk_string s = return $ HsString NoSourceText s++mk_char :: Char -> DsM HsLit+mk_char c = return $ HsChar NoSourceText c++repOverloadedLiteral :: HsOverLit Name -> DsM (Core TH.Lit)+repOverloadedLiteral (OverLit { ol_val = val})+ = do { lit <- mk_lit val; repLiteral lit }+ -- The type Rational will be in the environment, because+ -- the smart constructor 'TH.Syntax.rationalL' uses it in its type,+ -- and rationalL is sucked in when any TH stuff is used++mk_lit :: OverLitVal -> DsM HsLit+mk_lit (HsIntegral _ i) = mk_integer i+mk_lit (HsFractional f) = mk_rational f+mk_lit (HsIsString _ s) = mk_string s++repNameS :: Core String -> DsM (Core TH.Name)+repNameS (MkC name) = rep2 mkNameSName [name]++--------------- Miscellaneous -------------------++repGensym :: Core String -> DsM (Core (TH.Q TH.Name))+repGensym (MkC lit_str) = rep2 newNameName [lit_str]++repBindQ :: Type -> Type -- a and b+ -> Core (TH.Q a) -> Core (a -> TH.Q b) -> DsM (Core (TH.Q b))+repBindQ ty_a ty_b (MkC x) (MkC y)+ = rep2 bindQName [Type ty_a, Type ty_b, x, y]++repSequenceQ :: Type -> Core [TH.Q a] -> DsM (Core (TH.Q [a]))+repSequenceQ ty_a (MkC list)+ = rep2 sequenceQName [Type ty_a, list]++repUnboundVar :: Core TH.Name -> DsM (Core TH.ExpQ)+repUnboundVar (MkC name) = rep2 unboundVarEName [name]++------------ Lists -------------------+-- turn a list of patterns into a single pattern matching a list++repList :: Name -> (a -> DsM (Core b))+ -> [a] -> DsM (Core [b])+repList tc_name f args+ = do { args1 <- mapM f args+ ; coreList tc_name args1 }++coreList :: Name -- Of the TyCon of the element type+ -> [Core a] -> DsM (Core [a])+coreList tc_name es+ = do { elt_ty <- lookupType tc_name; return (coreList' elt_ty es) }++coreList' :: Type -- The element type+ -> [Core a] -> Core [a]+coreList' elt_ty es = MkC (mkListExpr elt_ty (map unC es ))++nonEmptyCoreList :: [Core a] -> Core [a]+ -- The list must be non-empty so we can get the element type+ -- Otherwise use coreList+nonEmptyCoreList [] = panic "coreList: empty argument"+nonEmptyCoreList xs@(MkC x:_) = MkC (mkListExpr (exprType x) (map unC xs))++coreStringLit :: String -> DsM (Core String)+coreStringLit s = do { z <- mkStringExpr s; return(MkC z) }++------------------- Maybe ------------------++-- | Construct Core expression for Nothing of a given type name+coreNothing :: Name -- ^ Name of the TyCon of the element type+ -> DsM (Core (Maybe a))+coreNothing tc_name =+ do { elt_ty <- lookupType tc_name; return (coreNothing' elt_ty) }++-- | Construct Core expression for Nothing of a given type+coreNothing' :: Type -- ^ The element type+ -> Core (Maybe a)+coreNothing' elt_ty = MkC (mkNothingExpr elt_ty)++-- | Store given Core expression in a Just of a given type name+coreJust :: Name -- ^ Name of the TyCon of the element type+ -> Core a -> DsM (Core (Maybe a))+coreJust tc_name es+ = do { elt_ty <- lookupType tc_name; return (coreJust' elt_ty es) }++-- | Store given Core expression in a Just of a given type+coreJust' :: Type -- ^ The element type+ -> Core a -> Core (Maybe a)+coreJust' elt_ty es = MkC (mkJustExpr elt_ty (unC es))++------------ Literals & Variables -------------------++coreIntLit :: Int -> DsM (Core Int)+coreIntLit i = do dflags <- getDynFlags+ return (MkC (mkIntExprInt dflags i))++coreVar :: Id -> Core TH.Name -- The Id has type Name+coreVar id = MkC (Var id)++----------------- Failure -----------------------+notHandledL :: SrcSpan -> String -> SDoc -> DsM a+notHandledL loc what doc+ | isGoodSrcSpan loc+ = putSrcSpanDs loc $ notHandled what doc+ | otherwise+ = notHandled what doc++notHandled :: String -> SDoc -> DsM a+notHandled what doc = failWithDs msg+ where+ msg = hang (text what <+> text "not (yet) handled by Template Haskell")+ 2 doc
+ deSugar/DsMonad.hs view
@@ -0,0 +1,733 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++@DsMonad@: monadery used in desugaring+-}++{-# LANGUAGE FlexibleInstances, FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} -- instance MonadThings is necessarily an orphan++module DsMonad (+ DsM, mapM, mapAndUnzipM,+ initDs, initDsTc, initTcDsForSolver, initDsWithModGuts, fixDs,+ foldlM, foldrM, whenGOptM, unsetGOptM, unsetWOptM, xoptM,+ Applicative(..),(<$>),++ duplicateLocalDs, newSysLocalDsNoLP, newSysLocalDs,+ newSysLocalsDsNoLP, newSysLocalsDs, newUniqueId,+ newFailLocalDs, newPredVarDs,+ getSrcSpanDs, putSrcSpanDs,+ mkPrintUnqualifiedDs,+ newUnique,+ UniqSupply, newUniqueSupply,+ getGhcModeDs, dsGetFamInstEnvs,+ dsLookupGlobal, dsLookupGlobalId, dsDPHBuiltin, dsLookupTyCon,+ dsLookupDataCon, dsLookupConLike,++ PArrBuiltin(..),+ dsLookupDPHRdrEnv, dsLookupDPHRdrEnv_maybe,+ dsInitPArrBuiltin,++ DsMetaEnv, DsMetaVal(..), dsGetMetaEnv, dsLookupMetaEnv, dsExtendMetaEnv,++ -- Getting and setting EvVars and term constraints in local environment+ getDictsDs, addDictsDs, getTmCsDs, addTmCsDs,++ -- Iterations for pm checking+ incrCheckPmIterDs, resetPmIterDs, dsGetCompleteMatches,++ -- Warnings and errors+ DsWarning, warnDs, warnIfSetDs, errDs, errDsCoreExpr,+ failWithDs, failDs, discardWarningsDs,+ askNoErrsDs,++ -- Data types+ DsMatchContext(..),+ EquationInfo(..), MatchResult(..), DsWrapper, idDsWrapper,+ CanItFail(..), orFail,++ -- Levity polymorphism+ dsNoLevPoly, dsNoLevPolyExpr, dsWhenNoErrs+ ) where++import TcRnMonad+import FamInstEnv+import CoreSyn+import MkCore ( unitExpr )+import CoreUtils ( exprType, isExprLevPoly )+import HsSyn+import TcIface+import TcMType ( checkForLevPolyX, formatLevPolyErr )+import LoadIface+import Finder+import PrelNames+import RdrName+import HscTypes+import Bag+import DataCon+import ConLike+import TyCon+import PmExpr+import Id+import Module+import Outputable+import SrcLoc+import Type+import UniqSupply+import Name+import NameEnv+import DynFlags+import ErrUtils+import FastString+import Maybes+import Var (EvVar)+import qualified GHC.LanguageExtensions as LangExt+import UniqFM ( lookupWithDefaultUFM )++import Data.IORef+import Control.Monad++{-+************************************************************************+* *+ Data types for the desugarer+* *+************************************************************************+-}++data DsMatchContext+ = DsMatchContext (HsMatchContext Name) SrcSpan+ deriving ()++instance Outputable DsMatchContext where+ ppr (DsMatchContext hs_match ss) = ppr ss <+> pprMatchContext hs_match++data EquationInfo+ = EqnInfo { eqn_pats :: [Pat Id], -- The patterns for an eqn+ eqn_rhs :: MatchResult } -- What to do after match++instance Outputable EquationInfo where+ ppr (EqnInfo pats _) = ppr pats++type DsWrapper = CoreExpr -> CoreExpr+idDsWrapper :: DsWrapper+idDsWrapper e = e++-- The semantics of (match vs (EqnInfo wrap pats rhs)) is the MatchResult+-- \fail. wrap (case vs of { pats -> rhs fail })+-- where vs are not bound by wrap+++-- A MatchResult is an expression with a hole in it+data MatchResult+ = MatchResult+ CanItFail -- Tells whether the failure expression is used+ (CoreExpr -> DsM CoreExpr)+ -- Takes a expression to plug in at the+ -- failure point(s). The expression should+ -- be duplicatable!++data CanItFail = CanFail | CantFail++orFail :: CanItFail -> CanItFail -> CanItFail+orFail CantFail CantFail = CantFail+orFail _ _ = CanFail++{-+************************************************************************+* *+ Monad functions+* *+************************************************************************+-}++-- Compatibility functions+fixDs :: (a -> DsM a) -> DsM a+fixDs = fixM++type DsWarning = (SrcSpan, SDoc)+ -- Not quite the same as a WarnMsg, we have an SDoc here+ -- and we'll do the print_unqual stuff later on to turn it+ -- into a Doc.++-- | Run a 'DsM' action inside the 'TcM' monad.+initDsTc :: DsM a -> TcM a+initDsTc thing_inside+ = do { tcg_env <- getGblEnv+ ; msg_var <- getErrsVar+ ; hsc_env <- getTopEnv+ ; envs <- mkDsEnvsFromTcGbl hsc_env msg_var tcg_env+ ; setEnvs envs $ initDPH thing_inside+ }++-- | Run a 'DsM' action inside the 'IO' monad.+initDs :: HscEnv -> TcGblEnv -> DsM a -> IO (Messages, Maybe a)+initDs hsc_env tcg_env thing_inside+ = do { msg_var <- newIORef emptyMessages+ ; envs <- mkDsEnvsFromTcGbl hsc_env msg_var tcg_env+ ; runDs hsc_env envs thing_inside+ }++-- | Build a set of desugarer environments derived from a 'TcGblEnv'.+mkDsEnvsFromTcGbl :: MonadIO m+ => HscEnv -> IORef Messages -> TcGblEnv+ -> m (DsGblEnv, DsLclEnv)+mkDsEnvsFromTcGbl hsc_env msg_var tcg_env+ = do { pm_iter_var <- liftIO $ newIORef 0+ ; let dflags = hsc_dflags hsc_env+ this_mod = tcg_mod tcg_env+ type_env = tcg_type_env tcg_env+ rdr_env = tcg_rdr_env tcg_env+ fam_inst_env = tcg_fam_inst_env tcg_env+ complete_matches = hptCompleteSigs hsc_env+ ++ tcg_complete_matches tcg_env+ ; return $ mkDsEnvs dflags this_mod rdr_env type_env fam_inst_env+ msg_var pm_iter_var complete_matches+ }++runDs :: HscEnv -> (DsGblEnv, DsLclEnv) -> DsM a -> IO (Messages, Maybe a)+runDs hsc_env (ds_gbl, ds_lcl) thing_inside+ = do { res <- initTcRnIf 'd' hsc_env ds_gbl ds_lcl+ (initDPH $ tryM thing_inside)+ ; msgs <- readIORef (ds_msgs ds_gbl)+ ; let final_res+ | errorsFound dflags msgs = Nothing+ | Right r <- res = Just r+ | otherwise = panic "initDs"+ ; return (msgs, final_res)+ }+ where dflags = hsc_dflags hsc_env++-- | Run a 'DsM' action in the context of an existing 'ModGuts'+initDsWithModGuts :: HscEnv -> ModGuts -> DsM a -> IO (Messages, Maybe a)+initDsWithModGuts hsc_env guts thing_inside+ = do { pm_iter_var <- newIORef 0+ ; msg_var <- newIORef emptyMessages+ ; let dflags = hsc_dflags hsc_env+ type_env = typeEnvFromEntities ids (mg_tcs guts) (mg_fam_insts guts)+ rdr_env = mg_rdr_env guts+ fam_inst_env = mg_fam_inst_env guts+ this_mod = mg_module guts+ complete_matches = hptCompleteSigs hsc_env+ ++ mg_complete_sigs guts++ bindsToIds (NonRec v _) = [v]+ bindsToIds (Rec binds) = map fst binds+ ids = concatMap bindsToIds (mg_binds guts)++ envs = mkDsEnvs dflags this_mod rdr_env type_env+ fam_inst_env msg_var pm_iter_var+ complete_matches+ ; runDs hsc_env envs thing_inside+ }++initTcDsForSolver :: TcM a -> DsM (Messages, Maybe a)+-- Spin up a TcM context so that we can run the constraint solver+-- Returns any error messages generated by the constraint solver+-- and (Just res) if no error happened; Nothing if an error happened+--+-- Simon says: I'm not very happy about this. We spin up a complete TcM monad+-- only to immediately refine it to a TcS monad.+-- Better perhaps to make TcS into its own monad, rather than building on TcS+-- But that may in turn interact with plugins++initTcDsForSolver thing_inside+ = do { (gbl, lcl) <- getEnvs+ ; hsc_env <- getTopEnv++ ; let DsGblEnv { ds_mod = mod+ , ds_fam_inst_env = fam_inst_env } = gbl++ DsLclEnv { dsl_loc = loc } = lcl++ ; liftIO $ initTc hsc_env HsSrcFile False mod loc $+ updGblEnv (\tc_gbl -> tc_gbl { tcg_fam_inst_env = fam_inst_env }) $+ thing_inside }++mkDsEnvs :: DynFlags -> Module -> GlobalRdrEnv -> TypeEnv -> FamInstEnv+ -> IORef Messages -> IORef Int -> [CompleteMatch]+ -> (DsGblEnv, DsLclEnv)+mkDsEnvs dflags mod rdr_env type_env fam_inst_env msg_var pmvar+ complete_matches+ = let if_genv = IfGblEnv { if_doc = text "mkDsEnvs",+ if_rec_types = Just (mod, return type_env) }+ if_lenv = mkIfLclEnv mod (text "GHC error in desugarer lookup in" <+> ppr mod)+ False -- not boot!+ real_span = realSrcLocSpan (mkRealSrcLoc (moduleNameFS (moduleName mod)) 1 1)+ completeMatchMap = mkCompleteMatchMap complete_matches+ gbl_env = DsGblEnv { ds_mod = mod+ , ds_fam_inst_env = fam_inst_env+ , ds_if_env = (if_genv, if_lenv)+ , ds_unqual = mkPrintUnqualified dflags rdr_env+ , ds_msgs = msg_var+ , ds_dph_env = emptyGlobalRdrEnv+ , ds_parr_bi = panic "DsMonad: uninitialised ds_parr_bi"+ , ds_complete_matches = completeMatchMap+ }+ lcl_env = DsLclEnv { dsl_meta = emptyNameEnv+ , dsl_loc = real_span+ , dsl_dicts = emptyBag+ , dsl_tm_cs = emptyBag+ , dsl_pm_iter = pmvar+ }+ in (gbl_env, lcl_env)+++{-+************************************************************************+* *+ Operations in the monad+* *+************************************************************************++And all this mysterious stuff is so we can occasionally reach out and+grab one or more names. @newLocalDs@ isn't exported---exported+functions are defined with it. The difference in name-strings makes+it easier to read debugging output.++Note [Levity polymorphism checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+According to the Levity Polymorphism paper+<http://cs.brynmawr.edu/~rae/papers/2017/levity/levity.pdf>, levity+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. The paper+explains it 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 levity polymorphic.++We cannot check for bad levity polymorphism conveniently in the type checker,+because we can't tell, a priori, which levity 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 DsMonad.dsNoLevPoly and friends.++Levity 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 levity polymorphic, omitting the check.+It would be nice to ASSERT that there is no levity polymorphism here,+but we can't, because of the fixM in DsArrows. 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 levity+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 -> Type -> DsM Id+newUniqueId id = mk_local (occNameFS (nameOccName (idName id)))++duplicateLocalDs :: Id -> DsM Id+duplicateLocalDs old_local+ = do { uniq <- newUnique+ ; return (setIdUnique old_local uniq) }++newPredVarDs :: PredType -> DsM Var+newPredVarDs pred+ = newSysLocalDs pred++newSysLocalDsNoLP, newSysLocalDs, newFailLocalDs :: 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 levity-polymorphic. It is necessary when the type is knot-tied because+-- of the fixM used in DsArrows. See Note [Levity polymorphism checking]+newSysLocalDs = mkSysLocalOrCoVarM (fsLit "ds")+newFailLocalDs = mkSysLocalOrCoVarM (fsLit "fail")+ -- the fail variable is used only in a situation where we can tell that+ -- levity-polymorphism is impossible.++newSysLocalsDsNoLP, newSysLocalsDs :: [Type] -> DsM [Id]+newSysLocalsDsNoLP = mapM newSysLocalDsNoLP+newSysLocalsDs = mapM newSysLocalDs++mk_local :: FastString -> Type -> DsM Id+mk_local fs ty = do { dsNoLevPoly ty (text "When trying to create a variable of type:" <+>+ ppr ty) -- could improve the msg with another+ -- parameter indicating context+ ; mkSysLocalOrCoVarM fs ty }++{-+We can also reach out and either set/grab location information from+the @SrcSpan@ being carried around.+-}++getGhcModeDs :: DsM GhcMode+getGhcModeDs = getDynFlags >>= return . ghcMode++-- | Get in-scope type constraints (pm check)+getDictsDs :: DsM (Bag EvVar)+getDictsDs = do { env <- getLclEnv; return (dsl_dicts env) }++-- | Add in-scope type constraints (pm check)+addDictsDs :: Bag EvVar -> DsM a -> DsM a+addDictsDs ev_vars+ = updLclEnv (\env -> env { dsl_dicts = unionBags ev_vars (dsl_dicts env) })++-- | Get in-scope term constraints (pm check)+getTmCsDs :: DsM (Bag SimpleEq)+getTmCsDs = do { env <- getLclEnv; return (dsl_tm_cs env) }++-- | Add in-scope term constraints (pm check)+addTmCsDs :: Bag SimpleEq -> DsM a -> DsM a+addTmCsDs tm_cs+ = updLclEnv (\env -> env { dsl_tm_cs = unionBags tm_cs (dsl_tm_cs env) })++-- | Increase the counter for elapsed pattern match check iterations.+-- If the current counter is already over the limit, fail+incrCheckPmIterDs :: DsM Int+incrCheckPmIterDs = do+ env <- getLclEnv+ cnt <- readTcRef (dsl_pm_iter env)+ max_iters <- maxPmCheckIterations <$> getDynFlags+ if cnt >= max_iters+ then failM+ else updTcRef (dsl_pm_iter env) (+1)+ return cnt++-- | Reset the counter for pattern match check iterations to zero+resetPmIterDs :: DsM ()+resetPmIterDs = do { env <- getLclEnv; writeTcRef (dsl_pm_iter env) 0 }++getSrcSpanDs :: DsM SrcSpan+getSrcSpanDs = do { env <- getLclEnv+ ; return (RealSrcSpan (dsl_loc env)) }++putSrcSpanDs :: SrcSpan -> DsM a -> DsM a+putSrcSpanDs (UnhelpfulSpan {}) thing_inside+ = thing_inside+putSrcSpanDs (RealSrcSpan real_span) thing_inside+ = updLclEnv (\ env -> env {dsl_loc = real_span}) thing_inside++-- | Emit a warning for the current source location+-- NB: Warns whether or not -Wxyz is set+warnDs :: WarnReason -> SDoc -> DsM ()+warnDs reason warn+ = do { env <- getGblEnv+ ; loc <- getSrcSpanDs+ ; dflags <- getDynFlags+ ; let msg = makeIntoWarning reason $+ mkWarnMsg dflags loc (ds_unqual env) warn+ ; updMutVar (ds_msgs env) (\ (w,e) -> (w `snocBag` msg, e)) }++-- | Emit a warning only if the correct WarnReason is set in the DynFlags+warnIfSetDs :: WarningFlag -> SDoc -> DsM ()+warnIfSetDs flag warn+ = whenWOptM flag $+ warnDs (Reason flag) warn++errDs :: SDoc -> DsM ()+errDs err+ = do { env <- getGblEnv+ ; loc <- getSrcSpanDs+ ; dflags <- getDynFlags+ ; let msg = mkErrMsg dflags loc (ds_unqual env) err+ ; updMutVar (ds_msgs env) (\ (w,e) -> (w, e `snocBag` msg)) }++-- | Issue an error, but return the expression for (), so that we can continue+-- reporting errors.+errDsCoreExpr :: SDoc -> DsM CoreExpr+errDsCoreExpr err+ = do { errDs err+ ; return unitExpr }++failWithDs :: SDoc -> DsM a+failWithDs err+ = do { errDs err+ ; failM }++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. TcRnMonad.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+ -- (Trac #13642)+ setGblEnv (env { ds_msgs = errs_var }) $+ thing_inside++ -- Propagate errors+ ; msgs@(warns, errs) <- readMutVar errs_var+ ; updMutVar (ds_msgs env) (\ (w,e) -> (w `unionBags` warns, e `unionBags` errs))++ -- And return+ ; case mb_res of+ Left _ -> failM+ Right res -> do { dflags <- getDynFlags+ ; let errs_found = errorsFound dflags msgs+ ; return (res, not errs_found) } }++mkPrintUnqualifiedDs :: DsM PrintUnqualified+mkPrintUnqualifiedDs = ds_unqual <$> getGblEnv++instance MonadThings (IOEnv (Env DsGblEnv DsLclEnv)) where+ lookupThing = dsLookupGlobal++-- | Attempt to load the given module and return its exported entities if+-- successful.+dsLoadModule :: SDoc -> Module -> DsM GlobalRdrEnv+dsLoadModule doc mod+ = do { env <- getGblEnv+ ; setEnvs (ds_if_env env) $ do+ { iface <- loadInterface doc mod ImportBySystem+ ; case iface of+ Failed err -> pprPanic "DsMonad.dsLoadModule: failed to load" (err $$ doc)+ Succeeded iface -> return $ mkGlobalRdrEnv . gresFromAvails prov . mi_exports $ iface+ } }+ where+ prov = Just (ImpSpec { is_decl = imp_spec, is_item = ImpAll })+ imp_spec = ImpDeclSpec { is_mod = name, is_qual = True,+ is_dloc = wiredInSrcSpan, is_as = name }+ name = moduleName mod++dsLookupGlobal :: Name -> DsM TyThing+-- Very like TcEnv.tcLookupGlobal+dsLookupGlobal name+ = do { env <- getGblEnv+ ; setEnvs (ds_if_env env)+ (tcIfaceGlobal name) }++dsLookupGlobalId :: Name -> DsM Id+dsLookupGlobalId name+ = tyThingId <$> dsLookupGlobal name++dsLookupTyCon :: Name -> DsM TyCon+dsLookupTyCon name+ = tyThingTyCon <$> dsLookupGlobal name++dsLookupDataCon :: Name -> DsM DataCon+dsLookupDataCon name+ = tyThingDataCon <$> dsLookupGlobal name++dsLookupConLike :: Name -> DsM ConLike+dsLookupConLike name+ = tyThingConLike <$> dsLookupGlobal name+++dsGetFamInstEnvs :: DsM FamInstEnvs+-- Gets both the external-package inst-env+-- and the home-pkg inst env (includes module being compiled)+dsGetFamInstEnvs+ = do { eps <- getEps; env <- getGblEnv+ ; return (eps_fam_inst_env eps, ds_fam_inst_env env) }++dsGetMetaEnv :: DsM (NameEnv DsMetaVal)+dsGetMetaEnv = do { env <- getLclEnv; return (dsl_meta env) }++-- | The @COMPLETE@ pragams provided by the user for a given `TyCon`.+dsGetCompleteMatches :: TyCon -> DsM [CompleteMatch]+dsGetCompleteMatches tc = do+ eps <- getEps+ env <- getGblEnv+ let lookup_completes ufm = lookupWithDefaultUFM ufm [] tc+ eps_matches_list = lookup_completes $ eps_complete_matches eps+ env_matches_list = lookup_completes $ ds_complete_matches env+ return $ eps_matches_list ++ env_matches_list++dsLookupMetaEnv :: Name -> DsM (Maybe DsMetaVal)+dsLookupMetaEnv name = do { env <- getLclEnv; return (lookupNameEnv (dsl_meta env) name) }++dsExtendMetaEnv :: DsMetaEnv -> DsM a -> DsM a+dsExtendMetaEnv menv thing_inside+ = updLclEnv (\env -> env { dsl_meta = dsl_meta env `plusNameEnv` menv }) thing_inside++discardWarningsDs :: DsM a -> DsM a+-- Ignore warnings inside the thing inside;+-- used to ignore inaccessable cases etc. inside generated code+discardWarningsDs thing_inside+ = do { env <- getGblEnv+ ; old_msgs <- readTcRef (ds_msgs env)++ ; result <- thing_inside++ -- Revert messages to old_msgs+ ; writeTcRef (ds_msgs env) old_msgs++ ; return result }++-- | Fail with an error message if the type is levity polymorphic.+dsNoLevPoly :: Type -> SDoc -> DsM ()+-- See Note [Levity polymorphism checking]+dsNoLevPoly ty doc = checkForLevPolyX errDs doc ty++-- | Check an expression for levity polymorphism, failing if it is+-- levity polymorphic.+dsNoLevPolyExpr :: CoreExpr -> SDoc -> DsM ()+-- See Note [Levity polymorphism checking]+dsNoLevPolyExpr e doc+ | isExprLevPoly e = errDs (formatLevPolyErr (exprType e) $$ doc)+ | otherwise = return ()++-- | Runs the thing_inside. If there are no errors, then returns the expr+-- given. Otherwise, returns unitExpr. This is useful for doing a bunch+-- of levity polymorphism checks and then avoiding making a core App.+-- (If we make a core App on a levity polymorphic argument, detecting how+-- to handle the let/app invariant might call isUnliftedType, which panics+-- on a levity polymorphic type.)+-- See #12709 for an example of why this machinery is necessary.+dsWhenNoErrs :: DsM a -> (a -> CoreExpr) -> DsM CoreExpr+dsWhenNoErrs thing_inside mk_expr+ = do { (result, no_errs) <- askNoErrsDs thing_inside+ ; return $ if no_errs+ then mk_expr result+ else unitExpr }++--------------------------------------------------------------------------+-- Data Parallel Haskell+--------------------------------------------------------------------------++-- | Run a 'DsM' with DPH things in scope if necessary.+initDPH :: DsM a -> DsM a+initDPH = loadDAP . initDPHBuiltins++-- | Extend the global environment with a 'GlobalRdrEnv' containing the exported+-- entities of,+--+-- * 'Data.Array.Parallel' iff '-XParallelArrays' specified (see also 'checkLoadDAP').+-- * 'Data.Array.Parallel.Prim' iff '-fvectorise' specified.+loadDAP :: DsM a -> DsM a+loadDAP thing_inside+ = do { dapEnv <- loadOneModule dATA_ARRAY_PARALLEL_NAME checkLoadDAP paErr+ ; dappEnv <- loadOneModule dATA_ARRAY_PARALLEL_PRIM_NAME (goptM Opt_Vectorise) veErr+ ; updGblEnv (\env -> env {ds_dph_env = dapEnv `plusOccEnv` dappEnv }) thing_inside+ }+ where+ loadOneModule :: ModuleName -- the module to load+ -> DsM Bool -- under which condition+ -> MsgDoc -- error message if module not found+ -> DsM GlobalRdrEnv -- empty if condition 'False'+ loadOneModule modname check err+ = do { doLoad <- check+ ; if not doLoad+ then return emptyGlobalRdrEnv+ else do {+ ; hsc_env <- getTopEnv+ ; result <- liftIO $ findImportedModule hsc_env modname Nothing+ ; case result of+ Found _ mod -> dsLoadModule err mod+ _ -> pprPgmError "Unable to use Data Parallel Haskell (DPH):" err+ } }++ paErr = text "To use ParallelArrays," <+> specBackend $$ hint1 $$ hint2+ veErr = text "To use -fvectorise," <+> specBackend $$ hint1 $$ hint2+ specBackend = text "you must specify a DPH backend package"+ hint1 = text "Look for packages named 'dph-lifted-*' with 'ghc-pkg'"+ hint2 = text "You may need to install them with 'cabal install dph-examples'"++-- | If '-XParallelArrays' given, we populate the builtin table for desugaring+-- those.+initDPHBuiltins :: DsM a -> DsM a+initDPHBuiltins thing_inside+ = do { doInitBuiltins <- checkLoadDAP+ ; if doInitBuiltins+ then dsInitPArrBuiltin thing_inside+ else thing_inside+ }++checkLoadDAP :: DsM Bool+checkLoadDAP+ = do { paEnabled <- xoptM LangExt.ParallelArrays+ ; mod <- getModule+ -- do not load 'Data.Array.Parallel' iff compiling 'base:GHC.PArr' or a+ -- module called 'dATA_ARRAY_PARALLEL_NAME'; see also the comments at the top+ -- of 'base:GHC.PArr' and 'Data.Array.Parallel' in the DPH libraries+ ; return $ paEnabled &&+ mod /= gHC_PARR' &&+ moduleName mod /= dATA_ARRAY_PARALLEL_NAME+ }++-- | Populate 'ds_parr_bi' from 'ds_dph_env'.+--+dsInitPArrBuiltin :: DsM a -> DsM a+dsInitPArrBuiltin thing_inside+ = do { lengthPVar <- externalVar (fsLit "lengthP")+ ; replicatePVar <- externalVar (fsLit "replicateP")+ ; singletonPVar <- externalVar (fsLit "singletonP")+ ; mapPVar <- externalVar (fsLit "mapP")+ ; filterPVar <- externalVar (fsLit "filterP")+ ; zipPVar <- externalVar (fsLit "zipP")+ ; crossMapPVar <- externalVar (fsLit "crossMapP")+ ; indexPVar <- externalVar (fsLit "!:")+ ; emptyPVar <- externalVar (fsLit "emptyP")+ ; appPVar <- externalVar (fsLit "+:+")+ -- ; enumFromToPVar <- externalVar (fsLit "enumFromToP")+ -- ; enumFromThenToPVar <- externalVar (fsLit "enumFromThenToP")+ ; enumFromToPVar <- return arithErr+ ; enumFromThenToPVar <- return arithErr++ ; updGblEnv (\env -> env {ds_parr_bi = PArrBuiltin+ { lengthPVar = lengthPVar+ , replicatePVar = replicatePVar+ , singletonPVar = singletonPVar+ , mapPVar = mapPVar+ , filterPVar = filterPVar+ , zipPVar = zipPVar+ , crossMapPVar = crossMapPVar+ , indexPVar = indexPVar+ , emptyPVar = emptyPVar+ , appPVar = appPVar+ , enumFromToPVar = enumFromToPVar+ , enumFromThenToPVar = enumFromThenToPVar+ } })+ thing_inside+ }+ where+ externalVar :: FastString -> DsM Var+ externalVar fs = dsLookupDPHRdrEnv (mkVarOccFS fs) >>= dsLookupGlobalId++ arithErr = panic "Arithmetic sequences have to wait until we support type classes"++-- |Get a name from "Data.Array.Parallel" for the desugarer, from the+-- 'ds_parr_bi' component of the global desugerar environment.+--+dsDPHBuiltin :: (PArrBuiltin -> a) -> DsM a+dsDPHBuiltin sel = (sel . ds_parr_bi) <$> getGblEnv++-- |Lookup a name exported by 'Data.Array.Parallel.Prim' or 'Data.Array.Parallel.Prim'.+-- Panic if there isn't one, or if it is defined multiple times.+dsLookupDPHRdrEnv :: OccName -> DsM Name+dsLookupDPHRdrEnv occ+ = liftM (fromMaybe (pprPanic nameNotFound (ppr occ)))+ $ dsLookupDPHRdrEnv_maybe occ+ where nameNotFound = "Name not found in 'Data.Array.Parallel' or 'Data.Array.Parallel.Prim':"++-- |Lookup a name exported by 'Data.Array.Parallel.Prim' or 'Data.Array.Parallel.Prim',+-- returning `Nothing` if it's not defined. Panic if it's defined multiple times.+dsLookupDPHRdrEnv_maybe :: OccName -> DsM (Maybe Name)+dsLookupDPHRdrEnv_maybe occ+ = do { env <- ds_dph_env <$> getGblEnv+ ; let gres = lookupGlobalRdrEnv env occ+ ; case gres of+ [] -> return $ Nothing+ [gre] -> return $ Just $ gre_name gre+ _ -> pprPanic multipleNames (ppr occ)+ }+ where multipleNames = "Multiple definitions in 'Data.Array.Parallel' and 'Data.Array.Parallel.Prim':"
+ deSugar/DsUsage.hs view
@@ -0,0 +1,224 @@+{-# LANGUAGE CPP #-}++module DsUsage (+ -- * Dependency/fingerprinting code (used by MkIface)+ mkUsageInfo, mkUsedNames, mkDependencies+ ) where++#include "HsVersions.h"++import DynFlags+import HscTypes+import TcRnTypes+import Name+import NameSet+import Module+import Outputable+import Util+import UniqSet+import UniqFM+import Fingerprint+import Maybes++import Data.List+import Data.IORef+import Data.Map (Map)+import qualified Data.Map as Map+import qualified Data.Set as Set++-- | Extract information from the rename and typecheck phases to produce+-- a dependencies information for the module being compiled.+mkDependencies :: TcGblEnv -> IO Dependencies+mkDependencies+ TcGblEnv{ tcg_mod = mod,+ tcg_imports = imports,+ tcg_th_used = th_var+ }+ = do+ -- Template Haskell used?+ th_used <- readIORef th_var+ let dep_mods = modDepsElts (delFromUFM (imp_dep_mods imports)+ (moduleName mod))+ -- M.hi-boot can be in the imp_dep_mods, but we must remove+ -- it before recording the modules on which this one depends!+ -- (We want to retain M.hi-boot in imp_dep_mods so that+ -- loadHiBootInterface can see if M's direct imports depend+ -- on M.hi-boot, and hence that we should do the hi-boot consistency+ -- check.)++ pkgs | th_used = Set.insert (toInstalledUnitId thUnitId) (imp_dep_pkgs imports)+ | otherwise = imp_dep_pkgs imports++ -- Set the packages required to be Safe according to Safe Haskell.+ -- See Note [RnNames . Tracking Trust Transitively]+ sorted_pkgs = sort (Set.toList pkgs)+ trust_pkgs = imp_trust_pkgs imports+ dep_pkgs' = map (\x -> (x, x `Set.member` trust_pkgs)) sorted_pkgs++ return Deps { dep_mods = dep_mods,+ dep_pkgs = dep_pkgs',+ dep_orphs = sortBy stableModuleCmp (imp_orphs imports),+ dep_finsts = sortBy stableModuleCmp (imp_finsts imports) }+ -- sort to get into canonical order+ -- NB. remember to use lexicographic ordering++mkUsedNames :: TcGblEnv -> NameSet+mkUsedNames TcGblEnv{ tcg_dus = dus } = allUses dus++mkUsageInfo :: HscEnv -> Module -> ImportedMods -> NameSet -> [FilePath] -> [(Module, Fingerprint)] -> IO [Usage]+mkUsageInfo hsc_env this_mod dir_imp_mods used_names dependent_files merged+ = do+ eps <- hscEPS hsc_env+ hashes <- mapM getFileHash dependent_files+ let mod_usages = mk_mod_usage_info (eps_PIT eps) hsc_env this_mod+ dir_imp_mods used_names+ usages = mod_usages ++ [ UsageFile { usg_file_path = f+ , usg_file_hash = hash }+ | (f, hash) <- zip dependent_files hashes ]+ ++ [ UsageMergedRequirement+ { usg_mod = mod,+ usg_mod_hash = hash+ }+ | (mod, hash) <- merged ]+ usages `seqList` return usages+ -- seq the list of Usages returned: occasionally these+ -- don't get evaluated for a while and we can end up hanging on to+ -- the entire collection of Ifaces.++mk_mod_usage_info :: PackageIfaceTable+ -> HscEnv+ -> Module+ -> ImportedMods+ -> NameSet+ -> [Usage]+mk_mod_usage_info pit hsc_env this_mod direct_imports used_names+ = mapMaybe mkUsage usage_mods+ where+ hpt = hsc_HPT hsc_env+ dflags = hsc_dflags hsc_env+ this_pkg = thisPackage dflags++ used_mods = moduleEnvKeys ent_map+ dir_imp_mods = moduleEnvKeys direct_imports+ all_mods = used_mods ++ filter (`notElem` used_mods) dir_imp_mods+ usage_mods = sortBy stableModuleCmp all_mods+ -- canonical order is imported, to avoid interface-file+ -- wobblage.++ -- ent_map groups together all the things imported and used+ -- from a particular module+ ent_map :: ModuleEnv [OccName]+ ent_map = nonDetFoldUniqSet add_mv emptyModuleEnv used_names+ -- nonDetFoldUFM is OK here. If you follow the logic, we sort by OccName+ -- in ent_hashs+ where+ add_mv name mv_map+ | isWiredInName name = mv_map -- ignore wired-in names+ | otherwise+ = case nameModule_maybe name of+ Nothing -> ASSERT2( isSystemName name, ppr name ) mv_map+ -- See Note [Internal used_names]++ Just mod ->+ -- See Note [Identity versus semantic module]+ let mod' = if isHoleModule mod+ then mkModule this_pkg (moduleName mod)+ else mod+ -- This lambda function is really just a+ -- specialised (++); originally came about to+ -- avoid quadratic behaviour (trac #2680)+ in extendModuleEnvWith (\_ xs -> occ:xs) mv_map mod' [occ]+ where occ = nameOccName name++ -- We want to create a Usage for a home module if+ -- a) we used something from it; has something in used_names+ -- b) we imported it, even if we used nothing from it+ -- (need to recompile if its export list changes: export_fprint)+ mkUsage :: Module -> Maybe Usage+ mkUsage mod+ | isNothing maybe_iface -- We can't depend on it if we didn't+ -- load its interface.+ || mod == this_mod -- We don't care about usages of+ -- things in *this* module+ = Nothing++ | moduleUnitId mod /= this_pkg+ = Just UsagePackageModule{ usg_mod = mod,+ usg_mod_hash = mod_hash,+ usg_safe = imp_safe }+ -- for package modules, we record the module hash only++ | (null used_occs+ && isNothing export_hash+ && not is_direct_import+ && not finsts_mod)+ = Nothing -- Record no usage info+ -- for directly-imported modules, we always want to record a usage+ -- on the orphan hash. This is what triggers a recompilation if+ -- an orphan is added or removed somewhere below us in the future.++ | otherwise+ = Just UsageHomeModule {+ usg_mod_name = moduleName mod,+ usg_mod_hash = mod_hash,+ usg_exports = export_hash,+ usg_entities = Map.toList ent_hashs,+ usg_safe = imp_safe }+ where+ maybe_iface = lookupIfaceByModule dflags hpt pit mod+ -- In one-shot mode, the interfaces for home-package+ -- modules accumulate in the PIT not HPT. Sigh.++ Just iface = maybe_iface+ finsts_mod = mi_finsts iface+ hash_env = mi_hash_fn iface+ mod_hash = mi_mod_hash iface+ export_hash | depend_on_exports = Just (mi_exp_hash iface)+ | otherwise = Nothing++ by_is_safe (ImportedByUser imv) = imv_is_safe imv+ by_is_safe _ = False+ (is_direct_import, imp_safe)+ = case lookupModuleEnv direct_imports mod of+ -- ezyang: I'm not sure if any is the correct+ -- metric here. If safety was guaranteed to be uniform+ -- across all imports, why did the old code only look+ -- at the first import?+ Just bys -> (True, any by_is_safe bys)+ Nothing -> (False, safeImplicitImpsReq dflags)+ -- Nothing case is for references to entities which were+ -- not directly imported (NB: the "implicit" Prelude import+ -- counts as directly imported! An entity is not directly+ -- imported if, e.g., we got a reference to it from a+ -- reexport of another module.)++ used_occs = lookupModuleEnv ent_map mod `orElse` []++ -- Making a Map here ensures that (a) we remove duplicates+ -- when we have usages on several subordinates of a single parent,+ -- and (b) that the usages emerge in a canonical order, which+ -- is why we use Map rather than OccEnv: Map works+ -- using Ord on the OccNames, which is a lexicographic ordering.+ ent_hashs :: Map OccName Fingerprint+ ent_hashs = Map.fromList (map lookup_occ used_occs)++ lookup_occ occ =+ case hash_env occ of+ Nothing -> pprPanic "mkUsage" (ppr mod <+> ppr occ <+> ppr used_names)+ Just r -> r++ depend_on_exports = is_direct_import+ {- True+ Even if we used 'import M ()', we have to register a+ usage on the export list because we are sensitive to+ changes in orphan instances/rules.+ False+ In GHC 6.8.x we always returned true, and in+ fact it recorded a dependency on *all* the+ modules underneath in the dependency tree. This+ happens to make orphans work right, but is too+ expensive: it'll read too many interface files.+ The 'isNothing maybe_iface' check above saved us+ from generating many of these usages (at least in+ one-shot mode), but that's even more bogus!+ -}
+ deSugar/DsUtils.hs view
@@ -0,0 +1,1008 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Utilities for desugaring++This module exports some utility functions of no great interest.+-}++{-# LANGUAGE CPP #-}++-- | Utility functions for constructing Core syntax, principally for desugaring+module DsUtils (+ EquationInfo(..),+ firstPat, shiftEqns,++ MatchResult(..), CanItFail(..), CaseAlt(..),+ cantFailMatchResult, alwaysFailMatchResult,+ extractMatchResult, combineMatchResults,+ adjustMatchResult, adjustMatchResultDs,+ mkCoLetMatchResult, mkViewMatchResult, mkGuardedMatchResult,+ matchCanFail, mkEvalMatchResult,+ mkCoPrimCaseMatchResult, mkCoAlgCaseMatchResult, mkCoSynCaseMatchResult,+ wrapBind, wrapBinds,++ mkErrorAppDs, mkCoreAppDs, mkCoreAppsDs, mkCastDs,++ seqVar,++ -- LHs tuples+ mkLHsVarPatTup, mkLHsPatTup, mkVanillaTuplePat,+ mkBigLHsVarTupId, mkBigLHsTupId, mkBigLHsVarPatTupId, mkBigLHsPatTupId,++ mkSelectorBinds,++ selectSimpleMatchVarL, selectMatchVars, selectMatchVar,+ mkOptTickBox, mkBinaryTickBox, decideBangHood, addBang+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} Match ( matchSimply )+import {-# SOURCE #-} DsExpr ( dsLExpr )++import HsSyn+import TcHsSyn+import TcType( tcSplitTyConApp )+import CoreSyn+import DsMonad++import CoreUtils+import MkCore+import MkId+import Id+import Literal+import TyCon+import DataCon+import PatSyn+import Type+import Coercion+import TysPrim+import TysWiredIn+import BasicTypes+import ConLike+import UniqSet+import UniqSupply+import Module+import PrelNames+import Name( isInternalName )+import Outputable+import SrcLoc+import Util+import DynFlags+import FastString+import qualified GHC.LanguageExtensions as LangExt++import TcEvidence++import Control.Monad ( zipWithM )++{-+************************************************************************+* *+\subsection{ Selecting match variables}+* *+************************************************************************++We're about to match against some patterns. We want to make some+@Ids@ to use as match variables. If a pattern has an @Id@ readily at+hand, which should indeed be bound to the pattern as a whole, then use it;+otherwise, make one up.+-}++selectSimpleMatchVarL :: LPat Id -> DsM Id+selectSimpleMatchVarL pat = selectMatchVar (unLoc pat)++-- (selectMatchVars ps tys) chooses variables of type tys+-- to use for matching ps against. If the pattern is a variable,+-- we try to use that, to save inventing lots of fresh variables.+--+-- OLD, but interesting note:+-- But even if it is a variable, its type might not match. Consider+-- data T a where+-- T1 :: Int -> T Int+-- T2 :: a -> T a+--+-- f :: T a -> a -> Int+-- f (T1 i) (x::Int) = x+-- f (T2 i) (y::a) = 0+-- Then we must not choose (x::Int) as the matching variable!+-- And nowadays we won't, because the (x::Int) will be wrapped in a CoPat++selectMatchVars :: [Pat Id] -> DsM [Id]+selectMatchVars ps = mapM selectMatchVar ps++selectMatchVar :: Pat Id -> DsM Id+selectMatchVar (BangPat pat) = selectMatchVar (unLoc pat)+selectMatchVar (LazyPat pat) = selectMatchVar (unLoc pat)+selectMatchVar (ParPat pat) = selectMatchVar (unLoc pat)+selectMatchVar (VarPat var) = return (localiseId (unLoc var))+ -- Note [Localise pattern binders]+selectMatchVar (AsPat var _) = return (unLoc var)+selectMatchVar other_pat = newSysLocalDsNoLP (hsPatType other_pat)+ -- OK, better make up one...++{-+Note [Localise pattern binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider module M where+ [Just a] = e+After renaming it looks like+ module M where+ [Just M.a] = e++We don't generalise, since it's a pattern binding, monomorphic, etc,+so after desugaring we may get something like+ M.a = case e of (v:_) ->+ case v of Just M.a -> M.a+Notice the "M.a" in the pattern; after all, it was in the original+pattern. However, after optimisation those pattern binders can become+let-binders, and then end up floated to top level. They have a+different *unique* by then (the simplifier is good about maintaining+proper scoping), but it's BAD to have two top-level bindings with the+External Name M.a, because that turns into two linker symbols for M.a.+It's quite rare for this to actually *happen* -- the only case I know+of is tc003 compiled with the 'hpc' way -- but that only makes it+all the more annoying.++To avoid this, we craftily call 'localiseId' in the desugarer, which+simply turns the External Name for the Id into an Internal one, but+doesn't change the unique. So the desugarer produces this:+ M.a{r8} = case e of (v:_) ->+ case v of Just a{r8} -> M.a{r8}+The unique is still 'r8', but the binding site in the pattern+is now an Internal Name. Now the simplifier's usual mechanisms+will propagate that Name to all the occurrence sites, as well as+un-shadowing it, so we'll get+ M.a{r8} = case e of (v:_) ->+ case v of Just a{s77} -> a{s77}+In fact, even CoreSubst.simplOptExpr will do this, and simpleOptExpr+runs on the output of the desugarer, so all is well by the end of+the desugaring pass.+++************************************************************************+* *+* type synonym EquationInfo and access functions for its pieces *+* *+************************************************************************+\subsection[EquationInfo-synonym]{@EquationInfo@: a useful synonym}++The ``equation info'' used by @match@ is relatively complicated and+worthy of a type synonym and a few handy functions.+-}++firstPat :: EquationInfo -> Pat Id+firstPat eqn = ASSERT( notNull (eqn_pats eqn) ) head (eqn_pats eqn)++shiftEqns :: [EquationInfo] -> [EquationInfo]+-- Drop the first pattern in each equation+shiftEqns eqns = [ eqn { eqn_pats = tail (eqn_pats eqn) } | eqn <- eqns ]++-- Functions on MatchResults++matchCanFail :: MatchResult -> Bool+matchCanFail (MatchResult CanFail _) = True+matchCanFail (MatchResult CantFail _) = False++alwaysFailMatchResult :: MatchResult+alwaysFailMatchResult = MatchResult CanFail (\fail -> return fail)++cantFailMatchResult :: CoreExpr -> MatchResult+cantFailMatchResult expr = MatchResult CantFail (\_ -> return expr)++extractMatchResult :: MatchResult -> CoreExpr -> DsM CoreExpr+extractMatchResult (MatchResult CantFail match_fn) _+ = match_fn (error "It can't fail!")++extractMatchResult (MatchResult CanFail match_fn) fail_expr = do+ (fail_bind, if_it_fails) <- mkFailurePair fail_expr+ body <- match_fn if_it_fails+ return (mkCoreLet fail_bind body)+++combineMatchResults :: MatchResult -> MatchResult -> MatchResult+combineMatchResults (MatchResult CanFail body_fn1)+ (MatchResult can_it_fail2 body_fn2)+ = MatchResult can_it_fail2 body_fn+ where+ body_fn fail = do body2 <- body_fn2 fail+ (fail_bind, duplicatable_expr) <- mkFailurePair body2+ body1 <- body_fn1 duplicatable_expr+ return (Let fail_bind body1)++combineMatchResults match_result1@(MatchResult CantFail _) _+ = match_result1++adjustMatchResult :: DsWrapper -> MatchResult -> MatchResult+adjustMatchResult encl_fn (MatchResult can_it_fail body_fn)+ = MatchResult can_it_fail (\fail -> encl_fn <$> body_fn fail)++adjustMatchResultDs :: (CoreExpr -> DsM CoreExpr) -> MatchResult -> MatchResult+adjustMatchResultDs encl_fn (MatchResult can_it_fail body_fn)+ = MatchResult can_it_fail (\fail -> encl_fn =<< body_fn fail)++wrapBinds :: [(Var,Var)] -> CoreExpr -> CoreExpr+wrapBinds [] e = e+wrapBinds ((new,old):prs) e = wrapBind new old (wrapBinds prs e)++wrapBind :: Var -> Var -> CoreExpr -> CoreExpr+wrapBind new old body -- NB: this function must deal with term+ | new==old = body -- variables, type variables or coercion variables+ | otherwise = Let (NonRec new (varToCoreExpr old)) body++seqVar :: Var -> CoreExpr -> CoreExpr+seqVar var body = Case (Var var) var (exprType body)+ [(DEFAULT, [], body)]++mkCoLetMatchResult :: CoreBind -> MatchResult -> MatchResult+mkCoLetMatchResult bind = adjustMatchResult (mkCoreLet bind)++-- (mkViewMatchResult var' viewExpr mr) makes the expression+-- let var' = viewExpr in mr+mkViewMatchResult :: Id -> CoreExpr -> MatchResult -> MatchResult+mkViewMatchResult var' viewExpr =+ adjustMatchResult (mkCoreLet (NonRec var' viewExpr))++mkEvalMatchResult :: Id -> Type -> MatchResult -> MatchResult+mkEvalMatchResult var ty+ = adjustMatchResult (\e -> Case (Var var) var ty [(DEFAULT, [], e)])++mkGuardedMatchResult :: CoreExpr -> MatchResult -> MatchResult+mkGuardedMatchResult pred_expr (MatchResult _ body_fn)+ = MatchResult CanFail (\fail -> do body <- body_fn fail+ return (mkIfThenElse pred_expr body fail))++mkCoPrimCaseMatchResult :: Id -- Scrutinee+ -> Type -- Type of the case+ -> [(Literal, MatchResult)] -- Alternatives+ -> MatchResult -- Literals are all unlifted+mkCoPrimCaseMatchResult var ty match_alts+ = MatchResult CanFail mk_case+ where+ mk_case fail = do+ alts <- mapM (mk_alt fail) sorted_alts+ return (Case (Var var) var ty ((DEFAULT, [], fail) : alts))++ sorted_alts = sortWith fst match_alts -- Right order for a Case+ mk_alt fail (lit, MatchResult _ body_fn)+ = ASSERT( not (litIsLifted lit) )+ do body <- body_fn fail+ return (LitAlt lit, [], body)++data CaseAlt a = MkCaseAlt{ alt_pat :: a,+ alt_bndrs :: [Var],+ alt_wrapper :: HsWrapper,+ alt_result :: MatchResult }++mkCoAlgCaseMatchResult+ :: DynFlags+ -> Id -- Scrutinee+ -> Type -- Type of exp+ -> [CaseAlt DataCon] -- Alternatives (bndrs *include* tyvars, dicts)+ -> MatchResult+mkCoAlgCaseMatchResult dflags var ty match_alts+ | isNewtype -- Newtype case; use a let+ = ASSERT( null (tail match_alts) && null (tail arg_ids1) )+ mkCoLetMatchResult (NonRec arg_id1 newtype_rhs) match_result1++ | isPArrFakeAlts match_alts+ = MatchResult CanFail $ mkPArrCase dflags var ty (sort_alts match_alts)+ | otherwise+ = mkDataConCase var ty match_alts+ where+ isNewtype = isNewTyCon (dataConTyCon (alt_pat alt1))++ -- [Interesting: because of GADTs, we can't rely on the type of+ -- the scrutinised Id to be sufficiently refined to have a TyCon in it]++ alt1@MkCaseAlt{ alt_bndrs = arg_ids1, alt_result = match_result1 }+ = ASSERT( notNull match_alts ) head match_alts+ -- Stuff for newtype+ arg_id1 = ASSERT( notNull arg_ids1 ) head arg_ids1+ var_ty = idType var+ (tc, ty_args) = tcSplitTyConApp var_ty -- Don't look through newtypes+ -- (not that splitTyConApp does, these days)+ newtype_rhs = unwrapNewTypeBody tc ty_args (Var var)++ --- Stuff for parallel arrays+ --+ -- Concerning `isPArrFakeAlts':+ --+ -- * it is *not* sufficient to just check the type of the type+ -- constructor, as we have to be careful not to confuse the real+ -- representation of parallel arrays with the fake constructors;+ -- moreover, a list of alternatives must not mix fake and real+ -- constructors (this is checked earlier on)+ --+ -- FIXME: We actually go through the whole list and make sure that+ -- either all or none of the constructors are fake parallel+ -- array constructors. This is to spot equations that mix fake+ -- constructors with the real representation defined in+ -- `PrelPArr'. It would be nicer to spot this situation+ -- earlier and raise a proper error message, but it can really+ -- only happen in `PrelPArr' anyway.+ --++ isPArrFakeAlts :: [CaseAlt DataCon] -> Bool+ isPArrFakeAlts [alt] = isPArrFakeCon (alt_pat alt)+ isPArrFakeAlts (alt:alts) =+ case (isPArrFakeCon (alt_pat alt), isPArrFakeAlts alts) of+ (True , True ) -> True+ (False, False) -> False+ _ -> panic "DsUtils: you may not mix `[:...:]' with `PArr' patterns"+ isPArrFakeAlts [] = panic "DsUtils: unexpectedly found an empty list of PArr fake alternatives"++mkCoSynCaseMatchResult :: Id -> Type -> CaseAlt PatSyn -> MatchResult+mkCoSynCaseMatchResult var ty alt = MatchResult CanFail $ mkPatSynCase var ty alt++sort_alts :: [CaseAlt DataCon] -> [CaseAlt DataCon]+sort_alts = sortWith (dataConTag . alt_pat)++mkPatSynCase :: Id -> Type -> CaseAlt PatSyn -> CoreExpr -> DsM CoreExpr+mkPatSynCase var ty alt fail = do+ matcher <- dsLExpr $ mkLHsWrap wrapper $+ nlHsTyApp matcher [getRuntimeRep "mkPatSynCase" ty, ty]+ let MatchResult _ mkCont = match_result+ cont <- mkCoreLams bndrs <$> mkCont fail+ return $ mkCoreAppsDs (text "patsyn" <+> ppr var) matcher [Var var, ensure_unstrict cont, Lam voidArgId fail]+ where+ MkCaseAlt{ alt_pat = psyn,+ alt_bndrs = bndrs,+ alt_wrapper = wrapper,+ alt_result = match_result} = alt+ (matcher, needs_void_lam) = patSynMatcher psyn++ -- See Note [Matchers and builders for pattern synonyms] in PatSyns+ -- on these extra Void# arguments+ ensure_unstrict cont | needs_void_lam = Lam voidArgId cont+ | otherwise = cont++mkDataConCase :: Id -> Type -> [CaseAlt DataCon] -> MatchResult+mkDataConCase _ _ [] = panic "mkDataConCase: no alternatives"+mkDataConCase var ty alts@(alt1:_) = MatchResult fail_flag mk_case+ where+ con1 = alt_pat alt1+ tycon = dataConTyCon con1+ data_cons = tyConDataCons tycon+ match_results = map alt_result alts++ sorted_alts :: [CaseAlt DataCon]+ sorted_alts = sort_alts alts++ var_ty = idType var+ (_, ty_args) = tcSplitTyConApp var_ty -- Don't look through newtypes+ -- (not that splitTyConApp does, these days)++ mk_case :: CoreExpr -> DsM CoreExpr+ mk_case fail = do+ alts <- mapM (mk_alt fail) sorted_alts+ return $ mkWildCase (Var var) (idType var) ty (mk_default fail ++ alts)++ mk_alt :: CoreExpr -> CaseAlt DataCon -> DsM CoreAlt+ mk_alt fail MkCaseAlt{ alt_pat = con,+ alt_bndrs = args,+ alt_result = MatchResult _ body_fn }+ = do { body <- body_fn fail+ ; case dataConBoxer con of {+ Nothing -> return (DataAlt con, args, body) ;+ Just (DCB boxer) ->+ do { us <- newUniqueSupply+ ; let (rep_ids, binds) = initUs_ us (boxer ty_args args)+ ; return (DataAlt con, rep_ids, mkLets binds body) } } }++ mk_default :: CoreExpr -> [CoreAlt]+ mk_default fail | exhaustive_case = []+ | otherwise = [(DEFAULT, [], fail)]++ fail_flag :: CanItFail+ fail_flag | exhaustive_case+ = foldr orFail CantFail [can_it_fail | MatchResult can_it_fail _ <- match_results]+ | otherwise+ = CanFail++ mentioned_constructors = mkUniqSet $ map alt_pat alts+ un_mentioned_constructors+ = mkUniqSet data_cons `minusUniqSet` mentioned_constructors+ exhaustive_case = isEmptyUniqSet un_mentioned_constructors++--- Stuff for parallel arrays+--+-- * the following is to desugar cases over fake constructors for+-- parallel arrays, which are introduced by `tidy1' in the `PArrPat'+-- case+--+mkPArrCase :: DynFlags -> Id -> Type -> [CaseAlt DataCon] -> CoreExpr -> DsM CoreExpr+mkPArrCase dflags var ty sorted_alts fail = do+ lengthP <- dsDPHBuiltin lengthPVar+ alt <- unboxAlt+ return (mkWildCase (len lengthP) intTy ty [alt])+ where+ elemTy = case splitTyConApp (idType var) of+ (_, [elemTy]) -> elemTy+ _ -> panic panicMsg+ panicMsg = "DsUtils.mkCoAlgCaseMatchResult: not a parallel array?"+ len lengthP = mkApps (Var lengthP) [Type elemTy, Var var]+ --+ unboxAlt = do+ l <- newSysLocalDs intPrimTy+ indexP <- dsDPHBuiltin indexPVar+ alts <- mapM (mkAlt indexP) sorted_alts+ return (DataAlt intDataCon, [l], mkWildCase (Var l) intPrimTy ty (dft : alts))+ where+ dft = (DEFAULT, [], fail)++ --+ -- each alternative matches one array length (corresponding to one+ -- fake array constructor), so the match is on a literal; each+ -- alternative's body is extended by a local binding for each+ -- constructor argument, which are bound to array elements starting+ -- with the first+ --+ mkAlt indexP alt@MkCaseAlt{alt_result = MatchResult _ bodyFun} = do+ body <- bodyFun fail+ return (LitAlt lit, [], mkCoreLets binds body)+ where+ lit = MachInt $ toInteger (dataConSourceArity (alt_pat alt))+ binds = [NonRec arg (indexExpr i) | (i, arg) <- zip [1..] (alt_bndrs alt)]+ --+ indexExpr i = mkApps (Var indexP) [Type elemTy, Var var, mkIntExpr dflags i]++{-+************************************************************************+* *+\subsection{Desugarer's versions of some Core functions}+* *+************************************************************************+-}++mkErrorAppDs :: Id -- The error function+ -> Type -- Type to which it should be applied+ -> SDoc -- The error message string to pass+ -> DsM CoreExpr++mkErrorAppDs err_id ty msg = do+ src_loc <- getSrcSpanDs+ dflags <- getDynFlags+ let+ full_msg = showSDoc dflags (hcat [ppr src_loc, vbar, msg])+ core_msg = Lit (mkMachString full_msg)+ -- mkMachString returns a result of type String#+ return (mkApps (Var err_id) [Type (getRuntimeRep "mkErrorAppDs" ty), Type ty, core_msg])++{-+'mkCoreAppDs' and 'mkCoreAppsDs' hand the special-case desugaring of 'seq'.++Note [Desugaring seq (1)] cf Trac #1031+~~~~~~~~~~~~~~~~~~~~~~~~~+ f x y = x `seq` (y `seq` (# x,y #))++The [CoreSyn let/app invariant] means that, other things being equal, because+the argument to the outer 'seq' has an unlifted type, we'll use call-by-value thus:++ f x y = case (y `seq` (# x,y #)) of v -> x `seq` v++But that is bad for two reasons:+ (a) we now evaluate y before x, and+ (b) we can't bind v to an unboxed pair++Seq is very, very special! So we recognise it right here, and desugar to+ case x of _ -> case y of _ -> (# x,y #)++Note [Desugaring seq (2)] cf Trac #2273+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ let chp = case b of { True -> fst x; False -> 0 }+ in chp `seq` ...chp...+Here the seq is designed to plug the space leak of retaining (snd x)+for too long.++If we rely on the ordinary inlining of seq, we'll get+ let chp = case b of { True -> fst x; False -> 0 }+ case chp of _ { I# -> ...chp... }++But since chp is cheap, and the case is an alluring contet, we'll+inline chp into the case scrutinee. Now there is only one use of chp,+so we'll inline a second copy. Alas, we've now ruined the purpose of+the seq, by re-introducing the space leak:+ case (case b of {True -> fst x; False -> 0}) of+ I# _ -> ...case b of {True -> fst x; False -> 0}...++We can try to avoid doing this by ensuring that the binder-swap in the+case happens, so we get his at an early stage:+ case chp of chp2 { I# -> ...chp2... }+But this is fragile. The real culprit is the source program. Perhaps we+should have said explicitly+ let !chp2 = chp in ...chp2...++But that's painful. So the code here does a little hack to make seq+more robust: a saturated application of 'seq' is turned *directly* into+the case expression, thus:+ x `seq` e2 ==> case x of x -> e2 -- Note shadowing!+ e1 `seq` e2 ==> case x of _ -> e2++So we desugar our example to:+ let chp = case b of { True -> fst x; False -> 0 }+ case chp of chp { I# -> ...chp... }+And now all is well.++The reason it's a hack is because if you define mySeq=seq, the hack+won't work on mySeq.++Note [Desugaring seq (3)] cf Trac #2409+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The isLocalId ensures that we don't turn+ True `seq` e+into+ case True of True { ... }+which stupidly tries to bind the datacon 'True'.+-}++-- NB: Make sure the argument is not levity polymorphic+mkCoreAppDs :: SDoc -> CoreExpr -> CoreExpr -> CoreExpr+mkCoreAppDs _ (Var f `App` Type ty1 `App` Type ty2 `App` arg1) arg2+ | f `hasKey` seqIdKey -- Note [Desugaring seq (1), (2)]+ = Case arg1 case_bndr ty2 [(DEFAULT,[],arg2)]+ where+ case_bndr = case arg1 of+ Var v1 | isInternalName (idName v1)+ -> v1 -- Note [Desugaring seq (2) and (3)]+ _ -> mkWildValBinder ty1++mkCoreAppDs s fun arg = mkCoreApp s fun arg -- The rest is done in MkCore++-- NB: No argument can be levity polymorphic+mkCoreAppsDs :: SDoc -> CoreExpr -> [CoreExpr] -> CoreExpr+mkCoreAppsDs s fun args = foldl (mkCoreAppDs s) fun args++mkCastDs :: CoreExpr -> Coercion -> CoreExpr+-- We define a desugarer-specific version of CoreUtils.mkCast,+-- because in the immediate output of the desugarer, we can have+-- apparently-mis-matched coercions: E.g.+-- let a = b+-- in (x :: a) |> (co :: b ~ Int)+-- Lint know about type-bindings for let and does not complain+-- So here we do not make the assertion checks that we make in+-- CoreUtils.mkCast; and we do less peephole optimisation too+mkCastDs e co | isReflCo co = e+ | otherwise = Cast e co++{-+************************************************************************+* *+ Tuples and selector bindings+* *+************************************************************************++This is used in various places to do with lazy patterns.+For each binder $b$ in the pattern, we create a binding:+\begin{verbatim}+ b = case v of pat' -> b'+\end{verbatim}+where @pat'@ is @pat@ with each binder @b@ cloned into @b'@.++ToDo: making these bindings should really depend on whether there's+much work to be done per binding. If the pattern is complex, it+should be de-mangled once, into a tuple (and then selected from).+Otherwise the demangling can be in-line in the bindings (as here).++Boring! Boring! One error message per binder. The above ToDo is+even more helpful. Something very similar happens for pattern-bound+expressions.++Note [mkSelectorBinds]+~~~~~~~~~~~~~~~~~~~~~~+mkSelectorBinds is used to desugar a pattern binding {p = e},+in a binding group:+ let { ...; p = e; ... } in body+where p binds x,y (this list of binders can be empty).+There are two cases.++------ Special case (A) -------+ For a pattern that is just a variable,+ let !x = e in body+ ==>+ let x = e in x `seq` body+ So we return the binding, with 'x' as the variable to seq.++------ Special case (B) -------+ For a pattern that is essentially just a tuple:+ * A product type, so cannot fail+ * Only one level, so that+ - generating multiple matches is fine+ - seq'ing it evaluates the same as matching it+ Then instead we generate+ { v = e+ ; x = case v of p -> x+ ; y = case v of p -> y }+ with 'v' as the variable to force++------ General case (C) -------+ In the general case we generate these bindings:+ let { ...; p = e; ... } in body+ ==>+ let { t = case e of p -> (x,y)+ ; x = case t of (x,y) -> x+ ; y = case t of (x,y) -> y }+ in t `seq` body++ Note that we return 't' as the variable to force if the pattern+ is strict (i.e. with -XStrict or an outermost-bang-pattern)++ Note that (A) /includes/ the situation where++ * The pattern binds exactly one variable+ let !(Just (Just x) = e in body+ ==>+ let { t = case e of Just (Just v) -> Unit v+ ; v = case t of Unit v -> v }+ in t `seq` body+ The 'Unit' is a one-tuple; see Note [One-tuples] in TysWiredIn+ Note that forcing 't' makes the pattern match happen,+ but does not force 'v'.++ * The pattern binds no variables+ let !(True,False) = e in body+ ==>+ let t = case e of (True,False) -> ()+ in t `seq` body+++------ Examples ----------+ * !(_, (_, a)) = e+ ==>+ t = case e of (_, (_, a)) -> Unit a+ a = case t of Unit a -> a++ Note that+ - Forcing 't' will force the pattern to match fully;+ e.g. will diverge if (snd e) is bottom+ - But 'a' itself is not forced; it is wrapped in a one-tuple+ (see Note [One-tuples] in TysWiredIn)++ * !(Just x) = e+ ==>+ t = case e of Just x -> Unit x+ x = case t of Unit x -> x++ Again, forcing 't' will fail if 'e' yields Nothing.++Note that even though this is rather general, the special cases+work out well:++* One binder, not -XStrict:++ let Just (Just v) = e in body+ ==>+ let t = case e of Just (Just v) -> Unit v+ v = case t of Unit v -> v+ in body+ ==>+ let v = case (case e of Just (Just v) -> Unit v) of+ Unit v -> v+ in body+ ==>+ let v = case e of Just (Just v) -> v+ in body++* Non-recursive, -XStrict+ let p = e in body+ ==>+ let { t = case e of p -> (x,y)+ ; x = case t of (x,y) -> x+ ; y = case t of (x,y) -> x }+ in t `seq` body+ ==> {inline seq, float x,y bindings inwards}+ let t = case e of p -> (x,y) in+ case t of t' ->+ let { x = case t' of (x,y) -> x+ ; y = case t' of (x,y) -> x } in+ body+ ==> {inline t, do case of case}+ case e of p ->+ let t = (x,y) in+ let { x = case t' of (x,y) -> x+ ; y = case t' of (x,y) -> x } in+ body+ ==> {case-cancellation, drop dead code}+ case e of p -> body++* Special case (B) is there to avoid fruitlessly taking the tuple+ apart and rebuilding it. For example, consider+ { K x y = e }+ where K is a product constructor. Then general case (A) does:+ { t = case e of K x y -> (x,y)+ ; x = case t of (x,y) -> x+ ; y = case t of (x,y) -> y }+ In the lazy case we can't optimise out this fruitless taking apart+ and rebuilding. Instead (B) builds+ { v = e+ ; x = case v of K x y -> x+ ; y = case v of K x y -> y }+ which is better.+-}++mkSelectorBinds :: [[Tickish Id]] -- ^ ticks to add, possibly+ -> LPat Id -- ^ The pattern+ -> CoreExpr -- ^ Expression to which the pattern is bound+ -> DsM (Id,[(Id,CoreExpr)])+ -- ^ Id the rhs is bound to, for desugaring strict+ -- binds (see Note [Desugar Strict binds] in DsBinds)+ -- and all the desugared binds++mkSelectorBinds ticks pat val_expr+ | L _ (VarPat (L _ v)) <- pat' -- Special case (A)+ = return (v, [(v, val_expr)])++ | is_flat_prod_lpat pat' -- Special case (B)+ = do { let pat_ty = hsLPatType pat'+ ; val_var <- newSysLocalDsNoLP pat_ty++ ; let mk_bind tick bndr_var+ -- (mk_bind sv bv) generates bv = case sv of { pat -> bv }+ -- Remember, 'pat' binds 'bv'+ = do { rhs_expr <- matchSimply (Var val_var) PatBindRhs pat'+ (Var bndr_var)+ (Var bndr_var) -- Neat hack+ -- Neat hack: since 'pat' can't fail, the+ -- "fail-expr" passed to matchSimply is not+ -- used. But it /is/ used for its type, and for+ -- that bndr_var is just the ticket.+ ; return (bndr_var, mkOptTickBox tick rhs_expr) }++ ; binds <- zipWithM mk_bind ticks' binders+ ; return ( val_var, (val_var, val_expr) : binds) }++ | otherwise -- General case (C)+ = do { tuple_var <- newSysLocalDs tuple_ty+ ; error_expr <- mkErrorAppDs iRREFUT_PAT_ERROR_ID tuple_ty (ppr pat')+ ; tuple_expr <- matchSimply val_expr PatBindRhs pat+ local_tuple error_expr+ ; let mk_tup_bind tick binder+ = (binder, mkOptTickBox tick $+ mkTupleSelector1 local_binders binder+ tuple_var (Var tuple_var))+ tup_binds = zipWith mk_tup_bind ticks' binders+ ; return (tuple_var, (tuple_var, tuple_expr) : tup_binds) }+ where+ pat' = strip_bangs pat+ -- Strip the bangs before looking for case (A) or (B)+ -- The incoming pattern may well have a bang on it++ binders = collectPatBinders pat'+ ticks' = ticks ++ repeat []++ local_binders = map localiseId binders -- See Note [Localise pattern binders]+ local_tuple = mkBigCoreVarTup1 binders+ tuple_ty = exprType local_tuple++strip_bangs :: LPat a -> LPat a+-- Remove outermost bangs and parens+strip_bangs (L _ (ParPat p)) = strip_bangs p+strip_bangs (L _ (BangPat p)) = strip_bangs p+strip_bangs lp = lp++is_flat_prod_lpat :: LPat a -> Bool+is_flat_prod_lpat p = is_flat_prod_pat (unLoc p)++is_flat_prod_pat :: Pat a -> Bool+is_flat_prod_pat (ParPat p) = is_flat_prod_lpat p+is_flat_prod_pat (TuplePat ps Boxed _) = all is_triv_lpat ps+is_flat_prod_pat (ConPatOut { pat_con = L _ pcon, pat_args = ps})+ | RealDataCon con <- pcon+ , isProductTyCon (dataConTyCon con)+ = all is_triv_lpat (hsConPatArgs ps)+is_flat_prod_pat _ = False++is_triv_lpat :: LPat a -> Bool+is_triv_lpat p = is_triv_pat (unLoc p)++is_triv_pat :: Pat a -> Bool+is_triv_pat (VarPat _) = True+is_triv_pat (WildPat _) = True+is_triv_pat (ParPat p) = is_triv_lpat p+is_triv_pat _ = False+++{- *********************************************************************+* *+ Creating big tuples and their types for full Haskell expressions.+ They work over *Ids*, and create tuples replete with their types,+ which is whey they are not in HsUtils.+* *+********************************************************************* -}++mkLHsPatTup :: [LPat Id] -> LPat Id+mkLHsPatTup [] = noLoc $ mkVanillaTuplePat [] Boxed+mkLHsPatTup [lpat] = lpat+mkLHsPatTup lpats = L (getLoc (head lpats)) $+ mkVanillaTuplePat lpats Boxed++mkLHsVarPatTup :: [Id] -> LPat Id+mkLHsVarPatTup bs = mkLHsPatTup (map nlVarPat bs)++mkVanillaTuplePat :: [OutPat Id] -> Boxity -> Pat Id+-- A vanilla tuple pattern simply gets its type from its sub-patterns+mkVanillaTuplePat pats box = TuplePat pats box (map hsLPatType pats)++-- The Big equivalents for the source tuple expressions+mkBigLHsVarTupId :: [Id] -> LHsExpr Id+mkBigLHsVarTupId ids = mkBigLHsTupId (map nlHsVar ids)++mkBigLHsTupId :: [LHsExpr Id] -> LHsExpr Id+mkBigLHsTupId = mkChunkified mkLHsTupleExpr++-- The Big equivalents for the source tuple patterns+mkBigLHsVarPatTupId :: [Id] -> LPat Id+mkBigLHsVarPatTupId bs = mkBigLHsPatTupId (map nlVarPat bs)++mkBigLHsPatTupId :: [LPat Id] -> LPat Id+mkBigLHsPatTupId = mkChunkified mkLHsPatTup++{-+************************************************************************+* *+ Code for pattern-matching and other failures+* *+************************************************************************++Generally, we handle pattern matching failure like this: let-bind a+fail-variable, and use that variable if the thing fails:+\begin{verbatim}+ let fail.33 = error "Help"+ in+ case x of+ p1 -> ...+ p2 -> fail.33+ p3 -> fail.33+ p4 -> ...+\end{verbatim}+Then+\begin{itemize}+\item+If the case can't fail, then there'll be no mention of @fail.33@, and the+simplifier will later discard it.++\item+If it can fail in only one way, then the simplifier will inline it.++\item+Only if it is used more than once will the let-binding remain.+\end{itemize}++There's a problem when the result of the case expression is of+unboxed type. Then the type of @fail.33@ is unboxed too, and+there is every chance that someone will change the let into a case:+\begin{verbatim}+ case error "Help" of+ fail.33 -> case ....+\end{verbatim}++which is of course utterly wrong. Rather than drop the condition that+only boxed types can be let-bound, we just turn the fail into a function+for the primitive case:+\begin{verbatim}+ let fail.33 :: Void -> Int#+ fail.33 = \_ -> error "Help"+ in+ case x of+ p1 -> ...+ p2 -> fail.33 void+ p3 -> fail.33 void+ p4 -> ...+\end{verbatim}++Now @fail.33@ is a function, so it can be let-bound.++We would *like* to use join points here; in fact, these "fail variables" are+paradigmatic join points! Sadly, this breaks pattern synonyms, which desugar as+CPS functions - i.e. they take "join points" as parameters. It's not impossible+to imagine extending our type system to allow passing join points around (very+carefully), but we certainly don't support it now.++99.99% of the time, the fail variables wind up as join points in short order+anyway, and the Void# doesn't do much harm.+-}++mkFailurePair :: CoreExpr -- Result type of the whole case expression+ -> DsM (CoreBind, -- Binds the newly-created fail variable+ -- to \ _ -> expression+ CoreExpr) -- Fail variable applied to realWorld#+-- See Note [Failure thunks and CPR]+mkFailurePair expr+ = do { fail_fun_var <- newFailLocalDs (voidPrimTy `mkFunTy` ty)+ ; fail_fun_arg <- newSysLocalDs voidPrimTy+ ; let real_arg = setOneShotLambda fail_fun_arg+ ; return (NonRec fail_fun_var (Lam real_arg expr),+ App (Var fail_fun_var) (Var voidPrimId)) }+ where+ ty = exprType expr++{-+Note [Failure thunks and CPR]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(This note predates join points as formal entities (hence the quotation marks).+We can't use actual join points here (see above); if we did, this would also+solve the CPR problem, since join points don't get CPR'd. See Note [Don't CPR+join points] in WorkWrap.)++When we make a failure point we ensure that it+does not look like a thunk. Example:++ let fail = \rw -> error "urk"+ in case x of+ [] -> fail realWorld#+ (y:ys) -> case ys of+ [] -> fail realWorld#+ (z:zs) -> (y,z)++Reason: we know that a failure point is always a "join point" and is+entered at most once. Adding a dummy 'realWorld' token argument makes+it clear that sharing is not an issue. And that in turn makes it more+CPR-friendly. This matters a lot: if you don't get it right, you lose+the tail call property. For example, see Trac #3403.+++************************************************************************+* *+ Ticks+* *+********************************************************************* -}++mkOptTickBox :: [Tickish Id] -> CoreExpr -> CoreExpr+mkOptTickBox = flip (foldr Tick)++mkBinaryTickBox :: Int -> Int -> CoreExpr -> DsM CoreExpr+mkBinaryTickBox ixT ixF e = do+ uq <- newUnique+ this_mod <- getModule+ let bndr1 = mkSysLocal (fsLit "t1") uq boolTy+ let+ falseBox = Tick (HpcTick this_mod ixF) (Var falseDataConId)+ trueBox = Tick (HpcTick this_mod ixT) (Var trueDataConId)+ --+ return $ Case e bndr1 boolTy+ [ (DataAlt falseDataCon, [], falseBox)+ , (DataAlt trueDataCon, [], trueBox)+ ]++++-- *******************************************************************++-- | Use -XStrict to add a ! or remove a ~+--+-- Examples:+-- ~pat => pat -- when -XStrict (even if pat = ~pat')+-- !pat => !pat -- always+-- pat => !pat -- when -XStrict+-- pat => pat -- otherwise+decideBangHood :: DynFlags+ -> LPat id -- ^ Original pattern+ -> LPat id -- Pattern with bang if necessary+decideBangHood dflags lpat+ | not (xopt LangExt.Strict dflags)+ = lpat+ | otherwise -- -XStrict+ = go lpat+ where+ go lp@(L l p)+ = case p of+ ParPat p -> L l (ParPat (go p))+ LazyPat lp' -> lp'+ BangPat _ -> lp+ _ -> L l (BangPat lp)++-- | Unconditionally make a 'Pat' strict.+addBang :: LPat id -- ^ Original pattern+ -> LPat id -- ^ Banged pattern+addBang = go+ where+ go lp@(L l p)+ = case p of+ ParPat p -> L l (ParPat (go p))+ LazyPat lp' -> L l (BangPat lp')+ BangPat _ -> lp+ _ -> L l (BangPat lp)
+ deSugar/Match.hs view
@@ -0,0 +1,1135 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++The @match@ function+-}++{-# LANGUAGE CPP #-}++module Match ( match, matchEquations, matchWrapper, matchSimply, matchSinglePat ) where++#include "HsVersions.h"++import {-#SOURCE#-} DsExpr (dsLExpr, dsSyntaxExpr)++import DynFlags+import HsSyn+import TcHsSyn+import TcEvidence+import TcRnMonad+import Check+import CoreSyn+import Literal+import CoreUtils+import MkCore+import DsMonad+import DsBinds+import DsGRHSs+import DsUtils+import Id+import ConLike+import DataCon+import PatSyn+import MatchCon+import MatchLit+import Type+import Coercion ( eqCoercion )+import TcType ( toTcTypeBag )+import TyCon( isNewTyCon )+import TysWiredIn+import ListSetOps+import SrcLoc+import Maybes+import Util+import Name+import Outputable+import BasicTypes ( isGenerated, fl_value )+import FastString+import Unique+import UniqDFM++import Control.Monad( when, unless )+import qualified Data.Map as Map++{-+************************************************************************+* *+ The main matching function+* *+************************************************************************++The function @match@ is basically the same as in the Wadler chapter,+except it is monadised, to carry around the name supply, info about+annotations, etc.++Notes on @match@'s arguments, assuming $m$ equations and $n$ patterns:+\begin{enumerate}+\item+A list of $n$ variable names, those variables presumably bound to the+$n$ expressions being matched against the $n$ patterns. Using the+list of $n$ expressions as the first argument showed no benefit and+some inelegance.++\item+The second argument, a list giving the ``equation info'' for each of+the $m$ equations:+\begin{itemize}+\item+the $n$ patterns for that equation, and+\item+a list of Core bindings [@(Id, CoreExpr)@ pairs] to be ``stuck on+the front'' of the matching code, as in:+\begin{verbatim}+let <binds>+in <matching-code>+\end{verbatim}+\item+and finally: (ToDo: fill in)++The right way to think about the ``after-match function'' is that it+is an embryonic @CoreExpr@ with a ``hole'' at the end for the+final ``else expression''.+\end{itemize}++There is a data type, @EquationInfo@, defined in module @DsMonad@.++An experiment with re-ordering this information about equations (in+particular, having the patterns available in column-major order)+showed no benefit.++\item+A default expression---what to evaluate if the overall pattern-match+fails. This expression will (almost?) always be+a measly expression @Var@, unless we know it will only be used once+(as we do in @glue_success_exprs@).++Leaving out this third argument to @match@ (and slamming in lots of+@Var "fail"@s) is a positively {\em bad} idea, because it makes it+impossible to share the default expressions. (Also, it stands no+chance of working in our post-upheaval world of @Locals@.)+\end{enumerate}++Note: @match@ is often called via @matchWrapper@ (end of this module),+a function that does much of the house-keeping that goes with a call+to @match@.++It is also worth mentioning the {\em typical} way a block of equations+is desugared with @match@. At each stage, it is the first column of+patterns that is examined. The steps carried out are roughly:+\begin{enumerate}+\item+Tidy the patterns in column~1 with @tidyEqnInfo@ (this may add+bindings to the second component of the equation-info):+\begin{itemize}+\item+Remove the `as' patterns from column~1.+\item+Make all constructor patterns in column~1 into @ConPats@, notably+@ListPats@ and @TuplePats@.+\item+Handle any irrefutable (or ``twiddle'') @LazyPats@.+\end{itemize}+\item+Now {\em unmix} the equations into {\em blocks} [w\/ local function+@unmix_eqns@], in which the equations in a block all have variable+patterns in column~1, or they all have constructor patterns in ...+(see ``the mixture rule'' in SLPJ).+\item+Call @matchEqnBlock@ on each block of equations; it will do the+appropriate thing for each kind of column-1 pattern, usually ending up+in a recursive call to @match@.+\end{enumerate}++We are a little more paranoid about the ``empty rule'' (SLPJ, p.~87)+than the Wadler-chapter code for @match@ (p.~93, first @match@ clause).+And gluing the ``success expressions'' together isn't quite so pretty.++This (more interesting) clause of @match@ uses @tidy_and_unmix_eqns@+(a)~to get `as'- and `twiddle'-patterns out of the way (tidying), and+(b)~to do ``the mixture rule'' (SLPJ, p.~88) [which really {\em+un}mixes the equations], producing a list of equation-info+blocks, each block having as its first column of patterns either all+constructors, or all variables (or similar beasts), etc.++@match_unmixed_eqn_blks@ simply takes the place of the @foldr@ in the+Wadler-chapter @match@ (p.~93, last clause), and @match_unmixed_blk@+corresponds roughly to @matchVarCon@.++Note [Match Ids]+~~~~~~~~~~~~~~~~+Most of the matching fuctions take an Id or [Id] as argument. This Id+is the scrutinee(s) of the match. The desugared expression may+sometimes use that Id in a local binding or as a case binder. So it+should not have an External name; Lint rejects non-top-level binders+with External names (Trac #13043).+-}++type MatchId = Id -- See Note [Match Ids]++match :: [MatchId] -- Variables rep\'ing the exprs we\'re matching with+ -- See Note [Match Ids]+ -> Type -- Type of the case expression+ -> [EquationInfo] -- Info about patterns, etc. (type synonym below)+ -> DsM MatchResult -- Desugared result!++match [] ty eqns+ = ASSERT2( not (null eqns), ppr ty )+ return (foldr1 combineMatchResults match_results)+ where+ match_results = [ ASSERT( null (eqn_pats eqn) )+ eqn_rhs eqn+ | eqn <- eqns ]++match vars@(v:_) ty eqns -- Eqns *can* be empty+ = ASSERT2( all (isInternalName . idName) vars, ppr vars )+ do { dflags <- getDynFlags+ -- Tidy the first pattern, generating+ -- auxiliary bindings if necessary+ ; (aux_binds, tidy_eqns) <- mapAndUnzipM (tidyEqnInfo v) eqns++ -- Group the equations and match each group in turn+ ; let grouped = groupEquations dflags tidy_eqns++ -- print the view patterns that are commoned up to help debug+ ; whenDOptM Opt_D_dump_view_pattern_commoning (debug grouped)++ ; match_results <- match_groups grouped+ ; return (adjustMatchResult (foldr (.) id aux_binds) $+ foldr1 combineMatchResults match_results) }+ where+ dropGroup :: [(PatGroup,EquationInfo)] -> [EquationInfo]+ dropGroup = map snd++ match_groups :: [[(PatGroup,EquationInfo)]] -> DsM [MatchResult]+ -- Result list of [MatchResult] is always non-empty+ match_groups [] = matchEmpty v ty+ match_groups gs = mapM match_group gs++ match_group :: [(PatGroup,EquationInfo)] -> DsM MatchResult+ match_group [] = panic "match_group"+ match_group eqns@((group,_) : _)+ = case group of+ PgCon {} -> matchConFamily vars ty (subGroupUniq [(c,e) | (PgCon c, e) <- eqns])+ PgSyn {} -> matchPatSyn vars ty (dropGroup eqns)+ PgLit {} -> matchLiterals vars ty (subGroupOrd [(l,e) | (PgLit l, e) <- eqns])+ PgAny -> matchVariables vars ty (dropGroup eqns)+ PgN {} -> matchNPats vars ty (dropGroup eqns)+ PgOverS {}-> matchNPats vars ty (dropGroup eqns)+ PgNpK {} -> matchNPlusKPats vars ty (dropGroup eqns)+ PgBang -> matchBangs vars ty (dropGroup eqns)+ PgCo {} -> matchCoercion vars ty (dropGroup eqns)+ PgView {} -> matchView vars ty (dropGroup eqns)+ PgOverloadedList -> matchOverloadedList vars ty (dropGroup eqns)++ -- FIXME: we should also warn about view patterns that should be+ -- commoned up but are not++ -- print some stuff to see what's getting grouped+ -- use -dppr-debug to see the resolution of overloaded literals+ debug eqns =+ let gs = map (\group -> foldr (\ (p,_) -> \acc ->+ case p of PgView e _ -> e:acc+ _ -> acc) [] group) eqns+ maybeWarn [] = return ()+ maybeWarn l = warnDs NoReason (vcat l)+ in+ maybeWarn $ (map (\g -> text "Putting these view expressions into the same case:" <+> (ppr g))+ (filter (not . null) gs))++matchEmpty :: MatchId -> Type -> DsM [MatchResult]+-- See Note [Empty case expressions]+matchEmpty var res_ty+ = return [MatchResult CanFail mk_seq]+ where+ mk_seq fail = return $ mkWildCase (Var var) (idType var) res_ty+ [(DEFAULT, [], fail)]++matchVariables :: [MatchId] -> Type -> [EquationInfo] -> DsM MatchResult+-- Real true variables, just like in matchVar, SLPJ p 94+-- No binding to do: they'll all be wildcards by now (done in tidy)+matchVariables (_:vars) ty eqns = match vars ty (shiftEqns eqns)+matchVariables [] _ _ = panic "matchVariables"++matchBangs :: [MatchId] -> Type -> [EquationInfo] -> DsM MatchResult+matchBangs (var:vars) ty eqns+ = do { match_result <- match (var:vars) ty $+ map (decomposeFirstPat getBangPat) eqns+ ; return (mkEvalMatchResult var ty match_result) }+matchBangs [] _ _ = panic "matchBangs"++matchCoercion :: [MatchId] -> Type -> [EquationInfo] -> DsM MatchResult+-- Apply the coercion to the match variable and then match that+matchCoercion (var:vars) ty (eqns@(eqn1:_))+ = do { let CoPat co pat _ = firstPat eqn1+ ; let pat_ty' = hsPatType pat+ ; var' <- newUniqueId var pat_ty'+ ; match_result <- match (var':vars) ty $+ map (decomposeFirstPat getCoPat) eqns+ ; core_wrap <- dsHsWrapper co+ ; let bind = NonRec var' (core_wrap (Var var))+ ; return (mkCoLetMatchResult bind match_result) }+matchCoercion _ _ _ = panic "matchCoercion"++matchView :: [MatchId] -> Type -> [EquationInfo] -> DsM MatchResult+-- Apply the view function to the match variable and then match that+matchView (var:vars) ty (eqns@(eqn1:_))+ = do { -- we could pass in the expr from the PgView,+ -- but this needs to extract the pat anyway+ -- to figure out the type of the fresh variable+ let ViewPat viewExpr (L _ pat) _ = firstPat eqn1+ -- do the rest of the compilation+ ; let pat_ty' = hsPatType pat+ ; var' <- newUniqueId var pat_ty'+ ; match_result <- match (var':vars) ty $+ map (decomposeFirstPat getViewPat) eqns+ -- compile the view expressions+ ; viewExpr' <- dsLExpr viewExpr+ ; return (mkViewMatchResult var'+ (mkCoreAppDs (text "matchView") viewExpr' (Var var))+ match_result) }+matchView _ _ _ = panic "matchView"++matchOverloadedList :: [MatchId] -> Type -> [EquationInfo] -> DsM MatchResult+matchOverloadedList (var:vars) ty (eqns@(eqn1:_))+-- Since overloaded list patterns are treated as view patterns,+-- the code is roughly the same as for matchView+ = do { let ListPat _ elt_ty (Just (_,e)) = firstPat eqn1+ ; var' <- newUniqueId var (mkListTy elt_ty) -- we construct the overall type by hand+ ; match_result <- match (var':vars) ty $+ map (decomposeFirstPat getOLPat) eqns -- getOLPat builds the pattern inside as a non-overloaded version of the overloaded list pattern+ ; e' <- dsSyntaxExpr e [Var var]+ ; return (mkViewMatchResult var' e' match_result) }+matchOverloadedList _ _ _ = panic "matchOverloadedList"++-- decompose the first pattern and leave the rest alone+decomposeFirstPat :: (Pat Id -> Pat Id) -> EquationInfo -> EquationInfo+decomposeFirstPat extractpat (eqn@(EqnInfo { eqn_pats = pat : pats }))+ = eqn { eqn_pats = extractpat pat : pats}+decomposeFirstPat _ _ = panic "decomposeFirstPat"++getCoPat, getBangPat, getViewPat, getOLPat :: Pat Id -> Pat Id+getCoPat (CoPat _ pat _) = pat+getCoPat _ = panic "getCoPat"+getBangPat (BangPat pat ) = unLoc pat+getBangPat _ = panic "getBangPat"+getViewPat (ViewPat _ pat _) = unLoc pat+getViewPat _ = panic "getViewPat"+getOLPat (ListPat pats ty (Just _)) = ListPat pats ty Nothing+getOLPat _ = panic "getOLPat"++{-+Note [Empty case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The list of EquationInfo can be empty, arising from+ case x of {} or \case {}+In that situation we desugar to+ case x of { _ -> error "pattern match failure" }+The *desugarer* isn't certain whether there really should be no+alternatives, so it adds a default case, as it always does. A later+pass may remove it if it's inaccessible. (See also Note [Empty case+alternatives] in CoreSyn.)++We do *not* desugar simply to+ error "empty case"+or some such, because 'x' might be bound to (error "hello"), in which+case we want to see that "hello" exception, not (error "empty case").+See also Note [Case elimination: lifted case] in Simplify.+++************************************************************************+* *+ Tidying patterns+* *+************************************************************************++Tidy up the leftmost pattern in an @EquationInfo@, given the variable @v@+which will be scrutinised. This means:+\begin{itemize}+\item+Replace variable patterns @x@ (@x /= v@) with the pattern @_@,+together with the binding @x = v@.+\item+Replace the `as' pattern @x@@p@ with the pattern p and a binding @x = v@.+\item+Removing lazy (irrefutable) patterns (you don't want to know...).+\item+Converting explicit tuple-, list-, and parallel-array-pats into ordinary+@ConPats@.+\item+Convert the literal pat "" to [].+\end{itemize}++The result of this tidying is that the column of patterns will include+{\em only}:+\begin{description}+\item[@WildPats@:]+The @VarPat@ information isn't needed any more after this.++\item[@ConPats@:]+@ListPats@, @TuplePats@, etc., are all converted into @ConPats@.++\item[@LitPats@ and @NPats@:]+@LitPats@/@NPats@ of ``known friendly types'' (Int, Char,+Float, Double, at least) are converted to unboxed form; e.g.,+\tr{(NPat (HsInt i) _ _)} is converted to:+\begin{verbatim}+(ConPat I# _ _ [LitPat (HsIntPrim i)])+\end{verbatim}+\end{description}+-}++tidyEqnInfo :: Id -> EquationInfo+ -> DsM (DsWrapper, EquationInfo)+ -- DsM'd because of internal call to dsLHsBinds+ -- and mkSelectorBinds.+ -- "tidy1" does the interesting stuff, looking at+ -- one pattern and fiddling the list of bindings.+ --+ -- POST CONDITION: head pattern in the EqnInfo is+ -- WildPat+ -- ConPat+ -- NPat+ -- LitPat+ -- NPlusKPat+ -- but no other++tidyEqnInfo _ (EqnInfo { eqn_pats = [] })+ = panic "tidyEqnInfo"++tidyEqnInfo v eqn@(EqnInfo { eqn_pats = pat : pats })+ = do { (wrap, pat') <- tidy1 v pat+ ; return (wrap, eqn { eqn_pats = do pat' : pats }) }++tidy1 :: Id -- The Id being scrutinised+ -> Pat Id -- The pattern against which it is to be matched+ -> DsM (DsWrapper, -- Extra bindings to do before the match+ Pat Id) -- Equivalent pattern++-------------------------------------------------------+-- (pat', mr') = tidy1 v pat mr+-- tidies the *outer level only* of pat, giving pat'+-- It eliminates many pattern forms (as-patterns, variable patterns,+-- list patterns, etc) yielding one of:+-- WildPat+-- ConPatOut+-- LitPat+-- NPat+-- NPlusKPat++tidy1 v (ParPat pat) = tidy1 v (unLoc pat)+tidy1 v (SigPatOut pat _) = tidy1 v (unLoc pat)+tidy1 _ (WildPat ty) = return (idDsWrapper, WildPat ty)+tidy1 v (BangPat (L l p)) = tidy_bang_pat v l p++ -- case v of { x -> mr[] }+ -- = case v of { _ -> let x=v in mr[] }+tidy1 v (VarPat (L _ var))+ = return (wrapBind var v, WildPat (idType var))++ -- case v of { x@p -> mr[] }+ -- = case v of { p -> let x=v in mr[] }+tidy1 v (AsPat (L _ var) pat)+ = do { (wrap, pat') <- tidy1 v (unLoc pat)+ ; return (wrapBind var v . wrap, pat') }++{- now, here we handle lazy patterns:+ tidy1 v ~p bs = (v, v1 = case v of p -> v1 :+ v2 = case v of p -> v2 : ... : bs )++ where the v_i's are the binders in the pattern.++ ToDo: in "v_i = ... -> v_i", are the v_i's really the same thing?++ The case expr for v_i is just: match [v] [(p, [], \ x -> Var v_i)] any_expr+-}++tidy1 v (LazyPat pat)+ -- This is a convenient place to check for unlifted types under a lazy pattern.+ -- Doing this check during type-checking is unsatisfactory because we may+ -- not fully know the zonked types yet. We sure do here.+ = do { let unlifted_bndrs = filter (isUnliftedType . idType) (collectPatBinders pat)+ ; unless (null unlifted_bndrs) $+ putSrcSpanDs (getLoc pat) $+ errDs (hang (text "A lazy (~) pattern cannot bind variables of unlifted type." $$+ text "Unlifted variables:")+ 2 (vcat (map (\id -> ppr id <+> dcolon <+> ppr (idType id))+ unlifted_bndrs)))++ ; (_,sel_prs) <- mkSelectorBinds [] pat (Var v)+ ; let sel_binds = [NonRec b rhs | (b,rhs) <- sel_prs]+ ; return (mkCoreLets sel_binds, WildPat (idType v)) }++tidy1 _ (ListPat pats ty Nothing)+ = return (idDsWrapper, unLoc list_ConPat)+ where+ list_ConPat = foldr (\ x y -> mkPrefixConPat consDataCon [x, y] [ty])+ (mkNilPat ty)+ pats++-- Introduce fake parallel array constructors to be able to handle parallel+-- arrays with the existing machinery for constructor pattern+tidy1 _ (PArrPat pats ty)+ = return (idDsWrapper, unLoc parrConPat)+ where+ arity = length pats+ parrConPat = mkPrefixConPat (parrFakeCon arity) pats [ty]++tidy1 _ (TuplePat pats boxity tys)+ = return (idDsWrapper, unLoc tuple_ConPat)+ where+ arity = length pats+ tuple_ConPat = mkPrefixConPat (tupleDataCon boxity arity) pats tys++tidy1 _ (SumPat pat alt arity tys)+ = return (idDsWrapper, unLoc sum_ConPat)+ where+ sum_ConPat = mkPrefixConPat (sumDataCon alt arity) [pat] tys++-- LitPats: we *might* be able to replace these w/ a simpler form+tidy1 _ (LitPat lit)+ = return (idDsWrapper, tidyLitPat lit)++-- NPats: we *might* be able to replace these w/ a simpler form+tidy1 _ (NPat (L _ lit) mb_neg eq ty)+ = return (idDsWrapper, tidyNPat tidyLitPat lit mb_neg eq ty)++-- Everything else goes through unchanged...++tidy1 _ non_interesting_pat+ = return (idDsWrapper, non_interesting_pat)++--------------------+tidy_bang_pat :: Id -> SrcSpan -> Pat Id -> DsM (DsWrapper, Pat Id)++-- Discard par/sig under a bang+tidy_bang_pat v _ (ParPat (L l p)) = tidy_bang_pat v l p+tidy_bang_pat v _ (SigPatOut (L l p) _) = tidy_bang_pat v l p++-- Push the bang-pattern inwards, in the hope that+-- it may disappear next time+tidy_bang_pat v l (AsPat v' p) = tidy1 v (AsPat v' (L l (BangPat p)))+tidy_bang_pat v l (CoPat w p t) = tidy1 v (CoPat w (BangPat (L l p)) t)++-- Discard bang around strict pattern+tidy_bang_pat v _ p@(LitPat {}) = tidy1 v p+tidy_bang_pat v _ p@(ListPat {}) = tidy1 v p+tidy_bang_pat v _ p@(TuplePat {}) = tidy1 v p+tidy_bang_pat v _ p@(SumPat {}) = tidy1 v p+tidy_bang_pat v _ p@(PArrPat {}) = tidy1 v p++-- Data/newtype constructors+tidy_bang_pat v l p@(ConPatOut { pat_con = L _ (RealDataCon dc)+ , pat_args = args+ , pat_arg_tys = arg_tys })+ -- Newtypes: push bang inwards (Trac #9844)+ =+ if isNewTyCon (dataConTyCon dc)+ then tidy1 v (p { pat_args = push_bang_into_newtype_arg l ty args })+ else tidy1 v p -- Data types: discard the bang+ where+ (ty:_) = dataConInstArgTys dc arg_tys++-------------------+-- Default case, leave the bang there:+-- VarPat,+-- LazyPat,+-- WildPat,+-- ViewPat,+-- pattern synonyms (ConPatOut with PatSynCon)+-- NPat,+-- NPlusKPat+--+-- For LazyPat, remember that it's semantically like a VarPat+-- i.e. !(~p) is not like ~p, or p! (Trac #8952)+--+-- NB: SigPatIn, ConPatIn should not happen++tidy_bang_pat _ l p = return (idDsWrapper, BangPat (L l p))++-------------------+push_bang_into_newtype_arg :: SrcSpan+ -> Type -- The type of the argument we are pushing+ -- onto+ -> HsConPatDetails Id -> HsConPatDetails Id+-- See Note [Bang patterns and newtypes]+-- We are transforming !(N p) into (N !p)+push_bang_into_newtype_arg l _ty (PrefixCon (arg:args))+ = ASSERT( null args)+ PrefixCon [L l (BangPat arg)]+push_bang_into_newtype_arg l _ty (RecCon rf)+ | HsRecFields { rec_flds = L lf fld : flds } <- rf+ , HsRecField { hsRecFieldArg = arg } <- fld+ = ASSERT( null flds)+ RecCon (rf { rec_flds = [L lf (fld { hsRecFieldArg = L l (BangPat arg) })] })+push_bang_into_newtype_arg l ty (RecCon rf) -- If a user writes !(T {})+ | HsRecFields { rec_flds = [] } <- rf+ = PrefixCon [L l (BangPat (noLoc (WildPat ty)))]+push_bang_into_newtype_arg _ _ cd+ = pprPanic "push_bang_into_newtype_arg" (pprConArgs cd)++{-+Note [Bang patterns and newtypes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For the pattern !(Just pat) we can discard the bang, because+the pattern is strict anyway. But for !(N pat), where+ newtype NT = N Int+we definitely can't discard the bang. Trac #9844.++So what we do is to push the bang inwards, in the hope that it will+get discarded there. So we transform+ !(N pat) into (N !pat)++But what if there is nothing to push the bang onto? In at least one instance+a user has written !(N {}) which we translate into (N !_). See #13215+++\noindent+{\bf Previous @matchTwiddled@ stuff:}++Now we get to the only interesting part; note: there are choices for+translation [from Simon's notes]; translation~1:+\begin{verbatim}+deTwiddle [s,t] e+\end{verbatim}+returns+\begin{verbatim}+[ w = e,+ s = case w of [s,t] -> s+ t = case w of [s,t] -> t+]+\end{verbatim}++Here \tr{w} is a fresh variable, and the \tr{w}-binding prevents multiple+evaluation of \tr{e}. An alternative translation (No.~2):+\begin{verbatim}+[ w = case e of [s,t] -> (s,t)+ s = case w of (s,t) -> s+ t = case w of (s,t) -> t+]+\end{verbatim}++************************************************************************+* *+\subsubsection[improved-unmixing]{UNIMPLEMENTED idea for improved unmixing}+* *+************************************************************************++We might be able to optimise unmixing when confronted by+only-one-constructor-possible, of which tuples are the most notable+examples. Consider:+\begin{verbatim}+f (a,b,c) ... = ...+f d ... (e:f) = ...+f (g,h,i) ... = ...+f j ... = ...+\end{verbatim}+This definition would normally be unmixed into four equation blocks,+one per equation. But it could be unmixed into just one equation+block, because if the one equation matches (on the first column),+the others certainly will.++You have to be careful, though; the example+\begin{verbatim}+f j ... = ...+-------------------+f (a,b,c) ... = ...+f d ... (e:f) = ...+f (g,h,i) ... = ...+\end{verbatim}+{\em must} be broken into two blocks at the line shown; otherwise, you+are forcing unnecessary evaluation. In any case, the top-left pattern+always gives the cue. You could then unmix blocks into groups of...+\begin{description}+\item[all variables:]+As it is now.+\item[constructors or variables (mixed):]+Need to make sure the right names get bound for the variable patterns.+\item[literals or variables (mixed):]+Presumably just a variant on the constructor case (as it is now).+\end{description}++************************************************************************+* *+* matchWrapper: a convenient way to call @match@ *+* *+************************************************************************+\subsection[matchWrapper]{@matchWrapper@: a convenient interface to @match@}++Calls to @match@ often involve similar (non-trivial) work; that work+is collected here, in @matchWrapper@. This function takes as+arguments:+\begin{itemize}+\item+Typchecked @Matches@ (of a function definition, or a case or lambda+expression)---the main input;+\item+An error message to be inserted into any (runtime) pattern-matching+failure messages.+\end{itemize}++As results, @matchWrapper@ produces:+\begin{itemize}+\item+A list of variables (@Locals@) that the caller must ``promise'' to+bind to appropriate values; and+\item+a @CoreExpr@, the desugared output (main result).+\end{itemize}++The main actions of @matchWrapper@ include:+\begin{enumerate}+\item+Flatten the @[TypecheckedMatch]@ into a suitable list of+@EquationInfo@s.+\item+Create as many new variables as there are patterns in a pattern-list+(in any one of the @EquationInfo@s).+\item+Create a suitable ``if it fails'' expression---a call to @error@ using+the error-string input; the {\em type} of this fail value can be found+by examining one of the RHS expressions in one of the @EquationInfo@s.+\item+Call @match@ with all of this information!+\end{enumerate}+-}++matchWrapper :: HsMatchContext Name -- For shadowing warning messages+ -> Maybe (LHsExpr Id) -- The scrutinee, if we check a case expr+ -> MatchGroup Id (LHsExpr Id) -- Matches being desugared+ -> DsM ([Id], CoreExpr) -- Results++{-+ There is one small problem with the Lambda Patterns, when somebody+ writes something similar to:+\begin{verbatim}+ (\ (x:xs) -> ...)+\end{verbatim}+ he/she don't want a warning about incomplete patterns, that is done with+ the flag @opt_WarnSimplePatterns@.+ This problem also appears in the:+\begin{itemize}+\item @do@ patterns, but if the @do@ can fail+ it creates another equation if the match can fail+ (see @DsExpr.doDo@ function)+\item @let@ patterns, are treated by @matchSimply@+ List Comprension Patterns, are treated by @matchSimply@ also+\end{itemize}++We can't call @matchSimply@ with Lambda patterns,+due to the fact that lambda patterns can have more than+one pattern, and match simply only accepts one pattern.++JJQC 30-Nov-1997+-}++matchWrapper ctxt mb_scr (MG { mg_alts = L _ matches+ , mg_arg_tys = arg_tys+ , mg_res_ty = rhs_ty+ , mg_origin = origin })+ = do { dflags <- getDynFlags+ ; locn <- getSrcSpanDs++ ; new_vars <- case matches of+ [] -> mapM newSysLocalDsNoLP arg_tys+ (m:_) -> selectMatchVars (map unLoc (hsLMatchPats m))++ ; eqns_info <- mapM (mk_eqn_info new_vars) matches++ -- pattern match check warnings+ ; unless (isGenerated origin) $+ when (isAnyPmCheckEnabled dflags (DsMatchContext ctxt locn)) $+ addTmCsDs (genCaseTmCs1 mb_scr new_vars) $+ -- See Note [Type and Term Equality Propagation]+ checkMatches dflags (DsMatchContext ctxt locn) new_vars matches++ ; result_expr <- handleWarnings $+ matchEquations ctxt new_vars eqns_info rhs_ty+ ; return (new_vars, result_expr) }+ where+ mk_eqn_info vars (L _ (Match ctx pats _ grhss))+ = do { dflags <- getDynFlags+ ; let add_bang+ | FunRhs {mc_strictness=SrcStrict} <- ctx+ = pprTrace "addBang" empty addBang+ | otherwise+ = decideBangHood dflags+ upats = map (unLoc . add_bang) pats+ dicts = toTcTypeBag (collectEvVarsPats upats) -- Only TcTyVars+ ; tm_cs <- genCaseTmCs2 mb_scr upats vars+ ; match_result <- addDictsDs dicts $ -- See Note [Type and Term Equality Propagation]+ addTmCsDs tm_cs $ -- See Note [Type and Term Equality Propagation]+ dsGRHSs ctxt upats grhss rhs_ty+ ; return (EqnInfo { eqn_pats = upats, eqn_rhs = match_result}) }++ handleWarnings = if isGenerated origin+ then discardWarningsDs+ else id+++matchEquations :: HsMatchContext Name+ -> [MatchId] -> [EquationInfo] -> Type+ -> DsM CoreExpr+matchEquations ctxt vars eqns_info rhs_ty+ = do { let error_doc = matchContextErrString ctxt++ ; match_result <- match vars rhs_ty eqns_info++ ; fail_expr <- mkErrorAppDs pAT_ERROR_ID rhs_ty error_doc+ ; extractMatchResult match_result fail_expr }++{-+************************************************************************+* *+\subsection[matchSimply]{@matchSimply@: match a single expression against a single pattern}+* *+************************************************************************++@mkSimpleMatch@ is a wrapper for @match@ which deals with the+situation where we want to match a single expression against a single+pattern. It returns an expression.+-}++matchSimply :: CoreExpr -- Scrutinee+ -> HsMatchContext Name -- Match kind+ -> LPat Id -- Pattern it should match+ -> CoreExpr -- Return this if it matches+ -> CoreExpr -- Return this if it doesn't+ -> DsM CoreExpr+-- Do not warn about incomplete patterns; see matchSinglePat comments+matchSimply scrut hs_ctx pat result_expr fail_expr = do+ let+ match_result = cantFailMatchResult result_expr+ rhs_ty = exprType fail_expr+ -- Use exprType of fail_expr, because won't refine in the case of failure!+ match_result' <- matchSinglePat scrut hs_ctx pat rhs_ty match_result+ extractMatchResult match_result' fail_expr++matchSinglePat :: CoreExpr -> HsMatchContext Name -> LPat Id+ -> Type -> MatchResult -> DsM MatchResult+-- matchSinglePat ensures that the scrutinee is a variable+-- and then calls match_single_pat_var+--+-- matchSinglePat does not warn about incomplete patterns+-- Used for things like [ e | pat <- stuff ], where+-- incomplete patterns are just fine++matchSinglePat (Var var) ctx pat ty match_result+ | not (isExternalName (idName var))+ = match_single_pat_var var ctx pat ty match_result++matchSinglePat scrut hs_ctx pat ty match_result+ = do { var <- selectSimpleMatchVarL pat+ ; match_result' <- match_single_pat_var var hs_ctx pat ty match_result+ ; return (adjustMatchResult (bindNonRec var scrut) match_result') }++match_single_pat_var :: Id -- See Note [Match Ids]+ -> HsMatchContext Name -> LPat Id+ -> Type -> MatchResult -> DsM MatchResult+match_single_pat_var var ctx pat ty match_result+ = ASSERT2( isInternalName (idName var), ppr var )+ do { dflags <- getDynFlags+ ; locn <- getSrcSpanDs++ -- Pattern match check warnings+ ; checkSingle dflags (DsMatchContext ctx locn) var (unLoc pat)++ ; let eqn_info = EqnInfo { eqn_pats = [unLoc (decideBangHood dflags pat)]+ , eqn_rhs = match_result }+ ; match [var] ty [eqn_info] }+++{-+************************************************************************+* *+ Pattern classification+* *+************************************************************************+-}++data PatGroup+ = PgAny -- Immediate match: variables, wildcards,+ -- lazy patterns+ | PgCon DataCon -- Constructor patterns (incl list, tuple)+ | PgSyn PatSyn [Type] -- See Note [Pattern synonym groups]+ | PgLit Literal -- Literal patterns+ | PgN Rational -- Overloaded numeric literals;+ -- see Note [Don't use Literal for PgN]+ | PgOverS FastString -- Overloaded string literals+ | PgNpK Integer -- n+k patterns+ | PgBang -- Bang patterns+ | PgCo Type -- Coercion patterns; the type is the type+ -- of the pattern *inside*+ | PgView (LHsExpr Id) -- view pattern (e -> p):+ -- the LHsExpr is the expression e+ Type -- the Type is the type of p (equivalently, the result type of e)+ | PgOverloadedList++{- Note [Don't use Literal for PgN]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Previously we had, as PatGroup constructors++ | ...+ | PgN Literal -- Overloaded literals+ | PgNpK Literal -- n+k patterns+ | ...++But Literal is really supposed to represent an *unboxed* literal, like Int#.+We were sticking the literal from, say, an overloaded numeric literal pattern+into a MachInt constructor. This didn't really make sense; and we now have+the invariant that value in a MachInt must be in the range of the target+machine's Int# type, and an overloaded literal could meaningfully be larger.++Solution: For pattern grouping purposes, just store the literal directly in+the PgN constructor as a Rational if numeric, and add a PgOverStr constructor+for overloaded strings.+-}++groupEquations :: DynFlags -> [EquationInfo] -> [[(PatGroup, EquationInfo)]]+-- If the result is of form [g1, g2, g3],+-- (a) all the (pg,eq) pairs in g1 have the same pg+-- (b) none of the gi are empty+-- The ordering of equations is unchanged+groupEquations dflags eqns+ = runs same_gp [(patGroup dflags (firstPat eqn), eqn) | eqn <- eqns]+ where+ same_gp :: (PatGroup,EquationInfo) -> (PatGroup,EquationInfo) -> Bool+ (pg1,_) `same_gp` (pg2,_) = pg1 `sameGroup` pg2++subGroup :: (m -> [[EquationInfo]]) -- Map.elems+ -> m -- Map.empty+ -> (a -> m -> Maybe [EquationInfo]) -- Map.lookup+ -> (a -> [EquationInfo] -> m -> m) -- Map.insert+ -> [(a, EquationInfo)] -> [[EquationInfo]]+-- Input is a particular group. The result sub-groups the+-- equations by with particular constructor, literal etc they match.+-- Each sub-list in the result has the same PatGroup+-- See Note [Take care with pattern order]+-- Parameterized by map operations to allow different implementations+-- and constraints, eg. types without Ord instance.+subGroup elems empty lookup insert group+ = map reverse $ elems $ foldl accumulate empty group+ where+ accumulate pg_map (pg, eqn)+ = case lookup pg pg_map of+ Just eqns -> insert pg (eqn:eqns) pg_map+ Nothing -> insert pg [eqn] pg_map+ -- pg_map :: Map a [EquationInfo]+ -- Equations seen so far in reverse order of appearance++subGroupOrd :: Ord a => [(a, EquationInfo)] -> [[EquationInfo]]+subGroupOrd = subGroup Map.elems Map.empty Map.lookup Map.insert++subGroupUniq :: Uniquable a => [(a, EquationInfo)] -> [[EquationInfo]]+subGroupUniq =+ subGroup eltsUDFM emptyUDFM (flip lookupUDFM) (\k v m -> addToUDFM m k v)++{- Note [Pattern synonym groups]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we see+ f (P a) = e1+ f (P b) = e2+ ...+where P is a pattern synonym, can we put (P a -> e1) and (P b -> e2) in the+same group? We can if P is a constructor, but /not/ if P is a pattern synonym.+Consider (Trac #11224)+ -- readMaybe :: Read a => String -> Maybe a+ pattern PRead :: Read a => () => a -> String+ pattern PRead a <- (readMaybe -> Just a)++ f (PRead (x::Int)) = e1+ f (PRead (y::Bool)) = e2+This is all fine: we match the string by trying to read an Int; if that+fails we try to read a Bool. But clearly we can't combine the two into a single+match.++Conclusion: we can combine when we invoke PRead /at the same type/. Hence+in PgSyn we record the instantiaing types, and use them in sameGroup.++Note [Take care with pattern order]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the subGroup function we must be very careful about pattern re-ordering,+Consider the patterns [ (True, Nothing), (False, x), (True, y) ]+Then in bringing together the patterns for True, we must not+swap the Nothing and y!+-}++sameGroup :: PatGroup -> PatGroup -> Bool+-- Same group means that a single case expression+-- or test will suffice to match both, *and* the order+-- of testing within the group is insignificant.+sameGroup PgAny PgAny = True+sameGroup PgBang PgBang = True+sameGroup (PgCon _) (PgCon _) = True -- One case expression+sameGroup (PgSyn p1 t1) (PgSyn p2 t2) = p1==p2 && eqTypes t1 t2+ -- eqTypes: See Note [Pattern synonym groups]+sameGroup (PgLit _) (PgLit _) = True -- One case expression+sameGroup (PgN l1) (PgN l2) = l1==l2 -- Order is significant+sameGroup (PgOverS s1) (PgOverS s2) = s1==s2+sameGroup (PgNpK l1) (PgNpK l2) = l1==l2 -- See Note [Grouping overloaded literal patterns]+sameGroup (PgCo t1) (PgCo t2) = t1 `eqType` t2+ -- CoPats are in the same goup only if the type of the+ -- enclosed pattern is the same. The patterns outside the CoPat+ -- always have the same type, so this boils down to saying that+ -- the two coercions are identical.+sameGroup (PgView e1 t1) (PgView e2 t2) = viewLExprEq (e1,t1) (e2,t2)+ -- ViewPats are in the same group iff the expressions+ -- are "equal"---conservatively, we use syntactic equality+sameGroup _ _ = False++-- An approximation of syntactic equality used for determining when view+-- exprs are in the same group.+-- This function can always safely return false;+-- but doing so will result in the application of the view function being repeated.+--+-- Currently: compare applications of literals and variables+-- and anything else that we can do without involving other+-- HsSyn types in the recursion+--+-- NB we can't assume that the two view expressions have the same type. Consider+-- f (e1 -> True) = ...+-- f (e2 -> "hi") = ...+viewLExprEq :: (LHsExpr Id,Type) -> (LHsExpr Id,Type) -> Bool+viewLExprEq (e1,_) (e2,_) = lexp e1 e2+ where+ lexp :: LHsExpr Id -> LHsExpr Id -> Bool+ lexp e e' = exp (unLoc e) (unLoc e')++ ---------+ exp :: HsExpr Id -> HsExpr Id -> Bool+ -- real comparison is on HsExpr's+ -- strip parens+ exp (HsPar (L _ e)) e' = exp e e'+ exp e (HsPar (L _ e')) = exp e e'+ -- because the expressions do not necessarily have the same type,+ -- we have to compare the wrappers+ exp (HsWrap h e) (HsWrap h' e') = wrap h h' && exp e e'+ exp (HsVar i) (HsVar i') = i == i'+ exp (HsConLikeOut c) (HsConLikeOut c') = c == c'+ -- the instance for IPName derives using the id, so this works if the+ -- above does+ exp (HsIPVar i) (HsIPVar i') = i == i'+ exp (HsOverLabel l x) (HsOverLabel l' x') = l == l' && x == x'+ exp (HsOverLit l) (HsOverLit l') =+ -- Overloaded lits are equal if they have the same type+ -- and the data is the same.+ -- this is coarser than comparing the SyntaxExpr's in l and l',+ -- which resolve the overloading (e.g., fromInteger 1),+ -- because these expressions get written as a bunch of different variables+ -- (presumably to improve sharing)+ eqType (overLitType l) (overLitType l') && l == l'+ exp (HsApp e1 e2) (HsApp e1' e2') = lexp e1 e1' && lexp e2 e2'+ -- the fixities have been straightened out by now, so it's safe+ -- to ignore them?+ exp (OpApp l o _ ri) (OpApp l' o' _ ri') =+ lexp l l' && lexp o o' && lexp ri ri'+ exp (NegApp e n) (NegApp e' n') = lexp e e' && syn_exp n n'+ exp (SectionL e1 e2) (SectionL e1' e2') =+ lexp e1 e1' && lexp e2 e2'+ exp (SectionR e1 e2) (SectionR e1' e2') =+ lexp e1 e1' && lexp e2 e2'+ exp (ExplicitTuple es1 _) (ExplicitTuple es2 _) =+ eq_list tup_arg es1 es2+ exp (ExplicitSum _ _ e _) (ExplicitSum _ _ e' _) = lexp e e'+ exp (HsIf _ e e1 e2) (HsIf _ e' e1' e2') =+ lexp e e' && lexp e1 e1' && lexp e2 e2'++ -- Enhancement: could implement equality for more expressions+ -- if it seems useful+ -- But no need for HsLit, ExplicitList, ExplicitTuple,+ -- because they cannot be functions+ exp _ _ = False++ ---------+ syn_exp :: SyntaxExpr Id -> SyntaxExpr Id -> Bool+ syn_exp (SyntaxExpr { syn_expr = expr1+ , syn_arg_wraps = arg_wraps1+ , syn_res_wrap = res_wrap1 })+ (SyntaxExpr { syn_expr = expr2+ , syn_arg_wraps = arg_wraps2+ , syn_res_wrap = res_wrap2 })+ = exp expr1 expr2 &&+ and (zipWithEqual "viewLExprEq" wrap arg_wraps1 arg_wraps2) &&+ wrap res_wrap1 res_wrap2++ ---------+ tup_arg (L _ (Present e1)) (L _ (Present e2)) = lexp e1 e2+ tup_arg (L _ (Missing t1)) (L _ (Missing t2)) = eqType t1 t2+ tup_arg _ _ = False++ ---------+ wrap :: HsWrapper -> HsWrapper -> Bool+ -- Conservative, in that it demands that wrappers be+ -- syntactically identical and doesn't look under binders+ --+ -- Coarser notions of equality are possible+ -- (e.g., reassociating compositions,+ -- 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 (WpCast co) (WpCast co') = co `eqCoercion` co'+ wrap (WpEvApp et1) (WpEvApp et2) = et1 `ev_term` et2+ wrap (WpTyApp t) (WpTyApp t') = eqType t t'+ -- Enhancement: could implement equality for more wrappers+ -- if it seems useful (lams and lets)+ wrap _ _ = False++ ---------+ ev_term :: EvTerm -> EvTerm -> Bool+ ev_term (EvId a) (EvId b) = a==b+ ev_term (EvCoercion a) (EvCoercion b) = a `eqCoercion` b+ ev_term _ _ = False++ ---------+ eq_list :: (a->a->Bool) -> [a] -> [a] -> Bool+ eq_list _ [] [] = True+ eq_list _ [] (_:_) = False+ eq_list _ (_:_) [] = False+ eq_list eq (x:xs) (y:ys) = eq x y && eq_list eq xs ys++patGroup :: DynFlags -> Pat Id -> PatGroup+patGroup _ (ConPatOut { pat_con = L _ con+ , pat_arg_tys = tys })+ | RealDataCon dcon <- con = PgCon dcon+ | PatSynCon psyn <- con = PgSyn psyn tys+patGroup _ (WildPat {}) = PgAny+patGroup _ (BangPat {}) = PgBang+patGroup _ (NPat (L _ OverLit {ol_val=oval}) mb_neg _ _) =+ case (oval, isJust mb_neg) of+ (HsIntegral _ i, False) -> PgN (fromInteger i)+ (HsIntegral _ i, True ) -> PgN (-fromInteger i)+ (HsFractional r, False) -> PgN (fl_value r)+ (HsFractional r, True ) -> PgN (-fl_value r)+ (HsIsString _ s, _) -> ASSERT(isNothing mb_neg)+ PgOverS s+patGroup _ (NPlusKPat _ (L _ OverLit {ol_val=oval}) _ _ _ _) =+ case oval of+ HsIntegral _ i -> PgNpK i+ _ -> pprPanic "patGroup NPlusKPat" (ppr oval)+patGroup _ (CoPat _ p _) = PgCo (hsPatType p) -- Type of innelexp pattern+patGroup _ (ViewPat expr p _) = PgView expr (hsPatType (unLoc p))+patGroup _ (ListPat _ _ (Just _)) = PgOverloadedList+patGroup dflags (LitPat lit) = PgLit (hsLitKey dflags lit)+patGroup _ pat = pprPanic "patGroup" (ppr pat)++{-+Note [Grouping overloaded literal patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+WATCH OUT! Consider++ f (n+1) = ...+ f (n+2) = ...+ f (n+1) = ...++We can't group the first and third together, because the second may match+the same thing as the first. Same goes for *overloaded* literal patterns+ f 1 True = ...+ f 2 False = ...+ f 1 False = ...+If the first arg matches '1' but the second does not match 'True', we+cannot jump to the third equation! Because the same argument might+match '2'!+Hence we don't regard 1 and 2, or (n+1) and (n+2), as part of the same group.+-}
+ deSugar/Match.hs-boot view
@@ -0,0 +1,34 @@+module Match where+import Var ( Id )+import TcType ( Type )+import DsMonad ( DsM, EquationInfo, MatchResult )+import CoreSyn ( CoreExpr )+import HsSyn ( LPat, HsMatchContext, MatchGroup, LHsExpr )+import Name ( Name )++match :: [Id]+ -> Type+ -> [EquationInfo]+ -> DsM MatchResult++matchWrapper+ :: HsMatchContext Name+ -> Maybe (LHsExpr Id)+ -> MatchGroup Id (LHsExpr Id)+ -> DsM ([Id], CoreExpr)++matchSimply+ :: CoreExpr+ -> HsMatchContext Name+ -> LPat Id+ -> CoreExpr+ -> CoreExpr+ -> DsM CoreExpr++matchSinglePat+ :: CoreExpr+ -> HsMatchContext Name+ -> LPat Id+ -> Type+ -> MatchResult+ -> DsM MatchResult
+ deSugar/MatchCon.hs view
@@ -0,0 +1,287 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Pattern-matching constructors+-}++{-# LANGUAGE CPP #-}++module MatchCon ( matchConFamily, matchPatSyn ) where++#include "HsVersions.h"++import {-# SOURCE #-} Match ( match )++import HsSyn+import DsBinds+import ConLike+import TcType+import DsMonad+import DsUtils+import MkCore ( mkCoreLets )+import Util+import ListSetOps ( runs )+import Id+import NameEnv+import FieldLabel ( flSelector )+import SrcLoc+import DynFlags+import Outputable+import Control.Monad(liftM)++{-+We are confronted with the first column of patterns in a set of+equations, all beginning with constructors from one ``family'' (e.g.,+@[]@ and @:@ make up the @List@ ``family''). We want to generate the+alternatives for a @Case@ expression. There are several choices:+\begin{enumerate}+\item+Generate an alternative for every constructor in the family, whether+they are used in this set of equations or not; this is what the Wadler+chapter does.+\begin{description}+\item[Advantages:]+(a)~Simple. (b)~It may also be that large sparsely-used constructor+families are mainly handled by the code for literals.+\item[Disadvantages:]+(a)~Not practical for large sparsely-used constructor families, e.g.,+the ASCII character set. (b)~Have to look up a list of what+constructors make up the whole family.+\end{description}++\item+Generate an alternative for each constructor used, then add a default+alternative in case some constructors in the family weren't used.+\begin{description}+\item[Advantages:]+(a)~Alternatives aren't generated for unused constructors. (b)~The+STG is quite happy with defaults. (c)~No lookup in an environment needed.+\item[Disadvantages:]+(a)~A spurious default alternative may be generated.+\end{description}++\item+``Do it right:'' generate an alternative for each constructor used,+and add a default alternative if all constructors in the family+weren't used.+\begin{description}+\item[Advantages:]+(a)~You will get cases with only one alternative (and no default),+which should be amenable to optimisation. Tuples are a common example.+\item[Disadvantages:]+(b)~Have to look up constructor families in TDE (as above).+\end{description}+\end{enumerate}++We are implementing the ``do-it-right'' option for now. The arguments+to @matchConFamily@ are the same as to @match@; the extra @Int@+returned is the number of constructors in the family.++The function @matchConFamily@ is concerned with this+have-we-used-all-the-constructors? question; the local function+@match_cons_used@ does all the real work.+-}++matchConFamily :: [Id]+ -> Type+ -> [[EquationInfo]]+ -> DsM MatchResult+-- Each group of eqns is for a single constructor+matchConFamily (var:vars) ty groups+ = do dflags <- getDynFlags+ alts <- mapM (fmap toRealAlt . matchOneConLike vars ty) groups+ return (mkCoAlgCaseMatchResult dflags var ty alts)+ where+ toRealAlt alt = case alt_pat alt of+ RealDataCon dcon -> alt{ alt_pat = dcon }+ _ -> panic "matchConFamily: not RealDataCon"+matchConFamily [] _ _ = panic "matchConFamily []"++matchPatSyn :: [Id]+ -> Type+ -> [EquationInfo]+ -> DsM MatchResult+matchPatSyn (var:vars) ty eqns+ = do alt <- fmap toSynAlt $ matchOneConLike vars ty eqns+ return (mkCoSynCaseMatchResult var ty alt)+ where+ toSynAlt alt = case alt_pat alt of+ PatSynCon psyn -> alt{ alt_pat = psyn }+ _ -> panic "matchPatSyn: not PatSynCon"+matchPatSyn _ _ _ = panic "matchPatSyn []"++type ConArgPats = HsConDetails (LPat Id) (HsRecFields Id (LPat Id))++matchOneConLike :: [Id]+ -> Type+ -> [EquationInfo]+ -> DsM (CaseAlt ConLike)+matchOneConLike vars ty (eqn1 : eqns) -- All eqns for a single constructor+ = do { let inst_tys = ASSERT( tvs1 `equalLength` ex_tvs )+ arg_tys ++ mkTyVarTys tvs1++ val_arg_tys = conLikeInstOrigArgTys con1 inst_tys+ -- dataConInstOrigArgTys takes the univ and existential tyvars+ -- and returns the types of the *value* args, which is what we want++ match_group :: [Id]+ -> [(ConArgPats, EquationInfo)] -> DsM MatchResult+ -- All members of the group have compatible ConArgPats+ match_group arg_vars arg_eqn_prs+ = ASSERT( notNull arg_eqn_prs )+ do { (wraps, eqns') <- liftM unzip (mapM shift arg_eqn_prs)+ ; let group_arg_vars = select_arg_vars arg_vars arg_eqn_prs+ ; match_result <- match (group_arg_vars ++ vars) ty eqns'+ ; return (adjustMatchResult (foldr1 (.) wraps) match_result) }++ shift (_, eqn@(EqnInfo { eqn_pats = ConPatOut{ pat_tvs = tvs, pat_dicts = ds,+ pat_binds = bind, pat_args = args+ } : pats }))+ = do ds_bind <- dsTcEvBinds bind+ return ( wrapBinds (tvs `zip` tvs1)+ . wrapBinds (ds `zip` dicts1)+ . mkCoreLets ds_bind+ , eqn { eqn_pats = conArgPats val_arg_tys args ++ pats }+ )+ shift (_, (EqnInfo { eqn_pats = ps })) = pprPanic "matchOneCon/shift" (ppr ps)++ ; arg_vars <- selectConMatchVars val_arg_tys args1+ -- Use the first equation as a source of+ -- suggestions for the new variables++ -- Divide into sub-groups; see Note [Record patterns]+ ; let groups :: [[(ConArgPats, EquationInfo)]]+ groups = runs compatible_pats [ (pat_args (firstPat eqn), eqn)+ | eqn <- eqn1:eqns ]++ ; match_results <- mapM (match_group arg_vars) groups++ ; return $ MkCaseAlt{ alt_pat = con1,+ alt_bndrs = tvs1 ++ dicts1 ++ arg_vars,+ alt_wrapper = wrapper1,+ alt_result = foldr1 combineMatchResults match_results } }+ where+ ConPatOut { pat_con = L _ con1, pat_arg_tys = arg_tys, pat_wrap = wrapper1,+ pat_tvs = tvs1, pat_dicts = dicts1, pat_args = args1 }+ = firstPat eqn1+ fields1 = map flSelector (conLikeFieldLabels con1)++ ex_tvs = conLikeExTyVars con1++ -- Choose the right arg_vars in the right order for this group+ -- Note [Record patterns]+ select_arg_vars :: [Id] -> [(ConArgPats, EquationInfo)] -> [Id]+ select_arg_vars arg_vars ((arg_pats, _) : _)+ | RecCon flds <- arg_pats+ , let rpats = rec_flds flds+ , not (null rpats) -- Treated specially; cf conArgPats+ = ASSERT2( length fields1 == length arg_vars,+ ppr con1 $$ ppr fields1 $$ ppr arg_vars )+ map lookup_fld rpats+ | otherwise+ = arg_vars+ where+ fld_var_env = mkNameEnv $ zipEqual "get_arg_vars" fields1 arg_vars+ lookup_fld (L _ rpat) = lookupNameEnv_NF fld_var_env+ (idName (unLoc (hsRecFieldId rpat)))+ select_arg_vars _ [] = panic "matchOneCon/select_arg_vars []"+matchOneConLike _ _ [] = panic "matchOneCon []"++-----------------+compatible_pats :: (ConArgPats,a) -> (ConArgPats,a) -> Bool+-- Two constructors have compatible argument patterns if the number+-- and order of sub-matches is the same in both cases+compatible_pats (RecCon flds1, _) (RecCon flds2, _) = same_fields flds1 flds2+compatible_pats (RecCon flds1, _) _ = null (rec_flds flds1)+compatible_pats _ (RecCon flds2, _) = null (rec_flds flds2)+compatible_pats _ _ = True -- Prefix or infix con++same_fields :: HsRecFields Id (LPat Id) -> HsRecFields Id (LPat Id) -> Bool+same_fields flds1 flds2+ = all2 (\(L _ f1) (L _ f2)+ -> unLoc (hsRecFieldId f1) == unLoc (hsRecFieldId f2))+ (rec_flds flds1) (rec_flds flds2)+++-----------------+selectConMatchVars :: [Type] -> ConArgPats -> DsM [Id]+selectConMatchVars arg_tys (RecCon {}) = newSysLocalsDsNoLP arg_tys+selectConMatchVars _ (PrefixCon ps) = selectMatchVars (map unLoc ps)+selectConMatchVars _ (InfixCon p1 p2) = selectMatchVars [unLoc p1, unLoc p2]++conArgPats :: [Type] -- Instantiated argument types+ -- Used only to fill in the types of WildPats, which+ -- are probably never looked at anyway+ -> ConArgPats+ -> [Pat Id]+conArgPats _arg_tys (PrefixCon ps) = map unLoc ps+conArgPats _arg_tys (InfixCon p1 p2) = [unLoc p1, unLoc p2]+conArgPats arg_tys (RecCon (HsRecFields { rec_flds = rpats }))+ | null rpats = map WildPat arg_tys+ -- Important special case for C {}, which can be used for a+ -- datacon that isn't declared to have fields at all+ | otherwise = map (unLoc . hsRecFieldArg . unLoc) rpats++{-+Note [Record patterns]+~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T = T { x,y,z :: Bool }++ f (T { y=True, x=False }) = ...++We must match the patterns IN THE ORDER GIVEN, thus for the first+one we match y=True before x=False. See Trac #246; or imagine+matching against (T { y=False, x=undefined }): should fail without+touching the undefined.++Now consider:++ f (T { y=True, x=False }) = ...+ f (T { x=True, y= False}) = ...++In the first we must test y first; in the second we must test x+first. So we must divide even the equations for a single constructor+T into sub-goups, based on whether they match the same field in the+same order. That's what the (runs compatible_pats) grouping.++All non-record patterns are "compatible" in this sense, because the+positional patterns (T a b) and (a `T` b) all match the arguments+in order. Also T {} is special because it's equivalent to (T _ _).+Hence the (null rpats) checks here and there.+++Note [Existentials in shift_con_pat]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T = forall a. Ord a => T a (a->Int)++ f (T x f) True = ...expr1...+ f (T y g) False = ...expr2..++When we put in the tyvars etc we get++ f (T a (d::Ord a) (x::a) (f::a->Int)) True = ...expr1...+ f (T b (e::Ord b) (y::a) (g::a->Int)) True = ...expr2...++After desugaring etc we'll get a single case:++ f = \t::T b::Bool ->+ case t of+ T a (d::Ord a) (x::a) (f::a->Int)) ->+ case b of+ True -> ...expr1...+ False -> ...expr2...++*** We have to substitute [a/b, d/e] in expr2! **+Hence+ False -> ....((/\b\(e:Ord b).expr2) a d)....++Originally I tried to use+ (\b -> let e = d in expr2) a+to do this substitution. While this is "correct" in a way, it fails+Lint, because e::Ord b but d::Ord a.++-}
+ deSugar/MatchLit.hs view
@@ -0,0 +1,456 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Pattern-matching literal patterns+-}++{-# LANGUAGE CPP, ScopedTypeVariables #-}++module MatchLit ( dsLit, dsOverLit, dsOverLit', hsLitKey+ , tidyLitPat, tidyNPat+ , matchLiterals, matchNPlusKPats, matchNPats+ , warnAboutIdentities, warnAboutOverflowedLiterals+ , warnAboutEmptyEnumerations+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} Match ( match )+import {-# SOURCE #-} DsExpr ( dsExpr, dsSyntaxExpr )++import DsMonad+import DsUtils++import HsSyn++import Id+import CoreSyn+import MkCore+import TyCon+import DataCon+import TcHsSyn ( shortCutLit )+import TcType+import Name+import Type+import PrelNames+import TysWiredIn+import Literal+import SrcLoc+import Data.Ratio+import Outputable+import BasicTypes+import DynFlags+import Util+import FastString+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.Int+import Data.Word++{-+************************************************************************+* *+ Desugaring literals+ [used to be in DsExpr, but DsMeta needs it,+ and it's nice to avoid a loop]+* *+************************************************************************++We give int/float literals type @Integer@ and @Rational@, respectively.+The typechecker will (presumably) have put \tr{from{Integer,Rational}s}+around them.++ToDo: put in range checks for when converting ``@i@''+(or should that be in the typechecker?)++For numeric literals, we try to detect there use at a standard type+(@Int@, @Float@, etc.) are directly put in the right constructor.+[NB: down with the @App@ conversion.]++See also below where we look for @DictApps@ for \tr{plusInt}, etc.+-}++dsLit :: HsLit -> DsM CoreExpr+dsLit (HsStringPrim _ s) = return (Lit (MachStr s))+dsLit (HsCharPrim _ c) = return (Lit (MachChar c))+dsLit (HsIntPrim _ i) = return (Lit (MachInt i))+dsLit (HsWordPrim _ w) = return (Lit (MachWord w))+dsLit (HsInt64Prim _ i) = return (Lit (MachInt64 i))+dsLit (HsWord64Prim _ w) = return (Lit (MachWord64 w))+dsLit (HsFloatPrim f) = return (Lit (MachFloat (fl_value f)))+dsLit (HsDoublePrim d) = return (Lit (MachDouble (fl_value d)))++dsLit (HsChar _ c) = return (mkCharExpr c)+dsLit (HsString _ str) = mkStringExprFS str+dsLit (HsInteger _ i _) = mkIntegerExpr i+dsLit (HsInt _ i) = do dflags <- getDynFlags+ return (mkIntExpr dflags i)++dsLit (HsRat r ty) = do+ num <- mkIntegerExpr (numerator (fl_value r))+ denom <- mkIntegerExpr (denominator (fl_value r))+ return (mkCoreConApps ratio_data_con [Type integer_ty, num, denom])+ where+ (ratio_data_con, integer_ty)+ = case tcSplitTyConApp ty of+ (tycon, [i_ty]) -> ASSERT(isIntegerTy i_ty && tycon `hasKey` ratioTyConKey)+ (head (tyConDataCons tycon), i_ty)+ x -> pprPanic "dsLit" (ppr x)++dsOverLit :: HsOverLit Id -> DsM CoreExpr+dsOverLit lit = do { dflags <- getDynFlags+ ; warnAboutOverflowedLiterals dflags lit+ ; dsOverLit' dflags lit }++dsOverLit' :: DynFlags -> HsOverLit Id -> DsM CoreExpr+-- Post-typechecker, the HsExpr field of an OverLit contains+-- (an expression for) the literal value itself+dsOverLit' dflags (OverLit { ol_val = val, ol_rebindable = rebindable+ , ol_witness = witness, ol_type = ty })+ | not rebindable+ , Just expr <- shortCutLit dflags val ty = dsExpr expr -- Note [Literal short cut]+ | otherwise = dsExpr witness++{-+Note [Literal short cut]+~~~~~~~~~~~~~~~~~~~~~~~~+The type checker tries to do this short-cutting as early as possible, but+because of unification etc, more information is available to the desugarer.+And where it's possible to generate the correct literal right away, it's+much better to do so.+++************************************************************************+* *+ Warnings about overflowed literals+* *+************************************************************************++Warn about functions like toInteger, fromIntegral, that convert+between one type and another when the to- and from- types are the+same. Then it's probably (albeit not definitely) the identity+-}++warnAboutIdentities :: DynFlags -> CoreExpr -> Type -> DsM ()+warnAboutIdentities dflags (Var conv_fn) type_of_conv+ | wopt Opt_WarnIdentities dflags+ , idName conv_fn `elem` conversionNames+ , Just (arg_ty, res_ty) <- splitFunTy_maybe type_of_conv+ , arg_ty `eqType` res_ty -- So we are converting ty -> ty+ = warnDs (Reason Opt_WarnIdentities)+ (vcat [ text "Call of" <+> ppr conv_fn <+> dcolon <+> ppr type_of_conv+ , nest 2 $ text "can probably be omitted"+ ])+warnAboutIdentities _ _ _ = return ()++conversionNames :: [Name]+conversionNames+ = [ toIntegerName, toRationalName+ , fromIntegralName, realToFracName ]+ -- We can't easily add fromIntegerName, fromRationalName,+ -- because they are generated by literals++warnAboutOverflowedLiterals :: DynFlags -> HsOverLit Id -> DsM ()+warnAboutOverflowedLiterals dflags lit+ | wopt Opt_WarnOverflowedLiterals dflags+ , Just (i, tc) <- getIntegralLit lit+ = if tc == intTyConName then check i tc (undefined :: Int)+ else if tc == int8TyConName then check i tc (undefined :: Int8)+ else if tc == int16TyConName then check i tc (undefined :: Int16)+ else if tc == int32TyConName then check i tc (undefined :: Int32)+ else if tc == int64TyConName then check i tc (undefined :: Int64)+ else if tc == wordTyConName then check i tc (undefined :: Word)+ else if tc == word8TyConName then check i tc (undefined :: Word8)+ else if tc == word16TyConName then check i tc (undefined :: Word16)+ else if tc == word32TyConName then check i tc (undefined :: Word32)+ else if tc == word64TyConName then check i tc (undefined :: Word64)+ else return ()++ | otherwise = return ()+ where+ check :: forall a. (Bounded a, Integral a) => Integer -> Name -> a -> DsM ()+ check i tc _proxy+ = when (i < minB || i > maxB) $ do+ warnDs (Reason Opt_WarnOverflowedLiterals)+ (vcat [ text "Literal" <+> integer i+ <+> text "is out of the" <+> ppr tc <+> ptext (sLit "range")+ <+> integer minB <> text ".." <> integer maxB+ , sug ])+ where+ minB = toInteger (minBound :: a)+ maxB = toInteger (maxBound :: a)+ sug | minB == -i -- Note [Suggest NegativeLiterals]+ , i > 0+ , not (xopt LangExt.NegativeLiterals dflags)+ = text "If you are trying to write a large negative literal, use NegativeLiterals"+ | otherwise = Outputable.empty++{-+Note [Suggest NegativeLiterals]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If you write+ x :: Int8+ x = -128+it'll parse as (negate 128), and overflow. In this case, suggest NegativeLiterals.+We get an erroneous suggestion for+ x = 128+but perhaps that does not matter too much.+-}++warnAboutEmptyEnumerations :: DynFlags -> LHsExpr Id -> Maybe (LHsExpr Id) -> LHsExpr Id -> DsM ()+-- Warns about [2,3 .. 1] which returns the empty list+-- Only works for integral types, not floating point+warnAboutEmptyEnumerations dflags fromExpr mThnExpr toExpr+ | wopt Opt_WarnEmptyEnumerations dflags+ , Just (from,tc) <- getLHsIntegralLit fromExpr+ , Just mThn <- traverse getLHsIntegralLit mThnExpr+ , Just (to,_) <- getLHsIntegralLit toExpr+ , let check :: forall a. (Enum a, Num a) => a -> DsM ()+ check _proxy+ = when (null enumeration) $+ warnDs (Reason Opt_WarnEmptyEnumerations) (text "Enumeration is empty")+ where+ enumeration :: [a]+ enumeration = case mThn of+ Nothing -> [fromInteger from .. fromInteger to]+ Just (thn,_) -> [fromInteger from, fromInteger thn .. fromInteger to]++ = if tc == intTyConName then check (undefined :: Int)+ else if tc == int8TyConName then check (undefined :: Int8)+ else if tc == int16TyConName then check (undefined :: Int16)+ else if tc == int32TyConName then check (undefined :: Int32)+ else if tc == int64TyConName then check (undefined :: Int64)+ else if tc == wordTyConName then check (undefined :: Word)+ else if tc == word8TyConName then check (undefined :: Word8)+ else if tc == word16TyConName then check (undefined :: Word16)+ else if tc == word32TyConName then check (undefined :: Word32)+ else if tc == word64TyConName then check (undefined :: Word64)+ else if tc == integerTyConName then check (undefined :: Integer)+ else return ()++ | otherwise = return ()++getLHsIntegralLit :: LHsExpr Id -> Maybe (Integer, Name)+-- See if the expression is an Integral literal+-- Remember to look through automatically-added tick-boxes! (Trac #8384)+getLHsIntegralLit (L _ (HsPar e)) = getLHsIntegralLit e+getLHsIntegralLit (L _ (HsTick _ e)) = getLHsIntegralLit e+getLHsIntegralLit (L _ (HsBinTick _ _ e)) = getLHsIntegralLit e+getLHsIntegralLit (L _ (HsOverLit over_lit)) = getIntegralLit over_lit+getLHsIntegralLit _ = Nothing++getIntegralLit :: HsOverLit Id -> Maybe (Integer, Name)+getIntegralLit (OverLit { ol_val = HsIntegral _ i, ol_type = ty })+ | Just tc <- tyConAppTyCon_maybe ty+ = Just (i, tyConName tc)+getIntegralLit _ = Nothing++{-+************************************************************************+* *+ Tidying lit pats+* *+************************************************************************+-}++tidyLitPat :: HsLit -> Pat Id+-- Result has only the following HsLits:+-- HsIntPrim, HsWordPrim, HsCharPrim, HsFloatPrim+-- HsDoublePrim, HsStringPrim, HsString+-- * HsInteger, HsRat, HsInt can't show up in LitPats+-- * We get rid of HsChar right here+tidyLitPat (HsChar src c) = unLoc (mkCharLitPat src c)+tidyLitPat (HsString src s)+ | lengthFS s <= 1 -- Short string literals only+ = unLoc $ foldr (\c pat -> mkPrefixConPat consDataCon+ [mkCharLitPat src c, pat] [charTy])+ (mkNilPat charTy) (unpackFS s)+ -- The stringTy is the type of the whole pattern, not+ -- the type to instantiate (:) or [] with!+tidyLitPat lit = LitPat lit++----------------+tidyNPat :: (HsLit -> Pat Id) -- How to tidy a LitPat+ -- We need this argument because tidyNPat is called+ -- both by Match and by Check, but they tidy LitPats+ -- slightly differently; and we must desugar+ -- literals consistently (see Trac #5117)+ -> HsOverLit Id -> Maybe (SyntaxExpr Id) -> SyntaxExpr Id -> Type+ -> Pat Id+tidyNPat tidy_lit_pat (OverLit val False _ ty) mb_neg _eq outer_ty+ -- False: Take short cuts only if the literal is not using rebindable syntax+ --+ -- Once that is settled, look for cases where the type of the+ -- entire overloaded literal matches the type of the underlying literal,+ -- and in that case take the short cut+ -- NB: Watch out for weird cases like Trac #3382+ -- f :: Int -> Int+ -- f "blah" = 4+ -- which might be ok if we have 'instance IsString Int'+ --+ | not type_change, isIntTy ty, Just int_lit <- mb_int_lit+ = mk_con_pat intDataCon (HsIntPrim NoSourceText int_lit)+ | not type_change, isWordTy ty, Just int_lit <- mb_int_lit+ = mk_con_pat wordDataCon (HsWordPrim NoSourceText int_lit)+ | not type_change, isStringTy ty, Just str_lit <- mb_str_lit+ = tidy_lit_pat (HsString NoSourceText str_lit)+ -- NB: do /not/ convert Float or Double literals to F# 3.8 or D# 5.3+ -- If we do convert to the constructor form, we'll generate a case+ -- expression on a Float# or Double# and that's not allowed in Core; see+ -- Trac #9238 and Note [Rules for floating-point comparisons] in PrelRules+ where+ -- Sometimes (like in test case+ -- overloadedlists/should_run/overloadedlistsrun04), the SyntaxExprs include+ -- type-changing wrappers (for example, from Id Int to Int, for the identity+ -- type family Id). In these cases, we can't do the short-cut.+ type_change = not (outer_ty `eqType` ty)++ mk_con_pat :: DataCon -> HsLit -> Pat Id+ mk_con_pat con lit = unLoc (mkPrefixConPat con [noLoc $ LitPat lit] [])++ mb_int_lit :: Maybe Integer+ mb_int_lit = case (mb_neg, val) of+ (Nothing, HsIntegral _ i) -> Just i+ (Just _, HsIntegral _ i) -> Just (-i)+ _ -> Nothing++ mb_str_lit :: Maybe FastString+ mb_str_lit = case (mb_neg, val) of+ (Nothing, HsIsString _ s) -> Just s+ _ -> Nothing++tidyNPat _ over_lit mb_neg eq outer_ty+ = NPat (noLoc over_lit) mb_neg eq outer_ty++{-+************************************************************************+* *+ Pattern matching on LitPat+* *+************************************************************************+-}++matchLiterals :: [Id]+ -> Type -- Type of the whole case expression+ -> [[EquationInfo]] -- All PgLits+ -> DsM MatchResult++matchLiterals (var:vars) ty sub_groups+ = ASSERT( notNull sub_groups && all notNull sub_groups )+ do { -- Deal with each group+ ; alts <- mapM match_group sub_groups++ -- Combine results. For everything except String+ -- we can use a case expression; for String we need+ -- a chain of if-then-else+ ; if isStringTy (idType var) then+ do { eq_str <- dsLookupGlobalId eqStringName+ ; mrs <- mapM (wrap_str_guard eq_str) alts+ ; return (foldr1 combineMatchResults mrs) }+ else+ return (mkCoPrimCaseMatchResult var ty alts)+ }+ where+ match_group :: [EquationInfo] -> DsM (Literal, MatchResult)+ match_group eqns+ = do dflags <- getDynFlags+ let LitPat hs_lit = firstPat (head eqns)+ match_result <- match vars ty (shiftEqns eqns)+ return (hsLitKey dflags hs_lit, match_result)++ wrap_str_guard :: Id -> (Literal,MatchResult) -> DsM MatchResult+ -- Equality check for string literals+ wrap_str_guard eq_str (MachStr s, mr)+ = do { -- We now have to convert back to FastString. Perhaps there+ -- should be separate MachBytes and MachStr constructors?+ let s' = mkFastStringByteString s+ ; lit <- mkStringExprFS s'+ ; let pred = mkApps (Var eq_str) [Var var, lit]+ ; return (mkGuardedMatchResult pred mr) }+ wrap_str_guard _ (l, _) = pprPanic "matchLiterals/wrap_str_guard" (ppr l)++matchLiterals [] _ _ = panic "matchLiterals []"++---------------------------+hsLitKey :: DynFlags -> HsLit -> Literal+-- Get the Core literal corresponding to a HsLit.+-- It only works for primitive types and strings;+-- others have been removed by tidy+-- For HsString, it produces a MachStr, which really represents an _unboxed_+-- string literal; and we deal with it in matchLiterals above. Otherwise, it+-- produces a primitive Literal of type matching the original HsLit.+-- In the case of the fixed-width numeric types, we need to wrap here+-- because Literal has an invariant that the literal is in range, while+-- HsLit does not.+hsLitKey dflags (HsIntPrim _ i) = mkMachIntWrap dflags i+hsLitKey dflags (HsWordPrim _ w) = mkMachWordWrap dflags w+hsLitKey _ (HsInt64Prim _ i) = mkMachInt64Wrap i+hsLitKey _ (HsWord64Prim _ w) = mkMachWord64Wrap w+hsLitKey _ (HsCharPrim _ c) = mkMachChar c+hsLitKey _ (HsFloatPrim f) = mkMachFloat (fl_value f)+hsLitKey _ (HsDoublePrim d) = mkMachDouble (fl_value d)+hsLitKey _ (HsString _ s) = MachStr (fastStringToByteString s)+hsLitKey _ l = pprPanic "hsLitKey" (ppr l)++{-+************************************************************************+* *+ Pattern matching on NPat+* *+************************************************************************+-}++matchNPats :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult+matchNPats (var:vars) ty (eqn1:eqns) -- All for the same literal+ = do { let NPat (L _ lit) mb_neg eq_chk _ = firstPat eqn1+ ; lit_expr <- dsOverLit lit+ ; neg_lit <- case mb_neg of+ Nothing -> return lit_expr+ Just neg -> dsSyntaxExpr neg [lit_expr]+ ; pred_expr <- dsSyntaxExpr eq_chk [Var var, neg_lit]+ ; match_result <- match vars ty (shiftEqns (eqn1:eqns))+ ; return (mkGuardedMatchResult pred_expr match_result) }+matchNPats vars _ eqns = pprPanic "matchOneNPat" (ppr (vars, eqns))++{-+************************************************************************+* *+ Pattern matching on n+k patterns+* *+************************************************************************++For an n+k pattern, we use the various magic expressions we've been given.+We generate:+\begin{verbatim}+ if ge var lit then+ let n = sub var lit+ in <expr-for-a-successful-match>+ else+ <try-next-pattern-or-whatever>+\end{verbatim}+-}++matchNPlusKPats :: [Id] -> Type -> [EquationInfo] -> DsM MatchResult+-- All NPlusKPats, for the *same* literal k+matchNPlusKPats (var:vars) ty (eqn1:eqns)+ = do { let NPlusKPat (L _ n1) (L _ lit1) lit2 ge minus _ = firstPat eqn1+ ; lit1_expr <- dsOverLit lit1+ ; lit2_expr <- dsOverLit lit2+ ; pred_expr <- dsSyntaxExpr ge [Var var, lit1_expr]+ ; minusk_expr <- dsSyntaxExpr minus [Var var, lit2_expr]+ ; let (wraps, eqns') = mapAndUnzip (shift n1) (eqn1:eqns)+ ; match_result <- match vars ty eqns'+ ; return (mkGuardedMatchResult pred_expr $+ mkCoLetMatchResult (NonRec n1 minusk_expr) $+ adjustMatchResult (foldr1 (.) wraps) $+ match_result) }+ where+ shift n1 eqn@(EqnInfo { eqn_pats = NPlusKPat (L _ n) _ _ _ _ _ : pats })+ = (wrapBind n n1, eqn { eqn_pats = pats })+ -- The wrapBind is a no-op for the first equation+ shift _ e = pprPanic "matchNPlusKPats/shift" (ppr e)++matchNPlusKPats vars _ eqns = pprPanic "matchNPlusKPats" (ppr (vars, eqns))
+ deSugar/PmExpr.hs view
@@ -0,0 +1,449 @@+{-+Author: George Karachalias <george.karachalias@cs.kuleuven.be>++Haskell expressions (as used by the pattern matching checker) and utilities.+-}++{-# LANGUAGE CPP #-}++module PmExpr (+ PmExpr(..), PmLit(..), SimpleEq, ComplexEq, toComplex, eqPmLit,+ truePmExpr, falsePmExpr, isTruePmExpr, isFalsePmExpr, isNotPmExprOther,+ lhsExprToPmExpr, hsExprToPmExpr, substComplexEq, filterComplex,+ pprPmExprWithParens, runPmPprM+ ) where++#include "HsVersions.h"++import HsSyn+import Id+import Name+import NameSet+import DataCon+import ConLike+import TysWiredIn+import Outputable+import Util+import SrcLoc++import Data.Maybe (mapMaybe)+import Data.List (groupBy, sortBy, nubBy)+import Control.Monad.Trans.State.Lazy++{-+%************************************************************************+%* *+ Lifted Expressions+%* *+%************************************************************************+-}++{- Note [PmExprOther in PmExpr]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Since there is no plan to extend the (currently pretty naive) term oracle in+the near future, instead of playing with the verbose (HsExpr Id), we lift it to+PmExpr. All expressions the term oracle does not handle are wrapped by the+constructor PmExprOther. Note that we do not perform substitution in+PmExprOther. Because of this, we do not even print PmExprOther, since they may+refer to variables that are otherwise substituted away.+-}++-- ----------------------------------------------------------------------------+-- ** Types++-- | Lifted expressions for pattern match checking.+data PmExpr = PmExprVar Name+ | PmExprCon ConLike [PmExpr]+ | PmExprLit PmLit+ | PmExprEq PmExpr PmExpr -- Syntactic equality+ | PmExprOther (HsExpr Id) -- Note [PmExprOther in PmExpr]+++mkPmExprData :: DataCon -> [PmExpr] -> PmExpr+mkPmExprData dc args = PmExprCon (RealDataCon dc) args++-- | Literals (simple and overloaded ones) for pattern match checking.+data PmLit = PmSLit HsLit -- simple+ | PmOLit Bool {- is it negated? -} (HsOverLit Id) -- overloaded++-- | Equality between literals for pattern match checking.+eqPmLit :: PmLit -> PmLit -> Bool+eqPmLit (PmSLit l1) (PmSLit l2) = l1 == l2+eqPmLit (PmOLit b1 l1) (PmOLit b2 l2) = b1 == b2 && l1 == l2+ -- See Note [Undecidable Equality for Overloaded Literals]+eqPmLit _ _ = False++{- Note [Undecidable Equality for Overloaded Literals]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Equality on overloaded literals is undecidable in the general case. Consider+the following example:++ instance Num Bool where+ ...+ fromInteger 0 = False -- C-like representation of booleans+ fromInteger _ = True++ f :: Bool -> ()+ f 1 = () -- Clause A+ f 2 = () -- Clause B++Clause B is redundant but to detect this, we should be able to solve the+constraint: False ~ (fromInteger 2 ~ fromInteger 1) which means that we+have to look through function `fromInteger`, whose implementation could+be anything. This poses difficulties for:++1. The expressive power of the check.+ We cannot expect a reasonable implementation of pattern matching to detect+ that fromInteger 2 ~ fromInteger 1 is True, unless we unfold function+ fromInteger. This puts termination at risk and is undecidable in the+ general case.++2. Performance.+ Having an unresolved constraint False ~ (fromInteger 2 ~ fromInteger 1)+ lying around could become expensive really fast. Ticket #11161 illustrates+ how heavy use of overloaded literals can generate plenty of those+ constraints, effectively undermining the term oracle's performance.++3. Error nessages/Warnings.+ What should our message for `f` above be? A reasonable approach would be+ to issue:++ Pattern matches are (potentially) redundant:+ f 2 = ... under the assumption that 1 == 2++ but seems to complex and confusing for the user.++We choose to treat overloaded literals that look different as different. The+impact of this is the following:++ * Redundancy checking is rather conservative, since it cannot see that clause+ B above is redundant.++ * We have instant equality check for overloaded literals (we do not rely on+ the term oracle which is rather expensive, both in terms of performance and+ memory). This significantly improves the performance of functions `covered`+ `uncovered` and `divergent` in deSugar/Check.hs and effectively addresses+ #11161.++ * The warnings issued are simpler.++ * We do not play on the safe side, strictly speaking. The assumption that+ 1 /= 2 makes the redundancy check more conservative but at the same time+ makes its dual (exhaustiveness check) unsafe. This we can live with, mainly+ for two reasons:+ 1. At the moment we do not use the results of the check during compilation+ where this would be a disaster (could result in runtime errors even if+ our function was deemed exhaustive).+ 2. Pattern matcing on literals can never be considered exhaustive unless we+ have a catch-all clause. Hence, this assumption affects mainly the+ appearance of the warnings and is, in practice safe.+-}++nubPmLit :: [PmLit] -> [PmLit]+nubPmLit = nubBy eqPmLit++-- | Term equalities+type SimpleEq = (Id, PmExpr) -- We always use this orientation+type ComplexEq = (PmExpr, PmExpr)++-- | Lift a `SimpleEq` to a `ComplexEq`+toComplex :: SimpleEq -> ComplexEq+toComplex (x,e) = (PmExprVar (idName x), e)++-- | Expression `True'+truePmExpr :: PmExpr+truePmExpr = mkPmExprData trueDataCon []++-- | Expression `False'+falsePmExpr :: PmExpr+falsePmExpr = mkPmExprData falseDataCon []++-- ----------------------------------------------------------------------------+-- ** Predicates on PmExpr++-- | Check if an expression is lifted or not+isNotPmExprOther :: PmExpr -> Bool+isNotPmExprOther (PmExprOther _) = False+isNotPmExprOther _expr = True++-- | Check whether a literal is negated+isNegatedPmLit :: PmLit -> Bool+isNegatedPmLit (PmOLit b _) = b+isNegatedPmLit _other_lit = False++-- | Check whether a PmExpr is syntactically equal to term `True'.+isTruePmExpr :: PmExpr -> Bool+isTruePmExpr (PmExprCon c []) = c == RealDataCon trueDataCon+isTruePmExpr _other_expr = False++-- | Check whether a PmExpr is syntactically equal to term `False'.+isFalsePmExpr :: PmExpr -> Bool+isFalsePmExpr (PmExprCon c []) = c == RealDataCon falseDataCon+isFalsePmExpr _other_expr = False++-- | Check whether a PmExpr is syntactically e+isNilPmExpr :: PmExpr -> Bool+isNilPmExpr (PmExprCon c _) = c == RealDataCon nilDataCon+isNilPmExpr _other_expr = False++-- | Check whether a PmExpr is syntactically equal to (x == y).+-- Since (==) is overloaded and can have an arbitrary implementation, we use+-- the PmExprEq constructor to represent only equalities with non-overloaded+-- literals where it coincides with a syntactic equality check.+isPmExprEq :: PmExpr -> Maybe (PmExpr, PmExpr)+isPmExprEq (PmExprEq e1 e2) = Just (e1,e2)+isPmExprEq _other_expr = Nothing++-- | Check if a DataCon is (:).+isConsDataCon :: DataCon -> Bool+isConsDataCon con = consDataCon == con++-- ----------------------------------------------------------------------------+-- ** Substitution in PmExpr++-- | We return a boolean along with the expression. Hence, if substitution was+-- a no-op, we know that the expression still cannot progress.+substPmExpr :: Name -> PmExpr -> PmExpr -> (PmExpr, Bool)+substPmExpr x e1 e =+ case e of+ PmExprVar z | x == z -> (e1, True)+ | otherwise -> (e, False)+ PmExprCon c ps -> let (ps', bs) = mapAndUnzip (substPmExpr x e1) ps+ in (PmExprCon c ps', or bs)+ PmExprEq ex ey -> let (ex', bx) = substPmExpr x e1 ex+ (ey', by) = substPmExpr x e1 ey+ in (PmExprEq ex' ey', bx || by)+ _other_expr -> (e, False) -- The rest are terminals (We silently ignore+ -- Other). See Note [PmExprOther in PmExpr]++-- | Substitute in a complex equality. We return (Left eq) if the substitution+-- affected the equality or (Right eq) if nothing happened.+substComplexEq :: Name -> PmExpr -> ComplexEq -> Either ComplexEq ComplexEq+substComplexEq x e (ex, ey)+ | bx || by = Left (ex', ey')+ | otherwise = Right (ex', ey')+ where+ (ex', bx) = substPmExpr x e ex+ (ey', by) = substPmExpr x e ey++-- -----------------------------------------------------------------------+-- ** Lift source expressions (HsExpr Id) to PmExpr++lhsExprToPmExpr :: LHsExpr Id -> PmExpr+lhsExprToPmExpr (L _ e) = hsExprToPmExpr e++hsExprToPmExpr :: HsExpr Id -> PmExpr++hsExprToPmExpr (HsVar x) = PmExprVar (idName (unLoc x))+hsExprToPmExpr (HsConLikeOut c) = PmExprVar (conLikeName c)+hsExprToPmExpr (HsOverLit olit) = PmExprLit (PmOLit False olit)+hsExprToPmExpr (HsLit lit) = PmExprLit (PmSLit lit)++hsExprToPmExpr e@(NegApp _ neg_e)+ | PmExprLit (PmOLit False ol) <- synExprToPmExpr neg_e+ = PmExprLit (PmOLit True ol)+ | otherwise = PmExprOther e+hsExprToPmExpr (HsPar (L _ e)) = hsExprToPmExpr e++hsExprToPmExpr e@(ExplicitTuple ps boxity)+ | all tupArgPresent ps = mkPmExprData tuple_con tuple_args+ | otherwise = PmExprOther e+ where+ tuple_con = tupleDataCon boxity (length ps)+ tuple_args = [ lhsExprToPmExpr e | L _ (Present e) <- ps ]++hsExprToPmExpr e@(ExplicitList _elem_ty mb_ol elems)+ | Nothing <- mb_ol = foldr cons nil (map lhsExprToPmExpr elems)+ | otherwise = PmExprOther e {- overloaded list: No PmExprApp -}+ where+ cons x xs = mkPmExprData consDataCon [x,xs]+ nil = mkPmExprData nilDataCon []++hsExprToPmExpr (ExplicitPArr _elem_ty elems)+ = mkPmExprData (parrFakeCon (length elems)) (map lhsExprToPmExpr elems)+++-- we want this but we would have to make everything monadic :/+-- ./compiler/deSugar/DsMonad.hs:397:dsLookupDataCon :: Name -> DsM DataCon+--+-- hsExprToPmExpr (RecordCon c _ binds) = do+-- con <- dsLookupDataCon (unLoc c)+-- args <- mapM lhsExprToPmExpr (hsRecFieldsArgs binds)+-- return (PmExprCon con args)+hsExprToPmExpr e@(RecordCon _ _ _ _) = PmExprOther e++hsExprToPmExpr (HsTick _ e) = lhsExprToPmExpr e+hsExprToPmExpr (HsBinTick _ _ e) = lhsExprToPmExpr e+hsExprToPmExpr (HsTickPragma _ _ _ e) = lhsExprToPmExpr e+hsExprToPmExpr (HsSCC _ _ e) = lhsExprToPmExpr e+hsExprToPmExpr (HsCoreAnn _ _ e) = lhsExprToPmExpr e+hsExprToPmExpr (ExprWithTySig e _) = lhsExprToPmExpr e+hsExprToPmExpr (ExprWithTySigOut e _) = lhsExprToPmExpr e+hsExprToPmExpr (HsWrap _ e) = hsExprToPmExpr e+hsExprToPmExpr e = PmExprOther e -- the rest are not handled by the oracle++synExprToPmExpr :: SyntaxExpr Id -> PmExpr+synExprToPmExpr = hsExprToPmExpr . syn_expr -- ignore the wrappers++{-+%************************************************************************+%* *+ Pretty printing+%* *+%************************************************************************+-}++{- 1. Literals+~~~~~~~~~~~~~~+Starting with a function definition like:++ f :: Int -> Bool+ f 5 = True+ f 6 = True++The uncovered set looks like:+ { var |> False == (var == 5), False == (var == 6) }++Yet, we would like to print this nicely as follows:+ x , where x not one of {5,6}++Function `filterComplex' takes the set of residual constraints and packs+together the negative constraints that refer to the same variable so we can do+just this. Since these variables will be shown to the programmer, we also give+them better names (t1, t2, ..), hence the SDoc in PmNegLitCt.++2. Residual Constraints+~~~~~~~~~~~~~~~~~~~~~~~+Unhandled constraints that refer to HsExpr are typically ignored by the solver+(it does not even substitute in HsExpr so they are even printed as wildcards).+Additionally, the oracle returns a substitution if it succeeds so we apply this+substitution to the vectors before printing them out (see function `pprOne' in+Check.hs) to be more precice.+-}++-- -----------------------------------------------------------------------------+-- ** Transform residual constraints in appropriate form for pretty printing++type PmNegLitCt = (Name, (SDoc, [PmLit]))++filterComplex :: [ComplexEq] -> [PmNegLitCt]+filterComplex = zipWith rename nameList . map mkGroup+ . groupBy name . sortBy order . mapMaybe isNegLitCs+ where+ order x y = compare (fst x) (fst y)+ name x y = fst x == fst y+ mkGroup l = (fst (head l), nubPmLit $ map snd l)+ rename new (old, lits) = (old, (new, lits))++ isNegLitCs (e1,e2)+ | isFalsePmExpr e1, Just (x,y) <- isPmExprEq e2 = isNegLitCs' x y+ | isFalsePmExpr e2, Just (x,y) <- isPmExprEq e1 = isNegLitCs' x y+ | otherwise = Nothing++ isNegLitCs' (PmExprVar x) (PmExprLit l) = Just (x, l)+ isNegLitCs' (PmExprLit l) (PmExprVar x) = Just (x, l)+ isNegLitCs' _ _ = Nothing++ -- Try nice names p,q,r,s,t before using the (ugly) t_i+ nameList :: [SDoc]+ nameList = map text ["p","q","r","s","t"] +++ [ text ('t':show u) | u <- [(0 :: Int)..] ]++-- ----------------------------------------------------------------------------++runPmPprM :: PmPprM a -> [PmNegLitCt] -> (a, [(SDoc,[PmLit])])+runPmPprM m lit_env = (result, mapMaybe is_used lit_env)+ where+ (result, (_lit_env, used)) = runState m (lit_env, emptyNameSet)++ is_used (x,(name, lits))+ | elemNameSet x used = Just (name, lits)+ | otherwise = Nothing++type PmPprM a = State ([PmNegLitCt], NameSet) a+-- (the first part of the state is read only. make it a reader?)++addUsed :: Name -> PmPprM ()+addUsed x = modify (\(negated, used) -> (negated, extendNameSet used x))++checkNegation :: Name -> PmPprM (Maybe SDoc) -- the clean name if it is negated+checkNegation x = do+ negated <- gets fst+ return $ case lookup x negated of+ Just (new, _) -> Just new+ Nothing -> Nothing++-- | Pretty print a pmexpr, but remember to prettify the names of the variables+-- that refer to neg-literals. The ones that cannot be shown are printed as+-- underscores.+pprPmExpr :: PmExpr -> PmPprM SDoc+pprPmExpr (PmExprVar x) = do+ mb_name <- checkNegation x+ case mb_name of+ Just name -> addUsed x >> return name+ Nothing -> return underscore++pprPmExpr (PmExprCon con args) = pprPmExprCon con args+pprPmExpr (PmExprLit l) = return (ppr l)+pprPmExpr (PmExprEq _ _) = return underscore -- don't show+pprPmExpr (PmExprOther _) = return underscore -- don't show++needsParens :: PmExpr -> Bool+needsParens (PmExprVar {}) = False+needsParens (PmExprLit l) = isNegatedPmLit l+needsParens (PmExprEq {}) = False -- will become a wildcard+needsParens (PmExprOther {}) = False -- will become a wildcard+needsParens (PmExprCon (RealDataCon c) es)+ | isTupleDataCon c || isPArrFakeCon c+ || isConsDataCon c || null es = False+ | otherwise = True+needsParens (PmExprCon (PatSynCon _) es) = not (null es)++pprPmExprWithParens :: PmExpr -> PmPprM SDoc+pprPmExprWithParens expr+ | needsParens expr = parens <$> pprPmExpr expr+ | otherwise = pprPmExpr expr++pprPmExprCon :: ConLike -> [PmExpr] -> PmPprM SDoc+pprPmExprCon (RealDataCon con) args+ | isTupleDataCon con = mkTuple <$> mapM pprPmExpr args+ | isPArrFakeCon con = mkPArr <$> mapM pprPmExpr args+ | isConsDataCon con = pretty_list+ where+ mkTuple, mkPArr :: [SDoc] -> SDoc+ mkTuple = parens . fsep . punctuate comma+ mkPArr = paBrackets . fsep . punctuate comma++ -- lazily, to be used in the list case only+ pretty_list :: PmPprM SDoc+ pretty_list = case isNilPmExpr (last list) of+ True -> brackets . fsep . punctuate comma <$> mapM pprPmExpr (init list)+ False -> parens . hcat . punctuate colon <$> mapM pprPmExpr list++ list = list_elements args++ list_elements [x,y]+ | PmExprCon c es <- y, RealDataCon nilDataCon == c+ = ASSERT(null es) [x,y]+ | PmExprCon c es <- y, RealDataCon consDataCon == c+ = x : list_elements es+ | otherwise = [x,y]+ list_elements list = pprPanic "list_elements:" (ppr list)+pprPmExprCon cl args+ | conLikeIsInfix cl = case args of+ [x, y] -> do x' <- pprPmExprWithParens x+ y' <- pprPmExprWithParens y+ return (x' <+> ppr cl <+> y')+ -- can it be infix but have more than two arguments?+ list -> pprPanic "pprPmExprCon:" (ppr list)+ | null args = return (ppr cl)+ | otherwise = do args' <- mapM pprPmExprWithParens args+ return (fsep (ppr cl : args'))++instance Outputable PmLit where+ ppr (PmSLit l) = pmPprHsLit l+ ppr (PmOLit neg l) = (if neg then char '-' else empty) <> ppr l++-- not really useful for pmexprs per se+instance Outputable PmExpr where+ ppr e = fst $ runPmPprM (pprPmExpr e) []
+ deSugar/TmOracle.hs view
@@ -0,0 +1,257 @@+{-+Author: George Karachalias <george.karachalias@cs.kuleuven.be>++The term equality oracle. The main export of the module is function `tmOracle'.+-}++{-# LANGUAGE CPP, MultiWayIf #-}++module TmOracle (++ -- re-exported from PmExpr+ PmExpr(..), PmLit(..), SimpleEq, ComplexEq, PmVarEnv, falsePmExpr,+ eqPmLit, filterComplex, isNotPmExprOther, runPmPprM, lhsExprToPmExpr,+ hsExprToPmExpr, pprPmExprWithParens,++ -- the term oracle+ tmOracle, TmState, initialTmState, solveOneEq, extendSubst, canDiverge,++ -- misc.+ toComplex, exprDeepLookup, pmLitType, flattenPmVarEnv+ ) where++#include "HsVersions.h"++import PmExpr++import Id+import Name+import Type+import HsLit+import TcHsSyn+import MonadUtils+import Util++import NameEnv++{-+%************************************************************************+%* *+ The term equality oracle+%* *+%************************************************************************+-}++-- | The type of substitutions.+type PmVarEnv = NameEnv PmExpr++-- | The environment of the oracle contains+-- 1. A Bool (are there any constraints we cannot handle? (PmExprOther)).+-- 2. A substitution we extend with every step and return as a result.+type TmOracleEnv = (Bool, PmVarEnv)++-- | Check whether a constraint (x ~ BOT) can succeed,+-- given the resulting state of the term oracle.+canDiverge :: Name -> TmState -> Bool+canDiverge x (standby, (_unhandled, env))+ -- If the variable seems not evaluated, there is a possibility for+ -- constraint x ~ BOT to be satisfiable.+ | PmExprVar y <- varDeepLookup env x -- seems not forced+ -- If it is involved (directly or indirectly) in any equality in the+ -- worklist, we can assume that it is already indirectly evaluated,+ -- as a side-effect of equality checking. If not, then we can assume+ -- that the constraint is satisfiable.+ = not $ any (isForcedByEq x) standby || any (isForcedByEq y) standby+ -- Variable x is already in WHNF so the constraint is non-satisfiable+ | otherwise = False++ where+ isForcedByEq :: Name -> ComplexEq -> Bool+ isForcedByEq y (e1, e2) = varIn y e1 || varIn y e2++-- | Check whether a variable is in the free variables of an expression+varIn :: Name -> PmExpr -> Bool+varIn x e = case e of+ PmExprVar y -> x == y+ PmExprCon _ es -> any (x `varIn`) es+ PmExprLit _ -> False+ PmExprEq e1 e2 -> (x `varIn` e1) || (x `varIn` e2)+ PmExprOther _ -> False++-- | Flatten the DAG (Could be improved in terms of performance.).+flattenPmVarEnv :: PmVarEnv -> PmVarEnv+flattenPmVarEnv env = mapNameEnv (exprDeepLookup env) env++-- | The state of the term oracle (includes complex constraints that cannot+-- progress unless we get more information).+type TmState = ([ComplexEq], TmOracleEnv)++-- | Initial state of the oracle.+initialTmState :: TmState+initialTmState = ([], (False, emptyNameEnv))++-- | Solve a complex equality (top-level).+solveOneEq :: TmState -> ComplexEq -> Maybe TmState+solveOneEq solver_env@(_,(_,env)) complex+ = solveComplexEq solver_env -- do the actual *merging* with existing state+ $ simplifyComplexEq -- simplify as much as you can+ $ applySubstComplexEq env complex -- replace everything we already know++-- | Solve a complex equality.+solveComplexEq :: TmState -> ComplexEq -> Maybe TmState+solveComplexEq solver_state@(standby, (unhandled, env)) eq@(e1, e2) = case eq of+ -- We cannot do a thing about these cases+ (PmExprOther _,_) -> Just (standby, (True, env))+ (_,PmExprOther _) -> Just (standby, (True, env))++ (PmExprLit l1, PmExprLit l2) -> case eqPmLit l1 l2 of+ -- See Note [Undecidable Equality for Overloaded Literals]+ True -> Just solver_state+ False -> Nothing++ (PmExprCon c1 ts1, PmExprCon c2 ts2)+ | c1 == c2 -> foldlM solveComplexEq solver_state (zip ts1 ts2)+ | otherwise -> Nothing+ (PmExprCon _ [], PmExprEq t1 t2)+ | isTruePmExpr e1 -> solveComplexEq solver_state (t1, t2)+ | isFalsePmExpr e1 -> Just (eq:standby, (unhandled, env))+ (PmExprEq t1 t2, PmExprCon _ [])+ | isTruePmExpr e2 -> solveComplexEq solver_state (t1, t2)+ | isFalsePmExpr e2 -> Just (eq:standby, (unhandled, env))++ (PmExprVar x, PmExprVar y)+ | x == y -> Just solver_state+ | otherwise -> extendSubstAndSolve x e2 solver_state++ (PmExprVar x, _) -> extendSubstAndSolve x e2 solver_state+ (_, PmExprVar x) -> extendSubstAndSolve x e1 solver_state++ (PmExprEq _ _, PmExprEq _ _) -> Just (eq:standby, (unhandled, env))++ _ -> Just (standby, (True, env)) -- I HATE CATCH-ALLS++-- | Extend the substitution and solve the (possibly updated) constraints.+extendSubstAndSolve :: Name -> PmExpr -> TmState -> Maybe TmState+extendSubstAndSolve x e (standby, (unhandled, env))+ = foldlM solveComplexEq new_incr_state (map simplifyComplexEq changed)+ where+ -- Apply the substitution to the worklist and partition them to the ones+ -- that had some progress and the rest. Then, recurse over the ones that+ -- had some progress. Careful about performance:+ -- See Note [Representation of Term Equalities] in deSugar/Check.hs+ (changed, unchanged) = partitionWith (substComplexEq x e) standby+ new_incr_state = (unchanged, (unhandled, extendNameEnv env x e))++-- | When we know that a variable is fresh, we do not actually have to+-- check whether anything changes, we know that nothing does. Hence,+-- `extendSubst` simply extends the substitution, unlike what+-- `extendSubstAndSolve` does.+extendSubst :: Id -> PmExpr -> TmState -> TmState+extendSubst y e (standby, (unhandled, env))+ | isNotPmExprOther simpl_e+ = (standby, (unhandled, extendNameEnv env x simpl_e))+ | otherwise = (standby, (True, env))+ where+ x = idName y+ simpl_e = fst $ simplifyPmExpr $ exprDeepLookup env e++-- | Simplify a complex equality.+simplifyComplexEq :: ComplexEq -> ComplexEq+simplifyComplexEq (e1, e2) = (fst $ simplifyPmExpr e1, fst $ simplifyPmExpr e2)++-- | Simplify an expression. The boolean indicates if there has been any+-- simplification or if the operation was a no-op.+simplifyPmExpr :: PmExpr -> (PmExpr, Bool)+-- See Note [Deep equalities]+simplifyPmExpr e = case e of+ PmExprCon c ts -> case mapAndUnzip simplifyPmExpr ts of+ (ts', bs) -> (PmExprCon c ts', or bs)+ PmExprEq t1 t2 -> simplifyEqExpr t1 t2+ _other_expr -> (e, False) -- the others are terminals++-- | Simplify an equality expression. The equality is given in parts.+simplifyEqExpr :: PmExpr -> PmExpr -> (PmExpr, Bool)+-- See Note [Deep equalities]+simplifyEqExpr e1 e2 = case (e1, e2) of+ -- Varables+ (PmExprVar x, PmExprVar y)+ | x == y -> (truePmExpr, True)++ -- Literals+ (PmExprLit l1, PmExprLit l2) -> case eqPmLit l1 l2 of+ -- See Note [Undecidable Equality for Overloaded Literals]+ True -> (truePmExpr, True)+ False -> (falsePmExpr, True)++ -- Can potentially be simplified+ (PmExprEq {}, _) -> case (simplifyPmExpr e1, simplifyPmExpr e2) of+ ((e1', True ), (e2', _ )) -> simplifyEqExpr e1' e2'+ ((e1', _ ), (e2', True )) -> simplifyEqExpr e1' e2'+ ((e1', False), (e2', False)) -> (PmExprEq e1' e2', False) -- cannot progress+ (_, PmExprEq {}) -> case (simplifyPmExpr e1, simplifyPmExpr e2) of+ ((e1', True ), (e2', _ )) -> simplifyEqExpr e1' e2'+ ((e1', _ ), (e2', True )) -> simplifyEqExpr e1' e2'+ ((e1', False), (e2', False)) -> (PmExprEq e1' e2', False) -- cannot progress++ -- Constructors+ (PmExprCon c1 ts1, PmExprCon c2 ts2)+ | c1 == c2 ->+ let (ts1', bs1) = mapAndUnzip simplifyPmExpr ts1+ (ts2', bs2) = mapAndUnzip simplifyPmExpr ts2+ (tss, _bss) = zipWithAndUnzip simplifyEqExpr ts1' ts2'+ worst_case = PmExprEq (PmExprCon c1 ts1') (PmExprCon c2 ts2')+ in if | not (or bs1 || or bs2) -> (worst_case, False) -- no progress+ | all isTruePmExpr tss -> (truePmExpr, True)+ | any isFalsePmExpr tss -> (falsePmExpr, True)+ | otherwise -> (worst_case, False)+ | otherwise -> (falsePmExpr, True)++ -- We cannot do anything about the rest..+ _other_equality -> (original, False)++ where+ original = PmExprEq e1 e2 -- reconstruct equality++-- | Apply an (un-flattened) substitution to a simple equality.+applySubstComplexEq :: PmVarEnv -> ComplexEq -> ComplexEq+applySubstComplexEq env (e1,e2) = (exprDeepLookup env e1, exprDeepLookup env e2)++-- | Apply an (un-flattened) substitution to a variable.+varDeepLookup :: PmVarEnv -> Name -> PmExpr+varDeepLookup env x+ | Just e <- lookupNameEnv env x = exprDeepLookup env e -- go deeper+ | otherwise = PmExprVar x -- terminal+{-# INLINE varDeepLookup #-}++-- | Apply an (un-flattened) substitution to an expression.+exprDeepLookup :: PmVarEnv -> PmExpr -> PmExpr+exprDeepLookup env (PmExprVar x) = varDeepLookup env x+exprDeepLookup env (PmExprCon c es) = PmExprCon c (map (exprDeepLookup env) es)+exprDeepLookup env (PmExprEq e1 e2) = PmExprEq (exprDeepLookup env e1)+ (exprDeepLookup env e2)+exprDeepLookup _ other_expr = other_expr -- PmExprLit, PmExprOther++-- | External interface to the term oracle.+tmOracle :: TmState -> [ComplexEq] -> Maybe TmState+tmOracle tm_state eqs = foldlM solveOneEq tm_state eqs++-- | Type of a PmLit+pmLitType :: PmLit -> Type -- should be in PmExpr but gives cyclic imports :(+pmLitType (PmSLit lit) = hsLitType lit+pmLitType (PmOLit _ lit) = overLitType lit++{- Note [Deep equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~+Solving nested equalities is the most difficult part. The general strategy+is the following:++ * Equalities of the form (True ~ (e1 ~ e2)) are transformed to just+ (e1 ~ e2) and then treated recursively.++ * Equalities of the form (False ~ (e1 ~ e2)) cannot be analyzed unless+ we know more about the inner equality (e1 ~ e2). That's exactly what+ `simplifyEqExpr' tries to do: It takes e1 and e2 and either returns+ truePmExpr, falsePmExpr or (e1' ~ e2') in case it is uncertain. Note+ that it is not e but rather e', since it may perform some+ simplifications deeper.+-}
+ ghc.cabal view
@@ -0,0 +1,640 @@+Name: ghc+Version: 8.2.1+License: BSD3+License-File: LICENSE+Author: The GHC Team+Maintainer: glasgow-haskell-users@haskell.org+Homepage: http://www.haskell.org/ghc/+Synopsis: The GHC API+Description:+ GHC's functionality can be useful for more things than just+ compiling Haskell programs. Important use cases are programs+ that analyse (and perhaps transform) Haskell code. Others+ include loading Haskell code dynamically in a GHCi-like manner.+ For this reason, a lot of GHC's functionality is made available+ through this package.+Category: Development+Build-Type: Simple+Cabal-Version: >=2.0++extra-source-files:+ utils/md5.h+ Unique.h+ HsVersions.h+ nativeGen/NCG.h+ parser/cutils.h+ autogen/ghc_boot_platform.h+ autogen/CodeGen.Platform.hs+ autogen/Config.hs+ autogen/GHCConstantsHaskellExports.hs+ autogen/GHCConstantsHaskellType.hs+ autogen/GHCConstantsHaskellWrappers.hs+ autogen/*.hs-incl+++Flag terminfo+ Description: Build GHC with terminfo support on non-Windows platforms.+ Default: True+ Manual: True++Flag buildable+ Description: Make this package buildable (highly experimental)+ Default: False+ Manual: True++Library+ -- The generated code in autogen/ has been generated for a linux/x86_64 target+ -- So everything else is definitely not working...+ if !(os(linux) && arch(x86_64) && impl(ghc == 8.2.1))+ build-depends: base<0++ -- ...while this package may in theory allow to reinstall lib:ghc+ -- under very limited constraints, this most likely could fail in+ -- weird ways (e.g. mismatched tag numbers, GHC panics, etc), and+ -- since cabal doesn't mark this package as non-upgradable, we+ -- declare this package out of reach to the cabal solver by default+ -- here+ if !flag(buildable)+ build-depends: base<0++ Default-Language: Haskell2010+ Exposed: False++ Build-Depends: base == 4.10.*,+ deepseq >= 1.4 && < 1.5,+ directory >= 1 && < 1.4,+ process >= 1 && < 1.7,+ bytestring >= 0.9 && < 0.11,+ binary == 0.8.*,+ time >= 1.4 && < 1.9,+ containers >= 0.5 && < 0.6,+ array >= 0.1 && < 0.6,+ filepath >= 1 && < 1.5,+ template-haskell == 2.12.*,+ hpc == 0.6.*,+ transformers == 0.5.*,+ ghc-boot == 8.2.1,+ ghc-boot-th == 8.2.1,+ ghci == 8.2.1,+ hoopl >= 3.10.2 && < 3.11++ if os(windows)+ Build-Depends: Win32 >= 2.3 && < 2.6+ else+ if flag(terminfo)+ Build-Depends: terminfo == 0.4.*+ Build-Depends: unix == 2.7.*++ build-tools: alex ^>= 3.2.1, happy ^>= 1.19.5++ GHC-Options: -Wall -fno-warn-name-shadowing++ -- if flag(ghci)+ -- CPP-Options: -DGHCI+ -- Include-Dirs: ../rts/dist/build++ Other-Extensions:+ BangPatterns+ CPP+ DataKinds+ DeriveDataTypeable+ DeriveFoldable+ DeriveFunctor+ DeriveTraversable+ DisambiguateRecordFields+ ExplicitForAll+ FlexibleContexts+ FlexibleInstances+ GADTs+ GeneralizedNewtypeDeriving+ MagicHash+ MultiParamTypeClasses+ NamedFieldPuns+ NondecreasingIndentation+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ StandaloneDeriving+ Trustworthy+ TupleSections+ TypeFamilies+ TypeSynonymInstances+ UnboxedTuples+ UndecidableInstances++ Include-Dirs: . parser utils++ -- We need to set the unit id to ghc (without a version number)+ -- as it's magic. But we can't set it for old versions of GHC (e.g.+ -- when bootstrapping) because those versions of GHC don't understand+ -- that GHC is wired-in.+ if impl ( ghc >= 7.11 )+ GHC-Options: -this-unit-id ghc+ else+ if impl( ghc >= 7.9 )+ GHC-Options: -this-package-key ghc++ cpp-options: -DSTAGE=2++ Install-Includes: HsVersions.h, ghc_boot_platform.h++ c-sources:+ parser/cutils.c+ ghci/keepCAFsForGHCi.c+ cbits/genSym.c++ hs-source-dirs:+ autogen++ include-dirs:+ autogen++ hs-source-dirs:+ backpack+ basicTypes+ cmm+ codeGen+ coreSyn+ deSugar+ ghci+ hsSyn+ iface+ llvmGen+ main+ nativeGen+ parser+ prelude+ profiling+ rename+ simplCore+ simplStg+ specialise+ stgSyn+ stranal+ typecheck+ types+ utils+ vectorise++ Exposed-Modules:+ DriverBkp+ BkpSyn+ NameShape+ RnModIface+ Avail+ BasicTypes+ ConLike+ DataCon+ PatSyn+ Demand+ Debug+ Exception+ FieldLabel+ GhcMonad+ Hooks+ Id+ IdInfo+ Lexeme+ Literal+ Llvm+ Llvm.AbsSyn+ Llvm.MetaData+ Llvm.PpLlvm+ Llvm.Types+ LlvmCodeGen+ LlvmCodeGen.Base+ LlvmCodeGen.CodeGen+ LlvmCodeGen.Data+ LlvmCodeGen.Ppr+ LlvmCodeGen.Regs+ LlvmMangler+ MkId+ Module+ Name+ NameEnv+ NameSet+ OccName+ RdrName+ NameCache+ SrcLoc+ UniqSupply+ Unique+ Var+ VarEnv+ VarSet+ UnVarGraph+ BlockId+ CLabel+ Cmm+ CmmBuildInfoTables+ CmmPipeline+ CmmCallConv+ CmmCommonBlockElim+ CmmImplementSwitchPlans+ CmmContFlowOpt+ CmmExpr+ CmmInfo+ CmmLex+ CmmLint+ CmmLive+ CmmMachOp+ CmmMonad+ CmmSwitch+ CmmNode+ CmmOpt+ CmmParse+ CmmProcPoint+ CmmSink+ CmmType+ CmmUtils+ CmmLayoutStack+ MkGraph+ PprBase+ PprC+ PprCmm+ PprCmmDecl+ PprCmmExpr+ Bitmap+ CodeGen.Platform+ CodeGen.Platform.ARM+ CodeGen.Platform.ARM64+ CodeGen.Platform.NoRegs+ CodeGen.Platform.PPC+ CodeGen.Platform.PPC_Darwin+ CodeGen.Platform.SPARC+ CodeGen.Platform.X86+ CodeGen.Platform.X86_64+ CgUtils+ StgCmm+ StgCmmBind+ StgCmmClosure+ StgCmmCon+ StgCmmEnv+ StgCmmExpr+ StgCmmForeign+ StgCmmHeap+ StgCmmHpc+ StgCmmArgRep+ StgCmmLayout+ StgCmmMonad+ StgCmmPrim+ StgCmmProf+ StgCmmTicky+ StgCmmUtils+ StgCmmExtCode+ SMRep+ CoreArity+ CoreFVs+ CoreLint+ CorePrep+ CoreSubst+ CoreOpt+ CoreSyn+ TrieMap+ CoreTidy+ CoreUnfold+ CoreUtils+ CoreSeq+ CoreStats+ MkCore+ PprCore+ PmExpr+ TmOracle+ Check+ Coverage+ Desugar+ DsArrows+ DsBinds+ DsCCall+ DsExpr+ DsForeign+ DsGRHSs+ DsListComp+ DsMonad+ DsUsage+ DsUtils+ Match+ MatchCon+ MatchLit+ HsBinds+ HsDecls+ HsDoc+ HsExpr+ HsImpExp+ HsLit+ PlaceHolder+ HsPat+ HsSyn+ HsTypes+ HsUtils+ HsDumpAst+ BinIface+ BinFingerprint+ BuildTyCl+ IfaceEnv+ IfaceSyn+ IfaceType+ ToIface+ LoadIface+ MkIface+ TcIface+ FlagChecker+ Annotations+ CmdLineParser+ CodeOutput+ Config+ Constants+ DriverMkDepend+ DriverPhases+ PipelineMonad+ DriverPipeline+ DynFlags+ ErrUtils+ Finder+ GHC+ GhcMake+ GhcPlugins+ DynamicLoading+ HeaderInfo+ HscMain+ HscStats+ HscTypes+ InteractiveEval+ InteractiveEvalTypes+ PackageConfig+ Packages+ PlatformConstants+ Plugins+ TcPluginM+ PprTyThing+ StaticPtrTable+ SysTools+ SysTools.Terminal+ Elf+ TidyPgm+ Ctype+ HaddockUtils+ Lexer+ OptCoercion+ Parser+ RdrHsSyn+ ApiAnnotation+ ForeignCall+ KnownUniques+ PrelInfo+ PrelNames+ PrelRules+ PrimOp+ TysPrim+ TysWiredIn+ CostCentre+ ProfInit+ SCCfinal+ RnBinds+ RnEnv+ RnExpr+ RnHsDoc+ RnNames+ RnPat+ RnSource+ RnSplice+ RnTypes+ CoreMonad+ CSE+ FloatIn+ FloatOut+ LiberateCase+ OccurAnal+ SAT+ SetLevels+ SimplCore+ SimplEnv+ SimplMonad+ SimplUtils+ Simplify+ SimplStg+ StgStats+ StgCse+ UnariseStg+ RepType+ Rules+ SpecConstr+ Specialise+ CoreToStg+ StgLint+ StgSyn+ CallArity+ DmdAnal+ WorkWrap+ WwLib+ FamInst+ Inst+ TcAnnotations+ TcArrows+ TcBinds+ TcSigs+ TcClassDcl+ TcDefaults+ TcDeriv+ TcDerivInfer+ TcDerivUtils+ TcEnv+ TcExpr+ TcForeign+ TcGenDeriv+ TcGenFunctor+ TcGenGenerics+ TcHsSyn+ TcHsType+ TcInstDcls+ TcMType+ TcValidity+ TcMatches+ TcPat+ TcPatSyn+ TcRnDriver+ TcBackpack+ TcRnExports+ TcRnMonad+ TcRnTypes+ TcRules+ TcSimplify+ TcErrors+ TcTyClsDecls+ TcTyDecls+ TcTypeable+ TcType+ TcEvidence+ TcUnify+ TcInteract+ TcCanonical+ TcFlatten+ TcSMonad+ TcTypeNats+ TcSplice+ Class+ Coercion+ DsMeta+ THNames+ FamInstEnv+ FunDeps+ InstEnv+ TyCon+ CoAxiom+ Kind+ Type+ TyCoRep+ Unify+ Bag+ Binary+ BooleanFormula+ BufWrite+ Digraph+ Encoding+ FastFunctions+ FastMutInt+ FastString+ FastStringEnv+ Fingerprint+ FiniteMap+ FV+ GraphBase+ GraphColor+ GraphOps+ GraphPpr+ IOEnv+ Json+ ListSetOps+ ListT+ Maybes+ MonadUtils+ OrdList+ Outputable+ Pair+ Panic+ PprColour+ Pretty+ State+ Stream+ StringBuffer+ UniqDFM+ UniqDSet+ UniqFM+ UniqSet+ Util+ Vectorise.Builtins.Base+ Vectorise.Builtins.Initialise+ Vectorise.Builtins+ Vectorise.Monad.Base+ Vectorise.Monad.Naming+ Vectorise.Monad.Local+ Vectorise.Monad.Global+ Vectorise.Monad.InstEnv+ Vectorise.Monad+ Vectorise.Utils.Base+ Vectorise.Utils.Closure+ Vectorise.Utils.Hoisting+ Vectorise.Utils.PADict+ Vectorise.Utils.Poly+ Vectorise.Utils+ Vectorise.Generic.Description+ Vectorise.Generic.PAMethods+ Vectorise.Generic.PADict+ Vectorise.Generic.PData+ Vectorise.Type.Env+ Vectorise.Type.Type+ Vectorise.Type.TyConDecl+ Vectorise.Type.Classify+ Vectorise.Convert+ Vectorise.Vect+ Vectorise.Var+ Vectorise.Env+ Vectorise.Exp+ Vectorise+ Hoopl.Dataflow+ Hoopl+-- CgInfoTbls used in ghci/DebuggerUtils+-- CgHeapery mkVirtHeapOffsets used in ghci++ Exposed-Modules:+ AsmCodeGen+ TargetReg+ NCGMonad+ Instruction+ Format+ Reg+ RegClass+ PIC+ Platform+ CPrim+ X86.Regs+ X86.RegInfo+ X86.Instr+ X86.Cond+ X86.Ppr+ X86.CodeGen+ PPC.Regs+ PPC.RegInfo+ PPC.Instr+ PPC.Cond+ PPC.Ppr+ PPC.CodeGen+ SPARC.Base+ SPARC.Regs+ SPARC.Imm+ SPARC.AddrMode+ SPARC.Cond+ SPARC.Instr+ SPARC.Stack+ SPARC.ShortcutJump+ SPARC.Ppr+ SPARC.CodeGen+ SPARC.CodeGen.Amode+ SPARC.CodeGen.Base+ SPARC.CodeGen.CondCode+ SPARC.CodeGen.Gen32+ SPARC.CodeGen.Gen64+ SPARC.CodeGen.Sanity+ SPARC.CodeGen.Expand+ RegAlloc.Liveness+ RegAlloc.Graph.Main+ RegAlloc.Graph.Stats+ RegAlloc.Graph.ArchBase+ RegAlloc.Graph.ArchX86+ RegAlloc.Graph.Coalesce+ RegAlloc.Graph.Spill+ RegAlloc.Graph.SpillClean+ RegAlloc.Graph.SpillCost+ RegAlloc.Graph.TrivColorable+ RegAlloc.Linear.Main+ RegAlloc.Linear.JoinToTargets+ RegAlloc.Linear.State+ RegAlloc.Linear.Stats+ RegAlloc.Linear.FreeRegs+ RegAlloc.Linear.StackMap+ RegAlloc.Linear.Base+ RegAlloc.Linear.X86.FreeRegs+ RegAlloc.Linear.X86_64.FreeRegs+ RegAlloc.Linear.PPC.FreeRegs+ RegAlloc.Linear.SPARC.FreeRegs+ Dwarf+ Dwarf.Types+ Dwarf.Constants+ Convert+ ByteCodeTypes+ ByteCodeAsm+ ByteCodeGen+ ByteCodeInstr+ ByteCodeItbls+ ByteCodeLink+ Debugger+ Linker+ RtClosureInspect+ DebuggerUtils+ GHCi++ -- ghc:Serialized moved to ghc-boot:GHC.Serialized. So for+ -- compatibility with GHC 7.10 and earlier, we reexport it+ -- under the old name.+ reexported-modules:+ ghc-boot:GHC.Serialized as Serialized
+ ghci/ByteCodeAsm.hs view
@@ -0,0 +1,538 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, RecordWildCards #-}+{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}+--+-- (c) The University of Glasgow 2002-2006+--++-- | ByteCodeLink: Bytecode assembler and linker+module ByteCodeAsm (+ assembleBCOs, assembleOneBCO,++ bcoFreeNames,+ SizedSeq, sizeSS, ssElts,+ iNTERP_STACK_CHECK_THRESH+ ) where++#include "HsVersions.h"++import ByteCodeInstr+import ByteCodeItbls+import ByteCodeTypes+import GHCi.RemoteTypes+import GHCi++import HscTypes+import Name+import NameSet+import Literal+import TyCon+import FastString+import StgCmmLayout ( ArgRep(..) )+import SMRep+import DynFlags+import Outputable+import Platform+import Util+import Unique+import UniqDSet++-- From iserv+import SizedSeq++import Control.Monad+import Control.Monad.ST ( runST )+import Control.Monad.Trans.Class+import Control.Monad.Trans.State.Strict++import Data.Array.MArray++import qualified Data.Array.Unboxed as Array+import Data.Array.Base ( UArray(..) )++import Data.Array.Unsafe( castSTUArray )++import Foreign+import Data.Char ( ord )+import Data.List+import Data.Map (Map)+import Data.Maybe (fromMaybe)+import qualified Data.Map as Map++-- -----------------------------------------------------------------------------+-- Unlinked BCOs++-- CompiledByteCode represents the result of byte-code+-- compiling a bunch of functions and data types++-- | Finds external references. Remember to remove the names+-- defined by this group of BCOs themselves+bcoFreeNames :: UnlinkedBCO -> UniqDSet Name+bcoFreeNames bco+ = bco_refs bco `uniqDSetMinusUniqSet` mkNameSet [unlinkedBCOName bco]+ where+ bco_refs (UnlinkedBCO _ _ _ _ nonptrs ptrs)+ = unionManyUniqDSets (+ mkUniqDSet [ n | BCOPtrName n <- ssElts ptrs ] :+ mkUniqDSet [ n | BCONPtrItbl n <- ssElts nonptrs ] :+ map bco_refs [ bco | BCOPtrBCO bco <- ssElts ptrs ]+ )++-- -----------------------------------------------------------------------------+-- The bytecode assembler++-- The object format for bytecodes is: 16 bits for the opcode, and 16+-- for each field -- so the code can be considered a sequence of+-- 16-bit ints. Each field denotes either a stack offset or number of+-- items on the stack (eg SLIDE), and index into the pointer table (eg+-- PUSH_G), an index into the literal table (eg PUSH_I/D/L), or a+-- bytecode address in this BCO.++-- Top level assembler fn.+assembleBCOs+ :: HscEnv -> [ProtoBCO Name] -> [TyCon] -> [RemotePtr ()]+ -> Maybe ModBreaks+ -> IO CompiledByteCode+assembleBCOs hsc_env proto_bcos tycons top_strs modbreaks = do+ itblenv <- mkITbls hsc_env tycons+ bcos <- mapM (assembleBCO (hsc_dflags hsc_env)) proto_bcos+ (bcos',ptrs) <- mallocStrings hsc_env bcos+ return CompiledByteCode+ { bc_bcos = bcos'+ , bc_itbls = itblenv+ , bc_ffis = concat (map protoBCOFFIs proto_bcos)+ , bc_strs = top_strs ++ ptrs+ , bc_breaks = modbreaks+ }++-- Find all the literal strings and malloc them together. We want to+-- do this because:+--+-- a) It should be done when we compile the module, not each time we relink it+-- b) For -fexternal-interpreter It's more efficient to malloc the strings+-- as a single batch message, especially when compiling in parallel.+--+mallocStrings :: HscEnv -> [UnlinkedBCO] -> IO ([UnlinkedBCO], [RemotePtr ()])+mallocStrings hsc_env ulbcos = do+ let bytestrings = reverse (execState (mapM_ collect ulbcos) [])+ ptrs <- iservCmd hsc_env (MallocStrings bytestrings)+ return (evalState (mapM splice ulbcos) ptrs, ptrs)+ where+ splice bco@UnlinkedBCO{..} = do+ lits <- mapM spliceLit unlinkedBCOLits+ ptrs <- mapM splicePtr unlinkedBCOPtrs+ return bco { unlinkedBCOLits = lits, unlinkedBCOPtrs = ptrs }++ spliceLit (BCONPtrStr _) = do+ (RemotePtr p : rest) <- get+ put rest+ return (BCONPtrWord (fromIntegral p))+ spliceLit other = return other++ splicePtr (BCOPtrBCO bco) = BCOPtrBCO <$> splice bco+ splicePtr other = return other++ collect UnlinkedBCO{..} = do+ mapM_ collectLit unlinkedBCOLits+ mapM_ collectPtr unlinkedBCOPtrs++ collectLit (BCONPtrStr bs) = do+ strs <- get+ put (bs:strs)+ collectLit _ = return ()++ collectPtr (BCOPtrBCO bco) = collect bco+ collectPtr _ = return ()+++assembleOneBCO :: HscEnv -> ProtoBCO Name -> IO UnlinkedBCO+assembleOneBCO hsc_env pbco = do+ ubco <- assembleBCO (hsc_dflags hsc_env) pbco+ ([ubco'], _ptrs) <- mallocStrings hsc_env [ubco]+ return ubco'++assembleBCO :: DynFlags -> ProtoBCO Name -> IO UnlinkedBCO+assembleBCO dflags (ProtoBCO nm instrs bitmap bsize arity _origin _malloced) = do+ -- pass 1: collect up the offsets of the local labels.+ let asm = mapM_ (assembleI dflags) instrs++ initial_offset = 0++ -- Jump instructions are variable-sized, there are long and short variants+ -- depending on the magnitude of the offset. However, we can't tell what+ -- size instructions we will need until we have calculated the offsets of+ -- the labels, which depends on the size of the instructions... So we+ -- first create the label environment assuming that all jumps are short,+ -- and if the final size is indeed small enough for short jumps, we are+ -- done. Otherwise, we repeat the calculation, and we force all jumps in+ -- this BCO to be long.+ (n_insns0, lbl_map0) = inspectAsm dflags False initial_offset asm+ ((n_insns, lbl_map), long_jumps)+ | isLarge n_insns0 = (inspectAsm dflags True initial_offset asm, True)+ | otherwise = ((n_insns0, lbl_map0), False)++ env :: Word16 -> Word+ env lbl = fromMaybe+ (pprPanic "assembleBCO.findLabel" (ppr lbl))+ (Map.lookup lbl lbl_map)++ -- pass 2: run assembler and generate instructions, literals and pointers+ let initial_state = (emptySS, emptySS, emptySS)+ (final_insns, final_lits, final_ptrs) <- flip execStateT initial_state $ runAsm dflags long_jumps env asm++ -- precomputed size should be equal to final size+ ASSERT(n_insns == sizeSS final_insns) return ()++ let asm_insns = ssElts final_insns+ insns_arr = Array.listArray (0, fromIntegral n_insns - 1) asm_insns+ bitmap_arr = mkBitmapArray bsize bitmap+ ul_bco = UnlinkedBCO nm arity insns_arr bitmap_arr final_lits final_ptrs++ -- 8 Aug 01: Finalisers aren't safe when attached to non-primitive+ -- objects, since they might get run too early. Disable this until+ -- we figure out what to do.+ -- when (notNull malloced) (addFinalizer ul_bco (mapM_ zonk malloced))++ return ul_bco++mkBitmapArray :: Word16 -> [StgWord] -> UArray Int Word+-- Here the return type must be an array of Words, not StgWords,+-- because the underlying ByteArray# will end up as a component+-- of a BCO object.+mkBitmapArray bsize bitmap+ = Array.listArray (0, length bitmap) $+ fromIntegral bsize : map (fromInteger . fromStgWord) bitmap++-- instrs nonptrs ptrs+type AsmState = (SizedSeq Word16,+ SizedSeq BCONPtr,+ SizedSeq BCOPtr)++data Operand+ = Op Word+ | SmallOp Word16+ | LabelOp Word16+-- (unused) | LargeOp Word++data Assembler a+ = AllocPtr (IO BCOPtr) (Word -> Assembler a)+ | AllocLit [BCONPtr] (Word -> Assembler a)+ | AllocLabel Word16 (Assembler a)+ | Emit Word16 [Operand] (Assembler a)+ | NullAsm a++instance Functor Assembler where+ fmap = liftM++instance Applicative Assembler where+ pure = NullAsm+ (<*>) = ap++instance Monad Assembler where+ NullAsm x >>= f = f x+ AllocPtr p k >>= f = AllocPtr p (k >=> f)+ AllocLit l k >>= f = AllocLit l (k >=> f)+ AllocLabel lbl k >>= f = AllocLabel lbl (k >>= f)+ Emit w ops k >>= f = Emit w ops (k >>= f)++ioptr :: IO BCOPtr -> Assembler Word+ioptr p = AllocPtr p return++ptr :: BCOPtr -> Assembler Word+ptr = ioptr . return++lit :: [BCONPtr] -> Assembler Word+lit l = AllocLit l return++label :: Word16 -> Assembler ()+label w = AllocLabel w (return ())++emit :: Word16 -> [Operand] -> Assembler ()+emit w ops = Emit w ops (return ())++type LabelEnv = Word16 -> Word++largeOp :: Bool -> Operand -> Bool+largeOp long_jumps op = case op of+ SmallOp _ -> False+ Op w -> isLarge w+ LabelOp _ -> long_jumps+-- LargeOp _ -> True++runAsm :: DynFlags -> Bool -> LabelEnv -> Assembler a -> StateT AsmState IO a+runAsm dflags long_jumps e = go+ where+ go (NullAsm x) = return x+ go (AllocPtr p_io k) = do+ p <- lift p_io+ w <- state $ \(st_i0,st_l0,st_p0) ->+ let st_p1 = addToSS st_p0 p+ in (sizeSS st_p0, (st_i0,st_l0,st_p1))+ go $ k w+ go (AllocLit lits k) = do+ w <- state $ \(st_i0,st_l0,st_p0) ->+ let st_l1 = addListToSS st_l0 lits+ in (sizeSS st_l0, (st_i0,st_l1,st_p0))+ go $ k w+ go (AllocLabel _ k) = go k+ go (Emit w ops k) = do+ let largeOps = any (largeOp long_jumps) ops+ opcode+ | largeOps = largeArgInstr w+ | otherwise = w+ words = concatMap expand ops+ expand (SmallOp w) = [w]+ expand (LabelOp w) = expand (Op (e w))+ expand (Op w) = if largeOps then largeArg dflags w else [fromIntegral w]+-- expand (LargeOp w) = largeArg dflags w+ state $ \(st_i0,st_l0,st_p0) ->+ let st_i1 = addListToSS st_i0 (opcode : words)+ in ((), (st_i1,st_l0,st_p0))+ go k++type LabelEnvMap = Map Word16 Word++data InspectState = InspectState+ { instrCount :: !Word+ , ptrCount :: !Word+ , litCount :: !Word+ , lblEnv :: LabelEnvMap+ }++inspectAsm :: DynFlags -> Bool -> Word -> Assembler a -> (Word, LabelEnvMap)+inspectAsm dflags long_jumps initial_offset+ = go (InspectState initial_offset 0 0 Map.empty)+ where+ go s (NullAsm _) = (instrCount s, lblEnv s)+ go s (AllocPtr _ k) = go (s { ptrCount = n + 1 }) (k n)+ where n = ptrCount s+ go s (AllocLit ls k) = go (s { litCount = n + genericLength ls }) (k n)+ where n = litCount s+ go s (AllocLabel lbl k) = go s' k+ where s' = s { lblEnv = Map.insert lbl (instrCount s) (lblEnv s) }+ go s (Emit _ ops k) = go s' k+ where+ s' = s { instrCount = instrCount s + size }+ size = sum (map count ops) + 1+ largeOps = any (largeOp long_jumps) ops+ count (SmallOp _) = 1+ count (LabelOp _) = count (Op 0)+ count (Op _) = if largeOps then largeArg16s dflags else 1+-- count (LargeOp _) = largeArg16s dflags++-- Bring in all the bci_ bytecode constants.+#include "rts/Bytecodes.h"++largeArgInstr :: Word16 -> Word16+largeArgInstr bci = bci_FLAG_LARGE_ARGS .|. bci++largeArg :: DynFlags -> Word -> [Word16]+largeArg dflags w+ | wORD_SIZE_IN_BITS dflags == 64+ = [fromIntegral (w `shiftR` 48),+ fromIntegral (w `shiftR` 32),+ fromIntegral (w `shiftR` 16),+ fromIntegral w]+ | wORD_SIZE_IN_BITS dflags == 32+ = [fromIntegral (w `shiftR` 16),+ fromIntegral w]+ | otherwise = error "wORD_SIZE_IN_BITS not 32 or 64?"++largeArg16s :: DynFlags -> Word+largeArg16s dflags | wORD_SIZE_IN_BITS dflags == 64 = 4+ | otherwise = 2++assembleI :: DynFlags+ -> BCInstr+ -> Assembler ()+assembleI dflags i = case i of+ STKCHECK n -> emit bci_STKCHECK [Op n]+ PUSH_L o1 -> emit bci_PUSH_L [SmallOp o1]+ PUSH_LL o1 o2 -> emit bci_PUSH_LL [SmallOp o1, SmallOp o2]+ PUSH_LLL o1 o2 o3 -> emit bci_PUSH_LLL [SmallOp o1, SmallOp o2, SmallOp o3]+ PUSH_G nm -> do p <- ptr (BCOPtrName nm)+ emit bci_PUSH_G [Op p]+ PUSH_PRIMOP op -> do p <- ptr (BCOPtrPrimOp op)+ emit bci_PUSH_G [Op p]+ PUSH_BCO proto -> do let ul_bco = assembleBCO dflags proto+ p <- ioptr (liftM BCOPtrBCO ul_bco)+ emit bci_PUSH_G [Op p]+ PUSH_ALTS proto -> do let ul_bco = assembleBCO dflags proto+ p <- ioptr (liftM BCOPtrBCO ul_bco)+ emit bci_PUSH_ALTS [Op p]+ PUSH_ALTS_UNLIFTED proto pk+ -> do let ul_bco = assembleBCO dflags proto+ p <- ioptr (liftM BCOPtrBCO ul_bco)+ emit (push_alts pk) [Op p]+ PUSH_UBX lit nws -> do np <- literal lit+ emit bci_PUSH_UBX [Op np, SmallOp nws]++ PUSH_APPLY_N -> emit bci_PUSH_APPLY_N []+ PUSH_APPLY_V -> emit bci_PUSH_APPLY_V []+ PUSH_APPLY_F -> emit bci_PUSH_APPLY_F []+ PUSH_APPLY_D -> emit bci_PUSH_APPLY_D []+ PUSH_APPLY_L -> emit bci_PUSH_APPLY_L []+ PUSH_APPLY_P -> emit bci_PUSH_APPLY_P []+ PUSH_APPLY_PP -> emit bci_PUSH_APPLY_PP []+ PUSH_APPLY_PPP -> emit bci_PUSH_APPLY_PPP []+ PUSH_APPLY_PPPP -> emit bci_PUSH_APPLY_PPPP []+ PUSH_APPLY_PPPPP -> emit bci_PUSH_APPLY_PPPPP []+ PUSH_APPLY_PPPPPP -> emit bci_PUSH_APPLY_PPPPPP []++ SLIDE n by -> emit bci_SLIDE [SmallOp n, SmallOp by]+ ALLOC_AP n -> emit bci_ALLOC_AP [SmallOp n]+ ALLOC_AP_NOUPD n -> emit bci_ALLOC_AP_NOUPD [SmallOp n]+ ALLOC_PAP arity n -> emit bci_ALLOC_PAP [SmallOp arity, SmallOp n]+ MKAP off sz -> emit bci_MKAP [SmallOp off, SmallOp sz]+ MKPAP off sz -> emit bci_MKPAP [SmallOp off, SmallOp sz]+ UNPACK n -> emit bci_UNPACK [SmallOp n]+ PACK dcon sz -> do itbl_no <- lit [BCONPtrItbl (getName dcon)]+ emit bci_PACK [Op itbl_no, SmallOp sz]+ LABEL lbl -> label lbl+ TESTLT_I i l -> do np <- int i+ emit bci_TESTLT_I [Op np, LabelOp l]+ TESTEQ_I i l -> do np <- int i+ emit bci_TESTEQ_I [Op np, LabelOp l]+ TESTLT_W w l -> do np <- word w+ emit bci_TESTLT_W [Op np, LabelOp l]+ TESTEQ_W w l -> do np <- word w+ emit bci_TESTEQ_W [Op np, LabelOp l]+ TESTLT_F f l -> do np <- float f+ emit bci_TESTLT_F [Op np, LabelOp l]+ TESTEQ_F f l -> do np <- float f+ emit bci_TESTEQ_F [Op np, LabelOp l]+ TESTLT_D d l -> do np <- double d+ emit bci_TESTLT_D [Op np, LabelOp l]+ TESTEQ_D d l -> do np <- double d+ emit bci_TESTEQ_D [Op np, LabelOp l]+ TESTLT_P i l -> emit bci_TESTLT_P [SmallOp i, LabelOp l]+ TESTEQ_P i l -> emit bci_TESTEQ_P [SmallOp i, LabelOp l]+ CASEFAIL -> emit bci_CASEFAIL []+ SWIZZLE stkoff n -> emit bci_SWIZZLE [SmallOp stkoff, SmallOp n]+ JMP l -> emit bci_JMP [LabelOp l]+ ENTER -> emit bci_ENTER []+ RETURN -> emit bci_RETURN []+ RETURN_UBX rep -> emit (return_ubx rep) []+ CCALL off m_addr i -> do np <- addr m_addr+ emit bci_CCALL [SmallOp off, Op np, SmallOp i]+ BRK_FUN index uniq cc -> do p1 <- ptr BCOPtrBreakArray+ q <- int (getKey uniq)+ np <- addr cc+ emit bci_BRK_FUN [Op p1, SmallOp index,+ Op q, Op np]++ where+ literal (MachLabel fs (Just sz) _)+ | platformOS (targetPlatform dflags) == OSMinGW32+ = litlabel (appendFS fs (mkFastString ('@':show sz)))+ -- On Windows, stdcall labels have a suffix indicating the no. of+ -- arg words, e.g. foo@8. testcase: ffi012(ghci)+ literal (MachLabel fs _ _) = litlabel fs+ literal (MachWord w) = int (fromIntegral w)+ literal (MachInt j) = int (fromIntegral j)+ literal MachNullAddr = int 0+ literal (MachFloat r) = float (fromRational r)+ literal (MachDouble r) = double (fromRational r)+ literal (MachChar c) = int (ord c)+ literal (MachInt64 ii) = int64 (fromIntegral ii)+ literal (MachWord64 ii) = int64 (fromIntegral ii)+ literal (MachStr bs) = lit [BCONPtrStr bs]+ -- MachStr requires a zero-terminator when emitted+ literal LitInteger{} = panic "ByteCodeAsm.literal: LitInteger"++ litlabel fs = lit [BCONPtrLbl fs]+ addr (RemotePtr a) = words [fromIntegral a]+ float = words . mkLitF+ double = words . mkLitD dflags+ int = words . mkLitI+ int64 = words . mkLitI64 dflags+ words ws = lit (map BCONPtrWord ws)+ word w = words [w]++isLarge :: Word -> Bool+isLarge n = n > 65535++push_alts :: ArgRep -> Word16+push_alts V = bci_PUSH_ALTS_V+push_alts P = bci_PUSH_ALTS_P+push_alts N = bci_PUSH_ALTS_N+push_alts L = bci_PUSH_ALTS_L+push_alts F = bci_PUSH_ALTS_F+push_alts D = bci_PUSH_ALTS_D+push_alts V16 = error "push_alts: vector"+push_alts V32 = error "push_alts: vector"+push_alts V64 = error "push_alts: vector"++return_ubx :: ArgRep -> Word16+return_ubx V = bci_RETURN_V+return_ubx P = bci_RETURN_P+return_ubx N = bci_RETURN_N+return_ubx L = bci_RETURN_L+return_ubx F = bci_RETURN_F+return_ubx D = bci_RETURN_D+return_ubx V16 = error "return_ubx: vector"+return_ubx V32 = error "return_ubx: vector"+return_ubx V64 = error "return_ubx: vector"++-- Make lists of host-sized words for literals, so that when the+-- words are placed in memory at increasing addresses, the+-- bit pattern is correct for the host's word size and endianness.+mkLitI :: Int -> [Word]+mkLitF :: Float -> [Word]+mkLitD :: DynFlags -> Double -> [Word]+mkLitI64 :: DynFlags -> Int64 -> [Word]++mkLitF f+ = runST (do+ arr <- newArray_ ((0::Int),0)+ writeArray arr 0 f+ f_arr <- castSTUArray arr+ w0 <- readArray f_arr 0+ return [w0 :: Word]+ )++mkLitD dflags d+ | wORD_SIZE dflags == 4+ = runST (do+ arr <- newArray_ ((0::Int),1)+ writeArray arr 0 d+ d_arr <- castSTUArray arr+ w0 <- readArray d_arr 0+ w1 <- readArray d_arr 1+ return [w0 :: Word, w1]+ )+ | wORD_SIZE dflags == 8+ = runST (do+ arr <- newArray_ ((0::Int),0)+ writeArray arr 0 d+ d_arr <- castSTUArray arr+ w0 <- readArray d_arr 0+ return [w0 :: Word]+ )+ | otherwise+ = panic "mkLitD: Bad wORD_SIZE"++mkLitI64 dflags ii+ | wORD_SIZE dflags == 4+ = runST (do+ arr <- newArray_ ((0::Int),1)+ writeArray arr 0 ii+ d_arr <- castSTUArray arr+ w0 <- readArray d_arr 0+ w1 <- readArray d_arr 1+ return [w0 :: Word,w1]+ )+ | wORD_SIZE dflags == 8+ = runST (do+ arr <- newArray_ ((0::Int),0)+ writeArray arr 0 ii+ d_arr <- castSTUArray arr+ w0 <- readArray d_arr 0+ return [w0 :: Word]+ )+ | otherwise+ = panic "mkLitI64: Bad wORD_SIZE"++mkLitI i = [fromIntegral i :: Word]++iNTERP_STACK_CHECK_THRESH :: Int+iNTERP_STACK_CHECK_THRESH = INTERP_STACK_CHECK_THRESH
+ ghci/ByteCodeGen.hs view
@@ -0,0 +1,1798 @@+{-# LANGUAGE CPP, MagicHash, RecordWildCards, BangPatterns #-}+{-# OPTIONS_GHC -fprof-auto-top #-}+--+-- (c) The University of Glasgow 2002-2006+--++-- | ByteCodeGen: Generate bytecode from Core+module ByteCodeGen ( UnlinkedBCO, byteCodeGen, coreExprToBCOs ) where++#include "HsVersions.h"++import ByteCodeInstr+import ByteCodeAsm+import ByteCodeTypes++import GHCi+import GHCi.FFI+import GHCi.RemoteTypes+import BasicTypes+import DynFlags+import Outputable+import Platform+import Name+import MkId+import Id+import ForeignCall+import HscTypes+import CoreUtils+import CoreSyn+import PprCore+import Literal+import PrimOp+import CoreFVs+import Type+import RepType+import Kind ( isLiftedTypeKind )+import DataCon+import TyCon+import Util+import VarSet+import TysPrim+import ErrUtils+import Unique+import FastString+import Panic+import StgCmmLayout ( ArgRep(..), toArgRep, argRepSizeW )+import SMRep+import Bitmap+import OrdList+import Maybes+import VarEnv++import Data.List+import Foreign+import Control.Monad+import Data.Char++import UniqSupply+import Module+import Control.Arrow ( second )++import Control.Exception+import Data.Array+import Data.ByteString (ByteString)+import Data.Map (Map)+import Data.IntMap (IntMap)+import qualified Data.Map as Map+import qualified Data.IntMap as IntMap+import qualified FiniteMap as Map+import Data.Ord+#if MIN_VERSION_base(4,9,0)+import GHC.Stack.CCS+#else+import GHC.Stack as GHC.Stack.CCS+#endif++-- -----------------------------------------------------------------------------+-- Generating byte code for a complete module++byteCodeGen :: HscEnv+ -> Module+ -> CoreProgram+ -> [TyCon]+ -> Maybe ModBreaks+ -> IO CompiledByteCode+byteCodeGen hsc_env this_mod binds tycs mb_modBreaks+ = withTiming (pure dflags)+ (text "ByteCodeGen"<+>brackets (ppr this_mod))+ (const ()) $ do+ -- Split top-level binds into strings and others.+ -- See Note [generating code for top-level string literal bindings].+ let (strings, flatBinds) = splitEithers $ do+ (bndr, rhs) <- flattenBinds binds+ return $ case rhs of+ Lit (MachStr str) -> Left (bndr, str)+ _ -> Right (bndr, simpleFreeVars rhs)+ stringPtrs <- allocateTopStrings hsc_env strings++ us <- mkSplitUniqSupply 'y'+ (BcM_State{..}, proto_bcos) <-+ runBc hsc_env us this_mod mb_modBreaks (mkVarEnv stringPtrs) $+ mapM schemeTopBind flatBinds++ when (notNull ffis)+ (panic "ByteCodeGen.byteCodeGen: missing final emitBc?")++ dumpIfSet_dyn dflags Opt_D_dump_BCOs+ "Proto-BCOs" (vcat (intersperse (char ' ') (map ppr proto_bcos)))++ cbc <- assembleBCOs hsc_env proto_bcos tycs (map snd stringPtrs)+ (case modBreaks of+ Nothing -> Nothing+ Just mb -> Just mb{ modBreaks_breakInfo = breakInfo })++ -- Squash space leaks in the CompiledByteCode. This is really+ -- important, because when loading a set of modules into GHCi+ -- we don't touch the CompiledByteCode until the end when we+ -- do linking. Forcing out the thunks here reduces space+ -- usage by more than 50% when loading a large number of+ -- modules.+ evaluate (seqCompiledByteCode cbc)++ return cbc++ where dflags = hsc_dflags hsc_env++allocateTopStrings+ :: HscEnv+ -> [(Id, ByteString)]+ -> IO [(Var, RemotePtr ())]+allocateTopStrings hsc_env topStrings = do+ let !(bndrs, strings) = unzip topStrings+ ptrs <- iservCmd hsc_env $ MallocStrings strings+ return $ zip bndrs ptrs++{-+Note [generating code for top-level string literal bindings]++Here is a summary on how the byte code generator deals with top-level string+literals:++1. Top-level string literal bindings are spearted from the rest of the module.++2. The strings are allocated via iservCmd, in allocateTopStrings++3. The mapping from binders to allocated strings (topStrings) are maintained in+ BcM and used when generating code for variable references.+-}++-- -----------------------------------------------------------------------------+-- Generating byte code for an expression++-- Returns: the root BCO for this expression+coreExprToBCOs :: HscEnv+ -> Module+ -> CoreExpr+ -> IO UnlinkedBCO+coreExprToBCOs hsc_env this_mod expr+ = withTiming (pure dflags)+ (text "ByteCodeGen"<+>brackets (ppr this_mod))+ (const ()) $ do+ -- create a totally bogus name for the top-level BCO; this+ -- should be harmless, since it's never used for anything+ let invented_name = mkSystemVarName (mkPseudoUniqueE 0) (fsLit "ExprTopLevel")+ invented_id = Id.mkLocalId invented_name (panic "invented_id's type")++ -- the uniques are needed to generate fresh variables when we introduce new+ -- let bindings for ticked expressions+ us <- mkSplitUniqSupply 'y'+ (BcM_State _dflags _us _this_mod _final_ctr mallocd _ _ _, proto_bco)+ <- runBc hsc_env us this_mod Nothing emptyVarEnv $+ schemeTopBind (invented_id, simpleFreeVars expr)++ when (notNull mallocd)+ (panic "ByteCodeGen.coreExprToBCOs: missing final emitBc?")++ dumpIfSet_dyn dflags Opt_D_dump_BCOs "Proto-BCOs" (ppr proto_bco)++ assembleOneBCO hsc_env proto_bco+ where dflags = hsc_dflags hsc_env++-- The regular freeVars function gives more information than is useful to+-- us here. simpleFreeVars does the impedance matching.+simpleFreeVars :: CoreExpr -> AnnExpr Id DVarSet+simpleFreeVars = go . freeVars+ where+ go :: AnnExpr Id FVAnn -> AnnExpr Id DVarSet+ go (ann, e) = (freeVarsOfAnn ann, go' e)++ go' :: AnnExpr' Id FVAnn -> AnnExpr' Id DVarSet+ go' (AnnVar id) = AnnVar id+ go' (AnnLit lit) = AnnLit lit+ go' (AnnLam bndr body) = AnnLam bndr (go body)+ go' (AnnApp fun arg) = AnnApp (go fun) (go arg)+ go' (AnnCase scrut bndr ty alts) = AnnCase (go scrut) bndr ty (map go_alt alts)+ go' (AnnLet bind body) = AnnLet (go_bind bind) (go body)+ go' (AnnCast expr (ann, co)) = AnnCast (go expr) (freeVarsOfAnn ann, co)+ go' (AnnTick tick body) = AnnTick tick (go body)+ go' (AnnType ty) = AnnType ty+ go' (AnnCoercion co) = AnnCoercion co++ go_alt (con, args, expr) = (con, args, go expr)++ go_bind (AnnNonRec bndr rhs) = AnnNonRec bndr (go rhs)+ go_bind (AnnRec pairs) = AnnRec (map (second go) pairs)++-- -----------------------------------------------------------------------------+-- Compilation schema for the bytecode generator++type BCInstrList = OrdList BCInstr++type Sequel = Word -- back off to this depth before ENTER++-- Maps Ids to the offset from the stack _base_ so we don't have+-- to mess with it after each push/pop.+type BCEnv = Map Id Word -- To find vars on the stack++{-+ppBCEnv :: BCEnv -> SDoc+ppBCEnv p+ = text "begin-env"+ $$ nest 4 (vcat (map pp_one (sortBy cmp_snd (Map.toList p))))+ $$ text "end-env"+ where+ pp_one (var, offset) = int offset <> colon <+> ppr var <+> ppr (bcIdArgRep var)+ cmp_snd x y = compare (snd x) (snd y)+-}++-- Create a BCO and do a spot of peephole optimisation on the insns+-- at the same time.+mkProtoBCO+ :: DynFlags+ -> name+ -> BCInstrList+ -> Either [AnnAlt Id DVarSet] (AnnExpr Id DVarSet)+ -> Int+ -> Word16+ -> [StgWord]+ -> Bool -- True <=> is a return point, rather than a function+ -> [FFIInfo]+ -> ProtoBCO name+mkProtoBCO dflags nm instrs_ordlist origin arity bitmap_size bitmap is_ret ffis+ = ProtoBCO {+ protoBCOName = nm,+ protoBCOInstrs = maybe_with_stack_check,+ protoBCOBitmap = bitmap,+ protoBCOBitmapSize = bitmap_size,+ protoBCOArity = arity,+ protoBCOExpr = origin,+ protoBCOFFIs = ffis+ }+ where+ -- Overestimate the stack usage (in words) of this BCO,+ -- and if >= iNTERP_STACK_CHECK_THRESH, add an explicit+ -- stack check. (The interpreter always does a stack check+ -- for iNTERP_STACK_CHECK_THRESH words at the start of each+ -- BCO anyway, so we only need to add an explicit one in the+ -- (hopefully rare) cases when the (overestimated) stack use+ -- exceeds iNTERP_STACK_CHECK_THRESH.+ maybe_with_stack_check+ | is_ret && stack_usage < fromIntegral (aP_STACK_SPLIM dflags) = peep_d+ -- don't do stack checks at return points,+ -- everything is aggregated up to the top BCO+ -- (which must be a function).+ -- That is, unless the stack usage is >= AP_STACK_SPLIM,+ -- see bug #1466.+ | stack_usage >= fromIntegral iNTERP_STACK_CHECK_THRESH+ = STKCHECK stack_usage : peep_d+ | otherwise+ = peep_d -- the supposedly common case++ -- We assume that this sum doesn't wrap+ stack_usage = sum (map bciStackUse peep_d)++ -- Merge local pushes+ peep_d = peep (fromOL instrs_ordlist)++ peep (PUSH_L off1 : PUSH_L off2 : PUSH_L off3 : rest)+ = PUSH_LLL off1 (off2-1) (off3-2) : peep rest+ peep (PUSH_L off1 : PUSH_L off2 : rest)+ = PUSH_LL off1 (off2-1) : peep rest+ peep (i:rest)+ = i : peep rest+ peep []+ = []++argBits :: DynFlags -> [ArgRep] -> [Bool]+argBits _ [] = []+argBits dflags (rep : args)+ | isFollowableArg rep = False : argBits dflags args+ | otherwise = take (argRepSizeW dflags rep) (repeat True) ++ argBits dflags args++-- -----------------------------------------------------------------------------+-- schemeTopBind++-- Compile code for the right-hand side of a top-level binding++schemeTopBind :: (Id, AnnExpr Id DVarSet) -> BcM (ProtoBCO Name)+++schemeTopBind (id, rhs)+ | Just data_con <- isDataConWorkId_maybe id,+ isNullaryRepDataCon data_con = do+ dflags <- getDynFlags+ -- Special case for the worker of a nullary data con.+ -- It'll look like this: Nil = /\a -> Nil a+ -- If we feed it into schemeR, we'll get+ -- Nil = Nil+ -- because mkConAppCode treats nullary constructor applications+ -- by just re-using the single top-level definition. So+ -- for the worker itself, we must allocate it directly.+ -- ioToBc (putStrLn $ "top level BCO")+ emitBc (mkProtoBCO dflags (getName id) (toOL [PACK data_con 0, ENTER])+ (Right rhs) 0 0 [{-no bitmap-}] False{-not alts-})++ | otherwise+ = schemeR [{- No free variables -}] (id, rhs)+++-- -----------------------------------------------------------------------------+-- schemeR++-- Compile code for a right-hand side, to give a BCO that,+-- when executed with the free variables and arguments on top of the stack,+-- will return with a pointer to the result on top of the stack, after+-- removing the free variables and arguments.+--+-- Park the resulting BCO in the monad. Also requires the+-- variable to which this value was bound, so as to give the+-- resulting BCO a name.++schemeR :: [Id] -- Free vars of the RHS, ordered as they+ -- will appear in the thunk. Empty for+ -- top-level things, which have no free vars.+ -> (Id, AnnExpr Id DVarSet)+ -> BcM (ProtoBCO Name)+schemeR fvs (nm, rhs)+{-+ | trace (showSDoc (+ (char ' '+ $$ (ppr.filter (not.isTyVar).dVarSetElems.fst) rhs+ $$ pprCoreExpr (deAnnotate rhs)+ $$ char ' '+ ))) False+ = undefined+ | otherwise+-}+ = schemeR_wrk fvs nm rhs (collect rhs)++collect :: AnnExpr Id DVarSet -> ([Var], AnnExpr' Id DVarSet)+collect (_, e) = go [] e+ where+ go xs e | Just e' <- bcView e = go xs e'+ go xs (AnnLam x (_,e))+ | typePrimRep (idType x) `lengthExceeds` 1+ = multiValException+ | otherwise+ = go (x:xs) e+ go xs not_lambda = (reverse xs, not_lambda)++schemeR_wrk :: [Id] -> Id -> AnnExpr Id DVarSet -> ([Var], AnnExpr' Var DVarSet) -> BcM (ProtoBCO Name)+schemeR_wrk fvs nm original_body (args, body)+ = do+ dflags <- getDynFlags+ let+ all_args = reverse args ++ fvs+ arity = length all_args+ -- all_args are the args in reverse order. We're compiling a function+ -- \fv1..fvn x1..xn -> e+ -- i.e. the fvs come first++ szsw_args = map (fromIntegral . idSizeW dflags) all_args+ szw_args = sum szsw_args+ p_init = Map.fromList (zip all_args (mkStackOffsets 0 szsw_args))++ -- make the arg bitmap+ bits = argBits dflags (reverse (map bcIdArgRep all_args))+ bitmap_size = genericLength bits+ bitmap = mkBitmap dflags bits+ body_code <- schemeER_wrk szw_args p_init body++ emitBc (mkProtoBCO dflags (getName nm) body_code (Right original_body)+ arity bitmap_size bitmap False{-not alts-})++-- introduce break instructions for ticked expressions+schemeER_wrk :: Word -> BCEnv -> AnnExpr' Id DVarSet -> BcM BCInstrList+schemeER_wrk d p rhs+ | AnnTick (Breakpoint tick_no fvs) (_annot, newRhs) <- rhs+ = do code <- schemeE (fromIntegral d) 0 p newRhs+ cc_arr <- getCCArray+ this_mod <- moduleName <$> getCurrentModule+ let idOffSets = getVarOffSets d p fvs+ let breakInfo = CgBreakInfo+ { cgb_vars = idOffSets+ , cgb_resty = exprType (deAnnotate' newRhs)+ }+ newBreakInfo tick_no breakInfo+ dflags <- getDynFlags+ let cc | interpreterProfiled dflags = cc_arr ! tick_no+ | otherwise = toRemotePtr nullPtr+ let breakInstr = BRK_FUN (fromIntegral tick_no) (getUnique this_mod) cc+ return $ breakInstr `consOL` code+ | otherwise = schemeE (fromIntegral d) 0 p rhs++getVarOffSets :: Word -> BCEnv -> [Id] -> [(Id, Word16)]+getVarOffSets d p = catMaybes . map (getOffSet d p)++getOffSet :: Word -> BCEnv -> Id -> Maybe (Id, Word16)+getOffSet d env id+ = case lookupBCEnv_maybe id env of+ Nothing -> Nothing+ Just offset -> Just (id, trunc16 $ d - offset)++trunc16 :: Word -> Word16+trunc16 w+ | w > fromIntegral (maxBound :: Word16)+ = panic "stack depth overflow"+ | otherwise+ = fromIntegral w++fvsToEnv :: BCEnv -> DVarSet -> [Id]+-- Takes the free variables of a right-hand side, and+-- delivers an ordered list of the local variables that will+-- be captured in the thunk for the RHS+-- The BCEnv argument tells which variables are in the local+-- environment: these are the ones that should be captured+--+-- The code that constructs the thunk, and the code that executes+-- it, have to agree about this layout+fvsToEnv p fvs = [v | v <- dVarSetElems fvs,+ isId v, -- Could be a type variable+ v `Map.member` p]++-- -----------------------------------------------------------------------------+-- schemeE++returnUnboxedAtom :: Word -> Sequel -> BCEnv+ -> AnnExpr' Id DVarSet -> ArgRep+ -> BcM BCInstrList+-- Returning an unlifted value.+-- Heave it on the stack, SLIDE, and RETURN.+returnUnboxedAtom d s p e e_rep+ = do (push, szw) <- pushAtom d p e+ return (push -- value onto stack+ `appOL` mkSLIDE szw (d-s) -- clear to sequel+ `snocOL` RETURN_UBX e_rep) -- go++-- Compile code to apply the given expression to the remaining args+-- on the stack, returning a HNF.+schemeE :: Word -> Sequel -> BCEnv -> AnnExpr' Id DVarSet -> BcM BCInstrList++schemeE d s p e+ | Just e' <- bcView e+ = schemeE d s p e'++-- Delegate tail-calls to schemeT.+schemeE d s p e@(AnnApp _ _) = schemeT d s p e++schemeE d s p e@(AnnLit lit) = returnUnboxedAtom d s p e (typeArgRep (literalType lit))+schemeE d s p e@(AnnCoercion {}) = returnUnboxedAtom d s p e V++schemeE d s p e@(AnnVar v)+ | isUnliftedType (idType v) = returnUnboxedAtom d s p e (bcIdArgRep v)+ | otherwise = schemeT d s p e++schemeE d s p (AnnLet (AnnNonRec x (_,rhs)) (_,body))+ | (AnnVar v, args_r_to_l) <- splitApp rhs,+ Just data_con <- isDataConWorkId_maybe v,+ dataConRepArity data_con == length args_r_to_l+ = do -- Special case for a non-recursive let whose RHS is a+ -- saturated constructor application.+ -- Just allocate the constructor and carry on+ alloc_code <- mkConAppCode d s p data_con args_r_to_l+ body_code <- schemeE (d+1) s (Map.insert x d p) body+ return (alloc_code `appOL` body_code)++-- General case for let. Generates correct, if inefficient, code in+-- all situations.+schemeE d s p (AnnLet binds (_,body)) = do+ dflags <- getDynFlags+ let (xs,rhss) = case binds of AnnNonRec x rhs -> ([x],[rhs])+ AnnRec xs_n_rhss -> unzip xs_n_rhss+ n_binds = genericLength xs++ fvss = map (fvsToEnv p' . fst) rhss++ -- Sizes of free vars+ sizes = map (\rhs_fvs -> sum (map (fromIntegral . idSizeW dflags) rhs_fvs)) fvss++ -- the arity of each rhs+ arities = map (genericLength . fst . collect) rhss++ -- This p', d' defn is safe because all the items being pushed+ -- are ptrs, so all have size 1. d' and p' reflect the stack+ -- after the closures have been allocated in the heap (but not+ -- filled in), and pointers to them parked on the stack.+ p' = Map.insertList (zipE xs (mkStackOffsets d (genericReplicate n_binds 1))) p+ d' = d + fromIntegral n_binds+ zipE = zipEqual "schemeE"++ -- ToDo: don't build thunks for things with no free variables+ build_thunk _ [] size bco off arity+ = return (PUSH_BCO bco `consOL` unitOL (mkap (off+size) size))+ where+ mkap | arity == 0 = MKAP+ | otherwise = MKPAP+ build_thunk dd (fv:fvs) size bco off arity = do+ (push_code, pushed_szw) <- pushAtom dd p' (AnnVar fv)+ more_push_code <- build_thunk (dd + fromIntegral pushed_szw) fvs size bco off arity+ return (push_code `appOL` more_push_code)++ alloc_code = toOL (zipWith mkAlloc sizes arities)+ where mkAlloc sz 0+ | is_tick = ALLOC_AP_NOUPD sz+ | otherwise = ALLOC_AP sz+ mkAlloc sz arity = ALLOC_PAP arity sz++ is_tick = case binds of+ AnnNonRec id _ -> occNameFS (getOccName id) == tickFS+ _other -> False++ compile_bind d' fvs x rhs size arity off = do+ bco <- schemeR fvs (x,rhs)+ build_thunk d' fvs size bco off arity++ compile_binds =+ [ compile_bind d' fvs x rhs size arity n+ | (fvs, x, rhs, size, arity, n) <-+ zip6 fvss xs rhss sizes arities [n_binds, n_binds-1 .. 1]+ ]+ body_code <- schemeE d' s p' body+ thunk_codes <- sequence compile_binds+ return (alloc_code `appOL` concatOL thunk_codes `appOL` body_code)++-- Introduce a let binding for a ticked case expression. This rule+-- *should* only fire when the expression was not already let-bound+-- (the code gen for let bindings should take care of that). Todo: we+-- call exprFreeVars on a deAnnotated expression, this may not be the+-- best way to calculate the free vars but it seemed like the least+-- intrusive thing to do+schemeE d s p exp@(AnnTick (Breakpoint _id _fvs) _rhs)+ | isLiftedTypeKind (typeKind ty)+ = do id <- newId ty+ -- Todo: is emptyVarSet correct on the next line?+ let letExp = AnnLet (AnnNonRec id (fvs, exp)) (emptyDVarSet, AnnVar id)+ schemeE d s p letExp++ | otherwise+ = do -- If the result type is not definitely lifted, then we must generate+ -- let f = \s . tick<n> e+ -- in f realWorld#+ -- When we stop at the breakpoint, _result will have an unlifted+ -- type and hence won't be bound in the environment, but the+ -- breakpoint will otherwise work fine.+ --+ -- NB (Trac #12007) this /also/ applies for if (ty :: TYPE r), where+ -- r :: RuntimeRep is a variable. This can happen in the+ -- continuations for a pattern-synonym matcher+ -- match = /\(r::RuntimeRep) /\(a::TYPE r).+ -- \(k :: Int -> a) \(v::T).+ -- case v of MkV n -> k n+ -- Here (k n) :: a :: Type r, so we don't know if it's lifted+ -- or not; but that should be fine provided we add that void arg.++ id <- newId (mkFunTy realWorldStatePrimTy ty)+ st <- newId realWorldStatePrimTy+ let letExp = AnnLet (AnnNonRec id (fvs, AnnLam st (emptyDVarSet, exp)))+ (emptyDVarSet, (AnnApp (emptyDVarSet, AnnVar id)+ (emptyDVarSet, AnnVar realWorldPrimId)))+ schemeE d s p letExp++ where+ exp' = deAnnotate' exp+ fvs = exprFreeVarsDSet exp'+ ty = exprType exp'++-- ignore other kinds of tick+schemeE d s p (AnnTick _ (_, rhs)) = schemeE d s p rhs++schemeE d s p (AnnCase (_,scrut) _ _ []) = schemeE d s p scrut+ -- no alts: scrut is guaranteed to diverge++schemeE d s p (AnnCase scrut bndr _ [(DataAlt dc, [bind1, bind2], rhs)])+ | isUnboxedTupleCon dc -- handles pairs with one void argument (e.g. state token)+ -- Convert+ -- case .... of x { (# V'd-thing, a #) -> ... }+ -- to+ -- case .... of a { DEFAULT -> ... }+ -- because the return convention for both are identical.+ --+ -- Note that it does not matter losing the void-rep thing from the+ -- envt (it won't be bound now) because we never look such things up.+ , Just res <- case (typePrimRep (idType bind1), typePrimRep (idType bind2)) of+ ([], [_])+ -> Just $ doCase d s p scrut bind2 [(DEFAULT, [], rhs)] (Just bndr)+ ([_], [])+ -> Just $ doCase d s p scrut bind1 [(DEFAULT, [], rhs)] (Just bndr)+ _ -> Nothing+ = res++schemeE d s p (AnnCase scrut bndr _ [(DataAlt dc, [bind1], rhs)])+ | isUnboxedTupleCon dc+ , length (typePrimRep (idType bndr)) <= 1 -- handles unit tuples+ = doCase d s p scrut bind1 [(DEFAULT, [], rhs)] (Just bndr)++schemeE d s p (AnnCase scrut bndr _ alt@[(DEFAULT, [], _)])+ | isUnboxedTupleType (idType bndr)+ , Just ty <- case typePrimRep (idType bndr) of+ [_] -> Just (unwrapType (idType bndr))+ [] -> Just voidPrimTy+ _ -> Nothing+ -- handles any pattern with a single non-void binder; in particular I/O+ -- monad returns (# RealWorld#, a #)+ = doCase d s p scrut (bndr `setIdType` ty) alt (Just bndr)++schemeE d s p (AnnCase scrut bndr _ alts)+ = doCase d s p scrut bndr alts Nothing{-not an unboxed tuple-}++schemeE _ _ _ expr+ = pprPanic "ByteCodeGen.schemeE: unhandled case"+ (pprCoreExpr (deAnnotate' expr))++{-+ Ticked Expressions+ ------------------++ The idea is that the "breakpoint<n,fvs> E" is really just an annotation on+ the code. When we find such a thing, we pull out the useful information,+ and then compile the code as if it was just the expression E.++-}++-- Compile code to do a tail call. Specifically, push the fn,+-- slide the on-stack app back down to the sequel depth,+-- and enter. Four cases:+--+-- 0. (Nasty hack).+-- An application "GHC.Prim.tagToEnum# <type> unboxed-int".+-- The int will be on the stack. Generate a code sequence+-- to convert it to the relevant constructor, SLIDE and ENTER.+--+-- 1. The fn denotes a ccall. Defer to generateCCall.+--+-- 2. (Another nasty hack). Spot (# a::V, b #) and treat+-- it simply as b -- since the representations are identical+-- (the V takes up zero stack space). Also, spot+-- (# b #) and treat it as b.+--+-- 3. Application of a constructor, by defn saturated.+-- Split the args into ptrs and non-ptrs, and push the nonptrs,+-- then the ptrs, and then do PACK and RETURN.+--+-- 4. Otherwise, it must be a function call. Push the args+-- right to left, SLIDE and ENTER.++schemeT :: Word -- Stack depth+ -> Sequel -- Sequel depth+ -> BCEnv -- stack env+ -> AnnExpr' Id DVarSet+ -> BcM BCInstrList++schemeT d s p app++-- | trace ("schemeT: env in = \n" ++ showSDocDebug (ppBCEnv p)) False+-- = panic "schemeT ?!?!"++-- | trace ("\nschemeT\n" ++ showSDoc (pprCoreExpr (deAnnotate' app)) ++ "\n") False+-- = error "?!?!"++ -- Case 0+ | Just (arg, constr_names) <- maybe_is_tagToEnum_call app+ = implement_tagToId d s p arg constr_names++ -- Case 1+ | Just (CCall ccall_spec) <- isFCallId_maybe fn+ = if isSupportedCConv ccall_spec+ then generateCCall d s p ccall_spec fn args_r_to_l+ else unsupportedCConvException+++ -- Case 2: Constructor application+ | Just con <- maybe_saturated_dcon+ , isUnboxedTupleCon con+ = case args_r_to_l of+ [arg1,arg2] | isVAtom arg1 ->+ unboxedTupleReturn d s p arg2+ [arg1,arg2] | isVAtom arg2 ->+ unboxedTupleReturn d s p arg1+ _other -> multiValException++ -- Case 3: Ordinary data constructor+ | Just con <- maybe_saturated_dcon+ = do alloc_con <- mkConAppCode d s p con args_r_to_l+ return (alloc_con `appOL`+ mkSLIDE 1 (d - s) `snocOL`+ ENTER)++ -- Case 4: Tail call of function+ | otherwise+ = doTailCall d s p fn args_r_to_l++ where+ -- Extract the args (R->L) and fn+ -- The function will necessarily be a variable,+ -- because we are compiling a tail call+ (AnnVar fn, args_r_to_l) = splitApp app++ -- Only consider this to be a constructor application iff it is+ -- saturated. Otherwise, we'll call the constructor wrapper.+ n_args = length args_r_to_l+ maybe_saturated_dcon+ = case isDataConWorkId_maybe fn of+ Just con | dataConRepArity con == n_args -> Just con+ _ -> Nothing++-- -----------------------------------------------------------------------------+-- Generate code to build a constructor application,+-- leaving it on top of the stack++mkConAppCode :: Word -> Sequel -> BCEnv+ -> DataCon -- The data constructor+ -> [AnnExpr' Id DVarSet] -- Args, in *reverse* order+ -> BcM BCInstrList++mkConAppCode _ _ _ con [] -- Nullary constructor+ = ASSERT( isNullaryRepDataCon con )+ return (unitOL (PUSH_G (getName (dataConWorkId con))))+ -- Instead of doing a PACK, which would allocate a fresh+ -- copy of this constructor, use the single shared version.++mkConAppCode orig_d _ p con args_r_to_l+ = ASSERT( dataConRepArity con == length args_r_to_l )+ do_pushery orig_d (non_ptr_args ++ ptr_args)+ where+ -- The args are already in reverse order, which is the way PACK+ -- expects them to be. We must push the non-ptrs after the ptrs.+ (ptr_args, non_ptr_args) = partition isPtrAtom args_r_to_l++ do_pushery d (arg:args)+ = do (push, arg_words) <- pushAtom d p arg+ more_push_code <- do_pushery (d + fromIntegral arg_words) args+ return (push `appOL` more_push_code)+ do_pushery d []+ = return (unitOL (PACK con n_arg_words))+ where+ n_arg_words = trunc16 $ d - orig_d+++-- -----------------------------------------------------------------------------+-- Returning an unboxed tuple with one non-void component (the only+-- case we can handle).+--+-- Remember, we don't want to *evaluate* the component that is being+-- returned, even if it is a pointed type. We always just return.++unboxedTupleReturn+ :: Word -> Sequel -> BCEnv+ -> AnnExpr' Id DVarSet -> BcM BCInstrList+unboxedTupleReturn d s p arg = returnUnboxedAtom d s p arg (atomRep arg)++-- -----------------------------------------------------------------------------+-- Generate code for a tail-call++doTailCall+ :: Word -> Sequel -> BCEnv+ -> Id -> [AnnExpr' Id DVarSet]+ -> BcM BCInstrList+doTailCall init_d s p fn args+ = do_pushes init_d args (map atomRep args)+ where+ do_pushes d [] reps = do+ ASSERT( null reps ) return ()+ (push_fn, sz) <- pushAtom d p (AnnVar fn)+ ASSERT( sz == 1 ) return ()+ return (push_fn `appOL` (+ mkSLIDE (trunc16 $ d - init_d + 1) (init_d - s) `appOL`+ unitOL ENTER))+ do_pushes d args reps = do+ let (push_apply, n, rest_of_reps) = findPushSeq reps+ (these_args, rest_of_args) = splitAt n args+ (next_d, push_code) <- push_seq d these_args+ instrs <- do_pushes (next_d + 1) rest_of_args rest_of_reps+ -- ^^^ for the PUSH_APPLY_ instruction+ return (push_code `appOL` (push_apply `consOL` instrs))++ push_seq d [] = return (d, nilOL)+ push_seq d (arg:args) = do+ (push_code, sz) <- pushAtom d p arg+ (final_d, more_push_code) <- push_seq (d + fromIntegral sz) args+ return (final_d, push_code `appOL` more_push_code)++-- v. similar to CgStackery.findMatch, ToDo: merge+findPushSeq :: [ArgRep] -> (BCInstr, Int, [ArgRep])+findPushSeq (P: P: P: P: P: P: rest)+ = (PUSH_APPLY_PPPPPP, 6, rest)+findPushSeq (P: P: P: P: P: rest)+ = (PUSH_APPLY_PPPPP, 5, rest)+findPushSeq (P: P: P: P: rest)+ = (PUSH_APPLY_PPPP, 4, rest)+findPushSeq (P: P: P: rest)+ = (PUSH_APPLY_PPP, 3, rest)+findPushSeq (P: P: rest)+ = (PUSH_APPLY_PP, 2, rest)+findPushSeq (P: rest)+ = (PUSH_APPLY_P, 1, rest)+findPushSeq (V: rest)+ = (PUSH_APPLY_V, 1, rest)+findPushSeq (N: rest)+ = (PUSH_APPLY_N, 1, rest)+findPushSeq (F: rest)+ = (PUSH_APPLY_F, 1, rest)+findPushSeq (D: rest)+ = (PUSH_APPLY_D, 1, rest)+findPushSeq (L: rest)+ = (PUSH_APPLY_L, 1, rest)+findPushSeq _+ = panic "ByteCodeGen.findPushSeq"++-- -----------------------------------------------------------------------------+-- Case expressions++doCase :: Word -> Sequel -> BCEnv+ -> AnnExpr Id DVarSet -> Id -> [AnnAlt Id DVarSet]+ -> Maybe Id -- Just x <=> is an unboxed tuple case with scrut binder, don't enter the result+ -> BcM BCInstrList+doCase d s p (_,scrut) bndr alts is_unboxed_tuple+ | typePrimRep (idType bndr) `lengthExceeds` 1+ = multiValException+ | otherwise+ = do+ dflags <- getDynFlags+ let+ profiling+ | gopt Opt_ExternalInterpreter dflags = gopt Opt_SccProfilingOn dflags+ | otherwise = rtsIsProfiled++ -- Top of stack is the return itbl, as usual.+ -- underneath it is the pointer to the alt_code BCO.+ -- When an alt is entered, it assumes the returned value is+ -- on top of the itbl.+ ret_frame_sizeW :: Word+ ret_frame_sizeW = 2++ -- The extra frame we push to save/restor the CCCS when profiling+ save_ccs_sizeW | profiling = 2+ | otherwise = 0++ -- An unlifted value gets an extra info table pushed on top+ -- when it is returned.+ unlifted_itbl_sizeW :: Word+ unlifted_itbl_sizeW | isAlgCase = 0+ | otherwise = 1++ -- depth of stack after the return value has been pushed+ d_bndr = d + ret_frame_sizeW + fromIntegral (idSizeW dflags bndr)++ -- depth of stack after the extra info table for an unboxed return+ -- has been pushed, if any. This is the stack depth at the+ -- continuation.+ d_alts = d_bndr + unlifted_itbl_sizeW++ -- Env in which to compile the alts, not including+ -- any vars bound by the alts themselves+ d_bndr' = fromIntegral d_bndr - 1+ p_alts0 = Map.insert bndr d_bndr' p+ p_alts = case is_unboxed_tuple of+ Just ubx_bndr -> Map.insert ubx_bndr d_bndr' p_alts0+ Nothing -> p_alts0++ bndr_ty = idType bndr+ isAlgCase = not (isUnliftedType bndr_ty) && isNothing is_unboxed_tuple++ -- given an alt, return a discr and code for it.+ codeAlt (DEFAULT, _, (_,rhs))+ = do rhs_code <- schemeE d_alts s p_alts rhs+ return (NoDiscr, rhs_code)++ codeAlt alt@(_, bndrs, (_,rhs))+ -- primitive or nullary constructor alt: no need to UNPACK+ | null real_bndrs = do+ rhs_code <- schemeE d_alts s p_alts rhs+ return (my_discr alt, rhs_code)+ -- algebraic alt with some binders+ | otherwise =+ let+ (ptrs,nptrs) = partition (isFollowableArg.bcIdArgRep) real_bndrs+ ptr_sizes = map (fromIntegral . idSizeW dflags) ptrs+ nptrs_sizes = map (fromIntegral . idSizeW dflags) nptrs+ bind_sizes = ptr_sizes ++ nptrs_sizes+ size = sum ptr_sizes + sum nptrs_sizes+ -- the UNPACK instruction unpacks in reverse order...+ p' = Map.insertList+ (zip (reverse (ptrs ++ nptrs))+ (mkStackOffsets d_alts (reverse bind_sizes)))+ p_alts+ in do+ MASSERT(isAlgCase)+ rhs_code <- schemeE (d_alts + size) s p' rhs+ return (my_discr alt, unitOL (UNPACK (trunc16 size)) `appOL` rhs_code)+ where+ real_bndrs = filterOut isTyVar bndrs++ my_discr (DEFAULT, _, _) = NoDiscr {-shouldn't really happen-}+ my_discr (DataAlt dc, _, _)+ | isUnboxedTupleCon dc || isUnboxedSumCon dc+ = multiValException+ | otherwise+ = DiscrP (fromIntegral (dataConTag dc - fIRST_TAG))+ my_discr (LitAlt l, _, _)+ = case l of MachInt i -> DiscrI (fromInteger i)+ MachWord w -> DiscrW (fromInteger w)+ MachFloat r -> DiscrF (fromRational r)+ MachDouble r -> DiscrD (fromRational r)+ MachChar i -> DiscrI (ord i)+ _ -> pprPanic "schemeE(AnnCase).my_discr" (ppr l)++ maybe_ncons+ | not isAlgCase = Nothing+ | otherwise+ = case [dc | (DataAlt dc, _, _) <- alts] of+ [] -> Nothing+ (dc:_) -> Just (tyConFamilySize (dataConTyCon dc))++ -- the bitmap is relative to stack depth d, i.e. before the+ -- BCO, info table and return value are pushed on.+ -- This bit of code is v. similar to buildLivenessMask in CgBindery,+ -- except that here we build the bitmap from the known bindings of+ -- things that are pointers, whereas in CgBindery the code builds the+ -- bitmap from the free slots and unboxed bindings.+ -- (ToDo: merge?)+ --+ -- NOTE [7/12/2006] bug #1013, testcase ghci/should_run/ghci002.+ -- The bitmap must cover the portion of the stack up to the sequel only.+ -- Previously we were building a bitmap for the whole depth (d), but we+ -- really want a bitmap up to depth (d-s). This affects compilation of+ -- case-of-case expressions, which is the only time we can be compiling a+ -- case expression with s /= 0.+ bitmap_size = trunc16 $ d-s+ bitmap_size' :: Int+ bitmap_size' = fromIntegral bitmap_size+ bitmap = intsToReverseBitmap dflags bitmap_size'{-size-}+ (sort (filter (< bitmap_size') rel_slots))+ where+ binds = Map.toList p+ -- NB: unboxed tuple cases bind the scrut binder to the same offset+ -- as one of the alt binders, so we have to remove any duplicates here:+ rel_slots = nub $ map fromIntegral $ concat (map spread binds)+ spread (id, offset) | isFollowableArg (bcIdArgRep id) = [ rel_offset ]+ | otherwise = []+ where rel_offset = trunc16 $ d - fromIntegral offset - 1++ alt_stuff <- mapM codeAlt alts+ alt_final <- mkMultiBranch maybe_ncons alt_stuff++ let+ alt_bco_name = getName bndr+ alt_bco = mkProtoBCO dflags alt_bco_name alt_final (Left alts)+ 0{-no arity-} bitmap_size bitmap True{-is alts-}+-- trace ("case: bndr = " ++ showSDocDebug (ppr bndr) ++ "\ndepth = " ++ show d ++ "\nenv = \n" ++ showSDocDebug (ppBCEnv p) +++-- "\n bitmap = " ++ show bitmap) $ do++ scrut_code <- schemeE (d + ret_frame_sizeW + save_ccs_sizeW)+ (d + ret_frame_sizeW + save_ccs_sizeW)+ p scrut+ alt_bco' <- emitBc alt_bco+ let push_alts+ | isAlgCase = PUSH_ALTS alt_bco'+ | otherwise = PUSH_ALTS_UNLIFTED alt_bco' (typeArgRep bndr_ty)+ return (push_alts `consOL` scrut_code)+++-- -----------------------------------------------------------------------------+-- Deal with a CCall.++-- Taggedly push the args onto the stack R->L,+-- deferencing ForeignObj#s and adjusting addrs to point to+-- payloads in Ptr/Byte arrays. Then, generate the marshalling+-- (machine) code for the ccall, and create bytecodes to call that and+-- then return in the right way.++generateCCall :: Word -> Sequel -- stack and sequel depths+ -> BCEnv+ -> CCallSpec -- where to call+ -> Id -- of target, for type info+ -> [AnnExpr' Id DVarSet] -- args (atoms)+ -> BcM BCInstrList++generateCCall d0 s p (CCallSpec target cconv safety) fn args_r_to_l+ = do+ dflags <- getDynFlags++ let+ -- useful constants+ addr_sizeW :: Word16+ addr_sizeW = fromIntegral (argRepSizeW dflags N)++ -- Get the args on the stack, with tags and suitably+ -- dereferenced for the CCall. For each arg, return the+ -- depth to the first word of the bits for that arg, and the+ -- ArgRep of what was actually pushed.++ pargs _ [] = return []+ pargs d (a:az)+ = let arg_ty = unwrapType (exprType (deAnnotate' a))++ in case tyConAppTyCon_maybe arg_ty of+ -- Don't push the FO; instead push the Addr# it+ -- contains.+ Just t+ | t == arrayPrimTyCon || t == mutableArrayPrimTyCon+ -> do rest <- pargs (d + fromIntegral addr_sizeW) az+ code <- parg_ArrayishRep (fromIntegral (arrPtrsHdrSize dflags)) d p a+ return ((code,AddrRep):rest)++ | t == smallArrayPrimTyCon || t == smallMutableArrayPrimTyCon+ -> do rest <- pargs (d + fromIntegral addr_sizeW) az+ code <- parg_ArrayishRep (fromIntegral (smallArrPtrsHdrSize dflags)) d p a+ return ((code,AddrRep):rest)++ | t == byteArrayPrimTyCon || t == mutableByteArrayPrimTyCon+ -> do rest <- pargs (d + fromIntegral addr_sizeW) az+ code <- parg_ArrayishRep (fromIntegral (arrWordsHdrSize dflags)) d p a+ return ((code,AddrRep):rest)++ -- Default case: push taggedly, but otherwise intact.+ _+ -> do (code_a, sz_a) <- pushAtom d p a+ rest <- pargs (d + fromIntegral sz_a) az+ return ((code_a, atomPrimRep a) : rest)++ -- Do magic for Ptr/Byte arrays. Push a ptr to the array on+ -- the stack but then advance it over the headers, so as to+ -- point to the payload.+ parg_ArrayishRep :: Word16 -> Word -> BCEnv -> AnnExpr' Id DVarSet+ -> BcM BCInstrList+ parg_ArrayishRep hdrSize d p a+ = do (push_fo, _) <- pushAtom d p a+ -- The ptr points at the header. Advance it over the+ -- header and then pretend this is an Addr#.+ return (push_fo `snocOL` SWIZZLE 0 hdrSize)++ code_n_reps <- pargs d0 args_r_to_l+ let+ (pushs_arg, a_reps_pushed_r_to_l) = unzip code_n_reps+ a_reps_sizeW = fromIntegral (sum (map (primRepSizeW dflags) a_reps_pushed_r_to_l))++ push_args = concatOL pushs_arg+ d_after_args = d0 + a_reps_sizeW+ a_reps_pushed_RAW+ | null a_reps_pushed_r_to_l || head a_reps_pushed_r_to_l /= VoidRep+ = panic "ByteCodeGen.generateCCall: missing or invalid World token?"+ | otherwise+ = reverse (tail a_reps_pushed_r_to_l)++ -- Now: a_reps_pushed_RAW are the reps which are actually on the stack.+ -- push_args is the code to do that.+ -- d_after_args is the stack depth once the args are on.++ -- Get the result rep.+ (returns_void, r_rep)+ = case maybe_getCCallReturnRep (idType fn) of+ Nothing -> (True, VoidRep)+ Just rr -> (False, rr)+ {-+ Because the Haskell stack grows down, the a_reps refer to+ lowest to highest addresses in that order. The args for the call+ are on the stack. Now push an unboxed Addr# indicating+ the C function to call. Then push a dummy placeholder for the+ result. Finally, emit a CCALL insn with an offset pointing to the+ Addr# just pushed, and a literal field holding the mallocville+ address of the piece of marshalling code we generate.+ So, just prior to the CCALL insn, the stack looks like this+ (growing down, as usual):++ <arg_n>+ ...+ <arg_1>+ Addr# address_of_C_fn+ <placeholder-for-result#> (must be an unboxed type)++ The interpreter then calls the marshall code mentioned+ in the CCALL insn, passing it (& <placeholder-for-result#>),+ that is, the addr of the topmost word in the stack.+ When this returns, the placeholder will have been+ filled in. The placeholder is slid down to the sequel+ depth, and we RETURN.++ This arrangement makes it simple to do f-i-dynamic since the Addr#+ value is the first arg anyway.++ The marshalling code is generated specifically for this+ call site, and so knows exactly the (Haskell) stack+ offsets of the args, fn address and placeholder. It+ copies the args to the C stack, calls the stacked addr,+ and parks the result back in the placeholder. The interpreter+ calls it as a normal C call, assuming it has a signature+ void marshall_code ( StgWord* ptr_to_top_of_stack )+ -}+ -- resolve static address+ maybe_static_target =+ case target of+ DynamicTarget -> Nothing+ StaticTarget _ _ _ False ->+ panic "generateCCall: unexpected FFI value import"+ StaticTarget _ target _ True ->+ Just (MachLabel target mb_size IsFunction)+ where+ mb_size+ | OSMinGW32 <- platformOS (targetPlatform dflags)+ , StdCallConv <- cconv+ = Just (fromIntegral a_reps_sizeW * wORD_SIZE dflags)+ | otherwise+ = Nothing++ let+ is_static = isJust maybe_static_target++ -- Get the arg reps, zapping the leading Addr# in the dynamic case+ a_reps -- | trace (showSDoc (ppr a_reps_pushed_RAW)) False = error "???"+ | is_static = a_reps_pushed_RAW+ | otherwise = if null a_reps_pushed_RAW+ then panic "ByteCodeGen.generateCCall: dyn with no args"+ else tail a_reps_pushed_RAW++ -- push the Addr#+ (push_Addr, d_after_Addr)+ | Just machlabel <- maybe_static_target+ = (toOL [PUSH_UBX machlabel addr_sizeW],+ d_after_args + fromIntegral addr_sizeW)+ | otherwise -- is already on the stack+ = (nilOL, d_after_args)++ -- Push the return placeholder. For a call returning nothing,+ -- this is a V (tag).+ r_sizeW = fromIntegral (primRepSizeW dflags r_rep)+ d_after_r = d_after_Addr + fromIntegral r_sizeW+ push_r = (if returns_void+ then nilOL+ else unitOL (PUSH_UBX (mkDummyLiteral r_rep) r_sizeW))++ -- generate the marshalling code we're going to call++ -- Offset of the next stack frame down the stack. The CCALL+ -- instruction needs to describe the chunk of stack containing+ -- the ccall args to the GC, so it needs to know how large it+ -- is. See comment in Interpreter.c with the CCALL instruction.+ stk_offset = trunc16 $ d_after_r - s++ conv = case cconv of+ CCallConv -> FFICCall+ StdCallConv -> FFIStdCall+ _ -> panic "ByteCodeGen: unexpected calling convention"++ -- the only difference in libffi mode is that we prepare a cif+ -- describing the call type by calling libffi, and we attach the+ -- address of this to the CCALL instruction.+++ let ffires = primRepToFFIType dflags r_rep+ ffiargs = map (primRepToFFIType dflags) a_reps+ hsc_env <- getHscEnv+ token <- ioToBc $ iservCmd hsc_env (PrepFFI conv ffiargs ffires)+ recordFFIBc token++ let+ -- do the call+ do_call = unitOL (CCALL stk_offset token+ (fromIntegral (fromEnum (playInterruptible safety))))+ -- slide and return+ wrapup = mkSLIDE r_sizeW (d_after_r - fromIntegral r_sizeW - s)+ `snocOL` RETURN_UBX (toArgRep r_rep)+ --trace (show (arg1_offW, args_offW , (map argRepSizeW a_reps) )) $+ return (+ push_args `appOL`+ push_Addr `appOL` push_r `appOL` do_call `appOL` wrapup+ )++primRepToFFIType :: DynFlags -> PrimRep -> FFIType+primRepToFFIType dflags r+ = case r of+ VoidRep -> FFIVoid+ IntRep -> signed_word+ WordRep -> unsigned_word+ Int64Rep -> FFISInt64+ Word64Rep -> FFIUInt64+ AddrRep -> FFIPointer+ FloatRep -> FFIFloat+ DoubleRep -> FFIDouble+ _ -> panic "primRepToFFIType"+ where+ (signed_word, unsigned_word)+ | wORD_SIZE dflags == 4 = (FFISInt32, FFIUInt32)+ | wORD_SIZE dflags == 8 = (FFISInt64, FFIUInt64)+ | otherwise = panic "primTyDescChar"++-- Make a dummy literal, to be used as a placeholder for FFI return+-- values on the stack.+mkDummyLiteral :: PrimRep -> Literal+mkDummyLiteral pr+ = case pr of+ IntRep -> MachInt 0+ WordRep -> MachWord 0+ AddrRep -> MachNullAddr+ DoubleRep -> MachDouble 0+ FloatRep -> MachFloat 0+ Int64Rep -> MachInt64 0+ Word64Rep -> MachWord64 0+ _ -> pprPanic "mkDummyLiteral" (ppr pr)+++-- Convert (eg)+-- GHC.Prim.Char# -> GHC.Prim.State# GHC.Prim.RealWorld+-- -> (# GHC.Prim.State# GHC.Prim.RealWorld, GHC.Prim.Int# #)+--+-- to Just IntRep+-- and check that an unboxed pair is returned wherein the first arg is V'd.+--+-- Alternatively, for call-targets returning nothing, convert+--+-- GHC.Prim.Char# -> GHC.Prim.State# GHC.Prim.RealWorld+-- -> (# GHC.Prim.State# GHC.Prim.RealWorld #)+--+-- to Nothing++maybe_getCCallReturnRep :: Type -> Maybe PrimRep+maybe_getCCallReturnRep fn_ty+ = let+ (_a_tys, r_ty) = splitFunTys (dropForAlls fn_ty)+ r_reps = typePrimRepArgs r_ty++ blargh :: a -- Used at more than one type+ blargh = pprPanic "maybe_getCCallReturn: can't handle:"+ (pprType fn_ty)+ in+ case r_reps of+ [] -> panic "empty typePrimRepArgs"+ [VoidRep] -> Nothing+ [rep]+ | isGcPtrRep rep -> blargh+ | otherwise -> Just rep++ -- if it was, it would be impossible to create a+ -- valid return value placeholder on the stack+ _ -> blargh++maybe_is_tagToEnum_call :: AnnExpr' Id DVarSet -> Maybe (AnnExpr' Id DVarSet, [Name])+-- Detect and extract relevant info for the tagToEnum kludge.+maybe_is_tagToEnum_call app+ | AnnApp (_, AnnApp (_, AnnVar v) (_, AnnType t)) arg <- app+ , Just TagToEnumOp <- isPrimOpId_maybe v+ = Just (snd arg, extract_constr_Names t)+ | otherwise+ = Nothing+ where+ extract_constr_Names ty+ | rep_ty <- unwrapType ty+ , Just tyc <- tyConAppTyCon_maybe rep_ty+ , isDataTyCon tyc+ = map (getName . dataConWorkId) (tyConDataCons tyc)+ -- NOTE: use the worker name, not the source name of+ -- the DataCon. See DataCon.hs for details.+ | otherwise+ = pprPanic "maybe_is_tagToEnum_call.extract_constr_Ids" (ppr ty)++{- -----------------------------------------------------------------------------+Note [Implementing tagToEnum#]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(implement_tagToId arg names) compiles code which takes an argument+'arg', (call it i), and enters the i'th closure in the supplied list+as a consequence. The [Name] is a list of the constructors of this+(enumeration) type.++The code we generate is this:+ push arg+ push bogus-word++ TESTEQ_I 0 L1+ PUSH_G <lbl for first data con>+ JMP L_Exit++ L1: TESTEQ_I 1 L2+ PUSH_G <lbl for second data con>+ JMP L_Exit+ ...etc...+ Ln: TESTEQ_I n L_fail+ PUSH_G <lbl for last data con>+ JMP L_Exit++ L_fail: CASEFAIL++ L_exit: SLIDE 1 n+ ENTER++The 'bogus-word' push is because TESTEQ_I expects the top of the stack+to have an info-table, and the next word to have the value to be+tested. This is very weird, but it's the way it is right now. See+Interpreter.c. We don't acutally need an info-table here; we just+need to have the argument to be one-from-top on the stack, hence pushing+a 1-word null. See Trac #8383.+-}+++implement_tagToId :: Word -> Sequel -> BCEnv+ -> AnnExpr' Id DVarSet -> [Name] -> BcM BCInstrList+-- See Note [Implementing tagToEnum#]+implement_tagToId d s p arg names+ = ASSERT( notNull names )+ do (push_arg, arg_words) <- pushAtom d p arg+ labels <- getLabelsBc (genericLength names)+ label_fail <- getLabelBc+ label_exit <- getLabelBc+ let infos = zip4 labels (tail labels ++ [label_fail])+ [0 ..] names+ steps = map (mkStep label_exit) infos++ return (push_arg+ `appOL` unitOL (PUSH_UBX MachNullAddr 1)+ -- Push bogus word (see Note [Implementing tagToEnum#])+ `appOL` concatOL steps+ `appOL` toOL [ LABEL label_fail, CASEFAIL,+ LABEL label_exit ]+ `appOL` mkSLIDE 1 (d - s + fromIntegral arg_words + 1)+ -- "+1" to account for bogus word+ -- (see Note [Implementing tagToEnum#])+ `appOL` unitOL ENTER)+ where+ mkStep l_exit (my_label, next_label, n, name_for_n)+ = toOL [LABEL my_label,+ TESTEQ_I n next_label,+ PUSH_G name_for_n,+ JMP l_exit]+++-- -----------------------------------------------------------------------------+-- pushAtom++-- Push an atom onto the stack, returning suitable code & number of+-- stack words used.+--+-- The env p must map each variable to the highest- numbered stack+-- slot for it. For example, if the stack has depth 4 and we+-- tagged-ly push (v :: Int#) on it, the value will be in stack[4],+-- the tag in stack[5], the stack will have depth 6, and p must map v+-- to 5 and not to 4. Stack locations are numbered from zero, so a+-- depth 6 stack has valid words 0 .. 5.++pushAtom :: Word -> BCEnv -> AnnExpr' Id DVarSet -> BcM (BCInstrList, Word16)++pushAtom d p e+ | Just e' <- bcView e+ = pushAtom d p e'++pushAtom _ _ (AnnCoercion {}) -- Coercions are zero-width things,+ = return (nilOL, 0) -- treated just like a variable V++-- See Note [Empty case alternatives] in coreSyn/CoreSyn.hs+-- and Note [Bottoming expressions] in coreSyn/CoreUtils.hs:+-- The scrutinee of an empty case evaluates to bottom+pushAtom d p (AnnCase (_, a) _ _ []) -- trac #12128+ = pushAtom d p a++pushAtom d p (AnnVar v)+ | [] <- typePrimRep (idType v)+ = return (nilOL, 0)++ | isFCallId v+ = pprPanic "pushAtom: shouldn't get an FCallId here" (ppr v)++ | Just primop <- isPrimOpId_maybe v+ = return (unitOL (PUSH_PRIMOP primop), 1)++ | Just d_v <- lookupBCEnv_maybe v p -- v is a local variable+ = do dflags <- getDynFlags+ let sz :: Word16+ sz = fromIntegral (idSizeW dflags v)+ l = trunc16 $ d - d_v + fromIntegral sz - 2+ return (toOL (genericReplicate sz (PUSH_L l)), sz)+ -- d - d_v the number of words between the TOS+ -- and the 1st slot of the object+ --+ -- d - d_v - 1 the offset from the TOS of the 1st slot+ --+ -- d - d_v - 1 + sz - 1 the offset from the TOS of the last slot+ -- of the object.+ --+ -- Having found the last slot, we proceed to copy the right number of+ -- slots on to the top of the stack.++ | otherwise -- v must be a global variable+ = do topStrings <- getTopStrings+ case lookupVarEnv topStrings v of+ Just ptr -> pushAtom d p $ AnnLit $ MachWord $ fromIntegral $+ ptrToWordPtr $ fromRemotePtr ptr+ Nothing -> do+ dflags <- getDynFlags+ let sz :: Word16+ sz = fromIntegral (idSizeW dflags v)+ MASSERT(sz == 1)+ return (unitOL (PUSH_G (getName v)), sz)+++pushAtom _ _ (AnnLit lit) = do+ dflags <- getDynFlags+ let code rep+ = let size_host_words = fromIntegral (argRepSizeW dflags rep)+ in return (unitOL (PUSH_UBX lit size_host_words),+ size_host_words)++ case lit of+ MachLabel _ _ _ -> code N+ MachWord _ -> code N+ MachInt _ -> code N+ MachWord64 _ -> code L+ MachInt64 _ -> code L+ MachFloat _ -> code F+ MachDouble _ -> code D+ MachChar _ -> code N+ MachNullAddr -> code N+ MachStr _ -> code N+ -- No LitInteger's should be left by the time this is called.+ -- CorePrep should have converted them all to a real core+ -- representation.+ LitInteger {} -> panic "pushAtom: LitInteger"++pushAtom _ _ expr+ = pprPanic "ByteCodeGen.pushAtom"+ (pprCoreExpr (deAnnotate' expr))+++-- -----------------------------------------------------------------------------+-- Given a bunch of alts code and their discrs, do the donkey work+-- of making a multiway branch using a switch tree.+-- What a load of hassle!++mkMultiBranch :: Maybe Int -- # datacons in tycon, if alg alt+ -- a hint; generates better code+ -- Nothing is always safe+ -> [(Discr, BCInstrList)]+ -> BcM BCInstrList+mkMultiBranch maybe_ncons raw_ways = do+ lbl_default <- getLabelBc++ let+ mkTree :: [(Discr, BCInstrList)] -> Discr -> Discr -> BcM BCInstrList+ mkTree [] _range_lo _range_hi = return (unitOL (JMP lbl_default))+ -- shouldn't happen?++ mkTree [val] range_lo range_hi+ | range_lo == range_hi+ = return (snd val)+ | null defaults -- Note [CASEFAIL]+ = do lbl <- getLabelBc+ return (testEQ (fst val) lbl+ `consOL` (snd val+ `appOL` (LABEL lbl `consOL` unitOL CASEFAIL)))+ | otherwise+ = return (testEQ (fst val) lbl_default `consOL` snd val)++ -- Note [CASEFAIL] It may be that this case has no default+ -- branch, but the alternatives are not exhaustive - this+ -- happens for GADT cases for example, where the types+ -- prove that certain branches are impossible. We could+ -- just assume that the other cases won't occur, but if+ -- this assumption was wrong (because of a bug in GHC)+ -- then the result would be a segfault. So instead we+ -- emit an explicit test and a CASEFAIL instruction that+ -- causes the interpreter to barf() if it is ever+ -- executed.++ mkTree vals range_lo range_hi+ = let n = length vals `div` 2+ vals_lo = take n vals+ vals_hi = drop n vals+ v_mid = fst (head vals_hi)+ in do+ label_geq <- getLabelBc+ code_lo <- mkTree vals_lo range_lo (dec v_mid)+ code_hi <- mkTree vals_hi v_mid range_hi+ return (testLT v_mid label_geq+ `consOL` (code_lo+ `appOL` unitOL (LABEL label_geq)+ `appOL` code_hi))++ the_default+ = case defaults of+ [] -> nilOL+ [(_, def)] -> LABEL lbl_default `consOL` def+ _ -> panic "mkMultiBranch/the_default"+ instrs <- mkTree notd_ways init_lo init_hi+ return (instrs `appOL` the_default)+ where+ (defaults, not_defaults) = partition (isNoDiscr.fst) raw_ways+ notd_ways = sortBy (comparing fst) not_defaults++ testLT (DiscrI i) fail_label = TESTLT_I i fail_label+ testLT (DiscrW i) fail_label = TESTLT_W i fail_label+ testLT (DiscrF i) fail_label = TESTLT_F i fail_label+ testLT (DiscrD i) fail_label = TESTLT_D i fail_label+ testLT (DiscrP i) fail_label = TESTLT_P i fail_label+ testLT NoDiscr _ = panic "mkMultiBranch NoDiscr"++ testEQ (DiscrI i) fail_label = TESTEQ_I i fail_label+ testEQ (DiscrW i) fail_label = TESTEQ_W i fail_label+ testEQ (DiscrF i) fail_label = TESTEQ_F i fail_label+ testEQ (DiscrD i) fail_label = TESTEQ_D i fail_label+ testEQ (DiscrP i) fail_label = TESTEQ_P i fail_label+ testEQ NoDiscr _ = panic "mkMultiBranch NoDiscr"++ -- None of these will be needed if there are no non-default alts+ (init_lo, init_hi)+ | null notd_ways+ = panic "mkMultiBranch: awesome foursome"+ | otherwise+ = case fst (head notd_ways) of+ DiscrI _ -> ( DiscrI minBound, DiscrI maxBound )+ DiscrW _ -> ( DiscrW minBound, DiscrW maxBound )+ DiscrF _ -> ( DiscrF minF, DiscrF maxF )+ DiscrD _ -> ( DiscrD minD, DiscrD maxD )+ DiscrP _ -> ( DiscrP algMinBound, DiscrP algMaxBound )+ NoDiscr -> panic "mkMultiBranch NoDiscr"++ (algMinBound, algMaxBound)+ = case maybe_ncons of+ -- XXX What happens when n == 0?+ Just n -> (0, fromIntegral n - 1)+ Nothing -> (minBound, maxBound)++ isNoDiscr NoDiscr = True+ isNoDiscr _ = False++ dec (DiscrI i) = DiscrI (i-1)+ dec (DiscrW w) = DiscrW (w-1)+ dec (DiscrP i) = DiscrP (i-1)+ dec other = other -- not really right, but if you+ -- do cases on floating values, you'll get what you deserve++ -- same snotty comment applies to the following+ minF, maxF :: Float+ minD, maxD :: Double+ minF = -1.0e37+ maxF = 1.0e37+ minD = -1.0e308+ maxD = 1.0e308+++-- -----------------------------------------------------------------------------+-- Supporting junk for the compilation schemes++-- Describes case alts+data Discr+ = DiscrI Int+ | DiscrW Word+ | DiscrF Float+ | DiscrD Double+ | DiscrP Word16+ | NoDiscr+ deriving (Eq, Ord)++instance Outputable Discr where+ ppr (DiscrI i) = int i+ ppr (DiscrW w) = text (show w)+ ppr (DiscrF f) = text (show f)+ ppr (DiscrD d) = text (show d)+ ppr (DiscrP i) = ppr i+ ppr NoDiscr = text "DEF"+++lookupBCEnv_maybe :: Id -> BCEnv -> Maybe Word+lookupBCEnv_maybe = Map.lookup++idSizeW :: DynFlags -> Id -> Int+idSizeW dflags = argRepSizeW dflags . bcIdArgRep++bcIdArgRep :: Id -> ArgRep+bcIdArgRep = toArgRep . bcIdPrimRep++bcIdPrimRep :: Id -> PrimRep+bcIdPrimRep id+ | [rep] <- typePrimRepArgs (idType id)+ = rep+ | otherwise+ = pprPanic "bcIdPrimRep" (ppr id <+> dcolon <+> ppr (idType id))++isFollowableArg :: ArgRep -> Bool+isFollowableArg P = True+isFollowableArg _ = False++isVoidArg :: ArgRep -> Bool+isVoidArg V = True+isVoidArg _ = False++-- See bug #1257+multiValException :: a+multiValException = throwGhcException (ProgramError+ ("Error: bytecode compiler can't handle unboxed tuples and sums.\n"+++ " Possibly due to foreign import/export decls in source.\n"+++ " Workaround: use -fobject-code, or compile this module to .o separately."))++-- | Indicate if the calling convention is supported+isSupportedCConv :: CCallSpec -> Bool+isSupportedCConv (CCallSpec _ cconv _) = case cconv of+ CCallConv -> True -- we explicitly pattern match on every+ StdCallConv -> True -- convention to ensure that a warning+ PrimCallConv -> False -- is triggered when a new one is added+ JavaScriptCallConv -> False+ CApiConv -> False++-- See bug #10462+unsupportedCConvException :: a+unsupportedCConvException = throwGhcException (ProgramError+ ("Error: bytecode compiler can't handle some foreign calling conventions\n"+++ " Workaround: use -fobject-code, or compile this module to .o separately."))++mkSLIDE :: Word16 -> Word -> OrdList BCInstr+mkSLIDE n d+ -- if the amount to slide doesn't fit in a word,+ -- generate multiple slide instructions+ | d > fromIntegral limit+ = SLIDE n limit `consOL` mkSLIDE n (d - fromIntegral limit)+ | d == 0+ = nilOL+ | otherwise+ = if d == 0 then nilOL else unitOL (SLIDE n $ fromIntegral d)+ where+ limit :: Word16+ limit = maxBound++splitApp :: AnnExpr' Var ann -> (AnnExpr' Var ann, [AnnExpr' Var ann])+ -- The arguments are returned in *right-to-left* order+splitApp e | Just e' <- bcView e = splitApp e'+splitApp (AnnApp (_,f) (_,a)) = case splitApp f of+ (f', as) -> (f', a:as)+splitApp e = (e, [])+++bcView :: AnnExpr' Var ann -> Maybe (AnnExpr' Var ann)+-- The "bytecode view" of a term discards+-- a) type abstractions+-- b) type applications+-- c) casts+-- d) ticks (but not breakpoints)+-- Type lambdas *can* occur in random expressions,+-- whereas value lambdas cannot; that is why they are nuked here+bcView (AnnCast (_,e) _) = Just e+bcView (AnnLam v (_,e)) | isTyVar v = Just e+bcView (AnnApp (_,e) (_, AnnType _)) = Just e+bcView (AnnTick Breakpoint{} _) = Nothing+bcView (AnnTick _other_tick (_,e)) = Just e+bcView _ = Nothing++isVAtom :: AnnExpr' Var ann -> Bool+isVAtom e | Just e' <- bcView e = isVAtom e'+isVAtom (AnnVar v) = isVoidArg (bcIdArgRep v)+isVAtom (AnnCoercion {}) = True+isVAtom _ = False++atomPrimRep :: AnnExpr' Id ann -> PrimRep+atomPrimRep e | Just e' <- bcView e = atomPrimRep e'+atomPrimRep (AnnVar v) = bcIdPrimRep v+atomPrimRep (AnnLit l) = typePrimRep1 (literalType l)++-- Trac #12128:+-- A case expression can be an atom because empty cases evaluate to bottom.+-- See Note [Empty case alternatives] in coreSyn/CoreSyn.hs+atomPrimRep (AnnCase _ _ ty _) = ASSERT(typePrimRep ty == [LiftedRep]) LiftedRep+atomPrimRep (AnnCoercion {}) = VoidRep+atomPrimRep other = pprPanic "atomPrimRep" (ppr (deAnnotate' other))++atomRep :: AnnExpr' Id ann -> ArgRep+atomRep e = toArgRep (atomPrimRep e)++isPtrAtom :: AnnExpr' Id ann -> Bool+isPtrAtom e = isFollowableArg (atomRep e)++-- Let szsw be the sizes in words of some items pushed onto the stack,+-- which has initial depth d'. Return the values which the stack environment+-- should map these items to.+mkStackOffsets :: Word -> [Word] -> [Word]+mkStackOffsets original_depth szsw+ = map (subtract 1) (tail (scanl (+) original_depth szsw))++typeArgRep :: Type -> ArgRep+typeArgRep = toArgRep . typePrimRep1++-- -----------------------------------------------------------------------------+-- The bytecode generator's monad++data BcM_State+ = BcM_State+ { bcm_hsc_env :: HscEnv+ , uniqSupply :: UniqSupply -- for generating fresh variable names+ , thisModule :: Module -- current module (for breakpoints)+ , nextlabel :: Word16 -- for generating local labels+ , ffis :: [FFIInfo] -- ffi info blocks, to free later+ -- Should be free()d when it is GCd+ , modBreaks :: Maybe ModBreaks -- info about breakpoints+ , breakInfo :: IntMap CgBreakInfo+ , topStrings :: IdEnv (RemotePtr ()) -- top-level string literals+ -- See Note [generating code for top-level string literal bindings].+ }++newtype BcM r = BcM (BcM_State -> IO (BcM_State, r))++ioToBc :: IO a -> BcM a+ioToBc io = BcM $ \st -> do+ x <- io+ return (st, x)++runBc :: HscEnv -> UniqSupply -> Module -> Maybe ModBreaks+ -> IdEnv (RemotePtr ())+ -> BcM r+ -> IO (BcM_State, r)+runBc hsc_env us this_mod modBreaks topStrings (BcM m)+ = m (BcM_State hsc_env us this_mod 0 [] modBreaks IntMap.empty topStrings)++thenBc :: BcM a -> (a -> BcM b) -> BcM b+thenBc (BcM expr) cont = BcM $ \st0 -> do+ (st1, q) <- expr st0+ let BcM k = cont q+ (st2, r) <- k st1+ return (st2, r)++thenBc_ :: BcM a -> BcM b -> BcM b+thenBc_ (BcM expr) (BcM cont) = BcM $ \st0 -> do+ (st1, _) <- expr st0+ (st2, r) <- cont st1+ return (st2, r)++returnBc :: a -> BcM a+returnBc result = BcM $ \st -> (return (st, result))++instance Functor BcM where+ fmap = liftM++instance Applicative BcM where+ pure = returnBc+ (<*>) = ap+ (*>) = thenBc_++instance Monad BcM where+ (>>=) = thenBc+ (>>) = (*>)++instance HasDynFlags BcM where+ getDynFlags = BcM $ \st -> return (st, hsc_dflags (bcm_hsc_env st))++getHscEnv :: BcM HscEnv+getHscEnv = BcM $ \st -> return (st, bcm_hsc_env st)++emitBc :: ([FFIInfo] -> ProtoBCO Name) -> BcM (ProtoBCO Name)+emitBc bco+ = BcM $ \st -> return (st{ffis=[]}, bco (ffis st))++recordFFIBc :: RemotePtr C_ffi_cif -> BcM ()+recordFFIBc a+ = BcM $ \st -> return (st{ffis = FFIInfo a : ffis st}, ())++getLabelBc :: BcM Word16+getLabelBc+ = BcM $ \st -> do let nl = nextlabel st+ when (nl == maxBound) $+ panic "getLabelBc: Ran out of labels"+ return (st{nextlabel = nl + 1}, nl)++getLabelsBc :: Word16 -> BcM [Word16]+getLabelsBc n+ = BcM $ \st -> let ctr = nextlabel st+ in return (st{nextlabel = ctr+n}, [ctr .. ctr+n-1])++getCCArray :: BcM (Array BreakIndex (RemotePtr CostCentre))+getCCArray = BcM $ \st ->+ let breaks = expectJust "ByteCodeGen.getCCArray" $ modBreaks st in+ return (st, modBreaks_ccs breaks)+++newBreakInfo :: BreakIndex -> CgBreakInfo -> BcM ()+newBreakInfo ix info = BcM $ \st ->+ return (st{breakInfo = IntMap.insert ix info (breakInfo st)}, ())++newUnique :: BcM Unique+newUnique = BcM $+ \st -> case takeUniqFromSupply (uniqSupply st) of+ (uniq, us) -> let newState = st { uniqSupply = us }+ in return (newState, uniq)++getCurrentModule :: BcM Module+getCurrentModule = BcM $ \st -> return (st, thisModule st)++getTopStrings :: BcM (IdEnv (RemotePtr ()))+getTopStrings = BcM $ \st -> return (st, topStrings st)++newId :: Type -> BcM Id+newId ty = do+ uniq <- newUnique+ return $ mkSysLocal tickFS uniq ty++tickFS :: FastString+tickFS = fsLit "ticked"
+ ghci/ByteCodeInstr.hs view
@@ -0,0 +1,315 @@+{-# LANGUAGE CPP, MagicHash #-}+{-# OPTIONS_GHC -funbox-strict-fields #-}+--+-- (c) The University of Glasgow 2002-2006+--++-- | ByteCodeInstrs: Bytecode instruction definitions+module ByteCodeInstr (+ BCInstr(..), ProtoBCO(..), bciStackUse,+ ) where++#include "HsVersions.h"+#include "MachDeps.h"++import ByteCodeTypes+import GHCi.RemoteTypes+import GHCi.FFI (C_ffi_cif)+import StgCmmLayout ( ArgRep(..) )+import PprCore+import Outputable+import FastString+import Name+import Unique+import Id+import CoreSyn+import Literal+import DataCon+import VarSet+import PrimOp+import SMRep++import Data.Word+#if MIN_VERSION_base(4,9,0)+import GHC.Stack.CCS (CostCentre)+#else+import GHC.Stack (CostCentre)+#endif++-- ----------------------------------------------------------------------------+-- Bytecode instructions++data ProtoBCO a+ = ProtoBCO {+ protoBCOName :: a, -- name, in some sense+ protoBCOInstrs :: [BCInstr], -- instrs+ -- arity and GC info+ protoBCOBitmap :: [StgWord],+ protoBCOBitmapSize :: Word16,+ protoBCOArity :: Int,+ -- what the BCO came from+ protoBCOExpr :: Either [AnnAlt Id DVarSet] (AnnExpr Id DVarSet),+ -- malloc'd pointers+ protoBCOFFIs :: [FFIInfo]+ }++type LocalLabel = Word16++data BCInstr+ -- Messing with the stack+ = STKCHECK Word++ -- Push locals (existing bits of the stack)+ | PUSH_L !Word16{-offset-}+ | PUSH_LL !Word16 !Word16{-2 offsets-}+ | PUSH_LLL !Word16 !Word16 !Word16{-3 offsets-}++ -- Push a ptr (these all map to PUSH_G really)+ | PUSH_G Name+ | PUSH_PRIMOP PrimOp+ | PUSH_BCO (ProtoBCO Name)++ -- Push an alt continuation+ | PUSH_ALTS (ProtoBCO Name)+ | PUSH_ALTS_UNLIFTED (ProtoBCO Name) ArgRep++ -- Pushing literals+ | PUSH_UBX Literal Word16+ -- push this int/float/double/addr, on the stack. Word16+ -- is # of words to copy from literal pool. Eitherness reflects+ -- the difficulty of dealing with MachAddr here, mostly due to+ -- the excessive (and unnecessary) restrictions imposed by the+ -- designers of the new Foreign library. In particular it is+ -- quite impossible to convert an Addr to any other integral+ -- type, and it appears impossible to get hold of the bits of+ -- an addr, even though we need to assemble BCOs.++ -- various kinds of application+ | PUSH_APPLY_N+ | PUSH_APPLY_V+ | PUSH_APPLY_F+ | PUSH_APPLY_D+ | PUSH_APPLY_L+ | PUSH_APPLY_P+ | PUSH_APPLY_PP+ | PUSH_APPLY_PPP+ | PUSH_APPLY_PPPP+ | PUSH_APPLY_PPPPP+ | PUSH_APPLY_PPPPPP++ | SLIDE Word16{-this many-} Word16{-down by this much-}++ -- To do with the heap+ | ALLOC_AP !Word16 -- make an AP with this many payload words+ | ALLOC_AP_NOUPD !Word16 -- make an AP_NOUPD with this many payload words+ | ALLOC_PAP !Word16 !Word16 -- make a PAP with this arity / payload words+ | MKAP !Word16{-ptr to AP is this far down stack-} !Word16{-number of words-}+ | MKPAP !Word16{-ptr to PAP is this far down stack-} !Word16{-number of words-}+ | UNPACK !Word16 -- unpack N words from t.o.s Constr+ | PACK DataCon !Word16+ -- after assembly, the DataCon is an index into the+ -- itbl array+ -- For doing case trees+ | LABEL LocalLabel+ | TESTLT_I Int LocalLabel+ | TESTEQ_I Int LocalLabel+ | TESTLT_W Word LocalLabel+ | TESTEQ_W Word LocalLabel+ | TESTLT_F Float LocalLabel+ | TESTEQ_F Float LocalLabel+ | TESTLT_D Double LocalLabel+ | TESTEQ_D Double LocalLabel++ -- The Word16 value is a constructor number and therefore+ -- stored in the insn stream rather than as an offset into+ -- the literal pool.+ | TESTLT_P Word16 LocalLabel+ | TESTEQ_P Word16 LocalLabel++ | CASEFAIL+ | JMP LocalLabel++ -- For doing calls to C (via glue code generated by libffi)+ | CCALL Word16 -- stack frame size+ (RemotePtr C_ffi_cif) -- addr of the glue code+ Word16 -- whether or not the call is interruptible+ -- (XXX: inefficient, but I don't know+ -- what the alignment constraints are.)++ -- For doing magic ByteArray passing to foreign calls+ | SWIZZLE Word16 -- to the ptr N words down the stack,+ Word16 -- add M (interpreted as a signed 16-bit entity)++ -- To Infinity And Beyond+ | ENTER+ | RETURN -- return a lifted value+ | RETURN_UBX ArgRep -- return an unlifted value, here's its rep++ -- Breakpoints+ | BRK_FUN Word16 Unique (RemotePtr CostCentre)++-- -----------------------------------------------------------------------------+-- Printing bytecode instructions++instance Outputable a => Outputable (ProtoBCO a) where+ ppr (ProtoBCO name instrs bitmap bsize arity origin ffis)+ = (text "ProtoBCO" <+> ppr name <> char '#' <> int arity+ <+> text (show ffis) <> colon)+ $$ nest 3 (case origin of+ Left alts -> vcat (zipWith (<+>) (char '{' : repeat (char ';'))+ (map (pprCoreAltShort.deAnnAlt) alts)) <+> char '}'+ Right rhs -> pprCoreExprShort (deAnnotate rhs))+ $$ nest 3 (text "bitmap: " <+> text (show bsize) <+> ppr bitmap)+ $$ nest 3 (vcat (map ppr instrs))++-- Print enough of the Core expression to enable the reader to find+-- the expression in the -ddump-prep output. That is, we need to+-- include at least a binder.++pprCoreExprShort :: CoreExpr -> SDoc+pprCoreExprShort expr@(Lam _ _)+ = let+ (bndrs, _) = collectBinders expr+ in+ char '\\' <+> sep (map (pprBndr LambdaBind) bndrs) <+> arrow <+> text "..."++pprCoreExprShort (Case _expr var _ty _alts)+ = text "case of" <+> ppr var++pprCoreExprShort (Let (NonRec x _) _) = text "let" <+> ppr x <+> ptext (sLit ("= ... in ..."))+pprCoreExprShort (Let (Rec bs) _) = text "let {" <+> ppr (fst (head bs)) <+> ptext (sLit ("= ...; ... } in ..."))++pprCoreExprShort (Tick t e) = ppr t <+> pprCoreExprShort e+pprCoreExprShort (Cast e _) = pprCoreExprShort e <+> text "`cast` T"++pprCoreExprShort e = pprCoreExpr e++pprCoreAltShort :: CoreAlt -> SDoc+pprCoreAltShort (con, args, expr) = ppr con <+> sep (map ppr args) <+> text "->" <+> pprCoreExprShort expr++instance Outputable BCInstr where+ ppr (STKCHECK n) = text "STKCHECK" <+> ppr n+ ppr (PUSH_L offset) = text "PUSH_L " <+> ppr offset+ ppr (PUSH_LL o1 o2) = text "PUSH_LL " <+> ppr o1 <+> ppr o2+ ppr (PUSH_LLL o1 o2 o3) = text "PUSH_LLL" <+> ppr o1 <+> ppr o2 <+> ppr o3+ ppr (PUSH_G nm) = text "PUSH_G " <+> ppr nm+ ppr (PUSH_PRIMOP op) = text "PUSH_G " <+> text "GHC.PrimopWrappers."+ <> ppr op+ ppr (PUSH_BCO bco) = hang (text "PUSH_BCO") 2 (ppr bco)+ ppr (PUSH_ALTS bco) = hang (text "PUSH_ALTS") 2 (ppr bco)+ ppr (PUSH_ALTS_UNLIFTED bco pk) = hang (text "PUSH_ALTS_UNLIFTED" <+> ppr pk) 2 (ppr bco)++ ppr (PUSH_UBX lit nw) = text "PUSH_UBX" <+> parens (ppr nw) <+> ppr lit+ ppr PUSH_APPLY_N = text "PUSH_APPLY_N"+ ppr PUSH_APPLY_V = text "PUSH_APPLY_V"+ ppr PUSH_APPLY_F = text "PUSH_APPLY_F"+ ppr PUSH_APPLY_D = text "PUSH_APPLY_D"+ ppr PUSH_APPLY_L = text "PUSH_APPLY_L"+ ppr PUSH_APPLY_P = text "PUSH_APPLY_P"+ ppr PUSH_APPLY_PP = text "PUSH_APPLY_PP"+ ppr PUSH_APPLY_PPP = text "PUSH_APPLY_PPP"+ ppr PUSH_APPLY_PPPP = text "PUSH_APPLY_PPPP"+ ppr PUSH_APPLY_PPPPP = text "PUSH_APPLY_PPPPP"+ ppr PUSH_APPLY_PPPPPP = text "PUSH_APPLY_PPPPPP"++ ppr (SLIDE n d) = text "SLIDE " <+> ppr n <+> ppr d+ ppr (ALLOC_AP sz) = text "ALLOC_AP " <+> ppr sz+ ppr (ALLOC_AP_NOUPD sz) = text "ALLOC_AP_NOUPD " <+> ppr sz+ ppr (ALLOC_PAP arity sz) = text "ALLOC_PAP " <+> ppr arity <+> ppr sz+ ppr (MKAP offset sz) = text "MKAP " <+> ppr sz <+> text "words,"+ <+> ppr offset <+> text "stkoff"+ ppr (MKPAP offset sz) = text "MKPAP " <+> ppr sz <+> text "words,"+ <+> ppr offset <+> text "stkoff"+ ppr (UNPACK sz) = text "UNPACK " <+> ppr sz+ ppr (PACK dcon sz) = text "PACK " <+> ppr dcon <+> ppr sz+ ppr (LABEL lab) = text "__" <> ppr lab <> colon+ ppr (TESTLT_I i lab) = text "TESTLT_I" <+> int i <+> text "__" <> ppr lab+ ppr (TESTEQ_I i lab) = text "TESTEQ_I" <+> int i <+> text "__" <> ppr lab+ ppr (TESTLT_W i lab) = text "TESTLT_W" <+> int (fromIntegral i) <+> text "__" <> ppr lab+ ppr (TESTEQ_W i lab) = text "TESTEQ_W" <+> int (fromIntegral i) <+> text "__" <> ppr lab+ ppr (TESTLT_F f lab) = text "TESTLT_F" <+> float f <+> text "__" <> ppr lab+ ppr (TESTEQ_F f lab) = text "TESTEQ_F" <+> float f <+> text "__" <> ppr lab+ ppr (TESTLT_D d lab) = text "TESTLT_D" <+> double d <+> text "__" <> ppr lab+ ppr (TESTEQ_D d lab) = text "TESTEQ_D" <+> double d <+> text "__" <> ppr lab+ ppr (TESTLT_P i lab) = text "TESTLT_P" <+> ppr i <+> text "__" <> ppr lab+ ppr (TESTEQ_P i lab) = text "TESTEQ_P" <+> ppr i <+> text "__" <> ppr lab+ ppr CASEFAIL = text "CASEFAIL"+ ppr (JMP lab) = text "JMP" <+> ppr lab+ ppr (CCALL off marshall_addr int) = text "CCALL " <+> ppr off+ <+> text "marshall code at"+ <+> text (show marshall_addr)+ <+> (if int == 1+ then text "(interruptible)"+ else empty)+ ppr (SWIZZLE stkoff n) = text "SWIZZLE " <+> text "stkoff" <+> ppr stkoff+ <+> text "by" <+> ppr n+ ppr ENTER = text "ENTER"+ ppr RETURN = text "RETURN"+ ppr (RETURN_UBX pk) = text "RETURN_UBX " <+> ppr pk+ ppr (BRK_FUN index uniq _cc) = text "BRK_FUN" <+> ppr index <+> ppr uniq <+> text "<cc>"++-- -----------------------------------------------------------------------------+-- The stack use, in words, of each bytecode insn. These _must_ be+-- correct, or overestimates of reality, to be safe.++-- NOTE: we aggregate the stack use from case alternatives too, so that+-- we can do a single stack check at the beginning of a function only.++-- This could all be made more accurate by keeping track of a proper+-- stack high water mark, but it doesn't seem worth the hassle.++protoBCOStackUse :: ProtoBCO a -> Word+protoBCOStackUse bco = sum (map bciStackUse (protoBCOInstrs bco))++bciStackUse :: BCInstr -> Word+bciStackUse STKCHECK{} = 0+bciStackUse PUSH_L{} = 1+bciStackUse PUSH_LL{} = 2+bciStackUse PUSH_LLL{} = 3+bciStackUse PUSH_G{} = 1+bciStackUse PUSH_PRIMOP{} = 1+bciStackUse PUSH_BCO{} = 1+bciStackUse (PUSH_ALTS bco) = 2 + protoBCOStackUse bco+bciStackUse (PUSH_ALTS_UNLIFTED bco _) = 2 + protoBCOStackUse bco+bciStackUse (PUSH_UBX _ nw) = fromIntegral nw+bciStackUse PUSH_APPLY_N{} = 1+bciStackUse PUSH_APPLY_V{} = 1+bciStackUse PUSH_APPLY_F{} = 1+bciStackUse PUSH_APPLY_D{} = 1+bciStackUse PUSH_APPLY_L{} = 1+bciStackUse PUSH_APPLY_P{} = 1+bciStackUse PUSH_APPLY_PP{} = 1+bciStackUse PUSH_APPLY_PPP{} = 1+bciStackUse PUSH_APPLY_PPPP{} = 1+bciStackUse PUSH_APPLY_PPPPP{} = 1+bciStackUse PUSH_APPLY_PPPPPP{} = 1+bciStackUse ALLOC_AP{} = 1+bciStackUse ALLOC_AP_NOUPD{} = 1+bciStackUse ALLOC_PAP{} = 1+bciStackUse (UNPACK sz) = fromIntegral sz+bciStackUse LABEL{} = 0+bciStackUse TESTLT_I{} = 0+bciStackUse TESTEQ_I{} = 0+bciStackUse TESTLT_W{} = 0+bciStackUse TESTEQ_W{} = 0+bciStackUse TESTLT_F{} = 0+bciStackUse TESTEQ_F{} = 0+bciStackUse TESTLT_D{} = 0+bciStackUse TESTEQ_D{} = 0+bciStackUse TESTLT_P{} = 0+bciStackUse TESTEQ_P{} = 0+bciStackUse CASEFAIL{} = 0+bciStackUse JMP{} = 0+bciStackUse ENTER{} = 0+bciStackUse RETURN{} = 0+bciStackUse RETURN_UBX{} = 1+bciStackUse CCALL{} = 0+bciStackUse SWIZZLE{} = 0+bciStackUse BRK_FUN{} = 0++-- These insns actually reduce stack use, but we need the high-tide level,+-- so can't use this info. Not that it matters much.+bciStackUse SLIDE{} = 0+bciStackUse MKAP{} = 0+bciStackUse MKPAP{} = 0+bciStackUse PACK{} = 1 -- worst case is PACK 0 words
+ ghci/ByteCodeItbls.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE CPP, MagicHash, ScopedTypeVariables #-}+{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}+--+-- (c) The University of Glasgow 2002-2006+--++-- | ByteCodeItbls: Generate infotables for interpreter-made bytecodes+module ByteCodeItbls ( mkITbls ) where++#include "HsVersions.h"++import ByteCodeTypes+import GHCi+import DynFlags+import HscTypes+import Name ( Name, getName )+import NameEnv+import DataCon ( DataCon, dataConRepArgTys, dataConIdentity )+import TyCon ( TyCon, tyConFamilySize, isDataTyCon, tyConDataCons )+import RepType+import StgCmmLayout ( mkVirtConstrSizes )+import StgCmmClosure ( tagForCon, NonVoid (..) )+import Util+import Panic++{-+ Manufacturing of info tables for DataCons+-}++-- Make info tables for the data decls in this module+mkITbls :: HscEnv -> [TyCon] -> IO ItblEnv+mkITbls hsc_env tcs =+ foldr plusNameEnv emptyNameEnv <$>+ mapM (mkITbl hsc_env) (filter isDataTyCon tcs)+ where+ mkITbl :: HscEnv -> TyCon -> IO ItblEnv+ mkITbl hsc_env tc+ | dcs `lengthIs` n -- paranoia; this is an assertion.+ = make_constr_itbls hsc_env dcs+ where+ dcs = tyConDataCons tc+ n = tyConFamilySize tc+ mkITbl _ _ = panic "mkITbl"++mkItblEnv :: [(Name,ItblPtr)] -> ItblEnv+mkItblEnv pairs = mkNameEnv [(n, (n,p)) | (n,p) <- pairs]++-- Assumes constructors are numbered from zero, not one+make_constr_itbls :: HscEnv -> [DataCon] -> IO ItblEnv+make_constr_itbls hsc_env cons =+ mkItblEnv <$> mapM (uncurry mk_itbl) (zip cons [0..])+ where+ dflags = hsc_dflags hsc_env++ mk_itbl :: DataCon -> Int -> IO (Name,ItblPtr)+ mk_itbl dcon conNo = do+ let rep_args = [ NonVoid prim_rep+ | arg <- dataConRepArgTys dcon+ , prim_rep <- typePrimRep arg ]++ (tot_wds, ptr_wds) =+ mkVirtConstrSizes dflags rep_args++ ptrs' = ptr_wds+ nptrs' = tot_wds - ptr_wds+ nptrs_really+ | ptrs' + nptrs' >= mIN_PAYLOAD_SIZE dflags = nptrs'+ | otherwise = mIN_PAYLOAD_SIZE dflags - ptrs'++ descr = dataConIdentity dcon++ r <- iservCmd hsc_env (MkConInfoTable ptrs' nptrs_really+ conNo (tagForCon dflags dcon) descr)+ return (getName dcon, ItblPtr r)
+ ghci/ByteCodeLink.hs view
@@ -0,0 +1,195 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE UnboxedTuples #-}+{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}+--+-- (c) The University of Glasgow 2002-2006+--++-- | ByteCodeLink: Bytecode assembler and linker+module ByteCodeLink (+ ClosureEnv, emptyClosureEnv, extendClosureEnv,+ linkBCO, lookupStaticPtr,+ lookupIE,+ nameToCLabel, linkFail+ ) where++#include "HsVersions.h"++import GHCi.RemoteTypes+import GHCi.ResolvedBCO+import GHCi.InfoTable+import GHCi.BreakArray+import SizedSeq++import GHCi+import ByteCodeTypes+import HscTypes+import DynFlags+import Name+import NameEnv+import PrimOp+import Module+import FastString+import Panic+import Outputable+import Util++-- Standard libraries+import Data.Array.Unboxed+import Data.Array.Base+import Data.Word+import Foreign.Ptr+import GHC.IO ( IO(..) )+import GHC.Exts++{-+ Linking interpretables into something we can run+-}++type ClosureEnv = NameEnv (Name, ForeignHValue)++emptyClosureEnv :: ClosureEnv+emptyClosureEnv = emptyNameEnv++extendClosureEnv :: ClosureEnv -> [(Name,ForeignHValue)] -> ClosureEnv+extendClosureEnv cl_env pairs+ = extendNameEnvList cl_env [ (n, (n,v)) | (n,v) <- pairs]++{-+ Linking interpretables into something we can run+-}++linkBCO+ :: HscEnv -> ItblEnv -> ClosureEnv -> NameEnv Int -> RemoteRef BreakArray+ -> UnlinkedBCO+ -> IO ResolvedBCO+linkBCO hsc_env ie ce bco_ix breakarray+ (UnlinkedBCO _ arity insns bitmap lits0 ptrs0) = do+ lits <- mapM (lookupLiteral hsc_env ie) (ssElts lits0)+ ptrs <- mapM (resolvePtr hsc_env ie ce bco_ix breakarray) (ssElts ptrs0)+ let dflags = hsc_dflags hsc_env+ return (ResolvedBCO arity (toWordArray dflags insns) bitmap+ (listArray (0, fromIntegral (sizeSS lits0)-1) lits)+ (addListToSS emptySS ptrs))++-- Turn the insns array from a Word16 array into a Word array. The+-- latter is much faster to serialize/deserialize. Assumes the input+-- array is zero-indexed.+toWordArray :: DynFlags -> UArray Int Word16 -> UArray Int Word+toWordArray dflags (UArray _ _ n arr) = UArray 0 (n'-1) n' arr+ where n' = (n + w16s_per_word - 1) `quot` w16s_per_word+ w16s_per_word = wORD_SIZE dflags `quot` 2++lookupLiteral :: HscEnv -> ItblEnv -> BCONPtr -> IO Word+lookupLiteral _ _ (BCONPtrWord lit) = return lit+lookupLiteral hsc_env _ (BCONPtrLbl sym) = do+ Ptr a# <- lookupStaticPtr hsc_env sym+ return (W# (int2Word# (addr2Int# a#)))+lookupLiteral hsc_env ie (BCONPtrItbl nm) = do+ Ptr a# <- lookupIE hsc_env ie nm+ return (W# (int2Word# (addr2Int# a#)))+lookupLiteral _ _ (BCONPtrStr _) =+ -- should be eliminated during assembleBCOs+ panic "lookupLiteral: BCONPtrStr"++lookupStaticPtr :: HscEnv -> FastString -> IO (Ptr ())+lookupStaticPtr hsc_env addr_of_label_string = do+ m <- lookupSymbol hsc_env addr_of_label_string+ case m of+ Just ptr -> return ptr+ Nothing -> linkFail "ByteCodeLink: can't find label"+ (unpackFS addr_of_label_string)++lookupIE :: HscEnv -> ItblEnv -> Name -> IO (Ptr ())+lookupIE hsc_env ie con_nm =+ case lookupNameEnv ie con_nm of+ Just (_, ItblPtr a) -> return (conInfoPtr (fromRemotePtr (castRemotePtr a)))+ Nothing -> do -- try looking up in the object files.+ let sym_to_find1 = nameToCLabel con_nm "con_info"+ m <- lookupSymbol hsc_env sym_to_find1+ case m of+ Just addr -> return addr+ Nothing+ -> do -- perhaps a nullary constructor?+ let sym_to_find2 = nameToCLabel con_nm "static_info"+ n <- lookupSymbol hsc_env sym_to_find2+ case n of+ Just addr -> return addr+ Nothing -> linkFail "ByteCodeLink.lookupIE"+ (unpackFS sym_to_find1 ++ " or " +++ unpackFS sym_to_find2)++lookupPrimOp :: HscEnv -> PrimOp -> IO (RemotePtr ())+lookupPrimOp hsc_env primop = do+ let sym_to_find = primopToCLabel primop "closure"+ m <- lookupSymbol hsc_env (mkFastString sym_to_find)+ case m of+ Just p -> return (toRemotePtr p)+ Nothing -> linkFail "ByteCodeLink.lookupCE(primop)" sym_to_find++resolvePtr+ :: HscEnv -> ItblEnv -> ClosureEnv -> NameEnv Int -> RemoteRef BreakArray+ -> BCOPtr+ -> IO ResolvedBCOPtr+resolvePtr hsc_env _ie ce bco_ix _ (BCOPtrName nm)+ | Just ix <- lookupNameEnv bco_ix nm =+ return (ResolvedBCORef ix) -- ref to another BCO in this group+ | Just (_, rhv) <- lookupNameEnv ce nm =+ return (ResolvedBCOPtr (unsafeForeignRefToRemoteRef rhv))+ | otherwise =+ ASSERT2(isExternalName nm, ppr nm)+ do let sym_to_find = nameToCLabel nm "closure"+ m <- lookupSymbol hsc_env sym_to_find+ case m of+ Just p -> return (ResolvedBCOStaticPtr (toRemotePtr p))+ Nothing -> linkFail "ByteCodeLink.lookupCE" (unpackFS sym_to_find)+resolvePtr hsc_env _ _ _ _ (BCOPtrPrimOp op) =+ ResolvedBCOStaticPtr <$> lookupPrimOp hsc_env op+resolvePtr hsc_env ie ce bco_ix breakarray (BCOPtrBCO bco) =+ ResolvedBCOPtrBCO <$> linkBCO hsc_env ie ce bco_ix breakarray bco+resolvePtr _ _ _ _ breakarray BCOPtrBreakArray =+ return (ResolvedBCOPtrBreakArray breakarray)++linkFail :: String -> String -> IO a+linkFail who what+ = throwGhcExceptionIO (ProgramError $+ unlines [ "",who+ , "During interactive linking, GHCi couldn't find the following symbol:"+ , ' ' : ' ' : what+ , "This may be due to you not asking GHCi to load extra object files,"+ , "archives or DLLs needed by your current session. Restart GHCi, specifying"+ , "the missing library using the -L/path/to/object/dir and -lmissinglibname"+ , "flags, or simply by naming the relevant files on the GHCi command line."+ , "Alternatively, this link failure might indicate a bug in GHCi."+ , "If you suspect the latter, please send a bug report to:"+ , " glasgow-haskell-bugs@haskell.org"+ ])+++nameToCLabel :: Name -> String -> FastString+nameToCLabel n suffix = mkFastString label+ where+ encodeZ = zString . zEncodeFS+ (Module pkgKey modName) = ASSERT( isExternalName n ) nameModule n+ packagePart = encodeZ (unitIdFS pkgKey)+ modulePart = encodeZ (moduleNameFS modName)+ occPart = encodeZ (occNameFS (nameOccName n))++ label = concat+ [ if pkgKey == mainUnitId then "" else packagePart ++ "_"+ , modulePart+ , '_':occPart+ , '_':suffix+ ]+++primopToCLabel :: PrimOp -> String -> String+primopToCLabel primop suffix = concat+ [ "ghczmprim_GHCziPrimopWrappers_"+ , zString (zEncodeFS (occNameFS (primOpOcc primop)))+ , '_':suffix+ ]
+ ghci/ByteCodeTypes.hs view
@@ -0,0 +1,182 @@+{-# LANGUAGE CPP, MagicHash, RecordWildCards, GeneralizedNewtypeDeriving #-}+--+-- (c) The University of Glasgow 2002-2006+--++-- | Bytecode assembler types+module ByteCodeTypes+ ( CompiledByteCode(..), seqCompiledByteCode, FFIInfo(..)+ , UnlinkedBCO(..), BCOPtr(..), BCONPtr(..)+ , ItblEnv, ItblPtr(..)+ , CgBreakInfo(..)+ , ModBreaks (..), BreakIndex, emptyModBreaks+ , CCostCentre+ ) where++import FastString+import Id+import Name+import NameEnv+import Outputable+import PrimOp+import SizedSeq+import Type+import SrcLoc+import GHCi.BreakArray+import GHCi.RemoteTypes+import GHCi.FFI+import GHCi.InfoTable+import Control.DeepSeq++import Foreign+import Data.Array+import Data.Array.Base ( UArray(..) )+import Data.ByteString (ByteString)+import Data.IntMap (IntMap)+import qualified Data.IntMap as IntMap+#if MIN_VERSION_base(4,9,0)+import GHC.Stack.CCS+#else+import GHC.Stack as GHC.Stack.CCS+#endif++-- -----------------------------------------------------------------------------+-- Compiled Byte Code++data CompiledByteCode = CompiledByteCode+ { bc_bcos :: [UnlinkedBCO] -- Bunch of interpretable bindings+ , bc_itbls :: ItblEnv -- A mapping from DataCons to their itbls+ , bc_ffis :: [FFIInfo] -- ffi blocks we allocated+ , bc_strs :: [RemotePtr ()] -- malloc'd strings+ , bc_breaks :: Maybe ModBreaks -- breakpoint info (Nothing if we're not+ -- creating breakpoints, for some reason)+ }+ -- ToDo: we're not tracking strings that we malloc'd+newtype FFIInfo = FFIInfo (RemotePtr C_ffi_cif)+ deriving (Show, NFData)++instance Outputable CompiledByteCode where+ ppr CompiledByteCode{..} = ppr bc_bcos++-- Not a real NFData instance, because ModBreaks contains some things+-- we can't rnf+seqCompiledByteCode :: CompiledByteCode -> ()+seqCompiledByteCode CompiledByteCode{..} =+ rnf bc_bcos `seq`+ rnf (nameEnvElts bc_itbls) `seq`+ rnf bc_ffis `seq`+ rnf bc_strs `seq`+ rnf (fmap seqModBreaks bc_breaks)++type ItblEnv = NameEnv (Name, ItblPtr)+ -- We need the Name in the range so we know which+ -- elements to filter out when unloading a module++newtype ItblPtr = ItblPtr (RemotePtr StgInfoTable)+ deriving (Show, NFData)++data UnlinkedBCO+ = UnlinkedBCO {+ unlinkedBCOName :: !Name,+ unlinkedBCOArity :: {-# UNPACK #-} !Int,+ unlinkedBCOInstrs :: !(UArray Int Word16), -- insns+ unlinkedBCOBitmap :: !(UArray Int Word), -- bitmap+ unlinkedBCOLits :: !(SizedSeq BCONPtr), -- non-ptrs+ unlinkedBCOPtrs :: !(SizedSeq BCOPtr) -- ptrs+ }++instance NFData UnlinkedBCO where+ rnf UnlinkedBCO{..} =+ rnf unlinkedBCOLits `seq`+ rnf unlinkedBCOPtrs++data BCOPtr+ = BCOPtrName !Name+ | BCOPtrPrimOp !PrimOp+ | BCOPtrBCO !UnlinkedBCO+ | BCOPtrBreakArray -- a pointer to this module's BreakArray++instance NFData BCOPtr where+ rnf (BCOPtrBCO bco) = rnf bco+ rnf x = x `seq` ()++data BCONPtr+ = BCONPtrWord {-# UNPACK #-} !Word+ | BCONPtrLbl !FastString+ | BCONPtrItbl !Name+ | BCONPtrStr !ByteString++instance NFData BCONPtr where+ rnf x = x `seq` ()++-- | Information about a breakpoint that we know at code-generation time+data CgBreakInfo+ = CgBreakInfo+ { cgb_vars :: [(Id,Word16)]+ , cgb_resty :: Type+ }++-- Not a real NFData instance because we can't rnf Id or Type+seqCgBreakInfo :: CgBreakInfo -> ()+seqCgBreakInfo CgBreakInfo{..} =+ rnf (map snd cgb_vars) `seq`+ seqType cgb_resty++instance Outputable UnlinkedBCO where+ ppr (UnlinkedBCO nm _arity _insns _bitmap lits ptrs)+ = sep [text "BCO", ppr nm, text "with",+ ppr (sizeSS lits), text "lits",+ ppr (sizeSS ptrs), text "ptrs" ]++instance Outputable CgBreakInfo where+ ppr info = text "CgBreakInfo" <+>+ parens (ppr (cgb_vars info) <+>+ ppr (cgb_resty info))++-- -----------------------------------------------------------------------------+-- Breakpoints++-- | Breakpoint index+type BreakIndex = Int++-- | C CostCentre type+data CCostCentre++-- | All the information about the breakpoints for a module+data ModBreaks+ = ModBreaks+ { modBreaks_flags :: ForeignRef BreakArray+ -- ^ The array of flags, one per breakpoint,+ -- indicating which breakpoints are enabled.+ , modBreaks_locs :: !(Array BreakIndex SrcSpan)+ -- ^ An array giving the source span of each breakpoint.+ , modBreaks_vars :: !(Array BreakIndex [OccName])+ -- ^ An array giving the names of the free variables at each breakpoint.+ , modBreaks_decls :: !(Array BreakIndex [String])+ -- ^ An array giving the names of the declarations enclosing each breakpoint.+ , modBreaks_ccs :: !(Array BreakIndex (RemotePtr CostCentre))+ -- ^ Array pointing to cost centre for each breakpoint+ , modBreaks_breakInfo :: IntMap CgBreakInfo+ -- ^ info about each breakpoint from the bytecode generator+ }++seqModBreaks :: ModBreaks -> ()+seqModBreaks ModBreaks{..} =+ rnf modBreaks_flags `seq`+ rnf modBreaks_locs `seq`+ rnf modBreaks_vars `seq`+ rnf modBreaks_decls `seq`+ rnf modBreaks_ccs `seq`+ rnf (fmap seqCgBreakInfo modBreaks_breakInfo)++-- | Construct an empty ModBreaks+emptyModBreaks :: ModBreaks+emptyModBreaks = ModBreaks+ { modBreaks_flags = error "ModBreaks.modBreaks_array not initialised"+ -- ToDo: can we avoid this?+ , modBreaks_locs = array (0,-1) []+ , modBreaks_vars = array (0,-1) []+ , modBreaks_decls = array (0,-1) []+ , modBreaks_ccs = array (0,-1) []+ , modBreaks_breakInfo = IntMap.empty+ }
+ ghci/Debugger.hs view
@@ -0,0 +1,238 @@+{-# LANGUAGE MagicHash #-}++-----------------------------------------------------------------------------+--+-- GHCi Interactive debugging commands+--+-- Pepe Iborra (supported by Google SoC) 2006+--+-- ToDo: lots of violation of layering here. This module should+-- decide whether it is above the GHC API (import GHC and nothing+-- else) or below it.+--+-----------------------------------------------------------------------------++module Debugger (pprintClosureCommand, showTerm, pprTypeAndContents) where++import Linker+import RtClosureInspect++import GHCi+import GHCi.RemoteTypes+import GhcMonad+import HscTypes+import Id+import IfaceSyn ( showToHeader )+import IfaceEnv( newInteractiveBinder )+import Name+import Var hiding ( varName )+import VarSet+import UniqSet+import Type+import GHC+import Outputable+import PprTyThing+import ErrUtils+import MonadUtils+import DynFlags+import Exception++import Control.Monad+import Data.List+import Data.Maybe+import Data.IORef++import GHC.Exts++-------------------------------------+-- | The :print & friends commands+-------------------------------------+pprintClosureCommand :: GhcMonad m => Bool -> Bool -> String -> m ()+pprintClosureCommand bindThings force str = do+ tythings <- (catMaybes . concat) `liftM`+ mapM (\w -> GHC.parseName w >>=+ mapM GHC.lookupName)+ (words str)+ let ids = [id | AnId id <- tythings]++ -- Obtain the terms and the recovered type information+ (subst, terms) <- mapAccumLM go emptyTCvSubst ids++ -- Apply the substitutions obtained after recovering the types+ modifySession $ \hsc_env ->+ hsc_env{hsc_IC = substInteractiveContext (hsc_IC hsc_env) subst}++ -- Finally, print the Terms+ unqual <- GHC.getPrintUnqual+ docterms <- mapM showTerm terms+ dflags <- getDynFlags+ liftIO $ (printOutputForUser dflags unqual . vcat)+ (zipWith (\id docterm -> ppr id <+> char '=' <+> docterm)+ ids+ docterms)+ where+ -- Do the obtainTerm--bindSuspensions-computeSubstitution dance+ go :: GhcMonad m => TCvSubst -> Id -> m (TCvSubst, Term)+ go subst id = do+ let id' = id `setIdType` substTy subst (idType id)+ term_ <- GHC.obtainTermFromId maxBound force id'+ term <- tidyTermTyVars term_+ term' <- if bindThings &&+ (not (isUnliftedType (termType term)))+ then bindSuspensions term+ else return term+ -- Before leaving, we compare the type obtained to see if it's more specific+ -- Then, we extract a substitution,+ -- mapping the old tyvars to the reconstructed types.+ let reconstructed_type = termType term+ hsc_env <- getSession+ case (improveRTTIType hsc_env (idType id) (reconstructed_type)) of+ Nothing -> return (subst, term')+ Just subst' -> do { traceOptIf Opt_D_dump_rtti+ (fsep $ [text "RTTI Improvement for", ppr id,+ text "is the substitution:" , ppr subst'])+ ; return (subst `unionTCvSubst` subst', term')}++ tidyTermTyVars :: GhcMonad m => Term -> m Term+ tidyTermTyVars t =+ withSession $ \hsc_env -> do+ let env_tvs = tyThingsTyCoVars $ ic_tythings $ hsc_IC hsc_env+ my_tvs = termTyCoVars t+ tvs = env_tvs `minusVarSet` my_tvs+ tyvarOccName = nameOccName . tyVarName+ tidyEnv = (initTidyOccEnv (map tyvarOccName (nonDetEltsUniqSet tvs))+ -- It's OK to use nonDetEltsUniqSet here because initTidyOccEnv+ -- forgets the ordering immediately by creating an env+ , getUniqSet $ env_tvs `intersectVarSet` my_tvs)+ return $ mapTermType (snd . tidyOpenType tidyEnv) t++-- | Give names, and bind in the interactive environment, to all the suspensions+-- included (inductively) in a term+bindSuspensions :: GhcMonad m => Term -> m Term+bindSuspensions t = do+ hsc_env <- getSession+ inScope <- GHC.getBindings+ let ictxt = hsc_IC hsc_env+ prefix = "_t"+ alreadyUsedNames = map (occNameString . nameOccName . getName) inScope+ availNames = map ((prefix++) . show) [(1::Int)..] \\ alreadyUsedNames+ availNames_var <- liftIO $ newIORef availNames+ (t', stuff) <- liftIO $ foldTerm (nameSuspensionsAndGetInfos hsc_env availNames_var) t+ let (names, tys, hvals) = unzip3 stuff+ let ids = [ mkVanillaGlobal name ty+ | (name,ty) <- zip names tys]+ new_ic = extendInteractiveContextWithIds ictxt ids+ fhvs <- liftIO $ mapM (mkFinalizedHValue hsc_env <=< mkRemoteRef) hvals+ liftIO $ extendLinkEnv (zip names fhvs)+ setSession hsc_env {hsc_IC = new_ic }+ return t'+ where++-- Processing suspensions. Give names and recopilate info+ nameSuspensionsAndGetInfos :: HscEnv -> IORef [String]+ -> TermFold (IO (Term, [(Name,Type,HValue)]))+ nameSuspensionsAndGetInfos hsc_env freeNames = TermFold+ {+ fSuspension = doSuspension hsc_env freeNames+ , fTerm = \ty dc v tt -> do+ tt' <- sequence tt+ let (terms,names) = unzip tt'+ return (Term ty dc v terms, concat names)+ , fPrim = \ty n ->return (Prim ty n,[])+ , fNewtypeWrap =+ \ty dc t -> do+ (term, names) <- t+ return (NewtypeWrap ty dc term, names)+ , fRefWrap = \ty t -> do+ (term, names) <- t+ return (RefWrap ty term, names)+ }+ doSuspension hsc_env freeNames ct ty hval _name = do+ name <- atomicModifyIORef' freeNames (\x->(tail x, head x))+ n <- newGrimName hsc_env name+ return (Suspension ct ty hval (Just n), [(n,ty,hval)])+++-- A custom Term printer to enable the use of Show instances+showTerm :: GhcMonad m => Term -> m SDoc+showTerm term = do+ dflags <- GHC.getSessionDynFlags+ if gopt Opt_PrintEvldWithShow dflags+ then cPprTerm (liftM2 (++) (\_y->[cPprShowable]) cPprTermBase) term+ else cPprTerm cPprTermBase term+ where+ cPprShowable prec t@Term{ty=ty, val=val} =+ if not (isFullyEvaluatedTerm t)+ then return Nothing+ else do+ hsc_env <- getSession+ dflags <- GHC.getSessionDynFlags+ do+ (new_env, bname) <- bindToFreshName hsc_env ty "showme"+ setSession new_env+ -- XXX: this tries to disable logging of errors+ -- does this still do what it is intended to do+ -- with the changed error handling and logging?+ let noop_log _ _ _ _ _ _ = return ()+ expr = "show " ++ showPpr dflags bname+ _ <- GHC.setSessionDynFlags dflags{log_action=noop_log}+ fhv <- liftIO $ mkFinalizedHValue hsc_env =<< mkRemoteRef val+ txt_ <- withExtendedLinkEnv [(bname, fhv)]+ (GHC.compileExpr expr)+ let myprec = 10 -- application precedence. TODO Infix constructors+ let txt = unsafeCoerce# txt_ :: [a]+ if not (null txt) then+ return $ Just $ cparen (prec >= myprec && needsParens txt)+ (text txt)+ else return Nothing+ `gfinally` do+ setSession hsc_env+ GHC.setSessionDynFlags dflags+ cPprShowable prec NewtypeWrap{ty=new_ty,wrapped_term=t} =+ cPprShowable prec t{ty=new_ty}+ cPprShowable _ _ = return Nothing++ needsParens ('"':_) = False -- some simple heuristics to see whether parens+ -- are redundant in an arbitrary Show output+ needsParens ('(':_) = False+ needsParens txt = ' ' `elem` txt+++ bindToFreshName hsc_env ty userName = do+ name <- newGrimName hsc_env userName+ let id = mkVanillaGlobal name ty+ new_ic = extendInteractiveContextWithIds (hsc_IC hsc_env) [id]+ return (hsc_env {hsc_IC = new_ic }, name)++-- Create new uniques and give them sequentially numbered names+newGrimName :: MonadIO m => HscEnv -> String -> m Name+newGrimName hsc_env userName+ = liftIO (newInteractiveBinder hsc_env occ noSrcSpan)+ where+ occ = mkOccName varName userName++pprTypeAndContents :: GhcMonad m => Id -> m SDoc+pprTypeAndContents id = do+ dflags <- GHC.getSessionDynFlags+ let pcontents = gopt Opt_PrintBindContents dflags+ pprdId = (pprTyThing showToHeader . AnId) id+ if pcontents+ then do+ let depthBound = 100+ -- If the value is an exception, make sure we catch it and+ -- show the exception, rather than propagating the exception out.+ e_term <- gtry $ GHC.obtainTermFromId depthBound False id+ docs_term <- case e_term of+ Right term -> showTerm term+ Left exn -> return (text "*** Exception:" <+>+ text (show (exn :: SomeException)))+ return $ pprdId <+> equals <+> docs_term+ else return pprdId++--------------------------------------------------------------+-- Utils++traceOptIf :: GhcMonad m => DumpFlag -> SDoc -> m ()+traceOptIf flag doc = do+ dflags <- GHC.getSessionDynFlags+ when (dopt flag dflags) $ liftIO $ printInfoForUser dflags alwaysQualify doc
+ ghci/DebuggerUtils.hs view
@@ -0,0 +1,132 @@+{-# LANGUAGE CPP #-}++module DebuggerUtils (+ dataConInfoPtrToName,+ ) where++import GHCi.InfoTable+import CmmInfo ( stdInfoTableSizeB )+import DynFlags+import FastString+import TcRnTypes+import TcRnMonad+import IfaceEnv+import Module+import OccName+import Name+import Outputable+import Util++import Data.Char+import Foreign+import Data.List++#include "HsVersions.h"++-- | Given a data constructor in the heap, find its Name.+-- The info tables for data constructors have a field which records+-- the source name of the constructor as a Ptr Word8 (UTF-8 encoded+-- string). The format is:+--+-- > Package:Module.Name+--+-- We use this string to lookup the interpreter's internal representation of the name+-- using the lookupOrig.+--+dataConInfoPtrToName :: Ptr () -> TcM (Either String Name)+dataConInfoPtrToName x = do+ dflags <- getDynFlags+ theString <- liftIO $ do+ let ptr = castPtr x :: Ptr StgInfoTable+ conDescAddress <- getConDescAddress dflags ptr+ peekArray0 0 conDescAddress+ let (pkg, mod, occ) = parse theString+ pkgFS = mkFastStringByteList pkg+ modFS = mkFastStringByteList mod+ occFS = mkFastStringByteList occ+ occName = mkOccNameFS OccName.dataName occFS+ modName = mkModule (fsToUnitId pkgFS) (mkModuleNameFS modFS)+ return (Left $ showSDoc dflags $ ppr modName <> dot <> ppr occName)+ `recoverM` (Right `fmap` lookupOrig modName occName)++ where++ {- To find the string in the constructor's info table we need to consider+ the layout of info tables relative to the entry code for a closure.++ An info table can be next to the entry code for the closure, or it can+ be separate. The former (faster) is used in registerised versions of ghc,+ and the latter (portable) is for non-registerised versions.++ The diagrams below show where the string is to be found relative to+ the normal info table of the closure.++ 1) Code next to table:++ --------------+ | | <- pointer to the start of the string+ --------------+ | | <- the (start of the) info table structure+ | |+ | |+ --------------+ | entry code |+ | .... |++ In this case the pointer to the start of the string can be found in+ the memory location _one word before_ the first entry in the normal info+ table.++ 2) Code NOT next to table:++ --------------+ info table structure -> | *------------------> --------------+ | | | entry code |+ | | | .... |+ --------------+ ptr to start of str -> | |+ --------------++ In this case the pointer to the start of the string can be found+ in the memory location: info_table_ptr + info_table_size+ -}++ getConDescAddress :: DynFlags -> Ptr StgInfoTable -> IO (Ptr Word8)+ getConDescAddress dflags ptr+ | ghciTablesNextToCode = do+ let ptr' = ptr `plusPtr` (- wORD_SIZE dflags)+ -- NB. the offset must be read as an Int32 not a Word32, so+ -- that the sign is preserved when converting to an Int.+ offsetToString <- fromIntegral <$> (peek ptr' :: IO Int32)+ return $ (ptr `plusPtr` stdInfoTableSizeB dflags) `plusPtr` offsetToString+ | otherwise =+ peek $ intPtrToPtr $ ptrToIntPtr ptr + fromIntegral (stdInfoTableSizeB dflags)+ -- parsing names is a little bit fiddly because we have a string in the form:+ -- pkg:A.B.C.foo, and we want to split it into three parts: ("pkg", "A.B.C", "foo").+ -- Thus we split at the leftmost colon and the rightmost occurrence of the dot.+ -- It would be easier if the string was in the form pkg:A.B.C:foo, but alas+ -- this is not the conventional way of writing Haskell names. We stick with+ -- convention, even though it makes the parsing code more troublesome.+ -- Warning: this code assumes that the string is well formed.+ parse :: [Word8] -> ([Word8], [Word8], [Word8])+ parse input+ = ASSERT(all (>0) (map length [pkg, mod, occ])) (pkg, mod, occ)+ where+ dot = fromIntegral (ord '.')+ (pkg, rest1) = break (== fromIntegral (ord ':')) input+ (mod, occ)+ = (concat $ intersperse [dot] $ reverse modWords, occWord)+ where+ (modWords, occWord) = ASSERT(length rest1 > 0) (parseModOcc [] (tail rest1))+ parseModOcc :: [[Word8]] -> [Word8] -> ([[Word8]], [Word8])+ -- We only look for dots if str could start with a module name,+ -- i.e. if it starts with an upper case character.+ -- Otherwise we might think that "X.:->" is the module name in+ -- "X.:->.+", whereas actually "X" is the module name and+ -- ":->.+" is a constructor name.+ parseModOcc acc str@(c : _)+ | isUpper $ chr $ fromIntegral c+ = case break (== dot) str of+ (top, []) -> (acc, top)+ (top, _ : bot) -> parseModOcc (top : acc) bot+ parseModOcc acc str = (acc, str)
+ ghci/GHCi.hsc view
@@ -0,0 +1,677 @@+{-# LANGUAGE RecordWildCards, ScopedTypeVariables, BangPatterns, CPP #-}++--+-- | Interacting with the interpreter, whether it is running on an+-- external process or in the current process.+--+module GHCi+ ( -- * High-level interface to the interpreter+ evalStmt, EvalStatus_(..), EvalStatus, EvalResult(..), EvalExpr(..)+ , resumeStmt+ , abandonStmt+ , evalIO+ , evalString+ , evalStringToIOString+ , mallocData+ , createBCOs+ , addSptEntry+ , mkCostCentres+ , costCentreStackInfo+ , newBreakArray+ , enableBreakpoint+ , breakpointStatus+ , getBreakpointVar++ -- * The object-code linker+ , initObjLinker+ , lookupSymbol+ , lookupClosure+ , loadDLL+ , loadArchive+ , loadObj+ , unloadObj+ , addLibrarySearchPath+ , removeLibrarySearchPath+ , resolveObjs+ , findSystemLibrary++ -- * Lower-level API using messages+ , iservCmd, Message(..), withIServ, stopIServ+ , iservCall, readIServ, writeIServ+ , purgeLookupSymbolCache+ , freeHValueRefs+ , mkFinalizedHValue+ , wormhole, wormholeRef+ , mkEvalOpts+ , fromEvalResult+ ) where++import GHCi.Message+#ifdef GHCI+import GHCi.Run+#endif+import GHCi.RemoteTypes+import GHCi.ResolvedBCO+import GHCi.BreakArray (BreakArray)+import Fingerprint+import HscTypes+import UniqFM+import Panic+import DynFlags+import ErrUtils+import Outputable+import Exception+import BasicTypes+import FastString+import Util+import Hooks++import Control.Concurrent+import Control.Monad+import Control.Monad.IO.Class+import Data.Binary+import Data.Binary.Put+import Data.ByteString (ByteString)+import qualified Data.ByteString.Lazy as LB+import Data.IORef+import Foreign hiding (void)+#if MIN_VERSION_base(4,9,0)+import GHC.Stack.CCS (CostCentre,CostCentreStack)+#else+import GHC.Stack (CostCentre,CostCentreStack)+#endif+import System.Exit+import Data.Maybe+import GHC.IO.Handle.Types (Handle)+#ifdef mingw32_HOST_OS+import Foreign.C+import GHC.IO.Handle.FD (fdToHandle)+#if !MIN_VERSION_process(1,4,2)+import System.Posix.Internals+import Foreign.Marshal.Array+import Foreign.C.Error+import Foreign.Storable+#endif+#else+import System.Posix as Posix+#endif+import System.Directory+import System.Process+import GHC.Conc (getNumProcessors, pseq, par)++{- Note [Remote GHCi]++When the flag -fexternal-interpreter is given to GHC, interpreted code+is run in a separate process called iserv, and we communicate with the+external process over a pipe using Binary-encoded messages.++Motivation+~~~~~~~~~~++When the interpreted code is running in a separate process, it can+use a different "way", e.g. profiled or dynamic. This means++- compiling Template Haskell code with -prof does not require+ building the code without -prof first++- when GHC itself is profiled, it can interpret unprofiled code,+ and the same applies to dynamic linking.++- An unprofiled GHCi can load and run profiled code, which means it+ can use the stack-trace functionality provided by profiling without+ taking the performance hit on the compiler that profiling would+ entail.++For other reasons see RemoteGHCi on the wiki.++Implementation Overview+~~~~~~~~~~~~~~~~~~~~~~~++The main pieces are:++- libraries/ghci, containing:+ - types for talking about remote values (GHCi.RemoteTypes)+ - the message protocol (GHCi.Message),+ - implementation of the messages (GHCi.Run)+ - implementation of Template Haskell (GHCi.TH)+ - a few other things needed to run interpreted code++- top-level iserv directory, containing the codefor the external+ server. This is a fairly simple wrapper, most of the functionality+ is provided by modules in libraries/ghci.++- This module (GHCi) which provides the interface to the server used+ by the rest of GHC.++GHC works with and without -fexternal-interpreter. With the flag, all+interpreted code is run by the iserv binary. Without the flag,+interpreted code is run in the same process as GHC.++Things that do not work with -fexternal-interpreter+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++dynCompileExpr cannot work, because we have no way to run code of an+unknown type in the remote process. This API fails with an error+message if it is used with -fexternal-interpreter.++Other Notes on Remote GHCi+~~~~~~~~~~~~~~~~~~~~~~~~~~+ * This wiki page has an implementation overview:+ https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/ExternalInterpreter+ * Note [External GHCi pointers] in compiler/ghci/GHCi.hs+ * Note [Remote Template Haskell] in libraries/ghci/GHCi/TH.hs+-}++#ifndef GHCI+needExtInt :: IO a+needExtInt = throwIO+ (InstallationError "this operation requires -fexternal-interpreter")+#endif++-- | Run a command in the interpreter's context. With+-- @-fexternal-interpreter@, the command is serialized and sent to an+-- external iserv process, and the response is deserialized (hence the+-- @Binary@ constraint). With @-fno-external-interpreter@ we execute+-- the command directly here.+iservCmd :: Binary a => HscEnv -> Message a -> IO a+iservCmd hsc_env@HscEnv{..} msg+ | gopt Opt_ExternalInterpreter hsc_dflags =+ withIServ hsc_env $ \iserv ->+ uninterruptibleMask_ $ do -- Note [uninterruptibleMask_]+ iservCall iserv msg+ | otherwise = -- Just run it directly+#ifdef GHCI+ run msg+#else+ needExtInt+#endif++-- Note [uninterruptibleMask_ and iservCmd]+--+-- If we receive an async exception, such as ^C, while communicating+-- with the iserv process then we will be out-of-sync and not be able+-- to recoever. Thus we use uninterruptibleMask_ during+-- communication. A ^C will be delivered to the iserv process (because+-- signals get sent to the whole process group) which will interrupt+-- the running computation and return an EvalException result.++-- | Grab a lock on the 'IServ' and do something with it.+-- Overloaded because this is used from TcM as well as IO.+withIServ+ :: (MonadIO m, ExceptionMonad m)+ => HscEnv -> (IServ -> m a) -> m a+withIServ HscEnv{..} action =+ gmask $ \restore -> do+ m <- liftIO $ takeMVar hsc_iserv+ -- start the iserv process if we haven't done so yet+ iserv <- maybe (liftIO $ startIServ hsc_dflags) return m+ `gonException` (liftIO $ putMVar hsc_iserv Nothing)+ -- free any ForeignHValues that have been garbage collected.+ let iserv' = iserv{ iservPendingFrees = [] }+ a <- (do+ liftIO $ when (not (null (iservPendingFrees iserv))) $+ iservCall iserv (FreeHValueRefs (iservPendingFrees iserv))+ -- run the inner action+ restore $ action iserv)+ `gonException` (liftIO $ putMVar hsc_iserv (Just iserv'))+ liftIO $ putMVar hsc_iserv (Just iserv')+ return a+++-- -----------------------------------------------------------------------------+-- Wrappers around messages++-- | Execute an action of type @IO [a]@, returning 'ForeignHValue's for+-- each of the results.+evalStmt+ :: HscEnv -> Bool -> EvalExpr ForeignHValue+ -> IO (EvalStatus_ [ForeignHValue] [HValueRef])+evalStmt hsc_env step foreign_expr = do+ let dflags = hsc_dflags hsc_env+ status <- withExpr foreign_expr $ \expr ->+ iservCmd hsc_env (EvalStmt (mkEvalOpts dflags step) expr)+ handleEvalStatus hsc_env status+ where+ withExpr :: EvalExpr ForeignHValue -> (EvalExpr HValueRef -> IO a) -> IO a+ withExpr (EvalThis fhv) cont =+ withForeignRef fhv $ \hvref -> cont (EvalThis hvref)+ withExpr (EvalApp fl fr) cont =+ withExpr fl $ \fl' ->+ withExpr fr $ \fr' ->+ cont (EvalApp fl' fr')++resumeStmt+ :: HscEnv -> Bool -> ForeignRef (ResumeContext [HValueRef])+ -> IO (EvalStatus_ [ForeignHValue] [HValueRef])+resumeStmt hsc_env step resume_ctxt = do+ let dflags = hsc_dflags hsc_env+ status <- withForeignRef resume_ctxt $ \rhv ->+ iservCmd hsc_env (ResumeStmt (mkEvalOpts dflags step) rhv)+ handleEvalStatus hsc_env status++abandonStmt :: HscEnv -> ForeignRef (ResumeContext [HValueRef]) -> IO ()+abandonStmt hsc_env resume_ctxt = do+ withForeignRef resume_ctxt $ \rhv ->+ iservCmd hsc_env (AbandonStmt rhv)++handleEvalStatus+ :: HscEnv -> EvalStatus [HValueRef]+ -> IO (EvalStatus_ [ForeignHValue] [HValueRef])+handleEvalStatus hsc_env status =+ case status of+ EvalBreak a b c d e f -> return (EvalBreak a b c d e f)+ EvalComplete alloc res ->+ EvalComplete alloc <$> addFinalizer res+ where+ addFinalizer (EvalException e) = return (EvalException e)+ addFinalizer (EvalSuccess rs) = do+ EvalSuccess <$> mapM (mkFinalizedHValue hsc_env) rs++-- | Execute an action of type @IO ()@+evalIO :: HscEnv -> ForeignHValue -> IO ()+evalIO hsc_env fhv = do+ liftIO $ withForeignRef fhv $ \fhv ->+ iservCmd hsc_env (EvalIO fhv) >>= fromEvalResult++-- | Execute an action of type @IO String@+evalString :: HscEnv -> ForeignHValue -> IO String+evalString hsc_env fhv = do+ liftIO $ withForeignRef fhv $ \fhv ->+ iservCmd hsc_env (EvalString fhv) >>= fromEvalResult++-- | Execute an action of type @String -> IO String@+evalStringToIOString :: HscEnv -> ForeignHValue -> String -> IO String+evalStringToIOString hsc_env fhv str = do+ liftIO $ withForeignRef fhv $ \fhv ->+ iservCmd hsc_env (EvalStringToString fhv str) >>= fromEvalResult+++-- | Allocate and store the given bytes in memory, returning a pointer+-- to the memory in the remote process.+mallocData :: HscEnv -> ByteString -> IO (RemotePtr ())+mallocData hsc_env bs = iservCmd hsc_env (MallocData bs)++mkCostCentres+ :: HscEnv -> String -> [(String,String)] -> IO [RemotePtr CostCentre]+mkCostCentres hsc_env mod ccs =+ iservCmd hsc_env (MkCostCentres mod ccs)++-- | Create a set of BCOs that may be mutually recursive.+createBCOs :: HscEnv -> [ResolvedBCO] -> IO [HValueRef]+createBCOs hsc_env rbcos = do+ n_jobs <- case parMakeCount (hsc_dflags hsc_env) of+ Nothing -> liftIO getNumProcessors+ Just n -> return n+ -- Serializing ResolvedBCO is expensive, so if we're in parallel mode+ -- (-j<n>) parallelise the serialization.+ if (n_jobs == 1)+ then+ iservCmd hsc_env (CreateBCOs [runPut (put rbcos)])++ else do+ old_caps <- getNumCapabilities+ if old_caps == n_jobs+ then void $ evaluate puts+ else bracket_ (setNumCapabilities n_jobs)+ (setNumCapabilities old_caps)+ (void $ evaluate puts)+ iservCmd hsc_env (CreateBCOs puts)+ where+ puts = parMap doChunk (chunkList 100 rbcos)++ -- make sure we force the whole lazy ByteString+ doChunk c = pseq (LB.length bs) bs+ where bs = runPut (put c)++ -- We don't have the parallel package, so roll our own simple parMap+ parMap _ [] = []+ parMap f (x:xs) = fx `par` (fxs `pseq` (fx : fxs))+ where fx = f x; fxs = parMap f xs++addSptEntry :: HscEnv -> Fingerprint -> ForeignHValue -> IO ()+addSptEntry hsc_env fpr ref =+ withForeignRef ref $ \val ->+ iservCmd hsc_env (AddSptEntry fpr val)++costCentreStackInfo :: HscEnv -> RemotePtr CostCentreStack -> IO [String]+costCentreStackInfo hsc_env ccs =+ iservCmd hsc_env (CostCentreStackInfo ccs)++newBreakArray :: HscEnv -> Int -> IO (ForeignRef BreakArray)+newBreakArray hsc_env size = do+ breakArray <- iservCmd hsc_env (NewBreakArray size)+ mkFinalizedHValue hsc_env breakArray++enableBreakpoint :: HscEnv -> ForeignRef BreakArray -> Int -> Bool -> IO ()+enableBreakpoint hsc_env ref ix b = do+ withForeignRef ref $ \breakarray ->+ iservCmd hsc_env (EnableBreakpoint breakarray ix b)++breakpointStatus :: HscEnv -> ForeignRef BreakArray -> Int -> IO Bool+breakpointStatus hsc_env ref ix = do+ withForeignRef ref $ \breakarray ->+ iservCmd hsc_env (BreakpointStatus breakarray ix)++getBreakpointVar :: HscEnv -> ForeignHValue -> Int -> IO (Maybe ForeignHValue)+getBreakpointVar hsc_env ref ix =+ withForeignRef ref $ \apStack -> do+ mb <- iservCmd hsc_env (GetBreakpointVar apStack ix)+ mapM (mkFinalizedHValue hsc_env) mb++-- -----------------------------------------------------------------------------+-- Interface to the object-code linker++initObjLinker :: HscEnv -> IO ()+initObjLinker hsc_env = iservCmd hsc_env InitLinker++lookupSymbol :: HscEnv -> FastString -> IO (Maybe (Ptr ()))+lookupSymbol hsc_env@HscEnv{..} str+ | gopt Opt_ExternalInterpreter hsc_dflags =+ -- Profiling of GHCi showed a lot of time and allocation spent+ -- making cross-process LookupSymbol calls, so I added a GHC-side+ -- cache which sped things up quite a lot. We have to be careful+ -- to purge this cache when unloading code though.+ withIServ hsc_env $ \iserv@IServ{..} -> do+ cache <- readIORef iservLookupSymbolCache+ case lookupUFM cache str of+ Just p -> return (Just p)+ Nothing -> do+ m <- uninterruptibleMask_ $+ iservCall iserv (LookupSymbol (unpackFS str))+ case m of+ Nothing -> return Nothing+ Just r -> do+ let p = fromRemotePtr r+ writeIORef iservLookupSymbolCache $! addToUFM cache str p+ return (Just p)+ | otherwise =+#ifdef GHCI+ fmap fromRemotePtr <$> run (LookupSymbol (unpackFS str))+#else+ needExtInt+#endif++lookupClosure :: HscEnv -> String -> IO (Maybe HValueRef)+lookupClosure hsc_env str =+ iservCmd hsc_env (LookupClosure str)++purgeLookupSymbolCache :: HscEnv -> IO ()+purgeLookupSymbolCache hsc_env@HscEnv{..} =+ when (gopt Opt_ExternalInterpreter hsc_dflags) $+ withIServ hsc_env $ \IServ{..} ->+ writeIORef iservLookupSymbolCache emptyUFM+++-- | loadDLL loads a dynamic library using the OS's native linker+-- (i.e. dlopen() on Unix, LoadLibrary() on Windows). It takes either+-- an absolute pathname to the file, or a relative filename+-- (e.g. "libfoo.so" or "foo.dll"). In the latter case, loadDLL+-- searches the standard locations for the appropriate library.+--+-- Returns:+--+-- Nothing => success+-- Just err_msg => failure+loadDLL :: HscEnv -> String -> IO (Maybe String)+loadDLL hsc_env str = iservCmd hsc_env (LoadDLL str)++loadArchive :: HscEnv -> String -> IO ()+loadArchive hsc_env path = do+ path' <- canonicalizePath path -- Note [loadObj and relative paths]+ iservCmd hsc_env (LoadArchive path')++loadObj :: HscEnv -> String -> IO ()+loadObj hsc_env path = do+ path' <- canonicalizePath path -- Note [loadObj and relative paths]+ iservCmd hsc_env (LoadObj path')++unloadObj :: HscEnv -> String -> IO ()+unloadObj hsc_env path = do+ path' <- canonicalizePath path -- Note [loadObj and relative paths]+ iservCmd hsc_env (UnloadObj path')++-- Note [loadObj and relative paths]+-- the iserv process might have a different current directory from the+-- GHC process, so we must make paths absolute before sending them+-- over.++addLibrarySearchPath :: HscEnv -> String -> IO (Ptr ())+addLibrarySearchPath hsc_env str =+ fromRemotePtr <$> iservCmd hsc_env (AddLibrarySearchPath str)++removeLibrarySearchPath :: HscEnv -> Ptr () -> IO Bool+removeLibrarySearchPath hsc_env p =+ iservCmd hsc_env (RemoveLibrarySearchPath (toRemotePtr p))++resolveObjs :: HscEnv -> IO SuccessFlag+resolveObjs hsc_env = successIf <$> iservCmd hsc_env ResolveObjs++findSystemLibrary :: HscEnv -> String -> IO (Maybe String)+findSystemLibrary hsc_env str = iservCmd hsc_env (FindSystemLibrary str)+++-- -----------------------------------------------------------------------------+-- Raw calls and messages++-- | Send a 'Message' and receive the response from the iserv process+iservCall :: Binary a => IServ -> Message a -> IO a+iservCall iserv@IServ{..} msg =+ remoteCall iservPipe msg+ `catch` \(e :: SomeException) -> handleIServFailure iserv e++-- | Read a value from the iserv process+readIServ :: IServ -> Get a -> IO a+readIServ iserv@IServ{..} get =+ readPipe iservPipe get+ `catch` \(e :: SomeException) -> handleIServFailure iserv e++-- | Send a value to the iserv process+writeIServ :: IServ -> Put -> IO ()+writeIServ iserv@IServ{..} put =+ writePipe iservPipe put+ `catch` \(e :: SomeException) -> handleIServFailure iserv e++handleIServFailure :: IServ -> SomeException -> IO a+handleIServFailure IServ{..} e = do+ ex <- getProcessExitCode iservProcess+ case ex of+ Just (ExitFailure n) ->+ throw (InstallationError ("ghc-iserv terminated (" ++ show n ++ ")"))+ _ -> do+ terminateProcess iservProcess+ _ <- waitForProcess iservProcess+ throw e++-- -----------------------------------------------------------------------------+-- Starting and stopping the iserv process++startIServ :: DynFlags -> IO IServ+startIServ dflags = do+ let flavour+ | WayProf `elem` ways dflags = "-prof"+ | WayDyn `elem` ways dflags = "-dyn"+ | otherwise = ""+ prog = pgm_i dflags ++ flavour+ opts = getOpts dflags opt_i+ debugTraceMsg dflags 3 $ text "Starting " <> text prog+ let createProc = lookupHook createIservProcessHook+ (\cp -> do { (_,_,_,ph) <- createProcess cp+ ; return ph })+ dflags+ (ph, rh, wh) <- runWithPipes createProc prog opts+ lo_ref <- newIORef Nothing+ cache_ref <- newIORef emptyUFM+ return $ IServ+ { iservPipe = Pipe { pipeRead = rh+ , pipeWrite = wh+ , pipeLeftovers = lo_ref }+ , iservProcess = ph+ , iservLookupSymbolCache = cache_ref+ , iservPendingFrees = []+ }++stopIServ :: HscEnv -> IO ()+stopIServ HscEnv{..} =+ gmask $ \_restore -> do+ m <- takeMVar hsc_iserv+ maybe (return ()) stop m+ putMVar hsc_iserv Nothing+ where+ stop iserv = do+ ex <- getProcessExitCode (iservProcess iserv)+ if isJust ex+ then return ()+ else iservCall iserv Shutdown++runWithPipes :: (CreateProcess -> IO ProcessHandle)+ -> FilePath -> [String] -> IO (ProcessHandle, Handle, Handle)+#ifdef mingw32_HOST_OS+foreign import ccall "io.h _close"+ c__close :: CInt -> IO CInt++foreign import ccall unsafe "io.h _get_osfhandle"+ _get_osfhandle :: CInt -> IO CInt++runWithPipes createProc prog opts = do+ (rfd1, wfd1) <- createPipeFd -- we read on rfd1+ (rfd2, wfd2) <- createPipeFd -- we write on wfd2+ wh_client <- _get_osfhandle wfd1+ rh_client <- _get_osfhandle rfd2+ let args = show wh_client : show rh_client : opts+ ph <- createProc (proc prog args)+ rh <- mkHandle rfd1+ wh <- mkHandle wfd2+ return (ph, rh, wh)+ where mkHandle :: CInt -> IO Handle+ mkHandle fd = (fdToHandle fd) `onException` (c__close fd)++#if !MIN_VERSION_process(1,4,2)+-- This #include and the _O_BINARY below are the only reason this is hsc,+-- so we can remove that once we can depend on process 1.4.2+#include <fcntl.h>++createPipeFd :: IO (FD, FD)+createPipeFd = do+ allocaArray 2 $ \ pfds -> do+ throwErrnoIfMinus1_ "_pipe" $ c__pipe pfds 2 (#const _O_BINARY)+ readfd <- peek pfds+ writefd <- peekElemOff pfds 1+ return (readfd, writefd)++foreign import ccall "io.h _pipe" c__pipe ::+ Ptr CInt -> CUInt -> CInt -> IO CInt+#endif+#else+runWithPipes createProc prog opts = do+ (rfd1, wfd1) <- Posix.createPipe -- we read on rfd1+ (rfd2, wfd2) <- Posix.createPipe -- we write on wfd2+ setFdOption rfd1 CloseOnExec True+ setFdOption wfd2 CloseOnExec True+ let args = show wfd1 : show rfd2 : opts+ ph <- createProc (proc prog args)+ closeFd wfd1+ closeFd rfd2+ rh <- fdToHandle rfd1+ wh <- fdToHandle wfd2+ return (ph, rh, wh)+#endif++-- -----------------------------------------------------------------------------+{- Note [External GHCi pointers]++We have the following ways to reference things in GHCi:++HValue+------++HValue is a direct reference to an value in the local heap. Obviously+we cannot use this to refer to things in the external process.+++RemoteRef+---------++RemoteRef is a StablePtr to a heap-resident value. When+-fexternal-interpreter is used, this value resides in the external+process's heap. RemoteRefs are mostly used to send pointers in+messages between GHC and iserv.++A RemoteRef must be explicitly freed when no longer required, using+freeHValueRefs, or by attaching a finalizer with mkForeignHValue.++To get from a RemoteRef to an HValue you can use 'wormholeRef', which+fails with an error message if -fexternal-interpreter is in use.++ForeignRef+----------++A ForeignRef is a RemoteRef with a finalizer that will free the+'RemoteRef' when it is garbage collected. We mostly use ForeignHValue+on the GHC side.++The finalizer adds the RemoteRef to the iservPendingFrees list in the+IServ record. The next call to iservCmd will free any RemoteRefs in+the list. It was done this way rather than calling iservCmd directly,+because I didn't want to have arbitrary threads calling iservCmd. In+principle it would probably be ok, but it seems less hairy this way.+-}++-- | Creates a 'ForeignRef' that will automatically release the+-- 'RemoteRef' when it is no longer referenced.+mkFinalizedHValue :: HscEnv -> RemoteRef a -> IO (ForeignRef a)+mkFinalizedHValue HscEnv{..} rref = mkForeignRef rref free+ where+ !external = gopt Opt_ExternalInterpreter hsc_dflags+ hvref = toHValueRef rref++ free :: IO ()+ free+ | not external = freeRemoteRef hvref+ | otherwise =+ modifyMVar_ hsc_iserv $ \mb_iserv ->+ case mb_iserv of+ Nothing -> return Nothing -- already shut down+ Just iserv@IServ{..} ->+ return (Just iserv{iservPendingFrees = hvref : iservPendingFrees})++freeHValueRefs :: HscEnv -> [HValueRef] -> IO ()+freeHValueRefs _ [] = return ()+freeHValueRefs hsc_env refs = iservCmd hsc_env (FreeHValueRefs refs)++-- | Convert a 'ForeignRef' to the value it references directly. This+-- only works when the interpreter is running in the same process as+-- the compiler, so it fails when @-fexternal-interpreter@ is on.+wormhole :: DynFlags -> ForeignRef a -> IO a+wormhole dflags r = wormholeRef dflags (unsafeForeignRefToRemoteRef r)++-- | Convert an 'RemoteRef' to the value it references directly. This+-- only works when the interpreter is running in the same process as+-- the compiler, so it fails when @-fexternal-interpreter@ is on.+wormholeRef :: DynFlags -> RemoteRef a -> IO a+wormholeRef dflags _r+ | gopt Opt_ExternalInterpreter dflags+ = throwIO (InstallationError+ "this operation requires -fno-external-interpreter")+#ifdef GHCI+ | otherwise+ = localRef _r+#else+ | otherwise+ = throwIO (InstallationError+ "can't wormhole a value in a stage1 compiler")+#endif++-- -----------------------------------------------------------------------------+-- Misc utils++mkEvalOpts :: DynFlags -> Bool -> EvalOpts+mkEvalOpts dflags step =+ EvalOpts+ { useSandboxThread = gopt Opt_GhciSandbox dflags+ , singleStep = step+ , breakOnException = gopt Opt_BreakOnException dflags+ , breakOnError = gopt Opt_BreakOnError dflags }++fromEvalResult :: EvalResult a -> IO a+fromEvalResult (EvalException e) = throwIO (fromSerializableException e)+fromEvalResult (EvalSuccess a) = return a
+ ghci/Linker.hs view
@@ -0,0 +1,1475 @@+{-# LANGUAGE CPP, NondecreasingIndentation, TupleSections, RecordWildCards #-}+{-# OPTIONS_GHC -fno-cse #-}+-- -fno-cse is needed for GLOBAL_VAR's to behave properly++--+-- (c) The University of Glasgow 2002-2006+--+-- | The dynamic linker for GHCi.+--+-- This module deals with the top-level issues of dynamic linking,+-- calling the object-code linker and the byte-code linker where+-- necessary.+module Linker ( getHValue, showLinkerState,+ linkExpr, linkDecls, unload, withExtendedLinkEnv,+ extendLinkEnv, deleteFromLinkEnv,+ extendLoadedPkgs,+ linkPackages,initDynLinker,linkModule,+ linkCmdLineLibs+ ) where++#include "HsVersions.h"++import GHCi+import GHCi.RemoteTypes+import LoadIface+import ByteCodeLink+import ByteCodeAsm+import ByteCodeTypes+import TcRnMonad+import Packages+import DriverPhases+import Finder+import HscTypes+import Name+import NameEnv+import Module+import ListSetOps+import DynFlags+import BasicTypes+import Outputable+import Panic+import Util+import ErrUtils+import SrcLoc+import qualified Maybes+import UniqDSet+import FastString+import Platform+import SysTools++-- Standard libraries+import Control.Monad+import Control.Applicative((<|>))++import Data.IORef+import Data.List+import Data.Maybe+import Control.Concurrent.MVar++import System.FilePath+import System.Directory++import Exception++import Foreign (Ptr) -- needed for 2nd stage++{- **********************************************************************++ The Linker's state++ ********************************************************************* -}++{-+The persistent linker state *must* match the actual state of the+C dynamic linker at all times, so we keep it in a private global variable.++The global IORef used for PersistentLinkerState actually contains another MVar.+The reason for this is that we want to allow another loaded copy of the GHC+library to side-effect the PLS and for those changes to be reflected here.++The PersistentLinkerState maps Names to actual closures (for+interpreted code only), for use during linking.+-}+#if STAGE < 2+GLOBAL_VAR_M(v_PersistentLinkerState, newMVar (panic "Dynamic linker not initialised"), MVar PersistentLinkerState)+GLOBAL_VAR(v_InitLinkerDone, False, Bool) -- Set True when dynamic linker is initialised+#else+SHARED_GLOBAL_VAR_M( v_PersistentLinkerState+ , getOrSetLibHSghcPersistentLinkerState+ , "getOrSetLibHSghcPersistentLinkerState"+ , newMVar (panic "Dynamic linker not initialised")+ , MVar PersistentLinkerState)+-- Set True when dynamic linker is initialised+SHARED_GLOBAL_VAR( v_InitLinkerDone+ , getOrSetLibHSghcInitLinkerDone+ , "getOrSetLibHSghcInitLinkerDone"+ , False+ , Bool)+#endif++modifyPLS_ :: (PersistentLinkerState -> IO PersistentLinkerState) -> IO ()+modifyPLS_ f = readIORef v_PersistentLinkerState >>= flip modifyMVar_ f++modifyPLS :: (PersistentLinkerState -> IO (PersistentLinkerState, a)) -> IO a+modifyPLS f = readIORef v_PersistentLinkerState >>= flip modifyMVar f++data PersistentLinkerState+ = PersistentLinkerState {++ -- Current global mapping from Names to their true values+ closure_env :: ClosureEnv,++ -- The current global mapping from RdrNames of DataCons to+ -- info table addresses.+ -- When a new Unlinked is linked into the running image, or an existing+ -- module in the image is replaced, the itbl_env must be updated+ -- appropriately.+ itbl_env :: !ItblEnv,++ -- The currently loaded interpreted modules (home package)+ bcos_loaded :: ![Linkable],++ -- And the currently-loaded compiled modules (home package)+ objs_loaded :: ![Linkable],++ -- The currently-loaded packages; always object code+ -- Held, as usual, in dependency order; though I am not sure if+ -- that is really important+ pkgs_loaded :: ![LinkerUnitId],++ -- we need to remember the name of previous temporary DLL/.so+ -- libraries so we can link them (see #10322)+ temp_sos :: ![(FilePath, String)] }+++emptyPLS :: DynFlags -> PersistentLinkerState+emptyPLS _ = PersistentLinkerState {+ closure_env = emptyNameEnv,+ itbl_env = emptyNameEnv,+ pkgs_loaded = init_pkgs,+ bcos_loaded = [],+ objs_loaded = [],+ temp_sos = [] }++ -- Packages that don't need loading, because the compiler+ -- shares them with the interpreted program.+ --+ -- The linker's symbol table is populated with RTS symbols using an+ -- explicit list. See rts/Linker.c for details.+ where init_pkgs = map toInstalledUnitId [rtsUnitId]+++extendLoadedPkgs :: [InstalledUnitId] -> IO ()+extendLoadedPkgs pkgs =+ modifyPLS_ $ \s ->+ return s{ pkgs_loaded = pkgs ++ pkgs_loaded s }++extendLinkEnv :: [(Name,ForeignHValue)] -> IO ()+extendLinkEnv new_bindings =+ modifyPLS_ $ \pls -> do+ let ce = closure_env pls+ let new_ce = extendClosureEnv ce new_bindings+ return pls{ closure_env = new_ce }++deleteFromLinkEnv :: [Name] -> IO ()+deleteFromLinkEnv to_remove =+ modifyPLS_ $ \pls -> do+ let ce = closure_env pls+ let new_ce = delListFromNameEnv ce to_remove+ return pls{ closure_env = new_ce }++-- | Get the 'HValue' associated with the given name.+--+-- May cause loading the module that contains the name.+--+-- Throws a 'ProgramError' if loading fails or the name cannot be found.+getHValue :: HscEnv -> Name -> IO ForeignHValue+getHValue hsc_env name = do+ initDynLinker hsc_env+ pls <- modifyPLS $ \pls -> do+ if (isExternalName name) then do+ (pls', ok) <- linkDependencies hsc_env pls noSrcSpan+ [nameModule name]+ if (failed ok) then throwGhcExceptionIO (ProgramError "")+ else return (pls', pls')+ else+ return (pls, pls)+ case lookupNameEnv (closure_env pls) name of+ Just (_,aa) -> return aa+ Nothing+ -> ASSERT2(isExternalName name, ppr name)+ do let sym_to_find = nameToCLabel name "closure"+ m <- lookupClosure hsc_env (unpackFS sym_to_find)+ case m of+ Just hvref -> mkFinalizedHValue hsc_env hvref+ Nothing -> linkFail "ByteCodeLink.lookupCE"+ (unpackFS sym_to_find)++linkDependencies :: HscEnv -> PersistentLinkerState+ -> SrcSpan -> [Module]+ -> IO (PersistentLinkerState, SuccessFlag)+linkDependencies hsc_env pls span needed_mods = do+-- initDynLinker (hsc_dflags hsc_env)+ let hpt = hsc_HPT hsc_env+ dflags = hsc_dflags hsc_env+ -- The interpreter and dynamic linker can only handle object code built+ -- the "normal" way, i.e. no non-std ways like profiling or ticky-ticky.+ -- So here we check the build tag: if we're building a non-standard way+ -- then we need to find & link object files built the "normal" way.+ maybe_normal_osuf <- checkNonStdWay dflags span++ -- Find what packages and linkables are required+ (lnks, pkgs) <- getLinkDeps hsc_env hpt pls+ maybe_normal_osuf span needed_mods++ -- Link the packages and modules required+ pls1 <- linkPackages' hsc_env pkgs pls+ linkModules hsc_env pls1 lnks+++-- | Temporarily extend the linker state.++withExtendedLinkEnv :: (ExceptionMonad m) =>+ [(Name,ForeignHValue)] -> m a -> m a+withExtendedLinkEnv new_env action+ = gbracket (liftIO $ extendLinkEnv new_env)+ (\_ -> reset_old_env)+ (\_ -> action)+ where+ -- Remember that the linker state might be side-effected+ -- during the execution of the IO action, and we don't want to+ -- lose those changes (we might have linked a new module or+ -- package), so the reset action only removes the names we+ -- added earlier.+ reset_old_env = liftIO $ do+ modifyPLS_ $ \pls ->+ let cur = closure_env pls+ new = delListFromNameEnv cur (map fst new_env)+ in return pls{ closure_env = new }+++-- | Display the persistent linker state.+showLinkerState :: DynFlags -> IO ()+showLinkerState dflags+ = do pls <- readIORef v_PersistentLinkerState >>= readMVar+ putLogMsg dflags NoReason SevDump noSrcSpan+ (defaultDumpStyle dflags)+ (vcat [text "----- Linker state -----",+ text "Pkgs:" <+> ppr (pkgs_loaded pls),+ text "Objs:" <+> ppr (objs_loaded pls),+ text "BCOs:" <+> ppr (bcos_loaded pls)])+++{- **********************************************************************++ Initialisation++ ********************************************************************* -}++-- | Initialise the dynamic linker. This entails+--+-- a) Calling the C initialisation procedure,+--+-- b) Loading any packages specified on the command line,+--+-- c) Loading any packages specified on the command line, now held in the+-- @-l@ options in @v_Opt_l@,+--+-- d) Loading any @.o\/.dll@ files specified on the command line, now held+-- in @ldInputs@,+--+-- e) Loading any MacOS frameworks.+--+-- NOTE: This function is idempotent; if called more than once, it does+-- nothing. This is useful in Template Haskell, where we call it before+-- trying to link.+--+initDynLinker :: HscEnv -> IO ()+initDynLinker hsc_env =+ modifyPLS_ $ \pls0 -> do+ done <- readIORef v_InitLinkerDone+ if done then return pls0+ else do writeIORef v_InitLinkerDone True+ reallyInitDynLinker hsc_env++reallyInitDynLinker :: HscEnv -> IO PersistentLinkerState+reallyInitDynLinker hsc_env = do+ -- Initialise the linker state+ let dflags = hsc_dflags hsc_env+ pls0 = emptyPLS dflags++ -- (a) initialise the C dynamic linker+ initObjLinker hsc_env++ -- (b) Load packages from the command-line (Note [preload packages])+ pls <- linkPackages' hsc_env (preloadPackages (pkgState dflags)) pls0++ -- steps (c), (d) and (e)+ linkCmdLineLibs' hsc_env pls+++linkCmdLineLibs :: HscEnv -> IO ()+linkCmdLineLibs hsc_env = do+ initDynLinker hsc_env+ modifyPLS_ $ \pls -> do+ linkCmdLineLibs' hsc_env pls++linkCmdLineLibs' :: HscEnv -> PersistentLinkerState -> IO PersistentLinkerState+linkCmdLineLibs' hsc_env pls =+ do+ let dflags@(DynFlags { ldInputs = cmdline_ld_inputs+ , libraryPaths = lib_paths}) = hsc_dflags hsc_env++ -- (c) Link libraries from the command-line+ let minus_ls_1 = [ lib | Option ('-':'l':lib) <- cmdline_ld_inputs ]++ -- On Windows we want to add libpthread by default just as GCC would.+ -- However because we don't know the actual name of pthread's dll we+ -- need to defer this to the locateLib call so we can't initialize it+ -- inside of the rts. Instead we do it here to be able to find the+ -- import library for pthreads. See Trac #13210.+ let platform = targetPlatform dflags+ os = platformOS platform+ minus_ls = case os of+ OSMinGW32 -> "pthread" : minus_ls_1+ _ -> minus_ls_1++ libspecs <- mapM (locateLib hsc_env False lib_paths) minus_ls++ -- (d) Link .o files from the command-line+ classified_ld_inputs <- mapM (classifyLdInput dflags)+ [ f | FileOption _ f <- cmdline_ld_inputs ]++ -- (e) Link any MacOS frameworks+ let platform = targetPlatform dflags+ let (framework_paths, frameworks) =+ if platformUsesFrameworks platform+ then (frameworkPaths dflags, cmdlineFrameworks dflags)+ else ([],[])++ -- Finally do (c),(d),(e)+ let cmdline_lib_specs = catMaybes classified_ld_inputs+ ++ libspecs+ ++ map Framework frameworks+ if null cmdline_lib_specs then return pls+ else do++ -- Add directories to library search paths, this only has an effect+ -- on Windows. On Unix OSes this function is a NOP.+ let all_paths = let paths = takeDirectory (fst $ sPgm_c $ settings dflags)+ : framework_paths+ ++ lib_paths+ ++ [ takeDirectory dll | DLLPath dll <- libspecs ]+ in nub $ map normalise paths+ pathCache <- mapM (addLibrarySearchPath hsc_env) all_paths++ pls1 <- foldM (preloadLib hsc_env lib_paths framework_paths) pls+ cmdline_lib_specs+ maybePutStr dflags "final link ... "+ ok <- resolveObjs hsc_env++ -- DLLs are loaded, reset the search paths+ mapM_ (removeLibrarySearchPath hsc_env) $ reverse pathCache++ if succeeded ok then maybePutStrLn dflags "done"+ else throwGhcExceptionIO (ProgramError "linking extra libraries/objects failed")++ return pls1++{- Note [preload packages]++Why do we need to preload packages from the command line? This is an+explanation copied from #2437:++I tried to implement the suggestion from #3560, thinking it would be+easy, but there are two reasons we link in packages eagerly when they+are mentioned on the command line:++ * So that you can link in extra object files or libraries that+ depend on the packages. e.g. ghc -package foo -lbar where bar is a+ C library that depends on something in foo. So we could link in+ foo eagerly if and only if there are extra C libs or objects to+ link in, but....++ * Haskell code can depend on a C function exported by a package, and+ the normal dependency tracking that TH uses can't know about these+ dependencies. The test ghcilink004 relies on this, for example.++I conclude that we need two -package flags: one that says "this is a+package I want to make available", and one that says "this is a+package I want to link in eagerly". Would that be too complicated for+users?+-}++classifyLdInput :: DynFlags -> FilePath -> IO (Maybe LibrarySpec)+classifyLdInput dflags f+ | isObjectFilename platform f = return (Just (Object f))+ | isDynLibFilename platform f = return (Just (DLLPath f))+ | otherwise = do+ putLogMsg dflags NoReason SevInfo noSrcSpan+ (defaultUserStyle dflags)+ (text ("Warning: ignoring unrecognised input `" ++ f ++ "'"))+ return Nothing+ where platform = targetPlatform dflags++preloadLib+ :: HscEnv -> [String] -> [String] -> PersistentLinkerState+ -> LibrarySpec -> IO PersistentLinkerState+preloadLib hsc_env lib_paths framework_paths pls lib_spec = do+ maybePutStr dflags ("Loading object " ++ showLS lib_spec ++ " ... ")+ case lib_spec of+ Object static_ish -> do+ (b, pls1) <- preload_static lib_paths static_ish+ maybePutStrLn dflags (if b then "done" else "not found")+ return pls1++ Archive static_ish -> do+ b <- preload_static_archive lib_paths static_ish+ maybePutStrLn dflags (if b then "done" else "not found")+ return pls++ DLL dll_unadorned -> do+ maybe_errstr <- loadDLL hsc_env (mkSOName platform dll_unadorned)+ case maybe_errstr of+ Nothing -> maybePutStrLn dflags "done"+ Just mm | platformOS platform /= OSDarwin ->+ preloadFailed mm lib_paths lib_spec+ Just mm | otherwise -> do+ -- As a backup, on Darwin, try to also load a .so file+ -- since (apparently) some things install that way - see+ -- ticket #8770.+ let libfile = ("lib" ++ dll_unadorned) <.> "so"+ err2 <- loadDLL hsc_env libfile+ case err2 of+ Nothing -> maybePutStrLn dflags "done"+ Just _ -> preloadFailed mm lib_paths lib_spec+ return pls++ DLLPath dll_path -> do+ do maybe_errstr <- loadDLL hsc_env dll_path+ case maybe_errstr of+ Nothing -> maybePutStrLn dflags "done"+ Just mm -> preloadFailed mm lib_paths lib_spec+ return pls++ Framework framework ->+ if platformUsesFrameworks (targetPlatform dflags)+ then do maybe_errstr <- loadFramework hsc_env framework_paths framework+ case maybe_errstr of+ Nothing -> maybePutStrLn dflags "done"+ Just mm -> preloadFailed mm framework_paths lib_spec+ return pls+ else panic "preloadLib Framework"++ where+ dflags = hsc_dflags hsc_env++ platform = targetPlatform dflags++ preloadFailed :: String -> [String] -> LibrarySpec -> IO ()+ preloadFailed sys_errmsg paths spec+ = do maybePutStr dflags "failed.\n"+ throwGhcExceptionIO $+ CmdLineError (+ "user specified .o/.so/.DLL could not be loaded ("+ ++ sys_errmsg ++ ")\nWhilst trying to load: "+ ++ showLS spec ++ "\nAdditional directories searched:"+ ++ (if null paths then " (none)" else+ intercalate "\n" (map (" "++) paths)))++ -- Not interested in the paths in the static case.+ preload_static _paths name+ = do b <- doesFileExist name+ if not b then return (False, pls)+ else if dynamicGhc+ then do pls1 <- dynLoadObjs hsc_env pls [name]+ return (True, pls1)+ else do loadObj hsc_env name+ return (True, pls)++ preload_static_archive _paths name+ = do b <- doesFileExist name+ if not b then return False+ else do if dynamicGhc+ then panic "Loading archives not supported"+ else loadArchive hsc_env name+ return True+++{- **********************************************************************++ Link a byte-code expression++ ********************************************************************* -}++-- | Link a single expression, /including/ first linking packages and+-- modules that this expression depends on.+--+-- Raises an IO exception ('ProgramError') if it can't find a compiled+-- version of the dependents to link.+--+linkExpr :: HscEnv -> SrcSpan -> UnlinkedBCO -> IO ForeignHValue+linkExpr hsc_env span root_ul_bco+ = do {+ -- Initialise the linker (if it's not been done already)+ ; initDynLinker hsc_env++ -- Take lock for the actual work.+ ; modifyPLS $ \pls0 -> do {++ -- Link the packages and modules required+ ; (pls, ok) <- linkDependencies hsc_env pls0 span needed_mods+ ; if failed ok then+ throwGhcExceptionIO (ProgramError "")+ else do {++ -- Link the expression itself+ let ie = itbl_env pls+ ce = closure_env pls++ -- Link the necessary packages and linkables++ ; let nobreakarray = error "no break array"+ bco_ix = mkNameEnv [(unlinkedBCOName root_ul_bco, 0)]+ ; resolved <- linkBCO hsc_env ie ce bco_ix nobreakarray root_ul_bco+ ; [root_hvref] <- createBCOs hsc_env [resolved]+ ; fhv <- mkFinalizedHValue hsc_env root_hvref+ ; return (pls, fhv)+ }}}+ where+ free_names = uniqDSetToList (bcoFreeNames root_ul_bco)++ needed_mods :: [Module]+ needed_mods = [ nameModule n | n <- free_names,+ isExternalName n, -- Names from other modules+ not (isWiredInName n) -- Exclude wired-in names+ ] -- (see note below)+ -- Exclude wired-in names because we may not have read+ -- their interface files, so getLinkDeps will fail+ -- All wired-in names are in the base package, which we link+ -- by default, so we can safely ignore them here.++dieWith :: DynFlags -> SrcSpan -> MsgDoc -> IO a+dieWith dflags span msg = throwGhcExceptionIO (ProgramError (showSDoc dflags (mkLocMessage SevFatal span msg)))+++checkNonStdWay :: DynFlags -> SrcSpan -> IO (Maybe FilePath)+checkNonStdWay dflags srcspan+ | gopt Opt_ExternalInterpreter dflags = return Nothing+ -- with -fexternal-interpreter we load the .o files, whatever way+ -- they were built. If they were built for a non-std way, then+ -- we will use the appropriate variant of the iserv binary to load them.++ | interpWays == haskellWays = return Nothing+ -- 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 haskellWays)+ = failNonStd dflags srcspan++ | otherwise = return (Just (interpTag ++ "o"))+ where+ haskellWays = filter (not . wayRTSOnly) (ways dflags)+ interpTag = case mkBuildTag interpWays of+ "" -> ""+ tag -> tag ++ "_"++normalObjectSuffix :: String+normalObjectSuffix = phaseInputExt StopLn++failNonStd :: DynFlags -> SrcSpan -> IO (Maybe FilePath)+failNonStd dflags srcspan = dieWith dflags srcspan $+ text "Cannot load" <+> compWay <+>+ text "objects when GHC is built" <+> ghciWay $$+ text "To fix this, either:" $$+ text " (1) Use -fexternal-interprter, 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."+ where compWay+ | WayDyn `elem` ways dflags = text "-dynamic"+ | WayProf `elem` ways dflags = text "-prof"+ | otherwise = text "normal"+ ghciWay+ | dynamicGhc = text "with -dynamic"+ | rtsIsProfiled = text "with -prof"+ | otherwise = text "the normal way"++getLinkDeps :: HscEnv -> HomePackageTable+ -> PersistentLinkerState+ -> Maybe FilePath -- replace object suffices?+ -> SrcSpan -- for error messages+ -> [Module] -- If you need these+ -> IO ([Linkable], [InstalledUnitId]) -- ... then link these first+-- Fails with an IO exception if it can't find enough files++getLinkDeps hsc_env hpt pls replace_osuf span mods+-- Find all the packages and linkables that a set of modules depends on+ = do {+ -- 1. Find the dependent home-pkg-modules/packages from each iface+ -- (omitting modules from the interactive package, which is already linked)+ ; (mods_s, pkgs_s) <- follow_deps (filterOut isInteractiveModule mods)+ emptyUniqDSet emptyUniqDSet;++ ; let {+ -- 2. Exclude ones already linked+ -- Main reason: avoid findModule calls in get_linkable+ mods_needed = mods_s `minusList` linked_mods ;+ pkgs_needed = pkgs_s `minusList` pkgs_loaded pls ;++ linked_mods = map (moduleName.linkableModule)+ (objs_loaded pls ++ bcos_loaded pls) }++ -- 3. For each dependent module, find its linkable+ -- This will either be in the HPT or (in the case of one-shot+ -- compilation) we may need to use maybe_getFileLinkable+ ; let { osuf = objectSuf dflags }+ ; lnks_needed <- mapM (get_linkable osuf) mods_needed++ ; return (lnks_needed, pkgs_needed) }+ where+ dflags = hsc_dflags hsc_env+ this_pkg = thisPackage dflags++ -- The ModIface contains the transitive closure of the module dependencies+ -- within the current package, *except* for boot modules: if we encounter+ -- a boot module, we have to find its real interface and discover the+ -- dependencies of that. Hence we need to traverse the dependency+ -- tree recursively. See bug #936, testcase ghci/prog007.+ follow_deps :: [Module] -- modules to follow+ -> UniqDSet ModuleName -- accum. module dependencies+ -> UniqDSet InstalledUnitId -- accum. package dependencies+ -> IO ([ModuleName], [InstalledUnitId]) -- result+ follow_deps [] acc_mods acc_pkgs+ = return (uniqDSetToList acc_mods, uniqDSetToList acc_pkgs)+ follow_deps (mod:mods) acc_mods acc_pkgs+ = do+ mb_iface <- initIfaceCheck (text "getLinkDeps") hsc_env $+ loadInterface msg mod (ImportByUser False)+ iface <- case mb_iface of+ Maybes.Failed err -> throwGhcExceptionIO (ProgramError (showSDoc dflags err))+ Maybes.Succeeded iface -> return iface++ when (mi_boot iface) $ link_boot_mod_error mod++ let+ pkg = moduleUnitId mod+ deps = mi_deps iface++ pkg_deps = dep_pkgs deps+ (boot_deps, mod_deps) = partitionWith is_boot (dep_mods deps)+ where is_boot (m,True) = Left m+ is_boot (m,False) = Right m++ boot_deps' = filter (not . (`elementOfUniqDSet` acc_mods)) boot_deps+ acc_mods' = addListToUniqDSet acc_mods (moduleName mod : mod_deps)+ acc_pkgs' = addListToUniqDSet acc_pkgs $ map fst pkg_deps+ --+ if pkg /= this_pkg+ then follow_deps mods acc_mods (addOneToUniqDSet acc_pkgs' (toInstalledUnitId pkg))+ else follow_deps (map (mkModule this_pkg) boot_deps' ++ mods)+ acc_mods' acc_pkgs'+ where+ msg = text "need to link module" <+> ppr mod <+>+ text "due to use of Template Haskell"+++ link_boot_mod_error mod =+ throwGhcExceptionIO (ProgramError (showSDoc dflags (+ text "module" <+> ppr mod <+>+ text "cannot be linked; it is only available as a boot module")))++ no_obj :: Outputable a => a -> IO b+ no_obj mod = dieWith dflags span $+ text "cannot find object file for module " <>+ quotes (ppr mod) $$+ while_linking_expr++ while_linking_expr = text "while linking an interpreted expression"++ -- This one is a build-system bug++ get_linkable osuf mod_name -- A home-package module+ | Just mod_info <- lookupHpt hpt mod_name+ = adjust_linkable (Maybes.expectJust "getLinkDeps" (hm_linkable mod_info))+ | otherwise+ = do -- It's not in the HPT because we are in one shot mode,+ -- so use the Finder to get a ModLocation...+ mb_stuff <- findHomeModule hsc_env mod_name+ case mb_stuff of+ Found loc mod -> found loc mod+ _ -> no_obj mod_name+ where+ found loc mod = do {+ -- ...and then find the linkable for it+ mb_lnk <- findObjectLinkableMaybe mod loc ;+ case mb_lnk of {+ Nothing -> no_obj mod ;+ Just lnk -> adjust_linkable lnk+ }}++ adjust_linkable lnk+ | Just new_osuf <- replace_osuf = do+ new_uls <- mapM (adjust_ul new_osuf)+ (linkableUnlinked lnk)+ return lnk{ linkableUnlinked=new_uls }+ | otherwise =+ return lnk++ adjust_ul new_osuf (DotO file) = do+ MASSERT(osuf `isSuffixOf` file)+ let file_base = fromJust (stripExtension osuf file)+ new_file = file_base <.> new_osuf+ ok <- doesFileExist new_file+ if (not ok)+ then dieWith dflags span $+ text "cannot find object file "+ <> quotes (text new_file) $$ while_linking_expr+ else return (DotO new_file)+ adjust_ul _ (DotA fp) = panic ("adjust_ul DotA " ++ show fp)+ adjust_ul _ (DotDLL fp) = panic ("adjust_ul DotDLL " ++ show fp)+ adjust_ul _ l@(BCOs {}) = return l+#if !MIN_VERSION_filepath(1,4,1)+ stripExtension :: String -> FilePath -> Maybe FilePath+ stripExtension [] path = Just path+ stripExtension ext@(x:_) path = stripSuffix dotExt path+ where dotExt = if isExtSeparator x then ext else '.':ext++ stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]+ stripSuffix xs ys = fmap reverse $ stripPrefix (reverse xs) (reverse ys)+#endif++++{- **********************************************************************++ Loading a Decls statement++ ********************************************************************* -}++linkDecls :: HscEnv -> SrcSpan -> CompiledByteCode -> IO ()+linkDecls hsc_env span cbc@CompiledByteCode{..} = do+ -- Initialise the linker (if it's not been done already)+ initDynLinker hsc_env++ -- Take lock for the actual work.+ modifyPLS $ \pls0 -> do++ -- Link the packages and modules required+ (pls, ok) <- linkDependencies hsc_env pls0 span needed_mods+ if failed ok+ then throwGhcExceptionIO (ProgramError "")+ else do++ -- Link the expression itself+ let ie = plusNameEnv (itbl_env pls) bc_itbls+ ce = closure_env pls++ -- Link the necessary packages and linkables+ new_bindings <- linkSomeBCOs hsc_env ie ce [cbc]+ nms_fhvs <- makeForeignNamedHValueRefs hsc_env new_bindings+ let pls2 = pls { closure_env = extendClosureEnv ce nms_fhvs+ , itbl_env = ie }+ return (pls2, ())+ where+ free_names = uniqDSetToList $+ foldr (unionUniqDSets . bcoFreeNames) emptyUniqDSet bc_bcos++ needed_mods :: [Module]+ needed_mods = [ nameModule n | n <- free_names,+ isExternalName n, -- Names from other modules+ not (isWiredInName n) -- Exclude wired-in names+ ] -- (see note below)+ -- Exclude wired-in names because we may not have read+ -- their interface files, so getLinkDeps will fail+ -- All wired-in names are in the base package, which we link+ -- by default, so we can safely ignore them here.++{- **********************************************************************++ Loading a single module++ ********************************************************************* -}++linkModule :: HscEnv -> Module -> IO ()+linkModule hsc_env mod = do+ initDynLinker hsc_env+ modifyPLS_ $ \pls -> do+ (pls', ok) <- linkDependencies hsc_env pls noSrcSpan [mod]+ if (failed ok) then throwGhcExceptionIO (ProgramError "could not link module")+ else return pls'++{- **********************************************************************++ Link some linkables+ The linkables may consist of a mixture of+ byte-code modules and object modules++ ********************************************************************* -}++linkModules :: HscEnv -> PersistentLinkerState -> [Linkable]+ -> IO (PersistentLinkerState, SuccessFlag)+linkModules hsc_env pls linkables+ = mask_ $ do -- don't want to be interrupted by ^C in here++ let (objs, bcos) = partition isObjectLinkable+ (concatMap partitionLinkable linkables)++ -- Load objects first; they can't depend on BCOs+ (pls1, ok_flag) <- dynLinkObjs hsc_env pls objs++ if failed ok_flag then+ return (pls1, Failed)+ else do+ pls2 <- dynLinkBCOs hsc_env pls1 bcos+ return (pls2, Succeeded)+++-- HACK to support f-x-dynamic in the interpreter; no other purpose+partitionLinkable :: Linkable -> [Linkable]+partitionLinkable li+ = let li_uls = linkableUnlinked li+ li_uls_obj = filter isObject li_uls+ li_uls_bco = filter isInterpretable li_uls+ in+ case (li_uls_obj, li_uls_bco) of+ (_:_, _:_) -> [li {linkableUnlinked=li_uls_obj},+ li {linkableUnlinked=li_uls_bco}]+ _ -> [li]++findModuleLinkable_maybe :: [Linkable] -> Module -> Maybe Linkable+findModuleLinkable_maybe lis mod+ = case [LM time nm us | LM time nm us <- lis, nm == mod] of+ [] -> Nothing+ [li] -> Just li+ _ -> pprPanic "findModuleLinkable" (ppr mod)++linkableInSet :: Linkable -> [Linkable] -> Bool+linkableInSet l objs_loaded =+ case findModuleLinkable_maybe objs_loaded (linkableModule l) of+ Nothing -> False+ Just m -> linkableTime l == linkableTime m+++{- **********************************************************************++ The object-code linker++ ********************************************************************* -}++dynLinkObjs :: HscEnv -> PersistentLinkerState -> [Linkable]+ -> IO (PersistentLinkerState, SuccessFlag)+dynLinkObjs hsc_env pls objs = do+ -- Load the object files and link them+ let (objs_loaded', new_objs) = rmDupLinkables (objs_loaded pls) objs+ pls1 = pls { objs_loaded = objs_loaded' }+ unlinkeds = concatMap linkableUnlinked new_objs+ wanted_objs = map nameOfObject unlinkeds++ if interpreterDynamic (hsc_dflags hsc_env)+ then do pls2 <- dynLoadObjs hsc_env pls1 wanted_objs+ return (pls2, Succeeded)+ else do mapM_ (loadObj hsc_env) wanted_objs++ -- Link them all together+ ok <- resolveObjs hsc_env++ -- If resolving failed, unload all our+ -- object modules and carry on+ if succeeded ok then do+ return (pls1, Succeeded)+ else do+ pls2 <- unload_wkr hsc_env [] pls1+ return (pls2, Failed)+++dynLoadObjs :: HscEnv -> PersistentLinkerState -> [FilePath]+ -> IO PersistentLinkerState+dynLoadObjs _ pls [] = return pls+dynLoadObjs hsc_env pls objs = do+ let dflags = hsc_dflags hsc_env+ let platform = targetPlatform dflags+ let minus_ls = [ lib | Option ('-':'l':lib) <- ldInputs dflags ]+ let minus_big_ls = [ lib | Option ('-':'L':lib) <- ldInputs dflags ]+ (soFile, libPath , libName) <- newTempLibName dflags (soExt platform)+ let+ dflags2 = dflags {+ -- We don't want the original ldInputs in+ -- (they're already linked in), but we do want+ -- to link against previous dynLoadObjs+ -- libraries if there were any, so that the linker+ -- can resolve dependencies when it loads this+ -- library.+ ldInputs =+ concatMap+ (\(lp, l) ->+ [ Option ("-L" ++ lp)+ , Option "-Xlinker"+ , Option "-rpath"+ , Option "-Xlinker"+ , Option lp+ , Option ("-l" ++ l)+ ])+ (temp_sos pls)+ ++ concatMap+ (\lp ->+ [ Option ("-L" ++ lp)+ , Option "-Xlinker"+ , Option "-rpath"+ , Option "-Xlinker"+ , Option lp+ ])+ minus_big_ls+ -- See Note [-Xlinker -rpath vs -Wl,-rpath]+ ++ map (\l -> Option ("-l" ++ l)) minus_ls,+ -- Add -l options and -L options from dflags.+ --+ -- When running TH for a non-dynamic way, we still+ -- need to make -l flags to link against the dynamic+ -- libraries, so we need to add WayDyn to ways.+ --+ -- Even if we're e.g. profiling, we still want+ -- the vanilla dynamic libraries, so we set the+ -- ways / build tag to be just WayDyn.+ ways = [WayDyn],+ buildTag = mkBuildTag [WayDyn],+ outputFile = Just soFile+ }+ -- link all "loaded packages" so symbols in those can be resolved+ -- Note: We are loading packages with local scope, so to see the+ -- symbols in this link we must link all loaded packages again.+ linkDynLib dflags2 objs (pkgs_loaded pls)+ consIORef (filesToNotIntermediateClean dflags) soFile+ m <- loadDLL hsc_env soFile+ case m of+ Nothing -> return pls { temp_sos = (libPath, libName) : temp_sos pls }+ Just err -> panic ("Loading temp shared object failed: " ++ err)++rmDupLinkables :: [Linkable] -- Already loaded+ -> [Linkable] -- New linkables+ -> ([Linkable], -- New loaded set (including new ones)+ [Linkable]) -- New linkables (excluding dups)+rmDupLinkables already ls+ = go already [] ls+ where+ go already extras [] = (already, extras)+ go already extras (l:ls)+ | linkableInSet l already = go already extras ls+ | otherwise = go (l:already) (l:extras) ls++{- **********************************************************************++ The byte-code linker++ ********************************************************************* -}+++dynLinkBCOs :: HscEnv -> PersistentLinkerState -> [Linkable]+ -> IO PersistentLinkerState+dynLinkBCOs hsc_env pls bcos = do++ let (bcos_loaded', new_bcos) = rmDupLinkables (bcos_loaded pls) bcos+ pls1 = pls { bcos_loaded = bcos_loaded' }+ unlinkeds :: [Unlinked]+ unlinkeds = concatMap linkableUnlinked new_bcos++ cbcs :: [CompiledByteCode]+ cbcs = map byteCodeOfObject unlinkeds+++ ies = map bc_itbls cbcs+ gce = closure_env pls+ final_ie = foldr plusNameEnv (itbl_env pls) ies++ names_and_refs <- linkSomeBCOs hsc_env final_ie gce cbcs++ -- We only want to add the external ones to the ClosureEnv+ let (to_add, to_drop) = partition (isExternalName.fst) names_and_refs++ -- Immediately release any HValueRefs we're not going to add+ freeHValueRefs hsc_env (map snd to_drop)+ -- Wrap finalizers on the ones we want to keep+ new_binds <- makeForeignNamedHValueRefs hsc_env to_add++ return pls1 { closure_env = extendClosureEnv gce new_binds,+ itbl_env = final_ie }++-- Link a bunch of BCOs and return references to their values+linkSomeBCOs :: HscEnv+ -> ItblEnv+ -> ClosureEnv+ -> [CompiledByteCode]+ -> IO [(Name,HValueRef)]+ -- The returned HValueRefs are associated 1-1 with+ -- the incoming unlinked BCOs. Each gives the+ -- value of the corresponding unlinked BCO++linkSomeBCOs hsc_env ie ce mods = foldr fun do_link mods []+ where+ fun CompiledByteCode{..} inner accum =+ case bc_breaks of+ Nothing -> inner ((panic "linkSomeBCOs: no break array", bc_bcos) : accum)+ Just mb -> withForeignRef (modBreaks_flags mb) $ \breakarray ->+ inner ((breakarray, bc_bcos) : accum)++ do_link [] = return []+ do_link mods = do+ let flat = [ (breakarray, bco) | (breakarray, bcos) <- mods, bco <- bcos ]+ names = map (unlinkedBCOName . snd) flat+ bco_ix = mkNameEnv (zip names [0..])+ resolved <- sequence [ linkBCO hsc_env ie ce bco_ix breakarray bco+ | (breakarray, bco) <- flat ]+ hvrefs <- createBCOs hsc_env resolved+ return (zip names hvrefs)++-- | Useful to apply to the result of 'linkSomeBCOs'+makeForeignNamedHValueRefs+ :: HscEnv -> [(Name,HValueRef)] -> IO [(Name,ForeignHValue)]+makeForeignNamedHValueRefs hsc_env bindings =+ mapM (\(n, hvref) -> (n,) <$> mkFinalizedHValue hsc_env hvref) bindings++{- **********************************************************************++ Unload some object modules++ ********************************************************************* -}++-- ---------------------------------------------------------------------------+-- | Unloading old objects ready for a new compilation sweep.+--+-- The compilation manager provides us with a list of linkables that it+-- considers \"stable\", i.e. won't be recompiled this time around. For+-- each of the modules current linked in memory,+--+-- * if the linkable is stable (and it's the same one -- the user may have+-- recompiled the module on the side), we keep it,+--+-- * otherwise, we unload it.+--+-- * we also implicitly unload all temporary bindings at this point.+--+unload :: HscEnv+ -> [Linkable] -- ^ The linkables to *keep*.+ -> IO ()+unload hsc_env linkables+ = mask_ $ do -- mask, so we're safe from Ctrl-C in here++ -- Initialise the linker (if it's not been done already)+ initDynLinker hsc_env++ new_pls+ <- modifyPLS $ \pls -> do+ pls1 <- unload_wkr hsc_env linkables pls+ return (pls1, pls1)++ let dflags = hsc_dflags hsc_env+ debugTraceMsg dflags 3 $+ text "unload: retaining objs" <+> ppr (objs_loaded new_pls)+ debugTraceMsg dflags 3 $+ text "unload: retaining bcos" <+> ppr (bcos_loaded new_pls)+ return ()++unload_wkr :: HscEnv+ -> [Linkable] -- stable linkables+ -> PersistentLinkerState+ -> IO PersistentLinkerState+-- Does the core unload business+-- (the wrapper blocks exceptions and deals with the PLS get and put)++unload_wkr hsc_env keep_linkables pls = do+ let (objs_to_keep, bcos_to_keep) = partition isObjectLinkable keep_linkables++ discard keep l = not (linkableInSet l keep)++ (objs_to_unload, remaining_objs_loaded) =+ partition (discard objs_to_keep) (objs_loaded pls)+ (bcos_to_unload, remaining_bcos_loaded) =+ partition (discard bcos_to_keep) (bcos_loaded pls)++ mapM_ unloadObjs objs_to_unload+ mapM_ unloadObjs bcos_to_unload++ -- If we unloaded any object files at all, we need to purge the cache+ -- of lookupSymbol results.+ when (not (null (objs_to_unload +++ filter (not . null . linkableObjs) bcos_to_unload))) $+ purgeLookupSymbolCache hsc_env++ let bcos_retained = map linkableModule remaining_bcos_loaded++ -- Note that we want to remove all *local*+ -- (i.e. non-isExternal) names too (these are the+ -- temporary bindings from the command line).+ keep_name (n,_) = isExternalName n &&+ nameModule n `elem` bcos_retained++ itbl_env' = filterNameEnv keep_name (itbl_env pls)+ closure_env' = filterNameEnv keep_name (closure_env pls)++ new_pls = pls { itbl_env = itbl_env',+ closure_env = closure_env',+ bcos_loaded = remaining_bcos_loaded,+ objs_loaded = remaining_objs_loaded }++ return new_pls+ where+ unloadObjs :: Linkable -> IO ()+ unloadObjs lnk+ | dynamicGhc = return ()+ -- We don't do any cleanup when linking objects with the+ -- dynamic linker. Doing so introduces extra complexity for+ -- not much benefit.+ | otherwise+ = mapM_ (unloadObj hsc_env) [f | DotO f <- linkableUnlinked lnk]+ -- The components of a BCO linkable may contain+ -- dot-o files. Which is very confusing.+ --+ -- But the BCO parts can be unlinked just by+ -- letting go of them (plus of course depopulating+ -- the symbol table which is done in the main body)++{- **********************************************************************++ Loading packages++ ********************************************************************* -}++data LibrarySpec+ = Object FilePath -- Full path name of a .o file, including trailing .o+ -- For dynamic objects only, try to find the object+ -- file in all the directories specified in+ -- v_Library_paths before giving up.++ | Archive FilePath -- Full path name of a .a file, including trailing .a++ | DLL String -- "Unadorned" name of a .DLL/.so+ -- e.g. On unix "qt" denotes "libqt.so"+ -- On Windows "burble" denotes "burble.DLL" or "libburble.dll"+ -- loadDLL is platform-specific and adds the lib/.so/.DLL+ -- suffixes platform-dependently++ | DLLPath FilePath -- Absolute or relative pathname to a dynamic library+ -- (ends with .dll or .so).++ | Framework String -- Only used for darwin, but does no harm++-- If this package is already part of the GHCi binary, we'll already+-- have the right DLLs for this package loaded, so don't try to+-- load them again.+--+-- But on Win32 we must load them 'again'; doing so is a harmless no-op+-- as far as the loader is concerned, but it does initialise the list+-- of DLL handles that rts/Linker.c maintains, and that in turn is+-- used by lookupSymbol. So we must call addDLL for each library+-- just to get the DLL handle into the list.+partOfGHCi :: [PackageName]+partOfGHCi+ | isWindowsHost || isDarwinHost = []+ | otherwise = map (PackageName . mkFastString)+ ["base", "template-haskell", "editline"]++showLS :: LibrarySpec -> String+showLS (Object nm) = "(static) " ++ nm+showLS (Archive nm) = "(static archive) " ++ nm+showLS (DLL nm) = "(dynamic) " ++ nm+showLS (DLLPath nm) = "(dynamic) " ++ nm+showLS (Framework nm) = "(framework) " ++ nm++-- TODO: Make this type more precise+type LinkerUnitId = InstalledUnitId++-- | Link exactly the specified packages, and their dependents (unless of+-- course they are already linked). The dependents are linked+-- automatically, and it doesn't matter what order you specify the input+-- packages.+--+linkPackages :: HscEnv -> [LinkerUnitId] -> IO ()+-- NOTE: in fact, since each module tracks all the packages it depends on,+-- we don't really need to use the package-config dependencies.+--+-- However we do need the package-config stuff (to find aux libs etc),+-- and following them lets us load libraries in the right order, which+-- perhaps makes the error message a bit more localised if we get a link+-- failure. So the dependency walking code is still here.++linkPackages hsc_env new_pkgs = do+ -- It's probably not safe to try to load packages concurrently, so we take+ -- a lock.+ initDynLinker hsc_env+ modifyPLS_ $ \pls -> do+ linkPackages' hsc_env new_pkgs pls++linkPackages' :: HscEnv -> [LinkerUnitId] -> PersistentLinkerState+ -> IO PersistentLinkerState+linkPackages' hsc_env new_pks pls = do+ pkgs' <- link (pkgs_loaded pls) new_pks+ return $! pls { pkgs_loaded = pkgs' }+ where+ dflags = hsc_dflags hsc_env++ link :: [LinkerUnitId] -> [LinkerUnitId] -> IO [LinkerUnitId]+ link pkgs new_pkgs =+ foldM link_one pkgs new_pkgs++ link_one pkgs new_pkg+ | new_pkg `elem` pkgs -- Already linked+ = return pkgs++ | Just pkg_cfg <- lookupInstalledPackage dflags new_pkg+ = do { -- Link dependents first+ pkgs' <- link pkgs (depends pkg_cfg)+ -- Now link the package itself+ ; linkPackage hsc_env pkg_cfg+ ; return (new_pkg : pkgs') }++ | otherwise+ = throwGhcExceptionIO (CmdLineError ("unknown package: " ++ unpackFS (installedUnitIdFS new_pkg)))+++linkPackage :: HscEnv -> PackageConfig -> IO ()+linkPackage hsc_env pkg+ = do+ let dflags = hsc_dflags hsc_env+ platform = targetPlatform dflags+ dirs | interpreterDynamic dflags = Packages.libraryDynDirs pkg+ | otherwise = Packages.libraryDirs pkg++ let hs_libs = Packages.hsLibraries pkg+ -- The FFI GHCi import lib isn't needed as+ -- compiler/ghci/Linker.hs + rts/Linker.c link the+ -- interpreted references to FFI to the compiled FFI.+ -- We therefore filter it out so that we don't get+ -- duplicate symbol errors.+ hs_libs' = filter ("HSffi" /=) hs_libs++ -- Because of slight differences between the GHC dynamic linker and+ -- the native system linker some packages have to link with a+ -- different list of libraries when using GHCi. Examples include: libs+ -- that are actually gnu ld scripts, and the possibility that the .a+ -- libs do not exactly match the .so/.dll equivalents. So if the+ -- package file provides an "extra-ghci-libraries" field then we use+ -- that instead of the "extra-libraries" field.+ extra_libs =+ (if null (Packages.extraGHCiLibraries pkg)+ then Packages.extraLibraries pkg+ else Packages.extraGHCiLibraries pkg)+ ++ [ lib | '-':'l':lib <- Packages.ldOptions pkg ]++ hs_classifieds <- mapM (locateLib hsc_env True dirs) hs_libs'+ extra_classifieds <- mapM (locateLib hsc_env False dirs) extra_libs+ let classifieds = hs_classifieds ++ extra_classifieds++ -- Complication: all the .so's must be loaded before any of the .o's.+ let known_dlls = [ dll | DLLPath dll <- classifieds ]+ dlls = [ dll | DLL dll <- classifieds ]+ objs = [ obj | Object obj <- classifieds ]+ archs = [ arch | Archive arch <- classifieds ]++ -- Add directories to library search paths+ let dll_paths = map takeDirectory known_dlls+ all_paths = nub $ map normalise $ dll_paths ++ dirs+ pathCache <- mapM (addLibrarySearchPath hsc_env) all_paths++ maybePutStr dflags+ ("Loading package " ++ sourcePackageIdString pkg ++ " ... ")++ -- See comments with partOfGHCi+ when (packageName pkg `notElem` partOfGHCi) $ do+ loadFrameworks hsc_env platform pkg+ mapM_ (load_dyn hsc_env)+ (known_dlls ++ map (mkSOName platform) dlls)++ -- After loading all the DLLs, we can load the static objects.+ -- Ordering isn't important here, because we do one final link+ -- step to resolve everything.+ mapM_ (loadObj hsc_env) objs+ mapM_ (loadArchive hsc_env) archs++ maybePutStr dflags "linking ... "+ ok <- resolveObjs hsc_env++ -- DLLs are loaded, reset the search paths+ -- Import libraries will be loaded via loadArchive so only+ -- reset the DLL search path after all archives are loaded+ -- as well.+ mapM_ (removeLibrarySearchPath hsc_env) $ reverse pathCache++ if succeeded ok+ then maybePutStrLn dflags "done."+ else let errmsg = "unable to load package `"+ ++ sourcePackageIdString pkg ++ "'"+ in throwGhcExceptionIO (InstallationError errmsg)++-- we have already searched the filesystem; the strings passed to load_dyn+-- can be passed directly to loadDLL. They are either fully-qualified+-- ("/usr/lib/libfoo.so"), or unqualified ("libfoo.so"). In the latter case,+-- loadDLL is going to search the system paths to find the library.+--+load_dyn :: HscEnv -> FilePath -> IO ()+load_dyn hsc_env dll = do+ r <- loadDLL hsc_env dll+ case r of+ Nothing -> return ()+ Just err -> throwGhcExceptionIO (CmdLineError ("can't load .so/.DLL for: "+ ++ dll ++ " (" ++ err ++ ")" ))++loadFrameworks :: HscEnv -> Platform -> PackageConfig -> IO ()+loadFrameworks hsc_env platform pkg+ = when (platformUsesFrameworks platform) $ mapM_ load frameworks+ where+ fw_dirs = Packages.frameworkDirs pkg+ frameworks = Packages.frameworks pkg++ load fw = do r <- loadFramework hsc_env fw_dirs fw+ case r of+ Nothing -> return ()+ Just err -> throwGhcExceptionIO (CmdLineError ("can't load framework: "+ ++ fw ++ " (" ++ err ++ ")" ))++-- Try to find an object file for a given library in the given paths.+-- If it isn't present, we assume that addDLL in the RTS can find it,+-- which generally means that it should be a dynamic library in the+-- standard system search path.+-- For GHCi we tend to prefer dynamic libraries over static ones as+-- they are easier to load and manage, have less overhead.+locateLib :: HscEnv -> Bool -> [FilePath] -> String -> IO LibrarySpec+locateLib hsc_env is_hs dirs lib+ | not is_hs+ -- For non-Haskell libraries (e.g. gmp, iconv):+ -- first look in library-dirs for a dynamic library (libfoo.so)+ -- then look in library-dirs for a static library (libfoo.a)+ -- then look in library-dirs and inplace GCC for a dynamic library (libfoo.so)+ -- then check for system dynamic libraries (e.g. kernel32.dll on windows)+ -- then try looking for import libraries on Windows (.dll.a, .lib)+ -- then try "gcc --print-file-name" to search gcc's search path+ -- then look in library-dirs and inplace GCC for a static library (libfoo.a)+ -- for a dynamic library (#5289)+ -- otherwise, assume loadDLL can find it+ --+ = findDll `orElse`+ findSysDll `orElse`+ tryImpLib `orElse`+ tryGcc `orElse`+ findArchive `orElse`+ assumeDll++ | loading_dynamic_hs_libs -- search for .so libraries first.+ = findHSDll `orElse`+ findDynObject `orElse`+ assumeDll++ | loading_profiled_hs_libs -- only a libHSfoo_p.a archive will do.+ = findArchive `orElse`+ assumeDll++ | otherwise+ -- HSfoo.o is the best, but only works for the normal way+ -- libHSfoo.a is the backup option.+ = findObject `orElse`+ findArchive `orElse`+ assumeDll++ where+ dflags = hsc_dflags hsc_env++ obj_file = lib <.> "o"+ dyn_obj_file = lib <.> "dyn_o"+ arch_files = [ "lib" ++ lib ++ lib_tag <.> "a"+ , lib <.> "a" -- native code has no lib_tag+ ]+ lib_tag = if is_hs && loading_profiled_hs_libs then "_p" else ""++ loading_profiled_hs_libs = interpreterProfiled dflags+ loading_dynamic_hs_libs = interpreterDynamic dflags++ import_libs = [ lib <.> "lib" , "lib" ++ lib <.> "lib"+ , "lib" ++ lib <.> "dll.a", lib <.> "dll.a"+ ]++ hs_dyn_lib_name = lib ++ '-':programName dflags ++ projectVersion dflags+ hs_dyn_lib_file = mkHsSOName platform hs_dyn_lib_name++ so_name = mkSOName platform lib+ lib_so_name = "lib" ++ so_name+ dyn_lib_file = case (arch, os) of+ (ArchX86_64, OSSolaris2) -> "64" </> so_name+ _ -> so_name++ findObject = liftM (fmap Object) $ findFile dirs obj_file+ findDynObject = liftM (fmap Object) $ findFile dirs dyn_obj_file+ findArchive = let local name = liftM (fmap Archive) $ findFile dirs name+ linked name = liftM (fmap Archive) $ searchForLibUsingGcc dflags name dirs+ check name = apply [local name, linked name]+ in apply (map check arch_files)+ findHSDll = liftM (fmap DLLPath) $ findFile dirs hs_dyn_lib_file+ findDll = liftM (fmap DLLPath) $ findFile dirs dyn_lib_file+ findSysDll = fmap (fmap $ DLL . dropExtension . takeFileName) $ findSystemLibrary hsc_env so_name+ tryGcc = let short = liftM (fmap DLLPath) $ searchForLibUsingGcc dflags so_name dirs+ full = liftM (fmap DLLPath) $ searchForLibUsingGcc dflags lib_so_name dirs+ in liftM2 (<|>) short full+ tryImpLib = case os of+ OSMinGW32 -> let check name = liftM (fmap Archive) $ searchForLibUsingGcc dflags name dirs+ in apply (map check import_libs)+ _ -> return Nothing++ assumeDll = return (DLL lib)+ infixr `orElse`+ f `orElse` g = f >>= maybe g return++ apply [] = return Nothing+ apply (x:xs) = do x' <- x+ if isJust x'+ then return x'+ else apply xs++ platform = targetPlatform dflags+ arch = platformArch platform+ os = platformOS platform++searchForLibUsingGcc :: DynFlags -> String -> [FilePath] -> IO (Maybe FilePath)+searchForLibUsingGcc dflags so dirs = do+ -- GCC does not seem to extend the library search path (using -L) when using+ -- --print-file-name. So instead pass it a new base location.+ str <- askLd dflags (map (FileOption "-B") dirs+ ++ [Option "--print-file-name", Option so])+ let file = case lines str of+ [] -> ""+ l:_ -> l+ if (file == so)+ then return Nothing+ else return (Just file)++-- ----------------------------------------------------------------------------+-- Loading a dynamic library (dlopen()-ish on Unix, LoadLibrary-ish on Win32)++-- Darwin / MacOS X only: load a framework+-- a framework is a dynamic library packaged inside a directory of the same+-- name. They are searched for in different paths than normal libraries.+loadFramework :: HscEnv -> [FilePath] -> FilePath -> IO (Maybe String)+loadFramework hsc_env extraPaths rootname+ = do { either_dir <- tryIO getHomeDirectory+ ; let homeFrameworkPath = case either_dir of+ Left _ -> []+ Right dir -> [dir </> "Library/Frameworks"]+ ps = extraPaths ++ homeFrameworkPath ++ defaultFrameworkPaths+ ; mb_fwk <- findFile ps fwk_file+ ; case mb_fwk of+ Just fwk_path -> loadDLL hsc_env fwk_path+ Nothing -> return (Just "not found") }+ -- Tried all our known library paths, but dlopen()+ -- has no built-in paths for frameworks: give up+ where+ fwk_file = rootname <.> "framework" </> rootname+ -- sorry for the hardcoded paths, I hope they won't change anytime soon:+ defaultFrameworkPaths = ["/Library/Frameworks", "/System/Library/Frameworks"]++{- **********************************************************************++ Helper functions++ ********************************************************************* -}++maybePutStr :: DynFlags -> String -> IO ()+maybePutStr dflags s+ = when (verbosity dflags > 1) $+ putLogMsg dflags+ NoReason+ SevInteractive+ noSrcSpan+ (defaultUserStyle dflags)+ (text s)++maybePutStrLn :: DynFlags -> String -> IO ()+maybePutStrLn dflags s = maybePutStr dflags (s ++ "\n")
+ ghci/RtClosureInspect.hs view
@@ -0,0 +1,1281 @@+{-# LANGUAGE BangPatterns, CPP, ScopedTypeVariables, MagicHash, UnboxedTuples #-}++-----------------------------------------------------------------------------+--+-- GHC Interactive support for inspecting arbitrary closures at runtime+--+-- Pepe Iborra (supported by Google SoC) 2006+--+-----------------------------------------------------------------------------+module RtClosureInspect(+ cvObtainTerm, -- :: HscEnv -> Int -> Bool -> Maybe Type -> HValue -> IO Term+ cvReconstructType,+ improveRTTIType,++ Term(..),+ isTerm, isSuspension, isPrim, isFun, isFunLike, isNewtypeWrap,+ isFullyEvaluated, isFullyEvaluatedTerm,+ termType, mapTermType, termTyCoVars,+ foldTerm, TermFold(..), foldTermM, TermFoldM(..), idTermFold,+ pprTerm, cPprTerm, cPprTermBase, CustomTermPrinter,++-- unsafeDeepSeq,++ Closure(..), getClosureData, ClosureType(..), isConstr, isIndirection+ ) where++#include "HsVersions.h"++import DebuggerUtils+import GHCi.RemoteTypes ( HValue )+import qualified GHCi.InfoTable as InfoTable+import GHCi.InfoTable (StgInfoTable, peekItbl)+import HscTypes++import DataCon+import Type+import RepType+import qualified Unify as U+import Var+import TcRnMonad+import TcType+import TcMType+import TcHsSyn ( zonkTcTypeToType, mkEmptyZonkEnv )+import TcUnify+import TcEnv++import TyCon+import Name+import Util+import VarSet+import BasicTypes ( Boxity(..) )+import TysPrim+import PrelNames+import TysWiredIn+import DynFlags+import Outputable as Ppr+import GHC.Arr ( Array(..) )+import GHC.Exts+import GHC.IO ( IO(..) )++import Control.Monad+import Data.Maybe+import Data.Array.Base+import Data.Ix+import Data.List+import qualified Data.Sequence as Seq+import Data.Sequence (viewl, ViewL(..))+import Foreign+import System.IO.Unsafe++---------------------------------------------+-- * A representation of semi evaluated Terms+---------------------------------------------++data Term = Term { ty :: RttiType+ , dc :: Either String DataCon+ -- Carries a text representation if the datacon is+ -- not exported by the .hi file, which is the case+ -- for private constructors in -O0 compiled libraries+ , val :: HValue+ , subTerms :: [Term] }++ | Prim { ty :: RttiType+ , value :: [Word] }++ | Suspension { ctype :: ClosureType+ , ty :: RttiType+ , val :: HValue+ , bound_to :: Maybe Name -- Useful for printing+ }+ | NewtypeWrap{ -- At runtime there are no newtypes, and hence no+ -- newtype constructors. A NewtypeWrap is just a+ -- made-up tag saying "heads up, there used to be+ -- a newtype constructor here".+ ty :: RttiType+ , dc :: Either String DataCon+ , wrapped_term :: Term }+ | RefWrap { -- The contents of a reference+ ty :: RttiType+ , wrapped_term :: Term }++isTerm, isSuspension, isPrim, isFun, isFunLike, isNewtypeWrap :: Term -> Bool+isTerm Term{} = True+isTerm _ = False+isSuspension Suspension{} = True+isSuspension _ = False+isPrim Prim{} = True+isPrim _ = False+isNewtypeWrap NewtypeWrap{} = True+isNewtypeWrap _ = False++isFun Suspension{ctype=Fun} = True+isFun _ = False++isFunLike s@Suspension{ty=ty} = isFun s || isFunTy ty+isFunLike _ = False++termType :: Term -> RttiType+termType t = ty t++isFullyEvaluatedTerm :: Term -> Bool+isFullyEvaluatedTerm Term {subTerms=tt} = all isFullyEvaluatedTerm tt+isFullyEvaluatedTerm Prim {} = True+isFullyEvaluatedTerm NewtypeWrap{wrapped_term=t} = isFullyEvaluatedTerm t+isFullyEvaluatedTerm RefWrap{wrapped_term=t} = isFullyEvaluatedTerm t+isFullyEvaluatedTerm _ = False++instance Outputable (Term) where+ ppr t | Just doc <- cPprTerm cPprTermBase t = doc+ | otherwise = panic "Outputable Term instance"++-------------------------------------------------------------------------+-- Runtime Closure Datatype and functions for retrieving closure related stuff+-------------------------------------------------------------------------+data ClosureType = Constr+ | Fun+ | Thunk Int+ | ThunkSelector+ | Blackhole+ | AP+ | PAP+ | Indirection Int+ | MutVar Int+ | MVar Int+ | Other Int+ deriving (Show, Eq)++data Closure = Closure { tipe :: ClosureType+ , infoPtr :: Ptr ()+ , infoTable :: StgInfoTable+ , ptrs :: Array Int HValue+ , nonPtrs :: [Word]+ }++instance Outputable ClosureType where+ ppr = text . show++#include "rts/storage/ClosureTypes.h"++aP_CODE, pAP_CODE :: Int+aP_CODE = AP+pAP_CODE = PAP+#undef AP+#undef PAP++getClosureData :: DynFlags -> a -> IO Closure+getClosureData dflags a =+ case unpackClosure# a of+ (# iptr, ptrs, nptrs #) -> do+ let iptr0 = Ptr iptr+ let iptr1+ | ghciTablesNextToCode = iptr0+ | otherwise =+ -- the info pointer we get back from unpackClosure#+ -- is to the beginning of the standard info table,+ -- but the Storable instance for info tables takes+ -- into account the extra entry pointer when+ -- !ghciTablesNextToCode, so we must adjust here:+ iptr0 `plusPtr` negate (wORD_SIZE dflags)+ itbl <- peekItbl iptr1+ let tipe = readCType (InfoTable.tipe itbl)+ elems = fromIntegral (InfoTable.ptrs itbl)+ ptrsList = Array 0 (elems - 1) elems ptrs+ nptrs_data = [W# (indexWordArray# nptrs i)+ | I# i <- [0.. fromIntegral (InfoTable.nptrs itbl)-1] ]+ ASSERT(elems >= 0) return ()+ ptrsList `seq`+ return (Closure tipe iptr0 itbl ptrsList nptrs_data)++readCType :: Integral a => a -> ClosureType+readCType i+ | i >= CONSTR && i <= CONSTR_NOCAF = Constr+ | i >= FUN && i <= FUN_STATIC = Fun+ | i >= THUNK && i < THUNK_SELECTOR = Thunk i'+ | i == THUNK_SELECTOR = ThunkSelector+ | i == BLACKHOLE = Blackhole+ | i >= IND && i <= IND_STATIC = Indirection i'+ | i' == aP_CODE = AP+ | i == AP_STACK = AP+ | i' == pAP_CODE = PAP+ | i == MUT_VAR_CLEAN || i == MUT_VAR_DIRTY= MutVar i'+ | i == MVAR_CLEAN || i == MVAR_DIRTY = MVar i'+ | otherwise = Other i'+ where i' = fromIntegral i++isConstr, isIndirection, isThunk :: ClosureType -> Bool+isConstr Constr = True+isConstr _ = False++isIndirection (Indirection _) = True+isIndirection _ = False++isThunk (Thunk _) = True+isThunk ThunkSelector = True+isThunk AP = True+isThunk _ = False++isFullyEvaluated :: DynFlags -> a -> IO Bool+isFullyEvaluated dflags a = do+ closure <- getClosureData dflags a+ case tipe closure of+ Constr -> do are_subs_evaluated <- amapM (isFullyEvaluated dflags) (ptrs closure)+ return$ and are_subs_evaluated+ _ -> return False+ where amapM f = sequence . amap' f++-- TODO: Fix it. Probably the otherwise case is failing, trace/debug it+{-+unsafeDeepSeq :: a -> b -> b+unsafeDeepSeq = unsafeDeepSeq1 2+ where unsafeDeepSeq1 0 a b = seq a $! b+ unsafeDeepSeq1 i a b -- 1st case avoids infinite loops for non reducible thunks+ | not (isConstr tipe) = seq a $! unsafeDeepSeq1 (i-1) a b+ -- | unsafePerformIO (isFullyEvaluated a) = b+ | otherwise = case unsafePerformIO (getClosureData a) of+ closure -> foldl' (flip unsafeDeepSeq) b (ptrs closure)+ where tipe = unsafePerformIO (getClosureType a)+-}++-----------------------------------+-- * Traversals for Terms+-----------------------------------+type TermProcessor a b = RttiType -> Either String DataCon -> HValue -> [a] -> b++data TermFold a = TermFold { fTerm :: TermProcessor a a+ , fPrim :: RttiType -> [Word] -> a+ , fSuspension :: ClosureType -> RttiType -> HValue+ -> Maybe Name -> a+ , fNewtypeWrap :: RttiType -> Either String DataCon+ -> a -> a+ , fRefWrap :: RttiType -> a -> a+ }+++data TermFoldM m a =+ TermFoldM {fTermM :: TermProcessor a (m a)+ , fPrimM :: RttiType -> [Word] -> m a+ , fSuspensionM :: ClosureType -> RttiType -> HValue+ -> Maybe Name -> m a+ , fNewtypeWrapM :: RttiType -> Either String DataCon+ -> a -> m a+ , fRefWrapM :: RttiType -> a -> m a+ }++foldTerm :: TermFold a -> Term -> a+foldTerm tf (Term ty dc v tt) = fTerm tf ty dc v (map (foldTerm tf) tt)+foldTerm tf (Prim ty v ) = fPrim tf ty v+foldTerm tf (Suspension ct ty v b) = fSuspension tf ct ty v b+foldTerm tf (NewtypeWrap ty dc t) = fNewtypeWrap tf ty dc (foldTerm tf t)+foldTerm tf (RefWrap ty t) = fRefWrap tf ty (foldTerm tf t)+++foldTermM :: Monad m => TermFoldM m a -> Term -> m a+foldTermM tf (Term ty dc v tt) = mapM (foldTermM tf) tt >>= fTermM tf ty dc v+foldTermM tf (Prim ty v ) = fPrimM tf ty v+foldTermM tf (Suspension ct ty v b) = fSuspensionM tf ct ty v b+foldTermM tf (NewtypeWrap ty dc t) = foldTermM tf t >>= fNewtypeWrapM tf ty dc+foldTermM tf (RefWrap ty t) = foldTermM tf t >>= fRefWrapM tf ty++idTermFold :: TermFold Term+idTermFold = TermFold {+ fTerm = Term,+ fPrim = Prim,+ fSuspension = Suspension,+ fNewtypeWrap = NewtypeWrap,+ fRefWrap = RefWrap+ }++mapTermType :: (RttiType -> Type) -> Term -> Term+mapTermType f = foldTerm idTermFold {+ fTerm = \ty dc hval tt -> Term (f ty) dc hval tt,+ fSuspension = \ct ty hval n ->+ Suspension ct (f ty) hval n,+ fNewtypeWrap= \ty dc t -> NewtypeWrap (f ty) dc t,+ fRefWrap = \ty t -> RefWrap (f ty) t}++mapTermTypeM :: Monad m => (RttiType -> m Type) -> Term -> m Term+mapTermTypeM f = foldTermM TermFoldM {+ fTermM = \ty dc hval tt -> f ty >>= \ty' -> return $ Term ty' dc hval tt,+ fPrimM = (return.) . Prim,+ fSuspensionM = \ct ty hval n ->+ f ty >>= \ty' -> return $ Suspension ct ty' hval n,+ fNewtypeWrapM= \ty dc t -> f ty >>= \ty' -> return $ NewtypeWrap ty' dc t,+ fRefWrapM = \ty t -> f ty >>= \ty' -> return $ RefWrap ty' t}++termTyCoVars :: Term -> TyCoVarSet+termTyCoVars = foldTerm TermFold {+ fTerm = \ty _ _ tt ->+ tyCoVarsOfType ty `unionVarSet` concatVarEnv tt,+ fSuspension = \_ ty _ _ -> tyCoVarsOfType ty,+ fPrim = \ _ _ -> emptyVarSet,+ fNewtypeWrap= \ty _ t -> tyCoVarsOfType ty `unionVarSet` t,+ fRefWrap = \ty t -> tyCoVarsOfType ty `unionVarSet` t}+ where concatVarEnv = foldr unionVarSet emptyVarSet++----------------------------------+-- Pretty printing of terms+----------------------------------++type Precedence = Int+type TermPrinter = Precedence -> Term -> SDoc+type TermPrinterM m = Precedence -> Term -> m SDoc++app_prec,cons_prec, max_prec ::Int+max_prec = 10+app_prec = max_prec+cons_prec = 5 -- TODO Extract this info from GHC itself++pprTerm :: TermPrinter -> TermPrinter+pprTerm y p t | Just doc <- pprTermM (\p -> Just . y p) p t = doc+pprTerm _ _ _ = panic "pprTerm"++pprTermM, ppr_termM, pprNewtypeWrap :: Monad m => TermPrinterM m -> TermPrinterM m+pprTermM y p t = pprDeeper `liftM` ppr_termM y p t++ppr_termM y p Term{dc=Left dc_tag, subTerms=tt} = do+ tt_docs <- mapM (y app_prec) tt+ return $ cparen (not (null tt) && p >= app_prec)+ (text dc_tag <+> pprDeeperList fsep tt_docs)++ppr_termM y p Term{dc=Right dc, subTerms=tt} = do+{- | dataConIsInfix dc, (t1:t2:tt') <- tt --TODO fixity+ = parens (ppr_term1 True t1 <+> ppr dc <+> ppr_term1 True ppr t2)+ <+> hsep (map (ppr_term1 True) tt)+-} -- TODO Printing infix constructors properly+ tt_docs' <- mapM (y app_prec) tt+ return $ sdocWithPprDebug $ \dbg ->+ -- Don't show the dictionary arguments to+ -- constructors unless -dppr-debug is on+ let tt_docs = if dbg+ then tt_docs'+ else dropList (dataConTheta dc) tt_docs'+ in if null tt_docs+ then ppr dc+ else cparen (p >= app_prec) $+ sep [ppr dc, nest 2 (pprDeeperList fsep tt_docs)]++ppr_termM y p t@NewtypeWrap{} = pprNewtypeWrap y p t+ppr_termM y p RefWrap{wrapped_term=t} = do+ contents <- y app_prec t+ return$ cparen (p >= app_prec) (text "GHC.Prim.MutVar#" <+> contents)+ -- The constructor name is wired in here ^^^ for the sake of simplicity.+ -- I don't think mutvars are going to change in a near future.+ -- In any case this is solely a presentation matter: MutVar# is+ -- a datatype with no constructors, implemented by the RTS+ -- (hence there is no way to obtain a datacon and print it).+ppr_termM _ _ t = ppr_termM1 t+++ppr_termM1 :: Monad m => Term -> m SDoc+ppr_termM1 Prim{value=words, ty=ty} =+ return $ repPrim (tyConAppTyCon ty) words+ppr_termM1 Suspension{ty=ty, bound_to=Nothing} =+ return (char '_' <+> ifPprDebug (text "::" <> ppr ty))+ppr_termM1 Suspension{ty=ty, bound_to=Just n}+-- | Just _ <- splitFunTy_maybe ty = return$ ptext (sLit("<function>")+ | otherwise = return$ parens$ ppr n <> text "::" <> ppr ty+ppr_termM1 Term{} = panic "ppr_termM1 - Term"+ppr_termM1 RefWrap{} = panic "ppr_termM1 - RefWrap"+ppr_termM1 NewtypeWrap{} = panic "ppr_termM1 - NewtypeWrap"++pprNewtypeWrap y p NewtypeWrap{ty=ty, wrapped_term=t}+ | Just (tc,_) <- tcSplitTyConApp_maybe ty+ , ASSERT(isNewTyCon tc) True+ , Just new_dc <- tyConSingleDataCon_maybe tc = do+ real_term <- y max_prec t+ return $ cparen (p >= app_prec) (ppr new_dc <+> real_term)+pprNewtypeWrap _ _ _ = panic "pprNewtypeWrap"++-------------------------------------------------------+-- Custom Term Pretty Printers+-------------------------------------------------------++-- We can want to customize the representation of a+-- term depending on its type.+-- However, note that custom printers have to work with+-- type representations, instead of directly with types.+-- We cannot use type classes here, unless we employ some+-- typerep trickery (e.g. Weirich's RepLib tricks),+-- which I didn't. Therefore, this code replicates a lot+-- of what type classes provide for free.++type CustomTermPrinter m = TermPrinterM m+ -> [Precedence -> Term -> (m (Maybe SDoc))]++-- | Takes a list of custom printers with a explicit recursion knot and a term,+-- and returns the output of the first successful printer, or the default printer+cPprTerm :: Monad m => CustomTermPrinter m -> Term -> m SDoc+cPprTerm printers_ = go 0 where+ printers = printers_ go+ go prec t = do+ let default_ = Just `liftM` pprTermM go prec t+ mb_customDocs = [pp prec t | pp <- printers] ++ [default_]+ Just doc <- firstJustM mb_customDocs+ return$ cparen (prec>app_prec+1) doc++ firstJustM (mb:mbs) = mb >>= maybe (firstJustM mbs) (return . Just)+ firstJustM [] = return Nothing++-- Default set of custom printers. Note that the recursion knot is explicit+cPprTermBase :: forall m. Monad m => CustomTermPrinter m+cPprTermBase y =+ [ ifTerm (isTupleTy.ty) (\_p -> liftM (parens . hcat . punctuate comma)+ . mapM (y (-1))+ . subTerms)+ , ifTerm (\t -> isTyCon listTyCon (ty t) && subTerms t `lengthIs` 2)+ ppr_list+ , ifTerm (isTyCon intTyCon . ty) ppr_int+ , ifTerm (isTyCon charTyCon . ty) ppr_char+ , ifTerm (isTyCon floatTyCon . ty) ppr_float+ , ifTerm (isTyCon doubleTyCon . ty) ppr_double+ , ifTerm (isIntegerTy . ty) ppr_integer+ ]+ where+ ifTerm :: (Term -> Bool)+ -> (Precedence -> Term -> m SDoc)+ -> Precedence -> Term -> m (Maybe SDoc)+ ifTerm pred f prec t@Term{}+ | pred t = Just `liftM` f prec t+ ifTerm _ _ _ _ = return Nothing++ isTupleTy ty = fromMaybe False $ do+ (tc,_) <- tcSplitTyConApp_maybe ty+ return (isBoxedTupleTyCon tc)++ isTyCon a_tc ty = fromMaybe False $ do+ (tc,_) <- tcSplitTyConApp_maybe ty+ return (a_tc == tc)++ isIntegerTy ty = fromMaybe False $ do+ (tc,_) <- tcSplitTyConApp_maybe ty+ return (tyConName tc == integerTyConName)++ ppr_int, ppr_char, ppr_float, ppr_double, ppr_integer+ :: Precedence -> Term -> m SDoc+ ppr_int _ v = return (Ppr.int (unsafeCoerce# (val v)))+ ppr_char _ v = return (Ppr.char '\'' <> Ppr.char (unsafeCoerce# (val v)) <> Ppr.char '\'')+ ppr_float _ v = return (Ppr.float (unsafeCoerce# (val v)))+ ppr_double _ v = return (Ppr.double (unsafeCoerce# (val v)))+ ppr_integer _ v = return (Ppr.integer (unsafeCoerce# (val v)))++ --Note pprinting of list terms is not lazy+ ppr_list :: Precedence -> Term -> m SDoc+ ppr_list p (Term{subTerms=[h,t]}) = do+ let elems = h : getListTerms t+ isConsLast = not (termType (last elems) `eqType` termType h)+ is_string = all (isCharTy . ty) elems++ print_elems <- mapM (y cons_prec) elems+ if is_string+ then return (Ppr.doubleQuotes (Ppr.text (unsafeCoerce# (map val elems))))+ else if isConsLast+ then return $ cparen (p >= cons_prec)+ $ pprDeeperList fsep+ $ punctuate (space<>colon) print_elems+ else return $ brackets+ $ pprDeeperList fcat+ $ punctuate comma print_elems++ where getListTerms Term{subTerms=[h,t]} = h : getListTerms t+ getListTerms Term{subTerms=[]} = []+ getListTerms t@Suspension{} = [t]+ getListTerms t = pprPanic "getListTerms" (ppr t)+ ppr_list _ _ = panic "doList"+++repPrim :: TyCon -> [Word] -> SDoc+repPrim t = rep where+ rep x+ | t == charPrimTyCon = text $ show (build x :: Char)+ | t == intPrimTyCon = text $ show (build x :: Int)+ | t == wordPrimTyCon = text $ show (build x :: Word)+ | t == floatPrimTyCon = text $ show (build x :: Float)+ | t == doublePrimTyCon = text $ show (build x :: Double)+ | t == int32PrimTyCon = text $ show (build x :: Int32)+ | t == word32PrimTyCon = text $ show (build x :: Word32)+ | t == int64PrimTyCon = text $ show (build x :: Int64)+ | t == word64PrimTyCon = text $ show (build x :: Word64)+ | t == addrPrimTyCon = text $ show (nullPtr `plusPtr` build x)+ | t == stablePtrPrimTyCon = text "<stablePtr>"+ | t == stableNamePrimTyCon = text "<stableName>"+ | t == statePrimTyCon = text "<statethread>"+ | t == proxyPrimTyCon = text "<proxy>"+ | t == realWorldTyCon = text "<realworld>"+ | t == threadIdPrimTyCon = text "<ThreadId>"+ | t == weakPrimTyCon = text "<Weak>"+ | t == arrayPrimTyCon = text "<array>"+ | t == smallArrayPrimTyCon = text "<smallArray>"+ | t == byteArrayPrimTyCon = text "<bytearray>"+ | t == mutableArrayPrimTyCon = text "<mutableArray>"+ | t == smallMutableArrayPrimTyCon = text "<smallMutableArray>"+ | t == mutableByteArrayPrimTyCon = text "<mutableByteArray>"+ | t == mutVarPrimTyCon = text "<mutVar>"+ | t == mVarPrimTyCon = text "<mVar>"+ | t == tVarPrimTyCon = text "<tVar>"+ | otherwise = char '<' <> ppr t <> char '>'+ where build ww = unsafePerformIO $ withArray ww (peek . castPtr)+-- This ^^^ relies on the representation of Haskell heap values being+-- the same as in a C array.++-----------------------------------+-- Type Reconstruction+-----------------------------------+{-+Type Reconstruction is type inference done on heap closures.+The algorithm walks the heap generating a set of equations, which+are solved with syntactic unification.+A type reconstruction equation looks like:++ <datacon reptype> = <actual heap contents>++The full equation set is generated by traversing all the subterms, starting+from a given term.++The only difficult part is that newtypes are only found in the lhs of equations.+Right hand sides are missing them. We can either (a) drop them from the lhs, or+(b) reconstruct them in the rhs when possible.++The function congruenceNewtypes takes a shot at (b)+-}+++-- A (non-mutable) tau type containing+-- existentially quantified tyvars.+-- (since GHC type language currently does not support+-- existentials, we leave these variables unquantified)+type RttiType = Type++-- An incomplete type as stored in GHCi:+-- no polymorphism: no quantifiers & all tyvars are skolem.+type GhciType = Type+++-- The Type Reconstruction monad+--------------------------------+type TR a = TcM a++runTR :: HscEnv -> TR a -> IO a+runTR hsc_env thing = do+ mb_val <- runTR_maybe hsc_env thing+ case mb_val of+ Nothing -> error "unable to :print the term"+ Just x -> return x++runTR_maybe :: HscEnv -> TR a -> IO (Maybe a)+runTR_maybe hsc_env thing_inside+ = do { (_errs, res) <- initTcInteractive hsc_env thing_inside+ ; return res }++-- | Term Reconstruction trace+traceTR :: SDoc -> TR ()+traceTR = liftTcM . traceOptTcRn Opt_D_dump_rtti+++-- Semantically different to recoverM in TcRnMonad+-- recoverM retains the errors in the first action,+-- whereas recoverTc here does not+recoverTR :: TR a -> TR a -> TR a+recoverTR = tryTcDiscardingErrs++trIO :: IO a -> TR a+trIO = liftTcM . liftIO++liftTcM :: TcM a -> TR a+liftTcM = id++newVar :: Kind -> TR TcType+newVar = liftTcM . newFlexiTyVarTy++newOpenVar :: TR TcType+newOpenVar = liftTcM newOpenFlexiTyVarTy++instTyVars :: [TyVar] -> TR (TCvSubst, [TcTyVar])+-- Instantiate fresh mutable type variables from some TyVars+-- This function preserves the print-name, which helps error messages+instTyVars tvs+ = liftTcM $ fst <$> captureConstraints (newMetaTyVars tvs)++type RttiInstantiation = [(TcTyVar, TyVar)]+ -- Associates the typechecker-world meta type variables+ -- (which are mutable and may be refined), to their+ -- debugger-world RuntimeUnk counterparts.+ -- If the TcTyVar has not been refined by the runtime type+ -- elaboration, then we want to turn it back into the+ -- original RuntimeUnk++-- | Returns the instantiated type scheme ty', and the+-- mapping from new (instantiated) -to- old (skolem) type variables+instScheme :: QuantifiedType -> TR (TcType, RttiInstantiation)+instScheme (tvs, ty)+ = do { (subst, tvs') <- instTyVars tvs+ ; let rtti_inst = [(tv',tv) | (tv',tv) <- tvs' `zip` tvs]+ ; return (substTy subst ty, rtti_inst) }++applyRevSubst :: RttiInstantiation -> TR ()+-- Apply the *reverse* substitution in-place to any un-filled-in+-- meta tyvars. This recovers the original debugger-world variable+-- unless it has been refined by new information from the heap+applyRevSubst pairs = liftTcM (mapM_ do_pair pairs)+ where+ do_pair (tc_tv, rtti_tv)+ = do { tc_ty <- zonkTcTyVar tc_tv+ ; case tcGetTyVar_maybe tc_ty of+ Just tv | isMetaTyVar tv -> writeMetaTyVar tv (mkTyVarTy rtti_tv)+ _ -> return () }++-- Adds a constraint of the form t1 == t2+-- t1 is expected to come from walking the heap+-- t2 is expected to come from a datacon signature+-- Before unification, congruenceNewtypes needs to+-- do its magic.+addConstraint :: TcType -> TcType -> TR ()+addConstraint actual expected = do+ traceTR (text "add constraint:" <+> fsep [ppr actual, equals, ppr expected])+ recoverTR (traceTR $ fsep [text "Failed to unify", ppr actual,+ text "with", ppr expected]) $+ discardResult $+ captureConstraints $+ do { (ty1, ty2) <- congruenceNewtypes actual expected+ ; unifyType noThing ty1 ty2 }+ -- TOMDO: what about the coercion?+ -- we should consider family instances++-- Type & Term reconstruction+------------------------------+cvObtainTerm :: HscEnv -> Int -> Bool -> RttiType -> HValue -> IO Term+cvObtainTerm hsc_env max_depth force old_ty hval = runTR hsc_env $ do+ -- we quantify existential tyvars as universal,+ -- as this is needed to be able to manipulate+ -- them properly+ let quant_old_ty@(old_tvs, old_tau) = quantifyType old_ty+ sigma_old_ty = mkInvForAllTys old_tvs old_tau+ traceTR (text "Term reconstruction started with initial type " <> ppr old_ty)+ term <-+ if null old_tvs+ then do+ term <- go max_depth sigma_old_ty sigma_old_ty hval+ term' <- zonkTerm term+ return $ fixFunDictionaries $ expandNewtypes term'+ else do+ (old_ty', rev_subst) <- instScheme quant_old_ty+ my_ty <- newOpenVar+ when (check1 quant_old_ty) (traceTR (text "check1 passed") >>+ addConstraint my_ty old_ty')+ term <- go max_depth my_ty sigma_old_ty hval+ new_ty <- zonkTcType (termType term)+ if isMonomorphic new_ty || check2 (quantifyType new_ty) quant_old_ty+ then do+ traceTR (text "check2 passed")+ addConstraint new_ty old_ty'+ applyRevSubst rev_subst+ zterm' <- zonkTerm term+ return ((fixFunDictionaries . expandNewtypes) zterm')+ else do+ traceTR (text "check2 failed" <+> parens+ (ppr term <+> text "::" <+> ppr new_ty))+ -- we have unsound types. Replace constructor types in+ -- subterms with tyvars+ zterm' <- mapTermTypeM+ (\ty -> case tcSplitTyConApp_maybe ty of+ Just (tc, _:_) | tc /= funTyCon+ -> newOpenVar+ _ -> return ty)+ term+ zonkTerm zterm'+ traceTR (text "Term reconstruction completed." $$+ text "Term obtained: " <> ppr term $$+ text "Type obtained: " <> ppr (termType term))+ return term+ where+ dflags = hsc_dflags hsc_env++ go :: Int -> Type -> Type -> HValue -> TcM Term+ -- I believe that my_ty should not have any enclosing+ -- foralls, nor any free RuntimeUnk skolems;+ -- that is partly what the quantifyType stuff achieved+ --+ -- [SPJ May 11] I don't understand the difference between my_ty and old_ty++ go 0 my_ty _old_ty a = do+ traceTR (text "Gave up reconstructing a term after" <>+ int max_depth <> text " steps")+ clos <- trIO $ getClosureData dflags a+ return (Suspension (tipe clos) my_ty a Nothing)+ go !max_depth my_ty old_ty a = do+ let monomorphic = not(isTyVarTy my_ty)+ -- This ^^^ is a convention. The ancestor tests for+ -- monomorphism and passes a type instead of a tv+ clos <- trIO $ getClosureData dflags a+ case tipe clos of+-- Thunks we may want to force+ t | isThunk t && force -> traceTR (text "Forcing a " <> text (show t)) >>+ seq a (go (pred max_depth) my_ty old_ty a)+-- Blackholes are indirections iff the payload is not TSO or BLOCKING_QUEUE. So we+-- treat them like indirections; if the payload is TSO or BLOCKING_QUEUE, we'll end up+-- showing '_' which is what we want.+ Blackhole -> do traceTR (text "Following a BLACKHOLE")+ appArr (go max_depth my_ty old_ty) (ptrs clos) 0+-- We always follow indirections+ Indirection i -> do traceTR (text "Following an indirection" <> parens (int i) )+ go max_depth my_ty old_ty $! (ptrs clos ! 0)+-- We also follow references+ MutVar _ | Just (tycon,[world,contents_ty]) <- tcSplitTyConApp_maybe old_ty+ -> do+ -- Deal with the MutVar# primitive+ -- It does not have a constructor at all,+ -- so we simulate the following one+ -- MutVar# :: contents_ty -> MutVar# s contents_ty+ traceTR (text "Following a MutVar")+ contents_tv <- newVar liftedTypeKind+ contents <- trIO$ IO$ \w -> readMutVar# (unsafeCoerce# a) w+ ASSERT(isUnliftedType my_ty) return ()+ (mutvar_ty,_) <- instScheme $ quantifyType $ mkFunTy+ contents_ty (mkTyConApp tycon [world,contents_ty])+ addConstraint (mkFunTy contents_tv my_ty) mutvar_ty+ x <- go (pred max_depth) contents_tv contents_ty contents+ return (RefWrap my_ty x)++ -- The interesting case+ Constr -> do+ traceTR (text "entering a constructor " <>+ if monomorphic+ then parens (text "already monomorphic: " <> ppr my_ty)+ else Ppr.empty)+ Right dcname <- dataConInfoPtrToName (infoPtr clos)+ (_,mb_dc) <- tryTc (tcLookupDataCon dcname)+ case mb_dc of+ Nothing -> do -- This can happen for private constructors compiled -O0+ -- where the .hi descriptor does not export them+ -- In such case, we return a best approximation:+ -- ignore the unpointed args, and recover the pointeds+ -- This preserves laziness, and should be safe.+ traceTR (text "Not constructor" <+> ppr dcname)+ let dflags = hsc_dflags hsc_env+ tag = showPpr dflags dcname+ vars <- replicateM (length$ elems$ ptrs clos)+ (newVar liftedTypeKind)+ subTerms <- sequence [appArr (go (pred max_depth) tv tv) (ptrs clos) i+ | (i, tv) <- zip [0..] vars]+ return (Term my_ty (Left ('<' : tag ++ ">")) a subTerms)+ Just dc -> do+ traceTR (text "Is constructor" <+> (ppr dc $$ ppr my_ty))+ subTtypes <- getDataConArgTys dc my_ty+ subTerms <- extractSubTerms (\ty -> go (pred max_depth) ty ty) clos subTtypes+ return (Term my_ty (Right dc) a subTerms)++-- The otherwise case: can be a Thunk,AP,PAP,etc.+ tipe_clos -> do+ traceTR (text "Unknown closure:" <+> ppr tipe_clos)+ return (Suspension tipe_clos my_ty a Nothing)++ -- insert NewtypeWraps around newtypes+ expandNewtypes = foldTerm idTermFold { fTerm = worker } where+ worker ty dc hval tt+ | Just (tc, args) <- tcSplitTyConApp_maybe ty+ , isNewTyCon tc+ , wrapped_type <- newTyConInstRhs tc args+ , Just dc' <- tyConSingleDataCon_maybe tc+ , t' <- worker wrapped_type dc hval tt+ = NewtypeWrap ty (Right dc') t'+ | otherwise = Term ty dc hval tt+++ -- Avoid returning types where predicates have been expanded to dictionaries.+ fixFunDictionaries = foldTerm idTermFold {fSuspension = worker} where+ worker ct ty hval n | isFunTy ty = Suspension ct (dictsView ty) hval n+ | otherwise = Suspension ct ty hval n++extractSubTerms :: (Type -> HValue -> TcM Term)+ -> Closure -> [Type] -> TcM [Term]+extractSubTerms recurse clos = liftM thdOf3 . go 0 (nonPtrs clos)+ where+ go ptr_i ws [] = return (ptr_i, ws, [])+ go ptr_i ws (ty:tys)+ | Just (tc, elem_tys) <- tcSplitTyConApp_maybe ty+ , isUnboxedTupleTyCon tc+ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ = do (ptr_i, ws, terms0) <- go ptr_i ws (dropRuntimeRepArgs elem_tys)+ (ptr_i, ws, terms1) <- go ptr_i ws tys+ return (ptr_i, ws, unboxedTupleTerm ty terms0 : terms1)+ | otherwise+ = case typePrimRepArgs ty of+ [rep_ty] -> do+ (ptr_i, ws, term0) <- go_rep ptr_i ws ty rep_ty+ (ptr_i, ws, terms1) <- go ptr_i ws tys+ return (ptr_i, ws, term0 : terms1)+ rep_tys -> do+ (ptr_i, ws, terms0) <- go_unary_types ptr_i ws rep_tys+ (ptr_i, ws, terms1) <- go ptr_i ws tys+ return (ptr_i, ws, unboxedTupleTerm ty terms0 : terms1)++ go_unary_types ptr_i ws [] = return (ptr_i, ws, [])+ go_unary_types ptr_i ws (rep_ty:rep_tys) = do+ tv <- newVar liftedTypeKind+ (ptr_i, ws, term0) <- go_rep ptr_i ws tv rep_ty+ (ptr_i, ws, terms1) <- go_unary_types ptr_i ws rep_tys+ return (ptr_i, ws, term0 : terms1)++ go_rep ptr_i ws ty rep+ | isGcPtrRep rep+ = do t <- appArr (recurse ty) (ptrs clos) ptr_i+ return (ptr_i + 1, ws, t)+ | otherwise+ = do dflags <- getDynFlags+ let (ws0, ws1) = splitAt (primRepSizeW dflags rep) ws+ return (ptr_i, ws1, Prim ty ws0)++ unboxedTupleTerm ty terms+ = Term ty (Right (tupleDataCon Unboxed (length terms)))+ (error "unboxedTupleTerm: no HValue for unboxed tuple") terms+++-- Fast, breadth-first Type reconstruction+------------------------------------------+cvReconstructType :: HscEnv -> Int -> GhciType -> HValue -> IO (Maybe Type)+cvReconstructType hsc_env max_depth old_ty hval = runTR_maybe hsc_env $ do+ traceTR (text "RTTI started with initial type " <> ppr old_ty)+ let sigma_old_ty@(old_tvs, _) = quantifyType old_ty+ new_ty <-+ if null old_tvs+ then return old_ty+ else do+ (old_ty', rev_subst) <- instScheme sigma_old_ty+ my_ty <- newOpenVar+ when (check1 sigma_old_ty) (traceTR (text "check1 passed") >>+ addConstraint my_ty old_ty')+ search (isMonomorphic `fmap` zonkTcType my_ty)+ (\(ty,a) -> go ty a)+ (Seq.singleton (my_ty, hval))+ max_depth+ new_ty <- zonkTcType my_ty+ if isMonomorphic new_ty || check2 (quantifyType new_ty) sigma_old_ty+ then do+ traceTR (text "check2 passed" <+> ppr old_ty $$ ppr new_ty)+ addConstraint my_ty old_ty'+ applyRevSubst rev_subst+ zonkRttiType new_ty+ else traceTR (text "check2 failed" <+> parens (ppr new_ty)) >>+ return old_ty+ traceTR (text "RTTI completed. Type obtained:" <+> ppr new_ty)+ return new_ty+ where+ dflags = hsc_dflags hsc_env++-- search :: m Bool -> ([a] -> [a] -> [a]) -> [a] -> m ()+ search _ _ _ 0 = traceTR (text "Failed to reconstruct a type after " <>+ int max_depth <> text " steps")+ search stop expand l d =+ case viewl l of+ EmptyL -> return ()+ x :< xx -> unlessM stop $ do+ new <- expand x+ search stop expand (xx `mappend` Seq.fromList new) $! (pred d)++ -- returns unification tasks,since we are going to want a breadth-first search+ go :: Type -> HValue -> TR [(Type, HValue)]+ go my_ty a = do+ traceTR (text "go" <+> ppr my_ty)+ clos <- trIO $ getClosureData dflags a+ case tipe clos of+ Blackhole -> appArr (go my_ty) (ptrs clos) 0 -- carefully, don't eval the TSO+ Indirection _ -> go my_ty $! (ptrs clos ! 0)+ MutVar _ -> do+ contents <- trIO$ IO$ \w -> readMutVar# (unsafeCoerce# a) w+ tv' <- newVar liftedTypeKind+ world <- newVar liftedTypeKind+ addConstraint my_ty (mkTyConApp mutVarPrimTyCon [world,tv'])+ return [(tv', contents)]+ Constr -> do+ Right dcname <- dataConInfoPtrToName (infoPtr clos)+ traceTR (text "Constr1" <+> ppr dcname)+ (_,mb_dc) <- tryTc (tcLookupDataCon dcname)+ case mb_dc of+ Nothing-> do+ forM (elems $ ptrs clos) $ \a -> do+ tv <- newVar liftedTypeKind+ return (tv, a)++ Just dc -> do+ arg_tys <- getDataConArgTys dc my_ty+ (_, itys) <- findPtrTyss 0 arg_tys+ traceTR (text "Constr2" <+> ppr dcname <+> ppr arg_tys)+ return $ [ appArr (\e-> (ty,e)) (ptrs clos) i+ | (i,ty) <- itys]+ _ -> return []++findPtrTys :: Int -- Current pointer index+ -> Type -- Type+ -> TR (Int, [(Int, Type)])+findPtrTys i ty+ | Just (tc, elem_tys) <- tcSplitTyConApp_maybe ty+ , isUnboxedTupleTyCon tc+ = findPtrTyss i elem_tys++ | otherwise+ = case typePrimRep ty of+ [rep] | isGcPtrRep rep -> return (i + 1, [(i, ty)])+ | otherwise -> return (i, [])+ prim_reps ->+ foldM (\(i, extras) prim_rep ->+ if isGcPtrRep prim_rep+ then newVar liftedTypeKind >>= \tv -> return (i + 1, extras ++ [(i, tv)])+ else return (i, extras))+ (i, []) prim_reps++findPtrTyss :: Int+ -> [Type]+ -> TR (Int, [(Int, Type)])+findPtrTyss i tys = foldM step (i, []) tys+ where step (i, discovered) elem_ty = do+ (i, extras) <- findPtrTys i elem_ty+ return (i, discovered ++ extras)+++-- Compute the difference between a base type and the type found by RTTI+-- improveType <base_type> <rtti_type>+-- The types can contain skolem type variables, which need to be treated as normal vars.+-- In particular, we want them to unify with things.+improveRTTIType :: HscEnv -> RttiType -> RttiType -> Maybe TCvSubst+improveRTTIType _ base_ty new_ty = U.tcUnifyTyKi base_ty new_ty++getDataConArgTys :: DataCon -> Type -> TR [Type]+-- Given the result type ty of a constructor application (D a b c :: ty)+-- return the types of the arguments. This is RTTI-land, so 'ty' might+-- not be fully known. Moreover, the arg types might involve existentials;+-- if so, make up fresh RTTI type variables for them+--+-- I believe that con_app_ty should not have any enclosing foralls+getDataConArgTys dc con_app_ty+ = do { let rep_con_app_ty = unwrapType con_app_ty+ ; traceTR (text "getDataConArgTys 1" <+> (ppr con_app_ty $$ ppr rep_con_app_ty+ $$ ppr (tcSplitTyConApp_maybe rep_con_app_ty)))+ ; (subst, _) <- instTyVars (univ_tvs ++ ex_tvs)+ ; addConstraint rep_con_app_ty (substTy subst (dataConOrigResTy dc))+ -- See Note [Constructor arg types]+ ; let con_arg_tys = substTys subst (dataConRepArgTys dc)+ ; traceTR (text "getDataConArgTys 2" <+> (ppr rep_con_app_ty $$ ppr con_arg_tys $$ ppr subst))+ ; return con_arg_tys }+ where+ univ_tvs = dataConUnivTyVars dc+ ex_tvs = dataConExTyVars dc++{- Note [Constructor arg types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider a GADT (cf Trac #7386)+ data family D a b+ data instance D [a] a where+ MkT :: a -> D [a] (Maybe a)+ ...++In getDataConArgTys+* con_app_ty is the known type (from outside) of the constructor application,+ say D [Int] Int++* The data constructor MkT has a (representation) dataConTyCon = DList,+ say where+ data DList a where+ MkT :: a -> DList a (Maybe a)+ ...++So the dataConTyCon of the data constructor, DList, differs from+the "outside" type, D. So we can't straightforwardly decompose the+"outside" type, and we end up in the "_" branch of the case.++Then we match the dataConOrigResTy of the data constructor against the+outside type, hoping to get a substitution that tells how to instantiate+the *representation* type constructor. This looks a bit delicate to+me, but it seems to work.+-}++-- Soundness checks+--------------------+{-+This is not formalized anywhere, so hold to your seats!+RTTI in the presence of newtypes can be a tricky and unsound business.++Example:+~~~~~~~~~+Suppose we are doing RTTI for a partially evaluated+closure t, the real type of which is t :: MkT Int, for++ newtype MkT a = MkT [Maybe a]++The table below shows the results of RTTI and the improvement+calculated for different combinations of evaluatedness and :type t.+Regard the two first columns as input and the next two as output.++ # | t | :type t | rtti(t) | improv. | result+ ------------------------------------------------------------+ 1 | _ | t b | a | none | OK+ 2 | _ | MkT b | a | none | OK+ 3 | _ | t Int | a | none | OK++ If t is not evaluated at *all*, we are safe.++ 4 | (_ : _) | t b | [a] | t = [] | UNSOUND+ 5 | (_ : _) | MkT b | MkT a | none | OK (compensating for the missing newtype)+ 6 | (_ : _) | t Int | [Int] | t = [] | UNSOUND++ If a is a minimal whnf, we run into trouble. Note that+ row 5 above does newtype enrichment on the ty_rtty parameter.++ 7 | (Just _:_)| t b |[Maybe a] | t = [], | UNSOUND+ | | | b = Maybe a|++ 8 | (Just _:_)| MkT b | MkT a | none | OK+ 9 | (Just _:_)| t Int | FAIL | none | OK++ And if t is any more evaluated than whnf, we are still in trouble.+ Because constraints are solved in top-down order, when we reach the+ Maybe subterm what we got is already unsound. This explains why the+ row 9 fails to complete.++ 10 | (Just _:_)| t Int | [Maybe a] | FAIL | OK+ 11 | (Just 1:_)| t Int | [Maybe Int] | FAIL | OK++ We can undo the failure in row 9 by leaving out the constraint+ coming from the type signature of t (i.e., the 2nd column).+ Note that this type information is still used+ to calculate the improvement. But we fail+ when trying to calculate the improvement, as there is no unifier for+ t Int = [Maybe a] or t Int = [Maybe Int].+++ Another set of examples with t :: [MkT (Maybe Int)] \equiv [[Maybe (Maybe Int)]]++ # | t | :type t | rtti(t) | improvement | result+ ---------------------------------------------------------------------+ 1 |(Just _:_) | [t (Maybe a)] | [[Maybe b]] | t = [] |+ | | | | b = Maybe a |++The checks:+~~~~~~~~~~~+Consider a function obtainType that takes a value and a type and produces+the Term representation and a substitution (the improvement).+Assume an auxiliar rtti' function which does the actual job if recovering+the type, but which may produce a false type.++In pseudocode:++ rtti' :: a -> IO Type -- Does not use the static type information++ obtainType :: a -> Type -> IO (Maybe (Term, Improvement))+ obtainType v old_ty = do+ rtti_ty <- rtti' v+ if monomorphic rtti_ty || (check rtti_ty old_ty)+ then ...+ else return Nothing+ where check rtti_ty old_ty = check1 rtti_ty &&+ check2 rtti_ty old_ty++ check1 :: Type -> Bool+ check2 :: Type -> Type -> Bool++Now, if rtti' returns a monomorphic type, we are safe.+If that is not the case, then we consider two conditions.+++1. To prevent the class of unsoundness displayed by+ rows 4 and 7 in the example: no higher kind tyvars+ accepted.++ check1 (t a) = NO+ check1 (t Int) = NO+ check1 ([] a) = YES++2. To prevent the class of unsoundness shown by row 6,+ the rtti type should be structurally more+ defined than the old type we are comparing it to.+ check2 :: NewType -> OldType -> Bool+ check2 a _ = True+ check2 [a] a = True+ check2 [a] (t Int) = False+ check2 [a] (t a) = False -- By check1 we never reach this equation+ check2 [Int] a = True+ check2 [Int] (t Int) = True+ check2 [Maybe a] (t Int) = False+ check2 [Maybe Int] (t Int) = True+ check2 (Maybe [a]) (m [Int]) = False+ check2 (Maybe [Int]) (m [Int]) = True++-}++check1 :: QuantifiedType -> Bool+check1 (tvs, _) = not $ any isHigherKind (map tyVarKind tvs)+ where+ isHigherKind = not . null . fst . splitPiTys++check2 :: QuantifiedType -> QuantifiedType -> Bool+check2 (_, rtti_ty) (_, old_ty)+ | Just (_, rttis) <- tcSplitTyConApp_maybe rtti_ty+ = case () of+ _ | Just (_,olds) <- tcSplitTyConApp_maybe old_ty+ -> and$ zipWith check2 (map quantifyType rttis) (map quantifyType olds)+ _ | Just _ <- splitAppTy_maybe old_ty+ -> isMonomorphicOnNonPhantomArgs rtti_ty+ _ -> True+ | otherwise = True++-- Dealing with newtypes+--------------------------+{-+ congruenceNewtypes does a parallel fold over two Type values,+ compensating for missing newtypes on both sides.+ This is necessary because newtypes are not present+ in runtime, but sometimes there is evidence available.+ Evidence can come from DataCon signatures or+ from compile-time type inference.+ What we are doing here is an approximation+ of unification modulo a set of equations derived+ from newtype definitions. These equations should be the+ same as the equality coercions generated for newtypes+ in System Fc. The idea is to perform a sort of rewriting,+ taking those equations as rules, before launching unification.++ The caller must ensure the following.+ The 1st type (lhs) comes from the heap structure of ptrs,nptrs.+ The 2nd type (rhs) comes from a DataCon type signature.+ Rewriting (i.e. adding/removing a newtype wrapper) can happen+ in both types, but in the rhs it is restricted to the result type.++ Note that it is very tricky to make this 'rewriting'+ work with the unification implemented by TcM, where+ substitutions are operationally inlined. The order in which+ constraints are unified is vital as we cannot modify+ anything that has been touched by a previous unification step.+Therefore, congruenceNewtypes is sound only if the types+recovered by the RTTI mechanism are unified Top-Down.+-}+congruenceNewtypes :: TcType -> TcType -> TR (TcType,TcType)+congruenceNewtypes lhs rhs = go lhs rhs >>= \rhs' -> return (lhs,rhs')+ where+ go l r+ -- TyVar lhs inductive case+ | Just tv <- getTyVar_maybe l+ , isTcTyVar tv+ , isMetaTyVar tv+ = recoverTR (return r) $ do+ Indirect ty_v <- readMetaTyVar tv+ traceTR $ fsep [text "(congruence) Following indirect tyvar:",+ ppr tv, equals, ppr ty_v]+ go ty_v r+-- FunTy inductive case+ | Just (l1,l2) <- splitFunTy_maybe l+ , Just (r1,r2) <- splitFunTy_maybe r+ = do r2' <- go l2 r2+ r1' <- go l1 r1+ return (mkFunTy r1' r2')+-- TyconApp Inductive case; this is the interesting bit.+ | Just (tycon_l, _) <- tcSplitTyConApp_maybe lhs+ , Just (tycon_r, _) <- tcSplitTyConApp_maybe rhs+ , tycon_l /= tycon_r+ = upgrade tycon_l r++ | otherwise = return r++ where upgrade :: TyCon -> Type -> TR Type+ upgrade new_tycon ty+ | not (isNewTyCon new_tycon) = do+ traceTR (text "(Upgrade) Not matching newtype evidence: " <>+ ppr new_tycon <> text " for " <> ppr ty)+ return ty+ | otherwise = do+ traceTR (text "(Upgrade) upgraded " <> ppr ty <>+ text " in presence of newtype evidence " <> ppr new_tycon)+ (_, vars) <- instTyVars (tyConTyVars new_tycon)+ let ty' = mkTyConApp new_tycon (mkTyVarTys vars)+ rep_ty = unwrapType ty'+ _ <- liftTcM (unifyType noThing ty rep_ty)+ -- assumes that reptype doesn't ^^^^ touch tyconApp args+ return ty'+++zonkTerm :: Term -> TcM Term+zonkTerm = foldTermM (TermFoldM+ { fTermM = \ty dc v tt -> zonkRttiType ty >>= \ty' ->+ return (Term ty' dc v tt)+ , fSuspensionM = \ct ty v b -> zonkRttiType ty >>= \ty ->+ return (Suspension ct ty v b)+ , fNewtypeWrapM = \ty dc t -> zonkRttiType ty >>= \ty' ->+ return$ NewtypeWrap ty' dc t+ , fRefWrapM = \ty t -> return RefWrap `ap`+ zonkRttiType ty `ap` return t+ , fPrimM = (return.) . Prim })++zonkRttiType :: TcType -> TcM Type+-- Zonk the type, replacing any unbound Meta tyvars+-- by skolems, safely out of Meta-tyvar-land+zonkRttiType = zonkTcTypeToType (mkEmptyZonkEnv zonk_unbound_meta)+ where+ zonk_unbound_meta tv+ = ASSERT( isTcTyVar tv )+ do { tv' <- skolemiseRuntimeUnk tv+ -- This is where RuntimeUnks are born:+ -- otherwise-unconstrained unification variables are+ -- turned into RuntimeUnks as they leave the+ -- typechecker's monad+ ; return (mkTyVarTy tv') }++--------------------------------------------------------------------------------+-- Restore Class predicates out of a representation type+dictsView :: Type -> Type+dictsView ty = ty+++-- Use only for RTTI types+isMonomorphic :: RttiType -> Bool+isMonomorphic ty = noExistentials && noUniversals+ where (tvs, _, ty') = tcSplitSigmaTy ty+ noExistentials = noFreeVarsOfType ty'+ noUniversals = null tvs++-- Use only for RTTI types+isMonomorphicOnNonPhantomArgs :: RttiType -> Bool+isMonomorphicOnNonPhantomArgs ty+ | Just (tc, all_args) <- tcSplitTyConApp_maybe (unwrapType ty)+ , phantom_vars <- tyConPhantomTyVars tc+ , concrete_args <- [ arg | (tyv,arg) <- tyConTyVars tc `zip` all_args+ , tyv `notElem` phantom_vars]+ = all isMonomorphicOnNonPhantomArgs concrete_args+ | Just (ty1, ty2) <- splitFunTy_maybe ty+ = all isMonomorphicOnNonPhantomArgs [ty1,ty2]+ | otherwise = isMonomorphic ty++tyConPhantomTyVars :: TyCon -> [TyVar]+tyConPhantomTyVars tc+ | isAlgTyCon tc+ , Just dcs <- tyConDataCons_maybe tc+ , dc_vars <- concatMap dataConUnivTyVars dcs+ = tyConTyVars tc \\ dc_vars+tyConPhantomTyVars _ = []++type QuantifiedType = ([TyVar], Type)+ -- Make the free type variables explicit+ -- The returned Type should have no top-level foralls (I believe)++quantifyType :: Type -> QuantifiedType+-- Generalize the type: find all free and forall'd tyvars+-- and return them, together with the type inside, which+-- should not be a forall type.+--+-- Thus (quantifyType (forall a. a->[b]))+-- returns ([a,b], a -> [b])++quantifyType ty = ( filter isTyVar $+ tyCoVarsOfTypeWellScoped rho+ , rho)+ where+ (_tvs, rho) = tcSplitForAllTys ty++-- Strict application of f at index i+appArr :: Ix i => (e -> a) -> Array i e -> Int -> a+appArr f a@(Array _ _ _ ptrs#) i@(I# i#)+ = ASSERT2(i < length(elems a), ppr(length$ elems a, i))+ case indexArray# ptrs# i# of+ (# e #) -> f e++amap' :: (t -> b) -> Array Int t -> [b]+amap' f (Array i0 i _ arr#) = map g [0 .. i - i0]+ where g (I# i#) = case indexArray# arr# i# of+ (# e #) -> f e
+ ghci/keepCAFsForGHCi.c view
@@ -0,0 +1,15 @@+#include "Rts.h"++// This file is only included in the dynamic library.+// It contains an __attribute__((constructor)) function (run prior to main())+// which sets the keepCAFs flag in the RTS, before any Haskell code is run.+// This is required so that GHCi can use dynamic libraries instead of HSxyz.o+// files.++static void keepCAFsForGHCi(void) __attribute__((constructor));++static void keepCAFsForGHCi(void)+{+ keepCAFs = 1;+}+
+ hsSyn/Convert.hs view
@@ -0,0 +1,1721 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++This module converts Template Haskell syntax into HsSyn+-}++{-# LANGUAGE ScopedTypeVariables #-}++module Convert( convertToHsExpr, convertToPat, convertToHsDecls,+ convertToHsType,+ thRdrNameGuesses ) where++import HsSyn as Hs+import qualified Class+import RdrName+import qualified Name+import Module+import RdrHsSyn+import qualified OccName+import OccName+import SrcLoc+import Type+import qualified Coercion ( Role(..) )+import TysWiredIn+import TysPrim (eqPrimTyCon)+import BasicTypes as Hs+import ForeignCall+import Unique+import ErrUtils+import Bag+import Lexeme+import Util+import FastString+import Outputable+import MonadUtils ( foldrM )++import qualified Data.ByteString as BS+import Control.Monad( unless, liftM, ap, (<=<) )++import Data.Maybe( catMaybes, fromMaybe, isNothing )+import Language.Haskell.TH as TH hiding (sigP)+import Language.Haskell.TH.Syntax as TH++-------------------------------------------------------------------+-- The external interface++convertToHsDecls :: SrcSpan -> [TH.Dec] -> Either MsgDoc [LHsDecl RdrName]+convertToHsDecls loc ds = initCvt loc (fmap catMaybes (mapM cvt_dec ds))+ where+ cvt_dec d = wrapMsg "declaration" d (cvtDec d)++convertToHsExpr :: SrcSpan -> TH.Exp -> Either MsgDoc (LHsExpr RdrName)+convertToHsExpr loc e+ = initCvt loc $ wrapMsg "expression" e $ cvtl e++convertToPat :: SrcSpan -> TH.Pat -> Either MsgDoc (LPat RdrName)+convertToPat loc p+ = initCvt loc $ wrapMsg "pattern" p $ cvtPat p++convertToHsType :: SrcSpan -> TH.Type -> Either MsgDoc (LHsType RdrName)+convertToHsType loc t+ = initCvt loc $ wrapMsg "type" t $ cvtType t++-------------------------------------------------------------------+newtype CvtM a = CvtM { unCvtM :: SrcSpan -> Either MsgDoc (SrcSpan, a) }+ -- Push down the source location;+ -- Can fail, with a single error message++-- NB: If the conversion succeeds with (Right x), there should+-- be no exception values hiding in x+-- Reason: so a (head []) in TH code doesn't subsequently+-- make GHC crash when it tries to walk the generated tree++-- Use the loc everywhere, for lack of anything better+-- In particular, we want it on binding locations, so that variables bound in+-- the spliced-in declarations get a location that at least relates to the splice point++instance Functor CvtM where+ fmap = liftM++instance Applicative CvtM where+ pure x = CvtM $ \loc -> Right (loc,x)+ (<*>) = ap++instance Monad CvtM where+ (CvtM m) >>= k = CvtM $ \loc -> case m loc of+ Left err -> Left err+ Right (loc',v) -> unCvtM (k v) loc'++initCvt :: SrcSpan -> CvtM a -> Either MsgDoc a+initCvt loc (CvtM m) = fmap snd (m loc)++force :: a -> CvtM ()+force a = a `seq` return ()++failWith :: MsgDoc -> CvtM a+failWith m = CvtM (\_ -> Left m)++getL :: CvtM SrcSpan+getL = CvtM (\loc -> Right (loc,loc))++setL :: SrcSpan -> CvtM ()+setL loc = CvtM (\_ -> Right (loc, ()))++returnL :: a -> CvtM (Located a)+returnL x = CvtM (\loc -> Right (loc, L loc x))++returnJustL :: a -> CvtM (Maybe (Located a))+returnJustL = fmap Just . returnL++wrapParL :: (Located a -> a) -> a -> CvtM a+wrapParL add_par x = CvtM (\loc -> Right (loc, add_par (L loc x)))++wrapMsg :: (Show a, TH.Ppr a) => String -> a -> CvtM b -> CvtM b+-- E.g wrapMsg "declaration" dec thing+wrapMsg what item (CvtM m)+ = CvtM (\loc -> case m loc of+ Left err -> Left (err $$ getPprStyle msg)+ Right v -> Right v)+ where+ -- Show the item in pretty syntax normally,+ -- but with all its constructors if you say -dppr-debug+ msg sty = hang (text "When splicing a TH" <+> text what <> colon)+ 2 (if debugStyle sty+ then text (show item)+ else text (pprint item))++wrapL :: CvtM a -> CvtM (Located a)+wrapL (CvtM m) = CvtM (\loc -> case m loc of+ Left err -> Left err+ Right (loc',v) -> Right (loc',L loc v))++-------------------------------------------------------------------+cvtDecs :: [TH.Dec] -> CvtM [LHsDecl RdrName]+cvtDecs = fmap catMaybes . mapM cvtDec++cvtDec :: TH.Dec -> CvtM (Maybe (LHsDecl RdrName))+cvtDec (TH.ValD pat body ds)+ | TH.VarP s <- pat+ = do { s' <- vNameL s+ ; cl' <- cvtClause (mkPrefixFunRhs s') (Clause [] body ds)+ ; returnJustL $ Hs.ValD $ mkFunBind s' [cl'] }++ | otherwise+ = do { pat' <- cvtPat pat+ ; body' <- cvtGuard body+ ; ds' <- cvtLocalDecs (text "a where clause") ds+ ; returnJustL $ Hs.ValD $+ PatBind { pat_lhs = pat', pat_rhs = GRHSs body' (noLoc ds')+ , pat_rhs_ty = placeHolderType, bind_fvs = placeHolderNames+ , pat_ticks = ([],[]) } }++cvtDec (TH.FunD nm cls)+ | null cls+ = failWith (text "Function binding for"+ <+> quotes (text (TH.pprint nm))+ <+> text "has no equations")+ | otherwise+ = do { nm' <- vNameL nm+ ; cls' <- mapM (cvtClause (mkPrefixFunRhs nm')) cls+ ; returnJustL $ Hs.ValD $ mkFunBind nm' cls' }++cvtDec (TH.SigD nm typ)+ = do { nm' <- vNameL nm+ ; ty' <- cvtType typ+ ; returnJustL $ Hs.SigD (TypeSig [nm'] (mkLHsSigWcType ty')) }++cvtDec (TH.InfixD fx nm)+ -- Fixity signatures are allowed for variables, constructors, and types+ -- the renamer automatically looks for types during renaming, even when+ -- the RdrName says it's a variable or a constructor. So, just assume+ -- it's a variable or constructor and proceed.+ = do { nm' <- vcNameL nm+ ; returnJustL (Hs.SigD (FixSig (FixitySig [nm'] (cvtFixity fx)))) }++cvtDec (PragmaD prag)+ = cvtPragmaD prag++cvtDec (TySynD tc tvs rhs)+ = do { (_, tc', tvs') <- cvt_tycl_hdr [] tc tvs+ ; rhs' <- cvtType rhs+ ; returnJustL $ TyClD $+ SynDecl { tcdLName = tc', tcdTyVars = tvs'+ , tcdFixity = Prefix+ , tcdFVs = placeHolderNames+ , tcdRhs = rhs' } }++cvtDec (DataD ctxt tc tvs ksig constrs derivs)+ = do { let isGadtCon (GadtC _ _ _) = True+ isGadtCon (RecGadtC _ _ _) = True+ isGadtCon (ForallC _ _ c) = isGadtCon c+ isGadtCon _ = False+ isGadtDecl = all isGadtCon constrs+ isH98Decl = all (not . isGadtCon) constrs+ ; unless (isGadtDecl || isH98Decl)+ (failWith (text "Cannot mix GADT constructors with Haskell 98"+ <+> text "constructors"))+ ; unless (isNothing ksig || isGadtDecl)+ (failWith (text "Kind signatures are only allowed on GADTs"))+ ; (ctxt', tc', tvs') <- cvt_tycl_hdr ctxt tc tvs+ ; ksig' <- cvtKind `traverse` ksig+ ; cons' <- mapM cvtConstr constrs+ ; derivs' <- cvtDerivs derivs+ ; let defn = HsDataDefn { dd_ND = DataType, dd_cType = Nothing+ , dd_ctxt = ctxt'+ , dd_kindSig = ksig'+ , dd_cons = cons', dd_derivs = derivs' }+ ; returnJustL $ TyClD (DataDecl { tcdLName = tc', tcdTyVars = tvs'+ , tcdFixity = Prefix+ , tcdDataDefn = defn+ , tcdDataCusk = PlaceHolder+ , tcdFVs = placeHolderNames }) }++cvtDec (NewtypeD ctxt tc tvs ksig constr derivs)+ = do { (ctxt', tc', tvs') <- cvt_tycl_hdr ctxt tc tvs+ ; ksig' <- cvtKind `traverse` ksig+ ; con' <- cvtConstr constr+ ; derivs' <- cvtDerivs derivs+ ; let defn = HsDataDefn { dd_ND = NewType, dd_cType = Nothing+ , dd_ctxt = ctxt'+ , dd_kindSig = ksig'+ , dd_cons = [con']+ , dd_derivs = derivs' }+ ; returnJustL $ TyClD (DataDecl { tcdLName = tc', tcdTyVars = tvs'+ , tcdFixity = Prefix+ , tcdDataDefn = defn+ , tcdDataCusk = PlaceHolder+ , tcdFVs = placeHolderNames }) }++cvtDec (ClassD ctxt cl tvs fds decs)+ = do { (cxt', tc', tvs') <- cvt_tycl_hdr ctxt cl tvs+ ; fds' <- mapM cvt_fundep fds+ ; (binds', sigs', fams', ats', adts') <- cvt_ci_decs (text "a class declaration") decs+ ; unless (null adts')+ (failWith $ (text "Default data instance declarations"+ <+> text "are not allowed:")+ $$ (Outputable.ppr adts'))+ ; at_defs <- mapM cvt_at_def ats'+ ; returnJustL $ TyClD $+ ClassDecl { tcdCtxt = cxt', tcdLName = tc', tcdTyVars = tvs'+ , tcdFixity = Prefix+ , tcdFDs = fds', tcdSigs = Hs.mkClassOpSigs sigs'+ , tcdMeths = binds'+ , tcdATs = fams', tcdATDefs = at_defs, tcdDocs = []+ , tcdFVs = placeHolderNames }+ -- no docs in TH ^^+ }+ where+ cvt_at_def :: LTyFamInstDecl RdrName -> CvtM (LTyFamDefltEqn RdrName)+ -- Very similar to what happens in RdrHsSyn.mkClassDecl+ cvt_at_def decl = case RdrHsSyn.mkATDefault decl of+ Right def -> return def+ Left (_, msg) -> failWith msg++cvtDec (InstanceD o ctxt ty decs)+ = do { let doc = text "an instance declaration"+ ; (binds', sigs', fams', ats', adts') <- cvt_ci_decs doc decs+ ; unless (null fams') (failWith (mkBadDecMsg doc fams'))+ ; ctxt' <- cvtContext ctxt+ ; L loc ty' <- cvtType ty+ ; let inst_ty' = mkHsQualTy ctxt loc ctxt' $ L loc ty'+ ; returnJustL $ InstD $ ClsInstD $+ ClsInstDecl { cid_poly_ty = mkLHsSigType inst_ty'+ , cid_binds = binds'+ , cid_sigs = Hs.mkClassOpSigs sigs'+ , cid_tyfam_insts = ats', cid_datafam_insts = adts'+ , cid_overlap_mode = fmap (L loc . overlap) o } }+ where+ overlap pragma =+ case pragma of+ TH.Overlaps -> Hs.Overlaps (SourceText "OVERLAPS")+ TH.Overlappable -> Hs.Overlappable (SourceText "OVERLAPPABLE")+ TH.Overlapping -> Hs.Overlapping (SourceText "OVERLAPPING")+ TH.Incoherent -> Hs.Incoherent (SourceText "INCOHERENT")+++++cvtDec (ForeignD ford)+ = do { ford' <- cvtForD ford+ ; returnJustL $ ForD ford' }++cvtDec (DataFamilyD tc tvs kind)+ = do { (_, tc', tvs') <- cvt_tycl_hdr [] tc tvs+ ; result <- cvtMaybeKindToFamilyResultSig kind+ ; returnJustL $ TyClD $ FamDecl $+ FamilyDecl DataFamily tc' tvs' Prefix result Nothing }++cvtDec (DataInstD ctxt tc tys ksig constrs derivs)+ = do { (ctxt', tc', typats') <- cvt_tyinst_hdr ctxt tc tys+ ; ksig' <- cvtKind `traverse` ksig+ ; cons' <- mapM cvtConstr constrs+ ; derivs' <- cvtDerivs derivs+ ; let defn = HsDataDefn { dd_ND = DataType, dd_cType = Nothing+ , dd_ctxt = ctxt'+ , dd_kindSig = ksig'+ , dd_cons = cons', dd_derivs = derivs' }++ ; returnJustL $ InstD $ DataFamInstD+ { dfid_inst = DataFamInstDecl { dfid_tycon = tc', dfid_pats = typats'+ , dfid_defn = defn+ , dfid_fixity = Prefix+ , dfid_fvs = placeHolderNames } }}++cvtDec (NewtypeInstD ctxt tc tys ksig constr derivs)+ = do { (ctxt', tc', typats') <- cvt_tyinst_hdr ctxt tc tys+ ; ksig' <- cvtKind `traverse` ksig+ ; con' <- cvtConstr constr+ ; derivs' <- cvtDerivs derivs+ ; let defn = HsDataDefn { dd_ND = NewType, dd_cType = Nothing+ , dd_ctxt = ctxt'+ , dd_kindSig = ksig'+ , dd_cons = [con'], dd_derivs = derivs' }+ ; returnJustL $ InstD $ DataFamInstD+ { dfid_inst = DataFamInstDecl { dfid_tycon = tc', dfid_pats = typats'+ , dfid_defn = defn+ , dfid_fixity = Prefix+ , dfid_fvs = placeHolderNames } }}++cvtDec (TySynInstD tc eqn)+ = do { tc' <- tconNameL tc+ ; eqn' <- cvtTySynEqn tc' eqn+ ; returnJustL $ InstD $ TyFamInstD+ { tfid_inst = TyFamInstDecl { tfid_eqn = eqn'+ , tfid_fvs = placeHolderNames } } }++cvtDec (OpenTypeFamilyD head)+ = do { (tc', tyvars', result', injectivity') <- cvt_tyfam_head head+ ; returnJustL $ TyClD $ FamDecl $+ FamilyDecl OpenTypeFamily tc' tyvars' Prefix result' injectivity' }++cvtDec (ClosedTypeFamilyD head eqns)+ = do { (tc', tyvars', result', injectivity') <- cvt_tyfam_head head+ ; eqns' <- mapM (cvtTySynEqn tc') eqns+ ; returnJustL $ TyClD $ FamDecl $+ FamilyDecl (ClosedTypeFamily (Just eqns')) tc' tyvars' Prefix result'+ injectivity' }++cvtDec (TH.RoleAnnotD tc roles)+ = do { tc' <- tconNameL tc+ ; let roles' = map (noLoc . cvtRole) roles+ ; returnJustL $ Hs.RoleAnnotD (RoleAnnotDecl tc' roles') }++cvtDec (TH.StandaloneDerivD ds cxt ty)+ = do { cxt' <- cvtContext cxt+ ; L loc ty' <- cvtType ty+ ; let inst_ty' = mkHsQualTy cxt loc cxt' $ L loc ty'+ ; returnJustL $ DerivD $+ DerivDecl { deriv_strategy = fmap (L loc . cvtDerivStrategy) ds+ , deriv_type = mkLHsSigType inst_ty'+ , deriv_overlap_mode = Nothing } }++cvtDec (TH.DefaultSigD nm typ)+ = do { nm' <- vNameL nm+ ; ty' <- cvtType typ+ ; returnJustL $ Hs.SigD $ ClassOpSig True [nm'] (mkLHsSigType ty') }++cvtDec (TH.PatSynD nm args dir pat)+ = do { nm' <- cNameL nm+ ; args' <- cvtArgs args+ ; dir' <- cvtDir nm' dir+ ; pat' <- cvtPat pat+ ; returnJustL $ Hs.ValD $ PatSynBind $+ PSB nm' placeHolderType args' pat' dir' }+ where+ cvtArgs (TH.PrefixPatSyn args) = Hs.PrefixPatSyn <$> mapM vNameL args+ cvtArgs (TH.InfixPatSyn a1 a2) = Hs.InfixPatSyn <$> vNameL a1 <*> vNameL a2+ cvtArgs (TH.RecordPatSyn sels)+ = do { sels' <- mapM vNameL sels+ ; vars' <- mapM (vNameL . mkNameS . nameBase) sels+ ; return $ Hs.RecordPatSyn $ zipWith RecordPatSynField sels' vars' }++ cvtDir _ Unidir = return Unidirectional+ cvtDir _ ImplBidir = return ImplicitBidirectional+ cvtDir n (ExplBidir cls) =+ do { ms <- mapM (cvtClause (mkPrefixFunRhs n)) cls+ ; return $ ExplicitBidirectional $ mkMatchGroup FromSource ms }++cvtDec (TH.PatSynSigD nm ty)+ = do { nm' <- cNameL nm+ ; ty' <- cvtPatSynSigTy ty+ ; returnJustL $ Hs.SigD $ PatSynSig [nm'] (mkLHsSigType ty') }++----------------+cvtTySynEqn :: Located RdrName -> TySynEqn -> CvtM (LTyFamInstEqn RdrName)+cvtTySynEqn tc (TySynEqn lhs rhs)+ = do { lhs' <- mapM (wrap_apps <=< cvtType) lhs+ ; rhs' <- cvtType rhs+ ; returnL $ TyFamEqn { tfe_tycon = tc+ , tfe_pats = mkHsImplicitBndrs lhs'+ , tfe_fixity = Prefix+ , tfe_rhs = rhs' } }++----------------+cvt_ci_decs :: MsgDoc -> [TH.Dec]+ -> CvtM (LHsBinds RdrName,+ [LSig RdrName],+ [LFamilyDecl RdrName],+ [LTyFamInstDecl RdrName],+ [LDataFamInstDecl RdrName])+-- Convert the declarations inside a class or instance decl+-- ie signatures, bindings, and associated types+cvt_ci_decs doc decs+ = do { decs' <- cvtDecs decs+ ; let (ats', bind_sig_decs') = partitionWith is_tyfam_inst decs'+ ; let (adts', no_ats') = partitionWith is_datafam_inst bind_sig_decs'+ ; let (sigs', prob_binds') = partitionWith is_sig no_ats'+ ; let (binds', prob_fams') = partitionWith is_bind prob_binds'+ ; let (fams', bads) = partitionWith is_fam_decl prob_fams'+ ; unless (null bads) (failWith (mkBadDecMsg doc bads))+ --We use FromSource as the origin of the bind+ -- because the TH declaration is user-written+ ; return (listToBag binds', sigs', fams', ats', adts') }++----------------+cvt_tycl_hdr :: TH.Cxt -> TH.Name -> [TH.TyVarBndr]+ -> CvtM ( LHsContext RdrName+ , Located RdrName+ , LHsQTyVars RdrName)+cvt_tycl_hdr cxt tc tvs+ = do { cxt' <- cvtContext cxt+ ; tc' <- tconNameL tc+ ; tvs' <- cvtTvs tvs+ ; return (cxt', tc', tvs')+ }++cvt_tyinst_hdr :: TH.Cxt -> TH.Name -> [TH.Type]+ -> CvtM ( LHsContext RdrName+ , Located RdrName+ , HsImplicitBndrs RdrName [LHsType RdrName])+cvt_tyinst_hdr cxt tc tys+ = do { cxt' <- cvtContext cxt+ ; tc' <- tconNameL tc+ ; tys' <- mapM (wrap_apps <=< cvtType) tys+ ; return (cxt', tc', mkHsImplicitBndrs tys') }++----------------+cvt_tyfam_head :: TypeFamilyHead+ -> CvtM ( Located RdrName+ , LHsQTyVars RdrName+ , Hs.LFamilyResultSig RdrName+ , Maybe (Hs.LInjectivityAnn RdrName))++cvt_tyfam_head (TypeFamilyHead tc tyvars result injectivity)+ = do {(_, tc', tyvars') <- cvt_tycl_hdr [] tc tyvars+ ; result' <- cvtFamilyResultSig result+ ; injectivity' <- traverse cvtInjectivityAnnotation injectivity+ ; return (tc', tyvars', result', injectivity') }++-------------------------------------------------------------------+-- Partitioning declarations+-------------------------------------------------------------------++is_fam_decl :: LHsDecl RdrName -> Either (LFamilyDecl RdrName) (LHsDecl RdrName)+is_fam_decl (L loc (TyClD (FamDecl { tcdFam = d }))) = Left (L loc d)+is_fam_decl decl = Right decl++is_tyfam_inst :: LHsDecl RdrName -> Either (LTyFamInstDecl RdrName) (LHsDecl RdrName)+is_tyfam_inst (L loc (Hs.InstD (TyFamInstD { tfid_inst = d }))) = Left (L loc d)+is_tyfam_inst decl = Right decl++is_datafam_inst :: LHsDecl RdrName -> Either (LDataFamInstDecl RdrName) (LHsDecl RdrName)+is_datafam_inst (L loc (Hs.InstD (DataFamInstD { dfid_inst = d }))) = Left (L loc d)+is_datafam_inst decl = Right decl++is_sig :: LHsDecl RdrName -> Either (LSig RdrName) (LHsDecl RdrName)+is_sig (L loc (Hs.SigD sig)) = Left (L loc sig)+is_sig decl = Right decl++is_bind :: LHsDecl RdrName -> Either (LHsBind RdrName) (LHsDecl RdrName)+is_bind (L loc (Hs.ValD bind)) = Left (L loc bind)+is_bind decl = Right decl++mkBadDecMsg :: Outputable a => MsgDoc -> [a] -> MsgDoc+mkBadDecMsg doc bads+ = sep [ text "Illegal declaration(s) in" <+> doc <> colon+ , nest 2 (vcat (map Outputable.ppr bads)) ]++---------------------------------------------------+-- Data types+---------------------------------------------------++cvtConstr :: TH.Con -> CvtM (LConDecl RdrName)++cvtConstr (NormalC c strtys)+ = do { c' <- cNameL c+ ; cxt' <- returnL []+ ; tys' <- mapM cvt_arg strtys+ ; returnL $ mkConDeclH98 c' Nothing cxt' (PrefixCon tys') }++cvtConstr (RecC c varstrtys)+ = do { c' <- cNameL c+ ; cxt' <- returnL []+ ; args' <- mapM cvt_id_arg varstrtys+ ; returnL $ mkConDeclH98 c' Nothing cxt'+ (RecCon (noLoc args')) }++cvtConstr (InfixC st1 c st2)+ = do { c' <- cNameL c+ ; cxt' <- returnL []+ ; st1' <- cvt_arg st1+ ; st2' <- cvt_arg st2+ ; returnL $ mkConDeclH98 c' Nothing cxt' (InfixCon st1' st2') }++cvtConstr (ForallC tvs ctxt con)+ = do { tvs' <- cvtTvs tvs+ ; L loc ctxt' <- cvtContext ctxt+ ; L _ con' <- cvtConstr con+ ; returnL $ case con' of+ ConDeclGADT { con_type = conT } ->+ let hs_ty = mkHsForAllTy tvs noSrcSpan tvs' rho_ty+ rho_ty = mkHsQualTy ctxt noSrcSpan (L loc ctxt')+ (hsib_body conT)+ in con' { con_type = mkHsImplicitBndrs hs_ty }+ ConDeclH98 {} ->+ let qvars = case (tvs, con_qvars con') of+ ([], Nothing) -> Nothing+ (_ , m_qvs ) -> Just $+ mkHsQTvs (hsQTvExplicit tvs' +++ maybe [] hsQTvExplicit m_qvs)+ in con' { con_qvars = qvars+ , con_cxt = Just $+ L loc (ctxt' +++ unLoc (fromMaybe (noLoc [])+ (con_cxt con'))) } }++cvtConstr (GadtC c strtys ty)+ = do { c' <- mapM cNameL c+ ; args <- mapM cvt_arg strtys+ ; L _ ty' <- cvtType ty+ ; c_ty <- mk_arr_apps args ty'+ ; returnL $ mkGadtDecl c' (mkLHsSigType c_ty)}++cvtConstr (RecGadtC c varstrtys ty)+ = do { c' <- mapM cNameL c+ ; ty' <- cvtType ty+ ; rec_flds <- mapM cvt_id_arg varstrtys+ ; let rec_ty = noLoc (HsFunTy (noLoc $ HsRecTy rec_flds) ty')+ ; returnL $ mkGadtDecl c' (mkLHsSigType rec_ty) }++cvtSrcUnpackedness :: TH.SourceUnpackedness -> SrcUnpackedness+cvtSrcUnpackedness NoSourceUnpackedness = NoSrcUnpack+cvtSrcUnpackedness SourceNoUnpack = SrcNoUnpack+cvtSrcUnpackedness SourceUnpack = SrcUnpack++cvtSrcStrictness :: TH.SourceStrictness -> SrcStrictness+cvtSrcStrictness NoSourceStrictness = NoSrcStrict+cvtSrcStrictness SourceLazy = SrcLazy+cvtSrcStrictness SourceStrict = SrcStrict++cvt_arg :: (TH.Bang, TH.Type) -> CvtM (LHsType RdrName)+cvt_arg (Bang su ss, ty)+ = do { ty'' <- cvtType ty+ ; ty' <- wrap_apps ty''+ ; let su' = cvtSrcUnpackedness su+ ; let ss' = cvtSrcStrictness ss+ ; returnL $ HsBangTy (HsSrcBang NoSourceText su' ss') ty' }++cvt_id_arg :: (TH.Name, TH.Bang, TH.Type) -> CvtM (LConDeclField RdrName)+cvt_id_arg (i, str, ty)+ = do { L li i' <- vNameL i+ ; ty' <- cvt_arg (str,ty)+ ; return $ noLoc (ConDeclField+ { cd_fld_names+ = [L li $ FieldOcc (L li i') PlaceHolder]+ , cd_fld_type = ty'+ , cd_fld_doc = Nothing}) }++cvtDerivs :: [TH.DerivClause] -> CvtM (HsDeriving RdrName)+cvtDerivs cs = do { cs' <- mapM cvtDerivClause cs+ ; returnL cs' }++cvt_fundep :: FunDep -> CvtM (Located (Class.FunDep (Located RdrName)))+cvt_fundep (FunDep xs ys) = do { xs' <- mapM tNameL xs+ ; ys' <- mapM tNameL ys+ ; returnL (xs', ys') }+++------------------------------------------+-- Foreign declarations+------------------------------------------++cvtForD :: Foreign -> CvtM (ForeignDecl RdrName)+cvtForD (ImportF callconv safety from nm ty)+ -- the prim and javascript calling conventions do not support headers+ -- and are inserted verbatim, analogous to mkImport in RdrHsSyn+ | callconv == TH.Prim || callconv == TH.JavaScript+ = mk_imp (CImport (noLoc (cvt_conv callconv)) (noLoc safety') Nothing+ (CFunction (StaticTarget (SourceText from)+ (mkFastString from) Nothing+ True))+ (noLoc $ quotedSourceText from))+ | Just impspec <- parseCImport (noLoc (cvt_conv callconv)) (noLoc safety')+ (mkFastString (TH.nameBase nm))+ from (noLoc $ quotedSourceText from)+ = mk_imp impspec+ | otherwise+ = failWith $ text (show from) <+> text "is not a valid ccall impent"+ where+ mk_imp impspec+ = do { nm' <- vNameL nm+ ; ty' <- cvtType ty+ ; return (ForeignImport { fd_name = nm'+ , fd_sig_ty = mkLHsSigType ty'+ , fd_co = noForeignImportCoercionYet+ , fd_fi = impspec })+ }+ safety' = case safety of+ Unsafe -> PlayRisky+ Safe -> PlaySafe+ Interruptible -> PlayInterruptible++cvtForD (ExportF callconv as nm ty)+ = do { nm' <- vNameL nm+ ; ty' <- cvtType ty+ ; let e = CExport (noLoc (CExportStatic (SourceText as)+ (mkFastString as)+ (cvt_conv callconv)))+ (noLoc (SourceText as))+ ; return $ ForeignExport { fd_name = nm'+ , fd_sig_ty = mkLHsSigType ty'+ , fd_co = noForeignExportCoercionYet+ , fd_fe = e } }++cvt_conv :: TH.Callconv -> CCallConv+cvt_conv TH.CCall = CCallConv+cvt_conv TH.StdCall = StdCallConv+cvt_conv TH.CApi = CApiConv+cvt_conv TH.Prim = PrimCallConv+cvt_conv TH.JavaScript = JavaScriptCallConv++------------------------------------------+-- Pragmas+------------------------------------------++cvtPragmaD :: Pragma -> CvtM (Maybe (LHsDecl RdrName))+cvtPragmaD (InlineP nm inline rm phases)+ = do { nm' <- vNameL nm+ ; let dflt = dfltActivation inline+ ; let src TH.NoInline = "{-# NOINLINE"+ src TH.Inline = "{-# INLINE"+ src TH.Inlinable = "{-# INLINABLE"+ ; let ip = InlinePragma { inl_src = SourceText $ src inline+ , inl_inline = cvtInline inline+ , inl_rule = cvtRuleMatch rm+ , inl_act = cvtPhases phases dflt+ , inl_sat = Nothing }+ ; returnJustL $ Hs.SigD $ InlineSig nm' ip }++cvtPragmaD (SpecialiseP nm ty inline phases)+ = do { nm' <- vNameL nm+ ; ty' <- cvtType ty+ ; let src TH.NoInline = "{-# SPECIALISE NOINLINE"+ src TH.Inline = "{-# SPECIALISE INLINE"+ src TH.Inlinable = "{-# SPECIALISE INLINE"+ ; let (inline', dflt,srcText) = case inline of+ Just inline1 -> (cvtInline inline1, dfltActivation inline1,+ src inline1)+ Nothing -> (EmptyInlineSpec, AlwaysActive,+ "{-# SPECIALISE")+ ; let ip = InlinePragma { inl_src = SourceText srcText+ , inl_inline = inline'+ , inl_rule = Hs.FunLike+ , inl_act = cvtPhases phases dflt+ , inl_sat = Nothing }+ ; returnJustL $ Hs.SigD $ SpecSig nm' [mkLHsSigType ty'] ip }++cvtPragmaD (SpecialiseInstP ty)+ = do { ty' <- cvtType ty+ ; returnJustL $ Hs.SigD $+ SpecInstSig (SourceText "{-# SPECIALISE") (mkLHsSigType ty') }++cvtPragmaD (RuleP nm bndrs lhs rhs phases)+ = do { let nm' = mkFastString nm+ ; let act = cvtPhases phases AlwaysActive+ ; bndrs' <- mapM cvtRuleBndr bndrs+ ; lhs' <- cvtl lhs+ ; rhs' <- cvtl rhs+ ; returnJustL $ Hs.RuleD+ $ HsRules (SourceText "{-# RULES")+ [noLoc $ HsRule (noLoc (SourceText nm,nm')) act bndrs'+ lhs' placeHolderNames+ rhs' placeHolderNames]+ }++cvtPragmaD (AnnP target exp)+ = do { exp' <- cvtl exp+ ; target' <- case target of+ ModuleAnnotation -> return ModuleAnnProvenance+ TypeAnnotation n -> do+ n' <- tconName n+ return (TypeAnnProvenance (noLoc n'))+ ValueAnnotation n -> do+ n' <- vcName n+ return (ValueAnnProvenance (noLoc n'))+ ; returnJustL $ Hs.AnnD $ HsAnnotation (SourceText "{-# ANN") target'+ exp'+ }++cvtPragmaD (LineP line file)+ = do { setL (srcLocSpan (mkSrcLoc (fsLit file) line 1))+ ; return Nothing+ }+cvtPragmaD (CompleteP cls mty)+ = do { cls' <- noLoc <$> mapM cNameL cls+ ; mty' <- traverse tconNameL mty+ ; returnJustL $ Hs.SigD+ $ CompleteMatchSig NoSourceText cls' mty' }++dfltActivation :: TH.Inline -> Activation+dfltActivation TH.NoInline = NeverActive+dfltActivation _ = AlwaysActive++cvtInline :: TH.Inline -> Hs.InlineSpec+cvtInline TH.NoInline = Hs.NoInline+cvtInline TH.Inline = Hs.Inline+cvtInline TH.Inlinable = Hs.Inlinable++cvtRuleMatch :: TH.RuleMatch -> RuleMatchInfo+cvtRuleMatch TH.ConLike = Hs.ConLike+cvtRuleMatch TH.FunLike = Hs.FunLike++cvtPhases :: TH.Phases -> Activation -> Activation+cvtPhases AllPhases dflt = dflt+cvtPhases (FromPhase i) _ = ActiveAfter NoSourceText i+cvtPhases (BeforePhase i) _ = ActiveBefore NoSourceText i++cvtRuleBndr :: TH.RuleBndr -> CvtM (Hs.LRuleBndr RdrName)+cvtRuleBndr (RuleVar n)+ = do { n' <- vNameL n+ ; return $ noLoc $ Hs.RuleBndr n' }+cvtRuleBndr (TypedRuleVar n ty)+ = do { n' <- vNameL n+ ; ty' <- cvtType ty+ ; return $ noLoc $ Hs.RuleBndrSig n' $ mkLHsSigWcType ty' }++---------------------------------------------------+-- Declarations+---------------------------------------------------++cvtLocalDecs :: MsgDoc -> [TH.Dec] -> CvtM (HsLocalBinds RdrName)+cvtLocalDecs doc ds+ | null ds+ = return EmptyLocalBinds+ | otherwise+ = do { ds' <- cvtDecs ds+ ; let (binds, prob_sigs) = partitionWith is_bind ds'+ ; let (sigs, bads) = partitionWith is_sig prob_sigs+ ; unless (null bads) (failWith (mkBadDecMsg doc bads))+ ; return (HsValBinds (ValBindsIn (listToBag binds) sigs)) }++cvtClause :: HsMatchContext RdrName+ -> TH.Clause -> CvtM (Hs.LMatch RdrName (LHsExpr RdrName))+cvtClause ctxt (Clause ps body wheres)+ = do { ps' <- cvtPats ps+ ; pps <- mapM wrap_conpat ps'+ ; g' <- cvtGuard body+ ; ds' <- cvtLocalDecs (text "a where clause") wheres+ ; returnL $ Hs.Match ctxt pps Nothing+ (GRHSs g' (noLoc ds')) }+++-------------------------------------------------------------------+-- Expressions+-------------------------------------------------------------------++cvtl :: TH.Exp -> CvtM (LHsExpr RdrName)+cvtl e = wrapL (cvt e)+ where+ cvt (VarE s) = do { s' <- vName s; return $ HsVar (noLoc s') }+ cvt (ConE s) = do { s' <- cName s; return $ HsVar (noLoc s') }+ cvt (LitE l)+ | overloadedLit l = do { l' <- cvtOverLit l; return $ HsOverLit l' }+ | otherwise = do { l' <- cvtLit l; return $ HsLit l' }+ cvt (AppE x@(LamE _ _) y) = do { x' <- cvtl x; y' <- cvtl y+ ; return $ HsApp (mkLHsPar x') (mkLHsPar y')}+ cvt (AppE x y) = do { x' <- cvtl x; y' <- cvtl y+ ; return $ HsApp (mkLHsPar x') (mkLHsPar y')}+ cvt (AppTypeE e t) = do { e' <- cvtl e+ ; t' <- cvtType t+ ; tp <- wrap_apps t'+ ; return $ HsAppType e' $ mkHsWildCardBndrs tp }+ cvt (LamE ps e) = do { ps' <- cvtPats ps; e' <- cvtl e+ ; return $ HsLam (mkMatchGroup FromSource+ [mkSimpleMatch LambdaExpr ps' e'])}+ cvt (LamCaseE ms) = do { ms' <- mapM (cvtMatch LambdaExpr) ms+ ; return $ HsLamCase (mkMatchGroup FromSource ms')+ }+ cvt (TupE [e]) = do { e' <- cvtl e; return $ HsPar e' }+ -- Note [Dropping constructors]+ -- Singleton tuples treated like nothing (just parens)+ cvt (TupE es) = do { es' <- mapM cvtl es+ ; return $ ExplicitTuple (map (noLoc . Present) es')+ Boxed }+ cvt (UnboxedTupE es) = do { es' <- mapM cvtl es+ ; return $ ExplicitTuple+ (map (noLoc . Present) es') Unboxed }+ cvt (UnboxedSumE e alt arity) = do { e' <- cvtl e+ ; unboxedSumChecks alt arity+ ; return $ ExplicitSum+ alt arity e' placeHolderType }+ cvt (CondE x y z) = do { x' <- cvtl x; y' <- cvtl y; z' <- cvtl z;+ ; return $ HsIf (Just noSyntaxExpr) x' y' z' }+ cvt (MultiIfE alts)+ | null alts = failWith (text "Multi-way if-expression with no alternatives")+ | otherwise = do { alts' <- mapM cvtpair alts+ ; return $ HsMultiIf placeHolderType alts' }+ cvt (LetE ds e) = do { ds' <- cvtLocalDecs (text "a let expression") ds+ ; e' <- cvtl e; return $ HsLet (noLoc ds') e' }+ cvt (CaseE e ms) = do { e' <- cvtl e; ms' <- mapM (cvtMatch CaseAlt) ms+ ; return $ HsCase e' (mkMatchGroup FromSource ms') }+ cvt (DoE ss) = cvtHsDo DoExpr ss+ cvt (CompE ss) = cvtHsDo ListComp ss+ cvt (ArithSeqE dd) = do { dd' <- cvtDD dd; return $ ArithSeq noPostTcExpr Nothing dd' }+ cvt (ListE xs)+ | Just s <- allCharLs xs = do { l' <- cvtLit (StringL s); return (HsLit l') }+ -- Note [Converting strings]+ | otherwise = do { xs' <- mapM cvtl xs+ ; return $ ExplicitList placeHolderType Nothing xs'+ }++ -- Infix expressions+ cvt (InfixE (Just x) s (Just y)) = do { x' <- cvtl x; s' <- cvtl s; y' <- cvtl y+ ; wrapParL HsPar $+ OpApp (mkLHsPar x') s' undefined (mkLHsPar y') }+ -- Parenthesise both arguments and result,+ -- to ensure this operator application does+ -- does not get re-associated+ -- See Note [Operator association]+ cvt (InfixE Nothing s (Just y)) = do { s' <- cvtl s; y' <- cvtl y+ ; wrapParL HsPar $ SectionR s' y' }+ -- See Note [Sections in HsSyn] in HsExpr+ cvt (InfixE (Just x) s Nothing ) = do { x' <- cvtl x; s' <- cvtl s+ ; wrapParL HsPar $ SectionL x' s' }++ cvt (InfixE Nothing s Nothing ) = do { s' <- cvtl s; return $ HsPar s' }+ -- Can I indicate this is an infix thing?+ -- Note [Dropping constructors]++ cvt (UInfixE x s y) = do { x' <- cvtl x+ ; let x'' = case x' of+ L _ (OpApp {}) -> x'+ _ -> mkLHsPar x'+ ; cvtOpApp x'' s y } -- Note [Converting UInfix]++ cvt (ParensE e) = do { e' <- cvtl e; return $ HsPar e' }+ cvt (SigE e t) = do { e' <- cvtl e; t' <- cvtType t+ ; return $ ExprWithTySig e' (mkLHsSigWcType t') }+ cvt (RecConE c flds) = do { c' <- cNameL c+ ; flds' <- mapM (cvtFld (mkFieldOcc . noLoc)) flds+ ; return $ mkRdrRecordCon c' (HsRecFields flds' Nothing) }+ cvt (RecUpdE e flds) = do { e' <- cvtl e+ ; flds'+ <- mapM (cvtFld (mkAmbiguousFieldOcc . noLoc))+ flds+ ; return $ mkRdrRecordUpd e' flds' }+ cvt (StaticE e) = fmap (HsStatic placeHolderNames) $ cvtl e+ cvt (UnboundVarE s) = do { s' <- vName s; return $ HsVar (noLoc s') }++{- Note [Dropping constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we drop constructors from the input (for instance, when we encounter @TupE [e]@)+we must insert parentheses around the argument. Otherwise, @UInfix@ constructors in @e@+could meet @UInfix@ constructors containing the @TupE [e]@. For example:++ UInfixE x * (TupE [UInfixE y + z])++If we drop the singleton tuple but don't insert parentheses, the @UInfixE@s would meet+and the above expression would be reassociated to++ OpApp (OpApp x * y) + z++which we don't want.+-}++cvtFld :: (RdrName -> t) -> (TH.Name, TH.Exp) -> CvtM (LHsRecField' t (LHsExpr RdrName))+cvtFld f (v,e)+ = do { v' <- vNameL v; e' <- cvtl e+ ; return (noLoc $ HsRecField { hsRecFieldLbl = fmap f v'+ , hsRecFieldArg = e'+ , hsRecPun = False}) }++cvtDD :: Range -> CvtM (ArithSeqInfo RdrName)+cvtDD (FromR x) = do { x' <- cvtl x; return $ From x' }+cvtDD (FromThenR x y) = do { x' <- cvtl x; y' <- cvtl y; return $ FromThen x' y' }+cvtDD (FromToR x y) = do { x' <- cvtl x; y' <- cvtl y; return $ FromTo x' y' }+cvtDD (FromThenToR x y z) = do { x' <- cvtl x; y' <- cvtl y; z' <- cvtl z; return $ FromThenTo x' y' z' }++{- Note [Operator assocation]+We must be quite careful about adding parens:+ * Infix (UInfix ...) op arg Needs parens round the first arg+ * Infix (Infix ...) op arg Needs parens round the first arg+ * UInfix (UInfix ...) op arg No parens for first arg+ * UInfix (Infix ...) op arg Needs parens round first arg+++Note [Converting UInfix]+~~~~~~~~~~~~~~~~~~~~~~~~+When converting @UInfixE@, @UInfixP@, and @UInfixT@ values, we want to readjust+the trees to reflect the fixities of the underlying operators:++ UInfixE x * (UInfixE y + z) ---> (x * y) + z++This is done by the renamer (see @mkOppAppRn@, @mkConOppPatRn@, and+@mkHsOpTyRn@ in RnTypes), which expects that the input will be completely+right-biased for types and left-biased for everything else. So we left-bias the+trees of @UInfixP@ and @UInfixE@ and use HsAppsTy for UInfixT.++Sample input:++ UInfixE+ (UInfixE x op1 y)+ op2+ (UInfixE z op3 w)++Sample output:++ OpApp+ (OpApp+ (OpApp x op1 y)+ op2+ z)+ op3+ w++The functions @cvtOpApp@, @cvtOpAppP@, and @cvtOpAppT@ are responsible for this+biasing.+-}++{- | @cvtOpApp x op y@ converts @op@ and @y@ and produces the operator application @x `op` y@.+The produced tree of infix expressions will be left-biased, provided @x@ is.++We can see that @cvtOpApp@ is correct as follows. The inductive hypothesis+is that @cvtOpApp x op y@ is left-biased, provided @x@ is. It is clear that+this holds for both branches (of @cvtOpApp@), provided we assume it holds for+the recursive calls to @cvtOpApp@.++When we call @cvtOpApp@ from @cvtl@, the first argument will always be left-biased+since we have already run @cvtl@ on it.+-}+cvtOpApp :: LHsExpr RdrName -> TH.Exp -> TH.Exp -> CvtM (HsExpr RdrName)+cvtOpApp x op1 (UInfixE y op2 z)+ = do { l <- wrapL $ cvtOpApp x op1 y+ ; cvtOpApp l op2 z }+cvtOpApp x op y+ = do { op' <- cvtl op+ ; y' <- cvtl y+ ; return (OpApp x op' undefined y') }++-------------------------------------+-- Do notation and statements+-------------------------------------++cvtHsDo :: HsStmtContext Name.Name -> [TH.Stmt] -> CvtM (HsExpr RdrName)+cvtHsDo do_or_lc stmts+ | null stmts = failWith (text "Empty stmt list in do-block")+ | otherwise+ = do { stmts' <- cvtStmts stmts+ ; let Just (stmts'', last') = snocView stmts'++ ; last'' <- case last' of+ L loc (BodyStmt body _ _ _) -> return (L loc (mkLastStmt body))+ _ -> failWith (bad_last last')++ ; return $ HsDo do_or_lc (noLoc (stmts'' ++ [last''])) placeHolderType }+ where+ bad_last stmt = vcat [ text "Illegal last statement of" <+> pprAStmtContext do_or_lc <> colon+ , nest 2 $ Outputable.ppr stmt+ , text "(It should be an expression.)" ]++cvtStmts :: [TH.Stmt] -> CvtM [Hs.LStmt RdrName (LHsExpr RdrName)]+cvtStmts = mapM cvtStmt++cvtStmt :: TH.Stmt -> CvtM (Hs.LStmt RdrName (LHsExpr RdrName))+cvtStmt (NoBindS e) = do { e' <- cvtl e; returnL $ mkBodyStmt e' }+cvtStmt (TH.BindS p e) = do { p' <- cvtPat p; e' <- cvtl e; returnL $ mkBindStmt p' e' }+cvtStmt (TH.LetS ds) = do { ds' <- cvtLocalDecs (text "a let binding") ds+ ; returnL $ LetStmt (noLoc ds') }+cvtStmt (TH.ParS dss) = do { dss' <- mapM cvt_one dss; returnL $ ParStmt dss' noExpr noSyntaxExpr placeHolderType }+ where+ cvt_one ds = do { ds' <- cvtStmts ds; return (ParStmtBlock ds' undefined noSyntaxExpr) }++cvtMatch :: HsMatchContext RdrName+ -> TH.Match -> CvtM (Hs.LMatch RdrName (LHsExpr RdrName))+cvtMatch ctxt (TH.Match p body decs)+ = do { p' <- cvtPat p+ ; lp <- case ctxt of+ CaseAlt -> return p'+ _ -> wrap_conpat p'+ ; g' <- cvtGuard body+ ; decs' <- cvtLocalDecs (text "a where clause") decs+ ; returnL $ Hs.Match ctxt [lp] Nothing+ (GRHSs g' (noLoc decs')) }++cvtGuard :: TH.Body -> CvtM [LGRHS RdrName (LHsExpr RdrName)]+cvtGuard (GuardedB pairs) = mapM cvtpair pairs+cvtGuard (NormalB e) = do { e' <- cvtl e; g' <- returnL $ GRHS [] e'; return [g'] }++cvtpair :: (TH.Guard, TH.Exp) -> CvtM (LGRHS RdrName (LHsExpr RdrName))+cvtpair (NormalG ge,rhs) = do { ge' <- cvtl ge; rhs' <- cvtl rhs+ ; g' <- returnL $ mkBodyStmt ge'+ ; returnL $ GRHS [g'] rhs' }+cvtpair (PatG gs,rhs) = do { gs' <- cvtStmts gs; rhs' <- cvtl rhs+ ; returnL $ GRHS gs' rhs' }++cvtOverLit :: Lit -> CvtM (HsOverLit RdrName)+cvtOverLit (IntegerL i)+ = do { force i; return $ mkHsIntegral NoSourceText i placeHolderType}+cvtOverLit (RationalL r)+ = do { force r; return $ mkHsFractional (cvtFractionalLit r) placeHolderType}+cvtOverLit (StringL s)+ = do { let { s' = mkFastString s }+ ; force s'+ ; return $ mkHsIsString (quotedSourceText s) s' placeHolderType+ }+cvtOverLit _ = panic "Convert.cvtOverLit: Unexpected overloaded literal"+-- An Integer is like an (overloaded) '3' in a Haskell source program+-- Similarly 3.5 for fractionals++{- Note [Converting strings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we get (ListE [CharL 'x', CharL 'y']) we'd like to convert to+a string literal for "xy". Of course, we might hope to get+(LitE (StringL "xy")), but not always, and allCharLs fails quickly+if it isn't a literal string+-}++allCharLs :: [TH.Exp] -> Maybe String+-- Note [Converting strings]+-- NB: only fire up this setup for a non-empty list, else+-- there's a danger of returning "" for [] :: [Int]!+allCharLs xs+ = case xs of+ LitE (CharL c) : ys -> go [c] ys+ _ -> Nothing+ where+ go cs [] = Just (reverse cs)+ go cs (LitE (CharL c) : ys) = go (c:cs) ys+ go _ _ = Nothing++cvtLit :: Lit -> CvtM HsLit+cvtLit (IntPrimL i) = do { force i; return $ HsIntPrim NoSourceText i }+cvtLit (WordPrimL w) = do { force w; return $ HsWordPrim NoSourceText w }+cvtLit (FloatPrimL f) = do { force f; return $ HsFloatPrim (cvtFractionalLit f) }+cvtLit (DoublePrimL f) = do { force f; return $ HsDoublePrim (cvtFractionalLit f) }+cvtLit (CharL c) = do { force c; return $ HsChar NoSourceText c }+cvtLit (CharPrimL c) = do { force c; return $ HsCharPrim NoSourceText c }+cvtLit (StringL s) = do { let { s' = mkFastString s }+ ; force s'+ ; return $ HsString (quotedSourceText s) s' }+cvtLit (StringPrimL s) = do { let { s' = BS.pack s }+ ; force s'+ ; return $ HsStringPrim NoSourceText s' }+cvtLit _ = panic "Convert.cvtLit: Unexpected literal"+ -- cvtLit should not be called on IntegerL, RationalL+ -- That precondition is established right here in+ -- Convert.hs, hence panic++quotedSourceText :: String -> SourceText+quotedSourceText s = SourceText $ "\"" ++ s ++ "\""++cvtPats :: [TH.Pat] -> CvtM [Hs.LPat RdrName]+cvtPats pats = mapM cvtPat pats++cvtPat :: TH.Pat -> CvtM (Hs.LPat RdrName)+cvtPat pat = wrapL (cvtp pat)++cvtp :: TH.Pat -> CvtM (Hs.Pat RdrName)+cvtp (TH.LitP l)+ | overloadedLit l = do { l' <- cvtOverLit l+ ; return (mkNPat (noLoc l') Nothing) }+ -- Not right for negative patterns;+ -- need to think about that!+ | otherwise = do { l' <- cvtLit l; return $ Hs.LitPat l' }+cvtp (TH.VarP s) = do { s' <- vName s; return $ Hs.VarPat (noLoc s') }+cvtp (TupP [p]) = do { p' <- cvtPat p; return $ ParPat p' } -- Note [Dropping constructors]+cvtp (TupP ps) = do { ps' <- cvtPats ps; return $ TuplePat ps' Boxed [] }+cvtp (UnboxedTupP ps) = do { ps' <- cvtPats ps; return $ TuplePat ps' Unboxed [] }+cvtp (UnboxedSumP p alt arity)+ = do { p' <- cvtPat p+ ; unboxedSumChecks alt arity+ ; return $ SumPat p' alt arity placeHolderType }+cvtp (ConP s ps) = do { s' <- cNameL s; ps' <- cvtPats ps+ ; pps <- mapM wrap_conpat ps'+ ; return $ ConPatIn s' (PrefixCon pps) }+cvtp (InfixP p1 s p2) = do { s' <- cNameL s; p1' <- cvtPat p1; p2' <- cvtPat p2+ ; wrapParL ParPat $+ ConPatIn s' (InfixCon (mkParPat p1') (mkParPat p2')) }+ -- See Note [Operator association]+cvtp (UInfixP p1 s p2) = do { p1' <- cvtPat p1; cvtOpAppP p1' s p2 } -- Note [Converting UInfix]+cvtp (ParensP p) = do { p' <- cvtPat p;+ ; case p' of -- may be wrapped ConPatIn+ (L _ (ParPat {})) -> return $ unLoc p'+ _ -> return $ ParPat p' }+cvtp (TildeP p) = do { p' <- cvtPat p; return $ LazyPat p' }+cvtp (BangP p) = do { p' <- cvtPat p; return $ BangPat p' }+cvtp (TH.AsP s p) = do { s' <- vNameL s; p' <- cvtPat p; return $ AsPat s' p' }+cvtp TH.WildP = return $ WildPat placeHolderType+cvtp (RecP c fs) = do { c' <- cNameL c; fs' <- mapM cvtPatFld fs+ ; return $ ConPatIn c'+ $ Hs.RecCon (HsRecFields fs' Nothing) }+cvtp (ListP ps) = do { ps' <- cvtPats ps+ ; return $ ListPat ps' placeHolderType Nothing }+cvtp (SigP p t) = do { p' <- cvtPat p; t' <- cvtType t+ ; return $ SigPatIn p' (mkLHsSigWcType t') }+cvtp (ViewP e p) = do { e' <- cvtl e; p' <- cvtPat p+ ; return $ ViewPat e' p' placeHolderType }++cvtPatFld :: (TH.Name, TH.Pat) -> CvtM (LHsRecField RdrName (LPat RdrName))+cvtPatFld (s,p)+ = do { L ls s' <- vNameL s; p' <- cvtPat p+ ; return (noLoc $ HsRecField { hsRecFieldLbl+ = L ls $ mkFieldOcc (L ls s')+ , hsRecFieldArg = p'+ , hsRecPun = False}) }++wrap_conpat :: Hs.LPat RdrName -> CvtM (Hs.LPat RdrName)+wrap_conpat p@(L _ (ConPatIn _ (InfixCon{}))) = returnL $ ParPat p+wrap_conpat p@(L _ (ConPatIn _ (PrefixCon []))) = return p+wrap_conpat p@(L _ (ConPatIn _ (PrefixCon _))) = returnL $ ParPat p+wrap_conpat p = return p++{- | @cvtOpAppP x op y@ converts @op@ and @y@ and produces the operator application @x `op` y@.+The produced tree of infix patterns will be left-biased, provided @x@ is.++See the @cvtOpApp@ documentation for how this function works.+-}+cvtOpAppP :: Hs.LPat RdrName -> TH.Name -> TH.Pat -> CvtM (Hs.Pat RdrName)+cvtOpAppP x op1 (UInfixP y op2 z)+ = do { l <- wrapL $ cvtOpAppP x op1 y+ ; cvtOpAppP l op2 z }+cvtOpAppP x op y+ = do { op' <- cNameL op+ ; y' <- cvtPat y+ ; return (ConPatIn op' (InfixCon x y')) }++-----------------------------------------------------------+-- Types and type variables++cvtTvs :: [TH.TyVarBndr] -> CvtM (LHsQTyVars RdrName)+cvtTvs tvs = do { tvs' <- mapM cvt_tv tvs; return (mkHsQTvs tvs') }++cvt_tv :: TH.TyVarBndr -> CvtM (LHsTyVarBndr RdrName)+cvt_tv (TH.PlainTV nm)+ = do { nm' <- tNameL nm+ ; returnL $ UserTyVar nm' }+cvt_tv (TH.KindedTV nm ki)+ = do { nm' <- tNameL nm+ ; ki' <- cvtKind ki+ ; returnL $ KindedTyVar nm' ki' }++cvtRole :: TH.Role -> Maybe Coercion.Role+cvtRole TH.NominalR = Just Coercion.Nominal+cvtRole TH.RepresentationalR = Just Coercion.Representational+cvtRole TH.PhantomR = Just Coercion.Phantom+cvtRole TH.InferR = Nothing++cvtContext :: TH.Cxt -> CvtM (LHsContext RdrName)+cvtContext tys = do { preds' <- mapM cvtPred tys; returnL preds' }++cvtPred :: TH.Pred -> CvtM (LHsType RdrName)+cvtPred = cvtType++cvtDerivClause :: TH.DerivClause+ -> CvtM (LHsDerivingClause RdrName)+cvtDerivClause (TH.DerivClause ds ctxt)+ = do { ctxt'@(L loc _) <- fmap (map mkLHsSigType) <$> cvtContext ctxt+ ; let ds' = fmap (L loc . cvtDerivStrategy) ds+ ; returnL $ HsDerivingClause ds' ctxt' }++cvtDerivStrategy :: TH.DerivStrategy -> Hs.DerivStrategy+cvtDerivStrategy TH.StockStrategy = Hs.StockStrategy+cvtDerivStrategy TH.AnyclassStrategy = Hs.AnyclassStrategy+cvtDerivStrategy TH.NewtypeStrategy = Hs.NewtypeStrategy++cvtType :: TH.Type -> CvtM (LHsType RdrName)+cvtType = cvtTypeKind "type"++cvtTypeKind :: String -> TH.Type -> CvtM (LHsType RdrName)+cvtTypeKind ty_str ty+ = do { (head_ty, tys') <- split_ty_app ty+ ; case head_ty of+ TupleT n+ | length tys' == n -- Saturated+ -> if n==1 then return (head tys') -- Singleton tuples treated+ -- like nothing (ie just parens)+ else returnL (HsTupleTy HsBoxedOrConstraintTuple tys')+ | n == 1+ -> failWith (ptext (sLit ("Illegal 1-tuple " ++ ty_str ++ " constructor")))+ | otherwise+ -> mk_apps (HsTyVar NotPromoted+ (noLoc (getRdrName (tupleTyCon Boxed n)))) tys'+ UnboxedTupleT n+ | length tys' == n -- Saturated+ -> returnL (HsTupleTy HsUnboxedTuple tys')+ | otherwise+ -> mk_apps (HsTyVar NotPromoted+ (noLoc (getRdrName (tupleTyCon Unboxed n)))) tys'+ UnboxedSumT n+ | n < 2+ -> failWith $+ vcat [ text "Illegal sum arity:" <+> text (show n)+ , nest 2 $+ text "Sums must have an arity of at least 2" ]+ | length tys' == n -- Saturated+ -> returnL (HsSumTy tys')+ | otherwise+ -> mk_apps (HsTyVar NotPromoted (noLoc (getRdrName (sumTyCon n))))+ tys'+ ArrowT+ | [x',y'] <- tys' -> returnL (HsFunTy x' y')+ | otherwise ->+ mk_apps (HsTyVar NotPromoted (noLoc (getRdrName funTyCon)))+ tys'+ ListT+ | [x'] <- tys' -> returnL (HsListTy x')+ | otherwise ->+ mk_apps (HsTyVar NotPromoted (noLoc (getRdrName listTyCon)))+ tys'+ VarT nm -> do { nm' <- tNameL nm+ ; mk_apps (HsTyVar NotPromoted nm') tys' }+ ConT nm -> do { nm' <- tconName nm+ ; mk_apps (HsTyVar NotPromoted (noLoc nm')) tys' }++ ForallT tvs cxt ty+ | null tys'+ -> do { tvs' <- cvtTvs tvs+ ; cxt' <- cvtContext cxt+ ; ty' <- cvtType ty+ ; loc <- getL+ ; let hs_ty = mkHsForAllTy tvs loc tvs' rho_ty+ rho_ty = mkHsQualTy cxt loc cxt' ty'++ ; return hs_ty }++ SigT ty ki+ -> do { ty' <- cvtType ty+ ; ki' <- cvtKind ki+ ; mk_apps (HsKindSig ty' ki') tys'+ }++ LitT lit+ -> returnL (HsTyLit (cvtTyLit lit))++ WildCardT+ -> mk_apps mkAnonWildCardTy tys'++ InfixT t1 s t2+ -> do { s' <- tconName s+ ; t1' <- cvtType t1+ ; t2' <- cvtType t2+ ; mk_apps (HsTyVar NotPromoted (noLoc s')) [t1', t2']+ }++ UInfixT t1 s t2+ -> do { t1' <- cvtType t1+ ; t2' <- cvtType t2+ ; s' <- tconName s+ ; return $ cvtOpAppT t1' s' t2'+ } -- Note [Converting UInfix]++ ParensT t+ -> do { t' <- cvtType t+ ; returnL $ HsParTy t'+ }++ PromotedT nm -> do { nm' <- cName nm+ ; mk_apps (HsTyVar NotPromoted (noLoc nm')) tys' }+ -- Promoted data constructor; hence cName++ PromotedTupleT n+ | n == 1+ -> failWith (ptext (sLit ("Illegal promoted 1-tuple " ++ ty_str)))+ | m == n -- Saturated+ -> do { let kis = replicate m placeHolderKind+ ; returnL (HsExplicitTupleTy kis tys')+ }+ where+ m = length tys'++ PromotedNilT+ -> returnL (HsExplicitListTy Promoted placeHolderKind [])++ PromotedConsT -- See Note [Representing concrete syntax in types]+ -- in Language.Haskell.TH.Syntax+ | [ty1, L _ (HsExplicitListTy ip _ tys2)] <- tys'+ -> returnL (HsExplicitListTy ip placeHolderKind (ty1:tys2))+ | otherwise+ -> mk_apps (HsTyVar NotPromoted (noLoc (getRdrName consDataCon)))+ tys'++ StarT+ -> returnL (HsTyVar NotPromoted (noLoc+ (getRdrName liftedTypeKindTyCon)))++ ConstraintT+ -> returnL (HsTyVar NotPromoted+ (noLoc (getRdrName constraintKindTyCon)))++ EqualityT+ | [x',y'] <- tys' -> returnL (HsEqTy x' y')+ | otherwise ->+ mk_apps (HsTyVar NotPromoted+ (noLoc (getRdrName eqPrimTyCon))) tys'++ _ -> failWith (ptext (sLit ("Malformed " ++ ty_str)) <+> text (show ty))+ }++-- | Constructs an application of a type to arguments passed in a list.+mk_apps :: HsType RdrName -> [LHsType RdrName] -> CvtM (LHsType RdrName)+mk_apps head_ty [] = returnL head_ty+mk_apps head_ty (ty:tys) =+ do { head_ty' <- returnL head_ty+ ; p_ty <- add_parens ty+ ; mk_apps (HsAppTy head_ty' p_ty) tys }+ where+ add_parens t@(L _ HsAppTy{}) = returnL (HsParTy t)+ add_parens t = return t++wrap_apps :: LHsType RdrName -> CvtM (LHsType RdrName)+wrap_apps t@(L _ HsAppTy {}) = returnL (HsParTy t)+wrap_apps t = return t++-- | Constructs an arrow type with a specified return type+mk_arr_apps :: [LHsType RdrName] -> HsType RdrName -> CvtM (LHsType RdrName)+mk_arr_apps tys return_ty = foldrM go return_ty tys >>= returnL+ where go :: LHsType RdrName -> HsType RdrName -> CvtM (HsType RdrName)+ go arg ret_ty = do { ret_ty_l <- returnL ret_ty+ ; return (HsFunTy arg ret_ty_l) }++split_ty_app :: TH.Type -> CvtM (TH.Type, [LHsType RdrName])+split_ty_app ty = go ty []+ where+ go (AppT f a) as' = do { a' <- cvtType a; go f (a':as') }+ go f as = return (f,as)++cvtTyLit :: TH.TyLit -> HsTyLit+cvtTyLit (TH.NumTyLit i) = HsNumTy NoSourceText i+cvtTyLit (TH.StrTyLit s) = HsStrTy NoSourceText (fsLit s)++{- | @cvtOpAppT x op y@ takes converted arguments and flattens any HsAppsTy+ structure in them.+-}+cvtOpAppT :: LHsType RdrName -> RdrName -> LHsType RdrName -> LHsType RdrName+cvtOpAppT t1@(L loc1 _) op t2@(L loc2 _)+ = L (combineSrcSpans loc1 loc2) $+ HsAppsTy (t1' ++ [noLoc $ HsAppInfix (noLoc op)] ++ t2')+ where+ t1' | L _ (HsAppsTy t1s) <- t1+ = t1s+ | otherwise+ = [noLoc $ HsAppPrefix t1]++ t2' | L _ (HsAppsTy t2s) <- t2+ = t2s+ | otherwise+ = [noLoc $ HsAppPrefix t2]++cvtKind :: TH.Kind -> CvtM (LHsKind RdrName)+cvtKind = cvtTypeKind "kind"++-- | Convert Maybe Kind to a type family result signature. Used with data+-- families where naming of the result is not possible (thus only kind or no+-- signature is possible).+cvtMaybeKindToFamilyResultSig :: Maybe TH.Kind+ -> CvtM (LFamilyResultSig RdrName)+cvtMaybeKindToFamilyResultSig Nothing = returnL Hs.NoSig+cvtMaybeKindToFamilyResultSig (Just ki) = do { ki' <- cvtKind ki+ ; returnL (Hs.KindSig ki') }++-- | Convert type family result signature. Used with both open and closed type+-- families.+cvtFamilyResultSig :: TH.FamilyResultSig -> CvtM (Hs.LFamilyResultSig RdrName)+cvtFamilyResultSig TH.NoSig = returnL Hs.NoSig+cvtFamilyResultSig (TH.KindSig ki) = do { ki' <- cvtKind ki+ ; returnL (Hs.KindSig ki') }+cvtFamilyResultSig (TH.TyVarSig bndr) = do { tv <- cvt_tv bndr+ ; returnL (Hs.TyVarSig tv) }++-- | Convert injectivity annotation of a type family.+cvtInjectivityAnnotation :: TH.InjectivityAnn+ -> CvtM (Hs.LInjectivityAnn RdrName)+cvtInjectivityAnnotation (TH.InjectivityAnn annLHS annRHS)+ = do { annLHS' <- tNameL annLHS+ ; annRHS' <- mapM tNameL annRHS+ ; returnL (Hs.InjectivityAnn annLHS' annRHS') }++cvtPatSynSigTy :: TH.Type -> CvtM (LHsType RdrName)+-- pattern synonym types are of peculiar shapes, which is why we treat+-- them separately from regular types;+-- see Note [Pattern synonym type signatures and Template Haskell]+cvtPatSynSigTy (ForallT univs reqs (ForallT exis provs ty))+ | null exis, null provs = cvtType (ForallT univs reqs ty)+ | null univs, null reqs = do { l <- getL+ ; ty' <- cvtType (ForallT exis provs ty)+ ; return $ L l (HsQualTy { hst_ctxt = L l []+ , hst_body = ty' }) }+ | null reqs = do { l <- getL+ ; univs' <- hsQTvExplicit <$> cvtTvs univs+ ; ty' <- cvtType (ForallT exis provs ty)+ ; let forTy = HsForAllTy { hst_bndrs = univs'+ , hst_body = L l cxtTy }+ cxtTy = HsQualTy { hst_ctxt = L l []+ , hst_body = ty' }+ ; return $ L l forTy }+ | otherwise = cvtType (ForallT univs reqs (ForallT exis provs ty))+cvtPatSynSigTy ty = cvtType ty++-----------------------------------------------------------+cvtFixity :: TH.Fixity -> Hs.Fixity+cvtFixity (TH.Fixity prec dir) = Hs.Fixity NoSourceText prec (cvt_dir dir)+ where+ cvt_dir TH.InfixL = Hs.InfixL+ cvt_dir TH.InfixR = Hs.InfixR+ cvt_dir TH.InfixN = Hs.InfixN++-----------------------------------------------------------+++-----------------------------------------------------------+-- some useful things++overloadedLit :: Lit -> Bool+-- True for literals that Haskell treats as overloaded+overloadedLit (IntegerL _) = True+overloadedLit (RationalL _) = True+overloadedLit _ = False++cvtFractionalLit :: Rational -> FractionalLit+cvtFractionalLit r = FL { fl_text = show (fromRational r :: Double), fl_value = r }++-- Checks that are performed when converting unboxed sum expressions and+-- patterns alike.+unboxedSumChecks :: TH.SumAlt -> TH.SumArity -> CvtM ()+unboxedSumChecks alt arity+ | alt > arity+ = failWith $ text "Sum alternative" <+> text (show alt)+ <+> text "exceeds its arity," <+> text (show arity)+ | alt <= 0+ = failWith $ vcat [ text "Illegal sum alternative:" <+> text (show alt)+ , nest 2 $ text "Sum alternatives must start from 1" ]+ | arity < 2+ = failWith $ vcat [ text "Illegal sum arity:" <+> text (show arity)+ , nest 2 $ text "Sums must have an arity of at least 2" ]+ | otherwise+ = return ()++-- | If passed an empty list of 'TH.TyVarBndr's, this simply returns the+-- third argument (an 'LHsType'). Otherwise, return an 'HsForAllTy'+-- using the provided 'LHsQTyVars' and 'LHsType'.+mkHsForAllTy :: [TH.TyVarBndr]+ -- ^ The original Template Haskell type variable binders+ -> SrcSpan+ -- ^ The location of the returned 'LHsType' if it needs an+ -- explicit forall+ -> LHsQTyVars name+ -- ^ The converted type variable binders+ -> LHsType name+ -- ^ The converted rho type+ -> LHsType name+ -- ^ The complete type, quantified with a forall if necessary+mkHsForAllTy tvs loc tvs' rho_ty+ | null tvs = rho_ty+ | otherwise = L loc $ HsForAllTy { hst_bndrs = hsQTvExplicit tvs'+ , hst_body = rho_ty }++-- | If passed an empty 'TH.Cxt', this simply returns the third argument+-- (an 'LHsType'). Otherwise, return an 'HsQualTy' using the provided+-- 'LHsContext' and 'LHsType'.++-- It's important that we don't build an HsQualTy if the context is empty,+-- as the pretty-printer for HsType _always_ prints contexts, even if+-- they're empty. See Trac #13183.+mkHsQualTy :: TH.Cxt+ -- ^ The original Template Haskell context+ -> SrcSpan+ -- ^ The location of the returned 'LHsType' if it needs an+ -- explicit context+ -> LHsContext name+ -- ^ The converted context+ -> LHsType name+ -- ^ The converted tau type+ -> LHsType name+ -- ^ The complete type, qualified with a context if necessary+mkHsQualTy ctxt loc ctxt' ty+ | null ctxt = ty+ | otherwise = L loc $ HsQualTy { hst_ctxt = ctxt', hst_body = ty }++--------------------------------------------------------------------+-- Turning Name back into RdrName+--------------------------------------------------------------------++-- variable names+vNameL, cNameL, vcNameL, tNameL, tconNameL :: TH.Name -> CvtM (Located RdrName)+vName, cName, vcName, tName, tconName :: TH.Name -> CvtM RdrName++-- Variable names+vNameL n = wrapL (vName n)+vName n = cvtName OccName.varName n++-- Constructor function names; this is Haskell source, hence srcDataName+cNameL n = wrapL (cName n)+cName n = cvtName OccName.dataName n++-- Variable *or* constructor names; check by looking at the first char+vcNameL n = wrapL (vcName n)+vcName n = if isVarName n then vName n else cName n++-- Type variable names+tNameL n = wrapL (tName n)+tName n = cvtName OccName.tvName n++-- Type Constructor names+tconNameL n = wrapL (tconName n)+tconName n = cvtName OccName.tcClsName n++cvtName :: OccName.NameSpace -> TH.Name -> CvtM RdrName+cvtName ctxt_ns (TH.Name occ flavour)+ | not (okOcc ctxt_ns occ_str) = failWith (badOcc ctxt_ns occ_str)+ | otherwise+ = do { loc <- getL+ ; let rdr_name = thRdrName loc ctxt_ns occ_str flavour+ ; force rdr_name+ ; return rdr_name }+ where+ occ_str = TH.occString occ++okOcc :: OccName.NameSpace -> String -> Bool+okOcc ns str+ | OccName.isVarNameSpace ns = okVarOcc str+ | OccName.isDataConNameSpace ns = okConOcc str+ | otherwise = okTcOcc str++-- Determine the name space of a name in a type+--+isVarName :: TH.Name -> Bool+isVarName (TH.Name occ _)+ = case TH.occString occ of+ "" -> False+ (c:_) -> startsVarId c || startsVarSym c++badOcc :: OccName.NameSpace -> String -> SDoc+badOcc ctxt_ns occ+ = text "Illegal" <+> pprNameSpace ctxt_ns+ <+> text "name:" <+> quotes (text occ)++thRdrName :: SrcSpan -> OccName.NameSpace -> String -> TH.NameFlavour -> RdrName+-- This turns a TH Name into a RdrName; used for both binders and occurrences+-- See Note [Binders in Template Haskell]+-- The passed-in name space tells what the context is expecting;+-- use it unless the TH name knows what name-space it comes+-- from, in which case use the latter+--+-- We pass in a SrcSpan (gotten from the monad) because this function+-- is used for *binders* and if we make an Exact Name we want it+-- to have a binding site inside it. (cf Trac #5434)+--+-- ToDo: we may generate silly RdrNames, by passing a name space+-- that doesn't match the string, like VarName ":+",+-- which will give confusing error messages later+--+-- The strict applications ensure that any buried exceptions get forced+thRdrName loc ctxt_ns th_occ th_name+ = case th_name of+ TH.NameG th_ns pkg mod -> thOrigRdrName th_occ th_ns pkg mod+ TH.NameQ mod -> (mkRdrQual $! mk_mod mod) $! occ+ TH.NameL uniq -> nameRdrName $! (((Name.mkInternalName $! mk_uniq uniq) $! occ) loc)+ TH.NameU uniq -> nameRdrName $! (((Name.mkSystemNameAt $! mk_uniq uniq) $! occ) loc)+ TH.NameS | Just name <- isBuiltInOcc_maybe occ -> nameRdrName $! name+ | otherwise -> mkRdrUnqual $! occ+ -- We check for built-in syntax here, because the TH+ -- user might have written a (NameS "(,,)"), for example+ where+ occ :: OccName.OccName+ occ = mk_occ ctxt_ns th_occ++thOrigRdrName :: String -> TH.NameSpace -> PkgName -> ModName -> RdrName+thOrigRdrName occ th_ns pkg mod = (mkOrig $! (mkModule (mk_pkg pkg) (mk_mod mod))) $! (mk_occ (mk_ghc_ns th_ns) occ)++thRdrNameGuesses :: TH.Name -> [RdrName]+thRdrNameGuesses (TH.Name occ flavour)+ -- This special case for NameG ensures that we don't generate duplicates in the output list+ | TH.NameG th_ns pkg mod <- flavour = [ thOrigRdrName occ_str th_ns pkg mod]+ | otherwise = [ thRdrName noSrcSpan gns occ_str flavour+ | gns <- guessed_nss]+ where+ -- guessed_ns are the name spaces guessed from looking at the TH name+ guessed_nss | isLexCon (mkFastString occ_str) = [OccName.tcName, OccName.dataName]+ | otherwise = [OccName.varName, OccName.tvName]+ occ_str = TH.occString occ++-- The packing and unpacking is rather turgid :-(+mk_occ :: OccName.NameSpace -> String -> OccName.OccName+mk_occ ns occ = OccName.mkOccName ns occ++mk_ghc_ns :: TH.NameSpace -> OccName.NameSpace+mk_ghc_ns TH.DataName = OccName.dataName+mk_ghc_ns TH.TcClsName = OccName.tcClsName+mk_ghc_ns TH.VarName = OccName.varName++mk_mod :: TH.ModName -> ModuleName+mk_mod mod = mkModuleName (TH.modString mod)++mk_pkg :: TH.PkgName -> UnitId+mk_pkg pkg = stringToUnitId (TH.pkgString pkg)++mk_uniq :: Int -> Unique+mk_uniq u = mkUniqueGrimily u++{-+Note [Binders in Template Haskell]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this TH term construction:+ do { x1 <- TH.newName "x" -- newName :: String -> Q TH.Name+ ; x2 <- TH.newName "x" -- Builds a NameU+ ; x3 <- TH.newName "x"++ ; let x = mkName "x" -- mkName :: String -> TH.Name+ -- Builds a NameS++ ; return (LamE (..pattern [x1,x2]..) $+ LamE (VarPat x3) $+ ..tuple (x1,x2,x3,x)) }++It represents the term \[x1,x2]. \x3. (x1,x2,x3,x)++a) We don't want to complain about "x" being bound twice in+ the pattern [x1,x2]+b) We don't want x3 to shadow the x1,x2+c) We *do* want 'x' (dynamically bound with mkName) to bind+ to the innermost binding of "x", namely x3.+d) When pretty printing, we want to print a unique with x1,x2+ etc, else they'll all print as "x" which isn't very helpful++When we convert all this to HsSyn, the TH.Names are converted with+thRdrName. To achieve (b) we want the binders to be Exact RdrNames.+Achieving (a) is a bit awkward, because+ - We must check for duplicate and shadowed names on Names,+ not RdrNames, *after* renaming.+ See Note [Collect binders only after renaming] in HsUtils++ - But to achieve (a) we must distinguish between the Exact+ RdrNames arising from TH and the Unqual RdrNames that would+ come from a user writing \[x,x] -> blah++So in Convert.thRdrName we translate+ TH Name RdrName+ --------------------------------------------------------+ NameU (arising from newName) --> Exact (Name{ System })+ NameS (arising from mkName) --> Unqual++Notice that the NameUs generate *System* Names. Then, when+figuring out shadowing and duplicates, we can filter out+System Names.++This use of System Names fits with other uses of System Names, eg for+temporary variables "a". Since there are lots of things called "a" we+usually want to print the name with the unique, and that is indeed+the way System Names are printed.++There's a small complication of course; see Note [Looking up Exact+RdrNames] in RnEnv.+-}++{-+Note [Pattern synonym type signatures and Template Haskell]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++In general, the type signature of a pattern synonym++ pattern P x1 x2 .. xn = <some-pattern>++is of the form++ forall univs. reqs => forall exis. provs => t1 -> t2 -> ... -> tn -> t++with the following parts:++ 1) the (possibly empty lists of) universally quantified type+ variables `univs` and required constraints `reqs` on them.+ 2) the (possibly empty lists of) existentially quantified type+ variables `exis` and the provided constraints `provs` on them.+ 3) the types `t1`, `t2`, .., `tn` of the pattern synonym's arguments x1,+ x2, .., xn, respectively+ 4) the type `t` of <some-pattern>, mentioning only universals from `univs`.++Due to the two forall quantifiers and constraint contexts (either of+which might be empty), pattern synonym type signatures are treated+specially in `deSugar/DsMeta.hs`, `hsSyn/Convert.hs`, and+`typecheck/TcSplice.hs`:++ (a) When desugaring a pattern synonym from HsSyn to TH.Dec in+ `deSugar/DsMeta.hs`, we represent its *full* type signature in TH, i.e.:++ ForallT univs reqs (ForallT exis provs ty)+ (where ty is the AST representation of t1 -> t2 -> ... -> tn -> t)++ (b) When converting pattern synonyms from TH.Dec to HsSyn in+ `hsSyn/Convert.hs`, we convert their TH type signatures back to an+ appropriate Haskell pattern synonym type of the form++ forall univs. reqs => forall exis. provs => t1 -> t2 -> ... -> tn -> t++ where initial empty `univs` type variables or an empty `reqs`+ constraint context are represented *explicitly* as `() =>`.++ (c) When reifying a pattern synonym in `typecheck/TcSplice.hs`, we always+ return its *full* type, i.e.:++ ForallT univs reqs (ForallT exis provs ty)+ (where ty is the AST representation of t1 -> t2 -> ... -> tn -> t)++The key point is to always represent a pattern synonym's *full* type+in cases (a) and (c) to make it clear which of the two forall+quantifiers and/or constraint contexts are specified, and which are+not. See GHC's user's guide on pattern synonyms for more information+about pattern synonym type signatures.++-}
+ hsSyn/HsBinds.hs view
@@ -0,0 +1,1193 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[HsBinds]{Abstract syntax: top-level bindings and signatures}++Datatype for: @BindGroup@, @Bind@, @Sig@, @Bind@.+-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE BangPatterns #-}++module HsBinds where++import {-# SOURCE #-} HsExpr ( pprExpr, LHsExpr,+ MatchGroup, pprFunBind,+ GRHSs, pprPatBind )+import {-# SOURCE #-} HsPat ( LPat )++import PlaceHolder ( PostTc,PostRn,DataId,OutputableBndrId )+import HsTypes+import PprCore ()+import CoreSyn+import TcEvidence+import Type+import Name+import NameSet+import BasicTypes+import Outputable+import SrcLoc+import Var+import Bag+import FastString+import BooleanFormula (LBooleanFormula)+import DynFlags++import Data.Data hiding ( Fixity )+import Data.List hiding ( foldr )+import Data.Ord+import Data.Foldable ( Foldable(..) )++{-+************************************************************************+* *+\subsection{Bindings: @BindGroup@}+* *+************************************************************************++Global bindings (where clauses)+-}++-- During renaming, we need bindings where the left-hand sides+-- have been renamed but the the right-hand sides have not.+-- the ...LR datatypes are parametrized by two id types,+-- one for the left and one for the right.+-- Other than during renaming, these will be the same.++-- | Haskell Local Bindings+type HsLocalBinds id = HsLocalBindsLR id id++-- | Located Haskell local bindings+type LHsLocalBinds id = Located (HsLocalBinds id)++-- | Haskell Local Bindings with separate Left and Right identifier types+--+-- Bindings in a 'let' expression+-- or a 'where' clause+data HsLocalBindsLR idL idR+ = HsValBinds (HsValBindsLR idL idR)+ -- ^ Haskell Value Bindings++ -- There should be no pattern synonyms in the HsValBindsLR+ -- These are *local* (not top level) bindings+ -- The parser accepts them, however, leaving the the+ -- renamer to report them++ | HsIPBinds (HsIPBinds idR)+ -- ^ Haskell Implicit Parameter Bindings++ | EmptyLocalBinds+ -- ^ Empty Local Bindings++type LHsLocalBindsLR idL idR = Located (HsLocalBindsLR idL idR)++deriving instance (DataId idL, DataId idR)+ => Data (HsLocalBindsLR idL idR)++-- | Haskell Value Bindings+type HsValBinds id = HsValBindsLR id id++-- | Haskell Value bindings with separate Left and Right identifier types+-- (not implicit parameters)+-- Used for both top level and nested bindings+-- May contain pattern synonym bindings+data HsValBindsLR idL idR+ = -- | Value Bindings In+ --+ -- Before renaming RHS; idR is always RdrName+ -- Not dependency analysed+ -- Recursive by default+ ValBindsIn+ (LHsBindsLR idL idR) [LSig idR]++ -- | Value Bindings Out+ --+ -- After renaming RHS; idR can be Name or Id Dependency analysed,+ -- later bindings in the list may depend on earlier ones.+ | ValBindsOut+ [(RecFlag, LHsBinds idL)]+ [LSig Name]++deriving instance (DataId idL, DataId idR)+ => Data (HsValBindsLR idL idR)++-- | Located Haskell Binding+type LHsBind id = LHsBindLR id id++-- | Located Haskell Bindings+type LHsBinds id = LHsBindsLR id id++-- | Haskell Binding+type HsBind id = HsBindLR id id++-- | Located Haskell Bindings with separate Left and Right identifier types+type LHsBindsLR idL idR = Bag (LHsBindLR idL idR)++-- | Located Haskell Binding with separate Left and Right identifier types+type LHsBindLR idL idR = Located (HsBindLR idL idR)++{- Note [Varieties of binding pattern matches]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The distinction between FunBind and PatBind is a bit subtle. FunBind covers+patterns which resemble function bindings and simple variable bindings.++ f x = e+ f !x = e+ f = e+ !x = e -- FunRhs has SrcStrict+ x `f` y = e -- FunRhs has Infix++The actual patterns and RHSs of a FunBind are encoding in fun_matches.+The m_ctxt field of Match will be FunRhs and carries two bits of information+about the match,++ * the mc_strictness field describes whether the match is decorated with a bang+ (e.g. `!x = e`)+ * the mc_fixity field describes the fixity of the function binder++By contrast, PatBind represents data constructor patterns, as well as a few+other interesting cases. Namely,++ Just x = e+ (x) = e+ x :: Ty = e+-}++-- | Haskell Binding with separate Left and Right id's+data HsBindLR idL idR+ = -- | Function-like Binding+ --+ -- FunBind is used for both functions @f x = e@+ -- and variables @f = \x -> e@+ -- and strict variables @!x = x + 1@+ --+ -- Reason 1: Special case for type inference: see 'TcBinds.tcMonoBinds'.+ --+ -- Reason 2: Instance decls can only have FunBinds, which is convenient.+ -- If you change this, you'll need to change e.g. rnMethodBinds+ --+ -- But note that the form @f :: a->a = ...@+ -- parses as a pattern binding, just like+ -- @(f :: a -> a) = ... @+ --+ -- Strict bindings have their strictness recorded in the 'SrcStrictness' of their+ -- 'MatchContext'. See Note [Varieties of binding pattern matches] for+ -- details about the relationship between FunBind and PatBind.+ --+ -- 'ApiAnnotation.AnnKeywordId's+ --+ -- - 'ApiAnnotation.AnnFunId', attached to each element of fun_matches+ --+ -- - 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnWhere',+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose',++ -- For details on above see note [Api annotations] in ApiAnnotation+ FunBind {++ fun_id :: Located idL, -- Note [fun_id in Match] in HsExpr++ fun_matches :: MatchGroup idR (LHsExpr idR), -- ^ The payload++ fun_co_fn :: HsWrapper, -- ^ Coercion from the type of the MatchGroup to the type of+ -- the Id. Example:+ --+ -- @+ -- f :: Int -> forall a. a -> a+ -- f x y = y+ -- @+ --+ -- Then the MatchGroup will have type (Int -> a' -> a')+ -- (with a free type variable a'). The coercion will take+ -- a CoreExpr of this type and convert it to a CoreExpr of+ -- type Int -> forall a'. a' -> a'+ -- Notice that the coercion captures the free a'.++ bind_fvs :: PostRn idL NameSet, -- ^ After the renamer, this contains+ -- the locally-bound+ -- free variables of this defn.+ -- See Note [Bind free vars]+++ fun_tick :: [Tickish Id] -- ^ Ticks to put on the rhs, if any+ }++ -- | Pattern Binding+ --+ -- The pattern is never a simple variable;+ -- That case is done by FunBind.+ -- See Note [Varieties of binding pattern matches] for details about the+ -- relationship between FunBind and PatBind.++ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnBang',+ -- 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnWhere',+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose',++ -- For details on above see note [Api annotations] in ApiAnnotation+ | PatBind {+ pat_lhs :: LPat idL,+ pat_rhs :: GRHSs idR (LHsExpr idR),+ pat_rhs_ty :: PostTc idR Type, -- ^ Type of the GRHSs+ bind_fvs :: PostRn idL NameSet, -- ^ See Note [Bind free vars]+ pat_ticks :: ([Tickish Id], [[Tickish Id]])+ -- ^ Ticks to put on the rhs, if any, and ticks to put on+ -- the bound variables.+ }++ -- | Variable Binding+ --+ -- Dictionary binding and suchlike.+ -- All VarBinds are introduced by the type checker+ | VarBind {+ var_id :: idL,+ var_rhs :: LHsExpr idR, -- ^ Located only for consistency+ var_inline :: Bool -- ^ True <=> inline this binding regardless+ -- (used for implication constraints only)+ }++ -- | Abstraction Bindings+ | AbsBinds { -- Binds abstraction; TRANSLATION+ abs_tvs :: [TyVar],+ abs_ev_vars :: [EvVar], -- ^ Includes equality constraints++ -- | AbsBinds only gets used when idL = idR after renaming,+ -- but these need to be idL's for the collect... code in HsUtil+ -- to have the right type+ abs_exports :: [ABExport idL],++ -- | Evidence bindings+ -- Why a list? See TcInstDcls+ -- Note [Typechecking plan for instance declarations]+ abs_ev_binds :: [TcEvBinds],++ -- | Typechecked user bindings+ abs_binds :: LHsBinds idL+ }++ -- | Abstraction Bindings Signature+ | AbsBindsSig { -- Simpler form of AbsBinds, used with a type sig+ -- in tcPolyCheck. Produces simpler desugaring and+ -- is necessary to avoid #11405, comment:3.+ abs_tvs :: [TyVar],+ abs_ev_vars :: [EvVar],++ abs_sig_export :: idL, -- like abe_poly+ abs_sig_prags :: TcSpecPrags,++ abs_sig_ev_bind :: TcEvBinds, -- no list needed here+ abs_sig_bind :: LHsBind idL -- always only one, and it's always a+ -- FunBind+ }++ -- | Patterns Synonym Binding+ | PatSynBind (PatSynBind idL idR)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnPattern',+ -- 'ApiAnnotation.AnnLarrow','ApiAnnotation.AnnEqual',+ -- 'ApiAnnotation.AnnWhere'+ -- 'ApiAnnotation.AnnOpen' @'{'@,'ApiAnnotation.AnnClose' @'}'@++ -- For details on above see note [Api annotations] in ApiAnnotation++deriving instance (DataId idL, DataId idR)+ => Data (HsBindLR idL idR)++ -- Consider (AbsBinds tvs ds [(ftvs, poly_f, mono_f) binds]+ --+ -- Creates bindings for (polymorphic, overloaded) poly_f+ -- in terms of monomorphic, non-overloaded mono_f+ --+ -- Invariants:+ -- 1. 'binds' binds mono_f+ -- 2. ftvs is a subset of tvs+ -- 3. ftvs includes all tyvars free in ds+ --+ -- See Note [AbsBinds]++-- | Abtraction Bindings Export+data ABExport id+ = ABE { abe_poly :: id -- ^ Any INLINE pragmas is attached to this Id+ , abe_mono :: id+ , abe_wrap :: HsWrapper -- ^ See Note [ABExport wrapper]+ -- Shape: (forall abs_tvs. abs_ev_vars => abe_mono) ~ abe_poly+ , abe_prags :: TcSpecPrags -- ^ SPECIALISE pragmas+ } deriving Data++-- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnPattern',+-- 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnLarrow'+-- 'ApiAnnotation.AnnWhere','ApiAnnotation.AnnOpen' @'{'@,+-- 'ApiAnnotation.AnnClose' @'}'@,++-- For details on above see note [Api annotations] in ApiAnnotation++-- | Pattern Synonym binding+data PatSynBind idL idR+ = PSB { psb_id :: Located idL, -- ^ Name of the pattern synonym+ psb_fvs :: PostRn idR NameSet, -- ^ See Note [Bind free vars]+ psb_args :: HsPatSynDetails (Located idR), -- ^ Formal parameter names+ psb_def :: LPat idR, -- ^ Right-hand side+ psb_dir :: HsPatSynDir idR -- ^ Directionality+ }+deriving instance (DataId idL, DataId idR)+ => Data (PatSynBind idL idR)++{-+Note [AbsBinds]+~~~~~~~~~~~~~~~+The AbsBinds constructor is used in the output of the type checker, to record+*typechecked* and *generalised* bindings. Consider a module M, with this+top-level binding, where there is no type signature for M.reverse,+ M.reverse [] = []+ M.reverse (x:xs) = M.reverse xs ++ [x]++In Hindley-Milner, a recursive binding is typechecked with the *recursive* uses+being *monomorphic*. So after typechecking *and* desugaring we will get something+like this++ M.reverse :: forall a. [a] -> [a]+ = /\a. letrec+ reverse :: [a] -> [a] = \xs -> case xs of+ [] -> []+ (x:xs) -> reverse xs ++ [x]+ in reverse++Notice that 'M.reverse' is polymorphic as expected, but there is a local+definition for plain 'reverse' which is *monomorphic*. The type variable+'a' scopes over the entire letrec.++That's after desugaring. What about after type checking but before+desugaring? That's where AbsBinds comes in. It looks like this:++ AbsBinds { abs_tvs = [a]+ , abs_exports = [ABE { abe_poly = M.reverse :: forall a. [a] -> [a],+ , abe_mono = reverse :: [a] -> [a]}]+ , abs_binds = { reverse :: [a] -> [a]+ = \xs -> case xs of+ [] -> []+ (x:xs) -> reverse xs ++ [x] } }++Here,+ * abs_tvs says what type variables are abstracted over the binding group,+ just 'a' in this case.+ * abs_binds is the *monomorphic* bindings of the group+ * abs_exports describes how to get the polymorphic Id 'M.reverse' from the+ monomorphic one 'reverse'++Notice that the *original* function (the polymorphic one you thought+you were defining) appears in the abe_poly field of the+abs_exports. The bindings in abs_binds are for fresh, local, Ids with+a *monomorphic* Id.++If there is a group of mutually recursive (see Note [Polymorphic+recursion]) functions without type signatures, we get one AbsBinds+with the monomorphic versions of the bindings in abs_binds, and one+element of abe_exports for each variable bound in the mutually+recursive group. This is true even for pattern bindings. Example:+ (f,g) = (\x -> x, f)+After type checking we get+ AbsBinds { abs_tvs = [a]+ , abs_exports = [ ABE { abe_poly = M.f :: forall a. a -> a+ , abe_mono = f :: a -> a }+ , ABE { abe_poly = M.g :: forall a. a -> a+ , abe_mono = g :: a -> a }]+ , abs_binds = { (f,g) = (\x -> x, f) }++Note [Polymorphic recursion]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ Rec { f x = ...(g ef)...++ ; g :: forall a. [a] -> [a]+ ; g y = ...(f eg)... }++These bindings /are/ mutually recursive (f calls g, and g calls f).+But we can use the type signature for g to break the recursion,+like this:++ 1. Add g :: forall a. [a] -> [a] to the type environment++ 2. Typecheck the definition of f, all by itself,+ including generalising it to find its most general+ type, say f :: forall b. b -> b -> [b]++ 3. Extend the type environment with that type for f++ 4. Typecheck the definition of g, all by itself,+ checking that it has the type claimed by its signature++Steps 2 and 4 each generate a separate AbsBinds, so we end+up with+ Rec { AbsBinds { ...for f ... }+ ; AbsBinds { ...for g ... } }++This approach allows both f and to call each other+polymorphically, even though only g has a signature.++We get an AbsBinds that encompasses multiple source-program+bindings only when+ * Each binding in the group has at least one binder that+ lacks a user type signature+ * The group forms a strongly connected component++Note [ABExport wrapper]+~~~~~~~~~~~~~~~~~~~~~~~+Consider+ (f,g) = (\x.x, \y.y)+This ultimately desugars to something like this:+ tup :: forall a b. (a->a, b->b)+ tup = /\a b. (\x:a.x, \y:b.y)+ f :: forall a. a -> a+ f = /\a. case tup a Any of+ (fm::a->a,gm:Any->Any) -> fm+ ...similarly for g...++The abe_wrap field deals with impedance-matching between+ (/\a b. case tup a b of { (f,g) -> f })+and the thing we really want, which may have fewer type+variables. The action happens in TcBinds.mkExport.++Note [Bind free vars]+~~~~~~~~~~~~~~~~~~~~~+The bind_fvs field of FunBind and PatBind records the free variables+of the definition. It is used for the following purposes++a) Dependency analysis prior to type checking+ (see TcBinds.tc_group)++b) Deciding whether we can do generalisation of the binding+ (see TcBinds.decideGeneralisationPlan)++c) Deciding whether the binding can be used in static forms+ (see TcExpr.checkClosedInStaticForm for the HsStatic case and+ TcBinds.isClosedBndrGroup).++Specifically,++ * bind_fvs includes all free vars that are defined in this module+ (including top-level things and lexically scoped type variables)++ * bind_fvs excludes imported vars; this is just to keep the set smaller++ * Before renaming, and after typechecking, the field is unused;+ it's just an error thunk+-}++instance (OutputableBndrId idL, OutputableBndrId idR)+ => Outputable (HsLocalBindsLR idL idR) where+ ppr (HsValBinds bs) = ppr bs+ ppr (HsIPBinds bs) = ppr bs+ ppr EmptyLocalBinds = empty++instance (OutputableBndrId idL, OutputableBndrId idR)+ => Outputable (HsValBindsLR idL idR) where+ ppr (ValBindsIn binds sigs)+ = pprDeclList (pprLHsBindsForUser binds sigs)++ ppr (ValBindsOut sccs sigs)+ = getPprStyle $ \ sty ->+ if debugStyle sty then -- Print with sccs showing+ vcat (map ppr sigs) $$ vcat (map ppr_scc sccs)+ else+ pprDeclList (pprLHsBindsForUser (unionManyBags (map snd sccs)) sigs)+ where+ ppr_scc (rec_flag, binds) = pp_rec rec_flag <+> pprLHsBinds binds+ pp_rec Recursive = text "rec"+ pp_rec NonRecursive = text "nonrec"++pprLHsBinds :: (OutputableBndrId idL, OutputableBndrId idR)+ => LHsBindsLR idL idR -> SDoc+pprLHsBinds binds+ | isEmptyLHsBinds binds = empty+ | otherwise = pprDeclList (map ppr (bagToList binds))++pprLHsBindsForUser :: (OutputableBndrId idL, OutputableBndrId idR,+ OutputableBndrId id2)+ => LHsBindsLR idL idR -> [LSig id2] -> [SDoc]+-- pprLHsBindsForUser is different to pprLHsBinds because+-- a) No braces: 'let' and 'where' include a list of HsBindGroups+-- and we don't want several groups of bindings each+-- with braces around+-- b) Sort by location before printing+-- c) Include signatures+pprLHsBindsForUser binds sigs+ = map snd (sort_by_loc decls)+ where++ decls :: [(SrcSpan, SDoc)]+ decls = [(loc, ppr sig) | L loc sig <- sigs] +++ [(loc, ppr bind) | L loc bind <- bagToList binds]++ sort_by_loc decls = sortBy (comparing fst) decls++pprDeclList :: [SDoc] -> SDoc -- Braces with a space+-- Print a bunch of declarations+-- One could choose { d1; d2; ... }, using 'sep'+-- or d1+-- d2+-- ..+-- using vcat+-- At the moment we chose the latter+-- Also we do the 'pprDeeperList' thing.+pprDeclList ds = pprDeeperList vcat ds++------------+emptyLocalBinds :: HsLocalBindsLR a b+emptyLocalBinds = EmptyLocalBinds++isEmptyLocalBinds :: HsLocalBindsLR a b -> Bool+isEmptyLocalBinds (HsValBinds ds) = isEmptyValBinds ds+isEmptyLocalBinds (HsIPBinds ds) = isEmptyIPBinds ds+isEmptyLocalBinds EmptyLocalBinds = True++eqEmptyLocalBinds :: HsLocalBindsLR a b -> Bool+eqEmptyLocalBinds EmptyLocalBinds = True+eqEmptyLocalBinds _ = False++isEmptyValBinds :: HsValBindsLR a b -> Bool+isEmptyValBinds (ValBindsIn ds sigs) = isEmptyLHsBinds ds && null sigs+isEmptyValBinds (ValBindsOut ds sigs) = null ds && null sigs++emptyValBindsIn, emptyValBindsOut :: HsValBindsLR a b+emptyValBindsIn = ValBindsIn emptyBag []+emptyValBindsOut = ValBindsOut [] []++emptyLHsBinds :: LHsBindsLR idL idR+emptyLHsBinds = emptyBag++isEmptyLHsBinds :: LHsBindsLR idL idR -> Bool+isEmptyLHsBinds = isEmptyBag++------------+plusHsValBinds :: HsValBinds a -> HsValBinds a -> HsValBinds a+plusHsValBinds (ValBindsIn ds1 sigs1) (ValBindsIn ds2 sigs2)+ = ValBindsIn (ds1 `unionBags` ds2) (sigs1 ++ sigs2)+plusHsValBinds (ValBindsOut ds1 sigs1) (ValBindsOut ds2 sigs2)+ = ValBindsOut (ds1 ++ ds2) (sigs1 ++ sigs2)+plusHsValBinds _ _+ = panic "HsBinds.plusHsValBinds"++{-+What AbsBinds means+~~~~~~~~~~~~~~~~~~~+ AbsBinds tvs+ [d1,d2]+ [(tvs1, f1p, f1m),+ (tvs2, f2p, f2m)]+ BIND+means++ f1p = /\ tvs -> \ [d1,d2] -> letrec DBINDS and BIND+ in fm++ gp = ...same again, with gm instead of fm++This is a pretty bad translation, because it duplicates all the bindings.+So the desugarer tries to do a better job:++ fp = /\ [a,b] -> \ [d1,d2] -> case tp [a,b] [d1,d2] of+ (fm,gm) -> fm+ ..ditto for gp..++ tp = /\ [a,b] -> \ [d1,d2] -> letrec DBINDS and BIND+ in (fm,gm)+-}++instance (OutputableBndrId idL, OutputableBndrId idR)+ => Outputable (HsBindLR idL idR) where+ ppr mbind = ppr_monobind mbind++ppr_monobind :: (OutputableBndrId idL, OutputableBndrId idR)+ => HsBindLR idL idR -> SDoc++ppr_monobind (PatBind { pat_lhs = pat, pat_rhs = grhss })+ = pprPatBind pat grhss+ppr_monobind (VarBind { var_id = var, var_rhs = rhs })+ = sep [pprBndr CasePatBind var, nest 2 $ equals <+> pprExpr (unLoc rhs)]+ppr_monobind (FunBind { fun_id = fun,+ fun_co_fn = wrap,+ fun_matches = matches,+ fun_tick = ticks })+ = pprTicks empty (if null ticks then empty+ else text "-- ticks = " <> ppr ticks)+ $$ ifPprDebug (pprBndr LetBind (unLoc fun))+ $$ pprFunBind matches+ $$ ifPprDebug (ppr wrap)+ppr_monobind (PatSynBind psb) = ppr psb+ppr_monobind (AbsBinds { abs_tvs = tyvars, abs_ev_vars = dictvars+ , abs_exports = exports, abs_binds = val_binds+ , abs_ev_binds = ev_binds })+ = sdocWithDynFlags $ \ dflags ->+ if gopt Opt_PrintTypecheckerElaboration dflags then+ -- Show extra information (bug number: #10662)+ hang (text "AbsBinds" <+> brackets (interpp'SP tyvars)+ <+> brackets (interpp'SP dictvars))+ 2 $ braces $ vcat+ [ text "Exports:" <+>+ brackets (sep (punctuate comma (map ppr exports)))+ , text "Exported types:" <+>+ vcat [pprBndr LetBind (abe_poly ex) | ex <- exports]+ , text "Binds:" <+> pprLHsBinds val_binds+ , text "Evidence:" <+> ppr ev_binds ]+ else+ pprLHsBinds val_binds+ppr_monobind (AbsBindsSig { abs_tvs = tyvars+ , abs_ev_vars = dictvars+ , abs_sig_export = poly_id+ , abs_sig_ev_bind = ev_bind+ , abs_sig_bind = bind })+ = sdocWithDynFlags $ \ dflags ->+ if gopt Opt_PrintTypecheckerElaboration dflags then+ hang (text "AbsBindsSig" <+> brackets (interpp'SP tyvars)+ <+> brackets (interpp'SP dictvars))+ 2 $ braces $ vcat+ [ text "Exported type:" <+> pprBndr LetBind poly_id+ , text "Bind:" <+> ppr bind+ , text "Evidence:" <+> ppr ev_bind ]+ else+ ppr bind++instance (OutputableBndr id) => Outputable (ABExport id) where+ ppr (ABE { abe_wrap = wrap, abe_poly = gbl, abe_mono = lcl, abe_prags = prags })+ = vcat [ ppr gbl <+> text "<=" <+> ppr lcl+ , nest 2 (pprTcSpecPrags prags)+ , nest 2 (text "wrap:" <+> ppr wrap)]++instance (OutputableBndr idL, OutputableBndrId idR)+ => Outputable (PatSynBind idL idR) where+ ppr (PSB{ psb_id = (L _ psyn), psb_args = details, psb_def = pat,+ psb_dir = dir })+ = ppr_lhs <+> ppr_rhs+ where+ ppr_lhs = text "pattern" <+> ppr_details+ ppr_simple syntax = syntax <+> ppr pat++ ppr_details = case details of+ InfixPatSyn v1 v2 -> hsep [ppr v1, pprInfixOcc psyn, ppr v2]+ PrefixPatSyn vs -> hsep (pprPrefixOcc psyn : map ppr vs)+ RecordPatSyn vs ->+ pprPrefixOcc psyn+ <> braces (sep (punctuate comma (map ppr vs)))++ ppr_rhs = case dir of+ Unidirectional -> ppr_simple (text "<-")+ ImplicitBidirectional -> ppr_simple equals+ ExplicitBidirectional mg -> ppr_simple (text "<-") <+> ptext (sLit "where") $$+ (nest 2 $ pprFunBind mg)++pprTicks :: SDoc -> SDoc -> SDoc+-- Print stuff about ticks only when -dppr-debug is on, to avoid+-- them appearing in error messages (from the desugarer); see Trac # 3263+-- Also print ticks in dumpStyle, so that -ddump-hpc actually does+-- something useful.+pprTicks pp_no_debug pp_when_debug+ = getPprStyle (\ sty -> if debugStyle sty || dumpStyle sty+ then pp_when_debug+ else pp_no_debug)++{-+************************************************************************+* *+ Implicit parameter bindings+* *+************************************************************************+-}++-- | Haskell Implicit Parameter Bindings+data HsIPBinds id+ = IPBinds+ [LIPBind id]+ TcEvBinds -- Only in typechecker output; binds+ -- uses of the implicit parameters+deriving instance (DataId id) => Data (HsIPBinds id)++isEmptyIPBinds :: HsIPBinds id -> Bool+isEmptyIPBinds (IPBinds is ds) = null is && isEmptyTcEvBinds ds++-- | Located Implicit Parameter Binding+type LIPBind id = Located (IPBind id)+-- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSemi' when in a+-- list++-- For details on above see note [Api annotations] in ApiAnnotation++-- | Implicit parameter bindings.+--+-- These bindings start off as (Left "x") in the parser and stay+-- that way until after type-checking when they are replaced with+-- (Right d), where "d" is the name of the dictionary holding the+-- evidence for the implicit parameter.+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnEqual'++-- For details on above see note [Api annotations] in ApiAnnotation+data IPBind id+ = IPBind (Either (Located HsIPName) id) (LHsExpr id)+deriving instance (DataId name) => Data (IPBind name)++instance (OutputableBndrId id ) => Outputable (HsIPBinds id) where+ ppr (IPBinds bs ds) = pprDeeperList vcat (map ppr bs)+ $$ ifPprDebug (ppr ds)++instance (OutputableBndrId id ) => Outputable (IPBind id) where+ ppr (IPBind lr rhs) = name <+> equals <+> pprExpr (unLoc rhs)+ where name = case lr of+ Left (L _ ip) -> pprBndr LetBind ip+ Right id -> pprBndr LetBind id++{-+************************************************************************+* *+\subsection{@Sig@: type signatures and value-modifying user pragmas}+* *+************************************************************************++It is convenient to lump ``value-modifying'' user-pragmas (e.g.,+``specialise this function to these four types...'') in with type+signatures. Then all the machinery to move them into place, etc.,+serves for both.+-}++-- | Located Signature+type LSig name = Located (Sig name)++-- | Signatures and pragmas+data Sig name+ = -- | An ordinary type signature+ --+ -- > f :: Num a => a -> a+ --+ -- After renaming, this list of Names contains the named and unnamed+ -- wildcards brought into scope by this signature. For a signature+ -- @_ -> _a -> Bool@, the renamer will give the unnamed wildcard @_@+ -- a freshly generated name, e.g. @_w@. @_w@ and the named wildcard @_a@+ -- are then both replaced with fresh meta vars in the type. Their names+ -- are stored in the type signature that brought them into scope, in+ -- this third field to be more specific.+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDcolon',+ -- 'ApiAnnotation.AnnComma'++ -- For details on above see note [Api annotations] in ApiAnnotation+ TypeSig+ [Located name] -- LHS of the signature; e.g. f,g,h :: blah+ (LHsSigWcType name) -- RHS of the signature; can have wildcards++ -- | A pattern synonym type signature+ --+ -- > pattern Single :: () => (Show a) => a -> [a]+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnPattern',+ -- 'ApiAnnotation.AnnDcolon','ApiAnnotation.AnnForall'+ -- 'ApiAnnotation.AnnDot','ApiAnnotation.AnnDarrow'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | PatSynSig [Located name] (LHsSigType name)+ -- P :: forall a b. Req => Prov => ty++ -- | A signature for a class method+ -- False: ordinary class-method signature+ -- True: generic-default class method signature+ -- e.g. class C a where+ -- op :: a -> a -- Ordinary+ -- default op :: Eq a => a -> a -- Generic default+ -- No wildcards allowed here+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDefault',+ -- 'ApiAnnotation.AnnDcolon'+ | ClassOpSig Bool [Located name] (LHsSigType name)++ -- | A type signature in generated code, notably the code+ -- generated for record selectors. We simply record+ -- the desired Id itself, replete with its name, type+ -- and IdDetails. Otherwise it's just like a type+ -- signature: there should be an accompanying binding+ | IdSig Id++ -- | An ordinary fixity declaration+ --+ -- > infixl 8 ***+ --+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnInfix',+ -- 'ApiAnnotation.AnnVal'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | FixSig (FixitySig name)++ -- | An inline pragma+ --+ -- > {#- INLINE f #-}+ --+ -- - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpen' @'{-\# INLINE'@ and @'['@,+ -- 'ApiAnnotation.AnnClose','ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnVal','ApiAnnotation.AnnTilde',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | InlineSig (Located name) -- Function name+ InlinePragma -- Never defaultInlinePragma++ -- | A specialisation pragma+ --+ -- > {-# SPECIALISE f :: Int -> Int #-}+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnOpen' @'{-\# SPECIALISE'@ and @'['@,+ -- 'ApiAnnotation.AnnTilde',+ -- 'ApiAnnotation.AnnVal',+ -- 'ApiAnnotation.AnnClose' @']'@ and @'\#-}'@,+ -- 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | SpecSig (Located name) -- Specialise a function or datatype ...+ [LHsSigType name] -- ... to these types+ InlinePragma -- The pragma on SPECIALISE_INLINE form.+ -- If it's just defaultInlinePragma, then we said+ -- SPECIALISE, not SPECIALISE_INLINE++ -- | A specialisation pragma for instance declarations only+ --+ -- > {-# SPECIALISE instance Eq [Int] #-}+ --+ -- (Class tys); should be a specialisation of the+ -- current instance declaration+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnInstance','ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | SpecInstSig SourceText (LHsSigType name)+ -- Note [Pragma source text] in BasicTypes++ -- | A minimal complete definition pragma+ --+ -- > {-# MINIMAL a | (b, c | (d | e)) #-}+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnVbar','ApiAnnotation.AnnComma',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | MinimalSig SourceText (LBooleanFormula (Located name))+ -- Note [Pragma source text] in BasicTypes++ -- | A "set cost centre" pragma for declarations+ --+ -- > {-# SCC funName #-}+ --+ -- or+ --+ -- > {-# SCC funName "cost_centre_name" #-}++ | SCCFunSig SourceText -- Note [Pragma source text] in BasicTypes+ (Located name) -- Function name+ (Maybe (Located StringLiteral))+ -- | A complete match pragma+ --+ -- > {-# COMPLETE C, D [:: T] #-}+ --+ -- Used to inform the pattern match checker about additional+ -- complete matchings which, for example, arise from pattern+ -- synonym definitions.+ | CompleteMatchSig SourceText (Located [Located name]) (Maybe (Located name))++deriving instance (DataId name) => Data (Sig name)++-- | Located Fixity Signature+type LFixitySig name = Located (FixitySig name)++-- | Fixity Signature+data FixitySig name = FixitySig [Located name] Fixity+ deriving Data++-- | Type checker Specialisation Pragmas+--+-- 'TcSpecPrags' conveys @SPECIALISE@ pragmas from the type checker to the desugarer+data TcSpecPrags+ = IsDefaultMethod -- ^ Super-specialised: a default method should+ -- be macro-expanded at every call site+ | SpecPrags [LTcSpecPrag]+ deriving Data++-- | Located Type checker Specification Pragmas+type LTcSpecPrag = Located TcSpecPrag++-- | Type checker Specification Pragma+data TcSpecPrag+ = SpecPrag+ Id+ HsWrapper+ InlinePragma+ -- ^ The Id to be specialised, an wrapper that specialises the+ -- polymorphic function, and inlining spec for the specialised function+ deriving Data++noSpecPrags :: TcSpecPrags+noSpecPrags = SpecPrags []++hasSpecPrags :: TcSpecPrags -> Bool+hasSpecPrags (SpecPrags ps) = not (null ps)+hasSpecPrags IsDefaultMethod = False++isDefaultMethod :: TcSpecPrags -> Bool+isDefaultMethod IsDefaultMethod = True+isDefaultMethod (SpecPrags {}) = False+++isFixityLSig :: LSig name -> Bool+isFixityLSig (L _ (FixSig {})) = True+isFixityLSig _ = False++isTypeLSig :: LSig name -> Bool -- Type signatures+isTypeLSig (L _(TypeSig {})) = True+isTypeLSig (L _(ClassOpSig {})) = True+isTypeLSig (L _(IdSig {})) = True+isTypeLSig _ = False++isSpecLSig :: LSig name -> Bool+isSpecLSig (L _(SpecSig {})) = True+isSpecLSig _ = False++isSpecInstLSig :: LSig name -> Bool+isSpecInstLSig (L _ (SpecInstSig {})) = True+isSpecInstLSig _ = False++isPragLSig :: LSig name -> Bool+-- Identifies pragmas+isPragLSig (L _ (SpecSig {})) = True+isPragLSig (L _ (InlineSig {})) = True+isPragLSig (L _ (SCCFunSig {})) = True+isPragLSig (L _ (CompleteMatchSig {})) = True+isPragLSig _ = False++isInlineLSig :: LSig name -> Bool+-- Identifies inline pragmas+isInlineLSig (L _ (InlineSig {})) = True+isInlineLSig _ = False++isMinimalLSig :: LSig name -> Bool+isMinimalLSig (L _ (MinimalSig {})) = True+isMinimalLSig _ = False++isSCCFunSig :: LSig name -> Bool+isSCCFunSig (L _ (SCCFunSig {})) = True+isSCCFunSig _ = False++isCompleteMatchSig :: LSig name -> Bool+isCompleteMatchSig (L _ (CompleteMatchSig {} )) = True+isCompleteMatchSig _ = False++hsSigDoc :: Sig name -> SDoc+hsSigDoc (TypeSig {}) = text "type signature"+hsSigDoc (PatSynSig {}) = text "pattern synonym signature"+hsSigDoc (ClassOpSig is_deflt _ _)+ | is_deflt = text "default type signature"+ | otherwise = text "class method signature"+hsSigDoc (IdSig {}) = text "id signature"+hsSigDoc (SpecSig {}) = text "SPECIALISE pragma"+hsSigDoc (InlineSig _ prag) = ppr (inlinePragmaSpec prag) <+> text "pragma"+hsSigDoc (SpecInstSig {}) = text "SPECIALISE instance pragma"+hsSigDoc (FixSig {}) = text "fixity declaration"+hsSigDoc (MinimalSig {}) = text "MINIMAL pragma"+hsSigDoc (SCCFunSig {}) = text "SCC pragma"+hsSigDoc (CompleteMatchSig {}) = text "COMPLETE pragma"++{-+Check if signatures overlap; this is used when checking for duplicate+signatures. Since some of the signatures contain a list of names, testing for+equality is not enough -- we have to check if they overlap.+-}++instance (OutputableBndrId name ) => Outputable (Sig name) where+ ppr sig = ppr_sig sig++ppr_sig :: (OutputableBndrId name ) => Sig name -> SDoc+ppr_sig (TypeSig vars ty) = pprVarSig (map unLoc vars) (ppr ty)+ppr_sig (ClassOpSig is_deflt vars ty)+ | is_deflt = text "default" <+> pprVarSig (map unLoc vars) (ppr ty)+ | otherwise = pprVarSig (map unLoc vars) (ppr ty)+ppr_sig (IdSig id) = pprVarSig [id] (ppr (varType id))+ppr_sig (FixSig fix_sig) = ppr fix_sig+ppr_sig (SpecSig var ty inl@(InlinePragma { inl_inline = spec }))+ = pragSrcBrackets (inl_src inl) pragmaSrc (pprSpec (unLoc var)+ (interpp'SP ty) inl)+ where+ pragmaSrc = case spec of+ EmptyInlineSpec -> "{-# SPECIALISE"+ _ -> "{-# SPECIALISE_INLINE"+ppr_sig (InlineSig var inl)+ = pragSrcBrackets (inl_src inl) "{-# INLINE" (pprInline inl+ <+> pprPrefixOcc (unLoc var))+ppr_sig (SpecInstSig src ty)+ = pragSrcBrackets src "{-# SPECIALISE" (text "instance" <+> ppr ty)+ppr_sig (MinimalSig src bf)+ = pragSrcBrackets src "{-# MINIMAL" (pprMinimalSig bf)+ppr_sig (PatSynSig names sig_ty)+ = text "pattern" <+> pprVarSig (map unLoc names) (ppr sig_ty)+ppr_sig (SCCFunSig src fn mlabel)+ = pragSrcBrackets src "{-# SCC" (ppr fn <+> maybe empty ppr mlabel )+ppr_sig (CompleteMatchSig src cs mty)+ = pragSrcBrackets src "{-# COMPLETE"+ ((hsep (punctuate comma (map ppr (unLoc cs))))+ <+> opt_sig)+ where+ opt_sig = maybe empty ((\t -> dcolon <+> ppr t) . unLoc) mty++instance OutputableBndr name => Outputable (FixitySig name) where+ ppr (FixitySig names fixity) = sep [ppr fixity, pprops]+ where+ pprops = hsep $ punctuate comma (map (pprInfixOcc . unLoc) names)++pragBrackets :: SDoc -> SDoc+pragBrackets doc = text "{-#" <+> doc <+> text "#-}"++-- | Using SourceText in case the pragma was spelled differently or used mixed+-- case+pragSrcBrackets :: SourceText -> String -> SDoc -> SDoc+pragSrcBrackets (SourceText src) _ doc = text src <+> doc <+> text "#-}"+pragSrcBrackets NoSourceText alt doc = text alt <+> doc <+> text "#-}"++pprVarSig :: (OutputableBndr id) => [id] -> SDoc -> SDoc+pprVarSig vars pp_ty = sep [pprvars <+> dcolon, nest 2 pp_ty]+ where+ pprvars = hsep $ punctuate comma (map pprPrefixOcc vars)++pprSpec :: (OutputableBndr id) => id -> SDoc -> InlinePragma -> SDoc+pprSpec var pp_ty inl = pp_inl <+> pprVarSig [var] pp_ty+ where+ pp_inl | isDefaultInlinePragma inl = empty+ | otherwise = pprInline inl++pprTcSpecPrags :: TcSpecPrags -> SDoc+pprTcSpecPrags IsDefaultMethod = text "<default method>"+pprTcSpecPrags (SpecPrags ps) = vcat (map (ppr . unLoc) ps)++instance Outputable TcSpecPrag where+ ppr (SpecPrag var _ inl)+ = text "SPECIALIZE" <+> pprSpec var (text "<type>") inl++pprMinimalSig :: (OutputableBndr name)+ => LBooleanFormula (Located name) -> SDoc+pprMinimalSig (L _ bf) = ppr (fmap unLoc bf)++{-+************************************************************************+* *+\subsection[PatSynBind]{A pattern synonym definition}+* *+************************************************************************+-}++-- | Haskell Pattern Synonym Details+data HsPatSynDetails a+ = InfixPatSyn a a -- ^ Infix Pattern Synonym+ | PrefixPatSyn [a] -- ^ Prefix Pattern Synonym+ | RecordPatSyn [RecordPatSynField a] -- ^ Record Pattern Synonym+ deriving Data+++-- See Note [Record PatSyn Fields]+-- | Record Pattern Synonym Field+data RecordPatSynField a+ = RecordPatSynField {+ recordPatSynSelectorId :: a -- Selector name visible in rest of the file+ , recordPatSynPatVar :: a+ -- Filled in by renamer, the name used internally+ -- by the pattern+ } deriving Data++++{-+Note [Record PatSyn Fields]++Consider the following two pattern synonyms.++pattern P x y = ([x,True], [y,'v'])+pattern Q{ x, y } =([x,True], [y,'v'])++In P, we just have two local binders, x and y.++In Q, we have local binders but also top-level record selectors+x :: ([Bool], [Char]) -> Bool and similarly for y.++It would make sense to support record-like syntax++pattern Q{ x=x1, y=y1 } = ([x1,True], [y1,'v'])++when we have a different name for the local and top-level binder+the distinction between the two names clear++-}+instance Functor RecordPatSynField where+ fmap f (RecordPatSynField { recordPatSynSelectorId = visible+ , recordPatSynPatVar = hidden })+ = RecordPatSynField { recordPatSynSelectorId = f visible+ , recordPatSynPatVar = f hidden }++instance Outputable a => Outputable (RecordPatSynField a) where+ ppr (RecordPatSynField { recordPatSynSelectorId = v }) = ppr v++instance Foldable RecordPatSynField where+ foldMap f (RecordPatSynField { recordPatSynSelectorId = visible+ , recordPatSynPatVar = hidden })+ = f visible `mappend` f hidden++instance Traversable RecordPatSynField where+ traverse f (RecordPatSynField { recordPatSynSelectorId =visible+ , recordPatSynPatVar = hidden })+ = (\ sel_id pat_var -> RecordPatSynField { recordPatSynSelectorId = sel_id+ , recordPatSynPatVar = pat_var })+ <$> f visible <*> f hidden+++instance Functor HsPatSynDetails where+ fmap f (InfixPatSyn left right) = InfixPatSyn (f left) (f right)+ fmap f (PrefixPatSyn args) = PrefixPatSyn (fmap f args)+ fmap f (RecordPatSyn args) = RecordPatSyn (map (fmap f) args)++instance Foldable HsPatSynDetails where+ foldMap f (InfixPatSyn left right) = f left `mappend` f right+ foldMap f (PrefixPatSyn args) = foldMap f args+ foldMap f (RecordPatSyn args) = foldMap (foldMap f) args++ foldl1 f (InfixPatSyn left right) = left `f` right+ foldl1 f (PrefixPatSyn args) = Data.List.foldl1 f args+ foldl1 f (RecordPatSyn args) =+ Data.List.foldl1 f (map (Data.Foldable.foldl1 f) args)++ foldr1 f (InfixPatSyn left right) = left `f` right+ foldr1 f (PrefixPatSyn args) = Data.List.foldr1 f args+ foldr1 f (RecordPatSyn args) =+ Data.List.foldr1 f (map (Data.Foldable.foldr1 f) args)++ length (InfixPatSyn _ _) = 2+ length (PrefixPatSyn args) = Data.List.length args+ length (RecordPatSyn args) = Data.List.length args++ null (InfixPatSyn _ _) = False+ null (PrefixPatSyn args) = Data.List.null args+ null (RecordPatSyn args) = Data.List.null args++ toList (InfixPatSyn left right) = [left, right]+ toList (PrefixPatSyn args) = args+ toList (RecordPatSyn args) = foldMap toList args++instance Traversable HsPatSynDetails where+ traverse f (InfixPatSyn left right) = InfixPatSyn <$> f left <*> f right+ traverse f (PrefixPatSyn args) = PrefixPatSyn <$> traverse f args+ traverse f (RecordPatSyn args) = RecordPatSyn <$> traverse (traverse f) args++-- | Haskell Pattern Synonym Direction+data HsPatSynDir id+ = Unidirectional+ | ImplicitBidirectional+ | ExplicitBidirectional (MatchGroup id (LHsExpr id))+deriving instance (DataId id) => Data (HsPatSynDir id)
+ hsSyn/HsDecls.hs view
@@ -0,0 +1,2104 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveFoldable,+ DeriveTraversable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleInstances #-}++-- | Abstract syntax of global declarations.+--+-- Definitions for: @SynDecl@ and @ConDecl@, @ClassDecl@,+-- @InstDecl@, @DefaultDecl@ and @ForeignDecl@.+module HsDecls (+ -- * Toplevel declarations+ HsDecl(..), LHsDecl, HsDataDefn(..), HsDeriving,+ HsDerivingClause(..), LHsDerivingClause,++ -- ** Class or type declarations+ TyClDecl(..), LTyClDecl,+ TyClGroup(..), mkTyClGroup, emptyTyClGroup,+ tyClGroupTyClDecls, tyClGroupInstDecls, tyClGroupRoleDecls,+ isClassDecl, isDataDecl, isSynDecl, tcdName,+ isFamilyDecl, isTypeFamilyDecl, isDataFamilyDecl,+ isOpenTypeFamilyInfo, isClosedTypeFamilyInfo,+ tyFamInstDeclName, tyFamInstDeclLName,+ countTyClDecls, pprTyClDeclFlavour,+ tyClDeclLName, tyClDeclTyVars,+ hsDeclHasCusk, famDeclHasCusk,+ FamilyDecl(..), LFamilyDecl,++ -- ** Instance declarations+ InstDecl(..), LInstDecl, NewOrData(..), FamilyInfo(..),+ TyFamInstDecl(..), LTyFamInstDecl, instDeclDataFamInsts,+ DataFamInstDecl(..), LDataFamInstDecl, pprDataFamInstFlavour,+ TyFamEqn(..), TyFamInstEqn, LTyFamInstEqn, TyFamDefltEqn, LTyFamDefltEqn,+ HsTyPats,+ LClsInstDecl, ClsInstDecl(..),++ -- ** Standalone deriving declarations+ DerivDecl(..), LDerivDecl,+ -- ** @RULE@ declarations+ LRuleDecls,RuleDecls(..),RuleDecl(..), LRuleDecl, RuleBndr(..),LRuleBndr,+ collectRuleBndrSigTys,+ flattenRuleDecls, pprFullRuleName,+ -- ** @VECTORISE@ declarations+ VectDecl(..), LVectDecl,+ lvectDeclName, lvectInstDecl,+ -- ** @default@ declarations+ DefaultDecl(..), LDefaultDecl,+ -- ** Template haskell declaration splice+ SpliceExplicitFlag(..),+ SpliceDecl(..), LSpliceDecl,+ -- ** Foreign function interface declarations+ ForeignDecl(..), LForeignDecl, ForeignImport(..), ForeignExport(..),+ noForeignImportCoercionYet, noForeignExportCoercionYet,+ CImportSpec(..),+ -- ** Data-constructor declarations+ ConDecl(..), LConDecl,+ HsConDeclDetails, hsConDeclArgTys,+ getConNames,+ getConDetails,+ gadtDeclDetails,+ -- ** Document comments+ DocDecl(..), LDocDecl, docDeclDoc,+ -- ** Deprecations+ WarnDecl(..), LWarnDecl,+ WarnDecls(..), LWarnDecls,+ -- ** Annotations+ AnnDecl(..), LAnnDecl,+ AnnProvenance(..), annProvenanceName_maybe,+ -- ** Role annotations+ RoleAnnotDecl(..), LRoleAnnotDecl, roleAnnotDeclName,+ -- ** Injective type families+ FamilyResultSig(..), LFamilyResultSig, InjectivityAnn(..), LInjectivityAnn,+ resultVariableName,++ -- * Grouping+ HsGroup(..), emptyRdrGroup, emptyRnGroup, appendGroups, hsGroupInstDecls++ ) where++-- friends:+import {-# SOURCE #-} HsExpr( LHsExpr, HsExpr, HsSplice, pprExpr,+ pprSpliceDecl )+ -- Because Expr imports Decls via HsBracket++import HsBinds+import HsTypes+import HsDoc+import TyCon+import Name+import BasicTypes+import Coercion+import ForeignCall+import PlaceHolder ( PostTc,PostRn,PlaceHolder(..),DataId, OutputableBndrId )+import NameSet++-- others:+import InstEnv+import Class+import Outputable+import Util+import SrcLoc++import Bag+import Maybes+import Data.Data hiding (TyCon,Fixity, Infix)++{-+************************************************************************+* *+\subsection[HsDecl]{Declarations}+* *+************************************************************************+-}++type LHsDecl id = Located (HsDecl id)+ -- ^ When in a list this may have+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSemi'+ --++-- For details on above see note [Api annotations] in ApiAnnotation++-- | A Haskell Declaration+data HsDecl id+ = TyClD (TyClDecl id) -- ^ Type or Class Declaration+ | InstD (InstDecl id) -- ^ Instance declaration+ | DerivD (DerivDecl id) -- ^ Deriving declaration+ | ValD (HsBind id) -- ^ Value declaration+ | SigD (Sig id) -- ^ Signature declaration+ | DefD (DefaultDecl id) -- ^ 'default' declaration+ | ForD (ForeignDecl id) -- ^ Foreign declaration+ | WarningD (WarnDecls id) -- ^ Warning declaration+ | AnnD (AnnDecl id) -- ^ Annotation declaration+ | RuleD (RuleDecls id) -- ^ Rule declaration+ | VectD (VectDecl id) -- ^ Vectorise declaration+ | SpliceD (SpliceDecl id) -- ^ Splice declaration+ -- (Includes quasi-quotes)+ | DocD (DocDecl) -- ^ Documentation comment declaration+ | RoleAnnotD (RoleAnnotDecl id) -- ^ Role annotation declaration+deriving instance (DataId id) => Data (HsDecl id)+++-- NB: all top-level fixity decls are contained EITHER+-- EITHER SigDs+-- OR in the ClassDecls in TyClDs+--+-- The former covers+-- a) data constructors+-- b) class methods (but they can be also done in the+-- signatures of class decls)+-- c) imported functions (that have an IfacSig)+-- d) top level decls+--+-- The latter is for class methods only++-- | Haskell Group+--+-- A 'HsDecl' is categorised into a 'HsGroup' before being+-- fed to the renamer.+data HsGroup id+ = HsGroup {+ hs_valds :: HsValBinds id,+ hs_splcds :: [LSpliceDecl id],++ hs_tyclds :: [TyClGroup id],+ -- A list of mutually-recursive groups;+ -- This includes `InstDecl`s as well;+ -- Parser generates a singleton list;+ -- renamer does dependency analysis++ hs_derivds :: [LDerivDecl id],++ hs_fixds :: [LFixitySig id],+ -- Snaffled out of both top-level fixity signatures,+ -- and those in class declarations++ hs_defds :: [LDefaultDecl id],+ hs_fords :: [LForeignDecl id],+ hs_warnds :: [LWarnDecls id],+ hs_annds :: [LAnnDecl id],+ hs_ruleds :: [LRuleDecls id],+ hs_vects :: [LVectDecl id],++ hs_docs :: [LDocDecl]+ }+deriving instance (DataId id) => Data (HsGroup id)++emptyGroup, emptyRdrGroup, emptyRnGroup :: HsGroup a+emptyRdrGroup = emptyGroup { hs_valds = emptyValBindsIn }+emptyRnGroup = emptyGroup { hs_valds = emptyValBindsOut }++hsGroupInstDecls :: HsGroup id -> [LInstDecl id]+hsGroupInstDecls = (=<<) group_instds . hs_tyclds++emptyGroup = HsGroup { hs_tyclds = [],+ hs_derivds = [],+ hs_fixds = [], hs_defds = [], hs_annds = [],+ hs_fords = [], hs_warnds = [], hs_ruleds = [], hs_vects = [],+ hs_valds = error "emptyGroup hs_valds: Can't happen",+ hs_splcds = [],+ hs_docs = [] }++appendGroups :: HsGroup a -> HsGroup a -> HsGroup a+appendGroups+ HsGroup {+ hs_valds = val_groups1,+ hs_splcds = spliceds1,+ hs_tyclds = tyclds1,+ hs_derivds = derivds1,+ hs_fixds = fixds1,+ hs_defds = defds1,+ hs_annds = annds1,+ hs_fords = fords1,+ hs_warnds = warnds1,+ hs_ruleds = rulds1,+ hs_vects = vects1,+ hs_docs = docs1 }+ HsGroup {+ hs_valds = val_groups2,+ hs_splcds = spliceds2,+ hs_tyclds = tyclds2,+ hs_derivds = derivds2,+ hs_fixds = fixds2,+ hs_defds = defds2,+ hs_annds = annds2,+ hs_fords = fords2,+ hs_warnds = warnds2,+ hs_ruleds = rulds2,+ hs_vects = vects2,+ hs_docs = docs2 }+ =+ HsGroup {+ hs_valds = val_groups1 `plusHsValBinds` val_groups2,+ hs_splcds = spliceds1 ++ spliceds2,+ hs_tyclds = tyclds1 ++ tyclds2,+ hs_derivds = derivds1 ++ derivds2,+ hs_fixds = fixds1 ++ fixds2,+ hs_annds = annds1 ++ annds2,+ hs_defds = defds1 ++ defds2,+ hs_fords = fords1 ++ fords2,+ hs_warnds = warnds1 ++ warnds2,+ hs_ruleds = rulds1 ++ rulds2,+ hs_vects = vects1 ++ vects2,+ hs_docs = docs1 ++ docs2 }++instance (OutputableBndrId name) => Outputable (HsDecl name) where+ ppr (TyClD dcl) = ppr dcl+ ppr (ValD binds) = ppr binds+ ppr (DefD def) = ppr def+ ppr (InstD inst) = ppr inst+ ppr (DerivD deriv) = ppr deriv+ ppr (ForD fd) = ppr fd+ ppr (SigD sd) = ppr sd+ ppr (RuleD rd) = ppr rd+ ppr (VectD vect) = ppr vect+ ppr (WarningD wd) = ppr wd+ ppr (AnnD ad) = ppr ad+ ppr (SpliceD dd) = ppr dd+ ppr (DocD doc) = ppr doc+ ppr (RoleAnnotD ra) = ppr ra++instance (OutputableBndrId name) => Outputable (HsGroup name) where+ ppr (HsGroup { hs_valds = val_decls,+ hs_tyclds = tycl_decls,+ hs_derivds = deriv_decls,+ hs_fixds = fix_decls,+ hs_warnds = deprec_decls,+ hs_annds = ann_decls,+ hs_fords = foreign_decls,+ hs_defds = default_decls,+ hs_ruleds = rule_decls,+ hs_vects = vect_decls })+ = vcat_mb empty+ [ppr_ds fix_decls, ppr_ds default_decls,+ ppr_ds deprec_decls, ppr_ds ann_decls,+ ppr_ds rule_decls,+ ppr_ds vect_decls,+ if isEmptyValBinds val_decls+ then Nothing+ else Just (ppr val_decls),+ ppr_ds (tyClGroupTyClDecls tycl_decls),+ ppr_ds (tyClGroupInstDecls tycl_decls),+ ppr_ds deriv_decls,+ ppr_ds foreign_decls]+ where+ ppr_ds :: Outputable a => [a] -> Maybe SDoc+ ppr_ds [] = Nothing+ ppr_ds ds = Just (vcat (map ppr ds))++ vcat_mb :: SDoc -> [Maybe SDoc] -> SDoc+ -- Concatenate vertically with white-space between non-blanks+ vcat_mb _ [] = empty+ vcat_mb gap (Nothing : ds) = vcat_mb gap ds+ vcat_mb gap (Just d : ds) = gap $$ d $$ vcat_mb blankLine ds++-- | Located Splice Declaration+type LSpliceDecl name = Located (SpliceDecl name)++-- | Splice Declaration+data SpliceDecl id+ = SpliceDecl -- Top level splice+ (Located (HsSplice id))+ SpliceExplicitFlag+deriving instance (DataId id) => Data (SpliceDecl id)++instance (OutputableBndrId name) => Outputable (SpliceDecl name) where+ ppr (SpliceDecl (L _ e) f) = pprSpliceDecl e f++{-+************************************************************************+* *+ Type and class declarations+* *+************************************************************************++Note [The Naming story]+~~~~~~~~~~~~~~~~~~~~~~~+Here is the story about the implicit names that go with type, class,+and instance decls. It's a bit tricky, so pay attention!++"Implicit" (or "system") binders+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ Each data type decl defines+ a worker name for each constructor+ to-T and from-T convertors+ Each class decl defines+ a tycon for the class+ a data constructor for that tycon+ the worker for that constructor+ a selector for each superclass++All have occurrence names that are derived uniquely from their parent+declaration.++None of these get separate definitions in an interface file; they are+fully defined by the data or class decl. But they may *occur* in+interface files, of course. Any such occurrence must haul in the+relevant type or class decl.++Plan of attack:+ - Ensure they "point to" the parent data/class decl+ when loading that decl from an interface file+ (See RnHiFiles.getSysBinders)++ - When typechecking the decl, we build the implicit TyCons and Ids.+ When doing so we look them up in the name cache (RnEnv.lookupSysName),+ to ensure correct module and provenance is set++These are the two places that we have to conjure up the magic derived+names. (The actual magic is in OccName.mkWorkerOcc, etc.)++Default methods+~~~~~~~~~~~~~~~+ - Occurrence name is derived uniquely from the method name+ E.g. $dmmax++ - If there is a default method name at all, it's recorded in+ the ClassOpSig (in HsBinds), in the DefMethInfo field.+ (DefMethInfo is defined in Class.hs)++Source-code class decls and interface-code class decls are treated subtly+differently, which has given me a great deal of confusion over the years.+Here's the deal. (We distinguish the two cases because source-code decls+have (Just binds) in the tcdMeths field, whereas interface decls have Nothing.++In *source-code* class declarations:++ - When parsing, every ClassOpSig gets a DefMeth with a suitable RdrName+ This is done by RdrHsSyn.mkClassOpSigDM++ - The renamer renames it to a Name++ - During typechecking, we generate a binding for each $dm for+ which there's a programmer-supplied default method:+ class Foo a where+ op1 :: <type>+ op2 :: <type>+ op1 = ...+ We generate a binding for $dmop1 but not for $dmop2.+ The Class for Foo has a Nothing for op2 and+ a Just ($dm_op1, VanillaDM) for op1.+ The Name for $dmop2 is simply discarded.++In *interface-file* class declarations:+ - When parsing, we see if there's an explicit programmer-supplied default method+ because there's an '=' sign to indicate it:+ class Foo a where+ op1 = :: <type> -- NB the '='+ op2 :: <type>+ We use this info to generate a DefMeth with a suitable RdrName for op1,+ and a NoDefMeth for op2+ - The interface file has a separate definition for $dmop1, with unfolding etc.+ - The renamer renames it to a Name.+ - The renamer treats $dmop1 as a free variable of the declaration, so that+ the binding for $dmop1 will be sucked in. (See RnHsSyn.tyClDeclFVs)+ This doesn't happen for source code class decls, because they *bind* the default method.++Dictionary functions+~~~~~~~~~~~~~~~~~~~~+Each instance declaration gives rise to one dictionary function binding.++The type checker makes up new source-code instance declarations+(e.g. from 'deriving' or generic default methods --- see+TcInstDcls.tcInstDecls1). So we can't generate the names for+dictionary functions in advance (we don't know how many we need).++On the other hand for interface-file instance declarations, the decl+specifies the name of the dictionary function, and it has a binding elsewhere+in the interface file:+ instance {Eq Int} = dEqInt+ dEqInt :: {Eq Int} <pragma info>++So again we treat source code and interface file code slightly differently.++Source code:+ - Source code instance decls have a Nothing in the (Maybe name) field+ (see data InstDecl below)++ - The typechecker makes up a Local name for the dict fun for any source-code+ instance decl, whether it comes from a source-code instance decl, or whether+ the instance decl is derived from some other construct (e.g. 'deriving').++ - The occurrence name it chooses is derived from the instance decl (just for+ documentation really) --- e.g. dNumInt. Two dict funs may share a common+ occurrence name, but will have different uniques. E.g.+ instance Foo [Int] where ...+ instance Foo [Bool] where ...+ These might both be dFooList++ - The CoreTidy phase externalises the name, and ensures the occurrence name is+ unique (this isn't special to dict funs). So we'd get dFooList and dFooList1.++ - We can take this relaxed approach (changing the occurrence name later)+ because dict fun Ids are not captured in a TyCon or Class (unlike default+ methods, say). Instead, they are kept separately in the InstEnv. This+ makes it easy to adjust them after compiling a module. (Once we've finished+ compiling that module, they don't change any more.)+++Interface file code:+ - The instance decl gives the dict fun name, so the InstDecl has a (Just name)+ in the (Maybe name) field.++ - RnHsSyn.instDeclFVs treats the dict fun name as free in the decl, so that we+ suck in the dfun binding+-}++-- | Located Declaration of a Type or Class+type LTyClDecl name = Located (TyClDecl name)++-- | A type or class declaration.+data TyClDecl name+ = -- | @type/data family T :: *->*@+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnType',+ -- 'ApiAnnotation.AnnData',+ -- 'ApiAnnotation.AnnFamily','ApiAnnotation.AnnDcolon',+ -- 'ApiAnnotation.AnnWhere','ApiAnnotation.AnnOpenP',+ -- 'ApiAnnotation.AnnDcolon','ApiAnnotation.AnnCloseP',+ -- 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnRarrow',+ -- 'ApiAnnotation.AnnVbar'++ -- For details on above see note [Api annotations] in ApiAnnotation+ FamDecl { tcdFam :: FamilyDecl name }++ | -- | @type@ declaration+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnType',+ -- 'ApiAnnotation.AnnEqual',++ -- For details on above see note [Api annotations] in ApiAnnotation+ SynDecl { tcdLName :: Located name -- ^ Type constructor+ , tcdTyVars :: LHsQTyVars name -- ^ Type variables; for an associated type+ -- these include outer binders+ , tcdFixity :: LexicalFixity -- ^ Fixity used in the declaration+ , tcdRhs :: LHsType name -- ^ RHS of type declaration+ , tcdFVs :: PostRn name NameSet }++ | -- | @data@ declaration+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnData',+ -- 'ApiAnnotation.AnnFamily',+ -- 'ApiAnnotation.AnnNewType',+ -- 'ApiAnnotation.AnnNewType','ApiAnnotation.AnnDcolon'+ -- 'ApiAnnotation.AnnWhere',++ -- For details on above see note [Api annotations] in ApiAnnotation+ DataDecl { tcdLName :: Located name -- ^ Type constructor+ , tcdTyVars :: LHsQTyVars name -- ^ Type variables; for an associated type+ -- these include outer binders+ -- Eg class T a where+ -- type F a :: *+ -- type F a = a -> a+ -- Here the type decl for 'f' includes 'a'+ -- in its tcdTyVars+ , tcdFixity :: LexicalFixity -- ^ Fixity used in the declaration+ , tcdDataDefn :: HsDataDefn name+ , tcdDataCusk :: PostRn name Bool -- ^ does this have a CUSK?+ , tcdFVs :: PostRn name NameSet }++ | ClassDecl { tcdCtxt :: LHsContext name, -- ^ Context...+ tcdLName :: Located name, -- ^ Name of the class+ tcdTyVars :: LHsQTyVars name, -- ^ Class type variables+ tcdFixity :: LexicalFixity, -- ^ Fixity used in the declaration+ tcdFDs :: [Located (FunDep (Located name))],+ -- ^ Functional deps+ tcdSigs :: [LSig name], -- ^ Methods' signatures+ tcdMeths :: LHsBinds name, -- ^ Default methods+ tcdATs :: [LFamilyDecl name], -- ^ Associated types;+ tcdATDefs :: [LTyFamDefltEqn name], -- ^ Associated type defaults+ tcdDocs :: [LDocDecl], -- ^ Haddock docs+ tcdFVs :: PostRn name NameSet+ }+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnClass',+ -- 'ApiAnnotation.AnnWhere','ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose'+ -- - The tcdFDs will have 'ApiAnnotation.AnnVbar',+ -- 'ApiAnnotation.AnnComma'+ -- 'ApiAnnotation.AnnRarrow'++ -- For details on above see note [Api annotations] in ApiAnnotation++deriving instance (DataId id) => Data (TyClDecl id)+++-- Simple classifiers for TyClDecl+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++-- | @True@ <=> argument is a @data@\/@newtype@+-- declaration.+isDataDecl :: TyClDecl name -> Bool+isDataDecl (DataDecl {}) = True+isDataDecl _other = False++-- | type or type instance declaration+isSynDecl :: TyClDecl name -> Bool+isSynDecl (SynDecl {}) = True+isSynDecl _other = False++-- | type class+isClassDecl :: TyClDecl name -> Bool+isClassDecl (ClassDecl {}) = True+isClassDecl _ = False++-- | type/data family declaration+isFamilyDecl :: TyClDecl name -> Bool+isFamilyDecl (FamDecl {}) = True+isFamilyDecl _other = False++-- | type family declaration+isTypeFamilyDecl :: TyClDecl name -> Bool+isTypeFamilyDecl (FamDecl (FamilyDecl { fdInfo = info })) = case info of+ OpenTypeFamily -> True+ ClosedTypeFamily {} -> True+ _ -> False+isTypeFamilyDecl _ = False++-- | open type family info+isOpenTypeFamilyInfo :: FamilyInfo name -> Bool+isOpenTypeFamilyInfo OpenTypeFamily = True+isOpenTypeFamilyInfo _ = False++-- | closed type family info+isClosedTypeFamilyInfo :: FamilyInfo name -> Bool+isClosedTypeFamilyInfo (ClosedTypeFamily {}) = True+isClosedTypeFamilyInfo _ = False++-- | data family declaration+isDataFamilyDecl :: TyClDecl name -> Bool+isDataFamilyDecl (FamDecl (FamilyDecl { fdInfo = DataFamily })) = True+isDataFamilyDecl _other = False++-- Dealing with names++tyFamInstDeclName :: TyFamInstDecl name -> name+tyFamInstDeclName = unLoc . tyFamInstDeclLName++tyFamInstDeclLName :: TyFamInstDecl name -> Located name+tyFamInstDeclLName (TyFamInstDecl { tfid_eqn =+ (L _ (TyFamEqn { tfe_tycon = ln })) })+ = ln++tyClDeclLName :: TyClDecl name -> Located name+tyClDeclLName (FamDecl { tcdFam = FamilyDecl { fdLName = ln } }) = ln+tyClDeclLName decl = tcdLName decl++tcdName :: TyClDecl name -> name+tcdName = unLoc . tyClDeclLName++tyClDeclTyVars :: TyClDecl name -> LHsQTyVars name+tyClDeclTyVars (FamDecl { tcdFam = FamilyDecl { fdTyVars = tvs } }) = tvs+tyClDeclTyVars d = tcdTyVars d++countTyClDecls :: [TyClDecl name] -> (Int, Int, Int, Int, Int)+ -- class, synonym decls, data, newtype, family decls+countTyClDecls decls+ = (count isClassDecl decls,+ count isSynDecl decls, -- excluding...+ count isDataTy decls, -- ...family...+ count isNewTy decls, -- ...instances+ count isFamilyDecl decls)+ where+ isDataTy DataDecl{ tcdDataDefn = HsDataDefn { dd_ND = DataType } } = True+ isDataTy _ = False++ isNewTy DataDecl{ tcdDataDefn = HsDataDefn { dd_ND = NewType } } = True+ isNewTy _ = False++-- | Does this declaration have a complete, user-supplied kind signature?+-- See Note [Complete user-supplied kind signatures]+hsDeclHasCusk :: TyClDecl Name -> Bool+hsDeclHasCusk (FamDecl { tcdFam = fam_decl }) = famDeclHasCusk Nothing fam_decl+hsDeclHasCusk (SynDecl { tcdTyVars = tyvars, tcdRhs = rhs })+ -- NB: Keep this synchronized with 'getInitialKind'+ = hsTvbAllKinded tyvars && rhs_annotated rhs+ where+ rhs_annotated (L _ ty) = case ty of+ HsParTy lty -> rhs_annotated lty+ HsKindSig {} -> True+ _ -> False+hsDeclHasCusk (DataDecl { tcdDataCusk = cusk }) = cusk+hsDeclHasCusk (ClassDecl { tcdTyVars = tyvars }) = hsTvbAllKinded tyvars++-- Pretty-printing TyClDecl+-- ~~~~~~~~~~~~~~~~~~~~~~~~++instance (OutputableBndrId name) => Outputable (TyClDecl name) where++ ppr (FamDecl { tcdFam = decl }) = ppr decl+ ppr (SynDecl { tcdLName = ltycon, tcdTyVars = tyvars, tcdFixity = fixity+ , tcdRhs = rhs })+ = hang (text "type" <+>+ pp_vanilla_decl_head ltycon tyvars fixity [] <+> equals)+ 4 (ppr rhs)++ ppr (DataDecl { tcdLName = ltycon, tcdTyVars = tyvars, tcdFixity = fixity+ , tcdDataDefn = defn })+ = pp_data_defn (pp_vanilla_decl_head ltycon tyvars fixity) defn++ ppr (ClassDecl {tcdCtxt = context, tcdLName = lclas, tcdTyVars = tyvars,+ tcdFixity = fixity,+ tcdFDs = fds,+ tcdSigs = sigs, tcdMeths = methods,+ tcdATs = ats, tcdATDefs = at_defs})+ | null sigs && isEmptyBag methods && null ats && null at_defs -- No "where" part+ = top_matter++ | otherwise -- Laid out+ = vcat [ top_matter <+> text "where"+ , nest 2 $ pprDeclList (map (pprFamilyDecl NotTopLevel . unLoc) ats +++ map ppr_fam_deflt_eqn at_defs +++ pprLHsBindsForUser methods sigs) ]+ where+ top_matter = text "class"+ <+> pp_vanilla_decl_head lclas tyvars fixity (unLoc context)+ <+> pprFundeps (map unLoc fds)++instance (OutputableBndrId name) => Outputable (TyClGroup name) where+ ppr (TyClGroup { group_tyclds = tyclds+ , group_roles = roles+ , group_instds = instds+ }+ )+ = ppr tyclds $$+ ppr roles $$+ ppr instds++pp_vanilla_decl_head :: (OutputableBndrId name) => Located name+ -> LHsQTyVars name+ -> LexicalFixity+ -> HsContext name+ -> SDoc+pp_vanilla_decl_head thing (HsQTvs { hsq_explicit = tyvars }) fixity context+ = hsep [pprHsContext context, pp_tyvars tyvars]+ where+ pp_tyvars (varl:varsr)+ | fixity == Infix+ = hsep [ppr (unLoc varl), pprInfixOcc (unLoc thing)+ , hsep (map (ppr.unLoc) varsr)]+ | otherwise = hsep [ pprPrefixOcc (unLoc thing)+ , hsep (map (ppr.unLoc) (varl:varsr))]+ pp_tyvars [] = ppr thing++pprTyClDeclFlavour :: TyClDecl a -> SDoc+pprTyClDeclFlavour (ClassDecl {}) = text "class"+pprTyClDeclFlavour (SynDecl {}) = text "type"+pprTyClDeclFlavour (FamDecl { tcdFam = FamilyDecl { fdInfo = info }})+ = pprFlavour info <+> text "family"+pprTyClDeclFlavour (DataDecl { tcdDataDefn = HsDataDefn { dd_ND = nd } })+ = ppr nd+++{- Note [Complete user-supplied kind signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We kind-check declarations differently if they have a complete, user-supplied+kind signature (CUSK). This is because we can safely generalise a CUSKed+declaration before checking all of the others, supporting polymorphic recursion.+See ghc.haskell.org/trac/ghc/wiki/GhcKinds/KindInference#Proposednewstrategy+and #9200 for lots of discussion of how we got here.++A declaration has a CUSK if we can know its complete kind without doing any+inference, at all. Here are the rules:++ - A class or datatype is said to have a CUSK if and only if all of its type+variables are annotated. Its result kind is, by construction, Constraint or *+respectively.++ - A type synonym has a CUSK if and only if all of its type variables and its+RHS are annotated with kinds.++ - A closed type family is said to have a CUSK if and only if all of its type+variables and its return type are annotated.++ - An open type family always has a CUSK -- unannotated type variables (and+return type) default to *.++ - Additionally, if -XTypeInType is on, then a data definition with a top-level+ :: must explicitly bind all kind variables to the right of the ::.+ See test dependent/should_compile/KindLevels, which requires this case.+ (Naturally, any kind variable mentioned before the :: should not be bound+ after it.)+-}+++{- *********************************************************************+* *+ TyClGroup+ Strongly connected components of+ type, class, instance, and role declarations+* *+********************************************************************* -}++{- Note [TyClGroups and dependency analysis]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A TyClGroup represents a strongly connected components of type/class/instance+decls, together with the role annotations for the type/class declarations.++The hs_tyclds :: [TyClGroup] field of a HsGroup is a dependency-order+sequence of strongly-connected components.++Invariants+ * The type and class declarations, group_tyclds, may depend on each+ other, or earlier TyClGroups, but not on later ones++ * The role annotations, group_roles, are role-annotations for some or+ all of the types and classes in group_tyclds (only).++ * The instance declarations, group_instds, may (and usually will)+ depend on group_tyclds, or on earlier TyClGroups, but not on later+ ones.++See Note [Dependency analsis of type, class, and instance decls]+in RnSource for more info.+-}++-- | Type or Class Group+data TyClGroup name -- See Note [TyClGroups and dependency analysis]+ = TyClGroup { group_tyclds :: [LTyClDecl name]+ , group_roles :: [LRoleAnnotDecl name]+ , group_instds :: [LInstDecl name] }+deriving instance (DataId id) => Data (TyClGroup id)++emptyTyClGroup :: TyClGroup name+emptyTyClGroup = TyClGroup [] [] []++tyClGroupTyClDecls :: [TyClGroup name] -> [LTyClDecl name]+tyClGroupTyClDecls = concatMap group_tyclds++tyClGroupInstDecls :: [TyClGroup name] -> [LInstDecl name]+tyClGroupInstDecls = concatMap group_instds++tyClGroupRoleDecls :: [TyClGroup name] -> [LRoleAnnotDecl name]+tyClGroupRoleDecls = concatMap group_roles++mkTyClGroup :: [LTyClDecl name] -> [LInstDecl name] -> TyClGroup name+mkTyClGroup decls instds = TyClGroup+ { group_tyclds = decls+ , group_roles = []+ , group_instds = instds+ }++++{- *********************************************************************+* *+ Data and type family declarations+* *+********************************************************************* -}++{- Note [FamilyResultSig]+~~~~~~~~~~~~~~~~~~~~~~~~~++This data type represents the return signature of a type family. Possible+values are:++ * NoSig - the user supplied no return signature:+ type family Id a where ...++ * KindSig - the user supplied the return kind:+ type family Id a :: * where ...++ * TyVarSig - user named the result with a type variable and possibly+ provided a kind signature for that variable:+ type family Id a = r where ...+ type family Id a = (r :: *) where ...++ Naming result of a type family is required if we want to provide+ injectivity annotation for a type family:+ type family Id a = r | r -> a where ...++See also: Note [Injectivity annotation]++Note [Injectivity annotation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++A user can declare a type family to be injective:++ type family Id a = r | r -> a where ...++ * The part after the "|" is called "injectivity annotation".+ * "r -> a" part is called "injectivity condition"; at the moment terms+ "injectivity annotation" and "injectivity condition" are synonymous+ because we only allow a single injectivity condition.+ * "r" is the "LHS of injectivity condition". LHS can only contain the+ variable naming the result of a type family.++ * "a" is the "RHS of injectivity condition". RHS contains space-separated+ type and kind variables representing the arguments of a type+ family. Variables can be omitted if a type family is not injective in+ these arguments. Example:+ type family Foo a b c = d | d -> a c where ...++Note that:+ (a) naming of type family result is required to provide injectivity+ annotation+ (b) for associated types if the result was named then injectivity annotation+ is mandatory. Otherwise result type variable is indistinguishable from+ associated type default.++It is possible that in the future this syntax will be extended to support+more complicated injectivity annotations. For example we could declare that+if we know the result of Plus and one of its arguments we can determine the+other argument:++ type family Plus a b = (r :: Nat) | r a -> b, r b -> a where ...++Here injectivity annotation would consist of two comma-separated injectivity+conditions.++See also Note [Injective type families] in TyCon+-}++-- | Located type Family Result Signature+type LFamilyResultSig name = Located (FamilyResultSig name)++-- | type Family Result Signature+data FamilyResultSig name = -- see Note [FamilyResultSig]+ NoSig+ -- ^ - 'ApiAnnotation.AnnKeywordId' :++ -- For details on above see note [Api annotations] in ApiAnnotation++ | KindSig (LHsKind name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpenP','ApiAnnotation.AnnDcolon',+ -- 'ApiAnnotation.AnnCloseP'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | TyVarSig (LHsTyVarBndr name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpenP','ApiAnnotation.AnnDcolon',+ -- 'ApiAnnotation.AnnCloseP', 'ApiAnnotation.AnnEqual'++ -- For details on above see note [Api annotations] in ApiAnnotation++deriving instance (DataId name) => Data (FamilyResultSig name)++-- | Located type Family Declaration+type LFamilyDecl name = Located (FamilyDecl name)++-- | type Family Declaration+data FamilyDecl name = FamilyDecl+ { fdInfo :: FamilyInfo name -- type/data, closed/open+ , fdLName :: Located name -- type constructor+ , fdTyVars :: LHsQTyVars name -- type variables+ , fdFixity :: LexicalFixity -- Fixity used in the declaration+ , fdResultSig :: LFamilyResultSig name -- result signature+ , fdInjectivityAnn :: Maybe (LInjectivityAnn name) -- optional injectivity ann+ }+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnType',+ -- 'ApiAnnotation.AnnData', 'ApiAnnotation.AnnFamily',+ -- 'ApiAnnotation.AnnWhere', 'ApiAnnotation.AnnOpenP',+ -- 'ApiAnnotation.AnnDcolon', 'ApiAnnotation.AnnCloseP',+ -- 'ApiAnnotation.AnnEqual', 'ApiAnnotation.AnnRarrow',+ -- 'ApiAnnotation.AnnVbar'++ -- For details on above see note [Api annotations] in ApiAnnotation++deriving instance (DataId id) => Data (FamilyDecl id)++-- | Located Injectivity Annotation+type LInjectivityAnn name = Located (InjectivityAnn name)++-- | If the user supplied an injectivity annotation it is represented using+-- InjectivityAnn. At the moment this is a single injectivity condition - see+-- Note [Injectivity annotation]. `Located name` stores the LHS of injectivity+-- condition. `[Located name]` stores the RHS of injectivity condition. Example:+--+-- type family Foo a b c = r | r -> a c where ...+--+-- This will be represented as "InjectivityAnn `r` [`a`, `c`]"+data InjectivityAnn name+ = InjectivityAnn (Located name) [Located name]+ -- ^ - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnRarrow', 'ApiAnnotation.AnnVbar'++ -- For details on above see note [Api annotations] in ApiAnnotation+ deriving Data++data FamilyInfo name+ = DataFamily+ | OpenTypeFamily+ -- | 'Nothing' if we're in an hs-boot file and the user+ -- said "type family Foo x where .."+ | ClosedTypeFamily (Maybe [LTyFamInstEqn name])+deriving instance (DataId name) => Data (FamilyInfo name)++-- | Does this family declaration have a complete, user-supplied kind signature?+famDeclHasCusk :: Maybe Bool+ -- ^ if associated, does the enclosing class have a CUSK?+ -> FamilyDecl name -> Bool+famDeclHasCusk _ (FamilyDecl { fdInfo = ClosedTypeFamily _+ , fdTyVars = tyvars+ , fdResultSig = L _ resultSig })+ = hsTvbAllKinded tyvars && hasReturnKindSignature resultSig+famDeclHasCusk mb_class_cusk _ = mb_class_cusk `orElse` True+ -- all un-associated open families have CUSKs!++-- | Does this family declaration have user-supplied return kind signature?+hasReturnKindSignature :: FamilyResultSig a -> Bool+hasReturnKindSignature NoSig = False+hasReturnKindSignature (TyVarSig (L _ (UserTyVar _))) = False+hasReturnKindSignature _ = True++-- | Maybe return name of the result type variable+resultVariableName :: FamilyResultSig a -> Maybe a+resultVariableName (TyVarSig sig) = Just $ hsLTyVarName sig+resultVariableName _ = Nothing++instance (OutputableBndrId name) => Outputable (FamilyDecl name) where+ ppr = pprFamilyDecl TopLevel++pprFamilyDecl :: (OutputableBndrId name)+ => TopLevelFlag -> FamilyDecl name -> SDoc+pprFamilyDecl top_level (FamilyDecl { fdInfo = info, fdLName = ltycon+ , fdTyVars = tyvars+ , fdFixity = fixity+ , fdResultSig = L _ result+ , fdInjectivityAnn = mb_inj })+ = vcat [ pprFlavour info <+> pp_top_level <+>+ pp_vanilla_decl_head ltycon tyvars fixity [] <+>+ pp_kind <+> pp_inj <+> pp_where+ , nest 2 $ pp_eqns ]+ where+ pp_top_level = case top_level of+ TopLevel -> text "family"+ NotTopLevel -> empty++ pp_kind = case result of+ NoSig -> empty+ KindSig kind -> dcolon <+> ppr kind+ TyVarSig tv_bndr -> text "=" <+> ppr tv_bndr+ pp_inj = case mb_inj of+ Just (L _ (InjectivityAnn lhs rhs)) ->+ hsep [ vbar, ppr lhs, text "->", hsep (map ppr rhs) ]+ Nothing -> empty+ (pp_where, pp_eqns) = case info of+ ClosedTypeFamily mb_eqns ->+ ( text "where"+ , case mb_eqns of+ Nothing -> text ".."+ Just eqns -> vcat $ map ppr_fam_inst_eqn eqns )+ _ -> (empty, empty)++pprFlavour :: FamilyInfo name -> SDoc+pprFlavour DataFamily = text "data"+pprFlavour OpenTypeFamily = text "type"+pprFlavour (ClosedTypeFamily {}) = text "type"++instance Outputable (FamilyInfo name) where+ ppr info = pprFlavour info <+> text "family"++++{- *********************************************************************+* *+ Data types and data constructors+* *+********************************************************************* -}++-- | Haskell Data type Definition+data HsDataDefn name -- The payload of a data type defn+ -- Used *both* for vanilla data declarations,+ -- *and* for data family instances+ = -- | Declares a data type or newtype, giving its constructors+ -- @+ -- data/newtype T a = <constrs>+ -- data/newtype instance T [a] = <constrs>+ -- @+ HsDataDefn { dd_ND :: NewOrData,+ dd_ctxt :: LHsContext name, -- ^ Context+ dd_cType :: Maybe (Located CType),+ dd_kindSig:: Maybe (LHsKind name),+ -- ^ Optional kind signature.+ --+ -- @(Just k)@ for a GADT-style @data@,+ -- or @data instance@ decl, with explicit kind sig+ --+ -- Always @Nothing@ for H98-syntax decls++ dd_cons :: [LConDecl name],+ -- ^ Data constructors+ --+ -- For @data T a = T1 | T2 a@+ -- the 'LConDecl's all have 'ConDeclH98'.+ -- For @data T a where { T1 :: T a }@+ -- the 'LConDecls' all have 'ConDeclGADT'.++ dd_derivs :: HsDeriving name -- ^ Optional 'deriving' claues++ -- For details on above see note [Api annotations] in ApiAnnotation+ }+deriving instance (DataId id) => Data (HsDataDefn id)++-- | Haskell Deriving clause+type HsDeriving name = Located [LHsDerivingClause name]+ -- ^ The optional @deriving@ clauses of a data declaration. "Clauses" is+ -- plural because one can specify multiple deriving clauses using the+ -- @-XDerivingStrategies@ language extension.+ --+ -- The list of 'LHsDerivingClause's corresponds to exactly what the user+ -- requested to derive, in order. If no deriving clauses were specified,+ -- the list is empty.++type LHsDerivingClause name = Located (HsDerivingClause name)++-- | A single @deriving@ clause of a data declaration.+--+-- - 'ApiAnnotation.AnnKeywordId' :+-- 'ApiAnnotation.AnnDeriving', 'ApiAnnotation.AnnStock',+-- 'ApiAnnotation.AnnAnyClass', 'Api.AnnNewtype',+-- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'+data HsDerivingClause name+ -- See Note [Deriving strategies] in TcDeriv+ = HsDerivingClause+ { deriv_clause_strategy :: Maybe (Located DerivStrategy)+ -- ^ The user-specified strategy (if any) to use when deriving+ -- 'deriv_clause_tys'.+ , deriv_clause_tys :: Located [LHsSigType name]+ -- ^ The types to derive.+ --+ -- It uses 'LHsSigType's because, with @-XGeneralizedNewtypeDeriving@,+ -- we can mention type variables that aren't bound by the datatype, e.g.+ --+ -- > data T b = ... deriving (C [a])+ --+ -- should produce a derived instance for @C [a] (T b)@.+ }+deriving instance (DataId id) => Data (HsDerivingClause id)++instance (OutputableBndrId name)+ => Outputable (HsDerivingClause name) where+ ppr (HsDerivingClause { deriv_clause_strategy = dcs+ , deriv_clause_tys = L _ dct })+ = hsep [ text "deriving"+ , ppDerivStrategy dcs+ , pp_dct dct ]+ where+ -- This complexity is to distinguish between+ -- deriving Show+ -- deriving (Show)+ pp_dct [a@(HsIB { hsib_body = L _ HsAppsTy{} })] = parens (ppr a)+ pp_dct [a] = ppr a+ pp_dct _ = parens (interpp'SP dct)++data NewOrData+ = NewType -- ^ @newtype Blah ...@+ | DataType -- ^ @data Blah ...@+ deriving( Eq, Data ) -- Needed because Demand derives Eq++-- | Located data Constructor Declaration+type LConDecl name = Located (ConDecl name)+ -- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSemi' when+ -- in a GADT constructor list++ -- For details on above see note [Api annotations] in ApiAnnotation++-- |+--+-- @+-- data T b = forall a. Eq a => MkT a b+-- MkT :: forall b a. Eq a => MkT a b+--+-- data T b where+-- MkT1 :: Int -> T Int+--+-- data T = Int `MkT` Int+-- | MkT2+--+-- data T a where+-- Int `MkT` Int :: T Int+-- @+--+-- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnOpen',+-- 'ApiAnnotation.AnnDotdot','ApiAnnotation.AnnCLose',+-- 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnVbar',+-- 'ApiAnnotation.AnnDarrow','ApiAnnotation.AnnDarrow',+-- 'ApiAnnotation.AnnForall','ApiAnnotation.AnnDot'++-- For details on above see note [Api annotations] in ApiAnnotation++-- | data Constructor Declaration+data ConDecl name+ = ConDeclGADT+ { con_names :: [Located name]+ , con_type :: LHsSigType name+ -- ^ The type after the ‘::’+ , con_doc :: Maybe LHsDocString+ -- ^ A possible Haddock comment.+ }++ | ConDeclH98+ { con_name :: Located name++ , con_qvars :: Maybe (LHsQTyVars name)+ -- User-written forall (if any), and its implicit+ -- kind variables+ -- Non-Nothing needs -XExistentialQuantification+ -- e.g. data T a = forall b. MkT b (b->a)+ -- con_qvars = {b}++ , con_cxt :: Maybe (LHsContext name)+ -- ^ User-written context (if any)++ , con_details :: HsConDeclDetails name+ -- ^ Arguments++ , con_doc :: Maybe LHsDocString+ -- ^ A possible Haddock comment.+ }+deriving instance (DataId name) => Data (ConDecl name)++-- | Haskell data Constructor Declaration Details+type HsConDeclDetails name+ = HsConDetails (LBangType name) (Located [LConDeclField name])++getConNames :: ConDecl name -> [Located name]+getConNames ConDeclH98 {con_name = name} = [name]+getConNames ConDeclGADT {con_names = names} = names++-- don't call with RdrNames, because it can't deal with HsAppsTy+getConDetails :: ConDecl name -> HsConDeclDetails name+getConDetails ConDeclH98 {con_details = details} = details+getConDetails ConDeclGADT {con_type = ty } = details+ where+ (details,_,_,_) = gadtDeclDetails ty++-- don't call with RdrNames, because it can't deal with HsAppsTy+gadtDeclDetails :: LHsSigType name+ -> ( HsConDeclDetails name+ , LHsType name+ , LHsContext name+ , [LHsTyVarBndr name] )+gadtDeclDetails HsIB {hsib_body = lbody_ty} = (details,res_ty,cxt,tvs)+ where+ (tvs, cxt, tau) = splitLHsSigmaTy lbody_ty+ (details, res_ty) -- See Note [Sorting out the result type]+ = case tau of+ L _ (HsFunTy (L l (HsRecTy flds)) res_ty')+ -> (RecCon (L l flds), res_ty')+ _other -> (PrefixCon [], tau)++hsConDeclArgTys :: HsConDeclDetails name -> [LBangType name]+hsConDeclArgTys (PrefixCon tys) = tys+hsConDeclArgTys (InfixCon ty1 ty2) = [ty1,ty2]+hsConDeclArgTys (RecCon flds) = map (cd_fld_type . unLoc) (unLoc flds)++pp_data_defn :: (OutputableBndrId name)+ => (HsContext name -> SDoc) -- Printing the header+ -> HsDataDefn name+ -> SDoc+pp_data_defn pp_hdr (HsDataDefn { dd_ND = new_or_data, dd_ctxt = L _ context+ , dd_cType = mb_ct+ , dd_kindSig = mb_sig+ , dd_cons = condecls, dd_derivs = derivings })+ | null condecls+ = ppr new_or_data <+> pp_ct <+> pp_hdr context <+> pp_sig+ <+> pp_derivings derivings++ | otherwise+ = hang (ppr new_or_data <+> pp_ct <+> pp_hdr context <+> pp_sig)+ 2 (pp_condecls condecls $$ pp_derivings derivings)+ where+ pp_ct = case mb_ct of+ Nothing -> empty+ Just ct -> ppr ct+ pp_sig = case mb_sig of+ Nothing -> empty+ Just kind -> dcolon <+> ppr kind+ pp_derivings (L _ ds) = vcat (map ppr ds)++instance (OutputableBndrId name) => Outputable (HsDataDefn name) where+ ppr d = pp_data_defn (\_ -> text "Naked HsDataDefn") d++instance Outputable NewOrData where+ ppr NewType = text "newtype"+ ppr DataType = text "data"++pp_condecls :: (OutputableBndrId name) => [LConDecl name] -> SDoc+pp_condecls cs@(L _ ConDeclGADT{} : _) -- In GADT syntax+ = hang (text "where") 2 (vcat (map ppr cs))+pp_condecls cs -- In H98 syntax+ = equals <+> sep (punctuate (text " |") (map ppr cs))++instance (OutputableBndrId name) => Outputable (ConDecl name) where+ ppr = pprConDecl++pprConDecl :: (OutputableBndrId name) => ConDecl name -> SDoc+pprConDecl (ConDeclH98 { con_name = L _ con+ , con_qvars = mtvs+ , con_cxt = mcxt+ , con_details = details+ , con_doc = doc })+ = sep [ppr_mbDoc doc, pprHsForAll tvs cxt, ppr_details details]+ where+ ppr_details (InfixCon t1 t2) = hsep [ppr t1, pprInfixOcc con, ppr t2]+ ppr_details (PrefixCon tys) = hsep (pprPrefixOcc con+ : map (pprParendHsType . unLoc) tys)+ ppr_details (RecCon fields) = pprPrefixOcc con+ <+> pprConDeclFields (unLoc fields)+ tvs = case mtvs of+ Nothing -> []+ Just (HsQTvs { hsq_explicit = tvs }) -> tvs++ cxt = fromMaybe (noLoc []) mcxt++pprConDecl (ConDeclGADT { con_names = cons, con_type = res_ty, con_doc = doc })+ = sep [ppr_mbDoc doc <+> ppr_con_names cons <+> dcolon+ <+> ppr res_ty]++ppr_con_names :: (OutputableBndr name) => [Located name] -> SDoc+ppr_con_names = pprWithCommas (pprPrefixOcc . unLoc)++{-+************************************************************************+* *+ Instance declarations+* *+************************************************************************++Note [Type family instance declarations in HsSyn]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The data type TyFamEqn represents one equation of a type family instance.+It is parameterised over its tfe_pats field:++ * An ordinary type family instance declaration looks like this in source Haskell+ type instance T [a] Int = a -> a+ (or something similar for a closed family)+ It is represented by a TyFamInstEqn, with *type* in the tfe_pats field.++ * On the other hand, the *default instance* of an associated type looks like+ this in source Haskell+ class C a where+ type T a b+ type T a b = a -> b -- The default instance+ It is represented by a TyFamDefltEqn, with *type variables* in the tfe_pats+ field.+-}++----------------- Type synonym family instances -------------++-- | Located Type Family Instance Equation+type LTyFamInstEqn name = Located (TyFamInstEqn name)+ -- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSemi'+ -- when in a list++-- For details on above see note [Api annotations] in ApiAnnotation++-- | Located Type Family Default Equation+type LTyFamDefltEqn name = Located (TyFamDefltEqn name)++-- | Haskell Type Patterns+type HsTyPats name = HsImplicitBndrs name [LHsType name]+ -- ^ Type patterns (with kind and type bndrs)+ -- See Note [Family instance declaration binders]++{- Note [Family instance declaration binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The HsTyPats field is LHS patterns or a type/data family instance.++The hsib_vars of the HsImplicitBndrs are the template variables of the+type patterns, i.e. fv(pat_tys). Note in particular++* The hsib_vars *includes* any anonymous wildcards. For example+ type instance F a _ = a+ The hsib_vars will be {a, _}. Remember that each separate wildcard+ '_' gets its own unique. In this context wildcards behave just like+ an ordinary type variable, only anonymous.++* The hsib_vars *including* type variables that are already in scope++ Eg class C s t where+ type F t p :: *+ instance C w (a,b) where+ type F (a,b) x = x->a+ The hsib_vars of the F decl are {a,b,x}, even though the F decl+ is nested inside the 'instance' decl.++ However after the renamer, the uniques will match up:+ instance C w7 (a8,b9) where+ type F (a8,b9) x10 = x10->a8+ so that we can compare the type pattern in the 'instance' decl and+ in the associated 'type' decl+-}++-- | Type Family Instance Equation+type TyFamInstEqn name = TyFamEqn name (HsTyPats name)++-- | Type Family Default Equation+type TyFamDefltEqn name = TyFamEqn name (LHsQTyVars name)+ -- See Note [Type family instance declarations in HsSyn]++-- | Type Family Equation+--+-- One equation in a type family instance declaration+-- See Note [Type family instance declarations in HsSyn]+data TyFamEqn name pats+ = TyFamEqn+ { tfe_tycon :: Located name+ , tfe_pats :: pats+ , tfe_fixity :: LexicalFixity -- ^ Fixity used in the declaration+ , tfe_rhs :: LHsType name }+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnEqual'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name, Data pats) => Data (TyFamEqn name pats)++-- | Located Type Family Instance Declaration+type LTyFamInstDecl name = Located (TyFamInstDecl name)++-- | Type Family Instance Declaration+data TyFamInstDecl name+ = TyFamInstDecl+ { tfid_eqn :: LTyFamInstEqn name+ , tfid_fvs :: PostRn name NameSet }+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnType',+ -- 'ApiAnnotation.AnnInstance',++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (TyFamInstDecl name)++----------------- Data family instances -------------++-- | Located Data Family Instance Declaration+type LDataFamInstDecl name = Located (DataFamInstDecl name)++-- | Data Family Instance Declaration+data DataFamInstDecl name+ = DataFamInstDecl+ { dfid_tycon :: Located name+ , dfid_pats :: HsTyPats name -- LHS+ , dfid_fixity :: LexicalFixity -- ^ Fixity used in the declaration+ , dfid_defn :: HsDataDefn name -- RHS+ , dfid_fvs :: PostRn name NameSet } -- Free vars for dependency analysis+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnData',+ -- 'ApiAnnotation.AnnNewType','ApiAnnotation.AnnInstance',+ -- 'ApiAnnotation.AnnDcolon'+ -- 'ApiAnnotation.AnnWhere','ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (DataFamInstDecl name)+++----------------- Class instances -------------++-- | Located Class Instance Declaration+type LClsInstDecl name = Located (ClsInstDecl name)++-- | Class Instance Declaration+data ClsInstDecl name+ = ClsInstDecl+ { cid_poly_ty :: LHsSigType name -- Context => Class Instance-type+ -- Using a polytype means that the renamer conveniently+ -- figures out the quantified type variables for us.+ , cid_binds :: LHsBinds name -- Class methods+ , cid_sigs :: [LSig name] -- User-supplied pragmatic info+ , cid_tyfam_insts :: [LTyFamInstDecl name] -- Type family instances+ , cid_datafam_insts :: [LDataFamInstDecl name] -- Data family instances+ , cid_overlap_mode :: Maybe (Located OverlapMode)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose',++ -- For details on above see note [Api annotations] in ApiAnnotation+ }+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnInstance',+ -- 'ApiAnnotation.AnnWhere',+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose',++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId id) => Data (ClsInstDecl id)+++----------------- Instances of all kinds -------------++-- | Located Instance Declaration+type LInstDecl name = Located (InstDecl name)++-- | Instance Declaration+data InstDecl name -- Both class and family instances+ = ClsInstD+ { cid_inst :: ClsInstDecl name }+ | DataFamInstD -- data family instance+ { dfid_inst :: DataFamInstDecl name }+ | TyFamInstD -- type family instance+ { tfid_inst :: TyFamInstDecl name }+deriving instance (DataId id) => Data (InstDecl id)++instance (OutputableBndrId name) => Outputable (TyFamInstDecl name) where+ ppr = pprTyFamInstDecl TopLevel++pprTyFamInstDecl :: (OutputableBndrId name)+ => TopLevelFlag -> TyFamInstDecl name -> SDoc+pprTyFamInstDecl top_lvl (TyFamInstDecl { tfid_eqn = eqn })+ = text "type" <+> ppr_instance_keyword top_lvl <+> ppr_fam_inst_eqn eqn++ppr_instance_keyword :: TopLevelFlag -> SDoc+ppr_instance_keyword TopLevel = text "instance"+ppr_instance_keyword NotTopLevel = empty++ppr_fam_inst_eqn :: (OutputableBndrId name) => LTyFamInstEqn name -> SDoc+ppr_fam_inst_eqn (L _ (TyFamEqn { tfe_tycon = tycon+ , tfe_pats = pats+ , tfe_fixity = fixity+ , tfe_rhs = rhs }))+ = pp_fam_inst_lhs tycon pats fixity [] <+> equals <+> ppr rhs++ppr_fam_deflt_eqn :: (OutputableBndrId name) => LTyFamDefltEqn name -> SDoc+ppr_fam_deflt_eqn (L _ (TyFamEqn { tfe_tycon = tycon+ , tfe_pats = tvs+ , tfe_fixity = fixity+ , tfe_rhs = rhs }))+ = text "type" <+> pp_vanilla_decl_head tycon tvs fixity []+ <+> equals <+> ppr rhs++instance (OutputableBndrId name) => Outputable (DataFamInstDecl name) where+ ppr = pprDataFamInstDecl TopLevel++pprDataFamInstDecl :: (OutputableBndrId name)+ => TopLevelFlag -> DataFamInstDecl name -> SDoc+pprDataFamInstDecl top_lvl (DataFamInstDecl { dfid_tycon = tycon+ , dfid_pats = pats+ , dfid_fixity = fixity+ , dfid_defn = defn })+ = pp_data_defn pp_hdr defn+ where+ pp_hdr ctxt = ppr_instance_keyword top_lvl+ <+> pp_fam_inst_lhs tycon pats fixity ctxt++pprDataFamInstFlavour :: DataFamInstDecl name -> SDoc+pprDataFamInstFlavour (DataFamInstDecl { dfid_defn = (HsDataDefn { dd_ND = nd }) })+ = ppr nd++pp_fam_inst_lhs :: (OutputableBndrId name) => Located name+ -> HsTyPats name+ -> LexicalFixity+ -> HsContext name+ -> SDoc+pp_fam_inst_lhs thing (HsIB { hsib_body = typats }) fixity context+ -- explicit type patterns+ = hsep [ pprHsContext context, pp_pats typats]+ where+ pp_pats (patl:patsr)+ | fixity == Infix+ = hsep [pprParendHsType (unLoc patl), pprInfixOcc (unLoc thing)+ , hsep (map (pprParendHsType.unLoc) patsr)]+ | otherwise = hsep [ pprPrefixOcc (unLoc thing)+ , hsep (map (pprParendHsType.unLoc) (patl:patsr))]+ pp_pats [] = empty++instance (OutputableBndrId name) => Outputable (ClsInstDecl name) where+ ppr (ClsInstDecl { cid_poly_ty = inst_ty, cid_binds = binds+ , cid_sigs = sigs, cid_tyfam_insts = ats+ , cid_overlap_mode = mbOverlap+ , cid_datafam_insts = adts })+ | null sigs, null ats, null adts, isEmptyBag binds -- No "where" part+ = top_matter++ | otherwise -- Laid out+ = vcat [ top_matter <+> text "where"+ , nest 2 $ pprDeclList $+ map (pprTyFamInstDecl NotTopLevel . unLoc) ats +++ map (pprDataFamInstDecl NotTopLevel . unLoc) adts +++ pprLHsBindsForUser binds sigs ]+ where+ top_matter = text "instance" <+> ppOverlapPragma mbOverlap+ <+> ppr inst_ty++ppDerivStrategy :: Maybe (Located DerivStrategy) -> SDoc+ppDerivStrategy mb =+ case mb of+ Nothing -> empty+ Just (L _ ds) -> ppr ds++ppOverlapPragma :: Maybe (Located OverlapMode) -> SDoc+ppOverlapPragma mb =+ case mb of+ Nothing -> empty+ Just (L _ (NoOverlap s)) -> maybe_stext s "{-# NO_OVERLAP #-}"+ Just (L _ (Overlappable s)) -> maybe_stext s "{-# OVERLAPPABLE #-}"+ Just (L _ (Overlapping s)) -> maybe_stext s "{-# OVERLAPPING #-}"+ Just (L _ (Overlaps s)) -> maybe_stext s "{-# OVERLAPS #-}"+ Just (L _ (Incoherent s)) -> maybe_stext s "{-# INCOHERENT #-}"+ where+ maybe_stext NoSourceText alt = text alt+ maybe_stext (SourceText src) _ = text src <+> text "#-}"+++instance (OutputableBndrId name) => Outputable (InstDecl name) where+ ppr (ClsInstD { cid_inst = decl }) = ppr decl+ ppr (TyFamInstD { tfid_inst = decl }) = ppr decl+ ppr (DataFamInstD { dfid_inst = decl }) = ppr decl++-- Extract the declarations of associated data types from an instance++instDeclDataFamInsts :: [LInstDecl name] -> [DataFamInstDecl name]+instDeclDataFamInsts inst_decls+ = concatMap do_one inst_decls+ where+ do_one (L _ (ClsInstD { cid_inst = ClsInstDecl { cid_datafam_insts = fam_insts } }))+ = map unLoc fam_insts+ do_one (L _ (DataFamInstD { dfid_inst = fam_inst })) = [fam_inst]+ do_one (L _ (TyFamInstD {})) = []++{-+************************************************************************+* *+\subsection[DerivDecl]{A stand-alone instance deriving declaration}+* *+************************************************************************+-}++-- | Located Deriving Declaration+type LDerivDecl name = Located (DerivDecl name)++-- | Deriving Declaration+data DerivDecl name = DerivDecl+ { deriv_type :: LHsSigType name+ , deriv_strategy :: Maybe (Located DerivStrategy)+ , deriv_overlap_mode :: Maybe (Located OverlapMode)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDeriving',+ -- 'ApiAnnotation.AnnInstance', 'ApiAnnotation.AnnStock',+ -- 'ApiAnnotation.AnnAnyClass', 'Api.AnnNewtype',+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ }+deriving instance (DataId name) => Data (DerivDecl name)++instance (OutputableBndrId name) => Outputable (DerivDecl name) where+ ppr (DerivDecl { deriv_type = ty+ , deriv_strategy = ds+ , deriv_overlap_mode = o })+ = hsep [ text "deriving"+ , ppDerivStrategy ds+ , text "instance"+ , ppOverlapPragma o+ , ppr ty ]++{-+************************************************************************+* *+\subsection[DefaultDecl]{A @default@ declaration}+* *+************************************************************************++There can only be one default declaration per module, but it is hard+for the parser to check that; we pass them all through in the abstract+syntax, and that restriction must be checked in the front end.+-}++-- | Located Default Declaration+type LDefaultDecl name = Located (DefaultDecl name)++-- | Default Declaration+data DefaultDecl name+ = DefaultDecl [LHsType name]+ -- ^ - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnDefault',+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (DefaultDecl name)++instance (OutputableBndrId name) => Outputable (DefaultDecl name) where++ ppr (DefaultDecl tys)+ = text "default" <+> parens (interpp'SP tys)++{-+************************************************************************+* *+\subsection{Foreign function interface declaration}+* *+************************************************************************+-}++-- foreign declarations are distinguished as to whether they define or use a+-- Haskell name+--+-- * the Boolean value indicates whether the pre-standard deprecated syntax+-- has been used++-- | Located Foreign Declaration+type LForeignDecl name = Located (ForeignDecl name)++-- | Foreign Declaration+data ForeignDecl name+ = ForeignImport+ { fd_name :: Located name -- defines this name+ , fd_sig_ty :: LHsSigType name -- sig_ty+ , fd_co :: PostTc name Coercion -- rep_ty ~ sig_ty+ , fd_fi :: ForeignImport }++ | ForeignExport+ { fd_name :: Located name -- uses this name+ , fd_sig_ty :: LHsSigType name -- sig_ty+ , fd_co :: PostTc name Coercion -- rep_ty ~ sig_ty+ , fd_fe :: ForeignExport }+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnForeign',+ -- 'ApiAnnotation.AnnImport','ApiAnnotation.AnnExport',+ -- 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation++deriving instance (DataId name) => Data (ForeignDecl name)+{-+ In both ForeignImport and ForeignExport:+ sig_ty is the type given in the Haskell code+ rep_ty is the representation for this type, i.e. with newtypes+ coerced away and type functions evaluated.+ Thus if the declaration is valid, then rep_ty will only use types+ such as Int and IO that we know how to make foreign calls with.+-}++noForeignImportCoercionYet :: PlaceHolder+noForeignImportCoercionYet = PlaceHolder++noForeignExportCoercionYet :: PlaceHolder+noForeignExportCoercionYet = PlaceHolder++-- Specification Of an imported external entity in dependence on the calling+-- convention+--+data ForeignImport = -- import of a C entity+ --+ -- * the two strings specifying a header file or library+ -- may be empty, which indicates the absence of a+ -- header or object specification (both are not used+ -- in the case of `CWrapper' and when `CFunction'+ -- has a dynamic target)+ --+ -- * the calling convention is irrelevant for code+ -- generation in the case of `CLabel', but is needed+ -- for pretty printing+ --+ -- * `Safety' is irrelevant for `CLabel' and `CWrapper'+ --+ CImport (Located CCallConv) -- ccall or stdcall+ (Located Safety) -- interruptible, safe or unsafe+ (Maybe Header) -- name of C header+ CImportSpec -- details of the C entity+ (Located SourceText) -- original source text for+ -- the C entity+ deriving Data++-- details of an external C entity+--+data CImportSpec = CLabel CLabelString -- import address of a C label+ | CFunction CCallTarget -- static or dynamic function+ | CWrapper -- wrapper to expose closures+ -- (former f.e.d.)+ deriving Data++-- specification of an externally exported entity in dependence on the calling+-- convention+--+data ForeignExport = CExport (Located CExportSpec) -- contains the calling+ -- convention+ (Located SourceText) -- original source text for+ -- the C entity+ deriving Data++-- pretty printing of foreign declarations+--++instance (OutputableBndrId name) => Outputable (ForeignDecl name) where+ ppr (ForeignImport { fd_name = n, fd_sig_ty = ty, fd_fi = fimport })+ = hang (text "foreign import" <+> ppr fimport <+> ppr n)+ 2 (dcolon <+> ppr ty)+ ppr (ForeignExport { fd_name = n, fd_sig_ty = ty, fd_fe = fexport }) =+ hang (text "foreign export" <+> ppr fexport <+> ppr n)+ 2 (dcolon <+> ppr ty)++instance Outputable ForeignImport where+ ppr (CImport cconv safety mHeader spec (L _ srcText)) =+ ppr cconv <+> ppr safety+ <+> pprWithSourceText srcText (pprCEntity spec "")+ where+ pp_hdr = case mHeader of+ Nothing -> empty+ Just (Header _ header) -> ftext header++ pprCEntity (CLabel lbl) _ =+ doubleQuotes $ text "static" <+> pp_hdr <+> char '&' <> ppr lbl+ pprCEntity (CFunction (StaticTarget st _lbl _ isFun)) src =+ if dqNeeded then doubleQuotes ce else empty+ where+ dqNeeded = (take 6 src == "static")+ || isJust mHeader+ || not isFun+ || st /= NoSourceText+ ce =+ -- We may need to drop leading spaces first+ (if take 6 src == "static" then text "static" else empty)+ <+> pp_hdr+ <+> (if isFun then empty else text "value")+ <+> (pprWithSourceText st empty)+ pprCEntity (CFunction DynamicTarget) _ =+ doubleQuotes $ text "dynamic"+ pprCEntity CWrapper _ = doubleQuotes $ text "wrapper"++instance Outputable ForeignExport where+ ppr (CExport (L _ (CExportStatic _ lbl cconv)) _) =+ ppr cconv <+> char '"' <> ppr lbl <> char '"'++{-+************************************************************************+* *+\subsection{Transformation rules}+* *+************************************************************************+-}++-- | Located Rule Declarations+type LRuleDecls name = Located (RuleDecls name)++ -- Note [Pragma source text] in BasicTypes+-- | Rule Declarations+data RuleDecls name = HsRules { rds_src :: SourceText+ , rds_rules :: [LRuleDecl name] }+deriving instance (DataId name) => Data (RuleDecls name)++-- | Located Rule Declaration+type LRuleDecl name = Located (RuleDecl name)++-- | Rule Declaration+data RuleDecl name+ = HsRule -- Source rule+ (Located (SourceText,RuleName)) -- Rule name+ -- Note [Pragma source text] in BasicTypes+ Activation+ [LRuleBndr name] -- Forall'd vars; after typechecking this+ -- includes tyvars+ (Located (HsExpr name)) -- LHS+ (PostRn name NameSet) -- Free-vars from the LHS+ (Located (HsExpr name)) -- RHS+ (PostRn name NameSet) -- Free-vars from the RHS+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnTilde',+ -- 'ApiAnnotation.AnnVal',+ -- 'ApiAnnotation.AnnClose',+ -- 'ApiAnnotation.AnnForall','ApiAnnotation.AnnDot',+ -- 'ApiAnnotation.AnnEqual',++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (RuleDecl name)++flattenRuleDecls :: [LRuleDecls name] -> [LRuleDecl name]+flattenRuleDecls decls = concatMap (rds_rules . unLoc) decls++-- | Located Rule Binder+type LRuleBndr name = Located (RuleBndr name)++-- | Rule Binder+data RuleBndr name+ = RuleBndr (Located name)+ | RuleBndrSig (Located name) (LHsSigWcType name)+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnDcolon','ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (RuleBndr name)++collectRuleBndrSigTys :: [RuleBndr name] -> [LHsSigWcType name]+collectRuleBndrSigTys bndrs = [ty | RuleBndrSig _ ty <- bndrs]++pprFullRuleName :: Located (SourceText, RuleName) -> SDoc+pprFullRuleName (L _ (st, n)) = pprWithSourceText st (doubleQuotes $ ftext n)++instance (OutputableBndrId name) => Outputable (RuleDecls name) where+ ppr (HsRules st rules)+ = pprWithSourceText st (text "{-# RULES")+ <+> vcat (punctuate semi (map ppr rules)) <+> text "#-}"++instance (OutputableBndrId name) => Outputable (RuleDecl name) where+ ppr (HsRule name act ns lhs _fv_lhs rhs _fv_rhs)+ = sep [pprFullRuleName name <+> ppr act,+ nest 4 (pp_forall <+> pprExpr (unLoc lhs)),+ nest 6 (equals <+> pprExpr (unLoc rhs)) ]+ where+ pp_forall | null ns = empty+ | otherwise = forAllLit <+> fsep (map ppr ns) <> dot++instance (OutputableBndrId name) => Outputable (RuleBndr name) where+ ppr (RuleBndr name) = ppr name+ ppr (RuleBndrSig name ty) = parens (ppr name <> dcolon <> ppr ty)++{-+************************************************************************+* *+\subsection{Vectorisation declarations}+* *+************************************************************************++A vectorisation pragma, one of++ {-# VECTORISE f = closure1 g (scalar_map g) #-}+ {-# VECTORISE SCALAR f #-}+ {-# NOVECTORISE f #-}++ {-# VECTORISE type T = ty #-}+ {-# VECTORISE SCALAR type T #-}+-}++-- | Located Vectorise Declaration+type LVectDecl name = Located (VectDecl name)++-- | Vectorise Declaration+data VectDecl name+ = HsVect+ SourceText -- Note [Pragma source text] in BasicTypes+ (Located name)+ (LHsExpr name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsNoVect+ SourceText -- Note [Pragma source text] in BasicTypes+ (Located name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsVectTypeIn -- pre type-checking+ SourceText -- Note [Pragma source text] in BasicTypes+ Bool -- 'TRUE' => SCALAR declaration+ (Located name)+ (Maybe (Located name)) -- 'Nothing' => no right-hand side+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnType','ApiAnnotation.AnnClose',+ -- 'ApiAnnotation.AnnEqual'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsVectTypeOut -- post type-checking+ Bool -- 'TRUE' => SCALAR declaration+ TyCon+ (Maybe TyCon) -- 'Nothing' => no right-hand side+ | HsVectClassIn -- pre type-checking+ SourceText -- Note [Pragma source text] in BasicTypes+ (Located name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClass','ApiAnnotation.AnnClose',++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsVectClassOut -- post type-checking+ Class+ | HsVectInstIn -- pre type-checking (always SCALAR) !!!FIXME: should be superfluous now+ (LHsSigType name)+ | HsVectInstOut -- post type-checking (always SCALAR) !!!FIXME: should be superfluous now+ ClsInst+deriving instance (DataId name) => Data (VectDecl name)++lvectDeclName :: NamedThing name => LVectDecl name -> Name+lvectDeclName (L _ (HsVect _ (L _ name) _)) = getName name+lvectDeclName (L _ (HsNoVect _ (L _ name))) = getName name+lvectDeclName (L _ (HsVectTypeIn _ _ (L _ name) _)) = getName name+lvectDeclName (L _ (HsVectTypeOut _ tycon _)) = getName tycon+lvectDeclName (L _ (HsVectClassIn _ (L _ name))) = getName name+lvectDeclName (L _ (HsVectClassOut cls)) = getName cls+lvectDeclName (L _ (HsVectInstIn _))+ = panic "HsDecls.lvectDeclName: HsVectInstIn"+lvectDeclName (L _ (HsVectInstOut _))+ = panic "HsDecls.lvectDeclName: HsVectInstOut"++lvectInstDecl :: LVectDecl name -> Bool+lvectInstDecl (L _ (HsVectInstIn _)) = True+lvectInstDecl (L _ (HsVectInstOut _)) = True+lvectInstDecl _ = False++instance (OutputableBndrId name) => Outputable (VectDecl name) where+ ppr (HsVect _ v rhs)+ = sep [text "{-# VECTORISE" <+> ppr v,+ nest 4 $+ pprExpr (unLoc rhs) <+> text "#-}" ]+ ppr (HsNoVect _ v)+ = sep [text "{-# NOVECTORISE" <+> ppr v <+> text "#-}" ]+ ppr (HsVectTypeIn _ False t Nothing)+ = sep [text "{-# VECTORISE type" <+> ppr t <+> text "#-}" ]+ ppr (HsVectTypeIn _ False t (Just t'))+ = sep [text "{-# VECTORISE type" <+> ppr t, text "=", ppr t', text "#-}" ]+ ppr (HsVectTypeIn _ True t Nothing)+ = sep [text "{-# VECTORISE SCALAR type" <+> ppr t <+> text "#-}" ]+ ppr (HsVectTypeIn _ True t (Just t'))+ = sep [text "{-# VECTORISE SCALAR type" <+> ppr t, text "=", ppr t', text "#-}" ]+ ppr (HsVectTypeOut False t Nothing)+ = sep [text "{-# VECTORISE type" <+> ppr t <+> text "#-}" ]+ ppr (HsVectTypeOut False t (Just t'))+ = sep [text "{-# VECTORISE type" <+> ppr t, text "=", ppr t', text "#-}" ]+ ppr (HsVectTypeOut True t Nothing)+ = sep [text "{-# VECTORISE SCALAR type" <+> ppr t <+> text "#-}" ]+ ppr (HsVectTypeOut True t (Just t'))+ = sep [text "{-# VECTORISE SCALAR type" <+> ppr t, text "=", ppr t', text "#-}" ]+ ppr (HsVectClassIn _ c)+ = sep [text "{-# VECTORISE class" <+> ppr c <+> text "#-}" ]+ ppr (HsVectClassOut c)+ = sep [text "{-# VECTORISE class" <+> ppr c <+> text "#-}" ]+ ppr (HsVectInstIn ty)+ = sep [text "{-# VECTORISE SCALAR instance" <+> ppr ty <+> text "#-}" ]+ ppr (HsVectInstOut i)+ = sep [text "{-# VECTORISE SCALAR instance" <+> ppr i <+> text "#-}" ]++{-+************************************************************************+* *+\subsection[DocDecl]{Document comments}+* *+************************************************************************+-}++-- | Located Documentation comment Declaration+type LDocDecl = Located (DocDecl)++-- | Documentation comment Declaration+data DocDecl+ = DocCommentNext HsDocString+ | DocCommentPrev HsDocString+ | DocCommentNamed String HsDocString+ | DocGroup Int HsDocString+ deriving Data++-- Okay, I need to reconstruct the document comments, but for now:+instance Outputable DocDecl where+ ppr _ = text "<document comment>"++docDeclDoc :: DocDecl -> HsDocString+docDeclDoc (DocCommentNext d) = d+docDeclDoc (DocCommentPrev d) = d+docDeclDoc (DocCommentNamed _ d) = d+docDeclDoc (DocGroup _ d) = d++{-+************************************************************************+* *+\subsection[DeprecDecl]{Deprecations}+* *+************************************************************************++We use exported entities for things to deprecate.+-}++-- | Located Warning Declarations+type LWarnDecls name = Located (WarnDecls name)++ -- Note [Pragma source text] in BasicTypes+-- | Warning pragma Declarations+data WarnDecls name = Warnings { wd_src :: SourceText+ , wd_warnings :: [LWarnDecl name]+ }+ deriving Data++-- | Located Warning pragma Declaration+type LWarnDecl name = Located (WarnDecl name)++-- | Warning pragma Declaration+data WarnDecl name = Warning [Located name] WarningTxt+ deriving Data++instance OutputableBndr name => Outputable (WarnDecls name) where+ ppr (Warnings (SourceText src) decls)+ = text src <+> vcat (punctuate comma (map ppr decls)) <+> text "#-}"+ ppr (Warnings NoSourceText _decls) = panic "WarnDecls"++instance OutputableBndr name => Outputable (WarnDecl name) where+ ppr (Warning thing txt)+ = hsep ( punctuate comma (map ppr thing))+ <+> ppr txt++{-+************************************************************************+* *+\subsection[AnnDecl]{Annotations}+* *+************************************************************************+-}++-- | Located Annotation Declaration+type LAnnDecl name = Located (AnnDecl name)++-- | Annotation Declaration+data AnnDecl name = HsAnnotation+ SourceText -- Note [Pragma source text] in BasicTypes+ (AnnProvenance name) (Located (HsExpr name))+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnType'+ -- 'ApiAnnotation.AnnModule'+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (AnnDecl name)++instance (OutputableBndrId name) => Outputable (AnnDecl name) where+ ppr (HsAnnotation _ provenance expr)+ = hsep [text "{-#", pprAnnProvenance provenance, pprExpr (unLoc expr), text "#-}"]++-- | Annotation Provenance+data AnnProvenance name = ValueAnnProvenance (Located name)+ | TypeAnnProvenance (Located name)+ | ModuleAnnProvenance+ deriving (Data, Functor)+deriving instance Foldable AnnProvenance+deriving instance Traversable AnnProvenance++annProvenanceName_maybe :: AnnProvenance name -> Maybe name+annProvenanceName_maybe (ValueAnnProvenance (L _ name)) = Just name+annProvenanceName_maybe (TypeAnnProvenance (L _ name)) = Just name+annProvenanceName_maybe ModuleAnnProvenance = Nothing++pprAnnProvenance :: OutputableBndr name => AnnProvenance name -> SDoc+pprAnnProvenance ModuleAnnProvenance = text "ANN module"+pprAnnProvenance (ValueAnnProvenance (L _ name))+ = text "ANN" <+> ppr name+pprAnnProvenance (TypeAnnProvenance (L _ name))+ = text "ANN type" <+> ppr name++{-+************************************************************************+* *+\subsection[RoleAnnot]{Role annotations}+* *+************************************************************************+-}++-- | Located Role Annotation Declaration+type LRoleAnnotDecl name = Located (RoleAnnotDecl name)++-- See #8185 for more info about why role annotations are+-- top-level declarations+-- | Role Annotation Declaration+data RoleAnnotDecl name+ = RoleAnnotDecl (Located name) -- type constructor+ [Located (Maybe Role)] -- optional annotations+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnType',+ -- 'ApiAnnotation.AnnRole'++ -- For details on above see note [Api annotations] in ApiAnnotation+ deriving Data++instance OutputableBndr name => Outputable (RoleAnnotDecl name) where+ ppr (RoleAnnotDecl ltycon roles)+ = text "type role" <+> ppr ltycon <+>+ hsep (map (pp_role . unLoc) roles)+ where+ pp_role Nothing = underscore+ pp_role (Just r) = ppr r++roleAnnotDeclName :: RoleAnnotDecl name -> name+roleAnnotDeclName (RoleAnnotDecl (L _ name) _) = name
+ hsSyn/HsDoc.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE CPP, DeriveDataTypeable #-}++module HsDoc (+ HsDocString(..),+ LHsDocString,+ ppr_mbDoc+ ) where++#include "HsVersions.h"++import Outputable+import SrcLoc+import FastString++import Data.Data++-- | Haskell Documentation String+newtype HsDocString = HsDocString FastString+ deriving (Eq, Show, Data)++-- | Located Haskell Documentation String+type LHsDocString = Located HsDocString++instance Outputable HsDocString where+ ppr (HsDocString fs) = ftext fs++ppr_mbDoc :: Maybe LHsDocString -> SDoc+ppr_mbDoc (Just doc) = ppr doc+ppr_mbDoc Nothing = empty+
+ hsSyn/HsDumpAst.hs view
@@ -0,0 +1,206 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Contains a debug function to dump parts of the hsSyn AST. It uses a syb+-- traversal which falls back to displaying based on the constructor name, so+-- can be used to dump anything having a @Data.Data@ instance.++module HsDumpAst (+ -- * Dumping ASTs+ showAstData,+ BlankSrcSpan(..),+ ) where++import Data.Data hiding (Fixity)+import Data.List+import Bag+import BasicTypes+import FastString+import NameSet+import Name+import RdrName+import DataCon+import SrcLoc+import HsSyn+import OccName hiding (occName)+import Var+import Module+import DynFlags+import Outputable hiding (space)++import qualified Data.ByteString as B++data BlankSrcSpan = BlankSrcSpan | NoBlankSrcSpan+ deriving (Eq,Show)++-- | Show a GHC syntax tree. This parameterised because it is also used for+-- comparing ASTs in ppr roundtripping tests, where the SrcSpan's are blanked+-- out, to avoid comparing locations, only structure+showAstData :: Data a => BlankSrcSpan -> a -> String+showAstData b = showAstData' 0+ where+ showAstData' :: Data a => Int -> a -> String+ showAstData' n =+ generic+ `ext1Q` list+ `extQ` string `extQ` fastString `extQ` srcSpan `extQ` lit+ `extQ` bytestring+ `extQ` name `extQ` occName `extQ` moduleName `extQ` var+ `extQ` dataCon+ `extQ` bagName `extQ` bagRdrName `extQ` bagVar `extQ` nameSet+ `extQ` fixity+ `ext2Q` located+ where generic :: Data a => a -> String+ generic t = indent n ++ "(" ++ showConstr (toConstr t)+ ++ space (unwords (gmapQ (showAstData' (n+1)) t)) ++ ")"++ space "" = ""+ space s = ' ':s++ indent i = "\n" ++ replicate i ' '++ string :: String -> String+ string = normalize_newlines . show++ fastString :: FastString -> String+ fastString = ("{FastString: "++) . (++"}") . normalize_newlines+ . show++ bytestring :: B.ByteString -> String+ bytestring = normalize_newlines . show++ list l = indent n ++ "["+ ++ intercalate "," (map (showAstData' (n+1)) l)+ ++ "]"++ -- Eliminate word-size dependence+ lit :: HsLit -> String+ lit (HsWordPrim s x) = numericLit "HsWord{64}Prim" x s+ lit (HsWord64Prim s x) = numericLit "HsWord{64}Prim" x s+ lit (HsIntPrim s x) = numericLit "HsInt{64}Prim" x s+ lit (HsInt64Prim s x) = numericLit "HsInt{64}Prim" x s+ lit l = generic l++ numericLit :: String -> Integer -> SourceText -> String+ numericLit tag x s = indent n ++ unwords [ "{" ++ tag+ , generic x+ , generic s ++ "}" ]++ name :: Name -> String+ name = ("{Name: "++) . (++"}") . showSDocDebug_ . ppr++ occName = ("{OccName: "++) . (++"}") . OccName.occNameString++ moduleName :: ModuleName -> String+ moduleName = ("{ModuleName: "++) . (++"}") . showSDoc_ . ppr++ srcSpan :: SrcSpan -> String+ srcSpan ss = case b of+ BlankSrcSpan -> "{ "++ "ss" ++"}"+ NoBlankSrcSpan ->+ "{ "++ showSDoc_ (hang (ppr ss) (n+2)+ -- TODO: show annotations here+ (text "")+ )+ ++"}"++ var :: Var -> String+ var = ("{Var: "++) . (++"}") . showSDocDebug_ . ppr++ dataCon :: DataCon -> String+ dataCon = ("{DataCon: "++) . (++"}") . showSDoc_ . ppr++ bagRdrName:: Bag (Located (HsBind RdrName)) -> String+ bagRdrName = ("{Bag(Located (HsBind RdrName)): "++) . (++"}")+ . list . bagToList++ bagName :: Bag (Located (HsBind Name)) -> String+ bagName = ("{Bag(Located (HsBind Name)): "++) . (++"}")+ . list . bagToList++ bagVar :: Bag (Located (HsBind Var)) -> String+ bagVar = ("{Bag(Located (HsBind Var)): "++) . (++"}")+ . list . bagToList++ nameSet = ("{NameSet: "++) . (++"}") . list . nameSetElemsStable++ fixity :: Fixity -> String+ fixity = ("{Fixity: "++) . (++"}") . showSDoc_ . ppr++ located :: (Data b,Data loc) => GenLocated loc b -> String+ located (L ss a) =+ indent n ++ "("+ ++ case cast ss of+ Just (s :: SrcSpan) ->+ srcSpan s+ Nothing -> "nnnnnnnn"+ ++ showAstData' (n+1) a+ ++ ")"++normalize_newlines :: String -> String+normalize_newlines ('\\':'r':'\\':'n':xs) = '\\':'n':normalize_newlines xs+normalize_newlines (x:xs) = x:normalize_newlines xs+normalize_newlines [] = []++showSDoc_ :: SDoc -> String+showSDoc_ = normalize_newlines . showSDoc unsafeGlobalDynFlags++showSDocDebug_ :: SDoc -> String+showSDocDebug_ = normalize_newlines . showSDocDebug unsafeGlobalDynFlags++{-+************************************************************************+* *+* Copied from syb+* *+************************************************************************+-}+++-- | The type constructor for queries+newtype Q q x = Q { unQ :: x -> q }++-- | Extend a generic query by a type-specific case+extQ :: ( Typeable a+ , Typeable b+ )+ => (a -> q)+ -> (b -> q)+ -> a+ -> q+extQ f g a = maybe (f a) g (cast a)++-- | Type extension of queries for type constructors+ext1Q :: (Data d, Typeable t)+ => (d -> q)+ -> (forall e. Data e => t e -> q)+ -> d -> q+ext1Q def ext = unQ ((Q def) `ext1` (Q ext))+++-- | Type extension of queries for type constructors+ext2Q :: (Data d, Typeable t)+ => (d -> q)+ -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)+ -> d -> q+ext2Q def ext = unQ ((Q def) `ext2` (Q ext))++-- | Flexible type extension+ext1 :: (Data a, Typeable t)+ => c a+ -> (forall d. Data d => c (t d))+ -> c a+ext1 def ext = maybe def id (dataCast1 ext)++++-- | Flexible type extension+ext2 :: (Data a, Typeable t)+ => c a+ -> (forall d1 d2. (Data d1, Data d2) => c (t d1 d2))+ -> c a+ext2 def ext = maybe def id (dataCast2 ext)
+ hsSyn/HsExpr.hs view
@@ -0,0 +1,2556 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP, DeriveDataTypeable, ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE DeriveFunctor #-}++-- | Abstract Haskell syntax for expressions.+module HsExpr where++#include "HsVersions.h"++-- friends:+import HsDecls+import HsPat+import HsLit+import PlaceHolder ( PostTc,PostRn,DataId,DataIdPost,+ NameOrRdrName,OutputableBndrId )+import HsTypes+import HsBinds++-- others:+import TcEvidence+import CoreSyn+import Var+import DynFlags ( gopt, GeneralFlag(Opt_PrintExplicitCoercions) )+import Name+import NameSet+import RdrName ( GlobalRdrEnv )+import BasicTypes+import ConLike+import SrcLoc+import Util+import Outputable+import FastString+import Type++-- libraries:+import Data.Data hiding (Fixity(..))+import qualified Data.Data as Data (Fixity(..))+import Data.Maybe (isNothing)++import GHCi.RemoteTypes ( ForeignRef )+import qualified Language.Haskell.TH as TH (Q)++{-+************************************************************************+* *+\subsection{Expressions proper}+* *+************************************************************************+-}++-- * Expressions proper++-- | Located Haskell Expression+type LHsExpr id = Located (HsExpr id)+ -- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnComma' when+ -- in a list++ -- For details on above see note [Api annotations] in ApiAnnotation++-------------------------+-- | Post-Type checking Expression+--+-- PostTcExpr is an evidence expression attached to the syntax tree by the+-- type checker (c.f. postTcType).+type PostTcExpr = HsExpr Id++-- | Post-Type checking Table+--+-- We use a PostTcTable where there are a bunch of pieces of evidence, more+-- than is convenient to keep individually.+type PostTcTable = [(Name, PostTcExpr)]++noPostTcExpr :: PostTcExpr+noPostTcExpr = HsLit (HsString NoSourceText (fsLit "noPostTcExpr"))++noPostTcTable :: PostTcTable+noPostTcTable = []++-------------------------+-- | Syntax Expression+--+-- SyntaxExpr is like 'PostTcExpr', but it's filled in a little earlier,+-- by the renamer. It's used for rebindable syntax.+--+-- E.g. @(>>=)@ is filled in before the renamer by the appropriate 'Name' for+-- @(>>=)@, and then instantiated by the type checker with its type args+-- etc+--+-- This should desugar to+--+-- > syn_res_wrap $ syn_expr (syn_arg_wraps[0] arg0)+-- > (syn_arg_wraps[1] arg1) ...+--+-- where the actual arguments come from elsewhere in the AST.+-- This could be defined using @PostRn@ and @PostTc@ and such, but it's+-- harder to get it all to work out that way. ('noSyntaxExpr' is hard to+-- write, for example.)+data SyntaxExpr id = SyntaxExpr { syn_expr :: HsExpr id+ , syn_arg_wraps :: [HsWrapper]+ , syn_res_wrap :: HsWrapper }+deriving instance (DataId id) => Data (SyntaxExpr id)++-- | This is used for rebindable-syntax pieces that are too polymorphic+-- for tcSyntaxOp (trS_fmap and the mzip in ParStmt)+noExpr :: HsExpr id+noExpr = HsLit (HsString (SourceText "noExpr") (fsLit "noExpr"))++noSyntaxExpr :: SyntaxExpr id -- Before renaming, and sometimes after,+ -- (if the syntax slot makes no sense)+noSyntaxExpr = SyntaxExpr { syn_expr = HsLit (HsString NoSourceText+ (fsLit "noSyntaxExpr"))+ , syn_arg_wraps = []+ , syn_res_wrap = WpHole }++-- | Make a 'SyntaxExpr Name' (the "rn" is because this is used in the+-- renamer), missing its HsWrappers.+mkRnSyntaxExpr :: Name -> SyntaxExpr Name+mkRnSyntaxExpr name = SyntaxExpr { syn_expr = HsVar $ noLoc name+ , syn_arg_wraps = []+ , syn_res_wrap = WpHole }+ -- don't care about filling in syn_arg_wraps because we're clearly+ -- not past the typechecker++instance (OutputableBndrId id) => Outputable (SyntaxExpr id) where+ ppr (SyntaxExpr { syn_expr = expr+ , syn_arg_wraps = arg_wraps+ , syn_res_wrap = res_wrap })+ = sdocWithDynFlags $ \ dflags ->+ getPprStyle $ \s ->+ if debugStyle s || gopt Opt_PrintExplicitCoercions dflags+ then ppr expr <> braces (pprWithCommas ppr arg_wraps)+ <> braces (ppr res_wrap)+ else ppr expr++-- | Command Syntax Table (for Arrow syntax)+type CmdSyntaxTable id = [(Name, HsExpr id)]+-- See Note [CmdSyntaxTable]++{-+Note [CmdSyntaxtable]+~~~~~~~~~~~~~~~~~~~~~+Used only for arrow-syntax stuff (HsCmdTop), the CmdSyntaxTable keeps+track of the methods needed for a Cmd.++* Before the renamer, this list is an empty list++* After the renamer, it takes the form @[(std_name, HsVar actual_name)]@+ For example, for the 'arr' method+ * normal case: (GHC.Control.Arrow.arr, HsVar GHC.Control.Arrow.arr)+ * with rebindable syntax: (GHC.Control.Arrow.arr, arr_22)+ where @arr_22@ is whatever 'arr' is in scope++* After the type checker, it takes the form [(std_name, <expression>)]+ where <expression> is the evidence for the method. This evidence is+ instantiated with the class, but is still polymorphic in everything+ else. For example, in the case of 'arr', the evidence has type+ forall b c. (b->c) -> a b c+ where 'a' is the ambient type of the arrow. This polymorphism is+ important because the desugarer uses the same evidence at multiple+ different types.++This is Less Cool than what we normally do for rebindable syntax, which is to+make fully-instantiated piece of evidence at every use site. The Cmd way+is Less Cool because+ * The renamer has to predict which methods are needed.+ See the tedious RnExpr.methodNamesCmd.++ * The desugarer has to know the polymorphic type of the instantiated+ method. This is checked by Inst.tcSyntaxName, but is less flexible+ than the rest of rebindable syntax, where the type is less+ pre-ordained. (And this flexibility is useful; for example we can+ typecheck do-notation with (>>=) :: m1 a -> (a -> m2 b) -> m2 b.)+-}++-- | An unbound variable; used for treating out-of-scope variables as+-- expression holes+data UnboundVar+ = OutOfScope OccName GlobalRdrEnv -- ^ An (unqualified) out-of-scope+ -- variable, together with the GlobalRdrEnv+ -- with respect to which it is unbound++ -- See Note [OutOfScope and GlobalRdrEnv]++ | TrueExprHole OccName -- ^ A "true" expression hole (_ or _x)++ deriving Data++instance Outputable UnboundVar where+ ppr = ppr . unboundVarOcc++unboundVarOcc :: UnboundVar -> OccName+unboundVarOcc (OutOfScope occ _) = occ+unboundVarOcc (TrueExprHole occ) = occ++{-+Note [OutOfScope and GlobalRdrEnv]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To understand why we bundle a GlobalRdrEnv with an out-of-scope variable,+consider the following module:++ module A where++ foo :: ()+ foo = bar++ bat :: [Double]+ bat = [1.2, 3.4]++ $(return [])++ bar = ()+ bad = False++When A is compiled, the renamer determines that `bar` is not in scope in the+declaration of `foo` (since `bar` is declared in the following inter-splice+group). Once it has finished typechecking the entire module, the typechecker+then generates the associated error message, which specifies both the type of+`bar` and a list of possible in-scope alternatives:++ A.hs:6:7: error:+ • Variable not in scope: bar :: ()+ • ‘bar’ (line 13) is not in scope before the splice on line 11+ Perhaps you meant ‘bat’ (line 9)++When it calls RnEnv.unknownNameSuggestions to identify these alternatives, the+typechecker must provide a GlobalRdrEnv. If it provided the current one, which+contains top-level declarations for the entire module, the error message would+incorrectly suggest the out-of-scope `bar` and `bad` as possible alternatives+for `bar` (see Trac #11680). Instead, the typechecker must use the same+GlobalRdrEnv the renamer used when it determined that `bar` is out-of-scope.++To obtain this GlobalRdrEnv, can the typechecker simply use the out-of-scope+`bar`'s location to either reconstruct it (from the current GlobalRdrEnv) or to+look it up in some global store? Unfortunately, no. The problem is that+location information is not always sufficient for this task. This is most+apparent when dealing with the TH function addTopDecls, which adds its+declarations to the FOLLOWING inter-splice group. Consider these declarations:++ ex9 = cat -- cat is NOT in scope here++ $(do -------------------------------------------------------------+ ds <- [d| f = cab -- cat and cap are both in scope here+ cat = ()+ |]+ addTopDecls ds+ [d| g = cab -- only cap is in scope here+ cap = True+ |])++ ex10 = cat -- cat is NOT in scope here++ $(return []) -----------------------------------------------------++ ex11 = cat -- cat is in scope++Here, both occurrences of `cab` are out-of-scope, and so the typechecker needs+the GlobalRdrEnvs which were used when they were renamed. These GlobalRdrEnvs+are different (`cat` is present only in the GlobalRdrEnv for f's `cab'), but the+locations of the two `cab`s are the same (they are both created in the same+splice). Thus, we must include some additional information with each `cab` to+allow the typechecker to obtain the correct GlobalRdrEnv. Clearly, the simplest+information to use is the GlobalRdrEnv itself.+-}++-- | A Haskell expression.+data HsExpr id+ = HsVar (Located id) -- ^ Variable++ -- See Note [Located RdrNames]++ | HsUnboundVar UnboundVar -- ^ Unbound variable; also used for "holes"+ -- (_ or _x).+ -- Turned from HsVar to HsUnboundVar by the+ -- renamer, when it finds an out-of-scope+ -- variable or hole.+ -- Turned into HsVar by type checker, to support+ -- deferred type errors.++ | HsConLikeOut ConLike -- ^ After typechecker only; must be different+ -- HsVar for pretty printing++ | HsRecFld (AmbiguousFieldOcc id) -- ^ Variable pointing to record selector+ -- Not in use after typechecking++ | HsOverLabel (Maybe id) FastString+ -- ^ Overloaded label (Note [Overloaded labels] in GHC.OverloadedLabels)+ -- @Just id@ means @RebindableSyntax@ is in use, and gives the id of the+ -- in-scope 'fromLabel'.+ -- NB: Not in use after typechecking++ | HsIPVar HsIPName -- ^ Implicit parameter (not in use after typechecking)+ | HsOverLit (HsOverLit id) -- ^ Overloaded literals++ | HsLit HsLit -- ^ Simple (non-overloaded) literals++ | HsLam (MatchGroup id (LHsExpr id)) -- ^ Lambda abstraction. Currently always a single match+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnLam',+ -- 'ApiAnnotation.AnnRarrow',++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsLamCase (MatchGroup id (LHsExpr id)) -- ^ Lambda-case+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnLam',+ -- 'ApiAnnotation.AnnCase','ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsApp (LHsExpr id) (LHsExpr id) -- ^ Application++ | HsAppType (LHsExpr id) (LHsWcType id) -- ^ Visible type application+ --+ -- Explicit type argument; e.g f @Int x y+ -- NB: Has wildcards, but no implicit quantification+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnAt',++ | HsAppTypeOut (LHsExpr id) (LHsWcType Name) -- just for pretty-printing+++ -- | Operator applications:+ -- NB Bracketed ops such as (+) come out as Vars.++ -- NB We need an expr for the operator in an OpApp/Section since+ -- the typechecker may need to apply the operator to a few types.++ | OpApp (LHsExpr id) -- left operand+ (LHsExpr id) -- operator+ (PostRn id Fixity) -- Renamer adds fixity; bottom until then+ (LHsExpr id) -- right operand++ -- | Negation operator. Contains the negated expression and the name+ -- of 'negate'+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnMinus'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | NegApp (LHsExpr id)+ (SyntaxExpr id)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'('@,+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsPar (LHsExpr id) -- ^ Parenthesised expr; see Note [Parens in HsSyn]++ | SectionL (LHsExpr id) -- operand; see Note [Sections in HsSyn]+ (LHsExpr id) -- operator+ | SectionR (LHsExpr id) -- operator; see Note [Sections in HsSyn]+ (LHsExpr id) -- operand++ -- | Used for explicit tuples and sections thereof+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ExplicitTuple+ [LHsTupArg id]+ Boxity++ -- | Used for unboxed sum types+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'(#'@,+ -- 'ApiAnnotation.AnnVbar', 'ApiAnnotation.AnnClose' @'#)'@,+ --+ -- There will be multiple 'ApiAnnotation.AnnVbar', (1 - alternative) before+ -- the expression, (arity - alternative) after it+ | ExplicitSum+ ConTag -- Alternative (one-based)+ Arity -- Sum arity+ (LHsExpr id)+ (PostTc id [Type]) -- the type arguments++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnCase',+ -- 'ApiAnnotation.AnnOf','ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnClose' @'}'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsCase (LHsExpr id)+ (MatchGroup id (LHsExpr id))++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnIf',+ -- 'ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnThen','ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnElse',++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsIf (Maybe (SyntaxExpr id)) -- cond function+ -- Nothing => use the built-in 'if'+ -- See Note [Rebindable if]+ (LHsExpr id) -- predicate+ (LHsExpr id) -- then part+ (LHsExpr id) -- else part++ -- | Multi-way if+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnIf'+ -- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose',++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsMultiIf (PostTc id Type) [LGRHS id (LHsExpr id)]++ -- | let(rec)+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnLet',+ -- 'ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnClose' @'}'@,'ApiAnnotation.AnnIn'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsLet (LHsLocalBinds id)+ (LHsExpr id)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDo',+ -- 'ApiAnnotation.AnnOpen', 'ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnVbar',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsDo (HsStmtContext Name) -- The parameterisation is unimportant+ -- because in this context we never use+ -- the PatGuard or ParStmt variant+ (Located [ExprLStmt id]) -- "do":one or more stmts+ (PostTc id Type) -- Type of the whole expression++ -- | Syntactic list: [a,b,c,...]+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'['@,+ -- 'ApiAnnotation.AnnClose' @']'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ExplicitList+ (PostTc id Type) -- Gives type of components of list+ (Maybe (SyntaxExpr id)) -- For OverloadedLists, the fromListN witness+ [LHsExpr id]++ -- | Syntactic parallel array: [:e1, ..., en:]+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'[:'@,+ -- 'ApiAnnotation.AnnDotdot','ApiAnnotation.AnnComma',+ -- 'ApiAnnotation.AnnVbar'+ -- 'ApiAnnotation.AnnClose' @':]'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ExplicitPArr+ (PostTc id Type) -- type of elements of the parallel array+ [LHsExpr id]++ -- | Record construction+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnDotdot','ApiAnnotation.AnnClose' @'}'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | RecordCon+ { rcon_con_name :: Located id -- The constructor name;+ -- not used after type checking+ , rcon_con_like :: PostTc id ConLike -- The data constructor or pattern synonym+ , rcon_con_expr :: PostTcExpr -- Instantiated constructor function+ , rcon_flds :: HsRecordBinds id } -- The fields++ -- | Record update+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnDotdot','ApiAnnotation.AnnClose' @'}'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | RecordUpd+ { rupd_expr :: LHsExpr id+ , rupd_flds :: [LHsRecUpdField id]+ , rupd_cons :: PostTc id [ConLike]+ -- Filled in by the type checker to the+ -- _non-empty_ list of DataCons that have+ -- all the upd'd fields++ , rupd_in_tys :: PostTc id [Type] -- Argument types of *input* record type+ , rupd_out_tys :: PostTc id [Type] -- and *output* record type+ -- The original type can be reconstructed+ -- with conLikeResTy+ , rupd_wrap :: PostTc id HsWrapper -- See note [Record Update HsWrapper]+ }+ -- For a type family, the arg types are of the *instance* tycon,+ -- not the family tycon++ -- | Expression with an explicit type signature. @e :: type@+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ExprWithTySig+ (LHsExpr id)+ (LHsSigWcType id)++ | ExprWithTySigOut -- Post typechecking+ (LHsExpr id)+ (LHsSigWcType Name) -- Retain the signature,+ -- as HsSigType Name, for+ -- round-tripping purposes++ -- | Arithmetic sequence+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'['@,+ -- 'ApiAnnotation.AnnComma','ApiAnnotation.AnnDotdot',+ -- 'ApiAnnotation.AnnClose' @']'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ArithSeq+ PostTcExpr+ (Maybe (SyntaxExpr id)) -- For OverloadedLists, the fromList witness+ (ArithSeqInfo id)++ -- | Arithmetic sequence for parallel array+ --+ -- > [:e1..e2:] or [:e1, e2..e3:]+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'[:'@,+ -- 'ApiAnnotation.AnnComma','ApiAnnotation.AnnDotdot',+ -- 'ApiAnnotation.AnnVbar',+ -- 'ApiAnnotation.AnnClose' @':]'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | PArrSeq+ PostTcExpr+ (ArithSeqInfo id)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'{-\# SCC'@,+ -- 'ApiAnnotation.AnnVal' or 'ApiAnnotation.AnnValStr',+ -- 'ApiAnnotation.AnnClose' @'\#-}'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsSCC SourceText -- Note [Pragma source text] in BasicTypes+ StringLiteral -- "set cost centre" SCC pragma+ (LHsExpr id) -- expr whose cost is to be measured++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'{-\# CORE'@,+ -- 'ApiAnnotation.AnnVal', 'ApiAnnotation.AnnClose' @'\#-}'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsCoreAnn SourceText -- Note [Pragma source text] in BasicTypes+ StringLiteral -- hdaume: core annotation+ (LHsExpr id)++ -----------------------------------------------------------+ -- MetaHaskell Extensions++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnOpenE','ApiAnnotation.AnnOpenEQ',+ -- 'ApiAnnotation.AnnClose','ApiAnnotation.AnnCloseQ'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsBracket (HsBracket id)++ -- See Note [Pending Splices]+ | HsRnBracketOut+ (HsBracket Name) -- Output of the renamer is the *original* renamed+ -- expression, plus+ [PendingRnSplice] -- _renamed_ splices to be type checked++ | HsTcBracketOut+ (HsBracket Name) -- Output of the type checker is the *original*+ -- renamed expression, plus+ [PendingTcSplice] -- _typechecked_ splices to be+ -- pasted back in by the desugarer++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsSpliceE (HsSplice id)++ -----------------------------------------------------------+ -- Arrow notation extension++ -- | @proc@ notation for Arrows+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnProc',+ -- 'ApiAnnotation.AnnRarrow'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsProc (LPat id) -- arrow abstraction, proc+ (LHsCmdTop id) -- body of the abstraction+ -- always has an empty stack++ ---------------------------------------+ -- static pointers extension+ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnStatic',++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsStatic (PostRn id NameSet) -- Free variables of the body+ (LHsExpr id) -- Body++ ---------------------------------------+ -- The following are commands, not expressions proper+ -- They are only used in the parsing stage and are removed+ -- immediately in parser.RdrHsSyn.checkCommand++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.Annlarrowtail',+ -- 'ApiAnnotation.Annrarrowtail','ApiAnnotation.AnnLarrowtail',+ -- 'ApiAnnotation.AnnRarrowtail'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsArrApp -- Arrow tail, or arrow application (f -< arg)+ (LHsExpr id) -- arrow expression, f+ (LHsExpr id) -- input expression, arg+ (PostTc id Type) -- type of the arrow expressions f,+ -- of the form a t t', where arg :: t+ HsArrAppType -- higher-order (-<<) or first-order (-<)+ Bool -- True => right-to-left (f -< arg)+ -- False => left-to-right (arg >- f)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpenB' @'(|'@,+ -- 'ApiAnnotation.AnnCloseB' @'|)'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsArrForm -- Command formation, (| e cmd1 .. cmdn |)+ (LHsExpr id) -- the operator+ -- after type-checking, a type abstraction to be+ -- applied to the type of the local environment tuple+ (Maybe Fixity) -- fixity (filled in by the renamer), for forms that+ -- were converted from OpApp's by the renamer+ [LHsCmdTop id] -- argument commands++ ---------------------------------------+ -- Haskell program coverage (Hpc) Support++ | HsTick+ (Tickish id)+ (LHsExpr id) -- sub-expression++ | HsBinTick+ Int -- module-local tick number for True+ Int -- module-local tick number for False+ (LHsExpr id) -- sub-expression++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnOpen' @'{-\# GENERATED'@,+ -- 'ApiAnnotation.AnnVal','ApiAnnotation.AnnVal',+ -- 'ApiAnnotation.AnnColon','ApiAnnotation.AnnVal',+ -- 'ApiAnnotation.AnnMinus',+ -- 'ApiAnnotation.AnnVal','ApiAnnotation.AnnColon',+ -- 'ApiAnnotation.AnnVal',+ -- 'ApiAnnotation.AnnClose' @'\#-}'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsTickPragma -- A pragma introduced tick+ SourceText -- Note [Pragma source text] in BasicTypes+ (StringLiteral,(Int,Int),(Int,Int))+ -- external span for this tick+ ((SourceText,SourceText),(SourceText,SourceText))+ -- Source text for the four integers used in the span.+ -- See note [Pragma source text] in BasicTypes+ (LHsExpr id)++ ---------------------------------------+ -- These constructors only appear temporarily in the parser.+ -- The renamer translates them into the Right Thing.++ | EWildPat -- wildcard++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnAt'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | EAsPat (Located id) -- as pattern+ (LHsExpr id)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnRarrow'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | EViewPat (LHsExpr id) -- view pattern+ (LHsExpr id)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnTilde'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ELazyPat (LHsExpr id) -- ~ pattern+++ ---------------------------------------+ -- Finally, HsWrap appears only in typechecker output++ | HsWrap HsWrapper -- TRANSLATION+ (HsExpr id)++deriving instance (DataId id) => Data (HsExpr id)++-- | Located Haskell Tuple Argument+--+-- 'HsTupArg' is used for tuple sections+-- @(,a,)@ is represented by+-- @ExplicitTuple [Missing ty1, Present a, Missing ty3]@+-- Which in turn stands for @(\x:ty1 \y:ty2. (x,a,y))@+type LHsTupArg id = Located (HsTupArg id)+-- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnComma'++-- For details on above see note [Api annotations] in ApiAnnotation++-- | Haskell Tuple Argument+data HsTupArg id+ = Present (LHsExpr id) -- ^ The argument+ | Missing (PostTc id Type) -- ^ The argument is missing, but this is its type+deriving instance (DataId id) => Data (HsTupArg id)++tupArgPresent :: LHsTupArg id -> Bool+tupArgPresent (L _ (Present {})) = True+tupArgPresent (L _ (Missing {})) = False++{-+Note [Parens in HsSyn]+~~~~~~~~~~~~~~~~~~~~~~+HsPar (and ParPat in patterns, HsParTy in types) is used as follows++ * HsPar is required; the pretty printer does not add parens.++ * HsPars are respected when rearranging operator fixities.+ So a * (b + c) means what it says (where the parens are an HsPar)++ * For ParPat and HsParTy the pretty printer does add parens but this should be+ a no-op for ParsedSource, based on the pretty printer round trip feature+ introduced in+ https://phabricator.haskell.org/rGHC499e43824bda967546ebf95ee33ec1f84a114a7c++ * ParPat and HsParTy are pretty printed as '( .. )' regardless of whether or+ not they are strictly necssary. This should be addressed when #13238 is+ completed, to be treated the same as HsPar.+++Note [Sections in HsSyn]+~~~~~~~~~~~~~~~~~~~~~~~~+Sections should always appear wrapped in an HsPar, thus+ HsPar (SectionR ...)+The parser parses sections in a wider variety of situations+(See Note [Parsing sections]), but the renamer checks for those+parens. This invariant makes pretty-printing easier; we don't need+a special case for adding the parens round sections.++Note [Rebindable if]+~~~~~~~~~~~~~~~~~~~~+The rebindable syntax for 'if' is a bit special, because when+rebindable syntax is *off* we do not want to treat+ (if c then t else e)+as if it was an application (ifThenElse c t e). Why not?+Because we allow an 'if' to return *unboxed* results, thus+ if blah then 3# else 4#+whereas that would not be possible using a all to a polymorphic function+(because you can't call a polymorphic function at an unboxed type).++So we use Nothing to mean "use the old built-in typing rule".++Note [Record Update HsWrapper]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There is a wrapper in RecordUpd which is used for the *required*+constraints for pattern synonyms. This wrapper is created in the+typechecking and is then directly used in the desugaring without+modification.++For example, if we have the record pattern synonym P,+ pattern P :: (Show a) => a -> Maybe a+ pattern P{x} = Just x++ foo = (Just True) { x = False }+then `foo` desugars to something like+ foo = case Just True of+ P x -> P False+hence we need to provide the correct dictionaries to P's matcher on+the RHS so that we can build the expression.++Note [Located RdrNames]+~~~~~~~~~~~~~~~~~~~~~~~+A number of syntax elements have seemingly redundant locations attached to them.+This is deliberate, to allow transformations making use of the API Annotations+to easily correlate a Located Name in the RenamedSource with a Located RdrName+in the ParsedSource.++There are unfortunately enough differences between the ParsedSource and the+RenamedSource that the API Annotations cannot be used directly with+RenamedSource, so this allows a simple mapping to be used based on the location.+-}++instance (OutputableBndrId id) => Outputable (HsExpr id) where+ ppr expr = pprExpr expr++-----------------------+-- pprExpr, pprLExpr, pprBinds call pprDeeper;+-- the underscore versions do not+pprLExpr :: (OutputableBndrId id) => LHsExpr id -> SDoc+pprLExpr (L _ e) = pprExpr e++pprExpr :: (OutputableBndrId id) => HsExpr id -> SDoc+pprExpr e | isAtomicHsExpr e || isQuietHsExpr e = ppr_expr e+ | otherwise = pprDeeper (ppr_expr e)++isQuietHsExpr :: HsExpr id -> Bool+-- Parentheses do display something, but it gives little info and+-- if we go deeper when we go inside them then we get ugly things+-- like (...)+isQuietHsExpr (HsPar _) = True+-- applications don't display anything themselves+isQuietHsExpr (HsApp _ _) = True+isQuietHsExpr (HsAppType _ _) = True+isQuietHsExpr (HsAppTypeOut _ _) = True+isQuietHsExpr (OpApp _ _ _ _) = True+isQuietHsExpr _ = False++pprBinds :: (OutputableBndrId idL, OutputableBndrId idR)+ => HsLocalBindsLR idL idR -> SDoc+pprBinds b = pprDeeper (ppr b)++-----------------------+ppr_lexpr :: (OutputableBndrId id) => LHsExpr id -> SDoc+ppr_lexpr e = ppr_expr (unLoc e)++ppr_expr :: forall id. (OutputableBndrId id) => HsExpr id -> SDoc+ppr_expr (HsVar (L _ v)) = pprPrefixOcc v+ppr_expr (HsUnboundVar uv)= pprPrefixOcc (unboundVarOcc uv)+ppr_expr (HsConLikeOut c) = pprPrefixOcc c+ppr_expr (HsIPVar v) = ppr v+ppr_expr (HsOverLabel _ l)= char '#' <> ppr l+ppr_expr (HsLit lit) = ppr lit+ppr_expr (HsOverLit lit) = ppr lit+ppr_expr (HsPar e) = parens (ppr_lexpr e)++ppr_expr (HsCoreAnn stc (StringLiteral sta s) e)+ = vcat [pprWithSourceText stc (text "{-# CORE")+ <+> pprWithSourceText sta (doubleQuotes $ ftext s) <+> text "#-}"+ , ppr_lexpr e]++ppr_expr e@(HsApp {}) = ppr_apps e []+ppr_expr e@(HsAppType {}) = ppr_apps e []+ppr_expr e@(HsAppTypeOut {}) = ppr_apps e []++ppr_expr (OpApp e1 op _ e2)+ | Just pp_op <- should_print_infix (unLoc op)+ = pp_infixly pp_op+ | otherwise+ = pp_prefixly++ where+ should_print_infix (HsVar (L _ v)) = Just (pprInfixOcc v)+ should_print_infix (HsConLikeOut c)= Just (pprInfixOcc (conLikeName c))+ should_print_infix (HsRecFld f) = Just (pprInfixOcc f)+ should_print_infix (HsUnboundVar h@TrueExprHole{})+ = Just (pprInfixOcc (unboundVarOcc h))+ should_print_infix EWildPat = Just (text "`_`")+ should_print_infix (HsWrap _ e) = should_print_infix e+ should_print_infix _ = Nothing++ pp_e1 = pprDebugParendExpr e1 -- In debug mode, add parens+ pp_e2 = pprDebugParendExpr e2 -- to make precedence clear++ pp_prefixly+ = hang (ppr op) 2 (sep [pp_e1, pp_e2])++ pp_infixly pp_op+ = hang pp_e1 2 (sep [pp_op, nest 2 pp_e2])++ppr_expr (NegApp e _) = char '-' <+> pprDebugParendExpr e++ppr_expr (SectionL expr op)+ = case unLoc op of+ HsVar (L _ v) -> pp_infixly v+ HsConLikeOut c -> pp_infixly (conLikeName c)+ _ -> pp_prefixly+ where+ pp_expr = pprDebugParendExpr expr++ pp_prefixly = hang (hsep [text " \\ x_ ->", ppr op])+ 4 (hsep [pp_expr, text "x_ )"])+ pp_infixly v = (sep [pp_expr, pprInfixOcc v])++ppr_expr (SectionR op expr)+ = case unLoc op of+ HsVar (L _ v) -> pp_infixly v+ HsConLikeOut c -> pp_infixly (conLikeName c)+ _ -> pp_prefixly+ where+ pp_expr = pprDebugParendExpr expr++ pp_prefixly = hang (hsep [text "( \\ x_ ->", ppr op, text "x_"])+ 4 (pp_expr <> rparen)+ pp_infixly v = sep [pprInfixOcc v, pp_expr]++ppr_expr (ExplicitTuple exprs boxity)+ = tupleParens (boxityTupleSort boxity) (fcat (ppr_tup_args $ map unLoc exprs))+ where+ ppr_tup_args [] = []+ ppr_tup_args (Present e : es) = (ppr_lexpr e <> punc es) : ppr_tup_args es+ ppr_tup_args (Missing _ : es) = punc es : ppr_tup_args es++ punc (Present {} : _) = comma <> space+ punc (Missing {} : _) = comma+ punc [] = empty++ppr_expr (ExplicitSum alt arity expr _)+ = text "(#" <+> ppr_bars (alt - 1) <+> ppr expr <+> ppr_bars (arity - alt) <+> text "#)"+ where+ ppr_bars n = hsep (replicate n (char '|'))++ppr_expr (HsLam matches)+ = pprMatches matches++ppr_expr (HsLamCase matches)+ = sep [ sep [text "\\case"],+ nest 2 (pprMatches matches) ]++ppr_expr (HsCase expr matches@(MG { mg_alts = L _ [_] }))+ = sep [ sep [text "case", nest 4 (ppr expr), ptext (sLit "of {")],+ nest 2 (pprMatches matches) <+> char '}']+ppr_expr (HsCase expr matches)+ = sep [ sep [text "case", nest 4 (ppr expr), ptext (sLit "of")],+ nest 2 (pprMatches matches) ]++ppr_expr (HsIf _ e1 e2 e3)+ = sep [hsep [text "if", nest 2 (ppr e1), ptext (sLit "then")],+ nest 4 (ppr e2),+ text "else",+ nest 4 (ppr e3)]++ppr_expr (HsMultiIf _ alts)+ = hang (text "if") 3 (vcat (map ppr_alt alts))+ where ppr_alt (L _ (GRHS guards expr)) =+ hang vbar 2 (ppr_one one_alt)+ where+ ppr_one [] = panic "ppr_exp HsMultiIf"+ ppr_one (h:t) = hang h 2 (sep t)+ one_alt = [ interpp'SP guards+ , text "->" <+> pprDeeper (ppr expr) ]++-- special case: let ... in let ...+ppr_expr (HsLet (L _ binds) expr@(L _ (HsLet _ _)))+ = sep [hang (text "let") 2 (hsep [pprBinds binds, ptext (sLit "in")]),+ ppr_lexpr expr]++ppr_expr (HsLet (L _ binds) expr)+ = sep [hang (text "let") 2 (pprBinds binds),+ hang (text "in") 2 (ppr expr)]++ppr_expr (HsDo do_or_list_comp (L _ stmts) _) = pprDo do_or_list_comp stmts++ppr_expr (ExplicitList _ _ exprs)+ = brackets (pprDeeperList fsep (punctuate comma (map ppr_lexpr exprs)))++ppr_expr (ExplicitPArr _ exprs)+ = paBrackets (pprDeeperList fsep (punctuate comma (map ppr_lexpr exprs)))++ppr_expr (RecordCon { rcon_con_name = con_id, rcon_flds = rbinds })+ = hang (ppr con_id) 2 (ppr rbinds)++ppr_expr (RecordUpd { rupd_expr = L _ aexp, rupd_flds = rbinds })+ = hang (ppr aexp) 2 (braces (fsep (punctuate comma (map ppr rbinds))))++ppr_expr (ExprWithTySig expr sig)+ = hang (nest 2 (ppr_lexpr expr) <+> dcolon)+ 4 (ppr sig)+ppr_expr (ExprWithTySigOut expr sig)+ = hang (nest 2 (ppr_lexpr expr) <+> dcolon)+ 4 (ppr sig)++ppr_expr (ArithSeq _ _ info) = brackets (ppr info)+ppr_expr (PArrSeq _ info) = paBrackets (ppr info)++ppr_expr EWildPat = char '_'+ppr_expr (ELazyPat e) = char '~' <> ppr e+ppr_expr (EAsPat v e) = ppr v <> char '@' <> ppr e+ppr_expr (EViewPat p e) = ppr p <+> text "->" <+> ppr e++ppr_expr (HsSCC st (StringLiteral stl lbl) expr)+ = sep [ pprWithSourceText st (text "{-# SCC")+ -- no doublequotes if stl empty, for the case where the SCC was written+ -- without quotes.+ <+> pprWithSourceText stl (ftext lbl) <+> text "#-}",+ ppr expr ]++ppr_expr (HsWrap co_fn e)+ = pprHsWrapper co_fn (\parens -> if parens then pprExpr e+ else pprExpr e)++ppr_expr (HsSpliceE s) = pprSplice s+ppr_expr (HsBracket b) = pprHsBracket b+ppr_expr (HsRnBracketOut e []) = ppr e+ppr_expr (HsRnBracketOut e ps) = ppr e $$ text "pending(rn)" <+> ppr ps+ppr_expr (HsTcBracketOut e []) = ppr e+ppr_expr (HsTcBracketOut e ps) = ppr e $$ text "pending(tc)" <+> ppr ps++ppr_expr (HsProc pat (L _ (HsCmdTop cmd _ _ _)))+ = hsep [text "proc", ppr pat, ptext (sLit "->"), ppr cmd]++ppr_expr (HsStatic _ e)+ = hsep [text "static", ppr e]++ppr_expr (HsTick tickish exp)+ = pprTicks (ppr exp) $+ ppr tickish <+> ppr_lexpr exp+ppr_expr (HsBinTick tickIdTrue tickIdFalse exp)+ = pprTicks (ppr exp) $+ hcat [text "bintick<",+ ppr tickIdTrue,+ text ",",+ ppr tickIdFalse,+ text ">(",+ ppr exp, text ")"]+ppr_expr (HsTickPragma _ externalSrcLoc _ exp)+ = pprTicks (ppr exp) $+ hcat [text "tickpragma<",+ pprExternalSrcLoc externalSrcLoc,+ text ">(",+ ppr exp,+ text ")"]++ppr_expr (HsArrApp arrow arg _ HsFirstOrderApp True)+ = hsep [ppr_lexpr arrow, larrowt, ppr_lexpr arg]+ppr_expr (HsArrApp arrow arg _ HsFirstOrderApp False)+ = hsep [ppr_lexpr arg, arrowt, ppr_lexpr arrow]+ppr_expr (HsArrApp arrow arg _ HsHigherOrderApp True)+ = hsep [ppr_lexpr arrow, larrowtt, ppr_lexpr arg]+ppr_expr (HsArrApp arrow arg _ HsHigherOrderApp False)+ = hsep [ppr_lexpr arg, arrowtt, ppr_lexpr arrow]++ppr_expr (HsArrForm (L _ (HsVar (L _ v))) (Just _) [arg1, arg2])+ = sep [pprCmdArg (unLoc arg1), hsep [pprInfixOcc v, pprCmdArg (unLoc arg2)]]+ppr_expr (HsArrForm (L _ (HsConLikeOut c)) (Just _) [arg1, arg2])+ = sep [pprCmdArg (unLoc arg1), hsep [pprInfixOcc (conLikeName c), pprCmdArg (unLoc arg2)]]+ppr_expr (HsArrForm op _ args)+ = hang (text "(|" <+> ppr_lexpr op)+ 4 (sep (map (pprCmdArg.unLoc) args) <+> text "|)")+ppr_expr (HsRecFld f) = ppr f++-- We must tiresomely make the "id" parameter to the LHsWcType existential+-- because it's different in the HsAppType case and the HsAppTypeOut case+-- | Located Haskell Wildcard Type Expression+data LHsWcTypeX = forall id. (OutputableBndrId id) => LHsWcTypeX (LHsWcType id)++ppr_apps :: (OutputableBndrId id) => HsExpr id+ -> [Either (LHsExpr id) LHsWcTypeX]+ -> SDoc+ppr_apps (HsApp (L _ fun) arg) args+ = ppr_apps fun (Left arg : args)+ppr_apps (HsAppType (L _ fun) arg) args+ = ppr_apps fun (Right (LHsWcTypeX arg) : args)+ppr_apps (HsAppTypeOut (L _ fun) arg) args+ = ppr_apps fun (Right (LHsWcTypeX arg) : args)+ppr_apps fun args = hang (ppr_expr fun) 2 (sep (map pp args))+ where+ pp (Left arg) = ppr arg+ pp (Right (LHsWcTypeX (HsWC { hswc_body = L _ arg })))+ = char '@' <> pprParendHsType arg++pprExternalSrcLoc :: (StringLiteral,(Int,Int),(Int,Int)) -> SDoc+pprExternalSrcLoc (StringLiteral _ src,(n1,n2),(n3,n4))+ = ppr (src,(n1,n2),(n3,n4))++{-+HsSyn records exactly where the user put parens, with HsPar.+So generally speaking we print without adding any parens.+However, some code is internally generated, and in some places+parens are absolutely required; so for these places we use+pprParendLExpr (but don't print double parens of course).++For operator applications we don't add parens, because the operator+fixities should do the job, except in debug mode (-dppr-debug) so we+can see the structure of the parse tree.+-}++pprDebugParendExpr :: (OutputableBndrId id) => LHsExpr id -> SDoc+pprDebugParendExpr expr+ = getPprStyle (\sty ->+ if debugStyle sty then pprParendLExpr expr+ else pprLExpr expr)++pprParendLExpr :: (OutputableBndrId id) => LHsExpr id -> SDoc+pprParendLExpr (L _ e) = pprParendExpr e++pprParendExpr :: (OutputableBndrId id) => HsExpr id -> SDoc+pprParendExpr expr+ | hsExprNeedsParens expr = parens (pprExpr expr)+ | otherwise = pprExpr expr+ -- Using pprLExpr makes sure that we go 'deeper'+ -- I think that is usually (always?) right++hsExprNeedsParens :: HsExpr id -> Bool+-- True of expressions for which '(e)' and 'e'+-- mean the same thing+hsExprNeedsParens (ArithSeq {}) = False+hsExprNeedsParens (PArrSeq {}) = False+hsExprNeedsParens (HsLit {}) = False+hsExprNeedsParens (HsOverLit {}) = False+hsExprNeedsParens (HsVar {}) = False+hsExprNeedsParens (HsUnboundVar {}) = False+hsExprNeedsParens (HsConLikeOut {}) = False+hsExprNeedsParens (HsIPVar {}) = False+hsExprNeedsParens (HsOverLabel {}) = False+hsExprNeedsParens (ExplicitTuple {}) = False+hsExprNeedsParens (ExplicitList {}) = False+hsExprNeedsParens (ExplicitPArr {}) = False+hsExprNeedsParens (HsPar {}) = False+hsExprNeedsParens (HsBracket {}) = False+hsExprNeedsParens (HsRnBracketOut {}) = False+hsExprNeedsParens (HsTcBracketOut {}) = False+hsExprNeedsParens (HsDo sc _ _)+ | isListCompExpr sc = False+hsExprNeedsParens (HsRecFld{}) = False+hsExprNeedsParens (RecordCon{}) = False+hsExprNeedsParens (HsSpliceE{}) = False+hsExprNeedsParens (RecordUpd{}) = False+hsExprNeedsParens (HsWrap _ e) = hsExprNeedsParens e+hsExprNeedsParens _ = True+++isAtomicHsExpr :: HsExpr id -> Bool+-- True of a single token+isAtomicHsExpr (HsVar {}) = True+isAtomicHsExpr (HsConLikeOut {}) = True+isAtomicHsExpr (HsLit {}) = True+isAtomicHsExpr (HsOverLit {}) = True+isAtomicHsExpr (HsIPVar {}) = True+isAtomicHsExpr (HsOverLabel {}) = True+isAtomicHsExpr (HsUnboundVar {}) = True+isAtomicHsExpr (HsWrap _ e) = isAtomicHsExpr e+isAtomicHsExpr (HsPar e) = isAtomicHsExpr (unLoc e)+isAtomicHsExpr (HsRecFld{}) = True+isAtomicHsExpr _ = False++{-+************************************************************************+* *+\subsection{Commands (in arrow abstractions)}+* *+************************************************************************++We re-use HsExpr to represent these.+-}++-- | Located Haskell Command (for arrow syntax)+type LHsCmd id = Located (HsCmd id)++-- | Haskell Command (e.g. a "statement" in an Arrow proc block)+data HsCmd id+ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.Annlarrowtail',+ -- 'ApiAnnotation.Annrarrowtail','ApiAnnotation.AnnLarrowtail',+ -- 'ApiAnnotation.AnnRarrowtail'++ -- For details on above see note [Api annotations] in ApiAnnotation+ = HsCmdArrApp -- Arrow tail, or arrow application (f -< arg)+ (LHsExpr id) -- arrow expression, f+ (LHsExpr id) -- input expression, arg+ (PostTc id Type) -- type of the arrow expressions f,+ -- of the form a t t', where arg :: t+ HsArrAppType -- higher-order (-<<) or first-order (-<)+ Bool -- True => right-to-left (f -< arg)+ -- False => left-to-right (arg >- f)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpenB' @'(|'@,+ -- 'ApiAnnotation.AnnCloseB' @'|)'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | HsCmdArrForm -- Command formation, (| e cmd1 .. cmdn |)+ (LHsExpr id) -- The operator.+ -- After type-checking, a type abstraction to be+ -- applied to the type of the local environment tuple+ LexicalFixity -- Whether the operator appeared prefix or infix when+ -- parsed.+ (Maybe Fixity) -- fixity (filled in by the renamer), for forms that+ -- were converted from OpApp's by the renamer+ [LHsCmdTop id] -- argument commands++ | HsCmdApp (LHsCmd id)+ (LHsExpr id)++ | HsCmdLam (MatchGroup id (LHsCmd id)) -- kappa+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnLam',+ -- 'ApiAnnotation.AnnRarrow',++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCmdPar (LHsCmd id) -- parenthesised command+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'('@,+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCmdCase (LHsExpr id)+ (MatchGroup id (LHsCmd id)) -- bodies are HsCmd's+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnCase',+ -- 'ApiAnnotation.AnnOf','ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnClose' @'}'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCmdIf (Maybe (SyntaxExpr id)) -- cond function+ (LHsExpr id) -- predicate+ (LHsCmd id) -- then part+ (LHsCmd id) -- else part+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnIf',+ -- 'ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnThen','ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnElse',++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCmdLet (LHsLocalBinds id) -- let(rec)+ (LHsCmd id)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnLet',+ -- 'ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnClose' @'}'@,'ApiAnnotation.AnnIn'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCmdDo (Located [CmdLStmt id])+ (PostTc id Type) -- Type of the whole expression+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDo',+ -- 'ApiAnnotation.AnnOpen', 'ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnVbar',+ -- 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCmdWrap HsWrapper+ (HsCmd id) -- If cmd :: arg1 --> res+ -- wrap :: arg1 "->" arg2+ -- Then (HsCmdWrap wrap cmd) :: arg2 --> res+deriving instance (DataId id) => Data (HsCmd id)++-- | Haskell Array Application Type+data HsArrAppType = HsHigherOrderApp | HsFirstOrderApp+ deriving Data+++{- | Top-level command, introducing a new arrow.+This may occur inside a proc (where the stack is empty) or as an+argument of a command-forming operator.+-}++-- | Located Haskell Top-level Command+type LHsCmdTop id = Located (HsCmdTop id)++-- | Haskell Top-level Command+data HsCmdTop id+ = HsCmdTop (LHsCmd id)+ (PostTc id Type) -- Nested tuple of inputs on the command's stack+ (PostTc id Type) -- return type of the command+ (CmdSyntaxTable id) -- See Note [CmdSyntaxTable]+deriving instance (DataId id) => Data (HsCmdTop id)++instance (OutputableBndrId id) => Outputable (HsCmd id) where+ ppr cmd = pprCmd cmd++-----------------------+-- pprCmd and pprLCmd call pprDeeper;+-- the underscore versions do not+pprLCmd :: (OutputableBndrId id) => LHsCmd id -> SDoc+pprLCmd (L _ c) = pprCmd c++pprCmd :: (OutputableBndrId id) => HsCmd id -> SDoc+pprCmd c | isQuietHsCmd c = ppr_cmd c+ | otherwise = pprDeeper (ppr_cmd c)++isQuietHsCmd :: HsCmd id -> Bool+-- Parentheses do display something, but it gives little info and+-- if we go deeper when we go inside them then we get ugly things+-- like (...)+isQuietHsCmd (HsCmdPar _) = True+-- applications don't display anything themselves+isQuietHsCmd (HsCmdApp _ _) = True+isQuietHsCmd _ = False++-----------------------+ppr_lcmd :: (OutputableBndrId id) => LHsCmd id -> SDoc+ppr_lcmd c = ppr_cmd (unLoc c)++ppr_cmd :: forall id. (OutputableBndrId id) => HsCmd id -> SDoc+ppr_cmd (HsCmdPar c) = parens (ppr_lcmd c)++ppr_cmd (HsCmdApp c e)+ = let (fun, args) = collect_args c [e] in+ hang (ppr_lcmd fun) 2 (sep (map ppr args))+ where+ collect_args (L _ (HsCmdApp fun arg)) args = collect_args fun (arg:args)+ collect_args fun args = (fun, args)++ppr_cmd (HsCmdLam matches)+ = pprMatches matches++ppr_cmd (HsCmdCase expr matches)+ = sep [ sep [text "case", nest 4 (ppr expr), ptext (sLit "of")],+ nest 2 (pprMatches matches) ]++ppr_cmd (HsCmdIf _ e ct ce)+ = sep [hsep [text "if", nest 2 (ppr e), ptext (sLit "then")],+ nest 4 (ppr ct),+ text "else",+ nest 4 (ppr ce)]++-- special case: let ... in let ...+ppr_cmd (HsCmdLet (L _ binds) cmd@(L _ (HsCmdLet _ _)))+ = sep [hang (text "let") 2 (hsep [pprBinds binds, ptext (sLit "in")]),+ ppr_lcmd cmd]++ppr_cmd (HsCmdLet (L _ binds) cmd)+ = sep [hang (text "let") 2 (pprBinds binds),+ hang (text "in") 2 (ppr cmd)]++ppr_cmd (HsCmdDo (L _ stmts) _) = pprDo ArrowExpr stmts++ppr_cmd (HsCmdWrap w cmd)+ = pprHsWrapper w (\_ -> parens (ppr_cmd cmd))+ppr_cmd (HsCmdArrApp arrow arg _ HsFirstOrderApp True)+ = hsep [ppr_lexpr arrow, larrowt, ppr_lexpr arg]+ppr_cmd (HsCmdArrApp arrow arg _ HsFirstOrderApp False)+ = hsep [ppr_lexpr arg, arrowt, ppr_lexpr arrow]+ppr_cmd (HsCmdArrApp arrow arg _ HsHigherOrderApp True)+ = hsep [ppr_lexpr arrow, larrowtt, ppr_lexpr arg]+ppr_cmd (HsCmdArrApp arrow arg _ HsHigherOrderApp False)+ = hsep [ppr_lexpr arg, arrowtt, ppr_lexpr arrow]++ppr_cmd (HsCmdArrForm (L _ (HsVar (L _ v))) _ (Just _) [arg1, arg2])+ = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc v+ , pprCmdArg (unLoc arg2)])+ppr_cmd (HsCmdArrForm (L _ (HsVar (L _ v))) Infix _ [arg1, arg2])+ = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc v+ , pprCmdArg (unLoc arg2)])+ppr_cmd (HsCmdArrForm (L _ (HsConLikeOut c)) _ (Just _) [arg1, arg2])+ = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc (conLikeName c)+ , pprCmdArg (unLoc arg2)])+ppr_cmd (HsCmdArrForm (L _ (HsConLikeOut c)) Infix _ [arg1, arg2])+ = hang (pprCmdArg (unLoc arg1)) 4 (sep [ pprInfixOcc (conLikeName c)+ , pprCmdArg (unLoc arg2)])+ppr_cmd (HsCmdArrForm op _ _ args)+ = hang (text "(|" <> ppr_lexpr op)+ 4 (sep (map (pprCmdArg.unLoc) args) <> text "|)")++pprCmdArg :: (OutputableBndrId id) => HsCmdTop id -> SDoc+pprCmdArg (HsCmdTop cmd _ _ _)+ = ppr_lcmd cmd++instance (OutputableBndrId id) => Outputable (HsCmdTop id) where+ ppr = pprCmdArg++{-+************************************************************************+* *+\subsection{Record binds}+* *+************************************************************************+-}++-- | Haskell Record Bindings+type HsRecordBinds id = HsRecFields id (LHsExpr id)++{-+************************************************************************+* *+\subsection{@Match@, @GRHSs@, and @GRHS@ datatypes}+* *+************************************************************************++@Match@es are sets of pattern bindings and right hand sides for+functions, patterns or case branches. For example, if a function @g@+is defined as:+\begin{verbatim}+g (x,y) = y+g ((x:ys),y) = y+1,+\end{verbatim}+then \tr{g} has two @Match@es: @(x,y) = y@ and @((x:ys),y) = y+1@.++It is always the case that each element of an @[Match]@ list has the+same number of @pats@s inside it. This corresponds to saying that+a function defined by pattern matching must have the same number of+patterns in each equation.+-}++data MatchGroup id body+ = MG { mg_alts :: Located [LMatch id body] -- The alternatives+ , mg_arg_tys :: [PostTc id Type] -- Types of the arguments, t1..tn+ , mg_res_ty :: PostTc id Type -- Type of the result, tr+ , mg_origin :: Origin }+ -- The type is the type of the entire group+ -- t1 -> ... -> tn -> tr+ -- where there are n patterns+deriving instance (Data body,DataId id) => Data (MatchGroup id body)++-- | Located Match+type LMatch id body = Located (Match id body)+-- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSemi' when in a+-- list++-- For details on above see note [Api annotations] in ApiAnnotation+data Match id body+ = Match {+ m_ctxt :: HsMatchContext (NameOrRdrName id),+ -- See note [m_ctxt in Match]+ m_pats :: [LPat id], -- The patterns+ m_type :: (Maybe (LHsType id)),+ -- A type signature for the result of the match+ -- Nothing after typechecking+ -- NB: No longer supported+ m_grhss :: (GRHSs id body)+ }+deriving instance (Data body,DataId id) => Data (Match id body)++instance (OutputableBndrId idR, Outputable body)+ => Outputable (Match idR body) where+ ppr = pprMatch++{-+Note [m_ctxt in Match]+~~~~~~~~~~~~~~~~~~~~~~++A Match can occur in a number of contexts, such as a FunBind, HsCase, HsLam and+so on.++In order to simplify tooling processing and pretty print output, the provenance+is captured in an HsMatchContext.++This is particularly important for the API Annotations for a multi-equation+FunBind.++The parser initially creates a FunBind with a single Match in it for+every function definition it sees.++These are then grouped together by getMonoBind into a single FunBind,+where all the Matches are combined.++In the process, all the original FunBind fun_id's bar one are+discarded, including the locations.++This causes a problem for source to source conversions via API+Annotations, so the original fun_ids and infix flags are preserved in+the Match, when it originates from a FunBind.++Example infix function definition requiring individual API Annotations++ (&&& ) [] [] = []+ xs &&& [] = xs+ ( &&& ) [] ys = ys++++-}+++isInfixMatch :: Match id body -> Bool+isInfixMatch match = case m_ctxt match of+ FunRhs {mc_fixity = Infix} -> True+ _ -> False++isEmptyMatchGroup :: MatchGroup id body -> Bool+isEmptyMatchGroup (MG { mg_alts = ms }) = null $ unLoc ms++-- | Is there only one RHS in this list of matches?+isSingletonMatchGroup :: [LMatch id body] -> Bool+isSingletonMatchGroup matches+ | [L _ match] <- matches+ , Match { m_grhss = GRHSs { grhssGRHSs = [_] } } <- match+ = True+ | otherwise+ = False++matchGroupArity :: MatchGroup id body -> Arity+-- Precondition: MatchGroup is non-empty+-- This is called before type checking, when mg_arg_tys is not set+matchGroupArity (MG { mg_alts = alts })+ | L _ (alt1:_) <- alts = length (hsLMatchPats alt1)+ | otherwise = panic "matchGroupArity"++hsLMatchPats :: LMatch id body -> [LPat id]+hsLMatchPats (L _ (Match _ pats _ _)) = pats++-- | Guarded Right-Hand Sides+--+-- GRHSs are used both for pattern bindings and for Matches+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnVbar',+-- 'ApiAnnotation.AnnEqual','ApiAnnotation.AnnWhere',+-- 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnClose'+-- 'ApiAnnotation.AnnRarrow','ApiAnnotation.AnnSemi'++-- For details on above see note [Api annotations] in ApiAnnotation+data GRHSs id body+ = GRHSs {+ grhssGRHSs :: [LGRHS id body], -- ^ Guarded RHSs+ grhssLocalBinds :: LHsLocalBinds id -- ^ The where clause+ }+deriving instance (Data body,DataId id) => Data (GRHSs id body)++-- | Located Guarded Right-Hand Side+type LGRHS id body = Located (GRHS id body)++-- | Guarded Right Hand Side.+data GRHS id body = GRHS [GuardLStmt id] -- Guards+ body -- Right hand side+deriving instance (Data body,DataId id) => Data (GRHS id body)++-- We know the list must have at least one @Match@ in it.++pprMatches :: (OutputableBndrId idR, Outputable body)+ => MatchGroup idR body -> SDoc+pprMatches MG { mg_alts = matches }+ = vcat (map pprMatch (map unLoc (unLoc matches)))+ -- Don't print the type; it's only a place-holder before typechecking++-- Exported to HsBinds, which can't see the defn of HsMatchContext+pprFunBind :: (OutputableBndrId idR, Outputable body)+ => MatchGroup idR body -> SDoc+pprFunBind matches = pprMatches matches++-- Exported to HsBinds, which can't see the defn of HsMatchContext+pprPatBind :: forall bndr id body. (OutputableBndrId bndr,+ OutputableBndrId id,+ Outputable body)+ => LPat bndr -> GRHSs id body -> SDoc+pprPatBind pat (grhss)+ = sep [ppr pat, nest 2 (pprGRHSs (PatBindRhs :: HsMatchContext id) grhss)]++pprMatch :: (OutputableBndrId idR, Outputable body) => Match idR body -> SDoc+pprMatch match+ = sep [ sep (herald : map (nest 2 . pprParendLPat) other_pats)+ , nest 2 ppr_maybe_ty+ , nest 2 (pprGRHSs ctxt (m_grhss match)) ]+ where+ ctxt = m_ctxt match+ (herald, other_pats)+ = case ctxt of+ FunRhs {mc_fun=L _ fun, mc_fixity=fixity, mc_strictness=strictness}+ | strictness == SrcStrict -> ASSERT(null $ m_pats match)+ (char '!'<>pprPrefixOcc fun, m_pats match)+ -- a strict variable binding+ | fixity == Prefix -> (pprPrefixOcc fun, m_pats match)+ -- f x y z = e+ -- Not pprBndr; the AbsBinds will+ -- have printed the signature++ | null pats2 -> (pp_infix, [])+ -- x &&& y = e++ | otherwise -> (parens pp_infix, pats2)+ -- (x &&& y) z = e+ where+ pp_infix = pprParendLPat pat1 <+> pprInfixOcc fun <+> pprParendLPat pat2++ LambdaExpr -> (char '\\', m_pats match)++ _ -> ASSERT2( null pats1, ppr ctxt $$ ppr pat1 $$ ppr pats1 )+ (ppr pat1, []) -- No parens around the single pat++ (pat1:pats1) = m_pats match+ (pat2:pats2) = pats1+ ppr_maybe_ty = case m_type match of+ Just ty -> dcolon <+> ppr ty+ Nothing -> empty+++pprGRHSs :: (OutputableBndrId idR, Outputable body)+ => HsMatchContext idL -> GRHSs idR body -> SDoc+pprGRHSs ctxt (GRHSs grhss (L _ binds))+ = vcat (map (pprGRHS ctxt . unLoc) grhss)+ -- Print the "where" even if the contents of the binds is empty. Only+ -- EmptyLocalBinds means no "where" keyword+ $$ ppUnless (eqEmptyLocalBinds binds)+ (text "where" $$ nest 4 (pprBinds binds))++pprGRHS :: (OutputableBndrId idR, Outputable body)+ => HsMatchContext idL -> GRHS idR body -> SDoc+pprGRHS ctxt (GRHS [] body)+ = pp_rhs ctxt body++pprGRHS ctxt (GRHS guards body)+ = sep [vbar <+> interpp'SP guards, pp_rhs ctxt body]++pp_rhs :: Outputable body => HsMatchContext idL -> body -> SDoc+pp_rhs ctxt rhs = matchSeparator ctxt <+> pprDeeper (ppr rhs)++{-+************************************************************************+* *+\subsection{Do stmts and list comprehensions}+* *+************************************************************************+-}++-- | Located @do@ block Statement+type LStmt id body = Located (StmtLR id id body)++-- | Located Statement with separate Left and Right id's+type LStmtLR idL idR body = Located (StmtLR idL idR body)++-- | @do@ block Statement+type Stmt id body = StmtLR id id body++-- | Command Located Statement+type CmdLStmt id = LStmt id (LHsCmd id)++-- | Command Statement+type CmdStmt id = Stmt id (LHsCmd id)++-- | Expression Located Statement+type ExprLStmt id = LStmt id (LHsExpr id)++-- | Expression Statement+type ExprStmt id = Stmt id (LHsExpr id)++-- | Guard Located Statement+type GuardLStmt id = LStmt id (LHsExpr id)++-- | Guard Statement+type GuardStmt id = Stmt id (LHsExpr id)++-- | Ghci Located Statemnt+type GhciLStmt id = LStmt id (LHsExpr id)++-- | Ghci Statement+type GhciStmt id = Stmt id (LHsExpr id)++-- The SyntaxExprs in here are used *only* for do-notation and monad+-- comprehensions, which have rebindable syntax. Otherwise they are unused.+-- | API Annotations when in qualifier lists or guards+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnVbar',+-- 'ApiAnnotation.AnnComma','ApiAnnotation.AnnThen',+-- 'ApiAnnotation.AnnBy','ApiAnnotation.AnnBy',+-- 'ApiAnnotation.AnnGroup','ApiAnnotation.AnnUsing'++-- For details on above see note [Api annotations] in ApiAnnotation+data StmtLR idL idR body -- body should always be (LHs**** idR)+ = LastStmt -- Always the last Stmt in ListComp, MonadComp, PArrComp,+ -- and (after the renamer) DoExpr, MDoExpr+ -- Not used for GhciStmtCtxt, PatGuard, which scope over other stuff+ body+ Bool -- True <=> return was stripped by ApplicativeDo+ (SyntaxExpr idR) -- The return operator, used only for+ -- MonadComp For ListComp, PArrComp, we+ -- use the baked-in 'return' For DoExpr,+ -- MDoExpr, we don't apply a 'return' at+ -- all See Note [Monad Comprehensions] |+ -- - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnLarrow'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | BindStmt (LPat idL)+ body+ (SyntaxExpr idR) -- The (>>=) operator; see Note [The type of bind in Stmts]+ (SyntaxExpr idR) -- The fail operator+ -- The fail operator is noSyntaxExpr+ -- if the pattern match can't fail++ (PostTc idR Type) -- result type of the function passed to bind;+ -- that is, S in (>>=) :: Q -> (R -> S) -> T++ -- | 'ApplicativeStmt' represents an applicative expression built with+ -- <$> and <*>. It is generated by the renamer, and is desugared into the+ -- appropriate applicative expression by the desugarer, but it is intended+ -- to be invisible in error messages.+ --+ -- For full details, see Note [ApplicativeDo] in RnExpr+ --+ | ApplicativeStmt+ [ ( SyntaxExpr idR+ , ApplicativeArg idL idR) ]+ -- [(<$>, e1), (<*>, e2), ..., (<*>, en)]+ (Maybe (SyntaxExpr idR)) -- 'join', if necessary+ (PostTc idR Type) -- Type of the body++ | BodyStmt body -- See Note [BodyStmt]+ (SyntaxExpr idR) -- The (>>) operator+ (SyntaxExpr idR) -- The `guard` operator; used only in MonadComp+ -- See notes [Monad Comprehensions]+ (PostTc idR Type) -- Element type of the RHS (used for arrows)++ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnLet'+ -- 'ApiAnnotation.AnnOpen' @'{'@,'ApiAnnotation.AnnClose' @'}'@,++ -- For details on above see note [Api annotations] in ApiAnnotation+ | LetStmt (LHsLocalBindsLR idL idR)++ -- ParStmts only occur in a list/monad comprehension+ | ParStmt [ParStmtBlock idL idR]+ (HsExpr idR) -- Polymorphic `mzip` for monad comprehensions+ (SyntaxExpr idR) -- The `>>=` operator+ -- See notes [Monad Comprehensions]+ (PostTc idR Type) -- S in (>>=) :: Q -> (R -> S) -> T+ -- After renaming, the ids are the binders+ -- bound by the stmts and used after themp++ | TransStmt {+ trS_form :: TransForm,+ trS_stmts :: [ExprLStmt idL], -- Stmts to the *left* of the 'group'+ -- which generates the tuples to be grouped++ trS_bndrs :: [(idR, idR)], -- See Note [TransStmt binder map]++ trS_using :: LHsExpr idR,+ trS_by :: Maybe (LHsExpr idR), -- "by e" (optional)+ -- Invariant: if trS_form = GroupBy, then grp_by = Just e++ trS_ret :: SyntaxExpr idR, -- The monomorphic 'return' function for+ -- the inner monad comprehensions+ trS_bind :: SyntaxExpr idR, -- The '(>>=)' operator+ trS_bind_arg_ty :: PostTc idR Type, -- R in (>>=) :: Q -> (R -> S) -> T+ trS_fmap :: HsExpr idR -- The polymorphic 'fmap' function for desugaring+ -- Only for 'group' forms+ -- Just a simple HsExpr, because it's+ -- too polymorphic for tcSyntaxOp+ } -- See Note [Monad Comprehensions]++ -- Recursive statement (see Note [How RecStmt works] below)+ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnRec'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | RecStmt+ { recS_stmts :: [LStmtLR idL idR body]++ -- The next two fields are only valid after renaming+ , recS_later_ids :: [idR] -- The ids are a subset of the variables bound by the+ -- stmts that are used in stmts that follow the RecStmt++ , recS_rec_ids :: [idR] -- Ditto, but these variables are the "recursive" ones,+ -- that are used before they are bound in the stmts of+ -- the RecStmt.+ -- An Id can be in both groups+ -- Both sets of Ids are (now) treated monomorphically+ -- See Note [How RecStmt works] for why they are separate++ -- Rebindable syntax+ , recS_bind_fn :: SyntaxExpr idR -- The bind function+ , recS_ret_fn :: SyntaxExpr idR -- The return function+ , recS_mfix_fn :: SyntaxExpr idR -- The mfix function+ , recS_bind_ty :: PostTc idR Type -- S in (>>=) :: Q -> (R -> S) -> T++ -- These fields are only valid after typechecking+ , recS_later_rets :: [PostTcExpr] -- (only used in the arrow version)+ , recS_rec_rets :: [PostTcExpr] -- These expressions correspond 1-to-1+ -- with recS_later_ids and recS_rec_ids,+ -- and are the expressions that should be+ -- returned by the recursion.+ -- They may not quite be the Ids themselves,+ -- because the Id may be *polymorphic*, but+ -- the returned thing has to be *monomorphic*,+ -- so they may be type applications++ , recS_ret_ty :: PostTc idR Type -- The type of+ -- do { stmts; return (a,b,c) }+ -- With rebindable syntax the type might not+ -- be quite as simple as (m (tya, tyb, tyc)).+ }+deriving instance (Data body, DataId idL, DataId idR)+ => Data (StmtLR idL idR body)++data TransForm -- The 'f' below is the 'using' function, 'e' is the by function+ = ThenForm -- then f or then f by e (depending on trS_by)+ | GroupForm -- then group using f or then group by e using f (depending on trS_by)+ deriving Data++-- | Parenthesised Statement Block+data ParStmtBlock idL idR+ = ParStmtBlock+ [ExprLStmt idL]+ [idR] -- The variables to be returned+ (SyntaxExpr idR) -- The return operator+deriving instance (DataId idL, DataId idR) => Data (ParStmtBlock idL idR)++-- | Applicative Argument+data ApplicativeArg idL idR+ = ApplicativeArgOne -- pat <- expr (pat must be irrefutable)+ (LPat idL)+ (LHsExpr idL)+ | ApplicativeArgMany -- do { stmts; return vars }+ [ExprLStmt idL] -- stmts+ (HsExpr idL) -- return (v1,..,vn), or just (v1,..,vn)+ (LPat idL) -- (v1,...,vn)+deriving instance (DataId idL, DataId idR) => Data (ApplicativeArg idL idR)++{-+Note [The type of bind in Stmts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Some Stmts, notably BindStmt, keep the (>>=) bind operator.+We do NOT assume that it has type+ (>>=) :: m a -> (a -> m b) -> m b+In some cases (see Trac #303, #1537) it might have a more+exotic type, such as+ (>>=) :: m i j a -> (a -> m j k b) -> m i k b+So we must be careful not to make assumptions about the type.+In particular, the monad may not be uniform throughout.++Note [TransStmt binder map]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+The [(idR,idR)] in a TransStmt behaves as follows:++ * Before renaming: []++ * After renaming:+ [ (x27,x27), ..., (z35,z35) ]+ These are the variables+ bound by the stmts to the left of the 'group'+ and used either in the 'by' clause,+ or in the stmts following the 'group'+ Each item is a pair of identical variables.++ * After typechecking:+ [ (x27:Int, x27:[Int]), ..., (z35:Bool, z35:[Bool]) ]+ Each pair has the same unique, but different *types*.++Note [BodyStmt]+~~~~~~~~~~~~~~~+BodyStmts are a bit tricky, because what they mean+depends on the context. Consider the following contexts:++ A do expression of type (m res_ty)+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * BodyStmt E any_ty: do { ....; E; ... }+ E :: m any_ty+ Translation: E >> ...++ A list comprehensions of type [elt_ty]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * BodyStmt E Bool: [ .. | .... E ]+ [ .. | ..., E, ... ]+ [ .. | .... | ..., E | ... ]+ E :: Bool+ Translation: if E then fail else ...++ A guard list, guarding a RHS of type rhs_ty+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * BodyStmt E BooParStmtBlockl: f x | ..., E, ... = ...rhs...+ E :: Bool+ Translation: if E then fail else ...++ A monad comprehension of type (m res_ty)+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * BodyStmt E Bool: [ .. | .... E ]+ E :: Bool+ Translation: guard E >> ...++Array comprehensions are handled like list comprehensions.++Note [How RecStmt works]+~~~~~~~~~~~~~~~~~~~~~~~~+Example:+ HsDo [ BindStmt x ex++ , RecStmt { recS_rec_ids = [a, c]+ , recS_stmts = [ BindStmt b (return (a,c))+ , LetStmt a = ...b...+ , BindStmt c ec ]+ , recS_later_ids = [a, b]++ , return (a b) ]++Here, the RecStmt binds a,b,c; but+ - Only a,b are used in the stmts *following* the RecStmt,+ - Only a,c are used in the stmts *inside* the RecStmt+ *before* their bindings++Why do we need *both* rec_ids and later_ids? For monads they could be+combined into a single set of variables, but not for arrows. That+follows from the types of the respective feedback operators:++ mfix :: MonadFix m => (a -> m a) -> m a+ loop :: ArrowLoop a => a (b,d) (c,d) -> a b c++* For mfix, the 'a' covers the union of the later_ids and the rec_ids+* For 'loop', 'c' is the later_ids and 'd' is the rec_ids++Note [Typing a RecStmt]+~~~~~~~~~~~~~~~~~~~~~~~+A (RecStmt stmts) types as if you had written++ (v1,..,vn, _, ..., _) <- mfix (\~(_, ..., _, r1, ..., rm) ->+ do { stmts+ ; return (v1,..vn, r1, ..., rm) })++where v1..vn are the later_ids+ r1..rm are the rec_ids++Note [Monad Comprehensions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Monad comprehensions require separate functions like 'return' and+'>>=' for desugaring. These functions are stored in the statements+used in monad comprehensions. For example, the 'return' of the 'LastStmt'+expression is used to lift the body of the monad comprehension:++ [ body | stmts ]+ =>+ stmts >>= \bndrs -> return body++In transform and grouping statements ('then ..' and 'then group ..') the+'return' function is required for nested monad comprehensions, for example:++ [ body | stmts, then f, rest ]+ =>+ f [ env | stmts ] >>= \bndrs -> [ body | rest ]++BodyStmts require the 'Control.Monad.guard' function for boolean+expressions:++ [ body | exp, stmts ]+ =>+ guard exp >> [ body | stmts ]++Parallel statements require the 'Control.Monad.Zip.mzip' function:++ [ body | stmts1 | stmts2 | .. ]+ =>+ mzip stmts1 (mzip stmts2 (..)) >>= \(bndrs1, (bndrs2, ..)) -> return body++In any other context than 'MonadComp', the fields for most of these+'SyntaxExpr's stay bottom.+-}++instance (OutputableBndrId idL) => Outputable (ParStmtBlock idL idR) where+ ppr (ParStmtBlock stmts _ _) = interpp'SP stmts++instance (OutputableBndrId idL, OutputableBndrId idR, Outputable body)+ => Outputable (StmtLR idL idR body) where+ ppr stmt = pprStmt stmt++pprStmt :: forall idL idR body . (OutputableBndrId idL, OutputableBndrId idR,+ Outputable body)+ => (StmtLR idL idR body) -> SDoc+pprStmt (LastStmt expr ret_stripped _)+ = ifPprDebug (text "[last]") <+>+ (if ret_stripped then text "return" else empty) <+>+ ppr expr+pprStmt (BindStmt pat expr _ _ _) = hsep [ppr pat, larrow, ppr expr]+pprStmt (LetStmt (L _ binds)) = hsep [text "let", pprBinds binds]+pprStmt (BodyStmt expr _ _ _) = ppr expr+pprStmt (ParStmt stmtss _ _ _) = sep (punctuate (text " | ") (map ppr stmtss))++pprStmt (TransStmt { trS_stmts = stmts, trS_by = by, trS_using = using, trS_form = form })+ = sep $ punctuate comma (map ppr stmts ++ [pprTransStmt by using form])++pprStmt (RecStmt { recS_stmts = segment, recS_rec_ids = rec_ids+ , recS_later_ids = later_ids })+ = text "rec" <+>+ vcat [ ppr_do_stmts segment+ , ifPprDebug (vcat [ text "rec_ids=" <> ppr rec_ids+ , text "later_ids=" <> ppr later_ids])]++pprStmt (ApplicativeStmt args mb_join _)+ = getPprStyle $ \style ->+ if userStyle style+ then pp_for_user+ else pp_debug+ where+ -- make all the Applicative stuff invisible in error messages by+ -- flattening the whole ApplicativeStmt nest back to a sequence+ -- of statements.+ pp_for_user = vcat $ concatMap flattenArg args++ -- ppr directly rather than transforming here, because we need to+ -- inject a "return" which is hard when we're polymorphic in the id+ -- type.+ flattenStmt :: ExprLStmt idL -> [SDoc]+ flattenStmt (L _ (ApplicativeStmt args _ _)) = concatMap flattenArg args+ flattenStmt stmt = [ppr stmt]++ flattenArg (_, ApplicativeArgOne pat expr) =+ [ppr (BindStmt pat expr noSyntaxExpr noSyntaxExpr (panic "pprStmt")+ :: ExprStmt idL)]+ flattenArg (_, ApplicativeArgMany stmts _ _) =+ concatMap flattenStmt stmts++ pp_debug =+ let+ ap_expr = sep (punctuate (text " |") (map pp_arg args))+ in+ if isNothing mb_join+ then ap_expr+ else text "join" <+> parens ap_expr++ pp_arg (_, ApplicativeArgOne pat expr) =+ ppr (BindStmt pat expr noSyntaxExpr noSyntaxExpr (panic "pprStmt")+ :: ExprStmt idL)+ pp_arg (_, ApplicativeArgMany stmts return pat) =+ ppr pat <+>+ text "<-" <+>+ ppr (HsDo DoExpr (noLoc+ (stmts ++ [noLoc (LastStmt (noLoc return) False noSyntaxExpr)]))+ (error "pprStmt"))++pprTransformStmt :: (OutputableBndrId id)+ => [id] -> LHsExpr id -> Maybe (LHsExpr id) -> SDoc+pprTransformStmt bndrs using by+ = sep [ text "then" <+> ifPprDebug (braces (ppr bndrs))+ , nest 2 (ppr using)+ , nest 2 (pprBy by)]++pprTransStmt :: Outputable body => Maybe body -> body -> TransForm -> SDoc+pprTransStmt by using ThenForm+ = sep [ text "then", nest 2 (ppr using), nest 2 (pprBy by)]+pprTransStmt by using GroupForm+ = sep [ text "then group", nest 2 (pprBy by), nest 2 (ptext (sLit "using") <+> ppr using)]++pprBy :: Outputable body => Maybe body -> SDoc+pprBy Nothing = empty+pprBy (Just e) = text "by" <+> ppr e++pprDo :: (OutputableBndrId id, Outputable body)+ => HsStmtContext any -> [LStmt id body] -> SDoc+pprDo DoExpr stmts = text "do" <+> ppr_do_stmts stmts+pprDo GhciStmtCtxt stmts = text "do" <+> ppr_do_stmts stmts+pprDo ArrowExpr stmts = text "do" <+> ppr_do_stmts stmts+pprDo MDoExpr stmts = text "mdo" <+> ppr_do_stmts stmts+pprDo ListComp stmts = brackets $ pprComp stmts+pprDo PArrComp stmts = paBrackets $ pprComp stmts+pprDo MonadComp stmts = brackets $ pprComp stmts+pprDo _ _ = panic "pprDo" -- PatGuard, ParStmtCxt++ppr_do_stmts :: (OutputableBndrId idL, OutputableBndrId idR, Outputable body)+ => [LStmtLR idL idR body] -> SDoc+-- Print a bunch of do stmts+ppr_do_stmts stmts = pprDeeperList vcat (map ppr stmts)++pprComp :: (OutputableBndrId id, Outputable body) => [LStmt id body] -> SDoc+pprComp quals -- Prints: body | qual1, ..., qualn+ | Just (initStmts, L _ (LastStmt body _ _)) <- snocView quals+ = if null initStmts+ -- If there are no statements in a list comprehension besides the last+ -- one, we simply treat it like a normal list. This does arise+ -- occasionally in code that GHC generates, e.g., in implementations of+ -- 'range' for derived 'Ix' instances for product datatypes with exactly+ -- one constructor (e.g., see Trac #12583).+ then ppr body+ else hang (ppr body <+> vbar) 2 (pprQuals initStmts)+ | otherwise+ = pprPanic "pprComp" (pprQuals quals)++pprQuals :: (OutputableBndrId id, Outputable body) => [LStmt id body] -> SDoc+-- Show list comprehension qualifiers separated by commas+pprQuals quals = interpp'SP quals++{-+************************************************************************+* *+ Template Haskell quotation brackets+* *+************************************************************************+-}++-- | Haskell Splice+data HsSplice id+ = HsTypedSplice -- $$z or $$(f 4)+ SpliceDecoration -- Whether $$( ) variant found, for pretty printing+ id -- A unique name to identify this splice point+ (LHsExpr id) -- See Note [Pending Splices]++ | HsUntypedSplice -- $z or $(f 4)+ SpliceDecoration -- Whether $( ) variant found, for pretty printing+ id -- A unique name to identify this splice point+ (LHsExpr id) -- See Note [Pending Splices]++ | HsQuasiQuote -- See Note [Quasi-quote overview] in TcSplice+ id -- Splice point+ id -- Quoter+ SrcSpan -- The span of the enclosed string+ FastString -- The enclosed string++ | HsSpliced -- See Note [Delaying modFinalizers in untyped splices] in+ -- RnSplice.+ -- This is the result of splicing a splice. It is produced by+ -- the renamer and consumed by the typechecker. It lives only+ -- between the two.+ ThModFinalizers -- TH finalizers produced by the splice.+ (HsSplicedThing id) -- The result of splicing+ deriving Typeable+deriving instance (DataId id) => Data (HsSplice id)++-- | A splice can appear with various decorations wrapped around it. This data+-- type captures explicitly how it was originally written, for use in the pretty+-- printer.+data SpliceDecoration+ = HasParens -- ^ $( splice ) or $$( splice )+ | HasDollar -- ^ $splice or $$splice+ | NoParens -- ^ bare splice+ deriving (Data, Eq, Show)++instance Outputable SpliceDecoration where+ ppr x = text $ show x+++isTypedSplice :: HsSplice id -> Bool+isTypedSplice (HsTypedSplice {}) = True+isTypedSplice _ = False -- Quasi-quotes are untyped splices++-- | Finalizers produced by a splice with+-- 'Language.Haskell.TH.Syntax.addModFinalizer'+--+-- See Note [Delaying modFinalizers in untyped splices] in RnSplice. For how+-- this is used.+--+newtype ThModFinalizers = ThModFinalizers [ForeignRef (TH.Q ())]++-- A Data instance which ignores the argument of 'ThModFinalizers'.+instance Data ThModFinalizers where+ gunfold _ z _ = z $ ThModFinalizers []+ toConstr a = mkConstr (dataTypeOf a) "ThModFinalizers" [] Data.Prefix+ dataTypeOf a = mkDataType "HsExpr.ThModFinalizers" [toConstr a]++-- | Haskell Spliced Thing+--+-- Values that can result from running a splice.+data HsSplicedThing id+ = HsSplicedExpr (HsExpr id) -- ^ Haskell Spliced Expression+ | HsSplicedTy (HsType id) -- ^ Haskell Spliced Type+ | HsSplicedPat (Pat id) -- ^ Haskell Spliced Pattern+ deriving Typeable++deriving instance (DataId id) => Data (HsSplicedThing id)++-- See Note [Pending Splices]+type SplicePointName = Name++-- | Pending Renamer Splice+data PendingRnSplice+ = PendingRnSplice UntypedSpliceFlavour SplicePointName (LHsExpr Name)+ deriving Data++data UntypedSpliceFlavour+ = UntypedExpSplice+ | UntypedPatSplice+ | UntypedTypeSplice+ | UntypedDeclSplice+ deriving Data++-- | Pending Type-checker Splice+data PendingTcSplice+ = PendingTcSplice SplicePointName (LHsExpr Id)+ deriving Data+++{-+Note [Pending Splices]+~~~~~~~~~~~~~~~~~~~~~~+When we rename an untyped bracket, we name and lift out all the nested+splices, so that when the typechecker hits the bracket, it can+typecheck those nested splices without having to walk over the untyped+bracket code. So for example+ [| f $(g x) |]+looks like++ HsBracket (HsApp (HsVar "f") (HsSpliceE _ (g x)))++which the renamer rewrites to++ HsRnBracketOut (HsApp (HsVar f) (HsSpliceE sn (g x)))+ [PendingRnSplice UntypedExpSplice sn (g x)]++* The 'sn' is the Name of the splice point, the SplicePointName++* The PendingRnExpSplice gives the splice that splice-point name maps to;+ and the typechecker can now conveniently find these sub-expressions++* The other copy of the splice, in the second argument of HsSpliceE+ in the renamed first arg of HsRnBracketOut+ is used only for pretty printing++There are four varieties of pending splices generated by the renamer,+distinguished by their UntypedSpliceFlavour++ * Pending expression splices (UntypedExpSplice), e.g.,+ [|$(f x) + 2|]++ UntypedExpSplice is also used for+ * quasi-quotes, where the pending expression expands to+ $(quoter "...blah...")+ (see RnSplice.makePending, HsQuasiQuote case)++ * cross-stage lifting, where the pending expression expands to+ $(lift x)+ (see RnSplice.checkCrossStageLifting)++ * Pending pattern splices (UntypedPatSplice), e.g.,+ [| \$(f x) -> x |]++ * Pending type splices (UntypedTypeSplice), e.g.,+ [| f :: $(g x) |]++ * Pending declaration (UntypedDeclSplice), e.g.,+ [| let $(f x) in ... |]++There is a fifth variety of pending splice, which is generated by the type+checker:++ * Pending *typed* expression splices, (PendingTcSplice), e.g.,+ [||1 + $$(f 2)||]++It would be possible to eliminate HsRnBracketOut and use HsBracketOut for the+output of the renamer. However, when pretty printing the output of the renamer,+e.g., in a type error message, we *do not* want to print out the pending+splices. In contrast, when pretty printing the output of the type checker, we+*do* want to print the pending splices. So splitting them up seems to make+sense, although I hate to add another constructor to HsExpr.+-}++instance (OutputableBndrId id) => Outputable (HsSplicedThing id) where+ ppr (HsSplicedExpr e) = ppr_expr e+ ppr (HsSplicedTy t) = ppr t+ ppr (HsSplicedPat p) = ppr p++instance (OutputableBndrId id) => Outputable (HsSplice id) where+ ppr s = pprSplice s++pprPendingSplice :: (OutputableBndrId id)+ => SplicePointName -> LHsExpr id -> SDoc+pprPendingSplice n e = angleBrackets (ppr n <> comma <+> ppr e)++pprSpliceDecl :: (OutputableBndrId id)+ => HsSplice id -> SpliceExplicitFlag -> SDoc+pprSpliceDecl e@HsQuasiQuote{} _ = pprSplice e+pprSpliceDecl e ExplicitSplice = text "$(" <> ppr_splice_decl e <> text ")"+pprSpliceDecl e ImplicitSplice = ppr_splice_decl e++ppr_splice_decl :: (OutputableBndrId id) => HsSplice id -> SDoc+ppr_splice_decl (HsUntypedSplice _ n e) = ppr_splice empty n e empty+ppr_splice_decl e = pprSplice e++pprSplice :: (OutputableBndrId id) => HsSplice id -> SDoc+pprSplice (HsTypedSplice HasParens n e)+ = ppr_splice (text "$$(") n e (text ")")+pprSplice (HsTypedSplice HasDollar n e)+ = ppr_splice (text "$$") n e empty+pprSplice (HsTypedSplice NoParens n e)+ = ppr_splice empty n e empty+pprSplice (HsUntypedSplice HasParens n e)+ = ppr_splice (text "$(") n e (text ")")+pprSplice (HsUntypedSplice HasDollar n e)+ = ppr_splice (text "$") n e empty+pprSplice (HsUntypedSplice NoParens n e)+ = ppr_splice empty n e empty+pprSplice (HsQuasiQuote n q _ s) = ppr_quasi n q s+pprSplice (HsSpliced _ thing) = ppr thing++ppr_quasi :: OutputableBndr id => id -> id -> FastString -> SDoc+ppr_quasi n quoter quote = ifPprDebug (brackets (ppr n)) <>+ char '[' <> ppr quoter <> vbar <>+ ppr quote <> text "|]"++ppr_splice :: (OutputableBndrId id)+ => SDoc -> id -> LHsExpr id -> SDoc -> SDoc+ppr_splice herald n e trail+ = herald <> ifPprDebug (brackets (ppr n)) <> ppr e <> trail++-- | Haskell Bracket+data HsBracket id = ExpBr (LHsExpr id) -- [| expr |]+ | PatBr (LPat id) -- [p| pat |]+ | DecBrL [LHsDecl id] -- [d| decls |]; result of parser+ | DecBrG (HsGroup id) -- [d| decls |]; result of renamer+ | TypBr (LHsType id) -- [t| type |]+ | VarBr Bool id -- True: 'x, False: ''T+ -- (The Bool flag is used only in pprHsBracket)+ | TExpBr (LHsExpr id) -- [|| expr ||]+deriving instance (DataId id) => Data (HsBracket id)++isTypedBracket :: HsBracket id -> Bool+isTypedBracket (TExpBr {}) = True+isTypedBracket _ = False++instance (OutputableBndrId id) => Outputable (HsBracket id) where+ ppr = pprHsBracket+++pprHsBracket :: (OutputableBndrId id) => HsBracket id -> SDoc+pprHsBracket (ExpBr e) = thBrackets empty (ppr e)+pprHsBracket (PatBr p) = thBrackets (char 'p') (ppr p)+pprHsBracket (DecBrG gp) = thBrackets (char 'd') (ppr gp)+pprHsBracket (DecBrL ds) = thBrackets (char 'd') (vcat (map ppr ds))+pprHsBracket (TypBr t) = thBrackets (char 't') (ppr t)+pprHsBracket (VarBr True n)+ = char '\'' <> pprPrefixOcc n+pprHsBracket (VarBr False n)+ = text "''" <> pprPrefixOcc n+pprHsBracket (TExpBr e) = thTyBrackets (ppr e)++thBrackets :: SDoc -> SDoc -> SDoc+thBrackets pp_kind pp_body = char '[' <> pp_kind <> vbar <+>+ pp_body <+> text "|]"++thTyBrackets :: SDoc -> SDoc+thTyBrackets pp_body = text "[||" <+> pp_body <+> ptext (sLit "||]")++instance Outputable PendingRnSplice where+ ppr (PendingRnSplice _ n e) = pprPendingSplice n e++instance Outputable PendingTcSplice where+ ppr (PendingTcSplice n e) = pprPendingSplice n e++{-+************************************************************************+* *+\subsection{Enumerations and list comprehensions}+* *+************************************************************************+-}++-- | Arithmetic Sequence Information+data ArithSeqInfo id+ = From (LHsExpr id)+ | FromThen (LHsExpr id)+ (LHsExpr id)+ | FromTo (LHsExpr id)+ (LHsExpr id)+ | FromThenTo (LHsExpr id)+ (LHsExpr id)+ (LHsExpr id)+deriving instance (DataId id) => Data (ArithSeqInfo id)++instance (OutputableBndrId id)+ => Outputable (ArithSeqInfo id) where+ ppr (From e1) = hcat [ppr e1, pp_dotdot]+ ppr (FromThen e1 e2) = hcat [ppr e1, comma, space, ppr e2, pp_dotdot]+ ppr (FromTo e1 e3) = hcat [ppr e1, pp_dotdot, ppr e3]+ ppr (FromThenTo e1 e2 e3)+ = hcat [ppr e1, comma, space, ppr e2, pp_dotdot, ppr e3]++pp_dotdot :: SDoc+pp_dotdot = text " .. "++{-+************************************************************************+* *+\subsection{HsMatchCtxt}+* *+************************************************************************+-}++-- | Haskell Match Context+--+-- Context of a pattern match. This is more subtle than it would seem. See Note+-- [Varieties of pattern matches].+data HsMatchContext id -- Not an extensible tag+ = FunRhs { mc_fun :: Located id -- ^ function binder of @f@+ , mc_fixity :: LexicalFixity -- ^ fixing of @f@+ , mc_strictness :: SrcStrictness+ -- ^ was the pattern banged? See+ -- Note [Varieties of binding pattern matches]+ }+ -- ^A pattern matching on an argument of a+ -- function binding+ | LambdaExpr -- ^Patterns of a lambda+ | CaseAlt -- ^Patterns and guards on a case alternative+ | IfAlt -- ^Guards of a multi-way if alternative+ | ProcExpr -- ^Patterns of a proc+ | PatBindRhs -- ^A pattern binding eg [y] <- e = e++ | RecUpd -- ^Record update [used only in DsExpr to+ -- tell matchWrapper what sort of+ -- runtime error message to generate]++ | StmtCtxt (HsStmtContext id) -- ^Pattern of a do-stmt, list comprehension,+ -- pattern guard, etc++ | ThPatSplice -- ^A Template Haskell pattern splice+ | ThPatQuote -- ^A Template Haskell pattern quotation [p| (a,b) |]+ | PatSyn -- ^A pattern synonym declaration+ deriving Functor+deriving instance (DataIdPost id) => Data (HsMatchContext id)++instance OutputableBndr id => Outputable (HsMatchContext id) where+ ppr m@(FunRhs{}) = text "FunRhs" <+> ppr (mc_fun m) <+> ppr (mc_fixity m)+ ppr LambdaExpr = text "LambdaExpr"+ ppr CaseAlt = text "CaseAlt"+ ppr IfAlt = text "IfAlt"+ ppr ProcExpr = text "ProcExpr"+ ppr PatBindRhs = text "PatBindRhs"+ ppr RecUpd = text "RecUpd"+ ppr (StmtCtxt _) = text "StmtCtxt _"+ ppr ThPatSplice = text "ThPatSplice"+ ppr ThPatQuote = text "ThPatQuote"+ ppr PatSyn = text "PatSyn"++isPatSynCtxt :: HsMatchContext id -> Bool+isPatSynCtxt ctxt =+ case ctxt of+ PatSyn -> True+ _ -> False++-- | Haskell Statement Context+data HsStmtContext id+ = ListComp+ | MonadComp+ | PArrComp -- ^Parallel array comprehension++ | DoExpr -- ^do { ... }+ | MDoExpr -- ^mdo { ... } ie recursive do-expression+ | ArrowExpr -- ^do-notation in an arrow-command context++ | GhciStmtCtxt -- ^A command-line Stmt in GHCi pat <- rhs+ | PatGuard (HsMatchContext id) -- ^Pattern guard for specified thing+ | ParStmtCtxt (HsStmtContext id) -- ^A branch of a parallel stmt+ | TransStmtCtxt (HsStmtContext id) -- ^A branch of a transform stmt+ deriving Functor+deriving instance (DataIdPost id) => Data (HsStmtContext id)++isListCompExpr :: HsStmtContext id -> Bool+-- Uses syntax [ e | quals ]+isListCompExpr ListComp = True+isListCompExpr PArrComp = True+isListCompExpr MonadComp = True+isListCompExpr (ParStmtCtxt c) = isListCompExpr c+isListCompExpr (TransStmtCtxt c) = isListCompExpr c+isListCompExpr _ = False++isMonadCompExpr :: HsStmtContext id -> Bool+isMonadCompExpr MonadComp = True+isMonadCompExpr (ParStmtCtxt ctxt) = isMonadCompExpr ctxt+isMonadCompExpr (TransStmtCtxt ctxt) = isMonadCompExpr ctxt+isMonadCompExpr _ = False++-- | Should pattern match failure in a 'HsStmtContext' be desugared using+-- 'MonadFail'?+isMonadFailStmtContext :: HsStmtContext id -> Bool+isMonadFailStmtContext MonadComp = True+isMonadFailStmtContext DoExpr = True+isMonadFailStmtContext MDoExpr = True+isMonadFailStmtContext GhciStmtCtxt = True+isMonadFailStmtContext _ = False++matchSeparator :: HsMatchContext id -> SDoc+matchSeparator (FunRhs {}) = text "="+matchSeparator CaseAlt = text "->"+matchSeparator IfAlt = text "->"+matchSeparator LambdaExpr = text "->"+matchSeparator ProcExpr = text "->"+matchSeparator PatBindRhs = text "="+matchSeparator (StmtCtxt _) = text "<-"+matchSeparator RecUpd = text "=" -- This can be printed by the pattern+ -- match checker trace+matchSeparator ThPatSplice = panic "unused"+matchSeparator ThPatQuote = panic "unused"+matchSeparator PatSyn = panic "unused"++pprMatchContext :: (Outputable (NameOrRdrName id),Outputable id)+ => HsMatchContext id -> SDoc+pprMatchContext ctxt+ | want_an ctxt = text "an" <+> pprMatchContextNoun ctxt+ | otherwise = text "a" <+> pprMatchContextNoun ctxt+ where+ want_an (FunRhs {}) = True -- Use "an" in front+ want_an ProcExpr = True+ want_an _ = False++pprMatchContextNoun :: (Outputable (NameOrRdrName id),Outputable id)+ => HsMatchContext id -> SDoc+pprMatchContextNoun (FunRhs {mc_fun=L _ fun})+ = text "equation for"+ <+> quotes (ppr fun)+pprMatchContextNoun CaseAlt = text "case alternative"+pprMatchContextNoun IfAlt = text "multi-way if alternative"+pprMatchContextNoun RecUpd = text "record-update construct"+pprMatchContextNoun ThPatSplice = text "Template Haskell pattern splice"+pprMatchContextNoun ThPatQuote = text "Template Haskell pattern quotation"+pprMatchContextNoun PatBindRhs = text "pattern binding"+pprMatchContextNoun LambdaExpr = text "lambda abstraction"+pprMatchContextNoun ProcExpr = text "arrow abstraction"+pprMatchContextNoun (StmtCtxt ctxt) = text "pattern binding in"+ $$ pprStmtContext ctxt+pprMatchContextNoun PatSyn = text "pattern synonym declaration"++-----------------+pprAStmtContext, pprStmtContext :: (Outputable id,+ Outputable (NameOrRdrName id))+ => HsStmtContext id -> SDoc+pprAStmtContext ctxt = article <+> pprStmtContext ctxt+ where+ pp_an = text "an"+ pp_a = text "a"+ article = case ctxt of+ MDoExpr -> pp_an+ PArrComp -> pp_an+ GhciStmtCtxt -> pp_an+ _ -> pp_a+++-----------------+pprStmtContext GhciStmtCtxt = text "interactive GHCi command"+pprStmtContext DoExpr = text "'do' block"+pprStmtContext MDoExpr = text "'mdo' block"+pprStmtContext ArrowExpr = text "'do' block in an arrow command"+pprStmtContext ListComp = text "list comprehension"+pprStmtContext MonadComp = text "monad comprehension"+pprStmtContext PArrComp = text "array comprehension"+pprStmtContext (PatGuard ctxt) = text "pattern guard for" $$ pprMatchContext ctxt++-- Drop the inner contexts when reporting errors, else we get+-- Unexpected transform statement+-- in a transformed branch of+-- transformed branch of+-- transformed branch of monad comprehension+pprStmtContext (ParStmtCtxt c) =+ sdocWithPprDebug $ \dbg -> if dbg+ then sep [text "parallel branch of", pprAStmtContext c]+ else pprStmtContext c+pprStmtContext (TransStmtCtxt c) =+ sdocWithPprDebug $ \dbg -> if dbg+ then sep [text "transformed branch of", pprAStmtContext c]+ else pprStmtContext c++instance (Outputable id, Outputable (NameOrRdrName id))+ => Outputable (HsStmtContext id) where+ ppr = pprStmtContext++-- Used to generate the string for a *runtime* error message+matchContextErrString :: Outputable id+ => HsMatchContext id -> SDoc+matchContextErrString (FunRhs{mc_fun=L _ fun}) = text "function" <+> ppr fun+matchContextErrString CaseAlt = text "case"+matchContextErrString IfAlt = text "multi-way if"+matchContextErrString PatBindRhs = text "pattern binding"+matchContextErrString RecUpd = text "record update"+matchContextErrString LambdaExpr = text "lambda"+matchContextErrString ProcExpr = text "proc"+matchContextErrString ThPatSplice = panic "matchContextErrString" -- Not used at runtime+matchContextErrString ThPatQuote = panic "matchContextErrString" -- Not used at runtime+matchContextErrString PatSyn = panic "matchContextErrString" -- Not used at runtime+matchContextErrString (StmtCtxt (ParStmtCtxt c)) = matchContextErrString (StmtCtxt c)+matchContextErrString (StmtCtxt (TransStmtCtxt c)) = matchContextErrString (StmtCtxt c)+matchContextErrString (StmtCtxt (PatGuard _)) = text "pattern guard"+matchContextErrString (StmtCtxt GhciStmtCtxt) = text "interactive GHCi command"+matchContextErrString (StmtCtxt DoExpr) = text "'do' block"+matchContextErrString (StmtCtxt ArrowExpr) = text "'do' block"+matchContextErrString (StmtCtxt MDoExpr) = text "'mdo' block"+matchContextErrString (StmtCtxt ListComp) = text "list comprehension"+matchContextErrString (StmtCtxt MonadComp) = text "monad comprehension"+matchContextErrString (StmtCtxt PArrComp) = text "array comprehension"++pprMatchInCtxt :: (OutputableBndrId idR,+ Outputable (NameOrRdrName (NameOrRdrName idR)),+ Outputable body)+ => Match idR body -> SDoc+pprMatchInCtxt match = hang (text "In" <+> pprMatchContext (m_ctxt match)+ <> colon)+ 4 (pprMatch match)++pprStmtInCtxt :: (OutputableBndrId idL, OutputableBndrId idR,+ Outputable body)+ => HsStmtContext idL -> StmtLR idL idR body -> SDoc+pprStmtInCtxt ctxt (LastStmt e _ _)+ | isListCompExpr ctxt -- For [ e | .. ], do not mutter about "stmts"+ = hang (text "In the expression:") 2 (ppr e)++pprStmtInCtxt ctxt stmt+ = hang (text "In a stmt of" <+> pprAStmtContext ctxt <> colon)+ 2 (ppr_stmt stmt)+ where+ -- For Group and Transform Stmts, don't print the nested stmts!+ ppr_stmt (TransStmt { trS_by = by, trS_using = using+ , trS_form = form }) = pprTransStmt by using form+ ppr_stmt stmt = pprStmt stmt
+ hsSyn/HsExpr.hs-boot view
@@ -0,0 +1,57 @@+{-# LANGUAGE CPP, KindSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE RoleAnnotations #-}++module HsExpr where++import SrcLoc ( Located )+import Outputable ( SDoc, Outputable )+import {-# SOURCE #-} HsPat ( LPat )+import BasicTypes ( SpliceExplicitFlag(..))+import PlaceHolder ( DataId, OutputableBndrId )+import Data.Data hiding ( Fixity )++type role HsExpr nominal+type role HsCmd nominal+type role MatchGroup nominal representational+type role GRHSs nominal representational+type role HsSplice nominal+type role SyntaxExpr nominal+data HsExpr (i :: *)+data HsCmd (i :: *)+data HsSplice (i :: *)+data MatchGroup (a :: *) (body :: *)+data GRHSs (a :: *) (body :: *)+data SyntaxExpr (i :: *)++instance (DataId id) => Data (HsSplice id)+instance (DataId id) => Data (HsExpr id)+instance (DataId id) => Data (HsCmd id)+instance (Data body,DataId id) => Data (MatchGroup id body)+instance (Data body,DataId id) => Data (GRHSs id body)+instance (DataId id) => Data (SyntaxExpr id)++instance (OutputableBndrId id) => Outputable (HsExpr id)+instance (OutputableBndrId id) => Outputable (HsCmd id)++type LHsExpr a = Located (HsExpr a)++pprLExpr :: (OutputableBndrId id) => LHsExpr id -> SDoc++pprExpr :: (OutputableBndrId id) => HsExpr id -> SDoc++pprSplice :: (OutputableBndrId id) => HsSplice id -> SDoc++pprSpliceDecl :: (OutputableBndrId id)+ => HsSplice id -> SpliceExplicitFlag -> SDoc++pprPatBind :: (OutputableBndrId bndr,+ OutputableBndrId id,+ Outputable body)+ => LPat bndr -> GRHSs id body -> SDoc++pprFunBind :: (OutputableBndrId idR, Outputable body)+ => MatchGroup idR body -> SDoc
+ hsSyn/HsImpExp.hs view
@@ -0,0 +1,310 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++HsImpExp: Abstract syntax: imports, exports, interfaces+-}++{-# LANGUAGE DeriveDataTypeable #-}++module HsImpExp where++import Module ( ModuleName )+import HsDoc ( HsDocString )+import OccName ( HasOccName(..), isTcOcc, isSymOcc )+import BasicTypes ( SourceText(..), StringLiteral(..), pprWithSourceText )+import FieldLabel ( FieldLbl(..) )++import Outputable+import FastString+import SrcLoc++import Data.Data++{-+************************************************************************+* *+\subsection{Import and export declaration lists}+* *+************************************************************************++One per \tr{import} declaration in a module.+-}++-- | Located Import Declaration+type LImportDecl name = Located (ImportDecl name)+ -- ^ When in a list this may have+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSemi'++ -- For details on above see note [Api annotations] in ApiAnnotation++-- | Import Declaration+--+-- A single Haskell @import@ declaration.+data ImportDecl name+ = ImportDecl {+ ideclSourceSrc :: SourceText,+ -- Note [Pragma source text] in BasicTypes+ ideclName :: Located ModuleName, -- ^ Module name.+ ideclPkgQual :: Maybe StringLiteral, -- ^ Package qualifier.+ ideclSource :: Bool, -- ^ True <=> {-\# SOURCE \#-} import+ ideclSafe :: Bool, -- ^ True => safe import+ ideclQualified :: Bool, -- ^ True => qualified+ ideclImplicit :: Bool, -- ^ True => implicit import (of Prelude)+ ideclAs :: Maybe (Located ModuleName), -- ^ as Module+ ideclHiding :: Maybe (Bool, Located [LIE name])+ -- ^ (True => hiding, names)+ }+ -- ^+ -- 'ApiAnnotation.AnnKeywordId's+ --+ -- - 'ApiAnnotation.AnnImport'+ --+ -- - 'ApiAnnotation.AnnOpen', 'ApiAnnotation.AnnClose' for ideclSource+ --+ -- - 'ApiAnnotation.AnnSafe','ApiAnnotation.AnnQualified',+ -- 'ApiAnnotation.AnnPackageName','ApiAnnotation.AnnAs',+ -- 'ApiAnnotation.AnnVal'+ --+ -- - 'ApiAnnotation.AnnHiding','ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose' attached+ -- to location in ideclHiding++ -- For details on above see note [Api annotations] in ApiAnnotation+ deriving Data++simpleImportDecl :: ModuleName -> ImportDecl name+simpleImportDecl mn = ImportDecl {+ ideclSourceSrc = NoSourceText,+ ideclName = noLoc mn,+ ideclPkgQual = Nothing,+ ideclSource = False,+ ideclSafe = False,+ ideclImplicit = False,+ ideclQualified = False,+ ideclAs = Nothing,+ ideclHiding = Nothing+ }++instance (OutputableBndr name, HasOccName name) => Outputable (ImportDecl name) where+ ppr (ImportDecl { ideclSourceSrc = mSrcText, ideclName = mod'+ , ideclPkgQual = pkg+ , ideclSource = from, ideclSafe = safe+ , ideclQualified = qual, ideclImplicit = implicit+ , ideclAs = as, ideclHiding = spec })+ = hang (hsep [text "import", ppr_imp from, pp_implicit implicit, pp_safe safe,+ pp_qual qual, pp_pkg pkg, ppr mod', pp_as as])+ 4 (pp_spec spec)+ where+ pp_implicit False = empty+ pp_implicit True = ptext (sLit ("(implicit)"))++ pp_pkg Nothing = empty+ pp_pkg (Just (StringLiteral st p))+ = pprWithSourceText st (doubleQuotes (ftext p))++ pp_qual False = empty+ pp_qual True = text "qualified"++ pp_safe False = empty+ pp_safe True = text "safe"++ pp_as Nothing = empty+ pp_as (Just a) = text "as" <+> ppr a++ ppr_imp True = case mSrcText of+ NoSourceText -> text "{-# SOURCE #-}"+ SourceText src -> text src <+> text "#-}"+ ppr_imp False = empty++ pp_spec Nothing = empty+ pp_spec (Just (False, (L _ ies))) = ppr_ies ies+ pp_spec (Just (True, (L _ ies))) = text "hiding" <+> ppr_ies ies++ ppr_ies [] = text "()"+ ppr_ies ies = char '(' <+> interpp'SP ies <+> char ')'++{-+************************************************************************+* *+\subsection{Imported and exported entities}+* *+************************************************************************+-}++-- | A name in an import or export specfication which may have adornments. Used+-- primarily for accurate pretty printing of ParsedSource, and API Annotation+-- placement.+data IEWrappedName name+ = IEName (Located name) -- ^ no extra+ | IEPattern (Located name) -- ^ pattern X+ | IEType (Located name) -- ^ type (:+:)+ deriving (Eq,Data)++-- | Located name with possible adornment+-- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnType',+-- 'ApiAnnotation.AnnPattern'+type LIEWrappedName name = Located (IEWrappedName name)+-- For details on above see note [Api annotations] in ApiAnnotation+++-- | Located Import or Export+type LIE name = Located (IE name)+ -- ^ When in a list this may have+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnComma'++ -- For details on above see note [Api annotations] in ApiAnnotation++-- | Imported or exported entity.+data IE name+ = IEVar (LIEWrappedName name)+ -- ^ Imported or Exported Variable++ | IEThingAbs (LIEWrappedName name)+ -- ^ Imported or exported Thing with Absent list+ --+ -- The thing is a Class/Type (can't tell)+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnPattern',+ -- 'ApiAnnotation.AnnType','ApiAnnotation.AnnVal'++ -- For details on above see note [Api annotations] in ApiAnnotation+ -- See Note [Located RdrNames] in HsExpr+ | IEThingAll (LIEWrappedName name)+ -- ^ Imported or exported Thing with All imported or exported+ --+ -- The thing is a Class/Type and the All refers to methods/constructors+ --+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnDotdot','ApiAnnotation.AnnClose',+ -- 'ApiAnnotation.AnnType'++ -- For details on above see note [Api annotations] in ApiAnnotation+ -- See Note [Located RdrNames] in HsExpr++ | IEThingWith (LIEWrappedName name)+ IEWildcard+ [LIEWrappedName name]+ [Located (FieldLbl name)]+ -- ^ Imported or exported Thing With given imported or exported+ --+ -- The thing is a Class/Type and the imported or exported things are+ -- methods/constructors and record fields; see Note [IEThingWith]+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnClose',+ -- 'ApiAnnotation.AnnComma',+ -- 'ApiAnnotation.AnnType'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | IEModuleContents (Located ModuleName)+ -- ^ Imported or exported module contents+ --+ -- (Export Only)+ --+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnModule'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | IEGroup Int HsDocString -- ^ Doc section heading+ | IEDoc HsDocString -- ^ Some documentation+ | IEDocNamed String -- ^ Reference to named doc+ deriving (Eq, Data)++-- | Imported or Exported Wildcard+data IEWildcard = NoIEWildcard | IEWildcard Int deriving (Eq, Data)++{-+Note [IEThingWith]+~~~~~~~~~~~~~~~~~~++A definition like++ module M ( T(MkT, x) ) where+ data T = MkT { x :: Int }++gives rise to++ IEThingWith T [MkT] [FieldLabel "x" False x)] (without DuplicateRecordFields)+ IEThingWith T [MkT] [FieldLabel "x" True $sel:x:MkT)] (with DuplicateRecordFields)++See Note [Representing fields in AvailInfo] in Avail for more details.+-}++ieName :: IE name -> name+ieName (IEVar (L _ n)) = ieWrappedName n+ieName (IEThingAbs (L _ n)) = ieWrappedName n+ieName (IEThingWith (L _ n) _ _ _) = ieWrappedName n+ieName (IEThingAll (L _ n)) = ieWrappedName n+ieName _ = panic "ieName failed pattern match!"++ieNames :: IE a -> [a]+ieNames (IEVar (L _ n) ) = [ieWrappedName n]+ieNames (IEThingAbs (L _ n) ) = [ieWrappedName n]+ieNames (IEThingAll (L _ n) ) = [ieWrappedName n]+ieNames (IEThingWith (L _ n) _ ns _) = ieWrappedName n+ : map (ieWrappedName . unLoc) ns+ieNames (IEModuleContents _ ) = []+ieNames (IEGroup _ _ ) = []+ieNames (IEDoc _ ) = []+ieNames (IEDocNamed _ ) = []++ieWrappedName :: IEWrappedName name -> name+ieWrappedName (IEName (L _ n)) = n+ieWrappedName (IEPattern (L _ n)) = n+ieWrappedName (IEType (L _ n)) = n++ieLWrappedName :: LIEWrappedName name -> Located name+ieLWrappedName (L l n) = L l (ieWrappedName n)++replaceWrappedName :: IEWrappedName name1 -> name2 -> IEWrappedName name2+replaceWrappedName (IEName (L l _)) n = IEName (L l n)+replaceWrappedName (IEPattern (L l _)) n = IEPattern (L l n)+replaceWrappedName (IEType (L l _)) n = IEType (L l n)++replaceLWrappedName :: LIEWrappedName name1 -> name2 -> LIEWrappedName name2+replaceLWrappedName (L l n) n' = L l (replaceWrappedName n n')++instance (HasOccName name, OutputableBndr name) => Outputable (IE name) where+ ppr (IEVar var) = ppr (unLoc var)+ ppr (IEThingAbs thing) = ppr (unLoc thing)+ ppr (IEThingAll thing) = hcat [ppr (unLoc thing), text "(..)"]+ ppr (IEThingWith thing wc withs flds)+ = ppr (unLoc thing) <> parens (fsep (punctuate comma+ (ppWiths +++ map (ppr . flLabel . unLoc) flds)))+ where+ ppWiths =+ case wc of+ NoIEWildcard ->+ map (ppr . unLoc) withs+ IEWildcard pos ->+ let (bs, as) = splitAt pos (map (ppr . unLoc) withs)+ in bs ++ [text ".."] ++ as+ ppr (IEModuleContents mod')+ = text "module" <+> ppr mod'+ ppr (IEGroup n _) = text ("<IEGroup: " ++ show n ++ ">")+ ppr (IEDoc doc) = ppr doc+ ppr (IEDocNamed string) = text ("<IEDocNamed: " ++ string ++ ">")++instance (HasOccName name) => HasOccName (IEWrappedName name) where+ occName w = occName (ieWrappedName w)++instance (OutputableBndr name, HasOccName name)+ => OutputableBndr (IEWrappedName name) where+ pprBndr bs w = pprBndr bs (ieWrappedName w)+ pprPrefixOcc w = pprPrefixOcc (ieWrappedName w)+ pprInfixOcc w = pprInfixOcc (ieWrappedName w)++instance (HasOccName name, OutputableBndr name)+ => Outputable (IEWrappedName name) where+ ppr (IEName n) = pprPrefixOcc (unLoc n)+ ppr (IEPattern n) = text "pattern" <+> pprPrefixOcc (unLoc n)+ ppr (IEType n) = text "type" <+> pprPrefixOcc (unLoc n)++pprImpExp :: (HasOccName name, OutputableBndr name) => name -> SDoc+pprImpExp name = type_pref <+> pprPrefixOcc name+ where+ occ = occName name+ type_pref | isTcOcc occ && isSymOcc occ = text "type"+ | otherwise = empty
+ hsSyn/HsLit.hs view
@@ -0,0 +1,216 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[HsLit]{Abstract syntax: source-language literals}+-}++{-# LANGUAGE CPP, DeriveDataTypeable #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}++module HsLit where++#include "HsVersions.h"++import {-# SOURCE #-} HsExpr( HsExpr, pprExpr )+import BasicTypes ( FractionalLit(..),SourceText(..),pprWithSourceText )+import Type ( Type )+import Outputable+import FastString+import PlaceHolder ( PostTc,PostRn,DataId,OutputableBndrId )++import Data.ByteString (ByteString)+import Data.Data hiding ( Fixity )++{-+************************************************************************+* *+\subsection[HsLit]{Literals}+* *+************************************************************************+-}++-- Note [Literal source text] in BasicTypes for SourceText fields in+-- the following+-- | Haskell Literal+data HsLit+ = HsChar SourceText Char+ -- ^ Character+ | HsCharPrim SourceText Char+ -- ^ Unboxed character+ | HsString SourceText FastString+ -- ^ String+ | HsStringPrim SourceText ByteString+ -- ^ Packed bytes+ | HsInt SourceText Integer+ -- ^ Genuinely an Int; arises from+ -- @TcGenDeriv@, and from TRANSLATION+ | HsIntPrim SourceText Integer+ -- ^ literal @Int#@+ | HsWordPrim SourceText Integer+ -- ^ literal @Word#@+ | HsInt64Prim SourceText Integer+ -- ^ literal @Int64#@+ | HsWord64Prim SourceText Integer+ -- ^ literal @Word64#@+ | HsInteger SourceText Integer Type+ -- ^ Genuinely an integer; arises only+ -- from TRANSLATION (overloaded+ -- literals are done with HsOverLit)+ | HsRat FractionalLit Type+ -- ^ Genuinely a rational; arises only from+ -- TRANSLATION (overloaded literals are+ -- done with HsOverLit)+ | HsFloatPrim FractionalLit+ -- ^ Unboxed Float+ | HsDoublePrim FractionalLit+ -- ^ Unboxed Double+ deriving Data++instance Eq HsLit where+ (HsChar _ x1) == (HsChar _ x2) = x1==x2+ (HsCharPrim _ x1) == (HsCharPrim _ x2) = x1==x2+ (HsString _ x1) == (HsString _ x2) = x1==x2+ (HsStringPrim _ x1) == (HsStringPrim _ x2) = x1==x2+ (HsInt _ x1) == (HsInt _ x2) = x1==x2+ (HsIntPrim _ x1) == (HsIntPrim _ x2) = x1==x2+ (HsWordPrim _ x1) == (HsWordPrim _ x2) = x1==x2+ (HsInt64Prim _ x1) == (HsInt64Prim _ x2) = x1==x2+ (HsWord64Prim _ x1) == (HsWord64Prim _ x2) = x1==x2+ (HsInteger _ x1 _) == (HsInteger _ x2 _) = x1==x2+ (HsRat x1 _) == (HsRat x2 _) = x1==x2+ (HsFloatPrim x1) == (HsFloatPrim x2) = x1==x2+ (HsDoublePrim x1) == (HsDoublePrim x2) = x1==x2+ _ == _ = False++-- | Haskell Overloaded Literal+data HsOverLit id+ = OverLit {+ ol_val :: OverLitVal,+ ol_rebindable :: PostRn id Bool, -- Note [ol_rebindable]+ ol_witness :: HsExpr id, -- Note [Overloaded literal witnesses]+ ol_type :: PostTc id Type }+deriving instance (DataId id) => Data (HsOverLit id)++-- Note [Literal source text] in BasicTypes for SourceText fields in+-- the following+-- | Overloaded Literal Value+data OverLitVal+ = HsIntegral !SourceText !Integer -- ^ Integer-looking literals;+ | HsFractional !FractionalLit -- ^ Frac-looking literals+ | HsIsString !SourceText !FastString -- ^ String-looking literals+ deriving Data++overLitType :: HsOverLit a -> PostTc a Type+overLitType = ol_type++{-+Note [ol_rebindable]+~~~~~~~~~~~~~~~~~~~~+The ol_rebindable field is True if this literal is actually+using rebindable syntax. Specifically:++ False iff ol_witness is the standard one+ True iff ol_witness is non-standard++Equivalently it's True if+ a) RebindableSyntax is on+ b) the witness for fromInteger/fromRational/fromString+ that happens to be in scope isn't the standard one++Note [Overloaded literal witnesses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+*Before* type checking, the HsExpr in an HsOverLit is the+name of the coercion function, 'fromInteger' or 'fromRational'.+*After* type checking, it is a witness for the literal, such as+ (fromInteger 3) or lit_78+This witness should replace the literal.++This dual role is unusual, because we're replacing 'fromInteger' with+a call to fromInteger. Reason: it allows commoning up of the fromInteger+calls, which wouldn't be possible if the desguarar made the application.++The PostTcType in each branch records the type the overload literal is+found to have.+-}++-- Comparison operations are needed when grouping literals+-- for compiling pattern-matching (module MatchLit)+instance Eq (HsOverLit id) where+ (OverLit {ol_val = val1}) == (OverLit {ol_val=val2}) = val1 == val2++instance Eq OverLitVal where+ (HsIntegral _ i1) == (HsIntegral _ i2) = i1 == i2+ (HsFractional f1) == (HsFractional f2) = f1 == f2+ (HsIsString _ s1) == (HsIsString _ s2) = s1 == s2+ _ == _ = False++instance Ord (HsOverLit id) where+ compare (OverLit {ol_val=val1}) (OverLit {ol_val=val2}) = val1 `compare` val2++instance Ord OverLitVal where+ compare (HsIntegral _ i1) (HsIntegral _ i2) = i1 `compare` i2+ compare (HsIntegral _ _) (HsFractional _) = LT+ compare (HsIntegral _ _) (HsIsString _ _) = LT+ compare (HsFractional f1) (HsFractional f2) = f1 `compare` f2+ compare (HsFractional _) (HsIntegral _ _) = GT+ compare (HsFractional _) (HsIsString _ _) = LT+ compare (HsIsString _ s1) (HsIsString _ s2) = s1 `compare` s2+ compare (HsIsString _ _) (HsIntegral _ _) = GT+ compare (HsIsString _ _) (HsFractional _) = GT++instance Outputable HsLit where+ ppr (HsChar st c) = pprWithSourceText st (pprHsChar c)+ ppr (HsCharPrim st c) = pp_st_suffix st primCharSuffix (pprPrimChar c)+ ppr (HsString st s) = pprWithSourceText st (pprHsString s)+ ppr (HsStringPrim st s) = pprWithSourceText st (pprHsBytes s)+ ppr (HsInt st i) = pprWithSourceText st (integer i)+ ppr (HsInteger st i _) = pprWithSourceText st (integer i)+ ppr (HsRat f _) = ppr f+ ppr (HsFloatPrim f) = ppr f <> primFloatSuffix+ ppr (HsDoublePrim d) = ppr d <> primDoubleSuffix+ ppr (HsIntPrim st i) = pprWithSourceText st (pprPrimInt i)+ ppr (HsWordPrim st w) = pprWithSourceText st (pprPrimWord w)+ ppr (HsInt64Prim st i) = pp_st_suffix st primInt64Suffix (pprPrimInt64 i)+ ppr (HsWord64Prim st w) = pp_st_suffix st primWord64Suffix (pprPrimWord64 w)++pp_st_suffix :: SourceText -> SDoc -> SDoc -> SDoc+pp_st_suffix NoSourceText _ doc = doc+pp_st_suffix (SourceText st) suffix _ = text st <> suffix++-- in debug mode, print the expression that it's resolved to, too+instance (OutputableBndrId id) => Outputable (HsOverLit id) where+ ppr (OverLit {ol_val=val, ol_witness=witness})+ = ppr val <+> (ifPprDebug (parens (pprExpr witness)))++instance Outputable OverLitVal where+ ppr (HsIntegral st i) = pprWithSourceText st (integer i)+ ppr (HsFractional f) = ppr f+ ppr (HsIsString st s) = pprWithSourceText st (pprHsString s)++-- | pmPprHsLit pretty prints literals and is used when pretty printing pattern+-- match warnings. All are printed the same (i.e., without hashes if they are+-- primitive and not wrapped in constructors if they are boxed). This happens+-- mainly for too reasons:+-- * We do not want to expose their internal representation+-- * The warnings become too messy+pmPprHsLit :: HsLit -> SDoc+pmPprHsLit (HsChar _ c) = pprHsChar c+pmPprHsLit (HsCharPrim _ c) = pprHsChar c+pmPprHsLit (HsString st s) = pprWithSourceText st (pprHsString s)+pmPprHsLit (HsStringPrim _ s) = pprHsBytes s+pmPprHsLit (HsInt _ i) = integer i+pmPprHsLit (HsIntPrim _ i) = integer i+pmPprHsLit (HsWordPrim _ w) = integer w+pmPprHsLit (HsInt64Prim _ i) = integer i+pmPprHsLit (HsWord64Prim _ w) = integer w+pmPprHsLit (HsInteger _ i _) = integer i+pmPprHsLit (HsRat f _) = ppr f+pmPprHsLit (HsFloatPrim f) = ppr f+pmPprHsLit (HsDoublePrim d) = ppr d
+ hsSyn/HsPat.hs view
@@ -0,0 +1,698 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[PatSyntax]{Abstract Haskell syntax---patterns}+-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE TypeFamilies #-}++module HsPat (+ Pat(..), InPat, OutPat, LPat,++ HsConPatDetails, hsConPatArgs,+ HsRecFields(..), HsRecField'(..), LHsRecField',+ HsRecField, LHsRecField,+ HsRecUpdField, LHsRecUpdField,+ hsRecFields, hsRecFieldSel, hsRecFieldId, hsRecFieldsArgs,+ hsRecUpdFieldId, hsRecUpdFieldOcc, hsRecUpdFieldRdr,++ mkPrefixConPat, mkCharLitPat, mkNilPat,++ looksLazyPatBind,+ isBangedLPat, isBangedPatBind,+ hsPatNeedsParens,+ isIrrefutableHsPat,++ collectEvVarsPats,++ pprParendLPat, pprConArgs+ ) where++import {-# SOURCE #-} HsExpr (SyntaxExpr, LHsExpr, HsSplice, pprLExpr, pprSplice)++-- friends:+import HsBinds+import HsLit+import PlaceHolder+import HsTypes+import TcEvidence+import BasicTypes+-- others:+import PprCore ( {- instance OutputableBndr TyVar -} )+import TysWiredIn+import Var+import RdrName ( RdrName )+import ConLike+import DataCon+import TyCon+import Outputable+import Type+import SrcLoc+import Bag -- collect ev vars from pats+import DynFlags( gopt, GeneralFlag(..) )+import Maybes+-- libraries:+import Data.Data hiding (TyCon,Fixity)++type InPat id = LPat id -- No 'Out' constructors+type OutPat id = LPat id -- No 'In' constructors++type LPat id = Located (Pat id)++-- | Pattern+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnBang'++-- For details on above see note [Api annotations] in ApiAnnotation+data Pat id+ = ------------ Simple patterns ---------------+ WildPat (PostTc id Type) -- ^ Wildcard Pattern+ -- The sole reason for a type on a WildPat is to+ -- support hsPatType :: Pat Id -> Type++ | VarPat (Located id) -- ^ Variable Pattern++ -- See Note [Located RdrNames] in HsExpr+ | LazyPat (LPat id) -- ^ Lazy Pattern+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnTilde'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | AsPat (Located id) (LPat id) -- ^ As pattern+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnAt'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | ParPat (LPat id) -- ^ Parenthesised pattern+ -- See Note [Parens in HsSyn] in HsExpr+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'('@,+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | BangPat (LPat id) -- ^ Bang pattern+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnBang'++ -- For details on above see note [Api annotations] in ApiAnnotation++ ------------ Lists, tuples, arrays ---------------+ | ListPat [LPat id]+ (PostTc id Type) -- The type of the elements+ (Maybe (PostTc id Type, SyntaxExpr id)) -- For rebindable syntax+ -- For OverloadedLists a Just (ty,fn) gives+ -- overall type of the pattern, and the toList+ -- function to convert the scrutinee to a list value+ -- ^ Syntactic List+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'['@,+ -- 'ApiAnnotation.AnnClose' @']'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | TuplePat [LPat id] -- Tuple sub-patterns+ Boxity -- UnitPat is TuplePat []+ [PostTc id Type] -- [] before typechecker, filled in afterwards+ -- with the types of the tuple components+ -- You might think that the PostTc id Type was redundant, because we can+ -- get the pattern type by getting the types of the sub-patterns.+ -- But it's essential+ -- data T a where+ -- T1 :: Int -> T Int+ -- f :: (T a, a) -> Int+ -- f (T1 x, z) = z+ -- When desugaring, we must generate+ -- f = /\a. \v::a. case v of (t::T a, w::a) ->+ -- case t of (T1 (x::Int)) ->+ -- Note the (w::a), NOT (w::Int), because we have not yet+ -- refined 'a' to Int. So we must know that the second component+ -- of the tuple is of type 'a' not Int. See selectMatchVar+ -- (June 14: I'm not sure this comment is right; the sub-patterns+ -- will be wrapped in CoPats, no?)+ -- ^ Tuple sub-patterns+ --+ -- - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpen' @'('@ or @'(#'@,+ -- 'ApiAnnotation.AnnClose' @')'@ or @'#)'@++ | SumPat (LPat id) -- Sum sub-pattern+ ConTag -- Alternative (one-based)+ Arity -- Arity+ (PostTc id [Type]) -- PlaceHolder before typechecker, filled in+ -- afterwards with the types of the+ -- alternative+ -- ^ Anonymous sum pattern+ --+ -- - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpen' @'(#'@,+ -- 'ApiAnnotation.AnnClose' @'#)'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | PArrPat [LPat id] -- Syntactic parallel array+ (PostTc id Type) -- The type of the elements+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'[:'@,+ -- 'ApiAnnotation.AnnClose' @':]'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ ------------ Constructor patterns ---------------+ | ConPatIn (Located id)+ (HsConPatDetails id)+ -- ^ Constructor Pattern In++ | ConPatOut {+ pat_con :: Located ConLike,+ pat_arg_tys :: [Type], -- The universal arg types, 1-1 with the universal+ -- tyvars of the constructor/pattern synonym+ -- Use (conLikeResTy pat_con pat_arg_tys) to get+ -- the type of the pattern++ pat_tvs :: [TyVar], -- Existentially bound type variables+ -- in correctly-scoped order e.g. [k:*, x:k]+ pat_dicts :: [EvVar], -- Ditto *coercion variables* and *dictionaries*+ -- One reason for putting coercion variable here, I think,+ -- is to ensure their kinds are zonked++ pat_binds :: TcEvBinds, -- Bindings involving those dictionaries+ pat_args :: HsConPatDetails id,+ pat_wrap :: HsWrapper -- Extra wrapper to pass to the matcher+ -- Only relevant for pattern-synonyms;+ -- ignored for data cons+ }+ -- ^ Constructor Pattern Out++ ------------ View patterns ---------------+ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnRarrow'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | ViewPat (LHsExpr id)+ (LPat id)+ (PostTc id Type) -- The overall type of the pattern+ -- (= the argument type of the view function)+ -- for hsPatType.+ -- ^ View Pattern++ ------------ Pattern splices ---------------+ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'$('@+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | SplicePat (HsSplice id) -- ^ Splice Pattern (Includes quasi-quotes)++ ------------ Literal and n+k patterns ---------------+ | LitPat HsLit -- ^ Literal Pattern+ -- Used for *non-overloaded* literal patterns:+ -- Int#, Char#, Int, Char, String, etc.++ | NPat -- Natural Pattern+ -- Used for all overloaded literals,+ -- including overloaded strings with -XOverloadedStrings+ (Located (HsOverLit id)) -- ALWAYS positive+ (Maybe (SyntaxExpr id)) -- Just (Name of 'negate') for negative+ -- patterns, Nothing otherwise+ (SyntaxExpr id) -- Equality checker, of type t->t->Bool+ (PostTc id Type) -- Overall type of pattern. Might be+ -- different than the literal's type+ -- if (==) or negate changes the type++ -- ^ Natural Pattern+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnVal' @'+'@++ -- For details on above see note [Api annotations] in ApiAnnotation+ | NPlusKPat (Located id) -- n+k pattern+ (Located (HsOverLit id)) -- It'll always be an HsIntegral+ (HsOverLit id) -- See Note [NPlusK patterns] in TcPat+ -- NB: This could be (PostTc ...), but that induced a+ -- a new hs-boot file. Not worth it.++ (SyntaxExpr id) -- (>=) function, of type t1->t2->Bool+ (SyntaxExpr id) -- Name of '-' (see RnEnv.lookupSyntaxName)+ (PostTc id Type) -- Type of overall pattern+ -- ^ n+k pattern++ ------------ Pattern type signatures ---------------+ -- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation+ | SigPatIn (LPat id) -- Pattern with a type signature+ (LHsSigWcType id) -- Signature can bind both+ -- kind and type vars+ -- ^ Pattern with a type signature++ | SigPatOut (LPat id)+ Type+ -- ^ Pattern with a type signature++ ------------ Pattern coercions (translation only) ---------------+ | CoPat HsWrapper -- Coercion Pattern+ -- If co :: t1 ~ t2, p :: t2,+ -- then (CoPat co p) :: t1+ (Pat id) -- Why not LPat? Ans: existing locn will do+ Type -- Type of whole pattern, t1+ -- During desugaring a (CoPat co pat) turns into a cast with 'co' on+ -- the scrutinee, followed by a match on 'pat'+ -- ^ Coercion Pattern+deriving instance (DataId id) => Data (Pat id)++-- | Haskell Constructor Pattern Details+type HsConPatDetails id = HsConDetails (LPat id) (HsRecFields id (LPat id))++hsConPatArgs :: HsConPatDetails id -> [LPat id]+hsConPatArgs (PrefixCon ps) = ps+hsConPatArgs (RecCon fs) = map (hsRecFieldArg . unLoc) (rec_flds fs)+hsConPatArgs (InfixCon p1 p2) = [p1,p2]++-- | Haskell Record Fields+--+-- HsRecFields is used only for patterns and expressions (not data type+-- declarations)+data HsRecFields id arg -- A bunch of record fields+ -- { x = 3, y = True }+ -- Used for both expressions and patterns+ = HsRecFields { rec_flds :: [LHsRecField id arg],+ rec_dotdot :: Maybe Int } -- Note [DotDot fields]+ deriving (Functor, Foldable, Traversable)+deriving instance (DataId id, Data arg) => Data (HsRecFields id arg)+++-- Note [DotDot fields]+-- ~~~~~~~~~~~~~~~~~~~~+-- The rec_dotdot field means this:+-- Nothing => the normal case+-- Just n => the group uses ".." notation,+--+-- In the latter case:+--+-- *before* renamer: rec_flds are exactly the n user-written fields+--+-- *after* renamer: rec_flds includes *all* fields, with+-- the first 'n' being the user-written ones+-- and the remainder being 'filled in' implicitly++-- | Located Haskell Record Field+type LHsRecField' id arg = Located (HsRecField' id arg)++-- | Located Haskell Record Field+type LHsRecField id arg = Located (HsRecField id arg)++-- | Located Haskell Record Update Field+type LHsRecUpdField id = Located (HsRecUpdField id)++-- | Haskell Record Field+type HsRecField id arg = HsRecField' (FieldOcc id) arg++-- | Haskell Record Update Field+type HsRecUpdField id = HsRecField' (AmbiguousFieldOcc id) (LHsExpr id)++-- | Haskell Record Field+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnEqual',+--+-- For details on above see note [Api annotations] in ApiAnnotation+data HsRecField' id arg = HsRecField {+ hsRecFieldLbl :: Located id,+ hsRecFieldArg :: arg, -- ^ Filled in by renamer when punning+ hsRecPun :: Bool -- ^ Note [Punning]+ } deriving (Data, Functor, Foldable, Traversable)+++-- Note [Punning]+-- ~~~~~~~~~~~~~~+-- If you write T { x, y = v+1 }, the HsRecFields will be+-- HsRecField x x True ...+-- HsRecField y (v+1) False ...+-- That is, for "punned" field x is expanded (in the renamer)+-- to x=x; but with a punning flag so we can detect it later+-- (e.g. when pretty printing)+--+-- If the original field was qualified, we un-qualify it, thus+-- T { A.x } means T { A.x = x }+++-- Note [HsRecField and HsRecUpdField]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++-- A HsRecField (used for record construction and pattern matching)+-- contains an unambiguous occurrence of a field (i.e. a FieldOcc).+-- We can't just store the Name, because thanks to+-- DuplicateRecordFields this may not correspond to the label the user+-- wrote.+--+-- A HsRecUpdField (used for record update) contains a potentially+-- ambiguous occurrence of a field (an AmbiguousFieldOcc). The+-- renamer will fill in the selector function if it can, but if the+-- selector is ambiguous the renamer will defer to the typechecker.+-- After the typechecker, a unique selector will have been determined.+--+-- The renamer produces an Unambiguous result if it can, rather than+-- just doing the lookup in the typechecker, so that completely+-- unambiguous updates can be represented by 'DsMeta.repUpdFields'.+--+-- For example, suppose we have:+--+-- data S = MkS { x :: Int }+-- data T = MkT { x :: Int }+--+-- f z = (z { x = 3 }) :: S+--+-- The parsed HsRecUpdField corresponding to the record update will have:+--+-- hsRecFieldLbl = Unambiguous "x" PlaceHolder :: AmbiguousFieldOcc RdrName+--+-- After the renamer, this will become:+--+-- hsRecFieldLbl = Ambiguous "x" PlaceHolder :: AmbiguousFieldOcc Name+--+-- (note that the Unambiguous constructor is not type-correct here).+-- The typechecker will determine the particular selector:+--+-- hsRecFieldLbl = Unambiguous "x" $sel:x:MkS :: AmbiguousFieldOcc Id+--+-- See also Note [Disambiguating record fields] in TcExpr.++hsRecFields :: HsRecFields id arg -> [PostRn id id]+hsRecFields rbinds = map (unLoc . hsRecFieldSel . unLoc) (rec_flds rbinds)++-- Probably won't typecheck at once, things have changed :/+hsRecFieldsArgs :: HsRecFields id arg -> [arg]+hsRecFieldsArgs rbinds = map (hsRecFieldArg . unLoc) (rec_flds rbinds)++hsRecFieldSel :: HsRecField name arg -> Located (PostRn name name)+hsRecFieldSel = fmap selectorFieldOcc . hsRecFieldLbl++hsRecFieldId :: HsRecField Id arg -> Located Id+hsRecFieldId = hsRecFieldSel++hsRecUpdFieldRdr :: HsRecUpdField id -> Located RdrName+hsRecUpdFieldRdr = fmap rdrNameAmbiguousFieldOcc . hsRecFieldLbl++hsRecUpdFieldId :: HsRecField' (AmbiguousFieldOcc Id) arg -> Located Id+hsRecUpdFieldId = fmap selectorFieldOcc . hsRecUpdFieldOcc++hsRecUpdFieldOcc :: HsRecField' (AmbiguousFieldOcc Id) arg -> LFieldOcc Id+hsRecUpdFieldOcc = fmap unambiguousFieldOcc . hsRecFieldLbl+++{-+************************************************************************+* *+* Printing patterns+* *+************************************************************************+-}++instance (OutputableBndrId name) => Outputable (Pat name) where+ ppr = pprPat++pprPatBndr :: OutputableBndr name => name -> SDoc+pprPatBndr var -- Print with type info if -dppr-debug is on+ = getPprStyle $ \ sty ->+ if debugStyle sty then+ parens (pprBndr LambdaBind var) -- Could pass the site to pprPat+ -- but is it worth it?+ else+ pprPrefixOcc var++pprParendLPat :: (OutputableBndrId name) => LPat name -> SDoc+pprParendLPat (L _ p) = pprParendPat p++pprParendPat :: (OutputableBndrId name) => Pat name -> SDoc+pprParendPat p = sdocWithDynFlags $ \ dflags ->+ if need_parens dflags p+ then parens (pprPat p)+ else pprPat p+ where+ need_parens dflags p+ | CoPat {} <- p = gopt Opt_PrintTypecheckerElaboration dflags+ | otherwise = hsPatNeedsParens p+ -- For a CoPat we need parens if we are going to show it, which+ -- we do if -fprint-typechecker-elaboration is on (c.f. pprHsWrapper)+ -- But otherwise the CoPat is discarded, so it+ -- is the pattern inside that matters. Sigh.++pprPat :: (OutputableBndrId name) => Pat name -> SDoc+pprPat (VarPat (L _ var)) = pprPatBndr var+pprPat (WildPat _) = char '_'+pprPat (LazyPat pat) = char '~' <> pprParendLPat pat+pprPat (BangPat pat) = char '!' <> pprParendLPat pat+pprPat (AsPat name pat) = hcat [pprPrefixOcc (unLoc name), char '@', pprParendLPat pat]+pprPat (ViewPat expr pat _) = hcat [pprLExpr expr, text " -> ", ppr pat]+pprPat (ParPat pat) = parens (ppr pat)+pprPat (LitPat s) = ppr s+pprPat (NPat l Nothing _ _) = ppr l+pprPat (NPat l (Just _) _ _) = char '-' <> ppr l+pprPat (NPlusKPat n k _ _ _ _)= hcat [ppr n, char '+', ppr k]+pprPat (SplicePat splice) = pprSplice splice+pprPat (CoPat co pat _) = pprHsWrapper co (\parens -> if parens+ then pprParendPat pat+ else pprPat pat)+pprPat (SigPatIn pat ty) = ppr pat <+> dcolon <+> ppr ty+pprPat (SigPatOut pat ty) = ppr pat <+> dcolon <+> ppr ty+pprPat (ListPat pats _ _) = brackets (interpp'SP pats)+pprPat (PArrPat pats _) = paBrackets (interpp'SP pats)+pprPat (TuplePat pats bx _) = tupleParens (boxityTupleSort bx) (pprWithCommas ppr pats)+pprPat (SumPat pat alt arity _) = sumParens (pprAlternative ppr pat alt arity)+pprPat (ConPatIn con details) = pprUserCon (unLoc con) details+pprPat (ConPatOut { pat_con = con, pat_tvs = tvs, pat_dicts = dicts,+ pat_binds = binds, pat_args = details })+ = sdocWithDynFlags $ \dflags ->+ -- Tiresome; in TcBinds.tcRhs we print out a+ -- typechecked Pat in an error message,+ -- and we want to make sure it prints nicely+ if gopt Opt_PrintTypecheckerElaboration dflags then+ ppr con+ <> braces (sep [ hsep (map pprPatBndr (tvs ++ dicts))+ , ppr binds])+ <+> pprConArgs details+ else pprUserCon (unLoc con) details+++pprUserCon :: (OutputableBndr con, OutputableBndrId id)+ => con -> HsConPatDetails id -> SDoc+pprUserCon c (InfixCon p1 p2) = ppr p1 <+> pprInfixOcc c <+> ppr p2+pprUserCon c details = pprPrefixOcc c <+> pprConArgs details++pprConArgs :: (OutputableBndrId id) => HsConPatDetails id -> SDoc+pprConArgs (PrefixCon pats) = sep (map pprParendLPat pats)+pprConArgs (InfixCon p1 p2) = sep [pprParendLPat p1, pprParendLPat p2]+pprConArgs (RecCon rpats) = ppr rpats++instance (Outputable arg)+ => Outputable (HsRecFields id arg) where+ ppr (HsRecFields { rec_flds = flds, rec_dotdot = Nothing })+ = braces (fsep (punctuate comma (map ppr flds)))+ ppr (HsRecFields { rec_flds = flds, rec_dotdot = Just n })+ = braces (fsep (punctuate comma (map ppr (take n flds) ++ [dotdot])))+ where+ dotdot = text ".." <+> ifPprDebug (ppr (drop n flds))++instance (Outputable id, Outputable arg)+ => Outputable (HsRecField' id arg) where+ ppr (HsRecField { hsRecFieldLbl = f, hsRecFieldArg = arg,+ hsRecPun = pun })+ = ppr f <+> (ppUnless pun $ equals <+> ppr arg)+++{-+************************************************************************+* *+* Building patterns+* *+************************************************************************+-}++mkPrefixConPat :: DataCon -> [OutPat id] -> [Type] -> OutPat id+-- Make a vanilla Prefix constructor pattern+mkPrefixConPat dc pats tys+ = noLoc $ ConPatOut { pat_con = noLoc (RealDataCon dc), pat_tvs = [], pat_dicts = [],+ pat_binds = emptyTcEvBinds, pat_args = PrefixCon pats,+ pat_arg_tys = tys, pat_wrap = idHsWrapper }++mkNilPat :: Type -> OutPat id+mkNilPat ty = mkPrefixConPat nilDataCon [] [ty]++mkCharLitPat :: SourceText -> Char -> OutPat id+mkCharLitPat src c = mkPrefixConPat charDataCon+ [noLoc $ LitPat (HsCharPrim src c)] []++{-+************************************************************************+* *+* Predicates for checking things about pattern-lists in EquationInfo *+* *+************************************************************************++\subsection[Pat-list-predicates]{Look for interesting things in patterns}++Unlike in the Wadler chapter, where patterns are either ``variables''+or ``constructors,'' here we distinguish between:+\begin{description}+\item[unfailable:]+Patterns that cannot fail to match: variables, wildcards, and lazy+patterns.++These are the irrefutable patterns; the two other categories+are refutable patterns.++\item[constructor:]+A non-literal constructor pattern (see next category).++\item[literal patterns:]+At least the numeric ones may be overloaded.+\end{description}++A pattern is in {\em exactly one} of the above three categories; `as'+patterns are treated specially, of course.++The 1.3 report defines what ``irrefutable'' and ``failure-free'' patterns are.+-}++isBangedPatBind :: HsBind id -> Bool+isBangedPatBind (PatBind {pat_lhs = pat}) = isBangedLPat pat+isBangedPatBind _ = False++isBangedLPat :: LPat id -> Bool+isBangedLPat (L _ (ParPat p)) = isBangedLPat p+isBangedLPat (L _ (BangPat {})) = True+isBangedLPat _ = False++looksLazyPatBind :: HsBind id -> Bool+-- Returns True of anything *except*+-- a StrictHsBind (as above) or+-- a VarPat+-- In particular, returns True of a pattern binding with a compound pattern, like (I# x)+-- Looks through AbsBinds+looksLazyPatBind (PatBind { pat_lhs = p })+ = looksLazyLPat p+looksLazyPatBind (AbsBinds { abs_binds = binds })+ = anyBag (looksLazyPatBind . unLoc) binds+looksLazyPatBind (AbsBindsSig { abs_sig_bind = L _ bind })+ = looksLazyPatBind bind+looksLazyPatBind _+ = False++looksLazyLPat :: LPat id -> Bool+looksLazyLPat (L _ (ParPat p)) = looksLazyLPat p+looksLazyLPat (L _ (AsPat _ p)) = looksLazyLPat p+looksLazyLPat (L _ (BangPat {})) = False+looksLazyLPat (L _ (VarPat {})) = False+looksLazyLPat (L _ (WildPat {})) = False+looksLazyLPat _ = True++isIrrefutableHsPat :: (OutputableBndrId id) => LPat id -> Bool+-- (isIrrefutableHsPat p) is true if matching against p cannot fail,+-- in the sense of falling through to the next pattern.+-- (NB: this is not quite the same as the (silly) defn+-- in 3.17.2 of the Haskell 98 report.)+--+-- WARNING: isIrrefutableHsPat returns False if it's in doubt.+-- Specifically on a ConPatIn, which is what it sees for a+-- (LPat Name) in the renamer, it doesn't know the size of the+-- constructor family, so it returns False. Result: only+-- tuple patterns are considered irrefuable at the renamer stage.+--+-- But if it returns True, the pattern is definitely irrefutable+isIrrefutableHsPat pat+ = go pat+ where+ go (L _ pat) = go1 pat++ go1 (WildPat {}) = True+ go1 (VarPat {}) = True+ go1 (LazyPat {}) = True+ go1 (BangPat pat) = go pat+ go1 (CoPat _ pat _) = go1 pat+ go1 (ParPat pat) = go pat+ go1 (AsPat _ pat) = go pat+ go1 (ViewPat _ pat _) = go pat+ go1 (SigPatIn pat _) = go pat+ go1 (SigPatOut pat _) = go pat+ go1 (TuplePat pats _ _) = all go pats+ go1 (SumPat pat _ _ _) = go pat+ go1 (ListPat {}) = False+ go1 (PArrPat {}) = False -- ?++ go1 (ConPatIn {}) = False -- Conservative+ go1 (ConPatOut{ pat_con = L _ (RealDataCon con), pat_args = details })+ = isJust (tyConSingleDataCon_maybe (dataConTyCon con))+ -- NB: tyConSingleDataCon_maybe, *not* isProductTyCon, because+ -- the latter is false of existentials. See Trac #4439+ && all go (hsConPatArgs details)+ go1 (ConPatOut{ pat_con = L _ (PatSynCon _pat) })+ = False -- Conservative++ go1 (LitPat {}) = False+ go1 (NPat {}) = False+ go1 (NPlusKPat {}) = False++ -- We conservatively assume that no TH splices are irrefutable+ -- since we cannot know until the splice is evaluated.+ go1 (SplicePat {}) = False++hsPatNeedsParens :: Pat a -> Bool+hsPatNeedsParens (NPlusKPat {}) = True+hsPatNeedsParens (SplicePat {}) = False+hsPatNeedsParens (ConPatIn _ ds) = conPatNeedsParens ds+hsPatNeedsParens p@(ConPatOut {}) = conPatNeedsParens (pat_args p)+hsPatNeedsParens (SigPatIn {}) = True+hsPatNeedsParens (SigPatOut {}) = True+hsPatNeedsParens (ViewPat {}) = True+hsPatNeedsParens (CoPat _ p _) = hsPatNeedsParens p+hsPatNeedsParens (WildPat {}) = False+hsPatNeedsParens (VarPat {}) = False+hsPatNeedsParens (LazyPat {}) = False+hsPatNeedsParens (BangPat {}) = False+hsPatNeedsParens (ParPat {}) = False+hsPatNeedsParens (AsPat {}) = False+hsPatNeedsParens (TuplePat {}) = False+hsPatNeedsParens (SumPat {}) = False+hsPatNeedsParens (ListPat {}) = False+hsPatNeedsParens (PArrPat {}) = False+hsPatNeedsParens (LitPat {}) = False+hsPatNeedsParens (NPat {}) = False++conPatNeedsParens :: HsConDetails a b -> Bool+conPatNeedsParens (PrefixCon {}) = False+conPatNeedsParens (InfixCon {}) = True+conPatNeedsParens (RecCon {}) = False++{-+% Collect all EvVars from all constructor patterns+-}++-- May need to add more cases+collectEvVarsPats :: [Pat id] -> Bag EvVar+collectEvVarsPats = unionManyBags . map collectEvVarsPat++collectEvVarsLPat :: LPat id -> Bag EvVar+collectEvVarsLPat (L _ pat) = collectEvVarsPat pat++collectEvVarsPat :: Pat id -> Bag EvVar+collectEvVarsPat pat =+ case pat of+ LazyPat p -> collectEvVarsLPat p+ AsPat _ p -> collectEvVarsLPat p+ ParPat p -> collectEvVarsLPat p+ BangPat p -> collectEvVarsLPat p+ ListPat ps _ _ -> unionManyBags $ map collectEvVarsLPat ps+ TuplePat ps _ _ -> unionManyBags $ map collectEvVarsLPat ps+ SumPat p _ _ _ -> collectEvVarsLPat p+ PArrPat ps _ -> unionManyBags $ map collectEvVarsLPat ps+ ConPatOut {pat_dicts = dicts, pat_args = args}+ -> unionBags (listToBag dicts)+ $ unionManyBags+ $ map collectEvVarsLPat+ $ hsConPatArgs args+ SigPatOut p _ -> collectEvVarsLPat p+ CoPat _ p _ -> collectEvVarsPat p+ ConPatIn _ _ -> panic "foldMapPatBag: ConPatIn"+ SigPatIn _ _ -> panic "foldMapPatBag: SigPatIn"+ _other_pat -> emptyBag
+ hsSyn/HsPat.hs-boot view
@@ -0,0 +1,20 @@+{-# LANGUAGE CPP, KindSignatures #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE RoleAnnotations #-}++module HsPat where+import SrcLoc( Located )++import Data.Data hiding (Fixity)+import Outputable+import PlaceHolder ( DataId, OutputableBndrId )++type role Pat nominal+data Pat (i :: *)+type LPat i = Located (Pat i)++instance (DataId id) => Data (Pat id)+instance (OutputableBndrId name) => Outputable (Pat name)
+ hsSyn/HsSyn.hs view
@@ -0,0 +1,145 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section{Haskell abstract syntax definition}++This module glues together the pieces of the Haskell abstract syntax,+which is declared in the various \tr{Hs*} modules. This module,+therefore, is almost nothing but re-exporting.+-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}++module HsSyn (+ module HsBinds,+ module HsDecls,+ module HsExpr,+ module HsImpExp,+ module HsLit,+ module HsPat,+ module HsTypes,+ module HsUtils,+ module HsDoc,+ module PlaceHolder,+ Fixity,++ HsModule(..)+) where++-- friends:+import HsDecls+import HsBinds+import HsExpr+import HsImpExp+import HsLit+import PlaceHolder+import HsPat+import HsTypes+import BasicTypes ( Fixity, WarningTxt )+import HsUtils+import HsDoc+import OccName ( HasOccName(..) )++-- others:+import Outputable+import SrcLoc+import Module ( ModuleName )++-- libraries:+import Data.Data hiding ( Fixity )++-- | Haskell Module+--+-- All we actually declare here is the top-level structure for a module.+data HsModule name+ = HsModule {+ hsmodName :: Maybe (Located ModuleName),+ -- ^ @Nothing@: \"module X where\" is omitted (in which case the next+ -- field is Nothing too)+ hsmodExports :: Maybe (Located [LIE name]),+ -- ^ Export list+ --+ -- - @Nothing@: export list omitted, so export everything+ --+ -- - @Just []@: export /nothing/+ --+ -- - @Just [...]@: as you would expect...+ --+ --+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnOpen'+ -- ,'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ hsmodImports :: [LImportDecl name],+ -- ^ We snaffle interesting stuff out of the imported interfaces early+ -- on, adding that info to TyDecls/etc; so this list is often empty,+ -- downstream.+ hsmodDecls :: [LHsDecl name],+ -- ^ Type, class, value, and interface signature decls+ hsmodDeprecMessage :: Maybe (Located WarningTxt),+ -- ^ reason\/explanation for warning/deprecation of this module+ --+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnOpen'+ -- ,'ApiAnnotation.AnnClose'+ --++ -- For details on above see note [Api annotations] in ApiAnnotation+ hsmodHaddockModHeader :: Maybe LHsDocString+ -- ^ Haddock module info and description, unparsed+ --+ -- - 'ApiAnnotation.AnnKeywordId's : 'ApiAnnotation.AnnOpen'+ -- ,'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+ }+ -- ^ 'ApiAnnotation.AnnKeywordId's+ --+ -- - 'ApiAnnotation.AnnModule','ApiAnnotation.AnnWhere'+ --+ -- - 'ApiAnnotation.AnnOpen','ApiAnnotation.AnnSemi',+ -- 'ApiAnnotation.AnnClose' for explicit braces and semi around+ -- hsmodImports,hsmodDecls if this style is used.++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (HsModule name)++instance (OutputableBndrId name, HasOccName name)+ => Outputable (HsModule name) where++ ppr (HsModule Nothing _ imports decls _ mbDoc)+ = pp_mb mbDoc $$ pp_nonnull imports+ $$ pp_nonnull decls++ ppr (HsModule (Just name) exports imports decls deprec mbDoc)+ = vcat [+ pp_mb mbDoc,+ case exports of+ Nothing -> pp_header (text "where")+ Just es -> vcat [+ pp_header lparen,+ nest 8 (fsep (punctuate comma (map ppr (unLoc es)))),+ nest 4 (text ") where")+ ],+ pp_nonnull imports,+ pp_nonnull decls+ ]+ where+ pp_header rest = case deprec of+ Nothing -> pp_modname <+> rest+ Just d -> vcat [ pp_modname, ppr d, rest ]++ pp_modname = text "module" <+> ppr name++pp_mb :: Outputable t => Maybe t -> SDoc+pp_mb (Just x) = ppr x+pp_mb Nothing = empty++pp_nonnull :: Outputable t => [t] -> SDoc+pp_nonnull [] = empty+pp_nonnull xs = vcat (map ppr xs)
+ hsSyn/HsTypes.hs view
@@ -0,0 +1,1349 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++HsTypes: Abstract syntax: user-defined types+-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE CPP #-}++module HsTypes (+ HsType(..), LHsType, HsKind, LHsKind,+ HsTyVarBndr(..), LHsTyVarBndr,+ LHsQTyVars(..),+ HsImplicitBndrs(..),+ HsWildCardBndrs(..),+ LHsSigType, LHsSigWcType, LHsWcType,+ HsTupleSort(..),+ Promoted(..),+ HsContext, LHsContext,+ HsTyLit(..),+ HsIPName(..), hsIPNameFS,+ HsAppType(..),LHsAppType,++ LBangType, BangType,+ HsSrcBang(..), HsImplBang(..),+ SrcStrictness(..), SrcUnpackedness(..),+ getBangType, getBangStrictness,++ ConDeclField(..), LConDeclField, pprConDeclFields, updateGadtResult,++ HsConDetails(..),++ FieldOcc(..), LFieldOcc, mkFieldOcc,+ AmbiguousFieldOcc(..), mkAmbiguousFieldOcc,+ rdrNameAmbiguousFieldOcc, selectorAmbiguousFieldOcc,+ unambiguousFieldOcc, ambiguousFieldOcc,++ HsWildCardInfo(..), mkAnonWildCardTy,+ wildCardName, sameWildCard,++ mkHsImplicitBndrs, mkHsWildCardBndrs, hsImplicitBody,+ mkEmptyImplicitBndrs, mkEmptyWildCardBndrs,+ mkHsQTvs, hsQTvExplicit, emptyLHsQTvs, isEmptyLHsQTvs,+ isHsKindedTyVar, hsTvbAllKinded,+ hsScopedTvs, hsWcScopedTvs, dropWildCards,+ hsTyVarName, hsAllLTyVarNames, hsLTyVarLocNames,+ hsLTyVarName, hsLTyVarLocName, hsExplicitLTyVarNames,+ splitLHsInstDeclTy, getLHsInstDeclHead, getLHsInstDeclClass_maybe,+ splitLHsPatSynTy,+ splitLHsForAllTy, splitLHsQualTy, splitLHsSigmaTy,+ splitHsFunType, splitHsAppsTy,+ splitHsAppTys, getAppsTyHead_maybe, hsTyGetAppHead_maybe,+ mkHsOpTy, mkHsAppTy, mkHsAppTys,+ ignoreParens, hsSigType, hsSigWcType,+ hsLTyVarBndrToType, hsLTyVarBndrsToTypes,++ -- Printing+ pprParendHsType, pprHsForAll, pprHsForAllTvs, pprHsForAllExtra,+ pprHsContext, pprHsContextNoArrow, pprHsContextMaybe+ ) where++import {-# SOURCE #-} HsExpr ( HsSplice, pprSplice )++import PlaceHolder ( PostTc,PostRn,DataId,PlaceHolder(..),+ OutputableBndrId )++import Id ( Id )+import Name( Name )+import RdrName ( RdrName )+import NameSet ( NameSet, emptyNameSet )+import DataCon( HsSrcBang(..), HsImplBang(..),+ SrcStrictness(..), SrcUnpackedness(..) )+import TysPrim( funTyConName )+import Type+import HsDoc+import BasicTypes+import SrcLoc+import Outputable+import FastString+import Maybes( isJust )++import Data.Data hiding ( Fixity, Prefix, Infix )+import Data.Maybe ( fromMaybe )+import Control.Monad ( unless )++{-+************************************************************************+* *+\subsection{Bang annotations}+* *+************************************************************************+-}++-- | Located Bang Type+type LBangType name = Located (BangType name)++-- | Bang Type+type BangType name = HsType name -- Bangs are in the HsType data type++getBangType :: LHsType a -> LHsType a+getBangType (L _ (HsBangTy _ ty)) = ty+getBangType ty = ty++getBangStrictness :: LHsType a -> HsSrcBang+getBangStrictness (L _ (HsBangTy s _)) = s+getBangStrictness _ = (HsSrcBang NoSourceText NoSrcUnpack NoSrcStrict)++{-+************************************************************************+* *+\subsection{Data types}+* *+************************************************************************++This is the syntax for types as seen in type signatures.++Note [HsBSig binder lists]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider a binder (or pattern) decorated with a type or kind,+ \ (x :: a -> a). blah+ forall (a :: k -> *) (b :: k). blah+Then we use a LHsBndrSig on the binder, so that the+renamer can decorate it with the variables bound+by the pattern ('a' in the first example, 'k' in the second),+assuming that neither of them is in scope already+See also Note [Kind and type-variable binders] in RnTypes++Note [HsType binders]+~~~~~~~~~~~~~~~~~~~~~+The system for recording type and kind-variable binders in HsTypes+is a bit complicated. Here's how it works.++* In a HsType,+ HsForAllTy represents an /explicit, user-written/ 'forall'+ e.g. forall a b. ...+ HsQualTy represents an /explicit, user-written/ context+ e.g. (Eq a, Show a) => ...+ The context can be empty if that's what the user wrote+ These constructors represent what the user wrote, no more+ and no less.++* HsTyVarBndr describes a quantified type variable written by the+ user. For example+ f :: forall a (b :: *). blah+ here 'a' and '(b::*)' are each a HsTyVarBndr. A HsForAllTy has+ a list of LHsTyVarBndrs.++* HsImplicitBndrs is a wrapper that gives the implicitly-quantified+ kind and type variables of the wrapped thing. It is filled in by+ the renamer. For example, if the user writes+ f :: a -> a+ the HsImplicitBinders binds the 'a' (not a HsForAllTy!).+ NB: this implicit quantification is purely lexical: we bind any+ type or kind variables that are not in scope. The type checker+ may subsequently quantify over further kind variables.++* HsWildCardBndrs is a wrapper that binds the wildcard variables+ of the wrapped thing. It is filled in by the renamer+ f :: _a -> _+ The enclosing HsWildCardBndrs binds the wildcards _a and _.++* The explicit presence of these wrappers specifies, in the HsSyn,+ exactly where implicit quantification is allowed, and where+ wildcards are allowed.++* LHsQTyVars is used in data/class declarations, where the user gives+ explicit *type* variable bindings, but we need to implicitly bind+ *kind* variables. For example+ class C (a :: k -> *) where ...+ The 'k' is implicitly bound in the hsq_tvs field of LHsQTyVars++Note [The wildcard story for types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Types can have wildcards in them, to support partial type signatures,+like f :: Int -> (_ , _a) -> _a++A wildcard in a type can be++ * An anonymous wildcard,+ written '_'+ In HsType this is represented by HsWildCardTy.+ After the renamer, this contains a Name which uniquely+ identifies this particular occurrence.++ * A named wildcard,+ written '_a', '_foo', etc+ In HsType this is represented by (HsTyVar "_a")+ i.e. a perfectly ordinary type variable that happens+ to start with an underscore++Note carefully:++* When NamedWildCards is off, type variables that start with an+ underscore really /are/ ordinary type variables. And indeed, even+ when NamedWildCards is on you can bind _a explicitly as an ordinary+ type variable:+ data T _a _b = MkT _b _a+ Or even:+ f :: forall _a. _a -> _b+ Here _a is an ordinary forall'd binder, but (With NamedWildCards)+ _b is a named wildcard. (See the comments in Trac #10982)++* All wildcards, whether named or anonymous, are bound by the+ HsWildCardBndrs construct, which wraps types that are allowed+ to have wildcards.++* After type checking is done, we report what types the wildcards+ got unified with.++-}++-- | Located Haskell Context+type LHsContext name = Located (HsContext name)+ -- ^ 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnUnit'++ -- For details on above see note [Api annotations] in ApiAnnotation++-- | Haskell Context+type HsContext name = [LHsType name]++-- | Located Haskell Type+type LHsType name = Located (HsType name)+ -- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnComma' when+ -- in a list++ -- For details on above see note [Api annotations] in ApiAnnotation++-- | Haskell Kind+type HsKind name = HsType name++-- | Located Haskell Kind+type LHsKind name = Located (HsKind name)+ -- ^ 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation++--------------------------------------------------+-- LHsQTyVars+-- The explicitly-quantified binders in a data/type declaration++-- | Located Haskell Type Variable Binder+type LHsTyVarBndr name = Located (HsTyVarBndr name)+ -- See Note [HsType binders]++-- | Located Haskell Quantified Type Variables+data LHsQTyVars name -- See Note [HsType binders]+ = HsQTvs { hsq_implicit :: PostRn name [Name] -- implicit (dependent) variables+ , hsq_explicit :: [LHsTyVarBndr name] -- explicit variables+ -- See Note [HsForAllTy tyvar binders]+ , hsq_dependent :: PostRn name NameSet+ -- which explicit vars are dependent+ -- See Note [Dependent LHsQTyVars] in TcHsType+ }++deriving instance (DataId name) => Data (LHsQTyVars name)++mkHsQTvs :: [LHsTyVarBndr RdrName] -> LHsQTyVars RdrName+mkHsQTvs tvs = HsQTvs { hsq_implicit = PlaceHolder, hsq_explicit = tvs+ , hsq_dependent = PlaceHolder }++hsQTvExplicit :: LHsQTyVars name -> [LHsTyVarBndr name]+hsQTvExplicit = hsq_explicit++emptyLHsQTvs :: LHsQTyVars Name+emptyLHsQTvs = HsQTvs [] [] emptyNameSet++isEmptyLHsQTvs :: LHsQTyVars Name -> Bool+isEmptyLHsQTvs (HsQTvs [] [] _) = True+isEmptyLHsQTvs _ = False++------------------------------------------------+-- HsImplicitBndrs+-- Used to quantify the binders of a type in cases+-- when a HsForAll isn't appropriate:+-- * Patterns in a type/data family instance (HsTyPats)+-- * Type of a rule binder (RuleBndr)+-- * Pattern type signatures (SigPatIn)+-- In the last of these, wildcards can happen, so we must accommodate them++-- | Haskell Implicit Binders+data HsImplicitBndrs name thing -- See Note [HsType binders]+ = HsIB { hsib_vars :: PostRn name [Name] -- Implicitly-bound kind & type vars+ , hsib_body :: thing -- Main payload (type or list of types)+ , hsib_closed :: PostRn name Bool -- Taking the hsib_vars into account,+ -- is the payload closed? Used in+ -- TcHsType.decideKindGeneralisationPlan+ }++-- | Haskell Wildcard Binders+data HsWildCardBndrs name thing+ -- See Note [HsType binders]+ -- See Note [The wildcard story for types]+ = HsWC { hswc_wcs :: PostRn name [Name]+ -- Wild cards, both named and anonymous+ -- after the renamer++ , hswc_body :: thing+ -- Main payload (type or list of types)+ -- If there is an extra-constraints wildcard,+ -- it's still there in the hsc_body.+ }++deriving instance (Data name, Data thing, Data (PostRn name [Name]), Data (PostRn name Bool))+ => Data (HsImplicitBndrs name thing)++deriving instance (Data name, Data thing, Data (PostRn name [Name]))+ => Data (HsWildCardBndrs name thing)++-- | Located Haskell Signature Type+type LHsSigType name = HsImplicitBndrs name (LHsType name) -- Implicit only++-- | Located Haskell Wildcard Type+type LHsWcType name = HsWildCardBndrs name (LHsType name) -- Wildcard only++-- | Located Haskell Signature Wildcard Type+type LHsSigWcType name = HsWildCardBndrs name (LHsSigType name) -- Both++-- See Note [Representing type signatures]++hsImplicitBody :: HsImplicitBndrs name thing -> thing+hsImplicitBody (HsIB { hsib_body = body }) = body++hsSigType :: LHsSigType name -> LHsType name+hsSigType = hsImplicitBody++hsSigWcType :: LHsSigWcType name -> LHsType name+hsSigWcType sig_ty = hsib_body (hswc_body sig_ty)++dropWildCards :: LHsSigWcType name -> LHsSigType name+-- Drop the wildcard part of a LHsSigWcType+dropWildCards sig_ty = hswc_body sig_ty++{- Note [Representing type signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+HsSigType is used to represent an explicit user type signature+such as f :: a -> a+ or g (x :: a -> a) = x++A HsSigType is just a HsImplicitBndrs wrapping a LHsType.+ * The HsImplicitBndrs binds the /implicitly/ quantified tyvars+ * The LHsType binds the /explicitly/ quantified tyvars++E.g. For a signature like+ f :: forall (a::k). blah+we get+ HsIB { hsib_vars = [k]+ , hsib_body = HsForAllTy { hst_bndrs = [(a::*)]+ , hst_body = blah }+The implicit kind variable 'k' is bound by the HsIB;+the explicitly forall'd tyvar 'a' is bound by the HsForAllTy+-}++mkHsImplicitBndrs :: thing -> HsImplicitBndrs RdrName thing+mkHsImplicitBndrs x = HsIB { hsib_body = x+ , hsib_vars = PlaceHolder+ , hsib_closed = PlaceHolder }++mkHsWildCardBndrs :: thing -> HsWildCardBndrs RdrName thing+mkHsWildCardBndrs x = HsWC { hswc_body = x+ , hswc_wcs = PlaceHolder }++-- Add empty binders. This is a bit suspicious; what if+-- the wrapped thing had free type variables?+mkEmptyImplicitBndrs :: thing -> HsImplicitBndrs Name thing+mkEmptyImplicitBndrs x = HsIB { hsib_body = x+ , hsib_vars = []+ , hsib_closed = False }++mkEmptyWildCardBndrs :: thing -> HsWildCardBndrs Name thing+mkEmptyWildCardBndrs x = HsWC { hswc_body = x+ , hswc_wcs = [] }+++--------------------------------------------------+-- | These names are used early on to store the names of implicit+-- parameters. They completely disappear after type-checking.+newtype HsIPName = HsIPName FastString+ deriving( Eq, Data )++hsIPNameFS :: HsIPName -> FastString+hsIPNameFS (HsIPName n) = n++instance Outputable HsIPName where+ ppr (HsIPName n) = char '?' <> ftext n -- Ordinary implicit parameters++instance OutputableBndr HsIPName where+ pprBndr _ n = ppr n -- Simple for now+ pprInfixOcc n = ppr n+ pprPrefixOcc n = ppr n++--------------------------------------------------++-- | Haskell Type Variable Binder+data HsTyVarBndr name+ = UserTyVar -- no explicit kinding+ (Located name)+ -- See Note [Located RdrNames] in HsExpr+ | KindedTyVar+ (Located name)+ (LHsKind name) -- The user-supplied kind signature+ -- ^+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+ -- 'ApiAnnotation.AnnDcolon', 'ApiAnnotation.AnnClose'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (HsTyVarBndr name)++-- | Does this 'HsTyVarBndr' come with an explicit kind annotation?+isHsKindedTyVar :: HsTyVarBndr name -> Bool+isHsKindedTyVar (UserTyVar {}) = False+isHsKindedTyVar (KindedTyVar {}) = True++-- | Do all type variables in this 'LHsQTyVars' come with kind annotations?+hsTvbAllKinded :: LHsQTyVars name -> Bool+hsTvbAllKinded = all (isHsKindedTyVar . unLoc) . hsQTvExplicit++-- | Haskell Type+data HsType name+ = HsForAllTy -- See Note [HsType binders]+ { hst_bndrs :: [LHsTyVarBndr name] -- Explicit, user-supplied 'forall a b c'+ , hst_body :: LHsType name -- body type+ }+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnForall',+ -- 'ApiAnnotation.AnnDot','ApiAnnotation.AnnDarrow'+ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsQualTy -- See Note [HsType binders]+ { hst_ctxt :: LHsContext name -- Context C => blah+ , hst_body :: LHsType name }++ | HsTyVar Promoted -- whether explicitly promoted, for the pretty+ -- printer+ (Located name)+ -- Type variable, type constructor, or data constructor+ -- see Note [Promotions (HsTyVar)]+ -- See Note [Located RdrNames] in HsExpr+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsAppsTy [LHsAppType name] -- Used only before renaming,+ -- Note [HsAppsTy]+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ | HsAppTy (LHsType name)+ (LHsType name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsFunTy (LHsType name) -- function type+ (LHsType name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnRarrow',++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsListTy (LHsType name) -- Element type+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'['@,+ -- 'ApiAnnotation.AnnClose' @']'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsPArrTy (LHsType name) -- Elem. type of parallel array: [:t:]+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'[:'@,+ -- 'ApiAnnotation.AnnClose' @':]'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsTupleTy HsTupleSort+ [LHsType name] -- Element types (length gives arity)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'(' or '(#'@,+ -- 'ApiAnnotation.AnnClose' @')' or '#)'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsSumTy [LHsType name] -- Element types (length gives arity)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'(#'@,+ -- 'ApiAnnotation.AnnClose' '#)'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsOpTy (LHsType name) (Located name) (LHsType name)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsParTy (LHsType name) -- See Note [Parens in HsSyn] in HsExpr+ -- Parenthesis preserved for the precedence re-arrangement in RnTypes+ -- It's important that a * (b + c) doesn't get rearranged to (a*b) + c!+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'('@,+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsIParamTy (Located HsIPName) -- (?x :: ty)+ (LHsType name) -- Implicit parameters as they occur in contexts+ -- ^+ -- > (?x :: ty)+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsEqTy (LHsType name) -- ty1 ~ ty2+ (LHsType name) -- Always allowed even without TypeOperators, and has special kinding rule+ -- ^+ -- > ty1 ~ ty2+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnTilde'++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsKindSig (LHsType name) -- (ty :: kind)+ (LHsKind name) -- A type with a kind signature+ -- ^+ -- > (ty :: kind)+ --+ -- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'('@,+ -- 'ApiAnnotation.AnnDcolon','ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsSpliceTy (HsSplice name) -- Includes quasi-quotes+ (PostTc name Kind)+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'$('@,+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsDocTy (LHsType name) LHsDocString -- A documented type+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsBangTy HsSrcBang (LHsType name) -- Bang-style type annotations+ -- ^ - 'ApiAnnotation.AnnKeywordId' :+ -- 'ApiAnnotation.AnnOpen' @'{-\# UNPACK' or '{-\# NOUNPACK'@,+ -- 'ApiAnnotation.AnnClose' @'#-}'@+ -- 'ApiAnnotation.AnnBang' @\'!\'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsRecTy [LConDeclField name] -- Only in data type declarations+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'{'@,+ -- 'ApiAnnotation.AnnClose' @'}'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsCoreTy Type -- An escape hatch for tunnelling a *closed*+ -- Core Type through HsSyn.+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsExplicitListTy -- A promoted explicit list+ Promoted -- whether explcitly promoted, for pretty printer+ (PostTc name Kind) -- See Note [Promoted lists and tuples]+ [LHsType name]+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @"'["@,+ -- 'ApiAnnotation.AnnClose' @']'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsExplicitTupleTy -- A promoted explicit tuple+ [PostTc name Kind] -- See Note [Promoted lists and tuples]+ [LHsType name]+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @"'("@,+ -- 'ApiAnnotation.AnnClose' @')'@++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsTyLit HsTyLit -- A promoted numeric literal.+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation++ | HsWildCardTy (HsWildCardInfo name) -- A type wildcard+ -- See Note [The wildcard story for types]+ -- ^ - 'ApiAnnotation.AnnKeywordId' : None++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (HsType name)++-- Note [Literal source text] in BasicTypes for SourceText fields in+-- the following+-- | Haskell Type Literal+data HsTyLit+ = HsNumTy SourceText Integer+ | HsStrTy SourceText FastString+ deriving Data++newtype HsWildCardInfo name -- See Note [The wildcard story for types]+ = AnonWildCard (PostRn name (Located Name))+ -- A anonymous wild card ('_'). A fresh Name is generated for+ -- each individual anonymous wildcard during renaming+deriving instance (DataId name) => Data (HsWildCardInfo name)++-- | Located Haskell Application Type+type LHsAppType name = Located (HsAppType name)+ -- ^ 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnSimpleQuote'++-- | Haskell Application Type+data HsAppType name+ = HsAppInfix (Located name) -- either a symbol or an id in backticks+ | HsAppPrefix (LHsType name) -- anything else, including things like (+)+deriving instance (DataId name) => Data (HsAppType name)++instance (OutputableBndrId name) => Outputable (HsAppType name) where+ ppr = ppr_app_ty TopPrec++{-+Note [HsForAllTy tyvar binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+After parsing:+ * Implicit => empty+ Explicit => the variables the user wrote++After renaming+ * Implicit => the *type* variables free in the type+ Explicit => the variables the user wrote (renamed)++Qualified currently behaves exactly as Implicit,+but it is deprecated to use it for implicit quantification.+In this case, GHC 7.10 gives a warning; see+Note [Context quantification] in RnTypes, and Trac #4426.+In GHC 8.0, Qualified will no longer bind variables+and this will become an error.++The kind variables bound in the hsq_implicit field come both+ a) from the kind signatures on the kind vars (eg k1)+ b) from the scope of the forall (eg k2)+Example: f :: forall (a::k1) b. T a (b::k2)+++Note [Unit tuples]+~~~~~~~~~~~~~~~~~~+Consider the type+ type instance F Int = ()+We want to parse that "()"+ as HsTupleTy HsBoxedOrConstraintTuple [],+NOT as HsTyVar unitTyCon++Why? Because F might have kind (* -> Constraint), so we when parsing we+don't know if that tuple is going to be a constraint tuple or an ordinary+unit tuple. The HsTupleSort flag is specifically designed to deal with+that, but it has to work for unit tuples too.++Note [Promotions (HsTyVar)]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+HsTyVar: A name in a type or kind.+ Here are the allowed namespaces for the name.+ In a type:+ Var: not allowed+ Data: promoted data constructor+ Tv: type variable+ TcCls before renamer: type constructor, class constructor, or promoted data constructor+ TcCls after renamer: type constructor or class constructor+ In a kind:+ Var, Data: not allowed+ Tv: kind variable+ TcCls: kind constructor or promoted type constructor++ The 'Promoted' field in an HsTyVar captures whether the type was promoted in+ the source code by prefixing an apostrophe.++Note [HsAppsTy]+~~~~~~~~~~~~~~~+How to parse++ Foo * Int++? Is it `(*) Foo Int` or `Foo GHC.Types.* Int`? There's no way to know until renaming.+So we just take type expressions like this and put each component in a list, so be+sorted out in the renamer. The sorting out is done by RnTypes.mkHsOpTyRn. This means+that the parser should never produce HsAppTy or HsOpTy.++Note [Promoted lists and tuples]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Notice the difference between+ HsListTy HsExplicitListTy+ HsTupleTy HsExplicitListTupleTy++E.g. f :: [Int] HsListTy++ g3 :: T '[] All these use+ g2 :: T '[True] HsExplicitListTy+ g1 :: T '[True,False]+ g1a :: T [True,False] (can omit ' where unambiguous)++ kind of T :: [Bool] -> * This kind uses HsListTy!++E.g. h :: (Int,Bool) HsTupleTy; f is a pair+ k :: S '(True,False) HsExplicitTypleTy; S is indexed by+ a type-level pair of booleans+ kind of S :: (Bool,Bool) -> * This kind uses HsExplicitTupleTy++Note [Distinguishing tuple kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Apart from promotion, tuples can have one of three different kinds:++ x :: (Int, Bool) -- Regular boxed tuples+ f :: Int# -> (# Int#, Int# #) -- Unboxed tuples+ g :: (Eq a, Ord a) => a -- Constraint tuples++For convenience, internally we use a single constructor for all of these,+namely HsTupleTy, but keep track of the tuple kind (in the first argument to+HsTupleTy, a HsTupleSort). We can tell if a tuple is unboxed while parsing,+because of the #. However, with -XConstraintKinds we can only distinguish+between constraint and boxed tuples during type checking, in general. Hence the+four constructors of HsTupleSort:++ HsUnboxedTuple -> Produced by the parser+ HsBoxedTuple -> Certainly a boxed tuple+ HsConstraintTuple -> Certainly a constraint tuple+ HsBoxedOrConstraintTuple -> Could be a boxed or a constraint+ tuple. Produced by the parser only,+ disappears after type checking+-}++-- | Haskell Tuple Sort+data HsTupleSort = HsUnboxedTuple+ | HsBoxedTuple+ | HsConstraintTuple+ | HsBoxedOrConstraintTuple+ deriving Data+++-- | Promoted data types.+data Promoted = Promoted+ | NotPromoted+ deriving (Data, Eq, Show)++-- | Located Constructor Declaration Field+type LConDeclField name = Located (ConDeclField name)+ -- ^ May have 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnComma' when+ -- in a list++ -- For details on above see note [Api annotations] in ApiAnnotation++-- | Constructor Declaration Field+data ConDeclField name -- Record fields have Haddoc docs on them+ = ConDeclField { cd_fld_names :: [LFieldOcc name],+ -- ^ See Note [ConDeclField names]+ cd_fld_type :: LBangType name,+ cd_fld_doc :: Maybe LHsDocString }+ -- ^ - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnDcolon'++ -- For details on above see note [Api annotations] in ApiAnnotation+deriving instance (DataId name) => Data (ConDeclField name)++instance (OutputableBndrId name) => Outputable (ConDeclField name) where+ ppr (ConDeclField fld_n fld_ty _) = ppr fld_n <+> dcolon <+> ppr fld_ty++-- HsConDetails is used for patterns/expressions *and* for data type+-- declarations+-- | Haskell Constructor Details+data HsConDetails arg rec+ = PrefixCon [arg] -- C p1 p2 p3+ | RecCon rec -- C { x = p1, y = p2 }+ | InfixCon arg arg -- p1 `C` p2+ deriving Data++instance (Outputable arg, Outputable rec)+ => Outputable (HsConDetails arg rec) where+ ppr (PrefixCon args) = text "PrefixCon" <+> ppr args+ ppr (RecCon rec) = text "RecCon:" <+> ppr rec+ ppr (InfixCon l r) = text "InfixCon:" <+> ppr [l, r]++-- Takes details and result type of a GADT data constructor as created by the+-- parser and rejigs them using information about fixities from the renamer.+-- See Note [Sorting out the result type] in RdrHsSyn+updateGadtResult+ :: (Monad m)+ => (SDoc -> m ())+ -> SDoc+ -> HsConDetails (LHsType Name) (Located [LConDeclField Name])+ -- ^ Original details+ -> LHsType Name -- ^ Original result type+ -> m (HsConDetails (LHsType Name) (Located [LConDeclField Name]),+ LHsType Name)+updateGadtResult failWith doc details ty+ = do { let (arg_tys, res_ty) = splitHsFunType ty+ badConSig = text "Malformed constructor signature"+ ; case details of+ InfixCon {} -> pprPanic "updateGadtResult" (ppr ty)++ RecCon {} -> do { unless (null arg_tys)+ (failWith (doc <+> badConSig))+ ; return (details, res_ty) }++ PrefixCon {} -> return (PrefixCon arg_tys, res_ty)}++{-+Note [ConDeclField names]+~~~~~~~~~~~~~~~~~~~~~~~~~++A ConDeclField contains a list of field occurrences: these always+include the field label as the user wrote it. After the renamer, it+will additionally contain the identity of the selector function in the+second component.++Due to DuplicateRecordFields, the OccName of the selector function+may have been mangled, which is why we keep the original field label+separately. For example, when DuplicateRecordFields is enabled++ data T = MkT { x :: Int }++gives++ ConDeclField { cd_fld_names = [L _ (FieldOcc "x" $sel:x:MkT)], ... }.+-}++-----------------------+-- A valid type must have a for-all at the top of the type, or of the fn arg+-- types++---------------------+hsWcScopedTvs :: LHsSigWcType Name -> [Name]+-- Get the lexically-scoped type variables of a HsSigType+-- - the explicitly-given forall'd type variables+-- - the implicitly-bound kind variables+-- - the named wildcars; see Note [Scoping of named wildcards]+-- because they scope in the same way+hsWcScopedTvs sig_ty+ | HsWC { hswc_wcs = nwcs, hswc_body = sig_ty1 } <- sig_ty+ , HsIB { hsib_vars = vars, hsib_body = sig_ty2 } <- sig_ty1+ = case sig_ty2 of+ L _ (HsForAllTy { hst_bndrs = tvs }) -> vars ++ nwcs +++ map hsLTyVarName tvs+ -- include kind variables only if the type is headed by forall+ -- (this is consistent with GHC 7 behaviour)+ _ -> nwcs++hsScopedTvs :: LHsSigType Name -> [Name]+-- Same as hsWcScopedTvs, but for a LHsSigType+hsScopedTvs sig_ty+ | HsIB { hsib_vars = vars, hsib_body = sig_ty2 } <- sig_ty+ , L _ (HsForAllTy { hst_bndrs = tvs }) <- sig_ty2+ = vars ++ map hsLTyVarName tvs+ | otherwise+ = []++{- Note [Scoping of named wildcards]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f :: _a -> _a+ f x = let g :: _a -> _a+ g = ...+ in ...++Currently, for better or worse, the "_a" variables are all the same. So+although there is no explicit forall, the "_a" scopes over the definition.+I don't know if this is a good idea, but there it is.+-}++---------------------+hsTyVarName :: HsTyVarBndr name -> name+hsTyVarName (UserTyVar (L _ n)) = n+hsTyVarName (KindedTyVar (L _ n) _) = n++hsLTyVarName :: LHsTyVarBndr name -> name+hsLTyVarName = hsTyVarName . unLoc++hsExplicitLTyVarNames :: LHsQTyVars name -> [name]+-- Explicit variables only+hsExplicitLTyVarNames qtvs = map hsLTyVarName (hsQTvExplicit qtvs)++hsAllLTyVarNames :: LHsQTyVars Name -> [Name]+-- All variables+hsAllLTyVarNames (HsQTvs { hsq_implicit = kvs, hsq_explicit = tvs })+ = kvs ++ map hsLTyVarName tvs++hsLTyVarLocName :: LHsTyVarBndr name -> Located name+hsLTyVarLocName = fmap hsTyVarName++hsLTyVarLocNames :: LHsQTyVars name -> [Located name]+hsLTyVarLocNames qtvs = map hsLTyVarLocName (hsQTvExplicit qtvs)++-- | Convert a LHsTyVarBndr to an equivalent LHsType.+hsLTyVarBndrToType :: LHsTyVarBndr name -> LHsType name+hsLTyVarBndrToType = fmap cvt+ where cvt (UserTyVar n) = HsTyVar NotPromoted n+ cvt (KindedTyVar (L name_loc n) kind)+ = HsKindSig (L name_loc (HsTyVar NotPromoted (L name_loc n))) kind++-- | Convert a LHsTyVarBndrs to a list of types.+-- Works on *type* variable only, no kind vars.+hsLTyVarBndrsToTypes :: LHsQTyVars name -> [LHsType name]+hsLTyVarBndrsToTypes (HsQTvs { hsq_explicit = tvbs }) = map hsLTyVarBndrToType tvbs++---------------------+wildCardName :: HsWildCardInfo Name -> Name+wildCardName (AnonWildCard (L _ n)) = n++-- Two wild cards are the same when they have the same location+sameWildCard :: Located (HsWildCardInfo name)+ -> Located (HsWildCardInfo name) -> Bool+sameWildCard (L l1 (AnonWildCard _)) (L l2 (AnonWildCard _)) = l1 == l2++ignoreParens :: LHsType name -> LHsType name+ignoreParens (L _ (HsParTy ty)) = ignoreParens ty+ignoreParens (L _ (HsAppsTy [L _ (HsAppPrefix ty)])) = ignoreParens ty+ignoreParens ty = ty++{-+************************************************************************+* *+ Building types+* *+************************************************************************+-}++mkAnonWildCardTy :: HsType RdrName+mkAnonWildCardTy = HsWildCardTy (AnonWildCard PlaceHolder)++mkHsOpTy :: LHsType name -> Located name -> LHsType name -> HsType name+mkHsOpTy ty1 op ty2 = HsOpTy ty1 op ty2++mkHsAppTy :: LHsType name -> LHsType name -> LHsType name+mkHsAppTy t1 t2 = addCLoc t1 t2 (HsAppTy t1 t2)++mkHsAppTys :: LHsType name -> [LHsType name] -> LHsType name+mkHsAppTys = foldl mkHsAppTy+++{-+************************************************************************+* *+ Decomposing HsTypes+* *+************************************************************************+-}++---------------------------------+-- splitHsFunType decomposes a type (t1 -> t2 ... -> tn)+-- Breaks up any parens in the result type:+-- splitHsFunType (a -> (b -> c)) = ([a,b], c)+-- Also deals with (->) t1 t2; that is why it only works on LHsType Name+-- (see Trac #9096)+splitHsFunType :: LHsType Name -> ([LHsType Name], LHsType Name)+splitHsFunType (L _ (HsParTy ty))+ = splitHsFunType ty++splitHsFunType (L _ (HsFunTy x y))+ | (args, res) <- splitHsFunType y+ = (x:args, res)++splitHsFunType orig_ty@(L _ (HsAppTy t1 t2))+ = go t1 [t2]+ where -- Look for (->) t1 t2, possibly with parenthesisation+ go (L _ (HsTyVar _ (L _ fn))) tys | fn == funTyConName+ , [t1,t2] <- tys+ , (args, res) <- splitHsFunType t2+ = (t1:args, res)+ go (L _ (HsAppTy t1 t2)) tys = go t1 (t2:tys)+ go (L _ (HsParTy ty)) tys = go ty tys+ go _ _ = ([], orig_ty) -- Failure to match++splitHsFunType other = ([], other)++--------------------------------+-- | Retrieves the head of an HsAppsTy, if this can be done unambiguously,+-- without consulting fixities.+getAppsTyHead_maybe :: [LHsAppType name]+ -> Maybe (LHsType name, [LHsType name], LexicalFixity)+getAppsTyHead_maybe tys = case splitHsAppsTy tys of+ ([app1:apps], []) -> -- no symbols, some normal types+ Just (mkHsAppTys app1 apps, [], Prefix)+ ([app1l:appsl, app1r:appsr], [L loc op]) -> -- one operator+ Just ( L loc (HsTyVar NotPromoted (L loc op))+ , [mkHsAppTys app1l appsl, mkHsAppTys app1r appsr], Infix)+ _ -> -- can't figure it out+ Nothing++-- | Splits a [HsAppType name] (the payload of an HsAppsTy) into regions of prefix+-- types (normal types) and infix operators.+-- If @splitHsAppsTy tys = (non_syms, syms)@, then @tys@ starts with the first+-- element of @non_syms@ followed by the first element of @syms@ followed by+-- the next element of @non_syms@, etc. It is guaranteed that the non_syms list+-- has one more element than the syms list.+splitHsAppsTy :: [LHsAppType name] -> ([[LHsType name]], [Located name])+splitHsAppsTy = go [] [] []+ where+ go acc acc_non acc_sym [] = (reverse (reverse acc : acc_non), reverse acc_sym)+ go acc acc_non acc_sym (L _ (HsAppPrefix ty) : rest)+ = go (ty : acc) acc_non acc_sym rest+ go acc acc_non acc_sym (L _ (HsAppInfix op) : rest)+ = go [] (reverse acc : acc_non) (op : acc_sym) rest++-- Retrieve the name of the "head" of a nested type application+-- somewhat like splitHsAppTys, but a little more thorough+-- used to examine the result of a GADT-like datacon, so it doesn't handle+-- *all* cases (like lists, tuples, (~), etc.)+hsTyGetAppHead_maybe :: LHsType name -> Maybe (Located name, [LHsType name])+hsTyGetAppHead_maybe = go []+ where+ go tys (L _ (HsTyVar _ ln)) = Just (ln, tys)+ go tys (L _ (HsAppsTy apps))+ | Just (head, args, _) <- getAppsTyHead_maybe apps+ = go (args ++ tys) head+ go tys (L _ (HsAppTy l r)) = go (r : tys) l+ go tys (L _ (HsOpTy l (L loc n) r)) = Just (L loc n, l : r : tys)+ go tys (L _ (HsParTy t)) = go tys t+ go tys (L _ (HsKindSig t _)) = go tys t+ go _ _ = Nothing++splitHsAppTys :: LHsType Name -> [LHsType Name] -> (LHsType Name, [LHsType Name])+ -- no need to worry about HsAppsTy here+splitHsAppTys (L _ (HsAppTy f a)) as = splitHsAppTys f (a:as)+splitHsAppTys (L _ (HsParTy f)) as = splitHsAppTys f as+splitHsAppTys f as = (f,as)++--------------------------------+splitLHsPatSynTy :: LHsType name+ -> ( [LHsTyVarBndr name] -- universals+ , LHsContext name -- required constraints+ , [LHsTyVarBndr name] -- existentials+ , LHsContext name -- provided constraints+ , LHsType name) -- body type+splitLHsPatSynTy ty = (univs, reqs, exis, provs, ty4)+ where+ (univs, ty1) = splitLHsForAllTy ty+ (reqs, ty2) = splitLHsQualTy ty1+ (exis, ty3) = splitLHsForAllTy ty2+ (provs, ty4) = splitLHsQualTy ty3++splitLHsSigmaTy :: LHsType name -> ([LHsTyVarBndr name], LHsContext name, LHsType name)+splitLHsSigmaTy ty+ | (tvs, ty1) <- splitLHsForAllTy ty+ , (ctxt, ty2) <- splitLHsQualTy ty1+ = (tvs, ctxt, ty2)++splitLHsForAllTy :: LHsType name -> ([LHsTyVarBndr name], LHsType name)+splitLHsForAllTy (L _ (HsForAllTy { hst_bndrs = tvs, hst_body = body })) = (tvs, body)+splitLHsForAllTy body = ([], body)++splitLHsQualTy :: LHsType name -> (LHsContext name, LHsType name)+splitLHsQualTy (L _ (HsQualTy { hst_ctxt = ctxt, hst_body = body })) = (ctxt, body)+splitLHsQualTy body = (noLoc [], body)++splitLHsInstDeclTy :: LHsSigType Name+ -> ([Name], LHsContext Name, LHsType Name)+-- Split up an instance decl type, returning the pieces+splitLHsInstDeclTy (HsIB { hsib_vars = itkvs+ , hsib_body = inst_ty })+ | (tvs, cxt, body_ty) <- splitLHsSigmaTy inst_ty+ = (itkvs ++ map hsLTyVarName tvs, cxt, body_ty)+ -- Return implicitly bound type and kind vars+ -- For an instance decl, all of them are in scope++getLHsInstDeclHead :: LHsSigType name -> LHsType name+getLHsInstDeclHead inst_ty+ | (_tvs, _cxt, body_ty) <- splitLHsSigmaTy (hsSigType inst_ty)+ = body_ty++getLHsInstDeclClass_maybe :: LHsSigType name -> Maybe (Located name)+-- Works on (HsSigType RdrName)+getLHsInstDeclClass_maybe inst_ty+ = do { let head_ty = getLHsInstDeclHead inst_ty+ ; (cls, _) <- hsTyGetAppHead_maybe head_ty+ ; return cls }++{-+************************************************************************+* *+ FieldOcc+* *+************************************************************************+-}++-- | Located Field Occurrence+type LFieldOcc name = Located (FieldOcc name)++-- | Field Occurrence+--+-- Represents an *occurrence* of an unambiguous field. We store+-- both the 'RdrName' the user originally wrote, and after the+-- renamer, the selector function.+data FieldOcc name = FieldOcc { rdrNameFieldOcc :: Located RdrName+ -- ^ See Note [Located RdrNames] in HsExpr+ , selectorFieldOcc :: PostRn name name+ }+deriving instance Eq (PostRn name name) => Eq (FieldOcc name)+deriving instance Ord (PostRn name name) => Ord (FieldOcc name)+deriving instance (Data name, Data (PostRn name name)) => Data (FieldOcc name)++instance Outputable (FieldOcc name) where+ ppr = ppr . rdrNameFieldOcc++mkFieldOcc :: Located RdrName -> FieldOcc RdrName+mkFieldOcc rdr = FieldOcc rdr PlaceHolder+++-- | Ambiguous Field Occurrence+--+-- Represents an *occurrence* of a field that is potentially+-- ambiguous after the renamer, with the ambiguity resolved by the+-- typechecker. We always store the 'RdrName' that the user+-- originally wrote, and store the selector function after the renamer+-- (for unambiguous occurrences) or the typechecker (for ambiguous+-- occurrences).+--+-- See Note [HsRecField and HsRecUpdField] in HsPat and+-- Note [Disambiguating record fields] in TcExpr.+-- See Note [Located RdrNames] in HsExpr+data AmbiguousFieldOcc name+ = Unambiguous (Located RdrName) (PostRn name name)+ | Ambiguous (Located RdrName) (PostTc name name)+deriving instance ( Data name+ , Data (PostRn name name)+ , Data (PostTc name name))+ => Data (AmbiguousFieldOcc name)++instance Outputable (AmbiguousFieldOcc name) where+ ppr = ppr . rdrNameAmbiguousFieldOcc++instance OutputableBndr (AmbiguousFieldOcc name) where+ pprInfixOcc = pprInfixOcc . rdrNameAmbiguousFieldOcc+ pprPrefixOcc = pprPrefixOcc . rdrNameAmbiguousFieldOcc++mkAmbiguousFieldOcc :: Located RdrName -> AmbiguousFieldOcc RdrName+mkAmbiguousFieldOcc rdr = Unambiguous rdr PlaceHolder++rdrNameAmbiguousFieldOcc :: AmbiguousFieldOcc name -> RdrName+rdrNameAmbiguousFieldOcc (Unambiguous (L _ rdr) _) = rdr+rdrNameAmbiguousFieldOcc (Ambiguous (L _ rdr) _) = rdr++selectorAmbiguousFieldOcc :: AmbiguousFieldOcc Id -> Id+selectorAmbiguousFieldOcc (Unambiguous _ sel) = sel+selectorAmbiguousFieldOcc (Ambiguous _ sel) = sel++unambiguousFieldOcc :: AmbiguousFieldOcc Id -> FieldOcc Id+unambiguousFieldOcc (Unambiguous rdr sel) = FieldOcc rdr sel+unambiguousFieldOcc (Ambiguous rdr sel) = FieldOcc rdr sel++ambiguousFieldOcc :: FieldOcc name -> AmbiguousFieldOcc name+ambiguousFieldOcc (FieldOcc rdr sel) = Unambiguous rdr sel++{-+************************************************************************+* *+\subsection{Pretty printing}+* *+************************************************************************+-}++instance (OutputableBndrId name) => Outputable (HsType name) where+ ppr ty = pprHsType ty++instance Outputable HsTyLit where+ ppr = ppr_tylit++instance (OutputableBndrId name) => Outputable (LHsQTyVars name) where+ ppr (HsQTvs { hsq_explicit = tvs }) = interppSP tvs++instance (OutputableBndrId name) => Outputable (HsTyVarBndr name) where+ ppr (UserTyVar n) = ppr n+ ppr (KindedTyVar n k) = parens $ hsep [ppr n, dcolon, ppr k]++instance (Outputable thing) => Outputable (HsImplicitBndrs name thing) where+ ppr (HsIB { hsib_body = ty }) = ppr ty++instance (Outputable thing) => Outputable (HsWildCardBndrs name thing) where+ ppr (HsWC { hswc_body = ty }) = ppr ty++instance Outputable (HsWildCardInfo name) where+ ppr (AnonWildCard _) = char '_'++pprHsForAll :: (OutputableBndrId name)+ => [LHsTyVarBndr name] -> LHsContext name -> SDoc+pprHsForAll = pprHsForAllExtra Nothing++-- | Version of 'pprHsForAll' that can also print an extra-constraints+-- wildcard, e.g. @_ => a -> Bool@ or @(Show a, _) => a -> String@. This+-- underscore will be printed when the 'Maybe SrcSpan' argument is a 'Just'+-- containing the location of the extra-constraints wildcard. A special+-- function for this is needed, as the extra-constraints wildcard is removed+-- from the actual context and type, and stored in a separate field, thus just+-- printing the type will not print the extra-constraints wildcard.+pprHsForAllExtra :: (OutputableBndrId name)+ => Maybe SrcSpan -> [LHsTyVarBndr name] -> LHsContext name+ -> SDoc+pprHsForAllExtra extra qtvs cxt+ = pprHsForAllTvs qtvs <+> pprHsContextExtra show_extra (unLoc cxt)+ where+ show_extra = isJust extra++pprHsForAllTvs :: (OutputableBndrId name) => [LHsTyVarBndr name] -> SDoc+pprHsForAllTvs qtvs = sdocWithPprDebug $ \debug ->+ ppWhen (debug || not (null qtvs)) $ forAllLit <+> interppSP qtvs <> dot++pprHsContext :: (OutputableBndrId name) => HsContext name -> SDoc+pprHsContext = maybe empty (<+> darrow) . pprHsContextMaybe++pprHsContextNoArrow :: (OutputableBndrId name) => HsContext name -> SDoc+pprHsContextNoArrow = fromMaybe empty . pprHsContextMaybe++pprHsContextMaybe :: (OutputableBndrId name) => HsContext name -> Maybe SDoc+pprHsContextMaybe [] = Nothing+pprHsContextMaybe [L _ pred] = Just $ ppr_mono_ty FunPrec pred+pprHsContextMaybe cxt = Just $ parens (interpp'SP cxt)++-- For use in a HsQualTy, which always gets printed if it exists.+pprHsContextAlways :: (OutputableBndrId name) => HsContext name -> SDoc+pprHsContextAlways [] = parens empty <+> darrow+pprHsContextAlways [L _ ty] = ppr_mono_ty FunPrec ty <+> darrow+pprHsContextAlways cxt = parens (interpp'SP cxt) <+> darrow++-- True <=> print an extra-constraints wildcard, e.g. @(Show a, _) =>@+pprHsContextExtra :: (OutputableBndrId name) => Bool -> HsContext name -> SDoc+pprHsContextExtra show_extra ctxt+ | not show_extra+ = pprHsContext ctxt+ | null ctxt+ = char '_' <+> darrow+ | otherwise+ = parens (sep (punctuate comma ctxt')) <+> darrow+ where+ ctxt' = map ppr ctxt ++ [char '_']++pprConDeclFields :: (OutputableBndrId name) => [LConDeclField name] -> SDoc+pprConDeclFields fields = braces (sep (punctuate comma (map ppr_fld fields)))+ where+ ppr_fld (L _ (ConDeclField { cd_fld_names = ns, cd_fld_type = ty,+ cd_fld_doc = doc }))+ = ppr_names ns <+> dcolon <+> ppr ty <+> ppr_mbDoc doc+ ppr_names [n] = ppr n+ ppr_names ns = sep (punctuate comma (map ppr ns))++{-+Note [Printing KindedTyVars]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Trac #3830 reminded me that we should really only print the kind+signature on a KindedTyVar if the kind signature was put there by the+programmer. During kind inference GHC now adds a PostTcKind to UserTyVars,+rather than converting to KindedTyVars as before.++(As it happens, the message in #3830 comes out a different way now,+and the problem doesn't show up; but having the flag on a KindedTyVar+seems like the Right Thing anyway.)+-}++-- Printing works more-or-less as for Types++pprHsType, pprParendHsType :: (OutputableBndrId name) => HsType name -> SDoc++pprHsType ty = ppr_mono_ty TopPrec ty+pprParendHsType ty = ppr_mono_ty TyConPrec ty++ppr_mono_lty :: (OutputableBndrId name) => TyPrec -> LHsType name -> SDoc+ppr_mono_lty ctxt_prec ty = ppr_mono_ty ctxt_prec (unLoc ty)++ppr_mono_ty :: (OutputableBndrId name) => TyPrec -> HsType name -> SDoc+ppr_mono_ty ctxt_prec (HsForAllTy { hst_bndrs = tvs, hst_body = ty })+ = maybeParen ctxt_prec FunPrec $+ sep [pprHsForAllTvs tvs, ppr_mono_lty TopPrec ty]++ppr_mono_ty _ctxt_prec (HsQualTy { hst_ctxt = L _ ctxt, hst_body = ty })+ = sep [pprHsContextAlways ctxt, ppr_mono_lty TopPrec ty]++ppr_mono_ty _ (HsBangTy b ty) = ppr b <> ppr_mono_lty TyConPrec ty+ppr_mono_ty _ (HsRecTy flds) = pprConDeclFields flds+ppr_mono_ty _ (HsTyVar NotPromoted (L _ name))= pprPrefixOcc name+ppr_mono_ty _ (HsTyVar Promoted (L _ name))+ = space <> quote (pprPrefixOcc name)+ -- We need a space before the ' above, so the parser+ -- does not attach it to the previous symbol+ppr_mono_ty prec (HsFunTy ty1 ty2) = ppr_fun_ty prec ty1 ty2+ppr_mono_ty _ (HsTupleTy con tys) = tupleParens std_con (pprWithCommas ppr tys)+ where std_con = case con of+ HsUnboxedTuple -> UnboxedTuple+ _ -> BoxedTuple+ppr_mono_ty _ (HsSumTy tys) = tupleParens UnboxedTuple (pprWithBars ppr tys)+ppr_mono_ty _ (HsKindSig ty kind) = parens (ppr_mono_lty TopPrec ty <+> dcolon <+> ppr kind)+ppr_mono_ty _ (HsListTy ty) = brackets (ppr_mono_lty TopPrec ty)+ppr_mono_ty _ (HsPArrTy ty) = paBrackets (ppr_mono_lty TopPrec ty)+ppr_mono_ty prec (HsIParamTy n ty) = maybeParen prec FunPrec (ppr n <+> dcolon <+> ppr_mono_lty TopPrec ty)+ppr_mono_ty _ (HsSpliceTy s _) = pprSplice s+ppr_mono_ty _ (HsCoreTy ty) = ppr ty+ppr_mono_ty _ (HsExplicitListTy Promoted _ tys)+ = quote $ brackets (interpp'SP tys)+ppr_mono_ty _ (HsExplicitListTy NotPromoted _ tys)+ = brackets (interpp'SP tys)+ppr_mono_ty _ (HsExplicitTupleTy _ tys) = quote $ parens (interpp'SP tys)+ppr_mono_ty _ (HsTyLit t) = ppr_tylit t+ppr_mono_ty _ (HsWildCardTy {}) = char '_'++ppr_mono_ty ctxt_prec (HsEqTy ty1 ty2)+ = maybeParen ctxt_prec TyOpPrec $+ ppr_mono_lty TyOpPrec ty1 <+> char '~' <+> ppr_mono_lty TyOpPrec ty2++ppr_mono_ty _ctxt_prec (HsAppsTy tys)+ = hsep (map (ppr_app_ty TopPrec . unLoc) tys)++ppr_mono_ty _ctxt_prec (HsAppTy fun_ty arg_ty)+ = hsep [ppr_mono_lty FunPrec fun_ty, ppr_mono_lty TyConPrec arg_ty]++ppr_mono_ty ctxt_prec (HsOpTy ty1 (L _ op) ty2)+ = maybeParen ctxt_prec TyOpPrec $+ sep [ ppr_mono_lty TyOpPrec ty1+ , sep [pprInfixOcc op, ppr_mono_lty TyOpPrec ty2 ] ]++ppr_mono_ty _ (HsParTy ty)+ = parens (ppr_mono_lty TopPrec ty)+ -- Put the parens in where the user did+ -- But we still use the precedence stuff to add parens because+ -- toHsType doesn't put in any HsParTys, so we may still need them++ppr_mono_ty ctxt_prec (HsDocTy ty doc)+ = maybeParen ctxt_prec TyOpPrec $+ ppr_mono_lty TyOpPrec ty <+> ppr (unLoc doc)+ -- we pretty print Haddock comments on types as if they were+ -- postfix operators++--------------------------+ppr_fun_ty :: (OutputableBndrId name)+ => TyPrec -> LHsType name -> LHsType name -> SDoc+ppr_fun_ty ctxt_prec ty1 ty2+ = let p1 = ppr_mono_lty FunPrec ty1+ p2 = ppr_mono_lty TopPrec ty2+ in+ maybeParen ctxt_prec FunPrec $+ sep [p1, text "->" <+> p2]++--------------------------+ppr_app_ty :: (OutputableBndrId name) => TyPrec -> HsAppType name -> SDoc+ppr_app_ty _ (HsAppInfix (L _ n)) = pprInfixOcc n+ppr_app_ty _ (HsAppPrefix (L _ (HsTyVar NotPromoted (L _ n))))+ = pprPrefixOcc n+ppr_app_ty _ (HsAppPrefix (L _ (HsTyVar Promoted (L _ n))))+ = space <> quote (pprPrefixOcc n) -- We need a space before the ' above, so+ -- the parser does not attach it to the+ -- previous symbol+ppr_app_ty ctxt (HsAppPrefix ty) = ppr_mono_lty ctxt ty++--------------------------+ppr_tylit :: HsTyLit -> SDoc+ppr_tylit (HsNumTy _ i) = integer i+ppr_tylit (HsStrTy _ s) = text (show s)
+ hsSyn/HsUtils.hs view
@@ -0,0 +1,1251 @@+{-+(c) The University of Glasgow, 1992-2006+++Here we collect a variety of helper functions that construct or+analyse HsSyn. All these functions deal with generic HsSyn; functions+which deal with the instantiated versions are located elsewhere:++ Parameterised by Module+ ---------------- -------------+ RdrName parser/RdrHsSyn+ Name rename/RnHsSyn+ Id typecheck/TcHsSyn+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE TypeFamilies #-}++module HsUtils(+ -- Terms+ mkHsPar, mkHsApp, mkHsAppType, mkHsAppTypeOut, mkHsCaseAlt,+ mkSimpleMatch, unguardedGRHSs, unguardedRHS,+ mkMatchGroup, mkMatch, mkPrefixFunRhs, mkHsLam, mkHsIf,+ mkHsWrap, mkLHsWrap, mkHsWrapCo, mkHsWrapCoR, mkLHsWrapCo,+ mkHsDictLet, mkHsLams,+ mkHsOpApp, mkHsDo, mkHsComp, mkHsWrapPat, mkHsWrapPatCo,+ mkLHsPar, mkHsCmdWrap, mkLHsCmdWrap,++ nlHsTyApp, nlHsTyApps, nlHsVar, nlHsDataCon,+ nlHsLit, nlHsApp, nlHsApps, nlHsSyntaxApps,+ nlHsIntLit, nlHsVarApps,+ nlHsDo, nlHsOpApp, nlHsLam, nlHsPar, nlHsIf, nlHsCase, nlList,+ mkLHsTupleExpr, mkLHsVarTuple, missingTupArg,+ typeToLHsType,++ -- * Constructing general big tuples+ -- $big_tuples+ mkChunkified, chunkify,++ -- Bindings+ mkFunBind, mkVarBind, mkHsVarBind, mk_easy_FunBind, mkTopFunBind,+ mkPatSynBind,+ isInfixFunBind,++ -- Literals+ mkHsIntegral, mkHsFractional, mkHsIsString, mkHsString, mkHsStringPrimLit,++ -- Patterns+ mkNPat, mkNPlusKPat, nlVarPat, nlLitPat, nlConVarPat, nlConVarPatName, nlConPat,+ nlConPatName, nlInfixConPat, nlNullaryConPat, nlWildConPat, nlWildPat,+ nlWildPatName, nlWildPatId, nlTuplePat, mkParPat, nlParPat,+ mkBigLHsVarTup, mkBigLHsTup, mkBigLHsVarPatTup, mkBigLHsPatTup,++ -- Types+ mkHsAppTy, mkHsAppTys, userHsTyVarBndrs, userHsLTyVarBndrs,+ mkLHsSigType, mkLHsSigWcType, mkClassOpSigs, mkHsSigEnv,+ nlHsAppTy, nlHsTyVar, nlHsFunTy, nlHsParTy, nlHsTyConApp,++ -- Stmts+ mkTransformStmt, mkTransformByStmt, mkBodyStmt, mkBindStmt, mkTcBindStmt,+ mkLastStmt,+ emptyTransStmt, mkGroupUsingStmt, mkGroupByUsingStmt,+ emptyRecStmt, emptyRecStmtName, emptyRecStmtId, mkRecStmt,++ -- Template Haskell+ mkHsSpliceTy, mkHsSpliceE, mkHsSpliceTE, mkUntypedSplice,+ mkHsQuasiQuote, unqualQuasiQuote,++ -- Flags+ noRebindableInfo,++ -- Collecting binders+ isUnliftedHsBind, isBangedBind,++ collectLocalBinders, collectHsValBinders, collectHsBindListBinders,+ collectHsIdBinders,+ collectHsBindsBinders, collectHsBindBinders, collectMethodBinders,+ collectPatBinders, collectPatsBinders,+ collectLStmtsBinders, collectStmtsBinders,+ collectLStmtBinders, collectStmtBinders,++ hsLTyClDeclBinders, hsTyClForeignBinders,+ hsPatSynSelectors, getPatSynBinds,+ hsForeignDeclsBinders, hsGroupBinders, hsDataFamInstBinders,+ hsDataDefnBinders,++ -- Collecting implicit binders+ lStmtsImplicits, hsValBindsImplicits, lPatImplicits+ ) where++#include "HsVersions.h"++import HsDecls+import HsBinds+import HsExpr+import HsPat+import HsTypes+import HsLit+import PlaceHolder++import TcEvidence+import RdrName+import Var+import TyCoRep+import Type ( filterOutInvisibleTypes )+import TysWiredIn ( unitTy )+import TcType+import DataCon+import ConLike+import Id+import Name+import NameSet+import NameEnv+import BasicTypes+import SrcLoc+import FastString+import Util+import Bag+import Outputable+import Constants++import Data.Either+import Data.Function+import Data.List++{-+************************************************************************+* *+ Some useful helpers for constructing syntax+* *+************************************************************************++These functions attempt to construct a not-completely-useless SrcSpan+from their components, compared with the nl* functions below which+just attach noSrcSpan to everything.+-}++mkHsPar :: LHsExpr id -> LHsExpr id+mkHsPar e = L (getLoc e) (HsPar e)++mkSimpleMatch :: HsMatchContext (NameOrRdrName id)+ -> [LPat id] -> Located (body id)+ -> LMatch id (Located (body id))+mkSimpleMatch ctxt pats rhs+ = L loc $+ Match ctxt pats Nothing (unguardedGRHSs rhs)+ where+ loc = case pats of+ [] -> getLoc rhs+ (pat:_) -> combineSrcSpans (getLoc pat) (getLoc rhs)++unguardedGRHSs :: Located (body id) -> GRHSs id (Located (body id))+unguardedGRHSs rhs@(L loc _)+ = GRHSs (unguardedRHS loc rhs) (noLoc emptyLocalBinds)++unguardedRHS :: SrcSpan -> Located (body id) -> [LGRHS id (Located (body id))]+unguardedRHS loc rhs = [L loc (GRHS [] rhs)]++mkMatchGroup :: (PostTc name Type ~ PlaceHolder)+ => Origin -> [LMatch name (Located (body name))]+ -> MatchGroup name (Located (body name))+mkMatchGroup origin matches = MG { mg_alts = mkLocatedList matches+ , mg_arg_tys = []+ , mg_res_ty = placeHolderType+ , mg_origin = origin }++mkLocatedList :: [Located a] -> Located [Located a]+mkLocatedList [] = noLoc []+mkLocatedList ms = L (combineLocs (head ms) (last ms)) ms++mkHsApp :: LHsExpr name -> LHsExpr name -> LHsExpr name+mkHsApp e1 e2 = addCLoc e1 e2 (HsApp e1 e2)++mkHsAppType :: LHsExpr name -> LHsWcType name -> LHsExpr name+mkHsAppType e t = addCLoc e (hswc_body t) (HsAppType e t)++mkHsAppTypeOut :: LHsExpr Id -> LHsWcType Name -> LHsExpr Id+mkHsAppTypeOut e t = addCLoc e (hswc_body t) (HsAppTypeOut e t)++mkHsLam :: [LPat RdrName] -> LHsExpr RdrName -> LHsExpr RdrName+mkHsLam pats body = mkHsPar (L (getLoc body) (HsLam matches))+ where+ matches = mkMatchGroup Generated+ [mkSimpleMatch LambdaExpr pats body]++mkHsLams :: [TyVar] -> [EvVar] -> LHsExpr Id -> LHsExpr Id+mkHsLams tyvars dicts expr = mkLHsWrap (mkWpTyLams tyvars+ <.> mkWpLams dicts) expr++-- |A simple case alternative with a single pattern, no binds, no guards;+-- pre-typechecking+mkHsCaseAlt :: LPat id -> (Located (body id)) -> LMatch id (Located (body id))+mkHsCaseAlt pat expr+ = mkSimpleMatch CaseAlt [pat] expr++nlHsTyApp :: name -> [Type] -> LHsExpr name+nlHsTyApp fun_id tys = noLoc (HsWrap (mkWpTyApps tys) (HsVar (noLoc fun_id)))++nlHsTyApps :: name -> [Type] -> [LHsExpr name] -> LHsExpr name+nlHsTyApps fun_id tys xs = foldl nlHsApp (nlHsTyApp fun_id tys) xs++--------- Adding parens ---------+mkLHsPar :: LHsExpr name -> LHsExpr name+-- Wrap in parens if hsExprNeedsParens says it needs them+-- So 'f x' becomes '(f x)', but '3' stays as '3'+mkLHsPar le@(L loc e) | hsExprNeedsParens e = L loc (HsPar le)+ | otherwise = le++mkParPat :: LPat name -> LPat name+mkParPat lp@(L loc p) | hsPatNeedsParens p = L loc (ParPat lp)+ | otherwise = lp++nlParPat :: LPat name -> LPat name+nlParPat p = noLoc (ParPat p)++-------------------------------+-- These are the bits of syntax that contain rebindable names+-- See RnEnv.lookupSyntaxName++mkHsIntegral :: SourceText -> Integer -> PostTc RdrName Type+ -> HsOverLit RdrName+mkHsFractional :: FractionalLit -> PostTc RdrName Type -> HsOverLit RdrName+mkHsIsString :: SourceText -> FastString -> PostTc RdrName Type+ -> HsOverLit RdrName+mkHsDo :: HsStmtContext Name -> [ExprLStmt RdrName] -> HsExpr RdrName+mkHsComp :: HsStmtContext Name -> [ExprLStmt RdrName] -> LHsExpr RdrName+ -> HsExpr RdrName++mkNPat :: Located (HsOverLit RdrName) -> Maybe (SyntaxExpr RdrName) -> Pat RdrName+mkNPlusKPat :: Located RdrName -> Located (HsOverLit RdrName) -> Pat RdrName++mkLastStmt :: Located (bodyR idR) -> StmtLR idL idR (Located (bodyR idR))+mkBodyStmt :: Located (bodyR RdrName)+ -> StmtLR idL RdrName (Located (bodyR RdrName))+mkBindStmt :: (PostTc idR Type ~ PlaceHolder)+ => LPat idL -> Located (bodyR idR)+ -> StmtLR idL idR (Located (bodyR idR))+mkTcBindStmt :: LPat Id -> Located (bodyR Id) -> StmtLR Id Id (Located (bodyR Id))++emptyRecStmt :: StmtLR idL RdrName bodyR+emptyRecStmtName :: StmtLR Name Name bodyR+emptyRecStmtId :: StmtLR Id Id bodyR+mkRecStmt :: [LStmtLR idL RdrName bodyR] -> StmtLR idL RdrName bodyR+++mkHsIntegral src i = OverLit (HsIntegral src i) noRebindableInfo noExpr+mkHsFractional f = OverLit (HsFractional f) noRebindableInfo noExpr+mkHsIsString src s = OverLit (HsIsString src s) noRebindableInfo noExpr++noRebindableInfo :: PlaceHolder+noRebindableInfo = PlaceHolder -- Just another placeholder;++mkHsDo ctxt stmts = HsDo ctxt (mkLocatedList stmts) placeHolderType+mkHsComp ctxt stmts expr = mkHsDo ctxt (stmts ++ [last_stmt])+ where+ last_stmt = L (getLoc expr) $ mkLastStmt expr++mkHsIf :: LHsExpr id -> LHsExpr id -> LHsExpr id -> HsExpr id+mkHsIf c a b = HsIf (Just noSyntaxExpr) c a b++mkNPat lit neg = NPat lit neg noSyntaxExpr placeHolderType+mkNPlusKPat id lit = NPlusKPat id lit (unLoc lit) noSyntaxExpr noSyntaxExpr placeHolderType++mkTransformStmt :: (PostTc idR Type ~ PlaceHolder)+ => [ExprLStmt idL] -> LHsExpr idR+ -> StmtLR idL idR (LHsExpr idL)+mkTransformByStmt :: (PostTc idR Type ~ PlaceHolder)+ => [ExprLStmt idL] -> LHsExpr idR -> LHsExpr idR+ -> StmtLR idL idR (LHsExpr idL)+mkGroupUsingStmt :: (PostTc idR Type ~ PlaceHolder)+ => [ExprLStmt idL] -> LHsExpr idR+ -> StmtLR idL idR (LHsExpr idL)+mkGroupByUsingStmt :: (PostTc idR Type ~ PlaceHolder)+ => [ExprLStmt idL] -> LHsExpr idR -> LHsExpr idR+ -> StmtLR idL idR (LHsExpr idL)++emptyTransStmt :: (PostTc idR Type ~ PlaceHolder) => StmtLR idL idR (LHsExpr idR)+emptyTransStmt = TransStmt { trS_form = panic "emptyTransStmt: form"+ , trS_stmts = [], trS_bndrs = []+ , trS_by = Nothing, trS_using = noLoc noExpr+ , trS_ret = noSyntaxExpr, trS_bind = noSyntaxExpr+ , trS_bind_arg_ty = PlaceHolder+ , trS_fmap = noExpr }+mkTransformStmt ss u = emptyTransStmt { trS_form = ThenForm, trS_stmts = ss, trS_using = u }+mkTransformByStmt ss u b = emptyTransStmt { trS_form = ThenForm, trS_stmts = ss, trS_using = u, trS_by = Just b }+mkGroupUsingStmt ss u = emptyTransStmt { trS_form = GroupForm, trS_stmts = ss, trS_using = u }+mkGroupByUsingStmt ss b u = emptyTransStmt { trS_form = GroupForm, trS_stmts = ss, trS_using = u, trS_by = Just b }++mkLastStmt body = LastStmt body False noSyntaxExpr+mkBodyStmt body = BodyStmt body noSyntaxExpr noSyntaxExpr placeHolderType+mkBindStmt pat body = BindStmt pat body noSyntaxExpr noSyntaxExpr PlaceHolder+mkTcBindStmt pat body = BindStmt pat body noSyntaxExpr noSyntaxExpr unitTy+ -- don't use placeHolderTypeTc above, because that panics during zonking++emptyRecStmt' :: forall idL idR body.+ PostTc idR Type -> StmtLR idL idR body+emptyRecStmt' tyVal =+ RecStmt+ { recS_stmts = [], recS_later_ids = []+ , recS_rec_ids = []+ , recS_ret_fn = noSyntaxExpr+ , recS_mfix_fn = noSyntaxExpr+ , recS_bind_fn = noSyntaxExpr, recS_bind_ty = tyVal+ , recS_later_rets = []+ , recS_rec_rets = [], recS_ret_ty = tyVal }++emptyRecStmt = emptyRecStmt' placeHolderType+emptyRecStmtName = emptyRecStmt' placeHolderType+emptyRecStmtId = emptyRecStmt' unitTy -- a panic might trigger during zonking+mkRecStmt stmts = emptyRecStmt { recS_stmts = stmts }++-------------------------------+--- A useful function for building @OpApps@. The operator is always a+-- variable, and we don't know the fixity yet.+mkHsOpApp :: LHsExpr id -> id -> LHsExpr id -> HsExpr id+mkHsOpApp e1 op e2 = OpApp e1 (noLoc (HsVar (noLoc op)))+ (error "mkOpApp:fixity") e2++unqualSplice :: RdrName+unqualSplice = mkRdrUnqual (mkVarOccFS (fsLit "splice"))++mkUntypedSplice :: SpliceDecoration -> LHsExpr RdrName -> HsSplice RdrName+mkUntypedSplice hasParen e = HsUntypedSplice hasParen unqualSplice e++mkHsSpliceE :: SpliceDecoration -> LHsExpr RdrName -> HsExpr RdrName+mkHsSpliceE hasParen e = HsSpliceE (mkUntypedSplice hasParen e)++mkHsSpliceTE :: SpliceDecoration -> LHsExpr RdrName -> HsExpr RdrName+mkHsSpliceTE hasParen e = HsSpliceE (HsTypedSplice hasParen unqualSplice e)++mkHsSpliceTy :: SpliceDecoration -> LHsExpr RdrName -> HsType RdrName+mkHsSpliceTy hasParen e+ = HsSpliceTy (HsUntypedSplice hasParen unqualSplice e) placeHolderKind++mkHsQuasiQuote :: RdrName -> SrcSpan -> FastString -> HsSplice RdrName+mkHsQuasiQuote quoter span quote = HsQuasiQuote unqualSplice quoter span quote++unqualQuasiQuote :: RdrName+unqualQuasiQuote = mkRdrUnqual (mkVarOccFS (fsLit "quasiquote"))+ -- A name (uniquified later) to+ -- identify the quasi-quote++mkHsString :: String -> HsLit+mkHsString s = HsString NoSourceText (mkFastString s)++mkHsStringPrimLit :: FastString -> HsLit+mkHsStringPrimLit fs+ = HsStringPrim NoSourceText (fastStringToByteString fs)++-------------+userHsLTyVarBndrs :: SrcSpan -> [Located name] -> [LHsTyVarBndr name]+-- Caller sets location+userHsLTyVarBndrs loc bndrs = [ L loc (UserTyVar v) | v <- bndrs ]++userHsTyVarBndrs :: SrcSpan -> [name] -> [LHsTyVarBndr name]+-- Caller sets location+userHsTyVarBndrs loc bndrs = [ L loc (UserTyVar (L loc v)) | v <- bndrs ]+++{-+************************************************************************+* *+ Constructing syntax with no location info+* *+************************************************************************+-}++nlHsVar :: id -> LHsExpr id+nlHsVar n = noLoc (HsVar (noLoc n))++-- NB: Only for LHsExpr **Id**+nlHsDataCon :: DataCon -> LHsExpr Id+nlHsDataCon con = noLoc (HsConLikeOut (RealDataCon con))++nlHsLit :: HsLit -> LHsExpr id+nlHsLit n = noLoc (HsLit n)++nlVarPat :: id -> LPat id+nlVarPat n = noLoc (VarPat (noLoc n))++nlLitPat :: HsLit -> LPat id+nlLitPat l = noLoc (LitPat l)++nlHsApp :: LHsExpr id -> LHsExpr id -> LHsExpr id+nlHsApp f x = noLoc (HsApp f (mkLHsPar x))++nlHsSyntaxApps :: SyntaxExpr id -> [LHsExpr id] -> LHsExpr id+nlHsSyntaxApps (SyntaxExpr { syn_expr = fun+ , syn_arg_wraps = arg_wraps+ , syn_res_wrap = res_wrap }) args+ | [] <- arg_wraps -- in the noSyntaxExpr case+ = ASSERT( isIdHsWrapper res_wrap )+ foldl nlHsApp (noLoc fun) args++ | otherwise+ = mkLHsWrap res_wrap (foldl nlHsApp (noLoc fun) (zipWithEqual "nlHsSyntaxApps"+ mkLHsWrap arg_wraps args))++nlHsIntLit :: Integer -> LHsExpr id+nlHsIntLit n = noLoc (HsLit (HsInt NoSourceText n))++nlHsApps :: id -> [LHsExpr id] -> LHsExpr id+nlHsApps f xs = foldl nlHsApp (nlHsVar f) xs++nlHsVarApps :: id -> [id] -> LHsExpr id+nlHsVarApps f xs = noLoc (foldl mk (HsVar (noLoc f)) (map (HsVar . noLoc) xs))+ where+ mk f a = HsApp (noLoc f) (noLoc a)++nlConVarPat :: RdrName -> [RdrName] -> LPat RdrName+nlConVarPat con vars = nlConPat con (map nlVarPat vars)++nlConVarPatName :: Name -> [Name] -> LPat Name+nlConVarPatName con vars = nlConPatName con (map nlVarPat vars)++nlInfixConPat :: id -> LPat id -> LPat id -> LPat id+nlInfixConPat con l r = noLoc (ConPatIn (noLoc con) (InfixCon l r))++nlConPat :: RdrName -> [LPat RdrName] -> LPat RdrName+nlConPat con pats = noLoc (ConPatIn (noLoc con) (PrefixCon pats))++nlConPatName :: Name -> [LPat Name] -> LPat Name+nlConPatName con pats = noLoc (ConPatIn (noLoc con) (PrefixCon pats))++nlNullaryConPat :: id -> LPat id+nlNullaryConPat con = noLoc (ConPatIn (noLoc con) (PrefixCon []))++nlWildConPat :: DataCon -> LPat RdrName+nlWildConPat con = noLoc (ConPatIn (noLoc (getRdrName con))+ (PrefixCon (nOfThem (dataConSourceArity con)+ nlWildPat)))++nlWildPat :: LPat RdrName+nlWildPat = noLoc (WildPat placeHolderType ) -- Pre-typechecking++nlWildPatName :: LPat Name+nlWildPatName = noLoc (WildPat placeHolderType ) -- Pre-typechecking++nlWildPatId :: LPat Id+nlWildPatId = noLoc (WildPat placeHolderTypeTc ) -- Post-typechecking++nlHsDo :: HsStmtContext Name -> [LStmt RdrName (LHsExpr RdrName)]+ -> LHsExpr RdrName+nlHsDo ctxt stmts = noLoc (mkHsDo ctxt stmts)++nlHsOpApp :: LHsExpr id -> id -> LHsExpr id -> LHsExpr id+nlHsOpApp e1 op e2 = noLoc (mkHsOpApp e1 op e2)++nlHsLam :: LMatch RdrName (LHsExpr RdrName) -> LHsExpr RdrName+nlHsPar :: LHsExpr id -> LHsExpr id+nlHsIf :: LHsExpr id -> LHsExpr id -> LHsExpr id -> LHsExpr id+nlHsCase :: LHsExpr RdrName -> [LMatch RdrName (LHsExpr RdrName)]+ -> LHsExpr RdrName+nlList :: [LHsExpr RdrName] -> LHsExpr RdrName++nlHsLam match = noLoc (HsLam (mkMatchGroup Generated [match]))+nlHsPar e = noLoc (HsPar e)++-- Note [Rebindable nlHsIf]+-- nlHsIf should generate if-expressions which are NOT subject to+-- RebindableSyntax, so the first field of HsIf is Nothing. (#12080)+nlHsIf cond true false = noLoc (HsIf Nothing cond true false)++nlHsCase expr matches = noLoc (HsCase expr (mkMatchGroup Generated matches))+nlList exprs = noLoc (ExplicitList placeHolderType Nothing exprs)++nlHsAppTy :: LHsType name -> LHsType name -> LHsType name+nlHsTyVar :: name -> LHsType name+nlHsFunTy :: LHsType name -> LHsType name -> LHsType name+nlHsParTy :: LHsType name -> LHsType name++nlHsAppTy f t = noLoc (HsAppTy f t)+nlHsTyVar x = noLoc (HsTyVar NotPromoted (noLoc x))+nlHsFunTy a b = noLoc (HsFunTy a b)+nlHsParTy t = noLoc (HsParTy t)++nlHsTyConApp :: name -> [LHsType name] -> LHsType name+nlHsTyConApp tycon tys = foldl nlHsAppTy (nlHsTyVar tycon) tys++{-+Tuples. All these functions are *pre-typechecker* because they lack+types on the tuple.+-}++mkLHsTupleExpr :: [LHsExpr a] -> LHsExpr a+-- Makes a pre-typechecker boxed tuple, deals with 1 case+mkLHsTupleExpr [e] = e+mkLHsTupleExpr es = noLoc $ ExplicitTuple (map (noLoc . Present) es) Boxed++mkLHsVarTuple :: [a] -> LHsExpr a+mkLHsVarTuple ids = mkLHsTupleExpr (map nlHsVar ids)++nlTuplePat :: [LPat id] -> Boxity -> LPat id+nlTuplePat pats box = noLoc (TuplePat pats box [])++missingTupArg :: HsTupArg RdrName+missingTupArg = Missing placeHolderType++mkLHsPatTup :: [LPat id] -> LPat id+mkLHsPatTup [] = noLoc $ TuplePat [] Boxed []+mkLHsPatTup [lpat] = lpat+mkLHsPatTup lpats = L (getLoc (head lpats)) $ TuplePat lpats Boxed []++-- The Big equivalents for the source tuple expressions+mkBigLHsVarTup :: [id] -> LHsExpr id+mkBigLHsVarTup ids = mkBigLHsTup (map nlHsVar ids)++mkBigLHsTup :: [LHsExpr id] -> LHsExpr id+mkBigLHsTup = mkChunkified mkLHsTupleExpr++-- The Big equivalents for the source tuple patterns+mkBigLHsVarPatTup :: [id] -> LPat id+mkBigLHsVarPatTup bs = mkBigLHsPatTup (map nlVarPat bs)++mkBigLHsPatTup :: [LPat id] -> LPat id+mkBigLHsPatTup = mkChunkified mkLHsPatTup++-- $big_tuples+-- #big_tuples#+--+-- GHCs built in tuples can only go up to 'mAX_TUPLE_SIZE' in arity, but+-- we might concievably want to build such a massive tuple as part of the+-- output of a desugaring stage (notably that for list comprehensions).+--+-- We call tuples above this size \"big tuples\", and emulate them by+-- creating and pattern matching on >nested< tuples that are expressible+-- by GHC.+--+-- Nesting policy: it's better to have a 2-tuple of 10-tuples (3 objects)+-- than a 10-tuple of 2-tuples (11 objects), so we want the leaves of any+-- construction to be big.+--+-- If you just use the 'mkBigCoreTup', 'mkBigCoreVarTupTy', 'mkTupleSelector'+-- and 'mkTupleCase' functions to do all your work with tuples you should be+-- fine, and not have to worry about the arity limitation at all.++-- | Lifts a \"small\" constructor into a \"big\" constructor by recursive decompositon+mkChunkified :: ([a] -> a) -- ^ \"Small\" constructor function, of maximum input arity 'mAX_TUPLE_SIZE'+ -> [a] -- ^ Possible \"big\" list of things to construct from+ -> a -- ^ Constructed thing made possible by recursive decomposition+mkChunkified small_tuple as = mk_big_tuple (chunkify as)+ where+ -- Each sub-list is short enough to fit in a tuple+ mk_big_tuple [as] = small_tuple as+ mk_big_tuple as_s = mk_big_tuple (chunkify (map small_tuple as_s))++chunkify :: [a] -> [[a]]+-- ^ Split a list into lists that are small enough to have a corresponding+-- tuple arity. The sub-lists of the result all have length <= 'mAX_TUPLE_SIZE'+-- But there may be more than 'mAX_TUPLE_SIZE' sub-lists+chunkify xs+ | n_xs <= mAX_TUPLE_SIZE = [xs]+ | otherwise = split xs+ where+ n_xs = length xs+ split [] = []+ split xs = take mAX_TUPLE_SIZE xs : split (drop mAX_TUPLE_SIZE xs)++{-+************************************************************************+* *+ LHsSigType and LHsSigWcType+* *+********************************************************************* -}++mkLHsSigType :: LHsType RdrName -> LHsSigType RdrName+mkLHsSigType ty = mkHsImplicitBndrs ty++mkLHsSigWcType :: LHsType RdrName -> LHsSigWcType RdrName+mkLHsSigWcType ty = mkHsWildCardBndrs (mkHsImplicitBndrs ty)++mkHsSigEnv :: forall a. (LSig Name -> Maybe ([Located Name], a))+ -> [LSig Name]+ -> NameEnv a+mkHsSigEnv get_info sigs+ = mkNameEnv (mk_pairs ordinary_sigs)+ `extendNameEnvList` (mk_pairs gen_dm_sigs)+ -- The subtlety is this: in a class decl with a+ -- default-method signature as well as a method signature+ -- we want the latter to win (Trac #12533)+ -- class C x where+ -- op :: forall a . x a -> x a+ -- default op :: forall b . x b -> x b+ -- op x = ...(e :: b -> b)...+ -- The scoped type variables of the 'default op', namely 'b',+ -- scope over the code for op. The 'forall a' does not!+ -- This applies both in the renamer and typechecker, both+ -- of which use this function+ where+ (gen_dm_sigs, ordinary_sigs) = partition is_gen_dm_sig sigs+ is_gen_dm_sig (L _ (ClassOpSig True _ _)) = True+ is_gen_dm_sig _ = False++ mk_pairs :: [LSig Name] -> [(Name, a)]+ mk_pairs sigs = [ (n,a) | Just (ns,a) <- map get_info sigs+ , L _ n <- ns ]++mkClassOpSigs :: [LSig RdrName] -> [LSig RdrName]+-- Convert TypeSig to ClassOpSig+-- The former is what is parsed, but the latter is+-- what we need in class/instance declarations+mkClassOpSigs sigs+ = map fiddle sigs+ where+ fiddle (L loc (TypeSig nms ty)) = L loc (ClassOpSig False nms (dropWildCards ty))+ fiddle sig = sig++typeToLHsType :: Type -> LHsType RdrName+-- ^ Converting a Type to an HsType RdrName+-- This is needed to implement GeneralizedNewtypeDeriving.+--+-- Note that we use 'getRdrName' extensively, which+-- generates Exact RdrNames rather than strings.+typeToLHsType ty+ = go ty+ where+ go :: Type -> LHsType RdrName+ go ty@(FunTy arg _)+ | isPredTy arg+ , (theta, tau) <- tcSplitPhiTy ty+ = noLoc (HsQualTy { hst_ctxt = noLoc (map go theta)+ , hst_body = go tau })+ go (FunTy arg res) = nlHsFunTy (go arg) (go res)+ go ty@(ForAllTy {})+ | (tvs, tau) <- tcSplitForAllTys ty+ = noLoc (HsForAllTy { hst_bndrs = map go_tv tvs+ , hst_body = go tau })+ go (TyVarTy tv) = nlHsTyVar (getRdrName tv)+ go (AppTy t1 t2) = nlHsAppTy (go t1) (go t2)+ go (LitTy (NumTyLit n)) = noLoc $ HsTyLit (HsNumTy NoSourceText n)+ go (LitTy (StrTyLit s)) = noLoc $ HsTyLit (HsStrTy NoSourceText s)+ go (TyConApp tc args) = nlHsTyConApp (getRdrName tc) (map go args')+ where+ args' = filterOutInvisibleTypes tc args+ go (CastTy ty _) = go ty+ go (CoercionTy co) = pprPanic "toLHsSigWcType" (ppr co)++ -- Source-language types have _invisible_ kind arguments,+ -- so we must remove them here (Trac #8563)++ go_tv :: TyVar -> LHsTyVarBndr RdrName+ go_tv tv = noLoc $ KindedTyVar (noLoc (getRdrName tv))+ (go (tyVarKind tv))+++{- *********************************************************************+* *+ --------- HsWrappers: type args, dict args, casts ---------+* *+********************************************************************* -}++mkLHsWrap :: HsWrapper -> LHsExpr id -> LHsExpr id+mkLHsWrap co_fn (L loc e) = L loc (mkHsWrap co_fn e)++mkHsWrap :: HsWrapper -> HsExpr id -> HsExpr id+mkHsWrap co_fn e | isIdHsWrapper co_fn = e+ | otherwise = HsWrap co_fn e++mkHsWrapCo :: TcCoercionN -- A Nominal coercion a ~N b+ -> HsExpr id -> HsExpr id+mkHsWrapCo co e = mkHsWrap (mkWpCastN co) e++mkHsWrapCoR :: TcCoercionR -- A Representational coercion a ~R b+ -> HsExpr id -> HsExpr id+mkHsWrapCoR co e = mkHsWrap (mkWpCastR co) e++mkLHsWrapCo :: TcCoercionN -> LHsExpr id -> LHsExpr id+mkLHsWrapCo co (L loc e) = L loc (mkHsWrapCo co e)++mkHsCmdWrap :: HsWrapper -> HsCmd id -> HsCmd id+mkHsCmdWrap w cmd | isIdHsWrapper w = cmd+ | otherwise = HsCmdWrap w cmd++mkLHsCmdWrap :: HsWrapper -> LHsCmd id -> LHsCmd id+mkLHsCmdWrap w (L loc c) = L loc (mkHsCmdWrap w c)++mkHsWrapPat :: HsWrapper -> Pat id -> Type -> Pat id+mkHsWrapPat co_fn p ty | isIdHsWrapper co_fn = p+ | otherwise = CoPat co_fn p ty++mkHsWrapPatCo :: TcCoercionN -> Pat id -> Type -> Pat id+mkHsWrapPatCo co pat ty | isTcReflCo co = pat+ | otherwise = CoPat (mkWpCastN co) pat ty++mkHsDictLet :: TcEvBinds -> LHsExpr Id -> LHsExpr Id+mkHsDictLet ev_binds expr = mkLHsWrap (mkWpLet ev_binds) expr++{-+l+************************************************************************+* *+ Bindings; with a location at the top+* *+************************************************************************+-}++mkFunBind :: Located RdrName -> [LMatch RdrName (LHsExpr RdrName)]+ -> HsBind RdrName+-- Not infix, with place holders for coercion and free vars+mkFunBind fn ms = FunBind { fun_id = fn+ , fun_matches = mkMatchGroup Generated ms+ , fun_co_fn = idHsWrapper+ , bind_fvs = placeHolderNames+ , fun_tick = [] }++mkTopFunBind :: Origin -> Located Name -> [LMatch Name (LHsExpr Name)]+ -> HsBind Name+-- In Name-land, with empty bind_fvs+mkTopFunBind origin fn ms = FunBind { fun_id = fn+ , fun_matches = mkMatchGroup origin ms+ , fun_co_fn = idHsWrapper+ , bind_fvs = emptyNameSet -- NB: closed+ -- binding+ , fun_tick = [] }++mkHsVarBind :: SrcSpan -> RdrName -> LHsExpr RdrName -> LHsBind RdrName+mkHsVarBind loc var rhs = mk_easy_FunBind loc var [] rhs++mkVarBind :: id -> LHsExpr id -> LHsBind id+mkVarBind var rhs = L (getLoc rhs) $+ VarBind { var_id = var, var_rhs = rhs, var_inline = False }++mkPatSynBind :: Located RdrName -> HsPatSynDetails (Located RdrName)+ -> LPat RdrName -> HsPatSynDir RdrName -> HsBind RdrName+mkPatSynBind name details lpat dir = PatSynBind psb+ where+ psb = PSB{ psb_id = name+ , psb_args = details+ , psb_def = lpat+ , psb_dir = dir+ , psb_fvs = placeHolderNames }++-- |If any of the matches in the 'FunBind' are infix, the 'FunBind' is+-- considered infix.+isInfixFunBind :: HsBindLR id1 id2 -> Bool+isInfixFunBind (FunBind _ (MG matches _ _ _) _ _ _)+ = any (isInfixMatch . unLoc) (unLoc matches)+isInfixFunBind _ = False+++------------+mk_easy_FunBind :: SrcSpan -> RdrName -> [LPat RdrName]+ -> LHsExpr RdrName -> LHsBind RdrName+mk_easy_FunBind loc fun pats expr+ = L loc $ mkFunBind (L loc fun)+ [mkMatch (mkPrefixFunRhs (L loc fun)) pats expr+ (noLoc emptyLocalBinds)]++-- | Make a prefix, non-strict function 'HsMatchContext'+mkPrefixFunRhs :: Located id -> HsMatchContext id+mkPrefixFunRhs n = FunRhs n Prefix NoSrcStrict++------------+mkMatch :: HsMatchContext (NameOrRdrName id) -> [LPat id] -> LHsExpr id+ -> Located (HsLocalBinds id) -> LMatch id (LHsExpr id)+mkMatch ctxt pats expr lbinds+ = noLoc (Match ctxt (map paren pats) Nothing+ (GRHSs (unguardedRHS noSrcSpan expr) lbinds))+ where+ paren lp@(L l p) | hsPatNeedsParens p = L l (ParPat lp)+ | otherwise = lp++{-+************************************************************************+* *+ Collecting binders+* *+************************************************************************++Get all the binders in some HsBindGroups, IN THE ORDER OF APPEARANCE. eg.++...+where+ (x, y) = ...+ f i j = ...+ [a, b] = ...++it should return [x, y, f, a, b] (remember, order important).++Note [Collect binders only after renaming]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+These functions should only be used on HsSyn *after* the renamer,+to return a [Name] or [Id]. Before renaming the record punning+and wild-card mechanism makes it hard to know what is bound.+So these functions should not be applied to (HsSyn RdrName)++Note [Unlifted id check in isHsUnliftedBind]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose there is a binding with the type (Num a => (# a, a #)). Is this a+strict binding that should be disallowed at the top level? At first glance,+no, because it's a function. But consider how this is desugared via+AbsBinds:++ -- x :: Num a => (# a, a #)+ x = (# 3, 4 #)++becomes++ x = \ $dictNum ->+ let x_mono = (# fromInteger $dictNum 3, fromInteger $dictNum 4 #) in+ x_mono++Note that the inner let is strict. And thus if we have a bunch of mutually+recursive bindings of this form, we could end up in trouble. This was shown+up in #9140.++But if there is a type signature on x, everything changes because of the+desugaring used by AbsBindsSig:++ x :: Num a => (# a, a #)+ x = (# 3, 4 #)++becomes++ x = \ $dictNum -> (# fromInteger $dictNum 3, fromInteger $dictNum 4 #)++No strictness anymore! The bottom line here is that, for inferred types, we+care about the strictness of the type after the =>. For checked types+(AbsBindsSig), we care about the overall strictness.++This matters. If we don't separate out the AbsBindsSig case, then GHC runs into+a problem when compiling++ undefined :: forall (r :: RuntimeRep) (a :: TYPE r). HasCallStack => a++Looking only after the =>, we cannot tell if this is strict or not. (GHC panics+if you try.) Looking at the whole type, on the other hand, tells you that this+is a lifted function type, with no trouble at all.++-}++----------------- Bindings --------------------------++-- | Should we treat this as an unlifted bind? This will be true for any+-- bind that binds an unlifted variable, but we must be careful around+-- AbsBinds. See Note [Unlifted id check in isUnliftedHsBind]. For usage+-- information, see Note [Strict binds check] is DsBinds.+isUnliftedHsBind :: HsBind Id -> Bool -- works only over typechecked binds+isUnliftedHsBind (AbsBindsSig { abs_sig_export = id })+ = isUnliftedType (idType id)+isUnliftedHsBind bind+ = any is_unlifted_id (collectHsBindBinders bind)+ where+ is_unlifted_id id+ = case tcSplitSigmaTy (idType id) of+ (_, _, tau) -> isUnliftedType tau+ -- For the is_unlifted check, we need to look inside polymorphism+ -- and overloading. E.g. x = (# 1, True #)+ -- would get type forall a. Num a => (# a, Bool #)+ -- and we want to reject that. See Trac #9140++-- | Is a binding a strict variable bind (e.g. @!x = ...@)?+isBangedBind :: HsBind Id -> Bool+isBangedBind b | isBangedPatBind b = True+isBangedBind (FunBind {fun_matches = matches})+ | [L _ match] <- unLoc $ mg_alts matches+ , FunRhs{mc_strictness = SrcStrict} <- m_ctxt match+ = True+isBangedBind _ = False++collectLocalBinders :: HsLocalBindsLR idL idR -> [idL]+collectLocalBinders (HsValBinds binds) = collectHsIdBinders binds+ -- No pattern synonyms here+collectLocalBinders (HsIPBinds _) = []+collectLocalBinders EmptyLocalBinds = []++collectHsIdBinders, collectHsValBinders :: HsValBindsLR idL idR -> [idL]+-- Collect Id binders only, or Ids + pattern synonyms, respectively+collectHsIdBinders = collect_hs_val_binders True+collectHsValBinders = collect_hs_val_binders False++collectHsBindBinders :: HsBindLR idL idR -> [idL]+-- Collect both Ids and pattern-synonym binders+collectHsBindBinders b = collect_bind False b []++collectHsBindsBinders :: LHsBindsLR idL idR -> [idL]+collectHsBindsBinders binds = collect_binds False binds []++collectHsBindListBinders :: [LHsBindLR idL idR] -> [idL]+-- Same as collectHsBindsBinders, but works over a list of bindings+collectHsBindListBinders = foldr (collect_bind False . unLoc) []++collect_hs_val_binders :: Bool -> HsValBindsLR idL idR -> [idL]+collect_hs_val_binders ps (ValBindsIn binds _) = collect_binds ps binds []+collect_hs_val_binders ps (ValBindsOut binds _) = collect_out_binds ps binds++collect_out_binds :: Bool -> [(RecFlag, LHsBinds id)] -> [id]+collect_out_binds ps = foldr (collect_binds ps . snd) []++collect_binds :: Bool -> LHsBindsLR idL idR -> [idL] -> [idL]+-- Collect Ids, or Ids + pattern synonyms, depending on boolean flag+collect_binds ps binds acc = foldrBag (collect_bind ps . unLoc) acc binds++collect_bind :: Bool -> HsBindLR idL idR -> [idL] -> [idL]+collect_bind _ (PatBind { pat_lhs = p }) acc = collect_lpat p acc+collect_bind _ (FunBind { fun_id = L _ f }) acc = f : acc+collect_bind _ (VarBind { var_id = f }) acc = f : acc+collect_bind _ (AbsBinds { abs_exports = dbinds }) acc = map abe_poly dbinds ++ acc+ -- I don't think we want the binders from the abe_binds+ -- The only time we collect binders from a typechecked+ -- binding (hence see AbsBinds) is in zonking in TcHsSyn+collect_bind _ (AbsBindsSig { abs_sig_export = poly }) acc = poly : acc+collect_bind omitPatSyn (PatSynBind (PSB { psb_id = L _ ps })) acc+ | omitPatSyn = acc+ | otherwise = ps : acc++collectMethodBinders :: LHsBindsLR RdrName idR -> [Located RdrName]+-- Used exclusively for the bindings of an instance decl which are all FunBinds+collectMethodBinders binds = foldrBag (get . unLoc) [] binds+ where+ get (FunBind { fun_id = f }) fs = f : fs+ get _ fs = fs+ -- Someone else complains about non-FunBinds++----------------- Statements --------------------------+collectLStmtsBinders :: [LStmtLR idL idR body] -> [idL]+collectLStmtsBinders = concatMap collectLStmtBinders++collectStmtsBinders :: [StmtLR idL idR body] -> [idL]+collectStmtsBinders = concatMap collectStmtBinders++collectLStmtBinders :: LStmtLR idL idR body -> [idL]+collectLStmtBinders = collectStmtBinders . unLoc++collectStmtBinders :: StmtLR idL idR body -> [idL]+ -- Id Binders for a Stmt... [but what about pattern-sig type vars]?+collectStmtBinders (BindStmt pat _ _ _ _)= collectPatBinders pat+collectStmtBinders (LetStmt (L _ binds)) = collectLocalBinders binds+collectStmtBinders (BodyStmt {}) = []+collectStmtBinders (LastStmt {}) = []+collectStmtBinders (ParStmt xs _ _ _) = collectLStmtsBinders+ $ [s | ParStmtBlock ss _ _ <- xs, s <- ss]+collectStmtBinders (TransStmt { trS_stmts = stmts }) = collectLStmtsBinders stmts+collectStmtBinders (RecStmt { recS_stmts = ss }) = collectLStmtsBinders ss+collectStmtBinders ApplicativeStmt{} = []+++----------------- Patterns --------------------------+collectPatBinders :: LPat a -> [a]+collectPatBinders pat = collect_lpat pat []++collectPatsBinders :: [LPat a] -> [a]+collectPatsBinders pats = foldr collect_lpat [] pats++-------------+collect_lpat :: LPat name -> [name] -> [name]+collect_lpat (L _ pat) bndrs+ = go pat+ where+ go (VarPat (L _ var)) = var : bndrs+ go (WildPat _) = bndrs+ go (LazyPat pat) = collect_lpat pat bndrs+ go (BangPat pat) = collect_lpat pat bndrs+ go (AsPat (L _ a) pat) = a : collect_lpat pat bndrs+ go (ViewPat _ pat _) = collect_lpat pat bndrs+ go (ParPat pat) = collect_lpat pat bndrs++ go (ListPat pats _ _) = foldr collect_lpat bndrs pats+ go (PArrPat pats _) = foldr collect_lpat bndrs pats+ go (TuplePat pats _ _) = foldr collect_lpat bndrs pats+ go (SumPat pat _ _ _) = collect_lpat pat bndrs++ go (ConPatIn _ ps) = foldr collect_lpat bndrs (hsConPatArgs ps)+ go (ConPatOut {pat_args=ps}) = foldr collect_lpat bndrs (hsConPatArgs ps)+ -- See Note [Dictionary binders in ConPatOut]+ go (LitPat _) = bndrs+ go (NPat {}) = bndrs+ go (NPlusKPat (L _ n) _ _ _ _ _)= n : bndrs++ go (SigPatIn pat _) = collect_lpat pat bndrs+ go (SigPatOut pat _) = collect_lpat pat bndrs++ go (SplicePat (HsSpliced _ (HsSplicedPat pat)))+ = go pat+ go (SplicePat _) = bndrs+ go (CoPat _ pat _) = go pat++{-+Note [Dictionary binders in ConPatOut] See also same Note in DsArrows+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Do *not* gather (a) dictionary and (b) dictionary bindings as binders+of a ConPatOut pattern. For most calls it doesn't matter, because+it's pre-typechecker and there are no ConPatOuts. But it does matter+more in the desugarer; for example, DsUtils.mkSelectorBinds uses+collectPatBinders. In a lazy pattern, for example f ~(C x y) = ...,+we want to generate bindings for x,y but not for dictionaries bound by+C. (The type checker ensures they would not be used.)++Desugaring of arrow case expressions needs these bindings (see DsArrows+and arrowcase1), but SPJ (Jan 2007) says it's safer for it to use its+own pat-binder-collector:++Here's the problem. Consider++data T a where+ C :: Num a => a -> Int -> T a++f ~(C (n+1) m) = (n,m)++Here, the pattern (C (n+1)) binds a hidden dictionary (d::Num a),+and *also* uses that dictionary to match the (n+1) pattern. Yet, the+variables bound by the lazy pattern are n,m, *not* the dictionary d.+So in mkSelectorBinds in DsUtils, we want just m,n as the variables bound.+-}++hsGroupBinders :: HsGroup Name -> [Name]+hsGroupBinders (HsGroup { hs_valds = val_decls, hs_tyclds = tycl_decls,+ hs_fords = foreign_decls })+ = collectHsValBinders val_decls+ ++ hsTyClForeignBinders tycl_decls foreign_decls++hsTyClForeignBinders :: [TyClGroup Name]+ -> [LForeignDecl Name]+ -> [Name]+-- We need to look at instance declarations too,+-- because their associated types may bind data constructors+hsTyClForeignBinders tycl_decls foreign_decls+ = map unLoc (hsForeignDeclsBinders foreign_decls)+ ++ getSelectorNames+ (foldMap (foldMap hsLTyClDeclBinders . group_tyclds) tycl_decls+ `mappend`+ foldMap (foldMap hsLInstDeclBinders . group_instds) tycl_decls)+ where+ getSelectorNames :: ([Located Name], [LFieldOcc Name]) -> [Name]+ getSelectorNames (ns, fs) = map unLoc ns ++ map (selectorFieldOcc.unLoc) fs++-------------------+hsLTyClDeclBinders :: Located (TyClDecl name) -> ([Located name], [LFieldOcc name])+-- ^ Returns all the /binding/ names of the decl. The first one is++-- guaranteed to be the name of the decl. The first component+-- represents all binding names except record fields; the second+-- represents field occurrences. For record fields mentioned in+-- multiple constructors, the SrcLoc will be from the first occurrence.+--+-- Each returned (Located name) has a SrcSpan for the /whole/ declaration.+-- See Note [SrcSpan for binders]++hsLTyClDeclBinders (L loc (FamDecl { tcdFam = FamilyDecl { fdLName = L _ name } }))+ = ([L loc name], [])+hsLTyClDeclBinders (L loc (SynDecl { tcdLName = L _ name })) = ([L loc name], [])+hsLTyClDeclBinders (L loc (ClassDecl { tcdLName = L _ cls_name+ , tcdSigs = sigs, tcdATs = ats }))+ = (L loc cls_name :+ [ L fam_loc fam_name | L fam_loc (FamilyDecl { fdLName = L _ fam_name }) <- ats ] +++ [ L mem_loc mem_name | L mem_loc (ClassOpSig False ns _) <- sigs, L _ mem_name <- ns ]+ , [])+hsLTyClDeclBinders (L loc (DataDecl { tcdLName = L _ name, tcdDataDefn = defn }))+ = (\ (xs, ys) -> (L loc name : xs, ys)) $ hsDataDefnBinders defn++-------------------+hsForeignDeclsBinders :: [LForeignDecl name] -> [Located name]+-- See Note [SrcSpan for binders]+hsForeignDeclsBinders foreign_decls+ = [ L decl_loc n+ | L decl_loc (ForeignImport { fd_name = L _ n }) <- foreign_decls]+++-------------------+hsPatSynSelectors :: HsValBinds id -> [id]+-- Collects record pattern-synonym selectors only; the pattern synonym+-- names are collected by collectHsValBinders.+hsPatSynSelectors (ValBindsIn _ _) = panic "hsPatSynSelectors"+hsPatSynSelectors (ValBindsOut binds _)+ = foldrBag addPatSynSelector [] . unionManyBags $ map snd binds++addPatSynSelector:: LHsBind id -> [id] -> [id]+addPatSynSelector bind sels+ | L _ (PatSynBind (PSB { psb_args = RecordPatSyn as })) <- bind+ = map (unLoc . recordPatSynSelectorId) as ++ sels+ | otherwise = sels++getPatSynBinds :: [(RecFlag, LHsBinds id)] -> [PatSynBind id id]+getPatSynBinds binds+ = [ psb | (_, lbinds) <- binds+ , L _ (PatSynBind psb) <- bagToList lbinds ]++-------------------+hsLInstDeclBinders :: LInstDecl name -> ([Located name], [LFieldOcc name])+hsLInstDeclBinders (L _ (ClsInstD { cid_inst = ClsInstDecl { cid_datafam_insts = dfis } }))+ = foldMap (hsDataFamInstBinders . unLoc) dfis+hsLInstDeclBinders (L _ (DataFamInstD { dfid_inst = fi }))+ = hsDataFamInstBinders fi+hsLInstDeclBinders (L _ (TyFamInstD {})) = mempty++-------------------+-- the SrcLoc returned are for the whole declarations, not just the names+hsDataFamInstBinders :: DataFamInstDecl name -> ([Located name], [LFieldOcc name])+hsDataFamInstBinders (DataFamInstDecl { dfid_defn = defn })+ = hsDataDefnBinders defn+ -- There can't be repeated symbols because only data instances have binders++-------------------+-- the SrcLoc returned are for the whole declarations, not just the names+hsDataDefnBinders :: HsDataDefn name -> ([Located name], [LFieldOcc name])+hsDataDefnBinders (HsDataDefn { dd_cons = cons })+ = hsConDeclsBinders cons+ -- See Note [Binders in family instances]++-------------------+hsConDeclsBinders :: [LConDecl name] -> ([Located name], [LFieldOcc name])+ -- See hsLTyClDeclBinders for what this does+ -- The function is boringly complicated because of the records+ -- And since we only have equality, we have to be a little careful+hsConDeclsBinders cons = go id cons+ where go :: ([LFieldOcc name] -> [LFieldOcc name])+ -> [LConDecl name] -> ([Located name], [LFieldOcc name])+ go _ [] = ([], [])+ go remSeen (r:rs) =+ -- don't re-mangle the location of field names, because we don't+ -- have a record of the full location of the field declaration anyway+ case r of+ -- remove only the first occurrence of any seen field in order to+ -- avoid circumventing detection of duplicate fields (#9156)+ L loc (ConDeclGADT { con_names = names+ , con_type = HsIB { hsib_body = res_ty}}) ->+ case tau of+ L _ (HsFunTy+ (L _ (HsAppsTy+ [L _ (HsAppPrefix (L _ (HsRecTy flds)))])) _res_ty)+ -> record_gadt flds+ L _ (HsFunTy (L _ (HsRecTy flds)) _res_ty)+ -> record_gadt flds++ _other -> (map (L loc . unLoc) names ++ ns, fs)+ where (ns, fs) = go remSeen rs+ where+ (_tvs, _cxt, tau) = splitLHsSigmaTy res_ty+ record_gadt flds = (map (L loc . unLoc) names ++ ns, r' ++ fs)+ where r' = remSeen (concatMap (cd_fld_names . unLoc) flds)+ remSeen' = foldr (.) remSeen+ [deleteBy ((==) `on`+ unLoc . rdrNameFieldOcc . unLoc) v+ | v <- r']+ (ns, fs) = go remSeen' rs++ L loc (ConDeclH98 { con_name = name+ , con_details = RecCon flds }) ->+ ([L loc (unLoc name)] ++ ns, r' ++ fs)+ where r' = remSeen (concatMap (cd_fld_names . unLoc)+ (unLoc flds))+ remSeen'+ = foldr (.) remSeen+ [deleteBy ((==) `on`+ unLoc . rdrNameFieldOcc . unLoc) v | v <- r']+ (ns, fs) = go remSeen' rs+ L loc (ConDeclH98 { con_name = name }) ->+ ([L loc (unLoc name)] ++ ns, fs)+ where (ns, fs) = go remSeen rs++{-++Note [SrcSpan for binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~+When extracting the (Located RdrNme) for a binder, at least for the+main name (the TyCon of a type declaration etc), we want to give it+the @SrcSpan@ of the whole /declaration/, not just the name itself+(which is how it appears in the syntax tree). This SrcSpan (for the+entire declaration) is used as the SrcSpan for the Name that is+finally produced, and hence for error messages. (See Trac #8607.)++Note [Binders in family instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a type or data family instance declaration, the type+constructor is an *occurrence* not a binding site+ type instance T Int = Int -> Int -- No binders+ data instance S Bool = S1 | S2 -- Binders are S1,S2+++************************************************************************+* *+ Collecting binders the user did not write+* *+************************************************************************++The job of this family of functions is to run through binding sites and find the set of all Names+that were defined "implicitly", without being explicitly written by the user.++The main purpose is to find names introduced by record wildcards so that we can avoid+warning the user when they don't use those names (#4404)+-}++lStmtsImplicits :: [LStmtLR Name idR (Located (body idR))] -> NameSet+lStmtsImplicits = hs_lstmts+ where+ hs_lstmts :: [LStmtLR Name idR (Located (body idR))] -> NameSet+ hs_lstmts = foldr (\stmt rest -> unionNameSet (hs_stmt (unLoc stmt)) rest) emptyNameSet++ hs_stmt :: StmtLR Name idR (Located (body idR)) -> NameSet+ hs_stmt (BindStmt pat _ _ _ _) = lPatImplicits pat+ hs_stmt (ApplicativeStmt args _ _) = unionNameSets (map do_arg args)+ where do_arg (_, ApplicativeArgOne pat _) = lPatImplicits pat+ do_arg (_, ApplicativeArgMany stmts _ _) = hs_lstmts stmts+ hs_stmt (LetStmt binds) = hs_local_binds (unLoc binds)+ hs_stmt (BodyStmt {}) = emptyNameSet+ hs_stmt (LastStmt {}) = emptyNameSet+ hs_stmt (ParStmt xs _ _ _) = hs_lstmts [s | ParStmtBlock ss _ _ <- xs, s <- ss]+ hs_stmt (TransStmt { trS_stmts = stmts }) = hs_lstmts stmts+ hs_stmt (RecStmt { recS_stmts = ss }) = hs_lstmts ss++ hs_local_binds (HsValBinds val_binds) = hsValBindsImplicits val_binds+ hs_local_binds (HsIPBinds _) = emptyNameSet+ hs_local_binds EmptyLocalBinds = emptyNameSet++hsValBindsImplicits :: HsValBindsLR Name idR -> NameSet+hsValBindsImplicits (ValBindsOut binds _)+ = foldr (unionNameSet . lhsBindsImplicits . snd) emptyNameSet binds+hsValBindsImplicits (ValBindsIn binds _)+ = lhsBindsImplicits binds++lhsBindsImplicits :: LHsBindsLR Name idR -> NameSet+lhsBindsImplicits = foldBag unionNameSet (lhs_bind . unLoc) emptyNameSet+ where+ lhs_bind (PatBind { pat_lhs = lpat }) = lPatImplicits lpat+ lhs_bind _ = emptyNameSet++lPatImplicits :: LPat Name -> NameSet+lPatImplicits = hs_lpat+ where+ hs_lpat (L _ pat) = hs_pat pat++ hs_lpats = foldr (\pat rest -> hs_lpat pat `unionNameSet` rest) emptyNameSet++ hs_pat (LazyPat pat) = hs_lpat pat+ hs_pat (BangPat pat) = hs_lpat pat+ hs_pat (AsPat _ pat) = hs_lpat pat+ hs_pat (ViewPat _ pat _) = hs_lpat pat+ hs_pat (ParPat pat) = hs_lpat pat+ hs_pat (ListPat pats _ _) = hs_lpats pats+ hs_pat (PArrPat pats _) = hs_lpats pats+ hs_pat (TuplePat pats _ _) = hs_lpats pats++ hs_pat (SigPatIn pat _) = hs_lpat pat+ hs_pat (SigPatOut pat _) = hs_lpat pat+ hs_pat (CoPat _ pat _) = hs_pat pat++ hs_pat (ConPatIn _ ps) = details ps+ hs_pat (ConPatOut {pat_args=ps}) = details ps++ hs_pat _ = emptyNameSet++ details (PrefixCon ps) = hs_lpats ps+ details (RecCon fs) = hs_lpats explicit `unionNameSet` mkNameSet (collectPatsBinders implicit)+ where (explicit, implicit) = partitionEithers [if pat_explicit then Left pat else Right pat+ | (i, fld) <- [0..] `zip` rec_flds fs+ , let pat = hsRecFieldArg+ (unLoc fld)+ pat_explicit = maybe True (i<) (rec_dotdot fs)]+ details (InfixCon p1 p2) = hs_lpat p1 `unionNameSet` hs_lpat p2
+ hsSyn/PlaceHolder.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE StandaloneDeriving #-}++module PlaceHolder where++import Type ( Type )+import Outputable+import Name+import NameSet+import RdrName+import Var+import Coercion+import ConLike (ConLike)+import FieldLabel+import SrcLoc (Located)+import TcEvidence ( HsWrapper )++import Data.Data hiding ( Fixity )+import BasicTypes (Fixity)+++{-+%************************************************************************+%* *+\subsection{Annotating the syntax}+%* *+%************************************************************************+-}++-- NB: These are intentionally open, allowing API consumers (like Haddock)+-- to declare new instances++-- | used as place holder in PostTc and PostRn values+data PlaceHolder = PlaceHolder+ deriving (Data)++-- | Types that are not defined until after type checking+type family PostTc id ty -- Note [Pass sensitive types]+type instance PostTc Id ty = ty+type instance PostTc Name ty = PlaceHolder+type instance PostTc RdrName ty = PlaceHolder++-- | Types that are not defined until after renaming+type family PostRn id ty -- Note [Pass sensitive types]+type instance PostRn Id ty = ty+type instance PostRn Name ty = ty+type instance PostRn RdrName ty = PlaceHolder++placeHolderKind :: PlaceHolder+placeHolderKind = PlaceHolder++placeHolderFixity :: PlaceHolder+placeHolderFixity = PlaceHolder++placeHolderType :: PlaceHolder+placeHolderType = PlaceHolder++placeHolderTypeTc :: Type+placeHolderTypeTc = panic "Evaluated the place holder for a PostTcType"++placeHolderNames :: PlaceHolder+placeHolderNames = PlaceHolder++placeHolderNamesTc :: NameSet+placeHolderNamesTc = emptyNameSet++placeHolderHsWrapper :: PlaceHolder+placeHolderHsWrapper = PlaceHolder++{-++Note [Pass sensitive types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Since the same AST types are re-used through parsing,renaming and type+checking there are naturally some places in the AST that do not have+any meaningful value prior to the pass they are assigned a value.++Historically these have been filled in with place holder values of the form++ panic "error message"++This has meant the AST is difficult to traverse using standard generic+programming techniques. The problem is addressed by introducing+pass-specific data types, implemented as a pair of open type families,+one for PostTc and one for PostRn. These are then explicitly populated+with a PlaceHolder value when they do not yet have meaning.++In terms of actual usage, we have the following++ PostTc id Kind+ PostTc id Type++ PostRn id Fixity+ PostRn id NameSet++TcId and Var are synonyms for Id++Unfortunately the type checker termination checking conditions fail for the+DataId constraint type based on this, so even though it is safe the+UndecidableInstances pragma is required where this is used.+-}++type DataId id =+ ( DataIdPost id+ , DataIdPost (NameOrRdrName id)+ )++type DataIdPost id =+ ( Data id+ , Data (PostRn id NameSet)+ , Data (PostRn id Fixity)+ , Data (PostRn id Bool)+ , Data (PostRn id Name)+ , Data (PostRn id (Located Name))+ , Data (PostRn id [Name])++ , Data (PostRn id id)+ , Data (PostTc id Type)+ , Data (PostTc id Coercion)+ , Data (PostTc id id)+ , Data (PostTc id [Type])+ , Data (PostTc id ConLike)+ , Data (PostTc id [ConLike])+ , Data (PostTc id HsWrapper)+ , Data (PostTc id [FieldLabel])+ )+++-- |Follow the @id@, but never beyond Name. This is used in a 'HsMatchContext',+-- for printing messages related to a 'Match'+type family NameOrRdrName id where+ NameOrRdrName Id = Name+ NameOrRdrName Name = Name+ NameOrRdrName RdrName = RdrName++-- |Constraint type to bundle up the requirement for 'OutputableBndr' on both+-- the @id@ and the 'NameOrRdrName' type for it+type OutputableBndrId id =+ ( OutputableBndr id+ , OutputableBndr (NameOrRdrName id)+ )
+ iface/BinFingerprint.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE CPP #-}++-- | Computing fingerprints of values serializeable with GHC's "Binary" module.+module BinFingerprint+ ( -- * Computing fingerprints+ fingerprintBinMem+ , computeFingerprint+ , putNameLiterally+ ) where++#include "HsVersions.h"++import Fingerprint+import Binary+import Name+import Panic+import Util++fingerprintBinMem :: BinHandle -> IO Fingerprint+fingerprintBinMem bh = withBinBuffer bh f+ where+ f bs =+ -- we need to take care that we force the result here+ -- lest a reference to the ByteString may leak out of+ -- withBinBuffer.+ let fp = fingerprintByteString bs+ in fp `seq` return fp++computeFingerprint :: (Binary a)+ => (BinHandle -> Name -> IO ())+ -> a+ -> IO Fingerprint+computeFingerprint put_nonbinding_name a = do+ bh <- fmap set_user_data $ openBinMem (3*1024) -- just less than a block+ put_ bh a+ fp <- fingerprintBinMem bh+ return fp+ where+ set_user_data bh =+ setUserData bh $ newWriteState put_nonbinding_name putNameLiterally putFS++-- | Used when we want to fingerprint a structure without depending on the+-- fingerprints of external Names that it refers to.+putNameLiterally :: BinHandle -> Name -> IO ()+putNameLiterally bh name = ASSERT( isExternalName name ) do+ put_ bh $! nameModule name+ put_ bh $! nameOccName name
+ iface/BinIface.hs view
@@ -0,0 +1,390 @@+{-# LANGUAGE BinaryLiterals, CPP, ScopedTypeVariables #-}++--+-- (c) The University of Glasgow 2002-2006+--++{-# OPTIONS_GHC -O #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected++-- | Binary interface file support.+module BinIface (+ writeBinIface,+ readBinIface,+ getSymtabName,+ getDictFastString,+ CheckHiWay(..),+ TraceBinIFaceReading(..)+ ) where++#include "HsVersions.h"++import TcRnMonad+import PrelInfo ( isKnownKeyName, lookupKnownKeyName )+import IfaceEnv+import HscTypes+import Module+import Name+import DynFlags+import UniqFM+import UniqSupply+import Panic+import Binary+import SrcLoc+import ErrUtils+import FastMutInt+import Unique+import Outputable+import NameCache+import Platform+import FastString+import Constants+import Util++import Data.Bits+import Data.Char+import Data.List+import Data.Word+import Data.Array+import Data.IORef+import Control.Monad+++-- ---------------------------------------------------------------------------+-- Reading and writing binary interface files+--++data CheckHiWay = CheckHiWay | IgnoreHiWay+ deriving Eq++data TraceBinIFaceReading = TraceBinIFaceReading | QuietBinIFaceReading+ deriving Eq++-- | Read an interface file+readBinIface :: CheckHiWay -> TraceBinIFaceReading -> FilePath+ -> TcRnIf a b ModIface+readBinIface checkHiWay traceBinIFaceReading hi_path = do+ ncu <- mkNameCacheUpdater+ dflags <- getDynFlags+ liftIO $ readBinIface_ dflags checkHiWay traceBinIFaceReading hi_path ncu++readBinIface_ :: DynFlags -> CheckHiWay -> TraceBinIFaceReading -> FilePath+ -> NameCacheUpdater+ -> IO ModIface+readBinIface_ dflags checkHiWay traceBinIFaceReading hi_path ncu = do+ let printer :: SDoc -> IO ()+ printer = case traceBinIFaceReading of+ TraceBinIFaceReading -> \sd ->+ putLogMsg dflags+ NoReason+ SevOutput+ noSrcSpan+ (defaultDumpStyle dflags)+ sd+ QuietBinIFaceReading -> \_ -> return ()+ wantedGot :: Outputable a => String -> a -> a -> IO ()+ wantedGot what wanted got =+ printer (text what <> text ": " <>+ vcat [text "Wanted " <> ppr wanted <> text ",",+ text "got " <> ppr got])++ errorOnMismatch :: (Eq a, Show a) => String -> a -> a -> IO ()+ errorOnMismatch what wanted got =+ -- This will be caught by readIface which will emit an error+ -- msg containing the iface module name.+ when (wanted /= got) $ throwGhcExceptionIO $ ProgramError+ (what ++ " (wanted " ++ show wanted+ ++ ", got " ++ show got ++ ")")+ bh <- Binary.readBinMem hi_path++ -- Read the magic number to check that this really is a GHC .hi file+ -- (This magic number does not change when we change+ -- GHC interface file format)+ magic <- get bh+ wantedGot "Magic" (binaryInterfaceMagic dflags) magic+ errorOnMismatch "magic number mismatch: old/corrupt interface file?"+ (binaryInterfaceMagic dflags) magic++ -- Note [dummy iface field]+ -- read a dummy 32/64 bit value. This field used to hold the+ -- dictionary pointer in old interface file formats, but now+ -- the dictionary pointer is after the version (where it+ -- should be). Also, the serialisation of value of type "Bin+ -- a" used to depend on the word size of the machine, now they+ -- are always 32 bits.+ if wORD_SIZE dflags == 4+ then do _ <- Binary.get bh :: IO Word32; return ()+ else do _ <- Binary.get bh :: IO Word64; return ()++ -- Check the interface file version and ways.+ check_ver <- get bh+ let our_ver = show hiVersion+ wantedGot "Version" our_ver check_ver+ errorOnMismatch "mismatched interface file versions" our_ver check_ver++ check_way <- get bh+ let way_descr = getWayDescr dflags+ wantedGot "Way" way_descr check_way+ when (checkHiWay == CheckHiWay) $+ errorOnMismatch "mismatched interface file ways" way_descr check_way++ -- Read the dictionary+ -- The next word in the file is a pointer to where the dictionary is+ -- (probably at the end of the file)+ dict_p <- Binary.get bh+ data_p <- tellBin bh -- Remember where we are now+ seekBin bh dict_p+ dict <- getDictionary bh+ seekBin bh data_p -- Back to where we were before++ -- Initialise the user-data field of bh+ bh <- do+ bh <- return $ setUserData bh $ newReadState (error "getSymtabName")+ (getDictFastString dict)+ symtab_p <- Binary.get bh -- Get the symtab ptr+ data_p <- tellBin bh -- Remember where we are now+ seekBin bh symtab_p+ symtab <- getSymbolTable bh ncu+ seekBin bh data_p -- Back to where we were before++ -- It is only now that we know how to get a Name+ return $ setUserData bh $ newReadState (getSymtabName ncu dict symtab)+ (getDictFastString dict)++ -- Read the interface file+ get bh++-- | Write an interface file+writeBinIface :: DynFlags -> FilePath -> ModIface -> IO ()+writeBinIface dflags hi_path mod_iface = do+ bh <- openBinMem initBinMemSize+ put_ bh (binaryInterfaceMagic dflags)++ -- dummy 32/64-bit field before the version/way for+ -- compatibility with older interface file formats.+ -- See Note [dummy iface field] above.+ if wORD_SIZE dflags == 4+ then Binary.put_ bh (0 :: Word32)+ else Binary.put_ bh (0 :: Word64)++ -- The version and way descriptor go next+ put_ bh (show hiVersion)+ let way_descr = getWayDescr dflags+ put_ bh way_descr++ -- Remember where the dictionary pointer will go+ dict_p_p <- tellBin bh+ -- Placeholder for ptr to dictionary+ put_ bh dict_p_p++ -- Remember where the symbol table pointer will go+ symtab_p_p <- tellBin bh+ put_ bh symtab_p_p++ -- Make some intial state+ symtab_next <- newFastMutInt+ writeFastMutInt symtab_next 0+ symtab_map <- newIORef emptyUFM+ let bin_symtab = BinSymbolTable {+ bin_symtab_next = symtab_next,+ bin_symtab_map = symtab_map }+ dict_next_ref <- newFastMutInt+ writeFastMutInt dict_next_ref 0+ dict_map_ref <- newIORef emptyUFM+ let bin_dict = BinDictionary {+ bin_dict_next = dict_next_ref,+ bin_dict_map = dict_map_ref }++ -- Put the main thing,+ bh <- return $ setUserData bh $ newWriteState (putName bin_dict bin_symtab)+ (putName bin_dict bin_symtab)+ (putFastString bin_dict)+ put_ bh mod_iface++ -- Write the symtab pointer at the front of the file+ symtab_p <- tellBin bh -- This is where the symtab will start+ putAt bh symtab_p_p symtab_p -- Fill in the placeholder+ seekBin bh symtab_p -- Seek back to the end of the file++ -- Write the symbol table itself+ symtab_next <- readFastMutInt symtab_next+ symtab_map <- readIORef symtab_map+ putSymbolTable bh symtab_next symtab_map+ debugTraceMsg dflags 3 (text "writeBinIface:" <+> int symtab_next+ <+> text "Names")++ -- NB. write the dictionary after the symbol table, because+ -- writing the symbol table may create more dictionary entries.++ -- Write the dictionary pointer at the fornt of the file+ dict_p <- tellBin bh -- This is where the dictionary will start+ putAt bh dict_p_p dict_p -- Fill in the placeholder+ seekBin bh dict_p -- Seek back to the end of the file++ -- Write the dictionary itself+ dict_next <- readFastMutInt dict_next_ref+ dict_map <- readIORef dict_map_ref+ putDictionary bh dict_next dict_map+ debugTraceMsg dflags 3 (text "writeBinIface:" <+> int dict_next+ <+> text "dict entries")++ -- And send the result to the file+ writeBinMem bh hi_path++-- | Initial ram buffer to allocate for writing interface files+initBinMemSize :: Int+initBinMemSize = 1024 * 1024++binaryInterfaceMagic :: DynFlags -> Word32+binaryInterfaceMagic dflags+ | target32Bit (targetPlatform dflags) = 0x1face+ | otherwise = 0x1face64+++-- -----------------------------------------------------------------------------+-- The symbol table+--++putSymbolTable :: BinHandle -> Int -> UniqFM (Int,Name) -> IO ()+putSymbolTable bh next_off symtab = do+ put_ bh next_off+ let names = elems (array (0,next_off-1) (nonDetEltsUFM symtab))+ -- It's OK to use nonDetEltsUFM here because the elements have+ -- indices that array uses to create order+ mapM_ (\n -> serialiseName bh n symtab) names++getSymbolTable :: BinHandle -> NameCacheUpdater -> IO SymbolTable+getSymbolTable bh ncu = do+ sz <- get bh+ od_names <- sequence (replicate sz (get bh))+ updateNameCache ncu $ \namecache ->+ let arr = listArray (0,sz-1) names+ (namecache', names) =+ mapAccumR (fromOnDiskName arr) namecache od_names+ in (namecache', arr)++type OnDiskName = (UnitId, ModuleName, OccName)++fromOnDiskName :: Array Int Name -> NameCache -> OnDiskName -> (NameCache, Name)+fromOnDiskName _ nc (pid, mod_name, occ) =+ let mod = mkModule pid mod_name+ cache = nsNames nc+ in case lookupOrigNameCache cache mod occ of+ Just name -> (nc, name)+ Nothing ->+ let (uniq, us) = takeUniqFromSupply (nsUniqs nc)+ name = mkExternalName uniq mod occ noSrcSpan+ new_cache = extendNameCache cache mod occ name+ in ( nc{ nsUniqs = us, nsNames = new_cache }, name )++serialiseName :: BinHandle -> Name -> UniqFM (Int,Name) -> IO ()+serialiseName bh name _ = do+ let mod = ASSERT2( isExternalName name, ppr name ) nameModule name+ put_ bh (moduleUnitId mod, moduleName mod, nameOccName name)+++-- Note [Symbol table representation of names]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- An occurrence of a name in an interface file is serialized as a single 32-bit+-- word. The format of this word is:+-- 00xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx+-- A normal name. x is an index into the symbol table+-- 10xxxxxx xxyyyyyy yyyyyyyy yyyyyyyy+-- A known-key name. x is the Unique's Char, y is the int part. We assume that+-- all known-key uniques fit in this space. This is asserted by+-- PrelInfo.knownKeyNamesOkay.+--+-- During serialization we check for known-key things using isKnownKeyName.+-- During deserialization we use lookupKnownKeyName to get from the unique back+-- to its corresponding Name.+++-- See Note [Symbol table representation of names]+putName :: BinDictionary -> BinSymbolTable -> BinHandle -> Name -> IO ()+putName _dict BinSymbolTable{+ bin_symtab_map = symtab_map_ref,+ bin_symtab_next = symtab_next }+ bh name+ | isKnownKeyName name+ , let (c, u) = unpkUnique (nameUnique name) -- INVARIANT: (ord c) fits in 8 bits+ = -- ASSERT(u < 2^(22 :: Int))+ put_ bh (0x80000000+ .|. (fromIntegral (ord c) `shiftL` 22)+ .|. (fromIntegral u :: Word32))++ | otherwise+ = do symtab_map <- readIORef symtab_map_ref+ case lookupUFM symtab_map name of+ Just (off,_) -> put_ bh (fromIntegral off :: Word32)+ Nothing -> do+ off <- readFastMutInt symtab_next+ -- MASSERT(off < 2^(30 :: Int))+ writeFastMutInt symtab_next (off+1)+ writeIORef symtab_map_ref+ $! addToUFM symtab_map name (off,name)+ put_ bh (fromIntegral off :: Word32)++-- See Note [Symbol table representation of names]+getSymtabName :: NameCacheUpdater+ -> Dictionary -> SymbolTable+ -> BinHandle -> IO Name+getSymtabName _ncu _dict symtab bh = do+ i :: Word32 <- get bh+ case i .&. 0xC0000000 of+ 0x00000000 -> return $! symtab ! fromIntegral i++ 0x80000000 ->+ let+ tag = chr (fromIntegral ((i .&. 0x3FC00000) `shiftR` 22))+ ix = fromIntegral i .&. 0x003FFFFF+ u = mkUnique tag ix+ in+ return $! case lookupKnownKeyName u of+ Nothing -> pprPanic "getSymtabName:unknown known-key unique"+ (ppr i $$ ppr (unpkUnique u))+ Just n -> n++ _ -> pprPanic "getSymtabName:unknown name tag" (ppr i)++data BinSymbolTable = BinSymbolTable {+ bin_symtab_next :: !FastMutInt, -- The next index to use+ bin_symtab_map :: !(IORef (UniqFM (Int,Name)))+ -- indexed by Name+ }++putFastString :: BinDictionary -> BinHandle -> FastString -> IO ()+putFastString dict bh fs = allocateFastString dict fs >>= put_ bh++allocateFastString :: BinDictionary -> FastString -> IO Word32+allocateFastString BinDictionary { bin_dict_next = j_r,+ bin_dict_map = out_r} f = do+ out <- readIORef out_r+ let uniq = getUnique f+ case lookupUFM out uniq of+ Just (j, _) -> return (fromIntegral j :: Word32)+ Nothing -> do+ j <- readFastMutInt j_r+ writeFastMutInt j_r (j + 1)+ writeIORef out_r $! addToUFM out uniq (j, f)+ return (fromIntegral j :: Word32)++getDictFastString :: Dictionary -> BinHandle -> IO FastString+getDictFastString dict bh = do+ j <- get bh+ return $! (dict ! fromIntegral (j :: Word32))++data BinDictionary = BinDictionary {+ bin_dict_next :: !FastMutInt, -- The next index to use+ bin_dict_map :: !(IORef (UniqFM (Int,FastString)))+ -- indexed by FastString+ }++getWayDescr :: DynFlags -> String+getWayDescr dflags+ | platformUnregisterised (targetPlatform dflags) = 'u':tag+ | otherwise = tag+ where tag = buildTag dflags+ -- if this is an unregisterised build, make sure our interfaces+ -- can't be used by a registerised build.
+ iface/BuildTyCl.hs view
@@ -0,0 +1,476 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP #-}++module BuildTyCl (+ buildDataCon, mkDataConUnivTyVarBinders,+ buildPatSyn,+ TcMethInfo, buildClass,+ mkNewTyConRhs, mkDataTyConRhs,+ newImplicitBinder, newTyConRepName+ ) where++#include "HsVersions.h"++import IfaceEnv+import FamInstEnv( FamInstEnvs, mkNewTypeCoAxiom )+import TysWiredIn( isCTupleTyConName )+import TysPrim ( voidPrimTy )+import DataCon+import PatSyn+import Var+import VarSet+import BasicTypes+import Name+import MkId+import Class+import TyCon+import Type+import Id+import TcType++import SrcLoc( SrcSpan, noSrcSpan )+import DynFlags+import TcRnMonad+import UniqSupply+import Util+import Outputable++mkDataTyConRhs :: [DataCon] -> AlgTyConRhs+mkDataTyConRhs cons+ = DataTyCon {+ data_cons = cons,+ is_enum = not (null cons) && all is_enum_con cons+ -- See Note [Enumeration types] in TyCon+ }+ where+ is_enum_con con+ | (_univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res)+ <- dataConFullSig con+ = null ex_tvs && null eq_spec && null theta && null arg_tys+++mkNewTyConRhs :: Name -> TyCon -> DataCon -> TcRnIf m n AlgTyConRhs+-- ^ Monadic because it makes a Name for the coercion TyCon+-- We pass the Name of the parent TyCon, as well as the TyCon itself,+-- because the latter is part of a knot, whereas the former is not.+mkNewTyConRhs tycon_name tycon con+ = 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 } ) }+ -- Coreview looks through newtypes with a Nothing+ -- for nt_co, or uses explicit coercions otherwise+ where+ tvs = tyConTyVars tycon+ roles = tyConRoles tycon+ inst_con_ty = piResultTys (dataConUserType con) (mkTyVarTys tvs)+ rhs_ty = ASSERT( isFunTy inst_con_ty ) funArgTy inst_con_ty+ -- Instantiate the data con with the+ -- type variables from the tycon+ -- NB: a newtype DataCon has a type that must look like+ -- forall tvs. <arg-ty> -> T tvs+ -- Note that we *can't* use dataConInstOrigArgTys here because+ -- the newtype arising from class Foo a => Bar a where {}+ -- has a single argument (Foo a) that is a *type class*, so+ -- dataConInstOrigArgTys returns [].++ etad_tvs :: [TyVar] -- Matched lazily, so that mkNewTypeCo can+ etad_roles :: [Role] -- return a TyCon without pulling on rhs_ty+ etad_rhs :: Type -- See Note [Tricky iface loop] in LoadIface+ (etad_tvs, etad_roles, etad_rhs) = eta_reduce (reverse tvs) (reverse roles) rhs_ty++ eta_reduce :: [TyVar] -- Reversed+ -> [Role] -- also reversed+ -> Type -- Rhs type+ -> ([TyVar], [Role], Type) -- Eta-reduced version+ -- (tyvars in normal order)+ eta_reduce (a:as) (_:rs) ty | Just (fun, arg) <- splitAppTy_maybe ty,+ Just tv <- getTyVar_maybe arg,+ tv == a,+ not (a `elemVarSet` tyCoVarsOfType fun)+ = eta_reduce as rs fun+ eta_reduce tvs rs ty = (reverse tvs, reverse rs, ty)++------------------------------------------------------+buildDataCon :: FamInstEnvs+ -> Name+ -> Bool -- Declared infix+ -> TyConRepName+ -> [HsSrcBang]+ -> Maybe [HsImplBang]+ -- See Note [Bangs on imported data constructors] in MkId+ -> [FieldLabel] -- Field labels+ -> [TyVarBinder] -- Universals+ -> [TyVarBinder] -- Existentials+ -> [EqSpec] -- Equality spec+ -> ThetaType -- Does not include the "stupid theta"+ -- or the GADT equalities+ -> [Type] -> Type -- Argument and result types+ -> TyCon -- Rep tycon+ -> TcRnIf m n DataCon+-- A wrapper for DataCon.mkDataCon that+-- a) makes the worker Id+-- b) makes the wrapper Id if necessary, including+-- allocating its unique (hence monadic)+-- c) Sorts out the TyVarBinders. See mkDataConUnivTyBinders+buildDataCon fam_envs src_name declared_infix prom_info src_bangs impl_bangs field_lbls+ univ_tvs ex_tvs eq_spec ctxt arg_tys res_ty rep_tycon+ = do { wrap_name <- newImplicitBinder src_name mkDataConWrapperOcc+ ; work_name <- newImplicitBinder src_name mkDataConWorkerOcc+ -- This last one takes the name of the data constructor in the source+ -- code, which (for Haskell source anyway) will be in the DataName name+ -- space, and puts it into the VarName name space++ ; traceIf (text "buildDataCon 1" <+> ppr src_name)+ ; us <- newUniqueSupply+ ; dflags <- getDynFlags+ ; let stupid_ctxt = mkDataConStupidTheta rep_tycon arg_tys univ_tvs+ data_con = mkDataCon src_name declared_infix prom_info+ src_bangs field_lbls+ univ_tvs ex_tvs eq_spec ctxt+ arg_tys res_ty NoRRI rep_tycon+ stupid_ctxt dc_wrk dc_rep+ dc_wrk = mkDataConWorkId work_name data_con+ dc_rep = initUs_ us (mkDataConRep dflags fam_envs wrap_name+ impl_bangs data_con)++ ; traceIf (text "buildDataCon 2" <+> ppr src_name)+ ; return data_con }+++-- The stupid context for a data constructor should be limited to+-- the type variables mentioned in the arg_tys+-- ToDo: Or functionally dependent on?+-- This whole stupid theta thing is, well, stupid.+mkDataConStupidTheta :: TyCon -> [Type] -> [TyVarBinder] -> [PredType]+mkDataConStupidTheta tycon arg_tys univ_tvs+ | null stupid_theta = [] -- The common case+ | otherwise = filter in_arg_tys stupid_theta+ where+ tc_subst = zipTvSubst (tyConTyVars tycon)+ (mkTyVarTys (binderVars univ_tvs))+ stupid_theta = substTheta tc_subst (tyConStupidTheta tycon)+ -- Start by instantiating the master copy of the+ -- stupid theta, taken from the TyCon++ arg_tyvars = tyCoVarsOfTypes arg_tys+ in_arg_tys pred = not $ isEmptyVarSet $+ tyCoVarsOfType pred `intersectVarSet` arg_tyvars+++mkDataConUnivTyVarBinders :: [TyConBinder] -- From the TyCon+ -> [TyVarBinder] -- For the DataCon+-- See Note [Building the TyBinders for a DataCon]+mkDataConUnivTyVarBinders tc_bndrs+ = map mk_binder tc_bndrs+ where+ mk_binder (TvBndr tv tc_vis) = mkTyVarBinder vis tv+ where+ vis = case tc_vis of+ AnonTCB -> Specified+ NamedTCB Required -> Specified+ NamedTCB vis -> vis++{- Note [Building the TyBinders for a DataCon]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A DataCon needs to keep track of the visibility of its universals and+existentials, so that visible type application can work properly. This+is done by storing the universal and existential TyVarBinders.+See Note [TyVarBinders in DataCons] in DataCon.++During construction of a DataCon, we often start from the TyBinders of+the parent TyCon. For example+ data Maybe a = Nothing | Just a+The DataCons start from the TyBinders of the parent TyCon.++But the ultimate TyBinders for the DataCon are *different* than those+of the DataCon. Here is an example:++ data App a b = MkApp (a b) -- App :: forall {k}. (k->*) -> k -> *++The TyCon has++ tyConTyVars = [ k:*, a:k->*, b:k]+ tyConTyBinders = [ Named (TvBndr (k :: *) Inferred), Anon (k->*), Anon k ]++The TyBinders for App line up with App's kind, given above.++But the DataCon MkApp has the type+ MkApp :: forall {k} (a:k->*) (b:k). a b -> App k a b++That is, its TyBinders should be++ dataConUnivTyVarBinders = [ TvBndr (k:*) Inferred+ , TvBndr (a:k->*) Specified+ , TvBndr (b:k) Specified ]++So we want to take the TyCon's TyBinders and the TyCon's TyVars and+merge them, pulling+ - variable names from the TyVars+ - visibilities from the TyBinders+ - but changing Anon/Required to Specified++The last part about Required->Specified comes from this:+ data T k (a:k) b = MkT (a b)+Here k is Required in T's kind, but we don't have Required binders in+the TyBinders for a term (see Note [No Required TyBinder in terms]+in TyCoRep), so we change it to Specified when making MkT's TyBinders++This merging operation is done by mkDataConUnivTyBinders. In contrast,+the TyBinders passed to mkDataCon are the final TyBinders stored in the+DataCon (mkDataCon does no further work).+-}++------------------------------------------------------+buildPatSyn :: Name -> Bool+ -> (Id,Bool) -> Maybe (Id, Bool)+ -> ([TyVarBinder], ThetaType) -- ^ Univ and req+ -> ([TyVarBinder], ThetaType) -- ^ Ex and prov+ -> [Type] -- ^ Argument types+ -> Type -- ^ Result type+ -> [FieldLabel] -- ^ Field labels for+ -- a record pattern synonym+ -> PatSyn+buildPatSyn src_name declared_infix matcher@(matcher_id,_) builder+ (univ_tvs, req_theta) (ex_tvs, prov_theta) arg_tys+ pat_ty field_labels+ = -- The assertion checks that the matcher is+ -- compatible with the pattern synonym+ ASSERT2((and [ univ_tvs `equalLength` univ_tvs1+ , ex_tvs `equalLength` ex_tvs1+ , pat_ty `eqType` substTy subst pat_ty1+ , prov_theta `eqTypes` substTys subst prov_theta1+ , req_theta `eqTypes` substTys subst req_theta1+ , compareArgTys arg_tys (substTys subst arg_tys1)+ ])+ , (vcat [ ppr univ_tvs <+> twiddle <+> ppr univ_tvs1+ , ppr ex_tvs <+> twiddle <+> ppr ex_tvs1+ , ppr pat_ty <+> twiddle <+> ppr pat_ty1+ , ppr prov_theta <+> twiddle <+> ppr prov_theta1+ , ppr req_theta <+> twiddle <+> ppr req_theta1+ , ppr arg_tys <+> twiddle <+> ppr arg_tys1]))+ mkPatSyn src_name declared_infix+ (univ_tvs, req_theta) (ex_tvs, prov_theta)+ arg_tys pat_ty+ matcher builder field_labels+ where+ ((_:_:univ_tvs1), req_theta1, tau) = tcSplitSigmaTy $ idType matcher_id+ ([pat_ty1, cont_sigma, _], _) = tcSplitFunTys tau+ (ex_tvs1, prov_theta1, cont_tau) = tcSplitSigmaTy cont_sigma+ (arg_tys1, _) = (tcSplitFunTys cont_tau)+ twiddle = char '~'+ subst = zipTvSubst (univ_tvs1 ++ ex_tvs1)+ (mkTyVarTys (binderVars (univ_tvs ++ ex_tvs)))++ -- For a nullary pattern synonym we add a single void argument to the+ -- matcher to preserve laziness in the case of unlifted types.+ -- See #12746+ compareArgTys :: [Type] -> [Type] -> Bool+ compareArgTys [] [x] = x `eqType` voidPrimTy+ compareArgTys arg_tys matcher_arg_tys = arg_tys `eqTypes` matcher_arg_tys+++------------------------------------------------------+type TcMethInfo -- A temporary intermediate, to communicate+ -- between tcClassSigs and buildClass.+ = ( Name -- Name of the class op+ , Type -- Type of the class op+ , Maybe (DefMethSpec (SrcSpan, Type)))+ -- Nothing => no default method+ --+ -- Just VanillaDM => There is an ordinary+ -- polymorphic default method+ --+ -- Just (GenericDM (loc, ty)) => There is a generic default metho+ -- Here is its type, and the location+ -- of the type signature+ -- We need that location /only/ to attach it to the+ -- generic default method's Name; and we need /that/+ -- only to give the right location of an ambiguity error+ -- for the generic default method, spat out by checkValidClass++buildClass :: Name -- Name of the class/tycon (they have the same Name)+ -> [TyConBinder] -- Of the tycon+ -> [Role]+ -> [FunDep TyVar] -- Functional dependencies+ -- Super classes, associated types, method info, minimal complete def.+ -- This is Nothing if the class is abstract.+ -> Maybe (ThetaType, [ClassATItem], [TcMethInfo], ClassMinimalDef)+ -> TcRnIf m n Class++buildClass tycon_name binders roles fds Nothing+ = fixM $ \ rec_clas -> -- Only name generation inside loop+ do { traceIf (text "buildClass")++ ; tc_rep_name <- newTyConRepName tycon_name+ ; let univ_bndrs = mkDataConUnivTyVarBinders binders+ univ_tvs = binderVars univ_bndrs+ tycon = mkClassTyCon tycon_name binders roles+ AbstractTyCon rec_clas tc_rep_name+ result = mkAbstractClass tycon_name univ_tvs fds tycon+ ; traceIf (text "buildClass" <+> ppr tycon)+ ; return result }++buildClass tycon_name binders roles fds+ (Just (sc_theta, at_items, sig_stuff, mindef))+ = fixM $ \ rec_clas -> -- Only name generation inside loop+ do { traceIf (text "buildClass")++ ; datacon_name <- newImplicitBinder tycon_name mkClassDataConOcc+ ; tc_rep_name <- newTyConRepName tycon_name++ ; op_items <- mapM (mk_op_item rec_clas) sig_stuff+ -- Build the selector id and default method id++ -- Make selectors for the superclasses+ ; sc_sel_names <- mapM (newImplicitBinder tycon_name . mkSuperDictSelOcc)+ (takeList sc_theta [fIRST_TAG..])+ ; let sc_sel_ids = [ mkDictSelId sc_name rec_clas+ | sc_name <- sc_sel_names]+ -- We number off the Dict superclass selectors, 1, 2, 3 etc so that we+ -- can construct names for the selectors. Thus+ -- class (C a, C b) => D a b where ...+ -- gives superclass selectors+ -- D_sc1, D_sc2+ -- (We used to call them D_C, but now we can have two different+ -- superclasses both called C!)++ ; let use_newtype = isSingleton arg_tys+ -- Use a newtype if the data constructor+ -- (a) has exactly one value field+ -- i.e. exactly one operation or superclass taken together+ -- (b) that value is of lifted type (which they always are, because+ -- we box equality superclasses)+ -- See note [Class newtypes and equality predicates]++ -- We treat the dictionary superclasses as ordinary arguments.+ -- That means that in the case of+ -- class C a => D a+ -- we don't get a newtype with no arguments!+ args = sc_sel_names ++ op_names+ op_tys = [ty | (_,ty,_) <- sig_stuff]+ op_names = [op | (op,_,_) <- sig_stuff]+ arg_tys = sc_theta ++ op_tys+ rec_tycon = classTyCon rec_clas+ univ_bndrs = mkDataConUnivTyVarBinders binders+ univ_tvs = binderVars univ_bndrs++ ; rep_nm <- newTyConRepName datacon_name+ ; dict_con <- buildDataCon (panic "buildClass: FamInstEnvs")+ datacon_name+ False -- Not declared infix+ rep_nm+ (map (const no_bang) args)+ (Just (map (const HsLazy) args))+ [{- No fields -}]+ univ_bndrs+ [{- no existentials -}]+ [{- No GADT equalities -}]+ [{- No theta -}]+ arg_tys+ (mkTyConApp rec_tycon (mkTyVarTys univ_tvs))+ rec_tycon++ ; rhs <- case () of+ _ | use_newtype+ -> mkNewTyConRhs tycon_name rec_tycon dict_con+ | isCTupleTyConName tycon_name+ -> return (TupleTyCon { data_con = dict_con+ , tup_sort = ConstraintTuple })+ | otherwise+ -> return (mkDataTyConRhs [dict_con])++ ; let { tycon = mkClassTyCon tycon_name binders roles+ rhs rec_clas tc_rep_name+ -- A class can be recursive, and in the case of newtypes+ -- this matters. For example+ -- class C a where { op :: C b => a -> b -> Int }+ -- Because C has only one operation, it is represented by+ -- a newtype, and it should be a *recursive* newtype.+ -- [If we don't make it a recursive newtype, we'll expand the+ -- newtype like a synonym, but that will lead to an infinite+ -- type]++ ; result = mkClass tycon_name univ_tvs fds+ sc_theta sc_sel_ids at_items+ op_items mindef tycon+ }+ ; traceIf (text "buildClass" <+> ppr tycon)+ ; return result }+ where+ no_bang = HsSrcBang NoSourceText NoSrcUnpack NoSrcStrict++ mk_op_item :: Class -> TcMethInfo -> TcRnIf n m ClassOpItem+ mk_op_item rec_clas (op_name, _, dm_spec)+ = do { dm_info <- mk_dm_info op_name dm_spec+ ; return (mkDictSelId op_name rec_clas, dm_info) }++ mk_dm_info :: Name -> Maybe (DefMethSpec (SrcSpan, Type))+ -> TcRnIf n m (Maybe (Name, DefMethSpec Type))+ mk_dm_info _ Nothing+ = return Nothing+ mk_dm_info op_name (Just VanillaDM)+ = do { dm_name <- newImplicitBinder op_name mkDefaultMethodOcc+ ; return (Just (dm_name, VanillaDM)) }+ mk_dm_info op_name (Just (GenericDM (loc, dm_ty)))+ = do { dm_name <- newImplicitBinderLoc op_name mkDefaultMethodOcc loc+ ; return (Just (dm_name, GenericDM dm_ty)) }++{-+Note [Class newtypes and equality predicates]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ class (a ~ F b) => C a b where+ op :: a -> b++We cannot represent this by a newtype, even though it's not+existential, because there are two value fields (the equality+predicate and op. See Trac #2238++Moreover,+ class (a ~ F b) => C a b where {}+Here we can't use a newtype either, even though there is only+one field, because equality predicates are unboxed, and classes+are boxed.+-}++newImplicitBinder :: Name -- Base name+ -> (OccName -> OccName) -- Occurrence name modifier+ -> TcRnIf m n Name -- Implicit name+-- Called in BuildTyCl to allocate the implicit binders of type/class decls+-- For source type/class decls, this is the first occurrence+-- For iface ones, the LoadIface has already allocated a suitable name in the cache+newImplicitBinder base_name mk_sys_occ+ = newImplicitBinderLoc base_name mk_sys_occ (nameSrcSpan base_name)++newImplicitBinderLoc :: Name -- Base name+ -> (OccName -> OccName) -- Occurrence name modifier+ -> SrcSpan+ -> TcRnIf m n Name -- Implicit name+-- Just the same, but lets you specify the SrcSpan+newImplicitBinderLoc base_name mk_sys_occ loc+ | Just mod <- nameModule_maybe base_name+ = newGlobalBinder mod occ loc+ | otherwise -- When typechecking a [d| decl bracket |],+ -- TH generates types, classes etc with Internal names,+ -- so we follow suit for the implicit binders+ = do { uniq <- newUnique+ ; return (mkInternalName uniq occ loc) }+ where+ occ = mk_sys_occ (nameOccName base_name)++-- | Make the 'TyConRepName' for this 'TyCon'+newTyConRepName :: Name -> TcRnIf gbl lcl TyConRepName+newTyConRepName tc_name+ | Just mod <- nameModule_maybe tc_name+ , (mod, occ) <- tyConRepModOcc mod (nameOccName tc_name)+ = newGlobalBinder mod occ noSrcSpan+ | otherwise+ = newImplicitBinder tc_name mkTyConRepOcc
+ iface/FlagChecker.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE RecordWildCards #-}++-- | This module manages storing the various GHC option flags in a modules+-- interface file as part of the recompilation checking infrastructure.+module FlagChecker (+ fingerprintDynFlags+ ) where++import Binary+import BinIface ()+import DynFlags+import HscTypes+import Module+import Name+import Fingerprint+import BinFingerprint+-- import Outputable++import qualified Data.IntSet as IntSet+import System.FilePath (normalise)++-- | Produce a fingerprint of a @DynFlags@ value. We only base+-- the finger print on important fields in @DynFlags@ so that+-- the recompilation checker can use this fingerprint.+--+-- NB: The 'Module' parameter is the 'Module' recorded by the+-- *interface* file, not the actual 'Module' according to our+-- 'DynFlags'.+fingerprintDynFlags :: DynFlags -> Module+ -> (BinHandle -> Name -> IO ())+ -> IO Fingerprint++fingerprintDynFlags dflags@DynFlags{..} this_mod nameio =+ let mainis = if mainModIs == this_mod then Just mainFunIs else Nothing+ -- see #5878+ -- pkgopts = (thisPackage dflags, sort $ packageFlags dflags)+ safeHs = setSafeMode safeHaskell+ -- oflags = sort $ filter filterOFlags $ flags dflags++ -- *all* the extension flags and the language+ lang = (fmap fromEnum language,+ IntSet.toList $ extensionFlags)++ -- -I, -D and -U flags affect CPP+ cpp = (map normalise includePaths, opt_P dflags ++ picPOpts dflags)+ -- normalise: eliminate spurious differences due to "./foo" vs "foo"++ -- Note [path flags and recompilation]+ paths = [ hcSuf ]++ -- -fprof-auto etc.+ prof = if gopt Opt_SccProfilingOn dflags then fromEnum profAuto else 0++ -- -O, see https://ghc.haskell.org/trac/ghc/ticket/10923+ opt = if hscTarget == HscInterpreted ||+ hscTarget == HscNothing+ then 0+ else optLevel++ -- -fhpc, see https://ghc.haskell.org/trac/ghc/ticket/11798+ -- hpcDir is output-only, so we should recompile if it changes+ hpc = if gopt Opt_Hpc dflags then Just hpcDir else Nothing++ -- Nesting just to avoid ever more Binary tuple instances+ flags = (mainis, safeHs, lang, cpp, paths, (prof, opt, hpc))++ in -- pprTrace "flags" (ppr flags) $+ computeFingerprint nameio flags++{- Note [path flags and recompilation]++There are several flags that we deliberately omit from the+recompilation check; here we explain why.++-osuf, -odir, -hisuf, -hidir+ If GHC decides that it does not need to recompile, then+ it must have found an up-to-date .hi file and .o file.+ There is no point recording these flags - the user must+ have passed the correct ones. Indeed, the user may+ have compiled the source file in one-shot mode using+ -o to specify the .o file, and then loaded it in GHCi+ using -odir.++-stubdir+ We omit this one because it is automatically set by -outputdir, and+ we don't want changes in -outputdir to automatically trigger+ recompilation. This could be wrong, but only in very rare cases.++-i (importPaths)+ For the same reason as -osuf etc. above: if GHC decides not to+ recompile, then it must have already checked all the .hi files on+ which the current module depends, so it must have found them+ successfully. It is occasionally useful to be able to cd to a+ different directory and use -i flags to enable GHC to find the .hi+ files; we don't want this to force recompilation.++The only path-related flag left is -hcsuf.+-}
+ iface/IfaceEnv.hs view
@@ -0,0 +1,272 @@+-- (c) The University of Glasgow 2002-2006++{-# LANGUAGE CPP, RankNTypes #-}++module IfaceEnv (+ newGlobalBinder, newInteractiveBinder,+ externaliseName,+ lookupIfaceTop,+ lookupOrig, lookupOrigNameCache, extendNameCache,+ newIfaceName, newIfaceNames,+ extendIfaceIdEnv, extendIfaceTyVarEnv,+ tcIfaceLclId, tcIfaceTyVar, lookupIfaceVar,+ lookupIfaceTyVar, extendIfaceEnvs,+ setNameModule,++ ifaceExportNames,++ -- Name-cache stuff+ allocateGlobalBinder, updNameCache,+ mkNameCacheUpdater, NameCacheUpdater(..),+ ) where++#include "HsVersions.h"++import TcRnMonad+import HscTypes+import Type+import Var+import Name+import Avail+import Module+import FastString+import FastStringEnv+import IfaceType+import NameCache+import UniqSupply+import SrcLoc++import Outputable+import Data.List ( partition )++{-+*********************************************************+* *+ Allocating new Names in the Name Cache+* *+*********************************************************++See Also: Note [The Name Cache] in NameCache+-}++newGlobalBinder :: Module -> OccName -> SrcSpan -> TcRnIf a b Name+-- Used for source code and interface files, to make the+-- Name for a thing, given its Module and OccName+-- See Note [The Name Cache]+--+-- The cache may already already have a binding for this thing,+-- because we may have seen an occurrence before, but now is the+-- moment when we know its Module and SrcLoc in their full glory++newGlobalBinder mod occ loc+ = do { mod `seq` occ `seq` return () -- See notes with lookupOrig+ ; name <- updNameCache $ \name_cache ->+ allocateGlobalBinder name_cache mod occ loc+ ; traceIf (text "newGlobalBinder" <+>+ (vcat [ ppr mod <+> ppr occ <+> ppr loc, ppr name]))+ ; return name }++newInteractiveBinder :: HscEnv -> OccName -> SrcSpan -> IO Name+-- Works in the IO monad, and gets the Module+-- from the interactive context+newInteractiveBinder hsc_env occ loc+ = do { let mod = icInteractiveModule (hsc_IC hsc_env)+ ; updNameCacheIO hsc_env $ \name_cache ->+ allocateGlobalBinder name_cache mod occ loc }++allocateGlobalBinder+ :: NameCache+ -> Module -> OccName -> SrcSpan+ -> (NameCache, Name)+-- See Note [The Name Cache]+allocateGlobalBinder name_supply mod occ loc+ = case lookupOrigNameCache (nsNames name_supply) mod occ of+ -- A hit in the cache! We are at the binding site of the name.+ -- This is the moment when we know the SrcLoc+ -- of the Name, so we set this field in the Name we return.+ --+ -- Then (bogus) multiple bindings of the same Name+ -- get different SrcLocs can can be reported as such.+ --+ -- Possible other reason: it might be in the cache because we+ -- encountered an occurrence before the binding site for an+ -- implicitly-imported Name. Perhaps the current SrcLoc is+ -- better... but not really: it'll still just say 'imported'+ --+ -- IMPORTANT: Don't mess with wired-in names.+ -- Their wired-in-ness is in their NameSort+ -- and their Module is correct.++ Just name | isWiredInName name+ -> (name_supply, name)+ | otherwise+ -> (new_name_supply, name')+ where+ uniq = nameUnique name+ name' = mkExternalName uniq mod occ loc+ -- name' is like name, but with the right SrcSpan+ new_cache = extendNameCache (nsNames name_supply) mod occ name'+ new_name_supply = name_supply {nsNames = new_cache}++ -- Miss in the cache!+ -- Build a completely new Name, and put it in the cache+ _ -> (new_name_supply, name)+ where+ (uniq, us') = takeUniqFromSupply (nsUniqs name_supply)+ name = mkExternalName uniq mod occ loc+ new_cache = extendNameCache (nsNames name_supply) mod occ name+ new_name_supply = name_supply {nsUniqs = us', nsNames = new_cache}++ifaceExportNames :: [IfaceExport] -> TcRnIf gbl lcl [AvailInfo]+ifaceExportNames exports = return exports++-- | A function that atomically updates the name cache given a modifier+-- function. The second result of the modifier function will be the result+-- of the IO action.+newtype NameCacheUpdater+ = NCU { updateNameCache :: forall c. (NameCache -> (NameCache, c)) -> IO c }++mkNameCacheUpdater :: TcRnIf a b NameCacheUpdater+mkNameCacheUpdater = do { hsc_env <- getTopEnv+ ; return (NCU (updNameCacheIO hsc_env)) }++updNameCache :: (NameCache -> (NameCache, c)) -> TcRnIf a b c+updNameCache upd_fn = do { hsc_env <- getTopEnv+ ; liftIO $ updNameCacheIO hsc_env upd_fn }++{-+************************************************************************+* *+ Name cache access+* *+************************************************************************+-}++-- | Look up the 'Name' for a given 'Module' and 'OccName'.+-- Consider alternately using 'lookupIfaceTop' if you're in the 'IfL' monad+-- and 'Module' is simply that of the 'ModIface' you are typechecking.+lookupOrig :: Module -> OccName -> TcRnIf a b Name+lookupOrig mod occ+ = do { -- First ensure that mod and occ are evaluated+ -- If not, chaos can ensue:+ -- we read the name-cache+ -- then pull on mod (say)+ -- which does some stuff that modifies the name cache+ -- This did happen, with tycon_mod in TcIface.tcIfaceAlt (DataAlt..)+ mod `seq` occ `seq` return ()+ ; traceIf (text "lookup_orig" <+> ppr mod <+> ppr occ)++ ; updNameCache $ \name_cache ->+ case lookupOrigNameCache (nsNames name_cache) mod occ of {+ Just name -> (name_cache, name);+ Nothing ->+ case takeUniqFromSupply (nsUniqs name_cache) of {+ (uniq, us) ->+ let+ name = mkExternalName uniq mod occ noSrcSpan+ new_cache = extendNameCache (nsNames name_cache) mod occ name+ in (name_cache{ nsUniqs = us, nsNames = new_cache }, name)+ }}}++externaliseName :: Module -> Name -> TcRnIf m n Name+-- Take an Internal Name and make it an External one,+-- with the same unique+externaliseName mod name+ = do { let occ = nameOccName name+ loc = nameSrcSpan name+ uniq = nameUnique name+ ; occ `seq` return () -- c.f. seq in newGlobalBinder+ ; updNameCache $ \ ns ->+ let name' = mkExternalName uniq mod occ loc+ ns' = ns { nsNames = extendNameCache (nsNames ns) mod occ name' }+ in (ns', name') }++-- | Set the 'Module' of a 'Name'.+setNameModule :: Maybe Module -> Name -> TcRnIf m n Name+setNameModule Nothing n = return n+setNameModule (Just m) n =+ newGlobalBinder m (nameOccName n) (nameSrcSpan n)++{-+************************************************************************+* *+ Type variables and local Ids+* *+************************************************************************+-}++tcIfaceLclId :: FastString -> IfL Id+tcIfaceLclId occ+ = do { lcl <- getLclEnv+ ; case (lookupFsEnv (if_id_env lcl) occ) of+ Just ty_var -> return ty_var+ Nothing -> failIfM (text "Iface id out of scope: " <+> ppr occ)+ }++extendIfaceIdEnv :: [Id] -> IfL a -> IfL a+extendIfaceIdEnv ids thing_inside+ = do { env <- getLclEnv+ ; let { id_env' = extendFsEnvList (if_id_env env) pairs+ ; pairs = [(occNameFS (getOccName id), id) | id <- ids] }+ ; setLclEnv (env { if_id_env = id_env' }) thing_inside }+++tcIfaceTyVar :: FastString -> IfL TyVar+tcIfaceTyVar occ+ = do { lcl <- getLclEnv+ ; case (lookupFsEnv (if_tv_env lcl) occ) of+ Just ty_var -> return ty_var+ Nothing -> failIfM (text "Iface type variable out of scope: " <+> ppr occ)+ }++lookupIfaceTyVar :: IfaceTvBndr -> IfL (Maybe TyVar)+lookupIfaceTyVar (occ, _)+ = do { lcl <- getLclEnv+ ; return (lookupFsEnv (if_tv_env lcl) occ) }++lookupIfaceVar :: IfaceBndr -> IfL (Maybe TyCoVar)+lookupIfaceVar (IfaceIdBndr (occ, _))+ = do { lcl <- getLclEnv+ ; return (lookupFsEnv (if_id_env lcl) occ) }+lookupIfaceVar (IfaceTvBndr (occ, _))+ = do { lcl <- getLclEnv+ ; return (lookupFsEnv (if_tv_env lcl) occ) }++extendIfaceTyVarEnv :: [TyVar] -> IfL a -> IfL a+extendIfaceTyVarEnv tyvars thing_inside+ = do { env <- getLclEnv+ ; let { tv_env' = extendFsEnvList (if_tv_env env) pairs+ ; pairs = [(occNameFS (getOccName tv), tv) | tv <- tyvars] }+ ; setLclEnv (env { if_tv_env = tv_env' }) thing_inside }++extendIfaceEnvs :: [TyCoVar] -> IfL a -> IfL a+extendIfaceEnvs tcvs thing_inside+ = extendIfaceTyVarEnv tvs $+ extendIfaceIdEnv cvs $+ thing_inside+ where+ (tvs, cvs) = partition isTyVar tcvs++{-+************************************************************************+* *+ Getting from RdrNames to Names+* *+************************************************************************+-}++-- | Look up a top-level name from the current Iface module+lookupIfaceTop :: OccName -> IfL Name+lookupIfaceTop occ+ = do { env <- getLclEnv; lookupOrig (if_mod env) occ }++newIfaceName :: OccName -> IfL Name+newIfaceName occ+ = do { uniq <- newUnique+ ; return $! mkInternalName uniq occ noSrcSpan }++newIfaceNames :: [OccName] -> IfL [Name]+newIfaceNames occs+ = do { uniqs <- newUniqueSupply+ ; return [ mkInternalName uniq occ noSrcSpan+ | (occ,uniq) <- occs `zip` uniqsFromSupply uniqs] }
+ iface/IfaceEnv.hs-boot view
@@ -0,0 +1,9 @@+module IfaceEnv where++import Module+import OccName+import TcRnMonad+import Name+import SrcLoc++newGlobalBinder :: Module -> OccName -> SrcSpan -> TcRnIf a b Name
+ iface/IfaceSyn.hs view
@@ -0,0 +1,2220 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998+-}++{-# LANGUAGE CPP #-}++module IfaceSyn (+ module IfaceType,++ IfaceDecl(..), IfaceFamTyConFlav(..), IfaceClassOp(..), IfaceAT(..),+ IfaceConDecl(..), IfaceConDecls(..), IfaceEqSpec,+ IfaceExpr(..), IfaceAlt, IfaceLetBndr(..), IfaceJoinInfo(..),+ IfaceBinding(..), IfaceConAlt(..),+ IfaceIdInfo(..), IfaceIdDetails(..), IfaceUnfolding(..),+ IfaceInfoItem(..), IfaceRule(..), IfaceAnnotation(..), IfaceAnnTarget,+ IfaceClsInst(..), IfaceFamInst(..), IfaceTickish(..),+ IfaceClassBody(..),+ IfaceBang(..),+ IfaceSrcBang(..), SrcUnpackedness(..), SrcStrictness(..),+ IfaceAxBranch(..),+ IfaceTyConParent(..),+ IfaceCompleteMatch(..),++ -- * Binding names+ IfaceTopBndr,+ putIfaceTopBndr, getIfaceTopBndr,++ -- Misc+ ifaceDeclImplicitBndrs, visibleIfConDecls,+ ifaceDeclFingerprints,++ -- Free Names+ freeNamesIfDecl, freeNamesIfRule, freeNamesIfFamInst,++ -- Pretty printing+ pprIfaceExpr,+ pprIfaceDecl,+ AltPpr(..), ShowSub(..), ShowHowMuch(..), showToIface, showToHeader+ ) where++#include "HsVersions.h"++import IfaceType+import BinFingerprint+import CoreSyn( IsOrphan, isOrphan )+import PprCore() -- Printing DFunArgs+import Demand+import Class+import FieldLabel+import NameSet+import CoAxiom ( BranchIndex )+import Name+import CostCentre+import Literal+import ForeignCall+import Annotations( AnnPayload, AnnTarget )+import BasicTypes+import Outputable+import Module+import SrcLoc+import Fingerprint+import Binary+import BooleanFormula ( BooleanFormula, pprBooleanFormula, isTrue )+import Var( TyVarBndr(..) )+import TyCon ( Role (..), Injectivity(..) )+import Util( filterOut, filterByList )+import DataCon (SrcStrictness(..), SrcUnpackedness(..))+import Lexeme (isLexSym)++import Control.Monad+import System.IO.Unsafe+import Data.Maybe (isJust)++infixl 3 &&&++{-+************************************************************************+* *+ Declarations+* *+************************************************************************+-}++-- | A binding top-level 'Name' in an interface file (e.g. the name of an+-- 'IfaceDecl').+type IfaceTopBndr = Name+ -- It's convenient to have an Name in the IfaceSyn, although in each+ -- case the namespace is implied by the context. However, having an+ -- Name makes things like ifaceDeclImplicitBndrs and ifaceDeclFingerprints+ -- very convenient. Moreover, having the key of the binder means that+ -- we can encode known-key things cleverly in the symbol table. See Note+ -- [Symbol table representation of Names]+ --+ -- We don't serialise the namespace onto the disk though; rather we+ -- drop it when serialising and add it back in when deserialising.++getIfaceTopBndr :: BinHandle -> IO IfaceTopBndr+getIfaceTopBndr bh = get bh++putIfaceTopBndr :: BinHandle -> IfaceTopBndr -> IO ()+putIfaceTopBndr bh name =+ case getUserData bh of+ UserData{ ud_put_binding_name = put_binding_name } ->+ --pprTrace "putIfaceTopBndr" (ppr name) $+ put_binding_name bh name++data IfaceDecl+ = IfaceId { ifName :: IfaceTopBndr,+ ifType :: IfaceType,+ ifIdDetails :: IfaceIdDetails,+ ifIdInfo :: IfaceIdInfo }++ | IfaceData { ifName :: IfaceTopBndr, -- Type constructor+ ifBinders :: [IfaceTyConBinder],+ ifResKind :: IfaceType, -- Result kind of type constructor+ ifCType :: Maybe CType, -- C type for CAPI FFI+ ifRoles :: [Role], -- Roles+ ifCtxt :: IfaceContext, -- The "stupid theta"+ ifCons :: IfaceConDecls, -- Includes new/data/data family info+ ifGadtSyntax :: Bool, -- True <=> declared using+ -- GADT syntax+ ifParent :: IfaceTyConParent -- The axiom, for a newtype,+ -- or data/newtype family instance+ }++ | IfaceSynonym { ifName :: IfaceTopBndr, -- Type constructor+ ifRoles :: [Role], -- Roles+ ifBinders :: [IfaceTyConBinder],+ ifResKind :: IfaceKind, -- Kind of the *result*+ ifSynRhs :: IfaceType }++ | IfaceFamily { ifName :: IfaceTopBndr, -- Type constructor+ ifResVar :: Maybe IfLclName, -- Result variable name, used+ -- only for pretty-printing+ -- with --show-iface+ ifBinders :: [IfaceTyConBinder],+ ifResKind :: IfaceKind, -- Kind of the *tycon*+ ifFamFlav :: IfaceFamTyConFlav,+ ifFamInj :: Injectivity } -- injectivity information++ | IfaceClass { ifName :: IfaceTopBndr, -- Name of the class TyCon+ ifRoles :: [Role], -- Roles+ ifBinders :: [IfaceTyConBinder],+ ifFDs :: [FunDep IfLclName], -- Functional dependencies+ ifBody :: IfaceClassBody -- Methods, superclasses, ATs+ }++ | IfaceAxiom { ifName :: IfaceTopBndr, -- Axiom name+ ifTyCon :: IfaceTyCon, -- LHS TyCon+ ifRole :: Role, -- Role of axiom+ ifAxBranches :: [IfaceAxBranch] -- Branches+ }++ | IfacePatSyn { ifName :: IfaceTopBndr, -- Name of the pattern synonym+ ifPatIsInfix :: Bool,+ ifPatMatcher :: (IfExtName, Bool),+ ifPatBuilder :: Maybe (IfExtName, Bool),+ -- Everything below is redundant,+ -- but needed to implement pprIfaceDecl+ ifPatUnivBndrs :: [IfaceForAllBndr],+ ifPatExBndrs :: [IfaceForAllBndr],+ ifPatProvCtxt :: IfaceContext,+ ifPatReqCtxt :: IfaceContext,+ ifPatArgs :: [IfaceType],+ ifPatTy :: IfaceType,+ ifFieldLabels :: [FieldLabel] }++-- See also 'ClassBody'+data IfaceClassBody+ -- Abstract classes don't specify their body; they only occur in @hs-boot@ and+ -- @hsig@ files.+ = IfAbstractClass+ | IfConcreteClass {+ ifClassCtxt :: IfaceContext, -- Super classes+ ifATs :: [IfaceAT], -- Associated type families+ ifSigs :: [IfaceClassOp], -- Method signatures+ ifMinDef :: BooleanFormula IfLclName -- Minimal complete definition+ }++data IfaceTyConParent+ = IfNoParent+ | IfDataInstance IfExtName+ IfaceTyCon+ IfaceTcArgs++data IfaceFamTyConFlav+ = IfaceDataFamilyTyCon -- Data family+ | IfaceOpenSynFamilyTyCon+ | IfaceClosedSynFamilyTyCon (Maybe (IfExtName, [IfaceAxBranch]))+ -- ^ Name of associated axiom and branches for pretty printing purposes,+ -- or 'Nothing' for an empty closed family without an axiom+ | IfaceAbstractClosedSynFamilyTyCon+ | IfaceBuiltInSynFamTyCon -- for pretty printing purposes only++data IfaceClassOp+ = IfaceClassOp IfaceTopBndr+ IfaceType -- Class op type+ (Maybe (DefMethSpec IfaceType)) -- Default method+ -- The types of both the class op itself,+ -- and the default method, are *not* quantified+ -- over the class variables++data IfaceAT = IfaceAT -- See Class.ClassATItem+ IfaceDecl -- The associated type declaration+ (Maybe IfaceType) -- Default associated type instance, if any+++-- This is just like CoAxBranch+data IfaceAxBranch = IfaceAxBranch { ifaxbTyVars :: [IfaceTvBndr]+ , ifaxbCoVars :: [IfaceIdBndr]+ , ifaxbLHS :: IfaceTcArgs+ , ifaxbRoles :: [Role]+ , ifaxbRHS :: IfaceType+ , ifaxbIncomps :: [BranchIndex] }+ -- See Note [Storing compatibility] in CoAxiom++data IfaceConDecls+ = IfAbstractTyCon -- c.f TyCon.AbstractTyCon+ | IfDataTyCon [IfaceConDecl] -- Data type decls+ | IfNewTyCon IfaceConDecl -- Newtype decls++-- For IfDataTyCon and IfNewTyCon we store:+-- * the data constructor(s);+-- The field labels are stored individually in the IfaceConDecl+-- (there is some redundancy here, because a field label may occur+-- in multiple IfaceConDecls and represent the same field label)++data IfaceConDecl+ = IfCon {+ ifConName :: IfaceTopBndr, -- Constructor name+ ifConWrapper :: Bool, -- True <=> has a wrapper+ ifConInfix :: Bool, -- True <=> declared infix++ -- The universal type variables are precisely those+ -- of the type constructor of this data constructor+ -- This is *easy* to guarantee when creating the IfCon+ -- but it's not so easy for the original TyCon/DataCon+ -- So this guarantee holds for IfaceConDecl, but *not* for DataCon++ ifConExTvs :: [IfaceForAllBndr], -- Existential tyvars (w/ visibility)+ ifConEqSpec :: IfaceEqSpec, -- Equality constraints+ ifConCtxt :: IfaceContext, -- Non-stupid context+ ifConArgTys :: [IfaceType], -- Arg types+ ifConFields :: [FieldLabel], -- ...ditto... (field labels)+ ifConStricts :: [IfaceBang],+ -- Empty (meaning all lazy),+ -- or 1-1 corresp with arg tys+ -- See Note [Bangs on imported data constructors] in MkId+ ifConSrcStricts :: [IfaceSrcBang] } -- empty meaning no src stricts++type IfaceEqSpec = [(IfLclName,IfaceType)]++-- | This corresponds to an HsImplBang; that is, the final+-- implementation decision about the data constructor arg+data IfaceBang+ = IfNoBang | IfStrict | IfUnpack | IfUnpackCo IfaceCoercion++-- | This corresponds to HsSrcBang+data IfaceSrcBang+ = IfSrcBang SrcUnpackedness SrcStrictness++data IfaceClsInst+ = IfaceClsInst { ifInstCls :: IfExtName, -- See comments with+ ifInstTys :: [Maybe IfaceTyCon], -- the defn of ClsInst+ ifDFun :: IfExtName, -- The dfun+ ifOFlag :: OverlapFlag, -- Overlap flag+ ifInstOrph :: IsOrphan } -- See Note [Orphans] in InstEnv+ -- There's always a separate IfaceDecl for the DFun, which gives+ -- its IdInfo with its full type and version number.+ -- The instance declarations taken together have a version number,+ -- and we don't want that to wobble gratuitously+ -- If this instance decl is *used*, we'll record a usage on the dfun;+ -- and if the head does not change it won't be used if it wasn't before++-- The ifFamInstTys field of IfaceFamInst contains a list of the rough+-- match types+data IfaceFamInst+ = IfaceFamInst { ifFamInstFam :: IfExtName -- Family name+ , ifFamInstTys :: [Maybe IfaceTyCon] -- See above+ , ifFamInstAxiom :: IfExtName -- The axiom+ , ifFamInstOrph :: IsOrphan -- Just like IfaceClsInst+ }++data IfaceRule+ = IfaceRule {+ ifRuleName :: RuleName,+ ifActivation :: Activation,+ ifRuleBndrs :: [IfaceBndr], -- Tyvars and term vars+ ifRuleHead :: IfExtName, -- Head of lhs+ ifRuleArgs :: [IfaceExpr], -- Args of LHS+ ifRuleRhs :: IfaceExpr,+ ifRuleAuto :: Bool,+ ifRuleOrph :: IsOrphan -- Just like IfaceClsInst+ }++data IfaceAnnotation+ = IfaceAnnotation {+ ifAnnotatedTarget :: IfaceAnnTarget,+ ifAnnotatedValue :: AnnPayload+ }++type IfaceAnnTarget = AnnTarget OccName++data IfaceCompleteMatch = IfaceCompleteMatch [IfExtName] IfExtName++instance Outputable IfaceCompleteMatch where+ ppr (IfaceCompleteMatch cls ty) = text "COMPLETE" <> colon <+> ppr cls+ <+> dcolon <+> ppr ty+++++-- Here's a tricky case:+-- * Compile with -O module A, and B which imports A.f+-- * Change function f in A, and recompile without -O+-- * When we read in old A.hi we read in its IdInfo (as a thunk)+-- (In earlier GHCs we used to drop IdInfo immediately on reading,+-- but we do not do that now. Instead it's discarded when the+-- ModIface is read into the various decl pools.)+-- * The version comparison sees that new (=NoInfo) differs from old (=HasInfo *)+-- and so gives a new version.++data IfaceIdInfo+ = NoInfo -- When writing interface file without -O+ | HasInfo [IfaceInfoItem] -- Has info, and here it is++data IfaceInfoItem+ = HsArity Arity+ | HsStrictness StrictSig+ | HsInline InlinePragma+ | HsUnfold Bool -- True <=> isStrongLoopBreaker is true+ IfaceUnfolding -- See Note [Expose recursive functions]+ | HsNoCafRefs+ | HsLevity -- Present <=> never levity polymorphic++-- NB: Specialisations and rules come in separately and are+-- only later attached to the Id. Partial reason: some are orphans.++data IfaceUnfolding+ = IfCoreUnfold Bool IfaceExpr -- True <=> INLINABLE, False <=> regular unfolding+ -- Possibly could eliminate the Bool here, the information+ -- is also in the InlinePragma.++ | IfCompulsory IfaceExpr -- Only used for default methods, in fact++ | IfInlineRule Arity -- INLINE pragmas+ Bool -- OK to inline even if *un*-saturated+ Bool -- OK to inline even if context is boring+ IfaceExpr++ | IfDFunUnfold [IfaceBndr] [IfaceExpr]+++-- We only serialise the IdDetails of top-level Ids, and even then+-- we only need a very limited selection. Notably, none of the+-- implicit ones are needed here, because they are not put it+-- interface files++data IfaceIdDetails+ = IfVanillaId+ | IfRecSelId (Either IfaceTyCon IfaceDecl) Bool+ | IfDFunId++{-+Note [Versioning of instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See [http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance#Instances]+++************************************************************************+* *+ Functions over declarations+* *+************************************************************************+-}++visibleIfConDecls :: IfaceConDecls -> [IfaceConDecl]+visibleIfConDecls IfAbstractTyCon = []+visibleIfConDecls (IfDataTyCon cs) = cs+visibleIfConDecls (IfNewTyCon c) = [c]++ifaceDeclImplicitBndrs :: IfaceDecl -> [OccName]+-- *Excludes* the 'main' name, but *includes* the implicitly-bound names+-- Deeply revolting, because it has to predict what gets bound,+-- especially the question of whether there's a wrapper for a datacon+-- See Note [Implicit TyThings] in HscTypes++-- N.B. the set of names returned here *must* match the set of+-- TyThings returned by HscTypes.implicitTyThings, in the sense that+-- TyThing.getOccName should define a bijection between the two lists.+-- This invariant is used in LoadIface.loadDecl (see note [Tricky iface loop])+-- The order of the list does not matter.++ifaceDeclImplicitBndrs (IfaceData {ifName = tc_name, ifCons = cons })+ = case cons of+ IfAbstractTyCon -> []+ IfNewTyCon cd -> mkNewTyCoOcc (occName tc_name) : ifaceConDeclImplicitBndrs cd+ IfDataTyCon cds -> concatMap ifaceConDeclImplicitBndrs cds++ifaceDeclImplicitBndrs (IfaceClass { ifBody = IfAbstractClass })+ = []++ifaceDeclImplicitBndrs (IfaceClass { ifName = cls_tc_name+ , ifBody = IfConcreteClass {+ ifClassCtxt = sc_ctxt,+ ifSigs = sigs,+ ifATs = ats+ }})+ = -- (possibly) newtype coercion+ co_occs +++ -- data constructor (DataCon namespace)+ -- data worker (Id namespace)+ -- no wrapper (class dictionaries never have a wrapper)+ [dc_occ, dcww_occ] +++ -- associated types+ [occName (ifName at) | IfaceAT at _ <- ats ] +++ -- superclass selectors+ [mkSuperDictSelOcc n cls_tc_occ | n <- [1..n_ctxt]] +++ -- operation selectors+ [occName op | IfaceClassOp op _ _ <- sigs]+ where+ cls_tc_occ = occName cls_tc_name+ n_ctxt = length sc_ctxt+ n_sigs = length sigs+ co_occs | is_newtype = [mkNewTyCoOcc cls_tc_occ]+ | otherwise = []+ dcww_occ = mkDataConWorkerOcc dc_occ+ dc_occ = mkClassDataConOcc cls_tc_occ+ is_newtype = n_sigs + n_ctxt == 1 -- Sigh (keep this synced with buildClass)++ifaceDeclImplicitBndrs _ = []++ifaceConDeclImplicitBndrs :: IfaceConDecl -> [OccName]+ifaceConDeclImplicitBndrs (IfCon {+ ifConWrapper = has_wrapper, ifConName = con_name })+ = [occName con_name, work_occ] ++ wrap_occs+ where+ con_occ = occName con_name+ work_occ = mkDataConWorkerOcc con_occ -- Id namespace+ wrap_occs | has_wrapper = [mkDataConWrapperOcc con_occ] -- Id namespace+ | otherwise = []++-- -----------------------------------------------------------------------------+-- The fingerprints of an IfaceDecl++ -- We better give each name bound by the declaration a+ -- different fingerprint! So we calculate the fingerprint of+ -- each binder by combining the fingerprint of the whole+ -- declaration with the name of the binder. (#5614, #7215)+ifaceDeclFingerprints :: Fingerprint -> IfaceDecl -> [(OccName,Fingerprint)]+ifaceDeclFingerprints hash decl+ = (getOccName decl, hash) :+ [ (occ, computeFingerprint' (hash,occ))+ | occ <- ifaceDeclImplicitBndrs decl ]+ where+ computeFingerprint' =+ unsafeDupablePerformIO+ . computeFingerprint (panic "ifaceDeclFingerprints")++{-+************************************************************************+* *+ Expressions+* *+************************************************************************+-}++data IfaceExpr+ = IfaceLcl IfLclName+ | IfaceExt IfExtName+ | IfaceType IfaceType+ | IfaceCo IfaceCoercion+ | IfaceTuple TupleSort [IfaceExpr] -- Saturated; type arguments omitted+ | IfaceLam IfaceLamBndr IfaceExpr+ | IfaceApp IfaceExpr IfaceExpr+ | IfaceCase IfaceExpr IfLclName [IfaceAlt]+ | IfaceECase IfaceExpr IfaceType -- See Note [Empty case alternatives]+ | IfaceLet IfaceBinding IfaceExpr+ | IfaceCast IfaceExpr IfaceCoercion+ | IfaceLit Literal+ | IfaceFCall ForeignCall IfaceType+ | IfaceTick IfaceTickish IfaceExpr -- from Tick tickish E++data IfaceTickish+ = IfaceHpcTick Module Int -- from HpcTick x+ | IfaceSCC CostCentre Bool Bool -- from ProfNote+ | IfaceSource RealSrcSpan String -- from SourceNote+ -- no breakpoints: we never export these into interface files++type IfaceAlt = (IfaceConAlt, [IfLclName], IfaceExpr)+ -- Note: IfLclName, not IfaceBndr (and same with the case binder)+ -- We reconstruct the kind/type of the thing from the context+ -- thus saving bulk in interface files++data IfaceConAlt = IfaceDefault+ | IfaceDataAlt IfExtName+ | IfaceLitAlt Literal++data IfaceBinding+ = IfaceNonRec IfaceLetBndr IfaceExpr+ | IfaceRec [(IfaceLetBndr, IfaceExpr)]++-- IfaceLetBndr is like IfaceIdBndr, but has IdInfo too+-- It's used for *non-top-level* let/rec binders+-- See Note [IdInfo on nested let-bindings]+data IfaceLetBndr = IfLetBndr IfLclName IfaceType IfaceIdInfo IfaceJoinInfo++data IfaceJoinInfo = IfaceNotJoinPoint+ | IfaceJoinPoint JoinArity++{-+Note [Empty case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In IfaceSyn an IfaceCase does not record the types of the alternatives,+unlike CorSyn Case. But we need this type if the alternatives are empty.+Hence IfaceECase. See Note [Empty case alternatives] in CoreSyn.++Note [Expose recursive functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For supercompilation we want to put *all* unfoldings in the interface+file, even for functions that are recursive (or big). So we need to+know when an unfolding belongs to a loop-breaker so that we can refrain+from inlining it (except during supercompilation).++Note [IdInfo on nested let-bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Occasionally we want to preserve IdInfo on nested let bindings. The one+that came up was a NOINLINE pragma on a let-binding inside an INLINE+function. The user (Duncan Coutts) really wanted the NOINLINE control+to cross the separate compilation boundary.++In general we retain all info that is left by CoreTidy.tidyLetBndr, since+that is what is seen by importing module with --make+++************************************************************************+* *+ Printing IfaceDecl+* *+************************************************************************+-}++pprAxBranch :: SDoc -> IfaceAxBranch -> SDoc+-- The TyCon might be local (just an OccName), or this might+-- be a branch for an imported TyCon, so it would be an ExtName+-- So it's easier to take an SDoc here+pprAxBranch pp_tc (IfaceAxBranch { ifaxbTyVars = tvs+ , ifaxbCoVars = cvs+ , ifaxbLHS = pat_tys+ , ifaxbRHS = rhs+ , ifaxbIncomps = incomps })+ = hang ppr_binders 2 (hang pp_lhs 2 (equals <+> ppr rhs))+ $+$+ nest 2 maybe_incomps+ where+ ppr_binders+ | null tvs && null cvs = empty+ | null cvs+ = brackets (pprWithCommas (pprIfaceTvBndr True) tvs)+ | otherwise+ = brackets (pprWithCommas (pprIfaceTvBndr True) tvs <> semi <+>+ pprWithCommas pprIfaceIdBndr cvs)+ pp_lhs = hang pp_tc 2 (pprParendIfaceTcArgs pat_tys)+ maybe_incomps = ppUnless (null incomps) $ parens $+ text "incompatible indices:" <+> ppr incomps++instance Outputable IfaceAnnotation where+ ppr (IfaceAnnotation target value) = ppr target <+> colon <+> ppr value++instance NamedThing IfaceClassOp where+ getName (IfaceClassOp n _ _) = n++instance HasOccName IfaceClassOp where+ occName = getOccName++instance NamedThing IfaceConDecl where+ getName = ifConName++instance HasOccName IfaceConDecl where+ occName = getOccName++instance NamedThing IfaceDecl where+ getName = ifName++instance HasOccName IfaceDecl where+ occName = getOccName++instance Outputable IfaceDecl where+ ppr = pprIfaceDecl showToIface++{-+Note [Minimal complete definition] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The minimal complete definition should only be included if a complete+class definition is shown. Since the minimal complete definition is+anonymous we can't reuse the same mechanism that is used for the+filtering of method signatures. Instead we just check if anything at all is+filtered and hide it in that case.+-}++data ShowSub+ = ShowSub+ { ss_how_much :: ShowHowMuch+ , ss_forall :: ShowForAllFlag }++-- See Note [Printing IfaceDecl binders]+-- The alternative pretty printer referred to in the note.+newtype AltPpr = AltPpr (Maybe (OccName -> SDoc))++data ShowHowMuch+ = ShowHeader AltPpr -- ^Header information only, not rhs+ | ShowSome [OccName] AltPpr+ -- ^ Show only some sub-components. Specifically,+ --+ -- [@[]@] Print all sub-components.+ -- [@(n:ns)@] Print sub-component @n@ with @ShowSub = ns@;+ -- elide other sub-components to @...@+ -- May 14: the list is max 1 element long at the moment+ | ShowIface+ -- ^Everything including GHC-internal information (used in --show-iface)++{-+Note [Printing IfaceDecl binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The binders in an IfaceDecl are just OccNames, so we don't know what module they+come from. But when we pretty-print a TyThing by converting to an IfaceDecl+(see PprTyThing), the TyThing may come from some other module so we really need+the module qualifier. We solve this by passing in a pretty-printer for the+binders.++When printing an interface file (--show-iface), we want to print+everything unqualified, so we can just print the OccName directly.+-}++instance Outputable ShowHowMuch where+ ppr (ShowHeader _) = text "ShowHeader"+ ppr ShowIface = text "ShowIface"+ ppr (ShowSome occs _) = text "ShowSome" <+> ppr occs++showToHeader :: ShowSub+showToHeader = ShowSub { ss_how_much = ShowHeader $ AltPpr Nothing+ , ss_forall = ShowForAllWhen }++showToIface :: ShowSub+showToIface = ShowSub { ss_how_much = ShowIface+ , ss_forall = ShowForAllWhen }++ppShowIface :: ShowSub -> SDoc -> SDoc+ppShowIface (ShowSub { ss_how_much = ShowIface }) doc = doc+ppShowIface _ _ = Outputable.empty++-- show if all sub-components or the complete interface is shown+ppShowAllSubs :: ShowSub -> SDoc -> SDoc -- Note [Minimal complete definition]+ppShowAllSubs (ShowSub { ss_how_much = ShowSome [] _ }) doc = doc+ppShowAllSubs (ShowSub { ss_how_much = ShowIface }) doc = doc+ppShowAllSubs _ _ = Outputable.empty++ppShowRhs :: ShowSub -> SDoc -> SDoc+ppShowRhs (ShowSub { ss_how_much = ShowHeader _ }) _ = Outputable.empty+ppShowRhs _ doc = doc++showSub :: HasOccName n => ShowSub -> n -> Bool+showSub (ShowSub { ss_how_much = ShowHeader _ }) _ = False+showSub (ShowSub { ss_how_much = ShowSome (n:_) _ }) thing = n == occName thing+showSub (ShowSub { ss_how_much = _ }) _ = True++ppr_trim :: [Maybe SDoc] -> [SDoc]+-- Collapse a group of Nothings to a single "..."+ppr_trim xs+ = snd (foldr go (False, []) xs)+ where+ go (Just doc) (_, so_far) = (False, doc : so_far)+ go Nothing (True, so_far) = (True, so_far)+ go Nothing (False, so_far) = (True, text "..." : so_far)++isIfaceDataInstance :: IfaceTyConParent -> Bool+isIfaceDataInstance IfNoParent = False+isIfaceDataInstance _ = True++pprClassRoles :: ShowSub -> IfaceTopBndr -> [IfaceTyConBinder] -> [Role] -> SDoc+pprClassRoles ss clas binders roles =+ pprRoles (== Nominal)+ (pprPrefixIfDeclBndr (ss_how_much ss) (occName clas))+ binders+ roles++pprIfaceDecl :: ShowSub -> IfaceDecl -> SDoc+-- NB: pprIfaceDecl is also used for pretty-printing TyThings in GHCi+-- See Note [Pretty-printing TyThings] in PprTyThing+pprIfaceDecl ss (IfaceData { ifName = tycon, ifCType = ctype,+ ifCtxt = context,+ ifRoles = roles, ifCons = condecls,+ ifParent = parent,+ ifGadtSyntax = gadt,+ ifBinders = binders })++ | gadt_style = vcat [ pp_roles+ , pp_nd <+> pp_lhs <+> pp_where+ , nest 2 (vcat pp_cons)+ , nest 2 $ ppShowIface ss pp_extra ]+ | otherwise = vcat [ pp_roles+ , hang (pp_nd <+> pp_lhs) 2 (add_bars pp_cons)+ , nest 2 $ ppShowIface ss pp_extra ]+ where+ is_data_instance = isIfaceDataInstance parent++ gadt_style = gadt || any (not . isVanillaIfaceConDecl) cons+ cons = visibleIfConDecls condecls+ pp_where = ppWhen (gadt_style && not (null cons)) $ text "where"+ pp_cons = ppr_trim (map show_con cons) :: [SDoc]++ pp_lhs = case parent of+ IfNoParent -> pprIfaceDeclHead context ss tycon binders Nothing+ _ -> text "instance" <+> pprIfaceTyConParent parent++ pp_roles+ | is_data_instance = empty+ | otherwise = pprRoles (== Representational)+ (pprPrefixIfDeclBndr+ (ss_how_much ss)+ (occName tycon))+ binders roles+ -- Don't display roles for data family instances (yet)+ -- See discussion on Trac #8672.++ add_bars [] = Outputable.empty+ add_bars (c:cs) = sep ((equals <+> c) : map (vbar <+>) cs)++ ok_con dc = showSub ss dc || any (showSub ss . flSelector) (ifConFields dc)++ show_con dc+ | ok_con dc = Just $ pprIfaceConDecl ss gadt_style tycon binders parent dc+ | otherwise = Nothing++ pp_nd = case condecls of+ IfAbstractTyCon{} -> text "data"+ IfDataTyCon{} -> text "data"+ IfNewTyCon{} -> text "newtype"++ pp_extra = vcat [pprCType ctype]++pprIfaceDecl ss (IfaceClass { ifName = clas+ , ifRoles = roles+ , ifFDs = fds+ , ifBinders = binders+ , ifBody = IfAbstractClass })+ = vcat [ pprClassRoles ss clas binders roles+ , text "class" <+> pprIfaceDeclHead [] ss clas binders Nothing+ <+> pprFundeps fds ]++pprIfaceDecl ss (IfaceClass { ifName = clas+ , ifRoles = roles+ , ifFDs = fds+ , ifBinders = binders+ , ifBody = IfConcreteClass {+ ifATs = ats,+ ifSigs = sigs,+ ifClassCtxt = context,+ ifMinDef = minDef+ }})+ = vcat [ pprClassRoles ss clas binders roles+ , text "class" <+> pprIfaceDeclHead context ss clas binders Nothing+ <+> pprFundeps fds <+> pp_where+ , nest 2 (vcat [ vcat asocs, vcat dsigs+ , ppShowAllSubs ss (pprMinDef minDef)])]+ where+ pp_where = ppShowRhs ss $ ppUnless (null sigs && null ats) (text "where")++ asocs = ppr_trim $ map maybeShowAssoc ats+ dsigs = ppr_trim $ map maybeShowSig sigs++ maybeShowAssoc :: IfaceAT -> Maybe SDoc+ maybeShowAssoc asc@(IfaceAT d _)+ | showSub ss d = Just $ pprIfaceAT ss asc+ | otherwise = Nothing++ maybeShowSig :: IfaceClassOp -> Maybe SDoc+ maybeShowSig sg+ | showSub ss sg = Just $ pprIfaceClassOp ss sg+ | otherwise = Nothing++ pprMinDef :: BooleanFormula IfLclName -> SDoc+ pprMinDef minDef = ppUnless (isTrue minDef) $ -- hide empty definitions+ text "{-# MINIMAL" <+>+ pprBooleanFormula+ (\_ def -> cparen (isLexSym def) (ppr def)) 0 minDef <+>+ text "#-}"++pprIfaceDecl ss (IfaceSynonym { ifName = tc+ , ifBinders = binders+ , ifSynRhs = mono_ty+ , ifResKind = res_kind})+ = hang (text "type" <+> pprIfaceDeclHead [] ss tc binders Nothing <+> equals)+ 2 (sep [ pprIfaceForAll tvs, pprIfaceContextArr theta, ppr tau+ , ppUnless (isIfaceLiftedTypeKind res_kind) (dcolon <+> ppr res_kind) ])+ where+ (tvs, theta, tau) = splitIfaceSigmaTy mono_ty++pprIfaceDecl ss (IfaceFamily { ifName = tycon+ , ifFamFlav = rhs, ifBinders = binders+ , ifResKind = res_kind+ , ifResVar = res_var, ifFamInj = inj })+ | IfaceDataFamilyTyCon <- rhs+ = text "data family" <+> pprIfaceDeclHead [] ss tycon binders Nothing++ | otherwise+ = hang (text "type family" <+> pprIfaceDeclHead [] ss tycon binders (Just res_kind))+ 2 (pp_inj res_var inj <+> ppShowRhs ss (pp_rhs rhs))+ $$+ nest 2 (ppShowRhs ss (pp_branches rhs))+ where+ pp_inj Nothing _ = empty+ pp_inj (Just res) inj+ | Injective injectivity <- inj = hsep [ equals, ppr res+ , pp_inj_cond res injectivity]+ | otherwise = hsep [ equals, ppr res ]++ pp_inj_cond res inj = case filterByList inj binders of+ [] -> empty+ tvs -> hsep [vbar, ppr res, text "->", interppSP (map ifTyConBinderName tvs)]++ pp_rhs IfaceDataFamilyTyCon+ = ppShowIface ss (text "data")+ pp_rhs IfaceOpenSynFamilyTyCon+ = ppShowIface ss (text "open")+ pp_rhs IfaceAbstractClosedSynFamilyTyCon+ = ppShowIface ss (text "closed, abstract")+ pp_rhs (IfaceClosedSynFamilyTyCon {})+ = empty -- see pp_branches+ pp_rhs IfaceBuiltInSynFamTyCon+ = ppShowIface ss (text "built-in")++ pp_branches (IfaceClosedSynFamilyTyCon (Just (ax, brs)))+ = hang (text "where")+ 2 (vcat (map (pprAxBranch+ (pprPrefixIfDeclBndr+ (ss_how_much ss)+ (occName tycon))+ ) brs)+ $$ ppShowIface ss (text "axiom" <+> ppr ax))+ pp_branches _ = Outputable.empty++pprIfaceDecl _ (IfacePatSyn { ifName = name,+ ifPatUnivBndrs = univ_bndrs, ifPatExBndrs = ex_bndrs,+ ifPatProvCtxt = prov_ctxt, ifPatReqCtxt = req_ctxt,+ ifPatArgs = arg_tys,+ ifPatTy = pat_ty} )+ = sdocWithDynFlags mk_msg+ where+ mk_msg dflags+ = hsep [ text "pattern", pprPrefixOcc name, dcolon+ , univ_msg, pprIfaceContextArr req_ctxt+ , ppWhen insert_empty_ctxt $ parens empty <+> darrow+ , ex_msg, pprIfaceContextArr prov_ctxt+ , pprIfaceType $ foldr IfaceFunTy pat_ty arg_tys]+ where+ univ_msg = pprUserIfaceForAll univ_bndrs+ ex_msg = pprUserIfaceForAll ex_bndrs++ insert_empty_ctxt = null req_ctxt+ && not (null prov_ctxt && isEmpty dflags ex_msg)++pprIfaceDecl ss (IfaceId { ifName = var, ifType = ty,+ ifIdDetails = details, ifIdInfo = info })+ = vcat [ hang (pprPrefixIfDeclBndr (ss_how_much ss) (occName var) <+> dcolon)+ 2 (pprIfaceSigmaType (ss_forall ss) ty)+ , ppShowIface ss (ppr details)+ , ppShowIface ss (ppr info) ]++pprIfaceDecl _ (IfaceAxiom { ifName = name, ifTyCon = tycon+ , ifAxBranches = branches })+ = hang (text "axiom" <+> ppr name <> dcolon)+ 2 (vcat $ map (pprAxBranch (ppr tycon)) branches)+++pprCType :: Maybe CType -> SDoc+pprCType Nothing = Outputable.empty+pprCType (Just cType) = text "C type:" <+> ppr cType++-- if, for each role, suppress_if role is True, then suppress the role+-- output+pprRoles :: (Role -> Bool) -> SDoc -> [IfaceTyConBinder]+ -> [Role] -> SDoc+pprRoles suppress_if tyCon bndrs roles+ = sdocWithDynFlags $ \dflags ->+ let froles = suppressIfaceInvisibles dflags bndrs roles+ in ppUnless (all suppress_if roles || null froles) $+ text "type role" <+> tyCon <+> hsep (map ppr froles)++pprInfixIfDeclBndr :: ShowHowMuch -> OccName -> SDoc+pprInfixIfDeclBndr (ShowSome _ (AltPpr (Just ppr_bndr))) name+ = pprInfixVar (isSymOcc name) (ppr_bndr name)+pprInfixIfDeclBndr _ name+ = pprInfixVar (isSymOcc name) (ppr name)++pprPrefixIfDeclBndr :: ShowHowMuch -> OccName -> SDoc+pprPrefixIfDeclBndr (ShowHeader (AltPpr (Just ppr_bndr))) name+ = parenSymOcc name (ppr_bndr name)+pprPrefixIfDeclBndr (ShowSome _ (AltPpr (Just ppr_bndr))) name+ = parenSymOcc name (ppr_bndr name)+pprPrefixIfDeclBndr _ name+ = parenSymOcc name (ppr name)++instance Outputable IfaceClassOp where+ ppr = pprIfaceClassOp showToIface++pprIfaceClassOp :: ShowSub -> IfaceClassOp -> SDoc+pprIfaceClassOp ss (IfaceClassOp n ty dm)+ = pp_sig n ty $$ generic_dm+ where+ generic_dm | Just (GenericDM dm_ty) <- dm+ = text "default" <+> pp_sig n dm_ty+ | otherwise+ = empty+ pp_sig n ty+ = pprPrefixIfDeclBndr (ss_how_much ss) (occName n)+ <+> dcolon+ <+> pprIfaceSigmaType ShowForAllWhen ty++instance Outputable IfaceAT where+ ppr = pprIfaceAT showToIface++pprIfaceAT :: ShowSub -> IfaceAT -> SDoc+pprIfaceAT ss (IfaceAT d mb_def)+ = vcat [ pprIfaceDecl ss d+ , case mb_def of+ Nothing -> Outputable.empty+ Just rhs -> nest 2 $+ text "Default:" <+> ppr rhs ]++instance Outputable IfaceTyConParent where+ ppr p = pprIfaceTyConParent p++pprIfaceTyConParent :: IfaceTyConParent -> SDoc+pprIfaceTyConParent IfNoParent+ = Outputable.empty+pprIfaceTyConParent (IfDataInstance _ tc tys)+ = sdocWithDynFlags $ \dflags ->+ let ftys = stripInvisArgs dflags tys+ in pprIfaceTypeApp TopPrec tc ftys++pprIfaceDeclHead :: IfaceContext -> ShowSub -> Name+ -> [IfaceTyConBinder] -- of the tycon, for invisible-suppression+ -> Maybe IfaceKind+ -> SDoc+pprIfaceDeclHead context ss tc_occ bndrs m_res_kind+ = sdocWithDynFlags $ \ dflags ->+ sep [ pprIfaceContextArr context+ , pprPrefixIfDeclBndr (ss_how_much ss) (occName tc_occ)+ <+> pprIfaceTyConBinders (suppressIfaceInvisibles dflags bndrs bndrs)+ , maybe empty (\res_kind -> dcolon <+> pprIfaceType res_kind) m_res_kind ]++isVanillaIfaceConDecl :: IfaceConDecl -> Bool+isVanillaIfaceConDecl (IfCon { ifConExTvs = ex_tvs+ , ifConEqSpec = eq_spec+ , ifConCtxt = ctxt })+ = (null ex_tvs) && (null eq_spec) && (null ctxt)++pprIfaceConDecl :: ShowSub -> Bool+ -> IfaceTopBndr+ -> [IfaceTyConBinder]+ -> IfaceTyConParent+ -> IfaceConDecl -> SDoc+pprIfaceConDecl ss gadt_style tycon tc_binders parent+ (IfCon { ifConName = name, ifConInfix = is_infix,+ ifConExTvs = ex_tvs,+ ifConEqSpec = eq_spec, ifConCtxt = ctxt, ifConArgTys = arg_tys,+ ifConStricts = stricts, ifConFields = fields })+ | gadt_style = pp_prefix_con <+> dcolon <+> ppr_ty+ | not (null fields) = pp_prefix_con <+> pp_field_args+ | is_infix+ , [ty1, ty2] <- pp_args = sep [ ty1+ , pprInfixIfDeclBndr how_much (occName name)+ , ty2]++ | otherwise = pp_prefix_con <+> sep pp_args+ where+ how_much = ss_how_much ss+ tys_w_strs :: [(IfaceBang, IfaceType)]+ tys_w_strs = zip stricts arg_tys+ pp_prefix_con = pprPrefixIfDeclBndr how_much (occName name)++ (univ_tvs, pp_res_ty) = mk_user_con_res_ty eq_spec+ ppr_ty = pprIfaceForAllPart (map tv_to_forall_bndr univ_tvs ++ ex_tvs)+ ctxt pp_tau++ -- A bit gruesome this, but we can't form the full con_tau, and ppr it,+ -- because we don't have a Name for the tycon, only an OccName+ pp_tau | null fields+ = case pp_args ++ [pp_res_ty] of+ (t:ts) -> fsep (t : map (arrow <+>) ts)+ [] -> panic "pp_con_taus"+ | otherwise+ = sep [pp_field_args, arrow <+> pp_res_ty]++ ppr_bang IfNoBang = sdocWithPprDebug $ \dbg -> ppWhen dbg $ char '_'+ ppr_bang IfStrict = char '!'+ ppr_bang IfUnpack = text "{-# UNPACK #-}"+ ppr_bang (IfUnpackCo co) = text "! {-# UNPACK #-}" <>+ pprParendIfaceCoercion co++ pprParendBangTy (bang, ty) = ppr_bang bang <> pprParendIfaceType ty+ pprBangTy (bang, ty) = ppr_bang bang <> ppr ty++ pp_args :: [SDoc] -- With parens, e.g (Maybe a) or !(Maybe a)+ pp_args = map pprParendBangTy tys_w_strs++ pp_field_args :: SDoc -- Braces form: { x :: !Maybe a, y :: Int }+ pp_field_args = braces $ sep $ punctuate comma $ ppr_trim $+ zipWith maybe_show_label fields tys_w_strs++ maybe_show_label :: FieldLabel -> (IfaceBang, IfaceType) -> Maybe SDoc+ maybe_show_label lbl bty+ | showSub ss sel =+ Just (pprPrefixIfDeclBndr how_much occ <+> dcolon <+> pprBangTy bty)+ | otherwise =+ Nothing+ where+ sel = flSelector lbl+ occ = mkVarOccFS (flLabel lbl)++ mk_user_con_res_ty :: IfaceEqSpec -> ([IfaceTvBndr], SDoc)+ -- See Note [Result type of a data family GADT]+ mk_user_con_res_ty eq_spec+ | IfDataInstance _ tc tys <- parent+ = (con_univ_tvs, pprIfaceType (IfaceTyConApp tc (substIfaceTcArgs gadt_subst tys)))+ | otherwise+ = (con_univ_tvs, sdocWithDynFlags (ppr_tc_app gadt_subst))+ where+ gadt_subst = mkFsEnv eq_spec+ done_univ_tv (tv,_) = isJust (lookupFsEnv gadt_subst tv)+ con_univ_tvs = filterOut done_univ_tv (map ifTyConBinderTyVar tc_binders)++ ppr_tc_app gadt_subst dflags+ = pprPrefixIfDeclBndr how_much (occName tycon)+ <+> sep [ pprParendIfaceType (substIfaceTyVar gadt_subst tv)+ | (tv,_kind)+ <- map ifTyConBinderTyVar $+ suppressIfaceInvisibles dflags tc_binders tc_binders ]++instance Outputable IfaceRule where+ ppr (IfaceRule { ifRuleName = name, ifActivation = act, ifRuleBndrs = bndrs,+ ifRuleHead = fn, ifRuleArgs = args, ifRuleRhs = rhs,+ ifRuleOrph = orph })+ = sep [hsep [pprRuleName name,+ if isOrphan orph then text "[orphan]" else Outputable.empty,+ ppr act,+ text "forall" <+> pprIfaceBndrs bndrs],+ nest 2 (sep [ppr fn <+> sep (map pprParendIfaceExpr args),+ text "=" <+> ppr rhs])+ ]++instance Outputable IfaceClsInst where+ ppr (IfaceClsInst { ifDFun = dfun_id, ifOFlag = flag+ , ifInstCls = cls, ifInstTys = mb_tcs+ , ifInstOrph = orph })+ = hang (text "instance" <+> ppr flag+ <+> (if isOrphan orph then text "[orphan]" else Outputable.empty)+ <+> ppr cls <+> brackets (pprWithCommas ppr_rough mb_tcs))+ 2 (equals <+> ppr dfun_id)++instance Outputable IfaceFamInst where+ ppr (IfaceFamInst { ifFamInstFam = fam, ifFamInstTys = mb_tcs+ , ifFamInstAxiom = tycon_ax, ifFamInstOrph = orph })+ = hang (text "family instance"+ <+> (if isOrphan orph then text "[orphan]" else Outputable.empty)+ <+> ppr fam <+> pprWithCommas (brackets . ppr_rough) mb_tcs)+ 2 (equals <+> ppr tycon_ax)++ppr_rough :: Maybe IfaceTyCon -> SDoc+ppr_rough Nothing = dot+ppr_rough (Just tc) = ppr tc++tv_to_forall_bndr :: IfaceTvBndr -> IfaceForAllBndr+tv_to_forall_bndr tv = TvBndr tv Specified++{-+Note [Result type of a data family GADT]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data family T a+ data instance T (p,q) where+ T1 :: T (Int, Maybe c)+ T2 :: T (Bool, q)++The IfaceDecl actually looks like++ data TPr p q where+ T1 :: forall p q. forall c. (p~Int,q~Maybe c) => TPr p q+ T2 :: forall p q. (p~Bool) => TPr p q++To reconstruct the result types for T1 and T2 that we+want to pretty print, we substitute the eq-spec+[p->Int, q->Maybe c] in the arg pattern (p,q) to give+ T (Int, Maybe c)+Remember that in IfaceSyn, the TyCon and DataCon share the same+universal type variables.++----------------------------- Printing IfaceExpr ------------------------------------+-}++instance Outputable IfaceExpr where+ ppr e = pprIfaceExpr noParens e++noParens :: SDoc -> SDoc+noParens pp = pp++pprParendIfaceExpr :: IfaceExpr -> SDoc+pprParendIfaceExpr = pprIfaceExpr parens++-- | Pretty Print an IfaceExpre+--+-- The first argument should be a function that adds parens in context that need+-- an atomic value (e.g. function args)+pprIfaceExpr :: (SDoc -> SDoc) -> IfaceExpr -> SDoc++pprIfaceExpr _ (IfaceLcl v) = ppr v+pprIfaceExpr _ (IfaceExt v) = ppr v+pprIfaceExpr _ (IfaceLit l) = ppr l+pprIfaceExpr _ (IfaceFCall cc ty) = braces (ppr cc <+> ppr ty)+pprIfaceExpr _ (IfaceType ty) = char '@' <+> pprParendIfaceType ty+pprIfaceExpr _ (IfaceCo co) = text "@~" <+> pprParendIfaceCoercion co++pprIfaceExpr add_par app@(IfaceApp _ _) = add_par (pprIfaceApp app [])+pprIfaceExpr _ (IfaceTuple c as) = tupleParens c (pprWithCommas ppr as)++pprIfaceExpr add_par i@(IfaceLam _ _)+ = add_par (sep [char '\\' <+> sep (map pprIfaceLamBndr bndrs) <+> arrow,+ pprIfaceExpr noParens body])+ where+ (bndrs,body) = collect [] i+ collect bs (IfaceLam b e) = collect (b:bs) e+ collect bs e = (reverse bs, e)++pprIfaceExpr add_par (IfaceECase scrut ty)+ = add_par (sep [ text "case" <+> pprIfaceExpr noParens scrut+ , text "ret_ty" <+> pprParendIfaceType ty+ , text "of {}" ])++pprIfaceExpr add_par (IfaceCase scrut bndr [(con, bs, rhs)])+ = add_par (sep [text "case"+ <+> pprIfaceExpr noParens scrut <+> text "of"+ <+> ppr bndr <+> char '{' <+> ppr_con_bs con bs <+> arrow,+ pprIfaceExpr noParens rhs <+> char '}'])++pprIfaceExpr add_par (IfaceCase scrut bndr alts)+ = add_par (sep [text "case"+ <+> pprIfaceExpr noParens scrut <+> text "of"+ <+> ppr bndr <+> char '{',+ nest 2 (sep (map ppr_alt alts)) <+> char '}'])++pprIfaceExpr _ (IfaceCast expr co)+ = sep [pprParendIfaceExpr expr,+ nest 2 (text "`cast`"),+ pprParendIfaceCoercion co]++pprIfaceExpr add_par (IfaceLet (IfaceNonRec b rhs) body)+ = add_par (sep [text "let {",+ nest 2 (ppr_bind (b, rhs)),+ text "} in",+ pprIfaceExpr noParens body])++pprIfaceExpr add_par (IfaceLet (IfaceRec pairs) body)+ = add_par (sep [text "letrec {",+ nest 2 (sep (map ppr_bind pairs)),+ text "} in",+ pprIfaceExpr noParens body])++pprIfaceExpr add_par (IfaceTick tickish e)+ = add_par (pprIfaceTickish tickish <+> pprIfaceExpr noParens e)++ppr_alt :: (IfaceConAlt, [IfLclName], IfaceExpr) -> SDoc+ppr_alt (con, bs, rhs) = sep [ppr_con_bs con bs,+ arrow <+> pprIfaceExpr noParens rhs]++ppr_con_bs :: IfaceConAlt -> [IfLclName] -> SDoc+ppr_con_bs con bs = ppr con <+> hsep (map ppr bs)++ppr_bind :: (IfaceLetBndr, IfaceExpr) -> SDoc+ppr_bind (IfLetBndr b ty info ji, rhs)+ = sep [hang (ppr b <+> dcolon <+> ppr ty) 2 (ppr ji <+> ppr info),+ equals <+> pprIfaceExpr noParens rhs]++------------------+pprIfaceTickish :: IfaceTickish -> SDoc+pprIfaceTickish (IfaceHpcTick m ix)+ = braces (text "tick" <+> ppr m <+> ppr ix)+pprIfaceTickish (IfaceSCC cc tick scope)+ = braces (pprCostCentreCore cc <+> ppr tick <+> ppr scope)+pprIfaceTickish (IfaceSource src _names)+ = braces (pprUserRealSpan True src)++------------------+pprIfaceApp :: IfaceExpr -> [SDoc] -> SDoc+pprIfaceApp (IfaceApp fun arg) args = pprIfaceApp fun $+ nest 2 (pprParendIfaceExpr arg) : args+pprIfaceApp fun args = sep (pprParendIfaceExpr fun : args)++------------------+instance Outputable IfaceConAlt where+ ppr IfaceDefault = text "DEFAULT"+ ppr (IfaceLitAlt l) = ppr l+ ppr (IfaceDataAlt d) = ppr d++------------------+instance Outputable IfaceIdDetails where+ ppr IfVanillaId = Outputable.empty+ ppr (IfRecSelId tc b) = text "RecSel" <+> ppr tc+ <+> if b+ then text "<naughty>"+ else Outputable.empty+ ppr IfDFunId = text "DFunId"++instance Outputable IfaceIdInfo where+ ppr NoInfo = Outputable.empty+ ppr (HasInfo is) = text "{-" <+> pprWithCommas ppr is+ <+> text "-}"++instance Outputable IfaceInfoItem where+ ppr (HsUnfold lb unf) = text "Unfolding"+ <> ppWhen lb (text "(loop-breaker)")+ <> colon <+> ppr unf+ ppr (HsInline prag) = text "Inline:" <+> ppr prag+ ppr (HsArity arity) = text "Arity:" <+> int arity+ ppr (HsStrictness str) = text "Strictness:" <+> pprIfaceStrictSig str+ ppr HsNoCafRefs = text "HasNoCafRefs"+ ppr HsLevity = text "Never levity-polymorphic"++instance Outputable IfaceJoinInfo where+ ppr IfaceNotJoinPoint = empty+ ppr (IfaceJoinPoint ar) = angleBrackets (text "join" <+> ppr ar)++instance Outputable IfaceUnfolding where+ ppr (IfCompulsory e) = text "<compulsory>" <+> parens (ppr e)+ ppr (IfCoreUnfold s e) = (if s+ then text "<stable>"+ else Outputable.empty)+ <+> parens (ppr e)+ ppr (IfInlineRule a uok bok e) = sep [text "InlineRule"+ <+> ppr (a,uok,bok),+ pprParendIfaceExpr e]+ ppr (IfDFunUnfold bs es) = hang (text "DFun:" <+> sep (map ppr bs) <> dot)+ 2 (sep (map pprParendIfaceExpr es))++{-+************************************************************************+* *+ Finding the Names in IfaceSyn+* *+************************************************************************++This is used for dependency analysis in MkIface, so that we+fingerprint a declaration before the things that depend on it. It+is specific to interface-file fingerprinting in the sense that we+don't collect *all* Names: for example, the DFun of an instance is+recorded textually rather than by its fingerprint when+fingerprinting the instance, so DFuns are not dependencies.+-}++freeNamesIfDecl :: IfaceDecl -> NameSet+freeNamesIfDecl (IfaceId _s t d i) =+ freeNamesIfType t &&&+ freeNamesIfIdInfo i &&&+ freeNamesIfIdDetails d+freeNamesIfDecl d@IfaceData{} =+ freeNamesIfTyVarBndrs (ifBinders d) &&&+ freeNamesIfType (ifResKind d) &&&+ freeNamesIfaceTyConParent (ifParent d) &&&+ freeNamesIfContext (ifCtxt d) &&&+ freeNamesIfConDecls (ifCons d)+freeNamesIfDecl d@IfaceSynonym{} =+ freeNamesIfType (ifSynRhs d) &&&+ freeNamesIfTyVarBndrs (ifBinders d) &&&+ freeNamesIfKind (ifResKind d)+freeNamesIfDecl d@IfaceFamily{} =+ freeNamesIfFamFlav (ifFamFlav d) &&&+ freeNamesIfTyVarBndrs (ifBinders d) &&&+ freeNamesIfKind (ifResKind d)+freeNamesIfDecl d@IfaceClass{ ifBody = IfAbstractClass } =+ freeNamesIfTyVarBndrs (ifBinders d)+freeNamesIfDecl d@IfaceClass{ ifBody = d'@IfConcreteClass{} } =+ freeNamesIfTyVarBndrs (ifBinders d) &&&+ freeNamesIfContext (ifClassCtxt d') &&&+ fnList freeNamesIfAT (ifATs d') &&&+ fnList freeNamesIfClsSig (ifSigs d')+freeNamesIfDecl d@IfaceAxiom{} =+ freeNamesIfTc (ifTyCon d) &&&+ fnList freeNamesIfAxBranch (ifAxBranches d)+freeNamesIfDecl d@IfacePatSyn{} =+ unitNameSet (fst (ifPatMatcher d)) &&&+ maybe emptyNameSet (unitNameSet . fst) (ifPatBuilder d) &&&+ freeNamesIfTyVarBndrs (ifPatUnivBndrs d) &&&+ freeNamesIfTyVarBndrs (ifPatExBndrs d) &&&+ freeNamesIfContext (ifPatProvCtxt d) &&&+ freeNamesIfContext (ifPatReqCtxt d) &&&+ fnList freeNamesIfType (ifPatArgs d) &&&+ freeNamesIfType (ifPatTy d) &&&+ mkNameSet (map flSelector (ifFieldLabels d))++freeNamesIfAxBranch :: IfaceAxBranch -> NameSet+freeNamesIfAxBranch (IfaceAxBranch { ifaxbTyVars = tyvars+ , ifaxbCoVars = covars+ , ifaxbLHS = lhs+ , ifaxbRHS = rhs })+ = fnList freeNamesIfTvBndr tyvars &&&+ fnList freeNamesIfIdBndr covars &&&+ freeNamesIfTcArgs lhs &&&+ freeNamesIfType rhs++freeNamesIfIdDetails :: IfaceIdDetails -> NameSet+freeNamesIfIdDetails (IfRecSelId tc _) =+ either freeNamesIfTc freeNamesIfDecl tc+freeNamesIfIdDetails _ = emptyNameSet++-- All other changes are handled via the version info on the tycon+freeNamesIfFamFlav :: IfaceFamTyConFlav -> NameSet+freeNamesIfFamFlav IfaceOpenSynFamilyTyCon = emptyNameSet+freeNamesIfFamFlav IfaceDataFamilyTyCon = emptyNameSet+freeNamesIfFamFlav (IfaceClosedSynFamilyTyCon (Just (ax, br)))+ = unitNameSet ax &&& fnList freeNamesIfAxBranch br+freeNamesIfFamFlav (IfaceClosedSynFamilyTyCon Nothing) = emptyNameSet+freeNamesIfFamFlav IfaceAbstractClosedSynFamilyTyCon = emptyNameSet+freeNamesIfFamFlav IfaceBuiltInSynFamTyCon = emptyNameSet++freeNamesIfContext :: IfaceContext -> NameSet+freeNamesIfContext = fnList freeNamesIfType++freeNamesIfAT :: IfaceAT -> NameSet+freeNamesIfAT (IfaceAT decl mb_def)+ = freeNamesIfDecl decl &&&+ case mb_def of+ Nothing -> emptyNameSet+ Just rhs -> freeNamesIfType rhs++freeNamesIfClsSig :: IfaceClassOp -> NameSet+freeNamesIfClsSig (IfaceClassOp _n ty dm) = freeNamesIfType ty &&& freeNamesDM dm++freeNamesDM :: Maybe (DefMethSpec IfaceType) -> NameSet+freeNamesDM (Just (GenericDM ty)) = freeNamesIfType ty+freeNamesDM _ = emptyNameSet++freeNamesIfConDecls :: IfaceConDecls -> NameSet+freeNamesIfConDecls (IfDataTyCon c) = fnList freeNamesIfConDecl c+freeNamesIfConDecls (IfNewTyCon c) = freeNamesIfConDecl c+freeNamesIfConDecls _ = emptyNameSet++freeNamesIfConDecl :: IfaceConDecl -> NameSet+freeNamesIfConDecl (IfCon { ifConExTvs = ex_tvs, ifConCtxt = ctxt+ , ifConArgTys = arg_tys+ , ifConFields = flds+ , ifConEqSpec = eq_spec+ , ifConStricts = bangs })+ = freeNamesIfTyVarBndrs ex_tvs &&&+ freeNamesIfContext ctxt &&&+ fnList freeNamesIfType arg_tys &&&+ mkNameSet (map flSelector flds) &&&+ fnList freeNamesIfType (map snd eq_spec) &&& -- equality constraints+ fnList freeNamesIfBang bangs++freeNamesIfBang :: IfaceBang -> NameSet+freeNamesIfBang (IfUnpackCo co) = freeNamesIfCoercion co+freeNamesIfBang _ = emptyNameSet++freeNamesIfKind :: IfaceType -> NameSet+freeNamesIfKind = freeNamesIfType++freeNamesIfTcArgs :: IfaceTcArgs -> NameSet+freeNamesIfTcArgs (ITC_Vis t ts) = freeNamesIfType t &&& freeNamesIfTcArgs ts+freeNamesIfTcArgs (ITC_Invis k ks) = freeNamesIfKind k &&& freeNamesIfTcArgs ks+freeNamesIfTcArgs ITC_Nil = emptyNameSet++freeNamesIfType :: IfaceType -> NameSet+freeNamesIfType (IfaceFreeTyVar _) = emptyNameSet+freeNamesIfType (IfaceTyVar _) = emptyNameSet+freeNamesIfType (IfaceAppTy s t) = freeNamesIfType s &&& freeNamesIfType t+freeNamesIfType (IfaceTyConApp tc ts) = freeNamesIfTc tc &&& freeNamesIfTcArgs ts+freeNamesIfType (IfaceTupleTy _ _ ts) = freeNamesIfTcArgs ts+freeNamesIfType (IfaceLitTy _) = emptyNameSet+freeNamesIfType (IfaceForAllTy tv t) = freeNamesIfTyVarBndr tv &&& freeNamesIfType t+freeNamesIfType (IfaceFunTy s t) = freeNamesIfType s &&& freeNamesIfType t+freeNamesIfType (IfaceDFunTy s t) = freeNamesIfType s &&& freeNamesIfType t+freeNamesIfType (IfaceCastTy t c) = freeNamesIfType t &&& freeNamesIfCoercion c+freeNamesIfType (IfaceCoercionTy c) = freeNamesIfCoercion c++freeNamesIfCoercion :: IfaceCoercion -> NameSet+freeNamesIfCoercion (IfaceReflCo _ t) = freeNamesIfType t+freeNamesIfCoercion (IfaceFunCo _ c1 c2)+ = freeNamesIfCoercion c1 &&& freeNamesIfCoercion c2+freeNamesIfCoercion (IfaceTyConAppCo _ tc cos)+ = freeNamesIfTc tc &&& fnList freeNamesIfCoercion cos+freeNamesIfCoercion (IfaceAppCo c1 c2)+ = freeNamesIfCoercion c1 &&& freeNamesIfCoercion c2+freeNamesIfCoercion (IfaceForAllCo _ kind_co co)+ = freeNamesIfCoercion kind_co &&& freeNamesIfCoercion co+freeNamesIfCoercion (IfaceCoVarCo _)+ = emptyNameSet+freeNamesIfCoercion (IfaceAxiomInstCo ax _ cos)+ = unitNameSet ax &&& fnList freeNamesIfCoercion cos+freeNamesIfCoercion (IfaceUnivCo p _ t1 t2)+ = freeNamesIfProv p &&& freeNamesIfType t1 &&& freeNamesIfType t2+freeNamesIfCoercion (IfaceSymCo c)+ = freeNamesIfCoercion c+freeNamesIfCoercion (IfaceTransCo c1 c2)+ = freeNamesIfCoercion c1 &&& freeNamesIfCoercion c2+freeNamesIfCoercion (IfaceNthCo _ co)+ = freeNamesIfCoercion co+freeNamesIfCoercion (IfaceLRCo _ co)+ = freeNamesIfCoercion co+freeNamesIfCoercion (IfaceInstCo co co2)+ = freeNamesIfCoercion co &&& freeNamesIfCoercion co2+freeNamesIfCoercion (IfaceCoherenceCo c1 c2)+ = freeNamesIfCoercion c1 &&& freeNamesIfCoercion c2+freeNamesIfCoercion (IfaceKindCo c)+ = freeNamesIfCoercion c+freeNamesIfCoercion (IfaceSubCo co)+ = freeNamesIfCoercion co+freeNamesIfCoercion (IfaceAxiomRuleCo _ax cos)+ -- the axiom is just a string, so we don't count it as a name.+ = fnList freeNamesIfCoercion cos++freeNamesIfProv :: IfaceUnivCoProv -> NameSet+freeNamesIfProv IfaceUnsafeCoerceProv = emptyNameSet+freeNamesIfProv (IfacePhantomProv co) = freeNamesIfCoercion co+freeNamesIfProv (IfaceProofIrrelProv co) = freeNamesIfCoercion co+freeNamesIfProv (IfacePluginProv _) = emptyNameSet+freeNamesIfProv (IfaceHoleProv _) = emptyNameSet++freeNamesIfTyVarBndr :: TyVarBndr IfaceTvBndr vis -> NameSet+freeNamesIfTyVarBndr (TvBndr tv _) = freeNamesIfTvBndr tv++freeNamesIfTyVarBndrs :: [TyVarBndr IfaceTvBndr vis] -> NameSet+freeNamesIfTyVarBndrs = fnList freeNamesIfTyVarBndr++freeNamesIfBndr :: IfaceBndr -> NameSet+freeNamesIfBndr (IfaceIdBndr b) = freeNamesIfIdBndr b+freeNamesIfBndr (IfaceTvBndr b) = freeNamesIfTvBndr b++freeNamesIfBndrs :: [IfaceBndr] -> NameSet+freeNamesIfBndrs = fnList freeNamesIfBndr++freeNamesIfLetBndr :: IfaceLetBndr -> NameSet+-- Remember IfaceLetBndr is used only for *nested* bindings+-- The IdInfo can contain an unfolding (in the case of+-- local INLINE pragmas), so look there too+freeNamesIfLetBndr (IfLetBndr _name ty info _ji) = freeNamesIfType ty+ &&& freeNamesIfIdInfo info++freeNamesIfTvBndr :: IfaceTvBndr -> NameSet+freeNamesIfTvBndr (_fs,k) = freeNamesIfKind k+ -- kinds can have Names inside, because of promotion++freeNamesIfIdBndr :: IfaceIdBndr -> NameSet+freeNamesIfIdBndr (_fs,k) = freeNamesIfKind k++freeNamesIfIdInfo :: IfaceIdInfo -> NameSet+freeNamesIfIdInfo NoInfo = emptyNameSet+freeNamesIfIdInfo (HasInfo i) = fnList freeNamesItem i++freeNamesItem :: IfaceInfoItem -> NameSet+freeNamesItem (HsUnfold _ u) = freeNamesIfUnfold u+freeNamesItem _ = emptyNameSet++freeNamesIfUnfold :: IfaceUnfolding -> NameSet+freeNamesIfUnfold (IfCoreUnfold _ e) = freeNamesIfExpr e+freeNamesIfUnfold (IfCompulsory e) = freeNamesIfExpr e+freeNamesIfUnfold (IfInlineRule _ _ _ e) = freeNamesIfExpr e+freeNamesIfUnfold (IfDFunUnfold bs es) = freeNamesIfBndrs bs &&& fnList freeNamesIfExpr es++freeNamesIfExpr :: IfaceExpr -> NameSet+freeNamesIfExpr (IfaceExt v) = unitNameSet v+freeNamesIfExpr (IfaceFCall _ ty) = freeNamesIfType ty+freeNamesIfExpr (IfaceType ty) = freeNamesIfType ty+freeNamesIfExpr (IfaceCo co) = freeNamesIfCoercion co+freeNamesIfExpr (IfaceTuple _ as) = fnList freeNamesIfExpr as+freeNamesIfExpr (IfaceLam (b,_) body) = freeNamesIfBndr b &&& freeNamesIfExpr body+freeNamesIfExpr (IfaceApp f a) = freeNamesIfExpr f &&& freeNamesIfExpr a+freeNamesIfExpr (IfaceCast e co) = freeNamesIfExpr e &&& freeNamesIfCoercion co+freeNamesIfExpr (IfaceTick _ e) = freeNamesIfExpr e+freeNamesIfExpr (IfaceECase e ty) = freeNamesIfExpr e &&& freeNamesIfType ty+freeNamesIfExpr (IfaceCase s _ alts)+ = freeNamesIfExpr s &&& fnList fn_alt alts &&& fn_cons alts+ where+ fn_alt (_con,_bs,r) = freeNamesIfExpr r++ -- Depend on the data constructors. Just one will do!+ -- Note [Tracking data constructors]+ fn_cons [] = emptyNameSet+ fn_cons ((IfaceDefault ,_,_) : xs) = fn_cons xs+ fn_cons ((IfaceDataAlt con,_,_) : _ ) = unitNameSet con+ fn_cons (_ : _ ) = emptyNameSet++freeNamesIfExpr (IfaceLet (IfaceNonRec bndr rhs) body)+ = freeNamesIfLetBndr bndr &&& freeNamesIfExpr rhs &&& freeNamesIfExpr body++freeNamesIfExpr (IfaceLet (IfaceRec as) x)+ = fnList fn_pair as &&& freeNamesIfExpr x+ where+ fn_pair (bndr, rhs) = freeNamesIfLetBndr bndr &&& freeNamesIfExpr rhs++freeNamesIfExpr _ = emptyNameSet++freeNamesIfTc :: IfaceTyCon -> NameSet+freeNamesIfTc tc = unitNameSet (ifaceTyConName tc)+-- ToDo: shouldn't we include IfaceIntTc & co.?++freeNamesIfRule :: IfaceRule -> NameSet+freeNamesIfRule (IfaceRule { ifRuleBndrs = bs, ifRuleHead = f+ , ifRuleArgs = es, ifRuleRhs = rhs })+ = unitNameSet f &&&+ fnList freeNamesIfBndr bs &&&+ fnList freeNamesIfExpr es &&&+ freeNamesIfExpr rhs++freeNamesIfFamInst :: IfaceFamInst -> NameSet+freeNamesIfFamInst (IfaceFamInst { ifFamInstFam = famName+ , ifFamInstAxiom = axName })+ = unitNameSet famName &&&+ unitNameSet axName++freeNamesIfaceTyConParent :: IfaceTyConParent -> NameSet+freeNamesIfaceTyConParent IfNoParent = emptyNameSet+freeNamesIfaceTyConParent (IfDataInstance ax tc tys)+ = unitNameSet ax &&& freeNamesIfTc tc &&& freeNamesIfTcArgs tys++-- helpers+(&&&) :: NameSet -> NameSet -> NameSet+(&&&) = unionNameSet++fnList :: (a -> NameSet) -> [a] -> NameSet+fnList f = foldr (&&&) emptyNameSet . map f++{-+Note [Tracking data constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a case expression+ case e of { C a -> ...; ... }+You might think that we don't need to include the datacon C+in the free names, because its type will probably show up in+the free names of 'e'. But in rare circumstances this may+not happen. Here's the one that bit me:++ module DynFlags where+ import {-# SOURCE #-} Packages( PackageState )+ data DynFlags = DF ... PackageState ...++ module Packages where+ import DynFlags+ data PackageState = PS ...+ lookupModule (df :: DynFlags)+ = case df of+ DF ...p... -> case p of+ PS ... -> ...++Now, lookupModule depends on DynFlags, but the transitive dependency+on the *locally-defined* type PackageState is not visible. We need+to take account of the use of the data constructor PS in the pattern match.+++************************************************************************+* *+ Binary instances+* *+************************************************************************++Note that there is a bit of subtlety here when we encode names. While+IfaceTopBndrs is really just a synonym for Name, we need to take care to+encode them with {get,put}IfaceTopBndr. The difference becomes important when+we go to fingerprint an IfaceDecl. See Note [Fingerprinting IfaceDecls] for+details.++-}++instance Binary IfaceDecl where+ put_ bh (IfaceId name ty details idinfo) = do+ putByte bh 0+ putIfaceTopBndr bh name+ lazyPut bh (ty, details, idinfo)+ -- See Note [Lazy deserialization of IfaceId]++ put_ bh (IfaceData a1 a2 a3 a4 a5 a6 a7 a8 a9) = do+ putByte bh 2+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6+ put_ bh a7+ put_ bh a8+ put_ bh a9++ put_ bh (IfaceSynonym a1 a2 a3 a4 a5) = do+ putByte bh 3+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5++ put_ bh (IfaceFamily a1 a2 a3 a4 a5 a6) = do+ putByte bh 4+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6++ -- NB: Written in a funny way to avoid an interface change+ put_ bh (IfaceClass {+ ifName = a2,+ ifRoles = a3,+ ifBinders = a4,+ ifFDs = a5,+ ifBody = IfConcreteClass {+ ifClassCtxt = a1,+ ifATs = a6,+ ifSigs = a7,+ ifMinDef = a8+ }}) = do+ putByte bh 5+ put_ bh a1+ putIfaceTopBndr bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6+ put_ bh a7+ put_ bh a8++ put_ bh (IfaceAxiom a1 a2 a3 a4) = do+ putByte bh 6+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4++ put_ bh (IfacePatSyn a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11) = do+ putByte bh 7+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6+ put_ bh a7+ put_ bh a8+ put_ bh a9+ put_ bh a10+ put_ bh a11++ put_ bh (IfaceClass {+ ifName = a1,+ ifRoles = a2,+ ifBinders = a3,+ ifFDs = a4,+ ifBody = IfAbstractClass }) = do+ putByte bh 8+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do name <- get bh+ ~(ty, details, idinfo) <- lazyGet bh+ -- See Note [Lazy deserialization of IfaceId]+ return (IfaceId name ty details idinfo)+ 1 -> error "Binary.get(TyClDecl): ForeignType"+ 2 -> do a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ a7 <- get bh+ a8 <- get bh+ a9 <- get bh+ return (IfaceData a1 a2 a3 a4 a5 a6 a7 a8 a9)+ 3 -> do a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ return (IfaceSynonym a1 a2 a3 a4 a5)+ 4 -> do a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ return (IfaceFamily a1 a2 a3 a4 a5 a6)+ 5 -> do a1 <- get bh+ a2 <- getIfaceTopBndr bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ a7 <- get bh+ a8 <- get bh+ return (IfaceClass {+ ifName = a2,+ ifRoles = a3,+ ifBinders = a4,+ ifFDs = a5,+ ifBody = IfConcreteClass {+ ifClassCtxt = a1,+ ifATs = a6,+ ifSigs = a7,+ ifMinDef = a8+ }})+ 6 -> do a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ return (IfaceAxiom a1 a2 a3 a4)+ 7 -> do a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ a7 <- get bh+ a8 <- get bh+ a9 <- get bh+ a10 <- get bh+ a11 <- get bh+ return (IfacePatSyn a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11)+ 8 -> do a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ return (IfaceClass {+ ifName = a1,+ ifRoles = a2,+ ifBinders = a3,+ ifFDs = a4,+ ifBody = IfAbstractClass })+ _ -> panic (unwords ["Unknown IfaceDecl tag:", show h])++{- Note [Lazy deserialization of IfaceId]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The use of lazyPut and lazyGet in the IfaceId Binary instance is+purely for performance reasons, to avoid deserializing details about+identifiers that will never be used. It's not involved in tying the+knot in the type checker. It saved ~1% of the total build time of GHC.++When we read an interface file, we extend the PTE, a mapping of Names+to TyThings, with the declarations we have read. The extension of the+PTE is strict in the Names, but not in the TyThings themselves.+LoadIface.loadDecl calculates the list of (Name, TyThing) bindings to+add to the PTE. For an IfaceId, there's just one binding to add; and+the ty, details, and idinfo fields of an IfaceId are used only in the+TyThing. So by reading those fields lazily we may be able to save the+work of ever having to deserialize them (into IfaceType, etc.).++For IfaceData and IfaceClass, loadDecl creates extra implicit bindings+(the constructors and field selectors of the data declaration, or the+methods of the class), whose Names depend on more than just the Name+of the type constructor or class itself. So deserializing them lazily+would be more involved. Similar comments apply to the other+constructors of IfaceDecl with the additional point that they probably+represent a small proportion of all declarations.+-}++instance Binary IfaceFamTyConFlav where+ put_ bh IfaceDataFamilyTyCon = putByte bh 0+ put_ bh IfaceOpenSynFamilyTyCon = putByte bh 1+ put_ bh (IfaceClosedSynFamilyTyCon mb) = putByte bh 2 >> put_ bh mb+ put_ bh IfaceAbstractClosedSynFamilyTyCon = putByte bh 3+ put_ _ IfaceBuiltInSynFamTyCon+ = pprPanic "Cannot serialize IfaceBuiltInSynFamTyCon, used for pretty-printing only" Outputable.empty++ get bh = do { h <- getByte bh+ ; case h of+ 0 -> return IfaceDataFamilyTyCon+ 1 -> return IfaceOpenSynFamilyTyCon+ 2 -> do { mb <- get bh+ ; return (IfaceClosedSynFamilyTyCon mb) }+ 3 -> return IfaceAbstractClosedSynFamilyTyCon+ _ -> pprPanic "Binary.get(IfaceFamTyConFlav): Invalid tag"+ (ppr (fromIntegral h :: Int)) }++instance Binary IfaceClassOp where+ put_ bh (IfaceClassOp n ty def) = do+ putIfaceTopBndr bh n+ put_ bh ty+ put_ bh def+ get bh = do+ n <- getIfaceTopBndr bh+ ty <- get bh+ def <- get bh+ return (IfaceClassOp n ty def)++instance Binary IfaceAT where+ put_ bh (IfaceAT dec defs) = do+ put_ bh dec+ put_ bh defs+ get bh = do+ dec <- get bh+ defs <- get bh+ return (IfaceAT dec defs)++instance Binary IfaceAxBranch where+ put_ bh (IfaceAxBranch a1 a2 a3 a4 a5 a6) = do+ put_ bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6+ get bh = do+ a1 <- get bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ return (IfaceAxBranch a1 a2 a3 a4 a5 a6)++instance Binary IfaceConDecls where+ put_ bh IfAbstractTyCon = putByte bh 0+ put_ bh (IfDataTyCon cs) = putByte bh 1 >> put_ bh cs+ put_ bh (IfNewTyCon c) = putByte bh 2 >> put_ bh c+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IfAbstractTyCon+ 1 -> liftM IfDataTyCon (get bh)+ 2 -> liftM IfNewTyCon (get bh)+ _ -> error "Binary(IfaceConDecls).get: Invalid IfaceConDecls"++instance Binary IfaceConDecl where+ put_ bh (IfCon a1 a2 a3 a4 a5 a6 a7 a8 a9 a10) = do+ putIfaceTopBndr bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6+ put_ bh a7+ put_ bh (length a8)+ mapM_ (put_ bh) a8+ put_ bh a9+ put_ bh a10+ get bh = do+ a1 <- getIfaceTopBndr bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ a7 <- get bh+ n_fields <- get bh+ a8 <- replicateM n_fields (get bh)+ a9 <- get bh+ a10 <- get bh+ return (IfCon a1 a2 a3 a4 a5 a6 a7 a8 a9 a10)++instance Binary IfaceBang where+ put_ bh IfNoBang = putByte bh 0+ put_ bh IfStrict = putByte bh 1+ put_ bh IfUnpack = putByte bh 2+ put_ bh (IfUnpackCo co) = putByte bh 3 >> put_ bh co++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return IfNoBang+ 1 -> do return IfStrict+ 2 -> do return IfUnpack+ _ -> do { a <- get bh; return (IfUnpackCo a) }++instance Binary IfaceSrcBang where+ put_ bh (IfSrcBang a1 a2) =+ do put_ bh a1+ put_ bh a2++ get bh =+ do a1 <- get bh+ a2 <- get bh+ return (IfSrcBang a1 a2)++instance Binary IfaceClsInst where+ put_ bh (IfaceClsInst cls tys dfun flag orph) = do+ put_ bh cls+ put_ bh tys+ put_ bh dfun+ put_ bh flag+ put_ bh orph+ get bh = do+ cls <- get bh+ tys <- get bh+ dfun <- get bh+ flag <- get bh+ orph <- get bh+ return (IfaceClsInst cls tys dfun flag orph)++instance Binary IfaceFamInst where+ put_ bh (IfaceFamInst fam tys name orph) = do+ put_ bh fam+ put_ bh tys+ put_ bh name+ put_ bh orph+ get bh = do+ fam <- get bh+ tys <- get bh+ name <- get bh+ orph <- get bh+ return (IfaceFamInst fam tys name orph)++instance Binary IfaceRule where+ put_ bh (IfaceRule a1 a2 a3 a4 a5 a6 a7 a8) = do+ put_ bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ put_ bh a6+ put_ bh a7+ put_ bh a8+ get bh = do+ a1 <- get bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ a6 <- get bh+ a7 <- get bh+ a8 <- get bh+ return (IfaceRule a1 a2 a3 a4 a5 a6 a7 a8)++instance Binary IfaceAnnotation where+ put_ bh (IfaceAnnotation a1 a2) = do+ put_ bh a1+ put_ bh a2+ get bh = do+ a1 <- get bh+ a2 <- get bh+ return (IfaceAnnotation a1 a2)++instance Binary IfaceIdDetails where+ put_ bh IfVanillaId = putByte bh 0+ put_ bh (IfRecSelId a b) = putByte bh 1 >> put_ bh a >> put_ bh b+ put_ bh IfDFunId = putByte bh 2+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IfVanillaId+ 1 -> do { a <- get bh; b <- get bh; return (IfRecSelId a b) }+ _ -> return IfDFunId++instance Binary IfaceIdInfo where+ put_ bh NoInfo = putByte bh 0+ put_ bh (HasInfo i) = putByte bh 1 >> lazyPut bh i -- NB lazyPut++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return NoInfo+ _ -> liftM HasInfo $ lazyGet bh -- NB lazyGet++instance Binary IfaceInfoItem where+ put_ bh (HsArity aa) = putByte bh 0 >> put_ bh aa+ put_ bh (HsStrictness ab) = putByte bh 1 >> put_ bh ab+ put_ bh (HsUnfold lb ad) = putByte bh 2 >> put_ bh lb >> put_ bh ad+ put_ bh (HsInline ad) = putByte bh 3 >> put_ bh ad+ put_ bh HsNoCafRefs = putByte bh 4+ put_ bh HsLevity = putByte bh 5+ get bh = do+ h <- getByte bh+ case h of+ 0 -> liftM HsArity $ get bh+ 1 -> liftM HsStrictness $ get bh+ 2 -> do lb <- get bh+ ad <- get bh+ return (HsUnfold lb ad)+ 3 -> liftM HsInline $ get bh+ 4 -> return HsNoCafRefs+ _ -> return HsLevity++instance Binary IfaceUnfolding where+ put_ bh (IfCoreUnfold s e) = do+ putByte bh 0+ put_ bh s+ put_ bh e+ put_ bh (IfInlineRule a b c d) = do+ putByte bh 1+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh d+ put_ bh (IfDFunUnfold as bs) = do+ putByte bh 2+ put_ bh as+ put_ bh bs+ put_ bh (IfCompulsory e) = do+ putByte bh 3+ put_ bh e+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do s <- get bh+ e <- get bh+ return (IfCoreUnfold s e)+ 1 -> do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ return (IfInlineRule a b c d)+ 2 -> do as <- get bh+ bs <- get bh+ return (IfDFunUnfold as bs)+ _ -> do e <- get bh+ return (IfCompulsory e)+++instance Binary IfaceExpr where+ put_ bh (IfaceLcl aa) = do+ putByte bh 0+ put_ bh aa+ put_ bh (IfaceType ab) = do+ putByte bh 1+ put_ bh ab+ put_ bh (IfaceCo ab) = do+ putByte bh 2+ put_ bh ab+ put_ bh (IfaceTuple ac ad) = do+ putByte bh 3+ put_ bh ac+ put_ bh ad+ put_ bh (IfaceLam (ae, os) af) = do+ putByte bh 4+ put_ bh ae+ put_ bh os+ put_ bh af+ put_ bh (IfaceApp ag ah) = do+ putByte bh 5+ put_ bh ag+ put_ bh ah+ put_ bh (IfaceCase ai aj ak) = do+ putByte bh 6+ put_ bh ai+ put_ bh aj+ put_ bh ak+ put_ bh (IfaceLet al am) = do+ putByte bh 7+ put_ bh al+ put_ bh am+ put_ bh (IfaceTick an ao) = do+ putByte bh 8+ put_ bh an+ put_ bh ao+ put_ bh (IfaceLit ap) = do+ putByte bh 9+ put_ bh ap+ put_ bh (IfaceFCall as at) = do+ putByte bh 10+ put_ bh as+ put_ bh at+ put_ bh (IfaceExt aa) = do+ putByte bh 11+ put_ bh aa+ put_ bh (IfaceCast ie ico) = do+ putByte bh 12+ put_ bh ie+ put_ bh ico+ put_ bh (IfaceECase a b) = do+ putByte bh 13+ put_ bh a+ put_ bh b+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do aa <- get bh+ return (IfaceLcl aa)+ 1 -> do ab <- get bh+ return (IfaceType ab)+ 2 -> do ab <- get bh+ return (IfaceCo ab)+ 3 -> do ac <- get bh+ ad <- get bh+ return (IfaceTuple ac ad)+ 4 -> do ae <- get bh+ os <- get bh+ af <- get bh+ return (IfaceLam (ae, os) af)+ 5 -> do ag <- get bh+ ah <- get bh+ return (IfaceApp ag ah)+ 6 -> do ai <- get bh+ aj <- get bh+ ak <- get bh+ return (IfaceCase ai aj ak)+ 7 -> do al <- get bh+ am <- get bh+ return (IfaceLet al am)+ 8 -> do an <- get bh+ ao <- get bh+ return (IfaceTick an ao)+ 9 -> do ap <- get bh+ return (IfaceLit ap)+ 10 -> do as <- get bh+ at <- get bh+ return (IfaceFCall as at)+ 11 -> do aa <- get bh+ return (IfaceExt aa)+ 12 -> do ie <- get bh+ ico <- get bh+ return (IfaceCast ie ico)+ 13 -> do a <- get bh+ b <- get bh+ return (IfaceECase a b)+ _ -> panic ("get IfaceExpr " ++ show h)++instance Binary IfaceTickish where+ put_ bh (IfaceHpcTick m ix) = do+ putByte bh 0+ put_ bh m+ put_ bh ix+ put_ bh (IfaceSCC cc tick push) = do+ putByte bh 1+ put_ bh cc+ put_ bh tick+ put_ bh push+ put_ bh (IfaceSource src name) = do+ putByte bh 2+ put_ bh (srcSpanFile src)+ put_ bh (srcSpanStartLine src)+ put_ bh (srcSpanStartCol src)+ put_ bh (srcSpanEndLine src)+ put_ bh (srcSpanEndCol src)+ put_ bh name++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do m <- get bh+ ix <- get bh+ return (IfaceHpcTick m ix)+ 1 -> do cc <- get bh+ tick <- get bh+ push <- get bh+ return (IfaceSCC cc tick push)+ 2 -> do file <- get bh+ sl <- get bh+ sc <- get bh+ el <- get bh+ ec <- get bh+ let start = mkRealSrcLoc file sl sc+ end = mkRealSrcLoc file el ec+ name <- get bh+ return (IfaceSource (mkRealSrcSpan start end) name)+ _ -> panic ("get IfaceTickish " ++ show h)++instance Binary IfaceConAlt where+ put_ bh IfaceDefault = putByte bh 0+ put_ bh (IfaceDataAlt aa) = putByte bh 1 >> put_ bh aa+ put_ bh (IfaceLitAlt ac) = putByte bh 2 >> put_ bh ac+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IfaceDefault+ 1 -> liftM IfaceDataAlt $ get bh+ _ -> liftM IfaceLitAlt $ get bh++instance Binary IfaceBinding where+ put_ bh (IfaceNonRec aa ab) = putByte bh 0 >> put_ bh aa >> put_ bh ab+ put_ bh (IfaceRec ac) = putByte bh 1 >> put_ bh ac+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do { aa <- get bh; ab <- get bh; return (IfaceNonRec aa ab) }+ _ -> do { ac <- get bh; return (IfaceRec ac) }++instance Binary IfaceLetBndr where+ put_ bh (IfLetBndr a b c d) = do+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh d+ get bh = do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ return (IfLetBndr a b c d)++instance Binary IfaceJoinInfo where+ put_ bh IfaceNotJoinPoint = putByte bh 0+ put_ bh (IfaceJoinPoint ar) = do+ putByte bh 1+ put_ bh ar+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IfaceNotJoinPoint+ _ -> liftM IfaceJoinPoint $ get bh++instance Binary IfaceTyConParent where+ put_ bh IfNoParent = putByte bh 0+ put_ bh (IfDataInstance ax pr ty) = do+ putByte bh 1+ put_ bh ax+ put_ bh pr+ put_ bh ty+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IfNoParent+ _ -> do+ ax <- get bh+ pr <- get bh+ ty <- get bh+ return $ IfDataInstance ax pr ty++instance Binary IfaceCompleteMatch where+ put_ bh (IfaceCompleteMatch cs ts) = put_ bh cs >> put_ bh ts+ get bh = IfaceCompleteMatch <$> get bh <*> get bh
+ iface/IfaceType.hs view
@@ -0,0 +1,1552 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998+++This module defines interface types and binders+-}++{-# LANGUAGE CPP, FlexibleInstances, BangPatterns #-}+{-# LANGUAGE MultiWayIf #-}+ -- FlexibleInstances for Binary (DefMethSpec IfaceType)++module IfaceType (+ IfExtName, IfLclName,++ IfaceType(..), IfacePredType, IfaceKind, IfaceCoercion(..),+ IfaceUnivCoProv(..),+ IfaceTyCon(..), IfaceTyConInfo(..), IfaceTyConSort(..), IsPromoted(..),+ IfaceTyLit(..), IfaceTcArgs(..),+ IfaceContext, IfaceBndr(..), IfaceOneShot(..), IfaceLamBndr,+ IfaceTvBndr, IfaceIdBndr, IfaceTyConBinder,+ IfaceForAllBndr, ArgFlag(..), ShowForAllFlag(..),++ ifTyConBinderTyVar, ifTyConBinderName,++ -- Equality testing+ IfRnEnv2, emptyIfRnEnv2, eqIfaceType, eqIfaceTypes,+ eqIfaceTcArgs, eqIfaceTvBndrs, isIfaceLiftedTypeKind,++ -- Conversion from IfaceTcArgs -> [IfaceType]+ tcArgsIfaceTypes,++ -- Printing+ pprIfaceType, pprParendIfaceType,+ pprIfaceContext, pprIfaceContextArr,+ pprIfaceIdBndr, pprIfaceLamBndr, pprIfaceTvBndr, pprIfaceTyConBinders,+ pprIfaceBndrs, pprIfaceTcArgs, pprParendIfaceTcArgs,+ pprIfaceForAllPart, pprIfaceForAll, pprIfaceSigmaType,+ pprIfaceTyLit,+ pprIfaceCoercion, pprParendIfaceCoercion,+ splitIfaceSigmaTy, pprIfaceTypeApp, pprUserIfaceForAll,+ pprIfaceCoTcApp, pprTyTcApp, pprIfacePrefixApp,++ suppressIfaceInvisibles,+ stripIfaceInvisVars,+ stripInvisArgs,+ substIfaceType, substIfaceTyVar, substIfaceTcArgs, mkIfaceTySubst,+ eqIfaceTvBndr+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} TysWiredIn ( liftedRepDataConTyCon )++import DynFlags+import TyCon hiding ( pprPromotionQuote )+import CoAxiom+import Var+import PrelNames+import Name+import BasicTypes+import Binary+import Outputable+import FastString+import FastStringEnv+import UniqFM+import Util++import Data.List (foldl')++{-+************************************************************************+* *+ Local (nested) binders+* *+************************************************************************+-}++type IfLclName = FastString -- A local name in iface syntax++type IfExtName = Name -- An External or WiredIn Name can appear in IfaceSyn+ -- (However Internal or System Names never should)++data IfaceBndr -- Local (non-top-level) binders+ = IfaceIdBndr {-# UNPACK #-} !IfaceIdBndr+ | IfaceTvBndr {-# UNPACK #-} !IfaceTvBndr++type IfaceIdBndr = (IfLclName, IfaceType)+type IfaceTvBndr = (IfLclName, IfaceKind)++ifaceTvBndrName :: IfaceTvBndr -> IfLclName+ifaceTvBndrName (n,_) = n++type IfaceLamBndr = (IfaceBndr, IfaceOneShot)++data IfaceOneShot -- See Note [Preserve OneShotInfo] in CoreTicy+ = IfaceNoOneShot -- and Note [The oneShot function] in MkId+ | IfaceOneShot+++{-+%************************************************************************+%* *+ IfaceType+%* *+%************************************************************************+-}++-------------------------------+type IfaceKind = IfaceType++data IfaceType -- A kind of universal type, used for types and kinds+ = IfaceFreeTyVar TyVar -- See Note [Free tyvars in IfaceType]+ | IfaceTyVar IfLclName -- Type/coercion variable only, not tycon+ | IfaceLitTy IfaceTyLit+ | IfaceAppTy IfaceType IfaceType+ | IfaceFunTy IfaceType IfaceType+ | IfaceDFunTy IfaceType IfaceType+ | IfaceForAllTy IfaceForAllBndr IfaceType+ | IfaceTyConApp IfaceTyCon IfaceTcArgs -- Not necessarily saturated+ -- Includes newtypes, synonyms, tuples+ | IfaceCastTy IfaceType IfaceCoercion+ | IfaceCoercionTy IfaceCoercion++ | IfaceTupleTy -- Saturated tuples (unsaturated ones use IfaceTyConApp)+ TupleSort -- What sort of tuple?+ IsPromoted -- A bit like IfaceTyCon+ IfaceTcArgs -- arity = length args+ -- For promoted data cons, the kind args are omitted++type IfacePredType = IfaceType+type IfaceContext = [IfacePredType]++data IfaceTyLit+ = IfaceNumTyLit Integer+ | IfaceStrTyLit FastString+ deriving (Eq)++type IfaceTyConBinder = TyVarBndr IfaceTvBndr TyConBndrVis+type IfaceForAllBndr = TyVarBndr IfaceTvBndr ArgFlag++-- See Note [Suppressing invisible arguments]+-- We use a new list type (rather than [(IfaceType,Bool)], because+-- it'll be more compact and faster to parse in interface+-- files. Rather than two bytes and two decisions (nil/cons, and+-- type/kind) there'll just be one.+data IfaceTcArgs+ = ITC_Nil+ | ITC_Vis IfaceType IfaceTcArgs -- "Vis" means show when pretty-printing+ | ITC_Invis IfaceKind IfaceTcArgs -- "Invis" means don't show when pretty-printing+ -- except with -fprint-explicit-kinds++instance Monoid IfaceTcArgs where+ mempty = ITC_Nil+ ITC_Nil `mappend` xs = xs+ ITC_Vis ty rest `mappend` xs = ITC_Vis ty (rest `mappend` xs)+ ITC_Invis ki rest `mappend` xs = ITC_Invis ki (rest `mappend` xs)++-- Encodes type constructors, kind constructors,+-- coercion constructors, the lot.+-- We have to tag them in order to pretty print them+-- properly.+data IfaceTyCon = IfaceTyCon { ifaceTyConName :: IfExtName+ , ifaceTyConInfo :: IfaceTyConInfo }+ deriving (Eq)++-- | Is a TyCon a promoted data constructor or just a normal type constructor?+data IsPromoted = IsNotPromoted | IsPromoted+ deriving (Eq)++-- | The various types of TyCons which have special, built-in syntax.+data IfaceTyConSort = IfaceNormalTyCon -- ^ a regular tycon++ | IfaceTupleTyCon !Arity !TupleSort+ -- ^ e.g. @(a, b, c)@ or @(#a, b, c#)@.+ -- The arity is the tuple width, not the tycon arity+ -- (which is twice the width in the case of unboxed+ -- tuples).++ | IfaceSumTyCon !Arity+ -- ^ e.g. @(a | b | c)@++ | IfaceEqualityTyCon !Bool+ -- ^ a type equality. 'True' indicates kind-homogeneous.+ -- See Note [Equality predicates in IfaceType] for+ -- details.+ deriving (Eq)++{- Note [Free tyvars in IfaceType]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Nowadays (since Nov 16, 2016) we pretty-print a Type by converting to an+IfaceType and pretty printing that. This eliminates a lot of+pretty-print duplication, and it matches what we do with+pretty-printing TyThings.++It works fine for closed types, but when printing debug traces (e.g.+when using -ddump-tc-trace) we print a lot of /open/ types. These+types are full of TcTyVars, and it's absolutely crucial to print them+in their full glory, with their unique, TcTyVarDetails etc.++So we simply embed a TyVar in IfaceType with the IfaceFreeTyVar constructor.+Note that:++* We never expect to serialise an IfaceFreeTyVar into an interface file, nor+ to deserialise one. IfaceFreeTyVar is used only in the "convert to IfaceType+ and then pretty-print" pipeline.+++Note [Equality predicates in IfaceType]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC has several varieties of type equality (see Note [The equality types story]+in TysPrim for details) which all must be rendered with different surface syntax+during pretty-printing. Which syntax we use depends upon,++ 1. Which predicate tycon was used+ 2. Whether the types being compared are of the same kind.++Unfortunately, determining (2) from an IfaceType isn't possible since we can't+see through type synonyms. Consequently, we need to record whether the equality+is homogeneous or not in IfaceTyConSort for the purposes of pretty-printing.++Namely we handle these cases,++ Predicate Homogeneous Heterogeneous+ ---------------- ----------- -------------+ eqTyCon ~ N/A+ heqTyCon ~ ~~+ eqPrimTyCon ~# ~~+ eqReprPrimTyCon Coercible Coercible++-}++data IfaceTyConInfo -- Used to guide pretty-printing+ -- and to disambiguate D from 'D (they share a name)+ = IfaceTyConInfo { ifaceTyConIsPromoted :: IsPromoted+ , ifaceTyConSort :: IfaceTyConSort }+ deriving (Eq)++data IfaceCoercion+ = IfaceReflCo Role IfaceType+ | IfaceFunCo Role IfaceCoercion IfaceCoercion+ | IfaceTyConAppCo Role IfaceTyCon [IfaceCoercion]+ | IfaceAppCo IfaceCoercion IfaceCoercion+ | IfaceForAllCo IfaceTvBndr IfaceCoercion IfaceCoercion+ | IfaceCoVarCo IfLclName+ | IfaceAxiomInstCo IfExtName BranchIndex [IfaceCoercion]+ | IfaceUnivCo IfaceUnivCoProv Role IfaceType IfaceType+ | IfaceSymCo IfaceCoercion+ | IfaceTransCo IfaceCoercion IfaceCoercion+ | IfaceNthCo Int IfaceCoercion+ | IfaceLRCo LeftOrRight IfaceCoercion+ | IfaceInstCo IfaceCoercion IfaceCoercion+ | IfaceCoherenceCo IfaceCoercion IfaceCoercion+ | IfaceKindCo IfaceCoercion+ | IfaceSubCo IfaceCoercion+ | IfaceAxiomRuleCo IfLclName [IfaceCoercion]++data IfaceUnivCoProv+ = IfaceUnsafeCoerceProv+ | IfacePhantomProv IfaceCoercion+ | IfaceProofIrrelProv IfaceCoercion+ | IfacePluginProv String+ | IfaceHoleProv Unique+ -- ^ See Note [Holes in IfaceUnivCoProv]++{-+Note [Holes in IfaceUnivCoProv]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When typechecking fails the typechecker will produce a HoleProv UnivCoProv to+stand in place of the unproven assertion. While we generally don't want to let+these unproven assertions leak into interface files, we still need to be able to+pretty-print them as we use IfaceType's pretty-printer to render Types. For this+reason IfaceUnivCoProv has a IfaceHoleProv constructor; however, we fails when+asked to serialize to a IfaceHoleProv to ensure that they don't end up in an+interface file. To avoid an import loop between IfaceType and TyCoRep we only+keep the hole's Unique, since that is all we need to print.+-}++{-+%************************************************************************+%* *+ Functions over IFaceTypes+* *+************************************************************************+-}++ifaceTyConHasKey :: IfaceTyCon -> Unique -> Bool+ifaceTyConHasKey tc key = ifaceTyConName tc `hasKey` key++eqIfaceTvBndr :: IfaceTvBndr -> IfaceTvBndr -> Bool+eqIfaceTvBndr (occ1, _) (occ2, _) = occ1 == occ2++isIfaceLiftedTypeKind :: IfaceKind -> Bool+isIfaceLiftedTypeKind (IfaceTyConApp tc ITC_Nil)+ = isLiftedTypeKindTyConName (ifaceTyConName tc)+isIfaceLiftedTypeKind (IfaceTyConApp tc+ (ITC_Vis (IfaceTyConApp ptr_rep_lifted ITC_Nil) ITC_Nil))+ = tc `ifaceTyConHasKey` tYPETyConKey+ && ptr_rep_lifted `ifaceTyConHasKey` liftedRepDataConKey+isIfaceLiftedTypeKind _ = False++splitIfaceSigmaTy :: IfaceType -> ([IfaceForAllBndr], [IfacePredType], IfaceType)+-- Mainly for printing purposes+splitIfaceSigmaTy ty+ = (bndrs, theta, tau)+ where+ (bndrs, rho) = split_foralls ty+ (theta, tau) = split_rho rho++ split_foralls (IfaceForAllTy bndr ty)+ = case split_foralls ty of { (bndrs, rho) -> (bndr:bndrs, rho) }+ split_foralls rho = ([], rho)++ split_rho (IfaceDFunTy ty1 ty2)+ = case split_rho ty2 of { (ps, tau) -> (ty1:ps, tau) }+ split_rho tau = ([], tau)++suppressIfaceInvisibles :: DynFlags -> [IfaceTyConBinder] -> [a] -> [a]+suppressIfaceInvisibles dflags tys xs+ | gopt Opt_PrintExplicitKinds dflags = xs+ | otherwise = suppress tys xs+ where+ suppress _ [] = []+ suppress [] a = a+ suppress (k:ks) a@(_:xs)+ | isInvisibleTyConBinder k = suppress ks xs+ | otherwise = a++stripIfaceInvisVars :: DynFlags -> [IfaceTyConBinder] -> [IfaceTyConBinder]+stripIfaceInvisVars dflags tyvars+ | gopt Opt_PrintExplicitKinds dflags = tyvars+ | otherwise = filterOut isInvisibleTyConBinder tyvars++-- | Extract a IfaceTvBndr from a IfaceTyConBinder+ifTyConBinderTyVar :: IfaceTyConBinder -> IfaceTvBndr+ifTyConBinderTyVar = binderVar++-- | Extract the variable name from a IfaceTyConBinder+ifTyConBinderName :: IfaceTyConBinder -> IfLclName+ifTyConBinderName tcb = ifaceTvBndrName (ifTyConBinderTyVar tcb)++ifTypeIsVarFree :: IfaceType -> Bool+-- Returns True if the type definitely has no variables at all+-- Just used to control pretty printing+ifTypeIsVarFree ty = go ty+ where+ go (IfaceTyVar {}) = False+ go (IfaceFreeTyVar {}) = False+ go (IfaceAppTy fun arg) = go fun && go arg+ go (IfaceFunTy arg res) = go arg && go res+ go (IfaceDFunTy arg res) = go arg && go res+ go (IfaceForAllTy {}) = False+ go (IfaceTyConApp _ args) = go_args args+ go (IfaceTupleTy _ _ args) = go_args args+ go (IfaceLitTy _) = True+ go (IfaceCastTy {}) = False -- Safe+ go (IfaceCoercionTy {}) = False -- Safe++ go_args ITC_Nil = True+ go_args (ITC_Vis arg args) = go arg && go_args args+ go_args (ITC_Invis arg args) = go arg && go_args args++{-+Substitutions on IfaceType. This is only used during pretty-printing to construct+the result type of a GADT, and does not deal with binders (eg IfaceForAll), so+it doesn't need fancy capture stuff.+-}++type IfaceTySubst = FastStringEnv IfaceType++mkIfaceTySubst :: [IfaceTvBndr] -> [IfaceType] -> IfaceTySubst+mkIfaceTySubst tvs tys = mkFsEnv $ zipWithEqual "mkIfaceTySubst" (\(fs,_) ty -> (fs,ty)) tvs tys++substIfaceType :: IfaceTySubst -> IfaceType -> IfaceType+substIfaceType env ty+ = go ty+ where+ go (IfaceFreeTyVar tv) = IfaceFreeTyVar tv+ go (IfaceTyVar tv) = substIfaceTyVar env tv+ go (IfaceAppTy t1 t2) = IfaceAppTy (go t1) (go t2)+ go (IfaceFunTy t1 t2) = IfaceFunTy (go t1) (go t2)+ go (IfaceDFunTy t1 t2) = IfaceDFunTy (go t1) (go t2)+ go ty@(IfaceLitTy {}) = ty+ go (IfaceTyConApp tc tys) = IfaceTyConApp tc (substIfaceTcArgs env tys)+ go (IfaceTupleTy s i tys) = IfaceTupleTy s i (substIfaceTcArgs env tys)+ go (IfaceForAllTy {}) = pprPanic "substIfaceType" (ppr ty)+ go (IfaceCastTy ty co) = IfaceCastTy (go ty) (go_co co)+ go (IfaceCoercionTy co) = IfaceCoercionTy (go_co co)++ go_co (IfaceReflCo r ty) = IfaceReflCo r (go ty)+ go_co (IfaceFunCo r c1 c2) = IfaceFunCo r (go_co c1) (go_co c2)+ go_co (IfaceTyConAppCo r tc cos) = IfaceTyConAppCo r tc (go_cos cos)+ go_co (IfaceAppCo c1 c2) = IfaceAppCo (go_co c1) (go_co c2)+ go_co (IfaceForAllCo {}) = pprPanic "substIfaceCoercion" (ppr ty)+ go_co (IfaceCoVarCo cv) = IfaceCoVarCo cv+ go_co (IfaceAxiomInstCo a i cos) = IfaceAxiomInstCo a i (go_cos cos)+ go_co (IfaceUnivCo prov r t1 t2) = IfaceUnivCo (go_prov prov) r (go t1) (go t2)+ go_co (IfaceSymCo co) = IfaceSymCo (go_co co)+ go_co (IfaceTransCo co1 co2) = IfaceTransCo (go_co co1) (go_co co2)+ go_co (IfaceNthCo n co) = IfaceNthCo n (go_co co)+ go_co (IfaceLRCo lr co) = IfaceLRCo lr (go_co co)+ go_co (IfaceInstCo c1 c2) = IfaceInstCo (go_co c1) (go_co c2)+ go_co (IfaceCoherenceCo c1 c2) = IfaceCoherenceCo (go_co c1) (go_co c2)+ go_co (IfaceKindCo co) = IfaceKindCo (go_co co)+ go_co (IfaceSubCo co) = IfaceSubCo (go_co co)+ go_co (IfaceAxiomRuleCo n cos) = IfaceAxiomRuleCo n (go_cos cos)++ go_cos = map go_co++ go_prov IfaceUnsafeCoerceProv = IfaceUnsafeCoerceProv+ go_prov (IfacePhantomProv co) = IfacePhantomProv (go_co co)+ go_prov (IfaceProofIrrelProv co) = IfaceProofIrrelProv (go_co co)+ go_prov (IfacePluginProv str) = IfacePluginProv str+ go_prov (IfaceHoleProv h) = IfaceHoleProv h++substIfaceTcArgs :: IfaceTySubst -> IfaceTcArgs -> IfaceTcArgs+substIfaceTcArgs env args+ = go args+ where+ go ITC_Nil = ITC_Nil+ go (ITC_Vis ty tys) = ITC_Vis (substIfaceType env ty) (go tys)+ go (ITC_Invis ty tys) = ITC_Invis (substIfaceType env ty) (go tys)++substIfaceTyVar :: IfaceTySubst -> IfLclName -> IfaceType+substIfaceTyVar env tv+ | Just ty <- lookupFsEnv env tv = ty+ | otherwise = IfaceTyVar tv++{-+************************************************************************+* *+ Equality over IfaceTypes+* *+************************************************************************++Note [No kind check in ifaces]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We check iface types for equality only when checking the consistency+between two user-written signatures. In these cases, there is no possibility+for a kind mismatch. So we omit the kind check (which would be impossible to+write, anyway.)++-}++-- Like an RnEnv2, but mapping from FastString to deBruijn index+-- DeBruijn; see eqTypeX+type BoundVar = Int+data IfRnEnv2+ = IRV2 { ifenvL :: UniqFM BoundVar -- from FastString+ , ifenvR :: UniqFM BoundVar+ , ifenv_next :: BoundVar+ }++emptyIfRnEnv2 :: IfRnEnv2+emptyIfRnEnv2 = IRV2 { ifenvL = emptyUFM+ , ifenvR = emptyUFM+ , ifenv_next = 0 }++rnIfOccL :: IfRnEnv2 -> IfLclName -> Maybe BoundVar+rnIfOccL env = lookupUFM (ifenvL env)++rnIfOccR :: IfRnEnv2 -> IfLclName -> Maybe BoundVar+rnIfOccR env = lookupUFM (ifenvR env)++extendIfRnEnv2 :: IfRnEnv2 -> IfLclName -> IfLclName -> IfRnEnv2+extendIfRnEnv2 IRV2 { ifenvL = lenv+ , ifenvR = renv+ , ifenv_next = n } tv1 tv2+ = IRV2 { ifenvL = addToUFM lenv tv1 n+ , ifenvR = addToUFM renv tv2 n+ , ifenv_next = n + 1+ }++-- See Note [No kind check in ifaces]+eqIfaceType :: IfRnEnv2 -> IfaceType -> IfaceType -> Bool+eqIfaceType _ (IfaceFreeTyVar tv1) (IfaceFreeTyVar tv2)+ = tv1 == tv2 -- Should not happen+eqIfaceType env (IfaceTyVar tv1) (IfaceTyVar tv2) =+ case (rnIfOccL env tv1, rnIfOccR env tv2) of+ (Just v1, Just v2) -> v1 == v2+ (Nothing, Nothing) -> tv1 == tv2+ _ -> False+eqIfaceType _ (IfaceLitTy l1) (IfaceLitTy l2) = l1 == l2+eqIfaceType env (IfaceAppTy t11 t12) (IfaceAppTy t21 t22)+ = eqIfaceType env t11 t21 && eqIfaceType env t12 t22+eqIfaceType env (IfaceFunTy t11 t12) (IfaceFunTy t21 t22)+ = eqIfaceType env t11 t21 && eqIfaceType env t12 t22+eqIfaceType env (IfaceDFunTy t11 t12) (IfaceDFunTy t21 t22)+ = eqIfaceType env t11 t21 && eqIfaceType env t12 t22+eqIfaceType env (IfaceForAllTy bndr1 t1) (IfaceForAllTy bndr2 t2)+ = eqIfaceForAllBndr env bndr1 bndr2 (\env' -> eqIfaceType env' t1 t2)+eqIfaceType env (IfaceTyConApp tc1 tys1) (IfaceTyConApp tc2 tys2)+ = tc1 == tc2 && eqIfaceTcArgs env tys1 tys2+eqIfaceType env (IfaceTupleTy s1 tc1 tys1) (IfaceTupleTy s2 tc2 tys2)+ = s1 == s2 && tc1 == tc2 && eqIfaceTcArgs env tys1 tys2+eqIfaceType env (IfaceCastTy t1 _) (IfaceCastTy t2 _)+ = eqIfaceType env t1 t2+eqIfaceType _ (IfaceCoercionTy {}) (IfaceCoercionTy {})+ = True+eqIfaceType _ _ _ = False++eqIfaceTypes :: IfRnEnv2 -> [IfaceType] -> [IfaceType] -> Bool+eqIfaceTypes env tys1 tys2 = and (zipWith (eqIfaceType env) tys1 tys2)++eqIfaceForAllBndr :: IfRnEnv2 -> IfaceForAllBndr -> IfaceForAllBndr+ -> (IfRnEnv2 -> Bool) -- continuation+ -> Bool+eqIfaceForAllBndr env (TvBndr (tv1, k1) vis1) (TvBndr (tv2, k2) vis2) k+ = eqIfaceType env k1 k2 && vis1 == vis2 &&+ k (extendIfRnEnv2 env tv1 tv2)++eqIfaceTcArgs :: IfRnEnv2 -> IfaceTcArgs -> IfaceTcArgs -> Bool+eqIfaceTcArgs _ ITC_Nil ITC_Nil = True+eqIfaceTcArgs env (ITC_Vis ty1 tys1) (ITC_Vis ty2 tys2)+ = eqIfaceType env ty1 ty2 && eqIfaceTcArgs env tys1 tys2+eqIfaceTcArgs env (ITC_Invis ty1 tys1) (ITC_Invis ty2 tys2)+ = eqIfaceType env ty1 ty2 && eqIfaceTcArgs env tys1 tys2+eqIfaceTcArgs _ _ _ = False++-- | Similar to 'eqTyVarBndrs', checks that tyvar lists+-- are the same length and have matching kinds; if so, extend the+-- 'IfRnEnv2'. Returns 'Nothing' if they don't match.+eqIfaceTvBndrs :: IfRnEnv2 -> [IfaceTvBndr] -> [IfaceTvBndr] -> Maybe IfRnEnv2+eqIfaceTvBndrs env [] [] = Just env+eqIfaceTvBndrs env ((tv1, k1):tvs1) ((tv2, k2):tvs2)+ | eqIfaceType env k1 k2+ = eqIfaceTvBndrs (extendIfRnEnv2 env tv1 tv2) tvs1 tvs2+eqIfaceTvBndrs _ _ _ = Nothing++{-+************************************************************************+* *+ Functions over IFaceTcArgs+* *+************************************************************************+-}++stripInvisArgs :: DynFlags -> IfaceTcArgs -> IfaceTcArgs+stripInvisArgs dflags tys+ | gopt Opt_PrintExplicitKinds dflags = tys+ | otherwise = suppress_invis tys+ where+ suppress_invis c+ = case c of+ ITC_Invis _ ts -> suppress_invis ts+ _ -> c++tcArgsIfaceTypes :: IfaceTcArgs -> [IfaceType]+tcArgsIfaceTypes ITC_Nil = []+tcArgsIfaceTypes (ITC_Invis t ts) = t : tcArgsIfaceTypes ts+tcArgsIfaceTypes (ITC_Vis t ts) = t : tcArgsIfaceTypes ts++ifaceVisTcArgsLength :: IfaceTcArgs -> Int+ifaceVisTcArgsLength = go 0+ where+ go !n ITC_Nil = n+ go n (ITC_Vis _ rest) = go (n+1) rest+ go n (ITC_Invis _ rest) = go n rest++{-+Note [Suppressing invisible arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We use the IfaceTcArgs to specify which of the arguments to a type+constructor should be displayed when pretty-printing, under+the control of -fprint-explicit-kinds.+See also Type.filterOutInvisibleTypes.+For example, given+ T :: forall k. (k->*) -> k -> * -- Ordinary kind polymorphism+ 'Just :: forall k. k -> 'Maybe k -- Promoted+we want+ T * Tree Int prints as T Tree Int+ 'Just * prints as Just *+++************************************************************************+* *+ Pretty-printing+* *+************************************************************************+-}++if_print_coercions :: SDoc -- ^ if printing coercions+ -> SDoc -- ^ otherwise+ -> SDoc+if_print_coercions yes no+ = sdocWithDynFlags $ \dflags ->+ getPprStyle $ \style ->+ if gopt Opt_PrintExplicitCoercions dflags+ || dumpStyle style || debugStyle style+ then yes+ else no++pprIfaceInfixApp :: (TyPrec -> a -> SDoc) -> TyPrec -> SDoc -> a -> a -> SDoc+pprIfaceInfixApp pp p pp_tc ty1 ty2+ = maybeParen p FunPrec $+ sep [pp FunPrec ty1, pprInfixVar True pp_tc <+> pp FunPrec ty2]++pprIfacePrefixApp :: TyPrec -> SDoc -> [SDoc] -> SDoc+pprIfacePrefixApp p pp_fun pp_tys+ | null pp_tys = pp_fun+ | otherwise = maybeParen p TyConPrec $+ hang pp_fun 2 (sep pp_tys)++-- ----------------------------- Printing binders ------------------------------------++instance Outputable IfaceBndr where+ ppr (IfaceIdBndr bndr) = pprIfaceIdBndr bndr+ ppr (IfaceTvBndr bndr) = char '@' <+> pprIfaceTvBndr False bndr++pprIfaceBndrs :: [IfaceBndr] -> SDoc+pprIfaceBndrs bs = sep (map ppr bs)++pprIfaceLamBndr :: IfaceLamBndr -> SDoc+pprIfaceLamBndr (b, IfaceNoOneShot) = ppr b+pprIfaceLamBndr (b, IfaceOneShot) = ppr b <> text "[OneShot]"++pprIfaceIdBndr :: IfaceIdBndr -> SDoc+pprIfaceIdBndr (name, ty) = parens (ppr name <+> dcolon <+> ppr ty)++pprIfaceTvBndr :: Bool -> IfaceTvBndr -> SDoc+pprIfaceTvBndr use_parens (tv, ki)+ | isIfaceLiftedTypeKind ki = ppr tv+ | otherwise = maybe_parens (ppr tv <+> dcolon <+> ppr ki)+ where+ maybe_parens | use_parens = parens+ | otherwise = id++pprIfaceTyConBinders :: [IfaceTyConBinder] -> SDoc+pprIfaceTyConBinders = sep . map go+ where+ go tcb = pprIfaceTvBndr True (ifTyConBinderTyVar tcb)++instance Binary IfaceBndr where+ put_ bh (IfaceIdBndr aa) = do+ putByte bh 0+ put_ bh aa+ put_ bh (IfaceTvBndr ab) = do+ putByte bh 1+ put_ bh ab+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do aa <- get bh+ return (IfaceIdBndr aa)+ _ -> do ab <- get bh+ return (IfaceTvBndr ab)++instance Binary IfaceOneShot where+ put_ bh IfaceNoOneShot = do+ putByte bh 0+ put_ bh IfaceOneShot = do+ putByte bh 1+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return IfaceNoOneShot+ _ -> do return IfaceOneShot++-- ----------------------------- Printing IfaceType ------------------------------------++---------------------------------+instance Outputable IfaceType where+ ppr ty = pprIfaceType ty++pprIfaceType, pprParendIfaceType :: IfaceType -> SDoc+pprIfaceType = eliminateRuntimeRep (ppr_ty TopPrec)+pprParendIfaceType = eliminateRuntimeRep (ppr_ty TyConPrec)++ppr_ty :: TyPrec -> IfaceType -> SDoc+ppr_ty _ (IfaceFreeTyVar tyvar) = ppr tyvar -- This is the main reson for IfaceFreeTyVar!+ppr_ty _ (IfaceTyVar tyvar) = ppr tyvar -- See Note [TcTyVars in IfaceType]+ppr_ty ctxt_prec (IfaceTyConApp tc tys) = pprTyTcApp ctxt_prec tc tys+ppr_ty _ (IfaceTupleTy i p tys) = pprTuple i p tys+ppr_ty _ (IfaceLitTy n) = pprIfaceTyLit n+ -- Function types+ppr_ty ctxt_prec (IfaceFunTy ty1 ty2)+ = -- We don't want to lose synonyms, so we mustn't use splitFunTys here.+ maybeParen ctxt_prec FunPrec $+ sep [ppr_ty FunPrec ty1, sep (ppr_fun_tail ty2)]+ where+ ppr_fun_tail (IfaceFunTy ty1 ty2)+ = (arrow <+> ppr_ty FunPrec ty1) : ppr_fun_tail ty2+ ppr_fun_tail other_ty+ = [arrow <+> pprIfaceType other_ty]++ppr_ty ctxt_prec (IfaceAppTy ty1 ty2)+ = if_print_coercions+ ppr_app_ty+ ppr_app_ty_no_casts+ where+ ppr_app_ty =+ maybeParen ctxt_prec TyConPrec+ $ ppr_ty FunPrec ty1 <+> ppr_ty TyConPrec ty2++ -- Strip any casts from the head of the application+ ppr_app_ty_no_casts =+ case split_app_tys ty1 (ITC_Vis ty2 ITC_Nil) of+ (IfaceCastTy head _, args) -> ppr_ty ctxt_prec (mk_app_tys head args)+ _ -> ppr_app_ty++ split_app_tys :: IfaceType -> IfaceTcArgs -> (IfaceType, IfaceTcArgs)+ split_app_tys (IfaceAppTy t1 t2) args = split_app_tys t1 (t2 `ITC_Vis` args)+ split_app_tys head args = (head, args)++ mk_app_tys :: IfaceType -> IfaceTcArgs -> IfaceType+ mk_app_tys (IfaceTyConApp tc tys1) tys2 =+ IfaceTyConApp tc (tys1 `mappend` tys2)+ mk_app_tys t1 tys2 =+ foldl' IfaceAppTy t1 (tcArgsIfaceTypes tys2)++ppr_ty ctxt_prec (IfaceCastTy ty co)+ = if_print_coercions+ (parens (ppr_ty TopPrec ty <+> text "|>" <+> ppr co))+ (ppr_ty ctxt_prec ty)++ppr_ty ctxt_prec (IfaceCoercionTy co)+ = if_print_coercions+ (ppr_co ctxt_prec co)+ (text "<>")++ppr_ty ctxt_prec ty+ = maybeParen ctxt_prec FunPrec (pprIfaceSigmaType ShowForAllMust ty)++{-+Note [Defaulting RuntimeRep variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++RuntimeRep variables are considered by many (most?) users to be little more than+syntactic noise. When the notion was introduced there was a signficant and+understandable push-back from those with pedagogy in mind, which argued that+RuntimeRep variables would throw a wrench into nearly any teach approach since+they appear in even the lowly ($) function's type,++ ($) :: forall (w :: RuntimeRep) a (b :: TYPE w). (a -> b) -> a -> b++which is significantly less readable than its non RuntimeRep-polymorphic type of++ ($) :: (a -> b) -> a -> b++Moreover, unboxed types don't appear all that often in run-of-the-mill Haskell+programs, so it makes little sense to make all users pay this syntactic+overhead.++For this reason it was decided that we would hide RuntimeRep variables for now+(see #11549). We do this by defaulting all type variables of kind RuntimeRep to+PtrLiftedRep. This is done in a pass right before pretty-printing+(defaultRuntimeRepVars, controlled by -fprint-explicit-runtime-reps)+-}++-- | Default 'RuntimeRep' variables to 'LiftedPtr'. e.g.+--+-- @+-- ($) :: forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).+-- (a -> b) -> a -> b+-- @+--+-- turns in to,+--+-- @ ($) :: forall a (b :: *). (a -> b) -> a -> b @+--+-- We do this to prevent RuntimeRep variables from incurring a significant+-- syntactic overhead in otherwise simple type signatures (e.g. ($)). See+-- Note [Defaulting RuntimeRep variables] and #11549 for further discussion.+--+defaultRuntimeRepVars :: IfaceType -> IfaceType+defaultRuntimeRepVars = go emptyFsEnv+ where+ go :: FastStringEnv () -> IfaceType -> IfaceType+ go subs (IfaceForAllTy bndr ty)+ | isRuntimeRep var_kind+ = let subs' = extendFsEnv subs var ()+ in go subs' ty+ | otherwise+ = IfaceForAllTy (TvBndr (var, go subs var_kind) (binderArgFlag bndr))+ (go subs ty)+ where+ var :: IfLclName+ (var, var_kind) = binderVar bndr++ go subs (IfaceTyVar tv)+ | tv `elemFsEnv` subs+ = IfaceTyConApp liftedRep ITC_Nil++ go subs (IfaceFunTy kind ty)+ = IfaceFunTy (go subs kind) (go subs ty)++ go subs (IfaceAppTy x y)+ = IfaceAppTy (go subs x) (go subs y)++ go subs (IfaceDFunTy x y)+ = IfaceDFunTy (go subs x) (go subs y)++ go subs (IfaceCastTy x co)+ = IfaceCastTy (go subs x) co++ go _ other = other++ liftedRep :: IfaceTyCon+ liftedRep =+ IfaceTyCon dc_name (IfaceTyConInfo IsPromoted IfaceNormalTyCon)+ where dc_name = getName liftedRepDataConTyCon++ isRuntimeRep :: IfaceType -> Bool+ isRuntimeRep (IfaceTyConApp tc _) =+ tc `ifaceTyConHasKey` runtimeRepTyConKey+ isRuntimeRep _ = False++eliminateRuntimeRep :: (IfaceType -> SDoc) -> IfaceType -> SDoc+eliminateRuntimeRep f ty = sdocWithDynFlags $ \dflags ->+ if gopt Opt_PrintExplicitRuntimeReps dflags+ then f ty+ else f (defaultRuntimeRepVars ty)++instance Outputable IfaceTcArgs where+ ppr tca = pprIfaceTcArgs tca++pprIfaceTcArgs, pprParendIfaceTcArgs :: IfaceTcArgs -> SDoc+pprIfaceTcArgs = ppr_tc_args TopPrec+pprParendIfaceTcArgs = ppr_tc_args TyConPrec++ppr_tc_args :: TyPrec -> IfaceTcArgs -> SDoc+ppr_tc_args ctx_prec args+ = let pprTys t ts = ppr_ty ctx_prec t <+> ppr_tc_args ctx_prec ts+ in case args of+ ITC_Nil -> empty+ ITC_Vis t ts -> pprTys t ts+ ITC_Invis t ts -> pprTys t ts++-------------------+pprIfaceForAllPart :: [IfaceForAllBndr] -> [IfacePredType] -> SDoc -> SDoc+pprIfaceForAllPart tvs ctxt sdoc+ = ppr_iface_forall_part ShowForAllWhen tvs ctxt sdoc++pprIfaceForAllCoPart :: [(IfLclName, IfaceCoercion)] -> SDoc -> SDoc+pprIfaceForAllCoPart tvs sdoc+ = sep [ pprIfaceForAllCo tvs, sdoc ]++ppr_iface_forall_part :: ShowForAllFlag+ -> [IfaceForAllBndr] -> [IfacePredType] -> SDoc -> SDoc+ppr_iface_forall_part show_forall tvs ctxt sdoc+ = sep [ case show_forall of+ ShowForAllMust -> pprIfaceForAll tvs+ ShowForAllWhen -> pprUserIfaceForAll tvs+ , pprIfaceContextArr ctxt+ , sdoc]++-- | Render the "forall ... ." or "forall ... ->" bit of a type.+pprIfaceForAll :: [IfaceForAllBndr] -> SDoc+pprIfaceForAll [] = empty+pprIfaceForAll bndrs@(TvBndr _ vis : _)+ = add_separator (forAllLit <+> doc) <+> pprIfaceForAll bndrs'+ where+ (bndrs', doc) = ppr_itv_bndrs bndrs vis++ add_separator stuff = case vis of+ Required -> stuff <+> arrow+ _inv -> stuff <> dot+++-- | Render the ... in @(forall ... .)@ or @(forall ... ->)@.+-- Returns both the list of not-yet-rendered binders and the doc.+-- No anonymous binders here!+ppr_itv_bndrs :: [IfaceForAllBndr]+ -> ArgFlag -- ^ visibility of the first binder in the list+ -> ([IfaceForAllBndr], SDoc)+ppr_itv_bndrs all_bndrs@(bndr@(TvBndr _ vis) : bndrs) vis1+ | vis `sameVis` vis1 = let (bndrs', doc) = ppr_itv_bndrs bndrs vis1 in+ (bndrs', pprIfaceForAllBndr bndr <+> doc)+ | otherwise = (all_bndrs, empty)+ppr_itv_bndrs [] _ = ([], empty)++pprIfaceForAllCo :: [(IfLclName, IfaceCoercion)] -> SDoc+pprIfaceForAllCo [] = empty+pprIfaceForAllCo tvs = text "forall" <+> pprIfaceForAllCoBndrs tvs <> dot++pprIfaceForAllCoBndrs :: [(IfLclName, IfaceCoercion)] -> SDoc+pprIfaceForAllCoBndrs bndrs = hsep $ map pprIfaceForAllCoBndr bndrs++pprIfaceForAllBndr :: IfaceForAllBndr -> SDoc+pprIfaceForAllBndr (TvBndr tv Inferred) = sdocWithDynFlags $ \dflags ->+ if gopt Opt_PrintExplicitForalls dflags+ then braces $ pprIfaceTvBndr False tv+ else pprIfaceTvBndr True tv+pprIfaceForAllBndr (TvBndr tv _) = pprIfaceTvBndr True tv++pprIfaceForAllCoBndr :: (IfLclName, IfaceCoercion) -> SDoc+pprIfaceForAllCoBndr (tv, kind_co)+ = parens (ppr tv <+> dcolon <+> pprIfaceCoercion kind_co)++-- | Show forall flag+--+-- Unconditionally show the forall quantifier with ('ShowForAllMust')+-- or when ('ShowForAllWhen') the names used are free in the binder+-- or when compiling with -fprint-explicit-foralls.+data ShowForAllFlag = ShowForAllMust | ShowForAllWhen++pprIfaceSigmaType :: ShowForAllFlag -> IfaceType -> SDoc+pprIfaceSigmaType show_forall ty+ = ppr_iface_forall_part show_forall tvs theta (ppr tau)+ where+ (tvs, theta, tau) = splitIfaceSigmaTy ty++pprUserIfaceForAll :: [IfaceForAllBndr] -> SDoc+pprUserIfaceForAll tvs+ = sdocWithDynFlags $ \dflags ->+ ppWhen (any tv_has_kind_var tvs || gopt Opt_PrintExplicitForalls dflags) $+ pprIfaceForAll tvs+ where+ tv_has_kind_var (TvBndr (_,kind) _) = not (ifTypeIsVarFree kind)+++-------------------++-- See equivalent function in TyCoRep.hs+pprIfaceTyList :: TyPrec -> IfaceType -> IfaceType -> SDoc+-- Given a type-level list (t1 ': t2), see if we can print+-- it in list notation [t1, ...].+-- Precondition: Opt_PrintExplicitKinds is off+pprIfaceTyList ctxt_prec ty1 ty2+ = case gather ty2 of+ (arg_tys, Nothing)+ -> char '\'' <> brackets (fsep (punctuate comma+ (map (ppr_ty TopPrec) (ty1:arg_tys))))+ (arg_tys, Just tl)+ -> maybeParen ctxt_prec FunPrec $ hang (ppr_ty FunPrec ty1)+ 2 (fsep [ colon <+> ppr_ty FunPrec ty | ty <- arg_tys ++ [tl]])+ where+ gather :: IfaceType -> ([IfaceType], Maybe IfaceType)+ -- (gather ty) = (tys, Nothing) means ty is a list [t1, .., tn]+ -- = (tys, Just tl) means ty is of form t1:t2:...tn:tl+ gather (IfaceTyConApp tc tys)+ | tc `ifaceTyConHasKey` consDataConKey+ , (ITC_Invis _ (ITC_Vis ty1 (ITC_Vis ty2 ITC_Nil))) <- tys+ , (args, tl) <- gather ty2+ = (ty1:args, tl)+ | tc `ifaceTyConHasKey` nilDataConKey+ = ([], Nothing)+ gather ty = ([], Just ty)++pprIfaceTypeApp :: TyPrec -> IfaceTyCon -> IfaceTcArgs -> SDoc+pprIfaceTypeApp prec tc args = pprTyTcApp prec tc args++pprTyTcApp :: TyPrec -> IfaceTyCon -> IfaceTcArgs -> SDoc+pprTyTcApp ctxt_prec tc tys =+ sdocWithDynFlags $ \dflags ->+ getPprStyle $ \style ->+ pprTyTcApp' ctxt_prec tc tys dflags style++pprTyTcApp' :: TyPrec -> IfaceTyCon -> IfaceTcArgs+ -> DynFlags -> PprStyle -> SDoc+pprTyTcApp' ctxt_prec tc tys dflags style+ | ifaceTyConName tc `hasKey` ipClassKey+ , ITC_Vis (IfaceLitTy (IfaceStrTyLit n)) (ITC_Vis ty ITC_Nil) <- tys+ = maybeParen ctxt_prec FunPrec+ $ char '?' <> ftext n <> text "::" <> ppr_ty TopPrec ty++ | IfaceTupleTyCon arity sort <- ifaceTyConSort info+ , not (debugStyle style)+ , arity == ifaceVisTcArgsLength tys+ = pprTuple sort (ifaceTyConIsPromoted info) tys++ | IfaceSumTyCon arity <- ifaceTyConSort info+ = pprSum arity (ifaceTyConIsPromoted info) tys++ | tc `ifaceTyConHasKey` consDataConKey+ , not (gopt Opt_PrintExplicitKinds dflags)+ , ITC_Invis _ (ITC_Vis ty1 (ITC_Vis ty2 ITC_Nil)) <- tys+ = pprIfaceTyList ctxt_prec ty1 ty2++ | tc `ifaceTyConHasKey` tYPETyConKey+ , ITC_Vis (IfaceTyConApp rep ITC_Nil) ITC_Nil <- tys+ , rep `ifaceTyConHasKey` liftedRepDataConKey+ = kindStar++ | otherwise+ = sdocWithPprDebug $ \dbg ->+ if | not dbg && tc `ifaceTyConHasKey` errorMessageTypeErrorFamKey+ -- Suppress detail unles you _really_ want to see+ -> text "(TypeError ...)"++ | Just doc <- ppr_equality tc (tcArgsIfaceTypes tys)+ -> maybeParen ctxt_prec TyConPrec doc++ | otherwise+ -> ppr_iface_tc_app ppr_ty ctxt_prec tc tys_wo_kinds+ where+ info = ifaceTyConInfo tc+ tys_wo_kinds = tcArgsIfaceTypes $ stripInvisArgs dflags tys++-- | Pretty-print a type-level equality.+--+-- See Note [Equality predicates in IfaceType].+ppr_equality :: IfaceTyCon -> [IfaceType] -> Maybe SDoc+ppr_equality tc args+ | hetero_eq_tc+ , [k1, k2, t1, t2] <- args+ = Just $ print_equality (k1, k2, t1, t2)++ | hom_eq_tc+ , [k, t1, t2] <- args+ = Just $ print_equality (k, k, t1, t2)++ | otherwise+ = Nothing+ where+ homogeneous = case ifaceTyConSort $ ifaceTyConInfo tc of+ IfaceEqualityTyCon hom -> hom+ _other -> pprPanic "ppr_equality: homogeneity" (ppr tc)+ tc_name = ifaceTyConName tc+ pp = ppr_ty+ hom_eq_tc = tc_name `hasKey` eqTyConKey -- (~)+ hetero_eq_tc = tc_name `hasKey` eqPrimTyConKey -- (~#)+ || tc_name `hasKey` eqReprPrimTyConKey -- (~R#)+ || tc_name `hasKey` heqTyConKey -- (~~)++ print_equality args =+ sdocWithDynFlags+ $ \dflags -> getPprStyle+ $ \style -> print_equality' args style dflags++ print_equality' (ki1, ki2, ty1, ty2) style dflags+ | print_eqs+ = ppr_infix_eq (ppr tc)++ | hetero_eq_tc+ , print_kinds || not homogeneous+ = ppr_infix_eq (text "~~")++ | otherwise+ = if tc_name `hasKey` eqReprPrimTyConKey+ then text "Coercible"+ <+> sep [ pp TyConPrec ty1, pp TyConPrec ty2 ]+ else sep [pp TyOpPrec ty1, char '~', pp TyOpPrec ty2]+ where+ ppr_infix_eq eq_op+ = sep [ parens (pp TyOpPrec ty1 <+> dcolon <+> pp TyOpPrec ki1)+ , eq_op+ , parens (pp TyOpPrec ty2 <+> dcolon <+> pp TyOpPrec ki2) ]++ print_kinds = gopt Opt_PrintExplicitKinds dflags+ print_eqs = gopt Opt_PrintEqualityRelations dflags ||+ dumpStyle style || debugStyle style+++pprIfaceCoTcApp :: TyPrec -> IfaceTyCon -> [IfaceCoercion] -> SDoc+pprIfaceCoTcApp ctxt_prec tc tys = ppr_iface_tc_app ppr_co ctxt_prec tc tys++ppr_iface_tc_app :: (TyPrec -> a -> SDoc) -> TyPrec -> IfaceTyCon -> [a] -> SDoc+ppr_iface_tc_app pp _ tc [ty]+ | tc `ifaceTyConHasKey` listTyConKey = pprPromotionQuote tc <> brackets (pp TopPrec ty)+ | tc `ifaceTyConHasKey` parrTyConKey = pprPromotionQuote tc <> paBrackets (pp TopPrec ty)++ppr_iface_tc_app pp ctxt_prec tc tys+ | tc `ifaceTyConHasKey` starKindTyConKey+ || tc `ifaceTyConHasKey` liftedTypeKindTyConKey+ || tc `ifaceTyConHasKey` unicodeStarKindTyConKey+ = kindStar -- Handle unicode; do not wrap * in parens++ | not (isSymOcc (nameOccName (ifaceTyConName tc)))+ = pprIfacePrefixApp ctxt_prec (ppr tc) (map (pp TyConPrec) tys)++ | [ty1,ty2] <- tys -- Infix, two arguments;+ -- we know nothing of precedence though+ = pprIfaceInfixApp pp ctxt_prec (ppr tc) ty1 ty2++ | otherwise+ = pprIfacePrefixApp ctxt_prec (parens (ppr tc)) (map (pp TyConPrec) tys)++pprSum :: Arity -> IsPromoted -> IfaceTcArgs -> SDoc+pprSum _arity is_promoted args+ = -- drop the RuntimeRep vars.+ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ let tys = tcArgsIfaceTypes args+ args' = drop (length tys `div` 2) tys+ in pprPromotionQuoteI is_promoted+ <> sumParens (pprWithBars (ppr_ty TopPrec) args')++pprTuple :: TupleSort -> IsPromoted -> IfaceTcArgs -> SDoc+pprTuple ConstraintTuple IsNotPromoted ITC_Nil+ = text "() :: Constraint"++-- All promoted constructors have kind arguments+pprTuple sort IsPromoted args+ = let tys = tcArgsIfaceTypes args+ args' = drop (length tys `div` 2) tys+ in pprPromotionQuoteI IsPromoted <>+ tupleParens sort (pprWithCommas pprIfaceType args')++pprTuple sort promoted args+ = -- drop the RuntimeRep vars.+ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ let tys = tcArgsIfaceTypes args+ args' = case sort of+ UnboxedTuple -> drop (length tys `div` 2) tys+ _ -> tys+ in+ pprPromotionQuoteI promoted <>+ tupleParens sort (pprWithCommas pprIfaceType args')++pprIfaceTyLit :: IfaceTyLit -> SDoc+pprIfaceTyLit (IfaceNumTyLit n) = integer n+pprIfaceTyLit (IfaceStrTyLit n) = text (show n)++pprIfaceCoercion, pprParendIfaceCoercion :: IfaceCoercion -> SDoc+pprIfaceCoercion = ppr_co TopPrec+pprParendIfaceCoercion = ppr_co TyConPrec++ppr_co :: TyPrec -> IfaceCoercion -> SDoc+ppr_co _ (IfaceReflCo r ty) = angleBrackets (ppr ty) <> ppr_role r+ppr_co ctxt_prec (IfaceFunCo r co1 co2)+ = maybeParen ctxt_prec FunPrec $+ sep (ppr_co FunPrec co1 : ppr_fun_tail co2)+ where+ ppr_fun_tail (IfaceFunCo r co1 co2)+ = (arrow <> ppr_role r <+> ppr_co FunPrec co1) : ppr_fun_tail co2+ ppr_fun_tail other_co+ = [arrow <> ppr_role r <+> pprIfaceCoercion other_co]++ppr_co _ (IfaceTyConAppCo r tc cos)+ = parens (pprIfaceCoTcApp TopPrec tc cos) <> ppr_role r+ppr_co ctxt_prec (IfaceAppCo co1 co2)+ = maybeParen ctxt_prec TyConPrec $+ ppr_co FunPrec co1 <+> pprParendIfaceCoercion co2+ppr_co ctxt_prec co@(IfaceForAllCo {})+ = maybeParen ctxt_prec FunPrec (pprIfaceForAllCoPart tvs (pprIfaceCoercion inner_co))+ where+ (tvs, inner_co) = split_co co++ split_co (IfaceForAllCo (name, _) kind_co co')+ = let (tvs, co'') = split_co co' in ((name,kind_co):tvs,co'')+ split_co co' = ([], co')++ppr_co _ (IfaceCoVarCo covar) = ppr covar++ppr_co ctxt_prec (IfaceUnivCo IfaceUnsafeCoerceProv r ty1 ty2)+ = maybeParen ctxt_prec TyConPrec $+ text "UnsafeCo" <+> ppr r <+>+ pprParendIfaceType ty1 <+> pprParendIfaceType ty2++ppr_co _ctxt_prec (IfaceUnivCo (IfaceHoleProv u) _ _ _)+ = braces $ ppr u++ppr_co _ (IfaceUnivCo _ _ ty1 ty2)+ = angleBrackets ( ppr ty1 <> comma <+> ppr ty2 )++ppr_co ctxt_prec (IfaceInstCo co ty)+ = maybeParen ctxt_prec TyConPrec $+ text "Inst" <+> pprParendIfaceCoercion co+ <+> pprParendIfaceCoercion ty++ppr_co ctxt_prec (IfaceAxiomRuleCo tc cos)+ = maybeParen ctxt_prec TyConPrec $ ppr tc <+> parens (interpp'SP cos)++ppr_co ctxt_prec (IfaceAxiomInstCo n i cos)+ = ppr_special_co ctxt_prec (ppr n <> brackets (ppr i)) cos+ppr_co ctxt_prec (IfaceSymCo co)+ = ppr_special_co ctxt_prec (text "Sym") [co]+ppr_co ctxt_prec (IfaceTransCo co1 co2)+ = ppr_special_co ctxt_prec (text "Trans") [co1,co2]+ppr_co ctxt_prec (IfaceNthCo d co)+ = ppr_special_co ctxt_prec (text "Nth:" <> int d) [co]+ppr_co ctxt_prec (IfaceLRCo lr co)+ = ppr_special_co ctxt_prec (ppr lr) [co]+ppr_co ctxt_prec (IfaceSubCo co)+ = ppr_special_co ctxt_prec (text "Sub") [co]+ppr_co ctxt_prec (IfaceCoherenceCo co1 co2)+ = ppr_special_co ctxt_prec (text "Coh") [co1,co2]+ppr_co ctxt_prec (IfaceKindCo co)+ = ppr_special_co ctxt_prec (text "Kind") [co]++ppr_special_co :: TyPrec -> SDoc -> [IfaceCoercion] -> SDoc+ppr_special_co ctxt_prec doc cos+ = maybeParen ctxt_prec TyConPrec+ (sep [doc, nest 4 (sep (map pprParendIfaceCoercion cos))])++ppr_role :: Role -> SDoc+ppr_role r = underscore <> pp_role+ where pp_role = case r of+ Nominal -> char 'N'+ Representational -> char 'R'+ Phantom -> char 'P'++-------------------+instance Outputable IfaceTyCon where+ ppr tc = pprPromotionQuote tc <> ppr (ifaceTyConName tc)++pprPromotionQuote :: IfaceTyCon -> SDoc+pprPromotionQuote tc =+ pprPromotionQuoteI $ ifaceTyConIsPromoted $ ifaceTyConInfo tc++pprPromotionQuoteI :: IsPromoted -> SDoc+pprPromotionQuoteI IsNotPromoted = empty+pprPromotionQuoteI IsPromoted = char '\''++instance Outputable IfaceCoercion where+ ppr = pprIfaceCoercion++instance Binary IfaceTyCon where+ put_ bh (IfaceTyCon n i) = put_ bh n >> put_ bh i++ get bh = do n <- get bh+ i <- get bh+ return (IfaceTyCon n i)++instance Binary IsPromoted where+ put_ bh IsNotPromoted = putByte bh 0+ put_ bh IsPromoted = putByte bh 1++ get bh = do+ n <- getByte bh+ case n of+ 0 -> return IsNotPromoted+ 1 -> return IsPromoted+ _ -> fail "Binary(IsPromoted): fail)"++instance Binary IfaceTyConSort where+ put_ bh IfaceNormalTyCon = putByte bh 0+ put_ bh (IfaceTupleTyCon arity sort) = putByte bh 1 >> put_ bh arity >> put_ bh sort+ put_ bh (IfaceSumTyCon arity) = putByte bh 2 >> put_ bh arity+ put_ bh (IfaceEqualityTyCon hom)+ | hom = putByte bh 3+ | otherwise = putByte bh 4++ get bh = do+ n <- getByte bh+ case n of+ 0 -> return IfaceNormalTyCon+ 1 -> IfaceTupleTyCon <$> get bh <*> get bh+ 2 -> IfaceSumTyCon <$> get bh+ 3 -> return $ IfaceEqualityTyCon True+ 4 -> return $ IfaceEqualityTyCon False+ _ -> fail "Binary(IfaceTyConSort): fail"++instance Binary IfaceTyConInfo where+ put_ bh (IfaceTyConInfo i s) = put_ bh i >> put_ bh s++ get bh = IfaceTyConInfo <$> get bh <*> get bh++instance Outputable IfaceTyLit where+ ppr = pprIfaceTyLit++instance Binary IfaceTyLit where+ put_ bh (IfaceNumTyLit n) = putByte bh 1 >> put_ bh n+ put_ bh (IfaceStrTyLit n) = putByte bh 2 >> put_ bh n++ get bh =+ do tag <- getByte bh+ case tag of+ 1 -> do { n <- get bh+ ; return (IfaceNumTyLit n) }+ 2 -> do { n <- get bh+ ; return (IfaceStrTyLit n) }+ _ -> panic ("get IfaceTyLit " ++ show tag)++instance Binary IfaceTcArgs where+ put_ bh tk =+ case tk of+ ITC_Vis t ts -> putByte bh 0 >> put_ bh t >> put_ bh ts+ ITC_Invis t ts -> putByte bh 1 >> put_ bh t >> put_ bh ts+ ITC_Nil -> putByte bh 2++ get bh =+ do c <- getByte bh+ case c of+ 0 -> do+ t <- get bh+ ts <- get bh+ return $! ITC_Vis t ts+ 1 -> do+ t <- get bh+ ts <- get bh+ return $! ITC_Invis t ts+ 2 -> return ITC_Nil+ _ -> panic ("get IfaceTcArgs " ++ show c)++-------------------++-- Some notes about printing contexts+--+-- In the event that we are printing a singleton context (e.g. @Eq a@) we can+-- omit parentheses. However, we must take care to set the precedence correctly+-- to TyOpPrec, since something like @a :~: b@ must be parenthesized (see+-- #9658).+--+-- When printing a larger context we use 'fsep' instead of 'sep' so that+-- the context doesn't get displayed as a giant column. Rather than,+-- instance (Eq a,+-- Eq b,+-- Eq c,+-- Eq d,+-- Eq e,+-- Eq f,+-- Eq g,+-- Eq h,+-- Eq i,+-- Eq j,+-- Eq k,+-- Eq l) =>+-- Eq (a, b, c, d, e, f, g, h, i, j, k, l)+--+-- we want+--+-- instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g, Eq h, Eq i,+-- Eq j, Eq k, Eq l) =>+-- Eq (a, b, c, d, e, f, g, h, i, j, k, l)++++-- | Prints "(C a, D b) =>", including the arrow. This is used when we want to+-- print a context in a type.+pprIfaceContextArr :: [IfacePredType] -> SDoc+pprIfaceContextArr [] = empty+pprIfaceContextArr [pred] = ppr_ty TyOpPrec pred <+> darrow+pprIfaceContextArr preds =+ parens (fsep (punctuate comma (map ppr preds))) <+> darrow++-- | Prints a context or @()@ if empty. This is used when, e.g., we want to+-- display a context in an error message.+pprIfaceContext :: [IfacePredType] -> SDoc+pprIfaceContext [] = parens empty+pprIfaceContext [pred] = ppr_ty TyOpPrec pred+pprIfaceContext preds = parens (fsep (punctuate comma (map ppr preds)))++instance Binary IfaceType where+ put_ _ (IfaceFreeTyVar tv)+ = pprPanic "Can't serialise IfaceFreeTyVar" (ppr tv)++ put_ bh (IfaceForAllTy aa ab) = do+ putByte bh 0+ put_ bh aa+ put_ bh ab+ put_ bh (IfaceTyVar ad) = do+ putByte bh 1+ put_ bh ad+ put_ bh (IfaceAppTy ae af) = do+ putByte bh 2+ put_ bh ae+ put_ bh af+ put_ bh (IfaceFunTy ag ah) = do+ putByte bh 3+ put_ bh ag+ put_ bh ah+ put_ bh (IfaceDFunTy ag ah) = do+ putByte bh 4+ put_ bh ag+ put_ bh ah+ put_ bh (IfaceTyConApp tc tys)+ = do { putByte bh 5; put_ bh tc; put_ bh tys }+ put_ bh (IfaceCastTy a b)+ = do { putByte bh 6; put_ bh a; put_ bh b }+ put_ bh (IfaceCoercionTy a)+ = do { putByte bh 7; put_ bh a }+ put_ bh (IfaceTupleTy s i tys)+ = do { putByte bh 8; put_ bh s; put_ bh i; put_ bh tys }+ put_ bh (IfaceLitTy n)+ = do { putByte bh 9; put_ bh n }++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do aa <- get bh+ ab <- get bh+ return (IfaceForAllTy aa ab)+ 1 -> do ad <- get bh+ return (IfaceTyVar ad)+ 2 -> do ae <- get bh+ af <- get bh+ return (IfaceAppTy ae af)+ 3 -> do ag <- get bh+ ah <- get bh+ return (IfaceFunTy ag ah)+ 4 -> do ag <- get bh+ ah <- get bh+ return (IfaceDFunTy ag ah)+ 5 -> do { tc <- get bh; tys <- get bh+ ; return (IfaceTyConApp tc tys) }+ 6 -> do { a <- get bh; b <- get bh+ ; return (IfaceCastTy a b) }+ 7 -> do { a <- get bh+ ; return (IfaceCoercionTy a) }++ 8 -> do { s <- get bh; i <- get bh; tys <- get bh+ ; return (IfaceTupleTy s i tys) }+ _ -> do n <- get bh+ return (IfaceLitTy n)++instance Binary IfaceCoercion where+ put_ bh (IfaceReflCo a b) = do+ putByte bh 1+ put_ bh a+ put_ bh b+ put_ bh (IfaceFunCo a b c) = do+ putByte bh 2+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh (IfaceTyConAppCo a b c) = do+ putByte bh 3+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh (IfaceAppCo a b) = do+ putByte bh 4+ put_ bh a+ put_ bh b+ put_ bh (IfaceForAllCo a b c) = do+ putByte bh 5+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh (IfaceCoVarCo a) = do+ putByte bh 6+ put_ bh a+ put_ bh (IfaceAxiomInstCo a b c) = do+ putByte bh 7+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh (IfaceUnivCo a b c d) = do+ putByte bh 8+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh d+ put_ bh (IfaceSymCo a) = do+ putByte bh 9+ put_ bh a+ put_ bh (IfaceTransCo a b) = do+ putByte bh 10+ put_ bh a+ put_ bh b+ put_ bh (IfaceNthCo a b) = do+ putByte bh 11+ put_ bh a+ put_ bh b+ put_ bh (IfaceLRCo a b) = do+ putByte bh 12+ put_ bh a+ put_ bh b+ put_ bh (IfaceInstCo a b) = do+ putByte bh 13+ put_ bh a+ put_ bh b+ put_ bh (IfaceCoherenceCo a b) = do+ putByte bh 14+ put_ bh a+ put_ bh b+ put_ bh (IfaceKindCo a) = do+ putByte bh 15+ put_ bh a+ put_ bh (IfaceSubCo a) = do+ putByte bh 16+ put_ bh a+ put_ bh (IfaceAxiomRuleCo a b) = do+ putByte bh 17+ put_ bh a+ put_ bh b++ get bh = do+ tag <- getByte bh+ case tag of+ 1 -> do a <- get bh+ b <- get bh+ return $ IfaceReflCo a b+ 2 -> do a <- get bh+ b <- get bh+ c <- get bh+ return $ IfaceFunCo a b c+ 3 -> do a <- get bh+ b <- get bh+ c <- get bh+ return $ IfaceTyConAppCo a b c+ 4 -> do a <- get bh+ b <- get bh+ return $ IfaceAppCo a b+ 5 -> do a <- get bh+ b <- get bh+ c <- get bh+ return $ IfaceForAllCo a b c+ 6 -> do a <- get bh+ return $ IfaceCoVarCo a+ 7 -> do a <- get bh+ b <- get bh+ c <- get bh+ return $ IfaceAxiomInstCo a b c+ 8 -> do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ return $ IfaceUnivCo a b c d+ 9 -> do a <- get bh+ return $ IfaceSymCo a+ 10-> do a <- get bh+ b <- get bh+ return $ IfaceTransCo a b+ 11-> do a <- get bh+ b <- get bh+ return $ IfaceNthCo a b+ 12-> do a <- get bh+ b <- get bh+ return $ IfaceLRCo a b+ 13-> do a <- get bh+ b <- get bh+ return $ IfaceInstCo a b+ 14-> do a <- get bh+ b <- get bh+ return $ IfaceCoherenceCo a b+ 15-> do a <- get bh+ return $ IfaceKindCo a+ 16-> do a <- get bh+ return $ IfaceSubCo a+ 17-> do a <- get bh+ b <- get bh+ return $ IfaceAxiomRuleCo a b+ _ -> panic ("get IfaceCoercion " ++ show tag)++instance Binary IfaceUnivCoProv where+ put_ bh IfaceUnsafeCoerceProv = putByte bh 1+ put_ bh (IfacePhantomProv a) = do+ putByte bh 2+ put_ bh a+ put_ bh (IfaceProofIrrelProv a) = do+ putByte bh 3+ put_ bh a+ put_ bh (IfacePluginProv a) = do+ putByte bh 4+ put_ bh a+ put_ _ (IfaceHoleProv _) =+ pprPanic "Binary(IfaceUnivCoProv) hit a hole" empty+ -- See Note [Holes in IfaceUnivCoProv]++ get bh = do+ tag <- getByte bh+ case tag of+ 1 -> return $ IfaceUnsafeCoerceProv+ 2 -> do a <- get bh+ return $ IfacePhantomProv a+ 3 -> do a <- get bh+ return $ IfaceProofIrrelProv a+ 4 -> do a <- get bh+ return $ IfacePluginProv a+ _ -> panic ("get IfaceUnivCoProv " ++ show tag)+++instance Binary (DefMethSpec IfaceType) where+ put_ bh VanillaDM = putByte bh 0+ put_ bh (GenericDM t) = putByte bh 1 >> put_ bh t+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return VanillaDM+ _ -> do { t <- get bh; return (GenericDM t) }
+ iface/IfaceType.hs-boot view
@@ -0,0 +1,37 @@+-- Exists to allow TyCoRep to import pretty-printers+module IfaceType where++import Var (TyVarBndr, ArgFlag)+import TyCon (TyConBndrVis)+import BasicTypes (TyPrec)+import Outputable (Outputable, SDoc)+import FastString (FastString)++type IfLclName = FastString+type IfaceKind = IfaceType+type IfacePredType = IfaceType++data ShowForAllFlag+data IfaceType+data IfaceTyCon+data IfaceTyLit+data IfaceCoercion+data IfaceTcArgs+type IfaceTvBndr = (IfLclName, IfaceKind)+type IfaceTyConBinder = TyVarBndr IfaceTvBndr TyConBndrVis+type IfaceForAllBndr = TyVarBndr IfaceTvBndr ArgFlag++instance Outputable IfaceType++pprIfaceType, pprParendIfaceType :: IfaceType -> SDoc+pprIfaceSigmaType :: ShowForAllFlag -> IfaceType -> SDoc+pprIfaceTyLit :: IfaceTyLit -> SDoc+pprIfaceForAll :: [IfaceForAllBndr] -> SDoc+pprIfaceTvBndr :: Bool -> IfaceTvBndr -> SDoc+pprUserIfaceForAll :: [IfaceForAllBndr] -> SDoc+pprIfaceContext :: [IfacePredType] -> SDoc+pprIfaceContextArr :: [IfacePredType] -> SDoc+pprIfaceTypeApp :: TyPrec -> IfaceTyCon -> IfaceTcArgs -> SDoc+pprIfaceCoTcApp :: TyPrec -> IfaceTyCon -> [IfaceCoercion] -> SDoc+pprTyTcApp :: TyPrec -> IfaceTyCon -> IfaceTcArgs -> SDoc+pprIfacePrefixApp :: TyPrec -> SDoc -> [SDoc] -> SDoc
+ iface/LoadIface.hs view
@@ -0,0 +1,1184 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Loading interface files+-}++{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module LoadIface (+ -- Importing one thing+ tcLookupImported_maybe, importDecl,+ checkWiredInTyCon, ifCheckWiredInThing,++ -- RnM/TcM functions+ loadModuleInterface, loadModuleInterfaces,+ loadSrcInterface, loadSrcInterface_maybe,+ loadInterfaceForName, loadInterfaceForModule,++ -- IfM functions+ loadInterface,+ loadSysInterface, loadUserInterface, loadPluginInterface,+ findAndReadIface, readIface, -- Used when reading the module's old interface+ loadDecls, -- Should move to TcIface and be renamed+ initExternalPackageState,+ moduleFreeHolesPrecise,++ pprModIfaceSimple,+ ifaceStats, pprModIface, showIface+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} TcIface( tcIfaceDecl, tcIfaceRules, tcIfaceInst,+ tcIfaceFamInst, tcIfaceVectInfo,+ tcIfaceAnnotations, tcIfaceCompleteSigs )++import DynFlags+import IfaceSyn+import IfaceEnv+import HscTypes++import BasicTypes hiding (SuccessFlag(..))+import TcRnMonad++import Constants+import PrelNames+import PrelInfo+import PrimOp ( allThePrimOps, primOpFixity, primOpOcc )+import MkId ( seqId )+import TysPrim ( funTyConName )+import Rules+import TyCon+import Annotations+import InstEnv+import FamInstEnv+import Name+import NameEnv+import Avail+import Module+import Maybes+import ErrUtils+import Finder+import UniqFM+import SrcLoc+import Outputable+import BinIface+import Panic+import Util+import FastString+import Fingerprint+import Hooks+import FieldLabel+import RnModIface+import UniqDSet++import Control.Monad+import Control.Exception+import Data.IORef+import System.FilePath++{-+************************************************************************+* *+* tcImportDecl is the key function for "faulting in" *+* imported things+* *+************************************************************************++The main idea is this. We are chugging along type-checking source code, and+find a reference to GHC.Base.map. We call tcLookupGlobal, which doesn't find+it in the EPS type envt. So it+ 1 loads GHC.Base.hi+ 2 gets the decl for GHC.Base.map+ 3 typechecks it via tcIfaceDecl+ 4 and adds it to the type env in the EPS++Note that DURING STEP 4, we may find that map's type mentions a type+constructor that also++Notice that for imported things we read the current version from the EPS+mutable variable. This is important in situations like+ ...$(e1)...$(e2)...+where the code that e1 expands to might import some defns that+also turn out to be needed by the code that e2 expands to.+-}++tcLookupImported_maybe :: Name -> TcM (MaybeErr MsgDoc TyThing)+-- Returns (Failed err) if we can't find the interface file for the thing+tcLookupImported_maybe name+ = do { hsc_env <- getTopEnv+ ; mb_thing <- liftIO (lookupTypeHscEnv hsc_env name)+ ; case mb_thing of+ Just thing -> return (Succeeded thing)+ Nothing -> tcImportDecl_maybe name }++tcImportDecl_maybe :: Name -> TcM (MaybeErr MsgDoc TyThing)+-- Entry point for *source-code* uses of importDecl+tcImportDecl_maybe name+ | Just thing <- wiredInNameTyThing_maybe name+ = do { when (needWiredInHomeIface thing)+ (initIfaceTcRn (loadWiredInHomeIface name))+ -- See Note [Loading instances for wired-in things]+ ; return (Succeeded thing) }+ | otherwise+ = initIfaceTcRn (importDecl name)++importDecl :: Name -> IfM lcl (MaybeErr MsgDoc TyThing)+-- Get the TyThing for this Name from an interface file+-- It's not a wired-in thing -- the caller caught that+importDecl name+ = ASSERT( not (isWiredInName name) )+ do { traceIf nd_doc++ -- Load the interface, which should populate the PTE+ ; mb_iface <- ASSERT2( isExternalName name, ppr name )+ loadInterface nd_doc (nameModule name) ImportBySystem+ ; case mb_iface of {+ Failed err_msg -> return (Failed err_msg) ;+ Succeeded _ -> do++ -- Now look it up again; this time we should find it+ { eps <- getEps+ ; case lookupTypeEnv (eps_PTE eps) name of+ Just thing -> return $ Succeeded thing+ Nothing -> let doc = ifPprDebug (found_things_msg eps $$ empty)+ $$ not_found_msg+ in return $ Failed doc+ }}}+ where+ nd_doc = text "Need decl for" <+> ppr name+ not_found_msg = hang (text "Can't find interface-file declaration for" <+>+ pprNameSpace (occNameSpace (nameOccName name)) <+> ppr name)+ 2 (vcat [text "Probable cause: bug in .hi-boot file, or inconsistent .hi file",+ text "Use -ddump-if-trace to get an idea of which file caused the error"])+ found_things_msg eps =+ hang (text "Found the following declarations in" <+> ppr (nameModule name) <> colon)+ 2 (vcat (map ppr $ filter is_interesting $ nameEnvElts $ eps_PTE eps))+ where+ is_interesting thing = nameModule name == nameModule (getName thing)+++{-+************************************************************************+* *+ Checks for wired-in things+* *+************************************************************************++Note [Loading instances for wired-in things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to make sure that we have at least *read* the interface files+for any module with an instance decl or RULE that we might want.++* If the instance decl is an orphan, we have a whole separate mechanism+ (loadOrphanModules)++* If the instance decl is not an orphan, then the act of looking at the+ TyCon or Class will force in the defining module for the+ TyCon/Class, and hence the instance decl++* BUT, if the TyCon is a wired-in TyCon, we don't really need its interface;+ but we must make sure we read its interface in case it has instances or+ rules. That is what LoadIface.loadWiredInHomeIface does. It's called+ from TcIface.{tcImportDecl, checkWiredInTyCon, ifCheckWiredInThing}++* HOWEVER, only do this for TyCons. There are no wired-in Classes. There+ are some wired-in Ids, but we don't want to load their interfaces. For+ example, Control.Exception.Base.recSelError is wired in, but that module+ is compiled late in the base library, and we don't want to force it to+ load before it's been compiled!++All of this is done by the type checker. The renamer plays no role.+(It used to, but no longer.)+-}++checkWiredInTyCon :: TyCon -> TcM ()+-- Ensure that the home module of the TyCon (and hence its instances)+-- are loaded. See Note [Loading instances for wired-in things]+-- It might not be a wired-in tycon (see the calls in TcUnify),+-- in which case this is a no-op.+checkWiredInTyCon tc+ | not (isWiredInName tc_name)+ = return ()+ | otherwise+ = do { mod <- getModule+ ; traceIf (text "checkWiredInTyCon" <+> ppr tc_name $$ ppr mod)+ ; ASSERT( isExternalName tc_name )+ when (mod /= nameModule tc_name)+ (initIfaceTcRn (loadWiredInHomeIface tc_name))+ -- Don't look for (non-existent) Float.hi when+ -- compiling Float.hs, which mentions Float of course+ -- A bit yukky to call initIfaceTcRn here+ }+ where+ tc_name = tyConName tc++ifCheckWiredInThing :: TyThing -> IfL ()+-- Even though we are in an interface file, we want to make+-- sure the instances of a wired-in thing are loaded (imagine f :: Double -> Double)+-- Ditto want to ensure that RULES are loaded too+-- See Note [Loading instances for wired-in things]+ifCheckWiredInThing thing+ = do { mod <- getIfModule+ -- Check whether we are typechecking the interface for this+ -- very module. E.g when compiling the base library in --make mode+ -- we may typecheck GHC.Base.hi. At that point, GHC.Base is not in+ -- the HPT, so without the test we'll demand-load it into the PIT!+ -- C.f. the same test in checkWiredInTyCon above+ ; let name = getName thing+ ; ASSERT2( isExternalName name, ppr name )+ when (needWiredInHomeIface thing && mod /= nameModule name)+ (loadWiredInHomeIface name) }++needWiredInHomeIface :: TyThing -> Bool+-- Only for TyCons; see Note [Loading instances for wired-in things]+needWiredInHomeIface (ATyCon {}) = True+needWiredInHomeIface _ = False+++{-+************************************************************************+* *+ loadSrcInterface, loadOrphanModules, loadInterfaceForName++ These three are called from TcM-land+* *+************************************************************************+-}++-- | Load the interface corresponding to an @import@ directive in+-- source code. On a failure, fail in the monad with an error message.+loadSrcInterface :: SDoc+ -> ModuleName+ -> IsBootInterface -- {-# SOURCE #-} ?+ -> Maybe FastString -- "package", if any+ -> RnM ModIface++loadSrcInterface doc mod want_boot maybe_pkg+ = do { res <- loadSrcInterface_maybe doc mod want_boot maybe_pkg+ ; case res of+ Failed err -> failWithTc err+ Succeeded iface -> return iface }++-- | Like 'loadSrcInterface', but returns a 'MaybeErr'.+loadSrcInterface_maybe :: SDoc+ -> ModuleName+ -> IsBootInterface -- {-# SOURCE #-} ?+ -> Maybe FastString -- "package", if any+ -> RnM (MaybeErr MsgDoc ModIface)++loadSrcInterface_maybe doc mod want_boot maybe_pkg+ -- We must first find which Module this import refers to. This involves+ -- calling the Finder, which as a side effect will search the filesystem+ -- and create a ModLocation. If successful, loadIface will read the+ -- interface; it will call the Finder again, but the ModLocation will be+ -- cached from the first search.+ = do { hsc_env <- getTopEnv+ ; res <- liftIO $ findImportedModule hsc_env mod maybe_pkg+ ; case res of+ Found _ mod -> initIfaceTcRn $ loadInterface doc mod (ImportByUser want_boot)+ -- TODO: Make sure this error message is good+ err -> return (Failed (cannotFindModule (hsc_dflags hsc_env) mod err)) }++-- | Load interface directly for a fully qualified 'Module'. (This is a fairly+-- rare operation, but in particular it is used to load orphan modules+-- in order to pull their instances into the global package table and to+-- handle some operations in GHCi).+loadModuleInterface :: SDoc -> Module -> TcM ModIface+loadModuleInterface doc mod = initIfaceTcRn (loadSysInterface doc mod)++-- | Load interfaces for a collection of modules.+loadModuleInterfaces :: SDoc -> [Module] -> TcM ()+loadModuleInterfaces doc mods+ | null mods = return ()+ | otherwise = initIfaceTcRn (mapM_ load mods)+ where+ load mod = loadSysInterface (doc <+> parens (ppr mod)) mod++-- | Loads the interface for a given Name.+-- Should only be called for an imported name;+-- otherwise loadSysInterface may not find the interface+loadInterfaceForName :: SDoc -> Name -> TcRn ModIface+loadInterfaceForName doc name+ = do { when debugIsOn $ -- Check pre-condition+ do { this_mod <- getModule+ ; MASSERT2( not (nameIsLocalOrFrom this_mod name), ppr name <+> parens doc ) }+ ; ASSERT2( isExternalName name, ppr name )+ initIfaceTcRn $ loadSysInterface doc (nameModule name) }++-- | Loads the interface for a given Module.+loadInterfaceForModule :: SDoc -> Module -> TcRn ModIface+loadInterfaceForModule doc m+ = do+ -- Should not be called with this module+ when debugIsOn $ do+ this_mod <- getModule+ MASSERT2( this_mod /= m, ppr m <+> parens doc )+ initIfaceTcRn $ loadSysInterface doc m++{-+*********************************************************+* *+ loadInterface++ The main function to load an interface+ for an imported module, and put it in+ the External Package State+* *+*********************************************************+-}++-- | An 'IfM' function to load the home interface for a wired-in thing,+-- so that we're sure that we see its instance declarations and rules+-- See Note [Loading instances for wired-in things]+loadWiredInHomeIface :: Name -> IfM lcl ()+loadWiredInHomeIface name+ = ASSERT( isWiredInName name )+ do _ <- loadSysInterface doc (nameModule name); return ()+ where+ doc = text "Need home interface for wired-in thing" <+> ppr name++------------------+-- | Loads a system interface and throws an exception if it fails+loadSysInterface :: SDoc -> Module -> IfM lcl ModIface+loadSysInterface doc mod_name = loadInterfaceWithException doc mod_name ImportBySystem++------------------+-- | Loads a user interface and throws an exception if it fails. The first parameter indicates+-- whether we should import the boot variant of the module+loadUserInterface :: Bool -> SDoc -> Module -> IfM lcl ModIface+loadUserInterface is_boot doc mod_name+ = loadInterfaceWithException doc mod_name (ImportByUser is_boot)++loadPluginInterface :: SDoc -> Module -> IfM lcl ModIface+loadPluginInterface doc mod_name+ = loadInterfaceWithException doc mod_name ImportByPlugin++------------------+-- | A wrapper for 'loadInterface' that throws an exception if it fails+loadInterfaceWithException :: SDoc -> Module -> WhereFrom -> IfM lcl ModIface+loadInterfaceWithException doc mod_name where_from+ = withException (loadInterface doc mod_name where_from)++------------------+loadInterface :: SDoc -> Module -> WhereFrom+ -> IfM lcl (MaybeErr MsgDoc ModIface)++-- loadInterface looks in both the HPT and PIT for the required interface+-- If not found, it loads it, and puts it in the PIT (always).++-- If it can't find a suitable interface file, we+-- a) modify the PackageIfaceTable to have an empty entry+-- (to avoid repeated complaints)+-- b) return (Left message)+--+-- It's not necessarily an error for there not to be an interface+-- file -- perhaps the module has changed, and that interface+-- is no longer used++loadInterface doc_str mod from+ | isHoleModule mod+ -- Hole modules get special treatment+ = do dflags <- getDynFlags+ -- Redo search for our local hole module+ loadInterface doc_str (mkModule (thisPackage dflags) (moduleName mod)) from+ | otherwise+ = do { -- Read the state+ (eps,hpt) <- getEpsAndHpt+ ; gbl_env <- getGblEnv++ ; traceIf (text "Considering whether to load" <+> ppr mod <+> ppr from)++ -- Check whether we have the interface already+ ; dflags <- getDynFlags+ ; case lookupIfaceByModule dflags hpt (eps_PIT eps) mod of {+ Just iface+ -> return (Succeeded iface) ; -- Already loaded+ -- The (src_imp == mi_boot iface) test checks that the already-loaded+ -- interface isn't a boot iface. This can conceivably happen,+ -- if an earlier import had a before we got to real imports. I think.+ _ -> do {++ -- READ THE MODULE IN+ ; read_result <- case (wantHiBootFile dflags eps mod from) of+ Failed err -> return (Failed err)+ Succeeded hi_boot_file ->+ -- Stoutly warn against an EPS-updating import+ -- of one's own boot file! (one-shot only)+ --See Note [Do not update EPS with your own hi-boot]+ -- in MkIface.+ WARN( hi_boot_file &&+ fmap fst (if_rec_types gbl_env) == Just mod,+ ppr mod )+ computeInterface doc_str hi_boot_file mod+ ; case read_result of {+ Failed err -> do+ { let fake_iface = emptyModIface mod++ ; updateEps_ $ \eps ->+ eps { eps_PIT = extendModuleEnv (eps_PIT eps) (mi_module fake_iface) fake_iface }+ -- Not found, so add an empty iface to+ -- the EPS map so that we don't look again++ ; return (Failed err) } ;++ -- Found and parsed!+ -- We used to have a sanity check here that looked for:+ -- * System importing ..+ -- * a home package module ..+ -- * that we know nothing about (mb_dep == Nothing)!+ --+ -- But this is no longer valid because thNameToGhcName allows users to+ -- cause the system to load arbitrary interfaces (by supplying an appropriate+ -- Template Haskell original-name).+ Succeeded (iface, loc) ->+ let+ loc_doc = text loc+ in+ initIfaceLcl (mi_semantic_module iface) loc_doc (mi_boot iface) $ do++ -- Load the new ModIface into the External Package State+ -- Even home-package interfaces loaded by loadInterface+ -- (which only happens in OneShot mode; in Batch/Interactive+ -- mode, home-package modules are loaded one by one into the HPT)+ -- are put in the EPS.+ --+ -- The main thing is to add the ModIface to the PIT, but+ -- we also take the+ -- IfaceDecls, IfaceClsInst, IfaceFamInst, IfaceRules, IfaceVectInfo+ -- out of the ModIface and put them into the big EPS pools++ -- NB: *first* we do loadDecl, so that the provenance of all the locally-defined+ --- names is done correctly (notably, whether this is an .hi file or .hi-boot file).+ -- If we do loadExport first the wrong info gets into the cache (unless we+ -- explicitly tag each export which seems a bit of a bore)++ ; ignore_prags <- goptM Opt_IgnoreInterfacePragmas+ ; new_eps_decls <- loadDecls ignore_prags (mi_decls iface)+ ; new_eps_insts <- mapM tcIfaceInst (mi_insts iface)+ ; new_eps_fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface)+ ; new_eps_rules <- tcIfaceRules ignore_prags (mi_rules iface)+ ; new_eps_anns <- tcIfaceAnnotations (mi_anns iface)+ ; new_eps_vect_info <- tcIfaceVectInfo mod (mkNameEnv new_eps_decls) (mi_vect_info iface)+ ; new_eps_complete_sigs <- tcIfaceCompleteSigs (mi_complete_sigs iface)++ ; let { final_iface = iface {+ mi_decls = panic "No mi_decls in PIT",+ mi_insts = panic "No mi_insts in PIT",+ mi_fam_insts = panic "No mi_fam_insts in PIT",+ mi_rules = panic "No mi_rules in PIT",+ mi_anns = panic "No mi_anns in PIT"+ }+ }++ ; updateEps_ $ \ eps ->+ if elemModuleEnv mod (eps_PIT eps) || is_external_sig dflags iface+ then eps else+ eps {+ eps_PIT = extendModuleEnv (eps_PIT eps) mod final_iface,+ eps_PTE = addDeclsToPTE (eps_PTE eps) new_eps_decls,+ eps_rule_base = extendRuleBaseList (eps_rule_base eps)+ new_eps_rules,+ eps_complete_matches+ = extendCompleteMatchMap+ (eps_complete_matches eps)+ new_eps_complete_sigs,+ eps_inst_env = extendInstEnvList (eps_inst_env eps)+ new_eps_insts,+ eps_fam_inst_env = extendFamInstEnvList (eps_fam_inst_env eps)+ new_eps_fam_insts,+ eps_vect_info = plusVectInfo (eps_vect_info eps)+ new_eps_vect_info,+ eps_ann_env = extendAnnEnvList (eps_ann_env eps)+ new_eps_anns,+ eps_mod_fam_inst_env+ = let+ fam_inst_env =+ extendFamInstEnvList emptyFamInstEnv+ new_eps_fam_insts+ in+ extendModuleEnv (eps_mod_fam_inst_env eps)+ mod+ fam_inst_env,+ eps_stats = addEpsInStats (eps_stats eps)+ (length new_eps_decls)+ (length new_eps_insts)+ (length new_eps_rules) }++ ; return (Succeeded final_iface)+ }}}}++-- | Returns @True@ if a 'ModIface' comes from an external package.+-- In this case, we should NOT load it into the EPS; the entities+-- should instead come from the local merged signature interface.+is_external_sig :: DynFlags -> ModIface -> Bool+is_external_sig dflags iface =+ -- It's a signature iface...+ mi_semantic_module iface /= mi_module iface &&+ -- and it's not from the local package+ moduleUnitId (mi_module iface) /= thisPackage dflags++-- | This is an improved version of 'findAndReadIface' which can also+-- handle the case when a user requests @p[A=<B>]:M@ but we only+-- have an interface for @p[A=<A>]:M@ (the indefinite interface.+-- If we are not trying to build code, we load the interface we have,+-- *instantiating it* according to how the holes are specified.+-- (Of course, if we're actually building code, this is a hard error.)+--+-- In the presence of holes, 'computeInterface' has an important invariant:+-- to load module M, its set of transitively reachable requirements must+-- have an up-to-date local hi file for that requirement. Note that if+-- we are loading the interface of a requirement, this does not+-- apply to the requirement itself; e.g., @p[A=<A>]:A@ does not require+-- A.hi to be up-to-date (and indeed, we MUST NOT attempt to read A.hi, unless+-- we are actually typechecking p.)+computeInterface ::+ SDoc -> IsBootInterface -> Module+ -> TcRnIf gbl lcl (MaybeErr MsgDoc (ModIface, FilePath))+computeInterface doc_str hi_boot_file mod0 = do+ MASSERT( not (isHoleModule mod0) )+ dflags <- getDynFlags+ case splitModuleInsts mod0 of+ (imod, Just indef) | not (unitIdIsDefinite (thisPackage dflags)) -> do+ r <- findAndReadIface doc_str imod mod0 hi_boot_file+ case r of+ Succeeded (iface0, path) -> do+ hsc_env <- getTopEnv+ r <- liftIO $+ rnModIface hsc_env (indefUnitIdInsts (indefModuleUnitId indef))+ Nothing iface0+ case r of+ Right x -> return (Succeeded (x, path))+ Left errs -> liftIO . throwIO . mkSrcErr $ errs+ Failed err -> return (Failed err)+ (mod, _) ->+ findAndReadIface doc_str mod mod0 hi_boot_file++-- | Compute the signatures which must be compiled in order to+-- load the interface for a 'Module'. The output of this function+-- is always a subset of 'moduleFreeHoles'; it is more precise+-- because in signature @p[A=<A>,B=<B>]:B@, although the free holes+-- are A and B, B might not depend on A at all!+--+-- If this is invoked on a signature, this does NOT include the+-- signature itself; e.g. precise free module holes of+-- @p[A=<A>,B=<B>]:B@ never includes B.+moduleFreeHolesPrecise+ :: SDoc -> Module+ -> TcRnIf gbl lcl (MaybeErr MsgDoc (UniqDSet ModuleName))+moduleFreeHolesPrecise doc_str mod+ | moduleIsDefinite mod = return (Succeeded emptyUniqDSet)+ | otherwise =+ case splitModuleInsts mod of+ (imod, Just indef) -> do+ let insts = indefUnitIdInsts (indefModuleUnitId indef)+ traceIf (text "Considering whether to load" <+> ppr mod <+>+ text "to compute precise free module holes")+ (eps, hpt) <- getEpsAndHpt+ dflags <- getDynFlags+ case tryEpsAndHpt dflags eps hpt `firstJust` tryDepsCache eps imod insts of+ Just r -> return (Succeeded r)+ Nothing -> readAndCache imod insts+ (_, Nothing) -> return (Succeeded emptyUniqDSet)+ where+ tryEpsAndHpt dflags eps hpt =+ fmap mi_free_holes (lookupIfaceByModule dflags hpt (eps_PIT eps) mod)+ tryDepsCache eps imod insts =+ case lookupInstalledModuleEnv (eps_free_holes eps) imod of+ Just ifhs -> Just (renameFreeHoles ifhs insts)+ _otherwise -> Nothing+ readAndCache imod insts = do+ mb_iface <- findAndReadIface (text "moduleFreeHolesPrecise" <+> doc_str) imod mod False+ case mb_iface of+ Succeeded (iface, _) -> do+ let ifhs = mi_free_holes iface+ -- Cache it+ updateEps_ (\eps ->+ eps { eps_free_holes = extendInstalledModuleEnv (eps_free_holes eps) imod ifhs })+ return (Succeeded (renameFreeHoles ifhs insts))+ Failed err -> return (Failed err)++wantHiBootFile :: DynFlags -> ExternalPackageState -> Module -> WhereFrom+ -> MaybeErr MsgDoc IsBootInterface+-- Figure out whether we want Foo.hi or Foo.hi-boot+wantHiBootFile dflags eps mod from+ = case from of+ ImportByUser usr_boot+ | usr_boot && not this_package+ -> Failed (badSourceImport mod)+ | otherwise -> Succeeded usr_boot++ ImportByPlugin+ -> Succeeded False++ ImportBySystem+ | not this_package -- If the module to be imported is not from this package+ -> Succeeded False -- don't look it up in eps_is_boot, because that is keyed+ -- on the ModuleName of *home-package* modules only.+ -- We never import boot modules from other packages!++ | otherwise+ -> case lookupUFM (eps_is_boot eps) (moduleName mod) of+ Just (_, is_boot) -> Succeeded is_boot+ Nothing -> Succeeded False+ -- The boot-ness of the requested interface,+ -- based on the dependencies in directly-imported modules+ where+ this_package = thisPackage dflags == moduleUnitId mod++badSourceImport :: Module -> SDoc+badSourceImport mod+ = hang (text "You cannot {-# SOURCE #-} import a module from another package")+ 2 (text "but" <+> quotes (ppr mod) <+> ptext (sLit "is from package")+ <+> quotes (ppr (moduleUnitId mod)))++-----------------------------------------------------+-- Loading type/class/value decls+-- We pass the full Module name here, replete with+-- its package info, so that we can build a Name for+-- each binder with the right package info in it+-- All subsequent lookups, including crucially lookups during typechecking+-- the declaration itself, will find the fully-glorious Name+--+-- We handle ATs specially. They are not main declarations, but also not+-- implicit things (in particular, adding them to `implicitTyThings' would mess+-- things up in the renaming/type checking of source programs).+-----------------------------------------------------++addDeclsToPTE :: PackageTypeEnv -> [(Name,TyThing)] -> PackageTypeEnv+addDeclsToPTE pte things = extendNameEnvList pte things++loadDecls :: Bool+ -> [(Fingerprint, IfaceDecl)]+ -> IfL [(Name,TyThing)]+loadDecls ignore_prags ver_decls+ = do { thingss <- mapM (loadDecl ignore_prags) ver_decls+ ; return (concat thingss)+ }++loadDecl :: Bool -- Don't load pragmas into the decl pool+ -> (Fingerprint, IfaceDecl)+ -> IfL [(Name,TyThing)] -- The list can be poked eagerly, but the+ -- TyThings are forkM'd thunks+loadDecl ignore_prags (_version, decl)+ = do { -- Populate the name cache with final versions of all+ -- the names associated with the decl+ let main_name = ifName decl++ -- Typecheck the thing, lazily+ -- NB. Firstly, the laziness is there in case we never need the+ -- declaration (in one-shot mode), and secondly it is there so that+ -- we don't look up the occurrence of a name before calling mk_new_bndr+ -- on the binder. This is important because we must get the right name+ -- which includes its nameParent.++ ; thing <- forkM doc $ do { bumpDeclStats main_name+ ; tcIfaceDecl ignore_prags decl }++ -- Populate the type environment with the implicitTyThings too.+ --+ -- Note [Tricky iface loop]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~+ -- Summary: The delicate point here is that 'mini-env' must be+ -- buildable from 'thing' without demanding any of the things+ -- 'forkM'd by tcIfaceDecl.+ --+ -- In more detail: Consider the example+ -- data T a = MkT { x :: T a }+ -- The implicitTyThings of T are: [ <datacon MkT>, <selector x>]+ -- (plus their workers, wrappers, coercions etc etc)+ --+ -- We want to return an environment+ -- [ "MkT" -> <datacon MkT>, "x" -> <selector x>, ... ]+ -- (where the "MkT" is the *Name* associated with MkT, etc.)+ --+ -- We do this by mapping the implicit_names to the associated+ -- TyThings. By the invariant on ifaceDeclImplicitBndrs and+ -- implicitTyThings, we can use getOccName on the implicit+ -- TyThings to make this association: each Name's OccName should+ -- be the OccName of exactly one implicitTyThing. So the key is+ -- to define a "mini-env"+ --+ -- [ 'MkT' -> <datacon MkT>, 'x' -> <selector x>, ... ]+ -- where the 'MkT' here is the *OccName* associated with MkT.+ --+ -- However, there is a subtlety: due to how type checking needs+ -- to be staged, we can't poke on the forkM'd thunks inside the+ -- implicitTyThings while building this mini-env.+ -- If we poke these thunks too early, two problems could happen:+ -- (1) When processing mutually recursive modules across+ -- hs-boot boundaries, poking too early will do the+ -- type-checking before the recursive knot has been tied,+ -- so things will be type-checked in the wrong+ -- environment, and necessary variables won't be in+ -- scope.+ --+ -- (2) Looking up one OccName in the mini_env will cause+ -- others to be looked up, which might cause that+ -- original one to be looked up again, and hence loop.+ --+ -- The code below works because of the following invariant:+ -- getOccName on a TyThing does not force the suspended type+ -- checks in order to extract the name. For example, we don't+ -- poke on the "T a" type of <selector x> on the way to+ -- extracting <selector x>'s OccName. Of course, there is no+ -- reason in principle why getting the OccName should force the+ -- thunks, but this means we need to be careful in+ -- implicitTyThings and its helper functions.+ --+ -- All a bit too finely-balanced for my liking.++ -- This mini-env and lookup function mediates between the+ --'Name's n and the map from 'OccName's to the implicit TyThings+ ; let mini_env = mkOccEnv [(getOccName t, t) | t <- implicitTyThings thing]+ lookup n = case lookupOccEnv mini_env (getOccName n) of+ Just thing -> thing+ Nothing ->+ pprPanic "loadDecl" (ppr main_name <+> ppr n $$ ppr (decl))++ ; implicit_names <- mapM lookupIfaceTop (ifaceDeclImplicitBndrs decl)++-- ; traceIf (text "Loading decl for " <> ppr main_name $$ ppr implicit_names)+ ; return $ (main_name, thing) :+ -- uses the invariant that implicit_names and+ -- implicitTyThings are bijective+ [(n, lookup n) | n <- implicit_names]+ }+ where+ doc = text "Declaration for" <+> ppr (ifName decl)++bumpDeclStats :: Name -> IfL () -- Record that one more declaration has actually been used+bumpDeclStats name+ = do { traceIf (text "Loading decl for" <+> ppr name)+ ; updateEps_ (\eps -> let stats = eps_stats eps+ in eps { eps_stats = stats { n_decls_out = n_decls_out stats + 1 } })+ }++{-+*********************************************************+* *+\subsection{Reading an interface file}+* *+*********************************************************++Note [Home module load error]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the sought-for interface is in the current package (as determined+by -package-name flag) then it jolly well should already be in the HPT+because we process home-package modules in dependency order. (Except+in one-shot mode; see notes with hsc_HPT decl in HscTypes).++It is possible (though hard) to get this error through user behaviour.+ * Suppose package P (modules P1, P2) depends on package Q (modules Q1,+ Q2, with Q2 importing Q1)+ * We compile both packages.+ * Now we edit package Q so that it somehow depends on P+ * Now recompile Q with --make (without recompiling P).+ * Then Q1 imports, say, P1, which in turn depends on Q2. So Q2+ is a home-package module which is not yet in the HPT! Disaster.++This actually happened with P=base, Q=ghc-prim, via the AMP warnings.+See Trac #8320.+-}++findAndReadIface :: SDoc+ -- The unique identifier of the on-disk module we're+ -- looking for+ -> InstalledModule+ -- The *actual* module we're looking for. We use+ -- this to check the consistency of the requirements+ -- of the module we read out.+ -> Module+ -> IsBootInterface -- True <=> Look for a .hi-boot file+ -- False <=> Look for .hi file+ -> TcRnIf gbl lcl (MaybeErr MsgDoc (ModIface, FilePath))+ -- Nothing <=> file not found, or unreadable, or illegible+ -- Just x <=> successfully found and parsed++ -- It *doesn't* add an error to the monad, because+ -- sometimes it's ok to fail... see notes with loadInterface+findAndReadIface doc_str mod wanted_mod_with_insts hi_boot_file+ = do traceIf (sep [hsep [text "Reading",+ if hi_boot_file+ then text "[boot]"+ else Outputable.empty,+ text "interface for",+ ppr mod <> semi],+ nest 4 (text "reason:" <+> doc_str)])++ -- Check for GHC.Prim, and return its static interface+ -- TODO: make this check a function+ if mod `installedModuleEq` gHC_PRIM+ then do+ iface <- getHooked ghcPrimIfaceHook ghcPrimIface+ return (Succeeded (iface,+ "<built in interface for GHC.Prim>"))+ else do+ dflags <- getDynFlags+ -- Look for the file+ hsc_env <- getTopEnv+ mb_found <- liftIO (findExactModule hsc_env 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)++ -- See Note [Home module load error]+ if installedModuleUnitId mod `installedUnitIdEq` thisPackage dflags &&+ not (isOneShot (ghcMode dflags))+ then return (Failed (homeModError mod loc))+ else do r <- read_file file_path+ checkBuildDynamicToo r+ return r+ err -> do+ traceIf (text "...not found")+ dflags <- getDynFlags+ return (Failed (cannotFindInterface dflags+ (installedModuleName mod) err))+ where read_file file_path = do+ traceIf (text "readIFace" <+> text file_path)+ -- Figure out what is recorded in mi_module. If this is+ -- a fully definite interface, it'll match exactly, but+ -- if it's indefinite, the inside will be uninstantiated!+ dflags <- getDynFlags+ let wanted_mod =+ case splitModuleInsts wanted_mod_with_insts of+ (_, Nothing) -> wanted_mod_with_insts+ (_, Just indef_mod) ->+ indefModuleToModule dflags+ (generalizeIndefModule indef_mod)+ read_result <- readIface wanted_mod file_path+ case read_result of+ Failed err -> return (Failed (badIfaceFile file_path err))+ Succeeded iface -> return (Succeeded (iface, file_path))+ -- Don't forget to fill in the package name...+ checkBuildDynamicToo (Succeeded (iface, filePath)) = do+ dflags <- getDynFlags+ -- Indefinite interfaces are ALWAYS non-dynamic, and+ -- that's OK.+ let is_definite_iface = moduleIsDefinite (mi_module iface)+ when is_definite_iface $+ whenGeneratingDynamicToo dflags $ withDoDynamicToo $ do+ let ref = canGenerateDynamicToo dflags+ dynFilePath = addBootSuffix_maybe hi_boot_file+ $ replaceExtension filePath (dynHiSuf dflags)+ r <- read_file dynFilePath+ case r of+ Succeeded (dynIface, _)+ | mi_mod_hash iface == mi_mod_hash dynIface ->+ return ()+ | otherwise ->+ do traceIf (text "Dynamic hash doesn't match")+ liftIO $ writeIORef ref False+ Failed err ->+ do traceIf (text "Failed to load dynamic interface file:" $$ err)+ liftIO $ writeIORef ref False+ checkBuildDynamicToo _ = return ()++-- @readIface@ tries just the one file.++readIface :: Module -> FilePath+ -> TcRnIf gbl lcl (MaybeErr MsgDoc ModIface)+ -- Failed err <=> file not found, or unreadable, or illegible+ -- Succeeded iface <=> successfully found and parsed++readIface wanted_mod file_path+ = do { res <- tryMostM $+ readBinIface CheckHiWay QuietBinIFaceReading file_path+ ; dflags <- getDynFlags+ ; case res of+ Right iface+ -- NB: This check is NOT just a sanity check, it is+ -- critical for correctness of recompilation checking+ -- (it lets us tell when -this-unit-id has changed.)+ | wanted_mod == actual_mod+ -> return (Succeeded iface)+ | otherwise -> return (Failed err)+ where+ actual_mod = mi_module iface+ err = hiModuleNameMismatchWarn dflags wanted_mod actual_mod++ Left exn -> return (Failed (text (showException exn)))+ }++{-+*********************************************************+* *+ Wired-in interface for GHC.Prim+* *+*********************************************************+-}++initExternalPackageState :: ExternalPackageState+initExternalPackageState+ = EPS {+ eps_is_boot = emptyUFM,+ eps_PIT = emptyPackageIfaceTable,+ eps_free_holes = emptyInstalledModuleEnv,+ eps_PTE = emptyTypeEnv,+ eps_inst_env = emptyInstEnv,+ eps_fam_inst_env = emptyFamInstEnv,+ eps_rule_base = mkRuleBase builtinRules,+ -- Initialise the EPS rule pool with the built-in rules+ eps_mod_fam_inst_env+ = emptyModuleEnv,+ eps_vect_info = noVectInfo,+ eps_complete_matches = emptyUFM,+ eps_ann_env = emptyAnnEnv,+ eps_stats = EpsStats { n_ifaces_in = 0, n_decls_in = 0, n_decls_out = 0+ , n_insts_in = 0, n_insts_out = 0+ , n_rules_in = length builtinRules, n_rules_out = 0 }+ }++{-+*********************************************************+* *+ Wired-in interface for GHC.Prim+* *+*********************************************************+-}++ghcPrimIface :: ModIface+ghcPrimIface+ = (emptyModIface gHC_PRIM) {+ mi_exports = ghcPrimExports,+ mi_decls = [],+ mi_fixities = fixities,+ mi_fix_fn = mkIfaceFixCache fixities+ }+ where+ fixities = (getOccName seqId, Fixity NoSourceText 0 InfixR)+ -- seq is infixr 0+ : (occName funTyConName, funTyFixity) -- trac #10145+ : mapMaybe mkFixity allThePrimOps+ mkFixity op = (,) (primOpOcc op) <$> primOpFixity op++{-+*********************************************************+* *+\subsection{Statistics}+* *+*********************************************************+-}++ifaceStats :: ExternalPackageState -> SDoc+ifaceStats eps+ = hcat [text "Renamer stats: ", msg]+ where+ stats = eps_stats eps+ msg = vcat+ [int (n_ifaces_in stats) <+> text "interfaces read",+ hsep [ int (n_decls_out stats), text "type/class/variable imported, out of",+ int (n_decls_in stats), text "read"],+ hsep [ int (n_insts_out stats), text "instance decls imported, out of",+ int (n_insts_in stats), text "read"],+ hsep [ int (n_rules_out stats), text "rule decls imported, out of",+ int (n_rules_in stats), text "read"]+ ]++{-+************************************************************************+* *+ Printing interfaces+* *+************************************************************************+-}++-- | Read binary interface, and print it out+showIface :: HscEnv -> FilePath -> IO ()+showIface hsc_env filename = do+ -- skip the hi way check; we don't want to worry about profiled vs.+ -- non-profiled interfaces, for example.+ iface <- initTcRnIf 's' hsc_env () () $+ readBinIface IgnoreHiWay TraceBinIFaceReading filename+ let dflags = hsc_dflags hsc_env+ putLogMsg dflags NoReason SevDump noSrcSpan+ (defaultDumpStyle dflags) (pprModIface iface)++-- Show a ModIface but don't display details; suitable for ModIfaces stored in+-- the EPT.+pprModIfaceSimple :: ModIface -> SDoc+pprModIfaceSimple iface = ppr (mi_module iface) $$ pprDeps (mi_deps iface) $$ nest 2 (vcat (map pprExport (mi_exports iface)))++pprModIface :: ModIface -> SDoc+-- Show a ModIface+pprModIface iface+ = vcat [ text "interface"+ <+> ppr (mi_module iface) <+> pp_hsc_src (mi_hsc_src iface)+ <+> (if mi_orphan iface then text "[orphan module]" else Outputable.empty)+ <+> (if mi_finsts iface then text "[family instance module]" else Outputable.empty)+ <+> (if mi_hpc iface then text "[hpc]" else Outputable.empty)+ <+> integer hiVersion+ , nest 2 (text "interface hash:" <+> ppr (mi_iface_hash iface))+ , nest 2 (text "ABI hash:" <+> ppr (mi_mod_hash iface))+ , nest 2 (text "export-list hash:" <+> ppr (mi_exp_hash iface))+ , nest 2 (text "orphan hash:" <+> ppr (mi_orphan_hash iface))+ , nest 2 (text "flag hash:" <+> ppr (mi_flag_hash iface))+ , nest 2 (text "sig of:" <+> ppr (mi_sig_of iface))+ , nest 2 (text "used TH splices:" <+> ppr (mi_used_th iface))+ , nest 2 (text "where")+ , text "exports:"+ , nest 2 (vcat (map pprExport (mi_exports iface)))+ , pprDeps (mi_deps iface)+ , vcat (map pprUsage (mi_usages iface))+ , vcat (map pprIfaceAnnotation (mi_anns iface))+ , pprFixities (mi_fixities iface)+ , vcat [ppr ver $$ nest 2 (ppr decl) | (ver,decl) <- mi_decls iface]+ , vcat (map ppr (mi_insts iface))+ , vcat (map ppr (mi_fam_insts iface))+ , vcat (map ppr (mi_rules iface))+ , pprVectInfo (mi_vect_info iface)+ , ppr (mi_warns iface)+ , pprTrustInfo (mi_trust iface)+ , pprTrustPkg (mi_trust_pkg iface)+ , vcat (map ppr (mi_complete_sigs iface))+ ]+ where+ pp_hsc_src HsBootFile = text "[boot]"+ pp_hsc_src HsigFile = text "[hsig]"+ pp_hsc_src HsSrcFile = Outputable.empty++{-+When printing export lists, we print like this:+ Avail f f+ AvailTC C [C, x, y] C(x,y)+ AvailTC C [x, y] C!(x,y) -- Exporting x, y but not C+-}++pprExport :: IfaceExport -> SDoc+pprExport (Avail n) = ppr n+pprExport (AvailTC _ [] []) = Outputable.empty+pprExport (AvailTC n ns0 fs)+ = case ns0 of+ (n':ns) | n==n' -> ppr n <> pp_export ns fs+ _ -> ppr n <> vbar <> pp_export ns0 fs+ where+ pp_export [] [] = Outputable.empty+ pp_export names fs = braces (hsep (map ppr names ++ map (ppr . flLabel) fs))++pprUsage :: Usage -> SDoc+pprUsage usage@UsagePackageModule{}+ = pprUsageImport usage usg_mod+pprUsage usage@UsageHomeModule{}+ = pprUsageImport usage usg_mod_name $$+ nest 2 (+ maybe Outputable.empty (\v -> text "exports: " <> ppr v) (usg_exports usage) $$+ vcat [ ppr n <+> ppr v | (n,v) <- usg_entities usage ]+ )+pprUsage usage@UsageFile{}+ = hsep [text "addDependentFile",+ doubleQuotes (text (usg_file_path usage))]+pprUsage usage@UsageMergedRequirement{}+ = hsep [text "merged", ppr (usg_mod usage), ppr (usg_mod_hash usage)]++pprUsageImport :: Outputable a => Usage -> (Usage -> a) -> SDoc+pprUsageImport usage usg_mod'+ = hsep [text "import", safe, ppr (usg_mod' usage),+ ppr (usg_mod_hash usage)]+ where+ safe | usg_safe usage = text "safe"+ | otherwise = text " -/ "++pprDeps :: Dependencies -> SDoc+pprDeps (Deps { dep_mods = mods, dep_pkgs = pkgs, dep_orphs = orphs,+ dep_finsts = finsts })+ = vcat [text "module dependencies:" <+> fsep (map ppr_mod mods),+ text "package dependencies:" <+> fsep (map ppr_pkg pkgs),+ text "orphans:" <+> fsep (map ppr orphs),+ text "family instance modules:" <+> fsep (map ppr finsts)+ ]+ where+ ppr_mod (mod_name, boot) = ppr mod_name <+> ppr_boot boot+ ppr_pkg (pkg,trust_req) = ppr pkg <>+ (if trust_req then text "*" else Outputable.empty)+ ppr_boot True = text "[boot]"+ ppr_boot False = Outputable.empty++pprFixities :: [(OccName, Fixity)] -> SDoc+pprFixities [] = Outputable.empty+pprFixities fixes = text "fixities" <+> pprWithCommas pprFix fixes+ where+ pprFix (occ,fix) = ppr fix <+> ppr occ++pprVectInfo :: IfaceVectInfo -> SDoc+pprVectInfo (IfaceVectInfo { ifaceVectInfoVar = vars+ , ifaceVectInfoTyCon = tycons+ , ifaceVectInfoTyConReuse = tyconsReuse+ , ifaceVectInfoParallelVars = parallelVars+ , ifaceVectInfoParallelTyCons = parallelTyCons+ }) =+ vcat+ [ text "vectorised variables:" <+> hsep (map ppr vars)+ , text "vectorised tycons:" <+> hsep (map ppr tycons)+ , text "vectorised reused tycons:" <+> hsep (map ppr tyconsReuse)+ , text "parallel variables:" <+> hsep (map ppr parallelVars)+ , text "parallel tycons:" <+> hsep (map ppr parallelTyCons)+ ]++pprTrustInfo :: IfaceTrustInfo -> SDoc+pprTrustInfo trust = text "trusted:" <+> ppr trust++pprTrustPkg :: Bool -> SDoc+pprTrustPkg tpkg = text "require own pkg trusted:" <+> ppr tpkg++instance Outputable Warnings where+ ppr = pprWarns++pprWarns :: Warnings -> SDoc+pprWarns NoWarnings = Outputable.empty+pprWarns (WarnAll txt) = text "Warn all" <+> ppr txt+pprWarns (WarnSome prs) = text "Warnings"+ <+> vcat (map pprWarning prs)+ where pprWarning (name, txt) = ppr name <+> ppr txt++pprIfaceAnnotation :: IfaceAnnotation -> SDoc+pprIfaceAnnotation (IfaceAnnotation { ifAnnotatedTarget = target, ifAnnotatedValue = serialized })+ = ppr target <+> text "annotated by" <+> ppr serialized++{-+*********************************************************+* *+\subsection{Errors}+* *+*********************************************************+-}++badIfaceFile :: String -> SDoc -> SDoc+badIfaceFile file err+ = vcat [text "Bad interface file:" <+> text file,+ nest 4 err]++hiModuleNameMismatchWarn :: DynFlags -> Module -> Module -> MsgDoc+hiModuleNameMismatchWarn dflags requested_mod read_mod+ | moduleUnitId requested_mod == moduleUnitId read_mod =+ sep [text "Interface file contains module" <+> quotes (ppr read_mod) <> comma,+ text "but we were expecting module" <+> quotes (ppr requested_mod),+ sep [text "Probable cause: the source code which generated interface file",+ text "has an incompatible module name"+ ]+ ]+ | otherwise =+ -- ToDo: This will fail to have enough qualification when the package IDs+ -- are the same+ withPprStyle (mkUserStyle dflags alwaysQualify AllTheWay) $+ -- we want the Modules below to be qualified with package names,+ -- so reset the PrintUnqualified setting.+ hsep [ text "Something is amiss; requested module "+ , ppr requested_mod+ , text "differs from name found in the interface file"+ , ppr read_mod+ , parens (text "if these names look the same, try again with -dppr-debug")+ ]++homeModError :: InstalledModule -> ModLocation -> SDoc+-- See Note [Home module load error]+homeModError mod location+ = text "attempting to use module " <> quotes (ppr mod)+ <> (case ml_hs_file location of+ Just file -> space <> parens (text file)+ Nothing -> Outputable.empty)+ <+> text "which is not loaded"
+ iface/LoadIface.hs-boot view
@@ -0,0 +1,7 @@+module LoadIface where+import Module (Module)+import TcRnMonad (IfM)+import HscTypes (ModIface)+import Outputable (SDoc)++loadSysInterface :: SDoc -> Module -> IfM lcl ModIface
+ iface/MkIface.hs view
@@ -0,0 +1,1815 @@+{-+(c) The University of Glasgow 2006-2008+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998+-}++{-# LANGUAGE CPP, NondecreasingIndentation #-}++-- | Module for constructing @ModIface@ values (interface files),+-- writing them to disk and comparing two versions to see if+-- recompilation is required.+module MkIface (+ mkIface, -- Build a ModIface from a ModGuts,+ -- including computing version information++ mkIfaceTc,++ writeIfaceFile, -- Write the interface file++ checkOldIface, -- See if recompilation is required, by+ -- comparing version information+ RecompileRequired(..), recompileRequired,+ mkIfaceExports,++ tyThingToIfaceDecl -- Converting things to their Iface equivalents+ ) where++{-+ -----------------------------------------------+ Recompilation checking+ -----------------------------------------------++A complete description of how recompilation checking works can be+found in the wiki commentary:++ http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance++Please read the above page for a top-down description of how this all+works. Notes below cover specific issues related to the implementation.++Basic idea:++ * In the mi_usages information in an interface, we record the+ fingerprint of each free variable of the module++ * In mkIface, we compute the fingerprint of each exported thing A.f.+ For each external thing that A.f refers to, we include the fingerprint+ of the external reference when computing the fingerprint of A.f. So+ if anything that A.f depends on changes, then A.f's fingerprint will+ change.+ Also record any dependent files added with+ * addDependentFile+ * #include+ * -optP-include++ * In checkOldIface we compare the mi_usages for the module with+ the actual fingerprint for all each thing recorded in mi_usages+-}++#include "HsVersions.h"++import IfaceSyn+import BinFingerprint+import LoadIface+import ToIface+import FlagChecker++import DsUsage ( mkUsageInfo, mkUsedNames, mkDependencies )+import Id+import Annotations+import CoreSyn+import Class+import TyCon+import CoAxiom+import ConLike+import DataCon+import Type+import TcType+import InstEnv+import FamInstEnv+import TcRnMonad+import HsSyn+import HscTypes+import Finder+import DynFlags+import VarEnv+import VarSet+import Var+import Name+import Avail+import RdrName+import NameEnv+import NameSet+import Module+import BinIface+import ErrUtils+import Digraph+import SrcLoc+import Outputable+import BasicTypes hiding ( SuccessFlag(..) )+import Unique+import Util hiding ( eqListBy )+import FastString+import Maybes+import Binary+import Fingerprint+import Exception+import UniqSet+import Packages++import Control.Monad+import Data.Function+import Data.List+import qualified Data.Map as Map+import Data.Ord+import Data.IORef+import System.Directory+import System.FilePath++{-+************************************************************************+* *+\subsection{Completing an interface}+* *+************************************************************************+-}++mkIface :: HscEnv+ -> Maybe Fingerprint -- The old fingerprint, if we have it+ -> ModDetails -- The trimmed, tidied interface+ -> ModGuts -- Usages, deprecations, etc+ -> IO (ModIface, -- The new one+ Bool) -- True <=> there was an old Iface, and the+ -- new one is identical, so no need+ -- to write it++mkIface hsc_env maybe_old_fingerprint mod_details+ ModGuts{ mg_module = this_mod,+ mg_hsc_src = hsc_src,+ mg_usages = usages,+ mg_used_th = used_th,+ mg_deps = deps,+ mg_rdr_env = rdr_env,+ mg_fix_env = fix_env,+ mg_warns = warns,+ mg_hpc_info = hpc_info,+ mg_safe_haskell = safe_mode,+ mg_trust_pkg = self_trust+ }+ = mkIface_ hsc_env maybe_old_fingerprint+ this_mod hsc_src used_th deps rdr_env fix_env+ warns hpc_info self_trust+ safe_mode usages mod_details++-- | make an interface from the results of typechecking only. Useful+-- for non-optimising compilation, or where we aren't generating any+-- object code at all ('HscNothing').+mkIfaceTc :: HscEnv+ -> Maybe Fingerprint -- The old fingerprint, if we have it+ -> SafeHaskellMode -- The safe haskell mode+ -> ModDetails -- gotten from mkBootModDetails, probably+ -> TcGblEnv -- Usages, deprecations, etc+ -> IO (ModIface, Bool)+mkIfaceTc hsc_env maybe_old_fingerprint safe_mode mod_details+ tc_result@TcGblEnv{ tcg_mod = this_mod,+ tcg_src = hsc_src,+ tcg_imports = imports,+ tcg_rdr_env = rdr_env,+ tcg_fix_env = fix_env,+ tcg_merged = merged,+ tcg_warns = warns,+ tcg_hpc = other_hpc_info,+ tcg_th_splice_used = tc_splice_used,+ tcg_dependent_files = dependent_files+ }+ = do+ let used_names = mkUsedNames tc_result+ deps <- mkDependencies tc_result+ let hpc_info = emptyHpcInfo other_hpc_info+ used_th <- readIORef tc_splice_used+ dep_files <- (readIORef dependent_files)+ -- Do NOT use semantic module here; this_mod in mkUsageInfo+ -- is used solely to decide if we should record a dependency+ -- or not. When we instantiate a signature, the semantic+ -- module is something we want to record dependencies for,+ -- but if you pass that in here, we'll decide it's the local+ -- module and does not need to be recorded as a dependency.+ -- See Note [Identity versus semantic module]+ usages <- mkUsageInfo hsc_env this_mod (imp_mods imports) used_names dep_files merged+ mkIface_ hsc_env maybe_old_fingerprint+ this_mod hsc_src+ used_th deps rdr_env+ fix_env warns hpc_info+ (imp_trust_own_pkg imports) safe_mode usages mod_details+++mkIface_ :: HscEnv -> Maybe Fingerprint -> Module -> HscSource+ -> Bool -> Dependencies -> GlobalRdrEnv+ -> NameEnv FixItem -> Warnings -> HpcInfo+ -> Bool+ -> SafeHaskellMode+ -> [Usage]+ -> ModDetails+ -> IO (ModIface, Bool)+mkIface_ hsc_env maybe_old_fingerprint+ this_mod hsc_src used_th deps rdr_env fix_env src_warns+ hpc_info pkg_trust_req safe_mode usages+ ModDetails{ md_insts = insts,+ md_fam_insts = fam_insts,+ md_rules = rules,+ md_anns = anns,+ md_vect_info = vect_info,+ md_types = type_env,+ md_exports = exports,+ md_complete_sigs = complete_sigs }+-- NB: notice that mkIface does not look at the bindings+-- only at the TypeEnv. The previous Tidy phase has+-- put exactly the info into the TypeEnv that we want+-- to expose in the interface++ = do+ let semantic_mod = canonicalizeHomeModule (hsc_dflags hsc_env) (moduleName this_mod)+ entities = typeEnvElts type_env+ decls = [ tyThingToIfaceDecl entity+ | entity <- entities,+ let name = getName entity,+ not (isImplicitTyThing entity),+ -- No implicit Ids and class tycons in the interface file+ not (isWiredInName name),+ -- Nor wired-in things; the compiler knows about them anyhow+ nameIsLocalOrFrom semantic_mod name ]+ -- Sigh: see Note [Root-main Id] in TcRnDriver+ -- NB: ABSOLUTELY need to check against semantic_mod,+ -- because all of the names in an hsig p[H=<H>]:H+ -- are going to be for <H>, not the former id!+ -- See Note [Identity versus semantic module]++ fixities = sortBy (comparing fst)+ [(occ,fix) | FixItem occ fix <- nameEnvElts fix_env]+ -- The order of fixities returned from nameEnvElts is not+ -- deterministic, so we sort by OccName to canonicalize it.+ -- See Note [Deterministic UniqFM] in UniqDFM for more details.+ warns = src_warns+ iface_rules = map coreRuleToIfaceRule rules+ iface_insts = map instanceToIfaceInst $ fixSafeInstances safe_mode insts+ iface_fam_insts = map famInstToIfaceFamInst fam_insts+ iface_vect_info = flattenVectInfo vect_info+ trust_info = setSafeMode safe_mode+ annotations = map mkIfaceAnnotation anns+ icomplete_sigs = map mkIfaceCompleteSig complete_sigs++ intermediate_iface = ModIface {+ mi_module = this_mod,+ -- Need to record this because it depends on the -instantiated-with flag+ -- which could change+ mi_sig_of = if semantic_mod == this_mod+ then Nothing+ else Just semantic_mod,+ mi_hsc_src = hsc_src,+ mi_deps = deps,+ mi_usages = usages,+ mi_exports = mkIfaceExports exports,++ -- Sort these lexicographically, so that+ -- the result is stable across compilations+ mi_insts = sortBy cmp_inst iface_insts,+ mi_fam_insts = sortBy cmp_fam_inst iface_fam_insts,+ mi_rules = sortBy cmp_rule iface_rules,++ mi_vect_info = iface_vect_info,++ mi_fixities = fixities,+ mi_warns = warns,+ mi_anns = annotations,+ mi_globals = maybeGlobalRdrEnv rdr_env,++ -- Left out deliberately: filled in by addFingerprints+ mi_iface_hash = fingerprint0,+ mi_mod_hash = fingerprint0,+ mi_flag_hash = fingerprint0,+ mi_exp_hash = fingerprint0,+ mi_used_th = used_th,+ mi_orphan_hash = fingerprint0,+ mi_orphan = False, -- Always set by addFingerprints, but+ -- it's a strict field, so we can't omit it.+ mi_finsts = False, -- Ditto+ mi_decls = deliberatelyOmitted "decls",+ mi_hash_fn = deliberatelyOmitted "hash_fn",+ mi_hpc = isHpcUsed hpc_info,+ mi_trust = trust_info,+ mi_trust_pkg = pkg_trust_req,++ -- And build the cached values+ mi_warn_fn = mkIfaceWarnCache warns,+ mi_fix_fn = mkIfaceFixCache fixities,+ mi_complete_sigs = icomplete_sigs }++ (new_iface, no_change_at_all)+ <- {-# SCC "versioninfo" #-}+ addFingerprints hsc_env maybe_old_fingerprint+ intermediate_iface decls++ -- Debug printing+ dumpIfSet_dyn dflags Opt_D_dump_hi "FINAL INTERFACE"+ (pprModIface new_iface)++ -- bug #1617: on reload we weren't updating the PrintUnqualified+ -- correctly. This stems from the fact that the interface had+ -- not changed, so addFingerprints returns the old ModIface+ -- with the old GlobalRdrEnv (mi_globals).+ let final_iface = new_iface{ mi_globals = maybeGlobalRdrEnv rdr_env }++ return (final_iface, no_change_at_all)+ where+ cmp_rule = comparing ifRuleName+ -- Compare these lexicographically by OccName, *not* by unique,+ -- because the latter is not stable across compilations:+ cmp_inst = comparing (nameOccName . ifDFun)+ cmp_fam_inst = comparing (nameOccName . ifFamInstTcName)++ dflags = hsc_dflags hsc_env++ -- We only fill in mi_globals if the module was compiled to byte+ -- code. Otherwise, the compiler may not have retained all the+ -- top-level bindings and they won't be in the TypeEnv (see+ -- Desugar.addExportFlagsAndRules). The mi_globals field is used+ -- by GHCi to decide whether the module has its full top-level+ -- scope available. (#5534)+ maybeGlobalRdrEnv :: GlobalRdrEnv -> Maybe GlobalRdrEnv+ maybeGlobalRdrEnv rdr_env+ | targetRetainsAllBindings (hscTarget dflags) = Just rdr_env+ | otherwise = Nothing++ deliberatelyOmitted :: String -> a+ deliberatelyOmitted x = panic ("Deliberately omitted: " ++ x)++ ifFamInstTcName = ifFamInstFam++ flattenVectInfo (VectInfo { vectInfoVar = vVar+ , vectInfoTyCon = vTyCon+ , vectInfoParallelVars = vParallelVars+ , vectInfoParallelTyCons = vParallelTyCons+ }) =+ IfaceVectInfo+ { ifaceVectInfoVar = [Var.varName v | (v, _ ) <- dVarEnvElts vVar]+ , ifaceVectInfoTyCon = [tyConName t | (t, t_v) <- nameEnvElts vTyCon, t /= t_v]+ , ifaceVectInfoTyConReuse = [tyConName t | (t, t_v) <- nameEnvElts vTyCon, t == t_v]+ , ifaceVectInfoParallelVars = [Var.varName v | v <- dVarSetElems vParallelVars]+ , ifaceVectInfoParallelTyCons = nameSetElemsStable vParallelTyCons+ }++-----------------------------+writeIfaceFile :: DynFlags -> FilePath -> ModIface -> IO ()+writeIfaceFile dflags hi_file_path new_iface+ = do createDirectoryIfMissing True (takeDirectory hi_file_path)+ writeBinIface dflags hi_file_path new_iface+++-- -----------------------------------------------------------------------------+-- Look up parents and versions of Names++-- This is like a global version of the mi_hash_fn field in each ModIface.+-- Given a Name, it finds the ModIface, and then uses mi_hash_fn to get+-- the parent and version info.++mkHashFun+ :: HscEnv -- needed to look up versions+ -> ExternalPackageState -- ditto+ -> (Name -> IO Fingerprint)+mkHashFun hsc_env eps name+ | isHoleModule orig_mod+ = lookup (mkModule (thisPackage dflags) (moduleName orig_mod))+ | otherwise+ = lookup orig_mod+ where+ dflags = hsc_dflags hsc_env+ hpt = hsc_HPT hsc_env+ pit = eps_PIT eps+ occ = nameOccName name+ orig_mod = nameModule name+ lookup mod = do+ MASSERT2( isExternalName name, ppr name )+ iface <- case lookupIfaceByModule dflags hpt pit mod of+ Just iface -> return iface+ Nothing -> do+ -- This can occur when we're writing out ifaces for+ -- requirements; we didn't do any /real/ typechecking+ -- so there's no guarantee everything is loaded.+ -- Kind of a heinous hack.+ iface <- initIfaceLoad hsc_env . withException+ $ loadInterface (text "lookupVers2") mod ImportBySystem+ return iface+ return $ snd (mi_hash_fn iface occ `orElse`+ pprPanic "lookupVers1" (ppr mod <+> ppr occ))++-- ---------------------------------------------------------------------------+-- Compute fingerprints for the interface++{-+Note [Fingerprinting IfaceDecls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The general idea here is that we first examine the 'IfaceDecl's and determine+the recursive groups of them. We then walk these groups in dependency order,+serializing each contained 'IfaceDecl' to a "Binary" buffer which we then+hash using MD5 to produce a fingerprint for the group.++However, the serialization that we use is a bit funny: we override the @putName@+operation with our own which serializes the hash of a 'Name' instead of the+'Name' itself. This ensures that the fingerprint of a decl changes if anything+in its transitive closure changes. This trick is why we must be careful about+traversing in dependency order: we need to ensure that we have hashes for+everything referenced by the decl which we are fingerprinting.++Moreover, we need to be careful to distinguish between serialization of binding+Names (e.g. the ifName field of a IfaceDecl) and non-binding (e.g. the ifInstCls+field of a IfaceClsInst): only in the non-binding case should we include the+fingerprint; in the binding case we shouldn't since it is merely the name of the+thing that we are currently fingerprinting.+-}++-- | Add fingerprints for top-level declarations to a 'ModIface'.+--+-- See Note [Fingerprinting IfaceDecls]+addFingerprints+ :: HscEnv+ -> Maybe Fingerprint -- the old fingerprint, if any+ -> ModIface -- The new interface (lacking decls)+ -> [IfaceDecl] -- The new decls+ -> IO (ModIface, -- Updated interface+ Bool) -- True <=> no changes at all;+ -- no need to write Iface++addFingerprints hsc_env mb_old_fingerprint iface0 new_decls+ = do+ eps <- hscEPS hsc_env+ let+ -- The ABI of a declaration represents everything that is made+ -- visible about the declaration that a client can depend on.+ -- see IfaceDeclABI below.+ declABI :: IfaceDecl -> IfaceDeclABI+ -- TODO: I'm not sure if this should be semantic_mod or this_mod.+ -- See also Note [Identity versus semantic module]+ declABI decl = (this_mod, decl, extras)+ where extras = declExtras fix_fn ann_fn non_orph_rules non_orph_insts+ non_orph_fis decl++ edges :: [(IfaceDeclABI, Unique, [Unique])]+ edges = [ (abi, getUnique (getOccName decl), out)+ | decl <- new_decls+ , let abi = declABI decl+ , let out = localOccs $ freeNamesDeclABI abi+ ]++ name_module n = ASSERT2( isExternalName n, ppr n ) nameModule n+ localOccs =+ map (getUnique . getParent . getOccName)+ -- NB: names always use semantic module, so+ -- filtering must be on the semantic module!+ -- See Note [Identity versus semantic module]+ . filter ((== semantic_mod) . name_module)+ . nonDetEltsUniqSet+ -- It's OK to use nonDetEltsUFM as localOccs is only+ -- used to construct the edges and+ -- stronglyConnCompFromEdgedVertices is deterministic+ -- even with non-deterministic order of edges as+ -- explained in Note [Deterministic SCC] in Digraph.+ where getParent :: OccName -> OccName+ getParent occ = lookupOccEnv parent_map occ `orElse` occ++ -- maps OccNames to their parents in the current module.+ -- e.g. a reference to a constructor must be turned into a reference+ -- to the TyCon for the purposes of calculating dependencies.+ parent_map :: OccEnv OccName+ parent_map = foldl' extend emptyOccEnv new_decls+ where extend env d =+ extendOccEnvList env [ (b,n) | b <- ifaceDeclImplicitBndrs d ]+ where n = getOccName d++ -- strongly-connected groups of declarations, in dependency order+ groups :: [SCC IfaceDeclABI]+ groups =+ stronglyConnCompFromEdgedVerticesUniq edges++ global_hash_fn = mkHashFun hsc_env eps++ -- How to output Names when generating the data to fingerprint.+ -- Here we want to output the fingerprint for each top-level+ -- Name, whether it comes from the current module or another+ -- module. In this way, the fingerprint for a declaration will+ -- change if the fingerprint for anything it refers to (transitively)+ -- changes.+ mk_put_name :: OccEnv (OccName,Fingerprint)+ -> BinHandle -> Name -> IO ()+ mk_put_name local_env bh name+ | isWiredInName name = putNameLiterally bh name+ -- wired-in names don't have fingerprints+ | otherwise+ = ASSERT2( isExternalName name, ppr name )+ let hash | nameModule name /= semantic_mod = global_hash_fn name+ -- Get it from the REAL interface!!+ -- This will trigger when we compile an hsig file+ -- and we know a backing impl for it.+ -- See Note [Identity versus semantic module]+ | semantic_mod /= this_mod+ , not (isHoleModule semantic_mod) = global_hash_fn name+ | otherwise = return (snd (lookupOccEnv local_env (getOccName name)+ `orElse` pprPanic "urk! lookup local fingerprint"+ (ppr name $$ ppr local_env)))+ -- This panic indicates that we got the dependency+ -- analysis wrong, because we needed a fingerprint for+ -- an entity that wasn't in the environment. To debug+ -- it, turn the panic into a trace, uncomment the+ -- pprTraces below, run the compile again, and inspect+ -- the output and the generated .hi file with+ -- --show-iface.+ in hash >>= put_ bh++ -- take a strongly-connected group of declarations and compute+ -- its fingerprint.++ fingerprint_group :: (OccEnv (OccName,Fingerprint),+ [(Fingerprint,IfaceDecl)])+ -> SCC IfaceDeclABI+ -> IO (OccEnv (OccName,Fingerprint),+ [(Fingerprint,IfaceDecl)])++ fingerprint_group (local_env, decls_w_hashes) (AcyclicSCC abi)+ = do let hash_fn = mk_put_name local_env+ decl = abiDecl abi+ --pprTrace "fingerprinting" (ppr (ifName decl) ) $ do+ hash <- computeFingerprint hash_fn abi+ env' <- extend_hash_env local_env (hash,decl)+ return (env', (hash,decl) : decls_w_hashes)++ fingerprint_group (local_env, decls_w_hashes) (CyclicSCC abis)+ = do let decls = map abiDecl abis+ local_env1 <- foldM extend_hash_env local_env+ (zip (repeat fingerprint0) decls)+ let hash_fn = mk_put_name local_env1+ -- pprTrace "fingerprinting" (ppr (map ifName decls) ) $ do+ let stable_abis = sortBy cmp_abiNames abis+ -- put the cycle in a canonical order+ hash <- computeFingerprint hash_fn stable_abis+ let pairs = zip (repeat hash) decls+ local_env2 <- foldM extend_hash_env local_env pairs+ return (local_env2, pairs ++ decls_w_hashes)++ -- we have fingerprinted the whole declaration, but we now need+ -- to assign fingerprints to all the OccNames that it binds, to+ -- use when referencing those OccNames in later declarations.+ --+ extend_hash_env :: OccEnv (OccName,Fingerprint)+ -> (Fingerprint,IfaceDecl)+ -> IO (OccEnv (OccName,Fingerprint))+ extend_hash_env env0 (hash,d) = do+ return (foldr (\(b,fp) env -> extendOccEnv env b (b,fp)) env0+ (ifaceDeclFingerprints hash d))++ --+ (local_env, decls_w_hashes) <-+ foldM fingerprint_group (emptyOccEnv, []) groups++ -- when calculating fingerprints, we always need to use canonical+ -- ordering for lists of things. In particular, the mi_deps has various+ -- lists of modules and suchlike, so put these all in canonical order:+ let sorted_deps = sortDependencies (mi_deps iface0)++ -- The export hash of a module depends on the orphan hashes of the+ -- orphan modules below us in the dependency tree. This is the way+ -- that changes in orphans get propagated all the way up the+ -- dependency tree.+ --+ -- Note [A bad dep_orphs optimization]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- In a previous version of this code, we filtered out orphan modules which+ -- were not from the home package, justifying it by saying that "we'd+ -- pick up the ABI hashes of the external module instead". This is wrong.+ -- Suppose that we have:+ --+ -- module External where+ -- instance Show (a -> b)+ --+ -- module Home1 where+ -- import External+ --+ -- module Home2 where+ -- import Home1+ --+ -- The export hash of Home1 needs to reflect the orphan instances of+ -- External. It's true that Home1 will get rebuilt if the orphans+ -- of External, but we also need to make sure Home2 gets rebuilt+ -- as well. See #12733 for more details.+ let orph_mods+ = filter (/= this_mod) -- Note [Do not update EPS with your own hi-boot]+ $ dep_orphs sorted_deps+ dep_orphan_hashes <- getOrphanHashes hsc_env orph_mods++ -- Note [Do not update EPS with your own hi-boot]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- (See also Trac #10182). When your hs-boot file includes an orphan+ -- instance declaration, you may find that the dep_orphs of a module you+ -- import contains reference to yourself. DO NOT actually load this module+ -- or add it to the orphan hashes: you're going to provide the orphan+ -- instances yourself, no need to consult hs-boot; if you do load the+ -- interface into EPS, you will see a duplicate orphan instance.++ orphan_hash <- computeFingerprint (mk_put_name local_env)+ (map ifDFun orph_insts, orph_rules, orph_fis)++ -- the export list hash doesn't depend on the fingerprints of+ -- the Names it mentions, only the Names themselves, hence putNameLiterally.+ export_hash <- computeFingerprint putNameLiterally+ (mi_exports iface0,+ orphan_hash,+ dep_orphan_hashes,+ dep_pkgs (mi_deps iface0),+ -- See Note [Export hash depends on non-orphan family instances]+ dep_finsts (mi_deps iface0),+ -- dep_pkgs: see "Package Version Changes" on+ -- wiki/Commentary/Compiler/RecompilationAvoidance+ mi_trust iface0)+ -- Make sure change of Safe Haskell mode causes recomp.++ -- Note [Export hash depends on non-orphan family instances]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ --+ -- Suppose we have:+ --+ -- module A where+ -- type instance F Int = Bool+ --+ -- module B where+ -- import A+ --+ -- module C where+ -- import B+ --+ -- The family instance consistency check for C depends on the dep_finsts of+ -- B. If we rename module A to A2, when the dep_finsts of B changes, we need+ -- to make sure that C gets rebuilt. Effectively, the dep_finsts are part of+ -- the exports of B, because C always considers them when checking+ -- consistency.+ --+ -- A full discussion is in #12723.+ --+ -- We do NOT need to hash dep_orphs, because this is implied by+ -- dep_orphan_hashes, and we do not need to hash ordinary class instances,+ -- because there is no eager consistency check as there is with type families+ -- (also we didn't store it anywhere!)+ --++ -- put the declarations in a canonical order, sorted by OccName+ let sorted_decls = Map.elems $ Map.fromList $+ [(getOccName d, e) | e@(_, d) <- decls_w_hashes]++ -- the flag hash depends on:+ -- - (some of) dflags+ -- it returns two hashes, one that shouldn't change+ -- the abi hash and one that should+ flag_hash <- fingerprintDynFlags dflags this_mod putNameLiterally++ -- the ABI hash depends on:+ -- - decls+ -- - export list+ -- - orphans+ -- - deprecations+ -- - vect info+ -- - flag abi hash+ mod_hash <- computeFingerprint putNameLiterally+ (map fst sorted_decls,+ export_hash, -- includes orphan_hash+ mi_warns iface0,+ mi_vect_info iface0)++ -- The interface hash depends on:+ -- - the ABI hash, plus+ -- - the module level annotations,+ -- - usages+ -- - deps (home and external packages, dependent files)+ -- - hpc+ iface_hash <- computeFingerprint putNameLiterally+ (mod_hash,+ ann_fn (mkVarOcc "module"), -- See mkIfaceAnnCache+ mi_usages iface0,+ sorted_deps,+ mi_hpc iface0)++ let+ no_change_at_all = Just iface_hash == mb_old_fingerprint++ final_iface = iface0 {+ mi_mod_hash = mod_hash,+ mi_iface_hash = iface_hash,+ mi_exp_hash = export_hash,+ mi_orphan_hash = orphan_hash,+ mi_flag_hash = flag_hash,+ mi_orphan = not ( all ifRuleAuto orph_rules+ -- See Note [Orphans and auto-generated rules]+ && null orph_insts+ && null orph_fis+ && isNoIfaceVectInfo (mi_vect_info iface0)),+ mi_finsts = not . null $ mi_fam_insts iface0,+ mi_decls = sorted_decls,+ mi_hash_fn = lookupOccEnv local_env }+ --+ return (final_iface, no_change_at_all)++ where+ this_mod = mi_module iface0+ semantic_mod = mi_semantic_module iface0+ dflags = hsc_dflags hsc_env+ (non_orph_insts, orph_insts) = mkOrphMap ifInstOrph (mi_insts iface0)+ (non_orph_rules, orph_rules) = mkOrphMap ifRuleOrph (mi_rules iface0)+ (non_orph_fis, orph_fis) = mkOrphMap ifFamInstOrph (mi_fam_insts iface0)+ fix_fn = mi_fix_fn iface0+ ann_fn = mkIfaceAnnCache (mi_anns iface0)++-- | Retrieve the orphan hashes 'mi_orphan_hash' for a list of modules+-- (in particular, the orphan modules which are transitively imported by the+-- current module).+--+-- Q: Why do we need the hash at all, doesn't the list of transitively+-- imported orphan modules suffice?+--+-- A: If one of our transitive imports adds a new orphan instance, our+-- export hash must change so that modules which import us rebuild. If we just+-- hashed the [Module], the hash would not change even when a new instance was+-- added to a module that already had an orphan instance.+--+-- Q: Why don't we just hash the orphan hashes of our direct dependencies?+-- Why the full transitive closure?+--+-- A: Suppose we have these modules:+--+-- module A where+-- instance Show (a -> b) where+-- module B where+-- import A -- **+-- module C where+-- import A+-- import B+--+-- Whether or not we add or remove the import to A in B affects the+-- orphan hash of B. But it shouldn't really affect the orphan hash+-- of C. If we hashed only direct dependencies, there would be no+-- way to tell that the net effect was a wash, and we'd be forced+-- to recompile C and everything else.+getOrphanHashes :: HscEnv -> [Module] -> IO [Fingerprint]+getOrphanHashes hsc_env mods = do+ eps <- hscEPS hsc_env+ let+ hpt = hsc_HPT hsc_env+ pit = eps_PIT eps+ dflags = hsc_dflags hsc_env+ get_orph_hash mod =+ case lookupIfaceByModule dflags hpt pit mod of+ Just iface -> return (mi_orphan_hash iface)+ Nothing -> do -- similar to 'mkHashFun'+ iface <- initIfaceLoad hsc_env . withException+ $ loadInterface (text "getOrphanHashes") mod ImportBySystem+ return (mi_orphan_hash iface)++ --+ mapM get_orph_hash mods+++sortDependencies :: Dependencies -> Dependencies+sortDependencies d+ = Deps { dep_mods = sortBy (compare `on` (moduleNameFS.fst)) (dep_mods d),+ dep_pkgs = sortBy (compare `on` fst) (dep_pkgs d),+ dep_orphs = sortBy stableModuleCmp (dep_orphs d),+ dep_finsts = sortBy stableModuleCmp (dep_finsts d) }++-- | Creates cached lookup for the 'mi_anns' field of ModIface+-- Hackily, we use "module" as the OccName for any module-level annotations+mkIfaceAnnCache :: [IfaceAnnotation] -> OccName -> [AnnPayload]+mkIfaceAnnCache anns+ = \n -> lookupOccEnv env n `orElse` []+ where+ pair (IfaceAnnotation target value) =+ (case target of+ NamedTarget occn -> occn+ ModuleTarget _ -> mkVarOcc "module"+ , [value])+ -- flipping (++), so the first argument is always short+ env = mkOccEnv_C (flip (++)) (map pair anns)++{-+************************************************************************+* *+ The ABI of an IfaceDecl+* *+************************************************************************++Note [The ABI of an IfaceDecl]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The ABI of a declaration consists of:++ (a) the full name of the identifier (inc. module and package,+ because these are used to construct the symbol name by which+ the identifier is known externally).++ (b) the declaration itself, as exposed to clients. That is, the+ definition of an Id is included in the fingerprint only if+ it is made available as an unfolding in the interface.++ (c) the fixity of the identifier (if it exists)+ (d) for Ids: rules+ (e) for classes: instances, fixity & rules for methods+ (f) for datatypes: instances, fixity & rules for constrs++Items (c)-(f) are not stored in the IfaceDecl, but instead appear+elsewhere in the interface file. But they are *fingerprinted* with+the declaration itself. This is done by grouping (c)-(f) in IfaceDeclExtras,+and fingerprinting that as part of the declaration.+-}++type IfaceDeclABI = (Module, IfaceDecl, IfaceDeclExtras)++data IfaceDeclExtras+ = IfaceIdExtras IfaceIdExtras++ | IfaceDataExtras+ (Maybe Fixity) -- Fixity of the tycon itself (if it exists)+ [IfaceInstABI] -- Local class and family instances of this tycon+ -- See Note [Orphans] in InstEnv+ [AnnPayload] -- Annotations of the type itself+ [IfaceIdExtras] -- For each constructor: fixity, RULES and annotations++ | IfaceClassExtras+ (Maybe Fixity) -- Fixity of the class itself (if it exists)+ [IfaceInstABI] -- Local instances of this class *or*+ -- of its associated data types+ -- See Note [Orphans] in InstEnv+ [AnnPayload] -- Annotations of the type itself+ [IfaceIdExtras] -- For each class method: fixity, RULES and annotations++ | IfaceSynonymExtras (Maybe Fixity) [AnnPayload]++ | IfaceFamilyExtras (Maybe Fixity) [IfaceInstABI] [AnnPayload]++ | IfaceOtherDeclExtras++data IfaceIdExtras+ = IdExtras+ (Maybe Fixity) -- Fixity of the Id (if it exists)+ [IfaceRule] -- Rules for the Id+ [AnnPayload] -- Annotations for the Id++-- When hashing a class or family instance, we hash only the+-- DFunId or CoAxiom, because that depends on all the+-- information about the instance.+--+type IfaceInstABI = IfExtName -- Name of DFunId or CoAxiom that is evidence for the instance++abiDecl :: IfaceDeclABI -> IfaceDecl+abiDecl (_, decl, _) = decl++cmp_abiNames :: IfaceDeclABI -> IfaceDeclABI -> Ordering+cmp_abiNames abi1 abi2 = getOccName (abiDecl abi1) `compare`+ getOccName (abiDecl abi2)++freeNamesDeclABI :: IfaceDeclABI -> NameSet+freeNamesDeclABI (_mod, decl, extras) =+ freeNamesIfDecl decl `unionNameSet` freeNamesDeclExtras extras++freeNamesDeclExtras :: IfaceDeclExtras -> NameSet+freeNamesDeclExtras (IfaceIdExtras id_extras)+ = freeNamesIdExtras id_extras+freeNamesDeclExtras (IfaceDataExtras _ insts _ subs)+ = unionNameSets (mkNameSet insts : map freeNamesIdExtras subs)+freeNamesDeclExtras (IfaceClassExtras _ insts _ subs)+ = unionNameSets (mkNameSet insts : map freeNamesIdExtras subs)+freeNamesDeclExtras (IfaceSynonymExtras _ _)+ = emptyNameSet+freeNamesDeclExtras (IfaceFamilyExtras _ insts _)+ = mkNameSet insts+freeNamesDeclExtras IfaceOtherDeclExtras+ = emptyNameSet++freeNamesIdExtras :: IfaceIdExtras -> NameSet+freeNamesIdExtras (IdExtras _ rules _) = unionNameSets (map freeNamesIfRule rules)++instance Outputable IfaceDeclExtras where+ ppr IfaceOtherDeclExtras = Outputable.empty+ ppr (IfaceIdExtras extras) = ppr_id_extras extras+ ppr (IfaceSynonymExtras fix anns) = vcat [ppr fix, ppr anns]+ ppr (IfaceFamilyExtras fix finsts anns) = vcat [ppr fix, ppr finsts, ppr anns]+ ppr (IfaceDataExtras fix insts anns stuff) = vcat [ppr fix, ppr_insts insts, ppr anns,+ ppr_id_extras_s stuff]+ ppr (IfaceClassExtras fix insts anns stuff) = vcat [ppr fix, ppr_insts insts, ppr anns,+ ppr_id_extras_s stuff]++ppr_insts :: [IfaceInstABI] -> SDoc+ppr_insts _ = text "<insts>"++ppr_id_extras_s :: [IfaceIdExtras] -> SDoc+ppr_id_extras_s stuff = vcat (map ppr_id_extras stuff)++ppr_id_extras :: IfaceIdExtras -> SDoc+ppr_id_extras (IdExtras fix rules anns) = ppr fix $$ vcat (map ppr rules) $$ vcat (map ppr anns)++-- This instance is used only to compute fingerprints+instance Binary IfaceDeclExtras where+ get _bh = panic "no get for IfaceDeclExtras"+ put_ bh (IfaceIdExtras extras) = do+ putByte bh 1; put_ bh extras+ put_ bh (IfaceDataExtras fix insts anns cons) = do+ putByte bh 2; put_ bh fix; put_ bh insts; put_ bh anns; put_ bh cons+ put_ bh (IfaceClassExtras fix insts anns methods) = do+ putByte bh 3; put_ bh fix; put_ bh insts; put_ bh anns; put_ bh methods+ put_ bh (IfaceSynonymExtras fix anns) = do+ putByte bh 4; put_ bh fix; put_ bh anns+ put_ bh (IfaceFamilyExtras fix finsts anns) = do+ putByte bh 5; put_ bh fix; put_ bh finsts; put_ bh anns+ put_ bh IfaceOtherDeclExtras = putByte bh 6++instance Binary IfaceIdExtras where+ get _bh = panic "no get for IfaceIdExtras"+ put_ bh (IdExtras fix rules anns)= do { put_ bh fix; put_ bh rules; put_ bh anns }++declExtras :: (OccName -> Maybe Fixity)+ -> (OccName -> [AnnPayload])+ -> OccEnv [IfaceRule]+ -> OccEnv [IfaceClsInst]+ -> OccEnv [IfaceFamInst]+ -> IfaceDecl+ -> IfaceDeclExtras++declExtras fix_fn ann_fn rule_env inst_env fi_env decl+ = case decl of+ IfaceId{} -> IfaceIdExtras (id_extras n)+ IfaceData{ifCons=cons} ->+ IfaceDataExtras (fix_fn n)+ (map ifFamInstAxiom (lookupOccEnvL fi_env n) +++ map ifDFun (lookupOccEnvL inst_env n))+ (ann_fn n)+ (map (id_extras . occName . ifConName) (visibleIfConDecls cons))+ IfaceClass{ifBody = IfConcreteClass { ifSigs=sigs, ifATs=ats }} ->+ IfaceClassExtras (fix_fn n)+ (map ifDFun $ (concatMap at_extras ats)+ ++ lookupOccEnvL inst_env n)+ -- Include instances of the associated types+ -- as well as instances of the class (Trac #5147)+ (ann_fn n)+ [id_extras (getOccName op) | IfaceClassOp op _ _ <- sigs]+ IfaceSynonym{} -> IfaceSynonymExtras (fix_fn n)+ (ann_fn n)+ IfaceFamily{} -> IfaceFamilyExtras (fix_fn n)+ (map ifFamInstAxiom (lookupOccEnvL fi_env n))+ (ann_fn n)+ _other -> IfaceOtherDeclExtras+ where+ n = getOccName decl+ id_extras occ = IdExtras (fix_fn occ) (lookupOccEnvL rule_env occ) (ann_fn occ)+ at_extras (IfaceAT decl _) = lookupOccEnvL inst_env (getOccName decl)+++lookupOccEnvL :: OccEnv [v] -> OccName -> [v]+lookupOccEnvL env k = lookupOccEnv env k `orElse` []++{-+-- for testing: use the md5sum command to generate fingerprints and+-- compare the results against our built-in version.+ fp' <- oldMD5 dflags bh+ if fp /= fp' then pprPanic "computeFingerprint" (ppr fp <+> ppr fp')+ else return fp++oldMD5 dflags bh = do+ tmp <- newTempName dflags "bin"+ writeBinMem bh tmp+ tmp2 <- newTempName dflags "md5"+ let cmd = "md5sum " ++ tmp ++ " >" ++ tmp2+ r <- system cmd+ case r of+ ExitFailure _ -> throwGhcExceptionIO (PhaseFailed cmd r)+ ExitSuccess -> do+ hash_str <- readFile tmp2+ return $! readHexFingerprint hash_str+-}++----------------------+-- mkOrphMap partitions instance decls or rules into+-- (a) an OccEnv for ones that are not orphans,+-- mapping the local OccName to a list of its decls+-- (b) a list of orphan decls+mkOrphMap :: (decl -> IsOrphan) -- Extract orphan status from decl+ -> [decl] -- Sorted into canonical order+ -> (OccEnv [decl], -- Non-orphan decls associated with their key;+ -- each sublist in canonical order+ [decl]) -- Orphan decls; in canonical order+mkOrphMap get_key decls+ = foldl go (emptyOccEnv, []) decls+ where+ go (non_orphs, orphs) d+ | NotOrphan occ <- get_key d+ = (extendOccEnv_Acc (:) singleton non_orphs occ d, orphs)+ | otherwise = (non_orphs, d:orphs)++{-+************************************************************************+* *+ COMPLETE Pragmas+* *+************************************************************************+-}++mkIfaceCompleteSig :: CompleteMatch -> IfaceCompleteMatch+mkIfaceCompleteSig (CompleteMatch cls tc) = IfaceCompleteMatch cls tc+++{-+************************************************************************+* *+ Keeping track of what we've slurped, and fingerprints+* *+************************************************************************+-}+++mkIfaceAnnotation :: Annotation -> IfaceAnnotation+mkIfaceAnnotation (Annotation { ann_target = target, ann_value = payload })+ = IfaceAnnotation {+ ifAnnotatedTarget = fmap nameOccName target,+ ifAnnotatedValue = payload+ }++mkIfaceExports :: [AvailInfo] -> [IfaceExport] -- Sort to make canonical+mkIfaceExports exports+ = sortBy stableAvailCmp (map sort_subs exports)+ where+ sort_subs :: AvailInfo -> AvailInfo+ sort_subs (Avail n) = Avail n+ sort_subs (AvailTC n [] fs) = AvailTC n [] (sort_flds fs)+ sort_subs (AvailTC n (m:ms) fs)+ | n==m = AvailTC n (m:sortBy stableNameCmp ms) (sort_flds fs)+ | otherwise = AvailTC n (sortBy stableNameCmp (m:ms)) (sort_flds fs)+ -- Maintain the AvailTC Invariant++ sort_flds = sortBy (stableNameCmp `on` flSelector)++{-+Note [Original module]+~~~~~~~~~~~~~~~~~~~~~+Consider this:+ module X where { data family T }+ module Y( T(..) ) where { import X; data instance T Int = MkT Int }+The exported Avail from Y will look like+ X.T{X.T, Y.MkT}+That is, in Y,+ - only MkT is brought into scope by the data instance;+ - but the parent (used for grouping and naming in T(..) exports) is X.T+ - and in this case we export X.T too++In the result of MkIfaceExports, the names are grouped by defining module,+so we may need to split up a single Avail into multiple ones.++Note [Internal used_names]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Most of the used_names are External Names, but we can have Internal+Names too: see Note [Binders in Template Haskell] in Convert, and+Trac #5362 for an example. Such Names are always+ - Such Names are always for locally-defined things, for which we+ don't gather usage info, so we can just ignore them in ent_map+ - They are always System Names, hence the assert, just as a double check.+++************************************************************************+* *+ Load the old interface file for this module (unless+ we have it already), and check whether it is up to date+* *+************************************************************************+-}++data RecompileRequired+ = UpToDate+ -- ^ everything is up to date, recompilation is not required+ | MustCompile+ -- ^ The .hs file has been touched, or the .o/.hi file does not exist+ | RecompBecause String+ -- ^ The .o/.hi files are up to date, but something else has changed+ -- to force recompilation; the String says what (one-line summary)+ deriving Eq++recompileRequired :: RecompileRequired -> Bool+recompileRequired UpToDate = False+recompileRequired _ = True++++-- | Top level function to check if the version of an old interface file+-- is equivalent to the current source file the user asked us to compile.+-- If the same, we can avoid recompilation. We return a tuple where the+-- first element is a bool saying if we should recompile the object file+-- and the second is maybe the interface file, where Nothng means to+-- rebuild the interface file not use the exisitng one.+checkOldIface+ :: HscEnv+ -> ModSummary+ -> SourceModified+ -> Maybe ModIface -- Old interface from compilation manager, if any+ -> IO (RecompileRequired, Maybe ModIface)++checkOldIface hsc_env mod_summary source_modified maybe_iface+ = do let dflags = hsc_dflags hsc_env+ showPass dflags $+ "Checking old interface for " +++ (showPpr dflags $ ms_mod mod_summary) +++ " (use -ddump-hi-diffs for more details)"+ initIfaceCheck (text "checkOldIface") hsc_env $+ check_old_iface hsc_env mod_summary source_modified maybe_iface++check_old_iface+ :: HscEnv+ -> ModSummary+ -> SourceModified+ -> Maybe ModIface+ -> IfG (RecompileRequired, Maybe ModIface)++check_old_iface hsc_env mod_summary src_modified maybe_iface+ = let dflags = hsc_dflags hsc_env+ getIface =+ case maybe_iface of+ Just _ -> do+ traceIf (text "We already have the old interface for" <+>+ ppr (ms_mod mod_summary))+ return maybe_iface+ Nothing -> loadIface++ loadIface = do+ let iface_path = msHiFilePath mod_summary+ read_result <- readIface (ms_mod mod_summary) iface_path+ case read_result of+ Failed err -> do+ traceIf (text "FYI: cannot read old interface file:" $$ nest 4 err)+ traceHiDiffs (text "Old interface file was invalid:" $$ nest 4 err)+ return Nothing+ Succeeded iface -> do+ traceIf (text "Read the interface file" <+> text iface_path)+ return $ Just iface++ src_changed+ | gopt Opt_ForceRecomp (hsc_dflags hsc_env) = True+ | SourceModified <- src_modified = True+ | otherwise = False+ in do+ when src_changed $+ traceHiDiffs (nest 4 $ text "Source file changed or recompilation check turned off")++ case src_changed of+ -- If the source has changed and we're in interactive mode,+ -- avoid reading an interface; just return the one we might+ -- have been supplied with.+ True | not (isObjectTarget $ hscTarget dflags) ->+ return (MustCompile, maybe_iface)++ -- Try and read the old interface for the current module+ -- from the .hi file left from the last time we compiled it+ True -> do+ maybe_iface' <- getIface+ return (MustCompile, maybe_iface')++ False -> do+ maybe_iface' <- getIface+ case maybe_iface' of+ -- We can't retrieve the iface+ Nothing -> return (MustCompile, Nothing)++ -- We have got the old iface; check its versions+ -- even in the SourceUnmodifiedAndStable case we+ -- should check versions because some packages+ -- might have changed or gone away.+ Just iface -> checkVersions hsc_env mod_summary iface++-- | Check if a module is still the same 'version'.+--+-- This function is called in the recompilation checker after we have+-- determined that the module M being checked hasn't had any changes+-- to its source file since we last compiled M. So at this point in general+-- two things may have changed that mean we should recompile M:+-- * The interface export by a dependency of M has changed.+-- * The compiler flags specified this time for M have changed+-- in a manner that is significant for recompilation.+-- We return not just if we should recompile the object file but also+-- if we should rebuild the interface file.+checkVersions :: HscEnv+ -> ModSummary+ -> ModIface -- Old interface+ -> IfG (RecompileRequired, Maybe ModIface)+checkVersions hsc_env mod_summary iface+ = do { traceHiDiffs (text "Considering whether compilation is required for" <+>+ ppr (mi_module iface) <> colon)++ -- readIface will have verified that the InstalledUnitId matches,+ -- but we ALSO must make sure the instantiation matches up. See+ -- test case bkpcabal04!+ ; if moduleUnitId (mi_module iface) /= thisPackage (hsc_dflags hsc_env)+ then return (RecompBecause "-this-unit-id changed", Nothing) else do {+ ; recomp <- checkFlagHash hsc_env iface+ ; if recompileRequired recomp then return (recomp, Nothing) else do {+ ; recomp <- checkMergedSignatures mod_summary iface+ ; if recompileRequired recomp then return (recomp, Nothing) else do {+ ; recomp <- checkHsig mod_summary iface+ ; if recompileRequired recomp then return (recomp, Nothing) else do {+ ; recomp <- checkDependencies hsc_env mod_summary iface+ ; if recompileRequired recomp then return (recomp, Just iface) else do {++ -- Source code unchanged and no errors yet... carry on+ --+ -- First put the dependent-module info, read from the old+ -- interface, into the envt, so that when we look for+ -- interfaces we look for the right one (.hi or .hi-boot)+ --+ -- It's just temporary because either the usage check will succeed+ -- (in which case we are done with this module) or it'll fail (in which+ -- case we'll compile the module from scratch anyhow).+ --+ -- We do this regardless of compilation mode, although in --make mode+ -- all the dependent modules should be in the HPT already, so it's+ -- quite redundant+ ; updateEps_ $ \eps -> eps { eps_is_boot = mod_deps }+ ; recomp <- checkList [checkModUsage this_pkg u | u <- mi_usages iface]+ ; return (recomp, Just iface)+ }}}}}}+ where+ this_pkg = thisPackage (hsc_dflags hsc_env)+ -- This is a bit of a hack really+ mod_deps :: ModuleNameEnv (ModuleName, IsBootInterface)+ mod_deps = mkModDeps (dep_mods (mi_deps iface))++-- | Check if an hsig file needs recompilation because its+-- implementing module has changed.+checkHsig :: ModSummary -> ModIface -> IfG RecompileRequired+checkHsig mod_summary iface = do+ dflags <- getDynFlags+ let outer_mod = ms_mod mod_summary+ inner_mod = canonicalizeHomeModule dflags (moduleName outer_mod)+ MASSERT( moduleUnitId outer_mod == thisPackage dflags )+ case inner_mod == mi_semantic_module iface of+ True -> up_to_date (text "implementing module unchanged")+ False -> return (RecompBecause "implementing module changed")++-- | Check the flags haven't changed+checkFlagHash :: HscEnv -> ModIface -> IfG RecompileRequired+checkFlagHash hsc_env iface = do+ let old_hash = mi_flag_hash iface+ new_hash <- liftIO $ fingerprintDynFlags (hsc_dflags hsc_env)+ (mi_module iface)+ putNameLiterally+ case old_hash == new_hash of+ True -> up_to_date (text "Module flags unchanged")+ False -> out_of_date_hash "flags changed"+ (text " Module flags have changed")+ old_hash new_hash++-- Check that the set of signatures we are merging in match.+-- If the -unit-id flags change, this can change too.+checkMergedSignatures :: ModSummary -> ModIface -> IfG RecompileRequired+checkMergedSignatures mod_summary iface = do+ dflags <- getDynFlags+ let old_merged = sort [ mod | UsageMergedRequirement{ usg_mod = mod } <- mi_usages iface ]+ new_merged = case Map.lookup (ms_mod_name mod_summary)+ (requirementContext (pkgState dflags)) of+ Nothing -> []+ Just r -> sort $ map (indefModuleToModule dflags) r+ if old_merged == new_merged+ then up_to_date (text "signatures to merge in unchanged" $$ ppr new_merged)+ else return (RecompBecause "signatures to merge in changed")++-- If the direct imports of this module are resolved to targets that+-- are not among the dependencies of the previous interface file,+-- then we definitely need to recompile. This catches cases like+-- - an exposed package has been upgraded+-- - we are compiling with different package flags+-- - a home module that was shadowing a package module has been removed+-- - a new home module has been added that shadows a package module+-- See bug #1372.+--+-- Returns (RecompBecause <textual reason>) if recompilation is required.+checkDependencies :: HscEnv -> ModSummary -> ModIface -> IfG RecompileRequired+checkDependencies hsc_env summary iface+ = checkList (map dep_missing (ms_imps summary ++ ms_srcimps summary))+ where+ prev_dep_mods = dep_mods (mi_deps iface)+ prev_dep_pkgs = dep_pkgs (mi_deps iface)++ this_pkg = thisPackage (hsc_dflags hsc_env)++ dep_missing (mb_pkg, L _ mod) = do+ find_res <- liftIO $ findImportedModule hsc_env mod (mb_pkg)+ let reason = moduleNameString mod ++ " changed"+ case find_res of+ Found _ mod+ | pkg == this_pkg+ -> if moduleName mod `notElem` map fst prev_dep_mods+ then do traceHiDiffs $+ text "imported module " <> quotes (ppr mod) <>+ text " not among previous dependencies"+ return (RecompBecause reason)+ else+ return UpToDate+ | otherwise+ -> if toInstalledUnitId pkg `notElem` (map fst prev_dep_pkgs)+ then do traceHiDiffs $+ text "imported module " <> quotes (ppr mod) <>+ text " is from package " <> quotes (ppr pkg) <>+ text ", which is not among previous dependencies"+ return (RecompBecause reason)+ else+ return UpToDate+ where pkg = moduleUnitId mod+ _otherwise -> return (RecompBecause reason)++needInterface :: Module -> (ModIface -> IfG RecompileRequired)+ -> IfG RecompileRequired+needInterface mod continue+ = do -- Load the imported interface if possible+ let doc_str = sep [text "need version info for", ppr mod]+ traceHiDiffs (text "Checking usages for module" <+> ppr mod)++ mb_iface <- loadInterface doc_str mod ImportBySystem+ -- Load the interface, but don't complain on failure;+ -- Instead, get an Either back which we can test++ case mb_iface of+ Failed _ -> do+ traceHiDiffs (sep [text "Couldn't load interface for module",+ ppr mod])+ return MustCompile+ -- Couldn't find or parse a module mentioned in the+ -- old interface file. Don't complain: it might+ -- just be that the current module doesn't need that+ -- import and it's been deleted+ Succeeded iface -> continue iface++-- | Given the usage information extracted from the old+-- M.hi file for the module being compiled, figure out+-- whether M needs to be recompiled.+checkModUsage :: UnitId -> Usage -> IfG RecompileRequired+checkModUsage _this_pkg UsagePackageModule{+ usg_mod = mod,+ usg_mod_hash = old_mod_hash }+ = needInterface mod $ \iface -> do+ let reason = moduleNameString (moduleName mod) ++ " changed"+ checkModuleFingerprint reason old_mod_hash (mi_mod_hash iface)+ -- We only track the ABI hash of package modules, rather than+ -- individual entity usages, so if the ABI hash changes we must+ -- recompile. This is safe but may entail more recompilation when+ -- a dependent package has changed.++checkModUsage _ UsageMergedRequirement{ usg_mod = mod, usg_mod_hash = old_mod_hash }+ = needInterface mod $ \iface -> do+ let reason = moduleNameString (moduleName mod) ++ " changed (raw)"+ checkModuleFingerprint reason old_mod_hash (mi_mod_hash iface)++checkModUsage this_pkg UsageHomeModule{+ usg_mod_name = mod_name,+ usg_mod_hash = old_mod_hash,+ usg_exports = maybe_old_export_hash,+ usg_entities = old_decl_hash }+ = do+ let mod = mkModule this_pkg mod_name+ needInterface mod $ \iface -> do++ let+ new_mod_hash = mi_mod_hash iface+ new_decl_hash = mi_hash_fn iface+ new_export_hash = mi_exp_hash iface++ reason = moduleNameString mod_name ++ " changed"++ -- CHECK MODULE+ recompile <- checkModuleFingerprint reason old_mod_hash new_mod_hash+ if not (recompileRequired recompile)+ then return UpToDate+ else do++ -- CHECK EXPORT LIST+ checkMaybeHash reason maybe_old_export_hash new_export_hash+ (text " Export list changed") $ do++ -- CHECK ITEMS ONE BY ONE+ recompile <- checkList [ checkEntityUsage reason new_decl_hash u+ | u <- old_decl_hash]+ if recompileRequired recompile+ then return recompile -- This one failed, so just bail out now+ else up_to_date (text " Great! The bits I use are up to date")+++checkModUsage _this_pkg UsageFile{ usg_file_path = file,+ usg_file_hash = old_hash } =+ liftIO $+ handleIO handle $ do+ new_hash <- getFileHash file+ if (old_hash /= new_hash)+ then return recomp+ else return UpToDate+ where+ recomp = RecompBecause (file ++ " changed")+ handle =+#ifdef DEBUG+ \e -> pprTrace "UsageFile" (text (show e)) $ return recomp+#else+ \_ -> return recomp -- if we can't find the file, just recompile, don't fail+#endif++------------------------+checkModuleFingerprint :: String -> Fingerprint -> Fingerprint+ -> IfG RecompileRequired+checkModuleFingerprint reason old_mod_hash new_mod_hash+ | new_mod_hash == old_mod_hash+ = up_to_date (text "Module fingerprint unchanged")++ | otherwise+ = out_of_date_hash reason (text " Module fingerprint has changed")+ old_mod_hash new_mod_hash++------------------------+checkMaybeHash :: String -> Maybe Fingerprint -> Fingerprint -> SDoc+ -> IfG RecompileRequired -> IfG RecompileRequired+checkMaybeHash reason maybe_old_hash new_hash doc continue+ | Just hash <- maybe_old_hash, hash /= new_hash+ = out_of_date_hash reason doc hash new_hash+ | otherwise+ = continue++------------------------+checkEntityUsage :: String+ -> (OccName -> Maybe (OccName, Fingerprint))+ -> (OccName, Fingerprint)+ -> IfG RecompileRequired+checkEntityUsage reason new_hash (name,old_hash)+ = case new_hash name of++ Nothing -> -- We used it before, but it ain't there now+ out_of_date reason (sep [text "No longer exported:", ppr name])++ Just (_, new_hash) -- It's there, but is it up to date?+ | new_hash == old_hash -> do traceHiDiffs (text " Up to date" <+> ppr name <+> parens (ppr new_hash))+ return UpToDate+ | otherwise -> out_of_date_hash reason (text " Out of date:" <+> ppr name)+ old_hash new_hash++up_to_date :: SDoc -> IfG RecompileRequired+up_to_date msg = traceHiDiffs msg >> return UpToDate++out_of_date :: String -> SDoc -> IfG RecompileRequired+out_of_date reason msg = traceHiDiffs msg >> return (RecompBecause reason)++out_of_date_hash :: String -> SDoc -> Fingerprint -> Fingerprint -> IfG RecompileRequired+out_of_date_hash reason msg old_hash new_hash+ = out_of_date reason (hsep [msg, ppr old_hash, text "->", ppr new_hash])++----------------------+checkList :: [IfG RecompileRequired] -> IfG RecompileRequired+-- This helper is used in two places+checkList [] = return UpToDate+checkList (check:checks) = do recompile <- check+ if recompileRequired recompile+ then return recompile+ else checkList checks++{-+************************************************************************+* *+ Converting things to their Iface equivalents+* *+************************************************************************+-}++tyThingToIfaceDecl :: TyThing -> IfaceDecl+tyThingToIfaceDecl (AnId id) = idToIfaceDecl id+tyThingToIfaceDecl (ATyCon tycon) = snd (tyConToIfaceDecl emptyTidyEnv tycon)+tyThingToIfaceDecl (ACoAxiom ax) = coAxiomToIfaceDecl ax+tyThingToIfaceDecl (AConLike cl) = case cl of+ RealDataCon dc -> dataConToIfaceDecl dc -- for ppr purposes only+ PatSynCon ps -> patSynToIfaceDecl ps++--------------------------+idToIfaceDecl :: Id -> IfaceDecl+-- The Id is already tidied, so that locally-bound names+-- (lambdas, for-alls) already have non-clashing OccNames+-- We can't tidy it here, locally, because it may have+-- free variables in its type or IdInfo+idToIfaceDecl id+ = IfaceId { ifName = getName id,+ ifType = toIfaceType (idType id),+ ifIdDetails = toIfaceIdDetails (idDetails id),+ ifIdInfo = toIfaceIdInfo (idInfo id) }++--------------------------+dataConToIfaceDecl :: DataCon -> IfaceDecl+dataConToIfaceDecl dataCon+ = IfaceId { ifName = getName dataCon,+ ifType = toIfaceType (dataConUserType dataCon),+ ifIdDetails = IfVanillaId,+ ifIdInfo = NoInfo }++--------------------------+coAxiomToIfaceDecl :: CoAxiom br -> IfaceDecl+-- We *do* tidy Axioms, because they are not (and cannot+-- conveniently be) built in tidy form+coAxiomToIfaceDecl ax@(CoAxiom { co_ax_tc = tycon, co_ax_branches = branches+ , co_ax_role = role })+ = IfaceAxiom { ifName = getName ax+ , ifTyCon = toIfaceTyCon tycon+ , ifRole = role+ , ifAxBranches = map (coAxBranchToIfaceBranch tycon+ (map coAxBranchLHS branch_list))+ branch_list }+ where+ branch_list = fromBranches branches++-- 2nd parameter is the list of branch LHSs, for conversion from incompatible branches+-- to incompatible indices+-- See Note [Storing compatibility] in CoAxiom+coAxBranchToIfaceBranch :: TyCon -> [[Type]] -> CoAxBranch -> IfaceAxBranch+coAxBranchToIfaceBranch tc lhs_s+ branch@(CoAxBranch { cab_incomps = incomps })+ = (coAxBranchToIfaceBranch' tc branch) { ifaxbIncomps = iface_incomps }+ where+ iface_incomps = map (expectJust "iface_incomps"+ . (flip findIndex lhs_s+ . eqTypes)+ . coAxBranchLHS) incomps++-- use this one for standalone branches without incompatibles+coAxBranchToIfaceBranch' :: TyCon -> CoAxBranch -> IfaceAxBranch+coAxBranchToIfaceBranch' tc (CoAxBranch { cab_tvs = tvs, cab_cvs = cvs+ , cab_lhs = lhs+ , cab_roles = roles, cab_rhs = rhs })+ = IfaceAxBranch { ifaxbTyVars = toIfaceTvBndrs tidy_tvs+ , ifaxbCoVars = map toIfaceIdBndr cvs+ , ifaxbLHS = tidyToIfaceTcArgs env1 tc lhs+ , ifaxbRoles = roles+ , ifaxbRHS = tidyToIfaceType env1 rhs+ , ifaxbIncomps = [] }+ where+ (env1, tidy_tvs) = tidyTyCoVarBndrs emptyTidyEnv tvs+ -- Don't re-bind in-scope tyvars+ -- See Note [CoAxBranch type variables] in CoAxiom++-----------------+tyConToIfaceDecl :: TidyEnv -> TyCon -> (TidyEnv, IfaceDecl)+-- We *do* tidy TyCons, because they are not (and cannot+-- conveniently be) built in tidy form+-- The returned TidyEnv is the one after tidying the tyConTyVars+tyConToIfaceDecl env tycon+ | Just clas <- tyConClass_maybe tycon+ = classToIfaceDecl env clas++ | Just syn_rhs <- synTyConRhs_maybe tycon+ = ( tc_env1+ , IfaceSynonym { ifName = getName tycon,+ ifRoles = tyConRoles tycon,+ ifSynRhs = if_syn_type syn_rhs,+ ifBinders = if_binders,+ ifResKind = if_res_kind+ })++ | Just fam_flav <- famTyConFlav_maybe tycon+ = ( tc_env1+ , IfaceFamily { ifName = getName tycon,+ ifResVar = if_res_var,+ ifFamFlav = to_if_fam_flav fam_flav,+ ifBinders = if_binders,+ ifResKind = if_res_kind,+ ifFamInj = familyTyConInjectivityInfo tycon+ })++ | isAlgTyCon tycon+ = ( tc_env1+ , IfaceData { ifName = getName tycon,+ ifBinders = if_binders,+ ifResKind = if_res_kind,+ ifCType = tyConCType tycon,+ ifRoles = tyConRoles tycon,+ ifCtxt = tidyToIfaceContext tc_env1 (tyConStupidTheta tycon),+ ifCons = ifaceConDecls (algTyConRhs tycon),+ ifGadtSyntax = isGadtSyntaxTyCon tycon,+ ifParent = parent })++ | otherwise -- FunTyCon, PrimTyCon, promoted TyCon/DataCon+ -- We only convert these TyCons to IfaceTyCons when we are+ -- just about to pretty-print them, not because we are going+ -- to put them into interface files+ = ( env+ , IfaceData { ifName = getName tycon,+ ifBinders = if_binders,+ ifResKind = if_res_kind,+ ifCType = Nothing,+ ifRoles = tyConRoles tycon,+ ifCtxt = [],+ ifCons = IfDataTyCon [],+ ifGadtSyntax = False,+ ifParent = IfNoParent })+ where+ -- NOTE: Not all TyCons have `tyConTyVars` field. Forcing this when `tycon`+ -- is one of these TyCons (FunTyCon, PrimTyCon, PromotedDataCon) will cause+ -- an error.+ (tc_env1, tc_binders) = tidyTyConBinders env (tyConBinders tycon)+ tc_tyvars = binderVars tc_binders+ if_binders = toIfaceTyVarBinders tc_binders+ if_res_kind = tidyToIfaceType tc_env1 (tyConResKind tycon)+ if_syn_type ty = tidyToIfaceType tc_env1 ty+ if_res_var = getOccFS `fmap` tyConFamilyResVar_maybe tycon++ parent = case tyConFamInstSig_maybe tycon of+ Just (tc, ty, ax) -> IfDataInstance (coAxiomName ax)+ (toIfaceTyCon tc)+ (tidyToIfaceTcArgs tc_env1 tc ty)+ Nothing -> IfNoParent++ to_if_fam_flav OpenSynFamilyTyCon = IfaceOpenSynFamilyTyCon+ to_if_fam_flav (ClosedSynFamilyTyCon (Just ax))+ = IfaceClosedSynFamilyTyCon (Just (axn, ibr))+ where defs = fromBranches $ coAxiomBranches ax+ ibr = map (coAxBranchToIfaceBranch' tycon) defs+ axn = coAxiomName ax+ to_if_fam_flav (ClosedSynFamilyTyCon Nothing)+ = IfaceClosedSynFamilyTyCon Nothing+ to_if_fam_flav AbstractClosedSynFamilyTyCon = IfaceAbstractClosedSynFamilyTyCon+ to_if_fam_flav (DataFamilyTyCon {}) = IfaceDataFamilyTyCon+ to_if_fam_flav (BuiltInSynFamTyCon {}) = IfaceBuiltInSynFamTyCon++++ ifaceConDecls (NewTyCon { data_con = con }) = IfNewTyCon (ifaceConDecl con)+ ifaceConDecls (DataTyCon { data_cons = cons }) = IfDataTyCon (map ifaceConDecl cons)+ ifaceConDecls (TupleTyCon { data_con = con }) = IfDataTyCon [ifaceConDecl con]+ ifaceConDecls (SumTyCon { data_cons = cons }) = IfDataTyCon (map ifaceConDecl cons)+ ifaceConDecls AbstractTyCon = IfAbstractTyCon+ -- The AbstractTyCon case happens when a TyCon has been trimmed+ -- during tidying.+ -- Furthermore, tyThingToIfaceDecl is also used in TcRnDriver+ -- for GHCi, when browsing a module, in which case the+ -- AbstractTyCon and TupleTyCon cases are perfectly sensible.+ -- (Tuple declarations are not serialised into interface files.)++ ifaceConDecl data_con+ = IfCon { ifConName = dataConName data_con,+ ifConInfix = dataConIsInfix data_con,+ ifConWrapper = isJust (dataConWrapId_maybe data_con),+ ifConExTvs = map toIfaceForAllBndr ex_bndrs',+ ifConEqSpec = map (to_eq_spec . eqSpecPair) eq_spec,+ ifConCtxt = tidyToIfaceContext con_env2 theta,+ ifConArgTys = map (tidyToIfaceType con_env2) arg_tys,+ ifConFields = dataConFieldLabels data_con,+ ifConStricts = map (toIfaceBang con_env2)+ (dataConImplBangs data_con),+ ifConSrcStricts = map toIfaceSrcBang+ (dataConSrcBangs data_con)}+ where+ (univ_tvs, _ex_tvs, eq_spec, theta, arg_tys, _)+ = dataConFullSig data_con+ ex_bndrs = dataConExTyVarBinders data_con++ -- Tidy the univ_tvs of the data constructor to be identical+ -- to the tyConTyVars of the type constructor. This means+ -- (a) we don't need to redundantly put them into the interface file+ -- (b) when pretty-printing an Iface data declaration in H98-style syntax,+ -- we know that the type variables will line up+ -- The latter (b) is important because we pretty-print type constructors+ -- by converting to IfaceSyn and pretty-printing that+ con_env1 = (fst tc_env1, mkVarEnv (zipEqual "ifaceConDecl" univ_tvs tc_tyvars))+ -- A bit grimy, perhaps, but it's simple!++ (con_env2, ex_bndrs') = tidyTyVarBinders con_env1 ex_bndrs+ to_eq_spec (tv,ty) = (tidyTyVar con_env2 tv, tidyToIfaceType con_env2 ty)++classToIfaceDecl :: TidyEnv -> Class -> (TidyEnv, IfaceDecl)+classToIfaceDecl env clas+ = ( env1+ , IfaceClass { ifName = getName tycon,+ ifRoles = tyConRoles (classTyCon clas),+ ifBinders = toIfaceTyVarBinders tc_binders,+ ifBody = body,+ ifFDs = map toIfaceFD clas_fds })+ where+ (_, clas_fds, sc_theta, _, clas_ats, op_stuff)+ = classExtraBigSig clas+ tycon = classTyCon clas++ body | isAbstractTyCon tycon = IfAbstractClass+ | otherwise+ = IfConcreteClass {+ ifClassCtxt = tidyToIfaceContext env1 sc_theta,+ ifATs = map toIfaceAT clas_ats,+ ifSigs = map toIfaceClassOp op_stuff,+ ifMinDef = fmap getOccFS (classMinimalDef clas)+ }++ (env1, tc_binders) = tidyTyConBinders env (tyConBinders tycon)++ toIfaceAT :: ClassATItem -> IfaceAT+ toIfaceAT (ATI tc def)+ = IfaceAT if_decl (fmap (tidyToIfaceType env2 . fst) def)+ where+ (env2, if_decl) = tyConToIfaceDecl env1 tc++ toIfaceClassOp (sel_id, def_meth)+ = ASSERT( sel_tyvars == binderVars tc_binders )+ IfaceClassOp (getName sel_id)+ (tidyToIfaceType env1 op_ty)+ (fmap toDmSpec def_meth)+ where+ -- Be careful when splitting the type, because of things+ -- like class Foo a where+ -- op :: (?x :: String) => a -> a+ -- and class Baz a where+ -- op :: (Ord a) => a -> a+ (sel_tyvars, rho_ty) = splitForAllTys (idType sel_id)+ op_ty = funResultTy rho_ty++ toDmSpec :: (Name, DefMethSpec Type) -> DefMethSpec IfaceType+ toDmSpec (_, VanillaDM) = VanillaDM+ toDmSpec (_, GenericDM dm_ty) = GenericDM (tidyToIfaceType env1 dm_ty)++ toIfaceFD (tvs1, tvs2) = (map (tidyTyVar env1) tvs1+ ,map (tidyTyVar env1) tvs2)++--------------------------++tidyTyConBinder :: TidyEnv -> TyConBinder -> (TidyEnv, TyConBinder)+-- If the type variable "binder" is in scope, don't re-bind it+-- In a class decl, for example, the ATD binders mention+-- (amd must mention) the class tyvars+tidyTyConBinder env@(_, subst) tvb@(TvBndr tv vis)+ = case lookupVarEnv subst tv of+ Just tv' -> (env, TvBndr tv' vis)+ Nothing -> tidyTyVarBinder env tvb++tidyTyConBinders :: TidyEnv -> [TyConBinder] -> (TidyEnv, [TyConBinder])+tidyTyConBinders = mapAccumL tidyTyConBinder++tidyTyVar :: TidyEnv -> TyVar -> FastString+tidyTyVar (_, subst) tv = toIfaceTyVar (lookupVarEnv subst tv `orElse` tv)++--------------------------+instanceToIfaceInst :: ClsInst -> IfaceClsInst+instanceToIfaceInst (ClsInst { is_dfun = dfun_id, is_flag = oflag+ , is_cls_nm = cls_name, is_cls = cls+ , is_tcs = mb_tcs+ , is_orphan = orph })+ = ASSERT( cls_name == className cls )+ IfaceClsInst { ifDFun = dfun_name,+ ifOFlag = oflag,+ ifInstCls = cls_name,+ ifInstTys = map do_rough mb_tcs,+ ifInstOrph = orph }+ where+ do_rough Nothing = Nothing+ do_rough (Just n) = Just (toIfaceTyCon_name n)++ dfun_name = idName dfun_id+++--------------------------+famInstToIfaceFamInst :: FamInst -> IfaceFamInst+famInstToIfaceFamInst (FamInst { fi_axiom = axiom,+ fi_fam = fam,+ fi_tcs = roughs })+ = IfaceFamInst { ifFamInstAxiom = coAxiomName axiom+ , ifFamInstFam = fam+ , ifFamInstTys = map do_rough roughs+ , ifFamInstOrph = orph }+ where+ do_rough Nothing = Nothing+ do_rough (Just n) = Just (toIfaceTyCon_name n)++ fam_decl = tyConName $ coAxiomTyCon axiom+ mod = ASSERT( isExternalName (coAxiomName axiom) )+ nameModule (coAxiomName axiom)+ is_local name = nameIsLocalOrFrom mod name++ lhs_names = filterNameSet is_local (orphNamesOfCoCon axiom)++ orph | is_local fam_decl+ = NotOrphan (nameOccName fam_decl)+ | otherwise+ = chooseOrphanAnchor lhs_names++--------------------------+coreRuleToIfaceRule :: CoreRule -> IfaceRule+coreRuleToIfaceRule (BuiltinRule { ru_fn = fn})+ = pprTrace "toHsRule: builtin" (ppr fn) $+ bogusIfaceRule fn++coreRuleToIfaceRule (Rule { ru_name = name, ru_fn = fn,+ ru_act = act, ru_bndrs = bndrs,+ ru_args = args, ru_rhs = rhs,+ ru_orphan = orph, ru_auto = auto })+ = IfaceRule { ifRuleName = name, ifActivation = act,+ ifRuleBndrs = map toIfaceBndr bndrs,+ ifRuleHead = fn,+ ifRuleArgs = map do_arg args,+ ifRuleRhs = toIfaceExpr rhs,+ ifRuleAuto = auto,+ ifRuleOrph = orph }+ where+ -- For type args we must remove synonyms from the outermost+ -- level. Reason: so that when we read it back in we'll+ -- construct the same ru_rough field as we have right now;+ -- see tcIfaceRule+ do_arg (Type ty) = IfaceType (toIfaceType (deNoteType ty))+ do_arg (Coercion co) = IfaceCo (toIfaceCoercion co)+ do_arg arg = toIfaceExpr arg++bogusIfaceRule :: Name -> IfaceRule+bogusIfaceRule id_name+ = IfaceRule { ifRuleName = fsLit "bogus", ifActivation = NeverActive,+ ifRuleBndrs = [], ifRuleHead = id_name, ifRuleArgs = [],+ ifRuleRhs = IfaceExt id_name, ifRuleOrph = IsOrphan,+ ifRuleAuto = True }
+ iface/TcIface.hs view
@@ -0,0 +1,1875 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Type checking of type signatures in interface files+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE NondecreasingIndentation #-}++module TcIface (+ tcLookupImported_maybe,+ importDecl, checkWiredInTyCon, tcHiBootIface, typecheckIface,+ typecheckIfacesForMerging,+ typecheckIfaceForInstantiate,+ tcIfaceDecl, tcIfaceInst, tcIfaceFamInst, tcIfaceRules,+ tcIfaceVectInfo, tcIfaceAnnotations, tcIfaceCompleteSigs,+ tcIfaceExpr, -- Desired by HERMIT (Trac #7683)+ tcIfaceGlobal+ ) where++#include "HsVersions.h"++import TcTypeNats(typeNatCoAxiomRules)+import IfaceSyn+import LoadIface+import IfaceEnv+import BuildTyCl+import TcRnMonad+import TcType+import Type+import Coercion+import CoAxiom+import TyCoRep -- needs to build types & coercions in a knot+import HscTypes+import Annotations+import InstEnv+import FamInstEnv+import CoreSyn+import CoreUtils+import CoreUnfold+import CoreLint+import MkCore+import Id+import MkId+import IdInfo+import Class+import TyCon+import ConLike+import DataCon+import PrelNames+import TysWiredIn+import Literal+import Var+import VarEnv+import VarSet+import Name+import NameEnv+import NameSet+import OccurAnal ( occurAnalyseExpr )+import Demand+import Module+import UniqFM+import UniqSupply+import Outputable+import Maybes+import SrcLoc+import DynFlags+import Util+import FastString+import BasicTypes hiding ( SuccessFlag(..) )+import ListSetOps+import GHC.Fingerprint+import qualified BooleanFormula as BF++import Data.List+import Control.Monad+import qualified Data.Map as Map++{-+This module takes++ IfaceDecl -> TyThing+ IfaceType -> Type+ etc++An IfaceDecl is populated with RdrNames, and these are not renamed to+Names before typechecking, because there should be no scope errors etc.++ -- For (b) consider: f = \$(...h....)+ -- where h is imported, and calls f via an hi-boot file.+ -- This is bad! But it is not seen as a staging error, because h+ -- is indeed imported. We don't want the type-checker to black-hole+ -- when simplifying and compiling the splice!+ --+ -- Simple solution: discard any unfolding that mentions a variable+ -- bound in this module (and hence not yet processed).+ -- The discarding happens when forkM finds a type error.+++************************************************************************+* *+ Type-checking a complete interface+* *+************************************************************************++Suppose we discover we don't need to recompile. Then we must type+check the old interface file. This is a bit different to the+incremental type checking we do as we suck in interface files. Instead+we do things similarly as when we are typechecking source decls: we+bring into scope the type envt for the interface all at once, using a+knot. Remember, the decls aren't necessarily in dependency order --+and even if they were, the type decls might be mutually recursive.++Note [Knot-tying typecheckIface]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we are typechecking an interface A.hi, and we come across+a Name for another entity defined in A.hi. How do we get the+'TyCon', in this case? There are three cases:++ 1) tcHiBootIface in TcIface: We're typechecking an hi-boot file in+ preparation of checking if the hs file we're building+ is compatible. In this case, we want all of the internal+ TyCons to MATCH the ones that we just constructed during+ typechecking: the knot is thus tied through if_rec_types.++ 2) retypecheckLoop in GhcMake: We are retypechecking a+ mutually recursive cluster of hi files, in order to ensure+ that all of the references refer to each other correctly.+ In this case, the knot is tied through the HPT passed in,+ which contains all of the interfaces we are in the process+ of typechecking.++ 3) genModDetails in HscMain: We are typechecking an+ old interface to generate the ModDetails. In this case,+ we do the same thing as (2) and pass in an HPT with+ the HomeModInfo being generated to tie knots.++The upshot is that the CLIENT of this function is responsible+for making sure that the knot is tied correctly. If you don't,+then you'll get a message saying that we couldn't load the+declaration you wanted.++BTW, in one-shot mode we never call typecheckIface; instead,+loadInterface handles type-checking interface. In that case,+knots are tied through the EPS. No problem!+-}++-- Clients of this function be careful, see Note [Knot-tying typecheckIface]+typecheckIface :: ModIface -- Get the decls from here+ -> IfG ModDetails+typecheckIface iface+ = initIfaceLcl (mi_semantic_module iface) (text "typecheckIface") (mi_boot iface) $ do+ { -- Get the right set of decls and rules. If we are compiling without -O+ -- we discard pragmas before typechecking, so that we don't "see"+ -- information that we shouldn't. From a versioning point of view+ -- It's not actually *wrong* to do so, but in fact GHCi is unable+ -- to handle unboxed tuples, so it must not see unfoldings.+ ignore_prags <- goptM Opt_IgnoreInterfacePragmas++ -- Typecheck the decls. This is done lazily, so that the knot-tying+ -- within this single module works out right. It's the callers+ -- job to make sure the knot is tied.+ ; names_w_things <- loadDecls ignore_prags (mi_decls iface)+ ; let type_env = mkNameEnv names_w_things++ -- Now do those rules, instances and annotations+ ; insts <- mapM tcIfaceInst (mi_insts iface)+ ; fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface)+ ; rules <- tcIfaceRules ignore_prags (mi_rules iface)+ ; anns <- tcIfaceAnnotations (mi_anns iface)++ -- Vectorisation information+ ; vect_info <- tcIfaceVectInfo (mi_semantic_module iface) type_env (mi_vect_info iface)++ -- Exports+ ; exports <- ifaceExportNames (mi_exports iface)++ -- Complete Sigs+ ; complete_sigs <- tcIfaceCompleteSigs (mi_complete_sigs iface)++ -- Finished+ ; traceIf (vcat [text "Finished typechecking interface for" <+> ppr (mi_module iface),+ -- Careful! If we tug on the TyThing thunks too early+ -- we'll infinite loop with hs-boot. See #10083 for+ -- an example where this would cause non-termination.+ text "Type envt:" <+> ppr (map fst names_w_things)])+ ; return $ ModDetails { md_types = type_env+ , md_insts = insts+ , md_fam_insts = fam_insts+ , md_rules = rules+ , md_anns = anns+ , md_vect_info = vect_info+ , md_exports = exports+ , md_complete_sigs = complete_sigs+ }+ }++{-+************************************************************************+* *+ Typechecking for merging+* *+************************************************************************+-}++-- | Returns true if an 'IfaceDecl' is for @data T@ (an abstract data type)+isAbstractIfaceDecl :: IfaceDecl -> Bool+isAbstractIfaceDecl IfaceData{ ifCons = IfAbstractTyCon } = True+isAbstractIfaceDecl IfaceClass{ ifBody = IfAbstractClass } = True+isAbstractIfaceDecl IfaceFamily{ ifFamFlav = IfaceAbstractClosedSynFamilyTyCon } = True+isAbstractIfaceDecl _ = False++ifMaybeRoles :: IfaceDecl -> Maybe [Role]+ifMaybeRoles IfaceData { ifRoles = rs } = Just rs+ifMaybeRoles IfaceSynonym { ifRoles = rs } = Just rs+ifMaybeRoles IfaceClass { ifRoles = rs } = Just rs+ifMaybeRoles _ = Nothing++-- | Merge two 'IfaceDecl's together, preferring a non-abstract one. If+-- both are non-abstract we pick one arbitrarily (and check for consistency+-- later.)+mergeIfaceDecl :: IfaceDecl -> IfaceDecl -> IfaceDecl+mergeIfaceDecl d1 d2+ | isAbstractIfaceDecl d1 = d2 `withRolesFrom` d1+ | isAbstractIfaceDecl d2 = d1 `withRolesFrom` d2+ | IfaceClass{ ifBody = IfConcreteClass { ifSigs = ops1, ifMinDef = bf1 } } <- d1+ , IfaceClass{ ifBody = IfConcreteClass { ifSigs = ops2, ifMinDef = bf2 } } <- d2+ = let ops = nameEnvElts $+ plusNameEnv_C mergeIfaceClassOp+ (mkNameEnv [ (n, op) | op@(IfaceClassOp n _ _) <- ops1 ])+ (mkNameEnv [ (n, op) | op@(IfaceClassOp n _ _) <- ops2 ])+ in d1 { ifBody = (ifBody d1) {+ ifSigs = ops,+ ifMinDef = BF.mkOr [noLoc bf1, noLoc bf2]+ }+ } `withRolesFrom` d2+ -- It doesn't matter; we'll check for consistency later when+ -- we merge, see 'mergeSignatures'+ | otherwise = d1 `withRolesFrom` d2++-- Note [Role merging]+-- ~~~~~~~~~~~~~~~~~~~+-- First, why might it be necessary to do a non-trivial role+-- merge? It may rescue a merge that might otherwise fail:+--+-- signature A where+-- type role T nominal representational+-- data T a b+--+-- signature A where+-- type role T representational nominal+-- data T a b+--+-- A module that defines T as representational in both arguments+-- would successfully fill both signatures, so it would be better+-- if we merged the roles of these types in some nontrivial+-- way.+--+-- However, we have to be very careful about how we go about+-- doing this, because role subtyping is *conditional* on+-- the supertype being NOT representationally injective, e.g.,+-- if we have instead:+--+-- signature A where+-- type role T nominal representational+-- data T a b = T a b+--+-- signature A where+-- type role T representational nominal+-- data T a b = T a b+--+-- Should we merge the definitions of T so that the roles are R/R (or N/N)?+-- Absolutely not: neither resulting type is a subtype of the original+-- types (see Note [Role subtyping]), because data is not representationally+-- injective.+--+-- Thus, merging only occurs when BOTH TyCons in question are+-- representationally injective. If they're not, no merge.++withRolesFrom :: IfaceDecl -> IfaceDecl -> IfaceDecl+d1 `withRolesFrom` d2+ | Just roles1 <- ifMaybeRoles d1+ , Just roles2 <- ifMaybeRoles d2+ , not (isRepInjectiveIfaceDecl d1 || isRepInjectiveIfaceDecl d2)+ = d1 { ifRoles = mergeRoles roles1 roles2 }+ | otherwise = d1+ where+ mergeRoles roles1 roles2 = zipWith max roles1 roles2++isRepInjectiveIfaceDecl :: IfaceDecl -> Bool+isRepInjectiveIfaceDecl IfaceData{ ifCons = IfDataTyCon _ } = True+isRepInjectiveIfaceDecl IfaceFamily{ ifFamFlav = IfaceDataFamilyTyCon } = True+isRepInjectiveIfaceDecl _ = False++mergeIfaceClassOp :: IfaceClassOp -> IfaceClassOp -> IfaceClassOp+mergeIfaceClassOp op1@(IfaceClassOp _ _ (Just _)) _ = op1+mergeIfaceClassOp _ op2 = op2++-- | Merge two 'OccEnv's of 'IfaceDecl's by 'OccName'.+mergeIfaceDecls :: OccEnv IfaceDecl -> OccEnv IfaceDecl -> OccEnv IfaceDecl+mergeIfaceDecls = plusOccEnv_C mergeIfaceDecl++-- | This is a very interesting function. Like typecheckIface, we want+-- to type check an interface file into a ModDetails. However, the use-case+-- for these ModDetails is different: we want to compare all of the+-- ModDetails to ensure they define compatible declarations, and then+-- merge them together. So in particular, we have to take a different+-- strategy for knot-tying: we first speculatively merge the declarations+-- to get the "base" truth for what we believe the types will be+-- (this is "type computation.") Then we read everything in relative+-- to this truth and check for compatibility.+--+-- During the merge process, we may need to nondeterministically+-- pick a particular declaration to use, if multiple signatures define+-- the declaration ('mergeIfaceDecl'). If, for all choices, there+-- are no type synonym cycles in the resulting merged graph, then+-- we can show that our choice cannot matter. Consider the+-- set of entities which the declarations depend on: by assumption+-- of acyclicity, we can assume that these have already been shown to be equal+-- to each other (otherwise merging will fail). Then it must+-- be the case that all candidate declarations here are type-equal+-- (the choice doesn't matter) or there is an inequality (in which+-- case merging will fail.)+--+-- Unfortunately, the choice can matter if there is a cycle. Consider the+-- following merge:+--+-- signature H where { type A = C; type B = A; data C }+-- signature H where { type A = (); data B; type C = B }+--+-- If we pick @type A = C@ as our representative, there will be+-- a cycle and merging will fail. But if we pick @type A = ()@ as+-- our representative, no cycle occurs, and we instead conclude+-- that all of the types are unit. So it seems that we either+-- (a) need a stronger acyclicity check which considers *all*+-- possible choices from a merge, or (b) we must find a selection+-- of declarations which is acyclic, and show that this is always+-- the "best" choice we could have made (ezyang conjectures this+-- is the case but does not have a proof). For now this is+-- not implemented.+--+-- It's worth noting that at the moment, a data constructor and a+-- type synonym are never compatible. Consider:+--+-- signature H where { type Int=C; type B = Int; data C = Int}+-- signature H where { export Prelude.Int; data B; type C = B; }+--+-- This will be rejected, because the reexported Int in the second+-- signature (a proper data type) is never considered equal to a+-- type synonym. Perhaps this should be relaxed, where a type synonym+-- in a signature is considered implemented by a data type declaration+-- which matches the reference of the type synonym.+typecheckIfacesForMerging :: Module -> [ModIface] -> IORef TypeEnv -> IfM lcl (TypeEnv, [ModDetails])+typecheckIfacesForMerging mod ifaces tc_env_var =+ -- cannot be boot (False)+ initIfaceLcl mod (text "typecheckIfacesForMerging") False $ do+ ignore_prags <- goptM Opt_IgnoreInterfacePragmas+ -- Build the initial environment+ -- NB: Don't include dfuns here, because we don't want to+ -- serialize them out. See Note [rnIfaceNeverExported] in RnModIface+ -- NB: But coercions are OK, because they will have the right OccName.+ let mk_decl_env decls+ = mkOccEnv [ (getOccName decl, decl)+ | decl <- decls+ , case decl of+ IfaceId { ifIdDetails = IfDFunId } -> False -- exclude DFuns+ _ -> True ]+ decl_envs = map (mk_decl_env . map snd . mi_decls) ifaces+ :: [OccEnv IfaceDecl]+ decl_env = foldl' mergeIfaceDecls emptyOccEnv decl_envs+ :: OccEnv IfaceDecl+ -- TODO: change loadDecls to accept w/o Fingerprint+ names_w_things <- loadDecls ignore_prags (map (\x -> (fingerprint0, x))+ (occEnvElts decl_env))+ let global_type_env = mkNameEnv names_w_things+ writeMutVar tc_env_var global_type_env++ -- OK, now typecheck each ModIface using this environment+ details <- forM ifaces $ \iface -> do+ -- See Note [Resolving never-exported Names in TcIface]+ type_env <- fixM $ \type_env -> do+ setImplicitEnvM type_env $ do+ decls <- loadDecls ignore_prags (mi_decls iface)+ return (mkNameEnv decls)+ -- But note that we use this type_env to typecheck references to DFun+ -- in 'IfaceInst'+ setImplicitEnvM type_env $ do+ insts <- mapM tcIfaceInst (mi_insts iface)+ fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface)+ rules <- tcIfaceRules ignore_prags (mi_rules iface)+ anns <- tcIfaceAnnotations (mi_anns iface)+ vect_info <- tcIfaceVectInfo (mi_semantic_module iface) type_env (mi_vect_info iface)+ exports <- ifaceExportNames (mi_exports iface)+ complete_sigs <- tcIfaceCompleteSigs (mi_complete_sigs iface)+ return $ ModDetails { md_types = type_env+ , md_insts = insts+ , md_fam_insts = fam_insts+ , md_rules = rules+ , md_anns = anns+ , md_vect_info = vect_info+ , md_exports = exports+ , md_complete_sigs = complete_sigs+ }+ return (global_type_env, details)++-- | Typecheck a signature 'ModIface' under the assumption that we have+-- instantiated it under some implementation (recorded in 'mi_semantic_module')+-- and want to check if the implementation fills the signature.+--+-- This needs to operate slightly differently than 'typecheckIface'+-- because (1) we have a 'NameShape', from the exports of the+-- implementing module, which we will use to give our top-level+-- declarations the correct 'Name's even when the implementor+-- provided them with a reexport, and (2) we have to deal with+-- DFun silliness (see Note [rnIfaceNeverExported])+typecheckIfaceForInstantiate :: NameShape -> ModIface -> IfM lcl ModDetails+typecheckIfaceForInstantiate nsubst iface =+ initIfaceLclWithSubst (mi_semantic_module iface)+ (text "typecheckIfaceForInstantiate")+ (mi_boot iface) nsubst $ do+ ignore_prags <- goptM Opt_IgnoreInterfacePragmas+ -- See Note [Resolving never-exported Names in TcIface]+ type_env <- fixM $ \type_env -> do+ setImplicitEnvM type_env $ do+ decls <- loadDecls ignore_prags (mi_decls iface)+ return (mkNameEnv decls)+ -- See Note [rnIfaceNeverExported]+ setImplicitEnvM type_env $ do+ insts <- mapM tcIfaceInst (mi_insts iface)+ fam_insts <- mapM tcIfaceFamInst (mi_fam_insts iface)+ rules <- tcIfaceRules ignore_prags (mi_rules iface)+ anns <- tcIfaceAnnotations (mi_anns iface)+ vect_info <- tcIfaceVectInfo (mi_semantic_module iface) type_env (mi_vect_info iface)+ exports <- ifaceExportNames (mi_exports iface)+ complete_sigs <- tcIfaceCompleteSigs (mi_complete_sigs iface)+ return $ ModDetails { md_types = type_env+ , md_insts = insts+ , md_fam_insts = fam_insts+ , md_rules = rules+ , md_anns = anns+ , md_vect_info = vect_info+ , md_exports = exports+ , md_complete_sigs = complete_sigs+ }++-- Note [Resolving never-exported Names in TcIface]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- For the high-level overview, see+-- Note [Handling never-exported TyThings under Backpack]+--+-- As described in 'typecheckIfacesForMerging', the splendid innovation+-- of signature merging is to rewrite all Names in each of the signatures+-- we are merging together to a pre-merged structure; this is the key+-- ingredient that lets us solve some problems when merging type+-- synonyms.+--+-- However, when a 'Name' refers to a NON-exported entity, as is the+-- case with the DFun of a ClsInst, or a CoAxiom of a type family,+-- this strategy causes problems: if we pick one and rewrite all+-- references to a shared 'Name', we will accidentally fail to check+-- if the DFun or CoAxioms are compatible, as they will never be+-- checked--only exported entities are checked for compatibility,+-- and a non-exported TyThing is checked WHEN we are checking the+-- ClsInst or type family for compatibility in checkBootDeclM.+-- By virtue of the fact that everything's been pointed to the merged+-- declaration, you'll never notice there's a difference even if there+-- is one.+--+-- Fortunately, there are only a few places in the interface declarations+-- where this can occur, so we replace those calls with 'tcIfaceImplicit',+-- which will consult a local TypeEnv that records any never-exported+-- TyThings which we should wire up with.+--+-- Note that we actually knot-tie this local TypeEnv (the 'fixM'), because a+-- type family can refer to a coercion axiom, all of which are done in one go+-- when we typecheck 'mi_decls'. An alternate strategy would be to typecheck+-- coercions first before type families, but that seemed more fragile.+--++{-+************************************************************************+* *+ Type and class declarations+* *+************************************************************************+-}++tcHiBootIface :: HscSource -> Module -> TcRn SelfBootInfo+-- Load the hi-boot iface for the module being compiled,+-- if it indeed exists in the transitive closure of imports+-- Return the ModDetails; Nothing if no hi-boot iface+tcHiBootIface hsc_src mod+ | HsBootFile <- hsc_src -- Already compiling a hs-boot file+ = return NoSelfBoot+ | otherwise+ = do { traceIf (text "loadHiBootInterface" <+> ppr mod)++ ; mode <- getGhcMode+ ; if not (isOneShot mode)+ -- In --make and interactive mode, if this module has an hs-boot file+ -- we'll have compiled it already, and it'll be in the HPT+ --+ -- We check wheher the interface is a *boot* interface.+ -- It can happen (when using GHC from Visual Studio) that we+ -- compile a module in TypecheckOnly mode, with a stable,+ -- fully-populated HPT. In that case the boot interface isn't there+ -- (it's been replaced by the mother module) so we can't check it.+ -- And that's fine, because if M's ModInfo is in the HPT, then+ -- it's been compiled once, and we don't need to check the boot iface+ then do { hpt <- getHpt+ ; case lookupHpt hpt (moduleName mod) of+ Just info | mi_boot (hm_iface info)+ -> mkSelfBootInfo (hm_iface info) (hm_details info)+ _ -> return NoSelfBoot }+ else do++ -- OK, so we're in one-shot mode.+ -- Re #9245, we always check if there is an hi-boot interface+ -- to check consistency against, rather than just when we notice+ -- that an hi-boot is necessary due to a circular import.+ { read_result <- findAndReadIface+ need (fst (splitModuleInsts mod)) mod+ True -- Hi-boot file++ ; case read_result of {+ Succeeded (iface, _path) -> do { tc_iface <- initIfaceTcRn $ typecheckIface iface+ ; mkSelfBootInfo iface tc_iface } ;+ Failed err ->++ -- There was no hi-boot file. But if there is circularity in+ -- the module graph, there really should have been one.+ -- Since we've read all the direct imports by now,+ -- eps_is_boot will record if any of our imports mention the+ -- current module, which either means a module loop (not+ -- a SOURCE import) or that our hi-boot file has mysteriously+ -- disappeared.+ do { eps <- getEps+ ; case lookupUFM (eps_is_boot eps) (moduleName mod) of+ Nothing -> return NoSelfBoot -- The typical case++ Just (_, False) -> failWithTc moduleLoop+ -- Someone below us imported us!+ -- This is a loop with no hi-boot in the way++ Just (_mod, True) -> failWithTc (elaborate err)+ -- The hi-boot file has mysteriously disappeared.+ }}}}+ where+ need = text "Need the hi-boot interface for" <+> ppr mod+ <+> text "to compare against the Real Thing"++ moduleLoop = text "Circular imports: module" <+> quotes (ppr mod)+ <+> text "depends on itself"++ elaborate err = hang (text "Could not find hi-boot interface for" <+>+ quotes (ppr mod) <> colon) 4 err+++mkSelfBootInfo :: ModIface -> ModDetails -> TcRn SelfBootInfo+mkSelfBootInfo iface mds+ = do -- NB: This is computed DIRECTLY from the ModIface rather+ -- than from the ModDetails, so that we can query 'sb_tcs'+ -- WITHOUT forcing the contents of the interface.+ let tcs = map ifName+ . filter isIfaceTyCon+ . map snd+ $ mi_decls iface+ return $ SelfBoot { sb_mds = mds+ , sb_tcs = mkNameSet tcs }+ where+ -- | Retuerns @True@ if, when you call 'tcIfaceDecl' on+ -- this 'IfaceDecl', an ATyCon would be returned.+ -- NB: This code assumes that a TyCon cannot be implicit.+ isIfaceTyCon IfaceId{} = False+ isIfaceTyCon IfaceData{} = True+ isIfaceTyCon IfaceSynonym{} = True+ isIfaceTyCon IfaceFamily{} = True+ isIfaceTyCon IfaceClass{} = True+ isIfaceTyCon IfaceAxiom{} = False+ isIfaceTyCon IfacePatSyn{} = False++{-+************************************************************************+* *+ Type and class declarations+* *+************************************************************************++When typechecking a data type decl, we *lazily* (via forkM) typecheck+the constructor argument types. This is in the hope that we may never+poke on those argument types, and hence may never need to load the+interface files for types mentioned in the arg types.++E.g.+ data Foo.S = MkS Baz.T+Maybe we can get away without even loading the interface for Baz!++This is not just a performance thing. Suppose we have+ data Foo.S = MkS Baz.T+ data Baz.T = MkT Foo.S+(in different interface files, of course).+Now, first we load and typecheck Foo.S, and add it to the type envt.+If we do explore MkS's argument, we'll load and typecheck Baz.T.+If we explore MkT's argument we'll find Foo.S already in the envt.++If we typechecked constructor args eagerly, when loading Foo.S we'd try to+typecheck the type Baz.T. So we'd fault in Baz.T... and then need Foo.S...+which isn't done yet.++All very cunning. However, there is a rather subtle gotcha which bit+me when developing this stuff. When we typecheck the decl for S, we+extend the type envt with S, MkS, and all its implicit Ids. Suppose+(a bug, but it happened) that the list of implicit Ids depended in+turn on the constructor arg types. Then the following sequence of+events takes place:+ * we build a thunk <t> for the constructor arg tys+ * we build a thunk for the extended type environment (depends on <t>)+ * we write the extended type envt into the global EPS mutvar++Now we look something up in the type envt+ * that pulls on <t>+ * which reads the global type envt out of the global EPS mutvar+ * but that depends in turn on <t>++It's subtle, because, it'd work fine if we typechecked the constructor args+eagerly -- they don't need the extended type envt. They just get the extended+type envt by accident, because they look at it later.++What this means is that the implicitTyThings MUST NOT DEPEND on any of+the forkM stuff.+-}++tcIfaceDecl :: Bool -- ^ True <=> discard IdInfo on IfaceId bindings+ -> IfaceDecl+ -> IfL TyThing+tcIfaceDecl = tc_iface_decl Nothing++tc_iface_decl :: Maybe Class -- ^ For associated type/data family declarations+ -> Bool -- ^ True <=> discard IdInfo on IfaceId bindings+ -> IfaceDecl+ -> IfL TyThing+tc_iface_decl _ ignore_prags (IfaceId {ifName = name, ifType = iface_type,+ ifIdDetails = details, ifIdInfo = info})+ = do { ty <- tcIfaceType iface_type+ ; details <- tcIdDetails ty details+ ; info <- tcIdInfo ignore_prags name ty info+ ; return (AnId (mkGlobalId details name ty info)) }++tc_iface_decl _ _ (IfaceData {ifName = tc_name,+ ifCType = cType,+ ifBinders = binders,+ ifResKind = res_kind,+ ifRoles = roles,+ ifCtxt = ctxt, ifGadtSyntax = gadt_syn,+ ifCons = rdr_cons,+ ifParent = mb_parent })+ = bindIfaceTyConBinders_AT binders $ \ binders' -> do+ { res_kind' <- tcIfaceType res_kind++ ; tycon <- fixM $ \ tycon -> do+ { stupid_theta <- tcIfaceCtxt ctxt+ ; parent' <- tc_parent tc_name mb_parent+ ; cons <- tcIfaceDataCons tc_name tycon binders' rdr_cons+ ; return (mkAlgTyCon tc_name binders' res_kind'+ roles cType stupid_theta+ cons parent' gadt_syn) }+ ; traceIf (text "tcIfaceDecl4" <+> ppr tycon)+ ; return (ATyCon tycon) }+ where+ tc_parent :: Name -> IfaceTyConParent -> IfL AlgTyConFlav+ tc_parent tc_name IfNoParent+ = do { tc_rep_name <- newTyConRepName tc_name+ ; return (VanillaAlgTyCon tc_rep_name) }+ tc_parent _ (IfDataInstance ax_name _ arg_tys)+ = do { ax <- tcIfaceCoAxiom ax_name+ ; let fam_tc = coAxiomTyCon ax+ ax_unbr = toUnbranchedAxiom ax+ ; lhs_tys <- tcIfaceTcArgs arg_tys+ ; return (DataFamInstTyCon ax_unbr fam_tc lhs_tys) }++tc_iface_decl _ _ (IfaceSynonym {ifName = tc_name,+ ifRoles = roles,+ ifSynRhs = rhs_ty,+ ifBinders = binders,+ ifResKind = res_kind })+ = bindIfaceTyConBinders_AT binders $ \ binders' -> do+ { res_kind' <- tcIfaceType res_kind -- Note [Synonym kind loop]+ ; rhs <- forkM (mk_doc tc_name) $+ tcIfaceType rhs_ty+ ; let tycon = buildSynTyCon tc_name binders' res_kind' roles rhs+ ; return (ATyCon tycon) }+ where+ mk_doc n = text "Type synonym" <+> ppr n++tc_iface_decl parent _ (IfaceFamily {ifName = tc_name,+ ifFamFlav = fam_flav,+ ifBinders = binders,+ ifResKind = res_kind,+ ifResVar = res, ifFamInj = inj })+ = bindIfaceTyConBinders_AT binders $ \ binders' -> do+ { res_kind' <- tcIfaceType res_kind -- Note [Synonym kind loop]+ ; rhs <- forkM (mk_doc tc_name) $+ tc_fam_flav tc_name fam_flav+ ; res_name <- traverse (newIfaceName . mkTyVarOccFS) res+ ; let tycon = mkFamilyTyCon tc_name binders' res_kind' res_name rhs parent inj+ ; return (ATyCon tycon) }+ where+ mk_doc n = text "Type synonym" <+> ppr n++ tc_fam_flav :: Name -> IfaceFamTyConFlav -> IfL FamTyConFlav+ tc_fam_flav tc_name IfaceDataFamilyTyCon+ = do { tc_rep_name <- newTyConRepName tc_name+ ; return (DataFamilyTyCon tc_rep_name) }+ tc_fam_flav _ IfaceOpenSynFamilyTyCon= return OpenSynFamilyTyCon+ tc_fam_flav _ (IfaceClosedSynFamilyTyCon mb_ax_name_branches)+ = do { ax <- traverse (tcIfaceCoAxiom . fst) mb_ax_name_branches+ ; return (ClosedSynFamilyTyCon ax) }+ tc_fam_flav _ IfaceAbstractClosedSynFamilyTyCon+ = return AbstractClosedSynFamilyTyCon+ tc_fam_flav _ IfaceBuiltInSynFamTyCon+ = pprPanic "tc_iface_decl"+ (text "IfaceBuiltInSynFamTyCon in interface file")++tc_iface_decl _parent _ignore_prags+ (IfaceClass {ifName = tc_name,+ ifRoles = roles,+ ifBinders = binders,+ ifFDs = rdr_fds,+ ifBody = IfAbstractClass})+ = bindIfaceTyConBinders binders $ \ binders' -> do+ { fds <- mapM tc_fd rdr_fds+ ; cls <- buildClass tc_name binders' roles fds Nothing+ ; return (ATyCon (classTyCon cls)) }++tc_iface_decl _parent ignore_prags+ (IfaceClass {ifName = tc_name,+ ifRoles = roles,+ ifBinders = binders,+ ifFDs = rdr_fds,+ ifBody = IfConcreteClass {+ ifClassCtxt = rdr_ctxt,+ ifATs = rdr_ats, ifSigs = rdr_sigs,+ ifMinDef = mindef_occ+ }})+ = bindIfaceTyConBinders binders $ \ binders' -> do+ { traceIf (text "tc-iface-class1" <+> ppr tc_name)+ ; ctxt <- mapM tc_sc rdr_ctxt+ ; traceIf (text "tc-iface-class2" <+> ppr tc_name)+ ; sigs <- mapM tc_sig rdr_sigs+ ; fds <- mapM tc_fd rdr_fds+ ; traceIf (text "tc-iface-class3" <+> ppr tc_name)+ ; mindef <- traverse (lookupIfaceTop . mkVarOccFS) mindef_occ+ ; cls <- fixM $ \ cls -> do+ { ats <- mapM (tc_at cls) rdr_ats+ ; traceIf (text "tc-iface-class4" <+> ppr tc_name)+ ; buildClass tc_name binders' roles fds (Just (ctxt, ats, sigs, mindef)) }+ ; return (ATyCon (classTyCon cls)) }+ where+ tc_sc pred = forkM (mk_sc_doc pred) (tcIfaceType pred)+ -- The *length* of the superclasses is used by buildClass, and hence must+ -- not be inside the thunk. But the *content* maybe recursive and hence+ -- must be lazy (via forkM). Example:+ -- class C (T a) => D a where+ -- data T a+ -- Here the associated type T is knot-tied with the class, and+ -- so we must not pull on T too eagerly. See Trac #5970++ tc_sig :: IfaceClassOp -> IfL TcMethInfo+ tc_sig (IfaceClassOp op_name rdr_ty dm)+ = do { let doc = mk_op_doc op_name rdr_ty+ ; op_ty <- forkM (doc <+> text "ty") $ tcIfaceType rdr_ty+ -- Must be done lazily for just the same reason as the+ -- type of a data con; to avoid sucking in types that+ -- it mentions unless it's necessary to do so+ ; dm' <- tc_dm doc dm+ ; return (op_name, op_ty, dm') }++ tc_dm :: SDoc+ -> Maybe (DefMethSpec IfaceType)+ -> IfL (Maybe (DefMethSpec (SrcSpan, Type)))+ tc_dm _ Nothing = return Nothing+ tc_dm _ (Just VanillaDM) = return (Just VanillaDM)+ tc_dm doc (Just (GenericDM ty))+ = do { -- Must be done lazily to avoid sucking in types+ ; ty' <- forkM (doc <+> text "dm") $ tcIfaceType ty+ ; return (Just (GenericDM (noSrcSpan, ty'))) }++ tc_at cls (IfaceAT tc_decl if_def)+ = do ATyCon tc <- tc_iface_decl (Just cls) ignore_prags tc_decl+ mb_def <- case if_def of+ Nothing -> return Nothing+ Just def -> forkM (mk_at_doc tc) $+ extendIfaceTyVarEnv (tyConTyVars tc) $+ do { tc_def <- tcIfaceType def+ ; return (Just (tc_def, noSrcSpan)) }+ -- Must be done lazily in case the RHS of the defaults mention+ -- the type constructor being defined here+ -- e.g. type AT a; type AT b = AT [b] Trac #8002+ return (ATI tc mb_def)++ mk_sc_doc pred = text "Superclass" <+> ppr pred+ mk_at_doc tc = text "Associated type" <+> ppr tc+ mk_op_doc op_name op_ty = text "Class op" <+> sep [ppr op_name, ppr op_ty]++tc_iface_decl _ _ (IfaceAxiom { ifName = tc_name, ifTyCon = tc+ , ifAxBranches = branches, ifRole = role })+ = do { tc_tycon <- tcIfaceTyCon tc+ -- Must be done lazily, because axioms are forced when checking+ -- for family instance consistency, and the RHS may mention+ -- a hs-boot declared type constructor that is going to be+ -- defined by this module.+ -- e.g. type instance F Int = ToBeDefined+ -- See Trac #13803+ ; tc_branches <- forkM (text "Axiom branches" <+> ppr tc_name)+ $ tc_ax_branches branches+ ; let axiom = CoAxiom { co_ax_unique = nameUnique tc_name+ , co_ax_name = tc_name+ , co_ax_tc = tc_tycon+ , co_ax_role = role+ , co_ax_branches = manyBranches tc_branches+ , co_ax_implicit = False }+ ; return (ACoAxiom axiom) }++tc_iface_decl _ _ (IfacePatSyn{ ifName = name+ , ifPatMatcher = if_matcher+ , ifPatBuilder = if_builder+ , ifPatIsInfix = is_infix+ , ifPatUnivBndrs = univ_bndrs+ , ifPatExBndrs = ex_bndrs+ , ifPatProvCtxt = prov_ctxt+ , ifPatReqCtxt = req_ctxt+ , ifPatArgs = args+ , ifPatTy = pat_ty+ , ifFieldLabels = field_labels })+ = do { traceIf (text "tc_iface_decl" <+> ppr name)+ ; matcher <- tc_pr if_matcher+ ; builder <- fmapMaybeM tc_pr if_builder+ ; bindIfaceForAllBndrs univ_bndrs $ \univ_tvs -> do+ { bindIfaceForAllBndrs ex_bndrs $ \ex_tvs -> do+ { patsyn <- forkM (mk_doc name) $+ do { prov_theta <- tcIfaceCtxt prov_ctxt+ ; req_theta <- tcIfaceCtxt req_ctxt+ ; pat_ty <- tcIfaceType pat_ty+ ; arg_tys <- mapM tcIfaceType args+ ; return $ buildPatSyn name is_infix matcher builder+ (univ_tvs, req_theta)+ (ex_tvs, prov_theta)+ arg_tys pat_ty field_labels }+ ; return $ AConLike . PatSynCon $ patsyn }}}+ where+ mk_doc n = text "Pattern synonym" <+> ppr n+ tc_pr :: (IfExtName, Bool) -> IfL (Id, Bool)+ tc_pr (nm, b) = do { id <- forkM (ppr nm) (tcIfaceExtId nm)+ ; return (id, b) }++tc_fd :: FunDep IfLclName -> IfL (FunDep TyVar)+tc_fd (tvs1, tvs2) = do { tvs1' <- mapM tcIfaceTyVar tvs1+ ; tvs2' <- mapM tcIfaceTyVar tvs2+ ; return (tvs1', tvs2') }++tc_ax_branches :: [IfaceAxBranch] -> IfL [CoAxBranch]+tc_ax_branches if_branches = foldlM tc_ax_branch [] if_branches++tc_ax_branch :: [CoAxBranch] -> IfaceAxBranch -> IfL [CoAxBranch]+tc_ax_branch prev_branches+ (IfaceAxBranch { ifaxbTyVars = tv_bndrs, ifaxbCoVars = cv_bndrs+ , ifaxbLHS = lhs, ifaxbRHS = rhs+ , ifaxbRoles = roles, ifaxbIncomps = incomps })+ = bindIfaceTyConBinders_AT+ (map (\b -> TvBndr b (NamedTCB Inferred)) tv_bndrs) $ \ tvs ->+ -- The _AT variant is needed here; see Note [CoAxBranch type variables] in CoAxiom+ bindIfaceIds cv_bndrs $ \ cvs -> do+ { tc_lhs <- tcIfaceTcArgs lhs+ ; tc_rhs <- tcIfaceType rhs+ ; let br = CoAxBranch { cab_loc = noSrcSpan+ , cab_tvs = binderVars tvs+ , cab_cvs = cvs+ , cab_lhs = tc_lhs+ , cab_roles = roles+ , cab_rhs = tc_rhs+ , cab_incomps = map (prev_branches `getNth`) incomps }+ ; return (prev_branches ++ [br]) }++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 }+ where+ univ_tv_bndrs :: [TyVarBinder]+ univ_tv_bndrs = mkDataConUnivTyVarBinders tc_tybinders++ tc_con_decl (IfCon { ifConInfix = is_infix,+ ifConExTvs = ex_bndrs,+ ifConName = dc_name,+ ifConCtxt = ctxt, ifConEqSpec = spec,+ ifConArgTys = args, ifConFields = lbl_names,+ ifConStricts = if_stricts,+ ifConSrcStricts = if_src_stricts})+ = -- Universally-quantified tyvars are shared with+ -- parent TyCon, and are already in scope+ bindIfaceForAllBndrs ex_bndrs $ \ ex_tv_bndrs -> do+ { traceIf (text "Start interface-file tc_con_decl" <+> ppr dc_name)++ -- Read the context and argument types, but lazily for two reasons+ -- (a) to avoid looking tugging on a recursive use of+ -- the type itself, which is knot-tied+ -- (b) to avoid faulting in the component types unless+ -- they are really needed+ ; ~(eq_spec, theta, arg_tys, stricts) <- forkM (mk_doc dc_name) $+ do { eq_spec <- tcIfaceEqSpec spec+ ; theta <- tcIfaceCtxt ctxt+ ; arg_tys <- mapM tcIfaceType args+ ; stricts <- mapM tc_strict if_stricts+ -- The IfBang field can mention+ -- the type itself; hence inside forkM+ ; return (eq_spec, theta, arg_tys, stricts) }++ -- Remember, tycon is the representation tycon+ ; let orig_res_ty = mkFamilyTyConApp tycon+ (substTyVars (mkTvSubstPrs (map eqSpecPair eq_spec))+ (binderVars tc_tybinders))++ ; prom_rep_name <- newTyConRepName dc_name++ ; con <- buildDataCon (pprPanic "tcIfaceDataCons: FamInstEnvs" (ppr dc_name))+ dc_name is_infix prom_rep_name+ (map src_strict if_src_stricts)+ (Just stricts)+ -- Pass the HsImplBangs (i.e. final+ -- decisions) to buildDataCon; it'll use+ -- these to guide the construction of a+ -- worker.+ -- See Note [Bangs on imported data constructors] in MkId+ lbl_names+ univ_tv_bndrs ex_tv_bndrs+ eq_spec theta+ arg_tys orig_res_ty tycon+ ; traceIf (text "Done interface-file tc_con_decl" <+> ppr dc_name)+ ; return con }+ mk_doc con_name = text "Constructor" <+> ppr con_name++ tc_strict :: IfaceBang -> IfL HsImplBang+ tc_strict IfNoBang = return (HsLazy)+ tc_strict IfStrict = return (HsStrict)+ tc_strict IfUnpack = return (HsUnpack Nothing)+ tc_strict (IfUnpackCo if_co) = do { co <- tcIfaceCo if_co+ ; return (HsUnpack (Just co)) }++ src_strict :: IfaceSrcBang -> HsSrcBang+ src_strict (IfSrcBang unpk bang) = HsSrcBang NoSourceText unpk bang++tcIfaceEqSpec :: IfaceEqSpec -> IfL [EqSpec]+tcIfaceEqSpec spec+ = mapM do_item spec+ where+ do_item (occ, if_ty) = do { tv <- tcIfaceTyVar occ+ ; ty <- tcIfaceType if_ty+ ; return (mkEqSpec tv ty) }++{-+Note [Synonym kind loop]+~~~~~~~~~~~~~~~~~~~~~~~~+Notice that we eagerly grab the *kind* from the interface file, but+build a forkM thunk for the *rhs* (and family stuff). To see why,+consider this (Trac #2412)++M.hs: module M where { import X; data T = MkT S }+X.hs: module X where { import {-# SOURCE #-} M; type S = T }+M.hs-boot: module M where { data T }++When kind-checking M.hs we need S's kind. But we do not want to+find S's kind from (typeKind S-rhs), because we don't want to look at+S-rhs yet! Since S is imported from X.hi, S gets just one chance to+be defined, and we must not do that until we've finished with M.T.++Solution: record S's kind in the interface file; now we can safely+look at it.++************************************************************************+* *+ Instances+* *+************************************************************************+-}++tcIfaceInst :: IfaceClsInst -> IfL ClsInst+tcIfaceInst (IfaceClsInst { ifDFun = dfun_name, ifOFlag = oflag+ , ifInstCls = cls, ifInstTys = mb_tcs+ , ifInstOrph = orph })+ = do { dfun <- forkM (text "Dict fun" <+> ppr dfun_name) $+ fmap tyThingId (tcIfaceImplicit dfun_name)+ ; let mb_tcs' = map (fmap ifaceTyConName) mb_tcs+ ; return (mkImportedInstance cls mb_tcs' dfun_name dfun oflag orph) }++tcIfaceFamInst :: IfaceFamInst -> IfL FamInst+tcIfaceFamInst (IfaceFamInst { ifFamInstFam = fam, ifFamInstTys = mb_tcs+ , ifFamInstAxiom = axiom_name } )+ = do { axiom' <- forkM (text "Axiom" <+> ppr axiom_name) $+ tcIfaceCoAxiom axiom_name+ -- will panic if branched, but that's OK+ ; let axiom'' = toUnbranchedAxiom axiom'+ mb_tcs' = map (fmap ifaceTyConName) mb_tcs+ ; return (mkImportedFamInst fam mb_tcs' axiom'') }++{-+************************************************************************+* *+ Rules+* *+************************************************************************++We move a IfaceRule from eps_rules to eps_rule_base when all its LHS free vars+are in the type environment. However, remember that typechecking a Rule may+(as a side effect) augment the type envt, and so we may need to iterate the process.+-}++tcIfaceRules :: Bool -- True <=> ignore rules+ -> [IfaceRule]+ -> IfL [CoreRule]+tcIfaceRules ignore_prags if_rules+ | ignore_prags = return []+ | otherwise = mapM tcIfaceRule if_rules++tcIfaceRule :: IfaceRule -> IfL CoreRule+tcIfaceRule (IfaceRule {ifRuleName = name, ifActivation = act, ifRuleBndrs = bndrs,+ ifRuleHead = fn, ifRuleArgs = args, ifRuleRhs = rhs,+ ifRuleAuto = auto, ifRuleOrph = orph })+ = do { ~(bndrs', args', rhs') <-+ -- Typecheck the payload lazily, in the hope it'll never be looked at+ forkM (text "Rule" <+> pprRuleName name) $+ bindIfaceBndrs bndrs $ \ bndrs' ->+ do { args' <- mapM tcIfaceExpr args+ ; rhs' <- tcIfaceExpr rhs+ ; return (bndrs', args', rhs') }+ ; let mb_tcs = map ifTopFreeName args+ ; this_mod <- getIfModule+ ; return (Rule { ru_name = name, ru_fn = fn, ru_act = act,+ ru_bndrs = bndrs', ru_args = args',+ ru_rhs = occurAnalyseExpr rhs',+ ru_rough = mb_tcs,+ ru_origin = this_mod,+ ru_orphan = orph,+ ru_auto = auto,+ ru_local = False }) } -- An imported RULE is never for a local Id+ -- or, even if it is (module loop, perhaps)+ -- we'll just leave it in the non-local set+ where+ -- This function *must* mirror exactly what Rules.roughTopNames does+ -- We could have stored the ru_rough field in the iface file+ -- but that would be redundant, I think.+ -- The only wrinkle is that we must not be deceived by+ -- type synonyms at the top of a type arg. Since+ -- we can't tell at this point, we are careful not+ -- to write them out in coreRuleToIfaceRule+ ifTopFreeName :: IfaceExpr -> Maybe Name+ ifTopFreeName (IfaceType (IfaceTyConApp tc _ )) = Just (ifaceTyConName tc)+ ifTopFreeName (IfaceType (IfaceTupleTy s _ ts)) = Just (tupleTyConName s (length (tcArgsIfaceTypes ts)))+ ifTopFreeName (IfaceApp f _) = ifTopFreeName f+ ifTopFreeName (IfaceExt n) = Just n+ ifTopFreeName _ = Nothing++{-+************************************************************************+* *+ Annotations+* *+************************************************************************+-}++tcIfaceAnnotations :: [IfaceAnnotation] -> IfL [Annotation]+tcIfaceAnnotations = mapM tcIfaceAnnotation++tcIfaceAnnotation :: IfaceAnnotation -> IfL Annotation+tcIfaceAnnotation (IfaceAnnotation target serialized) = do+ target' <- tcIfaceAnnTarget target+ return $ Annotation {+ ann_target = target',+ ann_value = serialized+ }++tcIfaceAnnTarget :: IfaceAnnTarget -> IfL (AnnTarget Name)+tcIfaceAnnTarget (NamedTarget occ) = do+ name <- lookupIfaceTop occ+ return $ NamedTarget name+tcIfaceAnnTarget (ModuleTarget mod) = do+ return $ ModuleTarget mod++{-+************************************************************************+* *+ Complete Match Pragmas+* *+************************************************************************+-}++tcIfaceCompleteSigs :: [IfaceCompleteMatch] -> IfL [CompleteMatch]+tcIfaceCompleteSigs = mapM tcIfaceCompleteSig++tcIfaceCompleteSig :: IfaceCompleteMatch -> IfL CompleteMatch+tcIfaceCompleteSig (IfaceCompleteMatch ms t) = return (CompleteMatch ms t)++{-+************************************************************************+* *+ Vectorisation information+* *+************************************************************************+-}++-- We need access to the type environment as we need to look up information about type constructors+-- (i.e., their data constructors and whether they are class type constructors). If a vectorised+-- type constructor or class is defined in the same module as where it is vectorised, we cannot+-- look that information up from the type constructor that we obtained via a 'forkM'ed+-- 'tcIfaceTyCon' without recursively loading the interface that we are already type checking again+-- and again and again...+--+tcIfaceVectInfo :: Module -> TypeEnv -> IfaceVectInfo -> IfL VectInfo+tcIfaceVectInfo mod typeEnv (IfaceVectInfo+ { ifaceVectInfoVar = vars+ , ifaceVectInfoTyCon = tycons+ , ifaceVectInfoTyConReuse = tyconsReuse+ , ifaceVectInfoParallelVars = parallelVars+ , ifaceVectInfoParallelTyCons = parallelTyCons+ })+ = do { let parallelTyConsSet = mkNameSet parallelTyCons+ ; vVars <- mapM vectVarMapping vars+ ; let varsSet = mkVarSet (map fst vVars)+ ; tyConRes1 <- mapM (vectTyConVectMapping varsSet) tycons+ ; tyConRes2 <- mapM (vectTyConReuseMapping varsSet) tyconsReuse+ ; vParallelVars <- mapM vectVar parallelVars+ ; let (vTyCons, vDataCons, vScSels) = unzip3 (tyConRes1 ++ tyConRes2)+ ; return $ VectInfo+ { vectInfoVar = mkDVarEnv vVars `extendDVarEnvList` concat vScSels+ , vectInfoTyCon = mkNameEnv vTyCons+ , vectInfoDataCon = mkNameEnv (concat vDataCons)+ , vectInfoParallelVars = mkDVarSet vParallelVars+ , vectInfoParallelTyCons = parallelTyConsSet+ }+ }+ where+ vectVarMapping name+ = do { vName <- lookupIfaceTop (mkLocalisedOccName mod mkVectOcc name)+ ; var <- forkM (text "vect var" <+> ppr name) $+ tcIfaceExtId name+ ; vVar <- forkM (text "vect vVar [mod =" <+>+ ppr mod <> text "; nameModule =" <+>+ ppr (nameModule name) <> text "]" <+> ppr vName) $+ tcIfaceExtId vName+ ; return (var, (var, vVar))+ }+ -- where+ -- lookupLocalOrExternalId name+ -- = do { let mb_id = lookupTypeEnv typeEnv name+ -- ; case mb_id of+ -- -- id is local+ -- Just (AnId id) -> return id+ -- -- name is not an Id => internal inconsistency+ -- Just _ -> notAnIdErr+ -- -- Id is external+ -- Nothing -> tcIfaceExtId name+ -- }+ --+ -- notAnIdErr = pprPanic "TcIface.tcIfaceVectInfo: not an id" (ppr name)++ vectVar name+ = forkM (text "vect scalar var" <+> ppr name) $+ tcIfaceExtId name++ vectTyConVectMapping vars name+ = do { vName <- lookupIfaceTop (mkLocalisedOccName mod mkVectTyConOcc name)+ ; vectTyConMapping vars name vName+ }++ vectTyConReuseMapping vars name+ = vectTyConMapping vars name name++ vectTyConMapping vars name vName+ = do { tycon <- lookupLocalOrExternalTyCon name+ ; vTycon <- forkM (text "vTycon of" <+> ppr vName) $+ lookupLocalOrExternalTyCon vName++ -- Map the data constructors of the original type constructor to those of the+ -- vectorised type constructor /unless/ the type constructor was vectorised+ -- abstractly; if it was vectorised abstractly, the workers of its data constructors+ -- do not appear in the set of vectorised variables.+ --+ -- NB: This is lazy! We don't pull at the type constructors before we actually use+ -- the data constructor mapping.+ ; let isAbstract | isClassTyCon tycon = False+ | datacon:_ <- tyConDataCons tycon+ = not $ dataConWrapId datacon `elemVarSet` vars+ | otherwise = True+ vDataCons | isAbstract = []+ | otherwise = [ (dataConName datacon, (datacon, vDatacon))+ | (datacon, vDatacon) <- zip (tyConDataCons tycon)+ (tyConDataCons vTycon)+ ]++ -- Map the (implicit) superclass and methods selectors as they don't occur in+ -- the var map.+ vScSels | Just cls <- tyConClass_maybe tycon+ , Just vCls <- tyConClass_maybe vTycon+ = [ (sel, (sel, vSel))+ | (sel, vSel) <- zip (classAllSelIds cls) (classAllSelIds vCls)+ ]+ | otherwise+ = []++ ; return ( (name, (tycon, vTycon)) -- (T, T_v)+ , vDataCons -- list of (Ci, Ci_v)+ , vScSels -- list of (seli, seli_v)+ )+ }+ where+ -- we need a fully defined version of the type constructor to be able to extract+ -- its data constructors etc.+ lookupLocalOrExternalTyCon name+ = do { let mb_tycon = lookupTypeEnv typeEnv name+ ; case mb_tycon of+ -- tycon is local+ Just (ATyCon tycon) -> return tycon+ -- name is not a tycon => internal inconsistency+ Just _ -> notATyConErr+ -- tycon is external+ Nothing -> tcIfaceTyConByName name+ }++ notATyConErr = pprPanic "TcIface.tcIfaceVectInfo: not a tycon" (ppr name)++{-+************************************************************************+* *+ Types+* *+************************************************************************+-}++tcIfaceType :: IfaceType -> IfL Type+tcIfaceType = go+ where+ go (IfaceTyVar n) = TyVarTy <$> tcIfaceTyVar n+ go (IfaceFreeTyVar n) = pprPanic "tcIfaceType:IfaceFreeTyVar" (ppr n)+ go (IfaceAppTy t1 t2) = AppTy <$> go t1 <*> go t2+ go (IfaceLitTy l) = LitTy <$> tcIfaceTyLit l+ go (IfaceFunTy t1 t2) = FunTy <$> go t1 <*> go t2+ go (IfaceDFunTy t1 t2) = FunTy <$> go t1 <*> go t2+ go (IfaceTupleTy s i tks) = tcIfaceTupleTy s i tks+ go (IfaceTyConApp tc tks)+ = do { tc' <- tcIfaceTyCon tc+ ; tks' <- mapM go (tcArgsIfaceTypes tks)+ ; return (mkTyConApp tc' tks') }+ go (IfaceForAllTy bndr t)+ = bindIfaceForAllBndr bndr $ \ tv' vis ->+ ForAllTy (TvBndr tv' vis) <$> go t+ go (IfaceCastTy ty co) = CastTy <$> go ty <*> tcIfaceCo co+ go (IfaceCoercionTy co) = CoercionTy <$> tcIfaceCo co++tcIfaceTupleTy :: TupleSort -> IsPromoted -> IfaceTcArgs -> IfL Type+tcIfaceTupleTy sort is_promoted args+ = do { args' <- tcIfaceTcArgs args+ ; let arity = length args'+ ; base_tc <- tcTupleTyCon True sort arity+ ; case is_promoted of+ IsNotPromoted+ -> return (mkTyConApp base_tc args')++ IsPromoted+ -> do { let tc = promoteDataCon (tyConSingleDataCon base_tc)+ kind_args = map typeKind args'+ ; return (mkTyConApp tc (kind_args ++ args')) } }++-- See Note [Unboxed tuple RuntimeRep vars] in TyCon+tcTupleTyCon :: Bool -- True <=> typechecking a *type* (vs. an expr)+ -> TupleSort+ -> Arity -- the number of args. *not* the tuple arity.+ -> IfL TyCon+tcTupleTyCon in_type sort arity+ = case sort of+ ConstraintTuple -> do { thing <- tcIfaceGlobal (cTupleTyConName arity)+ ; return (tyThingTyCon thing) }+ BoxedTuple -> return (tupleTyCon Boxed arity)+ UnboxedTuple -> return (tupleTyCon Unboxed arity')+ where arity' | in_type = arity `div` 2+ | otherwise = arity+ -- in expressions, we only have term args++tcIfaceTcArgs :: IfaceTcArgs -> IfL [Type]+tcIfaceTcArgs = mapM tcIfaceType . tcArgsIfaceTypes++-----------------------------------------+tcIfaceCtxt :: IfaceContext -> IfL ThetaType+tcIfaceCtxt sts = mapM tcIfaceType sts++-----------------------------------------+tcIfaceTyLit :: IfaceTyLit -> IfL TyLit+tcIfaceTyLit (IfaceNumTyLit n) = return (NumTyLit n)+tcIfaceTyLit (IfaceStrTyLit n) = return (StrTyLit n)++{-+%************************************************************************+%* *+ Coercions+* *+************************************************************************+-}++tcIfaceCo :: IfaceCoercion -> IfL Coercion+tcIfaceCo = go+ where+ go (IfaceReflCo r t) = Refl r <$> tcIfaceType t+ go (IfaceFunCo r c1 c2) = mkFunCo r <$> go c1 <*> go c2+ go (IfaceTyConAppCo r tc cs)+ = TyConAppCo r <$> tcIfaceTyCon tc <*> mapM go cs+ go (IfaceAppCo c1 c2) = AppCo <$> go c1 <*> go c2+ go (IfaceForAllCo tv k c) = do { k' <- go k+ ; bindIfaceTyVar tv $ \ tv' ->+ ForAllCo tv' k' <$> go c }+ go (IfaceCoVarCo n) = CoVarCo <$> go_var n+ go (IfaceAxiomInstCo n i cs) = AxiomInstCo <$> tcIfaceCoAxiom n <*> pure i <*> mapM go cs+ go (IfaceUnivCo p r t1 t2) = UnivCo <$> tcIfaceUnivCoProv p <*> pure r+ <*> tcIfaceType t1 <*> tcIfaceType t2+ go (IfaceSymCo c) = SymCo <$> go c+ go (IfaceTransCo c1 c2) = TransCo <$> go c1+ <*> go c2+ go (IfaceInstCo c1 t2) = InstCo <$> go c1+ <*> go t2+ go (IfaceNthCo d c) = NthCo d <$> go c+ go (IfaceLRCo lr c) = LRCo lr <$> go c+ go (IfaceCoherenceCo c1 c2) = CoherenceCo <$> go c1+ <*> go c2+ go (IfaceKindCo c) = KindCo <$> go c+ go (IfaceSubCo c) = SubCo <$> go c+ go (IfaceAxiomRuleCo ax cos) = AxiomRuleCo <$> go_axiom_rule ax+ <*> mapM go cos++ go_var :: FastString -> IfL CoVar+ go_var = tcIfaceLclId++ go_axiom_rule :: FastString -> IfL CoAxiomRule+ go_axiom_rule n =+ case Map.lookup n typeNatCoAxiomRules of+ Just ax -> return ax+ _ -> pprPanic "go_axiom_rule" (ppr n)++tcIfaceUnivCoProv :: IfaceUnivCoProv -> IfL UnivCoProvenance+tcIfaceUnivCoProv IfaceUnsafeCoerceProv = return UnsafeCoerceProv+tcIfaceUnivCoProv (IfacePhantomProv kco) = PhantomProv <$> tcIfaceCo kco+tcIfaceUnivCoProv (IfaceProofIrrelProv kco) = ProofIrrelProv <$> tcIfaceCo kco+tcIfaceUnivCoProv (IfacePluginProv str) = return $ PluginProv str+tcIfaceUnivCoProv (IfaceHoleProv _) =+ pprPanic "tcIfaceUnivCoProv" (text "holes can't occur in interface files")++{-+************************************************************************+* *+ Core+* *+************************************************************************+-}++tcIfaceExpr :: IfaceExpr -> IfL CoreExpr+tcIfaceExpr (IfaceType ty)+ = Type <$> tcIfaceType ty++tcIfaceExpr (IfaceCo co)+ = Coercion <$> tcIfaceCo co++tcIfaceExpr (IfaceCast expr co)+ = Cast <$> tcIfaceExpr expr <*> tcIfaceCo co++tcIfaceExpr (IfaceLcl name)+ = Var <$> tcIfaceLclId name++tcIfaceExpr (IfaceExt gbl)+ = Var <$> tcIfaceExtId gbl++tcIfaceExpr (IfaceLit lit)+ = do lit' <- tcIfaceLit lit+ return (Lit lit')++tcIfaceExpr (IfaceFCall cc ty) = do+ ty' <- tcIfaceType ty+ u <- newUnique+ dflags <- getDynFlags+ return (Var (mkFCallId dflags u cc ty'))++tcIfaceExpr (IfaceTuple sort args)+ = do { args' <- mapM tcIfaceExpr args+ ; tc <- tcTupleTyCon False sort arity+ ; let con_tys = map exprType args'+ some_con_args = map Type con_tys ++ args'+ con_args = case sort of+ UnboxedTuple -> map (Type . getRuntimeRep "tcIfaceExpr") con_tys ++ some_con_args+ _ -> some_con_args+ -- Put the missing type arguments back in+ con_id = dataConWorkId (tyConSingleDataCon tc)+ ; return (mkApps (Var con_id) con_args) }+ where+ arity = length args++tcIfaceExpr (IfaceLam (bndr, os) body)+ = bindIfaceBndr bndr $ \bndr' ->+ Lam (tcIfaceOneShot os bndr') <$> tcIfaceExpr body+ where+ tcIfaceOneShot IfaceOneShot b = setOneShotLambda b+ tcIfaceOneShot _ b = b++tcIfaceExpr (IfaceApp fun arg)+ = App <$> tcIfaceExpr fun <*> tcIfaceExpr arg++tcIfaceExpr (IfaceECase scrut ty)+ = do { scrut' <- tcIfaceExpr scrut+ ; ty' <- tcIfaceType ty+ ; return (castBottomExpr scrut' ty') }++tcIfaceExpr (IfaceCase scrut case_bndr alts) = do+ scrut' <- tcIfaceExpr scrut+ case_bndr_name <- newIfaceName (mkVarOccFS case_bndr)+ let+ scrut_ty = exprType scrut'+ case_bndr' = mkLocalIdOrCoVar case_bndr_name scrut_ty+ tc_app = splitTyConApp scrut_ty+ -- NB: Won't always succeed (polymorphic case)+ -- but won't be demanded in those cases+ -- NB: not tcSplitTyConApp; we are looking at Core here+ -- look through non-rec newtypes to find the tycon that+ -- corresponds to the datacon in this case alternative++ extendIfaceIdEnv [case_bndr'] $ do+ alts' <- mapM (tcIfaceAlt scrut' tc_app) alts+ return (Case scrut' case_bndr' (coreAltsType alts') alts')++tcIfaceExpr (IfaceLet (IfaceNonRec (IfLetBndr fs ty info ji) rhs) body)+ = do { name <- newIfaceName (mkVarOccFS fs)+ ; ty' <- tcIfaceType ty+ ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}+ name ty' info+ ; let id = mkLocalIdOrCoVarWithInfo name ty' id_info+ `asJoinId_maybe` tcJoinInfo ji+ ; rhs' <- tcIfaceExpr rhs+ ; body' <- extendIfaceIdEnv [id] (tcIfaceExpr body)+ ; return (Let (NonRec id rhs') body') }++tcIfaceExpr (IfaceLet (IfaceRec pairs) body)+ = do { ids <- mapM tc_rec_bndr (map fst pairs)+ ; extendIfaceIdEnv ids $ do+ { pairs' <- zipWithM tc_pair pairs ids+ ; body' <- tcIfaceExpr body+ ; return (Let (Rec pairs') body') } }+ where+ tc_rec_bndr (IfLetBndr fs ty _ ji)+ = do { name <- newIfaceName (mkVarOccFS fs)+ ; ty' <- tcIfaceType ty+ ; return (mkLocalIdOrCoVar name ty' `asJoinId_maybe` tcJoinInfo ji) }+ tc_pair (IfLetBndr _ _ info _, rhs) id+ = do { rhs' <- tcIfaceExpr rhs+ ; id_info <- tcIdInfo False {- Don't ignore prags; we are inside one! -}+ (idName id) (idType id) info+ ; return (setIdInfo id id_info, rhs') }++tcIfaceExpr (IfaceTick tickish expr) = do+ expr' <- tcIfaceExpr expr+ -- If debug flag is not set: Ignore source notes+ dbgLvl <- fmap debugLevel getDynFlags+ case tickish of+ IfaceSource{} | dbgLvl > 0+ -> return expr'+ _otherwise -> do+ tickish' <- tcIfaceTickish tickish+ return (Tick tickish' expr')++-------------------------+tcIfaceTickish :: IfaceTickish -> IfM lcl (Tickish Id)+tcIfaceTickish (IfaceHpcTick modl ix) = return (HpcTick modl ix)+tcIfaceTickish (IfaceSCC cc tick push) = return (ProfNote cc tick push)+tcIfaceTickish (IfaceSource src name) = return (SourceNote src name)++-------------------------+tcIfaceLit :: Literal -> IfL Literal+-- Integer literals deserialise to (LitInteger i <error thunk>)+-- so tcIfaceLit just fills in the type.+-- See Note [Integer literals] in Literal+tcIfaceLit (LitInteger i _)+ = do t <- tcIfaceTyConByName integerTyConName+ return (mkLitInteger i (mkTyConTy t))+tcIfaceLit lit = return lit++-------------------------+tcIfaceAlt :: CoreExpr -> (TyCon, [Type])+ -> (IfaceConAlt, [FastString], IfaceExpr)+ -> IfL (AltCon, [TyVar], CoreExpr)+tcIfaceAlt _ _ (IfaceDefault, names, rhs)+ = ASSERT( null names ) do+ rhs' <- tcIfaceExpr rhs+ return (DEFAULT, [], rhs')++tcIfaceAlt _ _ (IfaceLitAlt lit, names, rhs)+ = ASSERT( null names ) do+ lit' <- tcIfaceLit lit+ rhs' <- tcIfaceExpr rhs+ return (LitAlt lit', [], rhs')++-- A case alternative is made quite a bit more complicated+-- by the fact that we omit type annotations because we can+-- work them out. True enough, but its not that easy!+tcIfaceAlt scrut (tycon, inst_tys) (IfaceDataAlt data_occ, arg_strs, rhs)+ = do { con <- tcIfaceDataCon data_occ+ ; when (debugIsOn && not (con `elem` tyConDataCons tycon))+ (failIfM (ppr scrut $$ ppr con $$ ppr tycon $$ ppr (tyConDataCons tycon)))+ ; tcIfaceDataAlt con inst_tys arg_strs rhs }++tcIfaceDataAlt :: DataCon -> [Type] -> [FastString] -> IfaceExpr+ -> IfL (AltCon, [TyVar], CoreExpr)+tcIfaceDataAlt con inst_tys arg_strs rhs+ = do { us <- newUniqueSupply+ ; let uniqs = uniqsFromSupply us+ ; let (ex_tvs, arg_ids)+ = dataConRepFSInstPat arg_strs uniqs con inst_tys++ ; rhs' <- extendIfaceEnvs ex_tvs $+ extendIfaceIdEnv arg_ids $+ tcIfaceExpr rhs+ ; return (DataAlt con, ex_tvs ++ arg_ids, rhs') }++{-+************************************************************************+* *+ IdInfo+* *+************************************************************************+-}++tcIdDetails :: Type -> IfaceIdDetails -> IfL IdDetails+tcIdDetails _ IfVanillaId = return VanillaId+tcIdDetails ty IfDFunId+ = return (DFunId (isNewTyCon (classTyCon cls)))+ where+ (_, _, cls, _) = tcSplitDFunTy ty++tcIdDetails _ (IfRecSelId tc naughty)+ = do { tc' <- either (fmap RecSelData . tcIfaceTyCon)+ (fmap (RecSelPatSyn . tyThingPatSyn) . tcIfaceDecl False)+ tc+ ; return (RecSelId { sel_tycon = tc', sel_naughty = naughty }) }+ where+ tyThingPatSyn (AConLike (PatSynCon ps)) = ps+ tyThingPatSyn _ = panic "tcIdDetails: expecting patsyn"++tcIdInfo :: Bool -> Name -> Type -> IfaceIdInfo -> IfL IdInfo+tcIdInfo ignore_prags name ty info = do+ lcl_env <- getLclEnv+ -- Set the CgInfo to something sensible but uninformative before+ -- we start; default assumption is that it has CAFs+ let init_info | if_boot lcl_env = vanillaIdInfo `setUnfoldingInfo` BootUnfolding+ | otherwise = vanillaIdInfo+ if ignore_prags+ then return init_info+ else case info of+ NoInfo -> return init_info+ HasInfo info -> foldlM tcPrag init_info info+ where+ tcPrag :: IdInfo -> IfaceInfoItem -> IfL IdInfo+ tcPrag info HsNoCafRefs = return (info `setCafInfo` NoCafRefs)+ tcPrag info (HsArity arity) = return (info `setArityInfo` arity)+ tcPrag info (HsStrictness str) = return (info `setStrictnessInfo` str)+ tcPrag info (HsInline prag) = return (info `setInlinePragInfo` prag)+ tcPrag info HsLevity = return (info `setNeverLevPoly` ty)++ -- The next two are lazy, so they don't transitively suck stuff in+ tcPrag info (HsUnfold lb if_unf)+ = do { unf <- tcUnfolding name ty info if_unf+ ; let info1 | lb = info `setOccInfo` strongLoopBreaker+ | otherwise = info+ ; return (info1 `setUnfoldingInfo` unf) }++tcJoinInfo :: IfaceJoinInfo -> Maybe JoinArity+tcJoinInfo (IfaceJoinPoint ar) = Just ar+tcJoinInfo IfaceNotJoinPoint = Nothing++tcUnfolding :: Name -> Type -> IdInfo -> IfaceUnfolding -> IfL Unfolding+tcUnfolding name _ info (IfCoreUnfold stable if_expr)+ = do { dflags <- getDynFlags+ ; mb_expr <- tcPragExpr name if_expr+ ; let unf_src | stable = InlineStable+ | otherwise = InlineRhs+ ; return $ case mb_expr of+ Nothing -> NoUnfolding+ Just expr -> mkUnfolding dflags unf_src+ True {- Top level -}+ (isBottomingSig strict_sig)+ expr+ }+ where+ -- Strictness should occur before unfolding!+ strict_sig = strictnessInfo info+tcUnfolding name _ _ (IfCompulsory if_expr)+ = do { mb_expr <- tcPragExpr name if_expr+ ; return (case mb_expr of+ Nothing -> NoUnfolding+ Just expr -> mkCompulsoryUnfolding expr) }++tcUnfolding name _ _ (IfInlineRule arity unsat_ok boring_ok if_expr)+ = do { mb_expr <- tcPragExpr name if_expr+ ; return (case mb_expr of+ Nothing -> NoUnfolding+ Just expr -> mkCoreUnfolding InlineStable True expr guidance )}+ where+ guidance = UnfWhen { ug_arity = arity, ug_unsat_ok = unsat_ok, ug_boring_ok = boring_ok }++tcUnfolding name dfun_ty _ (IfDFunUnfold bs ops)+ = bindIfaceBndrs bs $ \ bs' ->+ do { mb_ops1 <- forkM_maybe doc $ mapM tcIfaceExpr ops+ ; return (case mb_ops1 of+ Nothing -> noUnfolding+ Just ops1 -> mkDFunUnfolding bs' (classDataCon cls) ops1) }+ where+ doc = text "Class ops for dfun" <+> ppr name+ (_, _, cls, _) = tcSplitDFunTy dfun_ty++{-+For unfoldings we try to do the job lazily, so that we never type check+an unfolding that isn't going to be looked at.+-}++tcPragExpr :: Name -> IfaceExpr -> IfL (Maybe CoreExpr)+tcPragExpr name expr+ = forkM_maybe doc $ do+ core_expr' <- tcIfaceExpr expr++ -- Check for type consistency in the unfolding+ whenGOptM Opt_DoCoreLinting $ do+ in_scope <- get_in_scope+ dflags <- getDynFlags+ case lintUnfolding dflags noSrcLoc in_scope core_expr' of+ Nothing -> return ()+ Just fail_msg -> do { mod <- getIfModule+ ; pprPanic "Iface Lint failure"+ (vcat [ text "In interface for" <+> ppr mod+ , hang doc 2 fail_msg+ , ppr name <+> equals <+> ppr core_expr'+ , text "Iface expr =" <+> ppr expr ]) }+ return core_expr'+ where+ doc = text "Unfolding of" <+> ppr name++ get_in_scope :: IfL VarSet -- Totally disgusting; but just for linting+ get_in_scope+ = do { (gbl_env, lcl_env) <- getEnvs+ ; rec_ids <- case if_rec_types gbl_env of+ Nothing -> return []+ Just (_, get_env) -> do+ { type_env <- setLclEnv () get_env+ ; return (typeEnvIds type_env) }+ ; return (bindingsVars (if_tv_env lcl_env) `unionVarSet`+ bindingsVars (if_id_env lcl_env) `unionVarSet`+ mkVarSet rec_ids) }++ bindingsVars :: FastStringEnv Var -> VarSet+ bindingsVars ufm = mkVarSet $ nonDetEltsUFM ufm+ -- It's OK to use nonDetEltsUFM here because we immediately forget+ -- the ordering by creating a set++{-+************************************************************************+* *+ Getting from Names to TyThings+* *+************************************************************************+-}++tcIfaceGlobal :: Name -> IfL TyThing+tcIfaceGlobal name+ | Just thing <- wiredInNameTyThing_maybe name+ -- Wired-in things include TyCons, DataCons, and Ids+ -- Even though we are in an interface file, we want to make+ -- sure the instances and RULES of this thing (particularly TyCon) are loaded+ -- Imagine: f :: Double -> Double+ = do { ifCheckWiredInThing thing; return thing }++ | otherwise+ = do { env <- getGblEnv+ ; case if_rec_types env of { -- Note [Tying the knot]+ Just (mod, get_type_env)+ | nameIsLocalOrFrom mod name+ -> do -- It's defined in the module being compiled+ { type_env <- setLclEnv () get_type_env -- yuk+ ; case lookupNameEnv type_env name of+ Just thing -> return thing+ Nothing ->+ pprPanic "tcIfaceGlobal (local): not found"+ (ifKnotErr name (if_doc env) type_env)+ }++ ; _ -> do++ { hsc_env <- getTopEnv+ ; mb_thing <- liftIO (lookupTypeHscEnv hsc_env name)+ ; case mb_thing of {+ Just thing -> return thing ;+ Nothing -> do++ { mb_thing <- importDecl name -- It's imported; go get it+ ; case mb_thing of+ Failed err -> failIfM err+ Succeeded thing -> return thing+ }}}}}++ifKnotErr :: Name -> SDoc -> TypeEnv -> SDoc+ifKnotErr name env_doc type_env = vcat+ [ text "You are in a maze of twisty little passages, all alike."+ , text "While forcing the thunk for TyThing" <+> ppr name+ , text "which was lazily initialized by" <+> env_doc <> text ","+ , text "I tried to tie the knot, but I couldn't find" <+> ppr name+ , text "in the current type environment."+ , text "If you are developing GHC, please read Note [Tying the knot]"+ , text "and Note [Type-checking inside the knot]."+ , text "Consider rebuilding GHC with profiling for a better stack trace."+ , hang (text "Contents of current type environment:")+ 2 (ppr type_env)+ ]++-- Note [Tying the knot]+-- ~~~~~~~~~~~~~~~~~~~~~+-- The if_rec_types field is used when we are compiling M.hs, which indirectly+-- imports Foo.hi, which mentions M.T Then we look up M.T in M's type+-- environment, which is splatted into if_rec_types after we've built M's type+-- envt.+--+-- This is a dark and complicated part of GHC type checking, with a lot+-- of moving parts. Interested readers should also look at:+--+-- * Note [Knot-tying typecheckIface]+-- * Note [DFun knot-tying]+-- * Note [hsc_type_env_var hack]+--+-- There is also a wiki page on the subject, see:+--+-- https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/TyingTheKnot++tcIfaceTyConByName :: IfExtName -> IfL TyCon+tcIfaceTyConByName name+ = do { thing <- tcIfaceGlobal name+ ; return (tyThingTyCon thing) }++tcIfaceTyCon :: IfaceTyCon -> IfL TyCon+tcIfaceTyCon (IfaceTyCon name info)+ = do { thing <- tcIfaceGlobal name+ ; return $ case ifaceTyConIsPromoted info of+ IsNotPromoted -> tyThingTyCon thing+ IsPromoted -> promoteDataCon $ tyThingDataCon thing }++tcIfaceCoAxiom :: Name -> IfL (CoAxiom Branched)+tcIfaceCoAxiom name = do { thing <- tcIfaceImplicit name+ ; return (tyThingCoAxiom thing) }++tcIfaceDataCon :: Name -> IfL DataCon+tcIfaceDataCon name = do { thing <- tcIfaceGlobal name+ ; case thing of+ AConLike (RealDataCon dc) -> return dc+ _ -> pprPanic "tcIfaceExtDC" (ppr name$$ ppr thing) }++tcIfaceExtId :: Name -> IfL Id+tcIfaceExtId name = do { thing <- tcIfaceGlobal name+ ; case thing of+ AnId id -> return id+ _ -> pprPanic "tcIfaceExtId" (ppr name$$ ppr thing) }++-- See Note [Resolving never-exported Names in TcIface]+tcIfaceImplicit :: Name -> IfL TyThing+tcIfaceImplicit n = do+ lcl_env <- getLclEnv+ case if_implicits_env lcl_env of+ Nothing -> tcIfaceGlobal n+ Just tenv ->+ case lookupTypeEnv tenv n of+ Nothing -> pprPanic "tcIfaceInst" (ppr n $$ ppr tenv)+ Just tything -> return tything++{-+************************************************************************+* *+ Bindings+* *+************************************************************************+-}++bindIfaceId :: IfaceIdBndr -> (Id -> IfL a) -> IfL a+bindIfaceId (fs, ty) thing_inside+ = do { name <- newIfaceName (mkVarOccFS fs)+ ; ty' <- tcIfaceType ty+ ; let id = mkLocalIdOrCoVar name ty'+ ; extendIfaceIdEnv [id] (thing_inside id) }++bindIfaceIds :: [IfaceIdBndr] -> ([Id] -> IfL a) -> IfL a+bindIfaceIds [] thing_inside = thing_inside []+bindIfaceIds (b:bs) thing_inside+ = bindIfaceId b $ \b' ->+ bindIfaceIds bs $ \bs' ->+ thing_inside (b':bs')++bindIfaceBndr :: IfaceBndr -> (CoreBndr -> IfL a) -> IfL a+bindIfaceBndr (IfaceIdBndr bndr) thing_inside+ = bindIfaceId bndr thing_inside+bindIfaceBndr (IfaceTvBndr bndr) thing_inside+ = bindIfaceTyVar bndr thing_inside++bindIfaceBndrs :: [IfaceBndr] -> ([CoreBndr] -> IfL a) -> IfL a+bindIfaceBndrs [] thing_inside = thing_inside []+bindIfaceBndrs (b:bs) thing_inside+ = bindIfaceBndr b $ \ b' ->+ bindIfaceBndrs bs $ \ bs' ->+ thing_inside (b':bs')++-----------------------+bindIfaceForAllBndrs :: [IfaceForAllBndr] -> ([TyVarBinder] -> IfL a) -> IfL a+bindIfaceForAllBndrs [] thing_inside = thing_inside []+bindIfaceForAllBndrs (bndr:bndrs) thing_inside+ = bindIfaceForAllBndr bndr $ \tv vis ->+ bindIfaceForAllBndrs bndrs $ \bndrs' ->+ thing_inside (mkTyVarBinder vis tv : bndrs')++bindIfaceForAllBndr :: IfaceForAllBndr -> (TyVar -> ArgFlag -> IfL a) -> IfL a+bindIfaceForAllBndr (TvBndr tv vis) thing_inside+ = bindIfaceTyVar tv $ \tv' -> thing_inside tv' vis++bindIfaceTyVar :: IfaceTvBndr -> (TyVar -> IfL a) -> IfL a+bindIfaceTyVar (occ,kind) thing_inside+ = do { name <- newIfaceName (mkTyVarOccFS occ)+ ; tyvar <- mk_iface_tyvar name kind+ ; extendIfaceTyVarEnv [tyvar] (thing_inside tyvar) }++mk_iface_tyvar :: Name -> IfaceKind -> IfL TyVar+mk_iface_tyvar name ifKind+ = do { kind <- tcIfaceType ifKind+ ; return (Var.mkTyVar name kind) }++bindIfaceTyConBinders :: [IfaceTyConBinder]+ -> ([TyConBinder] -> IfL a) -> IfL a+bindIfaceTyConBinders [] thing_inside = thing_inside []+bindIfaceTyConBinders (b:bs) thing_inside+ = bindIfaceTyConBinderX bindIfaceTyVar b $ \ b' ->+ bindIfaceTyConBinders bs $ \ bs' ->+ thing_inside (b':bs')++bindIfaceTyConBinders_AT :: [IfaceTyConBinder]+ -> ([TyConBinder] -> IfL a) -> IfL a+-- Used for type variable in nested associated data/type declarations+-- where some of the type variables are already in scope+-- class C a where { data T a b }+-- Here 'a' is in scope when we look at the 'data T'+bindIfaceTyConBinders_AT [] thing_inside+ = thing_inside []+bindIfaceTyConBinders_AT (b : bs) thing_inside+ = bindIfaceTyConBinderX bind_tv b $ \b' ->+ bindIfaceTyConBinders_AT bs $ \bs' ->+ thing_inside (b':bs')+ where+ bind_tv tv thing+ = do { mb_tv <- lookupIfaceTyVar tv+ ; case mb_tv of+ Just b' -> thing b'+ Nothing -> bindIfaceTyVar tv thing }++bindIfaceTyConBinderX :: (IfaceTvBndr -> (TyVar -> IfL a) -> IfL a)+ -> IfaceTyConBinder+ -> (TyConBinder -> IfL a) -> IfL a+bindIfaceTyConBinderX bind_tv (TvBndr tv vis) thing_inside+ = bind_tv tv $ \tv' ->+ thing_inside (TvBndr tv' vis)
+ iface/TcIface.hs-boot view
@@ -0,0 +1,20 @@+module TcIface where++import IfaceSyn ( IfaceDecl, IfaceClsInst, IfaceFamInst, IfaceRule,+ IfaceAnnotation, IfaceCompleteMatch )+import TyCoRep ( TyThing )+import TcRnTypes ( IfL )+import InstEnv ( ClsInst )+import FamInstEnv ( FamInst )+import CoreSyn ( CoreRule )+import HscTypes ( TypeEnv, VectInfo, IfaceVectInfo, CompleteMatch )+import Module ( Module )+import Annotations ( Annotation )++tcIfaceDecl :: Bool -> IfaceDecl -> IfL TyThing+tcIfaceRules :: Bool -> [IfaceRule] -> IfL [CoreRule]+tcIfaceVectInfo :: Module -> TypeEnv -> IfaceVectInfo -> IfL VectInfo+tcIfaceInst :: IfaceClsInst -> IfL ClsInst+tcIfaceFamInst :: IfaceFamInst -> IfL FamInst+tcIfaceAnnotations :: [IfaceAnnotation] -> IfL [Annotation]+tcIfaceCompleteSigs :: [IfaceCompleteMatch] -> IfL [CompleteMatch]
+ iface/ToIface.hs view
@@ -0,0 +1,602 @@+{-# LANGUAGE CPP #-}++-- | Functions for converting Core things to interface file things.+module ToIface+ ( -- * Binders+ toIfaceTvBndr+ , toIfaceTvBndrs+ , toIfaceIdBndr+ , toIfaceBndr+ , toIfaceForAllBndr+ , toIfaceTyVarBinders+ , toIfaceTyVar+ -- * Types+ , toIfaceType, toIfaceTypeX+ , toIfaceKind+ , toIfaceTcArgs+ , toIfaceTyCon+ , toIfaceTyCon_name+ , toIfaceTyLit+ -- * Tidying types+ , tidyToIfaceType+ , tidyToIfaceContext+ , tidyToIfaceTcArgs+ -- * Coercions+ , toIfaceCoercion+ -- * Pattern synonyms+ , patSynToIfaceDecl+ -- * Expressions+ , toIfaceExpr+ , toIfaceBang+ , toIfaceSrcBang+ , toIfaceLetBndr+ , toIfaceIdDetails+ , toIfaceIdInfo+ , toIfUnfolding+ , toIfaceOneShot+ , toIfaceTickish+ , toIfaceBind+ , toIfaceAlt+ , toIfaceCon+ , toIfaceApp+ , toIfaceVar+ ) where++#include "HsVersions.h"++import IfaceSyn+import DataCon+import Id+import IdInfo+import CoreSyn+import TyCon hiding ( pprPromotionQuote )+import CoAxiom+import TysPrim ( eqPrimTyCon, eqReprPrimTyCon )+import TysWiredIn ( heqTyCon )+import MkId ( noinlineIdName )+import PrelNames+import Name+import BasicTypes+import Type+import PatSyn+import Outputable+import FastString+import Util+import Var+import VarEnv+import VarSet+import TyCoRep+import Demand ( isTopSig )++import Data.Maybe ( catMaybes )++----------------+toIfaceTvBndr :: TyVar -> IfaceTvBndr+toIfaceTvBndr tyvar = ( occNameFS (getOccName tyvar)+ , toIfaceKind (tyVarKind tyvar)+ )++toIfaceIdBndr :: Id -> (IfLclName, IfaceType)+toIfaceIdBndr id = (occNameFS (getOccName id), toIfaceType (idType id))++toIfaceTvBndrs :: [TyVar] -> [IfaceTvBndr]+toIfaceTvBndrs = map toIfaceTvBndr++toIfaceBndr :: Var -> IfaceBndr+toIfaceBndr var+ | isId var = IfaceIdBndr (toIfaceIdBndr var)+ | otherwise = IfaceTvBndr (toIfaceTvBndr var)++toIfaceTyVarBinder :: TyVarBndr TyVar vis -> TyVarBndr IfaceTvBndr vis+toIfaceTyVarBinder (TvBndr tv vis) = TvBndr (toIfaceTvBndr tv) vis++toIfaceTyVarBinders :: [TyVarBndr TyVar vis] -> [TyVarBndr IfaceTvBndr vis]+toIfaceTyVarBinders = map toIfaceTyVarBinder++{-+************************************************************************+* *+ Conversion from Type to IfaceType+* *+************************************************************************+-}++toIfaceKind :: Type -> IfaceType+toIfaceKind = toIfaceType++---------------------+toIfaceType :: Type -> IfaceType+toIfaceType = toIfaceTypeX emptyVarSet++toIfaceTypeX :: VarSet -> Type -> IfaceType+-- (toIfaceTypeX free ty)+-- translates the tyvars in 'free' as IfaceFreeTyVars+--+-- Synonyms are retained in the interface type+toIfaceTypeX fr (TyVarTy tv) -- See Note [TcTyVars in IfaceType] in IfaceType+ | tv `elemVarSet` fr = IfaceFreeTyVar tv+ | otherwise = IfaceTyVar (toIfaceTyVar tv)+toIfaceTypeX fr (AppTy t1 t2) = IfaceAppTy (toIfaceTypeX fr t1) (toIfaceTypeX fr t2)+toIfaceTypeX _ (LitTy n) = IfaceLitTy (toIfaceTyLit n)+toIfaceTypeX fr (ForAllTy b t) = IfaceForAllTy (toIfaceForAllBndr b)+ (toIfaceTypeX (fr `delVarSet` binderVar b) t)+toIfaceTypeX fr (FunTy t1 t2)+ | isPredTy t1 = IfaceDFunTy (toIfaceTypeX fr t1) (toIfaceTypeX fr t2)+ | otherwise = IfaceFunTy (toIfaceTypeX fr t1) (toIfaceTypeX fr t2)+toIfaceTypeX fr (CastTy ty co) = IfaceCastTy (toIfaceTypeX fr ty) (toIfaceCoercionX fr co)+toIfaceTypeX fr (CoercionTy co) = IfaceCoercionTy (toIfaceCoercionX fr co)++toIfaceTypeX fr (TyConApp tc tys)+ -- tuples+ | Just sort <- tyConTuple_maybe tc+ , n_tys == arity+ = IfaceTupleTy sort IsNotPromoted (toIfaceTcArgsX fr tc tys)++ | Just dc <- isPromotedDataCon_maybe tc+ , isTupleDataCon dc+ , n_tys == 2*arity+ = IfaceTupleTy BoxedTuple IsPromoted (toIfaceTcArgsX fr tc (drop arity tys))++ -- type equalities: see Note [Equality predicates in IfaceType]+ | tyConName tc == eqTyConName+ = let info = IfaceTyConInfo IsNotPromoted (IfaceEqualityTyCon True)+ in IfaceTyConApp (IfaceTyCon (tyConName tc) info) (toIfaceTcArgsX fr tc tys)++ | tc `elem` [ eqPrimTyCon, eqReprPrimTyCon, heqTyCon ]+ , [k1, k2, _t1, _t2] <- tys+ = let homogeneous = k1 `eqType` k2+ info = IfaceTyConInfo IsNotPromoted (IfaceEqualityTyCon homogeneous)+ in IfaceTyConApp (IfaceTyCon (tyConName tc) info) (toIfaceTcArgsX fr tc tys)++ -- other applications+ | otherwise+ = IfaceTyConApp (toIfaceTyCon tc) (toIfaceTcArgsX fr tc tys)+ where+ arity = tyConArity tc+ n_tys = length tys++toIfaceTyVar :: TyVar -> FastString+toIfaceTyVar = occNameFS . getOccName++toIfaceCoVar :: CoVar -> FastString+toIfaceCoVar = occNameFS . getOccName++toIfaceForAllBndr :: TyVarBinder -> IfaceForAllBndr+toIfaceForAllBndr (TvBndr v vis) = TvBndr (toIfaceTvBndr v) vis++----------------+toIfaceTyCon :: TyCon -> IfaceTyCon+toIfaceTyCon tc+ = IfaceTyCon tc_name info+ where+ tc_name = tyConName tc+ info = IfaceTyConInfo promoted sort+ promoted | isPromotedDataCon tc = IsPromoted+ | otherwise = IsNotPromoted++ tupleSort :: TyCon -> Maybe IfaceTyConSort+ tupleSort tc' =+ case tyConTuple_maybe tc' of+ Just UnboxedTuple -> let arity = tyConArity tc' `div` 2+ in Just $ IfaceTupleTyCon arity UnboxedTuple+ Just sort -> let arity = tyConArity tc'+ in Just $ IfaceTupleTyCon arity sort+ Nothing -> Nothing++ sort+ | Just tsort <- tupleSort tc = tsort++ | Just dcon <- isPromotedDataCon_maybe tc+ , let tc' = dataConTyCon dcon+ , Just tsort <- tupleSort tc' = tsort++ | isUnboxedSumTyCon tc+ , Just cons <- isDataSumTyCon_maybe tc = IfaceSumTyCon (length cons)++ | otherwise = IfaceNormalTyCon+++toIfaceTyCon_name :: Name -> IfaceTyCon+toIfaceTyCon_name n = IfaceTyCon n info+ where info = IfaceTyConInfo IsNotPromoted IfaceNormalTyCon+ -- Used for the "rough-match" tycon stuff,+ -- where pretty-printing is not an issue++toIfaceTyLit :: TyLit -> IfaceTyLit+toIfaceTyLit (NumTyLit x) = IfaceNumTyLit x+toIfaceTyLit (StrTyLit x) = IfaceStrTyLit x++----------------+toIfaceCoercion :: Coercion -> IfaceCoercion+toIfaceCoercion = toIfaceCoercionX emptyVarSet++toIfaceCoercionX :: VarSet -> Coercion -> IfaceCoercion+-- (toIfaceCoercionX free ty)+-- translates the tyvars in 'free' as IfaceFreeTyVars+toIfaceCoercionX fr co+ = go co+ where+ go (Refl r ty) = IfaceReflCo r (toIfaceType ty)+ go (CoVarCo cv) = IfaceCoVarCo (toIfaceCoVar cv)+ go (AppCo co1 co2) = IfaceAppCo (go co1) (go co2)+ go (SymCo co) = IfaceSymCo (go co)+ go (TransCo co1 co2) = IfaceTransCo (go co1) (go co2)+ go (NthCo d co) = IfaceNthCo d (go co)+ go (LRCo lr co) = IfaceLRCo lr (go co)+ go (InstCo co arg) = IfaceInstCo (go co) (go arg)+ go (CoherenceCo c1 c2) = IfaceCoherenceCo (go c1) (go c2)+ go (KindCo c) = IfaceKindCo (go c)+ go (SubCo co) = IfaceSubCo (go co)+ go (AxiomRuleCo co cs) = IfaceAxiomRuleCo (coaxrName co) (map go cs)+ go (AxiomInstCo c i cs) = IfaceAxiomInstCo (coAxiomName c) i (map go cs)+ go (UnivCo p r t1 t2) = IfaceUnivCo (go_prov p) r+ (toIfaceTypeX fr t1)+ (toIfaceTypeX fr t2)+ go (TyConAppCo r tc cos)+ | tc `hasKey` funTyConKey+ , [_,_,_,_] <- cos = pprPanic "toIfaceCoercion" (ppr co)+ | otherwise = IfaceTyConAppCo r (toIfaceTyCon tc) (map go cos)+ go (FunCo r co1 co2) = IfaceFunCo r (toIfaceCoercion co1)+ (toIfaceCoercion co2)++ go (ForAllCo tv k co) = IfaceForAllCo (toIfaceTvBndr tv)+ (toIfaceCoercionX fr' k)+ (toIfaceCoercionX fr' co)+ where+ fr' = fr `delVarSet` tv++ go_prov :: UnivCoProvenance -> IfaceUnivCoProv+ go_prov UnsafeCoerceProv = IfaceUnsafeCoerceProv+ go_prov (PhantomProv co) = IfacePhantomProv (go co)+ go_prov (ProofIrrelProv co) = IfaceProofIrrelProv (go co)+ go_prov (PluginProv str) = IfacePluginProv str+ go_prov (HoleProv h) = IfaceHoleProv (chUnique h)++toIfaceTcArgs :: TyCon -> [Type] -> IfaceTcArgs+toIfaceTcArgs = toIfaceTcArgsX emptyVarSet++toIfaceTcArgsX :: VarSet -> TyCon -> [Type] -> IfaceTcArgs+-- See Note [Suppressing invisible arguments]+-- We produce a result list of args describing visiblity+-- The awkward case is+-- T :: forall k. * -> k+-- And consider+-- T (forall j. blah) * blib+-- Is 'blib' visible? It depends on the visibility flag on j,+-- so we have to substitute for k. Annoying!+toIfaceTcArgsX fr tc ty_args+ = go (mkEmptyTCvSubst in_scope) (tyConKind tc) ty_args+ where+ in_scope = mkInScopeSet (tyCoVarsOfTypes ty_args)++ go _ _ [] = ITC_Nil+ go env ty ts+ | Just ty' <- coreView ty+ = go env ty' ts+ go env (ForAllTy (TvBndr tv vis) res) (t:ts)+ | isVisibleArgFlag vis = ITC_Vis t' ts'+ | otherwise = ITC_Invis t' ts'+ where+ t' = toIfaceTypeX fr t+ ts' = go (extendTvSubst env tv t) res ts++ go env (FunTy _ res) (t:ts) -- No type-class args in tycon apps+ = ITC_Vis (toIfaceTypeX fr t) (go env res ts)++ go env (TyVarTy tv) ts+ | Just ki <- lookupTyVar env tv = go env ki ts+ go env kind (t:ts) = WARN( True, ppr tc $$ ppr (tyConKind tc) $$ ppr ty_args )+ ITC_Vis (toIfaceTypeX fr t) (go env kind ts) -- Ill-kinded++tidyToIfaceType :: TidyEnv -> Type -> IfaceType+tidyToIfaceType env ty = toIfaceType (tidyType env ty)++tidyToIfaceTcArgs :: TidyEnv -> TyCon -> [Type] -> IfaceTcArgs+tidyToIfaceTcArgs env tc tys = toIfaceTcArgs tc (tidyTypes env tys)++tidyToIfaceContext :: TidyEnv -> ThetaType -> IfaceContext+tidyToIfaceContext env theta = map (tidyToIfaceType env) theta++{-+************************************************************************+* *+ Conversion of pattern synonyms+* *+************************************************************************+-}++patSynToIfaceDecl :: PatSyn -> IfaceDecl+patSynToIfaceDecl ps+ = IfacePatSyn { ifName = getName $ ps+ , ifPatMatcher = to_if_pr (patSynMatcher ps)+ , ifPatBuilder = fmap to_if_pr (patSynBuilder ps)+ , ifPatIsInfix = patSynIsInfix ps+ , ifPatUnivBndrs = map toIfaceForAllBndr univ_bndrs'+ , ifPatExBndrs = map toIfaceForAllBndr ex_bndrs'+ , ifPatProvCtxt = tidyToIfaceContext env2 prov_theta+ , ifPatReqCtxt = tidyToIfaceContext env2 req_theta+ , ifPatArgs = map (tidyToIfaceType env2) args+ , ifPatTy = tidyToIfaceType env2 rhs_ty+ , ifFieldLabels = (patSynFieldLabels ps)+ }+ where+ (_univ_tvs, req_theta, _ex_tvs, prov_theta, args, rhs_ty) = patSynSig ps+ univ_bndrs = patSynUnivTyVarBinders ps+ ex_bndrs = patSynExTyVarBinders ps+ (env1, univ_bndrs') = tidyTyVarBinders emptyTidyEnv univ_bndrs+ (env2, ex_bndrs') = tidyTyVarBinders env1 ex_bndrs+ to_if_pr (id, needs_dummy) = (idName id, needs_dummy)++{-+************************************************************************+* *+ Conversion of other things+* *+************************************************************************+-}++toIfaceBang :: TidyEnv -> HsImplBang -> IfaceBang+toIfaceBang _ HsLazy = IfNoBang+toIfaceBang _ (HsUnpack Nothing) = IfUnpack+toIfaceBang env (HsUnpack (Just co)) = IfUnpackCo (toIfaceCoercion (tidyCo env co))+toIfaceBang _ HsStrict = IfStrict++toIfaceSrcBang :: HsSrcBang -> IfaceSrcBang+toIfaceSrcBang (HsSrcBang _ unpk bang) = IfSrcBang unpk bang++toIfaceLetBndr :: Id -> IfaceLetBndr+toIfaceLetBndr id = IfLetBndr (occNameFS (getOccName id))+ (toIfaceType (idType id))+ (toIfaceIdInfo (idInfo id))+ (toIfaceJoinInfo (isJoinId_maybe id))+ -- Put into the interface file any IdInfo that CoreTidy.tidyLetBndr+ -- has left on the Id. See Note [IdInfo on nested let-bindings] in IfaceSyn++toIfaceIdDetails :: IdDetails -> IfaceIdDetails+toIfaceIdDetails VanillaId = IfVanillaId+toIfaceIdDetails (DFunId {}) = IfDFunId+toIfaceIdDetails (RecSelId { sel_naughty = n+ , sel_tycon = tc }) =+ let iface = case tc of+ RecSelData ty_con -> Left (toIfaceTyCon ty_con)+ RecSelPatSyn pat_syn -> Right (patSynToIfaceDecl pat_syn)+ in IfRecSelId iface n++ -- The remaining cases are all "implicit Ids" which don't+ -- appear in interface files at all+toIfaceIdDetails other = pprTrace "toIfaceIdDetails" (ppr other)+ IfVanillaId -- Unexpected; the other++toIfaceIdInfo :: IdInfo -> IfaceIdInfo+toIfaceIdInfo id_info+ = case catMaybes [arity_hsinfo, caf_hsinfo, strict_hsinfo,+ inline_hsinfo, unfold_hsinfo, levity_hsinfo] of+ [] -> NoInfo+ infos -> HasInfo infos+ -- NB: strictness and arity must appear in the list before unfolding+ -- See TcIface.tcUnfolding+ where+ ------------ Arity --------------+ arity_info = arityInfo id_info+ arity_hsinfo | arity_info == 0 = Nothing+ | otherwise = Just (HsArity arity_info)++ ------------ Caf Info --------------+ caf_info = cafInfo id_info+ caf_hsinfo = case caf_info of+ NoCafRefs -> Just HsNoCafRefs+ _other -> Nothing++ ------------ Strictness --------------+ -- No point in explicitly exporting TopSig+ sig_info = strictnessInfo id_info+ strict_hsinfo | not (isTopSig sig_info) = Just (HsStrictness sig_info)+ | otherwise = Nothing++ ------------ Unfolding --------------+ unfold_hsinfo = toIfUnfolding loop_breaker (unfoldingInfo id_info)+ loop_breaker = isStrongLoopBreaker (occInfo id_info)++ ------------ Inline prag --------------+ inline_prag = inlinePragInfo id_info+ inline_hsinfo | isDefaultInlinePragma inline_prag = Nothing+ | otherwise = Just (HsInline inline_prag)++ ------------ Levity polymorphism ----------+ levity_hsinfo | isNeverLevPolyIdInfo id_info = Just HsLevity+ | otherwise = Nothing++toIfaceJoinInfo :: Maybe JoinArity -> IfaceJoinInfo+toIfaceJoinInfo (Just ar) = IfaceJoinPoint ar+toIfaceJoinInfo Nothing = IfaceNotJoinPoint++--------------------------+toIfUnfolding :: Bool -> Unfolding -> Maybe IfaceInfoItem+toIfUnfolding lb (CoreUnfolding { uf_tmpl = rhs+ , uf_src = src+ , uf_guidance = guidance })+ = Just $ HsUnfold lb $+ case src of+ InlineStable+ -> case guidance of+ UnfWhen {ug_arity = arity, ug_unsat_ok = unsat_ok, ug_boring_ok = boring_ok }+ -> IfInlineRule arity unsat_ok boring_ok if_rhs+ _other -> IfCoreUnfold True if_rhs+ InlineCompulsory -> IfCompulsory if_rhs+ InlineRhs -> IfCoreUnfold False if_rhs+ -- Yes, even if guidance is UnfNever, expose the unfolding+ -- If we didn't want to expose the unfolding, TidyPgm would+ -- have stuck in NoUnfolding. For supercompilation we want+ -- to see that unfolding!+ where+ if_rhs = toIfaceExpr rhs++toIfUnfolding lb (DFunUnfolding { df_bndrs = bndrs, df_args = args })+ = Just (HsUnfold lb (IfDFunUnfold (map toIfaceBndr bndrs) (map toIfaceExpr args)))+ -- No need to serialise the data constructor;+ -- we can recover it from the type of the dfun++toIfUnfolding _ _+ = Nothing++{-+************************************************************************+* *+ Conversion of expressions+* *+************************************************************************+-}++toIfaceExpr :: CoreExpr -> IfaceExpr+toIfaceExpr (Var v) = toIfaceVar v+toIfaceExpr (Lit l) = IfaceLit l+toIfaceExpr (Type ty) = IfaceType (toIfaceType ty)+toIfaceExpr (Coercion co) = IfaceCo (toIfaceCoercion co)+toIfaceExpr (Lam x b) = IfaceLam (toIfaceBndr x, toIfaceOneShot x) (toIfaceExpr b)+toIfaceExpr (App f a) = toIfaceApp f [a]+toIfaceExpr (Case s x ty as)+ | null as = IfaceECase (toIfaceExpr s) (toIfaceType ty)+ | otherwise = IfaceCase (toIfaceExpr s) (getOccFS x) (map toIfaceAlt as)+toIfaceExpr (Let b e) = IfaceLet (toIfaceBind b) (toIfaceExpr e)+toIfaceExpr (Cast e co) = IfaceCast (toIfaceExpr e) (toIfaceCoercion co)+toIfaceExpr (Tick t e)+ | Just t' <- toIfaceTickish t = IfaceTick t' (toIfaceExpr e)+ | otherwise = toIfaceExpr e++toIfaceOneShot :: Id -> IfaceOneShot+toIfaceOneShot id | isId id+ , OneShotLam <- oneShotInfo (idInfo id)+ = IfaceOneShot+ | otherwise+ = IfaceNoOneShot++---------------------+toIfaceTickish :: Tickish Id -> Maybe IfaceTickish+toIfaceTickish (ProfNote cc tick push) = Just (IfaceSCC cc tick push)+toIfaceTickish (HpcTick modl ix) = Just (IfaceHpcTick modl ix)+toIfaceTickish (SourceNote src names) = Just (IfaceSource src names)+toIfaceTickish (Breakpoint {}) = Nothing+ -- Ignore breakpoints, since they are relevant only to GHCi, and+ -- should not be serialised (Trac #8333)++---------------------+toIfaceBind :: Bind Id -> IfaceBinding+toIfaceBind (NonRec b r) = IfaceNonRec (toIfaceLetBndr b) (toIfaceExpr r)+toIfaceBind (Rec prs) = IfaceRec [(toIfaceLetBndr b, toIfaceExpr r) | (b,r) <- prs]++---------------------+toIfaceAlt :: (AltCon, [Var], CoreExpr)+ -> (IfaceConAlt, [FastString], IfaceExpr)+toIfaceAlt (c,bs,r) = (toIfaceCon c, map getOccFS bs, toIfaceExpr r)++---------------------+toIfaceCon :: AltCon -> IfaceConAlt+toIfaceCon (DataAlt dc) = IfaceDataAlt (getName dc)+toIfaceCon (LitAlt l) = IfaceLitAlt l+toIfaceCon DEFAULT = IfaceDefault++---------------------+toIfaceApp :: Expr CoreBndr -> [Arg CoreBndr] -> IfaceExpr+toIfaceApp (App f a) as = toIfaceApp f (a:as)+toIfaceApp (Var v) as+ = case isDataConWorkId_maybe v of+ -- We convert the *worker* for tuples into IfaceTuples+ Just dc | saturated+ , Just tup_sort <- tyConTuple_maybe tc+ -> IfaceTuple tup_sort tup_args+ where+ val_args = dropWhile isTypeArg as+ saturated = val_args `lengthIs` idArity v+ tup_args = map toIfaceExpr val_args+ tc = dataConTyCon dc++ _ -> mkIfaceApps (toIfaceVar v) as++toIfaceApp e as = mkIfaceApps (toIfaceExpr e) as++mkIfaceApps :: IfaceExpr -> [CoreExpr] -> IfaceExpr+mkIfaceApps f as = foldl (\f a -> IfaceApp f (toIfaceExpr a)) f as++---------------------+toIfaceVar :: Id -> IfaceExpr+toIfaceVar v+ | Just fcall <- isFCallId_maybe v = IfaceFCall fcall (toIfaceType (idType v))+ -- Foreign calls have special syntax+ | isBootUnfolding (idUnfolding v)+ = IfaceApp (IfaceApp (IfaceExt noinlineIdName) (IfaceType (toIfaceType (idType v))))+ (IfaceExt name) -- don't use mkIfaceApps, or infinite loop+ -- See Note [Inlining and hs-boot files]+ | isExternalName name = IfaceExt name+ | otherwise = IfaceLcl (getOccFS name)+ where name = idName v+++{- Note [Inlining and hs-boot files]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this example (Trac #10083, #12789):++ ---------- RSR.hs-boot ------------+ module RSR where+ data RSR+ eqRSR :: RSR -> RSR -> Bool++ ---------- SR.hs ------------+ module SR where+ import {-# SOURCE #-} RSR+ data SR = MkSR RSR+ eqSR (MkSR r1) (MkSR r2) = eqRSR r1 r2++ ---------- RSR.hs ------------+ module RSR where+ import SR+ data RSR = MkRSR SR -- deriving( Eq )+ eqRSR (MkRSR s1) (MkRSR s2) = (eqSR s1 s2)+ foo x y = not (eqRSR x y)++When compiling RSR we get this code++ RSR.eqRSR :: RSR -> RSR -> Bool+ RSR.eqRSR = \ (ds1 :: RSR.RSR) (ds2 :: RSR.RSR) ->+ case ds1 of _ { RSR.MkRSR s1 ->+ case ds2 of _ { RSR.MkRSR s2 ->+ SR.eqSR s1 s2 }}++ RSR.foo :: RSR -> RSR -> Bool+ RSR.foo = \ (x :: RSR) (y :: RSR) -> not (RSR.eqRSR x y)++Now, when optimising foo:+ Inline eqRSR (small, non-rec)+ Inline eqSR (small, non-rec)+but the result of inlining eqSR from SR is another call to eqRSR, so+everything repeats. Neither eqSR nor eqRSR are (apparently) loop+breakers.++Solution: in the unfolding of eqSR in SR.hi, replace `eqRSR` in SR+with `noinline eqRSR`, so that eqRSR doesn't get inlined. This means+that when GHC inlines `eqSR`, it will not also inline `eqRSR`, exactly+as would have been the case if `foo` had been defined in SR.hs (and+marked as a loop-breaker).++But how do we arrange for this to happen? There are two ingredients:++ 1. When we serialize out unfoldings to IfaceExprs (toIfaceVar),+ for every variable reference we see if we are referring to an+ 'Id' that came from an hs-boot file. If so, we add a `noinline`+ to the reference.++ 2. But how do we know if a reference came from an hs-boot file+ or not? We could record this directly in the 'IdInfo', but+ actually we deduce this by looking at the unfolding: 'Id's+ that come from boot files are given a special unfolding+ (upon typechecking) 'BootUnfolding' which say that there is+ no unfolding, and the reason is because the 'Id' came from+ a boot file.++Here is a solution that doesn't work: when compiling RSR,+add a NOINLINE pragma to every function exported by the boot-file+for RSR (if it exists). Doing so makes the bootstrapped GHC itself+slower by 8% overall (on Trac #9872a-d, and T1969: the reason+is that these NOINLINE'd functions now can't be profitably inlined+outside of the hs-boot loop.++-}
+ iface/ToIface.hs-boot view
@@ -0,0 +1,17 @@+module ToIface where++import {-# SOURCE #-} TyCoRep+import {-# SOURCE #-} IfaceType+import Var ( TyVar, TyVarBinder )+import TyCon ( TyCon )+import VarSet( VarSet )++-- For TyCoRep+toIfaceType :: Type -> IfaceType+toIfaceTypeX :: VarSet -> Type -> IfaceType+toIfaceTyLit :: TyLit -> IfaceTyLit+toIfaceForAllBndr :: TyVarBinder -> IfaceForAllBndr+toIfaceTvBndr :: TyVar -> IfaceTvBndr+toIfaceTyCon :: TyCon -> IfaceTyCon+toIfaceTcArgs :: TyCon -> [Type] -> IfaceTcArgs+toIfaceCoercion :: Coercion -> IfaceCoercion
+ llvmGen/Llvm.hs view
@@ -0,0 +1,64 @@+-- ----------------------------------------------------------------------------+-- | This module supplies bindings to generate Llvm IR from Haskell+-- (<http://www.llvm.org/docs/LangRef.html>).+--+-- Note: this module is developed in a demand driven way. It is no complete+-- LLVM binding library in Haskell, but enough to generate code for GHC.+--+-- This code is derived from code taken from the Essential Haskell Compiler+-- (EHC) project (<http://www.cs.uu.nl/wiki/Ehc/WebHome>).+--++module Llvm (++ -- * Modules, Functions and Blocks+ LlvmModule(..),++ LlvmFunction(..), LlvmFunctionDecl(..),+ LlvmFunctions, LlvmFunctionDecls,+ LlvmStatement(..), LlvmExpression(..),+ LlvmBlocks, LlvmBlock(..), LlvmBlockId,+ LlvmParamAttr(..), LlvmParameter,++ -- * Atomic operations+ LlvmAtomicOp(..),++ -- * Fence synchronization+ LlvmSyncOrdering(..),++ -- * Call Handling+ LlvmCallConvention(..), LlvmCallType(..), LlvmParameterListType(..),+ LlvmLinkageType(..), LlvmFuncAttr(..),++ -- * Operations and Comparisons+ LlvmCmpOp(..), LlvmMachOp(..), LlvmCastOp(..),++ -- * Variables and Type System+ LlvmVar(..), LlvmStatic(..), LlvmLit(..), LlvmType(..),+ LlvmAlias, LMGlobal(..), LMString, LMSection, LMAlign,+ LMConst(..),++ -- ** Some basic types+ i64, i32, i16, i8, i1, i8Ptr, llvmWord, llvmWordPtr,++ -- ** Metadata types+ MetaExpr(..), MetaAnnot(..), MetaDecl(..), MetaId(..),++ -- ** Operations on the type system.+ isGlobal, getLitType, getVarType,+ getLink, getStatType, pVarLift, pVarLower,+ pLift, pLower, isInt, isFloat, isPointer, isVector, llvmWidthInBits,++ -- * Pretty Printing+ ppLit, ppName, ppPlainName,+ ppLlvmModule, ppLlvmComments, ppLlvmComment, ppLlvmGlobals,+ ppLlvmGlobal, ppLlvmFunctionDecls, ppLlvmFunctionDecl, ppLlvmFunctions,+ ppLlvmFunction, ppLlvmAlias, ppLlvmAliases, ppLlvmMetas, ppLlvmMeta,++ ) where++import Llvm.AbsSyn+import Llvm.MetaData+import Llvm.PpLlvm+import Llvm.Types+
+ llvmGen/Llvm/AbsSyn.hs view
@@ -0,0 +1,350 @@+--------------------------------------------------------------------------------+-- | The LLVM abstract syntax.+--++module Llvm.AbsSyn where++import Llvm.MetaData+import Llvm.Types++import Unique++-- | Block labels+type LlvmBlockId = Unique++-- | A block of LLVM code.+data LlvmBlock = LlvmBlock {+ -- | The code label for this block+ blockLabel :: LlvmBlockId,++ -- | A list of LlvmStatement's representing the code for this block.+ -- This list must end with a control flow statement.+ blockStmts :: [LlvmStatement]+ }++type LlvmBlocks = [LlvmBlock]++-- | An LLVM Module. This is a top level container in LLVM.+data LlvmModule = LlvmModule {+ -- | Comments to include at the start of the module.+ modComments :: [LMString],++ -- | LLVM Alias type definitions.+ modAliases :: [LlvmAlias],++ -- | LLVM meta data.+ modMeta :: [MetaDecl],++ -- | Global variables to include in the module.+ modGlobals :: [LMGlobal],++ -- | LLVM Functions used in this module but defined in other modules.+ modFwdDecls :: LlvmFunctionDecls,++ -- | LLVM Functions defined in this module.+ modFuncs :: LlvmFunctions+ }++-- | An LLVM Function+data LlvmFunction = LlvmFunction {+ -- | The signature of this declared function.+ funcDecl :: LlvmFunctionDecl,++ -- | The functions arguments+ funcArgs :: [LMString],++ -- | The function attributes.+ funcAttrs :: [LlvmFuncAttr],++ -- | The section to put the function into,+ funcSect :: LMSection,++ -- | Prefix data+ funcPrefix :: Maybe LlvmStatic,++ -- | The body of the functions.+ funcBody :: LlvmBlocks+ }++type LlvmFunctions = [LlvmFunction]++type SingleThreaded = Bool++-- | LLVM ordering types for synchronization purposes. (Introduced in LLVM+-- 3.0). Please see the LLVM documentation for a better description.+data LlvmSyncOrdering+ -- | Some partial order of operations exists.+ = SyncUnord+ -- | A single total order for operations at a single address exists.+ | SyncMonotonic+ -- | Acquire synchronization operation.+ | SyncAcquire+ -- | Release synchronization operation.+ | SyncRelease+ -- | Acquire + Release synchronization operation.+ | SyncAcqRel+ -- | Full sequential Consistency operation.+ | SyncSeqCst+ deriving (Show, Eq)++-- | LLVM atomic operations. Please see the @atomicrmw@ instruction in+-- the LLVM documentation for a complete description.+data LlvmAtomicOp+ = LAO_Xchg+ | LAO_Add+ | LAO_Sub+ | LAO_And+ | LAO_Nand+ | LAO_Or+ | LAO_Xor+ | LAO_Max+ | LAO_Min+ | LAO_Umax+ | LAO_Umin+ deriving (Show, Eq)++-- | Llvm Statements+data LlvmStatement+ {- |+ Assign an expression to an variable:+ * dest: Variable to assign to+ * source: Source expression+ -}+ = Assignment LlvmVar LlvmExpression++ {- |+ Memory fence operation+ -}+ | Fence Bool LlvmSyncOrdering++ {- |+ Always branch to the target label+ -}+ | Branch LlvmVar++ {- |+ Branch to label targetTrue if cond is true otherwise to label targetFalse+ * cond: condition that will be tested, must be of type i1+ * targetTrue: label to branch to if cond is true+ * targetFalse: label to branch to if cond is false+ -}+ | BranchIf LlvmVar LlvmVar LlvmVar++ {- |+ Comment+ Plain comment.+ -}+ | Comment [LMString]++ {- |+ Set a label on this position.+ * name: Identifier of this label, unique for this module+ -}+ | MkLabel LlvmBlockId++ {- |+ Store variable value in pointer ptr. If value is of type t then ptr must+ be of type t*.+ * value: Variable/Constant to store.+ * ptr: Location to store the value in+ -}+ | Store LlvmVar LlvmVar++ {- |+ Multiway branch+ * scrutinee: Variable or constant which must be of integer type that is+ determines which arm is chosen.+ * def: The default label if there is no match in target.+ * target: A list of (value,label) where the value is an integer+ constant and label the corresponding label to jump to if the+ scrutinee matches the value.+ -}+ | Switch LlvmVar LlvmVar [(LlvmVar, LlvmVar)]++ {- |+ Return a result.+ * result: The variable or constant to return+ -}+ | Return (Maybe LlvmVar)++ {- |+ An instruction for the optimizer that the code following is not reachable+ -}+ | Unreachable++ {- |+ Raise an expression to a statement (if don't want result or want to use+ Llvm unnamed values.+ -}+ | Expr LlvmExpression++ {- |+ A nop LLVM statement. Useful as its often more efficient to use this+ then to wrap LLvmStatement in a Just or [].+ -}+ | Nop++ {- |+ A LLVM statement with metadata attached to it.+ -}+ | MetaStmt [MetaAnnot] LlvmStatement++ deriving (Eq)+++-- | Llvm Expressions+data LlvmExpression+ {- |+ Allocate amount * sizeof(tp) bytes on the stack+ * tp: LlvmType to reserve room for+ * amount: The nr of tp's which must be allocated+ -}+ = Alloca LlvmType Int++ {- |+ Perform the machine operator op on the operands left and right+ * op: operator+ * left: left operand+ * right: right operand+ -}+ | LlvmOp LlvmMachOp LlvmVar LlvmVar++ {- |+ Perform a compare operation on the operands left and right+ * op: operator+ * left: left operand+ * right: right operand+ -}+ | Compare LlvmCmpOp LlvmVar LlvmVar++ {- |+ Extract a scalar element from a vector+ * val: The vector+ * idx: The index of the scalar within the vector+ -}+ | Extract LlvmVar LlvmVar++ {- |+ Extract a scalar element from a structure+ * val: The structure+ * idx: The index of the scalar within the structure+ Corresponds to "extractvalue" instruction.+ -}+ | ExtractV LlvmVar Int++ {- |+ Insert a scalar element into a vector+ * val: The source vector+ * elt: The scalar to insert+ * index: The index at which to insert the scalar+ -}+ | Insert LlvmVar LlvmVar LlvmVar++ {- |+ Allocate amount * sizeof(tp) bytes on the heap+ * tp: LlvmType to reserve room for+ * amount: The nr of tp's which must be allocated+ -}+ | Malloc LlvmType Int++ {- |+ Load the value at location ptr+ -}+ | Load LlvmVar++ {- |+ Atomic load of the value at location ptr+ -}+ | ALoad LlvmSyncOrdering SingleThreaded LlvmVar++ {- |+ Navigate in an structure, selecting elements+ * inbound: Is the pointer inbounds? (computed pointer doesn't overflow)+ * ptr: Location of the structure+ * indexes: A list of indexes to select the correct value.+ -}+ | GetElemPtr Bool LlvmVar [LlvmVar]++ {- |+ Cast the variable from to the to type. This is an abstraction of three+ cast operators in Llvm, inttoptr, prttoint and bitcast.+ * cast: Cast type+ * from: Variable to cast+ * to: type to cast to+ -}+ | Cast LlvmCastOp LlvmVar LlvmType++ {- |+ Atomic read-modify-write operation+ * op: Atomic operation+ * addr: Address to modify+ * operand: Operand to operation+ * ordering: Ordering requirement+ -}+ | AtomicRMW LlvmAtomicOp LlvmVar LlvmVar LlvmSyncOrdering++ {- |+ Compare-and-exchange operation+ * addr: Address to modify+ * old: Expected value+ * new: New value+ * suc_ord: Ordering required in success case+ * fail_ord: Ordering required in failure case, can be no stronger than+ suc_ord++ Result is an @i1@, true if store was successful.+ -}+ | CmpXChg LlvmVar LlvmVar LlvmVar LlvmSyncOrdering LlvmSyncOrdering++ {- |+ Call a function. The result is the value of the expression.+ * tailJumps: CallType to signal if the function should be tail called+ * fnptrval: An LLVM value containing a pointer to a function to be+ invoked. Can be indirect. Should be LMFunction type.+ * args: Concrete arguments for the parameters+ * attrs: A list of function attributes for the call. Only NoReturn,+ NoUnwind, ReadOnly and ReadNone are valid here.+ -}+ | Call LlvmCallType LlvmVar [LlvmVar] [LlvmFuncAttr]++ {- |+ Call a function as above but potentially taking metadata as arguments.+ * tailJumps: CallType to signal if the function should be tail called+ * fnptrval: An LLVM value containing a pointer to a function to be+ invoked. Can be indirect. Should be LMFunction type.+ * args: Arguments that may include metadata.+ * attrs: A list of function attributes for the call. Only NoReturn,+ NoUnwind, ReadOnly and ReadNone are valid here.+ -}+ | CallM LlvmCallType LlvmVar [MetaExpr] [LlvmFuncAttr]++ {- |+ Merge variables from different basic blocks which are predecessors of this+ basic block in a new variable of type tp.+ * tp: type of the merged variable, must match the types of the+ predecessor variables.+ * precessors: A list of variables and the basic block that they originate+ from.+ -}+ | Phi LlvmType [(LlvmVar,LlvmVar)]++ {- |+ Inline assembly expression. Syntax is very similar to the style used by GCC.+ * assembly: Actual inline assembly code.+ * constraints: Operand constraints.+ * return ty: Return type of function.+ * vars: Any variables involved in the assembly code.+ * sideeffect: Does the expression have side effects not visible from the+ constraints list.+ * alignstack: Should the stack be conservatively aligned before this+ expression is executed.+ -}+ | Asm LMString LMString LlvmType [LlvmVar] Bool Bool++ {- |+ A LLVM expression with metadata attached to it.+ -}+ | MExpr [MetaAnnot] LlvmExpression++ deriving (Eq)+
+ llvmGen/Llvm/MetaData.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module Llvm.MetaData where++import Llvm.Types+import Outputable++-- The LLVM Metadata System.+--+-- The LLVM metadata feature is poorly documented but roughly follows the+-- following design:+-- * Metadata can be constructed in a few different ways (See below).+-- * After which it can either be attached to LLVM statements to pass along+-- extra information to the optimizer and code generator OR specifically named+-- metadata has an affect on the whole module (i.e., linking behaviour).+--+--+-- # Constructing metadata+-- Metadata comes largely in three forms:+--+-- * Metadata expressions -- these are the raw metadata values that encode+-- information. They consist of metadata strings, metadata nodes, regular+-- LLVM values (both literals and references to global variables) and+-- metadata expressions (i.e., recursive data type). Some examples:+-- !{ !"hello", !0, i32 0 }+-- !{ !1, !{ i32 0 } }+--+-- * Metadata nodes -- global metadata variables that attach a metadata+-- expression to a number. For example:+-- !0 = !{ [<metadata expressions>] !}+--+-- * Named metadata -- global metadata variables that attach a metadata nodes+-- to a name. Used ONLY to communicated module level information to LLVM+-- through a meaningful name. For example:+-- !llvm.module.linkage = !{ !0, !1 }+--+--+-- # Using Metadata+-- Using metadata depends on the form it is in:+--+-- * Attach to instructions -- metadata can be attached to LLVM instructions+-- using a specific reference as follows:+-- %l = load i32* @glob, !nontemporal !10+-- %m = load i32* @glob, !nontemporal !{ i32 0, !{ i32 0 } }+-- Only metadata nodes or expressions can be attached, named metadata cannot.+-- Refer to LLVM documentation for which instructions take metadata and its+-- meaning.+--+-- * As arguments -- llvm functions can take metadata as arguments, for+-- example:+-- call void @llvm.dbg.value(metadata !{ i32 0 }, i64 0, metadata !1)+-- As with instructions, only metadata nodes or expressions can be attached.+--+-- * As a named metadata -- Here the metadata is simply declared in global+-- scope using a specific name to communicate module level information to LLVM.+-- For example:+-- !llvm.module.linkage = !{ !0, !1 }+--++-- | A reference to an un-named metadata node.+newtype MetaId = MetaId Int+ deriving (Eq, Ord, Enum)++instance Outputable MetaId where+ ppr (MetaId n) = char '!' <> int n++-- | LLVM metadata expressions+data MetaExpr = MetaStr !LMString+ | MetaNode !MetaId+ | MetaVar !LlvmVar+ | MetaStruct [MetaExpr]+ deriving (Eq)++instance Outputable MetaExpr where+ ppr (MetaVar (LMLitVar (LMNullLit _))) = text "null"+ ppr (MetaStr s ) = char '!' <> doubleQuotes (ftext s)+ ppr (MetaNode n ) = ppr n+ ppr (MetaVar v ) = ppr v+ ppr (MetaStruct es) = char '!' <> braces (ppCommaJoin es)++-- | Associates some metadata with a specific label for attaching to an+-- instruction.+data MetaAnnot = MetaAnnot LMString MetaExpr+ deriving (Eq)++-- | Metadata declarations. Metadata can only be declared in global scope.+data MetaDecl+ -- | Named metadata. Only used for communicating module information to+ -- LLVM. ('!name = !{ [!<n>] }' form).+ = MetaNamed !LMString [MetaId]+ -- | Metadata node declaration.+ -- ('!0 = metadata !{ <metadata expression> }' form).+ | MetaUnnamed !MetaId !MetaExpr
+ llvmGen/Llvm/PpLlvm.hs view
@@ -0,0 +1,497 @@+{-# LANGUAGE CPP #-}++--------------------------------------------------------------------------------+-- | Pretty print LLVM IR Code.+--++module Llvm.PpLlvm (++ -- * Top level LLVM objects.+ ppLlvmModule,+ ppLlvmComments,+ ppLlvmComment,+ ppLlvmGlobals,+ ppLlvmGlobal,+ ppLlvmAliases,+ ppLlvmAlias,+ ppLlvmMetas,+ ppLlvmMeta,+ ppLlvmFunctionDecls,+ ppLlvmFunctionDecl,+ ppLlvmFunctions,+ ppLlvmFunction,++ ) where++#include "HsVersions.h"++import Llvm.AbsSyn+import Llvm.MetaData+import Llvm.Types++import Data.List ( intersperse )+import Outputable+import Unique+import FastString ( sLit )++--------------------------------------------------------------------------------+-- * Top Level Print functions+--------------------------------------------------------------------------------++-- | Print out a whole LLVM module.+ppLlvmModule :: LlvmModule -> SDoc+ppLlvmModule (LlvmModule comments aliases meta globals decls funcs)+ = ppLlvmComments comments $+$ newLine+ $+$ ppLlvmAliases aliases $+$ newLine+ $+$ ppLlvmMetas meta $+$ newLine+ $+$ ppLlvmGlobals globals $+$ newLine+ $+$ ppLlvmFunctionDecls decls $+$ newLine+ $+$ ppLlvmFunctions funcs++-- | Print out a multi-line comment, can be inside a function or on its own+ppLlvmComments :: [LMString] -> SDoc+ppLlvmComments comments = vcat $ map ppLlvmComment comments++-- | Print out a comment, can be inside a function or on its own+ppLlvmComment :: LMString -> SDoc+ppLlvmComment com = semi <+> ftext com+++-- | Print out a list of global mutable variable definitions+ppLlvmGlobals :: [LMGlobal] -> SDoc+ppLlvmGlobals ls = vcat $ map ppLlvmGlobal ls++-- | Print out a global mutable variable definition+ppLlvmGlobal :: LMGlobal -> SDoc+ppLlvmGlobal (LMGlobal var@(LMGlobalVar _ _ link x a c) dat) =+ let sect = case x of+ Just x' -> text ", section" <+> doubleQuotes (ftext x')+ Nothing -> empty++ align = case a of+ Just a' -> text ", align" <+> int a'+ Nothing -> empty++ rhs = case dat of+ Just stat -> pprSpecialStatic stat+ Nothing -> ppr (pLower $ getVarType var)++ -- Position of linkage is different for aliases.+ const = case c of+ Global -> text "global"+ Constant -> text "constant"+ Alias -> text "alias"++ in ppAssignment var $ ppr link <+> const <+> rhs <> sect <> align+ $+$ newLine++ppLlvmGlobal (LMGlobal var val) = sdocWithDynFlags $ \dflags ->+ error $ "Non Global var ppr as global! "+ ++ showSDoc dflags (ppr var) ++ " " ++ showSDoc dflags (ppr val)+++-- | Print out a list of LLVM type aliases.+ppLlvmAliases :: [LlvmAlias] -> SDoc+ppLlvmAliases tys = vcat $ map ppLlvmAlias tys++-- | Print out an LLVM type alias.+ppLlvmAlias :: LlvmAlias -> SDoc+ppLlvmAlias (name, ty)+ = char '%' <> ftext name <+> equals <+> text "type" <+> ppr ty+++-- | Print out a list of LLVM metadata.+ppLlvmMetas :: [MetaDecl] -> SDoc+ppLlvmMetas metas = vcat $ map ppLlvmMeta metas++-- | Print out an LLVM metadata definition.+ppLlvmMeta :: MetaDecl -> SDoc+ppLlvmMeta (MetaUnnamed n m)+ = ppr n <+> equals <+> ppr m++ppLlvmMeta (MetaNamed n m)+ = exclamation <> ftext n <+> equals <+> exclamation <> braces nodes+ where+ nodes = hcat $ intersperse comma $ map ppr m+++-- | Print out a list of function definitions.+ppLlvmFunctions :: LlvmFunctions -> SDoc+ppLlvmFunctions funcs = vcat $ map ppLlvmFunction funcs++-- | Print out a function definition.+ppLlvmFunction :: LlvmFunction -> SDoc+ppLlvmFunction fun =+ let attrDoc = ppSpaceJoin (funcAttrs fun)+ secDoc = case funcSect fun of+ Just s' -> text "section" <+> (doubleQuotes $ ftext s')+ Nothing -> empty+ prefixDoc = case funcPrefix fun of+ Just v -> text "prefix" <+> ppr v+ Nothing -> empty+ in text "define" <+> ppLlvmFunctionHeader (funcDecl fun) (funcArgs fun)+ <+> attrDoc <+> secDoc <+> prefixDoc+ $+$ lbrace+ $+$ ppLlvmBlocks (funcBody fun)+ $+$ rbrace+ $+$ newLine+ $+$ newLine++-- | Print out a function definition header.+ppLlvmFunctionHeader :: LlvmFunctionDecl -> [LMString] -> SDoc+ppLlvmFunctionHeader (LlvmFunctionDecl n l c r varg p a) args+ = let varg' = case varg of+ VarArgs | null p -> sLit "..."+ | otherwise -> sLit ", ..."+ _otherwise -> sLit ""+ align = case a of+ Just a' -> text " align " <> ppr a'+ Nothing -> empty+ args' = map (\((ty,p),n) -> ppr ty <+> ppSpaceJoin p <+> char '%'+ <> ftext n)+ (zip p args)+ in ppr l <+> ppr c <+> ppr r <+> char '@' <> ftext n <> lparen <>+ (hsep $ punctuate comma args') <> ptext varg' <> rparen <> align++-- | Print out a list of function declaration.+ppLlvmFunctionDecls :: LlvmFunctionDecls -> SDoc+ppLlvmFunctionDecls decs = vcat $ map ppLlvmFunctionDecl decs++-- | Print out a function declaration.+-- Declarations define the function type but don't define the actual body of+-- the function.+ppLlvmFunctionDecl :: LlvmFunctionDecl -> SDoc+ppLlvmFunctionDecl (LlvmFunctionDecl n l c r varg p a)+ = let varg' = case varg of+ VarArgs | null p -> sLit "..."+ | otherwise -> sLit ", ..."+ _otherwise -> sLit ""+ align = case a of+ Just a' -> text " align" <+> ppr a'+ Nothing -> empty+ args = hcat $ intersperse (comma <> space) $+ map (\(t,a) -> ppr t <+> ppSpaceJoin a) p+ in text "declare" <+> ppr l <+> ppr c <+> ppr r <+> char '@' <>+ ftext n <> lparen <> args <> ptext varg' <> rparen <> align $+$ newLine+++-- | Print out a list of LLVM blocks.+ppLlvmBlocks :: LlvmBlocks -> SDoc+ppLlvmBlocks blocks = vcat $ map ppLlvmBlock blocks++-- | Print out an LLVM block.+-- It must be part of a function definition.+ppLlvmBlock :: LlvmBlock -> SDoc+ppLlvmBlock (LlvmBlock blockId stmts) =+ let isLabel (MkLabel _) = True+ isLabel _ = False+ (block, rest) = break isLabel stmts+ ppRest = case rest of+ MkLabel id:xs -> ppLlvmBlock (LlvmBlock id xs)+ _ -> empty+ in ppLlvmBlockLabel blockId+ $+$ (vcat $ map ppLlvmStatement block)+ $+$ newLine+ $+$ ppRest++-- | Print out an LLVM block label.+ppLlvmBlockLabel :: LlvmBlockId -> SDoc+ppLlvmBlockLabel id = pprUniqueAlways id <> colon+++-- | Print out an LLVM statement.+ppLlvmStatement :: LlvmStatement -> SDoc+ppLlvmStatement stmt =+ let ind = (text " " <>)+ in case stmt of+ Assignment dst expr -> ind $ ppAssignment dst (ppLlvmExpression expr)+ Fence st ord -> ind $ ppFence st ord+ Branch target -> ind $ ppBranch target+ BranchIf cond ifT ifF -> ind $ ppBranchIf cond ifT ifF+ Comment comments -> ind $ ppLlvmComments comments+ MkLabel label -> ppLlvmBlockLabel label+ Store value ptr -> ind $ ppStore value ptr+ Switch scrut def tgs -> ind $ ppSwitch scrut def tgs+ Return result -> ind $ ppReturn result+ Expr expr -> ind $ ppLlvmExpression expr+ Unreachable -> ind $ text "unreachable"+ Nop -> empty+ MetaStmt meta s -> ppMetaStatement meta s+++-- | Print out an LLVM expression.+ppLlvmExpression :: LlvmExpression -> SDoc+ppLlvmExpression expr+ = case expr of+ Alloca tp amount -> ppAlloca tp amount+ LlvmOp op left right -> ppMachOp op left right+ Call tp fp args attrs -> ppCall tp fp (map MetaVar args) attrs+ CallM tp fp args attrs -> ppCall tp fp args attrs+ Cast op from to -> ppCast op from to+ Compare op left right -> ppCmpOp op left right+ Extract vec idx -> ppExtract vec idx+ ExtractV struct idx -> ppExtractV struct idx+ Insert vec elt idx -> ppInsert vec elt idx+ GetElemPtr inb ptr indexes -> ppGetElementPtr inb ptr indexes+ Load ptr -> ppLoad ptr+ ALoad ord st ptr -> ppALoad ord st ptr+ Malloc tp amount -> ppMalloc tp amount+ AtomicRMW aop tgt src ordering -> ppAtomicRMW aop tgt src ordering+ CmpXChg addr old new s_ord f_ord -> ppCmpXChg addr old new s_ord f_ord+ Phi tp precessors -> ppPhi tp precessors+ Asm asm c ty v se sk -> ppAsm asm c ty v se sk+ MExpr meta expr -> ppMetaExpr meta expr+++--------------------------------------------------------------------------------+-- * Individual print functions+--------------------------------------------------------------------------------++-- | Should always be a function pointer. So a global var of function type+-- (since globals are always pointers) or a local var of pointer function type.+ppCall :: LlvmCallType -> LlvmVar -> [MetaExpr] -> [LlvmFuncAttr] -> SDoc+ppCall ct fptr args attrs = case fptr of+ --+ -- if local var function pointer, unwrap+ LMLocalVar _ (LMPointer (LMFunction d)) -> ppCall' d++ -- should be function type otherwise+ LMGlobalVar _ (LMFunction d) _ _ _ _ -> ppCall' d++ -- not pointer or function, so error+ _other -> error $ "ppCall called with non LMFunction type!\nMust be "+ ++ " called with either global var of function type or "+ ++ "local var of pointer function type."++ where+ ppCall' (LlvmFunctionDecl _ _ cc ret argTy params _) =+ let tc = if ct == TailCall then text "tail " else empty+ ppValues = hsep $ punctuate comma $ map ppCallMetaExpr args+ ppArgTy = (ppCommaJoin $ map fst params) <>+ (case argTy of+ VarArgs -> text ", ..."+ FixedArgs -> empty)+ fnty = space <> lparen <> ppArgTy <> rparen+ attrDoc = ppSpaceJoin attrs+ in tc <> text "call" <+> ppr cc <+> ppr ret+ <> fnty <+> ppName fptr <> lparen <+> ppValues+ <+> rparen <+> attrDoc++ -- Metadata needs to be marked as having the `metadata` type when used+ -- in a call argument+ ppCallMetaExpr (MetaVar v) = ppr v+ ppCallMetaExpr v = text "metadata" <+> ppr v++ppMachOp :: LlvmMachOp -> LlvmVar -> LlvmVar -> SDoc+ppMachOp op left right =+ (ppr op) <+> (ppr (getVarType left)) <+> ppName left+ <> comma <+> ppName right+++ppCmpOp :: LlvmCmpOp -> LlvmVar -> LlvmVar -> SDoc+ppCmpOp op left right =+ let cmpOp+ | isInt (getVarType left) && isInt (getVarType right) = text "icmp"+ | isFloat (getVarType left) && isFloat (getVarType right) = text "fcmp"+ | otherwise = text "icmp" -- Just continue as its much easier to debug+ {-+ | otherwise = error ("can't compare different types, left = "+ ++ (show $ getVarType left) ++ ", right = "+ ++ (show $ getVarType right))+ -}+ in cmpOp <+> ppr op <+> ppr (getVarType left)+ <+> ppName left <> comma <+> ppName right+++ppAssignment :: LlvmVar -> SDoc -> SDoc+ppAssignment var expr = ppName var <+> equals <+> expr++ppFence :: Bool -> LlvmSyncOrdering -> SDoc+ppFence st ord =+ let singleThread = case st of True -> text "singlethread"+ False -> empty+ in text "fence" <+> singleThread <+> ppSyncOrdering ord++ppSyncOrdering :: LlvmSyncOrdering -> SDoc+ppSyncOrdering SyncUnord = text "unordered"+ppSyncOrdering SyncMonotonic = text "monotonic"+ppSyncOrdering SyncAcquire = text "acquire"+ppSyncOrdering SyncRelease = text "release"+ppSyncOrdering SyncAcqRel = text "acq_rel"+ppSyncOrdering SyncSeqCst = text "seq_cst"++ppAtomicOp :: LlvmAtomicOp -> SDoc+ppAtomicOp LAO_Xchg = text "xchg"+ppAtomicOp LAO_Add = text "add"+ppAtomicOp LAO_Sub = text "sub"+ppAtomicOp LAO_And = text "and"+ppAtomicOp LAO_Nand = text "nand"+ppAtomicOp LAO_Or = text "or"+ppAtomicOp LAO_Xor = text "xor"+ppAtomicOp LAO_Max = text "max"+ppAtomicOp LAO_Min = text "min"+ppAtomicOp LAO_Umax = text "umax"+ppAtomicOp LAO_Umin = text "umin"++ppAtomicRMW :: LlvmAtomicOp -> LlvmVar -> LlvmVar -> LlvmSyncOrdering -> SDoc+ppAtomicRMW aop tgt src ordering =+ text "atomicrmw" <+> ppAtomicOp aop <+> ppr tgt <> comma+ <+> ppr src <+> ppSyncOrdering ordering++ppCmpXChg :: LlvmVar -> LlvmVar -> LlvmVar+ -> LlvmSyncOrdering -> LlvmSyncOrdering -> SDoc+ppCmpXChg addr old new s_ord f_ord =+ text "cmpxchg" <+> ppr addr <> comma <+> ppr old <> comma <+> ppr new+ <+> ppSyncOrdering s_ord <+> ppSyncOrdering f_ord++-- XXX: On x86, vector types need to be 16-byte aligned for aligned access, but+-- we have no way of guaranteeing that this is true with GHC (we would need to+-- modify the layout of the stack and closures, change the storage manager,+-- etc.). So, we blindly tell LLVM that *any* vector store or load could be+-- unaligned. In the future we may be able to guarantee that certain vector+-- access patterns are aligned, in which case we will need a more granular way+-- of specifying alignment.++ppLoad :: LlvmVar -> SDoc+ppLoad var = text "load" <+> ppr derefType <> comma <+> ppr var <> align+ where+ derefType = pLower $ getVarType var+ align | isVector . pLower . getVarType $ var = text ", align 1"+ | otherwise = empty++ppALoad :: LlvmSyncOrdering -> SingleThreaded -> LlvmVar -> SDoc+ppALoad ord st var = sdocWithDynFlags $ \dflags ->+ let alignment = (llvmWidthInBits dflags $ getVarType var) `quot` 8+ align = text ", align" <+> ppr alignment+ sThreaded | st = text " singlethread"+ | otherwise = empty+ derefType = pLower $ getVarType var+ in text "load atomic" <+> ppr derefType <> comma <+> ppr var <> sThreaded+ <+> ppSyncOrdering ord <> align++ppStore :: LlvmVar -> LlvmVar -> SDoc+ppStore val dst+ | isVecPtrVar dst = text "store" <+> ppr val <> comma <+> ppr dst <>+ comma <+> text "align 1"+ | otherwise = text "store" <+> ppr val <> comma <+> ppr dst+ where+ isVecPtrVar :: LlvmVar -> Bool+ isVecPtrVar = isVector . pLower . getVarType+++ppCast :: LlvmCastOp -> LlvmVar -> LlvmType -> SDoc+ppCast op from to+ = ppr op+ <+> ppr (getVarType from) <+> ppName from+ <+> text "to"+ <+> ppr to+++ppMalloc :: LlvmType -> Int -> SDoc+ppMalloc tp amount =+ let amount' = LMLitVar $ LMIntLit (toInteger amount) i32+ in text "malloc" <+> ppr tp <> comma <+> ppr amount'+++ppAlloca :: LlvmType -> Int -> SDoc+ppAlloca tp amount =+ let amount' = LMLitVar $ LMIntLit (toInteger amount) i32+ in text "alloca" <+> ppr tp <> comma <+> ppr amount'+++ppGetElementPtr :: Bool -> LlvmVar -> [LlvmVar] -> SDoc+ppGetElementPtr inb ptr idx =+ let indexes = comma <+> ppCommaJoin idx+ inbound = if inb then text "inbounds" else empty+ derefType = pLower $ getVarType ptr+ in text "getelementptr" <+> inbound <+> ppr derefType <> comma <+> ppr ptr+ <> indexes+++ppReturn :: Maybe LlvmVar -> SDoc+ppReturn (Just var) = text "ret" <+> ppr var+ppReturn Nothing = text "ret" <+> ppr LMVoid+++ppBranch :: LlvmVar -> SDoc+ppBranch var = text "br" <+> ppr var+++ppBranchIf :: LlvmVar -> LlvmVar -> LlvmVar -> SDoc+ppBranchIf cond trueT falseT+ = text "br" <+> ppr cond <> comma <+> ppr trueT <> comma <+> ppr falseT+++ppPhi :: LlvmType -> [(LlvmVar,LlvmVar)] -> SDoc+ppPhi tp preds =+ let ppPreds (val, label) = brackets $ ppName val <> comma <+> ppName label+ in text "phi" <+> ppr tp <+> hsep (punctuate comma $ map ppPreds preds)+++ppSwitch :: LlvmVar -> LlvmVar -> [(LlvmVar,LlvmVar)] -> SDoc+ppSwitch scrut dflt targets =+ let ppTarget (val, lab) = ppr val <> comma <+> ppr lab+ ppTargets xs = brackets $ vcat (map ppTarget xs)+ in text "switch" <+> ppr scrut <> comma <+> ppr dflt+ <+> ppTargets targets+++ppAsm :: LMString -> LMString -> LlvmType -> [LlvmVar] -> Bool -> Bool -> SDoc+ppAsm asm constraints rty vars sideeffect alignstack =+ let asm' = doubleQuotes $ ftext asm+ cons = doubleQuotes $ ftext constraints+ rty' = ppr rty+ vars' = lparen <+> ppCommaJoin vars <+> rparen+ side = if sideeffect then text "sideeffect" else empty+ align = if alignstack then text "alignstack" else empty+ in text "call" <+> rty' <+> text "asm" <+> side <+> align <+> asm' <> comma+ <+> cons <> vars'++ppExtract :: LlvmVar -> LlvmVar -> SDoc+ppExtract vec idx =+ text "extractelement"+ <+> ppr (getVarType vec) <+> ppName vec <> comma+ <+> ppr idx++ppExtractV :: LlvmVar -> Int -> SDoc+ppExtractV struct idx =+ text "extractvalue"+ <+> ppr (getVarType struct) <+> ppName struct <> comma+ <+> ppr idx++ppInsert :: LlvmVar -> LlvmVar -> LlvmVar -> SDoc+ppInsert vec elt idx =+ text "insertelement"+ <+> ppr (getVarType vec) <+> ppName vec <> comma+ <+> ppr (getVarType elt) <+> ppName elt <> comma+ <+> ppr idx+++ppMetaStatement :: [MetaAnnot] -> LlvmStatement -> SDoc+ppMetaStatement meta stmt = ppLlvmStatement stmt <> ppMetaAnnots meta++ppMetaExpr :: [MetaAnnot] -> LlvmExpression -> SDoc+ppMetaExpr meta expr = ppLlvmExpression expr <> ppMetaAnnots meta++ppMetaAnnots :: [MetaAnnot] -> SDoc+ppMetaAnnots meta = hcat $ map ppMeta meta+ where+ ppMeta (MetaAnnot name e)+ = comma <+> exclamation <> ftext name <+>+ case e of+ MetaNode n -> ppr n+ MetaStruct ms -> exclamation <> braces (ppCommaJoin ms)+ other -> exclamation <> braces (ppr other) -- possible?+++--------------------------------------------------------------------------------+-- * Misc functions+--------------------------------------------------------------------------------++-- | Blank line.+newLine :: SDoc+newLine = empty++-- | Exclamation point.+exclamation :: SDoc+exclamation = char '!'
+ llvmGen/Llvm/Types.hs view
@@ -0,0 +1,886 @@+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}++--------------------------------------------------------------------------------+-- | The LLVM Type System.+--++module Llvm.Types where++#include "HsVersions.h"++import Data.Char+import Data.Int+import Numeric++import DynFlags+import FastString+import Outputable+import Unique++-- from NCG+import PprBase++import GHC.Float++-- -----------------------------------------------------------------------------+-- * LLVM Basic Types and Variables+--++-- | A global mutable variable. Maybe defined or external+data LMGlobal = LMGlobal {+ getGlobalVar :: LlvmVar, -- ^ Returns the variable of the 'LMGlobal'+ getGlobalValue :: Maybe LlvmStatic -- ^ Return the value of the 'LMGlobal'+ }++-- | A String in LLVM+type LMString = FastString++-- | A type alias+type LlvmAlias = (LMString, LlvmType)++-- | Llvm Types+data LlvmType+ = LMInt Int -- ^ An integer with a given width in bits.+ | LMFloat -- ^ 32 bit floating point+ | LMDouble -- ^ 64 bit floating point+ | LMFloat80 -- ^ 80 bit (x86 only) floating point+ | LMFloat128 -- ^ 128 bit floating point+ | LMPointer LlvmType -- ^ A pointer to a 'LlvmType'+ | LMArray Int LlvmType -- ^ An array of 'LlvmType'+ | LMVector Int LlvmType -- ^ A vector of 'LlvmType'+ | LMLabel -- ^ A 'LlvmVar' can represent a label (address)+ | LMVoid -- ^ Void type+ | LMStruct [LlvmType] -- ^ Packed structure type+ | LMStructU [LlvmType] -- ^ Unpacked structure type+ | LMAlias LlvmAlias -- ^ A type alias+ | LMMetadata -- ^ LLVM Metadata++ -- | Function type, used to create pointers to functions+ | LMFunction LlvmFunctionDecl+ deriving (Eq)++instance Outputable LlvmType where+ ppr (LMInt size ) = char 'i' <> ppr size+ ppr (LMFloat ) = text "float"+ ppr (LMDouble ) = text "double"+ ppr (LMFloat80 ) = text "x86_fp80"+ ppr (LMFloat128 ) = text "fp128"+ ppr (LMPointer x ) = ppr x <> char '*'+ ppr (LMArray nr tp ) = char '[' <> ppr nr <> text " x " <> ppr tp <> char ']'+ ppr (LMVector nr tp ) = char '<' <> ppr nr <> text " x " <> ppr tp <> char '>'+ ppr (LMLabel ) = text "label"+ ppr (LMVoid ) = text "void"+ ppr (LMStruct tys ) = text "<{" <> ppCommaJoin tys <> text "}>"+ ppr (LMStructU tys ) = text "{" <> ppCommaJoin tys <> text "}"+ ppr (LMMetadata ) = text "metadata"++ ppr (LMFunction (LlvmFunctionDecl _ _ _ r varg p _))+ = ppr r <+> lparen <> ppParams varg p <> rparen++ ppr (LMAlias (s,_)) = char '%' <> ftext s++ppParams :: LlvmParameterListType -> [LlvmParameter] -> SDoc+ppParams varg p+ = let varg' = case varg of+ VarArgs | null args -> sLit "..."+ | otherwise -> sLit ", ..."+ _otherwise -> sLit ""+ -- by default we don't print param attributes+ args = map fst p+ in ppCommaJoin args <> ptext varg'++-- | An LLVM section definition. If Nothing then let LLVM decide the section+type LMSection = Maybe LMString+type LMAlign = Maybe Int++data LMConst = Global -- ^ Mutable global variable+ | Constant -- ^ Constant global variable+ | Alias -- ^ Alias of another variable+ deriving (Eq)++-- | LLVM Variables+data LlvmVar+ -- | Variables with a global scope.+ = LMGlobalVar LMString LlvmType LlvmLinkageType LMSection LMAlign LMConst+ -- | Variables local to a function or parameters.+ | LMLocalVar Unique LlvmType+ -- | Named local variables. Sometimes we need to be able to explicitly name+ -- variables (e.g for function arguments).+ | LMNLocalVar LMString LlvmType+ -- | A constant variable+ | LMLitVar LlvmLit+ deriving (Eq)++instance Outputable LlvmVar where+ ppr (LMLitVar x) = ppr x+ ppr (x ) = ppr (getVarType x) <+> ppName x+++-- | Llvm Literal Data.+--+-- These can be used inline in expressions.+data LlvmLit+ -- | Refers to an integer constant (i64 42).+ = LMIntLit Integer LlvmType+ -- | Floating point literal+ | LMFloatLit Double LlvmType+ -- | Literal NULL, only applicable to pointer types+ | LMNullLit LlvmType+ -- | Vector literal+ | LMVectorLit [LlvmLit]+ -- | Undefined value, random bit pattern. Useful for optimisations.+ | LMUndefLit LlvmType+ deriving (Eq)++instance Outputable LlvmLit where+ ppr l@(LMVectorLit {}) = ppLit l+ ppr l = ppr (getLitType l) <+> ppLit l+++-- | Llvm Static Data.+--+-- These represent the possible global level variables and constants.+data LlvmStatic+ = LMComment LMString -- ^ A comment in a static section+ | LMStaticLit LlvmLit -- ^ A static variant of a literal value+ | LMUninitType LlvmType -- ^ For uninitialised data+ | LMStaticStr LMString LlvmType -- ^ Defines a static 'LMString'+ | LMStaticArray [LlvmStatic] LlvmType -- ^ A static array+ | LMStaticStruc [LlvmStatic] LlvmType -- ^ A static structure type+ | LMStaticPointer LlvmVar -- ^ A pointer to other data++ -- static expressions, could split out but leave+ -- for moment for ease of use. Not many of them.++ | LMBitc LlvmStatic LlvmType -- ^ Pointer to Pointer conversion+ | LMPtoI LlvmStatic LlvmType -- ^ Pointer to Integer conversion+ | LMAdd LlvmStatic LlvmStatic -- ^ Constant addition operation+ | LMSub LlvmStatic LlvmStatic -- ^ Constant subtraction operation++instance Outputable LlvmStatic where+ ppr (LMComment s) = text "; " <> ftext s+ ppr (LMStaticLit l ) = ppr l+ ppr (LMUninitType t) = ppr t <> text " undef"+ ppr (LMStaticStr s t) = ppr t <> text " c\"" <> ftext s <> text "\\00\""+ ppr (LMStaticArray d t) = ppr t <> text " [" <> ppCommaJoin d <> char ']'+ ppr (LMStaticStruc d t) = ppr t <> text "<{" <> ppCommaJoin d <> text "}>"+ ppr (LMStaticPointer v) = ppr v+ ppr (LMBitc v t)+ = ppr t <> text " bitcast (" <> ppr v <> text " to " <> ppr t <> char ')'+ ppr (LMPtoI v t)+ = ppr t <> text " ptrtoint (" <> ppr v <> text " to " <> ppr t <> char ')'++ ppr (LMAdd s1 s2)+ = pprStaticArith s1 s2 (sLit "add") (sLit "fadd") "LMAdd"+ ppr (LMSub s1 s2)+ = pprStaticArith s1 s2 (sLit "sub") (sLit "fsub") "LMSub"+++pprSpecialStatic :: LlvmStatic -> SDoc+pprSpecialStatic (LMBitc v t) =+ ppr (pLower t) <> text ", bitcast (" <> ppr v <> text " to " <> ppr t+ <> char ')'+pprSpecialStatic stat = ppr stat+++pprStaticArith :: LlvmStatic -> LlvmStatic -> LitString -> LitString -> String -> SDoc+pprStaticArith s1 s2 int_op float_op op_name =+ let ty1 = getStatType s1+ op = if isFloat ty1 then float_op else int_op+ in if ty1 == getStatType s2+ then ppr ty1 <+> ptext op <+> lparen <> ppr s1 <> comma <> ppr s2 <> rparen+ else sdocWithDynFlags $ \dflags ->+ error $ op_name ++ " with different types! s1: "+ ++ showSDoc dflags (ppr s1) ++ ", s2: " ++ showSDoc dflags (ppr s2)++-- -----------------------------------------------------------------------------+-- ** Operations on LLVM Basic Types and Variables+--++-- | Return the variable name or value of the 'LlvmVar'+-- in Llvm IR textual representation (e.g. @\@x@, @%y@ or @42@).+ppName :: LlvmVar -> SDoc+ppName v@(LMGlobalVar {}) = char '@' <> ppPlainName v+ppName v@(LMLocalVar {}) = char '%' <> ppPlainName v+ppName v@(LMNLocalVar {}) = char '%' <> ppPlainName v+ppName v@(LMLitVar {}) = ppPlainName v++-- | Return the variable name or value of the 'LlvmVar'+-- in a plain textual representation (e.g. @x@, @y@ or @42@).+ppPlainName :: LlvmVar -> SDoc+ppPlainName (LMGlobalVar x _ _ _ _ _) = ftext x+ppPlainName (LMLocalVar x LMLabel ) = text (show x)+ppPlainName (LMLocalVar x _ ) = text ('l' : show x)+ppPlainName (LMNLocalVar x _ ) = ftext x+ppPlainName (LMLitVar x ) = ppLit x++-- | Print a literal value. No type.+ppLit :: LlvmLit -> SDoc+ppLit (LMIntLit i (LMInt 32)) = ppr (fromInteger i :: Int32)+ppLit (LMIntLit i (LMInt 64)) = ppr (fromInteger i :: Int64)+ppLit (LMIntLit i _ ) = ppr ((fromInteger i)::Int)+ppLit (LMFloatLit r LMFloat ) = ppFloat $ narrowFp r+ppLit (LMFloatLit r LMDouble) = ppDouble r+ppLit f@(LMFloatLit _ _) = sdocWithDynFlags (\dflags ->+ error $ "Can't print this float literal!" ++ showSDoc dflags (ppr f))+ppLit (LMVectorLit ls ) = char '<' <+> ppCommaJoin ls <+> char '>'+ppLit (LMNullLit _ ) = text "null"+-- Trac 11487 was an issue where we passed undef for some arguments+-- that were actually live. By chance the registers holding those+-- arguments usually happened to have the right values anyways, but+-- that was not guaranteed. To find such bugs reliably, we set the+-- flag below when validating, which replaces undef literals (at+-- common types) with values that are likely to cause a crash or test+-- failure.+ppLit (LMUndefLit t ) = sdocWithDynFlags f+ where f dflags+ | gopt Opt_LlvmFillUndefWithGarbage dflags,+ Just lit <- garbageLit t = ppLit lit+ | otherwise = text "undef"++garbageLit :: LlvmType -> Maybe LlvmLit+garbageLit t@(LMInt w) = Just (LMIntLit (0xbbbbbbbbbbbbbbb0 `mod` (2^w)) t)+ -- Use a value that looks like an untagged pointer, so we are more+ -- likely to try to enter it+garbageLit t+ | isFloat t = Just (LMFloatLit 12345678.9 t)+garbageLit t@(LMPointer _) = Just (LMNullLit t)+ -- Using null isn't totally ideal, since some functions may check for null.+ -- But producing another value is inconvenient since it needs a cast,+ -- and the knowledge for how to format casts is in PpLlvm.+garbageLit _ = Nothing+ -- More cases could be added, but this should do for now.++-- | Return the 'LlvmType' of the 'LlvmVar'+getVarType :: LlvmVar -> LlvmType+getVarType (LMGlobalVar _ y _ _ _ _) = y+getVarType (LMLocalVar _ y ) = y+getVarType (LMNLocalVar _ y ) = y+getVarType (LMLitVar l ) = getLitType l++-- | Return the 'LlvmType' of a 'LlvmLit'+getLitType :: LlvmLit -> LlvmType+getLitType (LMIntLit _ t) = t+getLitType (LMFloatLit _ t) = t+getLitType (LMVectorLit []) = panic "getLitType"+getLitType (LMVectorLit ls) = LMVector (length ls) (getLitType (head ls))+getLitType (LMNullLit t) = t+getLitType (LMUndefLit t) = t++-- | Return the 'LlvmType' of the 'LlvmStatic'+getStatType :: LlvmStatic -> LlvmType+getStatType (LMStaticLit l ) = getLitType l+getStatType (LMUninitType t) = t+getStatType (LMStaticStr _ t) = t+getStatType (LMStaticArray _ t) = t+getStatType (LMStaticStruc _ t) = t+getStatType (LMStaticPointer v) = getVarType v+getStatType (LMBitc _ t) = t+getStatType (LMPtoI _ t) = t+getStatType (LMAdd t _) = getStatType t+getStatType (LMSub t _) = getStatType t+getStatType (LMComment _) = error "Can't call getStatType on LMComment!"++-- | Return the 'LlvmLinkageType' for a 'LlvmVar'+getLink :: LlvmVar -> LlvmLinkageType+getLink (LMGlobalVar _ _ l _ _ _) = l+getLink _ = Internal++-- | Add a pointer indirection to the supplied type. 'LMLabel' and 'LMVoid'+-- cannot be lifted.+pLift :: LlvmType -> LlvmType+pLift LMLabel = error "Labels are unliftable"+pLift LMVoid = error "Voids are unliftable"+pLift LMMetadata = error "Metadatas are unliftable"+pLift x = LMPointer x++-- | Lift a variable to 'LMPointer' type.+pVarLift :: LlvmVar -> LlvmVar+pVarLift (LMGlobalVar s t l x a c) = LMGlobalVar s (pLift t) l x a c+pVarLift (LMLocalVar s t ) = LMLocalVar s (pLift t)+pVarLift (LMNLocalVar s t ) = LMNLocalVar s (pLift t)+pVarLift (LMLitVar _ ) = error $ "Can't lower a literal type!"++-- | Remove the pointer indirection of the supplied type. Only 'LMPointer'+-- constructors can be lowered.+pLower :: LlvmType -> LlvmType+pLower (LMPointer x) = x+pLower x = pprPanic "llvmGen(pLower)"+ $ ppr x <+> text " is a unlowerable type, need a pointer"++-- | Lower a variable of 'LMPointer' type.+pVarLower :: LlvmVar -> LlvmVar+pVarLower (LMGlobalVar s t l x a c) = LMGlobalVar s (pLower t) l x a c+pVarLower (LMLocalVar s t ) = LMLocalVar s (pLower t)+pVarLower (LMNLocalVar s t ) = LMNLocalVar s (pLower t)+pVarLower (LMLitVar _ ) = error $ "Can't lower a literal type!"++-- | Test if the given 'LlvmType' is an integer+isInt :: LlvmType -> Bool+isInt (LMInt _) = True+isInt _ = False++-- | Test if the given 'LlvmType' is a floating point type+isFloat :: LlvmType -> Bool+isFloat LMFloat = True+isFloat LMDouble = True+isFloat LMFloat80 = True+isFloat LMFloat128 = True+isFloat _ = False++-- | Test if the given 'LlvmType' is an 'LMPointer' construct+isPointer :: LlvmType -> Bool+isPointer (LMPointer _) = True+isPointer _ = False++-- | Test if the given 'LlvmType' is an 'LMVector' construct+isVector :: LlvmType -> Bool+isVector (LMVector {}) = True+isVector _ = False++-- | Test if a 'LlvmVar' is global.+isGlobal :: LlvmVar -> Bool+isGlobal (LMGlobalVar _ _ _ _ _ _) = True+isGlobal _ = False++-- | Width in bits of an 'LlvmType', returns 0 if not applicable+llvmWidthInBits :: DynFlags -> LlvmType -> Int+llvmWidthInBits _ (LMInt n) = n+llvmWidthInBits _ (LMFloat) = 32+llvmWidthInBits _ (LMDouble) = 64+llvmWidthInBits _ (LMFloat80) = 80+llvmWidthInBits _ (LMFloat128) = 128+-- Could return either a pointer width here or the width of what+-- it points to. We will go with the former for now.+-- PMW: At least judging by the way LLVM outputs constants, pointers+-- should use the former, but arrays the latter.+llvmWidthInBits dflags (LMPointer _) = llvmWidthInBits dflags (llvmWord dflags)+llvmWidthInBits dflags (LMArray n t) = n * llvmWidthInBits dflags t+llvmWidthInBits dflags (LMVector n ty) = n * llvmWidthInBits dflags ty+llvmWidthInBits _ LMLabel = 0+llvmWidthInBits _ LMVoid = 0+llvmWidthInBits dflags (LMStruct tys) = sum $ map (llvmWidthInBits dflags) tys+llvmWidthInBits _ (LMStructU _) =+ -- It's not trivial to calculate the bit width of the unpacked structs,+ -- since they will be aligned depending on the specified datalayout (+ -- http://llvm.org/docs/LangRef.html#data-layout ). One way we could support+ -- this could be to make the LlvmCodeGen.Ppr.moduleLayout be a data type+ -- that exposes the alignment information. However, currently the only place+ -- we use unpacked structs is LLVM intrinsics that return them (e.g.,+ -- llvm.sadd.with.overflow.*), so we don't actually need to compute their+ -- bit width.+ panic "llvmWidthInBits: not implemented for LMStructU"+llvmWidthInBits _ (LMFunction _) = 0+llvmWidthInBits dflags (LMAlias (_,t)) = llvmWidthInBits dflags t+llvmWidthInBits _ LMMetadata = panic "llvmWidthInBits: Meta-data has no runtime representation!"+++-- -----------------------------------------------------------------------------+-- ** Shortcut for Common Types+--++i128, i64, i32, i16, i8, i1, i8Ptr :: LlvmType+i128 = LMInt 128+i64 = LMInt 64+i32 = LMInt 32+i16 = LMInt 16+i8 = LMInt 8+i1 = LMInt 1+i8Ptr = pLift i8++-- | The target architectures word size+llvmWord, llvmWordPtr :: DynFlags -> LlvmType+llvmWord dflags = LMInt (wORD_SIZE dflags * 8)+llvmWordPtr dflags = pLift (llvmWord dflags)++-- -----------------------------------------------------------------------------+-- * LLVM Function Types+--++-- | An LLVM Function+data LlvmFunctionDecl = LlvmFunctionDecl {+ -- | Unique identifier of the function+ decName :: LMString,+ -- | LinkageType of the function+ funcLinkage :: LlvmLinkageType,+ -- | The calling convention of the function+ funcCc :: LlvmCallConvention,+ -- | Type of the returned value+ decReturnType :: LlvmType,+ -- | Indicates if this function uses varargs+ decVarargs :: LlvmParameterListType,+ -- | Parameter types and attributes+ decParams :: [LlvmParameter],+ -- | Function align value, must be power of 2+ funcAlign :: LMAlign+ }+ deriving (Eq)++instance Outputable LlvmFunctionDecl where+ ppr (LlvmFunctionDecl n l c r varg p a)+ = let align = case a of+ Just a' -> text " align " <> ppr a'+ Nothing -> empty+ in ppr l <+> ppr c <+> ppr r <+> char '@' <> ftext n <>+ lparen <> ppParams varg p <> rparen <> align++type LlvmFunctionDecls = [LlvmFunctionDecl]++type LlvmParameter = (LlvmType, [LlvmParamAttr])++-- | LLVM Parameter Attributes.+--+-- Parameter attributes are used to communicate additional information about+-- the result or parameters of a function+data LlvmParamAttr+ -- | This indicates to the code generator that the parameter or return value+ -- should be zero-extended to a 32-bit value by the caller (for a parameter)+ -- or the callee (for a return value).+ = ZeroExt+ -- | This indicates to the code generator that the parameter or return value+ -- should be sign-extended to a 32-bit value by the caller (for a parameter)+ -- or the callee (for a return value).+ | SignExt+ -- | This indicates that this parameter or return value should be treated in+ -- a special target-dependent fashion during while emitting code for a+ -- function call or return (usually, by putting it in a register as opposed+ -- to memory).+ | InReg+ -- | This indicates that the pointer parameter should really be passed by+ -- value to the function.+ | ByVal+ -- | This indicates that the pointer parameter specifies the address of a+ -- structure that is the return value of the function in the source program.+ | SRet+ -- | This indicates that the pointer does not alias any global or any other+ -- parameter.+ | NoAlias+ -- | This indicates that the callee does not make any copies of the pointer+ -- that outlive the callee itself+ | NoCapture+ -- | This indicates that the pointer parameter can be excised using the+ -- trampoline intrinsics.+ | Nest+ deriving (Eq)++instance Outputable LlvmParamAttr where+ ppr ZeroExt = text "zeroext"+ ppr SignExt = text "signext"+ ppr InReg = text "inreg"+ ppr ByVal = text "byval"+ ppr SRet = text "sret"+ ppr NoAlias = text "noalias"+ ppr NoCapture = text "nocapture"+ ppr Nest = text "nest"++-- | Llvm Function Attributes.+--+-- Function attributes are set to communicate additional information about a+-- function. Function attributes are considered to be part of the function,+-- not of the function type, so functions with different parameter attributes+-- can have the same function type. Functions can have multiple attributes.+--+-- Descriptions taken from <http://llvm.org/docs/LangRef.html#fnattrs>+data LlvmFuncAttr+ -- | This attribute indicates that the inliner should attempt to inline this+ -- function into callers whenever possible, ignoring any active inlining+ -- size threshold for this caller.+ = AlwaysInline+ -- | This attribute indicates that the source code contained a hint that+ -- inlining this function is desirable (such as the \"inline\" keyword in+ -- C/C++). It is just a hint; it imposes no requirements on the inliner.+ | InlineHint+ -- | This attribute indicates that the inliner should never inline this+ -- function in any situation. This attribute may not be used together+ -- with the alwaysinline attribute.+ | NoInline+ -- | This attribute suggests that optimization passes and code generator+ -- passes make choices that keep the code size of this function low, and+ -- otherwise do optimizations specifically to reduce code size.+ | OptSize+ -- | This function attribute indicates that the function never returns+ -- normally. This produces undefined behavior at runtime if the function+ -- ever does dynamically return.+ | NoReturn+ -- | This function attribute indicates that the function never returns with+ -- an unwind or exceptional control flow. If the function does unwind, its+ -- runtime behavior is undefined.+ | NoUnwind+ -- | This attribute indicates that the function computes its result (or+ -- decides to unwind an exception) based strictly on its arguments, without+ -- dereferencing any pointer arguments or otherwise accessing any mutable+ -- state (e.g. memory, control registers, etc) visible to caller functions.+ -- It does not write through any pointer arguments (including byval+ -- arguments) and never changes any state visible to callers. This means+ -- that it cannot unwind exceptions by calling the C++ exception throwing+ -- methods, but could use the unwind instruction.+ | ReadNone+ -- | This attribute indicates that the function does not write through any+ -- pointer arguments (including byval arguments) or otherwise modify any+ -- state (e.g. memory, control registers, etc) visible to caller functions.+ -- It may dereference pointer arguments and read state that may be set in+ -- the caller. A readonly function always returns the same value (or unwinds+ -- an exception identically) when called with the same set of arguments and+ -- global state. It cannot unwind an exception by calling the C++ exception+ -- throwing methods, but may use the unwind instruction.+ | ReadOnly+ -- | This attribute indicates that the function should emit a stack smashing+ -- protector. It is in the form of a \"canary\"—a random value placed on the+ -- stack before the local variables that's checked upon return from the+ -- function to see if it has been overwritten. A heuristic is used to+ -- determine if a function needs stack protectors or not.+ --+ -- If a function that has an ssp attribute is inlined into a function that+ -- doesn't have an ssp attribute, then the resulting function will have an+ -- ssp attribute.+ | Ssp+ -- | This attribute indicates that the function should always emit a stack+ -- smashing protector. This overrides the ssp function attribute.+ --+ -- If a function that has an sspreq attribute is inlined into a function+ -- that doesn't have an sspreq attribute or which has an ssp attribute,+ -- then the resulting function will have an sspreq attribute.+ | SspReq+ -- | This attribute indicates that the code generator should not use a red+ -- zone, even if the target-specific ABI normally permits it.+ | NoRedZone+ -- | This attributes disables implicit floating point instructions.+ | NoImplicitFloat+ -- | This attribute disables prologue / epilogue emission for the function.+ -- This can have very system-specific consequences.+ | Naked+ deriving (Eq)++instance Outputable LlvmFuncAttr where+ ppr AlwaysInline = text "alwaysinline"+ ppr InlineHint = text "inlinehint"+ ppr NoInline = text "noinline"+ ppr OptSize = text "optsize"+ ppr NoReturn = text "noreturn"+ ppr NoUnwind = text "nounwind"+ ppr ReadNone = text "readnon"+ ppr ReadOnly = text "readonly"+ ppr Ssp = text "ssp"+ ppr SspReq = text "ssqreq"+ ppr NoRedZone = text "noredzone"+ ppr NoImplicitFloat = text "noimplicitfloat"+ ppr Naked = text "naked"+++-- | Different types to call a function.+data LlvmCallType+ -- | Normal call, allocate a new stack frame.+ = StdCall+ -- | Tail call, perform the call in the current stack frame.+ | TailCall+ deriving (Eq,Show)++-- | Different calling conventions a function can use.+data LlvmCallConvention+ -- | The C calling convention.+ -- This calling convention (the default if no other calling convention is+ -- specified) matches the target C calling conventions. This calling+ -- convention supports varargs function calls and tolerates some mismatch in+ -- the declared prototype and implemented declaration of the function (as+ -- does normal C).+ = CC_Ccc+ -- | This calling convention attempts to make calls as fast as possible+ -- (e.g. by passing things in registers). This calling convention allows+ -- the target to use whatever tricks it wants to produce fast code for the+ -- target, without having to conform to an externally specified ABI+ -- (Application Binary Interface). Implementations of this convention should+ -- allow arbitrary tail call optimization to be supported. This calling+ -- convention does not support varargs and requires the prototype of al+ -- callees to exactly match the prototype of the function definition.+ | CC_Fastcc+ -- | This calling convention attempts to make code in the caller as efficient+ -- as possible under the assumption that the call is not commonly executed.+ -- As such, these calls often preserve all registers so that the call does+ -- not break any live ranges in the caller side. This calling convention+ -- does not support varargs and requires the prototype of all callees to+ -- exactly match the prototype of the function definition.+ | CC_Coldcc+ -- | The GHC-specific 'registerised' calling convention.+ | CC_Ghc+ -- | Any calling convention may be specified by number, allowing+ -- target-specific calling conventions to be used. Target specific calling+ -- conventions start at 64.+ | CC_Ncc Int+ -- | X86 Specific 'StdCall' convention. LLVM includes a specific alias for it+ -- rather than just using CC_Ncc.+ | CC_X86_Stdcc+ deriving (Eq)++instance Outputable LlvmCallConvention where+ ppr CC_Ccc = text "ccc"+ ppr CC_Fastcc = text "fastcc"+ ppr CC_Coldcc = text "coldcc"+ ppr CC_Ghc = text "ghccc"+ ppr (CC_Ncc i) = text "cc " <> ppr i+ ppr CC_X86_Stdcc = text "x86_stdcallcc"+++-- | Functions can have a fixed amount of parameters, or a variable amount.+data LlvmParameterListType+ -- Fixed amount of arguments.+ = FixedArgs+ -- Variable amount of arguments.+ | VarArgs+ deriving (Eq,Show)+++-- | Linkage type of a symbol.+--+-- The description of the constructors is copied from the Llvm Assembly Language+-- Reference Manual <http://www.llvm.org/docs/LangRef.html#linkage>, because+-- they correspond to the Llvm linkage types.+data LlvmLinkageType+ -- | Global values with internal linkage are only directly accessible by+ -- objects in the current module. In particular, linking code into a module+ -- with an internal global value may cause the internal to be renamed as+ -- necessary to avoid collisions. Because the symbol is internal to the+ -- module, all references can be updated. This corresponds to the notion+ -- of the @static@ keyword in C.+ = Internal+ -- | Globals with @linkonce@ linkage are merged with other globals of the+ -- same name when linkage occurs. This is typically used to implement+ -- inline functions, templates, or other code which must be generated+ -- in each translation unit that uses it. Unreferenced linkonce globals are+ -- allowed to be discarded.+ | LinkOnce+ -- | @weak@ linkage is exactly the same as linkonce linkage, except that+ -- unreferenced weak globals may not be discarded. This is used for globals+ -- that may be emitted in multiple translation units, but that are not+ -- guaranteed to be emitted into every translation unit that uses them. One+ -- example of this are common globals in C, such as @int X;@ at global+ -- scope.+ | Weak+ -- | @appending@ linkage may only be applied to global variables of pointer+ -- to array type. When two global variables with appending linkage are+ -- linked together, the two global arrays are appended together. This is+ -- the Llvm, typesafe, equivalent of having the system linker append+ -- together @sections@ with identical names when .o files are linked.+ | Appending+ -- | The semantics of this linkage follow the ELF model: the symbol is weak+ -- until linked, if not linked, the symbol becomes null instead of being an+ -- undefined reference.+ | ExternWeak+ -- | The symbol participates in linkage and can be used to resolve external+ -- symbol references.+ | ExternallyVisible+ -- | Alias for 'ExternallyVisible' but with explicit textual form in LLVM+ -- assembly.+ | External+ -- | Symbol is private to the module and should not appear in the symbol table+ | Private+ deriving (Eq)++instance Outputable LlvmLinkageType where+ ppr Internal = text "internal"+ ppr LinkOnce = text "linkonce"+ ppr Weak = text "weak"+ ppr Appending = text "appending"+ ppr ExternWeak = text "extern_weak"+ -- ExternallyVisible does not have a textual representation, it is+ -- the linkage type a function resolves to if no other is specified+ -- in Llvm.+ ppr ExternallyVisible = empty+ ppr External = text "external"+ ppr Private = text "private"++-- -----------------------------------------------------------------------------+-- * LLVM Operations+--++-- | Llvm binary operators machine operations.+data LlvmMachOp+ = LM_MO_Add -- ^ add two integer, floating point or vector values.+ | LM_MO_Sub -- ^ subtract two ...+ | LM_MO_Mul -- ^ multiply ..+ | LM_MO_UDiv -- ^ unsigned integer or vector division.+ | LM_MO_SDiv -- ^ signed integer ..+ | LM_MO_URem -- ^ unsigned integer or vector remainder (mod)+ | LM_MO_SRem -- ^ signed ...++ | LM_MO_FAdd -- ^ add two floating point or vector values.+ | LM_MO_FSub -- ^ subtract two ...+ | LM_MO_FMul -- ^ multiply ...+ | LM_MO_FDiv -- ^ divide ...+ | LM_MO_FRem -- ^ remainder ...++ -- | Left shift+ | LM_MO_Shl+ -- | Logical shift right+ -- Shift right, filling with zero+ | LM_MO_LShr+ -- | Arithmetic shift right+ -- The most significant bits of the result will be equal to the sign bit of+ -- the left operand.+ | LM_MO_AShr++ | LM_MO_And -- ^ AND bitwise logical operation.+ | LM_MO_Or -- ^ OR bitwise logical operation.+ | LM_MO_Xor -- ^ XOR bitwise logical operation.+ deriving (Eq)++instance Outputable LlvmMachOp where+ ppr LM_MO_Add = text "add"+ ppr LM_MO_Sub = text "sub"+ ppr LM_MO_Mul = text "mul"+ ppr LM_MO_UDiv = text "udiv"+ ppr LM_MO_SDiv = text "sdiv"+ ppr LM_MO_URem = text "urem"+ ppr LM_MO_SRem = text "srem"+ ppr LM_MO_FAdd = text "fadd"+ ppr LM_MO_FSub = text "fsub"+ ppr LM_MO_FMul = text "fmul"+ ppr LM_MO_FDiv = text "fdiv"+ ppr LM_MO_FRem = text "frem"+ ppr LM_MO_Shl = text "shl"+ ppr LM_MO_LShr = text "lshr"+ ppr LM_MO_AShr = text "ashr"+ ppr LM_MO_And = text "and"+ ppr LM_MO_Or = text "or"+ ppr LM_MO_Xor = text "xor"+++-- | Llvm compare operations.+data LlvmCmpOp+ = LM_CMP_Eq -- ^ Equal (Signed and Unsigned)+ | LM_CMP_Ne -- ^ Not equal (Signed and Unsigned)+ | LM_CMP_Ugt -- ^ Unsigned greater than+ | LM_CMP_Uge -- ^ Unsigned greater than or equal+ | LM_CMP_Ult -- ^ Unsigned less than+ | LM_CMP_Ule -- ^ Unsigned less than or equal+ | LM_CMP_Sgt -- ^ Signed greater than+ | LM_CMP_Sge -- ^ Signed greater than or equal+ | LM_CMP_Slt -- ^ Signed less than+ | LM_CMP_Sle -- ^ Signed less than or equal++ -- Float comparisons. GHC uses a mix of ordered and unordered float+ -- comparisons.+ | LM_CMP_Feq -- ^ Float equal+ | LM_CMP_Fne -- ^ Float not equal+ | LM_CMP_Fgt -- ^ Float greater than+ | LM_CMP_Fge -- ^ Float greater than or equal+ | LM_CMP_Flt -- ^ Float less than+ | LM_CMP_Fle -- ^ Float less than or equal+ deriving (Eq)++instance Outputable LlvmCmpOp where+ ppr LM_CMP_Eq = text "eq"+ ppr LM_CMP_Ne = text "ne"+ ppr LM_CMP_Ugt = text "ugt"+ ppr LM_CMP_Uge = text "uge"+ ppr LM_CMP_Ult = text "ult"+ ppr LM_CMP_Ule = text "ule"+ ppr LM_CMP_Sgt = text "sgt"+ ppr LM_CMP_Sge = text "sge"+ ppr LM_CMP_Slt = text "slt"+ ppr LM_CMP_Sle = text "sle"+ ppr LM_CMP_Feq = text "oeq"+ ppr LM_CMP_Fne = text "une"+ ppr LM_CMP_Fgt = text "ogt"+ ppr LM_CMP_Fge = text "oge"+ ppr LM_CMP_Flt = text "olt"+ ppr LM_CMP_Fle = text "ole"+++-- | Llvm cast operations.+data LlvmCastOp+ = LM_Trunc -- ^ Integer truncate+ | LM_Zext -- ^ Integer extend (zero fill)+ | LM_Sext -- ^ Integer extend (sign fill)+ | LM_Fptrunc -- ^ Float truncate+ | LM_Fpext -- ^ Float extend+ | LM_Fptoui -- ^ Float to unsigned Integer+ | LM_Fptosi -- ^ Float to signed Integer+ | LM_Uitofp -- ^ Unsigned Integer to Float+ | LM_Sitofp -- ^ Signed Int to Float+ | LM_Ptrtoint -- ^ Pointer to Integer+ | LM_Inttoptr -- ^ Integer to Pointer+ | LM_Bitcast -- ^ Cast between types where no bit manipulation is needed+ deriving (Eq)++instance Outputable LlvmCastOp where+ ppr LM_Trunc = text "trunc"+ ppr LM_Zext = text "zext"+ ppr LM_Sext = text "sext"+ ppr LM_Fptrunc = text "fptrunc"+ ppr LM_Fpext = text "fpext"+ ppr LM_Fptoui = text "fptoui"+ ppr LM_Fptosi = text "fptosi"+ ppr LM_Uitofp = text "uitofp"+ ppr LM_Sitofp = text "sitofp"+ ppr LM_Ptrtoint = text "ptrtoint"+ ppr LM_Inttoptr = text "inttoptr"+ ppr LM_Bitcast = text "bitcast"+++-- -----------------------------------------------------------------------------+-- * Floating point conversion+--++-- | Convert a Haskell Double to an LLVM hex encoded floating point form. In+-- Llvm float literals can be printed in a big-endian hexadecimal format,+-- regardless of underlying architecture.+--+-- See Note [LLVM Float Types].+ppDouble :: Double -> SDoc+ppDouble d+ = let bs = doubleToBytes d+ hex d' = case showHex d' "" of+ [] -> error "dToStr: too few hex digits for float"+ [x] -> ['0',x]+ [x,y] -> [x,y]+ _ -> error "dToStr: too many hex digits for float"++ str = map toUpper $ concat $ fixEndian $ map hex bs+ in text "0x" <> text str++-- Note [LLVM Float Types]+-- ~~~~~~~~~~~~~~~~~~~~~~~+-- We use 'ppDouble' for both printing Float and Double floating point types. This is+-- as LLVM expects all floating point constants (single & double) to be in IEEE+-- 754 Double precision format. However, for single precision numbers (Float)+-- they should be *representable* in IEEE 754 Single precision format. So the+-- easiest way to do this is to narrow and widen again.+-- (i.e., Double -> Float -> Double). We must be careful doing this that GHC+-- doesn't optimize that away.++-- Note [narrowFp & widenFp]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~+-- NOTE: we use float2Double & co directly as GHC likes to optimize away+-- successive calls of 'realToFrac', defeating the narrowing. (Bug #7600).+-- 'realToFrac' has inconsistent behaviour with optimisation as well that can+-- also cause issues, these methods don't.++narrowFp :: Double -> Float+{-# NOINLINE narrowFp #-}+narrowFp = double2Float++widenFp :: Float -> Double+{-# NOINLINE widenFp #-}+widenFp = float2Double++ppFloat :: Float -> SDoc+ppFloat = ppDouble . widenFp++-- | Reverse or leave byte data alone to fix endianness on this target.+fixEndian :: [a] -> [a]+#ifdef WORDS_BIGENDIAN+fixEndian = id+#else+fixEndian = reverse+#endif+++--------------------------------------------------------------------------------+-- * Misc functions+--------------------------------------------------------------------------------++ppCommaJoin :: (Outputable a) => [a] -> SDoc+ppCommaJoin strs = hsep $ punctuate comma (map ppr strs)++ppSpaceJoin :: (Outputable a) => [a] -> SDoc+ppSpaceJoin strs = hsep (map ppr strs)
+ llvmGen/LlvmCodeGen.hs view
@@ -0,0 +1,223 @@+{-# LANGUAGE CPP, TypeFamilies #-}++-- -----------------------------------------------------------------------------+-- | This is the top-level module in the LLVM code generator.+--+module LlvmCodeGen ( llvmCodeGen, llvmFixupAsm ) where++#include "HsVersions.h"++import Llvm+import LlvmCodeGen.Base+import LlvmCodeGen.CodeGen+import LlvmCodeGen.Data+import LlvmCodeGen.Ppr+import LlvmCodeGen.Regs+import LlvmMangler++import BlockId+import CgUtils ( fixStgRegisters )+import Cmm+import CmmUtils+import Hoopl+import PprCmm++import BufWrite+import DynFlags+import ErrUtils+import FastString+import Outputable+import UniqSupply+import SysTools ( figureLlvmVersion )+import qualified Stream++import Control.Monad ( when )+import Data.Maybe ( fromMaybe, catMaybes )+import System.IO++-- -----------------------------------------------------------------------------+-- | Top-level of the LLVM Code generator+--+llvmCodeGen :: DynFlags -> Handle -> UniqSupply+ -> Stream.Stream IO RawCmmGroup ()+ -> IO ()+llvmCodeGen dflags h us cmm_stream+ = withTiming (pure dflags) (text "LLVM CodeGen") (const ()) $ do+ bufh <- newBufHandle h++ -- Pass header+ showPass dflags "LLVM CodeGen"++ -- get llvm version, cache for later use+ ver <- (fromMaybe supportedLlvmVersion) `fmap` figureLlvmVersion dflags++ -- warn if unsupported+ debugTraceMsg dflags 2+ (text "Using LLVM version:" <+> text (show ver))+ let doWarn = wopt Opt_WarnUnsupportedLlvmVersion dflags+ when (ver /= supportedLlvmVersion && doWarn) $+ putMsg dflags (text "You are using an unsupported version of LLVM!"+ $+$ text ("Currently only " +++ llvmVersionStr supportedLlvmVersion +++ " is supported.")+ $+$ text "We will try though...")++ -- run code generation+ runLlvm dflags ver bufh us $+ llvmCodeGen' (liftStream cmm_stream)++ bFlush bufh++llvmCodeGen' :: Stream.Stream LlvmM RawCmmGroup () -> LlvmM ()+llvmCodeGen' cmm_stream+ = do -- Preamble+ renderLlvm pprLlvmHeader+ ghcInternalFunctions+ cmmMetaLlvmPrelude++ -- Procedures+ let llvmStream = Stream.mapM llvmGroupLlvmGens cmm_stream+ _ <- Stream.collect llvmStream++ -- Declare aliases for forward references+ renderLlvm . pprLlvmData =<< generateExternDecls++ -- Postamble+ cmmUsedLlvmGens++llvmGroupLlvmGens :: RawCmmGroup -> LlvmM ()+llvmGroupLlvmGens cmm = do++ -- Insert functions into map, collect data+ let split (CmmData s d' ) = return $ Just (s, d')+ split (CmmProc h l live g) = do+ -- Set function type+ let l' = case mapLookup (g_entry g) h of+ Nothing -> l+ Just (Statics info_lbl _) -> info_lbl+ lml <- strCLabel_llvm l'+ funInsert lml =<< llvmFunTy live+ return Nothing+ cdata <- fmap catMaybes $ mapM split cmm++ {-# SCC "llvm_datas_gen" #-}+ cmmDataLlvmGens cdata+ {-# SCC "llvm_procs_gen" #-}+ mapM_ cmmLlvmGen cmm++-- -----------------------------------------------------------------------------+-- | Do LLVM code generation on all these Cmms data sections.+--+cmmDataLlvmGens :: [(Section,CmmStatics)] -> LlvmM ()++cmmDataLlvmGens statics+ = do lmdatas <- mapM genLlvmData statics++ let (gss, tss) = unzip lmdatas++ let regGlobal (LMGlobal (LMGlobalVar l ty _ _ _ _) _)+ = funInsert l ty+ regGlobal _ = return ()+ mapM_ regGlobal (concat gss)+ gss' <- mapM aliasify $ concat gss++ renderLlvm $ pprLlvmData (concat gss', concat tss)++-- | LLVM can't handle entry blocks which loop back to themselves (could be+-- seen as an LLVM bug) so we rearrange the code to keep the original entry+-- label which branches to a newly generated second label that branches back+-- to itself. See: Trac #11649+fixBottom :: RawCmmDecl -> LlvmM RawCmmDecl+fixBottom cp@(CmmProc hdr entry_lbl live g) =+ maybe (pure cp) fix_block $ mapLookup (g_entry g) blk_map+ where+ blk_map = toBlockMap g++ fix_block :: CmmBlock -> LlvmM RawCmmDecl+ fix_block blk+ | (CmmEntry e_lbl tickscp, middle, CmmBranch b_lbl) <- blockSplit blk+ , isEmptyBlock middle+ , e_lbl == b_lbl = do+ new_lbl <- mkBlockId <$> getUniqueM++ let fst_blk =+ BlockCC (CmmEntry e_lbl tickscp) BNil (CmmBranch new_lbl)+ snd_blk =+ BlockCC (CmmEntry new_lbl tickscp) BNil (CmmBranch new_lbl)++ pure . CmmProc hdr entry_lbl live . ofBlockMap (g_entry g)+ $ mapFromList [(e_lbl, fst_blk), (new_lbl, snd_blk)]++ fix_block _ = pure cp++fixBottom rcd = pure rcd++-- | Complete LLVM code generation phase for a single top-level chunk of Cmm.+cmmLlvmGen ::RawCmmDecl -> LlvmM ()+cmmLlvmGen cmm@CmmProc{} = do++ -- rewrite assignments to global regs+ dflags <- getDynFlag id+ fixed_cmm <- fixBottom $+ {-# SCC "llvm_fix_regs" #-}+ fixStgRegisters dflags cmm++ dumpIfSetLlvm Opt_D_dump_opt_cmm "Optimised Cmm" (pprCmmGroup [fixed_cmm])++ -- generate llvm code from cmm+ llvmBC <- withClearVars $ genLlvmProc fixed_cmm++ -- pretty print+ (docs, ivars) <- fmap unzip $ mapM pprLlvmCmmDecl llvmBC++ -- Output, note down used variables+ renderLlvm (vcat docs)+ mapM_ markUsedVar $ concat ivars++cmmLlvmGen _ = return ()++-- -----------------------------------------------------------------------------+-- | Generate meta data nodes+--++cmmMetaLlvmPrelude :: LlvmM ()+cmmMetaLlvmPrelude = do+ metas <- flip mapM stgTBAA $ \(uniq, name, parent) -> do+ -- Generate / lookup meta data IDs+ tbaaId <- getMetaUniqueId+ setUniqMeta uniq tbaaId+ parentId <- maybe (return Nothing) getUniqMeta parent+ -- Build definition+ return $ MetaUnnamed tbaaId $ MetaStruct $+ case parentId of+ Just p -> [ MetaStr name, MetaNode p ]+ -- As of LLVM 4.0, a node without parents should be rendered as+ -- just a name on its own. Previously `null` was accepted as the+ -- name.+ Nothing -> [ MetaStr name ]+ renderLlvm $ ppLlvmMetas metas++-- -----------------------------------------------------------------------------+-- | Marks variables as used where necessary+--++cmmUsedLlvmGens :: LlvmM ()+cmmUsedLlvmGens = do++ -- LLVM would discard variables that are internal and not obviously+ -- used if we didn't provide these hints. This will generate a+ -- definition of the form+ --+ -- @llvm.used = appending global [42 x i8*] [i8* bitcast <var> to i8*, ...]+ --+ -- Which is the LLVM way of protecting them against getting removed.+ ivars <- getUsedVars+ let cast x = LMBitc (LMStaticPointer (pVarLift x)) i8Ptr+ ty = (LMArray (length ivars) i8Ptr)+ usedArray = LMStaticArray (map cast ivars) ty+ sectName = Just $ fsLit "llvm.metadata"+ lmUsedVar = LMGlobalVar (fsLit "llvm.used") ty Appending sectName Nothing Constant+ lmUsed = LMGlobal lmUsedVar (Just usedArray)+ if null ivars+ then return ()+ else renderLlvm $ pprLlvmData ([lmUsed], [])
+ llvmGen/LlvmCodeGen/Base.hs view
@@ -0,0 +1,550 @@+{-# LANGUAGE CPP #-}++-- ----------------------------------------------------------------------------+-- | Base LLVM Code Generation module+--+-- Contains functions useful through out the code generator.+--++module LlvmCodeGen.Base (++ LlvmCmmDecl, LlvmBasicBlock,+ LiveGlobalRegs,+ LlvmUnresData, LlvmData, UnresLabel, UnresStatic,++ LlvmVersion, supportedLlvmVersion, llvmVersionStr,++ LlvmM,+ runLlvm, liftStream, withClearVars, varLookup, varInsert,+ markStackReg, checkStackReg,+ funLookup, funInsert, getLlvmVer, getDynFlags, getDynFlag, getLlvmPlatform,+ dumpIfSetLlvm, renderLlvm, markUsedVar, getUsedVars,+ ghcInternalFunctions,++ getMetaUniqueId,+ setUniqMeta, getUniqMeta,++ cmmToLlvmType, widthToLlvmFloat, widthToLlvmInt, llvmFunTy,+ llvmFunSig, llvmFunArgs, llvmStdFunAttrs, llvmFunAlign, llvmInfAlign,+ llvmPtrBits, tysToParams, llvmFunSection,++ strCLabel_llvm, strDisplayName_llvm, strProcedureName_llvm,+ getGlobalPtr, generateExternDecls,++ aliasify,+ ) where++#include "HsVersions.h"+#include "ghcautoconf.h"++import Llvm+import LlvmCodeGen.Regs++import CLabel+import CodeGen.Platform ( activeStgRegs )+import DynFlags+import FastString+import Cmm hiding ( succ )+import Outputable as Outp+import Platform+import UniqFM+import Unique+import BufWrite ( BufHandle )+import UniqSet+import UniqSupply+import ErrUtils+import qualified Stream++import Control.Monad (ap)++-- ----------------------------------------------------------------------------+-- * Some Data Types+--++type LlvmCmmDecl = GenCmmDecl [LlvmData] (Maybe CmmStatics) (ListGraph LlvmStatement)+type LlvmBasicBlock = GenBasicBlock LlvmStatement++-- | Global registers live on proc entry+type LiveGlobalRegs = [GlobalReg]++-- | Unresolved code.+-- Of the form: (data label, data type, unresolved data)+type LlvmUnresData = (CLabel, Section, LlvmType, [UnresStatic])++-- | Top level LLVM Data (globals and type aliases)+type LlvmData = ([LMGlobal], [LlvmType])++-- | An unresolved Label.+--+-- Labels are unresolved when we haven't yet determined if they are defined in+-- the module we are currently compiling, or an external one.+type UnresLabel = CmmLit+type UnresStatic = Either UnresLabel LlvmStatic++-- ----------------------------------------------------------------------------+-- * Type translations+--++-- | Translate a basic CmmType to an LlvmType.+cmmToLlvmType :: CmmType -> LlvmType+cmmToLlvmType ty | isVecType ty = LMVector (vecLength ty) (cmmToLlvmType (vecElemType ty))+ | isFloatType ty = widthToLlvmFloat $ typeWidth ty+ | otherwise = widthToLlvmInt $ typeWidth ty++-- | Translate a Cmm Float Width to a LlvmType.+widthToLlvmFloat :: Width -> LlvmType+widthToLlvmFloat W32 = LMFloat+widthToLlvmFloat W64 = LMDouble+widthToLlvmFloat W80 = LMFloat80+widthToLlvmFloat W128 = LMFloat128+widthToLlvmFloat w = panic $ "widthToLlvmFloat: Bad float size: " ++ show w++-- | Translate a Cmm Bit Width to a LlvmType.+widthToLlvmInt :: Width -> LlvmType+widthToLlvmInt w = LMInt $ widthInBits w++-- | GHC Call Convention for LLVM+llvmGhcCC :: DynFlags -> LlvmCallConvention+llvmGhcCC dflags+ | platformUnregisterised (targetPlatform dflags) = CC_Ccc+ | otherwise = CC_Ghc++-- | Llvm Function type for Cmm function+llvmFunTy :: LiveGlobalRegs -> LlvmM LlvmType+llvmFunTy live = return . LMFunction =<< llvmFunSig' live (fsLit "a") ExternallyVisible++-- | Llvm Function signature+llvmFunSig :: LiveGlobalRegs -> CLabel -> LlvmLinkageType -> LlvmM LlvmFunctionDecl+llvmFunSig live lbl link = do+ lbl' <- strCLabel_llvm lbl+ llvmFunSig' live lbl' link++llvmFunSig' :: LiveGlobalRegs -> LMString -> LlvmLinkageType -> LlvmM LlvmFunctionDecl+llvmFunSig' live lbl link+ = do let toParams x | isPointer x = (x, [NoAlias, NoCapture])+ | otherwise = (x, [])+ dflags <- getDynFlags+ return $ LlvmFunctionDecl lbl link (llvmGhcCC dflags) LMVoid FixedArgs+ (map (toParams . getVarType) (llvmFunArgs dflags live))+ (llvmFunAlign dflags)++-- | Alignment to use for functions+llvmFunAlign :: DynFlags -> LMAlign+llvmFunAlign dflags = Just (wORD_SIZE dflags)++-- | Alignment to use for into tables+llvmInfAlign :: DynFlags -> LMAlign+llvmInfAlign dflags = Just (wORD_SIZE dflags)++-- | Section to use for a function+llvmFunSection :: DynFlags -> LMString -> LMSection+llvmFunSection dflags lbl+ | gopt Opt_SplitSections dflags = Just (concatFS [fsLit ".text.", lbl])+ | otherwise = Nothing++-- | A Function's arguments+llvmFunArgs :: DynFlags -> LiveGlobalRegs -> [LlvmVar]+llvmFunArgs dflags live =+ map (lmGlobalRegArg dflags) (filter isPassed (activeStgRegs platform))+ where platform = targetPlatform dflags+ isLive r = not (isSSE r) || r `elem` alwaysLive || r `elem` live+ isPassed r = not (isSSE r) || isLive r+ isSSE (FloatReg _) = True+ isSSE (DoubleReg _) = True+ isSSE (XmmReg _) = True+ isSSE (YmmReg _) = True+ isSSE (ZmmReg _) = True+ isSSE _ = False++-- | Llvm standard fun attributes+llvmStdFunAttrs :: [LlvmFuncAttr]+llvmStdFunAttrs = [NoUnwind]++-- | Convert a list of types to a list of function parameters+-- (each with no parameter attributes)+tysToParams :: [LlvmType] -> [LlvmParameter]+tysToParams = map (\ty -> (ty, []))++-- | Pointer width+llvmPtrBits :: DynFlags -> Int+llvmPtrBits dflags = widthInBits $ typeWidth $ gcWord dflags++-- ----------------------------------------------------------------------------+-- * Llvm Version+--++-- | LLVM Version Number+type LlvmVersion = (Int, Int)++-- | The LLVM Version that is currently supported.+supportedLlvmVersion :: LlvmVersion+supportedLlvmVersion = sUPPORTED_LLVM_VERSION++llvmVersionStr :: LlvmVersion -> String+llvmVersionStr (major, minor) = show major ++ "." ++ show minor++-- ----------------------------------------------------------------------------+-- * Environment Handling+--++data LlvmEnv = LlvmEnv+ { envVersion :: LlvmVersion -- ^ LLVM version+ , envDynFlags :: DynFlags -- ^ Dynamic flags+ , envOutput :: BufHandle -- ^ Output buffer+ , envUniq :: UniqSupply -- ^ Supply of unique values+ , envFreshMeta :: MetaId -- ^ Supply of fresh metadata IDs+ , envUniqMeta :: UniqFM MetaId -- ^ Global metadata nodes+ , envFunMap :: LlvmEnvMap -- ^ Global functions so far, with type+ , envAliases :: UniqSet LMString -- ^ Globals that we had to alias, see [Llvm Forward References]+ , envUsedVars :: [LlvmVar] -- ^ Pointers to be added to llvm.used (see @cmmUsedLlvmGens@)++ -- the following get cleared for every function (see @withClearVars@)+ , envVarMap :: LlvmEnvMap -- ^ Local variables so far, with type+ , envStackRegs :: [GlobalReg] -- ^ Non-constant registers (alloca'd in the function prelude)+ }++type LlvmEnvMap = UniqFM LlvmType++-- | The Llvm monad. Wraps @LlvmEnv@ state as well as the @IO@ monad+newtype LlvmM a = LlvmM { runLlvmM :: LlvmEnv -> IO (a, LlvmEnv) }++instance Functor LlvmM where+ fmap f m = LlvmM $ \env -> do (x, env') <- runLlvmM m env+ return (f x, env')++instance Applicative LlvmM where+ pure x = LlvmM $ \env -> return (x, env)+ (<*>) = ap++instance Monad LlvmM where+ m >>= f = LlvmM $ \env -> do (x, env') <- runLlvmM m env+ runLlvmM (f x) env'++instance HasDynFlags LlvmM where+ getDynFlags = LlvmM $ \env -> return (envDynFlags env, env)++instance MonadUnique LlvmM where+ getUniqueSupplyM = do+ us <- getEnv envUniq+ let (us1, us2) = splitUniqSupply us+ modifyEnv (\s -> s { envUniq = us2 })+ return us1++ getUniqueM = do+ us <- getEnv envUniq+ let (u,us') = takeUniqFromSupply us+ modifyEnv (\s -> s { envUniq = us' })+ return u++-- | Lifting of IO actions. Not exported, as we want to encapsulate IO.+liftIO :: IO a -> LlvmM a+liftIO m = LlvmM $ \env -> do x <- m+ return (x, env)++-- | Get initial Llvm environment.+runLlvm :: DynFlags -> LlvmVersion -> BufHandle -> UniqSupply -> LlvmM () -> IO ()+runLlvm dflags ver out us m = do+ _ <- runLlvmM m env+ return ()+ where env = LlvmEnv { envFunMap = emptyUFM+ , envVarMap = emptyUFM+ , envStackRegs = []+ , envUsedVars = []+ , envAliases = emptyUniqSet+ , envVersion = ver+ , envDynFlags = dflags+ , envOutput = out+ , envUniq = us+ , envFreshMeta = MetaId 0+ , envUniqMeta = emptyUFM+ }++-- | Get environment (internal)+getEnv :: (LlvmEnv -> a) -> LlvmM a+getEnv f = LlvmM (\env -> return (f env, env))++-- | Modify environment (internal)+modifyEnv :: (LlvmEnv -> LlvmEnv) -> LlvmM ()+modifyEnv f = LlvmM (\env -> return ((), f env))++-- | Lift a stream into the LlvmM monad+liftStream :: Stream.Stream IO a x -> Stream.Stream LlvmM a x+liftStream s = Stream.Stream $ do+ r <- liftIO $ Stream.runStream s+ case r of+ Left b -> return (Left b)+ Right (a, r2) -> return (Right (a, liftStream r2))++-- | Clear variables from the environment for a subcomputation+withClearVars :: LlvmM a -> LlvmM a+withClearVars m = LlvmM $ \env -> do+ (x, env') <- runLlvmM m env { envVarMap = emptyUFM, envStackRegs = [] }+ return (x, env' { envVarMap = emptyUFM, envStackRegs = [] })++-- | Insert variables or functions into the environment.+varInsert, funInsert :: Uniquable key => key -> LlvmType -> LlvmM ()+varInsert s t = modifyEnv $ \env -> env { envVarMap = addToUFM (envVarMap env) s t }+funInsert s t = modifyEnv $ \env -> env { envFunMap = addToUFM (envFunMap env) s t }++-- | Lookup variables or functions in the environment.+varLookup, funLookup :: Uniquable key => key -> LlvmM (Maybe LlvmType)+varLookup s = getEnv (flip lookupUFM s . envVarMap)+funLookup s = getEnv (flip lookupUFM s . envFunMap)++-- | Set a register as allocated on the stack+markStackReg :: GlobalReg -> LlvmM ()+markStackReg r = modifyEnv $ \env -> env { envStackRegs = r : envStackRegs env }++-- | Check whether a register is allocated on the stack+checkStackReg :: GlobalReg -> LlvmM Bool+checkStackReg r = getEnv ((elem r) . envStackRegs)++-- | Allocate a new global unnamed metadata identifier+getMetaUniqueId :: LlvmM MetaId+getMetaUniqueId = LlvmM $ \env ->+ return (envFreshMeta env, env { envFreshMeta = succ $ envFreshMeta env })++-- | Get the LLVM version we are generating code for+getLlvmVer :: LlvmM LlvmVersion+getLlvmVer = getEnv envVersion++-- | Get the platform we are generating code for+getDynFlag :: (DynFlags -> a) -> LlvmM a+getDynFlag f = getEnv (f . envDynFlags)++-- | Get the platform we are generating code for+getLlvmPlatform :: LlvmM Platform+getLlvmPlatform = getDynFlag targetPlatform++-- | Dumps the document if the corresponding flag has been set by the user+dumpIfSetLlvm :: DumpFlag -> String -> Outp.SDoc -> LlvmM ()+dumpIfSetLlvm flag hdr doc = do+ dflags <- getDynFlags+ liftIO $ dumpIfSet_dyn dflags flag hdr doc++-- | Prints the given contents to the output handle+renderLlvm :: Outp.SDoc -> LlvmM ()+renderLlvm sdoc = do++ -- Write to output+ dflags <- getDynFlags+ out <- getEnv envOutput+ liftIO $ Outp.bufLeftRenderSDoc dflags out+ (Outp.mkCodeStyle Outp.CStyle) sdoc++ -- Dump, if requested+ dumpIfSetLlvm Opt_D_dump_llvm "LLVM Code" sdoc+ return ()++-- | Marks a variable as "used"+markUsedVar :: LlvmVar -> LlvmM ()+markUsedVar v = modifyEnv $ \env -> env { envUsedVars = v : envUsedVars env }++-- | Return all variables marked as "used" so far+getUsedVars :: LlvmM [LlvmVar]+getUsedVars = getEnv envUsedVars++-- | Saves that at some point we didn't know the type of the label and+-- generated a reference to a type variable instead+saveAlias :: LMString -> LlvmM ()+saveAlias lbl = modifyEnv $ \env -> env { envAliases = addOneToUniqSet (envAliases env) lbl }++-- | Sets metadata node for a given unique+setUniqMeta :: Unique -> MetaId -> LlvmM ()+setUniqMeta f m = modifyEnv $ \env -> env { envUniqMeta = addToUFM (envUniqMeta env) f m }++-- | Gets metadata node for given unique+getUniqMeta :: Unique -> LlvmM (Maybe MetaId)+getUniqMeta s = getEnv (flip lookupUFM s . envUniqMeta)++-- ----------------------------------------------------------------------------+-- * Internal functions+--++-- | Here we pre-initialise some functions that are used internally by GHC+-- so as to make sure they have the most general type in the case that+-- user code also uses these functions but with a different type than GHC+-- internally. (Main offender is treating return type as 'void' instead of+-- 'void *'). Fixes trac #5486.+ghcInternalFunctions :: LlvmM ()+ghcInternalFunctions = do+ dflags <- getDynFlags+ mk "memcpy" i8Ptr [i8Ptr, i8Ptr, llvmWord dflags]+ mk "memmove" i8Ptr [i8Ptr, i8Ptr, llvmWord dflags]+ mk "memset" i8Ptr [i8Ptr, llvmWord dflags, llvmWord dflags]+ mk "newSpark" (llvmWord dflags) [i8Ptr, i8Ptr]+ where+ mk n ret args = do+ let n' = fsLit n `appendFS` fsLit "$def"+ decl = LlvmFunctionDecl n' ExternallyVisible CC_Ccc ret+ FixedArgs (tysToParams args) Nothing+ renderLlvm $ ppLlvmFunctionDecl decl+ funInsert n' (LMFunction decl)++-- ----------------------------------------------------------------------------+-- * Label handling+--++-- | Pretty print a 'CLabel'.+strCLabel_llvm :: CLabel -> LlvmM LMString+strCLabel_llvm lbl = do+ platform <- getLlvmPlatform+ dflags <- getDynFlags+ let sdoc = pprCLabel platform lbl+ str = Outp.renderWithStyle dflags sdoc (Outp.mkCodeStyle Outp.CStyle)+ return (fsLit str)++strDisplayName_llvm :: CLabel -> LlvmM LMString+strDisplayName_llvm lbl = do+ platform <- getLlvmPlatform+ dflags <- getDynFlags+ let sdoc = pprCLabel platform lbl+ depth = Outp.PartWay 1+ style = Outp.mkUserStyle dflags Outp.reallyAlwaysQualify depth+ str = Outp.renderWithStyle dflags sdoc style+ return (fsLit (dropInfoSuffix str))++dropInfoSuffix :: String -> String+dropInfoSuffix = go+ where go "_info" = []+ go "_static_info" = []+ go "_con_info" = []+ go (x:xs) = x:go xs+ go [] = []++strProcedureName_llvm :: CLabel -> LlvmM LMString+strProcedureName_llvm lbl = do+ platform <- getLlvmPlatform+ dflags <- getDynFlags+ let sdoc = pprCLabel platform lbl+ depth = Outp.PartWay 1+ style = Outp.mkUserStyle dflags Outp.neverQualify depth+ str = Outp.renderWithStyle dflags sdoc style+ return (fsLit str)++-- ----------------------------------------------------------------------------+-- * Global variables / forward references+--++-- | Create/get a pointer to a global value. Might return an alias if+-- the value in question hasn't been defined yet. We especially make+-- no guarantees on the type of the returned pointer.+getGlobalPtr :: LMString -> LlvmM LlvmVar+getGlobalPtr llvmLbl = do+ m_ty <- funLookup llvmLbl+ let mkGlbVar lbl ty = LMGlobalVar lbl (LMPointer ty) Private Nothing Nothing+ case m_ty of+ -- Directly reference if we have seen it already+ Just ty -> return $ mkGlbVar (llvmLbl `appendFS` fsLit "$def") ty Global+ -- Otherwise use a forward alias of it+ Nothing -> do+ saveAlias llvmLbl+ return $ mkGlbVar llvmLbl i8 Alias++-- | Generate definitions for aliases forward-referenced by @getGlobalPtr@.+--+-- Must be called at a point where we are sure that no new global definitions+-- will be generated anymore!+generateExternDecls :: LlvmM ([LMGlobal], [LlvmType])+generateExternDecls = do+ delayed <- fmap nonDetEltsUniqSet $ getEnv envAliases+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ defss <- flip mapM delayed $ \lbl -> do+ m_ty <- funLookup lbl+ case m_ty of+ -- If we have a definition we've already emitted the proper aliases+ -- when the symbol itself was emitted by @aliasify@+ Just _ -> return []++ -- If we don't have a definition this is an external symbol and we+ -- need to emit a declaration+ Nothing ->+ let var = LMGlobalVar lbl i8Ptr External Nothing Nothing Global+ in return [LMGlobal var Nothing]++ -- Reset forward list+ modifyEnv $ \env -> env { envAliases = emptyUniqSet }+ return (concat defss, [])++-- | Here we take a global variable definition, rename it with a+-- @$def@ suffix, and generate the appropriate alias.+aliasify :: LMGlobal -> LlvmM [LMGlobal]+aliasify (LMGlobal var val) = do+ let i8Ptr = LMPointer (LMInt 8)+ LMGlobalVar lbl ty link sect align const = var++ defLbl = lbl `appendFS` fsLit "$def"+ defVar = LMGlobalVar defLbl ty Internal sect align const++ defPtrVar = LMGlobalVar defLbl (LMPointer ty) link Nothing Nothing const+ aliasVar = LMGlobalVar lbl (LMPointer i8Ptr) link Nothing Nothing Alias+ aliasVal = LMBitc (LMStaticPointer defPtrVar) i8Ptr++ -- we need to mark the $def symbols as used so LLVM doesn't forget which+ -- section they need to go in. This will vanish once we switch away from+ -- mangling sections for TNTC.+ markUsedVar defVar++ return [ LMGlobal defVar val+ , LMGlobal aliasVar (Just aliasVal)+ ]++-- Note [Llvm Forward References]+--+-- The issue here is that LLVM insists on being strongly typed at+-- every corner, so the first time we mention something, we have to+-- settle what type we assign to it. That makes things awkward, as Cmm+-- will often reference things before their definition, and we have no+-- idea what (LLVM) type it is going to be before that point.+--+-- Our work-around is to define "aliases" of a standard type (i8 *) in+-- these kind of situations, which we later tell LLVM to be either+-- references to their actual local definitions (involving a cast) or+-- an external reference. This obviously only works for pointers.+--+-- In particular when we encounter a reference to a symbol in a chunk of+-- C-- there are three possible scenarios,+--+-- 1. We have already seen a definition for the referenced symbol. This+-- means we already know its type.+--+-- 2. We have not yet seen a definition but we will find one later in this+-- compilation unit. Since we want to be a good consumer of the+-- C-- streamed to us from upstream, we don't know the type of the+-- symbol at the time when we must emit the reference.+--+-- 3. We have not yet seen a definition nor will we find one in this+-- compilation unit. In this case the reference refers to an+-- external symbol for which we do not know the type.+--+-- Let's consider case (2) for a moment: say we see a reference to+-- the symbol @fooBar@ for which we have not seen a definition. As we+-- do not know the symbol's type, we assume it is of type @i8*@ and emit+-- the appropriate casts in @getSymbolPtr@. Later on, when we+-- encounter the definition of @fooBar@ we emit it but with a modified+-- name, @fooBar$def@ (which we'll call the definition symbol), to+-- since we have already had to assume that the symbol @fooBar@+-- is of type @i8*@. We then emit @fooBar@ itself as an alias+-- of @fooBar$def@ with appropriate casts. This all happens in+-- @aliasify@.+--+-- Case (3) is quite similar to (2): References are emitted assuming+-- the referenced symbol is of type @i8*@. When we arrive at the end of+-- the compilation unit and realize that the symbol is external, we emit+-- an LLVM @external global@ declaration for the symbol @fooBar@+-- (handled in @generateExternDecls@). This takes advantage of the+-- fact that the aliases produced by @aliasify@ for exported symbols+-- have external linkage and can therefore be used as normal symbols.+--+-- Historical note: As of release 3.5 LLVM does not allow aliases to+-- refer to declarations. This the reason why aliases are produced at the+-- point of definition instead of the point of usage, as was previously+-- done. See #9142 for details.+--+-- Finally, case (1) is trival. As we already have a definition for+-- and therefore know the type of the referenced symbol, we can do+-- away with casting the alias to the desired type in @getSymbolPtr@+-- and instead just emit a reference to the definition symbol directly.+-- This is the @Just@ case in @getSymbolPtr@.
+ llvmGen/LlvmCodeGen/CodeGen.hs view
@@ -0,0 +1,1912 @@+{-# LANGUAGE CPP, GADTs #-}+{-# OPTIONS_GHC -fno-warn-type-defaults #-}+-- ----------------------------------------------------------------------------+-- | Handle conversion of CmmProc to LLVM code.+--+module LlvmCodeGen.CodeGen ( genLlvmProc ) where++#include "HsVersions.h"++import Llvm+import LlvmCodeGen.Base+import LlvmCodeGen.Regs++import BlockId+import CodeGen.Platform ( activeStgRegs, callerSaves )+import CLabel+import Cmm+import PprCmm+import CmmUtils+import CmmSwitch+import Hoopl++import DynFlags+import FastString+import ForeignCall+import Outputable hiding (panic, pprPanic)+import qualified Outputable+import Platform+import OrdList+import UniqSupply+import Unique+import Util++import Control.Monad.Trans.Class+import Control.Monad.Trans.Writer++#if __GLASGOW_HASKELL__ > 710+import Data.Semigroup ( Semigroup )+import qualified Data.Semigroup as Semigroup+#endif+import Data.List ( nub )+import Data.Maybe ( catMaybes )++type Atomic = Bool+type LlvmStatements = OrdList LlvmStatement++-- -----------------------------------------------------------------------------+-- | Top-level of the LLVM proc Code generator+--+genLlvmProc :: RawCmmDecl -> LlvmM [LlvmCmmDecl]+genLlvmProc (CmmProc infos lbl live graph) = do+ let blocks = toBlockListEntryFirstFalseFallthrough graph+ (lmblocks, lmdata) <- basicBlocksCodeGen live blocks+ let info = mapLookup (g_entry graph) infos+ proc = CmmProc info lbl live (ListGraph lmblocks)+ return (proc:lmdata)++genLlvmProc _ = panic "genLlvmProc: case that shouldn't reach here!"++-- -----------------------------------------------------------------------------+-- * Block code generation+--++-- | Generate code for a list of blocks that make up a complete+-- procedure. The first block in the list is exepected to be the entry+-- point and will get the prologue.+basicBlocksCodeGen :: LiveGlobalRegs -> [CmmBlock]+ -> LlvmM ([LlvmBasicBlock], [LlvmCmmDecl])+basicBlocksCodeGen _ [] = panic "no entry block!"+basicBlocksCodeGen live (entryBlock:cmmBlocks)+ = do (prologue, prologueTops) <- funPrologue live (entryBlock:cmmBlocks)++ -- Generate code+ (BasicBlock bid entry, entryTops) <- basicBlockCodeGen entryBlock+ (blocks, topss) <- fmap unzip $ mapM basicBlockCodeGen cmmBlocks++ -- Compose+ let entryBlock = BasicBlock bid (fromOL prologue ++ entry)+ return (entryBlock : blocks, prologueTops ++ entryTops ++ concat topss)+++-- | Generate code for one block+basicBlockCodeGen :: CmmBlock -> LlvmM ( LlvmBasicBlock, [LlvmCmmDecl] )+basicBlockCodeGen block+ = do let (_, nodes, tail) = blockSplit block+ id = entryLabel block+ (mid_instrs, top) <- stmtsToInstrs $ blockToList nodes+ (tail_instrs, top') <- stmtToInstrs tail+ let instrs = fromOL (mid_instrs `appOL` tail_instrs)+ return (BasicBlock id instrs, top' ++ top)++-- -----------------------------------------------------------------------------+-- * CmmNode code generation+--++-- A statement conversion return data.+-- * LlvmStatements: The compiled LLVM statements.+-- * LlvmCmmDecl: Any global data needed.+type StmtData = (LlvmStatements, [LlvmCmmDecl])+++-- | Convert a list of CmmNode's to LlvmStatement's+stmtsToInstrs :: [CmmNode e x] -> LlvmM StmtData+stmtsToInstrs stmts+ = do (instrss, topss) <- fmap unzip $ mapM stmtToInstrs stmts+ return (concatOL instrss, concat topss)+++-- | Convert a CmmStmt to a list of LlvmStatement's+stmtToInstrs :: CmmNode e x -> LlvmM StmtData+stmtToInstrs stmt = case stmt of++ CmmComment _ -> return (nilOL, []) -- nuke comments+ CmmTick _ -> return (nilOL, [])+ CmmUnwind {} -> return (nilOL, [])++ CmmAssign reg src -> genAssign reg src+ CmmStore addr src -> genStore addr src++ CmmBranch id -> genBranch id+ CmmCondBranch arg true false likely+ -> genCondBranch arg true false likely+ CmmSwitch arg ids -> genSwitch arg ids++ -- Foreign Call+ CmmUnsafeForeignCall target res args+ -> genCall target res args++ -- Tail call+ CmmCall { cml_target = arg,+ cml_args_regs = live } -> genJump arg live++ _ -> panic "Llvm.CodeGen.stmtToInstrs"++-- | Wrapper function to declare an instrinct function by function type+getInstrinct2 :: LMString -> LlvmType -> LlvmM ExprData+getInstrinct2 fname fty@(LMFunction funSig) = do++ let fv = LMGlobalVar fname fty (funcLinkage funSig) Nothing Nothing Constant++ fn <- funLookup fname+ tops <- case fn of+ Just _ ->+ return []+ Nothing -> do+ funInsert fname fty+ un <- getUniqueM+ let lbl = mkAsmTempLabel un+ return [CmmData (Section Data lbl) [([],[fty])]]++ return (fv, nilOL, tops)++getInstrinct2 _ _ = error "getInstrinct2: Non-function type!"++-- | Declares an instrinct function by return and parameter types+getInstrinct :: LMString -> LlvmType -> [LlvmType] -> LlvmM ExprData+getInstrinct fname retTy parTys =+ let funSig = LlvmFunctionDecl fname ExternallyVisible CC_Ccc retTy+ FixedArgs (tysToParams parTys) Nothing+ fty = LMFunction funSig+ in getInstrinct2 fname fty++-- | Memory barrier instruction for LLVM >= 3.0+barrier :: LlvmM StmtData+barrier = do+ let s = Fence False SyncSeqCst+ return (unitOL s, [])++-- | Foreign Calls+genCall :: ForeignTarget -> [CmmFormal] -> [CmmActual]+ -> LlvmM StmtData++-- Write barrier needs to be handled specially as it is implemented as an LLVM+-- intrinsic function.+genCall (PrimTarget MO_WriteBarrier) _ _ = do+ platform <- getLlvmPlatform+ if platformArch platform `elem` [ArchX86, ArchX86_64, ArchSPARC]+ then return (nilOL, [])+ else barrier++genCall (PrimTarget MO_Touch) _ _+ = return (nilOL, [])++genCall (PrimTarget (MO_UF_Conv w)) [dst] [e] = runStmtsDecls $ do+ dstV <- getCmmRegW (CmmLocal dst)+ let ty = cmmToLlvmType $ localRegType dst+ width = widthToLlvmFloat w+ castV <- lift $ mkLocalVar ty+ ve <- exprToVarW e+ statement $ Assignment castV $ Cast LM_Uitofp ve width+ statement $ Store castV dstV++genCall (PrimTarget (MO_UF_Conv _)) [_] args =+ panic $ "genCall: Too many arguments to MO_UF_Conv. " +++ "Can only handle 1, given" ++ show (length args) ++ "."++-- Handle prefetching data+genCall t@(PrimTarget (MO_Prefetch_Data localityInt)) [] args+ | 0 <= localityInt && localityInt <= 3 = runStmtsDecls $ do+ let argTy = [i8Ptr, i32, i32, i32]+ funTy = \name -> LMFunction $ LlvmFunctionDecl name ExternallyVisible+ CC_Ccc LMVoid FixedArgs (tysToParams argTy) Nothing++ let (_, arg_hints) = foreignTargetHints t+ let args_hints' = zip args arg_hints+ argVars <- arg_varsW args_hints' ([], nilOL, [])+ fptr <- liftExprData $ getFunPtr funTy t+ argVars' <- castVarsW $ zip argVars argTy++ doTrashStmts+ let argSuffix = [mkIntLit i32 0, mkIntLit i32 localityInt, mkIntLit i32 1]+ statement $ Expr $ Call StdCall fptr (argVars' ++ argSuffix) []+ | otherwise = panic $ "prefetch locality level integer must be between 0 and 3, given: " ++ (show localityInt)++-- Handle PopCnt, Clz, Ctz, and BSwap that need to only convert arg+-- and return types+genCall t@(PrimTarget (MO_PopCnt w)) dsts args =+ genCallSimpleCast w t dsts args+genCall t@(PrimTarget (MO_Clz w)) dsts args =+ genCallSimpleCast w t dsts args+genCall t@(PrimTarget (MO_Ctz w)) dsts args =+ genCallSimpleCast w t dsts args+genCall t@(PrimTarget (MO_BSwap w)) dsts args =+ genCallSimpleCast w t dsts args++genCall (PrimTarget (MO_AtomicRMW width amop)) [dst] [addr, n] = runStmtsDecls $ do+ addrVar <- exprToVarW addr+ nVar <- exprToVarW n+ let targetTy = widthToLlvmInt width+ ptrExpr = Cast LM_Inttoptr addrVar (pLift targetTy)+ ptrVar <- doExprW (pLift targetTy) ptrExpr+ dstVar <- getCmmRegW (CmmLocal dst)+ let op = case amop of+ AMO_Add -> LAO_Add+ AMO_Sub -> LAO_Sub+ AMO_And -> LAO_And+ AMO_Nand -> LAO_Nand+ AMO_Or -> LAO_Or+ AMO_Xor -> LAO_Xor+ retVar <- doExprW targetTy $ AtomicRMW op ptrVar nVar SyncSeqCst+ statement $ Store retVar dstVar++genCall (PrimTarget (MO_AtomicRead _)) [dst] [addr] = runStmtsDecls $ do+ dstV <- getCmmRegW (CmmLocal dst)+ v1 <- genLoadW True addr (localRegType dst)+ statement $ Store v1 dstV++genCall (PrimTarget (MO_Cmpxchg _width))+ [dst] [addr, old, new] = runStmtsDecls $ do+ addrVar <- exprToVarW addr+ oldVar <- exprToVarW old+ newVar <- exprToVarW new+ let targetTy = getVarType oldVar+ ptrExpr = Cast LM_Inttoptr addrVar (pLift targetTy)+ ptrVar <- doExprW (pLift targetTy) ptrExpr+ dstVar <- getCmmRegW (CmmLocal dst)+ retVar <- doExprW (LMStructU [targetTy,i1])+ $ CmpXChg ptrVar oldVar newVar SyncSeqCst SyncSeqCst+ retVar' <- doExprW targetTy $ ExtractV retVar 0+ statement $ Store retVar' dstVar++genCall (PrimTarget (MO_AtomicWrite _width)) [] [addr, val] = runStmtsDecls $ do+ addrVar <- exprToVarW addr+ valVar <- exprToVarW val+ let ptrTy = pLift $ getVarType valVar+ ptrExpr = Cast LM_Inttoptr addrVar ptrTy+ ptrVar <- doExprW ptrTy ptrExpr+ statement $ Expr $ AtomicRMW LAO_Xchg ptrVar valVar SyncSeqCst++-- Handle memcpy function specifically since llvm's intrinsic version takes+-- some extra parameters.+genCall t@(PrimTarget op) [] args+ | Just align <- machOpMemcpyishAlign op = runStmtsDecls $ do+ dflags <- getDynFlags+ let isVolTy = [i1]+ isVolVal = [mkIntLit i1 0]+ argTy | MO_Memset _ <- op = [i8Ptr, i8, llvmWord dflags, i32] ++ isVolTy+ | otherwise = [i8Ptr, i8Ptr, llvmWord dflags, i32] ++ isVolTy+ funTy = \name -> LMFunction $ LlvmFunctionDecl name ExternallyVisible+ CC_Ccc LMVoid FixedArgs (tysToParams argTy) Nothing++ let (_, arg_hints) = foreignTargetHints t+ let args_hints = zip args arg_hints+ argVars <- arg_varsW args_hints ([], nilOL, [])+ fptr <- getFunPtrW funTy t+ argVars' <- castVarsW $ zip argVars argTy++ doTrashStmts+ let alignVal = mkIntLit i32 align+ arguments = argVars' ++ (alignVal:isVolVal)+ statement $ Expr $ Call StdCall fptr arguments []++-- We handle MO_U_Mul2 by simply using a 'mul' instruction, but with operands+-- twice the width (we first zero-extend them), e.g., on 64-bit arch we will+-- generate 'mul' on 128-bit operands. Then we only need some plumbing to+-- extract the two 64-bit values out of 128-bit result.+genCall (PrimTarget (MO_U_Mul2 w)) [dstH, dstL] [lhs, rhs] = runStmtsDecls $ do+ let width = widthToLlvmInt w+ bitWidth = widthInBits w+ width2x = LMInt (bitWidth * 2)+ -- First zero-extend the operands ('mul' instruction requires the operands+ -- and the result to be of the same type). Note that we don't use 'castVars'+ -- because it tries to do LM_Sext.+ lhsVar <- exprToVarW lhs+ rhsVar <- exprToVarW rhs+ lhsExt <- doExprW width2x $ Cast LM_Zext lhsVar width2x+ rhsExt <- doExprW width2x $ Cast LM_Zext rhsVar width2x+ -- Do the actual multiplication (note that the result is also 2x width).+ retV <- doExprW width2x $ LlvmOp LM_MO_Mul lhsExt rhsExt+ -- Extract the lower bits of the result into retL.+ retL <- doExprW width $ Cast LM_Trunc retV width+ -- Now we right-shift the higher bits by width.+ let widthLlvmLit = LMLitVar $ LMIntLit (fromIntegral bitWidth) width+ retShifted <- doExprW width2x $ LlvmOp LM_MO_LShr retV widthLlvmLit+ -- And extract them into retH.+ retH <- doExprW width $ Cast LM_Trunc retShifted width+ dstRegL <- getCmmRegW (CmmLocal dstL)+ dstRegH <- getCmmRegW (CmmLocal dstH)+ statement $ Store retL dstRegL+ statement $ Store retH dstRegH++-- MO_U_QuotRem2 is another case we handle by widening the registers to double+-- the width and use normal LLVM instructions (similarly to the MO_U_Mul2). The+-- main difference here is that we need to combine two words into one register+-- and then use both 'udiv' and 'urem' instructions to compute the result.+genCall (PrimTarget (MO_U_QuotRem2 w))+ [dstQ, dstR] [lhsH, lhsL, rhs] = runStmtsDecls $ do+ let width = widthToLlvmInt w+ bitWidth = widthInBits w+ width2x = LMInt (bitWidth * 2)+ -- First zero-extend all parameters to double width.+ let zeroExtend expr = do+ var <- exprToVarW expr+ doExprW width2x $ Cast LM_Zext var width2x+ lhsExtH <- zeroExtend lhsH+ lhsExtL <- zeroExtend lhsL+ rhsExt <- zeroExtend rhs+ -- Now we combine the first two parameters (that represent the high and low+ -- bits of the value). So first left-shift the high bits to their position+ -- and then bit-or them with the low bits.+ let widthLlvmLit = LMLitVar $ LMIntLit (fromIntegral bitWidth) width+ lhsExtHShifted <- doExprW width2x $ LlvmOp LM_MO_Shl lhsExtH widthLlvmLit+ lhsExt <- doExprW width2x $ LlvmOp LM_MO_Or lhsExtHShifted lhsExtL+ -- Finally, we can call 'udiv' and 'urem' to compute the results.+ retExtDiv <- doExprW width2x $ LlvmOp LM_MO_UDiv lhsExt rhsExt+ retExtRem <- doExprW width2x $ LlvmOp LM_MO_URem lhsExt rhsExt+ -- And since everything is in 2x width, we need to truncate the results and+ -- then return them.+ let narrow var = doExprW width $ Cast LM_Trunc var width+ retDiv <- narrow retExtDiv+ retRem <- narrow retExtRem+ dstRegQ <- lift $ getCmmReg (CmmLocal dstQ)+ dstRegR <- lift $ getCmmReg (CmmLocal dstR)+ statement $ Store retDiv dstRegQ+ statement $ Store retRem dstRegR++-- Handle the MO_{Add,Sub}IntC separately. LLVM versions return a record from+-- which we need to extract the actual values.+genCall t@(PrimTarget (MO_AddIntC w)) [dstV, dstO] [lhs, rhs] =+ genCallWithOverflow t w [dstV, dstO] [lhs, rhs]+genCall t@(PrimTarget (MO_SubIntC w)) [dstV, dstO] [lhs, rhs] =+ genCallWithOverflow t w [dstV, dstO] [lhs, rhs]++-- Similar to MO_{Add,Sub}IntC, but MO_Add2 expects the first element of the+-- return tuple to be the overflow bit and the second element to contain the+-- actual result of the addition. So we still use genCallWithOverflow but swap+-- the return registers.+genCall t@(PrimTarget (MO_Add2 w)) [dstO, dstV] [lhs, rhs] =+ genCallWithOverflow t w [dstV, dstO] [lhs, rhs]++genCall t@(PrimTarget (MO_SubWordC w)) [dstV, dstO] [lhs, rhs] =+ genCallWithOverflow t w [dstV, dstO] [lhs, rhs]++-- Handle all other foreign calls and prim ops.+genCall target res args = runStmtsDecls $ do+ dflags <- getDynFlags++ -- parameter types+ let arg_type (_, AddrHint) = i8Ptr+ -- cast pointers to i8*. Llvm equivalent of void*+ arg_type (expr, _) = cmmToLlvmType $ cmmExprType dflags expr++ -- ret type+ let ret_type [] = LMVoid+ ret_type [(_, AddrHint)] = i8Ptr+ ret_type [(reg, _)] = cmmToLlvmType $ localRegType reg+ ret_type t = panic $ "genCall: Too many return values! Can only handle"+ ++ " 0 or 1, given " ++ show (length t) ++ "."++ -- extract Cmm call convention, and translate to LLVM call convention+ platform <- lift $ getLlvmPlatform+ let lmconv = case target of+ ForeignTarget _ (ForeignConvention conv _ _ _) ->+ case conv of+ StdCallConv -> case platformArch platform of+ ArchX86 -> CC_X86_Stdcc+ ArchX86_64 -> CC_X86_Stdcc+ _ -> CC_Ccc+ CCallConv -> CC_Ccc+ CApiConv -> CC_Ccc+ PrimCallConv -> panic "LlvmCodeGen.CodeGen.genCall: PrimCallConv"+ JavaScriptCallConv -> panic "LlvmCodeGen.CodeGen.genCall: JavaScriptCallConv"++ PrimTarget _ -> CC_Ccc++ {-+ CC_Ccc of the possibilities here are a worry with the use of a custom+ calling convention for passing STG args. In practice the more+ dangerous combinations (e.g StdCall + llvmGhcCC) don't occur.++ The native code generator only handles StdCall and CCallConv.+ -}++ -- call attributes+ let fnAttrs | never_returns = NoReturn : llvmStdFunAttrs+ | otherwise = llvmStdFunAttrs++ never_returns = case target of+ ForeignTarget _ (ForeignConvention _ _ _ CmmNeverReturns) -> True+ _ -> False++ -- fun type+ let (res_hints, arg_hints) = foreignTargetHints target+ let args_hints = zip args arg_hints+ let ress_hints = zip res res_hints+ let ccTy = StdCall -- tail calls should be done through CmmJump+ let retTy = ret_type ress_hints+ let argTy = tysToParams $ map arg_type args_hints+ let funTy = \name -> LMFunction $ LlvmFunctionDecl name ExternallyVisible+ lmconv retTy FixedArgs argTy (llvmFunAlign dflags)+++ argVars <- arg_varsW args_hints ([], nilOL, [])+ fptr <- getFunPtrW funTy target++ let doReturn | ccTy == TailCall = statement $ Return Nothing+ | never_returns = statement $ Unreachable+ | otherwise = return ()++ doTrashStmts++ -- make the actual call+ case retTy of+ LMVoid -> do+ statement $ Expr $ Call ccTy fptr argVars fnAttrs++ _ -> do+ v1 <- doExprW retTy $ Call ccTy fptr argVars fnAttrs+ -- get the return register+ let ret_reg [reg] = reg+ ret_reg t = panic $ "genCall: Bad number of registers! Can only handle"+ ++ " 1, given " ++ show (length t) ++ "."+ let creg = ret_reg res+ vreg <- getCmmRegW (CmmLocal creg)+ if retTy == pLower (getVarType vreg)+ then do+ statement $ Store v1 vreg+ doReturn+ else do+ let ty = pLower $ getVarType vreg+ let op = case ty of+ vt | isPointer vt -> LM_Bitcast+ | isInt vt -> LM_Ptrtoint+ | otherwise ->+ panic $ "genCall: CmmReg bad match for"+ ++ " returned type!"++ v2 <- doExprW ty $ Cast op v1 ty+ statement $ Store v2 vreg+ doReturn++-- | Generate a call to an LLVM intrinsic that performs arithmetic operation+-- with overflow bit (i.e., returns a struct containing the actual result of the+-- operation and an overflow bit). This function will also extract the overflow+-- bit and zero-extend it (all the corresponding Cmm PrimOps represent the+-- overflow "bit" as a usual Int# or Word#).+genCallWithOverflow+ :: ForeignTarget -> Width -> [CmmFormal] -> [CmmActual] -> LlvmM StmtData+genCallWithOverflow t@(PrimTarget op) w [dstV, dstO] [lhs, rhs] = do+ -- So far this was only tested for the following four CallishMachOps.+ let valid = op `elem` [ MO_Add2 w+ , MO_AddIntC w+ , MO_SubIntC w+ , MO_SubWordC w+ ]+ MASSERT(valid)+ let width = widthToLlvmInt w+ -- This will do most of the work of generating the call to the intrinsic and+ -- extracting the values from the struct.+ (value, overflowBit, (stmts, top)) <-+ genCallExtract t w (lhs, rhs) (width, i1)+ -- value is i<width>, but overflowBit is i1, so we need to cast (Cmm expects+ -- both to be i<width>)+ (overflow, zext) <- doExpr width $ Cast LM_Zext overflowBit width+ dstRegV <- getCmmReg (CmmLocal dstV)+ dstRegO <- getCmmReg (CmmLocal dstO)+ let storeV = Store value dstRegV+ storeO = Store overflow dstRegO+ return (stmts `snocOL` zext `snocOL` storeV `snocOL` storeO, top)+genCallWithOverflow _ _ _ _ =+ panic "genCallExtract: wrong ForeignTarget or number of arguments"++-- | A helper function for genCallWithOverflow that handles generating the call+-- to the LLVM intrinsic and extracting the result from the struct to LlvmVars.+genCallExtract+ :: ForeignTarget -- ^ PrimOp+ -> Width -- ^ Width of the operands.+ -> (CmmActual, CmmActual) -- ^ Actual arguments.+ -> (LlvmType, LlvmType) -- ^ LLLVM types of the returned sturct.+ -> LlvmM (LlvmVar, LlvmVar, StmtData)+genCallExtract target@(PrimTarget op) w (argA, argB) (llvmTypeA, llvmTypeB) = do+ let width = widthToLlvmInt w+ argTy = [width, width]+ retTy = LMStructU [llvmTypeA, llvmTypeB]++ -- Process the arguments.+ let args_hints = zip [argA, argB] (snd $ foreignTargetHints target)+ (argsV1, args1, top1) <- arg_vars args_hints ([], nilOL, [])+ (argsV2, args2) <- castVars $ zip argsV1 argTy++ -- Get the function and make the call.+ fname <- cmmPrimOpFunctions op+ (fptr, _, top2) <- getInstrinct fname retTy argTy+ -- We use StdCall for primops. See also the last case of genCall.+ (retV, call) <- doExpr retTy $ Call StdCall fptr argsV2 []++ -- This will result in a two element struct, we need to use "extractvalue"+ -- to get them out of it.+ (res1, ext1) <- doExpr llvmTypeA (ExtractV retV 0)+ (res2, ext2) <- doExpr llvmTypeB (ExtractV retV 1)++ let stmts = args1 `appOL` args2 `snocOL` call `snocOL` ext1 `snocOL` ext2+ tops = top1 ++ top2+ return (res1, res2, (stmts, tops))++genCallExtract _ _ _ _ =+ panic "genCallExtract: unsupported ForeignTarget"++-- Handle simple function call that only need simple type casting, of the form:+-- truncate arg >>= \a -> call(a) >>= zext+--+-- since GHC only really has i32 and i64 types and things like Word8 are backed+-- by an i32 and just present a logical i8 range. So we must handle conversions+-- from i32 to i8 explicitly as LLVM is strict about types.+genCallSimpleCast :: Width -> ForeignTarget -> [CmmFormal] -> [CmmActual]+ -> LlvmM StmtData+genCallSimpleCast w t@(PrimTarget op) [dst] args = do+ let width = widthToLlvmInt w+ dstTy = cmmToLlvmType $ localRegType dst++ fname <- cmmPrimOpFunctions op+ (fptr, _, top3) <- getInstrinct fname width [width]++ dstV <- getCmmReg (CmmLocal dst)++ let (_, arg_hints) = foreignTargetHints t+ let args_hints = zip args arg_hints+ (argsV, stmts2, top2) <- arg_vars args_hints ([], nilOL, [])+ (argsV', stmts4) <- castVars $ zip argsV [width]+ (retV, s1) <- doExpr width $ Call StdCall fptr argsV' []+ ([retV'], stmts5) <- castVars [(retV,dstTy)]+ let s2 = Store retV' dstV++ let stmts = stmts2 `appOL` stmts4 `snocOL`+ s1 `appOL` stmts5 `snocOL` s2+ return (stmts, top2 ++ top3)+genCallSimpleCast _ _ dsts _ =+ panic ("genCallSimpleCast: " ++ show (length dsts) ++ " dsts")++-- | Create a function pointer from a target.+getFunPtrW :: (LMString -> LlvmType) -> ForeignTarget+ -> WriterT LlvmAccum LlvmM LlvmVar+getFunPtrW funTy targ = liftExprData $ getFunPtr funTy targ++-- | Create a function pointer from a target.+getFunPtr :: (LMString -> LlvmType) -> ForeignTarget+ -> LlvmM ExprData+getFunPtr funTy targ = case targ of+ ForeignTarget (CmmLit (CmmLabel lbl)) _ -> do+ name <- strCLabel_llvm lbl+ getHsFunc' name (funTy name)++ ForeignTarget expr _ -> do+ (v1, stmts, top) <- exprToVar expr+ dflags <- getDynFlags+ let fty = funTy $ fsLit "dynamic"+ cast = case getVarType v1 of+ ty | isPointer ty -> LM_Bitcast+ ty | isInt ty -> LM_Inttoptr++ ty -> panic $ "genCall: Expr is of bad type for function"+ ++ " call! (" ++ showSDoc dflags (ppr ty) ++ ")"++ (v2,s1) <- doExpr (pLift fty) $ Cast cast v1 (pLift fty)+ return (v2, stmts `snocOL` s1, top)++ PrimTarget mop -> do+ name <- cmmPrimOpFunctions mop+ let fty = funTy name+ getInstrinct2 name fty++-- | Conversion of call arguments.+arg_varsW :: [(CmmActual, ForeignHint)]+ -> ([LlvmVar], LlvmStatements, [LlvmCmmDecl])+ -> WriterT LlvmAccum LlvmM [LlvmVar]+arg_varsW xs ys = do+ (vars, stmts, decls) <- lift $ arg_vars xs ys+ tell $ LlvmAccum stmts decls+ return vars++-- | Conversion of call arguments.+arg_vars :: [(CmmActual, ForeignHint)]+ -> ([LlvmVar], LlvmStatements, [LlvmCmmDecl])+ -> LlvmM ([LlvmVar], LlvmStatements, [LlvmCmmDecl])++arg_vars [] (vars, stmts, tops)+ = return (vars, stmts, tops)++arg_vars ((e, AddrHint):rest) (vars, stmts, tops)+ = do (v1, stmts', top') <- exprToVar e+ dflags <- getDynFlags+ let op = case getVarType v1 of+ ty | isPointer ty -> LM_Bitcast+ ty | isInt ty -> LM_Inttoptr++ a -> panic $ "genCall: Can't cast llvmType to i8*! ("+ ++ showSDoc dflags (ppr a) ++ ")"++ (v2, s1) <- doExpr i8Ptr $ Cast op v1 i8Ptr+ arg_vars rest (vars ++ [v2], stmts `appOL` stmts' `snocOL` s1,+ tops ++ top')++arg_vars ((e, _):rest) (vars, stmts, tops)+ = do (v1, stmts', top') <- exprToVar e+ arg_vars rest (vars ++ [v1], stmts `appOL` stmts', tops ++ top')+++-- | Cast a collection of LLVM variables to specific types.+castVarsW :: [(LlvmVar, LlvmType)]+ -> WriterT LlvmAccum LlvmM [LlvmVar]+castVarsW vars = do+ (vars, stmts) <- lift $ castVars vars+ tell $ LlvmAccum stmts mempty+ return vars++-- | Cast a collection of LLVM variables to specific types.+castVars :: [(LlvmVar, LlvmType)]+ -> LlvmM ([LlvmVar], LlvmStatements)+castVars vars = do+ done <- mapM (uncurry castVar) vars+ let (vars', stmts) = unzip done+ return (vars', toOL stmts)++-- | Cast an LLVM variable to a specific type, panicing if it can't be done.+castVar :: LlvmVar -> LlvmType -> LlvmM (LlvmVar, LlvmStatement)+castVar v t | getVarType v == t+ = return (v, Nop)++ | otherwise+ = do dflags <- getDynFlags+ let op = case (getVarType v, t) of+ (LMInt n, LMInt m)+ -> if n < m then LM_Sext else LM_Trunc+ (vt, _) | isFloat vt && isFloat t+ -> if llvmWidthInBits dflags vt < llvmWidthInBits dflags t+ then LM_Fpext else LM_Fptrunc+ (vt, _) | isInt vt && isFloat t -> LM_Sitofp+ (vt, _) | isFloat vt && isInt t -> LM_Fptosi+ (vt, _) | isInt vt && isPointer t -> LM_Inttoptr+ (vt, _) | isPointer vt && isInt t -> LM_Ptrtoint+ (vt, _) | isPointer vt && isPointer t -> LM_Bitcast+ (vt, _) | isVector vt && isVector t -> LM_Bitcast++ (vt, _) -> panic $ "castVars: Can't cast this type ("+ ++ showSDoc dflags (ppr vt) ++ ") to (" ++ showSDoc dflags (ppr t) ++ ")"+ doExpr t $ Cast op v t+++-- | Decide what C function to use to implement a CallishMachOp+cmmPrimOpFunctions :: CallishMachOp -> LlvmM LMString+cmmPrimOpFunctions mop = do++ dflags <- getDynFlags+ let intrinTy1 = "p0i8.p0i8." ++ showSDoc dflags (ppr $ llvmWord dflags)+ intrinTy2 = "p0i8." ++ showSDoc dflags (ppr $ llvmWord dflags)+ unsupported = panic ("cmmPrimOpFunctions: " ++ show mop+ ++ " not supported here")++ return $ case mop of+ MO_F32_Exp -> fsLit "expf"+ MO_F32_Log -> fsLit "logf"+ MO_F32_Sqrt -> fsLit "llvm.sqrt.f32"+ MO_F32_Fabs -> fsLit "llvm.fabs.f32"+ MO_F32_Pwr -> fsLit "llvm.pow.f32"++ MO_F32_Sin -> fsLit "llvm.sin.f32"+ MO_F32_Cos -> fsLit "llvm.cos.f32"+ MO_F32_Tan -> fsLit "tanf"++ MO_F32_Asin -> fsLit "asinf"+ MO_F32_Acos -> fsLit "acosf"+ MO_F32_Atan -> fsLit "atanf"++ MO_F32_Sinh -> fsLit "sinhf"+ MO_F32_Cosh -> fsLit "coshf"+ MO_F32_Tanh -> fsLit "tanhf"++ MO_F64_Exp -> fsLit "exp"+ MO_F64_Log -> fsLit "log"+ MO_F64_Sqrt -> fsLit "llvm.sqrt.f64"+ MO_F64_Fabs -> fsLit "llvm.fabs.f64"+ MO_F64_Pwr -> fsLit "llvm.pow.f64"++ MO_F64_Sin -> fsLit "llvm.sin.f64"+ MO_F64_Cos -> fsLit "llvm.cos.f64"+ MO_F64_Tan -> fsLit "tan"++ MO_F64_Asin -> fsLit "asin"+ MO_F64_Acos -> fsLit "acos"+ MO_F64_Atan -> fsLit "atan"++ MO_F64_Sinh -> fsLit "sinh"+ MO_F64_Cosh -> fsLit "cosh"+ MO_F64_Tanh -> fsLit "tanh"++ MO_Memcpy _ -> fsLit $ "llvm.memcpy." ++ intrinTy1+ MO_Memmove _ -> fsLit $ "llvm.memmove." ++ intrinTy1+ MO_Memset _ -> fsLit $ "llvm.memset." ++ intrinTy2++ (MO_PopCnt w) -> fsLit $ "llvm.ctpop." ++ showSDoc dflags (ppr $ widthToLlvmInt w)+ (MO_BSwap w) -> fsLit $ "llvm.bswap." ++ showSDoc dflags (ppr $ widthToLlvmInt w)+ (MO_Clz w) -> fsLit $ "llvm.ctlz." ++ showSDoc dflags (ppr $ widthToLlvmInt w)+ (MO_Ctz w) -> fsLit $ "llvm.cttz." ++ showSDoc dflags (ppr $ widthToLlvmInt w)++ (MO_Prefetch_Data _ )-> fsLit "llvm.prefetch"++ MO_AddIntC w -> fsLit $ "llvm.sadd.with.overflow."+ ++ showSDoc dflags (ppr $ widthToLlvmInt w)+ MO_SubIntC w -> fsLit $ "llvm.ssub.with.overflow."+ ++ showSDoc dflags (ppr $ widthToLlvmInt w)+ MO_Add2 w -> fsLit $ "llvm.uadd.with.overflow."+ ++ showSDoc dflags (ppr $ widthToLlvmInt w)+ MO_SubWordC w -> fsLit $ "llvm.usub.with.overflow."+ ++ showSDoc dflags (ppr $ widthToLlvmInt w)++ MO_S_QuotRem {} -> unsupported+ MO_U_QuotRem {} -> unsupported+ MO_U_QuotRem2 {} -> unsupported+ -- We support MO_U_Mul2 through ordinary LLVM mul instruction, see the+ -- appropriate case of genCall.+ MO_U_Mul2 {} -> unsupported+ MO_WriteBarrier -> unsupported+ MO_Touch -> unsupported+ MO_UF_Conv _ -> unsupported++ MO_AtomicRead _ -> unsupported+ MO_AtomicRMW _ _ -> unsupported+ MO_AtomicWrite _ -> unsupported+ MO_Cmpxchg _ -> unsupported++-- | Tail function calls+genJump :: CmmExpr -> [GlobalReg] -> LlvmM StmtData++-- Call to known function+genJump (CmmLit (CmmLabel lbl)) live = do+ (vf, stmts, top) <- getHsFunc live lbl+ (stgRegs, stgStmts) <- funEpilogue live+ let s1 = Expr $ Call TailCall vf stgRegs llvmStdFunAttrs+ let s2 = Return Nothing+ return (stmts `appOL` stgStmts `snocOL` s1 `snocOL` s2, top)+++-- Call to unknown function / address+genJump expr live = do+ fty <- llvmFunTy live+ (vf, stmts, top) <- exprToVar expr+ dflags <- getDynFlags++ let cast = case getVarType vf of+ ty | isPointer ty -> LM_Bitcast+ ty | isInt ty -> LM_Inttoptr++ ty -> panic $ "genJump: Expr is of bad type for function call! ("+ ++ showSDoc dflags (ppr ty) ++ ")"++ (v1, s1) <- doExpr (pLift fty) $ Cast cast vf (pLift fty)+ (stgRegs, stgStmts) <- funEpilogue live+ let s2 = Expr $ Call TailCall v1 stgRegs llvmStdFunAttrs+ let s3 = Return Nothing+ return (stmts `snocOL` s1 `appOL` stgStmts `snocOL` s2 `snocOL` s3,+ top)+++-- | CmmAssign operation+--+-- We use stack allocated variables for CmmReg. The optimiser will replace+-- these with registers when possible.+genAssign :: CmmReg -> CmmExpr -> LlvmM StmtData+genAssign reg val = do+ vreg <- getCmmReg reg+ (vval, stmts2, top2) <- exprToVar val+ let stmts = stmts2++ let ty = (pLower . getVarType) vreg+ dflags <- getDynFlags+ case ty of+ -- Some registers are pointer types, so need to cast value to pointer+ LMPointer _ | getVarType vval == llvmWord dflags -> do+ (v, s1) <- doExpr ty $ Cast LM_Inttoptr vval ty+ let s2 = Store v vreg+ return (stmts `snocOL` s1 `snocOL` s2, top2)++ LMVector _ _ -> do+ (v, s1) <- doExpr ty $ Cast LM_Bitcast vval ty+ let s2 = Store v vreg+ return (stmts `snocOL` s1 `snocOL` s2, top2)++ _ -> do+ let s1 = Store vval vreg+ return (stmts `snocOL` s1, top2)+++-- | CmmStore operation+genStore :: CmmExpr -> CmmExpr -> LlvmM StmtData++-- First we try to detect a few common cases and produce better code for+-- these then the default case. We are mostly trying to detect Cmm code+-- like I32[Sp + n] and use 'getelementptr' operations instead of the+-- generic case that uses casts and pointer arithmetic+genStore addr@(CmmReg (CmmGlobal r)) val+ = genStore_fast addr r 0 val++genStore addr@(CmmRegOff (CmmGlobal r) n) val+ = genStore_fast addr r n val++genStore addr@(CmmMachOp (MO_Add _) [+ (CmmReg (CmmGlobal r)),+ (CmmLit (CmmInt n _))])+ val+ = genStore_fast addr r (fromInteger n) val++genStore addr@(CmmMachOp (MO_Sub _) [+ (CmmReg (CmmGlobal r)),+ (CmmLit (CmmInt n _))])+ val+ = genStore_fast addr r (negate $ fromInteger n) val++-- generic case+genStore addr val+ = getTBAAMeta topN >>= genStore_slow addr val++-- | CmmStore operation+-- This is a special case for storing to a global register pointer+-- offset such as I32[Sp+8].+genStore_fast :: CmmExpr -> GlobalReg -> Int -> CmmExpr+ -> LlvmM StmtData+genStore_fast addr r n val+ = do dflags <- getDynFlags+ (gv, grt, s1) <- getCmmRegVal (CmmGlobal r)+ meta <- getTBAARegMeta r+ let (ix,rem) = n `divMod` ((llvmWidthInBits dflags . pLower) grt `div` 8)+ case isPointer grt && rem == 0 of+ True -> do+ (vval, stmts, top) <- exprToVar val+ (ptr, s2) <- doExpr grt $ GetElemPtr True gv [toI32 ix]+ -- We might need a different pointer type, so check+ case pLower grt == getVarType vval of+ -- were fine+ True -> do+ let s3 = MetaStmt meta $ Store vval ptr+ return (stmts `appOL` s1 `snocOL` s2+ `snocOL` s3, top)++ -- cast to pointer type needed+ False -> do+ let ty = (pLift . getVarType) vval+ (ptr', s3) <- doExpr ty $ Cast LM_Bitcast ptr ty+ let s4 = MetaStmt meta $ Store vval ptr'+ return (stmts `appOL` s1 `snocOL` s2+ `snocOL` s3 `snocOL` s4, top)++ -- If its a bit type then we use the slow method since+ -- we can't avoid casting anyway.+ False -> genStore_slow addr val meta+++-- | CmmStore operation+-- Generic case. Uses casts and pointer arithmetic if needed.+genStore_slow :: CmmExpr -> CmmExpr -> [MetaAnnot] -> LlvmM StmtData+genStore_slow addr val meta = do+ (vaddr, stmts1, top1) <- exprToVar addr+ (vval, stmts2, top2) <- exprToVar val++ let stmts = stmts1 `appOL` stmts2+ dflags <- getDynFlags+ case getVarType vaddr of+ -- sometimes we need to cast an int to a pointer before storing+ LMPointer ty@(LMPointer _) | getVarType vval == llvmWord dflags -> do+ (v, s1) <- doExpr ty $ Cast LM_Inttoptr vval ty+ let s2 = MetaStmt meta $ Store v vaddr+ return (stmts `snocOL` s1 `snocOL` s2, top1 ++ top2)++ LMPointer _ -> do+ let s1 = MetaStmt meta $ Store vval vaddr+ return (stmts `snocOL` s1, top1 ++ top2)++ i@(LMInt _) | i == llvmWord dflags -> do+ let vty = pLift $ getVarType vval+ (vptr, s1) <- doExpr vty $ Cast LM_Inttoptr vaddr vty+ let s2 = MetaStmt meta $ Store vval vptr+ return (stmts `snocOL` s1 `snocOL` s2, top1 ++ top2)++ other ->+ pprPanic "genStore: ptr not right type!"+ (PprCmm.pprExpr addr <+> text (+ "Size of Ptr: " ++ show (llvmPtrBits dflags) +++ ", Size of var: " ++ show (llvmWidthInBits dflags other) +++ ", Var: " ++ showSDoc dflags (ppr vaddr)))+++-- | Unconditional branch+genBranch :: BlockId -> LlvmM StmtData+genBranch id =+ let label = blockIdToLlvm id+ in return (unitOL $ Branch label, [])+++-- | Conditional branch+genCondBranch :: CmmExpr -> BlockId -> BlockId -> Maybe Bool -> LlvmM StmtData+genCondBranch cond idT idF likely = do+ let labelT = blockIdToLlvm idT+ let labelF = blockIdToLlvm idF+ -- See Note [Literals and branch conditions].+ (vc, stmts1, top1) <- exprToVarOpt i1Option cond+ if getVarType vc == i1+ then do+ (vc', (stmts2, top2)) <- case likely of+ Just b -> genExpectLit (if b then 1 else 0) i1 vc+ _ -> pure (vc, (nilOL, []))+ let s1 = BranchIf vc' labelT labelF+ return (stmts1 `appOL` stmts2 `snocOL` s1, top1 ++ top2)+ else do+ dflags <- getDynFlags+ panic $ "genCondBranch: Cond expr not bool! (" ++ showSDoc dflags (ppr vc) ++ ")"+++-- | Generate call to llvm.expect.x intrinsic. Assigning result to a new var.+genExpectLit :: Integer -> LlvmType -> LlvmVar -> LlvmM (LlvmVar, StmtData)+genExpectLit expLit expTy var = do+ dflags <- getDynFlags++ let+ lit = LMLitVar $ LMIntLit expLit expTy++ llvmExpectName+ | isInt expTy = fsLit $ "llvm.expect." ++ showSDoc dflags (ppr expTy)+ | otherwise = panic $ "genExpectedLit: Type not an int!"++ (llvmExpect, stmts, top) <-+ getInstrinct llvmExpectName expTy [expTy, expTy]+ (var', call) <- doExpr expTy $ Call StdCall llvmExpect [var, lit] []+ return (var', (stmts `snocOL` call, top))++{- Note [Literals and branch conditions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++It is important that whenever we generate branch conditions for+literals like '1', they are properly narrowed to an LLVM expression of+type 'i1' (for bools.) Otherwise, nobody is happy. So when we convert+a CmmExpr to an LLVM expression for a branch conditional, exprToVarOpt+must be certain to return a properly narrowed type. genLit is+responsible for this, in the case of literal integers.++Often, we won't see direct statements like:++ if(1) {+ ...+ } else {+ ...+ }++at this point in the pipeline, because the Glorious Code Generator+will do trivial branch elimination in the sinking pass (among others,)+which will eliminate the expression entirely.++However, it's certainly possible and reasonable for this to occur in+hand-written C-- code. Consider something like:++ #ifndef SOME_CONDITIONAL+ #define CHECK_THING(x) 1+ #else+ #define CHECK_THING(x) some_operation((x))+ #endif++ f() {++ if (CHECK_THING(xyz)) {+ ...+ } else {+ ...+ }++ }++In such an instance, CHECK_THING might result in an *expression* in+one case, and a *literal* in the other, depending on what in+particular was #define'd. So we must be sure to properly narrow the+literal in this case to i1 as it won't be eliminated beforehand.++For a real example of this, see ./rts/StgStdThunks.cmm++-}++++-- | Switch branch+genSwitch :: CmmExpr -> SwitchTargets -> LlvmM StmtData+genSwitch cond ids = do+ (vc, stmts, top) <- exprToVar cond+ let ty = getVarType vc++ let labels = [ (mkIntLit ty ix, blockIdToLlvm b)+ | (ix, b) <- switchTargetsCases ids ]+ -- out of range is undefined, so let's just branch to first label+ let defLbl | Just l <- switchTargetsDefault ids = blockIdToLlvm l+ | otherwise = snd (head labels)++ let s1 = Switch vc defLbl labels+ return $ (stmts `snocOL` s1, top)+++-- -----------------------------------------------------------------------------+-- * CmmExpr code generation+--++-- | An expression conversion return data:+-- * LlvmVar: The var holding the result of the expression+-- * LlvmStatements: Any statements needed to evaluate the expression+-- * LlvmCmmDecl: Any global data needed for this expression+type ExprData = (LlvmVar, LlvmStatements, [LlvmCmmDecl])++-- | Values which can be passed to 'exprToVar' to configure its+-- behaviour in certain circumstances.+--+-- Currently just used for determining if a comparison should return+-- a boolean (i1) or a word. See Note [Literals and branch conditions].+newtype EOption = EOption { i1Expected :: Bool }+-- XXX: EOption is an ugly and inefficient solution to this problem.++-- | i1 type expected (condition scrutinee).+i1Option :: EOption+i1Option = EOption True++-- | Word type expected (usual).+wordOption :: EOption+wordOption = EOption False++-- | Convert a CmmExpr to a list of LlvmStatements with the result of the+-- expression being stored in the returned LlvmVar.+exprToVar :: CmmExpr -> LlvmM ExprData+exprToVar = exprToVarOpt wordOption++exprToVarOpt :: EOption -> CmmExpr -> LlvmM ExprData+exprToVarOpt opt e = case e of++ CmmLit lit+ -> genLit opt lit++ CmmLoad e' ty+ -> genLoad False e' ty++ -- Cmmreg in expression is the value, so must load. If you want actual+ -- reg pointer, call getCmmReg directly.+ CmmReg r -> do+ (v1, ty, s1) <- getCmmRegVal r+ case isPointer ty of+ True -> do+ -- Cmm wants the value, so pointer types must be cast to ints+ dflags <- getDynFlags+ (v2, s2) <- doExpr (llvmWord dflags) $ Cast LM_Ptrtoint v1 (llvmWord dflags)+ return (v2, s1 `snocOL` s2, [])++ False -> return (v1, s1, [])++ CmmMachOp op exprs+ -> genMachOp opt op exprs++ CmmRegOff r i+ -> do dflags <- getDynFlags+ exprToVar $ expandCmmReg dflags (r, i)++ CmmStackSlot _ _+ -> panic "exprToVar: CmmStackSlot not supported!"+++-- | Handle CmmMachOp expressions+genMachOp :: EOption -> MachOp -> [CmmExpr] -> LlvmM ExprData++-- Unary Machop+genMachOp _ op [x] = case op of++ MO_Not w ->+ let all1 = mkIntLit (widthToLlvmInt w) (-1)+ in negate (widthToLlvmInt w) all1 LM_MO_Xor++ MO_S_Neg w ->+ let all0 = mkIntLit (widthToLlvmInt w) 0+ in negate (widthToLlvmInt w) all0 LM_MO_Sub++ MO_F_Neg w ->+ let all0 = LMLitVar $ LMFloatLit (-0) (widthToLlvmFloat w)+ in negate (widthToLlvmFloat w) all0 LM_MO_FSub++ MO_SF_Conv _ w -> fiConv (widthToLlvmFloat w) LM_Sitofp+ MO_FS_Conv _ w -> fiConv (widthToLlvmInt w) LM_Fptosi++ MO_SS_Conv from to+ -> sameConv from (widthToLlvmInt to) LM_Trunc LM_Sext++ MO_UU_Conv from to+ -> sameConv from (widthToLlvmInt to) LM_Trunc LM_Zext++ MO_FF_Conv from to+ -> sameConv from (widthToLlvmFloat to) LM_Fptrunc LM_Fpext++ MO_VS_Neg len w ->+ let ty = widthToLlvmInt w+ vecty = LMVector len ty+ all0 = LMIntLit (-0) ty+ all0s = LMLitVar $ LMVectorLit (replicate len all0)+ in negateVec vecty all0s LM_MO_Sub++ MO_VF_Neg len w ->+ let ty = widthToLlvmFloat w+ vecty = LMVector len ty+ all0 = LMFloatLit (-0) ty+ all0s = LMLitVar $ LMVectorLit (replicate len all0)+ in negateVec vecty all0s LM_MO_FSub++ -- Handle unsupported cases explicitly so we get a warning+ -- of missing case when new MachOps added+ MO_Add _ -> panicOp+ MO_Mul _ -> panicOp+ MO_Sub _ -> panicOp+ MO_S_MulMayOflo _ -> panicOp+ MO_S_Quot _ -> panicOp+ MO_S_Rem _ -> panicOp+ MO_U_MulMayOflo _ -> panicOp+ MO_U_Quot _ -> panicOp+ MO_U_Rem _ -> panicOp++ MO_Eq _ -> panicOp+ MO_Ne _ -> panicOp+ MO_S_Ge _ -> panicOp+ MO_S_Gt _ -> panicOp+ MO_S_Le _ -> panicOp+ MO_S_Lt _ -> panicOp+ MO_U_Ge _ -> panicOp+ MO_U_Gt _ -> panicOp+ MO_U_Le _ -> panicOp+ MO_U_Lt _ -> panicOp++ MO_F_Add _ -> panicOp+ MO_F_Sub _ -> panicOp+ MO_F_Mul _ -> panicOp+ MO_F_Quot _ -> panicOp+ MO_F_Eq _ -> panicOp+ MO_F_Ne _ -> panicOp+ MO_F_Ge _ -> panicOp+ MO_F_Gt _ -> panicOp+ MO_F_Le _ -> panicOp+ MO_F_Lt _ -> panicOp++ MO_And _ -> panicOp+ MO_Or _ -> panicOp+ MO_Xor _ -> panicOp+ MO_Shl _ -> panicOp+ MO_U_Shr _ -> panicOp+ MO_S_Shr _ -> panicOp++ MO_V_Insert _ _ -> panicOp+ MO_V_Extract _ _ -> panicOp++ MO_V_Add _ _ -> panicOp+ MO_V_Sub _ _ -> panicOp+ MO_V_Mul _ _ -> panicOp++ MO_VS_Quot _ _ -> panicOp+ MO_VS_Rem _ _ -> panicOp++ MO_VU_Quot _ _ -> panicOp+ MO_VU_Rem _ _ -> panicOp++ MO_VF_Insert _ _ -> panicOp+ MO_VF_Extract _ _ -> panicOp++ MO_VF_Add _ _ -> panicOp+ MO_VF_Sub _ _ -> panicOp+ MO_VF_Mul _ _ -> panicOp+ MO_VF_Quot _ _ -> panicOp++ where+ negate ty v2 negOp = do+ (vx, stmts, top) <- exprToVar x+ (v1, s1) <- doExpr ty $ LlvmOp negOp v2 vx+ return (v1, stmts `snocOL` s1, top)++ negateVec ty v2 negOp = do+ (vx, stmts1, top) <- exprToVar x+ ([vx'], stmts2) <- castVars [(vx, ty)]+ (v1, s1) <- doExpr ty $ LlvmOp negOp v2 vx'+ return (v1, stmts1 `appOL` stmts2 `snocOL` s1, top)++ fiConv ty convOp = do+ (vx, stmts, top) <- exprToVar x+ (v1, s1) <- doExpr ty $ Cast convOp vx ty+ return (v1, stmts `snocOL` s1, top)++ sameConv from ty reduce expand = do+ x'@(vx, stmts, top) <- exprToVar x+ let sameConv' op = do+ (v1, s1) <- doExpr ty $ Cast op vx ty+ return (v1, stmts `snocOL` s1, top)+ dflags <- getDynFlags+ let toWidth = llvmWidthInBits dflags ty+ -- LLVM doesn't like trying to convert to same width, so+ -- need to check for that as we do get Cmm code doing it.+ case widthInBits from of+ w | w < toWidth -> sameConv' expand+ w | w > toWidth -> sameConv' reduce+ _w -> return x'++ panicOp = panic $ "LLVM.CodeGen.genMachOp: non unary op encountered"+ ++ "with one argument! (" ++ show op ++ ")"++-- Handle GlobalRegs pointers+genMachOp opt o@(MO_Add _) e@[(CmmReg (CmmGlobal r)), (CmmLit (CmmInt n _))]+ = genMachOp_fast opt o r (fromInteger n) e++genMachOp opt o@(MO_Sub _) e@[(CmmReg (CmmGlobal r)), (CmmLit (CmmInt n _))]+ = genMachOp_fast opt o r (negate . fromInteger $ n) e++-- Generic case+genMachOp opt op e = genMachOp_slow opt op e+++-- | Handle CmmMachOp expressions+-- This is a specialised method that handles Global register manipulations like+-- 'Sp - 16', using the getelementptr instruction.+genMachOp_fast :: EOption -> MachOp -> GlobalReg -> Int -> [CmmExpr]+ -> LlvmM ExprData+genMachOp_fast opt op r n e+ = do (gv, grt, s1) <- getCmmRegVal (CmmGlobal r)+ dflags <- getDynFlags+ let (ix,rem) = n `divMod` ((llvmWidthInBits dflags . pLower) grt `div` 8)+ case isPointer grt && rem == 0 of+ True -> do+ (ptr, s2) <- doExpr grt $ GetElemPtr True gv [toI32 ix]+ (var, s3) <- doExpr (llvmWord dflags) $ Cast LM_Ptrtoint ptr (llvmWord dflags)+ return (var, s1 `snocOL` s2 `snocOL` s3, [])++ False -> genMachOp_slow opt op e+++-- | Handle CmmMachOp expressions+-- This handles all the cases not handle by the specialised genMachOp_fast.+genMachOp_slow :: EOption -> MachOp -> [CmmExpr] -> LlvmM ExprData++-- Element extraction+genMachOp_slow _ (MO_V_Extract l w) [val, idx] = runExprData $ do+ vval <- exprToVarW val+ vidx <- exprToVarW idx+ [vval'] <- castVarsW [(vval, LMVector l ty)]+ doExprW ty $ Extract vval' vidx+ where+ ty = widthToLlvmInt w++genMachOp_slow _ (MO_VF_Extract l w) [val, idx] = runExprData $ do+ vval <- exprToVarW val+ vidx <- exprToVarW idx+ [vval'] <- castVarsW [(vval, LMVector l ty)]+ doExprW ty $ Extract vval' vidx+ where+ ty = widthToLlvmFloat w++-- Element insertion+genMachOp_slow _ (MO_V_Insert l w) [val, elt, idx] = runExprData $ do+ vval <- exprToVarW val+ velt <- exprToVarW elt+ vidx <- exprToVarW idx+ [vval'] <- castVarsW [(vval, ty)]+ doExprW ty $ Insert vval' velt vidx+ where+ ty = LMVector l (widthToLlvmInt w)++genMachOp_slow _ (MO_VF_Insert l w) [val, elt, idx] = runExprData $ do+ vval <- exprToVarW val+ velt <- exprToVarW elt+ vidx <- exprToVarW idx+ [vval'] <- castVarsW [(vval, ty)]+ doExprW ty $ Insert vval' velt vidx+ where+ ty = LMVector l (widthToLlvmFloat w)++-- Binary MachOp+genMachOp_slow opt op [x, y] = case op of++ MO_Eq _ -> genBinComp opt LM_CMP_Eq+ MO_Ne _ -> genBinComp opt LM_CMP_Ne++ MO_S_Gt _ -> genBinComp opt LM_CMP_Sgt+ MO_S_Ge _ -> genBinComp opt LM_CMP_Sge+ MO_S_Lt _ -> genBinComp opt LM_CMP_Slt+ MO_S_Le _ -> genBinComp opt LM_CMP_Sle++ MO_U_Gt _ -> genBinComp opt LM_CMP_Ugt+ MO_U_Ge _ -> genBinComp opt LM_CMP_Uge+ MO_U_Lt _ -> genBinComp opt LM_CMP_Ult+ MO_U_Le _ -> genBinComp opt LM_CMP_Ule++ MO_Add _ -> genBinMach LM_MO_Add+ MO_Sub _ -> genBinMach LM_MO_Sub+ MO_Mul _ -> genBinMach LM_MO_Mul++ MO_U_MulMayOflo _ -> panic "genMachOp: MO_U_MulMayOflo unsupported!"++ MO_S_MulMayOflo w -> isSMulOK w x y++ MO_S_Quot _ -> genBinMach LM_MO_SDiv+ MO_S_Rem _ -> genBinMach LM_MO_SRem++ MO_U_Quot _ -> genBinMach LM_MO_UDiv+ MO_U_Rem _ -> genBinMach LM_MO_URem++ MO_F_Eq _ -> genBinComp opt LM_CMP_Feq+ MO_F_Ne _ -> genBinComp opt LM_CMP_Fne+ MO_F_Gt _ -> genBinComp opt LM_CMP_Fgt+ MO_F_Ge _ -> genBinComp opt LM_CMP_Fge+ MO_F_Lt _ -> genBinComp opt LM_CMP_Flt+ MO_F_Le _ -> genBinComp opt LM_CMP_Fle++ MO_F_Add _ -> genBinMach LM_MO_FAdd+ MO_F_Sub _ -> genBinMach LM_MO_FSub+ MO_F_Mul _ -> genBinMach LM_MO_FMul+ MO_F_Quot _ -> genBinMach LM_MO_FDiv++ MO_And _ -> genBinMach LM_MO_And+ MO_Or _ -> genBinMach LM_MO_Or+ MO_Xor _ -> genBinMach LM_MO_Xor+ MO_Shl _ -> genBinMach LM_MO_Shl+ MO_U_Shr _ -> genBinMach LM_MO_LShr+ MO_S_Shr _ -> genBinMach LM_MO_AShr++ MO_V_Add l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_Add+ MO_V_Sub l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_Sub+ MO_V_Mul l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_Mul++ MO_VS_Quot l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_SDiv+ MO_VS_Rem l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_SRem++ MO_VU_Quot l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_UDiv+ MO_VU_Rem l w -> genCastBinMach (LMVector l (widthToLlvmInt w)) LM_MO_URem++ MO_VF_Add l w -> genCastBinMach (LMVector l (widthToLlvmFloat w)) LM_MO_FAdd+ MO_VF_Sub l w -> genCastBinMach (LMVector l (widthToLlvmFloat w)) LM_MO_FSub+ MO_VF_Mul l w -> genCastBinMach (LMVector l (widthToLlvmFloat w)) LM_MO_FMul+ MO_VF_Quot l w -> genCastBinMach (LMVector l (widthToLlvmFloat w)) LM_MO_FDiv++ MO_Not _ -> panicOp+ MO_S_Neg _ -> panicOp+ MO_F_Neg _ -> panicOp++ MO_SF_Conv _ _ -> panicOp+ MO_FS_Conv _ _ -> panicOp+ MO_SS_Conv _ _ -> panicOp+ MO_UU_Conv _ _ -> panicOp+ MO_FF_Conv _ _ -> panicOp++ MO_V_Insert {} -> panicOp+ MO_V_Extract {} -> panicOp++ MO_VS_Neg {} -> panicOp++ MO_VF_Insert {} -> panicOp+ MO_VF_Extract {} -> panicOp++ MO_VF_Neg {} -> panicOp++ where+ binLlvmOp ty binOp = runExprData $ do+ vx <- exprToVarW x+ vy <- exprToVarW y+ if getVarType vx == getVarType vy+ then do+ doExprW (ty vx) $ binOp vx vy++ else do+ -- Error. Continue anyway so we can debug the generated ll file.+ dflags <- getDynFlags+ let style = mkCodeStyle CStyle+ toString doc = renderWithStyle dflags doc style+ cmmToStr = (lines . toString . PprCmm.pprExpr)+ statement $ Comment $ map fsLit $ cmmToStr x+ statement $ Comment $ map fsLit $ cmmToStr y+ doExprW (ty vx) $ binOp vx vy++ binCastLlvmOp ty binOp = runExprData $ do+ vx <- exprToVarW x+ vy <- exprToVarW y+ [vx', vy'] <- castVarsW [(vx, ty), (vy, ty)]+ doExprW ty $ binOp vx' vy'++ -- | Need to use EOption here as Cmm expects word size results from+ -- comparisons while LLVM return i1. Need to extend to llvmWord type+ -- if expected. See Note [Literals and branch conditions].+ genBinComp opt cmp = do+ ed@(v1, stmts, top) <- binLlvmOp (\_ -> i1) (Compare cmp)+ dflags <- getDynFlags+ if getVarType v1 == i1+ then case i1Expected opt of+ True -> return ed+ False -> do+ let w_ = llvmWord dflags+ (v2, s1) <- doExpr w_ $ Cast LM_Zext v1 w_+ return (v2, stmts `snocOL` s1, top)+ else+ panic $ "genBinComp: Compare returned type other then i1! "+ ++ (showSDoc dflags $ ppr $ getVarType v1)++ genBinMach op = binLlvmOp getVarType (LlvmOp op)++ genCastBinMach ty op = binCastLlvmOp ty (LlvmOp op)++ -- | Detect if overflow will occur in signed multiply of the two+ -- CmmExpr's. This is the LLVM assembly equivalent of the NCG+ -- implementation. Its much longer due to type information/safety.+ -- This should actually compile to only about 3 asm instructions.+ isSMulOK :: Width -> CmmExpr -> CmmExpr -> LlvmM ExprData+ isSMulOK _ x y = runExprData $ do+ vx <- exprToVarW x+ vy <- exprToVarW y++ dflags <- getDynFlags+ let word = getVarType vx+ let word2 = LMInt $ 2 * (llvmWidthInBits dflags $ getVarType vx)+ let shift = llvmWidthInBits dflags word+ let shift1 = toIWord dflags (shift - 1)+ let shift2 = toIWord dflags shift++ if isInt word+ then do+ x1 <- doExprW word2 $ Cast LM_Sext vx word2+ y1 <- doExprW word2 $ Cast LM_Sext vy word2+ r1 <- doExprW word2 $ LlvmOp LM_MO_Mul x1 y1+ rlow1 <- doExprW word $ Cast LM_Trunc r1 word+ rlow2 <- doExprW word $ LlvmOp LM_MO_AShr rlow1 shift1+ rhigh1 <- doExprW word2 $ LlvmOp LM_MO_AShr r1 shift2+ rhigh2 <- doExprW word $ Cast LM_Trunc rhigh1 word+ doExprW word $ LlvmOp LM_MO_Sub rlow2 rhigh2++ else+ panic $ "isSMulOK: Not bit type! (" ++ showSDoc dflags (ppr word) ++ ")"++ panicOp = panic $ "LLVM.CodeGen.genMachOp_slow: unary op encountered"+ ++ "with two arguments! (" ++ show op ++ ")"++-- More then two expression, invalid!+genMachOp_slow _ _ _ = panic "genMachOp: More then 2 expressions in MachOp!"+++-- | Handle CmmLoad expression.+genLoad :: Atomic -> CmmExpr -> CmmType -> LlvmM ExprData++-- First we try to detect a few common cases and produce better code for+-- these then the default case. We are mostly trying to detect Cmm code+-- like I32[Sp + n] and use 'getelementptr' operations instead of the+-- generic case that uses casts and pointer arithmetic+genLoad atomic e@(CmmReg (CmmGlobal r)) ty+ = genLoad_fast atomic e r 0 ty++genLoad atomic e@(CmmRegOff (CmmGlobal r) n) ty+ = genLoad_fast atomic e r n ty++genLoad atomic e@(CmmMachOp (MO_Add _) [+ (CmmReg (CmmGlobal r)),+ (CmmLit (CmmInt n _))])+ ty+ = genLoad_fast atomic e r (fromInteger n) ty++genLoad atomic e@(CmmMachOp (MO_Sub _) [+ (CmmReg (CmmGlobal r)),+ (CmmLit (CmmInt n _))])+ ty+ = genLoad_fast atomic e r (negate $ fromInteger n) ty++-- generic case+genLoad atomic e ty+ = getTBAAMeta topN >>= genLoad_slow atomic e ty++-- | Handle CmmLoad expression.+-- This is a special case for loading from a global register pointer+-- offset such as I32[Sp+8].+genLoad_fast :: Atomic -> CmmExpr -> GlobalReg -> Int -> CmmType+ -> LlvmM ExprData+genLoad_fast atomic e r n ty = do+ dflags <- getDynFlags+ (gv, grt, s1) <- getCmmRegVal (CmmGlobal r)+ meta <- getTBAARegMeta r+ let ty' = cmmToLlvmType ty+ (ix,rem) = n `divMod` ((llvmWidthInBits dflags . pLower) grt `div` 8)+ case isPointer grt && rem == 0 of+ True -> do+ (ptr, s2) <- doExpr grt $ GetElemPtr True gv [toI32 ix]+ -- We might need a different pointer type, so check+ case grt == ty' of+ -- were fine+ True -> do+ (var, s3) <- doExpr ty' (MExpr meta $ loadInstr ptr)+ return (var, s1 `snocOL` s2 `snocOL` s3,+ [])++ -- cast to pointer type needed+ False -> do+ let pty = pLift ty'+ (ptr', s3) <- doExpr pty $ Cast LM_Bitcast ptr pty+ (var, s4) <- doExpr ty' (MExpr meta $ loadInstr ptr')+ return (var, s1 `snocOL` s2 `snocOL` s3+ `snocOL` s4, [])++ -- If its a bit type then we use the slow method since+ -- we can't avoid casting anyway.+ False -> genLoad_slow atomic e ty meta+ where+ loadInstr ptr | atomic = ALoad SyncSeqCst False ptr+ | otherwise = Load ptr++-- | Handle Cmm load expression.+-- Generic case. Uses casts and pointer arithmetic if needed.+genLoad_slow :: Atomic -> CmmExpr -> CmmType -> [MetaAnnot] -> LlvmM ExprData+genLoad_slow atomic e ty meta = runExprData $ do+ iptr <- exprToVarW e+ dflags <- getDynFlags+ case getVarType iptr of+ LMPointer _ -> do+ doExprW (cmmToLlvmType ty) (MExpr meta $ loadInstr iptr)++ i@(LMInt _) | i == llvmWord dflags -> do+ let pty = LMPointer $ cmmToLlvmType ty+ ptr <- doExprW pty $ Cast LM_Inttoptr iptr pty+ doExprW (cmmToLlvmType ty) (MExpr meta $ loadInstr ptr)++ other -> do pprPanic "exprToVar: CmmLoad expression is not right type!"+ (PprCmm.pprExpr e <+> text (+ "Size of Ptr: " ++ show (llvmPtrBits dflags) +++ ", Size of var: " ++ show (llvmWidthInBits dflags other) +++ ", Var: " ++ showSDoc dflags (ppr iptr)))+ where+ loadInstr ptr | atomic = ALoad SyncSeqCst False ptr+ | otherwise = Load ptr+++-- | Handle CmmReg expression. This will return a pointer to the stack+-- location of the register. Throws an error if it isn't allocated on+-- the stack.+getCmmReg :: CmmReg -> LlvmM LlvmVar+getCmmReg (CmmLocal (LocalReg un _))+ = do exists <- varLookup un+ dflags <- getDynFlags+ case exists of+ Just ety -> return (LMLocalVar un $ pLift ety)+ Nothing -> fail $ "getCmmReg: Cmm register " ++ showSDoc dflags (ppr un) ++ " was not allocated!"+ -- This should never happen, as every local variable should+ -- have been assigned a value at some point, triggering+ -- "funPrologue" to allocate it on the stack.++getCmmReg (CmmGlobal g)+ = do onStack <- checkStackReg g+ dflags <- getDynFlags+ if onStack+ then return (lmGlobalRegVar dflags g)+ else fail $ "getCmmReg: Cmm register " ++ showSDoc dflags (ppr g) ++ " not stack-allocated!"++-- | Return the value of a given register, as well as its type. Might+-- need to be load from stack.+getCmmRegVal :: CmmReg -> LlvmM (LlvmVar, LlvmType, LlvmStatements)+getCmmRegVal reg =+ case reg of+ CmmGlobal g -> do+ onStack <- checkStackReg g+ dflags <- getDynFlags+ if onStack then loadFromStack else do+ let r = lmGlobalRegArg dflags g+ return (r, getVarType r, nilOL)+ _ -> loadFromStack+ where loadFromStack = do+ ptr <- getCmmReg reg+ let ty = pLower $ getVarType ptr+ (v, s) <- doExpr ty (Load ptr)+ return (v, ty, unitOL s)++-- | Allocate a local CmmReg on the stack+allocReg :: CmmReg -> (LlvmVar, LlvmStatements)+allocReg (CmmLocal (LocalReg un ty))+ = let ty' = cmmToLlvmType ty+ var = LMLocalVar un (LMPointer ty')+ alc = Alloca ty' 1+ in (var, unitOL $ Assignment var alc)++allocReg _ = panic $ "allocReg: Global reg encountered! Global registers should"+ ++ " have been handled elsewhere!"+++-- | Generate code for a literal+genLit :: EOption -> CmmLit -> LlvmM ExprData+genLit opt (CmmInt i w)+ -- See Note [Literals and branch conditions].+ = let width | i1Expected opt = i1+ | otherwise = LMInt (widthInBits w)+ -- comm = Comment [ fsLit $ "EOption: " ++ show opt+ -- , fsLit $ "Width : " ++ show w+ -- , fsLit $ "Width' : " ++ show (widthInBits w)+ -- ]+ in return (mkIntLit width i, nilOL, [])++genLit _ (CmmFloat r w)+ = return (LMLitVar $ LMFloatLit (fromRational r) (widthToLlvmFloat w),+ nilOL, [])++genLit opt (CmmVec ls)+ = do llvmLits <- mapM toLlvmLit ls+ return (LMLitVar $ LMVectorLit llvmLits, nilOL, [])+ where+ toLlvmLit :: CmmLit -> LlvmM LlvmLit+ toLlvmLit lit = do+ (llvmLitVar, _, _) <- genLit opt lit+ case llvmLitVar of+ LMLitVar llvmLit -> return llvmLit+ _ -> panic "genLit"++genLit _ cmm@(CmmLabel l)+ = do var <- getGlobalPtr =<< strCLabel_llvm l+ dflags <- getDynFlags+ let lmty = cmmToLlvmType $ cmmLitType dflags cmm+ (v1, s1) <- doExpr lmty $ Cast LM_Ptrtoint var (llvmWord dflags)+ return (v1, unitOL s1, [])++genLit opt (CmmLabelOff label off) = do+ dflags <- getDynFlags+ (vlbl, stmts, stat) <- genLit opt (CmmLabel label)+ let voff = toIWord dflags off+ (v1, s1) <- doExpr (getVarType vlbl) $ LlvmOp LM_MO_Add vlbl voff+ return (v1, stmts `snocOL` s1, stat)++genLit opt (CmmLabelDiffOff l1 l2 off) = do+ dflags <- getDynFlags+ (vl1, stmts1, stat1) <- genLit opt (CmmLabel l1)+ (vl2, stmts2, stat2) <- genLit opt (CmmLabel l2)+ let voff = toIWord dflags off+ let ty1 = getVarType vl1+ let ty2 = getVarType vl2+ if (isInt ty1) && (isInt ty2)+ && (llvmWidthInBits dflags ty1 == llvmWidthInBits dflags ty2)++ then do+ (v1, s1) <- doExpr (getVarType vl1) $ LlvmOp LM_MO_Sub vl1 vl2+ (v2, s2) <- doExpr (getVarType v1 ) $ LlvmOp LM_MO_Add v1 voff+ return (v2, stmts1 `appOL` stmts2 `snocOL` s1 `snocOL` s2,+ stat1 ++ stat2)++ else+ panic "genLit: CmmLabelDiffOff encountered with different label ty!"++genLit opt (CmmBlock b)+ = genLit opt (CmmLabel $ infoTblLbl b)++genLit _ CmmHighStackMark+ = panic "genStaticLit - CmmHighStackMark unsupported!"+++-- -----------------------------------------------------------------------------+-- * Misc+--++-- | Find CmmRegs that get assigned and allocate them on the stack+--+-- Any register that gets written needs to be allcoated on the+-- stack. This avoids having to map a CmmReg to an equivalent SSA form+-- and avoids having to deal with Phi node insertion. This is also+-- the approach recommended by LLVM developers.+--+-- On the other hand, this is unnecessarily verbose if the register in+-- question is never written. Therefore we skip it where we can to+-- save a few lines in the output and hopefully speed compilation up a+-- bit.+funPrologue :: LiveGlobalRegs -> [CmmBlock] -> LlvmM StmtData+funPrologue live cmmBlocks = do++ trash <- getTrashRegs+ let getAssignedRegs :: CmmNode O O -> [CmmReg]+ getAssignedRegs (CmmAssign reg _) = [reg]+ -- Calls will trash all registers. Unfortunately, this needs them to+ -- be stack-allocated in the first place.+ getAssignedRegs (CmmUnsafeForeignCall _ rs _) = map CmmGlobal trash ++ map CmmLocal rs+ getAssignedRegs _ = []+ getRegsBlock (_, body, _) = concatMap getAssignedRegs $ blockToList body+ assignedRegs = nub $ concatMap (getRegsBlock . blockSplit) cmmBlocks+ isLive r = r `elem` alwaysLive || r `elem` live++ dflags <- getDynFlags+ stmtss <- flip mapM assignedRegs $ \reg ->+ case reg of+ CmmLocal (LocalReg un _) -> do+ let (newv, stmts) = allocReg reg+ varInsert un (pLower $ getVarType newv)+ return stmts+ CmmGlobal r -> do+ let reg = lmGlobalRegVar dflags r+ arg = lmGlobalRegArg dflags r+ ty = (pLower . getVarType) reg+ trash = LMLitVar $ LMUndefLit ty+ rval = if isLive r then arg else trash+ alloc = Assignment reg $ Alloca (pLower $ getVarType reg) 1+ markStackReg r+ return $ toOL [alloc, Store rval reg]++ return (concatOL stmtss, [])++-- | Function epilogue. Load STG variables to use as argument for call.+-- STG Liveness optimisation done here.+funEpilogue :: LiveGlobalRegs -> LlvmM ([LlvmVar], LlvmStatements)+funEpilogue live = do++ -- Have information and liveness optimisation is enabled?+ let liveRegs = alwaysLive ++ live+ isSSE (FloatReg _) = True+ isSSE (DoubleReg _) = True+ isSSE (XmmReg _) = True+ isSSE (YmmReg _) = True+ isSSE (ZmmReg _) = True+ isSSE _ = False++ -- Set to value or "undef" depending on whether the register is+ -- actually live+ dflags <- getDynFlags+ let loadExpr r = do+ (v, _, s) <- getCmmRegVal (CmmGlobal r)+ return (Just $ v, s)+ loadUndef r = do+ let ty = (pLower . getVarType $ lmGlobalRegVar dflags r)+ return (Just $ LMLitVar $ LMUndefLit ty, nilOL)+ platform <- getDynFlag targetPlatform+ loads <- flip mapM (activeStgRegs platform) $ \r -> case () of+ _ | r `elem` liveRegs -> loadExpr r+ | not (isSSE r) -> loadUndef r+ | otherwise -> return (Nothing, nilOL)++ let (vars, stmts) = unzip loads+ return (catMaybes vars, concatOL stmts)+++-- | A series of statements to trash all the STG registers.+--+-- In LLVM we pass the STG registers around everywhere in function calls.+-- So this means LLVM considers them live across the entire function, when+-- in reality they usually aren't. For Caller save registers across C calls+-- the saving and restoring of them is done by the Cmm code generator,+-- using Cmm local vars. So to stop LLVM saving them as well (and saving+-- all of them since it thinks they're always live, we trash them just+-- before the call by assigning the 'undef' value to them. The ones we+-- need are restored from the Cmm local var and the ones we don't need+-- are fine to be trashed.+getTrashStmts :: LlvmM LlvmStatements+getTrashStmts = do+ regs <- getTrashRegs+ stmts <- flip mapM regs $ \ r -> do+ reg <- getCmmReg (CmmGlobal r)+ let ty = (pLower . getVarType) reg+ return $ Store (LMLitVar $ LMUndefLit ty) reg+ return $ toOL stmts++getTrashRegs :: LlvmM [GlobalReg]+getTrashRegs = do plat <- getLlvmPlatform+ return $ filter (callerSaves plat) (activeStgRegs plat)++-- | Get a function pointer to the CLabel specified.+--+-- This is for Haskell functions, function type is assumed, so doesn't work+-- with foreign functions.+getHsFunc :: LiveGlobalRegs -> CLabel -> LlvmM ExprData+getHsFunc live lbl+ = do fty <- llvmFunTy live+ name <- strCLabel_llvm lbl+ getHsFunc' name fty++getHsFunc' :: LMString -> LlvmType -> LlvmM ExprData+getHsFunc' name fty+ = do fun <- getGlobalPtr name+ if getVarType fun == fty+ then return (fun, nilOL, [])+ else do (v1, s1) <- doExpr (pLift fty)+ $ Cast LM_Bitcast fun (pLift fty)+ return (v1, unitOL s1, [])++-- | Create a new local var+mkLocalVar :: LlvmType -> LlvmM LlvmVar+mkLocalVar ty = do+ un <- getUniqueM+ return $ LMLocalVar un ty+++-- | Execute an expression, assigning result to a var+doExpr :: LlvmType -> LlvmExpression -> LlvmM (LlvmVar, LlvmStatement)+doExpr ty expr = do+ v <- mkLocalVar ty+ return (v, Assignment v expr)+++-- | Expand CmmRegOff+expandCmmReg :: DynFlags -> (CmmReg, Int) -> CmmExpr+expandCmmReg dflags (reg, off)+ = let width = typeWidth (cmmRegType dflags reg)+ voff = CmmLit $ CmmInt (fromIntegral off) width+ in CmmMachOp (MO_Add width) [CmmReg reg, voff]+++-- | Convert a block id into a appropriate Llvm label+blockIdToLlvm :: BlockId -> LlvmVar+blockIdToLlvm bid = LMLocalVar (getUnique bid) LMLabel++-- | Create Llvm int Literal+mkIntLit :: Integral a => LlvmType -> a -> LlvmVar+mkIntLit ty i = LMLitVar $ LMIntLit (toInteger i) ty++-- | Convert int type to a LLvmVar of word or i32 size+toI32 :: Integral a => a -> LlvmVar+toI32 = mkIntLit i32++toIWord :: Integral a => DynFlags -> a -> LlvmVar+toIWord dflags = mkIntLit (llvmWord dflags)+++-- | Error functions+panic :: String -> a+panic s = Outputable.panic $ "LlvmCodeGen.CodeGen." ++ s++pprPanic :: String -> SDoc -> a+pprPanic s d = Outputable.pprPanic ("LlvmCodeGen.CodeGen." ++ s) d+++-- | Returns TBAA meta data by unique+getTBAAMeta :: Unique -> LlvmM [MetaAnnot]+getTBAAMeta u = do+ mi <- getUniqMeta u+ return [MetaAnnot tbaa (MetaNode i) | let Just i = mi]++-- | Returns TBAA meta data for given register+getTBAARegMeta :: GlobalReg -> LlvmM [MetaAnnot]+getTBAARegMeta = getTBAAMeta . getTBAA+++-- | A more convenient way of accumulating LLVM statements and declarations.+data LlvmAccum = LlvmAccum LlvmStatements [LlvmCmmDecl]++#if __GLASGOW_HASKELL__ > 710+instance Semigroup LlvmAccum where+ LlvmAccum stmtsA declsA <> LlvmAccum stmtsB declsB =+ LlvmAccum (stmtsA Semigroup.<> stmtsB) (declsA Semigroup.<> declsB)+#endif++instance Monoid LlvmAccum where+ mempty = LlvmAccum nilOL []+ LlvmAccum stmtsA declsA `mappend` LlvmAccum stmtsB declsB =+ LlvmAccum (stmtsA `mappend` stmtsB) (declsA `mappend` declsB)++liftExprData :: LlvmM ExprData -> WriterT LlvmAccum LlvmM LlvmVar+liftExprData action = do+ (var, stmts, decls) <- lift action+ tell $ LlvmAccum stmts decls+ return var++statement :: LlvmStatement -> WriterT LlvmAccum LlvmM ()+statement stmt = tell $ LlvmAccum (unitOL stmt) []++doExprW :: LlvmType -> LlvmExpression -> WriterT LlvmAccum LlvmM LlvmVar+doExprW a b = do+ (var, stmt) <- lift $ doExpr a b+ statement stmt+ return var++exprToVarW :: CmmExpr -> WriterT LlvmAccum LlvmM LlvmVar+exprToVarW = liftExprData . exprToVar++runExprData :: WriterT LlvmAccum LlvmM LlvmVar -> LlvmM ExprData+runExprData action = do+ (var, LlvmAccum stmts decls) <- runWriterT action+ return (var, stmts, decls)++runStmtsDecls :: WriterT LlvmAccum LlvmM () -> LlvmM (LlvmStatements, [LlvmCmmDecl])+runStmtsDecls action = do+ LlvmAccum stmts decls <- execWriterT action+ return (stmts, decls)++getCmmRegW :: CmmReg -> WriterT LlvmAccum LlvmM LlvmVar+getCmmRegW = lift . getCmmReg++genLoadW :: Atomic -> CmmExpr -> CmmType -> WriterT LlvmAccum LlvmM LlvmVar+genLoadW atomic e ty = liftExprData $ genLoad atomic e ty++doTrashStmts :: WriterT LlvmAccum LlvmM ()+doTrashStmts = do+ stmts <- lift getTrashStmts+ tell $ LlvmAccum stmts mempty
+ llvmGen/LlvmCodeGen/Data.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE CPP #-}+-- ----------------------------------------------------------------------------+-- | Handle conversion of CmmData to LLVM code.+--++module LlvmCodeGen.Data (+ genLlvmData, genData+ ) where++#include "HsVersions.h"++import Llvm+import LlvmCodeGen.Base++import BlockId+import CLabel+import Cmm+import DynFlags+import Platform++import FastString+import Outputable++-- ----------------------------------------------------------------------------+-- * Constants+--++-- | The string appended to a variable name to create its structure type alias+structStr :: LMString+structStr = fsLit "_struct"++-- ----------------------------------------------------------------------------+-- * Top level+--++-- | Pass a CmmStatic section to an equivalent Llvm code.+genLlvmData :: (Section, CmmStatics) -> LlvmM LlvmData+genLlvmData (sec, Statics lbl xs) = do+ label <- strCLabel_llvm lbl+ static <- mapM genData xs+ lmsec <- llvmSection sec+ let types = map getStatType static++ strucTy = LMStruct types+ tyAlias = LMAlias ((label `appendFS` structStr), strucTy)++ struct = Just $ LMStaticStruc static tyAlias+ link = if (externallyVisibleCLabel lbl)+ then ExternallyVisible else Internal+ align = case sec of+ Section CString _ -> Just 1+ _ -> Nothing+ const = if isSecConstant sec then Constant else Global+ varDef = LMGlobalVar label tyAlias link lmsec align const+ globDef = LMGlobal varDef struct++ return ([globDef], [tyAlias])++-- | Should a data in this section be considered constant+isSecConstant :: Section -> Bool+isSecConstant (Section t _) = case t of+ Text -> True+ ReadOnlyData -> True+ RelocatableReadOnlyData -> True+ ReadOnlyData16 -> True+ CString -> True+ Data -> False+ UninitialisedData -> False+ (OtherSection _) -> False++-- | Format the section type part of a Cmm Section+llvmSectionType :: Platform -> SectionType -> FastString+llvmSectionType p t = case t of+ Text -> fsLit ".text"+ ReadOnlyData -> fsLit ".rodata"+ RelocatableReadOnlyData -> fsLit ".data.rel.ro"+ ReadOnlyData16 -> fsLit ".rodata.cst16"+ Data -> fsLit ".data"+ UninitialisedData -> fsLit ".bss"+ CString -> case platformOS p of+ OSMinGW32 -> fsLit ".rdata"+ _ -> fsLit ".rodata.str"+ (OtherSection _) -> panic "llvmSectionType: unknown section type"++-- | Format a Cmm Section into a LLVM section name+llvmSection :: Section -> LlvmM LMSection+llvmSection (Section t suffix) = do+ dflags <- getDynFlags+ let splitSect = gopt Opt_SplitSections dflags+ platform = targetPlatform dflags+ if not splitSect+ then return Nothing+ else do+ lmsuffix <- strCLabel_llvm suffix+ return (Just (concatFS [llvmSectionType platform t, fsLit ".", lmsuffix]))++-- ----------------------------------------------------------------------------+-- * Generate static data+--++-- | Handle static data+genData :: CmmStatic -> LlvmM LlvmStatic++genData (CmmString str) = do+ let v = map (\x -> LMStaticLit $ LMIntLit (fromIntegral x) i8) str+ ve = v ++ [LMStaticLit $ LMIntLit 0 i8]+ return $ LMStaticArray ve (LMArray (length ve) i8)++genData (CmmUninitialised bytes)+ = return $ LMUninitType (LMArray bytes i8)++genData (CmmStaticLit lit)+ = genStaticLit lit++-- | Generate Llvm code for a static literal.+--+-- Will either generate the code or leave it unresolved if it is a 'CLabel'+-- which isn't yet known.+genStaticLit :: CmmLit -> LlvmM LlvmStatic+genStaticLit (CmmInt i w)+ = return $ LMStaticLit (LMIntLit i (LMInt $ widthInBits w))++genStaticLit (CmmFloat r w)+ = return $ LMStaticLit (LMFloatLit (fromRational r) (widthToLlvmFloat w))++genStaticLit (CmmVec ls)+ = do sls <- mapM toLlvmLit ls+ return $ LMStaticLit (LMVectorLit sls)+ where+ toLlvmLit :: CmmLit -> LlvmM LlvmLit+ toLlvmLit lit = do+ slit <- genStaticLit lit+ case slit of+ LMStaticLit llvmLit -> return llvmLit+ _ -> panic "genStaticLit"++-- Leave unresolved, will fix later+genStaticLit cmm@(CmmLabel l) = do+ var <- getGlobalPtr =<< strCLabel_llvm l+ dflags <- getDynFlags+ let ptr = LMStaticPointer var+ lmty = cmmToLlvmType $ cmmLitType dflags cmm+ return $ LMPtoI ptr lmty++genStaticLit (CmmLabelOff label off) = do+ dflags <- getDynFlags+ var <- genStaticLit (CmmLabel label)+ let offset = LMStaticLit $ LMIntLit (toInteger off) (llvmWord dflags)+ return $ LMAdd var offset++genStaticLit (CmmLabelDiffOff l1 l2 off) = do+ dflags <- getDynFlags+ var1 <- genStaticLit (CmmLabel l1)+ var2 <- genStaticLit (CmmLabel l2)+ let var = LMSub var1 var2+ offset = LMStaticLit $ LMIntLit (toInteger off) (llvmWord dflags)+ return $ LMAdd var offset++genStaticLit (CmmBlock b) = genStaticLit $ CmmLabel $ infoTblLbl b++genStaticLit (CmmHighStackMark)+ = panic "genStaticLit: CmmHighStackMark unsupported!"
+ llvmGen/LlvmCodeGen/Ppr.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE CPP #-}++-- ----------------------------------------------------------------------------+-- | Pretty print helpers for the LLVM Code generator.+--+module LlvmCodeGen.Ppr (+ pprLlvmHeader, pprLlvmCmmDecl, pprLlvmData, infoSection+ ) where++#include "HsVersions.h"++import Llvm+import LlvmCodeGen.Base+import LlvmCodeGen.Data++import CLabel+import Cmm+import Platform++import FastString+import Outputable+import Unique+++-- ----------------------------------------------------------------------------+-- * Top level+--++-- | Header code for LLVM modules+pprLlvmHeader :: SDoc+pprLlvmHeader = moduleLayout+++-- | LLVM module layout description for the host target+moduleLayout :: SDoc+moduleLayout = sdocWithPlatform $ \platform ->+ case platform of+ Platform { platformArch = ArchX86, platformOS = OSDarwin } ->+ text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32\""+ $+$ text "target triple = \"i386-apple-darwin9.8\""+ Platform { platformArch = ArchX86, platformOS = OSMinGW32 } ->+ text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32\""+ $+$ text "target triple = \"i686-pc-win32\""+ Platform { platformArch = ArchX86, platformOS = OSLinux } ->+ text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32\""+ $+$ text "target triple = \"i386-pc-linux-gnu\""+ Platform { platformArch = ArchX86_64, platformOS = OSDarwin } ->+ text "target datalayout = \"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64\""+ $+$ text "target triple = \"x86_64-apple-darwin10.0.0\""+ Platform { platformArch = ArchX86_64, platformOS = OSLinux } ->+ text "target datalayout = \"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64\""+ $+$ text "target triple = \"x86_64-linux-gnu\""+ Platform { platformArch = ArchARM {}, platformOS = OSLinux } ->+ text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32\""+ $+$ text "target triple = \"armv6-unknown-linux-gnueabihf\""+ Platform { platformArch = ArchARM {}, platformOS = OSAndroid } ->+ text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32\""+ $+$ text "target triple = \"arm-unknown-linux-androideabi\""+ Platform { platformArch = ArchARM {}, platformOS = OSQNXNTO } ->+ text "target datalayout = \"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:64:128-a0:0:64-n32\""+ $+$ text "target triple = \"arm-unknown-nto-qnx8.0.0eabi\""+ Platform { platformArch = ArchARM {}, platformOS = OSiOS } ->+ text "target datalayout = \"e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32\""+ $+$ text "target triple = \"thumbv7-apple-ios7.0.0\""+ Platform { platformArch = ArchARM64, platformOS = OSiOS } ->+ text "target datalayout = \"e-m:o-i64:64-i128:128-n32:64-S128\""+ $+$ text "target triple = \"arm64-apple-ios7.0.0\""+ Platform { platformArch = ArchX86, platformOS = OSiOS } ->+ text "target datalayout = \"e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128\""+ $+$ text "target triple = \"i386-apple-ios7.0.0\""+ Platform { platformArch = ArchX86_64, platformOS = OSiOS } ->+ text "target datalayout = \"e-m:o-i64:64-f80:128-n8:16:32:64-S128\""+ $+$ text "target triple = \"x86_64-apple-ios7.0.0\""+ Platform { platformArch = ArchARM64, platformOS = OSLinux } ->+ text "target datalayout = \"e-m:e-i64:64-i128:128-n32:64-S128\""+ $+$ text "target triple = \"aarch64-unknown-linux-gnu\""+ _ ->+ if platformIsCrossCompiling platform+ then panic "LlvmCodeGen.Ppr: Cross compiling without valid target info."+ else empty+ -- If you see the above panic, GHC is missing the required target datalayout+ -- and triple information. You can obtain this info by compiling a simple+ -- 'hello world' C program with the clang C compiler eg:+ -- clang -S hello.c -emit-llvm -o -+ -- and the first two lines of hello.ll should provide the 'target datalayout'+ -- and 'target triple' lines required.+++-- | Pretty print LLVM data code+pprLlvmData :: LlvmData -> SDoc+pprLlvmData (globals, types) =+ let ppLlvmTys (LMAlias a) = ppLlvmAlias a+ ppLlvmTys (LMFunction f) = ppLlvmFunctionDecl f+ ppLlvmTys _other = empty++ types' = vcat $ map ppLlvmTys types+ globals' = ppLlvmGlobals globals+ in types' $+$ globals'+++-- | Pretty print LLVM code+pprLlvmCmmDecl :: LlvmCmmDecl -> LlvmM (SDoc, [LlvmVar])+pprLlvmCmmDecl (CmmData _ lmdata)+ = return (vcat $ map pprLlvmData lmdata, [])++pprLlvmCmmDecl (CmmProc mb_info entry_lbl live (ListGraph blks))+ = do let lbl = case mb_info of+ Nothing -> entry_lbl+ Just (Statics info_lbl _) -> info_lbl+ link = if externallyVisibleCLabel lbl+ then ExternallyVisible+ else Internal+ lmblocks = map (\(BasicBlock id stmts) ->+ LlvmBlock (getUnique id) stmts) blks++ funDec <- llvmFunSig live lbl link+ dflags <- getDynFlags+ let buildArg = fsLit . showSDoc dflags . ppPlainName+ funArgs = map buildArg (llvmFunArgs dflags live)+ funSect = llvmFunSection dflags (decName funDec)++ -- generate the info table+ prefix <- case mb_info of+ Nothing -> return Nothing+ Just (Statics _ statics) -> do+ infoStatics <- mapM genData statics+ let infoTy = LMStruct $ map getStatType infoStatics+ return $ Just $ LMStaticStruc infoStatics infoTy+++ let fun = LlvmFunction funDec funArgs llvmStdFunAttrs funSect+ prefix lmblocks+ name = decName $ funcDecl fun+ defName = name `appendFS` fsLit "$def"+ funcDecl' = (funcDecl fun) { decName = defName }+ fun' = fun { funcDecl = funcDecl' }+ funTy = LMFunction funcDecl'+ funVar = LMGlobalVar name+ (LMPointer funTy)+ link+ Nothing+ Nothing+ Alias+ defVar = LMGlobalVar defName+ (LMPointer funTy)+ (funcLinkage funcDecl')+ (funcSect fun)+ (funcAlign funcDecl')+ Alias+ alias = LMGlobal funVar+ (Just $ LMBitc (LMStaticPointer defVar)+ (LMPointer $ LMInt 8))++ return (ppLlvmGlobal alias $+$ ppLlvmFunction fun', [])+++-- | The section we are putting info tables and their entry code into, should+-- be unique since we process the assembly pattern matching this.+infoSection :: String+infoSection = "X98A__STRIP,__me"
+ llvmGen/LlvmCodeGen/Regs.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE CPP #-}++--------------------------------------------------------------------------------+-- | Deal with Cmm registers+--++module LlvmCodeGen.Regs (+ lmGlobalRegArg, lmGlobalRegVar, alwaysLive,+ stgTBAA, baseN, stackN, heapN, rxN, topN, tbaa, getTBAA+ ) where++#include "HsVersions.h"++import Llvm++import CmmExpr+import DynFlags+import FastString+import Outputable ( panic )+import Unique++-- | Get the LlvmVar function variable storing the real register+lmGlobalRegVar :: DynFlags -> GlobalReg -> LlvmVar+lmGlobalRegVar dflags = pVarLift . lmGlobalReg dflags "_Var"++-- | Get the LlvmVar function argument storing the real register+lmGlobalRegArg :: DynFlags -> GlobalReg -> LlvmVar+lmGlobalRegArg dflags = lmGlobalReg dflags "_Arg"++{- Need to make sure the names here can't conflict with the unique generated+ names. Uniques generated names containing only base62 chars. So using say+ the '_' char guarantees this.+-}+lmGlobalReg :: DynFlags -> String -> GlobalReg -> LlvmVar+lmGlobalReg dflags suf reg+ = case reg of+ BaseReg -> ptrGlobal $ "Base" ++ suf+ Sp -> ptrGlobal $ "Sp" ++ suf+ Hp -> ptrGlobal $ "Hp" ++ suf+ VanillaReg 1 _ -> wordGlobal $ "R1" ++ suf+ VanillaReg 2 _ -> wordGlobal $ "R2" ++ suf+ VanillaReg 3 _ -> wordGlobal $ "R3" ++ suf+ VanillaReg 4 _ -> wordGlobal $ "R4" ++ suf+ VanillaReg 5 _ -> wordGlobal $ "R5" ++ suf+ VanillaReg 6 _ -> wordGlobal $ "R6" ++ suf+ VanillaReg 7 _ -> wordGlobal $ "R7" ++ suf+ VanillaReg 8 _ -> wordGlobal $ "R8" ++ suf+ SpLim -> wordGlobal $ "SpLim" ++ suf+ FloatReg 1 -> floatGlobal $"F1" ++ suf+ FloatReg 2 -> floatGlobal $"F2" ++ suf+ FloatReg 3 -> floatGlobal $"F3" ++ suf+ FloatReg 4 -> floatGlobal $"F4" ++ suf+ FloatReg 5 -> floatGlobal $"F5" ++ suf+ FloatReg 6 -> floatGlobal $"F6" ++ suf+ DoubleReg 1 -> doubleGlobal $ "D1" ++ suf+ DoubleReg 2 -> doubleGlobal $ "D2" ++ suf+ DoubleReg 3 -> doubleGlobal $ "D3" ++ suf+ DoubleReg 4 -> doubleGlobal $ "D4" ++ suf+ DoubleReg 5 -> doubleGlobal $ "D5" ++ suf+ DoubleReg 6 -> doubleGlobal $ "D6" ++ suf+ XmmReg 1 -> xmmGlobal $ "XMM1" ++ suf+ XmmReg 2 -> xmmGlobal $ "XMM2" ++ suf+ XmmReg 3 -> xmmGlobal $ "XMM3" ++ suf+ XmmReg 4 -> xmmGlobal $ "XMM4" ++ suf+ XmmReg 5 -> xmmGlobal $ "XMM5" ++ suf+ XmmReg 6 -> xmmGlobal $ "XMM6" ++ suf+ YmmReg 1 -> ymmGlobal $ "YMM1" ++ suf+ YmmReg 2 -> ymmGlobal $ "YMM2" ++ suf+ YmmReg 3 -> ymmGlobal $ "YMM3" ++ suf+ YmmReg 4 -> ymmGlobal $ "YMM4" ++ suf+ YmmReg 5 -> ymmGlobal $ "YMM5" ++ suf+ YmmReg 6 -> ymmGlobal $ "YMM6" ++ suf+ ZmmReg 1 -> zmmGlobal $ "ZMM1" ++ suf+ ZmmReg 2 -> zmmGlobal $ "ZMM2" ++ suf+ ZmmReg 3 -> zmmGlobal $ "ZMM3" ++ suf+ ZmmReg 4 -> zmmGlobal $ "ZMM4" ++ suf+ ZmmReg 5 -> zmmGlobal $ "ZMM5" ++ suf+ ZmmReg 6 -> zmmGlobal $ "ZMM6" ++ suf+ MachSp -> wordGlobal $ "MachSp" ++ suf+ _other -> panic $ "LlvmCodeGen.Reg: GlobalReg (" ++ (show reg)+ ++ ") not supported!"+ -- LongReg, HpLim, CCSS, CurrentTSO, CurrentNusery, HpAlloc+ -- EagerBlackholeInfo, GCEnter1, GCFun, BaseReg, PicBaseReg+ where+ wordGlobal name = LMNLocalVar (fsLit name) (llvmWord dflags)+ ptrGlobal name = LMNLocalVar (fsLit name) (llvmWordPtr dflags)+ floatGlobal name = LMNLocalVar (fsLit name) LMFloat+ doubleGlobal name = LMNLocalVar (fsLit name) LMDouble+ xmmGlobal name = LMNLocalVar (fsLit name) (LMVector 4 (LMInt 32))+ ymmGlobal name = LMNLocalVar (fsLit name) (LMVector 8 (LMInt 32))+ zmmGlobal name = LMNLocalVar (fsLit name) (LMVector 16 (LMInt 32))++-- | A list of STG Registers that should always be considered alive+alwaysLive :: [GlobalReg]+alwaysLive = [BaseReg, Sp, Hp, SpLim, HpLim, node]++-- | STG Type Based Alias Analysis hierarchy+stgTBAA :: [(Unique, LMString, Maybe Unique)]+stgTBAA+ = [ (rootN, fsLit "root", Nothing)+ , (topN, fsLit "top", Just rootN)+ , (stackN, fsLit "stack", Just topN)+ , (heapN, fsLit "heap", Just topN)+ , (rxN, fsLit "rx", Just heapN)+ , (baseN, fsLit "base", Just topN)+ -- FIX: Not 100% sure if this hierarchy is complete. I think the big thing+ -- is Sp is never aliased, so might want to change the hierarchy to have Sp+ -- on its own branch that is never aliased (e.g never use top as a TBAA+ -- node).+ ]++-- | Id values+-- The `rootN` node is the root (there can be more than one) of the TBAA+-- hierarchy and as of LLVM 4.0 should *only* be referenced by other nodes. It+-- should never occur in any LLVM instruction statement.+rootN, topN, stackN, heapN, rxN, baseN :: Unique+rootN = getUnique (fsLit "LlvmCodeGen.Regs.rootN")+topN = getUnique (fsLit "LlvmCodeGen.Regs.topN")+stackN = getUnique (fsLit "LlvmCodeGen.Regs.stackN")+heapN = getUnique (fsLit "LlvmCodeGen.Regs.heapN")+rxN = getUnique (fsLit "LlvmCodeGen.Regs.rxN")+baseN = getUnique (fsLit "LlvmCodeGen.Regs.baseN")++-- | The TBAA metadata identifier+tbaa :: LMString+tbaa = fsLit "tbaa"++-- | Get the correct TBAA metadata information for this register type+getTBAA :: GlobalReg -> Unique+getTBAA BaseReg = baseN+getTBAA Sp = stackN+getTBAA Hp = heapN+getTBAA (VanillaReg _ _) = rxN+getTBAA _ = topN
+ llvmGen/LlvmMangler.hs view
@@ -0,0 +1,127 @@+-- -----------------------------------------------------------------------------+-- | GHC LLVM Mangler+--+-- This script processes the assembly produced by LLVM, rewriting all symbols+-- of type @function to @object. This keeps them from going through the PLT,+-- which would be bad due to tables-next-to-code. On x86_64,+-- it also rewrites AVX instructions that require alignment to their+-- unaligned counterparts, since the stack is only 16-byte aligned but these+-- instructions require 32-byte alignment.+--++module LlvmMangler ( llvmFixupAsm ) where++import DynFlags ( DynFlags, targetPlatform )+import Platform ( platformArch, Arch(..) )+import ErrUtils ( withTiming )+import Outputable ( text )++import Control.Exception+import qualified Data.ByteString.Char8 as B+import System.IO++-- | Read in assembly file and process+llvmFixupAsm :: DynFlags -> FilePath -> FilePath -> IO ()+llvmFixupAsm dflags f1 f2 = {-# SCC "llvm_mangler" #-}+ withTiming (pure dflags) (text "LLVM Mangler") id $+ withBinaryFile f1 ReadMode $ \r -> withBinaryFile f2 WriteMode $ \w -> do+ go r w+ hClose r+ hClose w+ return ()+ where+ go :: Handle -> Handle -> IO ()+ go r w = do+ e_l <- try $ B.hGetLine r ::IO (Either IOError B.ByteString)+ let writeline a = B.hPutStrLn w (rewriteLine dflags rewrites a) >> go r w+ case e_l of+ Right l -> writeline l+ Left _ -> return ()++-- | These are the rewrites that the mangler will perform+rewrites :: [Rewrite]+rewrites = [rewriteSymType, rewriteAVX]++type Rewrite = DynFlags -> B.ByteString -> Maybe B.ByteString++-- | Rewrite a line of assembly source with the given rewrites,+-- taking the first rewrite that applies.+rewriteLine :: DynFlags -> [Rewrite] -> B.ByteString -> B.ByteString+rewriteLine dflags rewrites l+ -- We disable .subsections_via_symbols on darwin and ios, as the llvm code+ -- gen uses prefix data for the info table. This however does not prevent+ -- llvm from generating .subsections_via_symbols, which in turn with+ -- -dead_strip, strips the info tables, and therefore breaks ghc.+ | isSubsectionsViaSymbols l =+ (B.pack "## no .subsection_via_symbols for ghc. We need our info tables!")+ | otherwise =+ case firstJust $ map (\rewrite -> rewrite dflags rest) rewrites of+ Nothing -> l+ Just rewritten -> B.concat $ [symbol, B.pack "\t", rewritten]+ where+ isSubsectionsViaSymbols = B.isPrefixOf (B.pack ".subsections_via_symbols")++ (symbol, rest) = splitLine l++ firstJust :: [Maybe a] -> Maybe a+ firstJust (Just x:_) = Just x+ firstJust [] = Nothing+ firstJust (_:rest) = firstJust rest++-- | This rewrites @.type@ annotations of function symbols to @%object@.+-- This is done as the linker can relocate @%functions@ through the+-- Procedure Linking Table (PLT). This is bad since we expect that the+-- info table will appear directly before the symbol's location. In the+-- case that the PLT is used, this will be not an info table but instead+-- some random PLT garbage.+rewriteSymType :: Rewrite+rewriteSymType _ l+ | isType l = Just $ rewrite '@' $ rewrite '%' l+ | otherwise = Nothing+ where+ isType = B.isPrefixOf (B.pack ".type")++ rewrite :: Char -> B.ByteString -> B.ByteString+ rewrite prefix = replaceOnce funcType objType+ where+ funcType = prefix `B.cons` B.pack "function"+ objType = prefix `B.cons` B.pack "object"++-- | This rewrites aligned AVX instructions to their unaligned counterparts on+-- x86-64. This is necessary because the stack is not adequately aligned for+-- aligned AVX spills, so LLVM would emit code that adjusts the stack pointer+-- and disable tail call optimization. Both would be catastrophic here so GHC+-- tells LLVM that the stack is 32-byte aligned (even though it isn't) and then+-- rewrites the instructions in the mangler.+rewriteAVX :: Rewrite+rewriteAVX dflags s+ | not isX86_64 = Nothing+ | isVmovdqa s = Just $ replaceOnce (B.pack "vmovdqa") (B.pack "vmovdqu") s+ | isVmovap s = Just $ replaceOnce (B.pack "vmovap") (B.pack "vmovup") s+ | otherwise = Nothing+ where+ isX86_64 = platformArch (targetPlatform dflags) == ArchX86_64+ isVmovdqa = B.isPrefixOf (B.pack "vmovdqa")+ isVmovap = B.isPrefixOf (B.pack "vmovap")++-- | @replaceOnce match replace bs@ replaces the first occurrence of the+-- substring @match@ in @bs@ with @replace@.+replaceOnce :: B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString+replaceOnce matchBS replaceOnceBS = loop+ where+ loop :: B.ByteString -> B.ByteString+ loop cts =+ case B.breakSubstring matchBS cts of+ (hd,tl) | B.null tl -> hd+ | otherwise -> hd `B.append` replaceOnceBS `B.append`+ B.drop (B.length matchBS) tl++-- | This function splits a line of assembly code into the label and the+-- rest of the code.+splitLine :: B.ByteString -> (B.ByteString, B.ByteString)+splitLine l = (symbol, B.dropWhile isSpace rest)+ where+ isSpace ' ' = True+ isSpace '\t' = True+ isSpace _ = False+ (symbol, rest) = B.span (not . isSpace) l
+ main/Annotations.hs view
@@ -0,0 +1,132 @@+-- |+-- Support for source code annotation feature of GHC. That is the ANN pragma.+--+-- (c) The University of Glasgow 2006+-- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998+--+module Annotations (+ -- * Main Annotation data types+ Annotation(..), AnnPayload,+ AnnTarget(..), CoreAnnTarget,+ getAnnTargetName_maybe,++ -- * AnnEnv for collecting and querying Annotations+ AnnEnv,+ mkAnnEnv, extendAnnEnvList, plusAnnEnv, emptyAnnEnv,+ findAnns, findAnnsByTypeRep,+ deserializeAnns+ ) where++import Binary+import Module ( Module )+import Name+import Outputable+import GHC.Serialized+import UniqFM+import Unique++import Control.Monad+import Data.Maybe+import Data.Typeable+import Data.Word ( Word8 )+++-- | Represents an annotation after it has been sufficiently desugared from+-- it's initial form of 'HsDecls.AnnDecl'+data Annotation = Annotation {+ ann_target :: CoreAnnTarget, -- ^ The target of the annotation+ ann_value :: AnnPayload+ }++type AnnPayload = Serialized -- ^ The "payload" of an annotation+ -- allows recovery of its value at a given type,+ -- and can be persisted to an interface file++-- | An annotation target+data AnnTarget name+ = NamedTarget name -- ^ We are annotating something with a name:+ -- a type or identifier+ | ModuleTarget Module -- ^ We are annotating a particular module++-- | The kind of annotation target found in the middle end of the compiler+type CoreAnnTarget = AnnTarget Name++instance Functor AnnTarget where+ fmap f (NamedTarget nm) = NamedTarget (f nm)+ fmap _ (ModuleTarget mod) = ModuleTarget mod++-- | Get the 'name' of an annotation target if it exists.+getAnnTargetName_maybe :: AnnTarget name -> Maybe name+getAnnTargetName_maybe (NamedTarget nm) = Just nm+getAnnTargetName_maybe _ = Nothing++instance Uniquable name => Uniquable (AnnTarget name) where+ getUnique (NamedTarget nm) = getUnique nm+ getUnique (ModuleTarget mod) = deriveUnique (getUnique mod) 0+ -- deriveUnique prevents OccName uniques clashing with NamedTarget++instance Outputable name => Outputable (AnnTarget name) where+ ppr (NamedTarget nm) = text "Named target" <+> ppr nm+ ppr (ModuleTarget mod) = text "Module target" <+> ppr mod++instance Binary name => Binary (AnnTarget name) where+ put_ bh (NamedTarget a) = do+ putByte bh 0+ put_ bh a+ put_ bh (ModuleTarget a) = do+ putByte bh 1+ put_ bh a+ get bh = do+ h <- getByte bh+ case h of+ 0 -> liftM NamedTarget $ get bh+ _ -> liftM ModuleTarget $ get bh++instance Outputable Annotation where+ ppr ann = ppr (ann_target ann)++-- | A collection of annotations+-- Can't use a type synonym or we hit bug #2412 due to source import+newtype AnnEnv = MkAnnEnv (UniqFM [AnnPayload])++-- | An empty annotation environment.+emptyAnnEnv :: AnnEnv+emptyAnnEnv = MkAnnEnv emptyUFM++-- | Construct a new annotation environment that contains the list of+-- annotations provided.+mkAnnEnv :: [Annotation] -> AnnEnv+mkAnnEnv = extendAnnEnvList emptyAnnEnv++-- | Add the given annotation to the environment.+extendAnnEnvList :: AnnEnv -> [Annotation] -> AnnEnv+extendAnnEnvList (MkAnnEnv env) anns+ = MkAnnEnv $ addListToUFM_C (++) env $+ map (\ann -> (getUnique (ann_target ann), [ann_value ann])) anns++-- | Union two annotation environments.+plusAnnEnv :: AnnEnv -> AnnEnv -> AnnEnv+plusAnnEnv (MkAnnEnv env1) (MkAnnEnv env2) = MkAnnEnv $ plusUFM_C (++) env1 env2++-- | Find the annotations attached to the given target as 'Typeable'+-- values of your choice. If no deserializer is specified,+-- only transient annotations will be returned.+findAnns :: Typeable a => ([Word8] -> a) -> AnnEnv -> CoreAnnTarget -> [a]+findAnns deserialize (MkAnnEnv ann_env)+ = (mapMaybe (fromSerialized deserialize))+ . (lookupWithDefaultUFM ann_env [])++-- | Find the annotations attached to the given target as 'Typeable'+-- values of your choice. If no deserializer is specified,+-- only transient annotations will be returned.+findAnnsByTypeRep :: AnnEnv -> CoreAnnTarget -> TypeRep -> [[Word8]]+findAnnsByTypeRep (MkAnnEnv ann_env) target tyrep+ = [ ws | Serialized tyrep' ws <- lookupWithDefaultUFM ann_env [] target+ , tyrep' == tyrep ]++-- | Deserialize all annotations of a given type. This happens lazily, that is+-- no deserialization will take place until the [a] is actually demanded and+-- the [a] can also be empty (the UniqFM is not filtered).+deserializeAnns :: Typeable a => ([Word8] -> a) -> AnnEnv -> UniqFM [a]+deserializeAnns deserialize (MkAnnEnv ann_env)+ = mapUFM (mapMaybe (fromSerialized deserialize)) ann_env
+ main/CmdLineParser.hs view
@@ -0,0 +1,314 @@+{-# LANGUAGE CPP #-}++-------------------------------------------------------------------------------+--+-- | Command-line parser+--+-- This is an abstract command-line parser used by DynFlags.+--+-- (c) The University of Glasgow 2005+--+-------------------------------------------------------------------------------++module CmdLineParser+ (+ processArgs, OptKind(..), GhcFlagMode(..),+ CmdLineP(..), getCmdLineState, putCmdLineState,+ Flag(..), defFlag, defGhcFlag, defGhciFlag, defHiddenFlag,+ errorsToGhcException,++ EwM, runEwM, addErr, addWarn, getArg, getCurLoc, liftEwM, deprecate+ ) where++#include "HsVersions.h"++import Util+import Outputable+import Panic+import Bag+import SrcLoc++import Data.Function+import Data.List++import Control.Monad (liftM, ap)++--------------------------------------------------------+-- The Flag and OptKind types+--------------------------------------------------------++data Flag m = Flag+ { flagName :: String, -- Flag, without the leading "-"+ flagOptKind :: OptKind m, -- What to do if we see it+ flagGhcMode :: GhcFlagMode -- Which modes this flag affects+ }++defFlag :: String -> OptKind m -> Flag m+defFlag name optKind = Flag name optKind AllModes++defGhcFlag :: String -> OptKind m -> Flag m+defGhcFlag name optKind = Flag name optKind OnlyGhc++defGhciFlag :: String -> OptKind m -> Flag m+defGhciFlag name optKind = Flag name optKind OnlyGhci++defHiddenFlag :: String -> OptKind m -> Flag m+defHiddenFlag name optKind = Flag name optKind HiddenFlag++-- | GHC flag modes describing when a flag has an effect.+data GhcFlagMode+ = OnlyGhc -- ^ The flag only affects the non-interactive GHC+ | OnlyGhci -- ^ The flag only affects the interactive GHC+ | AllModes -- ^ The flag affects multiple ghc modes+ | HiddenFlag -- ^ This flag should not be seen in cli completion++data OptKind m -- Suppose the flag is -f+ = NoArg (EwM m ()) -- -f all by itself+ | HasArg (String -> EwM m ()) -- -farg or -f arg+ | SepArg (String -> EwM m ()) -- -f arg+ | Prefix (String -> EwM m ()) -- -farg+ | OptPrefix (String -> EwM m ()) -- -f or -farg (i.e. the arg is optional)+ | OptIntSuffix (Maybe Int -> EwM m ()) -- -f or -f=n; pass n to fn+ | IntSuffix (Int -> EwM m ()) -- -f or -f=n; pass n to fn+ | FloatSuffix (Float -> EwM m ()) -- -f or -f=n; pass n to fn+ | PassFlag (String -> EwM m ()) -- -f; pass "-f" fn+ | AnySuffix (String -> EwM m ()) -- -f or -farg; pass entire "-farg" to fn+ | PrefixPred (String -> Bool) (String -> EwM m ())+ | AnySuffixPred (String -> Bool) (String -> EwM m ())+++--------------------------------------------------------+-- The EwM monad+--------------------------------------------------------++type Err = Located String+type Warn = Located String+type Errs = Bag Err+type Warns = Bag Warn++-- EwM ("errors and warnings monad") is a monad+-- transformer for m that adds an (err, warn) state+newtype EwM m a = EwM { unEwM :: Located String -- Current parse arg+ -> Errs -> Warns+ -> m (Errs, Warns, a) }++instance Monad m => Functor (EwM m) where+ fmap = liftM++instance Monad m => Applicative (EwM m) where+ pure v = EwM (\_ e w -> return (e, w, v))+ (<*>) = ap++instance Monad m => Monad (EwM m) where+ (EwM f) >>= k = EwM (\l e w -> do (e', w', r) <- f l e w+ unEwM (k r) l e' w')++runEwM :: EwM m a -> m (Errs, Warns, a)+runEwM action = unEwM action (panic "processArgs: no arg yet") emptyBag emptyBag++setArg :: Located String -> EwM m () -> EwM m ()+setArg l (EwM f) = EwM (\_ es ws -> f l es ws)++addErr :: Monad m => String -> EwM m ()+addErr e = EwM (\(L loc _) es ws -> return (es `snocBag` L loc e, ws, ()))++addWarn :: Monad m => String -> EwM m ()+addWarn msg = EwM (\(L loc _) es ws -> return (es, ws `snocBag` L loc msg, ()))++deprecate :: Monad m => String -> EwM m ()+deprecate s = do+ arg <- getArg+ addWarn (arg ++ " is deprecated: " ++ s)++getArg :: Monad m => EwM m String+getArg = EwM (\(L _ arg) es ws -> return (es, ws, arg))++getCurLoc :: Monad m => EwM m SrcSpan+getCurLoc = EwM (\(L loc _) es ws -> return (es, ws, loc))++liftEwM :: Monad m => m a -> EwM m a+liftEwM action = EwM (\_ es ws -> do { r <- action; return (es, ws, r) })+++--------------------------------------------------------+-- A state monad for use in the command-line parser+--------------------------------------------------------++-- (CmdLineP s) typically instantiates the 'm' in (EwM m) and (OptKind m)+newtype CmdLineP s a = CmdLineP { runCmdLine :: s -> (a, s) }++instance Functor (CmdLineP s) where+ fmap = liftM++instance Applicative (CmdLineP s) where+ pure a = CmdLineP $ \s -> (a, s)+ (<*>) = ap++instance Monad (CmdLineP s) where+ m >>= k = CmdLineP $ \s ->+ let (a, s') = runCmdLine m s+ in runCmdLine (k a) s'+++getCmdLineState :: CmdLineP s s+getCmdLineState = CmdLineP $ \s -> (s,s)+putCmdLineState :: s -> CmdLineP s ()+putCmdLineState s = CmdLineP $ \_ -> ((),s)+++--------------------------------------------------------+-- Processing arguments+--------------------------------------------------------++processArgs :: Monad m+ => [Flag m] -- cmdline parser spec+ -> [Located String] -- args+ -> m ( [Located String], -- spare args+ [Located String], -- errors+ [Located String] ) -- warnings+processArgs spec args = do+ (errs, warns, spare) <- runEwM action+ return (spare, bagToList errs, bagToList warns)+ where+ action = process args []++ -- process :: [Located String] -> [Located String] -> EwM m [Located String]+ process [] spare = return (reverse spare)++ process (locArg@(L _ ('-' : arg)) : args) spare =+ case findArg spec arg of+ Just (rest, opt_kind) ->+ case processOneArg opt_kind rest arg args of+ Left err ->+ let b = process args spare+ in (setArg locArg $ addErr err) >> b++ Right (action,rest) ->+ let b = process rest spare+ in (setArg locArg $ action) >> b++ Nothing -> process args (locArg : spare)++ process (arg : args) spare = process args (arg : spare)+++processOneArg :: OptKind m -> String -> String -> [Located String]+ -> Either String (EwM m (), [Located String])+processOneArg opt_kind rest arg args+ = let dash_arg = '-' : arg+ rest_no_eq = dropEq rest+ in case opt_kind of+ NoArg a -> ASSERT(null rest) Right (a, args)++ HasArg f | notNull rest_no_eq -> Right (f rest_no_eq, args)+ | otherwise -> case args of+ [] -> missingArgErr dash_arg+ (L _ arg1:args1) -> Right (f arg1, args1)++ -- See Trac #9776+ SepArg f -> case args of+ [] -> missingArgErr dash_arg+ (L _ arg1:args1) -> Right (f arg1, args1)++ Prefix f | notNull rest_no_eq -> Right (f rest_no_eq, args)+ | otherwise -> unknownFlagErr dash_arg++ PrefixPred _ f | notNull rest_no_eq -> Right (f rest_no_eq, args)+ | otherwise -> unknownFlagErr dash_arg++ PassFlag f | notNull rest -> unknownFlagErr dash_arg+ | otherwise -> Right (f dash_arg, args)++ OptIntSuffix f | null rest -> Right (f Nothing, args)+ | Just n <- parseInt rest_no_eq -> Right (f (Just n), args)+ | otherwise -> Left ("malformed integer argument in " ++ dash_arg)++ IntSuffix f | Just n <- parseInt rest_no_eq -> Right (f n, args)+ | otherwise -> Left ("malformed integer argument in " ++ dash_arg)++ FloatSuffix f | Just n <- parseFloat rest_no_eq -> Right (f n, args)+ | otherwise -> Left ("malformed float argument in " ++ dash_arg)++ OptPrefix f -> Right (f rest_no_eq, args)+ AnySuffix f -> Right (f dash_arg, args)+ AnySuffixPred _ f -> Right (f dash_arg, args)++findArg :: [Flag m] -> String -> Maybe (String, OptKind m)+findArg spec arg =+ case sortBy (compare `on` (length . fst)) -- prefer longest matching flag+ [ (removeSpaces rest, optKind)+ | flag <- spec,+ let optKind = flagOptKind flag,+ Just rest <- [stripPrefix (flagName flag) arg],+ arg_ok optKind rest arg ]+ of+ [] -> Nothing+ (one:_) -> Just one++arg_ok :: OptKind t -> [Char] -> String -> Bool+arg_ok (NoArg _) rest _ = null rest+arg_ok (HasArg _) _ _ = True+arg_ok (SepArg _) rest _ = null rest+arg_ok (Prefix _) rest _ = notNull rest+arg_ok (PrefixPred p _) rest _ = notNull rest && p (dropEq rest)+arg_ok (OptIntSuffix _) _ _ = True+arg_ok (IntSuffix _) _ _ = True+arg_ok (FloatSuffix _) _ _ = True+arg_ok (OptPrefix _) _ _ = True+arg_ok (PassFlag _) rest _ = null rest+arg_ok (AnySuffix _) _ _ = True+arg_ok (AnySuffixPred p _) _ arg = p arg++-- | Parse an Int+--+-- Looks for "433" or "=342", with no trailing gubbins+-- * n or =n => Just n+-- * gibberish => Nothing+parseInt :: String -> Maybe Int+parseInt s = case reads s of+ ((n,""):_) -> Just n+ _ -> Nothing++parseFloat :: String -> Maybe Float+parseFloat s = case reads s of+ ((n,""):_) -> Just n+ _ -> Nothing++-- | Discards a leading equals sign+dropEq :: String -> String+dropEq ('=' : s) = s+dropEq s = s++unknownFlagErr :: String -> Either String a+unknownFlagErr f = Left ("unrecognised flag: " ++ f)++missingArgErr :: String -> Either String a+missingArgErr f = Left ("missing argument for flag: " ++ f)++--------------------------------------------------------+-- Utils+--------------------------------------------------------+++-- See Note [Handling errors when parsing flags]+errorsToGhcException :: [(String, -- Location+ String)] -- Error+ -> GhcException+errorsToGhcException errs =+ UsageError $ intercalate "\n" $ [ l ++ ": " ++ e | (l, e) <- errs ]++{- Note [Handling errors when parsing commandline flags]++Parsing of static and mode flags happens before any session is started, i.e.,+before the first call to 'GHC.withGhc'. Therefore, to report errors for+invalid usage of these two types of flags, we can not call any function that+needs DynFlags, as there are no DynFlags available yet (unsafeGlobalDynFlags+is not set either). So we always print "on the commandline" as the location,+which is true except for Api users, which is probably ok.++When reporting errors for invalid usage of dynamic flags we /can/ make use of+DynFlags, and we do so explicitly in DynFlags.parseDynamicFlagsFull.++Before, we called unsafeGlobalDynFlags when an invalid (combination of)+flag(s) was given on the commandline, resulting in panics (#9963).+-}
+ main/CodeOutput.hs view
@@ -0,0 +1,281 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section{Code output phase}+-}++{-# LANGUAGE CPP #-}++module CodeOutput( codeOutput, outputForeignStubs ) where++#include "HsVersions.h"++import AsmCodeGen ( nativeCodeGen )+import LlvmCodeGen ( llvmCodeGen )++import UniqSupply ( mkSplitUniqSupply )++import Finder ( mkStubPaths )+import PprC ( writeCs )+import CmmLint ( cmmLint )+import Packages+import Cmm ( RawCmmGroup )+import HscTypes+import DynFlags+import Config+import SysTools+import Stream (Stream)+import qualified Stream++import ErrUtils+import Outputable+import Module+import SrcLoc++import Control.Exception+import System.Directory+import System.FilePath+import System.IO+import Control.Monad (forM)++{-+************************************************************************+* *+\subsection{Steering}+* *+************************************************************************+-}++codeOutput :: DynFlags+ -> Module+ -> FilePath+ -> ModLocation+ -> ForeignStubs+ -> [(ForeignSrcLang, String)]+ -- ^ additional files to be compiled with with the C compiler+ -> [InstalledUnitId]+ -> Stream IO RawCmmGroup () -- Compiled C--+ -> IO (FilePath,+ (Bool{-stub_h_exists-}, Maybe FilePath{-stub_c_exists-}),+ [(ForeignSrcLang, FilePath)]{-foreign_fps-})++codeOutput dflags this_mod filenm location foreign_stubs foreign_files pkg_deps+ cmm_stream+ =+ do {+ -- Lint each CmmGroup as it goes past+ ; let linted_cmm_stream =+ if gopt Opt_DoCmmLinting dflags+ then Stream.mapM do_lint cmm_stream+ else cmm_stream++ do_lint cmm = withTiming (pure dflags)+ (text "CmmLint"<+>brackets (ppr this_mod))+ (const ()) $ do+ { case cmmLint dflags cmm of+ Just err -> do { log_action dflags+ dflags+ NoReason+ SevDump+ noSrcSpan+ (defaultDumpStyle dflags)+ err+ ; ghcExit dflags 1+ }+ Nothing -> return ()+ ; return cmm+ }++ ; stubs_exist <- outputForeignStubs dflags this_mod location foreign_stubs+ ; foreign_fps <- forM foreign_files $ \(lang, file_contents) -> do+ { fp <- outputForeignFile dflags lang file_contents;+ ; return (lang, fp);+ }+ ; case hscTarget dflags of {+ HscAsm -> outputAsm dflags this_mod location filenm+ linted_cmm_stream;+ HscC -> outputC dflags filenm linted_cmm_stream pkg_deps;+ HscLlvm -> outputLlvm dflags filenm linted_cmm_stream;+ HscInterpreted -> panic "codeOutput: HscInterpreted";+ HscNothing -> panic "codeOutput: HscNothing"+ }+ ; return (filenm, stubs_exist, foreign_fps)+ }++doOutput :: String -> (Handle -> IO a) -> IO a+doOutput filenm io_action = bracket (openFile filenm WriteMode) hClose io_action++{-+************************************************************************+* *+\subsection{C}+* *+************************************************************************+-}++outputC :: DynFlags+ -> FilePath+ -> Stream IO RawCmmGroup ()+ -> [InstalledUnitId]+ -> IO ()++outputC dflags filenm cmm_stream packages+ = do+ -- ToDo: make the C backend consume the C-- incrementally, by+ -- pushing the cmm_stream inside (c.f. nativeCodeGen)+ rawcmms <- Stream.collect cmm_stream++ -- figure out which header files to #include in the generated .hc file:+ --+ -- * extra_includes from packages+ -- * -#include options from the cmdline and OPTIONS pragmas+ -- * the _stub.h file, if there is one.+ --+ let rts = getPackageDetails dflags rtsUnitId++ let cc_injects = unlines (map mk_include (includes rts))+ mk_include h_file =+ case h_file of+ '"':_{-"-} -> "#include "++h_file+ '<':_ -> "#include "++h_file+ _ -> "#include \""++h_file++"\""++ let pkg_names = map installedUnitIdString packages++ doOutput filenm $ \ h -> do+ hPutStr h ("/* GHC_PACKAGES " ++ unwords pkg_names ++ "\n*/\n")+ hPutStr h cc_injects+ writeCs dflags h rawcmms++{-+************************************************************************+* *+\subsection{Assembler}+* *+************************************************************************+-}++outputAsm :: DynFlags -> Module -> ModLocation -> FilePath+ -> Stream IO RawCmmGroup ()+ -> IO ()+outputAsm dflags this_mod location filenm cmm_stream+ | cGhcWithNativeCodeGen == "YES"+ = do ncg_uniqs <- mkSplitUniqSupply 'n'++ debugTraceMsg dflags 4 (text "Outputing asm to" <+> text filenm)++ _ <- {-# SCC "OutputAsm" #-} doOutput filenm $+ \h -> {-# SCC "NativeCodeGen" #-}+ nativeCodeGen dflags this_mod location h ncg_uniqs cmm_stream+ return ()++ | otherwise+ = panic "This compiler was built without a native code generator"++{-+************************************************************************+* *+\subsection{LLVM}+* *+************************************************************************+-}++outputLlvm :: DynFlags -> FilePath -> Stream IO RawCmmGroup () -> IO ()+outputLlvm dflags filenm cmm_stream+ = do ncg_uniqs <- mkSplitUniqSupply 'n'++ {-# SCC "llvm_output" #-} doOutput filenm $+ \f -> {-# SCC "llvm_CodeGen" #-}+ llvmCodeGen dflags f ncg_uniqs cmm_stream++{-+************************************************************************+* *+\subsection{Foreign import/export}+* *+************************************************************************+-}++outputForeignStubs :: DynFlags -> Module -> ModLocation -> ForeignStubs+ -> IO (Bool, -- Header file created+ Maybe FilePath) -- C file created+outputForeignStubs dflags mod location stubs+ = do+ let stub_h = mkStubPaths dflags (moduleName mod) location+ stub_c <- newTempName dflags "c"++ case stubs of+ NoStubs ->+ return (False, Nothing)++ ForeignStubs h_code c_code -> do+ let+ stub_c_output_d = pprCode CStyle c_code+ stub_c_output_w = showSDoc dflags stub_c_output_d++ -- Header file protos for "foreign export"ed functions.+ stub_h_output_d = pprCode CStyle h_code+ stub_h_output_w = showSDoc dflags stub_h_output_d++ createDirectoryIfMissing True (takeDirectory stub_h)++ dumpIfSet_dyn dflags Opt_D_dump_foreign+ "Foreign export header file" stub_h_output_d++ -- we need the #includes from the rts package for the stub files+ let rts_includes =+ let rts_pkg = getPackageDetails dflags rtsUnitId in+ concatMap mk_include (includes rts_pkg)+ mk_include i = "#include \"" ++ i ++ "\"\n"++ -- wrapper code mentions the ffi_arg type, which comes from ffi.h+ ffi_includes | cLibFFI = "#include \"ffi.h\"\n"+ | otherwise = ""++ stub_h_file_exists+ <- outputForeignStubs_help stub_h stub_h_output_w+ ("#include \"HsFFI.h\"\n" ++ cplusplus_hdr) cplusplus_ftr++ dumpIfSet_dyn dflags Opt_D_dump_foreign+ "Foreign export stubs" stub_c_output_d++ stub_c_file_exists+ <- outputForeignStubs_help stub_c stub_c_output_w+ ("#define IN_STG_CODE 0\n" +++ "#include \"Rts.h\"\n" +++ rts_includes +++ ffi_includes +++ cplusplus_hdr)+ cplusplus_ftr+ -- We're adding the default hc_header to the stub file, but this+ -- isn't really HC code, so we need to define IN_STG_CODE==0 to+ -- avoid the register variables etc. being enabled.++ return (stub_h_file_exists, if stub_c_file_exists+ then Just stub_c+ else Nothing )+ where+ cplusplus_hdr = "#ifdef __cplusplus\nextern \"C\" {\n#endif\n"+ cplusplus_ftr = "#ifdef __cplusplus\n}\n#endif\n"+++-- Don't use doOutput for dumping the f. export stubs+-- since it is more than likely that the stubs file will+-- turn out to be empty, in which case no file should be created.+outputForeignStubs_help :: FilePath -> String -> String -> String -> IO Bool+outputForeignStubs_help _fname "" _header _footer = return False+outputForeignStubs_help fname doc_str header footer+ = do writeFile fname (header ++ doc_str ++ '\n':footer ++ "\n")+ return True++outputForeignFile :: DynFlags -> ForeignSrcLang -> String -> IO FilePath+outputForeignFile dflags lang file_contents+ = do+ extension <- case lang of+ LangC -> return "c"+ LangCxx -> return "cpp"+ LangObjc -> return "m"+ LangObjcxx -> return "mm"+ fp <- newTempName dflags extension+ writeFile fp file_contents+ return fp
+ main/Constants.hs view
@@ -0,0 +1,40 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[Constants]{Info about this compilation}+-}++module Constants (module Constants) where++import Config++hiVersion :: Integer+hiVersion = read (cProjectVersionInt ++ cProjectPatchLevel) :: Integer++-- All pretty arbitrary:++mAX_TUPLE_SIZE :: Int+mAX_TUPLE_SIZE = 62 -- Should really match the number+ -- of decls in Data.Tuple++mAX_CTUPLE_SIZE :: Int -- Constraint tuples+mAX_CTUPLE_SIZE = 62 -- Should match the number of decls in GHC.Classes++mAX_SUM_SIZE :: Int+mAX_SUM_SIZE = 62++-- | Default maximum depth for both class instance search and type family+-- reduction. See also Trac #5395.+mAX_REDUCTION_DEPTH :: Int+mAX_REDUCTION_DEPTH = 200++-- | Default maximum constraint-solver iterations+-- Typically there should be very few+mAX_SOLVER_ITERATIONS :: Int+mAX_SOLVER_ITERATIONS = 4++wORD64_SIZE :: Int+wORD64_SIZE = 8++tARGET_MAX_CHAR :: Int+tARGET_MAX_CHAR = 0x10ffff
+ main/DriverMkDepend.hs view
@@ -0,0 +1,406 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Makefile Dependency Generation+--+-- (c) The University of Glasgow 2005+--+-----------------------------------------------------------------------------++module DriverMkDepend (+ doMkDependHS+ ) where++#include "HsVersions.h"++import qualified GHC+import GhcMonad+import DynFlags+import Util+import HscTypes+import SysTools ( newTempName )+import qualified SysTools+import Module+import Digraph ( SCC(..) )+import Finder+import Outputable+import Panic+import SrcLoc+import Data.List+import FastString++import Exception+import ErrUtils++import System.Directory+import System.FilePath+import System.IO+import System.IO.Error ( isEOFError )+import Control.Monad ( when )+import Data.Maybe ( isJust )++-----------------------------------------------------------------+--+-- The main function+--+-----------------------------------------------------------------++doMkDependHS :: GhcMonad m => [FilePath] -> m ()+doMkDependHS srcs = do+ -- Initialisation+ dflags0 <- GHC.getSessionDynFlags++ -- We kludge things a bit for dependency generation. Rather than+ -- generating dependencies for each way separately, we generate+ -- them once and then duplicate them for each way's osuf/hisuf.+ -- We therefore do the initial dependency generation with an empty+ -- way and .o/.hi extensions, regardless of any flags that might+ -- be specified.+ let dflags = dflags0 {+ ways = [],+ buildTag = mkBuildTag [],+ hiSuf = "hi",+ objectSuf = "o"+ }+ _ <- GHC.setSessionDynFlags dflags++ when (null (depSuffixes dflags)) $ liftIO $+ throwGhcExceptionIO (ProgramError "You must specify at least one -dep-suffix")++ files <- liftIO $ beginMkDependHS dflags++ -- Do the downsweep to find all the modules+ targets <- mapM (\s -> GHC.guessTarget s Nothing) srcs+ GHC.setTargets targets+ let excl_mods = depExcludeMods dflags+ mod_summaries <- GHC.depanal excl_mods True {- Allow dup roots -}++ -- Sort into dependency order+ -- There should be no cycles+ let sorted = GHC.topSortModuleGraph False mod_summaries Nothing++ -- Print out the dependencies if wanted+ liftIO $ debugTraceMsg dflags 2 (text "Module dependencies" $$ ppr sorted)++ -- Prcess them one by one, dumping results into makefile+ -- and complaining about cycles+ hsc_env <- getSession+ root <- liftIO getCurrentDirectory+ mapM_ (liftIO . processDeps dflags hsc_env excl_mods root (mkd_tmp_hdl files)) sorted++ -- If -ddump-mod-cycles, show cycles in the module graph+ liftIO $ dumpModCycles dflags mod_summaries++ -- Tidy up+ liftIO $ endMkDependHS dflags files++ -- Unconditional exiting is a bad idea. If an error occurs we'll get an+ --exception; if that is not caught it's fine, but at least we have a+ --chance to find out exactly what went wrong. Uncomment the following+ --line if you disagree.++ --`GHC.ghcCatch` \_ -> io $ exitWith (ExitFailure 1)++-----------------------------------------------------------------+--+-- beginMkDependHs+-- Create a temporary file,+-- find the Makefile,+-- slurp through it, etc+--+-----------------------------------------------------------------++data MkDepFiles+ = MkDep { mkd_make_file :: FilePath, -- Name of the makefile+ mkd_make_hdl :: Maybe Handle, -- Handle for the open makefile+ mkd_tmp_file :: FilePath, -- Name of the temporary file+ mkd_tmp_hdl :: Handle } -- Handle of the open temporary file++beginMkDependHS :: DynFlags -> IO MkDepFiles+beginMkDependHS dflags = do+ -- open a new temp file in which to stuff the dependency info+ -- as we go along.+ tmp_file <- newTempName dflags "dep"+ tmp_hdl <- openFile tmp_file WriteMode++ -- open the makefile+ let makefile = depMakefile dflags+ exists <- doesFileExist makefile+ mb_make_hdl <-+ if not exists+ then return Nothing+ else do+ makefile_hdl <- openFile makefile ReadMode++ -- slurp through until we get the magic start string,+ -- copying the contents into dep_makefile+ let slurp = do+ l <- hGetLine makefile_hdl+ if (l == depStartMarker)+ then return ()+ else do hPutStrLn tmp_hdl l; slurp++ -- slurp through until we get the magic end marker,+ -- throwing away the contents+ let chuck = do+ l <- hGetLine makefile_hdl+ if (l == depEndMarker)+ then return ()+ else chuck++ catchIO slurp+ (\e -> if isEOFError e then return () else ioError e)+ catchIO chuck+ (\e -> if isEOFError e then return () else ioError e)++ return (Just makefile_hdl)+++ -- write the magic marker into the tmp file+ hPutStrLn tmp_hdl depStartMarker++ return (MkDep { mkd_make_file = makefile, mkd_make_hdl = mb_make_hdl,+ mkd_tmp_file = tmp_file, mkd_tmp_hdl = tmp_hdl})+++-----------------------------------------------------------------+--+-- processDeps+--+-----------------------------------------------------------------++processDeps :: DynFlags+ -> HscEnv+ -> [ModuleName]+ -> FilePath+ -> Handle -- Write dependencies to here+ -> SCC ModSummary+ -> IO ()+-- Write suitable dependencies to handle+-- Always:+-- this.o : this.hs+--+-- If the dependency is on something other than a .hi file:+-- this.o this.p_o ... : dep+-- otherwise+-- this.o ... : dep.hi+-- this.p_o ... : dep.p_hi+-- ...+-- (where .o is $osuf, and the other suffixes come from+-- the cmdline -s options).+--+-- For {-# SOURCE #-} imports the "hi" will be "hi-boot".++processDeps dflags _ _ _ _ (CyclicSCC nodes)+ = -- There shouldn't be any cycles; report them+ throwGhcExceptionIO (ProgramError (showSDoc dflags $ GHC.cyclicModuleErr nodes))++processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC node)+ = do { let extra_suffixes = depSuffixes dflags+ include_pkg_deps = depIncludePkgDeps dflags+ src_file = msHsFilePath node+ obj_file = msObjFilePath node+ obj_files = insertSuffixes obj_file extra_suffixes++ do_imp loc is_boot pkg_qual imp_mod+ = do { mb_hi <- findDependency hsc_env loc pkg_qual imp_mod+ is_boot include_pkg_deps+ ; case mb_hi of {+ Nothing -> return () ;+ Just hi_file -> do+ { let hi_files = insertSuffixes hi_file extra_suffixes+ write_dep (obj,hi) = writeDependency root hdl [obj] hi++ -- Add one dependency for each suffix;+ -- e.g. A.o : B.hi+ -- A.x_o : B.x_hi+ ; mapM_ write_dep (obj_files `zip` hi_files) }}}+++ -- Emit std dependency of the object(s) on the source file+ -- Something like A.o : A.hs+ ; writeDependency root hdl obj_files src_file++ -- Emit a dependency for each import++ ; let do_imps is_boot idecls = sequence_+ [ do_imp loc is_boot mb_pkg mod+ | (mb_pkg, L loc mod) <- idecls,+ mod `notElem` excl_mods ]++ ; do_imps True (ms_srcimps node)+ ; do_imps False (ms_imps node)+ }+++findDependency :: HscEnv+ -> SrcSpan+ -> Maybe FastString -- package qualifier, if any+ -> ModuleName -- Imported module+ -> IsBootInterface -- Source import+ -> Bool -- Record dependency on package modules+ -> IO (Maybe FilePath) -- Interface file file+findDependency hsc_env srcloc pkg imp is_boot include_pkg_deps+ = do { -- Find the module; this will be fast because+ -- we've done it once during downsweep+ r <- findImportedModule hsc_env imp pkg+ ; case r of+ Found loc _+ -- Home package: just depend on the .hi or hi-boot file+ | isJust (ml_hs_file loc) || include_pkg_deps+ -> return (Just (addBootSuffix_maybe is_boot (ml_hi_file loc)))++ -- Not in this package: we don't need a dependency+ | otherwise+ -> return Nothing++ fail ->+ let dflags = hsc_dflags hsc_env+ in throwOneError $ mkPlainErrMsg dflags srcloc $+ cannotFindModule dflags imp fail+ }++-----------------------------+writeDependency :: FilePath -> Handle -> [FilePath] -> FilePath -> IO ()+-- (writeDependency r h [t1,t2] dep) writes to handle h the dependency+-- t1 t2 : dep+writeDependency root hdl targets dep+ = do let -- We need to avoid making deps on+ -- c:/foo/...+ -- on cygwin as make gets confused by the :+ -- Making relative deps avoids some instances of this.+ dep' = makeRelative root dep+ forOutput = escapeSpaces . reslash Forwards . normalise+ output = unwords (map forOutput targets) ++ " : " ++ forOutput dep'+ hPutStrLn hdl output++-----------------------------+insertSuffixes+ :: FilePath -- Original filename; e.g. "foo.o"+ -> [String] -- Suffix prefixes e.g. ["x_", "y_"]+ -> [FilePath] -- Zapped filenames e.g. ["foo.x_o", "foo.y_o"]+ -- Note that that the extra bit gets inserted *before* the old suffix+ -- We assume the old suffix contains no dots, so we know where to+ -- split it+insertSuffixes file_name extras+ = [ basename <.> (extra ++ suffix) | extra <- extras ]+ where+ (basename, suffix) = case splitExtension file_name of+ -- Drop the "." from the extension+ (b, s) -> (b, drop 1 s)+++-----------------------------------------------------------------+--+-- endMkDependHs+-- Complete the makefile, close the tmp file etc+--+-----------------------------------------------------------------++endMkDependHS :: DynFlags -> MkDepFiles -> IO ()++endMkDependHS dflags+ (MkDep { mkd_make_file = makefile, mkd_make_hdl = makefile_hdl,+ mkd_tmp_file = tmp_file, mkd_tmp_hdl = tmp_hdl })+ = do+ -- write the magic marker into the tmp file+ hPutStrLn tmp_hdl depEndMarker++ case makefile_hdl of+ Nothing -> return ()+ Just hdl -> do++ -- slurp the rest of the original makefile and copy it into the output+ let slurp = do+ l <- hGetLine hdl+ hPutStrLn tmp_hdl l+ slurp++ catchIO slurp+ (\e -> if isEOFError e then return () else ioError e)++ hClose hdl++ hClose tmp_hdl -- make sure it's flushed++ -- Create a backup of the original makefile+ when (isJust makefile_hdl)+ (SysTools.copy dflags ("Backing up " ++ makefile)+ makefile (makefile++".bak"))++ -- Copy the new makefile in place+ SysTools.copy dflags "Installing new makefile" tmp_file makefile+++-----------------------------------------------------------------+-- Module cycles+-----------------------------------------------------------------++dumpModCycles :: DynFlags -> [ModSummary] -> IO ()+dumpModCycles dflags mod_summaries+ | not (dopt Opt_D_dump_mod_cycles dflags)+ = return ()++ | null cycles+ = putMsg dflags (text "No module cycles")++ | otherwise+ = putMsg dflags (hang (text "Module cycles found:") 2 pp_cycles)+ where++ cycles :: [[ModSummary]]+ cycles = [ c | CyclicSCC c <- GHC.topSortModuleGraph True mod_summaries Nothing ]++ pp_cycles = vcat [ (text "---------- Cycle" <+> int n <+> ptext (sLit "----------"))+ $$ pprCycle c $$ blankLine+ | (n,c) <- [1..] `zip` cycles ]++pprCycle :: [ModSummary] -> SDoc+-- Print a cycle, but show only the imports within the cycle+pprCycle summaries = pp_group (CyclicSCC summaries)+ where+ cycle_mods :: [ModuleName] -- The modules in this cycle+ cycle_mods = map (moduleName . ms_mod) summaries++ pp_group (AcyclicSCC ms) = pp_ms ms+ pp_group (CyclicSCC mss)+ = ASSERT( not (null boot_only) )+ -- The boot-only list must be non-empty, else there would+ -- be an infinite chain of non-boot imoprts, and we've+ -- already checked for that in processModDeps+ pp_ms loop_breaker $$ vcat (map pp_group groups)+ where+ (boot_only, others) = partition is_boot_only mss+ is_boot_only ms = not (any in_group (map snd (ms_imps ms)))+ in_group (L _ m) = m `elem` group_mods+ group_mods = map (moduleName . ms_mod) mss++ loop_breaker = head boot_only+ all_others = tail boot_only ++ others+ groups = GHC.topSortModuleGraph True all_others Nothing++ pp_ms summary = text mod_str <> text (take (20 - length mod_str) (repeat ' '))+ <+> (pp_imps empty (map snd (ms_imps summary)) $$+ pp_imps (text "{-# SOURCE #-}") (map snd (ms_srcimps summary)))+ where+ mod_str = moduleNameString (moduleName (ms_mod summary))++ pp_imps :: SDoc -> [Located ModuleName] -> SDoc+ pp_imps _ [] = empty+ pp_imps what lms+ = case [m | L _ m <- lms, m `elem` cycle_mods] of+ [] -> empty+ ms -> what <+> text "imports" <+>+ pprWithCommas ppr ms++-----------------------------------------------------------------+--+-- Flags+--+-----------------------------------------------------------------++depStartMarker, depEndMarker :: String+depStartMarker = "# DO NOT DELETE: Beginning of Haskell dependencies"+depEndMarker = "# DO NOT DELETE: End of Haskell dependencies"+
+ main/DriverPhases.hs view
@@ -0,0 +1,375 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+-- $Id: DriverPhases.hs,v 1.38 2005/05/17 11:01:59 simonmar Exp $+--+-- GHC Driver+--+-- (c) The University of Glasgow 2002+--+-----------------------------------------------------------------------------++module DriverPhases (+ HscSource(..), isHsBootOrSig, hscSourceString,+ Phase(..),+ happensBefore, eqPhase, anyHsc, isStopLn,+ startPhase,+ phaseInputExt,++ isHaskellishSuffix,+ isHaskellSrcSuffix,+ isBackpackishSuffix,+ isObjectSuffix,+ isCishSuffix,+ isDynLibSuffix,+ isHaskellUserSrcSuffix,+ isHaskellSigSuffix,+ isSourceSuffix,++ isHaskellishTarget,++ isHaskellishFilename,+ isHaskellSrcFilename,+ isHaskellSigFilename,+ isObjectFilename,+ isCishFilename,+ isDynLibFilename,+ isHaskellUserSrcFilename,+ isSourceFilename+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} DynFlags+import Outputable+import Platform+import System.FilePath+import Binary+import Util++-----------------------------------------------------------------------------+-- Phases++{-+ Phase of the | Suffix saying | Flag saying | (suffix of)+ compilation system | ``start here''| ``stop after''| output file++ literate pre-processor | .lhs | - | -+ C pre-processor (opt.) | - | -E | -+ Haskell compiler | .hs | -C, -S | .hc, .s+ C compiler (opt.) | .hc or .c | -S | .s+ assembler | .s or .S | -c | .o+ linker | other | - | a.out+-}++-- Note [HscSource types]+-- ~~~~~~~~~~~~~~~~~~~~~~+-- There are three types of source file for Haskell code:+--+-- * HsSrcFile is an ordinary hs file which contains code,+--+-- * HsBootFile is an hs-boot file, which is used to break+-- recursive module imports (there will always be an+-- HsSrcFile associated with it), and+--+-- * HsigFile is an hsig file, which contains only type+-- signatures and is used to specify signatures for+-- modules.+--+-- Syntactically, hs-boot files and hsig files are quite similar: they+-- only include type signatures and must be associated with an+-- actual HsSrcFile. isHsBootOrSig allows us to abstract over code+-- which is indifferent to which. However, there are some important+-- differences, mostly owing to the fact that hsigs are proper+-- modules (you `import Sig` directly) whereas HsBootFiles are+-- temporary placeholders (you `import {-# SOURCE #-} Mod).+-- When we finish compiling the true implementation of an hs-boot,+-- we replace the HomeModInfo with the real HsSrcFile. An HsigFile, on the+-- other hand, is never replaced (in particular, we *cannot* use the+-- HomeModInfo of the original HsSrcFile backing the signature, since it+-- will export too many symbols.)+--+-- Additionally, while HsSrcFile is the only Haskell file+-- which has *code*, we do generate .o files for HsigFile, because+-- this is how the recompilation checker figures out if a file+-- needs to be recompiled. These are fake object files which+-- should NOT be linked against.++data HscSource+ = HsSrcFile | HsBootFile | HsigFile+ deriving( Eq, Ord, Show )+ -- Ord needed for the finite maps we build in CompManager++instance Binary HscSource where+ put_ bh HsSrcFile = putByte bh 0+ put_ bh HsBootFile = putByte bh 1+ put_ bh HsigFile = putByte bh 2+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return HsSrcFile+ 1 -> return HsBootFile+ _ -> return HsigFile++hscSourceString :: HscSource -> String+hscSourceString HsSrcFile = ""+hscSourceString HsBootFile = "[boot]"+hscSourceString HsigFile = "[sig]"++-- See Note [isHsBootOrSig]+isHsBootOrSig :: HscSource -> Bool+isHsBootOrSig HsBootFile = True+isHsBootOrSig HsigFile = True+isHsBootOrSig _ = False++data Phase+ = Unlit HscSource+ | Cpp HscSource+ | HsPp HscSource+ | Hsc HscSource+ | Ccxx -- Compile C+++ | Cc -- Compile C+ | Cobjc -- Compile Objective-C+ | Cobjcxx -- Compile Objective-C+++ | HCc -- Haskellised C (as opposed to vanilla C) compilation+ | Splitter -- Assembly file splitter (part of '-split-objs')+ | SplitAs -- Assembler for split assembly files (part of '-split-objs')+ | As Bool -- Assembler for regular assembly files (Bool: with-cpp)+ | LlvmOpt -- Run LLVM opt tool over llvm assembly+ | LlvmLlc -- LLVM bitcode to native assembly+ | LlvmMangle -- Fix up TNTC by processing assembly produced by LLVM+ | CmmCpp -- pre-process Cmm source+ | Cmm -- parse & compile Cmm code+ | MergeForeign -- merge in the foreign object files++ -- The final phase is a pseudo-phase that tells the pipeline to stop.+ -- There is no runPhase case for it.+ | StopLn -- Stop, but linking will follow, so generate .o file+ deriving (Eq, Show)++instance Outputable Phase where+ ppr p = text (show p)++anyHsc :: Phase+anyHsc = Hsc (panic "anyHsc")++isStopLn :: Phase -> Bool+isStopLn StopLn = True+isStopLn _ = False++eqPhase :: Phase -> Phase -> Bool+-- Equality of constructors, ignoring the HscSource field+-- NB: the HscSource field can be 'bot'; see anyHsc above+eqPhase (Unlit _) (Unlit _) = True+eqPhase (Cpp _) (Cpp _) = True+eqPhase (HsPp _) (HsPp _) = True+eqPhase (Hsc _) (Hsc _) = True+eqPhase Cc Cc = True+eqPhase Cobjc Cobjc = True+eqPhase HCc HCc = True+eqPhase Splitter Splitter = True+eqPhase SplitAs SplitAs = True+eqPhase (As x) (As y) = x == y+eqPhase LlvmOpt LlvmOpt = True+eqPhase LlvmLlc LlvmLlc = True+eqPhase LlvmMangle LlvmMangle = True+eqPhase CmmCpp CmmCpp = True+eqPhase Cmm Cmm = True+eqPhase MergeForeign MergeForeign = True+eqPhase StopLn StopLn = True+eqPhase Ccxx Ccxx = True+eqPhase Cobjcxx Cobjcxx = True+eqPhase _ _ = False++{- Note [Partial ordering on phases]++We want to know which phases will occur before which others. This is used for+sanity checking, to ensure that the pipeline will stop at some point (see+DriverPipeline.runPipeline).++A < B iff A occurs before B in a normal compilation pipeline.++There is explicitly not a total ordering on phases, because in registerised+builds, the phase `HsC` doesn't happen before nor after any other phase.++Although we check that a normal user doesn't set the stop_phase to HsC through+use of -C with registerised builds (in Main.checkOptions), it is still+possible for a ghc-api user to do so. So be careful when using the function+happensBefore, and don't think that `not (a <= b)` implies `b < a`.+-}+happensBefore :: DynFlags -> Phase -> Phase -> Bool+happensBefore dflags p1 p2 = p1 `happensBefore'` p2+ where StopLn `happensBefore'` _ = False+ x `happensBefore'` y = after_x `eqPhase` y+ || after_x `happensBefore'` y+ where after_x = nextPhase dflags x++nextPhase :: DynFlags -> Phase -> Phase+nextPhase dflags p+ -- A conservative approximation to the next phase, used in happensBefore+ = case p of+ Unlit sf -> Cpp sf+ Cpp sf -> HsPp sf+ HsPp sf -> Hsc sf+ Hsc _ -> maybeHCc+ Splitter -> SplitAs+ LlvmOpt -> LlvmLlc+ LlvmLlc -> LlvmMangle+ LlvmMangle -> As False+ SplitAs -> MergeForeign+ As _ -> MergeForeign+ Ccxx -> As False+ Cc -> As False+ Cobjc -> As False+ Cobjcxx -> As False+ CmmCpp -> Cmm+ Cmm -> maybeHCc+ HCc -> As False+ MergeForeign -> StopLn+ StopLn -> panic "nextPhase: nothing after StopLn"+ where maybeHCc = if platformUnregisterised (targetPlatform dflags)+ then HCc+ else As False++-- the first compilation phase for a given file is determined+-- by its suffix.+startPhase :: String -> Phase+startPhase "lhs" = Unlit HsSrcFile+startPhase "lhs-boot" = Unlit HsBootFile+startPhase "lhsig" = Unlit HsigFile+startPhase "hs" = Cpp HsSrcFile+startPhase "hs-boot" = Cpp HsBootFile+startPhase "hsig" = Cpp HsigFile+startPhase "hscpp" = HsPp HsSrcFile+startPhase "hspp" = Hsc HsSrcFile+startPhase "hc" = HCc+startPhase "c" = Cc+startPhase "cpp" = Ccxx+startPhase "C" = Cc+startPhase "m" = Cobjc+startPhase "M" = Cobjcxx+startPhase "mm" = Cobjcxx+startPhase "cc" = Ccxx+startPhase "cxx" = Ccxx+startPhase "split_s" = Splitter+startPhase "s" = As False+startPhase "S" = As True+startPhase "ll" = LlvmOpt+startPhase "bc" = LlvmLlc+startPhase "lm_s" = LlvmMangle+startPhase "o" = StopLn+startPhase "cmm" = CmmCpp+startPhase "cmmcpp" = Cmm+startPhase _ = StopLn -- all unknown file types++-- This is used to determine the extension for the output from the+-- current phase (if it generates a new file). The extension depends+-- on the next phase in the pipeline.+phaseInputExt :: Phase -> String+phaseInputExt (Unlit HsSrcFile) = "lhs"+phaseInputExt (Unlit HsBootFile) = "lhs-boot"+phaseInputExt (Unlit HsigFile) = "lhsig"+phaseInputExt (Cpp _) = "lpp" -- intermediate only+phaseInputExt (HsPp _) = "hscpp" -- intermediate only+phaseInputExt (Hsc _) = "hspp" -- intermediate only+ -- NB: as things stand, phaseInputExt (Hsc x) must not evaluate x+ -- because runPipeline uses the StopBefore phase to pick the+ -- output filename. That could be fixed, but watch out.+phaseInputExt HCc = "hc"+phaseInputExt Ccxx = "cpp"+phaseInputExt Cobjc = "m"+phaseInputExt Cobjcxx = "mm"+phaseInputExt Cc = "c"+phaseInputExt Splitter = "split_s"+phaseInputExt (As True) = "S"+phaseInputExt (As False) = "s"+phaseInputExt LlvmOpt = "ll"+phaseInputExt LlvmLlc = "bc"+phaseInputExt LlvmMangle = "lm_s"+phaseInputExt SplitAs = "split_s"+phaseInputExt CmmCpp = "cmm"+phaseInputExt Cmm = "cmmcpp"+phaseInputExt MergeForeign = "o"+phaseInputExt StopLn = "o"++haskellish_src_suffixes, backpackish_suffixes, haskellish_suffixes, cish_suffixes,+ haskellish_user_src_suffixes, haskellish_sig_suffixes+ :: [String]+-- When a file with an extension in the haskellish_src_suffixes group is+-- loaded in --make mode, its imports will be loaded too.+haskellish_src_suffixes = haskellish_user_src_suffixes +++ [ "hspp", "hscpp" ]+haskellish_suffixes = haskellish_src_suffixes +++ [ "hc", "cmm", "cmmcpp" ]+cish_suffixes = [ "c", "cpp", "C", "cc", "cxx", "s", "S", "ll", "bc", "lm_s", "m", "M", "mm" ]++-- Will not be deleted as temp files:+haskellish_user_src_suffixes =+ haskellish_sig_suffixes ++ [ "hs", "lhs", "hs-boot", "lhs-boot" ]+haskellish_sig_suffixes = [ "hsig", "lhsig" ]+backpackish_suffixes = [ "bkp" ]++objish_suffixes :: Platform -> [String]+-- Use the appropriate suffix for the system on which+-- the GHC-compiled code will run+objish_suffixes platform = case platformOS platform of+ OSMinGW32 -> [ "o", "O", "obj", "OBJ" ]+ _ -> [ "o" ]++dynlib_suffixes :: Platform -> [String]+dynlib_suffixes platform = case platformOS platform of+ OSMinGW32 -> ["dll", "DLL"]+ OSDarwin -> ["dylib", "so"]+ _ -> ["so"]++isHaskellishSuffix, isBackpackishSuffix, isHaskellSrcSuffix, isCishSuffix,+ isHaskellUserSrcSuffix, isHaskellSigSuffix+ :: String -> Bool+isHaskellishSuffix s = s `elem` haskellish_suffixes+isBackpackishSuffix s = s `elem` backpackish_suffixes+isHaskellSigSuffix s = s `elem` haskellish_sig_suffixes+isHaskellSrcSuffix s = s `elem` haskellish_src_suffixes+isCishSuffix s = s `elem` cish_suffixes+isHaskellUserSrcSuffix s = s `elem` haskellish_user_src_suffixes++isObjectSuffix, isDynLibSuffix :: Platform -> String -> Bool+isObjectSuffix platform s = s `elem` objish_suffixes platform+isDynLibSuffix platform s = s `elem` dynlib_suffixes platform++isSourceSuffix :: String -> Bool+isSourceSuffix suff = isHaskellishSuffix suff+ || isCishSuffix suff+ || isBackpackishSuffix suff++-- | When we are given files (modified by -x arguments) we need+-- to determine if they are Haskellish or not to figure out+-- how we should try to compile it. The rules are:+--+-- 1. If no -x flag was specified, we check to see if+-- the file looks like a module name, has no extension,+-- or has a Haskell source extension.+--+-- 2. If an -x flag was specified, we just make sure the+-- specified suffix is a Haskell one.+isHaskellishTarget :: (String, Maybe Phase) -> Bool+isHaskellishTarget (f,Nothing) =+ looksLikeModuleName f || isHaskellSrcFilename f || not (hasExtension f)+isHaskellishTarget (_,Just phase) =+ phase `notElem` [ As True, As False, Cc, Cobjc, Cobjcxx, CmmCpp, Cmm+ , StopLn]++isHaskellishFilename, isHaskellSrcFilename, isCishFilename,+ isHaskellUserSrcFilename, isSourceFilename, isHaskellSigFilename+ :: FilePath -> Bool+-- takeExtension return .foo, so we drop 1 to get rid of the .+isHaskellishFilename f = isHaskellishSuffix (drop 1 $ takeExtension f)+isHaskellSrcFilename f = isHaskellSrcSuffix (drop 1 $ takeExtension f)+isCishFilename f = isCishSuffix (drop 1 $ takeExtension f)+isHaskellUserSrcFilename f = isHaskellUserSrcSuffix (drop 1 $ takeExtension f)+isSourceFilename f = isSourceSuffix (drop 1 $ takeExtension f)+isHaskellSigFilename f = isHaskellSigSuffix (drop 1 $ takeExtension f)++isObjectFilename, isDynLibFilename :: Platform -> FilePath -> Bool+isObjectFilename platform f = isObjectSuffix platform (drop 1 $ takeExtension f)+isDynLibFilename platform f = isDynLibSuffix platform (drop 1 $ takeExtension f)+
+ main/DriverPipeline.hs view
@@ -0,0 +1,2411 @@+{-# LANGUAGE CPP, NamedFieldPuns, NondecreasingIndentation #-}+{-# OPTIONS_GHC -fno-cse #-}+-- -fno-cse is needed for GLOBAL_VAR's to behave properly++-----------------------------------------------------------------------------+--+-- GHC Driver+--+-- (c) The University of Glasgow 2005+--+-----------------------------------------------------------------------------++module DriverPipeline (+ -- Run a series of compilation steps in a pipeline, for a+ -- collection of source files.+ oneShot, compileFile,++ -- Interfaces for the batch-mode driver+ linkBinary,++ -- Interfaces for the compilation manager (interpreted/batch-mode)+ preprocess,+ compileOne, compileOne',+ link,++ -- Exports for hooks to override runPhase and link+ PhasePlus(..), CompPipeline(..), PipeEnv(..), PipeState(..),+ phaseOutputFilename, getOutputFilename, getPipeState, getPipeEnv,+ hscPostBackendPhase, getLocation, setModLocation, setDynFlags,+ runPhase, exeFileName,+ mkExtraObjToLinkIntoBinary, mkNoteObjsToLinkIntoBinary,+ maybeCreateManifest,+ linkingNeeded, checkLinkInfo, writeInterfaceOnlyMode+ ) where++#include "HsVersions.h"++import PipelineMonad+import Packages+import HeaderInfo+import DriverPhases+import SysTools+import Elf+import HscMain+import Finder+import HscTypes hiding ( Hsc )+import Outputable+import Module+import ErrUtils+import DynFlags+import Config+import Panic+import Util+import StringBuffer ( hGetStringBuffer )+import BasicTypes ( SuccessFlag(..) )+import Maybes ( expectJust )+import SrcLoc+import LlvmCodeGen ( llvmFixupAsm )+import MonadUtils+import Platform+import TcRnTypes+import Hooks+import qualified GHC.LanguageExtensions as LangExt++import Exception+import System.Directory+import System.FilePath+import System.IO+import Control.Monad+import Data.List ( isSuffixOf )+import Data.Maybe+import Data.Version++-- ---------------------------------------------------------------------------+-- Pre-process++-- | Just preprocess a file, put the result in a temp. file (used by the+-- compilation manager during the summary phase).+--+-- We return the augmented DynFlags, because they contain the result+-- of slurping in the OPTIONS pragmas++preprocess :: HscEnv+ -> (FilePath, Maybe Phase) -- ^ filename and starting phase+ -> IO (DynFlags, FilePath)+preprocess hsc_env (filename, mb_phase) =+ ASSERT2(isJust mb_phase || isHaskellSrcFilename filename, text filename)+ runPipeline anyHsc hsc_env (filename, fmap RealPhase mb_phase)+ Nothing Temporary Nothing{-no ModLocation-} []{-no foreign objects-}++-- ---------------------------------------------------------------------------++-- | Compile+--+-- Compile a single module, under the control of the compilation manager.+--+-- This is the interface between the compilation manager and the+-- compiler proper (hsc), where we deal with tedious details like+-- reading the OPTIONS pragma from the source file, converting the+-- C or assembly that GHC produces into an object file, and compiling+-- FFI stub files.+--+-- NB. No old interface can also mean that the source has changed.++compileOne :: HscEnv+ -> ModSummary -- ^ summary for module being compiled+ -> Int -- ^ module N ...+ -> Int -- ^ ... of M+ -> Maybe ModIface -- ^ old interface, if we have one+ -> Maybe Linkable -- ^ old linkable, if we have one+ -> SourceModified+ -> IO HomeModInfo -- ^ the complete HomeModInfo, if successful++compileOne = compileOne' Nothing (Just batchMsg)++compileOne' :: Maybe TcGblEnv+ -> Maybe Messager+ -> HscEnv+ -> ModSummary -- ^ summary for module being compiled+ -> Int -- ^ module N ...+ -> Int -- ^ ... of M+ -> Maybe ModIface -- ^ old interface, if we have one+ -> Maybe Linkable -- ^ old linkable, if we have one+ -> SourceModified+ -> IO HomeModInfo -- ^ the complete HomeModInfo, if successful++compileOne' m_tc_result mHscMessage+ hsc_env0 summary mod_index nmods mb_old_iface maybe_old_linkable+ source_modified0+ = do++ debugTraceMsg dflags1 2 (text "compile: input file" <+> text input_fnpp)++ (status, hmi0) <- hscIncrementalCompile+ always_do_basic_recompilation_check+ m_tc_result mHscMessage+ hsc_env summary source_modified mb_old_iface (mod_index, nmods)++ let flags = hsc_dflags hsc_env0+ in do unless (gopt Opt_KeepHiFiles flags) $+ addFilesToClean flags [ml_hi_file $ ms_location summary]+ unless (gopt Opt_KeepOFiles flags) $+ addFilesToClean flags [ml_obj_file $ ms_location summary]++ case (status, hsc_lang) of+ (HscUpToDate, _) ->+ -- TODO recomp014 triggers this assert. What's going on?!+ -- ASSERT( isJust maybe_old_linkable || isNoLink (ghcLink dflags) )+ return hmi0 { hm_linkable = maybe_old_linkable }+ (HscNotGeneratingCode, HscNothing) ->+ let mb_linkable = if isHsBootOrSig src_flavour+ then Nothing+ -- TODO: Questionable.+ else Just (LM (ms_hs_date summary) this_mod [])+ in return hmi0 { hm_linkable = mb_linkable }+ (HscNotGeneratingCode, _) -> panic "compileOne HscNotGeneratingCode"+ (_, HscNothing) -> panic "compileOne HscNothing"+ (HscUpdateBoot, HscInterpreted) -> do+ return hmi0+ (HscUpdateBoot, _) -> do+ touchObjectFile dflags object_filename+ return hmi0+ (HscUpdateSig, HscInterpreted) ->+ let linkable = LM (ms_hs_date summary) this_mod []+ in return hmi0 { hm_linkable = Just linkable }+ (HscUpdateSig, _) -> do+ output_fn <- getOutputFilename next_phase+ Temporary basename dflags next_phase (Just location)++ -- #10660: Use the pipeline instead of calling+ -- compileEmptyStub directly, so -dynamic-too gets+ -- handled properly+ _ <- runPipeline StopLn hsc_env+ (output_fn,+ Just (HscOut src_flavour+ mod_name HscUpdateSig))+ (Just basename)+ Persistent+ (Just location)+ []+ o_time <- getModificationUTCTime object_filename+ let linkable = LM o_time this_mod [DotO object_filename]+ return hmi0 { hm_linkable = Just linkable }+ (HscRecomp cgguts summary, HscInterpreted) -> do+ (hasStub, comp_bc, spt_entries) <-+ hscInteractive hsc_env cgguts summary++ stub_o <- case hasStub of+ Nothing -> return []+ Just stub_c -> do+ stub_o <- compileStub hsc_env stub_c+ return [DotO stub_o]++ let hs_unlinked = [BCOs comp_bc spt_entries]+ unlinked_time = ms_hs_date summary+ -- Why do we use the timestamp of the source file here,+ -- rather than the current time? This works better in+ -- the case where the local clock is out of sync+ -- with the filesystem's clock. It's just as accurate:+ -- if the source is modified, then the linkable will+ -- be out of date.+ let linkable = LM unlinked_time (ms_mod summary)+ (hs_unlinked ++ stub_o)+ return hmi0 { hm_linkable = Just linkable }+ (HscRecomp cgguts summary, _) -> do+ output_fn <- getOutputFilename next_phase+ Temporary basename dflags next_phase (Just location)+ -- We're in --make mode: finish the compilation pipeline.+ _ <- runPipeline StopLn hsc_env+ (output_fn,+ Just (HscOut src_flavour mod_name (HscRecomp cgguts summary)))+ (Just basename)+ Persistent+ (Just location)+ []+ -- The object filename comes from the ModLocation+ o_time <- getModificationUTCTime object_filename+ let linkable = LM o_time this_mod [DotO object_filename]+ return hmi0 { hm_linkable = Just linkable }++ where dflags0 = ms_hspp_opts summary++ this_mod = ms_mod summary+ location = ms_location summary+ input_fn = expectJust "compile:hs" (ml_hs_file location)+ input_fnpp = ms_hspp_file summary+ mod_graph = hsc_mod_graph hsc_env0+ needsTH = any (xopt LangExt.TemplateHaskell . ms_hspp_opts) mod_graph+ needsQQ = any (xopt LangExt.QuasiQuotes . ms_hspp_opts) mod_graph+ needsLinker = needsTH || needsQQ+ isDynWay = any (== WayDyn) (ways dflags0)+ isProfWay = any (== WayProf) (ways dflags0)+ internalInterpreter = not (gopt Opt_ExternalInterpreter dflags0)++ src_flavour = ms_hsc_src summary+ mod_name = ms_mod_name summary+ next_phase = hscPostBackendPhase dflags src_flavour hsc_lang+ object_filename = ml_obj_file location++ -- #8180 - when using TemplateHaskell, switch on -dynamic-too so+ -- the linker can correctly load the object files. This isn't necessary+ -- when using -fexternal-interpreter.+ dflags1 = if needsLinker && dynamicGhc && internalInterpreter &&+ not isDynWay && not isProfWay+ then gopt_set dflags0 Opt_BuildDynamicToo+ else dflags0++ basename = dropExtension input_fn++ -- We add the directory in which the .hs files resides) to the import+ -- path. This is needed when we try to compile the .hc file later, if it+ -- imports a _stub.h file that we created here.+ current_dir = takeDirectory basename+ old_paths = includePaths dflags1+ prevailing_dflags = hsc_dflags hsc_env0+ dflags =+ dflags1 { includePaths = current_dir : old_paths+ , log_action = log_action prevailing_dflags+ , log_finaliser = log_finaliser prevailing_dflags }+ -- use the prevailing log_action / log_finaliser,+ -- not the one cached in the summary. This is so+ -- that we can change the log_action without having+ -- to re-summarize all the source files.+ hsc_env = hsc_env0 {hsc_dflags = dflags}++ -- Figure out what lang we're generating+ hsc_lang = hscTarget dflags++ -- -fforce-recomp should also work with --make+ force_recomp = gopt Opt_ForceRecomp dflags+ source_modified+ | force_recomp = SourceModified+ | otherwise = source_modified0++ always_do_basic_recompilation_check = case hsc_lang of+ HscInterpreted -> True+ _ -> False++-----------------------------------------------------------------------------+-- stub .h and .c files (for foreign export support), and cc files.++-- The _stub.c file is derived from the haskell source file, possibly taking+-- into account the -stubdir option.+--+-- The object file created by compiling the _stub.c file is put into a+-- temporary file, which will be later combined with the main .o file+-- (see the MergeForeigns phase).+--+-- Moreover, we also let the user emit arbitrary C/C++/ObjC/ObjC++ files+-- from TH, that are then compiled and linked to the module. This is+-- useful to implement facilities such as inline-c.++compileForeign :: HscEnv -> ForeignSrcLang -> FilePath -> IO FilePath+compileForeign hsc_env lang stub_c = do+ let phase = case lang of+ LangC -> Cc+ LangCxx -> Ccxx+ LangObjc -> Cobjc+ LangObjcxx -> Cobjcxx+ (_, stub_o) <- runPipeline StopLn hsc_env+ (stub_c, Just (RealPhase phase))+ Nothing Temporary Nothing{-no ModLocation-} []++ return stub_o++compileStub :: HscEnv -> FilePath -> IO FilePath+compileStub hsc_env stub_c = compileForeign hsc_env LangC stub_c++compileEmptyStub :: DynFlags -> HscEnv -> FilePath -> ModLocation -> ModuleName -> IO ()+compileEmptyStub dflags hsc_env basename location mod_name = do+ -- To maintain the invariant that every Haskell file+ -- compiles to object code, we make an empty (but+ -- valid) stub object file for signatures. However,+ -- we make sure this object file has a unique symbol,+ -- so that ranlib on OS X doesn't complain, see+ -- http://ghc.haskell.org/trac/ghc/ticket/12673+ -- and https://github.com/haskell/cabal/issues/2257+ empty_stub <- newTempName dflags "c"+ let src = text "int" <+> ppr (mkModule (thisPackage dflags) mod_name) <+> text "= 0;"+ writeFile empty_stub (showSDoc dflags (pprCode CStyle src))+ _ <- runPipeline StopLn hsc_env+ (empty_stub, Nothing)+ (Just basename)+ Persistent+ (Just location)+ []+ return ()++-- ---------------------------------------------------------------------------+-- Link++link :: GhcLink -- interactive or batch+ -> DynFlags -- dynamic flags+ -> Bool -- attempt linking in batch mode?+ -> HomePackageTable -- what to link+ -> IO SuccessFlag++-- For the moment, in the batch linker, we don't bother to tell doLink+-- which packages to link -- it just tries all that are available.+-- batch_attempt_linking should only be *looked at* in batch mode. It+-- should only be True if the upsweep was successful and someone+-- exports main, i.e., we have good reason to believe that linking+-- will succeed.++link ghcLink dflags+ = lookupHook linkHook l dflags ghcLink dflags+ where+ l LinkInMemory _ _ _+ = if cGhcWithInterpreter == "YES"+ then -- Not Linking...(demand linker will do the job)+ return Succeeded+ else panicBadLink LinkInMemory++ l NoLink _ _ _+ = return Succeeded++ l LinkBinary dflags batch_attempt_linking hpt+ = link' dflags batch_attempt_linking hpt++ l LinkStaticLib dflags batch_attempt_linking hpt+ = link' dflags batch_attempt_linking hpt++ l LinkDynLib dflags batch_attempt_linking hpt+ = link' dflags batch_attempt_linking hpt++panicBadLink :: GhcLink -> a+panicBadLink other = panic ("link: GHC not built to link this way: " +++ show other)++link' :: DynFlags -- dynamic flags+ -> Bool -- attempt linking in batch mode?+ -> HomePackageTable -- what to link+ -> IO SuccessFlag++link' dflags batch_attempt_linking hpt+ | batch_attempt_linking+ = do+ let+ staticLink = case ghcLink dflags of+ LinkStaticLib -> True+ _ -> platformBinariesAreStaticLibs (targetPlatform dflags)++ home_mod_infos = eltsHpt hpt++ -- the packages we depend on+ pkg_deps = concatMap (map fst . dep_pkgs . mi_deps . hm_iface) home_mod_infos++ -- the linkables to link+ linkables = map (expectJust "link".hm_linkable) home_mod_infos++ debugTraceMsg dflags 3 (text "link: linkables are ..." $$ vcat (map ppr linkables))++ -- check for the -no-link flag+ if isNoLink (ghcLink dflags)+ then do debugTraceMsg dflags 3 (text "link(batch): linking omitted (-c flag given).")+ return Succeeded+ else do++ let getOfiles (LM _ _ us) = map nameOfObject (filter isObject us)+ obj_files = concatMap getOfiles linkables++ exe_file = exeFileName staticLink dflags++ linking_needed <- linkingNeeded dflags staticLink linkables pkg_deps++ if not (gopt Opt_ForceRecomp dflags) && not linking_needed+ then do debugTraceMsg dflags 2 (text exe_file <+> text "is up to date, linking not required.")+ return Succeeded+ else do++ compilationProgressMsg dflags ("Linking " ++ exe_file ++ " ...")++ -- Don't showPass in Batch mode; doLink will do that for us.+ let link = case ghcLink dflags of+ LinkBinary -> linkBinary+ LinkStaticLib -> linkStaticLibCheck+ LinkDynLib -> linkDynLibCheck+ other -> panicBadLink other+ link dflags obj_files pkg_deps++ debugTraceMsg dflags 3 (text "link: done")++ -- linkBinary only returns if it succeeds+ return Succeeded++ | otherwise+ = do debugTraceMsg dflags 3 (text "link(batch): upsweep (partially) failed OR" $$+ text " Main.main not exported; not linking.")+ return Succeeded+++linkingNeeded :: DynFlags -> Bool -> [Linkable] -> [InstalledUnitId] -> IO Bool+linkingNeeded dflags staticLink linkables pkg_deps = do+ -- if the modification time on the executable is later than the+ -- modification times on all of the objects and libraries, then omit+ -- linking (unless the -fforce-recomp flag was given).+ let exe_file = exeFileName staticLink dflags+ e_exe_time <- tryIO $ getModificationUTCTime exe_file+ case e_exe_time of+ Left _ -> return True+ Right t -> do+ -- first check object files and extra_ld_inputs+ let extra_ld_inputs = [ f | FileOption _ f <- ldInputs dflags ]+ e_extra_times <- mapM (tryIO . getModificationUTCTime) extra_ld_inputs+ let (errs,extra_times) = splitEithers e_extra_times+ let obj_times = map linkableTime linkables ++ extra_times+ if not (null errs) || any (t <) obj_times+ then return True+ else do++ -- next, check libraries. XXX this only checks Haskell libraries,+ -- not extra_libraries or -l things from the command line.+ let pkg_hslibs = [ (collectLibraryPaths dflags [c], lib)+ | Just c <- map (lookupInstalledPackage dflags) pkg_deps,+ lib <- packageHsLibs dflags c ]++ pkg_libfiles <- mapM (uncurry (findHSLib dflags)) pkg_hslibs+ if any isNothing pkg_libfiles then return True else do+ e_lib_times <- mapM (tryIO . getModificationUTCTime)+ (catMaybes pkg_libfiles)+ let (lib_errs,lib_times) = splitEithers e_lib_times+ if not (null lib_errs) || any (t <) lib_times+ then return True+ else checkLinkInfo dflags pkg_deps exe_file++-- Returns 'False' if it was, and we can avoid linking, because the+-- previous binary was linked with "the same options".+checkLinkInfo :: DynFlags -> [InstalledUnitId] -> FilePath -> IO Bool+checkLinkInfo dflags pkg_deps exe_file+ | not (platformSupportsSavingLinkOpts (platformOS (targetPlatform dflags)))+ -- ToDo: Windows and OS X do not use the ELF binary format, so+ -- readelf does not work there. We need to find another way to do+ -- this.+ = return False -- conservatively we should return True, but not+ -- linking in this case was the behaviour for a long+ -- time so we leave it as-is.+ | otherwise+ = do+ link_info <- getLinkInfo dflags pkg_deps+ debugTraceMsg dflags 3 $ text ("Link info: " ++ link_info)+ m_exe_link_info <- readElfNoteAsString dflags exe_file+ ghcLinkInfoSectionName ghcLinkInfoNoteName+ let sameLinkInfo = (Just link_info == m_exe_link_info)+ debugTraceMsg dflags 3 $ case m_exe_link_info of+ Nothing -> text "Exe link info: Not found"+ Just s+ | sameLinkInfo -> text ("Exe link info is the same")+ | otherwise -> text ("Exe link info is different: " ++ s)+ return (not sameLinkInfo)++platformSupportsSavingLinkOpts :: OS -> Bool+platformSupportsSavingLinkOpts os+ | os == OSSolaris2 = False -- see #5382+ | otherwise = osElfTarget os++-- See Note [LinkInfo section]+ghcLinkInfoSectionName :: String+ghcLinkInfoSectionName = ".debug-ghc-link-info"+ -- if we use the ".debug" prefix, then strip will strip it by default++-- Identifier for the note (see Note [LinkInfo section])+ghcLinkInfoNoteName :: String+ghcLinkInfoNoteName = "GHC link info"++findHSLib :: DynFlags -> [String] -> String -> IO (Maybe FilePath)+findHSLib dflags dirs lib = do+ let batch_lib_file = if WayDyn `notElem` ways dflags+ then "lib" ++ lib <.> "a"+ else mkSOName (targetPlatform dflags) lib+ found <- filterM doesFileExist (map (</> batch_lib_file) dirs)+ case found of+ [] -> return Nothing+ (x:_) -> return (Just x)++-- -----------------------------------------------------------------------------+-- Compile files in one-shot mode.++oneShot :: HscEnv -> Phase -> [(String, Maybe Phase)] -> IO ()+oneShot hsc_env stop_phase srcs = do+ o_files <- mapM (compileFile hsc_env stop_phase) srcs+ doLink (hsc_dflags hsc_env) stop_phase o_files++compileFile :: HscEnv -> Phase -> (FilePath, Maybe Phase) -> IO FilePath+compileFile hsc_env stop_phase (src, mb_phase) = do+ exists <- doesFileExist src+ when (not exists) $+ throwGhcExceptionIO (CmdLineError ("does not exist: " ++ src))++ let+ dflags = hsc_dflags hsc_env+ split = gopt Opt_SplitObjs dflags+ mb_o_file = outputFile dflags+ ghc_link = ghcLink dflags -- Set by -c or -no-link++ -- When linking, the -o argument refers to the linker's output.+ -- otherwise, we use it as the name for the pipeline's output.+ output+ -- If we are dong -fno-code, then act as if the output is+ -- 'Temporary'. This stops GHC trying to copy files to their+ -- final location.+ | HscNothing <- hscTarget dflags = Temporary+ | StopLn <- stop_phase, not (isNoLink ghc_link) = Persistent+ -- -o foo applies to linker+ | isJust mb_o_file = SpecificFile+ -- -o foo applies to the file we are compiling now+ | otherwise = Persistent++ stop_phase' = case stop_phase of+ As _ | split -> SplitAs+ _ -> stop_phase++ ( _, out_file) <- runPipeline stop_phase' hsc_env+ (src, fmap RealPhase mb_phase) Nothing output+ Nothing{-no ModLocation-} []+ return out_file+++doLink :: DynFlags -> Phase -> [FilePath] -> IO ()+doLink dflags stop_phase o_files+ | not (isStopLn stop_phase)+ = return () -- We stopped before the linking phase++ | otherwise+ = case ghcLink dflags of+ NoLink -> return ()+ LinkBinary -> linkBinary dflags o_files []+ LinkStaticLib -> linkStaticLibCheck dflags o_files []+ LinkDynLib -> linkDynLibCheck dflags o_files []+ other -> panicBadLink other+++-- ---------------------------------------------------------------------------++-- | Run a compilation pipeline, consisting of multiple phases.+--+-- This is the interface to the compilation pipeline, which runs+-- a series of compilation steps on a single source file, specifying+-- at which stage to stop.+--+-- The DynFlags can be modified by phases in the pipeline (eg. by+-- OPTIONS_GHC pragmas), and the changes affect later phases in the+-- pipeline.+runPipeline+ :: Phase -- ^ When to stop+ -> HscEnv -- ^ Compilation environment+ -> (FilePath,Maybe PhasePlus) -- ^ Input filename (and maybe -x suffix)+ -> Maybe FilePath -- ^ original basename (if different from ^^^)+ -> PipelineOutput -- ^ Output filename+ -> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module+ -> [FilePath] -- ^ foreign objects+ -> IO (DynFlags, FilePath) -- ^ (final flags, output filename)+runPipeline stop_phase hsc_env0 (input_fn, mb_phase)+ mb_basename output maybe_loc foreign_os++ = do let+ dflags0 = hsc_dflags hsc_env0++ -- Decide where dump files should go based on the pipeline output+ dflags = dflags0 { dumpPrefix = Just (basename ++ ".") }+ hsc_env = hsc_env0 {hsc_dflags = dflags}++ (input_basename, suffix) = splitExtension input_fn+ suffix' = drop 1 suffix -- strip off the .+ basename | Just b <- mb_basename = b+ | otherwise = input_basename++ -- If we were given a -x flag, then use that phase to start from+ start_phase = fromMaybe (RealPhase (startPhase suffix')) mb_phase++ isHaskell (RealPhase (Unlit _)) = True+ isHaskell (RealPhase (Cpp _)) = True+ isHaskell (RealPhase (HsPp _)) = True+ isHaskell (RealPhase (Hsc _)) = True+ isHaskell (HscOut {}) = True+ isHaskell _ = False++ isHaskellishFile = isHaskell start_phase++ env = PipeEnv{ stop_phase,+ src_filename = input_fn,+ src_basename = basename,+ src_suffix = suffix',+ output_spec = output }++ when (isBackpackishSuffix suffix') $+ throwGhcExceptionIO (UsageError+ ("use --backpack to process " ++ input_fn))++ -- We want to catch cases of "you can't get there from here" before+ -- we start the pipeline, because otherwise it will just run off the+ -- end.+ let happensBefore' = happensBefore dflags+ case start_phase of+ RealPhase start_phase' ->+ -- See Note [Partial ordering on phases]+ -- Not the same as: (stop_phase `happensBefore` start_phase')+ when (not (start_phase' `happensBefore'` stop_phase ||+ start_phase' `eqPhase` stop_phase)) $+ throwGhcExceptionIO (UsageError+ ("cannot compile this file to desired target: "+ ++ input_fn))+ HscOut {} -> return ()++ debugTraceMsg dflags 4 (text "Running the pipeline")+ r <- runPipeline' start_phase hsc_env env input_fn+ maybe_loc foreign_os++ -- If we are compiling a Haskell module, and doing+ -- -dynamic-too, but couldn't do the -dynamic-too fast+ -- path, then rerun the pipeline for the dyn way+ let dflags = hsc_dflags hsc_env+ -- NB: Currently disabled on Windows (ref #7134, #8228, and #5987)+ when (not $ platformOS (targetPlatform dflags) == OSMinGW32) $ do+ when isHaskellishFile $ whenCannotGenerateDynamicToo dflags $ do+ debugTraceMsg dflags 4+ (text "Running the pipeline again for -dynamic-too")+ let dflags' = dynamicTooMkDynamicDynFlags dflags+ hsc_env' <- newHscEnv dflags'+ _ <- runPipeline' start_phase hsc_env' env input_fn+ maybe_loc foreign_os+ return ()+ return r++runPipeline'+ :: PhasePlus -- ^ When to start+ -> HscEnv -- ^ Compilation environment+ -> PipeEnv+ -> FilePath -- ^ Input filename+ -> Maybe ModLocation -- ^ A ModLocation, if this is a Haskell module+ -> [FilePath] -- ^ foreign objects, if we have one+ -> IO (DynFlags, FilePath) -- ^ (final flags, output filename)+runPipeline' start_phase hsc_env env input_fn+ maybe_loc foreign_os+ = do+ -- Execute the pipeline...+ let state = PipeState{ hsc_env, maybe_loc, foreign_os = foreign_os }++ evalP (pipeLoop start_phase input_fn) env state++-- ---------------------------------------------------------------------------+-- outer pipeline loop++-- | pipeLoop runs phases until we reach the stop phase+pipeLoop :: PhasePlus -> FilePath -> CompPipeline (DynFlags, FilePath)+pipeLoop phase input_fn = do+ env <- getPipeEnv+ dflags <- getDynFlags+ -- See Note [Partial ordering on phases]+ let happensBefore' = happensBefore dflags+ stopPhase = stop_phase env+ case phase of+ RealPhase realPhase | realPhase `eqPhase` stopPhase -- All done+ -> -- Sometimes, a compilation phase doesn't actually generate any output+ -- (eg. the CPP phase when -fcpp is not turned on). If we end on this+ -- stage, but we wanted to keep the output, then we have to explicitly+ -- copy the file, remembering to prepend a {-# LINE #-} pragma so that+ -- further compilation stages can tell what the original filename was.+ case output_spec env of+ Temporary ->+ return (dflags, input_fn)+ output ->+ do pst <- getPipeState+ final_fn <- liftIO $ getOutputFilename+ stopPhase output (src_basename env)+ dflags stopPhase (maybe_loc pst)+ when (final_fn /= input_fn) $ do+ let msg = ("Copying `" ++ input_fn ++"' to `" ++ final_fn ++ "'")+ line_prag = Just ("{-# LINE 1 \"" ++ src_filename env ++ "\" #-}\n")+ liftIO $ copyWithHeader dflags msg line_prag input_fn final_fn+ return (dflags, final_fn)+++ | not (realPhase `happensBefore'` stopPhase)+ -- Something has gone wrong. We'll try to cover all the cases when+ -- this could happen, so if we reach here it is a panic.+ -- eg. it might happen if the -C flag is used on a source file that+ -- has {-# OPTIONS -fasm #-}.+ -> panic ("pipeLoop: at phase " ++ show realPhase +++ " but I wanted to stop at phase " ++ show stopPhase)++ _+ -> do liftIO $ debugTraceMsg dflags 4+ (text "Running phase" <+> ppr phase)+ (next_phase, output_fn) <- runHookedPhase phase input_fn dflags+ r <- pipeLoop next_phase output_fn+ case phase of+ HscOut {} ->+ whenGeneratingDynamicToo dflags $ do+ setDynFlags $ dynamicTooMkDynamicDynFlags dflags+ -- TODO shouldn't ignore result:+ _ <- pipeLoop phase input_fn+ return ()+ _ ->+ return ()+ return r++runHookedPhase :: PhasePlus -> FilePath -> DynFlags+ -> CompPipeline (PhasePlus, FilePath)+runHookedPhase pp input dflags =+ lookupHook runPhaseHook runPhase dflags pp input dflags++-- -----------------------------------------------------------------------------+-- In each phase, we need to know into what filename to generate the+-- output. All the logic about which filenames we generate output+-- into is embodied in the following function.++-- | Computes the next output filename after we run @next_phase@.+-- Like 'getOutputFilename', but it operates in the 'CompPipeline' monad+-- (which specifies all of the ambient information.)+phaseOutputFilename :: Phase{-next phase-} -> CompPipeline FilePath+phaseOutputFilename next_phase = do+ PipeEnv{stop_phase, src_basename, output_spec} <- getPipeEnv+ PipeState{maybe_loc, hsc_env} <- getPipeState+ let dflags = hsc_dflags hsc_env+ liftIO $ getOutputFilename stop_phase output_spec+ src_basename dflags next_phase maybe_loc++-- | Computes the next output filename for something in the compilation+-- pipeline. This is controlled by several variables:+--+-- 1. 'Phase': the last phase to be run (e.g. 'stopPhase'). This+-- is used to tell if we're in the last phase or not, because+-- in that case flags like @-o@ may be important.+-- 2. 'PipelineOutput': is this intended to be a 'Temporary' or+-- 'Persistent' build output? Temporary files just go in+-- a fresh temporary name.+-- 3. 'String': what was the basename of the original input file?+-- 4. 'DynFlags': the obvious thing+-- 5. 'Phase': the phase we want to determine the output filename of.+-- 6. @Maybe ModLocation@: the 'ModLocation' of the module we're+-- compiling; this can be used to override the default output+-- of an object file. (TODO: do we actually need this?)+getOutputFilename+ :: Phase -> PipelineOutput -> String+ -> DynFlags -> Phase{-next phase-} -> Maybe ModLocation -> IO FilePath+getOutputFilename stop_phase output basename dflags next_phase maybe_location+ | 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"+ | keep_this_output = persistent_fn+ | otherwise = newTempName dflags suffix+ where+ hcsuf = hcSuf dflags+ odir = objectDir dflags+ osuf = objectSuf dflags+ keep_hc = gopt Opt_KeepHcFiles dflags+ keep_s = gopt Opt_KeepSFiles dflags+ keep_bc = gopt Opt_KeepLlvmFiles dflags++ myPhaseInputExt HCc = hcsuf+ myPhaseInputExt MergeForeign = osuf+ myPhaseInputExt StopLn = osuf+ myPhaseInputExt other = phaseInputExt other++ is_last_phase = next_phase `eqPhase` stop_phase++ -- sometimes, we keep output from intermediate stages+ keep_this_output =+ case next_phase of+ As _ | keep_s -> True+ LlvmOpt | keep_bc -> True+ HCc | keep_hc -> True+ _other -> False++ suffix = myPhaseInputExt next_phase++ -- persistent object files get put in odir+ persistent_fn+ | StopLn <- next_phase = return odir_persistent+ | otherwise = return persistent++ persistent = basename <.> suffix++ odir_persistent+ | Just loc <- maybe_location = ml_obj_file loc+ | Just d <- odir = d </> persistent+ | otherwise = persistent++-- -----------------------------------------------------------------------------+-- | Each phase in the pipeline returns the next phase to execute, and the+-- name of the file in which the output was placed.+--+-- We must do things dynamically this way, because we often don't know+-- what the rest of the phases will be until part-way through the+-- compilation: for example, an {-# OPTIONS -fasm #-} at the beginning+-- of a source file can change the latter stages of the pipeline from+-- taking the LLVM route to using the native code generator.+--+runPhase :: PhasePlus -- ^ Run this phase+ -> FilePath -- ^ name of the input file+ -> DynFlags -- ^ for convenience, we pass the current dflags in+ -> CompPipeline (PhasePlus, -- next phase to run+ FilePath) -- output filename++ -- Invariant: the output filename always contains the output+ -- Interesting case: Hsc when there is no recompilation to do+ -- Then the output filename is still a .o file+++-------------------------------------------------------------------------------+-- Unlit phase++runPhase (RealPhase (Unlit sf)) input_fn dflags+ = do+ output_fn <- phaseOutputFilename (Cpp sf)++ let flags = [ -- The -h option passes the file name for unlit to+ -- put in a #line directive+ SysTools.Option "-h"+ -- See Note [Don't normalise input filenames].+ , SysTools.Option $ escape input_fn+ , SysTools.FileOption "" input_fn+ , SysTools.FileOption "" output_fn+ ]++ liftIO $ SysTools.runUnlit dflags flags++ return (RealPhase (Cpp sf), output_fn)+ where+ -- escape the characters \, ", and ', but don't try to escape+ -- Unicode or anything else (so we don't use Util.charToC+ -- here). If we get this wrong, then in+ -- Coverage.isGoodTickSrcSpan where we check that the filename in+ -- a SrcLoc is the same as the source filenaame, the two will+ -- look bogusly different. See test:+ -- libraries/hpc/tests/function/subdir/tough2.hs+ escape ('\\':cs) = '\\':'\\': escape cs+ escape ('\"':cs) = '\\':'\"': escape cs+ escape ('\'':cs) = '\\':'\'': escape cs+ escape (c:cs) = c : escape cs+ escape [] = []++-------------------------------------------------------------------------------+-- Cpp phase : (a) gets OPTIONS out of file+-- (b) runs cpp if necessary++runPhase (RealPhase (Cpp sf)) input_fn dflags0+ = do+ src_opts <- liftIO $ getOptionsFromFile dflags0 input_fn+ (dflags1, unhandled_flags, warns)+ <- liftIO $ parseDynamicFilePragma dflags0 src_opts+ setDynFlags dflags1+ liftIO $ checkProcessArgsResult dflags1 unhandled_flags++ if not (xopt LangExt.Cpp dflags1) then do+ -- we have to be careful to emit warnings only once.+ unless (gopt Opt_Pp dflags1) $+ liftIO $ handleFlagWarnings dflags1 warns++ -- no need to preprocess CPP, just pass input file along+ -- to the next phase of the pipeline.+ return (RealPhase (HsPp sf), input_fn)+ else do+ output_fn <- phaseOutputFilename (HsPp sf)+ liftIO $ doCpp dflags1 True{-raw-}+ input_fn output_fn+ -- re-read the pragmas now that we've preprocessed the file+ -- See #2464,#3457+ src_opts <- liftIO $ getOptionsFromFile dflags0 output_fn+ (dflags2, unhandled_flags, warns)+ <- liftIO $ parseDynamicFilePragma dflags0 src_opts+ liftIO $ checkProcessArgsResult dflags2 unhandled_flags+ unless (gopt Opt_Pp dflags2) $+ liftIO $ handleFlagWarnings dflags2 warns+ -- the HsPp pass below will emit warnings++ setDynFlags dflags2++ return (RealPhase (HsPp sf), output_fn)++-------------------------------------------------------------------------------+-- HsPp phase++runPhase (RealPhase (HsPp sf)) input_fn dflags+ = do+ if not (gopt Opt_Pp dflags) then+ -- no need to preprocess, just pass input file along+ -- to the next phase of the pipeline.+ return (RealPhase (Hsc sf), input_fn)+ else do+ PipeEnv{src_basename, src_suffix} <- getPipeEnv+ let orig_fn = src_basename <.> src_suffix+ output_fn <- phaseOutputFilename (Hsc sf)+ liftIO $ SysTools.runPp dflags+ ( [ SysTools.Option orig_fn+ , SysTools.Option input_fn+ , SysTools.FileOption "" output_fn+ ]+ )++ -- re-read pragmas now that we've parsed the file (see #3674)+ src_opts <- liftIO $ getOptionsFromFile dflags output_fn+ (dflags1, unhandled_flags, warns)+ <- liftIO $ parseDynamicFilePragma dflags src_opts+ setDynFlags dflags1+ liftIO $ checkProcessArgsResult dflags1 unhandled_flags+ liftIO $ handleFlagWarnings dflags1 warns++ return (RealPhase (Hsc sf), output_fn)++-----------------------------------------------------------------------------+-- Hsc phase++-- Compilation of a single module, in "legacy" mode (_not_ under+-- the direction of the compilation manager).+runPhase (RealPhase (Hsc src_flavour)) input_fn dflags0+ = do -- normal Hsc mode, not mkdependHS++ PipeEnv{ stop_phase=stop,+ src_basename=basename,+ src_suffix=suff } <- getPipeEnv++ -- we add the current directory (i.e. the directory in which+ -- the .hs files resides) to the include path, since this is+ -- what gcc does, and it's probably what you want.+ let current_dir = takeDirectory basename+ paths = includePaths dflags0+ dflags = dflags0 { includePaths = current_dir : paths }++ setDynFlags dflags++ -- gather the imports and module name+ (hspp_buf,mod_name,imps,src_imps) <- liftIO $ do+ do+ buf <- hGetStringBuffer input_fn+ (src_imps,imps,L _ mod_name) <- getImports dflags buf input_fn (basename <.> suff)+ return (Just buf, mod_name, imps, src_imps)++ -- 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 src_flavour mod_name++ let o_file = ml_obj_file location -- The real object file+ hi_file = ml_hi_file location+ dest_file | writeInterfaceOnlyMode dflags+ = hi_file+ | otherwise+ = o_file++ -- Figure out if the source has changed, for recompilation avoidance.+ --+ -- Setting source_unchanged to True means that M.o seems+ -- to be up to date wrt M.hs; so no need to recompile unless imports have+ -- changed (which the compiler itself figures out).+ -- Setting source_unchanged to False tells the compiler that M.o is out of+ -- date wrt M.hs (or M.o doesn't exist) so we must recompile regardless.+ src_timestamp <- liftIO $ getModificationUTCTime (basename <.> suff)++ source_unchanged <- liftIO $+ if not (isStopLn stop)+ -- SourceModified unconditionally if+ -- (a) recompilation checker is off, or+ -- (b) we aren't going all the way to .o file (e.g. ghc -S)+ then return SourceModified+ -- Otherwise look at file modification dates+ else do dest_file_exists <- doesFileExist dest_file+ if not dest_file_exists+ then return SourceModified -- Need to recompile+ else do t2 <- getModificationUTCTime dest_file+ if t2 > src_timestamp+ then return SourceUnmodified+ else return SourceModified++ PipeState{hsc_env=hsc_env'} <- getPipeState++ -- Tell the finder cache about this module+ mod <- liftIO $ addHomeModuleToFinder hsc_env' mod_name location++ -- Make the ModSummary to hand to hscMain+ let+ mod_summary = ModSummary { ms_mod = mod,+ ms_hsc_src = src_flavour,+ ms_hspp_file = input_fn,+ ms_hspp_opts = dflags,+ ms_hspp_buf = hspp_buf,+ ms_location = location,+ ms_hs_date = src_timestamp,+ ms_obj_date = Nothing,+ ms_parsed_mod = Nothing,+ ms_iface_date = Nothing,+ ms_textual_imps = imps,+ ms_srcimps = src_imps }++ -- run the compiler!+ let msg hsc_env _ what _ = oneShotMsg hsc_env what+ (result, _) <- liftIO $ hscIncrementalCompile True Nothing (Just msg) hsc_env'+ mod_summary source_unchanged Nothing (1,1)++ return (HscOut src_flavour mod_name result,+ panic "HscOut doesn't have an input filename")++runPhase (HscOut src_flavour mod_name result) _ dflags = do+ location <- getLocation src_flavour mod_name+ setModLocation location++ let o_file = ml_obj_file location -- The real object file+ hsc_lang = hscTarget dflags+ next_phase = hscPostBackendPhase dflags src_flavour hsc_lang++ case result of+ HscNotGeneratingCode ->+ return (RealPhase StopLn,+ panic "No output filename from Hsc when no-code")+ HscUpToDate ->+ do liftIO $ touchObjectFile dflags o_file+ -- The .o file must have a later modification date+ -- than the source file (else we wouldn't get Nothing)+ -- but we touch it anyway, to keep 'make' happy (we think).+ return (RealPhase StopLn, o_file)+ HscUpdateBoot ->+ do -- In the case of hs-boot files, generate a dummy .o-boot+ -- stamp file for the benefit of Make+ liftIO $ touchObjectFile dflags o_file+ return (RealPhase StopLn, o_file)+ HscUpdateSig ->+ do -- We need to create a REAL but empty .o file+ -- because we are going to attempt to put it in a library+ PipeState{hsc_env=hsc_env'} <- getPipeState+ let input_fn = expectJust "runPhase" (ml_hs_file location)+ basename = dropExtension input_fn+ liftIO $ compileEmptyStub dflags hsc_env' basename location mod_name+ return (RealPhase StopLn, o_file)+ HscRecomp cgguts mod_summary+ -> do output_fn <- phaseOutputFilename next_phase++ PipeState{hsc_env=hsc_env'} <- getPipeState++ (outputFilename, mStub, foreign_files) <- liftIO $+ hscGenHardCode hsc_env' cgguts mod_summary output_fn+ stub_o <- liftIO (mapM (compileStub hsc_env') mStub)+ foreign_os <- liftIO $+ mapM (uncurry (compileForeign hsc_env')) foreign_files+ setForeignOs (maybe [] return stub_o ++ foreign_os)++ return (RealPhase next_phase, outputFilename)++-----------------------------------------------------------------------------+-- Cmm phase++runPhase (RealPhase CmmCpp) input_fn dflags+ = do+ output_fn <- phaseOutputFilename Cmm+ liftIO $ doCpp dflags False{-not raw-}+ input_fn output_fn+ return (RealPhase Cmm, output_fn)++runPhase (RealPhase Cmm) input_fn dflags+ = do+ let hsc_lang = hscTarget dflags++ let next_phase = hscPostBackendPhase dflags HsSrcFile hsc_lang++ output_fn <- phaseOutputFilename next_phase++ PipeState{hsc_env} <- getPipeState++ liftIO $ hscCompileCmmFile hsc_env input_fn output_fn++ return (RealPhase next_phase, output_fn)++-----------------------------------------------------------------------------+-- Cc phase++-- we don't support preprocessing .c files (with -E) now. Doing so introduces+-- way too many hacks, and I can't say I've ever used it anyway.++runPhase (RealPhase cc_phase) input_fn dflags+ | any (cc_phase `eqPhase`) [Cc, Ccxx, HCc, Cobjc, Cobjcxx]+ = do+ let platform = targetPlatform dflags+ hcc = cc_phase `eqPhase` HCc++ let cmdline_include_paths = includePaths dflags++ -- HC files have the dependent packages stamped into them+ pkgs <- if hcc then liftIO $ getHCFilePackages input_fn else return []++ -- add package include paths even if we're just compiling .c+ -- files; this is the Value Add(TM) that using ghc instead of+ -- gcc gives you :)+ pkg_include_dirs <- liftIO $ getPackageIncludePath dflags pkgs+ let include_paths = foldr (\ x xs -> ("-I" ++ x) : xs) []+ (cmdline_include_paths ++ pkg_include_dirs)++ let gcc_extra_viac_flags = extraGccViaCFlags dflags+ let pic_c_flags = picCCOpts dflags++ let verbFlags = getVerbFlags dflags++ -- cc-options are not passed when compiling .hc files. Our+ -- hc code doesn't not #include any header files anyway, so these+ -- options aren't necessary.+ pkg_extra_cc_opts <- liftIO $+ if cc_phase `eqPhase` HCc+ then return []+ else getPackageExtraCcOpts dflags pkgs++ framework_paths <-+ if platformUsesFrameworks platform+ then do pkgFrameworkPaths <- liftIO $ getPackageFrameworkPath dflags pkgs+ let cmdlineFrameworkPaths = frameworkPaths dflags+ return $ map ("-F"++)+ (cmdlineFrameworkPaths ++ pkgFrameworkPaths)+ else return []++ let split_objs = gopt Opt_SplitObjs dflags+ split_opt | hcc && split_objs = [ "-DUSE_SPLIT_MARKERS" ]+ | otherwise = [ ]++ let cc_opt | optLevel dflags >= 2 = [ "-O2" ]+ | optLevel dflags >= 1 = [ "-O" ]+ | otherwise = []++ -- Decide next phase+ let next_phase = As False+ output_fn <- phaseOutputFilename next_phase++ let+ more_hcc_opts =+ -- on x86 the floating point regs have greater precision+ -- than a double, which leads to unpredictable results.+ -- By default, we turn this off with -ffloat-store unless+ -- the user specified -fexcess-precision.+ (if platformArch platform == ArchX86 &&+ not (gopt Opt_ExcessPrecision dflags)+ then [ "-ffloat-store" ]+ else []) ++++ -- gcc's -fstrict-aliasing allows two accesses to memory+ -- to be considered non-aliasing if they have different types.+ -- This interacts badly with the C code we generate, which is+ -- very weakly typed, being derived from C--.+ ["-fno-strict-aliasing"]++ ghcVersionH <- liftIO $ getGhcVersionPathName dflags++ let gcc_lang_opt | cc_phase `eqPhase` Ccxx = "c++"+ | cc_phase `eqPhase` Cobjc = "objective-c"+ | cc_phase `eqPhase` Cobjcxx = "objective-c++"+ | otherwise = "c"+ liftIO $ SysTools.runCc dflags (+ -- force the C compiler to interpret this file as C when+ -- compiling .hc files, by adding the -x c option.+ -- Also useful for plain .c files, just in case GHC saw a+ -- -x c option.+ [ SysTools.Option "-x", SysTools.Option gcc_lang_opt+ , SysTools.FileOption "" input_fn+ , SysTools.Option "-o"+ , SysTools.FileOption "" output_fn+ ]+ ++ map SysTools.Option (+ pic_c_flags++ -- Stub files generated for foreign exports references the runIO_closure+ -- and runNonIO_closure symbols, which are defined in the base package.+ -- These symbols are imported into the stub.c file via RtsAPI.h, and the+ -- way we do the import depends on whether we're currently compiling+ -- the base package or not.+ ++ (if platformOS platform == OSMinGW32 &&+ thisPackage dflags == baseUnitId+ then [ "-DCOMPILING_BASE_PACKAGE" ]+ else [])++ -- We only support SparcV9 and better because V8 lacks an atomic CAS+ -- instruction. Note that the user can still override this+ -- (e.g., -mcpu=ultrasparc) as GCC picks the "best" -mcpu flag+ -- regardless of the ordering.+ --+ -- This is a temporary hack. See #2872, commit+ -- 5bd3072ac30216a505151601884ac88bf404c9f2+ ++ (if platformArch platform == ArchSPARC+ then ["-mcpu=v9"]+ else [])++ -- GCC 4.6+ doesn't like -Wimplicit when compiling C++.+ ++ (if (cc_phase /= Ccxx && cc_phase /= Cobjcxx)+ then ["-Wimplicit"]+ else [])++ ++ (if hcc+ then gcc_extra_viac_flags ++ more_hcc_opts+ else [])+ ++ verbFlags+ ++ [ "-S" ]+ ++ cc_opt+ ++ [ "-include", ghcVersionH ]+ ++ framework_paths+ ++ split_opt+ ++ include_paths+ ++ pkg_extra_cc_opts+ ))++ return (RealPhase next_phase, output_fn)++-----------------------------------------------------------------------------+-- Splitting phase++runPhase (RealPhase Splitter) input_fn dflags+ = do -- tmp_pfx is the prefix used for the split .s files++ split_s_prefix <- liftIO $ SysTools.newTempName dflags "split"+ let n_files_fn = split_s_prefix++ liftIO $ SysTools.runSplit dflags+ [ SysTools.FileOption "" input_fn+ , SysTools.FileOption "" split_s_prefix+ , SysTools.FileOption "" n_files_fn+ ]++ -- Save the number of split files for future references+ s <- liftIO $ readFile n_files_fn+ let n_files = read s :: Int+ dflags' = dflags { splitInfo = Just (split_s_prefix, n_files) }++ setDynFlags dflags'++ -- Remember to delete all these files+ liftIO $ addFilesToClean dflags'+ [ split_s_prefix ++ "__" ++ show n ++ ".s"+ | n <- [1..n_files]]++ return (RealPhase SplitAs,+ "**splitter**") -- we don't use the filename in SplitAs++-----------------------------------------------------------------------------+-- As, SpitAs phase : Assembler++-- This is for calling the assembler on a regular assembly file (not split).+runPhase (RealPhase (As with_cpp)) input_fn dflags+ = do+ -- LLVM from version 3.0 onwards doesn't support the OS X system+ -- assembler, so we use clang as the assembler instead. (#5636)+ let whichAsProg | hscTarget dflags == HscLlvm &&+ platformOS (targetPlatform dflags) == OSDarwin+ = return SysTools.runClang+ | otherwise = return SysTools.runAs++ as_prog <- whichAsProg+ let cmdline_include_paths = includePaths dflags+ let pic_c_flags = picCCOpts dflags++ next_phase <- maybeMergeForeign+ output_fn <- phaseOutputFilename next_phase++ -- we create directories for the object file, because it+ -- might be a hierarchical module.+ liftIO $ createDirectoryIfMissing True (takeDirectory output_fn)++ ccInfo <- liftIO $ getCompilerInfo dflags+ let runAssembler inputFilename outputFilename+ = liftIO $ as_prog dflags+ ([ SysTools.Option ("-I" ++ p) | p <- cmdline_include_paths ]++ -- See Note [-fPIC for assembler]+ ++ map SysTools.Option pic_c_flags++ -- We only support SparcV9 and better because V8 lacks an atomic CAS+ -- instruction so we have to make sure that the assembler accepts the+ -- instruction set. Note that the user can still override this+ -- (e.g., -mcpu=ultrasparc). GCC picks the "best" -mcpu flag+ -- regardless of the ordering.+ --+ -- This is a temporary hack.+ ++ (if platformArch (targetPlatform dflags) == ArchSPARC+ then [SysTools.Option "-mcpu=v9"]+ else [])+ ++ (if any (ccInfo ==) [Clang, AppleClang, AppleClang51]+ then [SysTools.Option "-Qunused-arguments"]+ else [])+ ++ [ SysTools.Option "-x"+ , if with_cpp+ then SysTools.Option "assembler-with-cpp"+ else SysTools.Option "assembler"+ , SysTools.Option "-c"+ , SysTools.FileOption "" inputFilename+ , SysTools.Option "-o"+ , SysTools.FileOption "" outputFilename+ ])++ liftIO $ debugTraceMsg dflags 4 (text "Running the assembler")+ runAssembler input_fn output_fn+ return (RealPhase next_phase, output_fn)+++-- This is for calling the assembler on a split assembly file (so a collection+-- of assembly files)+runPhase (RealPhase SplitAs) _input_fn dflags+ = do+ -- we'll handle the stub_o file in this phase, so don't MergeForeign,+ -- just jump straight to StopLn afterwards.+ let next_phase = StopLn+ output_fn <- phaseOutputFilename next_phase++ let base_o = dropExtension output_fn+ osuf = objectSuf dflags+ split_odir = base_o ++ "_" ++ osuf ++ "_split"++ let pic_c_flags = picCCOpts dflags++ -- this also creates the hierarchy+ liftIO $ createDirectoryIfMissing True split_odir++ -- remove M_split/ *.o, because we're going to archive M_split/ *.o+ -- later and we don't want to pick up any old objects.+ fs <- liftIO $ getDirectoryContents split_odir+ liftIO $ mapM_ removeFile $+ map (split_odir </>) $ filter (osuf `isSuffixOf`) fs++ let (split_s_prefix, n) = case splitInfo dflags of+ Nothing -> panic "No split info"+ Just x -> x++ let split_s n = split_s_prefix ++ "__" ++ show n <.> "s"++ split_obj :: Int -> FilePath+ split_obj n = split_odir </>+ takeFileName base_o ++ "__" ++ show n <.> osuf++ let assemble_file n+ = SysTools.runAs dflags (++ -- We only support SparcV9 and better because V8 lacks an atomic CAS+ -- instruction so we have to make sure that the assembler accepts the+ -- instruction set. Note that the user can still override this+ -- (e.g., -mcpu=ultrasparc). GCC picks the "best" -mcpu flag+ -- regardless of the ordering.+ --+ -- This is a temporary hack.+ (if platformArch (targetPlatform dflags) == ArchSPARC+ then [SysTools.Option "-mcpu=v9"]+ else []) ++++ -- See Note [-fPIC for assembler]+ map SysTools.Option pic_c_flags ++++ [ SysTools.Option "-c"+ , SysTools.Option "-o"+ , SysTools.FileOption "" (split_obj n)+ , SysTools.FileOption "" (split_s n)+ ])++ liftIO $ mapM_ assemble_file [1..n]++ -- Note [pipeline-split-init]+ -- If we have a stub file -- which will be part of foreign_os --+ -- it may contain constructor+ -- functions for initialisation of this module. We can't+ -- simply leave the stub as a separate object file, because it+ -- will never be linked in: nothing refers to it. We need to+ -- ensure that if we ever refer to the data in this module+ -- that needs initialisation, then we also pull in the+ -- initialisation routine.+ --+ -- To that end, we make a DANGEROUS ASSUMPTION here: the data+ -- that needs to be initialised is all in the FIRST split+ -- object. See Note [codegen-split-init].+ --+ -- We also merge in all the foreign objects since we're at it.++ PipeState{foreign_os} <- getPipeState+ if null foreign_os+ then return ()+ else liftIO $ do+ tmp_split_1 <- newTempName dflags osuf+ let split_1 = split_obj 1+ copyFile split_1 tmp_split_1+ removeFile split_1+ joinObjectFiles dflags (tmp_split_1 : foreign_os) split_1++ -- join them into a single .o file+ liftIO $ joinObjectFiles dflags (map split_obj [1..n]) output_fn++ return (RealPhase next_phase, output_fn)++-----------------------------------------------------------------------------+-- LlvmOpt phase++runPhase (RealPhase LlvmOpt) input_fn dflags+ = do+ let opt_lvl = max 0 (min 2 $ optLevel dflags)+ -- don't specify anything if user has specified commands. We do this+ -- for opt but not llc since opt is very specifically for optimisation+ -- passes only, so if the user is passing us extra options we assume+ -- they know what they are doing and don't get in the way.+ optFlag = if null (getOpts dflags opt_lo)+ then map SysTools.Option $ words (llvmOpts !! opt_lvl)+ else []+ tbaa | gopt Opt_LlvmTBAA dflags = "--enable-tbaa=true"+ | otherwise = "--enable-tbaa=false"+++ output_fn <- phaseOutputFilename LlvmLlc++ liftIO $ SysTools.runLlvmOpt dflags+ ([ SysTools.FileOption "" input_fn,+ SysTools.Option "-o",+ SysTools.FileOption "" output_fn]+ ++ optFlag+ ++ [SysTools.Option tbaa])++ return (RealPhase LlvmLlc, output_fn)+ where+ -- we always (unless -optlo specified) run Opt since we rely on it to+ -- fix up some pretty big deficiencies in the code we generate+ llvmOpts = [ "-mem2reg -globalopt"+ , "-O1 -globalopt"+ , "-O2"+ ]++-----------------------------------------------------------------------------+-- LlvmLlc phase++runPhase (RealPhase LlvmLlc) input_fn dflags+ = do+ let opt_lvl = max 0 (min 2 $ optLevel dflags)+ -- iOS requires external references to be loaded indirectly from the+ -- DATA segment or dyld traps at runtime writing into TEXT: see #7722+ rmodel | platformOS (targetPlatform dflags) == OSiOS = "dynamic-no-pic"+ | gopt Opt_PIC dflags = "pic"+ | WayDyn `elem` ways dflags = "dynamic-no-pic"+ | otherwise = "static"+ tbaa | gopt Opt_LlvmTBAA dflags = "--enable-tbaa=true"+ | otherwise = "--enable-tbaa=false"++ -- hidden debugging flag '-dno-llvm-mangler' to skip mangling+ let next_phase = case gopt Opt_NoLlvmMangler dflags of+ False -> LlvmMangle+ True | gopt Opt_SplitObjs dflags -> Splitter+ True -> As False++ output_fn <- phaseOutputFilename next_phase++ liftIO $ SysTools.runLlvmLlc dflags+ ([ SysTools.Option (llvmOpts !! opt_lvl),+ SysTools.Option $ "-relocation-model=" ++ rmodel,+ SysTools.FileOption "" input_fn,+ SysTools.Option "-o", SysTools.FileOption "" output_fn]+ ++ [SysTools.Option tbaa]+ ++ map SysTools.Option fpOpts+ ++ map SysTools.Option abiOpts+ ++ map SysTools.Option sseOpts+ ++ map SysTools.Option avxOpts+ ++ map SysTools.Option avx512Opts+ ++ map SysTools.Option stackAlignOpts)++ return (RealPhase next_phase, output_fn)+ where+ -- Bug in LLVM at O3 on OSX.+ llvmOpts = if platformOS (targetPlatform dflags) == OSDarwin+ then ["-O1", "-O2", "-O2"]+ else ["-O1", "-O2", "-O3"]+ -- On ARMv7 using LLVM, LLVM fails to allocate floating point registers+ -- while compiling GHC source code. It's probably due to fact that it+ -- does not enable VFP by default. Let's do this manually here+ fpOpts = case platformArch (targetPlatform dflags) of+ ArchARM ARMv7 ext _ -> if (elem VFPv3 ext)+ then ["-mattr=+v7,+vfp3"]+ else if (elem VFPv3D16 ext)+ then ["-mattr=+v7,+vfp3,+d16"]+ else []+ ArchARM ARMv6 ext _ -> if (elem VFPv2 ext)+ then ["-mattr=+v6,+vfp2"]+ else ["-mattr=+v6"]+ _ -> []+ -- On Ubuntu/Debian with ARM hard float ABI, LLVM's llc still+ -- compiles into soft-float ABI. We need to explicitly set abi+ -- to hard+ abiOpts = case platformArch (targetPlatform dflags) of+ ArchARM _ _ HARD -> ["-float-abi=hard"]+ ArchARM _ _ _ -> []+ _ -> []++ sseOpts | isSse4_2Enabled dflags = ["-mattr=+sse42"]+ | isSse2Enabled dflags = ["-mattr=+sse2"]+ | isSseEnabled dflags = ["-mattr=+sse"]+ | otherwise = []++ avxOpts | isAvx512fEnabled dflags = ["-mattr=+avx512f"]+ | isAvx2Enabled dflags = ["-mattr=+avx2"]+ | isAvxEnabled dflags = ["-mattr=+avx"]+ | otherwise = []++ avx512Opts =+ [ "-mattr=+avx512cd" | isAvx512cdEnabled dflags ] +++ [ "-mattr=+avx512er" | isAvx512erEnabled dflags ] +++ [ "-mattr=+avx512pf" | isAvx512pfEnabled dflags ]++ stackAlignOpts =+ case platformArch (targetPlatform dflags) of+ ArchX86_64 | isAvxEnabled dflags -> ["-stack-alignment=32"]+ _ -> []++-----------------------------------------------------------------------------+-- LlvmMangle phase++runPhase (RealPhase LlvmMangle) input_fn dflags+ = do+ let next_phase = if gopt Opt_SplitObjs dflags then Splitter else As False+ output_fn <- phaseOutputFilename next_phase+ liftIO $ llvmFixupAsm dflags input_fn output_fn+ return (RealPhase next_phase, output_fn)++-----------------------------------------------------------------------------+-- merge in stub objects++runPhase (RealPhase MergeForeign) input_fn dflags+ = do+ PipeState{foreign_os} <- getPipeState+ output_fn <- phaseOutputFilename StopLn+ liftIO $ createDirectoryIfMissing True (takeDirectory output_fn)+ if null foreign_os+ then panic "runPhase(MergeForeign): no foreign objects"+ else do+ liftIO $ joinObjectFiles dflags (input_fn : foreign_os) output_fn+ return (RealPhase StopLn, output_fn)++-- warning suppression+runPhase (RealPhase other) _input_fn _dflags =+ panic ("runPhase: don't know how to run phase " ++ show other)++maybeMergeForeign :: CompPipeline Phase+maybeMergeForeign+ = do+ PipeState{foreign_os} <- getPipeState+ if null foreign_os then return StopLn else return MergeForeign++getLocation :: HscSource -> ModuleName -> CompPipeline ModLocation+getLocation src_flavour mod_name = do+ dflags <- getDynFlags++ PipeEnv{ src_basename=basename,+ src_suffix=suff } <- getPipeEnv++ -- Build a ModLocation to pass to hscMain.+ -- The source filename is rather irrelevant by now, but it's used+ -- by hscMain for messages. hscMain also needs+ -- the .hi and .o filenames, and this is as good a way+ -- as any to generate them, and better than most. (e.g. takes+ -- into account the -osuf flags)+ location1 <- liftIO $ mkHomeModLocation2 dflags mod_name basename suff++ -- Boot-ify it if necessary+ let location2 | HsBootFile <- src_flavour = addBootSuffixLocn 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++ -- 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+ location4 | Just ofile <- expl_o_file+ , isNoLink (ghcLink dflags)+ = location3 { ml_obj_file = ofile }+ | otherwise = location3++ return location4++mkExtraObj :: DynFlags -> Suffix -> String -> IO FilePath+mkExtraObj dflags extn xs+ = do cFile <- newTempName dflags extn+ oFile <- newTempName dflags "o"+ writeFile cFile xs+ ccInfo <- liftIO $ getCompilerInfo dflags+ SysTools.runCc dflags+ ([Option "-c",+ FileOption "" cFile,+ Option "-o",+ FileOption "" oFile]+ ++ if extn /= "s"+ then cOpts+ else asmOpts ccInfo)+ return oFile+ where+ -- Pass a different set of options to the C compiler depending one whether+ -- we're compiling C or assembler. When compiling C, we pass the usual+ -- set of include directories and PIC flags.+ cOpts = map Option (picCCOpts dflags)+ ++ map (FileOption "-I")+ (includeDirs $ getPackageDetails dflags rtsUnitId)++ -- When compiling assembler code, we drop the usual C options, and if the+ -- compiler is Clang, we add an extra argument to tell Clang to ignore+ -- unused command line options. See trac #11684.+ asmOpts ccInfo =+ if any (ccInfo ==) [Clang, AppleClang, AppleClang51]+ then [Option "-Qunused-arguments"]+ else []+++-- When linking a binary, we need to create a C main() function that+-- starts everything off. This used to be compiled statically as part+-- of the RTS, but that made it hard to change the -rtsopts setting,+-- so now we generate and compile a main() stub as part of every+-- binary and pass the -rtsopts setting directly to the RTS (#5373)+--+mkExtraObjToLinkIntoBinary :: DynFlags -> IO FilePath+mkExtraObjToLinkIntoBinary dflags = do+ when (gopt Opt_NoHsMain dflags && haveRtsOptsFlags dflags) $ do+ putLogMsg dflags NoReason SevInfo noSrcSpan+ (defaultUserStyle dflags)+ (text "Warning: -rtsopts and -with-rtsopts have no effect with -no-hs-main." $$+ text " Call hs_init_ghc() from your main() function to set these options.")++ mkExtraObj dflags "c" (showSDoc dflags main)++ where+ main+ | gopt Opt_NoHsMain dflags = Outputable.empty+ | otherwise = vcat [+ text "#include \"Rts.h\"",+ text "extern StgClosure ZCMain_main_closure;",+ text "int main(int argc, char *argv[])",+ char '{',+ text " RtsConfig __conf = defaultRtsConfig;",+ text " __conf.rts_opts_enabled = "+ <> text (show (rtsOptsEnabled dflags)) <> semi,+ text " __conf.rts_opts_suggestions = "+ <> text (if rtsOptsSuggestions dflags+ then "true"+ else "false") <> semi,+ case rtsOpts dflags of+ Nothing -> Outputable.empty+ Just opts -> text " __conf.rts_opts= " <>+ text (show opts) <> semi,+ text " __conf.rts_hs_main = true;",+ text " return hs_main(argc,argv,&ZCMain_main_closure,__conf);",+ char '}',+ char '\n' -- final newline, to keep gcc happy+ ]++-- Write out the link info section into a new assembly file. Previously+-- this was included as inline assembly in the main.c file but this+-- is pretty fragile. gas gets upset trying to calculate relative offsets+-- that span the .note section (notably .text) when debug info is present+mkNoteObjsToLinkIntoBinary :: DynFlags -> [InstalledUnitId] -> IO [FilePath]+mkNoteObjsToLinkIntoBinary dflags dep_packages = do+ link_info <- getLinkInfo dflags dep_packages++ if (platformSupportsSavingLinkOpts (platformOS (targetPlatform dflags)))+ then fmap (:[]) $ mkExtraObj dflags "s" (showSDoc dflags (link_opts link_info))+ else return []++ where+ link_opts info = hcat [+ -- "link info" section (see Note [LinkInfo section])+ makeElfNote dflags ghcLinkInfoSectionName ghcLinkInfoNoteName 0 info,++ -- ALL generated assembly must have this section to disable+ -- executable stacks. See also+ -- compiler/nativeGen/AsmCodeGen.hs for another instance+ -- where we need to do this.+ if platformHasGnuNonexecStack (targetPlatform dflags)+ then text ".section .note.GNU-stack,\"\",@progbits\n"+ else Outputable.empty+ ]++-- | Return the "link info" string+--+-- See Note [LinkInfo section]+getLinkInfo :: DynFlags -> [InstalledUnitId] -> IO String+getLinkInfo dflags dep_packages = do+ package_link_opts <- getPackageLinkOpts dflags dep_packages+ pkg_frameworks <- if platformUsesFrameworks (targetPlatform dflags)+ then getPackageFrameworks dflags dep_packages+ else return []+ let extra_ld_inputs = ldInputs dflags+ let+ link_info = (package_link_opts,+ pkg_frameworks,+ rtsOpts dflags,+ rtsOptsEnabled dflags,+ gopt Opt_NoHsMain dflags,+ map showOpt extra_ld_inputs,+ getOpts dflags opt_l)+ --+ return (show link_info)+++{- Note [LinkInfo section]+ ~~~~~~~~~~~~~~~~~~~~~~~++The "link info" is a string representing the parameters of the link. We save+this information in the binary, and the next time we link, if nothing else has+changed, we use the link info stored in the existing binary to decide whether+to re-link or not.++The "link info" string is stored in a ELF section called ".debug-ghc-link-info"+(see ghcLinkInfoSectionName) with the SHT_NOTE type. For some time, it used to+not follow the specified record-based format (see #11022).++-}+++-----------------------------------------------------------------------------+-- Look for the /* GHC_PACKAGES ... */ comment at the top of a .hc file++getHCFilePackages :: FilePath -> IO [InstalledUnitId]+getHCFilePackages filename =+ Exception.bracket (openFile filename ReadMode) hClose $ \h -> do+ l <- hGetLine h+ case l of+ '/':'*':' ':'G':'H':'C':'_':'P':'A':'C':'K':'A':'G':'E':'S':rest ->+ return (map stringToInstalledUnitId (words rest))+ _other ->+ return []++-----------------------------------------------------------------------------+-- Static linking, of .o files++-- The list of packages passed to link is the list of packages on+-- which this program depends, as discovered by the compilation+-- manager. It is combined with the list of packages that the user+-- specifies on the command line with -package flags.+--+-- In one-shot linking mode, we can't discover the package+-- dependencies (because we haven't actually done any compilation or+-- read any interface files), so the user must explicitly specify all+-- the packages.++{-+Note [-Xlinker -rpath vs -Wl,-rpath]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++-Wl takes a comma-separated list of options which in the case of+-Wl,-rpath -Wl,some,path,with,commas parses the the path with commas+as separate options.+Buck, the build system, produces paths with commas in them.++-Xlinker doesn't have this disadvantage and as far as I can tell+it is supported by both gcc and clang. Anecdotally nvcc supports+-Xlinker, but not -Wl.+-}++linkBinary :: DynFlags -> [FilePath] -> [InstalledUnitId] -> IO ()+linkBinary = linkBinary' False++linkBinary' :: Bool -> DynFlags -> [FilePath] -> [InstalledUnitId] -> IO ()+linkBinary' staticLink dflags o_files dep_packages = do+ let platform = targetPlatform dflags+ mySettings = settings dflags+ verbFlags = getVerbFlags dflags+ output_fn = exeFileName staticLink dflags++ -- get the full list of packages to link with, by combining the+ -- explicit packages with the auto packages and all of their+ -- dependencies, and eliminating duplicates.++ full_output_fn <- if isAbsolute output_fn+ then return output_fn+ else do d <- getCurrentDirectory+ return $ normalise (d </> output_fn)+ pkg_lib_paths <- getPackageLibraryPath dflags dep_packages+ let pkg_lib_path_opts = concatMap get_pkg_lib_path_opts pkg_lib_paths+ get_pkg_lib_path_opts l+ | osElfTarget (platformOS platform) &&+ dynLibLoader dflags == SystemDependent &&+ WayDyn `elem` ways dflags+ = let libpath = if gopt Opt_RelativeDynlibPaths dflags+ then "$ORIGIN" </>+ (l `makeRelativeTo` full_output_fn)+ else l+ -- See Note [-Xlinker -rpath vs -Wl,-rpath]+ rpath = if gopt Opt_RPath dflags+ then ["-Xlinker", "-rpath", "-Xlinker", libpath]+ else []+ -- Solaris 11's linker does not support -rpath-link option. It silently+ -- ignores it and then complains about next option which is -l<some+ -- dir> as being a directory and not expected object file, E.g+ -- ld: elf error: file+ -- /tmp/ghc-src/libraries/base/dist-install/build:+ -- elf_begin: I/O error: region read: Is a directory+ rpathlink = if (platformOS platform) == OSSolaris2+ then []+ else ["-Xlinker", "-rpath-link", "-Xlinker", l]+ in ["-L" ++ l] ++ rpathlink ++ rpath+ | osMachOTarget (platformOS platform) &&+ dynLibLoader dflags == SystemDependent &&+ WayDyn `elem` ways dflags &&+ gopt Opt_RPath dflags+ = let libpath = if gopt Opt_RelativeDynlibPaths dflags+ then "@loader_path" </>+ (l `makeRelativeTo` full_output_fn)+ else l+ in ["-L" ++ l] ++ ["-Xlinker", "-rpath", "-Xlinker", libpath]+ | otherwise = ["-L" ++ l]++ let+ dead_strip+ | gopt Opt_WholeArchiveHsLibs dflags = []+ | otherwise = if osSubsectionsViaSymbols (platformOS platform)+ then ["-Wl,-dead_strip"]+ else []+ let lib_paths = libraryPaths dflags+ let lib_path_opts = map ("-L"++) lib_paths++ extraLinkObj <- mkExtraObjToLinkIntoBinary dflags+ noteLinkObjs <- mkNoteObjsToLinkIntoBinary dflags dep_packages++ let+ (pre_hs_libs, post_hs_libs)+ | gopt Opt_WholeArchiveHsLibs dflags+ = if platformOS platform == OSDarwin+ then (["-Wl,-all_load"], [])+ -- OS X does not have a flag to turn off -all_load+ else (["-Wl,--whole-archive"], ["-Wl,--no-whole-archive"])+ | otherwise+ = ([],[])++ pkg_link_opts <- do+ (package_hs_libs, extra_libs, other_flags) <- getPackageLinkOpts dflags dep_packages+ return $ if staticLink+ then package_hs_libs -- If building an executable really means making a static+ -- library (e.g. iOS), then we only keep the -l options for+ -- HS packages, because libtool doesn't accept other options.+ -- In the case of iOS these need to be added by hand to the+ -- final link in Xcode.+ else other_flags ++ dead_strip+ ++ pre_hs_libs ++ package_hs_libs ++ post_hs_libs+ ++ extra_libs+ -- -Wl,-u,<sym> contained in other_flags+ -- needs to be put before -l<package>,+ -- otherwise Solaris linker fails linking+ -- a binary with unresolved symbols in RTS+ -- which are defined in base package+ -- the reason for this is a note in ld(1) about+ -- '-u' option: "The placement of this option+ -- on the command line is significant.+ -- This option must be placed before the library+ -- that defines the symbol."++ -- frameworks+ pkg_framework_opts <- getPkgFrameworkOpts dflags platform dep_packages+ let framework_opts = getFrameworkOpts dflags platform++ -- probably _stub.o files+ let extra_ld_inputs = ldInputs dflags++ -- Here are some libs that need to be linked at the *end* of+ -- the command line, because they contain symbols that are referred to+ -- by the RTS. We can't therefore use the ordinary way opts for these.+ let+ debug_opts | WayDebug `elem` ways dflags = [+#if defined(HAVE_LIBBFD)+ "-lbfd", "-liberty"+#endif+ ]+ | otherwise = []++ let thread_opts+ | WayThreaded `elem` ways dflags =+ let os = platformOS (targetPlatform dflags)+ in if os `elem` [OSMinGW32, OSFreeBSD, OSOpenBSD, OSAndroid,+ OSNetBSD, OSHaiku, OSQNXNTO, OSiOS, OSDarwin]+ then []+ else ["-lpthread"]+ | otherwise = []++ rc_objs <- maybeCreateManifest dflags output_fn++ let link = if staticLink+ then SysTools.runLibtool+ else SysTools.runLink+ link dflags (+ map SysTools.Option verbFlags+ ++ [ SysTools.Option "-o"+ , SysTools.FileOption "" output_fn+ ]+ ++ map SysTools.Option (+ []++ -- See Note [No PIE eating when linking]+ ++ (if sGccSupportsNoPie mySettings+ then ["-no-pie"]+ else [])++ -- Permit the linker to auto link _symbol to _imp_symbol.+ -- This lets us link against DLLs without needing an "import library".+ ++ (if platformOS platform == OSMinGW32+ then ["-Wl,--enable-auto-import"]+ else [])++ -- '-no_compact_unwind'+ -- C++/Objective-C exceptions cannot use optimised+ -- stack unwinding code. The optimised form is the+ -- default in Xcode 4 on at least x86_64, and+ -- without this flag we're also seeing warnings+ -- like+ -- ld: warning: could not create compact unwind for .LFB3: non-standard register 5 being saved in prolog+ -- on x86.+ ++ (if sLdSupportsCompactUnwind mySettings &&+ not staticLink &&+ (platformOS platform == OSDarwin || platformOS platform == OSiOS) &&+ case platformArch platform of+ ArchX86 -> True+ ArchX86_64 -> True+ ArchARM {} -> True+ ArchARM64 -> True+ _ -> False+ then ["-Wl,-no_compact_unwind"]+ else [])++ -- '-no_pie'+ -- iOS uses 'dynamic-no-pic', so we must pass this to ld to suppress a warning; see #7722+ ++ (if platformOS platform == OSiOS &&+ not staticLink+ then ["-Wl,-no_pie"]+ else [])++ -- '-Wl,-read_only_relocs,suppress'+ -- ld gives loads of warnings like:+ -- ld: warning: text reloc in _base_GHCziArr_unsafeArray_info to _base_GHCziArr_unsafeArray_closure+ -- when linking any program. We're not sure+ -- whether this is something we ought to fix, but+ -- for now this flags silences them.+ ++ (if platformOS platform == OSDarwin &&+ platformArch platform == ArchX86 &&+ not staticLink+ then ["-Wl,-read_only_relocs,suppress"]+ else [])++ ++ (if sLdIsGnuLd mySettings &&+ not (gopt Opt_WholeArchiveHsLibs dflags)+ then ["-Wl,--gc-sections"]+ else [])++ ++ o_files+ ++ lib_path_opts)+ ++ extra_ld_inputs+ ++ map SysTools.Option (+ rc_objs+ ++ framework_opts+ ++ pkg_lib_path_opts+ ++ extraLinkObj:noteLinkObjs+ ++ pkg_link_opts+ ++ pkg_framework_opts+ ++ debug_opts+ ++ thread_opts+ ))++exeFileName :: Bool -> DynFlags -> FilePath+exeFileName staticLink dflags+ | Just s <- outputFile dflags =+ case platformOS (targetPlatform dflags) of+ OSMinGW32 -> s <?.> "exe"+ _ -> if staticLink+ then s <?.> "a"+ else s+ | otherwise =+ if platformOS (targetPlatform dflags) == OSMinGW32+ then "main.exe"+ else if staticLink+ then "liba.a"+ else "a.out"+ where s <?.> ext | null (takeExtension s) = s <.> ext+ | otherwise = s++maybeCreateManifest+ :: DynFlags+ -> FilePath -- filename of executable+ -> IO [FilePath] -- extra objects to embed, maybe+maybeCreateManifest dflags exe_filename+ | platformOS (targetPlatform dflags) == OSMinGW32 &&+ gopt Opt_GenManifest dflags+ = do let manifest_filename = exe_filename <.> "manifest"++ writeFile manifest_filename $+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"+++ " <assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"+++ " <assemblyIdentity version=\"1.0.0.0\"\n"+++ " processorArchitecture=\"X86\"\n"+++ " name=\"" ++ dropExtension exe_filename ++ "\"\n"+++ " type=\"win32\"/>\n\n"+++ " <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n"+++ " <security>\n"+++ " <requestedPrivileges>\n"+++ " <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n"+++ " </requestedPrivileges>\n"+++ " </security>\n"+++ " </trustInfo>\n"+++ "</assembly>\n"++ -- Windows will find the manifest file if it is named+ -- foo.exe.manifest. However, for extra robustness, and so that+ -- we can move the binary around, we can embed the manifest in+ -- the binary itself using windres:+ if not (gopt Opt_EmbedManifest dflags) then return [] else do++ rc_filename <- newTempName dflags "rc"+ rc_obj_filename <- newTempName dflags (objectSuf dflags)++ writeFile rc_filename $+ "1 24 MOVEABLE PURE " ++ show manifest_filename ++ "\n"+ -- magic numbers :-)+ -- show is a bit hackish above, but we need to escape the+ -- backslashes in the path.++ runWindres dflags $ map SysTools.Option $+ ["--input="++rc_filename,+ "--output="++rc_obj_filename,+ "--output-format=coff"]+ -- no FileOptions here: windres doesn't like seeing+ -- backslashes, apparently++ removeFile manifest_filename++ return [rc_obj_filename]+ | otherwise = return []+++linkDynLibCheck :: DynFlags -> [String] -> [InstalledUnitId] -> IO ()+linkDynLibCheck dflags o_files dep_packages+ = do+ when (haveRtsOptsFlags dflags) $ do+ putLogMsg dflags NoReason SevInfo noSrcSpan+ (defaultUserStyle dflags)+ (text "Warning: -rtsopts and -with-rtsopts have no effect with -shared." $$+ text " Call hs_init_ghc() from your main() function to set these options.")++ linkDynLib dflags o_files dep_packages++linkStaticLibCheck :: DynFlags -> [String] -> [InstalledUnitId] -> IO ()+linkStaticLibCheck dflags o_files dep_packages+ = do+ when (platformOS (targetPlatform dflags) `notElem` [OSiOS, OSDarwin]) $+ throwGhcExceptionIO (ProgramError "Static archive creation only supported on Darwin/OS X/iOS")+ linkBinary' True dflags o_files dep_packages++-- -----------------------------------------------------------------------------+-- Running CPP++doCpp :: DynFlags -> Bool -> FilePath -> FilePath -> IO ()+doCpp dflags raw input_fn output_fn = do+ let hscpp_opts = picPOpts dflags+ let cmdline_include_paths = includePaths dflags++ pkg_include_dirs <- getPackageIncludePath dflags []+ let include_paths = foldr (\ x xs -> "-I" : x : xs) []+ (cmdline_include_paths ++ pkg_include_dirs)++ let verbFlags = getVerbFlags dflags++ let cpp_prog args | raw = SysTools.runCpp dflags args+ | otherwise = SysTools.runCc dflags (SysTools.Option "-E" : args)++ let target_defs =+ [ "-D" ++ HOST_OS ++ "_BUILD_OS",+ "-D" ++ HOST_ARCH ++ "_BUILD_ARCH",+ "-D" ++ TARGET_OS ++ "_HOST_OS",+ "-D" ++ TARGET_ARCH ++ "_HOST_ARCH" ]+ -- remember, in code we *compile*, the HOST is the same our TARGET,+ -- and BUILD is the same as our HOST.++ let sse_defs =+ [ "-D__SSE__" | isSseEnabled dflags ] +++ [ "-D__SSE2__" | isSse2Enabled dflags ] +++ [ "-D__SSE4_2__" | isSse4_2Enabled dflags ]++ let avx_defs =+ [ "-D__AVX__" | isAvxEnabled dflags ] +++ [ "-D__AVX2__" | isAvx2Enabled dflags ] +++ [ "-D__AVX512CD__" | isAvx512cdEnabled dflags ] +++ [ "-D__AVX512ER__" | isAvx512erEnabled dflags ] +++ [ "-D__AVX512F__" | isAvx512fEnabled dflags ] +++ [ "-D__AVX512PF__" | isAvx512pfEnabled dflags ]++ backend_defs <- getBackendDefs dflags++ let th_defs = [ "-D__GLASGOW_HASKELL_TH__" ]+ -- Default CPP defines in Haskell source+ ghcVersionH <- getGhcVersionPathName dflags+ let hsSourceCppOpts = [ "-include", ghcVersionH ]++ -- MIN_VERSION macros+ let uids = explicitPackages (pkgState dflags)+ pkgs = catMaybes (map (lookupPackage dflags) uids)+ mb_macro_include <-+ if not (null pkgs) && gopt Opt_VersionMacros dflags+ then do macro_stub <- newTempName dflags "h"+ writeFile macro_stub (generatePackageVersionMacros pkgs)+ -- Include version macros for every *exposed* package.+ -- Without -hide-all-packages and with a package database+ -- size of 1000 packages, it takes cpp an estimated 2+ -- milliseconds to process this file. See Trac #10970+ -- comment 8.+ return [SysTools.FileOption "-include" macro_stub]+ else return []++ cpp_prog ( map SysTools.Option verbFlags+ ++ map SysTools.Option include_paths+ ++ map SysTools.Option hsSourceCppOpts+ ++ map SysTools.Option target_defs+ ++ map SysTools.Option backend_defs+ ++ map SysTools.Option th_defs+ ++ map SysTools.Option hscpp_opts+ ++ map SysTools.Option sse_defs+ ++ map SysTools.Option avx_defs+ ++ mb_macro_include+ -- Set the language mode to assembler-with-cpp when preprocessing. This+ -- alleviates some of the C99 macro rules relating to whitespace and the hash+ -- operator, which we tend to abuse. Clang in particular is not very happy+ -- about this.+ ++ [ SysTools.Option "-x"+ , SysTools.Option "assembler-with-cpp"+ , SysTools.Option input_fn+ -- We hackily use Option instead of FileOption here, so that the file+ -- name is not back-slashed on Windows. cpp is capable of+ -- dealing with / in filenames, so it works fine. Furthermore+ -- if we put in backslashes, cpp outputs #line directives+ -- with *double* backslashes. And that in turn means that+ -- our error messages get double backslashes in them.+ -- In due course we should arrange that the lexer deals+ -- with these \\ escapes properly.+ , SysTools.Option "-o"+ , SysTools.FileOption "" output_fn+ ])++getBackendDefs :: DynFlags -> IO [String]+getBackendDefs dflags | hscTarget dflags == HscLlvm = do+ llvmVer <- figureLlvmVersion dflags+ return $ case llvmVer of+ Just n -> [ "-D__GLASGOW_HASKELL_LLVM__=" ++ format n ]+ _ -> []+ where+ format (major, minor)+ | minor >= 100 = error "getBackendDefs: Unsupported minor version"+ | otherwise = show $ (100 * major + minor :: Int) -- Contract is Int++getBackendDefs _ =+ return []++-- ---------------------------------------------------------------------------+-- Macros (cribbed from Cabal)++generatePackageVersionMacros :: [PackageConfig] -> String+generatePackageVersionMacros pkgs = concat+ -- Do not add any C-style comments. See Trac #3389.+ [ generateMacros "" pkgname version+ | pkg <- pkgs+ , let version = packageVersion pkg+ pkgname = map fixchar (packageNameString pkg)+ ]++fixchar :: Char -> Char+fixchar '-' = '_'+fixchar c = c++generateMacros :: String -> String -> Version -> String+generateMacros prefix name version =+ concat+ ["#define ", prefix, "VERSION_",name," ",show (showVersion version),"\n"+ ,"#define MIN_", prefix, "VERSION_",name,"(major1,major2,minor) (\\\n"+ ," (major1) < ",major1," || \\\n"+ ," (major1) == ",major1," && (major2) < ",major2," || \\\n"+ ," (major1) == ",major1," && (major2) == ",major2," && (minor) <= ",minor,")"+ ,"\n\n"+ ]+ where+ (major1:major2:minor:_) = map show (versionBranch version ++ repeat 0)++-- ---------------------------------------------------------------------------+-- join object files into a single relocatable object file, using ld -r++joinObjectFiles :: DynFlags -> [FilePath] -> FilePath -> IO ()+joinObjectFiles dflags o_files output_fn = do+ let mySettings = settings dflags+ ldIsGnuLd = sLdIsGnuLd mySettings+ osInfo = platformOS (targetPlatform dflags)+ ld_r args cc = SysTools.runLink dflags ([+ SysTools.Option "-nostdlib",+ SysTools.Option "-Wl,-r"+ ]+ -- See Note [No PIE eating while linking] in SysTools+ ++ (if sGccSupportsNoPie mySettings+ then [SysTools.Option "-no-pie"]+ else [])++ ++ (if any (cc ==) [Clang, AppleClang, AppleClang51]+ then []+ else [SysTools.Option "-nodefaultlibs"])+ ++ (if osInfo == OSFreeBSD+ then [SysTools.Option "-L/usr/lib"]+ else [])+ -- gcc on sparc sets -Wl,--relax implicitly, but+ -- -r and --relax are incompatible for ld, so+ -- disable --relax explicitly.+ ++ (if platformArch (targetPlatform dflags)+ `elem` [ArchSPARC, ArchSPARC64]+ && ldIsGnuLd+ then [SysTools.Option "-Wl,-no-relax"]+ else [])+ ++ map SysTools.Option ld_build_id+ ++ [ SysTools.Option "-o",+ SysTools.FileOption "" output_fn ]+ ++ args)++ -- suppress the generation of the .note.gnu.build-id section,+ -- which we don't need and sometimes causes ld to emit a+ -- warning:+ ld_build_id | sLdSupportsBuildId mySettings = ["-Wl,--build-id=none"]+ | otherwise = []++ ccInfo <- getCompilerInfo dflags+ if ldIsGnuLd+ then do+ script <- newTempName dflags "ldscript"+ cwd <- getCurrentDirectory+ let o_files_abs = map (\x -> "\"" ++ (cwd </> x) ++ "\"") o_files+ writeFile script $ "INPUT(" ++ unwords o_files_abs ++ ")"+ ld_r [SysTools.FileOption "" script] ccInfo+ else if sLdSupportsFilelist mySettings+ then do+ filelist <- newTempName dflags "filelist"+ writeFile filelist $ unlines o_files+ ld_r [SysTools.Option "-Wl,-filelist",+ SysTools.FileOption "-Wl," filelist] ccInfo+ else do+ ld_r (map (SysTools.FileOption "") o_files) ccInfo++-- -----------------------------------------------------------------------------+-- Misc.++writeInterfaceOnlyMode :: DynFlags -> Bool+writeInterfaceOnlyMode dflags =+ gopt Opt_WriteInterface dflags &&+ HscNothing == hscTarget dflags++-- | What phase to run after one of the backend code generators has run+hscPostBackendPhase :: DynFlags -> HscSource -> HscTarget -> Phase+hscPostBackendPhase _ HsBootFile _ = StopLn+hscPostBackendPhase _ HsigFile _ = StopLn+hscPostBackendPhase dflags _ hsc_lang =+ case hsc_lang of+ HscC -> HCc+ HscAsm | gopt Opt_SplitObjs dflags -> Splitter+ | otherwise -> As False+ HscLlvm -> LlvmOpt+ HscNothing -> StopLn+ HscInterpreted -> StopLn++touchObjectFile :: DynFlags -> FilePath -> IO ()+touchObjectFile dflags path = do+ createDirectoryIfMissing True $ takeDirectory path+ SysTools.touch dflags "Touching object file" path++haveRtsOptsFlags :: DynFlags -> Bool+haveRtsOptsFlags dflags =+ isJust (rtsOpts dflags) || case rtsOptsEnabled dflags of+ RtsOptsSafeOnly -> False+ _ -> True++-- | Find out path to @ghcversion.h@ file+getGhcVersionPathName :: DynFlags -> IO FilePath+getGhcVersionPathName dflags = do+ dirs <- getPackageIncludePath dflags [toInstalledUnitId rtsUnitId]++ found <- filterM doesFileExist (map (</> "ghcversion.h") dirs)+ case found of+ [] -> throwGhcExceptionIO (InstallationError ("ghcversion.h missing"))+ (x:_) -> return x++-- Note [-fPIC for assembler]+-- When compiling .c source file GHC's driver pipeline basically+-- does the following two things:+-- 1. ${CC} -S 'PIC_CFLAGS' source.c+-- 2. ${CC} -x assembler -c 'PIC_CFLAGS' source.S+--+-- Why do we need to pass 'PIC_CFLAGS' both to C compiler and assembler?+-- Because on some architectures (at least sparc32) assembler also chooses+-- the relocation type!+-- Consider the following C module:+--+-- /* pic-sample.c */+-- int v;+-- void set_v (int n) { v = n; }+-- int get_v (void) { return v; }+--+-- $ gcc -S -fPIC pic-sample.c+-- $ gcc -c pic-sample.s -o pic-sample.no-pic.o # incorrect binary+-- $ gcc -c -fPIC pic-sample.s -o pic-sample.pic.o # correct binary+--+-- $ objdump -r -d pic-sample.pic.o > pic-sample.pic.o.od+-- $ objdump -r -d pic-sample.no-pic.o > pic-sample.no-pic.o.od+-- $ diff -u pic-sample.pic.o.od pic-sample.no-pic.o.od+--+-- Most of architectures won't show any difference in this test, but on sparc32+-- the following assembly snippet:+--+-- sethi %hi(_GLOBAL_OFFSET_TABLE_-8), %l7+--+-- generates two kinds or relocations, only 'R_SPARC_PC22' is correct:+--+-- 3c: 2f 00 00 00 sethi %hi(0), %l7+-- - 3c: R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_-0x8+-- + 3c: R_SPARC_HI22 _GLOBAL_OFFSET_TABLE_-0x8++{- Note [Don't normalise input filenames]++Summary+ We used to normalise input filenames when starting the unlit phase. This+ broke hpc in `--make` mode with imported literate modules (#2991).++Introduction+ 1) --main+ When compiling a module with --main, GHC scans its imports to find out which+ other modules it needs to compile too. It turns out that there is a small+ difference between saying `ghc --make A.hs`, when `A` imports `B`, and+ specifying both modules on the command line with `ghc --make A.hs B.hs`. In+ the former case, the filename for B is inferred to be './B.hs' instead of+ 'B.hs'.++ 2) unlit+ When GHC compiles a literate haskell file, the source code first needs to go+ through unlit, which turns it into normal Haskell source code. At the start+ of the unlit phase, in `Driver.Pipeline.runPhase`, we call unlit with the+ option `-h` and the name of the original file. We used to normalise this+ filename using System.FilePath.normalise, which among other things removes+ an initial './'. unlit then uses that filename in #line directives that it+ inserts in the transformed source code.++ 3) SrcSpan+ A SrcSpan represents a portion of a source code file. It has fields+ linenumber, start column, end column, and also a reference to the file it+ originated from. The SrcSpans for a literate haskell file refer to the+ filename that was passed to unlit -h.++ 4) -fhpc+ At some point during compilation with -fhpc, in the function+ `deSugar.Coverage.isGoodTickSrcSpan`, we compare the filename that a+ `SrcSpan` refers to with the name of the file we are currently compiling.+ For some reason I don't yet understand, they can sometimes legitimally be+ different, and then hpc ignores that SrcSpan.++Problem+ When running `ghc --make -fhpc A.hs`, where `A.hs` imports the literate+ module `B.lhs`, `B` is inferred to be in the file `./B.lhs` (1). At the+ start of the unlit phase, the name `./B.lhs` is normalised to `B.lhs` (2).+ Therefore the SrcSpans of `B` refer to the file `B.lhs` (3), but we are+ still compiling `./B.lhs`. Hpc thinks these two filenames are different (4),+ doesn't include ticks for B, and we have unhappy customers (#2991).++Solution+ Do not normalise `input_fn` when starting the unlit phase.++Alternative solution+ Another option would be to not compare the two filenames on equality, but to+ use System.FilePath.equalFilePath. That function first normalises its+ arguments. The problem is that by the time we need to do the comparison, the+ filenames have been turned into FastStrings, probably for performance+ reasons, so System.FilePath.equalFilePath can not be used directly.++Archeology+ The call to `normalise` was added in a commit called "Fix slash+ direction on Windows with the new filePath code" (c9b6b5e8). The problem+ that commit was addressing has since been solved in a different manner, in a+ commit called "Fix the filename passed to unlit" (1eedbc6b). So the+ `normalise` is no longer necessary.+-}
+ main/DynFlags.hs view
@@ -0,0 +1,5335 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}++-------------------------------------------------------------------------------+--+-- | Dynamic flags+--+-- Most flags are dynamic flags, which means they can change from compilation+-- to compilation using @OPTIONS_GHC@ pragmas, and in a multi-session GHC each+-- session can be using different dynamic flags. Dynamic flags can also be set+-- at the prompt in GHCi.+--+-- (c) The University of Glasgow 2005+--+-------------------------------------------------------------------------------++{-# OPTIONS_GHC -fno-cse #-}+-- -fno-cse is needed for GLOBAL_VAR's to behave properly++module DynFlags (+ -- * Dynamic flags and associated configuration types+ DumpFlag(..),+ GeneralFlag(..),+ WarningFlag(..), WarnReason(..),+ Language(..),+ PlatformConstants(..),+ FatalMessager, LogAction, LogFinaliser, FlushOut(..), FlushErr(..),+ ProfAuto(..),+ glasgowExtsFlags,+ warningGroups, warningHierarchies,+ hasPprDebug, hasNoDebugOutput, hasNoStateHack, hasNoOptCoercion,+ dopt, dopt_set, dopt_unset,+ gopt, gopt_set, gopt_unset, setGeneralFlag', unSetGeneralFlag',+ wopt, wopt_set, wopt_unset,+ wopt_fatal,+ xopt, xopt_set, xopt_unset,+ lang_set,+ useUnicodeSyntax,+ whenGeneratingDynamicToo, ifGeneratingDynamicToo,+ whenCannotGenerateDynamicToo,+ dynamicTooMkDynamicDynFlags,+ DynFlags(..),+ FlagSpec(..),+ HasDynFlags(..), ContainsDynFlags(..),+ RtsOptsEnabled(..),+ HscTarget(..), isObjectTarget, defaultObjectTarget,+ targetRetainsAllBindings,+ GhcMode(..), isOneShot,+ GhcLink(..), isNoLink,+ PackageFlag(..), PackageArg(..), ModRenaming(..),+ packageFlagsChanged,+ IgnorePackageFlag(..), TrustFlag(..),+ PackageDBFlag(..), PkgConfRef(..),+ Option(..), showOpt,+ DynLibLoader(..),+ fFlags, fLangFlags, xFlags,+ wWarningFlags,+ dynFlagDependencies,+ tablesNextToCode, mkTablesNextToCode,+ makeDynFlagsConsistent,+ shouldUseColor,++ Way(..), mkBuildTag, wayRTSOnly, addWay', updateWays,+ wayGeneralFlags, wayUnsetGeneralFlags,++ thisPackage, thisComponentId, thisUnitIdInsts,++ -- ** Log output+ putLogMsg,++ -- ** Safe Haskell+ SafeHaskellMode(..),+ safeHaskellOn, safeImportsOn, safeLanguageOn, safeInferOn,+ packageTrustOn,+ safeDirectImpsReq, safeImplicitImpsReq,+ unsafeFlags, unsafeFlagsForInfer,++ -- ** System tool settings and locations+ Settings(..),+ targetPlatform, programName, projectVersion,+ ghcUsagePath, ghciUsagePath, topDir, tmpDir, rawSettings,+ versionedAppDir,+ extraGccViaCFlags, systemPackageConfig,+ pgm_L, pgm_P, pgm_F, pgm_c, pgm_s, pgm_a, pgm_l, pgm_dll, pgm_T,+ pgm_windres, pgm_libtool, pgm_lo, pgm_lc, pgm_i,+ opt_L, opt_P, opt_F, opt_c, opt_a, opt_l, opt_i,+ opt_windres, opt_lo, opt_lc,+++ -- ** Manipulating DynFlags+ defaultDynFlags, -- Settings -> DynFlags+ defaultWays,+ interpWays,+ interpreterProfiled, interpreterDynamic,+ initDynFlags, -- DynFlags -> IO DynFlags+ defaultFatalMessager,+ defaultLogAction,+ defaultLogActionHPrintDoc,+ defaultLogActionHPutStrDoc,+ defaultFlushOut,+ defaultFlushErr,++ getOpts, -- DynFlags -> (DynFlags -> [a]) -> [a]+ getVerbFlags,+ updOptLevel,+ setTmpDir,+ setUnitId,+ interpretPackageEnv,+ canonicalizeHomeModule,++ -- ** Parsing DynFlags+ parseDynamicFlagsCmdLine,+ parseDynamicFilePragma,+ parseDynamicFlagsFull,++ -- ** Available DynFlags+ allNonDeprecatedFlags,+ flagsAll,+ flagsDynamic,+ flagsPackage,+ flagsForCompletion,++ supportedLanguagesAndExtensions,+ languageExtensions,++ -- ** DynFlags C compiler options+ picCCOpts, picPOpts,++ -- * Compiler configuration suitable for display to the user+ compilerInfo,++ rtsIsProfiled,+ dynamicGhc,++#include "GHCConstantsHaskellExports.hs"+ bLOCK_SIZE_W,+ wORD_SIZE_IN_BITS,+ tAG_MASK,+ mAX_PTR_TAG,+ tARGET_MIN_INT, tARGET_MAX_INT, tARGET_MAX_WORD,++ unsafeGlobalDynFlags, setUnsafeGlobalDynFlags,++ -- * SSE and AVX+ isSseEnabled,+ isSse2Enabled,+ isSse4_2Enabled,+ isAvxEnabled,+ isAvx2Enabled,+ isAvx512cdEnabled,+ isAvx512erEnabled,+ isAvx512fEnabled,+ isAvx512pfEnabled,++ -- * Linker/compiler information+ LinkerInfo(..),+ CompilerInfo(..),+ ) where++#include "HsVersions.h"++import Platform+import PlatformConstants+import Module+import PackageConfig+import {-# SOURCE #-} Hooks+import {-# SOURCE #-} PrelNames ( mAIN )+import {-# SOURCE #-} Packages (PackageState, emptyPackageState)+import DriverPhases ( Phase(..), phaseInputExt )+import Config+import CmdLineParser+import Constants+import Panic+import qualified PprColour as Col+import Util+import Maybes+import MonadUtils+import qualified Pretty+import SrcLoc+import BasicTypes ( IntWithInf, treatZeroAsInf )+import FastString+import Outputable+import Foreign.C ( CInt(..) )+import System.IO.Unsafe ( unsafeDupablePerformIO )+import {-# SOURCE #-} ErrUtils ( Severity(..), MsgDoc, mkLocMessageAnn+ , getCaretDiagnostic, dumpSDoc )+import Json+import SysTools.Terminal ( stderrSupportsAnsiColors )++import System.IO.Unsafe ( unsafePerformIO )+import Data.IORef+import Control.Arrow ((&&&))+import Control.Monad+import Control.Monad.Trans.Class+import Control.Monad.Trans.Writer+import Control.Monad.Trans.Reader+import Control.Monad.Trans.Except+import Control.Exception (throwIO)++import Data.Ord+import Data.Bits+import Data.Char+import Data.Int+import Data.List+import Data.Map (Map)+import qualified Data.Map as Map+import Data.Set (Set)+import qualified Data.Set as Set+import Data.Word+import System.FilePath+import System.Directory+import System.Environment (getEnv, lookupEnv)+import System.IO+import System.IO.Error+import Text.ParserCombinators.ReadP hiding (char)+import Text.ParserCombinators.ReadP as R++import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet++import GHC.Foreign (withCString, peekCString)+import qualified GHC.LanguageExtensions as LangExt++import Foreign (Ptr) -- needed for 2nd stage++-- Note [Updating flag description in the User's Guide]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- If you modify anything in this file please make sure that your changes are+-- described in the User's Guide. Usually at least two sections need to be+-- updated:+--+-- * Flag Reference section generated from the modules in+-- utils/mkUserGuidePart/Options+--+-- * Flag description in docs/users_guide/using.rst provides a detailed+-- explanation of flags' usage.++-- Note [Supporting CLI completion]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- The command line interface completion (in for example bash) is an easy way+-- for the developer to learn what flags are available from GHC.+-- GHC helps by separating which flags are available when compiling with GHC,+-- and which flags are available when using GHCi.+-- A flag is assumed to either work in both these modes, or only in one of them.+-- When adding or changing a flag, please consider for which mode the flag will+-- have effect, and annotate it accordingly. For Flags use defFlag, defGhcFlag,+-- defGhciFlag, and for FlagSpec use flagSpec or flagGhciSpec.++-- Note [Adding a language extension]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- There are a few steps to adding (or removing) a language extension,+--+-- * Adding the extension to GHC.LanguageExtensions+--+-- The Extension type in libraries/ghc-boot-th/GHC/LanguageExtensions/Type.hs+-- is the canonical list of language extensions known by GHC.+--+-- * Adding a flag to DynFlags.xFlags+--+-- This is fairly self-explanatory. The name should be concise, memorable,+-- and consistent with any previous implementations of the similar idea in+-- other Haskell compilers.+--+-- * Adding the flag to the documentation+--+-- This is the same as any other flag. See+-- Note [Updating flag description in the User's Guide]+--+-- * Adding the flag to Cabal+--+-- The Cabal library has its own list of all language extensions supported+-- by all major compilers. This is the list that user code being uploaded+-- to Hackage is checked against to ensure language extension validity.+-- Consequently, it is very important that this list remains up-to-date.+--+-- To this end, there is a testsuite test (testsuite/tests/driver/T4437.hs)+-- whose job it is to ensure these GHC's extensions are consistent with+-- Cabal.+--+-- The recommended workflow is,+--+-- 1. Temporarily add your new language extension to the+-- expectedGhcOnlyExtensions list in T4437 to ensure the test doesn't+-- break while Cabal is updated.+--+-- 2. After your GHC change is accepted, submit a Cabal pull request adding+-- your new extension to Cabal's list (found in+-- Cabal/Language/Haskell/Extension.hs).+--+-- 3. After your Cabal change is accepted, let the GHC developers know so+-- they can update the Cabal submodule and remove the extensions from+-- expectedGhcOnlyExtensions.+--+-- * Adding the flag to the GHC Wiki+--+-- There is a change log tracking language extension additions and removals+-- on the GHC wiki: https://ghc.haskell.org/trac/ghc/wiki/LanguagePragmaHistory+--+-- See Trac #4437 and #8176.++-- -----------------------------------------------------------------------------+-- DynFlags++data DumpFlag+-- See Note [Updating flag description in the User's Guide]++ -- debugging flags+ = Opt_D_dump_cmm+ | Opt_D_dump_cmm_from_stg+ | Opt_D_dump_cmm_raw+ | Opt_D_dump_cmm_verbose+ -- All of the cmm subflags (there are a lot!) automatically+ -- enabled if you run -ddump-cmm-verbose+ -- Each flag corresponds to exact stage of Cmm pipeline.+ | Opt_D_dump_cmm_cfg+ | Opt_D_dump_cmm_cbe+ | Opt_D_dump_cmm_switch+ | Opt_D_dump_cmm_proc+ | Opt_D_dump_cmm_sp+ | Opt_D_dump_cmm_sink+ | Opt_D_dump_cmm_caf+ | Opt_D_dump_cmm_procmap+ | Opt_D_dump_cmm_split+ | Opt_D_dump_cmm_info+ | Opt_D_dump_cmm_cps+ -- end cmm subflags+ | Opt_D_dump_asm+ | Opt_D_dump_asm_native+ | Opt_D_dump_asm_liveness+ | Opt_D_dump_asm_regalloc+ | Opt_D_dump_asm_regalloc_stages+ | Opt_D_dump_asm_conflicts+ | Opt_D_dump_asm_stats+ | Opt_D_dump_asm_expanded+ | Opt_D_dump_llvm+ | Opt_D_dump_core_stats+ | Opt_D_dump_deriv+ | Opt_D_dump_ds+ | Opt_D_dump_foreign+ | Opt_D_dump_inlinings+ | Opt_D_dump_rule_firings+ | Opt_D_dump_rule_rewrites+ | Opt_D_dump_simpl_trace+ | Opt_D_dump_occur_anal+ | Opt_D_dump_parsed+ | Opt_D_dump_parsed_ast+ | Opt_D_dump_rn+ | Opt_D_dump_rn_ast+ | Opt_D_dump_shape+ | Opt_D_dump_simpl+ | Opt_D_dump_simpl_iterations+ | Opt_D_dump_spec+ | Opt_D_dump_prep+ | Opt_D_dump_stg+ | Opt_D_dump_call_arity+ | Opt_D_dump_stranal+ | Opt_D_dump_str_signatures+ | Opt_D_dump_tc+ | Opt_D_dump_tc_ast+ | Opt_D_dump_types+ | Opt_D_dump_rules+ | Opt_D_dump_cse+ | Opt_D_dump_worker_wrapper+ | Opt_D_dump_rn_trace+ | Opt_D_dump_rn_stats+ | Opt_D_dump_opt_cmm+ | Opt_D_dump_simpl_stats+ | Opt_D_dump_cs_trace -- Constraint solver in type checker+ | Opt_D_dump_tc_trace+ | Opt_D_dump_ec_trace -- Pattern match exhaustiveness checker+ | Opt_D_dump_if_trace+ | Opt_D_dump_vt_trace+ | Opt_D_dump_splices+ | Opt_D_th_dec_file+ | Opt_D_dump_BCOs+ | Opt_D_dump_vect+ | Opt_D_dump_ticked+ | Opt_D_dump_rtti+ | Opt_D_source_stats+ | Opt_D_verbose_stg2stg+ | Opt_D_dump_hi+ | Opt_D_dump_hi_diffs+ | Opt_D_dump_mod_cycles+ | Opt_D_dump_mod_map+ | Opt_D_dump_view_pattern_commoning+ | Opt_D_verbose_core2core+ | Opt_D_dump_debug+ | Opt_D_dump_json+ | Opt_D_ppr_debug+ | Opt_D_no_debug_output+ deriving (Eq, Show, Enum)++-- | Enumerates the simple on-or-off dynamic flags+data GeneralFlag+-- See Note [Updating flag description in the User's Guide]++ = Opt_DumpToFile -- ^ Append dump output to files instead of stdout.+ | Opt_D_faststring_stats+ | Opt_D_dump_minimal_imports+ | Opt_DoCoreLinting+ | Opt_DoStgLinting+ | Opt_DoCmmLinting+ | Opt_DoAsmLinting+ | Opt_DoAnnotationLinting+ | Opt_NoLlvmMangler -- hidden flag++ | Opt_WarnIsError -- -Werror; makes warnings fatal+ | Opt_ShowWarnGroups -- Show the group a warning belongs to+ | Opt_HideSourcePaths -- Hide module source/object paths++ | Opt_PrintExplicitForalls+ | Opt_PrintExplicitKinds+ | Opt_PrintExplicitCoercions+ | Opt_PrintExplicitRuntimeReps+ | Opt_PrintEqualityRelations+ | Opt_PrintUnicodeSyntax+ | Opt_PrintExpandedSynonyms+ | Opt_PrintPotentialInstances+ | Opt_PrintTypecheckerElaboration++ -- optimisation opts+ | Opt_CallArity+ | Opt_Strictness+ | Opt_LateDmdAnal+ | Opt_KillAbsence+ | Opt_KillOneShot+ | Opt_FullLaziness+ | Opt_FloatIn+ | Opt_Specialise+ | Opt_SpecialiseAggressively+ | Opt_CrossModuleSpecialise+ | Opt_StaticArgumentTransformation+ | Opt_CSE+ | Opt_StgCSE+ | Opt_LiberateCase+ | Opt_SpecConstr+ | Opt_SpecConstrKeen+ | Opt_DoLambdaEtaExpansion+ | Opt_IgnoreAsserts+ | Opt_DoEtaReduction+ | Opt_CaseMerge+ | Opt_CaseFolding -- Constant folding through case-expressions+ | Opt_UnboxStrictFields+ | Opt_UnboxSmallStrictFields+ | Opt_DictsCheap+ | Opt_EnableRewriteRules -- Apply rewrite rules during simplification+ | Opt_Vectorise+ | Opt_VectorisationAvoidance+ | Opt_RegsGraph -- do graph coloring register allocation+ | Opt_RegsIterative -- do iterative coalescing graph coloring register allocation+ | Opt_PedanticBottoms -- Be picky about how we treat bottom+ | Opt_LlvmTBAA -- Use LLVM TBAA infastructure for improving AA (hidden flag)+ | Opt_LlvmPassVectorsInRegisters -- Pass SIMD vectors in registers (requires a patched LLVM) (hidden flag)+ | Opt_LlvmFillUndefWithGarbage -- Testing for undef bugs (hidden flag)+ | Opt_IrrefutableTuples+ | Opt_CmmSink+ | Opt_CmmElimCommonBlocks+ | Opt_OmitYields+ | Opt_FunToThunk -- allow WwLib.mkWorkerArgs to remove all value lambdas+ | Opt_DictsStrict -- be strict in argument dictionaries+ | Opt_DmdTxDictSel -- use a special demand transformer for dictionary selectors+ | Opt_Loopification -- See Note [Self-recursive tail calls]+ | Opt_CprAnal+ | Opt_WorkerWrapper+ | Opt_SolveConstantDicts++ -- Interface files+ | Opt_IgnoreInterfacePragmas+ | Opt_OmitInterfacePragmas+ | Opt_ExposeAllUnfoldings+ | Opt_WriteInterface -- forces .hi files to be written even with -fno-code++ -- profiling opts+ | Opt_AutoSccsOnIndividualCafs+ | Opt_ProfCountEntries++ -- misc opts+ | Opt_Pp+ | Opt_ForceRecomp+ | Opt_ExcessPrecision+ | Opt_EagerBlackHoling+ | Opt_NoHsMain+ | Opt_SplitObjs+ | Opt_SplitSections+ | Opt_StgStats+ | Opt_HideAllPackages+ | Opt_HideAllPluginPackages+ | Opt_PrintBindResult+ | Opt_Haddock+ | Opt_HaddockOptions+ | Opt_BreakOnException+ | Opt_BreakOnError+ | Opt_PrintEvldWithShow+ | Opt_PrintBindContents+ | Opt_GenManifest+ | Opt_EmbedManifest+ | Opt_SharedImplib+ | Opt_BuildingCabalPackage+ | Opt_IgnoreDotGhci+ | Opt_GhciSandbox+ | Opt_GhciHistory+ | Opt_LocalGhciHistory+ | Opt_HelpfulErrors+ | Opt_DeferTypeErrors+ | Opt_DeferTypedHoles+ | Opt_DeferOutOfScopeVariables+ | Opt_PIC+ | Opt_SccProfilingOn+ | Opt_Ticky+ | Opt_Ticky_Allocd+ | Opt_Ticky_LNE+ | Opt_Ticky_Dyn_Thunk+ | Opt_RPath+ | Opt_RelativeDynlibPaths+ | Opt_Hpc+ | Opt_FlatCache+ | Opt_ExternalInterpreter+ | Opt_OptimalApplicativeDo+ | Opt_VersionMacros+ | Opt_WholeArchiveHsLibs++ -- PreInlining is on by default. The option is there just to see how+ -- bad things get if you turn it off!+ | Opt_SimplPreInlining++ -- output style opts+ | Opt_ErrorSpans -- Include full span info in error messages,+ -- instead of just the start position.+ | Opt_DiagnosticsShowCaret -- Show snippets of offending code+ | Opt_PprCaseAsLet+ | Opt_PprShowTicks+ | Opt_ShowHoleConstraints++ -- Suppress all coercions, them replacing with '...'+ | Opt_SuppressCoercions+ | Opt_SuppressVarKinds+ -- Suppress module id prefixes on variables.+ | Opt_SuppressModulePrefixes+ -- Suppress type applications.+ | Opt_SuppressTypeApplications+ -- Suppress info such as arity and unfoldings on identifiers.+ | Opt_SuppressIdInfo+ -- Suppress separate type signatures in core, but leave types on+ -- lambda bound vars+ | Opt_SuppressUnfoldings+ -- Suppress the details of even stable unfoldings+ | Opt_SuppressTypeSignatures+ -- Suppress unique ids on variables.+ -- Except for uniques, as some simplifier phases introduce new+ -- variables that have otherwise identical names.+ | Opt_SuppressUniques+ | Opt_SuppressTicks -- Replaces Opt_PprShowTicks++ -- temporary flags+ | Opt_AutoLinkPackages+ | Opt_ImplicitImportQualified++ -- keeping stuff+ | Opt_KeepHiDiffs+ | Opt_KeepHcFiles+ | Opt_KeepSFiles+ | Opt_KeepTmpFiles+ | Opt_KeepRawTokenStream+ | Opt_KeepLlvmFiles+ | Opt_KeepHiFiles+ | Opt_KeepOFiles++ | Opt_BuildDynamicToo++ -- safe haskell flags+ | Opt_DistrustAllPackages+ | Opt_PackageTrust++ | Opt_G_NoStateHack+ | Opt_G_NoOptCoercion+ deriving (Eq, Show, Enum)++-- | Used when outputting warnings: if a reason is given, it is+-- displayed. If a warning isn't controlled by a flag, this is made+-- explicit at the point of use.+data WarnReason = NoReason | Reason !WarningFlag+ deriving Show++instance Outputable WarnReason where+ ppr = text . show++instance ToJson WarnReason where+ json NoReason = JSNull+ json (Reason wf) = JSString (show wf)++data WarningFlag =+-- See Note [Updating flag description in the User's Guide]+ Opt_WarnDuplicateExports+ | Opt_WarnDuplicateConstraints+ | Opt_WarnRedundantConstraints+ | Opt_WarnHiShadows+ | Opt_WarnImplicitPrelude+ | Opt_WarnIncompletePatterns+ | Opt_WarnIncompleteUniPatterns+ | Opt_WarnIncompletePatternsRecUpd+ | Opt_WarnOverflowedLiterals+ | Opt_WarnEmptyEnumerations+ | Opt_WarnMissingFields+ | Opt_WarnMissingImportList+ | Opt_WarnMissingMethods+ | Opt_WarnMissingSignatures+ | Opt_WarnMissingLocalSignatures+ | Opt_WarnNameShadowing+ | Opt_WarnOverlappingPatterns+ | Opt_WarnTypeDefaults+ | Opt_WarnMonomorphism+ | Opt_WarnUnusedTopBinds+ | Opt_WarnUnusedLocalBinds+ | Opt_WarnUnusedPatternBinds+ | Opt_WarnUnusedImports+ | Opt_WarnUnusedMatches+ | Opt_WarnUnusedTypePatterns+ | Opt_WarnUnusedForalls+ | Opt_WarnWarningsDeprecations+ | Opt_WarnDeprecatedFlags+ | Opt_WarnAMP -- Introduced in GHC 7.8, obsolete since 7.10+ | Opt_WarnMissingMonadFailInstances -- since 8.0+ | Opt_WarnSemigroup -- since 8.0+ | Opt_WarnDodgyExports+ | Opt_WarnDodgyImports+ | Opt_WarnOrphans+ | Opt_WarnAutoOrphans+ | Opt_WarnIdentities+ | Opt_WarnTabs+ | Opt_WarnUnrecognisedPragmas+ | Opt_WarnDodgyForeignImports+ | Opt_WarnUnusedDoBind+ | Opt_WarnWrongDoBind+ | Opt_WarnAlternativeLayoutRuleTransitional+ | Opt_WarnUnsafe+ | Opt_WarnSafe+ | Opt_WarnTrustworthySafe+ | Opt_WarnMissedSpecs+ | Opt_WarnAllMissedSpecs+ | Opt_WarnUnsupportedCallingConventions+ | Opt_WarnUnsupportedLlvmVersion+ | Opt_WarnInlineRuleShadowing+ | Opt_WarnTypedHoles+ | Opt_WarnPartialTypeSignatures+ | Opt_WarnMissingExportedSignatures+ | Opt_WarnUntickedPromotedConstructors+ | Opt_WarnDerivingTypeable+ | Opt_WarnDeferredTypeErrors+ | Opt_WarnDeferredOutOfScopeVariables+ | Opt_WarnNonCanonicalMonadInstances -- since 8.0+ | Opt_WarnNonCanonicalMonadFailInstances -- since 8.0+ | Opt_WarnNonCanonicalMonoidInstances -- since 8.0+ | Opt_WarnMissingPatternSynonymSignatures -- since 8.0+ | Opt_WarnUnrecognisedWarningFlags -- since 8.0+ | Opt_WarnSimplifiableClassConstraints -- Since 8.2+ | Opt_WarnCPPUndef -- Since 8.2+ | Opt_WarnUnbangedStrictPatterns -- Since 8.2+ | Opt_WarnMissingHomeModules -- Since 8.2+ deriving (Eq, Show, Enum)++data Language = Haskell98 | Haskell2010+ deriving (Eq, Enum, Show)++instance Outputable Language where+ ppr = text . show++-- | The various Safe Haskell modes+data SafeHaskellMode+ = Sf_None+ | Sf_Unsafe+ | Sf_Trustworthy+ | Sf_Safe+ deriving (Eq)++instance Show SafeHaskellMode where+ show Sf_None = "None"+ show Sf_Unsafe = "Unsafe"+ show Sf_Trustworthy = "Trustworthy"+ show Sf_Safe = "Safe"++instance Outputable SafeHaskellMode where+ ppr = text . show++-- | Contains not only a collection of 'GeneralFlag's but also a plethora of+-- information relating to the compilation of a single file or GHC session+data DynFlags = DynFlags {+ ghcMode :: GhcMode,+ ghcLink :: GhcLink,+ hscTarget :: HscTarget,+ settings :: Settings,+ verbosity :: Int, -- ^ Verbosity level: see Note [Verbosity levels]+ optLevel :: Int, -- ^ Optimisation level+ debugLevel :: Int, -- ^ How much debug information to produce+ simplPhases :: Int, -- ^ Number of simplifier phases+ maxSimplIterations :: Int, -- ^ Max simplifier iterations+ maxPmCheckIterations :: Int, -- ^ Max no iterations for pm checking+ ruleCheck :: Maybe String,+ strictnessBefore :: [Int], -- ^ Additional demand analysis++ parMakeCount :: Maybe Int, -- ^ The number of modules to compile in parallel+ -- in --make mode, where Nothing ==> compile as+ -- many in parallel as there are CPUs.++ enableTimeStats :: Bool, -- ^ Enable RTS timing statistics?+ ghcHeapSize :: Maybe Int, -- ^ The heap size to set.++ maxRelevantBinds :: Maybe Int, -- ^ Maximum number of bindings from the type envt+ -- to show in type error messages+ maxUncoveredPatterns :: Int, -- ^ Maximum number of unmatched patterns to show+ -- in non-exhaustiveness warnings+ simplTickFactor :: Int, -- ^ Multiplier for simplifier ticks+ specConstrThreshold :: Maybe Int, -- ^ Threshold for SpecConstr+ specConstrCount :: Maybe Int, -- ^ Max number of specialisations for any one function+ specConstrRecursive :: Int, -- ^ Max number of specialisations for recursive types+ -- Not optional; otherwise ForceSpecConstr can diverge.+ liberateCaseThreshold :: Maybe Int, -- ^ Threshold for LiberateCase+ floatLamArgs :: Maybe Int, -- ^ Arg count for lambda floating+ -- See CoreMonad.FloatOutSwitches++ historySize :: Int, -- ^ Simplification history size++ importPaths :: [FilePath],+ mainModIs :: Module,+ mainFunIs :: Maybe String,+ reductionDepth :: IntWithInf, -- ^ Typechecker maximum stack depth+ solverIterations :: IntWithInf, -- ^ Number of iterations in the constraints solver+ -- Typically only 1 is needed++ thisInstalledUnitId :: InstalledUnitId,+ thisComponentId_ :: Maybe ComponentId,+ thisUnitIdInsts_ :: Maybe [(ModuleName, Module)],++ -- ways+ ways :: [Way], -- ^ Way flags from the command line+ buildTag :: String, -- ^ The global \"way\" (e.g. \"p\" for prof)+ rtsBuildTag :: String, -- ^ The RTS \"way\"++ -- For object splitting+ splitInfo :: Maybe (String,Int),++ -- paths etc.+ objectDir :: Maybe String,+ dylibInstallName :: Maybe String,+ hiDir :: Maybe String,+ stubDir :: Maybe String,+ dumpDir :: Maybe String,++ objectSuf :: String,+ hcSuf :: String,+ hiSuf :: String,++ canGenerateDynamicToo :: IORef Bool,+ dynObjectSuf :: String,+ dynHiSuf :: String,++ -- Packages.isDllName needs to know whether a call is within a+ -- single DLL or not. Normally it does this by seeing if the call+ -- is to the same package, but for the ghc package, we split the+ -- package between 2 DLLs. The dllSplit tells us which sets of+ -- modules are in which package.+ dllSplitFile :: Maybe FilePath,+ dllSplit :: Maybe [Set String],++ outputFile :: Maybe String,+ dynOutputFile :: Maybe String,+ outputHi :: Maybe String,+ dynLibLoader :: DynLibLoader,++ -- | This is set by 'DriverPipeline.runPipeline' based on where+ -- its output is going.+ dumpPrefix :: Maybe FilePath,++ -- | Override the 'dumpPrefix' set by 'DriverPipeline.runPipeline'.+ -- Set by @-ddump-file-prefix@+ dumpPrefixForce :: Maybe FilePath,++ ldInputs :: [Option],++ includePaths :: [String],+ libraryPaths :: [String],+ frameworkPaths :: [String], -- used on darwin only+ cmdlineFrameworks :: [String], -- ditto++ rtsOpts :: Maybe String,+ rtsOptsEnabled :: RtsOptsEnabled,+ rtsOptsSuggestions :: Bool,++ hpcDir :: String, -- ^ Path to store the .mix files++ -- Plugins+ pluginModNames :: [ModuleName],+ pluginModNameOpts :: [(ModuleName,String)],+ frontendPluginOpts :: [String],+ -- ^ the @-ffrontend-opt@ flags given on the command line, in *reverse*+ -- order that they're specified on the command line.++ -- GHC API hooks+ hooks :: Hooks,++ -- For ghc -M+ depMakefile :: FilePath,+ depIncludePkgDeps :: Bool,+ depExcludeMods :: [ModuleName],+ depSuffixes :: [String],++ -- Package flags+ packageDBFlags :: [PackageDBFlag],+ -- ^ The @-package-db@ flags given on the command line, In+ -- *reverse* order that they're specified on the command line.+ -- This is intended to be applied with the list of "initial"+ -- package databases derived from @GHC_PACKAGE_PATH@; see+ -- 'getPackageConfRefs'.++ ignorePackageFlags :: [IgnorePackageFlag],+ -- ^ The @-ignore-package@ flags from the command line.+ -- In *reverse* order that they're specified on the command line.+ packageFlags :: [PackageFlag],+ -- ^ The @-package@ and @-hide-package@ flags from the command-line.+ -- In *reverse* order that they're specified on the command line.+ pluginPackageFlags :: [PackageFlag],+ -- ^ The @-plugin-package-id@ flags from command line.+ -- In *reverse* order that they're specified on the command line.+ trustFlags :: [TrustFlag],+ -- ^ The @-trust@ and @-distrust@ flags.+ -- In *reverse* order that they're specified on the command line.+ packageEnv :: Maybe FilePath,+ -- ^ Filepath to the package environment file (if overriding default)++ -- Package state+ -- NB. do not modify this field, it is calculated by+ -- Packages.initPackages+ pkgDatabase :: Maybe [(FilePath, [PackageConfig])],+ pkgState :: PackageState,++ -- Temporary files+ -- These have to be IORefs, because the defaultCleanupHandler needs to+ -- know what to clean when an exception happens+ filesToClean :: IORef [FilePath],+ dirsToClean :: IORef (Map FilePath FilePath),+ filesToNotIntermediateClean :: IORef [FilePath],+ -- The next available suffix to uniquely name a temp file, updated atomically+ nextTempSuffix :: IORef Int,++ -- Names of files which were generated from -ddump-to-file; used to+ -- track which ones we need to truncate because it's our first run+ -- through+ generatedDumps :: IORef (Set FilePath),++ -- hsc dynamic flags+ dumpFlags :: IntSet,+ generalFlags :: IntSet,+ warningFlags :: IntSet,+ fatalWarningFlags :: IntSet,+ -- Don't change this without updating extensionFlags:+ language :: Maybe Language,+ -- | Safe Haskell mode+ safeHaskell :: SafeHaskellMode,+ safeInfer :: Bool,+ safeInferred :: Bool,+ -- We store the location of where some extension and flags were turned on so+ -- we can produce accurate error messages when Safe Haskell fails due to+ -- them.+ thOnLoc :: SrcSpan,+ newDerivOnLoc :: SrcSpan,+ overlapInstLoc :: SrcSpan,+ incoherentOnLoc :: SrcSpan,+ pkgTrustOnLoc :: SrcSpan,+ warnSafeOnLoc :: SrcSpan,+ warnUnsafeOnLoc :: SrcSpan,+ trustworthyOnLoc :: SrcSpan,+ -- Don't change this without updating extensionFlags:+ extensions :: [OnOff LangExt.Extension],+ -- extensionFlags should always be equal to+ -- flattenExtensionFlags language extensions+ -- LangExt.Extension is defined in libraries/ghc-boot so that it can be used+ -- by template-haskell+ extensionFlags :: IntSet,++ -- Unfolding control+ -- See Note [Discounts and thresholds] in CoreUnfold+ ufCreationThreshold :: Int,+ ufUseThreshold :: Int,+ ufFunAppDiscount :: Int,+ ufDictDiscount :: Int,+ ufKeenessFactor :: Float,+ ufDearOp :: Int,+ ufVeryAggressive :: Bool,++ maxWorkerArgs :: Int,++ ghciHistSize :: Int,++ -- | MsgDoc output action: use "ErrUtils" instead of this if you can+ initLogAction :: IO (Maybe LogOutput),+ log_action :: LogAction,+ log_finaliser :: LogFinaliser,+ flushOut :: FlushOut,+ flushErr :: FlushErr,++ haddockOptions :: Maybe String,++ -- | GHCi scripts specified by -ghci-script, in reverse order+ ghciScripts :: [String],++ -- Output style options+ pprUserLength :: Int,+ pprCols :: Int,++ useUnicode :: Bool,+ useColor :: OverridingBool,+ canUseColor :: Bool,+ colScheme :: Col.Scheme,++ -- | what kind of {-# SCC #-} to add automatically+ profAuto :: ProfAuto,++ interactivePrint :: Maybe String,++ nextWrapperNum :: IORef (ModuleEnv Int),++ -- | Machine dependent flags (-m<blah> stuff)+ sseVersion :: Maybe SseVersion,+ avx :: Bool,+ avx2 :: Bool,+ avx512cd :: Bool, -- Enable AVX-512 Conflict Detection Instructions.+ avx512er :: Bool, -- Enable AVX-512 Exponential and Reciprocal Instructions.+ avx512f :: Bool, -- Enable AVX-512 instructions.+ avx512pf :: Bool, -- Enable AVX-512 PreFetch Instructions.++ -- | Run-time linker information (what options we need, etc.)+ rtldInfo :: IORef (Maybe LinkerInfo),++ -- | Run-time compiler information+ rtccInfo :: IORef (Maybe CompilerInfo),++ -- Constants used to control the amount of optimization done.++ -- | Max size, in bytes, of inline array allocations.+ maxInlineAllocSize :: Int,++ -- | Only inline memcpy if it generates no more than this many+ -- pseudo (roughly: Cmm) instructions.+ maxInlineMemcpyInsns :: Int,++ -- | Only inline memset if it generates no more than this many+ -- pseudo (roughly: Cmm) instructions.+ maxInlineMemsetInsns :: Int,++ -- | Reverse the order of error messages in GHC/GHCi+ reverseErrors :: Bool,++ -- | Limit the maximum number of errors to show+ maxErrors :: Maybe Int,++ -- | Unique supply configuration for testing build determinism+ initialUnique :: Int,+ uniqueIncrement :: Int+}++class HasDynFlags m where+ getDynFlags :: m DynFlags++{- It would be desirable to have the more generalised++ instance (MonadTrans t, Monad m, HasDynFlags m) => HasDynFlags (t m) where+ getDynFlags = lift getDynFlags++instance definition. However, that definition would overlap with the+`HasDynFlags (GhcT m)` instance. Instead we define instances for a+couple of common Monad transformers explicitly. -}++instance (Monoid a, Monad m, HasDynFlags m) => HasDynFlags (WriterT a m) where+ getDynFlags = lift getDynFlags++instance (Monad m, HasDynFlags m) => HasDynFlags (ReaderT a m) where+ getDynFlags = lift getDynFlags++instance (Monad m, HasDynFlags m) => HasDynFlags (MaybeT m) where+ getDynFlags = lift getDynFlags++instance (Monad m, HasDynFlags m) => HasDynFlags (ExceptT e m) where+ getDynFlags = lift getDynFlags++class ContainsDynFlags t where+ extractDynFlags :: t -> DynFlags++data ProfAuto+ = NoProfAuto -- ^ no SCC annotations added+ | ProfAutoAll -- ^ top-level and nested functions are annotated+ | ProfAutoTop -- ^ top-level functions annotated only+ | ProfAutoExports -- ^ exported functions annotated only+ | ProfAutoCalls -- ^ annotate call-sites+ deriving (Eq,Enum)++data Settings = Settings {+ sTargetPlatform :: Platform, -- Filled in by SysTools+ sGhcUsagePath :: FilePath, -- Filled in by SysTools+ sGhciUsagePath :: FilePath, -- ditto+ sTopDir :: FilePath,+ sTmpDir :: String, -- no trailing '/'+ sProgramName :: String,+ sProjectVersion :: String,+ -- You shouldn't need to look things up in rawSettings directly.+ -- They should have their own fields instead.+ sRawSettings :: [(String, String)],+ sExtraGccViaCFlags :: [String],+ sSystemPackageConfig :: FilePath,+ sLdSupportsCompactUnwind :: Bool,+ sLdSupportsBuildId :: Bool,+ sLdSupportsFilelist :: Bool,+ sLdIsGnuLd :: Bool,+ sGccSupportsNoPie :: Bool,+ -- commands for particular phases+ sPgm_L :: String,+ sPgm_P :: (String,[Option]),+ sPgm_F :: String,+ sPgm_c :: (String,[Option]),+ sPgm_s :: (String,[Option]),+ sPgm_a :: (String,[Option]),+ sPgm_l :: (String,[Option]),+ sPgm_dll :: (String,[Option]),+ sPgm_T :: String,+ sPgm_windres :: String,+ sPgm_libtool :: String,+ sPgm_lo :: (String,[Option]), -- LLVM: opt llvm optimiser+ sPgm_lc :: (String,[Option]), -- LLVM: llc static compiler+ sPgm_i :: String,+ -- options for particular phases+ sOpt_L :: [String],+ sOpt_P :: [String],+ sOpt_F :: [String],+ sOpt_c :: [String],+ sOpt_a :: [String],+ sOpt_l :: [String],+ sOpt_windres :: [String],+ sOpt_lo :: [String], -- LLVM: llvm optimiser+ sOpt_lc :: [String], -- LLVM: llc static compiler+ sOpt_i :: [String], -- iserv options++ sPlatformConstants :: PlatformConstants+ }++targetPlatform :: DynFlags -> Platform+targetPlatform dflags = sTargetPlatform (settings dflags)+programName :: DynFlags -> String+programName dflags = sProgramName (settings dflags)+projectVersion :: DynFlags -> String+projectVersion dflags = sProjectVersion (settings dflags)+ghcUsagePath :: DynFlags -> FilePath+ghcUsagePath dflags = sGhcUsagePath (settings dflags)+ghciUsagePath :: DynFlags -> FilePath+ghciUsagePath dflags = sGhciUsagePath (settings dflags)+topDir :: DynFlags -> FilePath+topDir dflags = sTopDir (settings dflags)+tmpDir :: DynFlags -> String+tmpDir dflags = sTmpDir (settings dflags)+rawSettings :: DynFlags -> [(String, String)]+rawSettings dflags = sRawSettings (settings dflags)+extraGccViaCFlags :: DynFlags -> [String]+extraGccViaCFlags dflags = sExtraGccViaCFlags (settings dflags)+systemPackageConfig :: DynFlags -> FilePath+systemPackageConfig dflags = sSystemPackageConfig (settings dflags)+pgm_L :: DynFlags -> String+pgm_L dflags = sPgm_L (settings dflags)+pgm_P :: DynFlags -> (String,[Option])+pgm_P dflags = sPgm_P (settings dflags)+pgm_F :: DynFlags -> String+pgm_F dflags = sPgm_F (settings dflags)+pgm_c :: DynFlags -> (String,[Option])+pgm_c dflags = sPgm_c (settings dflags)+pgm_s :: DynFlags -> (String,[Option])+pgm_s dflags = sPgm_s (settings dflags)+pgm_a :: DynFlags -> (String,[Option])+pgm_a dflags = sPgm_a (settings dflags)+pgm_l :: DynFlags -> (String,[Option])+pgm_l dflags = sPgm_l (settings dflags)+pgm_dll :: DynFlags -> (String,[Option])+pgm_dll dflags = sPgm_dll (settings dflags)+pgm_T :: DynFlags -> String+pgm_T dflags = sPgm_T (settings dflags)+pgm_windres :: DynFlags -> String+pgm_windres dflags = sPgm_windres (settings dflags)+pgm_libtool :: DynFlags -> String+pgm_libtool dflags = sPgm_libtool (settings dflags)+pgm_lo :: DynFlags -> (String,[Option])+pgm_lo dflags = sPgm_lo (settings dflags)+pgm_lc :: DynFlags -> (String,[Option])+pgm_lc dflags = sPgm_lc (settings dflags)+pgm_i :: DynFlags -> String+pgm_i dflags = sPgm_i (settings dflags)+opt_L :: DynFlags -> [String]+opt_L dflags = sOpt_L (settings dflags)+opt_P :: DynFlags -> [String]+opt_P dflags = concatMap (wayOptP (targetPlatform dflags)) (ways dflags)+ ++ sOpt_P (settings dflags)+opt_F :: DynFlags -> [String]+opt_F dflags = sOpt_F (settings dflags)+opt_c :: DynFlags -> [String]+opt_c dflags = concatMap (wayOptc (targetPlatform dflags)) (ways dflags)+ ++ sOpt_c (settings dflags)+opt_a :: DynFlags -> [String]+opt_a dflags = sOpt_a (settings dflags)+opt_l :: DynFlags -> [String]+opt_l dflags = concatMap (wayOptl (targetPlatform dflags)) (ways dflags)+ ++ sOpt_l (settings dflags)+opt_windres :: DynFlags -> [String]+opt_windres dflags = sOpt_windres (settings dflags)+opt_lo :: DynFlags -> [String]+opt_lo dflags = sOpt_lo (settings dflags)+opt_lc :: DynFlags -> [String]+opt_lc dflags = sOpt_lc (settings dflags)+opt_i :: DynFlags -> [String]+opt_i dflags = sOpt_i (settings dflags)++-- | The directory for this version of ghc in the user's app directory+-- (typically something like @~/.ghc/x86_64-linux-7.6.3@)+--+versionedAppDir :: DynFlags -> MaybeT IO FilePath+versionedAppDir dflags = do+ -- Make sure we handle the case the HOME isn't set (see #11678)+ appdir <- tryMaybeT $ getAppUserDataDirectory (programName dflags)+ return $ appdir </> versionedFilePath dflags++-- | A filepath like @x86_64-linux-7.6.3@ with the platform string to use when+-- constructing platform-version-dependent files that need to co-exist.+--+versionedFilePath :: DynFlags -> FilePath+versionedFilePath dflags = TARGET_ARCH+ ++ '-':TARGET_OS+ ++ '-':projectVersion dflags+ -- NB: This functionality is reimplemented in Cabal, so if you+ -- change it, be sure to update Cabal.++-- | The target code type of the compilation (if any).+--+-- Whenever you change the target, also make sure to set 'ghcLink' to+-- something sensible.+--+-- 'HscNothing' can be used to avoid generating any output, however, note+-- that:+--+-- * If a program uses Template Haskell the typechecker may try to run code+-- from an imported module. This will fail if no code has been generated+-- for this module. You can use 'GHC.needsTemplateHaskell' to detect+-- whether this might be the case and choose to either switch to a+-- different target or avoid typechecking such modules. (The latter may be+-- preferable for security reasons.)+--+data HscTarget+ = HscC -- ^ Generate C code.+ | HscAsm -- ^ Generate assembly using the native code generator.+ | HscLlvm -- ^ Generate assembly using the llvm code generator.+ | HscInterpreted -- ^ Generate bytecode. (Requires 'LinkInMemory')+ | HscNothing -- ^ Don't generate any code. See notes above.+ deriving (Eq, Show)++-- | Will this target result in an object file on the disk?+isObjectTarget :: HscTarget -> Bool+isObjectTarget HscC = True+isObjectTarget HscAsm = True+isObjectTarget HscLlvm = True+isObjectTarget _ = False++-- | Does this target retain *all* top-level bindings for a module,+-- rather than just the exported bindings, in the TypeEnv and compiled+-- code (if any)? In interpreted mode we do this, so that GHCi can+-- call functions inside a module. In HscNothing mode we also do it,+-- so that Haddock can get access to the GlobalRdrEnv for a module+-- after typechecking it.+targetRetainsAllBindings :: HscTarget -> Bool+targetRetainsAllBindings HscInterpreted = True+targetRetainsAllBindings HscNothing = True+targetRetainsAllBindings _ = False++-- | The 'GhcMode' tells us whether we're doing multi-module+-- compilation (controlled via the "GHC" API) or one-shot+-- (single-module) compilation. This makes a difference primarily to+-- the "Finder": in one-shot mode we look for interface files for+-- imported modules, but in multi-module mode we look for source files+-- in order to check whether they need to be recompiled.+data GhcMode+ = CompManager -- ^ @\-\-make@, GHCi, etc.+ | OneShot -- ^ @ghc -c Foo.hs@+ | MkDepend -- ^ @ghc -M@, see "Finder" for why we need this+ deriving Eq++instance Outputable GhcMode where+ ppr CompManager = text "CompManager"+ ppr OneShot = text "OneShot"+ ppr MkDepend = text "MkDepend"++isOneShot :: GhcMode -> Bool+isOneShot OneShot = True+isOneShot _other = False++-- | What to do in the link step, if there is one.+data GhcLink+ = NoLink -- ^ Don't link at all+ | LinkBinary -- ^ Link object code into a binary+ | LinkInMemory -- ^ Use the in-memory dynamic linker (works for both+ -- bytecode and object code).+ | LinkDynLib -- ^ Link objects into a dynamic lib (DLL on Windows, DSO on ELF platforms)+ | LinkStaticLib -- ^ Link objects into a static lib+ deriving (Eq, Show)++isNoLink :: GhcLink -> Bool+isNoLink NoLink = True+isNoLink _ = False++-- | We accept flags which make packages visible, but how they select+-- the package varies; this data type reflects what selection criterion+-- is used.+data PackageArg =+ PackageArg String -- ^ @-package@, by 'PackageName'+ | UnitIdArg UnitId -- ^ @-package-id@, by 'UnitId'+ deriving (Eq, Show)+instance Outputable PackageArg where+ ppr (PackageArg pn) = text "package" <+> text pn+ ppr (UnitIdArg uid) = text "unit" <+> ppr uid++-- | Represents the renaming that may be associated with an exposed+-- package, e.g. the @rns@ part of @-package "foo (rns)"@.+--+-- Here are some example parsings of the package flags (where+-- a string literal is punned to be a 'ModuleName':+--+-- * @-package foo@ is @ModRenaming True []@+-- * @-package foo ()@ is @ModRenaming False []@+-- * @-package foo (A)@ is @ModRenaming False [("A", "A")]@+-- * @-package foo (A as B)@ is @ModRenaming False [("A", "B")]@+-- * @-package foo with (A as B)@ is @ModRenaming True [("A", "B")]@+data ModRenaming = ModRenaming {+ modRenamingWithImplicit :: Bool, -- ^ Bring all exposed modules into scope?+ modRenamings :: [(ModuleName, ModuleName)] -- ^ Bring module @m@ into scope+ -- under name @n@.+ } deriving (Eq)+instance Outputable ModRenaming where+ ppr (ModRenaming b rns) = ppr b <+> parens (ppr rns)++-- | Flags for manipulating the set of non-broken packages.+newtype IgnorePackageFlag = IgnorePackage String -- ^ @-ignore-package@+ deriving (Eq)++-- | Flags for manipulating package trust.+data TrustFlag+ = TrustPackage String -- ^ @-trust@+ | DistrustPackage String -- ^ @-distrust@+ deriving (Eq)++-- | Flags for manipulating packages visibility.+data PackageFlag+ = ExposePackage String PackageArg ModRenaming -- ^ @-package@, @-package-id@+ | HidePackage String -- ^ @-hide-package@+ deriving (Eq) -- NB: equality instance is used by packageFlagsChanged++data PackageDBFlag+ = PackageDB PkgConfRef+ | NoUserPackageDB+ | NoGlobalPackageDB+ | ClearPackageDBs+ deriving (Eq)++packageFlagsChanged :: DynFlags -> DynFlags -> Bool+packageFlagsChanged idflags1 idflags0 =+ packageFlags idflags1 /= packageFlags idflags0 ||+ ignorePackageFlags idflags1 /= ignorePackageFlags idflags0 ||+ pluginPackageFlags idflags1 /= pluginPackageFlags idflags0 ||+ trustFlags idflags1 /= trustFlags idflags0 ||+ packageDBFlags idflags1 /= packageDBFlags idflags0 ||+ packageGFlags idflags1 /= packageGFlags idflags0+ where+ packageGFlags dflags = map (`gopt` dflags)+ [ Opt_HideAllPackages+ , Opt_HideAllPluginPackages+ , Opt_AutoLinkPackages ]++instance Outputable PackageFlag where+ ppr (ExposePackage n arg rn) = text n <> braces (ppr arg <+> ppr rn)+ ppr (HidePackage str) = text "-hide-package" <+> text str++defaultHscTarget :: Platform -> HscTarget+defaultHscTarget = defaultObjectTarget++-- | The 'HscTarget' value corresponding to the default way to create+-- object files on the current platform.+defaultObjectTarget :: Platform -> HscTarget+defaultObjectTarget platform+ | platformUnregisterised platform = HscC+ | cGhcWithNativeCodeGen == "YES" = HscAsm+ | otherwise = HscLlvm++tablesNextToCode :: DynFlags -> Bool+tablesNextToCode dflags+ = mkTablesNextToCode (platformUnregisterised (targetPlatform dflags))++-- Determines whether we will be compiling+-- info tables that reside just before the entry code, or with an+-- indirection to the entry code. See TABLES_NEXT_TO_CODE in+-- includes/rts/storage/InfoTables.h.+mkTablesNextToCode :: Bool -> Bool+mkTablesNextToCode unregisterised+ = not unregisterised && cGhcEnableTablesNextToCode == "YES"++data DynLibLoader+ = Deployable+ | SystemDependent+ deriving Eq++data RtsOptsEnabled = RtsOptsNone | RtsOptsSafeOnly | RtsOptsAll+ deriving (Show)++shouldUseColor :: DynFlags -> Bool+shouldUseColor dflags = overrideWith (canUseColor dflags) (useColor dflags)++-----------------------------------------------------------------------------+-- Ways++-- The central concept of a "way" is that all objects in a given+-- program must be compiled in the same "way". Certain options change+-- parameters of the virtual machine, eg. profiling adds an extra word+-- to the object header, so profiling objects cannot be linked with+-- non-profiling objects.++-- After parsing the command-line options, we determine which "way" we+-- are building - this might be a combination way, eg. profiling+threaded.++-- We then find the "build-tag" associated with this way, and this+-- becomes the suffix used to find .hi files and libraries used in+-- this compilation.++data Way+ = WayCustom String -- for GHC API clients building custom variants+ | WayThreaded+ | WayDebug+ | WayProf+ | WayEventLog+ | WayDyn+ deriving (Eq, Ord, Show)++allowed_combination :: [Way] -> Bool+allowed_combination way = and [ x `allowedWith` y+ | x <- way, y <- way, x < y ]+ where+ -- Note ordering in these tests: the left argument is+ -- <= the right argument, according to the Ord instance+ -- on Way above.++ -- dyn is allowed with everything+ _ `allowedWith` WayDyn = True+ WayDyn `allowedWith` _ = True++ -- debug is allowed with everything+ _ `allowedWith` WayDebug = True+ WayDebug `allowedWith` _ = True++ (WayCustom {}) `allowedWith` _ = True+ WayThreaded `allowedWith` WayProf = True+ WayThreaded `allowedWith` WayEventLog = True+ WayProf `allowedWith` WayEventLog = True+ _ `allowedWith` _ = False++mkBuildTag :: [Way] -> String+mkBuildTag ways = concat (intersperse "_" (map wayTag ways))++wayTag :: Way -> String+wayTag (WayCustom xs) = xs+wayTag WayThreaded = "thr"+wayTag WayDebug = "debug"+wayTag WayDyn = "dyn"+wayTag WayProf = "p"+wayTag WayEventLog = "l"++wayRTSOnly :: Way -> Bool+wayRTSOnly (WayCustom {}) = False+wayRTSOnly WayThreaded = True+wayRTSOnly WayDebug = True+wayRTSOnly WayDyn = False+wayRTSOnly WayProf = False+wayRTSOnly WayEventLog = True++wayDesc :: Way -> String+wayDesc (WayCustom xs) = xs+wayDesc WayThreaded = "Threaded"+wayDesc WayDebug = "Debug"+wayDesc WayDyn = "Dynamic"+wayDesc WayProf = "Profiling"+wayDesc WayEventLog = "RTS Event Logging"++-- Turn these flags on when enabling this way+wayGeneralFlags :: Platform -> Way -> [GeneralFlag]+wayGeneralFlags _ (WayCustom {}) = []+wayGeneralFlags _ WayThreaded = []+wayGeneralFlags _ WayDebug = []+wayGeneralFlags _ WayDyn = [Opt_PIC]+ -- We could get away without adding -fPIC when compiling the+ -- modules of a program that is to be linked with -dynamic; the+ -- program itself does not need to be position-independent, only+ -- the libraries need to be. HOWEVER, GHCi links objects into a+ -- .so before loading the .so using the system linker. Since only+ -- PIC objects can be linked into a .so, we have to compile even+ -- modules of the main program with -fPIC when using -dynamic.+wayGeneralFlags _ WayProf = [Opt_SccProfilingOn]+wayGeneralFlags _ WayEventLog = []++-- Turn these flags off when enabling this way+wayUnsetGeneralFlags :: Platform -> Way -> [GeneralFlag]+wayUnsetGeneralFlags _ (WayCustom {}) = []+wayUnsetGeneralFlags _ WayThreaded = []+wayUnsetGeneralFlags _ WayDebug = []+wayUnsetGeneralFlags _ WayDyn = [-- There's no point splitting objects+ -- when we're going to be dynamically+ -- linking. Plus it breaks compilation+ -- on OSX x86.+ Opt_SplitObjs,+ -- If splitobjs wasn't useful for this,+ -- assume sections aren't either.+ Opt_SplitSections]+wayUnsetGeneralFlags _ WayProf = []+wayUnsetGeneralFlags _ WayEventLog = []++wayOptc :: Platform -> Way -> [String]+wayOptc _ (WayCustom {}) = []+wayOptc platform WayThreaded = case platformOS platform of+ OSOpenBSD -> ["-pthread"]+ OSNetBSD -> ["-pthread"]+ _ -> []+wayOptc _ WayDebug = []+wayOptc _ WayDyn = []+wayOptc _ WayProf = ["-DPROFILING"]+wayOptc _ WayEventLog = ["-DTRACING"]++wayOptl :: Platform -> Way -> [String]+wayOptl _ (WayCustom {}) = []+wayOptl platform WayThreaded =+ case platformOS platform of+ -- FreeBSD's default threading library is the KSE-based M:N libpthread,+ -- which GHC has some problems with. It's currently not clear whether+ -- the problems are our fault or theirs, but it seems that using the+ -- alternative 1:1 threading library libthr works around it:+ OSFreeBSD -> ["-lthr"]+ OSOpenBSD -> ["-pthread"]+ OSNetBSD -> ["-pthread"]+ _ -> []+wayOptl _ WayDebug = []+wayOptl _ WayDyn = []+wayOptl _ WayProf = []+wayOptl _ WayEventLog = []++wayOptP :: Platform -> Way -> [String]+wayOptP _ (WayCustom {}) = []+wayOptP _ WayThreaded = []+wayOptP _ WayDebug = []+wayOptP _ WayDyn = []+wayOptP _ WayProf = ["-DPROFILING"]+wayOptP _ WayEventLog = ["-DTRACING"]++whenGeneratingDynamicToo :: MonadIO m => DynFlags -> m () -> m ()+whenGeneratingDynamicToo dflags f = ifGeneratingDynamicToo dflags f (return ())++ifGeneratingDynamicToo :: MonadIO m => DynFlags -> m a -> m a -> m a+ifGeneratingDynamicToo dflags f g = generateDynamicTooConditional dflags f g g++whenCannotGenerateDynamicToo :: MonadIO m => DynFlags -> m () -> m ()+whenCannotGenerateDynamicToo dflags f+ = ifCannotGenerateDynamicToo dflags f (return ())++ifCannotGenerateDynamicToo :: MonadIO m => DynFlags -> m a -> m a -> m a+ifCannotGenerateDynamicToo dflags f g+ = generateDynamicTooConditional dflags g f g++generateDynamicTooConditional :: MonadIO m+ => DynFlags -> m a -> m a -> m a -> m a+generateDynamicTooConditional dflags canGen cannotGen notTryingToGen+ = if gopt Opt_BuildDynamicToo dflags+ then do let ref = canGenerateDynamicToo dflags+ b <- liftIO $ readIORef ref+ if b then canGen else cannotGen+ else notTryingToGen++dynamicTooMkDynamicDynFlags :: DynFlags -> DynFlags+dynamicTooMkDynamicDynFlags dflags0+ = let dflags1 = addWay' WayDyn dflags0+ dflags2 = dflags1 {+ outputFile = dynOutputFile dflags1,+ hiSuf = dynHiSuf dflags1,+ objectSuf = dynObjectSuf dflags1+ }+ dflags3 = updateWays dflags2+ dflags4 = gopt_unset dflags3 Opt_BuildDynamicToo+ in dflags4++-----------------------------------------------------------------------------++-- | Used by 'GHC.runGhc' to partially initialize a new 'DynFlags' value+initDynFlags :: DynFlags -> IO DynFlags+initDynFlags dflags = do+ let -- We can't build with dynamic-too on Windows, as labels before+ -- the fork point are different depending on whether we are+ -- building dynamically or not.+ platformCanGenerateDynamicToo+ = platformOS (targetPlatform dflags) /= OSMinGW32+ refCanGenerateDynamicToo <- newIORef platformCanGenerateDynamicToo+ refNextTempSuffix <- newIORef 0+ refFilesToClean <- newIORef []+ refDirsToClean <- newIORef Map.empty+ refFilesToNotIntermediateClean <- newIORef []+ refGeneratedDumps <- newIORef Set.empty+ refRtldInfo <- newIORef Nothing+ refRtccInfo <- newIORef Nothing+ wrapperNum <- newIORef emptyModuleEnv+ canUseUnicode <- do let enc = localeEncoding+ str = "‘’"+ (withCString enc str $ \cstr ->+ do str' <- peekCString enc cstr+ return (str == str'))+ `catchIOError` \_ -> return False+ canUseColor <- stderrSupportsAnsiColors+ maybeGhcColorsEnv <- lookupEnv "GHC_COLORS"+ maybeGhcColoursEnv <- lookupEnv "GHC_COLOURS"+ let adjustCols (Just env) = Col.parseScheme env+ adjustCols Nothing = id+ let (useColor', colScheme') =+ (adjustCols maybeGhcColoursEnv . adjustCols maybeGhcColorsEnv)+ (useColor dflags, colScheme dflags)+ return dflags{+ canGenerateDynamicToo = refCanGenerateDynamicToo,+ nextTempSuffix = refNextTempSuffix,+ filesToClean = refFilesToClean,+ dirsToClean = refDirsToClean,+ filesToNotIntermediateClean = refFilesToNotIntermediateClean,+ generatedDumps = refGeneratedDumps,+ nextWrapperNum = wrapperNum,+ useUnicode = canUseUnicode,+ useColor = useColor',+ canUseColor = canUseColor,+ colScheme = colScheme',+ rtldInfo = refRtldInfo,+ rtccInfo = refRtccInfo+ }++-- | The normal 'DynFlags'. Note that they are not suitable for use in this form+-- and must be fully initialized by 'GHC.runGhc' first.+defaultDynFlags :: Settings -> DynFlags+defaultDynFlags mySettings =+-- See Note [Updating flag description in the User's Guide]+ DynFlags {+ ghcMode = CompManager,+ ghcLink = LinkBinary,+ hscTarget = defaultHscTarget (sTargetPlatform mySettings),+ verbosity = 0,+ optLevel = 0,+ debugLevel = 0,+ simplPhases = 2,+ maxSimplIterations = 4,+ maxPmCheckIterations = 2000000,+ ruleCheck = Nothing,+ maxRelevantBinds = Just 6,+ maxUncoveredPatterns = 4,+ simplTickFactor = 100,+ specConstrThreshold = Just 2000,+ specConstrCount = Just 3,+ specConstrRecursive = 3,+ liberateCaseThreshold = Just 2000,+ floatLamArgs = Just 0, -- Default: float only if no fvs++ historySize = 20,+ strictnessBefore = [],++ parMakeCount = Just 1,++ enableTimeStats = False,+ ghcHeapSize = Nothing,++ importPaths = ["."],+ mainModIs = mAIN,+ mainFunIs = Nothing,+ reductionDepth = treatZeroAsInf mAX_REDUCTION_DEPTH,+ solverIterations = treatZeroAsInf mAX_SOLVER_ITERATIONS,++ thisInstalledUnitId = toInstalledUnitId mainUnitId,+ thisUnitIdInsts_ = Nothing,+ thisComponentId_ = Nothing,++ objectDir = Nothing,+ dylibInstallName = Nothing,+ hiDir = Nothing,+ stubDir = Nothing,+ dumpDir = Nothing,++ objectSuf = phaseInputExt StopLn,+ hcSuf = phaseInputExt HCc,+ hiSuf = "hi",++ canGenerateDynamicToo = panic "defaultDynFlags: No canGenerateDynamicToo",+ dynObjectSuf = "dyn_" ++ phaseInputExt StopLn,+ dynHiSuf = "dyn_hi",++ dllSplitFile = Nothing,+ dllSplit = Nothing,++ pluginModNames = [],+ pluginModNameOpts = [],+ frontendPluginOpts = [],+ hooks = emptyHooks,++ outputFile = Nothing,+ dynOutputFile = Nothing,+ outputHi = Nothing,+ dynLibLoader = SystemDependent,+ dumpPrefix = Nothing,+ dumpPrefixForce = Nothing,+ ldInputs = [],+ includePaths = [],+ libraryPaths = [],+ frameworkPaths = [],+ cmdlineFrameworks = [],+ rtsOpts = Nothing,+ rtsOptsEnabled = RtsOptsSafeOnly,+ rtsOptsSuggestions = True,++ hpcDir = ".hpc",++ packageDBFlags = [],+ packageFlags = [],+ pluginPackageFlags = [],+ ignorePackageFlags = [],+ trustFlags = [],+ packageEnv = Nothing,+ pkgDatabase = Nothing,+ -- This gets filled in with GHC.setSessionDynFlags+ pkgState = emptyPackageState,+ ways = defaultWays mySettings,+ buildTag = mkBuildTag (defaultWays mySettings),+ rtsBuildTag = mkBuildTag (defaultWays mySettings),+ splitInfo = Nothing,+ settings = mySettings,+ -- ghc -M values+ depMakefile = "Makefile",+ depIncludePkgDeps = False,+ depExcludeMods = [],+ depSuffixes = [],+ -- end of ghc -M values+ nextTempSuffix = panic "defaultDynFlags: No nextTempSuffix",+ filesToClean = panic "defaultDynFlags: No filesToClean",+ dirsToClean = panic "defaultDynFlags: No dirsToClean",+ filesToNotIntermediateClean = panic "defaultDynFlags: No filesToNotIntermediateClean",+ generatedDumps = panic "defaultDynFlags: No generatedDumps",+ haddockOptions = Nothing,+ dumpFlags = IntSet.empty,+ generalFlags = IntSet.fromList (map fromEnum (defaultFlags mySettings)),+ warningFlags = IntSet.fromList (map fromEnum standardWarnings),+ fatalWarningFlags = IntSet.empty,+ ghciScripts = [],+ language = Nothing,+ safeHaskell = Sf_None,+ safeInfer = True,+ safeInferred = True,+ thOnLoc = noSrcSpan,+ newDerivOnLoc = noSrcSpan,+ overlapInstLoc = noSrcSpan,+ incoherentOnLoc = noSrcSpan,+ pkgTrustOnLoc = noSrcSpan,+ warnSafeOnLoc = noSrcSpan,+ warnUnsafeOnLoc = noSrcSpan,+ trustworthyOnLoc = noSrcSpan,+ extensions = [],+ extensionFlags = flattenExtensionFlags Nothing [],++ -- The ufCreationThreshold threshold must be reasonably high to+ -- take account of possible discounts.+ -- E.g. 450 is not enough in 'fulsom' for Interval.sqr to inline+ -- into Csg.calc (The unfolding for sqr never makes it into the+ -- interface file.)+ ufCreationThreshold = 750,+ ufUseThreshold = 60,+ ufFunAppDiscount = 60,+ -- Be fairly keen to inline a function if that means+ -- we'll be able to pick the right method from a dictionary+ ufDictDiscount = 30,+ ufKeenessFactor = 1.5,+ ufDearOp = 40,+ ufVeryAggressive = False,++ maxWorkerArgs = 10,++ ghciHistSize = 50, -- keep a log of length 50 by default++ -- Logging++ initLogAction = defaultLogOutput,++ log_action = defaultLogAction,+ log_finaliser = \ _ -> return (),++ flushOut = defaultFlushOut,+ flushErr = defaultFlushErr,+ pprUserLength = 5,+ pprCols = 100,+ useUnicode = False,+ useColor = Auto,+ canUseColor = False,+ colScheme = Col.defaultScheme,+ profAuto = NoProfAuto,+ interactivePrint = Nothing,+ nextWrapperNum = panic "defaultDynFlags: No nextWrapperNum",+ sseVersion = Nothing,+ avx = False,+ avx2 = False,+ avx512cd = False,+ avx512er = False,+ avx512f = False,+ avx512pf = False,+ rtldInfo = panic "defaultDynFlags: no rtldInfo",+ rtccInfo = panic "defaultDynFlags: no rtccInfo",++ maxInlineAllocSize = 128,+ maxInlineMemcpyInsns = 32,+ maxInlineMemsetInsns = 32,++ initialUnique = 0,+ uniqueIncrement = 1,++ reverseErrors = False,+ maxErrors = Nothing+ }++defaultWays :: Settings -> [Way]+defaultWays settings = if pc_DYNAMIC_BY_DEFAULT (sPlatformConstants settings)+ then [WayDyn]+ else []++interpWays :: [Way]+interpWays+ | dynamicGhc = [WayDyn]+ | rtsIsProfiled = [WayProf]+ | otherwise = []++interpreterProfiled :: DynFlags -> Bool+interpreterProfiled dflags+ | gopt Opt_ExternalInterpreter dflags = gopt Opt_SccProfilingOn dflags+ | otherwise = rtsIsProfiled++interpreterDynamic :: DynFlags -> Bool+interpreterDynamic dflags+ | gopt Opt_ExternalInterpreter dflags = WayDyn `elem` ways dflags+ | otherwise = dynamicGhc++--------------------------------------------------------------------------+--+-- Note [JSON Error Messages]+--+-- When the user requests the compiler output to be dumped as json+-- we modify the log_action to collect all the messages in an IORef+-- and then finally in GHC.withCleanupSession the log_finaliser is+-- called which prints out the messages together.+--+-- Before the compiler calls log_action, it has already turned the `ErrMsg`+-- into a formatted message. This means that we lose some possible+-- information to provide to the user but refactoring log_action is quite+-- invasive as it is called in many places. So, for now I left it alone+-- and we can refine its behaviour as users request different output.++type FatalMessager = String -> IO ()++data LogOutput = LogOutput+ { getLogAction :: LogAction+ , getLogFinaliser :: LogFinaliser+ }++defaultLogOutput :: IO (Maybe LogOutput)+defaultLogOutput = return $ Nothing++type LogAction = DynFlags+ -> WarnReason+ -> Severity+ -> SrcSpan+ -> PprStyle+ -> MsgDoc+ -> IO ()++type LogFinaliser = DynFlags -> IO ()++defaultFatalMessager :: FatalMessager+defaultFatalMessager = hPutStrLn stderr+++-- See Note [JSON Error Messages]+jsonLogOutput :: IO (Maybe LogOutput)+jsonLogOutput = do+ ref <- newIORef []+ return . Just $ LogOutput (jsonLogAction ref) (jsonLogFinaliser ref)++jsonLogAction :: IORef [SDoc] -> LogAction+jsonLogAction iref dflags reason severity srcSpan style msg+ = do+ addMessage . withPprStyle (mkCodeStyle CStyle) . renderJSON $+ JSObject [ ( "span", json srcSpan )+ , ( "doc" , JSString (showSDoc dflags msg) )+ , ( "severity", json severity )+ , ( "reason" , json reason )+ ]+ defaultLogAction dflags reason severity srcSpan style msg+ where+ addMessage m = modifyIORef iref (m:)+++jsonLogFinaliser :: IORef [SDoc] -> DynFlags -> IO ()+jsonLogFinaliser iref dflags = do+ msgs <- readIORef iref+ let fmt_msgs = brackets $ pprWithCommas (blankLine $$) msgs+ output fmt_msgs+ where+ -- dumpSDoc uses log_action to output the dump+ dflags' = dflags { log_action = defaultLogAction }+ output doc = dumpSDoc dflags' neverQualify Opt_D_dump_json "" doc+++defaultLogAction :: LogAction+defaultLogAction dflags reason severity srcSpan style msg+ = case severity of+ SevOutput -> printOut msg style+ SevDump -> printOut (msg $$ blankLine) style+ SevInteractive -> putStrSDoc msg style+ SevInfo -> printErrs msg style+ SevFatal -> printErrs msg style+ _ -> do -- otherwise (i.e. SevError or SevWarning)+ hPutChar stderr '\n'+ caretDiagnostic <-+ if gopt Opt_DiagnosticsShowCaret dflags+ then getCaretDiagnostic severity srcSpan+ else pure empty+ printErrs (message $+$ caretDiagnostic)+ (setStyleColoured True style)+ -- careful (#2302): printErrs prints in UTF-8,+ -- whereas converting to string first and using+ -- hPutStr would just emit the low 8 bits of+ -- each unicode char.+ where printOut = defaultLogActionHPrintDoc dflags stdout+ printErrs = defaultLogActionHPrintDoc dflags stderr+ putStrSDoc = defaultLogActionHPutStrDoc dflags stdout+ -- Pretty print the warning flag, if any (#10752)+ message = mkLocMessageAnn flagMsg severity srcSpan msg+ flagMsg = case reason of+ NoReason -> Nothing+ Reason flag -> (\spec -> "-W" ++ flagSpecName spec ++ flagGrp flag) <$>+ flagSpecOf flag++ flagGrp flag+ | gopt Opt_ShowWarnGroups dflags =+ case smallestGroups flag of+ [] -> ""+ groups -> " (in " ++ intercalate ", " (map ("-W"++) groups) ++ ")"+ | otherwise = ""++-- | Like 'defaultLogActionHPutStrDoc' but appends an extra newline.+defaultLogActionHPrintDoc :: DynFlags -> Handle -> SDoc -> PprStyle -> IO ()+defaultLogActionHPrintDoc dflags h d sty+ = defaultLogActionHPutStrDoc dflags h (d $$ text "") sty++defaultLogActionHPutStrDoc :: DynFlags -> Handle -> SDoc -> PprStyle -> IO ()+defaultLogActionHPutStrDoc dflags h d sty+ -- Don't add a newline at the end, so that successive+ -- calls to this log-action can output all on the same line+ = printSDoc Pretty.PageMode dflags h sty d++newtype FlushOut = FlushOut (IO ())++defaultFlushOut :: FlushOut+defaultFlushOut = FlushOut $ hFlush stdout++newtype FlushErr = FlushErr (IO ())++defaultFlushErr :: FlushErr+defaultFlushErr = FlushErr $ hFlush stderr++{-+Note [Verbosity levels]+~~~~~~~~~~~~~~~~~~~~~~~+ 0 | print errors & warnings only+ 1 | minimal verbosity: print "compiling M ... done." for each module.+ 2 | equivalent to -dshow-passes+ 3 | equivalent to existing "ghc -v"+ 4 | "ghc -v -ddump-most"+ 5 | "ghc -v -ddump-all"+-}++data OnOff a = On a+ | Off a+ deriving (Eq, Show)++instance Outputable a => Outputable (OnOff a) where+ ppr (On x) = text "On" <+> ppr x+ ppr (Off x) = text "Off" <+> ppr x++-- OnOffs accumulate in reverse order, so we use foldr in order to+-- process them in the right order+flattenExtensionFlags :: Maybe Language -> [OnOff LangExt.Extension] -> IntSet+flattenExtensionFlags ml = foldr f defaultExtensionFlags+ where f (On f) flags = IntSet.insert (fromEnum f) flags+ f (Off f) flags = IntSet.delete (fromEnum f) flags+ defaultExtensionFlags = IntSet.fromList (map fromEnum (languageExtensions ml))++languageExtensions :: Maybe Language -> [LangExt.Extension]++languageExtensions Nothing+ -- Nothing => the default case+ = LangExt.NondecreasingIndentation -- This has been on by default for some time+ : delete LangExt.DatatypeContexts -- The Haskell' committee decided to+ -- remove datatype contexts from the+ -- language:+ -- http://www.haskell.org/pipermail/haskell-prime/2011-January/003335.html+ (languageExtensions (Just Haskell2010))++ -- NB: MonoPatBinds is no longer the default++languageExtensions (Just Haskell98)+ = [LangExt.ImplicitPrelude,+ LangExt.MonomorphismRestriction,+ LangExt.NPlusKPatterns,+ LangExt.DatatypeContexts,+ LangExt.TraditionalRecordSyntax,+ LangExt.NondecreasingIndentation+ -- strictly speaking non-standard, but we always had this+ -- on implicitly before the option was added in 7.1, and+ -- turning it off breaks code, so we're keeping it on for+ -- backwards compatibility. Cabal uses -XHaskell98 by+ -- default unless you specify another language.+ ]++languageExtensions (Just Haskell2010)+ = [LangExt.ImplicitPrelude,+ LangExt.MonomorphismRestriction,+ LangExt.DatatypeContexts,+ LangExt.TraditionalRecordSyntax,+ LangExt.EmptyDataDecls,+ LangExt.ForeignFunctionInterface,+ LangExt.PatternGuards,+ LangExt.DoAndIfThenElse,+ LangExt.RelaxedPolyRec]++hasPprDebug :: DynFlags -> Bool+hasPprDebug = dopt Opt_D_ppr_debug++hasNoDebugOutput :: DynFlags -> Bool+hasNoDebugOutput = dopt Opt_D_no_debug_output++hasNoStateHack :: DynFlags -> Bool+hasNoStateHack = gopt Opt_G_NoStateHack++hasNoOptCoercion :: DynFlags -> Bool+hasNoOptCoercion = gopt Opt_G_NoOptCoercion+++-- | Test whether a 'DumpFlag' is set+dopt :: DumpFlag -> DynFlags -> Bool+dopt f dflags = (fromEnum f `IntSet.member` dumpFlags dflags)+ || (verbosity dflags >= 4 && enableIfVerbose f)+ where enableIfVerbose Opt_D_dump_tc_trace = False+ enableIfVerbose Opt_D_dump_rn_trace = False+ enableIfVerbose Opt_D_dump_cs_trace = False+ enableIfVerbose Opt_D_dump_if_trace = False+ enableIfVerbose Opt_D_dump_vt_trace = False+ enableIfVerbose Opt_D_dump_tc = False+ enableIfVerbose Opt_D_dump_rn = False+ enableIfVerbose Opt_D_dump_shape = False+ enableIfVerbose Opt_D_dump_rn_stats = False+ enableIfVerbose Opt_D_dump_hi_diffs = False+ enableIfVerbose Opt_D_verbose_core2core = False+ enableIfVerbose Opt_D_verbose_stg2stg = False+ enableIfVerbose Opt_D_dump_splices = False+ enableIfVerbose Opt_D_th_dec_file = False+ enableIfVerbose Opt_D_dump_rule_firings = False+ enableIfVerbose Opt_D_dump_rule_rewrites = False+ enableIfVerbose Opt_D_dump_simpl_trace = False+ enableIfVerbose Opt_D_dump_rtti = False+ enableIfVerbose Opt_D_dump_inlinings = False+ enableIfVerbose Opt_D_dump_core_stats = False+ enableIfVerbose Opt_D_dump_asm_stats = False+ enableIfVerbose Opt_D_dump_types = False+ enableIfVerbose Opt_D_dump_simpl_iterations = False+ enableIfVerbose Opt_D_dump_ticked = False+ enableIfVerbose Opt_D_dump_view_pattern_commoning = False+ enableIfVerbose Opt_D_dump_mod_cycles = False+ enableIfVerbose Opt_D_dump_mod_map = False+ enableIfVerbose Opt_D_dump_ec_trace = False+ enableIfVerbose _ = True++-- | Set a 'DumpFlag'+dopt_set :: DynFlags -> DumpFlag -> DynFlags+dopt_set dfs f = dfs{ dumpFlags = IntSet.insert (fromEnum f) (dumpFlags dfs) }++-- | Unset a 'DumpFlag'+dopt_unset :: DynFlags -> DumpFlag -> DynFlags+dopt_unset dfs f = dfs{ dumpFlags = IntSet.delete (fromEnum f) (dumpFlags dfs) }++-- | Test whether a 'GeneralFlag' is set+gopt :: GeneralFlag -> DynFlags -> Bool+gopt f dflags = fromEnum f `IntSet.member` generalFlags dflags++-- | Set a 'GeneralFlag'+gopt_set :: DynFlags -> GeneralFlag -> DynFlags+gopt_set dfs f = dfs{ generalFlags = IntSet.insert (fromEnum f) (generalFlags dfs) }++-- | Unset a 'GeneralFlag'+gopt_unset :: DynFlags -> GeneralFlag -> DynFlags+gopt_unset dfs f = dfs{ generalFlags = IntSet.delete (fromEnum f) (generalFlags dfs) }++-- | Test whether a 'WarningFlag' is set+wopt :: WarningFlag -> DynFlags -> Bool+wopt f dflags = fromEnum f `IntSet.member` warningFlags dflags++-- | Set a 'WarningFlag'+wopt_set :: DynFlags -> WarningFlag -> DynFlags+wopt_set dfs f = dfs{ warningFlags = IntSet.insert (fromEnum f) (warningFlags dfs) }++-- | Unset a 'WarningFlag'+wopt_unset :: DynFlags -> WarningFlag -> DynFlags+wopt_unset dfs f = dfs{ warningFlags = IntSet.delete (fromEnum f) (warningFlags dfs) }++-- | Test whether a 'WarningFlag' is set as fatal+wopt_fatal :: WarningFlag -> DynFlags -> Bool+wopt_fatal f dflags = fromEnum f `IntSet.member` fatalWarningFlags dflags++-- | Mark a 'WarningFlag' as fatal (do not set the flag)+wopt_set_fatal :: DynFlags -> WarningFlag -> DynFlags+wopt_set_fatal dfs f+ = dfs { fatalWarningFlags =+ IntSet.insert (fromEnum f) (fatalWarningFlags dfs) }++-- | Mark a 'WarningFlag' as not fatal+wopt_unset_fatal :: DynFlags -> WarningFlag -> DynFlags+wopt_unset_fatal dfs f+ = dfs { fatalWarningFlags =+ IntSet.delete (fromEnum f) (fatalWarningFlags dfs) }++-- | Test whether a 'LangExt.Extension' is set+xopt :: LangExt.Extension -> DynFlags -> Bool+xopt f dflags = fromEnum f `IntSet.member` extensionFlags dflags++-- | Set a 'LangExt.Extension'+xopt_set :: DynFlags -> LangExt.Extension -> DynFlags+xopt_set dfs f+ = let onoffs = On f : extensions dfs+ in dfs { extensions = onoffs,+ extensionFlags = flattenExtensionFlags (language dfs) onoffs }++-- | Unset a 'LangExt.Extension'+xopt_unset :: DynFlags -> LangExt.Extension -> DynFlags+xopt_unset dfs f+ = let onoffs = Off f : extensions dfs+ in dfs { extensions = onoffs,+ extensionFlags = flattenExtensionFlags (language dfs) onoffs }++lang_set :: DynFlags -> Maybe Language -> DynFlags+lang_set dflags lang =+ dflags {+ language = lang,+ extensionFlags = flattenExtensionFlags lang (extensions dflags)+ }++-- | An internal helper to check whether to use unicode syntax for output.+--+-- Note: You should very likely be using 'Outputable.unicodeSyntax' instead+-- of this function.+useUnicodeSyntax :: DynFlags -> Bool+useUnicodeSyntax = gopt Opt_PrintUnicodeSyntax++-- | Set the Haskell language standard to use+setLanguage :: Language -> DynP ()+setLanguage l = upd (`lang_set` Just l)++-- | Some modules have dependencies on others through the DynFlags rather than textual imports+dynFlagDependencies :: DynFlags -> [ModuleName]+dynFlagDependencies = pluginModNames++-- | Is the -fpackage-trust mode on+packageTrustOn :: DynFlags -> Bool+packageTrustOn = gopt Opt_PackageTrust++-- | Is Safe Haskell on in some way (including inference mode)+safeHaskellOn :: DynFlags -> Bool+safeHaskellOn dflags = safeHaskell dflags /= Sf_None || safeInferOn dflags++-- | Is the Safe Haskell safe language in use+safeLanguageOn :: DynFlags -> Bool+safeLanguageOn dflags = safeHaskell dflags == Sf_Safe++-- | Is the Safe Haskell safe inference mode active+safeInferOn :: DynFlags -> Bool+safeInferOn = safeInfer++-- | Test if Safe Imports are on in some form+safeImportsOn :: DynFlags -> Bool+safeImportsOn dflags = safeHaskell dflags == Sf_Unsafe ||+ safeHaskell dflags == Sf_Trustworthy ||+ safeHaskell dflags == Sf_Safe++-- | Set a 'Safe Haskell' flag+setSafeHaskell :: SafeHaskellMode -> DynP ()+setSafeHaskell s = updM f+ where f dfs = do+ let sf = safeHaskell dfs+ safeM <- combineSafeFlags sf s+ case s of+ Sf_Safe -> return $ dfs { safeHaskell = safeM, safeInfer = False }+ -- leave safe inferrence on in Trustworthy mode so we can warn+ -- if it could have been inferred safe.+ Sf_Trustworthy -> do+ l <- getCurLoc+ return $ dfs { safeHaskell = safeM, trustworthyOnLoc = l }+ -- leave safe inference on in Unsafe mode as well.+ _ -> return $ dfs { safeHaskell = safeM }++-- | Are all direct imports required to be safe for this Safe Haskell mode?+-- Direct imports are when the code explicitly imports a module+safeDirectImpsReq :: DynFlags -> Bool+safeDirectImpsReq d = safeLanguageOn d++-- | Are all implicit imports required to be safe for this Safe Haskell mode?+-- Implicit imports are things in the prelude. e.g System.IO when print is used.+safeImplicitImpsReq :: DynFlags -> Bool+safeImplicitImpsReq d = safeLanguageOn d++-- | Combine two Safe Haskell modes correctly. Used for dealing with multiple flags.+-- This makes Safe Haskell very much a monoid but for now I prefer this as I don't+-- want to export this functionality from the module but do want to export the+-- type constructors.+combineSafeFlags :: SafeHaskellMode -> SafeHaskellMode -> DynP SafeHaskellMode+combineSafeFlags a b | a == Sf_None = return b+ | b == Sf_None = return a+ | a == b = return a+ | otherwise = addErr errm >> pure a+ where errm = "Incompatible Safe Haskell flags! ("+ ++ show a ++ ", " ++ show b ++ ")"++-- | A list of unsafe flags under Safe Haskell. Tuple elements are:+-- * name of the flag+-- * function to get srcspan that enabled the flag+-- * function to test if the flag is on+-- * function to turn the flag off+unsafeFlags, unsafeFlagsForInfer+ :: [(String, DynFlags -> SrcSpan, DynFlags -> Bool, DynFlags -> DynFlags)]+unsafeFlags = [ ("-XGeneralizedNewtypeDeriving", newDerivOnLoc,+ xopt LangExt.GeneralizedNewtypeDeriving,+ flip xopt_unset LangExt.GeneralizedNewtypeDeriving)+ , ("-XTemplateHaskell", thOnLoc,+ xopt LangExt.TemplateHaskell,+ flip xopt_unset LangExt.TemplateHaskell)+ ]+unsafeFlagsForInfer = unsafeFlags+++-- | Retrieve the options corresponding to a particular @opt_*@ field in the correct order+getOpts :: DynFlags -- ^ 'DynFlags' to retrieve the options from+ -> (DynFlags -> [a]) -- ^ Relevant record accessor: one of the @opt_*@ accessors+ -> [a] -- ^ Correctly ordered extracted options+getOpts dflags opts = reverse (opts dflags)+ -- We add to the options from the front, so we need to reverse the list++-- | Gets the verbosity flag for the current verbosity level. This is fed to+-- other tools, so GHC-specific verbosity flags like @-ddump-most@ are not included+getVerbFlags :: DynFlags -> [String]+getVerbFlags dflags+ | verbosity dflags >= 4 = ["-v"]+ | otherwise = []++setObjectDir, setHiDir, setStubDir, setDumpDir, setOutputDir,+ setDynObjectSuf, setDynHiSuf,+ setDylibInstallName,+ setObjectSuf, setHiSuf, setHcSuf, parseDynLibLoaderMode,+ setPgmP, addOptl, addOptc, addOptP,+ addCmdlineFramework, addHaddockOpts, addGhciScript,+ setInteractivePrint+ :: String -> DynFlags -> DynFlags+setOutputFile, setDynOutputFile, setOutputHi, setDumpPrefixForce+ :: Maybe String -> DynFlags -> DynFlags++setObjectDir f d = d { objectDir = Just f}+setHiDir f d = d { hiDir = Just f}+setStubDir f d = d { stubDir = Just f, includePaths = f : includePaths d }+ -- -stubdir D adds an implicit -I D, so that gcc can find the _stub.h file+ -- \#included from the .hc file when compiling via C (i.e. unregisterised+ -- builds).+setDumpDir f d = d { dumpDir = Just f}+setOutputDir f = setObjectDir f . setHiDir f . setStubDir f . setDumpDir f+setDylibInstallName f d = d { dylibInstallName = Just f}++setObjectSuf f d = d { objectSuf = f}+setDynObjectSuf f d = d { dynObjectSuf = f}+setHiSuf f d = d { hiSuf = f}+setDynHiSuf f d = d { dynHiSuf = f}+setHcSuf f d = d { hcSuf = f}++setOutputFile f d = d { outputFile = f}+setDynOutputFile f d = d { dynOutputFile = f}+setOutputHi f d = d { outputHi = f}++setJsonLogAction :: DynFlags -> DynFlags+setJsonLogAction d = d { initLogAction = jsonLogOutput }++thisComponentId :: DynFlags -> ComponentId+thisComponentId dflags =+ case thisComponentId_ dflags of+ Just cid -> cid+ Nothing ->+ case thisUnitIdInsts_ dflags of+ Just _ ->+ throwGhcException $ CmdLineError ("Use of -instantiated-with requires -this-component-id")+ Nothing -> ComponentId (unitIdFS (thisPackage dflags))++thisUnitIdInsts :: DynFlags -> [(ModuleName, Module)]+thisUnitIdInsts dflags =+ case thisUnitIdInsts_ dflags of+ Just insts -> insts+ Nothing -> []++thisPackage :: DynFlags -> UnitId+thisPackage dflags =+ case thisUnitIdInsts_ dflags of+ Nothing -> default_uid+ Just insts+ | all (\(x,y) -> mkHoleModule x == y) insts+ -> newUnitId (thisComponentId dflags) insts+ | otherwise+ -> default_uid+ where+ default_uid = DefiniteUnitId (DefUnitId (thisInstalledUnitId dflags))++parseUnitIdInsts :: String -> [(ModuleName, Module)]+parseUnitIdInsts str = case filter ((=="").snd) (readP_to_S parse str) of+ [(r, "")] -> r+ _ -> throwGhcException $ CmdLineError ("Can't parse -instantiated-with: " ++ str)+ where parse = sepBy parseEntry (R.char ',')+ parseEntry = do+ n <- parseModuleName+ _ <- R.char '='+ m <- parseModuleId+ return (n, m)++setUnitIdInsts :: String -> DynFlags -> DynFlags+setUnitIdInsts s d =+ d { thisUnitIdInsts_ = Just (parseUnitIdInsts s) }++setComponentId :: String -> DynFlags -> DynFlags+setComponentId s d =+ d { thisComponentId_ = Just (ComponentId (fsLit s)) }++addPluginModuleName :: String -> DynFlags -> DynFlags+addPluginModuleName name d = d { pluginModNames = (mkModuleName name) : (pluginModNames d) }++addPluginModuleNameOption :: String -> DynFlags -> DynFlags+addPluginModuleNameOption optflag d = d { pluginModNameOpts = (mkModuleName m, option) : (pluginModNameOpts d) }+ where (m, rest) = break (== ':') optflag+ option = case rest of+ [] -> "" -- should probably signal an error+ (_:plug_opt) -> plug_opt -- ignore the ':' from break++addFrontendPluginOption :: String -> DynFlags -> DynFlags+addFrontendPluginOption s d = d { frontendPluginOpts = s : frontendPluginOpts d }++parseDynLibLoaderMode f d =+ case splitAt 8 f of+ ("deploy", "") -> d { dynLibLoader = Deployable }+ ("sysdep", "") -> d { dynLibLoader = SystemDependent }+ _ -> throwGhcException (CmdLineError ("Unknown dynlib loader: " ++ f))++setDumpPrefixForce f d = d { dumpPrefixForce = f}++-- XXX HACK: Prelude> words "'does not' work" ===> ["'does","not'","work"]+-- Config.hs should really use Option.+setPgmP f = let (pgm:args) = words f in alterSettings (\s -> s { sPgm_P = (pgm, map Option args)})+addOptl f = alterSettings (\s -> s { sOpt_l = f : sOpt_l s})+addOptc f = alterSettings (\s -> s { sOpt_c = f : sOpt_c s})+addOptP f = alterSettings (\s -> s { sOpt_P = f : sOpt_P s})+++setDepMakefile :: FilePath -> DynFlags -> DynFlags+setDepMakefile f d = d { depMakefile = f }++setDepIncludePkgDeps :: Bool -> DynFlags -> DynFlags+setDepIncludePkgDeps b d = d { depIncludePkgDeps = b }++addDepExcludeMod :: String -> DynFlags -> DynFlags+addDepExcludeMod m d+ = d { depExcludeMods = mkModuleName m : depExcludeMods d }++addDepSuffix :: FilePath -> DynFlags -> DynFlags+addDepSuffix s d = d { depSuffixes = s : depSuffixes d }++addCmdlineFramework f d = d { cmdlineFrameworks = f : cmdlineFrameworks d}++addHaddockOpts f d = d { haddockOptions = Just f}++addGhciScript f d = d { ghciScripts = f : ghciScripts d}++setInteractivePrint f d = d { interactivePrint = Just f}++-- -----------------------------------------------------------------------------+-- Command-line options++-- | When invoking external tools as part of the compilation pipeline, we+-- pass these a sequence of options on the command-line. Rather than+-- just using a list of Strings, we use a type that allows us to distinguish+-- between filepaths and 'other stuff'. The reason for this is that+-- this type gives us a handle on transforming filenames, and filenames only,+-- to whatever format they're expected to be on a particular platform.+data Option+ = FileOption -- an entry that _contains_ filename(s) / filepaths.+ String -- a non-filepath prefix that shouldn't be+ -- transformed (e.g., "/out=")+ String -- the filepath/filename portion+ | Option String+ deriving ( Eq )++showOpt :: Option -> String+showOpt (FileOption pre f) = pre ++ f+showOpt (Option s) = s++-----------------------------------------------------------------------------+-- Setting the optimisation level++updOptLevel :: Int -> DynFlags -> DynFlags+-- ^ Sets the 'DynFlags' to be appropriate to the optimisation level+updOptLevel n dfs+ = dfs2{ optLevel = final_n }+ where+ final_n = max 0 (min 2 n) -- Clamp to 0 <= n <= 2+ dfs1 = foldr (flip gopt_unset) dfs remove_gopts+ dfs2 = foldr (flip gopt_set) dfs1 extra_gopts++ extra_gopts = [ f | (ns,f) <- optLevelFlags, final_n `elem` ns ]+ remove_gopts = [ f | (ns,f) <- optLevelFlags, final_n `notElem` ns ]++{- **********************************************************************+%* *+ DynFlags parser+%* *+%********************************************************************* -}++-- -----------------------------------------------------------------------------+-- Parsing the dynamic flags.+++-- | Parse dynamic flags from a list of command line arguments. Returns the+-- the parsed 'DynFlags', the left-over arguments, and a list of warnings.+-- Throws a 'UsageError' if errors occurred during parsing (such as unknown+-- flags or missing arguments).+parseDynamicFlagsCmdLine :: MonadIO m => DynFlags -> [Located String]+ -> m (DynFlags, [Located String], [Located String])+ -- ^ Updated 'DynFlags', left-over arguments, and+ -- list of warnings.+parseDynamicFlagsCmdLine = parseDynamicFlagsFull flagsAll True+++-- | Like 'parseDynamicFlagsCmdLine' but does not allow the package flags+-- (-package, -hide-package, -ignore-package, -hide-all-packages, -package-db).+-- Used to parse flags set in a modules pragma.+parseDynamicFilePragma :: MonadIO m => DynFlags -> [Located String]+ -> m (DynFlags, [Located String], [Located String])+ -- ^ Updated 'DynFlags', left-over arguments, and+ -- list of warnings.+parseDynamicFilePragma = parseDynamicFlagsFull flagsDynamic False+++-- | Parses the dynamically set flags for GHC. This is the most general form of+-- the dynamic flag parser that the other methods simply wrap. It allows+-- saying which flags are valid flags and indicating if we are parsing+-- arguments from the command line or from a file pragma.+parseDynamicFlagsFull :: MonadIO m+ => [Flag (CmdLineP DynFlags)] -- ^ valid flags to match against+ -> Bool -- ^ are the arguments from the command line?+ -> DynFlags -- ^ current dynamic flags+ -> [Located String] -- ^ arguments to parse+ -> m (DynFlags, [Located String], [Located String])+parseDynamicFlagsFull activeFlags cmdline dflags0 args = do+ let ((leftover, errs, warns), dflags1)+ = runCmdLine (processArgs activeFlags args) dflags0++ -- See Note [Handling errors when parsing commandline flags]+ unless (null errs) $ liftIO $ throwGhcExceptionIO $+ errorsToGhcException . map (showPpr dflags0 . getLoc &&& unLoc) $ errs++ -- check for disabled flags in safe haskell+ let (dflags2, sh_warns) = safeFlagCheck cmdline dflags1+ dflags3 = updateWays dflags2+ theWays = ways dflags3++ unless (allowed_combination theWays) $ liftIO $+ throwGhcExceptionIO (CmdLineError ("combination not supported: " +++ intercalate "/" (map wayDesc theWays)))++ let chooseOutput+ | isJust (outputFile dflags3) -- Only iff user specified -o ...+ , not (isJust (dynOutputFile dflags3)) -- but not -dyno+ = return $ dflags3 { dynOutputFile = Just $ dynOut (fromJust $ outputFile dflags3) }+ | otherwise+ = return dflags3+ where+ dynOut = flip addExtension (dynObjectSuf dflags3) . dropExtension+ dflags4 <- ifGeneratingDynamicToo dflags3 chooseOutput (return dflags3)++ let (dflags5, consistency_warnings) = makeDynFlagsConsistent dflags4++ dflags6 <- case dllSplitFile dflags5 of+ Nothing -> return (dflags5 { dllSplit = Nothing })+ Just f ->+ case dllSplit dflags5 of+ Just _ ->+ -- If dllSplit is out of date then it would have+ -- been set to Nothing. As it's a Just, it must be+ -- up-to-date.+ return dflags5+ Nothing ->+ do xs <- liftIO $ readFile f+ let ss = map (Set.fromList . words) (lines xs)+ return $ dflags5 { dllSplit = Just ss }++ -- Set timer stats & heap size+ when (enableTimeStats dflags6) $ liftIO enableTimingStats+ case (ghcHeapSize dflags6) of+ Just x -> liftIO (setHeapSize x)+ _ -> return ()++ dflags7 <- liftIO $ setLogAction dflags6++ liftIO $ setUnsafeGlobalDynFlags dflags7++ return (dflags7, leftover, consistency_warnings ++ sh_warns ++ warns)++setLogAction :: DynFlags -> IO DynFlags+setLogAction dflags = do+ mlogger <- initLogAction dflags+ return $+ maybe+ dflags+ (\logger ->+ dflags+ { log_action = getLogAction logger+ , log_finaliser = getLogFinaliser logger+ , initLogAction = return $ Nothing -- Don't initialise it twice+ })+ mlogger++-- | Write an error or warning to the 'LogOutput'.+putLogMsg :: DynFlags -> WarnReason -> Severity -> SrcSpan -> PprStyle+ -> MsgDoc -> IO ()+putLogMsg dflags = log_action dflags dflags++updateWays :: DynFlags -> DynFlags+updateWays dflags+ = let theWays = sort $ nub $ ways dflags+ in dflags {+ ways = theWays,+ buildTag = mkBuildTag (filter (not . wayRTSOnly) theWays),+ rtsBuildTag = mkBuildTag theWays+ }++-- | Check (and potentially disable) any extensions that aren't allowed+-- in safe mode.+--+-- The bool is to indicate if we are parsing command line flags (false means+-- file pragma). This allows us to generate better warnings.+safeFlagCheck :: Bool -> DynFlags -> (DynFlags, [Located String])+safeFlagCheck _ dflags | safeLanguageOn dflags = (dflagsUnset, warns)+ where+ -- Handle illegal flags under safe language.+ (dflagsUnset, warns) = foldl check_method (dflags, []) unsafeFlags++ check_method (df, warns) (str,loc,test,fix)+ | test df = (fix df, warns ++ safeFailure (loc df) str)+ | otherwise = (df, warns)++ safeFailure loc str+ = [L loc $ str ++ " is not allowed in Safe Haskell; ignoring "+ ++ str]++safeFlagCheck cmdl dflags =+ case (safeInferOn dflags) of+ True | safeFlags -> (dflags', warn)+ True -> (dflags' { safeInferred = False }, warn)+ False -> (dflags', warn)++ where+ -- dynflags and warn for when -fpackage-trust by itself with no safe+ -- haskell flag+ (dflags', warn)+ | safeHaskell dflags == Sf_None && not cmdl && packageTrustOn dflags+ = (gopt_unset dflags Opt_PackageTrust, pkgWarnMsg)+ | otherwise = (dflags, [])++ pkgWarnMsg = [L (pkgTrustOnLoc dflags') $+ "-fpackage-trust ignored;" +++ " must be specified with a Safe Haskell flag"]++ -- Have we inferred Unsafe? See Note [HscMain . Safe Haskell Inference]+ safeFlags = all (\(_,_,t,_) -> not $ t dflags) unsafeFlagsForInfer+++{- **********************************************************************+%* *+ DynFlags specifications+%* *+%********************************************************************* -}++-- | All dynamic flags option strings without the deprecated ones.+-- These are the user facing strings for enabling and disabling options.+allNonDeprecatedFlags :: [String]+allNonDeprecatedFlags = allFlagsDeps False++-- | All flags with possibility to filter deprecated ones+allFlagsDeps :: Bool -> [String]+allFlagsDeps keepDeprecated = [ '-':flagName flag+ | (deprecated, flag) <- flagsAllDeps+ , ok (flagOptKind flag)+ , keepDeprecated || not (isDeprecated deprecated)]+ where ok (PrefixPred _ _) = False+ ok _ = True+ isDeprecated Deprecated = True+ isDeprecated _ = False++{-+ - Below we export user facing symbols for GHC dynamic flags for use with the+ - GHC API.+ -}++-- All dynamic flags present in GHC.+flagsAll :: [Flag (CmdLineP DynFlags)]+flagsAll = map snd flagsAllDeps++-- All dynamic flags present in GHC with deprecation information.+flagsAllDeps :: [(Deprecation, Flag (CmdLineP DynFlags))]+flagsAllDeps = package_flags_deps ++ dynamic_flags_deps+++-- All dynamic flags, minus package flags, present in GHC.+flagsDynamic :: [Flag (CmdLineP DynFlags)]+flagsDynamic = map snd dynamic_flags_deps++-- ALl package flags present in GHC.+flagsPackage :: [Flag (CmdLineP DynFlags)]+flagsPackage = map snd package_flags_deps++----------------Helpers to make flags and keep deprecation information----------++type FlagMaker m = String -> OptKind m -> Flag m+type DynFlagMaker = FlagMaker (CmdLineP DynFlags)+data Deprecation = NotDeprecated | Deprecated deriving (Eq, Ord)++-- Make a non-deprecated flag+make_ord_flag :: DynFlagMaker -> String -> OptKind (CmdLineP DynFlags)+ -> (Deprecation, Flag (CmdLineP DynFlags))+make_ord_flag fm name kind = (NotDeprecated, fm name kind)++-- Make a deprecated flag+make_dep_flag :: DynFlagMaker -> String -> OptKind (CmdLineP DynFlags) -> String+ -> (Deprecation, Flag (CmdLineP DynFlags))+make_dep_flag fm name kind message = (Deprecated,+ fm name $ add_dep_message kind message)++add_dep_message :: OptKind (CmdLineP DynFlags) -> String+ -> OptKind (CmdLineP DynFlags)+add_dep_message (NoArg f) message = NoArg $ f >> deprecate message+add_dep_message (HasArg f) message = HasArg $ \s -> f s >> deprecate message+add_dep_message (SepArg f) message = SepArg $ \s -> f s >> deprecate message+add_dep_message (Prefix f) message = Prefix $ \s -> f s >> deprecate message+add_dep_message (OptPrefix f) message =+ OptPrefix $ \s -> f s >> deprecate message+add_dep_message (OptIntSuffix f) message =+ OptIntSuffix $ \oi -> f oi >> deprecate message+add_dep_message (IntSuffix f) message =+ IntSuffix $ \i -> f i >> deprecate message+add_dep_message (FloatSuffix f) message =+ FloatSuffix $ \fl -> f fl >> deprecate message+add_dep_message (PassFlag f) message =+ PassFlag $ \s -> f s >> deprecate message+add_dep_message (AnySuffix f) message =+ AnySuffix $ \s -> f s >> deprecate message+add_dep_message (PrefixPred pred f) message =+ PrefixPred pred $ \s -> f s >> deprecate message+add_dep_message (AnySuffixPred pred f) message =+ AnySuffixPred pred $ \s -> f s >> deprecate message++----------------------- The main flags themselves ------------------------------+-- See Note [Updating flag description in the User's Guide]+-- See Note [Supporting CLI completion]+dynamic_flags_deps :: [(Deprecation, Flag (CmdLineP DynFlags))]+dynamic_flags_deps = [+ make_dep_flag defFlag "n" (NoArg $ return ())+ "The -n flag is deprecated and no longer has any effect"+ , make_ord_flag defFlag "cpp" (NoArg (setExtensionFlag LangExt.Cpp))+ , make_ord_flag defFlag "F" (NoArg (setGeneralFlag Opt_Pp))+ , (Deprecated, defFlag "#include"+ (HasArg (\_s ->+ addWarn ("-#include and INCLUDE pragmas are " +++ "deprecated: They no longer have any effect"))))+ , make_ord_flag defFlag "v" (OptIntSuffix setVerbosity)++ , make_ord_flag defGhcFlag "j" (OptIntSuffix+ (\n -> case n of+ Just n+ | n > 0 -> upd (\d -> d { parMakeCount = Just n })+ | otherwise -> addErr "Syntax: -j[n] where n > 0"+ Nothing -> upd (\d -> d { parMakeCount = Nothing })))+ -- When the number of parallel builds+ -- is omitted, it is the same+ -- as specifing that the number of+ -- parallel builds is equal to the+ -- result of getNumProcessors+ , make_ord_flag defFlag "instantiated-with" (sepArg setUnitIdInsts)+ , make_ord_flag defFlag "this-component-id" (sepArg setComponentId)++ -- RTS options -------------------------------------------------------------+ , make_ord_flag defFlag "H" (HasArg (\s -> upd (\d ->+ d { ghcHeapSize = Just $ fromIntegral (decodeSize s)})))++ , make_ord_flag defFlag "Rghc-timing" (NoArg (upd (\d ->+ d { enableTimeStats = True })))++ ------- ways ---------------------------------------------------------------+ , make_ord_flag defGhcFlag "prof" (NoArg (addWay WayProf))+ , make_ord_flag defGhcFlag "eventlog" (NoArg (addWay WayEventLog))+ , make_dep_flag defGhcFlag "smp"+ (NoArg $ addWay WayThreaded) "Use -threaded instead"+ , make_ord_flag defGhcFlag "debug" (NoArg (addWay WayDebug))+ , make_ord_flag defGhcFlag "threaded" (NoArg (addWay WayThreaded))++ , make_ord_flag defGhcFlag "ticky"+ (NoArg (setGeneralFlag Opt_Ticky >> addWay WayDebug))++ -- -ticky enables ticky-ticky code generation, and also implies -debug which+ -- is required to get the RTS ticky support.++ ----- Linker --------------------------------------------------------+ , make_ord_flag defGhcFlag "static" (NoArg removeWayDyn)+ , make_ord_flag defGhcFlag "dynamic" (NoArg (addWay WayDyn))+ , make_ord_flag defGhcFlag "rdynamic" $ noArg $+#ifdef linux_HOST_OS+ addOptl "-rdynamic"+#elif defined (mingw32_HOST_OS)+ addOptl "-Wl,--export-all-symbols"+#else+ -- ignored for compat w/ gcc:+ id+#endif+ , make_ord_flag defGhcFlag "relative-dynlib-paths"+ (NoArg (setGeneralFlag Opt_RelativeDynlibPaths))++ ------- Specific phases --------------------------------------------+ -- need to appear before -pgmL to be parsed as LLVM flags.+ , make_ord_flag defFlag "pgmlo"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_lo = (f,[])})))+ , make_ord_flag defFlag "pgmlc"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_lc = (f,[])})))+ , make_ord_flag defFlag "pgmi"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_i = f})))+ , make_ord_flag defFlag "pgmL"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_L = f})))+ , make_ord_flag defFlag "pgmP"+ (hasArg setPgmP)+ , make_ord_flag defFlag "pgmF"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_F = f})))+ , make_ord_flag defFlag "pgmc"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_c = (f,[])})))+ , make_ord_flag defFlag "pgms"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_s = (f,[])})))+ , make_ord_flag defFlag "pgma"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_a = (f,[])})))+ , make_ord_flag defFlag "pgml"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_l = (f,[])})))+ , make_ord_flag defFlag "pgmdll"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_dll = (f,[])})))+ , make_ord_flag defFlag "pgmwindres"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_windres = f})))+ , make_ord_flag defFlag "pgmlibtool"+ (hasArg (\f -> alterSettings (\s -> s { sPgm_libtool = f})))++ -- need to appear before -optl/-opta to be parsed as LLVM flags.+ , make_ord_flag defFlag "optlo"+ (hasArg (\f -> alterSettings (\s -> s { sOpt_lo = f : sOpt_lo s})))+ , make_ord_flag defFlag "optlc"+ (hasArg (\f -> alterSettings (\s -> s { sOpt_lc = f : sOpt_lc s})))+ , make_ord_flag defFlag "opti"+ (hasArg (\f -> alterSettings (\s -> s { sOpt_i = f : sOpt_i s})))+ , make_ord_flag defFlag "optL"+ (hasArg (\f -> alterSettings (\s -> s { sOpt_L = f : sOpt_L s})))+ , make_ord_flag defFlag "optP"+ (hasArg addOptP)+ , make_ord_flag defFlag "optF"+ (hasArg (\f -> alterSettings (\s -> s { sOpt_F = f : sOpt_F s})))+ , make_ord_flag defFlag "optc"+ (hasArg addOptc)+ , make_ord_flag defFlag "opta"+ (hasArg (\f -> alterSettings (\s -> s { sOpt_a = f : sOpt_a s})))+ , make_ord_flag defFlag "optl"+ (hasArg addOptl)+ , make_ord_flag defFlag "optwindres"+ (hasArg (\f ->+ alterSettings (\s -> s { sOpt_windres = f : sOpt_windres s})))++ , make_ord_flag defGhcFlag "split-objs"+ (NoArg (if can_split+ then setGeneralFlag Opt_SplitObjs+ else addWarn "ignoring -fsplit-objs"))++ , make_ord_flag defGhcFlag "split-sections"+ (noArgM (\dflags -> do+ if platformHasSubsectionsViaSymbols (targetPlatform dflags)+ then do addErr $+ "-split-sections is not useful on this platform " +++ "since it always uses subsections via symbols."+ return dflags+ else return (gopt_set dflags Opt_SplitSections)))++ -------- ghc -M -----------------------------------------------------+ , make_ord_flag defGhcFlag "dep-suffix" (hasArg addDepSuffix)+ , make_ord_flag defGhcFlag "dep-makefile" (hasArg setDepMakefile)+ , make_ord_flag defGhcFlag "include-pkg-deps"+ (noArg (setDepIncludePkgDeps True))+ , make_ord_flag defGhcFlag "exclude-module" (hasArg addDepExcludeMod)++ -------- Linking ----------------------------------------------------+ , make_ord_flag defGhcFlag "no-link"+ (noArg (\d -> d { ghcLink=NoLink }))+ , make_ord_flag defGhcFlag "shared"+ (noArg (\d -> d { ghcLink=LinkDynLib }))+ , make_ord_flag defGhcFlag "staticlib"+ (noArg (\d -> d { ghcLink=LinkStaticLib }))+ , make_ord_flag defGhcFlag "dynload" (hasArg parseDynLibLoaderMode)+ , make_ord_flag defGhcFlag "dylib-install-name" (hasArg setDylibInstallName)+ -- -dll-split is an internal flag, used only during the GHC build+ , make_ord_flag defHiddenFlag "dll-split"+ (hasArg (\f d -> d { dllSplitFile = Just f, dllSplit = Nothing }))++ ------- Libraries ---------------------------------------------------+ , make_ord_flag defFlag "L" (Prefix addLibraryPath)+ , make_ord_flag defFlag "l" (hasArg (addLdInputs . Option . ("-l" ++)))++ ------- Frameworks --------------------------------------------------+ -- -framework-path should really be -F ...+ , make_ord_flag defFlag "framework-path" (HasArg addFrameworkPath)+ , make_ord_flag defFlag "framework" (hasArg addCmdlineFramework)++ ------- Output Redirection ------------------------------------------+ , make_ord_flag defGhcFlag "odir" (hasArg setObjectDir)+ , make_ord_flag defGhcFlag "o" (sepArg (setOutputFile . Just))+ , make_ord_flag defGhcFlag "dyno"+ (sepArg (setDynOutputFile . Just))+ , make_ord_flag defGhcFlag "ohi"+ (hasArg (setOutputHi . Just ))+ , make_ord_flag defGhcFlag "osuf" (hasArg setObjectSuf)+ , make_ord_flag defGhcFlag "dynosuf" (hasArg setDynObjectSuf)+ , make_ord_flag defGhcFlag "hcsuf" (hasArg setHcSuf)+ , make_ord_flag defGhcFlag "hisuf" (hasArg setHiSuf)+ , make_ord_flag defGhcFlag "dynhisuf" (hasArg setDynHiSuf)+ , make_ord_flag defGhcFlag "hidir" (hasArg setHiDir)+ , make_ord_flag defGhcFlag "tmpdir" (hasArg setTmpDir)+ , make_ord_flag defGhcFlag "stubdir" (hasArg setStubDir)+ , make_ord_flag defGhcFlag "dumpdir" (hasArg setDumpDir)+ , make_ord_flag defGhcFlag "outputdir" (hasArg setOutputDir)+ , make_ord_flag defGhcFlag "ddump-file-prefix"+ (hasArg (setDumpPrefixForce . Just))++ , make_ord_flag defGhcFlag "dynamic-too"+ (NoArg (setGeneralFlag Opt_BuildDynamicToo))++ ------- Keeping temporary files -------------------------------------+ -- These can be singular (think ghc -c) or plural (think ghc --make)+ , make_ord_flag defGhcFlag "keep-hc-file"+ (NoArg (setGeneralFlag Opt_KeepHcFiles))+ , make_ord_flag defGhcFlag "keep-hc-files"+ (NoArg (setGeneralFlag Opt_KeepHcFiles))+ , make_ord_flag defGhcFlag "keep-s-file"+ (NoArg (setGeneralFlag Opt_KeepSFiles))+ , make_ord_flag defGhcFlag "keep-s-files"+ (NoArg (setGeneralFlag Opt_KeepSFiles))+ , make_ord_flag defGhcFlag "keep-llvm-file"+ (NoArg $ setObjTarget HscLlvm >> setGeneralFlag Opt_KeepLlvmFiles)+ , make_ord_flag defGhcFlag "keep-llvm-files"+ (NoArg $ setObjTarget HscLlvm >> setGeneralFlag Opt_KeepLlvmFiles)+ -- This only makes sense as plural+ , make_ord_flag defGhcFlag "keep-tmp-files"+ (NoArg (setGeneralFlag Opt_KeepTmpFiles))+ , make_ord_flag defGhcFlag "keep-hi-file"+ (NoArg (setGeneralFlag Opt_KeepHiFiles))+ , make_ord_flag defGhcFlag "no-keep-hi-file"+ (NoArg (unSetGeneralFlag Opt_KeepHiFiles))+ , make_ord_flag defGhcFlag "keep-hi-files"+ (NoArg (setGeneralFlag Opt_KeepHiFiles))+ , make_ord_flag defGhcFlag "no-keep-hi-files"+ (NoArg (unSetGeneralFlag Opt_KeepHiFiles))+ , make_ord_flag defGhcFlag "keep-o-file"+ (NoArg (setGeneralFlag Opt_KeepOFiles))+ , make_ord_flag defGhcFlag "no-keep-o-file"+ (NoArg (unSetGeneralFlag Opt_KeepOFiles))+ , make_ord_flag defGhcFlag "keep-o-files"+ (NoArg (setGeneralFlag Opt_KeepOFiles))+ , make_ord_flag defGhcFlag "no-keep-o-files"+ (NoArg (unSetGeneralFlag Opt_KeepOFiles))++ ------- Miscellaneous ----------------------------------------------+ , make_ord_flag defGhcFlag "no-auto-link-packages"+ (NoArg (unSetGeneralFlag Opt_AutoLinkPackages))+ , make_ord_flag defGhcFlag "no-hs-main"+ (NoArg (setGeneralFlag Opt_NoHsMain))+ , make_ord_flag defGhcFlag "fno-state-hack"+ (NoArg (setGeneralFlag Opt_G_NoStateHack))+ , make_ord_flag defGhcFlag "fno-opt-coercion"+ (NoArg (setGeneralFlag Opt_G_NoOptCoercion))+ , make_ord_flag defGhcFlag "with-rtsopts"+ (HasArg setRtsOpts)+ , make_ord_flag defGhcFlag "rtsopts"+ (NoArg (setRtsOptsEnabled RtsOptsAll))+ , make_ord_flag defGhcFlag "rtsopts=all"+ (NoArg (setRtsOptsEnabled RtsOptsAll))+ , make_ord_flag defGhcFlag "rtsopts=some"+ (NoArg (setRtsOptsEnabled RtsOptsSafeOnly))+ , make_ord_flag defGhcFlag "rtsopts=none"+ (NoArg (setRtsOptsEnabled RtsOptsNone))+ , make_ord_flag defGhcFlag "no-rtsopts"+ (NoArg (setRtsOptsEnabled RtsOptsNone))+ , make_ord_flag defGhcFlag "no-rtsopts-suggestions"+ (noArg (\d -> d {rtsOptsSuggestions = False}))++ , make_ord_flag defGhcFlag "main-is" (SepArg setMainIs)+ , make_ord_flag defGhcFlag "haddock" (NoArg (setGeneralFlag Opt_Haddock))+ , make_ord_flag defGhcFlag "haddock-opts" (hasArg addHaddockOpts)+ , make_ord_flag defGhcFlag "hpcdir" (SepArg setOptHpcDir)+ , make_ord_flag defGhciFlag "ghci-script" (hasArg addGhciScript)+ , make_ord_flag defGhciFlag "interactive-print" (hasArg setInteractivePrint)+ , make_ord_flag defGhcFlag "ticky-allocd"+ (NoArg (setGeneralFlag Opt_Ticky_Allocd))+ , make_ord_flag defGhcFlag "ticky-LNE"+ (NoArg (setGeneralFlag Opt_Ticky_LNE))+ , make_ord_flag defGhcFlag "ticky-dyn-thunk"+ (NoArg (setGeneralFlag Opt_Ticky_Dyn_Thunk))+ ------- recompilation checker --------------------------------------+ , make_dep_flag defGhcFlag "recomp"+ (NoArg $ unSetGeneralFlag Opt_ForceRecomp)+ "Use -fno-force-recomp instead"+ , make_dep_flag defGhcFlag "no-recomp"+ (NoArg $ setGeneralFlag Opt_ForceRecomp) "Use -fforce-recomp instead"+ , make_ord_flag defFlag "fmax-errors"+ (intSuffix (\n d -> d { maxErrors = Just (max 1 n) }))+ , make_ord_flag defFlag "fno-max-errors"+ (noArg (\d -> d { maxErrors = Nothing }))+ , make_ord_flag defFlag "freverse-errors"+ (noArg (\d -> d {reverseErrors = True} ))+ , make_ord_flag defFlag "fno-reverse-errors"+ (noArg (\d -> d {reverseErrors = False} ))++ ------ HsCpp opts ---------------------------------------------------+ , make_ord_flag defFlag "D" (AnySuffix (upd . addOptP))+ , make_ord_flag defFlag "U" (AnySuffix (upd . addOptP))++ ------- Include/Import Paths ----------------------------------------+ , make_ord_flag defFlag "I" (Prefix addIncludePath)+ , make_ord_flag defFlag "i" (OptPrefix addImportPath)++ ------ Output style options -----------------------------------------+ , make_ord_flag defFlag "dppr-user-length" (intSuffix (\n d ->+ d { pprUserLength = n }))+ , make_ord_flag defFlag "dppr-cols" (intSuffix (\n d ->+ d { pprCols = n }))+ , make_ord_flag defFlag "fdiagnostics-color=auto"+ (NoArg (upd (\d -> d { useColor = Auto })))+ , make_ord_flag defFlag "fdiagnostics-color=always"+ (NoArg (upd (\d -> d { useColor = Always })))+ , make_ord_flag defFlag "fdiagnostics-color=never"+ (NoArg (upd (\d -> d { useColor = Never })))++ -- Suppress all that is suppressable in core dumps.+ -- Except for uniques, as some simplifier phases introduce new variables that+ -- have otherwise identical names.+ , make_ord_flag defGhcFlag "dsuppress-all"+ (NoArg $ do setGeneralFlag Opt_SuppressCoercions+ setGeneralFlag Opt_SuppressVarKinds+ setGeneralFlag Opt_SuppressModulePrefixes+ setGeneralFlag Opt_SuppressTypeApplications+ setGeneralFlag Opt_SuppressIdInfo+ setGeneralFlag Opt_SuppressTicks+ setGeneralFlag Opt_SuppressTypeSignatures)++ ------ Debugging ----------------------------------------------------+ , make_ord_flag defGhcFlag "dstg-stats"+ (NoArg (setGeneralFlag Opt_StgStats))++ , make_ord_flag defGhcFlag "ddump-cmm"+ (setDumpFlag Opt_D_dump_cmm)+ , make_ord_flag defGhcFlag "ddump-cmm-from-stg"+ (setDumpFlag Opt_D_dump_cmm_from_stg)+ , make_ord_flag defGhcFlag "ddump-cmm-raw"+ (setDumpFlag Opt_D_dump_cmm_raw)+ , make_ord_flag defGhcFlag "ddump-cmm-verbose"+ (setDumpFlag Opt_D_dump_cmm_verbose)+ , make_ord_flag defGhcFlag "ddump-cmm-cfg"+ (setDumpFlag Opt_D_dump_cmm_cfg)+ , make_ord_flag defGhcFlag "ddump-cmm-cbe"+ (setDumpFlag Opt_D_dump_cmm_cbe)+ , make_ord_flag defGhcFlag "ddump-cmm-switch"+ (setDumpFlag Opt_D_dump_cmm_switch)+ , make_ord_flag defGhcFlag "ddump-cmm-proc"+ (setDumpFlag Opt_D_dump_cmm_proc)+ , make_ord_flag defGhcFlag "ddump-cmm-sp"+ (setDumpFlag Opt_D_dump_cmm_sp)+ , make_ord_flag defGhcFlag "ddump-cmm-sink"+ (setDumpFlag Opt_D_dump_cmm_sink)+ , make_ord_flag defGhcFlag "ddump-cmm-caf"+ (setDumpFlag Opt_D_dump_cmm_caf)+ , make_ord_flag defGhcFlag "ddump-cmm-procmap"+ (setDumpFlag Opt_D_dump_cmm_procmap)+ , make_ord_flag defGhcFlag "ddump-cmm-split"+ (setDumpFlag Opt_D_dump_cmm_split)+ , make_ord_flag defGhcFlag "ddump-cmm-info"+ (setDumpFlag Opt_D_dump_cmm_info)+ , make_ord_flag defGhcFlag "ddump-cmm-cps"+ (setDumpFlag Opt_D_dump_cmm_cps)+ , make_ord_flag defGhcFlag "ddump-core-stats"+ (setDumpFlag Opt_D_dump_core_stats)+ , make_ord_flag defGhcFlag "ddump-asm"+ (setDumpFlag Opt_D_dump_asm)+ , make_ord_flag defGhcFlag "ddump-asm-native"+ (setDumpFlag Opt_D_dump_asm_native)+ , make_ord_flag defGhcFlag "ddump-asm-liveness"+ (setDumpFlag Opt_D_dump_asm_liveness)+ , make_ord_flag defGhcFlag "ddump-asm-regalloc"+ (setDumpFlag Opt_D_dump_asm_regalloc)+ , make_ord_flag defGhcFlag "ddump-asm-conflicts"+ (setDumpFlag Opt_D_dump_asm_conflicts)+ , make_ord_flag defGhcFlag "ddump-asm-regalloc-stages"+ (setDumpFlag Opt_D_dump_asm_regalloc_stages)+ , make_ord_flag defGhcFlag "ddump-asm-stats"+ (setDumpFlag Opt_D_dump_asm_stats)+ , make_ord_flag defGhcFlag "ddump-asm-expanded"+ (setDumpFlag Opt_D_dump_asm_expanded)+ , make_ord_flag defGhcFlag "ddump-llvm"+ (NoArg $ setObjTarget HscLlvm >> setDumpFlag' Opt_D_dump_llvm)+ , make_ord_flag defGhcFlag "ddump-deriv"+ (setDumpFlag Opt_D_dump_deriv)+ , make_ord_flag defGhcFlag "ddump-ds"+ (setDumpFlag Opt_D_dump_ds)+ , make_ord_flag defGhcFlag "ddump-foreign"+ (setDumpFlag Opt_D_dump_foreign)+ , make_ord_flag defGhcFlag "ddump-inlinings"+ (setDumpFlag Opt_D_dump_inlinings)+ , make_ord_flag defGhcFlag "ddump-rule-firings"+ (setDumpFlag Opt_D_dump_rule_firings)+ , make_ord_flag defGhcFlag "ddump-rule-rewrites"+ (setDumpFlag Opt_D_dump_rule_rewrites)+ , make_ord_flag defGhcFlag "ddump-simpl-trace"+ (setDumpFlag Opt_D_dump_simpl_trace)+ , make_ord_flag defGhcFlag "ddump-occur-anal"+ (setDumpFlag Opt_D_dump_occur_anal)+ , make_ord_flag defGhcFlag "ddump-parsed"+ (setDumpFlag Opt_D_dump_parsed)+ , make_ord_flag defGhcFlag "ddump-parsed-ast"+ (setDumpFlag Opt_D_dump_parsed_ast)+ , make_ord_flag defGhcFlag "ddump-rn"+ (setDumpFlag Opt_D_dump_rn)+ , make_ord_flag defGhcFlag "ddump-rn-ast"+ (setDumpFlag Opt_D_dump_rn_ast)+ , make_ord_flag defGhcFlag "ddump-simpl"+ (setDumpFlag Opt_D_dump_simpl)+ , make_ord_flag defGhcFlag "ddump-simpl-iterations"+ (setDumpFlag Opt_D_dump_simpl_iterations)+ , make_ord_flag defGhcFlag "ddump-spec"+ (setDumpFlag Opt_D_dump_spec)+ , make_ord_flag defGhcFlag "ddump-prep"+ (setDumpFlag Opt_D_dump_prep)+ , make_ord_flag defGhcFlag "ddump-stg"+ (setDumpFlag Opt_D_dump_stg)+ , make_ord_flag defGhcFlag "ddump-call-arity"+ (setDumpFlag Opt_D_dump_call_arity)+ , make_ord_flag defGhcFlag "ddump-stranal"+ (setDumpFlag Opt_D_dump_stranal)+ , make_ord_flag defGhcFlag "ddump-str-signatures"+ (setDumpFlag Opt_D_dump_str_signatures)+ , make_ord_flag defGhcFlag "ddump-tc"+ (setDumpFlag Opt_D_dump_tc)+ , make_ord_flag defGhcFlag "ddump-tc-ast"+ (setDumpFlag Opt_D_dump_tc_ast)+ , make_ord_flag defGhcFlag "ddump-types"+ (setDumpFlag Opt_D_dump_types)+ , make_ord_flag defGhcFlag "ddump-rules"+ (setDumpFlag Opt_D_dump_rules)+ , make_ord_flag defGhcFlag "ddump-cse"+ (setDumpFlag Opt_D_dump_cse)+ , make_ord_flag defGhcFlag "ddump-worker-wrapper"+ (setDumpFlag Opt_D_dump_worker_wrapper)+ , make_ord_flag defGhcFlag "ddump-rn-trace"+ (setDumpFlag Opt_D_dump_rn_trace)+ , make_ord_flag defGhcFlag "ddump-shape"+ (setDumpFlag Opt_D_dump_shape)+ , make_ord_flag defGhcFlag "ddump-if-trace"+ (setDumpFlag Opt_D_dump_if_trace)+ , make_ord_flag defGhcFlag "ddump-cs-trace"+ (setDumpFlag Opt_D_dump_cs_trace)+ , make_ord_flag defGhcFlag "ddump-tc-trace"+ (NoArg (do setDumpFlag' Opt_D_dump_tc_trace+ setDumpFlag' Opt_D_dump_cs_trace))+ , make_ord_flag defGhcFlag "ddump-ec-trace"+ (setDumpFlag Opt_D_dump_ec_trace)+ , make_ord_flag defGhcFlag "ddump-vt-trace"+ (setDumpFlag Opt_D_dump_vt_trace)+ , make_ord_flag defGhcFlag "ddump-splices"+ (setDumpFlag Opt_D_dump_splices)+ , make_ord_flag defGhcFlag "dth-dec-file"+ (setDumpFlag Opt_D_th_dec_file)++ , make_ord_flag defGhcFlag "ddump-rn-stats"+ (setDumpFlag Opt_D_dump_rn_stats)+ , make_ord_flag defGhcFlag "ddump-opt-cmm"+ (setDumpFlag Opt_D_dump_opt_cmm)+ , make_ord_flag defGhcFlag "ddump-simpl-stats"+ (setDumpFlag Opt_D_dump_simpl_stats)+ , make_ord_flag defGhcFlag "ddump-bcos"+ (setDumpFlag Opt_D_dump_BCOs)+ , make_ord_flag defGhcFlag "dsource-stats"+ (setDumpFlag Opt_D_source_stats)+ , make_ord_flag defGhcFlag "dverbose-core2core"+ (NoArg $ setVerbosity (Just 2) >> setVerboseCore2Core)+ , make_ord_flag defGhcFlag "dverbose-stg2stg"+ (setDumpFlag Opt_D_verbose_stg2stg)+ , make_ord_flag defGhcFlag "ddump-hi"+ (setDumpFlag Opt_D_dump_hi)+ , make_ord_flag defGhcFlag "ddump-minimal-imports"+ (NoArg (setGeneralFlag Opt_D_dump_minimal_imports))+ , make_ord_flag defGhcFlag "ddump-vect"+ (setDumpFlag Opt_D_dump_vect)+ , make_ord_flag defGhcFlag "ddump-hpc"+ (setDumpFlag Opt_D_dump_ticked) -- back compat+ , make_ord_flag defGhcFlag "ddump-ticked"+ (setDumpFlag Opt_D_dump_ticked)+ , make_ord_flag defGhcFlag "ddump-mod-cycles"+ (setDumpFlag Opt_D_dump_mod_cycles)+ , make_ord_flag defGhcFlag "ddump-mod-map"+ (setDumpFlag Opt_D_dump_mod_map)+ , make_ord_flag defGhcFlag "ddump-view-pattern-commoning"+ (setDumpFlag Opt_D_dump_view_pattern_commoning)+ , make_ord_flag defGhcFlag "ddump-to-file"+ (NoArg (setGeneralFlag Opt_DumpToFile))+ , make_ord_flag defGhcFlag "ddump-hi-diffs"+ (setDumpFlag Opt_D_dump_hi_diffs)+ , make_ord_flag defGhcFlag "ddump-rtti"+ (setDumpFlag Opt_D_dump_rtti)+ , make_ord_flag defGhcFlag "dcore-lint"+ (NoArg (setGeneralFlag Opt_DoCoreLinting))+ , make_ord_flag defGhcFlag "dstg-lint"+ (NoArg (setGeneralFlag Opt_DoStgLinting))+ , make_ord_flag defGhcFlag "dcmm-lint"+ (NoArg (setGeneralFlag Opt_DoCmmLinting))+ , make_ord_flag defGhcFlag "dasm-lint"+ (NoArg (setGeneralFlag Opt_DoAsmLinting))+ , make_ord_flag defGhcFlag "dannot-lint"+ (NoArg (setGeneralFlag Opt_DoAnnotationLinting))+ , make_ord_flag defGhcFlag "dshow-passes"+ (NoArg $ forceRecompile >> (setVerbosity $ Just 2))+ , make_ord_flag defGhcFlag "dfaststring-stats"+ (NoArg (setGeneralFlag Opt_D_faststring_stats))+ , make_ord_flag defGhcFlag "dno-llvm-mangler"+ (NoArg (setGeneralFlag Opt_NoLlvmMangler)) -- hidden flag+ , make_ord_flag defGhcFlag "ddump-debug"+ (setDumpFlag Opt_D_dump_debug)+ , make_ord_flag defGhcFlag "ddump-json"+ (noArg (flip dopt_set Opt_D_dump_json . setJsonLogAction ) )+ , make_ord_flag defGhcFlag "dppr-debug"+ (setDumpFlag Opt_D_ppr_debug)+ , make_ord_flag defGhcFlag "dno-debug-output"+ (setDumpFlag Opt_D_no_debug_output)++ ------ Machine dependent (-m<blah>) stuff ---------------------------++ , make_ord_flag defGhcFlag "msse" (noArg (\d ->+ d { sseVersion = Just SSE1 }))+ , make_ord_flag defGhcFlag "msse2" (noArg (\d ->+ d { sseVersion = Just SSE2 }))+ , make_ord_flag defGhcFlag "msse3" (noArg (\d ->+ d { sseVersion = Just SSE3 }))+ , make_ord_flag defGhcFlag "msse4" (noArg (\d ->+ d { sseVersion = Just SSE4 }))+ , make_ord_flag defGhcFlag "msse4.2" (noArg (\d ->+ d { sseVersion = Just SSE42 }))+ , make_ord_flag defGhcFlag "mavx" (noArg (\d -> d { avx = True }))+ , make_ord_flag defGhcFlag "mavx2" (noArg (\d -> d { avx2 = True }))+ , make_ord_flag defGhcFlag "mavx512cd" (noArg (\d ->+ d { avx512cd = True }))+ , make_ord_flag defGhcFlag "mavx512er" (noArg (\d ->+ d { avx512er = True }))+ , make_ord_flag defGhcFlag "mavx512f" (noArg (\d -> d { avx512f = True }))+ , make_ord_flag defGhcFlag "mavx512pf" (noArg (\d ->+ d { avx512pf = True }))++ ------ Warning opts -------------------------------------------------+ , make_ord_flag defFlag "W" (NoArg (mapM_ setWarningFlag minusWOpts))+ , make_ord_flag defFlag "Werror"+ (NoArg (do { setGeneralFlag Opt_WarnIsError+ ; mapM_ setFatalWarningFlag minusWeverythingOpts }))+ , make_ord_flag defFlag "Wwarn"+ (NoArg (do { unSetGeneralFlag Opt_WarnIsError+ ; mapM_ unSetFatalWarningFlag minusWeverythingOpts }))+ -- Opt_WarnIsError is still needed to pass -Werror+ -- to CPP; see runCpp in SysTools+ , make_dep_flag defFlag "Wnot" (NoArg (upd (\d ->+ d {warningFlags = IntSet.empty})))+ "Use -w or -Wno-everything instead"+ , make_ord_flag defFlag "w" (NoArg (upd (\d ->+ d {warningFlags = IntSet.empty})))++ -- New-style uniform warning sets+ --+ -- Note that -Weverything > -Wall > -Wextra > -Wdefault > -Wno-everything+ , make_ord_flag defFlag "Weverything" (NoArg (mapM_+ setWarningFlag minusWeverythingOpts))+ , make_ord_flag defFlag "Wno-everything"+ (NoArg (upd (\d -> d {warningFlags = IntSet.empty})))++ , make_ord_flag defFlag "Wall" (NoArg (mapM_+ setWarningFlag minusWallOpts))+ , make_ord_flag defFlag "Wno-all" (NoArg (mapM_+ unSetWarningFlag minusWallOpts))++ , make_ord_flag defFlag "Wextra" (NoArg (mapM_+ setWarningFlag minusWOpts))+ , make_ord_flag defFlag "Wno-extra" (NoArg (mapM_+ unSetWarningFlag minusWOpts))++ , make_ord_flag defFlag "Wdefault" (NoArg (mapM_+ setWarningFlag standardWarnings))+ , make_ord_flag defFlag "Wno-default" (NoArg (mapM_+ unSetWarningFlag standardWarnings))++ , make_ord_flag defFlag "Wcompat" (NoArg (mapM_+ setWarningFlag minusWcompatOpts))+ , make_ord_flag defFlag "Wno-compat" (NoArg (mapM_+ unSetWarningFlag minusWcompatOpts))++ ------ Plugin flags ------------------------------------------------+ , make_ord_flag defGhcFlag "fplugin-opt" (hasArg addPluginModuleNameOption)+ , make_ord_flag defGhcFlag "fplugin" (hasArg addPluginModuleName)+ , make_ord_flag defGhcFlag "ffrontend-opt" (hasArg addFrontendPluginOption)++ ------ Optimisation flags ------------------------------------------+ , make_ord_flag defGhcFlag "O" (noArgM (setOptLevel 1))+ , make_dep_flag defGhcFlag "Onot" (noArgM $ setOptLevel 0 )+ "Use -O0 instead"+ , make_ord_flag defGhcFlag "Odph" (noArgM setDPHOpt)+ , make_ord_flag defGhcFlag "O" (optIntSuffixM (\mb_n ->+ setOptLevel (mb_n `orElse` 1)))+ -- If the number is missing, use 1+++ , make_ord_flag defFlag "fmax-relevant-binds"+ (intSuffix (\n d -> d { maxRelevantBinds = Just n }))+ , make_ord_flag defFlag "fno-max-relevant-binds"+ (noArg (\d -> d { maxRelevantBinds = Nothing }))+ , make_ord_flag defFlag "fmax-uncovered-patterns"+ (intSuffix (\n d -> d { maxUncoveredPatterns = n }))+ , make_ord_flag defFlag "fsimplifier-phases"+ (intSuffix (\n d -> d { simplPhases = n }))+ , make_ord_flag defFlag "fmax-simplifier-iterations"+ (intSuffix (\n d -> d { maxSimplIterations = n }))+ , make_ord_flag defFlag "fmax-pmcheck-iterations"+ (intSuffix (\n d -> d{ maxPmCheckIterations = n }))+ , make_ord_flag defFlag "fsimpl-tick-factor"+ (intSuffix (\n d -> d { simplTickFactor = n }))+ , make_ord_flag defFlag "fspec-constr-threshold"+ (intSuffix (\n d -> d { specConstrThreshold = Just n }))+ , make_ord_flag defFlag "fno-spec-constr-threshold"+ (noArg (\d -> d { specConstrThreshold = Nothing }))+ , make_ord_flag defFlag "fspec-constr-count"+ (intSuffix (\n d -> d { specConstrCount = Just n }))+ , make_ord_flag defFlag "fno-spec-constr-count"+ (noArg (\d -> d { specConstrCount = Nothing }))+ , make_ord_flag defFlag "fspec-constr-recursive"+ (intSuffix (\n d -> d { specConstrRecursive = n }))+ , make_ord_flag defFlag "fliberate-case-threshold"+ (intSuffix (\n d -> d { liberateCaseThreshold = Just n }))+ , make_ord_flag defFlag "fno-liberate-case-threshold"+ (noArg (\d -> d { liberateCaseThreshold = Nothing }))+ , make_ord_flag defFlag "frule-check"+ (sepArg (\s d -> d { ruleCheck = Just s }))+ , make_ord_flag defFlag "freduction-depth"+ (intSuffix (\n d -> d { reductionDepth = treatZeroAsInf n }))+ , make_ord_flag defFlag "fconstraint-solver-iterations"+ (intSuffix (\n d -> d { solverIterations = treatZeroAsInf n }))+ , (Deprecated, defFlag "fcontext-stack"+ (intSuffixM (\n d ->+ do { deprecate $ "use -freduction-depth=" ++ show n ++ " instead"+ ; return $ d { reductionDepth = treatZeroAsInf n } })))+ , (Deprecated, defFlag "ftype-function-depth"+ (intSuffixM (\n d ->+ do { deprecate $ "use -freduction-depth=" ++ show n ++ " instead"+ ; return $ d { reductionDepth = treatZeroAsInf n } })))+ , make_ord_flag defFlag "fstrictness-before"+ (intSuffix (\n d -> d { strictnessBefore = n : strictnessBefore d }))+ , make_ord_flag defFlag "ffloat-lam-args"+ (intSuffix (\n d -> d { floatLamArgs = Just n }))+ , make_ord_flag defFlag "ffloat-all-lams"+ (noArg (\d -> d { floatLamArgs = Nothing }))+ , make_ord_flag defFlag "fhistory-size"+ (intSuffix (\n d -> d { historySize = n }))+ , make_ord_flag defFlag "funfolding-creation-threshold"+ (intSuffix (\n d -> d {ufCreationThreshold = n}))+ , make_ord_flag defFlag "funfolding-use-threshold"+ (intSuffix (\n d -> d {ufUseThreshold = n}))+ , make_ord_flag defFlag "funfolding-fun-discount"+ (intSuffix (\n d -> d {ufFunAppDiscount = n}))+ , make_ord_flag defFlag "funfolding-dict-discount"+ (intSuffix (\n d -> d {ufDictDiscount = n}))+ , make_ord_flag defFlag "funfolding-keeness-factor"+ (floatSuffix (\n d -> d {ufKeenessFactor = n}))+ , make_ord_flag defFlag "fmax-worker-args"+ (intSuffix (\n d -> d {maxWorkerArgs = n}))+ , make_ord_flag defGhciFlag "fghci-hist-size"+ (intSuffix (\n d -> d {ghciHistSize = n}))+ , make_ord_flag defGhcFlag "fmax-inline-alloc-size"+ (intSuffix (\n d -> d { maxInlineAllocSize = n }))+ , make_ord_flag defGhcFlag "fmax-inline-memcpy-insns"+ (intSuffix (\n d -> d { maxInlineMemcpyInsns = n }))+ , make_ord_flag defGhcFlag "fmax-inline-memset-insns"+ (intSuffix (\n d -> d { maxInlineMemsetInsns = n }))+ , make_ord_flag defGhcFlag "dinitial-unique"+ (intSuffix (\n d -> d { initialUnique = n }))+ , make_ord_flag defGhcFlag "dunique-increment"+ (intSuffix (\n d -> d { uniqueIncrement = n }))++ ------ Profiling ----------------------------------------------------++ -- OLD profiling flags+ , make_dep_flag defGhcFlag "auto-all"+ (noArg (\d -> d { profAuto = ProfAutoAll } ))+ "Use -fprof-auto instead"+ , make_dep_flag defGhcFlag "no-auto-all"+ (noArg (\d -> d { profAuto = NoProfAuto } ))+ "Use -fno-prof-auto instead"+ , make_dep_flag defGhcFlag "auto"+ (noArg (\d -> d { profAuto = ProfAutoExports } ))+ "Use -fprof-auto-exported instead"+ , make_dep_flag defGhcFlag "no-auto"+ (noArg (\d -> d { profAuto = NoProfAuto } ))+ "Use -fno-prof-auto instead"+ , make_dep_flag defGhcFlag "caf-all"+ (NoArg (setGeneralFlag Opt_AutoSccsOnIndividualCafs))+ "Use -fprof-cafs instead"+ , make_dep_flag defGhcFlag "no-caf-all"+ (NoArg (unSetGeneralFlag Opt_AutoSccsOnIndividualCafs))+ "Use -fno-prof-cafs instead"++ -- NEW profiling flags+ , make_ord_flag defGhcFlag "fprof-auto"+ (noArg (\d -> d { profAuto = ProfAutoAll } ))+ , make_ord_flag defGhcFlag "fprof-auto-top"+ (noArg (\d -> d { profAuto = ProfAutoTop } ))+ , make_ord_flag defGhcFlag "fprof-auto-exported"+ (noArg (\d -> d { profAuto = ProfAutoExports } ))+ , make_ord_flag defGhcFlag "fprof-auto-calls"+ (noArg (\d -> d { profAuto = ProfAutoCalls } ))+ , make_ord_flag defGhcFlag "fno-prof-auto"+ (noArg (\d -> d { profAuto = NoProfAuto } ))++ ------ Compiler flags -----------------------------------------------++ , make_ord_flag defGhcFlag "fasm" (NoArg (setObjTarget HscAsm))+ , make_ord_flag defGhcFlag "fvia-c" (NoArg+ (addWarn $ "The -fvia-c flag does nothing; " +++ "it will be removed in a future GHC release"))+ , make_ord_flag defGhcFlag "fvia-C" (NoArg+ (addWarn $ "The -fvia-C flag does nothing; " +++ "it will be removed in a future GHC release"))+ , make_ord_flag defGhcFlag "fllvm" (NoArg (setObjTarget HscLlvm))++ , make_ord_flag defFlag "fno-code" (NoArg ((upd $ \d ->+ d { ghcLink=NoLink }) >> setTarget HscNothing))+ , make_ord_flag defFlag "fbyte-code" (NoArg (setTarget HscInterpreted))+ , make_ord_flag defFlag "fobject-code" (NoArg (setTargetWithPlatform+ defaultHscTarget))+ , make_dep_flag defFlag "fglasgow-exts"+ (NoArg enableGlasgowExts) "Use individual extensions instead"+ , make_dep_flag defFlag "fno-glasgow-exts"+ (NoArg disableGlasgowExts) "Use individual extensions instead"+ , make_ord_flag defFlag "Wunused-binds" (NoArg enableUnusedBinds)+ , make_ord_flag defFlag "Wno-unused-binds" (NoArg disableUnusedBinds)+ , make_ord_flag defHiddenFlag "fwarn-unused-binds" (NoArg enableUnusedBinds)+ , make_ord_flag defHiddenFlag "fno-warn-unused-binds" (NoArg+ disableUnusedBinds)++ ------ Safe Haskell flags -------------------------------------------+ , make_ord_flag defFlag "fpackage-trust" (NoArg setPackageTrust)+ , make_ord_flag defFlag "fno-safe-infer" (noArg (\d ->+ d { safeInfer = False }))+ , make_ord_flag defGhcFlag "fPIC" (NoArg (setGeneralFlag Opt_PIC))+ , make_ord_flag defGhcFlag "fno-PIC" (NoArg (unSetGeneralFlag Opt_PIC))++ ------ Debugging flags ----------------------------------------------+ , make_ord_flag defGhcFlag "g" (OptIntSuffix setDebugLevel)+ ]+ ++ map (mkFlag turnOn "" setGeneralFlag ) negatableFlagsDeps+ ++ map (mkFlag turnOff "no-" unSetGeneralFlag ) negatableFlagsDeps+ ++ map (mkFlag turnOn "d" setGeneralFlag ) dFlagsDeps+ ++ map (mkFlag turnOff "dno-" unSetGeneralFlag ) dFlagsDeps+ ++ map (mkFlag turnOn "f" setGeneralFlag ) fFlagsDeps+ ++ map (mkFlag turnOff "fno-" unSetGeneralFlag ) fFlagsDeps+ ++ map (mkFlag turnOn "W" setWarningFlag ) wWarningFlagsDeps+ ++ map (mkFlag turnOff "Wno-" unSetWarningFlag ) wWarningFlagsDeps+ ++ map (mkFlag turnOn "Werror=" (\flag -> do {+ ; setWarningFlag flag+ ; setFatalWarningFlag flag }))+ wWarningFlagsDeps+ ++ map (mkFlag turnOn "Wwarn=" unSetFatalWarningFlag )+ wWarningFlagsDeps+ ++ map (mkFlag turnOn "Wno-error=" unSetFatalWarningFlag )+ wWarningFlagsDeps+ ++ map (mkFlag turnOn "fwarn-" setWarningFlag . hideFlag)+ wWarningFlagsDeps+ ++ map (mkFlag turnOff "fno-warn-" unSetWarningFlag . hideFlag)+ wWarningFlagsDeps+ ++ [ (NotDeprecated, unrecognisedWarning "W"),+ (Deprecated, unrecognisedWarning "fwarn-"),+ (Deprecated, unrecognisedWarning "fno-warn-") ]+ ++ map (mkFlag turnOn "f" setExtensionFlag ) fLangFlagsDeps+ ++ map (mkFlag turnOff "fno-" unSetExtensionFlag) fLangFlagsDeps+ ++ map (mkFlag turnOn "X" setExtensionFlag ) xFlagsDeps+ ++ map (mkFlag turnOff "XNo" unSetExtensionFlag) xFlagsDeps+ ++ map (mkFlag turnOn "X" setLanguage ) languageFlagsDeps+ ++ map (mkFlag turnOn "X" setSafeHaskell ) safeHaskellFlagsDeps+ ++ [ make_dep_flag defFlag "XGenerics"+ (NoArg $ return ())+ ("it does nothing; look into -XDefaultSignatures " +++ "and -XDeriveGeneric for generic programming support.")+ , make_dep_flag defFlag "XNoGenerics"+ (NoArg $ return ())+ ("it does nothing; look into -XDefaultSignatures and " +++ "-XDeriveGeneric for generic programming support.") ]++-- | This is where we handle unrecognised warning flags. We only issue a warning+-- if -Wunrecognised-warning-flags is set. See Trac #11429 for context.+unrecognisedWarning :: String -> Flag (CmdLineP DynFlags)+unrecognisedWarning prefix = defHiddenFlag prefix (Prefix action)+ where+ action :: String -> EwM (CmdLineP DynFlags) ()+ action flag = do+ f <- wopt Opt_WarnUnrecognisedWarningFlags <$> liftEwM getCmdLineState+ when f $ addWarn $ "unrecognised warning flag: -" ++ prefix ++ flag++-- See Note [Supporting CLI completion]+package_flags_deps :: [(Deprecation, Flag (CmdLineP DynFlags))]+package_flags_deps = [+ ------- Packages ----------------------------------------------------+ make_ord_flag defFlag "package-db"+ (HasArg (addPkgConfRef . PkgConfFile))+ , make_ord_flag defFlag "clear-package-db" (NoArg clearPkgConf)+ , make_ord_flag defFlag "no-global-package-db" (NoArg removeGlobalPkgConf)+ , make_ord_flag defFlag "no-user-package-db" (NoArg removeUserPkgConf)+ , make_ord_flag defFlag "global-package-db"+ (NoArg (addPkgConfRef GlobalPkgConf))+ , make_ord_flag defFlag "user-package-db"+ (NoArg (addPkgConfRef UserPkgConf))+ -- backwards compat with GHC<=7.4 :+ , make_dep_flag defFlag "package-conf"+ (HasArg $ addPkgConfRef . PkgConfFile) "Use -package-db instead"+ , make_dep_flag defFlag "no-user-package-conf"+ (NoArg removeUserPkgConf) "Use -no-user-package-db instead"+ , make_ord_flag defGhcFlag "package-name" (HasArg $ \name -> do+ upd (setUnitId name))+ -- TODO: Since we JUST deprecated+ -- -this-package-key, let's keep this+ -- undeprecated for another cycle.+ -- Deprecate this eventually.+ -- deprecate "Use -this-unit-id instead")+ , make_dep_flag defGhcFlag "this-package-key" (HasArg $ upd . setUnitId)+ "Use -this-unit-id instead"+ , make_ord_flag defGhcFlag "this-unit-id" (hasArg setUnitId)+ , make_ord_flag defFlag "package" (HasArg exposePackage)+ , make_ord_flag defFlag "plugin-package-id" (HasArg exposePluginPackageId)+ , make_ord_flag defFlag "plugin-package" (HasArg exposePluginPackage)+ , make_ord_flag defFlag "package-id" (HasArg exposePackageId)+ , make_ord_flag defFlag "hide-package" (HasArg hidePackage)+ , make_ord_flag defFlag "hide-all-packages"+ (NoArg (setGeneralFlag Opt_HideAllPackages))+ , make_ord_flag defFlag "hide-all-plugin-packages"+ (NoArg (setGeneralFlag Opt_HideAllPluginPackages))+ , make_ord_flag defFlag "package-env" (HasArg setPackageEnv)+ , make_ord_flag defFlag "ignore-package" (HasArg ignorePackage)+ , make_dep_flag defFlag "syslib" (HasArg exposePackage) "Use -package instead"+ , make_ord_flag defFlag "distrust-all-packages"+ (NoArg (setGeneralFlag Opt_DistrustAllPackages))+ , make_ord_flag defFlag "trust" (HasArg trustPackage)+ , make_ord_flag defFlag "distrust" (HasArg distrustPackage)+ ]+ where+ setPackageEnv env = upd $ \s -> s { packageEnv = Just env }++-- | Make a list of flags for shell completion.+-- Filter all available flags into two groups, for interactive GHC vs all other.+flagsForCompletion :: Bool -> [String]+flagsForCompletion isInteractive+ = [ '-':flagName flag+ | flag <- flagsAll+ , modeFilter (flagGhcMode flag)+ ]+ where+ modeFilter AllModes = True+ modeFilter OnlyGhci = isInteractive+ modeFilter OnlyGhc = not isInteractive+ modeFilter HiddenFlag = False++type TurnOnFlag = Bool -- True <=> we are turning the flag on+ -- False <=> we are turning the flag off+turnOn :: TurnOnFlag; turnOn = True+turnOff :: TurnOnFlag; turnOff = False++data FlagSpec flag+ = FlagSpec+ { flagSpecName :: String -- ^ Flag in string form+ , flagSpecFlag :: flag -- ^ Flag in internal form+ , flagSpecAction :: (TurnOnFlag -> DynP ())+ -- ^ Extra action to run when the flag is found+ -- Typically, emit a warning or error+ , flagSpecGhcMode :: GhcFlagMode+ -- ^ In which ghc mode the flag has effect+ }++-- | Define a new flag.+flagSpec :: String -> flag -> (Deprecation, FlagSpec flag)+flagSpec name flag = flagSpec' name flag nop++-- | Define a new flag with an effect.+flagSpec' :: String -> flag -> (TurnOnFlag -> DynP ())+ -> (Deprecation, FlagSpec flag)+flagSpec' name flag act = (NotDeprecated, FlagSpec name flag act AllModes)++-- | Define a new deprecated flag with an effect.+depFlagSpecOp :: String -> flag -> (TurnOnFlag -> DynP ()) -> String+ -> (Deprecation, FlagSpec flag)+depFlagSpecOp name flag act dep =+ (Deprecated, snd (flagSpec' name flag (\f -> act f >> deprecate dep)))++-- | Define a new deprecated flag.+depFlagSpec :: String -> flag -> String+ -> (Deprecation, FlagSpec flag)+depFlagSpec name flag dep = depFlagSpecOp name flag nop dep++-- | Define a new deprecated flag with an effect where the deprecation message+-- depends on the flag value+depFlagSpecOp' :: String+ -> flag+ -> (TurnOnFlag -> DynP ())+ -> (TurnOnFlag -> String)+ -> (Deprecation, FlagSpec flag)+depFlagSpecOp' name flag act dep =+ (Deprecated, FlagSpec name flag (\f -> act f >> (deprecate $ dep f))+ AllModes)++-- | Define a new deprecated flag where the deprecation message+-- depends on the flag value+depFlagSpec' :: String+ -> flag+ -> (TurnOnFlag -> String)+ -> (Deprecation, FlagSpec flag)+depFlagSpec' name flag dep = depFlagSpecOp' name flag nop dep+++-- | Define a new deprecated flag where the deprecation message+-- is shown depending on the flag value+depFlagSpecCond :: String+ -> flag+ -> (TurnOnFlag -> Bool)+ -> String+ -> (Deprecation, FlagSpec flag)+depFlagSpecCond name flag cond dep =+ (Deprecated, FlagSpec name flag (\f -> when (cond f) $ deprecate dep)+ AllModes)++-- | Define a new flag for GHCi.+flagGhciSpec :: String -> flag -> (Deprecation, FlagSpec flag)+flagGhciSpec name flag = flagGhciSpec' name flag nop++-- | Define a new flag for GHCi with an effect.+flagGhciSpec' :: String -> flag -> (TurnOnFlag -> DynP ())+ -> (Deprecation, FlagSpec flag)+flagGhciSpec' name flag act = (NotDeprecated, FlagSpec name flag act OnlyGhci)++-- | Define a new flag invisible to CLI completion.+flagHiddenSpec :: String -> flag -> (Deprecation, FlagSpec flag)+flagHiddenSpec name flag = flagHiddenSpec' name flag nop++-- | Define a new flag invisible to CLI completion with an effect.+flagHiddenSpec' :: String -> flag -> (TurnOnFlag -> DynP ())+ -> (Deprecation, FlagSpec flag)+flagHiddenSpec' name flag act = (NotDeprecated, FlagSpec name flag act+ HiddenFlag)++-- | Hide a 'FlagSpec' from being displayed in @--show-options@.+--+-- This is for example useful for flags that are obsolete, but should not+-- (yet) be deprecated for compatibility reasons.+hideFlag :: (Deprecation, FlagSpec a) -> (Deprecation, FlagSpec a)+hideFlag (dep, fs) = (dep, fs { flagSpecGhcMode = HiddenFlag })++mkFlag :: TurnOnFlag -- ^ True <=> it should be turned on+ -> String -- ^ The flag prefix+ -> (flag -> DynP ()) -- ^ What to do when the flag is found+ -> (Deprecation, FlagSpec flag) -- ^ Specification of+ -- this particular flag+ -> (Deprecation, Flag (CmdLineP DynFlags))+mkFlag turn_on flagPrefix f (dep, (FlagSpec name flag extra_action mode))+ = (dep,+ Flag (flagPrefix ++ name) (NoArg (f flag >> extra_action turn_on)) mode)++deprecatedForExtension :: String -> TurnOnFlag -> String+deprecatedForExtension lang turn_on+ = "use -X" ++ flag +++ " or pragma {-# LANGUAGE " ++ flag ++ " #-} instead"+ where+ flag | turn_on = lang+ | otherwise = "No" ++ lang++useInstead :: String -> TurnOnFlag -> String+useInstead flag turn_on+ = "Use -f" ++ no ++ flag ++ " instead"+ where+ no = if turn_on then "" else "no-"++nop :: TurnOnFlag -> DynP ()+nop _ = return ()++-- | Find the 'FlagSpec' for a 'WarningFlag'.+flagSpecOf :: WarningFlag -> Maybe (FlagSpec WarningFlag)+flagSpecOf flag = listToMaybe $ filter check wWarningFlags+ where+ check fs = flagSpecFlag fs == flag++-- | These @-W\<blah\>@ flags can all be reversed with @-Wno-\<blah\>@+wWarningFlags :: [FlagSpec WarningFlag]+wWarningFlags = map snd (sortBy (comparing fst) wWarningFlagsDeps)++wWarningFlagsDeps :: [(Deprecation, FlagSpec WarningFlag)]+wWarningFlagsDeps = [+-- See Note [Updating flag description in the User's Guide]+-- See Note [Supporting CLI completion]+-- Please keep the list of flags below sorted alphabetically+ flagSpec "alternative-layout-rule-transitional"+ Opt_WarnAlternativeLayoutRuleTransitional,+ depFlagSpec "amp" Opt_WarnAMP+ "it has no effect",+ depFlagSpec "auto-orphans" Opt_WarnAutoOrphans+ "it has no effect",+ flagSpec "cpp-undef" Opt_WarnCPPUndef,+ flagSpec "unbanged-strict-patterns" Opt_WarnUnbangedStrictPatterns,+ flagSpec "deferred-type-errors" Opt_WarnDeferredTypeErrors,+ flagSpec "deferred-out-of-scope-variables"+ Opt_WarnDeferredOutOfScopeVariables,+ flagSpec "deprecations" Opt_WarnWarningsDeprecations,+ flagSpec "deprecated-flags" Opt_WarnDeprecatedFlags,+ flagSpec "deriving-typeable" Opt_WarnDerivingTypeable,+ flagSpec "dodgy-exports" Opt_WarnDodgyExports,+ flagSpec "dodgy-foreign-imports" Opt_WarnDodgyForeignImports,+ flagSpec "dodgy-imports" Opt_WarnDodgyImports,+ flagSpec "empty-enumerations" Opt_WarnEmptyEnumerations,+ depFlagSpec "duplicate-constraints" Opt_WarnDuplicateConstraints+ "it is subsumed by -Wredundant-constraints",+ flagSpec "redundant-constraints" Opt_WarnRedundantConstraints,+ flagSpec "duplicate-exports" Opt_WarnDuplicateExports,+ flagSpec "hi-shadowing" Opt_WarnHiShadows,+ flagSpec "implicit-prelude" Opt_WarnImplicitPrelude,+ flagSpec "incomplete-patterns" Opt_WarnIncompletePatterns,+ flagSpec "incomplete-record-updates" Opt_WarnIncompletePatternsRecUpd,+ flagSpec "incomplete-uni-patterns" Opt_WarnIncompleteUniPatterns,+ flagSpec "inline-rule-shadowing" Opt_WarnInlineRuleShadowing,+ flagSpec "identities" Opt_WarnIdentities,+ flagSpec "missing-fields" Opt_WarnMissingFields,+ flagSpec "missing-import-lists" Opt_WarnMissingImportList,+ depFlagSpec "missing-local-sigs" Opt_WarnMissingLocalSignatures+ "it is replaced by -Wmissing-local-signatures",+ flagSpec "missing-local-signatures" Opt_WarnMissingLocalSignatures,+ flagSpec "missing-methods" Opt_WarnMissingMethods,+ flagSpec "missing-monadfail-instances" Opt_WarnMissingMonadFailInstances,+ flagSpec "semigroup" Opt_WarnSemigroup,+ flagSpec "missing-signatures" Opt_WarnMissingSignatures,+ depFlagSpec "missing-exported-sigs" Opt_WarnMissingExportedSignatures+ "it is replaced by -Wmissing-exported-signatures",+ flagSpec "missing-exported-signatures" Opt_WarnMissingExportedSignatures,+ flagSpec "monomorphism-restriction" Opt_WarnMonomorphism,+ flagSpec "name-shadowing" Opt_WarnNameShadowing,+ flagSpec "noncanonical-monad-instances"+ Opt_WarnNonCanonicalMonadInstances,+ flagSpec "noncanonical-monadfail-instances"+ Opt_WarnNonCanonicalMonadFailInstances,+ flagSpec "noncanonical-monoid-instances"+ Opt_WarnNonCanonicalMonoidInstances,+ flagSpec "orphans" Opt_WarnOrphans,+ flagSpec "overflowed-literals" Opt_WarnOverflowedLiterals,+ flagSpec "overlapping-patterns" Opt_WarnOverlappingPatterns,+ flagSpec "missed-specialisations" Opt_WarnMissedSpecs,+ flagSpec "missed-specializations" Opt_WarnMissedSpecs,+ flagSpec "all-missed-specialisations" Opt_WarnAllMissedSpecs,+ flagSpec "all-missed-specializations" Opt_WarnAllMissedSpecs,+ flagSpec' "safe" Opt_WarnSafe setWarnSafe,+ flagSpec "trustworthy-safe" Opt_WarnTrustworthySafe,+ flagSpec "tabs" Opt_WarnTabs,+ flagSpec "type-defaults" Opt_WarnTypeDefaults,+ flagSpec "typed-holes" Opt_WarnTypedHoles,+ flagSpec "partial-type-signatures" Opt_WarnPartialTypeSignatures,+ flagSpec "unrecognised-pragmas" Opt_WarnUnrecognisedPragmas,+ flagSpec' "unsafe" Opt_WarnUnsafe setWarnUnsafe,+ flagSpec "unsupported-calling-conventions"+ Opt_WarnUnsupportedCallingConventions,+ flagSpec "unsupported-llvm-version" Opt_WarnUnsupportedLlvmVersion,+ flagSpec "unticked-promoted-constructors"+ Opt_WarnUntickedPromotedConstructors,+ flagSpec "unused-do-bind" Opt_WarnUnusedDoBind,+ flagSpec "unused-foralls" Opt_WarnUnusedForalls,+ flagSpec "unused-imports" Opt_WarnUnusedImports,+ flagSpec "unused-local-binds" Opt_WarnUnusedLocalBinds,+ flagSpec "unused-matches" Opt_WarnUnusedMatches,+ flagSpec "unused-pattern-binds" Opt_WarnUnusedPatternBinds,+ flagSpec "unused-top-binds" Opt_WarnUnusedTopBinds,+ flagSpec "unused-type-patterns" Opt_WarnUnusedTypePatterns,+ flagSpec "warnings-deprecations" Opt_WarnWarningsDeprecations,+ flagSpec "wrong-do-bind" Opt_WarnWrongDoBind,+ flagSpec "missing-pattern-synonym-signatures"+ Opt_WarnMissingPatternSynonymSignatures,+ flagSpec "simplifiable-class-constraints" Opt_WarnSimplifiableClassConstraints,+ flagSpec "missing-home-modules" Opt_WarnMissingHomeModules,+ flagSpec "unrecognised-warning-flags" Opt_WarnUnrecognisedWarningFlags ]++-- | These @-\<blah\>@ flags can all be reversed with @-no-\<blah\>@+negatableFlagsDeps :: [(Deprecation, FlagSpec GeneralFlag)]+negatableFlagsDeps = [+ flagGhciSpec "ignore-dot-ghci" Opt_IgnoreDotGhci ]++-- | These @-d\<blah\>@ flags can all be reversed with @-dno-\<blah\>@+dFlagsDeps :: [(Deprecation, FlagSpec GeneralFlag)]+dFlagsDeps = [+-- See Note [Updating flag description in the User's Guide]+-- See Note [Supporting CLI completion]+-- Please keep the list of flags below sorted alphabetically+ flagSpec "ppr-case-as-let" Opt_PprCaseAsLet,+ depFlagSpec' "ppr-ticks" Opt_PprShowTicks+ (\turn_on -> useInstead "suppress-ticks" (not turn_on)),+ flagSpec "suppress-ticks" Opt_SuppressTicks,+ flagSpec "suppress-coercions" Opt_SuppressCoercions,+ flagSpec "suppress-idinfo" Opt_SuppressIdInfo,+ flagSpec "suppress-unfoldings" Opt_SuppressUnfoldings,+ flagSpec "suppress-module-prefixes" Opt_SuppressModulePrefixes,+ flagSpec "suppress-type-applications" Opt_SuppressTypeApplications,+ flagSpec "suppress-type-signatures" Opt_SuppressTypeSignatures,+ flagSpec "suppress-uniques" Opt_SuppressUniques,+ flagSpec "suppress-var-kinds" Opt_SuppressVarKinds]++-- | These @-f\<blah\>@ flags can all be reversed with @-fno-\<blah\>@+fFlags :: [FlagSpec GeneralFlag]+fFlags = map snd fFlagsDeps++fFlagsDeps :: [(Deprecation, FlagSpec GeneralFlag)]+fFlagsDeps = [+-- See Note [Updating flag description in the User's Guide]+-- See Note [Supporting CLI completion]+-- Please keep the list of flags below sorted alphabetically+ flagGhciSpec "break-on-error" Opt_BreakOnError,+ flagGhciSpec "break-on-exception" Opt_BreakOnException,+ flagSpec "building-cabal-package" Opt_BuildingCabalPackage,+ flagSpec "call-arity" Opt_CallArity,+ flagSpec "case-merge" Opt_CaseMerge,+ flagSpec "case-folding" Opt_CaseFolding,+ flagSpec "cmm-elim-common-blocks" Opt_CmmElimCommonBlocks,+ flagSpec "cmm-sink" Opt_CmmSink,+ flagSpec "cse" Opt_CSE,+ flagSpec "stg-cse" Opt_StgCSE,+ flagSpec "cpr-anal" Opt_CprAnal,+ flagSpec "defer-type-errors" Opt_DeferTypeErrors,+ flagSpec "defer-typed-holes" Opt_DeferTypedHoles,+ flagSpec "defer-out-of-scope-variables" Opt_DeferOutOfScopeVariables,+ flagSpec "diagnostics-show-caret" Opt_DiagnosticsShowCaret,+ flagSpec "dicts-cheap" Opt_DictsCheap,+ flagSpec "dicts-strict" Opt_DictsStrict,+ flagSpec "dmd-tx-dict-sel" Opt_DmdTxDictSel,+ flagSpec "do-eta-reduction" Opt_DoEtaReduction,+ flagSpec "do-lambda-eta-expansion" Opt_DoLambdaEtaExpansion,+ flagSpec "eager-blackholing" Opt_EagerBlackHoling,+ flagSpec "embed-manifest" Opt_EmbedManifest,+ flagSpec "enable-rewrite-rules" Opt_EnableRewriteRules,+ flagSpec "error-spans" Opt_ErrorSpans,+ flagSpec "excess-precision" Opt_ExcessPrecision,+ flagSpec "expose-all-unfoldings" Opt_ExposeAllUnfoldings,+ flagSpec "external-interpreter" Opt_ExternalInterpreter,+ flagSpec "flat-cache" Opt_FlatCache,+ flagSpec "float-in" Opt_FloatIn,+ flagSpec "force-recomp" Opt_ForceRecomp,+ flagSpec "full-laziness" Opt_FullLaziness,+ flagSpec "fun-to-thunk" Opt_FunToThunk,+ flagSpec "gen-manifest" Opt_GenManifest,+ flagSpec "ghci-history" Opt_GhciHistory,+ flagGhciSpec "local-ghci-history" Opt_LocalGhciHistory,+ flagSpec "ghci-sandbox" Opt_GhciSandbox,+ flagSpec "helpful-errors" Opt_HelpfulErrors,+ flagSpec "hpc" Opt_Hpc,+ flagSpec "ignore-asserts" Opt_IgnoreAsserts,+ flagSpec "ignore-interface-pragmas" Opt_IgnoreInterfacePragmas,+ flagGhciSpec "implicit-import-qualified" Opt_ImplicitImportQualified,+ flagSpec "irrefutable-tuples" Opt_IrrefutableTuples,+ flagSpec "kill-absence" Opt_KillAbsence,+ flagSpec "kill-one-shot" Opt_KillOneShot,+ flagSpec "late-dmd-anal" Opt_LateDmdAnal,+ flagSpec "liberate-case" Opt_LiberateCase,+ flagHiddenSpec "llvm-pass-vectors-in-regs" Opt_LlvmPassVectorsInRegisters,+ flagHiddenSpec "llvm-tbaa" Opt_LlvmTBAA,+ flagHiddenSpec "llvm-fill-undef-with-garbage" Opt_LlvmFillUndefWithGarbage,+ flagSpec "loopification" Opt_Loopification,+ flagSpec "omit-interface-pragmas" Opt_OmitInterfacePragmas,+ flagSpec "omit-yields" Opt_OmitYields,+ flagSpec "optimal-applicative-do" Opt_OptimalApplicativeDo,+ flagSpec "pedantic-bottoms" Opt_PedanticBottoms,+ flagSpec "pre-inlining" Opt_SimplPreInlining,+ flagGhciSpec "print-bind-contents" Opt_PrintBindContents,+ flagGhciSpec "print-bind-result" Opt_PrintBindResult,+ flagGhciSpec "print-evld-with-show" Opt_PrintEvldWithShow,+ flagSpec "print-explicit-foralls" Opt_PrintExplicitForalls,+ flagSpec "print-explicit-kinds" Opt_PrintExplicitKinds,+ flagSpec "print-explicit-coercions" Opt_PrintExplicitCoercions,+ flagSpec "print-explicit-runtime-reps" Opt_PrintExplicitRuntimeReps,+ flagSpec "print-equality-relations" Opt_PrintEqualityRelations,+ flagSpec "print-unicode-syntax" Opt_PrintUnicodeSyntax,+ flagSpec "print-expanded-synonyms" Opt_PrintExpandedSynonyms,+ flagSpec "print-potential-instances" Opt_PrintPotentialInstances,+ flagSpec "print-typechecker-elaboration" Opt_PrintTypecheckerElaboration,+ flagSpec "prof-cafs" Opt_AutoSccsOnIndividualCafs,+ flagSpec "prof-count-entries" Opt_ProfCountEntries,+ flagSpec "regs-graph" Opt_RegsGraph,+ flagSpec "regs-iterative" Opt_RegsIterative,+ depFlagSpec' "rewrite-rules" Opt_EnableRewriteRules+ (useInstead "enable-rewrite-rules"),+ flagSpec "shared-implib" Opt_SharedImplib,+ flagSpec "spec-constr" Opt_SpecConstr,+ flagSpec "spec-constr-keen" Opt_SpecConstrKeen,+ flagSpec "specialise" Opt_Specialise,+ flagSpec "specialize" Opt_Specialise,+ flagSpec "specialise-aggressively" Opt_SpecialiseAggressively,+ flagSpec "specialize-aggressively" Opt_SpecialiseAggressively,+ flagSpec "cross-module-specialise" Opt_CrossModuleSpecialise,+ flagSpec "cross-module-specialize" Opt_CrossModuleSpecialise,+ flagSpec "static-argument-transformation" Opt_StaticArgumentTransformation,+ flagSpec "strictness" Opt_Strictness,+ flagSpec "use-rpaths" Opt_RPath,+ flagSpec "write-interface" Opt_WriteInterface,+ flagSpec "unbox-small-strict-fields" Opt_UnboxSmallStrictFields,+ flagSpec "unbox-strict-fields" Opt_UnboxStrictFields,+ flagSpec "vectorisation-avoidance" Opt_VectorisationAvoidance,+ flagSpec "vectorise" Opt_Vectorise,+ flagSpec "version-macros" Opt_VersionMacros,+ flagSpec "worker-wrapper" Opt_WorkerWrapper,+ flagSpec "solve-constant-dicts" Opt_SolveConstantDicts,+ flagSpec "show-warning-groups" Opt_ShowWarnGroups,+ flagSpec "hide-source-paths" Opt_HideSourcePaths,+ flagSpec "show-hole-constraints" Opt_ShowHoleConstraints,+ flagSpec "whole-archive-hs-libs" Opt_WholeArchiveHsLibs+ ]++-- | These @-f\<blah\>@ flags can all be reversed with @-fno-\<blah\>@+fLangFlags :: [FlagSpec LangExt.Extension]+fLangFlags = map snd fLangFlagsDeps++fLangFlagsDeps :: [(Deprecation, FlagSpec LangExt.Extension)]+fLangFlagsDeps = [+-- See Note [Updating flag description in the User's Guide]+-- See Note [Supporting CLI completion]+ depFlagSpecOp' "th" LangExt.TemplateHaskell+ checkTemplateHaskellOk+ (deprecatedForExtension "TemplateHaskell"),+ depFlagSpec' "fi" LangExt.ForeignFunctionInterface+ (deprecatedForExtension "ForeignFunctionInterface"),+ depFlagSpec' "ffi" LangExt.ForeignFunctionInterface+ (deprecatedForExtension "ForeignFunctionInterface"),+ depFlagSpec' "arrows" LangExt.Arrows+ (deprecatedForExtension "Arrows"),+ depFlagSpec' "implicit-prelude" LangExt.ImplicitPrelude+ (deprecatedForExtension "ImplicitPrelude"),+ depFlagSpec' "bang-patterns" LangExt.BangPatterns+ (deprecatedForExtension "BangPatterns"),+ depFlagSpec' "monomorphism-restriction" LangExt.MonomorphismRestriction+ (deprecatedForExtension "MonomorphismRestriction"),+ depFlagSpec' "mono-pat-binds" LangExt.MonoPatBinds+ (deprecatedForExtension "MonoPatBinds"),+ depFlagSpec' "extended-default-rules" LangExt.ExtendedDefaultRules+ (deprecatedForExtension "ExtendedDefaultRules"),+ depFlagSpec' "implicit-params" LangExt.ImplicitParams+ (deprecatedForExtension "ImplicitParams"),+ depFlagSpec' "scoped-type-variables" LangExt.ScopedTypeVariables+ (deprecatedForExtension "ScopedTypeVariables"),+ depFlagSpec' "parr" LangExt.ParallelArrays+ (deprecatedForExtension "ParallelArrays"),+ depFlagSpec' "PArr" LangExt.ParallelArrays+ (deprecatedForExtension "ParallelArrays"),+ depFlagSpec' "allow-overlapping-instances" LangExt.OverlappingInstances+ (deprecatedForExtension "OverlappingInstances"),+ depFlagSpec' "allow-undecidable-instances" LangExt.UndecidableInstances+ (deprecatedForExtension "UndecidableInstances"),+ depFlagSpec' "allow-incoherent-instances" LangExt.IncoherentInstances+ (deprecatedForExtension "IncoherentInstances")+ ]++supportedLanguages :: [String]+supportedLanguages = map (flagSpecName . snd) languageFlagsDeps++supportedLanguageOverlays :: [String]+supportedLanguageOverlays = map (flagSpecName . snd) safeHaskellFlagsDeps++supportedExtensions :: [String]+supportedExtensions = concatMap toFlagSpecNamePair xFlags+ where+ toFlagSpecNamePair flg+ | otherwise = [name, noName]+ where+ noName = "No" ++ name+ name = flagSpecName flg++supportedLanguagesAndExtensions :: [String]+supportedLanguagesAndExtensions =+ supportedLanguages ++ supportedLanguageOverlays ++ supportedExtensions++-- | These -X<blah> flags cannot be reversed with -XNo<blah>+languageFlagsDeps :: [(Deprecation, FlagSpec Language)]+languageFlagsDeps = [+ flagSpec "Haskell98" Haskell98,+ flagSpec "Haskell2010" Haskell2010+ ]++-- | These -X<blah> flags cannot be reversed with -XNo<blah>+-- They are used to place hard requirements on what GHC Haskell language+-- features can be used.+safeHaskellFlagsDeps :: [(Deprecation, FlagSpec SafeHaskellMode)]+safeHaskellFlagsDeps = [mkF Sf_Unsafe, mkF Sf_Trustworthy, mkF Sf_Safe]+ where mkF flag = flagSpec (show flag) flag++-- | These -X<blah> flags can all be reversed with -XNo<blah>+xFlags :: [FlagSpec LangExt.Extension]+xFlags = map snd xFlagsDeps++xFlagsDeps :: [(Deprecation, FlagSpec LangExt.Extension)]+xFlagsDeps = [+-- See Note [Updating flag description in the User's Guide]+-- See Note [Supporting CLI completion]+-- See Note [Adding a language extension]+-- Please keep the list of flags below sorted alphabetically+ flagSpec "AllowAmbiguousTypes" LangExt.AllowAmbiguousTypes,+ flagSpec "AlternativeLayoutRule" LangExt.AlternativeLayoutRule,+ flagSpec "AlternativeLayoutRuleTransitional"+ LangExt.AlternativeLayoutRuleTransitional,+ flagSpec "Arrows" LangExt.Arrows,+ flagSpec "AutoDeriveTypeable" LangExt.AutoDeriveTypeable,+ flagSpec "BangPatterns" LangExt.BangPatterns,+ flagSpec "BinaryLiterals" LangExt.BinaryLiterals,+ flagSpec "CApiFFI" LangExt.CApiFFI,+ flagSpec "CPP" LangExt.Cpp,+ flagSpec "ConstrainedClassMethods" LangExt.ConstrainedClassMethods,+ flagSpec "ConstraintKinds" LangExt.ConstraintKinds,+ flagSpec "DataKinds" LangExt.DataKinds,+ depFlagSpecCond "DatatypeContexts" LangExt.DatatypeContexts+ id+ ("It was widely considered a misfeature, " +++ "and has been removed from the Haskell language."),+ flagSpec "DefaultSignatures" LangExt.DefaultSignatures,+ flagSpec "DeriveAnyClass" LangExt.DeriveAnyClass,+ flagSpec "DeriveDataTypeable" LangExt.DeriveDataTypeable,+ flagSpec "DeriveFoldable" LangExt.DeriveFoldable,+ flagSpec "DeriveFunctor" LangExt.DeriveFunctor,+ flagSpec "DeriveGeneric" LangExt.DeriveGeneric,+ flagSpec "DeriveLift" LangExt.DeriveLift,+ flagSpec "DeriveTraversable" LangExt.DeriveTraversable,+ flagSpec "DerivingStrategies" LangExt.DerivingStrategies,+ flagSpec "DisambiguateRecordFields" LangExt.DisambiguateRecordFields,+ flagSpec "DoAndIfThenElse" LangExt.DoAndIfThenElse,+ depFlagSpec' "DoRec" LangExt.RecursiveDo+ (deprecatedForExtension "RecursiveDo"),+ flagSpec "DuplicateRecordFields" LangExt.DuplicateRecordFields,+ flagSpec "EmptyCase" LangExt.EmptyCase,+ flagSpec "EmptyDataDecls" LangExt.EmptyDataDecls,+ flagSpec "ExistentialQuantification" LangExt.ExistentialQuantification,+ flagSpec "ExplicitForAll" LangExt.ExplicitForAll,+ flagSpec "ExplicitNamespaces" LangExt.ExplicitNamespaces,+ flagSpec "ExtendedDefaultRules" LangExt.ExtendedDefaultRules,+ flagSpec "FlexibleContexts" LangExt.FlexibleContexts,+ flagSpec "FlexibleInstances" LangExt.FlexibleInstances,+ flagSpec "ForeignFunctionInterface" LangExt.ForeignFunctionInterface,+ flagSpec "FunctionalDependencies" LangExt.FunctionalDependencies,+ flagSpec "GADTSyntax" LangExt.GADTSyntax,+ flagSpec "GADTs" LangExt.GADTs,+ flagSpec "GHCForeignImportPrim" LangExt.GHCForeignImportPrim,+ flagSpec' "GeneralizedNewtypeDeriving" LangExt.GeneralizedNewtypeDeriving+ setGenDeriving,+ flagSpec "ImplicitParams" LangExt.ImplicitParams,+ flagSpec "ImplicitPrelude" LangExt.ImplicitPrelude,+ flagSpec "ImpredicativeTypes" LangExt.ImpredicativeTypes,+ flagSpec' "IncoherentInstances" LangExt.IncoherentInstances+ setIncoherentInsts,+ flagSpec "TypeFamilyDependencies" LangExt.TypeFamilyDependencies,+ flagSpec "InstanceSigs" LangExt.InstanceSigs,+ flagSpec "ApplicativeDo" LangExt.ApplicativeDo,+ flagSpec "InterruptibleFFI" LangExt.InterruptibleFFI,+ flagSpec "JavaScriptFFI" LangExt.JavaScriptFFI,+ flagSpec "KindSignatures" LangExt.KindSignatures,+ flagSpec "LambdaCase" LangExt.LambdaCase,+ flagSpec "LiberalTypeSynonyms" LangExt.LiberalTypeSynonyms,+ flagSpec "MagicHash" LangExt.MagicHash,+ flagSpec "MonadComprehensions" LangExt.MonadComprehensions,+ flagSpec "MonadFailDesugaring" LangExt.MonadFailDesugaring,+ flagSpec "MonoLocalBinds" LangExt.MonoLocalBinds,+ depFlagSpecCond "MonoPatBinds" LangExt.MonoPatBinds+ id+ "Experimental feature now removed; has no effect",+ flagSpec "MonomorphismRestriction" LangExt.MonomorphismRestriction,+ flagSpec "MultiParamTypeClasses" LangExt.MultiParamTypeClasses,+ flagSpec "MultiWayIf" LangExt.MultiWayIf,+ flagSpec "NPlusKPatterns" LangExt.NPlusKPatterns,+ flagSpec "NamedFieldPuns" LangExt.RecordPuns,+ flagSpec "NamedWildCards" LangExt.NamedWildCards,+ flagSpec "NegativeLiterals" LangExt.NegativeLiterals,+ flagSpec "NondecreasingIndentation" LangExt.NondecreasingIndentation,+ depFlagSpec' "NullaryTypeClasses" LangExt.NullaryTypeClasses+ (deprecatedForExtension "MultiParamTypeClasses"),+ flagSpec "NumDecimals" LangExt.NumDecimals,+ depFlagSpecOp "OverlappingInstances" LangExt.OverlappingInstances+ setOverlappingInsts+ "instead use per-instance pragmas OVERLAPPING/OVERLAPPABLE/OVERLAPS",+ flagSpec "OverloadedLabels" LangExt.OverloadedLabels,+ flagSpec "OverloadedLists" LangExt.OverloadedLists,+ flagSpec "OverloadedStrings" LangExt.OverloadedStrings,+ flagSpec "PackageImports" LangExt.PackageImports,+ flagSpec "ParallelArrays" LangExt.ParallelArrays,+ flagSpec "ParallelListComp" LangExt.ParallelListComp,+ flagSpec "PartialTypeSignatures" LangExt.PartialTypeSignatures,+ flagSpec "PatternGuards" LangExt.PatternGuards,+ depFlagSpec' "PatternSignatures" LangExt.ScopedTypeVariables+ (deprecatedForExtension "ScopedTypeVariables"),+ flagSpec "PatternSynonyms" LangExt.PatternSynonyms,+ flagSpec "PolyKinds" LangExt.PolyKinds,+ flagSpec "PolymorphicComponents" LangExt.RankNTypes,+ flagSpec "PostfixOperators" LangExt.PostfixOperators,+ flagSpec "QuasiQuotes" LangExt.QuasiQuotes,+ flagSpec "Rank2Types" LangExt.RankNTypes,+ flagSpec "RankNTypes" LangExt.RankNTypes,+ flagSpec "RebindableSyntax" LangExt.RebindableSyntax,+ depFlagSpec' "RecordPuns" LangExt.RecordPuns+ (deprecatedForExtension "NamedFieldPuns"),+ flagSpec "RecordWildCards" LangExt.RecordWildCards,+ flagSpec "RecursiveDo" LangExt.RecursiveDo,+ flagSpec "RelaxedLayout" LangExt.RelaxedLayout,+ depFlagSpecCond "RelaxedPolyRec" LangExt.RelaxedPolyRec+ not+ "You can't turn off RelaxedPolyRec any more",+ flagSpec "RoleAnnotations" LangExt.RoleAnnotations,+ flagSpec "ScopedTypeVariables" LangExt.ScopedTypeVariables,+ flagSpec "StandaloneDeriving" LangExt.StandaloneDeriving,+ flagSpec "StaticPointers" LangExt.StaticPointers,+ flagSpec "Strict" LangExt.Strict,+ flagSpec "StrictData" LangExt.StrictData,+ flagSpec' "TemplateHaskell" LangExt.TemplateHaskell+ checkTemplateHaskellOk,+ flagSpec "TemplateHaskellQuotes" LangExt.TemplateHaskellQuotes,+ flagSpec "TraditionalRecordSyntax" LangExt.TraditionalRecordSyntax,+ flagSpec "TransformListComp" LangExt.TransformListComp,+ flagSpec "TupleSections" LangExt.TupleSections,+ flagSpec "TypeApplications" LangExt.TypeApplications,+ flagSpec "TypeInType" LangExt.TypeInType,+ flagSpec "TypeFamilies" LangExt.TypeFamilies,+ flagSpec "TypeOperators" LangExt.TypeOperators,+ flagSpec "TypeSynonymInstances" LangExt.TypeSynonymInstances,+ flagSpec "UnboxedTuples" LangExt.UnboxedTuples,+ flagSpec "UnboxedSums" LangExt.UnboxedSums,+ flagSpec "UndecidableInstances" LangExt.UndecidableInstances,+ flagSpec "UndecidableSuperClasses" LangExt.UndecidableSuperClasses,+ flagSpec "UnicodeSyntax" LangExt.UnicodeSyntax,+ flagSpec "UnliftedFFITypes" LangExt.UnliftedFFITypes,+ flagSpec "ViewPatterns" LangExt.ViewPatterns+ ]++defaultFlags :: Settings -> [GeneralFlag]+defaultFlags settings+-- See Note [Updating flag description in the User's Guide]+ = [ Opt_AutoLinkPackages,+ Opt_DiagnosticsShowCaret,+ Opt_EmbedManifest,+ Opt_FlatCache,+ Opt_GenManifest,+ Opt_GhciHistory,+ Opt_GhciSandbox,+ Opt_HelpfulErrors,+ Opt_KeepHiFiles,+ Opt_KeepOFiles,+ Opt_OmitYields,+ Opt_PrintBindContents,+ Opt_ProfCountEntries,+ Opt_RPath,+ Opt_SharedImplib,+ Opt_SimplPreInlining,+ Opt_VersionMacros+ ]++ ++ [f | (ns,f) <- optLevelFlags, 0 `elem` ns]+ -- The default -O0 options++ ++ default_PIC platform++ ++ concatMap (wayGeneralFlags platform) (defaultWays settings)++ where platform = sTargetPlatform settings++default_PIC :: Platform -> [GeneralFlag]+default_PIC platform =+ case (platformOS platform, platformArch platform) of+ (OSDarwin, ArchX86_64) -> [Opt_PIC]+ (OSOpenBSD, ArchX86_64) -> [Opt_PIC] -- Due to PIE support in+ -- OpenBSD since 5.3 release+ -- (1 May 2013) we need to+ -- always generate PIC. See+ -- #10597 for more+ -- information.+ _ -> []++-- General flags that are switched on/off when other general flags are switched+-- on+impliedGFlags :: [(GeneralFlag, TurnOnFlag, GeneralFlag)]+impliedGFlags = [(Opt_DeferTypeErrors, turnOn, Opt_DeferTypedHoles)+ ,(Opt_DeferTypeErrors, turnOn, Opt_DeferOutOfScopeVariables)+ ,(Opt_Strictness, turnOn, Opt_WorkerWrapper)+ ]++-- General flags that are switched on/off when other general flags are switched+-- off+impliedOffGFlags :: [(GeneralFlag, TurnOnFlag, GeneralFlag)]+impliedOffGFlags = [(Opt_Strictness, turnOff, Opt_WorkerWrapper)]++impliedXFlags :: [(LangExt.Extension, TurnOnFlag, LangExt.Extension)]+impliedXFlags+-- See Note [Updating flag description in the User's Guide]+ = [ (LangExt.RankNTypes, turnOn, LangExt.ExplicitForAll)+ , (LangExt.ScopedTypeVariables, turnOn, LangExt.ExplicitForAll)+ , (LangExt.LiberalTypeSynonyms, turnOn, LangExt.ExplicitForAll)+ , (LangExt.ExistentialQuantification, turnOn, LangExt.ExplicitForAll)+ , (LangExt.FlexibleInstances, turnOn, LangExt.TypeSynonymInstances)+ , (LangExt.FunctionalDependencies, turnOn, LangExt.MultiParamTypeClasses)+ , (LangExt.MultiParamTypeClasses, turnOn, LangExt.ConstrainedClassMethods) -- c.f. Trac #7854+ , (LangExt.TypeFamilyDependencies, turnOn, LangExt.TypeFamilies)++ , (LangExt.RebindableSyntax, turnOff, LangExt.ImplicitPrelude) -- NB: turn off!++ , (LangExt.GADTs, turnOn, LangExt.GADTSyntax)+ , (LangExt.GADTs, turnOn, LangExt.MonoLocalBinds)+ , (LangExt.TypeFamilies, turnOn, LangExt.MonoLocalBinds)++ , (LangExt.TypeFamilies, turnOn, LangExt.KindSignatures) -- Type families use kind signatures+ , (LangExt.PolyKinds, turnOn, LangExt.KindSignatures) -- Ditto polymorphic kinds+ , (LangExt.TypeInType, turnOn, LangExt.DataKinds)+ , (LangExt.TypeInType, turnOn, LangExt.PolyKinds)+ , (LangExt.TypeInType, turnOn, LangExt.KindSignatures)++ -- AutoDeriveTypeable is not very useful without DeriveDataTypeable+ , (LangExt.AutoDeriveTypeable, turnOn, LangExt.DeriveDataTypeable)++ -- We turn this on so that we can export associated type+ -- type synonyms in subordinates (e.g. MyClass(type AssocType))+ , (LangExt.TypeFamilies, turnOn, LangExt.ExplicitNamespaces)+ , (LangExt.TypeOperators, turnOn, LangExt.ExplicitNamespaces)++ , (LangExt.ImpredicativeTypes, turnOn, LangExt.RankNTypes)++ -- Record wild-cards implies field disambiguation+ -- Otherwise if you write (C {..}) you may well get+ -- stuff like " 'a' not in scope ", which is a bit silly+ -- if the compiler has just filled in field 'a' of constructor 'C'+ , (LangExt.RecordWildCards, turnOn, LangExt.DisambiguateRecordFields)++ , (LangExt.ParallelArrays, turnOn, LangExt.ParallelListComp)++ , (LangExt.JavaScriptFFI, turnOn, LangExt.InterruptibleFFI)++ , (LangExt.DeriveTraversable, turnOn, LangExt.DeriveFunctor)+ , (LangExt.DeriveTraversable, turnOn, LangExt.DeriveFoldable)++ -- Duplicate record fields require field disambiguation+ , (LangExt.DuplicateRecordFields, turnOn, LangExt.DisambiguateRecordFields)++ , (LangExt.TemplateHaskell, turnOn, LangExt.TemplateHaskellQuotes)+ , (LangExt.Strict, turnOn, LangExt.StrictData)+ ]++-- Note [Documenting optimisation flags]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- If you change the list of flags enabled for particular optimisation levels+-- please remember to update the User's Guide. The relevant files are:+--+-- * utils/mkUserGuidePart/Options/+-- * docs/users_guide/using.rst+--+-- The first contains the Flag Refrence section, which breifly lists all+-- available flags. The second contains a detailed description of the+-- flags. Both places should contain information whether a flag is implied by+-- -O0, -O or -O2.++optLevelFlags :: [([Int], GeneralFlag)]+optLevelFlags -- see Note [Documenting optimisation flags]+ = [ ([0,1,2], Opt_DoLambdaEtaExpansion)+ , ([0,1,2], Opt_DoEtaReduction) -- See Note [Eta-reduction in -O0]+ , ([0,1,2], Opt_DmdTxDictSel)+ , ([0,1,2], Opt_LlvmTBAA)+ , ([0,1,2], Opt_VectorisationAvoidance)+ -- This one is important for a tiresome reason:+ -- we want to make sure that the bindings for data+ -- constructors are eta-expanded. This is probably+ -- a good thing anyway, but it seems fragile.++ , ([0], Opt_IgnoreInterfacePragmas)+ , ([0], Opt_OmitInterfacePragmas)++ , ([1,2], Opt_CallArity)+ , ([1,2], Opt_CaseMerge)+ , ([1,2], Opt_CaseFolding)+ , ([1,2], Opt_CmmElimCommonBlocks)+ , ([1,2], Opt_CmmSink)+ , ([1,2], Opt_CSE)+ , ([1,2], Opt_StgCSE)+ , ([1,2], Opt_EnableRewriteRules) -- Off for -O0; see Note [Scoping for Builtin rules]+ -- in PrelRules+ , ([1,2], Opt_FloatIn)+ , ([1,2], Opt_FullLaziness)+ , ([1,2], Opt_IgnoreAsserts)+ , ([1,2], Opt_Loopification)+ , ([1,2], Opt_Specialise)+ , ([1,2], Opt_CrossModuleSpecialise)+ , ([1,2], Opt_Strictness)+ , ([1,2], Opt_UnboxSmallStrictFields)+ , ([1,2], Opt_CprAnal)+ , ([1,2], Opt_WorkerWrapper)+ , ([1,2], Opt_SolveConstantDicts)++ , ([2], Opt_LiberateCase)+ , ([2], Opt_SpecConstr)+-- , ([2], Opt_RegsGraph)+-- RegsGraph suffers performance regression. See #7679+-- , ([2], Opt_StaticArgumentTransformation)+-- Static Argument Transformation needs investigation. See #9374+ ]++{- Note [Eta-reduction in -O0]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Trac #11562 showed an example which tripped an ASSERT in CoreToStg; a+function was marked as MayHaveCafRefs when in fact it obviously+didn't. Reason was:+ * Eta reduction wasn't happening in the simplifier, but it was+ happening in CorePrep, on+ $fBla = MkDict (/\a. K a)+ * Result: rhsIsStatic told TidyPgm that $fBla might have CAF refs+ but the eta-reduced version (MkDict K) obviously doesn't+Simple solution: just let the simplifier do eta-reduction even in -O0.+After all, CorePrep does it unconditionally! Not a big deal, but+removes an assertion failure. -}+++-- -----------------------------------------------------------------------------+-- Standard sets of warning options++-- Note [Documenting warning flags]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- If you change the list of warning enabled by default+-- please remember to update the User's Guide. The relevant file is:+--+-- * utils/mkUserGuidePart/+-- * docs/users_guide/using-warnings.rst++-- | Warning groups.+--+-- As all warnings are in the Weverything set, it is ignored when+-- displaying to the user which group a warning is in.+warningGroups :: [(String, [WarningFlag])]+warningGroups =+ [ ("compat", minusWcompatOpts)+ , ("unused-binds", unusedBindsFlags)+ , ("default", standardWarnings)+ , ("extra", minusWOpts)+ , ("all", minusWallOpts)+ , ("everything", minusWeverythingOpts)+ ]++-- | Warning group hierarchies, where there is an explicit inclusion+-- relation.+--+-- Each inner list is a hierarchy of warning groups, ordered from+-- smallest to largest, where each group is a superset of the one+-- before it.+--+-- Separating this from 'warningGroups' allows for multiple+-- hierarchies with no inherent relation to be defined.+--+-- The special-case Weverything group is not included.+warningHierarchies :: [[String]]+warningHierarchies = hierarchies ++ map (:[]) rest+ where+ hierarchies = [["default", "extra", "all"]]+ rest = filter (`notElem` "everything" : concat hierarchies) $+ map fst warningGroups++-- | Find the smallest group in every hierarchy which a warning+-- belongs to, excluding Weverything.+smallestGroups :: WarningFlag -> [String]+smallestGroups flag = mapMaybe go warningHierarchies where+ -- Because each hierarchy is arranged from smallest to largest,+ -- the first group we find in a hierarchy which contains the flag+ -- is the smallest.+ go (group:rest) = fromMaybe (go rest) $ do+ flags <- lookup group warningGroups+ guard (flag `elem` flags)+ pure (Just group)+ go [] = Nothing++-- | Warnings enabled unless specified otherwise+standardWarnings :: [WarningFlag]+standardWarnings -- see Note [Documenting warning flags]+ = [ Opt_WarnOverlappingPatterns,+ Opt_WarnWarningsDeprecations,+ Opt_WarnDeprecatedFlags,+ Opt_WarnDeferredTypeErrors,+ Opt_WarnTypedHoles,+ Opt_WarnDeferredOutOfScopeVariables,+ Opt_WarnPartialTypeSignatures,+ Opt_WarnUnrecognisedPragmas,+ Opt_WarnDuplicateExports,+ Opt_WarnOverflowedLiterals,+ Opt_WarnEmptyEnumerations,+ Opt_WarnMissingFields,+ Opt_WarnMissingMethods,+ Opt_WarnWrongDoBind,+ Opt_WarnUnsupportedCallingConventions,+ Opt_WarnDodgyForeignImports,+ Opt_WarnInlineRuleShadowing,+ Opt_WarnAlternativeLayoutRuleTransitional,+ Opt_WarnUnsupportedLlvmVersion,+ Opt_WarnTabs,+ Opt_WarnUnrecognisedWarningFlags,+ Opt_WarnSimplifiableClassConstraints+ ]++-- | Things you get with -W+minusWOpts :: [WarningFlag]+minusWOpts+ = standardWarnings +++ [ Opt_WarnUnusedTopBinds,+ Opt_WarnUnusedLocalBinds,+ Opt_WarnUnusedPatternBinds,+ Opt_WarnUnusedMatches,+ Opt_WarnUnusedForalls,+ Opt_WarnUnusedImports,+ Opt_WarnIncompletePatterns,+ Opt_WarnDodgyExports,+ Opt_WarnDodgyImports,+ Opt_WarnUnbangedStrictPatterns+ ]++-- | Things you get with -Wall+minusWallOpts :: [WarningFlag]+minusWallOpts+ = minusWOpts +++ [ Opt_WarnTypeDefaults,+ Opt_WarnNameShadowing,+ Opt_WarnMissingSignatures,+ Opt_WarnHiShadows,+ Opt_WarnOrphans,+ Opt_WarnUnusedDoBind,+ Opt_WarnTrustworthySafe,+ Opt_WarnUntickedPromotedConstructors,+ Opt_WarnMissingPatternSynonymSignatures+ ]++-- | Things you get with -Weverything, i.e. *all* known warnings flags+minusWeverythingOpts :: [WarningFlag]+minusWeverythingOpts = [ toEnum 0 .. ]++-- | Things you get with -Wcompat.+--+-- This is intended to group together warnings that will be enabled by default+-- at some point in the future, so that library authors eager to make their+-- code future compatible to fix issues before they even generate warnings.+minusWcompatOpts :: [WarningFlag]+minusWcompatOpts+ = [ Opt_WarnMissingMonadFailInstances+ , Opt_WarnSemigroup+ , Opt_WarnNonCanonicalMonoidInstances+ ]++enableUnusedBinds :: DynP ()+enableUnusedBinds = mapM_ setWarningFlag unusedBindsFlags++disableUnusedBinds :: DynP ()+disableUnusedBinds = mapM_ unSetWarningFlag unusedBindsFlags++-- Things you get with -Wunused-binds+unusedBindsFlags :: [WarningFlag]+unusedBindsFlags = [ Opt_WarnUnusedTopBinds+ , Opt_WarnUnusedLocalBinds+ , Opt_WarnUnusedPatternBinds+ ]++enableGlasgowExts :: DynP ()+enableGlasgowExts = do setGeneralFlag Opt_PrintExplicitForalls+ mapM_ setExtensionFlag glasgowExtsFlags++disableGlasgowExts :: DynP ()+disableGlasgowExts = do unSetGeneralFlag Opt_PrintExplicitForalls+ mapM_ unSetExtensionFlag glasgowExtsFlags++glasgowExtsFlags :: [LangExt.Extension]+glasgowExtsFlags = [+ LangExt.ConstrainedClassMethods+ , LangExt.DeriveDataTypeable+ , LangExt.DeriveFoldable+ , LangExt.DeriveFunctor+ , LangExt.DeriveGeneric+ , LangExt.DeriveTraversable+ , LangExt.EmptyDataDecls+ , LangExt.ExistentialQuantification+ , LangExt.ExplicitNamespaces+ , LangExt.FlexibleContexts+ , LangExt.FlexibleInstances+ , LangExt.ForeignFunctionInterface+ , LangExt.FunctionalDependencies+ , LangExt.GeneralizedNewtypeDeriving+ , LangExt.ImplicitParams+ , LangExt.KindSignatures+ , LangExt.LiberalTypeSynonyms+ , LangExt.MagicHash+ , LangExt.MultiParamTypeClasses+ , LangExt.ParallelListComp+ , LangExt.PatternGuards+ , LangExt.PostfixOperators+ , LangExt.RankNTypes+ , LangExt.RecursiveDo+ , LangExt.ScopedTypeVariables+ , LangExt.StandaloneDeriving+ , LangExt.TypeOperators+ , LangExt.TypeSynonymInstances+ , LangExt.UnboxedTuples+ , LangExt.UnicodeSyntax+ , LangExt.UnliftedFFITypes ]++foreign import ccall unsafe "rts_isProfiled" rtsIsProfiledIO :: IO CInt++-- | Was the runtime system built with profiling enabled?+rtsIsProfiled :: Bool+rtsIsProfiled = unsafeDupablePerformIO rtsIsProfiledIO /= 0++-- Consult the RTS to find whether GHC itself has been built with+-- dynamic linking. This can't be statically known at compile-time,+-- because we build both the static and dynamic versions together with+-- -dynamic-too.+foreign import ccall unsafe "rts_isDynamic" rtsIsDynamicIO :: IO CInt++dynamicGhc :: Bool+dynamicGhc = unsafeDupablePerformIO rtsIsDynamicIO /= 0++setWarnSafe :: Bool -> DynP ()+setWarnSafe True = getCurLoc >>= \l -> upd (\d -> d { warnSafeOnLoc = l })+setWarnSafe False = return ()++setWarnUnsafe :: Bool -> DynP ()+setWarnUnsafe True = getCurLoc >>= \l -> upd (\d -> d { warnUnsafeOnLoc = l })+setWarnUnsafe False = return ()++setPackageTrust :: DynP ()+setPackageTrust = do+ setGeneralFlag Opt_PackageTrust+ l <- getCurLoc+ upd $ \d -> d { pkgTrustOnLoc = l }++setGenDeriving :: TurnOnFlag -> DynP ()+setGenDeriving True = getCurLoc >>= \l -> upd (\d -> d { newDerivOnLoc = l })+setGenDeriving False = return ()++setOverlappingInsts :: TurnOnFlag -> DynP ()+setOverlappingInsts False = return ()+setOverlappingInsts True = do+ l <- getCurLoc+ upd (\d -> d { overlapInstLoc = l })++setIncoherentInsts :: TurnOnFlag -> DynP ()+setIncoherentInsts False = return ()+setIncoherentInsts True = do+ l <- getCurLoc+ upd (\d -> d { incoherentOnLoc = l })++checkTemplateHaskellOk :: TurnOnFlag -> DynP ()+checkTemplateHaskellOk _turn_on+ = getCurLoc >>= \l -> upd (\d -> d { thOnLoc = l })++{- **********************************************************************+%* *+ DynFlags constructors+%* *+%********************************************************************* -}++type DynP = EwM (CmdLineP DynFlags)++upd :: (DynFlags -> DynFlags) -> DynP ()+upd f = liftEwM (do dflags <- getCmdLineState+ putCmdLineState $! f dflags)++updM :: (DynFlags -> DynP DynFlags) -> DynP ()+updM f = do dflags <- liftEwM getCmdLineState+ dflags' <- f dflags+ liftEwM $ putCmdLineState $! dflags'++--------------- Constructor functions for OptKind -----------------+noArg :: (DynFlags -> DynFlags) -> OptKind (CmdLineP DynFlags)+noArg fn = NoArg (upd fn)++noArgM :: (DynFlags -> DynP DynFlags) -> OptKind (CmdLineP DynFlags)+noArgM fn = NoArg (updM fn)++hasArg :: (String -> DynFlags -> DynFlags) -> OptKind (CmdLineP DynFlags)+hasArg fn = HasArg (upd . fn)++sepArg :: (String -> DynFlags -> DynFlags) -> OptKind (CmdLineP DynFlags)+sepArg fn = SepArg (upd . fn)++intSuffix :: (Int -> DynFlags -> DynFlags) -> OptKind (CmdLineP DynFlags)+intSuffix fn = IntSuffix (\n -> upd (fn n))++intSuffixM :: (Int -> DynFlags -> DynP DynFlags) -> OptKind (CmdLineP DynFlags)+intSuffixM fn = IntSuffix (\n -> updM (fn n))++floatSuffix :: (Float -> DynFlags -> DynFlags) -> OptKind (CmdLineP DynFlags)+floatSuffix fn = FloatSuffix (\n -> upd (fn n))++optIntSuffixM :: (Maybe Int -> DynFlags -> DynP DynFlags)+ -> OptKind (CmdLineP DynFlags)+optIntSuffixM fn = OptIntSuffix (\mi -> updM (fn mi))++setDumpFlag :: DumpFlag -> OptKind (CmdLineP DynFlags)+setDumpFlag dump_flag = NoArg (setDumpFlag' dump_flag)++--------------------------+addWay :: Way -> DynP ()+addWay w = upd (addWay' w)++addWay' :: Way -> DynFlags -> DynFlags+addWay' w dflags0 = let platform = targetPlatform dflags0+ dflags1 = dflags0 { ways = w : ways dflags0 }+ dflags2 = foldr setGeneralFlag' dflags1+ (wayGeneralFlags platform w)+ dflags3 = foldr unSetGeneralFlag' dflags2+ (wayUnsetGeneralFlags platform w)+ in dflags3++removeWayDyn :: DynP ()+removeWayDyn = upd (\dfs -> dfs { ways = filter (WayDyn /=) (ways dfs) })++--------------------------+setGeneralFlag, unSetGeneralFlag :: GeneralFlag -> DynP ()+setGeneralFlag f = upd (setGeneralFlag' f)+unSetGeneralFlag f = upd (unSetGeneralFlag' f)++setGeneralFlag' :: GeneralFlag -> DynFlags -> DynFlags+setGeneralFlag' f dflags = foldr ($) (gopt_set dflags f) deps+ where+ deps = [ if turn_on then setGeneralFlag' d+ else unSetGeneralFlag' d+ | (f', turn_on, d) <- impliedGFlags, f' == f ]+ -- When you set f, set the ones it implies+ -- NB: use setGeneralFlag recursively, in case the implied flags+ -- implies further flags++unSetGeneralFlag' :: GeneralFlag -> DynFlags -> DynFlags+unSetGeneralFlag' f dflags = foldr ($) (gopt_unset dflags f) deps+ where+ deps = [ if turn_on then setGeneralFlag' d+ else unSetGeneralFlag' d+ | (f', turn_on, d) <- impliedOffGFlags, f' == f ]+ -- In general, when you un-set f, we don't un-set the things it implies.+ -- There are however some exceptions, e.g., -fno-strictness implies+ -- -fno-worker-wrapper.+ --+ -- NB: use unSetGeneralFlag' recursively, in case the implied off flags+ -- imply further flags.++--------------------------+setWarningFlag, unSetWarningFlag :: WarningFlag -> DynP ()+setWarningFlag f = upd (\dfs -> wopt_set dfs f)+unSetWarningFlag f = upd (\dfs -> wopt_unset dfs f)++setFatalWarningFlag, unSetFatalWarningFlag :: WarningFlag -> DynP ()+setFatalWarningFlag f = upd (\dfs -> wopt_set_fatal dfs f)+unSetFatalWarningFlag f = upd (\dfs -> wopt_unset_fatal dfs f)++--------------------------+setExtensionFlag, unSetExtensionFlag :: LangExt.Extension -> DynP ()+setExtensionFlag f = upd (setExtensionFlag' f)+unSetExtensionFlag f = upd (unSetExtensionFlag' f)++setExtensionFlag', unSetExtensionFlag' :: LangExt.Extension -> DynFlags -> DynFlags+setExtensionFlag' f dflags = foldr ($) (xopt_set dflags f) deps+ where+ deps = [ if turn_on then setExtensionFlag' d+ else unSetExtensionFlag' d+ | (f', turn_on, d) <- impliedXFlags, f' == f ]+ -- When you set f, set the ones it implies+ -- NB: use setExtensionFlag recursively, in case the implied flags+ -- implies further flags++unSetExtensionFlag' f dflags = xopt_unset dflags f+ -- When you un-set f, however, we don't un-set the things it implies+ -- (except for -fno-glasgow-exts, which is treated specially)++--------------------------+alterSettings :: (Settings -> Settings) -> DynFlags -> DynFlags+alterSettings f dflags = dflags { settings = f (settings dflags) }++--------------------------+setDumpFlag' :: DumpFlag -> DynP ()+setDumpFlag' dump_flag+ = do upd (\dfs -> dopt_set dfs dump_flag)+ when want_recomp forceRecompile+ where -- Certain dumpy-things are really interested in what's going+ -- on during recompilation checking, so in those cases we+ -- don't want to turn it off.+ want_recomp = dump_flag `notElem` [Opt_D_dump_if_trace,+ Opt_D_dump_hi_diffs,+ Opt_D_no_debug_output]++forceRecompile :: DynP ()+-- Whenver we -ddump, force recompilation (by switching off the+-- recompilation checker), else you don't see the dump! However,+-- don't switch it off in --make mode, else *everything* gets+-- recompiled which probably isn't what you want+forceRecompile = do dfs <- liftEwM getCmdLineState+ when (force_recomp dfs) (setGeneralFlag Opt_ForceRecomp)+ where+ force_recomp dfs = isOneShot (ghcMode dfs)+++setVerboseCore2Core :: DynP ()+setVerboseCore2Core = setDumpFlag' Opt_D_verbose_core2core++setVerbosity :: Maybe Int -> DynP ()+setVerbosity mb_n = upd (\dfs -> dfs{ verbosity = mb_n `orElse` 3 })++setDebugLevel :: Maybe Int -> DynP ()+setDebugLevel mb_n = upd (\dfs -> dfs{ debugLevel = mb_n `orElse` 2 })++data PkgConfRef+ = GlobalPkgConf+ | UserPkgConf+ | PkgConfFile FilePath+ deriving Eq++addPkgConfRef :: PkgConfRef -> DynP ()+addPkgConfRef p = upd $ \s ->+ s { packageDBFlags = PackageDB p : packageDBFlags s }++removeUserPkgConf :: DynP ()+removeUserPkgConf = upd $ \s ->+ s { packageDBFlags = NoUserPackageDB : packageDBFlags s }++removeGlobalPkgConf :: DynP ()+removeGlobalPkgConf = upd $ \s ->+ s { packageDBFlags = NoGlobalPackageDB : packageDBFlags s }++clearPkgConf :: DynP ()+clearPkgConf = upd $ \s ->+ s { packageDBFlags = ClearPackageDBs : packageDBFlags s }++parsePackageFlag :: String -- the flag+ -> ReadP PackageArg -- type of argument+ -> String -- string to parse+ -> PackageFlag+parsePackageFlag flag arg_parse str+ = case filter ((=="").snd) (readP_to_S parse str) of+ [(r, "")] -> r+ _ -> throwGhcException $ CmdLineError ("Can't parse package flag: " ++ str)+ where doc = flag ++ " " ++ str+ parse = do+ pkg_arg <- tok arg_parse+ let mk_expose = ExposePackage doc pkg_arg+ ( do _ <- tok $ string "with"+ fmap (mk_expose . ModRenaming True) parseRns+ <++ fmap (mk_expose . ModRenaming False) parseRns+ <++ return (mk_expose (ModRenaming True [])))+ parseRns = do _ <- tok $ R.char '('+ rns <- tok $ sepBy parseItem (tok $ R.char ',')+ _ <- tok $ R.char ')'+ return rns+ parseItem = do+ orig <- tok $ parseModuleName+ (do _ <- tok $ string "as"+ new <- tok $ parseModuleName+ return (orig, new)+ ++++ return (orig, orig))+ tok m = m >>= \x -> skipSpaces >> return x++exposePackage, exposePackageId, hidePackage,+ exposePluginPackage, exposePluginPackageId,+ ignorePackage,+ trustPackage, distrustPackage :: String -> DynP ()+exposePackage p = upd (exposePackage' p)+exposePackageId p =+ upd (\s -> s{ packageFlags =+ parsePackageFlag "-package-id" parseUnitIdArg p : packageFlags s })+exposePluginPackage p =+ upd (\s -> s{ pluginPackageFlags =+ parsePackageFlag "-plugin-package" parsePackageArg p : pluginPackageFlags s })+exposePluginPackageId p =+ upd (\s -> s{ pluginPackageFlags =+ parsePackageFlag "-plugin-package-id" parseUnitIdArg p : pluginPackageFlags s })+hidePackage p =+ upd (\s -> s{ packageFlags = HidePackage p : packageFlags s })+ignorePackage p =+ upd (\s -> s{ ignorePackageFlags = IgnorePackage p : ignorePackageFlags s })++trustPackage p = exposePackage p >> -- both trust and distrust also expose a package+ upd (\s -> s{ trustFlags = TrustPackage p : trustFlags s })+distrustPackage p = exposePackage p >>+ upd (\s -> s{ trustFlags = DistrustPackage p : trustFlags s })++exposePackage' :: String -> DynFlags -> DynFlags+exposePackage' p dflags+ = dflags { packageFlags =+ parsePackageFlag "-package" parsePackageArg p : packageFlags dflags }++parsePackageArg :: ReadP PackageArg+parsePackageArg =+ fmap PackageArg (munch1 (\c -> isAlphaNum c || c `elem` ":-_."))++parseUnitIdArg :: ReadP PackageArg+parseUnitIdArg =+ fmap UnitIdArg parseUnitId++setUnitId :: String -> DynFlags -> DynFlags+setUnitId p d = d { thisInstalledUnitId = stringToInstalledUnitId p }++-- | Given a 'ModuleName' of a signature in the home library, find+-- out how it is instantiated. E.g., the canonical form of+-- A in @p[A=q[]:A]@ is @q[]:A@.+canonicalizeHomeModule :: DynFlags -> ModuleName -> Module+canonicalizeHomeModule dflags mod_name =+ case lookup mod_name (thisUnitIdInsts dflags) of+ Nothing -> mkModule (thisPackage dflags) mod_name+ Just mod -> mod+++-- -----------------------------------------------------------------------------+-- | Find the package environment (if one exists)+--+-- We interpret the package environment as a set of package flags; to be+-- specific, if we find a package environment file like+--+-- > clear-package-db+-- > global-package-db+-- > package-db blah/package.conf.d+-- > package-id id1+-- > package-id id2+--+-- we interpret this as+--+-- > [ -hide-all-packages+-- > , -clear-package-db+-- > , -global-package-db+-- > , -package-db blah/package.conf.d+-- > , -package-id id1+-- > , -package-id id2+-- > ]+--+-- There's also an older syntax alias for package-id, which is just an+-- unadorned package id+--+-- > id1+-- > id2+--+interpretPackageEnv :: DynFlags -> IO DynFlags+interpretPackageEnv dflags = do+ mPkgEnv <- runMaybeT $ msum $ [+ getCmdLineArg >>= \env -> msum [+ probeEnvFile env+ , probeEnvName env+ , cmdLineError env+ ]+ , getEnvVar >>= \env -> msum [+ probeEnvFile env+ , probeEnvName env+ , envError env+ ]+ , notIfHideAllPackages >> msum [+ findLocalEnvFile >>= probeEnvFile+ , probeEnvName defaultEnvName+ ]+ ]+ case mPkgEnv of+ Nothing ->+ -- No environment found. Leave DynFlags unchanged.+ return dflags+ Just envfile -> do+ content <- readFile envfile+ let setFlags :: DynP ()+ setFlags = do+ setGeneralFlag Opt_HideAllPackages+ parseEnvFile envfile content++ (_, dflags') = runCmdLine (runEwM setFlags) dflags++ return dflags'+ where+ -- Loading environments (by name or by location)++ namedEnvPath :: String -> MaybeT IO FilePath+ namedEnvPath name = do+ appdir <- versionedAppDir dflags+ return $ appdir </> "environments" </> name++ probeEnvName :: String -> MaybeT IO FilePath+ probeEnvName name = probeEnvFile =<< namedEnvPath name++ probeEnvFile :: FilePath -> MaybeT IO FilePath+ probeEnvFile path = do+ guard =<< liftMaybeT (doesFileExist path)+ return path++ parseEnvFile :: FilePath -> String -> DynP ()+ parseEnvFile envfile = mapM_ parseEntry . lines+ where+ parseEntry str = case words str of+ ("package-db": _) -> addPkgConfRef (PkgConfFile (envdir </> db))+ -- relative package dbs are interpreted relative to the env file+ where envdir = takeDirectory envfile+ db = drop 11 str+ ["clear-package-db"] -> clearPkgConf+ ["global-package-db"] -> addPkgConfRef GlobalPkgConf+ ["user-package-db"] -> addPkgConfRef UserPkgConf+ ["package-id", pkgid] -> exposePackageId pkgid+ (('-':'-':_):_) -> return () -- comments+ -- and the original syntax introduced in 7.10:+ [pkgid] -> exposePackageId pkgid+ [] -> return ()+ _ -> throwGhcException $ CmdLineError $+ "Can't parse environment file entry: "+ ++ envfile ++ ": " ++ str++ -- Various ways to define which environment to use++ getCmdLineArg :: MaybeT IO String+ getCmdLineArg = MaybeT $ return $ packageEnv dflags++ getEnvVar :: MaybeT IO String+ getEnvVar = do+ mvar <- liftMaybeT $ try $ getEnv "GHC_ENVIRONMENT"+ case mvar of+ Right var -> return var+ Left err -> if isDoesNotExistError err then mzero+ else liftMaybeT $ throwIO err++ notIfHideAllPackages :: MaybeT IO ()+ notIfHideAllPackages =+ guard (not (gopt Opt_HideAllPackages dflags))++ defaultEnvName :: String+ defaultEnvName = "default"++ -- e.g. .ghc.environment.x86_64-linux-7.6.3+ localEnvFileName :: FilePath+ localEnvFileName = ".ghc.environment" <.> versionedFilePath dflags++ -- Search for an env file, starting in the current dir and looking upwards.+ -- Fail if we get to the users home dir or the filesystem root. That is,+ -- we don't look for an env file in the user's home dir. The user-wide+ -- env lives in ghc's versionedAppDir/environments/default+ findLocalEnvFile :: MaybeT IO FilePath+ findLocalEnvFile = do+ curdir <- liftMaybeT getCurrentDirectory+ homedir <- tryMaybeT getHomeDirectory+ let probe dir | isDrive dir || dir == homedir+ = mzero+ probe dir = do+ let file = dir </> localEnvFileName+ exists <- liftMaybeT (doesFileExist file)+ if exists+ then return file+ else probe (takeDirectory dir)+ probe curdir++ -- Error reporting++ cmdLineError :: String -> MaybeT IO a+ cmdLineError env = liftMaybeT . throwGhcExceptionIO . CmdLineError $+ "Package environment " ++ show env ++ " not found"++ envError :: String -> MaybeT IO a+ envError env = liftMaybeT . throwGhcExceptionIO . CmdLineError $+ "Package environment "+ ++ show env+ ++ " (specified in GHC_ENVIRONMENT) not found"+++-- If we're linking a binary, then only targets that produce object+-- code are allowed (requests for other target types are ignored).+setTarget :: HscTarget -> DynP ()+setTarget l = setTargetWithPlatform (const l)++setTargetWithPlatform :: (Platform -> HscTarget) -> DynP ()+setTargetWithPlatform f = upd set+ where+ set dfs = let l = f (targetPlatform dfs)+ in if ghcLink dfs /= LinkBinary || isObjectTarget l+ then dfs{ hscTarget = l }+ else dfs++-- Changes the target only if we're compiling object code. This is+-- used by -fasm and -fllvm, which switch from one to the other, but+-- not from bytecode to object-code. The idea is that -fasm/-fllvm+-- can be safely used in an OPTIONS_GHC pragma.+setObjTarget :: HscTarget -> DynP ()+setObjTarget l = updM set+ where+ set dflags+ | isObjectTarget (hscTarget dflags)+ = return $ dflags { hscTarget = l }+ | otherwise = return dflags++setOptLevel :: Int -> DynFlags -> DynP DynFlags+setOptLevel n dflags = return (updOptLevel n dflags)++checkOptLevel :: Int -> DynFlags -> Either String DynFlags+checkOptLevel n dflags+ | hscTarget dflags == HscInterpreted && n > 0+ = Left "-O conflicts with --interactive; -O ignored."+ | otherwise+ = Right dflags++-- -Odph is equivalent to+--+-- -O2 optimise as much as possible+-- -fmax-simplifier-iterations20 this is necessary sometimes+-- -fsimplifier-phases=3 we use an additional simplifier phase for fusion+--+setDPHOpt :: DynFlags -> DynP DynFlags+setDPHOpt dflags = setOptLevel 2 (dflags { maxSimplIterations = 20+ , simplPhases = 3+ })++setMainIs :: String -> DynP ()+setMainIs arg+ | not (null main_fn) && isLower (head main_fn)+ -- The arg looked like "Foo.Bar.baz"+ = upd $ \d -> d { mainFunIs = Just main_fn,+ mainModIs = mkModule mainUnitId (mkModuleName main_mod) }++ | isUpper (head arg) -- The arg looked like "Foo" or "Foo.Bar"+ = upd $ \d -> d { mainModIs = mkModule mainUnitId (mkModuleName arg) }++ | otherwise -- The arg looked like "baz"+ = upd $ \d -> d { mainFunIs = Just arg }+ where+ (main_mod, main_fn) = splitLongestPrefix arg (== '.')++addLdInputs :: Option -> DynFlags -> DynFlags+addLdInputs p dflags = dflags{ldInputs = ldInputs dflags ++ [p]}++-----------------------------------------------------------------------------+-- Paths & Libraries++addImportPath, addLibraryPath, addIncludePath, addFrameworkPath :: FilePath -> DynP ()++-- -i on its own deletes the import paths+addImportPath "" = upd (\s -> s{importPaths = []})+addImportPath p = upd (\s -> s{importPaths = importPaths s ++ splitPathList p})++addLibraryPath p =+ upd (\s -> s{libraryPaths = libraryPaths s ++ splitPathList p})++addIncludePath p =+ upd (\s -> s{includePaths = includePaths s ++ splitPathList p})++addFrameworkPath p =+ upd (\s -> s{frameworkPaths = frameworkPaths s ++ splitPathList p})++#ifndef mingw32_TARGET_OS+split_marker :: Char+split_marker = ':' -- not configurable (ToDo)+#endif++splitPathList :: String -> [String]+splitPathList s = filter notNull (splitUp s)+ -- empty paths are ignored: there might be a trailing+ -- ':' in the initial list, for example. Empty paths can+ -- cause confusion when they are translated into -I options+ -- for passing to gcc.+ where+#ifndef mingw32_TARGET_OS+ splitUp xs = split split_marker xs+#else+ -- Windows: 'hybrid' support for DOS-style paths in directory lists.+ --+ -- That is, if "foo:bar:baz" is used, this interpreted as+ -- consisting of three entries, 'foo', 'bar', 'baz'.+ -- However, with "c:/foo:c:\\foo;x:/bar", this is interpreted+ -- as 3 elts, "c:/foo", "c:\\foo", "x:/bar"+ --+ -- Notice that no attempt is made to fully replace the 'standard'+ -- split marker ':' with the Windows / DOS one, ';'. The reason being+ -- that this will cause too much breakage for users & ':' will+ -- work fine even with DOS paths, if you're not insisting on being silly.+ -- So, use either.+ splitUp [] = []+ splitUp (x:':':div:xs) | div `elem` dir_markers+ = ((x:':':div:p): splitUp rs)+ where+ (p,rs) = findNextPath xs+ -- we used to check for existence of the path here, but that+ -- required the IO monad to be threaded through the command-line+ -- parser which is quite inconvenient. The+ splitUp xs = cons p (splitUp rs)+ where+ (p,rs) = findNextPath xs++ cons "" xs = xs+ cons x xs = x:xs++ -- will be called either when we've consumed nought or the+ -- "<Drive>:/" part of a DOS path, so splitting is just a Q of+ -- finding the next split marker.+ findNextPath xs =+ case break (`elem` split_markers) xs of+ (p, _:ds) -> (p, ds)+ (p, xs) -> (p, xs)++ split_markers :: [Char]+ split_markers = [':', ';']++ dir_markers :: [Char]+ dir_markers = ['/', '\\']+#endif++-- -----------------------------------------------------------------------------+-- tmpDir, where we store temporary files.++setTmpDir :: FilePath -> DynFlags -> DynFlags+setTmpDir dir = alterSettings (\s -> s { sTmpDir = normalise dir })+ -- we used to fix /cygdrive/c/.. on Windows, but this doesn't+ -- seem necessary now --SDM 7/2/2008++-----------------------------------------------------------------------------+-- RTS opts++setRtsOpts :: String -> DynP ()+setRtsOpts arg = upd $ \ d -> d {rtsOpts = Just arg}++setRtsOptsEnabled :: RtsOptsEnabled -> DynP ()+setRtsOptsEnabled arg = upd $ \ d -> d {rtsOptsEnabled = arg}++-----------------------------------------------------------------------------+-- Hpc stuff++setOptHpcDir :: String -> DynP ()+setOptHpcDir arg = upd $ \ d -> d {hpcDir = arg}++-----------------------------------------------------------------------------+-- Via-C compilation stuff++-- There are some options that we need to pass to gcc when compiling+-- Haskell code via C, but are only supported by recent versions of+-- gcc. The configure script decides which of these options we need,+-- and puts them in the "settings" file in $topdir. The advantage of+-- having these in a separate file is that the file can be created at+-- install-time depending on the available gcc version, and even+-- re-generated later if gcc is upgraded.+--+-- The options below are not dependent on the version of gcc, only the+-- platform.++picCCOpts :: DynFlags -> [String]+picCCOpts dflags+ = case platformOS (targetPlatform dflags) of+ OSDarwin+ -- Apple prefers to do things the other way round.+ -- PIC is on by default.+ -- -mdynamic-no-pic:+ -- Turn off PIC code generation.+ -- -fno-common:+ -- Don't generate "common" symbols - these are unwanted+ -- in dynamic libraries.++ | gopt Opt_PIC dflags -> ["-fno-common", "-U__PIC__", "-D__PIC__"]+ | otherwise -> ["-mdynamic-no-pic"]+ OSMinGW32 -- no -fPIC for Windows+ | gopt Opt_PIC dflags -> ["-U__PIC__", "-D__PIC__"]+ | otherwise -> []+ _+ -- we need -fPIC for C files when we are compiling with -dynamic,+ -- otherwise things like stub.c files don't get compiled+ -- correctly. They need to reference data in the Haskell+ -- objects, but can't without -fPIC. See+ -- http://ghc.haskell.org/trac/ghc/wiki/Commentary/PositionIndependentCode+ | gopt Opt_PIC dflags || WayDyn `elem` ways dflags ->+ ["-fPIC", "-U__PIC__", "-D__PIC__"]+ | otherwise -> []++picPOpts :: DynFlags -> [String]+picPOpts dflags+ | gopt Opt_PIC dflags = ["-U__PIC__", "-D__PIC__"]+ | otherwise = []++-- -----------------------------------------------------------------------------+-- Splitting++can_split :: Bool+can_split = cSupportsSplitObjs == "YES"++-- -----------------------------------------------------------------------------+-- Compiler Info++compilerInfo :: DynFlags -> [(String, String)]+compilerInfo dflags+ = -- We always make "Project name" be first to keep parsing in+ -- other languages simple, i.e. when looking for other fields,+ -- you don't have to worry whether there is a leading '[' or not+ ("Project name", cProjectName)+ -- Next come the settings, so anything else can be overridden+ -- in the settings file (as "lookup" uses the first match for the+ -- key)+ : rawSettings dflags+ ++ [("Project version", projectVersion dflags),+ ("Project Git commit id", cProjectGitCommitId),+ ("Booter version", cBooterVersion),+ ("Stage", cStage),+ ("Build platform", cBuildPlatformString),+ ("Host platform", cHostPlatformString),+ ("Target platform", cTargetPlatformString),+ ("Have interpreter", cGhcWithInterpreter),+ ("Object splitting supported", cSupportsSplitObjs),+ ("Have native code generator", cGhcWithNativeCodeGen),+ ("Support SMP", cGhcWithSMP),+ ("Tables next to code", cGhcEnableTablesNextToCode),+ ("RTS ways", cGhcRTSWays),+ ("RTS expects libdw", showBool cGhcRtsWithLibdw),+ -- Whether or not we support @-dynamic-too@+ ("Support dynamic-too", showBool $ not isWindows),+ -- Whether or not we support the @-j@ flag with @--make@.+ ("Support parallel --make", "YES"),+ -- Whether or not we support "Foo from foo-0.1-XXX:Foo" syntax in+ -- installed package info.+ ("Support reexported-modules", "YES"),+ -- Whether or not we support extended @-package foo (Foo)@ syntax.+ ("Support thinning and renaming package flags", "YES"),+ -- Whether or not we support Backpack.+ ("Support Backpack", "YES"),+ -- If true, we require that the 'id' field in installed package info+ -- match what is passed to the @-this-unit-id@ flag for modules+ -- built in it+ ("Requires unified installed package IDs", "YES"),+ -- Whether or not we support the @-this-package-key@ flag. Prefer+ -- "Uses unit IDs" over it.+ ("Uses package keys", "YES"),+ -- Whether or not we support the @-this-unit-id@ flag+ ("Uses unit IDs", "YES"),+ -- Whether or not GHC compiles libraries as dynamic by default+ ("Dynamic by default", showBool $ dYNAMIC_BY_DEFAULT dflags),+ -- Whether or not GHC was compiled using -dynamic+ ("GHC Dynamic", showBool dynamicGhc),+ -- Whether or not GHC was compiled using -prof+ ("GHC Profiled", showBool rtsIsProfiled),+ ("Leading underscore", cLeadingUnderscore),+ ("Debug on", show debugIsOn),+ ("LibDir", topDir dflags),+ -- The path of the global package database used by GHC+ ("Global Package DB", systemPackageConfig dflags)+ ]+ where+ showBool True = "YES"+ showBool False = "NO"+ isWindows = platformOS (targetPlatform dflags) == OSMinGW32++-- Produced by deriveConstants+#include "GHCConstantsHaskellWrappers.hs"++bLOCK_SIZE_W :: DynFlags -> Int+bLOCK_SIZE_W dflags = bLOCK_SIZE dflags `quot` wORD_SIZE dflags++wORD_SIZE_IN_BITS :: DynFlags -> Int+wORD_SIZE_IN_BITS dflags = wORD_SIZE dflags * 8++tAG_MASK :: DynFlags -> Int+tAG_MASK dflags = (1 `shiftL` tAG_BITS dflags) - 1++mAX_PTR_TAG :: DynFlags -> Int+mAX_PTR_TAG = tAG_MASK++-- Might be worth caching these in targetPlatform?+tARGET_MIN_INT, tARGET_MAX_INT, tARGET_MAX_WORD :: DynFlags -> Integer+tARGET_MIN_INT dflags+ = case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (minBound :: Int32)+ 8 -> toInteger (minBound :: Int64)+ w -> panic ("tARGET_MIN_INT: Unknown platformWordSize: " ++ show w)+tARGET_MAX_INT dflags+ = case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (maxBound :: Int32)+ 8 -> toInteger (maxBound :: Int64)+ w -> panic ("tARGET_MAX_INT: Unknown platformWordSize: " ++ show w)+tARGET_MAX_WORD dflags+ = case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (maxBound :: Word32)+ 8 -> toInteger (maxBound :: Word64)+ w -> panic ("tARGET_MAX_WORD: Unknown platformWordSize: " ++ show w)+++{- -----------------------------------------------------------------------------+Note [DynFlags consistency]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++There are a number of number of DynFlags configurations which either+do not make sense or lead to unimplemented or buggy codepaths in the+compiler. makeDynFlagsConsistent is responsible for verifying the validity+of a set of DynFlags, fixing any issues, and reporting them back to the+caller.++GHCi and -O+---------------++When using optimization, the compiler can introduce several things+(such as unboxed tuples) into the intermediate code, which GHCi later+chokes on since the bytecode interpreter can't handle this (and while+this is arguably a bug these aren't handled, there are no plans to fix+it.)++While the driver pipeline always checks for this particular erroneous+combination when parsing flags, we also need to check when we update+the flags; this is because API clients may parse flags but update the+DynFlags afterwords, before finally running code inside a session (see+T10052 and #10052).+-}++-- | Resolve any internal inconsistencies in a set of 'DynFlags'.+-- Returns the consistent 'DynFlags' as well as a list of warnings+-- to report to the user.+makeDynFlagsConsistent :: DynFlags -> (DynFlags, [Located String])+-- Whenever makeDynFlagsConsistent does anything, it starts over, to+-- ensure that a later change doesn't invalidate an earlier check.+-- Be careful not to introduce potential loops!+makeDynFlagsConsistent dflags+ -- Disable -dynamic-too on Windows (#8228, #7134, #5987)+ | os == OSMinGW32 && gopt Opt_BuildDynamicToo dflags+ = let dflags' = gopt_unset dflags Opt_BuildDynamicToo+ warn = "-dynamic-too is not supported on Windows"+ in loop dflags' warn+ | hscTarget dflags == HscC &&+ not (platformUnregisterised (targetPlatform dflags))+ = if cGhcWithNativeCodeGen == "YES"+ then let dflags' = dflags { hscTarget = HscAsm }+ warn = "Compiler not unregisterised, so using native code generator rather than compiling via C"+ in loop dflags' warn+ else let dflags' = dflags { hscTarget = HscLlvm }+ warn = "Compiler not unregisterised, so using LLVM rather than compiling via C"+ in loop dflags' warn+ | gopt Opt_Hpc dflags && hscTarget dflags == HscInterpreted+ = let dflags' = gopt_unset dflags Opt_Hpc+ warn = "Hpc can't be used with byte-code interpreter. Ignoring -fhpc."+ in loop dflags' warn+ | hscTarget dflags `elem` [HscAsm, HscLlvm] &&+ platformUnregisterised (targetPlatform dflags)+ = loop (dflags { hscTarget = HscC })+ "Compiler unregisterised, so compiling via C"+ | hscTarget dflags == HscAsm &&+ cGhcWithNativeCodeGen /= "YES"+ = let dflags' = dflags { hscTarget = HscLlvm }+ warn = "No native code generator, so using LLVM"+ in loop dflags' warn+ | hscTarget dflags == HscLlvm &&+ not ((arch == ArchX86_64) && (os == OSLinux || os == OSDarwin || os == OSFreeBSD)) &&+ not ((isARM arch) && (os == OSLinux)) &&+ (gopt Opt_PIC dflags || WayDyn `elem` ways dflags)+ = if cGhcWithNativeCodeGen == "YES"+ then let dflags' = dflags { hscTarget = HscAsm }+ warn = "Using native code generator rather than LLVM, as LLVM is incompatible with -fPIC and -dynamic on this platform"+ in loop dflags' warn+ else throwGhcException $ CmdLineError "Can't use -fPIC or -dynamic on this platform"+ | os == OSDarwin &&+ arch == ArchX86_64 &&+ not (gopt Opt_PIC dflags)+ = loop (gopt_set dflags Opt_PIC)+ "Enabling -fPIC as it is always on for this platform"+ | Left err <- checkOptLevel (optLevel dflags) dflags+ = loop (updOptLevel 0 dflags) err++ | LinkInMemory <- ghcLink dflags+ , not (gopt Opt_ExternalInterpreter dflags)+ , rtsIsProfiled+ , isObjectTarget (hscTarget dflags)+ , WayProf `notElem` ways dflags+ = loop dflags{ways = WayProf : ways dflags}+ "Enabling -prof, because -fobject-code is enabled and GHCi is profiled"++ | otherwise = (dflags, [])+ where loc = mkGeneralSrcSpan (fsLit "when making flags consistent")+ loop updated_dflags warning+ = case makeDynFlagsConsistent updated_dflags of+ (dflags', ws) -> (dflags', L loc warning : ws)+ platform = targetPlatform dflags+ arch = platformArch platform+ os = platformOS platform+++--------------------------------------------------------------------------+-- Do not use unsafeGlobalDynFlags!+--+-- unsafeGlobalDynFlags is a hack, necessary because we need to be able+-- to show SDocs when tracing, but we don't always have DynFlags+-- available.+--+-- Do not use it if you can help it. You may get the wrong value, or this+-- panic!++-- | This is the value that 'unsafeGlobalDynFlags' takes before it is+-- initialized.+defaultGlobalDynFlags :: DynFlags+defaultGlobalDynFlags =+ (defaultDynFlags settings) { verbosity = 2 }+ where+ settings = panic "v_unsafeGlobalDynFlags: not initialised"++#if STAGE < 2+GLOBAL_VAR(v_unsafeGlobalDynFlags, defaultGlobalDynFlags, DynFlags)+#else+SHARED_GLOBAL_VAR( v_unsafeGlobalDynFlags+ , getOrSetLibHSghcGlobalDynFlags+ , "getOrSetLibHSghcGlobalDynFlags"+ , defaultGlobalDynFlags+ , DynFlags )+#endif++unsafeGlobalDynFlags :: DynFlags+unsafeGlobalDynFlags = unsafePerformIO $ readIORef v_unsafeGlobalDynFlags++setUnsafeGlobalDynFlags :: DynFlags -> IO ()+setUnsafeGlobalDynFlags = writeIORef v_unsafeGlobalDynFlags++-- -----------------------------------------------------------------------------+-- SSE and AVX++-- TODO: Instead of using a separate predicate (i.e. isSse2Enabled) to+-- check if SSE is enabled, we might have x86-64 imply the -msse2+-- flag.++data SseVersion = SSE1+ | SSE2+ | SSE3+ | SSE4+ | SSE42+ deriving (Eq, Ord)++isSseEnabled :: DynFlags -> Bool+isSseEnabled dflags = case platformArch (targetPlatform dflags) of+ ArchX86_64 -> True+ ArchX86 -> sseVersion dflags >= Just SSE1+ _ -> False++isSse2Enabled :: DynFlags -> Bool+isSse2Enabled dflags = case platformArch (targetPlatform dflags) of+ ArchX86_64 -> -- SSE2 is fixed on for x86_64. It would be+ -- possible to make it optional, but we'd need to+ -- fix at least the foreign call code where the+ -- calling convention specifies the use of xmm regs,+ -- and possibly other places.+ True+ ArchX86 -> sseVersion dflags >= Just SSE2+ _ -> False++isSse4_2Enabled :: DynFlags -> Bool+isSse4_2Enabled dflags = sseVersion dflags >= Just SSE42++isAvxEnabled :: DynFlags -> Bool+isAvxEnabled dflags = avx dflags || avx2 dflags || avx512f dflags++isAvx2Enabled :: DynFlags -> Bool+isAvx2Enabled dflags = avx2 dflags || avx512f dflags++isAvx512cdEnabled :: DynFlags -> Bool+isAvx512cdEnabled dflags = avx512cd dflags++isAvx512erEnabled :: DynFlags -> Bool+isAvx512erEnabled dflags = avx512er dflags++isAvx512fEnabled :: DynFlags -> Bool+isAvx512fEnabled dflags = avx512f dflags++isAvx512pfEnabled :: DynFlags -> Bool+isAvx512pfEnabled dflags = avx512pf dflags++-- -----------------------------------------------------------------------------+-- Linker/compiler information++-- LinkerInfo contains any extra options needed by the system linker.+data LinkerInfo+ = GnuLD [Option]+ | GnuGold [Option]+ | DarwinLD [Option]+ | SolarisLD [Option]+ | AixLD [Option]+ | UnknownLD+ deriving Eq++-- CompilerInfo tells us which C compiler we're using+data CompilerInfo+ = GCC+ | Clang+ | AppleClang+ | AppleClang51+ | UnknownCC+ deriving Eq++-- -----------------------------------------------------------------------------+-- RTS hooks++-- Convert sizes like "3.5M" into integers+decodeSize :: String -> Integer+decodeSize str+ | c == "" = truncate n+ | c == "K" || c == "k" = truncate (n * 1000)+ | c == "M" || c == "m" = truncate (n * 1000 * 1000)+ | c == "G" || c == "g" = truncate (n * 1000 * 1000 * 1000)+ | otherwise = throwGhcException (CmdLineError ("can't decode size: " ++ str))+ where (m, c) = span pred str+ n = readRational m+ pred c = isDigit c || c == '.'++foreign import ccall unsafe "setHeapSize" setHeapSize :: Int -> IO ()+foreign import ccall unsafe "enableTimingStats" enableTimingStats :: IO ()
+ main/DynFlags.hs-boot view
@@ -0,0 +1,17 @@++module DynFlags where++import Platform++data DynFlags+data DumpFlag++targetPlatform :: DynFlags -> Platform+pprUserLength :: DynFlags -> Int+pprCols :: DynFlags -> Int+unsafeGlobalDynFlags :: DynFlags+useUnicode :: DynFlags -> Bool+useUnicodeSyntax :: DynFlags -> Bool+shouldUseColor :: DynFlags -> Bool+hasPprDebug :: DynFlags -> Bool+hasNoDebugOutput :: DynFlags -> Bool
+ main/DynamicLoading.hs view
@@ -0,0 +1,269 @@+{-# LANGUAGE CPP, MagicHash #-}++-- | Dynamically lookup up values from modules and loading them.+module DynamicLoading (+#ifdef GHCI+ -- * Loading plugins+ loadPlugins,+ loadFrontendPlugin,++ -- * Force loading information+ forceLoadModuleInterfaces,+ forceLoadNameModuleInterface,+ forceLoadTyCon,++ -- * Finding names+ lookupRdrNameInModuleForPlugins,++ -- * Loading values+ getValueSafely,+ getHValueSafely,+ lessUnsafeCoerce+#else+ pluginError,+#endif+ ) where++#ifdef GHCI+import Linker ( linkModule, getHValue )+import GHCi ( wormhole )+import SrcLoc ( noSrcSpan )+import Finder ( findPluginModule, cannotFindModule )+import TcRnMonad ( initTcInteractive, initIfaceTcRn )+import LoadIface ( loadPluginInterface )+import RdrName ( RdrName, ImportSpec(..), ImpDeclSpec(..)+ , ImpItemSpec(..), mkGlobalRdrEnv, lookupGRE_RdrName+ , gre_name, mkRdrQual )+import OccName ( OccName, mkVarOcc )+import RnNames ( gresFromAvails )+import DynFlags+import Plugins ( Plugin, FrontendPlugin, CommandLineOption )+import PrelNames ( pluginTyConName, frontendPluginTyConName )++import HscTypes+import GHCi.RemoteTypes ( HValue )+import Type ( Type, eqType, mkTyConTy, pprTyThingCategory )+import TyCon ( TyCon )+import Name ( Name, nameModule_maybe )+import Id ( idType )+import Module ( Module, ModuleName )+import Panic+import FastString+import ErrUtils+import Outputable+import Exception+import Hooks++import Data.Maybe ( mapMaybe )+import GHC.Exts ( unsafeCoerce# )++#else++import Module ( ModuleName, moduleNameString )+import Panic++import Data.List ( intercalate )++#endif++#ifdef GHCI++loadPlugins :: HscEnv -> IO [(ModuleName, Plugin, [CommandLineOption])]+loadPlugins hsc_env+ = do { plugins <- mapM (loadPlugin hsc_env) to_load+ ; return $ zipWith attachOptions to_load plugins }+ where+ dflags = hsc_dflags hsc_env+ to_load = pluginModNames dflags++ attachOptions mod_nm plug = (mod_nm, plug, options)+ where+ options = [ option | (opt_mod_nm, option) <- pluginModNameOpts dflags+ , opt_mod_nm == mod_nm ]++loadPlugin :: HscEnv -> ModuleName -> IO Plugin+loadPlugin = loadPlugin' (mkVarOcc "plugin") pluginTyConName++loadFrontendPlugin :: HscEnv -> ModuleName -> IO FrontendPlugin+loadFrontendPlugin = loadPlugin' (mkVarOcc "frontendPlugin") frontendPluginTyConName++loadPlugin' :: OccName -> Name -> HscEnv -> ModuleName -> IO a+loadPlugin' occ_name plugin_name hsc_env mod_name+ = do { let plugin_rdr_name = mkRdrQual mod_name occ_name+ dflags = hsc_dflags hsc_env+ ; mb_name <- lookupRdrNameInModuleForPlugins hsc_env mod_name+ plugin_rdr_name+ ; case mb_name of {+ Nothing ->+ throwGhcExceptionIO (CmdLineError $ showSDoc dflags $ hsep+ [ text "The module", ppr mod_name+ , text "did not export the plugin name"+ , ppr plugin_rdr_name ]) ;+ Just name ->++ do { plugin_tycon <- forceLoadTyCon hsc_env plugin_name+ ; mb_plugin <- getValueSafely hsc_env name (mkTyConTy plugin_tycon)+ ; case mb_plugin of+ Nothing ->+ throwGhcExceptionIO (CmdLineError $ showSDoc dflags $ hsep+ [ text "The value", ppr name+ , text "did not have the type"+ , ppr pluginTyConName, text "as required"])+ Just plugin -> return plugin } } }+++-- | Force the interfaces for the given modules to be loaded. The 'SDoc' parameter is used+-- for debugging (@-ddump-if-trace@) only: it is shown as the reason why the module is being loaded.+forceLoadModuleInterfaces :: HscEnv -> SDoc -> [Module] -> IO ()+forceLoadModuleInterfaces hsc_env doc modules+ = (initTcInteractive hsc_env $+ initIfaceTcRn $+ mapM_ (loadPluginInterface doc) modules)+ >> return ()++-- | Force the interface for the module containing the name to be loaded. The 'SDoc' parameter is used+-- for debugging (@-ddump-if-trace@) only: it is shown as the reason why the module is being loaded.+forceLoadNameModuleInterface :: HscEnv -> SDoc -> Name -> IO ()+forceLoadNameModuleInterface hsc_env reason name = do+ let name_modules = mapMaybe nameModule_maybe [name]+ forceLoadModuleInterfaces hsc_env reason name_modules++-- | Load the 'TyCon' associated with the given name, come hell or high water. Fails if:+--+-- * The interface could not be loaded+-- * The name is not that of a 'TyCon'+-- * The name did not exist in the loaded module+forceLoadTyCon :: HscEnv -> Name -> IO TyCon+forceLoadTyCon hsc_env con_name = do+ forceLoadNameModuleInterface hsc_env (text "contains a name used in an invocation of loadTyConTy") con_name++ mb_con_thing <- lookupTypeHscEnv hsc_env con_name+ case mb_con_thing of+ Nothing -> throwCmdLineErrorS dflags $ missingTyThingError con_name+ Just (ATyCon tycon) -> return tycon+ Just con_thing -> throwCmdLineErrorS dflags $ wrongTyThingError con_name con_thing+ where dflags = hsc_dflags hsc_env++-- | Loads the value corresponding to a 'Name' if that value has the given 'Type'. This only provides limited safety+-- in that it is up to the user to ensure that that type corresponds to the type you try to use the return value at!+--+-- If the value found was not of the correct type, returns @Nothing@. Any other condition results in an exception:+--+-- * If we could not load the names module+-- * If the thing being loaded is not a value+-- * If the Name does not exist in the module+-- * If the link failed++getValueSafely :: HscEnv -> Name -> Type -> IO (Maybe a)+getValueSafely hsc_env val_name expected_type = do+ mb_hval <- lookupHook getValueSafelyHook getHValueSafely dflags hsc_env val_name expected_type+ case mb_hval of+ Nothing -> return Nothing+ Just hval -> do+ value <- lessUnsafeCoerce dflags "getValueSafely" hval+ return (Just value)+ where+ dflags = hsc_dflags hsc_env++getHValueSafely :: HscEnv -> Name -> Type -> IO (Maybe HValue)+getHValueSafely hsc_env val_name expected_type = do+ forceLoadNameModuleInterface hsc_env (text "contains a name used in an invocation of getHValueSafely") val_name+ -- Now look up the names for the value and type constructor in the type environment+ mb_val_thing <- lookupTypeHscEnv hsc_env val_name+ case mb_val_thing of+ Nothing -> throwCmdLineErrorS dflags $ missingTyThingError val_name+ Just (AnId id) -> do+ -- Check the value type in the interface against the type recovered from the type constructor+ -- before finally casting the value to the type we assume corresponds to that constructor+ if expected_type `eqType` idType id+ then do+ -- Link in the module that contains the value, if it has such a module+ case nameModule_maybe val_name of+ Just mod -> do linkModule hsc_env mod+ return ()+ Nothing -> return ()+ -- Find the value that we just linked in and cast it given that we have proved it's type+ hval <- getHValue hsc_env val_name >>= wormhole dflags+ return (Just hval)+ else return Nothing+ Just val_thing -> throwCmdLineErrorS dflags $ wrongTyThingError val_name val_thing+ where dflags = hsc_dflags hsc_env++-- | Coerce a value as usual, but:+--+-- 1) Evaluate it immediately to get a segfault early if the coercion was wrong+--+-- 2) Wrap it in some debug messages at verbosity 3 or higher so we can see what happened+-- if it /does/ segfault+lessUnsafeCoerce :: DynFlags -> String -> a -> IO b+lessUnsafeCoerce dflags context what = do+ debugTraceMsg dflags 3 $ (text "Coercing a value in") <+> (text context) <>+ (text "...")+ output <- evaluate (unsafeCoerce# what)+ debugTraceMsg dflags 3 (text "Successfully evaluated coercion")+ return output+++-- | Finds the 'Name' corresponding to the given 'RdrName' in the+-- context of the 'ModuleName'. Returns @Nothing@ if no such 'Name'+-- could be found. Any other condition results in an exception:+--+-- * If the module could not be found+-- * If we could not determine the imports of the module+--+-- Can only be used for looking up names while loading plugins (and is+-- *not* suitable for use within plugins). The interface file is+-- loaded very partially: just enough that it can be used, without its+-- rules and instances affecting (and being linked from!) the module+-- being compiled. This was introduced by 57d6798.+lookupRdrNameInModuleForPlugins :: HscEnv -> ModuleName -> RdrName -> IO (Maybe Name)+lookupRdrNameInModuleForPlugins hsc_env mod_name rdr_name = do+ -- First find the package the module resides in by searching exposed packages and home modules+ found_module <- findPluginModule hsc_env mod_name+ case found_module of+ Found _ mod -> do+ -- Find the exports of the module+ (_, mb_iface) <- initTcInteractive hsc_env $+ initIfaceTcRn $+ loadPluginInterface doc mod+ case mb_iface of+ Just iface -> do+ -- Try and find the required name in the exports+ let decl_spec = ImpDeclSpec { is_mod = mod_name, is_as = mod_name+ , is_qual = False, is_dloc = noSrcSpan }+ imp_spec = ImpSpec decl_spec ImpAll+ env = mkGlobalRdrEnv (gresFromAvails (Just imp_spec) (mi_exports iface))+ case lookupGRE_RdrName rdr_name env of+ [gre] -> return (Just (gre_name gre))+ [] -> return Nothing+ _ -> panic "lookupRdrNameInModule"++ Nothing -> throwCmdLineErrorS dflags $ hsep [text "Could not determine the exports of the module", ppr mod_name]+ err -> throwCmdLineErrorS dflags $ cannotFindModule dflags mod_name err+ where+ dflags = hsc_dflags hsc_env+ doc = text "contains a name used in an invocation of lookupRdrNameInModule"++wrongTyThingError :: Name -> TyThing -> SDoc+wrongTyThingError name got_thing = hsep [text "The name", ppr name, ptext (sLit "is not that of a value but rather a"), pprTyThingCategory got_thing]++missingTyThingError :: Name -> SDoc+missingTyThingError name = hsep [text "The name", ppr name, ptext (sLit "is not in the type environment: are you sure it exists?")]++throwCmdLineErrorS :: DynFlags -> SDoc -> IO a+throwCmdLineErrorS dflags = throwCmdLineError . showSDoc dflags++throwCmdLineError :: String -> IO a+throwCmdLineError = throwGhcExceptionIO . CmdLineError++#else++pluginError :: [ModuleName] -> a+pluginError modnames = throwGhcException (CmdLineError msg)+ where+ msg = "not built for interactive use - can't load plugins ("+ -- module names are not z-encoded+ ++ intercalate ", " (map moduleNameString modnames)+ ++ ")"++#endif
+ main/Elf.hs view
@@ -0,0 +1,471 @@+{-+-----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 2015+--+-- ELF format tools+--+-----------------------------------------------------------------------------+-}++module Elf (+ readElfSectionByName,+ readElfNoteAsString,+ makeElfNote+ ) where++import Exception+import DynFlags+import Platform+import ErrUtils+import Maybes (MaybeT(..),runMaybeT)+import Util (charToC)+import Outputable (text,hcat,SDoc)++import Control.Monad (when)+import Data.Binary.Get+import Data.Word+import Data.Char (ord)+import Data.ByteString.Lazy (ByteString)+import qualified Data.ByteString.Lazy as LBS+import qualified Data.ByteString.Lazy.Char8 as B8++{- Note [ELF specification]+ ~~~~~~~~~~~~~~~~~~~~~~~~++ ELF (Executable and Linking Format) is described in the System V Application+ Binary Interface (or ABI). The latter is composed of two parts: a generic+ part and a processor specific part. The generic ABI describes the parts of+ the interface that remain constant across all hardware implementations of+ System V.++ The latest release of the specification of the generic ABI is the version+ 4.1 from March 18, 1997:++ - http://www.sco.com/developers/devspecs/gabi41.pdf++ Since 1997, snapshots of the draft for the "next" version are published:++ - http://www.sco.com/developers/gabi/++ Quoting the notice on the website: "There is more than one instance of these+ chapters to permit references to older instances to remain valid. All+ modifications to these chapters are forward-compatible, so that correct use+ of an older specification will not be invalidated by a newer instance.+ Approximately on a yearly basis, a new instance will be saved, as it reaches+ what appears to be a stable state."++ Nevertheless we will see that since 1998 it is not true for Note sections.++ Many ELF sections+ -----------------++ ELF-4.1: the normal section number fields in ELF are limited to 16 bits,+ which runs out of bits when you try to cram in more sections than that. Two+ fields are concerned: the one containing the number of the sections and the+ one containing the index of the section that contains section's names. (The+ same thing applies to the field containing the number of segments, but we+ don't care about it here).++ ELF-next: to solve this, theses fields in the ELF header have an escape+ value (different for each case), and the actual section number is stashed+ into unused fields in the first section header.++ We support this extension as it is forward-compatible with ELF-4.1.+ Moreover, GHC may generate objects with a lot of sections with the+ "function-sections" feature (one section per function).++ Note sections+ -------------++ Sections with type "note" (SHT_NOTE in the specification) are used to add+ arbitrary data into an ELF file. An entry in a note section is composed of a+ name, a type and a value.++ ELF-4.1: "The note information in sections and program header elements holds+ any number of entries, each of which is an array of 4-byte words in the+ format of the target processor." Each entry has the following format:+ | namesz | Word32: size of the name string (including the ending \0)+ | descsz | Word32: size of the value+ | type | Word32: type of the note+ | name | Name string (with \0 padding to ensure 4-byte alignment)+ | ... |+ | desc | Value (with \0 padding to ensure 4-byte alignment)+ | ... |++ ELF-next: "The note information in sections and program header elements+ holds a variable amount of entries. In 64-bit objects (files with+ e_ident[EI_CLASS] equal to ELFCLASS64), each entry is an array of 8-byte+ words in the format of the target processor. In 32-bit objects (files with+ e_ident[EI_CLASS] equal to ELFCLASS32), each entry is an array of 4-byte+ words in the format of the target processor." (from 1998-2015 snapshots)++ This is not forward-compatible with ELF-4.1. In practice, for almost all+ platforms namesz, descz and type fields are 4-byte words for both 32-bit and+ 64-bit objects (see elf.h and readelf source code).++ The only exception in readelf source code is for IA_64 machines with OpenVMS+ OS: "This OS has so many departures from the ELF standard that we test it at+ many places" (comment for is_ia64_vms() in readelf.c). In this case, namesz,+ descsz and type fields are 8-byte words and name and value fields are padded+ to ensure 8-byte alignment.++ We don't support this platform in the following code. Reading a note section+ could be done easily (by testing Machine and OS fields in the ELF header).+ Writing a note section, however, requires that we generate a different+ assembly code for GAS depending on the target platform and this is a little+ bit more involved.++-}+++-- | ELF header+--+-- The ELF header indicates the native word size (32-bit or 64-bit) and the+-- endianness of the target machine. We directly store getters for words of+-- different sizes as it is more convenient to use. We also store the word size+-- as it is useful to skip some uninteresting fields.+--+-- Other information such as the target machine and OS are left out as we don't+-- use them yet. We could add them in the future if we ever need them.+data ElfHeader = ElfHeader+ { gw16 :: Get Word16 -- ^ Get a Word16 with the correct endianness+ , gw32 :: Get Word32 -- ^ Get a Word32 with the correct endianness+ , gwN :: Get Word64 -- ^ Get a Word with the correct word size+ -- and endianness+ , wordSize :: Int -- ^ Word size in bytes+ }+++-- | Read the ELF header+readElfHeader :: DynFlags -> ByteString -> IO (Maybe ElfHeader)+readElfHeader dflags bs = runGetOrThrow getHeader bs `catchIO` \_ -> do+ debugTraceMsg dflags 3 $+ text ("Unable to read ELF header")+ return Nothing+ where+ getHeader = do+ magic <- getWord32be+ ws <- getWord8+ endian <- getWord8+ version <- getWord8+ skip 9 -- skip OSABI, ABI version and padding+ when (magic /= 0x7F454C46 || version /= 1) $ fail "Invalid ELF header"++ case (ws, endian) of+ -- ELF 32, little endian+ (1,1) -> return . Just $ ElfHeader+ getWord16le+ getWord32le+ (fmap fromIntegral getWord32le) 4+ -- ELF 32, big endian+ (1,2) -> return . Just $ ElfHeader+ getWord16be+ getWord32be+ (fmap fromIntegral getWord32be) 4+ -- ELF 64, little endian+ (2,1) -> return . Just $ ElfHeader+ getWord16le+ getWord32le+ (fmap fromIntegral getWord64le) 8+ -- ELF 64, big endian+ (2,2) -> return . Just $ ElfHeader+ getWord16be+ getWord32be+ (fmap fromIntegral getWord64be) 8+ _ -> fail "Invalid ELF header"+++------------------+-- SECTIONS+------------------+++-- | Description of the section table+data SectionTable = SectionTable+ { sectionTableOffset :: Word64 -- ^ offset of the table describing sections+ , sectionEntrySize :: Word16 -- ^ size of an entry in the section table+ , sectionEntryCount :: Word64 -- ^ number of sections+ , sectionNameIndex :: Word32 -- ^ index of a special section which+ -- contains section's names+ }++-- | Read the ELF section table+readElfSectionTable :: DynFlags+ -> ElfHeader+ -> ByteString+ -> IO (Maybe SectionTable)++readElfSectionTable dflags hdr bs = action `catchIO` \_ -> do+ debugTraceMsg dflags 3 $+ text ("Unable to read ELF section table")+ return Nothing+ where+ getSectionTable :: Get SectionTable+ getSectionTable = do+ skip (24 + 2*wordSize hdr) -- skip header and some other fields+ secTableOffset <- gwN hdr+ skip 10+ entrySize <- gw16 hdr+ entryCount <- gw16 hdr+ secNameIndex <- gw16 hdr+ return (SectionTable secTableOffset entrySize+ (fromIntegral entryCount)+ (fromIntegral secNameIndex))++ action = do+ secTable <- runGetOrThrow getSectionTable bs+ -- In some cases, the number of entries and the index of the section+ -- containing section's names must be found in unused fields of the first+ -- section entry (see Note [ELF specification])+ let+ offSize0 = fromIntegral $ sectionTableOffset secTable + 8+ + 3 * fromIntegral (wordSize hdr)+ offLink0 = fromIntegral $ offSize0 + fromIntegral (wordSize hdr)++ entryCount' <- if sectionEntryCount secTable /= 0+ then return (sectionEntryCount secTable)+ else runGetOrThrow (gwN hdr) (LBS.drop offSize0 bs)+ entryNameIndex' <- if sectionNameIndex secTable /= 0xffff+ then return (sectionNameIndex secTable)+ else runGetOrThrow (gw32 hdr) (LBS.drop offLink0 bs)+ return (Just $ secTable+ { sectionEntryCount = entryCount'+ , sectionNameIndex = entryNameIndex'+ })+++-- | A section+data Section = Section+ { entryName :: ByteString -- ^ Name of the section+ , entryBS :: ByteString -- ^ Content of the section+ }++-- | Read a ELF section+readElfSectionByIndex :: DynFlags+ -> ElfHeader+ -> SectionTable+ -> Word64+ -> ByteString+ -> IO (Maybe Section)++readElfSectionByIndex dflags hdr secTable i bs = action `catchIO` \_ -> do+ debugTraceMsg dflags 3 $+ text ("Unable to read ELF section")+ return Nothing+ where+ -- read an entry from the section table+ getEntry = do+ nameIndex <- gw32 hdr+ skip (4+2*wordSize hdr)+ offset <- fmap fromIntegral $ gwN hdr+ size <- fmap fromIntegral $ gwN hdr+ let bs' = LBS.take size (LBS.drop offset bs)+ return (nameIndex,bs')++ -- read the entry with the given index in the section table+ getEntryByIndex x = runGetOrThrow getEntry bs'+ where+ bs' = LBS.drop off bs+ off = fromIntegral $ sectionTableOffset secTable ++ x * fromIntegral (sectionEntrySize secTable)++ -- Get the name of a section+ getEntryName nameIndex = do+ let idx = fromIntegral (sectionNameIndex secTable)+ (_,nameTable) <- getEntryByIndex idx+ let bs' = LBS.drop nameIndex nameTable+ runGetOrThrow getLazyByteStringNul bs'++ action = do+ (nameIndex,bs') <- getEntryByIndex (fromIntegral i)+ name <- getEntryName (fromIntegral nameIndex)+ return (Just $ Section name bs')+++-- | Find a section from its name. Return the section contents.+--+-- We do not perform any check on the section type.+findSectionFromName :: DynFlags+ -> ElfHeader+ -> SectionTable+ -> String+ -> ByteString+ -> IO (Maybe ByteString)+findSectionFromName dflags hdr secTable name bs =+ rec [0..sectionEntryCount secTable - 1]+ where+ -- convert the required section name into a ByteString to perform+ -- ByteString comparison instead of String comparison+ name' = B8.pack name++ -- compare recursively each section name and return the contents of+ -- the matching one, if any+ rec [] = return Nothing+ rec (x:xs) = do+ me <- readElfSectionByIndex dflags hdr secTable x bs+ case me of+ Just e | entryName e == name' -> return (Just (entryBS e))+ _ -> rec xs+++-- | Given a section name, read its contents as a ByteString.+--+-- If the section isn't found or if there is any parsing error, we return+-- Nothing+readElfSectionByName :: DynFlags+ -> ByteString+ -> String+ -> IO (Maybe LBS.ByteString)++readElfSectionByName dflags bs name = action `catchIO` \_ -> do+ debugTraceMsg dflags 3 $+ text ("Unable to read ELF section \"" ++ name ++ "\"")+ return Nothing+ where+ action = runMaybeT $ do+ hdr <- MaybeT $ readElfHeader dflags bs+ secTable <- MaybeT $ readElfSectionTable dflags hdr bs+ MaybeT $ findSectionFromName dflags hdr secTable name bs++------------------+-- NOTE SECTIONS+------------------++-- | read a Note as a ByteString+--+-- If you try to read a note from a section which does not support the Note+-- format, the parsing is likely to fail and Nothing will be returned+readElfNoteBS :: DynFlags+ -> ByteString+ -> String+ -> String+ -> IO (Maybe LBS.ByteString)++readElfNoteBS dflags bs sectionName noteId = action `catchIO` \_ -> do+ debugTraceMsg dflags 3 $+ text ("Unable to read ELF note \"" ++ noteId +++ "\" in section \"" ++ sectionName ++ "\"")+ return Nothing+ where+ -- align the getter on n bytes+ align n = do+ m <- bytesRead+ if m `mod` n == 0+ then return ()+ else skip 1 >> align n++ -- noteId as a bytestring+ noteId' = B8.pack noteId++ -- read notes recursively until the one with a valid identifier is found+ findNote hdr = do+ align 4+ namesz <- gw32 hdr+ descsz <- gw32 hdr+ _ <- gw32 hdr -- we don't use the note type+ name <- if namesz == 0+ then return LBS.empty+ else getLazyByteStringNul+ align 4+ desc <- if descsz == 0+ then return LBS.empty+ else getLazyByteString (fromIntegral descsz)+ if name == noteId'+ then return $ Just desc+ else findNote hdr+++ action = runMaybeT $ do+ hdr <- MaybeT $ readElfHeader dflags bs+ sec <- MaybeT $ readElfSectionByName dflags bs sectionName+ MaybeT $ runGetOrThrow (findNote hdr) sec++-- | read a Note as a String+--+-- If you try to read a note from a section which does not support the Note+-- format, the parsing is likely to fail and Nothing will be returned+readElfNoteAsString :: DynFlags+ -> FilePath+ -> String+ -> String+ -> IO (Maybe String)++readElfNoteAsString dflags path sectionName noteId = action `catchIO` \_ -> do+ debugTraceMsg dflags 3 $+ text ("Unable to read ELF note \"" ++ noteId +++ "\" in section \"" ++ sectionName ++ "\"")+ return Nothing+ where+ action = do+ bs <- LBS.readFile path+ note <- readElfNoteBS dflags bs sectionName noteId+ return (fmap B8.unpack note)+++-- | Generate the GAS code to create a Note section+--+-- Header fields for notes are 32-bit long (see Note [ELF specification]).+--+-- It seems there is no easy way to force GNU AS to generate a 32-bit word in+-- every case. Hence we use .int directive to create them: however "The byte+-- order and bit size of the number depends on what kind of target the assembly+-- is for." (https://sourceware.org/binutils/docs/as/Int.html#Int)+--+-- If we add new target platforms, we need to check that the generated words+-- are 32-bit long, otherwise we need to use platform specific directives to+-- force 32-bit .int in asWord32.+makeElfNote :: DynFlags -> String -> String -> Word32 -> String -> SDoc+makeElfNote dflags sectionName noteName typ contents = hcat [+ text "\t.section ",+ text sectionName,+ text ",\"\",",+ text elfSectionNote,+ text "\n",++ -- note name length (+ 1 for ending \0)+ asWord32 (length noteName + 1),++ -- note contents size+ asWord32 (length contents),++ -- note type+ asWord32 typ,++ -- note name (.asciz for \0 ending string) + padding+ text "\t.asciz \"",+ text noteName,+ text "\"\n",+ text "\t.align 4\n",++ -- note contents (.ascii to avoid ending \0) + padding+ text "\t.ascii \"",+ text (escape contents),+ text "\"\n",+ text "\t.align 4\n"]+ where+ escape :: String -> String+ escape = concatMap (charToC.fromIntegral.ord)++ asWord32 :: Show a => a -> SDoc+ asWord32 x = hcat [+ text "\t.int ",+ text (show x),+ text "\n"]++ elfSectionNote :: String+ elfSectionNote = case platformArch (targetPlatform dflags) of+ ArchARM _ _ _ -> "%note"+ _ -> "@note"++++------------------+-- Helpers+------------------++-- | runGet in IO monad that throws an IOException on failure+runGetOrThrow :: Get a -> LBS.ByteString -> IO a+runGetOrThrow g bs = case runGetOrFail g bs of+ Left _ -> fail "Error while reading file"+ Right (_,_,a) -> return a
+ main/ErrUtils.hs view
@@ -0,0 +1,675 @@+{-+(c) The AQUA Project, Glasgow University, 1994-1998++\section[ErrsUtils]{Utilities for error reporting}+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE RecordWildCards #-}++module ErrUtils (+ -- * Basic types+ Validity(..), andValid, allValid, isValid, getInvalids,+ Severity(..),++ -- * Messages+ ErrMsg, errMsgDoc,+ ErrDoc, errDoc, errDocImportant, errDocContext, errDocSupplementary,+ WarnMsg, MsgDoc,+ Messages, ErrorMessages, WarningMessages,+ unionMessages,+ errMsgSpan, errMsgContext,+ errorsFound, isEmptyMessages,+ isWarnMsgFatal,++ -- ** Formatting+ pprMessageBag, pprErrMsgBagWithLoc,+ pprLocErrMsg, printBagOfErrors,+ formatErrDoc,++ -- ** Construction+ emptyMessages, mkLocMessage, mkLocMessageAnn, makeIntoWarning,+ mkErrMsg, mkPlainErrMsg, mkErrDoc, mkLongErrMsg, mkWarnMsg,+ mkPlainWarnMsg,+ warnIsErrorMsg, mkLongWarnMsg,++ -- * Utilities+ doIfSet, doIfSet_dyn,+ getCaretDiagnostic,++ -- * Dump files+ dumpIfSet, dumpIfSet_dyn, dumpIfSet_dyn_printer,+ mkDumpDoc, dumpSDoc,++ -- * Issuing messages during compilation+ putMsg, printInfoForUser, printOutputForUser,+ logInfo, logOutput,+ errorMsg, warningMsg,+ fatalErrorMsg, fatalErrorMsg'',+ compilationProgressMsg,+ showPass, withTiming,+ debugTraceMsg,+ ghcExit,+ prettyPrintGhcErrors,+ ) where++#include "HsVersions.h"++import Bag+import Exception+import Outputable+import Panic+import qualified PprColour as Col+import SrcLoc+import DynFlags+import FastString (unpackFS)+import StringBuffer (atLine, hGetStringBuffer, len, lexemeToString)+import Json++import System.Directory+import System.Exit ( ExitCode(..), exitWith )+import System.FilePath ( takeDirectory, (</>) )+import Data.List+import qualified Data.Set as Set+import Data.IORef+import Data.Maybe ( fromMaybe )+import Data.Ord+import Data.Time+import Control.Monad+import Control.Monad.IO.Class+import System.IO+import System.IO.Error ( catchIOError )+import GHC.Conc ( getAllocationCounter )+import System.CPUTime++-------------------------+type MsgDoc = SDoc++-------------------------+data Validity+ = IsValid -- ^ Everything is fine+ | NotValid MsgDoc -- ^ A problem, and some indication of why++isValid :: Validity -> Bool+isValid IsValid = True+isValid (NotValid {}) = False++andValid :: Validity -> Validity -> Validity+andValid IsValid v = v+andValid v _ = v++-- | If they aren't all valid, return the first+allValid :: [Validity] -> Validity+allValid [] = IsValid+allValid (v : vs) = v `andValid` allValid vs++getInvalids :: [Validity] -> [MsgDoc]+getInvalids vs = [d | NotValid d <- vs]++-- -----------------------------------------------------------------------------+-- Basic error messages: just render a message with a source location.++type Messages = (WarningMessages, ErrorMessages)+type WarningMessages = Bag WarnMsg+type ErrorMessages = Bag ErrMsg++unionMessages :: Messages -> Messages -> Messages+unionMessages (warns1, errs1) (warns2, errs2) =+ (warns1 `unionBags` warns2, errs1 `unionBags` errs2)++data ErrMsg = ErrMsg {+ errMsgSpan :: SrcSpan,+ errMsgContext :: PrintUnqualified,+ errMsgDoc :: ErrDoc,+ -- | This has the same text as errDocImportant . errMsgDoc.+ errMsgShortString :: String,+ errMsgSeverity :: Severity,+ errMsgReason :: WarnReason+ }+ -- The SrcSpan is used for sorting errors into line-number order+++-- | Categorise error msgs by their importance. This is so each section can+-- be rendered visually distinct. See Note [Error report] for where these come+-- from.+data ErrDoc = ErrDoc {+ -- | Primary error msg.+ errDocImportant :: [MsgDoc],+ -- | Context e.g. \"In the second argument of ...\".+ errDocContext :: [MsgDoc],+ -- | Supplementary information, e.g. \"Relevant bindings include ...\".+ errDocSupplementary :: [MsgDoc]+ }++errDoc :: [MsgDoc] -> [MsgDoc] -> [MsgDoc] -> ErrDoc+errDoc = ErrDoc++type WarnMsg = ErrMsg++data Severity+ = SevOutput+ | SevFatal+ | SevInteractive++ | SevDump+ -- ^ Log messagse intended for compiler developers+ -- No file/line/column stuff++ | SevInfo+ -- ^ Log messages intended for end users.+ -- No file/line/column stuff.++ | SevWarning+ | SevError+ -- ^ SevWarning and SevError are used for warnings and errors+ -- o The message has a file/line/column heading,+ -- plus "warning:" or "error:",+ -- added by mkLocMessags+ -- o Output is intended for end users+ deriving Show+++instance ToJson Severity where+ json s = JSString (show s)+++instance Show ErrMsg where+ show em = errMsgShortString em++pprMessageBag :: Bag MsgDoc -> SDoc+pprMessageBag msgs = vcat (punctuate blankLine (bagToList msgs))++-- | Make an unannotated error message with location info.+mkLocMessage :: Severity -> SrcSpan -> MsgDoc -> MsgDoc+mkLocMessage = mkLocMessageAnn Nothing++-- | Make a possibly annotated error message with location info.+mkLocMessageAnn+ :: Maybe String -- ^ optional annotation+ -> Severity -- ^ severity+ -> SrcSpan -- ^ location+ -> MsgDoc -- ^ message+ -> MsgDoc+ -- Always print the location, even if it is unhelpful. Error messages+ -- are supposed to be in a standard format, and one without a location+ -- would look strange. Better to say explicitly "<no location info>".+mkLocMessageAnn ann severity locn msg+ = sdocWithDynFlags $ \dflags ->+ let locn' = if gopt Opt_ErrorSpans dflags+ then ppr locn+ else ppr (srcSpanStart locn)++ sevColour = getSeverityColour severity (colScheme dflags)++ -- Add optional information+ optAnn = case ann of+ Nothing -> text ""+ Just i -> text " [" <> coloured sevColour (text i) <> text "]"++ -- Add prefixes, like Foo.hs:34: warning:+ -- <the warning message>+ header = locn' <> colon <+>+ coloured sevColour sevText <> optAnn++ in coloured (Col.sMessage (colScheme dflags))+ (hang (coloured (Col.sHeader (colScheme dflags)) header) 4+ msg)++ where+ sevText =+ case severity of+ SevWarning -> text "warning:"+ SevError -> text "error:"+ SevFatal -> text "fatal:"+ _ -> empty++getSeverityColour :: Severity -> Col.Scheme -> Col.PprColour+getSeverityColour SevWarning = Col.sWarning+getSeverityColour SevError = Col.sError+getSeverityColour SevFatal = Col.sFatal+getSeverityColour _ = const mempty++getCaretDiagnostic :: Severity -> SrcSpan -> IO MsgDoc+getCaretDiagnostic _ (UnhelpfulSpan _) = pure empty+getCaretDiagnostic severity (RealSrcSpan span) = do+ caretDiagnostic <$> getSrcLine (srcSpanFile span) row++ where+ getSrcLine fn i =+ getLine i (unpackFS fn)+ `catchIOError` \_ ->+ pure Nothing++ getLine i fn = do+ -- StringBuffer has advantages over readFile:+ -- (a) no lazy IO, otherwise IO exceptions may occur in pure code+ -- (b) always UTF-8, rather than some system-dependent encoding+ -- (Haskell source code must be UTF-8 anyway)+ content <- hGetStringBuffer fn+ case atLine i content of+ Just at_line -> pure $+ case lines (fix <$> lexemeToString at_line (len at_line)) of+ srcLine : _ -> Just srcLine+ _ -> Nothing+ _ -> pure Nothing++ -- allow user to visibly see that their code is incorrectly encoded+ -- (StringBuffer.nextChar uses \0 to represent undecodable characters)+ fix '\0' = '\xfffd'+ fix c = c++ row = srcSpanStartLine span+ rowStr = show row+ multiline = row /= srcSpanEndLine span++ caretDiagnostic Nothing = empty+ caretDiagnostic (Just srcLineWithNewline) =+ sdocWithDynFlags $ \ dflags ->+ let sevColour = getSeverityColour severity (colScheme dflags)+ marginColour = Col.sMargin (colScheme dflags)+ in+ coloured marginColour (text marginSpace) <>+ text ("\n") <>+ coloured marginColour (text marginRow) <>+ text (" " ++ srcLinePre) <>+ coloured sevColour (text srcLineSpan) <>+ text (srcLinePost ++ "\n") <>+ coloured marginColour (text marginSpace) <>+ coloured sevColour (text (" " ++ caretLine))++ where++ -- expand tabs in a device-independent manner #13664+ expandTabs tabWidth i s =+ case s of+ "" -> ""+ '\t' : cs -> replicate effectiveWidth ' ' +++ expandTabs tabWidth (i + effectiveWidth) cs+ c : cs -> c : expandTabs tabWidth (i + 1) cs+ where effectiveWidth = tabWidth - i `mod` tabWidth++ srcLine = filter (/= '\n') (expandTabs 8 0 srcLineWithNewline)++ start = srcSpanStartCol span - 1+ end | multiline = length srcLine+ | otherwise = srcSpanEndCol span - 1+ width = max 1 (end - start)++ marginWidth = length rowStr+ marginSpace = replicate marginWidth ' ' ++ " |"+ marginRow = rowStr ++ " |"++ (srcLinePre, srcLineRest) = splitAt start srcLine+ (srcLineSpan, srcLinePost) = splitAt width srcLineRest++ caretEllipsis | multiline = "..."+ | otherwise = ""+ caretLine = replicate start ' ' ++ replicate width '^' ++ caretEllipsis++makeIntoWarning :: WarnReason -> ErrMsg -> ErrMsg+makeIntoWarning reason err = err+ { errMsgSeverity = SevWarning+ , errMsgReason = reason }++-- -----------------------------------------------------------------------------+-- Collecting up messages for later ordering and printing.++mk_err_msg :: DynFlags -> Severity -> SrcSpan -> PrintUnqualified -> ErrDoc -> ErrMsg+mk_err_msg dflags sev locn print_unqual doc+ = ErrMsg { errMsgSpan = locn+ , errMsgContext = print_unqual+ , errMsgDoc = doc+ , errMsgShortString = showSDoc dflags (vcat (errDocImportant doc))+ , errMsgSeverity = sev+ , errMsgReason = NoReason }++mkErrDoc :: DynFlags -> SrcSpan -> PrintUnqualified -> ErrDoc -> ErrMsg+mkErrDoc dflags = mk_err_msg dflags SevError++mkLongErrMsg, mkLongWarnMsg :: DynFlags -> SrcSpan -> PrintUnqualified -> MsgDoc -> MsgDoc -> ErrMsg+-- ^ A long (multi-line) error message+mkErrMsg, mkWarnMsg :: DynFlags -> SrcSpan -> PrintUnqualified -> MsgDoc -> ErrMsg+-- ^ A short (one-line) error message+mkPlainErrMsg, mkPlainWarnMsg :: DynFlags -> SrcSpan -> MsgDoc -> ErrMsg+-- ^ Variant that doesn't care about qualified/unqualified names++mkLongErrMsg dflags locn unqual msg extra = mk_err_msg dflags SevError locn unqual (ErrDoc [msg] [] [extra])+mkErrMsg dflags locn unqual msg = mk_err_msg dflags SevError locn unqual (ErrDoc [msg] [] [])+mkPlainErrMsg dflags locn msg = mk_err_msg dflags SevError locn alwaysQualify (ErrDoc [msg] [] [])+mkLongWarnMsg dflags locn unqual msg extra = mk_err_msg dflags SevWarning locn unqual (ErrDoc [msg] [] [extra])+mkWarnMsg dflags locn unqual msg = mk_err_msg dflags SevWarning locn unqual (ErrDoc [msg] [] [])+mkPlainWarnMsg dflags locn msg = mk_err_msg dflags SevWarning locn alwaysQualify (ErrDoc [msg] [] [])++----------------+emptyMessages :: Messages+emptyMessages = (emptyBag, emptyBag)++isEmptyMessages :: Messages -> Bool+isEmptyMessages (warns, errs) = isEmptyBag warns && isEmptyBag errs++warnIsErrorMsg :: DynFlags -> ErrMsg+warnIsErrorMsg dflags+ = mkPlainErrMsg dflags noSrcSpan (text "\nFailing due to -Werror.")++errorsFound :: DynFlags -> Messages -> Bool+errorsFound _dflags (_warns, errs) = not (isEmptyBag errs)++printBagOfErrors :: DynFlags -> Bag ErrMsg -> IO ()+printBagOfErrors dflags bag_of_errors+ = sequence_ [ let style = mkErrStyle dflags unqual+ in putLogMsg dflags reason sev s style (formatErrDoc dflags doc)+ | ErrMsg { errMsgSpan = s,+ errMsgDoc = doc,+ errMsgSeverity = sev,+ errMsgReason = reason,+ errMsgContext = unqual } <- sortMsgBag (Just dflags)+ bag_of_errors ]++formatErrDoc :: DynFlags -> ErrDoc -> SDoc+formatErrDoc dflags (ErrDoc important context supplementary)+ = case msgs of+ [msg] -> vcat msg+ _ -> vcat $ map starred msgs+ where+ msgs = filter (not . null) $ map (filter (not . Outputable.isEmpty dflags))+ [important, context, supplementary]+ starred = (bullet<+>) . vcat++pprErrMsgBagWithLoc :: Bag ErrMsg -> [SDoc]+pprErrMsgBagWithLoc bag = [ pprLocErrMsg item | item <- sortMsgBag Nothing bag ]++pprLocErrMsg :: ErrMsg -> SDoc+pprLocErrMsg (ErrMsg { errMsgSpan = s+ , errMsgDoc = doc+ , errMsgSeverity = sev+ , errMsgContext = unqual })+ = sdocWithDynFlags $ \dflags ->+ withPprStyle (mkErrStyle dflags unqual) $+ mkLocMessage sev s (formatErrDoc dflags doc)++sortMsgBag :: Maybe DynFlags -> Bag ErrMsg -> [ErrMsg]+sortMsgBag dflags = maybeLimit . sortBy (maybeFlip cmp) . bagToList+ where maybeFlip :: (a -> a -> b) -> (a -> a -> b)+ maybeFlip+ | fromMaybe False (fmap reverseErrors dflags) = flip+ | otherwise = id+ cmp = comparing errMsgSpan+ maybeLimit = case join (fmap maxErrors dflags) of+ Nothing -> id+ Just err_limit -> take err_limit++ghcExit :: DynFlags -> Int -> IO ()+ghcExit dflags val+ | val == 0 = exitWith ExitSuccess+ | otherwise = do errorMsg dflags (text "\nCompilation had errors\n\n")+ exitWith (ExitFailure val)++doIfSet :: Bool -> IO () -> IO ()+doIfSet flag action | flag = action+ | otherwise = return ()++doIfSet_dyn :: DynFlags -> GeneralFlag -> IO () -> IO()+doIfSet_dyn dflags flag action | gopt flag dflags = action+ | otherwise = return ()++-- -----------------------------------------------------------------------------+-- Dumping++dumpIfSet :: DynFlags -> Bool -> String -> SDoc -> IO ()+dumpIfSet dflags flag hdr doc+ | not flag = return ()+ | otherwise = putLogMsg dflags+ NoReason+ SevDump+ noSrcSpan+ (defaultDumpStyle dflags)+ (mkDumpDoc hdr doc)++-- | a wrapper around 'dumpSDoc'.+-- First check whether the dump flag is set+-- Do nothing if it is unset+dumpIfSet_dyn :: DynFlags -> DumpFlag -> String -> SDoc -> IO ()+dumpIfSet_dyn dflags flag hdr doc+ = when (dopt flag dflags) $ dumpSDoc dflags alwaysQualify flag hdr doc++-- | a wrapper around 'dumpSDoc'.+-- First check whether the dump flag is set+-- Do nothing if it is unset+--+-- Unlike 'dumpIfSet_dyn',+-- has a printer argument but no header argument+dumpIfSet_dyn_printer :: PrintUnqualified+ -> DynFlags -> DumpFlag -> SDoc -> IO ()+dumpIfSet_dyn_printer printer dflags flag doc+ = when (dopt flag dflags) $ dumpSDoc dflags printer flag "" doc++mkDumpDoc :: String -> SDoc -> SDoc+mkDumpDoc hdr doc+ = vcat [blankLine,+ line <+> text hdr <+> line,+ doc,+ blankLine]+ where+ line = text (replicate 20 '=')+++-- | Write out a dump.+-- If --dump-to-file is set then this goes to a file.+-- otherwise emit to stdout.+--+-- When @hdr@ is empty, we print in a more compact format (no separators and+-- blank lines)+--+-- The 'DumpFlag' is used only to choose the filename to use if @--dump-to-file@+-- is used; it is not used to decide whether to dump the output+dumpSDoc :: DynFlags -> PrintUnqualified -> DumpFlag -> String -> SDoc -> IO ()+dumpSDoc dflags print_unqual flag hdr doc+ = do let mFile = chooseDumpFile dflags flag+ dump_style = mkDumpStyle dflags print_unqual+ case mFile of+ Just fileName+ -> do+ let gdref = generatedDumps dflags+ gd <- readIORef gdref+ let append = Set.member fileName gd+ mode = if append then AppendMode else WriteMode+ unless append $+ writeIORef gdref (Set.insert fileName gd)+ createDirectoryIfMissing True (takeDirectory fileName)+ handle <- openFile fileName mode++ -- We do not want the dump file to be affected by+ -- environment variables, but instead to always use+ -- UTF8. See:+ -- https://ghc.haskell.org/trac/ghc/ticket/10762+ hSetEncoding handle utf8++ doc' <- if null hdr+ then return doc+ else do t <- getCurrentTime+ let d = text (show t)+ $$ blankLine+ $$ doc+ return $ mkDumpDoc hdr d+ defaultLogActionHPrintDoc dflags handle doc' dump_style+ hClose handle++ -- write the dump to stdout+ Nothing -> do+ let (doc', severity)+ | null hdr = (doc, SevOutput)+ | otherwise = (mkDumpDoc hdr doc, SevDump)+ putLogMsg dflags NoReason severity noSrcSpan dump_style doc'+++-- | Choose where to put a dump file based on DynFlags+--+chooseDumpFile :: DynFlags -> DumpFlag -> Maybe FilePath+chooseDumpFile dflags flag++ | gopt Opt_DumpToFile dflags || flag == Opt_D_th_dec_file+ , Just prefix <- getPrefix+ = Just $ setDir (prefix ++ (beautifyDumpName flag))++ | otherwise+ = Nothing++ where getPrefix+ -- dump file location is being forced+ -- by the --ddump-file-prefix flag.+ | Just prefix <- dumpPrefixForce dflags+ = Just prefix+ -- dump file location chosen by DriverPipeline.runPipeline+ | Just prefix <- dumpPrefix dflags+ = Just prefix+ -- we haven't got a place to put a dump file.+ | otherwise+ = Nothing+ setDir f = case dumpDir dflags of+ Just d -> d </> f+ Nothing -> f++-- | Build a nice file name from name of a 'DumpFlag' constructor+beautifyDumpName :: DumpFlag -> String+beautifyDumpName Opt_D_th_dec_file = "th.hs"+beautifyDumpName flag+ = let str = show flag+ suff = case stripPrefix "Opt_D_" str of+ Just x -> x+ Nothing -> panic ("Bad flag name: " ++ str)+ dash = map (\c -> if c == '_' then '-' else c) suff+ in dash+++-- -----------------------------------------------------------------------------+-- Outputting messages from the compiler++-- We want all messages to go through one place, so that we can+-- redirect them if necessary. For example, when GHC is used as a+-- library we might want to catch all messages that GHC tries to+-- output and do something else with them.++ifVerbose :: DynFlags -> Int -> IO () -> IO ()+ifVerbose dflags val act+ | verbosity dflags >= val = act+ | otherwise = return ()++errorMsg :: DynFlags -> MsgDoc -> IO ()+errorMsg dflags msg+ = putLogMsg dflags NoReason SevError noSrcSpan (defaultErrStyle dflags) msg++warningMsg :: DynFlags -> MsgDoc -> IO ()+warningMsg dflags msg+ = putLogMsg dflags NoReason SevWarning noSrcSpan (defaultErrStyle dflags) msg++fatalErrorMsg :: DynFlags -> MsgDoc -> IO ()+fatalErrorMsg dflags msg =+ putLogMsg dflags NoReason SevFatal noSrcSpan (defaultErrStyle dflags) msg++fatalErrorMsg'' :: FatalMessager -> String -> IO ()+fatalErrorMsg'' fm msg = fm msg++compilationProgressMsg :: DynFlags -> String -> IO ()+compilationProgressMsg dflags msg+ = ifVerbose dflags 1 $+ logOutput dflags (defaultUserStyle dflags) (text msg)++showPass :: DynFlags -> String -> IO ()+showPass dflags what+ = ifVerbose dflags 2 $+ logInfo dflags (defaultUserStyle dflags) (text "***" <+> text what <> colon)++-- | Time a compilation phase.+--+-- When timings are enabled (e.g. with the @-v2@ flag), the allocations+-- and CPU time used by the phase will be reported to stderr. Consider+-- a typical usage: @withTiming getDynFlags (text "simplify") force pass@.+-- When timings are enabled the following costs are included in the+-- produced accounting,+--+-- - The cost of executing @pass@ to a result @r@ in WHNF+-- - The cost of evaluating @force r@ to WHNF (e.g. @()@)+--+-- The choice of the @force@ function depends upon the amount of forcing+-- desired; the goal here is to ensure that the cost of evaluating the result+-- is, to the greatest extent possible, included in the accounting provided by+-- 'withTiming'. Often the pass already sufficiently forces its result during+-- construction; in this case @const ()@ is a reasonable choice.+-- In other cases, it is necessary to evaluate the result to normal form, in+-- which case something like @Control.DeepSeq.rnf@ is appropriate.+--+-- To avoid adversely affecting compiler performance when timings are not+-- requested, the result is only forced when timings are enabled.+withTiming :: MonadIO m+ => m DynFlags -- ^ A means of getting a 'DynFlags' (often+ -- 'getDynFlags' will work here)+ -> SDoc -- ^ The name of the phase+ -> (a -> ()) -- ^ A function to force the result+ -- (often either @const ()@ or 'rnf')+ -> m a -- ^ The body of the phase to be timed+ -> m a+withTiming getDFlags what force_result action+ = do dflags <- getDFlags+ if verbosity dflags >= 2+ then do liftIO $ logInfo dflags (defaultUserStyle dflags)+ $ text "***" <+> what <> colon+ alloc0 <- liftIO getAllocationCounter+ start <- liftIO getCPUTime+ !r <- action+ () <- pure $ force_result r+ end <- liftIO getCPUTime+ alloc1 <- liftIO getAllocationCounter+ -- recall that allocation counter counts down+ let alloc = alloc0 - alloc1+ liftIO $ logInfo dflags (defaultUserStyle dflags)+ (text "!!!" <+> what <> colon <+> text "finished in"+ <+> doublePrec 2 (realToFrac (end - start) * 1e-9)+ <+> text "milliseconds"+ <> comma+ <+> text "allocated"+ <+> doublePrec 3 (realToFrac alloc / 1024 / 1024)+ <+> text "megabytes")+ pure r+ else action++debugTraceMsg :: DynFlags -> Int -> MsgDoc -> IO ()+debugTraceMsg dflags val msg = ifVerbose dflags val $+ logInfo dflags (defaultDumpStyle dflags) msg+putMsg :: DynFlags -> MsgDoc -> IO ()+putMsg dflags msg = logInfo dflags (defaultUserStyle dflags) msg++printInfoForUser :: DynFlags -> PrintUnqualified -> MsgDoc -> IO ()+printInfoForUser dflags print_unqual msg+ = logInfo dflags (mkUserStyle dflags print_unqual AllTheWay) msg++printOutputForUser :: DynFlags -> PrintUnqualified -> MsgDoc -> IO ()+printOutputForUser dflags print_unqual msg+ = logOutput dflags (mkUserStyle dflags print_unqual AllTheWay) msg++logInfo :: DynFlags -> PprStyle -> MsgDoc -> IO ()+logInfo dflags sty msg+ = putLogMsg dflags NoReason SevInfo noSrcSpan sty msg++logOutput :: DynFlags -> PprStyle -> MsgDoc -> IO ()+-- ^ Like 'logInfo' but with 'SevOutput' rather then 'SevInfo'+logOutput dflags sty msg+ = putLogMsg dflags NoReason SevOutput noSrcSpan sty msg++prettyPrintGhcErrors :: ExceptionMonad m => DynFlags -> m a -> m a+prettyPrintGhcErrors dflags+ = ghandle $ \e -> case e of+ PprPanic str doc ->+ pprDebugAndThen dflags panic (text str) doc+ PprSorry str doc ->+ pprDebugAndThen dflags sorry (text str) doc+ PprProgramError str doc ->+ pprDebugAndThen dflags pgmError (text str) doc+ _ ->+ liftIO $ throwIO e++-- | Checks if given 'WarnMsg' is a fatal warning.+isWarnMsgFatal :: DynFlags -> WarnMsg -> Bool+isWarnMsgFatal dflags ErrMsg{errMsgReason = Reason wflag}+ = wopt_fatal wflag dflags+isWarnMsgFatal dflags _ = gopt Opt_WarnIsError dflags
+ main/ErrUtils.hs-boot view
@@ -0,0 +1,25 @@+module ErrUtils where++import Outputable (SDoc, PrintUnqualified )+import SrcLoc (SrcSpan)+import Json+import {-# SOURCE #-} DynFlags ( DynFlags, DumpFlag )++data Severity+ = SevOutput+ | SevFatal+ | SevInteractive+ | SevDump+ | SevInfo+ | SevWarning+ | SevError+++type MsgDoc = SDoc++mkLocMessage :: Severity -> SrcSpan -> MsgDoc -> MsgDoc+mkLocMessageAnn :: Maybe String -> Severity -> SrcSpan -> MsgDoc -> MsgDoc+getCaretDiagnostic :: Severity -> SrcSpan -> IO MsgDoc+dumpSDoc :: DynFlags -> PrintUnqualified -> DumpFlag -> String -> SDoc -> IO ()++instance ToJson Severity
+ main/Finder.hs view
@@ -0,0 +1,776 @@+{-+(c) The University of Glasgow, 2000-2006++\section[Finder]{Module Finder}+-}++{-# LANGUAGE CPP #-}++module Finder (+ flushFinderCaches,+ FindResult(..),+ findImportedModule,+ findPluginModule,+ findExactModule,+ findHomeModule,+ findExposedPackageModule,+ mkHomeModLocation,+ mkHomeModLocation2,+ mkHiOnlyModLocation,+ mkHiPath,+ mkObjPath,+ addHomeModuleToFinder,+ uncacheModule,+ mkStubPaths,++ findObjectLinkableMaybe,+ findObjectLinkable,++ cannotFindModule,+ cannotFindInterface,++ ) where++#include "HsVersions.h"++import Module+import HscTypes+import Packages+import FastString+import Util+import PrelNames ( gHC_PRIM )+import DynFlags+import Outputable+import Maybes ( expectJust )++import Data.IORef ( IORef, readIORef, atomicModifyIORef' )+import System.Directory+import System.FilePath+import Control.Monad+import Data.Time+import Data.List ( foldl' )+++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.lookupModuleInAllPackages for that.++-- -----------------------------------------------------------------------------+-- The finder's cache++-- remove all the home modules from the cache; package modules are+-- assumed to not move around during a session.+flushFinderCaches :: HscEnv -> IO ()+flushFinderCaches hsc_env =+ atomicModifyIORef' fc_ref $ \fm -> (filterInstalledModuleEnv is_ext fm, ())+ where+ this_pkg = thisPackage (hsc_dflags hsc_env)+ fc_ref = hsc_FC hsc_env+ is_ext mod _ | not (installedModuleUnitId mod `installedUnitIdEq` this_pkg) = True+ | otherwise = False++addToFinderCache :: IORef FinderCache -> InstalledModule -> InstalledFindResult -> IO ()+addToFinderCache ref key val =+ atomicModifyIORef' ref $ \c -> (extendInstalledModuleEnv c key val, ())++removeFromFinderCache :: IORef FinderCache -> InstalledModule -> IO ()+removeFromFinderCache ref key =+ atomicModifyIORef' ref $ \c -> (delInstalledModuleEnv c key, ())++lookupFinderCache :: IORef FinderCache -> InstalledModule -> IO (Maybe InstalledFindResult)+lookupFinderCache ref key = do+ c <- readIORef ref+ return $! lookupInstalledModuleEnv c key++-- -----------------------------------------------------------------------------+-- 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 :: HscEnv -> ModuleName -> Maybe FastString -> IO FindResult+findImportedModule hsc_env mod_name mb_pkg =+ case mb_pkg of+ Nothing -> unqual_import+ Just pkg | pkg == fsLit "this" -> home_import -- "this" is special+ | otherwise -> pkg_import+ where+ home_import = findHomeModule hsc_env mod_name++ pkg_import = findExposedPackageModule hsc_env mod_name mb_pkg++ unqual_import = home_import+ `orIfNotFound`+ findExposedPackageModule hsc_env mod_name Nothing++-- | 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 :: HscEnv -> ModuleName -> IO FindResult+findPluginModule hsc_env mod_name =+ findHomeModule hsc_env mod_name+ `orIfNotFound`+ findExposedPluginPackageModule hsc_env 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 :: HscEnv -> InstalledModule -> IO InstalledFindResult+findExactModule hsc_env mod =+ let dflags = hsc_dflags hsc_env+ in if installedModuleUnitId mod `installedUnitIdEq` thisPackage dflags+ then findInstalledHomeModule hsc_env (installedModuleName mod)+ else findPackageModule hsc_env 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_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_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_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 :: HscEnv -> ModuleName -> IO InstalledFindResult -> IO InstalledFindResult+homeSearchCache hsc_env mod_name do_this = do+ let mod = mkHomeInstalledModule (hsc_dflags hsc_env) mod_name+ modLocationCache hsc_env mod do_this++findExposedPackageModule :: HscEnv -> ModuleName -> Maybe FastString+ -> IO FindResult+findExposedPackageModule hsc_env mod_name mb_pkg+ = findLookupResult hsc_env+ $ lookupModuleWithSuggestions+ (hsc_dflags hsc_env) mod_name mb_pkg++findExposedPluginPackageModule :: HscEnv -> ModuleName+ -> IO FindResult+findExposedPluginPackageModule hsc_env mod_name+ = findLookupResult hsc_env+ $ lookupPluginModuleWithSuggestions+ (hsc_dflags hsc_env) mod_name Nothing++findLookupResult :: HscEnv -> LookupResult -> IO FindResult+findLookupResult hsc_env r = case r of+ LookupFound m pkg_conf -> do+ let im = fst (splitModuleInsts m)+ r' <- findPackageModule_ hsc_env im 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 (moduleUnitId m))+ InstalledNotFound fp _ -> return (NotFound{ fr_paths = fp, fr_pkg = Just (moduleUnitId m)+ , fr_pkgs_hidden = []+ , fr_mods_hidden = []+ , fr_suggestions = []})+ LookupMultiple rs ->+ return (FoundMultiple rs)+ LookupHidden pkg_hiddens mod_hiddens ->+ return (NotFound{ fr_paths = [], fr_pkg = Nothing+ , fr_pkgs_hidden = map (moduleUnitId.fst) pkg_hiddens+ , fr_mods_hidden = map (moduleUnitId.fst) mod_hiddens+ , fr_suggestions = [] })+ LookupNotFound suggest ->+ return (NotFound{ fr_paths = [], fr_pkg = Nothing+ , fr_pkgs_hidden = []+ , fr_mods_hidden = []+ , fr_suggestions = suggest })++modLocationCache :: HscEnv -> InstalledModule -> IO InstalledFindResult -> IO InstalledFindResult+modLocationCache hsc_env mod do_this = do+ m <- lookupFinderCache (hsc_FC hsc_env) mod+ case m of+ Just result -> return result+ Nothing -> do+ result <- do_this+ addToFinderCache (hsc_FC hsc_env) mod result+ return result++mkHomeInstalledModule :: DynFlags -> ModuleName -> InstalledModule+mkHomeInstalledModule dflags mod_name =+ let iuid = fst (splitUnitIdInsts (thisPackage dflags))+ in InstalledModule iuid mod_name++-- This returns a module because it's more convenient for users+addHomeModuleToFinder :: HscEnv -> ModuleName -> ModLocation -> IO Module+addHomeModuleToFinder hsc_env mod_name loc = do+ let mod = mkHomeInstalledModule (hsc_dflags hsc_env) mod_name+ addToFinderCache (hsc_FC hsc_env) mod (InstalledFound loc mod)+ return (mkModule (thisPackage (hsc_dflags hsc_env)) mod_name)++uncacheModule :: HscEnv -> ModuleName -> IO ()+uncacheModule hsc_env mod_name = do+ let mod = mkHomeInstalledModule (hsc_dflags hsc_env) mod_name+ removeFromFinderCache (hsc_FC hsc_env) mod++-- -----------------------------------------------------------------------------+-- The internal workers++findHomeModule :: HscEnv -> ModuleName -> IO FindResult+findHomeModule hsc_env mod_name = do+ r <- findInstalledHomeModule hsc_env mod_name+ return $ case r of+ InstalledFound loc _ -> Found loc (mkModule uid mod_name)+ InstalledNoPackage _ -> NoPackage uid -- impossible+ InstalledNotFound fps _ -> NotFound {+ fr_paths = fps,+ fr_pkg = Just uid,+ fr_mods_hidden = [],+ fr_pkgs_hidden = [],+ fr_suggestions = []+ }+ where+ dflags = hsc_dflags hsc_env+ uid = thisPackage dflags++-- | 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 :: HscEnv -> ModuleName -> IO InstalledFindResult+findInstalledHomeModule hsc_env mod_name =+ homeSearchCache hsc_env mod_name $+ let+ dflags = hsc_dflags hsc_env+ home_path = importPaths dflags+ hisuf = hiSuf dflags+ mod = mkHomeInstalledModule dflags mod_name++ source_exts =+ [ ("hs", mkHomeModLocationSearched dflags mod_name "hs")+ , ("lhs", mkHomeModLocationSearched dflags mod_name "lhs")+ , ("hsig", mkHomeModLocationSearched dflags mod_name "hsig")+ , ("lhsig", mkHomeModLocationSearched dflags mod_name "lhsig")+ ]++ hi_exts = [ (hisuf, mkHiOnlyModLocation dflags hisuf)+ , (addBootSuffix hisuf, mkHiOnlyModLocation dflags hisuf)+ ]++ -- 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 | isOneShot (ghcMode dflags) = 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 :: HscEnv -> InstalledModule -> IO InstalledFindResult+findPackageModule hsc_env mod = do+ let+ dflags = hsc_dflags hsc_env+ pkg_id = installedModuleUnitId mod+ --+ case lookupInstalledPackage dflags pkg_id of+ Nothing -> return (InstalledNoPackage pkg_id)+ Just pkg_conf -> findPackageModule_ hsc_env mod pkg_conf++-- | 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 @Packages.hs@) and (2)+-- the 'PackageConfig' 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_ :: HscEnv -> InstalledModule -> PackageConfig -> IO InstalledFindResult+findPackageModule_ hsc_env mod pkg_conf =+ ASSERT2( installedModuleUnitId mod == installedPackageConfigId pkg_conf, ppr (installedModuleUnitId mod) <+> ppr (installedPackageConfigId pkg_conf) )+ modLocationCache hsc_env 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+ dflags = hsc_dflags hsc_env+ tag = buildTag dflags++ -- hi-suffix for packages depends on the build tag.+ package_hisuf | null tag = "hi"+ | otherwise = tag ++ "_hi"++ mk_hi_loc = mkHiOnlyModLocation dflags package_hisuf++ import_dirs = importDirs 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] | MkDepend <- ghcMode dflags -> do+ -- there's only one place that this .hi file can be, so+ -- don't bother looking for it.+ let basename = moduleNameSlashes (installedModuleName mod)+ loc <- mk_hi_loc one basename+ 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 -> IO ModLocation -- action+ )+ ]+ -> IO InstalledFindResult++searchPathExts paths mod exts+ = do result <- search to_search+{-+ hPutStrLn stderr (showSDoc $+ vcat [text "Search" <+> ppr mod <+> sep (map (text. fst) exts)+ , nest 2 (vcat (map text paths))+ , case result of+ Succeeded (loc, p) -> text "Found" <+> ppr loc+ Failed fs -> text "not found"])+-}+ return result++ where+ basename = moduleNameSlashes (installedModuleName mod)++ to_search :: [(FilePath, IO 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 (installedModuleUnitId mod)))++ search ((file, mk_result) : rest) = do+ b <- doesFileExist file+ if b+ then do { loc <- mk_result; return (InstalledFound loc mod) }+ else search rest++mkHomeModLocationSearched :: DynFlags -> ModuleName -> FileExt+ -> FilePath -> BaseName -> IO ModLocation+mkHomeModLocationSearched dflags mod suff path basename = do+ mkHomeModLocation2 dflags 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 :: DynFlags -> ModuleName -> FilePath -> IO ModLocation+mkHomeModLocation dflags mod src_filename = do+ let (basename,extension) = splitExtension src_filename+ mkHomeModLocation2 dflags mod basename extension++mkHomeModLocation2 :: DynFlags+ -> ModuleName+ -> FilePath -- Of source module, without suffix+ -> String -- Suffix+ -> IO ModLocation+mkHomeModLocation2 dflags mod src_basename ext = do+ let mod_basename = moduleNameSlashes mod++ obj_fn = mkObjPath dflags src_basename mod_basename+ hi_fn = mkHiPath dflags src_basename mod_basename++ return (ModLocation{ ml_hs_file = Just (src_basename <.> ext),+ ml_hi_file = hi_fn,+ ml_obj_file = obj_fn })++mkHiOnlyModLocation :: DynFlags -> Suffix -> FilePath -> String+ -> IO ModLocation+mkHiOnlyModLocation dflags hisuf path basename+ = do let full_basename = path </> basename+ obj_fn = mkObjPath dflags full_basename basename+ return 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_obj_file = obj_fn+ }++-- | Constructs the filename of a .o file for a given source file.+-- Does /not/ check whether the .o file exists+mkObjPath+ :: DynFlags+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkObjPath dflags basename mod_basename = obj_basename <.> osuf+ where+ odir = objectDir dflags+ osuf = objectSuf dflags++ 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+ :: DynFlags+ -> FilePath -- the filename of the source file, minus the extension+ -> String -- the module name with dots replaced by slashes+ -> FilePath+mkHiPath dflags basename mod_basename = hi_basename <.> hisuf+ where+ hidir = hiDir dflags+ hisuf = hiSuf dflags++ hi_basename | Just dir <- hidir = 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+ :: DynFlags+ -> ModuleName+ -> ModLocation+ -> FilePath++mkStubPaths dflags mod location+ = let+ stubdir = stubDir dflags++ 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)++-- -----------------------------------------------------------------------------+-- Error messages++cannotFindModule :: DynFlags -> ModuleName -> FindResult -> SDoc+cannotFindModule = cantFindErr (sLit "Could not find module")+ (sLit "Ambiguous module name")++cannotFindInterface :: DynFlags -> ModuleName -> InstalledFindResult -> SDoc+cannotFindInterface = cantFindInstalledErr (sLit "Failed to load interface for")+ (sLit "Ambiguous interface for")++cantFindErr :: LitString -> LitString -> DynFlags -> ModuleName -> FindResult+ -> SDoc+cantFindErr _ multiple_found _ mod_name (FoundMultiple mods)+ | Just pkgs <- unambiguousPackages+ = hang (ptext multiple_found <+> quotes (ppr mod_name) <> colon) 2 (+ sep [text "it was found in multiple packages:",+ hsep (map ppr pkgs) ]+ )+ | otherwise+ = hang (ptext multiple_found <+> quotes (ppr mod_name) <> colon) 2 (+ vcat (map pprMod mods)+ )+ where+ unambiguousPackages = foldl' unambiguousPackage (Just []) mods+ unambiguousPackage (Just xs) (m, ModOrigin (Just _) _ _ _)+ = Just (moduleUnitId m : xs)+ unambiguousPackage _ _ = Nothing++ pprMod (m, o) = text "it is bound as" <+> ppr m <+>+ text "by" <+> pprOrigin m o+ pprOrigin _ ModHidden = panic "cantFindErr: bound by mod hidden"+ pprOrigin m (ModOrigin e res _ f) = sep $ punctuate comma (+ if e == Just True+ then [text "package" <+> ppr (moduleUnitId m)]+ else [] +++ map ((text "a reexport in package" <+>)+ .ppr.packageConfigId) res +++ if f then [text "a package flag"] else []+ )++cantFindErr cannot_find _ dflags mod_name find_result+ = ptext cannot_find <+> quotes (ppr mod_name)+ $$ more_info+ where+ more_info+ = case find_result of+ NoPackage pkg+ -> text "no unit id matching" <+> quotes (ppr pkg) <+>+ text "was found"++ NotFound { fr_paths = files, fr_pkg = mb_pkg+ , fr_mods_hidden = mod_hiddens, fr_pkgs_hidden = pkg_hiddens+ , fr_suggestions = suggest }+ | Just pkg <- mb_pkg, pkg /= thisPackage dflags+ -> not_found_in_package pkg files++ | not (null suggest)+ -> pp_suggestions suggest $$ tried_these files++ | null files && null mod_hiddens && null pkg_hiddens+ -> text "It is not a module in the current program, or in any known package."++ | otherwise+ -> vcat (map pkg_hidden pkg_hiddens) $$+ vcat (map mod_hidden mod_hiddens) $$+ tried_these files++ _ -> panic "cantFindErr"++ build_tag = buildTag dflags++ not_found_in_package pkg files+ | build_tag /= ""+ = let+ build = if build_tag == "p" then "profiling"+ else "\"" ++ build_tag ++ "\""+ in+ text "Perhaps you haven't installed the " <> text build <>+ text " libraries for package " <> quotes (ppr pkg) <> char '?' $$+ tried_these files++ | otherwise+ = text "There are files missing in the " <> quotes (ppr pkg) <>+ text " package," $$+ text "try running 'ghc-pkg check'." $$+ tried_these files++ tried_these files+ | null files = Outputable.empty+ | verbosity dflags < 3 =+ text "Use -v to see a list of the files searched for."+ | otherwise =+ hang (text "Locations searched:") 2 $ vcat (map text files)++ pkg_hidden :: UnitId -> SDoc+ pkg_hidden pkgid =+ text "It is a member of the hidden package"+ <+> quotes (ppr pkgid)+ --FIXME: we don't really want to show the unit id here we should+ -- show the source package id or installed package id if it's ambiguous+ <> dot $$ cabal_pkg_hidden_hint pkgid+ cabal_pkg_hidden_hint pkgid+ | gopt Opt_BuildingCabalPackage dflags+ = let pkg = expectJust "pkg_hidden" (lookupPackage dflags pkgid)+ in text "Perhaps you need to add" <+>+ quotes (ppr (packageName pkg)) <+>+ text "to the build-depends in your .cabal file."+ | otherwise = Outputable.empty++ mod_hidden pkg =+ text "it is a hidden module in the package" <+> quotes (ppr pkg)++ pp_suggestions :: [ModuleSuggestion] -> SDoc+ pp_suggestions sugs+ | null sugs = Outputable.empty+ | otherwise = hang (text "Perhaps you meant")+ 2 (vcat (map pp_sugg sugs))++ -- NB: Prefer the *original* location, and then reexports, and then+ -- package flags when making suggestions. ToDo: if the original package+ -- also has a reexport, prefer that one+ pp_sugg (SuggestVisible m mod o) = ppr m <+> provenance o+ where provenance ModHidden = Outputable.empty+ provenance (ModOrigin{ fromOrigPackage = e,+ fromExposedReexport = res,+ fromPackageFlag = f })+ | Just True <- e+ = parens (text "from" <+> ppr (moduleUnitId mod))+ | f && moduleName mod == m+ = parens (text "from" <+> ppr (moduleUnitId mod))+ | (pkg:_) <- res+ = parens (text "from" <+> ppr (packageConfigId pkg)+ <> comma <+> text "reexporting" <+> ppr mod)+ | f+ = parens (text "defined via package flags to be"+ <+> ppr mod)+ | otherwise = Outputable.empty+ pp_sugg (SuggestHidden m mod o) = ppr m <+> provenance o+ where provenance ModHidden = Outputable.empty+ provenance (ModOrigin{ fromOrigPackage = e,+ fromHiddenReexport = rhs })+ | Just False <- e+ = parens (text "needs flag -package-key"+ <+> ppr (moduleUnitId mod))+ | (pkg:_) <- rhs+ = parens (text "needs flag -package-id"+ <+> ppr (packageConfigId pkg))+ | otherwise = Outputable.empty++cantFindInstalledErr :: LitString -> LitString -> DynFlags -> ModuleName -> InstalledFindResult+ -> SDoc+cantFindInstalledErr cannot_find _ dflags mod_name find_result+ = ptext cannot_find <+> quotes (ppr mod_name)+ $$ more_info+ where+ more_info+ = case find_result of+ InstalledNoPackage pkg+ -> text "no unit id matching" <+> quotes (ppr pkg) <+>+ text "was found" $$ looks_like_srcpkgid pkg++ InstalledNotFound files mb_pkg+ | Just pkg <- mb_pkg, not (pkg `installedUnitIdEq` thisPackage dflags)+ -> not_found_in_package pkg files++ | null files+ -> text "It is not a module in the current program, or in any known package."++ | otherwise+ -> tried_these files++ _ -> panic "cantFindInstalledErr"++ build_tag = buildTag dflags++ looks_like_srcpkgid :: InstalledUnitId -> SDoc+ looks_like_srcpkgid pk+ -- Unsafely coerce a unit id FastString into a source package ID+ -- FastString and see if it means anything.+ | (pkg:pkgs) <- searchPackageId dflags (SourcePackageId (installedUnitIdFS pk))+ = parens (text "This unit ID looks like the source package ID;" $$+ text "the real unit ID is" <+> quotes (ftext (installedUnitIdFS (unitId pkg))) $$+ (if null pkgs then Outputable.empty+ else text "and" <+> int (length pkgs) <+> text "other candidates"))+ -- Todo: also check if it looks like a package name!+ | otherwise = Outputable.empty++ not_found_in_package pkg files+ | build_tag /= ""+ = let+ build = if build_tag == "p" then "profiling"+ else "\"" ++ build_tag ++ "\""+ in+ text "Perhaps you haven't installed the " <> text build <>+ text " libraries for package " <> quotes (ppr pkg) <> char '?' $$+ tried_these files++ | otherwise+ = text "There are files missing in the " <> quotes (ppr pkg) <>+ text " package," $$+ text "try running 'ghc-pkg check'." $$+ tried_these files++ tried_these files+ | null files = Outputable.empty+ | verbosity dflags < 3 =+ text "Use -v to see a list of the files searched for."+ | otherwise =+ hang (text "Locations searched:") 2 $ vcat (map text files)
+ main/GHC.hs view
@@ -0,0 +1,1541 @@+{-# LANGUAGE CPP, NondecreasingIndentation, ScopedTypeVariables,+ NamedFieldPuns, TupleSections #-}++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2005-2012+--+-- The GHC API+--+-- -----------------------------------------------------------------------------++module GHC (+ -- * Initialisation+ defaultErrorHandler,+ defaultCleanupHandler,+ prettyPrintGhcErrors,+ withSignalHandlers,+ withCleanupSession,++ -- * GHC Monad+ Ghc, GhcT, GhcMonad(..), HscEnv,+ runGhc, runGhcT, initGhcMonad,+ gcatch, gbracket, gfinally,+ printException,+ handleSourceError,+ needsTemplateHaskell,++ -- * Flags and settings+ DynFlags(..), GeneralFlag(..), Severity(..), HscTarget(..), gopt,+ GhcMode(..), GhcLink(..), defaultObjectTarget,+ parseDynamicFlags,+ getSessionDynFlags, setSessionDynFlags,+ getProgramDynFlags, setProgramDynFlags, setLogAction,+ getInteractiveDynFlags, setInteractiveDynFlags,++ -- * Targets+ Target(..), TargetId(..), Phase,+ setTargets,+ getTargets,+ addTarget,+ removeTarget,+ guessTarget,++ -- * Loading\/compiling the program+ depanal,+ load, LoadHowMuch(..), InteractiveImport(..),+ SuccessFlag(..), succeeded, failed,+ defaultWarnErrLogger, WarnErrLogger,+ workingDirectoryChanged,+ parseModule, typecheckModule, desugarModule, loadModule,+ ParsedModule(..), TypecheckedModule(..), DesugaredModule(..),+ TypecheckedSource, ParsedSource, RenamedSource, -- ditto+ TypecheckedMod, ParsedMod,+ moduleInfo, renamedSource, typecheckedSource,+ parsedSource, coreModule,++ -- ** Compiling to Core+ CoreModule(..),+ compileToCoreModule, compileToCoreSimplified,++ -- * Inspecting the module structure of the program+ ModuleGraph, ModSummary(..), ms_mod_name, ModLocation(..),+ getModSummary,+ getModuleGraph,+ isLoaded,+ topSortModuleGraph,++ -- * Inspecting modules+ ModuleInfo,+ getModuleInfo,+ modInfoTyThings,+ modInfoTopLevelScope,+ modInfoExports,+ modInfoExportsWithSelectors,+ modInfoInstances,+ modInfoIsExportedName,+ modInfoLookupName,+ modInfoIface,+ modInfoSafe,+ lookupGlobalName,+ findGlobalAnns,+ mkPrintUnqualifiedForModule,+ ModIface(..),+ SafeHaskellMode(..),++ -- * Querying the environment+ -- packageDbModules,++ -- * Printing+ PrintUnqualified, alwaysQualify,++ -- * Interactive evaluation++ -- ** Executing statements+ execStmt, ExecOptions(..), execOptions, ExecResult(..),+ resumeExec,++ -- ** Adding new declarations+ runDecls, runDeclsWithLocation,++ -- ** Get/set the current context+ parseImportDecl,+ setContext, getContext,+ setGHCiMonad, getGHCiMonad,++ -- ** Inspecting the current context+ getBindings, getInsts, getPrintUnqual,+ findModule, lookupModule,+ isModuleTrusted, moduleTrustReqs,+ getNamesInScope,+ getRdrNamesInScope,+ getGRE,+ moduleIsInterpreted,+ getInfo,+ showModule,+ moduleIsBootOrNotObjectLinkable,+ getNameToInstancesIndex,++ -- ** Inspecting types and kinds+ exprType, TcRnExprMode(..),+ typeKind,++ -- ** Looking up a Name+ parseName,+ lookupName,++ -- ** Compiling expressions+ HValue, parseExpr, compileParsedExpr,+ InteractiveEval.compileExpr, dynCompileExpr,+ ForeignHValue,+ compileExprRemote, compileParsedExprRemote,++ -- ** Other+ runTcInteractive, -- Desired by some clients (Trac #8878)+ isStmt, hasImport, isImport, isDecl,++ -- ** The debugger+ SingleStep(..),+ Resume(..),+ History(historyBreakInfo, historyEnclosingDecls),+ GHC.getHistorySpan, getHistoryModule,+ abandon, abandonAll,+ getResumeContext,+ GHC.obtainTermFromId, GHC.obtainTermFromVal, reconstructType,+ modInfoModBreaks,+ ModBreaks(..), BreakIndex,+ BreakInfo(breakInfo_number, breakInfo_module),+ InteractiveEval.back,+ InteractiveEval.forward,++ -- * Abstract syntax elements++ -- ** Packages+ UnitId,++ -- ** Modules+ Module, mkModule, pprModule, moduleName, moduleUnitId,+ ModuleName, mkModuleName, moduleNameString,++ -- ** Names+ Name,+ isExternalName, nameModule, pprParenSymName, nameSrcSpan,+ NamedThing(..),+ RdrName(Qual,Unqual),++ -- ** Identifiers+ Id, idType,+ isImplicitId, isDeadBinder,+ isExportedId, isLocalId, isGlobalId,+ isRecordSelector,+ isPrimOpId, isFCallId, isClassOpId_maybe,+ isDataConWorkId, idDataCon,+ isBottomingId, isDictonaryId,+ recordSelectorTyCon,++ -- ** Type constructors+ TyCon,+ tyConTyVars, tyConDataCons, tyConArity,+ isClassTyCon, isTypeSynonymTyCon, isTypeFamilyTyCon, isNewTyCon,+ isPrimTyCon, isFunTyCon,+ isFamilyTyCon, isOpenFamilyTyCon, isOpenTypeFamilyTyCon,+ tyConClass_maybe,+ synTyConRhs_maybe, synTyConDefn_maybe, tyConKind,++ -- ** Type variables+ TyVar,+ alphaTyVars,++ -- ** Data constructors+ DataCon,+ dataConSig, dataConType, dataConTyCon, dataConFieldLabels,+ dataConIsInfix, isVanillaDataCon, dataConUserType,+ dataConSrcBangs,+ StrictnessMark(..), isMarkedStrict,++ -- ** Classes+ Class,+ classMethods, classSCTheta, classTvsFds, classATs,+ pprFundeps,++ -- ** Instances+ ClsInst,+ instanceDFunId,+ pprInstance, pprInstanceHdr,+ pprFamInst,++ FamInst,++ -- ** Types and Kinds+ Type, splitForAllTys, funResultTy,+ pprParendType, pprTypeApp,+ Kind,+ PredType,+ ThetaType, pprForAll, pprThetaArrowTy,++ -- ** Entities+ TyThing(..),++ -- ** Syntax+ module HsSyn, -- ToDo: remove extraneous bits++ -- ** Fixities+ FixityDirection(..),+ defaultFixity, maxPrecedence,+ negateFixity,+ compareFixity,+ LexicalFixity(..),++ -- ** Source locations+ SrcLoc(..), RealSrcLoc,+ mkSrcLoc, noSrcLoc,+ srcLocFile, srcLocLine, srcLocCol,+ SrcSpan(..), RealSrcSpan,+ mkSrcSpan, srcLocSpan, isGoodSrcSpan, noSrcSpan,+ srcSpanStart, srcSpanEnd,+ srcSpanFile,+ srcSpanStartLine, srcSpanEndLine,+ srcSpanStartCol, srcSpanEndCol,++ -- ** Located+ GenLocated(..), Located,++ -- *** Constructing Located+ noLoc, mkGeneralLocated,++ -- *** Deconstructing Located+ getLoc, unLoc,++ -- *** Combining and comparing Located values+ eqLocated, cmpLocated, combineLocs, addCLoc,+ leftmost_smallest, leftmost_largest, rightmost,+ spans, isSubspanOf,++ -- * Exceptions+ GhcException(..), showGhcException,++ -- * Token stream manipulations+ Token,+ getTokenStream, getRichTokenStream,+ showRichTokenStream, addSourceToTokens,++ -- * Pure interface to the parser+ parser,++ -- * API Annotations+ ApiAnns,AnnKeywordId(..),AnnotationComment(..),+ getAnnotation, getAndRemoveAnnotation,+ getAnnotationComments, getAndRemoveAnnotationComments,+ unicodeAnn,++ -- * Miscellaneous+ --sessionHscEnv,+ cyclicModuleErr,+ ) where++{-+ ToDo:++ * inline bits of HscMain here to simplify layering: hscTcExpr, hscStmt.+-}++#include "HsVersions.h"++import ByteCodeTypes+import InteractiveEval+import InteractiveEvalTypes+import TcRnDriver ( runTcInteractive )+import GHCi+import GHCi.RemoteTypes++import PprTyThing ( pprFamInst )+import HscMain+import GhcMake+import DriverPipeline ( compileOne' )+import GhcMonad+import TcRnMonad ( finalSafeMode, fixSafeInstances )+import TcRnTypes+import Packages+import NameSet+import RdrName+import HsSyn+import Type hiding( typeKind )+import TcType hiding( typeKind )+import Id+import TysPrim ( alphaTyVars )+import TyCon+import Class+import DataCon+import Name hiding ( varName )+import Avail+import InstEnv+import FamInstEnv ( FamInst )+import SrcLoc+import CoreSyn+import TidyPgm+import DriverPhases ( Phase(..), isHaskellSrcFilename )+import Finder+import HscTypes+import DynFlags+import SysTools+import Annotations+import Module+import Panic+import Platform+import Bag ( listToBag, unitBag )+import ErrUtils+import MonadUtils+import Util+import StringBuffer+import Outputable+import BasicTypes+import Maybes ( expectJust )+import FastString+import qualified Parser+import Lexer+import ApiAnnotation+import qualified GHC.LanguageExtensions as LangExt+import NameEnv+import CoreFVs ( orphNamesOfFamInst )+import FamInstEnv ( famInstEnvElts )+import TcRnDriver+import Inst+import FamInst++import Data.Foldable+import qualified Data.Map.Strict as Map+import Data.Set (Set)+import qualified Data.Sequence as Seq+import System.Directory ( doesFileExist )+import Data.Maybe+import Data.List ( find )+import Data.Time+import Data.Typeable ( Typeable )+import Data.Word ( Word8 )+import Control.Monad+import System.Exit ( exitWith, ExitCode(..) )+import Exception+import Data.IORef+import System.FilePath+import System.IO+import Prelude hiding (init)+++-- %************************************************************************+-- %* *+-- Initialisation: exception handlers+-- %* *+-- %************************************************************************+++-- | Install some default exception handlers and run the inner computation.+-- Unless you want to handle exceptions yourself, you should wrap this around+-- the top level of your program. The default handlers output the error+-- message(s) to stderr and exit cleanly.+defaultErrorHandler :: (ExceptionMonad m)+ => FatalMessager -> FlushOut -> m a -> m a+defaultErrorHandler fm (FlushOut flushOut) inner =+ -- top-level exception handler: any unrecognised exception is a compiler bug.+ ghandle (\exception -> liftIO $ do+ flushOut+ case fromException exception of+ -- an IO exception probably isn't our fault, so don't panic+ Just (ioe :: IOException) ->+ fatalErrorMsg'' fm (show ioe)+ _ -> case fromException exception of+ Just UserInterrupt ->+ -- Important to let this one propagate out so our+ -- calling process knows we were interrupted by ^C+ liftIO $ throwIO UserInterrupt+ Just StackOverflow ->+ fatalErrorMsg'' fm "stack overflow: use +RTS -K<size> to increase it"+ _ -> case fromException exception of+ Just (ex :: ExitCode) -> liftIO $ throwIO ex+ _ ->+ fatalErrorMsg'' fm+ (show (Panic (show exception)))+ exitWith (ExitFailure 1)+ ) $++ -- error messages propagated as exceptions+ handleGhcException+ (\ge -> liftIO $ do+ flushOut+ case ge of+ Signal _ -> exitWith (ExitFailure 1)+ _ -> do fatalErrorMsg'' fm (show ge)+ exitWith (ExitFailure 1)+ ) $+ inner++-- | This function is no longer necessary, cleanup is now done by+-- runGhc/runGhcT.+{-# DEPRECATED defaultCleanupHandler "Cleanup is now done by runGhc/runGhcT" #-}+defaultCleanupHandler :: (ExceptionMonad m) => DynFlags -> m a -> m a+defaultCleanupHandler _ m = m+ where _warning_suppression = m `gonException` undefined+++-- %************************************************************************+-- %* *+-- The Ghc Monad+-- %* *+-- %************************************************************************++-- | Run function for the 'Ghc' monad.+--+-- It initialises the GHC session and warnings via 'initGhcMonad'. Each call+-- to this function will create a new session which should not be shared among+-- several threads.+--+-- Any errors not handled inside the 'Ghc' action are propagated as IO+-- exceptions.++runGhc :: Maybe FilePath -- ^ See argument to 'initGhcMonad'.+ -> Ghc a -- ^ The action to perform.+ -> IO a+runGhc mb_top_dir ghc = do+ ref <- newIORef (panic "empty session")+ let session = Session ref+ flip unGhc session $ withSignalHandlers $ do -- catch ^C+ initGhcMonad mb_top_dir+ withCleanupSession ghc++-- | Run function for 'GhcT' monad transformer.+--+-- It initialises the GHC session and warnings via 'initGhcMonad'. Each call+-- to this function will create a new session which should not be shared among+-- several threads.++runGhcT :: ExceptionMonad m =>+ Maybe FilePath -- ^ See argument to 'initGhcMonad'.+ -> GhcT m a -- ^ The action to perform.+ -> m a+runGhcT mb_top_dir ghct = do+ ref <- liftIO $ newIORef (panic "empty session")+ let session = Session ref+ flip unGhcT session $ withSignalHandlers $ do -- catch ^C+ initGhcMonad mb_top_dir+ withCleanupSession ghct++withCleanupSession :: GhcMonad m => m a -> m a+withCleanupSession ghc = ghc `gfinally` cleanup+ where+ cleanup = do+ hsc_env <- getSession+ let dflags = hsc_dflags hsc_env+ liftIO $ do+ cleanTempFiles dflags+ cleanTempDirs dflags+ stopIServ hsc_env -- shut down the IServ+ log_finaliser dflags dflags+ -- exceptions will be blocked while we clean the temporary files,+ -- so there shouldn't be any difficulty if we receive further+ -- signals.++-- | Initialise a GHC session.+--+-- If you implement a custom 'GhcMonad' you must call this function in the+-- monad run function. It will initialise the session variable and clear all+-- warnings.+--+-- The first argument should point to the directory where GHC's library files+-- reside. More precisely, this should be the output of @ghc --print-libdir@+-- of the version of GHC the module using this API is compiled with. For+-- portability, you should use the @ghc-paths@ package, available at+-- <http://hackage.haskell.org/package/ghc-paths>.++initGhcMonad :: GhcMonad m => Maybe FilePath -> m ()+initGhcMonad mb_top_dir+ = do { env <- liftIO $+ do { mySettings <- initSysTools mb_top_dir+ ; dflags <- initDynFlags (defaultDynFlags mySettings)+ ; checkBrokenTablesNextToCode dflags+ ; setUnsafeGlobalDynFlags dflags+ -- c.f. DynFlags.parseDynamicFlagsFull, which+ -- creates DynFlags and sets the UnsafeGlobalDynFlags+ ; newHscEnv dflags }+ ; setSession env }++-- | The binutils linker on ARM emits unnecessary R_ARM_COPY relocations which+-- breaks tables-next-to-code in dynamically linked modules. This+-- check should be more selective but there is currently no released+-- version where this bug is fixed.+-- See https://sourceware.org/bugzilla/show_bug.cgi?id=16177 and+-- https://ghc.haskell.org/trac/ghc/ticket/4210#comment:29+checkBrokenTablesNextToCode :: MonadIO m => DynFlags -> m ()+checkBrokenTablesNextToCode dflags+ = do { broken <- checkBrokenTablesNextToCode' dflags+ ; when broken+ $ do { _ <- liftIO $ throwIO $ mkApiErr dflags invalidLdErr+ ; fail "unsupported linker"+ }+ }+ where+ invalidLdErr = text "Tables-next-to-code not supported on ARM" <+>+ text "when using binutils ld (please see:" <+>+ text "https://sourceware.org/bugzilla/show_bug.cgi?id=16177)"++checkBrokenTablesNextToCode' :: MonadIO m => DynFlags -> m Bool+checkBrokenTablesNextToCode' dflags+ | not (isARM arch) = return False+ | WayDyn `notElem` ways dflags = return False+ | not (tablesNextToCode dflags) = return False+ | otherwise = do+ linkerInfo <- liftIO $ getLinkerInfo dflags+ case linkerInfo of+ GnuLD _ -> return True+ _ -> return False+ where platform = targetPlatform dflags+ arch = platformArch platform+++-- %************************************************************************+-- %* *+-- Flags & settings+-- %* *+-- %************************************************************************++-- $DynFlags+--+-- The GHC session maintains two sets of 'DynFlags':+--+-- * The "interactive" @DynFlags@, which are used for everything+-- related to interactive evaluation, including 'runStmt',+-- 'runDecls', 'exprType', 'lookupName' and so on (everything+-- under \"Interactive evaluation\" in this module).+--+-- * The "program" @DynFlags@, which are used when loading+-- whole modules with 'load'+--+-- 'setInteractiveDynFlags', 'getInteractiveDynFlags' work with the+-- interactive @DynFlags@.+--+-- 'setProgramDynFlags', 'getProgramDynFlags' work with the+-- program @DynFlags@.+--+-- 'setSessionDynFlags' sets both @DynFlags@, and 'getSessionDynFlags'+-- retrieves the program @DynFlags@ (for backwards compatibility).+++-- | Updates both the interactive and program DynFlags in a Session.+-- This also reads the package database (unless it has already been+-- read), and prepares the compilers knowledge about packages. It can+-- be called again to load new packages: just add new package flags to+-- (packageFlags dflags).+--+-- Returns a list of new packages that may need to be linked in using+-- the dynamic linker (see 'linkPackages') as a result of new package+-- flags. If you are not doing linking or doing static linking, you+-- can ignore the list of packages returned.+--+setSessionDynFlags :: GhcMonad m => DynFlags -> m [InstalledUnitId]+setSessionDynFlags dflags = do+ dflags' <- checkNewDynFlags dflags+ (dflags'', preload) <- liftIO $ initPackages dflags'+ modifySession $ \h -> h{ hsc_dflags = dflags''+ , hsc_IC = (hsc_IC h){ ic_dflags = dflags'' } }+ invalidateModSummaryCache+ return preload++-- | Sets the program 'DynFlags'. Note: this invalidates the internal+-- cached module graph, causing more work to be done the next time+-- 'load' is called.+setProgramDynFlags :: GhcMonad m => DynFlags -> m [InstalledUnitId]+setProgramDynFlags dflags = setProgramDynFlags_ True dflags++-- | Set the action taken when the compiler produces a message. This+-- can also be accomplished using 'setProgramDynFlags', but using+-- 'setLogAction' avoids invalidating the cached module graph.+setLogAction :: GhcMonad m => LogAction -> LogFinaliser -> m ()+setLogAction action finaliser = do+ dflags' <- getProgramDynFlags+ void $ setProgramDynFlags_ False $+ dflags' { log_action = action+ , log_finaliser = finaliser }++setProgramDynFlags_ :: GhcMonad m => Bool -> DynFlags -> m [InstalledUnitId]+setProgramDynFlags_ invalidate_needed dflags = do+ dflags' <- checkNewDynFlags dflags+ dflags_prev <- getProgramDynFlags+ (dflags'', preload) <-+ if (packageFlagsChanged dflags_prev dflags')+ then liftIO $ initPackages dflags'+ else return (dflags', [])+ modifySession $ \h -> h{ hsc_dflags = dflags'' }+ when invalidate_needed $ invalidateModSummaryCache+ return preload+++-- When changing the DynFlags, we want the changes to apply to future+-- loads, but without completely discarding the program. But the+-- DynFlags are cached in each ModSummary in the hsc_mod_graph, so+-- after a change to DynFlags, the changes would apply to new modules+-- but not existing modules; this seems undesirable.+--+-- Furthermore, the GHC API client might expect that changing+-- log_action would affect future compilation messages, but for those+-- modules we have cached ModSummaries for, we'll continue to use the+-- old log_action. This is definitely wrong (#7478).+--+-- Hence, we invalidate the ModSummary cache after changing the+-- DynFlags. We do this by tweaking the date on each ModSummary, so+-- that the next downsweep will think that all the files have changed+-- and preprocess them again. This won't necessarily cause everything+-- to be recompiled, because by the time we check whether we need to+-- recopmile a module, we'll have re-summarised the module and have a+-- correct ModSummary.+--+invalidateModSummaryCache :: GhcMonad m => m ()+invalidateModSummaryCache =+ modifySession $ \h -> h { hsc_mod_graph = map inval (hsc_mod_graph h) }+ where+ inval ms = ms { ms_hs_date = addUTCTime (-1) (ms_hs_date ms) }++-- | Returns the program 'DynFlags'.+getProgramDynFlags :: GhcMonad m => m DynFlags+getProgramDynFlags = getSessionDynFlags++-- | Set the 'DynFlags' used to evaluate interactive expressions.+-- Note: this cannot be used for changes to packages. Use+-- 'setSessionDynFlags', or 'setProgramDynFlags' and then copy the+-- 'pkgState' into the interactive @DynFlags@.+setInteractiveDynFlags :: GhcMonad m => DynFlags -> m ()+setInteractiveDynFlags dflags = do+ dflags' <- checkNewDynFlags dflags+ dflags'' <- checkNewInteractiveDynFlags dflags'+ modifySession $ \h -> h{ hsc_IC = (hsc_IC h) { ic_dflags = dflags'' }}++-- | Get the 'DynFlags' used to evaluate interactive expressions.+getInteractiveDynFlags :: GhcMonad m => m DynFlags+getInteractiveDynFlags = withSession $ \h -> return (ic_dflags (hsc_IC h))+++parseDynamicFlags :: MonadIO m =>+ DynFlags -> [Located String]+ -> m (DynFlags, [Located String], [Located String])+parseDynamicFlags = parseDynamicFlagsCmdLine++-- | Checks the set of new DynFlags for possibly erroneous option+-- combinations when invoking 'setSessionDynFlags' and friends, and if+-- found, returns a fixed copy (if possible).+checkNewDynFlags :: MonadIO m => DynFlags -> m DynFlags+checkNewDynFlags dflags = do+ -- See Note [DynFlags consistency]+ let (dflags', warnings) = makeDynFlagsConsistent dflags+ liftIO $ handleFlagWarnings dflags warnings+ return dflags'++checkNewInteractiveDynFlags :: MonadIO m => DynFlags -> m DynFlags+checkNewInteractiveDynFlags dflags0 = do+ dflags1 <-+ if xopt LangExt.StaticPointers dflags0+ then do liftIO $ printOrThrowWarnings dflags0 $ listToBag+ [mkPlainWarnMsg dflags0 interactiveSrcSpan+ $ text "StaticPointers is not supported in GHCi interactive expressions."]+ return $ xopt_unset dflags0 LangExt.StaticPointers+ else return dflags0+ return dflags1+++-- %************************************************************************+-- %* *+-- Setting, getting, and modifying the targets+-- %* *+-- %************************************************************************++-- ToDo: think about relative vs. absolute file paths. And what+-- happens when the current directory changes.++-- | Sets the targets for this session. Each target may be a module name+-- or a filename. The targets correspond to the set of root modules for+-- the program\/library. Unloading the current program is achieved by+-- setting the current set of targets to be empty, followed by 'load'.+setTargets :: GhcMonad m => [Target] -> m ()+setTargets targets = modifySession (\h -> h{ hsc_targets = targets })++-- | Returns the current set of targets+getTargets :: GhcMonad m => m [Target]+getTargets = withSession (return . hsc_targets)++-- | Add another target.+addTarget :: GhcMonad m => Target -> m ()+addTarget target+ = modifySession (\h -> h{ hsc_targets = target : hsc_targets h })++-- | Remove a target+removeTarget :: GhcMonad m => TargetId -> m ()+removeTarget target_id+ = modifySession (\h -> h{ hsc_targets = filter (hsc_targets h) })+ where+ filter targets = [ t | t@(Target id _ _) <- targets, id /= target_id ]++-- | Attempts to guess what Target a string refers to. This function+-- implements the @--make@/GHCi command-line syntax for filenames:+--+-- - if the string looks like a Haskell source filename, then interpret it+-- as such+--+-- - if adding a .hs or .lhs suffix yields the name of an existing file,+-- then use that+--+-- - otherwise interpret the string as a module name+--+guessTarget :: GhcMonad m => String -> Maybe Phase -> m Target+guessTarget str (Just phase)+ = return (Target (TargetFile str (Just phase)) True Nothing)+guessTarget str Nothing+ | isHaskellSrcFilename file+ = return (target (TargetFile file Nothing))+ | otherwise+ = do exists <- liftIO $ doesFileExist hs_file+ if exists+ then return (target (TargetFile hs_file Nothing))+ else do+ exists <- liftIO $ doesFileExist lhs_file+ if exists+ then return (target (TargetFile lhs_file Nothing))+ else do+ if looksLikeModuleName file+ then return (target (TargetModule (mkModuleName file)))+ else do+ dflags <- getDynFlags+ liftIO $ throwGhcExceptionIO+ (ProgramError (showSDoc dflags $+ text "target" <+> quotes (text file) <+>+ text "is not a module name or a source file"))+ where+ (file,obj_allowed)+ | '*':rest <- str = (rest, False)+ | otherwise = (str, True)++ hs_file = file <.> "hs"+ lhs_file = file <.> "lhs"++ target tid = Target tid obj_allowed Nothing+++-- | Inform GHC that the working directory has changed. GHC will flush+-- its cache of module locations, since it may no longer be valid.+--+-- Note: Before changing the working directory make sure all threads running+-- in the same session have stopped. If you change the working directory,+-- you should also unload the current program (set targets to empty,+-- followed by load).+workingDirectoryChanged :: GhcMonad m => m ()+workingDirectoryChanged = withSession $ (liftIO . flushFinderCaches)+++-- %************************************************************************+-- %* *+-- Running phases one at a time+-- %* *+-- %************************************************************************++class ParsedMod m where+ modSummary :: m -> ModSummary+ parsedSource :: m -> ParsedSource++class ParsedMod m => TypecheckedMod m where+ renamedSource :: m -> Maybe RenamedSource+ typecheckedSource :: m -> TypecheckedSource+ moduleInfo :: m -> ModuleInfo+ tm_internals :: m -> (TcGblEnv, ModDetails)+ -- ToDo: improvements that could be made here:+ -- if the module succeeded renaming but not typechecking,+ -- we can still get back the GlobalRdrEnv and exports, so+ -- perhaps the ModuleInfo should be split up into separate+ -- fields.++class TypecheckedMod m => DesugaredMod m where+ coreModule :: m -> ModGuts++-- | The result of successful parsing.+data ParsedModule =+ ParsedModule { pm_mod_summary :: ModSummary+ , pm_parsed_source :: ParsedSource+ , pm_extra_src_files :: [FilePath]+ , pm_annotations :: ApiAnns }+ -- See Note [Api annotations] in ApiAnnotation.hs++instance ParsedMod ParsedModule where+ modSummary m = pm_mod_summary m+ parsedSource m = pm_parsed_source m++-- | The result of successful typechecking. It also contains the parser+-- result.+data TypecheckedModule =+ TypecheckedModule { tm_parsed_module :: ParsedModule+ , tm_renamed_source :: Maybe RenamedSource+ , tm_typechecked_source :: TypecheckedSource+ , tm_checked_module_info :: ModuleInfo+ , tm_internals_ :: (TcGblEnv, ModDetails)+ }++instance ParsedMod TypecheckedModule where+ modSummary m = modSummary (tm_parsed_module m)+ parsedSource m = parsedSource (tm_parsed_module m)++instance TypecheckedMod TypecheckedModule where+ renamedSource m = tm_renamed_source m+ typecheckedSource m = tm_typechecked_source m+ moduleInfo m = tm_checked_module_info m+ tm_internals m = tm_internals_ m++-- | The result of successful desugaring (i.e., translation to core). Also+-- contains all the information of a typechecked module.+data DesugaredModule =+ DesugaredModule { dm_typechecked_module :: TypecheckedModule+ , dm_core_module :: ModGuts+ }++instance ParsedMod DesugaredModule where+ modSummary m = modSummary (dm_typechecked_module m)+ parsedSource m = parsedSource (dm_typechecked_module m)++instance TypecheckedMod DesugaredModule where+ renamedSource m = renamedSource (dm_typechecked_module m)+ typecheckedSource m = typecheckedSource (dm_typechecked_module m)+ moduleInfo m = moduleInfo (dm_typechecked_module m)+ tm_internals m = tm_internals_ (dm_typechecked_module m)++instance DesugaredMod DesugaredModule where+ coreModule m = dm_core_module m++type ParsedSource = Located (HsModule RdrName)+type RenamedSource = (HsGroup Name, [LImportDecl Name], Maybe [LIE Name],+ Maybe LHsDocString)+type TypecheckedSource = LHsBinds Id++-- NOTE:+-- - things that aren't in the output of the typechecker right now:+-- - the export list+-- - the imports+-- - type signatures+-- - type/data/newtype declarations+-- - class declarations+-- - instances+-- - extra things in the typechecker's output:+-- - default methods are turned into top-level decls.+-- - dictionary bindings++-- | Return the 'ModSummary' of a module with the given name.+--+-- The module must be part of the module graph (see 'hsc_mod_graph' and+-- 'ModuleGraph'). If this is not the case, this function will throw a+-- 'GhcApiError'.+--+-- This function ignores boot modules and requires that there is only one+-- non-boot module with the given name.+getModSummary :: GhcMonad m => ModuleName -> m ModSummary+getModSummary mod = do+ mg <- liftM hsc_mod_graph getSession+ case [ ms | ms <- mg, ms_mod_name ms == mod, not (isBootSummary ms) ] of+ [] -> do dflags <- getDynFlags+ liftIO $ throwIO $ mkApiErr dflags (text "Module not part of module graph")+ [ms] -> return ms+ multiple -> do dflags <- getDynFlags+ liftIO $ throwIO $ mkApiErr dflags (text "getModSummary is ambiguous: " <+> ppr multiple)++-- | Parse a module.+--+-- Throws a 'SourceError' on parse error.+parseModule :: GhcMonad m => ModSummary -> m ParsedModule+parseModule ms = do+ hsc_env <- getSession+ let hsc_env_tmp = hsc_env { hsc_dflags = ms_hspp_opts ms }+ hpm <- liftIO $ hscParse hsc_env_tmp ms+ return (ParsedModule ms (hpm_module hpm) (hpm_src_files hpm)+ (hpm_annotations hpm))+ -- See Note [Api annotations] in ApiAnnotation.hs++-- | Typecheck and rename a parsed module.+--+-- Throws a 'SourceError' if either fails.+typecheckModule :: GhcMonad m => ParsedModule -> m TypecheckedModule+typecheckModule pmod = do+ let ms = modSummary pmod+ hsc_env <- getSession+ let hsc_env_tmp = hsc_env { hsc_dflags = ms_hspp_opts ms }+ (tc_gbl_env, rn_info)+ <- liftIO $ hscTypecheckRename hsc_env_tmp ms $+ HsParsedModule { hpm_module = parsedSource pmod,+ hpm_src_files = pm_extra_src_files pmod,+ hpm_annotations = pm_annotations pmod }+ details <- liftIO $ makeSimpleDetails hsc_env_tmp tc_gbl_env+ safe <- liftIO $ finalSafeMode (ms_hspp_opts ms) tc_gbl_env++ return $+ TypecheckedModule {+ tm_internals_ = (tc_gbl_env, details),+ tm_parsed_module = pmod,+ tm_renamed_source = rn_info,+ tm_typechecked_source = tcg_binds tc_gbl_env,+ tm_checked_module_info =+ ModuleInfo {+ minf_type_env = md_types details,+ minf_exports = md_exports details,+ minf_rdr_env = Just (tcg_rdr_env tc_gbl_env),+ minf_instances = fixSafeInstances safe $ md_insts details,+ minf_iface = Nothing,+ minf_safe = safe,+ minf_modBreaks = emptyModBreaks+ }}++-- | Desugar a typechecked module.+desugarModule :: GhcMonad m => TypecheckedModule -> m DesugaredModule+desugarModule tcm = do+ let ms = modSummary tcm+ let (tcg, _) = tm_internals tcm+ hsc_env <- getSession+ let hsc_env_tmp = hsc_env { hsc_dflags = ms_hspp_opts ms }+ guts <- liftIO $ hscDesugar hsc_env_tmp ms tcg+ return $+ DesugaredModule {+ dm_typechecked_module = tcm,+ dm_core_module = guts+ }++-- | Load a module. Input doesn't need to be desugared.+--+-- A module must be loaded before dependent modules can be typechecked. This+-- always includes generating a 'ModIface' and, depending on the+-- 'DynFlags.hscTarget', may also include code generation.+--+-- This function will always cause recompilation and will always overwrite+-- previous compilation results (potentially files on disk).+--+loadModule :: (TypecheckedMod mod, GhcMonad m) => mod -> m mod+loadModule tcm = do+ let ms = modSummary tcm+ let mod = ms_mod_name ms+ let loc = ms_location ms+ let (tcg, _details) = tm_internals tcm++ mb_linkable <- case ms_obj_date ms of+ Just t | t > ms_hs_date ms -> do+ l <- liftIO $ findObjectLinkable (ms_mod ms)+ (ml_obj_file loc) t+ return (Just l)+ _otherwise -> return Nothing++ let source_modified | isNothing mb_linkable = SourceModified+ | otherwise = SourceUnmodified+ -- we can't determine stability here++ -- compile doesn't change the session+ hsc_env <- getSession+ mod_info <- liftIO $ compileOne' (Just tcg) Nothing+ hsc_env ms 1 1 Nothing mb_linkable+ source_modified++ modifySession $ \e -> e{ hsc_HPT = addToHpt (hsc_HPT e) mod mod_info }+ return tcm+++-- %************************************************************************+-- %* *+-- Dealing with Core+-- %* *+-- %************************************************************************++-- | A CoreModule consists of just the fields of a 'ModGuts' that are needed for+-- the 'GHC.compileToCoreModule' interface.+data CoreModule+ = CoreModule {+ -- | Module name+ cm_module :: !Module,+ -- | Type environment for types declared in this module+ cm_types :: !TypeEnv,+ -- | Declarations+ cm_binds :: CoreProgram,+ -- | Safe Haskell mode+ cm_safe :: SafeHaskellMode+ }++instance Outputable CoreModule where+ ppr (CoreModule {cm_module = mn, cm_types = te, cm_binds = cb,+ cm_safe = sf})+ = text "%module" <+> ppr mn <+> parens (ppr sf) <+> ppr te+ $$ vcat (map ppr cb)++-- | This is the way to get access to the Core bindings corresponding+-- to a module. 'compileToCore' parses, typechecks, and+-- desugars the module, then returns the resulting Core module (consisting of+-- the module name, type declarations, and function declarations) if+-- successful.+compileToCoreModule :: GhcMonad m => FilePath -> m CoreModule+compileToCoreModule = compileCore False++-- | Like compileToCoreModule, but invokes the simplifier, so+-- as to return simplified and tidied Core.+compileToCoreSimplified :: GhcMonad m => FilePath -> m CoreModule+compileToCoreSimplified = compileCore True++compileCore :: GhcMonad m => Bool -> FilePath -> m CoreModule+compileCore simplify fn = do+ -- First, set the target to the desired filename+ target <- guessTarget fn Nothing+ addTarget target+ _ <- load LoadAllTargets+ -- Then find dependencies+ modGraph <- depanal [] True+ case find ((== fn) . msHsFilePath) modGraph of+ Just modSummary -> do+ -- Now we have the module name;+ -- parse, typecheck and desugar the module+ mod_guts <- coreModule `fmap`+ -- TODO: space leaky: call hsc* directly?+ (desugarModule =<< typecheckModule =<< parseModule modSummary)+ liftM (gutsToCoreModule (mg_safe_haskell mod_guts)) $+ if simplify+ then do+ -- If simplify is true: simplify (hscSimplify), then tidy+ -- (tidyProgram).+ hsc_env <- getSession+ simpl_guts <- liftIO $ hscSimplify hsc_env mod_guts+ tidy_guts <- liftIO $ tidyProgram hsc_env simpl_guts+ return $ Left tidy_guts+ else+ return $ Right mod_guts++ Nothing -> panic "compileToCoreModule: target FilePath not found in\+ module dependency graph"+ where -- two versions, based on whether we simplify (thus run tidyProgram,+ -- which returns a (CgGuts, ModDetails) pair, or not (in which case+ -- we just have a ModGuts.+ gutsToCoreModule :: SafeHaskellMode+ -> Either (CgGuts, ModDetails) ModGuts+ -> CoreModule+ gutsToCoreModule safe_mode (Left (cg, md)) = CoreModule {+ cm_module = cg_module cg,+ cm_types = md_types md,+ cm_binds = cg_binds cg,+ cm_safe = safe_mode+ }+ gutsToCoreModule safe_mode (Right mg) = CoreModule {+ cm_module = mg_module mg,+ cm_types = typeEnvFromEntities (bindersOfBinds (mg_binds mg))+ (mg_tcs mg)+ (mg_fam_insts mg),+ cm_binds = mg_binds mg,+ cm_safe = safe_mode+ }++-- %************************************************************************+-- %* *+-- Inspecting the session+-- %* *+-- %************************************************************************++-- | Get the module dependency graph.+getModuleGraph :: GhcMonad m => m ModuleGraph -- ToDo: DiGraph ModSummary+getModuleGraph = liftM hsc_mod_graph getSession++-- | Determines whether a set of modules requires Template Haskell.+--+-- Note that if the session's 'DynFlags' enabled Template Haskell when+-- 'depanal' was called, then each module in the returned module graph will+-- have Template Haskell enabled whether it is actually needed or not.+needsTemplateHaskell :: ModuleGraph -> Bool+needsTemplateHaskell ms =+ any (xopt LangExt.TemplateHaskell . ms_hspp_opts) ms++-- | Return @True@ <==> module is loaded.+isLoaded :: GhcMonad m => ModuleName -> m Bool+isLoaded m = withSession $ \hsc_env ->+ return $! isJust (lookupHpt (hsc_HPT hsc_env) m)++-- | Return the bindings for the current interactive session.+getBindings :: GhcMonad m => m [TyThing]+getBindings = withSession $ \hsc_env ->+ return $ icInScopeTTs $ hsc_IC hsc_env++-- | Return the instances for the current interactive session.+getInsts :: GhcMonad m => m ([ClsInst], [FamInst])+getInsts = withSession $ \hsc_env ->+ return $ ic_instances (hsc_IC hsc_env)++getPrintUnqual :: GhcMonad m => m PrintUnqualified+getPrintUnqual = withSession $ \hsc_env ->+ return (icPrintUnqual (hsc_dflags hsc_env) (hsc_IC hsc_env))++-- | Container for information about a 'Module'.+data ModuleInfo = ModuleInfo {+ minf_type_env :: TypeEnv,+ minf_exports :: [AvailInfo],+ minf_rdr_env :: Maybe GlobalRdrEnv, -- Nothing for a compiled/package mod+ minf_instances :: [ClsInst],+ minf_iface :: Maybe ModIface,+ minf_safe :: SafeHaskellMode,+ minf_modBreaks :: ModBreaks+ }+ -- We don't want HomeModInfo here, because a ModuleInfo applies+ -- to package modules too.++-- | Request information about a loaded 'Module'+getModuleInfo :: GhcMonad m => Module -> m (Maybe ModuleInfo) -- XXX: Maybe X+getModuleInfo mdl = withSession $ \hsc_env -> do+ let mg = hsc_mod_graph hsc_env+ if mdl `elem` map ms_mod mg+ then liftIO $ getHomeModuleInfo hsc_env mdl+ else do+ {- if isHomeModule (hsc_dflags hsc_env) mdl+ then return Nothing+ else -} liftIO $ getPackageModuleInfo hsc_env mdl+ -- ToDo: we don't understand what the following comment means.+ -- (SDM, 19/7/2011)+ -- getPackageModuleInfo will attempt to find the interface, so+ -- we don't want to call it for a home module, just in case there+ -- was a problem loading the module and the interface doesn't+ -- exist... hence the isHomeModule test here. (ToDo: reinstate)++getPackageModuleInfo :: HscEnv -> Module -> IO (Maybe ModuleInfo)+getPackageModuleInfo hsc_env mdl+ = do eps <- hscEPS hsc_env+ iface <- hscGetModuleInterface hsc_env mdl+ let+ avails = mi_exports iface+ pte = eps_PTE eps+ tys = [ ty | name <- concatMap availNames avails,+ Just ty <- [lookupTypeEnv pte name] ]+ --+ return (Just (ModuleInfo {+ minf_type_env = mkTypeEnv tys,+ minf_exports = avails,+ minf_rdr_env = Just $! availsToGlobalRdrEnv (moduleName mdl) avails,+ minf_instances = error "getModuleInfo: instances for package module unimplemented",+ minf_iface = Just iface,+ minf_safe = getSafeMode $ mi_trust iface,+ minf_modBreaks = emptyModBreaks+ }))++getHomeModuleInfo :: HscEnv -> Module -> IO (Maybe ModuleInfo)+getHomeModuleInfo hsc_env mdl =+ case lookupHpt (hsc_HPT hsc_env) (moduleName mdl) of+ Nothing -> return Nothing+ Just hmi -> do+ let details = hm_details hmi+ iface = hm_iface hmi+ return (Just (ModuleInfo {+ minf_type_env = md_types details,+ minf_exports = md_exports details,+ minf_rdr_env = mi_globals $! hm_iface hmi,+ minf_instances = md_insts details,+ minf_iface = Just iface,+ minf_safe = getSafeMode $ mi_trust iface+ ,minf_modBreaks = getModBreaks hmi+ }))++-- | The list of top-level entities defined in a module+modInfoTyThings :: ModuleInfo -> [TyThing]+modInfoTyThings minf = typeEnvElts (minf_type_env minf)++modInfoTopLevelScope :: ModuleInfo -> Maybe [Name]+modInfoTopLevelScope minf+ = fmap (map gre_name . globalRdrEnvElts) (minf_rdr_env minf)++modInfoExports :: ModuleInfo -> [Name]+modInfoExports minf = concatMap availNames $! minf_exports minf++modInfoExportsWithSelectors :: ModuleInfo -> [Name]+modInfoExportsWithSelectors minf = concatMap availNamesWithSelectors $! minf_exports minf++-- | Returns the instances defined by the specified module.+-- Warning: currently unimplemented for package modules.+modInfoInstances :: ModuleInfo -> [ClsInst]+modInfoInstances = minf_instances++modInfoIsExportedName :: ModuleInfo -> Name -> Bool+modInfoIsExportedName minf name = elemNameSet name (availsToNameSet (minf_exports minf))++mkPrintUnqualifiedForModule :: GhcMonad m =>+ ModuleInfo+ -> m (Maybe PrintUnqualified) -- XXX: returns a Maybe X+mkPrintUnqualifiedForModule minf = withSession $ \hsc_env -> do+ return (fmap (mkPrintUnqualified (hsc_dflags hsc_env)) (minf_rdr_env minf))++modInfoLookupName :: GhcMonad m =>+ ModuleInfo -> Name+ -> m (Maybe TyThing) -- XXX: returns a Maybe X+modInfoLookupName minf name = withSession $ \hsc_env -> do+ case lookupTypeEnv (minf_type_env minf) name of+ Just tyThing -> return (Just tyThing)+ Nothing -> do+ eps <- liftIO $ readIORef (hsc_EPS hsc_env)+ return $! lookupType (hsc_dflags hsc_env)+ (hsc_HPT hsc_env) (eps_PTE eps) name++modInfoIface :: ModuleInfo -> Maybe ModIface+modInfoIface = minf_iface++-- | Retrieve module safe haskell mode+modInfoSafe :: ModuleInfo -> SafeHaskellMode+modInfoSafe = minf_safe++modInfoModBreaks :: ModuleInfo -> ModBreaks+modInfoModBreaks = minf_modBreaks++isDictonaryId :: Id -> Bool+isDictonaryId id+ = case tcSplitSigmaTy (idType id) of {+ (_tvs, _theta, tau) -> isDictTy tau }++-- | Looks up a global name: that is, any top-level name in any+-- visible module. Unlike 'lookupName', lookupGlobalName does not use+-- the interactive context, and therefore does not require a preceding+-- 'setContext'.+lookupGlobalName :: GhcMonad m => Name -> m (Maybe TyThing)+lookupGlobalName name = withSession $ \hsc_env -> do+ liftIO $ lookupTypeHscEnv hsc_env name++findGlobalAnns :: (GhcMonad m, Typeable a) => ([Word8] -> a) -> AnnTarget Name -> m [a]+findGlobalAnns deserialize target = withSession $ \hsc_env -> do+ ann_env <- liftIO $ prepareAnnotations hsc_env Nothing+ return (findAnns deserialize ann_env target)++-- | get the GlobalRdrEnv for a session+getGRE :: GhcMonad m => m GlobalRdrEnv+getGRE = withSession $ \hsc_env-> return $ ic_rn_gbl_env (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+-- is mentioned in the instance head.+getNameToInstancesIndex :: GhcMonad m+ => m (Messages, Maybe (NameEnv ([ClsInst], [FamInst])))+getNameToInstancesIndex = do+ hsc_env <- getSession+ liftIO $ runTcInteractive hsc_env $+ do { loadUnqualIfaces hsc_env (hsc_IC hsc_env)+ ; InstEnvs {ie_global, ie_local, ie_visible} <- tcGetInstEnvs+ ; (pkg_fie, home_fie) <- tcGetFamInstEnvs+ -- We use Data.Sequence.Seq because we are creating left associated+ -- mappends.+ -- cls_index and fam_index below are adapted from TcRnDriver.lookupInsts+ ; let cls_index = Map.fromListWith mappend+ [ (n, Seq.singleton ispec)+ | ispec <- instEnvElts ie_local ++ instEnvElts ie_global+ , instIsVisible ie_visible ispec+ , n <- nameSetElemsStable $ orphNamesOfClsInst ispec+ ]+ ; let fam_index = Map.fromListWith mappend+ [ (n, Seq.singleton fispec)+ | fispec <- famInstEnvElts home_fie ++ famInstEnvElts pkg_fie+ , n <- nameSetElemsStable $ orphNamesOfFamInst fispec+ ]+ ; return $ mkNameEnv $+ [ (nm, (toList clss, toList fams))+ | (nm, (clss, fams)) <- Map.toList $ Map.unionWith mappend+ (fmap (,Seq.empty) cls_index)+ (fmap (Seq.empty,) fam_index)+ ] }++-- -----------------------------------------------------------------------------++{- ToDo: Move the primary logic here to compiler/main/Packages.hs+-- | Return all /external/ modules available in the package database.+-- Modules from the current session (i.e., from the 'HomePackageTable') are+-- not included. This includes module names which are reexported by packages.+packageDbModules :: GhcMonad m =>+ Bool -- ^ Only consider exposed packages.+ -> m [Module]+packageDbModules only_exposed = do+ dflags <- getSessionDynFlags+ let pkgs = eltsUFM (pkgIdMap (pkgState dflags))+ return $+ [ mkModule pid modname+ | p <- pkgs+ , not only_exposed || exposed p+ , let pid = packageConfigId p+ , modname <- exposedModules p+ ++ map exportName (reexportedModules p) ]+ -}++-- -----------------------------------------------------------------------------+-- Misc exported utils++dataConType :: DataCon -> Type+dataConType dc = idType (dataConWrapId dc)++-- | print a 'NamedThing', adding parentheses if the name is an operator.+pprParenSymName :: NamedThing a => a -> SDoc+pprParenSymName a = parenSymOcc (getOccName a) (ppr (getName a))++-- ----------------------------------------------------------------------------++#if 0++-- ToDo:+-- - Data and Typeable instances for HsSyn.++-- ToDo: check for small transformations that happen to the syntax in+-- the typechecker (eg. -e ==> negate e, perhaps for fromIntegral)++-- ToDo: maybe use TH syntax instead of IfaceSyn? There's already a way+-- to get from TyCons, Ids etc. to TH syntax (reify).++-- :browse will use either lm_toplev or inspect lm_interface, depending+-- on whether the module is interpreted or not.++#endif++-- Extract the filename, stringbuffer content and dynflags associed to a module+--+-- XXX: Explain pre-conditions+getModuleSourceAndFlags :: GhcMonad m => Module -> m (String, StringBuffer, DynFlags)+getModuleSourceAndFlags mod = do+ m <- getModSummary (moduleName mod)+ case ml_hs_file $ ms_location m of+ Nothing -> do dflags <- getDynFlags+ liftIO $ throwIO $ mkApiErr dflags (text "No source available for module " <+> ppr mod)+ Just sourceFile -> do+ source <- liftIO $ hGetStringBuffer sourceFile+ return (sourceFile, source, ms_hspp_opts m)+++-- | Return module source as token stream, including comments.+--+-- The module must be in the module graph and its source must be available.+-- Throws a 'HscTypes.SourceError' on parse error.+getTokenStream :: GhcMonad m => Module -> m [Located Token]+getTokenStream mod = do+ (sourceFile, source, flags) <- getModuleSourceAndFlags mod+ let startLoc = mkRealSrcLoc (mkFastString sourceFile) 1 1+ case lexTokenStream source startLoc flags of+ POk _ ts -> return ts+ PFailed span err ->+ do dflags <- getDynFlags+ liftIO $ throwIO $ mkSrcErr (unitBag $ mkPlainErrMsg dflags span err)++-- | Give even more information on the source than 'getTokenStream'+-- This function allows reconstructing the source completely with+-- 'showRichTokenStream'.+getRichTokenStream :: GhcMonad m => Module -> m [(Located Token, String)]+getRichTokenStream mod = do+ (sourceFile, source, flags) <- getModuleSourceAndFlags mod+ let startLoc = mkRealSrcLoc (mkFastString sourceFile) 1 1+ case lexTokenStream source startLoc flags of+ POk _ ts -> return $ addSourceToTokens startLoc source ts+ PFailed span err ->+ do dflags <- getDynFlags+ liftIO $ throwIO $ mkSrcErr (unitBag $ mkPlainErrMsg dflags span err)++-- | Given a source location and a StringBuffer corresponding to this+-- location, return a rich token stream with the source associated to the+-- tokens.+addSourceToTokens :: RealSrcLoc -> StringBuffer -> [Located Token]+ -> [(Located Token, String)]+addSourceToTokens _ _ [] = []+addSourceToTokens loc buf (t@(L span _) : ts)+ = case span of+ UnhelpfulSpan _ -> (t,"") : addSourceToTokens loc buf ts+ RealSrcSpan s -> (t,str) : addSourceToTokens newLoc newBuf ts+ where+ (newLoc, newBuf, str) = go "" loc buf+ start = realSrcSpanStart s+ end = realSrcSpanEnd s+ go acc loc buf | loc < start = go acc nLoc nBuf+ | start <= loc && loc < end = go (ch:acc) nLoc nBuf+ | otherwise = (loc, buf, reverse acc)+ where (ch, nBuf) = nextChar buf+ nLoc = advanceSrcLoc loc ch+++-- | Take a rich token stream such as produced from 'getRichTokenStream' and+-- return source code almost identical to the original code (except for+-- insignificant whitespace.)+showRichTokenStream :: [(Located Token, String)] -> String+showRichTokenStream ts = go startLoc ts ""+ where sourceFile = getFile $ map (getLoc . fst) ts+ getFile [] = panic "showRichTokenStream: No source file found"+ getFile (UnhelpfulSpan _ : xs) = getFile xs+ getFile (RealSrcSpan s : _) = srcSpanFile s+ startLoc = mkRealSrcLoc sourceFile 1 1+ go _ [] = id+ go loc ((L span _, str):ts)+ = case span of+ UnhelpfulSpan _ -> go loc ts+ RealSrcSpan s+ | locLine == tokLine -> ((replicate (tokCol - locCol) ' ') ++)+ . (str ++)+ . go tokEnd ts+ | otherwise -> ((replicate (tokLine - locLine) '\n') ++)+ . ((replicate (tokCol - 1) ' ') ++)+ . (str ++)+ . go tokEnd ts+ where (locLine, locCol) = (srcLocLine loc, srcLocCol loc)+ (tokLine, tokCol) = (srcSpanStartLine s, srcSpanStartCol s)+ tokEnd = realSrcSpanEnd s++-- -----------------------------------------------------------------------------+-- Interactive evaluation++-- | Takes a 'ModuleName' and possibly a 'UnitId', and consults the+-- 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+ let+ dflags = hsc_dflags hsc_env+ this_pkg = thisPackage dflags+ --+ case maybe_pkg of+ Just pkg | fsToUnitId pkg /= this_pkg && pkg /= fsLit "this" -> liftIO $ do+ res <- findImportedModule hsc_env mod_name maybe_pkg+ case res of+ Found _ m -> return m+ err -> throwOneError $ noModError dflags noSrcSpan mod_name err+ _otherwise -> do+ home <- lookupLoadedHomeModule mod_name+ case home of+ Just m -> return m+ Nothing -> liftIO $ do+ res <- findImportedModule hsc_env mod_name maybe_pkg+ case res of+ Found loc m | moduleUnitId m /= this_pkg -> return m+ | otherwise -> modNotLoadedError dflags m loc+ err -> throwOneError $ noModError dflags 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)))++-- | 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),+-- but 'lookupModule' will check to see whether the module can also be+-- found in a package, and if so, that package 'Module' will be+-- 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+ home <- lookupLoadedHomeModule mod_name+ case home of+ Just m -> return m+ Nothing -> liftIO $ do+ res <- findExposedPackageModule hsc_env mod_name Nothing+ case res of+ Found _ m -> return m+ err -> throwOneError $ noModError (hsc_dflags hsc_env) noSrcSpan mod_name err++lookupLoadedHomeModule :: GhcMonad m => ModuleName -> m (Maybe Module)+lookupLoadedHomeModule mod_name = withSession $ \hsc_env ->+ case lookupHpt (hsc_HPT hsc_env) mod_name of+ Just mod_info -> return (Just (mi_module (hm_iface mod_info)))+ _not_a_home_module -> return Nothing++-- | Check that a module is safe to import (according to Safe Haskell).+--+-- We return True to indicate the import is safe and False otherwise+-- although in the False case an error may be thrown first.+isModuleTrusted :: GhcMonad m => Module -> m Bool+isModuleTrusted m = withSession $ \hsc_env ->+ liftIO $ hscCheckSafe hsc_env m noSrcSpan++-- | Return if a module is trusted and the pkgs it depends on to be trusted.+moduleTrustReqs :: GhcMonad m => Module -> m (Bool, Set InstalledUnitId)+moduleTrustReqs m = withSession $ \hsc_env ->+ liftIO $ hscGetSafe hsc_env m noSrcSpan++-- | Set the monad GHCi lifts user statements into.+--+-- Checks that a type (in string form) is an instance of the+-- @GHC.GHCi.GHCiSandboxIO@ type class. Sets it to be the GHCi monad if it is,+-- throws an error otherwise.+setGHCiMonad :: GhcMonad m => String -> m ()+setGHCiMonad name = withSession $ \hsc_env -> do+ ty <- liftIO $ hscIsGHCiMonad hsc_env name+ modifySession $ \s ->+ let ic = (hsc_IC s) { ic_monad = ty }+ in s { hsc_IC = ic }++-- | Get the monad GHCi lifts user statements into.+getGHCiMonad :: GhcMonad m => m Name+getGHCiMonad = fmap (ic_monad . hsc_IC) getSession++getHistorySpan :: GhcMonad m => History -> m SrcSpan+getHistorySpan h = withSession $ \hsc_env ->+ return $ InteractiveEval.getHistorySpan hsc_env h++obtainTermFromVal :: GhcMonad m => Int -> Bool -> Type -> a -> m Term+obtainTermFromVal bound force ty a = withSession $ \hsc_env ->+ liftIO $ InteractiveEval.obtainTermFromVal hsc_env bound force ty a++obtainTermFromId :: GhcMonad m => Int -> Bool -> Id -> m Term+obtainTermFromId bound force id = withSession $ \hsc_env ->+ liftIO $ InteractiveEval.obtainTermFromId hsc_env bound force id+++-- | Returns the 'TyThing' for a 'Name'. The 'Name' may refer to any+-- entity known to GHC, including 'Name's defined using 'runStmt'.+lookupName :: GhcMonad m => Name -> m (Maybe TyThing)+lookupName name =+ withSession $ \hsc_env ->+ liftIO $ hscTcRcLookupName hsc_env name++-- -----------------------------------------------------------------------------+-- Pure API++-- | A pure interface to the module parser.+--+parser :: String -- ^ Haskell module source text (full Unicode is supported)+ -> DynFlags -- ^ the flags+ -> FilePath -- ^ the filename (for source locations)+ -> Either ErrorMessages (WarningMessages, Located (HsModule RdrName))++parser str dflags filename =+ let+ loc = mkRealSrcLoc (mkFastString filename) 1 1+ buf = stringToStringBuffer str+ in+ case unP Parser.parseModule (mkPState dflags buf loc) of++ PFailed span err ->+ Left (unitBag (mkPlainErrMsg dflags span err))++ POk pst rdr_module ->+ let (warns,_) = getMessages pst dflags in+ Right (warns, rdr_module)
+ main/GhcMake.hs view
@@ -0,0 +1,2258 @@+{-# LANGUAGE BangPatterns, CPP, NondecreasingIndentation, ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}+-- NB: we specifically ignore deprecations. GHC 7.6 marks the .QSem module as+-- deprecated, although it became un-deprecated later. As a result, using 7.6+-- as your bootstrap compiler throws annoying warnings.++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2011+--+-- This module implements multi-module compilation, and is used+-- by --make and GHCi.+--+-- -----------------------------------------------------------------------------+module GhcMake(+ depanal,+ load, load', LoadHowMuch(..),++ topSortModuleGraph,++ ms_home_srcimps, ms_home_imps,++ IsBoot(..),+ summariseModule,+ hscSourceToIsBoot,+ findExtraSigImports,+ implicitRequirements,++ noModError, cyclicModuleErr,+ moduleGraphNodes, SummaryNode+ ) where++#include "HsVersions.h"++import qualified Linker ( unload )++import DriverPhases+import DriverPipeline+import DynFlags+import ErrUtils+import Finder+import GhcMonad+import HeaderInfo+import HscTypes+import Module+import TcIface ( typecheckIface )+import TcRnMonad ( initIfaceCheck )+import HscMain++import Bag ( listToBag )+import BasicTypes+import Digraph+import Exception ( tryIO, gbracket, gfinally )+import FastString+import Maybes ( expectJust )+import Name+import MonadUtils ( allM, MonadIO )+import Outputable+import Panic+import SrcLoc+import StringBuffer+import SysTools+import UniqFM+import UniqDSet+import TcBackpack+import Packages+import UniqSet+import Util+import qualified GHC.LanguageExtensions as LangExt+import NameEnv++import Data.Either ( rights, partitionEithers )+import qualified Data.Map as Map+import Data.Map (Map)+import qualified Data.Set as Set+import qualified FiniteMap as Map ( insertListWith )++import Control.Concurrent ( forkIOWithUnmask, killThread )+import qualified GHC.Conc as CC+import Control.Concurrent.MVar+import Control.Concurrent.QSem+import Control.Exception+import Control.Monad+import Data.IORef+import Data.List+import qualified Data.List as List+import Data.Maybe+import Data.Ord ( comparing )+import Data.Time+import System.Directory+import System.FilePath+import System.IO ( fixIO )+import System.IO.Error ( isDoesNotExistError )++import GHC.Conc ( getNumProcessors, getNumCapabilities, setNumCapabilities )++label_self :: String -> IO ()+label_self thread_name = do+ self_tid <- CC.myThreadId+ CC.labelThread self_tid thread_name++-- -----------------------------------------------------------------------------+-- Loading the program++-- | Perform a dependency analysis starting from the current targets+-- and update the session with the new module graph.+--+-- Dependency analysis entails parsing the @import@ directives and may+-- therefore require running certain preprocessors.+--+-- Note that each 'ModSummary' in the module graph caches its 'DynFlags'.+-- These 'DynFlags' are determined by the /current/ session 'DynFlags' and the+-- @OPTIONS@ and @LANGUAGE@ pragmas of the parsed module. Thus if you want+-- changes to the 'DynFlags' to take effect you need to call this function+-- again.+--+depanal :: GhcMonad m =>+ [ModuleName] -- ^ excluded modules+ -> Bool -- ^ allow duplicate roots+ -> m ModuleGraph+depanal excluded_mods allow_dup_roots = do+ hsc_env <- getSession+ let+ dflags = hsc_dflags hsc_env+ targets = hsc_targets hsc_env+ old_graph = hsc_mod_graph hsc_env++ withTiming (pure dflags) (text "Chasing dependencies") (const ()) $ do+ liftIO $ debugTraceMsg dflags 2 (hcat [+ text "Chasing modules from: ",+ hcat (punctuate comma (map pprTarget targets))])++ mod_graphE <- liftIO $ downsweep hsc_env old_graph+ excluded_mods allow_dup_roots+ mod_graph <- reportImportErrors mod_graphE++ warnMissingHomeModules hsc_env mod_graph++ setSession hsc_env { hsc_mod_graph = mod_graph }+ return mod_graph++-- Note [Missing home modules]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Sometimes user doesn't want GHC to pick up modules, not explicitly listed+-- in a command line. For example, cabal may want to enable this warning+-- when building a library, so that GHC warns user about modules, not listed+-- neither in `exposed-modules`, nor in `other-modules`.+--+-- Here "home module" means a module, that doesn't come from an other package.+--+-- For example, if GHC is invoked with modules "A" and "B" as targets,+-- but "A" imports some other module "C", then GHC will issue a warning+-- about module "C" not being listed in a command line.+--+-- The warning in enabled by `-Wmissing-home-modules`. See Trac #13129+warnMissingHomeModules :: GhcMonad m => HscEnv -> ModuleGraph -> m ()+warnMissingHomeModules hsc_env mod_graph =+ when (wopt Opt_WarnMissingHomeModules dflags && not (null missing)) $+ logWarnings (listToBag [warn])+ where+ dflags = hsc_dflags hsc_env+ targets = map targetId (hsc_targets hsc_env)++ is_known_module mod = any (is_my_target mod) targets++ -- We need to be careful to handle the case where (possibly+ -- path-qualified) filenames (aka 'TargetFile') rather than module+ -- names are being passed on the GHC command-line.+ --+ -- For instance, `ghc --make src-exe/Main.hs` and+ -- `ghc --make -isrc-exe Main` are supposed to be equivalent.+ -- Note also that we can't always infer the associated module name+ -- directly from the filename argument. See Trac #13727.+ is_my_target mod (TargetModule name)+ = moduleName (ms_mod mod) == name+ is_my_target mod (TargetFile target_file _)+ | Just mod_file <- ml_hs_file (ms_location mod)+ = target_file == mod_file ||+ -- We can get a file target even if a module name was+ -- originally specified in a command line because it can+ -- be converted in guessTarget (by appending .hs/.lhs).+ -- So let's convert it back and compare with module name+ mkModuleName (fst $ splitExtension target_file)+ == moduleName (ms_mod mod)+ is_my_target _ _ = False++ missing = map (moduleName . ms_mod) $+ filter (not . is_known_module) mod_graph++ msg+ | gopt Opt_BuildingCabalPackage dflags+ = text "These modules are needed for compilation but not listed in your .cabal file's other-modules: "+ <> sep (map ppr missing)+ | otherwise+ = text "Modules are not listed in command line but needed for compilation: "+ <> sep (map ppr missing)+ warn = makeIntoWarning+ (Reason Opt_WarnMissingHomeModules)+ (mkPlainErrMsg dflags noSrcSpan msg)++-- | Describes which modules of the module graph need to be loaded.+data LoadHowMuch+ = LoadAllTargets+ -- ^ Load all targets and its dependencies.+ | LoadUpTo ModuleName+ -- ^ Load only the given module and its dependencies.+ | LoadDependenciesOf ModuleName+ -- ^ Load only the dependencies of the given module, but not the module+ -- itself.++-- | Try to load the program. See 'LoadHowMuch' for the different modes.+--+-- This function implements the core of GHC's @--make@ mode. It preprocesses,+-- compiles and loads the specified modules, avoiding re-compilation wherever+-- possible. Depending on the target (see 'DynFlags.hscTarget') compiling+-- and loading may result in files being created on disk.+--+-- Calls the 'defaultWarnErrLogger' after each compiling each module, whether+-- successful or not.+--+-- Throw a 'SourceError' if errors are encountered before the actual+-- compilation starts (e.g., during dependency analysis). All other errors+-- are reported using the 'defaultWarnErrLogger'.+--+load :: GhcMonad m => LoadHowMuch -> m SuccessFlag+load how_much = do+ mod_graph <- depanal [] False+ load' how_much (Just batchMsg) mod_graph++-- | 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+ 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++ -- The "bad" boot modules are the ones for which we have+ -- B.hs-boot in the module graph, but no B.hs+ -- The downsweep should have ensured this does not happen+ -- (see msDeps)+ let all_home_mods = [ms_mod_name s+ | s <- mod_graph, not (isBootSummary s)]+ -- TODO: Figure out what the correct form of this assert is. It's violated+ -- when you have HsBootMerge nodes in the graph: then you'll have hs-boot+ -- files without corresponding hs files.+ -- bad_boot_mods = [s | s <- mod_graph, isBootSummary s,+ -- not (ms_mod_name s `elem` all_home_mods)]+ -- ASSERT( null bad_boot_mods ) return ()++ -- check that the module given in HowMuch actually exists, otherwise+ -- topSortModuleGraph will bomb later.+ let checkHowMuch (LoadUpTo m) = checkMod m+ checkHowMuch (LoadDependenciesOf m) = checkMod m+ checkHowMuch _ = id++ checkMod m and_then+ | m `elem` all_home_mods = and_then+ | otherwise = do+ liftIO $ errorMsg dflags (text "no such module:" <+>+ quotes (ppr m))+ return Failed++ checkHowMuch how_much $ do++ -- mg2_with_srcimps drops the hi-boot nodes, returning a+ -- graph with cycles. Among other things, it is used for+ -- backing out partially complete cycles following a failed+ -- upsweep, and for removing from hpt all the modules+ -- not in strict downwards closure, during calls to compile.+ let mg2_with_srcimps :: [SCC ModSummary]+ mg2_with_srcimps = topSortModuleGraph True mod_graph Nothing++ -- If we can determine that any of the {-# SOURCE #-} imports+ -- are definitely unnecessary, then emit a warning.+ warnUnnecessarySourceImports mg2_with_srcimps++ let+ -- check the stability property for each module.+ stable_mods@(stable_obj,stable_bco)+ = checkStability hpt1 mg2_with_srcimps all_home_mods++ -- prune bits of the HPT which are definitely redundant now,+ -- to save space.+ pruned_hpt = pruneHomePackageTable hpt1+ (flattenSCCs mg2_with_srcimps)+ stable_mods++ _ <- 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 $ hsc_env { hsc_HPT = pruned_hpt }++ liftIO $ debugTraceMsg dflags 2 (text "Stable obj:" <+> ppr stable_obj $$+ text "Stable BCO:" <+> ppr stable_bco)++ -- Unload any modules which are going to be re-linked this time around.+ let stable_linkables = [ linkable+ | m <- stable_obj++stable_bco,+ Just hmi <- [lookupHpt pruned_hpt m],+ Just linkable <- [hm_linkable hmi] ]+ liftIO $ unload hsc_env stable_linkables++ -- We could at this point detect cycles which aren't broken by+ -- a source-import, and complain immediately, but it seems better+ -- to let upsweep_mods do this, so at least some useful work gets+ -- done before the upsweep is abandoned.+ --hPutStrLn stderr "after tsort:\n"+ --hPutStrLn stderr (showSDoc (vcat (map ppr mg2)))++ -- Now do the upsweep, calling compile for each module in+ -- turn. Final result is version 3 of everything.++ -- Topologically sort the module graph, this time including hi-boot+ -- nodes, and possibly just including the portion of the graph+ -- reachable from the module specified in the 2nd argument to load.+ -- This graph should be cycle-free.+ -- If we're restricting the upsweep to a portion of the graph, we+ -- also want to retain everything that is still stable.+ let full_mg :: [SCC ModSummary]+ full_mg = topSortModuleGraph False mod_graph Nothing++ maybe_top_mod = case how_much of+ LoadUpTo m -> Just m+ LoadDependenciesOf m -> Just m+ _ -> Nothing++ partial_mg0 :: [SCC ModSummary]+ partial_mg0 = topSortModuleGraph False mod_graph maybe_top_mod++ -- LoadDependenciesOf m: we want the upsweep to stop just+ -- short of the specified module (unless the specified module+ -- is stable).+ partial_mg+ | LoadDependenciesOf _mod <- how_much+ = ASSERT( case last partial_mg0 of+ AcyclicSCC ms -> ms_mod_name ms == _mod; _ -> False )+ List.init partial_mg0+ | otherwise+ = partial_mg0++ stable_mg =+ [ AcyclicSCC ms+ | AcyclicSCC ms <- full_mg,+ ms_mod_name ms `elem` stable_obj++stable_bco ]++ -- the modules from partial_mg that are not also stable+ -- NB. also keep cycles, we need to emit an error message later+ unstable_mg = filter not_stable partial_mg+ where not_stable (CyclicSCC _) = True+ not_stable (AcyclicSCC ms)+ = ms_mod_name ms `notElem` stable_obj++stable_bco++ -- Load all the stable modules first, before attempting to load+ -- an unstable module (#7231).+ mg = stable_mg ++ unstable_mg++ -- clean up between compilations+ let cleanup hsc_env = intermediateCleanTempFiles (hsc_dflags hsc_env)+ (flattenSCCs mg2_with_srcimps)+ hsc_env++ liftIO $ debugTraceMsg dflags 2 (hang (text "Ready for upsweep")+ 2 (ppr mg))++ n_jobs <- case parMakeCount dflags of+ Nothing -> liftIO getNumProcessors+ Just n -> return n+ let upsweep_fn | n_jobs > 1 = parUpsweep n_jobs+ | otherwise = upsweep++ setSession hsc_env{ hsc_HPT = emptyHomePackageTable }+ (upsweep_ok, modsUpswept)+ <- upsweep_fn mHscMessage pruned_hpt stable_mods cleanup mg++ -- Make modsDone be the summaries for each home module now+ -- available; this should equal the domain of hpt3.+ -- Get in in a roughly top .. bottom order (hence reverse).++ let modsDone = reverse modsUpswept++ -- Try and do linking in some form, depending on whether the+ -- upsweep was completely or only partially successful.++ if succeeded upsweep_ok++ then+ -- Easy; just relink it all.+ do liftIO $ debugTraceMsg dflags 2 (text "Upsweep completely successful.")++ -- Clean up after ourselves+ hsc_env1 <- getSession+ liftIO $ intermediateCleanTempFiles dflags modsDone hsc_env1++ -- Issue a warning for the confusing case where the user+ -- said '-o foo' but we're not going to do any linking.+ -- We attempt linking if either (a) one of the modules is+ -- 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 no_hs_main = gopt Opt_NoHsMain dflags+ let+ main_mod = mainModIs dflags+ a_root_is_Main = any ((==main_mod).ms_mod) mod_graph+ do_linking = a_root_is_Main || no_hs_main || ghcLink dflags == LinkDynLib || ghcLink dflags == LinkStaticLib++ -- link everything together+ linkresult <- liftIO $ link (ghcLink dflags) dflags do_linking (hsc_HPT hsc_env1)++ if ghcLink dflags == LinkBinary && isJust ofile && not do_linking+ then do+ liftIO $ errorMsg dflags $ text+ ("output was redirected with -o, " +++ "but no output will be generated\n" +++ "because there is no " +++ moduleNameString (moduleName main_mod) ++ " module.")+ -- This should be an error, not a warning (#10895).+ loadFinish Failed linkresult+ else+ loadFinish Succeeded linkresult++ else+ -- Tricky. We need to back out the effects of compiling any+ -- half-done cycles, both so as to clean up the top level envs+ -- and to avoid telling the interactive linker to link them.+ do liftIO $ debugTraceMsg dflags 2 (text "Upsweep partially successful.")++ let modsDone_names+ = map ms_mod modsDone+ let mods_to_zap_names+ = findPartiallyCompletedCycles modsDone_names+ mg2_with_srcimps+ let mods_to_keep+ = filter ((`Set.notMember` mods_to_zap_names).ms_mod)+ modsDone++ hsc_env1 <- getSession+ let hpt4 = retainInTopLevelEnvs (map ms_mod_name mods_to_keep)+ (hsc_HPT hsc_env1)++ -- Clean up after ourselves+ liftIO $ intermediateCleanTempFiles dflags mods_to_keep hsc_env1++ -- there should be no Nothings where linkables should be, now+ let just_linkables =+ isNoLink (ghcLink dflags)+ || allHpt (isJust.hm_linkable)+ (filterHpt ((== HsSrcFile).mi_hsc_src.hm_iface)+ hpt4)+ ASSERT( just_linkables ) do++ -- Link everything together+ linkresult <- liftIO $ link (ghcLink dflags) dflags False hpt4++ modifySession $ \hsc_env -> hsc_env{ hsc_HPT = hpt4 }+ loadFinish Failed linkresult+++-- | Finish up after a load.+loadFinish :: GhcMonad m => SuccessFlag -> SuccessFlag -> m SuccessFlag++-- If the link failed, unload everything and return.+loadFinish _all_ok Failed+ = do hsc_env <- getSession+ liftIO $ unload hsc_env []+ modifySession discardProg+ return Failed++-- Empty the interactive context and set the module context to the topmost+-- newly loaded module, or the Prelude if none were loaded.+loadFinish all_ok Succeeded+ = do modifySession discardIC+ return all_ok+++-- | Forget the current program, but retain the persistent info in HscEnv+discardProg :: HscEnv -> HscEnv+discardProg hsc_env+ = discardIC $ hsc_env { hsc_mod_graph = emptyMG+ , hsc_HPT = emptyHomePackageTable }++-- | Discard the contents of the InteractiveContext, but keep the DynFlags.+-- It will also keep ic_int_print and ic_monad if their names are from+-- external packages.+discardIC :: HscEnv -> HscEnv+discardIC hsc_env+ = hsc_env { hsc_IC = empty_ic { ic_int_print = new_ic_int_print+ , ic_monad = new_ic_monad } }+ where+ -- Force the new values for ic_int_print and ic_monad to avoid leaking old_ic+ !new_ic_int_print = keep_external_name ic_int_print+ !new_ic_monad = keep_external_name ic_monad+ dflags = ic_dflags old_ic+ old_ic = hsc_IC hsc_env+ empty_ic = emptyInteractiveContext dflags+ keep_external_name ic_name+ | nameIsFromExternalPackage this_pkg old_name = old_name+ | otherwise = ic_name empty_ic+ where+ this_pkg = thisPackage dflags+ old_name = ic_name old_ic++intermediateCleanTempFiles :: DynFlags -> [ModSummary] -> HscEnv -> IO ()+intermediateCleanTempFiles dflags summaries hsc_env+ = do notIntermediate <- readIORef (filesToNotIntermediateClean dflags)+ cleanTempFilesExcept dflags (notIntermediate ++ except)+ where+ except =+ -- Save preprocessed files. The preprocessed file *might* be+ -- the same as the source file, but that doesn't do any+ -- harm.+ map ms_hspp_file summaries +++ -- Save object files for loaded modules. The point of this+ -- is that we might have generated and compiled a stub C+ -- file, and in the case of GHCi the object file will be a+ -- temporary file which we must not remove because we need+ -- to load/link it later.+ hptObjs (hsc_HPT hsc_env)++-- | If there is no -o option, guess the name of target executable+-- by using top-level source file name as a base.+guessOutputFile :: GhcMonad m => m ()+guessOutputFile = modifySession $ \env ->+ let dflags = hsc_dflags env+ -- Force mod_graph to avoid leaking env+ !mod_graph = hsc_mod_graph env+ mainModuleSrcPath :: Maybe String+ mainModuleSrcPath = do+ let isMain = (== mainModIs dflags) . ms_mod+ [ms] <- return (filter isMain mod_graph)+ ml_hs_file (ms_location ms)+ name = fmap dropExtension mainModuleSrcPath++ name_exe = do+#if defined(mingw32_HOST_OS)+ -- 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 DriverPipeline.exeFileName. See #2248+ name' <- fmap (<.> "exe") name+#else+ name' <- name+#endif+ mainModuleSrcPath' <- mainModuleSrcPath+ -- #9930: don't clobber input files (unless they ask for it)+ if name' == mainModuleSrcPath'+ then throwGhcException . UsageError $+ "default output name would overwrite the input file; " +++ "must specify -o explicitly"+ else Just name'+ in+ case outputFile dflags of+ Just _ -> env+ Nothing -> env { hsc_dflags = dflags { outputFile = name_exe } }++-- -----------------------------------------------------------------------------+--+-- | Prune the HomePackageTable+--+-- Before doing an upsweep, we can throw away:+--+-- - For non-stable modules:+-- - all ModDetails, all linked code+-- - all unlinked code that is out of date with respect to+-- the source file+--+-- This is VERY IMPORTANT otherwise we'll end up requiring 2x the+-- 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+ -> [ModSummary]+ -> ([ModuleName],[ModuleName])+ -> HomePackageTable+pruneHomePackageTable hpt summ (stable_obj, stable_bco)+ = mapHpt prune hpt+ where prune hmi+ | is_stable modl = hmi'+ | otherwise = hmi'{ hm_details = emptyModDetails }+ where+ modl = moduleName (mi_module (hm_iface hmi))+ hmi' | Just l <- hm_linkable hmi, linkableTime l < ms_hs_date 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]++ is_stable m = m `elem` stable_obj || m `elem` stable_bco++-- -----------------------------------------------------------------------------+--+-- | Return (names of) all those in modsDone who are part of a cycle as defined+-- by theGraph.+findPartiallyCompletedCycles :: [Module] -> [SCC ModSummary] -> Set.Set Module+findPartiallyCompletedCycles modsDone theGraph+ = Set.unions+ [mods_in_this_cycle+ | CyclicSCC vs <- theGraph -- Acyclic? Not interesting.+ , let names_in_this_cycle = Set.fromList (map ms_mod vs)+ mods_in_this_cycle =+ Set.intersection (Set.fromList modsDone) names_in_this_cycle+ -- If size mods_in_this_cycle == size names_in_this_cycle,+ -- then this cycle has already been completed and we're not+ -- interested.+ , Set.size mods_in_this_cycle < Set.size names_in_this_cycle]+++-- ---------------------------------------------------------------------------+--+-- | Unloading+unload :: HscEnv -> [Linkable] -> IO ()+unload hsc_env stable_linkables -- Unload everthing *except* 'stable_linkables'+ = case ghcLink (hsc_dflags hsc_env) of+ LinkInMemory -> Linker.unload hsc_env stable_linkables+ _other -> return ()++-- -----------------------------------------------------------------------------+{- |++ Stability tells us which modules definitely do not need to be recompiled.+ There are two main reasons for having stability:++ - avoid doing a complete upsweep of the module graph in GHCi when+ modules near the bottom of the tree have not changed.++ - to tell GHCi when it can load object code: we can only load object code+ for a module when we also load object code fo all of the imports of the+ module. So we need to know that we will definitely not be recompiling+ any of these modules, and we can use the object code.++ The stability check is as follows. Both stableObject and+ stableBCO are used during the upsweep phase later.++@+ stable m = stableObject m || stableBCO m++ stableObject m =+ all stableObject (imports m)+ && old linkable does not exist, or is == on-disk .o+ && date(on-disk .o) > date(.hs)++ stableBCO m =+ all stable (imports m)+ && date(BCO) > date(.hs)+@++ These properties embody the following ideas:++ - if a module is stable, then:++ - if it has been compiled in a previous pass (present in HPT)+ then it does not need to be compiled or re-linked.++ - if it has not been compiled in a previous pass,+ then we only need to read its .hi file from disk and+ link it to produce a 'ModDetails'.++ - if a modules is not stable, we will definitely be at least+ re-linking, and possibly re-compiling it during the 'upsweep'.+ All non-stable modules can (and should) therefore be unlinked+ before the 'upsweep'.++ - Note that objects are only considered stable if they only depend+ on other objects. We can't link object code against byte code.++ - Note that even if an object is stable, we may end up recompiling+ if the interface is out of date because an *external* interface+ has changed. The current code in GhcMake handles this case+ fairly poorly, so be careful.+-}+checkStability+ :: HomePackageTable -- HPT from last compilation+ -> [SCC ModSummary] -- current module graph (cyclic)+ -> [ModuleName] -- all home modules+ -> ([ModuleName], -- stableObject+ [ModuleName]) -- stableBCO++checkStability hpt sccs all_home_mods = foldl checkSCC ([],[]) sccs+ where+ checkSCC (stable_obj, stable_bco) scc0+ | stableObjects = (scc_mods ++ stable_obj, stable_bco)+ | stableBCOs = (stable_obj, scc_mods ++ stable_bco)+ | otherwise = (stable_obj, stable_bco)+ where+ scc = flattenSCC scc0+ scc_mods = map ms_mod_name scc+ home_module m = m `elem` all_home_mods && m `notElem` scc_mods++ scc_allimps = nub (filter home_module (concatMap ms_home_allimps scc))+ -- all imports outside the current SCC, but in the home pkg++ stable_obj_imps = map (`elem` stable_obj) scc_allimps+ stable_bco_imps = map (`elem` stable_bco) scc_allimps++ stableObjects =+ and stable_obj_imps+ && all object_ok scc++ stableBCOs =+ and (zipWith (||) stable_obj_imps stable_bco_imps)+ && all bco_ok scc++ object_ok ms+ | gopt Opt_ForceRecomp (ms_hspp_opts ms) = False+ | Just t <- ms_obj_date ms = t >= ms_hs_date ms+ && same_as_prev t+ | otherwise = False+ where+ same_as_prev t = case lookupHpt hpt (ms_mod_name ms) of+ Just hmi | Just l <- hm_linkable hmi+ -> isObjectLinkable l && t == linkableTime l+ _other -> True+ -- why '>=' rather than '>' above? If the filesystem stores+ -- times to the nearset second, we may occasionally find that+ -- the object & source have the same modification time,+ -- especially if the source was automatically generated+ -- and compiled. Using >= is slightly unsafe, but it matches+ -- make's behaviour.+ --+ -- But see #5527, where someone ran into this and it caused+ -- a problem.++ bco_ok ms+ | gopt Opt_ForceRecomp (ms_hspp_opts ms) = False+ | otherwise = case lookupHpt hpt (ms_mod_name ms) of+ Just hmi | Just l <- hm_linkable hmi ->+ not (isObjectLinkable l) &&+ linkableTime l >= ms_hs_date ms+ _other -> False++{- Parallel Upsweep+ -+ - The parallel upsweep attempts to concurrently compile the modules in the+ - compilation graph using multiple Haskell threads.+ -+ - The Algorithm+ -+ - A Haskell thread is spawned for each module in the module graph, waiting for+ - its direct dependencies to finish building before it itself begins to build.+ -+ - Each module is associated with an initially empty MVar that stores the+ - result of that particular module's compile. If the compile succeeded, then+ - the HscEnv (synchronized by an MVar) is updated with the fresh HMI of that+ - module, and the module's HMI is deleted from the old HPT (synchronized by an+ - IORef) to save space.+ -+ - Instead of immediately outputting messages to the standard handles, all+ - compilation output is deferred to a per-module TQueue. A QSem is used to+ - limit the number of workers that are compiling simultaneously.+ -+ - Meanwhile, the main thread sequentially loops over all the modules in the+ - module graph, outputting the messages stored in each module's TQueue.+-}++-- | Each module is given a unique 'LogQueue' to redirect compilation messages+-- to. A 'Nothing' value contains the result of compilation, and denotes the+-- end of the message queue.+data LogQueue = LogQueue !(IORef [Maybe (WarnReason, Severity, SrcSpan, PprStyle, MsgDoc)])+ !(MVar ())++-- | The graph of modules to compile and their corresponding result 'MVar' and+-- 'LogQueue'.+type CompilationGraph = [(ModSummary, MVar SuccessFlag, LogQueue)]++-- | Build a 'CompilationGraph' out of a list of strongly-connected modules,+-- also returning the first, if any, encountered module cycle.+buildCompGraph :: [SCC ModSummary] -> IO (CompilationGraph, Maybe [ModSummary])+buildCompGraph [] = return ([], Nothing)+buildCompGraph (scc:sccs) = case scc of+ AcyclicSCC ms -> do+ mvar <- newEmptyMVar+ log_queue <- do+ ref <- newIORef []+ sem <- newEmptyMVar+ return (LogQueue ref sem)+ (rest,cycle) <- buildCompGraph sccs+ return ((ms,mvar,log_queue):rest, cycle)+ CyclicSCC mss -> return ([], Just mss)++-- A Module and whether it is a boot module.+type BuildModule = (Module, IsBoot)++-- | 'Bool' indicating if a module is a boot module or not. We need to treat+-- boot modules specially when building compilation graphs, since they break+-- cycles. Regular source files and signature files are treated equivalently.+data IsBoot = IsBoot | NotBoot+ deriving (Ord, Eq, Show, Read)++-- | Tests if an 'HscSource' is a boot file, primarily for constructing+-- elements of 'BuildModule'.+hscSourceToIsBoot :: HscSource -> IsBoot+hscSourceToIsBoot HsBootFile = IsBoot+hscSourceToIsBoot _ = NotBoot++mkBuildModule :: ModSummary -> BuildModule+mkBuildModule ms = (ms_mod ms, if isBootSummary ms then IsBoot else NotBoot)++-- | The entry point to the parallel upsweep.+--+-- See also the simpler, sequential 'upsweep'.+parUpsweep+ :: GhcMonad m+ => Int+ -- ^ The number of workers we wish to run in parallel+ -> Maybe Messager+ -> HomePackageTable+ -> ([ModuleName],[ModuleName])+ -> (HscEnv -> IO ())+ -> [SCC ModSummary]+ -> m (SuccessFlag,+ [ModSummary])+parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do+ hsc_env <- getSession+ let dflags = hsc_dflags hsc_env++ when (not (null (unitIdsToCheck dflags))) $+ throwGhcException (ProgramError "Backpack typechecking not supported with -j")++ -- The bits of shared state we'll be using:++ -- The global HscEnv is updated with the module's HMI when a module+ -- successfully compiles.+ hsc_env_var <- liftIO $ newMVar hsc_env++ -- The old HPT is used for recompilation checking in upsweep_mod. When a+ -- module successfully gets compiled, its HMI is pruned from the old HPT.+ old_hpt_var <- liftIO $ newIORef old_hpt++ -- What we use to limit parallelism with.+ par_sem <- liftIO $ newQSem n_jobs+++ let updNumCapabilities = liftIO $ do+ n_capabilities <- getNumCapabilities+ n_cpus <- getNumProcessors+ -- Setting number of capabilities more than+ -- CPU count usually leads to high userspace+ -- lock contention. Trac #9221+ let n_caps = min n_jobs n_cpus+ unless (n_capabilities /= 1) $ setNumCapabilities n_caps+ return n_capabilities+ -- Reset the number of capabilities once the upsweep ends.+ let resetNumCapabilities orig_n = liftIO $ setNumCapabilities orig_n++ gbracket updNumCapabilities resetNumCapabilities $ \_ -> do++ -- Sync the global session with the latest HscEnv once the upsweep ends.+ let finallySyncSession io = io `gfinally` do+ hsc_env <- liftIO $ readMVar hsc_env_var+ setSession hsc_env++ finallySyncSession $ do++ -- Build the compilation graph out of the list of SCCs. Module cycles are+ -- handled at the very end, after some useful work gets done. Note that+ -- this list is topologically sorted (by virtue of 'sccs' being sorted so).+ (comp_graph,cycle) <- liftIO $ buildCompGraph sccs+ let comp_graph_w_idx = zip comp_graph [1..]++ -- The list of all loops in the compilation graph.+ -- NB: For convenience, the last module of each loop (aka the module that+ -- finishes the loop) is prepended to the beginning of the loop.+ let comp_graph_loops = go (map fstOf3 (reverse comp_graph))+ where+ go [] = []+ go (ms:mss) | Just loop <- getModLoop ms (ms:mss)+ = map mkBuildModule (ms:loop) : go mss+ | otherwise+ = go mss++ -- Build a Map out of the compilation graph with which we can efficiently+ -- look up the result MVar associated with a particular home module.+ let home_mod_map :: Map BuildModule (MVar SuccessFlag, Int)+ home_mod_map =+ Map.fromList [ (mkBuildModule ms, (mvar, idx))+ | ((ms,mvar,_),idx) <- comp_graph_w_idx ]+++ liftIO $ label_self "main --make thread"+ -- For each module in the module graph, spawn a worker thread that will+ -- compile this module.+ let { spawnWorkers = forM comp_graph_w_idx $ \((mod,!mvar,!log_queue),!mod_idx) ->+ forkIOWithUnmask $ \unmask -> do+ liftIO $ label_self $ unwords+ [ "worker --make thread"+ , "for module"+ , show (moduleNameString (ms_mod_name mod))+ , "number"+ , show mod_idx+ ]+ -- Replace the default log_action with one that writes each+ -- message to the module's log_queue. The main thread will+ -- deal with synchronously printing these messages.+ --+ -- Use a local filesToClean var so that we can clean up+ -- intermediate files in a timely fashion (as soon as+ -- compilation for that module is finished) without having to+ -- worry about accidentally deleting a simultaneous compile's+ -- important files.+ lcl_files_to_clean <- newIORef []+ let lcl_dflags = dflags { log_action = parLogAction log_queue+ , filesToClean = lcl_files_to_clean }++ -- Unmask asynchronous exceptions and perform the thread-local+ -- work to compile the module (see parUpsweep_one).+ m_res <- try $ unmask $ prettyPrintGhcErrors lcl_dflags $+ parUpsweep_one mod home_mod_map comp_graph_loops+ lcl_dflags mHscMessage cleanup+ par_sem hsc_env_var old_hpt_var+ stable_mods mod_idx (length sccs)++ res <- case m_res of+ Right flag -> return flag+ Left exc -> do+ -- Don't print ThreadKilled exceptions: they are used+ -- to kill the worker thread in the event of a user+ -- interrupt, and the user doesn't have to be informed+ -- about that.+ when (fromException exc /= Just ThreadKilled)+ (errorMsg lcl_dflags (text (show exc)))+ return Failed++ -- Populate the result MVar.+ putMVar mvar res++ -- Write the end marker to the message queue, telling the main+ -- thread that it can stop waiting for messages from this+ -- particular compile.+ writeLogQueue log_queue Nothing++ -- Add the remaining files that weren't cleaned up to the+ -- global filesToClean ref, for cleanup later.+ files_kept <- readIORef (filesToClean lcl_dflags)+ addFilesToClean dflags files_kept+++ -- Kill all the workers, masking interrupts (since killThread is+ -- interruptible). XXX: This is not ideal.+ ; killWorkers = uninterruptibleMask_ . mapM_ killThread }+++ -- Spawn the workers, making sure to kill them later. Collect the results+ -- of each compile.+ results <- liftIO $ bracket spawnWorkers killWorkers $ \_ ->+ -- Loop over each module in the compilation graph in order, printing+ -- each message from its log_queue.+ forM comp_graph $ \(mod,mvar,log_queue) -> do+ printLogs dflags log_queue+ result <- readMVar mvar+ if succeeded result then return (Just mod) else return Nothing+++ -- Collect and return the ModSummaries of all the successful compiles.+ -- NB: Reverse this list to maintain output parity with the sequential upsweep.+ let ok_results = reverse (catMaybes results)++ -- Handle any cycle in the original compilation graph and return the result+ -- of the upsweep.+ case cycle of+ Just mss -> do+ liftIO $ fatalErrorMsg dflags (cyclicModuleErr mss)+ return (Failed,ok_results)+ Nothing -> do+ let success_flag = successIf (all isJust results)+ return (success_flag,ok_results)++ where+ writeLogQueue :: LogQueue -> Maybe (WarnReason,Severity,SrcSpan,PprStyle,MsgDoc) -> IO ()+ writeLogQueue (LogQueue ref sem) msg = do+ atomicModifyIORef' ref $ \msgs -> (msg:msgs,())+ _ <- tryPutMVar sem ()+ return ()++ -- The log_action callback that is used to synchronize messages from a+ -- worker thread.+ parLogAction :: LogQueue -> LogAction+ parLogAction log_queue _dflags !reason !severity !srcSpan !style !msg = do+ writeLogQueue log_queue (Just (reason,severity,srcSpan,style,msg))++ -- Print each message from the log_queue using the log_action from the+ -- session's DynFlags.+ printLogs :: DynFlags -> LogQueue -> IO ()+ printLogs !dflags (LogQueue ref sem) = read_msgs+ where read_msgs = do+ takeMVar sem+ msgs <- atomicModifyIORef' ref $ \xs -> ([], reverse xs)+ print_loop msgs++ print_loop [] = read_msgs+ print_loop (x:xs) = case x of+ Just (reason,severity,srcSpan,style,msg) -> do+ putLogMsg dflags reason severity srcSpan style msg+ print_loop xs+ -- Exit the loop once we encounter the end marker.+ Nothing -> return ()++-- The interruptible subset of the worker threads' work.+parUpsweep_one+ :: ModSummary+ -- ^ The module we wish to compile+ -> Map BuildModule (MVar SuccessFlag, Int)+ -- ^ The map of home modules and their result MVar+ -> [[BuildModule]]+ -- ^ The list of all module loops within the compilation graph.+ -> DynFlags+ -- ^ The thread-local DynFlags+ -> Maybe Messager+ -- ^ The messager+ -> (HscEnv -> IO ())+ -- ^ The callback for cleaning up intermediate files+ -> QSem+ -- ^ The semaphore for limiting the number of simultaneous compiles+ -> MVar HscEnv+ -- ^ The MVar that synchronizes updates to the global HscEnv+ -> IORef HomePackageTable+ -- ^ The old HPT+ -> ([ModuleName],[ModuleName])+ -- ^ Lists of stable objects and BCOs+ -> Int+ -- ^ The index of this module+ -> Int+ -- ^ The total number of modules+ -> IO SuccessFlag+ -- ^ The result of this compile+parUpsweep_one mod home_mod_map comp_graph_loops lcl_dflags mHscMessage cleanup par_sem+ hsc_env_var old_hpt_var stable_mods mod_index num_mods = do++ let this_build_mod = mkBuildModule mod++ let home_imps = map unLoc $ ms_home_imps mod+ let home_src_imps = map unLoc $ ms_home_srcimps mod++ -- All the textual imports of this module.+ let textual_deps = Set.fromList $ mapFst (mkModule (thisPackage lcl_dflags)) $+ zip home_imps (repeat NotBoot) +++ zip home_src_imps (repeat IsBoot)++ -- Dealing with module loops+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~+ --+ -- Not only do we have to deal with explicit textual dependencies, we also+ -- have to deal with implicit dependencies introduced by import cycles that+ -- are broken by an hs-boot file. We have to ensure that:+ --+ -- 1. A module that breaks a loop must depend on all the modules in the+ -- loop (transitively or otherwise). This is normally always fulfilled+ -- by the module's textual dependencies except in degenerate loops,+ -- e.g.:+ --+ -- A.hs imports B.hs-boot+ -- B.hs doesn't import A.hs+ -- C.hs imports A.hs, B.hs+ --+ -- In this scenario, getModLoop will detect the module loop [A,B] but+ -- the loop finisher B doesn't depend on A. So we have to explicitly add+ -- A in as a dependency of B when we are compiling B.+ --+ -- 2. A module that depends on a module in an external loop can't proceed+ -- until the entire loop is re-typechecked.+ --+ -- These two invariants have to be maintained to correctly build a+ -- compilation graph with one or more loops.+++ -- The loop that this module will finish. After this module successfully+ -- compiles, this loop is going to get re-typechecked.+ let finish_loop = listToMaybe+ [ tail loop | loop <- comp_graph_loops+ , head loop == this_build_mod ]++ -- If this module finishes a loop then it must depend on all the other+ -- modules in that loop because the entire module loop is going to be+ -- re-typechecked once this module gets compiled. These extra dependencies+ -- are this module's "internal" loop dependencies, because this module is+ -- inside the loop in question.+ let int_loop_deps = Set.fromList $+ case finish_loop of+ Nothing -> []+ Just loop -> filter (/= this_build_mod) loop++ -- If this module depends on a module within a loop then it must wait for+ -- that loop to get re-typechecked, i.e. it must wait on the module that+ -- finishes that loop. These extra dependencies are this module's+ -- "external" loop dependencies, because this module is outside of the+ -- loop(s) in question.+ let ext_loop_deps = Set.fromList+ [ head loop | loop <- comp_graph_loops+ , any (`Set.member` textual_deps) loop+ , this_build_mod `notElem` loop ]+++ let all_deps = foldl1 Set.union [textual_deps, int_loop_deps, ext_loop_deps]++ -- All of the module's home-module dependencies.+ let home_deps_with_idx =+ [ home_dep | dep <- Set.toList all_deps+ , Just home_dep <- [Map.lookup dep home_mod_map] ]++ -- Sort the list of dependencies in reverse-topological order. This way, by+ -- the time we get woken up by the result of an earlier dependency,+ -- subsequent dependencies are more likely to have finished. This step+ -- effectively reduces the number of MVars that each thread blocks on.+ let home_deps = map fst $ sortBy (flip (comparing snd)) home_deps_with_idx++ -- Wait for the all the module's dependencies to finish building.+ deps_ok <- allM (fmap succeeded . readMVar) home_deps++ -- We can't build this module if any of its dependencies failed to build.+ if not deps_ok+ then return Failed+ else do+ -- Any hsc_env at this point is OK to use since we only really require+ -- that the HPT contains the HMIs of our dependencies.+ hsc_env <- readMVar hsc_env_var+ old_hpt <- readIORef old_hpt_var++ let logger err = printBagOfErrors lcl_dflags (srcErrorMessages err)++ -- Limit the number of parallel compiles.+ let withSem sem = bracket_ (waitQSem sem) (signalQSem sem)+ mb_mod_info <- withSem par_sem $+ handleSourceError (\err -> do logger err; return Nothing) $ do+ -- Have the ModSummary and HscEnv point to our local log_action+ -- and filesToClean var.+ let lcl_mod = localize_mod mod+ let lcl_hsc_env = localize_hsc_env hsc_env++ -- Re-typecheck the loop+ -- This is necessary to make sure the knot is tied when+ -- we close a recursive module loop, see bug #12035.+ type_env_var <- liftIO $ newIORef emptyNameEnv+ let lcl_hsc_env' = lcl_hsc_env { hsc_type_env_var =+ Just (ms_mod lcl_mod, type_env_var) }+ lcl_hsc_env'' <- case finish_loop of+ Nothing -> return lcl_hsc_env'+ Just loop -> typecheckLoop lcl_dflags lcl_hsc_env' $+ map (moduleName . fst) loop++ -- Compile the module.+ mod_info <- upsweep_mod lcl_hsc_env'' mHscMessage old_hpt stable_mods+ lcl_mod mod_index num_mods+ return (Just mod_info)++ case mb_mod_info of+ Nothing -> return Failed+ Just mod_info -> do+ let this_mod = ms_mod_name mod++ -- Prune the old HPT unless this is an hs-boot module.+ unless (isBootSummary mod) $+ atomicModifyIORef' old_hpt_var $ \old_hpt ->+ (delFromHpt old_hpt this_mod, ())++ -- Update and fetch the global HscEnv.+ lcl_hsc_env' <- modifyMVar hsc_env_var $ \hsc_env -> do+ let hsc_env' = hsc_env+ { hsc_HPT = addToHpt (hsc_HPT hsc_env)+ this_mod mod_info }+ -- If this module is a loop finisher, now is the time to+ -- re-typecheck the loop.+ hsc_env'' <- case finish_loop of+ Nothing -> return hsc_env'+ Just loop -> typecheckLoop lcl_dflags hsc_env' $+ map (moduleName . fst) loop+ return (hsc_env'', localize_hsc_env hsc_env'')++ -- Clean up any intermediate files.+ cleanup lcl_hsc_env'+ return Succeeded++ where+ localize_mod mod+ = mod { ms_hspp_opts = (ms_hspp_opts mod)+ { log_action = log_action lcl_dflags+ , filesToClean = filesToClean lcl_dflags } }++ localize_hsc_env hsc_env+ = hsc_env { hsc_dflags = (hsc_dflags hsc_env)+ { log_action = log_action lcl_dflags+ , filesToClean = filesToClean lcl_dflags } }++-- -----------------------------------------------------------------------------+--+-- | The upsweep+--+-- This is where we compile each module in the module graph, in a pass+-- from the bottom to the top of the graph.+--+-- There better had not be any cyclic groups here -- we check for them.+upsweep+ :: GhcMonad m+ => Maybe Messager+ -> HomePackageTable -- ^ HPT from last time round (pruned)+ -> ([ModuleName],[ModuleName]) -- ^ stable modules (see checkStability)+ -> (HscEnv -> IO ()) -- ^ How to clean up unwanted tmp files+ -> [SCC ModSummary] -- ^ Mods to do (the worklist)+ -> m (SuccessFlag,+ [ModSummary])+ -- ^ Returns:+ --+ -- 1. A flag whether the complete upsweep was successful.+ -- 2. The 'HscEnv' in the monad has an updated HPT+ -- 3. A list of modules which succeeded loading.++upsweep mHscMessage old_hpt stable_mods cleanup sccs = do+ dflags <- getSessionDynFlags+ (res, done) <- upsweep' old_hpt [] sccs 1 (length sccs)+ (unitIdsToCheck dflags) done_holes+ return (res, reverse done)+ where+ done_holes = emptyUniqSet++ upsweep' _old_hpt done+ [] _ _ uids_to_check _+ = do hsc_env <- getSession+ liftIO . runHsc hsc_env $ mapM_ (ioMsgMaybe . tcRnCheckUnitId hsc_env) uids_to_check+ return (Succeeded, done)++ upsweep' _old_hpt done+ (CyclicSCC ms:_) _ _ _ _+ = do dflags <- getSessionDynFlags+ liftIO $ fatalErrorMsg dflags (cyclicModuleErr ms)+ return (Failed, done)++ upsweep' old_hpt done+ (AcyclicSCC mod:mods) mod_index nmods uids_to_check done_holes+ = do -- putStrLn ("UPSWEEP_MOD: hpt = " +++ -- show (map (moduleUserString.moduleName.mi_module.hm_iface)+ -- (moduleEnvElts (hsc_HPT hsc_env)))+ let logger _mod = defaultWarnErrLogger++ hsc_env <- getSession++ -- TODO: Cache this, so that we don't repeatedly re-check+ -- our imports when you run --make.+ let (ready_uids, uids_to_check')+ = partition (\uid -> isEmptyUniqDSet+ (unitIdFreeHoles uid `uniqDSetMinusUniqSet` done_holes))+ uids_to_check+ done_holes'+ | ms_hsc_src mod == HsigFile+ = addOneToUniqSet done_holes (ms_mod_name mod)+ | otherwise = done_holes+ liftIO . runHsc hsc_env $ mapM_ (ioMsgMaybe . tcRnCheckUnitId hsc_env) ready_uids++ -- Remove unwanted tmp files between compilations+ liftIO (cleanup hsc_env)++ -- Get ready to tie the knot+ type_env_var <- liftIO $ newIORef emptyNameEnv+ let hsc_env1 = hsc_env { hsc_type_env_var =+ Just (ms_mod mod, type_env_var) }+ setSession hsc_env1++ -- Lazily reload the HPT modules participating in the loop.+ -- See Note [Tying the knot]--if we don't throw out the old HPT+ -- and reinitalize the knot-tying process, anything that was forced+ -- while we were previously typechecking won't get updated, this+ -- was bug #12035.+ hsc_env2 <- liftIO $ reTypecheckLoop hsc_env1 mod done+ setSession hsc_env2++ mb_mod_info+ <- handleSourceError+ (\err -> do logger mod (Just err); return Nothing) $ do+ mod_info <- liftIO $ upsweep_mod hsc_env2 mHscMessage old_hpt stable_mods+ mod mod_index nmods+ logger mod Nothing -- log warnings+ return (Just mod_info)++ case mb_mod_info of+ Nothing -> return (Failed, done)+ Just mod_info -> do+ let this_mod = ms_mod_name mod++ -- Add new info to hsc_env+ hpt1 = addToHpt (hsc_HPT hsc_env2) this_mod mod_info+ hsc_env3 = hsc_env2 { hsc_HPT = hpt1, hsc_type_env_var = Nothing }++ -- Space-saving: delete the old HPT entry+ -- for mod BUT if mod is a hs-boot+ -- node, don't delete it. For the+ -- interface, the HPT entry is probaby for the+ -- main Haskell source file. Deleting it+ -- would force the real module to be recompiled+ -- every time.+ old_hpt1 | isBootSummary mod = old_hpt+ | otherwise = delFromHpt old_hpt this_mod++ done' = mod:done++ -- fixup our HomePackageTable after we've finished compiling+ -- a mutually-recursive loop. We have to do this again+ -- to make sure we have the final unfoldings, which may+ -- not have been computed accurately in the previous+ -- retypecheck.+ hsc_env4 <- liftIO $ reTypecheckLoop hsc_env3 mod done'+ setSession hsc_env4++ -- Add any necessary entries to the static pointer+ -- table. See Note [Grand plan for static forms] in+ -- StaticPtrTable.+ when (hscTarget (hsc_dflags hsc_env4) == HscInterpreted) $+ liftIO $ hscAddSptEntries hsc_env4+ [ spt+ | Just linkable <- pure $ hm_linkable mod_info+ , unlinked <- linkableUnlinked linkable+ , BCOs _ spts <- pure unlinked+ , spt <- spts+ ]++ upsweep' old_hpt1 done' mods (mod_index+1) nmods uids_to_check' done_holes'++unitIdsToCheck :: DynFlags -> [UnitId]+unitIdsToCheck dflags =+ nubSort $ concatMap goUnitId (explicitPackages (pkgState dflags))+ where+ goUnitId uid =+ case splitUnitIdInsts uid of+ (_, Just indef) ->+ let insts = indefUnitIdInsts indef+ in uid : concatMap (goUnitId . moduleUnitId . snd) insts+ _ -> []++maybeGetIfaceDate :: DynFlags -> ModLocation -> IO (Maybe UTCTime)+maybeGetIfaceDate dflags location+ | writeInterfaceOnlyMode dflags+ -- Minor optimization: it should be harmless to check the hi file location+ -- always, but it's better to avoid hitting the filesystem if possible.+ = modificationTimeIfExists (ml_hi_file location)+ | otherwise+ = return Nothing++-- | Compile a single module. Always produce a Linkable for it if+-- successful. If no compilation happened, return the old Linkable.+upsweep_mod :: HscEnv+ -> Maybe Messager+ -> HomePackageTable+ -> ([ModuleName],[ModuleName])+ -> ModSummary+ -> Int -- index of module+ -> Int -- total number of modules+ -> IO HomeModInfo+upsweep_mod hsc_env mHscMessage old_hpt (stable_obj, stable_bco) summary mod_index nmods+ = let+ this_mod_name = ms_mod_name summary+ this_mod = ms_mod summary+ mb_obj_date = ms_obj_date summary+ mb_if_date = ms_iface_date summary+ obj_fn = ml_obj_file (ms_location summary)+ hs_date = ms_hs_date summary++ is_stable_obj = this_mod_name `elem` stable_obj+ is_stable_bco = this_mod_name `elem` stable_bco++ old_hmi = lookupHpt old_hpt this_mod_name++ -- We're using the dflags for this module now, obtained by+ -- applying any options in its LANGUAGE & OPTIONS_GHC pragmas.+ dflags = ms_hspp_opts summary+ prevailing_target = hscTarget (hsc_dflags hsc_env)+ local_target = hscTarget dflags++ -- If OPTIONS_GHC contains -fasm or -fllvm, be careful that+ -- we don't do anything dodgy: these should only work to change+ -- from -fllvm to -fasm and vice-versa, otherwise we could+ -- end up trying to link object code to byte code.+ target = if prevailing_target /= local_target+ && (not (isObjectTarget prevailing_target)+ || not (isObjectTarget local_target))+ then prevailing_target+ else local_target++ -- store the corrected hscTarget into the summary+ summary' = summary{ ms_hspp_opts = dflags { hscTarget = target } }++ -- 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 -> Just iface+ | not (mi_boot iface) -> Just iface+ | otherwise -> Nothing+ where+ iface = hm_iface hm_info++ compile_it :: Maybe Linkable -> SourceModified -> IO HomeModInfo+ compile_it mb_linkable src_modified =+ compileOne' Nothing mHscMessage hsc_env summary' mod_index nmods+ mb_old_iface mb_linkable src_modified++ compile_it_discard_iface :: Maybe Linkable -> SourceModified+ -> IO HomeModInfo+ compile_it_discard_iface mb_linkable src_modified =+ compileOne' Nothing mHscMessage hsc_env summary' mod_index nmods+ Nothing mb_linkable src_modified++ -- With the HscNothing target we create empty linkables to avoid+ -- recompilation. We have to detect these to recompile anyway if+ -- the target changed since the last compile.+ is_fake_linkable+ | Just hmi <- old_hmi, Just l <- hm_linkable hmi =+ null (linkableUnlinked l)+ | otherwise =+ -- we have no linkable, so it cannot be fake+ False++ implies False _ = True+ implies True x = x++ in+ case () of+ _+ -- Regardless of whether we're generating object code or+ -- byte code, we can always use an existing object file+ -- if it is *stable* (see checkStability).+ | is_stable_obj, Just hmi <- old_hmi -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "skipping stable obj mod:" <+> ppr this_mod_name)+ return hmi+ -- object is stable, and we have an entry in the+ -- old HPT: nothing to do++ | is_stable_obj, isNothing old_hmi -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "compiling stable on-disk mod:" <+> ppr this_mod_name)+ linkable <- liftIO $ findObjectLinkable this_mod obj_fn+ (expectJust "upsweep1" mb_obj_date)+ compile_it (Just linkable) SourceUnmodifiedAndStable+ -- object is stable, but we need to load the interface+ -- off disk to make a HMI.++ | not (isObjectTarget target), is_stable_bco,+ (target /= HscNothing) `implies` not is_fake_linkable ->+ ASSERT(isJust old_hmi) -- must be in the old_hpt+ let Just hmi = old_hmi in do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "skipping stable BCO mod:" <+> ppr this_mod_name)+ return hmi+ -- BCO is stable: nothing to do++ | not (isObjectTarget target),+ Just hmi <- old_hmi,+ Just l <- hm_linkable hmi,+ not (isObjectLinkable l),+ (target /= HscNothing) `implies` not is_fake_linkable,+ linkableTime l >= ms_hs_date summary -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "compiling non-stable BCO mod:" <+> ppr this_mod_name)+ compile_it (Just l) SourceUnmodified+ -- we have an old BCO that is up to date with respect+ -- to the source: do a recompilation check as normal.++ -- When generating object code, if there's an up-to-date+ -- object file on the disk, then we can use it.+ -- However, if the object file is new (compared to any+ -- linkable we had from a previous compilation), then we+ -- must discard any in-memory interface, because this+ -- means the user has compiled the source file+ -- separately and generated a new interface, that we must+ -- read from the disk.+ --+ | isObjectTarget target,+ Just obj_date <- mb_obj_date,+ obj_date >= hs_date -> do+ case old_hmi of+ Just hmi+ | Just l <- hm_linkable hmi,+ isObjectLinkable l && linkableTime l == obj_date -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "compiling mod with new on-disk obj:" <+> ppr this_mod_name)+ compile_it (Just l) SourceUnmodified+ _otherwise -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "compiling mod with new on-disk obj2:" <+> ppr this_mod_name)+ linkable <- liftIO $ findObjectLinkable this_mod obj_fn obj_date+ compile_it_discard_iface (Just linkable) SourceUnmodified++ -- See Note [Recompilation checking when typechecking only]+ | writeInterfaceOnlyMode dflags,+ Just if_date <- mb_if_date,+ if_date >= hs_date -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "skipping tc'd mod:" <+> ppr this_mod_name)+ compile_it Nothing SourceUnmodified++ _otherwise -> do+ liftIO $ debugTraceMsg (hsc_dflags hsc_env) 5+ (text "compiling mod:" <+> ppr this_mod_name)+ compile_it Nothing SourceModified++-- Note [Recompilation checking when typechecking only]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- If we are compiling with -fno-code -fwrite-interface, there won't+-- be any object code that we can compare against, nor should there+-- be: we're *just* generating interface files. In this case, we+-- want to check if the interface file is new, in lieu of the object+-- file. See also Trac #9243.+++-- Filter modules in the HPT+retainInTopLevelEnvs :: [ModuleName] -> HomePackageTable -> HomePackageTable+retainInTopLevelEnvs keep_these hpt+ = listToHpt [ (mod, expectJust "retain" mb_mod_info)+ | mod <- keep_these+ , let mb_mod_info = lookupHpt hpt mod+ , isJust mb_mod_info ]++-- ---------------------------------------------------------------------------+-- Typecheck module loops+{-+See bug #930. This code fixes a long-standing bug in --make. The+problem is that when compiling the modules *inside* a loop, a data+type that is only defined at the top of the loop looks opaque; but+after the loop is done, the structure of the data type becomes+apparent.++The difficulty is then that two different bits of code have+different notions of what the data type looks like.++The idea is that after we compile a module which also has an .hs-boot+file, we re-generate the ModDetails for each of the modules that+depends on the .hs-boot file, so that everyone points to the proper+TyCons, Ids etc. defined by the real module, not the boot module.+Fortunately re-generating a ModDetails from a ModIface is easy: the+function TcIface.typecheckIface does exactly that.++Picking the modules to re-typecheck is slightly tricky. Starting from+the module graph consisting of the modules that have already been+compiled, we reverse the edges (so they point from the imported module+to the importing module), and depth-first-search from the .hs-boot+node. This gives us all the modules that depend transitively on the+.hs-boot module, and those are exactly the modules that we need to+re-typecheck.++Following this fix, GHC can compile itself with --make -O2.+-}++reTypecheckLoop :: HscEnv -> ModSummary -> ModuleGraph -> IO HscEnv+reTypecheckLoop hsc_env ms graph+ | Just loop <- getModLoop ms graph+ -- SOME hs-boot files should still+ -- get used, just not the loop-closer.+ , let non_boot = filter (\l -> not (isBootSummary l &&+ ms_mod l == ms_mod ms)) loop+ = typecheckLoop (hsc_dflags hsc_env) hsc_env (map ms_mod_name non_boot)+ | otherwise+ = return hsc_env++getModLoop :: ModSummary -> ModuleGraph -> Maybe [ModSummary]+getModLoop ms graph+ | not (isBootSummary ms)+ , any (\m -> ms_mod m == this_mod && isBootSummary m) graph+ , let mss = reachableBackwards (ms_mod_name ms) graph+ = Just mss+ | otherwise+ = Nothing+ where+ this_mod = ms_mod ms++typecheckLoop :: DynFlags -> HscEnv -> [ModuleName] -> IO HscEnv+typecheckLoop dflags hsc_env mods = do+ debugTraceMsg dflags 2 $+ text "Re-typechecking loop: " <> ppr mods+ new_hpt <-+ fixIO $ \new_hpt -> do+ let new_hsc_env = hsc_env{ hsc_HPT = new_hpt }+ mds <- initIfaceCheck (text "typecheckLoop") new_hsc_env $+ mapM (typecheckIface . hm_iface) hmis+ let new_hpt = addListToHpt old_hpt+ (zip mods [ hmi{ hm_details = details }+ | (hmi,details) <- zip hmis mds ])+ return new_hpt+ return hsc_env{ hsc_HPT = new_hpt }+ where+ old_hpt = hsc_HPT hsc_env+ hmis = map (expectJust "typecheckLoop" . lookupHpt old_hpt) mods++reachableBackwards :: ModuleName -> [ModSummary] -> [ModSummary]+reachableBackwards mod summaries+ = [ ms | (ms,_,_) <- reachableG (transposeG graph) root ]+ where -- the rest just sets up the graph:+ (graph, lookup_node) = moduleGraphNodes False summaries+ root = expectJust "reachableBackwards" (lookup_node HsBootFile mod)++-- ---------------------------------------------------------------------------+--+-- | Topological sort of the module graph+topSortModuleGraph+ :: Bool+ -- ^ Drop hi-boot nodes? (see below)+ -> [ModSummary]+ -> Maybe ModuleName+ -- ^ Root module name. If @Nothing@, use the full graph.+ -> [SCC ModSummary]+-- ^ Calculate SCCs of the module graph, possibly dropping the hi-boot nodes+-- The resulting list of strongly-connected-components is in topologically+-- sorted order, starting with the module(s) at the bottom of the+-- dependency graph (ie compile them first) and ending with the ones at+-- the top.+--+-- Drop hi-boot nodes (first boolean arg)?+--+-- - @False@: treat the hi-boot summaries as nodes of the graph,+-- so the graph must be acyclic+--+-- - @True@: eliminate the hi-boot nodes, and instead pretend+-- the a source-import of Foo is an import of Foo+-- The resulting graph has no hi-boot nodes, but can be cyclic++topSortModuleGraph drop_hs_boot_nodes summaries mb_root_mod+ = map (fmap summaryNodeSummary) $ stronglyConnCompG initial_graph+ where+ -- stronglyConnCompG flips the original order, so if we reverse+ -- the summaries we get a stable topological sort.+ (graph, lookup_node) = moduleGraphNodes drop_hs_boot_nodes (reverse summaries)++ initial_graph = case mb_root_mod of+ Nothing -> graph+ Just root_mod ->+ -- restrict the graph to just those modules reachable from+ -- the specified module. We do this by building a graph with+ -- the full set of nodes, and determining the reachable set from+ -- the specified node.+ let root | Just node <- lookup_node HsSrcFile root_mod, graph `hasVertexG` node = node+ | otherwise = throwGhcException (ProgramError "module does not exist")+ in graphFromEdgedVerticesUniq (seq root (reachableG graph root))++type SummaryNode = (ModSummary, Int, [Int])++summaryNodeKey :: SummaryNode -> Int+summaryNodeKey (_, k, _) = k++summaryNodeSummary :: SummaryNode -> ModSummary+summaryNodeSummary (s, _, _) = s++moduleGraphNodes :: Bool -> [ModSummary]+ -> (Graph SummaryNode, HscSource -> ModuleName -> Maybe SummaryNode)+moduleGraphNodes drop_hs_boot_nodes summaries =+ (graphFromEdgedVerticesUniq nodes, lookup_node)+ where+ numbered_summaries = zip summaries [1..]++ lookup_node :: HscSource -> ModuleName -> Maybe SummaryNode+ lookup_node hs_src mod = Map.lookup (mod, hscSourceToIsBoot hs_src) node_map++ lookup_key :: HscSource -> ModuleName -> Maybe Int+ lookup_key hs_src mod = fmap summaryNodeKey (lookup_node hs_src mod)++ node_map :: NodeMap SummaryNode+ node_map = Map.fromList [ ((moduleName (ms_mod s),+ hscSourceToIsBoot (ms_hsc_src s)), node)+ | node@(s, _, _) <- nodes ]++ -- We use integers as the keys for the SCC algorithm+ nodes :: [SummaryNode]+ nodes = [ (s, key, out_keys)+ | (s, key) <- numbered_summaries+ -- Drop the hi-boot ones if told to do so+ , not (isBootSummary s && drop_hs_boot_nodes)+ , let out_keys = out_edge_keys hs_boot_key (map unLoc (ms_home_srcimps s)) +++ out_edge_keys HsSrcFile (map unLoc (ms_home_imps s)) +++ (-- see [boot-edges] below+ if drop_hs_boot_nodes || ms_hsc_src s == HsBootFile+ then []+ else case lookup_key HsBootFile (ms_mod_name s) of+ Nothing -> []+ Just k -> [k]) ]++ -- [boot-edges] if this is a .hs and there is an equivalent+ -- .hs-boot, add a link from the former to the latter. This+ -- has the effect of detecting bogus cases where the .hs-boot+ -- depends on the .hs, by introducing a cycle. Additionally,+ -- it ensures that we will always process the .hs-boot before+ -- the .hs, and so the HomePackageTable will always have the+ -- most up to date information.++ -- Drop hs-boot nodes by using HsSrcFile as the key+ hs_boot_key | drop_hs_boot_nodes = HsSrcFile+ | otherwise = HsBootFile++ out_edge_keys :: HscSource -> [ModuleName] -> [Int]+ out_edge_keys hi_boot ms = mapMaybe (lookup_key hi_boot) ms+ -- If we want keep_hi_boot_nodes, then we do lookup_key with+ -- IsBoot; else NotBoot++-- The nodes of the graph are keyed by (mod, is boot?) pairs+-- NB: hsig files show up as *normal* nodes (not boot!), since they don't+-- participate in cycles (for now)+type NodeKey = (ModuleName, IsBoot)+type NodeMap a = Map.Map NodeKey a++msKey :: ModSummary -> NodeKey+msKey (ModSummary { ms_mod = mod, ms_hsc_src = boot })+ = (moduleName mod, hscSourceToIsBoot boot)++mkNodeMap :: [ModSummary] -> NodeMap ModSummary+mkNodeMap summaries = Map.fromList [ (msKey s, s) | s <- summaries]++nodeMapElts :: NodeMap a -> [a]+nodeMapElts = Map.elems++-- | If there are {-# SOURCE #-} imports between strongly connected+-- components in the topological sort, then those imports can+-- definitely be replaced by ordinary non-SOURCE imports: if SOURCE+-- were necessary, then the edge would be part of a cycle.+warnUnnecessarySourceImports :: GhcMonad m => [SCC ModSummary] -> m ()+warnUnnecessarySourceImports sccs = do+ dflags <- getDynFlags+ when (wopt Opt_WarnUnusedImports dflags)+ (logWarnings (listToBag (concatMap (check dflags . flattenSCC) sccs)))+ where check dflags ms =+ let mods_in_this_cycle = map ms_mod_name ms in+ [ warn dflags i | m <- ms, i <- ms_home_srcimps m,+ unLoc i `notElem` mods_in_this_cycle ]++ warn :: DynFlags -> Located ModuleName -> WarnMsg+ warn dflags (L loc mod) =+ mkPlainErrMsg dflags loc+ (text "Warning: {-# SOURCE #-} unnecessary in import of "+ <+> quotes (ppr mod))+++reportImportErrors :: MonadIO m => [Either ErrMsg b] -> m [b]+reportImportErrors xs | null errs = return oks+ | otherwise = throwManyErrors errs+ where (errs, oks) = partitionEithers xs++throwManyErrors :: MonadIO m => [ErrMsg] -> m ab+throwManyErrors errs = liftIO $ throwIO $ mkSrcErr $ listToBag errs+++-----------------------------------------------------------------------------+--+-- | Downsweep (dependency analysis)+--+-- Chase downwards from the specified root set, returning summaries+-- for all home modules encountered. Only follow source-import+-- links.+--+-- We pass in the previous collection of summaries, which is used as a+-- cache to avoid recalculating a module summary if the source is+-- unchanged.+--+-- The returned list of [ModSummary] nodes has one node for each home-package+-- module, plus one for any hs-boot files. The imports of these nodes+-- are all there, including the imports of non-home-package modules.+downsweep :: HscEnv+ -> [ModSummary] -- Old summaries+ -> [ModuleName] -- Ignore dependencies on these; treat+ -- them as if they were package modules+ -> Bool -- True <=> allow multiple targets to have+ -- the same module name; this is+ -- very useful for ghc -M+ -> IO [Either ErrMsg ModSummary]+ -- The elts of [ModSummary] all have distinct+ -- (Modules, IsBoot) identifiers, unless the Bool is true+ -- in which case there can be repeats+downsweep hsc_env old_summaries excl_mods allow_dup_roots+ = do+ rootSummaries <- mapM getRootSummary roots+ rootSummariesOk <- reportImportErrors rootSummaries+ let root_map = mkRootMap rootSummariesOk+ checkDuplicates root_map+ summs <- loop (concatMap calcDeps rootSummariesOk) root_map+ return summs+ where+ calcDeps = msDeps++ dflags = hsc_dflags hsc_env+ roots = hsc_targets hsc_env++ old_summary_map :: NodeMap ModSummary+ old_summary_map = mkNodeMap old_summaries++ getRootSummary :: Target -> IO (Either ErrMsg ModSummary)+ getRootSummary (Target (TargetFile file mb_phase) obj_allowed maybe_buf)+ = do exists <- liftIO $ doesFileExist file+ if exists+ then Right `fmap` summariseFile hsc_env old_summaries file mb_phase+ obj_allowed maybe_buf+ else return $ Left $ mkPlainErrMsg dflags noSrcSpan $+ text "can't find file:" <+> text file+ getRootSummary (Target (TargetModule modl) obj_allowed maybe_buf)+ = do maybe_summary <- summariseModule hsc_env old_summary_map NotBoot+ (L rootLoc modl) obj_allowed+ maybe_buf excl_mods+ case maybe_summary of+ Nothing -> return $ Left $ moduleNotFoundErr dflags modl+ Just s -> return s++ rootLoc = mkGeneralSrcSpan (fsLit "<command line>")++ -- In a root module, the filename is allowed to diverge from the module+ -- name, so we have to check that there aren't multiple root files+ -- defining the same module (otherwise the duplicates will be silently+ -- ignored, leading to confusing behaviour).+ checkDuplicates :: NodeMap [Either ErrMsg ModSummary] -> IO ()+ checkDuplicates root_map+ | allow_dup_roots = return ()+ | null dup_roots = return ()+ | otherwise = liftIO $ multiRootsErr dflags (head dup_roots)+ where+ dup_roots :: [[ModSummary]] -- Each at least of length 2+ dup_roots = filterOut isSingleton $ map rights $ nodeMapElts root_map++ loop :: [(Located ModuleName,IsBoot)]+ -- Work list: process these modules+ -> NodeMap [Either ErrMsg ModSummary]+ -- Visited set; the range is a list because+ -- the roots can have the same module names+ -- if allow_dup_roots is True+ -> IO [Either ErrMsg ModSummary]+ -- The result includes the worklist, except+ -- for those mentioned in the visited set+ loop [] done = return (concat (nodeMapElts done))+ loop ((wanted_mod, is_boot) : ss) done+ | Just summs <- Map.lookup key done+ = if isSingleton summs then+ loop ss done+ else+ do { multiRootsErr dflags (rights summs); return [] }+ | otherwise+ = do mb_s <- summariseModule hsc_env old_summary_map+ is_boot wanted_mod True+ Nothing excl_mods+ case mb_s of+ Nothing -> loop ss done+ Just (Left e) -> loop ss (Map.insert key [Left e] done)+ Just (Right s)-> loop (calcDeps s ++ ss)+ (Map.insert key [Right s] done)+ where+ key = (unLoc wanted_mod, is_boot)++mkRootMap :: [ModSummary] -> NodeMap [Either ErrMsg ModSummary]+mkRootMap summaries = Map.insertListWith (flip (++))+ [ (msKey s, [Right s]) | s <- summaries ]+ Map.empty++-- | Returns the dependencies of the ModSummary s.+-- A wrinkle is that for a {-# SOURCE #-} import we return+-- *both* the hs-boot file+-- *and* the source file+-- as "dependencies". That ensures that the list of all relevant+-- modules always contains B.hs if it contains B.hs-boot.+-- Remember, this pass isn't doing the topological sort. It's+-- just gathering the list of all relevant ModSummaries+msDeps :: ModSummary -> [(Located ModuleName, IsBoot)]+msDeps s =+ concat [ [(m,IsBoot), (m,NotBoot)] | m <- ms_home_srcimps s ]+ ++ [ (m,NotBoot) | m <- ms_home_imps s ]++home_imps :: [(Maybe FastString, Located ModuleName)] -> [Located ModuleName]+home_imps imps = [ lmodname | (mb_pkg, lmodname) <- imps,+ isLocal mb_pkg ]+ where isLocal Nothing = True+ isLocal (Just pkg) | pkg == fsLit "this" = True -- "this" is special+ isLocal _ = False++ms_home_allimps :: ModSummary -> [ModuleName]+ms_home_allimps ms = map unLoc (ms_home_srcimps ms ++ ms_home_imps ms)++-- | Like 'ms_home_imps', but for SOURCE imports.+ms_home_srcimps :: ModSummary -> [Located ModuleName]+ms_home_srcimps = home_imps . ms_srcimps++-- | All of the (possibly) home module imports from a+-- 'ModSummary'; that is to say, each of these module names+-- could be a home import if an appropriately named file+-- existed. (This is in contrast to package qualified+-- imports, which are guaranteed not to be home imports.)+ms_home_imps :: ModSummary -> [Located ModuleName]+ms_home_imps = home_imps . ms_imps++-----------------------------------------------------------------------------+-- Summarising modules++-- We have two types of summarisation:+--+-- * Summarise a file. This is used for the root module(s) passed to+-- cmLoadModules. The file is read, and used to determine the root+-- module name. The module name may differ from the filename.+--+-- * Summarise a module. We are given a module name, and must provide+-- a summary. The finder is used to locate the file in which the module+-- resides.++summariseFile+ :: HscEnv+ -> [ModSummary] -- old summaries+ -> FilePath -- source file name+ -> Maybe Phase -- start phase+ -> Bool -- object code allowed?+ -> Maybe (StringBuffer,UTCTime)+ -> IO ModSummary++summariseFile hsc_env old_summaries file mb_phase obj_allowed maybe_buf+ -- we can use a cached summary if one is available and the+ -- source file hasn't changed, But we have to look up the summary+ -- by source file, rather than module name as we do in summarise.+ | Just old_summary <- findSummaryBySourceFile old_summaries file+ = do+ let location = ms_location old_summary+ dflags = hsc_dflags hsc_env++ src_timestamp <- get_src_timestamp+ -- The file exists; we checked in getRootSummary above.+ -- If it gets removed subsequently, then this+ -- getModificationUTCTime may fail, but that's the right+ -- behaviour.++ -- return the cached summary if the source didn't change+ if ms_hs_date old_summary == src_timestamp &&+ not (gopt Opt_ForceRecomp (hsc_dflags hsc_env))+ then do -- update the object-file timestamp+ obj_timestamp <-+ if isObjectTarget (hscTarget (hsc_dflags hsc_env))+ || obj_allowed -- bug #1205+ then liftIO $ getObjTimestamp location NotBoot+ else return Nothing+ hi_timestamp <- maybeGetIfaceDate dflags location+ return old_summary{ ms_obj_date = obj_timestamp+ , ms_iface_date = hi_timestamp }+ else+ new_summary src_timestamp++ | otherwise+ = do src_timestamp <- get_src_timestamp+ new_summary src_timestamp+ where+ get_src_timestamp = case maybe_buf of+ Just (_,t) -> return t+ Nothing -> liftIO $ getModificationUTCTime file+ -- getModificationUTCTime may fail++ new_summary src_timestamp = do+ let dflags = hsc_dflags hsc_env++ let hsc_src = if isHaskellSigFilename file then HsigFile else HsSrcFile++ (dflags', hspp_fn, buf)+ <- preprocessFile hsc_env file mb_phase maybe_buf++ (srcimps,the_imps, L _ mod_name) <- getImports dflags' buf hspp_fn file++ -- Make a ModLocation for this file+ location <- liftIO $ mkHomeModLocation dflags mod_name file++ -- 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+ mod <- liftIO $ addHomeModuleToFinder hsc_env mod_name location++ -- when the user asks to load a source file by name, we only+ -- use an object file if -fobject-code is on. See #1205.+ obj_timestamp <-+ if isObjectTarget (hscTarget (hsc_dflags hsc_env))+ || obj_allowed -- bug #1205+ then liftIO $ modificationTimeIfExists (ml_obj_file location)+ else return Nothing++ hi_timestamp <- maybeGetIfaceDate dflags location++ extra_sig_imports <- findExtraSigImports hsc_env hsc_src mod_name+ required_by_imports <- implicitRequirements hsc_env the_imps++ return (ModSummary { ms_mod = mod,+ ms_hsc_src = hsc_src,+ ms_location = location,+ ms_hspp_file = hspp_fn,+ ms_hspp_opts = dflags',+ ms_hspp_buf = Just buf,+ ms_parsed_mod = Nothing,+ ms_srcimps = srcimps,+ ms_textual_imps = the_imps ++ extra_sig_imports ++ required_by_imports,+ ms_hs_date = src_timestamp,+ ms_iface_date = hi_timestamp,+ ms_obj_date = obj_timestamp })++findSummaryBySourceFile :: [ModSummary] -> FilePath -> Maybe ModSummary+findSummaryBySourceFile summaries file+ = case [ ms | ms <- summaries, HsSrcFile <- [ms_hsc_src ms],+ expectJust "findSummaryBySourceFile" (ml_hs_file (ms_location ms)) == file ] of+ [] -> Nothing+ (x:_) -> Just x++-- Summarise a module, and pick up source and timestamp.+summariseModule+ :: HscEnv+ -> NodeMap ModSummary -- Map of old summaries+ -> IsBoot -- IsBoot <=> a {-# SOURCE #-} import+ -> Located ModuleName -- Imported module to be summarised+ -> Bool -- object code allowed?+ -> Maybe (StringBuffer, UTCTime)+ -> [ModuleName] -- Modules to exclude+ -> IO (Maybe (Either ErrMsg ModSummary)) -- Its new summary++summariseModule hsc_env old_summary_map is_boot (L loc wanted_mod)+ obj_allowed maybe_buf excl_mods+ | wanted_mod `elem` excl_mods+ = return Nothing++ | Just old_summary <- Map.lookup (wanted_mod, is_boot) old_summary_map+ = do -- Find its new timestamp; all the+ -- ModSummaries in the old map have valid ml_hs_files+ let location = ms_location old_summary+ src_fn = expectJust "summariseModule" (ml_hs_file location)++ -- check the modification time on the source file, and+ -- return the cached summary if it hasn't changed. If the+ -- file has disappeared, we need to call the Finder again.+ case maybe_buf of+ Just (_,t) -> check_timestamp old_summary location src_fn t+ Nothing -> do+ m <- tryIO (getModificationUTCTime src_fn)+ case m of+ Right t -> check_timestamp old_summary location src_fn t+ Left e | isDoesNotExistError e -> find_it+ | otherwise -> ioError e++ | otherwise = find_it+ where+ dflags = hsc_dflags hsc_env++ check_timestamp old_summary location src_fn src_timestamp+ | ms_hs_date old_summary == src_timestamp &&+ not (gopt Opt_ForceRecomp dflags) = do+ -- update the object-file timestamp+ obj_timestamp <-+ if isObjectTarget (hscTarget (hsc_dflags hsc_env))+ || obj_allowed -- bug #1205+ then getObjTimestamp location is_boot+ else return Nothing+ hi_timestamp <- maybeGetIfaceDate dflags location+ return (Just (Right old_summary{ ms_obj_date = obj_timestamp+ , ms_iface_date = hi_timestamp}))+ | otherwise =+ -- source changed: re-summarise.+ new_summary location (ms_mod old_summary) src_fn src_timestamp++ find_it = do+ -- Don't use the Finder's cache this time. If the module was+ -- previously a package module, it may have now appeared on the+ -- search path, so we want to consider it to be a home module. If+ -- the module was previously a home module, it may have moved.+ uncacheModule hsc_env wanted_mod+ found <- findImportedModule hsc_env wanted_mod Nothing+ case found of+ Found location mod+ | isJust (ml_hs_file location) ->+ -- Home package+ just_found location mod++ _ -> return Nothing+ -- Not found+ -- (If it is TRULY not found at all, we'll+ -- error when we actually try to compile)++ just_found location mod = do+ -- Adjust location to point to the hs-boot source file,+ -- hi file, object file, when is_boot says so+ let location' | IsBoot <- is_boot = addBootSuffixLocn location+ | otherwise = location+ src_fn = expectJust "summarise2" (ml_hs_file location')++ -- Check that it exists+ -- It might have been deleted since the Finder last found it+ maybe_t <- modificationTimeIfExists src_fn+ case maybe_t of+ Nothing -> return $ Just $ Left $ noHsFileErr dflags loc src_fn+ Just t -> new_summary location' mod src_fn t+++ new_summary location mod src_fn src_timestamp+ = do+ -- Preprocess the source file and get its imports+ -- The dflags' contains the OPTIONS pragmas+ (dflags', hspp_fn, buf) <- preprocessFile hsc_env src_fn Nothing maybe_buf+ (srcimps, the_imps, L mod_loc mod_name) <- getImports dflags' buf hspp_fn src_fn++ -- NB: Despite the fact that is_boot is a top-level parameter, we+ -- don't actually know coming into this function what the HscSource+ -- of the module in question is. This is because we may be processing+ -- this module because another module in the graph imported it: in this+ -- case, we know if it's a boot or not because of the {-# SOURCE #-}+ -- annotation, but we don't know if it's a signature or a regular+ -- module until we actually look it up on the filesystem.+ let hsc_src = case is_boot of+ IsBoot -> HsBootFile+ _ | isHaskellSigFilename src_fn -> HsigFile+ | otherwise -> HsSrcFile++ when (mod_name /= wanted_mod) $+ throwOneError $ mkPlainErrMsg dflags' mod_loc $+ text "File name does not match module name:"+ $$ text "Saw:" <+> quotes (ppr mod_name)+ $$ text "Expected:" <+> quotes (ppr wanted_mod)++ when (hsc_src == HsigFile && isNothing (lookup mod_name (thisUnitIdInsts dflags))) $+ let suggested_instantiated_with =+ hcat (punctuate comma $+ [ ppr k <> text "=" <> ppr v+ | (k,v) <- ((mod_name, mkHoleModule mod_name)+ : thisUnitIdInsts dflags)+ ])+ in throwOneError $ mkPlainErrMsg dflags' mod_loc $+ text "Unexpected signature:" <+> quotes (ppr mod_name)+ $$ if gopt Opt_BuildingCabalPackage dflags+ then parens (text "Try adding" <+> quotes (ppr mod_name)+ <+> text "to the"+ <+> quotes (text "signatures")+ <+> text "field in your Cabal file.")+ else parens (text "Try passing -instantiated-with=\"" <>+ suggested_instantiated_with <> text "\"" $$+ text "replacing <" <> ppr mod_name <> text "> as necessary.")++ -- Find the object timestamp, and return the summary+ obj_timestamp <-+ if isObjectTarget (hscTarget (hsc_dflags hsc_env))+ || obj_allowed -- bug #1205+ then getObjTimestamp location is_boot+ else return Nothing++ hi_timestamp <- maybeGetIfaceDate dflags location++ extra_sig_imports <- findExtraSigImports hsc_env hsc_src mod_name+ required_by_imports <- implicitRequirements hsc_env the_imps++ return (Just (Right (ModSummary { ms_mod = mod,+ ms_hsc_src = hsc_src,+ ms_location = location,+ ms_hspp_file = hspp_fn,+ ms_hspp_opts = dflags',+ ms_hspp_buf = Just buf,+ ms_parsed_mod = Nothing,+ ms_srcimps = srcimps,+ ms_textual_imps = the_imps ++ extra_sig_imports ++ required_by_imports,+ ms_hs_date = src_timestamp,+ ms_iface_date = hi_timestamp,+ ms_obj_date = obj_timestamp })))+++getObjTimestamp :: ModLocation -> IsBoot -> IO (Maybe UTCTime)+getObjTimestamp location is_boot+ = if is_boot == IsBoot then return Nothing+ else modificationTimeIfExists (ml_obj_file location)+++preprocessFile :: HscEnv+ -> FilePath+ -> Maybe Phase -- ^ Starting phase+ -> Maybe (StringBuffer,UTCTime)+ -> IO (DynFlags, FilePath, StringBuffer)+preprocessFile hsc_env src_fn mb_phase Nothing+ = do+ (dflags', hspp_fn) <- preprocess hsc_env (src_fn, mb_phase)+ buf <- hGetStringBuffer hspp_fn+ return (dflags', hspp_fn, buf)++preprocessFile hsc_env src_fn mb_phase (Just (buf, _time))+ = do+ let dflags = hsc_dflags hsc_env+ let local_opts = getOptions dflags buf src_fn++ (dflags', leftovers, warns)+ <- parseDynamicFilePragma dflags local_opts+ checkProcessArgsResult dflags leftovers+ handleFlagWarnings dflags' warns++ let needs_preprocessing+ | Just (Unlit _) <- mb_phase = True+ | Nothing <- mb_phase, Unlit _ <- startPhase src_fn = True+ -- note: local_opts is only required if there's no Unlit phase+ | xopt LangExt.Cpp dflags' = True+ | gopt Opt_Pp dflags' = True+ | otherwise = False++ when needs_preprocessing $+ throwGhcExceptionIO (ProgramError "buffer needs preprocesing; interactive check disabled")++ return (dflags', src_fn, buf)+++-----------------------------------------------------------------------------+-- Error messages+-----------------------------------------------------------------------------++noModError :: DynFlags -> SrcSpan -> ModuleName -> FindResult -> ErrMsg+-- ToDo: we don't have a proper line number for this error+noModError dflags loc wanted_mod err+ = mkPlainErrMsg dflags loc $ cannotFindModule dflags wanted_mod err++noHsFileErr :: DynFlags -> SrcSpan -> String -> ErrMsg+noHsFileErr dflags loc path+ = mkPlainErrMsg dflags loc $ text "Can't find" <+> text path++moduleNotFoundErr :: DynFlags -> ModuleName -> ErrMsg+moduleNotFoundErr dflags mod+ = mkPlainErrMsg dflags noSrcSpan $+ text "module" <+> quotes (ppr mod) <+> text "cannot be found locally"++multiRootsErr :: DynFlags -> [ModSummary] -> IO ()+multiRootsErr _ [] = panic "multiRootsErr"+multiRootsErr dflags summs@(summ1:_)+ = throwOneError $ mkPlainErrMsg dflags noSrcSpan $+ text "module" <+> quotes (ppr mod) <+>+ text "is defined in multiple files:" <+>+ sep (map text files)+ where+ mod = ms_mod summ1+ files = map (expectJust "checkDup" . ml_hs_file . ms_location) summs++cyclicModuleErr :: [ModSummary] -> SDoc+-- From a strongly connected component we find+-- a single cycle to report+cyclicModuleErr mss+ = ASSERT( not (null mss) )+ case findCycle graph of+ Nothing -> text "Unexpected non-cycle" <+> ppr mss+ Just path -> vcat [ text "Module imports form a cycle:"+ , nest 2 (show_path path) ]+ where+ graph :: [Node NodeKey ModSummary]+ graph = [(ms, msKey ms, get_deps ms) | ms <- mss]++ get_deps :: ModSummary -> [NodeKey]+ get_deps ms = ([ (unLoc m, IsBoot) | m <- ms_home_srcimps ms ] +++ [ (unLoc m, NotBoot) | m <- ms_home_imps ms ])++ show_path [] = panic "show_path"+ show_path [m] = text "module" <+> ppr_ms m+ <+> text "imports itself"+ show_path (m1:m2:ms) = vcat ( nest 7 (text "module" <+> ppr_ms m1)+ : nest 6 (text "imports" <+> ppr_ms m2)+ : go ms )+ where+ go [] = [text "which imports" <+> ppr_ms m1]+ go (m:ms) = (text "which imports" <+> ppr_ms m) : go ms+++ ppr_ms :: ModSummary -> SDoc+ ppr_ms ms = quotes (ppr (moduleName (ms_mod ms))) <+>+ (parens (text (msHsFilePath ms)))
+ main/GhcMonad.hs view
@@ -0,0 +1,207 @@+{-# LANGUAGE CPP, RankNTypes #-}+{-# OPTIONS_GHC -funbox-strict-fields #-}+-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2010+--+-- The Session type and related functionality+--+-- -----------------------------------------------------------------------------++module GhcMonad (+ -- * 'Ghc' monad stuff+ GhcMonad(..),+ Ghc(..),+ GhcT(..), liftGhcT,+ reflectGhc, reifyGhc,+ getSessionDynFlags,+ liftIO,+ Session(..), withSession, modifySession, withTempSession,++ -- ** Warnings+ logWarnings, printException,+ WarnErrLogger, defaultWarnErrLogger+ ) where++import MonadUtils+import HscTypes+import DynFlags+import Exception+import ErrUtils++import Control.Monad+import Data.IORef++-- -----------------------------------------------------------------------------+-- | A monad that has all the features needed by GHC API calls.+--+-- In short, a GHC monad+--+-- - allows embedding of IO actions,+--+-- - can log warnings,+--+-- - allows handling of (extensible) exceptions, and+--+-- - maintains a current session.+--+-- If you do not use 'Ghc' or 'GhcT', make sure to call 'GHC.initGhcMonad'+-- before any call to the GHC API functions can occur.+--+class (Functor m, MonadIO m, ExceptionMonad m, HasDynFlags m) => GhcMonad m where+ getSession :: m HscEnv+ setSession :: HscEnv -> m ()++-- | Call the argument with the current session.+withSession :: GhcMonad m => (HscEnv -> m a) -> m a+withSession f = getSession >>= f++-- | Grabs the DynFlags from the Session+getSessionDynFlags :: GhcMonad m => m DynFlags+getSessionDynFlags = withSession (return . hsc_dflags)++-- | Set the current session to the result of applying the current session to+-- the argument.+modifySession :: GhcMonad m => (HscEnv -> HscEnv) -> m ()+modifySession f = do h <- getSession+ setSession $! f h++withSavedSession :: GhcMonad m => m a -> m a+withSavedSession m = do+ saved_session <- getSession+ m `gfinally` setSession saved_session++-- | Call an action with a temporarily modified Session.+withTempSession :: GhcMonad m => (HscEnv -> HscEnv) -> m a -> m a+withTempSession f m =+ withSavedSession $ modifySession f >> m++-- -----------------------------------------------------------------------------+-- | A monad that allows logging of warnings.++logWarnings :: GhcMonad m => WarningMessages -> m ()+logWarnings warns = do+ dflags <- getSessionDynFlags+ liftIO $ printOrThrowWarnings dflags warns++-- -----------------------------------------------------------------------------+-- | A minimal implementation of a 'GhcMonad'. If you need a custom monad,+-- e.g., to maintain additional state consider wrapping this monad or using+-- 'GhcT'.+newtype Ghc a = Ghc { unGhc :: Session -> IO a }++-- | The Session is a handle to the complete state of a compilation+-- session. A compilation session consists of a set of modules+-- constituting the current program or library, the context for+-- interactive evaluation, and various caches.+data Session = Session !(IORef HscEnv)++instance Functor Ghc where+ fmap f m = Ghc $ \s -> f `fmap` unGhc m s++instance Applicative Ghc where+ pure a = Ghc $ \_ -> return a+ g <*> m = do f <- g; a <- m; return (f a)++instance Monad Ghc where+ m >>= g = Ghc $ \s -> do a <- unGhc m s; unGhc (g a) s++instance MonadIO Ghc where+ liftIO ioA = Ghc $ \_ -> ioA++instance MonadFix Ghc where+ mfix f = Ghc $ \s -> mfix (\x -> unGhc (f x) s)++instance ExceptionMonad Ghc where+ gcatch act handle =+ Ghc $ \s -> unGhc act s `gcatch` \e -> unGhc (handle e) s+ gmask f =+ Ghc $ \s -> gmask $ \io_restore ->+ let+ g_restore (Ghc m) = Ghc $ \s -> io_restore (m s)+ in+ unGhc (f g_restore) s++instance HasDynFlags Ghc where+ getDynFlags = getSessionDynFlags++instance GhcMonad Ghc where+ getSession = Ghc $ \(Session r) -> readIORef r+ setSession s' = Ghc $ \(Session r) -> writeIORef r s'++-- | Reflect a computation in the 'Ghc' monad into the 'IO' monad.+--+-- You can use this to call functions returning an action in the 'Ghc' monad+-- inside an 'IO' action. This is needed for some (too restrictive) callback+-- arguments of some library functions:+--+-- > libFunc :: String -> (Int -> IO a) -> IO a+-- > ghcFunc :: Int -> Ghc a+-- >+-- > ghcFuncUsingLibFunc :: String -> Ghc a -> Ghc a+-- > ghcFuncUsingLibFunc str =+-- > reifyGhc $ \s ->+-- > libFunc $ \i -> do+-- > reflectGhc (ghcFunc i) s+--+reflectGhc :: Ghc a -> Session -> IO a+reflectGhc m = unGhc m++-- > Dual to 'reflectGhc'. See its documentation.+reifyGhc :: (Session -> IO a) -> Ghc a+reifyGhc act = Ghc $ act++-- -----------------------------------------------------------------------------+-- | A monad transformer to add GHC specific features to another monad.+--+-- Note that the wrapped monad must support IO and handling of exceptions.+newtype GhcT m a = GhcT { unGhcT :: Session -> m a }++liftGhcT :: m a -> GhcT m a+liftGhcT m = GhcT $ \_ -> m++instance Functor m => Functor (GhcT m) where+ fmap f m = GhcT $ \s -> f `fmap` unGhcT m s++instance Applicative m => Applicative (GhcT m) where+ pure x = GhcT $ \_ -> pure x+ g <*> m = GhcT $ \s -> unGhcT g s <*> unGhcT m s++instance Monad m => Monad (GhcT m) where+ m >>= k = GhcT $ \s -> do a <- unGhcT m s; unGhcT (k a) s++instance MonadIO m => MonadIO (GhcT m) where+ liftIO ioA = GhcT $ \_ -> liftIO ioA++instance ExceptionMonad m => ExceptionMonad (GhcT m) where+ gcatch act handle =+ GhcT $ \s -> unGhcT act s `gcatch` \e -> unGhcT (handle e) s+ gmask f =+ GhcT $ \s -> gmask $ \io_restore ->+ let+ g_restore (GhcT m) = GhcT $ \s -> io_restore (m s)+ in+ unGhcT (f g_restore) s++instance MonadIO m => HasDynFlags (GhcT m) where+ getDynFlags = GhcT $ \(Session r) -> liftM hsc_dflags (liftIO $ readIORef r)++instance ExceptionMonad m => GhcMonad (GhcT m) where+ getSession = GhcT $ \(Session r) -> liftIO $ readIORef r+ setSession s' = GhcT $ \(Session r) -> liftIO $ writeIORef r s'+++-- | Print the error message and all warnings. Useful inside exception+-- handlers. Clears warnings after printing.+printException :: GhcMonad m => SourceError -> m ()+printException err = do+ dflags <- getSessionDynFlags+ liftIO $ printBagOfErrors dflags (srcErrorMessages err)++-- | A function called to log warnings and errors.+type WarnErrLogger = forall m. GhcMonad m => Maybe SourceError -> m ()++defaultWarnErrLogger :: WarnErrLogger+defaultWarnErrLogger Nothing = return ()+defaultWarnErrLogger (Just e) = printException e+
+ main/GhcPlugins.hs view
@@ -0,0 +1,84 @@+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}++-- | This module is not used by GHC itself. Rather, it exports all of+-- the functions and types you are likely to need when writing a+-- plugin for GHC. So authors of plugins can probably get away simply+-- with saying "import GhcPlugins".+--+-- Particularly interesting modules for plugin writers include+-- "CoreSyn" and "CoreMonad".+module GhcPlugins(+ module Plugins,+ module RdrName, module OccName, module Name, module Var, module Id, module IdInfo,+ module CoreMonad, module CoreSyn, module Literal, module DataCon,+ module CoreUtils, module MkCore, module CoreFVs, module CoreSubst,+ module Rules, module Annotations,+ module DynFlags, module Packages,+ module Module, module Type, module TyCon, module Coercion,+ module TysWiredIn, module HscTypes, module BasicTypes,+ module VarSet, module VarEnv, module NameSet, module NameEnv,+ module UniqSet, module UniqFM, module FiniteMap,+ module Util, module GHC.Serialized, module SrcLoc, module Outputable,+ module UniqSupply, module Unique, module FastString+ ) where++-- Plugin stuff itself+import Plugins++-- Variable naming+import RdrName+import OccName hiding ( varName {- conflicts with Var.varName -} )+import Name hiding ( varName {- reexport from OccName, conflicts with Var.varName -} )+import Var+import Id hiding ( lazySetIdInfo, setIdExported, setIdNotExported {- all three conflict with Var -} )+import IdInfo++-- Core+import CoreMonad+import CoreSyn+import Literal+import DataCon+import CoreUtils+import MkCore+import CoreFVs+import CoreSubst hiding( substTyVarBndr, substCoVarBndr, extendCvSubst )+ -- These names are also exported by Type++-- Core "extras"+import Rules+import Annotations++-- Pipeline-related stuff+import DynFlags+import Packages++-- Important GHC types+import Module+import Type hiding {- conflict with CoreSubst -}+ ( substTy, extendTvSubst, extendTvSubstList, isInScope )+import Coercion hiding {- conflict with CoreSubst -}+ ( substCo )+import TyCon+import TysWiredIn+import HscTypes+import BasicTypes hiding ( Version {- conflicts with Packages.Version -} )++-- Collections and maps+import VarSet+import VarEnv+import NameSet+import NameEnv+import UniqSet+import UniqFM+-- Conflicts with UniqFM:+--import LazyUniqFM+import FiniteMap++-- Common utilities+import Util+import GHC.Serialized+import SrcLoc+import Outputable+import UniqSupply+import Unique ( Unique, Uniquable(..) )+import FastString
+ main/HeaderInfo.hs view
@@ -0,0 +1,338 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- | Parsing the top of a Haskell source file to get its module name,+-- imports and options.+--+-- (c) Simon Marlow 2005+-- (c) Lemmih 2006+--+-----------------------------------------------------------------------------++module HeaderInfo ( getImports+ , mkPrelImports -- used by the renamer too+ , getOptionsFromFile, getOptions+ , optionsErrorMsgs,+ checkProcessArgsResult ) where++#include "HsVersions.h"++import RdrName+import HscTypes+import Parser ( parseHeader )+import Lexer+import FastString+import HsSyn+import Module+import PrelNames+import StringBuffer+import SrcLoc+import DynFlags+import ErrUtils+import Util+import Outputable+import Pretty ()+import Maybes+import Bag ( emptyBag, listToBag, unitBag )+import MonadUtils+import Exception+import BasicTypes+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import System.IO+import System.IO.Unsafe+import Data.List++------------------------------------------------------------------------------++-- | Parse the imports of a source file.+--+-- Throws a 'SourceError' if parsing fails.+getImports :: DynFlags+ -> StringBuffer -- ^ Parse this.+ -> FilePath -- ^ Filename the buffer came from. Used for+ -- reporting parse error locations.+ -> FilePath -- ^ The original source filename (used for locations+ -- in the function result)+ -> IO ([(Maybe FastString, Located ModuleName)],+ [(Maybe FastString, Located ModuleName)],+ Located ModuleName)+ -- ^ The source imports, normal imports, and the module name.+getImports dflags buf filename source_filename = do+ let loc = mkRealSrcLoc (mkFastString filename) 1 1+ case unP parseHeader (mkPState dflags buf loc) of+ PFailed span err -> parseError dflags span err+ POk pst rdr_module -> do+ let _ms@(_warns, errs) = getMessages pst dflags+ -- don't log warnings: they'll be reported when we parse the file+ -- for real. See #2500.+ ms = (emptyBag, errs)+ -- logWarnings warns+ if errorsFound dflags ms+ then throwIO $ mkSrcErr errs+ else+ case rdr_module of+ L _ hsmod ->+ let+ mb_mod = hsmodName hsmod+ imps = hsmodImports hsmod+ main_loc = srcLocSpan (mkSrcLoc (mkFastString source_filename) 1 1)+ mod = mb_mod `orElse` L main_loc mAIN_NAME+ (src_idecls, ord_idecls) = partition (ideclSource.unLoc) imps++ -- GHC.Prim doesn't exist physically, so don't go looking for it.+ ordinary_imps = filter ((/= moduleName gHC_PRIM) . unLoc . ideclName . unLoc)+ ord_idecls++ implicit_prelude = xopt LangExt.ImplicitPrelude dflags+ implicit_imports = mkPrelImports (unLoc mod) main_loc+ implicit_prelude imps+ convImport (L _ i) = (fmap sl_fs (ideclPkgQual i), ideclName i)+ in+ return (map convImport src_idecls,+ map convImport (implicit_imports ++ ordinary_imps),+ mod)++mkPrelImports :: ModuleName+ -> SrcSpan -- Attribute the "import Prelude" to this location+ -> Bool -> [LImportDecl RdrName]+ -> [LImportDecl RdrName]+-- Construct the implicit declaration "import Prelude" (or not)+--+-- NB: opt_NoImplicitPrelude is slightly different to import Prelude ();+-- because the former doesn't even look at Prelude.hi for instance+-- declarations, whereas the latter does.+mkPrelImports this_mod loc implicit_prelude import_decls+ | this_mod == pRELUDE_NAME+ || explicit_prelude_import+ || not implicit_prelude+ = []+ | otherwise = [preludeImportDecl]+ where+ explicit_prelude_import+ = notNull [ () | L _ (ImportDecl { ideclName = mod+ , ideclPkgQual = Nothing })+ <- import_decls+ , unLoc mod == pRELUDE_NAME ]++ preludeImportDecl :: LImportDecl RdrName+ preludeImportDecl+ = L loc $ ImportDecl { ideclSourceSrc = NoSourceText,+ ideclName = L loc pRELUDE_NAME,+ ideclPkgQual = Nothing,+ ideclSource = False,+ ideclSafe = False, -- Not a safe import+ ideclQualified = False,+ ideclImplicit = True, -- Implicit!+ ideclAs = Nothing,+ ideclHiding = Nothing }++parseError :: DynFlags -> SrcSpan -> MsgDoc -> IO a+parseError dflags span err = throwOneError $ mkPlainErrMsg dflags span err++--------------------------------------------------------------+-- Get options+--------------------------------------------------------------++-- | Parse OPTIONS and LANGUAGE pragmas of the source file.+--+-- Throws a 'SourceError' if flag parsing fails (including unsupported flags.)+getOptionsFromFile :: DynFlags+ -> FilePath -- ^ Input file+ -> IO [Located String] -- ^ Parsed options, if any.+getOptionsFromFile dflags filename+ = Exception.bracket+ (openBinaryFile filename ReadMode)+ (hClose)+ (\handle -> do+ opts <- fmap (getOptions' dflags)+ (lazyGetToks dflags' filename handle)+ seqList opts $ return opts)+ where -- We don't need to get haddock doc tokens when we're just+ -- getting the options from pragmas, and lazily lexing them+ -- correctly is a little tricky: If there is "\n" or "\n-"+ -- left at the end of a buffer then the haddock doc may+ -- continue past the end of the buffer, despite the fact that+ -- we already have an apparently-complete token.+ -- We therefore just turn Opt_Haddock off when doing the lazy+ -- lex.+ dflags' = gopt_unset dflags Opt_Haddock++blockSize :: Int+-- blockSize = 17 -- for testing :-)+blockSize = 1024++lazyGetToks :: DynFlags -> FilePath -> Handle -> IO [Located Token]+lazyGetToks dflags filename handle = do+ buf <- hGetStringBufferBlock handle blockSize+ unsafeInterleaveIO $ lazyLexBuf handle (pragState dflags buf loc) False blockSize+ where+ loc = mkRealSrcLoc (mkFastString filename) 1 1++ lazyLexBuf :: Handle -> PState -> Bool -> Int -> IO [Located Token]+ lazyLexBuf handle state eof size = do+ case unP (lexer False return) state of+ POk state' t -> do+ -- pprTrace "lazyLexBuf" (text (show (buffer state'))) (return ())+ if atEnd (buffer state') && not eof+ -- if this token reached the end of the buffer, and we haven't+ -- necessarily read up to the end of the file, then the token might+ -- be truncated, so read some more of the file and lex it again.+ then getMore handle state size+ else case t of+ L _ ITeof -> return [t]+ _other -> do rest <- lazyLexBuf handle state' eof size+ return (t : rest)+ _ | not eof -> getMore handle state size+ | otherwise -> return [L (RealSrcSpan (last_loc state)) ITeof]+ -- parser assumes an ITeof sentinel at the end++ getMore :: Handle -> PState -> Int -> IO [Located Token]+ getMore handle state size = do+ -- pprTrace "getMore" (text (show (buffer state))) (return ())+ let new_size = size * 2+ -- double the buffer size each time we read a new block. This+ -- counteracts the quadratic slowdown we otherwise get for very+ -- large module names (#5981)+ nextbuf <- hGetStringBufferBlock handle new_size+ if (len nextbuf == 0) then lazyLexBuf handle state True new_size else do+ newbuf <- appendStringBuffers (buffer state) nextbuf+ unsafeInterleaveIO $ lazyLexBuf handle state{buffer=newbuf} False new_size+++getToks :: DynFlags -> FilePath -> StringBuffer -> [Located Token]+getToks dflags filename buf = lexAll (pragState dflags buf loc)+ where+ loc = mkRealSrcLoc (mkFastString filename) 1 1++ lexAll state = case unP (lexer False return) state of+ POk _ t@(L _ ITeof) -> [t]+ POk state' t -> t : lexAll state'+ _ -> [L (RealSrcSpan (last_loc state)) ITeof]+++-- | Parse OPTIONS and LANGUAGE pragmas of the source file.+--+-- Throws a 'SourceError' if flag parsing fails (including unsupported flags.)+getOptions :: DynFlags+ -> StringBuffer -- ^ Input Buffer+ -> FilePath -- ^ Source filename. Used for location info.+ -> [Located String] -- ^ Parsed options.+getOptions dflags buf filename+ = getOptions' dflags (getToks dflags filename buf)++-- The token parser is written manually because Happy can't+-- return a partial result when it encounters a lexer error.+-- We want to extract options before the buffer is passed through+-- CPP, so we can't use the same trick as 'getImports'.+getOptions' :: DynFlags+ -> [Located Token] -- Input buffer+ -> [Located String] -- Options.+getOptions' dflags toks+ = parseToks toks+ where+ getToken (L _loc tok) = tok+ getLoc (L loc _tok) = loc++ parseToks (open:close:xs)+ | IToptions_prag str <- getToken open+ , ITclose_prag <- getToken close+ = case toArgs str of+ Left err -> panic ("getOptions'.parseToks: " ++ err)+ Right args -> map (L (getLoc open)) args ++ parseToks xs+ parseToks (open:close:xs)+ | ITinclude_prag str <- getToken open+ , ITclose_prag <- getToken close+ = map (L (getLoc open)) ["-#include",removeSpaces str] +++ parseToks xs+ parseToks (open:close:xs)+ | ITdocOptions str <- getToken open+ , ITclose_prag <- getToken close+ = map (L (getLoc open)) ["-haddock-opts", removeSpaces str]+ ++ parseToks xs+ parseToks (open:xs)+ | ITlanguage_prag <- getToken open+ = parseLanguage xs+ parseToks (comment:xs) -- Skip over comments+ | isComment (getToken comment)+ = parseToks xs+ parseToks _ = []+ parseLanguage (L loc (ITconid fs):rest)+ = checkExtension dflags (L loc fs) :+ case rest of+ (L _loc ITcomma):more -> parseLanguage more+ (L _loc ITclose_prag):more -> parseToks more+ (L loc _):_ -> languagePragParseError dflags loc+ [] -> panic "getOptions'.parseLanguage(1) went past eof token"+ parseLanguage (tok:_)+ = languagePragParseError dflags (getLoc tok)+ parseLanguage []+ = panic "getOptions'.parseLanguage(2) went past eof token"++ isComment :: Token -> Bool+ isComment c =+ case c of+ (ITlineComment {}) -> True+ (ITblockComment {}) -> True+ (ITdocCommentNext {}) -> True+ (ITdocCommentPrev {}) -> True+ (ITdocCommentNamed {}) -> True+ (ITdocSection {}) -> True+ _ -> False++-----------------------------------------------------------------------------++-- | Complain about non-dynamic flags in OPTIONS pragmas.+--+-- Throws a 'SourceError' if the input list is non-empty claiming that the+-- input flags are unknown.+checkProcessArgsResult :: MonadIO m => DynFlags -> [Located String] -> m ()+checkProcessArgsResult dflags flags+ = when (notNull flags) $+ liftIO $ throwIO $ mkSrcErr $ listToBag $ map mkMsg flags+ where mkMsg (L loc flag)+ = mkPlainErrMsg dflags loc $+ (text "unknown flag in {-# OPTIONS_GHC #-} pragma:" <+>+ text flag)++-----------------------------------------------------------------------------++checkExtension :: DynFlags -> Located FastString -> Located String+checkExtension dflags (L l ext)+-- Checks if a given extension is valid, and if so returns+-- its corresponding flag. Otherwise it throws an exception.+ = let ext' = unpackFS ext in+ if ext' `elem` supportedLanguagesAndExtensions+ then L l ("-X"++ext')+ else unsupportedExtnError dflags l ext'++languagePragParseError :: DynFlags -> SrcSpan -> a+languagePragParseError dflags loc =+ throw $ mkSrcErr $ unitBag $+ (mkPlainErrMsg dflags loc $+ vcat [ text "Cannot parse LANGUAGE pragma"+ , text "Expecting comma-separated list of language options,"+ , text "each starting with a capital letter"+ , nest 2 (text "E.g. {-# LANGUAGE TemplateHaskell, GADTs #-}") ])++unsupportedExtnError :: DynFlags -> SrcSpan -> String -> a+unsupportedExtnError dflags loc unsup =+ throw $ mkSrcErr $ unitBag $+ mkPlainErrMsg dflags loc $+ text "Unsupported extension: " <> text unsup $$+ if null suggestions then Outputable.empty else text "Perhaps you meant" <+> quotedListWithOr (map text suggestions)+ where+ suggestions = fuzzyMatch unsup supportedLanguagesAndExtensions+++optionsErrorMsgs :: DynFlags -> [String] -> [Located String] -> FilePath -> Messages+optionsErrorMsgs dflags unhandled_flags flags_lines _filename+ = (emptyBag, listToBag (map mkMsg unhandled_flags_lines))+ where unhandled_flags_lines = [ L l f | f <- unhandled_flags,+ L l f' <- flags_lines, f == f' ]+ mkMsg (L flagSpan flag) =+ ErrUtils.mkPlainErrMsg dflags flagSpan $+ text "unknown flag in {-# OPTIONS_GHC #-} pragma:" <+> text flag+
+ main/Hooks.hs view
@@ -0,0 +1,96 @@+-- \section[Hooks]{Low level API hooks}++-- NB: this module is SOURCE-imported by DynFlags, and should primarily+-- refer to *types*, rather than *code*+-- If you import too muchhere , then the revolting compiler_stage2_dll0_MODULES+-- stuff in compiler/ghc.mk makes DynFlags link to too much stuff++{-# LANGUAGE CPP #-}+module Hooks ( Hooks+ , emptyHooks+ , lookupHook+ , getHooked+ -- the hooks:+ , dsForeignsHook+ , tcForeignImportsHook+ , tcForeignExportsHook+ , hscFrontendHook+ , hscCompileCoreExprHook+ , ghcPrimIfaceHook+ , runPhaseHook+ , runMetaHook+ , linkHook+ , runRnSpliceHook+ , getValueSafelyHook+ , createIservProcessHook+ ) where++import DynFlags+import Name+import PipelineMonad+import HscTypes+import HsDecls+import HsBinds+import HsExpr+import OrdList+import Id+import TcRnTypes+import Bag+import RdrName+import CoreSyn+import GHCi.RemoteTypes+import SrcLoc+import Type+import System.Process+import BasicTypes++import Data.Maybe++{-+************************************************************************+* *+\subsection{Hooks}+* *+************************************************************************+-}++-- | Hooks can be used by GHC API clients to replace parts of+-- the compiler pipeline. If a hook is not installed, GHC+-- uses the default built-in behaviour++emptyHooks :: Hooks+emptyHooks = Hooks+ { dsForeignsHook = Nothing+ , tcForeignImportsHook = Nothing+ , tcForeignExportsHook = Nothing+ , hscFrontendHook = Nothing+ , hscCompileCoreExprHook = Nothing+ , ghcPrimIfaceHook = Nothing+ , runPhaseHook = Nothing+ , runMetaHook = Nothing+ , linkHook = Nothing+ , runRnSpliceHook = Nothing+ , getValueSafelyHook = Nothing+ , createIservProcessHook = Nothing+ }++data Hooks = Hooks+ { dsForeignsHook :: Maybe ([LForeignDecl Id] -> DsM (ForeignStubs, OrdList (Id, CoreExpr)))+ , tcForeignImportsHook :: Maybe ([LForeignDecl Name] -> TcM ([Id], [LForeignDecl Id], Bag GlobalRdrElt))+ , tcForeignExportsHook :: Maybe ([LForeignDecl Name] -> TcM (LHsBinds TcId, [LForeignDecl TcId], Bag GlobalRdrElt))+ , hscFrontendHook :: Maybe (ModSummary -> Hsc FrontendResult)+ , hscCompileCoreExprHook :: Maybe (HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue)+ , ghcPrimIfaceHook :: Maybe ModIface+ , runPhaseHook :: Maybe (PhasePlus -> FilePath -> DynFlags -> CompPipeline (PhasePlus, FilePath))+ , runMetaHook :: Maybe (MetaHook TcM)+ , linkHook :: Maybe (GhcLink -> DynFlags -> Bool -> HomePackageTable -> IO SuccessFlag)+ , runRnSpliceHook :: Maybe (HsSplice Name -> RnM (HsSplice Name))+ , getValueSafelyHook :: Maybe (HscEnv -> Name -> Type -> IO (Maybe HValue))+ , createIservProcessHook :: Maybe (CreateProcess -> IO ProcessHandle)+ }++getHooked :: (Functor f, HasDynFlags f) => (Hooks -> Maybe a) -> a -> f a+getHooked hook def = fmap (lookupHook hook def) getDynFlags++lookupHook :: (Hooks -> Maybe a) -> a -> DynFlags -> a+lookupHook hook def = fromMaybe def . hook . hooks
+ main/Hooks.hs-boot view
@@ -0,0 +1,5 @@+module Hooks where++data Hooks++emptyHooks :: Hooks
+ main/HscMain.hs view
@@ -0,0 +1,1784 @@+{-# LANGUAGE BangPatterns, CPP, MagicHash, NondecreasingIndentation #-}+{-# OPTIONS_GHC -fprof-auto-top #-}++-------------------------------------------------------------------------------+--+-- | Main API for compiling plain Haskell source code.+--+-- This module implements compilation of a Haskell source. It is+-- /not/ concerned with preprocessing of source files; this is handled+-- in "DriverPipeline".+--+-- There are various entry points depending on what mode we're in:+-- "batch" mode (@--make@), "one-shot" mode (@-c@, @-S@ etc.), and+-- "interactive" mode (GHCi). There are also entry points for+-- individual passes: parsing, typechecking/renaming, desugaring, and+-- simplification.+--+-- All the functions here take an 'HscEnv' as a parameter, but none of+-- them return a new one: 'HscEnv' is treated as an immutable value+-- from here on in (although it has mutable components, for the+-- caches).+--+-- We use the Hsc monad to deal with warning messages consistently:+-- specifically, while executing within an Hsc monad, warnings are+-- collected. When a Hsc monad returns to an IO monad, the+-- warnings are printed, or compilation aborts if the @-Werror@+-- flag is enabled.+--+-- (c) The GRASP/AQUA Project, Glasgow University, 1993-2000+--+-------------------------------------------------------------------------------++module HscMain+ (+ -- * Making an HscEnv+ newHscEnv++ -- * Compiling complete source files+ , Messager, batchMsg+ , HscStatus (..)+ , hscIncrementalCompile+ , hscCompileCmmFile++ , hscGenHardCode+ , hscInteractive++ -- * Running passes separately+ , hscParse+ , hscTypecheckRename+ , hscDesugar+ , makeSimpleDetails+ , hscSimplify -- ToDo, shouldn't really export this++ -- * Safe Haskell+ , hscCheckSafe+ , hscGetSafe++ -- * Support for interactive evaluation+ , hscParseIdentifier+ , hscTcRcLookupName+ , hscTcRnGetInfo+ , hscIsGHCiMonad+ , hscGetModuleInterface+ , hscRnImportDecls+ , hscTcRnLookupRdrName+ , hscStmt, hscStmtWithLocation, hscParsedStmt+ , hscDecls, hscDeclsWithLocation+ , hscTcExpr, TcRnExprMode(..), hscImport, hscKcType+ , hscParseExpr+ , hscCompileCoreExpr+ -- * Low-level exports for hooks+ , hscCompileCoreExpr'+ -- We want to make sure that we export enough to be able to redefine+ -- hscFileFrontEnd in client code+ , hscParse', hscSimplify', hscDesugar', tcRnModule'+ , getHscEnv+ , hscSimpleIface', hscNormalIface'+ , oneShotMsg+ , hscFileFrontEnd, genericHscFrontend, dumpIfaceStats+ , ioMsgMaybe+ , showModuleIndex+ , hscAddSptEntries+ ) where++import Data.Data hiding (Fixity, TyCon)+import Id+import GHCi ( addSptEntry )+import GHCi.RemoteTypes ( ForeignHValue )+import ByteCodeGen ( byteCodeGen, coreExprToBCOs )+import Linker+import CoreTidy ( tidyExpr )+import Type ( Type )+import {- Kind parts of -} Type ( Kind )+import CoreLint ( lintInteractiveExpr )+import VarEnv ( emptyTidyEnv )+import Panic+import ConLike+import Control.Concurrent++import Module+import Packages+import RdrName+import HsSyn+import HsDumpAst+import CoreSyn+import StringBuffer+import Parser+import Lexer+import SrcLoc+import TcRnDriver+import TcIface ( typecheckIface )+import TcRnMonad+import NameCache ( initNameCache )+import LoadIface ( ifaceStats, initExternalPackageState )+import PrelInfo+import MkIface+import Desugar+import SimplCore+import TidyPgm+import CorePrep+import CoreToStg ( coreToStg )+import qualified StgCmm ( codeGen )+import StgSyn+import CostCentre+import ProfInit+import TyCon+import Name+import SimplStg ( stg2stg )+import Cmm+import CmmParse ( parseCmmFile )+import CmmBuildInfoTables+import CmmPipeline+import CmmInfo+import CodeOutput+import InstEnv+import FamInstEnv+import Fingerprint ( Fingerprint )+import Hooks+import TcEnv++import DynFlags+import ErrUtils+import Platform ( platformOS, osSubsectionsViaSymbols )++import Outputable+import NameEnv+import HscStats ( ppSourceStats )+import HscTypes+import FastString+import UniqSupply+import Bag+import Exception+import qualified Stream+import Stream (Stream)++import Util++import Data.List+import Control.Monad+import Data.IORef+import System.FilePath as FilePath+import System.Directory+import System.IO (fixIO)+import qualified Data.Map as Map+import qualified Data.Set as S+import Data.Set (Set)++#include "HsVersions.h"+++{- **********************************************************************+%* *+ Initialisation+%* *+%********************************************************************* -}++newHscEnv :: DynFlags -> IO HscEnv+newHscEnv dflags = do+ eps_var <- newIORef initExternalPackageState+ us <- mkSplitUniqSupply 'r'+ nc_var <- newIORef (initNameCache us knownKeyNames)+ fc_var <- newIORef emptyInstalledModuleEnv+ iserv_mvar <- newMVar Nothing+ return HscEnv { hsc_dflags = dflags+ , hsc_targets = []+ , hsc_mod_graph = []+ , hsc_IC = emptyInteractiveContext dflags+ , hsc_HPT = emptyHomePackageTable+ , hsc_EPS = eps_var+ , hsc_NC = nc_var+ , hsc_FC = fc_var+ , hsc_type_env_var = Nothing+ , hsc_iserv = iserv_mvar+ }++-- -----------------------------------------------------------------------------++getWarnings :: Hsc WarningMessages+getWarnings = Hsc $ \_ w -> return (w, w)++clearWarnings :: Hsc ()+clearWarnings = Hsc $ \_ _ -> return ((), emptyBag)++logWarnings :: WarningMessages -> Hsc ()+logWarnings w = Hsc $ \_ w0 -> return ((), w0 `unionBags` w)++getHscEnv :: Hsc HscEnv+getHscEnv = Hsc $ \e w -> return (e, w)++handleWarnings :: Hsc ()+handleWarnings = do+ dflags <- getDynFlags+ w <- getWarnings+ liftIO $ printOrThrowWarnings dflags w+ clearWarnings++-- | log warning in the monad, and if there are errors then+-- throw a SourceError exception.+logWarningsReportErrors :: Messages -> Hsc ()+logWarningsReportErrors (warns,errs) = do+ logWarnings warns+ when (not $ isEmptyBag errs) $ throwErrors errs++-- | Throw some errors.+throwErrors :: ErrorMessages -> Hsc a+throwErrors = liftIO . throwIO . mkSrcErr++-- | Deal with errors and warnings returned by a compilation step+--+-- In order to reduce dependencies to other parts of the compiler, functions+-- outside the "main" parts of GHC return warnings and errors as a parameter+-- and signal success via by wrapping the result in a 'Maybe' type. This+-- function logs the returned warnings and propagates errors as exceptions+-- (of type 'SourceError').+--+-- This function assumes the following invariants:+--+-- 1. If the second result indicates success (is of the form 'Just x'),+-- there must be no error messages in the first result.+--+-- 2. If there are no error messages, but the second result indicates failure+-- there should be warnings in the first result. That is, if the action+-- failed, it must have been due to the warnings (i.e., @-Werror@).+ioMsgMaybe :: IO (Messages, Maybe a) -> Hsc a+ioMsgMaybe ioA = do+ ((warns,errs), mb_r) <- liftIO ioA+ logWarnings warns+ case mb_r of+ Nothing -> throwErrors errs+ Just r -> ASSERT( isEmptyBag errs ) return r++-- | like ioMsgMaybe, except that we ignore error messages and return+-- 'Nothing' instead.+ioMsgMaybe' :: IO (Messages, Maybe a) -> Hsc (Maybe a)+ioMsgMaybe' ioA = do+ ((warns,_errs), mb_r) <- liftIO $ ioA+ logWarnings warns+ return mb_r++-- -----------------------------------------------------------------------------+-- | Lookup things in the compiler's environment++hscTcRnLookupRdrName :: HscEnv -> Located RdrName -> IO [Name]+hscTcRnLookupRdrName hsc_env0 rdr_name+ = runInteractiveHsc hsc_env0 $+ do { hsc_env <- getHscEnv+ ; ioMsgMaybe $ tcRnLookupRdrName hsc_env rdr_name }++hscTcRcLookupName :: HscEnv -> Name -> IO (Maybe TyThing)+hscTcRcLookupName hsc_env0 name = runInteractiveHsc hsc_env0 $ do+ hsc_env <- getHscEnv+ ioMsgMaybe' $ tcRnLookupName hsc_env name+ -- ignore errors: the only error we're likely to get is+ -- "name not found", and the Maybe in the return type+ -- is used to indicate that.++hscTcRnGetInfo :: HscEnv -> Name -> IO (Maybe (TyThing, Fixity, [ClsInst], [FamInst]))+hscTcRnGetInfo hsc_env0 name+ = runInteractiveHsc hsc_env0 $+ do { hsc_env <- getHscEnv+ ; ioMsgMaybe' $ tcRnGetInfo hsc_env name }++hscIsGHCiMonad :: HscEnv -> String -> IO Name+hscIsGHCiMonad hsc_env name+ = runHsc hsc_env $ ioMsgMaybe $ isGHCiMonad hsc_env name++hscGetModuleInterface :: HscEnv -> Module -> IO ModIface+hscGetModuleInterface hsc_env0 mod = runInteractiveHsc hsc_env0 $ do+ hsc_env <- getHscEnv+ ioMsgMaybe $ getModuleInterface hsc_env mod++-- -----------------------------------------------------------------------------+-- | Rename some import declarations+hscRnImportDecls :: HscEnv -> [LImportDecl RdrName] -> IO GlobalRdrEnv+hscRnImportDecls hsc_env0 import_decls = runInteractiveHsc hsc_env0 $ do+ hsc_env <- getHscEnv+ ioMsgMaybe $ tcRnImportDecls hsc_env import_decls++-- -----------------------------------------------------------------------------+-- | parse a file, returning the abstract syntax++hscParse :: HscEnv -> ModSummary -> IO HsParsedModule+hscParse hsc_env mod_summary = runHsc hsc_env $ hscParse' mod_summary++-- internal version, that doesn't fail due to -Werror+hscParse' :: ModSummary -> Hsc HsParsedModule+hscParse' mod_summary+ | Just r <- ms_parsed_mod mod_summary = return r+ | otherwise = {-# SCC "Parser" #-}+ withTiming getDynFlags+ (text "Parser"<+>brackets (ppr $ ms_mod mod_summary))+ (const ()) $ do+ dflags <- getDynFlags+ let src_filename = ms_hspp_file mod_summary+ maybe_src_buf = ms_hspp_buf mod_summary++ -------------------------- Parser ----------------+ -- sometimes we already have the buffer in memory, perhaps+ -- because we needed to parse the imports out of it, or get the+ -- module name.+ buf <- case maybe_src_buf of+ Just b -> return b+ Nothing -> liftIO $ hGetStringBuffer src_filename++ let loc = mkRealSrcLoc (mkFastString src_filename) 1 1+ let parseMod | HsigFile == ms_hsc_src mod_summary+ = parseSignature+ | otherwise = parseModule++ case unP parseMod (mkPState dflags buf loc) of+ PFailed span err ->+ liftIO $ throwOneError (mkPlainErrMsg dflags span err)++ POk pst rdr_module -> do+ logWarningsReportErrors (getMessages pst dflags)+ liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" $+ ppr rdr_module+ liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST" $+ text (showAstData NoBlankSrcSpan rdr_module)+ liftIO $ dumpIfSet_dyn dflags Opt_D_source_stats "Source Statistics" $+ ppSourceStats False rdr_module++ -- To get the list of extra source files, we take the list+ -- that the parser gave us,+ -- - eliminate files beginning with '<'. gcc likes to use+ -- pseudo-filenames like "<built-in>" and "<command-line>"+ -- - normalise them (elimiante differences between ./f and f)+ -- - filter out the preprocessed source file+ -- - filter out anything beginning with tmpdir+ -- - remove duplicates+ -- - filter out the .hs/.lhs source filename if we have one+ --+ let n_hspp = FilePath.normalise src_filename+ srcs0 = nub $ filter (not . (tmpDir dflags `isPrefixOf`))+ $ filter (not . (== n_hspp))+ $ map FilePath.normalise+ $ filter (not . (isPrefixOf "<"))+ $ map unpackFS+ $ srcfiles pst+ srcs1 = case ml_hs_file (ms_location mod_summary) of+ Just f -> filter (/= FilePath.normalise f) srcs0+ Nothing -> srcs0++ -- sometimes we see source files from earlier+ -- preprocessing stages that cannot be found, so just+ -- filter them out:+ srcs2 <- liftIO $ filterM doesFileExist srcs1++ return HsParsedModule {+ hpm_module = rdr_module,+ hpm_src_files = srcs2,+ hpm_annotations+ = (Map.fromListWith (++) $ annotations pst,+ Map.fromList $ ((noSrcSpan,comment_q pst)+ :(annotations_comments pst)))+ }++-- XXX: should this really be a Maybe X? Check under which circumstances this+-- can become a Nothing and decide whether this should instead throw an+-- exception/signal an error.+type RenamedStuff =+ (Maybe (HsGroup Name, [LImportDecl Name], Maybe [LIE Name],+ Maybe LHsDocString))++-- | Rename and typecheck a module, additionally returning the renamed syntax+hscTypecheckRename :: HscEnv -> ModSummary -> HsParsedModule+ -> IO (TcGblEnv, RenamedStuff)+hscTypecheckRename hsc_env mod_summary rdr_module = runHsc hsc_env $ do+ tc_result <- hscTypecheck True mod_summary (Just rdr_module)++ -- This 'do' is in the Maybe monad!+ let rn_info = do decl <- tcg_rn_decls tc_result+ let imports = tcg_rn_imports tc_result+ exports = tcg_rn_exports tc_result+ doc_hdr = tcg_doc_hdr tc_result+ return (decl,imports,exports,doc_hdr)++ return (tc_result, rn_info)++hscTypecheck :: Bool -- ^ Keep renamed source?+ -> ModSummary -> Maybe HsParsedModule+ -> Hsc TcGblEnv+hscTypecheck keep_rn mod_summary mb_rdr_module = do+ hsc_env <- getHscEnv+ let hsc_src = ms_hsc_src mod_summary+ dflags = hsc_dflags hsc_env+ outer_mod = ms_mod mod_summary+ mod_name = moduleName outer_mod+ outer_mod' = mkModule (thisPackage dflags) mod_name+ inner_mod = canonicalizeHomeModule dflags mod_name+ src_filename = ms_hspp_file mod_summary+ real_loc = realSrcLocSpan $ mkRealSrcLoc (mkFastString src_filename) 1 1+ MASSERT( moduleUnitId outer_mod == thisPackage dflags )+ if hsc_src == HsigFile && not (isHoleModule inner_mod)+ then ioMsgMaybe $ tcRnInstantiateSignature hsc_env outer_mod' real_loc+ else+ do hpm <- case mb_rdr_module of+ Just hpm -> return hpm+ Nothing -> hscParse' mod_summary+ tc_result0 <- tcRnModule' hsc_env mod_summary keep_rn hpm+ if hsc_src == HsigFile+ then do (iface, _, _) <- liftIO $ hscSimpleIface hsc_env tc_result0 Nothing+ ioMsgMaybe $+ tcRnMergeSignatures hsc_env hpm tc_result0 iface+ else return tc_result0++-- wrapper around tcRnModule to handle safe haskell extras+tcRnModule' :: HscEnv -> ModSummary -> Bool -> HsParsedModule+ -> Hsc TcGblEnv+tcRnModule' hsc_env sum save_rn_syntax mod = do+ tcg_res <- {-# SCC "Typecheck-Rename" #-}+ ioMsgMaybe $+ tcRnModule hsc_env (ms_hsc_src sum) save_rn_syntax mod++ -- See Note [Safe Haskell Overlapping Instances Implementation]+ -- although this is used for more than just that failure case.+ (tcSafeOK, whyUnsafe) <- liftIO $ readIORef (tcg_safeInfer tcg_res)+ dflags <- getDynFlags+ let allSafeOK = safeInferred dflags && tcSafeOK++ -- end of the safe haskell line, how to respond to user?+ if not (safeHaskellOn dflags) || (safeInferOn dflags && not allSafeOK)+ -- if safe Haskell off or safe infer failed, mark unsafe+ then markUnsafeInfer tcg_res whyUnsafe++ -- module (could be) safe, throw warning if needed+ else do+ tcg_res' <- hscCheckSafeImports tcg_res+ safe <- liftIO $ fst <$> readIORef (tcg_safeInfer tcg_res')+ when safe $ do+ case wopt Opt_WarnSafe dflags of+ True -> (logWarnings $ unitBag $+ makeIntoWarning (Reason Opt_WarnSafe) $+ mkPlainWarnMsg dflags (warnSafeOnLoc dflags) $+ errSafe tcg_res')+ False | safeHaskell dflags == Sf_Trustworthy &&+ wopt Opt_WarnTrustworthySafe dflags ->+ (logWarnings $ unitBag $+ makeIntoWarning (Reason Opt_WarnTrustworthySafe) $+ mkPlainWarnMsg dflags (trustworthyOnLoc dflags) $+ errTwthySafe tcg_res')+ False -> return ()+ return tcg_res'+ where+ pprMod t = ppr $ moduleName $ tcg_mod t+ errSafe t = quotes (pprMod t) <+> text "has been inferred as safe!"+ errTwthySafe t = quotes (pprMod t)+ <+> text "is marked as Trustworthy but has been inferred as safe!"++-- | Convert a typechecked module to Core+hscDesugar :: HscEnv -> ModSummary -> TcGblEnv -> IO ModGuts+hscDesugar hsc_env mod_summary tc_result =+ runHsc hsc_env $ hscDesugar' (ms_location mod_summary) tc_result++hscDesugar' :: ModLocation -> TcGblEnv -> Hsc ModGuts+hscDesugar' mod_location tc_result = do+ hsc_env <- getHscEnv+ r <- ioMsgMaybe $+ {-# SCC "deSugar" #-}+ deSugar hsc_env mod_location tc_result++ -- always check -Werror after desugaring, this is the last opportunity for+ -- warnings to arise before the backend.+ handleWarnings+ return r++-- | Make a 'ModDetails' from the results of typechecking. Used when+-- typechecking only, as opposed to full compilation.+makeSimpleDetails :: HscEnv -> TcGblEnv -> IO ModDetails+makeSimpleDetails hsc_env tc_result = mkBootModDetailsTc hsc_env tc_result+++{- **********************************************************************+%* *+ The main compiler pipeline+%* *+%********************************************************************* -}++{-+ --------------------------------+ The compilation proper+ --------------------------------++It's the task of the compilation proper to compile Haskell, hs-boot and core+files to either byte-code, hard-code (C, asm, LLVM, ect) or to nothing at all+(the module is still parsed and type-checked. This feature is mostly used by+IDE's and the likes). Compilation can happen in either 'one-shot', 'batch',+'nothing', or 'interactive' mode. 'One-shot' mode targets hard-code, 'batch'+mode targets hard-code, 'nothing' mode targets nothing and 'interactive' mode+targets byte-code.++The modes are kept separate because of their different types and meanings:++ * In 'one-shot' mode, we're only compiling a single file and can therefore+ discard the new ModIface and ModDetails. This is also the reason it only+ targets hard-code; compiling to byte-code or nothing doesn't make sense when+ we discard the result.++ * 'Batch' mode is like 'one-shot' except that we keep the resulting ModIface+ and ModDetails. 'Batch' mode doesn't target byte-code since that require us to+ return the newly compiled byte-code.++ * 'Nothing' mode has exactly the same type as 'batch' mode but they're still+ kept separate. This is because compiling to nothing is fairly special: We+ don't output any interface files, we don't run the simplifier and we don't+ generate any code.++ * 'Interactive' mode is similar to 'batch' mode except that we return the+ compiled byte-code together with the ModIface and ModDetails.++Trying to compile a hs-boot file to byte-code will result in a run-time error.+This is the only thing that isn't caught by the type-system.+-}+++type Messager = HscEnv -> (Int,Int) -> RecompileRequired -> ModSummary -> IO ()++-- | This function runs GHC's frontend with recompilation+-- avoidance. Specifically, it checks if recompilation is needed,+-- and if it is, it parses and typechecks the input module.+-- It does not write out the results of typechecking (See+-- compileOne and hscIncrementalCompile).+hscIncrementalFrontend :: Bool -- always do basic recompilation check?+ -> Maybe TcGblEnv+ -> Maybe Messager+ -> ModSummary+ -> SourceModified+ -> Maybe ModIface -- Old interface, if available+ -> (Int,Int) -- (i,n) = module i of n (for msgs)+ -> Hsc (Either ModIface (FrontendResult, Maybe Fingerprint))++hscIncrementalFrontend+ always_do_basic_recompilation_check m_tc_result+ mHscMessage mod_summary source_modified mb_old_iface mod_index+ = do+ hsc_env <- getHscEnv++ let msg what = case mHscMessage of+ Just hscMessage -> hscMessage hsc_env mod_index what mod_summary+ Nothing -> return ()++ skip iface = do+ liftIO $ msg UpToDate+ return $ Left iface++ compile mb_old_hash reason = do+ liftIO $ msg reason+ result <- genericHscFrontend mod_summary+ return $ Right (result, mb_old_hash)++ stable = case source_modified of+ SourceUnmodifiedAndStable -> True+ _ -> False++ case m_tc_result of+ Just tc_result+ | not always_do_basic_recompilation_check ->+ return $ Right (FrontendTypecheck tc_result, Nothing)+ _ -> do+ (recomp_reqd, mb_checked_iface)+ <- {-# SCC "checkOldIface" #-}+ liftIO $ checkOldIface hsc_env mod_summary+ source_modified mb_old_iface+ -- save the interface that comes back from checkOldIface.+ -- In one-shot mode we don't have the old iface until this+ -- point, when checkOldIface reads it from the disk.+ let mb_old_hash = fmap mi_iface_hash mb_checked_iface++ case mb_checked_iface of+ Just iface | not (recompileRequired recomp_reqd) ->+ -- If the module used TH splices when it was last+ -- compiled, then the recompilation check is not+ -- accurate enough (#481) and we must ignore+ -- it. However, if the module is stable (none of+ -- the modules it depends on, directly or+ -- indirectly, changed), then we *can* skip+ -- recompilation. This is why the SourceModified+ -- type contains SourceUnmodifiedAndStable, and+ -- it's pretty important: otherwise ghc --make+ -- would always recompile TH modules, even if+ -- nothing at all has changed. Stability is just+ -- the same check that make is doing for us in+ -- one-shot mode.+ case m_tc_result of+ Nothing+ | mi_used_th iface && not stable ->+ compile mb_old_hash (RecompBecause "TH")+ _ ->+ skip iface+ _ ->+ case m_tc_result of+ Nothing -> compile mb_old_hash recomp_reqd+ Just tc_result ->+ return $ Right (FrontendTypecheck tc_result, mb_old_hash)++genericHscFrontend :: ModSummary -> Hsc FrontendResult+genericHscFrontend mod_summary =+ getHooked hscFrontendHook genericHscFrontend' >>= ($ mod_summary)++genericHscFrontend' :: ModSummary -> Hsc FrontendResult+genericHscFrontend' mod_summary+ = FrontendTypecheck `fmap` hscFileFrontEnd mod_summary++--------------------------------------------------------------+-- Compilers+--------------------------------------------------------------++-- Compile Haskell/boot in OneShot mode.+hscIncrementalCompile :: Bool+ -> Maybe TcGblEnv+ -> Maybe Messager+ -> HscEnv+ -> ModSummary+ -> SourceModified+ -> Maybe ModIface+ -> (Int,Int)+ -- HomeModInfo does not contain linkable, since we haven't+ -- code-genned yet+ -> IO (HscStatus, HomeModInfo)+hscIncrementalCompile always_do_basic_recompilation_check m_tc_result+ mHscMessage hsc_env' mod_summary source_modified mb_old_iface mod_index+ = do+ -- One-shot mode needs a knot-tying mutable variable for interface+ -- files. See TcRnTypes.TcGblEnv.tcg_type_env_var.+ -- See also Note [hsc_type_env_var hack]+ type_env_var <- newIORef emptyNameEnv+ let mod = ms_mod mod_summary+ hsc_env | isOneShot (ghcMode (hsc_dflags hsc_env'))+ = hsc_env' { hsc_type_env_var = Just (mod, type_env_var) }+ | otherwise+ = hsc_env'++ -- NB: enter Hsc monad here so that we don't bail out early with+ -- -Werror on typechecker warnings; we also want to run the desugarer+ -- to get those warnings too. (But we'll always exit at that point+ -- because the desugarer runs ioMsgMaybe.)+ runHsc hsc_env $ do+ let dflags = hsc_dflags hsc_env++ e <- hscIncrementalFrontend always_do_basic_recompilation_check m_tc_result mHscMessage+ mod_summary source_modified mb_old_iface mod_index+ case e of+ -- We didn't need to do any typechecking; the old interface+ -- file on disk was good enough.+ Left iface -> do+ -- Knot tying! See Note [Knot-tying typecheckIface]+ hmi <- liftIO . fixIO $ \hmi' -> do+ let hsc_env' =+ hsc_env {+ hsc_HPT = addToHpt (hsc_HPT hsc_env)+ (ms_mod_name mod_summary) hmi'+ }+ -- NB: This result is actually not that useful+ -- in one-shot mode, since we're not going to do+ -- any further typechecking. It's much more useful+ -- in make mode, since this HMI will go into the HPT.+ details <- genModDetails hsc_env' iface+ return HomeModInfo{+ hm_details = details,+ hm_iface = iface,+ hm_linkable = Nothing }+ return (HscUpToDate, hmi)+ -- We finished type checking. (mb_old_hash is the hash of+ -- the interface that existed on disk; it's possible we had+ -- to retypecheck but the resulting interface is exactly+ -- the same.)+ Right (FrontendTypecheck tc_result, mb_old_hash) -> do+ (status, hmi, no_change)+ <- case ms_hsc_src mod_summary of+ HsSrcFile | hscTarget dflags /= HscNothing ->+ finish hsc_env mod_summary tc_result mb_old_hash+ _ ->+ finishTypecheckOnly hsc_env mod_summary tc_result mb_old_hash+ liftIO $ hscMaybeWriteIface dflags (hm_iface hmi) no_change mod_summary+ return (status, hmi)++-- Generates and writes out the final interface for a typecheck.+finishTypecheckOnly :: HscEnv+ -> ModSummary+ -> TcGblEnv+ -> Maybe Fingerprint+ -> Hsc (HscStatus, HomeModInfo, Bool)+finishTypecheckOnly hsc_env summary tc_result mb_old_hash = do+ let dflags = hsc_dflags hsc_env+ (iface, changed, details) <- liftIO $ hscSimpleIface hsc_env tc_result mb_old_hash+ let hsc_status =+ case (hscTarget dflags, ms_hsc_src summary) of+ (HscNothing, _) -> HscNotGeneratingCode+ (_, HsBootFile) -> HscUpdateBoot+ (_, HsigFile) -> HscUpdateSig+ _ -> panic "finishTypecheckOnly"+ return (hsc_status,+ HomeModInfo{ hm_details = details,+ hm_iface = iface,+ hm_linkable = Nothing },+ changed)++-- Runs the post-typechecking frontend (desugar and simplify),+-- and then generates and writes out the final interface. We want+-- to write the interface AFTER simplification so we can get+-- as up-to-date and good unfoldings and other info as possible+-- in the interface file. This is only ever run for HsSrcFile,+-- and NOT for HscNothing.+finish :: HscEnv+ -> ModSummary+ -> TcGblEnv+ -> Maybe Fingerprint+ -> Hsc (HscStatus, HomeModInfo, Bool)+finish hsc_env summary tc_result mb_old_hash = do+ let dflags = hsc_dflags hsc_env+ MASSERT( ms_hsc_src summary == HsSrcFile )+ MASSERT( hscTarget dflags /= HscNothing )+ guts0 <- hscDesugar' (ms_location summary) tc_result+ guts <- hscSimplify' guts0+ (iface, changed, details, cgguts) <- liftIO $ hscNormalIface hsc_env guts mb_old_hash++ return (HscRecomp cgguts summary,+ HomeModInfo{ hm_details = details,+ hm_iface = iface,+ hm_linkable = Nothing },+ changed)++hscMaybeWriteIface :: DynFlags -> ModIface -> Bool -> ModSummary -> IO ()+hscMaybeWriteIface dflags iface changed summary =+ let force_write_interface = gopt Opt_WriteInterface dflags+ write_interface = case hscTarget dflags of+ HscNothing -> False+ HscInterpreted -> False+ _ -> True+ in when (write_interface || force_write_interface) $+ hscWriteIface dflags iface changed summary++--------------------------------------------------------------+-- NoRecomp handlers+--------------------------------------------------------------++-- NB: this must be knot-tied appropriately, see hscIncrementalCompile+genModDetails :: HscEnv -> ModIface -> IO ModDetails+genModDetails hsc_env old_iface+ = do+ new_details <- {-# SCC "tcRnIface" #-}+ initIfaceLoad hsc_env (typecheckIface old_iface)+ dumpIfaceStats hsc_env+ return new_details++--------------------------------------------------------------+-- Progress displayers.+--------------------------------------------------------------++oneShotMsg :: HscEnv -> RecompileRequired -> IO ()+oneShotMsg hsc_env recomp =+ case recomp of+ UpToDate ->+ compilationProgressMsg (hsc_dflags hsc_env) $+ "compilation IS NOT required"+ _ ->+ return ()++batchMsg :: Messager+batchMsg hsc_env mod_index recomp mod_summary =+ case recomp of+ MustCompile -> showMsg "Compiling " ""+ UpToDate+ | verbosity (hsc_dflags hsc_env) >= 2 -> showMsg "Skipping " ""+ | otherwise -> return ()+ RecompBecause reason -> showMsg "Compiling " (" [" ++ reason ++ "]")+ where+ dflags = hsc_dflags hsc_env+ showMsg msg reason =+ compilationProgressMsg dflags $+ (showModuleIndex mod_index +++ msg ++ showModMsg dflags (hscTarget dflags)+ (recompileRequired recomp) mod_summary)+ ++ reason++--------------------------------------------------------------+-- FrontEnds+--------------------------------------------------------------++-- | Given a 'ModSummary', parses and typechecks it, returning the+-- 'TcGblEnv' resulting from type-checking.+hscFileFrontEnd :: ModSummary -> Hsc TcGblEnv+hscFileFrontEnd mod_summary = hscTypecheck False mod_summary Nothing++--------------------------------------------------------------+-- Safe Haskell+--------------------------------------------------------------++-- Note [Safe Haskell Trust Check]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Safe Haskell checks that an import is trusted according to the following+-- rules for an import of module M that resides in Package P:+--+-- * If M is recorded as Safe and all its trust dependencies are OK+-- then M is considered safe.+-- * If M is recorded as Trustworthy and P is considered trusted and+-- all M's trust dependencies are OK then M is considered safe.+--+-- By trust dependencies we mean that the check is transitive. So if+-- a module M that is Safe relies on a module N that is trustworthy,+-- importing module M will first check (according to the second case)+-- that N is trusted before checking M is trusted.+--+-- This is a minimal description, so please refer to the user guide+-- for more details. The user guide is also considered the authoritative+-- source in this matter, not the comments or code.+++-- Note [Safe Haskell Inference]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Safe Haskell does Safe inference on modules that don't have any specific+-- safe haskell mode flag. The basic approach to this is:+-- * When deciding if we need to do a Safe language check, treat+-- an unmarked module as having -XSafe mode specified.+-- * For checks, don't throw errors but return them to the caller.+-- * Caller checks if there are errors:+-- * For modules explicitly marked -XSafe, we throw the errors.+-- * For unmarked modules (inference mode), we drop the errors+-- and mark the module as being Unsafe.+--+-- It used to be that we only did safe inference on modules that had no Safe+-- Haskell flags, but now we perform safe inference on all modules as we want+-- to allow users to set the `-Wsafe`, `-Wunsafe` and+-- `-Wtrustworthy-safe` flags on Trustworthy and Unsafe modules so that a+-- user can ensure their assumptions are correct and see reasons for why a+-- module is safe or unsafe.+--+-- This is tricky as we must be careful when we should throw an error compared+-- to just warnings. For checking safe imports we manage it as two steps. First+-- we check any imports that are required to be safe, then we check all other+-- imports to see if we can infer them to be safe.+++-- | Check that the safe imports of the module being compiled are valid.+-- If not we either issue a compilation error if the module is explicitly+-- using Safe Haskell, or mark the module as unsafe if we're in safe+-- inference mode.+hscCheckSafeImports :: TcGblEnv -> Hsc TcGblEnv+hscCheckSafeImports tcg_env = do+ dflags <- getDynFlags+ tcg_env' <- checkSafeImports dflags tcg_env+ checkRULES dflags tcg_env'++ where+ checkRULES dflags tcg_env' = do+ case safeLanguageOn dflags of+ True -> do+ -- XSafe: we nuke user written RULES+ logWarnings $ warns dflags (tcg_rules tcg_env')+ return tcg_env' { tcg_rules = [] }+ False+ -- SafeInferred: user defined RULES, so not safe+ | safeInferOn dflags && not (null $ tcg_rules tcg_env')+ -> markUnsafeInfer tcg_env' $ warns dflags (tcg_rules tcg_env')++ -- Trustworthy OR SafeInferred: with no RULES+ | otherwise+ -> return tcg_env'++ warns dflags rules = listToBag $ map (warnRules dflags) rules+ warnRules dflags (L loc (HsRule n _ _ _ _ _ _)) =+ mkPlainWarnMsg dflags loc $+ text "Rule \"" <> ftext (snd $ unLoc n) <> text "\" ignored" $+$+ text "User defined rules are disabled under Safe Haskell"++-- | Validate that safe imported modules are actually safe. For modules in the+-- HomePackage (the package the module we are compiling in resides) this just+-- involves checking its trust type is 'Safe' or 'Trustworthy'. For modules+-- that reside in another package we also must check that the external pacakge+-- is trusted. See the Note [Safe Haskell Trust Check] above for more+-- information.+--+-- The code for this is quite tricky as the whole algorithm is done in a few+-- distinct phases in different parts of the code base. See+-- RnNames.rnImportDecl for where package trust dependencies for a module are+-- collected and unioned. Specifically see the Note [RnNames . Tracking Trust+-- Transitively] and the Note [RnNames . Trust Own Package].+checkSafeImports :: DynFlags -> TcGblEnv -> Hsc TcGblEnv+checkSafeImports dflags tcg_env+ = do+ imps <- mapM condense imports'+ let (safeImps, regImps) = partition (\(_,_,s) -> s) imps++ -- We want to use the warning state specifically for detecting if safe+ -- inference has failed, so store and clear any existing warnings.+ oldErrs <- getWarnings+ clearWarnings++ -- Check safe imports are correct+ safePkgs <- S.fromList <$> mapMaybeM checkSafe safeImps+ safeErrs <- getWarnings+ clearWarnings++ -- Check non-safe imports are correct if inferring safety+ -- See the Note [Safe Haskell Inference]+ (infErrs, infPkgs) <- case (safeInferOn dflags) of+ False -> return (emptyBag, S.empty)+ True -> do infPkgs <- S.fromList <$> mapMaybeM checkSafe regImps+ infErrs <- getWarnings+ clearWarnings+ return (infErrs, infPkgs)++ -- restore old errors+ logWarnings oldErrs++ case (isEmptyBag safeErrs) of+ -- Failed safe check+ False -> liftIO . throwIO . mkSrcErr $ safeErrs++ -- Passed safe check+ True -> do+ let infPassed = isEmptyBag infErrs+ tcg_env' <- case (not infPassed) of+ True -> markUnsafeInfer tcg_env infErrs+ False -> return tcg_env+ when (packageTrustOn dflags) $ checkPkgTrust dflags pkgReqs+ let newTrust = pkgTrustReqs safePkgs infPkgs infPassed+ return tcg_env' { tcg_imports = impInfo `plusImportAvails` newTrust }++ where+ impInfo = tcg_imports tcg_env -- ImportAvails+ imports = imp_mods impInfo -- ImportedMods+ imports1 = moduleEnvToList imports -- (Module, [ImportedBy])+ imports' = map (fmap importedByUser) imports1 -- (Module, [ImportedModsVal])+ pkgReqs = imp_trust_pkgs impInfo -- [UnitId]++ condense :: (Module, [ImportedModsVal]) -> Hsc (Module, SrcSpan, IsSafeImport)+ condense (_, []) = panic "HscMain.condense: Pattern match failure!"+ condense (m, x:xs) = do imv <- foldlM cond' x xs+ return (m, imv_span imv, imv_is_safe imv)++ -- ImportedModsVal = (ModuleName, Bool, SrcSpan, IsSafeImport)+ cond' :: ImportedModsVal -> ImportedModsVal -> Hsc ImportedModsVal+ cond' v1 v2+ | imv_is_safe v1 /= imv_is_safe v2+ = throwErrors $ unitBag $ mkPlainErrMsg dflags (imv_span v1)+ (text "Module" <+> ppr (imv_name v1) <+>+ (text $ "is imported both as a safe and unsafe import!"))+ | otherwise+ = return v1++ -- easier interface to work with+ checkSafe :: (Module, SrcSpan, a) -> Hsc (Maybe InstalledUnitId)+ checkSafe (m, l, _) = fst `fmap` hscCheckSafe' dflags m l++ -- what pkg's to add to our trust requirements+ pkgTrustReqs :: Set InstalledUnitId -> Set InstalledUnitId -> Bool -> ImportAvails+ pkgTrustReqs req inf infPassed | safeInferOn dflags+ && safeHaskell dflags == Sf_None && infPassed+ = emptyImportAvails {+ imp_trust_pkgs = req `S.union` inf+ }+ pkgTrustReqs _ _ _ | safeHaskell dflags == Sf_Unsafe+ = emptyImportAvails+ pkgTrustReqs req _ _ = emptyImportAvails { imp_trust_pkgs = req }++-- | Check that a module is safe to import.+--+-- We return True to indicate the import is safe and False otherwise+-- although in the False case an exception may be thrown first.+hscCheckSafe :: HscEnv -> Module -> SrcSpan -> IO Bool+hscCheckSafe hsc_env m l = runHsc hsc_env $ do+ dflags <- getDynFlags+ pkgs <- snd `fmap` hscCheckSafe' dflags m l+ when (packageTrustOn dflags) $ checkPkgTrust dflags pkgs+ errs <- getWarnings+ return $ isEmptyBag errs++-- | Return if a module is trusted and the pkgs it depends on to be trusted.+hscGetSafe :: HscEnv -> Module -> SrcSpan -> IO (Bool, Set InstalledUnitId)+hscGetSafe hsc_env m l = runHsc hsc_env $ do+ dflags <- getDynFlags+ (self, pkgs) <- hscCheckSafe' dflags m l+ good <- isEmptyBag `fmap` getWarnings+ clearWarnings -- don't want them printed...+ let pkgs' | Just p <- self = S.insert p pkgs+ | otherwise = pkgs+ return (good, pkgs')++-- | Is a module trusted? If not, throw or log errors depending on the type.+-- Return (regardless of trusted or not) if the trust type requires the modules+-- own package be trusted and a list of other packages required to be trusted+-- (these later ones haven't been checked) but the own package trust has been.+hscCheckSafe' :: DynFlags -> Module -> SrcSpan -> Hsc (Maybe InstalledUnitId, Set InstalledUnitId)+hscCheckSafe' dflags m l = do+ (tw, pkgs) <- isModSafe m l+ case tw of+ False -> return (Nothing, pkgs)+ True | isHomePkg m -> return (Nothing, pkgs)+ -- TODO: do we also have to check the trust of the instantiation?+ -- Not necessary if that is reflected in dependencies+ | otherwise -> return (Just $ toInstalledUnitId (moduleUnitId m), pkgs)+ where+ isModSafe :: Module -> SrcSpan -> Hsc (Bool, Set InstalledUnitId)+ isModSafe m l = do+ iface <- lookup' m+ case iface of+ -- can't load iface to check trust!+ Nothing -> throwErrors $ unitBag $ mkPlainErrMsg dflags l+ $ text "Can't load the interface file for" <+> ppr m+ <> text ", to check that it can be safely imported"++ -- got iface, check trust+ Just iface' ->+ let trust = getSafeMode $ mi_trust iface'+ trust_own_pkg = mi_trust_pkg iface'+ -- check module is trusted+ safeM = trust `elem` [Sf_Safe, Sf_Trustworthy]+ -- check package is trusted+ safeP = packageTrusted trust trust_own_pkg m+ -- pkg trust reqs+ pkgRs = S.fromList . map fst $ filter snd $ dep_pkgs $ mi_deps iface'+ -- General errors we throw but Safe errors we log+ errs = case (safeM, safeP) of+ (True, True ) -> emptyBag+ (True, False) -> pkgTrustErr+ (False, _ ) -> modTrustErr+ in do+ logWarnings errs+ return (trust == Sf_Trustworthy, pkgRs)++ where+ pkgTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $+ sep [ ppr (moduleName m)+ <> text ": Can't be safely imported!"+ , text "The package (" <> ppr (moduleUnitId m)+ <> text ") the module resides in isn't trusted."+ ]+ modTrustErr = unitBag $ mkErrMsg dflags l (pkgQual dflags) $+ sep [ ppr (moduleName m)+ <> text ": Can't be safely imported!"+ , text "The module itself isn't safe." ]++ -- | Check the package a module resides in is trusted. Safe compiled+ -- modules are trusted without requiring that their package is trusted. For+ -- trustworthy modules, modules in the home package are trusted but+ -- otherwise we check the package trust flag.+ packageTrusted :: SafeHaskellMode -> Bool -> Module -> Bool+ packageTrusted Sf_None _ _ = False -- shouldn't hit these cases+ packageTrusted Sf_Unsafe _ _ = False -- prefer for completeness.+ packageTrusted _ _ _+ | not (packageTrustOn dflags) = True+ packageTrusted Sf_Safe False _ = True+ packageTrusted _ _ m+ | isHomePkg m = True+ | otherwise = trusted $ getPackageDetails dflags (moduleUnitId m)++ lookup' :: Module -> Hsc (Maybe ModIface)+ lookup' m = do+ hsc_env <- getHscEnv+ hsc_eps <- liftIO $ hscEPS hsc_env+ let pkgIfaceT = eps_PIT hsc_eps+ homePkgT = hsc_HPT hsc_env+ iface = lookupIfaceByModule dflags homePkgT pkgIfaceT m+ -- the 'lookupIfaceByModule' method will always fail when calling from GHCi+ -- as the compiler hasn't filled in the various module tables+ -- so we need to call 'getModuleInterface' to load from disk+ iface' <- case iface of+ Just _ -> return iface+ Nothing -> snd `fmap` (liftIO $ getModuleInterface hsc_env m)+ return iface'+++ isHomePkg :: Module -> Bool+ isHomePkg m+ | thisPackage dflags == moduleUnitId m = True+ | otherwise = False++-- | Check the list of packages are trusted.+checkPkgTrust :: DynFlags -> Set InstalledUnitId -> Hsc ()+checkPkgTrust dflags pkgs =+ case errors of+ [] -> return ()+ _ -> (liftIO . throwIO . mkSrcErr . listToBag) errors+ where+ errors = S.foldr go [] pkgs+ go pkg acc+ | trusted $ getInstalledPackageDetails dflags pkg+ = acc+ | otherwise+ = (:acc) $ mkErrMsg dflags noSrcSpan (pkgQual dflags)+ $ text "The package (" <> ppr pkg <> text ") is required" <>+ text " to be trusted but it isn't!"++-- | Set module to unsafe and (potentially) wipe trust information.+--+-- Make sure to call this method to set a module to inferred unsafe, it should+-- be a central and single failure method. We only wipe the trust information+-- when we aren't in a specific Safe Haskell mode.+--+-- While we only use this for recording that a module was inferred unsafe, we+-- may call it on modules using Trustworthy or Unsafe flags so as to allow+-- warning flags for safety to function correctly. See Note [Safe Haskell+-- Inference].+markUnsafeInfer :: TcGblEnv -> WarningMessages -> Hsc TcGblEnv+markUnsafeInfer tcg_env whyUnsafe = do+ dflags <- getDynFlags++ when (wopt Opt_WarnUnsafe dflags)+ (logWarnings $ unitBag $ makeIntoWarning (Reason Opt_WarnUnsafe) $+ mkPlainWarnMsg dflags (warnUnsafeOnLoc dflags) (whyUnsafe' dflags))++ liftIO $ writeIORef (tcg_safeInfer tcg_env) (False, whyUnsafe)+ -- NOTE: Only wipe trust when not in an explicity safe haskell mode. Other+ -- times inference may be on but we are in Trustworthy mode -- so we want+ -- to record safe-inference failed but not wipe the trust dependencies.+ case safeHaskell dflags == Sf_None of+ True -> return $ tcg_env { tcg_imports = wiped_trust }+ False -> return tcg_env++ where+ wiped_trust = (tcg_imports tcg_env) { imp_trust_pkgs = S.empty }+ pprMod = ppr $ moduleName $ tcg_mod tcg_env+ whyUnsafe' df = vcat [ quotes pprMod <+> text "has been inferred as unsafe!"+ , text "Reason:"+ , nest 4 $ (vcat $ badFlags df) $+$+ (vcat $ pprErrMsgBagWithLoc whyUnsafe) $+$+ (vcat $ badInsts $ tcg_insts tcg_env)+ ]+ badFlags df = concat $ map (badFlag df) unsafeFlagsForInfer+ badFlag df (str,loc,on,_)+ | on df = [mkLocMessage SevOutput (loc df) $+ text str <+> text "is not allowed in Safe Haskell"]+ | otherwise = []+ badInsts insts = concat $ map badInst insts++ checkOverlap (NoOverlap _) = False+ checkOverlap _ = True++ badInst ins | checkOverlap (overlapMode (is_flag ins))+ = [mkLocMessage SevOutput (nameSrcSpan $ getName $ is_dfun ins) $+ ppr (overlapMode $ is_flag ins) <+>+ text "overlap mode isn't allowed in Safe Haskell"]+ | otherwise = []+++-- | Figure out the final correct safe haskell mode+hscGetSafeMode :: TcGblEnv -> Hsc SafeHaskellMode+hscGetSafeMode tcg_env = do+ dflags <- getDynFlags+ liftIO $ finalSafeMode dflags tcg_env++--------------------------------------------------------------+-- Simplifiers+--------------------------------------------------------------++hscSimplify :: HscEnv -> ModGuts -> IO ModGuts+hscSimplify hsc_env modguts = runHsc hsc_env $ hscSimplify' modguts++hscSimplify' :: ModGuts -> Hsc ModGuts+hscSimplify' ds_result = do+ hsc_env <- getHscEnv+ {-# SCC "Core2Core" #-}+ liftIO $ core2core hsc_env ds_result++--------------------------------------------------------------+-- Interface generators+--------------------------------------------------------------++hscSimpleIface :: HscEnv+ -> TcGblEnv+ -> Maybe Fingerprint+ -> IO (ModIface, Bool, ModDetails)+hscSimpleIface hsc_env tc_result mb_old_iface+ = runHsc hsc_env $ hscSimpleIface' tc_result mb_old_iface++hscSimpleIface' :: TcGblEnv+ -> Maybe Fingerprint+ -> Hsc (ModIface, Bool, ModDetails)+hscSimpleIface' tc_result mb_old_iface = do+ hsc_env <- getHscEnv+ details <- liftIO $ mkBootModDetailsTc hsc_env tc_result+ safe_mode <- hscGetSafeMode tc_result+ (new_iface, no_change)+ <- {-# SCC "MkFinalIface" #-}+ liftIO $+ mkIfaceTc hsc_env mb_old_iface safe_mode details tc_result+ -- And the answer is ...+ liftIO $ dumpIfaceStats hsc_env+ return (new_iface, no_change, details)++hscNormalIface :: HscEnv+ -> ModGuts+ -> Maybe Fingerprint+ -> IO (ModIface, Bool, ModDetails, CgGuts)+hscNormalIface hsc_env simpl_result mb_old_iface =+ runHsc hsc_env $ hscNormalIface' simpl_result mb_old_iface++hscNormalIface' :: ModGuts+ -> Maybe Fingerprint+ -> Hsc (ModIface, Bool, ModDetails, CgGuts)+hscNormalIface' simpl_result mb_old_iface = do+ hsc_env <- getHscEnv+ (cg_guts, details) <- {-# SCC "CoreTidy" #-}+ liftIO $ tidyProgram hsc_env simpl_result++ -- BUILD THE NEW ModIface and ModDetails+ -- and emit external core if necessary+ -- This has to happen *after* code gen so that the back-end+ -- info has been set. Not yet clear if it matters waiting+ -- until after code output+ (new_iface, no_change)+ <- {-# SCC "MkFinalIface" #-}+ liftIO $+ mkIface hsc_env mb_old_iface details simpl_result++ liftIO $ dumpIfaceStats hsc_env++ -- Return the prepared code.+ return (new_iface, no_change, details, cg_guts)++--------------------------------------------------------------+-- BackEnd combinators+--------------------------------------------------------------++hscWriteIface :: DynFlags -> ModIface -> Bool -> ModSummary -> IO ()+hscWriteIface dflags iface no_change mod_summary = do+ let ifaceFile = ml_hi_file (ms_location mod_summary)+ unless no_change $+ {-# SCC "writeIface" #-}+ writeIfaceFile dflags ifaceFile iface+ whenGeneratingDynamicToo dflags $ do+ -- TODO: We should do a no_change check for the dynamic+ -- interface file too+ -- TODO: Should handle the dynamic hi filename properly+ let dynIfaceFile = replaceExtension ifaceFile (dynHiSuf dflags)+ dynIfaceFile' = addBootSuffix_maybe (mi_boot iface) dynIfaceFile+ dynDflags = dynamicTooMkDynamicDynFlags dflags+ writeIfaceFile dynDflags dynIfaceFile' iface++-- | Compile to hard-code.+hscGenHardCode :: HscEnv -> CgGuts -> ModSummary -> FilePath+ -> IO (FilePath, Maybe FilePath, [(ForeignSrcLang, FilePath)])+ -- ^ @Just f@ <=> _stub.c is f+hscGenHardCode hsc_env cgguts mod_summary output_filename = do+ let CgGuts{ -- This is the last use of the ModGuts in a compilation.+ -- From now on, we just use the bits we need.+ cg_module = this_mod,+ cg_binds = core_binds,+ cg_tycons = tycons,+ cg_foreign = foreign_stubs0,+ cg_foreign_files = foreign_files,+ cg_dep_pkgs = dependencies,+ cg_hpc_info = hpc_info } = cgguts+ dflags = hsc_dflags hsc_env+ location = ms_location mod_summary+ data_tycons = filter isDataTyCon tycons+ -- cg_tycons includes newtypes, for the benefit of External Core,+ -- but we don't generate any code for newtypes++ -------------------+ -- PREPARE FOR CODE GENERATION+ -- Do saturation and convert to A-normal form+ prepd_binds <- {-# SCC "CorePrep" #-}+ corePrepPgm hsc_env this_mod location+ core_binds data_tycons+ ----------------- Convert to STG ------------------+ (stg_binds, cost_centre_info)+ <- {-# SCC "CoreToStg" #-}+ myCoreToStg dflags this_mod prepd_binds++ let prof_init = profilingInitCode this_mod cost_centre_info+ foreign_stubs = foreign_stubs0 `appendStubC` prof_init++ ------------------ Code generation ------------------++ -- The back-end is streamed: each top-level function goes+ -- from Stg all the way to asm before dealing with the next+ -- top-level function, so showPass isn't very useful here.+ -- Hence we have one showPass for the whole backend, the+ -- next showPass after this will be "Assembler".+ withTiming (pure dflags)+ (text "CodeGen"<+>brackets (ppr this_mod))+ (const ()) $ do+ cmms <- {-# SCC "StgCmm" #-}+ doCodeGen hsc_env this_mod data_tycons+ cost_centre_info+ stg_binds hpc_info++ ------------------ Code output -----------------------+ rawcmms0 <- {-# SCC "cmmToRawCmm" #-}+ cmmToRawCmm dflags cmms++ let dump a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_raw "Raw Cmm"+ (ppr a)+ return a+ rawcmms1 = Stream.mapM dump rawcmms0++ (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps)+ <- {-# SCC "codeOutput" #-}+ codeOutput dflags this_mod output_filename location+ foreign_stubs foreign_files dependencies rawcmms1+ return (output_filename, stub_c_exists, foreign_fps)+++hscInteractive :: HscEnv+ -> CgGuts+ -> ModSummary+ -> IO (Maybe FilePath, CompiledByteCode, [SptEntry])+hscInteractive hsc_env cgguts mod_summary = do+ let dflags = hsc_dflags hsc_env+ let CgGuts{ -- This is the last use of the ModGuts in a compilation.+ -- From now on, we just use the bits we need.+ cg_module = this_mod,+ cg_binds = core_binds,+ cg_tycons = tycons,+ cg_foreign = foreign_stubs,+ cg_modBreaks = mod_breaks,+ cg_spt_entries = spt_entries } = cgguts++ location = ms_location mod_summary+ data_tycons = filter isDataTyCon tycons+ -- cg_tycons includes newtypes, for the benefit of External Core,+ -- but we don't generate any code for newtypes++ -------------------+ -- PREPARE FOR CODE GENERATION+ -- Do saturation and convert to A-normal form+ prepd_binds <- {-# SCC "CorePrep" #-}+ corePrepPgm hsc_env this_mod location core_binds data_tycons+ ----------------- Generate byte code ------------------+ comp_bc <- byteCodeGen hsc_env this_mod prepd_binds data_tycons mod_breaks+ ------------------ Create f-x-dynamic C-side stuff -----+ (_istub_h_exists, istub_c_exists)+ <- outputForeignStubs dflags this_mod location foreign_stubs+ return (istub_c_exists, comp_bc, spt_entries)++------------------------------++hscCompileCmmFile :: HscEnv -> FilePath -> FilePath -> IO ()+hscCompileCmmFile hsc_env filename output_filename = runHsc hsc_env $ do+ let dflags = hsc_dflags hsc_env+ cmm <- ioMsgMaybe $ parseCmmFile dflags filename+ liftIO $ do+ us <- mkSplitUniqSupply 'S'+ let initTopSRT = initUs_ us emptySRT+ dumpIfSet_dyn dflags Opt_D_dump_cmm_verbose "Parsed Cmm" (ppr cmm)+ (_, cmmgroup) <- cmmPipeline hsc_env initTopSRT cmm+ rawCmms <- cmmToRawCmm dflags (Stream.yield cmmgroup)+ let -- Make up a module name to give the NCG. We can't pass bottom here+ -- lest we reproduce #11784.+ mod_name = mkModuleName $ "Cmm$" ++ FilePath.takeFileName filename+ cmm_mod = mkModule (thisPackage dflags) mod_name+ _ <- codeOutput dflags cmm_mod output_filename no_loc NoStubs [] []+ rawCmms+ return ()+ where+ no_loc = ModLocation{ ml_hs_file = Just filename,+ ml_hi_file = panic "hscCompileCmmFile: no hi file",+ ml_obj_file = panic "hscCompileCmmFile: no obj file" }++-------------------- Stuff for new code gen ---------------------++doCodeGen :: HscEnv -> Module -> [TyCon]+ -> CollectedCCs+ -> [StgTopBinding]+ -> HpcInfo+ -> IO (Stream IO CmmGroup ())+ -- Note we produce a 'Stream' of CmmGroups, so that the+ -- backend can be run incrementally. Otherwise it generates all+ -- the C-- up front, which has a significant space cost.+doCodeGen hsc_env this_mod data_tycons+ cost_centre_info stg_binds hpc_info = do+ let dflags = hsc_dflags hsc_env++ let cmm_stream :: Stream IO CmmGroup ()+ cmm_stream = {-# SCC "StgCmm" #-}+ StgCmm.codeGen dflags this_mod data_tycons+ cost_centre_info stg_binds hpc_info++ -- codegen consumes a stream of CmmGroup, and produces a new+ -- stream of CmmGroup (not necessarily synchronised: one+ -- CmmGroup on input may produce many CmmGroups on output due+ -- to proc-point splitting).++ let dump1 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm_from_stg+ "Cmm produced by codegen" (ppr a)+ return a++ ppr_stream1 = Stream.mapM dump1 cmm_stream++ -- We are building a single SRT for the entire module, so+ -- we must thread it through all the procedures as we cps-convert them.+ us <- mkSplitUniqSupply 'S'++ -- When splitting, we generate one SRT per split chunk, otherwise+ -- we generate one SRT for the whole module.+ let+ pipeline_stream+ | gopt Opt_SplitObjs dflags || gopt Opt_SplitSections dflags ||+ osSubsectionsViaSymbols (platformOS (targetPlatform dflags))+ = {-# SCC "cmmPipeline" #-}+ let run_pipeline us cmmgroup = do+ let (topSRT', us') = initUs us emptySRT+ (topSRT, cmmgroup) <- cmmPipeline hsc_env topSRT' cmmgroup+ let srt | isEmptySRT topSRT = []+ | otherwise = srtToData topSRT+ return (us', srt ++ cmmgroup)++ in do _ <- Stream.mapAccumL run_pipeline us ppr_stream1+ return ()++ | otherwise+ = {-# SCC "cmmPipeline" #-}+ let initTopSRT = initUs_ us emptySRT+ run_pipeline = cmmPipeline hsc_env+ in do topSRT <- Stream.mapAccumL run_pipeline initTopSRT ppr_stream1+ Stream.yield (srtToData topSRT)++ let+ dump2 a = do dumpIfSet_dyn dflags Opt_D_dump_cmm+ "Output Cmm" (ppr a)+ return a++ ppr_stream2 = Stream.mapM dump2 pipeline_stream++ return ppr_stream2++++myCoreToStg :: DynFlags -> Module -> CoreProgram+ -> IO ( [StgTopBinding] -- output program+ , CollectedCCs) -- cost centre info (declared and used)+myCoreToStg dflags this_mod prepd_binds = do+ let stg_binds+ = {-# SCC "Core2Stg" #-}+ coreToStg dflags this_mod prepd_binds++ (stg_binds2, cost_centre_info)+ <- {-# SCC "Stg2Stg" #-}+ stg2stg dflags this_mod stg_binds++ return (stg_binds2, cost_centre_info)+++{- **********************************************************************+%* *+\subsection{Compiling a do-statement}+%* *+%********************************************************************* -}++{-+When the UnlinkedBCOExpr is linked you get an HValue of type *IO [HValue]* When+you run it you get a list of HValues that should be the same length as the list+of names; add them to the ClosureEnv.++A naked expression returns a singleton Name [it]. The stmt is lifted into the+IO monad as explained in Note [Interactively-bound Ids in GHCi] in HscTypes+-}++-- | Compile a stmt all the way to an HValue, but don't run it+--+-- We return Nothing to indicate an empty statement (or comment only), not a+-- parse error.+hscStmt :: HscEnv -> String -> IO (Maybe ([Id], ForeignHValue, FixityEnv))+hscStmt hsc_env stmt = hscStmtWithLocation hsc_env stmt "<interactive>" 1++-- | Compile a stmt all the way to an HValue, but don't run it+--+-- We return Nothing to indicate an empty statement (or comment only), not a+-- parse error.+hscStmtWithLocation :: HscEnv+ -> String -- ^ The statement+ -> String -- ^ The source+ -> Int -- ^ Starting line+ -> IO ( Maybe ([Id]+ , ForeignHValue {- IO [HValue] -}+ , FixityEnv))+hscStmtWithLocation hsc_env0 stmt source linenumber =+ runInteractiveHsc hsc_env0 $ do+ maybe_stmt <- hscParseStmtWithLocation source linenumber stmt+ case maybe_stmt of+ Nothing -> return Nothing++ Just parsed_stmt -> do+ hsc_env <- getHscEnv+ liftIO $ hscParsedStmt hsc_env parsed_stmt++hscParsedStmt :: HscEnv+ -> GhciLStmt RdrName -- ^ The parsed statement+ -> IO ( Maybe ([Id]+ , ForeignHValue {- IO [HValue] -}+ , FixityEnv))+hscParsedStmt hsc_env stmt = runInteractiveHsc hsc_env $ do+ -- Rename and typecheck it+ (ids, tc_expr, fix_env) <- ioMsgMaybe $ tcRnStmt hsc_env stmt++ -- Desugar it+ ds_expr <- ioMsgMaybe $ deSugarExpr hsc_env tc_expr+ liftIO (lintInteractiveExpr "desugar expression" hsc_env ds_expr)+ handleWarnings++ -- Then code-gen, and link it+ -- It's important NOT to have package 'interactive' as thisUnitId+ -- for linking, else we try to link 'main' and can't find it.+ -- Whereas the linker already knows to ignore 'interactive'+ let src_span = srcLocSpan interactiveSrcLoc+ hval <- liftIO $ hscCompileCoreExpr hsc_env src_span ds_expr++ return $ Just (ids, hval, fix_env)++-- | Compile a decls+hscDecls :: HscEnv+ -> String -- ^ The statement+ -> IO ([TyThing], InteractiveContext)+hscDecls hsc_env str = hscDeclsWithLocation hsc_env str "<interactive>" 1++-- | Compile a decls+hscDeclsWithLocation :: HscEnv+ -> String -- ^ The statement+ -> String -- ^ The source+ -> Int -- ^ Starting line+ -> IO ([TyThing], InteractiveContext)+hscDeclsWithLocation hsc_env0 str source linenumber =+ runInteractiveHsc hsc_env0 $ do+ L _ (HsModule{ hsmodDecls = decls }) <-+ hscParseThingWithLocation source linenumber parseModule str++ {- Rename and typecheck it -}+ hsc_env <- getHscEnv+ tc_gblenv <- ioMsgMaybe $ tcRnDeclsi hsc_env decls++ {- Grab the new instances -}+ -- We grab the whole environment because of the overlapping that may have+ -- been done. See the notes at the definition of InteractiveContext+ -- (ic_instances) for more details.+ let defaults = tcg_default tc_gblenv++ {- Desugar it -}+ -- We use a basically null location for iNTERACTIVE+ let iNTERACTIVELoc = ModLocation{ ml_hs_file = Nothing,+ ml_hi_file = panic "hsDeclsWithLocation:ml_hi_file",+ ml_obj_file = panic "hsDeclsWithLocation:ml_hi_file"}+ ds_result <- hscDesugar' iNTERACTIVELoc tc_gblenv++ {- Simplify -}+ simpl_mg <- liftIO $ hscSimplify hsc_env ds_result++ {- Tidy -}+ (tidy_cg, mod_details) <- liftIO $ tidyProgram hsc_env simpl_mg++ let !CgGuts{ cg_module = this_mod,+ cg_binds = core_binds,+ cg_tycons = tycons,+ cg_modBreaks = mod_breaks } = tidy_cg++ !ModDetails { md_insts = cls_insts+ , md_fam_insts = fam_insts } = mod_details+ -- Get the *tidied* cls_insts and fam_insts++ data_tycons = filter isDataTyCon tycons++ {- Prepare For Code Generation -}+ -- Do saturation and convert to A-normal form+ prepd_binds <- {-# SCC "CorePrep" #-}+ liftIO $ corePrepPgm hsc_env this_mod iNTERACTIVELoc core_binds data_tycons++ {- Generate byte code -}+ cbc <- liftIO $ byteCodeGen hsc_env this_mod+ prepd_binds data_tycons mod_breaks++ let src_span = srcLocSpan interactiveSrcLoc+ liftIO $ linkDecls hsc_env src_span cbc++ {- Load static pointer table entries -}+ liftIO $ hscAddSptEntries hsc_env (cg_spt_entries tidy_cg)++ let tcs = filterOut isImplicitTyCon (mg_tcs simpl_mg)+ patsyns = mg_patsyns simpl_mg++ ext_ids = [ id | id <- bindersOfBinds core_binds+ , isExternalName (idName id)+ , not (isDFunId id || isImplicitId id) ]+ -- We only need to keep around the external bindings+ -- (as decided by TidyPgm), since those are the only ones+ -- that might later be looked up by name. But we can exclude+ -- - DFunIds, which are in 'cls_insts' (see Note [ic_tythings] in HscTypes+ -- - Implicit Ids, which are implicit in tcs+ -- c.f. TcRnDriver.runTcInteractive, which reconstructs the TypeEnv++ new_tythings = map AnId ext_ids ++ map ATyCon tcs ++ map (AConLike . PatSynCon) patsyns+ ictxt = hsc_IC hsc_env+ -- See Note [Fixity declarations in GHCi]+ fix_env = tcg_fix_env tc_gblenv+ new_ictxt = extendInteractiveContext ictxt new_tythings cls_insts+ fam_insts defaults fix_env+ return (new_tythings, new_ictxt)++-- | Load the given static-pointer table entries into the interpreter.+-- See Note [Grand plan for static forms] in StaticPtrTable.+hscAddSptEntries :: HscEnv -> [SptEntry] -> IO ()+hscAddSptEntries hsc_env entries = do+ let add_spt_entry :: SptEntry -> IO ()+ add_spt_entry (SptEntry i fpr) = do+ val <- getHValue hsc_env (idName i)+ addSptEntry hsc_env fpr val+ mapM_ add_spt_entry entries++{-+ Note [Fixity declarations in GHCi]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++ To support fixity declarations on types defined within GHCi (as requested+ in #10018) we record the fixity environment in InteractiveContext.+ When we want to evaluate something TcRnDriver.runTcInteractive pulls out this+ fixity environment and uses it to initialize the global typechecker environment.+ After the typechecker has finished its business, an updated fixity environment+ (reflecting whatever fixity declarations were present in the statements we+ passed it) will be returned from hscParsedStmt. This is passed to+ updateFixityEnv, which will stuff it back into InteractiveContext, to be+ used in evaluating the next statement.++-}++hscImport :: HscEnv -> String -> IO (ImportDecl RdrName)+hscImport hsc_env str = runInteractiveHsc hsc_env $ do+ (L _ (HsModule{hsmodImports=is})) <-+ hscParseThing parseModule str+ case is of+ [L _ i] -> return i+ _ -> liftIO $ throwOneError $+ mkPlainErrMsg (hsc_dflags hsc_env) noSrcSpan $+ text "parse error in import declaration"++-- | Typecheck an expression (but don't run it)+hscTcExpr :: HscEnv+ -> TcRnExprMode+ -> String -- ^ The expression+ -> IO Type+hscTcExpr hsc_env0 mode expr = runInteractiveHsc hsc_env0 $ do+ hsc_env <- getHscEnv+ parsed_expr <- hscParseExpr expr+ ioMsgMaybe $ tcRnExpr hsc_env mode parsed_expr++-- | Find the kind of a type+-- Currently this does *not* generalise the kinds of the type+hscKcType+ :: HscEnv+ -> Bool -- ^ Normalise the type+ -> String -- ^ The type as a string+ -> IO (Type, Kind) -- ^ Resulting type (possibly normalised) and kind+hscKcType hsc_env0 normalise str = runInteractiveHsc hsc_env0 $ do+ hsc_env <- getHscEnv+ ty <- hscParseType str+ ioMsgMaybe $ tcRnType hsc_env normalise ty++hscParseExpr :: String -> Hsc (LHsExpr RdrName)+hscParseExpr expr = do+ hsc_env <- getHscEnv+ maybe_stmt <- hscParseStmt expr+ case maybe_stmt of+ Just (L _ (BodyStmt expr _ _ _)) -> return expr+ _ -> throwErrors $ unitBag $ mkPlainErrMsg (hsc_dflags hsc_env) noSrcSpan+ (text "not an expression:" <+> quotes (text expr))++hscParseStmt :: String -> Hsc (Maybe (GhciLStmt RdrName))+hscParseStmt = hscParseThing parseStmt++hscParseStmtWithLocation :: String -> Int -> String+ -> Hsc (Maybe (GhciLStmt RdrName))+hscParseStmtWithLocation source linenumber stmt =+ hscParseThingWithLocation source linenumber parseStmt stmt++hscParseType :: String -> Hsc (LHsType RdrName)+hscParseType = hscParseThing parseType++hscParseIdentifier :: HscEnv -> String -> IO (Located RdrName)+hscParseIdentifier hsc_env str =+ runInteractiveHsc hsc_env $ hscParseThing parseIdentifier str++hscParseThing :: (Outputable thing, Data thing)+ => Lexer.P thing -> String -> Hsc thing+hscParseThing = hscParseThingWithLocation "<interactive>" 1++hscParseThingWithLocation :: (Outputable thing, Data thing) => String -> Int+ -> Lexer.P thing -> String -> Hsc thing+hscParseThingWithLocation source linenumber parser str+ = withTiming getDynFlags+ (text "Parser [source]")+ (const ()) $ {-# SCC "Parser" #-} do+ dflags <- getDynFlags++ let buf = stringToStringBuffer str+ loc = mkRealSrcLoc (fsLit source) linenumber 1++ case unP parser (mkPState dflags buf loc) of+ PFailed span err -> do+ let msg = mkPlainErrMsg dflags span err+ throwErrors $ unitBag msg++ POk pst thing -> do+ logWarningsReportErrors (getMessages pst dflags)+ liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed "Parser" (ppr thing)+ liftIO $ dumpIfSet_dyn dflags Opt_D_dump_parsed_ast "Parser AST" $+ text $ showAstData NoBlankSrcSpan thing+ return thing+++{- **********************************************************************+%* *+ Desugar, simplify, convert to bytecode, and link an expression+%* *+%********************************************************************* -}++hscCompileCoreExpr :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue+hscCompileCoreExpr hsc_env =+ lookupHook hscCompileCoreExprHook hscCompileCoreExpr' (hsc_dflags hsc_env) hsc_env++hscCompileCoreExpr' :: HscEnv -> SrcSpan -> CoreExpr -> IO ForeignHValue+hscCompileCoreExpr' hsc_env srcspan ds_expr+ = do { let dflags = hsc_dflags hsc_env++ {- Simplify it -}+ ; simpl_expr <- simplifyExpr dflags ds_expr++ {- Tidy it (temporary, until coreSat does cloning) -}+ ; let tidy_expr = tidyExpr emptyTidyEnv simpl_expr++ {- Prepare for codegen -}+ ; prepd_expr <- corePrepExpr dflags hsc_env tidy_expr++ {- Lint if necessary -}+ ; lintInteractiveExpr "hscCompileExpr" hsc_env prepd_expr++ {- Convert to BCOs -}+ ; bcos <- coreExprToBCOs hsc_env+ (icInteractiveModule (hsc_IC hsc_env)) prepd_expr++ {- link it -}+ ; hval <- linkExpr hsc_env srcspan bcos++ ; return hval }+++{- **********************************************************************+%* *+ Statistics on reading interfaces+%* *+%********************************************************************* -}++dumpIfaceStats :: HscEnv -> IO ()+dumpIfaceStats hsc_env = do+ eps <- readIORef (hsc_EPS hsc_env)+ dumpIfSet dflags (dump_if_trace || dump_rn_stats)+ "Interface statistics"+ (ifaceStats eps)+ where+ dflags = hsc_dflags hsc_env+ dump_rn_stats = dopt Opt_D_dump_rn_stats dflags+ dump_if_trace = dopt Opt_D_dump_if_trace dflags+++{- **********************************************************************+%* *+ Progress Messages: Module i of n+%* *+%********************************************************************* -}++showModuleIndex :: (Int, Int) -> String+showModuleIndex (i,n) = "[" ++ padded ++ " of " ++ n_str ++ "] "+ where+ n_str = show n+ i_str = show i+ padded = replicate (length n_str - length i_str) ' ' ++ i_str
+ main/HscStats.hs view
@@ -0,0 +1,180 @@+-- |+-- Statistics for per-module compilations+--+-- (c) The GRASP/AQUA Project, Glasgow University, 1993-1998+--++{-# LANGUAGE FlexibleContexts #-}++module HscStats ( ppSourceStats ) where++import Bag+import HsSyn+import Outputable+import RdrName+import SrcLoc+import Util++import Data.Char+import Data.Foldable (foldl')++-- | Source Statistics+ppSourceStats :: Bool -> Located (HsModule RdrName) -> SDoc+ppSourceStats short (L _ (HsModule _ exports imports ldecls _ _))+ = (if short then hcat else vcat)+ (map pp_val+ [("ExportAll ", export_all), -- 1 if no export list+ ("ExportDecls ", export_ds),+ ("ExportModules ", export_ms),+ ("Imports ", imp_no),+ (" ImpSafe ", imp_safe),+ (" ImpQual ", imp_qual),+ (" ImpAs ", imp_as),+ (" ImpAll ", imp_all),+ (" ImpPartial ", imp_partial),+ (" ImpHiding ", imp_hiding),+ ("FixityDecls ", fixity_sigs),+ ("DefaultDecls ", default_ds),+ ("TypeDecls ", type_ds),+ ("DataDecls ", data_ds),+ ("NewTypeDecls ", newt_ds),+ ("TypeFamilyDecls ", type_fam_ds),+ ("DataConstrs ", data_constrs),+ ("DataDerivings ", data_derivs),+ ("ClassDecls ", class_ds),+ ("ClassMethods ", class_method_ds),+ ("DefaultMethods ", default_method_ds),+ ("InstDecls ", inst_ds),+ ("InstMethods ", inst_method_ds),+ ("InstType ", inst_type_ds),+ ("InstData ", inst_data_ds),+ ("TypeSigs ", bind_tys),+ ("ClassOpSigs ", generic_sigs),+ ("ValBinds ", val_bind_ds),+ ("FunBinds ", fn_bind_ds),+ ("PatSynBinds ", patsyn_ds),+ ("InlineMeths ", method_inlines),+ ("InlineBinds ", bind_inlines),+ ("SpecialisedMeths ", method_specs),+ ("SpecialisedBinds ", bind_specs)+ ])+ where+ decls = map unLoc ldecls++ pp_val (_, 0) = empty+ pp_val (str, n)+ | not short = hcat [text str, int n]+ | otherwise = hcat [text (trim str), equals, int n, semi]++ trim ls = takeWhile (not.isSpace) (dropWhile isSpace ls)++ (fixity_sigs, bind_tys, bind_specs, bind_inlines, generic_sigs)+ = count_sigs [d | SigD d <- decls]+ -- NB: this omits fixity decls on local bindings and+ -- in class decls. ToDo++ tycl_decls = [d | TyClD d <- decls]+ (class_ds, type_ds, data_ds, newt_ds, type_fam_ds) =+ countTyClDecls tycl_decls++ inst_decls = [d | InstD d <- decls]+ inst_ds = length inst_decls+ default_ds = count (\ x -> case x of { DefD{} -> True; _ -> False}) decls+ val_decls = [d | ValD d <- decls]++ real_exports = case exports of { Nothing -> []; Just (L _ es) -> es }+ n_exports = length real_exports+ export_ms = count (\ e -> case unLoc e of { IEModuleContents{} -> True;_ -> False})+ real_exports+ export_ds = n_exports - export_ms+ export_all = case exports of { Nothing -> 1; _ -> 0 }++ (val_bind_ds, fn_bind_ds, patsyn_ds)+ = sum3 (map count_bind val_decls)++ (imp_no, imp_safe, imp_qual, imp_as, imp_all, imp_partial, imp_hiding)+ = sum7 (map import_info imports)+ (data_constrs, data_derivs)+ = sum2 (map data_info tycl_decls)+ (class_method_ds, default_method_ds)+ = sum2 (map class_info tycl_decls)+ (inst_method_ds, method_specs, method_inlines, inst_type_ds, inst_data_ds)+ = sum5 (map inst_info inst_decls)++ count_bind (PatBind { pat_lhs = L _ (VarPat _) }) = (1,0,0)+ count_bind (PatBind {}) = (0,1,0)+ count_bind (FunBind {}) = (0,1,0)+ count_bind (PatSynBind {}) = (0,0,1)+ count_bind b = pprPanic "count_bind: Unhandled binder" (ppr b)++ count_sigs sigs = sum5 (map sig_info sigs)++ sig_info (FixSig {}) = (1,0,0,0,0)+ sig_info (TypeSig {}) = (0,1,0,0,0)+ sig_info (SpecSig {}) = (0,0,1,0,0)+ sig_info (InlineSig {}) = (0,0,0,1,0)+ sig_info (ClassOpSig {}) = (0,0,0,0,1)+ sig_info _ = (0,0,0,0,0)++ import_info (L _ (ImportDecl { ideclSafe = safe, ideclQualified = qual+ , ideclAs = as, ideclHiding = spec }))+ = add7 (1, safe_info safe, qual_info qual, as_info as, 0,0,0) (spec_info spec)+ safe_info = qual_info+ qual_info False = 0+ qual_info True = 1+ as_info Nothing = 0+ as_info (Just _) = 1+ spec_info Nothing = (0,0,0,0,1,0,0)+ spec_info (Just (False, _)) = (0,0,0,0,0,1,0)+ spec_info (Just (True, _)) = (0,0,0,0,0,0,1)++ data_info (DataDecl { tcdDataDefn = HsDataDefn { dd_cons = cs+ , dd_derivs = L _ derivs}})+ = ( length cs+ , foldl' (\s dc -> length (deriv_clause_tys $ unLoc dc) + s)+ 0 derivs )+ data_info _ = (0,0)++ class_info decl@(ClassDecl {})+ = (classops, addpr (sum3 (map count_bind methods)))+ where+ methods = map unLoc $ bagToList (tcdMeths decl)+ (_, classops, _, _, _) = count_sigs (map unLoc (tcdSigs decl))+ class_info _ = (0,0)++ inst_info (TyFamInstD {}) = (0,0,0,1,0)+ inst_info (DataFamInstD {}) = (0,0,0,0,1)+ inst_info (ClsInstD { cid_inst = ClsInstDecl {cid_binds = inst_meths+ , cid_sigs = inst_sigs+ , cid_tyfam_insts = ats+ , cid_datafam_insts = adts } })+ = case count_sigs (map unLoc inst_sigs) of+ (_,_,ss,is,_) ->+ (addpr (sum3 (map count_bind methods)),+ ss, is, length ats, length adts)+ where+ methods = map unLoc $ bagToList inst_meths++ -- TODO: use Sum monoid+ addpr :: (Int,Int,Int) -> Int+ sum2 :: [(Int, Int)] -> (Int, Int)+ sum3 :: [(Int, Int, Int)] -> (Int, Int, Int)+ sum5 :: [(Int, Int, Int, Int, Int)] -> (Int, Int, Int, Int, Int)+ sum7 :: [(Int, Int, Int, Int, Int, Int, Int)] -> (Int, Int, Int, Int, Int, Int, Int)+ add7 :: (Int, Int, Int, Int, Int, Int, Int) -> (Int, Int, Int, Int, Int, Int, Int)+ -> (Int, Int, Int, Int, Int, Int, Int)++ addpr (x,y,z) = x+y+z+ sum2 = foldr add2 (0,0)+ where+ add2 (x1,x2) (y1,y2) = (x1+y1,x2+y2)+ sum3 = foldr add3 (0,0,0)+ where+ add3 (x1,x2,x3) (y1,y2,y3) = (x1+y1,x2+y2,x3+y3)+ sum5 = foldr add5 (0,0,0,0,0)+ where+ add5 (x1,x2,x3,x4,x5) (y1,y2,y3,y4,y5) = (x1+y1,x2+y2,x3+y3,x4+y4,x5+y5)+ sum7 = foldr add7 (0,0,0,0,0,0,0)++ add7 (x1,x2,x3,x4,x5,x6,x7) (y1,y2,y3,y4,y5,y6,y7) = (x1+y1,x2+y2,x3+y3,x4+y4,x5+y5,x6+y6,x7+y7)+
+ main/HscTypes.hs view
@@ -0,0 +1,3115 @@+{-+(c) The University of Glasgow, 2006++\section[HscTypes]{Types for the per-module compiler}+-}++{-# LANGUAGE CPP, ScopedTypeVariables #-}++-- | Types for the per-module compiler+module HscTypes (+ -- * compilation state+ HscEnv(..), hscEPS,+ FinderCache, FindResult(..), InstalledFindResult(..),+ Target(..), TargetId(..), pprTarget, pprTargetId,+ ModuleGraph, emptyMG,+ HscStatus(..),+ IServ(..),++ -- * Hsc monad+ Hsc(..), runHsc, runInteractiveHsc,++ -- * Information about modules+ ModDetails(..), emptyModDetails,+ ModGuts(..), CgGuts(..), ForeignStubs(..), appendStubC,+ ImportedMods, ImportedBy(..), importedByUser, ImportedModsVal(..), SptEntry(..),+ ForeignSrcLang(..),++ ModSummary(..), ms_imps, ms_installed_mod, ms_mod_name, showModMsg, isBootSummary,+ msHsFilePath, msHiFilePath, msObjFilePath,+ SourceModified(..),++ -- * Information about the module being compiled+ -- (re-exported from DriverPhases)+ HscSource(..), isHsBootOrSig, hscSourceString,+++ -- * State relating to modules in this package+ HomePackageTable, HomeModInfo(..), emptyHomePackageTable,+ lookupHpt, eltsHpt, filterHpt, allHpt, mapHpt, delFromHpt,+ addToHpt, addListToHpt, lookupHptDirectly, listToHpt,+ hptCompleteSigs,+ hptInstances, hptRules, hptVectInfo, pprHPT,+ hptObjs,++ -- * State relating to known packages+ ExternalPackageState(..), EpsStats(..), addEpsInStats,+ PackageTypeEnv, PackageIfaceTable, emptyPackageIfaceTable,+ lookupIfaceByModule, emptyModIface, lookupHptByModule,++ PackageInstEnv, PackageFamInstEnv, PackageRuleBase,+ PackageCompleteMatchMap,++ mkSOName, mkHsSOName, soExt,++ -- * Metaprogramming+ MetaRequest(..),+ MetaResult, -- data constructors not exported to ensure correct response type+ metaRequestE, metaRequestP, metaRequestT, metaRequestD, metaRequestAW,+ MetaHook,++ -- * Annotations+ prepareAnnotations,++ -- * Interactive context+ InteractiveContext(..), emptyInteractiveContext,+ icPrintUnqual, icInScopeTTs, icExtendGblRdrEnv,+ extendInteractiveContext, extendInteractiveContextWithIds,+ substInteractiveContext,+ setInteractivePrintName, icInteractiveModule,+ InteractiveImport(..), setInteractivePackage,+ mkPrintUnqualified, pprModulePrefix,+ mkQualPackage, mkQualModule, pkgQual,++ -- * Interfaces+ ModIface(..), mkIfaceWarnCache, mkIfaceHashCache, mkIfaceFixCache,+ emptyIfaceWarnCache, mi_boot, mi_fix,+ mi_semantic_module,+ mi_free_holes,+ renameFreeHoles,++ -- * Fixity+ FixityEnv, FixItem(..), lookupFixity, emptyFixityEnv,++ -- * TyThings and type environments+ TyThing(..), tyThingAvailInfo,+ tyThingTyCon, tyThingDataCon, tyThingConLike,+ tyThingId, tyThingCoAxiom, tyThingParent_maybe, tyThingsTyCoVars,+ implicitTyThings, implicitTyConThings, implicitClassThings,+ isImplicitTyThing,++ TypeEnv, lookupType, lookupTypeHscEnv, mkTypeEnv, emptyTypeEnv,+ typeEnvFromEntities, mkTypeEnvWithImplicits,+ extendTypeEnv, extendTypeEnvList,+ extendTypeEnvWithIds, plusTypeEnv,+ lookupTypeEnv,+ typeEnvElts, typeEnvTyCons, typeEnvIds, typeEnvPatSyns,+ typeEnvDataCons, typeEnvCoAxioms, typeEnvClasses,++ -- * MonadThings+ MonadThings(..),++ -- * Information on imports and exports+ WhetherHasOrphans, IsBootInterface, Usage(..),+ Dependencies(..), noDependencies,+ updNameCacheIO,+ IfaceExport,++ -- * Warnings+ Warnings(..), WarningTxt(..), plusWarns,++ -- * Linker stuff+ Linkable(..), isObjectLinkable, linkableObjs,+ Unlinked(..), CompiledByteCode,+ isObject, nameOfObject, isInterpretable, byteCodeOfObject,++ -- * Program coverage+ HpcInfo(..), emptyHpcInfo, isHpcUsed, AnyHpcUsage,++ -- * Breakpoints+ ModBreaks (..), emptyModBreaks,++ -- * Vectorisation information+ VectInfo(..), IfaceVectInfo(..), noVectInfo, plusVectInfo,+ noIfaceVectInfo, isNoIfaceVectInfo,++ -- * Safe Haskell information+ IfaceTrustInfo, getSafeMode, setSafeMode, noIfaceTrustInfo,+ trustInfoToNum, numToTrustInfo, IsSafeImport,++ -- * result of the parser+ HsParsedModule(..),++ -- * Compilation errors and warnings+ SourceError, GhcApiError, mkSrcErr, srcErrorMessages, mkApiErr,+ throwOneError, handleSourceError,+ handleFlagWarnings, printOrThrowWarnings,++ -- * COMPLETE signature+ CompleteMatch(..), CompleteMatchMap,+ mkCompleteMatchMap, extendCompleteMatchMap+ ) where++#include "HsVersions.h"++import ByteCodeTypes+import InteractiveEvalTypes ( Resume )+import GHCi.Message ( Pipe )+import GHCi.RemoteTypes+import GHC.ForeignSrcLang++import UniqFM+import HsSyn+import RdrName+import Avail+import Module+import InstEnv ( InstEnv, ClsInst, identicalClsInstHead )+import FamInstEnv+import CoreSyn ( CoreProgram, RuleBase, CoreRule, CoreVect )+import Name+import NameEnv+import NameSet+import VarEnv+import VarSet+import Var+import Id+import IdInfo ( IdDetails(..), RecSelParent(..))+import Type++import ApiAnnotation ( ApiAnns )+import Annotations ( Annotation, AnnEnv, mkAnnEnv, plusAnnEnv )+import Class+import TyCon+import CoAxiom+import ConLike+import DataCon+import PatSyn+import PrelNames ( gHC_PRIM, ioTyConName, printName, mkInteractiveModule+ , eqTyConName )+import TysWiredIn+import Packages hiding ( Version(..) )+import DynFlags+import DriverPhases ( Phase, HscSource(..), isHsBootOrSig, hscSourceString )+import BasicTypes+import IfaceSyn+import Maybes+import Outputable+import SrcLoc+import Unique+import UniqDFM+import FastString+import StringBuffer ( StringBuffer )+import Fingerprint+import MonadUtils+import Bag+import Binary+import ErrUtils+import NameCache+import Platform+import Util+import UniqDSet+import GHC.Serialized ( Serialized )++import Foreign+import Control.Monad ( guard, liftM, when, ap )+import Data.Foldable ( foldl' )+import Data.IORef+import Data.Time+import Exception+import System.FilePath+import Control.Concurrent+import System.Process ( ProcessHandle )++-- -----------------------------------------------------------------------------+-- Compilation state+-- -----------------------------------------------------------------------------++-- | Status of a compilation to hard-code+data HscStatus+ = HscNotGeneratingCode+ | HscUpToDate+ | HscUpdateBoot+ | HscUpdateSig+ | HscRecomp CgGuts ModSummary++-- -----------------------------------------------------------------------------+-- The Hsc monad: Passing an environment and warning state++newtype Hsc a = Hsc (HscEnv -> WarningMessages -> IO (a, WarningMessages))++instance Functor Hsc where+ fmap = liftM++instance Applicative Hsc where+ pure a = Hsc $ \_ w -> return (a, w)+ (<*>) = ap++instance Monad Hsc where+ Hsc m >>= k = Hsc $ \e w -> do (a, w1) <- m e w+ case k a of+ Hsc k' -> k' e w1++instance MonadIO Hsc where+ liftIO io = Hsc $ \_ w -> do a <- io; return (a, w)++instance HasDynFlags Hsc where+ getDynFlags = Hsc $ \e w -> return (hsc_dflags e, w)++runHsc :: HscEnv -> Hsc a -> IO a+runHsc hsc_env (Hsc hsc) = do+ (a, w) <- hsc hsc_env emptyBag+ printOrThrowWarnings (hsc_dflags hsc_env) w+ return a++runInteractiveHsc :: HscEnv -> Hsc a -> IO a+-- A variant of runHsc that switches in the DynFlags from the+-- InteractiveContext before running the Hsc computation.+runInteractiveHsc hsc_env+ = runHsc (hsc_env { hsc_dflags = interactive_dflags })+ where+ interactive_dflags = ic_dflags (hsc_IC hsc_env)++-- -----------------------------------------------------------------------------+-- Source Errors++-- When the compiler (HscMain) discovers errors, it throws an+-- exception in the IO monad.++mkSrcErr :: ErrorMessages -> SourceError+mkSrcErr = SourceError++srcErrorMessages :: SourceError -> ErrorMessages+srcErrorMessages (SourceError msgs) = msgs++mkApiErr :: DynFlags -> SDoc -> GhcApiError+mkApiErr dflags msg = GhcApiError (showSDoc dflags msg)++throwOneError :: MonadIO m => ErrMsg -> m ab+throwOneError err = liftIO $ throwIO $ mkSrcErr $ unitBag err++-- | A source error is an error that is caused by one or more errors in the+-- source code. A 'SourceError' is thrown by many functions in the+-- compilation pipeline. Inside GHC these errors are merely printed via+-- 'log_action', but API clients may treat them differently, for example,+-- insert them into a list box. If you want the default behaviour, use the+-- idiom:+--+-- > handleSourceError printExceptionAndWarnings $ do+-- > ... api calls that may fail ...+--+-- The 'SourceError's error messages can be accessed via 'srcErrorMessages'.+-- This list may be empty if the compiler failed due to @-Werror@+-- ('Opt_WarnIsError').+--+-- See 'printExceptionAndWarnings' for more information on what to take care+-- of when writing a custom error handler.+newtype SourceError = SourceError ErrorMessages++instance Show SourceError where+ show (SourceError msgs) = unlines . map show . bagToList $ msgs++instance Exception SourceError++-- | Perform the given action and call the exception handler if the action+-- throws a 'SourceError'. See 'SourceError' for more information.+handleSourceError :: (ExceptionMonad m) =>+ (SourceError -> m a) -- ^ exception handler+ -> m a -- ^ action to perform+ -> m a+handleSourceError handler act =+ gcatch act (\(e :: SourceError) -> handler e)++-- | An error thrown if the GHC API is used in an incorrect fashion.+newtype GhcApiError = GhcApiError String++instance Show GhcApiError where+ show (GhcApiError msg) = msg++instance Exception GhcApiError++-- | Given a bag of warnings, turn them into an exception if+-- -Werror is enabled, or print them out otherwise.+printOrThrowWarnings :: DynFlags -> Bag WarnMsg -> IO ()+printOrThrowWarnings dflags warns+ | anyBag (isWarnMsgFatal dflags) warns+ = throwIO $ mkSrcErr $ warns `snocBag` warnIsErrorMsg dflags+ | otherwise+ = printBagOfErrors dflags warns++handleFlagWarnings :: DynFlags -> [Located String] -> IO ()+handleFlagWarnings dflags warns+ = when (wopt Opt_WarnDeprecatedFlags dflags) $ do+ -- It would be nicer if warns :: [Located MsgDoc], but that+ -- has circular import problems.+ let bag = listToBag [ mkPlainWarnMsg dflags loc (text warn)+ | L loc warn <- warns ]++ printOrThrowWarnings dflags bag++{-+************************************************************************+* *+\subsection{HscEnv}+* *+************************************************************************+-}++-- | HscEnv is like 'Session', except that some of the fields are immutable.+-- An HscEnv is used to compile a single module from plain Haskell source+-- code (after preprocessing) to either C, assembly or C--. Things like+-- the module graph don't change during a single compilation.+--+-- Historical note: \"hsc\" used to be the name of the compiler binary,+-- when there was a separate driver and compiler. To compile a single+-- module, the driver would invoke hsc on the source code... so nowadays+-- we think of hsc as the layer of the compiler that deals with compiling+-- a single module.+data HscEnv+ = HscEnv {+ hsc_dflags :: DynFlags,+ -- ^ The dynamic flag settings++ hsc_targets :: [Target],+ -- ^ The targets (or roots) of the current session++ hsc_mod_graph :: ModuleGraph,+ -- ^ The module graph of the current session++ hsc_IC :: InteractiveContext,+ -- ^ The context for evaluating interactive statements++ hsc_HPT :: HomePackageTable,+ -- ^ The home package table describes already-compiled+ -- home-package modules, /excluding/ the module we+ -- are compiling right now.+ -- (In one-shot mode the current module is the only+ -- home-package module, so hsc_HPT is empty. All other+ -- modules count as \"external-package\" modules.+ -- However, even in GHCi mode, hi-boot interfaces are+ -- demand-loaded into the external-package table.)+ --+ -- 'hsc_HPT' is not mutable because we only demand-load+ -- external packages; the home package is eagerly+ -- loaded, module by module, by the compilation manager.+ --+ -- The HPT may contain modules compiled earlier by @--make@+ -- but not actually below the current module in the dependency+ -- graph.+ --+ -- (This changes a previous invariant: changed Jan 05.)++ hsc_EPS :: {-# UNPACK #-} !(IORef ExternalPackageState),+ -- ^ Information about the currently loaded external packages.+ -- This is mutable because packages will be demand-loaded during+ -- a compilation run as required.++ hsc_NC :: {-# UNPACK #-} !(IORef NameCache),+ -- ^ As with 'hsc_EPS', this is side-effected by compiling to+ -- reflect sucking in interface files. They cache the state of+ -- external interface files, in effect.++ hsc_FC :: {-# UNPACK #-} !(IORef FinderCache),+ -- ^ The cached result of performing finding in the file system++ hsc_type_env_var :: Maybe (Module, IORef TypeEnv)+ -- ^ Used for one-shot compilation only, to initialise+ -- the 'IfGblEnv'. See 'TcRnTypes.tcg_type_env_var' for+ -- 'TcRnTypes.TcGblEnv'. See also Note [hsc_type_env_var hack]++ , hsc_iserv :: MVar (Maybe IServ)+ -- ^ interactive server process. Created the first+ -- time it is needed.+ }++-- Note [hsc_type_env_var hack]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- hsc_type_env_var is used to initialize tcg_type_env_var, and+-- eventually it is the mutable variable that is queried from+-- if_rec_types to get a TypeEnv. So, clearly, it's something+-- related to knot-tying (see Note [Tying the knot]).+-- hsc_type_env_var is used in two places: initTcRn (where+-- it initializes tcg_type_env_var) and initIfaceCheck+-- (where it initializes if_rec_types).+--+-- But why do we need a way to feed a mutable variable in? Why+-- can't we just initialize tcg_type_env_var when we start+-- typechecking? The problem is we need to knot-tie the+-- EPS, and we may start adding things to the EPS before type+-- checking starts.+--+-- Here is a concrete example. Suppose we are running+-- "ghc -c A.hs", and we have this file system state:+--+-- A.hs-boot A.hi-boot **up to date**+-- B.hs B.hi **up to date**+-- A.hs A.hi **stale**+--+-- The first thing we do is run checkOldIface on A.hi.+-- checkOldIface will call loadInterface on B.hi so it can+-- get its hands on the fingerprints, to find out if A.hi+-- needs recompilation. But loadInterface also populates+-- the EPS! And so if compilation turns out to be necessary,+-- as it is in this case, the thunks we put into the EPS for+-- B.hi need to have the correct if_rec_types mutable variable+-- to query.+--+-- If the mutable variable is only allocated WHEN we start+-- typechecking, then that's too late: we can't get the+-- information to the thunks. So we need to pre-commit+-- to a type variable in 'hscIncrementalCompile' BEFORE we+-- check the old interface.+--+-- This is all a massive hack because arguably checkOldIface+-- should not populate the EPS. But that's a refactor for+-- another day.+++data IServ = IServ+ { iservPipe :: Pipe+ , iservProcess :: ProcessHandle+ , iservLookupSymbolCache :: IORef (UniqFM (Ptr ()))+ , iservPendingFrees :: [HValueRef]+ }++-- | Retrieve the ExternalPackageState cache.+hscEPS :: HscEnv -> IO ExternalPackageState+hscEPS hsc_env = readIORef (hsc_EPS hsc_env)++-- | A compilation target.+--+-- A target may be supplied with the actual text of the+-- module. If so, use this instead of the file contents (this+-- is for use in an IDE where the file hasn't been saved by+-- the user yet).+data Target+ = Target {+ targetId :: TargetId, -- ^ module or filename+ targetAllowObjCode :: Bool, -- ^ object code allowed?+ targetContents :: Maybe (StringBuffer,UTCTime)+ -- ^ in-memory text buffer?+ }++data TargetId+ = TargetModule ModuleName+ -- ^ A module name: search for the file+ | TargetFile FilePath (Maybe Phase)+ -- ^ A filename: preprocess & parse it to find the module name.+ -- If specified, the Phase indicates how to compile this file+ -- (which phase to start from). Nothing indicates the starting phase+ -- should be determined from the suffix of the filename.+ deriving Eq++pprTarget :: Target -> SDoc+pprTarget (Target id obj _) =+ (if obj then char '*' else empty) <> pprTargetId id++instance Outputable Target where+ ppr = pprTarget++pprTargetId :: TargetId -> SDoc+pprTargetId (TargetModule m) = ppr m+pprTargetId (TargetFile f _) = text f++instance Outputable TargetId where+ ppr = pprTargetId++{-+************************************************************************+* *+\subsection{Package and Module Tables}+* *+************************************************************************+-}++-- | Helps us find information about modules in the home package+type HomePackageTable = DModuleNameEnv HomeModInfo+ -- Domain = modules in the home package that have been fully compiled+ -- "home" unit id cached here for convenience++-- | Helps us find information about modules in the imported packages+type PackageIfaceTable = ModuleEnv ModIface+ -- Domain = modules in the imported packages++-- | Constructs an empty HomePackageTable+emptyHomePackageTable :: HomePackageTable+emptyHomePackageTable = emptyUDFM++-- | Constructs an empty PackageIfaceTable+emptyPackageIfaceTable :: PackageIfaceTable+emptyPackageIfaceTable = emptyModuleEnv++pprHPT :: HomePackageTable -> SDoc+-- A bit arbitrary for now+pprHPT hpt = pprUDFM hpt $ \hms ->+ vcat [ hang (ppr (mi_module (hm_iface hm)))+ 2 (ppr (md_types (hm_details hm)))+ | hm <- hms ]++lookupHpt :: HomePackageTable -> ModuleName -> Maybe HomeModInfo+lookupHpt = lookupUDFM++lookupHptDirectly :: HomePackageTable -> Unique -> Maybe HomeModInfo+lookupHptDirectly = lookupUDFM_Directly++eltsHpt :: HomePackageTable -> [HomeModInfo]+eltsHpt = eltsUDFM++filterHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> HomePackageTable+filterHpt = filterUDFM++allHpt :: (HomeModInfo -> Bool) -> HomePackageTable -> Bool+allHpt = allUDFM++mapHpt :: (HomeModInfo -> HomeModInfo) -> HomePackageTable -> HomePackageTable+mapHpt = mapUDFM++delFromHpt :: HomePackageTable -> ModuleName -> HomePackageTable+delFromHpt = delFromUDFM++addToHpt :: HomePackageTable -> ModuleName -> HomeModInfo -> HomePackageTable+addToHpt = addToUDFM++addListToHpt+ :: HomePackageTable -> [(ModuleName, HomeModInfo)] -> HomePackageTable+addListToHpt = addListToUDFM++listToHpt :: [(ModuleName, HomeModInfo)] -> HomePackageTable+listToHpt = listToUDFM++lookupHptByModule :: HomePackageTable -> Module -> Maybe HomeModInfo+-- The HPT is indexed by ModuleName, not Module,+-- we must check for a hit on the right Module+lookupHptByModule hpt mod+ = case lookupHpt hpt (moduleName mod) of+ Just hm | mi_module (hm_iface hm) == mod -> Just hm+ _otherwise -> Nothing++-- | Information about modules in the package being compiled+data HomeModInfo+ = HomeModInfo {+ hm_iface :: !ModIface,+ -- ^ The basic loaded interface file: every loaded module has one of+ -- these, even if it is imported from another package+ hm_details :: !ModDetails,+ -- ^ Extra information that has been created from the 'ModIface' for+ -- the module, typically during typechecking+ hm_linkable :: !(Maybe Linkable)+ -- ^ The actual artifact we would like to link to access things in+ -- this module.+ --+ -- 'hm_linkable' might be Nothing:+ --+ -- 1. If this is an .hs-boot module+ --+ -- 2. Temporarily during compilation if we pruned away+ -- the old linkable because it was out of date.+ --+ -- After a complete compilation ('GHC.load'), all 'hm_linkable' fields+ -- in the 'HomePackageTable' will be @Just@.+ --+ -- When re-linking a module ('HscMain.HscNoRecomp'), we construct the+ -- 'HomeModInfo' by building a new 'ModDetails' from the old+ -- 'ModIface' (only).+ }++-- | Find the 'ModIface' for a 'Module', searching in both the loaded home+-- and external package module information+lookupIfaceByModule+ :: DynFlags+ -> HomePackageTable+ -> PackageIfaceTable+ -> Module+ -> Maybe ModIface+lookupIfaceByModule _dflags hpt pit mod+ = case lookupHptByModule hpt mod of+ Just hm -> Just (hm_iface hm)+ Nothing -> lookupModuleEnv pit mod++-- If the module does come from the home package, why do we look in the PIT as well?+-- (a) In OneShot mode, even home-package modules accumulate in the PIT+-- (b) Even in Batch (--make) mode, there is *one* case where a home-package+-- module is in the PIT, namely GHC.Prim when compiling the base package.+-- We could eliminate (b) if we wanted, by making GHC.Prim belong to a package+-- of its own, but it doesn't seem worth the bother.++hptCompleteSigs :: HscEnv -> [CompleteMatch]+hptCompleteSigs = hptAllThings (md_complete_sigs . hm_details)++-- | Find all the instance declarations (of classes and families) from+-- the Home Package Table filtered by the provided predicate function.+-- Used in @tcRnImports@, to select the instances that are in the+-- transitive closure of imports from the currently compiled module.+hptInstances :: HscEnv -> (ModuleName -> Bool) -> ([ClsInst], [FamInst])+hptInstances hsc_env want_this_module+ = let (insts, famInsts) = unzip $ flip hptAllThings hsc_env $ \mod_info -> do+ guard (want_this_module (moduleName (mi_module (hm_iface mod_info))))+ let details = hm_details mod_info+ return (md_insts details, md_fam_insts details)+ in (concat insts, concat famInsts)++-- | Get the combined VectInfo of all modules in the home package table. In+-- contrast to instances and rules, we don't care whether the modules are+-- "below" us in the dependency sense. The VectInfo of those modules not "below"+-- us does not affect the compilation of the current module.+hptVectInfo :: HscEnv -> VectInfo+hptVectInfo = concatVectInfo . hptAllThings ((: []) . md_vect_info . hm_details)++-- | Get rules from modules "below" this one (in the dependency sense)+hptRules :: HscEnv -> [(ModuleName, IsBootInterface)] -> [CoreRule]+hptRules = hptSomeThingsBelowUs (md_rules . hm_details) False+++-- | Get annotations from modules "below" this one (in the dependency sense)+hptAnns :: HscEnv -> Maybe [(ModuleName, IsBootInterface)] -> [Annotation]+hptAnns hsc_env (Just deps) = hptSomeThingsBelowUs (md_anns . hm_details) False hsc_env deps+hptAnns hsc_env Nothing = hptAllThings (md_anns . hm_details) hsc_env++hptAllThings :: (HomeModInfo -> [a]) -> HscEnv -> [a]+hptAllThings extract hsc_env = concatMap extract (eltsHpt (hsc_HPT hsc_env))++-- | Get things from modules "below" this one (in the dependency sense)+-- C.f Inst.hptInstances+hptSomeThingsBelowUs :: (HomeModInfo -> [a]) -> Bool -> HscEnv -> [(ModuleName, IsBootInterface)] -> [a]+hptSomeThingsBelowUs extract include_hi_boot hsc_env deps+ | isOneShot (ghcMode (hsc_dflags hsc_env)) = []++ | otherwise+ = let hpt = hsc_HPT hsc_env+ in+ [ thing+ | -- Find each non-hi-boot module below me+ (mod, is_boot_mod) <- deps+ , include_hi_boot || not is_boot_mod++ -- unsavoury: when compiling the base package with --make, we+ -- sometimes try to look up RULES etc for GHC.Prim. GHC.Prim won't+ -- be in the HPT, because we never compile it; it's in the EPT+ -- instead. ToDo: clean up, and remove this slightly bogus filter:+ , mod /= moduleName gHC_PRIM++ -- Look it up in the HPT+ , let things = case lookupHpt hpt mod of+ Just info -> extract info+ Nothing -> pprTrace "WARNING in hptSomeThingsBelowUs" msg []+ msg = vcat [text "missing module" <+> ppr mod,+ text "Probable cause: out-of-date interface files"]+ -- This really shouldn't happen, but see Trac #962++ -- And get its dfuns+ , thing <- things ]++hptObjs :: HomePackageTable -> [FilePath]+hptObjs hpt = concat (map (maybe [] linkableObjs . hm_linkable) (eltsHpt hpt))++{-+************************************************************************+* *+\subsection{Metaprogramming}+* *+************************************************************************+-}++-- | The supported metaprogramming result types+data MetaRequest+ = MetaE (LHsExpr RdrName -> MetaResult)+ | MetaP (LPat RdrName -> MetaResult)+ | MetaT (LHsType RdrName -> MetaResult)+ | MetaD ([LHsDecl RdrName] -> MetaResult)+ | MetaAW (Serialized -> MetaResult)++-- | data constructors not exported to ensure correct result type+data MetaResult+ = MetaResE { unMetaResE :: LHsExpr RdrName }+ | MetaResP { unMetaResP :: LPat RdrName }+ | MetaResT { unMetaResT :: LHsType RdrName }+ | MetaResD { unMetaResD :: [LHsDecl RdrName] }+ | MetaResAW { unMetaResAW :: Serialized }++type MetaHook f = MetaRequest -> LHsExpr Id -> f MetaResult++metaRequestE :: Functor f => MetaHook f -> LHsExpr Id -> f (LHsExpr RdrName)+metaRequestE h = fmap unMetaResE . h (MetaE MetaResE)++metaRequestP :: Functor f => MetaHook f -> LHsExpr Id -> f (LPat RdrName)+metaRequestP h = fmap unMetaResP . h (MetaP MetaResP)++metaRequestT :: Functor f => MetaHook f -> LHsExpr Id -> f (LHsType RdrName)+metaRequestT h = fmap unMetaResT . h (MetaT MetaResT)++metaRequestD :: Functor f => MetaHook f -> LHsExpr Id -> f [LHsDecl RdrName]+metaRequestD h = fmap unMetaResD . h (MetaD MetaResD)++metaRequestAW :: Functor f => MetaHook f -> LHsExpr Id -> f Serialized+metaRequestAW h = fmap unMetaResAW . h (MetaAW MetaResAW)++{-+************************************************************************+* *+\subsection{Dealing with Annotations}+* *+************************************************************************+-}++-- | Deal with gathering annotations in from all possible places+-- and combining them into a single 'AnnEnv'+prepareAnnotations :: HscEnv -> Maybe ModGuts -> IO AnnEnv+prepareAnnotations hsc_env mb_guts = do+ eps <- hscEPS hsc_env+ let -- Extract annotations from the module being compiled if supplied one+ mb_this_module_anns = fmap (mkAnnEnv . mg_anns) mb_guts+ -- Extract dependencies of the module if we are supplied one,+ -- otherwise load annotations from all home package table+ -- entries regardless of dependency ordering.+ home_pkg_anns = (mkAnnEnv . hptAnns hsc_env) $ fmap (dep_mods . mg_deps) mb_guts+ other_pkg_anns = eps_ann_env eps+ ann_env = foldl1' plusAnnEnv $ catMaybes [mb_this_module_anns,+ Just home_pkg_anns,+ Just other_pkg_anns]+ return ann_env++{-+************************************************************************+* *+\subsection{The Finder cache}+* *+************************************************************************+-}++-- | The 'FinderCache' maps modules to the result of+-- searching for that module. It records the results of searching for+-- modules along the search path. On @:load@, we flush the entire+-- contents of this cache.+--+type FinderCache = InstalledModuleEnv InstalledFindResult++data InstalledFindResult+ = InstalledFound ModLocation InstalledModule+ | InstalledNoPackage InstalledUnitId+ | InstalledNotFound [FilePath] (Maybe InstalledUnitId)++-- | The result of searching for an imported module.+--+-- NB: FindResult manages both user source-import lookups+-- (which can result in 'Module') as well as direct imports+-- for interfaces (which always result in 'InstalledModule').+data FindResult+ = Found ModLocation Module+ -- ^ The module was found+ | NoPackage UnitId+ -- ^ The requested package was not found+ | FoundMultiple [(Module, ModuleOrigin)]+ -- ^ _Error_: both in multiple packages++ -- | Not found+ | NotFound+ { fr_paths :: [FilePath] -- Places where I looked++ , fr_pkg :: Maybe UnitId -- Just p => module is in this package's+ -- manifest, but couldn't find+ -- the .hi file++ , fr_mods_hidden :: [UnitId] -- Module is in these packages,+ -- but the *module* is hidden++ , fr_pkgs_hidden :: [UnitId] -- Module is in these packages,+ -- but the *package* is hidden++ , fr_suggestions :: [ModuleSuggestion] -- Possible mis-spelled modules+ }++{-+************************************************************************+* *+\subsection{Symbol tables and Module details}+* *+************************************************************************+-}++-- | A 'ModIface' plus a 'ModDetails' summarises everything we know+-- about a compiled module. The 'ModIface' is the stuff *before* linking,+-- and can be written out to an interface file. The 'ModDetails is after+-- linking and can be completely recovered from just the 'ModIface'.+--+-- When we read an interface file, we also construct a 'ModIface' from it,+-- except that we explicitly make the 'mi_decls' and a few other fields empty;+-- as when reading we consolidate the declarations etc. into a number of indexed+-- maps and environments in the 'ExternalPackageState'.+data ModIface+ = ModIface {+ mi_module :: !Module, -- ^ Name of the module we are for+ mi_sig_of :: !(Maybe Module), -- ^ Are we a sig of another mod?+ mi_iface_hash :: !Fingerprint, -- ^ Hash of the whole interface+ mi_mod_hash :: !Fingerprint, -- ^ Hash of the ABI only+ mi_flag_hash :: !Fingerprint, -- ^ Hash of the important flags+ -- used when compiling this module++ mi_orphan :: !WhetherHasOrphans, -- ^ Whether this module has orphans+ mi_finsts :: !WhetherHasFamInst,+ -- ^ Whether this module has family instances.+ -- See Note [The type family instance consistency story].+ mi_hsc_src :: !HscSource, -- ^ Boot? Signature?++ mi_deps :: Dependencies,+ -- ^ The dependencies of the module. This is+ -- consulted for directly-imported modules, but not+ -- for anything else (hence lazy)++ mi_usages :: [Usage],+ -- ^ Usages; kept sorted so that it's easy to decide+ -- whether to write a new iface file (changing usages+ -- doesn't affect the hash of this module)+ -- NOT STRICT! we read this field lazily from the interface file+ -- It is *only* consulted by the recompilation checker++ mi_exports :: ![IfaceExport],+ -- ^ Exports+ -- Kept sorted by (mod,occ), to make version comparisons easier+ -- Records the modules that are the declaration points for things+ -- exported by this module, and the 'OccName's of those things++ mi_exp_hash :: !Fingerprint,+ -- ^ Hash of export list++ mi_used_th :: !Bool,+ -- ^ Module required TH splices when it was compiled.+ -- This disables recompilation avoidance (see #481).++ mi_fixities :: [(OccName,Fixity)],+ -- ^ Fixities+ -- NOT STRICT! we read this field lazily from the interface file++ mi_warns :: Warnings,+ -- ^ Warnings+ -- NOT STRICT! we read this field lazily from the interface file++ mi_anns :: [IfaceAnnotation],+ -- ^ Annotations+ -- NOT STRICT! we read this field lazily from the interface file+++ mi_decls :: [(Fingerprint,IfaceDecl)],+ -- ^ Type, class and variable declarations+ -- The hash of an Id changes if its fixity or deprecations change+ -- (as well as its type of course)+ -- Ditto data constructors, class operations, except that+ -- the hash of the parent class/tycon changes++ mi_globals :: !(Maybe GlobalRdrEnv),+ -- ^ Binds all the things defined at the top level in+ -- the /original source/ code for this module. which+ -- is NOT the same as mi_exports, nor mi_decls (which+ -- may contains declarations for things not actually+ -- defined by the user). Used for GHCi and for inspecting+ -- the contents of modules via the GHC API only.+ --+ -- (We need the source file to figure out the+ -- top-level environment, if we didn't compile this module+ -- from source then this field contains @Nothing@).+ --+ -- Strictly speaking this field should live in the+ -- 'HomeModInfo', but that leads to more plumbing.++ -- Instance declarations and rules+ mi_insts :: [IfaceClsInst], -- ^ Sorted class instance+ mi_fam_insts :: [IfaceFamInst], -- ^ Sorted family instances+ mi_rules :: [IfaceRule], -- ^ Sorted rules+ mi_orphan_hash :: !Fingerprint, -- ^ Hash for orphan rules, class and family+ -- instances, and vectorise pragmas combined++ mi_vect_info :: !IfaceVectInfo, -- ^ Vectorisation information++ -- Cached environments for easy lookup+ -- These are computed (lazily) from other fields+ -- and are not put into the interface file+ mi_warn_fn :: OccName -> Maybe WarningTxt,+ -- ^ Cached lookup for 'mi_warns'+ mi_fix_fn :: OccName -> Maybe Fixity,+ -- ^ Cached lookup for 'mi_fixities'+ mi_hash_fn :: OccName -> Maybe (OccName, Fingerprint),+ -- ^ Cached lookup for 'mi_decls'.+ -- The @Nothing@ in 'mi_hash_fn' means that the thing+ -- isn't in decls. It's useful to know that when+ -- seeing if we are up to date wrt. the old interface.+ -- The 'OccName' is the parent of the name, if it has one.++ mi_hpc :: !AnyHpcUsage,+ -- ^ True if this program uses Hpc at any point in the program.++ mi_trust :: !IfaceTrustInfo,+ -- ^ Safe Haskell Trust information for this module.++ mi_trust_pkg :: !Bool,+ -- ^ Do we require the package this module resides in be trusted+ -- to trust this module? This is used for the situation where a+ -- module is Safe (so doesn't require the package be trusted+ -- itself) but imports some trustworthy modules from its own+ -- package (which does require its own package be trusted).+ -- See Note [RnNames . Trust Own Package]+ mi_complete_sigs :: [IfaceCompleteMatch]+ }++-- | Old-style accessor for whether or not the ModIface came from an hs-boot+-- file.+mi_boot :: ModIface -> Bool+mi_boot iface = mi_hsc_src iface == HsBootFile++-- | Lookups up a (possibly cached) fixity from a 'ModIface'. If one cannot be+-- found, 'defaultFixity' is returned instead.+mi_fix :: ModIface -> OccName -> Fixity+mi_fix iface name = mi_fix_fn iface name `orElse` defaultFixity++-- | The semantic module for this interface; e.g., if it's a interface+-- for a signature, if 'mi_module' is @p[A=<A>]:A@, 'mi_semantic_module'+-- will be @<A>@.+mi_semantic_module :: ModIface -> Module+mi_semantic_module iface = case mi_sig_of iface of+ Nothing -> mi_module iface+ Just mod -> mod++-- | The "precise" free holes, e.g., the signatures that this+-- 'ModIface' depends on.+mi_free_holes :: ModIface -> UniqDSet ModuleName+mi_free_holes iface =+ case splitModuleInsts (mi_module iface) of+ (_, Just indef)+ -- A mini-hack: we rely on the fact that 'renameFreeHoles'+ -- drops things that aren't holes.+ -> renameFreeHoles (mkUniqDSet cands) (indefUnitIdInsts (indefModuleUnitId indef))+ _ -> emptyUniqDSet+ where+ cands = map fst (dep_mods (mi_deps iface))++-- | Given a set of free holes, and a unit identifier, rename+-- the free holes according to the instantiation of the unit+-- identifier. For example, if we have A and B free, and+-- our unit identity is @p[A=<C>,B=impl:B]@, the renamed free+-- holes are just C.+renameFreeHoles :: UniqDSet ModuleName -> [(ModuleName, Module)] -> UniqDSet ModuleName+renameFreeHoles fhs insts =+ unionManyUniqDSets (map lookup_impl (uniqDSetToList fhs))+ where+ hmap = listToUFM insts+ lookup_impl mod_name+ | Just mod <- lookupUFM hmap mod_name = moduleFreeHoles mod+ -- It wasn't actually a hole+ | otherwise = emptyUniqDSet++instance Binary ModIface where+ put_ bh (ModIface {+ mi_module = mod,+ mi_sig_of = sig_of,+ mi_hsc_src = hsc_src,+ mi_iface_hash= iface_hash,+ mi_mod_hash = mod_hash,+ mi_flag_hash = flag_hash,+ mi_orphan = orphan,+ mi_finsts = hasFamInsts,+ mi_deps = deps,+ mi_usages = usages,+ mi_exports = exports,+ mi_exp_hash = exp_hash,+ mi_used_th = used_th,+ mi_fixities = fixities,+ mi_warns = warns,+ mi_anns = anns,+ mi_decls = decls,+ mi_insts = insts,+ mi_fam_insts = fam_insts,+ mi_rules = rules,+ mi_orphan_hash = orphan_hash,+ mi_vect_info = vect_info,+ mi_hpc = hpc_info,+ mi_trust = trust,+ mi_trust_pkg = trust_pkg,+ mi_complete_sigs = complete_sigs }) = do+ put_ bh mod+ put_ bh sig_of+ put_ bh hsc_src+ put_ bh iface_hash+ put_ bh mod_hash+ put_ bh flag_hash+ put_ bh orphan+ put_ bh hasFamInsts+ lazyPut bh deps+ lazyPut bh usages+ put_ bh exports+ put_ bh exp_hash+ put_ bh used_th+ put_ bh fixities+ lazyPut bh warns+ lazyPut bh anns+ put_ bh decls+ put_ bh insts+ put_ bh fam_insts+ lazyPut bh rules+ put_ bh orphan_hash+ put_ bh vect_info+ put_ bh hpc_info+ put_ bh trust+ put_ bh trust_pkg+ put_ bh complete_sigs++ get bh = do+ mod <- get bh+ sig_of <- get bh+ hsc_src <- get bh+ iface_hash <- get bh+ mod_hash <- get bh+ flag_hash <- get bh+ orphan <- get bh+ hasFamInsts <- get bh+ deps <- lazyGet bh+ usages <- {-# SCC "bin_usages" #-} lazyGet bh+ exports <- {-# SCC "bin_exports" #-} get bh+ exp_hash <- get bh+ used_th <- get bh+ fixities <- {-# SCC "bin_fixities" #-} get bh+ warns <- {-# SCC "bin_warns" #-} lazyGet bh+ anns <- {-# SCC "bin_anns" #-} lazyGet bh+ decls <- {-# SCC "bin_tycldecls" #-} get bh+ insts <- {-# SCC "bin_insts" #-} get bh+ fam_insts <- {-# SCC "bin_fam_insts" #-} get bh+ rules <- {-# SCC "bin_rules" #-} lazyGet bh+ orphan_hash <- get bh+ vect_info <- get bh+ hpc_info <- get bh+ trust <- get bh+ trust_pkg <- get bh+ complete_sigs <- get bh+ return (ModIface {+ mi_module = mod,+ mi_sig_of = sig_of,+ mi_hsc_src = hsc_src,+ mi_iface_hash = iface_hash,+ mi_mod_hash = mod_hash,+ mi_flag_hash = flag_hash,+ mi_orphan = orphan,+ mi_finsts = hasFamInsts,+ mi_deps = deps,+ mi_usages = usages,+ mi_exports = exports,+ mi_exp_hash = exp_hash,+ mi_used_th = used_th,+ mi_anns = anns,+ mi_fixities = fixities,+ mi_warns = warns,+ mi_decls = decls,+ mi_globals = Nothing,+ mi_insts = insts,+ mi_fam_insts = fam_insts,+ mi_rules = rules,+ mi_orphan_hash = orphan_hash,+ mi_vect_info = vect_info,+ mi_hpc = hpc_info,+ mi_trust = trust,+ mi_trust_pkg = trust_pkg,+ -- And build the cached values+ mi_warn_fn = mkIfaceWarnCache warns,+ mi_fix_fn = mkIfaceFixCache fixities,+ mi_hash_fn = mkIfaceHashCache decls,+ mi_complete_sigs = complete_sigs })++-- | The original names declared of a certain module that are exported+type IfaceExport = AvailInfo++-- | Constructs an empty ModIface+emptyModIface :: Module -> ModIface+emptyModIface mod+ = ModIface { mi_module = mod,+ mi_sig_of = Nothing,+ mi_iface_hash = fingerprint0,+ mi_mod_hash = fingerprint0,+ mi_flag_hash = fingerprint0,+ mi_orphan = False,+ mi_finsts = False,+ mi_hsc_src = HsSrcFile,+ mi_deps = noDependencies,+ mi_usages = [],+ mi_exports = [],+ mi_exp_hash = fingerprint0,+ mi_used_th = False,+ mi_fixities = [],+ mi_warns = NoWarnings,+ mi_anns = [],+ mi_insts = [],+ mi_fam_insts = [],+ mi_rules = [],+ mi_decls = [],+ mi_globals = Nothing,+ mi_orphan_hash = fingerprint0,+ mi_vect_info = noIfaceVectInfo,+ mi_warn_fn = emptyIfaceWarnCache,+ mi_fix_fn = emptyIfaceFixCache,+ mi_hash_fn = emptyIfaceHashCache,+ mi_hpc = False,+ mi_trust = noIfaceTrustInfo,+ mi_trust_pkg = False,+ mi_complete_sigs = [] }+++-- | Constructs cache for the 'mi_hash_fn' field of a 'ModIface'+mkIfaceHashCache :: [(Fingerprint,IfaceDecl)]+ -> (OccName -> Maybe (OccName, Fingerprint))+mkIfaceHashCache pairs+ = \occ -> lookupOccEnv env occ+ where+ env = foldl' add_decl emptyOccEnv pairs+ add_decl env0 (v,d) = foldl' add env0 (ifaceDeclFingerprints v d)+ where+ add env0 (occ,hash) = extendOccEnv env0 occ (occ,hash)++emptyIfaceHashCache :: OccName -> Maybe (OccName, Fingerprint)+emptyIfaceHashCache _occ = Nothing+++-- | The 'ModDetails' is essentially a cache for information in the 'ModIface'+-- for home modules only. Information relating to packages will be loaded into+-- global environments in 'ExternalPackageState'.+data ModDetails+ = ModDetails {+ -- The next two fields are created by the typechecker+ md_exports :: [AvailInfo],+ md_types :: !TypeEnv, -- ^ Local type environment for this particular module+ -- Includes Ids, TyCons, PatSyns+ md_insts :: ![ClsInst], -- ^ 'DFunId's for the instances in this module+ md_fam_insts :: ![FamInst],+ md_rules :: ![CoreRule], -- ^ Domain may include 'Id's from other modules+ md_anns :: ![Annotation], -- ^ Annotations present in this module: currently+ -- they only annotate things also declared in this module+ md_vect_info :: !VectInfo, -- ^ Module vectorisation information+ md_complete_sigs :: [CompleteMatch]+ -- ^ Complete match pragmas for this module+ }++-- | Constructs an empty ModDetails+emptyModDetails :: ModDetails+emptyModDetails+ = ModDetails { md_types = emptyTypeEnv,+ md_exports = [],+ md_insts = [],+ md_rules = [],+ md_fam_insts = [],+ md_anns = [],+ md_vect_info = noVectInfo,+ md_complete_sigs = [] }++-- | Records the modules directly imported by a module for extracting e.g.+-- usage information, and also to give better error message+type ImportedMods = ModuleEnv [ImportedBy]++-- | If a module was "imported" by the user, we associate it with+-- more detailed usage information 'ImportedModsVal'; a module+-- imported by the system only gets used for usage information.+data ImportedBy+ = ImportedByUser ImportedModsVal+ | ImportedBySystem++importedByUser :: [ImportedBy] -> [ImportedModsVal]+importedByUser (ImportedByUser imv : bys) = imv : importedByUser bys+importedByUser (ImportedBySystem : bys) = importedByUser bys+importedByUser [] = []++data ImportedModsVal+ = ImportedModsVal {+ imv_name :: ModuleName, -- ^ The name the module is imported with+ imv_span :: SrcSpan, -- ^ the source span of the whole import+ imv_is_safe :: IsSafeImport, -- ^ whether this is a safe import+ imv_is_hiding :: Bool, -- ^ whether this is an "hiding" import+ imv_all_exports :: GlobalRdrEnv, -- ^ all the things the module could provide+ imv_qualified :: Bool -- ^ whether this is a qualified import+ }++-- | A ModGuts is carried through the compiler, accumulating stuff as it goes+-- There is only one ModGuts at any time, the one for the module+-- being compiled right now. Once it is compiled, a 'ModIface' and+-- 'ModDetails' are extracted and the ModGuts is discarded.+data ModGuts+ = ModGuts {+ mg_module :: !Module, -- ^ Module being compiled+ mg_hsc_src :: HscSource, -- ^ Whether it's an hs-boot module+ mg_loc :: SrcSpan, -- ^ For error messages from inner passes+ mg_exports :: ![AvailInfo], -- ^ What it exports+ mg_deps :: !Dependencies, -- ^ What it depends on, directly or+ -- otherwise+ mg_usages :: ![Usage], -- ^ What was used? Used for interfaces.++ mg_used_th :: !Bool, -- ^ Did we run a TH splice?+ mg_rdr_env :: !GlobalRdrEnv, -- ^ Top-level lexical environment++ -- These fields all describe the things **declared in this module**+ mg_fix_env :: !FixityEnv, -- ^ Fixities declared in this module.+ -- Used for creating interface files.+ mg_tcs :: ![TyCon], -- ^ TyCons declared in this module+ -- (includes TyCons for classes)+ mg_insts :: ![ClsInst], -- ^ Class instances declared in this module+ mg_fam_insts :: ![FamInst],+ -- ^ Family instances declared in this module+ mg_patsyns :: ![PatSyn], -- ^ Pattern synonyms declared in this module+ mg_rules :: ![CoreRule], -- ^ Before the core pipeline starts, contains+ -- See Note [Overall plumbing for rules] in Rules.hs+ mg_binds :: !CoreProgram, -- ^ Bindings for this module+ mg_foreign :: !ForeignStubs, -- ^ Foreign exports declared in this module+ mg_foreign_files :: ![(ForeignSrcLang, String)],+ -- ^ Files to be compiled with the C compiler+ mg_warns :: !Warnings, -- ^ Warnings declared in the module+ mg_anns :: [Annotation], -- ^ Annotations declared in this module+ mg_complete_sigs :: [CompleteMatch], -- ^ Complete Matches+ mg_hpc_info :: !HpcInfo, -- ^ Coverage tick boxes in the module+ mg_modBreaks :: !(Maybe ModBreaks), -- ^ Breakpoints for the module+ mg_vect_decls:: ![CoreVect], -- ^ Vectorisation declarations in this module+ -- (produced by desugarer & consumed by vectoriser)+ mg_vect_info :: !VectInfo, -- ^ Pool of vectorised declarations in the module++ -- The next two fields are unusual, because they give instance+ -- environments for *all* modules in the home package, including+ -- this module, rather than for *just* this module.+ -- Reason: when looking up an instance we don't want to have to+ -- look at each module in the home package in turn+ mg_inst_env :: InstEnv, -- ^ Class instance environment for+ -- /home-package/ modules (including this+ -- one); c.f. 'tcg_inst_env'+ mg_fam_inst_env :: FamInstEnv, -- ^ Type-family instance environment for+ -- /home-package/ modules (including this+ -- one); c.f. 'tcg_fam_inst_env'++ mg_safe_haskell :: SafeHaskellMode, -- ^ Safe Haskell mode+ mg_trust_pkg :: Bool -- ^ Do we need to trust our+ -- own package for Safe Haskell?+ -- See Note [RnNames . Trust Own Package]+ }++-- The ModGuts takes on several slightly different forms:+--+-- After simplification, the following fields change slightly:+-- mg_rules Orphan rules only (local ones now attached to binds)+-- mg_binds With rules attached++---------------------------------------------------------+-- The Tidy pass forks the information about this module:+-- * one lot goes to interface file generation (ModIface)+-- and later compilations (ModDetails)+-- * the other lot goes to code generation (CgGuts)++-- | A restricted form of 'ModGuts' for code generation purposes+data CgGuts+ = CgGuts {+ cg_module :: !Module,+ -- ^ Module being compiled++ cg_tycons :: [TyCon],+ -- ^ Algebraic data types (including ones that started+ -- life as classes); generate constructors and info+ -- tables. Includes newtypes, just for the benefit of+ -- External Core++ cg_binds :: CoreProgram,+ -- ^ The tidied main bindings, including+ -- previously-implicit bindings for record and class+ -- selectors, and data constructor wrappers. But *not*+ -- data constructor workers; reason: we we regard them+ -- as part of the code-gen of tycons++ cg_foreign :: !ForeignStubs, -- ^ Foreign export stubs+ cg_foreign_files :: ![(ForeignSrcLang, String)],+ cg_dep_pkgs :: ![InstalledUnitId], -- ^ Dependent packages, used to+ -- generate #includes for C code gen+ cg_hpc_info :: !HpcInfo, -- ^ Program coverage tick box information+ cg_modBreaks :: !(Maybe ModBreaks), -- ^ Module breakpoints+ cg_spt_entries :: [SptEntry]+ -- ^ Static pointer table entries for static forms defined in+ -- the module.+ -- See Note [Grand plan for static forms] in StaticPtrTable+ }++-----------------------------------+-- | Foreign export stubs+data ForeignStubs+ = NoStubs+ -- ^ We don't have any stubs+ | ForeignStubs SDoc SDoc+ -- ^ There are some stubs. Parameters:+ --+ -- 1) Header file prototypes for+ -- "foreign exported" functions+ --+ -- 2) C stubs to use when calling+ -- "foreign exported" functions++appendStubC :: ForeignStubs -> SDoc -> ForeignStubs+appendStubC NoStubs c_code = ForeignStubs empty c_code+appendStubC (ForeignStubs h c) c_code = ForeignStubs h (c $$ c_code)++-- | An entry to be inserted into a module's static pointer table.+-- See Note [Grand plan for static forms] in StaticPtrTable.+data SptEntry = SptEntry Id Fingerprint++instance Outputable SptEntry where+ ppr (SptEntry id fpr) = ppr id <> colon <+> ppr fpr++{-+************************************************************************+* *+ The interactive context+* *+************************************************************************++Note [The interactive package]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Type, class, and value declarations at the command prompt are treated+as if they were defined in modules+ interactive:Ghci1+ interactive:Ghci2+ ...etc...+with each bunch of declarations using a new module, all sharing a+common package 'interactive' (see Module.interactiveUnitId, and+PrelNames.mkInteractiveModule).++This scheme deals well with shadowing. For example:++ ghci> data T = A+ ghci> data T = B+ ghci> :i A+ data Ghci1.T = A -- Defined at <interactive>:2:10++Here we must display info about constructor A, but its type T has been+shadowed by the second declaration. But it has a respectable+qualified name (Ghci1.T), and its source location says where it was+defined.++So the main invariant continues to hold, that in any session an+original name M.T only refers to one unique thing. (In a previous+iteration both the T's above were called :Interactive.T, albeit with+different uniques, which gave rise to all sorts of trouble.)++The details are a bit tricky though:++ * The field ic_mod_index counts which Ghci module we've got up to.+ It is incremented when extending ic_tythings++ * ic_tythings contains only things from the 'interactive' package.++ * Module from the 'interactive' package (Ghci1, Ghci2 etc) never go+ in the Home Package Table (HPT). When you say :load, that's when we+ extend the HPT.++ * The 'thisPackage' field of DynFlags is *not* set to 'interactive'.+ It stays as 'main' (or whatever -this-unit-id says), and is the+ package to which :load'ed modules are added to.++ * So how do we arrange that declarations at the command prompt get to+ be in the 'interactive' package? Simply by setting the tcg_mod+ field of the TcGblEnv to "interactive:Ghci1". This is done by the+ call to initTc in initTcInteractive, which in turn get the module+ from it 'icInteractiveModule' field of the interactive context.++ The 'thisPackage' field stays as 'main' (or whatever -this-unit-id says.++ * The main trickiness is that the type environment (tcg_type_env) and+ fixity envt (tcg_fix_env), now contain entities from all the+ interactive-package modules (Ghci1, Ghci2, ...) together, rather+ than just a single module as is usually the case. So you can't use+ "nameIsLocalOrFrom" to decide whether to look in the TcGblEnv vs+ the HPT/PTE. This is a change, but not a problem provided you+ know.++* However, the tcg_binds, tcg_sigs, tcg_insts, tcg_fam_insts, etc fields+ of the TcGblEnv, which collect "things defined in this module", all+ refer to stuff define in a single GHCi command, *not* all the commands+ so far.++ In contrast, tcg_inst_env, tcg_fam_inst_env, have instances from+ all GhciN modules, which makes sense -- they are all "home package"+ modules.+++Note [Interactively-bound Ids in GHCi]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The Ids bound by previous Stmts in GHCi are currently+ a) GlobalIds, with+ b) An External Name, like Ghci4.foo+ See Note [The interactive package] above+ c) A tidied type++ (a) They must be GlobalIds (not LocalIds) otherwise when we come to+ compile an expression using these ids later, the byte code+ generator will consider the occurrences to be free rather than+ global.++ (b) Having an External Name is important because of Note+ [GlobalRdrEnv shadowing] in RdrName++ (c) Their types are tidied. This is important, because :info may ask+ to look at them, and :info expects the things it looks up to have+ tidy types++Where do interactively-bound Ids come from?++ - GHCi REPL Stmts e.g.+ ghci> let foo x = x+1+ These start with an Internal Name because a Stmt is a local+ construct, so the renamer naturally builds an Internal name for+ each of its binders. Then in tcRnStmt they are externalised via+ TcRnDriver.externaliseAndTidyId, so they get Names like Ghic4.foo.++ - Ids bound by the debugger etc have Names constructed by+ IfaceEnv.newInteractiveBinder; at the call sites it is followed by+ mkVanillaGlobal or mkVanillaGlobalWithInfo. So again, they are+ all Global, External.++ - TyCons, Classes, and Ids bound by other top-level declarations in+ GHCi (eg foreign import, record selectors) also get External+ Names, with Ghci9 (or 8, or 7, etc) as the module name.+++Note [ic_tythings]+~~~~~~~~~~~~~~~~~~+The ic_tythings field contains+ * The TyThings declared by the user at the command prompt+ (eg Ids, TyCons, Classes)++ * The user-visible Ids that arise from such things, which+ *don't* come from 'implicitTyThings', notably:+ - record selectors+ - class ops+ The implicitTyThings are readily obtained from the TyThings+ but record selectors etc are not++It does *not* contain+ * DFunIds (they can be gotten from ic_instances)+ * CoAxioms (ditto)++See also Note [Interactively-bound Ids in GHCi]++Note [Override identical instances in GHCi]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If you declare a new instance in GHCi that is identical to a previous one,+we simply override the previous one; we don't regard it as overlapping.+e.g. Prelude> data T = A | B+ Prelude> instance Eq T where ...+ Prelude> instance Eq T where ... -- This one overrides++It's exactly the same for type-family instances. See Trac #7102+-}++-- | Interactive context, recording information about the state of the+-- context in which statements are executed in a GHC session.+data InteractiveContext+ = InteractiveContext {+ ic_dflags :: DynFlags,+ -- ^ The 'DynFlags' used to evaluate interative expressions+ -- and statements.++ ic_mod_index :: Int,+ -- ^ Each GHCi stmt or declaration brings some new things into+ -- scope. We give them names like interactive:Ghci9.T,+ -- where the ic_index is the '9'. The ic_mod_index is+ -- incremented whenever we add something to ic_tythings+ -- See Note [The interactive package]++ ic_imports :: [InteractiveImport],+ -- ^ The GHCi top-level scope (ic_rn_gbl_env) is extended with+ -- these imports+ --+ -- This field is only stored here so that the client+ -- can retrieve it with GHC.getContext. GHC itself doesn't+ -- use it, but does reset it to empty sometimes (such+ -- as before a GHC.load). The context is set with GHC.setContext.++ ic_tythings :: [TyThing],+ -- ^ TyThings defined by the user, in reverse order of+ -- definition (ie most recent at the front)+ -- See Note [ic_tythings]++ ic_rn_gbl_env :: GlobalRdrEnv,+ -- ^ The cached 'GlobalRdrEnv', built by+ -- 'InteractiveEval.setContext' and updated regularly+ -- It contains everything in scope at the command line,+ -- including everything in ic_tythings++ ic_instances :: ([ClsInst], [FamInst]),+ -- ^ All instances and family instances created during+ -- this session. These are grabbed en masse after each+ -- update to be sure that proper overlapping is retained.+ -- That is, rather than re-check the overlapping each+ -- time we update the context, we just take the results+ -- from the instance code that already does that.++ ic_fix_env :: FixityEnv,+ -- ^ Fixities declared in let statements++ ic_default :: Maybe [Type],+ -- ^ The current default types, set by a 'default' declaration++ ic_resume :: [Resume],+ -- ^ The stack of breakpoint contexts++ ic_monad :: Name,+ -- ^ The monad that GHCi is executing in++ ic_int_print :: Name,+ -- ^ The function that is used for printing results+ -- of expressions in ghci and -e mode.++ ic_cwd :: Maybe FilePath+ -- virtual CWD of the program+ }++data InteractiveImport+ = IIDecl (ImportDecl RdrName)+ -- ^ Bring the exports of a particular module+ -- (filtered by an import decl) into scope++ | IIModule ModuleName+ -- ^ Bring into scope the entire top-level envt of+ -- of this module, including the things imported+ -- into it.+++-- | Constructs an empty InteractiveContext.+emptyInteractiveContext :: DynFlags -> InteractiveContext+emptyInteractiveContext dflags+ = InteractiveContext {+ ic_dflags = dflags,+ ic_imports = [],+ ic_rn_gbl_env = emptyGlobalRdrEnv,+ ic_mod_index = 1,+ ic_tythings = [],+ ic_instances = ([],[]),+ ic_fix_env = emptyNameEnv,+ ic_monad = ioTyConName, -- IO monad by default+ ic_int_print = printName, -- System.IO.print by default+ ic_default = Nothing,+ ic_resume = [],+ ic_cwd = Nothing }++icInteractiveModule :: InteractiveContext -> Module+icInteractiveModule (InteractiveContext { ic_mod_index = index })+ = mkInteractiveModule index++-- | This function returns the list of visible TyThings (useful for+-- e.g. showBindings)+icInScopeTTs :: InteractiveContext -> [TyThing]+icInScopeTTs = ic_tythings++-- | Get the PrintUnqualified function based on the flags and this InteractiveContext+icPrintUnqual :: DynFlags -> InteractiveContext -> PrintUnqualified+icPrintUnqual dflags InteractiveContext{ ic_rn_gbl_env = grenv } =+ mkPrintUnqualified dflags grenv++-- | extendInteractiveContext is called with new TyThings recently defined to update the+-- InteractiveContext to include them. Ids are easily removed when shadowed,+-- but Classes and TyCons are not. Some work could be done to determine+-- whether they are entirely shadowed, but as you could still have references+-- to them (e.g. instances for classes or values of the type for TyCons), it's+-- not clear whether removing them is even the appropriate behavior.+extendInteractiveContext :: InteractiveContext+ -> [TyThing]+ -> [ClsInst] -> [FamInst]+ -> Maybe [Type]+ -> FixityEnv+ -> InteractiveContext+extendInteractiveContext ictxt new_tythings new_cls_insts new_fam_insts defaults fix_env+ = ictxt { ic_mod_index = ic_mod_index ictxt + 1+ -- Always bump this; even instances should create+ -- a new mod_index (Trac #9426)+ , ic_tythings = new_tythings ++ ic_tythings ictxt+ , ic_rn_gbl_env = ic_rn_gbl_env ictxt `icExtendGblRdrEnv` new_tythings+ , ic_instances = ( new_cls_insts ++ old_cls_insts+ , new_fam_insts ++ fam_insts )+ -- we don't shadow old family instances (#7102),+ -- so don't need to remove them here+ , ic_default = defaults+ , ic_fix_env = fix_env -- See Note [Fixity declarations in GHCi]+ }+ where++ -- Discard old instances that have been fully overridden+ -- See Note [Override identical instances in GHCi]+ (cls_insts, fam_insts) = ic_instances ictxt+ old_cls_insts = filterOut (\i -> any (identicalClsInstHead i) new_cls_insts) cls_insts++extendInteractiveContextWithIds :: InteractiveContext -> [Id] -> InteractiveContext+-- Just a specialised version+extendInteractiveContextWithIds ictxt new_ids+ | null new_ids = ictxt+ | otherwise = ictxt { ic_mod_index = ic_mod_index ictxt + 1+ , ic_tythings = new_tythings ++ ic_tythings ictxt+ , ic_rn_gbl_env = ic_rn_gbl_env ictxt `icExtendGblRdrEnv` new_tythings }+ where+ new_tythings = map AnId new_ids++setInteractivePackage :: HscEnv -> HscEnv+-- Set the 'thisPackage' DynFlag to 'interactive'+setInteractivePackage hsc_env+ = hsc_env { hsc_dflags = (hsc_dflags hsc_env)+ { thisInstalledUnitId = toInstalledUnitId interactiveUnitId } }++setInteractivePrintName :: InteractiveContext -> Name -> InteractiveContext+setInteractivePrintName ic n = ic{ic_int_print = n}++ -- ToDo: should not add Ids to the gbl env here++-- | Add TyThings to the GlobalRdrEnv, earlier ones in the list shadowing+-- later ones, and shadowing existing entries in the GlobalRdrEnv.+icExtendGblRdrEnv :: GlobalRdrEnv -> [TyThing] -> GlobalRdrEnv+icExtendGblRdrEnv env tythings+ = foldr add env tythings -- Foldr makes things in the front of+ -- the list shadow things at the back+ where+ -- One at a time, to ensure each shadows the previous ones+ add thing env+ | is_sub_bndr thing+ = env+ | otherwise+ = foldl extendGlobalRdrEnv env1 (concatMap localGREsFromAvail avail)+ where+ env1 = shadowNames env (concatMap availNames avail)+ avail = tyThingAvailInfo thing++ -- Ugh! The new_tythings may include record selectors, since they+ -- are not implicit-ids, and must appear in the TypeEnv. But they+ -- will also be brought into scope by the corresponding (ATyCon+ -- tc). And we want the latter, because that has the correct+ -- parent (Trac #10520)+ is_sub_bndr (AnId f) = case idDetails f of+ RecSelId {} -> True+ ClassOpId {} -> True+ _ -> False+ is_sub_bndr _ = False++substInteractiveContext :: InteractiveContext -> TCvSubst -> InteractiveContext+substInteractiveContext ictxt@InteractiveContext{ ic_tythings = tts } subst+ | isEmptyTCvSubst subst = ictxt+ | otherwise = ictxt { ic_tythings = map subst_ty tts }+ where+ subst_ty (AnId id) = AnId $ id `setIdType` substTyUnchecked subst (idType id)+ subst_ty tt = tt++instance Outputable InteractiveImport where+ ppr (IIModule m) = char '*' <> ppr m+ ppr (IIDecl d) = ppr d++{-+************************************************************************+* *+ Building a PrintUnqualified+* *+************************************************************************++Note [Printing original names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Deciding how to print names is pretty tricky. We are given a name+P:M.T, where P is the package name, M is the defining module, and T is+the occurrence name, and we have to decide in which form to display+the name given a GlobalRdrEnv describing the current scope.++Ideally we want to display the name in the form in which it is in+scope. However, the name might not be in scope at all, and that's+where it gets tricky. Here are the cases:++ 1. T uniquely maps to P:M.T ---> "T" NameUnqual+ 2. There is an X for which X.T+ uniquely maps to P:M.T ---> "X.T" NameQual X+ 3. There is no binding for "M.T" ---> "M.T" NameNotInScope1+ 4. Otherwise ---> "P:M.T" NameNotInScope2++(3) and (4) apply when the entity P:M.T is not in the GlobalRdrEnv at+all. In these cases we still want to refer to the name as "M.T", *but*+"M.T" might mean something else in the current scope (e.g. if there's+an "import X as M"), so to avoid confusion we avoid using "M.T" if+there's already a binding for it. Instead we write P:M.T.++There's one further subtlety: in case (3), what if there are two+things around, P1:M.T and P2:M.T? Then we don't want to print both of+them as M.T! However only one of the modules P1:M and P2:M can be+exposed (say P2), so we use M.T for that, and P1:M.T for the other one.+This is handled by the qual_mod component of PrintUnqualified, inside+the (ppr mod) of case (3), in Name.pprModulePrefix++Note [Printing unit ids]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the old days, original names were tied to PackageIds, which directly+corresponded to the entities that users wrote in Cabal files, and were perfectly+suitable for printing when we need to disambiguate packages. However, with+UnitId, the situation can be different: if the key is instantiated with+some holes, we should try to give the user some more useful information.+-}++-- | Creates some functions that work out the best ways to format+-- names for the user according to a set of heuristics.+mkPrintUnqualified :: DynFlags -> GlobalRdrEnv -> PrintUnqualified+mkPrintUnqualified dflags env = QueryQualify qual_name+ (mkQualModule dflags)+ (mkQualPackage dflags)+ where+ qual_name mod occ+ | [gre] <- unqual_gres+ , right_name gre+ = NameUnqual -- If there's a unique entity that's in scope+ -- unqualified with 'occ' AND that entity is+ -- the right one, then we can use the unqualified name++ | [] <- unqual_gres+ , any is_name forceUnqualNames+ , not (isDerivedOccName occ)+ = NameUnqual -- Don't qualify names that come from modules+ -- that come with GHC, often appear in error messages,+ -- but aren't typically in scope. Doing this does not+ -- cause ambiguity, and it reduces the amount of+ -- qualification in error messages thus improving+ -- readability.+ --+ -- A motivating example is 'Constraint'. It's often not+ -- in scope, but printing GHC.Prim.Constraint seems+ -- overkill.++ | [gre] <- qual_gres+ = NameQual (greQualModName gre)++ | null qual_gres+ = if null (lookupGRE_RdrName (mkRdrQual (moduleName mod) occ) env)+ then NameNotInScope1+ else NameNotInScope2++ | otherwise+ = NameNotInScope1 -- Can happen if 'f' is bound twice in the module+ -- Eg f = True; g = 0; f = False+ where+ is_name :: Name -> Bool+ is_name name = ASSERT2( isExternalName name, ppr name )+ nameModule name == mod && nameOccName name == occ++ forceUnqualNames :: [Name]+ forceUnqualNames =+ map tyConName [ constraintKindTyCon, heqTyCon, coercibleTyCon+ , starKindTyCon, unicodeStarKindTyCon ]+ ++ [ eqTyConName ]++ right_name gre = nameModule_maybe (gre_name gre) == Just mod++ unqual_gres = lookupGRE_RdrName (mkRdrUnqual occ) env+ qual_gres = filter right_name (lookupGlobalRdrEnv env occ)++ -- we can mention a module P:M without the P: qualifier iff+ -- "import M" would resolve unambiguously to P:M. (if P is the+ -- current package we can just assume it is unqualified).++-- | Creates a function for formatting modules based on two heuristics:+-- (1) if the module is the current module, don't qualify, and (2) if there+-- is only one exposed package which exports this module, don't qualify.+mkQualModule :: DynFlags -> QueryQualifyModule+mkQualModule dflags mod+ | moduleUnitId mod == thisPackage dflags = False++ | [(_, pkgconfig)] <- lookup,+ packageConfigId pkgconfig == moduleUnitId mod+ -- this says: we are given a module P:M, is there just one exposed package+ -- that exposes a module M, and is it package P?+ = False++ | otherwise = True+ where lookup = lookupModuleInAllPackages dflags (moduleName mod)++-- | Creates a function for formatting packages based on two heuristics:+-- (1) don't qualify if the package in question is "main", and (2) only qualify+-- with a unit id if the package ID would be ambiguous.+mkQualPackage :: DynFlags -> QueryQualifyPackage+mkQualPackage dflags pkg_key+ | pkg_key == mainUnitId || pkg_key == interactiveUnitId+ -- Skip the lookup if it's main, since it won't be in the package+ -- database!+ = False+ | Just pkgid <- mb_pkgid+ , searchPackageId dflags pkgid `lengthIs` 1+ -- this says: we are given a package pkg-0.1@MMM, are there only one+ -- exposed packages whose package ID is pkg-0.1?+ = False+ | otherwise+ = True+ where mb_pkgid = fmap sourcePackageId (lookupPackage dflags pkg_key)++-- | A function which only qualifies package names if necessary; but+-- qualifies all other identifiers.+pkgQual :: DynFlags -> PrintUnqualified+pkgQual dflags = alwaysQualify {+ queryQualifyPackage = mkQualPackage dflags+ }++{-+************************************************************************+* *+ Implicit TyThings+* *+************************************************************************++Note [Implicit TyThings]+~~~~~~~~~~~~~~~~~~~~~~~~+ DEFINITION: An "implicit" TyThing is one that does not have its own+ IfaceDecl in an interface file. Instead, its binding in the type+ environment is created as part of typechecking the IfaceDecl for+ some other thing.++Examples:+ * All DataCons are implicit, because they are generated from the+ IfaceDecl for the data/newtype. Ditto class methods.++ * Record selectors are *not* implicit, because they get their own+ free-standing IfaceDecl.++ * Associated data/type families are implicit because they are+ included in the IfaceDecl of the parent class. (NB: the+ IfaceClass decl happens to use IfaceDecl recursively for the+ associated types, but that's irrelevant here.)++ * Dictionary function Ids are not implicit.++ * Axioms for newtypes are implicit (same as above), but axioms+ for data/type family instances are *not* implicit (like DFunIds).+-}++-- | Determine the 'TyThing's brought into scope by another 'TyThing'+-- /other/ than itself. For example, Id's don't have any implicit TyThings+-- as they just bring themselves into scope, but classes bring their+-- dictionary datatype, type constructor and some selector functions into+-- scope, just for a start!++-- N.B. the set of TyThings returned here *must* match the set of+-- names returned by LoadIface.ifaceDeclImplicitBndrs, in the sense that+-- TyThing.getOccName should define a bijection between the two lists.+-- This invariant is used in LoadIface.loadDecl (see note [Tricky iface loop])+-- The order of the list does not matter.+implicitTyThings :: TyThing -> [TyThing]+implicitTyThings (AnId _) = []+implicitTyThings (ACoAxiom _cc) = []+implicitTyThings (ATyCon tc) = implicitTyConThings tc+implicitTyThings (AConLike cl) = implicitConLikeThings cl++implicitConLikeThings :: ConLike -> [TyThing]+implicitConLikeThings (RealDataCon dc)+ = dataConImplicitTyThings dc++implicitConLikeThings (PatSynCon {})+ = [] -- Pattern synonyms have no implicit Ids; the wrapper and matcher+ -- are not "implicit"; they are simply new top-level bindings,+ -- and they have their own declaration in an interface file+ -- Unless a record pat syn when there are implicit selectors+ -- They are still not included here as `implicitConLikeThings` is+ -- used by `tcTyClsDecls` whilst pattern synonyms are typed checked+ -- by `tcTopValBinds`.++implicitClassThings :: Class -> [TyThing]+implicitClassThings cl+ = -- Does not include default methods, because those Ids may have+ -- their own pragmas, unfoldings etc, not derived from the Class object++ -- associated types+ -- No recursive call for the classATs, because they+ -- are only the family decls; they have no implicit things+ map ATyCon (classATs cl) ++++ -- superclass and operation selectors+ map AnId (classAllSelIds cl)++implicitTyConThings :: TyCon -> [TyThing]+implicitTyConThings tc+ = class_stuff +++ -- fields (names of selectors)++ -- (possibly) implicit newtype axioms+ -- or type family axioms+ implicitCoTyCon tc ++++ -- for each data constructor in order,+ -- the constructor, worker, and (possibly) wrapper+ [ thing | dc <- tyConDataCons tc+ , thing <- AConLike (RealDataCon dc) : dataConImplicitTyThings dc ]+ -- NB. record selectors are *not* implicit, they have fully-fledged+ -- bindings that pass through the compilation pipeline as normal.+ where+ class_stuff = case tyConClass_maybe tc of+ Nothing -> []+ Just cl -> implicitClassThings cl++-- For newtypes and closed type families (only) add the implicit coercion tycon+implicitCoTyCon :: TyCon -> [TyThing]+implicitCoTyCon tc+ | Just co <- newTyConCo_maybe tc = [ACoAxiom $ toBranchedAxiom co]+ | Just co <- isClosedSynFamilyTyConWithAxiom_maybe tc+ = [ACoAxiom co]+ | otherwise = []++-- | Returns @True@ if there should be no interface-file declaration+-- for this thing on its own: either it is built-in, or it is part+-- of some other declaration, or it is generated implicitly by some+-- other declaration.+isImplicitTyThing :: TyThing -> Bool+isImplicitTyThing (AConLike cl) = case cl of+ RealDataCon {} -> True+ PatSynCon {} -> False+isImplicitTyThing (AnId id) = isImplicitId id+isImplicitTyThing (ATyCon tc) = isImplicitTyCon tc+isImplicitTyThing (ACoAxiom ax) = isImplicitCoAxiom ax++-- | tyThingParent_maybe x returns (Just p)+-- when pprTyThingInContext should print a declaration for p+-- (albeit with some "..." in it) when asked to show x+-- It returns the *immediate* parent. So a datacon returns its tycon+-- but the tycon could be the associated type of a class, so it in turn+-- might have a parent.+tyThingParent_maybe :: TyThing -> Maybe TyThing+tyThingParent_maybe (AConLike cl) = case cl of+ RealDataCon dc -> Just (ATyCon (dataConTyCon dc))+ PatSynCon{} -> Nothing+tyThingParent_maybe (ATyCon tc) = case tyConAssoc_maybe tc of+ Just cls -> Just (ATyCon (classTyCon cls))+ Nothing -> Nothing+tyThingParent_maybe (AnId id) = case idDetails id of+ RecSelId { sel_tycon = RecSelData tc } ->+ Just (ATyCon tc)+ ClassOpId cls ->+ Just (ATyCon (classTyCon cls))+ _other -> Nothing+tyThingParent_maybe _other = Nothing++tyThingsTyCoVars :: [TyThing] -> TyCoVarSet+tyThingsTyCoVars tts =+ unionVarSets $ map ttToVarSet tts+ where+ ttToVarSet (AnId id) = tyCoVarsOfType $ idType id+ ttToVarSet (AConLike cl) = case cl of+ RealDataCon dc -> tyCoVarsOfType $ dataConRepType dc+ PatSynCon{} -> emptyVarSet+ ttToVarSet (ATyCon tc)+ = case tyConClass_maybe tc of+ Just cls -> (mkVarSet . fst . classTvsFds) cls+ Nothing -> tyCoVarsOfType $ tyConKind tc+ ttToVarSet (ACoAxiom _) = emptyVarSet++-- | The Names that a TyThing should bring into scope. Used to build+-- the GlobalRdrEnv for the InteractiveContext.+tyThingAvailInfo :: TyThing -> [AvailInfo]+tyThingAvailInfo (ATyCon t)+ = case tyConClass_maybe t of+ Just c -> [AvailTC n (n : map getName (classMethods c)+ ++ map getName (classATs c))+ [] ]+ where n = getName c+ Nothing -> [AvailTC n (n : map getName dcs) flds]+ where n = getName t+ dcs = tyConDataCons t+ flds = tyConFieldLabels t+tyThingAvailInfo (AConLike (PatSynCon p))+ = map avail ((getName p) : map flSelector (patSynFieldLabels p))+tyThingAvailInfo t+ = [avail (getName t)]++{-+************************************************************************+* *+ TypeEnv+* *+************************************************************************+-}++-- | A map from 'Name's to 'TyThing's, constructed by typechecking+-- local declarations or interface files+type TypeEnv = NameEnv TyThing++emptyTypeEnv :: TypeEnv+typeEnvElts :: TypeEnv -> [TyThing]+typeEnvTyCons :: TypeEnv -> [TyCon]+typeEnvCoAxioms :: TypeEnv -> [CoAxiom Branched]+typeEnvIds :: TypeEnv -> [Id]+typeEnvPatSyns :: TypeEnv -> [PatSyn]+typeEnvDataCons :: TypeEnv -> [DataCon]+typeEnvClasses :: TypeEnv -> [Class]+lookupTypeEnv :: TypeEnv -> Name -> Maybe TyThing++emptyTypeEnv = emptyNameEnv+typeEnvElts env = nameEnvElts env+typeEnvTyCons env = [tc | ATyCon tc <- typeEnvElts env]+typeEnvCoAxioms env = [ax | ACoAxiom ax <- typeEnvElts env]+typeEnvIds env = [id | AnId id <- typeEnvElts env]+typeEnvPatSyns env = [ps | AConLike (PatSynCon ps) <- typeEnvElts env]+typeEnvDataCons env = [dc | AConLike (RealDataCon dc) <- typeEnvElts env]+typeEnvClasses env = [cl | tc <- typeEnvTyCons env,+ Just cl <- [tyConClass_maybe tc]]++mkTypeEnv :: [TyThing] -> TypeEnv+mkTypeEnv things = extendTypeEnvList emptyTypeEnv things++mkTypeEnvWithImplicits :: [TyThing] -> TypeEnv+mkTypeEnvWithImplicits things =+ mkTypeEnv things+ `plusNameEnv`+ mkTypeEnv (concatMap implicitTyThings things)++typeEnvFromEntities :: [Id] -> [TyCon] -> [FamInst] -> TypeEnv+typeEnvFromEntities ids tcs famInsts =+ mkTypeEnv ( map AnId ids+ ++ map ATyCon all_tcs+ ++ concatMap implicitTyConThings all_tcs+ ++ map (ACoAxiom . toBranchedAxiom . famInstAxiom) famInsts+ )+ where+ all_tcs = tcs ++ famInstsRepTyCons famInsts++lookupTypeEnv = lookupNameEnv++-- Extend the type environment+extendTypeEnv :: TypeEnv -> TyThing -> TypeEnv+extendTypeEnv env thing = extendNameEnv env (getName thing) thing++extendTypeEnvList :: TypeEnv -> [TyThing] -> TypeEnv+extendTypeEnvList env things = foldl extendTypeEnv env things++extendTypeEnvWithIds :: TypeEnv -> [Id] -> TypeEnv+extendTypeEnvWithIds env ids+ = extendNameEnvList env [(getName id, AnId id) | id <- ids]++plusTypeEnv :: TypeEnv -> TypeEnv -> TypeEnv+plusTypeEnv env1 env2 = plusNameEnv env1 env2++-- | Find the 'TyThing' for the given 'Name' by using all the resources+-- at our disposal: the compiled modules in the 'HomePackageTable' and the+-- compiled modules in other packages that live in 'PackageTypeEnv'. Note+-- that this does NOT look up the 'TyThing' in the module being compiled: you+-- have to do that yourself, if desired+lookupType :: DynFlags+ -> HomePackageTable+ -> PackageTypeEnv+ -> Name+ -> Maybe TyThing++lookupType dflags hpt pte name+ | isOneShot (ghcMode dflags) -- in one-shot, we don't use the HPT+ = lookupNameEnv pte name+ | otherwise+ = case lookupHptByModule hpt mod of+ Just hm -> lookupNameEnv (md_types (hm_details hm)) name+ Nothing -> lookupNameEnv pte name+ where+ mod = ASSERT2( isExternalName name, ppr name )+ if isHoleName name+ then mkModule (thisPackage dflags) (moduleName (nameModule name))+ else nameModule name++-- | As 'lookupType', but with a marginally easier-to-use interface+-- if you have a 'HscEnv'+lookupTypeHscEnv :: HscEnv -> Name -> IO (Maybe TyThing)+lookupTypeHscEnv hsc_env name = do+ eps <- readIORef (hsc_EPS hsc_env)+ return $! lookupType dflags hpt (eps_PTE eps) name+ where+ dflags = hsc_dflags hsc_env+ hpt = hsc_HPT hsc_env++-- | Get the 'TyCon' from a 'TyThing' if it is a type constructor thing. Panics otherwise+tyThingTyCon :: TyThing -> TyCon+tyThingTyCon (ATyCon tc) = tc+tyThingTyCon other = pprPanic "tyThingTyCon" (ppr other)++-- | Get the 'CoAxiom' from a 'TyThing' if it is a coercion axiom thing. Panics otherwise+tyThingCoAxiom :: TyThing -> CoAxiom Branched+tyThingCoAxiom (ACoAxiom ax) = ax+tyThingCoAxiom other = pprPanic "tyThingCoAxiom" (ppr other)++-- | Get the 'DataCon' from a 'TyThing' if it is a data constructor thing. Panics otherwise+tyThingDataCon :: TyThing -> DataCon+tyThingDataCon (AConLike (RealDataCon dc)) = dc+tyThingDataCon other = pprPanic "tyThingDataCon" (ppr other)++-- | Get the 'ConLike' from a 'TyThing' if it is a data constructor thing.+-- Panics otherwise+tyThingConLike :: TyThing -> ConLike+tyThingConLike (AConLike dc) = dc+tyThingConLike other = pprPanic "tyThingConLike" (ppr other)++-- | Get the 'Id' from a 'TyThing' if it is a id *or* data constructor thing. Panics otherwise+tyThingId :: TyThing -> Id+tyThingId (AnId id) = id+tyThingId (AConLike (RealDataCon dc)) = dataConWrapId dc+tyThingId other = pprPanic "tyThingId" (ppr other)++{-+************************************************************************+* *+\subsection{MonadThings and friends}+* *+************************************************************************+-}++-- | Class that abstracts out the common ability of the monads in GHC+-- to lookup a 'TyThing' in the monadic environment by 'Name'. Provides+-- a number of related convenience functions for accessing particular+-- kinds of 'TyThing'+class Monad m => MonadThings m where+ lookupThing :: Name -> m TyThing++ lookupId :: Name -> m Id+ lookupId = liftM tyThingId . lookupThing++ lookupDataCon :: Name -> m DataCon+ lookupDataCon = liftM tyThingDataCon . lookupThing++ lookupTyCon :: Name -> m TyCon+ lookupTyCon = liftM tyThingTyCon . lookupThing++{-+************************************************************************+* *+\subsection{Auxiliary types}+* *+************************************************************************++These types are defined here because they are mentioned in ModDetails,+but they are mostly elaborated elsewhere+-}++------------------ Warnings -------------------------+-- | Warning information for a module+data Warnings+ = NoWarnings -- ^ Nothing deprecated+ | WarnAll WarningTxt -- ^ Whole module deprecated+ | WarnSome [(OccName,WarningTxt)] -- ^ Some specific things deprecated++ -- Only an OccName is needed because+ -- (1) a deprecation always applies to a binding+ -- defined in the module in which the deprecation appears.+ -- (2) deprecations are only reported outside the defining module.+ -- this is important because, otherwise, if we saw something like+ --+ -- {-# DEPRECATED f "" #-}+ -- f = ...+ -- h = f+ -- g = let f = undefined in f+ --+ -- we'd need more information than an OccName to know to say something+ -- about the use of f in h but not the use of the locally bound f in g+ --+ -- however, because we only report about deprecations from the outside,+ -- and a module can only export one value called f,+ -- an OccName suffices.+ --+ -- this is in contrast with fixity declarations, where we need to map+ -- a Name to its fixity declaration.+ deriving( Eq )++instance Binary Warnings where+ put_ bh NoWarnings = putByte bh 0+ put_ bh (WarnAll t) = do+ putByte bh 1+ put_ bh t+ put_ bh (WarnSome ts) = do+ putByte bh 2+ put_ bh ts++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return NoWarnings+ 1 -> do aa <- get bh+ return (WarnAll aa)+ _ -> do aa <- get bh+ return (WarnSome aa)++-- | Constructs the cache for the 'mi_warn_fn' field of a 'ModIface'+mkIfaceWarnCache :: Warnings -> OccName -> Maybe WarningTxt+mkIfaceWarnCache NoWarnings = \_ -> Nothing+mkIfaceWarnCache (WarnAll t) = \_ -> Just t+mkIfaceWarnCache (WarnSome pairs) = lookupOccEnv (mkOccEnv pairs)++emptyIfaceWarnCache :: OccName -> Maybe WarningTxt+emptyIfaceWarnCache _ = Nothing++plusWarns :: Warnings -> Warnings -> Warnings+plusWarns d NoWarnings = d+plusWarns NoWarnings d = d+plusWarns _ (WarnAll t) = WarnAll t+plusWarns (WarnAll t) _ = WarnAll t+plusWarns (WarnSome v1) (WarnSome v2) = WarnSome (v1 ++ v2)++-- | Creates cached lookup for the 'mi_fix_fn' field of 'ModIface'+mkIfaceFixCache :: [(OccName, Fixity)] -> OccName -> Maybe Fixity+mkIfaceFixCache pairs+ = \n -> lookupOccEnv env n+ where+ env = mkOccEnv pairs++emptyIfaceFixCache :: OccName -> Maybe Fixity+emptyIfaceFixCache _ = Nothing++-- | Fixity environment mapping names to their fixities+type FixityEnv = NameEnv FixItem++-- | Fixity information for an 'Name'. We keep the OccName in the range+-- so that we can generate an interface from it+data FixItem = FixItem OccName Fixity++instance Outputable FixItem where+ ppr (FixItem occ fix) = ppr fix <+> ppr occ++emptyFixityEnv :: FixityEnv+emptyFixityEnv = emptyNameEnv++lookupFixity :: FixityEnv -> Name -> Fixity+lookupFixity env n = case lookupNameEnv env n of+ Just (FixItem _ fix) -> fix+ Nothing -> defaultFixity++{-+************************************************************************+* *+\subsection{WhatsImported}+* *+************************************************************************+-}++-- | Records whether a module has orphans. An \"orphan\" is one of:+--+-- * An instance declaration in a module other than the definition+-- module for one of the type constructors or classes in the instance head+--+-- * A transformation rule in a module other than the one defining+-- the function in the head of the rule+--+-- * A vectorisation pragma+type WhetherHasOrphans = Bool++-- | Does this module define family instances?+type WhetherHasFamInst = Bool++-- | Did this module originate from a *-boot file?+type IsBootInterface = Bool++-- | Dependency information about ALL modules and packages below this one+-- in the import hierarchy.+--+-- Invariant: the dependencies of a module @M@ never includes @M@.+--+-- Invariant: none of the lists contain duplicates.+data Dependencies+ = Deps { dep_mods :: [(ModuleName, IsBootInterface)]+ -- ^ All home-package modules transitively below this one+ -- I.e. modules that this one imports, or that are in the+ -- dep_mods of those directly-imported modules++ , dep_pkgs :: [(InstalledUnitId, Bool)]+ -- ^ All packages transitively below this module+ -- I.e. packages to which this module's direct imports belong,+ -- or that are in the dep_pkgs of those modules+ -- The bool indicates if the package is required to be+ -- trusted when the module is imported as a safe import+ -- (Safe Haskell). See Note [RnNames . Tracking Trust Transitively]++ , dep_orphs :: [Module]+ -- ^ Transitive closure of orphan modules (whether+ -- home or external pkg).+ --+ -- (Possible optimization: don't include family+ -- instance orphans as they are anyway included in+ -- 'dep_finsts'. But then be careful about code+ -- which relies on dep_orphs having the complete list!)+ -- This does NOT include us, unlike 'imp_orphs'.++ , dep_finsts :: [Module]+ -- ^ Transitive closure of depended upon modules which+ -- contain family instances (whether home or external).+ -- This is used by 'checkFamInstConsistency'. This+ -- does NOT include us, unlike 'imp_finsts'. See Note+ -- [The type family instance consistency story].+ }+ deriving( Eq )+ -- Equality used only for old/new comparison in MkIface.addFingerprints+ -- See 'TcRnTypes.ImportAvails' for details on dependencies.++instance Binary Dependencies where+ put_ bh deps = do put_ bh (dep_mods deps)+ put_ bh (dep_pkgs deps)+ put_ bh (dep_orphs deps)+ put_ bh (dep_finsts deps)++ get bh = do ms <- get bh+ ps <- get bh+ os <- get bh+ fis <- get bh+ return (Deps { dep_mods = ms, dep_pkgs = ps, dep_orphs = os,+ dep_finsts = fis })++noDependencies :: Dependencies+noDependencies = Deps [] [] [] []++-- | Records modules for which changes may force recompilation of this module+-- See wiki: http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance+--+-- This differs from Dependencies. A module X may be in the dep_mods of this+-- module (via an import chain) but if we don't use anything from X it won't+-- appear in our Usage+data Usage+ -- | Module from another package+ = UsagePackageModule {+ usg_mod :: Module,+ -- ^ External package module depended on+ usg_mod_hash :: Fingerprint,+ -- ^ Cached module fingerprint+ usg_safe :: IsSafeImport+ -- ^ Was this module imported as a safe import+ }+ -- | Module from the current package+ | UsageHomeModule {+ usg_mod_name :: ModuleName,+ -- ^ Name of the module+ usg_mod_hash :: Fingerprint,+ -- ^ Cached module fingerprint+ usg_entities :: [(OccName,Fingerprint)],+ -- ^ Entities we depend on, sorted by occurrence name and fingerprinted.+ -- NB: usages are for parent names only, e.g. type constructors+ -- but not the associated data constructors.+ usg_exports :: Maybe Fingerprint,+ -- ^ Fingerprint for the export list of this module,+ -- if we directly imported it (and hence we depend on its export list)+ usg_safe :: IsSafeImport+ -- ^ Was this module imported as a safe import+ } -- ^ Module from the current package+ -- | A file upon which the module depends, e.g. a CPP #include, or using TH's+ -- 'addDependentFile'+ | UsageFile {+ usg_file_path :: FilePath,+ -- ^ External file dependency. From a CPP #include or TH+ -- addDependentFile. Should be absolute.+ usg_file_hash :: Fingerprint+ -- ^ 'Fingerprint' of the file contents.++ -- Note: We don't consider things like modification timestamps+ -- here, because there's no reason to recompile if the actual+ -- contents don't change. This previously lead to odd+ -- recompilation behaviors; see #8114+ }+ -- | A requirement which was merged into this one.+ | UsageMergedRequirement {+ usg_mod :: Module,+ usg_mod_hash :: Fingerprint+ }+ deriving( Eq )+ -- The export list field is (Just v) if we depend on the export list:+ -- i.e. we imported the module directly, whether or not we+ -- enumerated the things we imported, or just imported+ -- everything+ -- We need to recompile if M's exports change, because+ -- if the import was import M, we might now have a name clash+ -- in the importing module.+ -- if the import was import M(x) M might no longer export x+ -- The only way we don't depend on the export list is if we have+ -- import M()+ -- And of course, for modules that aren't imported directly we don't+ -- depend on their export lists++instance Binary Usage where+ put_ bh usg@UsagePackageModule{} = do+ putByte bh 0+ put_ bh (usg_mod usg)+ put_ bh (usg_mod_hash usg)+ put_ bh (usg_safe usg)++ put_ bh usg@UsageHomeModule{} = do+ putByte bh 1+ put_ bh (usg_mod_name usg)+ put_ bh (usg_mod_hash usg)+ put_ bh (usg_exports usg)+ put_ bh (usg_entities usg)+ put_ bh (usg_safe usg)++ put_ bh usg@UsageFile{} = do+ putByte bh 2+ put_ bh (usg_file_path usg)+ put_ bh (usg_file_hash usg)++ put_ bh usg@UsageMergedRequirement{} = do+ putByte bh 3+ put_ bh (usg_mod usg)+ put_ bh (usg_mod_hash usg)++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do+ nm <- get bh+ mod <- get bh+ safe <- get bh+ return UsagePackageModule { usg_mod = nm, usg_mod_hash = mod, usg_safe = safe }+ 1 -> do+ nm <- get bh+ mod <- get bh+ exps <- get bh+ ents <- get bh+ safe <- get bh+ return UsageHomeModule { usg_mod_name = nm, usg_mod_hash = mod,+ usg_exports = exps, usg_entities = ents, usg_safe = safe }+ 2 -> do+ fp <- get bh+ hash <- get bh+ return UsageFile { usg_file_path = fp, usg_file_hash = hash }+ 3 -> do+ mod <- get bh+ hash <- get bh+ return UsageMergedRequirement { usg_mod = mod, usg_mod_hash = hash }+ i -> error ("Binary.get(Usage): " ++ show i)++{-+************************************************************************+* *+ The External Package State+* *+************************************************************************+-}++type PackageTypeEnv = TypeEnv+type PackageRuleBase = RuleBase+type PackageInstEnv = InstEnv+type PackageFamInstEnv = FamInstEnv+type PackageVectInfo = VectInfo+type PackageAnnEnv = AnnEnv+type PackageCompleteMatchMap = CompleteMatchMap++-- | Information about other packages that we have slurped in by reading+-- their interface files+data ExternalPackageState+ = EPS {+ eps_is_boot :: !(ModuleNameEnv (ModuleName, IsBootInterface)),+ -- ^ In OneShot mode (only), home-package modules+ -- accumulate in the external package state, and are+ -- sucked in lazily. For these home-pkg modules+ -- (only) we need to record which are boot modules.+ -- We set this field after loading all the+ -- explicitly-imported interfaces, but before doing+ -- anything else+ --+ -- The 'ModuleName' part is not necessary, but it's useful for+ -- debug prints, and it's convenient because this field comes+ -- direct from 'TcRnTypes.imp_dep_mods'++ eps_PIT :: !PackageIfaceTable,+ -- ^ The 'ModIface's for modules in external packages+ -- whose interfaces we have opened.+ -- The declarations in these interface files are held in the+ -- 'eps_decls', 'eps_inst_env', 'eps_fam_inst_env' and 'eps_rules'+ -- fields of this record, not in the 'mi_decls' fields of the+ -- interface we have sucked in.+ --+ -- What /is/ in the PIT is:+ --+ -- * The Module+ --+ -- * Fingerprint info+ --+ -- * Its exports+ --+ -- * Fixities+ --+ -- * Deprecations and warnings++ eps_free_holes :: InstalledModuleEnv (UniqDSet ModuleName),+ -- ^ Cache for 'mi_free_holes'. Ordinarily, we can rely on+ -- the 'eps_PIT' for this information, EXCEPT that when+ -- we do dependency analysis, we need to look at the+ -- 'Dependencies' of our imports to determine what their+ -- precise free holes are ('moduleFreeHolesPrecise'). We+ -- don't want to repeatedly reread in the interface+ -- for every import, so cache it here. When the PIT+ -- gets filled in we can drop these entries.++ eps_PTE :: !PackageTypeEnv,+ -- ^ Result of typechecking all the external package+ -- interface files we have sucked in. The domain of+ -- the mapping is external-package modules++ eps_inst_env :: !PackageInstEnv, -- ^ The total 'InstEnv' accumulated+ -- from all the external-package modules+ eps_fam_inst_env :: !PackageFamInstEnv,-- ^ The total 'FamInstEnv' accumulated+ -- from all the external-package modules+ eps_rule_base :: !PackageRuleBase, -- ^ The total 'RuleEnv' accumulated+ -- from all the external-package modules+ eps_vect_info :: !PackageVectInfo, -- ^ The total 'VectInfo' accumulated+ -- from all the external-package modules+ eps_ann_env :: !PackageAnnEnv, -- ^ The total 'AnnEnv' accumulated+ -- from all the external-package modules+ eps_complete_matches :: !PackageCompleteMatchMap,+ -- ^ The total 'CompleteMatchMap' accumulated+ -- from all the external-package modules++ eps_mod_fam_inst_env :: !(ModuleEnv FamInstEnv), -- ^ The family instances accumulated from external+ -- packages, keyed off the module that declared them++ eps_stats :: !EpsStats -- ^ Stastics about what was loaded from external packages+ }++-- | Accumulated statistics about what we are putting into the 'ExternalPackageState'.+-- \"In\" means stuff that is just /read/ from interface files,+-- \"Out\" means actually sucked in and type-checked+data EpsStats = EpsStats { n_ifaces_in+ , n_decls_in, n_decls_out+ , n_rules_in, n_rules_out+ , n_insts_in, n_insts_out :: !Int }++addEpsInStats :: EpsStats -> Int -> Int -> Int -> EpsStats+-- ^ Add stats for one newly-read interface+addEpsInStats stats n_decls n_insts n_rules+ = stats { n_ifaces_in = n_ifaces_in stats + 1+ , n_decls_in = n_decls_in stats + n_decls+ , n_insts_in = n_insts_in stats + n_insts+ , n_rules_in = n_rules_in stats + n_rules }++{-+Names in a NameCache are always stored as a Global, and have the SrcLoc+of their binding locations.++Actually that's not quite right. When we first encounter the original+name, we might not be at its binding site (e.g. we are reading an+interface file); so we give it 'noSrcLoc' then. Later, when we find+its binding site, we fix it up.+-}++updNameCacheIO :: HscEnv+ -> (NameCache -> (NameCache, c)) -- The updating function+ -> IO c+updNameCacheIO hsc_env upd_fn+ = atomicModifyIORef' (hsc_NC hsc_env) upd_fn++mkSOName :: Platform -> FilePath -> FilePath+mkSOName platform root+ = case platformOS platform of+ OSMinGW32 -> root <.> soExt platform+ _ -> ("lib" ++ root) <.> soExt platform++mkHsSOName :: Platform -> FilePath -> FilePath+mkHsSOName platform root = ("lib" ++ root) <.> soExt platform++soExt :: Platform -> FilePath+soExt platform+ = case platformOS platform of+ OSDarwin -> "dylib"+ OSiOS -> "dylib"+ OSMinGW32 -> "dll"+ _ -> "so"++{-+************************************************************************+* *+ The module graph and ModSummary type+ A ModSummary is a node in the compilation manager's+ dependency graph, and it's also passed to hscMain+* *+************************************************************************+-}++-- | A ModuleGraph contains all the nodes from the home package (only).+-- There will be a node for each source module, plus a node for each hi-boot+-- module.+--+-- The graph is not necessarily stored in topologically-sorted order. Use+-- 'GHC.topSortModuleGraph' and 'Digraph.flattenSCC' to achieve this.+type ModuleGraph = [ModSummary]++emptyMG :: ModuleGraph+emptyMG = []++-- | A single node in a 'ModuleGraph'. The nodes of the module graph+-- are one of:+--+-- * A regular Haskell source module+-- * A hi-boot source module+--+data ModSummary+ = ModSummary {+ ms_mod :: Module,+ -- ^ Identity of the module+ ms_hsc_src :: HscSource,+ -- ^ The module source either plain Haskell or hs-boot+ ms_location :: ModLocation,+ -- ^ Location of the various files belonging to the module+ ms_hs_date :: UTCTime,+ -- ^ Timestamp of source file+ ms_obj_date :: Maybe UTCTime,+ -- ^ Timestamp of object, if we have one+ ms_iface_date :: Maybe UTCTime,+ -- ^ Timestamp of hi file, if we *only* are typechecking (it is+ -- 'Nothing' otherwise.+ -- See Note [Recompilation checking when typechecking only] and #9243+ ms_srcimps :: [(Maybe FastString, Located ModuleName)],+ -- ^ Source imports of the module+ ms_textual_imps :: [(Maybe FastString, Located ModuleName)],+ -- ^ Non-source imports of the module from the module *text*+ ms_parsed_mod :: Maybe HsParsedModule,+ -- ^ The parsed, nonrenamed source, if we have it. This is also+ -- used to support "inline module syntax" in Backpack files.+ ms_hspp_file :: FilePath,+ -- ^ Filename of preprocessed source file+ ms_hspp_opts :: DynFlags,+ -- ^ Cached flags from @OPTIONS@, @INCLUDE@ and @LANGUAGE@+ -- pragmas in the modules source code+ ms_hspp_buf :: Maybe StringBuffer+ -- ^ The actual preprocessed source, if we have it+ }++ms_installed_mod :: ModSummary -> InstalledModule+ms_installed_mod = fst . splitModuleInsts . ms_mod++ms_mod_name :: ModSummary -> ModuleName+ms_mod_name = moduleName . ms_mod++ms_imps :: ModSummary -> [(Maybe FastString, Located ModuleName)]+ms_imps ms =+ ms_textual_imps ms +++ map mk_additional_import (dynFlagDependencies (ms_hspp_opts ms))+ where+ mk_additional_import mod_nm = (Nothing, noLoc mod_nm)++-- The ModLocation contains both the original source filename and the+-- filename of the cleaned-up source file after all preprocessing has been+-- done. The point is that the summariser will have to cpp/unlit/whatever+-- all files anyway, and there's no point in doing this twice -- just+-- park the result in a temp file, put the name of it in the location,+-- and let @compile@ read from that file on the way back up.++-- The ModLocation is stable over successive up-sweeps in GHCi, wheres+-- the ms_hs_date and imports can, of course, change++msHsFilePath, msHiFilePath, msObjFilePath :: ModSummary -> FilePath+msHsFilePath ms = expectJust "msHsFilePath" (ml_hs_file (ms_location ms))+msHiFilePath ms = ml_hi_file (ms_location ms)+msObjFilePath ms = ml_obj_file (ms_location ms)++-- | Did this 'ModSummary' originate from a hs-boot file?+isBootSummary :: ModSummary -> Bool+isBootSummary ms = ms_hsc_src ms == HsBootFile++instance Outputable ModSummary where+ ppr ms+ = sep [text "ModSummary {",+ nest 3 (sep [text "ms_hs_date = " <> text (show (ms_hs_date ms)),+ text "ms_mod =" <+> ppr (ms_mod ms)+ <> text (hscSourceString (ms_hsc_src ms)) <> comma,+ text "ms_textual_imps =" <+> ppr (ms_textual_imps ms),+ text "ms_srcimps =" <+> ppr (ms_srcimps ms)]),+ char '}'+ ]++showModMsg :: DynFlags -> HscTarget -> Bool -> ModSummary -> String+showModMsg dflags target recomp mod_summary = showSDoc dflags $+ if gopt Opt_HideSourcePaths dflags+ then text mod_str+ else hsep+ [ text (mod_str ++ replicate (max 0 (16 - length mod_str)) ' ')+ , char '('+ , text (op $ msHsFilePath mod_summary) <> char ','+ , case target of+ HscInterpreted | recomp -> text "interpreted"+ HscNothing -> text "nothing"+ _ -> text (op $ msObjFilePath mod_summary)+ , char ')'+ ]+ where+ op = normalise+ mod = moduleName (ms_mod mod_summary)+ mod_str = showPpr dflags mod ++ hscSourceString (ms_hsc_src mod_summary)++{-+************************************************************************+* *+\subsection{Recmpilation}+* *+************************************************************************+-}++-- | Indicates whether a given module's source has been modified since it+-- was last compiled.+data SourceModified+ = SourceModified+ -- ^ the source has been modified+ | SourceUnmodified+ -- ^ the source has not been modified. Compilation may or may+ -- not be necessary, depending on whether any dependencies have+ -- changed since we last compiled.+ | SourceUnmodifiedAndStable+ -- ^ the source has not been modified, and furthermore all of+ -- its (transitive) dependencies are up to date; it definitely+ -- does not need to be recompiled. This is important for two+ -- reasons: (a) we can omit the version check in checkOldIface,+ -- and (b) if the module used TH splices we don't need to force+ -- recompilation.++{-+************************************************************************+* *+\subsection{Hpc Support}+* *+************************************************************************+-}++-- | Information about a modules use of Haskell Program Coverage+data HpcInfo+ = HpcInfo+ { hpcInfoTickCount :: Int+ , hpcInfoHash :: Int+ }+ | NoHpcInfo+ { hpcUsed :: AnyHpcUsage -- ^ Is hpc used anywhere on the module \*tree\*?+ }++-- | This is used to signal if one of my imports used HPC instrumentation+-- even if there is no module-local HPC usage+type AnyHpcUsage = Bool++emptyHpcInfo :: AnyHpcUsage -> HpcInfo+emptyHpcInfo = NoHpcInfo++-- | Find out if HPC is used by this module or any of the modules+-- it depends upon+isHpcUsed :: HpcInfo -> AnyHpcUsage+isHpcUsed (HpcInfo {}) = True+isHpcUsed (NoHpcInfo { hpcUsed = used }) = used++{-+************************************************************************+* *+\subsection{Vectorisation Support}+* *+************************************************************************++The following information is generated and consumed by the vectorisation+subsystem. It communicates the vectorisation status of declarations from one+module to another.++Why do we need both f and f_v in the ModGuts/ModDetails/EPS version VectInfo+below? We need to know `f' when converting to IfaceVectInfo. However, during+vectorisation, we need to know `f_v', whose `Var' we cannot lookup based+on just the OccName easily in a Core pass.+-}++-- |Vectorisation information for 'ModGuts', 'ModDetails' and 'ExternalPackageState'; see also+-- documentation at 'Vectorise.Env.GlobalEnv'.+--+-- NB: The following tables may also include 'Var's, 'TyCon's and 'DataCon's from imported modules,+-- which have been subsequently vectorised in the current module.+--+data VectInfo+ = VectInfo+ { vectInfoVar :: DVarEnv (Var , Var ) -- ^ @(f, f_v)@ keyed on @f@+ , vectInfoTyCon :: NameEnv (TyCon , TyCon) -- ^ @(T, T_v)@ keyed on @T@+ , vectInfoDataCon :: NameEnv (DataCon, DataCon) -- ^ @(C, C_v)@ keyed on @C@+ , vectInfoParallelVars :: DVarSet -- ^ set of parallel variables+ , vectInfoParallelTyCons :: NameSet -- ^ set of parallel type constructors+ }++-- |Vectorisation information for 'ModIface'; i.e, the vectorisation information propagated+-- across module boundaries.+--+-- NB: The field 'ifaceVectInfoVar' explicitly contains the workers of data constructors as well as+-- class selectors — i.e., their mappings are /not/ implicitly generated from the data types.+-- Moreover, whether the worker of a data constructor is in 'ifaceVectInfoVar' determines+-- whether that data constructor was vectorised (or is part of an abstractly vectorised type+-- constructor).+--+data IfaceVectInfo+ = IfaceVectInfo+ { ifaceVectInfoVar :: [Name] -- ^ All variables in here have a vectorised variant+ , ifaceVectInfoTyCon :: [Name] -- ^ All 'TyCon's in here have a vectorised variant;+ -- the name of the vectorised variant and those of its+ -- data constructors are determined by+ -- 'OccName.mkVectTyConOcc' and+ -- 'OccName.mkVectDataConOcc'; the names of the+ -- isomorphisms are determined by 'OccName.mkVectIsoOcc'+ , ifaceVectInfoTyConReuse :: [Name] -- ^ The vectorised form of all the 'TyCon's in here+ -- coincides with the unconverted form; the name of the+ -- isomorphisms is determined by 'OccName.mkVectIsoOcc'+ , ifaceVectInfoParallelVars :: [Name] -- iface version of 'vectInfoParallelVar'+ , ifaceVectInfoParallelTyCons :: [Name] -- iface version of 'vectInfoParallelTyCon'+ }++noVectInfo :: VectInfo+noVectInfo+ = VectInfo emptyDVarEnv emptyNameEnv emptyNameEnv emptyDVarSet emptyNameSet++plusVectInfo :: VectInfo -> VectInfo -> VectInfo+plusVectInfo vi1 vi2 =+ VectInfo (vectInfoVar vi1 `plusDVarEnv` vectInfoVar vi2)+ (vectInfoTyCon vi1 `plusNameEnv` vectInfoTyCon vi2)+ (vectInfoDataCon vi1 `plusNameEnv` vectInfoDataCon vi2)+ (vectInfoParallelVars vi1 `unionDVarSet` vectInfoParallelVars vi2)+ (vectInfoParallelTyCons vi1 `unionNameSet` vectInfoParallelTyCons vi2)++concatVectInfo :: [VectInfo] -> VectInfo+concatVectInfo = foldr plusVectInfo noVectInfo++noIfaceVectInfo :: IfaceVectInfo+noIfaceVectInfo = IfaceVectInfo [] [] [] [] []++isNoIfaceVectInfo :: IfaceVectInfo -> Bool+isNoIfaceVectInfo (IfaceVectInfo l1 l2 l3 l4 l5)+ = null l1 && null l2 && null l3 && null l4 && null l5++instance Outputable VectInfo where+ ppr info = vcat+ [ text "variables :" <+> ppr (vectInfoVar info)+ , text "tycons :" <+> ppr (vectInfoTyCon info)+ , text "datacons :" <+> ppr (vectInfoDataCon info)+ , text "parallel vars :" <+> ppr (vectInfoParallelVars info)+ , text "parallel tycons :" <+> ppr (vectInfoParallelTyCons info)+ ]++instance Outputable IfaceVectInfo where+ ppr info = vcat+ [ text "variables :" <+> ppr (ifaceVectInfoVar info)+ , text "tycons :" <+> ppr (ifaceVectInfoTyCon info)+ , text "tycons reuse :" <+> ppr (ifaceVectInfoTyConReuse info)+ , text "parallel vars :" <+> ppr (ifaceVectInfoParallelVars info)+ , text "parallel tycons :" <+> ppr (ifaceVectInfoParallelTyCons info)+ ]+++instance Binary IfaceVectInfo where+ put_ bh (IfaceVectInfo a1 a2 a3 a4 a5) = do+ put_ bh a1+ put_ bh a2+ put_ bh a3+ put_ bh a4+ put_ bh a5+ get bh = do+ a1 <- get bh+ a2 <- get bh+ a3 <- get bh+ a4 <- get bh+ a5 <- get bh+ return (IfaceVectInfo a1 a2 a3 a4 a5)++{-+************************************************************************+* *+\subsection{Safe Haskell Support}+* *+************************************************************************++This stuff here is related to supporting the Safe Haskell extension,+primarily about storing under what trust type a module has been compiled.+-}++-- | Is an import a safe import?+type IsSafeImport = Bool++-- | Safe Haskell information for 'ModIface'+-- Simply a wrapper around SafeHaskellMode to sepperate iface and flags+newtype IfaceTrustInfo = TrustInfo SafeHaskellMode++getSafeMode :: IfaceTrustInfo -> SafeHaskellMode+getSafeMode (TrustInfo x) = x++setSafeMode :: SafeHaskellMode -> IfaceTrustInfo+setSafeMode = TrustInfo++noIfaceTrustInfo :: IfaceTrustInfo+noIfaceTrustInfo = setSafeMode Sf_None++trustInfoToNum :: IfaceTrustInfo -> Word8+trustInfoToNum it+ = case getSafeMode it of+ Sf_None -> 0+ Sf_Unsafe -> 1+ Sf_Trustworthy -> 2+ Sf_Safe -> 3++numToTrustInfo :: Word8 -> IfaceTrustInfo+numToTrustInfo 0 = setSafeMode Sf_None+numToTrustInfo 1 = setSafeMode Sf_Unsafe+numToTrustInfo 2 = setSafeMode Sf_Trustworthy+numToTrustInfo 3 = setSafeMode Sf_Safe+numToTrustInfo 4 = setSafeMode Sf_Safe -- retained for backwards compat, used+ -- to be Sf_SafeInfered but we no longer+ -- differentiate.+numToTrustInfo n = error $ "numToTrustInfo: bad input number! (" ++ show n ++ ")"++instance Outputable IfaceTrustInfo where+ ppr (TrustInfo Sf_None) = text "none"+ ppr (TrustInfo Sf_Unsafe) = text "unsafe"+ ppr (TrustInfo Sf_Trustworthy) = text "trustworthy"+ ppr (TrustInfo Sf_Safe) = text "safe"++instance Binary IfaceTrustInfo where+ put_ bh iftrust = putByte bh $ trustInfoToNum iftrust+ get bh = getByte bh >>= (return . numToTrustInfo)++{-+************************************************************************+* *+\subsection{Parser result}+* *+************************************************************************+-}++data HsParsedModule = HsParsedModule {+ hpm_module :: Located (HsModule RdrName),+ hpm_src_files :: [FilePath],+ -- ^ extra source files (e.g. from #includes). The lexer collects+ -- these from '# <file> <line>' pragmas, which the C preprocessor+ -- leaves behind. These files and their timestamps are stored in+ -- the .hi file, so that we can force recompilation if any of+ -- them change (#3589)+ hpm_annotations :: ApiAnns+ -- See note [Api annotations] in ApiAnnotation.hs+ }++{-+************************************************************************+* *+\subsection{Linkable stuff}+* *+************************************************************************++This stuff is in here, rather than (say) in Linker.hs, because the Linker.hs+stuff is the *dynamic* linker, and isn't present in a stage-1 compiler+-}++-- | Information we can use to dynamically link modules into the compiler+data Linkable = LM {+ linkableTime :: UTCTime, -- ^ Time at which this linkable was built+ -- (i.e. when the bytecodes were produced,+ -- or the mod date on the files)+ linkableModule :: Module, -- ^ The linkable module itself+ linkableUnlinked :: [Unlinked]+ -- ^ Those files and chunks of code we have yet to link.+ --+ -- INVARIANT: A valid linkable always has at least one 'Unlinked' item.+ -- If this list is empty, the Linkable represents a fake linkable, which+ -- is generated in HscNothing mode to avoid recompiling modules.+ --+ -- ToDo: Do items get removed from this list when they get linked?+ }++isObjectLinkable :: Linkable -> Bool+isObjectLinkable l = not (null unlinked) && all isObject unlinked+ where unlinked = linkableUnlinked l+ -- A linkable with no Unlinked's is treated as a BCO. We can+ -- generate a linkable with no Unlinked's as a result of+ -- compiling a module in HscNothing mode, and this choice+ -- happens to work well with checkStability in module GHC.++linkableObjs :: Linkable -> [FilePath]+linkableObjs l = [ f | DotO f <- linkableUnlinked l ]++instance Outputable Linkable where+ ppr (LM when_made mod unlinkeds)+ = (text "LinkableM" <+> parens (text (show when_made)) <+> ppr mod)+ $$ nest 3 (ppr unlinkeds)++-------------------------------------------++-- | Objects which have yet to be linked by the compiler+data Unlinked+ = DotO FilePath -- ^ An object file (.o)+ | DotA FilePath -- ^ Static archive file (.a)+ | DotDLL FilePath -- ^ Dynamically linked library file (.so, .dll, .dylib)+ | BCOs CompiledByteCode+ [SptEntry] -- ^ A byte-code object, lives only in memory. Also+ -- carries some static pointer table entries which+ -- should be loaded along with the BCOs.+ -- See Note [Grant plan for static forms] in+ -- StaticPtrTable.++instance Outputable Unlinked where+ ppr (DotO path) = text "DotO" <+> text path+ ppr (DotA path) = text "DotA" <+> text path+ ppr (DotDLL path) = text "DotDLL" <+> text path+ ppr (BCOs bcos spt) = text "BCOs" <+> ppr bcos <+> ppr spt++-- | Is this an actual file on disk we can link in somehow?+isObject :: Unlinked -> Bool+isObject (DotO _) = True+isObject (DotA _) = True+isObject (DotDLL _) = True+isObject _ = False++-- | Is this a bytecode linkable with no file on disk?+isInterpretable :: Unlinked -> Bool+isInterpretable = not . isObject++-- | Retrieve the filename of the linkable if possible. Panic if it is a byte-code object+nameOfObject :: Unlinked -> FilePath+nameOfObject (DotO fn) = fn+nameOfObject (DotA fn) = fn+nameOfObject (DotDLL fn) = fn+nameOfObject other = pprPanic "nameOfObject" (ppr other)++-- | Retrieve the compiled byte-code if possible. Panic if it is a file-based linkable+byteCodeOfObject :: Unlinked -> CompiledByteCode+byteCodeOfObject (BCOs bc _) = bc+byteCodeOfObject other = pprPanic "byteCodeOfObject" (ppr other)+++-------------------------------------------++-- | A list of conlikes which represents a complete pattern match.+-- These arise from @COMPLETE@ signatures.++-- See Note [Implementation of COMPLETE signatures]+data CompleteMatch = CompleteMatch {+ completeMatchConLikes :: [Name]+ -- ^ The ConLikes that form a covering family+ -- (e.g. Nothing, Just)+ , completeMatchTyCon :: Name+ -- ^ The TyCon that they cover (e.g. Maybe)+ }++instance Outputable CompleteMatch where+ ppr (CompleteMatch cl ty) = text "CompleteMatch:" <+> ppr cl+ <+> dcolon <+> ppr ty++-- | A map keyed by the 'completeMatchTyCon'.++-- See Note [Implementation of COMPLETE signatures]+type CompleteMatchMap = UniqFM [CompleteMatch]++mkCompleteMatchMap :: [CompleteMatch] -> CompleteMatchMap+mkCompleteMatchMap = extendCompleteMatchMap emptyUFM++extendCompleteMatchMap :: CompleteMatchMap -> [CompleteMatch]+ -> CompleteMatchMap+extendCompleteMatchMap = foldl' insertMatch+ where+ insertMatch :: CompleteMatchMap -> CompleteMatch -> CompleteMatchMap+ insertMatch ufm c@(CompleteMatch _ t) = addToUFM_C (++) ufm t [c]++{-+Note [Implementation of COMPLETE signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A COMPLETE signature represents a set of conlikes (i.e., constructors or+pattern synonyms) such that if they are all pattern-matched against in a+function, it gives rise to a total function. An example is:++ newtype Boolean = Boolean Int+ pattern F, T :: Boolean+ pattern F = Boolean 0+ pattern T = Boolean 1+ {-# COMPLETE F, T #-}++ -- This is a total function+ booleanToInt :: Boolean -> Int+ booleanToInt F = 0+ booleanToInt T = 1++COMPLETE sets are represented internally in GHC with the CompleteMatch data+type. For example, {-# COMPLETE F, T #-} would be represented as:++ CompleteMatch { complateMatchConLikes = [F, T]+ , completeMatchTyCon = Boolean }++Note that GHC was able to infer the completeMatchTyCon (Boolean), but for the+cases in which it's ambiguous, you can also explicitly specify it in the source+language by writing this:++ {-# COMPLETE F, T :: Boolean #-}++For efficiency purposes, GHC collects all of the CompleteMatches that it knows+about into a CompleteMatchMap, which is a map that is keyed by the+completeMatchTyCon. In other words, you could have a multiple COMPLETE sets+for the same TyCon:++ {-# COMPLETE F, T1 :: Boolean #-}+ {-# COMPLETE F, T2 :: Boolean #-}++And looking up the values in the CompleteMatchMap associated with Boolean+would give you [CompleteMatch [F, T1] Boolean, CompleteMatch [F, T2] Boolean].+dsGetCompleteMatches in DsMeta accomplishes this lookup.++Also see Note [Typechecking Complete Matches] in TcBinds for a more detailed+explanation for how GHC ensures that all the conlikes in a COMPLETE set are+consistent.+-}
+ main/InteractiveEval.hs view
@@ -0,0 +1,937 @@+{-# LANGUAGE CPP, MagicHash, NondecreasingIndentation, UnboxedTuples,+ RecordWildCards, BangPatterns #-}++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2005-2007+--+-- Running statements interactively+--+-- -----------------------------------------------------------------------------++module InteractiveEval (+ Resume(..), History(..),+ execStmt, ExecOptions(..), execOptions, ExecResult(..), resumeExec,+ runDecls, runDeclsWithLocation,+ isStmt, hasImport, isImport, isDecl,+ parseImportDecl, SingleStep(..),+ abandon, abandonAll,+ getResumeContext,+ getHistorySpan,+ getModBreaks,+ getHistoryModule,+ back, forward,+ setContext, getContext,+ availsToGlobalRdrEnv,+ getNamesInScope,+ getRdrNamesInScope,+ moduleIsInterpreted,+ getInfo,+ exprType,+ typeKind,+ parseName,+ showModule,+ moduleIsBootOrNotObjectLinkable,+ parseExpr, compileParsedExpr,+ compileExpr, dynCompileExpr,+ compileExprRemote, compileParsedExprRemote,+ Term(..), obtainTermFromId, obtainTermFromVal, reconstructType+ ) where++#include "HsVersions.h"++import InteractiveEvalTypes++import GHCi+import GHCi.Message+import GHCi.RemoteTypes+import GhcMonad+import HscMain+import HsSyn+import HscTypes+import InstEnv+import IfaceEnv ( newInteractiveBinder )+import FamInstEnv ( FamInst )+import CoreFVs ( orphNamesOfFamInst )+import TyCon+import Type hiding( typeKind )+import RepType+import TcType hiding( typeKind )+import Var+import Id+import Name hiding ( varName )+import NameSet+import Avail+import RdrName+import VarEnv+import ByteCodeTypes+import Linker+import DynFlags+import Unique+import UniqSupply+import MonadUtils+import Module+import PrelNames ( toDynName, pretendNameIsInScope )+import Panic+import Maybes+import ErrUtils+import SrcLoc+import RtClosureInspect+import Outputable+import FastString+import Bag+import qualified Lexer (P (..), ParseResult(..), unP, mkPState)+import qualified Parser (parseStmt, parseModule, parseDeclaration, parseImport)++import System.Directory+import Data.Dynamic+import Data.Either+import qualified Data.IntMap as IntMap+import Data.List (find,intercalate)+import StringBuffer (stringToStringBuffer)+import Control.Monad+import GHC.Exts+import Data.Array+import Exception++-- -----------------------------------------------------------------------------+-- running a statement interactively++getResumeContext :: GhcMonad m => m [Resume]+getResumeContext = withSession (return . ic_resume . hsc_IC)++mkHistory :: HscEnv -> ForeignHValue -> BreakInfo -> History+mkHistory hsc_env hval bi = History hval bi (findEnclosingDecls hsc_env bi)++getHistoryModule :: History -> Module+getHistoryModule = breakInfo_module . historyBreakInfo++getHistorySpan :: HscEnv -> History -> SrcSpan+getHistorySpan hsc_env History{..} =+ let BreakInfo{..} = historyBreakInfo in+ case lookupHpt (hsc_HPT hsc_env) (moduleName breakInfo_module) of+ Just hmi -> modBreaks_locs (getModBreaks hmi) ! breakInfo_number+ _ -> panic "getHistorySpan"++getModBreaks :: HomeModInfo -> ModBreaks+getModBreaks hmi+ | Just linkable <- hm_linkable hmi,+ [BCOs cbc _] <- linkableUnlinked linkable+ = fromMaybe emptyModBreaks (bc_breaks cbc)+ | otherwise+ = emptyModBreaks -- probably object code++{- | Finds the enclosing top level function name -}+-- ToDo: a better way to do this would be to keep hold of the decl_path computed+-- by the coverage pass, which gives the list of lexically-enclosing bindings+-- for each tick.+findEnclosingDecls :: HscEnv -> BreakInfo -> [String]+findEnclosingDecls hsc_env (BreakInfo modl ix) =+ let hmi = expectJust "findEnclosingDecls" $+ lookupHpt (hsc_HPT hsc_env) (moduleName modl)+ mb = getModBreaks hmi+ in modBreaks_decls mb ! ix++-- | Update fixity environment in the current interactive context.+updateFixityEnv :: GhcMonad m => FixityEnv -> m ()+updateFixityEnv fix_env = do+ hsc_env <- getSession+ let ic = hsc_IC hsc_env+ setSession $ hsc_env { hsc_IC = ic { ic_fix_env = fix_env } }++-- -----------------------------------------------------------------------------+-- execStmt++-- | default ExecOptions+execOptions :: ExecOptions+execOptions = ExecOptions+ { execSingleStep = RunToCompletion+ , execSourceFile = "<interactive>"+ , execLineNumber = 1+ , execWrap = EvalThis -- just run the statement, don't wrap it in anything+ }++-- | Run a statement in the current interactive context.+execStmt+ :: GhcMonad m+ => String -- ^ a statement (bind or expression)+ -> ExecOptions+ -> m ExecResult+execStmt stmt ExecOptions{..} = do+ hsc_env <- getSession++ -- Turn off -fwarn-unused-local-binds when running a statement, to hide+ -- warnings about the implicit bindings we introduce.+ let ic = hsc_IC hsc_env -- use the interactive dflags+ idflags' = ic_dflags ic `wopt_unset` Opt_WarnUnusedLocalBinds+ hsc_env' = hsc_env{ hsc_IC = ic{ ic_dflags = idflags' } }++ -- compile to value (IO [HValue]), don't run+ r <- liftIO $ hscStmtWithLocation hsc_env' stmt+ execSourceFile execLineNumber++ case r of+ -- empty statement / comment+ Nothing -> return (ExecComplete (Right []) 0)++ Just (ids, hval, fix_env) -> do+ updateFixityEnv fix_env++ status <-+ withVirtualCWD $+ liftIO $+ evalStmt hsc_env' (isStep execSingleStep) (execWrap hval)++ let ic = hsc_IC hsc_env+ bindings = (ic_tythings ic, ic_rn_gbl_env ic)++ size = ghciHistSize idflags'++ handleRunStatus execSingleStep stmt bindings ids+ status (emptyHistory size)+++runDecls :: GhcMonad m => String -> m [Name]+runDecls = runDeclsWithLocation "<interactive>" 1++-- | Run some declarations and return any user-visible names that were brought+-- into scope.+runDeclsWithLocation :: GhcMonad m => String -> Int -> String -> m [Name]+runDeclsWithLocation source linenumber expr =+ do+ hsc_env <- getSession+ (tyThings, ic) <- liftIO $ hscDeclsWithLocation hsc_env expr source linenumber++ setSession $ hsc_env { hsc_IC = ic }+ hsc_env <- getSession+ hsc_env' <- liftIO $ rttiEnvironment hsc_env+ setSession hsc_env'+ return $ filter (not . isDerivedOccName . nameOccName)+ -- For this filter, see Note [What to show to users]+ $ map getName tyThings++{- Note [What to show to users]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't want to display internally-generated bindings to users.+Things like the coercion axiom for newtypes. These bindings all get+OccNames that users can't write, to avoid the possiblity of name+clashes (in linker symbols). That gives a convenient way to suppress+them. The relevant predicate is OccName.isDerivedOccName.+See Trac #11051 for more background and examples.+-}++withVirtualCWD :: GhcMonad m => m a -> m a+withVirtualCWD m = do+ hsc_env <- getSession++ -- a virtual CWD is only necessary when we're running interpreted code in+ -- the same process as the compiler.+ if gopt Opt_ExternalInterpreter (hsc_dflags hsc_env) then m else do++ let ic = hsc_IC hsc_env+ let set_cwd = do+ dir <- liftIO $ getCurrentDirectory+ case ic_cwd ic of+ Just dir -> liftIO $ setCurrentDirectory dir+ Nothing -> return ()+ return dir++ reset_cwd orig_dir = do+ virt_dir <- liftIO $ getCurrentDirectory+ hsc_env <- getSession+ let old_IC = hsc_IC hsc_env+ setSession hsc_env{ hsc_IC = old_IC{ ic_cwd = Just virt_dir } }+ liftIO $ setCurrentDirectory orig_dir++ gbracket set_cwd reset_cwd $ \_ -> m++parseImportDecl :: GhcMonad m => String -> m (ImportDecl RdrName)+parseImportDecl expr = withSession $ \hsc_env -> liftIO $ hscImport hsc_env expr++emptyHistory :: Int -> BoundedList History+emptyHistory size = nilBL size++handleRunStatus :: GhcMonad m+ => SingleStep -> String-> ([TyThing],GlobalRdrEnv) -> [Id]+ -> EvalStatus_ [ForeignHValue] [HValueRef]+ -> BoundedList History+ -> m ExecResult++handleRunStatus step expr bindings final_ids status history+ | RunAndLogSteps <- step = tracing+ | otherwise = not_tracing+ where+ tracing+ | EvalBreak is_exception apStack_ref ix mod_uniq resume_ctxt _ccs <- status+ , not is_exception+ = do+ hsc_env <- getSession+ let hmi = expectJust "handleRunStatus" $+ lookupHptDirectly (hsc_HPT hsc_env)+ (mkUniqueGrimily mod_uniq)+ modl = mi_module (hm_iface hmi)+ breaks = getModBreaks hmi++ b <- liftIO $+ breakpointStatus hsc_env (modBreaks_flags breaks) ix+ if b+ then not_tracing+ -- This breakpoint is explicitly enabled; we want to stop+ -- instead of just logging it.+ else do+ apStack_fhv <- liftIO $ mkFinalizedHValue hsc_env apStack_ref+ let bi = BreakInfo modl ix+ !history' = mkHistory hsc_env apStack_fhv bi `consBL` history+ -- history is strict, otherwise our BoundedList is pointless.+ fhv <- liftIO $ mkFinalizedHValue hsc_env resume_ctxt+ status <- liftIO $ GHCi.resumeStmt hsc_env True fhv+ handleRunStatus RunAndLogSteps expr bindings final_ids+ status history'+ | otherwise+ = not_tracing++ not_tracing+ -- Hit a breakpoint+ | EvalBreak is_exception apStack_ref ix mod_uniq resume_ctxt ccs <- status+ = do+ hsc_env <- getSession+ resume_ctxt_fhv <- liftIO $ mkFinalizedHValue hsc_env resume_ctxt+ apStack_fhv <- liftIO $ mkFinalizedHValue hsc_env apStack_ref+ let hmi = expectJust "handleRunStatus" $+ lookupHptDirectly (hsc_HPT hsc_env)+ (mkUniqueGrimily mod_uniq)+ modl = mi_module (hm_iface hmi)+ bp | is_exception = Nothing+ | otherwise = Just (BreakInfo modl ix)+ (hsc_env1, names, span, decl) <- liftIO $+ bindLocalsAtBreakpoint hsc_env apStack_fhv bp+ let+ resume = Resume+ { resumeStmt = expr, resumeContext = resume_ctxt_fhv+ , resumeBindings = bindings, resumeFinalIds = final_ids+ , resumeApStack = apStack_fhv+ , resumeBreakInfo = bp+ , resumeSpan = span, resumeHistory = toListBL history+ , resumeDecl = decl+ , resumeCCS = ccs+ , resumeHistoryIx = 0 }+ hsc_env2 = pushResume hsc_env1 resume++ setSession hsc_env2+ return (ExecBreak names bp)++ -- Completed successfully+ | EvalComplete allocs (EvalSuccess hvals) <- status+ = do hsc_env <- getSession+ let final_ic = extendInteractiveContextWithIds (hsc_IC hsc_env) final_ids+ final_names = map getName final_ids+ liftIO $ Linker.extendLinkEnv (zip final_names hvals)+ hsc_env' <- liftIO $ rttiEnvironment hsc_env{hsc_IC=final_ic}+ setSession hsc_env'+ return (ExecComplete (Right final_names) allocs)++ -- Completed with an exception+ | EvalComplete alloc (EvalException e) <- status+ = return (ExecComplete (Left (fromSerializableException e)) alloc)++ | otherwise+ = panic "not_tracing" -- actually exhaustive, but GHC can't tell+++resumeExec :: GhcMonad m => (SrcSpan->Bool) -> SingleStep -> m ExecResult+resumeExec canLogSpan step+ = do+ hsc_env <- getSession+ let ic = hsc_IC hsc_env+ resume = ic_resume ic++ case resume of+ [] -> liftIO $+ throwGhcExceptionIO (ProgramError "not stopped at a breakpoint")+ (r:rs) -> do+ -- 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+ ic' = ic { ic_tythings = resume_tmp_te,+ ic_rn_gbl_env = resume_rdr_env,+ ic_resume = rs }+ setSession hsc_env{ hsc_IC = ic' }++ -- remove any bindings created since the breakpoint from the+ -- linker's environment+ let old_names = map getName resume_tmp_te+ new_names = [ n | thing <- ic_tythings ic+ , let n = getName thing+ , not (n `elem` old_names) ]+ liftIO $ Linker.deleteFromLinkEnv new_names++ case r of+ Resume { resumeStmt = expr, resumeContext = fhv+ , resumeBindings = bindings, resumeFinalIds = final_ids+ , resumeApStack = apStack, resumeBreakInfo = mb_brkpt+ , resumeSpan = span+ , resumeHistory = hist } -> do+ withVirtualCWD $ do+ status <- liftIO $ GHCi.resumeStmt hsc_env (isStep step) fhv+ let prevHistoryLst = fromListBL 50 hist+ hist' = case mb_brkpt of+ Nothing -> prevHistoryLst+ Just bi+ | not $canLogSpan span -> prevHistoryLst+ | otherwise -> mkHistory hsc_env apStack bi `consBL`+ fromListBL 50 hist+ handleRunStatus step expr bindings final_ids status hist'++back :: GhcMonad m => Int -> m ([Name], Int, SrcSpan, String)+back n = moveHist (+n)++forward :: GhcMonad m => Int -> m ([Name], Int, SrcSpan, String)+forward n = moveHist (subtract n)++moveHist :: GhcMonad m => (Int -> Int) -> m ([Name], Int, SrcSpan, String)+moveHist fn = do+ hsc_env <- getSession+ case ic_resume (hsc_IC hsc_env) of+ [] -> liftIO $+ throwGhcExceptionIO (ProgramError "not stopped at a breakpoint")+ (r:rs) -> do+ let ix = resumeHistoryIx r+ history = resumeHistory r+ new_ix = fn ix+ --+ when (new_ix > length history) $ liftIO $+ throwGhcExceptionIO (ProgramError "no more logged breakpoints")+ when (new_ix < 0) $ liftIO $+ throwGhcExceptionIO (ProgramError "already at the beginning of the history")++ let+ update_ic apStack mb_info = do+ (hsc_env1, names, span, decl) <-+ liftIO $ bindLocalsAtBreakpoint hsc_env apStack mb_info+ let ic = hsc_IC hsc_env1+ r' = r { resumeHistoryIx = new_ix }+ ic' = ic { ic_resume = r':rs }++ setSession hsc_env1{ hsc_IC = ic' }++ return (names, new_ix, span, decl)++ -- careful: we want apStack to be the AP_STACK itself, not a thunk+ -- around it, hence the cases are carefully constructed below to+ -- make this the case. ToDo: this is v. fragile, do something better.+ if new_ix == 0+ then case r of+ Resume { resumeApStack = apStack,+ resumeBreakInfo = mb_brkpt } ->+ update_ic apStack mb_brkpt+ else case history !! (new_ix - 1) of+ History{..} ->+ update_ic historyApStack (Just historyBreakInfo)+++-- -----------------------------------------------------------------------------+-- After stopping at a breakpoint, add free variables to the environment++result_fs :: FastString+result_fs = fsLit "_result"++bindLocalsAtBreakpoint+ :: HscEnv+ -> ForeignHValue+ -> Maybe BreakInfo+ -> IO (HscEnv, [Name], SrcSpan, String)++-- Nothing case: we stopped when an exception was raised, not at a+-- breakpoint. We have no location information or local variables to+-- bind, all we can do is bind a local variable to the exception+-- value.+bindLocalsAtBreakpoint hsc_env apStack Nothing = do+ let exn_occ = mkVarOccFS (fsLit "_exception")+ span = mkGeneralSrcSpan (fsLit "<unknown>")+ exn_name <- newInteractiveBinder hsc_env exn_occ span++ let e_fs = fsLit "e"+ e_name = mkInternalName (getUnique e_fs) (mkTyVarOccFS e_fs) span+ e_tyvar = mkRuntimeUnkTyVar e_name liftedTypeKind+ exn_id = Id.mkVanillaGlobal exn_name (mkTyVarTy e_tyvar)++ ictxt0 = hsc_IC hsc_env+ ictxt1 = extendInteractiveContextWithIds ictxt0 [exn_id]+ --+ Linker.extendLinkEnv [(exn_name, apStack)]+ return (hsc_env{ hsc_IC = ictxt1 }, [exn_name], span, "<exception thrown>")++-- Just case: we stopped at a breakpoint, we have information about the location+-- of the breakpoint and the free variables of the expression.+bindLocalsAtBreakpoint hsc_env apStack_fhv (Just BreakInfo{..}) = do+ let+ hmi = expectJust "bindLocalsAtBreakpoint" $+ lookupHpt (hsc_HPT hsc_env) (moduleName breakInfo_module)+ breaks = getModBreaks hmi+ info = expectJust "bindLocalsAtBreakpoint2" $+ IntMap.lookup breakInfo_number (modBreaks_breakInfo breaks)+ vars = cgb_vars info+ result_ty = cgb_resty info+ occs = modBreaks_vars breaks ! breakInfo_number+ span = modBreaks_locs breaks ! breakInfo_number+ decl = intercalate "." $ modBreaks_decls breaks ! breakInfo_number++ -- Filter out any unboxed ids;+ -- we can't bind these at the prompt+ pointers = filter (\(id,_) -> isPointer id) vars+ isPointer id | [rep] <- typePrimRep (idType id)+ , isGcPtrRep rep = True+ | otherwise = False++ (ids, offsets) = unzip pointers++ free_tvs = tyCoVarsOfTypesList (result_ty:map idType ids)++ -- It might be that getIdValFromApStack fails, because the AP_STACK+ -- has been accidentally evaluated, or something else has gone wrong.+ -- So that we don't fall over in a heap when this happens, just don't+ -- bind any free variables instead, and we emit a warning.+ mb_hValues <-+ mapM (getBreakpointVar hsc_env apStack_fhv . fromIntegral) offsets+ when (any isNothing mb_hValues) $+ debugTraceMsg (hsc_dflags hsc_env) 1 $+ text "Warning: _result has been evaluated, some bindings have been lost"++ us <- mkSplitUniqSupply 'I' -- Dodgy; will give the same uniques every time+ let tv_subst = newTyVars us free_tvs+ filtered_ids = [ id | (id, Just _hv) <- zip ids mb_hValues ]+ (_,tidy_tys) = tidyOpenTypes emptyTidyEnv $+ map (substTy tv_subst . idType) filtered_ids++ new_ids <- zipWith3M mkNewId occs tidy_tys filtered_ids+ result_name <- newInteractiveBinder hsc_env (mkVarOccFS result_fs) span++ let result_id = Id.mkVanillaGlobal result_name+ (substTy tv_subst result_ty)+ result_ok = isPointer result_id++ final_ids | result_ok = result_id : new_ids+ | otherwise = new_ids+ ictxt0 = hsc_IC hsc_env+ ictxt1 = extendInteractiveContextWithIds ictxt0 final_ids+ names = map idName new_ids++ let fhvs = catMaybes mb_hValues+ Linker.extendLinkEnv (zip names fhvs)+ when result_ok $ Linker.extendLinkEnv [(result_name, apStack_fhv)]+ hsc_env1 <- rttiEnvironment hsc_env{ hsc_IC = ictxt1 }+ return (hsc_env1, if result_ok then result_name:names else names, span, decl)+ where+ -- We need a fresh Unique for each Id we bind, because the linker+ -- state is single-threaded and otherwise we'd spam old bindings+ -- whenever we stop at a breakpoint. The InteractveContext is properly+ -- saved/restored, but not the linker state. See #1743, test break026.+ mkNewId :: OccName -> Type -> Id -> IO Id+ mkNewId occ ty old_id+ = do { name <- newInteractiveBinder hsc_env occ (getSrcSpan old_id)+ ; return (Id.mkVanillaGlobalWithInfo name ty (idInfo old_id)) }++ newTyVars :: UniqSupply -> [TcTyVar] -> TCvSubst+ -- Similarly, clone the type variables mentioned in the types+ -- we have here, *and* make them all RuntimeUnk tyvars+ newTyVars us tvs+ = mkTvSubstPrs [ (tv, mkTyVarTy (mkRuntimeUnkTyVar name (tyVarKind tv)))+ | (tv, uniq) <- tvs `zip` uniqsFromSupply us+ , let name = setNameUnique (tyVarName tv) uniq ]++rttiEnvironment :: HscEnv -> IO HscEnv+rttiEnvironment hsc_env@HscEnv{hsc_IC=ic} = do+ let tmp_ids = [id | AnId id <- ic_tythings ic]+ incompletelyTypedIds =+ [id | id <- tmp_ids+ , not $ noSkolems id+ , (occNameFS.nameOccName.idName) id /= result_fs]+ hsc_env' <- foldM improveTypes hsc_env (map idName incompletelyTypedIds)+ return hsc_env'+ where+ noSkolems = noFreeVarsOfType . idType+ improveTypes hsc_env@HscEnv{hsc_IC=ic} name = do+ let tmp_ids = [id | AnId id <- ic_tythings ic]+ Just id = find (\i -> idName i == name) tmp_ids+ if noSkolems id+ then return hsc_env+ else do+ mb_new_ty <- reconstructType hsc_env 10 id+ let old_ty = idType id+ case mb_new_ty of+ Nothing -> return hsc_env+ Just new_ty -> do+ case improveRTTIType hsc_env old_ty new_ty of+ Nothing -> return $+ WARN(True, text (":print failed to calculate the "+ ++ "improvement for a type")) hsc_env+ Just subst -> do+ let dflags = hsc_dflags hsc_env+ when (dopt Opt_D_dump_rtti dflags) $+ printInfoForUser dflags alwaysQualify $+ fsep [text "RTTI Improvement for", ppr id, equals, ppr subst]++ let ic' = substInteractiveContext ic subst+ return hsc_env{hsc_IC=ic'}++pushResume :: HscEnv -> Resume -> HscEnv+pushResume hsc_env resume = hsc_env { hsc_IC = ictxt1 }+ where+ ictxt0 = hsc_IC hsc_env+ ictxt1 = ictxt0 { ic_resume = resume : ic_resume ictxt0 }++-- -----------------------------------------------------------------------------+-- Abandoning a resume context++abandon :: GhcMonad m => m Bool+abandon = do+ hsc_env <- getSession+ let ic = hsc_IC hsc_env+ resume = ic_resume ic+ case resume of+ [] -> return False+ r:rs -> do+ setSession hsc_env{ hsc_IC = ic { ic_resume = rs } }+ liftIO $ abandonStmt hsc_env (resumeContext r)+ return True++abandonAll :: GhcMonad m => m Bool+abandonAll = do+ hsc_env <- getSession+ let ic = hsc_IC hsc_env+ resume = ic_resume ic+ case resume of+ [] -> return False+ rs -> do+ setSession hsc_env{ hsc_IC = ic { ic_resume = [] } }+ liftIO $ mapM_ (abandonStmt hsc_env. resumeContext) rs+ return True++-- -----------------------------------------------------------------------------+-- Bounded list, optimised for repeated cons++data BoundedList a = BL+ {-# UNPACK #-} !Int -- length+ {-# UNPACK #-} !Int -- bound+ [a] -- left+ [a] -- right, list is (left ++ reverse right)++nilBL :: Int -> BoundedList a+nilBL bound = BL 0 bound [] []++consBL :: a -> BoundedList a -> BoundedList a+consBL a (BL len bound left right)+ | len < bound = BL (len+1) bound (a:left) right+ | null right = BL len bound [a] $! tail (reverse left)+ | otherwise = BL len bound (a:left) $! tail right++toListBL :: BoundedList a -> [a]+toListBL (BL _ _ left right) = left ++ reverse right++fromListBL :: Int -> [a] -> BoundedList a+fromListBL bound l = BL (length l) bound l []++-- lenBL (BL len _ _ _) = len++-- -----------------------------------------------------------------------------+-- | Set the interactive evaluation context.+--+-- (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.+--+-- We retain in scope all the things defined at the prompt, and kept+-- in ic_tythings. (Indeed, they shadow stuff from ic_imports.)++setContext :: GhcMonad m => [InteractiveImport] -> m ()+setContext imports+ = do { hsc_env <- getSession+ ; let dflags = hsc_dflags hsc_env+ ; all_env_err <- liftIO $ findGlobalRdrEnv hsc_env imports+ ; case all_env_err of+ Left (mod, err) ->+ 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+ ; setSession+ hsc_env{ hsc_IC = old_ic { ic_imports = imports+ , ic_rn_gbl_env = final_rdr_env }}}}+ where+ formatError dflags mod err = ProgramError . showSDoc dflags $+ text "Cannot add module" <+> ppr mod <+>+ text "to context:" <+> text err++findGlobalRdrEnv :: HscEnv -> [InteractiveImport]+ -> IO (Either (ModuleName, String) GlobalRdrEnv)+-- Compute the GlobalRdrEnv for the interactive context+findGlobalRdrEnv hsc_env imports+ = do { idecls_env <- hscRnImportDecls hsc_env idecls+ -- This call also loads any orphan modules+ ; return $ case partitionEithers (map mkEnv imods) of+ ([], imods_env) -> Right (foldr plusGlobalRdrEnv idecls_env imods_env)+ (err : _, _) -> Left err }+ where+ idecls :: [LImportDecl RdrName]+ idecls = [noLoc d | IIDecl d <- imports]++ imods :: [ModuleName]+ imods = [m | IIModule m <- imports]++ mkEnv mod = case mkTopLevEnv (hsc_HPT hsc_env) mod of+ Left err -> Left (mod, err)+ Right env -> Right env++availsToGlobalRdrEnv :: ModuleName -> [AvailInfo] -> GlobalRdrEnv+availsToGlobalRdrEnv mod_name avails+ = mkGlobalRdrEnv (gresFromAvails (Just imp_spec) avails)+ where+ -- We're building a GlobalRdrEnv as if the user imported+ -- all the specified modules into the global interactive module+ imp_spec = ImpSpec { is_decl = decl, is_item = ImpAll}+ decl = ImpDeclSpec { is_mod = mod_name, is_as = mod_name,+ is_qual = False,+ is_dloc = srcLocSpan interactiveSrcLoc }++mkTopLevEnv :: HomePackageTable -> ModuleName -> Either String GlobalRdrEnv+mkTopLevEnv hpt modl+ = case lookupHpt hpt modl of+ Nothing -> Left "not a home module"+ Just details ->+ case mi_globals (hm_iface details) of+ Nothing -> Left "not interpreted"+ Just env -> Right env++-- | Get the interactive evaluation context, consisting of a pair of the+-- set of modules from which we take the full top-level scope, and the set+-- of modules from which we take just the exports respectively.+getContext :: GhcMonad m => m [InteractiveImport]+getContext = withSession $ \HscEnv{ hsc_IC=ic } ->+ return (ic_imports ic)++-- | Returns @True@ if the specified module is interpreted, and hence has+-- its full top-level scope available.+moduleIsInterpreted :: GhcMonad m => Module -> m Bool+moduleIsInterpreted modl = withSession $ \h ->+ if moduleUnitId modl /= thisPackage (hsc_dflags h)+ then return False+ else case lookupHpt (hsc_HPT h) (moduleName modl) of+ Just details -> return (isJust (mi_globals (hm_iface details)))+ _not_a_home_module -> return False++-- | Looks up an identifier in the current interactive context (for :info)+-- Filter the instances by the ones whose tycons (or clases resp)+-- are in scope (qualified or otherwise). Otherwise we list a whole lot too many!+-- The exact choice of which ones to show, and which to hide, is a judgement call.+-- (see Trac #1581)+getInfo :: GhcMonad m => Bool -> Name -> m (Maybe (TyThing,Fixity,[ClsInst],[FamInst]))+getInfo allInfo name+ = withSession $ \hsc_env ->+ do mb_stuff <- liftIO $ hscTcRnGetInfo hsc_env name+ case mb_stuff of+ Nothing -> return Nothing+ Just (thing, fixity, cls_insts, fam_insts) -> do+ let rdr_env = ic_rn_gbl_env (hsc_IC hsc_env)++ -- Filter the instances based on whether the constituent names of their+ -- instance heads are all in scope.+ let cls_insts' = filter (plausible rdr_env . orphNamesOfClsInst) cls_insts+ fam_insts' = filter (plausible rdr_env . orphNamesOfFamInst) fam_insts+ return (Just (thing, fixity, cls_insts', fam_insts'))+ where+ plausible rdr_env names+ -- Dfun involving only names that are in ic_rn_glb_env+ = allInfo+ || nameSetAll ok names+ where -- A name is ok if it's in the rdr_env,+ -- whether qualified or not+ ok n | n == name = True+ -- The one we looked for in the first place!+ | pretendNameIsInScope n = True+ | isBuiltInSyntax n = True+ | 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 -> do+ return (map gre_name (globalRdrEnvElts (ic_rn_gbl_env (hsc_IC hsc_env))))++-- | Returns all 'RdrName's in scope in the current interactive+-- context, excluding any that are internally-generated.+getRdrNamesInScope :: GhcMonad m => m [RdrName]+getRdrNamesInScope = withSession $ \hsc_env -> do+ let+ ic = hsc_IC hsc_env+ gbl_rdrenv = ic_rn_gbl_env ic+ gbl_names = concatMap greRdrNames $ globalRdrEnvElts gbl_rdrenv+ -- Exclude internally generated names; see e.g. Trac #11328+ return (filter (not . isDerivedOccName . rdrNameOcc) gbl_names)+++-- | Parses a string as an identifier, and returns the list of 'Name's that+-- the identifier can refer to in the current interactive context.+parseName :: GhcMonad m => String -> m [Name]+parseName str = withSession $ \hsc_env -> liftIO $+ do { lrdr_name <- hscParseIdentifier hsc_env str+ ; hscTcRnLookupRdrName hsc_env lrdr_name }++-- | Returns @True@ if passed string is a statement.+isStmt :: DynFlags -> String -> Bool+isStmt dflags stmt =+ case parseThing Parser.parseStmt dflags stmt of+ Lexer.POk _ _ -> True+ Lexer.PFailed _ _ -> False++-- | Returns @True@ if passed string has an import declaration.+hasImport :: DynFlags -> String -> Bool+hasImport dflags stmt =+ case parseThing Parser.parseModule dflags stmt of+ Lexer.POk _ thing -> hasImports thing+ Lexer.PFailed _ _ -> False+ where+ hasImports = not . null . hsmodImports . unLoc++-- | Returns @True@ if passed string is an import declaration.+isImport :: DynFlags -> String -> Bool+isImport dflags stmt =+ case parseThing Parser.parseImport dflags stmt of+ Lexer.POk _ _ -> True+ Lexer.PFailed _ _ -> False++-- | Returns @True@ if passed string is a declaration but __/not a splice/__.+isDecl :: DynFlags -> String -> Bool+isDecl dflags stmt = do+ case parseThing Parser.parseDeclaration dflags stmt of+ Lexer.POk _ thing ->+ case unLoc thing of+ SpliceD _ -> False+ _ -> True+ Lexer.PFailed _ _ -> False++parseThing :: Lexer.P thing -> DynFlags -> String -> Lexer.ParseResult thing+parseThing parser dflags stmt = do+ let buf = stringToStringBuffer stmt+ loc = mkRealSrcLoc (fsLit "<interactive>") 1 1++ Lexer.unP parser (Lexer.mkPState dflags buf loc)++-- -----------------------------------------------------------------------------+-- Getting the type of an expression++-- | Get the type of an expression+-- Returns the type as described by 'TcRnExprMode'+exprType :: GhcMonad m => TcRnExprMode -> String -> m Type+exprType mode expr = withSession $ \hsc_env -> do+ ty <- liftIO $ hscTcExpr hsc_env mode expr+ return $ tidyType emptyTidyEnv ty++-- -----------------------------------------------------------------------------+-- Getting the kind of a type++-- | Get the kind of a type+typeKind :: GhcMonad m => Bool -> String -> m (Type, Kind)+typeKind normalise str = withSession $ \hsc_env -> do+ liftIO $ hscKcType hsc_env normalise str++-----------------------------------------------------------------------------+-- Compile an expression, run it and deliver the result++-- | Parse an expression, the parsed expression can be further processed and+-- passed to compileParsedExpr.+parseExpr :: GhcMonad m => String -> m (LHsExpr RdrName)+parseExpr expr = withSession $ \hsc_env -> do+ liftIO $ runInteractiveHsc hsc_env $ hscParseExpr expr++-- | Compile an expression, run it and deliver the resulting HValue.+compileExpr :: GhcMonad m => String -> m HValue+compileExpr expr = do+ parsed_expr <- parseExpr expr+ compileParsedExpr parsed_expr++-- | Compile an expression, run it and deliver the resulting HValue.+compileExprRemote :: GhcMonad m => String -> m ForeignHValue+compileExprRemote expr = do+ parsed_expr <- parseExpr expr+ compileParsedExprRemote parsed_expr++-- | Compile an parsed expression (before renaming), run it and deliver+-- the resulting HValue.+compileParsedExprRemote :: GhcMonad m => LHsExpr RdrName -> m ForeignHValue+compileParsedExprRemote expr@(L loc _) = withSession $ \hsc_env -> do+ -- > let _compileParsedExpr = expr+ -- Create let stmt from expr to make hscParsedStmt happy.+ -- We will ignore the returned [Id], namely [expr_id], and not really+ -- create a new binding.+ let expr_fs = fsLit "_compileParsedExpr"+ expr_name = mkInternalName (getUnique expr_fs) (mkTyVarOccFS expr_fs) loc+ let_stmt = L loc . LetStmt . L loc . HsValBinds $+ ValBindsIn (unitBag $ mkHsVarBind loc (getRdrName expr_name) expr) []++ Just ([_id], hvals_io, fix_env) <- liftIO $ hscParsedStmt hsc_env let_stmt+ updateFixityEnv fix_env+ status <- liftIO $ evalStmt hsc_env False (EvalThis hvals_io)+ case status of+ EvalComplete _ (EvalSuccess [hval]) -> return hval+ EvalComplete _ (EvalException e) ->+ liftIO $ throwIO (fromSerializableException e)+ _ -> panic "compileParsedExpr"++compileParsedExpr :: GhcMonad m => LHsExpr RdrName -> m HValue+compileParsedExpr expr = do+ fhv <- compileParsedExprRemote expr+ dflags <- getDynFlags+ liftIO $ wormhole dflags fhv++-- | Compile an expression, run it and return the result as a Dynamic.+dynCompileExpr :: GhcMonad m => String -> m Dynamic+dynCompileExpr expr = do+ parsed_expr <- parseExpr expr+ -- > Data.Dynamic.toDyn expr+ let loc = getLoc parsed_expr+ to_dyn_expr = mkHsApp (L loc . HsVar . L loc $ getRdrName toDynName)+ parsed_expr+ hval <- compileParsedExpr to_dyn_expr+ return (unsafeCoerce# hval :: Dynamic)++-----------------------------------------------------------------------------+-- show a module and it's source/object filenames++showModule :: GhcMonad m => ModSummary -> m String+showModule mod_summary =+ withSession $ \hsc_env -> do+ interpreted <- moduleIsBootOrNotObjectLinkable mod_summary+ let dflags = hsc_dflags hsc_env+ return (showModMsg dflags (hscTarget dflags) interpreted mod_summary)++moduleIsBootOrNotObjectLinkable :: GhcMonad m => ModSummary -> m Bool+moduleIsBootOrNotObjectLinkable mod_summary = withSession $ \hsc_env ->+ case lookupHpt (hsc_HPT hsc_env) (ms_mod_name mod_summary) of+ Nothing -> panic "missing linkable"+ Just mod_info -> return $ case hm_linkable mod_info of+ Nothing -> True+ Just linkable -> not (isObjectLinkable linkable)++----------------------------------------------------------------------------+-- RTTI primitives++obtainTermFromVal :: HscEnv -> Int -> Bool -> Type -> a -> IO Term+obtainTermFromVal hsc_env bound force ty x =+ cvObtainTerm hsc_env bound force ty (unsafeCoerce# x)++obtainTermFromId :: HscEnv -> Int -> Bool -> Id -> IO Term+obtainTermFromId hsc_env bound force id = do+ let dflags = hsc_dflags hsc_env+ hv <- Linker.getHValue hsc_env (varName id) >>= wormhole dflags+ cvObtainTerm hsc_env bound force (idType id) hv++-- Uses RTTI to reconstruct the type of an Id, making it less polymorphic+reconstructType :: HscEnv -> Int -> Id -> IO (Maybe Type)+reconstructType hsc_env bound id = do+ let dflags = hsc_dflags hsc_env+ hv <- Linker.getHValue hsc_env (varName id) >>= wormhole dflags+ cvReconstructType hsc_env bound (idType id) hv++mkRuntimeUnkTyVar :: Name -> Kind -> TyVar+mkRuntimeUnkTyVar name kind = mkTcTyVar name kind RuntimeUnk
+ main/InteractiveEvalTypes.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE CPP #-}++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2005-2007+--+-- Running statements interactively+--+-- -----------------------------------------------------------------------------++module InteractiveEvalTypes (+ Resume(..), History(..), ExecResult(..),+ SingleStep(..), isStep, ExecOptions(..),+ BreakInfo(..)+ ) where++import GHCi.RemoteTypes+import GHCi.Message (EvalExpr, ResumeContext)+import Id+import Name+import Module+import RdrName+import Type+import SrcLoc+import Exception++import Data.Word+#if MIN_VERSION_base(4,9,0)+import GHC.Stack.CCS+#else+import GHC.Stack as GHC.Stack.CCS+#endif++data ExecOptions+ = ExecOptions+ { execSingleStep :: SingleStep -- ^ stepping mode+ , execSourceFile :: String -- ^ filename (for errors)+ , execLineNumber :: Int -- ^ line number (for errors)+ , execWrap :: ForeignHValue -> EvalExpr ForeignHValue+ }++data SingleStep+ = RunToCompletion+ | SingleStep+ | RunAndLogSteps++isStep :: SingleStep -> Bool+isStep RunToCompletion = False+isStep _ = True++data ExecResult+ = ExecComplete+ { execResult :: Either SomeException [Name]+ , execAllocation :: Word64+ }+ | ExecBreak+ { breakNames :: [Name]+ , breakInfo :: Maybe BreakInfo+ }++data BreakInfo = BreakInfo+ { breakInfo_module :: Module+ , breakInfo_number :: Int+ }++data Resume = Resume+ { resumeStmt :: String -- the original statement+ , resumeContext :: ForeignRef (ResumeContext [HValueRef])+ , resumeBindings :: ([TyThing], GlobalRdrEnv)+ , resumeFinalIds :: [Id] -- [Id] to bind on completion+ , resumeApStack :: ForeignHValue -- The object from which we can get+ -- value of the free variables.+ , resumeBreakInfo :: Maybe BreakInfo+ -- the breakpoint we stopped at+ -- (module, index)+ -- (Nothing <=> exception)+ , resumeSpan :: SrcSpan -- just a copy of the SrcSpan+ -- from the ModBreaks,+ -- otherwise it's a pain to+ -- fetch the ModDetails &+ -- ModBreaks to get this.+ , resumeDecl :: String -- ditto+ , resumeCCS :: RemotePtr CostCentreStack+ , resumeHistory :: [History]+ , resumeHistoryIx :: Int -- 0 <==> at the top of the history+ }++data History+ = History {+ historyApStack :: ForeignHValue,+ historyBreakInfo :: BreakInfo,+ historyEnclosingDecls :: [String] -- declarations enclosing the breakpoint+ }
+ main/PackageConfig.hs view
@@ -0,0 +1,152 @@+{-# LANGUAGE CPP, RecordWildCards, FlexibleInstances, MultiParamTypeClasses #-}++-- |+-- Package configuration information: essentially the interface to Cabal, with+-- some utilities+--+-- (c) The University of Glasgow, 2004+--+module PackageConfig (+ -- $package_naming++ -- * UnitId+ packageConfigId,+ expandedPackageConfigId,+ definitePackageConfigId,+ installedPackageConfigId,++ -- * The PackageConfig type: information about a package+ PackageConfig,+ InstalledPackageInfo(..),+ ComponentId(..),+ SourcePackageId(..),+ PackageName(..),+ Version(..),+ defaultPackageConfig,+ sourcePackageIdString,+ packageNameString,+ pprPackageConfig,+ ) where++#include "HsVersions.h"++import GHC.PackageDb+import Data.Version++import FastString+import Outputable+import Module+import Unique++-- -----------------------------------------------------------------------------+-- Our PackageConfig type is the InstalledPackageInfo from ghc-boot,+-- which is similar to a subset of the InstalledPackageInfo type from Cabal.++type PackageConfig = InstalledPackageInfo+ ComponentId+ SourcePackageId+ PackageName+ Module.InstalledUnitId+ Module.UnitId+ Module.ModuleName+ Module.Module++-- TODO: there's no need for these to be FastString, as we don't need the uniq+-- feature, but ghc doesn't currently have convenient support for any+-- other compact string types, e.g. plain ByteString or Text.++newtype SourcePackageId = SourcePackageId FastString deriving (Eq, Ord)+newtype PackageName = PackageName FastString deriving (Eq, Ord)++instance BinaryStringRep SourcePackageId where+ fromStringRep = SourcePackageId . mkFastStringByteString+ toStringRep (SourcePackageId s) = fastStringToByteString s++instance BinaryStringRep PackageName where+ fromStringRep = PackageName . mkFastStringByteString+ toStringRep (PackageName s) = fastStringToByteString s++instance Uniquable SourcePackageId where+ getUnique (SourcePackageId n) = getUnique n++instance Uniquable PackageName where+ getUnique (PackageName n) = getUnique n++instance Outputable SourcePackageId where+ ppr (SourcePackageId str) = ftext str++instance Outputable PackageName where+ ppr (PackageName str) = ftext str++defaultPackageConfig :: PackageConfig+defaultPackageConfig = emptyInstalledPackageInfo++sourcePackageIdString :: PackageConfig -> String+sourcePackageIdString pkg = unpackFS str+ where+ SourcePackageId str = sourcePackageId pkg++packageNameString :: PackageConfig -> String+packageNameString pkg = unpackFS str+ where+ PackageName str = packageName pkg++pprPackageConfig :: PackageConfig -> SDoc+pprPackageConfig InstalledPackageInfo {..} =+ vcat [+ field "name" (ppr packageName),+ field "version" (text (showVersion packageVersion)),+ field "id" (ppr unitId),+ field "exposed" (ppr exposed),+ field "exposed-modules" (ppr exposedModules),+ field "hidden-modules" (fsep (map ppr hiddenModules)),+ field "trusted" (ppr trusted),+ field "import-dirs" (fsep (map text importDirs)),+ field "library-dirs" (fsep (map text libraryDirs)),+ field "dynamic-library-dirs" (fsep (map text libraryDynDirs)),+ field "hs-libraries" (fsep (map text hsLibraries)),+ field "extra-libraries" (fsep (map text extraLibraries)),+ field "extra-ghci-libraries" (fsep (map text extraGHCiLibraries)),+ field "include-dirs" (fsep (map text includeDirs)),+ field "includes" (fsep (map text includes)),+ field "depends" (fsep (map ppr depends)),+ field "cc-options" (fsep (map text ccOptions)),+ field "ld-options" (fsep (map text ldOptions)),+ field "framework-dirs" (fsep (map text frameworkDirs)),+ field "frameworks" (fsep (map text frameworks)),+ field "haddock-interfaces" (fsep (map text haddockInterfaces)),+ field "haddock-html" (fsep (map text haddockHTMLs))+ ]+ where+ field name body = text name <> colon <+> nest 4 body++-- -----------------------------------------------------------------------------+-- UnitId (package names, versions and dep hash)++-- $package_naming+-- #package_naming#+-- Mostly the compiler deals in terms of 'UnitId's, which are md5 hashes+-- of a package ID, keys of its dependencies, and Cabal flags. You're expected+-- to pass in the unit id in the @-this-unit-id@ flag. However, for+-- wired-in packages like @base@ & @rts@, we don't necessarily know what the+-- version is, so these are handled specially; see #wired_in_packages#.++-- | Get the GHC 'UnitId' right out of a Cabalish 'PackageConfig'+installedPackageConfigId :: PackageConfig -> InstalledUnitId+installedPackageConfigId = unitId++packageConfigId :: PackageConfig -> UnitId+packageConfigId p =+ if indefinite p+ then newUnitId (componentId p) (instantiatedWith p)+ else DefiniteUnitId (DefUnitId (unitId p))++expandedPackageConfigId :: PackageConfig -> UnitId+expandedPackageConfigId p =+ newUnitId (componentId p) (instantiatedWith p)++definitePackageConfigId :: PackageConfig -> Maybe DefUnitId+definitePackageConfigId p =+ case packageConfigId p of+ DefiniteUnitId def_uid -> Just def_uid+ _ -> Nothing
+ main/PackageConfig.hs-boot view
@@ -0,0 +1,7 @@+module PackageConfig where+import FastString+import {-# SOURCE #-} Module+import GHC.PackageDb+newtype PackageName = PackageName FastString+newtype SourcePackageId = SourcePackageId FastString+type PackageConfig = InstalledPackageInfo ComponentId SourcePackageId PackageName UnitId ModuleName Module
+ main/Packages.hs view
@@ -0,0 +1,2042 @@+-- (c) The University of Glasgow, 2006++{-# LANGUAGE CPP, ScopedTypeVariables, BangPatterns, FlexibleContexts #-}++-- | Package manipulation+module Packages (+ module PackageConfig,++ -- * Reading the package config, and processing cmdline args+ PackageState(preloadPackages, explicitPackages, requirementContext),+ PackageConfigMap,+ emptyPackageState,+ initPackages,+ readPackageConfigs,+ getPackageConfRefs,+ resolvePackageConfig,+ readPackageConfig,+ listPackageConfigMap,++ -- * Querying the package config+ lookupPackage,+ lookupPackage',+ lookupInstalledPackage,+ lookupPackageName,+ improveUnitId,+ searchPackageId,+ getPackageDetails,+ getInstalledPackageDetails,+ componentIdString,+ displayInstalledUnitId,+ listVisibleModuleNames,+ lookupModuleInAllPackages,+ lookupModuleWithSuggestions,+ lookupPluginModuleWithSuggestions,+ LookupResult(..),+ ModuleSuggestion(..),+ ModuleOrigin(..),++ -- * Inspecting the set of packages in scope+ getPackageIncludePath,+ getPackageLibraryPath,+ getPackageLinkOpts,+ getPackageExtraCcOpts,+ getPackageFrameworkPath,+ getPackageFrameworks,+ getPackageConfigMap,+ getPreloadPackagesAnd,++ collectIncludeDirs, collectLibraryPaths, collectLinkOpts,+ packageHsLibs,++ -- * Utils+ unwireUnitId,+ pprFlag,+ pprPackages,+ pprPackagesSimple,+ pprModuleMap,+ isDllName+ )+where++#include "HsVersions.h"++import GHC.PackageDb+import PackageConfig+import DynFlags+import Name ( Name, nameModule_maybe )+import UniqFM+import UniqDFM+import UniqSet+import Module+import Util+import Panic+import Outputable+import Maybes++import System.Environment ( getEnv )+import FastString+import ErrUtils ( debugTraceMsg, MsgDoc, printInfoForUser )+import Exception++import System.Directory+import System.FilePath as FilePath+import qualified System.FilePath.Posix as FilePath.Posix+import Control.Monad+import Data.Graph (stronglyConnComp, SCC(..))+import Data.Char ( toUpper )+import Data.List as List+import Data.Map (Map)+import Data.Set (Set)+import Data.Maybe (mapMaybe)+import Data.Monoid (First(..))+#if __GLASGOW_HASKELL__ > 710+import Data.Semigroup ( Semigroup )+import qualified Data.Semigroup as Semigroup+#endif+import qualified Data.Map as Map+import qualified Data.Map.Strict as MapStrict+import qualified Data.Set as Set+import Data.Version++-- ---------------------------------------------------------------------------+-- The Package state++-- | Package state is all stored in 'DynFlags', including the details of+-- all packages, which packages are exposed, and which modules they+-- provide.+--+-- The package state is computed by 'initPackages', and kept in DynFlags.+-- It is influenced by various package flags:+--+-- * @-package <pkg>@ and @-package-id <pkg>@ cause @<pkg>@ to become exposed.+-- If @-hide-all-packages@ was not specified, these commands also cause+-- all other packages with the same name to become hidden.+--+-- * @-hide-package <pkg>@ causes @<pkg>@ to become hidden.+--+-- * (there are a few more flags, check below for their semantics)+--+-- The package state has the following properties.+--+-- * Let @exposedPackages@ be the set of packages thus exposed.+-- Let @depExposedPackages@ be the transitive closure from @exposedPackages@ of+-- their dependencies.+--+-- * When searching for a module from an preload import declaration,+-- only the exposed modules in @exposedPackages@ are valid.+--+-- * When searching for a module from an implicit import, all modules+-- from @depExposedPackages@ are valid.+--+-- * When linking in a compilation manager mode, we link in packages the+-- program depends on (the compiler knows this list by the+-- time it gets to the link step). Also, we link in all packages+-- which were mentioned with preload @-package@ flags on the command-line,+-- or are a transitive dependency of same, or are \"base\"\/\"rts\".+-- The reason for this is that we might need packages which don't+-- contain any Haskell modules, and therefore won't be discovered+-- by the normal mechanism of dependency tracking.++-- Notes on DLLs+-- ~~~~~~~~~~~~~+-- When compiling module A, which imports module B, we need to+-- know whether B will be in the same DLL as A.+-- If it's in the same DLL, we refer to B_f_closure+-- If it isn't, we refer to _imp__B_f_closure+-- When compiling A, we record in B's Module value whether it's+-- in a different DLL, by setting the DLL flag.++-- | Given a module name, there may be multiple ways it came into scope,+-- possibly simultaneously. This data type tracks all the possible ways+-- it could have come into scope. Warning: don't use the record functions,+-- they're partial!+data ModuleOrigin =+ -- | Module is hidden, and thus never will be available for import.+ -- (But maybe the user didn't realize), so we'll still keep track+ -- of these modules.)+ ModHidden+ -- | Module is public, and could have come from some places.+ | ModOrigin {+ -- | @Just False@ means that this module is in+ -- someone's @exported-modules@ list, but that package is hidden;+ -- @Just True@ means that it is available; @Nothing@ means neither+ -- applies.+ fromOrigPackage :: Maybe Bool+ -- | Is the module available from a reexport of an exposed package?+ -- There could be multiple.+ , fromExposedReexport :: [PackageConfig]+ -- | Is the module available from a reexport of a hidden package?+ , fromHiddenReexport :: [PackageConfig]+ -- | Did the module export come from a package flag? (ToDo: track+ -- more information.+ , fromPackageFlag :: Bool+ }++instance Outputable ModuleOrigin where+ ppr ModHidden = text "hidden module"+ ppr (ModOrigin e res rhs f) = sep (punctuate comma (+ (case e of+ Nothing -> []+ Just False -> [text "hidden package"]+ Just True -> [text "exposed package"]) +++ (if null res+ then []+ else [text "reexport by" <+>+ sep (map (ppr . packageConfigId) res)]) +++ (if null rhs+ then []+ else [text "hidden reexport by" <+>+ sep (map (ppr . packageConfigId) res)]) +++ (if f then [text "package flag"] else [])+ ))++-- | Smart constructor for a module which is in @exposed-modules@. Takes+-- as an argument whether or not the defining package is exposed.+fromExposedModules :: Bool -> ModuleOrigin+fromExposedModules e = ModOrigin (Just e) [] [] False++-- | Smart constructor for a module which is in @reexported-modules@. Takes+-- as an argument whether or not the reexporting package is expsed, and+-- also its 'PackageConfig'.+fromReexportedModules :: Bool -> PackageConfig -> ModuleOrigin+fromReexportedModules True pkg = ModOrigin Nothing [pkg] [] False+fromReexportedModules False pkg = ModOrigin Nothing [] [pkg] False++-- | Smart constructor for a module which was bound by a package flag.+fromFlag :: ModuleOrigin+fromFlag = ModOrigin Nothing [] [] True++#if __GLASGOW_HASKELL__ > 710+instance Semigroup ModuleOrigin where+ ModOrigin e res rhs f <> ModOrigin e' res' rhs' f' =+ ModOrigin (g e e') (res ++ res') (rhs ++ rhs') (f || f')+ where g (Just b) (Just b')+ | b == b' = Just b+ | otherwise = panic "ModOrigin: package both exposed/hidden"+ g Nothing x = x+ g x Nothing = x+ _x <> _y = panic "ModOrigin: hidden module redefined"+#endif++instance Monoid ModuleOrigin where+ mempty = ModOrigin Nothing [] [] False+ mappend (ModOrigin e res rhs f) (ModOrigin e' res' rhs' f') =+ ModOrigin (g e e') (res ++ res') (rhs ++ rhs') (f || f')+ where g (Just b) (Just b')+ | b == b' = Just b+ | otherwise = panic "ModOrigin: package both exposed/hidden"+ g Nothing x = x+ g x Nothing = x+ mappend _ _ = panic "ModOrigin: hidden module redefined"++-- | Is the name from the import actually visible? (i.e. does it cause+-- ambiguity, or is it only relevant when we're making suggestions?)+originVisible :: ModuleOrigin -> Bool+originVisible ModHidden = False+originVisible (ModOrigin b res _ f) = b == Just True || not (null res) || f++-- | Are there actually no providers for this module? This will never occur+-- except when we're filtering based on package imports.+originEmpty :: ModuleOrigin -> Bool+originEmpty (ModOrigin Nothing [] [] False) = True+originEmpty _ = False++-- | 'UniqFM' map from 'InstalledUnitId'+type InstalledUnitIdMap = UniqDFM++-- | 'UniqFM' map from 'UnitId' to 'PackageConfig', plus+-- the transitive closure of preload packages.+data PackageConfigMap = PackageConfigMap {+ unPackageConfigMap :: InstalledUnitIdMap PackageConfig,+ -- | The set of transitively reachable packages according+ -- to the explicitly provided command line arguments.+ -- See Note [UnitId to InstalledUnitId improvement]+ preloadClosure :: UniqSet InstalledUnitId+ }++-- | 'UniqFM' map from 'UnitId' to a 'UnitVisibility'.+type VisibilityMap = Map UnitId UnitVisibility++-- | 'UnitVisibility' records the various aspects of visibility of a particular+-- 'UnitId'.+data UnitVisibility = UnitVisibility+ { uv_expose_all :: Bool+ -- ^ Should all modules in exposed-modules should be dumped into scope?+ , uv_renamings :: [(ModuleName, ModuleName)]+ -- ^ Any custom renamings that should bring extra 'ModuleName's into+ -- scope.+ , uv_package_name :: First FastString+ -- ^ The package name is associated with the 'UnitId'. This is used+ -- to implement legacy behavior where @-package foo-0.1@ implicitly+ -- hides any packages named @foo@+ , uv_requirements :: Map ModuleName (Set IndefModule)+ -- ^ The signatures which are contributed to the requirements context+ -- from this unit ID.+ , uv_explicit :: Bool+ -- ^ Whether or not this unit was explicitly brought into scope,+ -- as opposed to implicitly via the 'exposed' fields in the+ -- package database (when @-hide-all-packages@ is not passed.)+ }++instance Outputable UnitVisibility where+ ppr (UnitVisibility {+ uv_expose_all = b,+ uv_renamings = rns,+ uv_package_name = First mb_pn,+ uv_requirements = reqs,+ uv_explicit = explicit+ }) = ppr (b, rns, mb_pn, reqs, explicit)+instance Monoid UnitVisibility where+ mempty = UnitVisibility+ { uv_expose_all = False+ , uv_renamings = []+ , uv_package_name = First Nothing+ , uv_requirements = Map.empty+ , uv_explicit = False+ }+ mappend uv1 uv2+ = UnitVisibility+ { uv_expose_all = uv_expose_all uv1 || uv_expose_all uv2+ , uv_renamings = uv_renamings uv1 ++ uv_renamings uv2+ , uv_package_name = mappend (uv_package_name uv1) (uv_package_name uv2)+ , uv_requirements = Map.unionWith Set.union (uv_requirements uv1) (uv_requirements uv2)+ , uv_explicit = uv_explicit uv1 || uv_explicit uv2+ }++type WiredUnitId = DefUnitId+type PreloadUnitId = InstalledUnitId++-- | Map from 'ModuleName' to 'Module' to all the origins of the bindings+-- in scope. The 'PackageConf' is not cached, mostly for convenience reasons+-- (since this is the slow path, we'll just look it up again).+type ModuleToPkgConfAll =+ Map ModuleName (Map Module ModuleOrigin)++data PackageState = PackageState {+ -- | A mapping of 'UnitId' to 'PackageConfig'. This list is adjusted+ -- so that only valid packages are here. 'PackageConfig' reflects+ -- what was stored *on disk*, except for the 'trusted' flag, which+ -- is adjusted at runtime. (In particular, some packages in this map+ -- may have the 'exposed' flag be 'False'.)+ pkgIdMap :: PackageConfigMap,++ -- | A mapping of 'PackageName' to 'ComponentId'. This is used when+ -- users refer to packages in Backpack includes.+ packageNameMap :: Map PackageName ComponentId,++ -- | A mapping from wired in names to the original names from the+ -- package database.+ unwireMap :: Map WiredUnitId WiredUnitId,++ -- | The packages we're going to link in eagerly. This list+ -- should be in reverse dependency order; that is, a package+ -- is always mentioned before the packages it depends on.+ preloadPackages :: [PreloadUnitId],++ -- | Packages which we explicitly depend on (from a command line flag).+ -- We'll use this to generate version macros.+ explicitPackages :: [UnitId],++ -- | This is a full map from 'ModuleName' to all modules which may possibly+ -- be providing it. These providers may be hidden (but we'll still want+ -- to report them in error messages), or it may be an ambiguous import.+ moduleToPkgConfAll :: !ModuleToPkgConfAll,++ -- | A map, like 'moduleToPkgConfAll', but controlling plugin visibility.+ pluginModuleToPkgConfAll :: !ModuleToPkgConfAll,++ -- | A map saying, for each requirement, what interfaces must be merged+ -- together when we use them. For example, if our dependencies+ -- are @p[A=<A>]@ and @q[A=<A>,B=r[C=<A>]:B]@, then the interfaces+ -- to merge for A are @p[A=<A>]:A@, @q[A=<A>,B=r[C=<A>]:B]:A@+ -- and @r[C=<A>]:C@.+ --+ -- There's an entry in this map for each hole in our home library.+ requirementContext :: Map ModuleName [IndefModule]+ }++emptyPackageState :: PackageState+emptyPackageState = PackageState {+ pkgIdMap = emptyPackageConfigMap,+ packageNameMap = Map.empty,+ unwireMap = Map.empty,+ preloadPackages = [],+ explicitPackages = [],+ moduleToPkgConfAll = Map.empty,+ pluginModuleToPkgConfAll = Map.empty,+ requirementContext = Map.empty+ }++type InstalledPackageIndex = Map InstalledUnitId PackageConfig++-- | Empty package configuration map+emptyPackageConfigMap :: PackageConfigMap+emptyPackageConfigMap = PackageConfigMap emptyUDFM emptyUniqSet++-- | Find the package we know about with the given unit id, if any+lookupPackage :: DynFlags -> UnitId -> Maybe PackageConfig+lookupPackage dflags = lookupPackage' (isIndefinite dflags) (pkgIdMap (pkgState dflags))++-- | A more specialized interface, which takes a boolean specifying+-- whether or not to look for on-the-fly renamed interfaces, and+-- just a 'PackageConfigMap' rather than a 'DynFlags' (so it can+-- be used while we're initializing 'DynFlags'+lookupPackage' :: Bool -> PackageConfigMap -> UnitId -> Maybe PackageConfig+lookupPackage' False (PackageConfigMap pkg_map _) uid = lookupUDFM pkg_map uid+lookupPackage' True m@(PackageConfigMap pkg_map _) uid =+ case splitUnitIdInsts uid of+ (iuid, Just indef) ->+ fmap (renamePackage m (indefUnitIdInsts indef))+ (lookupUDFM pkg_map iuid)+ (_, Nothing) -> lookupUDFM pkg_map uid++{-+-- | Find the indefinite package for a given 'ComponentId'.+-- The way this works is just by fiat'ing that every indefinite package's+-- unit key is precisely its component ID; and that they share uniques.+lookupComponentId :: DynFlags -> ComponentId -> Maybe PackageConfig+lookupComponentId dflags (ComponentId cid_fs) = lookupUDFM pkg_map cid_fs+ where+ PackageConfigMap pkg_map = pkgIdMap (pkgState dflags)+-}++-- | Find the package we know about with the given package name (e.g. @foo@), if any+-- (NB: there might be a locally defined unit name which overrides this)+lookupPackageName :: DynFlags -> PackageName -> Maybe ComponentId+lookupPackageName dflags n = Map.lookup n (packageNameMap (pkgState dflags))++-- | Search for packages with a given package ID (e.g. \"foo-0.1\")+searchPackageId :: DynFlags -> SourcePackageId -> [PackageConfig]+searchPackageId dflags pid = filter ((pid ==) . sourcePackageId)+ (listPackageConfigMap dflags)++-- | Extends the package configuration map with a list of package configs.+extendPackageConfigMap+ :: PackageConfigMap -> [PackageConfig] -> PackageConfigMap+extendPackageConfigMap (PackageConfigMap pkg_map closure) new_pkgs+ = PackageConfigMap (foldl add pkg_map new_pkgs) closure+ -- We also add the expanded version of the packageConfigId, so that+ -- 'improveUnitId' can find it.+ where add pkg_map p = addToUDFM (addToUDFM pkg_map (expandedPackageConfigId p) p)+ (installedPackageConfigId p) p++-- | Looks up the package with the given id in the package state, panicing if it is+-- not found+getPackageDetails :: DynFlags -> UnitId -> PackageConfig+getPackageDetails dflags pid =+ expectJust "getPackageDetails" (lookupPackage dflags pid)++lookupInstalledPackage :: DynFlags -> InstalledUnitId -> Maybe PackageConfig+lookupInstalledPackage dflags uid = lookupInstalledPackage' (pkgIdMap (pkgState dflags)) uid++lookupInstalledPackage' :: PackageConfigMap -> InstalledUnitId -> Maybe PackageConfig+lookupInstalledPackage' (PackageConfigMap db _) uid = lookupUDFM db uid++getInstalledPackageDetails :: DynFlags -> InstalledUnitId -> PackageConfig+getInstalledPackageDetails dflags uid =+ expectJust "getInstalledPackageDetails" $+ lookupInstalledPackage dflags uid++-- | Get a list of entries from the package database. NB: be careful with+-- this function, although all packages in this map are "visible", this+-- does not imply that the exposed-modules of the package are available+-- (they may have been thinned or renamed).+listPackageConfigMap :: DynFlags -> [PackageConfig]+listPackageConfigMap dflags = eltsUDFM pkg_map+ where+ PackageConfigMap pkg_map _ = pkgIdMap (pkgState dflags)++-- ----------------------------------------------------------------------------+-- Loading the package db files and building up the package state++-- | Call this after 'DynFlags.parseDynFlags'. It reads the package+-- database files, and sets up various internal tables of package+-- information, according to the package-related flags on the+-- command-line (@-package@, @-hide-package@ etc.)+--+-- Returns a list of packages to link in if we're doing dynamic linking.+-- This list contains the packages that the user explicitly mentioned with+-- @-package@ flags.+--+-- 'initPackages' can be called again subsequently after updating the+-- 'packageFlags' field of the 'DynFlags', and it will update the+-- 'pkgState' in 'DynFlags' and return a list of packages to+-- link in.+initPackages :: DynFlags -> IO (DynFlags, [PreloadUnitId])+initPackages dflags0 = do+ dflags <- interpretPackageEnv dflags0+ pkg_db <-+ case pkgDatabase dflags of+ Nothing -> readPackageConfigs dflags+ Just db -> return $ map (\(p, pkgs)+ -> (p, setBatchPackageFlags dflags pkgs)) db+ (pkg_state, preload, insts)+ <- mkPackageState dflags pkg_db []+ return (dflags{ pkgDatabase = Just pkg_db,+ pkgState = pkg_state,+ thisUnitIdInsts_ = insts },+ preload)++-- -----------------------------------------------------------------------------+-- Reading the package database(s)++readPackageConfigs :: DynFlags -> IO [(FilePath, [PackageConfig])]+readPackageConfigs dflags = do+ conf_refs <- getPackageConfRefs dflags+ confs <- liftM catMaybes $ mapM (resolvePackageConfig dflags) conf_refs+ mapM (readPackageConfig dflags) confs+++getPackageConfRefs :: DynFlags -> IO [PkgConfRef]+getPackageConfRefs dflags = do+ let system_conf_refs = [UserPkgConf, GlobalPkgConf]++ e_pkg_path <- tryIO (getEnv $ map toUpper (programName dflags) ++ "_PACKAGE_PATH")+ let base_conf_refs = case e_pkg_path of+ Left _ -> system_conf_refs+ Right path+ | not (null path) && isSearchPathSeparator (last path)+ -> map PkgConfFile (splitSearchPath (init path)) ++ system_conf_refs+ | otherwise+ -> map PkgConfFile (splitSearchPath path)++ -- Apply the package DB-related flags from the command line to get the+ -- final list of package DBs.+ --+ -- Notes on ordering:+ -- * The list of flags is reversed (later ones first)+ -- * We work with the package DB list in "left shadows right" order+ -- * and finally reverse it at the end, to get "right shadows left"+ --+ return $ reverse (foldr doFlag base_conf_refs (packageDBFlags dflags))+ where+ doFlag (PackageDB p) dbs = p : dbs+ doFlag NoUserPackageDB dbs = filter isNotUser dbs+ doFlag NoGlobalPackageDB dbs = filter isNotGlobal dbs+ doFlag ClearPackageDBs _ = []++ isNotUser UserPkgConf = False+ isNotUser _ = True++ isNotGlobal GlobalPkgConf = False+ isNotGlobal _ = True++resolvePackageConfig :: DynFlags -> PkgConfRef -> IO (Maybe FilePath)+resolvePackageConfig dflags GlobalPkgConf = return $ Just (systemPackageConfig dflags)+-- NB: This logic is reimplemented in Cabal, so if you change it,+-- make sure you update Cabal. (Or, better yet, dump it in the+-- compiler info so Cabal can use the info.)+resolvePackageConfig dflags UserPkgConf = runMaybeT $ do+ dir <- versionedAppDir dflags+ let pkgconf = dir </> "package.conf.d"+ exist <- tryMaybeT $ doesDirectoryExist pkgconf+ if exist then return pkgconf else mzero+resolvePackageConfig _ (PkgConfFile name) = return $ Just name++readPackageConfig :: DynFlags -> FilePath -> IO (FilePath, [PackageConfig])+readPackageConfig dflags conf_file = do+ isdir <- doesDirectoryExist conf_file++ proto_pkg_configs <-+ if isdir+ then readDirStylePackageConfig conf_file+ else do+ isfile <- doesFileExist conf_file+ if isfile+ then do+ mpkgs <- tryReadOldFileStylePackageConfig+ case mpkgs of+ Just pkgs -> return pkgs+ Nothing -> throwGhcExceptionIO $ InstallationError $+ "ghc no longer supports single-file style package " +++ "databases (" ++ conf_file +++ ") use 'ghc-pkg init' to create the database with " +++ "the correct format."+ else throwGhcExceptionIO $ InstallationError $+ "can't find a package database at " ++ conf_file++ let+ top_dir = topDir dflags+ pkgroot = takeDirectory conf_file+ pkg_configs1 = map (mungePackageConfig top_dir pkgroot)+ proto_pkg_configs+ pkg_configs2 = setBatchPackageFlags dflags pkg_configs1+ --+ return (conf_file, pkg_configs2)+ where+ readDirStylePackageConfig conf_dir = do+ let filename = conf_dir </> "package.cache"+ cache_exists <- doesFileExist filename+ if cache_exists+ then do+ debugTraceMsg dflags 2 $ text "Using binary package database:"+ <+> text filename+ readPackageDbForGhc filename+ else do+ -- If there is no package.cache file, we check if the database is not+ -- empty by inspecting if the directory contains any .conf file. If it+ -- does, something is wrong and we fail. Otherwise we assume that the+ -- database is empty.+ debugTraceMsg dflags 2 $ text "There is no package.cache in"+ <+> text conf_dir+ <> text ", checking if the database is empty"+ db_empty <- all (not . isSuffixOf ".conf")+ <$> getDirectoryContents conf_dir+ if db_empty+ then do+ debugTraceMsg dflags 3 $ text "There are no .conf files in"+ <+> text conf_dir <> text ", treating"+ <+> text "package database as empty"+ return []+ else do+ throwGhcExceptionIO $ InstallationError $+ "there is no package.cache in " ++ conf_dir +++ " even though package database is not empty"+++ -- Single-file style package dbs have been deprecated for some time, but+ -- it turns out that Cabal was using them in one place. So this is a+ -- workaround to allow older Cabal versions to use this newer ghc.+ -- We check if the file db contains just "[]" and if so, we look for a new+ -- dir-style db in conf_file.d/, ie in a dir next to the given file.+ -- We cannot just replace the file with a new dir style since Cabal still+ -- assumes it's a file and tries to overwrite with 'writeFile'.+ -- ghc-pkg also cooperates with this workaround.+ tryReadOldFileStylePackageConfig = do+ content <- readFile conf_file `catchIO` \_ -> return ""+ if take 2 content == "[]"+ then do+ let conf_dir = conf_file <.> "d"+ direxists <- doesDirectoryExist conf_dir+ if direxists+ then do debugTraceMsg dflags 2 (text "Ignoring old file-style db and trying:" <+> text conf_dir)+ liftM Just (readDirStylePackageConfig conf_dir)+ else return (Just []) -- ghc-pkg will create it when it's updated+ else return Nothing++setBatchPackageFlags :: DynFlags -> [PackageConfig] -> [PackageConfig]+setBatchPackageFlags dflags pkgs = maybeDistrustAll pkgs+ where+ maybeDistrustAll pkgs'+ | gopt Opt_DistrustAllPackages dflags = map distrust pkgs'+ | otherwise = pkgs'++ distrust pkg = pkg{ trusted = False }++mungePackageConfig :: FilePath -> FilePath+ -> PackageConfig -> PackageConfig+mungePackageConfig top_dir pkgroot =+ mungeDynLibFields+ . mungePackagePaths top_dir pkgroot++mungeDynLibFields :: PackageConfig -> PackageConfig+mungeDynLibFields pkg =+ pkg {+ libraryDynDirs = libraryDynDirs pkg+ `orIfNull` libraryDirs pkg+ }+ where+ orIfNull [] flags = flags+ orIfNull flags _ = flags++-- TODO: This code is duplicated in utils/ghc-pkg/Main.hs+mungePackagePaths :: FilePath -> FilePath -> PackageConfig -> PackageConfig+-- Perform path/URL variable substitution as per the Cabal ${pkgroot} spec+-- (http://www.haskell.org/pipermail/libraries/2009-May/011772.html)+-- Paths/URLs can be relative to ${pkgroot} or ${pkgrooturl}.+-- The "pkgroot" is the directory containing the package database.+--+-- Also perform a similar substitution for the older GHC-specific+-- "$topdir" variable. The "topdir" is the location of the ghc+-- installation (obtained from the -B option).+mungePackagePaths top_dir pkgroot pkg =+ pkg {+ importDirs = munge_paths (importDirs pkg),+ includeDirs = munge_paths (includeDirs pkg),+ libraryDirs = munge_paths (libraryDirs pkg),+ libraryDynDirs = munge_paths (libraryDynDirs pkg),+ frameworkDirs = munge_paths (frameworkDirs pkg),+ haddockInterfaces = munge_paths (haddockInterfaces pkg),+ haddockHTMLs = munge_urls (haddockHTMLs pkg)+ }+ where+ munge_paths = map munge_path+ munge_urls = map munge_url++ munge_path p+ | Just p' <- stripVarPrefix "${pkgroot}" p = pkgroot ++ p'+ | Just p' <- stripVarPrefix "$topdir" p = top_dir ++ p'+ | otherwise = p++ munge_url p+ | Just p' <- stripVarPrefix "${pkgrooturl}" p = toUrlPath pkgroot p'+ | Just p' <- stripVarPrefix "$httptopdir" p = toUrlPath top_dir p'+ | otherwise = p++ toUrlPath r p = "file:///"+ -- URLs always use posix style '/' separators:+ ++ FilePath.Posix.joinPath+ (r : -- We need to drop a leading "/" or "\\"+ -- if there is one:+ dropWhile (all isPathSeparator)+ (FilePath.splitDirectories p))++ -- We could drop the separator here, and then use </> above. However,+ -- by leaving it in and using ++ we keep the same path separator+ -- rather than letting FilePath change it to use \ as the separator+ stripVarPrefix var path = case stripPrefix var path of+ Just [] -> Just []+ Just cs@(c : _) | isPathSeparator c -> Just cs+ _ -> Nothing+++-- -----------------------------------------------------------------------------+-- Modify our copy of the package database based on trust flags,+-- -trust and -distrust.++applyTrustFlag+ :: DynFlags+ -> PackagePrecedenceIndex+ -> UnusablePackages+ -> [PackageConfig]+ -> TrustFlag+ -> IO [PackageConfig]+applyTrustFlag dflags prec_map unusable pkgs flag =+ case flag of+ -- we trust all matching packages. Maybe should only trust first one?+ -- and leave others the same or set them untrusted+ TrustPackage str ->+ case selectPackages prec_map (PackageArg str) pkgs unusable of+ Left ps -> trustFlagErr dflags flag ps+ Right (ps,qs) -> return (map trust ps ++ qs)+ where trust p = p {trusted=True}++ DistrustPackage str ->+ case selectPackages prec_map (PackageArg str) pkgs unusable of+ Left ps -> trustFlagErr dflags flag ps+ Right (ps,qs) -> return (map distrust ps ++ qs)+ where distrust p = p {trusted=False}++-- | A little utility to tell if the 'thisPackage' is indefinite+-- (if it is not, we should never use on-the-fly renaming.)+isIndefinite :: DynFlags -> Bool+isIndefinite dflags = not (unitIdIsDefinite (thisPackage dflags))++applyPackageFlag+ :: DynFlags+ -> PackagePrecedenceIndex+ -> PackageConfigMap+ -> UnusablePackages+ -> Bool -- if False, if you expose a package, it implicitly hides+ -- any previously exposed packages with the same name+ -> [PackageConfig]+ -> VisibilityMap -- Initially exposed+ -> PackageFlag -- flag to apply+ -> IO VisibilityMap -- Now exposed++applyPackageFlag dflags prec_map pkg_db unusable no_hide_others pkgs vm flag =+ case flag of+ ExposePackage _ arg (ModRenaming b rns) ->+ case findPackages prec_map pkg_db arg pkgs unusable of+ Left ps -> packageFlagErr dflags flag ps+ Right (p:_) -> return vm'+ where+ n = fsPackageName p++ -- If a user says @-unit-id p[A=<A>]@, this imposes+ -- a requirement on us: whatever our signature A is,+ -- it must fulfill all of p[A=<A>]:A's requirements.+ -- This method is responsible for computing what our+ -- inherited requirements are.+ reqs | UnitIdArg orig_uid <- arg = collectHoles orig_uid+ | otherwise = Map.empty++ collectHoles uid = case splitUnitIdInsts uid of+ (_, Just indef) ->+ let local = [ Map.singleton+ (moduleName mod)+ (Set.singleton $ IndefModule indef mod_name)+ | (mod_name, mod) <- indefUnitIdInsts indef+ , isHoleModule mod ]+ recurse = [ collectHoles (moduleUnitId mod)+ | (_, mod) <- indefUnitIdInsts indef ]+ in Map.unionsWith Set.union $ local ++ recurse+ -- Other types of unit identities don't have holes+ (_, Nothing) -> Map.empty+++ uv = UnitVisibility+ { uv_expose_all = b+ , uv_renamings = rns+ , uv_package_name = First (Just n)+ , uv_requirements = reqs+ , uv_explicit = True+ }+ vm' = Map.insertWith mappend (packageConfigId p) uv vm_cleared+ -- In the old days, if you said `ghc -package p-0.1 -package p-0.2`+ -- (or if p-0.1 was registered in the pkgdb as exposed: True),+ -- the second package flag would override the first one and you+ -- would only see p-0.2 in exposed modules. This is good for+ -- usability.+ --+ -- However, with thinning and renaming (or Backpack), there might be+ -- situations where you legitimately want to see two versions of a+ -- package at the same time, and this behavior would make it+ -- impossible to do so. So we decided that if you pass+ -- -hide-all-packages, this should turn OFF the overriding behavior+ -- where an exposed package hides all other packages with the same+ -- name. This should not affect Cabal at all, which only ever+ -- exposes one package at a time.+ --+ -- NB: Why a variable no_hide_others? We have to apply this logic to+ -- -plugin-package too, and it's more consistent if the switch in+ -- behavior is based off of+ -- -hide-all-packages/-hide-all-plugin-packages depending on what+ -- flag is in question.+ vm_cleared | no_hide_others = vm+ -- NB: renamings never clear+ | (_:_) <- rns = vm+ | otherwise = Map.filterWithKey+ (\k uv -> k == packageConfigId p+ || First (Just n) /= uv_package_name uv) vm+ _ -> panic "applyPackageFlag"++ HidePackage str ->+ case findPackages prec_map pkg_db (PackageArg str) pkgs unusable of+ Left ps -> packageFlagErr dflags flag ps+ Right ps -> return vm'+ where vm' = foldl' (flip Map.delete) vm (map packageConfigId ps)++-- | Like 'selectPackages', but doesn't return a list of unmatched+-- packages. Furthermore, any packages it returns are *renamed*+-- if the 'UnitArg' has a renaming associated with it.+findPackages :: PackagePrecedenceIndex+ -> PackageConfigMap -> PackageArg -> [PackageConfig]+ -> UnusablePackages+ -> Either [(PackageConfig, UnusablePackageReason)]+ [PackageConfig]+findPackages prec_map pkg_db arg pkgs unusable+ = let ps = mapMaybe (finder arg) pkgs+ in if null ps+ then Left (mapMaybe (\(x,y) -> finder arg x >>= \x' -> return (x',y))+ (Map.elems unusable))+ else Right (sortByPreference prec_map ps)+ where+ finder (PackageArg str) p+ = if str == sourcePackageIdString p || str == packageNameString p+ then Just p+ else Nothing+ finder (UnitIdArg uid) p+ = let (iuid, mb_indef) = splitUnitIdInsts uid+ in if iuid == installedPackageConfigId p+ then Just (case mb_indef of+ Nothing -> p+ Just indef -> renamePackage pkg_db (indefUnitIdInsts indef) p)+ else Nothing++selectPackages :: PackagePrecedenceIndex -> PackageArg -> [PackageConfig]+ -> UnusablePackages+ -> Either [(PackageConfig, UnusablePackageReason)]+ ([PackageConfig], [PackageConfig])+selectPackages prec_map arg pkgs unusable+ = let matches = matching arg+ (ps,rest) = partition matches pkgs+ in if null ps+ then Left (filter (matches.fst) (Map.elems unusable))+ else Right (sortByPreference prec_map ps, rest)++-- | Rename a 'PackageConfig' according to some module instantiation.+renamePackage :: PackageConfigMap -> [(ModuleName, Module)]+ -> PackageConfig -> PackageConfig+renamePackage pkg_map insts conf =+ let hsubst = listToUFM insts+ smod = renameHoleModule' pkg_map hsubst+ new_insts = map (\(k,v) -> (k,smod v)) (instantiatedWith conf)+ in conf {+ instantiatedWith = new_insts,+ exposedModules = map (\(mod_name, mb_mod) -> (mod_name, fmap smod mb_mod))+ (exposedModules conf)+ }+++-- A package named on the command line can either include the+-- version, or just the name if it is unambiguous.+matchingStr :: String -> PackageConfig -> Bool+matchingStr str p+ = str == sourcePackageIdString p+ || str == packageNameString p++matchingId :: InstalledUnitId -> PackageConfig -> Bool+matchingId uid p = uid == installedPackageConfigId p++matching :: PackageArg -> PackageConfig -> Bool+matching (PackageArg str) = matchingStr str+matching (UnitIdArg (DefiniteUnitId (DefUnitId uid))) = matchingId uid+matching (UnitIdArg _) = \_ -> False -- TODO: warn in this case++-- | This sorts a list of packages, putting "preferred" packages first.+-- See 'compareByPreference' for the semantics of "preference".+sortByPreference :: PackagePrecedenceIndex -> [PackageConfig] -> [PackageConfig]+sortByPreference prec_map = sortBy (flip (compareByPreference prec_map))++-- | Returns 'GT' if @pkg@ should be preferred over @pkg'@ when picking+-- which should be "active". Here is the order of preference:+--+-- 1. First, prefer the latest version+-- 2. If the versions are the same, prefer the package that+-- came in the latest package database.+--+-- Pursuant to #12518, we could change this policy to, for example, remove+-- the version preference, meaning that we would always prefer the packages+-- in alter package database.+--+compareByPreference+ :: PackagePrecedenceIndex+ -> PackageConfig+ -> PackageConfig+ -> Ordering+compareByPreference prec_map pkg pkg' =+ case comparing packageVersion pkg pkg' of+ GT -> GT+ EQ | Just prec <- Map.lookup (unitId pkg) prec_map+ , Just prec' <- Map.lookup (unitId pkg') prec_map+ -- Prefer the package from the later DB flag (i.e., higher+ -- precedence)+ -> compare prec prec'+ | otherwise+ -> EQ+ LT -> LT++comparing :: Ord a => (t -> a) -> t -> t -> Ordering+comparing f a b = f a `compare` f b++packageFlagErr :: DynFlags+ -> PackageFlag+ -> [(PackageConfig, UnusablePackageReason)]+ -> IO a++-- for missing DPH package we emit a more helpful error message, because+-- this may be the result of using -fdph-par or -fdph-seq.+packageFlagErr dflags (ExposePackage _ (PackageArg pkg) _) []+ | is_dph_package pkg+ = throwGhcExceptionIO (CmdLineError (showSDoc dflags $ dph_err))+ where dph_err = text "the " <> text pkg <> text " package is not installed."+ $$ text "To install it: \"cabal install dph\"."+ is_dph_package pkg = "dph" `isPrefixOf` pkg+packageFlagErr dflags flag reasons+ = packageFlagErr' dflags (pprFlag flag) reasons++trustFlagErr :: DynFlags+ -> TrustFlag+ -> [(PackageConfig, UnusablePackageReason)]+ -> IO a+trustFlagErr dflags flag reasons+ = packageFlagErr' dflags (pprTrustFlag flag) reasons++packageFlagErr' :: DynFlags+ -> SDoc+ -> [(PackageConfig, UnusablePackageReason)]+ -> IO a+packageFlagErr' dflags flag_doc reasons+ = throwGhcExceptionIO (CmdLineError (showSDoc dflags $ err))+ where err = text "cannot satisfy " <> flag_doc <>+ (if null reasons then Outputable.empty else text ": ") $$+ nest 4 (ppr_reasons $$+ text "(use -v for more information)")+ ppr_reasons = vcat (map ppr_reason reasons)+ ppr_reason (p, reason) =+ pprReason (ppr (unitId p) <+> text "is") reason++pprFlag :: PackageFlag -> SDoc+pprFlag flag = case flag of+ HidePackage p -> text "-hide-package " <> text p+ ExposePackage doc _ _ -> text doc++pprTrustFlag :: TrustFlag -> SDoc+pprTrustFlag flag = case flag of+ TrustPackage p -> text "-trust " <> text p+ DistrustPackage p -> text "-distrust " <> text p++-- -----------------------------------------------------------------------------+-- Wired-in packages++wired_in_pkgids :: [String]+wired_in_pkgids = map unitIdString wiredInUnitIds++type WiredPackagesMap = Map WiredUnitId WiredUnitId++findWiredInPackages+ :: DynFlags+ -> PackagePrecedenceIndex+ -> [PackageConfig] -- database+ -> VisibilityMap -- info on what packages are visible+ -- for wired in selection+ -> IO ([PackageConfig], -- package database updated for wired in+ WiredPackagesMap) -- map from unit id to wired identity++findWiredInPackages dflags prec_map pkgs vis_map = do+ --+ -- Now we must find our wired-in packages, and rename them to+ -- their canonical names (eg. base-1.0 ==> base).+ --+ let+ matches :: PackageConfig -> String -> Bool+ pc `matches` pid = packageNameString pc == pid++ -- find which package corresponds to each wired-in package+ -- delete any other packages with the same name+ -- update the package and any dependencies to point to the new+ -- one.+ --+ -- When choosing which package to map to a wired-in package+ -- name, we try to pick the latest version of exposed packages.+ -- However, if there are no exposed wired in packages available+ -- (e.g. -hide-all-packages was used), we can't bail: we *have*+ -- to assign a package for the wired-in package: so we try again+ -- with hidden packages included to (and pick the latest+ -- version).+ --+ -- You can also override the default choice by using -ignore-package:+ -- this works even when there is no exposed wired in package+ -- available.+ --+ findWiredInPackage :: [PackageConfig] -> String+ -> IO (Maybe PackageConfig)+ findWiredInPackage pkgs wired_pkg =+ let all_ps = [ p | p <- pkgs, p `matches` wired_pkg ]+ all_exposed_ps =+ [ p | p <- all_ps+ , Map.member (packageConfigId p) vis_map ] in+ case all_exposed_ps of+ [] -> case all_ps of+ [] -> notfound+ many -> pick (head (sortByPreference prec_map many))+ many -> pick (head (sortByPreference prec_map many))+ where+ notfound = do+ debugTraceMsg dflags 2 $+ text "wired-in package "+ <> text wired_pkg+ <> text " not found."+ return Nothing+ pick :: PackageConfig+ -> IO (Maybe PackageConfig)+ pick pkg = do+ debugTraceMsg dflags 2 $+ text "wired-in package "+ <> text wired_pkg+ <> text " mapped to "+ <> ppr (unitId pkg)+ return (Just pkg)+++ mb_wired_in_pkgs <- mapM (findWiredInPackage pkgs) wired_in_pkgids+ let+ wired_in_pkgs = catMaybes mb_wired_in_pkgs+ wired_in_ids = mapMaybe definitePackageConfigId wired_in_pkgs++ -- this is old: we used to assume that if there were+ -- multiple versions of wired-in packages installed that+ -- they were mutually exclusive. Now we're assuming that+ -- you have one "main" version of each wired-in package+ -- (the latest version), and the others are backward-compat+ -- wrappers that depend on this one. e.g. base-4.0 is the+ -- latest, base-3.0 is a compat wrapper depending on base-4.0.+ {-+ deleteOtherWiredInPackages pkgs = filterOut bad pkgs+ where bad p = any (p `matches`) wired_in_pkgids+ && package p `notElem` map fst wired_in_ids+ -}++ wiredInMap :: Map WiredUnitId WiredUnitId+ wiredInMap = foldl' add_mapping Map.empty pkgs+ where add_mapping m pkg+ | Just key <- definitePackageConfigId pkg+ , key `elem` wired_in_ids+ = Map.insert key (DefUnitId (stringToInstalledUnitId (packageNameString pkg))) m+ | otherwise = m++ updateWiredInDependencies pkgs = map (upd_deps . upd_pkg) pkgs+ where upd_pkg pkg+ | Just def_uid <- definitePackageConfigId pkg+ , def_uid `elem` wired_in_ids+ = let PackageName fs = packageName pkg+ in pkg {+ unitId = fsToInstalledUnitId fs,+ componentId = ComponentId fs+ }+ | otherwise+ = pkg+ upd_deps pkg = pkg {+ -- temporary harmless DefUnitId invariant violation+ depends = map (unDefUnitId . upd_wired_in wiredInMap . DefUnitId) (depends pkg),+ exposedModules+ = map (\(k,v) -> (k, fmap (upd_wired_in_mod wiredInMap) v))+ (exposedModules pkg)+ }+++ return (updateWiredInDependencies pkgs, wiredInMap)++-- Helper functions for rewiring Module and UnitId. These+-- rewrite UnitIds of modules in wired-in packages to the form known to the+-- compiler. For instance, base-4.9.0.0 will be rewritten to just base, to match+-- what appears in PrelNames.++upd_wired_in_mod :: WiredPackagesMap -> Module -> Module+upd_wired_in_mod wiredInMap (Module uid m) = Module (upd_wired_in_uid wiredInMap uid) m++upd_wired_in_uid :: WiredPackagesMap -> UnitId -> UnitId+upd_wired_in_uid wiredInMap (DefiniteUnitId def_uid) =+ DefiniteUnitId (upd_wired_in wiredInMap def_uid)+upd_wired_in_uid wiredInMap (IndefiniteUnitId indef_uid) =+ IndefiniteUnitId $ newIndefUnitId+ (indefUnitIdComponentId indef_uid)+ (map (\(x,y) -> (x,upd_wired_in_mod wiredInMap y)) (indefUnitIdInsts indef_uid))++upd_wired_in :: WiredPackagesMap -> DefUnitId -> DefUnitId+upd_wired_in wiredInMap key+ | Just key' <- Map.lookup key wiredInMap = key'+ | otherwise = key++updateVisibilityMap :: WiredPackagesMap -> VisibilityMap -> VisibilityMap+updateVisibilityMap wiredInMap vis_map = foldl' f vis_map (Map.toList wiredInMap)+ where f vm (from, to) = case Map.lookup (DefiniteUnitId from) vis_map of+ Nothing -> vm+ Just r -> Map.insert (DefiniteUnitId to) r+ (Map.delete (DefiniteUnitId from) vm)+++-- ----------------------------------------------------------------------------++-- | The reason why a package is unusable.+data UnusablePackageReason+ = -- | We ignored it explicitly using @-ignore-package@.+ IgnoredWithFlag+ -- | This package transitively depends on a package that was never present+ -- in any of the provided databases.+ | BrokenDependencies [InstalledUnitId]+ -- | This package transitively depends on a package involved in a cycle.+ -- Note that the list of 'InstalledUnitId' reports the direct dependencies+ -- of this package that (transitively) depended on the cycle, and not+ -- the actual cycle itself (which we report separately at high verbosity.)+ | CyclicDependencies [InstalledUnitId]+ -- | This package transitively depends on a package which was ignored.+ | IgnoredDependencies [InstalledUnitId]+ -- | This package transitively depends on a package which was+ -- shadowed by an ABI-incompatible package.+ | ShadowedDependencies [InstalledUnitId]++instance Outputable UnusablePackageReason where+ ppr IgnoredWithFlag = text "[ignored with flag]"+ ppr (BrokenDependencies uids) = brackets (text "broken" <+> ppr uids)+ ppr (CyclicDependencies uids) = brackets (text "cyclic" <+> ppr uids)+ ppr (IgnoredDependencies uids) = brackets (text "ignored" <+> ppr uids)+ ppr (ShadowedDependencies uids) = brackets (text "shadowed" <+> ppr uids)++type UnusablePackages = Map InstalledUnitId+ (PackageConfig, UnusablePackageReason)++pprReason :: SDoc -> UnusablePackageReason -> SDoc+pprReason pref reason = case reason of+ IgnoredWithFlag ->+ pref <+> text "ignored due to an -ignore-package flag"+ BrokenDependencies deps ->+ pref <+> text "unusable due to missing dependencies:" $$+ nest 2 (hsep (map ppr deps))+ CyclicDependencies deps ->+ pref <+> text "unusable due to cyclic dependencies:" $$+ nest 2 (hsep (map ppr deps))+ IgnoredDependencies deps ->+ pref <+> text "unusable due to ignored dependencies:" $$+ nest 2 (hsep (map ppr deps))+ ShadowedDependencies deps ->+ pref <+> text "unusable due to shadowed dependencies:" $$+ nest 2 (hsep (map ppr deps))++reportCycles :: DynFlags -> [SCC PackageConfig] -> IO ()+reportCycles dflags sccs = mapM_ report sccs+ where+ report (AcyclicSCC _) = return ()+ report (CyclicSCC vs) =+ debugTraceMsg dflags 2 $+ text "these packages are involved in a cycle:" $$+ nest 2 (hsep (map (ppr . unitId) vs))++reportUnusable :: DynFlags -> UnusablePackages -> IO ()+reportUnusable dflags pkgs = mapM_ report (Map.toList pkgs)+ where+ report (ipid, (_, reason)) =+ debugTraceMsg dflags 2 $+ pprReason+ (text "package" <+> ppr ipid <+> text "is") reason++-- ----------------------------------------------------------------------------+--+-- Utilities on the database+--++-- | A reverse dependency index, mapping an 'InstalledUnitId' to+-- the 'InstalledUnitId's which have a dependency on it.+type RevIndex = Map InstalledUnitId [InstalledUnitId]++-- | Compute the reverse dependency index of a package database.+reverseDeps :: InstalledPackageIndex -> RevIndex+reverseDeps db = Map.foldl' go Map.empty db+ where+ go r pkg = foldl' (go' (unitId pkg)) r (depends pkg)+ go' from r to = Map.insertWith (++) to [from] r++-- | Given a list of 'InstalledUnitId's to remove, a database,+-- and a reverse dependency index (as computed by 'reverseDeps'),+-- remove those packages, plus any packages which depend on them.+-- Returns the pruned database, as well as a list of 'PackageConfig's+-- that was removed.+removePackages :: [InstalledUnitId] -> RevIndex+ -> InstalledPackageIndex+ -> (InstalledPackageIndex, [PackageConfig])+removePackages uids index m = go uids (m,[])+ where+ go [] (m,pkgs) = (m,pkgs)+ go (uid:uids) (m,pkgs)+ | Just pkg <- Map.lookup uid m+ = case Map.lookup uid index of+ Nothing -> go uids (Map.delete uid m, pkg:pkgs)+ Just rdeps -> go (rdeps ++ uids) (Map.delete uid m, pkg:pkgs)+ | otherwise+ = go uids (m,pkgs)++-- | Given a 'PackageConfig' from some 'InstalledPackageIndex',+-- return all entries in 'depends' which correspond to packages+-- that do not exist in the index.+depsNotAvailable :: InstalledPackageIndex+ -> PackageConfig+ -> [InstalledUnitId]+depsNotAvailable pkg_map pkg = filter (not . (`Map.member` pkg_map)) (depends pkg)++-- | Given a 'PackageConfig' from some 'InstalledPackageIndex'+-- return all entries in 'abiDepends' which correspond to packages+-- that do not exist, OR have mismatching ABIs.+depsAbiMismatch :: InstalledPackageIndex+ -> PackageConfig+ -> [InstalledUnitId]+depsAbiMismatch pkg_map pkg = map fst . filter (not . abiMatch) $ abiDepends pkg+ where+ abiMatch (dep_uid, abi)+ | Just dep_pkg <- Map.lookup dep_uid pkg_map+ = abiHash dep_pkg == abi+ | otherwise+ = False++-- -----------------------------------------------------------------------------+-- Ignore packages++ignorePackages :: [IgnorePackageFlag] -> [PackageConfig] -> UnusablePackages+ignorePackages flags pkgs = Map.fromList (concatMap doit flags)+ where+ doit (IgnorePackage str) =+ case partition (matchingStr str) pkgs of+ (ps, _) -> [ (unitId p, (p, IgnoredWithFlag))+ | p <- ps ]+ -- missing package is not an error for -ignore-package,+ -- because a common usage is to -ignore-package P as+ -- a preventative measure just in case P exists.++-- ----------------------------------------------------------------------------+--+-- Merging databases+--++-- | For each package, a mapping from uid -> i indicates that this+-- package was brought into GHC by the ith @-package-db@ flag on+-- the command line. We use this mapping to make sure we prefer+-- packages that were defined later on the command line, if there+-- is an ambiguity.+type PackagePrecedenceIndex = Map InstalledUnitId Int++-- | Given a list of databases, merge them together, where+-- packages with the same unit id in later databases override+-- earlier ones. This does NOT check if the resulting database+-- makes sense (that's done by 'validateDatabase').+mergeDatabases :: DynFlags -> [(FilePath, [PackageConfig])]+ -> IO (InstalledPackageIndex, PackagePrecedenceIndex)+mergeDatabases dflags = foldM merge (Map.empty, Map.empty) . zip [1..]+ where+ merge (pkg_map, prec_map) (i, (db_path, db)) = do+ debugTraceMsg dflags 2 $+ text "loading package database" <+> text db_path+ forM_ (Set.toList override_set) $ \pkg ->+ debugTraceMsg dflags 2 $+ text "package" <+> ppr pkg <+>+ text "overrides a previously defined package"+ return (pkg_map', prec_map')+ where+ db_map = mk_pkg_map db+ mk_pkg_map = Map.fromList . map (\p -> (unitId p, p))++ -- The set of UnitIds which appear in both db and pkgs. These are the+ -- ones that get overridden. Compute this just to give some+ -- helpful debug messages at -v2+ override_set :: Set InstalledUnitId+ override_set = Set.intersection (Map.keysSet db_map)+ (Map.keysSet pkg_map)++ -- Now merge the sets together (NB: in case of duplicate,+ -- first argument preferred)+ pkg_map' :: InstalledPackageIndex+ pkg_map' = Map.union db_map pkg_map++ prec_map' :: PackagePrecedenceIndex+ prec_map' = Map.union (Map.map (const i) db_map) prec_map++-- | Validates a database, removing unusable packages from it+-- (this includes removing packages that the user has explicitly+-- ignored.) Our general strategy:+--+-- 1. Remove all broken packages (dangling dependencies)+-- 2. Remove all packages that are cyclic+-- 3. Apply ignore flags+-- 4. Remove all packages which have deps with mismatching ABIs+--+validateDatabase :: DynFlags -> InstalledPackageIndex+ -> (InstalledPackageIndex, UnusablePackages, [SCC PackageConfig])+validateDatabase dflags pkg_map1 =+ (pkg_map5, unusable, sccs)+ where+ ignore_flags = reverse (ignorePackageFlags dflags)++ -- Compute the reverse dependency index+ index = reverseDeps pkg_map1++ -- Helper function+ mk_unusable mk_err dep_matcher m uids =+ Map.fromList [ (unitId pkg, (pkg, mk_err (dep_matcher m pkg)))+ | pkg <- uids ]++ -- Find broken packages+ directly_broken = filter (not . null . depsNotAvailable pkg_map1)+ (Map.elems pkg_map1)+ (pkg_map2, broken) = removePackages (map unitId directly_broken) index pkg_map1+ unusable_broken = mk_unusable BrokenDependencies depsNotAvailable pkg_map2 broken++ -- Find recursive packages+ sccs = stronglyConnComp [ (pkg, unitId pkg, depends pkg)+ | pkg <- Map.elems pkg_map2 ]+ getCyclicSCC (CyclicSCC vs) = map unitId vs+ getCyclicSCC (AcyclicSCC _) = []+ (pkg_map3, cyclic) = removePackages (concatMap getCyclicSCC sccs) index pkg_map2+ unusable_cyclic = mk_unusable CyclicDependencies depsNotAvailable pkg_map3 cyclic++ -- Apply ignore flags+ directly_ignored = ignorePackages ignore_flags (Map.elems pkg_map3)+ (pkg_map4, ignored) = removePackages (Map.keys directly_ignored) index pkg_map3+ unusable_ignored = mk_unusable IgnoredDependencies depsNotAvailable pkg_map4 ignored++ -- Knock out packages whose dependencies don't agree with ABI+ -- (i.e., got invalidated due to shadowing)+ directly_shadowed = filter (not . null . depsAbiMismatch pkg_map4)+ (Map.elems pkg_map4)+ (pkg_map5, shadowed) = removePackages (map unitId directly_shadowed) index pkg_map4+ unusable_shadowed = mk_unusable ShadowedDependencies depsAbiMismatch pkg_map5 shadowed++ unusable = directly_ignored `Map.union` unusable_ignored+ `Map.union` unusable_broken+ `Map.union` unusable_cyclic+ `Map.union` unusable_shadowed++-- -----------------------------------------------------------------------------+-- When all the command-line options are in, we can process our package+-- settings and populate the package state.++mkPackageState+ :: DynFlags+ -- initial databases, in the order they were specified on+ -- the command line (later databases shadow earlier ones)+ -> [(FilePath, [PackageConfig])]+ -> [PreloadUnitId] -- preloaded packages+ -> IO (PackageState,+ [PreloadUnitId], -- new packages to preload+ Maybe [(ModuleName, Module)])++mkPackageState dflags dbs preload0 = do+{-+ Plan.++ There are two main steps for making the package state:++ 1. We want to build a single, unified package database based+ on all of the input databases, which upholds the invariant that+ there is only one package per any UnitId and there are no+ dangling dependencies. We'll do this by merging, and+ then successively filtering out bad dependencies.++ a) Merge all the databases together.+ If an input database defines unit ID that is already in+ the unified database, that package SHADOWS the existing+ package in the current unified database. Note that+ order is important: packages defined later in the list of+ command line arguments shadow those defined earlier.++ b) Remove all packages with missing dependencies, or+ mutually recursive dependencies.++ b) Remove packages selected by -ignore-package from input database++ c) Remove all packages which depended on packages that are now+ shadowed by an ABI-incompatible package++ d) report (with -v) any packages that were removed by steps 1-3++ 2. We want to look at the flags controlling package visibility,+ and build a mapping of what module names are in scope and+ where they live.++ a) on the final, unified database, we apply -trust/-distrust+ flags directly, modifying the database so that the 'trusted'+ field has the correct value.++ b) we use the -package/-hide-package flags to compute a+ visibility map, stating what packages are "exposed" for+ the purposes of computing the module map.+ * if any flag refers to a package which was removed by 1-5, then+ we can give an error message explaining why+ * if -hide-all-packages what not specified, this step also+ hides packages which are superseded by later exposed packages+ * this step is done TWICE if -plugin-package/-hide-all-plugin-packages+ are used++ c) based on the visibility map, we pick wired packages and rewrite+ them to have the expected unitId.++ d) finally, using the visibility map and the package database,+ we build a mapping saying what every in scope module name points to.+-}++ -- This, and the other reverse's that you will see, are due to the face that+ -- packageFlags, pluginPackageFlags, etc. are all specified in *reverse* order+ -- than they are on the command line.+ let other_flags = reverse (packageFlags dflags)+ debugTraceMsg dflags 2 $+ text "package flags" <+> ppr other_flags++ -- Merge databases together, without checking validity+ (pkg_map1, prec_map) <- mergeDatabases dflags dbs++ -- Now that we've merged everything together, prune out unusable+ -- packages.+ let (pkg_map2, unusable, sccs) = validateDatabase dflags pkg_map1++ reportCycles dflags sccs+ reportUnusable dflags unusable++ -- Apply trust flags (these flags apply regardless of whether+ -- or not packages are visible or not)+ pkgs1 <- foldM (applyTrustFlag dflags prec_map unusable)+ (Map.elems pkg_map2) (reverse (trustFlags dflags))+ let prelim_pkg_db = extendPackageConfigMap emptyPackageConfigMap pkgs1++ --+ -- Calculate the initial set of packages, prior to any package flags.+ -- This set contains the latest version of all valid (not unusable) packages,+ -- or is empty if we have -hide-all-packages+ --+ let preferLater pkg pkg' =+ case compareByPreference prec_map pkg pkg' of+ GT -> pkg+ _ -> pkg'+ calcInitial m pkg = addToUDFM_C preferLater m (fsPackageName pkg) pkg+ initial = if gopt Opt_HideAllPackages dflags+ then emptyUDFM+ else foldl' calcInitial emptyUDFM pkgs1+ vis_map1 = foldUDFM (\p vm ->+ -- Note: we NEVER expose indefinite packages by+ -- default, because it's almost assuredly not+ -- what you want (no mix-in linking has occurred).+ if exposed p && unitIdIsDefinite (packageConfigId p)+ then Map.insert (packageConfigId p)+ UnitVisibility {+ uv_expose_all = True,+ uv_renamings = [],+ uv_package_name = First (Just (fsPackageName p)),+ uv_requirements = Map.empty,+ uv_explicit = False+ }+ vm+ else vm)+ Map.empty initial++ --+ -- Compute a visibility map according to the command-line flags (-package,+ -- -hide-package). This needs to know about the unusable packages, since if a+ -- user tries to enable an unusable package, we should let them know.+ --+ vis_map2 <- foldM (applyPackageFlag dflags prec_map prelim_pkg_db unusable+ (gopt Opt_HideAllPackages dflags) pkgs1)+ vis_map1 other_flags++ --+ -- Sort out which packages are wired in. This has to be done last, since+ -- it modifies the unit ids of wired in packages, but when we process+ -- package arguments we need to key against the old versions.+ --+ (pkgs2, wired_map) <- findWiredInPackages dflags prec_map pkgs1 vis_map2+ let pkg_db = extendPackageConfigMap emptyPackageConfigMap pkgs2++ -- Update the visibility map, so we treat wired packages as visible.+ let vis_map = updateVisibilityMap wired_map vis_map2++ let hide_plugin_pkgs = gopt Opt_HideAllPluginPackages dflags+ plugin_vis_map <-+ case pluginPackageFlags dflags of+ -- common case; try to share the old vis_map+ [] | not hide_plugin_pkgs -> return vis_map+ | otherwise -> return Map.empty+ _ -> do let plugin_vis_map1+ | hide_plugin_pkgs = Map.empty+ -- Use the vis_map PRIOR to wired in,+ -- because otherwise applyPackageFlag+ -- won't work.+ | otherwise = vis_map2+ plugin_vis_map2+ <- foldM (applyPackageFlag dflags prec_map prelim_pkg_db unusable+ (gopt Opt_HideAllPluginPackages dflags) pkgs1)+ plugin_vis_map1+ (reverse (pluginPackageFlags dflags))+ -- Updating based on wired in packages is mostly+ -- good hygiene, because it won't matter: no wired in+ -- package has a compiler plugin.+ -- TODO: If a wired in package had a compiler plugin,+ -- and you tried to pick different wired in packages+ -- with the plugin flags and the normal flags... what+ -- would happen? I don't know! But this doesn't seem+ -- likely to actually happen.+ return (updateVisibilityMap wired_map plugin_vis_map2)++ --+ -- Here we build up a set of the packages mentioned in -package+ -- flags on the command line; these are called the "preload"+ -- packages. we link these packages in eagerly. The preload set+ -- should contain at least rts & base, which is why we pretend that+ -- the command line contains -package rts & -package base.+ --+ -- NB: preload IS important even for type-checking, because we+ -- need the correct include path to be set.+ --+ let preload1 = Map.keys (Map.filter uv_explicit vis_map)++ let pkgname_map = foldl add Map.empty pkgs2+ where add pn_map p+ = Map.insert (packageName p) (componentId p) pn_map++ -- The explicitPackages accurately reflects the set of packages we have turned+ -- on; as such, it also is the only way one can come up with requirements.+ -- The requirement context is directly based off of this: we simply+ -- look for nested unit IDs that are directly fed holes: the requirements+ -- of those units are precisely the ones we need to track+ let explicit_pkgs = Map.keys vis_map+ req_ctx = Map.map (Set.toList)+ $ Map.unionsWith Set.union (map uv_requirements (Map.elems vis_map))+++ let preload2 = preload1++ let+ -- add base & rts to the preload packages+ basicLinkedPackages+ | gopt Opt_AutoLinkPackages dflags+ = filter (flip elemUDFM (unPackageConfigMap pkg_db))+ [baseUnitId, rtsUnitId]+ | otherwise = []+ -- but in any case remove the current package from the set of+ -- preloaded packages so that base/rts does not end up in the+ -- set up preloaded package when we are just building it+ -- (NB: since this is only relevant for base/rts it doesn't matter+ -- that thisUnitIdInsts_ is not wired yet)+ --+ preload3 = nub $ filter (/= thisPackage dflags)+ $ (basicLinkedPackages ++ preload2)++ -- Close the preload packages with their dependencies+ dep_preload <- closeDeps dflags pkg_db (zip (map toInstalledUnitId preload3) (repeat Nothing))+ let new_dep_preload = filter (`notElem` preload0) dep_preload++ let mod_map = mkModuleToPkgConfAll dflags pkg_db vis_map+ when (dopt Opt_D_dump_mod_map dflags) $+ printInfoForUser (dflags { pprCols = 200 })+ alwaysQualify (pprModuleMap mod_map)++ -- Force pstate to avoid leaking the dflags0 passed to mkPackageState+ let !pstate = PackageState{+ preloadPackages = dep_preload,+ explicitPackages = explicit_pkgs,+ pkgIdMap = pkg_db,+ moduleToPkgConfAll = mod_map,+ pluginModuleToPkgConfAll = mkModuleToPkgConfAll dflags pkg_db plugin_vis_map,+ packageNameMap = pkgname_map,+ unwireMap = Map.fromList [ (v,k) | (k,v) <- Map.toList wired_map ],+ requirementContext = req_ctx+ }+ let new_insts = fmap (map (fmap (upd_wired_in_mod wired_map))) (thisUnitIdInsts_ dflags)+ return (pstate, new_dep_preload, new_insts)++-- | Given a wired-in 'UnitId', "unwire" it into the 'UnitId'+-- that it was recorded as in the package database.+unwireUnitId :: DynFlags -> UnitId -> UnitId+unwireUnitId dflags uid@(DefiniteUnitId def_uid) =+ maybe uid DefiniteUnitId (Map.lookup def_uid (unwireMap (pkgState dflags)))+unwireUnitId _ uid = uid++-- -----------------------------------------------------------------------------+-- | Makes the mapping from module to package info++-- Slight irritation: we proceed by leafing through everything+-- in the installed package database, which makes handling indefinite+-- packages a bit bothersome.++mkModuleToPkgConfAll+ :: DynFlags+ -> PackageConfigMap+ -> VisibilityMap+ -> ModuleToPkgConfAll+mkModuleToPkgConfAll dflags pkg_db vis_map =+ Map.foldlWithKey extend_modmap emptyMap vis_map+ where+ emptyMap = Map.empty+ sing pk m _ = Map.singleton (mkModule pk m)+ addListTo = foldl' merge+ merge m (k, v) = MapStrict.insertWith (Map.unionWith mappend) k v m+ setOrigins m os = fmap (const os) m+ extend_modmap modmap uid+ UnitVisibility { uv_expose_all = b, uv_renamings = rns }+ = addListTo modmap theBindings+ where+ pkg = pkg_lookup uid++ theBindings :: [(ModuleName, Map Module ModuleOrigin)]+ theBindings = newBindings b rns++ newBindings :: Bool+ -> [(ModuleName, ModuleName)]+ -> [(ModuleName, Map Module ModuleOrigin)]+ newBindings e rns = es e ++ hiddens ++ map rnBinding rns++ rnBinding :: (ModuleName, ModuleName)+ -> (ModuleName, Map Module ModuleOrigin)+ rnBinding (orig, new) = (new, setOrigins origEntry fromFlag)+ where origEntry = case lookupUFM esmap orig of+ Just r -> r+ Nothing -> throwGhcException (CmdLineError (showSDoc dflags+ (text "package flag: could not find module name" <+>+ ppr orig <+> text "in package" <+> ppr pk)))++ es :: Bool -> [(ModuleName, Map Module ModuleOrigin)]+ es e = do+ (m, exposedReexport) <- exposed_mods+ let (pk', m', pkg', origin') =+ case exposedReexport of+ Nothing -> (pk, m, pkg, fromExposedModules e)+ Just (Module pk' m') ->+ let pkg' = pkg_lookup pk'+ in (pk', m', pkg', fromReexportedModules e pkg')+ return (m, sing pk' m' pkg' origin')++ esmap :: UniqFM (Map Module ModuleOrigin)+ esmap = listToUFM (es False) -- parameter here doesn't matter, orig will+ -- be overwritten++ hiddens = [(m, sing pk m pkg ModHidden) | m <- hidden_mods]++ pk = packageConfigId pkg+ pkg_lookup uid = lookupPackage' (isIndefinite dflags) pkg_db uid+ `orElse` pprPanic "pkg_lookup" (ppr uid)++ exposed_mods = exposedModules pkg+ hidden_mods = hiddenModules pkg++-- -----------------------------------------------------------------------------+-- Extracting information from the packages in scope++-- Many of these functions take a list of packages: in those cases,+-- the list is expected to contain the "dependent packages",+-- i.e. those packages that were found to be depended on by the+-- current module/program. These can be auto or non-auto packages, it+-- doesn't really matter. The list is always combined with the list+-- of preload (command-line) packages to determine which packages to+-- use.++-- | Find all the include directories in these and the preload packages+getPackageIncludePath :: DynFlags -> [PreloadUnitId] -> IO [String]+getPackageIncludePath dflags pkgs =+ collectIncludeDirs `fmap` getPreloadPackagesAnd dflags pkgs++collectIncludeDirs :: [PackageConfig] -> [FilePath]+collectIncludeDirs ps = nub (filter notNull (concatMap includeDirs ps))++-- | Find all the library paths in these and the preload packages+getPackageLibraryPath :: DynFlags -> [PreloadUnitId] -> IO [String]+getPackageLibraryPath dflags pkgs =+ collectLibraryPaths dflags `fmap` getPreloadPackagesAnd dflags pkgs++collectLibraryPaths :: DynFlags -> [PackageConfig] -> [FilePath]+collectLibraryPaths dflags = nub . filter notNull+ . concatMap (libraryDirsForWay dflags)++-- | Find all the link options in these and the preload packages,+-- returning (package hs lib options, extra library options, other flags)+getPackageLinkOpts :: DynFlags -> [PreloadUnitId] -> IO ([String], [String], [String])+getPackageLinkOpts dflags pkgs =+ collectLinkOpts dflags `fmap` getPreloadPackagesAnd dflags pkgs++collectLinkOpts :: DynFlags -> [PackageConfig] -> ([String], [String], [String])+collectLinkOpts dflags ps =+ (+ concatMap (map ("-l" ++) . packageHsLibs dflags) ps,+ concatMap (map ("-l" ++) . extraLibraries) ps,+ concatMap ldOptions ps+ )++packageHsLibs :: DynFlags -> PackageConfig -> [String]+packageHsLibs dflags p = map (mkDynName . addSuffix) (hsLibraries p)+ where+ ways0 = ways dflags++ ways1 = filter (/= WayDyn) ways0+ -- the name of a shared library is libHSfoo-ghc<version>.so+ -- we leave out the _dyn, because it is superfluous++ -- debug and profiled RTSs include support for -eventlog+ ways2 | WayDebug `elem` ways1 || WayProf `elem` ways1+ = filter (/= WayEventLog) ways1+ | otherwise+ = ways1++ tag = mkBuildTag (filter (not . wayRTSOnly) ways2)+ rts_tag = mkBuildTag ways2++ mkDynName x+ | WayDyn `notElem` ways dflags = x+ | "HS" `isPrefixOf` x =+ x ++ '-':programName dflags ++ projectVersion dflags+ -- For non-Haskell libraries, we use the name "Cfoo". The .a+ -- file is libCfoo.a, and the .so is libfoo.so. That way the+ -- linker knows what we mean for the vanilla (-lCfoo) and dyn+ -- (-lfoo) ways. We therefore need to strip the 'C' off here.+ | Just x' <- stripPrefix "C" x = x'+ | otherwise+ = panic ("Don't understand library name " ++ x)++ addSuffix rts@"HSrts" = rts ++ (expandTag rts_tag)+ addSuffix other_lib = other_lib ++ (expandTag tag)++ expandTag t | null t = ""+ | otherwise = '_':t++-- | Either the 'libraryDirs' or 'libraryDynDirs' as appropriate for the way.+libraryDirsForWay :: DynFlags -> PackageConfig -> [String]+libraryDirsForWay dflags+ | WayDyn `elem` ways dflags = libraryDynDirs+ | otherwise = libraryDirs++-- | Find all the C-compiler options in these and the preload packages+getPackageExtraCcOpts :: DynFlags -> [PreloadUnitId] -> IO [String]+getPackageExtraCcOpts dflags pkgs = do+ ps <- getPreloadPackagesAnd dflags pkgs+ return (concatMap ccOptions ps)++-- | Find all the package framework paths in these and the preload packages+getPackageFrameworkPath :: DynFlags -> [PreloadUnitId] -> IO [String]+getPackageFrameworkPath dflags pkgs = do+ ps <- getPreloadPackagesAnd dflags pkgs+ return (nub (filter notNull (concatMap frameworkDirs ps)))++-- | Find all the package frameworks in these and the preload packages+getPackageFrameworks :: DynFlags -> [PreloadUnitId] -> IO [String]+getPackageFrameworks dflags pkgs = do+ ps <- getPreloadPackagesAnd dflags pkgs+ return (concatMap frameworks ps)++-- -----------------------------------------------------------------------------+-- Package Utils++-- | Takes a 'ModuleName', and if the module is in any package returns+-- list of modules which take that name.+lookupModuleInAllPackages :: DynFlags+ -> ModuleName+ -> [(Module, PackageConfig)]+lookupModuleInAllPackages dflags m+ = case lookupModuleWithSuggestions dflags m Nothing of+ LookupFound a b -> [(a,b)]+ LookupMultiple rs -> map f rs+ where f (m,_) = (m, expectJust "lookupModule" (lookupPackage dflags+ (moduleUnitId m)))+ _ -> []++-- | The result of performing a lookup+data LookupResult =+ -- | Found the module uniquely, nothing else to do+ LookupFound Module PackageConfig+ -- | Multiple modules with the same name in scope+ | LookupMultiple [(Module, ModuleOrigin)]+ -- | No modules found, but there were some hidden ones with+ -- an exact name match. First is due to package hidden, second+ -- is due to module being hidden+ | LookupHidden [(Module, ModuleOrigin)] [(Module, ModuleOrigin)]+ -- | Nothing found, here are some suggested different names+ | LookupNotFound [ModuleSuggestion] -- suggestions++data ModuleSuggestion = SuggestVisible ModuleName Module ModuleOrigin+ | SuggestHidden ModuleName Module ModuleOrigin++lookupModuleWithSuggestions :: DynFlags+ -> ModuleName+ -> Maybe FastString+ -> LookupResult+lookupModuleWithSuggestions dflags+ = lookupModuleWithSuggestions' dflags+ (moduleToPkgConfAll (pkgState dflags))++lookupPluginModuleWithSuggestions :: DynFlags+ -> ModuleName+ -> Maybe FastString+ -> LookupResult+lookupPluginModuleWithSuggestions dflags+ = lookupModuleWithSuggestions' dflags+ (pluginModuleToPkgConfAll (pkgState dflags))++lookupModuleWithSuggestions' :: DynFlags+ -> ModuleToPkgConfAll+ -> ModuleName+ -> Maybe FastString+ -> LookupResult+lookupModuleWithSuggestions' dflags mod_map m mb_pn+ = case Map.lookup m mod_map of+ Nothing -> LookupNotFound suggestions+ Just xs ->+ case foldl' classify ([],[],[]) (Map.toList xs) of+ ([], [], []) -> LookupNotFound suggestions+ (_, _, [(m, _)]) -> LookupFound m (mod_pkg m)+ (_, _, exposed@(_:_)) -> LookupMultiple exposed+ (hidden_pkg, hidden_mod, []) -> LookupHidden hidden_pkg hidden_mod+ where+ classify (hidden_pkg, hidden_mod, exposed) (m, origin0) =+ let origin = filterOrigin mb_pn (mod_pkg m) origin0+ x = (m, origin)+ in case origin of+ ModHidden -> (hidden_pkg, x:hidden_mod, exposed)+ _ | originEmpty origin -> (hidden_pkg, hidden_mod, exposed)+ | originVisible origin -> (hidden_pkg, hidden_mod, x:exposed)+ | otherwise -> (x:hidden_pkg, hidden_mod, exposed)++ pkg_lookup p = lookupPackage dflags p `orElse` pprPanic "lookupModuleWithSuggestions" (ppr p <+> ppr m)+ mod_pkg = pkg_lookup . moduleUnitId++ -- Filters out origins which are not associated with the given package+ -- qualifier. No-op if there is no package qualifier. Test if this+ -- excluded all origins with 'originEmpty'.+ filterOrigin :: Maybe FastString+ -> PackageConfig+ -> ModuleOrigin+ -> ModuleOrigin+ filterOrigin Nothing _ o = o+ filterOrigin (Just pn) pkg o =+ case o of+ ModHidden -> if go pkg then ModHidden else mempty+ ModOrigin { fromOrigPackage = e, fromExposedReexport = res,+ fromHiddenReexport = rhs }+ -> ModOrigin {+ fromOrigPackage = if go pkg then e else Nothing+ , fromExposedReexport = filter go res+ , fromHiddenReexport = filter go rhs+ , fromPackageFlag = False -- always excluded+ }+ where go pkg = pn == fsPackageName pkg++ suggestions+ | gopt Opt_HelpfulErrors dflags =+ fuzzyLookup (moduleNameString m) all_mods+ | otherwise = []++ all_mods :: [(String, ModuleSuggestion)] -- All modules+ all_mods = sortBy (comparing fst) $+ [ (moduleNameString m, suggestion)+ | (m, e) <- Map.toList (moduleToPkgConfAll (pkgState dflags))+ , suggestion <- map (getSuggestion m) (Map.toList e)+ ]+ getSuggestion name (mod, origin) =+ (if originVisible origin then SuggestVisible else SuggestHidden)+ name mod origin++listVisibleModuleNames :: DynFlags -> [ModuleName]+listVisibleModuleNames dflags =+ map fst (filter visible (Map.toList (moduleToPkgConfAll (pkgState dflags))))+ where visible (_, ms) = any originVisible (Map.elems ms)++-- | Find all the 'PackageConfig' in both the preload packages from 'DynFlags' and corresponding to the list of+-- 'PackageConfig's+getPreloadPackagesAnd :: DynFlags -> [PreloadUnitId] -> IO [PackageConfig]+getPreloadPackagesAnd dflags pkgids =+ let+ state = pkgState dflags+ pkg_map = pkgIdMap state+ preload = preloadPackages state+ pairs = zip pkgids (repeat Nothing)+ in do+ all_pkgs <- throwErr dflags (foldM (add_package dflags pkg_map) preload pairs)+ return (map (getInstalledPackageDetails dflags) all_pkgs)++-- Takes a list of packages, and returns the list with dependencies included,+-- in reverse dependency order (a package appears before those it depends on).+closeDeps :: DynFlags+ -> PackageConfigMap+ -> [(InstalledUnitId, Maybe InstalledUnitId)]+ -> IO [InstalledUnitId]+closeDeps dflags pkg_map ps+ = throwErr dflags (closeDepsErr dflags pkg_map ps)++throwErr :: DynFlags -> MaybeErr MsgDoc a -> IO a+throwErr dflags m+ = case m of+ Failed e -> throwGhcExceptionIO (CmdLineError (showSDoc dflags e))+ Succeeded r -> return r++closeDepsErr :: DynFlags+ -> PackageConfigMap+ -> [(InstalledUnitId,Maybe InstalledUnitId)]+ -> MaybeErr MsgDoc [InstalledUnitId]+closeDepsErr dflags pkg_map ps = foldM (add_package dflags pkg_map) [] ps++-- internal helper+add_package :: DynFlags+ -> PackageConfigMap+ -> [PreloadUnitId]+ -> (PreloadUnitId,Maybe PreloadUnitId)+ -> MaybeErr MsgDoc [PreloadUnitId]+add_package dflags pkg_db ps (p, mb_parent)+ | p `elem` ps = return ps -- Check if we've already added this package+ | otherwise =+ case lookupInstalledPackage' pkg_db p of+ Nothing -> Failed (missingPackageMsg p <>+ missingDependencyMsg mb_parent)+ Just pkg -> do+ -- Add the package's dependents also+ ps' <- foldM add_unit_key ps (depends pkg)+ return (p : ps')+ where+ add_unit_key ps key+ = add_package dflags pkg_db ps (key, Just p)++missingPackageMsg :: Outputable pkgid => pkgid -> SDoc+missingPackageMsg p = text "unknown package:" <+> ppr p++missingDependencyMsg :: Maybe InstalledUnitId -> SDoc+missingDependencyMsg Nothing = Outputable.empty+missingDependencyMsg (Just parent)+ = space <> parens (text "dependency of" <+> ftext (installedUnitIdFS parent))++-- -----------------------------------------------------------------------------++componentIdString :: DynFlags -> ComponentId -> Maybe String+componentIdString dflags cid = do+ conf <- lookupInstalledPackage dflags (componentIdToInstalledUnitId cid)+ return $+ case sourceLibName conf of+ Nothing -> sourcePackageIdString conf+ Just (PackageName libname) ->+ packageNameString conf+ ++ "-" ++ showVersion (packageVersion conf)+ ++ ":" ++ unpackFS libname++displayInstalledUnitId :: DynFlags -> InstalledUnitId -> Maybe String+displayInstalledUnitId dflags uid =+ fmap sourcePackageIdString (lookupInstalledPackage dflags uid)++-- | Will the 'Name' come from a dynamically linked library?+isDllName :: DynFlags -> Module -> Name -> Bool+-- Despite the "dll", I think this function just means that+-- the symbol comes from another dynamically-linked package,+-- and applies on all platforms, not just Windows+isDllName dflags this_mod name+ | WayDyn `notElem` ways dflags = False+ | Just mod <- nameModule_maybe name+ -- Issue #8696 - when GHC is dynamically linked, it will attempt+ -- to load the dynamic dependencies of object files at compile+ -- time for things like QuasiQuotes or+ -- TemplateHaskell. Unfortunately, this interacts badly with+ -- intra-package linking, because we don't generate indirect+ -- (dynamic) symbols for intra-package calls. This means that if a+ -- module with an intra-package call is loaded without its+ -- dependencies, then GHC fails to link. This is the cause of #+ --+ -- In the mean time, always force dynamic indirections to be+ -- generated: when the module name isn't the module being+ -- compiled, references are dynamic.+ = if mod /= this_mod+ then True+ else case dllSplit dflags of+ Nothing -> False+ Just ss ->+ let findMod m = let modStr = moduleNameString (moduleName m)+ in case find (modStr `Set.member`) ss of+ Just i -> i+ Nothing -> panic ("Can't find " ++ modStr ++ "in DLL split")+ in findMod mod /= findMod this_mod++ | otherwise = False -- no, it is not even an external name++-- -----------------------------------------------------------------------------+-- Displaying packages++-- | Show (very verbose) package info+pprPackages :: DynFlags -> SDoc+pprPackages = pprPackagesWith pprPackageConfig++pprPackagesWith :: (PackageConfig -> SDoc) -> DynFlags -> SDoc+pprPackagesWith pprIPI dflags =+ vcat (intersperse (text "---") (map pprIPI (listPackageConfigMap dflags)))++-- | Show simplified package info.+--+-- The idea is to only print package id, and any information that might+-- be different from the package databases (exposure, trust)+pprPackagesSimple :: DynFlags -> SDoc+pprPackagesSimple = pprPackagesWith pprIPI+ where pprIPI ipi = let i = installedUnitIdFS (unitId ipi)+ e = if exposed ipi then text "E" else text " "+ t = if trusted ipi then text "T" else text " "+ in e <> t <> text " " <> ftext i++-- | Show the mapping of modules to where they come from.+pprModuleMap :: ModuleToPkgConfAll -> SDoc+pprModuleMap mod_map =+ vcat (map pprLine (Map.toList mod_map))+ where+ pprLine (m,e) = ppr m $$ nest 50 (vcat (map (pprEntry m) (Map.toList e)))+ pprEntry :: Outputable a => ModuleName -> (Module, a) -> SDoc+ pprEntry m (m',o)+ | m == moduleName m' = ppr (moduleUnitId m') <+> parens (ppr o)+ | otherwise = ppr m' <+> parens (ppr o)++fsPackageName :: PackageConfig -> FastString+fsPackageName = mkFastString . packageNameString++-- | Given a fully instantiated 'UnitId', improve it into a+-- 'InstalledUnitId' if we can find it in the package database.+improveUnitId :: PackageConfigMap -> UnitId -> UnitId+improveUnitId _ uid@(DefiniteUnitId _) = uid -- short circuit+improveUnitId pkg_map uid =+ -- Do NOT lookup indefinite ones, they won't be useful!+ case lookupPackage' False pkg_map uid of+ Nothing -> uid+ Just pkg ->+ -- Do NOT improve if the indefinite unit id is not+ -- part of the closure unique set. See+ -- Note [UnitId to InstalledUnitId improvement]+ if installedPackageConfigId pkg `elementOfUniqSet` preloadClosure pkg_map+ then packageConfigId pkg+ else uid++-- | Retrieve the 'PackageConfigMap' from 'DynFlags'; used+-- in the @hs-boot@ loop-breaker.+getPackageConfigMap :: DynFlags -> PackageConfigMap+getPackageConfigMap = pkgIdMap . pkgState
+ main/Packages.hs-boot view
@@ -0,0 +1,10 @@+module Packages where+import {-# SOURCE #-} DynFlags(DynFlags)+import {-# SOURCE #-} Module(ComponentId, UnitId, InstalledUnitId)+data PackageState+data PackageConfigMap+emptyPackageState :: PackageState+componentIdString :: DynFlags -> ComponentId -> Maybe String+displayInstalledUnitId :: DynFlags -> InstalledUnitId -> Maybe String+improveUnitId :: PackageConfigMap -> UnitId -> UnitId+getPackageConfigMap :: DynFlags -> PackageConfigMap
+ main/PipelineMonad.hs view
@@ -0,0 +1,107 @@+{-# LANGUAGE NamedFieldPuns #-}+-- | The CompPipeline monad and associated ops+--+-- Defined in separate module so that it can safely be imported from Hooks+module PipelineMonad (+ CompPipeline(..), evalP+ , PhasePlus(..)+ , PipeEnv(..), PipeState(..), PipelineOutput(..)+ , getPipeEnv, getPipeState, setDynFlags, setModLocation, setForeignOs+ ) where++import MonadUtils+import Outputable+import DynFlags+import DriverPhases+import HscTypes+import Module++import Control.Monad++newtype CompPipeline a = P { unP :: PipeEnv -> PipeState -> IO (PipeState, a) }++evalP :: CompPipeline a -> PipeEnv -> PipeState -> IO a+evalP f env st = liftM snd $ unP f env st++instance Functor CompPipeline where+ fmap = liftM++instance Applicative CompPipeline where+ pure a = P $ \_env state -> return (state, a)+ (<*>) = ap++instance Monad CompPipeline where+ P m >>= k = P $ \env state -> do (state',a) <- m env state+ unP (k a) env state'++instance MonadIO CompPipeline where+ liftIO m = P $ \_env state -> do a <- m; return (state, a)++data PhasePlus = RealPhase Phase+ | HscOut HscSource ModuleName HscStatus++instance Outputable PhasePlus where+ ppr (RealPhase p) = ppr p+ ppr (HscOut {}) = text "HscOut"++-- -----------------------------------------------------------------------------+-- The pipeline uses a monad to carry around various bits of information++-- PipeEnv: invariant information passed down+data PipeEnv = PipeEnv {+ stop_phase :: Phase, -- ^ Stop just before this phase+ src_filename :: String, -- ^ basename of original input source+ src_basename :: String, -- ^ basename of original input source+ src_suffix :: String, -- ^ its extension+ output_spec :: PipelineOutput -- ^ says where to put the pipeline output+ }++-- PipeState: information that might change during a pipeline run+data PipeState = PipeState {+ hsc_env :: HscEnv,+ -- ^ only the DynFlags change in the HscEnv. The DynFlags change+ -- at various points, for example when we read the OPTIONS_GHC+ -- pragmas in the Cpp phase.+ maybe_loc :: Maybe ModLocation,+ -- ^ the ModLocation. This is discovered during compilation,+ -- in the Hsc phase where we read the module header.+ foreign_os :: [FilePath]+ -- ^ additional object files resulting from compiling foreign+ -- code. They come from two sources: foreign stubs, and+ -- add{C,Cxx,Objc,Objcxx}File from template haskell+ }++data PipelineOutput+ = Temporary+ -- ^ Output should be to a temporary file: we're going to+ -- run more compilation steps on this output later.+ | Persistent+ -- ^ We want a persistent file, i.e. a file in the current directory+ -- derived from the input filename, but with the appropriate extension.+ -- eg. in "ghc -c Foo.hs" the output goes into ./Foo.o.+ | SpecificFile+ -- ^ The output must go into the specific outputFile in DynFlags.+ -- We don't store the filename in the constructor as it changes+ -- when doing -dynamic-too.+ deriving Show++getPipeEnv :: CompPipeline PipeEnv+getPipeEnv = P $ \env state -> return (state, env)++getPipeState :: CompPipeline PipeState+getPipeState = P $ \_env state -> return (state, state)++instance HasDynFlags CompPipeline where+ getDynFlags = P $ \_env state -> return (state, hsc_dflags (hsc_env state))++setDynFlags :: DynFlags -> CompPipeline ()+setDynFlags dflags = P $ \_env state ->+ return (state{hsc_env= (hsc_env state){ hsc_dflags = dflags }}, ())++setModLocation :: ModLocation -> CompPipeline ()+setModLocation loc = P $ \_env state ->+ return (state{ maybe_loc = Just loc }, ())++setForeignOs :: [FilePath] -> CompPipeline ()+setForeignOs os = P $ \_env state ->+ return (state{ foreign_os = os }, ())
+ main/PlatformConstants.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE CPP #-}++-------------------------------------------------------------------------------+--+-- | Platform constants+--+-- (c) The University of Glasgow 2013+--+-------------------------------------------------------------------------------++module PlatformConstants (PlatformConstants(..)) where++-- Produced by deriveConstants+#include "GHCConstantsHaskellType.hs"+
+ main/Plugins.hs view
@@ -0,0 +1,48 @@+module Plugins (+ FrontendPlugin(..), defaultFrontendPlugin,+ Plugin(..), CommandLineOption,+ defaultPlugin+ ) where++import CoreMonad ( CoreToDo, CoreM )+import TcRnTypes ( TcPlugin )+import GhcMonad+import DriverPhases+++-- | Command line options gathered from the -PModule.Name:stuff syntax+-- are given to you as this type+type CommandLineOption = String++-- | 'Plugin' is the core compiler plugin data type. Try to avoid+-- constructing one of these directly, and just modify some fields of+-- 'defaultPlugin' instead: this is to try and preserve source-code+-- compatibility when we add fields to this.+--+-- Nonetheless, this API is preliminary and highly likely to change in+-- the future.+data Plugin = Plugin {+ installCoreToDos :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]+ -- ^ Modify the Core pipeline that will be used for compilation.+ -- This is called as the Core pipeline is built for every module+ -- being compiled, and plugins get the opportunity to modify the+ -- pipeline in a nondeterministic order.+ , tcPlugin :: [CommandLineOption] -> Maybe TcPlugin+ -- ^ An optional typechecker plugin, which may modify the+ -- behaviour of the constraint solver.+ }++-- | Default plugin: does nothing at all! For compatibility reasons+-- you should base all your plugin definitions on this default value.+defaultPlugin :: Plugin+defaultPlugin = Plugin {+ installCoreToDos = const return+ , tcPlugin = const Nothing+ }++type FrontendPluginAction = [String] -> [(String, Maybe Phase)] -> Ghc ()+data FrontendPlugin = FrontendPlugin {+ frontend :: FrontendPluginAction+ }+defaultFrontendPlugin :: FrontendPlugin+defaultFrontendPlugin = FrontendPlugin { frontend = \_ _ -> return () }
+ main/PprTyThing.hs view
@@ -0,0 +1,171 @@+-----------------------------------------------------------------------------+--+-- Pretty-printing TyThings+--+-- (c) The GHC Team 2005+--+-----------------------------------------------------------------------------++{-# LANGUAGE CPP #-}+module PprTyThing (+ pprTyThing,+ pprTyThingInContext,+ pprTyThingLoc,+ pprTyThingInContextLoc,+ pprTyThingHdr,+ pprTypeForUser,+ pprFamInst+ ) where++#include "HsVersions.h"++import Type ( TyThing(..) )+import IfaceSyn ( ShowSub(..), ShowHowMuch(..), AltPpr(..)+ , showToHeader, pprIfaceDecl )+import CoAxiom ( coAxiomTyCon )+import HscTypes( tyThingParent_maybe )+import MkIface ( tyThingToIfaceDecl )+import Type ( tidyOpenType )+import FamInstEnv( FamInst(..), FamFlavor(..) )+import Type( Type, pprTypeApp, pprSigmaType )+import Name+import VarEnv( emptyTidyEnv )+import Outputable++-- -----------------------------------------------------------------------------+-- Pretty-printing entities that we get from the GHC API++{- Note [Pretty-printing TyThings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We pretty-print a TyThing by converting it to an IfaceDecl,+and pretty-printing that (see ppr_ty_thing below).+Here is why:++* When pretty-printing (a type, say), the idiomatic solution is not to+ "rename type variables on the fly", but rather to "tidy" the type+ (which gives each variable a distinct print-name), and then+ pretty-print it (without renaming). Separate the two+ concerns. Functions like tidyType do this.++* Alas, for type constructors, TyCon, tidying does not work well,+ because a TyCon includes DataCons which include Types, which mention+ TyCons. And tidying can't tidy a mutually recursive data structure+ graph, only trees.++* One alternative would be to ensure that TyCons get type variables+ with distinct print-names. That's ok for type variables but less+ easy for kind variables. Processing data type declarations is+ already so complicated that I don't think it's sensible to add the+ extra requirement that it generates only "pretty" types and kinds.++* One place the non-pretty names can show up is in GHCi. But another+ is in interface files. Look at MkIface.tyThingToIfaceDecl which+ converts a TyThing (i.e. TyCon, Class etc) to an IfaceDecl. And it+ already does tidying as part of that conversion! Why? Because+ interface files contains fast-strings, not uniques, so the names+ must at least be distinct.++So if we convert to IfaceDecl, we get a nice tidy IfaceDecl, and can+print that. Of course, that means that pretty-printing IfaceDecls+must be careful to display nice user-friendly results, but that's ok.++See #7730, #8776 for details -}++--------------------+-- | Pretty-prints a 'FamInst' (type/data family instance) with its defining location.+pprFamInst :: FamInst -> SDoc+-- * For data instances we go via pprTyThing of the representational TyCon,+-- because there is already much cleverness associated with printing+-- data type declarations that I don't want to duplicate+-- * For type instances we print directly here; there is no TyCon+-- to give to pprTyThing+--+-- FamInstEnv.pprFamInst does a more quick-and-dirty job for internal purposes++pprFamInst (FamInst { fi_flavor = DataFamilyInst rep_tc })+ = pprTyThingInContextLoc (ATyCon rep_tc)++pprFamInst (FamInst { fi_flavor = SynFamilyInst, fi_axiom = axiom+ , fi_tys = lhs_tys, fi_rhs = rhs })+ = showWithLoc (pprDefinedAt (getName axiom)) $+ hang (text "type instance" <+> pprTypeApp (coAxiomTyCon axiom) lhs_tys)+ 2 (equals <+> ppr rhs)++----------------------------+-- | Pretty-prints a 'TyThing' with its defining location.+pprTyThingLoc :: TyThing -> SDoc+pprTyThingLoc tyThing+ = showWithLoc (pprDefinedAt (getName tyThing))+ (pprTyThing showToHeader tyThing)++-- | Pretty-prints the 'TyThing' header. For functions and data constructors+-- the function is equivalent to 'pprTyThing' but for type constructors+-- and classes it prints only the header part of the declaration.+pprTyThingHdr :: TyThing -> SDoc+pprTyThingHdr = pprTyThing showToHeader++-- | Pretty-prints a 'TyThing' in context: that is, if the entity+-- is a data constructor, record selector, or class method, then+-- the entity's parent declaration is pretty-printed with irrelevant+-- parts omitted.+pprTyThingInContext :: ShowSub -> TyThing -> SDoc+pprTyThingInContext show_sub thing+ = go [] thing+ where+ go ss thing+ = case tyThingParent_maybe thing of+ Just parent ->+ go (getOccName thing : ss) parent+ Nothing ->+ pprTyThing+ (show_sub { ss_how_much = ShowSome ss (AltPpr Nothing) })+ thing++-- | Like 'pprTyThingInContext', but adds the defining location.+pprTyThingInContextLoc :: TyThing -> SDoc+pprTyThingInContextLoc tyThing+ = showWithLoc (pprDefinedAt (getName tyThing))+ (pprTyThingInContext showToHeader tyThing)++-- | Pretty-prints a 'TyThing'.+pprTyThing :: ShowSub -> TyThing -> SDoc+-- We pretty-print 'TyThing' via 'IfaceDecl'+-- See Note [Pretty-printing TyThings]+pprTyThing ss ty_thing+ = pprIfaceDecl ss' (tyThingToIfaceDecl ty_thing)+ where+ ss' = case ss_how_much ss of+ ShowHeader (AltPpr Nothing) -> ss { ss_how_much = ShowHeader ppr' }+ ShowSome xs (AltPpr Nothing) -> ss { ss_how_much = ShowSome xs ppr' }+ _ -> ss++ ppr' = AltPpr $ ppr_bndr $ getName ty_thing++ ppr_bndr :: Name -> Maybe (OccName -> SDoc)+ ppr_bndr name+ | isBuiltInSyntax name+ = Nothing+ | otherwise+ = case nameModule_maybe name of+ Just mod -> Just $ \occ -> getPprStyle $ \sty ->+ pprModulePrefix sty mod occ <> ppr occ+ Nothing -> WARN( True, ppr name ) Nothing+ -- Nothing is unexpected here; TyThings have External names++pprTypeForUser :: Type -> SDoc+-- The type is tidied+pprTypeForUser ty+ = pprSigmaType tidy_ty+ where+ (_, tidy_ty) = tidyOpenType emptyTidyEnv ty+ -- Often the types/kinds we print in ghci are fully generalised+ -- and have no free variables, but it turns out that we sometimes+ -- print un-generalised kinds (eg when doing :k T), so it's+ -- better to use tidyOpenType here++showWithLoc :: SDoc -> SDoc -> SDoc+showWithLoc loc doc+ = hang doc 2 (char '\t' <> comment <+> loc)+ -- The tab tries to make them line up a bit+ where+ comment = text "--"
+ main/StaticPtrTable.hs view
@@ -0,0 +1,290 @@+-- | Code generation for the Static Pointer Table+--+-- (c) 2014 I/O Tweag+--+-- Each module that uses 'static' keyword declares an initialization function of+-- the form hs_spt_init_<module>() which is emitted into the _stub.c file and+-- annotated with __attribute__((constructor)) so that it gets executed at+-- startup time.+--+-- The function's purpose is to call hs_spt_insert to insert the static+-- pointers of this module in the hashtable of the RTS, and it looks something+-- like this:+--+-- > static void hs_hpc_init_Main(void) __attribute__((constructor));+-- > static void hs_hpc_init_Main(void) {+-- >+-- > static StgWord64 k0[2] = {16252233372134256ULL,7370534374096082ULL};+-- > extern StgPtr Main_r2wb_closure;+-- > hs_spt_insert(k0, &Main_r2wb_closure);+-- >+-- > static StgWord64 k1[2] = {12545634534567898ULL,5409674567544151ULL};+-- > extern StgPtr Main_r2wc_closure;+-- > hs_spt_insert(k1, &Main_r2wc_closure);+-- >+-- > }+--+-- where the constants are fingerprints produced from the static forms.+--+-- The linker must find the definitions matching the @extern StgPtr <name>@+-- declarations. For this to work, the identifiers of static pointers need to be+-- exported. This is done in SetLevels.newLvlVar.+--+-- There is also a finalization function for the time when the module is+-- unloaded.+--+-- > static void hs_hpc_fini_Main(void) __attribute__((destructor));+-- > static void hs_hpc_fini_Main(void) {+-- >+-- > static StgWord64 k0[2] = {16252233372134256ULL,7370534374096082ULL};+-- > hs_spt_remove(k0);+-- >+-- > static StgWord64 k1[2] = {12545634534567898ULL,5409674567544151ULL};+-- > hs_spt_remove(k1);+-- >+-- > }+--++{-# LANGUAGE ViewPatterns, TupleSections #-}+module StaticPtrTable+ ( sptCreateStaticBinds+ , sptModuleInitCode+ ) where++{- Note [Grand plan for static forms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Static forms go through the compilation phases as follows.+Here is a running example:++ f x = let k = map toUpper+ in ...(static k)...++* The renamer looks for out-of-scope names in the body of the static+ form, as always If all names are in scope, the free variables of the+ body are stored in AST at the location of the static form.++* The typechecker verifies that all free variables occurring in the+ static form are floatable to top level (see Note [Meaning of+ IdBindingInfo] in TcRnTypes). In our example, 'k' is floatable, even+ though it is bound in a nested let, we are fine.++* The desugarer replaces the static form with an application of the+ function 'makeStatic' (defined in module GHC.StaticPtr.Internal of+ base). So we get++ f x = let k = map toUpper+ in ...fromStaticPtr (makeStatic location k)...++* The simplifier runs the FloatOut pass which moves the calls to 'makeStatic'+ to the top level. Thus the FloatOut pass is always executed, even when+ optimizations are disabled. So we get++ k = map toUpper+ static_ptr = makeStatic location k+ f x = ...fromStaticPtr static_ptr...++ The FloatOut pass is careful to produce an /exported/ Id for a floated+ 'makeStatic' call, so the binding is not removed or inlined by the+ simplifier.+ E.g. the code for `f` above might look like++ static_ptr = makeStatic location k+ f x = ...(case static_ptr of ...)...++ which might be simplified to++ f x = ...(case makeStatic location k of ...)...++ BUT the top-level binding for static_ptr must remain, so that it can be+ collected to populate the Static Pointer Table.++ Making the binding exported also has a necessary effect during the+ CoreTidy pass.++* The CoreTidy pass replaces all bindings of the form++ b = /\ ... -> makeStatic location value++ with++ b = /\ ... -> StaticPtr key (StaticPtrInfo "pkg key" "module" location) value++ where a distinct key is generated for each binding.++* If we are compiling to object code we insert a C stub (generated by+ sptModuleInitCode) into the final object which runs when the module is loaded,+ inserting the static forms defined by the module into the RTS's static pointer+ table.++* If we are compiling for the byte-code interpreter, we instead explicitly add+ the SPT entries (recorded in CgGuts' cg_spt_entries field) to the interpreter+ process' SPT table using the addSptEntry interpreter message. This happens+ in upsweep after we have compiled the module (see GhcMake.upsweep').+-}++import CLabel+import CoreSyn+import CoreUtils (collectMakeStaticArgs)+import DataCon+import DynFlags+import HscTypes+import Id+import MkCore (mkStringExprFSWith)+import Module+import Name+import Outputable+import Platform+import PrelNames+import TcEnv (lookupGlobal)+import Type++import Control.Monad.Trans.Class (lift)+import Control.Monad.Trans.State+import Data.List+import Data.Maybe+import GHC.Fingerprint+import qualified GHC.LanguageExtensions as LangExt++-- | Replaces all bindings of the form+--+-- > b = /\ ... -> makeStatic location value+--+-- with+--+-- > b = /\ ... ->+-- > StaticPtr key (StaticPtrInfo "pkg key" "module" location) value+--+-- where a distinct key is generated for each binding.+--+-- It also yields the C stub that inserts these bindings into the static+-- pointer table.+sptCreateStaticBinds :: HscEnv -> Module -> CoreProgram+ -> IO ([SptEntry], CoreProgram)+sptCreateStaticBinds hsc_env this_mod binds+ | not (xopt LangExt.StaticPointers dflags) =+ return ([], binds)+ | otherwise = do+ -- Make sure the required interface files are loaded.+ _ <- lookupGlobal hsc_env unpackCStringName+ (fps, binds') <- evalStateT (go [] [] binds) 0+ return (fps, binds')+ where+ go fps bs xs = case xs of+ [] -> return (reverse fps, reverse bs)+ bnd : xs' -> do+ (fps', bnd') <- replaceStaticBind bnd+ go (reverse fps' ++ fps) (bnd' : bs) xs'++ dflags = hsc_dflags hsc_env++ -- Generates keys and replaces 'makeStatic' with 'StaticPtr'.+ --+ -- The 'Int' state is used to produce a different key for each binding.+ replaceStaticBind :: CoreBind+ -> StateT Int IO ([SptEntry], CoreBind)+ replaceStaticBind (NonRec b e) = do (mfp, (b', e')) <- replaceStatic b e+ return (maybeToList mfp, NonRec b' e')+ replaceStaticBind (Rec rbs) = do+ (mfps, rbs') <- unzip <$> mapM (uncurry replaceStatic) rbs+ return (catMaybes mfps, Rec rbs')++ replaceStatic :: Id -> CoreExpr+ -> StateT Int IO (Maybe SptEntry, (Id, CoreExpr))+ replaceStatic b e@(collectTyBinders -> (tvs, e0)) =+ case collectMakeStaticArgs e0 of+ Nothing -> return (Nothing, (b, e))+ Just (_, t, info, arg) -> do+ (fp, e') <- mkStaticBind t info arg+ return (Just (SptEntry b fp), (b, foldr Lam e' tvs))++ mkStaticBind :: Type -> CoreExpr -> CoreExpr+ -> StateT Int IO (Fingerprint, CoreExpr)+ mkStaticBind t srcLoc e = do+ i <- get+ put (i + 1)+ staticPtrInfoDataCon <-+ lift $ lookupDataConHscEnv staticPtrInfoDataConName+ let fp@(Fingerprint w0 w1) = mkStaticPtrFingerprint i+ info <- mkConApp staticPtrInfoDataCon <$>+ (++[srcLoc]) <$>+ mapM (mkStringExprFSWith (lift . lookupIdHscEnv))+ [ unitIdFS $ moduleUnitId this_mod+ , moduleNameFS $ moduleName this_mod+ ]++ -- The module interface of GHC.StaticPtr should be loaded at least+ -- when looking up 'fromStatic' during type-checking.+ staticPtrDataCon <- lift $ lookupDataConHscEnv staticPtrDataConName+ return (fp, mkConApp staticPtrDataCon+ [ Type t+ , mkWord64LitWordRep dflags w0+ , mkWord64LitWordRep dflags w1+ , info+ , e ])++ mkStaticPtrFingerprint :: Int -> Fingerprint+ mkStaticPtrFingerprint n = fingerprintString $ intercalate ":"+ [ unitIdString $ moduleUnitId this_mod+ , moduleNameString $ moduleName this_mod+ , show n+ ]++ -- Choose either 'Word64#' or 'Word#' to represent the arguments of the+ -- 'Fingerprint' data constructor.+ mkWord64LitWordRep dflags+ | platformWordSize (targetPlatform dflags) < 8 = mkWord64LitWord64+ | otherwise = mkWordLit dflags . toInteger++ lookupIdHscEnv :: Name -> IO Id+ lookupIdHscEnv n = lookupTypeHscEnv hsc_env n >>=+ maybe (getError n) (return . tyThingId)++ lookupDataConHscEnv :: Name -> IO DataCon+ lookupDataConHscEnv n = lookupTypeHscEnv hsc_env n >>=+ maybe (getError n) (return . tyThingDataCon)++ getError n = pprPanic "sptCreateStaticBinds.get: not found" $+ text "Couldn't find" <+> ppr n++-- | @sptModuleInitCode module fps@ is a C stub to insert the static entries+-- of @module@ into the static pointer table.+--+-- @fps@ is a list associating each binding corresponding to a static entry with+-- its fingerprint.+sptModuleInitCode :: Module -> [SptEntry] -> SDoc+sptModuleInitCode _ [] = Outputable.empty+sptModuleInitCode this_mod entries = vcat+ [ text "static void hs_spt_init_" <> ppr this_mod+ <> text "(void) __attribute__((constructor));"+ , text "static void hs_spt_init_" <> ppr this_mod <> text "(void)"+ , braces $ vcat $+ [ text "static StgWord64 k" <> int i <> text "[2] = "+ <> pprFingerprint fp <> semi+ $$ text "extern StgPtr "+ <> (ppr $ mkClosureLabel (idName n) (idCafInfo n)) <> semi+ $$ text "hs_spt_insert" <> parens+ (hcat $ punctuate comma+ [ char 'k' <> int i+ , char '&' <> ppr (mkClosureLabel (idName n) (idCafInfo n))+ ]+ )+ <> semi+ | (i, SptEntry n fp) <- zip [0..] entries+ ]+ , text "static void hs_spt_fini_" <> ppr this_mod+ <> text "(void) __attribute__((destructor));"+ , text "static void hs_spt_fini_" <> ppr this_mod <> text "(void)"+ , braces $ vcat $+ [ text "StgWord64 k" <> int i <> text "[2] = "+ <> pprFingerprint fp <> semi+ $$ text "hs_spt_remove" <> parens (char 'k' <> int i) <> semi+ | (i, (SptEntry _ fp)) <- zip [0..] entries+ ]+ ]+ where+ pprFingerprint :: Fingerprint -> SDoc+ pprFingerprint (Fingerprint w1 w2) =+ braces $ hcat $ punctuate comma+ [ integer (fromIntegral w1) <> text "ULL"+ , integer (fromIntegral w2) <> text "ULL"+ ]
+ main/SysTools.hs view
@@ -0,0 +1,1784 @@+{-+-----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 2001-2003+--+-- Access to system tools: gcc, cp, rm etc+--+-----------------------------------------------------------------------------+-}++{-# LANGUAGE CPP, ScopedTypeVariables #-}++module SysTools (+ -- Initialisation+ initSysTools,++ -- Interface to system tools+ runUnlit, runCpp, runCc, -- [Option] -> IO ()+ runPp, -- [Option] -> IO ()+ runSplit, -- [Option] -> IO ()+ runAs, runLink, runLibtool, -- [Option] -> IO ()+ runMkDLL,+ runWindres,+ runLlvmOpt,+ runLlvmLlc,+ runClang,+ figureLlvmVersion,++ getLinkerInfo,+ getCompilerInfo,++ linkDynLib,++ askLd,++ touch, -- String -> String -> IO ()+ copy,+ copyWithHeader,++ -- Temporary-file management+ setTmpDir,+ newTempName, newTempLibName,+ cleanTempDirs, cleanTempFiles, cleanTempFilesExcept,+ addFilesToClean,++ Option(..),++ -- frameworks+ getPkgFrameworkOpts,+ getFrameworkOpts+++ ) where++#include "HsVersions.h"++import DriverPhases+import Module+import Packages+import Config+import Outputable+import ErrUtils+import Panic+import Platform+import Util+import DynFlags+import Exception++import LlvmCodeGen.Base (llvmVersionStr, supportedLlvmVersion)++import Data.IORef+import Control.Monad+import System.Exit+import System.Environment+import System.FilePath+import System.IO+import System.IO.Error as IO+import System.Directory+import Data.Char+import Data.List+import qualified Data.Map as Map+import qualified Data.Set as Set++#ifndef mingw32_HOST_OS+import qualified System.Posix.Internals+#else /* Must be Win32 */+import Foreign+import Foreign.C.String+#if MIN_VERSION_Win32(2,5,0)+import qualified System.Win32.Types as Win32+#else+import qualified System.Win32.Info as Win32+#endif+import System.Win32.Types (DWORD, LPTSTR, HANDLE)+import System.Win32.Types (failIfNull, failIf, iNVALID_HANDLE_VALUE)+import System.Win32.File (createFile,closeHandle, gENERIC_READ, fILE_SHARE_READ, oPEN_EXISTING, fILE_ATTRIBUTE_NORMAL, fILE_FLAG_BACKUP_SEMANTICS )+import System.Win32.DLL (loadLibrary, getProcAddress)+#endif++import System.Process+import Control.Concurrent+import FastString+import SrcLoc ( SrcLoc, mkSrcLoc, noSrcSpan, mkSrcSpan )++#ifdef mingw32_HOST_OS+# if defined(i386_HOST_ARCH)+# define WINDOWS_CCONV stdcall+# elif defined(x86_64_HOST_ARCH)+# define WINDOWS_CCONV ccall+# else+# error Unknown mingw32 arch+# endif+#endif++{-+How GHC finds its files+~~~~~~~~~~~~~~~~~~~~~~~++[Note topdir]++GHC needs various support files (library packages, RTS etc), plus+various auxiliary programs (cp, gcc, etc). It starts by finding topdir,+the root of GHC's support files++On Unix:+ - ghc always has a shell wrapper that passes a -B<dir> option++On Windows:+ - ghc never has a shell wrapper.+ - we can find the location of the ghc binary, which is+ $topdir/<foo>/<something>.exe+ where <something> may be "ghc", "ghc-stage2", or similar+ - we strip off the "<foo>/<something>.exe" to leave $topdir.++from topdir we can find package.conf, ghc-asm, etc.+++SysTools.initSysProgs figures out exactly where all the auxiliary programs+are, and initialises mutable variables to make it easy to call them.+To to this, it makes use of definitions in Config.hs, which is a Haskell+file containing variables whose value is figured out by the build system.++Config.hs contains two sorts of things++ cGCC, The *names* of the programs+ cCPP e.g. cGCC = gcc+ cUNLIT cCPP = gcc -E+ etc They do *not* include paths+++ cUNLIT_DIR The *path* to the directory containing unlit, split etc+ cSPLIT_DIR *relative* to the root of the build tree,+ for use when running *in-place* in a build tree (only)++++---------------------------------------------+NOTES for an ALTERNATIVE scheme (i.e *not* what is currently implemented):++Another hair-brained scheme for simplifying the current tool location+nightmare in GHC: Simon originally suggested using another+configuration file along the lines of GCC's specs file - which is fine+except that it means adding code to read yet another configuration+file. What I didn't notice is that the current package.conf is+general enough to do this:++Package+ {name = "tools", import_dirs = [], source_dirs = [],+ library_dirs = [], hs_libraries = [], extra_libraries = [],+ include_dirs = [], c_includes = [], package_deps = [],+ extra_ghc_opts = ["-pgmc/usr/bin/gcc","-pgml${topdir}/bin/unlit", ... etc.],+ extra_cc_opts = [], extra_ld_opts = []}++Which would have the advantage that we get to collect together in one+place the path-specific package stuff with the path-specific tool+stuff.+ End of NOTES+---------------------------------------------++************************************************************************+* *+\subsection{Initialisation}+* *+************************************************************************+-}++initSysTools :: Maybe String -- Maybe TopDir path (without the '-B' prefix)+ -> IO Settings -- Set all the mutable variables above, holding+ -- (a) the system programs+ -- (b) the package-config file+ -- (c) the GHC usage message+initSysTools mbMinusB+ = do top_dir <- findTopDir mbMinusB+ -- see [Note topdir]+ -- NB: top_dir is assumed to be in standard Unix+ -- format, '/' separated++ let settingsFile = top_dir </> "settings"+ platformConstantsFile = top_dir </> "platformConstants"+ installed :: FilePath -> FilePath+ installed file = top_dir </> file+ libexec :: FilePath -> FilePath+ libexec file = top_dir </> "bin" </> file++ settingsStr <- readFile settingsFile+ platformConstantsStr <- readFile platformConstantsFile+ mySettings <- case maybeReadFuzzy settingsStr of+ Just s ->+ return s+ Nothing ->+ pgmError ("Can't parse " ++ show settingsFile)+ platformConstants <- case maybeReadFuzzy platformConstantsStr of+ Just s ->+ return s+ Nothing ->+ pgmError ("Can't parse " +++ show platformConstantsFile)+ let getSetting key = case lookup key mySettings of+ Just xs ->+ return $ case stripPrefix "$topdir" xs of+ Just [] ->+ top_dir+ Just xs'@(c:_)+ | isPathSeparator c ->+ top_dir ++ xs'+ _ ->+ xs+ Nothing -> pgmError ("No entry for " ++ show key ++ " in " ++ show settingsFile)+ getBooleanSetting key = case lookup key mySettings of+ Just "YES" -> return True+ Just "NO" -> return False+ Just xs -> pgmError ("Bad value for " ++ show key ++ ": " ++ show xs)+ Nothing -> pgmError ("No entry for " ++ show key ++ " in " ++ show settingsFile)+ readSetting key = case lookup key mySettings of+ Just xs ->+ case maybeRead xs of+ Just v -> return v+ Nothing -> pgmError ("Failed to read " ++ show key ++ " value " ++ show xs)+ Nothing -> pgmError ("No entry for " ++ show key ++ " in " ++ show settingsFile)+ crossCompiling <- getBooleanSetting "cross compiling"+ targetArch <- readSetting "target arch"+ targetOS <- readSetting "target os"+ targetWordSize <- readSetting "target word size"+ targetUnregisterised <- getBooleanSetting "Unregisterised"+ targetHasGnuNonexecStack <- readSetting "target has GNU nonexec stack"+ targetHasIdentDirective <- readSetting "target has .ident directive"+ targetHasSubsectionsViaSymbols <- readSetting "target has subsections via symbols"+ myExtraGccViaCFlags <- getSetting "GCC extra via C opts"+ -- On Windows, mingw is distributed with GHC,+ -- so we look in TopDir/../mingw/bin+ -- It would perhaps be nice to be able to override this+ -- with the settings file, but it would be a little fiddly+ -- to make that possible, so for now you can't.+ gcc_prog <- getSetting "C compiler command"+ gcc_args_str <- getSetting "C compiler flags"+ gccSupportsNoPie <- getBooleanSetting "C compiler supports -no-pie"+ cpp_prog <- getSetting "Haskell CPP command"+ cpp_args_str <- getSetting "Haskell CPP flags"+ let unreg_gcc_args = if targetUnregisterised+ then ["-DNO_REGS", "-DUSE_MINIINTERPRETER"]+ else []+ -- TABLES_NEXT_TO_CODE affects the info table layout.+ tntc_gcc_args+ | mkTablesNextToCode targetUnregisterised+ = ["-DTABLES_NEXT_TO_CODE"]+ | otherwise = []+ cpp_args= map Option (words cpp_args_str)+ gcc_args = map Option (words gcc_args_str+ ++ unreg_gcc_args+ ++ tntc_gcc_args)+ ldSupportsCompactUnwind <- getBooleanSetting "ld supports compact unwind"+ ldSupportsBuildId <- getBooleanSetting "ld supports build-id"+ ldSupportsFilelist <- getBooleanSetting "ld supports filelist"+ ldIsGnuLd <- getBooleanSetting "ld is GNU ld"+ perl_path <- getSetting "perl command"++ let pkgconfig_path = installed "package.conf.d"+ ghc_usage_msg_path = installed "ghc-usage.txt"+ ghci_usage_msg_path = installed "ghci-usage.txt"++ -- For all systems, unlit, split, mangle are GHC utilities+ -- architecture-specific stuff is done when building Config.hs+ unlit_path = libexec cGHC_UNLIT_PGM++ -- split is a Perl script+ split_script = libexec cGHC_SPLIT_PGM++ windres_path <- getSetting "windres command"+ libtool_path <- getSetting "libtool command"++ tmpdir <- getTemporaryDirectory++ touch_path <- getSetting "touch command"++ let -- On Win32 we don't want to rely on #!/bin/perl, so we prepend+ -- a call to Perl to get the invocation of split.+ -- On Unix, scripts are invoked using the '#!' method. Binary+ -- installations of GHC on Unix place the correct line on the+ -- front of the script at installation time, so we don't want+ -- to wire-in our knowledge of $(PERL) on the host system here.+ (split_prog, split_args)+ | isWindowsHost = (perl_path, [Option split_script])+ | otherwise = (split_script, [])+ mkdll_prog <- getSetting "dllwrap command"+ let mkdll_args = []++ -- cpp is derived from gcc on all platforms+ -- HACK, see setPgmP below. We keep 'words' here to remember to fix+ -- Config.hs one day.+++ -- Other things being equal, as and ld are simply gcc+ gcc_link_args_str <- getSetting "C compiler link flags"+ let as_prog = gcc_prog+ as_args = gcc_args+ ld_prog = gcc_prog+ ld_args = gcc_args ++ map Option (words gcc_link_args_str)++ -- We just assume on command line+ lc_prog <- getSetting "LLVM llc command"+ lo_prog <- getSetting "LLVM opt command"++ let iserv_prog = libexec "ghc-iserv"++ let platform = Platform {+ platformArch = targetArch,+ platformOS = targetOS,+ platformWordSize = targetWordSize,+ platformUnregisterised = targetUnregisterised,+ platformHasGnuNonexecStack = targetHasGnuNonexecStack,+ platformHasIdentDirective = targetHasIdentDirective,+ platformHasSubsectionsViaSymbols = targetHasSubsectionsViaSymbols,+ platformIsCrossCompiling = crossCompiling+ }++ return $ Settings {+ sTargetPlatform = platform,+ sTmpDir = normalise tmpdir,+ sGhcUsagePath = ghc_usage_msg_path,+ sGhciUsagePath = ghci_usage_msg_path,+ sTopDir = top_dir,+ sRawSettings = mySettings,+ sExtraGccViaCFlags = words myExtraGccViaCFlags,+ sSystemPackageConfig = pkgconfig_path,+ sLdSupportsCompactUnwind = ldSupportsCompactUnwind,+ sLdSupportsBuildId = ldSupportsBuildId,+ sLdSupportsFilelist = ldSupportsFilelist,+ sLdIsGnuLd = ldIsGnuLd,+ sGccSupportsNoPie = gccSupportsNoPie,+ sProgramName = "ghc",+ sProjectVersion = cProjectVersion,+ sPgm_L = unlit_path,+ sPgm_P = (cpp_prog, cpp_args),+ sPgm_F = "",+ sPgm_c = (gcc_prog, gcc_args),+ sPgm_s = (split_prog,split_args),+ sPgm_a = (as_prog, as_args),+ sPgm_l = (ld_prog, ld_args),+ sPgm_dll = (mkdll_prog,mkdll_args),+ sPgm_T = touch_path,+ sPgm_windres = windres_path,+ sPgm_libtool = libtool_path,+ sPgm_lo = (lo_prog,[]),+ sPgm_lc = (lc_prog,[]),+ sPgm_i = iserv_prog,+ sOpt_L = [],+ sOpt_P = [],+ sOpt_F = [],+ sOpt_c = [],+ sOpt_a = [],+ sOpt_l = [],+ sOpt_windres = [],+ sOpt_lo = [],+ sOpt_lc = [],+ sOpt_i = [],+ sPlatformConstants = platformConstants+ }++-- returns a Unix-format path (relying on getBaseDir to do so too)+findTopDir :: Maybe String -- Maybe TopDir path (without the '-B' prefix).+ -> IO String -- TopDir (in Unix format '/' separated)+findTopDir (Just minusb) = return (normalise minusb)+findTopDir Nothing+ = do -- Get directory of executable+ maybe_exec_dir <- getBaseDir+ case maybe_exec_dir of+ -- "Just" on Windows, "Nothing" on unix+ Nothing -> throwGhcExceptionIO (InstallationError "missing -B<dir> option")+ Just dir -> return dir++{-+************************************************************************+* *+\subsection{Running an external program}+* *+************************************************************************+-}++runUnlit :: DynFlags -> [Option] -> IO ()+runUnlit dflags args = do+ let prog = pgm_L dflags+ opts = getOpts dflags opt_L+ runSomething dflags "Literate pre-processor" prog+ (map Option opts ++ args)++runCpp :: DynFlags -> [Option] -> IO ()+runCpp dflags args = do+ let (p,args0) = pgm_P dflags+ args1 = map Option (getOpts dflags opt_P)+ args2 = [Option "-Werror" | gopt Opt_WarnIsError dflags]+ ++ [Option "-Wundef" | wopt Opt_WarnCPPUndef dflags]+ mb_env <- getGccEnv args2+ runSomethingFiltered dflags id "C pre-processor" p+ (args0 ++ args1 ++ args2 ++ args) mb_env++runPp :: DynFlags -> [Option] -> IO ()+runPp dflags args = do+ let prog = pgm_F dflags+ opts = map Option (getOpts dflags opt_F)+ runSomething dflags "Haskell pre-processor" prog (args ++ opts)++runCc :: DynFlags -> [Option] -> IO ()+runCc dflags args = do+ let (p,args0) = pgm_c dflags+ args1 = map Option (getOpts dflags opt_c)+ args2 = args0 ++ args1 ++ args+ mb_env <- getGccEnv args2+ runSomethingResponseFile dflags cc_filter "C Compiler" p args2 mb_env+ where+ -- discard some harmless warnings from gcc that we can't turn off+ cc_filter = unlines . doFilter . lines++ {-+ gcc gives warnings in chunks like so:+ In file included from /foo/bar/baz.h:11,+ from /foo/bar/baz2.h:22,+ from wibble.c:33:+ /foo/flibble:14: global register variable ...+ /foo/flibble:15: warning: call-clobbered r...+ We break it up into its chunks, remove any call-clobbered register+ warnings from each chunk, and then delete any chunks that we have+ emptied of warnings.+ -}+ doFilter = unChunkWarnings . filterWarnings . chunkWarnings []+ -- We can't assume that the output will start with an "In file inc..."+ -- line, so we start off expecting a list of warnings rather than a+ -- location stack.+ chunkWarnings :: [String] -- The location stack to use for the next+ -- list of warnings+ -> [String] -- The remaining lines to look at+ -> [([String], [String])]+ chunkWarnings loc_stack [] = [(loc_stack, [])]+ chunkWarnings loc_stack xs+ = case break loc_stack_start xs of+ (warnings, lss:xs') ->+ case span loc_start_continuation xs' of+ (lsc, xs'') ->+ (loc_stack, warnings) : chunkWarnings (lss : lsc) xs''+ _ -> [(loc_stack, xs)]++ filterWarnings :: [([String], [String])] -> [([String], [String])]+ filterWarnings [] = []+ -- If the warnings are already empty then we are probably doing+ -- something wrong, so don't delete anything+ filterWarnings ((xs, []) : zs) = (xs, []) : filterWarnings zs+ filterWarnings ((xs, ys) : zs) = case filter wantedWarning ys of+ [] -> filterWarnings zs+ ys' -> (xs, ys') : filterWarnings zs++ unChunkWarnings :: [([String], [String])] -> [String]+ unChunkWarnings [] = []+ unChunkWarnings ((xs, ys) : zs) = xs ++ ys ++ unChunkWarnings zs++ loc_stack_start s = "In file included from " `isPrefixOf` s+ loc_start_continuation s = " from " `isPrefixOf` s+ wantedWarning w+ | "warning: call-clobbered register used" `isContainedIn` w = False+ | otherwise = True++isContainedIn :: String -> String -> Bool+xs `isContainedIn` ys = any (xs `isPrefixOf`) (tails ys)++-- | Run the linker with some arguments and return the output+askLd :: DynFlags -> [Option] -> IO String+askLd dflags args = do+ let (p,args0) = pgm_l dflags+ args1 = map Option (getOpts dflags opt_l)+ args2 = args0 ++ args1 ++ args+ mb_env <- getGccEnv args2+ runSomethingWith dflags "gcc" p args2 $ \real_args ->+ readCreateProcessWithExitCode' (proc p real_args){ env = mb_env }++-- Similar to System.Process.readCreateProcessWithExitCode, but stderr is+-- inherited from the parent process, and output to stderr is not captured.+readCreateProcessWithExitCode'+ :: CreateProcess+ -> IO (ExitCode, String) -- ^ stdout+readCreateProcessWithExitCode' proc = do+ (_, Just outh, _, pid) <-+ createProcess proc{ std_out = CreatePipe }++ -- fork off a thread to start consuming the output+ output <- hGetContents outh+ outMVar <- newEmptyMVar+ _ <- forkIO $ evaluate (length output) >> putMVar outMVar ()++ -- wait on the output+ takeMVar outMVar+ hClose outh++ -- wait on the process+ ex <- waitForProcess pid++ return (ex, output)++replaceVar :: (String, String) -> [(String, String)] -> [(String, String)]+replaceVar (var, value) env =+ (var, value) : filter (\(var',_) -> var /= var') env++-- | Version of @System.Process.readProcessWithExitCode@ that takes a+-- key-value tuple to insert into the environment.+readProcessEnvWithExitCode+ :: String -- ^ program path+ -> [String] -- ^ program args+ -> (String, String) -- ^ addition to the environment+ -> IO (ExitCode, String, String) -- ^ (exit_code, stdout, stderr)+readProcessEnvWithExitCode prog args env_update = do+ current_env <- getEnvironment+ readCreateProcessWithExitCode (proc prog args) {+ env = Just (replaceVar env_update current_env) } ""++-- Don't let gcc localize version info string, #8825+c_locale_env :: (String, String)+c_locale_env = ("LANGUAGE", "C")++-- If the -B<dir> option is set, add <dir> to PATH. This works around+-- a bug in gcc on Windows Vista where it can't find its auxiliary+-- binaries (see bug #1110).+getGccEnv :: [Option] -> IO (Maybe [(String,String)])+getGccEnv opts =+ if null b_dirs+ then return Nothing+ else do env <- getEnvironment+ return (Just (map mangle_path env))+ where+ (b_dirs, _) = partitionWith get_b_opt opts++ get_b_opt (Option ('-':'B':dir)) = Left dir+ get_b_opt other = Right other++ mangle_path (path,paths) | map toUpper path == "PATH"+ = (path, '\"' : head b_dirs ++ "\";" ++ paths)+ mangle_path other = other++runSplit :: DynFlags -> [Option] -> IO ()+runSplit dflags args = do+ let (p,args0) = pgm_s dflags+ runSomething dflags "Splitter" p (args0++args)++runAs :: DynFlags -> [Option] -> IO ()+runAs dflags args = do+ let (p,args0) = pgm_a dflags+ args1 = map Option (getOpts dflags opt_a)+ args2 = args0 ++ args1 ++ args+ mb_env <- getGccEnv args2+ runSomethingFiltered dflags id "Assembler" p args2 mb_env++-- | Run the LLVM Optimiser+runLlvmOpt :: DynFlags -> [Option] -> IO ()+runLlvmOpt dflags args = do+ let (p,args0) = pgm_lo dflags+ args1 = map Option (getOpts dflags opt_lo)+ runSomething dflags "LLVM Optimiser" p (args0 ++ args1 ++ args)++-- | Run the LLVM Compiler+runLlvmLlc :: DynFlags -> [Option] -> IO ()+runLlvmLlc dflags args = do+ let (p,args0) = pgm_lc dflags+ args1 = map Option (getOpts dflags opt_lc)+ runSomething dflags "LLVM Compiler" p (args0 ++ args1 ++ args)++-- | Run the clang compiler (used as an assembler for the LLVM+-- backend on OS X as LLVM doesn't support the OS X system+-- assembler)+runClang :: DynFlags -> [Option] -> IO ()+runClang dflags args = do+ -- we simply assume its available on the PATH+ let clang = "clang"+ -- be careful what options we call clang with+ -- see #5903 and #7617 for bugs caused by this.+ (_,args0) = pgm_a dflags+ args1 = map Option (getOpts dflags opt_a)+ args2 = args0 ++ args1 ++ args+ mb_env <- getGccEnv args2+ Exception.catch (do+ runSomethingFiltered dflags id "Clang (Assembler)" clang args2 mb_env+ )+ (\(err :: SomeException) -> do+ errorMsg dflags $+ text ("Error running clang! you need clang installed to use the" +++ " LLVM backend") $+$+ text "(or GHC tried to execute clang incorrectly)"+ throwIO err+ )++-- | Figure out which version of LLVM we are running this session+figureLlvmVersion :: DynFlags -> IO (Maybe (Int, Int))+figureLlvmVersion dflags = do+ let (pgm,opts) = pgm_lc dflags+ args = filter notNull (map showOpt opts)+ -- we grab the args even though they should be useless just in+ -- case the user is using a customised 'llc' that requires some+ -- of the options they've specified. llc doesn't care what other+ -- options are specified when '-version' is used.+ args' = args ++ ["-version"]+ ver <- catchIO (do+ (pin, pout, perr, _) <- runInteractiveProcess pgm args'+ Nothing Nothing+ {- > llc -version+ LLVM (http://llvm.org/):+ LLVM version 3.5.2+ ...+ -}+ hSetBinaryMode pout False+ _ <- hGetLine pout+ vline <- dropWhile (not . isDigit) `fmap` hGetLine pout+ v <- case span (/= '.') vline of+ ("",_) -> fail "no digits!"+ (x,y) -> return (read x+ , read $ takeWhile isDigit $ drop 1 y)++ hClose pin+ hClose pout+ hClose perr+ return $ Just v+ )+ (\err -> do+ debugTraceMsg dflags 2+ (text "Error (figuring out LLVM version):" <+>+ text (show err))+ errorMsg dflags $ vcat+ [ text "Warning:", nest 9 $+ text "Couldn't figure out LLVM version!" $$+ text ("Make sure you have installed LLVM " +++ llvmVersionStr supportedLlvmVersion) ]+ return Nothing)+ return ver++{- Note [Windows stack usage]++See: Trac #8870 (and #8834 for related info) and #12186++On Windows, occasionally we need to grow the stack. In order to do+this, we would normally just bump the stack pointer - but there's a+catch on Windows.++If the stack pointer is bumped by more than a single page, then the+pages between the initial pointer and the resulting location must be+properly committed by the Windows virtual memory subsystem. This is+only needed in the event we bump by more than one page (i.e 4097 bytes+or more).++Windows compilers solve this by emitting a call to a special function+called _chkstk, which does this committing of the pages for you.++The reason this was causing a segfault was because due to the fact the+new code generator tends to generate larger functions, we needed more+stack space in GHC itself. In the x86 codegen, we needed approximately+~12kb of stack space in one go, which caused the process to segfault,+as the intervening pages were not committed.++GCC can emit such a check for us automatically but only when the flag+-fstack-check is used.++See https://gcc.gnu.org/onlinedocs/gnat_ugn/Stack-Overflow-Checking.html+for more information.++-}++{- Note [Run-time linker info]++See also: Trac #5240, Trac #6063, Trac #10110++Before 'runLink', we need to be sure to get the relevant information+about the linker we're using at runtime to see if we need any extra+options. For example, GNU ld requires '--reduce-memory-overheads' and+'--hash-size=31' in order to use reasonable amounts of memory (see+trac #5240.) But this isn't supported in GNU gold.++Generally, the linker changing from what was detected at ./configure+time has always been possible using -pgml, but on Linux it can happen+'transparently' by installing packages like binutils-gold, which+change what /usr/bin/ld actually points to.++Clang vs GCC notes:++For gcc, 'gcc -Wl,--version' gives a bunch of output about how to+invoke the linker before the version information string. For 'clang',+the version information for 'ld' is all that's output. For this+reason, we typically need to slurp up all of the standard error output+and look through it.++Other notes:++We cache the LinkerInfo inside DynFlags, since clients may link+multiple times. The definition of LinkerInfo is there to avoid a+circular dependency.++-}++{- Note [ELF needed shared libs]++Some distributions change the link editor's default handling of+ELF DT_NEEDED tags to include only those shared objects that are+needed to resolve undefined symbols. For Template Haskell we need+the last temporary shared library also if it is not needed for the+currently linked temporary shared library. We specify --no-as-needed+to override the default. This flag exists in GNU ld and GNU gold.++The flag is only needed on ELF systems. On Windows (PE) and Mac OS X+(Mach-O) the flag is not needed.++-}++{- Note [Windows static libGCC]++The GCC versions being upgraded to in #10726 are configured with+dynamic linking of libgcc supported. This results in libgcc being+linked dynamically when a shared library is created.++This introduces thus an extra dependency on GCC dll that was not+needed before by shared libraries created with GHC. This is a particular+issue on Windows because you get a non-obvious error due to this missing+dependency. This dependent dll is also not commonly on your path.++For this reason using the static libgcc is preferred as it preserves+the same behaviour that existed before. There are however some very good+reasons to have the shared version as well as described on page 181 of+https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc.pdf :++"There are several situations in which an application should use the+ shared ‘libgcc’ instead of the static version. The most common of these+ is when the application wishes to throw and catch exceptions across different+ shared libraries. In that case, each of the libraries as well as the application+ itself should use the shared ‘libgcc’. "++-}++neededLinkArgs :: LinkerInfo -> [Option]+neededLinkArgs (GnuLD o) = o+neededLinkArgs (GnuGold o) = o+neededLinkArgs (DarwinLD o) = o+neededLinkArgs (SolarisLD o) = o+neededLinkArgs (AixLD o) = o+neededLinkArgs UnknownLD = []++-- Grab linker info and cache it in DynFlags.+getLinkerInfo :: DynFlags -> IO LinkerInfo+getLinkerInfo dflags = do+ info <- readIORef (rtldInfo dflags)+ case info of+ Just v -> return v+ Nothing -> do+ v <- getLinkerInfo' dflags+ writeIORef (rtldInfo dflags) (Just v)+ return v++-- See Note [Run-time linker info].+getLinkerInfo' :: DynFlags -> IO LinkerInfo+getLinkerInfo' dflags = do+ let platform = targetPlatform dflags+ os = platformOS platform+ (pgm,args0) = pgm_l dflags+ args1 = map Option (getOpts dflags opt_l)+ args2 = args0 ++ args1+ args3 = filter notNull (map showOpt args2)++ -- Try to grab the info from the process output.+ parseLinkerInfo stdo _stde _exitc+ | any ("GNU ld" `isPrefixOf`) stdo =+ -- GNU ld specifically needs to use less memory. This especially+ -- hurts on small object files. Trac #5240.+ -- Set DT_NEEDED for all shared libraries. Trac #10110.+ -- TODO: Investigate if these help or hurt when using split sections.+ return (GnuLD $ map Option ["-Wl,--hash-size=31",+ "-Wl,--reduce-memory-overheads",+ -- ELF specific flag+ -- see Note [ELF needed shared libs]+ "-Wl,--no-as-needed"])++ | any ("GNU gold" `isPrefixOf`) stdo =+ -- GNU gold only needs --no-as-needed. Trac #10110.+ -- ELF specific flag, see Note [ELF needed shared libs]+ return (GnuGold [Option "-Wl,--no-as-needed"])++ -- Unknown linker.+ | otherwise = fail "invalid --version output, or linker is unsupported"++ -- Process the executable call+ info <- catchIO (do+ case os of+ OSSolaris2 ->+ -- Solaris uses its own Solaris linker. Even all+ -- GNU C are recommended to configure with Solaris+ -- linker instead of using GNU binutils linker. Also+ -- all GCC distributed with Solaris follows this rule+ -- precisely so we assume here, the Solaris linker is+ -- used.+ return $ SolarisLD []+ OSAIX ->+ -- IBM AIX uses its own non-binutils linker as well+ return $ AixLD []+ OSDarwin ->+ -- Darwin has neither GNU Gold or GNU LD, but a strange linker+ -- that doesn't support --version. We can just assume that's+ -- what we're using.+ return $ DarwinLD []+ OSiOS ->+ -- Ditto for iOS+ return $ DarwinLD []+ OSMinGW32 ->+ -- GHC doesn't support anything but GNU ld on Windows anyway.+ -- Process creation is also fairly expensive on win32, so+ -- we short-circuit here.+ return $ GnuLD $ map Option+ [ -- Reduce ld memory usage+ "-Wl,--hash-size=31"+ , "-Wl,--reduce-memory-overheads"+ -- Emit gcc stack checks+ -- Note [Windows stack usage]+ , "-fstack-check"+ -- Force static linking of libGCC+ -- Note [Windows static libGCC]+ , "-static-libgcc" ]+ _ -> do+ -- In practice, we use the compiler as the linker here. Pass+ -- -Wl,--version to get linker version info.+ (exitc, stdo, stde) <- readProcessEnvWithExitCode pgm+ (["-Wl,--version"] ++ args3)+ c_locale_env+ -- Split the output by lines to make certain kinds+ -- of processing easier. In particular, 'clang' and 'gcc'+ -- have slightly different outputs for '-Wl,--version', but+ -- it's still easy to figure out.+ parseLinkerInfo (lines stdo) (lines stde) exitc+ )+ (\err -> do+ debugTraceMsg dflags 2+ (text "Error (figuring out linker information):" <+>+ text (show err))+ errorMsg dflags $ hang (text "Warning:") 9 $+ text "Couldn't figure out linker information!" $$+ text "Make sure you're using GNU ld, GNU gold" <+>+ text "or the built in OS X linker, etc."+ return UnknownLD)+ return info++-- Grab compiler info and cache it in DynFlags.+getCompilerInfo :: DynFlags -> IO CompilerInfo+getCompilerInfo dflags = do+ info <- readIORef (rtccInfo dflags)+ case info of+ Just v -> return v+ Nothing -> do+ v <- getCompilerInfo' dflags+ writeIORef (rtccInfo dflags) (Just v)+ return v++-- See Note [Run-time linker info].+getCompilerInfo' :: DynFlags -> IO CompilerInfo+getCompilerInfo' dflags = do+ let (pgm,_) = pgm_c dflags+ -- Try to grab the info from the process output.+ parseCompilerInfo _stdo stde _exitc+ -- Regular GCC+ | any ("gcc version" `isInfixOf`) stde =+ return GCC+ -- Regular clang+ | any ("clang version" `isInfixOf`) stde =+ return Clang+ -- XCode 5.1 clang+ | any ("Apple LLVM version 5.1" `isPrefixOf`) stde =+ return AppleClang51+ -- XCode 5 clang+ | any ("Apple LLVM version" `isPrefixOf`) stde =+ return AppleClang+ -- XCode 4.1 clang+ | any ("Apple clang version" `isPrefixOf`) stde =+ return AppleClang+ -- Unknown linker.+ | otherwise = fail "invalid -v output, or compiler is unsupported"++ -- Process the executable call+ info <- catchIO (do+ (exitc, stdo, stde) <-+ readProcessEnvWithExitCode pgm ["-v"] c_locale_env+ -- Split the output by lines to make certain kinds+ -- of processing easier.+ parseCompilerInfo (lines stdo) (lines stde) exitc+ )+ (\err -> do+ debugTraceMsg dflags 2+ (text "Error (figuring out C compiler information):" <+>+ text (show err))+ errorMsg dflags $ hang (text "Warning:") 9 $+ text "Couldn't figure out C compiler information!" $$+ text "Make sure you're using GNU gcc, or clang"+ return UnknownCC)+ return info++runLink :: DynFlags -> [Option] -> IO ()+runLink dflags args = do+ -- See Note [Run-time linker info]+ linkargs <- neededLinkArgs `fmap` getLinkerInfo dflags+ let (p,args0) = pgm_l dflags+ args1 = map Option (getOpts dflags opt_l)+ args2 = args0 ++ linkargs ++ args1 ++ args+ mb_env <- getGccEnv args2+ runSomethingResponseFile dflags ld_filter "Linker" p args2 mb_env+ where+ ld_filter = case (platformOS (targetPlatform dflags)) of+ OSSolaris2 -> sunos_ld_filter+ _ -> id+{-+ SunOS/Solaris ld emits harmless warning messages about unresolved+ symbols in case of compiling into shared library when we do not+ link against all the required libs. That is the case of GHC which+ does not link against RTS library explicitly in order to be able to+ choose the library later based on binary application linking+ parameters. The warnings look like:++Undefined first referenced+ symbol in file+stg_ap_n_fast ./T2386_Lib.o+stg_upd_frame_info ./T2386_Lib.o+templatezmhaskell_LanguageziHaskellziTHziLib_litE_closure ./T2386_Lib.o+templatezmhaskell_LanguageziHaskellziTHziLib_appE_closure ./T2386_Lib.o+templatezmhaskell_LanguageziHaskellziTHziLib_conE_closure ./T2386_Lib.o+templatezmhaskell_LanguageziHaskellziTHziSyntax_mkNameGzud_closure ./T2386_Lib.o+newCAF ./T2386_Lib.o+stg_bh_upd_frame_info ./T2386_Lib.o+stg_ap_ppp_fast ./T2386_Lib.o+templatezmhaskell_LanguageziHaskellziTHziLib_stringL_closure ./T2386_Lib.o+stg_ap_p_fast ./T2386_Lib.o+stg_ap_pp_fast ./T2386_Lib.o+ld: warning: symbol referencing errors++ this is actually coming from T2386 testcase. The emitting of those+ warnings is also a reason why so many TH testcases fail on Solaris.++ Following filter code is SunOS/Solaris linker specific and should+ filter out only linker warnings. Please note that the logic is a+ little bit more complex due to the simple reason that we need to preserve+ any other linker emitted messages. If there are any. Simply speaking+ if we see "Undefined" and later "ld: warning:..." then we omit all+ text between (including) the marks. Otherwise we copy the whole output.+-}+ sunos_ld_filter :: String -> String+ sunos_ld_filter = unlines . sunos_ld_filter' . lines+ sunos_ld_filter' x = if (undefined_found x && ld_warning_found x)+ then (ld_prefix x) ++ (ld_postfix x)+ else x+ breakStartsWith x y = break (isPrefixOf x) y+ ld_prefix = fst . breakStartsWith "Undefined"+ undefined_found = not . null . snd . breakStartsWith "Undefined"+ ld_warn_break = breakStartsWith "ld: warning: symbol referencing errors"+ ld_postfix = tail . snd . ld_warn_break+ ld_warning_found = not . null . snd . ld_warn_break+++runLibtool :: DynFlags -> [Option] -> IO ()+runLibtool dflags args = do+ linkargs <- neededLinkArgs `fmap` getLinkerInfo dflags+ let args1 = map Option (getOpts dflags opt_l)+ args2 = [Option "-static"] ++ args1 ++ args ++ linkargs+ libtool = pgm_libtool dflags+ mb_env <- getGccEnv args2+ runSomethingFiltered dflags id "Linker" libtool args2 mb_env++runMkDLL :: DynFlags -> [Option] -> IO ()+runMkDLL dflags args = do+ let (p,args0) = pgm_dll dflags+ args1 = args0 ++ args+ mb_env <- getGccEnv (args0++args)+ runSomethingFiltered dflags id "Make DLL" p args1 mb_env++runWindres :: DynFlags -> [Option] -> IO ()+runWindres dflags args = do+ let (gcc, gcc_args) = pgm_c dflags+ windres = pgm_windres dflags+ opts = map Option (getOpts dflags opt_windres)+ quote x = "\"" ++ x ++ "\""+ args' = -- If windres.exe and gcc.exe are in a directory containing+ -- spaces then windres fails to run gcc. We therefore need+ -- to tell it what command to use...+ Option ("--preprocessor=" +++ unwords (map quote (gcc :+ map showOpt gcc_args +++ map showOpt opts +++ ["-E", "-xc", "-DRC_INVOKED"])))+ -- ...but if we do that then if windres calls popen then+ -- it can't understand the quoting, so we have to use+ -- --use-temp-file so that it interprets it correctly.+ -- See #1828.+ : Option "--use-temp-file"+ : args+ mb_env <- getGccEnv gcc_args+ runSomethingFiltered dflags id "Windres" windres args' mb_env++touch :: DynFlags -> String -> String -> IO ()+touch dflags purpose arg =+ runSomething dflags purpose (pgm_T dflags) [FileOption "" arg]++copy :: DynFlags -> String -> FilePath -> FilePath -> IO ()+copy dflags purpose from to = copyWithHeader dflags purpose Nothing from to++copyWithHeader :: DynFlags -> String -> Maybe String -> FilePath -> FilePath+ -> IO ()+copyWithHeader dflags purpose maybe_header from to = do+ showPass dflags purpose++ hout <- openBinaryFile to WriteMode+ hin <- openBinaryFile from ReadMode+ ls <- hGetContents hin -- inefficient, but it'll do for now. ToDo: speed up+ maybe (return ()) (header hout) maybe_header+ hPutStr hout ls+ hClose hout+ hClose hin+ where+ -- write the header string in UTF-8. The header is something like+ -- {-# LINE "foo.hs" #-}+ -- and we want to make sure a Unicode filename isn't mangled.+ header h str = do+ hSetEncoding h utf8+ hPutStr h str+ hSetBinaryMode h True++++{-+************************************************************************+* *+\subsection{Managing temporary files+* *+************************************************************************+-}++cleanTempDirs :: DynFlags -> IO ()+cleanTempDirs dflags+ = unless (gopt Opt_KeepTmpFiles dflags)+ $ mask_+ $ do let ref = dirsToClean dflags+ ds <- atomicModifyIORef' ref $ \ds -> (Map.empty, ds)+ removeTmpDirs dflags (Map.elems ds)++cleanTempFiles :: DynFlags -> IO ()+cleanTempFiles dflags+ = unless (gopt Opt_KeepTmpFiles dflags)+ $ mask_+ $ do let ref = filesToClean dflags+ fs <- atomicModifyIORef' ref $ \fs -> ([],fs)+ removeTmpFiles dflags fs++cleanTempFilesExcept :: DynFlags -> [FilePath] -> IO ()+cleanTempFilesExcept dflags dont_delete+ = unless (gopt Opt_KeepTmpFiles dflags)+ $ mask_+ $ do let ref = filesToClean dflags+ to_delete <- atomicModifyIORef' ref $ \files ->+ let res@(_to_keep, _to_delete) =+ partition (`Set.member` dont_delete_set) files+ in res+ removeTmpFiles dflags to_delete+ where dont_delete_set = Set.fromList dont_delete+++-- Return a unique numeric temp file suffix+newTempSuffix :: DynFlags -> IO Int+newTempSuffix dflags = atomicModifyIORef' (nextTempSuffix dflags) $ \n -> (n+1,n)++-- Find a temporary name that doesn't already exist.+newTempName :: DynFlags -> Suffix -> IO FilePath+newTempName dflags extn+ = do d <- getTempDir dflags+ findTempName (d </> "ghc_") -- See Note [Deterministic base name]+ where+ findTempName :: FilePath -> IO FilePath+ findTempName prefix+ = do n <- newTempSuffix dflags+ let filename = prefix ++ show n <.> extn+ b <- doesFileExist filename+ if b then findTempName prefix+ else do -- clean it up later+ consIORef (filesToClean dflags) filename+ return filename++newTempLibName :: DynFlags -> Suffix -> IO (FilePath, FilePath, String)+newTempLibName dflags extn+ = do d <- getTempDir dflags+ findTempName d ("ghc_")+ where+ findTempName :: FilePath -> String -> IO (FilePath, FilePath, String)+ findTempName dir prefix+ = do n <- newTempSuffix dflags -- See Note [Deterministic base name]+ let libname = prefix ++ show n+ filename = dir </> "lib" ++ libname <.> extn+ b <- doesFileExist filename+ if b then findTempName dir prefix+ else do -- clean it up later+ consIORef (filesToClean dflags) filename+ return (filename, dir, libname)+++-- Return our temporary directory within tmp_dir, creating one if we+-- don't have one yet.+getTempDir :: DynFlags -> IO FilePath+getTempDir dflags = do+ mapping <- readIORef dir_ref+ case Map.lookup tmp_dir mapping of+ Nothing -> do+ pid <- getProcessID+ let prefix = tmp_dir </> "ghc" ++ show pid ++ "_"+ mask_ $ mkTempDir prefix+ Just dir -> return dir+ where+ tmp_dir = tmpDir dflags+ dir_ref = dirsToClean dflags++ mkTempDir :: FilePath -> IO FilePath+ mkTempDir prefix = do+ n <- newTempSuffix dflags+ let our_dir = prefix ++ show n++ -- 1. Speculatively create our new directory.+ createDirectory our_dir++ -- 2. Update the dirsToClean mapping unless an entry already exists+ -- (i.e. unless another thread beat us to it).+ their_dir <- atomicModifyIORef' dir_ref $ \mapping ->+ case Map.lookup tmp_dir mapping of+ Just dir -> (mapping, Just dir)+ Nothing -> (Map.insert tmp_dir our_dir mapping, Nothing)++ -- 3. If there was an existing entry, return it and delete the+ -- directory we created. Otherwise return the directory we created.+ case their_dir of+ Nothing -> do+ debugTraceMsg dflags 2 $+ text "Created temporary directory:" <+> text our_dir+ return our_dir+ Just dir -> do+ removeDirectory our_dir+ return dir+ `catchIO` \e -> if isAlreadyExistsError e+ then mkTempDir prefix else ioError e++-- Note [Deterministic base name]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- The filename of temporary files, especially the basename of C files, can end+-- up in the output in some form, e.g. as part of linker debug information. In the+-- interest of bit-wise exactly reproducible compilation (#4012), the basename of+-- the temporary file no longer contains random information (it used to contain+-- the process id).+--+-- This is ok, as the temporary directory used contains the pid (see getTempDir).++addFilesToClean :: DynFlags -> [FilePath] -> IO ()+-- May include wildcards [used by DriverPipeline.run_phase SplitMangle]+addFilesToClean dflags new_files+ = atomicModifyIORef' (filesToClean dflags) $ \files -> (new_files++files, ())++removeTmpDirs :: DynFlags -> [FilePath] -> IO ()+removeTmpDirs dflags ds+ = traceCmd dflags "Deleting temp dirs"+ ("Deleting: " ++ unwords ds)+ (mapM_ (removeWith dflags removeDirectory) ds)++removeTmpFiles :: DynFlags -> [FilePath] -> IO ()+removeTmpFiles dflags fs+ = warnNon $+ traceCmd dflags "Deleting temp files"+ ("Deleting: " ++ unwords deletees)+ (mapM_ (removeWith dflags removeFile) deletees)+ where+ -- Flat out refuse to delete files that are likely to be source input+ -- files (is there a worse bug than having a compiler delete your source+ -- files?)+ --+ -- Deleting source files is a sign of a bug elsewhere, so prominently flag+ -- the condition.+ warnNon act+ | null non_deletees = act+ | otherwise = do+ putMsg dflags (text "WARNING - NOT deleting source files:" <+> hsep (map text non_deletees))+ act++ (non_deletees, deletees) = partition isHaskellUserSrcFilename fs++removeWith :: DynFlags -> (FilePath -> IO ()) -> FilePath -> IO ()+removeWith dflags remover f = remover f `catchIO`+ (\e ->+ let msg = if isDoesNotExistError e+ then text "Warning: deleting non-existent" <+> text f+ else text "Warning: exception raised when deleting"+ <+> text f <> colon+ $$ text (show e)+ in debugTraceMsg dflags 2 msg+ )++-----------------------------------------------------------------------------+-- Running an external program++runSomething :: DynFlags+ -> String -- For -v message+ -> String -- Command name (possibly a full path)+ -- assumed already dos-ified+ -> [Option] -- Arguments+ -- runSomething will dos-ify them+ -> IO ()++runSomething dflags phase_name pgm args =+ runSomethingFiltered dflags id phase_name pgm args Nothing++-- | Run a command, placing the arguments in an external response file.+--+-- This command is used in order to avoid overlong command line arguments on+-- Windows. The command line arguments are first written to an external,+-- temporary response file, and then passed to the linker via @filepath.+-- response files for passing them in. See:+--+-- https://gcc.gnu.org/wiki/Response_Files+-- https://ghc.haskell.org/trac/ghc/ticket/10777+runSomethingResponseFile+ :: DynFlags -> (String->String) -> String -> String -> [Option]+ -> Maybe [(String,String)] -> IO ()++runSomethingResponseFile dflags filter_fn phase_name pgm args mb_env =+ runSomethingWith dflags phase_name pgm args $ \real_args -> do+ fp <- getResponseFile real_args+ let args = ['@':fp]+ r <- builderMainLoop dflags filter_fn pgm args mb_env+ return (r,())+ where+ getResponseFile args = do+ fp <- newTempName dflags "rsp"+ withFile fp WriteMode $ \h -> do+#if defined(mingw32_HOST_OS)+ hSetEncoding h latin1+#else+ hSetEncoding h utf8+#endif+ hPutStr h $ unlines $ map escape args+ return fp++ -- Note: Response files have backslash-escaping, double quoting, and are+ -- whitespace separated (some implementations use newline, others any+ -- whitespace character). Therefore, escape any backslashes, newlines, and+ -- double quotes in the argument, and surround the content with double+ -- quotes.+ --+ -- Another possibility that could be considered would be to convert+ -- backslashes in the argument to forward slashes. This would generally do+ -- the right thing, since backslashes in general only appear in arguments+ -- as part of file paths on Windows, and the forward slash is accepted for+ -- those. However, escaping is more reliable, in case somehow a backslash+ -- appears in a non-file.+ escape x = concat+ [ "\""+ , concatMap+ (\c ->+ case c of+ '\\' -> "\\\\"+ '\n' -> "\\n"+ '\"' -> "\\\""+ _ -> [c])+ x+ , "\""+ ]++runSomethingFiltered+ :: DynFlags -> (String->String) -> String -> String -> [Option]+ -> Maybe [(String,String)] -> IO ()++runSomethingFiltered dflags filter_fn phase_name pgm args mb_env = do+ runSomethingWith dflags phase_name pgm args $ \real_args -> do+ r <- builderMainLoop dflags filter_fn pgm real_args mb_env+ return (r,())++runSomethingWith+ :: DynFlags -> String -> String -> [Option]+ -> ([String] -> IO (ExitCode, a))+ -> IO a++runSomethingWith dflags phase_name pgm args io = do+ let real_args = filter notNull (map showOpt args)+ cmdLine = showCommandForUser pgm real_args+ traceCmd dflags phase_name cmdLine $ handleProc pgm phase_name $ io real_args++handleProc :: String -> String -> IO (ExitCode, r) -> IO r+handleProc pgm phase_name proc = do+ (rc, r) <- proc `catchIO` handler+ case rc of+ ExitSuccess{} -> return r+ ExitFailure n -> throwGhcExceptionIO (+ ProgramError ("`" ++ takeFileName pgm ++ "'" +++ " failed in phase `" ++ phase_name ++ "'." +++ " (Exit code: " ++ show n ++ ")"))+ where+ handler err =+ if IO.isDoesNotExistError err+ then does_not_exist+ else throwGhcExceptionIO (ProgramError $ show err)++ does_not_exist = throwGhcExceptionIO (InstallationError ("could not execute: " ++ pgm))+++builderMainLoop :: DynFlags -> (String -> String) -> FilePath+ -> [String] -> Maybe [(String, String)]+ -> IO ExitCode+builderMainLoop dflags filter_fn pgm real_args mb_env = do+ chan <- newChan+ (hStdIn, hStdOut, hStdErr, hProcess) <- runInteractiveProcess pgm real_args Nothing mb_env++ -- and run a loop piping the output from the compiler to the log_action in DynFlags+ hSetBuffering hStdOut LineBuffering+ hSetBuffering hStdErr LineBuffering+ _ <- forkIO (readerProc chan hStdOut filter_fn)+ _ <- forkIO (readerProc chan hStdErr filter_fn)+ -- we don't want to finish until 2 streams have been completed+ -- (stdout and stderr)+ -- nor until 1 exit code has been retrieved.+ rc <- loop chan hProcess (2::Integer) (1::Integer) ExitSuccess+ -- after that, we're done here.+ hClose hStdIn+ hClose hStdOut+ hClose hStdErr+ return rc+ where+ -- status starts at zero, and increments each time either+ -- a reader process gets EOF, or the build proc exits. We wait+ -- for all of these to happen (status==3).+ -- ToDo: we should really have a contingency plan in case any of+ -- the threads dies, such as a timeout.+ loop _ _ 0 0 exitcode = return exitcode+ loop chan hProcess t p exitcode = do+ mb_code <- if p > 0+ then getProcessExitCode hProcess+ else return Nothing+ case mb_code of+ Just code -> loop chan hProcess t (p-1) code+ Nothing+ | t > 0 -> do+ msg <- readChan chan+ case msg of+ BuildMsg msg -> do+ putLogMsg dflags NoReason SevInfo noSrcSpan+ (defaultUserStyle dflags) msg+ loop chan hProcess t p exitcode+ BuildError loc msg -> do+ putLogMsg dflags NoReason SevError (mkSrcSpan loc loc)+ (defaultUserStyle dflags) msg+ loop chan hProcess t p exitcode+ EOF ->+ loop chan hProcess (t-1) p exitcode+ | otherwise -> loop chan hProcess t p exitcode++readerProc :: Chan BuildMessage -> Handle -> (String -> String) -> IO ()+readerProc chan hdl filter_fn =+ (do str <- hGetContents hdl+ loop (linesPlatform (filter_fn str)) Nothing)+ `finally`+ writeChan chan EOF+ -- ToDo: check errors more carefully+ -- ToDo: in the future, the filter should be implemented as+ -- a stream transformer.+ where+ loop [] Nothing = return ()+ loop [] (Just err) = writeChan chan err+ loop (l:ls) in_err =+ case in_err of+ Just err@(BuildError srcLoc msg)+ | leading_whitespace l -> do+ loop ls (Just (BuildError srcLoc (msg $$ text l)))+ | otherwise -> do+ writeChan chan err+ checkError l ls+ Nothing -> do+ checkError l ls+ _ -> panic "readerProc/loop"++ checkError l ls+ = case parseError l of+ Nothing -> do+ writeChan chan (BuildMsg (text l))+ loop ls Nothing+ Just (file, lineNum, colNum, msg) -> do+ let srcLoc = mkSrcLoc (mkFastString file) lineNum colNum+ loop ls (Just (BuildError srcLoc (text msg)))++ leading_whitespace [] = False+ leading_whitespace (x:_) = isSpace x++parseError :: String -> Maybe (String, Int, Int, String)+parseError s0 = case breakColon s0 of+ Just (filename, s1) ->+ case breakIntColon s1 of+ Just (lineNum, s2) ->+ case breakIntColon s2 of+ Just (columnNum, s3) ->+ Just (filename, lineNum, columnNum, s3)+ Nothing ->+ Just (filename, lineNum, 0, s2)+ Nothing -> Nothing+ Nothing -> Nothing++breakColon :: String -> Maybe (String, String)+breakColon xs = case break (':' ==) xs of+ (ys, _:zs) -> Just (ys, zs)+ _ -> Nothing++breakIntColon :: String -> Maybe (Int, String)+breakIntColon xs = case break (':' ==) xs of+ (ys, _:zs)+ | not (null ys) && all isAscii ys && all isDigit ys ->+ Just (read ys, zs)+ _ -> Nothing++data BuildMessage+ = BuildMsg !SDoc+ | BuildError !SrcLoc !SDoc+ | EOF++traceCmd :: DynFlags -> String -> String -> IO a -> IO a+-- trace the command (at two levels of verbosity)+traceCmd dflags phase_name cmd_line action+ = do { let verb = verbosity dflags+ ; showPass dflags phase_name+ ; debugTraceMsg dflags 3 (text cmd_line)+ ; case flushErr dflags of+ FlushErr io -> io++ -- And run it!+ ; action `catchIO` handle_exn verb+ }+ where+ handle_exn _verb exn = do { debugTraceMsg dflags 2 (char '\n')+ ; debugTraceMsg dflags 2 (text "Failed:" <+> text cmd_line <+> text (show exn))+ ; throwGhcExceptionIO (ProgramError (show exn))}++{-+************************************************************************+* *+\subsection{Support code}+* *+************************************************************************+-}++-----------------------------------------------------------------------------+-- Define getBaseDir :: IO (Maybe String)++getBaseDir :: IO (Maybe String)+#if defined(mingw32_HOST_OS)+-- Assuming we are running ghc, accessed by path $(stuff)/<foo>/ghc.exe,+-- return the path $(stuff)/lib.+getBaseDir = try_size 2048 -- plenty, PATH_MAX is 512 under Win32.+ where+ try_size size = allocaArray (fromIntegral size) $ \buf -> do+ ret <- c_GetModuleFileName nullPtr buf size+ case ret of+ 0 -> return Nothing+ _ | ret < size -> do+ path <- peekCWString buf+ real <- getFinalPath path -- try to resolve symlinks paths+ let libdir = (rootDir . sanitize . maybe path id) real+ exists <- doesDirectoryExist libdir+ if exists+ then return $ Just libdir+ else fail path+ | otherwise -> try_size (size * 2)++ -- getFinalPath returns paths in full raw form.+ -- Unfortunately GHC isn't set up to handle these+ -- So if the call succeeded, we need to drop the+ -- \\?\ prefix.+ sanitize s = if "\\\\?\\" `isPrefixOf` s+ then drop 4 s+ else s++ rootDir s = case splitFileName $ normalise s of+ (d, ghc_exe)+ | lower ghc_exe `elem` ["ghc.exe",+ "ghc-stage1.exe",+ "ghc-stage2.exe",+ "ghc-stage3.exe"] ->+ case splitFileName $ takeDirectory d of+ -- ghc is in $topdir/bin/ghc.exe+ (d', _) -> takeDirectory d' </> "lib"+ _ -> fail s++ fail s = panic ("can't decompose ghc.exe path: " ++ show s)+ lower = map toLower++foreign import WINDOWS_CCONV unsafe "windows.h GetModuleFileNameW"+ c_GetModuleFileName :: Ptr () -> CWString -> Word32 -> IO Word32++-- Attempt to resolve symlinks in order to find the actual location GHC+-- is located at. See Trac #11759.+getFinalPath :: FilePath -> IO (Maybe FilePath)+getFinalPath name = do+ dllHwnd <- failIfNull "LoadLibray" $ loadLibrary "kernel32.dll"+ -- Note: The API GetFinalPathNameByHandleW is only available starting from Windows Vista.+ -- This means that we can't bind directly to it since it may be missing.+ -- Instead try to find it's address at runtime and if we don't succeed consider the+ -- function failed.+ addr_m <- (fmap Just $ failIfNull "getProcAddress" $ getProcAddress dllHwnd "GetFinalPathNameByHandleW")+ `catch` (\(_ :: SomeException) -> return Nothing)+ case addr_m of+ Nothing -> return Nothing+ Just addr -> do handle <- failIf (==iNVALID_HANDLE_VALUE) "CreateFile"+ $ createFile name+ gENERIC_READ+ fILE_SHARE_READ+ Nothing+ oPEN_EXISTING+ (fILE_ATTRIBUTE_NORMAL .|. fILE_FLAG_BACKUP_SEMANTICS)+ Nothing+ let fnPtr = makeGetFinalPathNameByHandle $ castPtrToFunPtr addr+ path <- Win32.try "GetFinalPathName"+ (\buf len -> fnPtr handle buf len 0) 512+ `finally` closeHandle handle+ return $ Just path++type GetFinalPath = HANDLE -> LPTSTR -> DWORD -> DWORD -> IO DWORD++foreign import WINDOWS_CCONV unsafe "dynamic"+ makeGetFinalPathNameByHandle :: FunPtr GetFinalPath -> GetFinalPath+#else+getBaseDir = return Nothing+#endif++#ifdef mingw32_HOST_OS+foreign import ccall unsafe "_getpid" getProcessID :: IO Int -- relies on Int == Int32 on Windows+#else+getProcessID :: IO Int+getProcessID = System.Posix.Internals.c_getpid >>= return . fromIntegral+#endif++-- Divvy up text stream into lines, taking platform dependent+-- line termination into account.+linesPlatform :: String -> [String]+#if !defined(mingw32_HOST_OS)+linesPlatform ls = lines ls+#else+linesPlatform "" = []+linesPlatform xs =+ case lineBreak xs of+ (as,xs1) -> as : linesPlatform xs1+ where+ lineBreak "" = ("","")+ lineBreak ('\r':'\n':xs) = ([],xs)+ lineBreak ('\n':xs) = ([],xs)+ lineBreak (x:xs) = let (as,bs) = lineBreak xs in (x:as,bs)++#endif++{-+Note [No PIE eating while linking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As of 2016 some Linux distributions (e.g. Debian) have started enabling -pie by+default in their gcc builds. This is incompatible with -r as it implies that we+are producing an executable. Consequently, we must manually pass -no-pie to gcc+when joining object files or linking dynamic libraries. See #12759.+-}++linkDynLib :: DynFlags -> [String] -> [InstalledUnitId] -> IO ()+linkDynLib dflags0 o_files dep_packages+ = do+ let -- This is a rather ugly hack to fix dynamically linked+ -- GHC on Windows. If GHC is linked with -threaded, then+ -- it links against libHSrts_thr. But if base is linked+ -- against libHSrts, then both end up getting loaded,+ -- and things go wrong. We therefore link the libraries+ -- with the same RTS flags that we link GHC with.+ dflags1 = if cGhcThreaded then addWay' WayThreaded dflags0+ else dflags0+ dflags2 = if cGhcDebugged then addWay' WayDebug dflags1+ else dflags1+ dflags = updateWays dflags2++ verbFlags = getVerbFlags dflags+ o_file = outputFile dflags++ pkgs <- getPreloadPackagesAnd dflags dep_packages++ let pkg_lib_paths = collectLibraryPaths dflags pkgs+ let pkg_lib_path_opts = concatMap get_pkg_lib_path_opts pkg_lib_paths+ get_pkg_lib_path_opts l+ | ( osElfTarget (platformOS (targetPlatform dflags)) ||+ osMachOTarget (platformOS (targetPlatform dflags)) ) &&+ dynLibLoader dflags == SystemDependent &&+ WayDyn `elem` ways dflags+ = ["-L" ++ l, "-Xlinker", "-rpath", "-Xlinker", l]+ -- See Note [-Xlinker -rpath vs -Wl,-rpath]+ | otherwise = ["-L" ++ l]++ let lib_paths = libraryPaths dflags+ let lib_path_opts = map ("-L"++) lib_paths++ -- We don't want to link our dynamic libs against the RTS package,+ -- because the RTS lib comes in several flavours and we want to be+ -- able to pick the flavour when a binary is linked.+ -- On Windows we need to link the RTS import lib as Windows does+ -- not allow undefined symbols.+ -- The RTS library path is still added to the library search path+ -- above in case the RTS is being explicitly linked in (see #3807).+ let platform = targetPlatform dflags+ os = platformOS platform+ pkgs_no_rts = case os of+ OSMinGW32 ->+ pkgs+ _ ->+ filter ((/= rtsUnitId) . packageConfigId) pkgs+ let pkg_link_opts = let (package_hs_libs, extra_libs, other_flags) = collectLinkOpts dflags pkgs_no_rts+ in package_hs_libs ++ extra_libs ++ other_flags++ -- probably _stub.o files+ -- and last temporary shared object file+ let extra_ld_inputs = ldInputs dflags++ -- frameworks+ pkg_framework_opts <- getPkgFrameworkOpts dflags platform+ (map unitId pkgs)+ let framework_opts = getFrameworkOpts dflags platform++ case os of+ OSMinGW32 -> do+ -------------------------------------------------------------+ -- Making a DLL+ -------------------------------------------------------------+ let output_fn = case o_file of+ Just s -> s+ Nothing -> "HSdll.dll"++ runLink dflags (+ map Option verbFlags+ ++ [ Option "-o"+ , FileOption "" output_fn+ , Option "-shared"+ ] +++ [ FileOption "-Wl,--out-implib=" (output_fn ++ ".a")+ | gopt Opt_SharedImplib dflags+ ]+ ++ map (FileOption "") o_files++ -- Permit the linker to auto link _symbol to _imp_symbol+ -- This lets us link against DLLs without needing an "import library"+ ++ [Option "-Wl,--enable-auto-import"]++ ++ extra_ld_inputs+ ++ map Option (+ lib_path_opts+ ++ pkg_lib_path_opts+ ++ pkg_link_opts+ ))+ OSDarwin -> do+ -------------------------------------------------------------------+ -- Making a darwin dylib+ -------------------------------------------------------------------+ -- About the options used for Darwin:+ -- -dynamiclib+ -- Apple's way of saying -shared+ -- -undefined dynamic_lookup:+ -- Without these options, we'd have to specify the correct+ -- dependencies for each of the dylibs. Note that we could+ -- (and should) do without this for all libraries except+ -- the RTS; all we need to do is to pass the correct+ -- HSfoo_dyn.dylib files to the link command.+ -- This feature requires Mac OS X 10.3 or later; there is+ -- a similar feature, -flat_namespace -undefined suppress,+ -- which works on earlier versions, but it has other+ -- disadvantages.+ -- -single_module+ -- Build the dynamic library as a single "module", i.e. no+ -- dynamic binding nonsense when referring to symbols from+ -- within the library. The NCG assumes that this option is+ -- specified (on i386, at least).+ -- -install_name+ -- Mac OS/X stores the path where a dynamic library is (to+ -- be) installed in the library itself. It's called the+ -- "install name" of the library. Then any library or+ -- executable that links against it before it's installed+ -- will search for it in its ultimate install location.+ -- By default we set the install name to the absolute path+ -- at build time, but it can be overridden by the+ -- -dylib-install-name option passed to ghc. Cabal does+ -- this.+ -------------------------------------------------------------------++ let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; }++ instName <- case dylibInstallName dflags of+ Just n -> return n+ Nothing -> return $ "@rpath" `combine` (takeFileName output_fn)+ runLink dflags (+ map Option verbFlags+ ++ [ Option "-dynamiclib"+ , Option "-o"+ , FileOption "" output_fn+ ]+ ++ map Option o_files+ ++ [ Option "-undefined",+ Option "dynamic_lookup",+ Option "-single_module" ]+ ++ (if platformArch platform == ArchX86_64+ then [ ]+ else [ Option "-Wl,-read_only_relocs,suppress" ])+ ++ [ Option "-install_name", Option instName ]+ ++ map Option lib_path_opts+ ++ extra_ld_inputs+ ++ map Option framework_opts+ ++ map Option pkg_lib_path_opts+ ++ map Option pkg_link_opts+ ++ map Option pkg_framework_opts+ )+ OSiOS -> throwGhcExceptionIO (ProgramError "dynamic libraries are not supported on iOS target")+ _ -> do+ -------------------------------------------------------------------+ -- Making a DSO+ -------------------------------------------------------------------++ let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; }+ let bsymbolicFlag = -- we need symbolic linking to resolve+ -- non-PIC intra-package-relocations+ ["-Wl,-Bsymbolic"]++ runLink dflags (+ map Option verbFlags+ ++ [ Option "-o"+ , FileOption "" output_fn+ ]+ -- See Note [No PIE eating when linking]+ ++ (if sGccSupportsNoPie (settings dflags)+ then [Option "-no-pie"]+ else [])+ ++ map Option o_files+ ++ [ Option "-shared" ]+ ++ map Option bsymbolicFlag+ -- Set the library soname. We use -h rather than -soname as+ -- Solaris 10 doesn't support the latter:+ ++ [ Option ("-Wl,-h," ++ takeFileName output_fn) ]+ ++ extra_ld_inputs+ ++ map Option lib_path_opts+ ++ map Option pkg_lib_path_opts+ ++ map Option pkg_link_opts+ )++getPkgFrameworkOpts :: DynFlags -> Platform -> [InstalledUnitId] -> IO [String]+getPkgFrameworkOpts dflags platform dep_packages+ | platformUsesFrameworks platform = do+ pkg_framework_path_opts <- do+ pkg_framework_paths <- getPackageFrameworkPath dflags dep_packages+ return $ map ("-F" ++) pkg_framework_paths++ pkg_framework_opts <- do+ pkg_frameworks <- getPackageFrameworks dflags dep_packages+ return $ concat [ ["-framework", fw] | fw <- pkg_frameworks ]++ return (pkg_framework_path_opts ++ pkg_framework_opts)++ | otherwise = return []++getFrameworkOpts :: DynFlags -> Platform -> [String]+getFrameworkOpts dflags platform+ | platformUsesFrameworks platform = framework_path_opts ++ framework_opts+ | otherwise = []+ where+ framework_paths = frameworkPaths dflags+ framework_path_opts = map ("-F" ++) framework_paths++ frameworks = cmdlineFrameworks dflags+ -- reverse because they're added in reverse order from the cmd line:+ framework_opts = concat [ ["-framework", fw]+ | fw <- reverse frameworks ]
+ main/SysTools/Terminal.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+module SysTools.Terminal (stderrSupportsAnsiColors) where+#if defined MIN_VERSION_terminfo+import Control.Exception (catch)+import Data.Maybe (fromMaybe)+import System.Console.Terminfo (SetupTermError, Terminal, getCapability,+ setupTermFromEnv, termColors)+import System.Posix (queryTerminal, stdError)+#elif defined mingw32_HOST_OS+import Control.Exception (catch, try)+import Data.Bits ((.|.), (.&.))+import Data.List (isInfixOf, isPrefixOf, isSuffixOf)+import Foreign (FunPtr, Ptr, allocaBytes, castPtrToFunPtr,+ peek, plusPtr, sizeOf, with)+import Foreign.C (CInt(..), CWchar, peekCWStringLen)+import qualified Graphics.Win32 as Win32+import qualified System.Win32 as Win32+#endif++#if defined mingw32_HOST_OS && !defined WINAPI+# if defined i386_HOST_ARCH+# define WINAPI stdcall+# elif defined x86_64_HOST_ARCH+# define WINAPI ccall+# else+# error unknown architecture+# endif+#endif++-- | Check if ANSI escape sequences can be used to control color in stderr.+stderrSupportsAnsiColors :: IO Bool+stderrSupportsAnsiColors = do+#if defined MIN_VERSION_terminfo+ queryTerminal stdError `andM` do+ (termSupportsColors <$> setupTermFromEnv)+ `catch` \ (_ :: SetupTermError) ->+ pure False++ where++ andM :: Monad m => m Bool -> m Bool -> m Bool+ andM mx my = do+ x <- mx+ if x+ then my+ else pure x++ termSupportsColors :: Terminal -> Bool+ termSupportsColors term = fromMaybe 0 (getCapability term termColors) > 0++#elif defined mingw32_HOST_OS+ h <- Win32.getStdHandle Win32.sTD_ERROR_HANDLE+ `catch` \ (_ :: IOError) ->+ pure Win32.nullHANDLE+ if h == Win32.nullHANDLE+ then pure False+ else do+ eMode <- try (getConsoleMode h)+ case eMode of+ Left (_ :: IOError) -> queryCygwinTerminal h+ Right mode+ | modeHasVTP mode -> pure True+ | otherwise -> enableVTP h mode++ where++ queryCygwinTerminal :: Win32.HANDLE -> IO Bool+ queryCygwinTerminal h = do+ fileType <- Win32.getFileType h+ if fileType /= Win32.fILE_TYPE_PIPE+ then pure False+ else do+ fn <- getFileNameByHandle h+ pure (("\\cygwin-" `isPrefixOf` fn || "\\msys-" `isPrefixOf` fn) &&+ "-pty" `isInfixOf` fn &&+ "-master" `isSuffixOf` fn)+ `catch` \ (_ :: IOError) ->+ pure False++ enableVTP :: Win32.HANDLE -> Win32.DWORD -> IO Bool+ enableVTP h mode = do+ setConsoleMode h (modeAddVTP mode)+ modeHasVTP <$> getConsoleMode h+ `catch` \ (_ :: IOError) ->+ pure False++ modeHasVTP :: Win32.DWORD -> Bool+ modeHasVTP mode = mode .&. eNABLE_VIRTUAL_TERMINAL_PROCESSING /= 0++ modeAddVTP :: Win32.DWORD -> Win32.DWORD+ modeAddVTP mode = mode .|. eNABLE_VIRTUAL_TERMINAL_PROCESSING++eNABLE_VIRTUAL_TERMINAL_PROCESSING :: Win32.DWORD+eNABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004++getConsoleMode :: Win32.HANDLE -> IO Win32.DWORD+getConsoleMode h = with 64 $ \ mode -> do+ Win32.failIfFalse_ "GetConsoleMode" (c_GetConsoleMode h mode)+ peek mode++setConsoleMode :: Win32.HANDLE -> Win32.DWORD -> IO ()+setConsoleMode h mode = do+ Win32.failIfFalse_ "SetConsoleMode" (c_SetConsoleMode h mode)++foreign import WINAPI unsafe "windows.h GetConsoleMode" c_GetConsoleMode+ :: Win32.HANDLE -> Ptr Win32.DWORD -> IO Win32.BOOL++foreign import WINAPI unsafe "windows.h SetConsoleMode" c_SetConsoleMode+ :: Win32.HANDLE -> Win32.DWORD -> IO Win32.BOOL++fileNameInfo :: CInt+fileNameInfo = 2++mAX_PATH :: Num a => a+mAX_PATH = 260++getFileNameByHandle :: Win32.HANDLE -> IO String+getFileNameByHandle h = do+ let sizeOfDWORD = sizeOf (undefined :: Win32.DWORD)+ let sizeOfWchar = sizeOf (undefined :: CWchar)+ -- note: implicitly assuming that DWORD has stronger alignment than wchar_t+ let bufSize = sizeOfDWORD + mAX_PATH * sizeOfWchar+ allocaBytes bufSize $ \ buf -> do+ getFileInformationByHandleEx h fileNameInfo buf (fromIntegral bufSize)+ len :: Win32.DWORD <- peek buf+ let len' = fromIntegral len `div` sizeOfWchar+ peekCWStringLen (buf `plusPtr` sizeOfDWORD, min len' mAX_PATH)++getFileInformationByHandleEx+ :: Win32.HANDLE -> CInt -> Ptr a -> Win32.DWORD -> IO ()+getFileInformationByHandleEx h cls buf bufSize = do+ lib <- Win32.getModuleHandle (Just "kernel32.dll")+ ptr <- Win32.getProcAddress lib "GetFileInformationByHandleEx"+ let c_GetFileInformationByHandleEx =+ mk_GetFileInformationByHandleEx (castPtrToFunPtr ptr)+ Win32.failIfFalse_ "getFileInformationByHandleEx"+ (c_GetFileInformationByHandleEx h cls buf bufSize)++type F_GetFileInformationByHandleEx a =+ Win32.HANDLE -> CInt -> Ptr a -> Win32.DWORD -> IO Win32.BOOL++foreign import WINAPI "dynamic"+ mk_GetFileInformationByHandleEx+ :: FunPtr (F_GetFileInformationByHandleEx a)+ -> F_GetFileInformationByHandleEx a++#else+ pure False+#endif
+ main/TidyPgm.hs view
@@ -0,0 +1,1492 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section{Tidying up Core}+-}++{-# LANGUAGE CPP, ViewPatterns #-}++module TidyPgm (+ mkBootModDetailsTc, tidyProgram, globaliseAndTidyId+ ) where++#include "HsVersions.h"++import TcRnTypes+import DynFlags+import CoreSyn+import CoreUnfold+import CoreFVs+import CoreTidy+import CoreMonad+import CorePrep+import CoreUtils (rhsIsStatic)+import CoreStats (coreBindsStats, CoreStats(..))+import CoreSeq (seqBinds)+import CoreLint+import Literal+import Rules+import PatSyn+import ConLike+import CoreArity ( exprArity, exprBotStrictness_maybe )+import StaticPtrTable+import VarEnv+import VarSet+import Var+import Id+import MkId ( mkDictSelRhs )+import IdInfo+import InstEnv+import FamInstEnv+import Type ( tidyTopType )+import Demand ( appIsBottom, isTopSig, isBottomingSig )+import BasicTypes+import Name hiding (varName)+import NameSet+import NameEnv+import NameCache+import Avail+import IfaceEnv+import TcEnv+import TcRnMonad+import DataCon+import TyCon+import Class+import Module+import Packages( isDllName )+import HscTypes+import Maybes+import UniqSupply+import ErrUtils (Severity(..))+import Outputable+import UniqDFM+import SrcLoc+import qualified ErrUtils as Err++import Control.Monad+import Data.Function+import Data.List ( sortBy )+import Data.IORef ( atomicModifyIORef' )++{-+Constructing the TypeEnv, Instances, Rules, VectInfo from which the+ModIface is constructed, and which goes on to subsequent modules in+--make mode.++Most of the interface file is obtained simply by serialising the+TypeEnv. One important consequence is that if the *interface file*+has pragma info if and only if the final TypeEnv does. This is not so+important for *this* module, but it's essential for ghc --make:+subsequent compilations must not see (e.g.) the arity if the interface+file does not contain arity If they do, they'll exploit the arity;+then the arity might change, but the iface file doesn't change =>+recompilation does not happen => disaster.++For data types, the final TypeEnv will have a TyThing for the TyCon,+plus one for each DataCon; the interface file will contain just one+data type declaration, but it is de-serialised back into a collection+of TyThings.++************************************************************************+* *+ Plan A: simpleTidyPgm+* *+************************************************************************+++Plan A: mkBootModDetails: omit pragmas, make interfaces small+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Ignore the bindings++* Drop all WiredIn things from the TypeEnv+ (we never want them in interface files)++* Retain all TyCons and Classes in the TypeEnv, to avoid+ having to find which ones are mentioned in the+ types of exported Ids++* Trim off the constructors of non-exported TyCons, both+ from the TyCon and from the TypeEnv++* Drop non-exported Ids from the TypeEnv++* Tidy the types of the DFunIds of Instances,+ make them into GlobalIds, (they already have External Names)+ and add them to the TypeEnv++* Tidy the types of the (exported) Ids in the TypeEnv,+ make them into GlobalIds (they already have External Names)++* Drop rules altogether++* Tidy the bindings, to ensure that the Caf and Arity+ information is correct for each top-level binder; the+ code generator needs it. And to ensure that local names have+ distinct OccNames in case of object-file splitting++* If this an hsig file, drop the instances altogether too (they'll+ get pulled in by the implicit module import.+-}++-- This is Plan A: make a small type env when typechecking only,+-- or when compiling a hs-boot file, or simply when not using -O+--+-- We don't look at the bindings at all -- there aren't any+-- for hs-boot files++mkBootModDetailsTc :: HscEnv -> TcGblEnv -> IO ModDetails+mkBootModDetailsTc hsc_env+ TcGblEnv{ tcg_exports = exports,+ tcg_type_env = type_env, -- just for the Ids+ tcg_tcs = tcs,+ tcg_patsyns = pat_syns,+ tcg_insts = insts,+ tcg_fam_insts = fam_insts,+ tcg_mod = this_mod+ }+ = -- This timing isn't terribly useful since the result isn't forced, but+ -- the message is useful to locating oneself in the compilation process.+ Err.withTiming (pure dflags)+ (text "CoreTidy"<+>brackets (ppr this_mod))+ (const ()) $+ do { let { insts' = map (tidyClsInstDFun globaliseAndTidyId) insts+ ; pat_syns' = map (tidyPatSynIds globaliseAndTidyId) pat_syns+ ; type_env1 = mkBootTypeEnv (availsToNameSet exports)+ (typeEnvIds type_env) tcs fam_insts+ ; type_env2 = extendTypeEnvWithPatSyns pat_syns' type_env1+ ; dfun_ids = map instanceDFunId insts'+ ; type_env' = extendTypeEnvWithIds type_env2 dfun_ids+ }+ ; return (ModDetails { md_types = type_env'+ , md_insts = insts'+ , md_fam_insts = fam_insts+ , md_rules = []+ , md_anns = []+ , md_exports = exports+ , md_vect_info = noVectInfo+ , md_complete_sigs = []+ })+ }+ where+ dflags = hsc_dflags hsc_env++mkBootTypeEnv :: NameSet -> [Id] -> [TyCon] -> [FamInst] -> TypeEnv+mkBootTypeEnv exports ids tcs fam_insts+ = tidyTypeEnv True $+ typeEnvFromEntities final_ids tcs fam_insts+ where+ -- Find the LocalIds in the type env that are exported+ -- Make them into GlobalIds, and tidy their types+ --+ -- It's very important to remove the non-exported ones+ -- because we don't tidy the OccNames, and if we don't remove+ -- the non-exported ones we'll get many things with the+ -- same name in the interface file, giving chaos.+ --+ -- Do make sure that we keep Ids that are already Global.+ -- When typechecking an .hs-boot file, the Ids come through as+ -- GlobalIds.+ final_ids = [ (if isLocalId id then globaliseAndTidyId id+ else id)+ `setIdUnfolding` BootUnfolding+ | id <- ids+ , keep_it id ]++ -- default methods have their export flag set, but everything+ -- else doesn't (yet), because this is pre-desugaring, so we+ -- must test both.+ keep_it id = isExportedId id || idName id `elemNameSet` exports++++globaliseAndTidyId :: Id -> Id+-- Takes an LocalId with an External Name,+-- makes it into a GlobalId+-- * unchanged Name (might be Internal or External)+-- * unchanged details+-- * VanillaIdInfo (makes a conservative assumption about Caf-hood)+globaliseAndTidyId id+ = Id.setIdType (globaliseId id) tidy_type+ where+ tidy_type = tidyTopType (idType id)++{-+************************************************************************+* *+ Plan B: tidy bindings, make TypeEnv full of IdInfo+* *+************************************************************************++Plan B: include pragmas, make interfaces+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Figure out which Ids are externally visible++* Tidy the bindings, externalising appropriate Ids++* Drop all Ids from the TypeEnv, and add all the External Ids from+ the bindings. (This adds their IdInfo to the TypeEnv; and adds+ floated-out Ids that weren't even in the TypeEnv before.)++Step 1: Figure out external Ids+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note [choosing external names]++See also the section "Interface stability" in the+RecompilationAvoidance commentary:+ http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance++First we figure out which Ids are "external" Ids. An+"external" Id is one that is visible from outside the compilation+unit. These are+ a) the user exported ones+ b) the ones bound to static forms+ c) ones mentioned in the unfoldings, workers,+ rules of externally-visible ones ,+ or vectorised versions of externally-visible ones++While figuring out which Ids are external, we pick a "tidy" OccName+for each one. That is, we make its OccName distinct from the other+external OccNames in this module, so that in interface files and+object code we can refer to it unambiguously by its OccName. The+OccName for each binder is prefixed by the name of the exported Id+that references it; e.g. if "f" references "x" in its unfolding, then+"x" is renamed to "f_x". This helps distinguish the different "x"s+from each other, and means that if "f" is later removed, things that+depend on the other "x"s will not need to be recompiled. Of course,+if there are multiple "f_x"s, then we have to disambiguate somehow; we+use "f_x0", "f_x1" etc.++As far as possible we should assign names in a deterministic fashion.+Each time this module is compiled with the same options, we should end+up with the same set of external names with the same types. That is,+the ABI hash in the interface should not change. This turns out to be+quite tricky, since the order of the bindings going into the tidy+phase is already non-deterministic, as it is based on the ordering of+Uniques, which are assigned unpredictably.++To name things in a stable way, we do a depth-first-search of the+bindings, starting from the exports sorted by name. This way, as long+as the bindings themselves are deterministic (they sometimes aren't!),+the order in which they are presented to the tidying phase does not+affect the names we assign.++Step 2: Tidy the program+~~~~~~~~~~~~~~~~~~~~~~~~+Next we traverse the bindings top to bottom. For each *top-level*+binder++ 1. Make it into a GlobalId; its IdDetails becomes VanillaGlobal,+ reflecting the fact that from now on we regard it as a global,+ not local, Id++ 2. Give it a system-wide Unique.+ [Even non-exported things need system-wide Uniques because the+ byte-code generator builds a single Name->BCO symbol table.]++ We use the NameCache kept in the HscEnv as the+ source of such system-wide uniques.++ For external Ids, use the original-name cache in the NameCache+ to ensure that the unique assigned is the same as the Id had+ in any previous compilation run.++ 3. Rename top-level Ids according to the names we chose in step 1.+ If it's an external Id, make it have a External Name, otherwise+ make it have an Internal Name. This is used by the code generator+ to decide whether to make the label externally visible++ 4. Give it its UTTERLY FINAL IdInfo; in ptic,+ * its unfolding, if it should have one++ * its arity, computed from the number of visible lambdas++ * its CAF info, computed from what is free in its RHS+++Finally, substitute these new top-level binders consistently+throughout, including in unfoldings. We also tidy binders in+RHSs, so that they print nicely in interfaces.+-}++tidyProgram :: HscEnv -> ModGuts -> IO (CgGuts, ModDetails)+tidyProgram hsc_env (ModGuts { mg_module = mod+ , mg_exports = exports+ , mg_rdr_env = rdr_env+ , mg_tcs = tcs+ , mg_insts = cls_insts+ , mg_fam_insts = fam_insts+ , mg_binds = binds+ , mg_patsyns = patsyns+ , mg_rules = imp_rules+ , mg_vect_info = vect_info+ , mg_anns = anns+ , mg_complete_sigs = complete_sigs+ , mg_deps = deps+ , mg_foreign = foreign_stubs+ , mg_foreign_files = foreign_files+ , mg_hpc_info = hpc_info+ , mg_modBreaks = modBreaks+ })++ = Err.withTiming (pure dflags)+ (text "CoreTidy"<+>brackets (ppr mod))+ (const ()) $+ do { let { omit_prags = gopt Opt_OmitInterfacePragmas dflags+ ; expose_all = gopt Opt_ExposeAllUnfoldings dflags+ ; print_unqual = mkPrintUnqualified dflags rdr_env+ }++ ; let { type_env = typeEnvFromEntities [] tcs fam_insts++ ; implicit_binds+ = concatMap getClassImplicitBinds (typeEnvClasses type_env) +++ concatMap getTyConImplicitBinds (typeEnvTyCons type_env)+ }++ ; (unfold_env, tidy_occ_env)+ <- chooseExternalIds hsc_env mod omit_prags expose_all+ binds implicit_binds imp_rules (vectInfoVar vect_info)+ ; let { (trimmed_binds, trimmed_rules)+ = findExternalRules omit_prags binds imp_rules unfold_env }++ ; (tidy_env, tidy_binds)+ <- tidyTopBinds hsc_env mod unfold_env tidy_occ_env trimmed_binds++ ; let { final_ids = [ id | id <- bindersOfBinds tidy_binds,+ isExternalName (idName id)]+ ; type_env1 = extendTypeEnvWithIds type_env final_ids++ ; tidy_cls_insts = map (tidyClsInstDFun (tidyVarOcc tidy_env)) cls_insts+ -- A DFunId will have a binding in tidy_binds, and so will now be in+ -- tidy_type_env, replete with IdInfo. Its name will be unchanged since+ -- it was born, but we want Global, IdInfo-rich (or not) DFunId in the+ -- tidy_cls_insts. Similarly the Ids inside a PatSyn.++ ; tidy_rules = tidyRules tidy_env trimmed_rules+ -- You might worry that the tidy_env contains IdInfo-rich stuff+ -- and indeed it does, but if omit_prags is on, ext_rules is+ -- empty++ ; tidy_vect_info = tidyVectInfo tidy_env vect_info++ -- Tidy the Ids inside each PatSyn, very similarly to DFunIds+ -- and then override the PatSyns in the type_env with the new tidy ones+ -- This is really the only reason we keep mg_patsyns at all; otherwise+ -- they could just stay in type_env+ ; tidy_patsyns = map (tidyPatSynIds (tidyVarOcc tidy_env)) patsyns+ ; type_env2 = extendTypeEnvWithPatSyns tidy_patsyns type_env1++ ; tidy_type_env = tidyTypeEnv omit_prags type_env2+ }+ -- See Note [Grand plan for static forms] in StaticPtrTable.+ ; (spt_entries, tidy_binds') <-+ sptCreateStaticBinds hsc_env mod tidy_binds+ ; let { spt_init_code = sptModuleInitCode mod spt_entries+ ; add_spt_init_code =+ case hscTarget dflags of+ -- If we are compiling for the interpreter we will insert+ -- any necessary SPT entries dynamically+ HscInterpreted -> id+ -- otherwise add a C stub to do so+ _ -> (`appendStubC` spt_init_code)+ }++ ; let { -- See Note [Injecting implicit bindings]+ all_tidy_binds = implicit_binds ++ tidy_binds'++ -- Get the TyCons to generate code for. Careful! We must use+ -- the untidied TypeEnv here, because we need+ -- (a) implicit TyCons arising from types and classes defined+ -- in this module+ -- (b) wired-in TyCons, which are normally removed from the+ -- TypeEnv we put in the ModDetails+ -- (c) Constructors even if they are not exported (the+ -- tidied TypeEnv has trimmed these away)+ ; alg_tycons = filter isAlgTyCon (typeEnvTyCons type_env)+ }++ ; endPassIO hsc_env print_unqual CoreTidy all_tidy_binds tidy_rules++ -- If the endPass didn't print the rules, but ddump-rules is+ -- on, print now+ ; unless (dopt Opt_D_dump_simpl dflags) $+ Err.dumpIfSet_dyn dflags Opt_D_dump_rules+ (showSDoc dflags (ppr CoreTidy <+> text "rules"))+ (pprRulesForUser dflags tidy_rules)++ -- Print one-line size info+ ; let cs = coreBindsStats tidy_binds+ ; when (dopt Opt_D_dump_core_stats dflags)+ (putLogMsg dflags NoReason SevDump noSrcSpan+ (defaultDumpStyle dflags)+ (text "Tidy size (terms,types,coercions)"+ <+> ppr (moduleName mod) <> colon+ <+> int (cs_tm cs)+ <+> int (cs_ty cs)+ <+> int (cs_co cs) ))++ ; return (CgGuts { cg_module = mod,+ cg_tycons = alg_tycons,+ cg_binds = all_tidy_binds,+ cg_foreign = add_spt_init_code foreign_stubs,+ cg_foreign_files = foreign_files,+ cg_dep_pkgs = map fst $ dep_pkgs deps,+ cg_hpc_info = hpc_info,+ cg_modBreaks = modBreaks,+ cg_spt_entries = spt_entries },++ ModDetails { md_types = tidy_type_env,+ md_rules = tidy_rules,+ md_insts = tidy_cls_insts,+ md_vect_info = tidy_vect_info,+ md_fam_insts = fam_insts,+ md_exports = exports,+ md_anns = anns, -- are already tidy+ md_complete_sigs = complete_sigs+ })+ }+ where+ dflags = hsc_dflags hsc_env++tidyTypeEnv :: Bool -- Compiling without -O, so omit prags+ -> TypeEnv -> TypeEnv++-- The competed type environment is gotten from+-- a) the types and classes defined here (plus implicit things)+-- b) adding Ids with correct IdInfo, including unfoldings,+-- gotten from the bindings+-- From (b) we keep only those Ids with External names;+-- the CoreTidy pass makes sure these are all and only+-- the externally-accessible ones+-- This truncates the type environment to include only the+-- exported Ids and things needed from them, which saves space+--+-- See Note [Don't attempt to trim data types]++tidyTypeEnv omit_prags type_env+ = let+ type_env1 = filterNameEnv (not . isWiredInName . getName) type_env+ -- (1) remove wired-in things+ type_env2 | omit_prags = mapNameEnv trimThing type_env1+ | otherwise = type_env1+ -- (2) trimmed if necessary+ in+ type_env2++--------------------------+trimThing :: TyThing -> TyThing+-- Trim off inessentials, for boot files and no -O+trimThing (AnId id)+ | not (isImplicitId id)+ = AnId (id `setIdInfo` vanillaIdInfo)++trimThing other_thing+ = other_thing++extendTypeEnvWithPatSyns :: [PatSyn] -> TypeEnv -> TypeEnv+extendTypeEnvWithPatSyns tidy_patsyns type_env+ = extendTypeEnvList type_env [AConLike (PatSynCon ps) | ps <- tidy_patsyns ]++tidyVectInfo :: TidyEnv -> VectInfo -> VectInfo+tidyVectInfo (_, var_env) info@(VectInfo { vectInfoVar = vars+ , vectInfoParallelVars = parallelVars+ })+ = info { vectInfoVar = tidy_vars+ , vectInfoParallelVars = tidy_parallelVars+ }+ where+ -- we only export mappings whose domain and co-domain is exported (otherwise, the iface is+ -- inconsistent)+ tidy_vars = mkDVarEnv [ (tidy_var, (tidy_var, tidy_var_v))+ | (var, var_v) <- eltsUDFM vars+ , let tidy_var = lookup_var var+ tidy_var_v = lookup_var var_v+ , isExternalId tidy_var && isExportedId tidy_var+ , isExternalId tidy_var_v && isExportedId tidy_var_v+ , isDataConWorkId var || not (isImplicitId var)+ ]++ tidy_parallelVars = mkDVarSet+ [ tidy_var+ | var <- dVarSetElems parallelVars+ , let tidy_var = lookup_var var+ , isExternalId tidy_var && isExportedId tidy_var+ ]++ lookup_var var = lookupWithDefaultVarEnv var_env var var++ -- We need to make sure that all names getting into the iface version of 'VectInfo' are+ -- external; otherwise, 'MkIface' will bomb out.+ isExternalId = isExternalName . idName++{-+Note [Don't attempt to trim data types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For some time GHC tried to avoid exporting the data constructors+of a data type if it wasn't strictly necessary to do so; see Trac #835.+But "strictly necessary" accumulated a longer and longer list+of exceptions, and finally I gave up the battle:++ commit 9a20e540754fc2af74c2e7392f2786a81d8d5f11+ Author: Simon Peyton Jones <simonpj@microsoft.com>+ Date: Thu Dec 6 16:03:16 2012 +0000++ Stop attempting to "trim" data types in interface files++ Without -O, we previously tried to make interface files smaller+ by not including the data constructors of data types. But+ there are a lot of exceptions, notably when Template Haskell is+ involved or, more recently, DataKinds.++ However Trac #7445 shows that even without TemplateHaskell, using+ the Data class and invoking Language.Haskell.TH.Quote.dataToExpQ+ is enough to require us to expose the data constructors.++ So I've given up on this "optimisation" -- it's probably not+ important anyway. Now I'm simply not attempting to trim off+ the data constructors. The gain in simplicity is worth the+ modest cost in interface file growth, which is limited to the+ bits reqd to describe those data constructors.++************************************************************************+* *+ Implicit bindings+* *+************************************************************************++Note [Injecting implicit bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We inject the implicit bindings right at the end, in CoreTidy.+Some of these bindings, notably record selectors, are not+constructed in an optimised form. E.g. record selector for+ data T = MkT { x :: {-# UNPACK #-} !Int }+Then the unfolding looks like+ x = \t. case t of MkT x1 -> let x = I# x1 in x+This generates bad code unless it's first simplified a bit. That is+why CoreUnfold.mkImplicitUnfolding uses simpleOptExpr to do a bit of+optimisation first. (Only matters when the selector is used curried;+eg map x ys.) See Trac #2070.++[Oct 09: in fact, record selectors are no longer implicit Ids at all,+because we really do want to optimise them properly. They are treated+much like any other Id. But doing "light" optimisation on an implicit+Id still makes sense.]++At one time I tried injecting the implicit bindings *early*, at the+beginning of SimplCore. But that gave rise to real difficulty,+because GlobalIds are supposed to have *fixed* IdInfo, but the+simplifier and other core-to-core passes mess with IdInfo all the+time. The straw that broke the camels back was when a class selector+got the wrong arity -- ie the simplifier gave it arity 2, whereas+importing modules were expecting it to have arity 1 (Trac #2844).+It's much safer just to inject them right at the end, after tidying.++Oh: two other reasons for injecting them late:++ - If implicit Ids are already in the bindings when we start TidyPgm,+ we'd have to be careful not to treat them as external Ids (in+ the sense of chooseExternalIds); else the Ids mentioned in *their*+ RHSs will be treated as external and you get an interface file+ saying a18 = <blah>+ but nothing referring to a18 (because the implicit Id is the+ one that does, and implicit Ids don't appear in interface files).++ - More seriously, the tidied type-envt will include the implicit+ Id replete with a18 in its unfolding; but we won't take account+ of a18 when computing a fingerprint for the class; result chaos.++There is one sort of implicit binding that is injected still later,+namely those for data constructor workers. Reason (I think): it's+really just a code generation trick.... binding itself makes no sense.+See Note [Data constructor workers] in CorePrep.+-}++getTyConImplicitBinds :: TyCon -> [CoreBind]+getTyConImplicitBinds tc = map get_defn (mapMaybe dataConWrapId_maybe (tyConDataCons tc))++getClassImplicitBinds :: Class -> [CoreBind]+getClassImplicitBinds cls+ = [ NonRec op (mkDictSelRhs cls val_index)+ | (op, val_index) <- classAllSelIds cls `zip` [0..] ]++get_defn :: Id -> CoreBind+get_defn id = NonRec id (unfoldingTemplate (realIdUnfolding id))++{-+************************************************************************+* *+\subsection{Step 1: finding externals}+* *+************************************************************************++See Note [Choosing external names].+-}++type UnfoldEnv = IdEnv (Name{-new name-}, Bool {-show unfolding-})+ -- Maps each top-level Id to its new Name (the Id is tidied in step 2)+ -- The Unique is unchanged. If the new Name is external, it will be+ -- visible in the interface file.+ --+ -- Bool => expose unfolding or not.++chooseExternalIds :: HscEnv+ -> Module+ -> Bool -> Bool+ -> [CoreBind]+ -> [CoreBind]+ -> [CoreRule]+ -> DVarEnv (Var, Var)+ -> IO (UnfoldEnv, TidyOccEnv)+ -- Step 1 from the notes above++chooseExternalIds hsc_env mod omit_prags expose_all binds implicit_binds imp_id_rules vect_vars+ = do { (unfold_env1,occ_env1) <- search init_work_list emptyVarEnv init_occ_env+ ; let internal_ids = filter (not . (`elemVarEnv` unfold_env1)) binders+ ; tidy_internal internal_ids unfold_env1 occ_env1 }+ where+ nc_var = hsc_NC hsc_env++ -- init_ext_ids is the intial list of Ids that should be+ -- externalised. It serves as the starting point for finding a+ -- deterministic, tidy, renaming for all external Ids in this+ -- module.+ --+ -- It is sorted, so that it has adeterministic order (i.e. it's the+ -- same list every time this module is compiled), in contrast to the+ -- bindings, which are ordered non-deterministically.+ init_work_list = zip init_ext_ids init_ext_ids+ init_ext_ids = sortBy (compare `on` getOccName) $ filter is_external binders++ -- An Id should be external if either (a) it is exported,+ -- (b) it appears in the RHS of a local rule for an imported Id, or+ -- (c) it is the vectorised version of an imported Id.+ -- See Note [Which rules to expose]+ is_external id = isExportedId id || id `elemVarSet` rule_rhs_vars+ || id `elemVarSet` vect_var_vs++ rule_rhs_vars = mapUnionVarSet ruleRhsFreeVars imp_id_rules+ vect_var_vs = mkVarSet [var_v | (var, var_v) <- eltsUDFM vect_vars, isGlobalId var]++ binders = map fst $ flattenBinds binds+ implicit_binders = bindersOfBinds implicit_binds+ binder_set = mkVarSet binders++ avoids = [getOccName name | bndr <- binders ++ implicit_binders,+ let name = idName bndr,+ isExternalName name ]+ -- In computing our "avoids" list, we must include+ -- all implicit Ids+ -- all things with global names (assigned once and for+ -- all by the renamer)+ -- since their names are "taken".+ -- The type environment is a convenient source of such things.+ -- In particular, the set of binders doesn't include+ -- implicit Ids at this stage.++ -- We also make sure to avoid any exported binders. Consider+ -- f{-u1-} = 1 -- Local decl+ -- ...+ -- f{-u2-} = 2 -- Exported decl+ --+ -- The second exported decl must 'get' the name 'f', so we+ -- have to put 'f' in the avoids list before we get to the first+ -- decl. tidyTopId then does a no-op on exported binders.+ init_occ_env = initTidyOccEnv avoids+++ search :: [(Id,Id)] -- The work-list: (external id, referring id)+ -- Make a tidy, external Name for the external id,+ -- add it to the UnfoldEnv, and do the same for the+ -- transitive closure of Ids it refers to+ -- The referring id is used to generate a tidy+ --- name for the external id+ -> UnfoldEnv -- id -> (new Name, show_unfold)+ -> TidyOccEnv -- occ env for choosing new Names+ -> IO (UnfoldEnv, TidyOccEnv)++ search [] unfold_env occ_env = return (unfold_env, occ_env)++ search ((idocc,referrer) : rest) unfold_env occ_env+ | idocc `elemVarEnv` unfold_env = search rest unfold_env occ_env+ | otherwise = do+ (occ_env', name') <- tidyTopName mod nc_var (Just referrer) occ_env idocc+ let+ (new_ids, show_unfold)+ | omit_prags = ([], False)+ | otherwise = addExternal expose_all refined_id++ -- add vectorised version if any exists+ new_ids' = new_ids ++ maybeToList (fmap snd $ lookupDVarEnv vect_vars idocc)++ -- 'idocc' is an *occurrence*, but we need to see the+ -- unfolding in the *definition*; so look up in binder_set+ refined_id = case lookupVarSet binder_set idocc of+ Just id -> id+ Nothing -> WARN( True, ppr idocc ) idocc++ unfold_env' = extendVarEnv unfold_env idocc (name',show_unfold)+ referrer' | isExportedId refined_id = refined_id+ | otherwise = referrer+ --+ search (zip new_ids' (repeat referrer') ++ rest) unfold_env' occ_env'++ tidy_internal :: [Id] -> UnfoldEnv -> TidyOccEnv+ -> IO (UnfoldEnv, TidyOccEnv)+ tidy_internal [] unfold_env occ_env = return (unfold_env,occ_env)+ tidy_internal (id:ids) unfold_env occ_env = do+ (occ_env', name') <- tidyTopName mod nc_var Nothing occ_env id+ let unfold_env' = extendVarEnv unfold_env id (name',False)+ tidy_internal ids unfold_env' occ_env'++addExternal :: Bool -> Id -> ([Id], Bool)+addExternal expose_all id = (new_needed_ids, show_unfold)+ where+ new_needed_ids = bndrFvsInOrder show_unfold id+ idinfo = idInfo id+ show_unfold = show_unfolding (unfoldingInfo idinfo)+ never_active = isNeverActive (inlinePragmaActivation (inlinePragInfo idinfo))+ loop_breaker = isStrongLoopBreaker (occInfo idinfo)+ bottoming_fn = isBottomingSig (strictnessInfo idinfo)++ -- Stuff to do with the Id's unfolding+ -- We leave the unfolding there even if there is a worker+ -- In GHCi the unfolding is used by importers++ show_unfolding (CoreUnfolding { uf_src = src, uf_guidance = guidance })+ = expose_all -- 'expose_all' says to expose all+ -- unfoldings willy-nilly++ || isStableSource src -- Always expose things whose+ -- source is an inline rule++ || not (bottoming_fn -- No need to inline bottom functions+ || never_active -- Or ones that say not to+ || loop_breaker -- Or that are loop breakers+ || neverUnfoldGuidance guidance)+ show_unfolding (DFunUnfolding {}) = True+ show_unfolding _ = False++{-+************************************************************************+* *+ Deterministic free variables+* *+************************************************************************++We want a deterministic free-variable list. exprFreeVars gives us+a VarSet, which is in a non-deterministic order when converted to a+list. Hence, here we define a free-variable finder that returns+the free variables in the order that they are encountered.++See Note [Choosing external names]+-}++bndrFvsInOrder :: Bool -> Id -> [Id]+bndrFvsInOrder show_unfold id+ = run (dffvLetBndr show_unfold id)++run :: DFFV () -> [Id]+run (DFFV m) = case m emptyVarSet (emptyVarSet, []) of+ ((_,ids),_) -> ids++newtype DFFV a+ = DFFV (VarSet -- Envt: non-top-level things that are in scope+ -- we don't want to record these as free vars+ -> (VarSet, [Var]) -- Input State: (set, list) of free vars so far+ -> ((VarSet,[Var]),a)) -- Output state++instance Functor DFFV where+ fmap = liftM++instance Applicative DFFV where+ pure a = DFFV $ \_ st -> (st, a)+ (<*>) = ap++instance Monad DFFV where+ (DFFV m) >>= k = DFFV $ \env st ->+ case m env st of+ (st',a) -> case k a of+ DFFV f -> f env st'++extendScope :: Var -> DFFV a -> DFFV a+extendScope v (DFFV f) = DFFV (\env st -> f (extendVarSet env v) st)++extendScopeList :: [Var] -> DFFV a -> DFFV a+extendScopeList vs (DFFV f) = DFFV (\env st -> f (extendVarSetList env vs) st)++insert :: Var -> DFFV ()+insert v = DFFV $ \ env (set, ids) ->+ let keep_me = isLocalId v &&+ not (v `elemVarSet` env) &&+ not (v `elemVarSet` set)+ in if keep_me+ then ((extendVarSet set v, v:ids), ())+ else ((set, ids), ())+++dffvExpr :: CoreExpr -> DFFV ()+dffvExpr (Var v) = insert v+dffvExpr (App e1 e2) = dffvExpr e1 >> dffvExpr e2+dffvExpr (Lam v e) = extendScope v (dffvExpr e)+dffvExpr (Tick (Breakpoint _ ids) e) = mapM_ insert ids >> dffvExpr e+dffvExpr (Tick _other e) = dffvExpr e+dffvExpr (Cast e _) = dffvExpr e+dffvExpr (Let (NonRec x r) e) = dffvBind (x,r) >> extendScope x (dffvExpr e)+dffvExpr (Let (Rec prs) e) = extendScopeList (map fst prs) $+ (mapM_ dffvBind prs >> dffvExpr e)+dffvExpr (Case e b _ as) = dffvExpr e >> extendScope b (mapM_ dffvAlt as)+dffvExpr _other = return ()++dffvAlt :: (t, [Var], CoreExpr) -> DFFV ()+dffvAlt (_,xs,r) = extendScopeList xs (dffvExpr r)++dffvBind :: (Id, CoreExpr) -> DFFV ()+dffvBind(x,r)+ | not (isId x) = dffvExpr r+ | otherwise = dffvLetBndr False x >> dffvExpr r+ -- Pass False because we are doing the RHS right here+ -- If you say True you'll get *exponential* behaviour!++dffvLetBndr :: Bool -> Id -> DFFV ()+-- Gather the free vars of the RULES and unfolding of a binder+-- We always get the free vars of a *stable* unfolding, but+-- for a *vanilla* one (InlineRhs), the flag controls what happens:+-- True <=> get fvs of even a *vanilla* unfolding+-- False <=> ignore an InlineRhs+-- For nested bindings (call from dffvBind) we always say "False" because+-- we are taking the fvs of the RHS anyway+-- For top-level bindings (call from addExternal, via bndrFvsInOrder)+-- we say "True" if we are exposing that unfolding+dffvLetBndr vanilla_unfold id+ = do { go_unf (unfoldingInfo idinfo)+ ; mapM_ go_rule (ruleInfoRules (ruleInfo idinfo)) }+ where+ idinfo = idInfo id++ go_unf (CoreUnfolding { uf_tmpl = rhs, uf_src = src })+ = case src of+ InlineRhs | vanilla_unfold -> dffvExpr rhs+ | otherwise -> return ()+ _ -> dffvExpr rhs++ go_unf (DFunUnfolding { df_bndrs = bndrs, df_args = args })+ = extendScopeList bndrs $ mapM_ dffvExpr args+ go_unf _ = return ()++ go_rule (BuiltinRule {}) = return ()+ go_rule (Rule { ru_bndrs = bndrs, ru_rhs = rhs })+ = extendScopeList bndrs (dffvExpr rhs)++{-+************************************************************************+* *+ findExternalRules+* *+************************************************************************++Note [Finding external rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The complete rules are gotten by combining+ a) local rules for imported Ids+ b) rules embedded in the top-level Ids++There are two complications:+ * Note [Which rules to expose]+ * Note [Trimming auto-rules]++Note [Which rules to expose]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The function 'expose_rule' filters out rules that mention, on the LHS,+Ids that aren't externally visible; these rules can't fire in a client+module.++The externally-visible binders are computed (by chooseExternalIds)+assuming that all orphan rules are externalised (see init_ext_ids in+function 'search'). So in fact it's a bit conservative and we may+export more than we need. (It's a sort of mutual recursion.)++Note [Trimming auto-rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Second, with auto-specialisation we may specialise local or imported+dfuns or INLINE functions, and then later inline them. That may leave+behind something like+ RULE "foo" forall d. f @ Int d = f_spec+where f is either local or imported, and there is no remaining+reference to f_spec except from the RULE.++Now that RULE *might* be useful to an importing module, but that is+purely speculative, and meanwhile the code is taking up space and+codegen time. I found that binary sizes jumped by 6-10% when I+started to specialise INLINE functions (again, Note [Inline+specialisations] in Specialise).++So it seems better to drop the binding for f_spec, and the rule+itself, if the auto-generated rule is the *only* reason that it is+being kept alive.++(The RULE still might have been useful in the past; that is, it was+the right thing to have generated it in the first place. See Note+[Inline specialisations] in Specialise. But now it has served its+purpose, and can be discarded.)++So findExternalRules does this:+ * Remove all bindings that are kept alive *only* by isAutoRule rules+ (this is done in trim_binds)+ * Remove all auto rules that mention bindings that have been removed+ (this is done by filtering by keep_rule)++NB: if a binding is kept alive for some *other* reason (e.g. f_spec is+called in the final code), we keep the rule too.++This stuff is the only reason for the ru_auto field in a Rule.+-}++findExternalRules :: Bool -- Omit pragmas+ -> [CoreBind]+ -> [CoreRule] -- Local rules for imported fns+ -> UnfoldEnv -- Ids that are exported, so we need their rules+ -> ([CoreBind], [CoreRule])+-- See Note [Finding external rules]+findExternalRules omit_prags binds imp_id_rules unfold_env+ = (trimmed_binds, filter keep_rule all_rules)+ where+ imp_rules = filter expose_rule imp_id_rules+ imp_user_rule_fvs = mapUnionVarSet user_rule_rhs_fvs imp_rules++ user_rule_rhs_fvs rule | isAutoRule rule = emptyVarSet+ | otherwise = ruleRhsFreeVars rule++ (trimmed_binds, local_bndrs, _, all_rules) = trim_binds binds++ keep_rule rule = ruleFreeVars rule `subVarSet` local_bndrs+ -- Remove rules that make no sense, because they mention a+ -- local binder (on LHS or RHS) that we have now discarded.+ -- (NB: ruleFreeVars only includes LocalIds)+ --+ -- LHS: we have already filtered out rules that mention internal Ids+ -- on LHS but that isn't enough because we might have by now+ -- discarded a binding with an external Id. (How?+ -- chooseExternalIds is a bit conservative.)+ --+ -- RHS: the auto rules that might mention a binder that has+ -- been discarded; see Note [Trimming auto-rules]++ expose_rule rule+ | omit_prags = False+ | otherwise = all is_external_id (ruleLhsFreeIdsList rule)+ -- Don't expose a rule whose LHS mentions a locally-defined+ -- Id that is completely internal (i.e. not visible to an+ -- importing module). NB: ruleLhsFreeIds only returns LocalIds.+ -- See Note [Which rules to expose]++ is_external_id id = case lookupVarEnv unfold_env id of+ Just (name, _) -> isExternalName name+ Nothing -> False++ trim_binds :: [CoreBind]+ -> ( [CoreBind] -- Trimmed bindings+ , VarSet -- Binders of those bindings+ , VarSet -- Free vars of those bindings + rhs of user rules+ -- (we don't bother to delete the binders)+ , [CoreRule]) -- All rules, imported + from the bindings+ -- This function removes unnecessary bindings, and gathers up rules from+ -- the bindings we keep. See Note [Trimming auto-rules]+ trim_binds [] -- Base case, start with imp_user_rule_fvs+ = ([], emptyVarSet, imp_user_rule_fvs, imp_rules)++ trim_binds (bind:binds)+ | any needed bndrs -- Keep binding+ = ( bind : binds', bndr_set', needed_fvs', local_rules ++ rules )+ | otherwise -- Discard binding altogether+ = stuff+ where+ stuff@(binds', bndr_set, needed_fvs, rules)+ = trim_binds binds+ needed bndr = isExportedId bndr || bndr `elemVarSet` needed_fvs++ bndrs = bindersOf bind+ rhss = rhssOfBind bind+ bndr_set' = bndr_set `extendVarSetList` bndrs++ needed_fvs' = needed_fvs `unionVarSet`+ mapUnionVarSet idUnfoldingVars bndrs `unionVarSet`+ -- Ignore type variables in the type of bndrs+ mapUnionVarSet exprFreeVars rhss `unionVarSet`+ mapUnionVarSet user_rule_rhs_fvs local_rules+ -- In needed_fvs', we don't bother to delete binders from the fv set++ local_rules = [ rule+ | id <- bndrs+ , is_external_id id -- Only collect rules for external Ids+ , rule <- idCoreRules id+ , expose_rule rule ] -- and ones that can fire in a client++{-+************************************************************************+* *+ tidyTopName+* *+************************************************************************++This is where we set names to local/global based on whether they really are+externally visible (see comment at the top of this module). If the name+was previously local, we have to give it a unique occurrence name if+we intend to externalise it.+-}++tidyTopName :: Module -> IORef NameCache -> Maybe Id -> TidyOccEnv+ -> Id -> IO (TidyOccEnv, Name)+tidyTopName mod nc_var maybe_ref occ_env id+ | global && internal = return (occ_env, localiseName name)++ | global && external = return (occ_env, name)+ -- Global names are assumed to have been allocated by the renamer,+ -- so they already have the "right" unique+ -- And it's a system-wide unique too++ -- Now we get to the real reason that all this is in the IO Monad:+ -- we have to update the name cache in a nice atomic fashion++ | local && internal = do { new_local_name <- atomicModifyIORef' nc_var mk_new_local+ ; return (occ_env', new_local_name) }+ -- Even local, internal names must get a unique occurrence, because+ -- if we do -split-objs we externalise the name later, in the code generator+ --+ -- Similarly, we must make sure it has a system-wide Unique, because+ -- the byte-code generator builds a system-wide Name->BCO symbol table++ | local && external = do { new_external_name <- atomicModifyIORef' nc_var mk_new_external+ ; return (occ_env', new_external_name) }++ | otherwise = panic "tidyTopName"+ where+ name = idName id+ external = isJust maybe_ref+ global = isExternalName name+ local = not global+ internal = not external+ loc = nameSrcSpan name++ old_occ = nameOccName name+ new_occ | Just ref <- maybe_ref+ , ref /= id+ = mkOccName (occNameSpace old_occ) $+ let+ ref_str = occNameString (getOccName ref)+ occ_str = occNameString old_occ+ in+ case occ_str of+ '$':'w':_ -> occ_str+ -- workers: the worker for a function already+ -- includes the occname for its parent, so there's+ -- no need to prepend the referrer.+ _other | isSystemName name -> ref_str+ | otherwise -> ref_str ++ '_' : occ_str+ -- If this name was system-generated, then don't bother+ -- to retain its OccName, just use the referrer. These+ -- system-generated names will become "f1", "f2", etc. for+ -- a referrer "f".+ | otherwise = old_occ++ (occ_env', occ') = tidyOccName occ_env new_occ++ mk_new_local nc = (nc { nsUniqs = us }, mkInternalName uniq occ' loc)+ where+ (uniq, us) = takeUniqFromSupply (nsUniqs nc)++ mk_new_external nc = allocateGlobalBinder nc mod occ' loc+ -- If we want to externalise a currently-local name, check+ -- whether we have already assigned a unique for it.+ -- If so, use it; if not, extend the table.+ -- All this is done by allcoateGlobalBinder.+ -- This is needed when *re*-compiling a module in GHCi; we must+ -- use the same name for externally-visible things as we did before.++{-+************************************************************************+* *+\subsection{Step 2: top-level tidying}+* *+************************************************************************+-}++-- TopTidyEnv: when tidying we need to know+-- * nc_var: The NameCache, containing a unique supply and any pre-ordained Names.+-- These may have arisen because the+-- renamer read in an interface file mentioning M.$wf, say,+-- and assigned it unique r77. If, on this compilation, we've+-- invented an Id whose name is $wf (but with a different unique)+-- we want to rename it to have unique r77, so that we can do easy+-- comparisons with stuff from the interface file+--+-- * occ_env: The TidyOccEnv, which tells us which local occurrences+-- are 'used'+--+-- * subst_env: A Var->Var mapping that substitutes the new Var for the old++tidyTopBinds :: HscEnv+ -> Module+ -> UnfoldEnv+ -> TidyOccEnv+ -> CoreProgram+ -> IO (TidyEnv, CoreProgram)++tidyTopBinds hsc_env this_mod unfold_env init_occ_env binds+ = do mkIntegerId <- lookupMkIntegerName dflags hsc_env+ integerSDataCon <- lookupIntegerSDataConName dflags hsc_env+ let cvt_integer = cvtLitInteger dflags mkIntegerId integerSDataCon+ result = tidy cvt_integer init_env binds+ seqBinds (snd result) `seq` return result+ -- This seqBinds avoids a spike in space usage (see #13564)+ where+ dflags = hsc_dflags hsc_env++ init_env = (init_occ_env, emptyVarEnv)++ tidy _ env [] = (env, [])+ tidy cvt_integer env (b:bs)+ = let (env1, b') = tidyTopBind dflags this_mod+ cvt_integer unfold_env env b+ (env2, bs') = tidy cvt_integer env1 bs+ in (env2, b':bs')++------------------------+tidyTopBind :: DynFlags+ -> Module+ -> (Integer -> CoreExpr)+ -> UnfoldEnv+ -> TidyEnv+ -> CoreBind+ -> (TidyEnv, CoreBind)++tidyTopBind dflags this_mod cvt_integer unfold_env+ (occ_env,subst1) (NonRec bndr rhs)+ = (tidy_env2, NonRec bndr' rhs')+ where+ Just (name',show_unfold) = lookupVarEnv unfold_env bndr+ caf_info = hasCafRefs dflags this_mod (subst1, cvt_integer)+ (idArity bndr) rhs+ (bndr', rhs') = tidyTopPair dflags show_unfold tidy_env2 caf_info name'+ (bndr, rhs)+ subst2 = extendVarEnv subst1 bndr bndr'+ tidy_env2 = (occ_env, subst2)++tidyTopBind dflags this_mod cvt_integer unfold_env+ (occ_env, subst1) (Rec prs)+ = (tidy_env2, Rec prs')+ where+ prs' = [ tidyTopPair dflags show_unfold tidy_env2 caf_info name' (id,rhs)+ | (id,rhs) <- prs,+ let (name',show_unfold) =+ expectJust "tidyTopBind" $ lookupVarEnv unfold_env id+ ]++ subst2 = extendVarEnvList subst1 (bndrs `zip` map fst prs')+ tidy_env2 = (occ_env, subst2)++ bndrs = map fst prs++ -- the CafInfo for a recursive group says whether *any* rhs in+ -- the group may refer indirectly to a CAF (because then, they all do).+ caf_info+ | or [ mayHaveCafRefs (hasCafRefs dflags this_mod+ (subst1, cvt_integer)+ (idArity bndr) rhs)+ | (bndr,rhs) <- prs ] = MayHaveCafRefs+ | otherwise = NoCafRefs++-----------------------------------------------------------+tidyTopPair :: DynFlags+ -> Bool -- show unfolding+ -> TidyEnv -- The TidyEnv is used to tidy the IdInfo+ -- It is knot-tied: don't look at it!+ -> CafInfo+ -> Name -- New name+ -> (Id, CoreExpr) -- Binder and RHS before tidying+ -> (Id, CoreExpr)+ -- This function is the heart of Step 2+ -- The rec_tidy_env is the one to use for the IdInfo+ -- It's necessary because when we are dealing with a recursive+ -- group, a variable late in the group might be mentioned+ -- in the IdInfo of one early in the group++tidyTopPair dflags show_unfold rhs_tidy_env caf_info name' (bndr, rhs)+ = (bndr1, rhs1)+ where+ bndr1 = mkGlobalId details name' ty' idinfo'+ details = idDetails bndr -- Preserve the IdDetails+ ty' = tidyTopType (idType bndr)+ rhs1 = tidyExpr rhs_tidy_env rhs+ idinfo' = tidyTopIdInfo dflags rhs_tidy_env name' rhs rhs1 (idInfo bndr)+ show_unfold caf_info++-- tidyTopIdInfo creates the final IdInfo for top-level+-- binders. There are two delicate pieces:+--+-- * Arity. After CoreTidy, this arity must not change any more.+-- Indeed, CorePrep must eta expand where necessary to make+-- the manifest arity equal to the claimed arity.+--+-- * CAF info. This must also remain valid through to code generation.+-- We add the info here so that it propagates to all+-- occurrences of the binders in RHSs, and hence to occurrences in+-- unfoldings, which are inside Ids imported by GHCi. Ditto RULES.+-- CoreToStg makes use of this when constructing SRTs.+tidyTopIdInfo :: DynFlags -> TidyEnv -> Name -> CoreExpr -> CoreExpr+ -> IdInfo -> Bool -> CafInfo -> IdInfo+tidyTopIdInfo dflags rhs_tidy_env name orig_rhs tidy_rhs idinfo show_unfold caf_info+ | not is_external -- For internal Ids (not externally visible)+ = vanillaIdInfo -- we only need enough info for code generation+ -- Arity and strictness info are enough;+ -- c.f. CoreTidy.tidyLetBndr+ `setCafInfo` caf_info+ `setArityInfo` arity+ `setStrictnessInfo` final_sig++ | otherwise -- Externally-visible Ids get the whole lot+ = vanillaIdInfo+ `setCafInfo` caf_info+ `setArityInfo` arity+ `setStrictnessInfo` final_sig+ `setOccInfo` robust_occ_info+ `setInlinePragInfo` (inlinePragInfo idinfo)+ `setUnfoldingInfo` unfold_info+ -- NB: we throw away the Rules+ -- They have already been extracted by findExternalRules+ where+ is_external = isExternalName name++ --------- OccInfo ------------+ robust_occ_info = zapFragileOcc (occInfo idinfo)+ -- It's important to keep loop-breaker information+ -- when we are doing -fexpose-all-unfoldings++ --------- Strictness ------------+ mb_bot_str = exprBotStrictness_maybe orig_rhs++ sig = strictnessInfo idinfo+ final_sig | not $ isTopSig sig+ = WARN( _bottom_hidden sig , ppr name ) sig+ -- try a cheap-and-cheerful bottom analyser+ | Just (_, nsig) <- mb_bot_str = nsig+ | otherwise = sig++ _bottom_hidden id_sig = case mb_bot_str of+ Nothing -> False+ Just (arity, _) -> not (appIsBottom id_sig arity)++ --------- Unfolding ------------+ unf_info = unfoldingInfo idinfo+ unfold_info | show_unfold = tidyUnfolding rhs_tidy_env unf_info unf_from_rhs+ | otherwise = noUnfolding+ unf_from_rhs = mkTopUnfolding dflags is_bot tidy_rhs+ is_bot = isBottomingSig final_sig+ -- NB: do *not* expose the worker if show_unfold is off,+ -- because that means this thing is a loop breaker or+ -- marked NOINLINE or something like that+ -- This is important: if you expose the worker for a loop-breaker+ -- then you can make the simplifier go into an infinite loop, because+ -- in effect the unfolding is exposed. See Trac #1709+ --+ -- You might think that if show_unfold is False, then the thing should+ -- not be w/w'd in the first place. But a legitimate reason is this:+ -- the function returns bottom+ -- In this case, show_unfold will be false (we don't expose unfoldings+ -- for bottoming functions), but we might still have a worker/wrapper+ -- split (see Note [Worker-wrapper for bottoming functions] in WorkWrap.hs++ --------- Arity ------------+ -- Usually the Id will have an accurate arity on it, because+ -- the simplifier has just run, but not always.+ -- One case I found was when the last thing the simplifier+ -- did was to let-bind a non-atomic argument and then float+ -- it to the top level. So it seems more robust just to+ -- fix it here.+ arity = exprArity orig_rhs++{-+************************************************************************+* *+ Figuring out CafInfo for an expression+* *+************************************************************************++hasCafRefs decides whether a top-level closure can point into the dynamic heap.+We mark such things as `MayHaveCafRefs' because this information is+used to decide whether a particular closure needs to be referenced+in an SRT or not.++There are two reasons for setting MayHaveCafRefs:+ a) The RHS is a CAF: a top-level updatable thunk.+ b) The RHS refers to something that MayHaveCafRefs++Possible improvement: In an effort to keep the number of CAFs (and+hence the size of the SRTs) down, we could also look at the expression and+decide whether it requires a small bounded amount of heap, so we can ignore+it as a CAF. In these cases however, we would need to use an additional+CAF list to keep track of non-collectable CAFs.++Note [Disgusting computation of CafRefs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We compute hasCafRefs here, because IdInfo is supposed to be finalised+after TidyPgm. But CorePrep does some transformations that affect CAF-hood.+So we have to *predict* the result here, which is revolting.++In particular CorePrep expands Integer literals. So in the prediction code+here we resort to applying the same expansion (cvt_integer). Ugh!+-}++type CafRefEnv = (VarEnv Id, Integer -> CoreExpr)+ -- The env finds the Caf-ness of the Id+ -- The Integer -> CoreExpr is the desugaring function for Integer literals+ -- See Note [Disgusting computation of CafRefs]++hasCafRefs :: DynFlags -> Module+ -> CafRefEnv -> Arity -> CoreExpr+ -> CafInfo+hasCafRefs dflags this_mod p@(_,cvt_integer) arity expr+ | is_caf || mentions_cafs = MayHaveCafRefs+ | otherwise = NoCafRefs+ where+ mentions_cafs = cafRefsE p expr+ is_dynamic_name = isDllName dflags this_mod+ is_caf = not (arity > 0 || rhsIsStatic (targetPlatform dflags) is_dynamic_name cvt_integer expr)++ -- NB. we pass in the arity of the expression, which is expected+ -- to be calculated by exprArity. This is because exprArity+ -- knows how much eta expansion is going to be done by+ -- CorePrep later on, and we don't want to duplicate that+ -- knowledge in rhsIsStatic below.++cafRefsE :: CafRefEnv -> Expr a -> Bool+cafRefsE p (Var id) = cafRefsV p id+cafRefsE p (Lit lit) = cafRefsL p lit+cafRefsE p (App f a) = cafRefsE p f || cafRefsE p a+cafRefsE p (Lam _ e) = cafRefsE p e+cafRefsE p (Let b e) = cafRefsEs p (rhssOfBind b) || cafRefsE p e+cafRefsE p (Case e _ _ alts) = cafRefsE p e || cafRefsEs p (rhssOfAlts alts)+cafRefsE p (Tick _n e) = cafRefsE p e+cafRefsE p (Cast e _co) = cafRefsE p e+cafRefsE _ (Type _) = False+cafRefsE _ (Coercion _) = False++cafRefsEs :: CafRefEnv -> [Expr a] -> Bool+cafRefsEs _ [] = False+cafRefsEs p (e:es) = cafRefsE p e || cafRefsEs p es++cafRefsL :: CafRefEnv -> Literal -> Bool+-- Don't forget that mk_integer id might have Caf refs!+-- We first need to convert the Integer into its final form, to+-- see whether mkInteger is used.+cafRefsL p@(_, cvt_integer) (LitInteger i _) = cafRefsE p (cvt_integer i)+cafRefsL _ _ = False++cafRefsV :: CafRefEnv -> Id -> Bool+cafRefsV (subst, _) id+ | not (isLocalId id) = mayHaveCafRefs (idCafInfo id)+ | Just id' <- lookupVarEnv subst id = mayHaveCafRefs (idCafInfo id')+ | otherwise = False+++{-+************************************************************************+* *+ Old, dead, type-trimming code+* *+************************************************************************++We used to try to "trim off" the constructors of data types that are+not exported, to reduce the size of interface files, at least without+-O. But that is not always possible: see the old Note [When we can't+trim types] below for exceptions.++Then (Trac #7445) I realised that the TH problem arises for any data type+that we have deriving( Data ), because we can invoke+ Language.Haskell.TH.Quote.dataToExpQ+to get a TH Exp representation of a value built from that data type.+You don't even need {-# LANGUAGE TemplateHaskell #-}.++At this point I give up. The pain of trimming constructors just+doesn't seem worth the gain. So I've dumped all the code, and am just+leaving it here at the end of the module in case something like this+is ever resurrected.+++Note [When we can't trim types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The basic idea of type trimming is to export algebraic data types+abstractly (without their data constructors) when compiling without+-O, unless of course they are explicitly exported by the user.++We always export synonyms, because they can be mentioned in the type+of an exported Id. We could do a full dependency analysis starting+from the explicit exports, but that's quite painful, and not done for+now.++But there are some times we can't do that, indicated by the 'no_trim_types' flag.++First, Template Haskell. Consider (Trac #2386) this+ module M(T, makeOne) where+ data T = Yay String+ makeOne = [| Yay "Yep" |]+Notice that T is exported abstractly, but makeOne effectively exports it too!+A module that splices in $(makeOne) will then look for a declaration of Yay,+so it'd better be there. Hence, brutally but simply, we switch off type+constructor trimming if TH is enabled in this module.++Second, data kinds. Consider (Trac #5912)+ {-# LANGUAGE DataKinds #-}+ module M() where+ data UnaryTypeC a = UnaryDataC a+ type Bug = 'UnaryDataC+We always export synonyms, so Bug is exposed, and that means that+UnaryTypeC must be too, even though it's not explicitly exported. In+effect, DataKinds means that we'd need to do a full dependency analysis+to see what data constructors are mentioned. But we don't do that yet.++In these two cases we just switch off type trimming altogether.++mustExposeTyCon :: Bool -- Type-trimming flag+ -> NameSet -- Exports+ -> TyCon -- The tycon+ -> Bool -- Can its rep be hidden?+-- We are compiling without -O, and thus trying to write as little as+-- possible into the interface file. But we must expose the details of+-- any data types whose constructors or fields are exported+mustExposeTyCon no_trim_types exports tc+ | no_trim_types -- See Note [When we can't trim types]+ = True++ | not (isAlgTyCon tc) -- Always expose synonyms (otherwise we'd have to+ -- figure out whether it was mentioned in the type+ -- of any other exported thing)+ = True++ | isEnumerationTyCon tc -- For an enumeration, exposing the constructors+ = True -- won't lead to the need for further exposure++ | isFamilyTyCon tc -- Open type family+ = True++ -- Below here we just have data/newtype decls or family instances++ | null data_cons -- Ditto if there are no data constructors+ = True -- (NB: empty data types do not count as enumerations+ -- see Note [Enumeration types] in TyCon++ | any exported_con data_cons -- Expose rep if any datacon or field is exported+ = True++ | isNewTyCon tc && isFFITy (snd (newTyConRhs tc))+ = True -- Expose the rep for newtypes if the rep is an FFI type.+ -- For a very annoying reason. 'Foreign import' is meant to+ -- be able to look through newtypes transparently, but it+ -- can only do that if it can "see" the newtype representation++ | otherwise+ = False+ where+ data_cons = tyConDataCons tc+ exported_con con = any (`elemNameSet` exports)+ (dataConName con : dataConFieldLabels con)+-}
+ nativeGen/AsmCodeGen.hs view
@@ -0,0 +1,1227 @@+-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 1993-2004+--+-- This is the top-level module in the native code generator.+--+-- -----------------------------------------------------------------------------++{-# LANGUAGE BangPatterns, CPP, GADTs, ScopedTypeVariables, UnboxedTuples #-}++module AsmCodeGen (+ -- * Module entry point+ nativeCodeGen++ -- * Test-only exports: see trac #12744+ -- used by testGraphNoSpills, which needs to access+ -- the register allocator intermediate data structures+ -- cmmNativeGen emits+ , cmmNativeGen+ , NcgImpl(..)+ , x86NcgImpl+ ) where++#include "HsVersions.h"+#include "nativeGen/NCG.h"+++import qualified X86.CodeGen+import qualified X86.Regs+import qualified X86.Instr+import qualified X86.Ppr++import qualified SPARC.CodeGen+import qualified SPARC.Regs+import qualified SPARC.Instr+import qualified SPARC.Ppr+import qualified SPARC.ShortcutJump+import qualified SPARC.CodeGen.Expand++import qualified PPC.CodeGen+import qualified PPC.Regs+import qualified PPC.RegInfo+import qualified PPC.Instr+import qualified PPC.Ppr++import RegAlloc.Liveness+import qualified RegAlloc.Linear.Main as Linear++import qualified GraphColor as Color+import qualified RegAlloc.Graph.Main as Color+import qualified RegAlloc.Graph.Stats as Color+import qualified RegAlloc.Graph.TrivColorable as Color++import TargetReg+import Platform+import Config+import Instruction+import PIC+import Reg+import NCGMonad+import Dwarf+import Debug++import BlockId+import CgUtils ( fixStgRegisters )+import Cmm+import CmmUtils+import Hoopl+import CmmOpt ( cmmMachOpFold )+import PprCmm+import CLabel++import UniqFM+import UniqSupply+import DynFlags+import Util+import Unique++import BasicTypes ( Alignment )+import Digraph+import qualified Pretty+import BufWrite+import Outputable+import FastString+import UniqSet+import ErrUtils+import Module+import Stream (Stream)+import qualified Stream++-- DEBUGGING ONLY+--import OrdList++import Data.List+import Data.Maybe+import Data.Ord ( comparing )+import Control.Exception+import Control.Monad+import System.IO++{-+The native-code generator has machine-independent and+machine-dependent modules.++This module ("AsmCodeGen") is the top-level machine-independent+module. Before entering machine-dependent land, we do some+machine-independent optimisations (defined below) on the+'CmmStmts's.++We convert to the machine-specific 'Instr' datatype with+'cmmCodeGen', assuming an infinite supply of registers. We then use+a machine-independent register allocator ('regAlloc') to rejoin+reality. Obviously, 'regAlloc' has machine-specific helper+functions (see about "RegAllocInfo" below).++Finally, we order the basic blocks of the function so as to minimise+the number of jumps between blocks, by utilising fallthrough wherever+possible.++The machine-dependent bits break down as follows:++ * ["MachRegs"] Everything about the target platform's machine+ registers (and immediate operands, and addresses, which tend to+ intermingle/interact with registers).++ * ["MachInstrs"] Includes the 'Instr' datatype (possibly should+ have a module of its own), plus a miscellany of other things+ (e.g., 'targetDoubleSize', 'smStablePtrTable', ...)++ * ["MachCodeGen"] is where 'Cmm' stuff turns into+ machine instructions.++ * ["PprMach"] 'pprInstr' turns an 'Instr' into text (well, really+ a 'SDoc').++ * ["RegAllocInfo"] In the register allocator, we manipulate+ 'MRegsState's, which are 'BitSet's, one bit per machine register.+ When we want to say something about a specific machine register+ (e.g., ``it gets clobbered by this instruction''), we set/unset+ its bit. Obviously, we do this 'BitSet' thing for efficiency+ reasons.++ The 'RegAllocInfo' module collects together the machine-specific+ info needed to do register allocation.++ * ["RegisterAlloc"] The (machine-independent) register allocator.+-}++-- -----------------------------------------------------------------------------+-- Top-level of the native codegen++data NcgImpl statics instr jumpDest = NcgImpl {+ cmmTopCodeGen :: RawCmmDecl -> NatM [NatCmmDecl statics instr],+ generateJumpTableForInstr :: instr -> Maybe (NatCmmDecl statics instr),+ getJumpDestBlockId :: jumpDest -> Maybe BlockId,+ canShortcut :: instr -> Maybe jumpDest,+ shortcutStatics :: (BlockId -> Maybe jumpDest) -> statics -> statics,+ shortcutJump :: (BlockId -> Maybe jumpDest) -> instr -> instr,+ pprNatCmmDecl :: NatCmmDecl statics instr -> SDoc,+ maxSpillSlots :: Int,+ allocatableRegs :: [RealReg],+ ncg_x86fp_kludge :: [NatCmmDecl statics instr] -> [NatCmmDecl statics instr],+ ncgExpandTop :: [NatCmmDecl statics instr] -> [NatCmmDecl statics instr],+ ncgAllocMoreStack :: Int -> NatCmmDecl statics instr -> UniqSM (NatCmmDecl statics instr),+ ncgMakeFarBranches :: LabelMap CmmStatics+ -> [NatBasicBlock instr] -> [NatBasicBlock instr],+ extractUnwindPoints :: [instr] -> [UnwindPoint]+ -- ^ given the instruction sequence of a block, produce a list of+ -- the block's 'UnwindPoint's+ -- See Note [What is this unwinding business?] in Debug+ -- and Note [Unwinding information in the NCG] in this module.+ }++--------------------+nativeCodeGen :: DynFlags -> Module -> ModLocation -> Handle -> UniqSupply+ -> Stream IO RawCmmGroup ()+ -> IO UniqSupply+nativeCodeGen dflags this_mod modLoc h us cmms+ = let platform = targetPlatform dflags+ nCG' :: (Outputable statics, Outputable instr, Instruction instr)+ => NcgImpl statics instr jumpDest -> IO UniqSupply+ nCG' ncgImpl = nativeCodeGen' dflags this_mod modLoc ncgImpl h us cmms+ in case platformArch platform of+ ArchX86 -> nCG' (x86NcgImpl dflags)+ ArchX86_64 -> nCG' (x86_64NcgImpl dflags)+ ArchPPC -> nCG' (ppcNcgImpl dflags)+ ArchSPARC -> nCG' (sparcNcgImpl dflags)+ ArchSPARC64 -> panic "nativeCodeGen: No NCG for SPARC64"+ ArchARM {} -> panic "nativeCodeGen: No NCG for ARM"+ ArchARM64 -> panic "nativeCodeGen: No NCG for ARM64"+ ArchPPC_64 _ -> nCG' (ppcNcgImpl dflags)+ ArchAlpha -> panic "nativeCodeGen: No NCG for Alpha"+ ArchMipseb -> panic "nativeCodeGen: No NCG for mipseb"+ ArchMipsel -> panic "nativeCodeGen: No NCG for mipsel"+ ArchUnknown -> panic "nativeCodeGen: No NCG for unknown arch"+ ArchJavaScript-> panic "nativeCodeGen: No NCG for JavaScript"++x86NcgImpl :: DynFlags -> NcgImpl (Alignment, CmmStatics) X86.Instr.Instr X86.Instr.JumpDest+x86NcgImpl dflags+ = (x86_64NcgImpl dflags) { ncg_x86fp_kludge = map x86fp_kludge }++x86_64NcgImpl :: DynFlags -> NcgImpl (Alignment, CmmStatics) X86.Instr.Instr X86.Instr.JumpDest+x86_64NcgImpl dflags+ = NcgImpl {+ cmmTopCodeGen = X86.CodeGen.cmmTopCodeGen+ ,generateJumpTableForInstr = X86.CodeGen.generateJumpTableForInstr dflags+ ,getJumpDestBlockId = X86.Instr.getJumpDestBlockId+ ,canShortcut = X86.Instr.canShortcut+ ,shortcutStatics = X86.Instr.shortcutStatics+ ,shortcutJump = X86.Instr.shortcutJump+ ,pprNatCmmDecl = X86.Ppr.pprNatCmmDecl+ ,maxSpillSlots = X86.Instr.maxSpillSlots dflags+ ,allocatableRegs = X86.Regs.allocatableRegs platform+ ,ncg_x86fp_kludge = id+ ,ncgAllocMoreStack = X86.Instr.allocMoreStack platform+ ,ncgExpandTop = id+ ,ncgMakeFarBranches = const id+ ,extractUnwindPoints = X86.CodeGen.extractUnwindPoints+ }+ where platform = targetPlatform dflags++ppcNcgImpl :: DynFlags -> NcgImpl CmmStatics PPC.Instr.Instr PPC.RegInfo.JumpDest+ppcNcgImpl dflags+ = NcgImpl {+ cmmTopCodeGen = PPC.CodeGen.cmmTopCodeGen+ ,generateJumpTableForInstr = PPC.CodeGen.generateJumpTableForInstr dflags+ ,getJumpDestBlockId = PPC.RegInfo.getJumpDestBlockId+ ,canShortcut = PPC.RegInfo.canShortcut+ ,shortcutStatics = PPC.RegInfo.shortcutStatics+ ,shortcutJump = PPC.RegInfo.shortcutJump+ ,pprNatCmmDecl = PPC.Ppr.pprNatCmmDecl+ ,maxSpillSlots = PPC.Instr.maxSpillSlots dflags+ ,allocatableRegs = PPC.Regs.allocatableRegs platform+ ,ncg_x86fp_kludge = id+ ,ncgAllocMoreStack = PPC.Instr.allocMoreStack platform+ ,ncgExpandTop = id+ ,ncgMakeFarBranches = PPC.Instr.makeFarBranches+ ,extractUnwindPoints = const []+ }+ where platform = targetPlatform dflags++sparcNcgImpl :: DynFlags -> NcgImpl CmmStatics SPARC.Instr.Instr SPARC.ShortcutJump.JumpDest+sparcNcgImpl dflags+ = NcgImpl {+ cmmTopCodeGen = SPARC.CodeGen.cmmTopCodeGen+ ,generateJumpTableForInstr = SPARC.CodeGen.generateJumpTableForInstr dflags+ ,getJumpDestBlockId = SPARC.ShortcutJump.getJumpDestBlockId+ ,canShortcut = SPARC.ShortcutJump.canShortcut+ ,shortcutStatics = SPARC.ShortcutJump.shortcutStatics+ ,shortcutJump = SPARC.ShortcutJump.shortcutJump+ ,pprNatCmmDecl = SPARC.Ppr.pprNatCmmDecl+ ,maxSpillSlots = SPARC.Instr.maxSpillSlots dflags+ ,allocatableRegs = SPARC.Regs.allocatableRegs+ ,ncg_x86fp_kludge = id+ ,ncgAllocMoreStack = noAllocMoreStack+ ,ncgExpandTop = map SPARC.CodeGen.Expand.expandTop+ ,ncgMakeFarBranches = const id+ ,extractUnwindPoints = const []+ }++--+-- Allocating more stack space for spilling is currently only+-- supported for the linear register allocator on x86/x86_64, the rest+-- default to the panic below. To support allocating extra stack on+-- more platforms provide a definition of ncgAllocMoreStack.+--+noAllocMoreStack :: Int -> NatCmmDecl statics instr -> UniqSM (NatCmmDecl statics instr)+noAllocMoreStack amount _+ = panic $ "Register allocator: out of stack slots (need " ++ show amount ++ ")\n"+ ++ " If you are trying to compile SHA1.hs from the crypto library then this\n"+ ++ " is a known limitation in the linear allocator.\n"+ ++ "\n"+ ++ " Try enabling the graph colouring allocator with -fregs-graph instead."+ ++ " You can still file a bug report if you like.\n"+++-- | Data accumulated during code generation. Mostly about statistics,+-- but also collects debug data for DWARF generation.+data NativeGenAcc statics instr+ = NGS { ngs_imports :: ![[CLabel]]+ , ngs_natives :: ![[NatCmmDecl statics instr]]+ -- ^ Native code generated, for statistics. This might+ -- hold a lot of data, so it is important to clear this+ -- field as early as possible if it isn't actually+ -- required.+ , ngs_colorStats :: ![[Color.RegAllocStats statics instr]]+ , ngs_linearStats :: ![[Linear.RegAllocStats]]+ , ngs_labels :: ![Label]+ , ngs_debug :: ![DebugBlock]+ , ngs_dwarfFiles :: !DwarfFiles+ , ngs_unwinds :: !(LabelMap [UnwindPoint])+ -- ^ see Note [Unwinding information in the NCG]+ -- and Note [What is this unwinding business?] in Debug.+ }++{-+Note [Unwinding information in the NCG]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Unwind information is a type of metadata which allows a debugging tool+to reconstruct the values of machine registers at the time a procedure was+entered. For the most part, the production of unwind information is handled by+the Cmm stage, where it is represented by CmmUnwind nodes.++Unfortunately, the Cmm stage doesn't know everything necessary to produce+accurate unwinding information. For instance, the x86-64 calling convention+requires that the stack pointer be aligned to 16 bytes, which in turn means that+GHC must sometimes add padding to $sp prior to performing a foreign call. When+this happens unwind information must be updated accordingly.+For this reason, we make the NCG backends responsible for producing+unwinding tables (with the extractUnwindPoints function in NcgImpl).++We accumulate the produced unwind tables over CmmGroups in the ngs_unwinds+field of NativeGenAcc. This is a label map which contains an entry for each+procedure, containing a list of unwinding points (e.g. a label and an associated+unwinding table).++See also Note [What is this unwinding business?] in Debug.+-}++nativeCodeGen' :: (Outputable statics, Outputable instr, Instruction instr)+ => DynFlags+ -> Module -> ModLocation+ -> NcgImpl statics instr jumpDest+ -> Handle+ -> UniqSupply+ -> Stream IO RawCmmGroup ()+ -> IO UniqSupply+nativeCodeGen' dflags this_mod modLoc ncgImpl h us cmms+ = do+ -- BufHandle is a performance hack. We could hide it inside+ -- Pretty if it weren't for the fact that we do lots of little+ -- printDocs here (in order to do codegen in constant space).+ bufh <- newBufHandle h+ let ngs0 = NGS [] [] [] [] [] [] emptyUFM mapEmpty+ (ngs, us') <- cmmNativeGenStream dflags this_mod modLoc ncgImpl bufh us+ cmms ngs0+ finishNativeGen dflags modLoc bufh us' ngs++finishNativeGen :: Instruction instr+ => DynFlags+ -> ModLocation+ -> BufHandle+ -> UniqSupply+ -> NativeGenAcc statics instr+ -> IO UniqSupply+finishNativeGen dflags modLoc bufh@(BufHandle _ _ h) us ngs+ = do+ -- Write debug data and finish+ let emitDw = debugLevel dflags > 0 && not (gopt Opt_SplitObjs dflags)+ us' <- if not emitDw then return us else do+ (dwarf, us') <- dwarfGen dflags modLoc us (ngs_debug ngs)+ emitNativeCode dflags bufh dwarf+ return us'+ bFlush bufh++ -- dump global NCG stats for graph coloring allocator+ let stats = concat (ngs_colorStats ngs)+ when (not (null stats)) $ do++ -- build the global register conflict graph+ let graphGlobal+ = foldl Color.union Color.initGraph+ $ [ Color.raGraph stat+ | stat@Color.RegAllocStatsStart{} <- stats]++ dump_stats (Color.pprStats stats graphGlobal)++ let platform = targetPlatform dflags+ dumpIfSet_dyn dflags+ Opt_D_dump_asm_conflicts "Register conflict graph"+ $ Color.dotGraph+ (targetRegDotColor platform)+ (Color.trivColorable platform+ (targetVirtualRegSqueeze platform)+ (targetRealRegSqueeze platform))+ $ graphGlobal+++ -- dump global NCG stats for linear allocator+ let linearStats = concat (ngs_linearStats ngs)+ when (not (null linearStats)) $+ dump_stats (Linear.pprStats (concat (ngs_natives ngs)) linearStats)++ -- write out the imports+ printSDocLn Pretty.LeftMode dflags h (mkCodeStyle AsmStyle)+ $ makeImportsDoc dflags (concat (ngs_imports ngs))+ return us'+ where+ dump_stats = dumpSDoc dflags alwaysQualify Opt_D_dump_asm_stats "NCG stats"++cmmNativeGenStream :: (Outputable statics, Outputable instr, Instruction instr)+ => DynFlags+ -> Module -> ModLocation+ -> NcgImpl statics instr jumpDest+ -> BufHandle+ -> UniqSupply+ -> Stream IO RawCmmGroup ()+ -> NativeGenAcc statics instr+ -> IO (NativeGenAcc statics instr, UniqSupply)++cmmNativeGenStream dflags this_mod modLoc ncgImpl h us cmm_stream ngs+ = do r <- Stream.runStream cmm_stream+ case r of+ Left () ->+ return (ngs { ngs_imports = reverse $ ngs_imports ngs+ , ngs_natives = reverse $ ngs_natives ngs+ , ngs_colorStats = reverse $ ngs_colorStats ngs+ , ngs_linearStats = reverse $ ngs_linearStats ngs+ },+ us)+ Right (cmms, cmm_stream') -> do++ -- Generate debug information+ let debugFlag = debugLevel dflags > 0+ !ndbgs | debugFlag = cmmDebugGen modLoc cmms+ | otherwise = []+ dbgMap = debugToMap ndbgs++ -- Insert split marker, generate native code+ let splitObjs = gopt Opt_SplitObjs dflags+ split_marker = CmmProc mapEmpty mkSplitMarkerLabel [] $+ ofBlockList (panic "split_marker_entry") []+ cmms' | splitObjs = split_marker : cmms+ | otherwise = cmms+ (ngs',us') <- cmmNativeGens dflags this_mod modLoc ncgImpl h+ dbgMap us cmms' ngs 0++ -- Link native code information into debug blocks+ -- See Note [What is this unwinding business?] in Debug.+ let !ldbgs = cmmDebugLink (ngs_labels ngs') (ngs_unwinds ngs') ndbgs+ dumpIfSet_dyn dflags Opt_D_dump_debug "Debug Infos"+ (vcat $ map ppr ldbgs)++ -- Emit & clear DWARF information when generating split+ -- object files, as we need it to land in the same object file+ -- When using split sections, note that we do not split the debug+ -- info but emit all the info at once in finishNativeGen.+ (ngs'', us'') <-+ if debugFlag && splitObjs+ then do (dwarf, us'') <- dwarfGen dflags modLoc us ldbgs+ emitNativeCode dflags h dwarf+ return (ngs' { ngs_debug = []+ , ngs_dwarfFiles = emptyUFM+ , ngs_labels = [] },+ us'')+ else return (ngs' { ngs_debug = ngs_debug ngs' ++ ldbgs+ , ngs_labels = [] },+ us')++ cmmNativeGenStream dflags this_mod modLoc ncgImpl h us''+ cmm_stream' ngs''++-- | Do native code generation on all these cmms.+--+cmmNativeGens :: forall statics instr jumpDest.+ (Outputable statics, Outputable instr, Instruction instr)+ => DynFlags+ -> Module -> ModLocation+ -> NcgImpl statics instr jumpDest+ -> BufHandle+ -> LabelMap DebugBlock+ -> UniqSupply+ -> [RawCmmDecl]+ -> NativeGenAcc statics instr+ -> Int+ -> IO (NativeGenAcc statics instr, UniqSupply)++cmmNativeGens dflags this_mod modLoc ncgImpl h dbgMap = go+ where+ go :: UniqSupply -> [RawCmmDecl]+ -> NativeGenAcc statics instr -> Int+ -> IO (NativeGenAcc statics instr, UniqSupply)++ go us [] ngs !_ =+ return (ngs, us)++ go us (cmm : cmms) ngs count = do+ let fileIds = ngs_dwarfFiles ngs+ (us', fileIds', native, imports, colorStats, linearStats, unwinds)+ <- {-# SCC "cmmNativeGen" #-}+ cmmNativeGen dflags this_mod modLoc ncgImpl us fileIds dbgMap+ cmm count++ -- Generate .file directives for every new file that has been+ -- used. Note that it is important that we generate these in+ -- ascending order, as Clang's 3.6 assembler complains.+ let newFileIds = sortBy (comparing snd) $+ nonDetEltsUFM $ fileIds' `minusUFM` fileIds+ -- See Note [Unique Determinism and code generation]+ pprDecl (f,n) = text "\t.file " <> ppr n <+>+ doubleQuotes (ftext f)++ emitNativeCode dflags h $ vcat $+ map pprDecl newFileIds +++ map (pprNatCmmDecl ncgImpl) native++ -- force evaluation all this stuff to avoid space leaks+ {-# SCC "seqString" #-} evaluate $ seqString (showSDoc dflags $ vcat $ map ppr imports)++ let !labels' = if debugLevel dflags > 0+ then cmmDebugLabels isMetaInstr native else []+ !natives' = if dopt Opt_D_dump_asm_stats dflags+ then native : ngs_natives ngs else []++ mCon = maybe id (:)+ ngs' = ngs{ ngs_imports = imports : ngs_imports ngs+ , ngs_natives = natives'+ , ngs_colorStats = colorStats `mCon` ngs_colorStats ngs+ , ngs_linearStats = linearStats `mCon` ngs_linearStats ngs+ , ngs_labels = ngs_labels ngs ++ labels'+ , ngs_dwarfFiles = fileIds'+ , ngs_unwinds = ngs_unwinds ngs `mapUnion` unwinds+ }+ go us' cmms ngs' (count + 1)++ seqString [] = ()+ seqString (x:xs) = x `seq` seqString xs+++emitNativeCode :: DynFlags -> BufHandle -> SDoc -> IO ()+emitNativeCode dflags h sdoc = do++ {-# SCC "pprNativeCode" #-} bufLeftRenderSDoc dflags h+ (mkCodeStyle AsmStyle) sdoc++ -- dump native code+ dumpIfSet_dyn dflags+ Opt_D_dump_asm "Asm code"+ sdoc++-- | Complete native code generation phase for a single top-level chunk of Cmm.+-- Dumping the output of each stage along the way.+-- Global conflict graph and NGC stats+cmmNativeGen+ :: (Outputable statics, Outputable instr, Instruction instr)+ => DynFlags+ -> Module -> ModLocation+ -> NcgImpl statics instr jumpDest+ -> UniqSupply+ -> DwarfFiles+ -> LabelMap DebugBlock+ -> RawCmmDecl -- ^ the cmm to generate code for+ -> Int -- ^ sequence number of this top thing+ -> IO ( UniqSupply+ , DwarfFiles+ , [NatCmmDecl statics instr] -- native code+ , [CLabel] -- things imported by this cmm+ , Maybe [Color.RegAllocStats statics instr] -- stats for the coloring register allocator+ , Maybe [Linear.RegAllocStats] -- stats for the linear register allocators+ , LabelMap [UnwindPoint] -- unwinding information for blocks+ )++cmmNativeGen dflags this_mod modLoc ncgImpl us fileIds dbgMap cmm count+ = do+ let platform = targetPlatform dflags++ -- rewrite assignments to global regs+ let fixed_cmm =+ {-# SCC "fixStgRegisters" #-}+ fixStgRegisters dflags cmm++ -- cmm to cmm optimisations+ let (opt_cmm, imports) =+ {-# SCC "cmmToCmm" #-}+ cmmToCmm dflags this_mod fixed_cmm++ dumpIfSet_dyn dflags+ Opt_D_dump_opt_cmm "Optimised Cmm"+ (pprCmmGroup [opt_cmm])++ -- generate native code from cmm+ let ((native, lastMinuteImports, fileIds'), usGen) =+ {-# SCC "genMachCode" #-}+ initUs us $ genMachCode dflags this_mod modLoc+ (cmmTopCodeGen ncgImpl)+ fileIds dbgMap opt_cmm++ dumpIfSet_dyn dflags+ Opt_D_dump_asm_native "Native code"+ (vcat $ map (pprNatCmmDecl ncgImpl) native)++ -- tag instructions with register liveness information+ let (withLiveness, usLive) =+ {-# SCC "regLiveness" #-}+ initUs usGen+ $ mapM (regLiveness platform)+ $ map natCmmTopToLive native++ dumpIfSet_dyn dflags+ Opt_D_dump_asm_liveness "Liveness annotations added"+ (vcat $ map ppr withLiveness)++ -- allocate registers+ (alloced, usAlloc, ppr_raStatsColor, ppr_raStatsLinear) <-+ if ( gopt Opt_RegsGraph dflags+ || gopt Opt_RegsIterative dflags )+ then do+ -- the regs usable for allocation+ let (alloc_regs :: UniqFM (UniqSet RealReg))+ = foldr (\r -> plusUFM_C unionUniqSets+ $ unitUFM (targetClassOfRealReg platform r) (unitUniqSet r))+ emptyUFM+ $ allocatableRegs ncgImpl++ -- do the graph coloring register allocation+ let ((alloced, regAllocStats), usAlloc)+ = {-# SCC "RegAlloc-color" #-}+ initUs usLive+ $ Color.regAlloc+ dflags+ alloc_regs+ (mkUniqSet [0 .. maxSpillSlots ncgImpl])+ withLiveness++ -- dump out what happened during register allocation+ dumpIfSet_dyn dflags+ Opt_D_dump_asm_regalloc "Registers allocated"+ (vcat $ map (pprNatCmmDecl ncgImpl) alloced)++ dumpIfSet_dyn dflags+ Opt_D_dump_asm_regalloc_stages "Build/spill stages"+ (vcat $ map (\(stage, stats)+ -> text "# --------------------------"+ $$ text "# cmm " <> int count <> text " Stage " <> int stage+ $$ ppr stats)+ $ zip [0..] regAllocStats)++ let mPprStats =+ if dopt Opt_D_dump_asm_stats dflags+ then Just regAllocStats else Nothing++ -- force evaluation of the Maybe to avoid space leak+ mPprStats `seq` return ()++ return ( alloced, usAlloc+ , mPprStats+ , Nothing)++ else do+ -- do linear register allocation+ let reg_alloc proc = do+ (alloced, maybe_more_stack, ra_stats) <-+ Linear.regAlloc dflags proc+ case maybe_more_stack of+ Nothing -> return ( alloced, ra_stats )+ Just amount -> do+ alloced' <- ncgAllocMoreStack ncgImpl amount alloced+ return (alloced', ra_stats )++ let ((alloced, regAllocStats), usAlloc)+ = {-# SCC "RegAlloc-linear" #-}+ initUs usLive+ $ liftM unzip+ $ mapM reg_alloc withLiveness++ dumpIfSet_dyn dflags+ Opt_D_dump_asm_regalloc "Registers allocated"+ (vcat $ map (pprNatCmmDecl ncgImpl) alloced)++ let mPprStats =+ if dopt Opt_D_dump_asm_stats dflags+ then Just (catMaybes regAllocStats) else Nothing++ -- force evaluation of the Maybe to avoid space leak+ mPprStats `seq` return ()++ return ( alloced, usAlloc+ , Nothing+ , mPprStats)++ ---- x86fp_kludge. This pass inserts ffree instructions to clear+ ---- the FPU stack on x86. The x86 ABI requires that the FPU stack+ ---- is clear, and library functions can return odd results if it+ ---- isn't.+ ----+ ---- NB. must happen before shortcutBranches, because that+ ---- generates JXX_GBLs which we can't fix up in x86fp_kludge.+ let kludged = {-# SCC "x86fp_kludge" #-} ncg_x86fp_kludge ncgImpl alloced++ ---- generate jump tables+ let tabled =+ {-# SCC "generateJumpTables" #-}+ generateJumpTables ncgImpl kludged++ ---- shortcut branches+ let shorted =+ {-# SCC "shortcutBranches" #-}+ shortcutBranches dflags ncgImpl tabled++ ---- sequence blocks+ let sequenced =+ {-# SCC "sequenceBlocks" #-}+ map (sequenceTop ncgImpl) shorted++ ---- expansion of SPARC synthetic instrs+ let expanded =+ {-# SCC "sparc_expand" #-}+ ncgExpandTop ncgImpl sequenced++ dumpIfSet_dyn dflags+ Opt_D_dump_asm_expanded "Synthetic instructions expanded"+ (vcat $ map (pprNatCmmDecl ncgImpl) expanded)++ -- generate unwinding information from cmm+ let unwinds :: BlockMap [UnwindPoint]+ unwinds =+ {-# SCC "unwindingInfo" #-}+ foldl' addUnwind mapEmpty expanded+ where+ addUnwind acc proc =+ acc `mapUnion` computeUnwinding dflags ncgImpl proc++ return ( usAlloc+ , fileIds'+ , expanded+ , lastMinuteImports ++ imports+ , ppr_raStatsColor+ , ppr_raStatsLinear+ , unwinds )+++x86fp_kludge :: NatCmmDecl (Alignment, CmmStatics) X86.Instr.Instr -> NatCmmDecl (Alignment, CmmStatics) X86.Instr.Instr+x86fp_kludge top@(CmmData _ _) = top+x86fp_kludge (CmmProc info lbl live (ListGraph code)) =+ CmmProc info lbl live (ListGraph $ X86.Instr.i386_insert_ffrees code)++-- | Compute unwinding tables for the blocks of a procedure+computeUnwinding :: Instruction instr+ => DynFlags -> NcgImpl statics instr jumpDest+ -> NatCmmDecl statics instr+ -- ^ the native code generated for the procedure+ -> LabelMap [UnwindPoint]+ -- ^ unwinding tables for all points of all blocks of the+ -- procedure+computeUnwinding dflags _ _+ | debugLevel dflags == 0 = mapEmpty+computeUnwinding _ _ (CmmData _ _) = mapEmpty+computeUnwinding _ ncgImpl (CmmProc _ _ _ (ListGraph blks)) =+ -- In general we would need to push unwinding information down the+ -- block-level call-graph to ensure that we fully account for all+ -- relevant register writes within a procedure.+ --+ -- However, the only unwinding information that we care about in GHC is for+ -- Sp. The fact that CmmLayoutStack already ensures that we have unwind+ -- information at the beginning of every block means that there is no need+ -- to perform this sort of push-down.+ mapFromList [ (blk_lbl, extractUnwindPoints ncgImpl instrs)+ | BasicBlock blk_lbl instrs <- blks ]++-- | Build a doc for all the imports.+--+makeImportsDoc :: DynFlags -> [CLabel] -> SDoc+makeImportsDoc dflags imports+ = dyld_stubs imports+ $$+ -- On recent versions of Darwin, the linker supports+ -- dead-stripping of code and data on a per-symbol basis.+ -- There's a hack to make this work in PprMach.pprNatCmmDecl.+ (if platformHasSubsectionsViaSymbols platform+ then text ".subsections_via_symbols"+ else Outputable.empty)+ $$+ -- On recent GNU ELF systems one can mark an object file+ -- as not requiring an executable stack. If all objects+ -- linked into a program have this note then the program+ -- will not use an executable stack, which is good for+ -- security. GHC generated code does not need an executable+ -- stack so add the note in:+ (if platformHasGnuNonexecStack platform+ then text ".section .note.GNU-stack,\"\",@progbits"+ else Outputable.empty)+ $$+ -- And just because every other compiler does, let's stick in+ -- an identifier directive: .ident "GHC x.y.z"+ (if platformHasIdentDirective platform+ then let compilerIdent = text "GHC" <+> text cProjectVersion+ in text ".ident" <+> doubleQuotes compilerIdent+ else Outputable.empty)++ where+ platform = targetPlatform dflags+ arch = platformArch platform+ os = platformOS platform++ -- Generate "symbol stubs" for all external symbols that might+ -- come from a dynamic library.+ dyld_stubs :: [CLabel] -> SDoc+{- dyld_stubs imps = vcat $ map pprDyldSymbolStub $+ map head $ group $ sort imps-}+ -- (Hack) sometimes two Labels pretty-print the same, but have+ -- different uniques; so we compare their text versions...+ dyld_stubs imps+ | needImportedSymbols dflags arch os+ = vcat $+ (pprGotDeclaration dflags arch os :) $+ map ( pprImportedSymbol dflags platform . fst . head) $+ groupBy (\(_,a) (_,b) -> a == b) $+ sortBy (\(_,a) (_,b) -> compare a b) $+ map doPpr $+ imps+ | otherwise+ = Outputable.empty++ doPpr lbl = (lbl, renderWithStyle dflags (pprCLabel platform lbl) astyle)+ astyle = mkCodeStyle AsmStyle+++-- -----------------------------------------------------------------------------+-- Sequencing the basic blocks++-- Cmm BasicBlocks are self-contained entities: they always end in a+-- jump, either non-local or to another basic block in the same proc.+-- In this phase, we attempt to place the basic blocks in a sequence+-- such that as many of the local jumps as possible turn into+-- fallthroughs.++sequenceTop+ :: Instruction instr+ => NcgImpl statics instr jumpDest -> NatCmmDecl statics instr -> NatCmmDecl statics instr++sequenceTop _ top@(CmmData _ _) = top+sequenceTop ncgImpl (CmmProc info lbl live (ListGraph blocks)) =+ CmmProc info lbl live (ListGraph $ ncgMakeFarBranches ncgImpl info $ sequenceBlocks info blocks)++-- The algorithm is very simple (and stupid): we make a graph out of+-- the blocks where there is an edge from one block to another iff the+-- first block ends by jumping to the second. Then we topologically+-- sort this graph. Then traverse the list: for each block, we first+-- output the block, then if it has an out edge, we move the+-- destination of the out edge to the front of the list, and continue.++-- FYI, the classic layout for basic blocks uses postorder DFS; this+-- algorithm is implemented in Hoopl.++sequenceBlocks+ :: Instruction instr+ => LabelMap i+ -> [NatBasicBlock instr]+ -> [NatBasicBlock instr]++sequenceBlocks _ [] = []+sequenceBlocks infos (entry:blocks) =+ seqBlocks infos (mkNode entry : reverse (flattenSCCs (sccBlocks blocks)))+ -- the first block is the entry point ==> it must remain at the start.+++sccBlocks+ :: Instruction instr+ => [NatBasicBlock instr]+ -> [SCC ( NatBasicBlock instr+ , BlockId+ , [BlockId])]++sccBlocks blocks = stronglyConnCompFromEdgedVerticesUniqR (map mkNode blocks)++-- we're only interested in the last instruction of+-- the block, and only if it has a single destination.+getOutEdges+ :: Instruction instr+ => [instr] -> [BlockId]++getOutEdges instrs+ = case jumpDestsOfInstr (last instrs) of+ [one] -> [one]+ _many -> []++mkNode :: (Instruction t)+ => GenBasicBlock t+ -> (GenBasicBlock t, BlockId, [BlockId])+mkNode block@(BasicBlock id instrs) = (block, id, getOutEdges instrs)++seqBlocks :: LabelMap i -> [(GenBasicBlock t1, BlockId, [BlockId])]+ -> [GenBasicBlock t1]+seqBlocks infos blocks = placeNext pullable0 todo0+ where+ -- pullable: Blocks that are not yet placed+ -- todo: Original order of blocks, to be followed if we have no good+ -- reason not to;+ -- may include blocks that have already been placed, but then+ -- these are not in pullable+ pullable0 = listToUFM [ (i,(b,n)) | (b,i,n) <- blocks ]+ todo0 = [i | (_,i,_) <- blocks ]++ placeNext _ [] = []+ placeNext pullable (i:rest)+ | Just (block, pullable') <- lookupDeleteUFM pullable i+ = place pullable' rest block+ | otherwise+ -- We already placed this block, so ignore+ = placeNext pullable rest++ place pullable todo (block,[])+ = block : placeNext pullable todo+ place pullable todo (block@(BasicBlock id instrs),[next])+ | mapMember next infos+ = block : placeNext pullable todo+ | Just (nextBlock, pullable') <- lookupDeleteUFM pullable next+ = BasicBlock id (init instrs) : place pullable' todo nextBlock+ | otherwise+ = block : placeNext pullable todo+ place _ _ (_,tooManyNextNodes)+ = pprPanic "seqBlocks" (ppr tooManyNextNodes)+++lookupDeleteUFM :: Uniquable key => UniqFM elt -> key -> Maybe (elt, UniqFM elt)+lookupDeleteUFM m k = do -- Maybe monad+ v <- lookupUFM m k+ return (v, delFromUFM m k)++-- -----------------------------------------------------------------------------+-- Generate jump tables++-- Analyzes all native code and generates data sections for all jump+-- table instructions.+generateJumpTables+ :: NcgImpl statics instr jumpDest+ -> [NatCmmDecl statics instr] -> [NatCmmDecl statics instr]+generateJumpTables ncgImpl xs = concatMap f xs+ where f p@(CmmProc _ _ _ (ListGraph xs)) = p : concatMap g xs+ f p = [p]+ g (BasicBlock _ xs) = catMaybes (map (generateJumpTableForInstr ncgImpl) xs)++-- -----------------------------------------------------------------------------+-- Shortcut branches++shortcutBranches+ :: DynFlags+ -> NcgImpl statics instr jumpDest+ -> [NatCmmDecl statics instr]+ -> [NatCmmDecl statics instr]++shortcutBranches dflags ncgImpl tops+ | optLevel dflags < 1 = tops -- only with -O or higher+ | otherwise = map (apply_mapping ncgImpl mapping) tops'+ where+ (tops', mappings) = mapAndUnzip (build_mapping ncgImpl) tops+ mapping = foldr plusUFM emptyUFM mappings++build_mapping :: NcgImpl statics instr jumpDest+ -> GenCmmDecl d (LabelMap t) (ListGraph instr)+ -> (GenCmmDecl d (LabelMap t) (ListGraph instr), UniqFM jumpDest)+build_mapping _ top@(CmmData _ _) = (top, emptyUFM)+build_mapping _ (CmmProc info lbl live (ListGraph []))+ = (CmmProc info lbl live (ListGraph []), emptyUFM)+build_mapping ncgImpl (CmmProc info lbl live (ListGraph (head:blocks)))+ = (CmmProc info lbl live (ListGraph (head:others)), mapping)+ -- drop the shorted blocks, but don't ever drop the first one,+ -- because it is pointed to by a global label.+ where+ -- find all the blocks that just consist of a jump that can be+ -- shorted.+ -- Don't completely eliminate loops here -- that can leave a dangling jump!+ (_, shortcut_blocks, others) =+ foldl split (setEmpty :: LabelSet, [], []) blocks+ split (s, shortcut_blocks, others) b@(BasicBlock id [insn])+ | Just jd <- canShortcut ncgImpl insn,+ Just dest <- getJumpDestBlockId ncgImpl jd,+ not (has_info id),+ (setMember dest s) || dest == id -- loop checks+ = (s, shortcut_blocks, b : others)+ split (s, shortcut_blocks, others) (BasicBlock id [insn])+ | Just dest <- canShortcut ncgImpl insn,+ not (has_info id)+ = (setInsert id s, (id,dest) : shortcut_blocks, others)+ split (s, shortcut_blocks, others) other = (s, shortcut_blocks, other : others)++ -- do not eliminate blocks that have an info table+ has_info l = mapMember l info++ -- build a mapping from BlockId to JumpDest for shorting branches+ mapping = foldl add emptyUFM shortcut_blocks+ add ufm (id,dest) = addToUFM ufm id dest++apply_mapping :: NcgImpl statics instr jumpDest+ -> UniqFM jumpDest+ -> GenCmmDecl statics h (ListGraph instr)+ -> GenCmmDecl statics h (ListGraph instr)+apply_mapping ncgImpl ufm (CmmData sec statics)+ = CmmData sec (shortcutStatics ncgImpl (lookupUFM ufm) statics)+apply_mapping ncgImpl ufm (CmmProc info lbl live (ListGraph blocks))+ = CmmProc info lbl live (ListGraph $ map short_bb blocks)+ where+ short_bb (BasicBlock id insns) = BasicBlock id $! map short_insn insns+ short_insn i = shortcutJump ncgImpl (lookupUFM ufm) i+ -- shortcutJump should apply the mapping repeatedly,+ -- just in case we can short multiple branches.++-- -----------------------------------------------------------------------------+-- Instruction selection++-- Native code instruction selection for a chunk of stix code. For+-- this part of the computation, we switch from the UniqSM monad to+-- the NatM monad. The latter carries not only a Unique, but also an+-- Int denoting the current C stack pointer offset in the generated+-- code; this is needed for creating correct spill offsets on+-- architectures which don't offer, or for which it would be+-- prohibitively expensive to employ, a frame pointer register. Viz,+-- x86.++-- The offset is measured in bytes, and indicates the difference+-- between the current (simulated) C stack-ptr and the value it was at+-- the beginning of the block. For stacks which grow down, this value+-- should be either zero or negative.++-- Along with the stack pointer offset, we also carry along a LabelMap of+-- DebugBlocks, which we read to generate .location directives.+--+-- Switching between the two monads whilst carrying along the same+-- Unique supply breaks abstraction. Is that bad?++genMachCode+ :: DynFlags+ -> Module -> ModLocation+ -> (RawCmmDecl -> NatM [NatCmmDecl statics instr])+ -> DwarfFiles+ -> LabelMap DebugBlock+ -> RawCmmDecl+ -> UniqSM+ ( [NatCmmDecl statics instr]+ , [CLabel]+ , DwarfFiles)++genMachCode dflags this_mod modLoc cmmTopCodeGen fileIds dbgMap cmm_top+ = do { initial_us <- getUniqueSupplyM+ ; let initial_st = mkNatM_State initial_us 0 dflags this_mod+ modLoc fileIds dbgMap+ (new_tops, final_st) = initNat initial_st (cmmTopCodeGen cmm_top)+ final_delta = natm_delta final_st+ final_imports = natm_imports final_st+ ; if final_delta == 0+ then return (new_tops, final_imports, natm_fileid final_st)+ else pprPanic "genMachCode: nonzero final delta" (int final_delta)+ }++-- -----------------------------------------------------------------------------+-- Generic Cmm optimiser++{-+Here we do:++ (a) Constant folding+ (c) Position independent code and dynamic linking+ (i) introduce the appropriate indirections+ and position independent refs+ (ii) compile a list of imported symbols+ (d) Some arch-specific optimizations++(a) will be moving to the new Hoopl pipeline, however, (c) and+(d) are only needed by the native backend and will continue to live+here.++Ideas for other things we could do (put these in Hoopl please!):++ - shortcut jumps-to-jumps+ - simple CSE: if an expr is assigned to a temp, then replace later occs of+ that expr with the temp, until the expr is no longer valid (can push through+ temp assignments, and certain assigns to mem...)+-}++cmmToCmm :: DynFlags -> Module -> RawCmmDecl -> (RawCmmDecl, [CLabel])+cmmToCmm _ _ top@(CmmData _ _) = (top, [])+cmmToCmm dflags this_mod (CmmProc info lbl live graph)+ = runCmmOpt dflags this_mod $+ do blocks' <- mapM cmmBlockConFold (toBlockList graph)+ return $ CmmProc info lbl live (ofBlockList (g_entry graph) blocks')++newtype CmmOptM a = CmmOptM (DynFlags -> Module -> [CLabel] -> (# a, [CLabel] #))++instance Functor CmmOptM where+ fmap = liftM++instance Applicative CmmOptM where+ pure x = CmmOptM $ \_ _ imports -> (# x, imports #)+ (<*>) = ap++instance Monad CmmOptM where+ (CmmOptM f) >>= g =+ CmmOptM $ \dflags this_mod imports ->+ case f dflags this_mod imports of+ (# x, imports' #) ->+ case g x of+ CmmOptM g' -> g' dflags this_mod imports'++instance CmmMakeDynamicReferenceM CmmOptM where+ addImport = addImportCmmOpt+ getThisModule = CmmOptM $ \_ this_mod imports -> (# this_mod, imports #)++addImportCmmOpt :: CLabel -> CmmOptM ()+addImportCmmOpt lbl = CmmOptM $ \_ _ imports -> (# (), lbl:imports #)++instance HasDynFlags CmmOptM where+ getDynFlags = CmmOptM $ \dflags _ imports -> (# dflags, imports #)++runCmmOpt :: DynFlags -> Module -> CmmOptM a -> (a, [CLabel])+runCmmOpt dflags this_mod (CmmOptM f) = case f dflags this_mod [] of+ (# result, imports #) -> (result, imports)++cmmBlockConFold :: CmmBlock -> CmmOptM CmmBlock+cmmBlockConFold block = do+ let (entry, middle, last) = blockSplit block+ stmts = blockToList middle+ stmts' <- mapM cmmStmtConFold stmts+ last' <- cmmStmtConFold last+ return $ blockJoin entry (blockFromList stmts') last'++-- This does three optimizations, but they're very quick to check, so we don't+-- bother turning them off even when the Hoopl code is active. Since+-- this is on the old Cmm representation, we can't reuse the code either:+-- * reg = reg --> nop+-- * if 0 then jump --> nop+-- * if 1 then jump --> jump+-- We might be tempted to skip this step entirely of not Opt_PIC, but+-- there is some PowerPC code for the non-PIC case, which would also+-- have to be separated.+cmmStmtConFold :: CmmNode e x -> CmmOptM (CmmNode e x)+cmmStmtConFold stmt+ = case stmt of+ CmmAssign reg src+ -> do src' <- cmmExprConFold DataReference src+ return $ case src' of+ CmmReg reg' | reg == reg' -> CmmComment (fsLit "nop")+ new_src -> CmmAssign reg new_src++ CmmStore addr src+ -> do addr' <- cmmExprConFold DataReference addr+ src' <- cmmExprConFold DataReference src+ return $ CmmStore addr' src'++ CmmCall { cml_target = addr }+ -> do addr' <- cmmExprConFold JumpReference addr+ return $ stmt { cml_target = addr' }++ CmmUnsafeForeignCall target regs args+ -> do target' <- case target of+ ForeignTarget e conv -> do+ e' <- cmmExprConFold CallReference e+ return $ ForeignTarget e' conv+ PrimTarget _ ->+ return target+ args' <- mapM (cmmExprConFold DataReference) args+ return $ CmmUnsafeForeignCall target' regs args'++ CmmCondBranch test true false likely+ -> do test' <- cmmExprConFold DataReference test+ return $ case test' of+ CmmLit (CmmInt 0 _) -> CmmBranch false+ CmmLit (CmmInt _ _) -> CmmBranch true+ _other -> CmmCondBranch test' true false likely++ CmmSwitch expr ids+ -> do expr' <- cmmExprConFold DataReference expr+ return $ CmmSwitch expr' ids++ other+ -> return other++cmmExprConFold :: ReferenceKind -> CmmExpr -> CmmOptM CmmExpr+cmmExprConFold referenceKind expr = do+ dflags <- getDynFlags++ -- With -O1 and greater, the cmmSink pass does constant-folding, so+ -- we don't need to do it again here.+ let expr' = if optLevel dflags >= 1+ then expr+ else cmmExprCon dflags expr++ cmmExprNative referenceKind expr'++cmmExprCon :: DynFlags -> CmmExpr -> CmmExpr+cmmExprCon dflags (CmmLoad addr rep) = CmmLoad (cmmExprCon dflags addr) rep+cmmExprCon dflags (CmmMachOp mop args)+ = cmmMachOpFold dflags mop (map (cmmExprCon dflags) args)+cmmExprCon _ other = other++-- handles both PIC and non-PIC cases... a very strange mixture+-- of things to do.+cmmExprNative :: ReferenceKind -> CmmExpr -> CmmOptM CmmExpr+cmmExprNative referenceKind expr = do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ arch = platformArch platform+ case expr of+ CmmLoad addr rep+ -> do addr' <- cmmExprNative DataReference addr+ return $ CmmLoad addr' rep++ CmmMachOp mop args+ -> do args' <- mapM (cmmExprNative DataReference) args+ return $ CmmMachOp mop args'++ CmmLit (CmmBlock id)+ -> cmmExprNative referenceKind (CmmLit (CmmLabel (infoTblLbl id)))+ -- we must convert block Ids to CLabels here, because we+ -- might have to do the PIC transformation. Hence we must+ -- not modify BlockIds beyond this point.++ CmmLit (CmmLabel lbl)+ -> do+ cmmMakeDynamicReference dflags referenceKind lbl+ CmmLit (CmmLabelOff lbl off)+ -> do+ dynRef <- cmmMakeDynamicReference dflags referenceKind lbl+ -- need to optimize here, since it's late+ return $ cmmMachOpFold dflags (MO_Add (wordWidth dflags)) [+ dynRef,+ (CmmLit $ CmmInt (fromIntegral off) (wordWidth dflags))+ ]++ -- On powerpc (non-PIC), it's easier to jump directly to a label than+ -- to use the register table, so we replace these registers+ -- with the corresponding labels:+ CmmReg (CmmGlobal EagerBlackholeInfo)+ | arch == ArchPPC && not (gopt Opt_PIC dflags)+ -> cmmExprNative referenceKind $+ CmmLit (CmmLabel (mkCmmCodeLabel rtsUnitId (fsLit "__stg_EAGER_BLACKHOLE_info")))+ CmmReg (CmmGlobal GCEnter1)+ | arch == ArchPPC && not (gopt Opt_PIC dflags)+ -> cmmExprNative referenceKind $+ CmmLit (CmmLabel (mkCmmCodeLabel rtsUnitId (fsLit "__stg_gc_enter_1")))+ CmmReg (CmmGlobal GCFun)+ | arch == ArchPPC && not (gopt Opt_PIC dflags)+ -> cmmExprNative referenceKind $+ CmmLit (CmmLabel (mkCmmCodeLabel rtsUnitId (fsLit "__stg_gc_fun")))++ other+ -> return other
+ nativeGen/CPrim.hs view
@@ -0,0 +1,101 @@+-- | Generating C symbol names emitted by the compiler.+module CPrim+ ( atomicReadLabel+ , atomicWriteLabel+ , atomicRMWLabel+ , cmpxchgLabel+ , popCntLabel+ , bSwapLabel+ , clzLabel+ , ctzLabel+ , word2FloatLabel+ ) where++import CmmType+import CmmMachOp+import Outputable++popCntLabel :: Width -> String+popCntLabel w = "hs_popcnt" ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "popCntLabel: Unsupported word width " (ppr w)++bSwapLabel :: Width -> String+bSwapLabel w = "hs_bswap" ++ pprWidth w+ where+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "bSwapLabel: Unsupported word width " (ppr w)++clzLabel :: Width -> String+clzLabel w = "hs_clz" ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "clzLabel: Unsupported word width " (ppr w)++ctzLabel :: Width -> String+ctzLabel w = "hs_ctz" ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "ctzLabel: Unsupported word width " (ppr w)++word2FloatLabel :: Width -> String+word2FloatLabel w = "hs_word2float" ++ pprWidth w+ where+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "word2FloatLabel: Unsupported word width " (ppr w)++atomicRMWLabel :: Width -> AtomicMachOp -> String+atomicRMWLabel w amop = "hs_atomic_" ++ pprFunName amop ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "atomicRMWLabel: Unsupported word width " (ppr w)++ pprFunName AMO_Add = "add"+ pprFunName AMO_Sub = "sub"+ pprFunName AMO_And = "and"+ pprFunName AMO_Nand = "nand"+ pprFunName AMO_Or = "or"+ pprFunName AMO_Xor = "xor"++cmpxchgLabel :: Width -> String+cmpxchgLabel w = "hs_cmpxchg" ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "cmpxchgLabel: Unsupported word width " (ppr w)++atomicReadLabel :: Width -> String+atomicReadLabel w = "hs_atomicread" ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "atomicReadLabel: Unsupported word width " (ppr w)++atomicWriteLabel :: Width -> String+atomicWriteLabel w = "hs_atomicwrite" ++ pprWidth w+ where+ pprWidth W8 = "8"+ pprWidth W16 = "16"+ pprWidth W32 = "32"+ pprWidth W64 = "64"+ pprWidth w = pprPanic "atomicWriteLabel: Unsupported word width " (ppr w)
+ nativeGen/Dwarf.hs view
@@ -0,0 +1,259 @@+module Dwarf (+ dwarfGen+ ) where++import CLabel+import CmmExpr ( GlobalReg(..) )+import Config ( cProjectName, cProjectVersion )+import CoreSyn ( Tickish(..) )+import Debug+import DynFlags+import Module+import Outputable+import Platform+import Unique+import UniqSupply++import Dwarf.Constants+import Dwarf.Types++import Control.Arrow ( first )+import Control.Monad ( mfilter )+import Data.Maybe+import Data.List ( sortBy )+import Data.Ord ( comparing )+import qualified Data.Map as Map+import System.FilePath+import System.Directory ( getCurrentDirectory )++import qualified Compiler.Hoopl as H++-- | Generate DWARF/debug information+dwarfGen :: DynFlags -> ModLocation -> UniqSupply -> [DebugBlock]+ -> IO (SDoc, UniqSupply)+dwarfGen _ _ us [] = return (empty, us)+dwarfGen df modLoc us blocks = do++ -- Convert debug data structures to DWARF info records+ -- We strip out block information when running with -g0 or -g1.+ let procs = debugSplitProcs blocks+ stripBlocks dbg+ | debugLevel df < 2 = dbg { dblBlocks = [] }+ | otherwise = dbg+ compPath <- getCurrentDirectory+ let lowLabel = dblCLabel $ head procs+ highLabel = mkAsmTempEndLabel $ dblCLabel $ last procs+ dwarfUnit = DwarfCompileUnit+ { dwChildren = map (procToDwarf df) (map stripBlocks procs)+ , dwName = fromMaybe "" (ml_hs_file modLoc)+ , dwCompDir = addTrailingPathSeparator compPath+ , dwProducer = cProjectName ++ " " ++ cProjectVersion+ , dwLowLabel = lowLabel+ , dwHighLabel = highLabel+ , dwLineLabel = dwarfLineLabel+ }++ -- Check whether we have any source code information, so we do not+ -- end up writing a pointer to an empty .debug_line section+ -- (dsymutil on Mac Os gets confused by this).+ let haveSrcIn blk = isJust (dblSourceTick blk) && isJust (dblPosition blk)+ || any haveSrcIn (dblBlocks blk)+ haveSrc = any haveSrcIn procs++ -- .debug_abbrev section: Declare the format we're using+ let abbrevSct = pprAbbrevDecls haveSrc++ -- .debug_info section: Information records on procedures and blocks+ let -- unique to identify start and end compilation unit .debug_inf+ (unitU, us') = takeUniqFromSupply us+ infoSct = vcat [ ptext dwarfInfoLabel <> colon+ , dwarfInfoSection+ , compileUnitHeader unitU+ , pprDwarfInfo haveSrc dwarfUnit+ , compileUnitFooter unitU+ ]++ -- .debug_line section: Generated mainly by the assembler, but we+ -- need to label it+ let lineSct = dwarfLineSection $$+ ptext dwarfLineLabel <> colon++ -- .debug_frame section: Information about the layout of the GHC stack+ let (framesU, us'') = takeUniqFromSupply us'+ frameSct = dwarfFrameSection $$+ ptext dwarfFrameLabel <> colon $$+ pprDwarfFrame (debugFrame framesU procs)++ -- .aranges section: Information about the bounds of compilation units+ let aranges' | gopt Opt_SplitSections df = map mkDwarfARange procs+ | otherwise = [DwarfARange lowLabel highLabel]+ let aranges = dwarfARangesSection $$ pprDwarfARanges aranges' unitU++ return (infoSct $$ abbrevSct $$ lineSct $$ frameSct $$ aranges, us'')++-- | Build an address range entry for one proc.+-- With split sections, each proc needs its own entry, since they may get+-- scattered in the final binary. Without split sections, we could make a+-- single arange based on the first/last proc.+mkDwarfARange :: DebugBlock -> DwarfARange+mkDwarfARange proc = DwarfARange start end+ where+ start = dblCLabel proc+ end = mkAsmTempEndLabel start++-- | Header for a compilation unit, establishing global format+-- parameters+compileUnitHeader :: Unique -> SDoc+compileUnitHeader unitU = sdocWithPlatform $ \plat ->+ let cuLabel = mkAsmTempLabel unitU -- sits right before initialLength field+ length = ppr (mkAsmTempEndLabel cuLabel) <> char '-' <> ppr cuLabel+ <> text "-4" -- length of initialLength field+ in vcat [ ppr cuLabel <> colon+ , text "\t.long " <> length -- compilation unit size+ , pprHalf 3 -- DWARF version+ , sectionOffset (ptext dwarfAbbrevLabel) (ptext dwarfAbbrevLabel)+ -- abbrevs offset+ , text "\t.byte " <> ppr (platformWordSize plat) -- word size+ ]++-- | Compilation unit footer, mainly establishing size of debug sections+compileUnitFooter :: Unique -> SDoc+compileUnitFooter unitU =+ let cuEndLabel = mkAsmTempEndLabel $ mkAsmTempLabel unitU+ in ppr cuEndLabel <> colon++-- | Splits the blocks by procedures. In the result all nested blocks+-- will come from the same procedure as the top-level block. See+-- Note [Splitting DebugBlocks] for details.+debugSplitProcs :: [DebugBlock] -> [DebugBlock]+debugSplitProcs b = concat $ H.mapElems $ mergeMaps $ map (split Nothing) b+ where mergeMaps = foldr (H.mapUnionWithKey (const (++))) H.mapEmpty+ split :: Maybe DebugBlock -> DebugBlock -> H.LabelMap [DebugBlock]+ split parent blk = H.mapInsert prc [blk'] nested+ where prc = dblProcedure blk+ blk' = blk { dblBlocks = own_blks+ , dblParent = parent+ }+ own_blks = fromMaybe [] $ H.mapLookup prc nested+ nested = mergeMaps $ map (split parent') $ dblBlocks blk+ -- Figure out who should be the parent of nested blocks.+ -- If @blk@ is optimized out then it isn't a good choice+ -- and we just use its parent.+ parent'+ | Nothing <- dblPosition blk = parent+ | otherwise = Just blk++{-+Note [Splitting DebugBlocks]++DWARF requires that we break up the the nested DebugBlocks produced from+the C-- AST. For instance, we begin with tick trees containing nested procs.+For example,++ proc A [tick1, tick2]+ block B [tick3]+ proc C [tick4]++when producing DWARF we need to procs (which are represented in DWARF as+TAG_subprogram DIEs) to be top-level DIEs. debugSplitProcs is responsible for+this transform, pulling out the nested procs into top-level procs.++However, in doing this we need to be careful to preserve the parentage of the+nested procs. This is the reason DebugBlocks carry the dblParent field, allowing+us to reorganize the above tree as,++ proc A [tick1, tick2]+ block B [tick3]+ proc C [tick4] parent=B++Here we have annotated the new proc C with an attribute giving its original+parent, B.+-}++-- | Generate DWARF info for a procedure debug block+procToDwarf :: DynFlags -> DebugBlock -> DwarfInfo+procToDwarf df prc+ = DwarfSubprogram { dwChildren = map (blockToDwarf df) (dblBlocks prc)+ , dwName = case dblSourceTick prc of+ Just s@SourceNote{} -> sourceName s+ _otherwise -> showSDocDump df $ ppr $ dblLabel prc+ , dwLabel = dblCLabel prc+ , dwParent = fmap mkAsmTempDieLabel+ $ mfilter (/= dblCLabel prc)+ $ fmap dblCLabel (dblParent prc)+ -- Omit parent if it would be self-referential+ }++-- | Generate DWARF info for a block+blockToDwarf :: DynFlags -> DebugBlock -> DwarfInfo+blockToDwarf df blk+ = DwarfBlock { dwChildren = concatMap (tickToDwarf df) (dblTicks blk)+ ++ map (blockToDwarf df) (dblBlocks blk)+ , dwLabel = dblCLabel blk+ , dwMarker = marker+ }+ where+ marker+ | Just _ <- dblPosition blk = Just $ mkAsmTempLabel $ dblLabel blk+ | otherwise = Nothing -- block was optimized out++tickToDwarf :: DynFlags -> Tickish () -> [DwarfInfo]+tickToDwarf _ (SourceNote ss _) = [DwarfSrcNote ss]+tickToDwarf _ _ = []++-- | Generates the data for the debug frame section, which encodes the+-- desired stack unwind behaviour for the debugger+debugFrame :: Unique -> [DebugBlock] -> DwarfFrame+debugFrame u procs+ = DwarfFrame { dwCieLabel = mkAsmTempLabel u+ , dwCieInit = initUws+ , dwCieProcs = map (procToFrame initUws) procs+ }+ where+ initUws :: UnwindTable+ initUws = Map.fromList [(Sp, Just (UwReg Sp 0))]++-- | Generates unwind information for a procedure debug block+procToFrame :: UnwindTable -> DebugBlock -> DwarfFrameProc+procToFrame initUws blk+ = DwarfFrameProc { dwFdeProc = dblCLabel blk+ , dwFdeHasInfo = dblHasInfoTbl blk+ , dwFdeBlocks = map (uncurry blockToFrame)+ (setHasInfo blockUws)+ }+ where blockUws :: [(DebugBlock, [UnwindPoint])]+ blockUws = map snd $ sortBy (comparing fst) $ flatten blk++ flatten :: DebugBlock+ -> [(Int, (DebugBlock, [UnwindPoint]))]+ flatten b@DebugBlock{ dblPosition=pos, dblUnwind=uws, dblBlocks=blocks }+ | Just p <- pos = (p, (b, uws')):nested+ | otherwise = nested -- block was optimized out+ where uws' = addDefaultUnwindings initUws uws+ nested = concatMap flatten blocks++ -- | If the current procedure has an info table, then we also say that+ -- its first block has one to ensure that it gets the necessary -1+ -- offset applied to its start address.+ -- See Note [Info Offset] in Dwarf.Types.+ setHasInfo :: [(DebugBlock, [UnwindPoint])]+ -> [(DebugBlock, [UnwindPoint])]+ setHasInfo [] = []+ setHasInfo (c0:cs) = first setIt c0 : cs+ where+ setIt child =+ child { dblHasInfoTbl = dblHasInfoTbl child+ || dblHasInfoTbl blk }++blockToFrame :: DebugBlock -> [UnwindPoint] -> DwarfFrameBlock+blockToFrame blk uws+ = DwarfFrameBlock { dwFdeBlkHasInfo = dblHasInfoTbl blk+ , dwFdeUnwind = uws+ }++addDefaultUnwindings :: UnwindTable -> [UnwindPoint] -> [UnwindPoint]+addDefaultUnwindings tbl pts =+ [ UnwindPoint lbl (tbl' `mappend` tbl)+ -- mappend is left-biased+ | UnwindPoint lbl tbl' <- pts+ ]
+ nativeGen/Dwarf/Constants.hs view
@@ -0,0 +1,225 @@+-- | Constants describing the DWARF format. Most of this simply+-- mirrors /usr/include/dwarf.h.++module Dwarf.Constants where++import FastString+import Platform+import Outputable++import Reg+import X86.Regs++import Data.Word++-- | Language ID used for Haskell.+dW_LANG_Haskell :: Word+dW_LANG_Haskell = 0x18+ -- Thanks to Nathan Howell for getting us our very own language ID!++-- * Dwarf tags+dW_TAG_compile_unit, dW_TAG_subroutine_type,+ dW_TAG_file_type, dW_TAG_subprogram, dW_TAG_lexical_block,+ dW_TAG_base_type, dW_TAG_structure_type, dW_TAG_pointer_type,+ dW_TAG_array_type, dW_TAG_subrange_type, dW_TAG_typedef,+ dW_TAG_variable, dW_TAG_arg_variable, dW_TAG_auto_variable,+ dW_TAG_ghc_src_note :: Word+dW_TAG_array_type = 1+dW_TAG_lexical_block = 11+dW_TAG_pointer_type = 15+dW_TAG_compile_unit = 17+dW_TAG_structure_type = 19+dW_TAG_typedef = 22+dW_TAG_subroutine_type = 32+dW_TAG_subrange_type = 33+dW_TAG_base_type = 36+dW_TAG_file_type = 41+dW_TAG_subprogram = 46+dW_TAG_variable = 52+dW_TAG_auto_variable = 256+dW_TAG_arg_variable = 257++dW_TAG_ghc_src_note = 0x5b00++-- * Dwarf attributes+dW_AT_name, dW_AT_stmt_list, dW_AT_low_pc, dW_AT_high_pc, dW_AT_language,+ dW_AT_comp_dir, dW_AT_producer, dW_AT_external, dW_AT_frame_base,+ dW_AT_use_UTF8, dW_AT_MIPS_linkage_name :: Word+dW_AT_name = 0x03+dW_AT_stmt_list = 0x10+dW_AT_low_pc = 0x11+dW_AT_high_pc = 0x12+dW_AT_language = 0x13+dW_AT_comp_dir = 0x1b+dW_AT_producer = 0x25+dW_AT_external = 0x3f+dW_AT_frame_base = 0x40+dW_AT_use_UTF8 = 0x53+dW_AT_MIPS_linkage_name = 0x2007++-- * Custom DWARF attributes+-- Chosen a more or less random section of the vendor-extensible region++-- ** Describing C-- blocks+-- These appear in DW_TAG_lexical_scope DIEs corresponding to C-- blocks+dW_AT_ghc_tick_parent :: Word+dW_AT_ghc_tick_parent = 0x2b20++-- ** Describing source notes+-- These appear in DW_TAG_ghc_src_note DIEs+dW_AT_ghc_span_file, dW_AT_ghc_span_start_line,+ dW_AT_ghc_span_start_col, dW_AT_ghc_span_end_line,+ dW_AT_ghc_span_end_col :: Word+dW_AT_ghc_span_file = 0x2b00+dW_AT_ghc_span_start_line = 0x2b01+dW_AT_ghc_span_start_col = 0x2b02+dW_AT_ghc_span_end_line = 0x2b03+dW_AT_ghc_span_end_col = 0x2b04+++-- * Abbrev declarations+dW_CHILDREN_no, dW_CHILDREN_yes :: Word8+dW_CHILDREN_no = 0+dW_CHILDREN_yes = 1++dW_FORM_addr, dW_FORM_data2, dW_FORM_data4, dW_FORM_string, dW_FORM_flag,+ dW_FORM_block1, dW_FORM_ref4, dW_FORM_ref_addr, dW_FORM_flag_present :: Word+dW_FORM_addr = 0x01+dW_FORM_data2 = 0x05+dW_FORM_data4 = 0x06+dW_FORM_string = 0x08+dW_FORM_flag = 0x0c+dW_FORM_block1 = 0x0a+dW_FORM_ref_addr = 0x10+dW_FORM_ref4 = 0x13+dW_FORM_flag_present = 0x19++-- * Dwarf native types+dW_ATE_address, dW_ATE_boolean, dW_ATE_float, dW_ATE_signed,+ dW_ATE_signed_char, dW_ATE_unsigned, dW_ATE_unsigned_char :: Word+dW_ATE_address = 1+dW_ATE_boolean = 2+dW_ATE_float = 4+dW_ATE_signed = 5+dW_ATE_signed_char = 6+dW_ATE_unsigned = 7+dW_ATE_unsigned_char = 8++-- * Call frame information+dW_CFA_set_loc, dW_CFA_undefined, dW_CFA_same_value,+ dW_CFA_def_cfa, dW_CFA_def_cfa_offset, dW_CFA_def_cfa_expression,+ dW_CFA_expression, dW_CFA_offset_extended_sf, dW_CFA_def_cfa_offset_sf,+ dW_CFA_def_cfa_sf, dW_CFA_val_offset, dW_CFA_val_expression,+ dW_CFA_offset :: Word8+dW_CFA_set_loc = 0x01+dW_CFA_undefined = 0x07+dW_CFA_same_value = 0x08+dW_CFA_def_cfa = 0x0c+dW_CFA_def_cfa_offset = 0x0e+dW_CFA_def_cfa_expression = 0x0f+dW_CFA_expression = 0x10+dW_CFA_offset_extended_sf = 0x11+dW_CFA_def_cfa_sf = 0x12+dW_CFA_def_cfa_offset_sf = 0x13+dW_CFA_val_offset = 0x14+dW_CFA_val_expression = 0x16+dW_CFA_offset = 0x80++-- * Operations+dW_OP_addr, dW_OP_deref, dW_OP_consts,+ dW_OP_minus, dW_OP_mul, dW_OP_plus,+ dW_OP_lit0, dW_OP_breg0, dW_OP_call_frame_cfa :: Word8+dW_OP_addr = 0x03+dW_OP_deref = 0x06+dW_OP_consts = 0x11+dW_OP_minus = 0x1c+dW_OP_mul = 0x1e+dW_OP_plus = 0x22+dW_OP_lit0 = 0x30+dW_OP_breg0 = 0x70+dW_OP_call_frame_cfa = 0x9c++-- * Dwarf section declarations+dwarfInfoSection, dwarfAbbrevSection, dwarfLineSection,+ dwarfFrameSection, dwarfGhcSection, dwarfARangesSection :: SDoc+dwarfInfoSection = dwarfSection "info"+dwarfAbbrevSection = dwarfSection "abbrev"+dwarfLineSection = dwarfSection "line"+dwarfFrameSection = dwarfSection "frame"+dwarfGhcSection = dwarfSection "ghc"+dwarfARangesSection = dwarfSection "aranges"++dwarfSection :: String -> SDoc+dwarfSection name = sdocWithPlatform $ \plat -> ftext $ mkFastString $+ case platformOS plat of+ os | osElfTarget os+ -> "\t.section .debug_" ++ name ++ ",\"\",@progbits"+ | osMachOTarget os+ -> "\t.section __DWARF,__debug_" ++ name ++ ",regular,debug"+ | otherwise+ -> "\t.section .debug_" ++ name ++ ",\"dr\""++-- * Dwarf section labels+dwarfInfoLabel, dwarfAbbrevLabel, dwarfLineLabel, dwarfFrameLabel :: LitString+dwarfInfoLabel = sLit ".Lsection_info"+dwarfAbbrevLabel = sLit ".Lsection_abbrev"+dwarfLineLabel = sLit ".Lsection_line"+dwarfFrameLabel = sLit ".Lsection_frame"++-- | Mapping of registers to DWARF register numbers+dwarfRegNo :: Platform -> Reg -> Word8+dwarfRegNo p r = case platformArch p of+ ArchX86+ | r == eax -> 0+ | r == ecx -> 1 -- yes, no typo+ | r == edx -> 2+ | r == ebx -> 3+ | r == esp -> 4+ | r == ebp -> 5+ | r == esi -> 6+ | r == edi -> 7+ ArchX86_64+ | r == rax -> 0+ | r == rdx -> 1 -- this neither. The order GCC allocates registers in?+ | r == rcx -> 2+ | r == rbx -> 3+ | r == rsi -> 4+ | r == rdi -> 5+ | r == rbp -> 6+ | r == rsp -> 7+ | r == r8 -> 8+ | r == r9 -> 9+ | r == r10 -> 10+ | r == r11 -> 11+ | r == r12 -> 12+ | r == r13 -> 13+ | r == r14 -> 14+ | r == r15 -> 15+ | r == xmm0 -> 17+ | r == xmm1 -> 18+ | r == xmm2 -> 19+ | r == xmm3 -> 20+ | r == xmm4 -> 21+ | r == xmm5 -> 22+ | r == xmm6 -> 23+ | r == xmm7 -> 24+ | r == xmm8 -> 25+ | r == xmm9 -> 26+ | r == xmm10 -> 27+ | r == xmm11 -> 28+ | r == xmm12 -> 29+ | r == xmm13 -> 30+ | r == xmm14 -> 31+ | r == xmm15 -> 32+ _other -> error "dwarfRegNo: Unsupported platform or unknown register!"++-- | Virtual register number to use for return address.+dwarfReturnRegNo :: Platform -> Word8+dwarfReturnRegNo p+ -- We "overwrite" IP with our pseudo register - that makes sense, as+ -- when using this mechanism gdb already knows the IP anyway. Clang+ -- does this too, so it must be safe.+ = case platformArch p of+ ArchX86 -> 8 -- eip+ ArchX86_64 -> 16 -- rip+ _other -> error "dwarfReturnRegNo: Unsupported platform!"
+ nativeGen/Dwarf/Types.hs view
@@ -0,0 +1,602 @@+module Dwarf.Types+ ( -- * Dwarf information+ DwarfInfo(..)+ , pprDwarfInfo+ , pprAbbrevDecls+ -- * Dwarf address range table+ , DwarfARange(..)+ , pprDwarfARanges+ -- * Dwarf frame+ , DwarfFrame(..), DwarfFrameProc(..), DwarfFrameBlock(..)+ , pprDwarfFrame+ -- * Utilities+ , pprByte+ , pprHalf+ , pprData4'+ , pprDwWord+ , pprWord+ , pprLEBWord+ , pprLEBInt+ , wordAlign+ , sectionOffset+ )+ where++import Debug+import CLabel+import CmmExpr ( GlobalReg(..) )+import Encoding+import FastString+import Outputable+import Platform+import Unique+import Reg+import SrcLoc++import Dwarf.Constants++import qualified Control.Monad.Trans.State.Strict as S+import Control.Monad (zipWithM, join)+import Data.Bits+import qualified Data.Map as Map+import Data.Word+import Data.Char++import CodeGen.Platform++-- | Individual dwarf records. Each one will be encoded as an entry in+-- the @.debug_info@ section.+data DwarfInfo+ = DwarfCompileUnit { dwChildren :: [DwarfInfo]+ , dwName :: String+ , dwProducer :: String+ , dwCompDir :: String+ , dwLowLabel :: CLabel+ , dwHighLabel :: CLabel+ , dwLineLabel :: LitString }+ | DwarfSubprogram { dwChildren :: [DwarfInfo]+ , dwName :: String+ , dwLabel :: CLabel+ , dwParent :: Maybe CLabel+ -- ^ label of DIE belonging to the parent tick+ }+ | DwarfBlock { dwChildren :: [DwarfInfo]+ , dwLabel :: CLabel+ , dwMarker :: Maybe CLabel+ }+ | DwarfSrcNote { dwSrcSpan :: RealSrcSpan+ }++-- | Abbreviation codes used for encoding above records in the+-- @.debug_info@ section.+data DwarfAbbrev+ = DwAbbrNull -- ^ Pseudo, used for marking the end of lists+ | DwAbbrCompileUnit+ | DwAbbrSubprogram+ | DwAbbrSubprogramWithParent+ | DwAbbrBlockWithoutCode+ | DwAbbrBlock+ | DwAbbrGhcSrcNote+ deriving (Eq, Enum)++-- | Generate assembly for the given abbreviation code+pprAbbrev :: DwarfAbbrev -> SDoc+pprAbbrev = pprLEBWord . fromIntegral . fromEnum++-- | Abbreviation declaration. This explains the binary encoding we+-- use for representing 'DwarfInfo'. Be aware that this must be updated+-- along with 'pprDwarfInfo'.+pprAbbrevDecls :: Bool -> SDoc+pprAbbrevDecls haveDebugLine =+ let mkAbbrev abbr tag chld flds =+ let fld (tag, form) = pprLEBWord tag $$ pprLEBWord form+ in pprAbbrev abbr $$ pprLEBWord tag $$ pprByte chld $$+ vcat (map fld flds) $$ pprByte 0 $$ pprByte 0+ -- These are shared between DwAbbrSubprogram and+ -- DwAbbrSubprogramWithParent+ subprogramAttrs =+ [ (dW_AT_name, dW_FORM_string)+ , (dW_AT_MIPS_linkage_name, dW_FORM_string)+ , (dW_AT_external, dW_FORM_flag)+ , (dW_AT_low_pc, dW_FORM_addr)+ , (dW_AT_high_pc, dW_FORM_addr)+ , (dW_AT_frame_base, dW_FORM_block1)+ ]+ in dwarfAbbrevSection $$+ ptext dwarfAbbrevLabel <> colon $$+ mkAbbrev DwAbbrCompileUnit dW_TAG_compile_unit dW_CHILDREN_yes+ ([(dW_AT_name, dW_FORM_string)+ , (dW_AT_producer, dW_FORM_string)+ , (dW_AT_language, dW_FORM_data4)+ , (dW_AT_comp_dir, dW_FORM_string)+ , (dW_AT_use_UTF8, dW_FORM_flag_present) -- not represented in body+ , (dW_AT_low_pc, dW_FORM_addr)+ , (dW_AT_high_pc, dW_FORM_addr)+ ] +++ (if haveDebugLine+ then [ (dW_AT_stmt_list, dW_FORM_data4) ]+ else [])) $$+ mkAbbrev DwAbbrSubprogram dW_TAG_subprogram dW_CHILDREN_yes+ subprogramAttrs $$+ mkAbbrev DwAbbrSubprogramWithParent dW_TAG_subprogram dW_CHILDREN_yes+ (subprogramAttrs ++ [(dW_AT_ghc_tick_parent, dW_FORM_ref_addr)]) $$+ mkAbbrev DwAbbrBlockWithoutCode dW_TAG_lexical_block dW_CHILDREN_yes+ [ (dW_AT_name, dW_FORM_string)+ ] $$+ mkAbbrev DwAbbrBlock dW_TAG_lexical_block dW_CHILDREN_yes+ [ (dW_AT_name, dW_FORM_string)+ , (dW_AT_low_pc, dW_FORM_addr)+ , (dW_AT_high_pc, dW_FORM_addr)+ ] $$+ mkAbbrev DwAbbrGhcSrcNote dW_TAG_ghc_src_note dW_CHILDREN_no+ [ (dW_AT_ghc_span_file, dW_FORM_string)+ , (dW_AT_ghc_span_start_line, dW_FORM_data4)+ , (dW_AT_ghc_span_start_col, dW_FORM_data2)+ , (dW_AT_ghc_span_end_line, dW_FORM_data4)+ , (dW_AT_ghc_span_end_col, dW_FORM_data2)+ ] $$+ pprByte 0++-- | Generate assembly for DWARF data+pprDwarfInfo :: Bool -> DwarfInfo -> SDoc+pprDwarfInfo haveSrc d+ = case d of+ DwarfCompileUnit {} -> hasChildren+ DwarfSubprogram {} -> hasChildren+ DwarfBlock {} -> hasChildren+ DwarfSrcNote {} -> noChildren+ where+ hasChildren =+ pprDwarfInfoOpen haveSrc d $$+ vcat (map (pprDwarfInfo haveSrc) (dwChildren d)) $$+ pprDwarfInfoClose+ noChildren = pprDwarfInfoOpen haveSrc d++-- | Prints assembler data corresponding to DWARF info records. Note+-- that the binary format of this is parameterized in @abbrevDecls@ and+-- has to be kept in synch.+pprDwarfInfoOpen :: Bool -> DwarfInfo -> SDoc+pprDwarfInfoOpen haveSrc (DwarfCompileUnit _ name producer compDir lowLabel+ highLabel lineLbl) =+ pprAbbrev DwAbbrCompileUnit+ $$ pprString name+ $$ pprString producer+ $$ pprData4 dW_LANG_Haskell+ $$ pprString compDir+ $$ pprWord (ppr lowLabel)+ $$ pprWord (ppr highLabel)+ $$ if haveSrc+ then sectionOffset (ptext lineLbl) (ptext dwarfLineLabel)+ else empty+pprDwarfInfoOpen _ (DwarfSubprogram _ name label+ parent) = sdocWithDynFlags $ \df ->+ ppr (mkAsmTempDieLabel label) <> colon+ $$ pprAbbrev abbrev+ $$ pprString name+ $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))+ $$ pprFlag (externallyVisibleCLabel label)+ $$ pprWord (ppr label)+ $$ pprWord (ppr $ mkAsmTempEndLabel label)+ $$ pprByte 1+ $$ pprByte dW_OP_call_frame_cfa+ $$ parentValue+ where+ abbrev = case parent of Nothing -> DwAbbrSubprogram+ Just _ -> DwAbbrSubprogramWithParent+ parentValue = maybe empty pprParentDie parent+ pprParentDie sym = sectionOffset (ppr sym) (ptext dwarfInfoLabel)+pprDwarfInfoOpen _ (DwarfBlock _ label Nothing) = sdocWithDynFlags $ \df ->+ ppr (mkAsmTempDieLabel label) <> colon+ $$ pprAbbrev DwAbbrBlockWithoutCode+ $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))+pprDwarfInfoOpen _ (DwarfBlock _ label (Just marker)) = sdocWithDynFlags $ \df ->+ ppr (mkAsmTempDieLabel label) <> colon+ $$ pprAbbrev DwAbbrBlock+ $$ pprString (renderWithStyle df (ppr label) (mkCodeStyle CStyle))+ $$ pprWord (ppr marker)+ $$ pprWord (ppr $ mkAsmTempEndLabel marker)+pprDwarfInfoOpen _ (DwarfSrcNote ss) =+ pprAbbrev DwAbbrGhcSrcNote+ $$ pprString' (ftext $ srcSpanFile ss)+ $$ pprData4 (fromIntegral $ srcSpanStartLine ss)+ $$ pprHalf (fromIntegral $ srcSpanStartCol ss)+ $$ pprData4 (fromIntegral $ srcSpanEndLine ss)+ $$ pprHalf (fromIntegral $ srcSpanEndCol ss)++-- | Close a DWARF info record with children+pprDwarfInfoClose :: SDoc+pprDwarfInfoClose = pprAbbrev DwAbbrNull++-- | A DWARF address range. This is used by the debugger to quickly locate+-- which compilation unit a given address belongs to. This type assumes+-- a non-segmented address-space.+data DwarfARange+ = DwarfARange+ { dwArngStartLabel :: CLabel+ , dwArngEndLabel :: CLabel+ }++-- | Print assembler directives corresponding to a DWARF @.debug_aranges@+-- address table entry.+pprDwarfARanges :: [DwarfARange] -> Unique -> SDoc+pprDwarfARanges arngs unitU = sdocWithPlatform $ \plat ->+ let wordSize = platformWordSize plat+ paddingSize = 4 :: Int+ -- header is 12 bytes long.+ -- entry is 8 bytes (32-bit platform) or 16 bytes (64-bit platform).+ -- pad such that first entry begins at multiple of entry size.+ pad n = vcat $ replicate n $ pprByte 0+ initialLength = 8 + paddingSize + 2*2*wordSize+ in pprDwWord (ppr initialLength)+ $$ pprHalf 2+ $$ sectionOffset (ppr $ mkAsmTempLabel $ unitU)+ (ptext dwarfInfoLabel)+ $$ pprByte (fromIntegral wordSize)+ $$ pprByte 0+ $$ pad paddingSize+ -- body+ $$ vcat (map pprDwarfARange arngs)+ -- terminus+ $$ pprWord (char '0')+ $$ pprWord (char '0')++pprDwarfARange :: DwarfARange -> SDoc+pprDwarfARange arng = pprWord (ppr $ dwArngStartLabel arng) $$ pprWord length+ where+ length = ppr (dwArngEndLabel arng)+ <> char '-' <> ppr (dwArngStartLabel arng)++-- | Information about unwind instructions for a procedure. This+-- corresponds to a "Common Information Entry" (CIE) in DWARF.+data DwarfFrame+ = DwarfFrame+ { dwCieLabel :: CLabel+ , dwCieInit :: UnwindTable+ , dwCieProcs :: [DwarfFrameProc]+ }++-- | Unwind instructions for an individual procedure. Corresponds to a+-- "Frame Description Entry" (FDE) in DWARF.+data DwarfFrameProc+ = DwarfFrameProc+ { dwFdeProc :: CLabel+ , dwFdeHasInfo :: Bool+ , dwFdeBlocks :: [DwarfFrameBlock]+ -- ^ List of blocks. Order must match asm!+ }++-- | Unwind instructions for a block. Will become part of the+-- containing FDE.+data DwarfFrameBlock+ = DwarfFrameBlock+ { dwFdeBlkHasInfo :: Bool+ , dwFdeUnwind :: [UnwindPoint]+ -- ^ these unwind points must occur in the same order as they occur+ -- in the block+ }++instance Outputable DwarfFrameBlock where+ ppr (DwarfFrameBlock hasInfo unwinds) = braces $ ppr hasInfo <+> ppr unwinds++-- | Header for the @.debug_frame@ section. Here we emit the "Common+-- Information Entry" record that etablishes general call frame+-- parameters and the default stack layout.+pprDwarfFrame :: DwarfFrame -> SDoc+pprDwarfFrame DwarfFrame{dwCieLabel=cieLabel,dwCieInit=cieInit,dwCieProcs=procs}+ = sdocWithPlatform $ \plat ->+ let cieStartLabel= mkAsmTempDerivedLabel cieLabel (fsLit "_start")+ cieEndLabel = mkAsmTempEndLabel cieLabel+ length = ppr cieEndLabel <> char '-' <> ppr cieStartLabel+ spReg = dwarfGlobalRegNo plat Sp+ retReg = dwarfReturnRegNo plat+ wordSize = platformWordSize plat+ pprInit :: (GlobalReg, Maybe UnwindExpr) -> SDoc+ pprInit (g, uw) = pprSetUnwind plat g (Nothing, uw)++ -- Preserve C stack pointer: This necessary to override that default+ -- unwinding behavior of setting $sp = CFA.+ preserveSp = case platformArch plat of+ ArchX86 -> pprByte dW_CFA_same_value $$ pprLEBWord 4+ ArchX86_64 -> pprByte dW_CFA_same_value $$ pprLEBWord 7+ _ -> empty+ in vcat [ ppr cieLabel <> colon+ , pprData4' length -- Length of CIE+ , ppr cieStartLabel <> colon+ , pprData4' (text "-1")+ -- Common Information Entry marker (-1 = 0xf..f)+ , pprByte 3 -- CIE version (we require DWARF 3)+ , pprByte 0 -- Augmentation (none)+ , pprByte 1 -- Code offset multiplicator+ , pprByte (128-fromIntegral wordSize)+ -- Data offset multiplicator+ -- (stacks grow down => "-w" in signed LEB128)+ , pprByte retReg -- virtual register holding return address+ ] $$+ -- Initial unwind table+ vcat (map pprInit $ Map.toList cieInit) $$+ vcat [ -- RET = *CFA+ pprByte (dW_CFA_offset+retReg)+ , pprByte 0++ -- Preserve C stack pointer+ , preserveSp++ -- Sp' = CFA+ -- (we need to set this manually as our (STG) Sp register is+ -- often not the architecture's default stack register)+ , pprByte dW_CFA_val_offset+ , pprLEBWord (fromIntegral spReg)+ , pprLEBWord 0+ ] $$+ wordAlign $$+ ppr cieEndLabel <> colon $$+ -- Procedure unwind tables+ vcat (map (pprFrameProc cieLabel cieInit) procs)++-- | Writes a "Frame Description Entry" for a procedure. This consists+-- mainly of referencing the CIE and writing state machine+-- instructions to describe how the frame base (CFA) changes.+pprFrameProc :: CLabel -> UnwindTable -> DwarfFrameProc -> SDoc+pprFrameProc frameLbl initUw (DwarfFrameProc procLbl hasInfo blocks)+ = let fdeLabel = mkAsmTempDerivedLabel procLbl (fsLit "_fde")+ fdeEndLabel = mkAsmTempDerivedLabel procLbl (fsLit "_fde_end")+ procEnd = mkAsmTempEndLabel procLbl+ ifInfo str = if hasInfo then text str else empty+ -- see [Note: Info Offset]+ in vcat [ ifPprDebug $ text "# Unwinding for" <+> ppr procLbl <> colon+ , pprData4' (ppr fdeEndLabel <> char '-' <> ppr fdeLabel)+ , ppr fdeLabel <> colon+ , pprData4' (ppr frameLbl <> char '-' <>+ ptext dwarfFrameLabel) -- Reference to CIE+ , pprWord (ppr procLbl <> ifInfo "-1") -- Code pointer+ , pprWord (ppr procEnd <> char '-' <>+ ppr procLbl <> ifInfo "+1") -- Block byte length+ ] $$+ vcat (S.evalState (mapM pprFrameBlock blocks) initUw) $$+ wordAlign $$+ ppr fdeEndLabel <> colon++-- | Generates unwind information for a block. We only generate+-- instructions where unwind information actually changes. This small+-- optimisations saves a lot of space, as subsequent blocks often have+-- the same unwind information.+pprFrameBlock :: DwarfFrameBlock -> S.State UnwindTable SDoc+pprFrameBlock (DwarfFrameBlock hasInfo uws0) =+ vcat <$> zipWithM pprFrameDecl (True : repeat False) uws0+ where+ pprFrameDecl :: Bool -> UnwindPoint -> S.State UnwindTable SDoc+ pprFrameDecl firstDecl (UnwindPoint lbl uws) = S.state $ \oldUws ->+ let -- Did a register's unwind expression change?+ isChanged :: GlobalReg -> Maybe UnwindExpr+ -> Maybe (Maybe UnwindExpr, Maybe UnwindExpr)+ isChanged g new+ -- the value didn't change+ | Just new == old = Nothing+ -- the value was and still is undefined+ | Nothing <- old+ , Nothing <- new = Nothing+ -- the value changed+ | otherwise = Just (join old, new)+ where+ old = Map.lookup g oldUws++ changed = Map.toList $ Map.mapMaybeWithKey isChanged uws++ in if oldUws == uws+ then (empty, oldUws)+ else let -- see [Note: Info Offset]+ needsOffset = firstDecl && hasInfo+ lblDoc = ppr lbl <>+ if needsOffset then text "-1" else empty+ doc = sdocWithPlatform $ \plat ->+ pprByte dW_CFA_set_loc $$ pprWord lblDoc $$+ vcat (map (uncurry $ pprSetUnwind plat) changed)+ in (doc, uws)++-- Note [Info Offset]+--+-- GDB was pretty much written with C-like programs in mind, and as a+-- result they assume that once you have a return address, it is a+-- good idea to look at (PC-1) to unwind further - as that's where the+-- "call" instruction is supposed to be.+--+-- Now on one hand, code generated by GHC looks nothing like what GDB+-- expects, and in fact going up from a return pointer is guaranteed+-- to land us inside an info table! On the other hand, that actually+-- gives us some wiggle room, as we expect IP to never *actually* end+-- up inside the info table, so we can "cheat" by putting whatever GDB+-- expects to see there. This is probably pretty safe, as GDB cannot+-- assume (PC-1) to be a valid code pointer in the first place - and I+-- have seen no code trying to correct this.+--+-- Note that this will not prevent GDB from failing to look-up the+-- correct function name for the frame, as that uses the symbol table,+-- which we can not manipulate as easily.++-- | Get DWARF register ID for a given GlobalReg+dwarfGlobalRegNo :: Platform -> GlobalReg -> Word8+dwarfGlobalRegNo p UnwindReturnReg = dwarfReturnRegNo p+dwarfGlobalRegNo p reg = maybe 0 (dwarfRegNo p . RegReal) $ globalRegMaybe p reg++-- | Generate code for setting the unwind information for a register,+-- optimized using its known old value in the table. Note that "Sp" is+-- special: We see it as synonym for the CFA.+pprSetUnwind :: Platform+ -> GlobalReg+ -- ^ the register to produce an unwinding table entry for+ -> (Maybe UnwindExpr, Maybe UnwindExpr)+ -- ^ the old and new values of the register+ -> SDoc+pprSetUnwind plat g (_, Nothing)+ = pprUndefUnwind plat g+pprSetUnwind _ Sp (Just (UwReg s _), Just (UwReg s' o')) | s == s'+ = if o' >= 0+ then pprByte dW_CFA_def_cfa_offset $$ pprLEBWord (fromIntegral o')+ else pprByte dW_CFA_def_cfa_offset_sf $$ pprLEBInt o'+pprSetUnwind plat Sp (_, Just (UwReg s' o'))+ = if o' >= 0+ then pprByte dW_CFA_def_cfa $$+ pprLEBRegNo plat s' $$+ pprLEBWord (fromIntegral o')+ else pprByte dW_CFA_def_cfa_sf $$+ pprLEBRegNo plat s' $$+ pprLEBInt o'+pprSetUnwind _ Sp (_, Just uw)+ = pprByte dW_CFA_def_cfa_expression $$ pprUnwindExpr False uw+pprSetUnwind plat g (_, Just (UwDeref (UwReg Sp o)))+ | o < 0 && ((-o) `mod` platformWordSize plat) == 0 -- expected case+ = pprByte (dW_CFA_offset + dwarfGlobalRegNo plat g) $$+ pprLEBWord (fromIntegral ((-o) `div` platformWordSize plat))+ | otherwise+ = pprByte dW_CFA_offset_extended_sf $$+ pprLEBRegNo plat g $$+ pprLEBInt o+pprSetUnwind plat g (_, Just (UwDeref uw))+ = pprByte dW_CFA_expression $$+ pprLEBRegNo plat g $$+ pprUnwindExpr True uw+pprSetUnwind plat g (_, Just (UwReg g' 0))+ | g == g'+ = pprByte dW_CFA_same_value $$+ pprLEBRegNo plat g+pprSetUnwind plat g (_, Just uw)+ = pprByte dW_CFA_val_expression $$+ pprLEBRegNo plat g $$+ pprUnwindExpr True uw++-- | Print the register number of the given 'GlobalReg' as an unsigned LEB128+-- encoded number.+pprLEBRegNo :: Platform -> GlobalReg -> SDoc+pprLEBRegNo plat = pprLEBWord . fromIntegral . dwarfGlobalRegNo plat++-- | Generates a DWARF expression for the given unwind expression. If+-- @spIsCFA@ is true, we see @Sp@ as the frame base CFA where it gets+-- mentioned.+pprUnwindExpr :: Bool -> UnwindExpr -> SDoc+pprUnwindExpr spIsCFA expr+ = sdocWithPlatform $ \plat ->+ let pprE (UwConst i)+ | i >= 0 && i < 32 = pprByte (dW_OP_lit0 + fromIntegral i)+ | otherwise = pprByte dW_OP_consts $$ pprLEBInt i -- lazy...+ pprE (UwReg Sp i) | spIsCFA+ = if i == 0+ then pprByte dW_OP_call_frame_cfa+ else pprE (UwPlus (UwReg Sp 0) (UwConst i))+ pprE (UwReg g i) = pprByte (dW_OP_breg0+dwarfGlobalRegNo plat g) $$+ pprLEBInt i+ pprE (UwDeref u) = pprE u $$ pprByte dW_OP_deref+ pprE (UwLabel l) = pprByte dW_OP_addr $$ pprWord (ppr l)+ pprE (UwPlus u1 u2) = pprE u1 $$ pprE u2 $$ pprByte dW_OP_plus+ pprE (UwMinus u1 u2) = pprE u1 $$ pprE u2 $$ pprByte dW_OP_minus+ pprE (UwTimes u1 u2) = pprE u1 $$ pprE u2 $$ pprByte dW_OP_mul+ in text "\t.uleb128 1f-.-1" $$ -- DW_FORM_block length+ pprE expr $$+ text "1:"++-- | Generate code for re-setting the unwind information for a+-- register to @undefined@+pprUndefUnwind :: Platform -> GlobalReg -> SDoc+pprUndefUnwind plat g = pprByte dW_CFA_undefined $$+ pprLEBRegNo plat g+++-- | Align assembly at (machine) word boundary+wordAlign :: SDoc+wordAlign = sdocWithPlatform $ \plat ->+ text "\t.align " <> case platformOS plat of+ OSDarwin -> case platformWordSize plat of+ 8 -> text "3"+ 4 -> text "2"+ _other -> error "wordAlign: Unsupported word size!"+ _other -> ppr (platformWordSize plat)++-- | Assembly for a single byte of constant DWARF data+pprByte :: Word8 -> SDoc+pprByte x = text "\t.byte " <> ppr (fromIntegral x :: Word)++-- | Assembly for a two-byte constant integer+pprHalf :: Word16 -> SDoc+pprHalf x = text "\t.short" <+> ppr (fromIntegral x :: Word)++-- | Assembly for a constant DWARF flag+pprFlag :: Bool -> SDoc+pprFlag f = pprByte (if f then 0xff else 0x00)++-- | Assembly for 4 bytes of dynamic DWARF data+pprData4' :: SDoc -> SDoc+pprData4' x = text "\t.long " <> x++-- | Assembly for 4 bytes of constant DWARF data+pprData4 :: Word -> SDoc+pprData4 = pprData4' . ppr++-- | Assembly for a DWARF word of dynamic data. This means 32 bit, as+-- we are generating 32 bit DWARF.+pprDwWord :: SDoc -> SDoc+pprDwWord = pprData4'++-- | Assembly for a machine word of dynamic data. Depends on the+-- architecture we are currently generating code for.+pprWord :: SDoc -> SDoc+pprWord s = (<> s) . sdocWithPlatform $ \plat ->+ case platformWordSize plat of+ 4 -> text "\t.long "+ 8 -> text "\t.quad "+ n -> panic $ "pprWord: Unsupported target platform word length " +++ show n ++ "!"++-- | Prints a number in "little endian base 128" format. The idea is+-- to optimize for small numbers by stopping once all further bytes+-- would be 0. The highest bit in every byte signals whether there+-- are further bytes to read.+pprLEBWord :: Word -> SDoc+pprLEBWord x | x < 128 = pprByte (fromIntegral x)+ | otherwise = pprByte (fromIntegral $ 128 .|. (x .&. 127)) $$+ pprLEBWord (x `shiftR` 7)++-- | Same as @pprLEBWord@, but for a signed number+pprLEBInt :: Int -> SDoc+pprLEBInt x | x >= -64 && x < 64+ = pprByte (fromIntegral (x .&. 127))+ | otherwise = pprByte (fromIntegral $ 128 .|. (x .&. 127)) $$+ pprLEBInt (x `shiftR` 7)++-- | Generates a dynamic null-terminated string. If required the+-- caller needs to make sure that the string is escaped properly.+pprString' :: SDoc -> SDoc+pprString' str = text "\t.asciz \"" <> str <> char '"'++-- | Generate a string constant. We take care to escape the string.+pprString :: String -> SDoc+pprString str+ = pprString' $ hcat $ map escapeChar $+ if utf8EncodedLength str == length str+ then str+ else map (chr . fromIntegral) $ bytesFS $ mkFastString str++-- | Escape a single non-unicode character+escapeChar :: Char -> SDoc+escapeChar '\\' = text "\\\\"+escapeChar '\"' = text "\\\""+escapeChar '\n' = text "\\n"+escapeChar c+ | isAscii c && isPrint c && c /= '?' -- prevents trigraph warnings+ = char c+ | otherwise+ = char '\\' <> char (intToDigit (ch `div` 64)) <>+ char (intToDigit ((ch `div` 8) `mod` 8)) <>+ char (intToDigit (ch `mod` 8))+ where ch = ord c++-- | Generate an offset into another section. This is tricky because+-- this is handled differently depending on platform: Mac Os expects+-- us to calculate the offset using assembler arithmetic. Linux expects+-- us to just reference the target directly, and will figure out on+-- their own that we actually need an offset. Finally, Windows has+-- a special directive to refer to relative offsets. Fun.+sectionOffset :: SDoc -> SDoc -> SDoc+sectionOffset target section = sdocWithPlatform $ \plat ->+ case platformOS plat of+ OSDarwin -> pprDwWord (target <> char '-' <> section)+ OSMinGW32 -> text "\t.secrel32 " <> target+ _other -> pprDwWord target
+ nativeGen/Format.hs view
@@ -0,0 +1,104 @@+-- | Formats on this architecture+-- A Format is a combination of width and class+--+-- TODO: Signed vs unsigned?+--+-- TODO: This module is currenly shared by all architectures because+-- NCGMonad need to know about it to make a VReg. It would be better+-- to have architecture specific formats, and do the overloading+-- properly. eg SPARC doesn't care about FF80.+--+module Format (+ Format(..),+ intFormat,+ floatFormat,+ isFloatFormat,+ cmmTypeFormat,+ formatToWidth,+ formatInBytes+)++where++import Cmm+import Outputable++-- It looks very like the old MachRep, but it's now of purely local+-- significance, here in the native code generator. You can change it+-- without global consequences.+--+-- A major use is as an opcode qualifier; thus the opcode+-- mov.l a b+-- might be encoded+-- MOV II32 a b+-- where the Format field encodes the ".l" part.++-- ToDo: it's not clear to me that we need separate signed-vs-unsigned formats+-- here. I've removed them from the x86 version, we'll see what happens --SDM++-- ToDo: quite a few occurrences of Format could usefully be replaced by Width++data Format+ = II8+ | II16+ | II32+ | II64+ | FF32+ | FF64+ | FF80+ deriving (Show, Eq)+++-- | Get the integer format of this width.+intFormat :: Width -> Format+intFormat width+ = case width of+ W8 -> II8+ W16 -> II16+ W32 -> II32+ W64 -> II64+ other -> sorry $ "The native code generator cannot " +++ "produce code for Format.intFormat " ++ show other+ ++ "\n\tConsider using the llvm backend with -fllvm"+++-- | Get the float format of this width.+floatFormat :: Width -> Format+floatFormat width+ = case width of+ W32 -> FF32+ W64 -> FF64+ other -> pprPanic "Format.floatFormat" (ppr other)+++-- | Check if a format represents a floating point value.+isFloatFormat :: Format -> Bool+isFloatFormat format+ = case format of+ FF32 -> True+ FF64 -> True+ FF80 -> True+ _ -> False+++-- | Convert a Cmm type to a Format.+cmmTypeFormat :: CmmType -> Format+cmmTypeFormat ty+ | isFloatType ty = floatFormat (typeWidth ty)+ | otherwise = intFormat (typeWidth ty)+++-- | Get the Width of a Format.+formatToWidth :: Format -> Width+formatToWidth format+ = case format of+ II8 -> W8+ II16 -> W16+ II32 -> W32+ II64 -> W64+ FF32 -> W32+ FF64 -> W64+ FF80 -> W80++formatInBytes :: Format -> Int+formatInBytes = widthInBytes . formatToWidth
+ nativeGen/Instruction.hs view
@@ -0,0 +1,201 @@++module Instruction (+ RegUsage(..),+ noUsage,+ GenBasicBlock(..), blockId,+ ListGraph(..),+ NatCmm,+ NatCmmDecl,+ NatBasicBlock,+ topInfoTable,+ entryBlocks,+ Instruction(..)+)++where++import Reg++import BlockId+import Hoopl+import DynFlags+import Cmm hiding (topInfoTable)+import Platform++-- | Holds a list of source and destination registers used by a+-- particular instruction.+--+-- Machine registers that are pre-allocated to stgRegs are filtered+-- out, because they are uninteresting from a register allocation+-- standpoint. (We wouldn't want them to end up on the free list!)+--+-- As far as we are concerned, the fixed registers simply don't exist+-- (for allocation purposes, anyway).+--+data RegUsage+ = RU [Reg] [Reg]++-- | No regs read or written to.+noUsage :: RegUsage+noUsage = RU [] []++-- Our flavours of the Cmm types+-- Type synonyms for Cmm populated with native code+type NatCmm instr+ = GenCmmGroup+ CmmStatics+ (LabelMap CmmStatics)+ (ListGraph instr)++type NatCmmDecl statics instr+ = GenCmmDecl+ statics+ (LabelMap CmmStatics)+ (ListGraph instr)+++type NatBasicBlock instr+ = GenBasicBlock instr+++-- | Returns the info table associated with the CmmDecl's entry point,+-- if any.+topInfoTable :: GenCmmDecl a (LabelMap i) (ListGraph b) -> Maybe i+topInfoTable (CmmProc infos _ _ (ListGraph (b:_)))+ = mapLookup (blockId b) infos+topInfoTable _+ = Nothing++-- | Return the list of BlockIds in a CmmDecl that are entry points+-- for this proc (i.e. they may be jumped to from outside this proc).+entryBlocks :: GenCmmDecl a (LabelMap i) (ListGraph b) -> [BlockId]+entryBlocks (CmmProc info _ _ (ListGraph code)) = entries+ where+ infos = mapKeys info+ entries = case code of+ [] -> infos+ BasicBlock entry _ : _ -- first block is the entry point+ | entry `elem` infos -> infos+ | otherwise -> entry : infos+entryBlocks _ = []++-- | Common things that we can do with instructions, on all architectures.+-- These are used by the shared parts of the native code generator,+-- specifically the register allocators.+--+class Instruction instr where++ -- | Get the registers that are being used by this instruction.+ -- regUsage doesn't need to do any trickery for jumps and such.+ -- Just state precisely the regs read and written by that insn.+ -- The consequences of control flow transfers, as far as register+ -- allocation goes, are taken care of by the register allocator.+ --+ regUsageOfInstr+ :: Platform+ -> instr+ -> RegUsage+++ -- | Apply a given mapping to all the register references in this+ -- instruction.+ patchRegsOfInstr+ :: instr+ -> (Reg -> Reg)+ -> instr+++ -- | Checks whether this instruction is a jump/branch instruction.+ -- One that can change the flow of control in a way that the+ -- register allocator needs to worry about.+ isJumpishInstr+ :: instr -> Bool+++ -- | Give the possible destinations of this jump instruction.+ -- Must be defined for all jumpish instructions.+ jumpDestsOfInstr+ :: instr -> [BlockId]+++ -- | Change the destination of this jump instruction.+ -- Used in the linear allocator when adding fixup blocks for join+ -- points.+ patchJumpInstr+ :: instr+ -> (BlockId -> BlockId)+ -> instr+++ -- | An instruction to spill a register into a spill slot.+ mkSpillInstr+ :: DynFlags+ -> Reg -- ^ the reg to spill+ -> Int -- ^ the current stack delta+ -> Int -- ^ spill slot to use+ -> instr+++ -- | An instruction to reload a register from a spill slot.+ mkLoadInstr+ :: DynFlags+ -> Reg -- ^ the reg to reload.+ -> Int -- ^ the current stack delta+ -> Int -- ^ the spill slot to use+ -> instr++ -- | See if this instruction is telling us the current C stack delta+ takeDeltaInstr+ :: instr+ -> Maybe Int++ -- | Check whether this instruction is some meta thing inserted into+ -- the instruction stream for other purposes.+ --+ -- Not something that has to be treated as a real machine instruction+ -- and have its registers allocated.+ --+ -- eg, comments, delta, ldata, etc.+ isMetaInstr+ :: instr+ -> Bool++++ -- | Copy the value in a register to another one.+ -- Must work for all register classes.+ mkRegRegMoveInstr+ :: Platform+ -> Reg -- ^ source register+ -> Reg -- ^ destination register+ -> instr++ -- | Take the source and destination from this reg -> reg move instruction+ -- or Nothing if it's not one+ takeRegRegMoveInstr+ :: instr+ -> Maybe (Reg, Reg)++ -- | Make an unconditional jump instruction.+ -- For architectures with branch delay slots, its ok to put+ -- a NOP after the jump. Don't fill the delay slot with an+ -- instruction that references regs or you'll confuse the+ -- linear allocator.+ mkJumpInstr+ :: BlockId+ -> [instr]+++ -- Subtract an amount from the C stack pointer+ mkStackAllocInstr+ :: Platform -- TODO: remove (needed by x86/x86_64+ -- because they share an Instr type)+ -> Int+ -> instr++ -- Add an amount to the C stack pointer+ mkStackDeallocInstr+ :: Platform -- TODO: remove (needed by x86/x86_64+ -- because they share an Instr type)+ -> Int+ -> instr
+ nativeGen/NCG.h view
@@ -0,0 +1,14 @@+/* -----------------------------------------------------------------------------++ (c) The University of Glasgow, 1994-2004++ Native-code generator header file - just useful macros for now.++ -------------------------------------------------------------------------- */++#ifndef NCG_H+#define NCG_H++#include "ghc_boot_platform.h"++#endif
+ nativeGen/NCGMonad.hs view
@@ -0,0 +1,211 @@+{-# LANGUAGE CPP #-}++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 1993-2004+--+-- The native code generator's monad.+--+-- -----------------------------------------------------------------------------++module NCGMonad (+ NatM_State(..), mkNatM_State,++ NatM, -- instance Monad+ initNat,+ addImportNat,+ getUniqueNat,+ mapAccumLNat,+ setDeltaNat,+ getDeltaNat,+ getThisModuleNat,+ getBlockIdNat,+ getNewLabelNat,+ getNewRegNat,+ getNewRegPairNat,+ getPicBaseMaybeNat,+ getPicBaseNat,+ getDynFlags,+ getModLoc,+ getFileId,+ getDebugBlock,++ DwarfFiles+)++where++#include "HsVersions.h"++import Reg+import Format+import TargetReg++import BlockId+import Hoopl+import CLabel ( CLabel, mkAsmTempLabel )+import Debug+import FastString ( FastString )+import UniqFM+import UniqSupply+import Unique ( Unique )+import DynFlags+import Module++import Control.Monad ( liftM, ap )++import Compiler.Hoopl ( LabelMap, Label )++data NatM_State+ = NatM_State {+ natm_us :: UniqSupply,+ natm_delta :: Int,+ natm_imports :: [(CLabel)],+ natm_pic :: Maybe Reg,+ natm_dflags :: DynFlags,+ natm_this_module :: Module,+ natm_modloc :: ModLocation,+ natm_fileid :: DwarfFiles,+ natm_debug_map :: LabelMap DebugBlock+ }++type DwarfFiles = UniqFM (FastString, Int)++newtype NatM result = NatM (NatM_State -> (result, NatM_State))++unNat :: NatM a -> NatM_State -> (a, NatM_State)+unNat (NatM a) = a++mkNatM_State :: UniqSupply -> Int -> DynFlags -> Module -> ModLocation ->+ DwarfFiles -> LabelMap DebugBlock -> NatM_State+mkNatM_State us delta dflags this_mod+ = NatM_State us delta [] Nothing dflags this_mod++initNat :: NatM_State -> NatM a -> (a, NatM_State)+initNat init_st m+ = case unNat m init_st of { (r,st) -> (r,st) }++instance Functor NatM where+ fmap = liftM++instance Applicative NatM where+ pure = returnNat+ (<*>) = ap++instance Monad NatM where+ (>>=) = thenNat++instance MonadUnique NatM where+ getUniqueSupplyM = NatM $ \st ->+ case splitUniqSupply (natm_us st) of+ (us1, us2) -> (us1, st {natm_us = us2})++ getUniqueM = NatM $ \st ->+ case takeUniqFromSupply (natm_us st) of+ (uniq, us') -> (uniq, st {natm_us = us'})++thenNat :: NatM a -> (a -> NatM b) -> NatM b+thenNat expr cont+ = NatM $ \st -> case unNat expr st of+ (result, st') -> unNat (cont result) st'++returnNat :: a -> NatM a+returnNat result+ = NatM $ \st -> (result, st)++mapAccumLNat :: (acc -> x -> NatM (acc, y))+ -> acc+ -> [x]+ -> NatM (acc, [y])++mapAccumLNat _ b []+ = return (b, [])+mapAccumLNat f b (x:xs)+ = do (b__2, x__2) <- f b x+ (b__3, xs__2) <- mapAccumLNat f b__2 xs+ return (b__3, x__2:xs__2)++getUniqueNat :: NatM Unique+getUniqueNat = NatM $ \ st ->+ case takeUniqFromSupply $ natm_us st of+ (uniq, us') -> (uniq, st {natm_us = us'})++instance HasDynFlags NatM where+ getDynFlags = NatM $ \ st -> (natm_dflags st, st)+++getDeltaNat :: NatM Int+getDeltaNat = NatM $ \ st -> (natm_delta st, st)+++setDeltaNat :: Int -> NatM ()+setDeltaNat delta = NatM $ \ st -> ((), st {natm_delta = delta})+++getThisModuleNat :: NatM Module+getThisModuleNat = NatM $ \ st -> (natm_this_module st, st)+++addImportNat :: CLabel -> NatM ()+addImportNat imp+ = NatM $ \ st -> ((), st {natm_imports = imp : natm_imports st})+++getBlockIdNat :: NatM BlockId+getBlockIdNat+ = do u <- getUniqueNat+ return (mkBlockId u)+++getNewLabelNat :: NatM CLabel+getNewLabelNat+ = do u <- getUniqueNat+ return (mkAsmTempLabel u)+++getNewRegNat :: Format -> NatM Reg+getNewRegNat rep+ = do u <- getUniqueNat+ dflags <- getDynFlags+ return (RegVirtual $ targetMkVirtualReg (targetPlatform dflags) u rep)+++getNewRegPairNat :: Format -> NatM (Reg,Reg)+getNewRegPairNat rep+ = do u <- getUniqueNat+ dflags <- getDynFlags+ let vLo = targetMkVirtualReg (targetPlatform dflags) u rep+ let lo = RegVirtual $ targetMkVirtualReg (targetPlatform dflags) u rep+ let hi = RegVirtual $ getHiVirtualRegFromLo vLo+ return (lo, hi)+++getPicBaseMaybeNat :: NatM (Maybe Reg)+getPicBaseMaybeNat+ = NatM (\state -> (natm_pic state, state))+++getPicBaseNat :: Format -> NatM Reg+getPicBaseNat rep+ = do mbPicBase <- getPicBaseMaybeNat+ case mbPicBase of+ Just picBase -> return picBase+ Nothing+ -> do+ reg <- getNewRegNat rep+ NatM (\state -> (reg, state { natm_pic = Just reg }))++getModLoc :: NatM ModLocation+getModLoc+ = NatM $ \ st -> (natm_modloc st, st)++getFileId :: FastString -> NatM Int+getFileId f = NatM $ \st ->+ case lookupUFM (natm_fileid st) f of+ Just (_,n) -> (n, st)+ Nothing -> let n = 1 + sizeUFM (natm_fileid st)+ fids = addToUFM (natm_fileid st) f (f,n)+ in n `seq` fids `seq` (n, st { natm_fileid = fids })++getDebugBlock :: Label -> NatM (Maybe DebugBlock)+getDebugBlock l = NatM $ \st -> (mapLookup l (natm_debug_map st), st)
+ nativeGen/PIC.hs view
@@ -0,0 +1,898 @@+{-+ This module handles generation of position independent code and+ dynamic-linking related issues for the native code generator.++ This depends both the architecture and OS, so we define it here+ instead of in one of the architecture specific modules.++ Things outside this module which are related to this:++ + module CLabel+ - PIC base label (pretty printed as local label 1)+ - DynamicLinkerLabels - several kinds:+ CodeStub, SymbolPtr, GotSymbolPtr, GotSymbolOffset+ - labelDynamic predicate+ + module Cmm+ - The GlobalReg datatype has a PicBaseReg constructor+ - The CmmLit datatype has a CmmLabelDiffOff constructor+ + codeGen & RTS+ - When tablesNextToCode, no absolute addresses are stored in info tables+ any more. Instead, offsets from the info label are used.+ - For Win32 only, SRTs might contain addresses of __imp_ symbol pointers+ because Win32 doesn't support external references in data sections.+ TODO: make sure this still works, it might be bitrotted+ + NCG+ - The cmmToCmm pass in AsmCodeGen calls cmmMakeDynamicReference for all+ labels.+ - nativeCodeGen calls pprImportedSymbol and pprGotDeclaration to output+ all the necessary stuff for imported symbols.+ - The NCG monad keeps track of a list of imported symbols.+ - MachCodeGen invokes initializePicBase to generate code to initialize+ the PIC base register when needed.+ - MachCodeGen calls cmmMakeDynamicReference whenever it uses a CLabel+ that wasn't in the original Cmm code (e.g. floating point literals).+-}++module PIC (+ cmmMakeDynamicReference,+ CmmMakeDynamicReferenceM(..),+ ReferenceKind(..),+ needImportedSymbols,+ pprImportedSymbol,+ pprGotDeclaration,++ initializePicBase_ppc,+ initializePicBase_x86+)++where++import qualified PPC.Instr as PPC+import qualified PPC.Regs as PPC++import qualified X86.Instr as X86++import Platform+import Instruction+import Reg+import NCGMonad+++import Hoopl+import Cmm+import CLabel ( CLabel, ForeignLabelSource(..), pprCLabel,+ mkDynamicLinkerLabel, DynamicLinkerLabelInfo(..),+ dynamicLinkerLabelInfo, mkPicBaseLabel,+ labelDynamic, externallyVisibleCLabel )++import CLabel ( mkForeignLabel )+++import BasicTypes+import Module++import Outputable++import DynFlags+import FastString++++--------------------------------------------------------------------------------+-- It gets called by the cmmToCmm pass for every CmmLabel in the Cmm+-- code. It does The Right Thing(tm) to convert the CmmLabel into a+-- position-independent, dynamic-linking-aware reference to the thing+-- in question.+-- Note that this also has to be called from MachCodeGen in order to+-- access static data like floating point literals (labels that were+-- created after the cmmToCmm pass).+-- The function must run in a monad that can keep track of imported symbols+-- A function for recording an imported symbol must be passed in:+-- - addImportCmmOpt for the CmmOptM monad+-- - addImportNat for the NatM monad.++data ReferenceKind+ = DataReference+ | CallReference+ | JumpReference+ deriving(Eq)++class Monad m => CmmMakeDynamicReferenceM m where+ addImport :: CLabel -> m ()+ getThisModule :: m Module++instance CmmMakeDynamicReferenceM NatM where+ addImport = addImportNat+ getThisModule = getThisModuleNat++cmmMakeDynamicReference+ :: CmmMakeDynamicReferenceM m+ => DynFlags+ -> ReferenceKind -- whether this is the target of a jump+ -> CLabel -- the label+ -> m CmmExpr++cmmMakeDynamicReference dflags referenceKind lbl+ | Just _ <- dynamicLinkerLabelInfo lbl+ = return $ CmmLit $ CmmLabel lbl -- already processed it, pass through++ | otherwise+ = do this_mod <- getThisModule+ case howToAccessLabel+ dflags+ (platformArch $ targetPlatform dflags)+ (platformOS $ targetPlatform dflags)+ this_mod+ referenceKind lbl of++ AccessViaStub -> do+ let stub = mkDynamicLinkerLabel CodeStub lbl+ addImport stub+ return $ CmmLit $ CmmLabel stub++ AccessViaSymbolPtr -> do+ let symbolPtr = mkDynamicLinkerLabel SymbolPtr lbl+ addImport symbolPtr+ return $ CmmLoad (cmmMakePicReference dflags symbolPtr) (bWord dflags)++ AccessDirectly -> case referenceKind of+ -- for data, we might have to make some calculations:+ DataReference -> return $ cmmMakePicReference dflags lbl+ -- all currently supported processors support+ -- PC-relative branch and call instructions,+ -- so just jump there if it's a call or a jump+ _ -> return $ CmmLit $ CmmLabel lbl+++-- -----------------------------------------------------------------------------+-- Create a position independent reference to a label.+-- (but do not bother with dynamic linking).+-- We calculate the label's address by adding some (platform-dependent)+-- offset to our base register; this offset is calculated by+-- the function picRelative in the platform-dependent part below.++cmmMakePicReference :: DynFlags -> CLabel -> CmmExpr+cmmMakePicReference dflags lbl++ -- Windows doesn't need PIC,+ -- everything gets relocated at runtime+ | OSMinGW32 <- platformOS $ targetPlatform dflags+ = CmmLit $ CmmLabel lbl++ | OSAIX <- platformOS $ targetPlatform dflags+ = CmmMachOp (MO_Add W32)+ [ CmmReg (CmmGlobal PicBaseReg)+ , CmmLit $ picRelative+ (platformArch $ targetPlatform dflags)+ (platformOS $ targetPlatform dflags)+ lbl ]++ -- both ABI versions default to medium code model+ | ArchPPC_64 _ <- platformArch $ targetPlatform dflags+ = CmmMachOp (MO_Add W32) -- code model medium+ [ CmmReg (CmmGlobal PicBaseReg)+ , CmmLit $ picRelative+ (platformArch $ targetPlatform dflags)+ (platformOS $ targetPlatform dflags)+ lbl ]++ | (gopt Opt_PIC dflags || WayDyn `elem` ways dflags) && absoluteLabel lbl+ = CmmMachOp (MO_Add (wordWidth dflags))+ [ CmmReg (CmmGlobal PicBaseReg)+ , CmmLit $ picRelative+ (platformArch $ targetPlatform dflags)+ (platformOS $ targetPlatform dflags)+ lbl ]++ | otherwise+ = CmmLit $ CmmLabel lbl+++absoluteLabel :: CLabel -> Bool+absoluteLabel lbl+ = case dynamicLinkerLabelInfo lbl of+ Just (GotSymbolPtr, _) -> False+ Just (GotSymbolOffset, _) -> False+ _ -> True+++--------------------------------------------------------------------------------+-- Knowledge about how special dynamic linker labels like symbol+-- pointers, code stubs and GOT offsets look like is located in the+-- module CLabel.++-- We have to decide which labels need to be accessed+-- indirectly or via a piece of stub code.+data LabelAccessStyle+ = AccessViaStub+ | AccessViaSymbolPtr+ | AccessDirectly++howToAccessLabel+ :: DynFlags -> Arch -> OS -> Module -> ReferenceKind -> CLabel -> LabelAccessStyle+++-- Windows+-- In Windows speak, a "module" is a set of objects linked into the+-- same Portable Exectuable (PE) file. (both .exe and .dll files are PEs).+--+-- If we're compiling a multi-module program then symbols from other modules+-- are accessed by a symbol pointer named __imp_SYMBOL. At runtime we have the+-- following.+--+-- (in the local module)+-- __imp_SYMBOL: addr of SYMBOL+--+-- (in the other module)+-- SYMBOL: the real function / data.+--+-- To access the function at SYMBOL from our local module, we just need to+-- dereference the local __imp_SYMBOL.+--+-- If not compiling with -dynamic we assume that all our code will be linked+-- into the same .exe file. In this case we always access symbols directly,+-- and never use __imp_SYMBOL.+--+howToAccessLabel dflags _ OSMinGW32 this_mod _ lbl++ -- Assume all symbols will be in the same PE, so just access them directly.+ | WayDyn `notElem` ways dflags+ = AccessDirectly++ -- If the target symbol is in another PE we need to access it via the+ -- appropriate __imp_SYMBOL pointer.+ | labelDynamic dflags this_mod lbl+ = AccessViaSymbolPtr++ -- Target symbol is in the same PE as the caller, so just access it directly.+ | otherwise+ = AccessDirectly+++-- Mach-O (Darwin, Mac OS X)+--+-- Indirect access is required in the following cases:+-- * things imported from a dynamic library+-- * (not on x86_64) data from a different module, if we're generating PIC code+-- It is always possible to access something indirectly,+-- even when it's not necessary.+--+howToAccessLabel dflags arch OSDarwin this_mod DataReference lbl+ -- data access to a dynamic library goes via a symbol pointer+ | labelDynamic dflags this_mod lbl+ = AccessViaSymbolPtr++ -- when generating PIC code, all cross-module data references must+ -- must go via a symbol pointer, too, because the assembler+ -- cannot generate code for a label difference where one+ -- label is undefined. Doesn't apply t x86_64.+ -- Unfortunately, we don't know whether it's cross-module,+ -- so we do it for all externally visible labels.+ -- This is a slight waste of time and space, but otherwise+ -- we'd need to pass the current Module all the way in to+ -- this function.+ | arch /= ArchX86_64+ , gopt Opt_PIC dflags && externallyVisibleCLabel lbl+ = AccessViaSymbolPtr++ | otherwise+ = AccessDirectly++howToAccessLabel dflags arch OSDarwin this_mod JumpReference lbl+ -- dyld code stubs don't work for tailcalls because the+ -- stack alignment is only right for regular calls.+ -- Therefore, we have to go via a symbol pointer:+ | arch == ArchX86 || arch == ArchX86_64+ , labelDynamic dflags this_mod lbl+ = AccessViaSymbolPtr+++howToAccessLabel dflags arch OSDarwin this_mod _ lbl+ -- Code stubs are the usual method of choice for imported code;+ -- not needed on x86_64 because Apple's new linker, ld64, generates+ -- them automatically.+ | arch /= ArchX86_64+ , labelDynamic dflags this_mod lbl+ = AccessViaStub++ | otherwise+ = AccessDirectly+++----------------------------------------------------------------------------+-- AIX++-- quite simple (for now)+howToAccessLabel _dflags _arch OSAIX _this_mod kind _lbl+ = case kind of+ DataReference -> AccessViaSymbolPtr+ CallReference -> AccessDirectly+ JumpReference -> AccessDirectly++-- ELF (Linux)+--+-- ELF tries to pretend to the main application code that dynamic linking does+-- not exist. While this may sound convenient, it tends to mess things up in+-- very bad ways, so we have to be careful when we generate code for the main+-- program (-dynamic but no -fPIC).+--+-- Indirect access is required for references to imported symbols+-- from position independent code. It is also required from the main program+-- when dynamic libraries containing Haskell code are used.++howToAccessLabel _ (ArchPPC_64 _) os _ kind _+ | osElfTarget os+ = case kind of+ -- ELF PPC64 (powerpc64-linux), AIX, MacOS 9, BeOS/PPC+ DataReference -> AccessViaSymbolPtr+ -- RTLD does not generate stubs for function descriptors+ -- in tail calls. Create a symbol pointer and generate+ -- the code to load the function descriptor at the call site.+ JumpReference -> AccessViaSymbolPtr+ -- regular calls are handled by the runtime linker+ _ -> AccessDirectly++howToAccessLabel dflags _ os _ _ _+ -- no PIC -> the dynamic linker does everything for us;+ -- if we don't dynamically link to Haskell code,+ -- it actually manages to do so without messing things up.+ | osElfTarget os+ , not (gopt Opt_PIC dflags) && WayDyn `notElem` ways dflags+ = AccessDirectly++howToAccessLabel dflags arch os this_mod DataReference lbl+ | osElfTarget os+ = case () of+ -- A dynamic label needs to be accessed via a symbol pointer.+ _ | labelDynamic dflags this_mod lbl+ -> AccessViaSymbolPtr++ -- For PowerPC32 -fPIC, we have to access even static data+ -- via a symbol pointer (see below for an explanation why+ -- PowerPC32 Linux is especially broken).+ | arch == ArchPPC+ , gopt Opt_PIC dflags+ -> AccessViaSymbolPtr++ | otherwise+ -> AccessDirectly+++ -- In most cases, we have to avoid symbol stubs on ELF, for the following reasons:+ -- on i386, the position-independent symbol stubs in the Procedure Linkage Table+ -- require the address of the GOT to be loaded into register %ebx on entry.+ -- The linker will take any reference to the symbol stub as a hint that+ -- the label in question is a code label. When linking executables, this+ -- will cause the linker to replace even data references to the label with+ -- references to the symbol stub.++ -- This leaves calling a (foreign) function from non-PIC code+ -- (AccessDirectly, because we get an implicit symbol stub)+ -- and calling functions from PIC code on non-i386 platforms (via a symbol stub)++howToAccessLabel dflags arch os this_mod CallReference lbl+ | osElfTarget os+ , labelDynamic dflags this_mod lbl && not (gopt Opt_PIC dflags)+ = AccessDirectly++ | osElfTarget os+ , arch /= ArchX86+ , labelDynamic dflags this_mod lbl && gopt Opt_PIC dflags+ = AccessViaStub++howToAccessLabel dflags _ os this_mod _ lbl+ | osElfTarget os+ = if labelDynamic dflags this_mod lbl+ then AccessViaSymbolPtr+ else AccessDirectly++-- all other platforms+howToAccessLabel dflags _ _ _ _ _+ | not (gopt Opt_PIC dflags)+ = AccessDirectly++ | otherwise+ = panic "howToAccessLabel: PIC not defined for this platform"++++-- -------------------------------------------------------------------+-- | Says what we we have to add to our 'PIC base register' in order to+-- get the address of a label.++picRelative :: Arch -> OS -> CLabel -> CmmLit++-- Darwin, but not x86_64:+-- The PIC base register points to the PIC base label at the beginning+-- of the current CmmDecl. We just have to use a label difference to+-- get the offset.+-- We have already made sure that all labels that are not from the current+-- module are accessed indirectly ('as' can't calculate differences between+-- undefined labels).+picRelative arch OSDarwin lbl+ | arch /= ArchX86_64+ = CmmLabelDiffOff lbl mkPicBaseLabel 0++-- On AIX we use an indirect local TOC anchored by 'gotLabel'.+-- This way we use up only one global TOC entry per compilation-unit+-- (this is quite similiar to GCC's @-mminimal-toc@ compilation mode)+picRelative _ OSAIX lbl+ = CmmLabelDiffOff lbl gotLabel 0++-- PowerPC Linux:+-- The PIC base register points to our fake GOT. Use a label difference+-- to get the offset.+-- We have made sure that *everything* is accessed indirectly, so this+-- is only used for offsets from the GOT to symbol pointers inside the+-- GOT.+picRelative ArchPPC os lbl+ | osElfTarget os+ = CmmLabelDiffOff lbl gotLabel 0+++-- Most Linux versions:+-- The PIC base register points to the GOT. Use foo@got for symbol+-- pointers, and foo@gotoff for everything else.+-- Linux and Darwin on x86_64:+-- The PIC base register is %rip, we use foo@gotpcrel for symbol pointers,+-- and a GotSymbolOffset label for other things.+-- For reasons of tradition, the symbol offset label is written as a plain label.+picRelative arch os lbl+ | osElfTarget os || (os == OSDarwin && arch == ArchX86_64)+ = let result+ | Just (SymbolPtr, lbl') <- dynamicLinkerLabelInfo lbl+ = CmmLabel $ mkDynamicLinkerLabel GotSymbolPtr lbl'++ | otherwise+ = CmmLabel $ mkDynamicLinkerLabel GotSymbolOffset lbl++ in result++picRelative _ _ _+ = panic "PositionIndependentCode.picRelative undefined for this platform"++++--------------------------------------------------------------------------------++needImportedSymbols :: DynFlags -> Arch -> OS -> Bool+needImportedSymbols dflags arch os+ | os == OSDarwin+ , arch /= ArchX86_64+ = True++ | os == OSAIX+ = True++ -- PowerPC Linux: -fPIC or -dynamic+ | osElfTarget os+ , arch == ArchPPC+ = gopt Opt_PIC dflags || WayDyn `elem` ways dflags++ -- PowerPC 64 Linux: always+ | osElfTarget os+ , arch == ArchPPC_64 ELF_V1 || arch == ArchPPC_64 ELF_V2+ = True++ -- i386 (and others?): -dynamic but not -fPIC+ | osElfTarget os+ , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2+ = WayDyn `elem` ways dflags && not (gopt Opt_PIC dflags)++ | otherwise+ = False++-- gotLabel+-- The label used to refer to our "fake GOT" from+-- position-independent code.+gotLabel :: CLabel+gotLabel+ -- HACK: this label isn't really foreign+ = mkForeignLabel+ (fsLit ".LCTOC1")+ Nothing ForeignLabelInThisPackage IsData++++--------------------------------------------------------------------------------+-- We don't need to declare any offset tables.+-- However, for PIC on x86, we need a small helper function.+pprGotDeclaration :: DynFlags -> Arch -> OS -> SDoc+pprGotDeclaration dflags ArchX86 OSDarwin+ | gopt Opt_PIC dflags+ = vcat [+ text ".section __TEXT,__textcoal_nt,coalesced,no_toc",+ text ".weak_definition ___i686.get_pc_thunk.ax",+ text ".private_extern ___i686.get_pc_thunk.ax",+ text "___i686.get_pc_thunk.ax:",+ text "\tmovl (%esp), %eax",+ text "\tret" ]++pprGotDeclaration _ _ OSDarwin+ = empty++-- Emit XCOFF TOC section+pprGotDeclaration _ _ OSAIX+ = vcat $ [ text ".toc"+ , text ".tc ghc_toc_table[TC],.LCTOC1"+ , text ".csect ghc_toc_table[RW]"+ -- See Note [.LCTOC1 in PPC PIC code]+ , text ".set .LCTOC1,$+0x8000"+ ]+++-- PPC 64 ELF v1 needs a Table Of Contents (TOC) on Linux+pprGotDeclaration _ (ArchPPC_64 ELF_V1) OSLinux+ = text ".section \".toc\",\"aw\""+-- In ELF v2 we also need to tell the assembler that we want ABI+-- version 2. This would normally be done at the top of the file+-- right after a file directive, but I could not figure out how+-- to do that.+pprGotDeclaration _ (ArchPPC_64 ELF_V2) OSLinux+ = vcat [ text ".abiversion 2",+ text ".section \".toc\",\"aw\""+ ]+pprGotDeclaration _ (ArchPPC_64 _) _+ = panic "pprGotDeclaration: ArchPPC_64 only Linux supported"++-- Emit GOT declaration+-- Output whatever needs to be output once per .s file.+pprGotDeclaration dflags arch os+ | osElfTarget os+ , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2+ , not (gopt Opt_PIC dflags)+ = empty++ | osElfTarget os+ , arch /= ArchPPC_64 ELF_V1 && arch /= ArchPPC_64 ELF_V2+ = vcat [+ -- See Note [.LCTOC1 in PPC PIC code]+ text ".section \".got2\",\"aw\"",+ text ".LCTOC1 = .+32768" ]++pprGotDeclaration _ _ _+ = panic "pprGotDeclaration: no match"+++--------------------------------------------------------------------------------+-- On Darwin, we have to generate our own stub code for lazy binding..+-- For each processor architecture, there are two versions, one for PIC+-- and one for non-PIC.+--+-- Whenever you change something in this assembler output, make sure+-- the splitter in driver/split/ghc-split.pl recognizes the new output++pprImportedSymbol :: DynFlags -> Platform -> CLabel -> SDoc+pprImportedSymbol dflags platform@(Platform { platformArch = ArchPPC, platformOS = OSDarwin }) importedLbl+ | Just (CodeStub, lbl) <- dynamicLinkerLabelInfo importedLbl+ = case gopt Opt_PIC dflags of+ False ->+ vcat [+ text ".symbol_stub",+ text "L" <> pprCLabel platform lbl <> ptext (sLit "$stub:"),+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\tlis r11,ha16(L" <> pprCLabel platform lbl+ <> text "$lazy_ptr)",+ text "\tlwz r12,lo16(L" <> pprCLabel platform lbl+ <> text "$lazy_ptr)(r11)",+ text "\tmtctr r12",+ text "\taddi r11,r11,lo16(L" <> pprCLabel platform lbl+ <> text "$lazy_ptr)",+ text "\tbctr"+ ]+ True ->+ vcat [+ text ".section __TEXT,__picsymbolstub1,"+ <> text "symbol_stubs,pure_instructions,32",+ text "\t.align 2",+ text "L" <> pprCLabel platform lbl <> ptext (sLit "$stub:"),+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\tmflr r0",+ text "\tbcl 20,31,L0$" <> pprCLabel platform lbl,+ text "L0$" <> pprCLabel platform lbl <> char ':',+ text "\tmflr r11",+ text "\taddis r11,r11,ha16(L" <> pprCLabel platform lbl+ <> text "$lazy_ptr-L0$" <> pprCLabel platform lbl <> char ')',+ text "\tmtlr r0",+ text "\tlwzu r12,lo16(L" <> pprCLabel platform lbl+ <> text "$lazy_ptr-L0$" <> pprCLabel platform lbl+ <> text ")(r11)",+ text "\tmtctr r12",+ text "\tbctr"+ ]+ $+$ vcat [+ text ".lazy_symbol_pointer",+ text "L" <> pprCLabel platform lbl <> ptext (sLit "$lazy_ptr:"),+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\t.long dyld_stub_binding_helper"]++ | Just (SymbolPtr, lbl) <- dynamicLinkerLabelInfo importedLbl+ = vcat [+ text ".non_lazy_symbol_pointer",+ char 'L' <> pprCLabel platform lbl <> text "$non_lazy_ptr:",+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\t.long\t0"]++ | otherwise+ = empty+++pprImportedSymbol dflags platform@(Platform { platformArch = ArchX86, platformOS = OSDarwin }) importedLbl+ | Just (CodeStub, lbl) <- dynamicLinkerLabelInfo importedLbl+ = case gopt Opt_PIC dflags of+ False ->+ vcat [+ text ".symbol_stub",+ text "L" <> pprCLabel platform lbl <> ptext (sLit "$stub:"),+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\tjmp *L" <> pprCLabel platform lbl+ <> text "$lazy_ptr",+ text "L" <> pprCLabel platform lbl+ <> text "$stub_binder:",+ text "\tpushl $L" <> pprCLabel platform lbl+ <> text "$lazy_ptr",+ text "\tjmp dyld_stub_binding_helper"+ ]+ True ->+ vcat [+ text ".section __TEXT,__picsymbolstub2,"+ <> text "symbol_stubs,pure_instructions,25",+ text "L" <> pprCLabel platform lbl <> ptext (sLit "$stub:"),+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\tcall ___i686.get_pc_thunk.ax",+ text "1:",+ text "\tmovl L" <> pprCLabel platform lbl+ <> text "$lazy_ptr-1b(%eax),%edx",+ text "\tjmp *%edx",+ text "L" <> pprCLabel platform lbl+ <> text "$stub_binder:",+ text "\tlea L" <> pprCLabel platform lbl+ <> text "$lazy_ptr-1b(%eax),%eax",+ text "\tpushl %eax",+ text "\tjmp dyld_stub_binding_helper"+ ]+ $+$ vcat [ text ".section __DATA, __la_sym_ptr"+ <> (if gopt Opt_PIC dflags then int 2 else int 3)+ <> text ",lazy_symbol_pointers",+ text "L" <> pprCLabel platform lbl <> ptext (sLit "$lazy_ptr:"),+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\t.long L" <> pprCLabel platform lbl+ <> text "$stub_binder"]++ | Just (SymbolPtr, lbl) <- dynamicLinkerLabelInfo importedLbl+ = vcat [+ text ".non_lazy_symbol_pointer",+ char 'L' <> pprCLabel platform lbl <> text "$non_lazy_ptr:",+ text "\t.indirect_symbol" <+> pprCLabel platform lbl,+ text "\t.long\t0"]++ | otherwise+ = empty+++pprImportedSymbol _ (Platform { platformOS = OSDarwin }) _+ = empty++-- XCOFF / AIX+--+-- Similiar to PPC64 ELF v1, there's dedicated TOC register (r2). To+-- workaround the limitation of a global TOC we use an indirect TOC+-- with the label `ghc_toc_table`.+--+-- See also GCC's `-mminimal-toc` compilation mode or+-- http://www.ibm.com/developerworks/rational/library/overview-toc-aix/+--+-- NB: No DSO-support yet++pprImportedSymbol _ platform@(Platform { platformOS = OSAIX }) importedLbl+ = case dynamicLinkerLabelInfo importedLbl of+ Just (SymbolPtr, lbl)+ -> vcat [+ text "LC.." <> pprCLabel platform lbl <> char ':',+ text "\t.long" <+> pprCLabel platform lbl ]+ _ -> empty++-- ELF / Linux+--+-- In theory, we don't need to generate any stubs or symbol pointers+-- by hand for Linux.+--+-- Reality differs from this in two areas.+--+-- 1) If we just use a dynamically imported symbol directly in a read-only+-- section of the main executable (as GCC does), ld generates R_*_COPY+-- relocations, which are fundamentally incompatible with reversed info+-- tables. Therefore, we need a table of imported addresses in a writable+-- section.+-- The "official" GOT mechanism (label@got) isn't intended to be used+-- in position dependent code, so we have to create our own "fake GOT"+-- when not Opt_PIC && WayDyn `elem` ways dflags.+--+-- 2) PowerPC Linux is just plain broken.+-- While it's theoretically possible to use GOT offsets larger+-- than 16 bit, the standard crt*.o files don't, which leads to+-- linker errors as soon as the GOT size exceeds 16 bit.+-- Also, the assembler doesn't support @gotoff labels.+-- In order to be able to use a larger GOT, we have to circumvent the+-- entire GOT mechanism and do it ourselves (this is also what GCC does).+++-- When needImportedSymbols is defined,+-- the NCG will keep track of all DynamicLinkerLabels it uses+-- and output each of them using pprImportedSymbol.++pprImportedSymbol _ platform@(Platform { platformArch = ArchPPC_64 _ })+ importedLbl+ | osElfTarget (platformOS platform)+ = case dynamicLinkerLabelInfo importedLbl of+ Just (SymbolPtr, lbl)+ -> vcat [+ text ".section \".toc\", \"aw\"",+ text ".LC_" <> pprCLabel platform lbl <> char ':',+ text "\t.quad" <+> pprCLabel platform lbl ]+ _ -> empty++pprImportedSymbol dflags platform importedLbl+ | osElfTarget (platformOS platform)+ = case dynamicLinkerLabelInfo importedLbl of+ Just (SymbolPtr, lbl)+ -> let symbolSize = case wordWidth dflags of+ W32 -> sLit "\t.long"+ W64 -> sLit "\t.quad"+ _ -> panic "Unknown wordRep in pprImportedSymbol"++ in vcat [+ text ".section \".got2\", \"aw\"",+ text ".LC_" <> pprCLabel platform lbl <> char ':',+ ptext symbolSize <+> pprCLabel platform lbl ]++ -- PLT code stubs are generated automatically by the dynamic linker.+ _ -> empty++pprImportedSymbol _ _ _+ = panic "PIC.pprImportedSymbol: no match"++--------------------------------------------------------------------------------+-- Generate code to calculate the address that should be put in the+-- PIC base register.+-- This is called by MachCodeGen for every CmmProc that accessed the+-- PIC base register. It adds the appropriate instructions to the+-- top of the CmmProc.++-- It is assumed that the first NatCmmDecl in the input list is a Proc+-- and the rest are CmmDatas.++-- Darwin is simple: just fetch the address of a local label.+-- The FETCHPC pseudo-instruction is expanded to multiple instructions+-- during pretty-printing so that we don't have to deal with the+-- local label:++-- PowerPC version:+-- bcl 20,31,1f.+-- 1: mflr picReg++-- i386 version:+-- call 1f+-- 1: popl %picReg++++-- Get a pointer to our own fake GOT, which is defined on a per-module basis.+-- This is exactly how GCC does it in linux.++initializePicBase_ppc+ :: Arch -> OS -> Reg+ -> [NatCmmDecl CmmStatics PPC.Instr]+ -> NatM [NatCmmDecl CmmStatics PPC.Instr]++initializePicBase_ppc ArchPPC os picReg+ (CmmProc info lab live (ListGraph blocks) : statics)+ | osElfTarget os+ = do+ let+ gotOffset = PPC.ImmConstantDiff+ (PPC.ImmCLbl gotLabel)+ (PPC.ImmCLbl mkPicBaseLabel)++ blocks' = case blocks of+ [] -> []+ (b:bs) -> fetchPC b : map maybeFetchPC bs++ maybeFetchPC b@(BasicBlock bID _)+ | bID `mapMember` info = fetchPC b+ | otherwise = b++ -- GCC does PIC prologs thusly:+ -- bcl 20,31,.L1+ -- .L1:+ -- mflr 30+ -- addis 30,30,.LCTOC1-.L1@ha+ -- addi 30,30,.LCTOC1-.L1@l+ -- TODO: below we use it over temporary register,+ -- it can and should be optimised by picking+ -- correct PIC reg.+ fetchPC (BasicBlock bID insns) =+ BasicBlock bID (PPC.FETCHPC picReg+ : PPC.ADDIS picReg picReg (PPC.HA gotOffset)+ : PPC.ADD picReg picReg+ (PPC.RIImm (PPC.LO gotOffset))+ : PPC.MR PPC.r30 picReg+ : insns)++ return (CmmProc info lab live (ListGraph blocks') : statics)+++initializePicBase_ppc ArchPPC OSDarwin picReg+ (CmmProc info lab live (ListGraph (entry:blocks)) : statics) -- just one entry because of splitting+ = return (CmmProc info lab live (ListGraph (b':blocks)) : statics)++ where BasicBlock bID insns = entry+ b' = BasicBlock bID (PPC.FETCHPC picReg : insns)++-------------------------------------------------------------------------+-- Load TOC into register 2+-- PowerPC 64-bit ELF ABI 2.0 requires the address of the callee+-- in register 12.+-- We pass the label to FETCHTOC and create a .localentry too.+-- TODO: Explain this better and refer to ABI spec!+{-+We would like to do approximately this, but spill slot allocation+might be added before the first BasicBlock. That violates the ABI.++For now we will emit the prologue code in the pretty printer,+which is also what we do for ELF v1.+initializePicBase_ppc (ArchPPC_64 ELF_V2) OSLinux picReg+ (CmmProc info lab live (ListGraph (entry:blocks)) : statics)+ = do+ bID <-getUniqueM+ return (CmmProc info lab live (ListGraph (b':entry:blocks))+ : statics)+ where BasicBlock entryID _ = entry+ b' = BasicBlock bID [PPC.FETCHTOC picReg lab,+ PPC.BCC PPC.ALWAYS entryID]+-}++initializePicBase_ppc _ _ _ _+ = panic "initializePicBase_ppc: not needed"+++-- We cheat a bit here by defining a pseudo-instruction named FETCHGOT+-- which pretty-prints as:+-- call 1f+-- 1: popl %picReg+-- addl __GLOBAL_OFFSET_TABLE__+.-1b, %picReg+-- (See PprMach.hs)++initializePicBase_x86+ :: Arch -> OS -> Reg+ -> [NatCmmDecl (Alignment, CmmStatics) X86.Instr]+ -> NatM [NatCmmDecl (Alignment, CmmStatics) X86.Instr]++initializePicBase_x86 ArchX86 os picReg+ (CmmProc info lab live (ListGraph blocks) : statics)+ | osElfTarget os+ = return (CmmProc info lab live (ListGraph blocks') : statics)+ where blocks' = case blocks of+ [] -> []+ (b:bs) -> fetchGOT b : map maybeFetchGOT bs++ -- we want to add a FETCHGOT instruction to the beginning of+ -- every block that is an entry point, which corresponds to+ -- the blocks that have entries in the info-table mapping.+ maybeFetchGOT b@(BasicBlock bID _)+ | bID `mapMember` info = fetchGOT b+ | otherwise = b++ fetchGOT (BasicBlock bID insns) =+ BasicBlock bID (X86.FETCHGOT picReg : insns)++initializePicBase_x86 ArchX86 OSDarwin picReg+ (CmmProc info lab live (ListGraph (entry:blocks)) : statics)+ = return (CmmProc info lab live (ListGraph (block':blocks)) : statics)++ where BasicBlock bID insns = entry+ block' = BasicBlock bID (X86.FETCHPC picReg : insns)++initializePicBase_x86 _ _ _ _+ = panic "initializePicBase_x86: not needed"+
+ nativeGen/PPC/CodeGen.hs view
@@ -0,0 +1,2307 @@+{-# LANGUAGE CPP, GADTs #-}++-----------------------------------------------------------------------------+--+-- Generating machine code (instruction selection)+--+-- (c) The University of Glasgow 1996-2004+--+-----------------------------------------------------------------------------++-- This is a big module, but, if you pay attention to+-- (a) the sectioning, and (b) the type signatures,+-- the structure should not be too overwhelming.++module PPC.CodeGen (+ cmmTopCodeGen,+ generateJumpTableForInstr,+ InstrBlock+)++where++#include "HsVersions.h"+#include "nativeGen/NCG.h"+#include "MachDeps.h"++-- NCG stuff:+import CodeGen.Platform+import PPC.Instr+import PPC.Cond+import PPC.Regs+import CPrim+import NCGMonad+import Instruction+import PIC+import Format+import RegClass+import Reg+import TargetReg+import Platform++-- Our intermediate code:+import BlockId+import PprCmm ( pprExpr )+import Cmm+import CmmUtils+import CmmSwitch+import CLabel+import Hoopl++-- The rest:+import OrdList+import Outputable+import Unique+import DynFlags++import Control.Monad ( mapAndUnzipM, when )+import Data.Bits+import Data.Word++import BasicTypes+import FastString+import Util++-- -----------------------------------------------------------------------------+-- Top-level of the instruction selector++-- | 'InstrBlock's are the insn sequences generated by the insn selectors.+-- They are really trees of insns to facilitate fast appending, where a+-- left-to-right traversal (pre-order?) yields the insns in the correct+-- order.++cmmTopCodeGen+ :: RawCmmDecl+ -> NatM [NatCmmDecl CmmStatics Instr]++cmmTopCodeGen (CmmProc info lab live graph) = do+ let blocks = toBlockListEntryFirst graph+ (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks+ dflags <- getDynFlags+ let proc = CmmProc info lab live (ListGraph $ concat nat_blocks)+ tops = proc : concat statics+ os = platformOS $ targetPlatform dflags+ arch = platformArch $ targetPlatform dflags+ case arch of+ ArchPPC | os == OSAIX -> return tops+ | otherwise -> do+ picBaseMb <- getPicBaseMaybeNat+ case picBaseMb of+ Just picBase -> initializePicBase_ppc arch os picBase tops+ Nothing -> return tops+ ArchPPC_64 ELF_V1 -> return tops+ -- generating function descriptor is handled in+ -- pretty printer+ ArchPPC_64 ELF_V2 -> return tops+ -- generating function prologue is handled in+ -- pretty printer+ _ -> panic "PPC.cmmTopCodeGen: unknown arch"++cmmTopCodeGen (CmmData sec dat) = do+ return [CmmData sec dat] -- no translation, we just use CmmStatic++basicBlockCodeGen+ :: Block CmmNode C C+ -> NatM ( [NatBasicBlock Instr]+ , [NatCmmDecl CmmStatics Instr])++basicBlockCodeGen block = do+ let (_, nodes, tail) = blockSplit block+ id = entryLabel block+ stmts = blockToList nodes+ mid_instrs <- stmtsToInstrs stmts+ tail_instrs <- stmtToInstrs tail+ let instrs = mid_instrs `appOL` tail_instrs+ -- code generation may introduce new basic block boundaries, which+ -- are indicated by the NEWBLOCK instruction. We must split up the+ -- instruction stream into basic blocks again. Also, we extract+ -- LDATAs here too.+ let+ (top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs++ mkBlocks (NEWBLOCK id) (instrs,blocks,statics)+ = ([], BasicBlock id instrs : blocks, statics)+ mkBlocks (LDATA sec dat) (instrs,blocks,statics)+ = (instrs, blocks, CmmData sec dat:statics)+ mkBlocks instr (instrs,blocks,statics)+ = (instr:instrs, blocks, statics)+ return (BasicBlock id top : other_blocks, statics)++stmtsToInstrs :: [CmmNode e x] -> NatM InstrBlock+stmtsToInstrs stmts+ = do instrss <- mapM stmtToInstrs stmts+ return (concatOL instrss)++stmtToInstrs :: CmmNode e x -> NatM InstrBlock+stmtToInstrs stmt = do+ dflags <- getDynFlags+ case stmt of+ CmmComment s -> return (unitOL (COMMENT s))+ CmmTick {} -> return nilOL+ CmmUnwind {} -> return nilOL++ CmmAssign reg src+ | isFloatType ty -> assignReg_FltCode format reg src+ | target32Bit (targetPlatform dflags) &&+ isWord64 ty -> assignReg_I64Code reg src+ | otherwise -> assignReg_IntCode format reg src+ where ty = cmmRegType dflags reg+ format = cmmTypeFormat ty++ CmmStore addr src+ | isFloatType ty -> assignMem_FltCode format addr src+ | target32Bit (targetPlatform dflags) &&+ isWord64 ty -> assignMem_I64Code addr src+ | otherwise -> assignMem_IntCode format addr src+ where ty = cmmExprType dflags src+ format = cmmTypeFormat ty++ CmmUnsafeForeignCall target result_regs args+ -> genCCall target result_regs args++ CmmBranch id -> genBranch id+ CmmCondBranch arg true false _ -> do+ b1 <- genCondJump true arg+ b2 <- genBranch false+ return (b1 `appOL` b2)+ CmmSwitch arg ids -> do dflags <- getDynFlags+ genSwitch dflags arg ids+ CmmCall { cml_target = arg } -> genJump arg+ _ ->+ panic "stmtToInstrs: statement should have been cps'd away"+++--------------------------------------------------------------------------------+-- | 'InstrBlock's are the insn sequences generated by the insn selectors.+-- They are really trees of insns to facilitate fast appending, where a+-- left-to-right traversal yields the insns in the correct order.+--+type InstrBlock+ = OrdList Instr+++-- | Register's passed up the tree. If the stix code forces the register+-- to live in a pre-decided machine register, it comes out as @Fixed@;+-- otherwise, it comes out as @Any@, and the parent can decide which+-- register to put it in.+--+data Register+ = Fixed Format Reg InstrBlock+ | Any Format (Reg -> InstrBlock)+++swizzleRegisterRep :: Register -> Format -> Register+swizzleRegisterRep (Fixed _ reg code) format = Fixed format reg code+swizzleRegisterRep (Any _ codefn) format = Any format codefn+++-- | Grab the Reg for a CmmReg+getRegisterReg :: Platform -> CmmReg -> Reg++getRegisterReg _ (CmmLocal (LocalReg u pk))+ = RegVirtual $ mkVirtualReg u (cmmTypeFormat pk)++getRegisterReg platform (CmmGlobal mid)+ = case globalRegMaybe platform mid of+ Just reg -> RegReal reg+ Nothing -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)+ -- By this stage, the only MagicIds remaining should be the+ -- ones which map to a real machine register on this+ -- platform. Hence ...++-- | Convert a BlockId to some CmmStatic data+jumpTableEntry :: DynFlags -> Maybe BlockId -> CmmStatic+jumpTableEntry dflags Nothing = CmmStaticLit (CmmInt 0 (wordWidth dflags))+jumpTableEntry _ (Just blockid) = CmmStaticLit (CmmLabel blockLabel)+ where blockLabel = mkAsmTempLabel (getUnique blockid)++++-- -----------------------------------------------------------------------------+-- General things for putting together code sequences++-- Expand CmmRegOff. ToDo: should we do it this way around, or convert+-- CmmExprs into CmmRegOff?+mangleIndexTree :: DynFlags -> CmmExpr -> CmmExpr+mangleIndexTree dflags (CmmRegOff reg off)+ = CmmMachOp (MO_Add width) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) width)]+ where width = typeWidth (cmmRegType dflags reg)++mangleIndexTree _ _+ = panic "PPC.CodeGen.mangleIndexTree: no match"++-- -----------------------------------------------------------------------------+-- Code gen for 64-bit arithmetic on 32-bit platforms++{-+Simple support for generating 64-bit code (ie, 64 bit values and 64+bit assignments) on 32-bit platforms. Unlike the main code generator+we merely shoot for generating working code as simply as possible, and+pay little attention to code quality. Specifically, there is no+attempt to deal cleverly with the fixed-vs-floating register+distinction; all values are generated into (pairs of) floating+registers, even if this would mean some redundant reg-reg moves as a+result. Only one of the VRegUniques is returned, since it will be+of the VRegUniqueLo form, and the upper-half VReg can be determined+by applying getHiVRegFromLo to it.+-}++data ChildCode64 -- a.k.a "Register64"+ = ChildCode64+ InstrBlock -- code+ Reg -- the lower 32-bit temporary which contains the+ -- result; use getHiVRegFromLo to find the other+ -- VRegUnique. Rules of this simplified insn+ -- selection game are therefore that the returned+ -- Reg may be modified+++-- | Compute an expression into a register, but+-- we don't mind which one it is.+getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)+getSomeReg expr = do+ r <- getRegister expr+ case r of+ Any rep code -> do+ tmp <- getNewRegNat rep+ return (tmp, code tmp)+ Fixed _ reg code ->+ return (reg, code)++getI64Amodes :: CmmExpr -> NatM (AddrMode, AddrMode, InstrBlock)+getI64Amodes addrTree = do+ Amode hi_addr addr_code <- getAmode D addrTree+ case addrOffset hi_addr 4 of+ Just lo_addr -> return (hi_addr, lo_addr, addr_code)+ Nothing -> do (hi_ptr, code) <- getSomeReg addrTree+ return (AddrRegImm hi_ptr (ImmInt 0),+ AddrRegImm hi_ptr (ImmInt 4),+ code)+++assignMem_I64Code :: CmmExpr -> CmmExpr -> NatM InstrBlock+assignMem_I64Code addrTree valueTree = do+ (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree+ ChildCode64 vcode rlo <- iselExpr64 valueTree+ let+ rhi = getHiVRegFromLo rlo++ -- Big-endian store+ mov_hi = ST II32 rhi hi_addr+ mov_lo = ST II32 rlo lo_addr+ return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)+++assignReg_I64Code :: CmmReg -> CmmExpr -> NatM InstrBlock+assignReg_I64Code (CmmLocal (LocalReg u_dst _)) valueTree = do+ ChildCode64 vcode r_src_lo <- iselExpr64 valueTree+ let+ r_dst_lo = RegVirtual $ mkVirtualReg u_dst II32+ r_dst_hi = getHiVRegFromLo r_dst_lo+ r_src_hi = getHiVRegFromLo r_src_lo+ mov_lo = MR r_dst_lo r_src_lo+ mov_hi = MR r_dst_hi r_src_hi+ return (+ vcode `snocOL` mov_lo `snocOL` mov_hi+ )++assignReg_I64Code _ _+ = panic "assignReg_I64Code(powerpc): invalid lvalue"+++iselExpr64 :: CmmExpr -> NatM ChildCode64+iselExpr64 (CmmLoad addrTree ty) | isWord64 ty = do+ (hi_addr, lo_addr, addr_code) <- getI64Amodes addrTree+ (rlo, rhi) <- getNewRegPairNat II32+ let mov_hi = LD II32 rhi hi_addr+ mov_lo = LD II32 rlo lo_addr+ return $ ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi)+ rlo++iselExpr64 (CmmReg (CmmLocal (LocalReg vu ty))) | isWord64 ty+ = return (ChildCode64 nilOL (RegVirtual $ mkVirtualReg vu II32))++iselExpr64 (CmmLit (CmmInt i _)) = do+ (rlo,rhi) <- getNewRegPairNat II32+ let+ half0 = fromIntegral (fromIntegral i :: Word16)+ half1 = fromIntegral (fromIntegral (i `shiftR` 16) :: Word16)+ half2 = fromIntegral (fromIntegral (i `shiftR` 32) :: Word16)+ half3 = fromIntegral (fromIntegral (i `shiftR` 48) :: Word16)++ code = toOL [+ LIS rlo (ImmInt half1),+ OR rlo rlo (RIImm $ ImmInt half0),+ LIS rhi (ImmInt half3),+ OR rhi rhi (RIImm $ ImmInt half2)+ ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do+ ChildCode64 code1 r1lo <- iselExpr64 e1+ ChildCode64 code2 r2lo <- iselExpr64 e2+ (rlo,rhi) <- getNewRegPairNat II32+ let+ r1hi = getHiVRegFromLo r1lo+ r2hi = getHiVRegFromLo r2lo+ code = code1 `appOL`+ code2 `appOL`+ toOL [ ADDC rlo r1lo r2lo,+ ADDE rhi r1hi r2hi ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmMachOp (MO_Sub _) [e1,e2]) = do+ ChildCode64 code1 r1lo <- iselExpr64 e1+ ChildCode64 code2 r2lo <- iselExpr64 e2+ (rlo,rhi) <- getNewRegPairNat II32+ let+ r1hi = getHiVRegFromLo r1lo+ r2hi = getHiVRegFromLo r2lo+ code = code1 `appOL`+ code2 `appOL`+ toOL [ SUBFC rlo r2lo (RIReg r1lo),+ SUBFE rhi r2hi r1hi ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmMachOp (MO_UU_Conv W32 W64) [expr]) = do+ (expr_reg,expr_code) <- getSomeReg expr+ (rlo, rhi) <- getNewRegPairNat II32+ let mov_hi = LI rhi (ImmInt 0)+ mov_lo = MR rlo expr_reg+ return $ ChildCode64 (expr_code `snocOL` mov_lo `snocOL` mov_hi)+ rlo+iselExpr64 expr+ = pprPanic "iselExpr64(powerpc)" (pprExpr expr)++++getRegister :: CmmExpr -> NatM Register+getRegister e = do dflags <- getDynFlags+ getRegister' dflags e++getRegister' :: DynFlags -> CmmExpr -> NatM Register++getRegister' dflags (CmmReg (CmmGlobal PicBaseReg))+ | OSAIX <- platformOS (targetPlatform dflags) = do+ let code dst = toOL [ LD II32 dst tocAddr ]+ tocAddr = AddrRegImm toc (ImmLit (text "ghc_toc_table[TC]"))+ return (Any II32 code)+ | target32Bit (targetPlatform dflags) = do+ reg <- getPicBaseNat $ archWordFormat (target32Bit (targetPlatform dflags))+ return (Fixed (archWordFormat (target32Bit (targetPlatform dflags)))+ reg nilOL)+ | otherwise = return (Fixed II64 toc nilOL)++getRegister' dflags (CmmReg reg)+ = return (Fixed (cmmTypeFormat (cmmRegType dflags reg))+ (getRegisterReg (targetPlatform dflags) reg) nilOL)++getRegister' dflags tree@(CmmRegOff _ _)+ = getRegister' dflags (mangleIndexTree dflags tree)++ -- for 32-bit architectuers, support some 64 -> 32 bit conversions:+ -- TO_W_(x), TO_W_(x >> 32)++getRegister' dflags (CmmMachOp (MO_UU_Conv W64 W32)+ [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]])+ | target32Bit (targetPlatform dflags) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 (getHiVRegFromLo rlo) code++getRegister' dflags (CmmMachOp (MO_SS_Conv W64 W32)+ [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]])+ | target32Bit (targetPlatform dflags) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 (getHiVRegFromLo rlo) code++getRegister' dflags (CmmMachOp (MO_UU_Conv W64 W32) [x])+ | target32Bit (targetPlatform dflags) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 rlo code++getRegister' dflags (CmmMachOp (MO_SS_Conv W64 W32) [x])+ | target32Bit (targetPlatform dflags) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 rlo code++getRegister' dflags (CmmLoad mem pk)+ | not (isWord64 pk) = do+ let platform = targetPlatform dflags+ Amode addr addr_code <- getAmode D mem+ let code dst = ASSERT((targetClassOfReg platform dst == RcDouble) == isFloatType pk)+ addr_code `snocOL` LD format dst addr+ return (Any format code)+ | not (target32Bit (targetPlatform dflags)) = do+ Amode addr addr_code <- getAmode DS mem+ let code dst = addr_code `snocOL` LD II64 dst addr+ return (Any II64 code)++ where format = cmmTypeFormat pk++-- catch simple cases of zero- or sign-extended load+getRegister' _ (CmmMachOp (MO_UU_Conv W8 W32) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II32 (\dst -> addr_code `snocOL` LD II8 dst addr))++getRegister' _ (CmmMachOp (MO_UU_Conv W8 W64) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II64 (\dst -> addr_code `snocOL` LD II8 dst addr))++-- Note: there is no Load Byte Arithmetic instruction, so no signed case here++getRegister' _ (CmmMachOp (MO_UU_Conv W16 W32) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II32 (\dst -> addr_code `snocOL` LD II16 dst addr))++getRegister' _ (CmmMachOp (MO_SS_Conv W16 W32) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II32 (\dst -> addr_code `snocOL` LA II16 dst addr))++getRegister' _ (CmmMachOp (MO_UU_Conv W16 W64) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II64 (\dst -> addr_code `snocOL` LD II16 dst addr))++getRegister' _ (CmmMachOp (MO_SS_Conv W16 W64) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II64 (\dst -> addr_code `snocOL` LA II16 dst addr))++getRegister' _ (CmmMachOp (MO_UU_Conv W32 W64) [CmmLoad mem _]) = do+ Amode addr addr_code <- getAmode D mem+ return (Any II64 (\dst -> addr_code `snocOL` LD II32 dst addr))++getRegister' _ (CmmMachOp (MO_SS_Conv W32 W64) [CmmLoad mem _]) = do+ -- lwa is DS-form. See Note [Power instruction format]+ Amode addr addr_code <- getAmode DS mem+ return (Any II64 (\dst -> addr_code `snocOL` LA II32 dst addr))++getRegister' dflags (CmmMachOp mop [x]) -- unary MachOps+ = case mop of+ MO_Not rep -> triv_ucode_int rep NOT++ MO_F_Neg w -> triv_ucode_float w FNEG+ MO_S_Neg w -> triv_ucode_int w NEG++ MO_FF_Conv W64 W32 -> trivialUCode FF32 FRSP x+ MO_FF_Conv W32 W64 -> conversionNop FF64 x++ MO_FS_Conv from to -> coerceFP2Int from to x+ MO_SF_Conv from to -> coerceInt2FP from to x++ MO_SS_Conv from to+ | from == to -> conversionNop (intFormat to) x++ -- narrowing is a nop: we treat the high bits as undefined+ MO_SS_Conv W64 to+ | arch32 -> panic "PPC.CodeGen.getRegister no 64 bit int register"+ | otherwise -> conversionNop (intFormat to) x+ MO_SS_Conv W32 to+ | arch32 -> conversionNop (intFormat to) x+ | otherwise -> case to of+ W64 -> triv_ucode_int to (EXTS II32)+ W16 -> conversionNop II16 x+ W8 -> conversionNop II8 x+ _ -> panic "PPC.CodeGen.getRegister: no match"+ MO_SS_Conv W16 W8 -> conversionNop II8 x+ MO_SS_Conv W8 to -> triv_ucode_int to (EXTS II8)+ MO_SS_Conv W16 to -> triv_ucode_int to (EXTS II16)++ MO_UU_Conv from to+ | from == to -> conversionNop (intFormat to) x+ -- narrowing is a nop: we treat the high bits as undefined+ MO_UU_Conv W64 to+ | arch32 -> panic "PPC.CodeGen.getRegister no 64 bit target"+ | otherwise -> conversionNop (intFormat to) x+ MO_UU_Conv W32 to+ | arch32 -> conversionNop (intFormat to) x+ | otherwise ->+ case to of+ W64 -> trivialCode to False AND x (CmmLit (CmmInt 4294967295 W64))+ W16 -> conversionNop II16 x+ W8 -> conversionNop II8 x+ _ -> panic "PPC.CodeGen.getRegister: no match"+ MO_UU_Conv W16 W8 -> conversionNop II8 x+ MO_UU_Conv W8 to -> trivialCode to False AND x (CmmLit (CmmInt 255 W32))+ MO_UU_Conv W16 to -> trivialCode to False AND x (CmmLit (CmmInt 65535 W32))+ _ -> panic "PPC.CodeGen.getRegister: no match"++ where+ triv_ucode_int width instr = trivialUCode (intFormat width) instr x+ triv_ucode_float width instr = trivialUCode (floatFormat width) instr x++ conversionNop new_format expr+ = do e_code <- getRegister' dflags expr+ return (swizzleRegisterRep e_code new_format)+ arch32 = target32Bit $ targetPlatform dflags++getRegister' dflags (CmmMachOp mop [x, y]) -- dyadic PrimOps+ = case mop of+ MO_F_Eq _ -> condFltReg EQQ x y+ MO_F_Ne _ -> condFltReg NE x y+ MO_F_Gt _ -> condFltReg GTT x y+ MO_F_Ge _ -> condFltReg GE x y+ MO_F_Lt _ -> condFltReg LTT x y+ MO_F_Le _ -> condFltReg LE x y++ MO_Eq rep -> condIntReg EQQ (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)+ MO_Ne rep -> condIntReg NE (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)++ MO_S_Gt rep -> condIntReg GTT (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_S_Ge rep -> condIntReg GE (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_S_Lt rep -> condIntReg LTT (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_S_Le rep -> condIntReg LE (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)++ MO_U_Gt rep -> condIntReg GU (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)+ MO_U_Ge rep -> condIntReg GEU (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)+ MO_U_Lt rep -> condIntReg LU (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)+ MO_U_Le rep -> condIntReg LEU (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)++ MO_F_Add w -> triv_float w FADD+ MO_F_Sub w -> triv_float w FSUB+ MO_F_Mul w -> triv_float w FMUL+ MO_F_Quot w -> triv_float w FDIV++ -- optimize addition with 32-bit immediate+ -- (needed for PIC)+ MO_Add W32 ->+ case y of+ CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate W32 True imm+ -> trivialCode W32 True ADD x (CmmLit $ CmmInt imm immrep)+ CmmLit lit+ -> do+ (src, srcCode) <- getSomeReg x+ let imm = litToImm lit+ code dst = srcCode `appOL` toOL [+ ADDIS dst src (HA imm),+ ADD dst dst (RIImm (LO imm))+ ]+ return (Any II32 code)+ _ -> trivialCode W32 True ADD x y++ MO_Add rep -> trivialCode rep True ADD x y+ MO_Sub rep ->+ case y of+ CmmLit (CmmInt imm immrep) | Just _ <- makeImmediate rep True (-imm)+ -> trivialCode rep True ADD x (CmmLit $ CmmInt (-imm) immrep)+ _ -> case x of+ CmmLit (CmmInt imm _)+ | Just _ <- makeImmediate rep True imm+ -- subfi ('substract from' with immediate) doesn't exist+ -> trivialCode rep True SUBFC y x+ _ -> trivialCodeNoImm' (intFormat rep) SUBF y x++ MO_Mul rep -> shiftMulCode rep True MULL x y+ MO_S_MulMayOflo rep -> do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let+ format = intFormat rep+ code dst = code1 `appOL` code2+ `appOL` toOL [ MULLO format dst src1 src2+ , MFOV format dst+ ]+ return (Any format code)++ MO_S_Quot rep -> trivialCodeNoImmSign (intFormat rep) True DIV+ (extendSExpr dflags rep x) (extendSExpr dflags rep y)+ MO_U_Quot rep -> trivialCodeNoImmSign (intFormat rep) False DIV+ (extendUExpr dflags rep x) (extendUExpr dflags rep y)++ MO_S_Rem rep -> remainderCode rep True (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_U_Rem rep -> remainderCode rep False (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)++ MO_And rep -> case y of+ (CmmLit (CmmInt imm _)) | imm == -8 || imm == -4+ -> do+ (src, srcCode) <- getSomeReg x+ let clear_mask = if imm == -4 then 2 else 3+ fmt = intFormat rep+ code dst = srcCode+ `appOL` unitOL (CLRRI fmt dst src clear_mask)+ return (Any fmt code)+ _ -> trivialCode rep False AND x y+ MO_Or rep -> trivialCode rep False OR x y+ MO_Xor rep -> trivialCode rep False XOR x y++ MO_Shl rep -> shiftMulCode rep False SL x y+ MO_S_Shr rep -> shiftMulCode rep False SRA (extendSExpr dflags rep x) y+ MO_U_Shr rep -> shiftMulCode rep False SR (extendUExpr dflags rep x) y+ _ -> panic "PPC.CodeGen.getRegister: no match"++ where+ triv_float :: Width -> (Format -> Reg -> Reg -> Reg -> Instr) -> NatM Register+ triv_float width instr = trivialCodeNoImm (floatFormat width) instr x y++getRegister' _ (CmmLit (CmmInt i rep))+ | Just imm <- makeImmediate rep True i+ = let+ code dst = unitOL (LI dst imm)+ in+ return (Any (intFormat rep) code)++getRegister' _ (CmmLit (CmmFloat f frep)) = do+ lbl <- getNewLabelNat+ dflags <- getDynFlags+ dynRef <- cmmMakeDynamicReference dflags DataReference lbl+ Amode addr addr_code <- getAmode D dynRef+ let format = floatFormat frep+ code dst =+ LDATA (Section ReadOnlyData lbl)+ (Statics lbl [CmmStaticLit (CmmFloat f frep)])+ `consOL` (addr_code `snocOL` LD format dst addr)+ return (Any format code)++getRegister' dflags (CmmLit lit)+ | target32Bit (targetPlatform dflags)+ = let rep = cmmLitType dflags lit+ imm = litToImm lit+ code dst = toOL [+ LIS dst (HA imm),+ ADD dst dst (RIImm (LO imm))+ ]+ in return (Any (cmmTypeFormat rep) code)+ | otherwise+ = do lbl <- getNewLabelNat+ dflags <- getDynFlags+ dynRef <- cmmMakeDynamicReference dflags DataReference lbl+ Amode addr addr_code <- getAmode D dynRef+ let rep = cmmLitType dflags lit+ format = cmmTypeFormat rep+ code dst =+ LDATA (Section ReadOnlyData lbl) (Statics lbl [CmmStaticLit lit])+ `consOL` (addr_code `snocOL` LD format dst addr)+ return (Any format code)++getRegister' _ other = pprPanic "getRegister(ppc)" (pprExpr other)++ -- extend?Rep: wrap integer expression of type rep+ -- in a conversion to II32 or II64 resp.+extendSExpr :: DynFlags -> Width -> CmmExpr -> CmmExpr+extendSExpr dflags W32 x+ | target32Bit (targetPlatform dflags) = x++extendSExpr dflags W64 x+ | not (target32Bit (targetPlatform dflags)) = x++extendSExpr dflags rep x =+ let size = if target32Bit $ targetPlatform dflags+ then W32+ else W64+ in CmmMachOp (MO_SS_Conv rep size) [x]++extendUExpr :: DynFlags -> Width -> CmmExpr -> CmmExpr+extendUExpr dflags W32 x+ | target32Bit (targetPlatform dflags) = x+extendUExpr dflags W64 x+ | not (target32Bit (targetPlatform dflags)) = x+extendUExpr dflags rep x =+ let size = if target32Bit $ targetPlatform dflags+ then W32+ else W64+ in CmmMachOp (MO_UU_Conv rep size) [x]++-- -----------------------------------------------------------------------------+-- The 'Amode' type: Memory addressing modes passed up the tree.++data Amode+ = Amode AddrMode InstrBlock++{-+Now, given a tree (the argument to an CmmLoad) that references memory,+produce a suitable addressing mode.++A Rule of the Game (tm) for Amodes: use of the addr bit must+immediately follow use of the code part, since the code part puts+values in registers which the addr then refers to. So you can't put+anything in between, lest it overwrite some of those registers. If+you need to do some other computation between the code part and use of+the addr bit, first store the effective address from the amode in a+temporary, then do the other computation, and then use the temporary:++ code+ LEA amode, tmp+ ... other computation ...+ ... (tmp) ...+-}++{- Note [Power instruction format]+In some instructions the 16 bit offset must be a multiple of 4, i.e.+the two least significant bits must be zero. The "Power ISA" specification+calls these instruction formats "DS-FORM" and the instructions with+arbitrary 16 bit offsets are "D-FORM".++The Power ISA specification document can be obtained from www.power.org.+-}+data InstrForm = D | DS++getAmode :: InstrForm -> CmmExpr -> NatM Amode+getAmode inf tree@(CmmRegOff _ _)+ = do dflags <- getDynFlags+ getAmode inf (mangleIndexTree dflags tree)++getAmode _ (CmmMachOp (MO_Sub W32) [x, CmmLit (CmmInt i _)])+ | Just off <- makeImmediate W32 True (-i)+ = do+ (reg, code) <- getSomeReg x+ return (Amode (AddrRegImm reg off) code)+++getAmode _ (CmmMachOp (MO_Add W32) [x, CmmLit (CmmInt i _)])+ | Just off <- makeImmediate W32 True i+ = do+ (reg, code) <- getSomeReg x+ return (Amode (AddrRegImm reg off) code)++getAmode D (CmmMachOp (MO_Sub W64) [x, CmmLit (CmmInt i _)])+ | Just off <- makeImmediate W64 True (-i)+ = do+ (reg, code) <- getSomeReg x+ return (Amode (AddrRegImm reg off) code)+++getAmode D (CmmMachOp (MO_Add W64) [x, CmmLit (CmmInt i _)])+ | Just off <- makeImmediate W64 True i+ = do+ (reg, code) <- getSomeReg x+ return (Amode (AddrRegImm reg off) code)++getAmode DS (CmmMachOp (MO_Sub W64) [x, CmmLit (CmmInt i _)])+ | Just off <- makeImmediate W64 True (-i)+ = do+ (reg, code) <- getSomeReg x+ (reg', off', code') <-+ if i `mod` 4 == 0+ then do return (reg, off, code)+ else do+ tmp <- getNewRegNat II64+ return (tmp, ImmInt 0,+ code `snocOL` ADD tmp reg (RIImm off))+ return (Amode (AddrRegImm reg' off') code')++getAmode DS (CmmMachOp (MO_Add W64) [x, CmmLit (CmmInt i _)])+ | Just off <- makeImmediate W64 True i+ = do+ (reg, code) <- getSomeReg x+ (reg', off', code') <-+ if i `mod` 4 == 0+ then do return (reg, off, code)+ else do+ tmp <- getNewRegNat II64+ return (tmp, ImmInt 0,+ code `snocOL` ADD tmp reg (RIImm off))+ return (Amode (AddrRegImm reg' off') code')++ -- optimize addition with 32-bit immediate+ -- (needed for PIC)+getAmode _ (CmmMachOp (MO_Add W32) [x, CmmLit lit])+ = do+ dflags <- getDynFlags+ (src, srcCode) <- getSomeReg x+ let imm = litToImm lit+ case () of+ _ | OSAIX <- platformOS (targetPlatform dflags)+ , isCmmLabelType lit ->+ -- HA16/LO16 relocations on labels not supported on AIX+ return (Amode (AddrRegImm src imm) srcCode)+ | otherwise -> do+ tmp <- getNewRegNat II32+ let code = srcCode `snocOL` ADDIS tmp src (HA imm)+ return (Amode (AddrRegImm tmp (LO imm)) code)+ where+ isCmmLabelType (CmmLabel {}) = True+ isCmmLabelType (CmmLabelOff {}) = True+ isCmmLabelType (CmmLabelDiffOff {}) = True+ isCmmLabelType _ = False++getAmode _ (CmmLit lit)+ = do+ dflags <- getDynFlags+ case platformArch $ targetPlatform dflags of+ ArchPPC -> do+ tmp <- getNewRegNat II32+ let imm = litToImm lit+ code = unitOL (LIS tmp (HA imm))+ return (Amode (AddrRegImm tmp (LO imm)) code)+ _ -> do -- TODO: Load from TOC,+ -- see getRegister' _ (CmmLit lit)+ tmp <- getNewRegNat II64+ let imm = litToImm lit+ code = toOL [+ LIS tmp (HIGHESTA imm),+ OR tmp tmp (RIImm (HIGHERA imm)),+ SL II64 tmp tmp (RIImm (ImmInt 32)),+ ORIS tmp tmp (HA imm)+ ]+ return (Amode (AddrRegImm tmp (LO imm)) code)++getAmode _ (CmmMachOp (MO_Add W32) [x, y])+ = do+ (regX, codeX) <- getSomeReg x+ (regY, codeY) <- getSomeReg y+ return (Amode (AddrRegReg regX regY) (codeX `appOL` codeY))++getAmode _ (CmmMachOp (MO_Add W64) [x, y])+ = do+ (regX, codeX) <- getSomeReg x+ (regY, codeY) <- getSomeReg y+ return (Amode (AddrRegReg regX regY) (codeX `appOL` codeY))++getAmode _ other+ = do+ (reg, code) <- getSomeReg other+ let+ off = ImmInt 0+ return (Amode (AddrRegImm reg off) code)+++-- The 'CondCode' type: Condition codes passed up the tree.+data CondCode+ = CondCode Bool Cond InstrBlock++-- Set up a condition code for a conditional branch.++getCondCode :: CmmExpr -> NatM CondCode++-- almost the same as everywhere else - but we need to+-- extend small integers to 32 bit or 64 bit first++getCondCode (CmmMachOp mop [x, y])+ = do+ dflags <- getDynFlags+ case mop of+ MO_F_Eq W32 -> condFltCode EQQ x y+ MO_F_Ne W32 -> condFltCode NE x y+ MO_F_Gt W32 -> condFltCode GTT x y+ MO_F_Ge W32 -> condFltCode GE x y+ MO_F_Lt W32 -> condFltCode LTT x y+ MO_F_Le W32 -> condFltCode LE x y++ MO_F_Eq W64 -> condFltCode EQQ x y+ MO_F_Ne W64 -> condFltCode NE x y+ MO_F_Gt W64 -> condFltCode GTT x y+ MO_F_Ge W64 -> condFltCode GE x y+ MO_F_Lt W64 -> condFltCode LTT x y+ MO_F_Le W64 -> condFltCode LE x y++ MO_Eq rep -> condIntCode EQQ (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)+ MO_Ne rep -> condIntCode NE (extendUExpr dflags rep x)+ (extendUExpr dflags rep y)++ MO_S_Gt rep -> condIntCode GTT (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_S_Ge rep -> condIntCode GE (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_S_Lt rep -> condIntCode LTT (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_S_Le rep -> condIntCode LE (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)++ MO_U_Gt rep -> condIntCode GU (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_U_Ge rep -> condIntCode GEU (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_U_Lt rep -> condIntCode LU (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)+ MO_U_Le rep -> condIntCode LEU (extendSExpr dflags rep x)+ (extendSExpr dflags rep y)++ _ -> pprPanic "getCondCode(powerpc)" (pprMachOp mop)++getCondCode _ = panic "getCondCode(2)(powerpc)"+++-- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be+-- passed back up the tree.++condIntCode, condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode++-- optimize pointer tag checks. Operation andi. sets condition register+-- so cmpi ..., 0 is redundant.+condIntCode cond (CmmMachOp (MO_And _) [x, CmmLit (CmmInt imm rep)])+ (CmmLit (CmmInt 0 _))+ | not $ condUnsigned cond,+ Just src2 <- makeImmediate rep False imm+ = do+ (src1, code) <- getSomeReg x+ let code' = code `snocOL` AND r0 src1 (RIImm src2)+ return (CondCode False cond code')++condIntCode cond x (CmmLit (CmmInt y rep))+ | Just src2 <- makeImmediate rep (not $ condUnsigned cond) y+ = do+ (src1, code) <- getSomeReg x+ dflags <- getDynFlags+ let format = archWordFormat $ target32Bit $ targetPlatform dflags+ code' = code `snocOL`+ (if condUnsigned cond then CMPL else CMP) format src1 (RIImm src2)+ return (CondCode False cond code')++condIntCode cond x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ dflags <- getDynFlags+ let format = archWordFormat $ target32Bit $ targetPlatform dflags+ code' = code1 `appOL` code2 `snocOL`+ (if condUnsigned cond then CMPL else CMP) format src1 (RIReg src2)+ return (CondCode False cond code')++condFltCode cond x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let+ code' = code1 `appOL` code2 `snocOL` FCMP src1 src2+ code'' = case cond of -- twiddle CR to handle unordered case+ GE -> code' `snocOL` CRNOR ltbit eqbit gtbit+ LE -> code' `snocOL` CRNOR gtbit eqbit ltbit+ _ -> code'+ where+ ltbit = 0 ; eqbit = 2 ; gtbit = 1+ return (CondCode True cond code'')++++-- -----------------------------------------------------------------------------+-- Generating assignments++-- Assignments are really at the heart of the whole code generation+-- business. Almost all top-level nodes of any real importance are+-- assignments, which correspond to loads, stores, or register+-- transfers. If we're really lucky, some of the register transfers+-- will go away, because we can use the destination register to+-- complete the code generation for the right hand side. This only+-- fails when the right hand side is forced into a fixed register+-- (e.g. the result of a call).++assignMem_IntCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock+assignReg_IntCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock++assignMem_FltCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock+assignReg_FltCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock++assignMem_IntCode pk addr src = do+ (srcReg, code) <- getSomeReg src+ Amode dstAddr addr_code <- case pk of+ II64 -> getAmode DS addr+ _ -> getAmode D addr+ return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr++-- dst is a reg, but src could be anything+assignReg_IntCode _ reg src+ = do+ dflags <- getDynFlags+ let dst = getRegisterReg (targetPlatform dflags) reg+ r <- getRegister src+ return $ case r of+ Any _ code -> code dst+ Fixed _ freg fcode -> fcode `snocOL` MR dst freg++++-- Easy, isn't it?+assignMem_FltCode = assignMem_IntCode+assignReg_FltCode = assignReg_IntCode++++genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock++genJump (CmmLit (CmmLabel lbl))+ = return (unitOL $ JMP lbl)++genJump tree+ = do+ dflags <- getDynFlags+ genJump' tree (platformToGCP (targetPlatform dflags))++genJump' :: CmmExpr -> GenCCallPlatform -> NatM InstrBlock++genJump' tree (GCPLinux64ELF 1)+ = do+ (target,code) <- getSomeReg tree+ return (code+ `snocOL` LD II64 r11 (AddrRegImm target (ImmInt 0))+ `snocOL` LD II64 toc (AddrRegImm target (ImmInt 8))+ `snocOL` MTCTR r11+ `snocOL` LD II64 r11 (AddrRegImm target (ImmInt 16))+ `snocOL` BCTR [] Nothing)++genJump' tree (GCPLinux64ELF 2)+ = do+ (target,code) <- getSomeReg tree+ return (code+ `snocOL` MR r12 target+ `snocOL` MTCTR r12+ `snocOL` BCTR [] Nothing)++genJump' tree _+ = do+ (target,code) <- getSomeReg tree+ return (code `snocOL` MTCTR target `snocOL` BCTR [] Nothing)++-- -----------------------------------------------------------------------------+-- Unconditional branches+genBranch :: BlockId -> NatM InstrBlock+genBranch = return . toOL . mkJumpInstr+++-- -----------------------------------------------------------------------------+-- Conditional jumps++{-+Conditional jumps are always to local labels, so we can use branch+instructions. We peek at the arguments to decide what kind of+comparison to do.+-}+++genCondJump+ :: BlockId -- the branch target+ -> CmmExpr -- the condition on which to branch+ -> NatM InstrBlock++genCondJump id bool = do+ CondCode _ cond code <- getCondCode bool+ return (code `snocOL` BCC cond id)++++-- -----------------------------------------------------------------------------+-- Generating C calls++-- Now the biggest nightmare---calls. Most of the nastiness is buried in+-- @get_arg@, which moves the arguments to the correct registers/stack+-- locations. Apart from that, the code is easy.++genCCall :: ForeignTarget -- function to call+ -> [CmmFormal] -- where to put the result+ -> [CmmActual] -- arguments (of mixed type)+ -> NatM InstrBlock+genCCall (PrimTarget MO_WriteBarrier) _ _+ = return $ unitOL LWSYNC++genCCall (PrimTarget MO_Touch) _ _+ = return $ nilOL++genCCall (PrimTarget (MO_Prefetch_Data _)) _ _+ = return $ nilOL++genCCall (PrimTarget (MO_Clz width)) [dst] [src]+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ reg_dst = getRegisterReg platform (CmmLocal dst)+ if target32Bit platform && width == W64+ then do+ ChildCode64 code vr_lo <- iselExpr64 src+ lbl1 <- getBlockIdNat+ lbl2 <- getBlockIdNat+ lbl3 <- getBlockIdNat+ let vr_hi = getHiVRegFromLo vr_lo+ cntlz = toOL [ CMPL II32 vr_hi (RIImm (ImmInt 0))+ , BCC NE lbl2+ , BCC ALWAYS lbl1++ , NEWBLOCK lbl1+ , CNTLZ II32 reg_dst vr_lo+ , ADD reg_dst reg_dst (RIImm (ImmInt 32))+ , BCC ALWAYS lbl3++ , NEWBLOCK lbl2+ , CNTLZ II32 reg_dst vr_hi+ , BCC ALWAYS lbl3++ , NEWBLOCK lbl3+ ]+ return $ code `appOL` cntlz+ else do+ let format = if width == W64 then II64 else II32+ (s_reg, s_code) <- getSomeReg src+ (pre, reg , post) <-+ case width of+ W64 -> return (nilOL, s_reg, nilOL)+ W32 -> return (nilOL, s_reg, nilOL)+ W16 -> do+ reg_tmp <- getNewRegNat format+ return+ ( unitOL $ AND reg_tmp s_reg (RIImm (ImmInt 65535))+ , reg_tmp+ , unitOL $ ADD reg_dst reg_dst (RIImm (ImmInt (-16)))+ )+ W8 -> do+ reg_tmp <- getNewRegNat format+ return+ ( unitOL $ AND reg_tmp s_reg (RIImm (ImmInt 255))+ , reg_tmp+ , unitOL $ ADD reg_dst reg_dst (RIImm (ImmInt (-24)))+ )+ _ -> panic "genCall: Clz wrong format"+ let cntlz = unitOL (CNTLZ format reg_dst reg)+ return $ s_code `appOL` pre `appOL` cntlz `appOL` post++genCCall (PrimTarget (MO_Ctz width)) [dst] [src]+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ reg_dst = getRegisterReg platform (CmmLocal dst)+ if target32Bit platform && width == W64+ then do+ let format = II32+ ChildCode64 code vr_lo <- iselExpr64 src+ lbl1 <- getBlockIdNat+ lbl2 <- getBlockIdNat+ lbl3 <- getBlockIdNat+ x' <- getNewRegNat format+ x'' <- getNewRegNat format+ r' <- getNewRegNat format+ cnttzlo <- cnttz format reg_dst vr_lo+ let vr_hi = getHiVRegFromLo vr_lo+ cnttz64 = toOL [ CMPL format vr_lo (RIImm (ImmInt 0))+ , BCC NE lbl2+ , BCC ALWAYS lbl1++ , NEWBLOCK lbl1+ , ADD x' vr_hi (RIImm (ImmInt (-1)))+ , ANDC x'' x' vr_hi+ , CNTLZ format r' x''+ -- 32 + (32 - clz(x''))+ , SUBFC reg_dst r' (RIImm (ImmInt 64))+ , BCC ALWAYS lbl3++ , NEWBLOCK lbl2+ ]+ `appOL` cnttzlo `appOL`+ toOL [ BCC ALWAYS lbl3++ , NEWBLOCK lbl3+ ]+ return $ code `appOL` cnttz64+ else do+ let format = if width == W64 then II64 else II32+ (s_reg, s_code) <- getSomeReg src+ (reg_ctz, pre_code) <-+ case width of+ W64 -> return (s_reg, nilOL)+ W32 -> return (s_reg, nilOL)+ W16 -> do+ reg_tmp <- getNewRegNat format+ return (reg_tmp, unitOL $ ORIS reg_tmp s_reg (ImmInt 1))+ W8 -> do+ reg_tmp <- getNewRegNat format+ return (reg_tmp, unitOL $ OR reg_tmp s_reg (RIImm (ImmInt 256)))+ _ -> panic "genCall: Ctz wrong format"+ ctz_code <- cnttz format reg_dst reg_ctz+ return $ s_code `appOL` pre_code `appOL` ctz_code+ where+ -- cnttz(x) = sizeof(x) - cntlz(~x & (x - 1))+ -- see Henry S. Warren, Hacker's Delight, p 107+ cnttz format dst src = do+ let format_bits = 8 * formatInBytes format+ x' <- getNewRegNat format+ x'' <- getNewRegNat format+ r' <- getNewRegNat format+ return $ toOL [ ADD x' src (RIImm (ImmInt (-1)))+ , ANDC x'' x' src+ , CNTLZ format r' x''+ , SUBFC dst r' (RIImm (ImmInt (format_bits)))+ ]++genCCall target dest_regs argsAndHints+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ case target of+ PrimTarget (MO_S_QuotRem width) -> divOp1 platform True width+ dest_regs argsAndHints+ PrimTarget (MO_U_QuotRem width) -> divOp1 platform False width+ dest_regs argsAndHints+ PrimTarget (MO_U_QuotRem2 width) -> divOp2 platform width dest_regs+ argsAndHints+ PrimTarget (MO_U_Mul2 width) -> multOp2 platform width dest_regs+ argsAndHints+ PrimTarget (MO_Add2 _) -> add2Op platform dest_regs argsAndHints+ PrimTarget (MO_SubWordC _) -> subcOp platform dest_regs argsAndHints+ PrimTarget (MO_AddIntC width) -> addSubCOp ADDO platform width+ dest_regs argsAndHints+ PrimTarget (MO_SubIntC width) -> addSubCOp SUBFO platform width+ dest_regs argsAndHints+ PrimTarget MO_F64_Fabs -> fabs platform dest_regs argsAndHints+ PrimTarget MO_F32_Fabs -> fabs platform dest_regs argsAndHints+ _ -> genCCall' dflags (platformToGCP platform)+ target dest_regs argsAndHints+ where divOp1 platform signed width [res_q, res_r] [arg_x, arg_y]+ = do let reg_q = getRegisterReg platform (CmmLocal res_q)+ reg_r = getRegisterReg platform (CmmLocal res_r)+ fmt = intFormat width+ (x_reg, x_code) <- getSomeReg arg_x+ (y_reg, y_code) <- getSomeReg arg_y+ return $ y_code `appOL` x_code+ `appOL` toOL [ DIV fmt signed reg_q x_reg y_reg+ , MULL fmt reg_r reg_q (RIReg y_reg)+ , SUBF reg_r reg_r x_reg+ ]++ divOp1 _ _ _ _ _+ = panic "genCCall: Wrong number of arguments for divOp1"+ divOp2 platform width [res_q, res_r]+ [arg_x_high, arg_x_low, arg_y]+ = do let reg_q = getRegisterReg platform (CmmLocal res_q)+ reg_r = getRegisterReg platform (CmmLocal res_r)+ fmt = intFormat width+ half = 4 * (formatInBytes fmt)+ (xh_reg, xh_code) <- getSomeReg arg_x_high+ (xl_reg, xl_code) <- getSomeReg arg_x_low+ (y_reg, y_code) <- getSomeReg arg_y+ s <- getNewRegNat fmt+ b <- getNewRegNat fmt+ v <- getNewRegNat fmt+ vn1 <- getNewRegNat fmt+ vn0 <- getNewRegNat fmt+ un32 <- getNewRegNat fmt+ tmp <- getNewRegNat fmt+ un10 <- getNewRegNat fmt+ un1 <- getNewRegNat fmt+ un0 <- getNewRegNat fmt+ q1 <- getNewRegNat fmt+ rhat <- getNewRegNat fmt+ tmp1 <- getNewRegNat fmt+ q0 <- getNewRegNat fmt+ un21 <- getNewRegNat fmt+ again1 <- getBlockIdNat+ no1 <- getBlockIdNat+ then1 <- getBlockIdNat+ endif1 <- getBlockIdNat+ again2 <- getBlockIdNat+ no2 <- getBlockIdNat+ then2 <- getBlockIdNat+ endif2 <- getBlockIdNat+ return $ y_code `appOL` xl_code `appOL` xh_code `appOL`+ -- see Hacker's Delight p 196 Figure 9-3+ toOL [ -- b = 2 ^ (bits_in_word / 2)+ LI b (ImmInt 1)+ , SL fmt b b (RIImm (ImmInt half))+ -- s = clz(y)+ , CNTLZ fmt s y_reg+ -- v = y << s+ , SL fmt v y_reg (RIReg s)+ -- vn1 = upper half of v+ , SR fmt vn1 v (RIImm (ImmInt half))+ -- vn0 = lower half of v+ , CLRLI fmt vn0 v half+ -- un32 = (u1 << s)+ -- | (u0 >> (bits_in_word - s))+ , SL fmt un32 xh_reg (RIReg s)+ , SUBFC tmp s+ (RIImm (ImmInt (8 * formatInBytes fmt)))+ , SR fmt tmp xl_reg (RIReg tmp)+ , OR un32 un32 (RIReg tmp)+ -- un10 = u0 << s+ , SL fmt un10 xl_reg (RIReg s)+ -- un1 = upper half of un10+ , SR fmt un1 un10 (RIImm (ImmInt half))+ -- un0 = lower half of un10+ , CLRLI fmt un0 un10 half+ -- q1 = un32/vn1+ , DIV fmt False q1 un32 vn1+ -- rhat = un32 - q1*vn1+ , MULL fmt tmp q1 (RIReg vn1)+ , SUBF rhat tmp un32+ , BCC ALWAYS again1++ , NEWBLOCK again1+ -- if (q1 >= b || q1*vn0 > b*rhat + un1)+ , CMPL fmt q1 (RIReg b)+ , BCC GEU then1+ , BCC ALWAYS no1++ , NEWBLOCK no1+ , MULL fmt tmp q1 (RIReg vn0)+ , SL fmt tmp1 rhat (RIImm (ImmInt half))+ , ADD tmp1 tmp1 (RIReg un1)+ , CMPL fmt tmp (RIReg tmp1)+ , BCC LEU endif1+ , BCC ALWAYS then1++ , NEWBLOCK then1+ -- q1 = q1 - 1+ , ADD q1 q1 (RIImm (ImmInt (-1)))+ -- rhat = rhat + vn1+ , ADD rhat rhat (RIReg vn1)+ -- if (rhat < b) goto again1+ , CMPL fmt rhat (RIReg b)+ , BCC LTT again1+ , BCC ALWAYS endif1++ , NEWBLOCK endif1+ -- un21 = un32*b + un1 - q1*v+ , SL fmt un21 un32 (RIImm (ImmInt half))+ , ADD un21 un21 (RIReg un1)+ , MULL fmt tmp q1 (RIReg v)+ , SUBF un21 tmp un21+ -- compute second quotient digit+ -- q0 = un21/vn1+ , DIV fmt False q0 un21 vn1+ -- rhat = un21- q0*vn1+ , MULL fmt tmp q0 (RIReg vn1)+ , SUBF rhat tmp un21+ , BCC ALWAYS again2++ , NEWBLOCK again2+ -- if (q0>b || q0*vn0 > b*rhat + un0)+ , CMPL fmt q0 (RIReg b)+ , BCC GEU then2+ , BCC ALWAYS no2++ , NEWBLOCK no2+ , MULL fmt tmp q0 (RIReg vn0)+ , SL fmt tmp1 rhat (RIImm (ImmInt half))+ , ADD tmp1 tmp1 (RIReg un0)+ , CMPL fmt tmp (RIReg tmp1)+ , BCC LEU endif2+ , BCC ALWAYS then2++ , NEWBLOCK then2+ -- q0 = q0 - 1+ , ADD q0 q0 (RIImm (ImmInt (-1)))+ -- rhat = rhat + vn1+ , ADD rhat rhat (RIReg vn1)+ -- if (rhat<b) goto again2+ , CMPL fmt rhat (RIReg b)+ , BCC LTT again2+ , BCC ALWAYS endif2++ , NEWBLOCK endif2+ -- compute remainder+ -- r = (un21*b + un0 - q0*v) >> s+ , SL fmt reg_r un21 (RIImm (ImmInt half))+ , ADD reg_r reg_r (RIReg un0)+ , MULL fmt tmp q0 (RIReg v)+ , SUBF reg_r tmp reg_r+ , SR fmt reg_r reg_r (RIReg s)+ -- compute quotient+ -- q = q1*b + q0+ , SL fmt reg_q q1 (RIImm (ImmInt half))+ , ADD reg_q reg_q (RIReg q0)+ ]+ divOp2 _ _ _ _+ = panic "genCCall: Wrong number of arguments for divOp2"+ multOp2 platform width [res_h, res_l] [arg_x, arg_y]+ = do let reg_h = getRegisterReg platform (CmmLocal res_h)+ reg_l = getRegisterReg platform (CmmLocal res_l)+ fmt = intFormat width+ (x_reg, x_code) <- getSomeReg arg_x+ (y_reg, y_code) <- getSomeReg arg_y+ return $ y_code `appOL` x_code+ `appOL` toOL [ MULL fmt reg_l x_reg (RIReg y_reg)+ , MULHU fmt reg_h x_reg y_reg+ ]+ multOp2 _ _ _ _+ = panic "genCall: Wrong number of arguments for multOp2"+ add2Op platform [res_h, res_l] [arg_x, arg_y]+ = do let reg_h = getRegisterReg platform (CmmLocal res_h)+ reg_l = getRegisterReg platform (CmmLocal res_l)+ (x_reg, x_code) <- getSomeReg arg_x+ (y_reg, y_code) <- getSomeReg arg_y+ return $ y_code `appOL` x_code+ `appOL` toOL [ LI reg_h (ImmInt 0)+ , ADDC reg_l x_reg y_reg+ , ADDZE reg_h reg_h+ ]+ add2Op _ _ _+ = panic "genCCall: Wrong number of arguments/results for add2"++ -- PowerPC subfc sets the carry for rT = ~(rA) + rB + 1,+ -- which is 0 for borrow and 1 otherwise. We need 1 and 0+ -- so xor with 1.+ subcOp platform [res_r, res_c] [arg_x, arg_y]+ = do let reg_r = getRegisterReg platform (CmmLocal res_r)+ reg_c = getRegisterReg platform (CmmLocal res_c)+ (x_reg, x_code) <- getSomeReg arg_x+ (y_reg, y_code) <- getSomeReg arg_y+ return $ y_code `appOL` x_code+ `appOL` toOL [ LI reg_c (ImmInt 0)+ , SUBFC reg_r y_reg (RIReg x_reg)+ , ADDZE reg_c reg_c+ , XOR reg_c reg_c (RIImm (ImmInt 1))+ ]+ subcOp _ _ _+ = panic "genCCall: Wrong number of arguments/results for subc"+ addSubCOp instr platform width [res_r, res_c] [arg_x, arg_y]+ = do let reg_r = getRegisterReg platform (CmmLocal res_r)+ reg_c = getRegisterReg platform (CmmLocal res_c)+ (x_reg, x_code) <- getSomeReg arg_x+ (y_reg, y_code) <- getSomeReg arg_y+ return $ y_code `appOL` x_code+ `appOL` toOL [ instr reg_r y_reg x_reg,+ -- SUBFO argument order reversed!+ MFOV (intFormat width) reg_c+ ]+ addSubCOp _ _ _ _ _+ = panic "genCall: Wrong number of arguments/results for addC"+ fabs platform [res] [arg]+ = do let res_r = getRegisterReg platform (CmmLocal res)+ (arg_reg, arg_code) <- getSomeReg arg+ return $ arg_code `snocOL` FABS res_r arg_reg+ fabs _ _ _+ = panic "genCall: Wrong number of arguments/results for fabs"++-- TODO: replace 'Int' by an enum such as 'PPC_64ABI'+data GenCCallPlatform = GCPLinux | GCPDarwin | GCPLinux64ELF !Int | GCPAIX++platformToGCP :: Platform -> GenCCallPlatform+platformToGCP platform = case platformOS platform of+ OSLinux -> case platformArch platform of+ ArchPPC -> GCPLinux+ ArchPPC_64 ELF_V1 -> GCPLinux64ELF 1+ ArchPPC_64 ELF_V2 -> GCPLinux64ELF 2+ _ -> panic "PPC.CodeGen.platformToGCP: Unknown Linux"+ OSAIX -> GCPAIX+ OSDarwin -> GCPDarwin+ _ -> panic "PPC.CodeGen.platformToGCP: not defined for this OS"+++genCCall'+ :: DynFlags+ -> GenCCallPlatform+ -> ForeignTarget -- function to call+ -> [CmmFormal] -- where to put the result+ -> [CmmActual] -- arguments (of mixed type)+ -> NatM InstrBlock++{-+ The PowerPC calling convention for Darwin/Mac OS X+ is described in Apple's document+ "Inside Mac OS X - Mach-O Runtime Architecture".++ PowerPC Linux uses the System V Release 4 Calling Convention+ for PowerPC. It is described in the+ "System V Application Binary Interface PowerPC Processor Supplement".++ Both conventions are similar:+ Parameters may be passed in general-purpose registers starting at r3, in+ floating point registers starting at f1, or on the stack.++ But there are substantial differences:+ * The number of registers used for parameter passing and the exact set of+ nonvolatile registers differs (see MachRegs.hs).+ * On Darwin, stack space is always reserved for parameters, even if they are+ passed in registers. The called routine may choose to save parameters from+ registers to the corresponding space on the stack.+ * On Darwin, a corresponding amount of GPRs is skipped when a floating point+ parameter is passed in an FPR.+ * SysV insists on either passing I64 arguments on the stack, or in two GPRs,+ starting with an odd-numbered GPR. It may skip a GPR to achieve this.+ Darwin just treats an I64 like two separate II32s (high word first).+ * I64 and FF64 arguments are 8-byte aligned on the stack for SysV, but only+ 4-byte aligned like everything else on Darwin.+ * The SysV spec claims that FF32 is represented as FF64 on the stack. GCC on+ PowerPC Linux does not agree, so neither do we.++ PowerPC 64 Linux uses the System V Release 4 Calling Convention for+ 64-bit PowerPC. It is specified in+ "64-bit PowerPC ELF Application Binary Interface Supplement 1.9"+ (PPC64 ELF v1.9).+ PowerPC 64 Linux in little endian mode uses the "Power Architecture 64-Bit+ ELF V2 ABI Specification -- OpenPOWER ABI for Linux Supplement"+ (PPC64 ELF v2).+ AIX follows the "PowerOpen ABI: Application Binary Interface Big-Endian+ 32-Bit Hardware Implementation"++ According to all conventions, the parameter area should be part of the+ caller's stack frame, allocated in the caller's prologue code (large enough+ to hold the parameter lists for all called routines). The NCG already+ uses the stack for register spilling, leaving 64 bytes free at the top.+ If we need a larger parameter area than that, we just allocate a new stack+ frame just before ccalling.+-}+++genCCall' dflags gcp target dest_regs args+ = ASSERT(not $ any (`elem` [II16]) $ map cmmTypeFormat argReps)+ -- we rely on argument promotion in the codeGen+ do+ (finalStack,passArgumentsCode,usedRegs) <- passArguments+ (zip args argReps)+ allArgRegs+ (allFPArgRegs platform)+ initialStackOffset+ (toOL []) []++ (labelOrExpr, reduceToFF32) <- case target of+ ForeignTarget (CmmLit (CmmLabel lbl)) _ -> do+ uses_pic_base_implicitly+ return (Left lbl, False)+ ForeignTarget expr _ -> do+ uses_pic_base_implicitly+ return (Right expr, False)+ PrimTarget mop -> outOfLineMachOp mop++ let codeBefore = move_sp_down finalStack `appOL` passArgumentsCode+ codeAfter = move_sp_up finalStack `appOL` moveResult reduceToFF32++ case labelOrExpr of+ Left lbl -> do -- the linker does all the work for us+ return ( codeBefore+ `snocOL` BL lbl usedRegs+ `appOL` maybeNOP -- some ABI require a NOP after BL+ `appOL` codeAfter)+ Right dyn -> do -- implement call through function pointer+ (dynReg, dynCode) <- getSomeReg dyn+ case gcp of+ GCPLinux64ELF 1 -> return ( dynCode+ `appOL` codeBefore+ `snocOL` ST spFormat toc (AddrRegImm sp (ImmInt 40))+ `snocOL` LD II64 r11 (AddrRegImm dynReg (ImmInt 0))+ `snocOL` LD II64 toc (AddrRegImm dynReg (ImmInt 8))+ `snocOL` MTCTR r11+ `snocOL` LD II64 r11 (AddrRegImm dynReg (ImmInt 16))+ `snocOL` BCTRL usedRegs+ `snocOL` LD spFormat toc (AddrRegImm sp (ImmInt 40))+ `appOL` codeAfter)+ GCPLinux64ELF 2 -> return ( dynCode+ `appOL` codeBefore+ `snocOL` ST spFormat toc (AddrRegImm sp (ImmInt 24))+ `snocOL` MR r12 dynReg+ `snocOL` MTCTR r12+ `snocOL` BCTRL usedRegs+ `snocOL` LD spFormat toc (AddrRegImm sp (ImmInt 24))+ `appOL` codeAfter)+ GCPAIX -> return ( dynCode+ -- AIX/XCOFF follows the PowerOPEN ABI+ -- which is quite similiar to LinuxPPC64/ELFv1+ `appOL` codeBefore+ `snocOL` ST spFormat toc (AddrRegImm sp (ImmInt 20))+ `snocOL` LD II32 r11 (AddrRegImm dynReg (ImmInt 0))+ `snocOL` LD II32 toc (AddrRegImm dynReg (ImmInt 4))+ `snocOL` MTCTR r11+ `snocOL` LD II32 r11 (AddrRegImm dynReg (ImmInt 8))+ `snocOL` BCTRL usedRegs+ `snocOL` LD spFormat toc (AddrRegImm sp (ImmInt 20))+ `appOL` codeAfter)+ _ -> return ( dynCode+ `snocOL` MTCTR dynReg+ `appOL` codeBefore+ `snocOL` BCTRL usedRegs+ `appOL` codeAfter)+ where+ platform = targetPlatform dflags++ uses_pic_base_implicitly = do+ -- See Note [implicit register in PPC PIC code]+ -- on why we claim to use PIC register here+ when (gopt Opt_PIC dflags && target32Bit platform) $ do+ _ <- getPicBaseNat $ archWordFormat True+ return ()++ initialStackOffset = case gcp of+ GCPAIX -> 24+ GCPDarwin -> 24+ GCPLinux -> 8+ GCPLinux64ELF 1 -> 48+ GCPLinux64ELF 2 -> 32+ _ -> panic "genCall': unknown calling convention"+ -- size of linkage area + size of arguments, in bytes+ stackDelta finalStack = case gcp of+ GCPAIX ->+ roundTo 16 $ (24 +) $ max 32 $ sum $+ map (widthInBytes . typeWidth) argReps+ GCPDarwin ->+ roundTo 16 $ (24 +) $ max 32 $ sum $+ map (widthInBytes . typeWidth) argReps+ GCPLinux -> roundTo 16 finalStack+ GCPLinux64ELF 1 ->+ roundTo 16 $ (48 +) $ max 64 $ sum $+ map (roundTo 8 . widthInBytes . typeWidth)+ argReps+ GCPLinux64ELF 2 ->+ roundTo 16 $ (32 +) $ max 64 $ sum $+ map (roundTo 8 . widthInBytes . typeWidth)+ argReps+ _ -> panic "genCall': unknown calling conv."++ argReps = map (cmmExprType dflags) args++ roundTo a x | x `mod` a == 0 = x+ | otherwise = x + a - (x `mod` a)++ spFormat = if target32Bit platform then II32 else II64++ -- TODO: Do not create a new stack frame if delta is too large.+ move_sp_down finalStack+ | delta > stackFrameHeaderSize dflags =+ toOL [STU spFormat sp (AddrRegImm sp (ImmInt (-delta))),+ DELTA (-delta)]+ | otherwise = nilOL+ where delta = stackDelta finalStack+ move_sp_up finalStack+ | delta > stackFrameHeaderSize dflags =+ toOL [ADD sp sp (RIImm (ImmInt delta)),+ DELTA 0]+ | otherwise = nilOL+ where delta = stackDelta finalStack++ -- A NOP instruction is required after a call (bl instruction)+ -- on AIX and 64-Bit Linux.+ -- If the call is to a function with a different TOC (r2) the+ -- link editor replaces the NOP instruction with a load of the TOC+ -- from the stack to restore the TOC.+ maybeNOP = case gcp of+ -- See Section 3.9.4 of OpenPower ABI+ GCPAIX -> unitOL NOP+ -- See Section 3.5.11 of PPC64 ELF v1.9+ GCPLinux64ELF 1 -> unitOL NOP+ -- See Section 2.3.6 of PPC64 ELF v2+ GCPLinux64ELF 2 -> unitOL NOP+ _ -> nilOL++ passArguments [] _ _ stackOffset accumCode accumUsed = return (stackOffset, accumCode, accumUsed)+ passArguments ((arg,arg_ty):args) gprs fprs stackOffset+ accumCode accumUsed | isWord64 arg_ty+ && target32Bit (targetPlatform dflags) =+ do+ ChildCode64 code vr_lo <- iselExpr64 arg+ let vr_hi = getHiVRegFromLo vr_lo++ case gcp of+ GCPAIX -> -- same as for Darwin+ do let storeWord vr (gpr:_) _ = MR gpr vr+ storeWord vr [] offset+ = ST II32 vr (AddrRegImm sp (ImmInt offset))+ passArguments args+ (drop 2 gprs)+ fprs+ (stackOffset+8)+ (accumCode `appOL` code+ `snocOL` storeWord vr_hi gprs stackOffset+ `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))+ ((take 2 gprs) ++ accumUsed)+ GCPDarwin ->+ do let storeWord vr (gpr:_) _ = MR gpr vr+ storeWord vr [] offset+ = ST II32 vr (AddrRegImm sp (ImmInt offset))+ passArguments args+ (drop 2 gprs)+ fprs+ (stackOffset+8)+ (accumCode `appOL` code+ `snocOL` storeWord vr_hi gprs stackOffset+ `snocOL` storeWord vr_lo (drop 1 gprs) (stackOffset+4))+ ((take 2 gprs) ++ accumUsed)+ GCPLinux ->+ do let stackOffset' = roundTo 8 stackOffset+ stackCode = accumCode `appOL` code+ `snocOL` ST II32 vr_hi (AddrRegImm sp (ImmInt stackOffset'))+ `snocOL` ST II32 vr_lo (AddrRegImm sp (ImmInt (stackOffset'+4)))+ regCode hireg loreg =+ accumCode `appOL` code+ `snocOL` MR hireg vr_hi+ `snocOL` MR loreg vr_lo++ case gprs of+ hireg : loreg : regs | even (length gprs) ->+ passArguments args regs fprs stackOffset+ (regCode hireg loreg) (hireg : loreg : accumUsed)+ _skipped : hireg : loreg : regs ->+ passArguments args regs fprs stackOffset+ (regCode hireg loreg) (hireg : loreg : accumUsed)+ _ -> -- only one or no regs left+ passArguments args [] fprs (stackOffset'+8)+ stackCode accumUsed+ GCPLinux64ELF _ -> panic "passArguments: 32 bit code"++ passArguments ((arg,rep):args) gprs fprs stackOffset accumCode accumUsed+ | reg : _ <- regs = do+ register <- getRegister arg+ let code = case register of+ Fixed _ freg fcode -> fcode `snocOL` MR reg freg+ Any _ acode -> acode reg+ stackOffsetRes = case gcp of+ -- The Darwin ABI requires that we reserve+ -- stack slots for register parameters+ GCPDarwin -> stackOffset + stackBytes+ -- ... so does the PowerOpen ABI.+ GCPAIX -> stackOffset + stackBytes+ -- ... the SysV ABI 32-bit doesn't.+ GCPLinux -> stackOffset+ -- ... but SysV ABI 64-bit does.+ GCPLinux64ELF _ -> stackOffset + stackBytes+ passArguments args+ (drop nGprs gprs)+ (drop nFprs fprs)+ stackOffsetRes+ (accumCode `appOL` code)+ (reg : accumUsed)+ | otherwise = do+ (vr, code) <- getSomeReg arg+ passArguments args+ (drop nGprs gprs)+ (drop nFprs fprs)+ (stackOffset' + stackBytes)+ (accumCode `appOL` code `snocOL` ST (cmmTypeFormat rep) vr stackSlot)+ accumUsed+ where+ stackOffset' = case gcp of+ GCPDarwin ->+ -- stackOffset is at least 4-byte aligned+ -- The Darwin ABI is happy with that.+ stackOffset+ GCPAIX ->+ -- The 32bit PowerOPEN ABI is happy with+ -- 32bit-alignment as well...+ stackOffset+ GCPLinux+ -- ... the SysV ABI requires 8-byte+ -- alignment for doubles.+ | isFloatType rep && typeWidth rep == W64 ->+ roundTo 8 stackOffset+ | otherwise ->+ stackOffset+ GCPLinux64ELF _ ->+ -- Everything on the stack is mapped to+ -- 8-byte aligned doublewords+ stackOffset+ stackOffset''+ | isFloatType rep && typeWidth rep == W32 =+ case gcp of+ -- The ELF v1 ABI Section 3.2.3 requires:+ -- "Single precision floating point values+ -- are mapped to the second word in a single+ -- doubleword"+ GCPLinux64ELF 1 -> stackOffset' + 4+ _ -> stackOffset'+ | otherwise = stackOffset'++ stackSlot = AddrRegImm sp (ImmInt stackOffset'')+ (nGprs, nFprs, stackBytes, regs)+ = case gcp of+ GCPAIX ->+ case cmmTypeFormat rep of+ II8 -> (1, 0, 4, gprs)+ II16 -> (1, 0, 4, gprs)+ II32 -> (1, 0, 4, gprs)+ -- The PowerOpen ABI requires that we skip a+ -- corresponding number of GPRs when we use+ -- the FPRs.+ --+ -- E.g. for a `double` two GPRs are skipped,+ -- whereas for a `float` one GPR is skipped+ -- when parameters are assigned to+ -- registers.+ --+ -- The PowerOpen ABI specification can be found at+ -- ftp://www.sourceware.org/pub/binutils/ppc-docs/ppc-poweropen/+ FF32 -> (1, 1, 4, fprs)+ FF64 -> (2, 1, 8, fprs)+ II64 -> panic "genCCall' passArguments II64"+ FF80 -> panic "genCCall' passArguments FF80"+ GCPDarwin ->+ case cmmTypeFormat rep of+ II8 -> (1, 0, 4, gprs)+ II16 -> (1, 0, 4, gprs)+ II32 -> (1, 0, 4, gprs)+ -- The Darwin ABI requires that we skip a+ -- corresponding number of GPRs when we use+ -- the FPRs.+ FF32 -> (1, 1, 4, fprs)+ FF64 -> (2, 1, 8, fprs)+ II64 -> panic "genCCall' passArguments II64"+ FF80 -> panic "genCCall' passArguments FF80"+ GCPLinux ->+ case cmmTypeFormat rep of+ II8 -> (1, 0, 4, gprs)+ II16 -> (1, 0, 4, gprs)+ II32 -> (1, 0, 4, gprs)+ -- ... the SysV ABI doesn't.+ FF32 -> (0, 1, 4, fprs)+ FF64 -> (0, 1, 8, fprs)+ II64 -> panic "genCCall' passArguments II64"+ FF80 -> panic "genCCall' passArguments FF80"+ GCPLinux64ELF _ ->+ case cmmTypeFormat rep of+ II8 -> (1, 0, 8, gprs)+ II16 -> (1, 0, 8, gprs)+ II32 -> (1, 0, 8, gprs)+ II64 -> (1, 0, 8, gprs)+ -- The ELFv1 ABI requires that we skip a+ -- corresponding number of GPRs when we use+ -- the FPRs.+ FF32 -> (1, 1, 8, fprs)+ FF64 -> (1, 1, 8, fprs)+ FF80 -> panic "genCCall' passArguments FF80"++ moveResult reduceToFF32 =+ case dest_regs of+ [] -> nilOL+ [dest]+ | reduceToFF32 && isFloat32 rep -> unitOL (FRSP r_dest f1)+ | isFloat32 rep || isFloat64 rep -> unitOL (MR r_dest f1)+ | isWord64 rep && target32Bit (targetPlatform dflags)+ -> toOL [MR (getHiVRegFromLo r_dest) r3,+ MR r_dest r4]+ | otherwise -> unitOL (MR r_dest r3)+ where rep = cmmRegType dflags (CmmLocal dest)+ r_dest = getRegisterReg platform (CmmLocal dest)+ _ -> panic "genCCall' moveResult: Bad dest_regs"++ outOfLineMachOp mop =+ do+ dflags <- getDynFlags+ mopExpr <- cmmMakeDynamicReference dflags CallReference $+ mkForeignLabel functionName Nothing ForeignLabelInThisPackage IsFunction+ let mopLabelOrExpr = case mopExpr of+ CmmLit (CmmLabel lbl) -> Left lbl+ _ -> Right mopExpr+ return (mopLabelOrExpr, reduce)+ where+ (functionName, reduce) = case mop of+ MO_F32_Exp -> (fsLit "exp", True)+ MO_F32_Log -> (fsLit "log", True)+ MO_F32_Sqrt -> (fsLit "sqrt", True)+ MO_F32_Fabs -> unsupported++ MO_F32_Sin -> (fsLit "sin", True)+ MO_F32_Cos -> (fsLit "cos", True)+ MO_F32_Tan -> (fsLit "tan", True)++ MO_F32_Asin -> (fsLit "asin", True)+ MO_F32_Acos -> (fsLit "acos", True)+ MO_F32_Atan -> (fsLit "atan", True)++ MO_F32_Sinh -> (fsLit "sinh", True)+ MO_F32_Cosh -> (fsLit "cosh", True)+ MO_F32_Tanh -> (fsLit "tanh", True)+ MO_F32_Pwr -> (fsLit "pow", True)++ MO_F64_Exp -> (fsLit "exp", False)+ MO_F64_Log -> (fsLit "log", False)+ MO_F64_Sqrt -> (fsLit "sqrt", False)+ MO_F64_Fabs -> unsupported++ MO_F64_Sin -> (fsLit "sin", False)+ MO_F64_Cos -> (fsLit "cos", False)+ MO_F64_Tan -> (fsLit "tan", False)++ MO_F64_Asin -> (fsLit "asin", False)+ MO_F64_Acos -> (fsLit "acos", False)+ MO_F64_Atan -> (fsLit "atan", False)++ MO_F64_Sinh -> (fsLit "sinh", False)+ MO_F64_Cosh -> (fsLit "cosh", False)+ MO_F64_Tanh -> (fsLit "tanh", False)+ MO_F64_Pwr -> (fsLit "pow", False)++ MO_UF_Conv w -> (fsLit $ word2FloatLabel w, False)++ MO_Memcpy _ -> (fsLit "memcpy", False)+ MO_Memset _ -> (fsLit "memset", False)+ MO_Memmove _ -> (fsLit "memmove", False)++ MO_BSwap w -> (fsLit $ bSwapLabel w, False)+ MO_PopCnt w -> (fsLit $ popCntLabel w, False)+ MO_Clz w -> (fsLit $ clzLabel w, False)+ MO_Ctz w -> (fsLit $ ctzLabel w, False)+ MO_AtomicRMW w amop -> (fsLit $ atomicRMWLabel w amop, False)+ MO_Cmpxchg w -> (fsLit $ cmpxchgLabel w, False)+ MO_AtomicRead w -> (fsLit $ atomicReadLabel w, False)+ MO_AtomicWrite w -> (fsLit $ atomicWriteLabel w, False)++ MO_S_QuotRem {} -> unsupported+ MO_U_QuotRem {} -> unsupported+ MO_U_QuotRem2 {} -> unsupported+ MO_Add2 {} -> unsupported+ MO_SubWordC {} -> unsupported+ MO_AddIntC {} -> unsupported+ MO_SubIntC {} -> unsupported+ MO_U_Mul2 {} -> unsupported+ MO_WriteBarrier -> unsupported+ MO_Touch -> unsupported+ (MO_Prefetch_Data _ ) -> unsupported+ unsupported = panic ("outOfLineCmmOp: " ++ show mop+ ++ " not supported")++-- -----------------------------------------------------------------------------+-- Generating a table-branch++genSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> NatM InstrBlock+genSwitch dflags expr targets+ | OSAIX <- platformOS (targetPlatform dflags)+ = do+ (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)+ let fmt = archWordFormat $ target32Bit $ targetPlatform dflags+ sha = if target32Bit $ targetPlatform dflags then 2 else 3+ tmp <- getNewRegNat fmt+ lbl <- getNewLabelNat+ dynRef <- cmmMakeDynamicReference dflags DataReference lbl+ (tableReg,t_code) <- getSomeReg $ dynRef+ let code = e_code `appOL` t_code `appOL` toOL [+ SL fmt tmp reg (RIImm (ImmInt sha)),+ LD fmt tmp (AddrRegReg tableReg tmp),+ MTCTR tmp,+ BCTR ids (Just lbl)+ ]+ return code++ | (gopt Opt_PIC dflags) || (not $ target32Bit $ targetPlatform dflags)+ = do+ (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)+ let fmt = archWordFormat $ target32Bit $ targetPlatform dflags+ sha = if target32Bit $ targetPlatform dflags then 2 else 3+ tmp <- getNewRegNat fmt+ lbl <- getNewLabelNat+ dynRef <- cmmMakeDynamicReference dflags DataReference lbl+ (tableReg,t_code) <- getSomeReg $ dynRef+ let code = e_code `appOL` t_code `appOL` toOL [+ SL fmt tmp reg (RIImm (ImmInt sha)),+ LD fmt tmp (AddrRegReg tableReg tmp),+ ADD tmp tmp (RIReg tableReg),+ MTCTR tmp,+ BCTR ids (Just lbl)+ ]+ return code+ | otherwise+ = do+ (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)+ let fmt = archWordFormat $ target32Bit $ targetPlatform dflags+ sha = if target32Bit $ targetPlatform dflags then 2 else 3+ tmp <- getNewRegNat fmt+ lbl <- getNewLabelNat+ let code = e_code `appOL` toOL [+ SL fmt tmp reg (RIImm (ImmInt sha)),+ ADDIS tmp tmp (HA (ImmCLbl lbl)),+ LD fmt tmp (AddrRegImm tmp (LO (ImmCLbl lbl))),+ MTCTR tmp,+ BCTR ids (Just lbl)+ ]+ return code+ where (offset, ids) = switchTargetsToTable targets++generateJumpTableForInstr :: DynFlags -> Instr+ -> Maybe (NatCmmDecl CmmStatics Instr)+generateJumpTableForInstr dflags (BCTR ids (Just lbl)) =+ let jumpTable+ | (gopt Opt_PIC dflags)+ || (not $ target32Bit $ targetPlatform dflags)+ = map jumpTableEntryRel ids+ | otherwise = map (jumpTableEntry dflags) ids+ where jumpTableEntryRel Nothing+ = CmmStaticLit (CmmInt 0 (wordWidth dflags))+ jumpTableEntryRel (Just blockid)+ = CmmStaticLit (CmmLabelDiffOff blockLabel lbl 0)+ where blockLabel = mkAsmTempLabel (getUnique blockid)+ in Just (CmmData (Section ReadOnlyData lbl) (Statics lbl jumpTable))+generateJumpTableForInstr _ _ = Nothing++-- -----------------------------------------------------------------------------+-- 'condIntReg' and 'condFltReg': condition codes into registers++-- Turn those condition codes into integers now (when they appear on+-- the right hand side of an assignment).++condIntReg, condFltReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register++condReg :: NatM CondCode -> NatM Register+condReg getCond = do+ CondCode _ cond cond_code <- getCond+ dflags <- getDynFlags+ let+ code dst = cond_code+ `appOL` negate_code+ `appOL` toOL [+ MFCR dst,+ RLWINM dst dst (bit + 1) 31 31+ ]++ negate_code | do_negate = unitOL (CRNOR bit bit bit)+ | otherwise = nilOL++ (bit, do_negate) = case cond of+ LTT -> (0, False)+ LE -> (1, True)+ EQQ -> (2, False)+ GE -> (0, True)+ GTT -> (1, False)++ NE -> (2, True)++ LU -> (0, False)+ LEU -> (1, True)+ GEU -> (0, True)+ GU -> (1, False)+ _ -> panic "PPC.CodeGen.codeReg: no match"++ format = archWordFormat $ target32Bit $ targetPlatform dflags+ return (Any format code)++condIntReg cond x y = condReg (condIntCode cond x y)+condFltReg cond x y = condReg (condFltCode cond x y)++++-- -----------------------------------------------------------------------------+-- 'trivial*Code': deal with trivial instructions++-- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',+-- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.+-- Only look for constants on the right hand side, because that's+-- where the generic optimizer will have put them.++-- Similarly, for unary instructions, we don't have to worry about+-- matching an StInt as the argument, because genericOpt will already+-- have handled the constant-folding.++++{-+Wolfgang's PowerPC version of The Rules:++A slightly modified version of The Rules to take advantage of the fact+that PowerPC instructions work on all registers and don't implicitly+clobber any fixed registers.++* The only expression for which getRegister returns Fixed is (CmmReg reg).++* If getRegister returns Any, then the code it generates may modify only:+ (a) fresh temporaries+ (b) the destination register+ It may *not* modify global registers, unless the global+ register happens to be the destination register.+ It may not clobber any other registers. In fact, only ccalls clobber any+ fixed registers.+ Also, it may not modify the counter register (used by genCCall).++ Corollary: If a getRegister for a subexpression returns Fixed, you need+ not move it to a fresh temporary before evaluating the next subexpression.+ The Fixed register won't be modified.+ Therefore, we don't need a counterpart for the x86's getStableReg on PPC.++* SDM's First Rule is valid for PowerPC, too: subexpressions can depend on+ the value of the destination register.+-}++trivialCode+ :: Width+ -> Bool+ -> (Reg -> Reg -> RI -> Instr)+ -> CmmExpr+ -> CmmExpr+ -> NatM Register++trivialCode rep signed instr x (CmmLit (CmmInt y _))+ | Just imm <- makeImmediate rep signed y+ = do+ (src1, code1) <- getSomeReg x+ let code dst = code1 `snocOL` instr dst src1 (RIImm imm)+ return (Any (intFormat rep) code)++trivialCode rep _ instr x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let code dst = code1 `appOL` code2 `snocOL` instr dst src1 (RIReg src2)+ return (Any (intFormat rep) code)++shiftMulCode+ :: Width+ -> Bool+ -> (Format-> Reg -> Reg -> RI -> Instr)+ -> CmmExpr+ -> CmmExpr+ -> NatM Register+shiftMulCode width sign instr x (CmmLit (CmmInt y _))+ | Just imm <- makeImmediate width sign y+ = do+ (src1, code1) <- getSomeReg x+ let format = intFormat width+ let code dst = code1 `snocOL` instr format dst src1 (RIImm imm)+ return (Any format code)++shiftMulCode width _ instr x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let format = intFormat width+ let code dst = code1 `appOL` code2 `snocOL` instr format dst src1 (RIReg src2)+ return (Any format code)++trivialCodeNoImm' :: Format -> (Reg -> Reg -> Reg -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialCodeNoImm' format instr x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let code dst = code1 `appOL` code2 `snocOL` instr dst src1 src2+ return (Any format code)++trivialCodeNoImm :: Format -> (Format -> Reg -> Reg -> Reg -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialCodeNoImm format instr x y = trivialCodeNoImm' format (instr format) x y++trivialCodeNoImmSign :: Format -> Bool+ -> (Format -> Bool -> Reg -> Reg -> Reg -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialCodeNoImmSign format sgn instr x y+ = trivialCodeNoImm' format (instr format sgn) x y+++trivialUCode+ :: Format+ -> (Reg -> Reg -> Instr)+ -> CmmExpr+ -> NatM Register+trivialUCode rep instr x = do+ (src, code) <- getSomeReg x+ let code' dst = code `snocOL` instr dst src+ return (Any rep code')++-- There is no "remainder" instruction on the PPC, so we have to do+-- it the hard way.+-- The "sgn" parameter is the signedness for the division instruction++remainderCode :: Width -> Bool -> CmmExpr -> CmmExpr -> NatM Register+remainderCode rep sgn x y = do+ let fmt = intFormat rep+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let code dst = code1 `appOL` code2 `appOL` toOL [+ DIV fmt sgn dst src1 src2,+ MULL fmt dst dst (RIReg src2),+ SUBF dst dst src1+ ]+ return (Any (intFormat rep) code)++coerceInt2FP :: Width -> Width -> CmmExpr -> NatM Register+coerceInt2FP fromRep toRep x = do+ dflags <- getDynFlags+ let arch = platformArch $ targetPlatform dflags+ coerceInt2FP' arch fromRep toRep x++coerceInt2FP' :: Arch -> Width -> Width -> CmmExpr -> NatM Register+coerceInt2FP' ArchPPC fromRep toRep x = do+ (src, code) <- getSomeReg x+ lbl <- getNewLabelNat+ itmp <- getNewRegNat II32+ ftmp <- getNewRegNat FF64+ dflags <- getDynFlags+ dynRef <- cmmMakeDynamicReference dflags DataReference lbl+ Amode addr addr_code <- getAmode D dynRef+ let+ code' dst = code `appOL` maybe_exts `appOL` toOL [+ LDATA (Section ReadOnlyData lbl) $ Statics lbl+ [CmmStaticLit (CmmInt 0x43300000 W32),+ CmmStaticLit (CmmInt 0x80000000 W32)],+ XORIS itmp src (ImmInt 0x8000),+ ST II32 itmp (spRel dflags 3),+ LIS itmp (ImmInt 0x4330),+ ST II32 itmp (spRel dflags 2),+ LD FF64 ftmp (spRel dflags 2)+ ] `appOL` addr_code `appOL` toOL [+ LD FF64 dst addr,+ FSUB FF64 dst ftmp dst+ ] `appOL` maybe_frsp dst++ maybe_exts = case fromRep of+ W8 -> unitOL $ EXTS II8 src src+ W16 -> unitOL $ EXTS II16 src src+ W32 -> nilOL+ _ -> panic "PPC.CodeGen.coerceInt2FP: no match"++ maybe_frsp dst+ = case toRep of+ W32 -> unitOL $ FRSP dst dst+ W64 -> nilOL+ _ -> panic "PPC.CodeGen.coerceInt2FP: no match"++ return (Any (floatFormat toRep) code')++-- On an ELF v1 Linux we use the compiler doubleword in the stack frame+-- this is the TOC pointer doubleword on ELF v2 Linux. The latter is only+-- set right before a call and restored right after return from the call.+-- So it is fine.+coerceInt2FP' (ArchPPC_64 _) fromRep toRep x = do+ (src, code) <- getSomeReg x+ dflags <- getDynFlags+ let+ code' dst = code `appOL` maybe_exts `appOL` toOL [+ ST II64 src (spRel dflags 3),+ LD FF64 dst (spRel dflags 3),+ FCFID dst dst+ ] `appOL` maybe_frsp dst++ maybe_exts = case fromRep of+ W8 -> unitOL $ EXTS II8 src src+ W16 -> unitOL $ EXTS II16 src src+ W32 -> unitOL $ EXTS II32 src src+ W64 -> nilOL+ _ -> panic "PPC.CodeGen.coerceInt2FP: no match"++ maybe_frsp dst+ = case toRep of+ W32 -> unitOL $ FRSP dst dst+ W64 -> nilOL+ _ -> panic "PPC.CodeGen.coerceInt2FP: no match"++ return (Any (floatFormat toRep) code')++coerceInt2FP' _ _ _ _ = panic "PPC.CodeGen.coerceInt2FP: unknown arch"+++coerceFP2Int :: Width -> Width -> CmmExpr -> NatM Register+coerceFP2Int fromRep toRep x = do+ dflags <- getDynFlags+ let arch = platformArch $ targetPlatform dflags+ coerceFP2Int' arch fromRep toRep x++coerceFP2Int' :: Arch -> Width -> Width -> CmmExpr -> NatM Register+coerceFP2Int' ArchPPC _ toRep x = do+ dflags <- getDynFlags+ -- the reps don't really matter: F*->FF64 and II32->I* are no-ops+ (src, code) <- getSomeReg x+ tmp <- getNewRegNat FF64+ let+ code' dst = code `appOL` toOL [+ -- convert to int in FP reg+ FCTIWZ tmp src,+ -- store value (64bit) from FP to stack+ ST FF64 tmp (spRel dflags 2),+ -- read low word of value (high word is undefined)+ LD II32 dst (spRel dflags 3)]+ return (Any (intFormat toRep) code')++coerceFP2Int' (ArchPPC_64 _) _ toRep x = do+ dflags <- getDynFlags+ -- the reps don't really matter: F*->FF64 and II64->I* are no-ops+ (src, code) <- getSomeReg x+ tmp <- getNewRegNat FF64+ let+ code' dst = code `appOL` toOL [+ -- convert to int in FP reg+ FCTIDZ tmp src,+ -- store value (64bit) from FP to compiler word on stack+ ST FF64 tmp (spRel dflags 3),+ LD II64 dst (spRel dflags 3)]+ return (Any (intFormat toRep) code')++coerceFP2Int' _ _ _ _ = panic "PPC.CodeGen.coerceFP2Int: unknown arch"++-- Note [.LCTOC1 in PPC PIC code]+-- The .LCTOC1 label is defined to point 32768 bytes into the GOT table+-- to make the most of the PPC's 16-bit displacements.+-- As 16-bit signed offset is used (usually via addi/lwz instructions)+-- first element will have '-32768' offset against .LCTOC1.++-- Note [implicit register in PPC PIC code]+-- PPC generates calls by labels in assembly+-- in form of:+-- bl puts+32768@plt+-- in this form it's not seen directly (by GHC NCG)+-- that r30 (PicBaseReg) is used,+-- but r30 is a required part of PLT code setup:+-- puts+32768@plt:+-- lwz r11,-30484(r30) ; offset in .LCTOC1+-- mtctr r11+-- bctr
+ nativeGen/PPC/Cond.hs view
@@ -0,0 +1,61 @@+module PPC.Cond (+ Cond(..),+ condNegate,+ condUnsigned,+ condToSigned,+ condToUnsigned,+)++where++import Panic++data Cond+ = ALWAYS+ | EQQ+ | GE+ | GEU+ | GTT+ | GU+ | LE+ | LEU+ | LTT+ | LU+ | NE+ deriving Eq+++condNegate :: Cond -> Cond+condNegate ALWAYS = panic "condNegate: ALWAYS"+condNegate EQQ = NE+condNegate GE = LTT+condNegate GEU = LU+condNegate GTT = LE+condNegate GU = LEU+condNegate LE = GTT+condNegate LEU = GU+condNegate LTT = GE+condNegate LU = GEU+condNegate NE = EQQ++-- Condition utils+condUnsigned :: Cond -> Bool+condUnsigned GU = True+condUnsigned LU = True+condUnsigned GEU = True+condUnsigned LEU = True+condUnsigned _ = False++condToSigned :: Cond -> Cond+condToSigned GU = GTT+condToSigned LU = LTT+condToSigned GEU = GE+condToSigned LEU = LE+condToSigned x = x++condToUnsigned :: Cond -> Cond+condToUnsigned GTT = GU+condToUnsigned LTT = LU+condToUnsigned GE = GEU+condToUnsigned LE = LEU+condToUnsigned x = x
+ nativeGen/PPC/Instr.hs view
@@ -0,0 +1,686 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Machine-dependent assembly language+--+-- (c) The University of Glasgow 1993-2004+--+-----------------------------------------------------------------------------++#include "HsVersions.h"+#include "nativeGen/NCG.h"++module PPC.Instr (+ archWordFormat,+ RI(..),+ Instr(..),+ stackFrameHeaderSize,+ maxSpillSlots,+ allocMoreStack,+ makeFarBranches+)++where++import PPC.Regs+import PPC.Cond+import Instruction+import Format+import TargetReg+import RegClass+import Reg++import CodeGen.Platform+import BlockId+import Hoopl+import DynFlags+import Cmm+import CmmInfo+import FastString+import CLabel+import Outputable+import Platform+import UniqFM (listToUFM, lookupUFM)+import UniqSupply++import Control.Monad (replicateM)+import Data.Maybe (fromMaybe)++--------------------------------------------------------------------------------+-- Format of a PPC memory address.+--+archWordFormat :: Bool -> Format+archWordFormat is32Bit+ | is32Bit = II32+ | otherwise = II64+++-- | Instruction instance for powerpc+instance Instruction Instr where+ regUsageOfInstr = ppc_regUsageOfInstr+ patchRegsOfInstr = ppc_patchRegsOfInstr+ isJumpishInstr = ppc_isJumpishInstr+ jumpDestsOfInstr = ppc_jumpDestsOfInstr+ patchJumpInstr = ppc_patchJumpInstr+ mkSpillInstr = ppc_mkSpillInstr+ mkLoadInstr = ppc_mkLoadInstr+ takeDeltaInstr = ppc_takeDeltaInstr+ isMetaInstr = ppc_isMetaInstr+ mkRegRegMoveInstr _ = ppc_mkRegRegMoveInstr+ takeRegRegMoveInstr = ppc_takeRegRegMoveInstr+ mkJumpInstr = ppc_mkJumpInstr+ mkStackAllocInstr = ppc_mkStackAllocInstr+ mkStackDeallocInstr = ppc_mkStackDeallocInstr+++ppc_mkStackAllocInstr :: Platform -> Int -> Instr+ppc_mkStackAllocInstr platform amount+ = ppc_mkStackAllocInstr' platform (-amount)++ppc_mkStackDeallocInstr :: Platform -> Int -> Instr+ppc_mkStackDeallocInstr platform amount+ = ppc_mkStackAllocInstr' platform amount++ppc_mkStackAllocInstr' :: Platform -> Int -> Instr+ppc_mkStackAllocInstr' platform amount+ = case platformArch platform of+ ArchPPC -> UPDATE_SP II32 (ImmInt amount)+ ArchPPC_64 _ -> UPDATE_SP II64 (ImmInt amount)+ _ -> panic $ "ppc_mkStackAllocInstr' "+ ++ show (platformArch platform)++--+-- See note [extra spill slots] in X86/Instr.hs+--+allocMoreStack+ :: Platform+ -> Int+ -> NatCmmDecl statics PPC.Instr.Instr+ -> UniqSM (NatCmmDecl statics PPC.Instr.Instr)++allocMoreStack _ _ top@(CmmData _ _) = return top+allocMoreStack platform slots (CmmProc info lbl live (ListGraph code)) = do+ let+ infos = mapKeys info+ entries = case code of+ [] -> infos+ BasicBlock entry _ : _ -- first block is the entry point+ | entry `elem` infos -> infos+ | otherwise -> entry : infos++ uniqs <- replicateM (length entries) getUniqueM++ let+ delta = ((x + stackAlign - 1) `quot` stackAlign) * stackAlign -- round up+ where x = slots * spillSlotSize -- sp delta++ alloc = mkStackAllocInstr platform delta+ dealloc = mkStackDeallocInstr platform delta++ new_blockmap :: LabelMap BlockId+ new_blockmap = mapFromList (zip entries (map mkBlockId uniqs))++ insert_stack_insns (BasicBlock id insns)+ | Just new_blockid <- mapLookup id new_blockmap+ = [ BasicBlock id [alloc, BCC ALWAYS new_blockid]+ , BasicBlock new_blockid block'+ ]+ | otherwise+ = [ BasicBlock id block' ]+ where+ block' = foldr insert_dealloc [] insns++ insert_dealloc insn r+ -- BCTR might or might not be a non-local jump. For+ -- "labeled-goto" we use JMP, and for "computed-goto" we+ -- use MTCTR followed by BCTR. See 'PPC.CodeGen.genJump'.+ = case insn of+ JMP _ -> dealloc : insn : r+ BCTR [] Nothing -> dealloc : insn : r+ BCTR ids label -> BCTR (map (fmap retarget) ids) label : r+ BCCFAR cond b -> BCCFAR cond (retarget b) : r+ BCC cond b -> BCC cond (retarget b) : r+ _ -> insn : r+ -- BL and BCTRL are call-like instructions rather than+ -- jumps, and are used only for C calls.++ retarget :: BlockId -> BlockId+ retarget b+ = fromMaybe b (mapLookup b new_blockmap)++ new_code+ = concatMap insert_stack_insns code++ -- in+ return (CmmProc info lbl live (ListGraph new_code))+++-- -----------------------------------------------------------------------------+-- Machine's assembly language++-- We have a few common "instructions" (nearly all the pseudo-ops) but+-- mostly all of 'Instr' is machine-specific.++-- Register or immediate+data RI+ = RIReg Reg+ | RIImm Imm++data Instr+ -- comment pseudo-op+ = COMMENT FastString++ -- some static data spat out during code+ -- generation. Will be extracted before+ -- pretty-printing.+ | LDATA Section CmmStatics++ -- start a new basic block. Useful during+ -- codegen, removed later. Preceding+ -- instruction should be a jump, as per the+ -- invariants for a BasicBlock (see Cmm).+ | NEWBLOCK BlockId++ -- specify current stack offset for+ -- benefit of subsequent passes+ | DELTA Int++ -- Loads and stores.+ | LD Format Reg AddrMode -- Load format, dst, src+ | LDFAR Format Reg AddrMode -- Load format, dst, src 32 bit offset+ | LA Format Reg AddrMode -- Load arithmetic format, dst, src+ | ST Format Reg AddrMode -- Store format, src, dst+ | STFAR Format Reg AddrMode -- Store format, src, dst 32 bit offset+ | STU Format Reg AddrMode -- Store with Update format, src, dst+ | LIS Reg Imm -- Load Immediate Shifted dst, src+ | LI Reg Imm -- Load Immediate dst, src+ | MR Reg Reg -- Move Register dst, src -- also for fmr++ | CMP Format Reg RI -- format, src1, src2+ | CMPL Format Reg RI -- format, src1, src2++ | BCC Cond BlockId+ | BCCFAR Cond BlockId+ | JMP CLabel -- same as branch,+ -- but with CLabel instead of block ID+ | MTCTR Reg+ | BCTR [Maybe BlockId] (Maybe CLabel) -- with list of local destinations, and jump table location if necessary+ | BL CLabel [Reg] -- with list of argument regs+ | BCTRL [Reg]++ | ADD Reg Reg RI -- dst, src1, src2+ | ADDO Reg Reg Reg -- add and set overflow+ | ADDC Reg Reg Reg -- (carrying) dst, src1, src2+ | ADDE Reg Reg Reg -- (extended) dst, src1, src2+ | ADDZE Reg Reg -- (to zero extended) dst, src+ | ADDIS Reg Reg Imm -- Add Immediate Shifted dst, src1, src2+ | SUBF Reg Reg Reg -- dst, src1, src2 ; dst = src2 - src1+ | SUBFO Reg Reg Reg -- subtract from and set overflow+ | SUBFC Reg Reg RI -- (carrying) dst, src1, src2 ;+ -- dst = src2 - src1+ | SUBFE Reg Reg Reg -- (extended) dst, src1, src2 ;+ -- dst = src2 - src1+ | MULL Format Reg Reg RI+ | MULLO Format Reg Reg Reg -- multiply and set overflow+ | MFOV Format Reg -- move overflow bit (1|33) to register+ -- pseudo-instruction; pretty printed as+ -- mfxer dst+ -- extr[w|d]i dst, dst, 1, [1|33]+ | MULHU Format Reg Reg Reg+ | DIV Format Bool Reg Reg Reg+ | AND Reg Reg RI -- dst, src1, src2+ | ANDC Reg Reg Reg -- AND with complement, dst = src1 & ~ src2+ | OR Reg Reg RI -- dst, src1, src2+ | ORIS Reg Reg Imm -- OR Immediate Shifted dst, src1, src2+ | XOR Reg Reg RI -- dst, src1, src2+ | XORIS Reg Reg Imm -- XOR Immediate Shifted dst, src1, src2++ | EXTS Format Reg Reg+ | CNTLZ Format Reg Reg++ | NEG Reg Reg+ | NOT Reg Reg++ | SL Format Reg Reg RI -- shift left+ | SR Format Reg Reg RI -- shift right+ | SRA Format Reg Reg RI -- shift right arithmetic++ | RLWINM Reg Reg Int Int Int -- Rotate Left Word Immediate then AND with Mask+ | CLRLI Format Reg Reg Int -- clear left immediate (extended mnemonic)+ | CLRRI Format Reg Reg Int -- clear right immediate (extended mnemonic)++ | FADD Format Reg Reg Reg+ | FSUB Format Reg Reg Reg+ | FMUL Format Reg Reg Reg+ | FDIV Format Reg Reg Reg+ | FABS Reg Reg -- abs is the same for single and double+ | FNEG Reg Reg -- negate is the same for single and double prec.++ | FCMP Reg Reg++ | FCTIWZ Reg Reg -- convert to integer word+ | FCTIDZ Reg Reg -- convert to integer double word+ | FCFID Reg Reg -- convert from integer double word+ | FRSP Reg Reg -- reduce to single precision+ -- (but destination is a FP register)++ | CRNOR Int Int Int -- condition register nor+ | MFCR Reg -- move from condition register++ | MFLR Reg -- move from link register+ | FETCHPC Reg -- pseudo-instruction:+ -- bcl to next insn, mflr reg+ | LWSYNC -- memory barrier+ | NOP -- no operation, PowerPC 64 bit+ -- needs this as place holder to+ -- reload TOC pointer+ | UPDATE_SP Format Imm -- expand/shrink spill area on C stack+ -- pseudo-instruction++-- | Get the registers that are being used by this instruction.+-- regUsage doesn't need to do any trickery for jumps and such.+-- Just state precisely the regs read and written by that insn.+-- The consequences of control flow transfers, as far as register+-- allocation goes, are taken care of by the register allocator.+--+ppc_regUsageOfInstr :: Platform -> Instr -> RegUsage+ppc_regUsageOfInstr platform instr+ = case instr of+ LD _ reg addr -> usage (regAddr addr, [reg])+ LDFAR _ reg addr -> usage (regAddr addr, [reg])+ LA _ reg addr -> usage (regAddr addr, [reg])+ ST _ reg addr -> usage (reg : regAddr addr, [])+ STFAR _ reg addr -> usage (reg : regAddr addr, [])+ STU _ reg addr -> usage (reg : regAddr addr, [])+ LIS reg _ -> usage ([], [reg])+ LI reg _ -> usage ([], [reg])+ MR reg1 reg2 -> usage ([reg2], [reg1])+ CMP _ reg ri -> usage (reg : regRI ri,[])+ CMPL _ reg ri -> usage (reg : regRI ri,[])+ BCC _ _ -> noUsage+ BCCFAR _ _ -> noUsage+ MTCTR reg -> usage ([reg],[])+ BCTR _ _ -> noUsage+ BL _ params -> usage (params, callClobberedRegs platform)+ BCTRL params -> usage (params, callClobberedRegs platform)++ ADD reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ ADDO reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ ADDC reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ ADDE reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ ADDZE reg1 reg2 -> usage ([reg2], [reg1])+ ADDIS reg1 reg2 _ -> usage ([reg2], [reg1])+ SUBF reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ SUBFO reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ SUBFC reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ SUBFE reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ MULL _ reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ MULLO _ reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ MFOV _ reg -> usage ([], [reg])+ MULHU _ reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ DIV _ _ reg1 reg2 reg3+ -> usage ([reg2,reg3], [reg1])++ AND reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ ANDC reg1 reg2 reg3 -> usage ([reg2,reg3], [reg1])+ OR reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ ORIS reg1 reg2 _ -> usage ([reg2], [reg1])+ XOR reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ XORIS reg1 reg2 _ -> usage ([reg2], [reg1])+ EXTS _ reg1 reg2 -> usage ([reg2], [reg1])+ CNTLZ _ reg1 reg2 -> usage ([reg2], [reg1])+ NEG reg1 reg2 -> usage ([reg2], [reg1])+ NOT reg1 reg2 -> usage ([reg2], [reg1])+ SL _ reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ SR _ reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ SRA _ reg1 reg2 ri -> usage (reg2 : regRI ri, [reg1])+ RLWINM reg1 reg2 _ _ _ -> usage ([reg2], [reg1])+ CLRLI _ reg1 reg2 _ -> usage ([reg2], [reg1])+ CLRRI _ reg1 reg2 _ -> usage ([reg2], [reg1])++ FADD _ r1 r2 r3 -> usage ([r2,r3], [r1])+ FSUB _ r1 r2 r3 -> usage ([r2,r3], [r1])+ FMUL _ r1 r2 r3 -> usage ([r2,r3], [r1])+ FDIV _ r1 r2 r3 -> usage ([r2,r3], [r1])+ FABS r1 r2 -> usage ([r2], [r1])+ FNEG r1 r2 -> usage ([r2], [r1])+ FCMP r1 r2 -> usage ([r1,r2], [])+ FCTIWZ r1 r2 -> usage ([r2], [r1])+ FCTIDZ r1 r2 -> usage ([r2], [r1])+ FCFID r1 r2 -> usage ([r2], [r1])+ FRSP r1 r2 -> usage ([r2], [r1])+ MFCR reg -> usage ([], [reg])+ MFLR reg -> usage ([], [reg])+ FETCHPC reg -> usage ([], [reg])+ UPDATE_SP _ _ -> usage ([], [sp])+ _ -> noUsage+ where+ usage (src, dst) = RU (filter (interesting platform) src)+ (filter (interesting platform) dst)+ regAddr (AddrRegReg r1 r2) = [r1, r2]+ regAddr (AddrRegImm r1 _) = [r1]++ regRI (RIReg r) = [r]+ regRI _ = []++interesting :: Platform -> Reg -> Bool+interesting _ (RegVirtual _) = True+interesting platform (RegReal (RealRegSingle i)) = freeReg platform i+interesting _ (RegReal (RealRegPair{}))+ = panic "PPC.Instr.interesting: no reg pairs on this arch"++++-- | Apply a given mapping to all the register references in this+-- instruction.+ppc_patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr+ppc_patchRegsOfInstr instr env+ = case instr of+ LD fmt reg addr -> LD fmt (env reg) (fixAddr addr)+ LDFAR fmt reg addr -> LDFAR fmt (env reg) (fixAddr addr)+ LA fmt reg addr -> LA fmt (env reg) (fixAddr addr)+ ST fmt reg addr -> ST fmt (env reg) (fixAddr addr)+ STFAR fmt reg addr -> STFAR fmt (env reg) (fixAddr addr)+ STU fmt reg addr -> STU fmt (env reg) (fixAddr addr)+ LIS reg imm -> LIS (env reg) imm+ LI reg imm -> LI (env reg) imm+ MR reg1 reg2 -> MR (env reg1) (env reg2)+ CMP fmt reg ri -> CMP fmt (env reg) (fixRI ri)+ CMPL fmt reg ri -> CMPL fmt (env reg) (fixRI ri)+ BCC cond lbl -> BCC cond lbl+ BCCFAR cond lbl -> BCCFAR cond lbl+ MTCTR reg -> MTCTR (env reg)+ BCTR targets lbl -> BCTR targets lbl+ BL imm argRegs -> BL imm argRegs -- argument regs+ BCTRL argRegs -> BCTRL argRegs -- cannot be remapped+ ADD reg1 reg2 ri -> ADD (env reg1) (env reg2) (fixRI ri)+ ADDO reg1 reg2 reg3 -> ADDO (env reg1) (env reg2) (env reg3)+ ADDC reg1 reg2 reg3 -> ADDC (env reg1) (env reg2) (env reg3)+ ADDE reg1 reg2 reg3 -> ADDE (env reg1) (env reg2) (env reg3)+ ADDZE reg1 reg2 -> ADDZE (env reg1) (env reg2)+ ADDIS reg1 reg2 imm -> ADDIS (env reg1) (env reg2) imm+ SUBF reg1 reg2 reg3 -> SUBF (env reg1) (env reg2) (env reg3)+ SUBFO reg1 reg2 reg3 -> SUBFO (env reg1) (env reg2) (env reg3)+ SUBFC reg1 reg2 ri -> SUBFC (env reg1) (env reg2) (fixRI ri)+ SUBFE reg1 reg2 reg3 -> SUBFE (env reg1) (env reg2) (env reg3)+ MULL fmt reg1 reg2 ri+ -> MULL fmt (env reg1) (env reg2) (fixRI ri)+ MULLO fmt reg1 reg2 reg3+ -> MULLO fmt (env reg1) (env reg2) (env reg3)+ MFOV fmt reg -> MFOV fmt (env reg)+ MULHU fmt reg1 reg2 reg3+ -> MULHU fmt (env reg1) (env reg2) (env reg3)+ DIV fmt sgn reg1 reg2 reg3+ -> DIV fmt sgn (env reg1) (env reg2) (env reg3)++ AND reg1 reg2 ri -> AND (env reg1) (env reg2) (fixRI ri)+ ANDC reg1 reg2 reg3 -> ANDC (env reg1) (env reg2) (env reg3)+ OR reg1 reg2 ri -> OR (env reg1) (env reg2) (fixRI ri)+ ORIS reg1 reg2 imm -> ORIS (env reg1) (env reg2) imm+ XOR reg1 reg2 ri -> XOR (env reg1) (env reg2) (fixRI ri)+ XORIS reg1 reg2 imm -> XORIS (env reg1) (env reg2) imm+ EXTS fmt reg1 reg2 -> EXTS fmt (env reg1) (env reg2)+ CNTLZ fmt reg1 reg2 -> CNTLZ fmt (env reg1) (env reg2)+ NEG reg1 reg2 -> NEG (env reg1) (env reg2)+ NOT reg1 reg2 -> NOT (env reg1) (env reg2)+ SL fmt reg1 reg2 ri+ -> SL fmt (env reg1) (env reg2) (fixRI ri)+ SR fmt reg1 reg2 ri+ -> SR fmt (env reg1) (env reg2) (fixRI ri)+ SRA fmt reg1 reg2 ri+ -> SRA fmt (env reg1) (env reg2) (fixRI ri)+ RLWINM reg1 reg2 sh mb me+ -> RLWINM (env reg1) (env reg2) sh mb me+ CLRLI fmt reg1 reg2 n -> CLRLI fmt (env reg1) (env reg2) n+ CLRRI fmt reg1 reg2 n -> CLRRI fmt (env reg1) (env reg2) n+ FADD fmt r1 r2 r3 -> FADD fmt (env r1) (env r2) (env r3)+ FSUB fmt r1 r2 r3 -> FSUB fmt (env r1) (env r2) (env r3)+ FMUL fmt r1 r2 r3 -> FMUL fmt (env r1) (env r2) (env r3)+ FDIV fmt r1 r2 r3 -> FDIV fmt (env r1) (env r2) (env r3)+ FABS r1 r2 -> FABS (env r1) (env r2)+ FNEG r1 r2 -> FNEG (env r1) (env r2)+ FCMP r1 r2 -> FCMP (env r1) (env r2)+ FCTIWZ r1 r2 -> FCTIWZ (env r1) (env r2)+ FCTIDZ r1 r2 -> FCTIDZ (env r1) (env r2)+ FCFID r1 r2 -> FCFID (env r1) (env r2)+ FRSP r1 r2 -> FRSP (env r1) (env r2)+ MFCR reg -> MFCR (env reg)+ MFLR reg -> MFLR (env reg)+ FETCHPC reg -> FETCHPC (env reg)+ _ -> instr+ where+ fixAddr (AddrRegReg r1 r2) = AddrRegReg (env r1) (env r2)+ fixAddr (AddrRegImm r1 i) = AddrRegImm (env r1) i++ fixRI (RIReg r) = RIReg (env r)+ fixRI other = other+++--------------------------------------------------------------------------------+-- | Checks whether this instruction is a jump/branch instruction.+-- One that can change the flow of control in a way that the+-- register allocator needs to worry about.+ppc_isJumpishInstr :: Instr -> Bool+ppc_isJumpishInstr instr+ = case instr of+ BCC{} -> True+ BCCFAR{} -> True+ BCTR{} -> True+ BCTRL{} -> True+ BL{} -> True+ JMP{} -> True+ _ -> False+++-- | Checks whether this instruction is a jump/branch instruction.+-- One that can change the flow of control in a way that the+-- register allocator needs to worry about.+ppc_jumpDestsOfInstr :: Instr -> [BlockId]+ppc_jumpDestsOfInstr insn+ = case insn of+ BCC _ id -> [id]+ BCCFAR _ id -> [id]+ BCTR targets _ -> [id | Just id <- targets]+ _ -> []+++-- | Change the destination of this jump instruction.+-- Used in the linear allocator when adding fixup blocks for join+-- points.+ppc_patchJumpInstr :: Instr -> (BlockId -> BlockId) -> Instr+ppc_patchJumpInstr insn patchF+ = case insn of+ BCC cc id -> BCC cc (patchF id)+ BCCFAR cc id -> BCCFAR cc (patchF id)+ BCTR ids lbl -> BCTR (map (fmap patchF) ids) lbl+ _ -> insn+++-- -----------------------------------------------------------------------------++-- | An instruction to spill a register into a spill slot.+ppc_mkSpillInstr+ :: DynFlags+ -> Reg -- register to spill+ -> Int -- current stack delta+ -> Int -- spill slot to use+ -> Instr++ppc_mkSpillInstr dflags reg delta slot+ = let platform = targetPlatform dflags+ off = spillSlotToOffset dflags slot+ arch = platformArch platform+ in+ let fmt = case targetClassOfReg platform reg of+ RcInteger -> case arch of+ ArchPPC -> II32+ _ -> II64+ RcDouble -> FF64+ _ -> panic "PPC.Instr.mkSpillInstr: no match"+ instr = case makeImmediate W32 True (off-delta) of+ Just _ -> ST+ Nothing -> STFAR -- pseudo instruction: 32 bit offsets++ in instr fmt reg (AddrRegImm sp (ImmInt (off-delta)))+++ppc_mkLoadInstr+ :: DynFlags+ -> Reg -- register to load+ -> Int -- current stack delta+ -> Int -- spill slot to use+ -> Instr++ppc_mkLoadInstr dflags reg delta slot+ = let platform = targetPlatform dflags+ off = spillSlotToOffset dflags slot+ arch = platformArch platform+ in+ let fmt = case targetClassOfReg platform reg of+ RcInteger -> case arch of+ ArchPPC -> II32+ _ -> II64+ RcDouble -> FF64+ _ -> panic "PPC.Instr.mkLoadInstr: no match"+ instr = case makeImmediate W32 True (off-delta) of+ Just _ -> LD+ Nothing -> LDFAR -- pseudo instruction: 32 bit offsets++ in instr fmt reg (AddrRegImm sp (ImmInt (off-delta)))+++-- | The size of a minimal stackframe header including minimal+-- parameter save area.+stackFrameHeaderSize :: DynFlags -> Int+stackFrameHeaderSize dflags+ = case platformOS platform of+ OSLinux -> case platformArch platform of+ -- header + parameter save area+ ArchPPC -> 64 -- TODO: check ABI spec+ ArchPPC_64 ELF_V1 -> 48 + 8 * 8+ ArchPPC_64 ELF_V2 -> 32 + 8 * 8+ _ -> panic "PPC.stackFrameHeaderSize: Unknown Linux"+ OSAIX -> 24 + 8 * 4+ OSDarwin -> 64 -- TODO: check ABI spec+ _ -> panic "PPC.stackFrameHeaderSize: not defined for this OS"+ where platform = targetPlatform dflags++-- | The maximum number of bytes required to spill a register. PPC32+-- has 32-bit GPRs and 64-bit FPRs, while PPC64 has 64-bit GPRs and+-- 64-bit FPRs. So the maximum is 8 regardless of platforms unlike+-- x86. Note that AltiVec's vector registers are 128-bit wide so we+-- must not use this to spill them.+spillSlotSize :: Int+spillSlotSize = 8++-- | The number of spill slots available without allocating more.+maxSpillSlots :: DynFlags -> Int+maxSpillSlots dflags+ = ((rESERVED_C_STACK_BYTES dflags - stackFrameHeaderSize dflags)+ `div` spillSlotSize) - 1+-- = 0 -- useful for testing allocMoreStack++-- | The number of bytes that the stack pointer should be aligned+-- to. This is 16 both on PPC32 and PPC64 at least for Darwin, and+-- Linux (see ELF processor specific supplements).+stackAlign :: Int+stackAlign = 16++-- | Convert a spill slot number to a *byte* offset, with no sign.+spillSlotToOffset :: DynFlags -> Int -> Int+spillSlotToOffset dflags slot+ = stackFrameHeaderSize dflags + spillSlotSize * slot+++--------------------------------------------------------------------------------+-- | See if this instruction is telling us the current C stack delta+ppc_takeDeltaInstr+ :: Instr+ -> Maybe Int++ppc_takeDeltaInstr instr+ = case instr of+ DELTA i -> Just i+ _ -> Nothing+++ppc_isMetaInstr+ :: Instr+ -> Bool++ppc_isMetaInstr instr+ = case instr of+ COMMENT{} -> True+ LDATA{} -> True+ NEWBLOCK{} -> True+ DELTA{} -> True+ _ -> False+++-- | Copy the value in a register to another one.+-- Must work for all register classes.+ppc_mkRegRegMoveInstr+ :: Reg+ -> Reg+ -> Instr++ppc_mkRegRegMoveInstr src dst+ = MR dst src+++-- | Make an unconditional jump instruction.+-- For architectures with branch delay slots, its ok to put+-- a NOP after the jump. Don't fill the delay slot with an+-- instruction that references regs or you'll confuse the+-- linear allocator.+ppc_mkJumpInstr+ :: BlockId+ -> [Instr]++ppc_mkJumpInstr id+ = [BCC ALWAYS id]+++-- | Take the source and destination from this reg -> reg move instruction+-- or Nothing if it's not one+ppc_takeRegRegMoveInstr :: Instr -> Maybe (Reg,Reg)+ppc_takeRegRegMoveInstr (MR dst src) = Just (src,dst)+ppc_takeRegRegMoveInstr _ = Nothing++-- -----------------------------------------------------------------------------+-- Making far branches++-- Conditional branches on PowerPC are limited to +-32KB; if our Procs get too+-- big, we have to work around this limitation.++makeFarBranches+ :: LabelMap CmmStatics+ -> [NatBasicBlock Instr]+ -> [NatBasicBlock Instr]+makeFarBranches info_env blocks+ | last blockAddresses < nearLimit = blocks+ | otherwise = zipWith handleBlock blockAddresses blocks+ where+ blockAddresses = scanl (+) 0 $ map blockLen blocks+ blockLen (BasicBlock _ instrs) = length instrs++ handleBlock addr (BasicBlock id instrs)+ = BasicBlock id (zipWith makeFar [addr..] instrs)++ makeFar _ (BCC ALWAYS tgt) = BCC ALWAYS tgt+ makeFar addr (BCC cond tgt)+ | abs (addr - targetAddr) >= nearLimit+ = BCCFAR cond tgt+ | otherwise+ = BCC cond tgt+ where Just targetAddr = lookupUFM blockAddressMap tgt+ makeFar _ other = other++ -- 8192 instructions are allowed; let's keep some distance, as+ -- we have a few pseudo-insns that are pretty-printed as+ -- multiple instructions, and it's just not worth the effort+ -- to calculate things exactly+ nearLimit = 7000 - mapSize info_env * maxRetInfoTableSizeW++ blockAddressMap = listToUFM $ zip (map blockId blocks) blockAddresses
+ nativeGen/PPC/Ppr.hs view
@@ -0,0 +1,1041 @@+-----------------------------------------------------------------------------+--+-- Pretty-printing assembly language+--+-- (c) The University of Glasgow 1993-2005+--+-----------------------------------------------------------------------------++{-# OPTIONS_GHC -fno-warn-orphans #-}+module PPC.Ppr (pprNatCmmDecl) where++import PPC.Regs+import PPC.Instr+import PPC.Cond+import PprBase+import Instruction+import Format+import Reg+import RegClass+import TargetReg++import Cmm hiding (topInfoTable)+import Hoopl++import CLabel++import Unique ( pprUniqueAlways, Uniquable(..) )+import Platform+import FastString+import Outputable+import DynFlags++import Data.Word+import Data.Int+import Data.Bits++-- -----------------------------------------------------------------------------+-- Printing this stuff out++pprNatCmmDecl :: NatCmmDecl CmmStatics Instr -> SDoc+pprNatCmmDecl (CmmData section dats) =+ pprSectionAlign section $$ pprDatas dats++pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =+ case topInfoTable proc of+ Nothing ->+ sdocWithPlatform $ \platform ->+ case blocks of+ [] -> -- special case for split markers:+ pprLabel lbl+ blocks -> -- special case for code without info table:+ pprSectionAlign (Section Text lbl) $$+ (case platformArch platform of+ ArchPPC_64 ELF_V1 -> pprFunctionDescriptor lbl+ ArchPPC_64 ELF_V2 -> pprFunctionPrologue lbl+ _ -> pprLabel lbl) $$ -- blocks guaranteed not null,+ -- so label needed+ vcat (map (pprBasicBlock top_info) blocks)++ Just (Statics info_lbl _) ->+ sdocWithPlatform $ \platform ->+ pprSectionAlign (Section Text info_lbl) $$+ (if platformHasSubsectionsViaSymbols platform+ then ppr (mkDeadStripPreventer info_lbl) <> char ':'+ else empty) $$+ vcat (map (pprBasicBlock top_info) blocks) $$+ -- above: Even the first block gets a label, because with branch-chain+ -- elimination, it might be the target of a goto.+ (if platformHasSubsectionsViaSymbols platform+ then+ -- See Note [Subsections Via Symbols] in X86/Ppr.hs+ text "\t.long "+ <+> ppr info_lbl+ <+> char '-'+ <+> ppr (mkDeadStripPreventer info_lbl)+ else empty)++pprFunctionDescriptor :: CLabel -> SDoc+pprFunctionDescriptor lab = pprGloblDecl lab+ $$ text ".section \".opd\",\"aw\""+ $$ text ".align 3"+ $$ ppr lab <> char ':'+ $$ text ".quad ."+ <> ppr lab+ <> text ",.TOC.@tocbase,0"+ $$ text ".previous"+ $$ text ".type "+ <> ppr lab+ <> text ", @function"+ $$ char '.'+ <> ppr lab+ <> char ':'++pprFunctionPrologue :: CLabel ->SDoc+pprFunctionPrologue lab = pprGloblDecl lab+ $$ text ".type "+ <> ppr lab+ <> text ", @function"+ $$ ppr lab <> char ':'+ $$ text "0:\taddis\t" <> pprReg toc+ <> text ",12,.TOC.-0b@ha"+ $$ text "\taddi\t" <> pprReg toc+ <> char ',' <> pprReg toc <> text ",.TOC.-0b@l"+ $$ text "\t.localentry\t" <> ppr lab+ <> text ",.-" <> ppr lab++pprBasicBlock :: LabelMap CmmStatics -> NatBasicBlock Instr -> SDoc+pprBasicBlock info_env (BasicBlock blockid instrs)+ = maybe_infotable $$+ pprLabel (mkAsmTempLabel (getUnique blockid)) $$+ vcat (map pprInstr instrs)+ where+ maybe_infotable = case mapLookup blockid info_env of+ Nothing -> empty+ Just (Statics info_lbl info) ->+ pprAlignForSection Text $$+ vcat (map pprData info) $$+ pprLabel info_lbl++++pprDatas :: CmmStatics -> SDoc+pprDatas (Statics lbl dats) = vcat (pprLabel lbl : map pprData dats)++pprData :: CmmStatic -> SDoc+pprData (CmmString str) = pprASCII str+pprData (CmmUninitialised bytes) = keyword <> int bytes+ where keyword = sdocWithPlatform $ \platform ->+ case platformOS platform of+ OSDarwin -> text ".space "+ OSAIX -> text ".space "+ _ -> text ".skip "+pprData (CmmStaticLit lit) = pprDataItem lit++pprGloblDecl :: CLabel -> SDoc+pprGloblDecl lbl+ | not (externallyVisibleCLabel lbl) = empty+ | otherwise = text ".globl " <> ppr lbl++pprTypeAndSizeDecl :: CLabel -> SDoc+pprTypeAndSizeDecl lbl+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSLinux && externallyVisibleCLabel lbl+ then text ".type " <>+ ppr lbl <> text ", @object"+ else empty++pprLabel :: CLabel -> SDoc+pprLabel lbl = pprGloblDecl lbl+ $$ pprTypeAndSizeDecl lbl+ $$ (ppr lbl <> char ':')+++pprASCII :: [Word8] -> SDoc+pprASCII str+ = vcat (map do1 str) $$ do1 0+ where+ do1 :: Word8 -> SDoc+ do1 w = text "\t.byte\t" <> int (fromIntegral w)+++-- -----------------------------------------------------------------------------+-- pprInstr: print an 'Instr'++instance Outputable Instr where+ ppr instr = pprInstr instr+++pprReg :: Reg -> SDoc++pprReg r+ = case r of+ RegReal (RealRegSingle i) -> ppr_reg_no i+ RegReal (RealRegPair{}) -> panic "PPC.pprReg: no reg pairs on this arch"+ RegVirtual (VirtualRegI u) -> text "%vI_" <> pprUniqueAlways u+ RegVirtual (VirtualRegHi u) -> text "%vHi_" <> pprUniqueAlways u+ RegVirtual (VirtualRegF u) -> text "%vF_" <> pprUniqueAlways u+ RegVirtual (VirtualRegD u) -> text "%vD_" <> pprUniqueAlways u+ RegVirtual (VirtualRegSSE u) -> text "%vSSE_" <> pprUniqueAlways u+ where+ ppr_reg_no :: Int -> SDoc+ ppr_reg_no i =+ sdocWithPlatform $ \platform ->+ case platformOS platform of+ OSDarwin ->+ ptext+ (case i of {+ 0 -> sLit "r0"; 1 -> sLit "r1";+ 2 -> sLit "r2"; 3 -> sLit "r3";+ 4 -> sLit "r4"; 5 -> sLit "r5";+ 6 -> sLit "r6"; 7 -> sLit "r7";+ 8 -> sLit "r8"; 9 -> sLit "r9";+ 10 -> sLit "r10"; 11 -> sLit "r11";+ 12 -> sLit "r12"; 13 -> sLit "r13";+ 14 -> sLit "r14"; 15 -> sLit "r15";+ 16 -> sLit "r16"; 17 -> sLit "r17";+ 18 -> sLit "r18"; 19 -> sLit "r19";+ 20 -> sLit "r20"; 21 -> sLit "r21";+ 22 -> sLit "r22"; 23 -> sLit "r23";+ 24 -> sLit "r24"; 25 -> sLit "r25";+ 26 -> sLit "r26"; 27 -> sLit "r27";+ 28 -> sLit "r28"; 29 -> sLit "r29";+ 30 -> sLit "r30"; 31 -> sLit "r31";+ 32 -> sLit "f0"; 33 -> sLit "f1";+ 34 -> sLit "f2"; 35 -> sLit "f3";+ 36 -> sLit "f4"; 37 -> sLit "f5";+ 38 -> sLit "f6"; 39 -> sLit "f7";+ 40 -> sLit "f8"; 41 -> sLit "f9";+ 42 -> sLit "f10"; 43 -> sLit "f11";+ 44 -> sLit "f12"; 45 -> sLit "f13";+ 46 -> sLit "f14"; 47 -> sLit "f15";+ 48 -> sLit "f16"; 49 -> sLit "f17";+ 50 -> sLit "f18"; 51 -> sLit "f19";+ 52 -> sLit "f20"; 53 -> sLit "f21";+ 54 -> sLit "f22"; 55 -> sLit "f23";+ 56 -> sLit "f24"; 57 -> sLit "f25";+ 58 -> sLit "f26"; 59 -> sLit "f27";+ 60 -> sLit "f28"; 61 -> sLit "f29";+ 62 -> sLit "f30"; 63 -> sLit "f31";+ _ -> sLit "very naughty powerpc register"+ })+ _+ | i <= 31 -> int i -- GPRs+ | i <= 63 -> int (i-32) -- FPRs+ | otherwise -> text "very naughty powerpc register"++++pprFormat :: Format -> SDoc+pprFormat x+ = ptext (case x of+ II8 -> sLit "b"+ II16 -> sLit "h"+ II32 -> sLit "w"+ II64 -> sLit "d"+ FF32 -> sLit "fs"+ FF64 -> sLit "fd"+ _ -> panic "PPC.Ppr.pprFormat: no match")+++pprCond :: Cond -> SDoc+pprCond c+ = ptext (case c of {+ ALWAYS -> sLit "";+ EQQ -> sLit "eq"; NE -> sLit "ne";+ LTT -> sLit "lt"; GE -> sLit "ge";+ GTT -> sLit "gt"; LE -> sLit "le";+ LU -> sLit "lt"; GEU -> sLit "ge";+ GU -> sLit "gt"; LEU -> sLit "le"; })+++pprImm :: Imm -> SDoc++pprImm (ImmInt i) = int i+pprImm (ImmInteger i) = integer i+pprImm (ImmCLbl l) = ppr l+pprImm (ImmIndex l i) = ppr l <> char '+' <> int i+pprImm (ImmLit s) = s++pprImm (ImmFloat _) = text "naughty float immediate"+pprImm (ImmDouble _) = text "naughty double immediate"++pprImm (ImmConstantSum a b) = pprImm a <> char '+' <> pprImm b+pprImm (ImmConstantDiff a b) = pprImm a <> char '-'+ <> lparen <> pprImm b <> rparen++pprImm (LO (ImmInt i)) = pprImm (LO (ImmInteger (toInteger i)))+pprImm (LO (ImmInteger i)) = pprImm (ImmInteger (toInteger lo16))+ where+ lo16 = fromInteger (i .&. 0xffff) :: Int16++pprImm (LO i)+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSDarwin+ then hcat [ text "lo16(", pprImm i, rparen ]+ else pprImm i <> text "@l"++pprImm (HI i)+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSDarwin+ then hcat [ text "hi16(", pprImm i, rparen ]+ else pprImm i <> text "@h"++pprImm (HA (ImmInt i)) = pprImm (HA (ImmInteger (toInteger i)))+pprImm (HA (ImmInteger i)) = pprImm (ImmInteger ha16)+ where+ ha16 = if lo16 >= 0x8000 then hi16+1 else hi16+ hi16 = (i `shiftR` 16)+ lo16 = i .&. 0xffff++pprImm (HA i)+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSDarwin+ then hcat [ text "ha16(", pprImm i, rparen ]+ else pprImm i <> text "@ha"++pprImm (HIGHERA i)+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSDarwin+ then panic "PPC.pprImm: highera not implemented on Darwin"+ else pprImm i <> text "@highera"++pprImm (HIGHESTA i)+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSDarwin+ then panic "PPC.pprImm: highesta not implemented on Darwin"+ else pprImm i <> text "@highesta"+++pprAddr :: AddrMode -> SDoc+pprAddr (AddrRegReg r1 r2)+ = pprReg r1 <+> text ", " <+> pprReg r2++pprAddr (AddrRegImm r1 (ImmInt i)) = hcat [ int i, char '(', pprReg r1, char ')' ]+pprAddr (AddrRegImm r1 (ImmInteger i)) = hcat [ integer i, char '(', pprReg r1, char ')' ]+pprAddr (AddrRegImm r1 imm) = hcat [ pprImm imm, char '(', pprReg r1, char ')' ]+++pprSectionAlign :: Section -> SDoc+pprSectionAlign sec@(Section seg _) =+ sdocWithPlatform $ \platform ->+ pprSectionHeader platform sec $$+ pprAlignForSection seg++-- | Print appropriate alignment for the given section type.+pprAlignForSection :: SectionType -> SDoc+pprAlignForSection seg =+ sdocWithPlatform $ \platform ->+ let osDarwin = platformOS platform == OSDarwin+ ppc64 = not $ target32Bit platform+ in ptext $ case seg of+ Text -> sLit ".align 2"+ Data+ | ppc64 -> sLit ".align 3"+ | otherwise -> sLit ".align 2"+ ReadOnlyData+ | osDarwin -> sLit ".align 2"+ | ppc64 -> sLit ".align 3"+ | otherwise -> sLit ".align 2"+ RelocatableReadOnlyData+ | osDarwin -> sLit ".align 2"+ | ppc64 -> sLit ".align 3"+ | otherwise -> sLit ".align 2"+ UninitialisedData+ | osDarwin -> sLit ".align 2"+ | ppc64 -> sLit ".align 3"+ | otherwise -> sLit ".align 2"+ ReadOnlyData16+ | osDarwin -> sLit ".align 4"+ | otherwise -> sLit ".align 4"+ -- TODO: This is copied from the ReadOnlyData case, but it can likely be+ -- made more efficient.+ CString+ | osDarwin -> sLit ".align 2"+ | ppc64 -> sLit ".align 3"+ | otherwise -> sLit ".align 2"+ OtherSection _ -> panic "PprMach.pprSectionAlign: unknown section"++pprDataItem :: CmmLit -> SDoc+pprDataItem lit+ = sdocWithDynFlags $ \dflags ->+ vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit dflags)+ where+ imm = litToImm lit+ archPPC_64 dflags = not $ target32Bit $ targetPlatform dflags++ ppr_item II8 _ _ = [text "\t.byte\t" <> pprImm imm]++ ppr_item II32 _ _ = [text "\t.long\t" <> pprImm imm]++ ppr_item II64 _ dflags+ | archPPC_64 dflags = [text "\t.quad\t" <> pprImm imm]+++ ppr_item FF32 (CmmFloat r _) _+ = let bs = floatToBytes (fromRational r)+ in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs++ ppr_item FF64 (CmmFloat r _) _+ = let bs = doubleToBytes (fromRational r)+ in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs++ ppr_item II16 _ _ = [text "\t.short\t" <> pprImm imm]++ ppr_item II64 (CmmInt x _) dflags+ | not(archPPC_64 dflags) =+ [text "\t.long\t"+ <> int (fromIntegral+ (fromIntegral (x `shiftR` 32) :: Word32)),+ text "\t.long\t"+ <> int (fromIntegral (fromIntegral x :: Word32))]++ ppr_item _ _ _+ = panic "PPC.Ppr.pprDataItem: no match"+++pprInstr :: Instr -> SDoc++pprInstr (COMMENT _) = empty -- nuke 'em+{-+pprInstr (COMMENT s) =+ if platformOS platform == OSLinux+ then text "# " <> ftext s+ else text "; " <> ftext s+-}+pprInstr (DELTA d)+ = pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))++pprInstr (NEWBLOCK _)+ = panic "PprMach.pprInstr: NEWBLOCK"++pprInstr (LDATA _ _)+ = panic "PprMach.pprInstr: LDATA"++{-+pprInstr (SPILL reg slot)+ = hcat [+ text "\tSPILL",+ char '\t',+ pprReg reg,+ comma,+ text "SLOT" <> parens (int slot)]++pprInstr (RELOAD slot reg)+ = hcat [+ text "\tRELOAD",+ char '\t',+ text "SLOT" <> parens (int slot),+ comma,+ pprReg reg]+-}++pprInstr (LD fmt reg addr) = hcat [+ char '\t',+ text "l",+ ptext (case fmt of+ II8 -> sLit "bz"+ II16 -> sLit "hz"+ II32 -> sLit "wz"+ II64 -> sLit "d"+ FF32 -> sLit "fs"+ FF64 -> sLit "fd"+ _ -> panic "PPC.Ppr.pprInstr: no match"+ ),+ case addr of AddrRegImm _ _ -> empty+ AddrRegReg _ _ -> char 'x',+ char '\t',+ pprReg reg,+ text ", ",+ pprAddr addr+ ]+pprInstr (LDFAR fmt reg (AddrRegImm source off)) =+ sdocWithPlatform $ \platform -> vcat [+ pprInstr (ADDIS (tmpReg platform) source (HA off)),+ pprInstr (LD fmt reg (AddrRegImm (tmpReg platform) (LO off)))+ ]++pprInstr (LDFAR _ _ _) =+ panic "PPC.Ppr.pprInstr LDFAR: no match"++pprInstr (LA fmt reg addr) = hcat [+ char '\t',+ text "l",+ ptext (case fmt of+ II8 -> sLit "ba"+ II16 -> sLit "ha"+ II32 -> sLit "wa"+ II64 -> sLit "d"+ FF32 -> sLit "fs"+ FF64 -> sLit "fd"+ _ -> panic "PPC.Ppr.pprInstr: no match"+ ),+ case addr of AddrRegImm _ _ -> empty+ AddrRegReg _ _ -> char 'x',+ char '\t',+ pprReg reg,+ text ", ",+ pprAddr addr+ ]+pprInstr (ST fmt reg addr) = hcat [+ char '\t',+ text "st",+ pprFormat fmt,+ case addr of AddrRegImm _ _ -> empty+ AddrRegReg _ _ -> char 'x',+ char '\t',+ pprReg reg,+ text ", ",+ pprAddr addr+ ]+pprInstr (STFAR fmt reg (AddrRegImm source off)) =+ sdocWithPlatform $ \platform -> vcat [+ pprInstr (ADDIS (tmpReg platform) source (HA off)),+ pprInstr (ST fmt reg (AddrRegImm (tmpReg platform) (LO off)))+ ]+pprInstr (STFAR _ _ _) =+ panic "PPC.Ppr.pprInstr STFAR: no match"+pprInstr (STU fmt reg addr) = hcat [+ char '\t',+ text "st",+ pprFormat fmt,+ char 'u',+ case addr of AddrRegImm _ _ -> empty+ AddrRegReg _ _ -> char 'x',+ char '\t',+ pprReg reg,+ text ", ",+ pprAddr addr+ ]+pprInstr (LIS reg imm) = hcat [+ char '\t',+ text "lis",+ char '\t',+ pprReg reg,+ text ", ",+ pprImm imm+ ]+pprInstr (LI reg imm) = hcat [+ char '\t',+ text "li",+ char '\t',+ pprReg reg,+ text ", ",+ pprImm imm+ ]+pprInstr (MR reg1 reg2)+ | reg1 == reg2 = empty+ | otherwise = hcat [+ char '\t',+ sdocWithPlatform $ \platform ->+ case targetClassOfReg platform reg1 of+ RcInteger -> text "mr"+ _ -> text "fmr",+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2+ ]+pprInstr (CMP fmt reg ri) = hcat [+ char '\t',+ op,+ char '\t',+ pprReg reg,+ text ", ",+ pprRI ri+ ]+ where+ op = hcat [+ text "cmp",+ pprFormat fmt,+ case ri of+ RIReg _ -> empty+ RIImm _ -> char 'i'+ ]+pprInstr (CMPL fmt reg ri) = hcat [+ char '\t',+ op,+ char '\t',+ pprReg reg,+ text ", ",+ pprRI ri+ ]+ where+ op = hcat [+ text "cmpl",+ pprFormat fmt,+ case ri of+ RIReg _ -> empty+ RIImm _ -> char 'i'+ ]+pprInstr (BCC cond blockid) = hcat [+ char '\t',+ text "b",+ pprCond cond,+ char '\t',+ ppr lbl+ ]+ where lbl = mkAsmTempLabel (getUnique blockid)++pprInstr (BCCFAR cond blockid) = vcat [+ hcat [+ text "\tb",+ pprCond (condNegate cond),+ text "\t$+8"+ ],+ hcat [+ text "\tb\t",+ ppr lbl+ ]+ ]+ where lbl = mkAsmTempLabel (getUnique blockid)++pprInstr (JMP lbl)+ -- We never jump to ForeignLabels; if we ever do, c.f. handling for "BL"+ | isForeignLabel lbl = panic "PPC.Ppr.pprInstr: JMP to ForeignLabel"+ | otherwise =+ hcat [ -- an alias for b that takes a CLabel+ char '\t',+ text "b",+ char '\t',+ ppr lbl+ ]++pprInstr (MTCTR reg) = hcat [+ char '\t',+ text "mtctr",+ char '\t',+ pprReg reg+ ]+pprInstr (BCTR _ _) = hcat [+ char '\t',+ text "bctr"+ ]+pprInstr (BL lbl _) = do+ sdocWithPlatform $ \platform -> case platformOS platform of+ OSAIX ->+ -- On AIX, "printf" denotes a function-descriptor (for use+ -- by function pointers), whereas the actual entry-code+ -- address is denoted by the dot-prefixed ".printf" label.+ -- Moreover, the PPC NCG only ever emits a BL instruction+ -- for calling C ABI functions. Most of the time these calls+ -- originate from FFI imports and have a 'ForeignLabel',+ -- but when profiling the codegen inserts calls via+ -- 'emitRtsCallGen' which are 'CmmLabel's even though+ -- they'd technically be more like 'ForeignLabel's.+ hcat [+ text "\tbl\t.",+ ppr lbl+ ]+ _ ->+ hcat [+ text "\tbl\t",+ ppr lbl+ ]+pprInstr (BCTRL _) = hcat [+ char '\t',+ text "bctrl"+ ]+pprInstr (ADD reg1 reg2 ri) = pprLogic (sLit "add") reg1 reg2 ri+pprInstr (ADDIS reg1 reg2 imm) = hcat [+ char '\t',+ text "addis",+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprImm imm+ ]++pprInstr (ADDO reg1 reg2 reg3) = pprLogic (sLit "addo") reg1 reg2 (RIReg reg3)+pprInstr (ADDC reg1 reg2 reg3) = pprLogic (sLit "addc") reg1 reg2 (RIReg reg3)+pprInstr (ADDE reg1 reg2 reg3) = pprLogic (sLit "adde") reg1 reg2 (RIReg reg3)+pprInstr (ADDZE reg1 reg2) = pprUnary (sLit "addze") reg1 reg2+pprInstr (SUBF reg1 reg2 reg3) = pprLogic (sLit "subf") reg1 reg2 (RIReg reg3)+pprInstr (SUBFO reg1 reg2 reg3) = pprLogic (sLit "subfo") reg1 reg2 (RIReg reg3)+pprInstr (SUBFC reg1 reg2 ri) = hcat [+ char '\t',+ text "subf",+ case ri of+ RIReg _ -> empty+ RIImm _ -> char 'i',+ text "c\t",+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprRI ri+ ]+pprInstr (SUBFE reg1 reg2 reg3) = pprLogic (sLit "subfe") reg1 reg2 (RIReg reg3)+pprInstr (MULL fmt reg1 reg2 ri) = pprMul fmt reg1 reg2 ri+pprInstr (MULLO fmt reg1 reg2 reg3) = hcat [+ char '\t',+ text "mull",+ case fmt of+ II32 -> char 'w'+ II64 -> char 'd'+ _ -> panic "PPC: illegal format",+ text "o\t",+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprReg reg3+ ]+pprInstr (MFOV fmt reg) = vcat [+ hcat [+ char '\t',+ text "mfxer",+ char '\t',+ pprReg reg+ ],+ hcat [+ char '\t',+ text "extr",+ case fmt of+ II32 -> char 'w'+ II64 -> char 'd'+ _ -> panic "PPC: illegal format",+ text "i\t",+ pprReg reg,+ text ", ",+ pprReg reg,+ text ", 1, ",+ case fmt of+ II32 -> text "1"+ II64 -> text "33"+ _ -> panic "PPC: illegal format"+ ]+ ]++pprInstr (MULHU fmt reg1 reg2 reg3) = hcat [+ char '\t',+ text "mulh",+ case fmt of+ II32 -> char 'w'+ II64 -> char 'd'+ _ -> panic "PPC: illegal format",+ text "u\t",+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprReg reg3+ ]++pprInstr (DIV fmt sgn reg1 reg2 reg3) = pprDiv fmt sgn reg1 reg2 reg3++ -- for some reason, "andi" doesn't exist.+ -- we'll use "andi." instead.+pprInstr (AND reg1 reg2 (RIImm imm)) = hcat [+ char '\t',+ text "andi.",+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprImm imm+ ]+pprInstr (AND reg1 reg2 ri) = pprLogic (sLit "and") reg1 reg2 ri+pprInstr (ANDC reg1 reg2 reg3) = pprLogic (sLit "andc") reg1 reg2 (RIReg reg3)++pprInstr (OR reg1 reg2 ri) = pprLogic (sLit "or") reg1 reg2 ri+pprInstr (XOR reg1 reg2 ri) = pprLogic (sLit "xor") reg1 reg2 ri++pprInstr (ORIS reg1 reg2 imm) = hcat [+ char '\t',+ text "oris",+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprImm imm+ ]++pprInstr (XORIS reg1 reg2 imm) = hcat [+ char '\t',+ text "xoris",+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprImm imm+ ]++pprInstr (EXTS fmt reg1 reg2) = hcat [+ char '\t',+ text "exts",+ pprFormat fmt,+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2+ ]+pprInstr (CNTLZ fmt reg1 reg2) = hcat [+ char '\t',+ text "cntlz",+ case fmt of+ II32 -> char 'w'+ II64 -> char 'd'+ _ -> panic "PPC: illegal format",+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2+ ]++pprInstr (NEG reg1 reg2) = pprUnary (sLit "neg") reg1 reg2+pprInstr (NOT reg1 reg2) = pprUnary (sLit "not") reg1 reg2++pprInstr (SR II32 reg1 reg2 (RIImm (ImmInt i))) | i < 0 || i > 31 =+ -- Handle the case where we are asked to shift a 32 bit register by+ -- less than zero or more than 31 bits. We convert this into a clear+ -- of the destination register.+ -- Fixes ticket http://ghc.haskell.org/trac/ghc/ticket/5900+ pprInstr (XOR reg1 reg2 (RIReg reg2))++pprInstr (SL II32 reg1 reg2 (RIImm (ImmInt i))) | i < 0 || i > 31 =+ -- As above for SR, but for left shifts.+ -- Fixes ticket http://ghc.haskell.org/trac/ghc/ticket/10870+ pprInstr (XOR reg1 reg2 (RIReg reg2))++pprInstr (SRA II32 reg1 reg2 (RIImm (ImmInt i))) | i > 31 =+ -- PT: I don't know what to do for negative shift amounts:+ -- For now just panic.+ --+ -- For shift amounts greater than 31 set all bit to the+ -- value of the sign bit, this also what sraw does.+ pprInstr (SRA II32 reg1 reg2 (RIImm (ImmInt 31)))++pprInstr (SL fmt reg1 reg2 ri) =+ let op = case fmt of+ II32 -> "slw"+ II64 -> "sld"+ _ -> panic "PPC.Ppr.pprInstr: shift illegal size"+ in pprLogic (sLit op) reg1 reg2 (limitShiftRI fmt ri)++pprInstr (SR fmt reg1 reg2 ri) =+ let op = case fmt of+ II32 -> "srw"+ II64 -> "srd"+ _ -> panic "PPC.Ppr.pprInstr: shift illegal size"+ in pprLogic (sLit op) reg1 reg2 (limitShiftRI fmt ri)++pprInstr (SRA fmt reg1 reg2 ri) =+ let op = case fmt of+ II32 -> "sraw"+ II64 -> "srad"+ _ -> panic "PPC.Ppr.pprInstr: shift illegal size"+ in pprLogic (sLit op) reg1 reg2 (limitShiftRI fmt ri)++pprInstr (RLWINM reg1 reg2 sh mb me) = hcat [+ text "\trlwinm\t",+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ int sh,+ text ", ",+ int mb,+ text ", ",+ int me+ ]++pprInstr (CLRLI fmt reg1 reg2 n) = hcat [+ text "\tclrl",+ pprFormat fmt,+ text "i ",+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ int n+ ]+pprInstr (CLRRI fmt reg1 reg2 n) = hcat [+ text "\tclrr",+ pprFormat fmt,+ text "i ",+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ int n+ ]++pprInstr (FADD fmt reg1 reg2 reg3) = pprBinaryF (sLit "fadd") fmt reg1 reg2 reg3+pprInstr (FSUB fmt reg1 reg2 reg3) = pprBinaryF (sLit "fsub") fmt reg1 reg2 reg3+pprInstr (FMUL fmt reg1 reg2 reg3) = pprBinaryF (sLit "fmul") fmt reg1 reg2 reg3+pprInstr (FDIV fmt reg1 reg2 reg3) = pprBinaryF (sLit "fdiv") fmt reg1 reg2 reg3+pprInstr (FABS reg1 reg2) = pprUnary (sLit "fabs") reg1 reg2+pprInstr (FNEG reg1 reg2) = pprUnary (sLit "fneg") reg1 reg2++pprInstr (FCMP reg1 reg2) = hcat [+ char '\t',+ text "fcmpu\t0, ",+ -- Note: we're using fcmpu, not fcmpo+ -- The difference is with fcmpo, compare with NaN is an invalid operation.+ -- We don't handle invalid fp ops, so we don't care.+ -- Morever, we use `fcmpu 0, ...` rather than `fcmpu cr0, ...` for+ -- better portability since some non-GNU assembler (such as+ -- IBM's `as`) tend not to support the symbolic register name cr0.+ -- This matches the syntax that GCC seems to emit for PPC targets.+ pprReg reg1,+ text ", ",+ pprReg reg2+ ]++pprInstr (FCTIWZ reg1 reg2) = pprUnary (sLit "fctiwz") reg1 reg2+pprInstr (FCTIDZ reg1 reg2) = pprUnary (sLit "fctidz") reg1 reg2+pprInstr (FCFID reg1 reg2) = pprUnary (sLit "fcfid") reg1 reg2+pprInstr (FRSP reg1 reg2) = pprUnary (sLit "frsp") reg1 reg2++pprInstr (CRNOR dst src1 src2) = hcat [+ text "\tcrnor\t",+ int dst,+ text ", ",+ int src1,+ text ", ",+ int src2+ ]++pprInstr (MFCR reg) = hcat [+ char '\t',+ text "mfcr",+ char '\t',+ pprReg reg+ ]++pprInstr (MFLR reg) = hcat [+ char '\t',+ text "mflr",+ char '\t',+ pprReg reg+ ]++pprInstr (FETCHPC reg) = vcat [+ text "\tbcl\t20,31,1f",+ hcat [ text "1:\tmflr\t", pprReg reg ]+ ]++pprInstr LWSYNC = text "\tlwsync"++pprInstr NOP = text "\tnop"++pprInstr (UPDATE_SP fmt amount@(ImmInt offset))+ | fits16Bits offset = vcat [+ pprInstr (LD fmt r0 (AddrRegImm sp (ImmInt 0))),+ pprInstr (STU fmt r0 (AddrRegImm sp amount))+ ]++pprInstr (UPDATE_SP fmt amount)+ = sdocWithPlatform $ \platform ->+ let tmp = tmpReg platform in+ vcat [+ pprInstr (LD fmt r0 (AddrRegImm sp (ImmInt 0))),+ pprInstr (ADDIS tmp sp (HA amount)),+ pprInstr (ADD tmp tmp (RIImm (LO amount))),+ pprInstr (STU fmt r0 (AddrRegReg sp tmp))+ ]++-- pprInstr _ = panic "pprInstr (ppc)"+++pprLogic :: LitString -> Reg -> Reg -> RI -> SDoc+pprLogic op reg1 reg2 ri = hcat [+ char '\t',+ ptext op,+ case ri of+ RIReg _ -> empty+ RIImm _ -> char 'i',+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprRI ri+ ]+++pprMul :: Format -> Reg -> Reg -> RI -> SDoc+pprMul fmt reg1 reg2 ri = hcat [+ char '\t',+ text "mull",+ case ri of+ RIReg _ -> case fmt of+ II32 -> char 'w'+ II64 -> char 'd'+ _ -> panic "PPC: illegal format"+ RIImm _ -> char 'i',+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprRI ri+ ]+++pprDiv :: Format -> Bool -> Reg -> Reg -> Reg -> SDoc+pprDiv fmt sgn reg1 reg2 reg3 = hcat [+ char '\t',+ text "div",+ case fmt of+ II32 -> char 'w'+ II64 -> char 'd'+ _ -> panic "PPC: illegal format",+ if sgn then empty else char 'u',+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprReg reg3+ ]+++pprUnary :: LitString -> Reg -> Reg -> SDoc+pprUnary op reg1 reg2 = hcat [+ char '\t',+ ptext op,+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2+ ]+++pprBinaryF :: LitString -> Format -> Reg -> Reg -> Reg -> SDoc+pprBinaryF op fmt reg1 reg2 reg3 = hcat [+ char '\t',+ ptext op,+ pprFFormat fmt,+ char '\t',+ pprReg reg1,+ text ", ",+ pprReg reg2,+ text ", ",+ pprReg reg3+ ]++pprRI :: RI -> SDoc+pprRI (RIReg r) = pprReg r+pprRI (RIImm r) = pprImm r+++pprFFormat :: Format -> SDoc+pprFFormat FF64 = empty+pprFFormat FF32 = char 's'+pprFFormat _ = panic "PPC.Ppr.pprFFormat: no match"++ -- limit immediate argument for shift instruction to range 0..63+ -- for 64 bit size and 0..32 otherwise+limitShiftRI :: Format -> RI -> RI+limitShiftRI II64 (RIImm (ImmInt i)) | i > 63 || i < 0 =+ panic $ "PPC.Ppr: Shift by " ++ show i ++ " bits is not allowed."+limitShiftRI II32 (RIImm (ImmInt i)) | i > 31 || i < 0 =+ panic $ "PPC.Ppr: 32 bit: Shift by " ++ show i ++ " bits is not allowed."+limitShiftRI _ x = x
+ nativeGen/PPC/RegInfo.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Machine-specific parts of the register allocator+--+-- (c) The University of Glasgow 1996-2004+--+-----------------------------------------------------------------------------+module PPC.RegInfo (+ JumpDest( DestBlockId ), getJumpDestBlockId,+ canShortcut,+ shortcutJump,++ shortcutStatics+)++where++#include "nativeGen/NCG.h"+#include "HsVersions.h"++import PPC.Instr++import BlockId+import Cmm+import CLabel++import Unique++data JumpDest = DestBlockId BlockId++getJumpDestBlockId :: JumpDest -> Maybe BlockId+getJumpDestBlockId (DestBlockId bid) = Just bid++canShortcut :: Instr -> Maybe JumpDest+canShortcut _ = Nothing++shortcutJump :: (BlockId -> Maybe JumpDest) -> Instr -> Instr+shortcutJump _ other = other+++-- Here because it knows about JumpDest+shortcutStatics :: (BlockId -> Maybe JumpDest) -> CmmStatics -> CmmStatics+shortcutStatics fn (Statics lbl statics)+ = Statics lbl $ map (shortcutStatic fn) statics+ -- we need to get the jump tables, so apply the mapping to the entries+ -- of a CmmData too.++shortcutLabel :: (BlockId -> Maybe JumpDest) -> CLabel -> CLabel+shortcutLabel fn lab+ | Just uq <- maybeAsmTemp lab = shortBlockId fn (mkBlockId uq)+ | otherwise = lab++shortcutStatic :: (BlockId -> Maybe JumpDest) -> CmmStatic -> CmmStatic+shortcutStatic fn (CmmStaticLit (CmmLabel lab))+ = CmmStaticLit (CmmLabel (shortcutLabel fn lab))+shortcutStatic fn (CmmStaticLit (CmmLabelDiffOff lbl1 lbl2 off))+ = CmmStaticLit (CmmLabelDiffOff (shortcutLabel fn lbl1) lbl2 off)+ -- slightly dodgy, we're ignoring the second label, but this+ -- works with the way we use CmmLabelDiffOff for jump tables now.+shortcutStatic _ other_static+ = other_static++shortBlockId+ :: (BlockId -> Maybe JumpDest)+ -> BlockId+ -> CLabel++shortBlockId fn blockid =+ case fn blockid of+ Nothing -> mkAsmTempLabel uq+ Just (DestBlockId blockid') -> shortBlockId fn blockid'+ where uq = getUnique blockid
+ nativeGen/PPC/Regs.hs view
@@ -0,0 +1,342 @@+{-# LANGUAGE CPP #-}++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 1994-2004+--+-- -----------------------------------------------------------------------------++module PPC.Regs (+ -- squeeze functions+ virtualRegSqueeze,+ realRegSqueeze,++ mkVirtualReg,+ regDotColor,++ -- immediates+ Imm(..),+ strImmLit,+ litToImm,++ -- addressing modes+ AddrMode(..),+ addrOffset,++ -- registers+ spRel,+ argRegs,+ allArgRegs,+ callClobberedRegs,+ allMachRegNos,+ classOfRealReg,+ showReg,++ -- machine specific+ allFPArgRegs,+ fits16Bits,+ makeImmediate,+ fReg,+ r0, sp, toc, r3, r4, r11, r12, r27, r28, r30,+ tmpReg,+ f1, f20, f21,++ allocatableRegs++)++where++#include "nativeGen/NCG.h"+#include "HsVersions.h"++import Reg+import RegClass+import Format++import Cmm+import CLabel ( CLabel )+import Unique++import CodeGen.Platform+import DynFlags+import Outputable+import Platform++import Data.Word ( Word8, Word16, Word32, Word64 )+import Data.Int ( Int8, Int16, Int32, Int64 )+++-- squeese functions for the graph allocator -----------------------------------++-- | regSqueeze_class reg+-- Calculuate the maximum number of register colors that could be+-- denied to a node of this class due to having this reg+-- as a neighbour.+--+{-# INLINE virtualRegSqueeze #-}+virtualRegSqueeze :: RegClass -> VirtualReg -> Int+virtualRegSqueeze cls vr+ = case cls of+ RcInteger+ -> case vr of+ VirtualRegI{} -> 1+ VirtualRegHi{} -> 1+ _other -> 0++ RcDouble+ -> case vr of+ VirtualRegD{} -> 1+ VirtualRegF{} -> 0+ _other -> 0++ _other -> 0++{-# INLINE realRegSqueeze #-}+realRegSqueeze :: RegClass -> RealReg -> Int+realRegSqueeze cls rr+ = case cls of+ RcInteger+ -> case rr of+ RealRegSingle regNo+ | regNo < 32 -> 1 -- first fp reg is 32+ | otherwise -> 0++ RealRegPair{} -> 0++ RcDouble+ -> case rr of+ RealRegSingle regNo+ | regNo < 32 -> 0+ | otherwise -> 1++ RealRegPair{} -> 0++ _other -> 0++mkVirtualReg :: Unique -> Format -> VirtualReg+mkVirtualReg u format+ | not (isFloatFormat format) = VirtualRegI u+ | otherwise+ = case format of+ FF32 -> VirtualRegD u+ FF64 -> VirtualRegD u+ _ -> panic "mkVirtualReg"++regDotColor :: RealReg -> SDoc+regDotColor reg+ = case classOfRealReg reg of+ RcInteger -> text "blue"+ RcFloat -> text "red"+ RcDouble -> text "green"+ RcDoubleSSE -> text "yellow"+++-- immediates ------------------------------------------------------------------+data Imm+ = ImmInt Int+ | ImmInteger Integer -- Sigh.+ | ImmCLbl CLabel -- AbstractC Label (with baggage)+ | ImmLit SDoc -- Simple string+ | ImmIndex CLabel Int+ | ImmFloat Rational+ | ImmDouble Rational+ | ImmConstantSum Imm Imm+ | ImmConstantDiff Imm Imm+ | LO Imm+ | HI Imm+ | HA Imm {- high halfword adjusted -}+ | HIGHERA Imm+ | HIGHESTA Imm+++strImmLit :: String -> Imm+strImmLit s = ImmLit (text s)+++litToImm :: CmmLit -> Imm+litToImm (CmmInt i w) = ImmInteger (narrowS w i)+ -- narrow to the width: a CmmInt might be out of+ -- range, but we assume that ImmInteger only contains+ -- in-range values. A signed value should be fine here.+litToImm (CmmFloat f W32) = ImmFloat f+litToImm (CmmFloat f W64) = ImmDouble f+litToImm (CmmLabel l) = ImmCLbl l+litToImm (CmmLabelOff l off) = ImmIndex l off+litToImm (CmmLabelDiffOff l1 l2 off)+ = ImmConstantSum+ (ImmConstantDiff (ImmCLbl l1) (ImmCLbl l2))+ (ImmInt off)+litToImm _ = panic "PPC.Regs.litToImm: no match"+++-- addressing modes ------------------------------------------------------------++data AddrMode+ = AddrRegReg Reg Reg+ | AddrRegImm Reg Imm+++addrOffset :: AddrMode -> Int -> Maybe AddrMode+addrOffset addr off+ = case addr of+ AddrRegImm r (ImmInt n)+ | fits16Bits n2 -> Just (AddrRegImm r (ImmInt n2))+ | otherwise -> Nothing+ where n2 = n + off++ AddrRegImm r (ImmInteger n)+ | fits16Bits n2 -> Just (AddrRegImm r (ImmInt (fromInteger n2)))+ | otherwise -> Nothing+ where n2 = n + toInteger off++ _ -> Nothing+++-- registers -------------------------------------------------------------------+-- @spRel@ gives us a stack relative addressing mode for volatile+-- temporaries and for excess call arguments. @fpRel@, where+-- applicable, is the same but for the frame pointer.++spRel :: DynFlags+ -> Int -- desired stack offset in words, positive or negative+ -> AddrMode++spRel dflags n = AddrRegImm sp (ImmInt (n * wORD_SIZE dflags))+++-- argRegs is the set of regs which are read for an n-argument call to C.+-- For archs which pass all args on the stack (x86), is empty.+-- Sparc passes up to the first 6 args in regs.+argRegs :: RegNo -> [Reg]+argRegs 0 = []+argRegs 1 = map regSingle [3]+argRegs 2 = map regSingle [3,4]+argRegs 3 = map regSingle [3..5]+argRegs 4 = map regSingle [3..6]+argRegs 5 = map regSingle [3..7]+argRegs 6 = map regSingle [3..8]+argRegs 7 = map regSingle [3..9]+argRegs 8 = map regSingle [3..10]+argRegs _ = panic "MachRegs.argRegs(powerpc): don't know about >8 arguments!"+++allArgRegs :: [Reg]+allArgRegs = map regSingle [3..10]+++-- these are the regs which we cannot assume stay alive over a C call.+callClobberedRegs :: Platform -> [Reg]+callClobberedRegs platform+ = case platformOS platform of+ OSAIX -> map regSingle (0:[2..12] ++ map fReg [0..13])+ OSDarwin -> map regSingle (0:[2..12] ++ map fReg [0..13])+ OSLinux -> map regSingle (0:[2..13] ++ map fReg [0..13])+ _ -> panic "PPC.Regs.callClobberedRegs: not defined for this architecture"+++allMachRegNos :: [RegNo]+allMachRegNos = [0..63]+++{-# INLINE classOfRealReg #-}+classOfRealReg :: RealReg -> RegClass+classOfRealReg (RealRegSingle i)+ | i < 32 = RcInteger+ | otherwise = RcDouble++classOfRealReg (RealRegPair{})+ = panic "regClass(ppr): no reg pairs on this architecture"++showReg :: RegNo -> String+showReg n+ | n >= 0 && n <= 31 = "%r" ++ show n+ | n >= 32 && n <= 63 = "%f" ++ show (n - 32)+ | otherwise = "%unknown_powerpc_real_reg_" ++ show n++++-- machine specific ------------------------------------------------------------++allFPArgRegs :: Platform -> [Reg]+allFPArgRegs platform+ = case platformOS platform of+ OSAIX -> map (regSingle . fReg) [1..13]+ OSDarwin -> map (regSingle . fReg) [1..13]+ OSLinux -> case platformArch platform of+ ArchPPC -> map (regSingle . fReg) [1..8]+ ArchPPC_64 _ -> map (regSingle . fReg) [1..13]+ _ -> panic "PPC.Regs.allFPArgRegs: unknown PPC Linux"+ _ -> panic "PPC.Regs.allFPArgRegs: not defined for this architecture"++fits16Bits :: Integral a => a -> Bool+fits16Bits x = x >= -32768 && x < 32768++makeImmediate :: Integral a => Width -> Bool -> a -> Maybe Imm+makeImmediate rep signed x = fmap ImmInt (toI16 rep signed)+ where+ narrow W64 False = fromIntegral (fromIntegral x :: Word64)+ narrow W32 False = fromIntegral (fromIntegral x :: Word32)+ narrow W16 False = fromIntegral (fromIntegral x :: Word16)+ narrow W8 False = fromIntegral (fromIntegral x :: Word8)+ narrow W64 True = fromIntegral (fromIntegral x :: Int64)+ narrow W32 True = fromIntegral (fromIntegral x :: Int32)+ narrow W16 True = fromIntegral (fromIntegral x :: Int16)+ narrow W8 True = fromIntegral (fromIntegral x :: Int8)+ narrow _ _ = panic "PPC.Regs.narrow: no match"++ narrowed = narrow rep signed++ toI16 W32 True+ | narrowed >= -32768 && narrowed < 32768 = Just narrowed+ | otherwise = Nothing+ toI16 W32 False+ | narrowed >= 0 && narrowed < 65536 = Just narrowed+ | otherwise = Nothing+ toI16 W64 True+ | narrowed >= -32768 && narrowed < 32768 = Just narrowed+ | otherwise = Nothing+ toI16 W64 False+ | narrowed >= 0 && narrowed < 65536 = Just narrowed+ | otherwise = Nothing+ toI16 _ _ = Just narrowed+++{-+The PowerPC has 64 registers of interest; 32 integer registers and 32 floating+point registers.+-}++fReg :: Int -> RegNo+fReg x = (32 + x)++r0, sp, toc, r3, r4, r11, r12, r27, r28, r30, f1, f20, f21 :: Reg+r0 = regSingle 0+sp = regSingle 1+toc = regSingle 2+r3 = regSingle 3+r4 = regSingle 4+r11 = regSingle 11+r12 = regSingle 12+r27 = regSingle 27+r28 = regSingle 28+r30 = regSingle 30+f1 = regSingle $ fReg 1+f20 = regSingle $ fReg 20+f21 = regSingle $ fReg 21++-- allocatableRegs is allMachRegNos with the fixed-use regs removed.+-- i.e., these are the regs for which we are prepared to allow the+-- register allocator to attempt to map VRegs to.+allocatableRegs :: Platform -> [RealReg]+allocatableRegs platform+ = let isFree i = freeReg platform i+ in map RealRegSingle $ filter isFree allMachRegNos++-- temporary register for compiler use+tmpReg :: Platform -> Reg+tmpReg platform =+ case platformArch platform of+ ArchPPC -> regSingle 13+ ArchPPC_64 _ -> regSingle 30+ _ -> panic "PPC.Regs.tmpReg: unknowm arch"
+ nativeGen/PprBase.hs view
@@ -0,0 +1,153 @@+-----------------------------------------------------------------------------+--+-- Pretty-printing assembly language+--+-- (c) The University of Glasgow 1993-2005+--+-----------------------------------------------------------------------------++module PprBase (+ castFloatToWord8Array,+ castDoubleToWord8Array,+ floatToBytes,+ doubleToBytes,+ pprSectionHeader+)++where++import CLabel+import Cmm+import DynFlags+import FastString+import Outputable+import Platform++import qualified Data.Array.Unsafe as U ( castSTUArray )+import Data.Array.ST++import Control.Monad.ST++import Data.Word++++-- -----------------------------------------------------------------------------+-- Converting floating-point literals to integrals for printing++castFloatToWord8Array :: STUArray s Int Float -> ST s (STUArray s Int Word8)+castFloatToWord8Array = U.castSTUArray++castDoubleToWord8Array :: STUArray s Int Double -> ST s (STUArray s Int Word8)+castDoubleToWord8Array = U.castSTUArray++-- floatToBytes and doubleToBytes convert to the host's byte+-- order. Providing that we're not cross-compiling for a+-- target with the opposite endianness, this should work ok+-- on all targets.++-- ToDo: this stuff is very similar to the shenanigans in PprAbs,+-- could they be merged?++floatToBytes :: Float -> [Int]+floatToBytes f+ = runST (do+ arr <- newArray_ ((0::Int),3)+ writeArray arr 0 f+ arr <- castFloatToWord8Array arr+ i0 <- readArray arr 0+ i1 <- readArray arr 1+ i2 <- readArray arr 2+ i3 <- readArray arr 3+ return (map fromIntegral [i0,i1,i2,i3])+ )++doubleToBytes :: Double -> [Int]+doubleToBytes d+ = runST (do+ arr <- newArray_ ((0::Int),7)+ writeArray arr 0 d+ arr <- castDoubleToWord8Array arr+ i0 <- readArray arr 0+ i1 <- readArray arr 1+ i2 <- readArray arr 2+ i3 <- readArray arr 3+ i4 <- readArray arr 4+ i5 <- readArray arr 5+ i6 <- readArray arr 6+ i7 <- readArray arr 7+ return (map fromIntegral [i0,i1,i2,i3,i4,i5,i6,i7])+ )++-- ----------------------------------------------------------------------------+-- Printing section headers.+--+-- If -split-section was specified, include the suffix label, otherwise just+-- print the section type. For Darwin, where subsections-for-symbols are+-- used instead, only print section type.+--+-- For string literals, additional flags are specified to enable merging of+-- identical strings in the linker. With -split-sections each string also gets+-- a unique section to allow strings from unused code to be GC'd.++pprSectionHeader :: Platform -> Section -> SDoc+pprSectionHeader platform (Section t suffix) =+ case platformOS platform of+ OSAIX -> pprXcoffSectionHeader t+ OSDarwin -> pprDarwinSectionHeader t+ _ -> pprGNUSectionHeader t suffix++pprGNUSectionHeader :: SectionType -> CLabel -> SDoc+pprGNUSectionHeader t suffix = sdocWithDynFlags $ \dflags ->+ let splitSections = gopt Opt_SplitSections dflags+ subsection | splitSections = char '.' <> ppr suffix+ | otherwise = empty+ in text ".section " <> ptext (header dflags) <> subsection <>+ flags dflags+ where+ header dflags = case t of+ Text -> sLit ".text"+ Data -> sLit ".data"+ ReadOnlyData -> sLit ".rodata"+ RelocatableReadOnlyData -> sLit ".data.rel.ro"+ UninitialisedData -> sLit ".bss"+ ReadOnlyData16 -> sLit ".rodata.cst16"+ CString+ | OSMinGW32 <- platformOS (targetPlatform dflags)+ -> sLit ".rdata"+ | otherwise -> sLit ".rodata.str"+ OtherSection _ ->+ panic "PprBase.pprGNUSectionHeader: unknown section type"+ flags dflags = case t of+ CString+ | OSMinGW32 <- platformOS (targetPlatform dflags)+ -> text ",\"dr\""+ | otherwise -> text ",\"aMS\",@progbits,1"+ _ -> empty++-- XCOFF doesn't support relocating label-differences, so we place all+-- RO sections into .text[PR] sections+pprXcoffSectionHeader :: SectionType -> SDoc+pprXcoffSectionHeader t = text $ case t of+ Text -> ".csect .text[PR]"+ Data -> ".csect .data[RW]"+ ReadOnlyData -> ".csect .text[PR] # ReadOnlyData"+ RelocatableReadOnlyData -> ".csect .text[PR] # RelocatableReadOnlyData"+ ReadOnlyData16 -> ".csect .text[PR] # ReadOnlyData16"+ CString -> ".csect .text[PR] # CString"+ UninitialisedData -> ".csect .data[BS]"+ OtherSection _ ->+ panic "PprBase.pprXcoffSectionHeader: unknown section type"++pprDarwinSectionHeader :: SectionType -> SDoc+pprDarwinSectionHeader t =+ ptext $ case t of+ Text -> sLit ".text"+ Data -> sLit ".data"+ ReadOnlyData -> sLit ".const"+ RelocatableReadOnlyData -> sLit ".const_data"+ UninitialisedData -> sLit ".data"+ ReadOnlyData16 -> sLit ".const"+ CString -> sLit ".section\t__TEXT,__cstring,cstring_literals"+ OtherSection _ ->+ panic "PprBase.pprDarwinSectionHeader: unknown section type"
+ nativeGen/Reg.hs view
@@ -0,0 +1,239 @@+-- | An architecture independent description of a register.+-- This needs to stay architecture independent because it is used+-- by NCGMonad and the register allocators, which are shared+-- by all architectures.+--+module Reg (+ RegNo,+ Reg(..),+ regPair,+ regSingle,+ isRealReg, takeRealReg,+ isVirtualReg, takeVirtualReg,++ VirtualReg(..),+ renameVirtualReg,+ classOfVirtualReg,+ getHiVirtualRegFromLo,+ getHiVRegFromLo,++ RealReg(..),+ regNosOfRealReg,+ realRegsAlias,++ liftPatchFnToRegReg+)++where++import Outputable+import Unique+import RegClass+import Data.List++-- | An identifier for a primitive real machine register.+type RegNo+ = Int++-- VirtualRegs are virtual registers. The register allocator will+-- eventually have to map them into RealRegs, or into spill slots.+--+-- VirtualRegs are allocated on the fly, usually to represent a single+-- value in the abstract assembly code (i.e. dynamic registers are+-- usually single assignment).+--+-- The single assignment restriction isn't necessary to get correct code,+-- although a better register allocation will result if single+-- assignment is used -- because the allocator maps a VirtualReg into+-- a single RealReg, even if the VirtualReg has multiple live ranges.+--+-- Virtual regs can be of either class, so that info is attached.+--+data VirtualReg+ = VirtualRegI {-# UNPACK #-} !Unique+ | VirtualRegHi {-# UNPACK #-} !Unique -- High part of 2-word register+ | VirtualRegF {-# UNPACK #-} !Unique+ | VirtualRegD {-# UNPACK #-} !Unique+ | VirtualRegSSE {-# UNPACK #-} !Unique+ deriving (Eq, Show)++-- This is laborious, but necessary. We can't derive Ord because+-- Unique doesn't have an Ord instance. Note nonDetCmpUnique in the+-- implementation. See Note [No Ord for Unique]+-- This is non-deterministic but we do not currently support deterministic+-- code-generation. See Note [Unique Determinism and code generation]+instance Ord VirtualReg where+ compare (VirtualRegI a) (VirtualRegI b) = nonDetCmpUnique a b+ compare (VirtualRegHi a) (VirtualRegHi b) = nonDetCmpUnique a b+ compare (VirtualRegF a) (VirtualRegF b) = nonDetCmpUnique a b+ compare (VirtualRegD a) (VirtualRegD b) = nonDetCmpUnique a b+ compare (VirtualRegSSE a) (VirtualRegSSE b) = nonDetCmpUnique a b+ compare VirtualRegI{} _ = LT+ compare _ VirtualRegI{} = GT+ compare VirtualRegHi{} _ = LT+ compare _ VirtualRegHi{} = GT+ compare VirtualRegF{} _ = LT+ compare _ VirtualRegF{} = GT+ compare VirtualRegD{} _ = LT+ compare _ VirtualRegD{} = GT+++instance Uniquable VirtualReg where+ getUnique reg+ = case reg of+ VirtualRegI u -> u+ VirtualRegHi u -> u+ VirtualRegF u -> u+ VirtualRegD u -> u+ VirtualRegSSE u -> u++instance Outputable VirtualReg where+ ppr reg+ = case reg of+ VirtualRegI u -> text "%vI_" <> pprUniqueAlways u+ VirtualRegHi u -> text "%vHi_" <> pprUniqueAlways u+ VirtualRegF u -> text "%vF_" <> pprUniqueAlways u+ VirtualRegD u -> text "%vD_" <> pprUniqueAlways u+ VirtualRegSSE u -> text "%vSSE_" <> pprUniqueAlways u+++renameVirtualReg :: Unique -> VirtualReg -> VirtualReg+renameVirtualReg u r+ = case r of+ VirtualRegI _ -> VirtualRegI u+ VirtualRegHi _ -> VirtualRegHi u+ VirtualRegF _ -> VirtualRegF u+ VirtualRegD _ -> VirtualRegD u+ VirtualRegSSE _ -> VirtualRegSSE u+++classOfVirtualReg :: VirtualReg -> RegClass+classOfVirtualReg vr+ = case vr of+ VirtualRegI{} -> RcInteger+ VirtualRegHi{} -> RcInteger+ VirtualRegF{} -> RcFloat+ VirtualRegD{} -> RcDouble+ VirtualRegSSE{} -> RcDoubleSSE+++-- Determine the upper-half vreg for a 64-bit quantity on a 32-bit platform+-- when supplied with the vreg for the lower-half of the quantity.+-- (NB. Not reversible).+getHiVirtualRegFromLo :: VirtualReg -> VirtualReg+getHiVirtualRegFromLo reg+ = case reg of+ -- makes a pseudo-unique with tag 'H'+ VirtualRegI u -> VirtualRegHi (newTagUnique u 'H')+ _ -> panic "Reg.getHiVirtualRegFromLo"++getHiVRegFromLo :: Reg -> Reg+getHiVRegFromLo reg+ = case reg of+ RegVirtual vr -> RegVirtual (getHiVirtualRegFromLo vr)+ RegReal _ -> panic "Reg.getHiVRegFromLo"+++------------------------------------------------------------------------------------+-- | RealRegs are machine regs which are available for allocation, in+-- the usual way. We know what class they are, because that's part of+-- the processor's architecture.+--+-- RealRegPairs are pairs of real registers that are allocated together+-- to hold a larger value, such as with Double regs on SPARC.+--+data RealReg+ = RealRegSingle {-# UNPACK #-} !RegNo+ | RealRegPair {-# UNPACK #-} !RegNo {-# UNPACK #-} !RegNo+ deriving (Eq, Show, Ord)++instance Uniquable RealReg where+ getUnique reg+ = case reg of+ RealRegSingle i -> mkRegSingleUnique i+ RealRegPair r1 r2 -> mkRegPairUnique (r1 * 65536 + r2)++instance Outputable RealReg where+ ppr reg+ = case reg of+ RealRegSingle i -> text "%r" <> int i+ RealRegPair r1 r2 -> text "%r(" <> int r1+ <> vbar <> int r2 <> text ")"++regNosOfRealReg :: RealReg -> [RegNo]+regNosOfRealReg rr+ = case rr of+ RealRegSingle r1 -> [r1]+ RealRegPair r1 r2 -> [r1, r2]+++realRegsAlias :: RealReg -> RealReg -> Bool+realRegsAlias rr1 rr2+ = not $ null $ intersect (regNosOfRealReg rr1) (regNosOfRealReg rr2)++--------------------------------------------------------------------------------+-- | A register, either virtual or real+data Reg+ = RegVirtual !VirtualReg+ | RegReal !RealReg+ deriving (Eq, Ord)++regSingle :: RegNo -> Reg+regSingle regNo = RegReal $ RealRegSingle regNo++regPair :: RegNo -> RegNo -> Reg+regPair regNo1 regNo2 = RegReal $ RealRegPair regNo1 regNo2+++-- We like to have Uniques for Reg so that we can make UniqFM and UniqSets+-- in the register allocator.+instance Uniquable Reg where+ getUnique reg+ = case reg of+ RegVirtual vr -> getUnique vr+ RegReal rr -> getUnique rr++-- | Print a reg in a generic manner+-- If you want the architecture specific names, then use the pprReg+-- function from the appropriate Ppr module.+instance Outputable Reg where+ ppr reg+ = case reg of+ RegVirtual vr -> ppr vr+ RegReal rr -> ppr rr+++isRealReg :: Reg -> Bool+isRealReg reg+ = case reg of+ RegReal _ -> True+ RegVirtual _ -> False++takeRealReg :: Reg -> Maybe RealReg+takeRealReg reg+ = case reg of+ RegReal rr -> Just rr+ _ -> Nothing+++isVirtualReg :: Reg -> Bool+isVirtualReg reg+ = case reg of+ RegReal _ -> False+ RegVirtual _ -> True++takeVirtualReg :: Reg -> Maybe VirtualReg+takeVirtualReg reg+ = case reg of+ RegReal _ -> Nothing+ RegVirtual vr -> Just vr+++-- | The patch function supplied by the allocator maps VirtualReg to RealReg+-- regs, but sometimes we want to apply it to plain old Reg.+--+liftPatchFnToRegReg :: (VirtualReg -> RealReg) -> (Reg -> Reg)+liftPatchFnToRegReg patchF reg+ = case reg of+ RegVirtual vr -> RegReal (patchF vr)+ RegReal _ -> reg
+ nativeGen/RegAlloc/Graph/ArchBase.hs view
@@ -0,0 +1,159 @@++-- | Utils for calculating general worst, bound, squeese and free, functions.+--+-- as per: "A Generalized Algorithm for Graph-Coloring Register Allocation"+-- Michael Smith, Normal Ramsey, Glenn Holloway.+-- PLDI 2004+--+-- These general versions are not used in GHC proper because they are too slow.+-- Instead, hand written optimised versions are provided for each architecture+-- in MachRegs*.hs+--+-- This code is here because we can test the architecture specific code against+-- it.+--+module RegAlloc.Graph.ArchBase (+ RegClass(..),+ Reg(..),+ RegSub(..),++ worst,+ bound,+ squeese+) where+import UniqSet+import UniqFM+import Unique+++-- Some basic register classes.+-- These aren't nessesarally in 1-to-1 correspondance with the allocatable+-- RegClasses in MachRegs.hs+data RegClass+ -- general purpose regs+ = ClassG32 -- 32 bit GPRs+ | ClassG16 -- 16 bit GPRs+ | ClassG8 -- 8 bit GPRs++ -- floating point regs+ | ClassF64 -- 64 bit FPRs+ deriving (Show, Eq, Enum)+++-- | A register of some class+data Reg+ -- a register of some class+ = Reg RegClass Int++ -- a sub-component of one of the other regs+ | RegSub RegSub Reg+ deriving (Show, Eq)+++-- | so we can put regs in UniqSets+instance Uniquable Reg where+ getUnique (Reg c i)+ = mkRegSingleUnique+ $ fromEnum c * 1000 + i++ getUnique (RegSub s (Reg c i))+ = mkRegSubUnique+ $ fromEnum s * 10000 + fromEnum c * 1000 + i++ getUnique (RegSub _ (RegSub _ _))+ = error "RegArchBase.getUnique: can't have a sub-reg of a sub-reg."+++-- | A subcomponent of another register+data RegSub+ = SubL16 -- lowest 16 bits+ | SubL8 -- lowest 8 bits+ | SubL8H -- second lowest 8 bits+ deriving (Show, Enum, Ord, Eq)+++-- | Worst case displacement+--+-- a node N of classN has some number of neighbors,+-- all of which are from classC.+--+-- (worst neighbors classN classC) is the maximum number of potential+-- colors for N that can be lost by coloring its neighbors.+--+-- This should be hand coded/cached for each particular architecture,+-- because the compute time is very long..+worst :: (RegClass -> UniqSet Reg)+ -> (Reg -> UniqSet Reg)+ -> Int -> RegClass -> RegClass -> Int++worst regsOfClass regAlias neighbors classN classC+ = let regAliasS regs = unionManyUniqSets+ $ map regAlias+ $ nonDetEltsUniqSet regs+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]++ -- all the regs in classes N, C+ regsN = regsOfClass classN+ regsC = regsOfClass classC++ -- all the possible subsets of c which have size < m+ regsS = filter (\s -> sizeUniqSet s >= 1+ && sizeUniqSet s <= neighbors)+ $ powersetLS regsC++ -- for each of the subsets of C, the regs which conflict+ -- with posiblities for N+ regsS_conflict+ = map (\s -> intersectUniqSets regsN (regAliasS s)) regsS++ in maximum $ map sizeUniqSet $ regsS_conflict+++-- | For a node N of classN and neighbors of classesC+-- (bound classN classesC) is the maximum number of potential+-- colors for N that can be lost by coloring its neighbors.+bound :: (RegClass -> UniqSet Reg)+ -> (Reg -> UniqSet Reg)+ -> RegClass -> [RegClass] -> Int++bound regsOfClass regAlias classN classesC+ = let regAliasS regs = unionManyUniqSets+ $ map regAlias+ $ nonDetEltsUFM regs+ -- See Note [Unique Determinism and code generation]++ regsC_aliases+ = unionManyUniqSets+ $ map (regAliasS . getUniqSet . regsOfClass) classesC++ overlap = intersectUniqSets (regsOfClass classN) regsC_aliases++ in sizeUniqSet overlap+++-- | The total squeese on a particular node with a list of neighbors.+--+-- A version of this should be constructed for each particular architecture,+-- possibly including uses of bound, so that alised registers don't get+-- counted twice, as per the paper.+squeese :: (RegClass -> UniqSet Reg)+ -> (Reg -> UniqSet Reg)+ -> RegClass -> [(Int, RegClass)] -> Int++squeese regsOfClass regAlias classN countCs+ = sum+ $ map (\(i, classC) -> worst regsOfClass regAlias i classN classC)+ $ countCs+++-- | powerset (for lists)+powersetL :: [a] -> [[a]]+powersetL = map concat . mapM (\x -> [[],[x]])+++-- | powersetLS (list of sets)+powersetLS :: Uniquable a => UniqSet a -> [UniqSet a]+powersetLS s = map mkUniqSet $ powersetL $ nonDetEltsUniqSet s+ -- See Note [Unique Determinism and code generation]
+ nativeGen/RegAlloc/Graph/ArchX86.hs view
@@ -0,0 +1,146 @@++-- | A description of the register set of the X86.+--+-- This isn't used directly in GHC proper.+--+-- See RegArchBase.hs for the reference.+-- See MachRegs.hs for the actual trivColorable function used in GHC.+--+module RegAlloc.Graph.ArchX86 (+ classOfReg,+ regsOfClass,+ regName,+ regAlias,+ worst,+ squeese,+) where+import RegAlloc.Graph.ArchBase (Reg(..), RegSub(..), RegClass(..))+import UniqSet+++-- | Determine the class of a register+classOfReg :: Reg -> RegClass+classOfReg reg+ = case reg of+ Reg c _ -> c++ RegSub SubL16 _ -> ClassG16+ RegSub SubL8 _ -> ClassG8+ RegSub SubL8H _ -> ClassG8+++-- | Determine all the regs that make up a certain class.+regsOfClass :: RegClass -> UniqSet Reg+regsOfClass c+ = case c of+ ClassG32+ -> mkUniqSet [ Reg ClassG32 i+ | i <- [0..7] ]++ ClassG16+ -> mkUniqSet [ RegSub SubL16 (Reg ClassG32 i)+ | i <- [0..7] ]++ ClassG8+ -> unionUniqSets+ (mkUniqSet [ RegSub SubL8 (Reg ClassG32 i) | i <- [0..3] ])+ (mkUniqSet [ RegSub SubL8H (Reg ClassG32 i) | i <- [0..3] ])++ ClassF64+ -> mkUniqSet [ Reg ClassF64 i+ | i <- [0..5] ]+++-- | Determine the common name of a reg+-- returns Nothing if this reg is not part of the machine.+regName :: Reg -> Maybe String+regName reg+ = case reg of+ Reg ClassG32 i+ | i <= 7-> Just $ [ "eax", "ebx", "ecx", "edx"+ , "ebp", "esi", "edi", "esp" ] !! i++ RegSub SubL16 (Reg ClassG32 i)+ | i <= 7 -> Just $ [ "ax", "bx", "cx", "dx"+ , "bp", "si", "di", "sp"] !! i++ RegSub SubL8 (Reg ClassG32 i)+ | i <= 3 -> Just $ [ "al", "bl", "cl", "dl"] !! i++ RegSub SubL8H (Reg ClassG32 i)+ | i <= 3 -> Just $ [ "ah", "bh", "ch", "dh"] !! i++ _ -> Nothing+++-- | Which regs alias what other regs.+regAlias :: Reg -> UniqSet Reg+regAlias reg+ = case reg of++ -- 32 bit regs alias all of the subregs+ Reg ClassG32 i++ -- for eax, ebx, ecx, eds+ | i <= 3+ -> mkUniqSet+ $ [ Reg ClassG32 i, RegSub SubL16 reg+ , RegSub SubL8 reg, RegSub SubL8H reg ]++ -- for esi, edi, esp, ebp+ | 4 <= i && i <= 7+ -> mkUniqSet+ $ [ Reg ClassG32 i, RegSub SubL16 reg ]++ -- 16 bit subregs alias the whole reg+ RegSub SubL16 r@(Reg ClassG32 _)+ -> regAlias r++ -- 8 bit subregs alias the 32 and 16, but not the other 8 bit subreg+ RegSub SubL8 r@(Reg ClassG32 _)+ -> mkUniqSet $ [ r, RegSub SubL16 r, RegSub SubL8 r ]++ RegSub SubL8H r@(Reg ClassG32 _)+ -> mkUniqSet $ [ r, RegSub SubL16 r, RegSub SubL8H r ]++ -- fp+ Reg ClassF64 _+ -> unitUniqSet reg++ _ -> error "regAlias: invalid register"+++-- | Optimised versions of RegColorBase.{worst, squeese} specific to x86+worst :: Int -> RegClass -> RegClass -> Int+worst n classN classC+ = case classN of+ ClassG32+ -> case classC of+ ClassG32 -> min n 8+ ClassG16 -> min n 8+ ClassG8 -> min n 4+ ClassF64 -> 0++ ClassG16+ -> case classC of+ ClassG32 -> min n 8+ ClassG16 -> min n 8+ ClassG8 -> min n 4+ ClassF64 -> 0++ ClassG8+ -> case classC of+ ClassG32 -> min (n*2) 8+ ClassG16 -> min (n*2) 8+ ClassG8 -> min n 8+ ClassF64 -> 0++ ClassF64+ -> case classC of+ ClassF64 -> min n 6+ _ -> 0++squeese :: RegClass -> [(Int, RegClass)] -> Int+squeese classN countCs+ = sum (map (\(i, classC) -> worst i classN classC) countCs)+
+ nativeGen/RegAlloc/Graph/Coalesce.hs view
@@ -0,0 +1,99 @@+-- | Register coalescing.+module RegAlloc.Graph.Coalesce (+ regCoalesce,+ slurpJoinMovs+) where+import RegAlloc.Liveness+import Instruction+import Reg++import Cmm+import Bag+import Digraph+import UniqFM+import UniqSet+import UniqSupply++import Data.List+++-- | Do register coalescing on this top level thing+--+-- For Reg -> Reg moves, if the first reg dies at the same time the+-- second reg is born then the mov only serves to join live ranges.+-- The two regs can be renamed to be the same and the move instruction+-- safely erased.+regCoalesce+ :: Instruction instr+ => [LiveCmmDecl statics instr]+ -> UniqSM [LiveCmmDecl statics instr]++regCoalesce code+ = do+ let joins = foldl' unionBags emptyBag+ $ map slurpJoinMovs code++ let alloc = foldl' buildAlloc emptyUFM+ $ bagToList joins++ let patched = map (patchEraseLive (sinkReg alloc)) code++ return patched+++-- | Add a v1 = v2 register renaming to the map.+-- The register with the lowest lexical name is set as the+-- canonical version.+buildAlloc :: UniqFM Reg -> (Reg, Reg) -> UniqFM Reg+buildAlloc fm (r1, r2)+ = let rmin = min r1 r2+ rmax = max r1 r2+ in addToUFM fm rmax rmin+++-- | Determine the canonical name for a register by following+-- v1 = v2 renamings in this map.+sinkReg :: UniqFM Reg -> Reg -> Reg+sinkReg fm r+ = case lookupUFM fm r of+ Nothing -> r+ Just r' -> sinkReg fm r'+++-- | Slurp out mov instructions that only serve to join live ranges.+--+-- During a mov, if the source reg dies and the destiation reg is+-- born then we can rename the two regs to the same thing and+-- eliminate the move.+slurpJoinMovs+ :: Instruction instr+ => LiveCmmDecl statics instr+ -> Bag (Reg, Reg)++slurpJoinMovs live+ = slurpCmm emptyBag live+ where+ slurpCmm rs CmmData{}+ = rs++ slurpCmm rs (CmmProc _ _ _ sccs)+ = foldl' slurpBlock rs (flattenSCCs sccs)++ slurpBlock rs (BasicBlock _ instrs)+ = foldl' slurpLI rs instrs++ slurpLI rs (LiveInstr _ Nothing) = rs+ slurpLI rs (LiveInstr instr (Just live))+ | Just (r1, r2) <- takeRegRegMoveInstr instr+ , elementOfUniqSet r1 $ liveDieRead live+ , elementOfUniqSet r2 $ liveBorn live++ -- only coalesce movs between two virtuals for now,+ -- else we end up with allocatable regs in the live+ -- regs list..+ , isVirtualReg r1 && isVirtualReg r2+ = consBag (r1, r2) rs++ | otherwise+ = rs+
+ nativeGen/RegAlloc/Graph/Main.hs view
@@ -0,0 +1,453 @@+{-# LANGUAGE ScopedTypeVariables #-}++-- | Graph coloring register allocator.+module RegAlloc.Graph.Main (+ regAlloc+) where+import qualified GraphColor as Color+import RegAlloc.Liveness+import RegAlloc.Graph.Spill+import RegAlloc.Graph.SpillClean+import RegAlloc.Graph.SpillCost+import RegAlloc.Graph.Stats+import RegAlloc.Graph.TrivColorable+import Instruction+import TargetReg+import RegClass+import Reg++import Bag+import DynFlags+import Outputable+import Platform+import UniqFM+import UniqSet+import UniqSupply+import Util (seqList)++import Data.List+import Data.Maybe+import Control.Monad+++-- | The maximum number of build\/spill cycles we'll allow.+--+-- It should only take 3 or 4 cycles for the allocator to converge.+-- If it takes any longer than this it's probably in an infinite loop,+-- so it's better just to bail out and report a bug.+maxSpinCount :: Int+maxSpinCount = 10+++-- | The top level of the graph coloring register allocator.+regAlloc+ :: (Outputable statics, Outputable instr, Instruction instr)+ => DynFlags+ -> UniqFM (UniqSet RealReg) -- ^ registers we can use for allocation+ -> UniqSet Int -- ^ set of available spill slots.+ -> [LiveCmmDecl statics instr] -- ^ code annotated with liveness information.+ -> UniqSM ( [NatCmmDecl statics instr], [RegAllocStats statics instr] )+ -- ^ code with registers allocated and stats for each stage of+ -- allocation++regAlloc dflags regsFree slotsFree code+ = do+ -- TODO: the regClass function is currently hard coded to the default+ -- target architecture. Would prefer to determine this from dflags.+ -- There are other uses of targetRegClass later in this module.+ let platform = targetPlatform dflags+ triv = trivColorable platform+ (targetVirtualRegSqueeze platform)+ (targetRealRegSqueeze platform)++ (code_final, debug_codeGraphs, _)+ <- regAlloc_spin dflags 0+ triv+ regsFree slotsFree [] code++ return ( code_final+ , reverse debug_codeGraphs )+++-- | Perform solver iterations for the graph coloring allocator.+--+-- We extract a register confict graph from the provided cmm code,+-- and try to colour it. If that works then we use the solution rewrite+-- the code with real hregs. If coloring doesn't work we add spill code+-- and try to colour it again. After `maxSpinCount` iterations we give up.+--+regAlloc_spin+ :: (Instruction instr,+ Outputable instr,+ Outputable statics)+ => DynFlags+ -> Int -- ^ Number of solver iterations we've already performed.+ -> Color.Triv VirtualReg RegClass RealReg+ -- ^ Function for calculating whether a register is trivially+ -- colourable.+ -> UniqFM (UniqSet RealReg) -- ^ Free registers that we can allocate.+ -> UniqSet Int -- ^ Free stack slots that we can use.+ -> [RegAllocStats statics instr] -- ^ Current regalloc stats to add to.+ -> [LiveCmmDecl statics instr] -- ^ Liveness annotated code to allocate.+ -> UniqSM ( [NatCmmDecl statics instr]+ , [RegAllocStats statics instr]+ , Color.Graph VirtualReg RegClass RealReg)++regAlloc_spin dflags spinCount triv regsFree slotsFree debug_codeGraphs code+ = do+ let platform = targetPlatform dflags++ -- If any of these dump flags are turned on we want to hang on to+ -- intermediate structures in the allocator - otherwise tell the+ -- allocator to ditch them early so we don't end up creating space leaks.+ let dump = or+ [ dopt Opt_D_dump_asm_regalloc_stages dflags+ , dopt Opt_D_dump_asm_stats dflags+ , dopt Opt_D_dump_asm_conflicts dflags ]++ -- Check that we're not running off down the garden path.+ when (spinCount > maxSpinCount)+ $ pprPanic "regAlloc_spin: max build/spill cycle count exceeded."+ ( text "It looks like the register allocator is stuck in an infinite loop."+ $$ text "max cycles = " <> int maxSpinCount+ $$ text "regsFree = " <> (hcat $ punctuate space $ map ppr+ $ nonDetEltsUniqSet $ unionManyUniqSets+ $ nonDetEltsUFM regsFree)+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ $$ text "slotsFree = " <> ppr (sizeUniqSet slotsFree))++ -- Build the register conflict graph from the cmm code.+ (graph :: Color.Graph VirtualReg RegClass RealReg)+ <- {-# SCC "BuildGraph" #-} buildGraph code++ -- VERY IMPORTANT:+ -- We really do want the graph to be fully evaluated _before_ we+ -- start coloring. If we don't do this now then when the call to+ -- Color.colorGraph forces bits of it, the heap will be filled with+ -- half evaluated pieces of graph and zillions of apply thunks.+ seqGraph graph `seq` return ()++ -- Build a map of the cost of spilling each instruction.+ -- This is a lazy binding, so the map will only be computed if we+ -- actually have to spill to the stack.+ let spillCosts = foldl' plusSpillCostInfo zeroSpillCostInfo+ $ map (slurpSpillCostInfo platform) code++ -- The function to choose regs to leave uncolored.+ let spill = chooseSpill spillCosts++ -- Record startup state in our log.+ let stat1+ = if spinCount == 0+ then Just $ RegAllocStatsStart+ { raLiveCmm = code+ , raGraph = graph+ , raSpillCosts = spillCosts }+ else Nothing++ -- Try and color the graph.+ let (graph_colored, rsSpill, rmCoalesce)+ = {-# SCC "ColorGraph" #-}+ Color.colorGraph+ (gopt Opt_RegsIterative dflags)+ spinCount+ regsFree triv spill graph++ -- Rewrite registers in the code that have been coalesced.+ let patchF reg+ | RegVirtual vr <- reg+ = case lookupUFM rmCoalesce vr of+ Just vr' -> patchF (RegVirtual vr')+ Nothing -> reg++ | otherwise+ = reg++ let code_coalesced+ = map (patchEraseLive patchF) code++ -- Check whether we've found a coloring.+ if isEmptyUniqSet rsSpill++ -- Coloring was successful because no registers needed to be spilled.+ then do+ -- if -fasm-lint is turned on then validate the graph.+ -- This checks for bugs in the graph allocator itself.+ let graph_colored_lint =+ if gopt Opt_DoAsmLinting dflags+ then Color.validateGraph (text "")+ True -- Require all nodes to be colored.+ graph_colored+ else graph_colored++ -- Rewrite the code to use real hregs, using the colored graph.+ let code_patched+ = map (patchRegsFromGraph platform graph_colored_lint)+ code_coalesced++ -- Clean out unneeded SPILL/RELOAD meta instructions.+ -- The spill code generator just spills the entire live range+ -- of a vreg, but it might not need to be on the stack for+ -- its entire lifetime.+ let code_spillclean+ = map (cleanSpills platform) code_patched++ -- Strip off liveness information from the allocated code.+ -- Also rewrite SPILL/RELOAD meta instructions into real machine+ -- instructions along the way+ let code_final+ = map (stripLive dflags) code_spillclean++ -- Record what happened in this stage for debugging+ let stat+ = RegAllocStatsColored+ { raCode = code+ , raGraph = graph+ , raGraphColored = graph_colored_lint+ , raCoalesced = rmCoalesce+ , raCodeCoalesced = code_coalesced+ , raPatched = code_patched+ , raSpillClean = code_spillclean+ , raFinal = code_final+ , raSRMs = foldl' addSRM (0, 0, 0)+ $ map countSRMs code_spillclean }++ -- Bundle up all the register allocator statistics.+ -- .. but make sure to drop them on the floor if they're not+ -- needed, otherwise we'll get a space leak.+ let statList =+ if dump then [stat] ++ maybeToList stat1 ++ debug_codeGraphs+ else []++ -- Ensure all the statistics are evaluated, to avoid space leaks.+ seqList statList (return ())++ return ( code_final+ , statList+ , graph_colored_lint)++ -- Coloring was unsuccessful. We need to spill some register to the+ -- stack, make a new graph, and try to color it again.+ else do+ -- if -fasm-lint is turned on then validate the graph+ let graph_colored_lint =+ if gopt Opt_DoAsmLinting dflags+ then Color.validateGraph (text "")+ False -- don't require nodes to be colored+ graph_colored+ else graph_colored++ -- Spill uncolored regs to the stack.+ (code_spilled, slotsFree', spillStats)+ <- regSpill platform code_coalesced slotsFree rsSpill++ -- Recalculate liveness information.+ -- NOTE: we have to reverse the SCCs here to get them back into+ -- the reverse-dependency order required by computeLiveness.+ -- If they're not in the correct order that function will panic.+ code_relive <- mapM (regLiveness platform . reverseBlocksInTops)+ code_spilled++ -- Record what happened in this stage for debugging.+ let stat =+ RegAllocStatsSpill+ { raCode = code+ , raGraph = graph_colored_lint+ , raCoalesced = rmCoalesce+ , raSpillStats = spillStats+ , raSpillCosts = spillCosts+ , raSpilled = code_spilled }++ -- Bundle up all the register allocator statistics.+ -- .. but make sure to drop them on the floor if they're not+ -- needed, otherwise we'll get a space leak.+ let statList =+ if dump+ then [stat] ++ maybeToList stat1 ++ debug_codeGraphs+ else []++ -- Ensure all the statistics are evaluated, to avoid space leaks.+ seqList statList (return ())++ regAlloc_spin dflags (spinCount + 1) triv regsFree slotsFree'+ statList+ code_relive+++-- | Build a graph from the liveness and coalesce information in this code.+buildGraph+ :: Instruction instr+ => [LiveCmmDecl statics instr]+ -> UniqSM (Color.Graph VirtualReg RegClass RealReg)++buildGraph code+ = do+ -- Slurp out the conflicts and reg->reg moves from this code.+ let (conflictList, moveList) =+ unzip $ map slurpConflicts code++ -- Slurp out the spill/reload coalesces.+ let moveList2 = map slurpReloadCoalesce code++ -- Add the reg-reg conflicts to the graph.+ let conflictBag = unionManyBags conflictList+ let graph_conflict+ = foldrBag graphAddConflictSet Color.initGraph conflictBag++ -- Add the coalescences edges to the graph.+ let moveBag+ = unionBags (unionManyBags moveList2)+ (unionManyBags moveList)++ let graph_coalesce+ = foldrBag graphAddCoalesce graph_conflict moveBag++ return graph_coalesce+++-- | Add some conflict edges to the graph.+-- Conflicts between virtual and real regs are recorded as exclusions.+graphAddConflictSet+ :: UniqSet Reg+ -> Color.Graph VirtualReg RegClass RealReg+ -> Color.Graph VirtualReg RegClass RealReg++graphAddConflictSet set graph+ = let virtuals = mkUniqSet+ [ vr | RegVirtual vr <- nonDetEltsUniqSet set ]++ graph1 = Color.addConflicts virtuals classOfVirtualReg graph++ graph2 = foldr (\(r1, r2) -> Color.addExclusion r1 classOfVirtualReg r2)+ graph1+ [ (vr, rr)+ | RegVirtual vr <- nonDetEltsUniqSet set+ , RegReal rr <- nonDetEltsUniqSet set]+ -- See Note [Unique Determinism and code generation]++ in graph2+++-- | Add some coalesence edges to the graph+-- Coalesences between virtual and real regs are recorded as preferences.+graphAddCoalesce+ :: (Reg, Reg)+ -> Color.Graph VirtualReg RegClass RealReg+ -> Color.Graph VirtualReg RegClass RealReg++graphAddCoalesce (r1, r2) graph+ | RegReal rr <- r1+ , RegVirtual vr <- r2+ = Color.addPreference (vr, classOfVirtualReg vr) rr graph++ | RegReal rr <- r2+ , RegVirtual vr <- r1+ = Color.addPreference (vr, classOfVirtualReg vr) rr graph++ | RegVirtual vr1 <- r1+ , RegVirtual vr2 <- r2+ = Color.addCoalesce+ (vr1, classOfVirtualReg vr1)+ (vr2, classOfVirtualReg vr2)+ graph++ -- We can't coalesce two real regs, but there could well be existing+ -- hreg,hreg moves in the input code. We'll just ignore these+ -- for coalescing purposes.+ | RegReal _ <- r1+ , RegReal _ <- r2+ = graph++ | otherwise+ = panic "graphAddCoalesce"+++-- | Patch registers in code using the reg -> reg mapping in this graph.+patchRegsFromGraph+ :: (Outputable statics, Outputable instr, Instruction instr)+ => Platform -> Color.Graph VirtualReg RegClass RealReg+ -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr++patchRegsFromGraph platform graph code+ = patchEraseLive patchF code+ where+ -- Function to lookup the hardreg for a virtual reg from the graph.+ patchF reg+ -- leave real regs alone.+ | RegReal{} <- reg+ = reg++ -- this virtual has a regular node in the graph.+ | RegVirtual vr <- reg+ , Just node <- Color.lookupNode graph vr+ = case Color.nodeColor node of+ Just color -> RegReal color+ Nothing -> RegVirtual vr++ -- no node in the graph for this virtual, bad news.+ | otherwise+ = pprPanic "patchRegsFromGraph: register mapping failed."+ ( text "There is no node in the graph for register "+ <> ppr reg+ $$ ppr code+ $$ Color.dotGraph+ (\_ -> text "white")+ (trivColorable platform+ (targetVirtualRegSqueeze platform)+ (targetRealRegSqueeze platform))+ graph)+++-----+-- for when laziness just isn't what you wanted...+-- We need to deepSeq the whole graph before trying to colour it to avoid+-- space leaks.+seqGraph :: Color.Graph VirtualReg RegClass RealReg -> ()+seqGraph graph = seqNodes (nonDetEltsUFM (Color.graphMap graph))+ -- See Note [Unique Determinism and code generation]++seqNodes :: [Color.Node VirtualReg RegClass RealReg] -> ()+seqNodes ns+ = case ns of+ [] -> ()+ (n : ns) -> seqNode n `seq` seqNodes ns++seqNode :: Color.Node VirtualReg RegClass RealReg -> ()+seqNode node+ = seqVirtualReg (Color.nodeId node)+ `seq` seqRegClass (Color.nodeClass node)+ `seq` seqMaybeRealReg (Color.nodeColor node)+ `seq` (seqVirtualRegList (nonDetEltsUniqSet (Color.nodeConflicts node)))+ `seq` (seqRealRegList (nonDetEltsUniqSet (Color.nodeExclusions node)))+ `seq` (seqRealRegList (Color.nodePreference node))+ `seq` (seqVirtualRegList (nonDetEltsUniqSet (Color.nodeCoalesce node)))+ -- It's OK to use nonDetEltsUniqSet for seq++seqVirtualReg :: VirtualReg -> ()+seqVirtualReg reg = reg `seq` ()++seqRealReg :: RealReg -> ()+seqRealReg reg = reg `seq` ()++seqRegClass :: RegClass -> ()+seqRegClass c = c `seq` ()++seqMaybeRealReg :: Maybe RealReg -> ()+seqMaybeRealReg mr+ = case mr of+ Nothing -> ()+ Just r -> seqRealReg r++seqVirtualRegList :: [VirtualReg] -> ()+seqVirtualRegList rs+ = case rs of+ [] -> ()+ (r : rs) -> seqVirtualReg r `seq` seqVirtualRegList rs++seqRealRegList :: [RealReg] -> ()+seqRealRegList rs+ = case rs of+ [] -> ()+ (r : rs) -> seqRealReg r `seq` seqRealRegList rs
+ nativeGen/RegAlloc/Graph/Spill.hs view
@@ -0,0 +1,379 @@++-- | When there aren't enough registers to hold all the vregs we have to spill+-- some of those vregs to slots on the stack. This module is used modify the+-- code to use those slots.+module RegAlloc.Graph.Spill (+ regSpill,+ SpillStats(..),+ accSpillSL+) where+import RegAlloc.Liveness+import Instruction+import Reg+import Cmm hiding (RegSet)+import BlockId+import Hoopl++import MonadUtils+import State+import Unique+import UniqFM+import UniqSet+import UniqSupply+import Outputable+import Platform++import Data.List+import Data.Maybe+import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet+++-- | Spill all these virtual regs to stack slots.+--+-- TODO: See if we can split some of the live ranges instead of just globally+-- spilling the virtual reg. This might make the spill cleaner's job easier.+--+-- TODO: On CISCy x86 and x86_64 we don't nessesarally have to add a mov instruction+-- when making spills. If an instr is using a spilled virtual we may be able to+-- address the spill slot directly.+--+regSpill+ :: Instruction instr+ => Platform+ -> [LiveCmmDecl statics instr] -- ^ the code+ -> UniqSet Int -- ^ available stack slots+ -> UniqSet VirtualReg -- ^ the regs to spill+ -> UniqSM+ ([LiveCmmDecl statics instr]+ -- code with SPILL and RELOAD meta instructions added.+ , UniqSet Int -- left over slots+ , SpillStats ) -- stats about what happened during spilling++regSpill platform code slotsFree regs++ -- Not enough slots to spill these regs.+ | sizeUniqSet slotsFree < sizeUniqSet regs+ = pprPanic "regSpill: out of spill slots!"+ ( text " regs to spill = " <> ppr (sizeUniqSet regs)+ $$ text " slots left = " <> ppr (sizeUniqSet slotsFree))++ | otherwise+ = do+ -- Allocate a slot for each of the spilled regs.+ let slots = take (sizeUniqSet regs) $ nonDetEltsUniqSet slotsFree+ let regSlotMap = listToUFM+ $ zip (nonDetEltsUniqSet regs) slots+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]++ -- Grab the unique supply from the monad.+ us <- getUniqueSupplyM++ -- Run the spiller on all the blocks.+ let (code', state') =+ runState (mapM (regSpill_top platform regSlotMap) code)+ (initSpillS us)++ return ( code'+ , minusUniqSet slotsFree (mkUniqSet slots)+ , makeSpillStats state')+++-- | Spill some registers to stack slots in a top-level thing.+regSpill_top+ :: Instruction instr+ => Platform+ -> RegMap Int+ -- ^ map of vregs to slots they're being spilled to.+ -> LiveCmmDecl statics instr+ -- ^ the top level thing.+ -> SpillM (LiveCmmDecl statics instr)++regSpill_top platform regSlotMap cmm+ = case cmm of+ CmmData{}+ -> return cmm++ CmmProc info label live sccs+ | LiveInfo static firstId mLiveVRegsOnEntry liveSlotsOnEntry <- info+ -> do+ -- We should only passed Cmms with the liveness maps filled in,+ -- but we'll create empty ones if they're not there just in case.+ let liveVRegsOnEntry = fromMaybe mapEmpty mLiveVRegsOnEntry++ -- The liveVRegsOnEntry contains the set of vregs that are live+ -- on entry to each basic block. If we spill one of those vregs+ -- we remove it from that set and add the corresponding slot+ -- number to the liveSlotsOnEntry set. The spill cleaner needs+ -- this information to erase unneeded spill and reload instructions+ -- after we've done a successful allocation.+ let liveSlotsOnEntry' :: BlockMap IntSet+ liveSlotsOnEntry'+ = mapFoldWithKey patchLiveSlot+ liveSlotsOnEntry liveVRegsOnEntry++ let info'+ = LiveInfo static firstId+ (Just liveVRegsOnEntry)+ liveSlotsOnEntry'++ -- Apply the spiller to all the basic blocks in the CmmProc.+ sccs' <- mapM (mapSCCM (regSpill_block platform regSlotMap)) sccs++ return $ CmmProc info' label live sccs'++ where -- Given a BlockId and the set of registers live in it,+ -- if registers in this block are being spilled to stack slots,+ -- then record the fact that these slots are now live in those blocks+ -- in the given slotmap.+ patchLiveSlot+ :: BlockId -> RegSet+ -> BlockMap IntSet -> BlockMap IntSet++ patchLiveSlot blockId regsLive slotMap+ = let+ -- Slots that are already recorded as being live.+ curSlotsLive = fromMaybe IntSet.empty+ $ mapLookup blockId slotMap++ moreSlotsLive = IntSet.fromList+ $ catMaybes+ $ map (lookupUFM regSlotMap)+ $ nonDetEltsUniqSet regsLive+ -- See Note [Unique Determinism and code generation]++ slotMap'+ = mapInsert blockId (IntSet.union curSlotsLive moreSlotsLive)+ slotMap++ in slotMap'+++-- | Spill some registers to stack slots in a basic block.+regSpill_block+ :: Instruction instr+ => Platform+ -> UniqFM Int -- ^ map of vregs to slots they're being spilled to.+ -> LiveBasicBlock instr+ -> SpillM (LiveBasicBlock instr)++regSpill_block platform regSlotMap (BasicBlock i instrs)+ = do instrss' <- mapM (regSpill_instr platform regSlotMap) instrs+ return $ BasicBlock i (concat instrss')+++-- | Spill some registers to stack slots in a single instruction.+-- If the instruction uses registers that need to be spilled, then it is+-- prefixed (or postfixed) with the appropriate RELOAD or SPILL meta+-- instructions.+regSpill_instr+ :: Instruction instr+ => Platform+ -> UniqFM Int -- ^ map of vregs to slots they're being spilled to.+ -> LiveInstr instr+ -> SpillM [LiveInstr instr]++regSpill_instr _ _ li@(LiveInstr _ Nothing)+ = do return [li]++regSpill_instr platform regSlotMap+ (LiveInstr instr (Just _))+ = do+ -- work out which regs are read and written in this instr+ let RU rlRead rlWritten = regUsageOfInstr platform instr++ -- sometimes a register is listed as being read more than once,+ -- nub this so we don't end up inserting two lots of spill code.+ let rsRead_ = nub rlRead+ let rsWritten_ = nub rlWritten++ -- if a reg is modified, it appears in both lists, want to undo this..+ let rsRead = rsRead_ \\ rsWritten_+ let rsWritten = rsWritten_ \\ rsRead_+ let rsModify = intersect rsRead_ rsWritten_++ -- work out if any of the regs being used are currently being spilled.+ let rsSpillRead = filter (\r -> elemUFM r regSlotMap) rsRead+ let rsSpillWritten = filter (\r -> elemUFM r regSlotMap) rsWritten+ let rsSpillModify = filter (\r -> elemUFM r regSlotMap) rsModify++ -- rewrite the instr and work out spill code.+ (instr1, prepost1) <- mapAccumLM (spillRead regSlotMap) instr rsSpillRead+ (instr2, prepost2) <- mapAccumLM (spillWrite regSlotMap) instr1 rsSpillWritten+ (instr3, prepost3) <- mapAccumLM (spillModify regSlotMap) instr2 rsSpillModify++ let (mPrefixes, mPostfixes) = unzip (prepost1 ++ prepost2 ++ prepost3)+ let prefixes = concat mPrefixes+ let postfixes = concat mPostfixes++ -- final code+ let instrs' = prefixes+ ++ [LiveInstr instr3 Nothing]+ ++ postfixes++ return $ instrs'+++-- | Add a RELOAD met a instruction to load a value for an instruction that+-- writes to a vreg that is being spilled.+spillRead+ :: Instruction instr+ => UniqFM Int+ -> instr+ -> Reg+ -> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))++spillRead regSlotMap instr reg+ | Just slot <- lookupUFM regSlotMap reg+ = do (instr', nReg) <- patchInstr reg instr++ modify $ \s -> s+ { stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 0, 1) }++ return ( instr'+ , ( [LiveInstr (RELOAD slot nReg) Nothing]+ , []) )++ | otherwise = panic "RegSpill.spillRead: no slot defined for spilled reg"+++-- | Add a SPILL meta instruction to store a value for an instruction that+-- writes to a vreg that is being spilled.+spillWrite+ :: Instruction instr+ => UniqFM Int+ -> instr+ -> Reg+ -> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))++spillWrite regSlotMap instr reg+ | Just slot <- lookupUFM regSlotMap reg+ = do (instr', nReg) <- patchInstr reg instr++ modify $ \s -> s+ { stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 1, 0) }++ return ( instr'+ , ( []+ , [LiveInstr (SPILL nReg slot) Nothing]))++ | otherwise = panic "RegSpill.spillWrite: no slot defined for spilled reg"+++-- | Add both RELOAD and SPILL meta instructions for an instruction that+-- both reads and writes to a vreg that is being spilled.+spillModify+ :: Instruction instr+ => UniqFM Int+ -> instr+ -> Reg+ -> SpillM (instr, ([LiveInstr instr'], [LiveInstr instr']))++spillModify regSlotMap instr reg+ | Just slot <- lookupUFM regSlotMap reg+ = do (instr', nReg) <- patchInstr reg instr++ modify $ \s -> s+ { stateSpillSL = addToUFM_C accSpillSL (stateSpillSL s) reg (reg, 1, 1) }++ return ( instr'+ , ( [LiveInstr (RELOAD slot nReg) Nothing]+ , [LiveInstr (SPILL nReg slot) Nothing]))++ | otherwise = panic "RegSpill.spillModify: no slot defined for spilled reg"+++-- | Rewrite uses of this virtual reg in an instr to use a different+-- virtual reg.+patchInstr+ :: Instruction instr+ => Reg -> instr -> SpillM (instr, Reg)++patchInstr reg instr+ = do nUnique <- newUnique++ -- The register we're rewriting is suppoed to be virtual.+ -- If it's not then something has gone horribly wrong.+ let nReg+ = case reg of+ RegVirtual vr+ -> RegVirtual (renameVirtualReg nUnique vr)++ RegReal{}+ -> panic "RegAlloc.Graph.Spill.patchIntr: not patching real reg"++ let instr' = patchReg1 reg nReg instr+ return (instr', nReg)+++patchReg1+ :: Instruction instr+ => Reg -> Reg -> instr -> instr++patchReg1 old new instr+ = let patchF r+ | r == old = new+ | otherwise = r+ in patchRegsOfInstr instr patchF+++-- Spiller monad --------------------------------------------------------------+-- | State monad for the spill code generator.+type SpillM a+ = State SpillS a++-- | Spill code generator state.+data SpillS+ = SpillS+ { -- | Unique supply for generating fresh vregs.+ stateUS :: UniqSupply++ -- | Spilled vreg vs the number of times it was loaded, stored.+ , stateSpillSL :: UniqFM (Reg, Int, Int) }+++-- | Create a new spiller state.+initSpillS :: UniqSupply -> SpillS+initSpillS uniqueSupply+ = SpillS+ { stateUS = uniqueSupply+ , stateSpillSL = emptyUFM }+++-- | Allocate a new unique in the spiller monad.+newUnique :: SpillM Unique+newUnique+ = do us <- gets stateUS+ case takeUniqFromSupply us of+ (uniq, us')+ -> do modify $ \s -> s { stateUS = us' }+ return uniq+++-- | Add a spill/reload count to a stats record for a register.+accSpillSL :: (Reg, Int, Int) -> (Reg, Int, Int) -> (Reg, Int, Int)+accSpillSL (r1, s1, l1) (_, s2, l2)+ = (r1, s1 + s2, l1 + l2)+++-- Spiller stats --------------------------------------------------------------+-- | Spiller statistics.+-- Tells us what registers were spilled.+data SpillStats+ = SpillStats+ { spillStoreLoad :: UniqFM (Reg, Int, Int) }+++-- | Extract spiller statistics from the spiller state.+makeSpillStats :: SpillS -> SpillStats+makeSpillStats s+ = SpillStats+ { spillStoreLoad = stateSpillSL s }+++instance Outputable SpillStats where+ ppr stats+ = pprUFM (spillStoreLoad stats)+ (vcat . map (\(r, s, l) -> ppr r <+> int s <+> int l))
+ nativeGen/RegAlloc/Graph/SpillClean.hs view
@@ -0,0 +1,612 @@++-- | Clean out unneeded spill\/reload instructions.+--+-- Handling of join points+-- ~~~~~~~~~~~~~~~~~~~~~~~+--+-- B1: B2:+-- ... ...+-- RELOAD SLOT(0), %r1 RELOAD SLOT(0), %r1+-- ... A ... ... B ...+-- jump B3 jump B3+--+-- B3: ... C ...+-- RELOAD SLOT(0), %r1+-- ...+--+-- The Plan+-- ~~~~~~~~+-- As long as %r1 hasn't been written to in A, B or C then we don't need+-- the reload in B3.+--+-- What we really care about here is that on the entry to B3, %r1 will+-- always have the same value that is in SLOT(0) (ie, %r1 is _valid_)+--+-- This also works if the reloads in B1\/B2 were spills instead, because+-- spilling %r1 to a slot makes that slot have the same value as %r1.+--+module RegAlloc.Graph.SpillClean (+ cleanSpills+) where+import RegAlloc.Liveness+import Instruction+import Reg++import BlockId+import Hoopl+import Cmm+import UniqSet+import UniqFM+import Unique+import State+import Outputable+import Platform++import Data.List+import Data.Maybe+import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet+++-- | The identification number of a spill slot.+-- A value is stored in a spill slot when we don't have a free+-- register to hold it.+type Slot = Int+++-- | Clean out unneeded spill\/reloads from this top level thing.+cleanSpills+ :: Instruction instr+ => Platform+ -> LiveCmmDecl statics instr+ -> LiveCmmDecl statics instr++cleanSpills platform cmm+ = evalState (cleanSpin platform 0 cmm) initCleanS+++-- | Do one pass of cleaning.+cleanSpin+ :: Instruction instr+ => Platform+ -> Int -- ^ Iteration number for the cleaner.+ -> LiveCmmDecl statics instr -- ^ Liveness annotated code to clean.+ -> CleanM (LiveCmmDecl statics instr)++cleanSpin platform spinCount code+ = do+ -- Initialise count of cleaned spill and reload instructions.+ modify $ \s -> s+ { sCleanedSpillsAcc = 0+ , sCleanedReloadsAcc = 0+ , sReloadedBy = emptyUFM }++ code_forward <- mapBlockTopM (cleanBlockForward platform) code+ code_backward <- cleanTopBackward code_forward++ -- During the cleaning of each block we collected information about+ -- what regs were valid across each jump. Based on this, work out+ -- whether it will be safe to erase reloads after join points for+ -- the next pass.+ collateJoinPoints++ -- Remember how many spill and reload instructions we cleaned in this pass.+ spills <- gets sCleanedSpillsAcc+ reloads <- gets sCleanedReloadsAcc+ modify $ \s -> s+ { sCleanedCount = (spills, reloads) : sCleanedCount s }++ -- If nothing was cleaned in this pass or the last one+ -- then we're done and it's time to bail out.+ cleanedCount <- gets sCleanedCount+ if take 2 cleanedCount == [(0, 0), (0, 0)]+ then return code++ -- otherwise go around again+ else cleanSpin platform (spinCount + 1) code_backward+++-------------------------------------------------------------------------------+-- | Clean out unneeded reload instructions,+-- while walking forward over the code.+cleanBlockForward+ :: Instruction instr+ => Platform+ -> LiveBasicBlock instr+ -> CleanM (LiveBasicBlock instr)++cleanBlockForward platform (BasicBlock blockId instrs)+ = do+ -- See if we have a valid association for the entry to this block.+ jumpValid <- gets sJumpValid+ let assoc = case lookupUFM jumpValid blockId of+ Just assoc -> assoc+ Nothing -> emptyAssoc++ instrs_reload <- cleanForward platform blockId assoc [] instrs+ return $ BasicBlock blockId instrs_reload++++-- | Clean out unneeded reload instructions.+--+-- Walking forwards across the code+-- On a reload, if we know a reg already has the same value as a slot+-- then we don't need to do the reload.+--+cleanForward+ :: Instruction instr+ => Platform+ -> BlockId -- ^ the block that we're currently in+ -> Assoc Store -- ^ two store locations are associated if+ -- they have the same value+ -> [LiveInstr instr] -- ^ acc+ -> [LiveInstr instr] -- ^ instrs to clean (in backwards order)+ -> CleanM [LiveInstr instr] -- ^ cleaned instrs (in forward order)++cleanForward _ _ _ acc []+ = return acc++-- Rewrite live range joins via spill slots to just a spill and a reg-reg move+-- hopefully the spill will be also be cleaned in the next pass+cleanForward platform blockId assoc acc (li1 : li2 : instrs)++ | LiveInstr (SPILL reg1 slot1) _ <- li1+ , LiveInstr (RELOAD slot2 reg2) _ <- li2+ , slot1 == slot2+ = do+ modify $ \s -> s { sCleanedReloadsAcc = sCleanedReloadsAcc s + 1 }+ cleanForward platform blockId assoc acc+ $ li1 : LiveInstr (mkRegRegMoveInstr platform reg1 reg2) Nothing+ : instrs++cleanForward platform blockId assoc acc (li@(LiveInstr i1 _) : instrs)+ | Just (r1, r2) <- takeRegRegMoveInstr i1+ = if r1 == r2+ -- Erase any left over nop reg reg moves while we're here+ -- this will also catch any nop moves that the previous case+ -- happens to add.+ then cleanForward platform blockId assoc acc instrs++ -- If r1 has the same value as some slots and we copy r1 to r2,+ -- then r2 is now associated with those slots instead+ else do let assoc' = addAssoc (SReg r1) (SReg r2)+ $ delAssoc (SReg r2)+ $ assoc++ cleanForward platform blockId assoc' (li : acc) instrs+++cleanForward platform blockId assoc acc (li : instrs)++ -- Update association due to the spill.+ | LiveInstr (SPILL reg slot) _ <- li+ = let assoc' = addAssoc (SReg reg) (SSlot slot)+ $ delAssoc (SSlot slot)+ $ assoc+ in cleanForward platform blockId assoc' (li : acc) instrs++ -- Clean a reload instr.+ | LiveInstr (RELOAD{}) _ <- li+ = do (assoc', mli) <- cleanReload platform blockId assoc li+ case mli of+ Nothing -> cleanForward platform blockId assoc' acc+ instrs++ Just li' -> cleanForward platform blockId assoc' (li' : acc)+ instrs++ -- Remember the association over a jump.+ | LiveInstr instr _ <- li+ , targets <- jumpDestsOfInstr instr+ , not $ null targets+ = do mapM_ (accJumpValid assoc) targets+ cleanForward platform blockId assoc (li : acc) instrs++ -- Writing to a reg changes its value.+ | LiveInstr instr _ <- li+ , RU _ written <- regUsageOfInstr platform instr+ = let assoc' = foldr delAssoc assoc (map SReg $ nub written)+ in cleanForward platform blockId assoc' (li : acc) instrs++++-- | Try and rewrite a reload instruction to something more pleasing+cleanReload+ :: Instruction instr+ => Platform+ -> BlockId+ -> Assoc Store+ -> LiveInstr instr+ -> CleanM (Assoc Store, Maybe (LiveInstr instr))++cleanReload platform blockId assoc li@(LiveInstr (RELOAD slot reg) _)++ -- If the reg we're reloading already has the same value as the slot+ -- then we can erase the instruction outright.+ | elemAssoc (SSlot slot) (SReg reg) assoc+ = do modify $ \s -> s { sCleanedReloadsAcc = sCleanedReloadsAcc s + 1 }+ return (assoc, Nothing)++ -- If we can find another reg with the same value as this slot then+ -- do a move instead of a reload.+ | Just reg2 <- findRegOfSlot assoc slot+ = do modify $ \s -> s { sCleanedReloadsAcc = sCleanedReloadsAcc s + 1 }++ let assoc' = addAssoc (SReg reg) (SReg reg2)+ $ delAssoc (SReg reg)+ $ assoc++ return ( assoc'+ , Just $ LiveInstr (mkRegRegMoveInstr platform reg2 reg) Nothing)++ -- Gotta keep this instr.+ | otherwise+ = do -- Update the association.+ let assoc'+ = addAssoc (SReg reg) (SSlot slot)+ -- doing the reload makes reg and slot the same value+ $ delAssoc (SReg reg)+ -- reg value changes on reload+ $ assoc++ -- Remember that this block reloads from this slot.+ accBlockReloadsSlot blockId slot++ return (assoc', Just li)++cleanReload _ _ _ _+ = panic "RegSpillClean.cleanReload: unhandled instr"+++-------------------------------------------------------------------------------+-- | Clean out unneeded spill instructions,+-- while walking backwards over the code.+--+-- If there were no reloads from a slot between a spill and the last one+-- then the slot was never read and we don't need the spill.+--+-- SPILL r0 -> s1+-- RELOAD s1 -> r2+-- SPILL r3 -> s1 <--- don't need this spill+-- SPILL r4 -> s1+-- RELOAD s1 -> r5+--+-- Maintain a set of+-- "slots which were spilled to but not reloaded from yet"+--+-- Walking backwards across the code:+-- a) On a reload from a slot, remove it from the set.+--+-- a) On a spill from a slot+-- If the slot is in set then we can erase the spill,+-- because it won't be reloaded from until after the next spill.+--+-- otherwise+-- keep the spill and add the slot to the set+--+-- TODO: This is mostly inter-block+-- we should really be updating the noReloads set as we cross jumps also.+--+-- TODO: generate noReloads from liveSlotsOnEntry+--+cleanTopBackward+ :: Instruction instr+ => LiveCmmDecl statics instr+ -> CleanM (LiveCmmDecl statics instr)++cleanTopBackward cmm+ = case cmm of+ CmmData{}+ -> return cmm++ CmmProc info label live sccs+ | LiveInfo _ _ _ liveSlotsOnEntry <- info+ -> do sccs' <- mapM (mapSCCM (cleanBlockBackward liveSlotsOnEntry)) sccs+ return $ CmmProc info label live sccs'+++cleanBlockBackward+ :: Instruction instr+ => BlockMap IntSet+ -> LiveBasicBlock instr+ -> CleanM (LiveBasicBlock instr)++cleanBlockBackward liveSlotsOnEntry (BasicBlock blockId instrs)+ = do instrs_spill <- cleanBackward liveSlotsOnEntry emptyUniqSet [] instrs+ return $ BasicBlock blockId instrs_spill++++cleanBackward+ :: Instruction instr+ => BlockMap IntSet -- ^ Slots live on entry to each block+ -> UniqSet Int -- ^ Slots that have been spilled, but not reloaded from+ -> [LiveInstr instr] -- ^ acc+ -> [LiveInstr instr] -- ^ Instrs to clean (in forwards order)+ -> CleanM [LiveInstr instr] -- ^ Cleaned instrs (in backwards order)++cleanBackward liveSlotsOnEntry noReloads acc lis+ = do reloadedBy <- gets sReloadedBy+ cleanBackward' liveSlotsOnEntry reloadedBy noReloads acc lis+++cleanBackward'+ :: Instruction instr+ => BlockMap IntSet+ -> UniqFM [BlockId]+ -> UniqSet Int+ -> [LiveInstr instr]+ -> [LiveInstr instr]+ -> State CleanS [LiveInstr instr]++cleanBackward' _ _ _ acc []+ = return acc++cleanBackward' liveSlotsOnEntry reloadedBy noReloads acc (li : instrs)++ -- If nothing ever reloads from this slot then we don't need the spill.+ | LiveInstr (SPILL _ slot) _ <- li+ , Nothing <- lookupUFM reloadedBy (SSlot slot)+ = do modify $ \s -> s { sCleanedSpillsAcc = sCleanedSpillsAcc s + 1 }+ cleanBackward liveSlotsOnEntry noReloads acc instrs++ | LiveInstr (SPILL _ slot) _ <- li+ = if elementOfUniqSet slot noReloads++ -- We can erase this spill because the slot won't be read until+ -- after the next one+ then do+ modify $ \s -> s { sCleanedSpillsAcc = sCleanedSpillsAcc s + 1 }+ cleanBackward liveSlotsOnEntry noReloads acc instrs++ else do+ -- This slot is being spilled to, but we haven't seen any reloads yet.+ let noReloads' = addOneToUniqSet noReloads slot+ cleanBackward liveSlotsOnEntry noReloads' (li : acc) instrs++ -- if we reload from a slot then it's no longer unused+ | LiveInstr (RELOAD slot _) _ <- li+ , noReloads' <- delOneFromUniqSet noReloads slot+ = cleanBackward liveSlotsOnEntry noReloads' (li : acc) instrs++ -- If a slot is live in a jump target then assume it's reloaded there.+ --+ -- TODO: A real dataflow analysis would do a better job here.+ -- If the target block _ever_ used the slot then we assume+ -- it always does, but if those reloads are cleaned the slot+ -- liveness map doesn't get updated.+ | LiveInstr instr _ <- li+ , targets <- jumpDestsOfInstr instr+ = do+ let slotsReloadedByTargets+ = IntSet.unions+ $ catMaybes+ $ map (flip mapLookup liveSlotsOnEntry)+ $ targets++ let noReloads'+ = foldl' delOneFromUniqSet noReloads+ $ IntSet.toList slotsReloadedByTargets++ cleanBackward liveSlotsOnEntry noReloads' (li : acc) instrs++ -- some other instruction+ | otherwise+ = cleanBackward liveSlotsOnEntry noReloads (li : acc) instrs+++-- | Combine the associations from all the inward control flow edges.+--+collateJoinPoints :: CleanM ()+collateJoinPoints+ = modify $ \s -> s+ { sJumpValid = mapUFM intersects (sJumpValidAcc s)+ , sJumpValidAcc = emptyUFM }++intersects :: [Assoc Store] -> Assoc Store+intersects [] = emptyAssoc+intersects assocs = foldl1' intersectAssoc assocs+++-- | See if we have a reg with the same value as this slot in the association table.+findRegOfSlot :: Assoc Store -> Int -> Maybe Reg+findRegOfSlot assoc slot+ | close <- closeAssoc (SSlot slot) assoc+ , Just (SReg reg) <- find isStoreReg $ nonDetEltsUniqSet close+ -- See Note [Unique Determinism and code generation]+ = Just reg++ | otherwise+ = Nothing+++-------------------------------------------------------------------------------+-- | Cleaner monad.+type CleanM+ = State CleanS++-- | Cleaner state.+data CleanS+ = CleanS+ { -- | Regs which are valid at the start of each block.+ sJumpValid :: UniqFM (Assoc Store)++ -- | Collecting up what regs were valid across each jump.+ -- in the next pass we can collate these and write the results+ -- to sJumpValid.+ , sJumpValidAcc :: UniqFM [Assoc Store]++ -- | Map of (slot -> blocks which reload from this slot)+ -- used to decide if whether slot spilled to will ever be+ -- reloaded from on this path.+ , sReloadedBy :: UniqFM [BlockId]++ -- | Spills and reloads cleaned each pass (latest at front)+ , sCleanedCount :: [(Int, Int)]++ -- | Spills and reloads that have been cleaned in this pass so far.+ , sCleanedSpillsAcc :: Int+ , sCleanedReloadsAcc :: Int }+++-- | Construct the initial cleaner state.+initCleanS :: CleanS+initCleanS+ = CleanS+ { sJumpValid = emptyUFM+ , sJumpValidAcc = emptyUFM++ , sReloadedBy = emptyUFM++ , sCleanedCount = []++ , sCleanedSpillsAcc = 0+ , sCleanedReloadsAcc = 0 }+++-- | Remember the associations before a jump.+accJumpValid :: Assoc Store -> BlockId -> CleanM ()+accJumpValid assocs target+ = modify $ \s -> s {+ sJumpValidAcc = addToUFM_C (++)+ (sJumpValidAcc s)+ target+ [assocs] }+++accBlockReloadsSlot :: BlockId -> Slot -> CleanM ()+accBlockReloadsSlot blockId slot+ = modify $ \s -> s {+ sReloadedBy = addToUFM_C (++)+ (sReloadedBy s)+ (SSlot slot)+ [blockId] }+++-------------------------------------------------------------------------------+-- A store location can be a stack slot or a register+data Store+ = SSlot Int+ | SReg Reg+++-- | Check if this is a reg store.+isStoreReg :: Store -> Bool+isStoreReg ss+ = case ss of+ SSlot _ -> False+ SReg _ -> True+++-- Spill cleaning is only done once all virtuals have been allocated to realRegs+instance Uniquable Store where+ getUnique (SReg r)+ | RegReal (RealRegSingle i) <- r+ = mkRegSingleUnique i++ | RegReal (RealRegPair r1 r2) <- r+ = mkRegPairUnique (r1 * 65535 + r2)++ | otherwise+ = error $ "RegSpillClean.getUnique: found virtual reg during spill clean,"+ ++ "only real regs expected."++ getUnique (SSlot i) = mkRegSubUnique i -- [SLPJ] I hope "SubUnique" is ok+++instance Outputable Store where+ ppr (SSlot i) = text "slot" <> int i+ ppr (SReg r) = ppr r+++-------------------------------------------------------------------------------+-- Association graphs.+-- In the spill cleaner, two store locations are associated if they are known+-- to hold the same value.+--+type Assoc a = UniqFM (UniqSet a)++-- | An empty association+emptyAssoc :: Assoc a+emptyAssoc = emptyUFM+++-- | Add an association between these two things.+addAssoc :: Uniquable a+ => a -> a -> Assoc a -> Assoc a++addAssoc a b m+ = let m1 = addToUFM_C unionUniqSets m a (unitUniqSet b)+ m2 = addToUFM_C unionUniqSets m1 b (unitUniqSet a)+ in m2+++-- | Delete all associations to a node.+delAssoc :: (Uniquable a)+ => a -> Assoc a -> Assoc a++delAssoc a m+ | Just aSet <- lookupUFM m a+ , m1 <- delFromUFM m a+ = nonDetFoldUniqSet (\x m -> delAssoc1 x a m) m1 aSet+ -- It's OK to use nonDetFoldUFM here because deletion is commutative++ | otherwise = m+++-- | Delete a single association edge (a -> b).+delAssoc1 :: Uniquable a+ => a -> a -> Assoc a -> Assoc a++delAssoc1 a b m+ | Just aSet <- lookupUFM m a+ = addToUFM m a (delOneFromUniqSet aSet b)++ | otherwise = m+++-- | Check if these two things are associated.+elemAssoc :: (Uniquable a)+ => a -> a -> Assoc a -> Bool++elemAssoc a b m+ = elementOfUniqSet b (closeAssoc a m)+++-- | Find the refl. trans. closure of the association from this point.+closeAssoc :: (Uniquable a)+ => a -> Assoc a -> UniqSet a++closeAssoc a assoc+ = closeAssoc' assoc emptyUniqSet (unitUniqSet a)+ where+ closeAssoc' assoc visited toVisit+ = case nonDetEltsUniqSet toVisit of+ -- See Note [Unique Determinism and code generation]++ -- nothing else to visit, we're done+ [] -> visited++ (x:_)+ -- we've already seen this node+ | elementOfUniqSet x visited+ -> closeAssoc' assoc visited (delOneFromUniqSet toVisit x)++ -- haven't seen this node before,+ -- remember to visit all its neighbors+ | otherwise+ -> let neighbors+ = case lookupUFM assoc x of+ Nothing -> emptyUniqSet+ Just set -> set++ in closeAssoc' assoc+ (addOneToUniqSet visited x)+ (unionUniqSets toVisit neighbors)++-- | Intersect two associations.+intersectAssoc :: Assoc a -> Assoc a -> Assoc a+intersectAssoc a b+ = intersectUFM_C (intersectUniqSets) a b+
+ nativeGen/RegAlloc/Graph/SpillCost.hs view
@@ -0,0 +1,291 @@++module RegAlloc.Graph.SpillCost (+ SpillCostRecord,+ plusSpillCostRecord,+ pprSpillCostRecord,++ SpillCostInfo,+ zeroSpillCostInfo,+ plusSpillCostInfo,++ slurpSpillCostInfo,+ chooseSpill,++ lifeMapFromSpillCostInfo+) where+import RegAlloc.Liveness+import Instruction+import RegClass+import Reg++import GraphBase++import Hoopl (mapLookup)+import Cmm+import UniqFM+import UniqSet+import Digraph (flattenSCCs)+import Outputable+import Platform+import State++import Data.List (nub, minimumBy)+import Data.Maybe+++-- | Records the expected cost to spill some regster.+type SpillCostRecord+ = ( VirtualReg -- register name+ , Int -- number of writes to this reg+ , Int -- number of reads from this reg+ , Int) -- number of instrs this reg was live on entry to+++-- | Map of `SpillCostRecord`+type SpillCostInfo+ = UniqFM SpillCostRecord+++-- | An empty map of spill costs.+zeroSpillCostInfo :: SpillCostInfo+zeroSpillCostInfo = emptyUFM+++-- | Add two spill cost infos.+plusSpillCostInfo :: SpillCostInfo -> SpillCostInfo -> SpillCostInfo+plusSpillCostInfo sc1 sc2+ = plusUFM_C plusSpillCostRecord sc1 sc2+++-- | Add two spill cost records.+plusSpillCostRecord :: SpillCostRecord -> SpillCostRecord -> SpillCostRecord+plusSpillCostRecord (r1, a1, b1, c1) (r2, a2, b2, c2)+ | r1 == r2 = (r1, a1 + a2, b1 + b2, c1 + c2)+ | otherwise = error "RegSpillCost.plusRegInt: regs don't match"+++-- | Slurp out information used for determining spill costs.+--+-- For each vreg, the number of times it was written to, read from,+-- and the number of instructions it was live on entry to (lifetime)+--+slurpSpillCostInfo :: (Outputable instr, Instruction instr)+ => Platform+ -> LiveCmmDecl statics instr+ -> SpillCostInfo++slurpSpillCostInfo platform cmm+ = execState (countCmm cmm) zeroSpillCostInfo+ where+ countCmm CmmData{} = return ()+ countCmm (CmmProc info _ _ sccs)+ = mapM_ (countBlock info)+ $ flattenSCCs sccs++ -- Lookup the regs that are live on entry to this block in+ -- the info table from the CmmProc.+ countBlock info (BasicBlock blockId instrs)+ | LiveInfo _ _ (Just blockLive) _ <- info+ , Just rsLiveEntry <- mapLookup blockId blockLive+ , rsLiveEntry_virt <- takeVirtuals rsLiveEntry+ = countLIs rsLiveEntry_virt instrs++ | otherwise+ = error "RegAlloc.SpillCost.slurpSpillCostInfo: bad block"++ countLIs _ []+ = return ()++ -- Skip over comment and delta pseudo instrs.+ countLIs rsLive (LiveInstr instr Nothing : lis)+ | isMetaInstr instr+ = countLIs rsLive lis++ | otherwise+ = pprPanic "RegSpillCost.slurpSpillCostInfo"+ $ text "no liveness information on instruction " <> ppr instr++ countLIs rsLiveEntry (LiveInstr instr (Just live) : lis)+ = do+ -- Increment the lifetime counts for regs live on entry to this instr.+ mapM_ incLifetime $ nonDetEltsUniqSet rsLiveEntry+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]++ -- Increment counts for what regs were read/written from.+ let (RU read written) = regUsageOfInstr platform instr+ mapM_ incUses $ catMaybes $ map takeVirtualReg $ nub read+ mapM_ incDefs $ catMaybes $ map takeVirtualReg $ nub written++ -- Compute liveness for entry to next instruction.+ let liveDieRead_virt = takeVirtuals (liveDieRead live)+ let liveDieWrite_virt = takeVirtuals (liveDieWrite live)+ let liveBorn_virt = takeVirtuals (liveBorn live)++ let rsLiveAcross+ = rsLiveEntry `minusUniqSet` liveDieRead_virt++ let rsLiveNext+ = (rsLiveAcross `unionUniqSets` liveBorn_virt)+ `minusUniqSet` liveDieWrite_virt++ countLIs rsLiveNext lis++ incDefs reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 1, 0, 0)+ incUses reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 1, 0)+ incLifetime reg = modify $ \s -> addToUFM_C plusSpillCostRecord s reg (reg, 0, 0, 1)+++-- | Take all the virtual registers from this set.+takeVirtuals :: UniqSet Reg -> UniqSet VirtualReg+takeVirtuals set = mkUniqSet+ [ vr | RegVirtual vr <- nonDetEltsUniqSet set ]+ -- See Note [Unique Determinism and code generation]+++-- | Choose a node to spill from this graph+chooseSpill+ :: SpillCostInfo+ -> Graph VirtualReg RegClass RealReg+ -> VirtualReg++chooseSpill info graph+ = let cost = spillCost_length info graph+ node = minimumBy (\n1 n2 -> compare (cost $ nodeId n1) (cost $ nodeId n2))+ $ nonDetEltsUFM $ graphMap graph+ -- See Note [Unique Determinism and code generation]++ in nodeId node+++-------------------------------------------------------------------------------+-- | Chaitins spill cost function is:+--+-- cost = sum loadCost * freq (u) + sum storeCost * freq (d)+-- u <- uses (v) d <- defs (v)+--+-- There are no loops in our code at the momemnt, so we can set the freq's to 1.+--+-- If we don't have live range splitting then Chaitins function performs badly+-- if we have lots of nested live ranges and very few registers.+--+-- v1 v2 v3+-- def v1 .+-- use v1 .+-- def v2 . .+-- def v3 . . .+-- use v1 . . .+-- use v3 . . .+-- use v2 . .+-- use v1 .+--+-- defs uses degree cost+-- v1: 1 3 3 1.5+-- v2: 1 2 3 1.0+-- v3: 1 1 3 0.666+--+-- v3 has the lowest cost, but if we only have 2 hardregs and we insert+-- spill code for v3 then this isn't going to improve the colorability of+-- the graph.+--+-- When compiling SHA1, which as very long basic blocks and some vregs+-- with very long live ranges the allocator seems to try and spill from+-- the inside out and eventually run out of stack slots.+--+-- Without live range splitting, its's better to spill from the outside+-- in so set the cost of very long live ranges to zero+--+{-+spillCost_chaitin+ :: SpillCostInfo+ -> Graph Reg RegClass Reg+ -> Reg+ -> Float++spillCost_chaitin info graph reg+ -- Spilling a live range that only lives for 1 instruction+ -- isn't going to help us at all - and we definitely want to avoid+ -- trying to re-spill previously inserted spill code.+ | lifetime <= 1 = 1/0++ -- It's unlikely that we'll find a reg for a live range this long+ -- better to spill it straight up and not risk trying to keep it around+ -- and have to go through the build/color cycle again.+ | lifetime > allocatableRegsInClass (regClass reg) * 10+ = 0++ -- Otherwise revert to chaitin's regular cost function.+ | otherwise = fromIntegral (uses + defs)+ / fromIntegral (nodeDegree graph reg)+ where (_, defs, uses, lifetime)+ = fromMaybe (reg, 0, 0, 0) $ lookupUFM info reg+-}++-- Just spill the longest live range.+spillCost_length+ :: SpillCostInfo+ -> Graph VirtualReg RegClass RealReg+ -> VirtualReg+ -> Float++spillCost_length info _ reg+ | lifetime <= 1 = 1/0+ | otherwise = 1 / fromIntegral lifetime+ where (_, _, _, lifetime)+ = fromMaybe (reg, 0, 0, 0)+ $ lookupUFM info reg+++-- | Extract a map of register lifetimes from a `SpillCostInfo`.+lifeMapFromSpillCostInfo :: SpillCostInfo -> UniqFM (VirtualReg, Int)+lifeMapFromSpillCostInfo info+ = listToUFM+ $ map (\(r, _, _, life) -> (r, (r, life)))+ $ nonDetEltsUFM info+ -- See Note [Unique Determinism and code generation]+++-- | Determine the degree (number of neighbors) of this node which+-- have the same class.+nodeDegree+ :: (VirtualReg -> RegClass)+ -> Graph VirtualReg RegClass RealReg+ -> VirtualReg+ -> Int++nodeDegree classOfVirtualReg graph reg+ | Just node <- lookupUFM (graphMap graph) reg++ , virtConflicts+ <- length+ $ filter (\r -> classOfVirtualReg r == classOfVirtualReg reg)+ $ nonDetEltsUniqSet+ -- See Note [Unique Determinism and code generation]+ $ nodeConflicts node++ = virtConflicts + sizeUniqSet (nodeExclusions node)++ | otherwise+ = 0+++-- | Show a spill cost record, including the degree from the graph+-- and final calulated spill cost.+pprSpillCostRecord+ :: (VirtualReg -> RegClass)+ -> (Reg -> SDoc)+ -> Graph VirtualReg RegClass RealReg+ -> SpillCostRecord+ -> SDoc++pprSpillCostRecord regClass pprReg graph (reg, uses, defs, life)+ = hsep+ [ pprReg (RegVirtual reg)+ , ppr uses+ , ppr defs+ , ppr life+ , ppr $ nodeDegree regClass graph reg+ , text $ show $ (fromIntegral (uses + defs)+ / fromIntegral (nodeDegree regClass graph reg) :: Float) ]+
+ nativeGen/RegAlloc/Graph/Stats.hs view
@@ -0,0 +1,348 @@+{-# LANGUAGE BangPatterns, CPP #-}++-- | Carries interesting info for debugging / profiling of the+-- graph coloring register allocator.+module RegAlloc.Graph.Stats (+ RegAllocStats (..),++ pprStats,+ pprStatsSpills,+ pprStatsLifetimes,+ pprStatsConflict,+ pprStatsLifeConflict,++ countSRMs, addSRM+) where++#include "nativeGen/NCG.h"++import qualified GraphColor as Color+import RegAlloc.Liveness+import RegAlloc.Graph.Spill+import RegAlloc.Graph.SpillCost+import RegAlloc.Graph.TrivColorable+import Instruction+import RegClass+import Reg+import TargetReg++import PprCmm()+import Outputable+import UniqFM+import UniqSet+import State++import Data.List+++-- | Holds interesting statistics from the register allocator.+data RegAllocStats statics instr++ -- Information about the initial conflict graph.+ = RegAllocStatsStart+ { -- | Initial code, with liveness.+ raLiveCmm :: [LiveCmmDecl statics instr]++ -- | The initial, uncolored graph.+ , raGraph :: Color.Graph VirtualReg RegClass RealReg++ -- | Information to help choose which regs to spill.+ , raSpillCosts :: SpillCostInfo }+++ -- Information about an intermediate graph.+ -- This is one that we couldn't color, so had to insert spill code+ -- instruction stream.+ | RegAllocStatsSpill+ { -- | Code we tried to allocate registers for.+ raCode :: [LiveCmmDecl statics instr]++ -- | Partially colored graph.+ , raGraph :: Color.Graph VirtualReg RegClass RealReg++ -- | The regs that were coalesced.+ , raCoalesced :: UniqFM VirtualReg++ -- | Spiller stats.+ , raSpillStats :: SpillStats++ -- | Number of instructions each reg lives for.+ , raSpillCosts :: SpillCostInfo++ -- | Code with spill instructions added.+ , raSpilled :: [LiveCmmDecl statics instr] }+++ -- a successful coloring+ | RegAllocStatsColored+ { -- | Code we tried to allocate registers for.+ raCode :: [LiveCmmDecl statics instr]++ -- | Uncolored graph.+ , raGraph :: Color.Graph VirtualReg RegClass RealReg++ -- | Coalesced and colored graph.+ , raGraphColored :: Color.Graph VirtualReg RegClass RealReg++ -- | Regs that were coalesced.+ , raCoalesced :: UniqFM VirtualReg++ -- | Code with coalescings applied.+ , raCodeCoalesced :: [LiveCmmDecl statics instr]++ -- | Code with vregs replaced by hregs.+ , raPatched :: [LiveCmmDecl statics instr]++ -- | Code with unneeded spill\/reloads cleaned out.+ , raSpillClean :: [LiveCmmDecl statics instr]++ -- | Final code.+ , raFinal :: [NatCmmDecl statics instr]++ -- | Spill\/reload\/reg-reg moves present in this code.+ , raSRMs :: (Int, Int, Int) }+++instance (Outputable statics, Outputable instr)+ => Outputable (RegAllocStats statics instr) where++ ppr (s@RegAllocStatsStart{}) = sdocWithPlatform $ \platform ->+ text "# Start"+ $$ text "# Native code with liveness information."+ $$ ppr (raLiveCmm s)+ $$ text ""+ $$ text "# Initial register conflict graph."+ $$ Color.dotGraph+ (targetRegDotColor platform)+ (trivColorable platform+ (targetVirtualRegSqueeze platform)+ (targetRealRegSqueeze platform))+ (raGraph s)+++ ppr (s@RegAllocStatsSpill{}) =+ text "# Spill"++ $$ text "# Code with liveness information."+ $$ ppr (raCode s)+ $$ text ""++ $$ (if (not $ isNullUFM $ raCoalesced s)+ then text "# Registers coalesced."+ $$ pprUFMWithKeys (raCoalesced s) (vcat . map ppr)+ $$ text ""+ else empty)++ $$ text "# Spills inserted."+ $$ ppr (raSpillStats s)+ $$ text ""++ $$ text "# Code with spills inserted."+ $$ ppr (raSpilled s)+++ ppr (s@RegAllocStatsColored { raSRMs = (spills, reloads, moves) })+ = sdocWithPlatform $ \platform ->+ text "# Colored"++ $$ text "# Code with liveness information."+ $$ ppr (raCode s)+ $$ text ""++ $$ text "# Register conflict graph (colored)."+ $$ Color.dotGraph+ (targetRegDotColor platform)+ (trivColorable platform+ (targetVirtualRegSqueeze platform)+ (targetRealRegSqueeze platform))+ (raGraphColored s)+ $$ text ""++ $$ (if (not $ isNullUFM $ raCoalesced s)+ then text "# Registers coalesced."+ $$ pprUFMWithKeys (raCoalesced s) (vcat . map ppr)+ $$ text ""+ else empty)++ $$ text "# Native code after coalescings applied."+ $$ ppr (raCodeCoalesced s)+ $$ text ""++ $$ text "# Native code after register allocation."+ $$ ppr (raPatched s)+ $$ text ""++ $$ text "# Clean out unneeded spill/reloads."+ $$ ppr (raSpillClean s)+ $$ text ""++ $$ text "# Final code, after rewriting spill/rewrite pseudo instrs."+ $$ ppr (raFinal s)+ $$ text ""+ $$ text "# Score:"+ $$ (text "# spills inserted: " <> int spills)+ $$ (text "# reloads inserted: " <> int reloads)+ $$ (text "# reg-reg moves remaining: " <> int moves)+ $$ text ""+++-- | Do all the different analysis on this list of RegAllocStats+pprStats+ :: [RegAllocStats statics instr]+ -> Color.Graph VirtualReg RegClass RealReg+ -> SDoc++pprStats stats graph+ = let outSpills = pprStatsSpills stats+ outLife = pprStatsLifetimes stats+ outConflict = pprStatsConflict stats+ outScatter = pprStatsLifeConflict stats graph++ in vcat [outSpills, outLife, outConflict, outScatter]+++-- | Dump a table of how many spill loads \/ stores were inserted for each vreg.+pprStatsSpills+ :: [RegAllocStats statics instr] -> SDoc++pprStatsSpills stats+ = let+ finals = [ s | s@RegAllocStatsColored{} <- stats]++ -- sum up how many stores\/loads\/reg-reg-moves were left in the code+ total = foldl' addSRM (0, 0, 0)+ $ map raSRMs finals++ in ( text "-- spills-added-total"+ $$ text "-- (stores, loads, reg_reg_moves_remaining)"+ $$ ppr total+ $$ text "")+++-- | Dump a table of how long vregs tend to live for in the initial code.+pprStatsLifetimes+ :: [RegAllocStats statics instr] -> SDoc++pprStatsLifetimes stats+ = let info = foldl' plusSpillCostInfo zeroSpillCostInfo+ [ raSpillCosts s+ | s@RegAllocStatsStart{} <- stats ]++ lifeBins = binLifetimeCount $ lifeMapFromSpillCostInfo info++ in ( text "-- vreg-population-lifetimes"+ $$ text "-- (instruction_count, number_of_vregs_that_lived_that_long)"+ $$ pprUFM lifeBins (vcat . map ppr)+ $$ text "\n")+++binLifetimeCount :: UniqFM (VirtualReg, Int) -> UniqFM (Int, Int)+binLifetimeCount fm+ = let lifes = map (\l -> (l, (l, 1)))+ $ map snd+ $ nonDetEltsUFM fm+ -- See Note [Unique Determinism and code generation]++ in addListToUFM_C+ (\(l1, c1) (_, c2) -> (l1, c1 + c2))+ emptyUFM+ lifes+++-- | Dump a table of how many conflicts vregs tend to have in the initial code.+pprStatsConflict+ :: [RegAllocStats statics instr] -> SDoc++pprStatsConflict stats+ = let confMap = foldl' (plusUFM_C (\(c1, n1) (_, n2) -> (c1, n1 + n2)))+ emptyUFM+ $ map Color.slurpNodeConflictCount+ [ raGraph s | s@RegAllocStatsStart{} <- stats ]++ in ( text "-- vreg-conflicts"+ $$ text "-- (conflict_count, number_of_vregs_that_had_that_many_conflicts)"+ $$ pprUFM confMap (vcat . map ppr)+ $$ text "\n")+++-- | For every vreg, dump it's how many conflicts it has and its lifetime+-- good for making a scatter plot.+pprStatsLifeConflict+ :: [RegAllocStats statics instr]+ -> Color.Graph VirtualReg RegClass RealReg -- ^ global register conflict graph+ -> SDoc++pprStatsLifeConflict stats graph+ = let lifeMap = lifeMapFromSpillCostInfo+ $ foldl' plusSpillCostInfo zeroSpillCostInfo+ $ [ raSpillCosts s | s@RegAllocStatsStart{} <- stats ]++ scatter = map (\r -> let lifetime = case lookupUFM lifeMap r of+ Just (_, l) -> l+ Nothing -> 0+ Just node = Color.lookupNode graph r+ in parens $ hcat $ punctuate (text ", ")+ [ doubleQuotes $ ppr $ Color.nodeId node+ , ppr $ sizeUniqSet (Color.nodeConflicts node)+ , ppr $ lifetime ])+ $ map Color.nodeId+ $ nonDetEltsUFM+ -- See Note [Unique Determinism and code generation]+ $ Color.graphMap graph++ in ( text "-- vreg-conflict-lifetime"+ $$ text "-- (vreg, vreg_conflicts, vreg_lifetime)"+ $$ (vcat scatter)+ $$ text "\n")+++-- | Count spill/reload/reg-reg moves.+-- Lets us see how well the register allocator has done.+countSRMs+ :: Instruction instr+ => LiveCmmDecl statics instr -> (Int, Int, Int)++countSRMs cmm+ = execState (mapBlockTopM countSRM_block cmm) (0, 0, 0)+++countSRM_block+ :: Instruction instr+ => GenBasicBlock (LiveInstr instr)+ -> State (Int, Int, Int) (GenBasicBlock (LiveInstr instr))++countSRM_block (BasicBlock i instrs)+ = do instrs' <- mapM countSRM_instr instrs+ return $ BasicBlock i instrs'+++countSRM_instr+ :: Instruction instr+ => LiveInstr instr -> State (Int, Int, Int) (LiveInstr instr)++countSRM_instr li+ | LiveInstr SPILL{} _ <- li+ = do modify $ \(s, r, m) -> (s + 1, r, m)+ return li++ | LiveInstr RELOAD{} _ <- li+ = do modify $ \(s, r, m) -> (s, r + 1, m)+ return li++ | LiveInstr instr _ <- li+ , Just _ <- takeRegRegMoveInstr instr+ = do modify $ \(s, r, m) -> (s, r, m + 1)+ return li++ | otherwise+ = return li+++-- sigh..+addSRM :: (Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int)+addSRM (s1, r1, m1) (s2, r2, m2)+ = let !s = s1 + s2+ !r = r1 + r2+ !m = m1 + m2+ in (s, r, m)+
+ nativeGen/RegAlloc/Graph/TrivColorable.hs view
@@ -0,0 +1,283 @@+{-# LANGUAGE CPP #-}++module RegAlloc.Graph.TrivColorable (+ trivColorable,+)++where++#include "HsVersions.h"++import RegClass+import Reg++import GraphBase++import UniqSet+import Platform+import Panic++-- trivColorable ---------------------------------------------------------------++-- trivColorable function for the graph coloring allocator+--+-- This gets hammered by scanGraph during register allocation,+-- so needs to be fairly efficient.+--+-- NOTE: This only works for arcitectures with just RcInteger and RcDouble+-- (which are disjoint) ie. x86, x86_64 and ppc+--+-- The number of allocatable regs is hard coded in here so we can do+-- a fast comparison in trivColorable.+--+-- It's ok if these numbers are _less_ than the actual number of free+-- regs, but they can't be more or the register conflict+-- graph won't color.+--+-- If the graph doesn't color then the allocator will panic, but it won't+-- generate bad object code or anything nasty like that.+--+-- There is an allocatableRegsInClass :: RegClass -> Int, but doing+-- the unboxing is too slow for us here.+-- TODO: Is that still true? Could we use allocatableRegsInClass+-- without losing performance now?+--+-- Look at includes/stg/MachRegs.h to get the numbers.+--+++-- Disjoint registers ----------------------------------------------------------+--+-- The definition has been unfolded into individual cases for speed.+-- Each architecture has a different register setup, so we use a+-- different regSqueeze function for each.+--+accSqueeze+ :: Int+ -> Int+ -> (reg -> Int)+ -> UniqSet reg+ -> Int++accSqueeze count maxCount squeeze us = acc count (nonDetEltsUniqSet us)+ -- See Note [Unique Determinism and code generation]+ where acc count [] = count+ acc count _ | count >= maxCount = count+ acc count (r:rs) = acc (count + squeeze r) rs++{- Note [accSqueeze]+~~~~~~~~~~~~~~~~~~~~+BL 2007/09+Doing a nice fold over the UniqSet makes trivColorable use+32% of total compile time and 42% of total alloc when compiling SHA1.hs from darcs.+Therefore the UniqFM is made non-abstract and we use custom fold.++MS 2010/04+When converting UniqFM to use Data.IntMap, the fold cannot use UniqFM internal+representation any more. But it is imperative that the accSqueeze stops+the folding if the count gets greater or equal to maxCount. We thus convert+UniqFM to a (lazy) list, do the fold and stops if necessary, which was+the most efficient variant tried. Benchmark compiling 10-times SHA1.hs follows.+(original = previous implementation, folding = fold of the whole UFM,+ lazyFold = the current implementation,+ hackFold = using internal representation of Data.IntMap)++ original folding hackFold lazyFold+ -O -fasm (used everywhere) 31.509s 30.387s 30.791s 30.603s+ 100.00% 96.44% 97.72% 97.12%+ -fregs-graph 67.938s 74.875s 62.673s 64.679s+ 100.00% 110.21% 92.25% 95.20%+ -fregs-iterative 89.761s 143.913s 81.075s 86.912s+ 100.00% 160.33% 90.32% 96.83%+ -fnew-codegen 38.225s 37.142s 37.551s 37.119s+ 100.00% 97.17% 98.24% 97.11%+ -fnew-codegen -fregs-graph 91.786s 91.51s 87.368s 86.88s+ 100.00% 99.70% 95.19% 94.65%+ -fnew-codegen -fregs-iterative 206.72s 343.632s 194.694s 208.677s+ 100.00% 166.23% 94.18% 100.95%+-}++trivColorable+ :: Platform+ -> (RegClass -> VirtualReg -> Int)+ -> (RegClass -> RealReg -> Int)+ -> Triv VirtualReg RegClass RealReg++trivColorable platform virtualRegSqueeze realRegSqueeze RcInteger conflicts exclusions+ | let cALLOCATABLE_REGS_INTEGER+ = (case platformArch platform of+ ArchX86 -> 3+ ArchX86_64 -> 5+ ArchPPC -> 16+ ArchSPARC -> 14+ ArchSPARC64 -> panic "trivColorable ArchSPARC64"+ ArchPPC_64 _ -> 15+ ArchARM _ _ _ -> panic "trivColorable ArchARM"+ ArchARM64 -> panic "trivColorable ArchARM64"+ ArchAlpha -> panic "trivColorable ArchAlpha"+ ArchMipseb -> panic "trivColorable ArchMipseb"+ ArchMipsel -> panic "trivColorable ArchMipsel"+ ArchJavaScript-> panic "trivColorable ArchJavaScript"+ ArchUnknown -> panic "trivColorable ArchUnknown")+ , count2 <- accSqueeze 0 cALLOCATABLE_REGS_INTEGER+ (virtualRegSqueeze RcInteger)+ conflicts++ , count3 <- accSqueeze count2 cALLOCATABLE_REGS_INTEGER+ (realRegSqueeze RcInteger)+ exclusions++ = count3 < cALLOCATABLE_REGS_INTEGER++trivColorable platform virtualRegSqueeze realRegSqueeze RcFloat conflicts exclusions+ | let cALLOCATABLE_REGS_FLOAT+ = (case platformArch platform of+ ArchX86 -> 0+ ArchX86_64 -> 0+ ArchPPC -> 0+ ArchSPARC -> 22+ ArchSPARC64 -> panic "trivColorable ArchSPARC64"+ ArchPPC_64 _ -> 0+ ArchARM _ _ _ -> panic "trivColorable ArchARM"+ ArchARM64 -> panic "trivColorable ArchARM64"+ ArchAlpha -> panic "trivColorable ArchAlpha"+ ArchMipseb -> panic "trivColorable ArchMipseb"+ ArchMipsel -> panic "trivColorable ArchMipsel"+ ArchJavaScript-> panic "trivColorable ArchJavaScript"+ ArchUnknown -> panic "trivColorable ArchUnknown")+ , count2 <- accSqueeze 0 cALLOCATABLE_REGS_FLOAT+ (virtualRegSqueeze RcFloat)+ conflicts++ , count3 <- accSqueeze count2 cALLOCATABLE_REGS_FLOAT+ (realRegSqueeze RcFloat)+ exclusions++ = count3 < cALLOCATABLE_REGS_FLOAT++trivColorable platform virtualRegSqueeze realRegSqueeze RcDouble conflicts exclusions+ | let cALLOCATABLE_REGS_DOUBLE+ = (case platformArch platform of+ ArchX86 -> 6+ ArchX86_64 -> 0+ ArchPPC -> 26+ ArchSPARC -> 11+ ArchSPARC64 -> panic "trivColorable ArchSPARC64"+ ArchPPC_64 _ -> 20+ ArchARM _ _ _ -> panic "trivColorable ArchARM"+ ArchARM64 -> panic "trivColorable ArchARM64"+ ArchAlpha -> panic "trivColorable ArchAlpha"+ ArchMipseb -> panic "trivColorable ArchMipseb"+ ArchMipsel -> panic "trivColorable ArchMipsel"+ ArchJavaScript-> panic "trivColorable ArchJavaScript"+ ArchUnknown -> panic "trivColorable ArchUnknown")+ , count2 <- accSqueeze 0 cALLOCATABLE_REGS_DOUBLE+ (virtualRegSqueeze RcDouble)+ conflicts++ , count3 <- accSqueeze count2 cALLOCATABLE_REGS_DOUBLE+ (realRegSqueeze RcDouble)+ exclusions++ = count3 < cALLOCATABLE_REGS_DOUBLE++trivColorable platform virtualRegSqueeze realRegSqueeze RcDoubleSSE conflicts exclusions+ | let cALLOCATABLE_REGS_SSE+ = (case platformArch platform of+ ArchX86 -> 8+ ArchX86_64 -> 10+ ArchPPC -> 0+ ArchSPARC -> 0+ ArchSPARC64 -> panic "trivColorable ArchSPARC64"+ ArchPPC_64 _ -> 0+ ArchARM _ _ _ -> panic "trivColorable ArchARM"+ ArchARM64 -> panic "trivColorable ArchARM64"+ ArchAlpha -> panic "trivColorable ArchAlpha"+ ArchMipseb -> panic "trivColorable ArchMipseb"+ ArchMipsel -> panic "trivColorable ArchMipsel"+ ArchJavaScript-> panic "trivColorable ArchJavaScript"+ ArchUnknown -> panic "trivColorable ArchUnknown")+ , count2 <- accSqueeze 0 cALLOCATABLE_REGS_SSE+ (virtualRegSqueeze RcDoubleSSE)+ conflicts++ , count3 <- accSqueeze count2 cALLOCATABLE_REGS_SSE+ (realRegSqueeze RcDoubleSSE)+ exclusions++ = count3 < cALLOCATABLE_REGS_SSE+++-- Specification Code ----------------------------------------------------------+--+-- The trivColorable function for each particular architecture should+-- implement the following function, but faster.+--++{-+trivColorable :: RegClass -> UniqSet Reg -> UniqSet Reg -> Bool+trivColorable classN conflicts exclusions+ = let++ acc :: Reg -> (Int, Int) -> (Int, Int)+ acc r (cd, cf)+ = case regClass r of+ RcInteger -> (cd+1, cf)+ RcFloat -> (cd, cf+1)+ _ -> panic "Regs.trivColorable: reg class not handled"++ tmp = nonDetFoldUFM acc (0, 0) conflicts+ (countInt, countFloat) = nonDetFoldUFM acc tmp exclusions++ squeese = worst countInt classN RcInteger+ + worst countFloat classN RcFloat++ in squeese < allocatableRegsInClass classN++-- | Worst case displacement+-- node N of classN has n neighbors of class C.+--+-- We currently only have RcInteger and RcDouble, which don't conflict at all.+-- This is a bit boring compared to what's in RegArchX86.+--+worst :: Int -> RegClass -> RegClass -> Int+worst n classN classC+ = case classN of+ RcInteger+ -> case classC of+ RcInteger -> min n (allocatableRegsInClass RcInteger)+ RcFloat -> 0++ RcDouble+ -> case classC of+ RcFloat -> min n (allocatableRegsInClass RcFloat)+ RcInteger -> 0++-- allocatableRegs is allMachRegNos with the fixed-use regs removed.+-- i.e., these are the regs for which we are prepared to allow the+-- register allocator to attempt to map VRegs to.+allocatableRegs :: [RegNo]+allocatableRegs+ = let isFree i = freeReg i+ in filter isFree allMachRegNos+++-- | The number of regs in each class.+-- We go via top level CAFs to ensure that we're not recomputing+-- the length of these lists each time the fn is called.+allocatableRegsInClass :: RegClass -> Int+allocatableRegsInClass cls+ = case cls of+ RcInteger -> allocatableRegsInteger+ RcFloat -> allocatableRegsDouble++allocatableRegsInteger :: Int+allocatableRegsInteger+ = length $ filter (\r -> regClass r == RcInteger)+ $ map RealReg allocatableRegs++allocatableRegsFloat :: Int+allocatableRegsFloat+ = length $ filter (\r -> regClass r == RcFloat+ $ map RealReg allocatableRegs+-}
+ nativeGen/RegAlloc/Linear/Base.hs view
@@ -0,0 +1,132 @@++-- | Put common type definitions here to break recursive module dependencies.++module RegAlloc.Linear.Base (+ BlockAssignment,++ Loc(..),+ regsOfLoc,++ -- for stats+ SpillReason(..),+ RegAllocStats(..),++ -- the allocator monad+ RA_State(..),+)++where++import RegAlloc.Linear.StackMap+import RegAlloc.Liveness+import Reg++import DynFlags+import Outputable+import Unique+import UniqFM+import UniqSupply+++-- | Used to store the register assignment on entry to a basic block.+-- We use this to handle join points, where multiple branch instructions+-- 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)+++-- | Where a vreg is currently stored+-- A temporary can be marked as living in both a register and memory+-- (InBoth), for example if it was recently loaded from a spill location.+-- This makes it cheap to spill (no save instruction required), but we+-- have to be careful to turn this into InReg if the value in the+-- register is changed.++-- This is also useful when a temporary is about to be clobbered. We+-- save it in a spill location, but mark it as InBoth because the current+-- instruction might still want to read it.+--+data Loc+ -- | vreg is in a register+ = InReg !RealReg++ -- | vreg is held in a stack slot+ | InMem {-# UNPACK #-} !StackSlot+++ -- | vreg is held in both a register and a stack slot+ | InBoth !RealReg+ {-# UNPACK #-} !StackSlot+ deriving (Eq, Show, Ord)++instance Outputable Loc where+ ppr l = text (show l)+++-- | Get the reg numbers stored in this Loc.+regsOfLoc :: Loc -> [RealReg]+regsOfLoc (InReg r) = [r]+regsOfLoc (InBoth r _) = [r]+regsOfLoc (InMem _) = []+++-- | Reasons why instructions might be inserted by the spiller.+-- Used when generating stats for -ddrop-asm-stats.+--+data SpillReason+ -- | vreg was spilled to a slot so we could use its+ -- current hreg for another vreg+ = SpillAlloc !Unique++ -- | vreg was moved because its hreg was clobbered+ | SpillClobber !Unique++ -- | vreg was loaded from a spill slot+ | SpillLoad !Unique++ -- | reg-reg move inserted during join to targets+ | SpillJoinRR !Unique++ -- | reg-mem move inserted during join to targets+ | SpillJoinRM !Unique+++-- | Used to carry interesting stats out of the register allocator.+data RegAllocStats+ = RegAllocStats+ { ra_spillInstrs :: UniqFM [Int] }+++-- | The register allocator state+data RA_State freeRegs+ = RA_State++ {+ -- | the current mapping from basic blocks to+ -- the register assignments at the beginning of that block.+ ra_blockassig :: BlockAssignment freeRegs++ -- | free machine registers+ , ra_freeregs :: !freeRegs++ -- | assignment of temps to locations+ , ra_assig :: RegMap Loc++ -- | current stack delta+ , ra_delta :: Int++ -- | free stack slots for spilling+ , ra_stack :: StackMap++ -- | unique supply for generating names for join point fixup blocks.+ , ra_us :: UniqSupply++ -- | Record why things were spilled, for -ddrop-asm-stats.+ -- Just keep a list here instead of a map of regs -> reasons.+ -- We don't want to slow down the allocator if we're not going to emit the stats.+ , ra_spills :: [SpillReason]+ , ra_DynFlags :: DynFlags }++
+ nativeGen/RegAlloc/Linear/FreeRegs.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE CPP #-}++module RegAlloc.Linear.FreeRegs (+ FR(..),+ maxSpillSlots+)++#include "HsVersions.h"++where++import Reg+import RegClass++import DynFlags+import Panic+import Platform++-- -----------------------------------------------------------------------------+-- The free register set+-- This needs to be *efficient*+-- Here's an inefficient 'executable specification' of the FreeRegs data type:+--+-- type FreeRegs = [RegNo]+-- noFreeRegs = 0+-- releaseReg n f = if n `elem` f then f else (n : f)+-- initFreeRegs = allocatableRegs+-- getFreeRegs cls f = filter ( (==cls) . regClass . RealReg ) f+-- allocateReg f r = filter (/= r) f++import qualified RegAlloc.Linear.PPC.FreeRegs as PPC+import qualified RegAlloc.Linear.SPARC.FreeRegs as SPARC+import qualified RegAlloc.Linear.X86.FreeRegs as X86+import qualified RegAlloc.Linear.X86_64.FreeRegs as X86_64++import qualified PPC.Instr+import qualified SPARC.Instr+import qualified X86.Instr++class Show freeRegs => FR freeRegs where+ frAllocateReg :: Platform -> RealReg -> freeRegs -> freeRegs+ frGetFreeRegs :: Platform -> RegClass -> freeRegs -> [RealReg]+ frInitFreeRegs :: Platform -> freeRegs+ frReleaseReg :: Platform -> RealReg -> freeRegs -> freeRegs++instance FR X86.FreeRegs where+ frAllocateReg = \_ -> X86.allocateReg+ frGetFreeRegs = X86.getFreeRegs+ frInitFreeRegs = X86.initFreeRegs+ frReleaseReg = \_ -> X86.releaseReg++instance FR X86_64.FreeRegs where+ frAllocateReg = \_ -> X86_64.allocateReg+ frGetFreeRegs = X86_64.getFreeRegs+ frInitFreeRegs = X86_64.initFreeRegs+ frReleaseReg = \_ -> X86_64.releaseReg++instance FR PPC.FreeRegs where+ frAllocateReg = \_ -> PPC.allocateReg+ frGetFreeRegs = \_ -> PPC.getFreeRegs+ frInitFreeRegs = PPC.initFreeRegs+ frReleaseReg = \_ -> PPC.releaseReg++instance FR SPARC.FreeRegs where+ frAllocateReg = SPARC.allocateReg+ frGetFreeRegs = \_ -> SPARC.getFreeRegs+ frInitFreeRegs = SPARC.initFreeRegs+ frReleaseReg = SPARC.releaseReg++maxSpillSlots :: DynFlags -> Int+maxSpillSlots dflags+ = case platformArch (targetPlatform dflags) of+ ArchX86 -> X86.Instr.maxSpillSlots dflags+ ArchX86_64 -> X86.Instr.maxSpillSlots dflags+ ArchPPC -> PPC.Instr.maxSpillSlots dflags+ ArchSPARC -> SPARC.Instr.maxSpillSlots dflags+ ArchSPARC64 -> panic "maxSpillSlots ArchSPARC64"+ ArchARM _ _ _ -> panic "maxSpillSlots ArchARM"+ ArchARM64 -> panic "maxSpillSlots ArchARM64"+ ArchPPC_64 _ -> PPC.Instr.maxSpillSlots dflags+ ArchAlpha -> panic "maxSpillSlots ArchAlpha"+ ArchMipseb -> panic "maxSpillSlots ArchMipseb"+ ArchMipsel -> panic "maxSpillSlots ArchMipsel"+ ArchJavaScript-> panic "maxSpillSlots ArchJavaScript"+ ArchUnknown -> panic "maxSpillSlots ArchUnknown"+
+ nativeGen/RegAlloc/Linear/JoinToTargets.hs view
@@ -0,0 +1,368 @@++-- | Handles joining of a jump instruction to its targets.++-- The first time we encounter a jump to a particular basic block, we+-- record the assignment of temporaries. The next time we encounter a+-- jump to the same block, we compare our current assignment to the+-- stored one. They might be different if spilling has occurred in one+-- branch; so some fixup code will be required to match up the assignments.+--+module RegAlloc.Linear.JoinToTargets (joinToTargets) where++import RegAlloc.Linear.State+import RegAlloc.Linear.Base+import RegAlloc.Linear.FreeRegs+import RegAlloc.Liveness+import Instruction+import Reg++import BlockId+import Hoopl+import Digraph+import DynFlags+import Outputable+import Unique+import UniqFM+import UniqSet++import Data.Foldable (foldl')++-- | For a jump instruction at the end of a block, generate fixup code so its+-- vregs are in the correct regs for its destination.+--+joinToTargets+ :: (FR freeRegs, Instruction instr)+ => BlockMap RegSet -- ^ maps the unique of the blockid to the set of vregs+ -- that are known to be live on the entry to each block.++ -> BlockId -- ^ id of the current block+ -> instr -- ^ branch instr on the end of the source block.++ -> RegM freeRegs ([NatBasicBlock instr] -- fresh blocks of fixup code.+ , instr) -- the original branch+ -- instruction, but maybe+ -- patched to jump+ -- to a fixup block first.++joinToTargets block_live id instr++ -- we only need to worry about jump instructions.+ | not $ isJumpishInstr instr+ = return ([], instr)++ | otherwise+ = joinToTargets' block_live [] id instr (jumpDestsOfInstr instr)++-----+joinToTargets'+ :: (FR freeRegs, Instruction instr)+ => BlockMap RegSet -- ^ maps the unique of the blockid to the set of vregs+ -- that are known to be live on the entry to each block.++ -> [NatBasicBlock instr] -- ^ acc blocks of fixup code.++ -> BlockId -- ^ id of the current block+ -> instr -- ^ branch instr on the end of the source block.++ -> [BlockId] -- ^ branch destinations still to consider.++ -> RegM freeRegs ([NatBasicBlock instr], instr)++-- no more targets to consider. all done.+joinToTargets' _ new_blocks _ instr []+ = return (new_blocks, instr)++-- handle a branch target.+joinToTargets' block_live new_blocks block_id instr (dest:dests)+ = do+ -- get the map of where the vregs are stored on entry to each basic block.+ block_assig <- getBlockAssigR++ -- get the assignment on entry to the branch instruction.+ assig <- getAssigR++ -- adjust the current assignment to remove any vregs that are not live+ -- on entry to the destination block.+ let Just live_set = mapLookup dest block_live+ let still_live uniq _ = uniq `elemUniqSet_Directly` live_set+ let adjusted_assig = filterUFM_Directly still_live assig++ -- and free up those registers which are now free.+ let to_free =+ [ r | (reg, loc) <- nonDetUFMToList assig+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ , not (elemUniqSet_Directly reg live_set)+ , r <- regsOfLoc loc ]++ case mapLookup dest block_assig of+ Nothing+ -> joinToTargets_first+ block_live new_blocks block_id instr dest dests+ block_assig adjusted_assig to_free++ Just (_, dest_assig)+ -> joinToTargets_again+ block_live new_blocks block_id instr dest dests+ adjusted_assig dest_assig+++-- this is the first time we jumped to this block.+joinToTargets_first :: (FR freeRegs, Instruction instr)+ => BlockMap RegSet+ -> [NatBasicBlock instr]+ -> BlockId+ -> instr+ -> BlockId+ -> [BlockId]+ -> BlockAssignment freeRegs+ -> RegMap Loc+ -> [RealReg]+ -> RegM freeRegs ([NatBasicBlock instr], instr)+joinToTargets_first block_live new_blocks block_id instr dest dests+ block_assig src_assig+ to_free++ = do dflags <- getDynFlags+ let platform = targetPlatform dflags++ -- free up the regs that are not live on entry to this block.+ freeregs <- getFreeRegsR+ 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)++ joinToTargets' block_live new_blocks block_id instr dests+++-- we've jumped to this block before+joinToTargets_again :: (Instruction instr, FR freeRegs)+ => BlockMap RegSet+ -> [NatBasicBlock instr]+ -> BlockId+ -> instr+ -> BlockId+ -> [BlockId]+ -> UniqFM Loc+ -> UniqFM Loc+ -> RegM freeRegs ([NatBasicBlock instr], instr)+joinToTargets_again+ block_live new_blocks block_id instr dest dests+ src_assig dest_assig++ -- the assignments already match, no problem.+ | nonDetUFMToList dest_assig == nonDetUFMToList src_assig+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ = joinToTargets' block_live new_blocks block_id instr dests++ -- assignments don't match, need fixup code+ | otherwise+ = do++ -- make a graph of what things need to be moved where.+ let graph = makeRegMovementGraph src_assig dest_assig++ -- look for cycles in the graph. This can happen if regs need to be swapped.+ -- Note that we depend on the fact that this function does a+ -- bottom up traversal of the tree-like portions of the graph.+ --+ -- eg, if we have+ -- R1 -> R2 -> R3+ --+ -- ie move value in R1 to R2 and value in R2 to R3.+ --+ -- We need to do the R2 -> R3 move before R1 -> R2.+ --+ let sccs = stronglyConnCompFromEdgedVerticesOrdR graph++{- -- debugging+ pprTrace+ ("joinToTargets: making fixup code")+ (vcat [ text " in block: " <> ppr block_id+ , text " jmp instruction: " <> ppr instr+ , text " src assignment: " <> ppr src_assig+ , text " dest assignment: " <> ppr dest_assig+ , text " movement graph: " <> ppr graph+ , text " sccs of graph: " <> ppr sccs+ , text ""])+ (return ())+-}+ delta <- getDeltaR+ fixUpInstrs_ <- mapM (handleComponent delta instr) sccs+ let fixUpInstrs = concat fixUpInstrs_++ -- make a new basic block containing the fixup code.+ -- A the end of the current block we will jump to the fixup one,+ -- then that will jump to our original destination.+ fixup_block_id <- getUniqueR+ let block = BasicBlock (mkBlockId fixup_block_id)+ $ fixUpInstrs ++ mkJumpInstr dest++{- pprTrace+ ("joinToTargets: fixup code is:")+ (vcat [ ppr block+ , text ""])+ (return ())+-}+ -- if we didn't need any fixups, then don't include the block+ case fixUpInstrs of+ [] -> joinToTargets' block_live new_blocks block_id instr dests++ -- patch the original branch instruction so it goes to our+ -- fixup block instead.+ _ -> let instr' = patchJumpInstr instr+ (\bid -> if bid == dest+ then mkBlockId fixup_block_id+ else bid) -- no change!++ in joinToTargets' block_live (block : new_blocks) block_id instr' dests+++-- | Construct a graph of register\/spill movements.+--+-- Cyclic components seem to occur only very rarely.+--+-- We cut some corners by not handling memory-to-memory moves.+-- This shouldn't happen because every temporary gets its own stack slot.+--+makeRegMovementGraph :: RegMap Loc -> RegMap Loc -> [(Unique, Loc, [Loc])]+makeRegMovementGraph adjusted_assig dest_assig+ = [ node | (vreg, src) <- nonDetUFMToList adjusted_assig+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ -- source reg might not be needed at the dest:+ , Just loc <- [lookupUFM_Directly dest_assig vreg]+ , node <- expandNode vreg src loc ]+++-- | Expand out the destination, so InBoth destinations turn into+-- a combination of InReg and InMem.++-- The InBoth handling is a little tricky here. If the destination is+-- InBoth, then we must ensure that the value ends up in both locations.+-- An InBoth destination must conflict with an InReg or InMem source, so+-- we expand an InBoth destination as necessary.+--+-- An InBoth source is slightly different: we only care about the register+-- that the source value is in, so that we can move it to the destinations.+--+expandNode+ :: a+ -> Loc -- ^ source of move+ -> Loc -- ^ destination of move+ -> [(a, Loc, [Loc])]++expandNode vreg loc@(InReg src) (InBoth dst mem)+ | src == dst = [(vreg, loc, [InMem mem])]+ | otherwise = [(vreg, loc, [InReg dst, InMem mem])]++expandNode vreg loc@(InMem src) (InBoth dst mem)+ | src == mem = [(vreg, loc, [InReg dst])]+ | otherwise = [(vreg, loc, [InReg dst, InMem mem])]++expandNode _ (InBoth _ src) (InMem dst)+ | src == dst = [] -- guaranteed to be true++expandNode _ (InBoth src _) (InReg dst)+ | src == dst = []++expandNode vreg (InBoth src _) dst+ = expandNode vreg (InReg src) dst++expandNode vreg src dst+ | src == dst = []+ | otherwise = [(vreg, src, [dst])]+++-- | Generate fixup code for a particular component in the move graph+-- This component tells us what values need to be moved to what+-- destinations. We have eliminated any possibility of single-node+-- cycles in expandNode above.+--+handleComponent+ :: Instruction instr+ => Int -> instr -> SCC (Unique, Loc, [Loc])+ -> RegM freeRegs [instr]++-- If the graph is acyclic then we won't get the swapping problem below.+-- In this case we can just do the moves directly, and avoid having to+-- go via a spill slot.+--+handleComponent delta _ (AcyclicSCC (vreg, src, dsts))+ = mapM (makeMove delta vreg src) dsts+++-- Handle some cyclic moves.+-- This can happen if we have two regs that need to be swapped.+-- eg:+-- vreg source loc dest loc+-- (vreg1, InReg r1, [InReg r2])+-- (vreg2, InReg r2, [InReg r1])+--+-- To avoid needing temp register, we just spill all the source regs, then+-- reaload them into their destination regs.+--+-- Note that we can not have cycles that involve memory locations as+-- sources as single destination because memory locations (stack slots)+-- are allocated exclusively for a virtual register and therefore can not+-- require a fixup.+--+handleComponent delta instr+ (CyclicSCC ((vreg, InReg sreg, (InReg dreg: _)) : rest))+ -- dest list may have more than one element, if the reg is also InMem.+ = do+ -- spill the source into its slot+ (instrSpill, slot)+ <- spillR (RegReal sreg) vreg++ -- reload into destination reg+ instrLoad <- loadR (RegReal dreg) slot++ remainingFixUps <- mapM (handleComponent delta instr)+ (stronglyConnCompFromEdgedVerticesOrdR rest)++ -- make sure to do all the reloads after all the spills,+ -- so we don't end up clobbering the source values.+ return ([instrSpill] ++ concat remainingFixUps ++ [instrLoad])++handleComponent _ _ (CyclicSCC _)+ = panic "Register Allocator: handleComponent cyclic"+++-- | Move a vreg between these two locations.+--+makeMove+ :: Instruction instr+ => Int -- ^ current C stack delta.+ -> Unique -- ^ unique of the vreg that we're moving.+ -> Loc -- ^ source location.+ -> Loc -- ^ destination location.+ -> RegM freeRegs instr -- ^ move instruction.++makeMove delta vreg src dst+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags++ case (src, dst) of+ (InReg s, InReg d) ->+ do recordSpill (SpillJoinRR vreg)+ return $ mkRegRegMoveInstr platform (RegReal s) (RegReal d)+ (InMem s, InReg d) ->+ do recordSpill (SpillJoinRM vreg)+ return $ mkLoadInstr dflags (RegReal d) delta s+ (InReg s, InMem d) ->+ do recordSpill (SpillJoinRM vreg)+ return $ mkSpillInstr dflags (RegReal s) delta d+ _ ->+ -- we don't handle memory to memory moves.+ -- they shouldn't happen because we don't share+ -- stack slots between vregs.+ panic ("makeMove " ++ show vreg ++ " (" ++ show src ++ ") ("+ ++ show dst ++ ")"+ ++ " we don't handle mem->mem moves.")+
+ nativeGen/RegAlloc/Linear/Main.hs view
@@ -0,0 +1,907 @@+{-# LANGUAGE BangPatterns, CPP, ScopedTypeVariables #-}++-----------------------------------------------------------------------------+--+-- The register allocator+--+-- (c) The University of Glasgow 2004+--+-----------------------------------------------------------------------------++{-+The algorithm is roughly:++ 1) Compute strongly connected components of the basic block list.++ 2) Compute liveness (mapping from pseudo register to+ point(s) of death?).++ 3) Walk instructions in each basic block. We keep track of+ (a) Free real registers (a bitmap?)+ (b) Current assignment of temporaries to machine registers and/or+ spill slots (call this the "assignment").+ (c) Partial mapping from basic block ids to a virt-to-loc mapping.+ When we first encounter a branch to a basic block,+ we fill in its entry in this table with the current mapping.++ For each instruction:+ (a) For each temporary *read* by the instruction:+ If the temporary does not have a real register allocation:+ - Allocate a real register from the free list. If+ the list is empty:+ - Find a temporary to spill. Pick one that is+ not used in this instruction (ToDo: not+ used for a while...)+ - generate a spill instruction+ - If the temporary was previously spilled,+ generate an instruction to read the temp from its spill loc.+ (optimisation: if we can see that a real register is going to+ be used soon, then don't use it for allocation).++ (b) For each real register clobbered by this instruction:+ If a temporary resides in it,+ If the temporary is live after this instruction,+ Move the temporary to another (non-clobbered & free) reg,+ or spill it to memory. Mark the temporary as residing+ in both memory and a register if it was spilled (it might+ need to be read by this instruction).++ (ToDo: this is wrong for jump instructions?)++ We do this after step (a), because if we start with+ movq v1, %rsi+ which is an instruction that clobbers %rsi, if v1 currently resides+ in %rsi we want to get+ movq %rsi, %freereg+ movq %rsi, %rsi -- will disappear+ instead of+ movq %rsi, %freereg+ movq %freereg, %rsi++ (c) Update the current assignment++ (d) If the instruction is a branch:+ if the destination block already has a register assignment,+ Generate a new block with fixup code and redirect the+ jump to the new block.+ else,+ Update the block id->assignment mapping with the current+ assignment.++ (e) Delete all register assignments for temps which are read+ (only) and die here. Update the free register list.++ (f) Mark all registers clobbered by this instruction as not free,+ and mark temporaries which have been spilled due to clobbering+ as in memory (step (a) marks then as in both mem & reg).++ (g) For each temporary *written* by this instruction:+ Allocate a real register as for (b), spilling something+ else if necessary.+ - except when updating the assignment, drop any memory+ locations that the temporary was previously in, since+ they will be no longer valid after this instruction.++ (h) Delete all register assignments for temps which are+ written and die here (there should rarely be any). Update+ the free register list.++ (i) Rewrite the instruction with the new mapping.++ (j) For each spilled reg known to be now dead, re-add its stack slot+ to the free list.++-}++module RegAlloc.Linear.Main (+ regAlloc,+ module RegAlloc.Linear.Base,+ module RegAlloc.Linear.Stats+ ) where++#include "HsVersions.h"+++import RegAlloc.Linear.State+import RegAlloc.Linear.Base+import RegAlloc.Linear.StackMap+import RegAlloc.Linear.FreeRegs+import RegAlloc.Linear.Stats+import RegAlloc.Linear.JoinToTargets+import qualified RegAlloc.Linear.PPC.FreeRegs as PPC+import qualified RegAlloc.Linear.SPARC.FreeRegs as SPARC+import qualified RegAlloc.Linear.X86.FreeRegs as X86+import qualified RegAlloc.Linear.X86_64.FreeRegs as X86_64+import TargetReg+import RegAlloc.Liveness+import Instruction+import Reg++import BlockId+import Hoopl+import Cmm hiding (RegSet)++import Digraph+import DynFlags+import Unique+import UniqSet+import UniqFM+import UniqSupply+import Outputable+import Platform++import Data.Maybe+import Data.List+import Control.Monad++-- -----------------------------------------------------------------------------+-- Top level of the register allocator++-- Allocate registers+regAlloc+ :: (Outputable instr, Instruction instr)+ => DynFlags+ -> LiveCmmDecl statics instr+ -> UniqSM ( NatCmmDecl statics instr+ , Maybe Int -- number of extra stack slots required,+ -- beyond maxSpillSlots+ , Maybe RegAllocStats)++regAlloc _ (CmmData sec d)+ = return+ ( CmmData sec d+ , Nothing+ , Nothing )++regAlloc _ (CmmProc (LiveInfo info _ _ _) lbl live [])+ = return ( CmmProc info lbl live (ListGraph [])+ , Nothing+ , Nothing )++regAlloc dflags (CmmProc static lbl live sccs)+ | LiveInfo info entry_ids@(first_id:_) (Just block_live) _ <- static+ = do+ -- do register allocation on each component.+ (final_blocks, stats, stack_use)+ <- linearRegAlloc dflags entry_ids block_live sccs++ -- make sure the block that was first in the input list+ -- stays at the front of the output+ let ((first':_), rest')+ = partition ((== first_id) . blockId) final_blocks++ let max_spill_slots = maxSpillSlots dflags+ extra_stack+ | stack_use > max_spill_slots+ = Just (stack_use - max_spill_slots)+ | otherwise+ = Nothing++ return ( CmmProc info lbl live (ListGraph (first' : rest'))+ , extra_stack+ , Just stats)++-- bogus. to make non-exhaustive match warning go away.+regAlloc _ (CmmProc _ _ _ _)+ = panic "RegAllocLinear.regAlloc: no match"+++-- -----------------------------------------------------------------------------+-- Linear sweep to allocate registers+++-- | Do register allocation on some basic blocks.+-- But be careful to allocate a block in an SCC only if it has+-- an entry in the block map or it is the first block.+--+linearRegAlloc+ :: (Outputable instr, Instruction instr)+ => DynFlags+ -> [BlockId] -- ^ entry points+ -> BlockMap RegSet+ -- ^ live regs on entry to each basic block+ -> [SCC (LiveBasicBlock instr)]+ -- ^ instructions annotated with "deaths"+ -> UniqSM ([NatBasicBlock instr], RegAllocStats, Int)++linearRegAlloc dflags entry_ids block_live sccs+ = case platformArch platform of+ ArchX86 -> go $ (frInitFreeRegs platform :: X86.FreeRegs)+ ArchX86_64 -> go $ (frInitFreeRegs platform :: X86_64.FreeRegs)+ ArchSPARC -> go $ (frInitFreeRegs platform :: SPARC.FreeRegs)+ ArchSPARC64 -> panic "linearRegAlloc ArchSPARC64"+ ArchPPC -> go $ (frInitFreeRegs platform :: PPC.FreeRegs)+ ArchARM _ _ _ -> panic "linearRegAlloc ArchARM"+ ArchARM64 -> panic "linearRegAlloc ArchARM64"+ ArchPPC_64 _ -> go $ (frInitFreeRegs platform :: PPC.FreeRegs)+ ArchAlpha -> panic "linearRegAlloc ArchAlpha"+ ArchMipseb -> panic "linearRegAlloc ArchMipseb"+ ArchMipsel -> panic "linearRegAlloc ArchMipsel"+ ArchJavaScript -> panic "linearRegAlloc ArchJavaScript"+ ArchUnknown -> panic "linearRegAlloc ArchUnknown"+ where+ go f = linearRegAlloc' dflags f entry_ids block_live sccs+ platform = targetPlatform dflags++linearRegAlloc'+ :: (FR freeRegs, Outputable instr, Instruction instr)+ => DynFlags+ -> freeRegs+ -> [BlockId] -- ^ entry points+ -> BlockMap RegSet -- ^ live regs on entry to each basic block+ -> [SCC (LiveBasicBlock instr)] -- ^ instructions annotated with "deaths"+ -> UniqSM ([NatBasicBlock instr], RegAllocStats, Int)++linearRegAlloc' dflags initFreeRegs entry_ids block_live sccs+ = do us <- getUniqueSupplyM+ let (_, stack, stats, blocks) =+ runR dflags mapEmpty initFreeRegs emptyRegMap (emptyStackMap dflags) us+ $ linearRA_SCCs entry_ids block_live [] sccs+ return (blocks, stats, getStackUse stack)+++linearRA_SCCs :: (FR freeRegs, Instruction instr, Outputable instr)+ => [BlockId]+ -> BlockMap RegSet+ -> [NatBasicBlock instr]+ -> [SCC (LiveBasicBlock instr)]+ -> RegM freeRegs [NatBasicBlock instr]++linearRA_SCCs _ _ blocksAcc []+ = return $ reverse blocksAcc++linearRA_SCCs entry_ids block_live blocksAcc (AcyclicSCC block : sccs)+ = do blocks' <- processBlock block_live block+ linearRA_SCCs entry_ids block_live+ ((reverse blocks') ++ blocksAcc)+ sccs++linearRA_SCCs entry_ids block_live blocksAcc (CyclicSCC blocks : sccs)+ = do+ blockss' <- process entry_ids block_live blocks [] (return []) False+ linearRA_SCCs entry_ids block_live+ (reverse (concat blockss') ++ blocksAcc)+ sccs++{- from John Dias's patch 2008/10/16:+ The linear-scan allocator sometimes allocates a block+ before allocating one of its predecessors, which could lead to+ inconsistent allocations. Make it so a block is only allocated+ if a predecessor has set the "incoming" assignments for the block, or+ if it's the procedure's entry block.++ BL 2009/02: Careful. If the assignment for a block doesn't get set for+ some reason then this function will loop. We should probably do some+ more sanity checking to guard against this eventuality.+-}++process :: (FR freeRegs, Instruction instr, Outputable instr)+ => [BlockId]+ -> BlockMap RegSet+ -> [GenBasicBlock (LiveInstr instr)]+ -> [GenBasicBlock (LiveInstr instr)]+ -> [[NatBasicBlock instr]]+ -> Bool+ -> RegM freeRegs [[NatBasicBlock instr]]++process _ _ [] [] accum _+ = return $ reverse accum++process entry_ids block_live [] next_round accum madeProgress+ | not madeProgress++ {- BUGS: There are so many unreachable blocks in the code the warnings are overwhelming.+ pprTrace "RegAlloc.Linear.Main.process: no progress made, bailing out."+ ( text "Unreachable blocks:"+ $$ vcat (map ppr next_round)) -}+ = return $ reverse accum++ | otherwise+ = process entry_ids block_live+ next_round [] accum False++process entry_ids block_live (b@(BasicBlock id _) : blocks)+ next_round accum madeProgress+ = do+ block_assig <- getBlockAssigR++ if isJust (mapLookup id block_assig)+ || id `elem` entry_ids+ then do+ b' <- processBlock block_live b+ process entry_ids block_live blocks+ next_round (b' : accum) True++ else process entry_ids block_live blocks+ (b : next_round) accum madeProgress+++-- | Do register allocation on this basic block+--+processBlock+ :: (FR freeRegs, Outputable instr, Instruction instr)+ => BlockMap RegSet -- ^ live regs on entry to each basic block+ -> LiveBasicBlock instr -- ^ block to do register allocation on+ -> RegM freeRegs [NatBasicBlock instr] -- ^ block with registers allocated++processBlock block_live (BasicBlock id instrs)+ = do initBlock id block_live+ (instrs', fixups)+ <- linearRA block_live [] [] id instrs+ return $ BasicBlock id instrs' : fixups+++-- | Load the freeregs and current reg assignment into the RegM state+-- for the basic block with this BlockId.+initBlock :: FR freeRegs+ => BlockId -> BlockMap RegSet -> RegM freeRegs ()+initBlock id block_live+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ block_assig <- getBlockAssigR+ case mapLookup 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,+ -- and we'll iterate again). The assignment begins+ -- empty.+ Nothing+ -> do -- pprTrace "initFreeRegs" (text $ show initFreeRegs) (return ())+ case mapLookup id block_live of+ Nothing ->+ setFreeRegsR (frInitFreeRegs platform)+ Just live ->+ setFreeRegsR $ foldl' (flip $ frAllocateReg platform) (frInitFreeRegs platform)+ [ r | RegReal r <- nonDetEltsUniqSet live ]+ -- See Note [Unique Determinism and code generation]+ setAssigR emptyRegMap++ -- load info about register assignments leading into this block.+ Just (freeregs, assig)+ -> do setFreeRegsR freeregs+ setAssigR assig+++-- | Do allocation for a sequence of instructions.+linearRA+ :: (FR freeRegs, Outputable instr, Instruction instr)+ => BlockMap RegSet -- ^ map of what vregs are live on entry to each block.+ -> [instr] -- ^ accumulator for instructions already processed.+ -> [NatBasicBlock instr] -- ^ accumulator for blocks of fixup code.+ -> BlockId -- ^ id of the current block, for debugging.+ -> [LiveInstr instr] -- ^ liveness annotated instructions in this block.++ -> RegM freeRegs+ ( [instr] -- instructions after register allocation+ , [NatBasicBlock instr]) -- fresh blocks of fixup code.+++linearRA _ accInstr accFixup _ []+ = return+ ( reverse accInstr -- instrs need to be returned in the correct order.+ , accFixup) -- it doesn't matter what order the fixup blocks are returned in.+++linearRA block_live accInstr accFixups id (instr:instrs)+ = do+ (accInstr', new_fixups) <- raInsn block_live accInstr id instr++ linearRA block_live accInstr' (new_fixups ++ accFixups) id instrs+++-- | Do allocation for a single instruction.+raInsn+ :: (FR freeRegs, Outputable instr, Instruction instr)+ => BlockMap RegSet -- ^ map of what vregs are love on entry to each block.+ -> [instr] -- ^ accumulator for instructions already processed.+ -> BlockId -- ^ the id of the current block, for debugging+ -> LiveInstr instr -- ^ the instr to have its regs allocated, with liveness info.+ -> RegM freeRegs+ ( [instr] -- new instructions+ , [NatBasicBlock instr]) -- extra fixup blocks++raInsn _ new_instrs _ (LiveInstr ii Nothing)+ | Just n <- takeDeltaInstr ii+ = do setDeltaR n+ return (new_instrs, [])++raInsn _ new_instrs _ (LiveInstr ii@(Instr i) Nothing)+ | isMetaInstr ii+ = return (i : new_instrs, [])+++raInsn block_live new_instrs id (LiveInstr (Instr instr) (Just live))+ = do+ assig <- getAssigR++ -- If we have a reg->reg move between virtual registers, where the+ -- src register is not live after this instruction, and the dst+ -- register does not already have an assignment,+ -- and the source register is assigned to a register, not to a spill slot,+ -- then we can eliminate the instruction.+ -- (we can't eliminate it if the source register is on the stack, because+ -- we do not want to use one spill slot for different virtual registers)+ case takeRegRegMoveInstr instr of+ Just (src,dst) | src `elementOfUniqSet` (liveDieRead live),+ isVirtualReg dst,+ not (dst `elemUFM` assig),+ isRealReg src || isInReg src assig -> do+ case src of+ (RegReal rr) -> setAssigR (addToUFM assig dst (InReg rr))+ -- if src is a fixed reg, then we just map dest to this+ -- reg in the assignment. src must be an allocatable reg,+ -- otherwise it wouldn't be in r_dying.+ _virt -> case lookupUFM assig src of+ Nothing -> panic "raInsn"+ Just loc ->+ setAssigR (addToUFM (delFromUFM assig src) dst loc)++ -- we have eliminated this instruction+ {-+ freeregs <- getFreeRegsR+ assig <- getAssigR+ pprTrace "raInsn" (text "ELIMINATED: " <> docToSDoc (pprInstr instr)+ $$ ppr r_dying <+> ppr w_dying $$ text (show freeregs) $$ ppr assig) $ do+ -}+ return (new_instrs, [])++ _ -> genRaInsn block_live new_instrs id instr+ (nonDetEltsUniqSet $ liveDieRead live)+ (nonDetEltsUniqSet $ liveDieWrite live)+ -- See Note [Unique Determinism and code generation]++raInsn _ _ _ instr+ = pprPanic "raInsn" (text "no match for:" <> ppr instr)++-- ToDo: what can we do about+--+-- R1 = x+-- jump I64[x] // [R1]+--+-- where x is mapped to the same reg as R1. We want to coalesce x and+-- R1, but the register allocator doesn't know whether x will be+-- assigned to again later, in which case x and R1 should be in+-- different registers. Right now we assume the worst, and the+-- assignment to R1 will clobber x, so we'll spill x into another reg,+-- generating another reg->reg move.+++isInReg :: Reg -> RegMap Loc -> Bool+isInReg src assig | Just (InReg _) <- lookupUFM assig src = True+ | otherwise = False+++genRaInsn :: (FR freeRegs, Instruction instr, Outputable instr)+ => BlockMap RegSet+ -> [instr]+ -> BlockId+ -> instr+ -> [Reg]+ -> [Reg]+ -> RegM freeRegs ([instr], [NatBasicBlock instr])++genRaInsn block_live new_instrs block_id instr r_dying w_dying = do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ case regUsageOfInstr platform instr of { RU read written ->+ do+ let real_written = [ rr | (RegReal rr) <- written ]+ let virt_written = [ vr | (RegVirtual vr) <- written ]++ -- we don't need to do anything with real registers that are+ -- only read by this instr. (the list is typically ~2 elements,+ -- so using nub isn't a problem).+ let virt_read = nub [ vr | (RegVirtual vr) <- read ]++ -- debugging+{- freeregs <- getFreeRegsR+ assig <- getAssigR+ pprDebugAndThen (defaultDynFlags Settings{ sTargetPlatform=platform }) trace "genRaInsn"+ (ppr instr+ $$ text "r_dying = " <+> ppr r_dying+ $$ text "w_dying = " <+> ppr w_dying+ $$ text "virt_read = " <+> ppr virt_read+ $$ text "virt_written = " <+> ppr virt_written+ $$ text "freeregs = " <+> text (show freeregs)+ $$ text "assig = " <+> ppr assig)+ $ do+-}++ -- (a), (b) allocate real regs for all regs read by this instruction.+ (r_spills, r_allocd) <-+ allocateRegsAndSpill True{-reading-} virt_read [] [] virt_read++ -- (c) save any temporaries which will be clobbered by this instruction+ clobber_saves <- saveClobberedTemps real_written r_dying++ -- (d) Update block map for new destinations+ -- NB. do this before removing dead regs from the assignment, because+ -- these dead regs might in fact be live in the jump targets (they're+ -- only dead in the code that follows in the current basic block).+ (fixup_blocks, adjusted_instr)+ <- joinToTargets block_live block_id instr++ -- (e) Delete all register assignments for temps which are read+ -- (only) and die here. Update the free register list.+ releaseRegs r_dying++ -- (f) Mark regs which are clobbered as unallocatable+ clobberRegs real_written++ -- (g) Allocate registers for temporaries *written* (only)+ (w_spills, w_allocd) <-+ allocateRegsAndSpill False{-writing-} virt_written [] [] virt_written++ -- (h) Release registers for temps which are written here and not+ -- used again.+ releaseRegs w_dying++ let+ -- (i) Patch the instruction+ patch_map+ = listToUFM+ [ (t, RegReal r)+ | (t, r) <- zip virt_read r_allocd+ ++ zip virt_written w_allocd ]++ patched_instr+ = patchRegsOfInstr adjusted_instr patchLookup++ patchLookup x+ = case lookupUFM patch_map x of+ Nothing -> x+ Just y -> y+++ -- (j) free up stack slots for dead spilled regs+ -- TODO (can't be bothered right now)++ -- erase reg->reg moves where the source and destination are the same.+ -- If the src temp didn't die in this instr but happened to be allocated+ -- to the same real reg as the destination, then we can erase the move anyway.+ let squashed_instr = case takeRegRegMoveInstr patched_instr of+ Just (src, dst)+ | src == dst -> []+ _ -> [patched_instr]++ let code = squashed_instr ++ w_spills ++ reverse r_spills+ ++ clobber_saves ++ new_instrs++-- pprTrace "patched-code" ((vcat $ map (docToSDoc . pprInstr) code)) $ do+-- pprTrace "pached-fixup" ((ppr fixup_blocks)) $ do++ return (code, fixup_blocks)++ }++-- -----------------------------------------------------------------------------+-- releaseRegs++releaseRegs :: FR freeRegs => [Reg] -> RegM freeRegs ()+releaseRegs regs = do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ assig <- getAssigR+ free <- getFreeRegsR+ let loop assig !free [] = do setAssigR assig; setFreeRegsR free; return ()+ loop assig !free (RegReal rr : rs) = loop assig (frReleaseReg platform rr free) rs+ loop assig !free (r:rs) =+ case lookupUFM assig r of+ Just (InBoth real _) -> loop (delFromUFM assig r)+ (frReleaseReg platform real free) rs+ Just (InReg real) -> loop (delFromUFM assig r)+ (frReleaseReg platform real free) rs+ _ -> loop (delFromUFM assig r) free rs+ loop assig free regs+++-- -----------------------------------------------------------------------------+-- Clobber real registers++-- For each temp in a register that is going to be clobbered:+-- - if the temp dies after this instruction, do nothing+-- - otherwise, put it somewhere safe (another reg if possible,+-- otherwise spill and record InBoth in the assignment).+-- - for allocateRegs on the temps *read*,+-- - clobbered regs are allocatable.+--+-- for allocateRegs on the temps *written*,+-- - clobbered regs are not allocatable.+--++saveClobberedTemps+ :: (Instruction instr, FR freeRegs)+ => [RealReg] -- real registers clobbered by this instruction+ -> [Reg] -- registers which are no longer live after this insn+ -> RegM freeRegs [instr] -- return: instructions to spill any temps that will+ -- be clobbered.++saveClobberedTemps [] _+ = return []++saveClobberedTemps clobbered dying+ = do+ assig <- getAssigR+ let to_spill+ = [ (temp,reg)+ | (temp, InReg reg) <- nonDetUFMToList assig+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ , any (realRegsAlias reg) clobbered+ , temp `notElem` map getUnique dying ]++ (instrs,assig') <- clobber assig [] to_spill+ setAssigR assig'+ return instrs++ where+ clobber assig instrs []+ = return (instrs, assig)++ clobber assig instrs ((temp, reg) : rest)+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags++ freeRegs <- getFreeRegsR+ let regclass = targetClassOfRealReg platform reg+ freeRegs_thisClass = frGetFreeRegs platform regclass freeRegs++ case filter (`notElem` clobbered) freeRegs_thisClass of++ -- (1) we have a free reg of the right class that isn't+ -- clobbered by this instruction; use it to save the+ -- clobbered value.+ (my_reg : _) -> do+ setFreeRegsR (frAllocateReg platform my_reg freeRegs)++ let new_assign = addToUFM assig temp (InReg my_reg)+ let instr = mkRegRegMoveInstr platform+ (RegReal reg) (RegReal my_reg)++ clobber new_assign (instr : instrs) rest++ -- (2) no free registers: spill the value+ [] -> do+ (spill, slot) <- spillR (RegReal reg) temp++ -- record why this reg was spilled for profiling+ recordSpill (SpillClobber temp)++ let new_assign = addToUFM assig temp (InBoth reg slot)++ clobber new_assign (spill : instrs) rest++++-- | Mark all these real regs as allocated,+-- and kick out their vreg assignments.+--+clobberRegs :: FR freeRegs => [RealReg] -> RegM freeRegs ()+clobberRegs []+ = return ()++clobberRegs clobbered+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags++ freeregs <- getFreeRegsR+ setFreeRegsR $! foldl' (flip $ frAllocateReg platform) freeregs clobbered++ assig <- getAssigR+ setAssigR $! clobber assig (nonDetUFMToList assig)+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]++ where+ -- if the temp was InReg and clobbered, then we will have+ -- saved it in saveClobberedTemps above. So the only case+ -- we have to worry about here is InBoth. Note that this+ -- also catches temps which were loaded up during allocation+ -- of read registers, not just those saved in saveClobberedTemps.++ clobber assig []+ = assig++ clobber assig ((temp, InBoth reg slot) : rest)+ | any (realRegsAlias reg) clobbered+ = clobber (addToUFM assig temp (InMem slot)) rest++ clobber assig (_:rest)+ = clobber assig rest++-- -----------------------------------------------------------------------------+-- allocateRegsAndSpill++-- Why are we performing a spill?+data SpillLoc = ReadMem StackSlot -- reading from register only in memory+ | WriteNew -- writing to a new variable+ | WriteMem -- writing to register only in memory+-- Note that ReadNew is not valid, since you don't want to be reading+-- from an uninitialized register. We also don't need the location of+-- the register in memory, since that will be invalidated by the write.+-- Technically, we could coalesce WriteNew and WriteMem into a single+-- entry as well. -- EZY++-- This function does several things:+-- For each temporary referred to by this instruction,+-- we allocate a real register (spilling another temporary if necessary).+-- We load the temporary up from memory if necessary.+-- We also update the register assignment in the process, and+-- the list of free registers and free stack slots.++allocateRegsAndSpill+ :: (FR freeRegs, Outputable instr, Instruction instr)+ => Bool -- True <=> reading (load up spilled regs)+ -> [VirtualReg] -- don't push these out+ -> [instr] -- spill insns+ -> [RealReg] -- real registers allocated (accum.)+ -> [VirtualReg] -- temps to allocate+ -> RegM freeRegs ( [instr] , [RealReg])++allocateRegsAndSpill _ _ spills alloc []+ = return (spills, reverse alloc)++allocateRegsAndSpill reading keep spills alloc (r:rs)+ = do assig <- getAssigR+ let doSpill = allocRegsAndSpill_spill reading keep spills alloc r rs assig+ case lookupUFM assig r of+ -- case (1a): already in a register+ Just (InReg my_reg) ->+ allocateRegsAndSpill reading keep spills (my_reg:alloc) rs++ -- case (1b): already in a register (and memory)+ -- NB1. if we're writing this register, update its assignment to be+ -- InReg, because the memory value is no longer valid.+ -- NB2. This is why we must process written registers here, even if they+ -- are also read by the same instruction.+ Just (InBoth my_reg _)+ -> do when (not reading) (setAssigR (addToUFM assig r (InReg my_reg)))+ allocateRegsAndSpill reading keep spills (my_reg:alloc) rs++ -- Not already in a register, so we need to find a free one...+ Just (InMem slot) | reading -> doSpill (ReadMem slot)+ | otherwise -> doSpill WriteMem+ Nothing | reading ->+ pprPanic "allocateRegsAndSpill: Cannot read from uninitialized register" (ppr r)+ -- NOTE: if the input to the NCG contains some+ -- unreachable blocks with junk code, this panic+ -- might be triggered. Make sure you only feed+ -- sensible code into the NCG. In CmmPipeline we+ -- call removeUnreachableBlocks at the end for this+ -- reason.++ | otherwise -> doSpill WriteNew+++-- reading is redundant with reason, but we keep it around because it's+-- convenient and it maintains the recursive structure of the allocator. -- EZY+allocRegsAndSpill_spill :: (FR freeRegs, Instruction instr, Outputable instr)+ => Bool+ -> [VirtualReg]+ -> [instr]+ -> [RealReg]+ -> VirtualReg+ -> [VirtualReg]+ -> UniqFM Loc+ -> SpillLoc+ -> RegM freeRegs ([instr], [RealReg])+allocRegsAndSpill_spill reading keep spills alloc r rs assig spill_loc+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ freeRegs <- getFreeRegsR+ let freeRegs_thisClass = frGetFreeRegs platform (classOfVirtualReg r) freeRegs++ case freeRegs_thisClass of++ -- case (2): we have a free register+ (my_reg : _) ->+ do spills' <- loadTemp r spill_loc my_reg spills++ setAssigR (addToUFM assig r $! newLocation spill_loc my_reg)+ setFreeRegsR $ frAllocateReg platform my_reg freeRegs++ allocateRegsAndSpill reading keep spills' (my_reg : alloc) rs+++ -- case (3): we need to push something out to free up a register+ [] ->+ do let keep' = map getUnique keep++ -- the vregs we could kick out that are already in a slot+ let candidates_inBoth+ = [ (temp, reg, mem)+ | (temp, InBoth reg mem) <- nonDetUFMToList assig+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ , temp `notElem` keep'+ , targetClassOfRealReg platform reg == classOfVirtualReg r ]++ -- the vregs we could kick out that are only in a reg+ -- this would require writing the reg to a new slot before using it.+ let candidates_inReg+ = [ (temp, reg)+ | (temp, InReg reg) <- nonDetUFMToList assig+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ , temp `notElem` keep'+ , targetClassOfRealReg platform reg == classOfVirtualReg r ]++ let result++ -- we have a temporary that is in both register and mem,+ -- just free up its register for use.+ | (temp, my_reg, slot) : _ <- candidates_inBoth+ = do spills' <- loadTemp r spill_loc my_reg spills+ let assig1 = addToUFM assig temp (InMem slot)+ let assig2 = addToUFM assig1 r $! newLocation spill_loc my_reg++ setAssigR assig2+ allocateRegsAndSpill reading keep spills' (my_reg:alloc) rs++ -- otherwise, we need to spill a temporary that currently+ -- resides in a register.+ | (temp_to_push_out, (my_reg :: RealReg)) : _+ <- candidates_inReg+ = do+ (spill_insn, slot) <- spillR (RegReal my_reg) temp_to_push_out+ let spill_store = (if reading then id else reverse)+ [ -- COMMENT (fsLit "spill alloc")+ spill_insn ]++ -- record that this temp was spilled+ recordSpill (SpillAlloc temp_to_push_out)++ -- update the register assignment+ let assig1 = addToUFM assig temp_to_push_out (InMem slot)+ let assig2 = addToUFM assig1 r $! newLocation spill_loc my_reg+ setAssigR assig2++ -- if need be, load up a spilled temp into the reg we've just freed up.+ spills' <- loadTemp r spill_loc my_reg spills++ allocateRegsAndSpill reading keep+ (spill_store ++ spills')+ (my_reg:alloc) rs+++ -- there wasn't anything to spill, so we're screwed.+ | otherwise+ = pprPanic ("RegAllocLinear.allocRegsAndSpill: no spill candidates\n")+ $ vcat+ [ text "allocating vreg: " <> text (show r)+ , text "assignment: " <> ppr assig+ , text "freeRegs: " <> text (show freeRegs)+ , text "initFreeRegs: " <> text (show (frInitFreeRegs platform `asTypeOf` freeRegs)) ]++ result+++-- | Calculate a new location after a register has been loaded.+newLocation :: SpillLoc -> RealReg -> Loc+-- if the tmp was read from a slot, then now its in a reg as well+newLocation (ReadMem slot) my_reg = InBoth my_reg slot+-- writes will always result in only the register being available+newLocation _ my_reg = InReg my_reg++-- | Load up a spilled temporary if we need to (read from memory).+loadTemp+ :: (Instruction instr)+ => VirtualReg -- the temp being loaded+ -> SpillLoc -- the current location of this temp+ -> RealReg -- the hreg to load the temp into+ -> [instr]+ -> RegM freeRegs [instr]++loadTemp vreg (ReadMem slot) hreg spills+ = do+ insn <- loadR (RegReal hreg) slot+ recordSpill (SpillLoad $ getUnique vreg)+ return $ {- COMMENT (fsLit "spill load") : -} insn : spills++loadTemp _ _ _ spills =+ return spills+
+ nativeGen/RegAlloc/Linear/PPC/FreeRegs.hs view
@@ -0,0 +1,60 @@+-- | Free regs map for PowerPC+module RegAlloc.Linear.PPC.FreeRegs+where++import PPC.Regs+import RegClass+import Reg++import Outputable+import Platform++import Data.Word+import Data.Bits+import Data.Foldable (foldl')++-- The PowerPC has 32 integer and 32 floating point registers.+-- This is 32bit PowerPC, so Word64 is inefficient - two Word32s are much+-- better.+-- Note that when getFreeRegs scans for free registers, it starts at register+-- 31 and counts down. This is a hack for the PowerPC - the higher-numbered+-- registers are callee-saves, while the lower regs are caller-saves, so it+-- makes sense to start at the high end.+-- Apart from that, the code does nothing PowerPC-specific, so feel free to+-- add your favourite platform to the #if (if you have 64 registers but only+-- 32-bit words).++data FreeRegs = FreeRegs !Word32 !Word32+ deriving( Show ) -- The Show is used in an ASSERT++noFreeRegs :: FreeRegs+noFreeRegs = FreeRegs 0 0++releaseReg :: RealReg -> FreeRegs -> FreeRegs+releaseReg (RealRegSingle r) (FreeRegs g f)+ | r > 31 = FreeRegs g (f .|. (1 `shiftL` (r - 32)))+ | otherwise = FreeRegs (g .|. (1 `shiftL` r)) f++releaseReg _ _+ = panic "RegAlloc.Linear.PPC.releaseReg: bad reg"++initFreeRegs :: Platform -> FreeRegs+initFreeRegs platform = foldl' (flip releaseReg) noFreeRegs (allocatableRegs platform)++getFreeRegs :: RegClass -> FreeRegs -> [RealReg] -- lazily+getFreeRegs cls (FreeRegs g f)+ | RcDouble <- cls = go f (0x80000000) 63+ | RcInteger <- cls = go g (0x80000000) 31+ | otherwise = pprPanic "RegAllocLinear.getFreeRegs: Bad register class" (ppr cls)+ where+ go _ 0 _ = []+ go x m i | x .&. m /= 0 = RealRegSingle i : (go x (m `shiftR` 1) $! i-1)+ | otherwise = go x (m `shiftR` 1) $! i-1++allocateReg :: RealReg -> FreeRegs -> FreeRegs+allocateReg (RealRegSingle r) (FreeRegs g f)+ | r > 31 = FreeRegs g (f .&. complement (1 `shiftL` (r - 32)))+ | otherwise = FreeRegs (g .&. complement (1 `shiftL` r)) f++allocateReg _ _+ = panic "RegAlloc.Linear.PPC.allocateReg: bad reg"
+ nativeGen/RegAlloc/Linear/SPARC/FreeRegs.hs view
@@ -0,0 +1,186 @@++-- | Free regs map for SPARC+module RegAlloc.Linear.SPARC.FreeRegs+where++import SPARC.Regs+import RegClass+import Reg++import CodeGen.Platform+import Outputable+import Platform++import Data.Word+import Data.Bits+import Data.Foldable (foldl')+++--------------------------------------------------------------------------------+-- SPARC is like PPC, except for twinning of floating point regs.+-- When we allocate a double reg we must take an even numbered+-- float reg, as well as the one after it.+++-- Holds bitmaps showing what registers are currently allocated.+-- The float and double reg bitmaps overlap, but we only alloc+-- float regs into the float map, and double regs into the double map.+--+-- Free regs have a bit set in the corresponding bitmap.+--+data FreeRegs+ = FreeRegs+ !Word32 -- int reg bitmap regs 0..31+ !Word32 -- float reg bitmap regs 32..63+ !Word32 -- double reg bitmap regs 32..63++instance Show FreeRegs where+ show = showFreeRegs++-- | A reg map where no regs are free to be allocated.+noFreeRegs :: FreeRegs+noFreeRegs = FreeRegs 0 0 0+++-- | The initial set of free regs.+initFreeRegs :: Platform -> FreeRegs+initFreeRegs platform+ = foldl' (flip $ releaseReg platform) noFreeRegs allocatableRegs+++-- | Get all the free registers of this class.+getFreeRegs :: RegClass -> FreeRegs -> [RealReg] -- lazily+getFreeRegs cls (FreeRegs g f d)+ | RcInteger <- cls = map RealRegSingle $ go 1 g 1 0+ | RcFloat <- cls = map RealRegSingle $ go 1 f 1 32+ | RcDouble <- cls = map (\i -> RealRegPair i (i+1)) $ go 2 d 1 32+ | otherwise = pprPanic "RegAllocLinear.getFreeRegs: Bad register class " (ppr cls)+ where+ go _ _ 0 _+ = []++ go step bitmap mask ix+ | bitmap .&. mask /= 0+ = ix : (go step bitmap (mask `shiftL` step) $! ix + step)++ | otherwise+ = go step bitmap (mask `shiftL` step) $! ix + step+++-- | Grab a register.+allocateReg :: Platform -> RealReg -> FreeRegs -> FreeRegs+allocateReg platform+ reg@(RealRegSingle r)+ (FreeRegs g f d)++ -- can't allocate free regs+ | not $ freeReg platform r+ = pprPanic "SPARC.FreeRegs.allocateReg: not allocating pinned reg" (ppr reg)++ -- a general purpose reg+ | r <= 31+ = let mask = complement (bitMask r)+ in FreeRegs+ (g .&. mask)+ f+ d++ -- a float reg+ | r >= 32, r <= 63+ = let mask = complement (bitMask (r - 32))++ -- the mask of the double this FP reg aliases+ maskLow = if r `mod` 2 == 0+ then complement (bitMask (r - 32))+ else complement (bitMask (r - 32 - 1))+ in FreeRegs+ g+ (f .&. mask)+ (d .&. maskLow)++ | otherwise+ = pprPanic "SPARC.FreeRegs.releaseReg: not allocating bad reg" (ppr reg)++allocateReg _+ reg@(RealRegPair r1 r2)+ (FreeRegs g f d)++ | r1 >= 32, r1 <= 63, r1 `mod` 2 == 0+ , r2 >= 32, r2 <= 63+ = let mask1 = complement (bitMask (r1 - 32))+ mask2 = complement (bitMask (r2 - 32))+ in+ FreeRegs+ g+ ((f .&. mask1) .&. mask2)+ (d .&. mask1)++ | otherwise+ = pprPanic "SPARC.FreeRegs.releaseReg: not allocating bad reg" (ppr reg)++++-- | Release a register from allocation.+-- The register liveness information says that most regs die after a C call,+-- but we still don't want to allocate to some of them.+--+releaseReg :: Platform -> RealReg -> FreeRegs -> FreeRegs+releaseReg platform+ reg@(RealRegSingle r)+ regs@(FreeRegs g f d)++ -- don't release pinned reg+ | not $ freeReg platform r+ = regs++ -- a general purpose reg+ | r <= 31+ = let mask = bitMask r+ in FreeRegs (g .|. mask) f d++ -- a float reg+ | r >= 32, r <= 63+ = let mask = bitMask (r - 32)++ -- the mask of the double this FP reg aliases+ maskLow = if r `mod` 2 == 0+ then bitMask (r - 32)+ else bitMask (r - 32 - 1)+ in FreeRegs+ g+ (f .|. mask)+ (d .|. maskLow)++ | otherwise+ = pprPanic "SPARC.FreeRegs.releaseReg: not releasing bad reg" (ppr reg)++releaseReg _+ reg@(RealRegPair r1 r2)+ (FreeRegs g f d)++ | r1 >= 32, r1 <= 63, r1 `mod` 2 == 0+ , r2 >= 32, r2 <= 63+ = let mask1 = bitMask (r1 - 32)+ mask2 = bitMask (r2 - 32)+ in+ FreeRegs+ g+ ((f .|. mask1) .|. mask2)+ (d .|. mask1)++ | otherwise+ = pprPanic "SPARC.FreeRegs.releaseReg: not releasing bad reg" (ppr reg)++++bitMask :: Int -> Word32+bitMask n = 1 `shiftL` n+++showFreeRegs :: FreeRegs -> String+showFreeRegs regs+ = "FreeRegs\n"+ ++ " integer: " ++ (show $ getFreeRegs RcInteger regs) ++ "\n"+ ++ " float: " ++ (show $ getFreeRegs RcFloat regs) ++ "\n"+ ++ " double: " ++ (show $ getFreeRegs RcDouble regs) ++ "\n"+
+ nativeGen/RegAlloc/Linear/StackMap.hs view
@@ -0,0 +1,59 @@++-- | The assignment of virtual registers to stack slots++-- We have lots of stack slots. Memory-to-memory moves are a pain on most+-- architectures. Therefore, we avoid having to generate memory-to-memory moves+-- by simply giving every virtual register its own stack slot.++-- The StackMap stack map keeps track of virtual register - stack slot+-- associations and of which stack slots are still free. Once it has been+-- associated, a stack slot is never "freed" or removed from the StackMap again,+-- it remains associated until we are done with the current CmmProc.+--+module RegAlloc.Linear.StackMap (+ StackSlot,+ StackMap(..),+ emptyStackMap,+ getStackSlotFor,+ getStackUse+)++where++import DynFlags+import UniqFM+import Unique+++-- | Identifier for a stack slot.+type StackSlot = Int++data StackMap+ = StackMap+ { -- | The slots that are still available to be allocated.+ stackMapNextFreeSlot :: !Int++ -- | Assignment of vregs to stack slots.+ , stackMapAssignment :: UniqFM StackSlot }+++-- | An empty stack map, with all slots available.+emptyStackMap :: DynFlags -> StackMap+emptyStackMap _ = StackMap 0 emptyUFM+++-- | If this vreg unique already has a stack assignment then return the slot number,+-- otherwise allocate a new slot, and update the map.+--+getStackSlotFor :: StackMap -> Unique -> (StackMap, Int)++getStackSlotFor fs@(StackMap _ reserved) reg+ | Just slot <- lookupUFM reserved reg = (fs, slot)++getStackSlotFor (StackMap freeSlot reserved) reg =+ (StackMap (freeSlot+1) (addToUFM reserved reg freeSlot), freeSlot)++-- | Return the number of stack slots that were allocated+getStackUse :: StackMap -> Int+getStackUse (StackMap freeSlot _) = freeSlot+
+ nativeGen/RegAlloc/Linear/State.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE UnboxedTuples #-}++-- | State monad for the linear register allocator.++-- Here we keep all the state that the register allocator keeps track+-- of as it walks the instructions in a basic block.++module RegAlloc.Linear.State (+ RA_State(..),+ RegM,+ runR,++ spillR,+ loadR,++ getFreeRegsR,+ setFreeRegsR,++ getAssigR,+ setAssigR,++ getBlockAssigR,+ setBlockAssigR,++ setDeltaR,+ getDeltaR,++ getUniqueR,++ recordSpill+)+where++import RegAlloc.Linear.Stats+import RegAlloc.Linear.StackMap+import RegAlloc.Linear.Base+import RegAlloc.Liveness+import Instruction+import Reg++import DynFlags+import Unique+import UniqSupply++import Control.Monad (liftM, ap)++-- | The register allocator monad type.+newtype RegM freeRegs a+ = RegM { unReg :: RA_State freeRegs -> (# RA_State freeRegs, a #) }++instance Functor (RegM freeRegs) where+ fmap = liftM++instance Applicative (RegM freeRegs) where+ pure a = RegM $ \s -> (# s, a #)+ (<*>) = ap++instance Monad (RegM freeRegs) where+ m >>= k = RegM $ \s -> case unReg m s of { (# s, a #) -> unReg (k a) s }++instance HasDynFlags (RegM a) where+ getDynFlags = RegM $ \s -> (# s, ra_DynFlags s #)+++-- | Run a computation in the RegM register allocator monad.+runR :: DynFlags+ -> BlockAssignment freeRegs+ -> freeRegs+ -> RegMap Loc+ -> StackMap+ -> UniqSupply+ -> RegM freeRegs a+ -> (BlockAssignment freeRegs, StackMap, RegAllocStats, a)++runR dflags block_assig freeregs assig stack us thing =+ case unReg thing+ (RA_State+ { ra_blockassig = block_assig+ , ra_freeregs = freeregs+ , ra_assig = assig+ , ra_delta = 0{-???-}+ , ra_stack = stack+ , ra_us = us+ , ra_spills = []+ , ra_DynFlags = dflags })+ of+ (# state'@RA_State+ { ra_blockassig = block_assig+ , ra_stack = stack' }+ , returned_thing #)++ -> (block_assig, stack', makeRAStats state', returned_thing)+++-- | Make register allocator stats from its final state.+makeRAStats :: RA_State freeRegs -> RegAllocStats+makeRAStats state+ = RegAllocStats+ { ra_spillInstrs = binSpillReasons (ra_spills state) }+++spillR :: Instruction instr+ => Reg -> Unique -> RegM freeRegs (instr, Int)++spillR reg temp = RegM $ \ s@RA_State{ra_delta=delta, ra_stack=stack} ->+ let dflags = ra_DynFlags s+ (stack',slot) = getStackSlotFor stack temp+ instr = mkSpillInstr dflags reg delta slot+ in+ (# s{ra_stack=stack'}, (instr,slot) #)+++loadR :: Instruction instr+ => Reg -> Int -> RegM freeRegs instr++loadR reg slot = RegM $ \ s@RA_State{ra_delta=delta} ->+ let dflags = ra_DynFlags s+ in (# s, mkLoadInstr dflags reg delta slot #)++getFreeRegsR :: RegM freeRegs freeRegs+getFreeRegsR = RegM $ \ s@RA_State{ra_freeregs = freeregs} ->+ (# s, freeregs #)++setFreeRegsR :: freeRegs -> RegM freeRegs ()+setFreeRegsR regs = RegM $ \ s ->+ (# s{ra_freeregs = regs}, () #)++getAssigR :: RegM freeRegs (RegMap Loc)+getAssigR = RegM $ \ s@RA_State{ra_assig = assig} ->+ (# s, assig #)++setAssigR :: RegMap Loc -> RegM freeRegs ()+setAssigR assig = RegM $ \ s ->+ (# s{ra_assig=assig}, () #)++getBlockAssigR :: RegM freeRegs (BlockAssignment freeRegs)+getBlockAssigR = RegM $ \ s@RA_State{ra_blockassig = assig} ->+ (# s, assig #)++setBlockAssigR :: BlockAssignment freeRegs -> RegM freeRegs ()+setBlockAssigR assig = RegM $ \ s ->+ (# s{ra_blockassig = assig}, () #)++setDeltaR :: Int -> RegM freeRegs ()+setDeltaR n = RegM $ \ s ->+ (# s{ra_delta = n}, () #)++getDeltaR :: RegM freeRegs Int+getDeltaR = RegM $ \s -> (# s, ra_delta s #)++getUniqueR :: RegM freeRegs Unique+getUniqueR = RegM $ \s ->+ case takeUniqFromSupply (ra_us s) of+ (uniq, us) -> (# s{ra_us = us}, uniq #)+++-- | Record that a spill instruction was inserted, for profiling.+recordSpill :: SpillReason -> RegM freeRegs ()+recordSpill spill+ = RegM $ \s -> (# s { ra_spills = spill : ra_spills s}, () #)+
+ nativeGen/RegAlloc/Linear/Stats.hs view
@@ -0,0 +1,86 @@+module RegAlloc.Linear.Stats (+ binSpillReasons,+ countRegRegMovesNat,+ pprStats+)++where++import RegAlloc.Linear.Base+import RegAlloc.Liveness+import Instruction++import UniqFM+import Outputable++import Data.List+import State++-- | Build a map of how many times each reg was alloced, clobbered, loaded etc.+binSpillReasons+ :: [SpillReason] -> UniqFM [Int]++binSpillReasons reasons+ = addListToUFM_C+ (zipWith (+))+ emptyUFM+ (map (\reason -> case reason of+ SpillAlloc r -> (r, [1, 0, 0, 0, 0])+ SpillClobber r -> (r, [0, 1, 0, 0, 0])+ SpillLoad r -> (r, [0, 0, 1, 0, 0])+ SpillJoinRR r -> (r, [0, 0, 0, 1, 0])+ SpillJoinRM r -> (r, [0, 0, 0, 0, 1])) reasons)+++-- | Count reg-reg moves remaining in this code.+countRegRegMovesNat+ :: Instruction instr+ => NatCmmDecl statics instr -> Int++countRegRegMovesNat cmm+ = execState (mapGenBlockTopM countBlock cmm) 0+ where+ countBlock b@(BasicBlock _ instrs)+ = do mapM_ countInstr instrs+ return b++ countInstr instr+ | Just _ <- takeRegRegMoveInstr instr+ = do modify (+ 1)+ return instr++ | otherwise+ = return instr+++-- | Pretty print some RegAllocStats+pprStats+ :: Instruction instr+ => [NatCmmDecl statics instr] -> [RegAllocStats] -> SDoc++pprStats code statss+ = let -- sum up all the instrs inserted by the spiller+ spills = foldl' (plusUFM_C (zipWith (+)))+ emptyUFM+ $ map ra_spillInstrs statss++ spillTotals = foldl' (zipWith (+))+ [0, 0, 0, 0, 0]+ $ nonDetEltsUFM spills+ -- See Note [Unique Determinism and code generation]++ -- count how many reg-reg-moves remain in the code+ moves = sum $ map countRegRegMovesNat code++ pprSpill (reg, spills)+ = parens $ (hcat $ punctuate (text ", ") (doubleQuotes (ppr reg) : map ppr spills))++ in ( text "-- spills-added-total"+ $$ text "-- (allocs, clobbers, loads, joinRR, joinRM, reg_reg_moves_remaining)"+ $$ (parens $ (hcat $ punctuate (text ", ") (map ppr spillTotals ++ [ppr moves])))+ $$ text ""+ $$ text "-- spills-added"+ $$ text "-- (reg_name, allocs, clobbers, loads, joinRR, joinRM)"+ $$ (pprUFMWithKeys spills (vcat . map pprSpill))+ $$ text "")+
+ nativeGen/RegAlloc/Linear/X86/FreeRegs.hs view
@@ -0,0 +1,52 @@++-- | Free regs map for i386+module RegAlloc.Linear.X86.FreeRegs+where++import X86.Regs+import RegClass+import Reg+import Panic+import Platform++import Data.Word+import Data.Bits+import Data.Foldable (foldl')++newtype FreeRegs = FreeRegs Word32+ deriving Show++noFreeRegs :: FreeRegs+noFreeRegs = FreeRegs 0++releaseReg :: RealReg -> FreeRegs -> FreeRegs+releaseReg (RealRegSingle n) (FreeRegs f)+ = FreeRegs (f .|. (1 `shiftL` n))++releaseReg _ _+ = panic "RegAlloc.Linear.X86.FreeRegs.releaseReg: no reg"++initFreeRegs :: Platform -> FreeRegs+initFreeRegs platform+ = foldl' (flip releaseReg) noFreeRegs (allocatableRegs platform)++getFreeRegs :: Platform -> RegClass -> FreeRegs -> [RealReg] -- lazily+getFreeRegs platform cls (FreeRegs f) = go f 0++ where go 0 _ = []+ go n m+ | n .&. 1 /= 0 && classOfRealReg platform (RealRegSingle m) == cls+ = RealRegSingle m : (go (n `shiftR` 1) $! (m+1))++ | otherwise+ = go (n `shiftR` 1) $! (m+1)+ -- ToDo: there's no point looking through all the integer registers+ -- in order to find a floating-point one.++allocateReg :: RealReg -> FreeRegs -> FreeRegs+allocateReg (RealRegSingle r) (FreeRegs f)+ = FreeRegs (f .&. complement (1 `shiftL` r))++allocateReg _ _+ = panic "RegAlloc.Linear.X86.FreeRegs.allocateReg: no reg"+
+ nativeGen/RegAlloc/Linear/X86_64/FreeRegs.hs view
@@ -0,0 +1,53 @@++-- | Free regs map for x86_64+module RegAlloc.Linear.X86_64.FreeRegs+where++import X86.Regs+import RegClass+import Reg+import Panic+import Platform++import Data.Foldable (foldl')+import Data.Word+import Data.Bits++newtype FreeRegs = FreeRegs Word64+ deriving Show++noFreeRegs :: FreeRegs+noFreeRegs = FreeRegs 0++releaseReg :: RealReg -> FreeRegs -> FreeRegs+releaseReg (RealRegSingle n) (FreeRegs f)+ = FreeRegs (f .|. (1 `shiftL` n))++releaseReg _ _+ = panic "RegAlloc.Linear.X86_64.FreeRegs.releaseReg: no reg"++initFreeRegs :: Platform -> FreeRegs+initFreeRegs platform+ = foldl' (flip releaseReg) noFreeRegs (allocatableRegs platform)++getFreeRegs :: Platform -> RegClass -> FreeRegs -> [RealReg] -- lazily+getFreeRegs platform cls (FreeRegs f) = go f 0++ where go 0 _ = []+ go n m+ | n .&. 1 /= 0 && classOfRealReg platform (RealRegSingle m) == cls+ = RealRegSingle m : (go (n `shiftR` 1) $! (m+1))++ | otherwise+ = go (n `shiftR` 1) $! (m+1)+ -- ToDo: there's no point looking through all the integer registers+ -- in order to find a floating-point one.++allocateReg :: RealReg -> FreeRegs -> FreeRegs+allocateReg (RealRegSingle r) (FreeRegs f)+ = FreeRegs (f .&. complement (1 `shiftL` r))++allocateReg _ _+ = panic "RegAlloc.Linear.X86_64.FreeRegs.allocateReg: no reg"++
+ nativeGen/RegAlloc/Liveness.hs view
@@ -0,0 +1,1009 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies #-}++-----------------------------------------------------------------------------+--+-- The register liveness determinator+--+-- (c) The University of Glasgow 2004-2013+--+-----------------------------------------------------------------------------++module RegAlloc.Liveness (+ RegSet,+ RegMap, emptyRegMap,+ BlockMap, mapEmpty,+ LiveCmmDecl,+ InstrSR (..),+ LiveInstr (..),+ Liveness (..),+ LiveInfo (..),+ LiveBasicBlock,++ mapBlockTop, mapBlockTopM, mapSCCM,+ mapGenBlockTop, mapGenBlockTopM,+ stripLive,+ stripLiveBlock,+ slurpConflicts,+ slurpReloadCoalesce,+ eraseDeltasLive,+ patchEraseLive,+ patchRegsLiveInstr,+ reverseBlocksInTops,+ regLiveness,+ natCmmTopToLive+ ) where+import Reg+import Instruction++import BlockId+import Hoopl+import Cmm hiding (RegSet, emptyRegSet)+import PprCmm()++import Digraph+import DynFlags+import MonadUtils+import Outputable+import Platform+import UniqSet+import UniqFM+import UniqSupply+import Bag+import State++import Data.List+import Data.Maybe+import Data.IntSet (IntSet)++-----------------------------------------------------------------------------+type RegSet = UniqSet Reg++type RegMap a = UniqFM a++emptyRegMap :: UniqFM a+emptyRegMap = emptyUFM++emptyRegSet :: RegSet+emptyRegSet = emptyUniqSet++type BlockMap a = LabelMap a+++-- | A top level thing which carries liveness information.+type LiveCmmDecl statics instr+ = GenCmmDecl+ statics+ LiveInfo+ [SCC (LiveBasicBlock instr)]+++-- | The register allocator also wants to use SPILL/RELOAD meta instructions,+-- so we'll keep those here.+data InstrSR instr+ -- | A real machine instruction+ = Instr instr++ -- | spill this reg to a stack slot+ | SPILL Reg Int++ -- | reload this reg from a stack slot+ | RELOAD Int Reg++instance Instruction instr => Instruction (InstrSR instr) where+ regUsageOfInstr platform i+ = case i of+ Instr instr -> regUsageOfInstr platform instr+ SPILL reg _ -> RU [reg] []+ RELOAD _ reg -> RU [] [reg]++ patchRegsOfInstr i f+ = case i of+ Instr instr -> Instr (patchRegsOfInstr instr f)+ SPILL reg slot -> SPILL (f reg) slot+ RELOAD slot reg -> RELOAD slot (f reg)++ isJumpishInstr i+ = case i of+ Instr instr -> isJumpishInstr instr+ _ -> False++ jumpDestsOfInstr i+ = case i of+ Instr instr -> jumpDestsOfInstr instr+ _ -> []++ patchJumpInstr i f+ = case i of+ Instr instr -> Instr (patchJumpInstr instr f)+ _ -> i++ mkSpillInstr = error "mkSpillInstr[InstrSR]: Not making SPILL meta-instr"+ mkLoadInstr = error "mkLoadInstr[InstrSR]: Not making LOAD meta-instr"++ takeDeltaInstr i+ = case i of+ Instr instr -> takeDeltaInstr instr+ _ -> Nothing++ isMetaInstr i+ = case i of+ Instr instr -> isMetaInstr instr+ _ -> False++ mkRegRegMoveInstr platform r1 r2+ = Instr (mkRegRegMoveInstr platform r1 r2)++ takeRegRegMoveInstr i+ = case i of+ Instr instr -> takeRegRegMoveInstr instr+ _ -> Nothing++ mkJumpInstr target = map Instr (mkJumpInstr target)++ mkStackAllocInstr platform amount =+ Instr (mkStackAllocInstr platform amount)++ mkStackDeallocInstr platform amount =+ Instr (mkStackDeallocInstr platform amount)+++-- | An instruction with liveness information.+data LiveInstr instr+ = LiveInstr (InstrSR instr) (Maybe Liveness)++-- | Liveness information.+-- The regs which die are ones which are no longer live in the *next* instruction+-- in this sequence.+-- (NB. if the instruction is a jump, these registers might still be live+-- at the jump target(s) - you have to check the liveness at the destination+-- block to find out).++data Liveness+ = Liveness+ { liveBorn :: RegSet -- ^ registers born in this instruction (written to for first time).+ , liveDieRead :: RegSet -- ^ registers that died because they were read for the last time.+ , liveDieWrite :: RegSet } -- ^ registers that died because they were clobbered by something.+++-- | Stash regs live on entry to each basic block in the info part of the cmm code.+data LiveInfo+ = LiveInfo+ (LabelMap CmmStatics) -- cmm info table static stuff+ [BlockId] -- entry points (first one is the+ -- entry point for the proc).+ (Maybe (BlockMap RegSet)) -- argument locals live on entry to this block+ (BlockMap IntSet) -- stack slots live on entry to this block+++-- | A basic block with liveness information.+type LiveBasicBlock instr+ = GenBasicBlock (LiveInstr instr)+++instance Outputable instr+ => Outputable (InstrSR instr) where++ ppr (Instr realInstr)+ = ppr realInstr++ ppr (SPILL reg slot)+ = hcat [+ text "\tSPILL",+ char ' ',+ ppr reg,+ comma,+ text "SLOT" <> parens (int slot)]++ ppr (RELOAD slot reg)+ = hcat [+ text "\tRELOAD",+ char ' ',+ text "SLOT" <> parens (int slot),+ comma,+ ppr reg]++instance Outputable instr+ => Outputable (LiveInstr instr) where++ ppr (LiveInstr instr Nothing)+ = ppr instr++ ppr (LiveInstr instr (Just live))+ = ppr instr+ $$ (nest 8+ $ vcat+ [ pprRegs (text "# born: ") (liveBorn live)+ , pprRegs (text "# r_dying: ") (liveDieRead live)+ , pprRegs (text "# w_dying: ") (liveDieWrite live) ]+ $+$ space)++ where pprRegs :: SDoc -> RegSet -> SDoc+ pprRegs name regs+ | isEmptyUniqSet regs = empty+ | otherwise = name <>+ (pprUFM (getUniqSet regs) (hcat . punctuate space . map ppr))++instance Outputable LiveInfo where+ ppr (LiveInfo mb_static entryIds liveVRegsOnEntry liveSlotsOnEntry)+ = (ppr mb_static)+ $$ text "# entryIds = " <> ppr entryIds+ $$ text "# liveVRegsOnEntry = " <> ppr liveVRegsOnEntry+ $$ text "# liveSlotsOnEntry = " <> text (show liveSlotsOnEntry)++++-- | map a function across all the basic blocks in this code+--+mapBlockTop+ :: (LiveBasicBlock instr -> LiveBasicBlock instr)+ -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr++mapBlockTop f cmm+ = evalState (mapBlockTopM (\x -> return $ f x) cmm) ()+++-- | map a function across all the basic blocks in this code (monadic version)+--+mapBlockTopM+ :: Monad m+ => (LiveBasicBlock instr -> m (LiveBasicBlock instr))+ -> LiveCmmDecl statics instr -> m (LiveCmmDecl statics instr)++mapBlockTopM _ cmm@(CmmData{})+ = return cmm++mapBlockTopM f (CmmProc header label live sccs)+ = do sccs' <- mapM (mapSCCM f) sccs+ return $ CmmProc header label live sccs'++mapSCCM :: Monad m => (a -> m b) -> SCC a -> m (SCC b)+mapSCCM f (AcyclicSCC x)+ = do x' <- f x+ return $ AcyclicSCC x'++mapSCCM f (CyclicSCC xs)+ = do xs' <- mapM f xs+ return $ CyclicSCC xs'+++-- map a function across all the basic blocks in this code+mapGenBlockTop+ :: (GenBasicBlock i -> GenBasicBlock i)+ -> (GenCmmDecl d h (ListGraph i) -> GenCmmDecl d h (ListGraph i))++mapGenBlockTop f cmm+ = evalState (mapGenBlockTopM (\x -> return $ f x) cmm) ()+++-- | map a function across all the basic blocks in this code (monadic version)+mapGenBlockTopM+ :: Monad m+ => (GenBasicBlock i -> m (GenBasicBlock i))+ -> (GenCmmDecl d h (ListGraph i) -> m (GenCmmDecl d h (ListGraph i)))++mapGenBlockTopM _ cmm@(CmmData{})+ = return cmm++mapGenBlockTopM f (CmmProc header label live (ListGraph blocks))+ = do blocks' <- mapM f blocks+ return $ CmmProc header label live (ListGraph blocks')+++-- | Slurp out the list of register conflicts and reg-reg moves from this top level thing.+-- Slurping of conflicts and moves is wrapped up together so we don't have+-- to make two passes over the same code when we want to build the graph.+--+slurpConflicts+ :: Instruction instr+ => LiveCmmDecl statics instr+ -> (Bag (UniqSet Reg), Bag (Reg, Reg))++slurpConflicts live+ = slurpCmm (emptyBag, emptyBag) live++ where slurpCmm rs CmmData{} = rs+ slurpCmm rs (CmmProc info _ _ sccs)+ = foldl' (slurpSCC info) rs sccs++ slurpSCC info rs (AcyclicSCC b)+ = slurpBlock info rs b++ slurpSCC info rs (CyclicSCC bs)+ = foldl' (slurpBlock info) rs bs++ slurpBlock info rs (BasicBlock blockId instrs)+ | LiveInfo _ _ (Just blockLive) _ <- info+ , Just rsLiveEntry <- mapLookup blockId blockLive+ , (conflicts, moves) <- slurpLIs rsLiveEntry rs instrs+ = (consBag rsLiveEntry conflicts, moves)++ | otherwise+ = panic "Liveness.slurpConflicts: bad block"++ slurpLIs rsLive (conflicts, moves) []+ = (consBag rsLive conflicts, moves)++ slurpLIs rsLive rs (LiveInstr _ Nothing : lis)+ = slurpLIs rsLive rs lis++ slurpLIs rsLiveEntry (conflicts, moves) (LiveInstr instr (Just live) : lis)+ = let+ -- regs that die because they are read for the last time at the start of an instruction+ -- are not live across it.+ rsLiveAcross = rsLiveEntry `minusUniqSet` (liveDieRead live)++ -- regs live on entry to the next instruction.+ -- be careful of orphans, make sure to delete dying regs _after_ unioning+ -- in the ones that are born here.+ rsLiveNext = (rsLiveAcross `unionUniqSets` (liveBorn live))+ `minusUniqSet` (liveDieWrite live)++ -- orphan vregs are the ones that die in the same instruction they are born in.+ -- these are likely to be results that are never used, but we still+ -- need to assign a hreg to them..+ rsOrphans = intersectUniqSets+ (liveBorn live)+ (unionUniqSets (liveDieWrite live) (liveDieRead live))++ --+ rsConflicts = unionUniqSets rsLiveNext rsOrphans++ in case takeRegRegMoveInstr instr of+ Just rr -> slurpLIs rsLiveNext+ ( consBag rsConflicts conflicts+ , consBag rr moves) lis++ Nothing -> slurpLIs rsLiveNext+ ( consBag rsConflicts conflicts+ , moves) lis+++-- | For spill\/reloads+--+-- SPILL v1, slot1+-- ...+-- RELOAD slot1, v2+--+-- If we can arrange that v1 and v2 are allocated to the same hreg it's more likely+-- the spill\/reload instrs can be cleaned and replaced by a nop reg-reg move.+--+--+slurpReloadCoalesce+ :: forall statics instr. Instruction instr+ => LiveCmmDecl statics instr+ -> Bag (Reg, Reg)++slurpReloadCoalesce live+ = slurpCmm emptyBag live++ where+ slurpCmm :: Bag (Reg, Reg)+ -> GenCmmDecl t t1 [SCC (LiveBasicBlock instr)]+ -> Bag (Reg, Reg)+ slurpCmm cs CmmData{} = cs+ slurpCmm cs (CmmProc _ _ _ sccs)+ = slurpComp cs (flattenSCCs sccs)++ slurpComp :: Bag (Reg, Reg)+ -> [LiveBasicBlock instr]+ -> Bag (Reg, Reg)+ slurpComp cs blocks+ = let (moveBags, _) = runState (slurpCompM blocks) emptyUFM+ in unionManyBags (cs : moveBags)++ slurpCompM :: [LiveBasicBlock instr]+ -> State (UniqFM [UniqFM Reg]) [Bag (Reg, Reg)]+ slurpCompM blocks+ = do -- run the analysis once to record the mapping across jumps.+ mapM_ (slurpBlock False) blocks++ -- run it a second time while using the information from the last pass.+ -- We /could/ run this many more times to deal with graphical control+ -- flow and propagating info across multiple jumps, but it's probably+ -- not worth the trouble.+ mapM (slurpBlock True) blocks++ slurpBlock :: Bool -> LiveBasicBlock instr+ -> State (UniqFM [UniqFM Reg]) (Bag (Reg, Reg))+ slurpBlock propagate (BasicBlock blockId instrs)+ = do -- grab the slot map for entry to this block+ slotMap <- if propagate+ then getSlotMap blockId+ else return emptyUFM++ (_, mMoves) <- mapAccumLM slurpLI slotMap instrs+ return $ listToBag $ catMaybes mMoves++ slurpLI :: UniqFM Reg -- current slotMap+ -> LiveInstr instr+ -> State (UniqFM [UniqFM Reg]) -- blockId -> [slot -> reg]+ -- for tracking slotMaps across jumps++ ( UniqFM Reg -- new slotMap+ , Maybe (Reg, Reg)) -- maybe a new coalesce edge++ slurpLI slotMap li++ -- remember what reg was stored into the slot+ | LiveInstr (SPILL reg slot) _ <- li+ , slotMap' <- addToUFM slotMap slot reg+ = return (slotMap', Nothing)++ -- add an edge between the this reg and the last one stored into the slot+ | LiveInstr (RELOAD slot reg) _ <- li+ = case lookupUFM slotMap slot of+ Just reg2+ | reg /= reg2 -> return (slotMap, Just (reg, reg2))+ | otherwise -> return (slotMap, Nothing)++ Nothing -> return (slotMap, Nothing)++ -- if we hit a jump, remember the current slotMap+ | LiveInstr (Instr instr) _ <- li+ , targets <- jumpDestsOfInstr instr+ , not $ null targets+ = do mapM_ (accSlotMap slotMap) targets+ return (slotMap, Nothing)++ | otherwise+ = return (slotMap, Nothing)++ -- record a slotmap for an in edge to this block+ accSlotMap slotMap blockId+ = modify (\s -> addToUFM_C (++) s blockId [slotMap])++ -- work out the slot map on entry to this block+ -- if we have slot maps for multiple in-edges then we need to merge them.+ getSlotMap blockId+ = do map <- get+ let slotMaps = fromMaybe [] (lookupUFM map blockId)+ return $ foldr mergeSlotMaps emptyUFM slotMaps++ mergeSlotMaps :: UniqFM Reg -> UniqFM Reg -> UniqFM Reg+ mergeSlotMaps map1 map2+ = listToUFM+ $ [ (k, r1)+ | (k, r1) <- nonDetUFMToList map1+ -- This is non-deterministic but we do not+ -- currently support deterministic code-generation.+ -- See Note [Unique Determinism and code generation]+ , case lookupUFM map2 k of+ Nothing -> False+ Just r2 -> r1 == r2 ]+++-- | Strip away liveness information, yielding NatCmmDecl+stripLive+ :: (Outputable statics, Outputable instr, Instruction instr)+ => DynFlags+ -> LiveCmmDecl statics instr+ -> NatCmmDecl statics instr++stripLive dflags live+ = stripCmm live++ where stripCmm :: (Outputable statics, Outputable instr, Instruction instr)+ => LiveCmmDecl statics instr -> NatCmmDecl statics instr+ stripCmm (CmmData sec ds) = CmmData sec ds+ stripCmm (CmmProc (LiveInfo info (first_id:_) _ _) label live sccs)+ = let final_blocks = flattenSCCs sccs++ -- make sure the block that was first in the input list+ -- stays at the front of the output. This is the entry point+ -- of the proc, and it needs to come first.+ ((first':_), rest')+ = partition ((== first_id) . blockId) final_blocks++ in CmmProc info label live+ (ListGraph $ map (stripLiveBlock dflags) $ first' : rest')++ -- procs used for stg_split_markers don't contain any blocks, and have no first_id.+ stripCmm (CmmProc (LiveInfo info [] _ _) label live [])+ = CmmProc info label live (ListGraph [])++ -- If the proc has blocks but we don't know what the first one was, then we're dead.+ stripCmm proc+ = pprPanic "RegAlloc.Liveness.stripLive: no first_id on proc" (ppr proc)++-- | Strip away liveness information from a basic block,+-- and make real spill instructions out of SPILL, RELOAD pseudos along the way.++stripLiveBlock+ :: Instruction instr+ => DynFlags+ -> LiveBasicBlock instr+ -> NatBasicBlock instr++stripLiveBlock dflags (BasicBlock i lis)+ = BasicBlock i instrs'++ where (instrs', _)+ = runState (spillNat [] lis) 0++ spillNat acc []+ = return (reverse acc)++ spillNat acc (LiveInstr (SPILL reg slot) _ : instrs)+ = do delta <- get+ spillNat (mkSpillInstr dflags reg delta slot : acc) instrs++ spillNat acc (LiveInstr (RELOAD slot reg) _ : instrs)+ = do delta <- get+ spillNat (mkLoadInstr dflags reg delta slot : acc) instrs++ spillNat acc (LiveInstr (Instr instr) _ : instrs)+ | Just i <- takeDeltaInstr instr+ = do put i+ spillNat acc instrs++ spillNat acc (LiveInstr (Instr instr) _ : instrs)+ = spillNat (instr : acc) instrs+++-- | Erase Delta instructions.++eraseDeltasLive+ :: Instruction instr+ => LiveCmmDecl statics instr+ -> LiveCmmDecl statics instr++eraseDeltasLive cmm+ = mapBlockTop eraseBlock cmm+ where+ eraseBlock (BasicBlock id lis)+ = BasicBlock id+ $ filter (\(LiveInstr i _) -> not $ isJust $ takeDeltaInstr i)+ $ lis+++-- | Patch the registers in this code according to this register mapping.+-- also erase reg -> reg moves when the reg is the same.+-- also erase reg -> reg moves when the destination dies in this instr.+patchEraseLive+ :: Instruction instr+ => (Reg -> Reg)+ -> LiveCmmDecl statics instr -> LiveCmmDecl statics instr++patchEraseLive patchF cmm+ = patchCmm cmm+ where+ patchCmm cmm@CmmData{} = cmm++ patchCmm (CmmProc info label live sccs)+ | LiveInfo static id (Just blockMap) mLiveSlots <- info+ = let+ patchRegSet set = mkUniqSet $ map patchF $ nonDetEltsUFM set+ -- See Note [Unique Determinism and code generation]+ blockMap' = mapMap (patchRegSet . getUniqSet) blockMap++ info' = LiveInfo static id (Just blockMap') mLiveSlots+ in CmmProc info' label live $ map patchSCC sccs++ | otherwise+ = panic "RegAlloc.Liveness.patchEraseLive: no blockMap"++ patchSCC (AcyclicSCC b) = AcyclicSCC (patchBlock b)+ patchSCC (CyclicSCC bs) = CyclicSCC (map patchBlock bs)++ patchBlock (BasicBlock id lis)+ = BasicBlock id $ patchInstrs lis++ patchInstrs [] = []+ patchInstrs (li : lis)++ | LiveInstr i (Just live) <- li'+ , Just (r1, r2) <- takeRegRegMoveInstr i+ , eatMe r1 r2 live+ = patchInstrs lis++ | otherwise+ = li' : patchInstrs lis++ where li' = patchRegsLiveInstr patchF li++ eatMe r1 r2 live+ -- source and destination regs are the same+ | r1 == r2 = True++ -- destination reg is never used+ | elementOfUniqSet r2 (liveBorn live)+ , elementOfUniqSet r2 (liveDieRead live) || elementOfUniqSet r2 (liveDieWrite live)+ = True++ | otherwise = False+++-- | Patch registers in this LiveInstr, including the liveness information.+--+patchRegsLiveInstr+ :: Instruction instr+ => (Reg -> Reg)+ -> LiveInstr instr -> LiveInstr instr++patchRegsLiveInstr patchF li+ = case li of+ LiveInstr instr Nothing+ -> LiveInstr (patchRegsOfInstr instr patchF) Nothing++ LiveInstr instr (Just live)+ -> LiveInstr+ (patchRegsOfInstr instr patchF)+ (Just live+ { -- WARNING: have to go via lists here because patchF changes the uniq in the Reg+ liveBorn = mapUniqSet patchF $ liveBorn live+ , liveDieRead = mapUniqSet patchF $ liveDieRead live+ , liveDieWrite = mapUniqSet patchF $ liveDieWrite live })+ -- See Note [Unique Determinism and code generation]+++--------------------------------------------------------------------------------+-- | Convert a NatCmmDecl to a LiveCmmDecl, with empty liveness information++natCmmTopToLive+ :: Instruction instr+ => NatCmmDecl statics instr+ -> LiveCmmDecl statics instr++natCmmTopToLive (CmmData i d)+ = CmmData i d++natCmmTopToLive (CmmProc info lbl live (ListGraph []))+ = CmmProc (LiveInfo info [] Nothing mapEmpty) lbl live []++natCmmTopToLive proc@(CmmProc info lbl live (ListGraph blocks@(first : _)))+ = let first_id = blockId first+ all_entry_ids = entryBlocks proc+ sccs = sccBlocks blocks all_entry_ids+ entry_ids = filter (/= first_id) all_entry_ids+ sccsLive = map (fmap (\(BasicBlock l instrs) ->+ BasicBlock l (map (\i -> LiveInstr (Instr i) Nothing) instrs)))+ $ sccs++ in CmmProc (LiveInfo info (first_id : entry_ids) Nothing mapEmpty)+ lbl live sccsLive+++--+-- Compute the liveness graph of the set of basic blocks. Important:+-- we also discard any unreachable code here, starting from the entry+-- points (the first block in the list, and any blocks with info+-- tables). Unreachable code arises when code blocks are orphaned in+-- earlier optimisation passes, and may confuse the register allocator+-- by referring to registers that are not initialised. It's easy to+-- discard the unreachable code as part of the SCC pass, so that's+-- exactly what we do. (#7574)+--+sccBlocks+ :: Instruction instr+ => [NatBasicBlock instr]+ -> [BlockId]+ -> [SCC (NatBasicBlock instr)]++sccBlocks blocks entries = map (fmap get_node) sccs+ where+ -- nodes :: [(NatBasicBlock instr, Unique, [Unique])]+ nodes = [ (block, id, getOutEdges instrs)+ | block@(BasicBlock id instrs) <- blocks ]++ g1 = graphFromEdgedVerticesUniq nodes++ reachable :: LabelSet+ reachable = setFromList [ id | (_,id,_) <- reachablesG g1 roots ]++ g2 = graphFromEdgedVerticesUniq [ node | node@(_,id,_) <- nodes+ , id `setMember` reachable ]++ sccs = stronglyConnCompG g2++ get_node (n, _, _) = n++ getOutEdges :: Instruction instr => [instr] -> [BlockId]+ getOutEdges instrs = concat $ map jumpDestsOfInstr instrs++ -- This is truly ugly, but I don't see a good alternative.+ -- Digraph just has the wrong API. We want to identify nodes+ -- by their keys (BlockId), but Digraph requires the whole+ -- node: (NatBasicBlock, BlockId, [BlockId]). This takes+ -- advantage of the fact that Digraph only looks at the key,+ -- even though it asks for the whole triple.+ roots = [(panic "sccBlocks",b,panic "sccBlocks") | b <- entries ]++++--------------------------------------------------------------------------------+-- Annotate code with register liveness information+--+regLiveness+ :: (Outputable instr, Instruction instr)+ => Platform+ -> LiveCmmDecl statics instr+ -> UniqSM (LiveCmmDecl statics instr)++regLiveness _ (CmmData i d)+ = return $ CmmData i d++regLiveness _ (CmmProc info lbl live [])+ | LiveInfo static mFirst _ _ <- info+ = return $ CmmProc+ (LiveInfo static mFirst (Just mapEmpty) mapEmpty)+ lbl live []++regLiveness platform (CmmProc info lbl live sccs)+ | LiveInfo static mFirst _ liveSlotsOnEntry <- info+ = let (ann_sccs, block_live) = computeLiveness platform sccs++ in return $ CmmProc (LiveInfo static mFirst (Just block_live) liveSlotsOnEntry)+ lbl live ann_sccs+++-- -----------------------------------------------------------------------------+-- | Check ordering of Blocks+-- The computeLiveness function requires SCCs to be in reverse+-- dependent order. If they're not the liveness information will be+-- wrong, and we'll get a bad allocation. Better to check for this+-- precondition explicitly or some other poor sucker will waste a+-- day staring at bad assembly code..+--+checkIsReverseDependent+ :: Instruction instr+ => [SCC (LiveBasicBlock instr)] -- ^ SCCs of blocks that we're about to run the liveness determinator on.+ -> Maybe BlockId -- ^ BlockIds that fail the test (if any)++checkIsReverseDependent sccs'+ = go emptyUniqSet sccs'++ where go _ []+ = Nothing++ go blocksSeen (AcyclicSCC block : sccs)+ = let dests = slurpJumpDestsOfBlock block+ blocksSeen' = unionUniqSets blocksSeen $ mkUniqSet [blockId block]+ badDests = dests `minusUniqSet` blocksSeen'+ in case nonDetEltsUniqSet badDests of+ -- See Note [Unique Determinism and code generation]+ [] -> go blocksSeen' sccs+ bad : _ -> Just bad++ go blocksSeen (CyclicSCC blocks : sccs)+ = let dests = unionManyUniqSets $ map slurpJumpDestsOfBlock blocks+ blocksSeen' = unionUniqSets blocksSeen $ mkUniqSet $ map blockId blocks+ badDests = dests `minusUniqSet` blocksSeen'+ in case nonDetEltsUniqSet badDests of+ -- See Note [Unique Determinism and code generation]+ [] -> go blocksSeen' sccs+ bad : _ -> Just bad++ slurpJumpDestsOfBlock (BasicBlock _ instrs)+ = unionManyUniqSets+ $ map (mkUniqSet . jumpDestsOfInstr)+ [ i | LiveInstr i _ <- instrs]+++-- | If we've compute liveness info for this code already we have to reverse+-- the SCCs in each top to get them back to the right order so we can do it again.+reverseBlocksInTops :: LiveCmmDecl statics instr -> LiveCmmDecl statics instr+reverseBlocksInTops top+ = case top of+ CmmData{} -> top+ CmmProc info lbl live sccs -> CmmProc info lbl live (reverse sccs)+++-- | Computing liveness+--+-- On entry, the SCCs must be in "reverse" order: later blocks may transfer+-- control to earlier ones only, else `panic`.+--+-- The SCCs returned are in the *opposite* order, which is exactly what we+-- want for the next pass.+--+computeLiveness+ :: (Outputable instr, Instruction instr)+ => Platform+ -> [SCC (LiveBasicBlock instr)]+ -> ([SCC (LiveBasicBlock instr)], -- instructions annotated with list of registers+ -- which are "dead after this instruction".+ BlockMap RegSet) -- blocks annotated with set of live registers+ -- on entry to the block.++computeLiveness platform sccs+ = case checkIsReverseDependent sccs of+ Nothing -> livenessSCCs platform mapEmpty [] sccs+ Just bad -> pprPanic "RegAlloc.Liveness.computeLivenss"+ (vcat [ text "SCCs aren't in reverse dependent order"+ , text "bad blockId" <+> ppr bad+ , ppr sccs])++livenessSCCs+ :: Instruction instr+ => Platform+ -> BlockMap RegSet+ -> [SCC (LiveBasicBlock instr)] -- accum+ -> [SCC (LiveBasicBlock instr)]+ -> ( [SCC (LiveBasicBlock instr)]+ , BlockMap RegSet)++livenessSCCs _ blockmap done []+ = (done, blockmap)++livenessSCCs platform blockmap done (AcyclicSCC block : sccs)+ = let (blockmap', block') = livenessBlock platform blockmap block+ in livenessSCCs platform blockmap' (AcyclicSCC block' : done) sccs++livenessSCCs platform blockmap done+ (CyclicSCC blocks : sccs) =+ livenessSCCs platform blockmap' (CyclicSCC blocks':done) sccs+ where (blockmap', blocks')+ = iterateUntilUnchanged linearLiveness equalBlockMaps+ blockmap blocks++ iterateUntilUnchanged+ :: (a -> b -> (a,c)) -> (a -> a -> Bool)+ -> a -> b+ -> (a,c)++ iterateUntilUnchanged f eq a b+ = head $+ concatMap tail $+ groupBy (\(a1, _) (a2, _) -> eq a1 a2) $+ iterate (\(a, _) -> f a b) $+ (a, panic "RegLiveness.livenessSCCs")+++ linearLiveness+ :: Instruction instr+ => BlockMap RegSet -> [LiveBasicBlock instr]+ -> (BlockMap RegSet, [LiveBasicBlock instr])++ linearLiveness = mapAccumL (livenessBlock platform)++ -- probably the least efficient way to compare two+ -- BlockMaps for equality.+ equalBlockMaps a b+ = a' == b'+ where a' = map f $ mapToList a+ b' = map f $ mapToList b+ f (key,elt) = (key, nonDetEltsUniqSet elt)+ -- See Note [Unique Determinism and code generation]++++-- | Annotate a basic block with register liveness information.+--+livenessBlock+ :: Instruction instr+ => Platform+ -> BlockMap RegSet+ -> LiveBasicBlock instr+ -> (BlockMap RegSet, LiveBasicBlock instr)++livenessBlock platform blockmap (BasicBlock block_id instrs)+ = let+ (regsLiveOnEntry, instrs1)+ = livenessBack platform emptyUniqSet blockmap [] (reverse instrs)+ blockmap' = mapInsert block_id regsLiveOnEntry blockmap++ instrs2 = livenessForward platform regsLiveOnEntry instrs1++ output = BasicBlock block_id instrs2++ in ( blockmap', output)++-- | Calculate liveness going forwards,+-- filling in when regs are born++livenessForward+ :: Instruction instr+ => Platform+ -> RegSet -- regs live on this instr+ -> [LiveInstr instr] -> [LiveInstr instr]++livenessForward _ _ [] = []+livenessForward platform rsLiveEntry (li@(LiveInstr instr mLive) : lis)+ | Just live <- mLive+ = let+ RU _ written = regUsageOfInstr platform instr+ -- Regs that are written to but weren't live on entry to this instruction+ -- are recorded as being born here.+ rsBorn = mkUniqSet+ $ filter (\r -> not $ elementOfUniqSet r rsLiveEntry) written++ rsLiveNext = (rsLiveEntry `unionUniqSets` rsBorn)+ `minusUniqSet` (liveDieRead live)+ `minusUniqSet` (liveDieWrite live)++ in LiveInstr instr (Just live { liveBorn = rsBorn })+ : livenessForward platform rsLiveNext lis++ | otherwise+ = li : livenessForward platform rsLiveEntry lis+++-- | Calculate liveness going backwards,+-- filling in when regs die, and what regs are live across each instruction++livenessBack+ :: Instruction instr+ => Platform+ -> RegSet -- regs live on this instr+ -> BlockMap RegSet -- regs live on entry to other BBs+ -> [LiveInstr instr] -- instructions (accum)+ -> [LiveInstr instr] -- instructions+ -> (RegSet, [LiveInstr instr])++livenessBack _ liveregs _ done [] = (liveregs, done)++livenessBack platform liveregs blockmap acc (instr : instrs)+ = let (liveregs', instr') = liveness1 platform liveregs blockmap instr+ in livenessBack platform liveregs' blockmap (instr' : acc) instrs+++-- don't bother tagging comments or deltas with liveness+liveness1+ :: Instruction instr+ => Platform+ -> RegSet+ -> BlockMap RegSet+ -> LiveInstr instr+ -> (RegSet, LiveInstr instr)++liveness1 _ liveregs _ (LiveInstr instr _)+ | isMetaInstr instr+ = (liveregs, LiveInstr instr Nothing)++liveness1 platform liveregs blockmap (LiveInstr instr _)++ | not_a_branch+ = (liveregs1, LiveInstr instr+ (Just $ Liveness+ { liveBorn = emptyUniqSet+ , liveDieRead = mkUniqSet r_dying+ , liveDieWrite = mkUniqSet w_dying }))++ | otherwise+ = (liveregs_br, LiveInstr instr+ (Just $ Liveness+ { liveBorn = emptyUniqSet+ , liveDieRead = mkUniqSet r_dying_br+ , liveDieWrite = mkUniqSet w_dying }))++ where+ !(RU read written) = regUsageOfInstr platform instr++ -- registers that were written here are dead going backwards.+ -- registers that were read here are live going backwards.+ liveregs1 = (liveregs `delListFromUniqSet` written)+ `addListToUniqSet` read++ -- registers that are not live beyond this point, are recorded+ -- as dying here.+ r_dying = [ reg | reg <- read, reg `notElem` written,+ not (elementOfUniqSet reg liveregs) ]++ w_dying = [ reg | reg <- written,+ not (elementOfUniqSet reg liveregs) ]++ -- union in the live regs from all the jump destinations of this+ -- instruction.+ targets = jumpDestsOfInstr instr -- where we go from here+ not_a_branch = null targets++ targetLiveRegs target+ = case mapLookup target blockmap of+ Just ra -> ra+ Nothing -> emptyRegSet++ live_from_branch = unionManyUniqSets (map targetLiveRegs targets)++ liveregs_br = liveregs1 `unionUniqSets` live_from_branch++ -- registers that are live only in the branch targets should+ -- be listed as dying here.+ live_branch_only = live_from_branch `minusUniqSet` liveregs+ r_dying_br = nonDetEltsUniqSet (mkUniqSet r_dying `unionUniqSets`+ live_branch_only)+ -- See Note [Unique Determinism and code generation]++
+ nativeGen/RegClass.hs view
@@ -0,0 +1,33 @@+-- | An architecture independent description of a register's class.+module RegClass+ ( RegClass (..) )++where++import Outputable+import Unique+++-- | The class of a register.+-- Used in the register allocator.+-- We treat all registers in a class as being interchangable.+--+data RegClass+ = RcInteger+ | RcFloat+ | RcDouble+ | RcDoubleSSE -- x86 only: the SSE regs are a separate class+ deriving Eq+++instance Uniquable RegClass where+ getUnique RcInteger = mkRegClassUnique 0+ getUnique RcFloat = mkRegClassUnique 1+ getUnique RcDouble = mkRegClassUnique 2+ getUnique RcDoubleSSE = mkRegClassUnique 3++instance Outputable RegClass where+ ppr RcInteger = Outputable.text "I"+ ppr RcFloat = Outputable.text "F"+ ppr RcDouble = Outputable.text "D"+ ppr RcDoubleSSE = Outputable.text "S"
+ nativeGen/SPARC/AddrMode.hs view
@@ -0,0 +1,42 @@++module SPARC.AddrMode (+ AddrMode(..),+ addrOffset+)++where++import SPARC.Imm+import SPARC.Base+import Reg++-- addressing modes ------------------------------------------------------------++-- | Represents a memory address in an instruction.+-- Being a RISC machine, the SPARC addressing modes are very regular.+--+data AddrMode+ = AddrRegReg Reg Reg -- addr = r1 + r2+ | AddrRegImm Reg Imm -- addr = r1 + imm+++-- | Add an integer offset to the address in an AddrMode.+--+addrOffset :: AddrMode -> Int -> Maybe AddrMode+addrOffset addr off+ = case addr of+ AddrRegImm r (ImmInt n)+ | fits13Bits n2 -> Just (AddrRegImm r (ImmInt n2))+ | otherwise -> Nothing+ where n2 = n + off++ AddrRegImm r (ImmInteger n)+ | fits13Bits n2 -> Just (AddrRegImm r (ImmInt (fromInteger n2)))+ | otherwise -> Nothing+ where n2 = n + toInteger off++ AddrRegReg r (RegReal (RealRegSingle 0))+ | fits13Bits off -> Just (AddrRegImm r (ImmInt off))+ | otherwise -> Nothing++ _ -> Nothing
+ nativeGen/SPARC/Base.hs view
@@ -0,0 +1,75 @@++-- | Bits and pieces on the bottom of the module dependency tree.+-- Also import the required constants, so we know what we're using.+--+-- In the interests of cross-compilation, we want to free ourselves+-- from the autoconf generated modules like main/Constants++module SPARC.Base (+ wordLength,+ wordLengthInBits,+ spillAreaLength,+ spillSlotSize,+ extraStackArgsHere,+ fits13Bits,+ is32BitInteger,+ largeOffsetError+)++where++import DynFlags+import Panic++import Data.Int+++-- On 32 bit SPARC, pointers are 32 bits.+wordLength :: Int+wordLength = 4++wordLengthInBits :: Int+wordLengthInBits+ = wordLength * 8++-- Size of the available spill area+spillAreaLength :: DynFlags -> Int+spillAreaLength+ = rESERVED_C_STACK_BYTES++-- | We need 8 bytes because our largest registers are 64 bit.+spillSlotSize :: Int+spillSlotSize = 8+++-- | We (allegedly) put the first six C-call arguments in registers;+-- where do we start putting the rest of them?+extraStackArgsHere :: Int+extraStackArgsHere = 23+++{-# SPECIALIZE fits13Bits :: Int -> Bool, Integer -> Bool #-}+-- | Check whether an offset is representable with 13 bits.+fits13Bits :: Integral a => a -> Bool+fits13Bits x = x >= -4096 && x < 4096++-- | Check whether an integer will fit in 32 bits.+-- A CmmInt is intended to be truncated to the appropriate+-- number of bits, so here we truncate it to Int64. This is+-- important because e.g. -1 as a CmmInt might be either+-- -1 or 18446744073709551615.+--+is32BitInteger :: Integer -> Bool+is32BitInteger i+ = i64 <= 0x7fffffff && i64 >= -0x80000000+ where i64 = fromIntegral i :: Int64+++-- | Sadness.+largeOffsetError :: (Show a) => a -> b+largeOffsetError i+ = panic ("ERROR: SPARC native-code generator cannot handle large offset ("+ ++ show i ++ ");\nprobably because of large constant data structures;" +++ "\nworkaround: use -fllvm on this module.\n")++
+ nativeGen/SPARC/CodeGen.hs view
@@ -0,0 +1,674 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Generating machine code (instruction selection)+--+-- (c) The University of Glasgow 1996-2013+--+-----------------------------------------------------------------------------++{-# LANGUAGE GADTs #-}+module SPARC.CodeGen (+ cmmTopCodeGen,+ generateJumpTableForInstr,+ InstrBlock+)++where++#include "HsVersions.h"+#include "nativeGen/NCG.h"+#include "MachDeps.h"++-- NCG stuff:+import SPARC.Base+import SPARC.CodeGen.Sanity+import SPARC.CodeGen.Amode+import SPARC.CodeGen.CondCode+import SPARC.CodeGen.Gen64+import SPARC.CodeGen.Gen32+import SPARC.CodeGen.Base+import SPARC.Ppr ()+import SPARC.Instr+import SPARC.Imm+import SPARC.AddrMode+import SPARC.Regs+import SPARC.Stack+import Instruction+import Format+import NCGMonad++-- Our intermediate code:+import BlockId+import Cmm+import CmmUtils+import CmmSwitch+import Hoopl+import PIC+import Reg+import CLabel+import CPrim++-- The rest:+import BasicTypes+import DynFlags+import FastString+import OrdList+import Outputable+import Platform+import Unique++import Control.Monad ( mapAndUnzipM )++-- | Top level code generation+cmmTopCodeGen :: RawCmmDecl+ -> NatM [NatCmmDecl CmmStatics Instr]++cmmTopCodeGen (CmmProc info lab live graph)+ = do let blocks = toBlockListEntryFirst graph+ (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks++ let proc = CmmProc info lab live (ListGraph $ concat nat_blocks)+ let tops = proc : concat statics++ return tops++cmmTopCodeGen (CmmData sec dat) = do+ return [CmmData sec dat] -- no translation, we just use CmmStatic+++-- | Do code generation on a single block of CMM code.+-- code generation may introduce new basic block boundaries, which+-- are indicated by the NEWBLOCK instruction. We must split up the+-- instruction stream into basic blocks again. Also, we extract+-- LDATAs here too.+basicBlockCodeGen :: CmmBlock+ -> NatM ( [NatBasicBlock Instr]+ , [NatCmmDecl CmmStatics Instr])++basicBlockCodeGen block = do+ let (_, nodes, tail) = blockSplit block+ id = entryLabel block+ stmts = blockToList nodes+ mid_instrs <- stmtsToInstrs stmts+ tail_instrs <- stmtToInstrs tail+ let instrs = mid_instrs `appOL` tail_instrs+ let+ (top,other_blocks,statics)+ = foldrOL mkBlocks ([],[],[]) instrs++ mkBlocks (NEWBLOCK id) (instrs,blocks,statics)+ = ([], BasicBlock id instrs : blocks, statics)++ mkBlocks (LDATA sec dat) (instrs,blocks,statics)+ = (instrs, blocks, CmmData sec dat:statics)++ mkBlocks instr (instrs,blocks,statics)+ = (instr:instrs, blocks, statics)++ -- do intra-block sanity checking+ blocksChecked+ = map (checkBlock block)+ $ BasicBlock id top : other_blocks++ return (blocksChecked, statics)+++-- | Convert some Cmm statements to SPARC instructions.+stmtsToInstrs :: [CmmNode e x] -> NatM InstrBlock+stmtsToInstrs stmts+ = do instrss <- mapM stmtToInstrs stmts+ return (concatOL instrss)+++stmtToInstrs :: CmmNode e x -> NatM InstrBlock+stmtToInstrs stmt = do+ dflags <- getDynFlags+ case stmt of+ CmmComment s -> return (unitOL (COMMENT s))+ CmmTick {} -> return nilOL+ CmmUnwind {} -> return nilOL++ CmmAssign reg src+ | isFloatType ty -> assignReg_FltCode format reg src+ | isWord64 ty -> assignReg_I64Code reg src+ | otherwise -> assignReg_IntCode format reg src+ where ty = cmmRegType dflags reg+ format = cmmTypeFormat ty++ CmmStore addr src+ | isFloatType ty -> assignMem_FltCode format addr src+ | isWord64 ty -> assignMem_I64Code addr src+ | otherwise -> assignMem_IntCode format addr src+ where ty = cmmExprType dflags src+ format = cmmTypeFormat ty++ CmmUnsafeForeignCall target result_regs args+ -> genCCall target result_regs args++ CmmBranch id -> genBranch id+ CmmCondBranch arg true false _ -> do+ b1 <- genCondJump true arg+ b2 <- genBranch false+ return (b1 `appOL` b2)+ CmmSwitch arg ids -> do dflags <- getDynFlags+ genSwitch dflags arg ids+ CmmCall { cml_target = arg } -> genJump arg++ _+ -> panic "stmtToInstrs: statement should have been cps'd away"+++{-+Now, given a tree (the argument to an CmmLoad) that references memory,+produce a suitable addressing mode.++A Rule of the Game (tm) for Amodes: use of the addr bit must+immediately follow use of the code part, since the code part puts+values in registers which the addr then refers to. So you can't put+anything in between, lest it overwrite some of those registers. If+you need to do some other computation between the code part and use of+the addr bit, first store the effective address from the amode in a+temporary, then do the other computation, and then use the temporary:++ code+ LEA amode, tmp+ ... other computation ...+ ... (tmp) ...+-}++++-- | Convert a BlockId to some CmmStatic data+jumpTableEntry :: DynFlags -> Maybe BlockId -> CmmStatic+jumpTableEntry dflags Nothing = CmmStaticLit (CmmInt 0 (wordWidth dflags))+jumpTableEntry _ (Just blockid) = CmmStaticLit (CmmLabel blockLabel)+ where blockLabel = mkAsmTempLabel (getUnique blockid)++++-- -----------------------------------------------------------------------------+-- Generating assignments++-- Assignments are really at the heart of the whole code generation+-- business. Almost all top-level nodes of any real importance are+-- assignments, which correspond to loads, stores, or register+-- transfers. If we're really lucky, some of the register transfers+-- will go away, because we can use the destination register to+-- complete the code generation for the right hand side. This only+-- fails when the right hand side is forced into a fixed register+-- (e.g. the result of a call).++assignMem_IntCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock+assignMem_IntCode pk addr src = do+ (srcReg, code) <- getSomeReg src+ Amode dstAddr addr_code <- getAmode addr+ return $ code `appOL` addr_code `snocOL` ST pk srcReg dstAddr+++assignReg_IntCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock+assignReg_IntCode _ reg src = do+ dflags <- getDynFlags+ r <- getRegister src+ let dst = getRegisterReg (targetPlatform dflags) reg+ return $ case r of+ Any _ code -> code dst+ Fixed _ freg fcode -> fcode `snocOL` OR False g0 (RIReg freg) dst++++-- Floating point assignment to memory+assignMem_FltCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock+assignMem_FltCode pk addr src = do+ dflags <- getDynFlags+ Amode dst__2 code1 <- getAmode addr+ (src__2, code2) <- getSomeReg src+ tmp1 <- getNewRegNat pk+ let+ pk__2 = cmmExprType dflags src+ code__2 = code1 `appOL` code2 `appOL`+ if formatToWidth pk == typeWidth pk__2+ then unitOL (ST pk src__2 dst__2)+ else toOL [ FxTOy (cmmTypeFormat pk__2) pk src__2 tmp1+ , ST pk tmp1 dst__2]+ return code__2++-- Floating point assignment to a register/temporary+assignReg_FltCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock+assignReg_FltCode pk dstCmmReg srcCmmExpr = do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ srcRegister <- getRegister srcCmmExpr+ let dstReg = getRegisterReg platform dstCmmReg++ return $ case srcRegister of+ Any _ code -> code dstReg+ Fixed _ srcFixedReg srcCode -> srcCode `snocOL` FMOV pk srcFixedReg dstReg+++++genJump :: CmmExpr{-the branch target-} -> NatM InstrBlock++genJump (CmmLit (CmmLabel lbl))+ = return (toOL [CALL (Left target) 0 True, NOP])+ where+ target = ImmCLbl lbl++genJump tree+ = do+ (target, code) <- getSomeReg tree+ return (code `snocOL` JMP (AddrRegReg target g0) `snocOL` NOP)++-- -----------------------------------------------------------------------------+-- Unconditional branches++genBranch :: BlockId -> NatM InstrBlock+genBranch = return . toOL . mkJumpInstr+++-- -----------------------------------------------------------------------------+-- Conditional jumps++{-+Conditional jumps are always to local labels, so we can use branch+instructions. We peek at the arguments to decide what kind of+comparison to do.++SPARC: First, we have to ensure that the condition codes are set+according to the supplied comparison operation. We generate slightly+different code for floating point comparisons, because a floating+point operation cannot directly precede a @BF@. We assume the worst+and fill that slot with a @NOP@.++SPARC: Do not fill the delay slots here; you will confuse the register+allocator.+-}+++genCondJump+ :: BlockId -- the branch target+ -> CmmExpr -- the condition on which to branch+ -> NatM InstrBlock++++genCondJump bid bool = do+ CondCode is_float cond code <- getCondCode bool+ return (+ code `appOL`+ toOL (+ if is_float+ then [NOP, BF cond False bid, NOP]+ else [BI cond False bid, NOP]+ )+ )++++-- -----------------------------------------------------------------------------+-- Generating a table-branch++genSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> NatM InstrBlock+genSwitch dflags expr targets+ | gopt Opt_PIC dflags+ = error "MachCodeGen: sparc genSwitch PIC not finished\n"++ | otherwise+ = do (e_reg, e_code) <- getSomeReg (cmmOffset dflags expr offset)++ base_reg <- getNewRegNat II32+ offset_reg <- getNewRegNat II32+ dst <- getNewRegNat II32++ label <- getNewLabelNat++ return $ e_code `appOL`+ toOL+ [ -- load base of jump table+ SETHI (HI (ImmCLbl label)) base_reg+ , OR False base_reg (RIImm $ LO $ ImmCLbl label) base_reg++ -- the addrs in the table are 32 bits wide..+ , SLL e_reg (RIImm $ ImmInt 2) offset_reg++ -- load and jump to the destination+ , LD II32 (AddrRegReg base_reg offset_reg) dst+ , JMP_TBL (AddrRegImm dst (ImmInt 0)) ids label+ , NOP ]+ where (offset, ids) = switchTargetsToTable targets++generateJumpTableForInstr :: DynFlags -> Instr+ -> Maybe (NatCmmDecl CmmStatics Instr)+generateJumpTableForInstr dflags (JMP_TBL _ ids label) =+ let jumpTable = map (jumpTableEntry dflags) ids+ in Just (CmmData (Section ReadOnlyData label) (Statics label jumpTable))+generateJumpTableForInstr _ _ = Nothing++++-- -----------------------------------------------------------------------------+-- Generating C calls++{-+ Now the biggest nightmare---calls. Most of the nastiness is buried in+ @get_arg@, which moves the arguments to the correct registers/stack+ locations. Apart from that, the code is easy.++ The SPARC calling convention is an absolute+ nightmare. The first 6x32 bits of arguments are mapped into+ %o0 through %o5, and the remaining arguments are dumped to the+ stack, beginning at [%sp+92]. (Note that %o6 == %sp.)++ If we have to put args on the stack, move %o6==%sp down by+ the number of words to go on the stack, to ensure there's enough space.++ According to Fraser and Hanson's lcc book, page 478, fig 17.2,+ 16 words above the stack pointer is a word for the address of+ a structure return value. I use this as a temporary location+ for moving values from float to int regs. Certainly it isn't+ safe to put anything in the 16 words starting at %sp, since+ this area can get trashed at any time due to window overflows+ caused by signal handlers.++ A final complication (if the above isn't enough) is that+ we can't blithely calculate the arguments one by one into+ %o0 .. %o5. Consider the following nested calls:++ fff a (fff b c)++ Naive code moves a into %o0, and (fff b c) into %o1. Unfortunately+ the inner call will itself use %o0, which trashes the value put there+ in preparation for the outer call. Upshot: we need to calculate the+ args into temporary regs, and move those to arg regs or onto the+ stack only immediately prior to the call proper. Sigh.+-}++genCCall+ :: ForeignTarget -- function to call+ -> [CmmFormal] -- where to put the result+ -> [CmmActual] -- arguments (of mixed type)+ -> NatM InstrBlock++++-- On SPARC under TSO (Total Store Ordering), writes earlier in the instruction stream+-- are guaranteed to take place before writes afterwards (unlike on PowerPC).+-- Ref: Section 8.4 of the SPARC V9 Architecture manual.+--+-- In the SPARC case we don't need a barrier.+--+genCCall (PrimTarget MO_WriteBarrier) _ _+ = return $ nilOL++genCCall (PrimTarget (MO_Prefetch_Data _)) _ _+ = return $ nilOL++genCCall target dest_regs args+ = do -- work out the arguments, and assign them to integer regs+ argcode_and_vregs <- mapM arg_to_int_vregs args+ let (argcodes, vregss) = unzip argcode_and_vregs+ let vregs = concat vregss++ let n_argRegs = length allArgRegs+ let n_argRegs_used = min (length vregs) n_argRegs+++ -- deal with static vs dynamic call targets+ callinsns <- case target of+ ForeignTarget (CmmLit (CmmLabel lbl)) _ ->+ return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))++ ForeignTarget expr _+ -> do (dyn_c, [dyn_r]) <- arg_to_int_vregs expr+ return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)++ PrimTarget mop+ -> do res <- outOfLineMachOp mop+ lblOrMopExpr <- case res of+ Left lbl -> do+ return (unitOL (CALL (Left (litToImm (CmmLabel lbl))) n_argRegs_used False))++ Right mopExpr -> do+ (dyn_c, [dyn_r]) <- arg_to_int_vregs mopExpr+ return (dyn_c `snocOL` CALL (Right dyn_r) n_argRegs_used False)++ return lblOrMopExpr++ let argcode = concatOL argcodes++ let (move_sp_down, move_sp_up)+ = let diff = length vregs - n_argRegs+ nn = if odd diff then diff + 1 else diff -- keep 8-byte alignment+ in if nn <= 0+ then (nilOL, nilOL)+ else (unitOL (moveSp (-1*nn)), unitOL (moveSp (1*nn)))++ let transfer_code+ = toOL (move_final vregs allArgRegs extraStackArgsHere)++ dflags <- getDynFlags+ return+ $ argcode `appOL`+ move_sp_down `appOL`+ transfer_code `appOL`+ callinsns `appOL`+ unitOL NOP `appOL`+ move_sp_up `appOL`+ assign_code (targetPlatform dflags) dest_regs+++-- | Generate code to calculate an argument, and move it into one+-- or two integer vregs.+arg_to_int_vregs :: CmmExpr -> NatM (OrdList Instr, [Reg])+arg_to_int_vregs arg = do dflags <- getDynFlags+ arg_to_int_vregs' dflags arg++arg_to_int_vregs' :: DynFlags -> CmmExpr -> NatM (OrdList Instr, [Reg])+arg_to_int_vregs' dflags arg++ -- If the expr produces a 64 bit int, then we can just use iselExpr64+ | isWord64 (cmmExprType dflags arg)+ = do (ChildCode64 code r_lo) <- iselExpr64 arg+ let r_hi = getHiVRegFromLo r_lo+ return (code, [r_hi, r_lo])++ | otherwise+ = do (src, code) <- getSomeReg arg+ let pk = cmmExprType dflags arg++ case cmmTypeFormat pk of++ -- Load a 64 bit float return value into two integer regs.+ FF64 -> do+ v1 <- getNewRegNat II32+ v2 <- getNewRegNat II32++ let code2 =+ code `snocOL`+ FMOV FF64 src f0 `snocOL`+ ST FF32 f0 (spRel 16) `snocOL`+ LD II32 (spRel 16) v1 `snocOL`+ ST FF32 f1 (spRel 16) `snocOL`+ LD II32 (spRel 16) v2++ return (code2, [v1,v2])++ -- Load a 32 bit float return value into an integer reg+ FF32 -> do+ v1 <- getNewRegNat II32++ let code2 =+ code `snocOL`+ ST FF32 src (spRel 16) `snocOL`+ LD II32 (spRel 16) v1++ return (code2, [v1])++ -- Move an integer return value into its destination reg.+ _ -> do+ v1 <- getNewRegNat II32++ let code2 =+ code `snocOL`+ OR False g0 (RIReg src) v1++ return (code2, [v1])+++-- | Move args from the integer vregs into which they have been+-- marshalled, into %o0 .. %o5, and the rest onto the stack.+--+move_final :: [Reg] -> [Reg] -> Int -> [Instr]++-- all args done+move_final [] _ _+ = []++-- out of aregs; move to stack+move_final (v:vs) [] offset+ = ST II32 v (spRel offset)+ : move_final vs [] (offset+1)++-- move into an arg (%o[0..5]) reg+move_final (v:vs) (a:az) offset+ = OR False g0 (RIReg v) a+ : move_final vs az offset+++-- | Assign results returned from the call into their+-- destination regs.+--+assign_code :: Platform -> [LocalReg] -> OrdList Instr++assign_code _ [] = nilOL++assign_code platform [dest]+ = let rep = localRegType dest+ width = typeWidth rep+ r_dest = getRegisterReg platform (CmmLocal dest)++ result+ | isFloatType rep+ , W32 <- width+ = unitOL $ FMOV FF32 (regSingle $ fReg 0) r_dest++ | isFloatType rep+ , W64 <- width+ = unitOL $ FMOV FF64 (regSingle $ fReg 0) r_dest++ | not $ isFloatType rep+ , W32 <- width+ = unitOL $ mkRegRegMoveInstr platform (regSingle $ oReg 0) r_dest++ | not $ isFloatType rep+ , W64 <- width+ , r_dest_hi <- getHiVRegFromLo r_dest+ = toOL [ mkRegRegMoveInstr platform (regSingle $ oReg 0) r_dest_hi+ , mkRegRegMoveInstr platform (regSingle $ oReg 1) r_dest]++ | otherwise+ = panic "SPARC.CodeGen.GenCCall: no match"++ in result++assign_code _ _+ = panic "SPARC.CodeGen.GenCCall: no match"++++-- | Generate a call to implement an out-of-line floating point operation+outOfLineMachOp+ :: CallishMachOp+ -> NatM (Either CLabel CmmExpr)++outOfLineMachOp mop+ = do let functionName+ = outOfLineMachOp_table mop++ dflags <- getDynFlags+ mopExpr <- cmmMakeDynamicReference dflags CallReference+ $ mkForeignLabel functionName Nothing ForeignLabelInExternalPackage IsFunction++ let mopLabelOrExpr+ = case mopExpr of+ CmmLit (CmmLabel lbl) -> Left lbl+ _ -> Right mopExpr++ return mopLabelOrExpr+++-- | Decide what C function to use to implement a CallishMachOp+--+outOfLineMachOp_table+ :: CallishMachOp+ -> FastString++outOfLineMachOp_table mop+ = case mop of+ MO_F32_Exp -> fsLit "expf"+ MO_F32_Log -> fsLit "logf"+ MO_F32_Sqrt -> fsLit "sqrtf"+ MO_F32_Fabs -> unsupported+ MO_F32_Pwr -> fsLit "powf"++ MO_F32_Sin -> fsLit "sinf"+ MO_F32_Cos -> fsLit "cosf"+ MO_F32_Tan -> fsLit "tanf"++ MO_F32_Asin -> fsLit "asinf"+ MO_F32_Acos -> fsLit "acosf"+ MO_F32_Atan -> fsLit "atanf"++ MO_F32_Sinh -> fsLit "sinhf"+ MO_F32_Cosh -> fsLit "coshf"+ MO_F32_Tanh -> fsLit "tanhf"++ MO_F64_Exp -> fsLit "exp"+ MO_F64_Log -> fsLit "log"+ MO_F64_Sqrt -> fsLit "sqrt"+ MO_F64_Fabs -> unsupported+ MO_F64_Pwr -> fsLit "pow"++ MO_F64_Sin -> fsLit "sin"+ MO_F64_Cos -> fsLit "cos"+ MO_F64_Tan -> fsLit "tan"++ MO_F64_Asin -> fsLit "asin"+ MO_F64_Acos -> fsLit "acos"+ MO_F64_Atan -> fsLit "atan"++ MO_F64_Sinh -> fsLit "sinh"+ MO_F64_Cosh -> fsLit "cosh"+ MO_F64_Tanh -> fsLit "tanh"++ MO_UF_Conv w -> fsLit $ word2FloatLabel w++ MO_Memcpy _ -> fsLit "memcpy"+ MO_Memset _ -> fsLit "memset"+ MO_Memmove _ -> fsLit "memmove"++ MO_BSwap w -> fsLit $ bSwapLabel w+ MO_PopCnt w -> fsLit $ popCntLabel w+ MO_Clz w -> fsLit $ clzLabel w+ MO_Ctz w -> fsLit $ ctzLabel w+ MO_AtomicRMW w amop -> fsLit $ atomicRMWLabel w amop+ MO_Cmpxchg w -> fsLit $ cmpxchgLabel w+ MO_AtomicRead w -> fsLit $ atomicReadLabel w+ MO_AtomicWrite w -> fsLit $ atomicWriteLabel w++ MO_S_QuotRem {} -> unsupported+ MO_U_QuotRem {} -> unsupported+ MO_U_QuotRem2 {} -> unsupported+ MO_Add2 {} -> unsupported+ MO_SubWordC {} -> unsupported+ MO_AddIntC {} -> unsupported+ MO_SubIntC {} -> unsupported+ MO_U_Mul2 {} -> unsupported+ MO_WriteBarrier -> unsupported+ MO_Touch -> unsupported+ (MO_Prefetch_Data _) -> unsupported+ where unsupported = panic ("outOfLineCmmOp: " ++ show mop+ ++ " not supported here")+
+ nativeGen/SPARC/CodeGen/Amode.hs view
@@ -0,0 +1,72 @@+module SPARC.CodeGen.Amode (+ getAmode+)++where++import {-# SOURCE #-} SPARC.CodeGen.Gen32+import SPARC.CodeGen.Base+import SPARC.AddrMode+import SPARC.Imm+import SPARC.Instr+import SPARC.Regs+import SPARC.Base+import NCGMonad+import Format++import Cmm++import OrdList+++-- | Generate code to reference a memory address.+getAmode+ :: CmmExpr -- ^ expr producing an address+ -> NatM Amode++getAmode tree@(CmmRegOff _ _)+ = do dflags <- getDynFlags+ getAmode (mangleIndexTree dflags tree)++getAmode (CmmMachOp (MO_Sub _) [x, CmmLit (CmmInt i _)])+ | fits13Bits (-i)+ = do+ (reg, code) <- getSomeReg x+ let+ off = ImmInt (-(fromInteger i))+ return (Amode (AddrRegImm reg off) code)+++getAmode (CmmMachOp (MO_Add _) [x, CmmLit (CmmInt i _)])+ | fits13Bits i+ = do+ (reg, code) <- getSomeReg x+ let+ off = ImmInt (fromInteger i)+ return (Amode (AddrRegImm reg off) code)++getAmode (CmmMachOp (MO_Add _) [x, y])+ = do+ (regX, codeX) <- getSomeReg x+ (regY, codeY) <- getSomeReg y+ let+ code = codeX `appOL` codeY+ return (Amode (AddrRegReg regX regY) code)++getAmode (CmmLit lit)+ = do+ let imm__2 = litToImm lit+ tmp1 <- getNewRegNat II32+ tmp2 <- getNewRegNat II32++ let code = toOL [ SETHI (HI imm__2) tmp1+ , OR False tmp1 (RIImm (LO imm__2)) tmp2]++ return (Amode (AddrRegReg tmp2 g0) code)++getAmode other+ = do+ (reg, code) <- getSomeReg other+ let+ off = ImmInt 0+ return (Amode (AddrRegImm reg off) code)
+ nativeGen/SPARC/CodeGen/Base.hs view
@@ -0,0 +1,117 @@+module SPARC.CodeGen.Base (+ InstrBlock,+ CondCode(..),+ ChildCode64(..),+ Amode(..),++ Register(..),+ setFormatOfRegister,++ getRegisterReg,+ mangleIndexTree+)++where++import SPARC.Instr+import SPARC.Cond+import SPARC.AddrMode+import SPARC.Regs+import Format+import Reg++import CodeGen.Platform+import DynFlags+import Cmm+import PprCmmExpr ()+import Platform++import Outputable+import OrdList++--------------------------------------------------------------------------------+-- | 'InstrBlock's are the insn sequences generated by the insn selectors.+-- They are really trees of insns to facilitate fast appending, where a+-- left-to-right traversal yields the insns in the correct order.+--+type InstrBlock+ = OrdList Instr+++-- | Condition codes passed up the tree.+--+data CondCode+ = CondCode Bool Cond InstrBlock+++-- | a.k.a "Register64"+-- Reg is the lower 32-bit temporary which contains the result.+-- Use getHiVRegFromLo to find the other VRegUnique.+--+-- Rules of this simplified insn selection game are therefore that+-- the returned Reg may be modified+--+data ChildCode64+ = ChildCode64+ InstrBlock+ Reg+++-- | Holds code that references a memory address.+data Amode+ = Amode+ -- the AddrMode we can use in the instruction+ -- that does the real load\/store.+ AddrMode++ -- other setup code we have to run first before we can use the+ -- above AddrMode.+ InstrBlock++++--------------------------------------------------------------------------------+-- | Code to produce a result into a register.+-- If the result must go in a specific register, it comes out as Fixed.+-- Otherwise, the parent can decide which register to put it in.+--+data Register+ = Fixed Format Reg InstrBlock+ | Any Format (Reg -> InstrBlock)+++-- | Change the format field in a Register.+setFormatOfRegister+ :: Register -> Format -> Register++setFormatOfRegister reg format+ = case reg of+ Fixed _ reg code -> Fixed format reg code+ Any _ codefn -> Any format codefn+++--------------------------------------------------------------------------------+-- | Grab the Reg for a CmmReg+getRegisterReg :: Platform -> CmmReg -> Reg++getRegisterReg _ (CmmLocal (LocalReg u pk))+ = RegVirtual $ mkVirtualReg u (cmmTypeFormat pk)++getRegisterReg platform (CmmGlobal mid)+ = case globalRegMaybe platform mid of+ Just reg -> RegReal reg+ Nothing -> pprPanic+ "SPARC.CodeGen.Base.getRegisterReg: global is in memory"+ (ppr $ CmmGlobal mid)+++-- Expand CmmRegOff. ToDo: should we do it this way around, or convert+-- CmmExprs into CmmRegOff?+mangleIndexTree :: DynFlags -> CmmExpr -> CmmExpr++mangleIndexTree dflags (CmmRegOff reg off)+ = CmmMachOp (MO_Add width) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) width)]+ where width = typeWidth (cmmRegType dflags reg)++mangleIndexTree _ _+ = panic "SPARC.CodeGen.Base.mangleIndexTree: no match"
+ nativeGen/SPARC/CodeGen/CondCode.hs view
@@ -0,0 +1,108 @@+module SPARC.CodeGen.CondCode (+ getCondCode,+ condIntCode,+ condFltCode+)++where++import {-# SOURCE #-} SPARC.CodeGen.Gen32+import SPARC.CodeGen.Base+import SPARC.Instr+import SPARC.Regs+import SPARC.Cond+import SPARC.Imm+import SPARC.Base+import NCGMonad+import Format++import Cmm++import OrdList+import Outputable+++getCondCode :: CmmExpr -> NatM CondCode+getCondCode (CmmMachOp mop [x, y])+ =+ case mop of+ MO_F_Eq W32 -> condFltCode EQQ x y+ MO_F_Ne W32 -> condFltCode NE x y+ MO_F_Gt W32 -> condFltCode GTT x y+ MO_F_Ge W32 -> condFltCode GE x y+ MO_F_Lt W32 -> condFltCode LTT x y+ MO_F_Le W32 -> condFltCode LE x y++ MO_F_Eq W64 -> condFltCode EQQ x y+ MO_F_Ne W64 -> condFltCode NE x y+ MO_F_Gt W64 -> condFltCode GTT x y+ MO_F_Ge W64 -> condFltCode GE x y+ MO_F_Lt W64 -> condFltCode LTT x y+ MO_F_Le W64 -> condFltCode LE x y++ MO_Eq _ -> condIntCode EQQ x y+ MO_Ne _ -> condIntCode NE x y++ MO_S_Gt _ -> condIntCode GTT x y+ MO_S_Ge _ -> condIntCode GE x y+ MO_S_Lt _ -> condIntCode LTT x y+ MO_S_Le _ -> condIntCode LE x y++ MO_U_Gt _ -> condIntCode GU x y+ MO_U_Ge _ -> condIntCode GEU x y+ MO_U_Lt _ -> condIntCode LU x y+ MO_U_Le _ -> condIntCode LEU x y++ _ -> pprPanic "SPARC.CodeGen.CondCode.getCondCode" (ppr (CmmMachOp mop [x,y]))++getCondCode other = pprPanic "SPARC.CodeGen.CondCode.getCondCode" (ppr other)++++++-- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be+-- passed back up the tree.++condIntCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode+condIntCode cond x (CmmLit (CmmInt y _))+ | fits13Bits y+ = do+ (src1, code) <- getSomeReg x+ let+ src2 = ImmInt (fromInteger y)+ code' = code `snocOL` SUB False True src1 (RIImm src2) g0+ return (CondCode False cond code')++condIntCode cond x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let+ code__2 = code1 `appOL` code2 `snocOL`+ SUB False True src1 (RIReg src2) g0+ return (CondCode False cond code__2)+++condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode+condFltCode cond x y = do+ dflags <- getDynFlags+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ tmp <- getNewRegNat FF64+ let+ promote x = FxTOy FF32 FF64 x tmp++ pk1 = cmmExprType dflags x+ pk2 = cmmExprType dflags y++ code__2 =+ if pk1 `cmmEqType` pk2 then+ code1 `appOL` code2 `snocOL`+ FCMP True (cmmTypeFormat pk1) src1 src2+ else if typeWidth pk1 == W32 then+ code1 `snocOL` promote src1 `appOL` code2 `snocOL`+ FCMP True FF64 tmp src2+ else+ code1 `appOL` code2 `snocOL` promote src2 `snocOL`+ FCMP True FF64 src1 tmp+ return (CondCode True cond code__2)
+ nativeGen/SPARC/CodeGen/Expand.hs view
@@ -0,0 +1,153 @@+-- | Expand out synthetic instructions into single machine instrs.+module SPARC.CodeGen.Expand (+ expandTop+)++where++import SPARC.Instr+import SPARC.Imm+import SPARC.AddrMode+import SPARC.Regs+import SPARC.Ppr ()+import Instruction+import Reg+import Format+import Cmm+++import Outputable+import OrdList++-- | Expand out synthetic instructions in this top level thing+expandTop :: NatCmmDecl CmmStatics Instr -> NatCmmDecl CmmStatics Instr+expandTop top@(CmmData{})+ = top++expandTop (CmmProc info lbl live (ListGraph blocks))+ = CmmProc info lbl live (ListGraph $ map expandBlock blocks)+++-- | Expand out synthetic instructions in this block+expandBlock :: NatBasicBlock Instr -> NatBasicBlock Instr++expandBlock (BasicBlock label instrs)+ = let instrs_ol = expandBlockInstrs instrs+ instrs' = fromOL instrs_ol+ in BasicBlock label instrs'+++-- | Expand out some instructions+expandBlockInstrs :: [Instr] -> OrdList Instr+expandBlockInstrs [] = nilOL++expandBlockInstrs (ii:is)+ = let ii_doubleRegs = remapRegPair ii+ is_misaligned = expandMisalignedDoubles ii_doubleRegs++ in is_misaligned `appOL` expandBlockInstrs is++++-- | In the SPARC instruction set the FP register pairs that are used+-- to hold 64 bit floats are refered to by just the first reg+-- of the pair. Remap our internal reg pairs to the appropriate reg.+--+-- For example:+-- ldd [%l1], (%f0 | %f1)+--+-- gets mapped to+-- ldd [$l1], %f0+--+remapRegPair :: Instr -> Instr+remapRegPair instr+ = let patchF reg+ = case reg of+ RegReal (RealRegSingle _)+ -> reg++ RegReal (RealRegPair r1 r2)++ -- sanity checking+ | r1 >= 32+ , r1 <= 63+ , r1 `mod` 2 == 0+ , r2 == r1 + 1+ -> RegReal (RealRegSingle r1)++ | otherwise+ -> pprPanic "SPARC.CodeGen.Expand: not remapping dodgy looking reg pair " (ppr reg)++ RegVirtual _+ -> pprPanic "SPARC.CodeGen.Expand: not remapping virtual reg " (ppr reg)++ in patchRegsOfInstr instr patchF+++++-- Expand out 64 bit load/stores into individual instructions to handle+-- possible double alignment problems.+--+-- TODO: It'd be better to use a scratch reg instead of the add/sub thing.+-- We might be able to do this faster if we use the UA2007 instr set+-- instead of restricting ourselves to SPARC V9.+--+expandMisalignedDoubles :: Instr -> OrdList Instr+expandMisalignedDoubles instr++ -- Translate to:+ -- add g1,g2,g1+ -- ld [g1],%fn+ -- ld [g1+4],%f(n+1)+ -- sub g1,g2,g1 -- to restore g1+ | LD FF64 (AddrRegReg r1 r2) fReg <- instr+ = toOL [ ADD False False r1 (RIReg r2) r1+ , LD FF32 (AddrRegReg r1 g0) fReg+ , LD FF32 (AddrRegImm r1 (ImmInt 4)) (fRegHi fReg)+ , SUB False False r1 (RIReg r2) r1 ]++ -- Translate to+ -- ld [addr],%fn+ -- ld [addr+4],%f(n+1)+ | LD FF64 addr fReg <- instr+ = let Just addr' = addrOffset addr 4+ in toOL [ LD FF32 addr fReg+ , LD FF32 addr' (fRegHi fReg) ]++ -- Translate to:+ -- add g1,g2,g1+ -- st %fn,[g1]+ -- st %f(n+1),[g1+4]+ -- sub g1,g2,g1 -- to restore g1+ | ST FF64 fReg (AddrRegReg r1 r2) <- instr+ = toOL [ ADD False False r1 (RIReg r2) r1+ , ST FF32 fReg (AddrRegReg r1 g0)+ , ST FF32 (fRegHi fReg) (AddrRegImm r1 (ImmInt 4))+ , SUB False False r1 (RIReg r2) r1 ]++ -- Translate to+ -- ld [addr],%fn+ -- ld [addr+4],%f(n+1)+ | ST FF64 fReg addr <- instr+ = let Just addr' = addrOffset addr 4+ in toOL [ ST FF32 fReg addr+ , ST FF32 (fRegHi fReg) addr' ]++ -- some other instr+ | otherwise+ = unitOL instr++++-- | The the high partner for this float reg.+fRegHi :: Reg -> Reg+fRegHi (RegReal (RealRegSingle r1))+ | r1 >= 32+ , r1 <= 63+ , r1 `mod` 2 == 0+ = (RegReal $ RealRegSingle (r1 + 1))++-- Can't take high partner for non-low reg.+fRegHi reg+ = pprPanic "SPARC.CodeGen.Expand: can't take fRegHi from " (ppr reg)
+ nativeGen/SPARC/CodeGen/Gen32.hs view
@@ -0,0 +1,690 @@+-- | Evaluation of 32 bit values.+module SPARC.CodeGen.Gen32 (+ getSomeReg,+ getRegister+)++where++import SPARC.CodeGen.CondCode+import SPARC.CodeGen.Amode+import SPARC.CodeGen.Gen64+import SPARC.CodeGen.Base+import SPARC.Stack+import SPARC.Instr+import SPARC.Cond+import SPARC.AddrMode+import SPARC.Imm+import SPARC.Regs+import SPARC.Base+import NCGMonad+import Format+import Reg++import Cmm++import Control.Monad (liftM)+import DynFlags+import OrdList+import Outputable++-- | The dual to getAnyReg: compute an expression into a register, but+-- we don't mind which one it is.+getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)+getSomeReg expr = do+ r <- getRegister expr+ case r of+ Any rep code -> do+ tmp <- getNewRegNat rep+ return (tmp, code tmp)+ Fixed _ reg code ->+ return (reg, code)++++-- | Make code to evaluate a 32 bit expression.+--+getRegister :: CmmExpr -> NatM Register++getRegister (CmmReg reg)+ = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ return (Fixed (cmmTypeFormat (cmmRegType dflags reg))+ (getRegisterReg platform reg) nilOL)++getRegister tree@(CmmRegOff _ _)+ = do dflags <- getDynFlags+ getRegister (mangleIndexTree dflags tree)++getRegister (CmmMachOp (MO_UU_Conv W64 W32)+ [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]]) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 (getHiVRegFromLo rlo) code++getRegister (CmmMachOp (MO_SS_Conv W64 W32)+ [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]]) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 (getHiVRegFromLo rlo) code++getRegister (CmmMachOp (MO_UU_Conv W64 W32) [x]) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 rlo code++getRegister (CmmMachOp (MO_SS_Conv W64 W32) [x]) = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 rlo code+++-- Load a literal float into a float register.+-- The actual literal is stored in a new data area, and we load it+-- at runtime.+getRegister (CmmLit (CmmFloat f W32)) = do++ -- a label for the new data area+ lbl <- getNewLabelNat+ tmp <- getNewRegNat II32++ let code dst = toOL [+ -- the data area+ LDATA (Section ReadOnlyData lbl) $ Statics lbl+ [CmmStaticLit (CmmFloat f W32)],++ -- load the literal+ SETHI (HI (ImmCLbl lbl)) tmp,+ LD II32 (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]++ return (Any FF32 code)++getRegister (CmmLit (CmmFloat d W64)) = do+ lbl <- getNewLabelNat+ tmp <- getNewRegNat II32+ let code dst = toOL [+ LDATA (Section ReadOnlyData lbl) $ Statics lbl+ [CmmStaticLit (CmmFloat d W64)],+ SETHI (HI (ImmCLbl lbl)) tmp,+ LD II64 (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]+ return (Any FF64 code)+++-- Unary machine ops+getRegister (CmmMachOp mop [x])+ = case mop of+ -- Floating point negation -------------------------+ MO_F_Neg W32 -> trivialUFCode FF32 (FNEG FF32) x+ MO_F_Neg W64 -> trivialUFCode FF64 (FNEG FF64) x+++ -- Integer negation --------------------------------+ MO_S_Neg rep -> trivialUCode (intFormat rep) (SUB False False g0) x+ MO_Not rep -> trivialUCode (intFormat rep) (XNOR False g0) x+++ -- Float word size conversion ----------------------+ MO_FF_Conv W64 W32 -> coerceDbl2Flt x+ MO_FF_Conv W32 W64 -> coerceFlt2Dbl x+++ -- Float <-> Signed Int conversion -----------------+ MO_FS_Conv from to -> coerceFP2Int from to x+ MO_SF_Conv from to -> coerceInt2FP from to x+++ -- Unsigned integer word size conversions ----------++ -- If it's the same size, then nothing needs to be done.+ MO_UU_Conv from to+ | from == to -> conversionNop (intFormat to) x++ -- To narrow an unsigned word, mask out the high bits to simulate what would+ -- happen if we copied the value into a smaller register.+ MO_UU_Conv W16 W8 -> trivialCode W8 (AND False) x (CmmLit (CmmInt 255 W8))+ MO_UU_Conv W32 W8 -> trivialCode W8 (AND False) x (CmmLit (CmmInt 255 W8))++ -- for narrowing 32 bit to 16 bit, don't use a literal mask value like the W16->W8+ -- case because the only way we can load it is via SETHI, which needs 2 ops.+ -- Do some shifts to chop out the high bits instead.+ MO_UU_Conv W32 W16+ -> do tmpReg <- getNewRegNat II32+ (xReg, xCode) <- getSomeReg x+ let code dst+ = xCode+ `appOL` toOL+ [ SLL xReg (RIImm $ ImmInt 16) tmpReg+ , SRL tmpReg (RIImm $ ImmInt 16) dst]++ return $ Any II32 code++ -- trivialCode W16 (AND False) x (CmmLit (CmmInt 65535 W16))++ -- To widen an unsigned word we don't have to do anything.+ -- Just leave it in the same register and mark the result as the new size.+ MO_UU_Conv W8 W16 -> conversionNop (intFormat W16) x+ MO_UU_Conv W8 W32 -> conversionNop (intFormat W32) x+ MO_UU_Conv W16 W32 -> conversionNop (intFormat W32) x+++ -- Signed integer word size conversions ------------++ -- Mask out high bits when narrowing them+ MO_SS_Conv W16 W8 -> trivialCode W8 (AND False) x (CmmLit (CmmInt 255 W8))+ MO_SS_Conv W32 W8 -> trivialCode W8 (AND False) x (CmmLit (CmmInt 255 W8))+ MO_SS_Conv W32 W16 -> trivialCode W16 (AND False) x (CmmLit (CmmInt 65535 W16))++ -- Sign extend signed words when widening them.+ MO_SS_Conv W8 W16 -> integerExtend W8 W16 x+ MO_SS_Conv W8 W32 -> integerExtend W8 W32 x+ MO_SS_Conv W16 W32 -> integerExtend W16 W32 x++ _ -> panic ("Unknown unary mach op: " ++ show mop)+++-- Binary machine ops+getRegister (CmmMachOp mop [x, y])+ = case mop of+ MO_Eq _ -> condIntReg EQQ x y+ MO_Ne _ -> condIntReg NE x y++ MO_S_Gt _ -> condIntReg GTT x y+ MO_S_Ge _ -> condIntReg GE x y+ MO_S_Lt _ -> condIntReg LTT x y+ MO_S_Le _ -> condIntReg LE x y++ MO_U_Gt W32 -> condIntReg GU x y+ MO_U_Ge W32 -> condIntReg GEU x y+ MO_U_Lt W32 -> condIntReg LU x y+ MO_U_Le W32 -> condIntReg LEU x y++ MO_U_Gt W16 -> condIntReg GU x y+ MO_U_Ge W16 -> condIntReg GEU x y+ MO_U_Lt W16 -> condIntReg LU x y+ MO_U_Le W16 -> condIntReg LEU x y++ MO_Add W32 -> trivialCode W32 (ADD False False) x y+ MO_Sub W32 -> trivialCode W32 (SUB False False) x y++ MO_S_MulMayOflo rep -> imulMayOflo rep x y++ MO_S_Quot W32 -> idiv True False x y+ MO_U_Quot W32 -> idiv False False x y++ MO_S_Rem W32 -> irem True x y+ MO_U_Rem W32 -> irem False x y++ MO_F_Eq _ -> condFltReg EQQ x y+ MO_F_Ne _ -> condFltReg NE x y++ MO_F_Gt _ -> condFltReg GTT x y+ MO_F_Ge _ -> condFltReg GE x y+ MO_F_Lt _ -> condFltReg LTT x y+ MO_F_Le _ -> condFltReg LE x y++ MO_F_Add w -> trivialFCode w FADD x y+ MO_F_Sub w -> trivialFCode w FSUB x y+ MO_F_Mul w -> trivialFCode w FMUL x y+ MO_F_Quot w -> trivialFCode w FDIV x y++ MO_And rep -> trivialCode rep (AND False) x y+ MO_Or rep -> trivialCode rep (OR False) x y+ MO_Xor rep -> trivialCode rep (XOR False) x y++ MO_Mul rep -> trivialCode rep (SMUL False) x y++ MO_Shl rep -> trivialCode rep SLL x y+ MO_U_Shr rep -> trivialCode rep SRL x y+ MO_S_Shr rep -> trivialCode rep SRA x y++ _ -> pprPanic "getRegister(sparc) - binary CmmMachOp (1)" (pprMachOp mop)++getRegister (CmmLoad mem pk) = do+ Amode src code <- getAmode mem+ let+ code__2 dst = code `snocOL` LD (cmmTypeFormat pk) src dst+ return (Any (cmmTypeFormat pk) code__2)++getRegister (CmmLit (CmmInt i _))+ | fits13Bits i+ = let+ src = ImmInt (fromInteger i)+ code dst = unitOL (OR False g0 (RIImm src) dst)+ in+ return (Any II32 code)++getRegister (CmmLit lit)+ = let imm = litToImm lit+ code dst = toOL [+ SETHI (HI imm) dst,+ OR False dst (RIImm (LO imm)) dst]+ in return (Any II32 code)+++getRegister _+ = panic "SPARC.CodeGen.Gen32.getRegister: no match"+++-- | sign extend and widen+integerExtend+ :: Width -- ^ width of source expression+ -> Width -- ^ width of result+ -> CmmExpr -- ^ source expression+ -> NatM Register++integerExtend from to expr+ = do -- load the expr into some register+ (reg, e_code) <- getSomeReg expr+ tmp <- getNewRegNat II32+ let bitCount+ = case (from, to) of+ (W8, W32) -> 24+ (W16, W32) -> 16+ (W8, W16) -> 24+ _ -> panic "SPARC.CodeGen.Gen32: no match"+ let code dst+ = e_code++ -- local shift word left to load the sign bit+ `snocOL` SLL reg (RIImm (ImmInt bitCount)) tmp++ -- arithmetic shift right to sign extend+ `snocOL` SRA tmp (RIImm (ImmInt bitCount)) dst++ return (Any (intFormat to) code)+++-- | For nop word format conversions we set the resulting value to have the+-- required size, but don't need to generate any actual code.+--+conversionNop+ :: Format -> CmmExpr -> NatM Register++conversionNop new_rep expr+ = do e_code <- getRegister expr+ return (setFormatOfRegister e_code new_rep)++++-- | Generate an integer division instruction.+idiv :: Bool -> Bool -> CmmExpr -> CmmExpr -> NatM Register++-- For unsigned division with a 32 bit numerator,+-- we can just clear the Y register.+idiv False cc x y+ = do+ (a_reg, a_code) <- getSomeReg x+ (b_reg, b_code) <- getSomeReg y++ let code dst+ = a_code+ `appOL` b_code+ `appOL` toOL+ [ WRY g0 g0+ , UDIV cc a_reg (RIReg b_reg) dst]++ return (Any II32 code)+++-- For _signed_ division with a 32 bit numerator,+-- we have to sign extend the numerator into the Y register.+idiv True cc x y+ = do+ (a_reg, a_code) <- getSomeReg x+ (b_reg, b_code) <- getSomeReg y++ tmp <- getNewRegNat II32++ let code dst+ = a_code+ `appOL` b_code+ `appOL` toOL+ [ SRA a_reg (RIImm (ImmInt 16)) tmp -- sign extend+ , SRA tmp (RIImm (ImmInt 16)) tmp++ , WRY tmp g0+ , SDIV cc a_reg (RIReg b_reg) dst]++ return (Any II32 code)+++-- | Do an integer remainder.+--+-- NOTE: The SPARC v8 architecture manual says that integer division+-- instructions _may_ generate a remainder, depending on the implementation.+-- If so it is _recommended_ that the remainder is placed in the Y register.+--+-- The UltraSparc 2007 manual says Y is _undefined_ after division.+--+-- The SPARC T2 doesn't store the remainder, not sure about the others.+-- It's probably best not to worry about it, and just generate our own+-- remainders.+--+irem :: Bool -> CmmExpr -> CmmExpr -> NatM Register++-- For unsigned operands:+-- Division is between a 64 bit numerator and a 32 bit denominator,+-- so we still have to clear the Y register.+irem False x y+ = do+ (a_reg, a_code) <- getSomeReg x+ (b_reg, b_code) <- getSomeReg y++ tmp_reg <- getNewRegNat II32++ let code dst+ = a_code+ `appOL` b_code+ `appOL` toOL+ [ WRY g0 g0+ , UDIV False a_reg (RIReg b_reg) tmp_reg+ , UMUL False tmp_reg (RIReg b_reg) tmp_reg+ , SUB False False a_reg (RIReg tmp_reg) dst]++ return (Any II32 code)++++-- For signed operands:+-- Make sure to sign extend into the Y register, or the remainder+-- will have the wrong sign when the numerator is negative.+--+-- TODO: When sign extending, GCC only shifts the a_reg right by 17 bits,+-- not the full 32. Not sure why this is, something to do with overflow?+-- If anyone cares enough about the speed of signed remainder they+-- can work it out themselves (then tell me). -- BL 2009/01/20+irem True x y+ = do+ (a_reg, a_code) <- getSomeReg x+ (b_reg, b_code) <- getSomeReg y++ tmp1_reg <- getNewRegNat II32+ tmp2_reg <- getNewRegNat II32++ let code dst+ = a_code+ `appOL` b_code+ `appOL` toOL+ [ SRA a_reg (RIImm (ImmInt 16)) tmp1_reg -- sign extend+ , SRA tmp1_reg (RIImm (ImmInt 16)) tmp1_reg -- sign extend+ , WRY tmp1_reg g0++ , SDIV False a_reg (RIReg b_reg) tmp2_reg+ , SMUL False tmp2_reg (RIReg b_reg) tmp2_reg+ , SUB False False a_reg (RIReg tmp2_reg) dst]++ return (Any II32 code)+++imulMayOflo :: Width -> CmmExpr -> CmmExpr -> NatM Register+imulMayOflo rep a b+ = do+ (a_reg, a_code) <- getSomeReg a+ (b_reg, b_code) <- getSomeReg b+ res_lo <- getNewRegNat II32+ res_hi <- getNewRegNat II32++ let shift_amt = case rep of+ W32 -> 31+ W64 -> 63+ _ -> panic "shift_amt"++ let code dst = a_code `appOL` b_code `appOL`+ toOL [+ SMUL False a_reg (RIReg b_reg) res_lo,+ RDY res_hi,+ SRA res_lo (RIImm (ImmInt shift_amt)) res_lo,+ SUB False False res_lo (RIReg res_hi) dst+ ]+ return (Any II32 code)+++-- -----------------------------------------------------------------------------+-- 'trivial*Code': deal with trivial instructions++-- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',+-- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.+-- Only look for constants on the right hand side, because that's+-- where the generic optimizer will have put them.++-- Similarly, for unary instructions, we don't have to worry about+-- matching an StInt as the argument, because genericOpt will already+-- have handled the constant-folding.++trivialCode+ :: Width+ -> (Reg -> RI -> Reg -> Instr)+ -> CmmExpr+ -> CmmExpr+ -> NatM Register++trivialCode _ instr x (CmmLit (CmmInt y _))+ | fits13Bits y+ = do+ (src1, code) <- getSomeReg x+ let+ src2 = ImmInt (fromInteger y)+ code__2 dst = code `snocOL` instr src1 (RIImm src2) dst+ return (Any II32 code__2)+++trivialCode _ instr x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let+ code__2 dst = code1 `appOL` code2 `snocOL`+ instr src1 (RIReg src2) dst+ return (Any II32 code__2)+++trivialFCode+ :: Width+ -> (Format -> Reg -> Reg -> Reg -> Instr)+ -> CmmExpr+ -> CmmExpr+ -> NatM Register++trivialFCode pk instr x y = do+ dflags <- getDynFlags+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ tmp <- getNewRegNat FF64+ let+ promote x = FxTOy FF32 FF64 x tmp++ pk1 = cmmExprType dflags x+ pk2 = cmmExprType dflags y++ code__2 dst =+ if pk1 `cmmEqType` pk2 then+ code1 `appOL` code2 `snocOL`+ instr (floatFormat pk) src1 src2 dst+ else if typeWidth pk1 == W32 then+ code1 `snocOL` promote src1 `appOL` code2 `snocOL`+ instr FF64 tmp src2 dst+ else+ code1 `appOL` code2 `snocOL` promote src2 `snocOL`+ instr FF64 src1 tmp dst+ return (Any (cmmTypeFormat $ if pk1 `cmmEqType` pk2 then pk1 else cmmFloat W64)+ code__2)++++trivialUCode+ :: Format+ -> (RI -> Reg -> Instr)+ -> CmmExpr+ -> NatM Register++trivialUCode format instr x = do+ (src, code) <- getSomeReg x+ let+ code__2 dst = code `snocOL` instr (RIReg src) dst+ return (Any format code__2)+++trivialUFCode+ :: Format+ -> (Reg -> Reg -> Instr)+ -> CmmExpr+ -> NatM Register++trivialUFCode pk instr x = do+ (src, code) <- getSomeReg x+ let+ code__2 dst = code `snocOL` instr src dst+ return (Any pk code__2)+++++-- Coercions -------------------------------------------------------------------++-- | Coerce a integer value to floating point+coerceInt2FP :: Width -> Width -> CmmExpr -> NatM Register+coerceInt2FP width1 width2 x = do+ (src, code) <- getSomeReg x+ let+ code__2 dst = code `appOL` toOL [+ ST (intFormat width1) src (spRel (-2)),+ LD (intFormat width1) (spRel (-2)) dst,+ FxTOy (intFormat width1) (floatFormat width2) dst dst]+ return (Any (floatFormat $ width2) code__2)++++-- | Coerce a floating point value to integer+--+-- NOTE: On sparc v9 there are no instructions to move a value from an+-- FP register directly to an int register, so we have to use a load/store.+--+coerceFP2Int :: Width -> Width -> CmmExpr -> NatM Register+coerceFP2Int width1 width2 x+ = do let fformat1 = floatFormat width1+ fformat2 = floatFormat width2++ iformat2 = intFormat width2++ (fsrc, code) <- getSomeReg x+ fdst <- getNewRegNat fformat2++ let code2 dst+ = code+ `appOL` toOL+ -- convert float to int format, leaving it in a float reg.+ [ FxTOy fformat1 iformat2 fsrc fdst++ -- store the int into mem, then load it back to move+ -- it into an actual int reg.+ , ST fformat2 fdst (spRel (-2))+ , LD iformat2 (spRel (-2)) dst]++ return (Any iformat2 code2)+++-- | Coerce a double precision floating point value to single precision.+coerceDbl2Flt :: CmmExpr -> NatM Register+coerceDbl2Flt x = do+ (src, code) <- getSomeReg x+ return (Any FF32 (\dst -> code `snocOL` FxTOy FF64 FF32 src dst))+++-- | Coerce a single precision floating point value to double precision+coerceFlt2Dbl :: CmmExpr -> NatM Register+coerceFlt2Dbl x = do+ (src, code) <- getSomeReg x+ return (Any FF64 (\dst -> code `snocOL` FxTOy FF32 FF64 src dst))+++++-- Condition Codes -------------------------------------------------------------+--+-- Evaluate a comparison, and get the result into a register.+--+-- Do not fill the delay slots here. you will confuse the register allocator.+--+condIntReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register+condIntReg EQQ x (CmmLit (CmmInt 0 _)) = do+ (src, code) <- getSomeReg x+ let+ code__2 dst = code `appOL` toOL [+ SUB False True g0 (RIReg src) g0,+ SUB True False g0 (RIImm (ImmInt (-1))) dst]+ return (Any II32 code__2)++condIntReg EQQ x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let+ code__2 dst = code1 `appOL` code2 `appOL` toOL [+ XOR False src1 (RIReg src2) dst,+ SUB False True g0 (RIReg dst) g0,+ SUB True False g0 (RIImm (ImmInt (-1))) dst]+ return (Any II32 code__2)++condIntReg NE x (CmmLit (CmmInt 0 _)) = do+ (src, code) <- getSomeReg x+ let+ code__2 dst = code `appOL` toOL [+ SUB False True g0 (RIReg src) g0,+ ADD True False g0 (RIImm (ImmInt 0)) dst]+ return (Any II32 code__2)++condIntReg NE x y = do+ (src1, code1) <- getSomeReg x+ (src2, code2) <- getSomeReg y+ let+ code__2 dst = code1 `appOL` code2 `appOL` toOL [+ XOR False src1 (RIReg src2) dst,+ SUB False True g0 (RIReg dst) g0,+ ADD True False g0 (RIImm (ImmInt 0)) dst]+ return (Any II32 code__2)++condIntReg cond x y = do+ bid1 <- liftM (\a -> seq a a) getBlockIdNat+ bid2 <- liftM (\a -> seq a a) getBlockIdNat+ CondCode _ cond cond_code <- condIntCode cond x y+ let+ code__2 dst+ = cond_code+ `appOL` toOL+ [ BI cond False bid1+ , NOP++ , OR False g0 (RIImm (ImmInt 0)) dst+ , BI ALWAYS False bid2+ , NOP++ , NEWBLOCK bid1+ , OR False g0 (RIImm (ImmInt 1)) dst+ , BI ALWAYS False bid2+ , NOP++ , NEWBLOCK bid2]++ return (Any II32 code__2)+++condFltReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register+condFltReg cond x y = do+ bid1 <- liftM (\a -> seq a a) getBlockIdNat+ bid2 <- liftM (\a -> seq a a) getBlockIdNat++ CondCode _ cond cond_code <- condFltCode cond x y+ let+ code__2 dst+ = cond_code+ `appOL` toOL+ [ NOP+ , BF cond False bid1+ , NOP++ , OR False g0 (RIImm (ImmInt 0)) dst+ , BI ALWAYS False bid2+ , NOP++ , NEWBLOCK bid1+ , OR False g0 (RIImm (ImmInt 1)) dst+ , BI ALWAYS False bid2+ , NOP++ , NEWBLOCK bid2 ]++ return (Any II32 code__2)
+ nativeGen/SPARC/CodeGen/Gen32.hs-boot view
@@ -0,0 +1,16 @@++module SPARC.CodeGen.Gen32 (+ getSomeReg,+ getRegister+)++where++import SPARC.CodeGen.Base+import NCGMonad+import Reg++import Cmm++getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)+getRegister :: CmmExpr -> NatM Register
+ nativeGen/SPARC/CodeGen/Gen64.hs view
@@ -0,0 +1,196 @@+-- | Evaluation of 64 bit values on 32 bit platforms.+module SPARC.CodeGen.Gen64 (+ assignMem_I64Code,+ assignReg_I64Code,+ iselExpr64+)++where++import {-# SOURCE #-} SPARC.CodeGen.Gen32+import SPARC.CodeGen.Base+import SPARC.CodeGen.Amode+import SPARC.Regs+import SPARC.AddrMode+import SPARC.Imm+import SPARC.Instr+import SPARC.Ppr()+import NCGMonad+import Instruction+import Format+import Reg++import Cmm++import DynFlags+import OrdList+import Outputable++-- | Code to assign a 64 bit value to memory.+assignMem_I64Code+ :: CmmExpr -- ^ expr producing the destination address+ -> CmmExpr -- ^ expr producing the source value.+ -> NatM InstrBlock++assignMem_I64Code addrTree valueTree+ = do+ ChildCode64 vcode rlo <- iselExpr64 valueTree++ (src, acode) <- getSomeReg addrTree+ let+ rhi = getHiVRegFromLo rlo++ -- Big-endian store+ mov_hi = ST II32 rhi (AddrRegImm src (ImmInt 0))+ mov_lo = ST II32 rlo (AddrRegImm src (ImmInt 4))++ code = vcode `appOL` acode `snocOL` mov_hi `snocOL` mov_lo++{- pprTrace "assignMem_I64Code"+ (vcat [ text "addrTree: " <+> ppr addrTree+ , text "valueTree: " <+> ppr valueTree+ , text "vcode:"+ , vcat $ map ppr $ fromOL vcode+ , text ""+ , text "acode:"+ , vcat $ map ppr $ fromOL acode ])+ $ -}+ return code+++-- | Code to assign a 64 bit value to a register.+assignReg_I64Code+ :: CmmReg -- ^ the destination register+ -> CmmExpr -- ^ expr producing the source value+ -> NatM InstrBlock++assignReg_I64Code (CmmLocal (LocalReg u_dst pk)) valueTree+ = do+ ChildCode64 vcode r_src_lo <- iselExpr64 valueTree+ let+ r_dst_lo = RegVirtual $ mkVirtualReg u_dst (cmmTypeFormat pk)+ r_dst_hi = getHiVRegFromLo r_dst_lo+ r_src_hi = getHiVRegFromLo r_src_lo+ mov_lo = mkMOV r_src_lo r_dst_lo+ mov_hi = mkMOV r_src_hi r_dst_hi+ mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg++ return (vcode `snocOL` mov_hi `snocOL` mov_lo)++assignReg_I64Code _ _+ = panic "assignReg_I64Code(sparc): invalid lvalue"+++++-- | Get the value of an expression into a 64 bit register.++iselExpr64 :: CmmExpr -> NatM ChildCode64++-- Load a 64 bit word+iselExpr64 (CmmLoad addrTree ty)+ | isWord64 ty+ = do Amode amode addr_code <- getAmode addrTree+ let result++ | AddrRegReg r1 r2 <- amode+ = do rlo <- getNewRegNat II32+ tmp <- getNewRegNat II32+ let rhi = getHiVRegFromLo rlo++ return $ ChildCode64+ ( addr_code+ `appOL` toOL+ [ ADD False False r1 (RIReg r2) tmp+ , LD II32 (AddrRegImm tmp (ImmInt 0)) rhi+ , LD II32 (AddrRegImm tmp (ImmInt 4)) rlo ])+ rlo++ | AddrRegImm r1 (ImmInt i) <- amode+ = do rlo <- getNewRegNat II32+ let rhi = getHiVRegFromLo rlo++ return $ ChildCode64+ ( addr_code+ `appOL` toOL+ [ LD II32 (AddrRegImm r1 (ImmInt $ 0 + i)) rhi+ , LD II32 (AddrRegImm r1 (ImmInt $ 4 + i)) rlo ])+ rlo++ | otherwise+ = panic "SPARC.CodeGen.Gen64: no match"++ result+++-- Add a literal to a 64 bit integer+iselExpr64 (CmmMachOp (MO_Add _) [e1, CmmLit (CmmInt i _)])+ = do ChildCode64 code1 r1_lo <- iselExpr64 e1+ let r1_hi = getHiVRegFromLo r1_lo++ r_dst_lo <- getNewRegNat II32+ let r_dst_hi = getHiVRegFromLo r_dst_lo++ let code = code1+ `appOL` toOL+ [ ADD False True r1_lo (RIImm (ImmInteger i)) r_dst_lo+ , ADD True False r1_hi (RIReg g0) r_dst_hi ]++ return $ ChildCode64 code r_dst_lo+++-- Addition of II64+iselExpr64 (CmmMachOp (MO_Add _) [e1, e2])+ = do ChildCode64 code1 r1_lo <- iselExpr64 e1+ let r1_hi = getHiVRegFromLo r1_lo++ ChildCode64 code2 r2_lo <- iselExpr64 e2+ let r2_hi = getHiVRegFromLo r2_lo++ r_dst_lo <- getNewRegNat II32+ let r_dst_hi = getHiVRegFromLo r_dst_lo++ let code = code1+ `appOL` code2+ `appOL` toOL+ [ ADD False True r1_lo (RIReg r2_lo) r_dst_lo+ , ADD True False r1_hi (RIReg r2_hi) r_dst_hi ]++ return $ ChildCode64 code r_dst_lo+++iselExpr64 (CmmReg (CmmLocal (LocalReg uq ty)))+ | isWord64 ty+ = do+ r_dst_lo <- getNewRegNat II32+ let r_dst_hi = getHiVRegFromLo r_dst_lo+ r_src_lo = RegVirtual $ mkVirtualReg uq II32+ r_src_hi = getHiVRegFromLo r_src_lo+ mov_lo = mkMOV r_src_lo r_dst_lo+ mov_hi = mkMOV r_src_hi r_dst_hi+ mkMOV sreg dreg = OR False g0 (RIReg sreg) dreg+ return (+ ChildCode64 (toOL [mov_hi, mov_lo]) r_dst_lo+ )++-- Convert something into II64+iselExpr64 (CmmMachOp (MO_UU_Conv _ W64) [expr])+ = do+ r_dst_lo <- getNewRegNat II32+ let r_dst_hi = getHiVRegFromLo r_dst_lo++ -- compute expr and load it into r_dst_lo+ (a_reg, a_code) <- getSomeReg expr++ dflags <- getDynFlags+ let platform = targetPlatform dflags+ code = a_code+ `appOL` toOL+ [ mkRegRegMoveInstr platform g0 r_dst_hi -- clear high 32 bits+ , mkRegRegMoveInstr platform a_reg r_dst_lo ]++ return $ ChildCode64 code r_dst_lo+++iselExpr64 expr+ = pprPanic "iselExpr64(sparc)" (ppr expr)
+ nativeGen/SPARC/CodeGen/Sanity.hs view
@@ -0,0 +1,67 @@+-- | One ounce of sanity checking is worth 10000000000000000 ounces+-- of staring blindly at assembly code trying to find the problem..+module SPARC.CodeGen.Sanity (+ checkBlock+)++where++import SPARC.Instr+import SPARC.Ppr ()+import Instruction++import Cmm++import Outputable+++-- | Enforce intra-block invariants.+--+checkBlock :: CmmBlock+ -> NatBasicBlock Instr+ -> NatBasicBlock Instr++checkBlock cmm block@(BasicBlock _ instrs)+ | checkBlockInstrs instrs+ = block++ | otherwise+ = pprPanic+ ("SPARC.CodeGen: bad block\n")+ ( vcat [ text " -- cmm -----------------\n"+ , ppr cmm+ , text " -- native code ---------\n"+ , ppr block ])+++checkBlockInstrs :: [Instr] -> Bool+checkBlockInstrs ii++ -- An unconditional jumps end the block.+ -- There must be an unconditional jump in the block, otherwise+ -- the register liveness determinator will get the liveness+ -- information wrong.+ --+ -- If the block ends with a cmm call that never returns+ -- then there can be unreachable instructions after the jump,+ -- but we don't mind here.+ --+ | instr : NOP : _ <- ii+ , isUnconditionalJump instr+ = True++ -- All jumps must have a NOP in their branch delay slot.+ -- The liveness determinator and register allocators aren't smart+ -- enough to handle branch delay slots.+ --+ | instr : NOP : is <- ii+ , isJumpishInstr instr+ = checkBlockInstrs is++ -- keep checking+ | _:i2:is <- ii+ = checkBlockInstrs (i2:is)++ -- this block is no good+ | otherwise+ = False
+ nativeGen/SPARC/Cond.hs view
@@ -0,0 +1,52 @@+module SPARC.Cond (+ Cond(..),+ condUnsigned,+ condToSigned,+ condToUnsigned+)++where++-- | Branch condition codes.+data Cond+ = ALWAYS+ | EQQ+ | GE+ | GEU+ | GTT+ | GU+ | LE+ | LEU+ | LTT+ | LU+ | NE+ | NEG+ | NEVER+ | POS+ | VC+ | VS+ deriving Eq+++condUnsigned :: Cond -> Bool+condUnsigned GU = True+condUnsigned LU = True+condUnsigned GEU = True+condUnsigned LEU = True+condUnsigned _ = False+++condToSigned :: Cond -> Cond+condToSigned GU = GTT+condToSigned LU = LTT+condToSigned GEU = GE+condToSigned LEU = LE+condToSigned x = x+++condToUnsigned :: Cond -> Cond+condToUnsigned GTT = GU+condToUnsigned LTT = LU+condToUnsigned GE = GEU+condToUnsigned LE = LEU+condToUnsigned x = x
+ nativeGen/SPARC/Imm.hs view
@@ -0,0 +1,65 @@+module SPARC.Imm (+ -- immediate values+ Imm(..),+ strImmLit,+ litToImm+)++where++import Cmm+import CLabel++import Outputable++-- | An immediate value.+-- Not all of these are directly representable by the machine.+-- Things like ImmLit are slurped out and put in a data segment instead.+--+data Imm+ = ImmInt Int++ -- Sigh.+ | ImmInteger Integer++ -- AbstractC Label (with baggage)+ | ImmCLbl CLabel++ -- Simple string+ | ImmLit SDoc+ | ImmIndex CLabel Int+ | ImmFloat Rational+ | ImmDouble Rational++ | ImmConstantSum Imm Imm+ | ImmConstantDiff Imm Imm++ | LO Imm+ | HI Imm+++-- | Create a ImmLit containing this string.+strImmLit :: String -> Imm+strImmLit s = ImmLit (text s)+++-- | Convert a CmmLit to an Imm.+-- Narrow to the width: a CmmInt might be out of+-- range, but we assume that ImmInteger only contains+-- in-range values. A signed value should be fine here.+--+litToImm :: CmmLit -> Imm+litToImm lit+ = case lit of+ CmmInt i w -> ImmInteger (narrowS w i)+ CmmFloat f W32 -> ImmFloat f+ CmmFloat f W64 -> ImmDouble f+ CmmLabel l -> ImmCLbl l+ CmmLabelOff l off -> ImmIndex l off++ CmmLabelDiffOff l1 l2 off+ -> ImmConstantSum+ (ImmConstantDiff (ImmCLbl l1) (ImmCLbl l2))+ (ImmInt off)++ _ -> panic "SPARC.Regs.litToImm: no match"
+ nativeGen/SPARC/Instr.hs view
@@ -0,0 +1,483 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Machine-dependent assembly language+--+-- (c) The University of Glasgow 1993-2004+--+-----------------------------------------------------------------------------+#include "HsVersions.h"+#include "nativeGen/NCG.h"++module SPARC.Instr (+ RI(..),+ riZero,++ fpRelEA,+ moveSp,++ isUnconditionalJump,++ Instr(..),+ maxSpillSlots+)++where++import SPARC.Stack+import SPARC.Imm+import SPARC.AddrMode+import SPARC.Cond+import SPARC.Regs+import SPARC.Base+import TargetReg+import Instruction+import RegClass+import Reg+import Format++import CLabel+import CodeGen.Platform+import BlockId+import DynFlags+import Cmm+import FastString+import Outputable+import Platform+++-- | Register or immediate+data RI+ = RIReg Reg+ | RIImm Imm++-- | Check if a RI represents a zero value.+-- - a literal zero+-- - register %g0, which is always zero.+--+riZero :: RI -> Bool+riZero (RIImm (ImmInt 0)) = True+riZero (RIImm (ImmInteger 0)) = True+riZero (RIReg (RegReal (RealRegSingle 0))) = True+riZero _ = False+++-- | Calculate the effective address which would be used by the+-- corresponding fpRel sequence.+fpRelEA :: Int -> Reg -> Instr+fpRelEA n dst+ = ADD False False fp (RIImm (ImmInt (n * wordLength))) dst+++-- | Code to shift the stack pointer by n words.+moveSp :: Int -> Instr+moveSp n+ = ADD False False sp (RIImm (ImmInt (n * wordLength))) sp++-- | An instruction that will cause the one after it never to be exectuted+isUnconditionalJump :: Instr -> Bool+isUnconditionalJump ii+ = case ii of+ CALL{} -> True+ JMP{} -> True+ JMP_TBL{} -> True+ BI ALWAYS _ _ -> True+ BF ALWAYS _ _ -> True+ _ -> False+++-- | instance for sparc instruction set+instance Instruction Instr where+ regUsageOfInstr = sparc_regUsageOfInstr+ patchRegsOfInstr = sparc_patchRegsOfInstr+ isJumpishInstr = sparc_isJumpishInstr+ jumpDestsOfInstr = sparc_jumpDestsOfInstr+ patchJumpInstr = sparc_patchJumpInstr+ mkSpillInstr = sparc_mkSpillInstr+ mkLoadInstr = sparc_mkLoadInstr+ takeDeltaInstr = sparc_takeDeltaInstr+ isMetaInstr = sparc_isMetaInstr+ mkRegRegMoveInstr = sparc_mkRegRegMoveInstr+ takeRegRegMoveInstr = sparc_takeRegRegMoveInstr+ mkJumpInstr = sparc_mkJumpInstr+ mkStackAllocInstr = panic "no sparc_mkStackAllocInstr"+ mkStackDeallocInstr = panic "no sparc_mkStackDeallocInstr"+++-- | SPARC instruction set.+-- Not complete. This is only the ones we need.+--+data Instr++ -- meta ops --------------------------------------------------+ -- comment pseudo-op+ = COMMENT FastString++ -- some static data spat out during code generation.+ -- Will be extracted before pretty-printing.+ | LDATA Section CmmStatics++ -- Start a new basic block. Useful during codegen, removed later.+ -- Preceding instruction should be a jump, as per the invariants+ -- for a BasicBlock (see Cmm).+ | NEWBLOCK BlockId++ -- specify current stack offset for benefit of subsequent passes.+ | DELTA Int++ -- real instrs -----------------------------------------------+ -- Loads and stores.+ | LD Format AddrMode Reg -- format, src, dst+ | ST Format Reg AddrMode -- format, src, dst++ -- Int Arithmetic.+ -- x: add/sub with carry bit.+ -- In SPARC V9 addx and friends were renamed addc.+ --+ -- cc: modify condition codes+ --+ | ADD Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst+ | SUB Bool Bool Reg RI Reg -- x?, cc?, src1, src2, dst++ | UMUL Bool Reg RI Reg -- cc?, src1, src2, dst+ | SMUL Bool Reg RI Reg -- cc?, src1, src2, dst+++ -- The SPARC divide instructions perform 64bit by 32bit division+ -- The Y register is xored into the first operand.++ -- On _some implementations_ the Y register is overwritten by+ -- the remainder, so we have to make sure it is 0 each time.++ -- dst <- ((Y `shiftL` 32) `or` src1) `div` src2+ | UDIV Bool Reg RI Reg -- cc?, src1, src2, dst+ | SDIV Bool Reg RI Reg -- cc?, src1, src2, dst++ | RDY Reg -- move contents of Y register to reg+ | WRY Reg Reg -- Y <- src1 `xor` src2++ -- Logic operations.+ | AND Bool Reg RI Reg -- cc?, src1, src2, dst+ | ANDN Bool Reg RI Reg -- cc?, src1, src2, dst+ | OR Bool Reg RI Reg -- cc?, src1, src2, dst+ | ORN Bool Reg RI Reg -- cc?, src1, src2, dst+ | XOR Bool Reg RI Reg -- cc?, src1, src2, dst+ | XNOR Bool Reg RI Reg -- cc?, src1, src2, dst+ | SLL Reg RI Reg -- src1, src2, dst+ | SRL Reg RI Reg -- src1, src2, dst+ | SRA Reg RI Reg -- src1, src2, dst++ -- Load immediates.+ | SETHI Imm Reg -- src, dst++ -- Do nothing.+ -- Implemented by the assembler as SETHI 0, %g0, but worth an alias+ | NOP++ -- Float Arithmetic.+ -- Note that we cheat by treating F{ABS,MOV,NEG} of doubles as single+ -- instructions right up until we spit them out.+ --+ | FABS Format Reg Reg -- src dst+ | FADD Format Reg Reg Reg -- src1, src2, dst+ | FCMP Bool Format Reg Reg -- exception?, src1, src2, dst+ | FDIV Format Reg Reg Reg -- src1, src2, dst+ | FMOV Format Reg Reg -- src, dst+ | FMUL Format Reg Reg Reg -- src1, src2, dst+ | FNEG Format Reg Reg -- src, dst+ | FSQRT Format Reg Reg -- src, dst+ | FSUB Format Reg Reg Reg -- src1, src2, dst+ | FxTOy Format Format Reg Reg -- src, dst++ -- Jumping around.+ | BI Cond Bool BlockId -- cond, annul?, target+ | BF Cond Bool BlockId -- cond, annul?, target++ | JMP AddrMode -- target++ -- With a tabled jump we know all the possible destinations.+ -- We also need this info so we can work out what regs are live across the jump.+ --+ | JMP_TBL AddrMode [Maybe BlockId] CLabel++ | CALL (Either Imm Reg) Int Bool -- target, args, terminal+++-- | regUsage returns the sets of src and destination registers used+-- by a particular instruction. Machine registers that are+-- pre-allocated to stgRegs are filtered out, because they are+-- uninteresting from a register allocation standpoint. (We wouldn't+-- want them to end up on the free list!) As far as we are concerned,+-- the fixed registers simply don't exist (for allocation purposes,+-- anyway).++-- regUsage doesn't need to do any trickery for jumps and such. Just+-- state precisely the regs read and written by that insn. The+-- consequences of control flow transfers, as far as register+-- allocation goes, are taken care of by the register allocator.+--+sparc_regUsageOfInstr :: Platform -> Instr -> RegUsage+sparc_regUsageOfInstr platform instr+ = case instr of+ LD _ addr reg -> usage (regAddr addr, [reg])+ ST _ reg addr -> usage (reg : regAddr addr, [])+ ADD _ _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SUB _ _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ UMUL _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SMUL _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ UDIV _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SDIV _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ RDY rd -> usage ([], [rd])+ WRY r1 r2 -> usage ([r1, r2], [])+ AND _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ ANDN _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ OR _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ ORN _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ XOR _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ XNOR _ r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SLL r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SRL r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SRA r1 ar r2 -> usage (r1 : regRI ar, [r2])+ SETHI _ reg -> usage ([], [reg])+ FABS _ r1 r2 -> usage ([r1], [r2])+ FADD _ r1 r2 r3 -> usage ([r1, r2], [r3])+ FCMP _ _ r1 r2 -> usage ([r1, r2], [])+ FDIV _ r1 r2 r3 -> usage ([r1, r2], [r3])+ FMOV _ r1 r2 -> usage ([r1], [r2])+ FMUL _ r1 r2 r3 -> usage ([r1, r2], [r3])+ FNEG _ r1 r2 -> usage ([r1], [r2])+ FSQRT _ r1 r2 -> usage ([r1], [r2])+ FSUB _ r1 r2 r3 -> usage ([r1, r2], [r3])+ FxTOy _ _ r1 r2 -> usage ([r1], [r2])++ JMP addr -> usage (regAddr addr, [])+ JMP_TBL addr _ _ -> usage (regAddr addr, [])++ CALL (Left _ ) _ True -> noUsage+ CALL (Left _ ) n False -> usage (argRegs n, callClobberedRegs)+ CALL (Right reg) _ True -> usage ([reg], [])+ CALL (Right reg) n False -> usage (reg : (argRegs n), callClobberedRegs)+ _ -> noUsage++ where+ usage (src, dst)+ = RU (filter (interesting platform) src)+ (filter (interesting platform) dst)++ regAddr (AddrRegReg r1 r2) = [r1, r2]+ regAddr (AddrRegImm r1 _) = [r1]++ regRI (RIReg r) = [r]+ regRI _ = []+++-- | Interesting regs are virtuals, or ones that are allocatable+-- by the register allocator.+interesting :: Platform -> Reg -> Bool+interesting platform reg+ = case reg of+ RegVirtual _ -> True+ RegReal (RealRegSingle r1) -> freeReg platform r1+ RegReal (RealRegPair r1 _) -> freeReg platform r1++++-- | Apply a given mapping to tall the register references in this instruction.+sparc_patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr+sparc_patchRegsOfInstr instr env = case instr of+ LD fmt addr reg -> LD fmt (fixAddr addr) (env reg)+ ST fmt reg addr -> ST fmt (env reg) (fixAddr addr)++ ADD x cc r1 ar r2 -> ADD x cc (env r1) (fixRI ar) (env r2)+ SUB x cc r1 ar r2 -> SUB x cc (env r1) (fixRI ar) (env r2)+ UMUL cc r1 ar r2 -> UMUL cc (env r1) (fixRI ar) (env r2)+ SMUL cc r1 ar r2 -> SMUL cc (env r1) (fixRI ar) (env r2)+ UDIV cc r1 ar r2 -> UDIV cc (env r1) (fixRI ar) (env r2)+ SDIV cc r1 ar r2 -> SDIV cc (env r1) (fixRI ar) (env r2)+ RDY rd -> RDY (env rd)+ WRY r1 r2 -> WRY (env r1) (env r2)+ AND b r1 ar r2 -> AND b (env r1) (fixRI ar) (env r2)+ ANDN b r1 ar r2 -> ANDN b (env r1) (fixRI ar) (env r2)+ OR b r1 ar r2 -> OR b (env r1) (fixRI ar) (env r2)+ ORN b r1 ar r2 -> ORN b (env r1) (fixRI ar) (env r2)+ XOR b r1 ar r2 -> XOR b (env r1) (fixRI ar) (env r2)+ XNOR b r1 ar r2 -> XNOR b (env r1) (fixRI ar) (env r2)+ SLL r1 ar r2 -> SLL (env r1) (fixRI ar) (env r2)+ SRL r1 ar r2 -> SRL (env r1) (fixRI ar) (env r2)+ SRA r1 ar r2 -> SRA (env r1) (fixRI ar) (env r2)++ SETHI imm reg -> SETHI imm (env reg)++ FABS s r1 r2 -> FABS s (env r1) (env r2)+ FADD s r1 r2 r3 -> FADD s (env r1) (env r2) (env r3)+ FCMP e s r1 r2 -> FCMP e s (env r1) (env r2)+ FDIV s r1 r2 r3 -> FDIV s (env r1) (env r2) (env r3)+ FMOV s r1 r2 -> FMOV s (env r1) (env r2)+ FMUL s r1 r2 r3 -> FMUL s (env r1) (env r2) (env r3)+ FNEG s r1 r2 -> FNEG s (env r1) (env r2)+ FSQRT s r1 r2 -> FSQRT s (env r1) (env r2)+ FSUB s r1 r2 r3 -> FSUB s (env r1) (env r2) (env r3)+ FxTOy s1 s2 r1 r2 -> FxTOy s1 s2 (env r1) (env r2)++ JMP addr -> JMP (fixAddr addr)+ JMP_TBL addr ids l -> JMP_TBL (fixAddr addr) ids l++ CALL (Left i) n t -> CALL (Left i) n t+ CALL (Right r) n t -> CALL (Right (env r)) n t+ _ -> instr++ where+ fixAddr (AddrRegReg r1 r2) = AddrRegReg (env r1) (env r2)+ fixAddr (AddrRegImm r1 i) = AddrRegImm (env r1) i++ fixRI (RIReg r) = RIReg (env r)+ fixRI other = other+++--------------------------------------------------------------------------------+sparc_isJumpishInstr :: Instr -> Bool+sparc_isJumpishInstr instr+ = case instr of+ BI{} -> True+ BF{} -> True+ JMP{} -> True+ JMP_TBL{} -> True+ CALL{} -> True+ _ -> False++sparc_jumpDestsOfInstr :: Instr -> [BlockId]+sparc_jumpDestsOfInstr insn+ = case insn of+ BI _ _ id -> [id]+ BF _ _ id -> [id]+ JMP_TBL _ ids _ -> [id | Just id <- ids]+ _ -> []+++sparc_patchJumpInstr :: Instr -> (BlockId -> BlockId) -> Instr+sparc_patchJumpInstr insn patchF+ = case insn of+ BI cc annul id -> BI cc annul (patchF id)+ BF cc annul id -> BF cc annul (patchF id)+ JMP_TBL n ids l -> JMP_TBL n (map (fmap patchF) ids) l+ _ -> insn+++--------------------------------------------------------------------------------+-- | Make a spill instruction.+-- On SPARC we spill below frame pointer leaving 2 words/spill+sparc_mkSpillInstr+ :: DynFlags+ -> Reg -- ^ register to spill+ -> Int -- ^ current stack delta+ -> Int -- ^ spill slot to use+ -> Instr++sparc_mkSpillInstr dflags reg _ slot+ = let platform = targetPlatform dflags+ off = spillSlotToOffset dflags slot+ off_w = 1 + (off `div` 4)+ fmt = case targetClassOfReg platform reg of+ RcInteger -> II32+ RcFloat -> FF32+ RcDouble -> FF64+ _ -> panic "sparc_mkSpillInstr"++ in ST fmt reg (fpRel (negate off_w))+++-- | Make a spill reload instruction.+sparc_mkLoadInstr+ :: DynFlags+ -> Reg -- ^ register to load into+ -> Int -- ^ current stack delta+ -> Int -- ^ spill slot to use+ -> Instr++sparc_mkLoadInstr dflags reg _ slot+ = let platform = targetPlatform dflags+ off = spillSlotToOffset dflags slot+ off_w = 1 + (off `div` 4)+ fmt = case targetClassOfReg platform reg of+ RcInteger -> II32+ RcFloat -> FF32+ RcDouble -> FF64+ _ -> panic "sparc_mkLoadInstr"++ in LD fmt (fpRel (- off_w)) reg+++--------------------------------------------------------------------------------+-- | See if this instruction is telling us the current C stack delta+sparc_takeDeltaInstr+ :: Instr+ -> Maybe Int++sparc_takeDeltaInstr instr+ = case instr of+ DELTA i -> Just i+ _ -> Nothing+++sparc_isMetaInstr+ :: Instr+ -> Bool++sparc_isMetaInstr instr+ = case instr of+ COMMENT{} -> True+ LDATA{} -> True+ NEWBLOCK{} -> True+ DELTA{} -> True+ _ -> False+++-- | Make a reg-reg move instruction.+-- On SPARC v8 there are no instructions to move directly between+-- floating point and integer regs. If we need to do that then we+-- have to go via memory.+--+sparc_mkRegRegMoveInstr+ :: Platform+ -> Reg+ -> Reg+ -> Instr++sparc_mkRegRegMoveInstr platform src dst+ | srcClass <- targetClassOfReg platform src+ , dstClass <- targetClassOfReg platform dst+ , srcClass == dstClass+ = case srcClass of+ RcInteger -> ADD False False src (RIReg g0) dst+ RcDouble -> FMOV FF64 src dst+ RcFloat -> FMOV FF32 src dst+ _ -> panic "sparc_mkRegRegMoveInstr"++ | otherwise+ = panic "SPARC.Instr.mkRegRegMoveInstr: classes of src and dest not the same"+++-- | Check whether an instruction represents a reg-reg move.+-- The register allocator attempts to eliminate reg->reg moves whenever it can,+-- by assigning the src and dest temporaries to the same real register.+--+sparc_takeRegRegMoveInstr :: Instr -> Maybe (Reg,Reg)+sparc_takeRegRegMoveInstr instr+ = case instr of+ ADD False False src (RIReg src2) dst+ | g0 == src2 -> Just (src, dst)++ FMOV FF64 src dst -> Just (src, dst)+ FMOV FF32 src dst -> Just (src, dst)+ _ -> Nothing+++-- | Make an unconditional branch instruction.+sparc_mkJumpInstr+ :: BlockId+ -> [Instr]++sparc_mkJumpInstr id+ = [BI ALWAYS False id+ , NOP] -- fill the branch delay slot.
+ nativeGen/SPARC/Ppr.hs view
@@ -0,0 +1,647 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Pretty-printing assembly language+--+-- (c) The University of Glasgow 1993-2005+--+-----------------------------------------------------------------------------++{-# OPTIONS_GHC -fno-warn-orphans #-}++module SPARC.Ppr (+ pprNatCmmDecl,+ pprBasicBlock,+ pprData,+ pprInstr,+ pprFormat,+ pprImm,+ pprDataItem+)++where++#include "HsVersions.h"+#include "nativeGen/NCG.h"++import SPARC.Regs+import SPARC.Instr+import SPARC.Cond+import SPARC.Imm+import SPARC.AddrMode+import SPARC.Base+import Instruction+import Reg+import Format+import PprBase++import Cmm hiding (topInfoTable)+import PprCmm()+import CLabel+import Hoopl++import Unique ( Uniquable(..), pprUniqueAlways )+import Outputable+import Platform+import FastString+import Data.Word++-- -----------------------------------------------------------------------------+-- Printing this stuff out++pprNatCmmDecl :: NatCmmDecl CmmStatics Instr -> SDoc+pprNatCmmDecl (CmmData section dats) =+ pprSectionAlign section $$ pprDatas dats++pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =+ case topInfoTable proc of+ Nothing ->+ case blocks of+ [] -> -- special case for split markers:+ pprLabel lbl+ blocks -> -- special case for code without info table:+ pprSectionAlign (Section Text lbl) $$+ pprLabel lbl $$ -- blocks guaranteed not null, so label needed+ vcat (map (pprBasicBlock top_info) blocks)++ Just (Statics info_lbl _) ->+ sdocWithPlatform $ \platform ->+ (if platformHasSubsectionsViaSymbols platform+ then pprSectionAlign dspSection $$+ ppr (mkDeadStripPreventer info_lbl) <> char ':'+ else empty) $$+ vcat (map (pprBasicBlock top_info) blocks) $$+ -- above: Even the first block gets a label, because with branch-chain+ -- elimination, it might be the target of a goto.+ (if platformHasSubsectionsViaSymbols platform+ then+ -- See Note [Subsections Via Symbols] in X86/Ppr.hs+ text "\t.long "+ <+> ppr info_lbl+ <+> char '-'+ <+> ppr (mkDeadStripPreventer info_lbl)+ else empty)++dspSection :: Section+dspSection = Section Text $+ panic "subsections-via-symbols doesn't combine with split-sections"++pprBasicBlock :: LabelMap CmmStatics -> NatBasicBlock Instr -> SDoc+pprBasicBlock info_env (BasicBlock blockid instrs)+ = maybe_infotable $$+ pprLabel (mkAsmTempLabel (getUnique blockid)) $$+ vcat (map pprInstr instrs)+ where+ maybe_infotable = case mapLookup blockid info_env of+ Nothing -> empty+ Just (Statics info_lbl info) ->+ pprAlignForSection Text $$+ vcat (map pprData info) $$+ pprLabel info_lbl+++pprDatas :: CmmStatics -> SDoc+pprDatas (Statics lbl dats) = vcat (pprLabel lbl : map pprData dats)++pprData :: CmmStatic -> SDoc+pprData (CmmString str) = pprASCII str+pprData (CmmUninitialised bytes) = text ".skip " <> int bytes+pprData (CmmStaticLit lit) = pprDataItem lit++pprGloblDecl :: CLabel -> SDoc+pprGloblDecl lbl+ | not (externallyVisibleCLabel lbl) = empty+ | otherwise = text ".global " <> ppr lbl++pprTypeAndSizeDecl :: CLabel -> SDoc+pprTypeAndSizeDecl lbl+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSLinux && externallyVisibleCLabel lbl+ then text ".type " <> ppr lbl <> ptext (sLit ", @object")+ else empty++pprLabel :: CLabel -> SDoc+pprLabel lbl = pprGloblDecl lbl+ $$ pprTypeAndSizeDecl lbl+ $$ (ppr lbl <> char ':')+++pprASCII :: [Word8] -> SDoc+pprASCII str+ = vcat (map do1 str) $$ do1 0+ where+ do1 :: Word8 -> SDoc+ do1 w = text "\t.byte\t" <> int (fromIntegral w)+++-- -----------------------------------------------------------------------------+-- pprInstr: print an 'Instr'++instance Outputable Instr where+ ppr instr = pprInstr instr+++-- | Pretty print a register.+pprReg :: Reg -> SDoc+pprReg reg+ = case reg of+ RegVirtual vr+ -> case vr of+ VirtualRegI u -> text "%vI_" <> pprUniqueAlways u+ VirtualRegHi u -> text "%vHi_" <> pprUniqueAlways u+ VirtualRegF u -> text "%vF_" <> pprUniqueAlways u+ VirtualRegD u -> text "%vD_" <> pprUniqueAlways u+ VirtualRegSSE u -> text "%vSSE_" <> pprUniqueAlways u++ RegReal rr+ -> case rr of+ RealRegSingle r1+ -> pprReg_ofRegNo r1++ RealRegPair r1 r2+ -> text "(" <> pprReg_ofRegNo r1+ <> vbar <> pprReg_ofRegNo r2+ <> text ")"++++-- | Pretty print a register name, based on this register number.+-- The definition has been unfolded so we get a jump-table in the+-- object code. This function is called quite a lot when emitting+-- the asm file..+--+pprReg_ofRegNo :: Int -> SDoc+pprReg_ofRegNo i+ = ptext+ (case i of {+ 0 -> sLit "%g0"; 1 -> sLit "%g1";+ 2 -> sLit "%g2"; 3 -> sLit "%g3";+ 4 -> sLit "%g4"; 5 -> sLit "%g5";+ 6 -> sLit "%g6"; 7 -> sLit "%g7";+ 8 -> sLit "%o0"; 9 -> sLit "%o1";+ 10 -> sLit "%o2"; 11 -> sLit "%o3";+ 12 -> sLit "%o4"; 13 -> sLit "%o5";+ 14 -> sLit "%o6"; 15 -> sLit "%o7";+ 16 -> sLit "%l0"; 17 -> sLit "%l1";+ 18 -> sLit "%l2"; 19 -> sLit "%l3";+ 20 -> sLit "%l4"; 21 -> sLit "%l5";+ 22 -> sLit "%l6"; 23 -> sLit "%l7";+ 24 -> sLit "%i0"; 25 -> sLit "%i1";+ 26 -> sLit "%i2"; 27 -> sLit "%i3";+ 28 -> sLit "%i4"; 29 -> sLit "%i5";+ 30 -> sLit "%i6"; 31 -> sLit "%i7";+ 32 -> sLit "%f0"; 33 -> sLit "%f1";+ 34 -> sLit "%f2"; 35 -> sLit "%f3";+ 36 -> sLit "%f4"; 37 -> sLit "%f5";+ 38 -> sLit "%f6"; 39 -> sLit "%f7";+ 40 -> sLit "%f8"; 41 -> sLit "%f9";+ 42 -> sLit "%f10"; 43 -> sLit "%f11";+ 44 -> sLit "%f12"; 45 -> sLit "%f13";+ 46 -> sLit "%f14"; 47 -> sLit "%f15";+ 48 -> sLit "%f16"; 49 -> sLit "%f17";+ 50 -> sLit "%f18"; 51 -> sLit "%f19";+ 52 -> sLit "%f20"; 53 -> sLit "%f21";+ 54 -> sLit "%f22"; 55 -> sLit "%f23";+ 56 -> sLit "%f24"; 57 -> sLit "%f25";+ 58 -> sLit "%f26"; 59 -> sLit "%f27";+ 60 -> sLit "%f28"; 61 -> sLit "%f29";+ 62 -> sLit "%f30"; 63 -> sLit "%f31";+ _ -> sLit "very naughty sparc register" })+++-- | Pretty print a format for an instruction suffix.+pprFormat :: Format -> SDoc+pprFormat x+ = ptext+ (case x of+ II8 -> sLit "ub"+ II16 -> sLit "uh"+ II32 -> sLit ""+ II64 -> sLit "d"+ FF32 -> sLit ""+ FF64 -> sLit "d"+ _ -> panic "SPARC.Ppr.pprFormat: no match")+++-- | Pretty print a format for an instruction suffix.+-- eg LD is 32bit on sparc, but LDD is 64 bit.+pprStFormat :: Format -> SDoc+pprStFormat x+ = ptext+ (case x of+ II8 -> sLit "b"+ II16 -> sLit "h"+ II32 -> sLit ""+ II64 -> sLit "x"+ FF32 -> sLit ""+ FF64 -> sLit "d"+ _ -> panic "SPARC.Ppr.pprFormat: no match")+++-- | Pretty print a condition code.+pprCond :: Cond -> SDoc+pprCond c+ = ptext+ (case c of+ ALWAYS -> sLit ""+ NEVER -> sLit "n"+ GEU -> sLit "geu"+ LU -> sLit "lu"+ EQQ -> sLit "e"+ GTT -> sLit "g"+ GE -> sLit "ge"+ GU -> sLit "gu"+ LTT -> sLit "l"+ LE -> sLit "le"+ LEU -> sLit "leu"+ NE -> sLit "ne"+ NEG -> sLit "neg"+ POS -> sLit "pos"+ VC -> sLit "vc"+ VS -> sLit "vs")+++-- | Pretty print an address mode.+pprAddr :: AddrMode -> SDoc+pprAddr am+ = case am of+ AddrRegReg r1 (RegReal (RealRegSingle 0))+ -> pprReg r1++ AddrRegReg r1 r2+ -> hcat [ pprReg r1, char '+', pprReg r2 ]++ AddrRegImm r1 (ImmInt i)+ | i == 0 -> pprReg r1+ | not (fits13Bits i) -> largeOffsetError i+ | otherwise -> hcat [ pprReg r1, pp_sign, int i ]+ where+ pp_sign = if i > 0 then char '+' else empty++ AddrRegImm r1 (ImmInteger i)+ | i == 0 -> pprReg r1+ | not (fits13Bits i) -> largeOffsetError i+ | otherwise -> hcat [ pprReg r1, pp_sign, integer i ]+ where+ pp_sign = if i > 0 then char '+' else empty++ AddrRegImm r1 imm+ -> hcat [ pprReg r1, char '+', pprImm imm ]+++-- | Pretty print an immediate value.+pprImm :: Imm -> SDoc+pprImm imm+ = case imm of+ ImmInt i -> int i+ ImmInteger i -> integer i+ ImmCLbl l -> ppr l+ ImmIndex l i -> ppr l <> char '+' <> int i+ ImmLit s -> s++ ImmConstantSum a b+ -> pprImm a <> char '+' <> pprImm b++ ImmConstantDiff a b+ -> pprImm a <> char '-' <> lparen <> pprImm b <> rparen++ LO i+ -> hcat [ text "%lo(", pprImm i, rparen ]++ HI i+ -> hcat [ text "%hi(", pprImm i, rparen ]++ -- these should have been converted to bytes and placed+ -- in the data section.+ ImmFloat _ -> text "naughty float immediate"+ ImmDouble _ -> text "naughty double immediate"+++-- | Pretty print a section \/ segment header.+-- On SPARC all the data sections must be at least 8 byte aligned+-- incase we store doubles in them.+--+pprSectionAlign :: Section -> SDoc+pprSectionAlign sec@(Section seg _) =+ sdocWithPlatform $ \platform ->+ pprSectionHeader platform sec $$+ pprAlignForSection seg++-- | Print appropriate alignment for the given section type.+pprAlignForSection :: SectionType -> SDoc+pprAlignForSection seg =+ ptext (case seg of+ Text -> sLit ".align 4"+ Data -> sLit ".align 8"+ ReadOnlyData -> sLit ".align 8"+ RelocatableReadOnlyData+ -> sLit ".align 8"+ UninitialisedData -> sLit ".align 8"+ ReadOnlyData16 -> sLit ".align 16"+ -- TODO: This is copied from the ReadOnlyData case, but it can likely be+ -- made more efficient.+ CString -> sLit ".align 8"+ OtherSection _ -> panic "PprMach.pprSectionHeader: unknown section")++-- | Pretty print a data item.+pprDataItem :: CmmLit -> SDoc+pprDataItem lit+ = sdocWithDynFlags $ \dflags ->+ vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit)+ where+ imm = litToImm lit++ ppr_item II8 _ = [text "\t.byte\t" <> pprImm imm]+ ppr_item II32 _ = [text "\t.long\t" <> pprImm imm]++ ppr_item FF32 (CmmFloat r _)+ = let bs = floatToBytes (fromRational r)+ in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs++ ppr_item FF64 (CmmFloat r _)+ = let bs = doubleToBytes (fromRational r)+ in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs++ ppr_item II16 _ = [text "\t.short\t" <> pprImm imm]+ ppr_item II64 _ = [text "\t.quad\t" <> pprImm imm]+ ppr_item _ _ = panic "SPARC.Ppr.pprDataItem: no match"+++-- | Pretty print an instruction.+pprInstr :: Instr -> SDoc++-- nuke comments.+pprInstr (COMMENT _)+ = empty++pprInstr (DELTA d)+ = pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))++-- Newblocks and LData should have been slurped out before producing the .s file.+pprInstr (NEWBLOCK _)+ = panic "X86.Ppr.pprInstr: NEWBLOCK"++pprInstr (LDATA _ _)+ = panic "PprMach.pprInstr: LDATA"++-- 64 bit FP loads are expanded into individual instructions in CodeGen.Expand+pprInstr (LD FF64 _ reg)+ | RegReal (RealRegSingle{}) <- reg+ = panic "SPARC.Ppr: not emitting potentially misaligned LD FF64 instr"++pprInstr (LD format addr reg)+ = hcat [+ text "\tld",+ pprFormat format,+ char '\t',+ lbrack,+ pprAddr addr,+ pp_rbracket_comma,+ pprReg reg+ ]++-- 64 bit FP storees are expanded into individual instructions in CodeGen.Expand+pprInstr (ST FF64 reg _)+ | RegReal (RealRegSingle{}) <- reg+ = panic "SPARC.Ppr: not emitting potentially misaligned ST FF64 instr"++-- no distinction is made between signed and unsigned bytes on stores for the+-- Sparc opcodes (at least I cannot see any, and gas is nagging me --SOF),+-- so we call a special-purpose pprFormat for ST..+pprInstr (ST format reg addr)+ = hcat [+ text "\tst",+ pprStFormat format,+ char '\t',+ pprReg reg,+ pp_comma_lbracket,+ pprAddr addr,+ rbrack+ ]+++pprInstr (ADD x cc reg1 ri reg2)+ | not x && not cc && riZero ri+ = hcat [ text "\tmov\t", pprReg reg1, comma, pprReg reg2 ]++ | otherwise+ = pprRegRIReg (if x then sLit "addx" else sLit "add") cc reg1 ri reg2+++pprInstr (SUB x cc reg1 ri reg2)+ | not x && cc && reg2 == g0+ = hcat [ text "\tcmp\t", pprReg reg1, comma, pprRI ri ]++ | not x && not cc && riZero ri+ = hcat [ text "\tmov\t", pprReg reg1, comma, pprReg reg2 ]++ | otherwise+ = pprRegRIReg (if x then sLit "subx" else sLit "sub") cc reg1 ri reg2++pprInstr (AND b reg1 ri reg2) = pprRegRIReg (sLit "and") b reg1 ri reg2++pprInstr (ANDN b reg1 ri reg2) = pprRegRIReg (sLit "andn") b reg1 ri reg2++pprInstr (OR b reg1 ri reg2)+ | not b && reg1 == g0+ = let doit = hcat [ text "\tmov\t", pprRI ri, comma, pprReg reg2 ]+ in case ri of+ RIReg rrr | rrr == reg2 -> empty+ _ -> doit++ | otherwise+ = pprRegRIReg (sLit "or") b reg1 ri reg2++pprInstr (ORN b reg1 ri reg2) = pprRegRIReg (sLit "orn") b reg1 ri reg2++pprInstr (XOR b reg1 ri reg2) = pprRegRIReg (sLit "xor") b reg1 ri reg2+pprInstr (XNOR b reg1 ri reg2) = pprRegRIReg (sLit "xnor") b reg1 ri reg2++pprInstr (SLL reg1 ri reg2) = pprRegRIReg (sLit "sll") False reg1 ri reg2+pprInstr (SRL reg1 ri reg2) = pprRegRIReg (sLit "srl") False reg1 ri reg2+pprInstr (SRA reg1 ri reg2) = pprRegRIReg (sLit "sra") False reg1 ri reg2++pprInstr (RDY rd) = text "\trd\t%y," <> pprReg rd+pprInstr (WRY reg1 reg2)+ = text "\twr\t"+ <> pprReg reg1+ <> char ','+ <> pprReg reg2+ <> char ','+ <> text "%y"++pprInstr (SMUL b reg1 ri reg2) = pprRegRIReg (sLit "smul") b reg1 ri reg2+pprInstr (UMUL b reg1 ri reg2) = pprRegRIReg (sLit "umul") b reg1 ri reg2+pprInstr (SDIV b reg1 ri reg2) = pprRegRIReg (sLit "sdiv") b reg1 ri reg2+pprInstr (UDIV b reg1 ri reg2) = pprRegRIReg (sLit "udiv") b reg1 ri reg2++pprInstr (SETHI imm reg)+ = hcat [+ text "\tsethi\t",+ pprImm imm,+ comma,+ pprReg reg+ ]++pprInstr NOP+ = text "\tnop"++pprInstr (FABS format reg1 reg2)+ = pprFormatRegReg (sLit "fabs") format reg1 reg2++pprInstr (FADD format reg1 reg2 reg3)+ = pprFormatRegRegReg (sLit "fadd") format reg1 reg2 reg3++pprInstr (FCMP e format reg1 reg2)+ = pprFormatRegReg (if e then sLit "fcmpe" else sLit "fcmp")+ format reg1 reg2++pprInstr (FDIV format reg1 reg2 reg3)+ = pprFormatRegRegReg (sLit "fdiv") format reg1 reg2 reg3++pprInstr (FMOV format reg1 reg2)+ = pprFormatRegReg (sLit "fmov") format reg1 reg2++pprInstr (FMUL format reg1 reg2 reg3)+ = pprFormatRegRegReg (sLit "fmul") format reg1 reg2 reg3++pprInstr (FNEG format reg1 reg2)+ = pprFormatRegReg (sLit "fneg") format reg1 reg2++pprInstr (FSQRT format reg1 reg2)+ = pprFormatRegReg (sLit "fsqrt") format reg1 reg2++pprInstr (FSUB format reg1 reg2 reg3)+ = pprFormatRegRegReg (sLit "fsub") format reg1 reg2 reg3++pprInstr (FxTOy format1 format2 reg1 reg2)+ = hcat [+ text "\tf",+ ptext+ (case format1 of+ II32 -> sLit "ito"+ FF32 -> sLit "sto"+ FF64 -> sLit "dto"+ _ -> panic "SPARC.Ppr.pprInstr.FxToY: no match"),+ ptext+ (case format2 of+ II32 -> sLit "i\t"+ II64 -> sLit "x\t"+ FF32 -> sLit "s\t"+ FF64 -> sLit "d\t"+ _ -> panic "SPARC.Ppr.pprInstr.FxToY: no match"),+ pprReg reg1, comma, pprReg reg2+ ]+++pprInstr (BI cond b blockid)+ = hcat [+ text "\tb", pprCond cond,+ if b then pp_comma_a else empty,+ char '\t',+ ppr (mkAsmTempLabel (getUnique blockid))+ ]++pprInstr (BF cond b blockid)+ = hcat [+ text "\tfb", pprCond cond,+ if b then pp_comma_a else empty,+ char '\t',+ ppr (mkAsmTempLabel (getUnique blockid))+ ]++pprInstr (JMP addr) = text "\tjmp\t" <> pprAddr addr+pprInstr (JMP_TBL op _ _) = pprInstr (JMP op)++pprInstr (CALL (Left imm) n _)+ = hcat [ text "\tcall\t", pprImm imm, comma, int n ]++pprInstr (CALL (Right reg) n _)+ = hcat [ text "\tcall\t", pprReg reg, comma, int n ]+++-- | Pretty print a RI+pprRI :: RI -> SDoc+pprRI (RIReg r) = pprReg r+pprRI (RIImm r) = pprImm r+++-- | Pretty print a two reg instruction.+pprFormatRegReg :: LitString -> Format -> Reg -> Reg -> SDoc+pprFormatRegReg name format reg1 reg2+ = hcat [+ char '\t',+ ptext name,+ (case format of+ FF32 -> text "s\t"+ FF64 -> text "d\t"+ _ -> panic "SPARC.Ppr.pprFormatRegReg: no match"),++ pprReg reg1,+ comma,+ pprReg reg2+ ]+++-- | Pretty print a three reg instruction.+pprFormatRegRegReg :: LitString -> Format -> Reg -> Reg -> Reg -> SDoc+pprFormatRegRegReg name format reg1 reg2 reg3+ = hcat [+ char '\t',+ ptext name,+ (case format of+ FF32 -> text "s\t"+ FF64 -> text "d\t"+ _ -> panic "SPARC.Ppr.pprFormatRegReg: no match"),+ pprReg reg1,+ comma,+ pprReg reg2,+ comma,+ pprReg reg3+ ]+++-- | Pretty print an instruction of two regs and a ri.+pprRegRIReg :: LitString -> Bool -> Reg -> RI -> Reg -> SDoc+pprRegRIReg name b reg1 ri reg2+ = hcat [+ char '\t',+ ptext name,+ if b then text "cc\t" else char '\t',+ pprReg reg1,+ comma,+ pprRI ri,+ comma,+ pprReg reg2+ ]++{-+pprRIReg :: LitString -> Bool -> RI -> Reg -> SDoc+pprRIReg name b ri reg1+ = hcat [+ char '\t',+ ptext name,+ if b then text "cc\t" else char '\t',+ pprRI ri,+ comma,+ pprReg reg1+ ]+-}++{-+pp_ld_lbracket :: SDoc+pp_ld_lbracket = text "\tld\t["+-}++pp_rbracket_comma :: SDoc+pp_rbracket_comma = text "],"+++pp_comma_lbracket :: SDoc+pp_comma_lbracket = text ",["+++pp_comma_a :: SDoc+pp_comma_a = text ",a"+
+ nativeGen/SPARC/Regs.hs view
@@ -0,0 +1,259 @@+-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 1994-2004+--+-- -----------------------------------------------------------------------------++module SPARC.Regs (+ -- registers+ showReg,+ virtualRegSqueeze,+ realRegSqueeze,+ classOfRealReg,+ allRealRegs,++ -- machine specific info+ gReg, iReg, lReg, oReg, fReg,+ fp, sp, g0, g1, g2, o0, o1, f0, f1, f6, f8, f22, f26, f27,++ -- allocatable+ allocatableRegs,++ -- args+ argRegs,+ allArgRegs,+ callClobberedRegs,++ --+ mkVirtualReg,+ regDotColor+)++where+++import CodeGen.Platform.SPARC+import Reg+import RegClass+import Format++import Unique+import Outputable++{-+ The SPARC has 64 registers of interest; 32 integer registers and 32+ floating point registers. The mapping of STG registers to SPARC+ machine registers is defined in StgRegs.h. We are, of course,+ prepared for any eventuality.++ The whole fp-register pairing thing on sparcs is a huge nuisance. See+ includes/stg/MachRegs.h for a description of what's going on+ here.+-}+++-- | Get the standard name for the register with this number.+showReg :: RegNo -> String+showReg n+ | n >= 0 && n < 8 = "%g" ++ show n+ | n >= 8 && n < 16 = "%o" ++ show (n-8)+ | n >= 16 && n < 24 = "%l" ++ show (n-16)+ | n >= 24 && n < 32 = "%i" ++ show (n-24)+ | n >= 32 && n < 64 = "%f" ++ show (n-32)+ | otherwise = panic "SPARC.Regs.showReg: unknown sparc register"+++-- Get the register class of a certain real reg+classOfRealReg :: RealReg -> RegClass+classOfRealReg reg+ = case reg of+ RealRegSingle i+ | i < 32 -> RcInteger+ | otherwise -> RcFloat++ RealRegPair{} -> RcDouble+++-- | regSqueeze_class reg+-- Calculuate the maximum number of register colors that could be+-- denied to a node of this class due to having this reg+-- as a neighbour.+--+{-# INLINE virtualRegSqueeze #-}+virtualRegSqueeze :: RegClass -> VirtualReg -> Int++virtualRegSqueeze cls vr+ = case cls of+ RcInteger+ -> case vr of+ VirtualRegI{} -> 1+ VirtualRegHi{} -> 1+ _other -> 0++ RcFloat+ -> case vr of+ VirtualRegF{} -> 1+ VirtualRegD{} -> 2+ _other -> 0++ RcDouble+ -> case vr of+ VirtualRegF{} -> 1+ VirtualRegD{} -> 1+ _other -> 0++ _other -> 0++{-# INLINE realRegSqueeze #-}+realRegSqueeze :: RegClass -> RealReg -> Int++realRegSqueeze cls rr+ = case cls of+ RcInteger+ -> case rr of+ RealRegSingle regNo+ | regNo < 32 -> 1+ | otherwise -> 0++ RealRegPair{} -> 0++ RcFloat+ -> case rr of+ RealRegSingle regNo+ | regNo < 32 -> 0+ | otherwise -> 1++ RealRegPair{} -> 2++ RcDouble+ -> case rr of+ RealRegSingle regNo+ | regNo < 32 -> 0+ | otherwise -> 1++ RealRegPair{} -> 1++ _other -> 0++-- | All the allocatable registers in the machine,+-- including register pairs.+allRealRegs :: [RealReg]+allRealRegs+ = [ (RealRegSingle i) | i <- [0..63] ]+ ++ [ (RealRegPair i (i+1)) | i <- [32, 34 .. 62 ] ]+++-- | Get the regno for this sort of reg+gReg, lReg, iReg, oReg, fReg :: Int -> RegNo++gReg x = x -- global regs+oReg x = (8 + x) -- output regs+lReg x = (16 + x) -- local regs+iReg x = (24 + x) -- input regs+fReg x = (32 + x) -- float regs+++-- | Some specific regs used by the code generator.+g0, g1, g2, fp, sp, o0, o1, f0, f1, f6, f8, f22, f26, f27 :: Reg++f6 = RegReal (RealRegSingle (fReg 6))+f8 = RegReal (RealRegSingle (fReg 8))+f22 = RegReal (RealRegSingle (fReg 22))+f26 = RegReal (RealRegSingle (fReg 26))+f27 = RegReal (RealRegSingle (fReg 27))++-- g0 is always zero, and writes to it vanish.+g0 = RegReal (RealRegSingle (gReg 0))+g1 = RegReal (RealRegSingle (gReg 1))+g2 = RegReal (RealRegSingle (gReg 2))++-- FP, SP, int and float return (from C) regs.+fp = RegReal (RealRegSingle (iReg 6))+sp = RegReal (RealRegSingle (oReg 6))+o0 = RegReal (RealRegSingle (oReg 0))+o1 = RegReal (RealRegSingle (oReg 1))+f0 = RegReal (RealRegSingle (fReg 0))+f1 = RegReal (RealRegSingle (fReg 1))++-- | Produce the second-half-of-a-double register given the first half.+{-+fPair :: Reg -> Maybe Reg+fPair (RealReg n)+ | n >= 32 && n `mod` 2 == 0 = Just (RealReg (n+1))++fPair (VirtualRegD u)+ = Just (VirtualRegHi u)++fPair reg+ = trace ("MachInstrs.fPair: can't get high half of supposed double reg " ++ showPpr reg)+ Nothing+-}+++-- | All the regs that the register allocator can allocate to,+-- with the the fixed use regs removed.+--+allocatableRegs :: [RealReg]+allocatableRegs+ = let isFree rr+ = case rr of+ RealRegSingle r -> freeReg r+ RealRegPair r1 r2 -> freeReg r1 && freeReg r2+ in filter isFree allRealRegs+++-- | The registers to place arguments for function calls,+-- for some number of arguments.+--+argRegs :: RegNo -> [Reg]+argRegs r+ = case r of+ 0 -> []+ 1 -> map (RegReal . RealRegSingle . oReg) [0]+ 2 -> map (RegReal . RealRegSingle . oReg) [0,1]+ 3 -> map (RegReal . RealRegSingle . oReg) [0,1,2]+ 4 -> map (RegReal . RealRegSingle . oReg) [0,1,2,3]+ 5 -> map (RegReal . RealRegSingle . oReg) [0,1,2,3,4]+ 6 -> map (RegReal . RealRegSingle . oReg) [0,1,2,3,4,5]+ _ -> panic "MachRegs.argRegs(sparc): don't know about >6 arguments!"+++-- | All all the regs that could possibly be returned by argRegs+--+allArgRegs :: [Reg]+allArgRegs+ = map (RegReal . RealRegSingle) [oReg i | i <- [0..5]]+++-- These are the regs that we cannot assume stay alive over a C call.+-- TODO: Why can we assume that o6 isn't clobbered? -- BL 2009/02+--+callClobberedRegs :: [Reg]+callClobberedRegs+ = map (RegReal . RealRegSingle)+ ( oReg 7 :+ [oReg i | i <- [0..5]] +++ [gReg i | i <- [1..7]] +++ [fReg i | i <- [0..31]] )++++-- | Make a virtual reg with this format.+mkVirtualReg :: Unique -> Format -> VirtualReg+mkVirtualReg u format+ | not (isFloatFormat format)+ = VirtualRegI u++ | otherwise+ = case format of+ FF32 -> VirtualRegF u+ FF64 -> VirtualRegD u+ _ -> panic "mkVReg"+++regDotColor :: RealReg -> SDoc+regDotColor reg+ = case classOfRealReg reg of+ RcInteger -> text "blue"+ RcFloat -> text "red"+ _other -> text "green"
+ nativeGen/SPARC/ShortcutJump.hs view
@@ -0,0 +1,69 @@+module SPARC.ShortcutJump (+ JumpDest(..), getJumpDestBlockId,+ canShortcut,+ shortcutJump,+ shortcutStatics,+ shortBlockId+)++where++import SPARC.Instr+import SPARC.Imm++import CLabel+import BlockId+import Cmm++import Panic+import Unique++++data JumpDest+ = DestBlockId BlockId+ | DestImm Imm++getJumpDestBlockId :: JumpDest -> Maybe BlockId+getJumpDestBlockId (DestBlockId bid) = Just bid+getJumpDestBlockId _ = Nothing+++canShortcut :: Instr -> Maybe JumpDest+canShortcut _ = Nothing+++shortcutJump :: (BlockId -> Maybe JumpDest) -> Instr -> Instr+shortcutJump _ other = other++++shortcutStatics :: (BlockId -> Maybe JumpDest) -> CmmStatics -> CmmStatics+shortcutStatics fn (Statics lbl statics)+ = Statics lbl $ map (shortcutStatic fn) statics+ -- we need to get the jump tables, so apply the mapping to the entries+ -- of a CmmData too.++shortcutLabel :: (BlockId -> Maybe JumpDest) -> CLabel -> CLabel+shortcutLabel fn lab+ | Just uq <- maybeAsmTemp lab = shortBlockId fn (mkBlockId uq)+ | otherwise = lab++shortcutStatic :: (BlockId -> Maybe JumpDest) -> CmmStatic -> CmmStatic+shortcutStatic fn (CmmStaticLit (CmmLabel lab))+ = CmmStaticLit (CmmLabel (shortcutLabel fn lab))+shortcutStatic fn (CmmStaticLit (CmmLabelDiffOff lbl1 lbl2 off))+ = CmmStaticLit (CmmLabelDiffOff (shortcutLabel fn lbl1) lbl2 off)+-- slightly dodgy, we're ignoring the second label, but this+-- works with the way we use CmmLabelDiffOff for jump tables now.+shortcutStatic _ other_static+ = other_static+++shortBlockId :: (BlockId -> Maybe JumpDest) -> BlockId -> CLabel+shortBlockId fn blockid =+ case fn blockid of+ Nothing -> mkAsmTempLabel (getUnique blockid)+ Just (DestBlockId blockid') -> shortBlockId fn blockid'+ Just (DestImm (ImmCLbl lbl)) -> lbl+ _other -> panic "shortBlockId"
+ nativeGen/SPARC/Stack.hs view
@@ -0,0 +1,57 @@+module SPARC.Stack (+ spRel,+ fpRel,+ spillSlotToOffset,+ maxSpillSlots+)++where++import SPARC.AddrMode+import SPARC.Regs+import SPARC.Base+import SPARC.Imm++import DynFlags+import Outputable++-- | Get an AddrMode relative to the address in sp.+-- This gives us a stack relative addressing mode for volatile+-- temporaries and for excess call arguments.+--+spRel :: Int -- ^ stack offset in words, positive or negative+ -> AddrMode++spRel n = AddrRegImm sp (ImmInt (n * wordLength))+++-- | Get an address relative to the frame pointer.+-- This doesn't work work for offsets greater than 13 bits; we just hope for the best+--+fpRel :: Int -> AddrMode+fpRel n+ = AddrRegImm fp (ImmInt (n * wordLength))+++-- | Convert a spill slot number to a *byte* offset, with no sign.+--+spillSlotToOffset :: DynFlags -> Int -> Int+spillSlotToOffset dflags slot+ | slot >= 0 && slot < maxSpillSlots dflags+ = 64 + spillSlotSize * slot++ | otherwise+ = pprPanic "spillSlotToOffset:"+ ( text "invalid spill location: " <> int slot+ $$ text "maxSpillSlots: " <> int (maxSpillSlots dflags))+++-- | The maximum number of spill slots available on the C stack.+-- If we use up all of the slots, then we're screwed.+--+-- Why do we reserve 64 bytes, instead of using the whole thing??+-- -- BL 2009/02/15+--+maxSpillSlots :: DynFlags -> Int+maxSpillSlots dflags+ = ((spillAreaLength dflags - 64) `div` spillSlotSize) - 1
+ nativeGen/TargetReg.hs view
@@ -0,0 +1,130 @@+{-# LANGUAGE CPP #-}+-- | Hard wired things related to registers.+-- This is module is preventing the native code generator being able to+-- emit code for non-host architectures.+--+-- TODO: Do a better job of the overloading, and eliminate this module.+-- We'd probably do better with a Register type class, and hook this to+-- Instruction somehow.+--+-- TODO: We should also make arch specific versions of RegAlloc.Graph.TrivColorable+module TargetReg (+ targetVirtualRegSqueeze,+ targetRealRegSqueeze,+ targetClassOfRealReg,+ targetMkVirtualReg,+ targetRegDotColor,+ targetClassOfReg+)++where++#include "HsVersions.h"++import Reg+import RegClass+import Format++import Outputable+import Unique+import Platform++import qualified X86.Regs as X86+import qualified X86.RegInfo as X86++import qualified PPC.Regs as PPC++import qualified SPARC.Regs as SPARC++targetVirtualRegSqueeze :: Platform -> RegClass -> VirtualReg -> Int+targetVirtualRegSqueeze platform+ = case platformArch platform of+ ArchX86 -> X86.virtualRegSqueeze+ ArchX86_64 -> X86.virtualRegSqueeze+ ArchPPC -> PPC.virtualRegSqueeze+ ArchSPARC -> SPARC.virtualRegSqueeze+ ArchSPARC64 -> panic "targetVirtualRegSqueeze ArchSPARC64"+ ArchPPC_64 _ -> PPC.virtualRegSqueeze+ ArchARM _ _ _ -> panic "targetVirtualRegSqueeze ArchARM"+ ArchARM64 -> panic "targetVirtualRegSqueeze ArchARM64"+ ArchAlpha -> panic "targetVirtualRegSqueeze ArchAlpha"+ ArchMipseb -> panic "targetVirtualRegSqueeze ArchMipseb"+ ArchMipsel -> panic "targetVirtualRegSqueeze ArchMipsel"+ ArchJavaScript-> panic "targetVirtualRegSqueeze ArchJavaScript"+ ArchUnknown -> panic "targetVirtualRegSqueeze ArchUnknown"+++targetRealRegSqueeze :: Platform -> RegClass -> RealReg -> Int+targetRealRegSqueeze platform+ = case platformArch platform of+ ArchX86 -> X86.realRegSqueeze+ ArchX86_64 -> X86.realRegSqueeze+ ArchPPC -> PPC.realRegSqueeze+ ArchSPARC -> SPARC.realRegSqueeze+ ArchSPARC64 -> panic "targetRealRegSqueeze ArchSPARC64"+ ArchPPC_64 _ -> PPC.realRegSqueeze+ ArchARM _ _ _ -> panic "targetRealRegSqueeze ArchARM"+ ArchARM64 -> panic "targetRealRegSqueeze ArchARM64"+ ArchAlpha -> panic "targetRealRegSqueeze ArchAlpha"+ ArchMipseb -> panic "targetRealRegSqueeze ArchMipseb"+ ArchMipsel -> panic "targetRealRegSqueeze ArchMipsel"+ ArchJavaScript-> panic "targetRealRegSqueeze ArchJavaScript"+ ArchUnknown -> panic "targetRealRegSqueeze ArchUnknown"++targetClassOfRealReg :: Platform -> RealReg -> RegClass+targetClassOfRealReg platform+ = case platformArch platform of+ ArchX86 -> X86.classOfRealReg platform+ ArchX86_64 -> X86.classOfRealReg platform+ ArchPPC -> PPC.classOfRealReg+ ArchSPARC -> SPARC.classOfRealReg+ ArchSPARC64 -> panic "targetClassOfRealReg ArchSPARC64"+ ArchPPC_64 _ -> PPC.classOfRealReg+ ArchARM _ _ _ -> panic "targetClassOfRealReg ArchARM"+ ArchARM64 -> panic "targetClassOfRealReg ArchARM64"+ ArchAlpha -> panic "targetClassOfRealReg ArchAlpha"+ ArchMipseb -> panic "targetClassOfRealReg ArchMipseb"+ ArchMipsel -> panic "targetClassOfRealReg ArchMipsel"+ ArchJavaScript-> panic "targetClassOfRealReg ArchJavaScript"+ ArchUnknown -> panic "targetClassOfRealReg ArchUnknown"++targetMkVirtualReg :: Platform -> Unique -> Format -> VirtualReg+targetMkVirtualReg platform+ = case platformArch platform of+ ArchX86 -> X86.mkVirtualReg+ ArchX86_64 -> X86.mkVirtualReg+ ArchPPC -> PPC.mkVirtualReg+ ArchSPARC -> SPARC.mkVirtualReg+ ArchSPARC64 -> panic "targetMkVirtualReg ArchSPARC64"+ ArchPPC_64 _ -> PPC.mkVirtualReg+ ArchARM _ _ _ -> panic "targetMkVirtualReg ArchARM"+ ArchARM64 -> panic "targetMkVirtualReg ArchARM64"+ ArchAlpha -> panic "targetMkVirtualReg ArchAlpha"+ ArchMipseb -> panic "targetMkVirtualReg ArchMipseb"+ ArchMipsel -> panic "targetMkVirtualReg ArchMipsel"+ ArchJavaScript-> panic "targetMkVirtualReg ArchJavaScript"+ ArchUnknown -> panic "targetMkVirtualReg ArchUnknown"++targetRegDotColor :: Platform -> RealReg -> SDoc+targetRegDotColor platform+ = case platformArch platform of+ ArchX86 -> X86.regDotColor platform+ ArchX86_64 -> X86.regDotColor platform+ ArchPPC -> PPC.regDotColor+ ArchSPARC -> SPARC.regDotColor+ ArchSPARC64 -> panic "targetRegDotColor ArchSPARC64"+ ArchPPC_64 _ -> PPC.regDotColor+ ArchARM _ _ _ -> panic "targetRegDotColor ArchARM"+ ArchARM64 -> panic "targetRegDotColor ArchARM64"+ ArchAlpha -> panic "targetRegDotColor ArchAlpha"+ ArchMipseb -> panic "targetRegDotColor ArchMipseb"+ ArchMipsel -> panic "targetRegDotColor ArchMipsel"+ ArchJavaScript-> panic "targetRegDotColor ArchJavaScript"+ ArchUnknown -> panic "targetRegDotColor ArchUnknown"+++targetClassOfReg :: Platform -> Reg -> RegClass+targetClassOfReg platform reg+ = case reg of+ RegVirtual vr -> classOfVirtualReg vr+ RegReal rr -> targetClassOfRealReg platform rr
+ nativeGen/X86/CodeGen.hs view
@@ -0,0 +1,3121 @@+{-# LANGUAGE CPP, GADTs, NondecreasingIndentation #-}++-- The default iteration limit is a bit too low for the definitions+-- in this module.+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fmax-pmcheck-iterations=10000000 #-}+#endif++-----------------------------------------------------------------------------+--+-- Generating machine code (instruction selection)+--+-- (c) The University of Glasgow 1996-2004+--+-----------------------------------------------------------------------------++-- This is a big module, but, if you pay attention to+-- (a) the sectioning, and (b) the type signatures, the+-- structure should not be too overwhelming.++module X86.CodeGen (+ cmmTopCodeGen,+ generateJumpTableForInstr,+ extractUnwindPoints,+ InstrBlock+)++where++#include "HsVersions.h"+#include "nativeGen/NCG.h"+#include "MachDeps.h"++-- NCG stuff:+import X86.Instr+import X86.Cond+import X86.Regs+import X86.RegInfo+import CodeGen.Platform+import CPrim+import Debug ( DebugBlock(..), UnwindPoint(..), UnwindTable+ , UnwindExpr(UwReg), toUnwindExpr )+import Instruction+import PIC+import NCGMonad+import Format+import Reg+import Platform++-- Our intermediate code:+import BasicTypes+import BlockId+import Module ( primUnitId )+import PprCmm ()+import CmmUtils+import CmmSwitch+import Cmm+import Hoopl+import CLabel+import CoreSyn ( Tickish(..) )+import SrcLoc ( srcSpanFile, srcSpanStartLine, srcSpanStartCol )++-- The rest:+import ForeignCall ( CCallConv(..) )+import OrdList+import Outputable+import Unique+import FastString+import DynFlags+import Util+import UniqSupply ( getUniqueM )++import Control.Monad+import Data.Bits+import Data.Foldable (fold)+import Data.Int+import Data.Maybe+import Data.Word++import qualified Data.Map as M++is32BitPlatform :: NatM Bool+is32BitPlatform = do+ dflags <- getDynFlags+ return $ target32Bit (targetPlatform dflags)++sse2Enabled :: NatM Bool+sse2Enabled = do+ dflags <- getDynFlags+ return (isSse2Enabled dflags)++sse4_2Enabled :: NatM Bool+sse4_2Enabled = do+ dflags <- getDynFlags+ return (isSse4_2Enabled dflags)++if_sse2 :: NatM a -> NatM a -> NatM a+if_sse2 sse2 x87 = do+ b <- sse2Enabled+ if b then sse2 else x87++cmmTopCodeGen+ :: RawCmmDecl+ -> NatM [NatCmmDecl (Alignment, CmmStatics) Instr]++cmmTopCodeGen (CmmProc info lab live graph) = do+ let blocks = toBlockListEntryFirst graph+ (nat_blocks,statics) <- mapAndUnzipM basicBlockCodeGen blocks+ picBaseMb <- getPicBaseMaybeNat+ dflags <- getDynFlags+ let proc = CmmProc info lab live (ListGraph $ concat nat_blocks)+ tops = proc : concat statics+ os = platformOS $ targetPlatform dflags++ case picBaseMb of+ Just picBase -> initializePicBase_x86 ArchX86 os picBase tops+ Nothing -> return tops++cmmTopCodeGen (CmmData sec dat) = do+ return [CmmData sec (1, dat)] -- no translation, we just use CmmStatic+++basicBlockCodeGen+ :: CmmBlock+ -> NatM ( [NatBasicBlock Instr]+ , [NatCmmDecl (Alignment, CmmStatics) Instr])++basicBlockCodeGen block = do+ let (_, nodes, tail) = blockSplit block+ id = entryLabel block+ stmts = blockToList nodes+ -- Generate location directive+ dbg <- getDebugBlock (entryLabel block)+ loc_instrs <- case dblSourceTick =<< dbg of+ Just (SourceNote span name)+ -> do fileId <- getFileId (srcSpanFile span)+ let line = srcSpanStartLine span; col = srcSpanStartCol span+ return $ unitOL $ LOCATION fileId line col name+ _ -> return nilOL+ mid_instrs <- stmtsToInstrs stmts+ tail_instrs <- stmtToInstrs tail+ let instrs = loc_instrs `appOL` mid_instrs `appOL` tail_instrs+ instrs' <- fold <$> traverse addSpUnwindings instrs+ -- code generation may introduce new basic block boundaries, which+ -- are indicated by the NEWBLOCK instruction. We must split up the+ -- instruction stream into basic blocks again. Also, we extract+ -- LDATAs here too.+ let+ (top,other_blocks,statics) = foldrOL mkBlocks ([],[],[]) instrs'++ mkBlocks (NEWBLOCK id) (instrs,blocks,statics)+ = ([], BasicBlock id instrs : blocks, statics)+ mkBlocks (LDATA sec dat) (instrs,blocks,statics)+ = (instrs, blocks, CmmData sec dat:statics)+ mkBlocks instr (instrs,blocks,statics)+ = (instr:instrs, blocks, statics)+ return (BasicBlock id top : other_blocks, statics)++-- | Convert 'DELTA' instructions into 'UNWIND' instructions to capture changes+-- in the @sp@ register. See Note [What is this unwinding business?] in Debug+-- for details.+addSpUnwindings :: Instr -> NatM (OrdList Instr)+addSpUnwindings instr@(DELTA d) = do+ dflags <- getDynFlags+ if debugLevel dflags >= 1+ then do lbl <- mkAsmTempLabel <$> getUniqueM+ let unwind = M.singleton MachSp (Just $ UwReg MachSp $ negate d)+ return $ toOL [ instr, UNWIND lbl unwind ]+ else return (unitOL instr)+addSpUnwindings instr = return $ unitOL instr++stmtsToInstrs :: [CmmNode e x] -> NatM InstrBlock+stmtsToInstrs stmts+ = do instrss <- mapM stmtToInstrs stmts+ return (concatOL instrss)+++stmtToInstrs :: CmmNode e x -> NatM InstrBlock+stmtToInstrs stmt = do+ dflags <- getDynFlags+ is32Bit <- is32BitPlatform+ case stmt of+ CmmComment s -> return (unitOL (COMMENT s))+ CmmTick {} -> return nilOL++ CmmUnwind regs -> do+ let to_unwind_entry :: (GlobalReg, Maybe CmmExpr) -> UnwindTable+ to_unwind_entry (reg, expr) = M.singleton reg (fmap toUnwindExpr expr)+ case foldMap to_unwind_entry regs of+ tbl | M.null tbl -> return nilOL+ | otherwise -> do+ lbl <- mkAsmTempLabel <$> getUniqueM+ return $ unitOL $ UNWIND lbl tbl++ CmmAssign reg src+ | isFloatType ty -> assignReg_FltCode format reg src+ | is32Bit && isWord64 ty -> assignReg_I64Code reg src+ | otherwise -> assignReg_IntCode format reg src+ where ty = cmmRegType dflags reg+ format = cmmTypeFormat ty++ CmmStore addr src+ | isFloatType ty -> assignMem_FltCode format addr src+ | is32Bit && isWord64 ty -> assignMem_I64Code addr src+ | otherwise -> assignMem_IntCode format addr src+ where ty = cmmExprType dflags src+ format = cmmTypeFormat ty++ CmmUnsafeForeignCall target result_regs args+ -> genCCall dflags is32Bit target result_regs args++ CmmBranch id -> genBranch id+ CmmCondBranch arg true false _ -> do+ b1 <- genCondJump true arg+ b2 <- genBranch false+ return (b1 `appOL` b2)+ CmmSwitch arg ids -> do dflags <- getDynFlags+ genSwitch dflags arg ids+ CmmCall { cml_target = arg+ , cml_args_regs = gregs } -> do+ dflags <- getDynFlags+ genJump arg (jumpRegs dflags gregs)+ _ ->+ panic "stmtToInstrs: statement should have been cps'd away"+++jumpRegs :: DynFlags -> [GlobalReg] -> [Reg]+jumpRegs dflags gregs = [ RegReal r | Just r <- map (globalRegMaybe platform) gregs ]+ where platform = targetPlatform dflags++--------------------------------------------------------------------------------+-- | 'InstrBlock's are the insn sequences generated by the insn selectors.+-- They are really trees of insns to facilitate fast appending, where a+-- left-to-right traversal yields the insns in the correct order.+--+type InstrBlock+ = OrdList Instr+++-- | Condition codes passed up the tree.+--+data CondCode+ = CondCode Bool Cond InstrBlock+++-- | a.k.a "Register64"+-- Reg is the lower 32-bit temporary which contains the result.+-- Use getHiVRegFromLo to find the other VRegUnique.+--+-- Rules of this simplified insn selection game are therefore that+-- the returned Reg may be modified+--+data ChildCode64+ = ChildCode64+ InstrBlock+ Reg+++-- | Register's passed up the tree. If the stix code forces the register+-- to live in a pre-decided machine register, it comes out as @Fixed@;+-- otherwise, it comes out as @Any@, and the parent can decide which+-- register to put it in.+--+data Register+ = Fixed Format Reg InstrBlock+ | Any Format (Reg -> InstrBlock)+++swizzleRegisterRep :: Register -> Format -> Register+swizzleRegisterRep (Fixed _ reg code) format = Fixed format reg code+swizzleRegisterRep (Any _ codefn) format = Any format codefn+++-- | Grab the Reg for a CmmReg+getRegisterReg :: Platform -> Bool -> CmmReg -> Reg++getRegisterReg _ use_sse2 (CmmLocal (LocalReg u pk))+ = let fmt = cmmTypeFormat pk in+ if isFloatFormat fmt && not use_sse2+ then RegVirtual (mkVirtualReg u FF80)+ else RegVirtual (mkVirtualReg u fmt)++getRegisterReg platform _ (CmmGlobal mid)+ = case globalRegMaybe platform mid of+ Just reg -> RegReal $ reg+ Nothing -> pprPanic "getRegisterReg-memory" (ppr $ CmmGlobal mid)+ -- By this stage, the only MagicIds remaining should be the+ -- ones which map to a real machine register on this+ -- platform. Hence ...+++-- | Memory addressing modes passed up the tree.+data Amode+ = Amode AddrMode InstrBlock++{-+Now, given a tree (the argument to an CmmLoad) that references memory,+produce a suitable addressing mode.++A Rule of the Game (tm) for Amodes: use of the addr bit must+immediately follow use of the code part, since the code part puts+values in registers which the addr then refers to. So you can't put+anything in between, lest it overwrite some of those registers. If+you need to do some other computation between the code part and use of+the addr bit, first store the effective address from the amode in a+temporary, then do the other computation, and then use the temporary:++ code+ LEA amode, tmp+ ... other computation ...+ ... (tmp) ...+-}+++-- | Check whether an integer will fit in 32 bits.+-- A CmmInt is intended to be truncated to the appropriate+-- number of bits, so here we truncate it to Int64. This is+-- important because e.g. -1 as a CmmInt might be either+-- -1 or 18446744073709551615.+--+is32BitInteger :: Integer -> Bool+is32BitInteger i = i64 <= 0x7fffffff && i64 >= -0x80000000+ where i64 = fromIntegral i :: Int64+++-- | Convert a BlockId to some CmmStatic data+jumpTableEntry :: DynFlags -> Maybe BlockId -> CmmStatic+jumpTableEntry dflags Nothing = CmmStaticLit (CmmInt 0 (wordWidth dflags))+jumpTableEntry _ (Just blockid) = CmmStaticLit (CmmLabel blockLabel)+ where blockLabel = mkAsmTempLabel (getUnique blockid)+++-- -----------------------------------------------------------------------------+-- General things for putting together code sequences++-- Expand CmmRegOff. ToDo: should we do it this way around, or convert+-- CmmExprs into CmmRegOff?+mangleIndexTree :: DynFlags -> CmmReg -> Int -> CmmExpr+mangleIndexTree dflags reg off+ = CmmMachOp (MO_Add width) [CmmReg reg, CmmLit (CmmInt (fromIntegral off) width)]+ where width = typeWidth (cmmRegType dflags reg)++-- | The dual to getAnyReg: compute an expression into a register, but+-- we don't mind which one it is.+getSomeReg :: CmmExpr -> NatM (Reg, InstrBlock)+getSomeReg expr = do+ r <- getRegister expr+ case r of+ Any rep code -> do+ tmp <- getNewRegNat rep+ return (tmp, code tmp)+ Fixed _ reg code ->+ return (reg, code)+++assignMem_I64Code :: CmmExpr -> CmmExpr -> NatM InstrBlock+assignMem_I64Code addrTree valueTree = do+ Amode addr addr_code <- getAmode addrTree+ ChildCode64 vcode rlo <- iselExpr64 valueTree+ let+ rhi = getHiVRegFromLo rlo++ -- Little-endian store+ mov_lo = MOV II32 (OpReg rlo) (OpAddr addr)+ mov_hi = MOV II32 (OpReg rhi) (OpAddr (fromJust (addrOffset addr 4)))+ return (vcode `appOL` addr_code `snocOL` mov_lo `snocOL` mov_hi)+++assignReg_I64Code :: CmmReg -> CmmExpr -> NatM InstrBlock+assignReg_I64Code (CmmLocal (LocalReg u_dst _)) valueTree = do+ ChildCode64 vcode r_src_lo <- iselExpr64 valueTree+ let+ r_dst_lo = RegVirtual $ mkVirtualReg u_dst II32+ r_dst_hi = getHiVRegFromLo r_dst_lo+ r_src_hi = getHiVRegFromLo r_src_lo+ mov_lo = MOV II32 (OpReg r_src_lo) (OpReg r_dst_lo)+ mov_hi = MOV II32 (OpReg r_src_hi) (OpReg r_dst_hi)+ return (+ vcode `snocOL` mov_lo `snocOL` mov_hi+ )++assignReg_I64Code _ _+ = panic "assignReg_I64Code(i386): invalid lvalue"+++iselExpr64 :: CmmExpr -> NatM ChildCode64+iselExpr64 (CmmLit (CmmInt i _)) = do+ (rlo,rhi) <- getNewRegPairNat II32+ let+ r = fromIntegral (fromIntegral i :: Word32)+ q = fromIntegral (fromIntegral (i `shiftR` 32) :: Word32)+ code = toOL [+ MOV II32 (OpImm (ImmInteger r)) (OpReg rlo),+ MOV II32 (OpImm (ImmInteger q)) (OpReg rhi)+ ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmLoad addrTree ty) | isWord64 ty = do+ Amode addr addr_code <- getAmode addrTree+ (rlo,rhi) <- getNewRegPairNat II32+ let+ mov_lo = MOV II32 (OpAddr addr) (OpReg rlo)+ mov_hi = MOV II32 (OpAddr (fromJust (addrOffset addr 4))) (OpReg rhi)+ return (+ ChildCode64 (addr_code `snocOL` mov_lo `snocOL` mov_hi)+ rlo+ )++iselExpr64 (CmmReg (CmmLocal (LocalReg vu ty))) | isWord64 ty+ = return (ChildCode64 nilOL (RegVirtual $ mkVirtualReg vu II32))++-- we handle addition, but rather badly+iselExpr64 (CmmMachOp (MO_Add _) [e1, CmmLit (CmmInt i _)]) = do+ ChildCode64 code1 r1lo <- iselExpr64 e1+ (rlo,rhi) <- getNewRegPairNat II32+ let+ r = fromIntegral (fromIntegral i :: Word32)+ q = fromIntegral (fromIntegral (i `shiftR` 32) :: Word32)+ r1hi = getHiVRegFromLo r1lo+ code = code1 `appOL`+ toOL [ MOV II32 (OpReg r1lo) (OpReg rlo),+ ADD II32 (OpImm (ImmInteger r)) (OpReg rlo),+ MOV II32 (OpReg r1hi) (OpReg rhi),+ ADC II32 (OpImm (ImmInteger q)) (OpReg rhi) ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmMachOp (MO_Add _) [e1,e2]) = do+ ChildCode64 code1 r1lo <- iselExpr64 e1+ ChildCode64 code2 r2lo <- iselExpr64 e2+ (rlo,rhi) <- getNewRegPairNat II32+ let+ r1hi = getHiVRegFromLo r1lo+ r2hi = getHiVRegFromLo r2lo+ code = code1 `appOL`+ code2 `appOL`+ toOL [ MOV II32 (OpReg r1lo) (OpReg rlo),+ ADD II32 (OpReg r2lo) (OpReg rlo),+ MOV II32 (OpReg r1hi) (OpReg rhi),+ ADC II32 (OpReg r2hi) (OpReg rhi) ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmMachOp (MO_Sub _) [e1,e2]) = do+ ChildCode64 code1 r1lo <- iselExpr64 e1+ ChildCode64 code2 r2lo <- iselExpr64 e2+ (rlo,rhi) <- getNewRegPairNat II32+ let+ r1hi = getHiVRegFromLo r1lo+ r2hi = getHiVRegFromLo r2lo+ code = code1 `appOL`+ code2 `appOL`+ toOL [ MOV II32 (OpReg r1lo) (OpReg rlo),+ SUB II32 (OpReg r2lo) (OpReg rlo),+ MOV II32 (OpReg r1hi) (OpReg rhi),+ SBB II32 (OpReg r2hi) (OpReg rhi) ]+ return (ChildCode64 code rlo)++iselExpr64 (CmmMachOp (MO_UU_Conv _ W64) [expr]) = do+ fn <- getAnyReg expr+ r_dst_lo <- getNewRegNat II32+ let r_dst_hi = getHiVRegFromLo r_dst_lo+ code = fn r_dst_lo+ return (+ ChildCode64 (code `snocOL`+ MOV II32 (OpImm (ImmInt 0)) (OpReg r_dst_hi))+ r_dst_lo+ )++iselExpr64 expr+ = pprPanic "iselExpr64(i386)" (ppr expr)+++--------------------------------------------------------------------------------+getRegister :: CmmExpr -> NatM Register+getRegister e = do dflags <- getDynFlags+ is32Bit <- is32BitPlatform+ getRegister' dflags is32Bit e++getRegister' :: DynFlags -> Bool -> CmmExpr -> NatM Register++getRegister' dflags is32Bit (CmmReg reg)+ = case reg of+ CmmGlobal PicBaseReg+ | is32Bit ->+ -- on x86_64, we have %rip for PicBaseReg, but it's not+ -- a full-featured register, it can only be used for+ -- rip-relative addressing.+ do reg' <- getPicBaseNat (archWordFormat is32Bit)+ return (Fixed (archWordFormat is32Bit) reg' nilOL)+ _ ->+ do use_sse2 <- sse2Enabled+ let+ fmt = cmmTypeFormat (cmmRegType dflags reg)+ format | not use_sse2 && isFloatFormat fmt = FF80+ | otherwise = fmt+ --+ let platform = targetPlatform dflags+ return (Fixed format+ (getRegisterReg platform use_sse2 reg)+ nilOL)+++getRegister' dflags is32Bit (CmmRegOff r n)+ = getRegister' dflags is32Bit $ mangleIndexTree dflags r n++-- for 32-bit architectuers, support some 64 -> 32 bit conversions:+-- TO_W_(x), TO_W_(x >> 32)++getRegister' _ is32Bit (CmmMachOp (MO_UU_Conv W64 W32)+ [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]])+ | is32Bit = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 (getHiVRegFromLo rlo) code++getRegister' _ is32Bit (CmmMachOp (MO_SS_Conv W64 W32)+ [CmmMachOp (MO_U_Shr W64) [x,CmmLit (CmmInt 32 _)]])+ | is32Bit = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 (getHiVRegFromLo rlo) code++getRegister' _ is32Bit (CmmMachOp (MO_UU_Conv W64 W32) [x])+ | is32Bit = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 rlo code++getRegister' _ is32Bit (CmmMachOp (MO_SS_Conv W64 W32) [x])+ | is32Bit = do+ ChildCode64 code rlo <- iselExpr64 x+ return $ Fixed II32 rlo code++getRegister' _ _ (CmmLit lit@(CmmFloat f w)) =+ if_sse2 float_const_sse2 float_const_x87+ where+ float_const_sse2+ | f == 0.0 = do+ let+ format = floatFormat w+ code dst = unitOL (XOR format (OpReg dst) (OpReg dst))+ -- I don't know why there are xorpd, xorps, and pxor instructions.+ -- They all appear to do the same thing --SDM+ return (Any format code)++ | otherwise = do+ Amode addr code <- memConstant (widthInBytes w) lit+ loadFloatAmode True w addr code++ float_const_x87 = case w of+ W64+ | f == 0.0 ->+ let code dst = unitOL (GLDZ dst)+ in return (Any FF80 code)++ | f == 1.0 ->+ let code dst = unitOL (GLD1 dst)+ in return (Any FF80 code)++ _otherwise -> do+ Amode addr code <- memConstant (widthInBytes w) lit+ loadFloatAmode False w addr code++-- catch simple cases of zero- or sign-extended load+getRegister' _ _ (CmmMachOp (MO_UU_Conv W8 W32) [CmmLoad addr _]) = do+ code <- intLoadCode (MOVZxL II8) addr+ return (Any II32 code)++getRegister' _ _ (CmmMachOp (MO_SS_Conv W8 W32) [CmmLoad addr _]) = do+ code <- intLoadCode (MOVSxL II8) addr+ return (Any II32 code)++getRegister' _ _ (CmmMachOp (MO_UU_Conv W16 W32) [CmmLoad addr _]) = do+ code <- intLoadCode (MOVZxL II16) addr+ return (Any II32 code)++getRegister' _ _ (CmmMachOp (MO_SS_Conv W16 W32) [CmmLoad addr _]) = do+ code <- intLoadCode (MOVSxL II16) addr+ return (Any II32 code)++-- catch simple cases of zero- or sign-extended load+getRegister' _ is32Bit (CmmMachOp (MO_UU_Conv W8 W64) [CmmLoad addr _])+ | not is32Bit = do+ code <- intLoadCode (MOVZxL II8) addr+ return (Any II64 code)++getRegister' _ is32Bit (CmmMachOp (MO_SS_Conv W8 W64) [CmmLoad addr _])+ | not is32Bit = do+ code <- intLoadCode (MOVSxL II8) addr+ return (Any II64 code)++getRegister' _ is32Bit (CmmMachOp (MO_UU_Conv W16 W64) [CmmLoad addr _])+ | not is32Bit = do+ code <- intLoadCode (MOVZxL II16) addr+ return (Any II64 code)++getRegister' _ is32Bit (CmmMachOp (MO_SS_Conv W16 W64) [CmmLoad addr _])+ | not is32Bit = do+ code <- intLoadCode (MOVSxL II16) addr+ return (Any II64 code)++getRegister' _ is32Bit (CmmMachOp (MO_UU_Conv W32 W64) [CmmLoad addr _])+ | not is32Bit = do+ code <- intLoadCode (MOV II32) addr -- 32-bit loads zero-extend+ return (Any II64 code)++getRegister' _ is32Bit (CmmMachOp (MO_SS_Conv W32 W64) [CmmLoad addr _])+ | not is32Bit = do+ code <- intLoadCode (MOVSxL II32) addr+ return (Any II64 code)++getRegister' _ is32Bit (CmmMachOp (MO_Add W64) [CmmReg (CmmGlobal PicBaseReg),+ CmmLit displacement])+ | not is32Bit = do+ return $ Any II64 (\dst -> unitOL $+ LEA II64 (OpAddr (ripRel (litToImm displacement))) (OpReg dst))++getRegister' dflags is32Bit (CmmMachOp mop [x]) = do -- unary MachOps+ sse2 <- sse2Enabled+ case mop of+ MO_F_Neg w+ | sse2 -> sse2NegCode w x+ | otherwise -> trivialUFCode FF80 (GNEG FF80) x++ MO_S_Neg w -> triv_ucode NEGI (intFormat w)+ MO_Not w -> triv_ucode NOT (intFormat w)++ -- Nop conversions+ MO_UU_Conv W32 W8 -> toI8Reg W32 x+ MO_SS_Conv W32 W8 -> toI8Reg W32 x+ MO_UU_Conv W16 W8 -> toI8Reg W16 x+ MO_SS_Conv W16 W8 -> toI8Reg W16 x+ MO_UU_Conv W32 W16 -> toI16Reg W32 x+ MO_SS_Conv W32 W16 -> toI16Reg W32 x++ MO_UU_Conv W64 W32 | not is32Bit -> conversionNop II64 x+ MO_SS_Conv W64 W32 | not is32Bit -> conversionNop II64 x+ MO_UU_Conv W64 W16 | not is32Bit -> toI16Reg W64 x+ MO_SS_Conv W64 W16 | not is32Bit -> toI16Reg W64 x+ MO_UU_Conv W64 W8 | not is32Bit -> toI8Reg W64 x+ MO_SS_Conv W64 W8 | not is32Bit -> toI8Reg W64 x++ MO_UU_Conv rep1 rep2 | rep1 == rep2 -> conversionNop (intFormat rep1) x+ MO_SS_Conv rep1 rep2 | rep1 == rep2 -> conversionNop (intFormat rep1) x++ -- widenings+ MO_UU_Conv W8 W32 -> integerExtend W8 W32 MOVZxL x+ MO_UU_Conv W16 W32 -> integerExtend W16 W32 MOVZxL x+ MO_UU_Conv W8 W16 -> integerExtend W8 W16 MOVZxL x++ MO_SS_Conv W8 W32 -> integerExtend W8 W32 MOVSxL x+ MO_SS_Conv W16 W32 -> integerExtend W16 W32 MOVSxL x+ MO_SS_Conv W8 W16 -> integerExtend W8 W16 MOVSxL x++ MO_UU_Conv W8 W64 | not is32Bit -> integerExtend W8 W64 MOVZxL x+ MO_UU_Conv W16 W64 | not is32Bit -> integerExtend W16 W64 MOVZxL x+ MO_UU_Conv W32 W64 | not is32Bit -> integerExtend W32 W64 MOVZxL x+ MO_SS_Conv W8 W64 | not is32Bit -> integerExtend W8 W64 MOVSxL x+ MO_SS_Conv W16 W64 | not is32Bit -> integerExtend W16 W64 MOVSxL x+ MO_SS_Conv W32 W64 | not is32Bit -> integerExtend W32 W64 MOVSxL x+ -- for 32-to-64 bit zero extension, amd64 uses an ordinary movl.+ -- However, we don't want the register allocator to throw it+ -- away as an unnecessary reg-to-reg move, so we keep it in+ -- the form of a movzl and print it as a movl later.++ MO_FF_Conv W32 W64+ | sse2 -> coerceFP2FP W64 x+ | otherwise -> conversionNop FF80 x++ MO_FF_Conv W64 W32 -> coerceFP2FP W32 x++ MO_FS_Conv from to -> coerceFP2Int from to x+ MO_SF_Conv from to -> coerceInt2FP from to x++ MO_V_Insert {} -> needLlvm+ MO_V_Extract {} -> needLlvm+ MO_V_Add {} -> needLlvm+ MO_V_Sub {} -> needLlvm+ MO_V_Mul {} -> needLlvm+ MO_VS_Quot {} -> needLlvm+ MO_VS_Rem {} -> needLlvm+ MO_VS_Neg {} -> needLlvm+ MO_VU_Quot {} -> needLlvm+ MO_VU_Rem {} -> needLlvm+ MO_VF_Insert {} -> needLlvm+ MO_VF_Extract {} -> needLlvm+ MO_VF_Add {} -> needLlvm+ MO_VF_Sub {} -> needLlvm+ MO_VF_Mul {} -> needLlvm+ MO_VF_Quot {} -> needLlvm+ MO_VF_Neg {} -> needLlvm++ _other -> pprPanic "getRegister" (pprMachOp mop)+ where+ triv_ucode :: (Format -> Operand -> Instr) -> Format -> NatM Register+ triv_ucode instr format = trivialUCode format (instr format) x++ -- signed or unsigned extension.+ integerExtend :: Width -> Width+ -> (Format -> Operand -> Operand -> Instr)+ -> CmmExpr -> NatM Register+ integerExtend from to instr expr = do+ (reg,e_code) <- if from == W8 then getByteReg expr+ else getSomeReg expr+ let+ code dst =+ e_code `snocOL`+ instr (intFormat from) (OpReg reg) (OpReg dst)+ return (Any (intFormat to) code)++ toI8Reg :: Width -> CmmExpr -> NatM Register+ toI8Reg new_rep expr+ = do codefn <- getAnyReg expr+ return (Any (intFormat new_rep) codefn)+ -- HACK: use getAnyReg to get a byte-addressable register.+ -- If the source was a Fixed register, this will add the+ -- mov instruction to put it into the desired destination.+ -- We're assuming that the destination won't be a fixed+ -- non-byte-addressable register; it won't be, because all+ -- fixed registers are word-sized.++ toI16Reg = toI8Reg -- for now++ conversionNop :: Format -> CmmExpr -> NatM Register+ conversionNop new_format expr+ = do e_code <- getRegister' dflags is32Bit expr+ return (swizzleRegisterRep e_code new_format)+++getRegister' _ is32Bit (CmmMachOp mop [x, y]) = do -- dyadic MachOps+ sse2 <- sse2Enabled+ case mop of+ MO_F_Eq _ -> condFltReg is32Bit EQQ x y+ MO_F_Ne _ -> condFltReg is32Bit NE x y+ MO_F_Gt _ -> condFltReg is32Bit GTT x y+ MO_F_Ge _ -> condFltReg is32Bit GE x y+ MO_F_Lt _ -> condFltReg is32Bit LTT x y+ MO_F_Le _ -> condFltReg is32Bit LE x y++ MO_Eq _ -> condIntReg EQQ x y+ MO_Ne _ -> condIntReg NE x y++ MO_S_Gt _ -> condIntReg GTT x y+ MO_S_Ge _ -> condIntReg GE x y+ MO_S_Lt _ -> condIntReg LTT x y+ MO_S_Le _ -> condIntReg LE x y++ MO_U_Gt _ -> condIntReg GU x y+ MO_U_Ge _ -> condIntReg GEU x y+ MO_U_Lt _ -> condIntReg LU x y+ MO_U_Le _ -> condIntReg LEU x y++ MO_F_Add w | sse2 -> trivialFCode_sse2 w ADD x y+ | otherwise -> trivialFCode_x87 GADD x y+ MO_F_Sub w | sse2 -> trivialFCode_sse2 w SUB x y+ | otherwise -> trivialFCode_x87 GSUB x y+ MO_F_Quot w | sse2 -> trivialFCode_sse2 w FDIV x y+ | otherwise -> trivialFCode_x87 GDIV x y+ MO_F_Mul w | sse2 -> trivialFCode_sse2 w MUL x y+ | otherwise -> trivialFCode_x87 GMUL x y++ MO_Add rep -> add_code rep x y+ MO_Sub rep -> sub_code rep x y++ MO_S_Quot rep -> div_code rep True True x y+ MO_S_Rem rep -> div_code rep True False x y+ MO_U_Quot rep -> div_code rep False True x y+ MO_U_Rem rep -> div_code rep False False x y++ MO_S_MulMayOflo rep -> imulMayOflo rep x y++ MO_Mul rep -> triv_op rep IMUL+ MO_And rep -> triv_op rep AND+ MO_Or rep -> triv_op rep OR+ MO_Xor rep -> triv_op rep XOR++ {- Shift ops on x86s have constraints on their source, it+ either has to be Imm, CL or 1+ => trivialCode is not restrictive enough (sigh.)+ -}+ MO_Shl rep -> shift_code rep SHL x y {-False-}+ MO_U_Shr rep -> shift_code rep SHR x y {-False-}+ MO_S_Shr rep -> shift_code rep SAR x y {-False-}++ MO_V_Insert {} -> needLlvm+ MO_V_Extract {} -> needLlvm+ MO_V_Add {} -> needLlvm+ MO_V_Sub {} -> needLlvm+ MO_V_Mul {} -> needLlvm+ MO_VS_Quot {} -> needLlvm+ MO_VS_Rem {} -> needLlvm+ MO_VS_Neg {} -> needLlvm+ MO_VF_Insert {} -> needLlvm+ MO_VF_Extract {} -> needLlvm+ MO_VF_Add {} -> needLlvm+ MO_VF_Sub {} -> needLlvm+ MO_VF_Mul {} -> needLlvm+ MO_VF_Quot {} -> needLlvm+ MO_VF_Neg {} -> needLlvm++ _other -> pprPanic "getRegister(x86) - binary CmmMachOp (1)" (pprMachOp mop)+ where+ --------------------+ triv_op width instr = trivialCode width op (Just op) x y+ where op = instr (intFormat width)++ imulMayOflo :: Width -> CmmExpr -> CmmExpr -> NatM Register+ imulMayOflo rep a b = do+ (a_reg, a_code) <- getNonClobberedReg a+ b_code <- getAnyReg b+ let+ shift_amt = case rep of+ W32 -> 31+ W64 -> 63+ _ -> panic "shift_amt"++ format = intFormat rep+ code = a_code `appOL` b_code eax `appOL`+ toOL [+ IMUL2 format (OpReg a_reg), -- result in %edx:%eax+ SAR format (OpImm (ImmInt shift_amt)) (OpReg eax),+ -- sign extend lower part+ SUB format (OpReg edx) (OpReg eax)+ -- compare against upper+ -- eax==0 if high part == sign extended low part+ ]+ return (Fixed format eax code)++ --------------------+ shift_code :: Width+ -> (Format -> Operand -> Operand -> Instr)+ -> CmmExpr+ -> CmmExpr+ -> NatM Register++ {- Case1: shift length as immediate -}+ shift_code width instr x (CmmLit lit) = do+ x_code <- getAnyReg x+ let+ format = intFormat width+ code dst+ = x_code dst `snocOL`+ instr format (OpImm (litToImm lit)) (OpReg dst)+ return (Any format code)++ {- Case2: shift length is complex (non-immediate)+ * y must go in %ecx.+ * we cannot do y first *and* put its result in %ecx, because+ %ecx might be clobbered by x.+ * if we do y second, then x cannot be+ in a clobbered reg. Also, we cannot clobber x's reg+ with the instruction itself.+ * so we can either:+ - do y first, put its result in a fresh tmp, then copy it to %ecx later+ - do y second and put its result into %ecx. x gets placed in a fresh+ tmp. This is likely to be better, because the reg alloc can+ eliminate this reg->reg move here (it won't eliminate the other one,+ because the move is into the fixed %ecx).+ -}+ shift_code width instr x y{-amount-} = do+ x_code <- getAnyReg x+ let format = intFormat width+ tmp <- getNewRegNat format+ y_code <- getAnyReg y+ let+ code = x_code tmp `appOL`+ y_code ecx `snocOL`+ instr format (OpReg ecx) (OpReg tmp)+ return (Fixed format tmp code)++ --------------------+ add_code :: Width -> CmmExpr -> CmmExpr -> NatM Register+ add_code rep x (CmmLit (CmmInt y _))+ | is32BitInteger y = add_int rep x y+ add_code rep x y = trivialCode rep (ADD format) (Just (ADD format)) x y+ where format = intFormat rep+ -- TODO: There are other interesting patterns we want to replace+ -- with a LEA, e.g. `(x + offset) + (y << shift)`.++ --------------------+ sub_code :: Width -> CmmExpr -> CmmExpr -> NatM Register+ sub_code rep x (CmmLit (CmmInt y _))+ | is32BitInteger (-y) = add_int rep x (-y)+ sub_code rep x y = trivialCode rep (SUB (intFormat rep)) Nothing x y++ -- our three-operand add instruction:+ add_int width x y = do+ (x_reg, x_code) <- getSomeReg x+ let+ format = intFormat width+ imm = ImmInt (fromInteger y)+ code dst+ = x_code `snocOL`+ LEA format+ (OpAddr (AddrBaseIndex (EABaseReg x_reg) EAIndexNone imm))+ (OpReg dst)+ --+ return (Any format code)++ ----------------------+ div_code width signed quotient x y = do+ (y_op, y_code) <- getRegOrMem y -- cannot be clobbered+ x_code <- getAnyReg x+ let+ format = intFormat width+ widen | signed = CLTD format+ | otherwise = XOR format (OpReg edx) (OpReg edx)++ instr | signed = IDIV+ | otherwise = DIV++ code = y_code `appOL`+ x_code eax `appOL`+ toOL [widen, instr format y_op]++ result | quotient = eax+ | otherwise = edx++ return (Fixed format result code)+++getRegister' _ _ (CmmLoad mem pk)+ | isFloatType pk+ = do+ Amode addr mem_code <- getAmode mem+ use_sse2 <- sse2Enabled+ loadFloatAmode use_sse2 (typeWidth pk) addr mem_code++getRegister' _ is32Bit (CmmLoad mem pk)+ | is32Bit && not (isWord64 pk)+ = do+ code <- intLoadCode instr mem+ return (Any format code)+ where+ width = typeWidth pk+ format = intFormat width+ instr = case width of+ W8 -> MOVZxL II8+ _other -> MOV format+ -- We always zero-extend 8-bit loads, if we+ -- can't think of anything better. This is because+ -- we can't guarantee access to an 8-bit variant of every register+ -- (esi and edi don't have 8-bit variants), so to make things+ -- simpler we do our 8-bit arithmetic with full 32-bit registers.++-- Simpler memory load code on x86_64+getRegister' _ is32Bit (CmmLoad mem pk)+ | not is32Bit+ = do+ code <- intLoadCode (MOV format) mem+ return (Any format code)+ where format = intFormat $ typeWidth pk++getRegister' _ is32Bit (CmmLit (CmmInt 0 width))+ = let+ format = intFormat width++ -- x86_64: 32-bit xor is one byte shorter, and zero-extends to 64 bits+ format1 = if is32Bit then format+ else case format of+ II64 -> II32+ _ -> format+ code dst+ = unitOL (XOR format1 (OpReg dst) (OpReg dst))+ in+ return (Any format code)++ -- optimisation for loading small literals on x86_64: take advantage+ -- of the automatic zero-extension from 32 to 64 bits, because the 32-bit+ -- instruction forms are shorter.+getRegister' dflags is32Bit (CmmLit lit)+ | not is32Bit, isWord64 (cmmLitType dflags lit), not (isBigLit lit)+ = let+ imm = litToImm lit+ code dst = unitOL (MOV II32 (OpImm imm) (OpReg dst))+ in+ return (Any II64 code)+ where+ isBigLit (CmmInt i _) = i < 0 || i > 0xffffffff+ isBigLit _ = False+ -- note1: not the same as (not.is32BitLit), because that checks for+ -- signed literals that fit in 32 bits, but we want unsigned+ -- literals here.+ -- note2: all labels are small, because we're assuming the+ -- small memory model (see gcc docs, -mcmodel=small).++getRegister' dflags _ (CmmLit lit)+ = do let format = cmmTypeFormat (cmmLitType dflags lit)+ imm = litToImm lit+ code dst = unitOL (MOV format (OpImm imm) (OpReg dst))+ return (Any format code)++getRegister' _ _ other+ | isVecExpr other = needLlvm+ | otherwise = pprPanic "getRegister(x86)" (ppr other)+++intLoadCode :: (Operand -> Operand -> Instr) -> CmmExpr+ -> NatM (Reg -> InstrBlock)+intLoadCode instr mem = do+ Amode src mem_code <- getAmode mem+ return (\dst -> mem_code `snocOL` instr (OpAddr src) (OpReg dst))++-- Compute an expression into *any* register, adding the appropriate+-- move instruction if necessary.+getAnyReg :: CmmExpr -> NatM (Reg -> InstrBlock)+getAnyReg expr = do+ r <- getRegister expr+ anyReg r++anyReg :: Register -> NatM (Reg -> InstrBlock)+anyReg (Any _ code) = return code+anyReg (Fixed rep reg fcode) = return (\dst -> fcode `snocOL` reg2reg rep reg dst)++-- A bit like getSomeReg, but we want a reg that can be byte-addressed.+-- Fixed registers might not be byte-addressable, so we make sure we've+-- got a temporary, inserting an extra reg copy if necessary.+getByteReg :: CmmExpr -> NatM (Reg, InstrBlock)+getByteReg expr = do+ is32Bit <- is32BitPlatform+ if is32Bit+ then do r <- getRegister expr+ case r of+ Any rep code -> do+ tmp <- getNewRegNat rep+ return (tmp, code tmp)+ Fixed rep reg code+ | isVirtualReg reg -> return (reg,code)+ | otherwise -> do+ tmp <- getNewRegNat rep+ return (tmp, code `snocOL` reg2reg rep reg tmp)+ -- ToDo: could optimise slightly by checking for+ -- byte-addressable real registers, but that will+ -- happen very rarely if at all.+ else getSomeReg expr -- all regs are byte-addressable on x86_64++-- Another variant: this time we want the result in a register that cannot+-- be modified by code to evaluate an arbitrary expression.+getNonClobberedReg :: CmmExpr -> NatM (Reg, InstrBlock)+getNonClobberedReg expr = do+ dflags <- getDynFlags+ r <- getRegister expr+ case r of+ Any rep code -> do+ tmp <- getNewRegNat rep+ return (tmp, code tmp)+ Fixed rep reg code+ -- only certain regs can be clobbered+ | reg `elem` instrClobberedRegs (targetPlatform dflags)+ -> do+ tmp <- getNewRegNat rep+ return (tmp, code `snocOL` reg2reg rep reg tmp)+ | otherwise ->+ return (reg, code)++reg2reg :: Format -> Reg -> Reg -> Instr+reg2reg format src dst+ | format == FF80 = GMOV src dst+ | otherwise = MOV format (OpReg src) (OpReg dst)+++--------------------------------------------------------------------------------+getAmode :: CmmExpr -> NatM Amode+getAmode e = do is32Bit <- is32BitPlatform+ getAmode' is32Bit e++getAmode' :: Bool -> CmmExpr -> NatM Amode+getAmode' _ (CmmRegOff r n) = do dflags <- getDynFlags+ getAmode $ mangleIndexTree dflags r n++getAmode' is32Bit (CmmMachOp (MO_Add W64) [CmmReg (CmmGlobal PicBaseReg),+ CmmLit displacement])+ | not is32Bit+ = return $ Amode (ripRel (litToImm displacement)) nilOL+++-- This is all just ridiculous, since it carefully undoes+-- what mangleIndexTree has just done.+getAmode' is32Bit (CmmMachOp (MO_Sub _rep) [x, CmmLit lit@(CmmInt i _)])+ | is32BitLit is32Bit lit+ -- ASSERT(rep == II32)???+ = do (x_reg, x_code) <- getSomeReg x+ let off = ImmInt (-(fromInteger i))+ return (Amode (AddrBaseIndex (EABaseReg x_reg) EAIndexNone off) x_code)++getAmode' is32Bit (CmmMachOp (MO_Add _rep) [x, CmmLit lit])+ | is32BitLit is32Bit lit+ -- ASSERT(rep == II32)???+ = do (x_reg, x_code) <- getSomeReg x+ let off = litToImm lit+ return (Amode (AddrBaseIndex (EABaseReg x_reg) EAIndexNone off) x_code)++-- Turn (lit1 << n + lit2) into (lit2 + lit1 << n) so it will be+-- recognised by the next rule.+getAmode' is32Bit (CmmMachOp (MO_Add rep) [a@(CmmMachOp (MO_Shl _) _),+ b@(CmmLit _)])+ = getAmode' is32Bit (CmmMachOp (MO_Add rep) [b,a])++-- Matches: (x + offset) + (y << shift)+getAmode' _ (CmmMachOp (MO_Add _) [CmmRegOff x offset,+ CmmMachOp (MO_Shl _)+ [y, CmmLit (CmmInt shift _)]])+ | shift == 0 || shift == 1 || shift == 2 || shift == 3+ = x86_complex_amode (CmmReg x) y shift (fromIntegral offset)++getAmode' _ (CmmMachOp (MO_Add _) [x, CmmMachOp (MO_Shl _)+ [y, CmmLit (CmmInt shift _)]])+ | shift == 0 || shift == 1 || shift == 2 || shift == 3+ = x86_complex_amode x y shift 0++getAmode' _ (CmmMachOp (MO_Add _)+ [x, CmmMachOp (MO_Add _)+ [CmmMachOp (MO_Shl _) [y, CmmLit (CmmInt shift _)],+ CmmLit (CmmInt offset _)]])+ | shift == 0 || shift == 1 || shift == 2 || shift == 3+ && is32BitInteger offset+ = x86_complex_amode x y shift offset++getAmode' _ (CmmMachOp (MO_Add _) [x,y])+ = x86_complex_amode x y 0 0++getAmode' is32Bit (CmmLit lit) | is32BitLit is32Bit lit+ = return (Amode (ImmAddr (litToImm lit) 0) nilOL)++getAmode' _ expr = do+ (reg,code) <- getSomeReg expr+ return (Amode (AddrBaseIndex (EABaseReg reg) EAIndexNone (ImmInt 0)) code)++-- | Like 'getAmode', but on 32-bit use simple register addressing+-- (i.e. no index register). This stops us from running out of+-- registers on x86 when using instructions such as cmpxchg, which can+-- use up to three virtual registers and one fixed register.+getSimpleAmode :: DynFlags -> Bool -> CmmExpr -> NatM Amode+getSimpleAmode dflags is32Bit addr+ | is32Bit = do+ addr_code <- getAnyReg addr+ addr_r <- getNewRegNat (intFormat (wordWidth dflags))+ let amode = AddrBaseIndex (EABaseReg addr_r) EAIndexNone (ImmInt 0)+ return $! Amode amode (addr_code addr_r)+ | otherwise = getAmode addr++x86_complex_amode :: CmmExpr -> CmmExpr -> Integer -> Integer -> NatM Amode+x86_complex_amode base index shift offset+ = do (x_reg, x_code) <- getNonClobberedReg base+ -- x must be in a temp, because it has to stay live over y_code+ -- we could compre x_reg and y_reg and do something better here...+ (y_reg, y_code) <- getSomeReg index+ let+ code = x_code `appOL` y_code+ base = case shift of 0 -> 1; 1 -> 2; 2 -> 4; 3 -> 8;+ n -> panic $ "x86_complex_amode: unhandled shift! (" ++ show n ++ ")"+ return (Amode (AddrBaseIndex (EABaseReg x_reg) (EAIndex y_reg base) (ImmInt (fromIntegral offset)))+ code)+++++-- -----------------------------------------------------------------------------+-- getOperand: sometimes any operand will do.++-- getNonClobberedOperand: the value of the operand will remain valid across+-- the computation of an arbitrary expression, unless the expression+-- is computed directly into a register which the operand refers to+-- (see trivialCode where this function is used for an example).++getNonClobberedOperand :: CmmExpr -> NatM (Operand, InstrBlock)+getNonClobberedOperand (CmmLit lit) = do+ use_sse2 <- sse2Enabled+ if use_sse2 && isSuitableFloatingPointLit lit+ then do+ let CmmFloat _ w = lit+ Amode addr code <- memConstant (widthInBytes w) lit+ return (OpAddr addr, code)+ else do++ is32Bit <- is32BitPlatform+ dflags <- getDynFlags+ if is32BitLit is32Bit lit && not (isFloatType (cmmLitType dflags lit))+ then return (OpImm (litToImm lit), nilOL)+ else getNonClobberedOperand_generic (CmmLit lit)++getNonClobberedOperand (CmmLoad mem pk) = do+ is32Bit <- is32BitPlatform+ use_sse2 <- sse2Enabled+ if (not (isFloatType pk) || use_sse2)+ && (if is32Bit then not (isWord64 pk) else True)+ then do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ Amode src mem_code <- getAmode mem+ (src',save_code) <-+ if (amodeCouldBeClobbered platform src)+ then do+ tmp <- getNewRegNat (archWordFormat is32Bit)+ return (AddrBaseIndex (EABaseReg tmp) EAIndexNone (ImmInt 0),+ unitOL (LEA (archWordFormat is32Bit)+ (OpAddr src)+ (OpReg tmp)))+ else+ return (src, nilOL)+ return (OpAddr src', mem_code `appOL` save_code)+ else do+ getNonClobberedOperand_generic (CmmLoad mem pk)++getNonClobberedOperand e = getNonClobberedOperand_generic e++getNonClobberedOperand_generic :: CmmExpr -> NatM (Operand, InstrBlock)+getNonClobberedOperand_generic e = do+ (reg, code) <- getNonClobberedReg e+ return (OpReg reg, code)++amodeCouldBeClobbered :: Platform -> AddrMode -> Bool+amodeCouldBeClobbered platform amode = any (regClobbered platform) (addrModeRegs amode)++regClobbered :: Platform -> Reg -> Bool+regClobbered platform (RegReal (RealRegSingle rr)) = freeReg platform rr+regClobbered _ _ = False++-- getOperand: the operand is not required to remain valid across the+-- computation of an arbitrary expression.+getOperand :: CmmExpr -> NatM (Operand, InstrBlock)++getOperand (CmmLit lit) = do+ use_sse2 <- sse2Enabled+ if (use_sse2 && isSuitableFloatingPointLit lit)+ then do+ let CmmFloat _ w = lit+ Amode addr code <- memConstant (widthInBytes w) lit+ return (OpAddr addr, code)+ else do++ is32Bit <- is32BitPlatform+ dflags <- getDynFlags+ if is32BitLit is32Bit lit && not (isFloatType (cmmLitType dflags lit))+ then return (OpImm (litToImm lit), nilOL)+ else getOperand_generic (CmmLit lit)++getOperand (CmmLoad mem pk) = do+ is32Bit <- is32BitPlatform+ use_sse2 <- sse2Enabled+ if (not (isFloatType pk) || use_sse2) && (if is32Bit then not (isWord64 pk) else True)+ then do+ Amode src mem_code <- getAmode mem+ return (OpAddr src, mem_code)+ else+ getOperand_generic (CmmLoad mem pk)++getOperand e = getOperand_generic e++getOperand_generic :: CmmExpr -> NatM (Operand, InstrBlock)+getOperand_generic e = do+ (reg, code) <- getSomeReg e+ return (OpReg reg, code)++isOperand :: Bool -> CmmExpr -> Bool+isOperand _ (CmmLoad _ _) = True+isOperand is32Bit (CmmLit lit) = is32BitLit is32Bit lit+ || isSuitableFloatingPointLit lit+isOperand _ _ = False++memConstant :: Int -> CmmLit -> NatM Amode+memConstant align lit = do+ lbl <- getNewLabelNat+ let rosection = Section ReadOnlyData lbl+ dflags <- getDynFlags+ (addr, addr_code) <- if target32Bit (targetPlatform dflags)+ then do dynRef <- cmmMakeDynamicReference+ dflags+ DataReference+ lbl+ Amode addr addr_code <- getAmode dynRef+ return (addr, addr_code)+ else return (ripRel (ImmCLbl lbl), nilOL)+ let code =+ LDATA rosection (align, Statics lbl [CmmStaticLit lit])+ `consOL` addr_code+ return (Amode addr code)+++loadFloatAmode :: Bool -> Width -> AddrMode -> InstrBlock -> NatM Register+loadFloatAmode use_sse2 w addr addr_code = do+ let format = floatFormat w+ code dst = addr_code `snocOL`+ if use_sse2+ then MOV format (OpAddr addr) (OpReg dst)+ else GLD format addr dst+ return (Any (if use_sse2 then format else FF80) code)+++-- if we want a floating-point literal as an operand, we can+-- use it directly from memory. However, if the literal is+-- zero, we're better off generating it into a register using+-- xor.+isSuitableFloatingPointLit :: CmmLit -> Bool+isSuitableFloatingPointLit (CmmFloat f _) = f /= 0.0+isSuitableFloatingPointLit _ = False++getRegOrMem :: CmmExpr -> NatM (Operand, InstrBlock)+getRegOrMem e@(CmmLoad mem pk) = do+ is32Bit <- is32BitPlatform+ use_sse2 <- sse2Enabled+ if (not (isFloatType pk) || use_sse2) && (if is32Bit then not (isWord64 pk) else True)+ then do+ Amode src mem_code <- getAmode mem+ return (OpAddr src, mem_code)+ else do+ (reg, code) <- getNonClobberedReg e+ return (OpReg reg, code)+getRegOrMem e = do+ (reg, code) <- getNonClobberedReg e+ return (OpReg reg, code)++is32BitLit :: Bool -> CmmLit -> Bool+is32BitLit is32Bit (CmmInt i W64)+ | not is32Bit+ = -- assume that labels are in the range 0-2^31-1: this assumes the+ -- small memory model (see gcc docs, -mcmodel=small).+ is32BitInteger i+is32BitLit _ _ = True+++++-- Set up a condition code for a conditional branch.++getCondCode :: CmmExpr -> NatM CondCode++-- yes, they really do seem to want exactly the same!++getCondCode (CmmMachOp mop [x, y])+ =+ case mop of+ MO_F_Eq W32 -> condFltCode EQQ x y+ MO_F_Ne W32 -> condFltCode NE x y+ MO_F_Gt W32 -> condFltCode GTT x y+ MO_F_Ge W32 -> condFltCode GE x y+ MO_F_Lt W32 -> condFltCode LTT x y+ MO_F_Le W32 -> condFltCode LE x y++ MO_F_Eq W64 -> condFltCode EQQ x y+ MO_F_Ne W64 -> condFltCode NE x y+ MO_F_Gt W64 -> condFltCode GTT x y+ MO_F_Ge W64 -> condFltCode GE x y+ MO_F_Lt W64 -> condFltCode LTT x y+ MO_F_Le W64 -> condFltCode LE x y++ _ -> condIntCode (machOpToCond mop) x y++getCondCode other = pprPanic "getCondCode(2)(x86,x86_64)" (ppr other)++machOpToCond :: MachOp -> Cond+machOpToCond mo = case mo of+ MO_Eq _ -> EQQ+ MO_Ne _ -> NE+ MO_S_Gt _ -> GTT+ MO_S_Ge _ -> GE+ MO_S_Lt _ -> LTT+ MO_S_Le _ -> LE+ MO_U_Gt _ -> GU+ MO_U_Ge _ -> GEU+ MO_U_Lt _ -> LU+ MO_U_Le _ -> LEU+ _other -> pprPanic "machOpToCond" (pprMachOp mo)+++-- @cond(Int|Flt)Code@: Turn a boolean expression into a condition, to be+-- passed back up the tree.++condIntCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode+condIntCode cond x y = do is32Bit <- is32BitPlatform+ condIntCode' is32Bit cond x y++condIntCode' :: Bool -> Cond -> CmmExpr -> CmmExpr -> NatM CondCode++-- memory vs immediate+condIntCode' is32Bit cond (CmmLoad x pk) (CmmLit lit)+ | is32BitLit is32Bit lit = do+ Amode x_addr x_code <- getAmode x+ let+ imm = litToImm lit+ code = x_code `snocOL`+ CMP (cmmTypeFormat pk) (OpImm imm) (OpAddr x_addr)+ --+ return (CondCode False cond code)++-- anything vs zero, using a mask+-- TODO: Add some sanity checking!!!!+condIntCode' is32Bit cond (CmmMachOp (MO_And _) [x,o2]) (CmmLit (CmmInt 0 pk))+ | (CmmLit lit@(CmmInt mask _)) <- o2, is32BitLit is32Bit lit+ = do+ (x_reg, x_code) <- getSomeReg x+ let+ code = x_code `snocOL`+ TEST (intFormat pk) (OpImm (ImmInteger mask)) (OpReg x_reg)+ --+ return (CondCode False cond code)++-- anything vs zero+condIntCode' _ cond x (CmmLit (CmmInt 0 pk)) = do+ (x_reg, x_code) <- getSomeReg x+ let+ code = x_code `snocOL`+ TEST (intFormat pk) (OpReg x_reg) (OpReg x_reg)+ --+ return (CondCode False cond code)++-- anything vs operand+condIntCode' is32Bit cond x y+ | isOperand is32Bit y = do+ dflags <- getDynFlags+ (x_reg, x_code) <- getNonClobberedReg x+ (y_op, y_code) <- getOperand y+ let+ code = x_code `appOL` y_code `snocOL`+ CMP (cmmTypeFormat (cmmExprType dflags x)) y_op (OpReg x_reg)+ return (CondCode False cond code)+-- operand vs. anything: invert the comparison so that we can use a+-- single comparison instruction.+ | isOperand is32Bit x+ , Just revcond <- maybeFlipCond cond = do+ dflags <- getDynFlags+ (y_reg, y_code) <- getNonClobberedReg y+ (x_op, x_code) <- getOperand x+ let+ code = y_code `appOL` x_code `snocOL`+ CMP (cmmTypeFormat (cmmExprType dflags x)) x_op (OpReg y_reg)+ return (CondCode False revcond code)++-- anything vs anything+condIntCode' _ cond x y = do+ dflags <- getDynFlags+ (y_reg, y_code) <- getNonClobberedReg y+ (x_op, x_code) <- getRegOrMem x+ let+ code = y_code `appOL`+ x_code `snocOL`+ CMP (cmmTypeFormat (cmmExprType dflags x)) (OpReg y_reg) x_op+ return (CondCode False cond code)++++--------------------------------------------------------------------------------+condFltCode :: Cond -> CmmExpr -> CmmExpr -> NatM CondCode++condFltCode cond x y+ = if_sse2 condFltCode_sse2 condFltCode_x87+ where++ condFltCode_x87+ = ASSERT(cond `elem` ([EQQ, NE, LE, LTT, GE, GTT])) do+ (x_reg, x_code) <- getNonClobberedReg x+ (y_reg, y_code) <- getSomeReg y+ let+ code = x_code `appOL` y_code `snocOL`+ GCMP cond x_reg y_reg+ -- The GCMP insn does the test and sets the zero flag if comparable+ -- and true. Hence we always supply EQQ as the condition to test.+ return (CondCode True EQQ code)++ -- in the SSE2 comparison ops (ucomiss, ucomisd) the left arg may be+ -- an operand, but the right must be a reg. We can probably do better+ -- than this general case...+ condFltCode_sse2 = do+ dflags <- getDynFlags+ (x_reg, x_code) <- getNonClobberedReg x+ (y_op, y_code) <- getOperand y+ let+ code = x_code `appOL`+ y_code `snocOL`+ CMP (floatFormat $ cmmExprWidth dflags x) y_op (OpReg x_reg)+ -- NB(1): we need to use the unsigned comparison operators on the+ -- result of this comparison.+ return (CondCode True (condToUnsigned cond) code)++-- -----------------------------------------------------------------------------+-- Generating assignments++-- Assignments are really at the heart of the whole code generation+-- business. Almost all top-level nodes of any real importance are+-- assignments, which correspond to loads, stores, or register+-- transfers. If we're really lucky, some of the register transfers+-- will go away, because we can use the destination register to+-- complete the code generation for the right hand side. This only+-- fails when the right hand side is forced into a fixed register+-- (e.g. the result of a call).++assignMem_IntCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock+assignReg_IntCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock++assignMem_FltCode :: Format -> CmmExpr -> CmmExpr -> NatM InstrBlock+assignReg_FltCode :: Format -> CmmReg -> CmmExpr -> NatM InstrBlock+++-- integer assignment to memory++-- specific case of adding/subtracting an integer to a particular address.+-- ToDo: catch other cases where we can use an operation directly on a memory+-- address.+assignMem_IntCode pk addr (CmmMachOp op [CmmLoad addr2 _,+ CmmLit (CmmInt i _)])+ | addr == addr2, pk /= II64 || is32BitInteger i,+ Just instr <- check op+ = do Amode amode code_addr <- getAmode addr+ let code = code_addr `snocOL`+ instr pk (OpImm (ImmInt (fromIntegral i))) (OpAddr amode)+ return code+ where+ check (MO_Add _) = Just ADD+ check (MO_Sub _) = Just SUB+ check _ = Nothing+ -- ToDo: more?++-- general case+assignMem_IntCode pk addr src = do+ is32Bit <- is32BitPlatform+ Amode addr code_addr <- getAmode addr+ (code_src, op_src) <- get_op_RI is32Bit src+ let+ code = code_src `appOL`+ code_addr `snocOL`+ MOV pk op_src (OpAddr addr)+ -- NOTE: op_src is stable, so it will still be valid+ -- after code_addr. This may involve the introduction+ -- of an extra MOV to a temporary register, but we hope+ -- the register allocator will get rid of it.+ --+ return code+ where+ get_op_RI :: Bool -> CmmExpr -> NatM (InstrBlock,Operand) -- code, operator+ get_op_RI is32Bit (CmmLit lit) | is32BitLit is32Bit lit+ = return (nilOL, OpImm (litToImm lit))+ get_op_RI _ op+ = do (reg,code) <- getNonClobberedReg op+ return (code, OpReg reg)+++-- Assign; dst is a reg, rhs is mem+assignReg_IntCode pk reg (CmmLoad src _) = do+ load_code <- intLoadCode (MOV pk) src+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ return (load_code (getRegisterReg platform False{-no sse2-} reg))++-- dst is a reg, but src could be anything+assignReg_IntCode _ reg src = do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ code <- getAnyReg src+ return (code (getRegisterReg platform False{-no sse2-} reg))+++-- Floating point assignment to memory+assignMem_FltCode pk addr src = do+ (src_reg, src_code) <- getNonClobberedReg src+ Amode addr addr_code <- getAmode addr+ use_sse2 <- sse2Enabled+ let+ code = src_code `appOL`+ addr_code `snocOL`+ if use_sse2 then MOV pk (OpReg src_reg) (OpAddr addr)+ else GST pk src_reg addr+ return code++-- Floating point assignment to a register/temporary+assignReg_FltCode _ reg src = do+ use_sse2 <- sse2Enabled+ src_code <- getAnyReg src+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ return (src_code (getRegisterReg platform use_sse2 reg))+++genJump :: CmmExpr{-the branch target-} -> [Reg] -> NatM InstrBlock++genJump (CmmLoad mem _) regs = do+ Amode target code <- getAmode mem+ return (code `snocOL` JMP (OpAddr target) regs)++genJump (CmmLit lit) regs = do+ return (unitOL (JMP (OpImm (litToImm lit)) regs))++genJump expr regs = do+ (reg,code) <- getSomeReg expr+ return (code `snocOL` JMP (OpReg reg) regs)+++-- -----------------------------------------------------------------------------+-- Unconditional branches++genBranch :: BlockId -> NatM InstrBlock+genBranch = return . toOL . mkJumpInstr++++-- -----------------------------------------------------------------------------+-- Conditional jumps++{-+Conditional jumps are always to local labels, so we can use branch+instructions. We peek at the arguments to decide what kind of+comparison to do.++I386: First, we have to ensure that the condition+codes are set according to the supplied comparison operation.+-}++genCondJump+ :: BlockId -- the branch target+ -> CmmExpr -- the condition on which to branch+ -> NatM InstrBlock++genCondJump id expr = do+ is32Bit <- is32BitPlatform+ genCondJump' is32Bit id expr++genCondJump' :: Bool -> BlockId -> CmmExpr -> NatM InstrBlock++-- 64-bit integer comparisons on 32-bit+genCondJump' is32Bit true (CmmMachOp mop [e1,e2])+ | is32Bit, Just W64 <- maybeIntComparison mop = do+ ChildCode64 code1 r1_lo <- iselExpr64 e1+ ChildCode64 code2 r2_lo <- iselExpr64 e2+ let r1_hi = getHiVRegFromLo r1_lo+ r2_hi = getHiVRegFromLo r2_lo+ cond = machOpToCond mop+ Just cond' = maybeFlipCond cond+ false <- getBlockIdNat+ return $ code1 `appOL` code2 `appOL` toOL [+ CMP II32 (OpReg r2_hi) (OpReg r1_hi),+ JXX cond true,+ JXX cond' false,+ CMP II32 (OpReg r2_lo) (OpReg r1_lo),+ JXX cond true,+ NEWBLOCK false ]++genCondJump' _ id bool = do+ CondCode is_float cond cond_code <- getCondCode bool+ use_sse2 <- sse2Enabled+ if not is_float || not use_sse2+ then+ return (cond_code `snocOL` JXX cond id)+ else do+ lbl <- getBlockIdNat++ -- see comment with condFltReg+ let code = case cond of+ NE -> or_unordered+ GU -> plain_test+ GEU -> plain_test+ _ -> and_ordered++ plain_test = unitOL (+ JXX cond id+ )+ or_unordered = toOL [+ JXX cond id,+ JXX PARITY id+ ]+ and_ordered = toOL [+ JXX PARITY lbl,+ JXX cond id,+ JXX ALWAYS lbl,+ NEWBLOCK lbl+ ]+ return (cond_code `appOL` code)++-- -----------------------------------------------------------------------------+-- Generating C calls++-- Now the biggest nightmare---calls. Most of the nastiness is buried in+-- @get_arg@, which moves the arguments to the correct registers/stack+-- locations. Apart from that, the code is easy.+--+-- (If applicable) Do not fill the delay slots here; you will confuse the+-- register allocator.++genCCall+ :: DynFlags+ -> Bool -- 32 bit platform?+ -> ForeignTarget -- function to call+ -> [CmmFormal] -- where to put the result+ -> [CmmActual] -- arguments (of mixed type)+ -> NatM InstrBlock++-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -++-- Unroll memcpy calls if the source and destination pointers are at+-- least DWORD aligned and the number of bytes to copy isn't too+-- large. Otherwise, call C's memcpy.+genCCall dflags is32Bit (PrimTarget (MO_Memcpy align)) _+ [dst, src, CmmLit (CmmInt n _)]+ | fromInteger insns <= maxInlineMemcpyInsns dflags && align .&. 3 == 0 = do+ code_dst <- getAnyReg dst+ dst_r <- getNewRegNat format+ code_src <- getAnyReg src+ src_r <- getNewRegNat format+ tmp_r <- getNewRegNat format+ return $ code_dst dst_r `appOL` code_src src_r `appOL`+ go dst_r src_r tmp_r (fromInteger n)+ where+ -- The number of instructions we will generate (approx). We need 2+ -- instructions per move.+ insns = 2 * ((n + sizeBytes - 1) `div` sizeBytes)++ format = if align .&. 4 /= 0 then II32 else (archWordFormat is32Bit)++ -- The size of each move, in bytes.+ sizeBytes :: Integer+ sizeBytes = fromIntegral (formatInBytes format)++ go :: Reg -> Reg -> Reg -> Integer -> OrdList Instr+ go dst src tmp i+ | i >= sizeBytes =+ unitOL (MOV format (OpAddr src_addr) (OpReg tmp)) `appOL`+ unitOL (MOV format (OpReg tmp) (OpAddr dst_addr)) `appOL`+ go dst src tmp (i - sizeBytes)+ -- Deal with remaining bytes.+ | i >= 4 = -- Will never happen on 32-bit+ unitOL (MOV II32 (OpAddr src_addr) (OpReg tmp)) `appOL`+ unitOL (MOV II32 (OpReg tmp) (OpAddr dst_addr)) `appOL`+ go dst src tmp (i - 4)+ | i >= 2 =+ unitOL (MOVZxL II16 (OpAddr src_addr) (OpReg tmp)) `appOL`+ unitOL (MOV II16 (OpReg tmp) (OpAddr dst_addr)) `appOL`+ go dst src tmp (i - 2)+ | i >= 1 =+ unitOL (MOVZxL II8 (OpAddr src_addr) (OpReg tmp)) `appOL`+ unitOL (MOV II8 (OpReg tmp) (OpAddr dst_addr)) `appOL`+ go dst src tmp (i - 1)+ | otherwise = nilOL+ where+ src_addr = AddrBaseIndex (EABaseReg src) EAIndexNone+ (ImmInteger (n - i))+ dst_addr = AddrBaseIndex (EABaseReg dst) EAIndexNone+ (ImmInteger (n - i))++genCCall dflags _ (PrimTarget (MO_Memset align)) _+ [dst,+ CmmLit (CmmInt c _),+ CmmLit (CmmInt n _)]+ | fromInteger insns <= maxInlineMemsetInsns dflags && align .&. 3 == 0 = do+ code_dst <- getAnyReg dst+ dst_r <- getNewRegNat format+ return $ code_dst dst_r `appOL` go dst_r (fromInteger n)+ where+ (format, val) = case align .&. 3 of+ 2 -> (II16, c2)+ 0 -> (II32, c4)+ _ -> (II8, c)+ c2 = c `shiftL` 8 .|. c+ c4 = c2 `shiftL` 16 .|. c2++ -- The number of instructions we will generate (approx). We need 1+ -- instructions per move.+ insns = (n + sizeBytes - 1) `div` sizeBytes++ -- The size of each move, in bytes.+ sizeBytes :: Integer+ sizeBytes = fromIntegral (formatInBytes format)++ go :: Reg -> Integer -> OrdList Instr+ go dst i+ -- TODO: Add movabs instruction and support 64-bit sets.+ | i >= sizeBytes = -- This might be smaller than the below sizes+ unitOL (MOV format (OpImm (ImmInteger val)) (OpAddr dst_addr)) `appOL`+ go dst (i - sizeBytes)+ | i >= 4 = -- Will never happen on 32-bit+ unitOL (MOV II32 (OpImm (ImmInteger c4)) (OpAddr dst_addr)) `appOL`+ go dst (i - 4)+ | i >= 2 =+ unitOL (MOV II16 (OpImm (ImmInteger c2)) (OpAddr dst_addr)) `appOL`+ go dst (i - 2)+ | i >= 1 =+ unitOL (MOV II8 (OpImm (ImmInteger c)) (OpAddr dst_addr)) `appOL`+ go dst (i - 1)+ | otherwise = nilOL+ where+ dst_addr = AddrBaseIndex (EABaseReg dst) EAIndexNone+ (ImmInteger (n - i))++genCCall _ _ (PrimTarget MO_WriteBarrier) _ _ = return nilOL+ -- write barrier compiles to no code on x86/x86-64;+ -- we keep it this long in order to prevent earlier optimisations.++genCCall _ _ (PrimTarget MO_Touch) _ _ = return nilOL++genCCall _ is32bit (PrimTarget (MO_Prefetch_Data n )) _ [src] =+ case n of+ 0 -> genPrefetch src $ PREFETCH NTA format+ 1 -> genPrefetch src $ PREFETCH Lvl2 format+ 2 -> genPrefetch src $ PREFETCH Lvl1 format+ 3 -> genPrefetch src $ PREFETCH Lvl0 format+ l -> panic $ "unexpected prefetch level in genCCall MO_Prefetch_Data: " ++ (show l)+ -- the c / llvm prefetch convention is 0, 1, 2, and 3+ -- the x86 corresponding names are : NTA, 2 , 1, and 0+ where+ format = archWordFormat is32bit+ -- need to know what register width for pointers!+ genPrefetch inRegSrc prefetchCTor =+ do+ code_src <- getAnyReg inRegSrc+ src_r <- getNewRegNat format+ return $ code_src src_r `appOL`+ (unitOL (prefetchCTor (OpAddr+ ((AddrBaseIndex (EABaseReg src_r ) EAIndexNone (ImmInt 0)))) ))+ -- prefetch always takes an address++genCCall dflags is32Bit (PrimTarget (MO_BSwap width)) [dst] [src] = do+ let platform = targetPlatform dflags+ let dst_r = getRegisterReg platform False (CmmLocal dst)+ case width of+ W64 | is32Bit -> do+ ChildCode64 vcode rlo <- iselExpr64 src+ let dst_rhi = getHiVRegFromLo dst_r+ rhi = getHiVRegFromLo rlo+ return $ vcode `appOL`+ toOL [ MOV II32 (OpReg rlo) (OpReg dst_rhi),+ MOV II32 (OpReg rhi) (OpReg dst_r),+ BSWAP II32 dst_rhi,+ BSWAP II32 dst_r ]+ W16 -> do code_src <- getAnyReg src+ return $ code_src dst_r `appOL`+ unitOL (BSWAP II32 dst_r) `appOL`+ unitOL (SHR II32 (OpImm $ ImmInt 16) (OpReg dst_r))+ _ -> do code_src <- getAnyReg src+ return $ code_src dst_r `appOL` unitOL (BSWAP format dst_r)+ where+ format = intFormat width++genCCall dflags is32Bit (PrimTarget (MO_PopCnt width)) dest_regs@[dst]+ args@[src] = do+ sse4_2 <- sse4_2Enabled+ let platform = targetPlatform dflags+ if sse4_2+ then do code_src <- getAnyReg src+ src_r <- getNewRegNat format+ let dst_r = getRegisterReg platform False (CmmLocal dst)+ return $ code_src src_r `appOL`+ (if width == W8 then+ -- The POPCNT instruction doesn't take a r/m8+ unitOL (MOVZxL II8 (OpReg src_r) (OpReg src_r)) `appOL`+ unitOL (POPCNT II16 (OpReg src_r) dst_r)+ else+ unitOL (POPCNT format (OpReg src_r) dst_r)) `appOL`+ (if width == W8 || width == W16 then+ -- We used a 16-bit destination register above,+ -- so zero-extend+ unitOL (MOVZxL II16 (OpReg dst_r) (OpReg dst_r))+ else nilOL)+ else do+ targetExpr <- cmmMakeDynamicReference dflags+ CallReference lbl+ let target = ForeignTarget targetExpr (ForeignConvention CCallConv+ [NoHint] [NoHint]+ CmmMayReturn)+ genCCall dflags is32Bit target dest_regs args+ where+ format = intFormat width+ lbl = mkCmmCodeLabel primUnitId (fsLit (popCntLabel width))++genCCall dflags is32Bit (PrimTarget (MO_Clz width)) dest_regs@[dst] args@[src]+ | is32Bit && width == W64 = do+ -- Fallback to `hs_clz64` on i386+ targetExpr <- cmmMakeDynamicReference dflags CallReference lbl+ let target = ForeignTarget targetExpr (ForeignConvention CCallConv+ [NoHint] [NoHint]+ CmmMayReturn)+ genCCall dflags is32Bit target dest_regs args++ | otherwise = do+ code_src <- getAnyReg src+ src_r <- getNewRegNat format+ tmp_r <- getNewRegNat format+ let dst_r = getRegisterReg platform False (CmmLocal dst)++ -- The following insn sequence makes sure 'clz 0' has a defined value.+ -- starting with Haswell, one could use the LZCNT insn instead.+ return $ code_src src_r `appOL` toOL+ ([ MOVZxL II8 (OpReg src_r) (OpReg src_r) | width == W8 ] +++ [ BSR format (OpReg src_r) tmp_r+ , MOV II32 (OpImm (ImmInt (2*bw-1))) (OpReg dst_r)+ , CMOV NE format (OpReg tmp_r) dst_r+ , XOR format (OpImm (ImmInt (bw-1))) (OpReg dst_r)+ ]) -- NB: We don't need to zero-extend the result for the+ -- W8/W16 cases because the 'MOV' insn already+ -- took care of implicitly clearing the upper bits+ where+ bw = widthInBits width+ platform = targetPlatform dflags+ format = if width == W8 then II16 else intFormat width+ lbl = mkCmmCodeLabel primUnitId (fsLit (clzLabel width))++genCCall dflags is32Bit (PrimTarget (MO_Ctz width)) [dst] [src]+ | is32Bit, width == W64 = do+ ChildCode64 vcode rlo <- iselExpr64 src+ let rhi = getHiVRegFromLo rlo+ dst_r = getRegisterReg platform False (CmmLocal dst)+ lbl1 <- getBlockIdNat+ lbl2 <- getBlockIdNat+ tmp_r <- getNewRegNat format++ -- The following instruction sequence corresponds to the pseudo-code+ --+ -- if (src) {+ -- dst = src.lo32 ? BSF(src.lo32) : (BSF(src.hi32) + 32);+ -- } else {+ -- dst = 64;+ -- }+ return $ vcode `appOL` toOL+ ([ MOV II32 (OpReg rhi) (OpReg tmp_r)+ , OR II32 (OpReg rlo) (OpReg tmp_r)+ , MOV II32 (OpImm (ImmInt 64)) (OpReg dst_r)+ , JXX EQQ lbl2+ , JXX ALWAYS lbl1++ , NEWBLOCK lbl1+ , BSF II32 (OpReg rhi) dst_r+ , ADD II32 (OpImm (ImmInt 32)) (OpReg dst_r)+ , BSF II32 (OpReg rlo) tmp_r+ , CMOV NE II32 (OpReg tmp_r) dst_r+ , JXX ALWAYS lbl2++ , NEWBLOCK lbl2+ ])++ | otherwise = do+ code_src <- getAnyReg src+ src_r <- getNewRegNat format+ tmp_r <- getNewRegNat format+ let dst_r = getRegisterReg platform False (CmmLocal dst)++ -- The following insn sequence makes sure 'ctz 0' has a defined value.+ -- starting with Haswell, one could use the TZCNT insn instead.+ return $ code_src src_r `appOL` toOL+ ([ MOVZxL II8 (OpReg src_r) (OpReg src_r) | width == W8 ] +++ [ BSF format (OpReg src_r) tmp_r+ , MOV II32 (OpImm (ImmInt bw)) (OpReg dst_r)+ , CMOV NE format (OpReg tmp_r) dst_r+ ]) -- NB: We don't need to zero-extend the result for the+ -- W8/W16 cases because the 'MOV' insn already+ -- took care of implicitly clearing the upper bits+ where+ bw = widthInBits width+ platform = targetPlatform dflags+ format = if width == W8 then II16 else intFormat width++genCCall dflags is32Bit (PrimTarget (MO_UF_Conv width)) dest_regs args = do+ targetExpr <- cmmMakeDynamicReference dflags+ CallReference lbl+ let target = ForeignTarget targetExpr (ForeignConvention CCallConv+ [NoHint] [NoHint]+ CmmMayReturn)+ genCCall dflags is32Bit target dest_regs args+ where+ lbl = mkCmmCodeLabel primUnitId (fsLit (word2FloatLabel width))++genCCall dflags is32Bit (PrimTarget (MO_AtomicRMW width amop)) [dst] [addr, n] = do+ Amode amode addr_code <-+ if amop `elem` [AMO_Add, AMO_Sub]+ then getAmode addr+ else getSimpleAmode dflags is32Bit addr -- See genCCall for MO_Cmpxchg+ arg <- getNewRegNat format+ arg_code <- getAnyReg n+ use_sse2 <- sse2Enabled+ let platform = targetPlatform dflags+ dst_r = getRegisterReg platform use_sse2 (CmmLocal dst)+ code <- op_code dst_r arg amode+ return $ addr_code `appOL` arg_code arg `appOL` code+ where+ -- Code for the operation+ op_code :: Reg -- Destination reg+ -> Reg -- Register containing argument+ -> AddrMode -- Address of location to mutate+ -> NatM (OrdList Instr)+ op_code dst_r arg amode = case amop of+ -- In the common case where dst_r is a virtual register the+ -- final move should go away, because it's the last use of arg+ -- and the first use of dst_r.+ AMO_Add -> return $ toOL [ LOCK (XADD format (OpReg arg) (OpAddr amode))+ , MOV format (OpReg arg) (OpReg dst_r)+ ]+ AMO_Sub -> return $ toOL [ NEGI format (OpReg arg)+ , LOCK (XADD format (OpReg arg) (OpAddr amode))+ , MOV format (OpReg arg) (OpReg dst_r)+ ]+ AMO_And -> cmpxchg_code (\ src dst -> unitOL $ AND format src dst)+ AMO_Nand -> cmpxchg_code (\ src dst -> toOL [ AND format src dst+ , NOT format dst+ ])+ AMO_Or -> cmpxchg_code (\ src dst -> unitOL $ OR format src dst)+ AMO_Xor -> cmpxchg_code (\ src dst -> unitOL $ XOR format src dst)+ where+ -- Simulate operation that lacks a dedicated instruction using+ -- cmpxchg.+ cmpxchg_code :: (Operand -> Operand -> OrdList Instr)+ -> NatM (OrdList Instr)+ cmpxchg_code instrs = do+ lbl <- getBlockIdNat+ tmp <- getNewRegNat format+ return $ toOL+ [ MOV format (OpAddr amode) (OpReg eax)+ , JXX ALWAYS lbl+ , NEWBLOCK lbl+ -- Keep old value so we can return it:+ , MOV format (OpReg eax) (OpReg dst_r)+ , MOV format (OpReg eax) (OpReg tmp)+ ]+ `appOL` instrs (OpReg arg) (OpReg tmp) `appOL` toOL+ [ LOCK (CMPXCHG format (OpReg tmp) (OpAddr amode))+ , JXX NE lbl+ ]++ format = intFormat width++genCCall dflags _ (PrimTarget (MO_AtomicRead width)) [dst] [addr] = do+ load_code <- intLoadCode (MOV (intFormat width)) addr+ let platform = targetPlatform dflags+ use_sse2 <- sse2Enabled+ return (load_code (getRegisterReg platform use_sse2 (CmmLocal dst)))++genCCall _ _ (PrimTarget (MO_AtomicWrite width)) [] [addr, val] = do+ code <- assignMem_IntCode (intFormat width) addr val+ return $ code `snocOL` MFENCE++genCCall dflags is32Bit (PrimTarget (MO_Cmpxchg width)) [dst] [addr, old, new] = do+ -- On x86 we don't have enough registers to use cmpxchg with a+ -- complicated addressing mode, so on that architecture we+ -- pre-compute the address first.+ Amode amode addr_code <- getSimpleAmode dflags is32Bit addr+ newval <- getNewRegNat format+ newval_code <- getAnyReg new+ oldval <- getNewRegNat format+ oldval_code <- getAnyReg old+ use_sse2 <- sse2Enabled+ let platform = targetPlatform dflags+ dst_r = getRegisterReg platform use_sse2 (CmmLocal dst)+ code = toOL+ [ MOV format (OpReg oldval) (OpReg eax)+ , LOCK (CMPXCHG format (OpReg newval) (OpAddr amode))+ , MOV format (OpReg eax) (OpReg dst_r)+ ]+ return $ addr_code `appOL` newval_code newval `appOL` oldval_code oldval+ `appOL` code+ where+ format = intFormat width++genCCall _ is32Bit target dest_regs args = do+ dflags <- getDynFlags+ let platform = targetPlatform dflags+ sse2 = isSse2Enabled dflags+ case (target, dest_regs) of+ -- void return type prim op+ (PrimTarget op, []) ->+ outOfLineCmmOp op Nothing args+ -- we only cope with a single result for foreign calls+ (PrimTarget op, [r])+ | sse2 -> case op of+ MO_F32_Fabs -> case args of+ [x] -> sse2FabsCode W32 x+ _ -> panic "genCCall: Wrong number of arguments for fabs"+ MO_F64_Fabs -> case args of+ [x] -> sse2FabsCode W64 x+ _ -> panic "genCCall: Wrong number of arguments for fabs"+ _other_op -> outOfLineCmmOp op (Just r) args+ | otherwise -> do+ l1 <- getNewLabelNat+ l2 <- getNewLabelNat+ if sse2+ then+ outOfLineCmmOp op (Just r) args+ else case op of+ MO_F32_Sqrt -> actuallyInlineFloatOp GSQRT FF32 args+ MO_F64_Sqrt -> actuallyInlineFloatOp GSQRT FF64 args++ MO_F32_Sin -> actuallyInlineFloatOp (\s -> GSIN s l1 l2) FF32 args+ MO_F64_Sin -> actuallyInlineFloatOp (\s -> GSIN s l1 l2) FF64 args++ MO_F32_Cos -> actuallyInlineFloatOp (\s -> GCOS s l1 l2) FF32 args+ MO_F64_Cos -> actuallyInlineFloatOp (\s -> GCOS s l1 l2) FF64 args++ MO_F32_Tan -> actuallyInlineFloatOp (\s -> GTAN s l1 l2) FF32 args+ MO_F64_Tan -> actuallyInlineFloatOp (\s -> GTAN s l1 l2) FF64 args++ _other_op -> outOfLineCmmOp op (Just r) args++ where+ actuallyInlineFloatOp instr format [x]+ = do res <- trivialUFCode format (instr format) x+ any <- anyReg res+ return (any (getRegisterReg platform False (CmmLocal r)))++ actuallyInlineFloatOp _ _ args+ = panic $ "genCCall.actuallyInlineFloatOp: bad number of arguments! ("+ ++ show (length args) ++ ")"++ sse2FabsCode :: Width -> CmmExpr -> NatM InstrBlock+ sse2FabsCode w x = do+ let fmt = floatFormat w+ x_code <- getAnyReg x+ let+ const | FF32 <- fmt = CmmInt 0x7fffffff W32+ | otherwise = CmmInt 0x7fffffffffffffff W64+ Amode amode amode_code <- memConstant (widthInBytes w) const+ tmp <- getNewRegNat fmt+ let+ code dst = x_code dst `appOL` amode_code `appOL` toOL [+ MOV fmt (OpAddr amode) (OpReg tmp),+ AND fmt (OpReg tmp) (OpReg dst)+ ]++ return $ code (getRegisterReg platform True (CmmLocal r))++ (PrimTarget (MO_S_QuotRem width), _) -> divOp1 platform True width dest_regs args+ (PrimTarget (MO_U_QuotRem width), _) -> divOp1 platform False width dest_regs args+ (PrimTarget (MO_U_QuotRem2 width), _) -> divOp2 platform False width dest_regs args+ (PrimTarget (MO_Add2 width), [res_h, res_l]) ->+ case args of+ [arg_x, arg_y] ->+ do hCode <- getAnyReg (CmmLit (CmmInt 0 width))+ let format = intFormat width+ lCode <- anyReg =<< trivialCode width (ADD_CC format)+ (Just (ADD_CC format)) arg_x arg_y+ let reg_l = getRegisterReg platform True (CmmLocal res_l)+ reg_h = getRegisterReg platform True (CmmLocal res_h)+ code = hCode reg_h `appOL`+ lCode reg_l `snocOL`+ ADC format (OpImm (ImmInteger 0)) (OpReg reg_h)+ return code+ _ -> panic "genCCall: Wrong number of arguments/results for add2"+ (PrimTarget (MO_SubWordC width), [res_r, res_c]) ->+ addSubIntC platform SUB_CC (const Nothing) CARRY width res_r res_c args+ (PrimTarget (MO_AddIntC width), [res_r, res_c]) ->+ addSubIntC platform ADD_CC (Just . ADD_CC) OFLO width res_r res_c args+ (PrimTarget (MO_SubIntC width), [res_r, res_c]) ->+ addSubIntC platform SUB_CC (const Nothing) OFLO width res_r res_c args+ (PrimTarget (MO_U_Mul2 width), [res_h, res_l]) ->+ case args of+ [arg_x, arg_y] ->+ do (y_reg, y_code) <- getRegOrMem arg_y+ x_code <- getAnyReg arg_x+ let format = intFormat width+ reg_h = getRegisterReg platform True (CmmLocal res_h)+ reg_l = getRegisterReg platform True (CmmLocal res_l)+ code = y_code `appOL`+ x_code rax `appOL`+ toOL [MUL2 format y_reg,+ MOV format (OpReg rdx) (OpReg reg_h),+ MOV format (OpReg rax) (OpReg reg_l)]+ return code+ _ -> panic "genCCall: Wrong number of arguments/results for mul2"++ _ -> if is32Bit+ then genCCall32' dflags target dest_regs args+ else genCCall64' dflags target dest_regs args++ where divOp1 platform signed width results [arg_x, arg_y]+ = divOp platform signed width results Nothing arg_x arg_y+ divOp1 _ _ _ _ _+ = panic "genCCall: Wrong number of arguments for divOp1"+ divOp2 platform signed width results [arg_x_high, arg_x_low, arg_y]+ = divOp platform signed width results (Just arg_x_high) arg_x_low arg_y+ divOp2 _ _ _ _ _+ = panic "genCCall: Wrong number of arguments for divOp2"+ divOp platform signed width [res_q, res_r]+ m_arg_x_high arg_x_low arg_y+ = do let format = intFormat width+ reg_q = getRegisterReg platform True (CmmLocal res_q)+ reg_r = getRegisterReg platform True (CmmLocal res_r)+ widen | signed = CLTD format+ | otherwise = XOR format (OpReg rdx) (OpReg rdx)+ instr | signed = IDIV+ | otherwise = DIV+ (y_reg, y_code) <- getRegOrMem arg_y+ x_low_code <- getAnyReg arg_x_low+ x_high_code <- case m_arg_x_high of+ Just arg_x_high ->+ getAnyReg arg_x_high+ Nothing ->+ return $ const $ unitOL widen+ return $ y_code `appOL`+ x_low_code rax `appOL`+ x_high_code rdx `appOL`+ toOL [instr format y_reg,+ MOV format (OpReg rax) (OpReg reg_q),+ MOV format (OpReg rdx) (OpReg reg_r)]+ divOp _ _ _ _ _ _ _+ = panic "genCCall: Wrong number of results for divOp"++ addSubIntC platform instr mrevinstr cond width+ res_r res_c [arg_x, arg_y]+ = do let format = intFormat width+ rCode <- anyReg =<< trivialCode width (instr format)+ (mrevinstr format) arg_x arg_y+ reg_tmp <- getNewRegNat II8+ let reg_c = getRegisterReg platform True (CmmLocal res_c)+ reg_r = getRegisterReg platform True (CmmLocal res_r)+ code = rCode reg_r `snocOL`+ SETCC cond (OpReg reg_tmp) `snocOL`+ MOVZxL II8 (OpReg reg_tmp) (OpReg reg_c)++ return code+ addSubIntC _ _ _ _ _ _ _ _+ = panic "genCCall: Wrong number of arguments/results for addSubIntC"++genCCall32' :: DynFlags+ -> ForeignTarget -- function to call+ -> [CmmFormal] -- where to put the result+ -> [CmmActual] -- arguments (of mixed type)+ -> NatM InstrBlock+genCCall32' dflags target dest_regs args = do+ let+ prom_args = map (maybePromoteCArg dflags W32) args++ -- Align stack to 16n for calls, assuming a starting stack+ -- alignment of 16n - word_size on procedure entry. Which we+ -- maintiain. See Note [rts/StgCRun.c : Stack Alignment on X86]+ sizes = map (arg_size . cmmExprType dflags) (reverse args)+ raw_arg_size = sum sizes + wORD_SIZE dflags+ arg_pad_size = (roundTo 16 $ raw_arg_size) - raw_arg_size+ tot_arg_size = raw_arg_size + arg_pad_size - wORD_SIZE dflags+ delta0 <- getDeltaNat+ setDeltaNat (delta0 - arg_pad_size)++ use_sse2 <- sse2Enabled+ push_codes <- mapM (push_arg use_sse2) (reverse prom_args)+ delta <- getDeltaNat+ MASSERT(delta == delta0 - tot_arg_size)++ -- deal with static vs dynamic call targets+ (callinsns,cconv) <-+ case target of+ ForeignTarget (CmmLit (CmmLabel lbl)) conv+ -> -- ToDo: stdcall arg sizes+ return (unitOL (CALL (Left fn_imm) []), conv)+ where fn_imm = ImmCLbl lbl+ ForeignTarget expr conv+ -> do { (dyn_r, dyn_c) <- getSomeReg expr+ ; ASSERT( isWord32 (cmmExprType dflags expr) )+ return (dyn_c `snocOL` CALL (Right dyn_r) [], conv) }+ PrimTarget _+ -> panic $ "genCCall: Can't handle PrimTarget call type here, error "+ ++ "probably because too many return values."++ let push_code+ | arg_pad_size /= 0+ = toOL [SUB II32 (OpImm (ImmInt arg_pad_size)) (OpReg esp),+ DELTA (delta0 - arg_pad_size)]+ `appOL` concatOL push_codes+ | otherwise+ = concatOL push_codes++ -- Deallocate parameters after call for ccall;+ -- but not for stdcall (callee does it)+ --+ -- We have to pop any stack padding we added+ -- even if we are doing stdcall, though (#5052)+ pop_size+ | ForeignConvention StdCallConv _ _ _ <- cconv = arg_pad_size+ | otherwise = tot_arg_size++ call = callinsns `appOL`+ toOL (+ (if pop_size==0 then [] else+ [ADD II32 (OpImm (ImmInt pop_size)) (OpReg esp)])+ +++ [DELTA delta0]+ )+ setDeltaNat delta0++ dflags <- getDynFlags+ let platform = targetPlatform dflags++ let+ -- assign the results, if necessary+ assign_code [] = nilOL+ assign_code [dest]+ | isFloatType ty =+ if use_sse2+ then let tmp_amode = AddrBaseIndex (EABaseReg esp)+ EAIndexNone+ (ImmInt 0)+ fmt = floatFormat w+ in toOL [ SUB II32 (OpImm (ImmInt b)) (OpReg esp),+ DELTA (delta0 - b),+ GST fmt fake0 tmp_amode,+ MOV fmt (OpAddr tmp_amode) (OpReg r_dest),+ ADD II32 (OpImm (ImmInt b)) (OpReg esp),+ DELTA delta0]+ else unitOL (GMOV fake0 r_dest)+ | isWord64 ty = toOL [MOV II32 (OpReg eax) (OpReg r_dest),+ MOV II32 (OpReg edx) (OpReg r_dest_hi)]+ | otherwise = unitOL (MOV (intFormat w)+ (OpReg eax)+ (OpReg r_dest))+ where+ ty = localRegType dest+ w = typeWidth ty+ b = widthInBytes w+ r_dest_hi = getHiVRegFromLo r_dest+ r_dest = getRegisterReg platform use_sse2 (CmmLocal dest)+ assign_code many = pprPanic "genCCall.assign_code - too many return values:" (ppr many)++ return (push_code `appOL`+ call `appOL`+ assign_code dest_regs)++ where+ arg_size :: CmmType -> Int -- Width in bytes+ arg_size ty = widthInBytes (typeWidth ty)++ roundTo a x | x `mod` a == 0 = x+ | otherwise = x + a - (x `mod` a)++ push_arg :: Bool -> CmmActual {-current argument-}+ -> NatM InstrBlock -- code++ push_arg use_sse2 arg -- we don't need the hints on x86+ | isWord64 arg_ty = do+ ChildCode64 code r_lo <- iselExpr64 arg+ delta <- getDeltaNat+ setDeltaNat (delta - 8)+ let r_hi = getHiVRegFromLo r_lo+ return ( code `appOL`+ toOL [PUSH II32 (OpReg r_hi), DELTA (delta - 4),+ PUSH II32 (OpReg r_lo), DELTA (delta - 8),+ DELTA (delta-8)]+ )++ | isFloatType arg_ty = do+ (reg, code) <- getSomeReg arg+ delta <- getDeltaNat+ setDeltaNat (delta-size)+ return (code `appOL`+ toOL [SUB II32 (OpImm (ImmInt size)) (OpReg esp),+ DELTA (delta-size),+ let addr = AddrBaseIndex (EABaseReg esp)+ EAIndexNone+ (ImmInt 0)+ format = floatFormat (typeWidth arg_ty)+ in+ if use_sse2+ then MOV format (OpReg reg) (OpAddr addr)+ else GST format reg addr+ ]+ )++ | otherwise = do+ (operand, code) <- getOperand arg+ delta <- getDeltaNat+ setDeltaNat (delta-size)+ return (code `snocOL`+ PUSH II32 operand `snocOL`+ DELTA (delta-size))++ where+ arg_ty = cmmExprType dflags arg+ size = arg_size arg_ty -- Byte size++genCCall64' :: DynFlags+ -> ForeignTarget -- function to call+ -> [CmmFormal] -- where to put the result+ -> [CmmActual] -- arguments (of mixed type)+ -> NatM InstrBlock+genCCall64' dflags target dest_regs args = do+ -- load up the register arguments+ let prom_args = map (maybePromoteCArg dflags W32) args++ (stack_args, int_regs_used, fp_regs_used, load_args_code, assign_args_code)+ <-+ if platformOS platform == OSMinGW32+ then load_args_win prom_args [] [] (allArgRegs platform) nilOL+ else do+ (stack_args, aregs, fregs, load_args_code, assign_args_code)+ <- load_args prom_args (allIntArgRegs platform)+ (allFPArgRegs platform)+ nilOL nilOL+ let used_regs rs as = reverse (drop (length rs) (reverse as))+ fregs_used = used_regs fregs (allFPArgRegs platform)+ aregs_used = used_regs aregs (allIntArgRegs platform)+ return (stack_args, aregs_used, fregs_used, load_args_code+ , assign_args_code)++ let+ arg_regs_used = int_regs_used ++ fp_regs_used+ arg_regs = [eax] ++ arg_regs_used+ -- for annotating the call instruction with+ sse_regs = length fp_regs_used+ arg_stack_slots = if platformOS platform == OSMinGW32+ then length stack_args + length (allArgRegs platform)+ else length stack_args+ tot_arg_size = arg_size * arg_stack_slots+++ -- Align stack to 16n for calls, assuming a starting stack+ -- alignment of 16n - word_size on procedure entry. Which we+ -- maintain. See Note [rts/StgCRun.c : Stack Alignment on X86]+ (real_size, adjust_rsp) <-+ if (tot_arg_size + wORD_SIZE dflags) `rem` 16 == 0+ then return (tot_arg_size, nilOL)+ else do -- we need to adjust...+ delta <- getDeltaNat+ setDeltaNat (delta - wORD_SIZE dflags)+ return (tot_arg_size + wORD_SIZE dflags, toOL [+ SUB II64 (OpImm (ImmInt (wORD_SIZE dflags))) (OpReg rsp),+ DELTA (delta - wORD_SIZE dflags) ])++ -- push the stack args, right to left+ push_code <- push_args (reverse stack_args) nilOL+ -- On Win64, we also have to leave stack space for the arguments+ -- that we are passing in registers+ lss_code <- if platformOS platform == OSMinGW32+ then leaveStackSpace (length (allArgRegs platform))+ else return nilOL+ delta <- getDeltaNat++ -- deal with static vs dynamic call targets+ (callinsns,_cconv) <-+ case target of+ ForeignTarget (CmmLit (CmmLabel lbl)) conv+ -> -- ToDo: stdcall arg sizes+ return (unitOL (CALL (Left fn_imm) arg_regs), conv)+ where fn_imm = ImmCLbl lbl+ ForeignTarget expr conv+ -> do (dyn_r, dyn_c) <- getSomeReg expr+ return (dyn_c `snocOL` CALL (Right dyn_r) arg_regs, conv)+ PrimTarget _+ -> panic $ "genCCall: Can't handle PrimTarget call type here, error "+ ++ "probably because too many return values."++ let+ -- The x86_64 ABI requires us to set %al to the number of SSE2+ -- registers that contain arguments, if the called routine+ -- is a varargs function. We don't know whether it's a+ -- varargs function or not, so we have to assume it is.+ --+ -- It's not safe to omit this assignment, even if the number+ -- of SSE2 regs in use is zero. If %al is larger than 8+ -- on entry to a varargs function, seg faults ensue.+ assign_eax n = unitOL (MOV II32 (OpImm (ImmInt n)) (OpReg eax))++ let call = callinsns `appOL`+ toOL (+ -- Deallocate parameters after call for ccall;+ -- stdcall has callee do it, but is not supported on+ -- x86_64 target (see #3336)+ (if real_size==0 then [] else+ [ADD (intFormat (wordWidth dflags)) (OpImm (ImmInt real_size)) (OpReg esp)])+ +++ [DELTA (delta + real_size)]+ )+ setDeltaNat (delta + real_size)++ let+ -- assign the results, if necessary+ assign_code [] = nilOL+ assign_code [dest] =+ case typeWidth rep of+ W32 | isFloatType rep -> unitOL (MOV (floatFormat W32)+ (OpReg xmm0)+ (OpReg r_dest))+ W64 | isFloatType rep -> unitOL (MOV (floatFormat W64)+ (OpReg xmm0)+ (OpReg r_dest))+ _ -> unitOL (MOV (cmmTypeFormat rep) (OpReg rax) (OpReg r_dest))+ where+ rep = localRegType dest+ r_dest = getRegisterReg platform True (CmmLocal dest)+ assign_code _many = panic "genCCall.assign_code many"++ return (adjust_rsp `appOL`+ push_code `appOL`+ load_args_code `appOL`+ assign_args_code `appOL`+ lss_code `appOL`+ assign_eax sse_regs `appOL`+ call `appOL`+ assign_code dest_regs)++ where platform = targetPlatform dflags+ arg_size = 8 -- always, at the mo+++ load_args :: [CmmExpr]+ -> [Reg] -- int regs avail for args+ -> [Reg] -- FP regs avail for args+ -> InstrBlock -- code computing args+ -> InstrBlock -- code assigning args to ABI regs+ -> NatM ([CmmExpr],[Reg],[Reg],InstrBlock,InstrBlock)+ -- no more regs to use+ load_args args [] [] code acode =+ return (args, [], [], code, acode)++ -- no more args to push+ load_args [] aregs fregs code acode =+ return ([], aregs, fregs, code, acode)++ load_args (arg : rest) aregs fregs code acode+ | isFloatType arg_rep = case fregs of+ [] -> push_this_arg+ (r:rs) -> do+ (code',acode') <- reg_this_arg r+ load_args rest aregs rs code' acode'+ | otherwise = case aregs of+ [] -> push_this_arg+ (r:rs) -> do+ (code',acode') <- reg_this_arg r+ load_args rest rs fregs code' acode'+ where++ -- put arg into the list of stack pushed args+ push_this_arg = do+ (args',ars,frs,code',acode')+ <- load_args rest aregs fregs code acode+ return (arg:args', ars, frs, code', acode')++ -- pass the arg into the given register+ reg_this_arg r+ -- "operand" args can be directly assigned into r+ | isOperand False arg = do+ arg_code <- getAnyReg arg+ return (code, (acode `appOL` arg_code r))+ -- The last non-operand arg can be directly assigned after its+ -- computation without going into a temporary register+ | all (isOperand False) rest = do+ arg_code <- getAnyReg arg+ return (code `appOL` arg_code r,acode)++ -- other args need to be computed beforehand to avoid clobbering+ -- previously assigned registers used to pass parameters (see+ -- #11792, #12614). They are assigned into temporary registers+ -- and get assigned to proper call ABI registers after they all+ -- have been computed.+ | otherwise = do+ arg_code <- getAnyReg arg+ tmp <- getNewRegNat arg_fmt+ let+ code' = code `appOL` arg_code tmp+ acode' = acode `snocOL` reg2reg arg_fmt tmp r+ return (code',acode')++ arg_rep = cmmExprType dflags arg+ arg_fmt = cmmTypeFormat arg_rep++ load_args_win :: [CmmExpr]+ -> [Reg] -- used int regs+ -> [Reg] -- used FP regs+ -> [(Reg, Reg)] -- (int, FP) regs avail for args+ -> InstrBlock+ -> NatM ([CmmExpr],[Reg],[Reg],InstrBlock,InstrBlock)+ load_args_win args usedInt usedFP [] code+ = return (args, usedInt, usedFP, code, nilOL)+ -- no more regs to use+ load_args_win [] usedInt usedFP _ code+ = return ([], usedInt, usedFP, code, nilOL)+ -- no more args to push+ load_args_win (arg : rest) usedInt usedFP+ ((ireg, freg) : regs) code+ | isFloatType arg_rep = do+ arg_code <- getAnyReg arg+ load_args_win rest (ireg : usedInt) (freg : usedFP) regs+ (code `appOL`+ arg_code freg `snocOL`+ -- If we are calling a varargs function+ -- then we need to define ireg as well+ -- as freg+ MOV II64 (OpReg freg) (OpReg ireg))+ | otherwise = do+ arg_code <- getAnyReg arg+ load_args_win rest (ireg : usedInt) usedFP regs+ (code `appOL` arg_code ireg)+ where+ arg_rep = cmmExprType dflags arg++ push_args [] code = return code+ push_args (arg:rest) code+ | isFloatType arg_rep = do+ (arg_reg, arg_code) <- getSomeReg arg+ delta <- getDeltaNat+ setDeltaNat (delta-arg_size)+ let code' = code `appOL` arg_code `appOL` toOL [+ SUB (intFormat (wordWidth dflags)) (OpImm (ImmInt arg_size)) (OpReg rsp),+ DELTA (delta-arg_size),+ MOV (floatFormat width) (OpReg arg_reg) (OpAddr (spRel dflags 0))]+ push_args rest code'++ | otherwise = do+ ASSERT(width == W64) return ()+ (arg_op, arg_code) <- getOperand arg+ delta <- getDeltaNat+ setDeltaNat (delta-arg_size)+ let code' = code `appOL` arg_code `appOL` toOL [+ PUSH II64 arg_op,+ DELTA (delta-arg_size)]+ push_args rest code'+ where+ arg_rep = cmmExprType dflags arg+ width = typeWidth arg_rep++ leaveStackSpace n = do+ delta <- getDeltaNat+ setDeltaNat (delta - n * arg_size)+ return $ toOL [+ SUB II64 (OpImm (ImmInt (n * wORD_SIZE dflags))) (OpReg rsp),+ DELTA (delta - n * arg_size)]++maybePromoteCArg :: DynFlags -> Width -> CmmExpr -> CmmExpr+maybePromoteCArg dflags wto arg+ | wfrom < wto = CmmMachOp (MO_UU_Conv wfrom wto) [arg]+ | otherwise = arg+ where+ wfrom = cmmExprWidth dflags arg++outOfLineCmmOp :: CallishMachOp -> Maybe CmmFormal -> [CmmActual] -> NatM InstrBlock+outOfLineCmmOp mop res args+ = do+ dflags <- getDynFlags+ targetExpr <- cmmMakeDynamicReference dflags CallReference lbl+ let target = ForeignTarget targetExpr+ (ForeignConvention CCallConv [] [] CmmMayReturn)++ stmtToInstrs (CmmUnsafeForeignCall target (catMaybes [res]) args)+ where+ -- Assume we can call these functions directly, and that they're not in a dynamic library.+ -- TODO: Why is this ok? Under linux this code will be in libm.so+ -- Is it because they're really implemented as a primitive instruction by the assembler?? -- BL 2009/12/31+ lbl = mkForeignLabel fn Nothing ForeignLabelInThisPackage IsFunction++ fn = case mop of+ MO_F32_Sqrt -> fsLit "sqrtf"+ MO_F32_Fabs -> fsLit "fabsf"+ MO_F32_Sin -> fsLit "sinf"+ MO_F32_Cos -> fsLit "cosf"+ MO_F32_Tan -> fsLit "tanf"+ MO_F32_Exp -> fsLit "expf"+ MO_F32_Log -> fsLit "logf"++ MO_F32_Asin -> fsLit "asinf"+ MO_F32_Acos -> fsLit "acosf"+ MO_F32_Atan -> fsLit "atanf"++ MO_F32_Sinh -> fsLit "sinhf"+ MO_F32_Cosh -> fsLit "coshf"+ MO_F32_Tanh -> fsLit "tanhf"+ MO_F32_Pwr -> fsLit "powf"++ MO_F64_Sqrt -> fsLit "sqrt"+ MO_F64_Fabs -> fsLit "fabs"+ MO_F64_Sin -> fsLit "sin"+ MO_F64_Cos -> fsLit "cos"+ MO_F64_Tan -> fsLit "tan"+ MO_F64_Exp -> fsLit "exp"+ MO_F64_Log -> fsLit "log"++ MO_F64_Asin -> fsLit "asin"+ MO_F64_Acos -> fsLit "acos"+ MO_F64_Atan -> fsLit "atan"++ MO_F64_Sinh -> fsLit "sinh"+ MO_F64_Cosh -> fsLit "cosh"+ MO_F64_Tanh -> fsLit "tanh"+ MO_F64_Pwr -> fsLit "pow"++ MO_Memcpy _ -> fsLit "memcpy"+ MO_Memset _ -> fsLit "memset"+ MO_Memmove _ -> fsLit "memmove"++ MO_PopCnt _ -> fsLit "popcnt"+ MO_BSwap _ -> fsLit "bswap"+ MO_Clz w -> fsLit $ clzLabel w+ MO_Ctz _ -> unsupported++ MO_AtomicRMW _ _ -> fsLit "atomicrmw"+ MO_AtomicRead _ -> fsLit "atomicread"+ MO_AtomicWrite _ -> fsLit "atomicwrite"+ MO_Cmpxchg _ -> fsLit "cmpxchg"++ MO_UF_Conv _ -> unsupported++ MO_S_QuotRem {} -> unsupported+ MO_U_QuotRem {} -> unsupported+ MO_U_QuotRem2 {} -> unsupported+ MO_Add2 {} -> unsupported+ MO_AddIntC {} -> unsupported+ MO_SubIntC {} -> unsupported+ MO_SubWordC {} -> unsupported+ MO_U_Mul2 {} -> unsupported+ MO_WriteBarrier -> unsupported+ MO_Touch -> unsupported+ (MO_Prefetch_Data _ ) -> unsupported+ unsupported = panic ("outOfLineCmmOp: " ++ show mop+ ++ " not supported here")++-- -----------------------------------------------------------------------------+-- Generating a table-branch++genSwitch :: DynFlags -> CmmExpr -> SwitchTargets -> NatM InstrBlock++genSwitch dflags expr targets+ | gopt Opt_PIC dflags+ = do+ (reg,e_code) <- getNonClobberedReg (cmmOffset dflags expr offset)+ -- getNonClobberedReg because it needs to survive across t_code+ lbl <- getNewLabelNat+ dflags <- getDynFlags+ let is32bit = target32Bit (targetPlatform dflags)+ os = platformOS (targetPlatform dflags)+ -- Might want to use .rodata.<function we're in> instead, but as+ -- long as it's something unique it'll work out since the+ -- references to the jump table are in the appropriate section.+ rosection = case os of+ -- on Mac OS X/x86_64, put the jump table in the text section to+ -- work around a limitation of the linker.+ -- ld64 is unable to handle the relocations for+ -- .quad L1 - L0+ -- if L0 is not preceded by a non-anonymous label in its section.+ OSDarwin | not is32bit -> Section Text lbl+ _ -> Section ReadOnlyData lbl+ dynRef <- cmmMakeDynamicReference dflags DataReference lbl+ (tableReg,t_code) <- getSomeReg $ dynRef+ let op = OpAddr (AddrBaseIndex (EABaseReg tableReg)+ (EAIndex reg (wORD_SIZE dflags)) (ImmInt 0))++ offsetReg <- getNewRegNat (intFormat (wordWidth dflags))+ return $ if is32bit || os == OSDarwin+ then e_code `appOL` t_code `appOL` toOL [+ ADD (intFormat (wordWidth dflags)) op (OpReg tableReg),+ JMP_TBL (OpReg tableReg) ids rosection lbl+ ]+ else -- HACK: On x86_64 binutils<2.17 is only able to generate+ -- PC32 relocations, hence we only get 32-bit offsets in+ -- the jump table. As these offsets are always negative+ -- we need to properly sign extend them to 64-bit. This+ -- hack should be removed in conjunction with the hack in+ -- PprMach.hs/pprDataItem once binutils 2.17 is standard.+ e_code `appOL` t_code `appOL` toOL [+ MOVSxL II32 op (OpReg offsetReg),+ ADD (intFormat (wordWidth dflags))+ (OpReg offsetReg)+ (OpReg tableReg),+ JMP_TBL (OpReg tableReg) ids rosection lbl+ ]+ | otherwise+ = do+ (reg,e_code) <- getSomeReg (cmmOffset dflags expr offset)+ lbl <- getNewLabelNat+ let op = OpAddr (AddrBaseIndex EABaseNone (EAIndex reg (wORD_SIZE dflags)) (ImmCLbl lbl))+ code = e_code `appOL` toOL [+ JMP_TBL op ids (Section ReadOnlyData lbl) lbl+ ]+ return code+ where (offset, ids) = switchTargetsToTable targets++generateJumpTableForInstr :: DynFlags -> Instr -> Maybe (NatCmmDecl (Alignment, CmmStatics) Instr)+generateJumpTableForInstr dflags (JMP_TBL _ ids section lbl)+ = Just (createJumpTable dflags ids section lbl)+generateJumpTableForInstr _ _ = Nothing++createJumpTable :: DynFlags -> [Maybe BlockId] -> Section -> CLabel+ -> GenCmmDecl (Alignment, CmmStatics) h g+createJumpTable dflags ids section lbl+ = let jumpTable+ | gopt Opt_PIC dflags =+ let jumpTableEntryRel Nothing+ = CmmStaticLit (CmmInt 0 (wordWidth dflags))+ jumpTableEntryRel (Just blockid)+ = CmmStaticLit (CmmLabelDiffOff blockLabel lbl 0)+ where blockLabel = mkAsmTempLabel (getUnique blockid)+ in map jumpTableEntryRel ids+ | otherwise = map (jumpTableEntry dflags) ids+ in CmmData section (1, Statics lbl jumpTable)++extractUnwindPoints :: [Instr] -> [UnwindPoint]+extractUnwindPoints instrs =+ [ UnwindPoint lbl unwinds | UNWIND lbl unwinds <- instrs]++-- -----------------------------------------------------------------------------+-- 'condIntReg' and 'condFltReg': condition codes into registers++-- Turn those condition codes into integers now (when they appear on+-- the right hand side of an assignment).+--+-- (If applicable) Do not fill the delay slots here; you will confuse the+-- register allocator.++condIntReg :: Cond -> CmmExpr -> CmmExpr -> NatM Register++condIntReg cond x y = do+ CondCode _ cond cond_code <- condIntCode cond x y+ tmp <- getNewRegNat II8+ let+ code dst = cond_code `appOL` toOL [+ SETCC cond (OpReg tmp),+ MOVZxL II8 (OpReg tmp) (OpReg dst)+ ]+ return (Any II32 code)++++condFltReg :: Bool -> Cond -> CmmExpr -> CmmExpr -> NatM Register+condFltReg is32Bit cond x y = if_sse2 condFltReg_sse2 condFltReg_x87+ where+ condFltReg_x87 = do+ CondCode _ cond cond_code <- condFltCode cond x y+ tmp <- getNewRegNat II8+ let+ code dst = cond_code `appOL` toOL [+ SETCC cond (OpReg tmp),+ MOVZxL II8 (OpReg tmp) (OpReg dst)+ ]+ return (Any II32 code)++ condFltReg_sse2 = do+ CondCode _ cond cond_code <- condFltCode cond x y+ tmp1 <- getNewRegNat (archWordFormat is32Bit)+ tmp2 <- getNewRegNat (archWordFormat is32Bit)+ let+ -- We have to worry about unordered operands (eg. comparisons+ -- against NaN). If the operands are unordered, the comparison+ -- sets the parity flag, carry flag and zero flag.+ -- All comparisons are supposed to return false for unordered+ -- operands except for !=, which returns true.+ --+ -- Optimisation: we don't have to test the parity flag if we+ -- know the test has already excluded the unordered case: eg >+ -- and >= test for a zero carry flag, which can only occur for+ -- ordered operands.+ --+ -- ToDo: by reversing comparisons we could avoid testing the+ -- parity flag in more cases.++ code dst =+ cond_code `appOL`+ (case cond of+ NE -> or_unordered dst+ GU -> plain_test dst+ GEU -> plain_test dst+ _ -> and_ordered dst)++ plain_test dst = toOL [+ SETCC cond (OpReg tmp1),+ MOVZxL II8 (OpReg tmp1) (OpReg dst)+ ]+ or_unordered dst = toOL [+ SETCC cond (OpReg tmp1),+ SETCC PARITY (OpReg tmp2),+ OR II8 (OpReg tmp1) (OpReg tmp2),+ MOVZxL II8 (OpReg tmp2) (OpReg dst)+ ]+ and_ordered dst = toOL [+ SETCC cond (OpReg tmp1),+ SETCC NOTPARITY (OpReg tmp2),+ AND II8 (OpReg tmp1) (OpReg tmp2),+ MOVZxL II8 (OpReg tmp2) (OpReg dst)+ ]+ return (Any II32 code)+++-- -----------------------------------------------------------------------------+-- 'trivial*Code': deal with trivial instructions++-- Trivial (dyadic: 'trivialCode', floating-point: 'trivialFCode',+-- unary: 'trivialUCode', unary fl-pt:'trivialUFCode') instructions.+-- Only look for constants on the right hand side, because that's+-- where the generic optimizer will have put them.++-- Similarly, for unary instructions, we don't have to worry about+-- matching an StInt as the argument, because genericOpt will already+-- have handled the constant-folding.+++{-+The Rules of the Game are:++* You cannot assume anything about the destination register dst;+ it may be anything, including a fixed reg.++* You may compute an operand into a fixed reg, but you may not+ subsequently change the contents of that fixed reg. If you+ want to do so, first copy the value either to a temporary+ or into dst. You are free to modify dst even if it happens+ to be a fixed reg -- that's not your problem.++* You cannot assume that a fixed reg will stay live over an+ arbitrary computation. The same applies to the dst reg.++* Temporary regs obtained from getNewRegNat are distinct from+ each other and from all other regs, and stay live over+ arbitrary computations.++--------------------++SDM's version of The Rules:++* If getRegister returns Any, that means it can generate correct+ code which places the result in any register, period. Even if that+ register happens to be read during the computation.++ Corollary #1: this means that if you are generating code for an+ operation with two arbitrary operands, you cannot assign the result+ of the first operand into the destination register before computing+ the second operand. The second operand might require the old value+ of the destination register.++ Corollary #2: A function might be able to generate more efficient+ code if it knows the destination register is a new temporary (and+ therefore not read by any of the sub-computations).++* If getRegister returns Any, then the code it generates may modify only:+ (a) fresh temporaries+ (b) the destination register+ (c) known registers (eg. %ecx is used by shifts)+ In particular, it may *not* modify global registers, unless the global+ register happens to be the destination register.+-}++trivialCode :: Width -> (Operand -> Operand -> Instr)+ -> Maybe (Operand -> Operand -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialCode width instr m a b+ = do is32Bit <- is32BitPlatform+ trivialCode' is32Bit width instr m a b++trivialCode' :: Bool -> Width -> (Operand -> Operand -> Instr)+ -> Maybe (Operand -> Operand -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialCode' is32Bit width _ (Just revinstr) (CmmLit lit_a) b+ | is32BitLit is32Bit lit_a = do+ b_code <- getAnyReg b+ let+ code dst+ = b_code dst `snocOL`+ revinstr (OpImm (litToImm lit_a)) (OpReg dst)+ return (Any (intFormat width) code)++trivialCode' _ width instr _ a b+ = genTrivialCode (intFormat width) instr a b++-- This is re-used for floating pt instructions too.+genTrivialCode :: Format -> (Operand -> Operand -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+genTrivialCode rep instr a b = do+ (b_op, b_code) <- getNonClobberedOperand b+ a_code <- getAnyReg a+ tmp <- getNewRegNat rep+ let+ -- We want the value of b to stay alive across the computation of a.+ -- But, we want to calculate a straight into the destination register,+ -- because the instruction only has two operands (dst := dst `op` src).+ -- The troublesome case is when the result of b is in the same register+ -- as the destination reg. In this case, we have to save b in a+ -- new temporary across the computation of a.+ code dst+ | dst `regClashesWithOp` b_op =+ b_code `appOL`+ unitOL (MOV rep b_op (OpReg tmp)) `appOL`+ a_code dst `snocOL`+ instr (OpReg tmp) (OpReg dst)+ | otherwise =+ b_code `appOL`+ a_code dst `snocOL`+ instr b_op (OpReg dst)+ return (Any rep code)++regClashesWithOp :: Reg -> Operand -> Bool+reg `regClashesWithOp` OpReg reg2 = reg == reg2+reg `regClashesWithOp` OpAddr amode = any (==reg) (addrModeRegs amode)+_ `regClashesWithOp` _ = False++-----------++trivialUCode :: Format -> (Operand -> Instr)+ -> CmmExpr -> NatM Register+trivialUCode rep instr x = do+ x_code <- getAnyReg x+ let+ code dst =+ x_code dst `snocOL`+ instr (OpReg dst)+ return (Any rep code)++-----------++trivialFCode_x87 :: (Format -> Reg -> Reg -> Reg -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialFCode_x87 instr x y = do+ (x_reg, x_code) <- getNonClobberedReg x -- these work for float regs too+ (y_reg, y_code) <- getSomeReg y+ let+ format = FF80 -- always, on x87+ code dst =+ x_code `appOL`+ y_code `snocOL`+ instr format x_reg y_reg dst+ return (Any format code)++trivialFCode_sse2 :: Width -> (Format -> Operand -> Operand -> Instr)+ -> CmmExpr -> CmmExpr -> NatM Register+trivialFCode_sse2 pk instr x y+ = genTrivialCode format (instr format) x y+ where format = floatFormat pk+++trivialUFCode :: Format -> (Reg -> Reg -> Instr) -> CmmExpr -> NatM Register+trivialUFCode format instr x = do+ (x_reg, x_code) <- getSomeReg x+ let+ code dst =+ x_code `snocOL`+ instr x_reg dst+ return (Any format code)+++--------------------------------------------------------------------------------+coerceInt2FP :: Width -> Width -> CmmExpr -> NatM Register+coerceInt2FP from to x = if_sse2 coerce_sse2 coerce_x87+ where+ coerce_x87 = do+ (x_reg, x_code) <- getSomeReg x+ let+ opc = case to of W32 -> GITOF; W64 -> GITOD;+ n -> panic $ "coerceInt2FP.x87: unhandled width ("+ ++ show n ++ ")"+ code dst = x_code `snocOL` opc x_reg dst+ -- ToDo: works for non-II32 reps?+ return (Any FF80 code)++ coerce_sse2 = do+ (x_op, x_code) <- getOperand x -- ToDo: could be a safe operand+ let+ opc = case to of W32 -> CVTSI2SS; W64 -> CVTSI2SD+ n -> panic $ "coerceInt2FP.sse: unhandled width ("+ ++ show n ++ ")"+ code dst = x_code `snocOL` opc (intFormat from) x_op dst+ return (Any (floatFormat to) code)+ -- works even if the destination rep is <II32++--------------------------------------------------------------------------------+coerceFP2Int :: Width -> Width -> CmmExpr -> NatM Register+coerceFP2Int from to x = if_sse2 coerceFP2Int_sse2 coerceFP2Int_x87+ where+ coerceFP2Int_x87 = do+ (x_reg, x_code) <- getSomeReg x+ let+ opc = case from of W32 -> GFTOI; W64 -> GDTOI+ n -> panic $ "coerceFP2Int.x87: unhandled width ("+ ++ show n ++ ")"+ code dst = x_code `snocOL` opc x_reg dst+ -- ToDo: works for non-II32 reps?+ return (Any (intFormat to) code)++ coerceFP2Int_sse2 = do+ (x_op, x_code) <- getOperand x -- ToDo: could be a safe operand+ let+ opc = case from of W32 -> CVTTSS2SIQ; W64 -> CVTTSD2SIQ;+ n -> panic $ "coerceFP2Init.sse: unhandled width ("+ ++ show n ++ ")"+ code dst = x_code `snocOL` opc (intFormat to) x_op dst+ return (Any (intFormat to) code)+ -- works even if the destination rep is <II32+++--------------------------------------------------------------------------------+coerceFP2FP :: Width -> CmmExpr -> NatM Register+coerceFP2FP to x = do+ use_sse2 <- sse2Enabled+ (x_reg, x_code) <- getSomeReg x+ let+ opc | use_sse2 = case to of W32 -> CVTSD2SS; W64 -> CVTSS2SD;+ n -> panic $ "coerceFP2FP: unhandled width ("+ ++ show n ++ ")"+ | otherwise = GDTOF+ code dst = x_code `snocOL` opc x_reg dst+ return (Any (if use_sse2 then floatFormat to else FF80) code)++--------------------------------------------------------------------------------++sse2NegCode :: Width -> CmmExpr -> NatM Register+sse2NegCode w x = do+ let fmt = floatFormat w+ x_code <- getAnyReg x+ -- This is how gcc does it, so it can't be that bad:+ let+ const = case fmt of+ FF32 -> CmmInt 0x80000000 W32+ FF64 -> CmmInt 0x8000000000000000 W64+ x@II8 -> wrongFmt x+ x@II16 -> wrongFmt x+ x@II32 -> wrongFmt x+ x@II64 -> wrongFmt x+ x@FF80 -> wrongFmt x+ where+ wrongFmt x = panic $ "sse2NegCode: " ++ show x+ Amode amode amode_code <- memConstant (widthInBytes w) const+ tmp <- getNewRegNat fmt+ let+ code dst = x_code dst `appOL` amode_code `appOL` toOL [+ MOV fmt (OpAddr amode) (OpReg tmp),+ XOR fmt (OpReg tmp) (OpReg dst)+ ]+ --+ return (Any fmt code)++isVecExpr :: CmmExpr -> Bool+isVecExpr (CmmMachOp (MO_V_Insert {}) _) = True+isVecExpr (CmmMachOp (MO_V_Extract {}) _) = True+isVecExpr (CmmMachOp (MO_V_Add {}) _) = True+isVecExpr (CmmMachOp (MO_V_Sub {}) _) = True+isVecExpr (CmmMachOp (MO_V_Mul {}) _) = True+isVecExpr (CmmMachOp (MO_VS_Quot {}) _) = True+isVecExpr (CmmMachOp (MO_VS_Rem {}) _) = True+isVecExpr (CmmMachOp (MO_VS_Neg {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Insert {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Extract {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Add {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Sub {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Mul {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Quot {}) _) = True+isVecExpr (CmmMachOp (MO_VF_Neg {}) _) = True+isVecExpr (CmmMachOp _ [e]) = isVecExpr e+isVecExpr _ = False++needLlvm :: NatM a+needLlvm =+ sorry $ unlines ["The native code generator does not support vector"+ ,"instructions. Please use -fllvm."]
+ nativeGen/X86/Cond.hs view
@@ -0,0 +1,68 @@+module X86.Cond (+ Cond(..),+ condUnsigned,+ condToSigned,+ condToUnsigned,+ maybeFlipCond+)++where++data Cond+ = ALWAYS -- What's really used? ToDo+ | EQQ+ | GE+ | GEU+ | GTT+ | GU+ | LE+ | LEU+ | LTT+ | LU+ | NE+ | NEG+ | POS+ | CARRY+ | OFLO+ | PARITY+ | NOTPARITY+ deriving Eq++condUnsigned :: Cond -> Bool+condUnsigned GU = True+condUnsigned LU = True+condUnsigned GEU = True+condUnsigned LEU = True+condUnsigned _ = False+++condToSigned :: Cond -> Cond+condToSigned GU = GTT+condToSigned LU = LTT+condToSigned GEU = GE+condToSigned LEU = LE+condToSigned x = x+++condToUnsigned :: Cond -> Cond+condToUnsigned GTT = GU+condToUnsigned LTT = LU+condToUnsigned GE = GEU+condToUnsigned LE = LEU+condToUnsigned x = x++-- | @maybeFlipCond c@ returns @Just c'@ if it is possible to flip the+-- arguments to the conditional @c@, and the new condition should be @c'@.+maybeFlipCond :: Cond -> Maybe Cond+maybeFlipCond cond = case cond of+ EQQ -> Just EQQ+ NE -> Just NE+ LU -> Just GU+ GU -> Just LU+ LEU -> Just GEU+ GEU -> Just LEU+ LTT -> Just GTT+ GTT -> Just LTT+ LE -> Just GE+ GE -> Just LE+ _other -> Nothing
+ nativeGen/X86/Instr.hs view
@@ -0,0 +1,1059 @@+{-# LANGUAGE CPP, TypeFamilies #-}++-----------------------------------------------------------------------------+--+-- Machine-dependent assembly language+--+-- (c) The University of Glasgow 1993-2004+--+-----------------------------------------------------------------------------++module X86.Instr (Instr(..), Operand(..), PrefetchVariant(..), JumpDest,+ getJumpDestBlockId, canShortcut, shortcutStatics,+ shortcutJump, i386_insert_ffrees, allocMoreStack,+ maxSpillSlots, archWordFormat)+where++#include "HsVersions.h"+#include "nativeGen/NCG.h"++import X86.Cond+import X86.Regs+import Instruction+import Format+import RegClass+import Reg+import TargetReg++import BlockId+import Hoopl+import CodeGen.Platform+import Cmm+import FastString+import Outputable+import Platform++import BasicTypes (Alignment)+import CLabel+import DynFlags+import UniqSet+import Unique+import UniqSupply+import Debug (UnwindTable)++import Control.Monad+import Data.Maybe (fromMaybe)++-- Format of an x86/x86_64 memory address, in bytes.+--+archWordFormat :: Bool -> Format+archWordFormat is32Bit+ | is32Bit = II32+ | otherwise = II64++-- | Instruction instance for x86 instruction set.+instance Instruction Instr where+ regUsageOfInstr = x86_regUsageOfInstr+ patchRegsOfInstr = x86_patchRegsOfInstr+ isJumpishInstr = x86_isJumpishInstr+ jumpDestsOfInstr = x86_jumpDestsOfInstr+ patchJumpInstr = x86_patchJumpInstr+ mkSpillInstr = x86_mkSpillInstr+ mkLoadInstr = x86_mkLoadInstr+ takeDeltaInstr = x86_takeDeltaInstr+ isMetaInstr = x86_isMetaInstr+ mkRegRegMoveInstr = x86_mkRegRegMoveInstr+ takeRegRegMoveInstr = x86_takeRegRegMoveInstr+ mkJumpInstr = x86_mkJumpInstr+ mkStackAllocInstr = x86_mkStackAllocInstr+ mkStackDeallocInstr = x86_mkStackDeallocInstr+++-- -----------------------------------------------------------------------------+-- Intel x86 instructions++{-+Intel, in their infinite wisdom, selected a stack model for floating+point registers on x86. That might have made sense back in 1979 --+nowadays we can see it for the nonsense it really is. A stack model+fits poorly with the existing nativeGen infrastructure, which assumes+flat integer and FP register sets. Prior to this commit, nativeGen+could not generate correct x86 FP code -- to do so would have meant+somehow working the register-stack paradigm into the register+allocator and spiller, which sounds very difficult.++We have decided to cheat, and go for a simple fix which requires no+infrastructure modifications, at the expense of generating ropey but+correct FP code. All notions of the x86 FP stack and its insns have+been removed. Instead, we pretend (to the instruction selector and+register allocator) that x86 has six floating point registers, %fake0+.. %fake5, which can be used in the usual flat manner. We further+claim that x86 has floating point instructions very similar to SPARC+and Alpha, that is, a simple 3-operand register-register arrangement.+Code generation and register allocation proceed on this basis.++When we come to print out the final assembly, our convenient fiction+is converted to dismal reality. Each fake instruction is+independently converted to a series of real x86 instructions.+%fake0 .. %fake5 are mapped to %st(0) .. %st(5). To do reg-reg+arithmetic operations, the two operands are pushed onto the top of the+FP stack, the operation done, and the result copied back into the+relevant register. There are only six %fake registers because 2 are+needed for the translation, and x86 has 8 in total.++The translation is inefficient but is simple and it works. A cleverer+translation would handle a sequence of insns, simulating the FP stack+contents, would not impose a fixed mapping from %fake to %st regs, and+hopefully could avoid most of the redundant reg-reg moves of the+current translation.++We might as well make use of whatever unique FP facilities Intel have+chosen to bless us with (let's not be churlish, after all).+Hence GLDZ and GLD1. Bwahahahahahahaha!+-}++{-+Note [x86 Floating point precision]++Intel's internal floating point registers are by default 80 bit+extended precision. This means that all operations done on values in+registers are done at 80 bits, and unless the intermediate values are+truncated to the appropriate size (32 or 64 bits) by storing in+memory, calculations in registers will give different results from+calculations which pass intermediate values in memory (eg. via+function calls).++One solution is to set the FPU into 64 bit precision mode. Some OSs+do this (eg. FreeBSD) and some don't (eg. Linux). The problem here is+that this will only affect 64-bit precision arithmetic; 32-bit+calculations will still be done at 64-bit precision in registers. So+it doesn't solve the whole problem.++There's also the issue of what the C library is expecting in terms of+precision. It seems to be the case that glibc on Linux expects the+FPU to be set to 80 bit precision, so setting it to 64 bit could have+unexpected effects. Changing the default could have undesirable+effects on other 3rd-party library code too, so the right thing would+be to save/restore the FPU control word across Haskell code if we were+to do this.++gcc's -ffloat-store gives consistent results by always storing the+results of floating-point calculations in memory, which works for both+32 and 64-bit precision. However, it only affects the values of+user-declared floating point variables in C, not intermediate results.+GHC in -fvia-C mode uses -ffloat-store (see the -fexcess-precision+flag).++Another problem is how to spill floating point registers in the+register allocator. Should we spill the whole 80 bits, or just 64?+On an OS which is set to 64 bit precision, spilling 64 is fine. On+Linux, spilling 64 bits will round the results of some operations.+This is what gcc does. Spilling at 80 bits requires taking up a full+128 bit slot (so we get alignment). We spill at 80-bits and ignore+the alignment problems.++In the future [edit: now available in GHC 7.0.1, with the -msse2+flag], we'll use the SSE registers for floating point. This requires+a CPU that supports SSE2 (ordinary SSE only supports 32 bit precision+float ops), which means P4 or Xeon and above. Using SSE will solve+all these problems, because the SSE registers use fixed 32 bit or 64+bit precision.++--SDM 1/2003+-}++data Instr+ -- comment pseudo-op+ = COMMENT FastString++ -- location pseudo-op (file, line, col, name)+ | LOCATION Int Int Int String++ -- some static data spat out during code+ -- generation. Will be extracted before+ -- pretty-printing.+ | LDATA Section (Alignment, CmmStatics)++ -- start a new basic block. Useful during+ -- codegen, removed later. Preceding+ -- instruction should be a jump, as per the+ -- invariants for a BasicBlock (see Cmm).+ | NEWBLOCK BlockId++ -- unwinding information+ -- See Note [Unwinding information in the NCG].+ | UNWIND CLabel UnwindTable++ -- specify current stack offset for benefit of subsequent passes.+ -- This carries a BlockId so it can be used in unwinding information.+ | DELTA Int++ -- Moves.+ | MOV Format Operand Operand+ | CMOV Cond Format Operand Reg+ | MOVZxL Format Operand Operand -- format is the size of operand 1+ | MOVSxL Format Operand Operand -- format is the size of operand 1+ -- x86_64 note: plain mov into a 32-bit register always zero-extends+ -- into the 64-bit reg, in contrast to the 8 and 16-bit movs which+ -- don't affect the high bits of the register.++ -- Load effective address (also a very useful three-operand add instruction :-)+ | LEA Format Operand Operand++ -- Int Arithmetic.+ | ADD Format Operand Operand+ | ADC Format Operand Operand+ | SUB Format Operand Operand+ | SBB Format Operand Operand++ | MUL Format Operand Operand+ | MUL2 Format Operand -- %edx:%eax = operand * %rax+ | IMUL Format Operand Operand -- signed int mul+ | IMUL2 Format Operand -- %edx:%eax = operand * %eax++ | DIV Format Operand -- eax := eax:edx/op, edx := eax:edx%op+ | IDIV Format Operand -- ditto, but signed++ -- Int Arithmetic, where the effects on the condition register+ -- are important. Used in specialized sequences such as MO_Add2.+ -- Do not rewrite these instructions to "equivalent" ones that+ -- have different effect on the condition register! (See #9013.)+ | ADD_CC Format Operand Operand+ | SUB_CC Format Operand Operand++ -- Simple bit-twiddling.+ | AND Format Operand Operand+ | OR Format Operand Operand+ | XOR Format Operand Operand+ | NOT Format Operand+ | NEGI Format Operand -- NEG instruction (name clash with Cond)+ | BSWAP Format Reg++ -- Shifts (amount may be immediate or %cl only)+ | SHL Format Operand{-amount-} Operand+ | SAR Format Operand{-amount-} Operand+ | SHR Format Operand{-amount-} Operand++ | BT Format Imm Operand+ | NOP++ -- x86 Float Arithmetic.+ -- Note that we cheat by treating G{ABS,MOV,NEG} of doubles+ -- as single instructions right up until we spit them out.+ -- all the 3-operand fake fp insns are src1 src2 dst+ -- and furthermore are constrained to be fp regs only.+ -- IMPORTANT: keep is_G_insn up to date with any changes here+ | GMOV Reg Reg -- src(fpreg), dst(fpreg)+ | GLD Format AddrMode Reg -- src, dst(fpreg)+ | GST Format Reg AddrMode -- src(fpreg), dst++ | GLDZ Reg -- dst(fpreg)+ | GLD1 Reg -- dst(fpreg)++ | GFTOI Reg Reg -- src(fpreg), dst(intreg)+ | GDTOI Reg Reg -- src(fpreg), dst(intreg)++ | GITOF Reg Reg -- src(intreg), dst(fpreg)+ | GITOD Reg Reg -- src(intreg), dst(fpreg)++ | GDTOF Reg Reg -- src(fpreg), dst(fpreg)++ | GADD Format Reg Reg Reg -- src1, src2, dst+ | GDIV Format Reg Reg Reg -- src1, src2, dst+ | GSUB Format Reg Reg Reg -- src1, src2, dst+ | GMUL Format Reg Reg Reg -- src1, src2, dst++ -- FP compare. Cond must be `elem` [EQQ, NE, LE, LTT, GE, GTT]+ -- Compare src1 with src2; set the Zero flag iff the numbers are+ -- comparable and the comparison is True. Subsequent code must+ -- test the %eflags zero flag regardless of the supplied Cond.+ | GCMP Cond Reg Reg -- src1, src2++ | GABS Format Reg Reg -- src, dst+ | GNEG Format Reg Reg -- src, dst+ | GSQRT Format Reg Reg -- src, dst+ | GSIN Format CLabel CLabel Reg Reg -- src, dst+ | GCOS Format CLabel CLabel Reg Reg -- src, dst+ | GTAN Format CLabel CLabel Reg Reg -- src, dst++ | GFREE -- do ffree on all x86 regs; an ugly hack+++ -- SSE2 floating point: we use a restricted set of the available SSE2+ -- instructions for floating-point.+ -- use MOV for moving (either movss or movsd (movlpd better?))+ | CVTSS2SD Reg Reg -- F32 to F64+ | CVTSD2SS Reg Reg -- F64 to F32+ | CVTTSS2SIQ Format Operand Reg -- F32 to I32/I64 (with truncation)+ | CVTTSD2SIQ Format Operand Reg -- F64 to I32/I64 (with truncation)+ | CVTSI2SS Format Operand Reg -- I32/I64 to F32+ | CVTSI2SD Format Operand Reg -- I32/I64 to F64++ -- use ADD & SUB for arithmetic. In both cases, operands+ -- are Operand Reg.++ -- SSE2 floating-point division:+ | FDIV Format Operand Operand -- divisor, dividend(dst)++ -- use CMP for comparisons. ucomiss and ucomisd instructions+ -- compare single/double prec floating point respectively.++ | SQRT Format Operand Reg -- src, dst+++ -- Comparison+ | TEST Format Operand Operand+ | CMP Format Operand Operand+ | SETCC Cond Operand++ -- Stack Operations.+ | PUSH Format Operand+ | POP Format Operand+ -- both unused (SDM):+ -- | PUSHA+ -- | POPA++ -- Jumping around.+ | JMP Operand [Reg] -- including live Regs at the call+ | JXX Cond BlockId -- includes unconditional branches+ | JXX_GBL Cond Imm -- non-local version of JXX+ -- Table jump+ | JMP_TBL Operand -- Address to jump to+ [Maybe BlockId] -- Blocks in the jump table+ Section -- Data section jump table should be put in+ CLabel -- Label of jump table+ | CALL (Either Imm Reg) [Reg]++ -- Other things.+ | CLTD Format -- sign extend %eax into %edx:%eax++ | FETCHGOT Reg -- pseudo-insn for ELF position-independent code+ -- pretty-prints as+ -- call 1f+ -- 1: popl %reg+ -- addl __GLOBAL_OFFSET_TABLE__+.-1b, %reg+ | FETCHPC Reg -- pseudo-insn for Darwin position-independent code+ -- pretty-prints as+ -- call 1f+ -- 1: popl %reg++ -- bit counting instructions+ | POPCNT Format Operand Reg -- [SSE4.2] count number of bits set to 1+ | BSF Format Operand Reg -- bit scan forward+ | BSR Format Operand Reg -- bit scan reverse++ -- prefetch+ | PREFETCH PrefetchVariant Format Operand -- prefetch Variant, addr size, address to prefetch+ -- variant can be NTA, Lvl0, Lvl1, or Lvl2++ | LOCK Instr -- lock prefix+ | XADD Format Operand Operand -- src (r), dst (r/m)+ | CMPXCHG Format Operand Operand -- src (r), dst (r/m), eax implicit+ | MFENCE++data PrefetchVariant = NTA | Lvl0 | Lvl1 | Lvl2+++data Operand+ = OpReg Reg -- register+ | OpImm Imm -- immediate value+ | OpAddr AddrMode -- memory reference++++-- | Returns which registers are read and written as a (read, written)+-- pair.+x86_regUsageOfInstr :: Platform -> Instr -> RegUsage+x86_regUsageOfInstr platform instr+ = case instr of+ MOV _ src dst -> usageRW src dst+ CMOV _ _ src dst -> mkRU (use_R src [dst]) [dst]+ MOVZxL _ src dst -> usageRW src dst+ MOVSxL _ src dst -> usageRW src dst+ LEA _ src dst -> usageRW src dst+ ADD _ src dst -> usageRM src dst+ ADC _ src dst -> usageRM src dst+ SUB _ src dst -> usageRM src dst+ SBB _ src dst -> usageRM src dst+ IMUL _ src dst -> usageRM src dst+ IMUL2 _ src -> mkRU (eax:use_R src []) [eax,edx]+ MUL _ src dst -> usageRM src dst+ MUL2 _ src -> mkRU (eax:use_R src []) [eax,edx]+ DIV _ op -> mkRU (eax:edx:use_R op []) [eax,edx]+ IDIV _ op -> mkRU (eax:edx:use_R op []) [eax,edx]+ ADD_CC _ src dst -> usageRM src dst+ SUB_CC _ src dst -> usageRM src dst+ AND _ src dst -> usageRM src dst+ OR _ src dst -> usageRM src dst++ XOR _ (OpReg src) (OpReg dst)+ | src == dst -> mkRU [] [dst]++ XOR _ src dst -> usageRM src dst+ NOT _ op -> usageM op+ BSWAP _ reg -> mkRU [reg] [reg]+ NEGI _ op -> usageM op+ SHL _ imm dst -> usageRM imm dst+ SAR _ imm dst -> usageRM imm dst+ SHR _ imm dst -> usageRM imm dst+ BT _ _ src -> mkRUR (use_R src [])++ PUSH _ op -> mkRUR (use_R op [])+ POP _ op -> mkRU [] (def_W op)+ TEST _ src dst -> mkRUR (use_R src $! use_R dst [])+ CMP _ src dst -> mkRUR (use_R src $! use_R dst [])+ SETCC _ op -> mkRU [] (def_W op)+ JXX _ _ -> mkRU [] []+ JXX_GBL _ _ -> mkRU [] []+ JMP op regs -> mkRUR (use_R op regs)+ JMP_TBL op _ _ _ -> mkRUR (use_R op [])+ CALL (Left _) params -> mkRU params (callClobberedRegs platform)+ CALL (Right reg) params -> mkRU (reg:params) (callClobberedRegs platform)+ CLTD _ -> mkRU [eax] [edx]+ NOP -> mkRU [] []++ GMOV src dst -> mkRU [src] [dst]+ GLD _ src dst -> mkRU (use_EA src []) [dst]+ GST _ src dst -> mkRUR (src : use_EA dst [])++ GLDZ dst -> mkRU [] [dst]+ GLD1 dst -> mkRU [] [dst]++ GFTOI src dst -> mkRU [src] [dst]+ GDTOI src dst -> mkRU [src] [dst]++ GITOF src dst -> mkRU [src] [dst]+ GITOD src dst -> mkRU [src] [dst]++ GDTOF src dst -> mkRU [src] [dst]++ GADD _ s1 s2 dst -> mkRU [s1,s2] [dst]+ GSUB _ s1 s2 dst -> mkRU [s1,s2] [dst]+ GMUL _ s1 s2 dst -> mkRU [s1,s2] [dst]+ GDIV _ s1 s2 dst -> mkRU [s1,s2] [dst]++ GCMP _ src1 src2 -> mkRUR [src1,src2]+ GABS _ src dst -> mkRU [src] [dst]+ GNEG _ src dst -> mkRU [src] [dst]+ GSQRT _ src dst -> mkRU [src] [dst]+ GSIN _ _ _ src dst -> mkRU [src] [dst]+ GCOS _ _ _ src dst -> mkRU [src] [dst]+ GTAN _ _ _ src dst -> mkRU [src] [dst]++ CVTSS2SD src dst -> mkRU [src] [dst]+ CVTSD2SS src dst -> mkRU [src] [dst]+ CVTTSS2SIQ _ src dst -> mkRU (use_R src []) [dst]+ CVTTSD2SIQ _ src dst -> mkRU (use_R src []) [dst]+ CVTSI2SS _ src dst -> mkRU (use_R src []) [dst]+ CVTSI2SD _ src dst -> mkRU (use_R src []) [dst]+ FDIV _ src dst -> usageRM src dst++ FETCHGOT reg -> mkRU [] [reg]+ FETCHPC reg -> mkRU [] [reg]++ COMMENT _ -> noUsage+ LOCATION{} -> noUsage+ UNWIND{} -> noUsage+ DELTA _ -> noUsage++ POPCNT _ src dst -> mkRU (use_R src []) [dst]+ BSF _ src dst -> mkRU (use_R src []) [dst]+ BSR _ src dst -> mkRU (use_R src []) [dst]++ -- note: might be a better way to do this+ PREFETCH _ _ src -> mkRU (use_R src []) []+ LOCK i -> x86_regUsageOfInstr platform i+ XADD _ src dst -> usageMM src dst+ CMPXCHG _ src dst -> usageRMM src dst (OpReg eax)+ MFENCE -> noUsage++ _other -> panic "regUsage: unrecognised instr"+ where+ -- # Definitions+ --+ -- Written: If the operand is a register, it's written. If it's an+ -- address, registers mentioned in the address are read.+ --+ -- Modified: If the operand is a register, it's both read and+ -- written. If it's an address, registers mentioned in the address+ -- are read.++ -- 2 operand form; first operand Read; second Written+ usageRW :: Operand -> Operand -> RegUsage+ usageRW op (OpReg reg) = mkRU (use_R op []) [reg]+ usageRW op (OpAddr ea) = mkRUR (use_R op $! use_EA ea [])+ usageRW _ _ = panic "X86.RegInfo.usageRW: no match"++ -- 2 operand form; first operand Read; second Modified+ usageRM :: Operand -> Operand -> RegUsage+ usageRM op (OpReg reg) = mkRU (use_R op [reg]) [reg]+ usageRM op (OpAddr ea) = mkRUR (use_R op $! use_EA ea [])+ usageRM _ _ = panic "X86.RegInfo.usageRM: no match"++ -- 2 operand form; first operand Modified; second Modified+ usageMM :: Operand -> Operand -> RegUsage+ usageMM (OpReg src) (OpReg dst) = mkRU [src, dst] [src, dst]+ usageMM (OpReg src) (OpAddr ea) = mkRU (use_EA ea [src]) [src]+ usageMM _ _ = panic "X86.RegInfo.usageMM: no match"++ -- 3 operand form; first operand Read; second Modified; third Modified+ usageRMM :: Operand -> Operand -> Operand -> RegUsage+ usageRMM (OpReg src) (OpReg dst) (OpReg reg) = mkRU [src, dst, reg] [dst, reg]+ usageRMM (OpReg src) (OpAddr ea) (OpReg reg) = mkRU (use_EA ea [src, reg]) [reg]+ usageRMM _ _ _ = panic "X86.RegInfo.usageRMM: no match"++ -- 1 operand form; operand Modified+ usageM :: Operand -> RegUsage+ usageM (OpReg reg) = mkRU [reg] [reg]+ usageM (OpAddr ea) = mkRUR (use_EA ea [])+ usageM _ = panic "X86.RegInfo.usageM: no match"++ -- Registers defd when an operand is written.+ def_W (OpReg reg) = [reg]+ def_W (OpAddr _ ) = []+ def_W _ = panic "X86.RegInfo.def_W: no match"++ -- Registers used when an operand is read.+ use_R (OpReg reg) tl = reg : tl+ use_R (OpImm _) tl = tl+ use_R (OpAddr ea) tl = use_EA ea tl++ -- Registers used to compute an effective address.+ use_EA (ImmAddr _ _) tl = tl+ use_EA (AddrBaseIndex base index _) tl =+ use_base base $! use_index index tl+ where use_base (EABaseReg r) tl = r : tl+ use_base _ tl = tl+ use_index EAIndexNone tl = tl+ use_index (EAIndex i _) tl = i : tl++ mkRUR src = src' `seq` RU src' []+ where src' = filter (interesting platform) src++ mkRU src dst = src' `seq` dst' `seq` RU src' dst'+ where src' = filter (interesting platform) src+ dst' = filter (interesting platform) dst++-- | Is this register interesting for the register allocator?+interesting :: Platform -> Reg -> Bool+interesting _ (RegVirtual _) = True+interesting platform (RegReal (RealRegSingle i)) = freeReg platform i+interesting _ (RegReal (RealRegPair{})) = panic "X86.interesting: no reg pairs on this arch"++++-- | Applies the supplied function to all registers in instructions.+-- Typically used to change virtual registers to real registers.+x86_patchRegsOfInstr :: Instr -> (Reg -> Reg) -> Instr+x86_patchRegsOfInstr instr env+ = case instr of+ MOV fmt src dst -> patch2 (MOV fmt) src dst+ CMOV cc fmt src dst -> CMOV cc fmt (patchOp src) (env dst)+ MOVZxL fmt src dst -> patch2 (MOVZxL fmt) src dst+ MOVSxL fmt src dst -> patch2 (MOVSxL fmt) src dst+ LEA fmt src dst -> patch2 (LEA fmt) src dst+ ADD fmt src dst -> patch2 (ADD fmt) src dst+ ADC fmt src dst -> patch2 (ADC fmt) src dst+ SUB fmt src dst -> patch2 (SUB fmt) src dst+ SBB fmt src dst -> patch2 (SBB fmt) src dst+ IMUL fmt src dst -> patch2 (IMUL fmt) src dst+ IMUL2 fmt src -> patch1 (IMUL2 fmt) src+ MUL fmt src dst -> patch2 (MUL fmt) src dst+ MUL2 fmt src -> patch1 (MUL2 fmt) src+ IDIV fmt op -> patch1 (IDIV fmt) op+ DIV fmt op -> patch1 (DIV fmt) op+ ADD_CC fmt src dst -> patch2 (ADD_CC fmt) src dst+ SUB_CC fmt src dst -> patch2 (SUB_CC fmt) src dst+ AND fmt src dst -> patch2 (AND fmt) src dst+ OR fmt src dst -> patch2 (OR fmt) src dst+ XOR fmt src dst -> patch2 (XOR fmt) src dst+ NOT fmt op -> patch1 (NOT fmt) op+ BSWAP fmt reg -> BSWAP fmt (env reg)+ NEGI fmt op -> patch1 (NEGI fmt) op+ SHL fmt imm dst -> patch1 (SHL fmt imm) dst+ SAR fmt imm dst -> patch1 (SAR fmt imm) dst+ SHR fmt imm dst -> patch1 (SHR fmt imm) dst+ BT fmt imm src -> patch1 (BT fmt imm) src+ TEST fmt src dst -> patch2 (TEST fmt) src dst+ CMP fmt src dst -> patch2 (CMP fmt) src dst+ PUSH fmt op -> patch1 (PUSH fmt) op+ POP fmt op -> patch1 (POP fmt) op+ SETCC cond op -> patch1 (SETCC cond) op+ JMP op regs -> JMP (patchOp op) regs+ JMP_TBL op ids s lbl -> JMP_TBL (patchOp op) ids s lbl++ GMOV src dst -> GMOV (env src) (env dst)+ GLD fmt src dst -> GLD fmt (lookupAddr src) (env dst)+ GST fmt src dst -> GST fmt (env src) (lookupAddr dst)++ GLDZ dst -> GLDZ (env dst)+ GLD1 dst -> GLD1 (env dst)++ GFTOI src dst -> GFTOI (env src) (env dst)+ GDTOI src dst -> GDTOI (env src) (env dst)++ GITOF src dst -> GITOF (env src) (env dst)+ GITOD src dst -> GITOD (env src) (env dst)++ GDTOF src dst -> GDTOF (env src) (env dst)++ GADD fmt s1 s2 dst -> GADD fmt (env s1) (env s2) (env dst)+ GSUB fmt s1 s2 dst -> GSUB fmt (env s1) (env s2) (env dst)+ GMUL fmt s1 s2 dst -> GMUL fmt (env s1) (env s2) (env dst)+ GDIV fmt s1 s2 dst -> GDIV fmt (env s1) (env s2) (env dst)++ GCMP fmt src1 src2 -> GCMP fmt (env src1) (env src2)+ GABS fmt src dst -> GABS fmt (env src) (env dst)+ GNEG fmt src dst -> GNEG fmt (env src) (env dst)+ GSQRT fmt src dst -> GSQRT fmt (env src) (env dst)+ GSIN fmt l1 l2 src dst -> GSIN fmt l1 l2 (env src) (env dst)+ GCOS fmt l1 l2 src dst -> GCOS fmt l1 l2 (env src) (env dst)+ GTAN fmt l1 l2 src dst -> GTAN fmt l1 l2 (env src) (env dst)++ CVTSS2SD src dst -> CVTSS2SD (env src) (env dst)+ CVTSD2SS src dst -> CVTSD2SS (env src) (env dst)+ CVTTSS2SIQ fmt src dst -> CVTTSS2SIQ fmt (patchOp src) (env dst)+ CVTTSD2SIQ fmt src dst -> CVTTSD2SIQ fmt (patchOp src) (env dst)+ CVTSI2SS fmt src dst -> CVTSI2SS fmt (patchOp src) (env dst)+ CVTSI2SD fmt src dst -> CVTSI2SD fmt (patchOp src) (env dst)+ FDIV fmt src dst -> FDIV fmt (patchOp src) (patchOp dst)++ CALL (Left _) _ -> instr+ CALL (Right reg) p -> CALL (Right (env reg)) p++ FETCHGOT reg -> FETCHGOT (env reg)+ FETCHPC reg -> FETCHPC (env reg)++ NOP -> instr+ COMMENT _ -> instr+ LOCATION {} -> instr+ UNWIND {} -> instr+ DELTA _ -> instr++ JXX _ _ -> instr+ JXX_GBL _ _ -> instr+ CLTD _ -> instr++ POPCNT fmt src dst -> POPCNT fmt (patchOp src) (env dst)+ BSF fmt src dst -> BSF fmt (patchOp src) (env dst)+ BSR fmt src dst -> BSR fmt (patchOp src) (env dst)++ PREFETCH lvl format src -> PREFETCH lvl format (patchOp src)++ LOCK i -> LOCK (x86_patchRegsOfInstr i env)+ XADD fmt src dst -> patch2 (XADD fmt) src dst+ CMPXCHG fmt src dst -> patch2 (CMPXCHG fmt) src dst+ MFENCE -> instr++ _other -> panic "patchRegs: unrecognised instr"++ where+ patch1 :: (Operand -> a) -> Operand -> a+ patch1 insn op = insn $! patchOp op+ patch2 :: (Operand -> Operand -> a) -> Operand -> Operand -> a+ patch2 insn src dst = (insn $! patchOp src) $! patchOp dst++ patchOp (OpReg reg) = OpReg $! env reg+ patchOp (OpImm imm) = OpImm imm+ patchOp (OpAddr ea) = OpAddr $! lookupAddr ea++ lookupAddr (ImmAddr imm off) = ImmAddr imm off+ lookupAddr (AddrBaseIndex base index disp)+ = ((AddrBaseIndex $! lookupBase base) $! lookupIndex index) disp+ where+ lookupBase EABaseNone = EABaseNone+ lookupBase EABaseRip = EABaseRip+ lookupBase (EABaseReg r) = EABaseReg $! env r++ lookupIndex EAIndexNone = EAIndexNone+ lookupIndex (EAIndex r i) = (EAIndex $! env r) i+++--------------------------------------------------------------------------------+x86_isJumpishInstr+ :: Instr -> Bool++x86_isJumpishInstr instr+ = case instr of+ JMP{} -> True+ JXX{} -> True+ JXX_GBL{} -> True+ JMP_TBL{} -> True+ CALL{} -> True+ _ -> False+++x86_jumpDestsOfInstr+ :: Instr+ -> [BlockId]++x86_jumpDestsOfInstr insn+ = case insn of+ JXX _ id -> [id]+ JMP_TBL _ ids _ _ -> [id | Just id <- ids]+ _ -> []+++x86_patchJumpInstr+ :: Instr -> (BlockId -> BlockId) -> Instr++x86_patchJumpInstr insn patchF+ = case insn of+ JXX cc id -> JXX cc (patchF id)+ JMP_TBL op ids section lbl+ -> JMP_TBL op (map (fmap patchF) ids) section lbl+ _ -> insn+++++-- -----------------------------------------------------------------------------+-- | Make a spill instruction.+x86_mkSpillInstr+ :: DynFlags+ -> Reg -- register to spill+ -> Int -- current stack delta+ -> Int -- spill slot to use+ -> Instr++x86_mkSpillInstr dflags reg delta slot+ = let off = spillSlotToOffset platform slot - delta+ in+ case targetClassOfReg platform reg of+ RcInteger -> MOV (archWordFormat is32Bit)+ (OpReg reg) (OpAddr (spRel dflags off))+ RcDouble -> GST FF80 reg (spRel dflags off) {- RcFloat/RcDouble -}+ RcDoubleSSE -> MOV FF64 (OpReg reg) (OpAddr (spRel dflags off))+ _ -> panic "X86.mkSpillInstr: no match"+ where platform = targetPlatform dflags+ is32Bit = target32Bit platform++-- | Make a spill reload instruction.+x86_mkLoadInstr+ :: DynFlags+ -> Reg -- register to load+ -> Int -- current stack delta+ -> Int -- spill slot to use+ -> Instr++x86_mkLoadInstr dflags reg delta slot+ = let off = spillSlotToOffset platform slot - delta+ in+ case targetClassOfReg platform reg of+ RcInteger -> MOV (archWordFormat is32Bit)+ (OpAddr (spRel dflags off)) (OpReg reg)+ RcDouble -> GLD FF80 (spRel dflags off) reg {- RcFloat/RcDouble -}+ RcDoubleSSE -> MOV FF64 (OpAddr (spRel dflags off)) (OpReg reg)+ _ -> panic "X86.x86_mkLoadInstr"+ where platform = targetPlatform dflags+ is32Bit = target32Bit platform++spillSlotSize :: Platform -> Int+spillSlotSize dflags = if is32Bit then 12 else 8+ where is32Bit = target32Bit dflags++maxSpillSlots :: DynFlags -> Int+maxSpillSlots dflags+ = ((rESERVED_C_STACK_BYTES dflags - 64) `div` spillSlotSize (targetPlatform dflags)) - 1+-- = 0 -- useful for testing allocMoreStack++-- number of bytes that the stack pointer should be aligned to+stackAlign :: Int+stackAlign = 16++-- convert a spill slot number to a *byte* offset, with no sign:+-- decide on a per arch basis whether you are spilling above or below+-- the C stack pointer.+spillSlotToOffset :: Platform -> Int -> Int+spillSlotToOffset platform slot+ = 64 + spillSlotSize platform * slot++--------------------------------------------------------------------------------++-- | See if this instruction is telling us the current C stack delta+x86_takeDeltaInstr+ :: Instr+ -> Maybe Int++x86_takeDeltaInstr instr+ = case instr of+ DELTA i -> Just i+ _ -> Nothing+++x86_isMetaInstr+ :: Instr+ -> Bool++x86_isMetaInstr instr+ = case instr of+ COMMENT{} -> True+ LOCATION{} -> True+ LDATA{} -> True+ NEWBLOCK{} -> True+ UNWIND{} -> True+ DELTA{} -> True+ _ -> False++++-- | Make a reg-reg move instruction.+-- On SPARC v8 there are no instructions to move directly between+-- floating point and integer regs. If we need to do that then we+-- have to go via memory.+--+x86_mkRegRegMoveInstr+ :: Platform+ -> Reg+ -> Reg+ -> Instr++x86_mkRegRegMoveInstr platform src dst+ = case targetClassOfReg platform src of+ RcInteger -> case platformArch platform of+ ArchX86 -> MOV II32 (OpReg src) (OpReg dst)+ ArchX86_64 -> MOV II64 (OpReg src) (OpReg dst)+ _ -> panic "x86_mkRegRegMoveInstr: Bad arch"+ RcDouble -> GMOV src dst+ RcDoubleSSE -> MOV FF64 (OpReg src) (OpReg dst)+ _ -> panic "X86.RegInfo.mkRegRegMoveInstr: no match"++-- | Check whether an instruction represents a reg-reg move.+-- The register allocator attempts to eliminate reg->reg moves whenever it can,+-- by assigning the src and dest temporaries to the same real register.+--+x86_takeRegRegMoveInstr+ :: Instr+ -> Maybe (Reg,Reg)++x86_takeRegRegMoveInstr (MOV _ (OpReg r1) (OpReg r2))+ = Just (r1,r2)++x86_takeRegRegMoveInstr _ = Nothing+++-- | Make an unconditional branch instruction.+x86_mkJumpInstr+ :: BlockId+ -> [Instr]++x86_mkJumpInstr id+ = [JXX ALWAYS id]+++x86_mkStackAllocInstr+ :: Platform+ -> Int+ -> Instr+x86_mkStackAllocInstr platform amount+ = case platformArch platform of+ ArchX86 -> SUB II32 (OpImm (ImmInt amount)) (OpReg esp)+ ArchX86_64 -> SUB II64 (OpImm (ImmInt amount)) (OpReg rsp)+ _ -> panic "x86_mkStackAllocInstr"++x86_mkStackDeallocInstr+ :: Platform+ -> Int+ -> Instr+x86_mkStackDeallocInstr platform amount+ = case platformArch platform of+ ArchX86 -> ADD II32 (OpImm (ImmInt amount)) (OpReg esp)+ ArchX86_64 -> ADD II64 (OpImm (ImmInt amount)) (OpReg rsp)+ _ -> panic "x86_mkStackDeallocInstr"++i386_insert_ffrees+ :: [GenBasicBlock Instr]+ -> [GenBasicBlock Instr]++i386_insert_ffrees blocks+ | any (any is_G_instr) [ instrs | BasicBlock _ instrs <- blocks ]+ = map insertGFREEs blocks+ | otherwise+ = blocks+ where+ insertGFREEs (BasicBlock id insns)+ = BasicBlock id (insertBeforeNonlocalTransfers GFREE insns)++insertBeforeNonlocalTransfers :: Instr -> [Instr] -> [Instr]+insertBeforeNonlocalTransfers insert insns+ = foldr p [] insns+ where p insn r = case insn of+ CALL _ _ -> insert : insn : r+ JMP _ _ -> insert : insn : r+ JXX_GBL _ _ -> panic "insertBeforeNonlocalTransfers: cannot handle JXX_GBL"+ _ -> insn : r+++-- if you ever add a new FP insn to the fake x86 FP insn set,+-- you must update this too+is_G_instr :: Instr -> Bool+is_G_instr instr+ = case instr of+ GMOV{} -> True+ GLD{} -> True+ GST{} -> True+ GLDZ{} -> True+ GLD1{} -> True+ GFTOI{} -> True+ GDTOI{} -> True+ GITOF{} -> True+ GITOD{} -> True+ GDTOF{} -> True+ GADD{} -> True+ GDIV{} -> True+ GSUB{} -> True+ GMUL{} -> True+ GCMP{} -> True+ GABS{} -> True+ GNEG{} -> True+ GSQRT{} -> True+ GSIN{} -> True+ GCOS{} -> True+ GTAN{} -> True+ GFREE -> panic "is_G_instr: GFREE (!)"+ _ -> False+++--+-- Note [extra spill slots]+--+-- If the register allocator used more spill slots than we have+-- pre-allocated (rESERVED_C_STACK_BYTES), then we must allocate more+-- C stack space on entry and exit from this proc. Therefore we+-- insert a "sub $N, %rsp" at every entry point, and an "add $N, %rsp"+-- before every non-local jump.+--+-- This became necessary when the new codegen started bundling entire+-- functions together into one proc, because the register allocator+-- assigns a different stack slot to each virtual reg within a proc.+-- To avoid using so many slots we could also:+--+-- - split up the proc into connected components before code generator+--+-- - rename the virtual regs, so that we re-use vreg names and hence+-- stack slots for non-overlapping vregs.+--+-- Note that when a block is both a non-local entry point (with an+-- info table) and a local branch target, we have to split it into+-- two, like so:+--+-- <info table>+-- L:+-- <code>+--+-- becomes+--+-- <info table>+-- L:+-- subl $rsp, N+-- jmp Lnew+-- Lnew:+-- <code>+--+-- and all branches pointing to L are retargetted to point to Lnew.+-- Otherwise, we would repeat the $rsp adjustment for each branch to+-- L.+--+allocMoreStack+ :: Platform+ -> Int+ -> NatCmmDecl statics X86.Instr.Instr+ -> UniqSM (NatCmmDecl statics X86.Instr.Instr)++allocMoreStack _ _ top@(CmmData _ _) = return top+allocMoreStack platform slots proc@(CmmProc info lbl live (ListGraph code)) = do+ let entries = entryBlocks proc++ uniqs <- replicateM (length entries) getUniqueM++ let+ delta = ((x + stackAlign - 1) `quot` stackAlign) * stackAlign -- round up+ where x = slots * spillSlotSize platform -- sp delta++ alloc = mkStackAllocInstr platform delta+ dealloc = mkStackDeallocInstr platform delta++ new_blockmap :: LabelMap BlockId+ new_blockmap = mapFromList (zip entries (map mkBlockId uniqs))++ insert_stack_insns (BasicBlock id insns)+ | Just new_blockid <- mapLookup id new_blockmap+ = [ BasicBlock id [alloc, JXX ALWAYS new_blockid]+ , BasicBlock new_blockid block' ]+ | otherwise+ = [ BasicBlock id block' ]+ where+ block' = foldr insert_dealloc [] insns++ insert_dealloc insn r = case insn of+ JMP _ _ -> dealloc : insn : r+ JXX_GBL _ _ -> panic "insert_dealloc: cannot handle JXX_GBL"+ _other -> x86_patchJumpInstr insn retarget : r+ where retarget b = fromMaybe b (mapLookup b new_blockmap)++ new_code = concatMap insert_stack_insns code+ -- in+ return (CmmProc info lbl live (ListGraph new_code))+++data JumpDest = DestBlockId BlockId | DestImm Imm++getJumpDestBlockId :: JumpDest -> Maybe BlockId+getJumpDestBlockId (DestBlockId bid) = Just bid+getJumpDestBlockId _ = Nothing++canShortcut :: Instr -> Maybe JumpDest+canShortcut (JXX ALWAYS id) = Just (DestBlockId id)+canShortcut (JMP (OpImm imm) _) = Just (DestImm imm)+canShortcut _ = Nothing+++-- This helper shortcuts a sequence of branches.+-- The blockset helps avoid following cycles.+shortcutJump :: (BlockId -> Maybe JumpDest) -> Instr -> Instr+shortcutJump fn insn = shortcutJump' fn (setEmpty :: LabelSet) insn+ where shortcutJump' fn seen insn@(JXX cc id) =+ if setMember id seen then insn+ else case fn id of+ Nothing -> insn+ Just (DestBlockId id') -> shortcutJump' fn seen' (JXX cc id')+ Just (DestImm imm) -> shortcutJump' fn seen' (JXX_GBL cc imm)+ where seen' = setInsert id seen+ shortcutJump' _ _ other = other++-- Here because it knows about JumpDest+shortcutStatics :: (BlockId -> Maybe JumpDest) -> (Alignment, CmmStatics) -> (Alignment, CmmStatics)+shortcutStatics fn (align, Statics lbl statics)+ = (align, Statics lbl $ map (shortcutStatic fn) statics)+ -- we need to get the jump tables, so apply the mapping to the entries+ -- of a CmmData too.++shortcutLabel :: (BlockId -> Maybe JumpDest) -> CLabel -> CLabel+shortcutLabel fn lab+ | Just uq <- maybeAsmTemp lab = shortBlockId fn emptyUniqSet (mkBlockId uq)+ | otherwise = lab++shortcutStatic :: (BlockId -> Maybe JumpDest) -> CmmStatic -> CmmStatic+shortcutStatic fn (CmmStaticLit (CmmLabel lab))+ = CmmStaticLit (CmmLabel (shortcutLabel fn lab))+shortcutStatic fn (CmmStaticLit (CmmLabelDiffOff lbl1 lbl2 off))+ = CmmStaticLit (CmmLabelDiffOff (shortcutLabel fn lbl1) lbl2 off)+ -- slightly dodgy, we're ignoring the second label, but this+ -- works with the way we use CmmLabelDiffOff for jump tables now.+shortcutStatic _ other_static+ = other_static++shortBlockId+ :: (BlockId -> Maybe JumpDest)+ -> UniqSet Unique+ -> BlockId+ -> CLabel++shortBlockId fn seen blockid =+ case (elementOfUniqSet uq seen, fn blockid) of+ (True, _) -> mkAsmTempLabel uq+ (_, Nothing) -> mkAsmTempLabel uq+ (_, Just (DestBlockId blockid')) -> shortBlockId fn (addOneToUniqSet seen uq) blockid'+ (_, Just (DestImm (ImmCLbl lbl))) -> lbl+ (_, _other) -> panic "shortBlockId"+ where uq = getUnique blockid
+ nativeGen/X86/Ppr.hs view
@@ -0,0 +1,1303 @@+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+--+-- Pretty-printing assembly language+--+-- (c) The University of Glasgow 1993-2005+--+-----------------------------------------------------------------------------++{-# OPTIONS_GHC -fno-warn-orphans #-}+module X86.Ppr (+ pprNatCmmDecl,+ pprData,+ pprInstr,+ pprFormat,+ pprImm,+ pprDataItem,+)++where++#include "HsVersions.h"+#include "nativeGen/NCG.h"++import X86.Regs+import X86.Instr+import X86.Cond+import Instruction+import Format+import Reg+import PprBase+++import Hoopl+import BasicTypes (Alignment)+import DynFlags+import Cmm hiding (topInfoTable)+import CLabel+import Unique ( pprUniqueAlways, Uniquable(..) )+import Platform+import FastString+import Outputable++import Data.Word++import Data.Char++import Data.Bits++-- -----------------------------------------------------------------------------+-- Printing this stuff out+--+--+-- Note [Subsections Via Symbols]+--+-- If we are using the .subsections_via_symbols directive+-- (available on recent versions of Darwin),+-- we have to make sure that there is some kind of reference+-- from the entry code to a label on the _top_ of of the info table,+-- so that the linker will not think it is unreferenced and dead-strip+-- it. That's why the label is called a DeadStripPreventer (_dsp).+--+-- The LLVM code gen already creates `iTableSuf` symbols, where+-- the X86 would generate the DeadStripPreventer (_dsp) symbol.+-- Therefore all that is left for llvm code gen, is to ensure+-- that all the `iTableSuf` symbols are marked as used.+-- As of this writing the documentation regarding the+-- .subsections_via_symbols and -dead_strip can be found at+-- <https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/Assembler/040-Assembler_Directives/asm_directives.html#//apple_ref/doc/uid/TP30000823-TPXREF101>++pprNatCmmDecl :: NatCmmDecl (Alignment, CmmStatics) Instr -> SDoc+pprNatCmmDecl (CmmData section dats) =+ pprSectionAlign section $$ pprDatas dats++pprNatCmmDecl proc@(CmmProc top_info lbl _ (ListGraph blocks)) =+ sdocWithDynFlags $ \dflags ->+ case topInfoTable proc of+ Nothing ->+ case blocks of+ [] -> -- special case for split markers:+ pprLabel lbl+ blocks -> -- special case for code without info table:+ pprSectionAlign (Section Text lbl) $$+ pprLabel lbl $$ -- blocks guaranteed not null, so label needed+ vcat (map (pprBasicBlock top_info) blocks) $$+ (if debugLevel dflags > 0+ then ppr (mkAsmTempEndLabel lbl) <> char ':' else empty) $$+ pprSizeDecl lbl++ Just (Statics info_lbl _) ->+ sdocWithPlatform $ \platform ->+ pprSectionAlign (Section Text info_lbl) $$+ (if platformHasSubsectionsViaSymbols platform+ then ppr (mkDeadStripPreventer info_lbl) <> char ':'+ else empty) $$+ vcat (map (pprBasicBlock top_info) blocks) $$+ -- above: Even the first block gets a label, because with branch-chain+ -- elimination, it might be the target of a goto.+ (if platformHasSubsectionsViaSymbols platform+ then -- See Note [Subsections Via Symbols]+ text "\t.long "+ <+> ppr info_lbl+ <+> char '-'+ <+> ppr (mkDeadStripPreventer info_lbl)+ else empty) $$+ (if debugLevel dflags > 0+ then ppr (mkAsmTempEndLabel info_lbl) <> char ':' else empty) $$+ pprSizeDecl info_lbl++-- | Output the ELF .size directive.+pprSizeDecl :: CLabel -> SDoc+pprSizeDecl lbl+ = sdocWithPlatform $ \platform ->+ if osElfTarget (platformOS platform)+ then text "\t.size" <+> ppr lbl <> ptext (sLit ", .-") <> ppr lbl+ else empty++pprBasicBlock :: LabelMap CmmStatics -> NatBasicBlock Instr -> SDoc+pprBasicBlock info_env (BasicBlock blockid instrs)+ = sdocWithDynFlags $ \dflags ->+ maybe_infotable $$+ pprLabel asmLbl $$+ vcat (map pprInstr instrs) $$+ (if debugLevel dflags > 0+ then ppr (mkAsmTempEndLabel asmLbl) <> char ':' else empty)+ where+ asmLbl = mkAsmTempLabel (getUnique blockid)+ maybe_infotable = case mapLookup blockid info_env of+ Nothing -> empty+ Just (Statics info_lbl info) ->+ pprAlignForSection Text $$+ infoTableLoc $$+ vcat (map pprData info) $$+ pprLabel info_lbl+ -- Make sure the info table has the right .loc for the block+ -- coming right after it. See [Note: Info Offset]+ infoTableLoc = case instrs of+ (l@LOCATION{} : _) -> pprInstr l+ _other -> empty++pprDatas :: (Alignment, CmmStatics) -> SDoc+pprDatas (align, (Statics lbl dats))+ = vcat (pprAlign align : pprLabel lbl : map pprData dats)++pprData :: CmmStatic -> SDoc+pprData (CmmString str)+ = ptext (sLit "\t.asciz ") <> doubleQuotes (pprASCII str)++pprData (CmmUninitialised bytes)+ = sdocWithPlatform $ \platform ->+ if platformOS platform == OSDarwin then text ".space " <> int bytes+ else text ".skip " <> int bytes++pprData (CmmStaticLit lit) = pprDataItem lit++pprGloblDecl :: CLabel -> SDoc+pprGloblDecl lbl+ | not (externallyVisibleCLabel lbl) = empty+ | otherwise = text ".globl " <> ppr lbl++pprTypeAndSizeDecl :: CLabel -> SDoc+pprTypeAndSizeDecl lbl+ = sdocWithPlatform $ \platform ->+ if osElfTarget (platformOS platform) && externallyVisibleCLabel lbl+ then text ".type " <> ppr lbl <> ptext (sLit ", @object")+ else empty++pprLabel :: CLabel -> SDoc+pprLabel lbl = pprGloblDecl lbl+ $$ pprTypeAndSizeDecl lbl+ $$ (ppr lbl <> char ':')+++pprASCII :: [Word8] -> SDoc+pprASCII str+ = hcat (map (do1 . fromIntegral) str)+ where+ do1 :: Int -> SDoc+ do1 w | '\t' <- chr w = ptext (sLit "\\t")+ do1 w | '\n' <- chr w = ptext (sLit "\\n")+ do1 w | '"' <- chr w = ptext (sLit "\\\"")+ do1 w | '\\' <- chr w = ptext (sLit "\\\\")+ do1 w | isPrint (chr w) = char (chr w)+ do1 w | otherwise = char '\\' <> octal w++ octal :: Int -> SDoc+ octal w = int ((w `div` 64) `mod` 8)+ <> int ((w `div` 8) `mod` 8)+ <> int (w `mod` 8)++pprAlign :: Int -> SDoc+pprAlign bytes+ = sdocWithPlatform $ \platform ->+ text ".align " <> int (alignment platform)+ where+ alignment platform = if platformOS platform == OSDarwin+ then log2 bytes+ else bytes++ log2 :: Int -> Int -- cache the common ones+ log2 1 = 0+ log2 2 = 1+ log2 4 = 2+ log2 8 = 3+ log2 n = 1 + log2 (n `quot` 2)++-- -----------------------------------------------------------------------------+-- pprInstr: print an 'Instr'++instance Outputable Instr where+ ppr instr = pprInstr instr+++pprReg :: Format -> Reg -> SDoc+pprReg f r+ = case r of+ RegReal (RealRegSingle i) ->+ sdocWithPlatform $ \platform ->+ if target32Bit platform then ppr32_reg_no f i+ else ppr64_reg_no f i+ RegReal (RealRegPair _ _) -> panic "X86.Ppr: no reg pairs on this arch"+ RegVirtual (VirtualRegI u) -> text "%vI_" <> pprUniqueAlways u+ RegVirtual (VirtualRegHi u) -> text "%vHi_" <> pprUniqueAlways u+ RegVirtual (VirtualRegF u) -> text "%vF_" <> pprUniqueAlways u+ RegVirtual (VirtualRegD u) -> text "%vD_" <> pprUniqueAlways u+ RegVirtual (VirtualRegSSE u) -> text "%vSSE_" <> pprUniqueAlways u+ where+ ppr32_reg_no :: Format -> Int -> SDoc+ ppr32_reg_no II8 = ppr32_reg_byte+ ppr32_reg_no II16 = ppr32_reg_word+ ppr32_reg_no _ = ppr32_reg_long++ ppr32_reg_byte i = ptext+ (case i of {+ 0 -> sLit "%al"; 1 -> sLit "%bl";+ 2 -> sLit "%cl"; 3 -> sLit "%dl";+ _ -> sLit "very naughty I386 byte register"+ })++ ppr32_reg_word i = ptext+ (case i of {+ 0 -> sLit "%ax"; 1 -> sLit "%bx";+ 2 -> sLit "%cx"; 3 -> sLit "%dx";+ 4 -> sLit "%si"; 5 -> sLit "%di";+ 6 -> sLit "%bp"; 7 -> sLit "%sp";+ _ -> sLit "very naughty I386 word register"+ })++ ppr32_reg_long i = ptext+ (case i of {+ 0 -> sLit "%eax"; 1 -> sLit "%ebx";+ 2 -> sLit "%ecx"; 3 -> sLit "%edx";+ 4 -> sLit "%esi"; 5 -> sLit "%edi";+ 6 -> sLit "%ebp"; 7 -> sLit "%esp";+ _ -> ppr_reg_float i+ })++ ppr64_reg_no :: Format -> Int -> SDoc+ ppr64_reg_no II8 = ppr64_reg_byte+ ppr64_reg_no II16 = ppr64_reg_word+ ppr64_reg_no II32 = ppr64_reg_long+ ppr64_reg_no _ = ppr64_reg_quad++ ppr64_reg_byte i = ptext+ (case i of {+ 0 -> sLit "%al"; 1 -> sLit "%bl";+ 2 -> sLit "%cl"; 3 -> sLit "%dl";+ 4 -> sLit "%sil"; 5 -> sLit "%dil"; -- new 8-bit regs!+ 6 -> sLit "%bpl"; 7 -> sLit "%spl";+ 8 -> sLit "%r8b"; 9 -> sLit "%r9b";+ 10 -> sLit "%r10b"; 11 -> sLit "%r11b";+ 12 -> sLit "%r12b"; 13 -> sLit "%r13b";+ 14 -> sLit "%r14b"; 15 -> sLit "%r15b";+ _ -> sLit "very naughty x86_64 byte register"+ })++ ppr64_reg_word i = ptext+ (case i of {+ 0 -> sLit "%ax"; 1 -> sLit "%bx";+ 2 -> sLit "%cx"; 3 -> sLit "%dx";+ 4 -> sLit "%si"; 5 -> sLit "%di";+ 6 -> sLit "%bp"; 7 -> sLit "%sp";+ 8 -> sLit "%r8w"; 9 -> sLit "%r9w";+ 10 -> sLit "%r10w"; 11 -> sLit "%r11w";+ 12 -> sLit "%r12w"; 13 -> sLit "%r13w";+ 14 -> sLit "%r14w"; 15 -> sLit "%r15w";+ _ -> sLit "very naughty x86_64 word register"+ })++ ppr64_reg_long i = ptext+ (case i of {+ 0 -> sLit "%eax"; 1 -> sLit "%ebx";+ 2 -> sLit "%ecx"; 3 -> sLit "%edx";+ 4 -> sLit "%esi"; 5 -> sLit "%edi";+ 6 -> sLit "%ebp"; 7 -> sLit "%esp";+ 8 -> sLit "%r8d"; 9 -> sLit "%r9d";+ 10 -> sLit "%r10d"; 11 -> sLit "%r11d";+ 12 -> sLit "%r12d"; 13 -> sLit "%r13d";+ 14 -> sLit "%r14d"; 15 -> sLit "%r15d";+ _ -> sLit "very naughty x86_64 register"+ })++ ppr64_reg_quad i = ptext+ (case i of {+ 0 -> sLit "%rax"; 1 -> sLit "%rbx";+ 2 -> sLit "%rcx"; 3 -> sLit "%rdx";+ 4 -> sLit "%rsi"; 5 -> sLit "%rdi";+ 6 -> sLit "%rbp"; 7 -> sLit "%rsp";+ 8 -> sLit "%r8"; 9 -> sLit "%r9";+ 10 -> sLit "%r10"; 11 -> sLit "%r11";+ 12 -> sLit "%r12"; 13 -> sLit "%r13";+ 14 -> sLit "%r14"; 15 -> sLit "%r15";+ _ -> ppr_reg_float i+ })++ppr_reg_float :: Int -> LitString+ppr_reg_float i = case i of+ 16 -> sLit "%fake0"; 17 -> sLit "%fake1"+ 18 -> sLit "%fake2"; 19 -> sLit "%fake3"+ 20 -> sLit "%fake4"; 21 -> sLit "%fake5"+ 24 -> sLit "%xmm0"; 25 -> sLit "%xmm1"+ 26 -> sLit "%xmm2"; 27 -> sLit "%xmm3"+ 28 -> sLit "%xmm4"; 29 -> sLit "%xmm5"+ 30 -> sLit "%xmm6"; 31 -> sLit "%xmm7"+ 32 -> sLit "%xmm8"; 33 -> sLit "%xmm9"+ 34 -> sLit "%xmm10"; 35 -> sLit "%xmm11"+ 36 -> sLit "%xmm12"; 37 -> sLit "%xmm13"+ 38 -> sLit "%xmm14"; 39 -> sLit "%xmm15"+ _ -> sLit "very naughty x86 register"++pprFormat :: Format -> SDoc+pprFormat x+ = ptext (case x of+ II8 -> sLit "b"+ II16 -> sLit "w"+ II32 -> sLit "l"+ II64 -> sLit "q"+ FF32 -> sLit "ss" -- "scalar single-precision float" (SSE2)+ FF64 -> sLit "sd" -- "scalar double-precision float" (SSE2)+ FF80 -> sLit "t"+ )++pprFormat_x87 :: Format -> SDoc+pprFormat_x87 x+ = ptext $ case x of+ FF32 -> sLit "s"+ FF64 -> sLit "l"+ FF80 -> sLit "t"+ _ -> panic "X86.Ppr.pprFormat_x87"++pprCond :: Cond -> SDoc+pprCond c+ = ptext (case c of {+ GEU -> sLit "ae"; LU -> sLit "b";+ EQQ -> sLit "e"; GTT -> sLit "g";+ GE -> sLit "ge"; GU -> sLit "a";+ LTT -> sLit "l"; LE -> sLit "le";+ LEU -> sLit "be"; NE -> sLit "ne";+ NEG -> sLit "s"; POS -> sLit "ns";+ CARRY -> sLit "c"; OFLO -> sLit "o";+ PARITY -> sLit "p"; NOTPARITY -> sLit "np";+ ALWAYS -> sLit "mp"})+++pprImm :: Imm -> SDoc+pprImm (ImmInt i) = int i+pprImm (ImmInteger i) = integer i+pprImm (ImmCLbl l) = ppr l+pprImm (ImmIndex l i) = ppr l <> char '+' <> int i+pprImm (ImmLit s) = s++pprImm (ImmFloat _) = text "naughty float immediate"+pprImm (ImmDouble _) = text "naughty double immediate"++pprImm (ImmConstantSum a b) = pprImm a <> char '+' <> pprImm b+pprImm (ImmConstantDiff a b) = pprImm a <> char '-'+ <> lparen <> pprImm b <> rparen++++pprAddr :: AddrMode -> SDoc+pprAddr (ImmAddr imm off)+ = let pp_imm = pprImm imm+ in+ if (off == 0) then+ pp_imm+ else if (off < 0) then+ pp_imm <> int off+ else+ pp_imm <> char '+' <> int off++pprAddr (AddrBaseIndex base index displacement)+ = sdocWithPlatform $ \platform ->+ let+ pp_disp = ppr_disp displacement+ pp_off p = pp_disp <> char '(' <> p <> char ')'+ pp_reg r = pprReg (archWordFormat (target32Bit platform)) r+ in+ case (base, index) of+ (EABaseNone, EAIndexNone) -> pp_disp+ (EABaseReg b, EAIndexNone) -> pp_off (pp_reg b)+ (EABaseRip, EAIndexNone) -> pp_off (text "%rip")+ (EABaseNone, EAIndex r i) -> pp_off (comma <> pp_reg r <> comma <> int i)+ (EABaseReg b, EAIndex r i) -> pp_off (pp_reg b <> comma <> pp_reg r+ <> comma <> int i)+ _ -> panic "X86.Ppr.pprAddr: no match"++ where+ ppr_disp (ImmInt 0) = empty+ ppr_disp imm = pprImm imm++-- | Print section header and appropriate alignment for that section.+pprSectionAlign :: Section -> SDoc+pprSectionAlign (Section (OtherSection _) _) =+ panic "X86.Ppr.pprSectionAlign: unknown section"+pprSectionAlign sec@(Section seg _) =+ sdocWithPlatform $ \platform ->+ pprSectionHeader platform sec $$+ pprAlignForSection seg++-- | Print appropriate alignment for the given section type.+pprAlignForSection :: SectionType -> SDoc+pprAlignForSection seg =+ sdocWithPlatform $ \platform ->+ text ".align " <>+ case platformOS platform of+ -- Darwin: alignments are given as shifts.+ OSDarwin+ | target32Bit platform ->+ case seg of+ ReadOnlyData16 -> int 4+ CString -> int 1+ _ -> int 2+ | otherwise ->+ case seg of+ ReadOnlyData16 -> int 4+ CString -> int 1+ _ -> int 3+ -- Other: alignments are given as bytes.+ _+ | target32Bit platform ->+ case seg of+ Text -> text "4,0x90"+ ReadOnlyData16 -> int 16+ CString -> int 1+ _ -> int 4+ | otherwise ->+ case seg of+ ReadOnlyData16 -> int 16+ CString -> int 1+ _ -> int 8++pprDataItem :: CmmLit -> SDoc+pprDataItem lit = sdocWithDynFlags $ \dflags -> pprDataItem' dflags lit++pprDataItem' :: DynFlags -> CmmLit -> SDoc+pprDataItem' dflags lit+ = vcat (ppr_item (cmmTypeFormat $ cmmLitType dflags lit) lit)+ where+ platform = targetPlatform dflags+ imm = litToImm lit++ -- These seem to be common:+ ppr_item II8 _ = [text "\t.byte\t" <> pprImm imm]+ ppr_item II16 _ = [text "\t.word\t" <> pprImm imm]+ ppr_item II32 _ = [text "\t.long\t" <> pprImm imm]++ ppr_item FF32 (CmmFloat r _)+ = let bs = floatToBytes (fromRational r)+ in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs++ ppr_item FF64 (CmmFloat r _)+ = let bs = doubleToBytes (fromRational r)+ in map (\b -> text "\t.byte\t" <> pprImm (ImmInt b)) bs++ ppr_item II64 _+ = case platformOS platform of+ OSDarwin+ | target32Bit platform ->+ case lit of+ CmmInt x _ ->+ [text "\t.long\t"+ <> int (fromIntegral (fromIntegral x :: Word32)),+ text "\t.long\t"+ <> int (fromIntegral+ (fromIntegral (x `shiftR` 32) :: Word32))]+ _ -> panic "X86.Ppr.ppr_item: no match for II64"+ | otherwise ->+ [text "\t.quad\t" <> pprImm imm]+ _+ | target32Bit platform ->+ [text "\t.quad\t" <> pprImm imm]+ | otherwise ->+ -- x86_64: binutils can't handle the R_X86_64_PC64+ -- relocation type, which means we can't do+ -- pc-relative 64-bit addresses. Fortunately we're+ -- assuming the small memory model, in which all such+ -- offsets will fit into 32 bits, so we have to stick+ -- to 32-bit offset fields and modify the RTS+ -- appropriately+ --+ -- See Note [x86-64-relative] in includes/rts/storage/InfoTables.h+ --+ case lit of+ -- A relative relocation:+ CmmLabelDiffOff _ _ _ ->+ [text "\t.long\t" <> pprImm imm,+ text "\t.long\t0"]+ _ ->+ [text "\t.quad\t" <> pprImm imm]++ ppr_item _ _+ = panic "X86.Ppr.ppr_item: no match"+++asmComment :: SDoc -> SDoc+asmComment c = ifPprDebug $ text "# " <> c++pprInstr :: Instr -> SDoc++pprInstr (COMMENT s)+ = asmComment (ftext s)++pprInstr (LOCATION file line col _name)+ = text "\t.loc " <> ppr file <+> ppr line <+> ppr col++pprInstr (DELTA d)+ = asmComment $ text ("\tdelta = " ++ show d)++pprInstr (NEWBLOCK _)+ = panic "PprMach.pprInstr: NEWBLOCK"++pprInstr (UNWIND lbl d)+ = asmComment (text "\tunwind = " <> ppr d)+ $$ ppr lbl <> colon++pprInstr (LDATA _ _)+ = panic "PprMach.pprInstr: LDATA"++{-+pprInstr (SPILL reg slot)+ = hcat [+ text "\tSPILL",+ char ' ',+ pprUserReg reg,+ comma,+ text "SLOT" <> parens (int slot)]++pprInstr (RELOAD slot reg)+ = hcat [+ text "\tRELOAD",+ char ' ',+ text "SLOT" <> parens (int slot),+ comma,+ pprUserReg reg]+-}++-- Replace 'mov $0x0,%reg' by 'xor %reg,%reg', which is smaller and cheaper.+-- The code generator catches most of these already, but not all.+pprInstr (MOV format (OpImm (ImmInt 0)) dst@(OpReg _))+ = pprInstr (XOR format' dst dst)+ where format' = case format of+ II64 -> II32 -- 32-bit version is equivalent, and smaller+ _ -> format+pprInstr (MOV format src dst)+ = pprFormatOpOp (sLit "mov") format src dst++pprInstr (CMOV cc format src dst)+ = pprCondOpReg (sLit "cmov") format cc src dst++pprInstr (MOVZxL II32 src dst) = pprFormatOpOp (sLit "mov") II32 src dst+ -- 32-to-64 bit zero extension on x86_64 is accomplished by a simple+ -- movl. But we represent it as a MOVZxL instruction, because+ -- the reg alloc would tend to throw away a plain reg-to-reg+ -- move, and we still want it to do that.++pprInstr (MOVZxL formats src dst)+ = pprFormatOpOpCoerce (sLit "movz") formats II32 src dst+ -- zero-extension only needs to extend to 32 bits: on x86_64,+ -- the remaining zero-extension to 64 bits is automatic, and the 32-bit+ -- instruction is shorter.++pprInstr (MOVSxL formats src dst)+ = sdocWithPlatform $ \platform ->+ pprFormatOpOpCoerce (sLit "movs") formats (archWordFormat (target32Bit platform)) src dst++-- here we do some patching, since the physical registers are only set late+-- in the code generation.+pprInstr (LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) (EAIndex reg2 1) (ImmInt 0))) dst@(OpReg reg3))+ | reg1 == reg3+ = pprFormatOpOp (sLit "add") format (OpReg reg2) dst++pprInstr (LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) (EAIndex reg2 1) (ImmInt 0))) dst@(OpReg reg3))+ | reg2 == reg3+ = pprFormatOpOp (sLit "add") format (OpReg reg1) dst++pprInstr (LEA format (OpAddr (AddrBaseIndex (EABaseReg reg1) EAIndexNone displ)) dst@(OpReg reg3))+ | reg1 == reg3+ = pprInstr (ADD format (OpImm displ) dst)++pprInstr (LEA format src dst) = pprFormatOpOp (sLit "lea") format src dst++pprInstr (ADD format (OpImm (ImmInt (-1))) dst)+ = pprFormatOp (sLit "dec") format dst+pprInstr (ADD format (OpImm (ImmInt 1)) dst)+ = pprFormatOp (sLit "inc") format dst+pprInstr (ADD format src dst) = pprFormatOpOp (sLit "add") format src dst+pprInstr (ADC format src dst) = pprFormatOpOp (sLit "adc") format src dst+pprInstr (SUB format src dst) = pprFormatOpOp (sLit "sub") format src dst+pprInstr (SBB format src dst) = pprFormatOpOp (sLit "sbb") format src dst+pprInstr (IMUL format op1 op2) = pprFormatOpOp (sLit "imul") format op1 op2++pprInstr (ADD_CC format src dst)+ = pprFormatOpOp (sLit "add") format src dst+pprInstr (SUB_CC format src dst)+ = pprFormatOpOp (sLit "sub") format src dst++{- A hack. The Intel documentation says that "The two and three+ operand forms [of IMUL] may also be used with unsigned operands+ because the lower half of the product is the same regardless if+ (sic) the operands are signed or unsigned. The CF and OF flags,+ however, cannot be used to determine if the upper half of the+ result is non-zero." So there.+-}++-- Use a 32-bit instruction when possible as it saves a byte.+-- Notably, extracting the tag bits of a pointer has this form.+-- TODO: we could save a byte in a subsequent CMP instruction too,+-- but need something like a peephole pass for this+pprInstr (AND II64 src@(OpImm (ImmInteger mask)) dst)+ | 0 <= mask && mask < 0xffffffff+ = pprInstr (AND II32 src dst)+pprInstr (AND FF32 src dst) = pprOpOp (sLit "andps") FF32 src dst+pprInstr (AND FF64 src dst) = pprOpOp (sLit "andpd") FF64 src dst+pprInstr (AND format src dst) = pprFormatOpOp (sLit "and") format src dst+pprInstr (OR format src dst) = pprFormatOpOp (sLit "or") format src dst++pprInstr (XOR FF32 src dst) = pprOpOp (sLit "xorps") FF32 src dst+pprInstr (XOR FF64 src dst) = pprOpOp (sLit "xorpd") FF64 src dst+pprInstr (XOR format src dst) = pprFormatOpOp (sLit "xor") format src dst++pprInstr (POPCNT format src dst) = pprOpOp (sLit "popcnt") format src (OpReg dst)+pprInstr (BSF format src dst) = pprOpOp (sLit "bsf") format src (OpReg dst)+pprInstr (BSR format src dst) = pprOpOp (sLit "bsr") format src (OpReg dst)++pprInstr (PREFETCH NTA format src ) = pprFormatOp_ (sLit "prefetchnta") format src+pprInstr (PREFETCH Lvl0 format src) = pprFormatOp_ (sLit "prefetcht0") format src+pprInstr (PREFETCH Lvl1 format src) = pprFormatOp_ (sLit "prefetcht1") format src+pprInstr (PREFETCH Lvl2 format src) = pprFormatOp_ (sLit "prefetcht2") format src++pprInstr (NOT format op) = pprFormatOp (sLit "not") format op+pprInstr (BSWAP format op) = pprFormatOp (sLit "bswap") format (OpReg op)+pprInstr (NEGI format op) = pprFormatOp (sLit "neg") format op++pprInstr (SHL format src dst) = pprShift (sLit "shl") format src dst+pprInstr (SAR format src dst) = pprShift (sLit "sar") format src dst+pprInstr (SHR format src dst) = pprShift (sLit "shr") format src dst++pprInstr (BT format imm src) = pprFormatImmOp (sLit "bt") format imm src++pprInstr (CMP format src dst)+ | isFloatFormat format = pprFormatOpOp (sLit "ucomi") format src dst -- SSE2+ | otherwise = pprFormatOpOp (sLit "cmp") format src dst++pprInstr (TEST format src dst) = sdocWithPlatform $ \platform ->+ let format' = case (src,dst) of+ -- Match instructions like 'test $0x3,%esi' or 'test $0x7,%rbx'.+ -- We can replace them by equivalent, but smaller instructions+ -- by reducing the size of the immediate operand as far as possible.+ -- (We could handle masks larger than a single byte too,+ -- but it would complicate the code considerably+ -- and tag checks are by far the most common case.)+ -- The mask must have the high bit clear for this smaller encoding+ -- to be completely equivalent to the original; in particular so+ -- that the signed comparison condition bits are the same as they+ -- would be if doing a full word comparison. See Trac #13425.+ (OpImm (ImmInteger mask), OpReg dstReg)+ | 0 <= mask && mask < 128 -> minSizeOfReg platform dstReg+ _ -> format+ in pprFormatOpOp (sLit "test") format' src dst+ where+ minSizeOfReg platform (RegReal (RealRegSingle i))+ | target32Bit platform && i <= 3 = II8 -- al, bl, cl, dl+ | target32Bit platform && i <= 7 = II16 -- si, di, bp, sp+ | not (target32Bit platform) && i <= 15 = II8 -- al .. r15b+ minSizeOfReg _ _ = format -- other++pprInstr (PUSH format op) = pprFormatOp (sLit "push") format op+pprInstr (POP format op) = pprFormatOp (sLit "pop") format op++-- both unused (SDM):+-- pprInstr PUSHA = text "\tpushal"+-- pprInstr POPA = text "\tpopal"++pprInstr NOP = text "\tnop"+pprInstr (CLTD II32) = text "\tcltd"+pprInstr (CLTD II64) = text "\tcqto"++pprInstr (SETCC cond op) = pprCondInstr (sLit "set") cond (pprOperand II8 op)++pprInstr (JXX cond blockid)+ = pprCondInstr (sLit "j") cond (ppr lab)+ where lab = mkAsmTempLabel (getUnique blockid)++pprInstr (JXX_GBL cond imm) = pprCondInstr (sLit "j") cond (pprImm imm)++pprInstr (JMP (OpImm imm) _) = text "\tjmp " <> pprImm imm+pprInstr (JMP op _) = sdocWithPlatform $ \platform ->+ text "\tjmp *"+ <> pprOperand (archWordFormat (target32Bit platform)) op+pprInstr (JMP_TBL op _ _ _) = pprInstr (JMP op [])+pprInstr (CALL (Left imm) _) = text "\tcall " <> pprImm imm+pprInstr (CALL (Right reg) _) = sdocWithPlatform $ \platform ->+ text "\tcall *"+ <> pprReg (archWordFormat (target32Bit platform)) reg++pprInstr (IDIV fmt op) = pprFormatOp (sLit "idiv") fmt op+pprInstr (DIV fmt op) = pprFormatOp (sLit "div") fmt op+pprInstr (IMUL2 fmt op) = pprFormatOp (sLit "imul") fmt op++-- x86_64 only+pprInstr (MUL format op1 op2) = pprFormatOpOp (sLit "mul") format op1 op2+pprInstr (MUL2 format op) = pprFormatOp (sLit "mul") format op++pprInstr (FDIV format op1 op2) = pprFormatOpOp (sLit "div") format op1 op2++pprInstr (CVTSS2SD from to) = pprRegReg (sLit "cvtss2sd") from to+pprInstr (CVTSD2SS from to) = pprRegReg (sLit "cvtsd2ss") from to+pprInstr (CVTTSS2SIQ fmt from to) = pprFormatFormatOpReg (sLit "cvttss2si") FF32 fmt from to+pprInstr (CVTTSD2SIQ fmt from to) = pprFormatFormatOpReg (sLit "cvttsd2si") FF64 fmt from to+pprInstr (CVTSI2SS fmt from to) = pprFormatOpReg (sLit "cvtsi2ss") fmt from to+pprInstr (CVTSI2SD fmt from to) = pprFormatOpReg (sLit "cvtsi2sd") fmt from to++ -- FETCHGOT for PIC on ELF platforms+pprInstr (FETCHGOT reg)+ = vcat [ text "\tcall 1f",+ hcat [ text "1:\tpopl\t", pprReg II32 reg ],+ hcat [ text "\taddl\t$_GLOBAL_OFFSET_TABLE_+(.-1b), ",+ pprReg II32 reg ]+ ]++ -- FETCHPC for PIC on Darwin/x86+ -- get the instruction pointer into a register+ -- (Terminology note: the IP is called Program Counter on PPC,+ -- and it's a good thing to use the same name on both platforms)+pprInstr (FETCHPC reg)+ = vcat [ text "\tcall 1f",+ hcat [ text "1:\tpopl\t", pprReg II32 reg ]+ ]+++-- -----------------------------------------------------------------------------+-- i386 floating-point++-- Simulating a flat register set on the x86 FP stack is tricky.+-- you have to free %st(7) before pushing anything on the FP reg stack+-- so as to preclude the possibility of a FP stack overflow exception.+pprInstr g@(GMOV src dst)+ | src == dst+ = empty+ | otherwise+ = pprG g (hcat [gtab, gpush src 0, gsemi, gpop dst 1])++-- GLD fmt addr dst ==> FLDsz addr ; FSTP (dst+1)+pprInstr g@(GLD fmt addr dst)+ = pprG g (hcat [gtab, text "fld", pprFormat_x87 fmt, gsp,+ pprAddr addr, gsemi, gpop dst 1])++-- GST fmt src addr ==> FLD dst ; FSTPsz addr+pprInstr g@(GST fmt src addr)+ | src == fake0 && fmt /= FF80 -- fstt instruction doesn't exist+ = pprG g (hcat [gtab,+ text "fst", pprFormat_x87 fmt, gsp, pprAddr addr])+ | otherwise+ = pprG g (hcat [gtab, gpush src 0, gsemi,+ text "fstp", pprFormat_x87 fmt, gsp, pprAddr addr])++pprInstr g@(GLDZ dst)+ = pprG g (hcat [gtab, text "fldz ; ", gpop dst 1])+pprInstr g@(GLD1 dst)+ = pprG g (hcat [gtab, text "fld1 ; ", gpop dst 1])++pprInstr (GFTOI src dst)+ = pprInstr (GDTOI src dst)++pprInstr g@(GDTOI src dst)+ = pprG g (vcat [+ hcat [gtab, text "subl $8, %esp ; fnstcw 4(%esp)"],+ hcat [gtab, gpush src 0],+ hcat [gtab, text "movzwl 4(%esp), ", reg,+ text " ; orl $0xC00, ", reg],+ hcat [gtab, text "movl ", reg, text ", 0(%esp) ; fldcw 0(%esp)"],+ hcat [gtab, text "fistpl 0(%esp)"],+ hcat [gtab, text "fldcw 4(%esp) ; movl 0(%esp), ", reg],+ hcat [gtab, text "addl $8, %esp"]+ ])+ where+ reg = pprReg II32 dst++pprInstr (GITOF src dst)+ = pprInstr (GITOD src dst)++pprInstr g@(GITOD src dst)+ = pprG g (hcat [gtab, text "pushl ", pprReg II32 src,+ text " ; fildl (%esp) ; ",+ gpop dst 1, text " ; addl $4,%esp"])++pprInstr g@(GDTOF src dst)+ = pprG g (vcat [gtab <> gpush src 0,+ gtab <> text "subl $4,%esp ; fstps (%esp) ; flds (%esp) ; addl $4,%esp ;",+ gtab <> gpop dst 1])++{- Gruesome swamp follows. If you're unfortunate enough to have ventured+ this far into the jungle AND you give a Rat's Ass (tm) what's going+ on, here's the deal. Generate code to do a floating point comparison+ of src1 and src2, of kind cond, and set the Zero flag if true.++ The complications are to do with handling NaNs correctly. We want the+ property that if either argument is NaN, then the result of the+ comparison is False ... except if we're comparing for inequality,+ in which case the answer is True.++ Here's how the general (non-inequality) case works. As an+ example, consider generating the an equality test:++ pushl %eax -- we need to mess with this+ <get src1 to top of FPU stack>+ fcomp <src2 location in FPU stack> and pop pushed src1+ -- Result of comparison is in FPU Status Register bits+ -- C3 C2 and C0+ fstsw %ax -- Move FPU Status Reg to %ax+ sahf -- move C3 C2 C0 from %ax to integer flag reg+ -- now the serious magic begins+ setpo %ah -- %ah = if comparable(neither arg was NaN) then 1 else 0+ sete %al -- %al = if arg1 == arg2 then 1 else 0+ andb %ah,%al -- %al &= %ah+ -- so %al == 1 iff (comparable && same); else it holds 0+ decb %al -- %al == 0, ZeroFlag=1 iff (comparable && same);+ else %al == 0xFF, ZeroFlag=0+ -- the zero flag is now set as we desire.+ popl %eax++ The special case of inequality differs thusly:++ setpe %ah -- %ah = if incomparable(either arg was NaN) then 1 else 0+ setne %al -- %al = if arg1 /= arg2 then 1 else 0+ orb %ah,%al -- %al = if (incomparable || different) then 1 else 0+ decb %al -- if (incomparable || different) then (%al == 0, ZF=1)+ else (%al == 0xFF, ZF=0)+-}+pprInstr g@(GCMP cond src1 src2)+ | case cond of { NE -> True; _ -> False }+ = pprG g (vcat [+ hcat [gtab, text "pushl %eax ; ",gpush src1 0],+ hcat [gtab, text "fcomp ", greg src2 1,+ text "; fstsw %ax ; sahf ; setpe %ah"],+ hcat [gtab, text "setne %al ; ",+ text "orb %ah,%al ; decb %al ; popl %eax"]+ ])+ | otherwise+ = pprG g (vcat [+ hcat [gtab, text "pushl %eax ; ",gpush src1 0],+ hcat [gtab, text "fcomp ", greg src2 1,+ text "; fstsw %ax ; sahf ; setpo %ah"],+ hcat [gtab, text "set", pprCond (fix_FP_cond cond), text " %al ; ",+ text "andb %ah,%al ; decb %al ; popl %eax"]+ ])+ where+ {- On the 486, the flags set by FP compare are the unsigned ones!+ (This looks like a HACK to me. WDP 96/03)+ -}+ fix_FP_cond :: Cond -> Cond+ fix_FP_cond GE = GEU+ fix_FP_cond GTT = GU+ fix_FP_cond LTT = LU+ fix_FP_cond LE = LEU+ fix_FP_cond EQQ = EQQ+ fix_FP_cond NE = NE+ fix_FP_cond _ = panic "X86.Ppr.fix_FP_cond: no match"+ -- there should be no others+++pprInstr g@(GABS _ src dst)+ = pprG g (hcat [gtab, gpush src 0, text " ; fabs ; ", gpop dst 1])++pprInstr g@(GNEG _ src dst)+ = pprG g (hcat [gtab, gpush src 0, text " ; fchs ; ", gpop dst 1])++pprInstr g@(GSQRT fmt src dst)+ = pprG g (hcat [gtab, gpush src 0, text " ; fsqrt"] $$+ hcat [gtab, gcoerceto fmt, gpop dst 1])++pprInstr g@(GSIN fmt l1 l2 src dst)+ = pprG g (pprTrigOp "fsin" False l1 l2 src dst fmt)++pprInstr g@(GCOS fmt l1 l2 src dst)+ = pprG g (pprTrigOp "fcos" False l1 l2 src dst fmt)++pprInstr g@(GTAN fmt l1 l2 src dst)+ = pprG g (pprTrigOp "fptan" True l1 l2 src dst fmt)++-- In the translations for GADD, GMUL, GSUB and GDIV,+-- the first two cases are mere optimisations. The otherwise clause+-- generates correct code under all circumstances.++pprInstr g@(GADD _ src1 src2 dst)+ | src1 == dst+ = pprG g (text "\t#GADD-xxxcase1" $$+ hcat [gtab, gpush src2 0,+ text " ; faddp %st(0),", greg src1 1])+ | src2 == dst+ = pprG g (text "\t#GADD-xxxcase2" $$+ hcat [gtab, gpush src1 0,+ text " ; faddp %st(0),", greg src2 1])+ | otherwise+ = pprG g (hcat [gtab, gpush src1 0,+ text " ; fadd ", greg src2 1, text ",%st(0)",+ gsemi, gpop dst 1])+++pprInstr g@(GMUL _ src1 src2 dst)+ | src1 == dst+ = pprG g (text "\t#GMUL-xxxcase1" $$+ hcat [gtab, gpush src2 0,+ text " ; fmulp %st(0),", greg src1 1])+ | src2 == dst+ = pprG g (text "\t#GMUL-xxxcase2" $$+ hcat [gtab, gpush src1 0,+ text " ; fmulp %st(0),", greg src2 1])+ | otherwise+ = pprG g (hcat [gtab, gpush src1 0,+ text " ; fmul ", greg src2 1, text ",%st(0)",+ gsemi, gpop dst 1])+++pprInstr g@(GSUB _ src1 src2 dst)+ | src1 == dst+ = pprG g (text "\t#GSUB-xxxcase1" $$+ hcat [gtab, gpush src2 0,+ text " ; fsubrp %st(0),", greg src1 1])+ | src2 == dst+ = pprG g (text "\t#GSUB-xxxcase2" $$+ hcat [gtab, gpush src1 0,+ text " ; fsubp %st(0),", greg src2 1])+ | otherwise+ = pprG g (hcat [gtab, gpush src1 0,+ text " ; fsub ", greg src2 1, text ",%st(0)",+ gsemi, gpop dst 1])+++pprInstr g@(GDIV _ src1 src2 dst)+ | src1 == dst+ = pprG g (text "\t#GDIV-xxxcase1" $$+ hcat [gtab, gpush src2 0,+ text " ; fdivrp %st(0),", greg src1 1])+ | src2 == dst+ = pprG g (text "\t#GDIV-xxxcase2" $$+ hcat [gtab, gpush src1 0,+ text " ; fdivp %st(0),", greg src2 1])+ | otherwise+ = pprG g (hcat [gtab, gpush src1 0,+ text " ; fdiv ", greg src2 1, text ",%st(0)",+ gsemi, gpop dst 1])+++pprInstr GFREE+ = vcat [ text "\tffree %st(0) ;ffree %st(1) ;ffree %st(2) ;ffree %st(3)",+ text "\tffree %st(4) ;ffree %st(5)"+ ]++-- Atomics++pprInstr (LOCK i) = text "\tlock" $$ pprInstr i++pprInstr MFENCE = text "\tmfence"++pprInstr (XADD format src dst) = pprFormatOpOp (sLit "xadd") format src dst++pprInstr (CMPXCHG format src dst)+ = pprFormatOpOp (sLit "cmpxchg") format src dst++pprInstr _+ = panic "X86.Ppr.pprInstr: no match"+++pprTrigOp :: String -> Bool -> CLabel -> CLabel+ -> Reg -> Reg -> Format -> SDoc+pprTrigOp op -- fsin, fcos or fptan+ isTan -- we need a couple of extra steps if we're doing tan+ l1 l2 -- internal labels for us to use+ src dst fmt+ = -- We'll be needing %eax later on+ hcat [gtab, text "pushl %eax;"] $$+ -- tan is going to use an extra space on the FP stack+ (if isTan then hcat [gtab, text "ffree %st(6)"] else empty) $$+ -- First put the value in %st(0) and try to apply the op to it+ hcat [gpush src 0, text ("; " ++ op)] $$+ -- Now look to see if C2 was set (overflow, |value| >= 2^63)+ hcat [gtab, text "fnstsw %ax"] $$+ hcat [gtab, text "test $0x400,%eax"] $$+ -- If we were in bounds then jump to the end+ hcat [gtab, text "je " <> ppr l1] $$+ -- Otherwise we need to shrink the value. Start by+ -- loading pi, doubleing it (by adding it to itself),+ -- and then swapping pi with the value, so the value we+ -- want to apply op to is in %st(0) again+ hcat [gtab, text "ffree %st(7); fldpi"] $$+ hcat [gtab, text "fadd %st(0),%st"] $$+ hcat [gtab, text "fxch %st(1)"] $$+ -- Now we have a loop in which we make the value smaller,+ -- see if it's small enough, and loop if not+ (ppr l2 <> char ':') $$+ hcat [gtab, text "fprem1"] $$+ -- My Debian libc uses fstsw here for the tan code, but I can't+ -- see any reason why it should need to be different for tan.+ hcat [gtab, text "fnstsw %ax"] $$+ hcat [gtab, text "test $0x400,%eax"] $$+ hcat [gtab, text "jne " <> ppr l2] $$+ hcat [gtab, text "fstp %st(1)"] $$+ hcat [gtab, text op] $$+ (ppr l1 <> char ':') $$+ -- Pop the 1.0 tan gave us+ (if isTan then hcat [gtab, text "fstp %st(0)"] else empty) $$+ -- Restore %eax+ hcat [gtab, text "popl %eax;"] $$+ -- And finally make the result the right size+ hcat [gtab, gcoerceto fmt, gpop dst 1]++--------------------------++-- coerce %st(0) to the specified size+gcoerceto :: Format -> SDoc+gcoerceto FF64 = empty+gcoerceto FF32 = empty --text "subl $4,%esp ; fstps (%esp) ; flds (%esp) ; addl $4,%esp ; "+gcoerceto _ = panic "X86.Ppr.gcoerceto: no match"++gpush :: Reg -> RegNo -> SDoc+gpush reg offset+ = hcat [text "fld ", greg reg offset]++gpop :: Reg -> RegNo -> SDoc+gpop reg offset+ = hcat [text "fstp ", greg reg offset]++greg :: Reg -> RegNo -> SDoc+greg reg offset = text "%st(" <> int (gregno reg - firstfake+offset) <> char ')'++gsemi :: SDoc+gsemi = text " ; "++gtab :: SDoc+gtab = char '\t'++gsp :: SDoc+gsp = char ' '++gregno :: Reg -> RegNo+gregno (RegReal (RealRegSingle i)) = i+gregno _ = --pprPanic "gregno" (ppr other)+ 999 -- bogus; only needed for debug printing++pprG :: Instr -> SDoc -> SDoc+pprG fake actual+ = (char '#' <> pprGInstr fake) $$ actual+++pprGInstr :: Instr -> SDoc+pprGInstr (GMOV src dst) = pprFormatRegReg (sLit "gmov") FF64 src dst+pprGInstr (GLD fmt src dst) = pprFormatAddrReg (sLit "gld") fmt src dst+pprGInstr (GST fmt src dst) = pprFormatRegAddr (sLit "gst") fmt src dst++pprGInstr (GLDZ dst) = pprFormatReg (sLit "gldz") FF64 dst+pprGInstr (GLD1 dst) = pprFormatReg (sLit "gld1") FF64 dst++pprGInstr (GFTOI src dst) = pprFormatFormatRegReg (sLit "gftoi") FF32 II32 src dst+pprGInstr (GDTOI src dst) = pprFormatFormatRegReg (sLit "gdtoi") FF64 II32 src dst++pprGInstr (GITOF src dst) = pprFormatFormatRegReg (sLit "gitof") II32 FF32 src dst+pprGInstr (GITOD src dst) = pprFormatFormatRegReg (sLit "gitod") II32 FF64 src dst+pprGInstr (GDTOF src dst) = pprFormatFormatRegReg (sLit "gdtof") FF64 FF32 src dst++pprGInstr (GCMP co src dst) = pprCondRegReg (sLit "gcmp_") FF64 co src dst+pprGInstr (GABS fmt src dst) = pprFormatRegReg (sLit "gabs") fmt src dst+pprGInstr (GNEG fmt src dst) = pprFormatRegReg (sLit "gneg") fmt src dst+pprGInstr (GSQRT fmt src dst) = pprFormatRegReg (sLit "gsqrt") fmt src dst+pprGInstr (GSIN fmt _ _ src dst) = pprFormatRegReg (sLit "gsin") fmt src dst+pprGInstr (GCOS fmt _ _ src dst) = pprFormatRegReg (sLit "gcos") fmt src dst+pprGInstr (GTAN fmt _ _ src dst) = pprFormatRegReg (sLit "gtan") fmt src dst++pprGInstr (GADD fmt src1 src2 dst) = pprFormatRegRegReg (sLit "gadd") fmt src1 src2 dst+pprGInstr (GSUB fmt src1 src2 dst) = pprFormatRegRegReg (sLit "gsub") fmt src1 src2 dst+pprGInstr (GMUL fmt src1 src2 dst) = pprFormatRegRegReg (sLit "gmul") fmt src1 src2 dst+pprGInstr (GDIV fmt src1 src2 dst) = pprFormatRegRegReg (sLit "gdiv") fmt src1 src2 dst++pprGInstr _ = panic "X86.Ppr.pprGInstr: no match"++pprDollImm :: Imm -> SDoc+pprDollImm i = text "$" <> pprImm i+++pprOperand :: Format -> Operand -> SDoc+pprOperand f (OpReg r) = pprReg f r+pprOperand _ (OpImm i) = pprDollImm i+pprOperand _ (OpAddr ea) = pprAddr ea+++pprMnemonic_ :: LitString -> SDoc+pprMnemonic_ name =+ char '\t' <> ptext name <> space+++pprMnemonic :: LitString -> Format -> SDoc+pprMnemonic name format =+ char '\t' <> ptext name <> pprFormat format <> space+++pprFormatImmOp :: LitString -> Format -> Imm -> Operand -> SDoc+pprFormatImmOp name format imm op1+ = hcat [+ pprMnemonic name format,+ char '$',+ pprImm imm,+ comma,+ pprOperand format op1+ ]+++pprFormatOp_ :: LitString -> Format -> Operand -> SDoc+pprFormatOp_ name format op1+ = hcat [+ pprMnemonic_ name ,+ pprOperand format op1+ ]++pprFormatOp :: LitString -> Format -> Operand -> SDoc+pprFormatOp name format op1+ = hcat [+ pprMnemonic name format,+ pprOperand format op1+ ]+++pprFormatOpOp :: LitString -> Format -> Operand -> Operand -> SDoc+pprFormatOpOp name format op1 op2+ = hcat [+ pprMnemonic name format,+ pprOperand format op1,+ comma,+ pprOperand format op2+ ]+++pprOpOp :: LitString -> Format -> Operand -> Operand -> SDoc+pprOpOp name format op1 op2+ = hcat [+ pprMnemonic_ name,+ pprOperand format op1,+ comma,+ pprOperand format op2+ ]+++pprFormatReg :: LitString -> Format -> Reg -> SDoc+pprFormatReg name format reg1+ = hcat [+ pprMnemonic name format,+ pprReg format reg1+ ]+++pprFormatRegReg :: LitString -> Format -> Reg -> Reg -> SDoc+pprFormatRegReg name format reg1 reg2+ = hcat [+ pprMnemonic name format,+ pprReg format reg1,+ comma,+ pprReg format reg2+ ]+++pprRegReg :: LitString -> Reg -> Reg -> SDoc+pprRegReg name reg1 reg2+ = sdocWithPlatform $ \platform ->+ hcat [+ pprMnemonic_ name,+ pprReg (archWordFormat (target32Bit platform)) reg1,+ comma,+ pprReg (archWordFormat (target32Bit platform)) reg2+ ]+++pprFormatOpReg :: LitString -> Format -> Operand -> Reg -> SDoc+pprFormatOpReg name format op1 reg2+ = sdocWithPlatform $ \platform ->+ hcat [+ pprMnemonic name format,+ pprOperand format op1,+ comma,+ pprReg (archWordFormat (target32Bit platform)) reg2+ ]++pprCondOpReg :: LitString -> Format -> Cond -> Operand -> Reg -> SDoc+pprCondOpReg name format cond op1 reg2+ = hcat [+ char '\t',+ ptext name,+ pprCond cond,+ space,+ pprOperand format op1,+ comma,+ pprReg format reg2+ ]++pprCondRegReg :: LitString -> Format -> Cond -> Reg -> Reg -> SDoc+pprCondRegReg name format cond reg1 reg2+ = hcat [+ char '\t',+ ptext name,+ pprCond cond,+ space,+ pprReg format reg1,+ comma,+ pprReg format reg2+ ]++pprFormatFormatRegReg :: LitString -> Format -> Format -> Reg -> Reg -> SDoc+pprFormatFormatRegReg name format1 format2 reg1 reg2+ = hcat [+ char '\t',+ ptext name,+ pprFormat format1,+ pprFormat format2,+ space,+ pprReg format1 reg1,+ comma,+ pprReg format2 reg2+ ]++pprFormatFormatOpReg :: LitString -> Format -> Format -> Operand -> Reg -> SDoc+pprFormatFormatOpReg name format1 format2 op1 reg2+ = hcat [+ pprMnemonic name format2,+ pprOperand format1 op1,+ comma,+ pprReg format2 reg2+ ]++pprFormatRegRegReg :: LitString -> Format -> Reg -> Reg -> Reg -> SDoc+pprFormatRegRegReg name format reg1 reg2 reg3+ = hcat [+ pprMnemonic name format,+ pprReg format reg1,+ comma,+ pprReg format reg2,+ comma,+ pprReg format reg3+ ]+++pprFormatAddrReg :: LitString -> Format -> AddrMode -> Reg -> SDoc+pprFormatAddrReg name format op dst+ = hcat [+ pprMnemonic name format,+ pprAddr op,+ comma,+ pprReg format dst+ ]+++pprFormatRegAddr :: LitString -> Format -> Reg -> AddrMode -> SDoc+pprFormatRegAddr name format src op+ = hcat [+ pprMnemonic name format,+ pprReg format src,+ comma,+ pprAddr op+ ]+++pprShift :: LitString -> Format -> Operand -> Operand -> SDoc+pprShift name format src dest+ = hcat [+ pprMnemonic name format,+ pprOperand II8 src, -- src is 8-bit sized+ comma,+ pprOperand format dest+ ]+++pprFormatOpOpCoerce :: LitString -> Format -> Format -> Operand -> Operand -> SDoc+pprFormatOpOpCoerce name format1 format2 op1 op2+ = hcat [ char '\t', ptext name, pprFormat format1, pprFormat format2, space,+ pprOperand format1 op1,+ comma,+ pprOperand format2 op2+ ]+++pprCondInstr :: LitString -> Cond -> SDoc -> SDoc+pprCondInstr name cond arg+ = hcat [ char '\t', ptext name, pprCond cond, space, arg]+
+ nativeGen/X86/RegInfo.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE CPP #-}+module X86.RegInfo (+ mkVirtualReg,+ regDotColor+)++where++#include "nativeGen/NCG.h"+#include "HsVersions.h"++import Format+import Reg++import Outputable+import Platform+import Unique++import UniqFM+import X86.Regs+++mkVirtualReg :: Unique -> Format -> VirtualReg+mkVirtualReg u format+ = case format of+ FF32 -> VirtualRegSSE u+ FF64 -> VirtualRegSSE u+ FF80 -> VirtualRegD u+ _other -> VirtualRegI u++regDotColor :: Platform -> RealReg -> SDoc+regDotColor platform reg+ = let Just str = lookupUFM (regColors platform) reg+ in text str++regColors :: Platform -> UniqFM [Char]+regColors platform = listToUFM (normalRegColors platform ++ fpRegColors)++normalRegColors :: Platform -> [(Reg,String)]+normalRegColors platform+ | target32Bit platform = [ (eax, "#00ff00")+ , (ebx, "#0000ff")+ , (ecx, "#00ffff")+ , (edx, "#0080ff") ]+ | otherwise = [ (rax, "#00ff00"), (eax, "#00ff00")+ , (rbx, "#0000ff"), (ebx, "#0000ff")+ , (rcx, "#00ffff"), (ecx, "#00ffff")+ , (rdx, "#0080ff"), (edx, "#00ffff")+ , (r8, "#00ff80")+ , (r9, "#008080")+ , (r10, "#0040ff")+ , (r11, "#00ff40")+ , (r12, "#008040")+ , (r13, "#004080")+ , (r14, "#004040")+ , (r15, "#002080") ]++fpRegColors :: [(Reg,String)]+fpRegColors =+ [ (fake0, "#ff00ff")+ , (fake1, "#ff00aa")+ , (fake2, "#aa00ff")+ , (fake3, "#aa00aa")+ , (fake4, "#ff0055")+ , (fake5, "#5500ff") ]++ ++ zip (map regSingle [24..39]) (repeat "red")
+ nativeGen/X86/Regs.hs view
@@ -0,0 +1,449 @@+{-# LANGUAGE CPP #-}++module X86.Regs (+ -- squeese functions for the graph allocator+ virtualRegSqueeze,+ realRegSqueeze,++ -- immediates+ Imm(..),+ strImmLit,+ litToImm,++ -- addressing modes+ AddrMode(..),+ addrOffset,++ -- registers+ spRel,+ argRegs,+ allArgRegs,+ allIntArgRegs,+ callClobberedRegs,+ instrClobberedRegs,+ allMachRegNos,+ classOfRealReg,+ showReg,++ -- machine specific+ EABase(..), EAIndex(..), addrModeRegs,++ eax, ebx, ecx, edx, esi, edi, ebp, esp,+ fake0, fake1, fake2, fake3, fake4, fake5, firstfake,++ rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp,+ r8, r9, r10, r11, r12, r13, r14, r15,+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,+ xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15,+ xmm,++ ripRel,+ allFPArgRegs,++ allocatableRegs+)++where++#include "nativeGen/NCG.h"+#include "HsVersions.h"++import CodeGen.Platform+import Reg+import RegClass++import Cmm+import CLabel ( CLabel )+import DynFlags+import Outputable+import Platform++-- | regSqueeze_class reg+-- Calculuate the maximum number of register colors that could be+-- denied to a node of this class due to having this reg+-- as a neighbour.+--+{-# INLINE virtualRegSqueeze #-}+virtualRegSqueeze :: RegClass -> VirtualReg -> Int++virtualRegSqueeze cls vr+ = case cls of+ RcInteger+ -> case vr of+ VirtualRegI{} -> 1+ VirtualRegHi{} -> 1+ _other -> 0++ RcDouble+ -> case vr of+ VirtualRegD{} -> 1+ VirtualRegF{} -> 0+ _other -> 0++ RcDoubleSSE+ -> case vr of+ VirtualRegSSE{} -> 1+ _other -> 0++ _other -> 0++{-# INLINE realRegSqueeze #-}+realRegSqueeze :: RegClass -> RealReg -> Int+realRegSqueeze cls rr+ = case cls of+ RcInteger+ -> case rr of+ RealRegSingle regNo+ | regNo < firstfake -> 1+ | otherwise -> 0++ RealRegPair{} -> 0++ RcDouble+ -> case rr of+ RealRegSingle regNo+ | regNo >= firstfake && regNo <= lastfake -> 1+ | otherwise -> 0++ RealRegPair{} -> 0++ RcDoubleSSE+ -> case rr of+ RealRegSingle regNo | regNo >= firstxmm -> 1+ _otherwise -> 0++ _other -> 0++-- -----------------------------------------------------------------------------+-- Immediates++data Imm+ = ImmInt Int+ | ImmInteger Integer -- Sigh.+ | ImmCLbl CLabel -- AbstractC Label (with baggage)+ | ImmLit SDoc -- Simple string+ | ImmIndex CLabel Int+ | ImmFloat Rational+ | ImmDouble Rational+ | ImmConstantSum Imm Imm+ | ImmConstantDiff Imm Imm+++strImmLit :: String -> Imm+strImmLit s = ImmLit (text s)+++litToImm :: CmmLit -> Imm+litToImm (CmmInt i w) = ImmInteger (narrowS w i)+ -- narrow to the width: a CmmInt might be out of+ -- range, but we assume that ImmInteger only contains+ -- in-range values. A signed value should be fine here.+litToImm (CmmFloat f W32) = ImmFloat f+litToImm (CmmFloat f W64) = ImmDouble f+litToImm (CmmLabel l) = ImmCLbl l+litToImm (CmmLabelOff l off) = ImmIndex l off+litToImm (CmmLabelDiffOff l1 l2 off)+ = ImmConstantSum+ (ImmConstantDiff (ImmCLbl l1) (ImmCLbl l2))+ (ImmInt off)+litToImm _ = panic "X86.Regs.litToImm: no match"++-- addressing modes ------------------------------------------------------------++data AddrMode+ = AddrBaseIndex EABase EAIndex Displacement+ | ImmAddr Imm Int++data EABase = EABaseNone | EABaseReg Reg | EABaseRip+data EAIndex = EAIndexNone | EAIndex Reg Int+type Displacement = Imm+++addrOffset :: AddrMode -> Int -> Maybe AddrMode+addrOffset addr off+ = case addr of+ ImmAddr i off0 -> Just (ImmAddr i (off0 + off))++ AddrBaseIndex r i (ImmInt n) -> Just (AddrBaseIndex r i (ImmInt (n + off)))+ AddrBaseIndex r i (ImmInteger n)+ -> Just (AddrBaseIndex r i (ImmInt (fromInteger (n + toInteger off))))++ AddrBaseIndex r i (ImmCLbl lbl)+ -> Just (AddrBaseIndex r i (ImmIndex lbl off))++ AddrBaseIndex r i (ImmIndex lbl ix)+ -> Just (AddrBaseIndex r i (ImmIndex lbl (ix+off)))++ _ -> Nothing -- in theory, shouldn't happen+++addrModeRegs :: AddrMode -> [Reg]+addrModeRegs (AddrBaseIndex b i _) = b_regs ++ i_regs+ where+ b_regs = case b of { EABaseReg r -> [r]; _ -> [] }+ i_regs = case i of { EAIndex r _ -> [r]; _ -> [] }+addrModeRegs _ = []+++-- registers -------------------------------------------------------------------++-- @spRel@ gives us a stack relative addressing mode for volatile+-- temporaries and for excess call arguments. @fpRel@, where+-- applicable, is the same but for the frame pointer.+++spRel :: DynFlags+ -> Int -- ^ desired stack offset in bytes, positive or negative+ -> AddrMode+spRel dflags n+ | target32Bit (targetPlatform dflags)+ = AddrBaseIndex (EABaseReg esp) EAIndexNone (ImmInt n)+ | otherwise+ = AddrBaseIndex (EABaseReg rsp) EAIndexNone (ImmInt n)++-- The register numbers must fit into 32 bits on x86, so that we can+-- use a Word32 to represent the set of free registers in the register+-- allocator.++firstfake, lastfake :: RegNo+firstfake = 16+lastfake = 21++firstxmm :: RegNo+firstxmm = 24++lastxmm :: Platform -> RegNo+lastxmm platform+ | target32Bit platform = 31+ | otherwise = 39++lastint :: Platform -> RegNo+lastint platform+ | target32Bit platform = 7 -- not %r8..%r15+ | otherwise = 15++intregnos :: Platform -> [RegNo]+intregnos platform = [0 .. lastint platform]++fakeregnos :: [RegNo]+fakeregnos = [firstfake .. lastfake]++xmmregnos :: Platform -> [RegNo]+xmmregnos platform = [firstxmm .. lastxmm platform]++floatregnos :: Platform -> [RegNo]+floatregnos platform = fakeregnos ++ xmmregnos platform+++-- argRegs is the set of regs which are read for an n-argument call to C.+-- For archs which pass all args on the stack (x86), is empty.+-- Sparc passes up to the first 6 args in regs.+argRegs :: RegNo -> [Reg]+argRegs _ = panic "MachRegs.argRegs(x86): should not be used!"++-- | The complete set of machine registers.+allMachRegNos :: Platform -> [RegNo]+allMachRegNos platform = intregnos platform ++ floatregnos platform++-- | Take the class of a register.+{-# INLINE classOfRealReg #-}+classOfRealReg :: Platform -> RealReg -> RegClass+-- On x86, we might want to have an 8-bit RegClass, which would+-- contain just regs 1-4 (the others don't have 8-bit versions).+-- However, we can get away without this at the moment because the+-- only allocatable integer regs are also 8-bit compatible (1, 3, 4).+classOfRealReg platform reg+ = case reg of+ RealRegSingle i+ | i <= lastint platform -> RcInteger+ | i <= lastfake -> RcDouble+ | otherwise -> RcDoubleSSE++ RealRegPair{} -> panic "X86.Regs.classOfRealReg: RegPairs on this arch"++-- | Get the name of the register with this number.+showReg :: Platform -> RegNo -> String+showReg platform n+ | n >= firstxmm = "%xmm" ++ show (n-firstxmm)+ | n >= firstfake = "%fake" ++ show (n-firstfake)+ | n >= 8 = "%r" ++ show n+ | otherwise = regNames platform !! n++regNames :: Platform -> [String]+regNames platform+ = if target32Bit platform+ then ["%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%ebp", "%esp"]+ else ["%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", "%rbp", "%rsp"]++++-- machine specific ------------------------------------------------------------+++{-+Intel x86 architecture:+- All registers except 7 (esp) are available for use.+- Only ebx, esi, edi and esp are available across a C call (they are callee-saves).+- Registers 0-7 have 16-bit counterparts (ax, bx etc.)+- Registers 0-3 have 8 bit counterparts (ah, bh etc.)+- Registers fake0..fake5 are fakes; we pretend x86 has 6 conventionally-addressable+ fp registers, and 3-operand insns for them, and we translate this into+ real stack-based x86 fp code after register allocation.++The fp registers are all Double registers; we don't have any RcFloat class+regs. @regClass@ barfs if you give it a VirtualRegF, and mkVReg above should+never generate them.+-}++fake0, fake1, fake2, fake3, fake4, fake5,+ eax, ebx, ecx, edx, esp, ebp, esi, edi :: Reg++eax = regSingle 0+ebx = regSingle 1+ecx = regSingle 2+edx = regSingle 3+esi = regSingle 4+edi = regSingle 5+ebp = regSingle 6+esp = regSingle 7+fake0 = regSingle 16+fake1 = regSingle 17+fake2 = regSingle 18+fake3 = regSingle 19+fake4 = regSingle 20+fake5 = regSingle 21++++{-+AMD x86_64 architecture:+- All 16 integer registers are addressable as 8, 16, 32 and 64-bit values:++ 8 16 32 64+ ---------------------+ al ax eax rax+ bl bx ebx rbx+ cl cx ecx rcx+ dl dx edx rdx+ sil si esi rsi+ dil si edi rdi+ bpl bp ebp rbp+ spl sp esp rsp+ r10b r10w r10d r10+ r11b r11w r11d r11+ r12b r12w r12d r12+ r13b r13w r13d r13+ r14b r14w r14d r14+ r15b r15w r15d r15+-}++rax, rbx, rcx, rdx, rsp, rbp, rsi, rdi,+ r8, r9, r10, r11, r12, r13, r14, r15,+ xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,+ xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 :: Reg++rax = regSingle 0+rbx = regSingle 1+rcx = regSingle 2+rdx = regSingle 3+rsi = regSingle 4+rdi = regSingle 5+rbp = regSingle 6+rsp = regSingle 7+r8 = regSingle 8+r9 = regSingle 9+r10 = regSingle 10+r11 = regSingle 11+r12 = regSingle 12+r13 = regSingle 13+r14 = regSingle 14+r15 = regSingle 15+xmm0 = regSingle 24+xmm1 = regSingle 25+xmm2 = regSingle 26+xmm3 = regSingle 27+xmm4 = regSingle 28+xmm5 = regSingle 29+xmm6 = regSingle 30+xmm7 = regSingle 31+xmm8 = regSingle 32+xmm9 = regSingle 33+xmm10 = regSingle 34+xmm11 = regSingle 35+xmm12 = regSingle 36+xmm13 = regSingle 37+xmm14 = regSingle 38+xmm15 = regSingle 39++ripRel :: Displacement -> AddrMode+ripRel imm = AddrBaseIndex EABaseRip EAIndexNone imm+++ -- so we can re-use some x86 code:+{-+eax = rax+ebx = rbx+ecx = rcx+edx = rdx+esi = rsi+edi = rdi+ebp = rbp+esp = rsp+-}++xmm :: RegNo -> Reg+xmm n = regSingle (firstxmm+n)+++++-- | these are the regs which we cannot assume stay alive over a C call.+callClobberedRegs :: Platform -> [Reg]+-- caller-saves registers+callClobberedRegs platform+ | target32Bit platform = [eax,ecx,edx] ++ map regSingle (floatregnos platform)+ | platformOS platform == OSMinGW32+ = [rax,rcx,rdx,r8,r9,r10,r11]+ ++ map regSingle (floatregnos platform)+ | otherwise+ -- all xmm regs are caller-saves+ -- caller-saves registers+ = [rax,rcx,rdx,rsi,rdi,r8,r9,r10,r11]+ ++ map regSingle (floatregnos platform)++allArgRegs :: Platform -> [(Reg, Reg)]+allArgRegs platform+ | platformOS platform == OSMinGW32 = zip [rcx,rdx,r8,r9]+ (map regSingle [firstxmm ..])+ | otherwise = panic "X86.Regs.allArgRegs: not defined for this arch"++allIntArgRegs :: Platform -> [Reg]+allIntArgRegs platform+ | (platformOS platform == OSMinGW32) || target32Bit platform+ = panic "X86.Regs.allIntArgRegs: not defined for this platform"+ | otherwise = [rdi,rsi,rdx,rcx,r8,r9]++allFPArgRegs :: Platform -> [Reg]+allFPArgRegs platform+ | platformOS platform == OSMinGW32+ = panic "X86.Regs.allFPArgRegs: not defined for this platform"+ | otherwise = map regSingle [firstxmm .. firstxmm+7]++-- Machine registers which might be clobbered by instructions that+-- generate results into fixed registers, or need arguments in a fixed+-- register.+instrClobberedRegs :: Platform -> [Reg]+instrClobberedRegs platform+ | target32Bit platform = [ eax, ecx, edx ]+ | otherwise = [ rax, rcx, rdx ]++--++-- allocatableRegs is allMachRegNos with the fixed-use regs removed.+-- i.e., these are the regs for which we are prepared to allow the+-- register allocator to attempt to map VRegs to.+allocatableRegs :: Platform -> [RealReg]+allocatableRegs platform+ = let isFree i = freeReg platform i+ in map RealRegSingle $ filter isFree (allMachRegNos platform)+
+ parser/ApiAnnotation.hs view
@@ -0,0 +1,362 @@+{-# LANGUAGE DeriveDataTypeable #-}++module ApiAnnotation (+ getAnnotation, getAndRemoveAnnotation,+ getAnnotationComments,getAndRemoveAnnotationComments,+ ApiAnns,+ ApiAnnKey,+ AnnKeywordId(..),+ AnnotationComment(..),+ IsUnicodeSyntax(..),+ unicodeAnn,+ HasE(..),+ LRdrName -- Exists for haddocks only+ ) where++import RdrName+import Outputable+import SrcLoc+import qualified Data.Map as Map+import Data.Data+++{-+Note [Api annotations]+~~~~~~~~~~~~~~~~~~~~~~+Given a parse tree of a Haskell module, how can we reconstruct+the original Haskell source code, retaining all whitespace and+source code comments? We need to track the locations of all+elements from the original source: this includes keywords such as+'let' / 'in' / 'do' etc as well as punctuation such as commas and+braces, and also comments. We collectively refer to this+metadata as the "API annotations".++Rather than annotate the resulting parse tree with these locations+directly (this would be a major change to some fairly core data+structures in GHC), we instead capture locations for these elements in a+structure separate from the parse tree, and returned in the+pm_annotations field of the ParsedModule type.++The full ApiAnns type is++> type ApiAnns = ( Map.Map ApiAnnKey [SrcSpan] -- non-comments+> , Map.Map SrcSpan [Located AnnotationComment]) -- comments++NON-COMMENT ELEMENTS++Intuitively, every AST element directly contains a bag of keywords+(keywords can show up more than once in a node: a semicolon i.e. newline+can show up multiple times before the next AST element), each of which+needs to be associated with its location in the original source code.++Consequently, the structure that records non-comment elements is logically+a two level map, from the SrcSpan of the AST element containing it, to+a map from keywords ('AnnKeyWord') to all locations of the keyword directly+in the AST element:++> type ApiAnnKey = (SrcSpan,AnnKeywordId)+>+> Map.Map ApiAnnKey [SrcSpan]++So++> let x = 1 in 2 *x++would result in the AST element++ L span (HsLet (binds for x = 1) (2 * x))++and the annotations++ (span,AnnLet) having the location of the 'let' keyword+ (span,AnnEqual) having the location of the '=' sign+ (span,AnnIn) having the location of the 'in' keyword++For any given element in the AST, there is only a set number of+keywords that are applicable for it (e.g., you'll never see an+'import' keyword associated with a let-binding.) The set of allowed+keywords is documented in a comment associated with the constructor+of a given AST element, although the ground truth is in Parser+and RdrHsSyn (which actually add the annotations; see #13012).++COMMENT ELEMENTS++Every comment is associated with a *located* AnnotationComment.+We associate comments with the lowest (most specific) AST element+enclosing them:++> Map.Map SrcSpan [Located AnnotationComment]++PARSER STATE++There are three fields in PState (the parser state) which play a role+with annotations.++> annotations :: [(ApiAnnKey,[SrcSpan])],+> comment_q :: [Located AnnotationComment],+> annotations_comments :: [(SrcSpan,[Located AnnotationComment])]++The 'annotations' and 'annotations_comments' fields are simple: they simply+accumulate annotations that will end up in 'ApiAnns' at the end+(after they are passed to Map.fromList).++The 'comment_q' field captures comments as they are seen in the token stream,+so that when they are ready to be allocated via the parser they are+available (at the time we lex a comment, we don't know what the enclosing+AST node of it is, so we can't associate it with a SrcSpan in+annotations_comments).++PARSER EMISSION OF ANNOTATIONS++The parser interacts with the lexer using the function++> addAnnotation :: SrcSpan -> AnnKeywordId -> SrcSpan -> P ()++which takes the AST element SrcSpan, the annotation keyword and the+target SrcSpan.++This adds the annotation to the `annotations` field of `PState` and+transfers any comments in `comment_q` WHICH ARE ENCLOSED by+the SrcSpan of this element to the `annotations_comments`+field. (Comments which are outside of this annotation are deferred+until later. 'allocateComments' in 'Lexer' is responsible for+making sure we only attach comments that actually fit in the 'SrcSpan'.)++The wiki page describing this feature is+https://ghc.haskell.org/trac/ghc/wiki/ApiAnnotations++-}+-- ---------------------------------------------------------------------++-- If you update this, update the Note [Api annotations] above+type ApiAnns = ( Map.Map ApiAnnKey [SrcSpan]+ , Map.Map SrcSpan [Located AnnotationComment])++-- If you update this, update the Note [Api annotations] above+type ApiAnnKey = (SrcSpan,AnnKeywordId)+++-- | Retrieve a list of annotation 'SrcSpan's based on the 'SrcSpan'+-- of the annotated AST element, and the known type of the annotation.+getAnnotation :: ApiAnns -> SrcSpan -> AnnKeywordId -> [SrcSpan]+getAnnotation (anns,_) span ann+ = case Map.lookup (span,ann) anns of+ Nothing -> []+ Just ss -> ss++-- | Retrieve a list of annotation 'SrcSpan's based on the 'SrcSpan'+-- of the annotated AST element, and the known type of the annotation.+-- The list is removed from the annotations.+getAndRemoveAnnotation :: ApiAnns -> SrcSpan -> AnnKeywordId+ -> ([SrcSpan],ApiAnns)+getAndRemoveAnnotation (anns,cs) span ann+ = case Map.lookup (span,ann) anns of+ Nothing -> ([],(anns,cs))+ Just ss -> (ss,(Map.delete (span,ann) anns,cs))++-- |Retrieve the comments allocated to the current 'SrcSpan'+--+-- Note: A given 'SrcSpan' may appear in multiple AST elements,+-- beware of duplicates+getAnnotationComments :: ApiAnns -> SrcSpan -> [Located AnnotationComment]+getAnnotationComments (_,anns) span =+ case Map.lookup span anns of+ Just cs -> cs+ Nothing -> []++-- |Retrieve the comments allocated to the current 'SrcSpan', and+-- remove them from the annotations+getAndRemoveAnnotationComments :: ApiAnns -> SrcSpan+ -> ([Located AnnotationComment],ApiAnns)+getAndRemoveAnnotationComments (anns,canns) span =+ case Map.lookup span canns of+ Just cs -> (cs,(anns,Map.delete span canns))+ Nothing -> ([],(anns,canns))++-- --------------------------------------------------------------------++-- | API Annotations exist so that tools can perform source to source+-- conversions of Haskell code. They are used to keep track of the+-- various syntactic keywords that are not captured in the existing+-- AST.+--+-- The annotations, together with original source comments are made+-- available in the @'pm_annotations'@ field of @'GHC.ParsedModule'@.+-- Comments are only retained if @'Opt_KeepRawTokenStream'@ is set in+-- @'DynFlags.DynFlags'@ before parsing.+--+-- The wiki page describing this feature is+-- https://ghc.haskell.org/trac/ghc/wiki/ApiAnnotations+--+-- Note: in general the names of these are taken from the+-- corresponding token, unless otherwise noted+-- See note [Api annotations] above for details of the usage+data AnnKeywordId+ = AnnAnyclass+ | AnnAs+ | AnnAt+ | AnnBang -- ^ '!'+ | AnnBackquote -- ^ '`'+ | AnnBy+ | AnnCase -- ^ case or lambda case+ | AnnClass+ | AnnClose -- ^ '\#)' or '\#-}' etc+ | AnnCloseB -- ^ '|)'+ | AnnCloseBU -- ^ '|)', unicode variant+ | AnnCloseC -- ^ '}'+ | AnnCloseQ -- ^ '|]'+ | AnnCloseQU -- ^ '|]', unicode variant+ | AnnCloseP -- ^ ')'+ | AnnCloseS -- ^ ']'+ | AnnColon+ | AnnComma -- ^ as a list separator+ | AnnCommaTuple -- ^ in a RdrName for a tuple+ | AnnDarrow -- ^ '=>'+ | AnnDarrowU -- ^ '=>', unicode variant+ | AnnData+ | AnnDcolon -- ^ '::'+ | AnnDcolonU -- ^ '::', unicode variant+ | AnnDefault+ | AnnDeriving+ | AnnDo+ | AnnDot -- ^ '.'+ | AnnDotdot -- ^ '..'+ | AnnElse+ | AnnEqual+ | AnnExport+ | AnnFamily+ | AnnForall+ | AnnForallU -- ^ Unicode variant+ | AnnForeign+ | AnnFunId -- ^ for function name in matches where there are+ -- multiple equations for the function.+ | AnnGroup+ | AnnHeader -- ^ for CType+ | AnnHiding+ | AnnIf+ | AnnImport+ | AnnIn+ | AnnInfix -- ^ 'infix' or 'infixl' or 'infixr'+ | AnnInstance+ | AnnLam+ | AnnLarrow -- ^ '<-'+ | AnnLarrowU -- ^ '<-', unicode variant+ | AnnLet+ | AnnMdo+ | AnnMinus -- ^ '-'+ | AnnModule+ | AnnNewtype+ | AnnName -- ^ where a name loses its location in the AST, this carries it+ | AnnOf+ | AnnOpen -- ^ '(\#' or '{-\# LANGUAGE' etc+ | AnnOpenB -- ^ '(|'+ | AnnOpenBU -- ^ '(|', unicode variant+ | AnnOpenC -- ^ '{'+ | AnnOpenE -- ^ '[e|' or '[e||'+ | AnnOpenEQ -- ^ '[|'+ | AnnOpenEQU -- ^ '[|', unicode variant+ | AnnOpenP -- ^ '('+ | AnnOpenPE -- ^ '$('+ | AnnOpenPTE -- ^ '$$('+ | AnnOpenS -- ^ '['+ | AnnPackageName+ | AnnPattern+ | AnnProc+ | AnnQualified+ | AnnRarrow -- ^ '->'+ | AnnRarrowU -- ^ '->', unicode variant+ | AnnRec+ | AnnRole+ | AnnSafe+ | AnnSemi -- ^ ';'+ | AnnSimpleQuote -- ^ '''+ | AnnSignature+ | AnnStatic -- ^ 'static'+ | AnnStock+ | AnnThen+ | AnnThIdSplice -- ^ '$'+ | AnnThIdTySplice -- ^ '$$'+ | AnnThTyQuote -- ^ double '''+ | AnnTilde -- ^ '~'+ | AnnTildehsh -- ^ '~#'+ | AnnType+ | AnnUnit -- ^ '()' for types+ | AnnUsing+ | AnnVal -- ^ e.g. INTEGER+ | AnnValStr -- ^ String value, will need quotes when output+ | AnnVbar -- ^ '|'+ | AnnWhere+ | Annlarrowtail -- ^ '-<'+ | AnnlarrowtailU -- ^ '-<', unicode variant+ | Annrarrowtail -- ^ '->'+ | AnnrarrowtailU -- ^ '->', unicode variant+ | AnnLarrowtail -- ^ '-<<'+ | AnnLarrowtailU -- ^ '-<<', unicode variant+ | AnnRarrowtail -- ^ '>>-'+ | AnnRarrowtailU -- ^ '>>-', unicode variant+ | AnnEofPos+ deriving (Eq, Ord, Data, Show)++instance Outputable AnnKeywordId where+ ppr x = text (show x)++-- ---------------------------------------------------------------------++data AnnotationComment =+ -- Documentation annotations+ AnnDocCommentNext String -- ^ something beginning '-- |'+ | AnnDocCommentPrev String -- ^ something beginning '-- ^'+ | AnnDocCommentNamed String -- ^ something beginning '-- $'+ | AnnDocSection Int String -- ^ a section heading+ | AnnDocOptions String -- ^ doc options (prune, ignore-exports, etc)+ | AnnLineComment String -- ^ comment starting by "--"+ | AnnBlockComment String -- ^ comment in {- -}+ deriving (Eq, Ord, Data, Show)+-- Note: these are based on the Token versions, but the Token type is+-- defined in Lexer.x and bringing it in here would create a loop++instance Outputable AnnotationComment where+ ppr x = text (show x)++-- | - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen',+-- 'ApiAnnotation.AnnClose','ApiAnnotation.AnnComma',+-- 'ApiAnnotation.AnnRarrow','ApiAnnotation.AnnTildehsh',+-- 'ApiAnnotation.AnnTilde'+-- - May have 'ApiAnnotation.AnnComma' when in a list+type LRdrName = Located RdrName+++-- | Certain tokens can have alternate representations when unicode syntax is+-- enabled. This flag is attached to those tokens in the lexer so that the+-- original source representation can be reproduced in the corresponding+-- 'ApiAnnotation'+data IsUnicodeSyntax = UnicodeSyntax | NormalSyntax+ deriving (Eq, Ord, Data, Show)++-- | Convert a normal annotation into its unicode equivalent one+unicodeAnn :: AnnKeywordId -> AnnKeywordId+unicodeAnn AnnForall = AnnForallU+unicodeAnn AnnDcolon = AnnDcolonU+unicodeAnn AnnLarrow = AnnLarrowU+unicodeAnn AnnRarrow = AnnRarrowU+unicodeAnn AnnDarrow = AnnDarrowU+unicodeAnn Annlarrowtail = AnnlarrowtailU+unicodeAnn Annrarrowtail = AnnrarrowtailU+unicodeAnn AnnLarrowtail = AnnLarrowtailU+unicodeAnn AnnRarrowtail = AnnRarrowtailU+unicodeAnn AnnOpenB = AnnOpenBU+unicodeAnn AnnCloseB = AnnCloseBU+unicodeAnn AnnOpenEQ = AnnOpenEQU+unicodeAnn AnnCloseQ = AnnCloseQU+unicodeAnn ann = ann+++-- | Some template haskell tokens have two variants, one with an `e` the other+-- not:+--+-- > [| or [e|+-- > [|| or [e||+--+-- This type indicates whether the 'e' is present or not.+data HasE = HasE | NoE+ deriving (Eq, Ord, Data, Show)
+ parser/Ctype.hs view
@@ -0,0 +1,216 @@+-- Character classification+{-# LANGUAGE CPP #-}+module Ctype+ ( is_ident -- Char# -> Bool+ , is_symbol -- Char# -> Bool+ , is_any -- Char# -> Bool+ , is_space -- Char# -> Bool+ , is_lower -- Char# -> Bool+ , is_upper -- Char# -> Bool+ , is_digit -- Char# -> Bool+ , is_alphanum -- Char# -> Bool++ , is_decdigit, is_hexdigit, is_octdigit, is_bindigit+ , hexDigit, octDecDigit+ ) where++#include "HsVersions.h"++import Data.Int ( Int32 )+import Data.Bits ( Bits((.&.)) )+import Data.Char ( ord, chr )+import Panic++-- Bit masks++cIdent, cSymbol, cAny, cSpace, cLower, cUpper, cDigit :: Int+cIdent = 1+cSymbol = 2+cAny = 4+cSpace = 8+cLower = 16+cUpper = 32+cDigit = 64++-- | The predicates below look costly, but aren't, GHC+GCC do a great job+-- at the big case below.++{-# INLINE is_ctype #-}+is_ctype :: Int -> Char -> Bool+is_ctype mask c = (fromIntegral (charType c) .&. fromIntegral mask) /= (0::Int32)++is_ident, is_symbol, is_any, is_space, is_lower, is_upper, is_digit,+ is_alphanum :: Char -> Bool+is_ident = is_ctype cIdent+is_symbol = is_ctype cSymbol+is_any = is_ctype cAny+is_space = is_ctype cSpace+is_lower = is_ctype cLower+is_upper = is_ctype cUpper+is_digit = is_ctype cDigit+is_alphanum = is_ctype (cLower+cUpper+cDigit)++-- Utils++hexDigit :: Char -> Int+hexDigit c | is_decdigit c = ord c - ord '0'+ | otherwise = ord (to_lower c) - ord 'a' + 10++octDecDigit :: Char -> Int+octDecDigit c = ord c - ord '0'++is_decdigit :: Char -> Bool+is_decdigit c+ = c >= '0' && c <= '9'++is_hexdigit :: Char -> Bool+is_hexdigit c+ = is_decdigit c+ || (c >= 'a' && c <= 'f')+ || (c >= 'A' && c <= 'F')++is_octdigit :: Char -> Bool+is_octdigit c = c >= '0' && c <= '7'++is_bindigit :: Char -> Bool+is_bindigit c = c == '0' || c == '1'++to_lower :: Char -> Char+to_lower c+ | c >= 'A' && c <= 'Z' = chr (ord c - (ord 'A' - ord 'a'))+ | otherwise = c++-- | We really mean .|. instead of + below, but GHC currently doesn't do+-- any constant folding with bitops. *sigh*++charType :: Char -> Int+charType c = case c of+ '\0' -> 0 -- \000+ '\1' -> 0 -- \001+ '\2' -> 0 -- \002+ '\3' -> 0 -- \003+ '\4' -> 0 -- \004+ '\5' -> 0 -- \005+ '\6' -> 0 -- \006+ '\7' -> 0 -- \007+ '\8' -> 0 -- \010+ '\9' -> cSpace -- \t (not allowed in strings, so !cAny)+ '\10' -> cSpace -- \n (ditto)+ '\11' -> cSpace -- \v (ditto)+ '\12' -> cSpace -- \f (ditto)+ '\13' -> cSpace -- ^M (ditto)+ '\14' -> 0 -- \016+ '\15' -> 0 -- \017+ '\16' -> 0 -- \020+ '\17' -> 0 -- \021+ '\18' -> 0 -- \022+ '\19' -> 0 -- \023+ '\20' -> 0 -- \024+ '\21' -> 0 -- \025+ '\22' -> 0 -- \026+ '\23' -> 0 -- \027+ '\24' -> 0 -- \030+ '\25' -> 0 -- \031+ '\26' -> 0 -- \032+ '\27' -> 0 -- \033+ '\28' -> 0 -- \034+ '\29' -> 0 -- \035+ '\30' -> 0 -- \036+ '\31' -> 0 -- \037+ '\32' -> cAny + cSpace --+ '\33' -> cAny + cSymbol -- !+ '\34' -> cAny -- "+ '\35' -> cAny + cSymbol -- #+ '\36' -> cAny + cSymbol -- $+ '\37' -> cAny + cSymbol -- %+ '\38' -> cAny + cSymbol -- &+ '\39' -> cAny + cIdent -- '+ '\40' -> cAny -- (+ '\41' -> cAny -- )+ '\42' -> cAny + cSymbol -- *+ '\43' -> cAny + cSymbol -- ++ '\44' -> cAny -- ,+ '\45' -> cAny + cSymbol -- -+ '\46' -> cAny + cSymbol -- .+ '\47' -> cAny + cSymbol -- /+ '\48' -> cAny + cIdent + cDigit -- 0+ '\49' -> cAny + cIdent + cDigit -- 1+ '\50' -> cAny + cIdent + cDigit -- 2+ '\51' -> cAny + cIdent + cDigit -- 3+ '\52' -> cAny + cIdent + cDigit -- 4+ '\53' -> cAny + cIdent + cDigit -- 5+ '\54' -> cAny + cIdent + cDigit -- 6+ '\55' -> cAny + cIdent + cDigit -- 7+ '\56' -> cAny + cIdent + cDigit -- 8+ '\57' -> cAny + cIdent + cDigit -- 9+ '\58' -> cAny + cSymbol -- :+ '\59' -> cAny -- ;+ '\60' -> cAny + cSymbol -- <+ '\61' -> cAny + cSymbol -- =+ '\62' -> cAny + cSymbol -- >+ '\63' -> cAny + cSymbol -- ?+ '\64' -> cAny + cSymbol -- @+ '\65' -> cAny + cIdent + cUpper -- A+ '\66' -> cAny + cIdent + cUpper -- B+ '\67' -> cAny + cIdent + cUpper -- C+ '\68' -> cAny + cIdent + cUpper -- D+ '\69' -> cAny + cIdent + cUpper -- E+ '\70' -> cAny + cIdent + cUpper -- F+ '\71' -> cAny + cIdent + cUpper -- G+ '\72' -> cAny + cIdent + cUpper -- H+ '\73' -> cAny + cIdent + cUpper -- I+ '\74' -> cAny + cIdent + cUpper -- J+ '\75' -> cAny + cIdent + cUpper -- K+ '\76' -> cAny + cIdent + cUpper -- L+ '\77' -> cAny + cIdent + cUpper -- M+ '\78' -> cAny + cIdent + cUpper -- N+ '\79' -> cAny + cIdent + cUpper -- O+ '\80' -> cAny + cIdent + cUpper -- P+ '\81' -> cAny + cIdent + cUpper -- Q+ '\82' -> cAny + cIdent + cUpper -- R+ '\83' -> cAny + cIdent + cUpper -- S+ '\84' -> cAny + cIdent + cUpper -- T+ '\85' -> cAny + cIdent + cUpper -- U+ '\86' -> cAny + cIdent + cUpper -- V+ '\87' -> cAny + cIdent + cUpper -- W+ '\88' -> cAny + cIdent + cUpper -- X+ '\89' -> cAny + cIdent + cUpper -- Y+ '\90' -> cAny + cIdent + cUpper -- Z+ '\91' -> cAny -- [+ '\92' -> cAny + cSymbol -- backslash+ '\93' -> cAny -- ]+ '\94' -> cAny + cSymbol -- ^+ '\95' -> cAny + cIdent + cLower -- _+ '\96' -> cAny -- `+ '\97' -> cAny + cIdent + cLower -- a+ '\98' -> cAny + cIdent + cLower -- b+ '\99' -> cAny + cIdent + cLower -- c+ '\100' -> cAny + cIdent + cLower -- d+ '\101' -> cAny + cIdent + cLower -- e+ '\102' -> cAny + cIdent + cLower -- f+ '\103' -> cAny + cIdent + cLower -- g+ '\104' -> cAny + cIdent + cLower -- h+ '\105' -> cAny + cIdent + cLower -- i+ '\106' -> cAny + cIdent + cLower -- j+ '\107' -> cAny + cIdent + cLower -- k+ '\108' -> cAny + cIdent + cLower -- l+ '\109' -> cAny + cIdent + cLower -- m+ '\110' -> cAny + cIdent + cLower -- n+ '\111' -> cAny + cIdent + cLower -- o+ '\112' -> cAny + cIdent + cLower -- p+ '\113' -> cAny + cIdent + cLower -- q+ '\114' -> cAny + cIdent + cLower -- r+ '\115' -> cAny + cIdent + cLower -- s+ '\116' -> cAny + cIdent + cLower -- t+ '\117' -> cAny + cIdent + cLower -- u+ '\118' -> cAny + cIdent + cLower -- v+ '\119' -> cAny + cIdent + cLower -- w+ '\120' -> cAny + cIdent + cLower -- x+ '\121' -> cAny + cIdent + cLower -- y+ '\122' -> cAny + cIdent + cLower -- z+ '\123' -> cAny -- {+ '\124' -> cAny + cSymbol -- |+ '\125' -> cAny -- }+ '\126' -> cAny + cSymbol -- ~+ '\127' -> 0 -- \177+ _ -> panic ("charType: " ++ show c)
+ parser/HaddockUtils.hs view
@@ -0,0 +1,32 @@++module HaddockUtils where++import HsSyn+import SrcLoc++import Control.Monad++-- -----------------------------------------------------------------------------+-- Adding documentation to record fields (used in parsing).++addFieldDoc :: LConDeclField a -> Maybe LHsDocString -> LConDeclField a+addFieldDoc (L l fld) doc+ = L l (fld { cd_fld_doc = cd_fld_doc fld `mplus` doc })++addFieldDocs :: [LConDeclField a] -> Maybe LHsDocString -> [LConDeclField a]+addFieldDocs [] _ = []+addFieldDocs (x:xs) doc = addFieldDoc x doc : xs+++addConDoc :: LConDecl a -> Maybe LHsDocString -> LConDecl a+addConDoc decl Nothing = decl+addConDoc (L p c) doc = L p ( c { con_doc = con_doc c `mplus` doc } )++addConDocs :: [LConDecl a] -> Maybe LHsDocString -> [LConDecl a]+addConDocs [] _ = []+addConDocs [x] doc = [addConDoc x doc]+addConDocs (x:xs) doc = x : addConDocs xs doc++addConDocFirst :: [LConDecl a] -> Maybe LHsDocString -> [LConDecl a]+addConDocFirst [] _ = []+addConDocFirst (x:xs) doc = addConDoc x doc : xs
+ parser/Lexer.x view
@@ -0,0 +1,2968 @@+-----------------------------------------------------------------------------+-- (c) The University of Glasgow, 2006+--+-- GHC's lexer for Haskell 2010 [1].+--+-- This is a combination of an Alex-generated lexer [2] from a regex+-- definition, with some hand-coded bits. [3]+--+-- Completely accurate information about token-spans within the source+-- file is maintained. Every token has a start and end RealSrcLoc+-- attached to it.+--+-- References:+-- [1] https://www.haskell.org/onlinereport/haskell2010/haskellch2.html+-- [2] http://www.haskell.org/alex/+-- [3] https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/Parser+--+-----------------------------------------------------------------------------++-- ToDo / known bugs:+-- - parsing integers is a bit slow+-- - readRational is a bit slow+--+-- Known bugs, that were also in the previous version:+-- - M... should be 3 tokens, not 1.+-- - pragma-end should be only valid in a pragma++-- qualified operator NOTES.+--+-- - If M.(+) is a single lexeme, then..+-- - Probably (+) should be a single lexeme too, for consistency.+-- Otherwise ( + ) would be a prefix operator, but M.( + ) would not be.+-- - But we have to rule out reserved operators, otherwise (..) becomes+-- a different lexeme.+-- - Should we therefore also rule out reserved operators in the qualified+-- form? This is quite difficult to achieve. We don't do it for+-- qualified varids.+++-- -----------------------------------------------------------------------------+-- Alex "Haskell code fragment top"++{+{-# LANGUAGE BangPatterns #-}++-- See Note [Warnings in code generated by Alex] in compiler/parser/Lexer.x+{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++{-# OPTIONS_GHC -funbox-strict-fields #-}++module Lexer (+ Token(..), lexer, pragState, mkPState, mkPStatePure, PState(..),+ P(..), ParseResult(..), mkParserFlags, ParserFlags(..), getSrcLoc,+ getPState, extopt, withThisPackage,+ failLocMsgP, failSpanMsgP, srcParseFail,+ getMessages,+ popContext, pushModuleContext, setLastToken, setSrcLoc,+ activeContext, nextIsEOF,+ getLexState, popLexState, pushLexState,+ extension, bangPatEnabled, datatypeContextsEnabled,+ traditionalRecordSyntaxEnabled,+ explicitForallEnabled,+ inRulePrag,+ explicitNamespacesEnabled,+ patternSynonymsEnabled,+ sccProfilingOn, hpcEnabled,+ addWarning,+ lexTokenStream,+ addAnnotation,AddAnn,addAnnsAt,mkParensApiAnn,+ commentToAnnotation,+ moveAnnotations+ ) where++-- base+import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import Control.Monad.Fail+#endif+import Data.Bits+import Data.Char+import Data.List+import Data.Maybe+import Data.Word++import Data.IntSet (IntSet)+import qualified Data.IntSet as IntSet++-- ghc-boot+import qualified GHC.LanguageExtensions as LangExt++-- bytestring+import Data.ByteString (ByteString)++-- containers+import Data.Map (Map)+import qualified Data.Map as Map++-- compiler/utils+import Bag+import Outputable+import StringBuffer+import FastString+import UniqFM+import Util ( readRational )++-- compiler/main+import ErrUtils+import DynFlags++-- compiler/basicTypes+import SrcLoc+import Module+import BasicTypes ( InlineSpec(..), RuleMatchInfo(..), FractionalLit(..),+ SourceText(..) )++-- compiler/parser+import Ctype++import ApiAnnotation+}++-- -----------------------------------------------------------------------------+-- Alex "Character set macros"++-- NB: The logic behind these definitions is also reflected in basicTypes/Lexeme.hs+-- Any changes here should likely be reflected there.+$unispace = \x05 -- Trick Alex into handling Unicode. See alexGetByte.+$nl = [\n\r\f]+$whitechar = [$nl\v\ $unispace]+$white_no_nl = $whitechar # \n -- TODO #8424+$tab = \t++$ascdigit = 0-9+$unidigit = \x03 -- Trick Alex into handling Unicode. See alexGetByte.+$decdigit = $ascdigit -- for now, should really be $digit (ToDo)+$digit = [$ascdigit $unidigit]++$special = [\(\)\,\;\[\]\`\{\}]+$ascsymbol = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~\:]+$unisymbol = \x04 -- Trick Alex into handling Unicode. See alexGetByte.+$symbol = [$ascsymbol $unisymbol] # [$special \_\"\']++$unilarge = \x01 -- Trick Alex into handling Unicode. See alexGetByte.+$asclarge = [A-Z]+$large = [$asclarge $unilarge]++$unismall = \x02 -- Trick Alex into handling Unicode. See alexGetByte.+$ascsmall = [a-z]+$small = [$ascsmall $unismall \_]++$unigraphic = \x06 -- Trick Alex into handling Unicode. See alexGetByte.+$graphic = [$small $large $symbol $digit $special $unigraphic \"\']++$binit = 0-1+$octit = 0-7+$hexit = [$decdigit A-F a-f]++$uniidchar = \x07 -- Trick Alex into handling Unicode. See alexGetByte.+$idchar = [$small $large $digit $uniidchar \']++$pragmachar = [$small $large $digit]++$docsym = [\| \^ \* \$]+++-- -----------------------------------------------------------------------------+-- Alex "Regular expression macros"++@varid = $small $idchar* -- variable identifiers+@conid = $large $idchar* -- constructor identifiers++@varsym = ($symbol # \:) $symbol* -- variable (operator) symbol+@consym = \: $symbol* -- constructor (operator) symbol++@decimal = $decdigit++@binary = $binit++@octal = $octit++@hexadecimal = $hexit++@exponent = [eE] [\-\+]? @decimal++@qual = (@conid \.)++@qvarid = @qual @varid+@qconid = @qual @conid+@qvarsym = @qual @varsym+@qconsym = @qual @consym++@floating_point = @decimal \. @decimal @exponent? | @decimal @exponent++-- normal signed numerical literals can only be explicitly negative,+-- not explicitly positive (contrast @exponent)+@negative = \-+@signed = @negative ?+++-- -----------------------------------------------------------------------------+-- Alex "Identifier"++haskell :-+++-- -----------------------------------------------------------------------------+-- Alex "Rules"++-- everywhere: skip whitespace+$white_no_nl+ ;+$tab { warnTab }++-- Everywhere: deal with nested comments. We explicitly rule out+-- pragmas, "{-#", so that we don't accidentally treat them as comments.+-- (this can happen even though pragmas will normally take precedence due to+-- longest-match, because pragmas aren't valid in every state, but comments+-- are). We also rule out nested Haddock comments, if the -haddock flag is+-- set.++"{-" / { isNormalComment } { nested_comment lexToken }++-- Single-line comments are a bit tricky. Haskell 98 says that two or+-- more dashes followed by a symbol should be parsed as a varsym, so we+-- have to exclude those.++-- Since Haddock comments aren't valid in every state, we need to rule them+-- out here.++-- The following two rules match comments that begin with two dashes, but+-- continue with a different character. The rules test that this character+-- is not a symbol (in which case we'd have a varsym), and that it's not a+-- space followed by a Haddock comment symbol (docsym) (in which case we'd+-- have a Haddock comment). The rules then munch the rest of the line.++"-- " ~$docsym .* { lineCommentToken }+"--" [^$symbol \ ] .* { lineCommentToken }++-- Next, match Haddock comments if no -haddock flag++"-- " $docsym .* / { ifExtension (not . haddockEnabled) } { lineCommentToken }++-- Now, when we've matched comments that begin with 2 dashes and continue+-- with a different character, we need to match comments that begin with three+-- or more dashes (which clearly can't be Haddock comments). We only need to+-- make sure that the first non-dash character isn't a symbol, and munch the+-- rest of the line.++"---"\-* ~$symbol .* { lineCommentToken }++-- Since the previous rules all match dashes followed by at least one+-- character, we also need to match a whole line filled with just dashes.++"--"\-* / { atEOL } { lineCommentToken }++-- We need this rule since none of the other single line comment rules+-- actually match this case.++"-- " / { atEOL } { lineCommentToken }++-- 'bol' state: beginning of a line. Slurp up all the whitespace (including+-- blank lines) until we find a non-whitespace character, then do layout+-- processing.+--+-- One slight wibble here: what if the line begins with {-#? In+-- theory, we have to lex the pragma to see if it's one we recognise,+-- and if it is, then we backtrack and do_bol, otherwise we treat it+-- as a nested comment. We don't bother with this: if the line begins+-- with {-#, then we'll assume it's a pragma we know about and go for do_bol.+<bol> {+ \n ;+ ^\# line { begin line_prag1 }+ ^\# / { followedByDigit } { begin line_prag1 }+ ^\# pragma .* \n ; -- GCC 3.3 CPP generated, apparently+ ^\# \! .* \n ; -- #!, for scripts+ () { do_bol }+}++-- after a layout keyword (let, where, do, of), we begin a new layout+-- context if the curly brace is missing.+-- Careful! This stuff is quite delicate.+<layout, layout_do, layout_if> {+ \{ / { notFollowedBy '-' } { hopefully_open_brace }+ -- we might encounter {-# here, but {- has been handled already+ \n ;+ ^\# (line)? { begin line_prag1 }+}++-- after an 'if', a vertical bar starts a layout context for MultiWayIf+<layout_if> {+ \| / { notFollowedBySymbol } { new_layout_context True dontGenerateSemic ITvbar }+ () { pop }+}++-- do is treated in a subtly different way, see new_layout_context+<layout> () { new_layout_context True generateSemic ITvocurly }+<layout_do> () { new_layout_context False generateSemic ITvocurly }++-- after a new layout context which was found to be to the left of the+-- previous context, we have generated a '{' token, and we now need to+-- generate a matching '}' token.+<layout_left> () { do_layout_left }++<0,option_prags> \n { begin bol }++"{-#" $whitechar* $pragmachar+ / { known_pragma linePrags }+ { dispatch_pragmas linePrags }++-- single-line line pragmas, of the form+-- # <line> "<file>" <extra-stuff> \n+<line_prag1> @decimal { setLine line_prag1a }+<line_prag1a> \" [$graphic \ ]* \" { setFile line_prag1b }+<line_prag1b> .* { pop }++-- Haskell-style line pragmas, of the form+-- {-# LINE <line> "<file>" #-}+<line_prag2> @decimal { setLine line_prag2a }+<line_prag2a> \" [$graphic \ ]* \" { setFile line_prag2b }+<line_prag2b> "#-}"|"-}" { pop }+ -- NOTE: accept -} at the end of a LINE pragma, for compatibility+ -- with older versions of GHC which generated these.++-- Haskell-style column pragmas, of the form+-- {-# COLUMN <column> #-}+<column_prag> @decimal $whitechar* "#-}" { setColumn }++<0,option_prags> {+ "{-#" $whitechar* $pragmachar++ $whitechar+ $pragmachar+ / { known_pragma twoWordPrags }+ { dispatch_pragmas twoWordPrags }++ "{-#" $whitechar* $pragmachar+ / { known_pragma oneWordPrags }+ { dispatch_pragmas oneWordPrags }++ -- We ignore all these pragmas, but don't generate a warning for them+ "{-#" $whitechar* $pragmachar+ / { known_pragma ignoredPrags }+ { dispatch_pragmas ignoredPrags }++ -- ToDo: should only be valid inside a pragma:+ "#-}" { endPrag }+}++<option_prags> {+ "{-#" $whitechar* $pragmachar+ / { known_pragma fileHeaderPrags }+ { dispatch_pragmas fileHeaderPrags }+}++<0> {+ -- In the "0" mode we ignore these pragmas+ "{-#" $whitechar* $pragmachar+ / { known_pragma fileHeaderPrags }+ { nested_comment lexToken }+}++<0,option_prags> {+ "{-#" { warnThen Opt_WarnUnrecognisedPragmas (text "Unrecognised pragma")+ (nested_comment lexToken) }+}++-- '0' state: ordinary lexemes++-- Haddock comments++<0,option_prags> {+ "-- " $docsym / { ifExtension haddockEnabled } { multiline_doc_comment }+ "{-" \ ? $docsym / { ifExtension haddockEnabled } { nested_doc_comment }+}++-- "special" symbols++<0> {+ "[:" / { ifExtension parrEnabled } { token ITopabrack }+ ":]" / { ifExtension parrEnabled } { token ITcpabrack }+}++<0> {+ "[|" / { ifExtension thQuotesEnabled } { token (ITopenExpQuote NoE+ NormalSyntax) }+ "[||" / { ifExtension thQuotesEnabled } { token (ITopenTExpQuote NoE) }+ "[e|" / { ifExtension thQuotesEnabled } { token (ITopenExpQuote HasE+ NormalSyntax) }+ "[e||" / { ifExtension thQuotesEnabled } { token (ITopenTExpQuote HasE) }+ "[p|" / { ifExtension thQuotesEnabled } { token ITopenPatQuote }+ "[d|" / { ifExtension thQuotesEnabled } { layout_token ITopenDecQuote }+ "[t|" / { ifExtension thQuotesEnabled } { token ITopenTypQuote }+ "|]" / { ifExtension thQuotesEnabled } { token (ITcloseQuote+ NormalSyntax) }+ "||]" / { ifExtension thQuotesEnabled } { token ITcloseTExpQuote }+ \$ @varid / { ifExtension thEnabled } { skip_one_varid ITidEscape }+ "$$" @varid / { ifExtension thEnabled } { skip_two_varid ITidTyEscape }+ "$(" / { ifExtension thEnabled } { token ITparenEscape }+ "$$(" / { ifExtension thEnabled } { token ITparenTyEscape }++ "[" @varid "|" / { ifExtension qqEnabled }+ { lex_quasiquote_tok }++ -- qualified quasi-quote (#5555)+ "[" @qvarid "|" / { ifExtension qqEnabled }+ { lex_qquasiquote_tok }++ $unigraphic -- ⟦+ / { ifCurrentChar '⟦' `alexAndPred`+ ifExtension (\i -> unicodeSyntaxEnabled i && thQuotesEnabled i) }+ { token (ITopenExpQuote NoE UnicodeSyntax) }+ $unigraphic -- ⟧+ / { ifCurrentChar '⟧' `alexAndPred`+ ifExtension (\i -> unicodeSyntaxEnabled i && thQuotesEnabled i) }+ { token (ITcloseQuote UnicodeSyntax) }+}++ -- See Note [Lexing type applications]+<0> {+ [^ $idchar \) ] ^+ "@"+ / { ifExtension typeApplicationEnabled `alexAndPred` notFollowedBySymbol }+ { token ITtypeApp }+}++<0> {+ "(|" / { ifExtension arrowsEnabled `alexAndPred` notFollowedBySymbol }+ { special (IToparenbar NormalSyntax) }+ "|)" / { ifExtension arrowsEnabled } { special (ITcparenbar NormalSyntax) }++ $unigraphic -- ⦇+ / { ifCurrentChar '⦇' `alexAndPred`+ ifExtension (\i -> unicodeSyntaxEnabled i && arrowsEnabled i) }+ { special (IToparenbar UnicodeSyntax) }+ $unigraphic -- ⦈+ / { ifCurrentChar '⦈' `alexAndPred`+ ifExtension (\i -> unicodeSyntaxEnabled i && arrowsEnabled i) }+ { special (ITcparenbar UnicodeSyntax) }+}++<0> {+ \? @varid / { ifExtension ipEnabled } { skip_one_varid ITdupipvarid }+}++<0> {+ "#" @varid / { ifExtension overloadedLabelsEnabled }+ { skip_one_varid ITlabelvarid }+}++<0> {+ "(#" / { orExtensions unboxedTuplesEnabled unboxedSumsEnabled }+ { token IToubxparen }+ "#)" / { orExtensions unboxedTuplesEnabled unboxedSumsEnabled }+ { token ITcubxparen }+}++<0,option_prags> {+ \( { special IToparen }+ \) { special ITcparen }+ \[ { special ITobrack }+ \] { special ITcbrack }+ \, { special ITcomma }+ \; { special ITsemi }+ \` { special ITbackquote }++ \{ { open_brace }+ \} { close_brace }+}++<0,option_prags> {+ @qvarid { idtoken qvarid }+ @qconid { idtoken qconid }+ @varid { varid }+ @conid { idtoken conid }+}++<0> {+ @qvarid "#"+ / { ifExtension magicHashEnabled } { idtoken qvarid }+ @qconid "#"+ / { ifExtension magicHashEnabled } { idtoken qconid }+ @varid "#"+ / { ifExtension magicHashEnabled } { varid }+ @conid "#"+ / { ifExtension magicHashEnabled } { idtoken conid }+}++-- ToDo: - move `var` and (sym) into lexical syntax?+-- - remove backquote from $special?+<0> {+ @qvarsym { idtoken qvarsym }+ @qconsym { idtoken qconsym }+ @varsym { varsym }+ @consym { consym }+}++-- For the normal boxed literals we need to be careful+-- when trying to be close to Haskell98+<0> {+ -- Normal integral literals (:: Num a => a, from Integer)+ @decimal { tok_num positive 0 0 decimal }+ 0[bB] @binary / { ifExtension binaryLiteralsEnabled } { tok_num positive 2 2 binary }+ 0[oO] @octal { tok_num positive 2 2 octal }+ 0[xX] @hexadecimal { tok_num positive 2 2 hexadecimal }+ @negative @decimal / { ifExtension negativeLiteralsEnabled } { tok_num negative 1 1 decimal }+ @negative 0[bB] @binary / { ifExtension negativeLiteralsEnabled `alexAndPred`+ ifExtension binaryLiteralsEnabled } { tok_num negative 3 3 binary }+ @negative 0[oO] @octal / { ifExtension negativeLiteralsEnabled } { tok_num negative 3 3 octal }+ @negative 0[xX] @hexadecimal / { ifExtension negativeLiteralsEnabled } { tok_num negative 3 3 hexadecimal }++ -- Normal rational literals (:: Fractional a => a, from Rational)+ @floating_point { strtoken tok_float }+ @negative @floating_point / { ifExtension negativeLiteralsEnabled } { strtoken tok_float }+}++<0> {+ -- Unboxed ints (:: Int#) and words (:: Word#)+ -- It's simpler (and faster?) to give separate cases to the negatives,+ -- especially considering octal/hexadecimal prefixes.+ @decimal \# / { ifExtension magicHashEnabled } { tok_primint positive 0 1 decimal }+ 0[bB] @binary \# / { ifExtension magicHashEnabled `alexAndPred`+ ifExtension binaryLiteralsEnabled } { tok_primint positive 2 3 binary }+ 0[oO] @octal \# / { ifExtension magicHashEnabled } { tok_primint positive 2 3 octal }+ 0[xX] @hexadecimal \# / { ifExtension magicHashEnabled } { tok_primint positive 2 3 hexadecimal }+ @negative @decimal \# / { ifExtension magicHashEnabled } { tok_primint negative 1 2 decimal }+ @negative 0[bB] @binary \# / { ifExtension magicHashEnabled `alexAndPred`+ ifExtension binaryLiteralsEnabled } { tok_primint negative 3 4 binary }+ @negative 0[oO] @octal \# / { ifExtension magicHashEnabled } { tok_primint negative 3 4 octal }+ @negative 0[xX] @hexadecimal \# / { ifExtension magicHashEnabled } { tok_primint negative 3 4 hexadecimal }++ @decimal \# \# / { ifExtension magicHashEnabled } { tok_primword 0 2 decimal }+ 0[bB] @binary \# \# / { ifExtension magicHashEnabled `alexAndPred`+ ifExtension binaryLiteralsEnabled } { tok_primword 2 4 binary }+ 0[oO] @octal \# \# / { ifExtension magicHashEnabled } { tok_primword 2 4 octal }+ 0[xX] @hexadecimal \# \# / { ifExtension magicHashEnabled } { tok_primword 2 4 hexadecimal }++ -- Unboxed floats and doubles (:: Float#, :: Double#)+ -- prim_{float,double} work with signed literals+ @signed @floating_point \# / { ifExtension magicHashEnabled } { init_strtoken 1 tok_primfloat }+ @signed @floating_point \# \# / { ifExtension magicHashEnabled } { init_strtoken 2 tok_primdouble }+}++-- Strings and chars are lexed by hand-written code. The reason is+-- that even if we recognise the string or char here in the regex+-- lexer, we would still have to parse the string afterward in order+-- to convert it to a String.+<0> {+ \' { lex_char_tok }+ \" { lex_string_tok }+}++-- Note [Lexing type applications]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- The desired syntax for type applications is to prefix the type application+-- with '@', like this:+--+-- foo @Int @Bool baz bum+--+-- This, of course, conflicts with as-patterns. The conflict arises because+-- expressions and patterns use the same parser, and also because we want+-- to allow type patterns within expression patterns.+--+-- Disambiguation is accomplished by requiring *something* to appear between+-- type application and the preceding token. This something must end with+-- a character that cannot be the end of the variable bound in an as-pattern.+-- Currently (June 2015), this means that the something cannot end with a+-- $idchar or a close-paren. (The close-paren is necessary if the as-bound+-- identifier is symbolic.)+--+-- Note that looking for whitespace before the '@' is insufficient, because+-- of this pathological case:+--+-- foo {- hi -}@Int+--+-- This design is predicated on the fact that as-patterns are generally+-- whitespace-free, and also that this whole thing is opt-in, with the+-- TypeApplications extension.++-- -----------------------------------------------------------------------------+-- Alex "Haskell code fragment bottom"++{++-- -----------------------------------------------------------------------------+-- The token type++data Token+ = ITas -- Haskell keywords+ | ITcase+ | ITclass+ | ITdata+ | ITdefault+ | ITderiving+ | ITdo+ | ITelse+ | IThiding+ | ITforeign+ | ITif+ | ITimport+ | ITin+ | ITinfix+ | ITinfixl+ | ITinfixr+ | ITinstance+ | ITlet+ | ITmodule+ | ITnewtype+ | ITof+ | ITqualified+ | ITthen+ | ITtype+ | ITwhere++ | ITforall IsUnicodeSyntax -- GHC extension keywords+ | ITexport+ | ITlabel+ | ITdynamic+ | ITsafe+ | ITinterruptible+ | ITunsafe+ | ITstdcallconv+ | ITccallconv+ | ITcapiconv+ | ITprimcallconv+ | ITjavascriptcallconv+ | ITmdo+ | ITfamily+ | ITrole+ | ITgroup+ | ITby+ | ITusing+ | ITpattern+ | ITstatic+ | ITstock+ | ITanyclass++ -- Backpack tokens+ | ITunit+ | ITsignature+ | ITdependency+ | ITrequires++ -- Pragmas, see note [Pragma source text] in BasicTypes+ | ITinline_prag SourceText InlineSpec RuleMatchInfo+ | ITspec_prag SourceText -- SPECIALISE+ | ITspec_inline_prag SourceText Bool -- SPECIALISE INLINE (or NOINLINE)+ | ITsource_prag SourceText+ | ITrules_prag SourceText+ | ITwarning_prag SourceText+ | ITdeprecated_prag SourceText+ | ITline_prag+ | ITscc_prag SourceText+ | ITgenerated_prag SourceText+ | ITcore_prag SourceText -- hdaume: core annotations+ | ITunpack_prag SourceText+ | ITnounpack_prag SourceText+ | ITann_prag SourceText+ | ITcomplete_prag SourceText+ | ITclose_prag+ | IToptions_prag String+ | ITinclude_prag String+ | ITlanguage_prag+ | ITvect_prag SourceText+ | ITvect_scalar_prag SourceText+ | ITnovect_prag SourceText+ | ITminimal_prag SourceText+ | IToverlappable_prag SourceText -- instance overlap mode+ | IToverlapping_prag SourceText -- instance overlap mode+ | IToverlaps_prag SourceText -- instance overlap mode+ | ITincoherent_prag SourceText -- instance overlap mode+ | ITctype SourceText++ | ITdotdot -- reserved symbols+ | ITcolon+ | ITdcolon IsUnicodeSyntax+ | ITequal+ | ITlam+ | ITlcase+ | ITvbar+ | ITlarrow IsUnicodeSyntax+ | ITrarrow IsUnicodeSyntax+ | ITat+ | ITtilde+ | ITtildehsh+ | ITdarrow IsUnicodeSyntax+ | ITminus+ | ITbang+ | ITdot++ | ITbiglam -- GHC-extension symbols++ | ITocurly -- special symbols+ | ITccurly+ | ITvocurly+ | ITvccurly+ | ITobrack+ | ITopabrack -- [:, for parallel arrays with -XParallelArrays+ | ITcpabrack -- :], for parallel arrays with -XParallelArrays+ | ITcbrack+ | IToparen+ | ITcparen+ | IToubxparen+ | ITcubxparen+ | ITsemi+ | ITcomma+ | ITunderscore+ | ITbackquote+ | ITsimpleQuote -- '++ | ITvarid FastString -- identifiers+ | ITconid FastString+ | ITvarsym FastString+ | ITconsym FastString+ | ITqvarid (FastString,FastString)+ | ITqconid (FastString,FastString)+ | ITqvarsym (FastString,FastString)+ | ITqconsym (FastString,FastString)++ | ITdupipvarid FastString -- GHC extension: implicit param: ?x+ | ITlabelvarid FastString -- Overloaded label: #x++ | ITchar SourceText Char -- Note [Literal source text] in BasicTypes+ | ITstring SourceText FastString -- Note [Literal source text] in BasicTypes+ | ITinteger SourceText Integer -- Note [Literal source text] in BasicTypes+ | ITrational FractionalLit++ | ITprimchar SourceText Char -- Note [Literal source text] in BasicTypes+ | ITprimstring SourceText ByteString -- Note [Literal source text] @BasicTypes+ | ITprimint SourceText Integer -- Note [Literal source text] in BasicTypes+ | ITprimword SourceText Integer -- Note [Literal source text] in BasicTypes+ | ITprimfloat FractionalLit+ | ITprimdouble FractionalLit++ -- Template Haskell extension tokens+ | ITopenExpQuote HasE IsUnicodeSyntax -- [| or [e|+ | ITopenPatQuote -- [p|+ | ITopenDecQuote -- [d|+ | ITopenTypQuote -- [t|+ | ITcloseQuote IsUnicodeSyntax -- |]+ | ITopenTExpQuote HasE -- [|| or [e||+ | ITcloseTExpQuote -- ||]+ | ITidEscape FastString -- $x+ | ITparenEscape -- $(+ | ITidTyEscape FastString -- $$x+ | ITparenTyEscape -- $$(+ | ITtyQuote -- ''+ | ITquasiQuote (FastString,FastString,RealSrcSpan)+ -- ITquasiQuote(quoter, quote, loc)+ -- represents a quasi-quote of the form+ -- [quoter| quote |]+ | ITqQuasiQuote (FastString,FastString,FastString,RealSrcSpan)+ -- ITqQuasiQuote(Qual, quoter, quote, loc)+ -- represents a qualified quasi-quote of the form+ -- [Qual.quoter| quote |]++ -- Arrow notation extension+ | ITproc+ | ITrec+ | IToparenbar IsUnicodeSyntax -- (|+ | ITcparenbar IsUnicodeSyntax -- |)+ | ITlarrowtail IsUnicodeSyntax -- -<+ | ITrarrowtail IsUnicodeSyntax -- >-+ | ITLarrowtail IsUnicodeSyntax -- -<<+ | ITRarrowtail IsUnicodeSyntax -- >>-++ -- type application '@' (lexed differently than as-pattern '@',+ -- due to checking for preceding whitespace)+ | ITtypeApp+++ | ITunknown String -- Used when the lexer can't make sense of it+ | ITeof -- end of file token++ -- Documentation annotations+ | ITdocCommentNext String -- something beginning '-- |'+ | ITdocCommentPrev String -- something beginning '-- ^'+ | ITdocCommentNamed String -- something beginning '-- $'+ | ITdocSection Int String -- a section heading+ | ITdocOptions String -- doc options (prune, ignore-exports, etc)+ | ITlineComment String -- comment starting by "--"+ | ITblockComment String -- comment in {- -}++ deriving Show++instance Outputable Token where+ ppr x = text (show x)+++-- the bitmap provided as the third component indicates whether the+-- corresponding extension keyword is valid under the extension options+-- provided to the compiler; if the extension corresponding to *any* of the+-- bits set in the bitmap is enabled, the keyword is valid (this setup+-- facilitates using a keyword in two different extensions that can be+-- activated independently)+--+reservedWordsFM :: UniqFM (Token, ExtsBitmap)+reservedWordsFM = listToUFM $+ map (\(x, y, z) -> (mkFastString x, (y, z)))+ [( "_", ITunderscore, 0 ),+ ( "as", ITas, 0 ),+ ( "case", ITcase, 0 ),+ ( "class", ITclass, 0 ),+ ( "data", ITdata, 0 ),+ ( "default", ITdefault, 0 ),+ ( "deriving", ITderiving, 0 ),+ ( "do", ITdo, 0 ),+ ( "else", ITelse, 0 ),+ ( "hiding", IThiding, 0 ),+ ( "if", ITif, 0 ),+ ( "import", ITimport, 0 ),+ ( "in", ITin, 0 ),+ ( "infix", ITinfix, 0 ),+ ( "infixl", ITinfixl, 0 ),+ ( "infixr", ITinfixr, 0 ),+ ( "instance", ITinstance, 0 ),+ ( "let", ITlet, 0 ),+ ( "module", ITmodule, 0 ),+ ( "newtype", ITnewtype, 0 ),+ ( "of", ITof, 0 ),+ ( "qualified", ITqualified, 0 ),+ ( "then", ITthen, 0 ),+ ( "type", ITtype, 0 ),+ ( "where", ITwhere, 0 ),++ ( "forall", ITforall NormalSyntax,+ xbit ExplicitForallBit .|.+ xbit InRulePragBit),+ ( "mdo", ITmdo, xbit RecursiveDoBit),+ -- See Note [Lexing type pseudo-keywords]+ ( "family", ITfamily, 0 ),+ ( "role", ITrole, 0 ),+ ( "pattern", ITpattern, xbit PatternSynonymsBit),+ ( "static", ITstatic, 0 ),+ ( "stock", ITstock, 0 ),+ ( "anyclass", ITanyclass, 0 ),+ ( "group", ITgroup, xbit TransformComprehensionsBit),+ ( "by", ITby, xbit TransformComprehensionsBit),+ ( "using", ITusing, xbit TransformComprehensionsBit),++ ( "foreign", ITforeign, xbit FfiBit),+ ( "export", ITexport, xbit FfiBit),+ ( "label", ITlabel, xbit FfiBit),+ ( "dynamic", ITdynamic, xbit FfiBit),+ ( "safe", ITsafe, xbit FfiBit .|.+ xbit SafeHaskellBit),+ ( "interruptible", ITinterruptible, xbit InterruptibleFfiBit),+ ( "unsafe", ITunsafe, xbit FfiBit),+ ( "stdcall", ITstdcallconv, xbit FfiBit),+ ( "ccall", ITccallconv, xbit FfiBit),+ ( "capi", ITcapiconv, xbit CApiFfiBit),+ ( "prim", ITprimcallconv, xbit FfiBit),+ ( "javascript", ITjavascriptcallconv, xbit FfiBit),++ ( "unit", ITunit, 0 ),+ ( "dependency", ITdependency, 0 ),+ ( "signature", ITsignature, 0 ),++ ( "rec", ITrec, xbit ArrowsBit .|.+ xbit RecursiveDoBit),+ ( "proc", ITproc, xbit ArrowsBit)+ ]++{-----------------------------------+Note [Lexing type pseudo-keywords]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++One might think that we wish to treat 'family' and 'role' as regular old+varids whenever -XTypeFamilies and -XRoleAnnotations are off, respectively.+But, there is no need to do so. These pseudo-keywords are not stolen syntax:+they are only used after the keyword 'type' at the top-level, where varids are+not allowed. Furthermore, checks further downstream (TcTyClsDecls) ensure that+type families and role annotations are never declared without their extensions+on. In fact, by unconditionally lexing these pseudo-keywords as special, we+can get better error messages.++Also, note that these are included in the `varid` production in the parser --+a key detail to make all this work.+-------------------------------------}++reservedSymsFM :: UniqFM (Token, ExtsBitmap -> Bool)+reservedSymsFM = listToUFM $+ map (\ (x,y,z) -> (mkFastString x,(y,z)))+ [ ("..", ITdotdot, always)+ -- (:) is a reserved op, meaning only list cons+ ,(":", ITcolon, always)+ ,("::", ITdcolon NormalSyntax, always)+ ,("=", ITequal, always)+ ,("\\", ITlam, always)+ ,("|", ITvbar, always)+ ,("<-", ITlarrow NormalSyntax, always)+ ,("->", ITrarrow NormalSyntax, always)+ ,("@", ITat, always)+ ,("~", ITtilde, always)+ ,("~#", ITtildehsh, magicHashEnabled)+ ,("=>", ITdarrow NormalSyntax, always)+ ,("-", ITminus, always)+ ,("!", ITbang, always)++ -- For 'forall a . t'+ ,(".", ITdot, always) -- \i -> explicitForallEnabled i || inRulePrag i)++ ,("-<", ITlarrowtail NormalSyntax, arrowsEnabled)+ ,(">-", ITrarrowtail NormalSyntax, arrowsEnabled)+ ,("-<<", ITLarrowtail NormalSyntax, arrowsEnabled)+ ,(">>-", ITRarrowtail NormalSyntax, arrowsEnabled)++ ,("∷", ITdcolon UnicodeSyntax, unicodeSyntaxEnabled)+ ,("⇒", ITdarrow UnicodeSyntax, unicodeSyntaxEnabled)+ ,("∀", ITforall UnicodeSyntax, unicodeSyntaxEnabled)+ ,("→", ITrarrow UnicodeSyntax, unicodeSyntaxEnabled)+ ,("←", ITlarrow UnicodeSyntax, unicodeSyntaxEnabled)++ ,("⤙", ITlarrowtail UnicodeSyntax,+ \i -> unicodeSyntaxEnabled i && arrowsEnabled i)+ ,("⤚", ITrarrowtail UnicodeSyntax,+ \i -> unicodeSyntaxEnabled i && arrowsEnabled i)+ ,("⤛", ITLarrowtail UnicodeSyntax,+ \i -> unicodeSyntaxEnabled i && arrowsEnabled i)+ ,("⤜", ITRarrowtail UnicodeSyntax,+ \i -> unicodeSyntaxEnabled i && arrowsEnabled i)++ -- ToDo: ideally, → and ∷ should be "specials", so that they cannot+ -- form part of a large operator. This would let us have a better+ -- syntax for kinds: ɑ∷*→* would be a legal kind signature. (maybe).+ ]++-- -----------------------------------------------------------------------------+-- Lexer actions++type Action = RealSrcSpan -> StringBuffer -> Int -> P (RealLocated Token)++special :: Token -> Action+special tok span _buf _len = return (L span tok)++token, layout_token :: Token -> Action+token t span _buf _len = return (L span t)+layout_token t span _buf _len = pushLexState layout >> return (L span t)++idtoken :: (StringBuffer -> Int -> Token) -> Action+idtoken f span buf len = return (L span $! (f buf len))++skip_one_varid :: (FastString -> Token) -> Action+skip_one_varid f span buf len+ = return (L span $! f (lexemeToFastString (stepOn buf) (len-1)))++skip_two_varid :: (FastString -> Token) -> Action+skip_two_varid f span buf len+ = return (L span $! f (lexemeToFastString (stepOn (stepOn buf)) (len-2)))++strtoken :: (String -> Token) -> Action+strtoken f span buf len =+ return (L span $! (f $! lexemeToString buf len))++init_strtoken :: Int -> (String -> Token) -> Action+-- like strtoken, but drops the last N character(s)+init_strtoken drop f span buf len =+ return (L span $! (f $! lexemeToString buf (len-drop)))++begin :: Int -> Action+begin code _span _str _len = do pushLexState code; lexToken++pop :: Action+pop _span _buf _len = do _ <- popLexState+ lexToken++hopefully_open_brace :: Action+hopefully_open_brace span buf len+ = do relaxed <- extension relaxedLayout+ ctx <- getContext+ (AI l _) <- getInput+ let offset = srcLocCol l+ isOK = relaxed ||+ case ctx of+ Layout prev_off _ : _ -> prev_off < offset+ _ -> True+ if isOK then pop_and open_brace span buf len+ else failSpanMsgP (RealSrcSpan span) (text "Missing block")++pop_and :: Action -> Action+pop_and act span buf len = do _ <- popLexState+ act span buf len++{-# INLINE nextCharIs #-}+nextCharIs :: StringBuffer -> (Char -> Bool) -> Bool+nextCharIs buf p = not (atEnd buf) && p (currentChar buf)++{-# INLINE nextCharIsNot #-}+nextCharIsNot :: StringBuffer -> (Char -> Bool) -> Bool+nextCharIsNot buf p = not (nextCharIs buf p)++notFollowedBy :: Char -> AlexAccPred ExtsBitmap+notFollowedBy char _ _ _ (AI _ buf)+ = nextCharIsNot buf (== char)++notFollowedBySymbol :: AlexAccPred ExtsBitmap+notFollowedBySymbol _ _ _ (AI _ buf)+ = nextCharIsNot buf (`elem` "!#$%&*+./<=>?@\\^|-~")++followedByDigit :: AlexAccPred ExtsBitmap+followedByDigit _ _ _ (AI _ buf)+ = afterOptionalSpace buf (\b -> nextCharIs b (`elem` ['0'..'9']))++ifCurrentChar :: Char -> AlexAccPred ExtsBitmap+ifCurrentChar char _ (AI _ buf) _ _+ = nextCharIs buf (== char)++-- We must reject doc comments as being ordinary comments everywhere.+-- In some cases the doc comment will be selected as the lexeme due to+-- maximal munch, but not always, because the nested comment rule is+-- valid in all states, but the doc-comment rules are only valid in+-- the non-layout states.+isNormalComment :: AlexAccPred ExtsBitmap+isNormalComment bits _ _ (AI _ buf)+ | haddockEnabled bits = notFollowedByDocOrPragma+ | otherwise = nextCharIsNot buf (== '#')+ where+ notFollowedByDocOrPragma+ = afterOptionalSpace buf (\b -> nextCharIsNot b (`elem` "|^*$#"))++afterOptionalSpace :: StringBuffer -> (StringBuffer -> Bool) -> Bool+afterOptionalSpace buf p+ = if nextCharIs buf (== ' ')+ then p (snd (nextChar buf))+ else p buf++atEOL :: AlexAccPred ExtsBitmap+atEOL _ _ _ (AI _ buf) = atEnd buf || currentChar buf == '\n'++ifExtension :: (ExtsBitmap -> Bool) -> AlexAccPred ExtsBitmap+ifExtension pred bits _ _ _ = pred bits++orExtensions :: (ExtsBitmap -> Bool) -> (ExtsBitmap -> Bool) -> AlexAccPred ExtsBitmap+orExtensions pred1 pred2 bits _ _ _ = pred1 bits || pred2 bits++multiline_doc_comment :: Action+multiline_doc_comment span buf _len = withLexedDocType (worker "")+ where+ worker commentAcc input docType checkNextLine = case alexGetChar' input of+ Just ('\n', input')+ | checkNextLine -> case checkIfCommentLine input' of+ Just input -> worker ('\n':commentAcc) input docType checkNextLine+ Nothing -> docCommentEnd input commentAcc docType buf span+ | otherwise -> docCommentEnd input commentAcc docType buf span+ Just (c, input) -> worker (c:commentAcc) input docType checkNextLine+ Nothing -> docCommentEnd input commentAcc docType buf span++ -- Check if the next line of input belongs to this doc comment as well.+ -- A doc comment continues onto the next line when the following+ -- conditions are met:+ -- * The line starts with "--"+ -- * The line doesn't start with "---".+ -- * The line doesn't start with "-- $", because that would be the+ -- start of a /new/ named haddock chunk (#10398).+ checkIfCommentLine :: AlexInput -> Maybe AlexInput+ checkIfCommentLine input = check (dropNonNewlineSpace input)+ where+ check input = do+ ('-', input) <- alexGetChar' input+ ('-', input) <- alexGetChar' input+ (c, after_c) <- alexGetChar' input+ case c of+ '-' -> Nothing+ ' ' -> case alexGetChar' after_c of+ Just ('$', _) -> Nothing+ _ -> Just input+ _ -> Just input++ dropNonNewlineSpace input = case alexGetChar' input of+ Just (c, input')+ | isSpace c && c /= '\n' -> dropNonNewlineSpace input'+ | otherwise -> input+ Nothing -> input++lineCommentToken :: Action+lineCommentToken span buf len = do+ b <- extension rawTokenStreamEnabled+ if b then strtoken ITlineComment span buf len else lexToken++{-+ nested comments require traversing by hand, they can't be parsed+ using regular expressions.+-}+nested_comment :: P (RealLocated Token) -> Action+nested_comment cont span buf len = do+ input <- getInput+ go (reverse $ lexemeToString buf len) (1::Int) input+ where+ go commentAcc 0 input = do+ setInput input+ b <- extension rawTokenStreamEnabled+ if b+ then docCommentEnd input commentAcc ITblockComment buf span+ else cont+ go commentAcc n input = case alexGetChar' input of+ Nothing -> errBrace input span+ Just ('-',input) -> case alexGetChar' input of+ Nothing -> errBrace input span+ Just ('\125',input) -> go ('\125':'-':commentAcc) (n-1) input -- '}'+ Just (_,_) -> go ('-':commentAcc) n input+ Just ('\123',input) -> case alexGetChar' input of -- '{' char+ Nothing -> errBrace input span+ Just ('-',input) -> go ('-':'\123':commentAcc) (n+1) input+ Just (_,_) -> go ('\123':commentAcc) n input+ Just (c,input) -> go (c:commentAcc) n input++nested_doc_comment :: Action+nested_doc_comment span buf _len = withLexedDocType (go "")+ where+ go commentAcc input docType _ = case alexGetChar' input of+ Nothing -> errBrace input span+ Just ('-',input) -> case alexGetChar' input of+ Nothing -> errBrace input span+ Just ('\125',input) ->+ docCommentEnd input commentAcc docType buf span+ Just (_,_) -> go ('-':commentAcc) input docType False+ Just ('\123', input) -> case alexGetChar' input of+ Nothing -> errBrace input span+ Just ('-',input) -> do+ setInput input+ let cont = do input <- getInput; go commentAcc input docType False+ nested_comment cont span buf _len+ Just (_,_) -> go ('\123':commentAcc) input docType False+ Just (c,input) -> go (c:commentAcc) input docType False++withLexedDocType :: (AlexInput -> (String -> Token) -> Bool -> P (RealLocated Token))+ -> P (RealLocated Token)+withLexedDocType lexDocComment = do+ input@(AI _ buf) <- getInput+ case prevChar buf ' ' of+ -- The `Bool` argument to lexDocComment signals whether or not the next+ -- line of input might also belong to this doc comment.+ '|' -> lexDocComment input ITdocCommentNext True+ '^' -> lexDocComment input ITdocCommentPrev True+ '$' -> lexDocComment input ITdocCommentNamed True+ '*' -> lexDocSection 1 input+ _ -> panic "withLexedDocType: Bad doc type"+ where+ lexDocSection n input = case alexGetChar' input of+ Just ('*', input) -> lexDocSection (n+1) input+ Just (_, _) -> lexDocComment input (ITdocSection n) False+ Nothing -> do setInput input; lexToken -- eof reached, lex it normally++-- RULES pragmas turn on the forall and '.' keywords, and we turn them+-- off again at the end of the pragma.+rulePrag :: Action+rulePrag span buf len = do+ setExts (.|. xbit InRulePragBit)+ let !src = lexemeToString buf len+ return (L span (ITrules_prag (SourceText src)))++endPrag :: Action+endPrag span _buf _len = do+ setExts (.&. complement (xbit InRulePragBit))+ return (L span ITclose_prag)++-- docCommentEnd+-------------------------------------------------------------------------------+-- This function is quite tricky. We can't just return a new token, we also+-- need to update the state of the parser. Why? Because the token is longer+-- than what was lexed by Alex, and the lexToken function doesn't know this, so+-- it writes the wrong token length to the parser state. This function is+-- called afterwards, so it can just update the state.++docCommentEnd :: AlexInput -> String -> (String -> Token) -> StringBuffer ->+ RealSrcSpan -> P (RealLocated Token)+docCommentEnd input commentAcc docType buf span = do+ setInput input+ let (AI loc nextBuf) = input+ comment = reverse commentAcc+ span' = mkRealSrcSpan (realSrcSpanStart span) loc+ last_len = byteDiff buf nextBuf++ span `seq` setLastToken span' last_len+ return (L span' (docType comment))++errBrace :: AlexInput -> RealSrcSpan -> P a+errBrace (AI end _) span = failLocMsgP (realSrcSpanStart span) end "unterminated `{-'"++open_brace, close_brace :: Action+open_brace span _str _len = do+ ctx <- getContext+ setContext (NoLayout:ctx)+ return (L span ITocurly)+close_brace span _str _len = do+ popContext+ return (L span ITccurly)++qvarid, qconid :: StringBuffer -> Int -> Token+qvarid buf len = ITqvarid $! splitQualName buf len False+qconid buf len = ITqconid $! splitQualName buf len False++splitQualName :: StringBuffer -> Int -> Bool -> (FastString,FastString)+-- takes a StringBuffer and a length, and returns the module name+-- and identifier parts of a qualified name. Splits at the *last* dot,+-- because of hierarchical module names.+splitQualName orig_buf len parens = split orig_buf orig_buf+ where+ split buf dot_buf+ | orig_buf `byteDiff` buf >= len = done dot_buf+ | c == '.' = found_dot buf'+ | otherwise = split buf' dot_buf+ where+ (c,buf') = nextChar buf++ -- careful, we might get names like M....+ -- so, if the character after the dot is not upper-case, this is+ -- the end of the qualifier part.+ found_dot buf -- buf points after the '.'+ | isUpper c = split buf' buf+ | otherwise = done buf+ where+ (c,buf') = nextChar buf++ done dot_buf =+ (lexemeToFastString orig_buf (qual_size - 1),+ if parens -- Prelude.(+)+ then lexemeToFastString (stepOn dot_buf) (len - qual_size - 2)+ else lexemeToFastString dot_buf (len - qual_size))+ where+ qual_size = orig_buf `byteDiff` dot_buf++varid :: Action+varid span buf len =+ case lookupUFM reservedWordsFM fs of+ Just (ITcase, _) -> do+ lambdaCase <- extension lambdaCaseEnabled+ keyword <- if lambdaCase+ then do+ lastTk <- getLastTk+ return $ case lastTk of+ Just ITlam -> ITlcase+ _ -> ITcase+ else+ return ITcase+ maybe_layout keyword+ return $ L span keyword+ Just (ITstatic, _) -> do+ staticPointers <- extension staticPointersEnabled+ if staticPointers+ then return $ L span ITstatic+ else return $ L span $ ITvarid fs+ Just (keyword, 0) -> do+ maybe_layout keyword+ return $ L span keyword+ Just (keyword, exts) -> do+ extsEnabled <- extension $ \i -> exts .&. i /= 0+ if extsEnabled+ then do+ maybe_layout keyword+ return $ L span keyword+ else+ return $ L span $ ITvarid fs+ Nothing ->+ return $ L span $ ITvarid fs+ where+ !fs = lexemeToFastString buf len++conid :: StringBuffer -> Int -> Token+conid buf len = ITconid $! lexemeToFastString buf len++qvarsym, qconsym :: StringBuffer -> Int -> Token+qvarsym buf len = ITqvarsym $! splitQualName buf len False+qconsym buf len = ITqconsym $! splitQualName buf len False++varsym, consym :: Action+varsym = sym ITvarsym+consym = sym ITconsym++sym :: (FastString -> Token) -> Action+sym con span buf len =+ case lookupUFM reservedSymsFM fs of+ Just (keyword, exts) -> do+ extsEnabled <- extension exts+ let !tk | extsEnabled = keyword+ | otherwise = con fs+ return $ L span tk+ Nothing ->+ return $ L span $! con fs+ where+ !fs = lexemeToFastString buf len++-- Variations on the integral numeric literal.+tok_integral :: (SourceText -> Integer -> Token)+ -> (Integer -> Integer)+ -> Int -> Int+ -> (Integer, (Char -> Int))+ -> Action+tok_integral itint transint transbuf translen (radix,char_to_int) span buf len+ = return $ L span $ itint (SourceText $ lexemeToString buf len)+ $! transint $ parseUnsignedInteger+ (offsetBytes transbuf buf) (subtract translen len) radix char_to_int++-- some conveniences for use with tok_integral+tok_num :: (Integer -> Integer)+ -> Int -> Int+ -> (Integer, (Char->Int)) -> Action+tok_num = tok_integral ITinteger+tok_primint :: (Integer -> Integer)+ -> Int -> Int+ -> (Integer, (Char->Int)) -> Action+tok_primint = tok_integral ITprimint+tok_primword :: Int -> Int+ -> (Integer, (Char->Int)) -> Action+tok_primword = tok_integral ITprimword positive+positive, negative :: (Integer -> Integer)+positive = id+negative = negate+decimal, octal, hexadecimal :: (Integer, Char -> Int)+decimal = (10,octDecDigit)+binary = (2,octDecDigit)+octal = (8,octDecDigit)+hexadecimal = (16,hexDigit)++-- readRational can understand negative rationals, exponents, everything.+tok_float, tok_primfloat, tok_primdouble :: String -> Token+tok_float str = ITrational $! readFractionalLit str+tok_primfloat str = ITprimfloat $! readFractionalLit str+tok_primdouble str = ITprimdouble $! readFractionalLit str++readFractionalLit :: String -> FractionalLit+readFractionalLit str = (FL $! str) $! readRational str++-- -----------------------------------------------------------------------------+-- Layout processing++-- we're at the first token on a line, insert layout tokens if necessary+do_bol :: Action+do_bol span _str _len = do+ (pos, gen_semic) <- getOffside+ case pos of+ LT -> do+ --trace "layout: inserting '}'" $ do+ popContext+ -- do NOT pop the lex state, we might have a ';' to insert+ return (L span ITvccurly)+ EQ | gen_semic -> do+ --trace "layout: inserting ';'" $ do+ _ <- popLexState+ return (L span ITsemi)+ _ -> do+ _ <- popLexState+ lexToken++-- certain keywords put us in the "layout" state, where we might+-- add an opening curly brace.+maybe_layout :: Token -> P ()+maybe_layout t = do -- If the alternative layout rule is enabled then+ -- we never create an implicit layout context here.+ -- Layout is handled XXX instead.+ -- The code for closing implicit contexts, or+ -- inserting implicit semi-colons, is therefore+ -- irrelevant as it only applies in an implicit+ -- context.+ alr <- extension alternativeLayoutRule+ unless alr $ f t+ where f ITdo = pushLexState layout_do+ f ITmdo = pushLexState layout_do+ f ITof = pushLexState layout+ f ITlcase = pushLexState layout+ f ITlet = pushLexState layout+ f ITwhere = pushLexState layout+ f ITrec = pushLexState layout+ f ITif = pushLexState layout_if+ f _ = return ()++-- Pushing a new implicit layout context. If the indentation of the+-- next token is not greater than the previous layout context, then+-- Haskell 98 says that the new layout context should be empty; that is+-- the lexer must generate {}.+--+-- We are slightly more lenient than this: when the new context is started+-- by a 'do', then we allow the new context to be at the same indentation as+-- the previous context. This is what the 'strict' argument is for.+new_layout_context :: Bool -> Bool -> Token -> Action+new_layout_context strict gen_semic tok span _buf len = do+ _ <- popLexState+ (AI l _) <- getInput+ let offset = srcLocCol l - len+ ctx <- getContext+ nondecreasing <- extension nondecreasingIndentation+ let strict' = strict || not nondecreasing+ case ctx of+ Layout prev_off _ : _ |+ (strict' && prev_off >= offset ||+ not strict' && prev_off > offset) -> do+ -- token is indented to the left of the previous context.+ -- we must generate a {} sequence now.+ pushLexState layout_left+ return (L span tok)+ _ -> do setContext (Layout offset gen_semic : ctx)+ return (L span tok)++do_layout_left :: Action+do_layout_left span _buf _len = do+ _ <- popLexState+ pushLexState bol -- we must be at the start of a line+ return (L span ITvccurly)++-- -----------------------------------------------------------------------------+-- LINE pragmas++setLine :: Int -> Action+setLine code span buf len = do+ let line = parseUnsignedInteger buf len 10 octDecDigit+ setSrcLoc (mkRealSrcLoc (srcSpanFile span) (fromIntegral line - 1) 1)+ -- subtract one: the line number refers to the *following* line+ _ <- popLexState+ pushLexState code+ lexToken++setColumn :: Action+setColumn span buf len = do+ let column =+ case reads (lexemeToString buf len) of+ [(column, _)] -> column+ _ -> error "setColumn: expected integer" -- shouldn't happen+ setSrcLoc (mkRealSrcLoc (srcSpanFile span) (srcSpanEndLine span)+ (fromIntegral (column :: Integer)))+ _ <- popLexState+ lexToken++setFile :: Int -> Action+setFile code span buf len = do+ let file = mkFastString (go (lexemeToString (stepOn buf) (len-2)))+ where go ('\\':c:cs) = c : go cs+ go (c:cs) = c : go cs+ go [] = []+ -- decode escapes in the filename. e.g. on Windows+ -- when our filenames have backslashes in, gcc seems to+ -- escape the backslashes. One symptom of not doing this+ -- is that filenames in error messages look a bit strange:+ -- C:\\foo\bar.hs+ -- only the first backslash is doubled, because we apply+ -- System.FilePath.normalise before printing out+ -- filenames and it does not remove duplicate+ -- backslashes after the drive letter (should it?).+ setAlrLastLoc $ alrInitialLoc file+ setSrcLoc (mkRealSrcLoc file (srcSpanEndLine span) (srcSpanEndCol span))+ addSrcFile file+ _ <- popLexState+ pushLexState code+ lexToken++alrInitialLoc :: FastString -> RealSrcSpan+alrInitialLoc file = mkRealSrcSpan loc loc+ where -- This is a hack to ensure that the first line in a file+ -- looks like it is after the initial location:+ loc = mkRealSrcLoc file (-1) (-1)++-- -----------------------------------------------------------------------------+-- Options, includes and language pragmas.++lex_string_prag :: (String -> Token) -> Action+lex_string_prag mkTok span _buf _len+ = do input <- getInput+ start <- getSrcLoc+ tok <- go [] input+ end <- getSrcLoc+ return (L (mkRealSrcSpan start end) tok)+ where go acc input+ = if isString input "#-}"+ then do setInput input+ return (mkTok (reverse acc))+ else case alexGetChar input of+ Just (c,i) -> go (c:acc) i+ Nothing -> err input+ isString _ [] = True+ isString i (x:xs)+ = case alexGetChar i of+ Just (c,i') | c == x -> isString i' xs+ _other -> False+ err (AI end _) = failLocMsgP (realSrcSpanStart span) end "unterminated options pragma"+++-- -----------------------------------------------------------------------------+-- Strings & Chars++-- This stuff is horrible. I hates it.++lex_string_tok :: Action+lex_string_tok span buf _len = do+ tok <- lex_string ""+ (AI end bufEnd) <- getInput+ let+ tok' = case tok of+ ITprimstring _ bs -> ITprimstring (SourceText src) bs+ ITstring _ s -> ITstring (SourceText src) s+ _ -> panic "lex_string_tok"+ src = lexemeToString buf (cur bufEnd - cur buf)+ return (L (mkRealSrcSpan (realSrcSpanStart span) end) tok')++lex_string :: String -> P Token+lex_string s = do+ i <- getInput+ case alexGetChar' i of+ Nothing -> lit_error i++ Just ('"',i) -> do+ setInput i+ magicHash <- extension magicHashEnabled+ if magicHash+ then do+ i <- getInput+ case alexGetChar' i of+ Just ('#',i) -> do+ setInput i+ if any (> '\xFF') s+ then failMsgP "primitive string literal must contain only characters <= \'\\xFF\'"+ else let bs = unsafeMkByteString (reverse s)+ in return (ITprimstring (SourceText (reverse s)) bs)+ _other ->+ return (ITstring (SourceText (reverse s))+ (mkFastString (reverse s)))+ else+ return (ITstring (SourceText (reverse s))+ (mkFastString (reverse s)))++ Just ('\\',i)+ | Just ('&',i) <- next -> do+ setInput i; lex_string s+ | Just (c,i) <- next, c <= '\x7f' && is_space c -> do+ -- is_space only works for <= '\x7f' (#3751, #5425)+ setInput i; lex_stringgap s+ where next = alexGetChar' i++ Just (c, i1) -> do+ case c of+ '\\' -> do setInput i1; c' <- lex_escape; lex_string (c':s)+ c | isAny c -> do setInput i1; lex_string (c:s)+ _other -> lit_error i++lex_stringgap :: String -> P Token+lex_stringgap s = do+ i <- getInput+ c <- getCharOrFail i+ case c of+ '\\' -> lex_string s+ c | c <= '\x7f' && is_space c -> lex_stringgap s+ -- is_space only works for <= '\x7f' (#3751, #5425)+ _other -> lit_error i+++lex_char_tok :: Action+-- Here we are basically parsing character literals, such as 'x' or '\n'+-- but we additionally spot 'x and ''T, returning ITsimpleQuote and+-- ITtyQuote respectively, but WITHOUT CONSUMING the x or T part+-- (the parser does that).+-- So we have to do two characters of lookahead: when we see 'x we need to+-- see if there's a trailing quote+lex_char_tok span buf _len = do -- We've seen '+ i1 <- getInput -- Look ahead to first character+ let loc = realSrcSpanStart span+ case alexGetChar' i1 of+ Nothing -> lit_error i1++ Just ('\'', i2@(AI end2 _)) -> do -- We've seen ''+ setInput i2+ return (L (mkRealSrcSpan loc end2) ITtyQuote)++ Just ('\\', i2@(AI _end2 _)) -> do -- We've seen 'backslash+ setInput i2+ lit_ch <- lex_escape+ i3 <- getInput+ mc <- getCharOrFail i3 -- Trailing quote+ if mc == '\'' then finish_char_tok buf loc lit_ch+ else lit_error i3++ Just (c, i2@(AI _end2 _))+ | not (isAny c) -> lit_error i1+ | otherwise ->++ -- We've seen 'x, where x is a valid character+ -- (i.e. not newline etc) but not a quote or backslash+ case alexGetChar' i2 of -- Look ahead one more character+ Just ('\'', i3) -> do -- We've seen 'x'+ setInput i3+ finish_char_tok buf loc c+ _other -> do -- We've seen 'x not followed by quote+ -- (including the possibility of EOF)+ -- Just parse the quote only+ let (AI end _) = i1+ return (L (mkRealSrcSpan loc end) ITsimpleQuote)++finish_char_tok :: StringBuffer -> RealSrcLoc -> Char -> P (RealLocated Token)+finish_char_tok buf loc ch -- We've already seen the closing quote+ -- Just need to check for trailing #+ = do magicHash <- extension magicHashEnabled+ i@(AI end bufEnd) <- getInput+ let src = lexemeToString buf (cur bufEnd - cur buf)+ if magicHash then do+ case alexGetChar' i of+ Just ('#',i@(AI end _)) -> do+ setInput i+ return (L (mkRealSrcSpan loc end)+ (ITprimchar (SourceText src) ch))+ _other ->+ return (L (mkRealSrcSpan loc end)+ (ITchar (SourceText src) ch))+ else do+ return (L (mkRealSrcSpan loc end) (ITchar (SourceText src) ch))++isAny :: Char -> Bool+isAny c | c > '\x7f' = isPrint c+ | otherwise = is_any c++lex_escape :: P Char+lex_escape = do+ i0 <- getInput+ c <- getCharOrFail i0+ case c of+ 'a' -> return '\a'+ 'b' -> return '\b'+ 'f' -> return '\f'+ 'n' -> return '\n'+ 'r' -> return '\r'+ 't' -> return '\t'+ 'v' -> return '\v'+ '\\' -> return '\\'+ '"' -> return '\"'+ '\'' -> return '\''+ '^' -> do i1 <- getInput+ c <- getCharOrFail i1+ if c >= '@' && c <= '_'+ then return (chr (ord c - ord '@'))+ else lit_error i1++ 'x' -> readNum is_hexdigit 16 hexDigit+ 'o' -> readNum is_octdigit 8 octDecDigit+ x | is_decdigit x -> readNum2 is_decdigit 10 octDecDigit (octDecDigit x)++ c1 -> do+ i <- getInput+ case alexGetChar' i of+ Nothing -> lit_error i0+ Just (c2,i2) ->+ case alexGetChar' i2 of+ Nothing -> do lit_error i0+ Just (c3,i3) ->+ let str = [c1,c2,c3] in+ case [ (c,rest) | (p,c) <- silly_escape_chars,+ Just rest <- [stripPrefix p str] ] of+ (escape_char,[]):_ -> do+ setInput i3+ return escape_char+ (escape_char,_:_):_ -> do+ setInput i2+ return escape_char+ [] -> lit_error i0++readNum :: (Char -> Bool) -> Int -> (Char -> Int) -> P Char+readNum is_digit base conv = do+ i <- getInput+ c <- getCharOrFail i+ if is_digit c+ then readNum2 is_digit base conv (conv c)+ else lit_error i++readNum2 :: (Char -> Bool) -> Int -> (Char -> Int) -> Int -> P Char+readNum2 is_digit base conv i = do+ input <- getInput+ read i input+ where read i input = do+ case alexGetChar' input of+ Just (c,input') | is_digit c -> do+ let i' = i*base + conv c+ if i' > 0x10ffff+ then setInput input >> lexError "numeric escape sequence out of range"+ else read i' input'+ _other -> do+ setInput input; return (chr i)+++silly_escape_chars :: [(String, Char)]+silly_escape_chars = [+ ("NUL", '\NUL'),+ ("SOH", '\SOH'),+ ("STX", '\STX'),+ ("ETX", '\ETX'),+ ("EOT", '\EOT'),+ ("ENQ", '\ENQ'),+ ("ACK", '\ACK'),+ ("BEL", '\BEL'),+ ("BS", '\BS'),+ ("HT", '\HT'),+ ("LF", '\LF'),+ ("VT", '\VT'),+ ("FF", '\FF'),+ ("CR", '\CR'),+ ("SO", '\SO'),+ ("SI", '\SI'),+ ("DLE", '\DLE'),+ ("DC1", '\DC1'),+ ("DC2", '\DC2'),+ ("DC3", '\DC3'),+ ("DC4", '\DC4'),+ ("NAK", '\NAK'),+ ("SYN", '\SYN'),+ ("ETB", '\ETB'),+ ("CAN", '\CAN'),+ ("EM", '\EM'),+ ("SUB", '\SUB'),+ ("ESC", '\ESC'),+ ("FS", '\FS'),+ ("GS", '\GS'),+ ("RS", '\RS'),+ ("US", '\US'),+ ("SP", '\SP'),+ ("DEL", '\DEL')+ ]++-- before calling lit_error, ensure that the current input is pointing to+-- the position of the error in the buffer. This is so that we can report+-- a correct location to the user, but also so we can detect UTF-8 decoding+-- errors if they occur.+lit_error :: AlexInput -> P a+lit_error i = do setInput i; lexError "lexical error in string/character literal"++getCharOrFail :: AlexInput -> P Char+getCharOrFail i = do+ case alexGetChar' i of+ Nothing -> lexError "unexpected end-of-file in string/character literal"+ Just (c,i) -> do setInput i; return c++-- -----------------------------------------------------------------------------+-- QuasiQuote++lex_qquasiquote_tok :: Action+lex_qquasiquote_tok span buf len = do+ let (qual, quoter) = splitQualName (stepOn buf) (len - 2) False+ quoteStart <- getSrcLoc+ quote <- lex_quasiquote quoteStart ""+ end <- getSrcLoc+ return (L (mkRealSrcSpan (realSrcSpanStart span) end)+ (ITqQuasiQuote (qual,+ quoter,+ mkFastString (reverse quote),+ mkRealSrcSpan quoteStart end)))++lex_quasiquote_tok :: Action+lex_quasiquote_tok span buf len = do+ let quoter = tail (lexemeToString buf (len - 1))+ -- 'tail' drops the initial '[',+ -- while the -1 drops the trailing '|'+ quoteStart <- getSrcLoc+ quote <- lex_quasiquote quoteStart ""+ end <- getSrcLoc+ return (L (mkRealSrcSpan (realSrcSpanStart span) end)+ (ITquasiQuote (mkFastString quoter,+ mkFastString (reverse quote),+ mkRealSrcSpan quoteStart end)))++lex_quasiquote :: RealSrcLoc -> String -> P String+lex_quasiquote start s = do+ i <- getInput+ case alexGetChar' i of+ Nothing -> quasiquote_error start++ -- NB: The string "|]" terminates the quasiquote,+ -- with absolutely no escaping. See the extensive+ -- discussion on Trac #5348 for why there is no+ -- escape handling.+ Just ('|',i)+ | Just (']',i) <- alexGetChar' i+ -> do { setInput i; return s }++ Just (c, i) -> do+ setInput i; lex_quasiquote start (c : s)++quasiquote_error :: RealSrcLoc -> P a+quasiquote_error start = do+ (AI end buf) <- getInput+ reportLexError start end buf "unterminated quasiquotation"++-- -----------------------------------------------------------------------------+-- Warnings++warnTab :: Action+warnTab srcspan _buf _len = do+ addTabWarning srcspan+ lexToken++warnThen :: WarningFlag -> SDoc -> Action -> Action+warnThen option warning action srcspan buf len = do+ addWarning option (RealSrcSpan srcspan) warning+ action srcspan buf len++-- -----------------------------------------------------------------------------+-- The Parse Monad++-- | Do we want to generate ';' layout tokens? In some cases we just want to+-- generate '}', e.g. in MultiWayIf we don't need ';'s because '|' separates+-- alternatives (unlike a `case` expression where we need ';' to as a separator+-- between alternatives).+type GenSemic = Bool++generateSemic, dontGenerateSemic :: GenSemic+generateSemic = True+dontGenerateSemic = False++data LayoutContext+ = NoLayout+ | Layout !Int !GenSemic+ deriving Show++data ParseResult a+ = POk PState a+ | PFailed+ SrcSpan -- The start and end of the text span related to+ -- the error. Might be used in environments which can+ -- show this span, e.g. by highlighting it.+ MsgDoc -- The error message++-- | Test whether a 'WarningFlag' is set+warnopt :: WarningFlag -> ParserFlags -> Bool+warnopt f options = fromEnum f `IntSet.member` pWarningFlags options++-- | Test whether a 'LangExt.Extension' is set+extopt :: LangExt.Extension -> ParserFlags -> Bool+extopt f options = fromEnum f `IntSet.member` pExtensionFlags options++-- | The subset of the 'DynFlags' used by the parser+data ParserFlags = ParserFlags {+ pWarningFlags :: IntSet+ , pExtensionFlags :: IntSet+ , pThisPackage :: UnitId -- ^ key of package currently being compiled+ , pExtsBitmap :: !ExtsBitmap -- ^ bitmap of permitted extensions+ }++data PState = PState {+ buffer :: StringBuffer,+ options :: ParserFlags,+ -- This needs to take DynFlags as an argument until+ -- we have a fix for #10143+ messages :: DynFlags -> Messages,+ tab_first :: Maybe RealSrcSpan, -- pos of first tab warning in the file+ tab_count :: !Int, -- number of tab warnings in the file+ last_tk :: Maybe Token,+ last_loc :: RealSrcSpan, -- pos of previous token+ last_len :: !Int, -- len of previous token+ loc :: RealSrcLoc, -- current loc (end of prev token + 1)+ context :: [LayoutContext],+ lex_state :: [Int],+ srcfiles :: [FastString],+ -- Used in the alternative layout rule:+ -- These tokens are the next ones to be sent out. They are+ -- just blindly emitted, without the rule looking at them again:+ alr_pending_implicit_tokens :: [RealLocated Token],+ -- This is the next token to be considered or, if it is Nothing,+ -- we need to get the next token from the input stream:+ alr_next_token :: Maybe (RealLocated Token),+ -- This is what we consider to be the location of the last token+ -- emitted:+ alr_last_loc :: RealSrcSpan,+ -- The stack of layout contexts:+ alr_context :: [ALRContext],+ -- Are we expecting a '{'? If it's Just, then the ALRLayout tells+ -- us what sort of layout the '{' will open:+ alr_expecting_ocurly :: Maybe ALRLayout,+ -- Have we just had the '}' for a let block? If so, than an 'in'+ -- token doesn't need to close anything:+ alr_justClosedExplicitLetBlock :: Bool,++ -- The next three are used to implement Annotations giving the+ -- locations of 'noise' tokens in the source, so that users of+ -- the GHC API can do source to source conversions.+ -- See note [Api annotations] in ApiAnnotation.hs+ annotations :: [(ApiAnnKey,[SrcSpan])],+ comment_q :: [Located AnnotationComment],+ annotations_comments :: [(SrcSpan,[Located AnnotationComment])]+ }+ -- last_loc and last_len are used when generating error messages,+ -- and in pushCurrentContext only. Sigh, if only Happy passed the+ -- current token to happyError, we could at least get rid of last_len.+ -- Getting rid of last_loc would require finding another way to+ -- implement pushCurrentContext (which is only called from one place).++data ALRContext = ALRNoLayout Bool{- does it contain commas? -}+ Bool{- is it a 'let' block? -}+ | ALRLayout ALRLayout Int+data ALRLayout = ALRLayoutLet+ | ALRLayoutWhere+ | ALRLayoutOf+ | ALRLayoutDo++newtype P a = P { unP :: PState -> ParseResult a }++instance Functor P where+ fmap = liftM++instance Applicative P where+ pure = returnP+ (<*>) = ap++instance Monad P where+ (>>=) = thenP+ fail = failP++#if __GLASGOW_HASKELL__ > 710+instance MonadFail P where+ fail = failP+#endif++returnP :: a -> P a+returnP a = a `seq` (P $ \s -> POk s a)++thenP :: P a -> (a -> P b) -> P b+(P m) `thenP` k = P $ \ s ->+ case m s of+ POk s1 a -> (unP (k a)) s1+ PFailed span err -> PFailed span err++failP :: String -> P a+failP msg = P $ \s -> PFailed (RealSrcSpan (last_loc s)) (text msg)++failMsgP :: String -> P a+failMsgP msg = P $ \s -> PFailed (RealSrcSpan (last_loc s)) (text msg)++failLocMsgP :: RealSrcLoc -> RealSrcLoc -> String -> P a+failLocMsgP loc1 loc2 str = P $ \_ -> PFailed (RealSrcSpan (mkRealSrcSpan loc1 loc2)) (text str)++failSpanMsgP :: SrcSpan -> SDoc -> P a+failSpanMsgP span msg = P $ \_ -> PFailed span msg++getPState :: P PState+getPState = P $ \s -> POk s s++withThisPackage :: (UnitId -> a) -> P a+withThisPackage f = P $ \s@(PState{options = o}) -> POk s (f (pThisPackage o))++extension :: (ExtsBitmap -> Bool) -> P Bool+extension p = P $ \s -> POk s (p $! (pExtsBitmap . options) s)++getExts :: P ExtsBitmap+getExts = P $ \s -> POk s (pExtsBitmap . options $ s)++setExts :: (ExtsBitmap -> ExtsBitmap) -> P ()+setExts f = P $ \s -> POk s {+ options =+ let p = options s+ in p { pExtsBitmap = f (pExtsBitmap p) }+ } ()++setSrcLoc :: RealSrcLoc -> P ()+setSrcLoc new_loc = P $ \s -> POk s{loc=new_loc} ()++getSrcLoc :: P RealSrcLoc+getSrcLoc = P $ \s@(PState{ loc=loc }) -> POk s loc++addSrcFile :: FastString -> P ()+addSrcFile f = P $ \s -> POk s{ srcfiles = f : srcfiles s } ()++setLastToken :: RealSrcSpan -> Int -> P ()+setLastToken loc len = P $ \s -> POk s {+ last_loc=loc,+ last_len=len+ } ()++setLastTk :: Token -> P ()+setLastTk tk = P $ \s -> POk s { last_tk = Just tk } ()++getLastTk :: P (Maybe Token)+getLastTk = P $ \s@(PState { last_tk = last_tk }) -> POk s last_tk++data AlexInput = AI RealSrcLoc StringBuffer++alexInputPrevChar :: AlexInput -> Char+alexInputPrevChar (AI _ buf) = prevChar buf '\n'++-- backwards compatibility for Alex 2.x+alexGetChar :: AlexInput -> Maybe (Char,AlexInput)+alexGetChar inp = case alexGetByte inp of+ Nothing -> Nothing+ Just (b,i) -> c `seq` Just (c,i)+ where c = chr $ fromIntegral b++alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)+alexGetByte (AI loc s)+ | atEnd s = Nothing+ | otherwise = byte `seq` loc' `seq` s' `seq`+ --trace (show (ord c)) $+ Just (byte, (AI loc' s'))+ where (c,s') = nextChar s+ loc' = advanceSrcLoc loc c+ byte = fromIntegral $ ord adj_c++ non_graphic = '\x00'+ upper = '\x01'+ lower = '\x02'+ digit = '\x03'+ symbol = '\x04'+ space = '\x05'+ other_graphic = '\x06'+ uniidchar = '\x07'++ adj_c+ | c <= '\x07' = non_graphic+ | c <= '\x7f' = c+ -- Alex doesn't handle Unicode, so when Unicode+ -- character is encountered we output these values+ -- with the actual character value hidden in the state.+ | otherwise =+ -- NB: The logic behind these definitions is also reflected+ -- in basicTypes/Lexeme.hs+ -- Any changes here should likely be reflected there.++ case generalCategory c of+ UppercaseLetter -> upper+ LowercaseLetter -> lower+ TitlecaseLetter -> upper+ ModifierLetter -> uniidchar -- see #10196+ OtherLetter -> lower -- see #1103+ NonSpacingMark -> uniidchar -- see #7650+ SpacingCombiningMark -> other_graphic+ EnclosingMark -> other_graphic+ DecimalNumber -> digit+ LetterNumber -> other_graphic+ OtherNumber -> digit -- see #4373+ ConnectorPunctuation -> symbol+ DashPunctuation -> symbol+ OpenPunctuation -> other_graphic+ ClosePunctuation -> other_graphic+ InitialQuote -> other_graphic+ FinalQuote -> other_graphic+ OtherPunctuation -> symbol+ MathSymbol -> symbol+ CurrencySymbol -> symbol+ ModifierSymbol -> symbol+ OtherSymbol -> symbol+ Space -> space+ _other -> non_graphic++-- This version does not squash unicode characters, it is used when+-- lexing strings.+alexGetChar' :: AlexInput -> Maybe (Char,AlexInput)+alexGetChar' (AI loc s)+ | atEnd s = Nothing+ | otherwise = c `seq` loc' `seq` s' `seq`+ --trace (show (ord c)) $+ Just (c, (AI loc' s'))+ where (c,s') = nextChar s+ loc' = advanceSrcLoc loc c++getInput :: P AlexInput+getInput = P $ \s@PState{ loc=l, buffer=b } -> POk s (AI l b)++setInput :: AlexInput -> P ()+setInput (AI l b) = P $ \s -> POk s{ loc=l, buffer=b } ()++nextIsEOF :: P Bool+nextIsEOF = do+ AI _ s <- getInput+ return $ atEnd s++pushLexState :: Int -> P ()+pushLexState ls = P $ \s@PState{ lex_state=l } -> POk s{lex_state=ls:l} ()++popLexState :: P Int+popLexState = P $ \s@PState{ lex_state=ls:l } -> POk s{ lex_state=l } ls++getLexState :: P Int+getLexState = P $ \s@PState{ lex_state=ls:_ } -> POk s ls++popNextToken :: P (Maybe (RealLocated Token))+popNextToken+ = P $ \s@PState{ alr_next_token = m } ->+ POk (s {alr_next_token = Nothing}) m++activeContext :: P Bool+activeContext = do+ ctxt <- getALRContext+ expc <- getAlrExpectingOCurly+ impt <- implicitTokenPending+ case (ctxt,expc) of+ ([],Nothing) -> return impt+ _other -> return True++setAlrLastLoc :: RealSrcSpan -> P ()+setAlrLastLoc l = P $ \s -> POk (s {alr_last_loc = l}) ()++getAlrLastLoc :: P RealSrcSpan+getAlrLastLoc = P $ \s@(PState {alr_last_loc = l}) -> POk s l++getALRContext :: P [ALRContext]+getALRContext = P $ \s@(PState {alr_context = cs}) -> POk s cs++setALRContext :: [ALRContext] -> P ()+setALRContext cs = P $ \s -> POk (s {alr_context = cs}) ()++getALRTransitional :: P Bool+getALRTransitional = P $ \s@PState {options = o} ->+ POk s (extopt LangExt.AlternativeLayoutRuleTransitional o)++getJustClosedExplicitLetBlock :: P Bool+getJustClosedExplicitLetBlock+ = P $ \s@(PState {alr_justClosedExplicitLetBlock = b}) -> POk s b++setJustClosedExplicitLetBlock :: Bool -> P ()+setJustClosedExplicitLetBlock b+ = P $ \s -> POk (s {alr_justClosedExplicitLetBlock = b}) ()++setNextToken :: RealLocated Token -> P ()+setNextToken t = P $ \s -> POk (s {alr_next_token = Just t}) ()++implicitTokenPending :: P Bool+implicitTokenPending+ = P $ \s@PState{ alr_pending_implicit_tokens = ts } ->+ case ts of+ [] -> POk s False+ _ -> POk s True++popPendingImplicitToken :: P (Maybe (RealLocated Token))+popPendingImplicitToken+ = P $ \s@PState{ alr_pending_implicit_tokens = ts } ->+ case ts of+ [] -> POk s Nothing+ (t : ts') -> POk (s {alr_pending_implicit_tokens = ts'}) (Just t)++setPendingImplicitTokens :: [RealLocated Token] -> P ()+setPendingImplicitTokens ts = P $ \s -> POk (s {alr_pending_implicit_tokens = ts}) ()++getAlrExpectingOCurly :: P (Maybe ALRLayout)+getAlrExpectingOCurly = P $ \s@(PState {alr_expecting_ocurly = b}) -> POk s b++setAlrExpectingOCurly :: Maybe ALRLayout -> P ()+setAlrExpectingOCurly b = P $ \s -> POk (s {alr_expecting_ocurly = b}) ()++-- for reasons of efficiency, flags indicating language extensions (eg,+-- -fglasgow-exts or -XParallelArrays) are represented by a bitmap+-- stored in an unboxed Word64+type ExtsBitmap = Word64++xbit :: ExtBits -> ExtsBitmap+xbit = bit . fromEnum++xtest :: ExtBits -> ExtsBitmap -> Bool+xtest ext xmap = testBit xmap (fromEnum ext)++data ExtBits+ = FfiBit+ | InterruptibleFfiBit+ | CApiFfiBit+ | ParrBit+ | ArrowsBit+ | ThBit+ | ThQuotesBit+ | IpBit+ | OverloadedLabelsBit -- #x overloaded labels+ | ExplicitForallBit -- the 'forall' keyword and '.' symbol+ | BangPatBit -- Tells the parser to understand bang-patterns+ -- (doesn't affect the lexer)+ | PatternSynonymsBit -- pattern synonyms+ | HaddockBit-- Lex and parse Haddock comments+ | MagicHashBit -- "#" in both functions and operators+ | RecursiveDoBit -- mdo+ | UnicodeSyntaxBit -- the forall symbol, arrow symbols, etc+ | UnboxedTuplesBit -- (# and #)+ | UnboxedSumsBit -- (# and #)+ | DatatypeContextsBit+ | TransformComprehensionsBit+ | QqBit -- enable quasiquoting+ | InRulePragBit+ | RawTokenStreamBit -- producing a token stream with all comments included+ | SccProfilingOnBit+ | HpcBit+ | AlternativeLayoutRuleBit+ | RelaxedLayoutBit+ | NondecreasingIndentationBit+ | SafeHaskellBit+ | TraditionalRecordSyntaxBit+ | ExplicitNamespacesBit+ | LambdaCaseBit+ | BinaryLiteralsBit+ | NegativeLiteralsBit+ | TypeApplicationsBit+ | StaticPointersBit+ deriving Enum+++always :: ExtsBitmap -> Bool+always _ = True+parrEnabled :: ExtsBitmap -> Bool+parrEnabled = xtest ParrBit+arrowsEnabled :: ExtsBitmap -> Bool+arrowsEnabled = xtest ArrowsBit+thEnabled :: ExtsBitmap -> Bool+thEnabled = xtest ThBit+thQuotesEnabled :: ExtsBitmap -> Bool+thQuotesEnabled = xtest ThQuotesBit+ipEnabled :: ExtsBitmap -> Bool+ipEnabled = xtest IpBit+overloadedLabelsEnabled :: ExtsBitmap -> Bool+overloadedLabelsEnabled = xtest OverloadedLabelsBit+explicitForallEnabled :: ExtsBitmap -> Bool+explicitForallEnabled = xtest ExplicitForallBit+bangPatEnabled :: ExtsBitmap -> Bool+bangPatEnabled = xtest BangPatBit+haddockEnabled :: ExtsBitmap -> Bool+haddockEnabled = xtest HaddockBit+magicHashEnabled :: ExtsBitmap -> Bool+magicHashEnabled = xtest MagicHashBit+unicodeSyntaxEnabled :: ExtsBitmap -> Bool+unicodeSyntaxEnabled = xtest UnicodeSyntaxBit+unboxedTuplesEnabled :: ExtsBitmap -> Bool+unboxedTuplesEnabled = xtest UnboxedTuplesBit+unboxedSumsEnabled :: ExtsBitmap -> Bool+unboxedSumsEnabled = xtest UnboxedSumsBit+datatypeContextsEnabled :: ExtsBitmap -> Bool+datatypeContextsEnabled = xtest DatatypeContextsBit+qqEnabled :: ExtsBitmap -> Bool+qqEnabled = xtest QqBit+inRulePrag :: ExtsBitmap -> Bool+inRulePrag = xtest InRulePragBit+rawTokenStreamEnabled :: ExtsBitmap -> Bool+rawTokenStreamEnabled = xtest RawTokenStreamBit+alternativeLayoutRule :: ExtsBitmap -> Bool+alternativeLayoutRule = xtest AlternativeLayoutRuleBit+hpcEnabled :: ExtsBitmap -> Bool+hpcEnabled = xtest HpcBit+relaxedLayout :: ExtsBitmap -> Bool+relaxedLayout = xtest RelaxedLayoutBit+nondecreasingIndentation :: ExtsBitmap -> Bool+nondecreasingIndentation = xtest NondecreasingIndentationBit+sccProfilingOn :: ExtsBitmap -> Bool+sccProfilingOn = xtest SccProfilingOnBit+traditionalRecordSyntaxEnabled :: ExtsBitmap -> Bool+traditionalRecordSyntaxEnabled = xtest TraditionalRecordSyntaxBit++explicitNamespacesEnabled :: ExtsBitmap -> Bool+explicitNamespacesEnabled = xtest ExplicitNamespacesBit+lambdaCaseEnabled :: ExtsBitmap -> Bool+lambdaCaseEnabled = xtest LambdaCaseBit+binaryLiteralsEnabled :: ExtsBitmap -> Bool+binaryLiteralsEnabled = xtest BinaryLiteralsBit+negativeLiteralsEnabled :: ExtsBitmap -> Bool+negativeLiteralsEnabled = xtest NegativeLiteralsBit+patternSynonymsEnabled :: ExtsBitmap -> Bool+patternSynonymsEnabled = xtest PatternSynonymsBit+typeApplicationEnabled :: ExtsBitmap -> Bool+typeApplicationEnabled = xtest TypeApplicationsBit+staticPointersEnabled :: ExtsBitmap -> Bool+staticPointersEnabled = xtest StaticPointersBit++-- PState for parsing options pragmas+--+pragState :: DynFlags -> StringBuffer -> RealSrcLoc -> PState+pragState dynflags buf loc = (mkPState dynflags buf loc) {+ lex_state = [bol, option_prags, 0]+ }++-- | Extracts the flag information needed for parsing+mkParserFlags :: DynFlags -> ParserFlags+mkParserFlags flags =+ ParserFlags {+ pWarningFlags = DynFlags.warningFlags flags+ , pExtensionFlags = DynFlags.extensionFlags flags+ , pThisPackage = DynFlags.thisPackage flags+ , pExtsBitmap = bitmap+ }+ where+ bitmap = FfiBit `setBitIf` xopt LangExt.ForeignFunctionInterface flags+ .|. InterruptibleFfiBit `setBitIf` xopt LangExt.InterruptibleFFI flags+ .|. CApiFfiBit `setBitIf` xopt LangExt.CApiFFI flags+ .|. ParrBit `setBitIf` xopt LangExt.ParallelArrays flags+ .|. ArrowsBit `setBitIf` xopt LangExt.Arrows flags+ .|. ThBit `setBitIf` xopt LangExt.TemplateHaskell flags+ .|. ThQuotesBit `setBitIf` xopt LangExt.TemplateHaskellQuotes flags+ .|. QqBit `setBitIf` xopt LangExt.QuasiQuotes flags+ .|. IpBit `setBitIf` xopt LangExt.ImplicitParams flags+ .|. OverloadedLabelsBit `setBitIf` xopt LangExt.OverloadedLabels flags+ .|. ExplicitForallBit `setBitIf` xopt LangExt.ExplicitForAll flags+ .|. BangPatBit `setBitIf` xopt LangExt.BangPatterns flags+ .|. HaddockBit `setBitIf` gopt Opt_Haddock flags+ .|. MagicHashBit `setBitIf` xopt LangExt.MagicHash flags+ .|. RecursiveDoBit `setBitIf` xopt LangExt.RecursiveDo flags+ .|. UnicodeSyntaxBit `setBitIf` xopt LangExt.UnicodeSyntax flags+ .|. UnboxedTuplesBit `setBitIf` xopt LangExt.UnboxedTuples flags+ .|. UnboxedSumsBit `setBitIf` xopt LangExt.UnboxedSums flags+ .|. DatatypeContextsBit `setBitIf` xopt LangExt.DatatypeContexts flags+ .|. TransformComprehensionsBit `setBitIf` xopt LangExt.TransformListComp flags+ .|. TransformComprehensionsBit `setBitIf` xopt LangExt.MonadComprehensions flags+ .|. RawTokenStreamBit `setBitIf` gopt Opt_KeepRawTokenStream flags+ .|. HpcBit `setBitIf` gopt Opt_Hpc flags+ .|. AlternativeLayoutRuleBit `setBitIf` xopt LangExt.AlternativeLayoutRule flags+ .|. RelaxedLayoutBit `setBitIf` xopt LangExt.RelaxedLayout flags+ .|. SccProfilingOnBit `setBitIf` gopt Opt_SccProfilingOn flags+ .|. NondecreasingIndentationBit `setBitIf` xopt LangExt.NondecreasingIndentation flags+ .|. SafeHaskellBit `setBitIf` safeImportsOn flags+ .|. TraditionalRecordSyntaxBit `setBitIf` xopt LangExt.TraditionalRecordSyntax flags+ .|. ExplicitNamespacesBit `setBitIf` xopt LangExt.ExplicitNamespaces flags+ .|. LambdaCaseBit `setBitIf` xopt LangExt.LambdaCase flags+ .|. BinaryLiteralsBit `setBitIf` xopt LangExt.BinaryLiterals flags+ .|. NegativeLiteralsBit `setBitIf` xopt LangExt.NegativeLiterals flags+ .|. PatternSynonymsBit `setBitIf` xopt LangExt.PatternSynonyms flags+ .|. TypeApplicationsBit `setBitIf` xopt LangExt.TypeApplications flags+ .|. StaticPointersBit `setBitIf` xopt LangExt.StaticPointers flags++ setBitIf :: ExtBits -> Bool -> ExtsBitmap+ b `setBitIf` cond | cond = xbit b+ | otherwise = 0++-- | Creates a parse state from a 'DynFlags' value+mkPState :: DynFlags -> StringBuffer -> RealSrcLoc -> PState+mkPState flags = mkPStatePure (mkParserFlags flags)++-- | Creates a parse state from a 'ParserFlags' value+mkPStatePure :: ParserFlags -> StringBuffer -> RealSrcLoc -> PState+mkPStatePure options buf loc =+ PState {+ buffer = buf,+ options = options,+ messages = const emptyMessages,+ tab_first = Nothing,+ tab_count = 0,+ last_tk = Nothing,+ last_loc = mkRealSrcSpan loc loc,+ last_len = 0,+ loc = loc,+ context = [],+ lex_state = [bol, 0],+ srcfiles = [],+ alr_pending_implicit_tokens = [],+ alr_next_token = Nothing,+ alr_last_loc = alrInitialLoc (fsLit "<no file>"),+ alr_context = [],+ alr_expecting_ocurly = Nothing,+ alr_justClosedExplicitLetBlock = False,+ annotations = [],+ comment_q = [],+ annotations_comments = []+ }++addWarning :: WarningFlag -> SrcSpan -> SDoc -> P ()+addWarning option srcspan warning+ = P $ \s@PState{messages=m, options=o} ->+ let+ m' d =+ let (ws, es) = m d+ warning' = makeIntoWarning (Reason option) $+ mkWarnMsg d srcspan alwaysQualify warning+ ws' = if warnopt option o then ws `snocBag` warning' else ws+ in (ws', es)+ in POk s{messages=m'} ()++addTabWarning :: RealSrcSpan -> P ()+addTabWarning srcspan+ = P $ \s@PState{tab_first=tf, tab_count=tc, options=o} ->+ let tf' = if isJust tf then tf else Just srcspan+ tc' = tc + 1+ s' = if warnopt Opt_WarnTabs o+ then s{tab_first = tf', tab_count = tc'}+ else s+ in POk s' ()++mkTabWarning :: PState -> DynFlags -> Maybe ErrMsg+mkTabWarning PState{tab_first=tf, tab_count=tc} d =+ let middle = if tc == 1+ then text ""+ else text ", and in" <+> speakNOf (tc - 1) (text "further location")+ message = text "Tab character found here"+ <> middle+ <> text "."+ $+$ text "Please use spaces instead."+ in fmap (\s -> makeIntoWarning (Reason Opt_WarnTabs) $+ mkWarnMsg d (RealSrcSpan s) alwaysQualify message) tf++getMessages :: PState -> DynFlags -> Messages+getMessages p@PState{messages=m} d =+ let (ws, es) = m d+ tabwarning = mkTabWarning p d+ ws' = maybe ws (`consBag` ws) tabwarning+ in (ws', es)++getContext :: P [LayoutContext]+getContext = P $ \s@PState{context=ctx} -> POk s ctx++setContext :: [LayoutContext] -> P ()+setContext ctx = P $ \s -> POk s{context=ctx} ()++popContext :: P ()+popContext = P $ \ s@(PState{ buffer = buf, options = o, context = ctx,+ last_len = len, last_loc = last_loc }) ->+ case ctx of+ (_:tl) -> POk s{ context = tl } ()+ [] -> PFailed (RealSrcSpan last_loc) (srcParseErr o buf len)++-- Push a new layout context at the indentation of the last token read.+pushCurrentContext :: GenSemic -> P ()+pushCurrentContext gen_semic = P $ \ s@PState{ last_loc=loc, context=ctx } ->+ POk s{context = Layout (srcSpanStartCol loc) gen_semic : ctx} ()++-- This is only used at the outer level of a module when the 'module' keyword is+-- missing.+pushModuleContext :: P ()+pushModuleContext = pushCurrentContext generateSemic++getOffside :: P (Ordering, Bool)+getOffside = P $ \s@PState{last_loc=loc, context=stk} ->+ let offs = srcSpanStartCol loc in+ let ord = case stk of+ Layout n gen_semic : _ ->+ --trace ("layout: " ++ show n ++ ", offs: " ++ show offs) $+ (compare offs n, gen_semic)+ _ ->+ (GT, dontGenerateSemic)+ in POk s ord++-- ---------------------------------------------------------------------------+-- Construct a parse error++srcParseErr+ :: ParserFlags+ -> StringBuffer -- current buffer (placed just after the last token)+ -> Int -- length of the previous token+ -> MsgDoc+srcParseErr options buf len+ = if null token+ then text "parse error (possibly incorrect indentation or mismatched brackets)"+ else text "parse error on input" <+> quotes (text token)+ $$ ppWhen (not th_enabled && token == "$") -- #7396+ (text "Perhaps you intended to use TemplateHaskell")+ $$ ppWhen (token == "<-")+ (text "Perhaps this statement should be within a 'do' block?")+ $$ ppWhen (token == "=")+ (text "Perhaps you need a 'let' in a 'do' block?"+ $$ text "e.g. 'let x = 5' instead of 'x = 5'")+ $$ ppWhen (not ps_enabled && pattern == "pattern") -- #12429+ (text "Perhaps you intended to use PatternSynonyms")+ where token = lexemeToString (offsetBytes (-len) buf) len+ pattern = lexemeToString (offsetBytes (-len - 8) buf) 7+ th_enabled = extopt LangExt.TemplateHaskell options+ ps_enabled = extopt LangExt.PatternSynonyms options++-- Report a parse failure, giving the span of the previous token as+-- the location of the error. This is the entry point for errors+-- detected during parsing.+srcParseFail :: P a+srcParseFail = P $ \PState{ buffer = buf, options = o, last_len = len,+ last_loc = last_loc } ->+ PFailed (RealSrcSpan last_loc) (srcParseErr o buf len)++-- A lexical error is reported at a particular position in the source file,+-- not over a token range.+lexError :: String -> P a+lexError str = do+ loc <- getSrcLoc+ (AI end buf) <- getInput+ reportLexError loc end buf str++-- -----------------------------------------------------------------------------+-- This is the top-level function: called from the parser each time a+-- new token is to be read from the input.++lexer :: Bool -> (Located Token -> P a) -> P a+lexer queueComments cont = do+ alr <- extension alternativeLayoutRule+ let lexTokenFun = if alr then lexTokenAlr else lexToken+ (L span tok) <- lexTokenFun+ --trace ("token: " ++ show tok) $ do++ case tok of+ ITeof -> addAnnotationOnly noSrcSpan AnnEofPos (RealSrcSpan span)+ _ -> return ()++ if (queueComments && isDocComment tok)+ then queueComment (L (RealSrcSpan span) tok)+ else return ()++ if (queueComments && isComment tok)+ then queueComment (L (RealSrcSpan span) tok) >> lexer queueComments cont+ else cont (L (RealSrcSpan span) tok)++lexTokenAlr :: P (RealLocated Token)+lexTokenAlr = do mPending <- popPendingImplicitToken+ t <- case mPending of+ Nothing ->+ do mNext <- popNextToken+ t <- case mNext of+ Nothing -> lexToken+ Just next -> return next+ alternativeLayoutRuleToken t+ Just t ->+ return t+ setAlrLastLoc (getLoc t)+ case unLoc t of+ ITwhere -> setAlrExpectingOCurly (Just ALRLayoutWhere)+ ITlet -> setAlrExpectingOCurly (Just ALRLayoutLet)+ ITof -> setAlrExpectingOCurly (Just ALRLayoutOf)+ ITdo -> setAlrExpectingOCurly (Just ALRLayoutDo)+ ITmdo -> setAlrExpectingOCurly (Just ALRLayoutDo)+ ITrec -> setAlrExpectingOCurly (Just ALRLayoutDo)+ _ -> return ()+ return t++alternativeLayoutRuleToken :: RealLocated Token -> P (RealLocated Token)+alternativeLayoutRuleToken t+ = do context <- getALRContext+ lastLoc <- getAlrLastLoc+ mExpectingOCurly <- getAlrExpectingOCurly+ transitional <- getALRTransitional+ justClosedExplicitLetBlock <- getJustClosedExplicitLetBlock+ setJustClosedExplicitLetBlock False+ let thisLoc = getLoc t+ thisCol = srcSpanStartCol thisLoc+ newLine = srcSpanStartLine thisLoc > srcSpanEndLine lastLoc+ case (unLoc t, context, mExpectingOCurly) of+ -- This case handles a GHC extension to the original H98+ -- layout rule...+ (ITocurly, _, Just alrLayout) ->+ do setAlrExpectingOCurly Nothing+ let isLet = case alrLayout of+ ALRLayoutLet -> True+ _ -> False+ setALRContext (ALRNoLayout (containsCommas ITocurly) isLet : context)+ return t+ -- ...and makes this case unnecessary+ {-+ -- I think our implicit open-curly handling is slightly+ -- different to John's, in how it interacts with newlines+ -- and "in"+ (ITocurly, _, Just _) ->+ do setAlrExpectingOCurly Nothing+ setNextToken t+ lexTokenAlr+ -}+ (_, ALRLayout _ col : _ls, Just expectingOCurly)+ | (thisCol > col) ||+ (thisCol == col &&+ isNonDecreasingIntentation expectingOCurly) ->+ do setAlrExpectingOCurly Nothing+ setALRContext (ALRLayout expectingOCurly thisCol : context)+ setNextToken t+ return (L thisLoc ITocurly)+ | otherwise ->+ do setAlrExpectingOCurly Nothing+ setPendingImplicitTokens [L lastLoc ITccurly]+ setNextToken t+ return (L lastLoc ITocurly)+ (_, _, Just expectingOCurly) ->+ do setAlrExpectingOCurly Nothing+ setALRContext (ALRLayout expectingOCurly thisCol : context)+ setNextToken t+ return (L thisLoc ITocurly)+ -- We do the [] cases earlier than in the spec, as we+ -- have an actual EOF token+ (ITeof, ALRLayout _ _ : ls, _) ->+ do setALRContext ls+ setNextToken t+ return (L thisLoc ITccurly)+ (ITeof, _, _) ->+ return t+ -- the other ITeof case omitted; general case below covers it+ (ITin, _, _)+ | justClosedExplicitLetBlock ->+ return t+ (ITin, ALRLayout ALRLayoutLet _ : ls, _)+ | newLine ->+ do setPendingImplicitTokens [t]+ setALRContext ls+ return (L thisLoc ITccurly)+ -- This next case is to handle a transitional issue:+ (ITwhere, ALRLayout _ col : ls, _)+ | newLine && thisCol == col && transitional ->+ do addWarning Opt_WarnAlternativeLayoutRuleTransitional+ (RealSrcSpan thisLoc)+ (transitionalAlternativeLayoutWarning+ "`where' clause at the same depth as implicit layout block")+ setALRContext ls+ setNextToken t+ -- Note that we use lastLoc, as we may need to close+ -- more layouts, or give a semicolon+ return (L lastLoc ITccurly)+ -- This next case is to handle a transitional issue:+ (ITvbar, ALRLayout _ col : ls, _)+ | newLine && thisCol == col && transitional ->+ do addWarning Opt_WarnAlternativeLayoutRuleTransitional+ (RealSrcSpan thisLoc)+ (transitionalAlternativeLayoutWarning+ "`|' at the same depth as implicit layout block")+ setALRContext ls+ setNextToken t+ -- Note that we use lastLoc, as we may need to close+ -- more layouts, or give a semicolon+ return (L lastLoc ITccurly)+ (_, ALRLayout _ col : ls, _)+ | newLine && thisCol == col ->+ do setNextToken t+ return (L thisLoc ITsemi)+ | newLine && thisCol < col ->+ do setALRContext ls+ setNextToken t+ -- Note that we use lastLoc, as we may need to close+ -- more layouts, or give a semicolon+ return (L lastLoc ITccurly)+ -- We need to handle close before open, as 'then' is both+ -- an open and a close+ (u, _, _)+ | isALRclose u ->+ case context of+ ALRLayout _ _ : ls ->+ do setALRContext ls+ setNextToken t+ return (L thisLoc ITccurly)+ ALRNoLayout _ isLet : ls ->+ do let ls' = if isALRopen u+ then ALRNoLayout (containsCommas u) False : ls+ else ls+ setALRContext ls'+ when isLet $ setJustClosedExplicitLetBlock True+ return t+ [] ->+ do let ls = if isALRopen u+ then [ALRNoLayout (containsCommas u) False]+ else []+ setALRContext ls+ -- XXX This is an error in John's code, but+ -- it looks reachable to me at first glance+ return t+ (u, _, _)+ | isALRopen u ->+ do setALRContext (ALRNoLayout (containsCommas u) False : context)+ return t+ (ITin, ALRLayout ALRLayoutLet _ : ls, _) ->+ do setALRContext ls+ setPendingImplicitTokens [t]+ return (L thisLoc ITccurly)+ (ITin, ALRLayout _ _ : ls, _) ->+ do setALRContext ls+ setNextToken t+ return (L thisLoc ITccurly)+ -- the other ITin case omitted; general case below covers it+ (ITcomma, ALRLayout _ _ : ls, _)+ | topNoLayoutContainsCommas ls ->+ do setALRContext ls+ setNextToken t+ return (L thisLoc ITccurly)+ (ITwhere, ALRLayout ALRLayoutDo _ : ls, _) ->+ do setALRContext ls+ setPendingImplicitTokens [t]+ return (L thisLoc ITccurly)+ -- the other ITwhere case omitted; general case below covers it+ (_, _, _) -> return t++transitionalAlternativeLayoutWarning :: String -> SDoc+transitionalAlternativeLayoutWarning msg+ = text "transitional layout will not be accepted in the future:"+ $$ text msg++isALRopen :: Token -> Bool+isALRopen ITcase = True+isALRopen ITif = True+isALRopen ITthen = True+isALRopen IToparen = True+isALRopen ITobrack = True+isALRopen ITocurly = True+-- GHC Extensions:+isALRopen IToubxparen = True+isALRopen ITparenEscape = True+isALRopen ITparenTyEscape = True+isALRopen _ = False++isALRclose :: Token -> Bool+isALRclose ITof = True+isALRclose ITthen = True+isALRclose ITelse = True+isALRclose ITcparen = True+isALRclose ITcbrack = True+isALRclose ITccurly = True+-- GHC Extensions:+isALRclose ITcubxparen = True+isALRclose _ = False++isNonDecreasingIntentation :: ALRLayout -> Bool+isNonDecreasingIntentation ALRLayoutDo = True+isNonDecreasingIntentation _ = False++containsCommas :: Token -> Bool+containsCommas IToparen = True+containsCommas ITobrack = True+-- John doesn't have {} as containing commas, but records contain them,+-- which caused a problem parsing Cabal's Distribution.Simple.InstallDirs+-- (defaultInstallDirs).+containsCommas ITocurly = True+-- GHC Extensions:+containsCommas IToubxparen = True+containsCommas _ = False++topNoLayoutContainsCommas :: [ALRContext] -> Bool+topNoLayoutContainsCommas [] = False+topNoLayoutContainsCommas (ALRLayout _ _ : ls) = topNoLayoutContainsCommas ls+topNoLayoutContainsCommas (ALRNoLayout b _ : _) = b++lexToken :: P (RealLocated Token)+lexToken = do+ inp@(AI loc1 buf) <- getInput+ sc <- getLexState+ exts <- getExts+ case alexScanUser exts inp sc of+ AlexEOF -> do+ let span = mkRealSrcSpan loc1 loc1+ setLastToken span 0+ return (L span ITeof)+ AlexError (AI loc2 buf) ->+ reportLexError loc1 loc2 buf "lexical error"+ AlexSkip inp2 _ -> do+ setInput inp2+ lexToken+ AlexToken inp2@(AI end buf2) _ t -> do+ setInput inp2+ let span = mkRealSrcSpan loc1 end+ let bytes = byteDiff buf buf2+ span `seq` setLastToken span bytes+ lt <- t span buf bytes+ case unLoc lt of+ ITlineComment _ -> return lt+ ITblockComment _ -> return lt+ lt' -> do+ setLastTk lt'+ return lt++reportLexError :: RealSrcLoc -> RealSrcLoc -> StringBuffer -> [Char] -> P a+reportLexError loc1 loc2 buf str+ | atEnd buf = failLocMsgP loc1 loc2 (str ++ " at end of input")+ | otherwise =+ let c = fst (nextChar buf)+ in if c == '\0' -- decoding errors are mapped to '\0', see utf8DecodeChar#+ then failLocMsgP loc2 loc2 (str ++ " (UTF-8 decoding error)")+ else failLocMsgP loc1 loc2 (str ++ " at character " ++ show c)++lexTokenStream :: StringBuffer -> RealSrcLoc -> DynFlags -> ParseResult [Located Token]+lexTokenStream buf loc dflags = unP go initState+ where dflags' = gopt_set (gopt_unset dflags Opt_Haddock) Opt_KeepRawTokenStream+ initState = mkPState dflags' buf loc+ go = do+ ltok <- lexer False return+ case ltok of+ L _ ITeof -> return []+ _ -> liftM (ltok:) go++linePrags = Map.singleton "line" (begin line_prag2)++fileHeaderPrags = Map.fromList([("options", lex_string_prag IToptions_prag),+ ("options_ghc", lex_string_prag IToptions_prag),+ ("options_haddock", lex_string_prag ITdocOptions),+ ("language", token ITlanguage_prag),+ ("include", lex_string_prag ITinclude_prag)])++ignoredPrags = Map.fromList (map ignored pragmas)+ where ignored opt = (opt, nested_comment lexToken)+ impls = ["hugs", "nhc98", "jhc", "yhc", "catch", "derive"]+ options_pragmas = map ("options_" ++) impls+ -- CFILES is a hugs-only thing.+ pragmas = options_pragmas ++ ["cfiles", "contract"]++oneWordPrags = Map.fromList [+ ("rules", rulePrag),+ ("inline",+ strtoken (\s -> (ITinline_prag (SourceText s) Inline FunLike))),+ ("inlinable",+ strtoken (\s -> (ITinline_prag (SourceText s) Inlinable FunLike))),+ ("inlineable",+ strtoken (\s -> (ITinline_prag (SourceText s) Inlinable FunLike))),+ -- Spelling variant+ ("notinline",+ strtoken (\s -> (ITinline_prag (SourceText s) NoInline FunLike))),+ ("specialize", strtoken (\s -> ITspec_prag (SourceText s))),+ ("source", strtoken (\s -> ITsource_prag (SourceText s))),+ ("warning", strtoken (\s -> ITwarning_prag (SourceText s))),+ ("deprecated", strtoken (\s -> ITdeprecated_prag (SourceText s))),+ ("scc", strtoken (\s -> ITscc_prag (SourceText s))),+ ("generated", strtoken (\s -> ITgenerated_prag (SourceText s))),+ ("core", strtoken (\s -> ITcore_prag (SourceText s))),+ ("unpack", strtoken (\s -> ITunpack_prag (SourceText s))),+ ("nounpack", strtoken (\s -> ITnounpack_prag (SourceText s))),+ ("ann", strtoken (\s -> ITann_prag (SourceText s))),+ ("vectorize", strtoken (\s -> ITvect_prag (SourceText s))),+ ("novectorize", strtoken (\s -> ITnovect_prag (SourceText s))),+ ("minimal", strtoken (\s -> ITminimal_prag (SourceText s))),+ ("overlaps", strtoken (\s -> IToverlaps_prag (SourceText s))),+ ("overlappable", strtoken (\s -> IToverlappable_prag (SourceText s))),+ ("overlapping", strtoken (\s -> IToverlapping_prag (SourceText s))),+ ("incoherent", strtoken (\s -> ITincoherent_prag (SourceText s))),+ ("ctype", strtoken (\s -> ITctype (SourceText s))),+ ("complete", strtoken (\s -> ITcomplete_prag (SourceText s))),+ ("column", begin column_prag)+ ]++twoWordPrags = Map.fromList([+ ("inline conlike",+ strtoken (\s -> (ITinline_prag (SourceText s) Inline ConLike))),+ ("notinline conlike",+ strtoken (\s -> (ITinline_prag (SourceText s) NoInline ConLike))),+ ("specialize inline",+ strtoken (\s -> (ITspec_inline_prag (SourceText s) True))),+ ("specialize notinline",+ strtoken (\s -> (ITspec_inline_prag (SourceText s) False))),+ ("vectorize scalar",+ strtoken (\s -> ITvect_scalar_prag (SourceText s)))])++dispatch_pragmas :: Map String Action -> Action+dispatch_pragmas prags span buf len = case Map.lookup (clean_pragma (lexemeToString buf len)) prags of+ Just found -> found span buf len+ Nothing -> lexError "unknown pragma"++known_pragma :: Map String Action -> AlexAccPred ExtsBitmap+known_pragma prags _ (AI _ startbuf) _ (AI _ curbuf)+ = isKnown && nextCharIsNot curbuf pragmaNameChar+ where l = lexemeToString startbuf (byteDiff startbuf curbuf)+ isKnown = isJust $ Map.lookup (clean_pragma l) prags+ pragmaNameChar c = isAlphaNum c || c == '_'++clean_pragma :: String -> String+clean_pragma prag = canon_ws (map toLower (unprefix prag))+ where unprefix prag' = case stripPrefix "{-#" prag' of+ Just rest -> rest+ Nothing -> prag'+ canonical prag' = case prag' of+ "noinline" -> "notinline"+ "specialise" -> "specialize"+ "vectorise" -> "vectorize"+ "novectorise" -> "novectorize"+ "constructorlike" -> "conlike"+ _ -> prag'+ canon_ws s = unwords (map canonical (words s))++++{-+%************************************************************************+%* *+ Helper functions for generating annotations in the parser+%* *+%************************************************************************+-}++-- | Encapsulated call to addAnnotation, requiring only the SrcSpan of+-- the AST construct the annotation belongs to; together with the+-- AnnKeywordId, this is the key of the annotation map.+--+-- This type is useful for places in the parser where it is not yet+-- known what SrcSpan an annotation should be added to. The most+-- common situation is when we are parsing a list: the annotations+-- need to be associated with the AST element that *contains* the+-- list, not the list itself. 'AddAnn' lets us defer adding the+-- annotations until we finish parsing the list and are now parsing+-- the enclosing element; we then apply the 'AddAnn' to associate+-- the annotations. Another common situation is where a common fragment of+-- the AST has been factored out but there is no separate AST node for+-- this fragment (this occurs in class and data declarations). In this+-- case, the annotation belongs to the parent data declaration.+--+-- The usual way an 'AddAnn' is created is using the 'mj' ("make jump")+-- function, and then it can be discharged using the 'ams' function.+type AddAnn = SrcSpan -> P ()++addAnnotation :: SrcSpan -- SrcSpan of enclosing AST construct+ -> AnnKeywordId -- The first two parameters are the key+ -> SrcSpan -- The location of the keyword itself+ -> P ()+addAnnotation l a v = do+ addAnnotationOnly l a v+ allocateComments l++addAnnotationOnly :: SrcSpan -> AnnKeywordId -> SrcSpan -> P ()+addAnnotationOnly l a v = P $ \s -> POk s {+ annotations = ((l,a), [v]) : annotations s+ } ()++-- |Given a location and a list of AddAnn, apply them all to the location.+addAnnsAt :: SrcSpan -> [AddAnn] -> P ()+addAnnsAt loc anns = mapM_ (\a -> a loc) anns++-- |Given a 'SrcSpan' that surrounds a 'HsPar' or 'HsParTy', generate+-- 'AddAnn' values for the opening and closing bordering on the start+-- and end of the span+mkParensApiAnn :: SrcSpan -> [AddAnn]+mkParensApiAnn (UnhelpfulSpan _) = []+mkParensApiAnn s@(RealSrcSpan ss) = [mj AnnOpenP lo,mj AnnCloseP lc]+ where+ mj a l = (\s -> addAnnotation s a l)+ f = srcSpanFile ss+ sl = srcSpanStartLine ss+ sc = srcSpanStartCol ss+ el = srcSpanEndLine ss+ ec = srcSpanEndCol ss+ lo = mkSrcSpan (srcSpanStart s) (mkSrcLoc f sl (sc+1))+ lc = mkSrcSpan (mkSrcLoc f el (ec - 1)) (srcSpanEnd s)++-- | Move the annotations and comments belonging to the @old@ span to the @new@+-- one.+moveAnnotations :: SrcSpan -> SrcSpan -> P ()+moveAnnotations old new = P $ \s ->+ let+ updateAnn ((l,a),v)+ | l == old = ((new,a),v)+ | otherwise = ((l,a),v)+ updateComment (l,c)+ | l == old = (new,c)+ | otherwise = (l,c)+ in+ POk s {+ annotations = map updateAnn (annotations s)+ , annotations_comments = map updateComment (annotations_comments s)+ } ()++queueComment :: Located Token -> P()+queueComment c = P $ \s -> POk s {+ comment_q = commentToAnnotation c : comment_q s+ } ()++-- | Go through the @comment_q@ in @PState@ and remove all comments+-- that belong within the given span+allocateComments :: SrcSpan -> P ()+allocateComments ss = P $ \s ->+ let+ (before,rest) = break (\(L l _) -> isSubspanOf l ss) (comment_q s)+ (middle,after) = break (\(L l _) -> not (isSubspanOf l ss)) rest+ comment_q' = before ++ after+ newAnns = if null middle then []+ else [(ss,middle)]+ in+ POk s {+ comment_q = comment_q'+ , annotations_comments = newAnns ++ (annotations_comments s)+ } ()++commentToAnnotation :: Located Token -> Located AnnotationComment+commentToAnnotation (L l (ITdocCommentNext s)) = L l (AnnDocCommentNext s)+commentToAnnotation (L l (ITdocCommentPrev s)) = L l (AnnDocCommentPrev s)+commentToAnnotation (L l (ITdocCommentNamed s)) = L l (AnnDocCommentNamed s)+commentToAnnotation (L l (ITdocSection n s)) = L l (AnnDocSection n s)+commentToAnnotation (L l (ITdocOptions s)) = L l (AnnDocOptions s)+commentToAnnotation (L l (ITlineComment s)) = L l (AnnLineComment s)+commentToAnnotation (L l (ITblockComment s)) = L l (AnnBlockComment s)+commentToAnnotation _ = panic "commentToAnnotation"++-- ---------------------------------------------------------------------++isComment :: Token -> Bool+isComment (ITlineComment _) = True+isComment (ITblockComment _) = True+isComment _ = False++isDocComment :: Token -> Bool+isDocComment (ITdocCommentNext _) = True+isDocComment (ITdocCommentPrev _) = True+isDocComment (ITdocCommentNamed _) = True+isDocComment (ITdocSection _ _) = True+isDocComment (ITdocOptions _) = True+isDocComment _ = False++{- Note [Warnings in code generated by Alex]++We add the following warning suppression flags to all code generated by Alex:++{-# OPTIONS_GHC -fno-warn-unused-matches #-}+{-# OPTIONS_GHC -fno-warn-unused-binds #-}+{-# OPTIONS_GHC -fno-warn-unused-imports #-}+{-# OPTIONS_GHC -fno-warn-tabs #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++Without these flags, current versions of Alex will generate code that is not+warning free. Note that this is the result of Alex' internals, not of the way+we have written our (Lexer).x files.++As always, we need code to be warning free when validating with -Werror.++The list of flags is as short as possible (at the time of writing), to try to+avoid suppressing warnings for bugs in our own code.++TODO. Reevaluate this situation once Alex >3.1.4 is released. Hopefully you+can remove these flags from all (Lexer).x files in the repository, and also+delete this Note. Don't forget to update aclocal.m4, and send a HEADS UP+message to ghc-devs.++The first release of Alex after 3.1.4 will either suppress all warnings itself+[1] (bad), or most warnings will be fixed and only a few select ones will be+suppressed by default [2] (better).++[1] https://github.com/simonmar/alex/commit/1eefcde22ba1bb9b51d523814415714e20f0761e+[2] https://github.com/simonmar/alex/pull/69+-}+}
+ parser/Parser.y view
@@ -0,0 +1,3723 @@+-- -*-haskell-*-+-- ---------------------------------------------------------------------------+-- (c) The University of Glasgow 1997-2003+---+-- The GHC grammar.+--+-- Author(s): Simon Marlow, Sven Panne 1997, 1998, 1999+-- ---------------------------------------------------------------------------++{+-- | This module provides the generated Happy parser for Haskell. It exports+-- a number of parsers which may be used in any library that uses the GHC API.+-- A common usage pattern is to initialize the parser state with a given string+-- and then parse that string:+--+-- @+-- runParser :: DynFlags -> String -> P a -> ParseResult a+-- runParser flags str parser = unP parser parseState+-- where+-- filename = "\<interactive\>"+-- location = mkRealSrcLoc (mkFastString filename) 1 1+-- buffer = stringToStringBuffer str+-- parseState = mkPState flags buffer location+-- @+module Parser (parseModule, parseSignature, parseImport, parseStatement, parseBackpack,+ parseDeclaration, parseExpression, parsePattern,+ parseTypeSignature,+ parseStmt, parseIdentifier,+ parseType, parseHeader) where++-- base+import Control.Monad ( unless, liftM )+import GHC.Exts+import Data.Char+import Control.Monad ( mplus )+import Control.Applicative ((<$))++-- compiler/hsSyn+import HsSyn++-- compiler/main+import HscTypes ( IsBootInterface, WarningTxt(..) )+import DynFlags+import BkpSyn+import PackageConfig++-- compiler/utils+import OrdList+import BooleanFormula ( BooleanFormula(..), LBooleanFormula(..), mkTrue )+import FastString+import Maybes ( orElse )+import Outputable++-- compiler/basicTypes+import RdrName+import OccName ( varName, dataName, tcClsName, tvName, startsWithUnderscore )+import DataCon ( DataCon, dataConName )+import SrcLoc+import Module+import BasicTypes++-- compiler/types+import Type ( funTyCon )+import Kind ( Kind )+import Class ( FunDep )++-- compiler/parser+import RdrHsSyn+import Lexer+import HaddockUtils+import ApiAnnotation++-- compiler/typecheck+import TcEvidence ( emptyTcEvBinds )++-- compiler/prelude+import ForeignCall+import TysPrim ( eqPrimTyCon )+import PrelNames ( eqTyCon_RDR )+import TysWiredIn ( unitTyCon, unitDataCon, tupleTyCon, tupleDataCon, nilDataCon,+ unboxedUnitTyCon, unboxedUnitDataCon,+ listTyCon_RDR, parrTyCon_RDR, consDataCon_RDR )++-- compiler/utils+import Util ( looksLikePackageName )+import Prelude++import qualified GHC.LanguageExtensions as LangExt+}++%expect 36 -- shift/reduce conflicts++{- Last updated: 3 Aug 2016++If you modify this parser and add a conflict, please update this comment.+You can learn more about the conflicts by passing 'happy' the -i flag:++ happy -agc --strict compiler/parser/Parser.y -idetailed-info++How is this section formatted? Look up the state the conflict is+reported at, and copy the list of applicable rules (at the top, without the+rule numbers). Mark *** for the rule that is the conflicting reduction (that+is, the interpretation which is NOT taken). NB: Happy doesn't print a rule+in a state if it is empty, but you should include it in the list (you can+look these up in the Grammar section of the info file).++Obviously the state numbers are not stable across modifications to the parser,+the idea is to reproduce enough information on each conflict so you can figure+out what happened if the states were renumbered. Try not to gratuitously move+productions around in this file.++-------------------------------------------------------------------------------++state 0 contains 1 shift/reduce conflicts.++ Conflicts: DOCNEXT (empty missing_module_keyword reduces)++Ambiguity when the source file starts with "-- | doc". We need another+token of lookahead to determine if a top declaration or the 'module' keyword+follows. Shift parses as if the 'module' keyword follows.++-------------------------------------------------------------------------------++state 48 contains 2 shift/reduce conflicts.++ *** strict_mark -> unpackedness .+ strict_mark -> unpackedness . strictness++ Conflicts: '~' '!'++-------------------------------------------------------------------------------++state 52 contains 1 shift/reduce conflict.++ context -> btype .+ *** type -> btype .+ type -> btype . '->' ctype++ Conflicts: '->'++-------------------------------------------------------------------------------++state 53 contains 9 shift/reduce conflicts.++ *** btype -> tyapps .+ tyapps -> tyapps . tyapp++ Conflicts: ':' '-' '!' '.' '`' VARSYM CONSYM QVARSYM QCONSYM++-------------------------------------------------------------------------------++state 134 contains 14 shift/reduce conflicts.++ exp -> infixexp . '::' sigtype+ exp -> infixexp . '-<' exp+ exp -> infixexp . '>-' exp+ exp -> infixexp . '-<<' exp+ exp -> infixexp . '>>-' exp+ *** exp -> infixexp .+ infixexp -> infixexp . qop exp10++ Conflicts: ':' '::' '-' '!' '-<' '>-' '-<<' '>>-'+ '.' '`' VARSYM CONSYM QVARSYM QCONSYM++Examples of ambiguity:+ 'if x then y else z -< e'+ 'if x then y else z :: T'+ 'if x then y else z + 1' (NB: '+' is in VARSYM)++Shift parses as (per longest-parse rule):+ 'if x then y else (z -< T)'+ 'if x then y else (z :: T)'+ 'if x then y else (z + 1)'++-------------------------------------------------------------------------------++state 299 contains 1 shift/reduce conflicts.++ rule -> STRING . rule_activation rule_forall infixexp '=' exp++ Conflict: '[' (empty rule_activation reduces)++We don't know whether the '[' starts the activation or not: it+might be the start of the declaration with the activation being+empty. --SDM 1/4/2002++Example ambiguity:+ '{-# RULE [0] f = ... #-}'++We parse this as having a [0] rule activation for rewriting 'f', rather+a rule instructing how to rewrite the expression '[0] f'.++-------------------------------------------------------------------------------++state 309 contains 1 shift/reduce conflict.++ *** type -> btype .+ type -> btype . '->' ctype++ Conflict: '->'++Same as state 50 but without contexts.++-------------------------------------------------------------------------------++state 348 contains 1 shift/reduce conflicts.++ tup_exprs -> commas . tup_tail+ sysdcon_nolist -> '(' commas . ')'+ commas -> commas . ','++ Conflict: ')' (empty tup_tail reduces)++A tuple section with NO free variables '(,,)' is indistinguishable+from the Haskell98 data constructor for a tuple. Shift resolves in+favor of sysdcon, which is good because a tuple section will get rejected+if -XTupleSections is not specified.++-------------------------------------------------------------------------------++state 402 contains 1 shift/reduce conflicts.++ tup_exprs -> commas . tup_tail+ sysdcon_nolist -> '(#' commas . '#)'+ commas -> commas . ','++ Conflict: '#)' (empty tup_tail reduces)++Same as State 324 for unboxed tuples.++-------------------------------------------------------------------------------++state 477 contains 1 shift/reduce conflict.++ oqtycon -> '(' qtyconsym . ')'+ *** qtyconop -> qtyconsym .++ Conflict: ')'++TODO: Why?++-------------------------------------------------------------------------------++state 658 contains 1 shift/reduce conflicts.++ *** aexp2 -> ipvar .+ dbind -> ipvar . '=' exp++ Conflict: '='++Example ambiguity: 'let ?x ...'++The parser can't tell whether the ?x is the lhs of a normal binding or+an implicit binding. Fortunately, resolving as shift gives it the only+sensible meaning, namely the lhs of an implicit binding.++-------------------------------------------------------------------------------++state 731 contains 1 shift/reduce conflicts.++ rule -> STRING rule_activation . rule_forall infixexp '=' exp++ Conflict: 'forall' (empty rule_forall reduces)++Example ambiguity: '{-# RULES "name" forall = ... #-}'++'forall' is a valid variable name---we don't know whether+to treat a forall on the input as the beginning of a quantifier+or the beginning of the rule itself. Resolving to shift means+it's always treated as a quantifier, hence the above is disallowed.+This saves explicitly defining a grammar for the rule lhs that+doesn't include 'forall'.++-------------------------------------------------------------------------------++state 963 contains 1 shift/reduce conflicts.++ transformqual -> 'then' 'group' . 'using' exp+ transformqual -> 'then' 'group' . 'by' exp 'using' exp+ *** special_id -> 'group' .++ Conflict: 'by'++-------------------------------------------------------------------------------++state 1303 contains 1 shift/reduce conflict.++ *** atype -> tyvar .+ tv_bndr -> '(' tyvar . '::' kind ')'++ Conflict: '::'++TODO: Why?++-------------------------------------------------------------------------------+-- API Annotations+--++A lot of the productions are now cluttered with calls to+aa,am,ams,amms etc.++These are helper functions to make sure that the locations of the+various keywords such as do / let / in are captured for use by tools+that want to do source to source conversions, such as refactorers or+structured editors.++The helper functions are defined at the bottom of this file.++See+ https://ghc.haskell.org/trac/ghc/wiki/ApiAnnotations and+ https://ghc.haskell.org/trac/ghc/wiki/GhcAstAnnotations+for some background.++If you modify the parser and want to ensure that the API annotations are processed+correctly, see the README in (REPO)/utils/check-api-annotations for details on+how to set up a test using the check-api-annotations utility, and interpret the+output it generates.++Note [Parsing lists]+---------------------+You might be wondering why we spend so much effort encoding our lists this+way:++importdecls+ : importdecls ';' importdecl+ | importdecls ';'+ | importdecl+ | {- empty -}++This might seem like an awfully roundabout way to declare a list; plus, to add+insult to injury you have to reverse the results at the end. The answer is that+left recursion prevents us from running out of stack space when parsing long+sequences. See: https://www.haskell.org/happy/doc/html/sec-sequences.html for+more guidance.++By adding/removing branches, you can affect what lists are accepted. Here+are the most common patterns, rewritten as regular expressions for clarity:++ -- Equivalent to: ';'* (x ';'+)* x? (can be empty, permits leading/trailing semis)+ xs : xs ';' x+ | xs ';'+ | x+ | {- empty -}++ -- Equivalent to x (';' x)* ';'* (non-empty, permits trailing semis)+ xs : xs ';' x+ | xs ';'+ | x++ -- Equivalent to ';'* alts (';' alts)* ';'* (non-empty, permits leading/trailing semis)+ alts : alts1+ | ';' alts+ alts1 : alts1 ';' alt+ | alts1 ';'+ | alt++ -- Equivalent to x (',' x)+ (non-empty, no trailing semis)+ xs : x+ | x ',' xs++-- -----------------------------------------------------------------------------++-}++%token+ '_' { L _ ITunderscore } -- Haskell keywords+ 'as' { L _ ITas }+ 'case' { L _ ITcase }+ 'class' { L _ ITclass }+ 'data' { L _ ITdata }+ 'default' { L _ ITdefault }+ 'deriving' { L _ ITderiving }+ 'do' { L _ ITdo }+ 'else' { L _ ITelse }+ 'hiding' { L _ IThiding }+ 'if' { L _ ITif }+ 'import' { L _ ITimport }+ 'in' { L _ ITin }+ 'infix' { L _ ITinfix }+ 'infixl' { L _ ITinfixl }+ 'infixr' { L _ ITinfixr }+ 'instance' { L _ ITinstance }+ 'let' { L _ ITlet }+ 'module' { L _ ITmodule }+ 'newtype' { L _ ITnewtype }+ 'of' { L _ ITof }+ 'qualified' { L _ ITqualified }+ 'then' { L _ ITthen }+ 'type' { L _ ITtype }+ 'where' { L _ ITwhere }++ 'forall' { L _ (ITforall _) } -- GHC extension keywords+ 'foreign' { L _ ITforeign }+ 'export' { L _ ITexport }+ 'label' { L _ ITlabel }+ 'dynamic' { L _ ITdynamic }+ 'safe' { L _ ITsafe }+ 'interruptible' { L _ ITinterruptible }+ 'unsafe' { L _ ITunsafe }+ 'mdo' { L _ ITmdo }+ 'family' { L _ ITfamily }+ 'role' { L _ ITrole }+ 'stdcall' { L _ ITstdcallconv }+ 'ccall' { L _ ITccallconv }+ 'capi' { L _ ITcapiconv }+ 'prim' { L _ ITprimcallconv }+ 'javascript' { L _ ITjavascriptcallconv }+ 'proc' { L _ ITproc } -- for arrow notation extension+ 'rec' { L _ ITrec } -- for arrow notation extension+ 'group' { L _ ITgroup } -- for list transform extension+ 'by' { L _ ITby } -- for list transform extension+ 'using' { L _ ITusing } -- for list transform extension+ 'pattern' { L _ ITpattern } -- for pattern synonyms+ 'static' { L _ ITstatic } -- for static pointers extension+ 'stock' { L _ ITstock } -- for DerivingStrategies extension+ 'anyclass' { L _ ITanyclass } -- for DerivingStrategies extension++ 'unit' { L _ ITunit }+ 'signature' { L _ ITsignature }+ 'dependency' { L _ ITdependency }++ '{-# INLINE' { L _ (ITinline_prag _ _ _) } -- INLINE or INLINABLE+ '{-# SPECIALISE' { L _ (ITspec_prag _) }+ '{-# SPECIALISE_INLINE' { L _ (ITspec_inline_prag _ _) }+ '{-# SOURCE' { L _ (ITsource_prag _) }+ '{-# RULES' { L _ (ITrules_prag _) }+ '{-# CORE' { L _ (ITcore_prag _) } -- hdaume: annotated core+ '{-# SCC' { L _ (ITscc_prag _)}+ '{-# GENERATED' { L _ (ITgenerated_prag _) }+ '{-# DEPRECATED' { L _ (ITdeprecated_prag _) }+ '{-# WARNING' { L _ (ITwarning_prag _) }+ '{-# UNPACK' { L _ (ITunpack_prag _) }+ '{-# NOUNPACK' { L _ (ITnounpack_prag _) }+ '{-# ANN' { L _ (ITann_prag _) }+ '{-# VECTORISE' { L _ (ITvect_prag _) }+ '{-# VECTORISE_SCALAR' { L _ (ITvect_scalar_prag _) }+ '{-# NOVECTORISE' { L _ (ITnovect_prag _) }+ '{-# MINIMAL' { L _ (ITminimal_prag _) }+ '{-# CTYPE' { L _ (ITctype _) }+ '{-# OVERLAPPING' { L _ (IToverlapping_prag _) }+ '{-# OVERLAPPABLE' { L _ (IToverlappable_prag _) }+ '{-# OVERLAPS' { L _ (IToverlaps_prag _) }+ '{-# INCOHERENT' { L _ (ITincoherent_prag _) }+ '{-# COMPLETE' { L _ (ITcomplete_prag _) }+ '#-}' { L _ ITclose_prag }++ '..' { L _ ITdotdot } -- reserved symbols+ ':' { L _ ITcolon }+ '::' { L _ (ITdcolon _) }+ '=' { L _ ITequal }+ '\\' { L _ ITlam }+ 'lcase' { L _ ITlcase }+ '|' { L _ ITvbar }+ '<-' { L _ (ITlarrow _) }+ '->' { L _ (ITrarrow _) }+ '@' { L _ ITat }+ '~' { L _ ITtilde }+ '~#' { L _ ITtildehsh }+ '=>' { L _ (ITdarrow _) }+ '-' { L _ ITminus }+ '!' { L _ ITbang }+ '-<' { L _ (ITlarrowtail _) } -- for arrow notation+ '>-' { L _ (ITrarrowtail _) } -- for arrow notation+ '-<<' { L _ (ITLarrowtail _) } -- for arrow notation+ '>>-' { L _ (ITRarrowtail _) } -- for arrow notation+ '.' { L _ ITdot }+ TYPEAPP { L _ ITtypeApp }++ '{' { L _ ITocurly } -- special symbols+ '}' { L _ ITccurly }+ vocurly { L _ ITvocurly } -- virtual open curly (from layout)+ vccurly { L _ ITvccurly } -- virtual close curly (from layout)+ '[' { L _ ITobrack }+ ']' { L _ ITcbrack }+ '[:' { L _ ITopabrack }+ ':]' { L _ ITcpabrack }+ '(' { L _ IToparen }+ ')' { L _ ITcparen }+ '(#' { L _ IToubxparen }+ '#)' { L _ ITcubxparen }+ '(|' { L _ (IToparenbar _) }+ '|)' { L _ (ITcparenbar _) }+ ';' { L _ ITsemi }+ ',' { L _ ITcomma }+ '`' { L _ ITbackquote }+ SIMPLEQUOTE { L _ ITsimpleQuote } -- 'x++ VARID { L _ (ITvarid _) } -- identifiers+ CONID { L _ (ITconid _) }+ VARSYM { L _ (ITvarsym _) }+ CONSYM { L _ (ITconsym _) }+ QVARID { L _ (ITqvarid _) }+ QCONID { L _ (ITqconid _) }+ QVARSYM { L _ (ITqvarsym _) }+ QCONSYM { L _ (ITqconsym _) }++ IPDUPVARID { L _ (ITdupipvarid _) } -- GHC extension+ LABELVARID { L _ (ITlabelvarid _) }++ CHAR { L _ (ITchar _ _) }+ STRING { L _ (ITstring _ _) }+ INTEGER { L _ (ITinteger _ _) }+ RATIONAL { L _ (ITrational _) }++ PRIMCHAR { L _ (ITprimchar _ _) }+ PRIMSTRING { L _ (ITprimstring _ _) }+ PRIMINTEGER { L _ (ITprimint _ _) }+ PRIMWORD { L _ (ITprimword _ _) }+ PRIMFLOAT { L _ (ITprimfloat _) }+ PRIMDOUBLE { L _ (ITprimdouble _) }++ DOCNEXT { L _ (ITdocCommentNext _) }+ DOCPREV { L _ (ITdocCommentPrev _) }+ DOCNAMED { L _ (ITdocCommentNamed _) }+ DOCSECTION { L _ (ITdocSection _ _) }++-- Template Haskell+'[|' { L _ (ITopenExpQuote _ _) }+'[p|' { L _ ITopenPatQuote }+'[t|' { L _ ITopenTypQuote }+'[d|' { L _ ITopenDecQuote }+'|]' { L _ (ITcloseQuote _) }+'[||' { L _ (ITopenTExpQuote _) }+'||]' { L _ ITcloseTExpQuote }+TH_ID_SPLICE { L _ (ITidEscape _) } -- $x+'$(' { L _ ITparenEscape } -- $( exp )+TH_ID_TY_SPLICE { L _ (ITidTyEscape _) } -- $$x+'$$(' { L _ ITparenTyEscape } -- $$( exp )+TH_TY_QUOTE { L _ ITtyQuote } -- ''T+TH_QUASIQUOTE { L _ (ITquasiQuote _) }+TH_QQUASIQUOTE { L _ (ITqQuasiQuote _) }++%monad { P } { >>= } { return }+%lexer { (lexer True) } { L _ ITeof }+%tokentype { (Located Token) }++-- Exported parsers+%name parseModule module+%name parseSignature signature+%name parseImport importdecl+%name parseStatement stmt+%name parseDeclaration topdecl+%name parseExpression exp+%name parsePattern pat+%name parseTypeSignature sigdecl+%name parseStmt maybe_stmt+%name parseIdentifier identifier+%name parseType ctype+%name parseBackpack backpack+%partial parseHeader header+%%++-----------------------------------------------------------------------------+-- Identifiers; one of the entry points+identifier :: { Located RdrName }+ : qvar { $1 }+ | qcon { $1 }+ | qvarop { $1 }+ | qconop { $1 }+ | '(' '->' ')' {% ams (sLL $1 $> $ getRdrName funTyCon)+ [mj AnnOpenP $1,mu AnnRarrow $2,mj AnnCloseP $3] }++-----------------------------------------------------------------------------+-- Backpack stuff++backpack :: { [LHsUnit PackageName] }+ : implicit_top units close { fromOL $2 }+ | '{' units '}' { fromOL $2 }++units :: { OrdList (LHsUnit PackageName) }+ : units ';' unit { $1 `appOL` unitOL $3 }+ | units ';' { $1 }+ | unit { unitOL $1 }++unit :: { LHsUnit PackageName }+ : 'unit' pkgname 'where' unitbody+ { sL1 $1 $ HsUnit { hsunitName = $2+ , hsunitBody = fromOL $4 } }++unitid :: { LHsUnitId PackageName }+ : pkgname { sL1 $1 $ HsUnitId $1 [] }+ | pkgname '[' msubsts ']' { sLL $1 $> $ HsUnitId $1 (fromOL $3) }++msubsts :: { OrdList (LHsModuleSubst PackageName) }+ : msubsts ',' msubst { $1 `appOL` unitOL $3 }+ | msubsts ',' { $1 }+ | msubst { unitOL $1 }++msubst :: { LHsModuleSubst PackageName }+ : modid '=' moduleid { sLL $1 $> $ ($1, $3) }+ | modid VARSYM modid VARSYM { sLL $1 $> $ ($1, sLL $2 $> $ HsModuleVar $3) }++moduleid :: { LHsModuleId PackageName }+ : VARSYM modid VARSYM { sLL $1 $> $ HsModuleVar $2 }+ | unitid ':' modid { sLL $1 $> $ HsModuleId $1 $3 }++pkgname :: { Located PackageName }+ : STRING { sL1 $1 $ PackageName (getSTRING $1) }+ | litpkgname { sL1 $1 $ PackageName (unLoc $1) }++litpkgname_segment :: { Located FastString }+ : VARID { sL1 $1 $ getVARID $1 }+ | CONID { sL1 $1 $ getCONID $1 }+ | special_id { $1 }++litpkgname :: { Located FastString }+ : litpkgname_segment { $1 }+ -- a bit of a hack, means p - b is parsed same as p-b, enough for now.+ | litpkgname_segment '-' litpkgname { sLL $1 $> $ appendFS (unLoc $1) (consFS '-' (unLoc $3)) }++mayberns :: { Maybe [LRenaming] }+ : {- empty -} { Nothing }+ | '(' rns ')' { Just (fromOL $2) }++rns :: { OrdList LRenaming }+ : rns ',' rn { $1 `appOL` unitOL $3 }+ | rns ',' { $1 }+ | rn { unitOL $1 }++rn :: { LRenaming }+ : modid 'as' modid { sLL $1 $> $ Renaming $1 (Just $3) }+ | modid { sL1 $1 $ Renaming $1 Nothing }++unitbody :: { OrdList (LHsUnitDecl PackageName) }+ : '{' unitdecls '}' { $2 }+ | vocurly unitdecls close { $2 }++unitdecls :: { OrdList (LHsUnitDecl PackageName) }+ : unitdecls ';' unitdecl { $1 `appOL` unitOL $3 }+ | unitdecls ';' { $1 }+ | unitdecl { unitOL $1 }++unitdecl :: { LHsUnitDecl PackageName }+ : maybedocheader 'module' modid maybemodwarning maybeexports 'where' body+ -- XXX not accurate+ { sL1 $2 $ DeclD ModuleD $3 (Just (sL1 $2 (HsModule (Just $3) $5 (fst $ snd $7) (snd $ snd $7) $4 $1))) }+ | maybedocheader 'signature' modid maybemodwarning maybeexports 'where' body+ { sL1 $2 $ DeclD SignatureD $3 (Just (sL1 $2 (HsModule (Just $3) $5 (fst $ snd $7) (snd $ snd $7) $4 $1))) }+ -- NB: MUST have maybedocheader here, otherwise shift-reduce conflict+ -- will prevent us from parsing both forms.+ | maybedocheader 'module' modid+ { sL1 $2 $ DeclD ModuleD $3 Nothing }+ | maybedocheader 'signature' modid+ { sL1 $2 $ DeclD SignatureD $3 Nothing }+ | 'dependency' unitid mayberns+ { sL1 $1 $ IncludeD (IncludeDecl { idUnitId = $2+ , idModRenaming = $3+ , idSignatureInclude = False }) }+ | 'dependency' 'signature' unitid+ { sL1 $1 $ IncludeD (IncludeDecl { idUnitId = $3+ , idModRenaming = Nothing+ , idSignatureInclude = True }) }++-----------------------------------------------------------------------------+-- Module Header++-- The place for module deprecation is really too restrictive, but if it+-- was allowed at its natural place just before 'module', we get an ugly+-- s/r conflict with the second alternative. Another solution would be the+-- introduction of a new pragma DEPRECATED_MODULE, but this is not very nice,+-- either, and DEPRECATED is only expected to be used by people who really+-- know what they are doing. :-)++signature :: { Located (HsModule RdrName) }+ : maybedocheader 'signature' modid maybemodwarning maybeexports 'where' body+ {% fileSrcSpan >>= \ loc ->+ ams (L loc (HsModule (Just $3) $5 (fst $ snd $7)+ (snd $ snd $7) $4 $1)+ )+ ([mj AnnSignature $2, mj AnnWhere $6] ++ fst $7) }++module :: { Located (HsModule RdrName) }+ : maybedocheader 'module' modid maybemodwarning maybeexports 'where' body+ {% fileSrcSpan >>= \ loc ->+ ams (L loc (HsModule (Just $3) $5 (fst $ snd $7)+ (snd $ snd $7) $4 $1)+ )+ ([mj AnnModule $2, mj AnnWhere $6] ++ fst $7) }+ | body2+ {% fileSrcSpan >>= \ loc ->+ ams (L loc (HsModule Nothing Nothing+ (fst $ snd $1) (snd $ snd $1) Nothing Nothing))+ (fst $1) }++maybedocheader :: { Maybe LHsDocString }+ : moduleheader { $1 }+ | {- empty -} { Nothing }++missing_module_keyword :: { () }+ : {- empty -} {% pushModuleContext }++implicit_top :: { () }+ : {- empty -} {% pushModuleContext }++maybemodwarning :: { Maybe (Located WarningTxt) }+ : '{-# DEPRECATED' strings '#-}'+ {% ajs (Just (sLL $1 $> $ DeprecatedTxt (sL1 $1 (getDEPRECATED_PRAGs $1)) (snd $ unLoc $2)))+ (mo $1:mc $3: (fst $ unLoc $2)) }+ | '{-# WARNING' strings '#-}'+ {% ajs (Just (sLL $1 $> $ WarningTxt (sL1 $1 (getWARNING_PRAGs $1)) (snd $ unLoc $2)))+ (mo $1:mc $3 : (fst $ unLoc $2)) }+ | {- empty -} { Nothing }++body :: { ([AddAnn]+ ,([LImportDecl RdrName], [LHsDecl RdrName])) }+ : '{' top '}' { (moc $1:mcc $3:(fst $2)+ , snd $2) }+ | vocurly top close { (fst $2, snd $2) }++body2 :: { ([AddAnn]+ ,([LImportDecl RdrName], [LHsDecl RdrName])) }+ : '{' top '}' { (moc $1:mcc $3+ :(fst $2), snd $2) }+ | missing_module_keyword top close { ([],snd $2) }+++top :: { ([AddAnn]+ ,([LImportDecl RdrName], [LHsDecl RdrName])) }+ : semis top1 { ($1, $2) }++top1 :: { ([LImportDecl RdrName], [LHsDecl RdrName]) }+ : importdecls_semi topdecls_semi { (reverse $1, cvTopDecls $2) }+ | importdecls_semi topdecls { (reverse $1, cvTopDecls $2) }+ | importdecls { (reverse $1, []) }++-----------------------------------------------------------------------------+-- Module declaration & imports only++header :: { Located (HsModule RdrName) }+ : maybedocheader 'module' modid maybemodwarning maybeexports 'where' header_body+ {% fileSrcSpan >>= \ loc ->+ ams (L loc (HsModule (Just $3) $5 $7 [] $4 $1+ )) [mj AnnModule $2,mj AnnWhere $6] }+ | maybedocheader 'signature' modid maybemodwarning maybeexports 'where' header_body+ {% fileSrcSpan >>= \ loc ->+ ams (L loc (HsModule (Just $3) $5 $7 [] $4 $1+ )) [mj AnnModule $2,mj AnnWhere $6] }+ | header_body2+ {% fileSrcSpan >>= \ loc ->+ return (L loc (HsModule Nothing Nothing $1 [] Nothing+ Nothing)) }++header_body :: { [LImportDecl RdrName] }+ : '{' header_top { $2 }+ | vocurly header_top { $2 }++header_body2 :: { [LImportDecl RdrName] }+ : '{' header_top { $2 }+ | missing_module_keyword header_top { $2 }++header_top :: { [LImportDecl RdrName] }+ : semis header_top_importdecls { $2 }++header_top_importdecls :: { [LImportDecl RdrName] }+ : importdecls_semi { $1 }+ | importdecls { $1 }++-----------------------------------------------------------------------------+-- The Export List++maybeexports :: { (Maybe (Located [LIE RdrName])) }+ : '(' exportlist ')' {% ams (sLL $1 $> ()) [mop $1,mcp $3] >>+ return (Just (sLL $1 $> (fromOL $2))) }+ | {- empty -} { Nothing }++exportlist :: { OrdList (LIE RdrName) }+ : expdoclist ',' expdoclist {% addAnnotation (oll $1) AnnComma (gl $2)+ >> return ($1 `appOL` $3) }+ | exportlist1 { $1 }++exportlist1 :: { OrdList (LIE RdrName) }+ : expdoclist export expdoclist ',' exportlist1+ {% (addAnnotation (oll ($1 `appOL` $2 `appOL` $3))+ AnnComma (gl $4) ) >>+ return ($1 `appOL` $2 `appOL` $3 `appOL` $5) }+ | expdoclist export expdoclist { $1 `appOL` $2 `appOL` $3 }+ | expdoclist { $1 }++expdoclist :: { OrdList (LIE RdrName) }+ : exp_doc expdoclist { $1 `appOL` $2 }+ | {- empty -} { nilOL }++exp_doc :: { OrdList (LIE RdrName) }+ : docsection { unitOL (sL1 $1 (case (unLoc $1) of (n, doc) -> IEGroup n doc)) }+ | docnamed { unitOL (sL1 $1 (IEDocNamed ((fst . unLoc) $1))) }+ | docnext { unitOL (sL1 $1 (IEDoc (unLoc $1))) }+++ -- No longer allow things like [] and (,,,) to be exported+ -- They are built in syntax, always available+export :: { OrdList (LIE RdrName) }+ : qcname_ext export_subspec {% mkModuleImpExp $1 (snd $ unLoc $2)+ >>= \ie -> amsu (sLL $1 $> ie) (fst $ unLoc $2) }+ | 'module' modid {% amsu (sLL $1 $> (IEModuleContents $2))+ [mj AnnModule $1] }+ | 'pattern' qcon {% amsu (sLL $1 $> (IEVar (sLL $1 $> (IEPattern $2))))+ [mj AnnPattern $1] }++export_subspec :: { Located ([AddAnn],ImpExpSubSpec) }+ : {- empty -} { sL0 ([],ImpExpAbs) }+ | '(' qcnames ')' {% mkImpExpSubSpec (reverse (snd $2))+ >>= \(as,ie) -> return $ sLL $1 $>+ (as ++ [mop $1,mcp $3] ++ fst $2, ie) }+++qcnames :: { ([AddAnn], [Located ImpExpQcSpec]) }+ : {- empty -} { ([],[]) }+ | qcnames1 { $1 }++qcnames1 :: { ([AddAnn], [Located ImpExpQcSpec]) } -- A reversed list+ : qcnames1 ',' qcname_ext_w_wildcard {% case (head (snd $1)) of+ l@(L _ ImpExpQcWildcard) ->+ return ([mj AnnComma $2, mj AnnDotdot l]+ ,(snd (unLoc $3) : snd $1))+ l -> (ams (head (snd $1)) [mj AnnComma $2] >>+ return (fst $1 ++ fst (unLoc $3),+ snd (unLoc $3) : snd $1)) }+++ -- Annotations re-added in mkImpExpSubSpec+ | qcname_ext_w_wildcard { (fst (unLoc $1),[snd (unLoc $1)]) }++-- Variable, data constructor or wildcard+-- or tagged type constructor+qcname_ext_w_wildcard :: { Located ([AddAnn], Located ImpExpQcSpec) }+ : qcname_ext { sL1 $1 ([],$1) }+ | '..' { sL1 $1 ([mj AnnDotdot $1], sL1 $1 ImpExpQcWildcard) }++qcname_ext :: { Located ImpExpQcSpec }+ : qcname { sL1 $1 (ImpExpQcName $1) }+ | 'type' oqtycon {% do { n <- mkTypeImpExp $2+ ; ams (sLL $1 $> (ImpExpQcType n))+ [mj AnnType $1] } }++qcname :: { Located RdrName } -- Variable or type constructor+ : qvar { $1 } -- Things which look like functions+ -- Note: This includes record selectors but+ -- also (-.->), see #11432+ | oqtycon_no_varcon { $1 } -- see Note [Type constructors in export list]++-----------------------------------------------------------------------------+-- Import Declarations++-- importdecls and topdecls must contain at least one declaration;+-- top handles the fact that these may be optional.++-- One or more semicolons+semis1 :: { [AddAnn] }+semis1 : semis1 ';' { mj AnnSemi $2 : $1 }+ | ';' { [mj AnnSemi $1] }++-- Zero or more semicolons+semis :: { [AddAnn] }+semis : semis ';' { mj AnnSemi $2 : $1 }+ | {- empty -} { [] }++-- No trailing semicolons, non-empty+importdecls :: { [LImportDecl RdrName] }+importdecls+ : importdecls_semi importdecl+ { $2 : $1 }++-- May have trailing semicolons, can be empty+importdecls_semi :: { [LImportDecl RdrName] }+importdecls_semi+ : importdecls_semi importdecl semis1+ {% ams $2 $3 >> return ($2 : $1) }+ | {- empty -} { [] }++importdecl :: { LImportDecl RdrName }+ : 'import' maybe_src maybe_safe optqualified maybe_pkg modid maybeas maybeimpspec+ {% ams (L (comb4 $1 $6 (snd $7) $8) $+ ImportDecl { ideclSourceSrc = snd $ fst $2+ , ideclName = $6, ideclPkgQual = snd $5+ , ideclSource = snd $2, ideclSafe = snd $3+ , ideclQualified = snd $4, ideclImplicit = False+ , ideclAs = unLoc (snd $7)+ , ideclHiding = unLoc $8 })+ ((mj AnnImport $1 : (fst $ fst $2) ++ fst $3 ++ fst $4+ ++ fst $5 ++ fst $7)) }++maybe_src :: { (([AddAnn],SourceText),IsBootInterface) }+ : '{-# SOURCE' '#-}' { (([mo $1,mc $2],getSOURCE_PRAGs $1)+ ,True) }+ | {- empty -} { (([],NoSourceText),False) }++maybe_safe :: { ([AddAnn],Bool) }+ : 'safe' { ([mj AnnSafe $1],True) }+ | {- empty -} { ([],False) }++maybe_pkg :: { ([AddAnn],Maybe StringLiteral) }+ : STRING {% let pkgFS = getSTRING $1 in+ if looksLikePackageName (unpackFS pkgFS)+ then return ([mj AnnPackageName $1], Just (StringLiteral (getSTRINGs $1) pkgFS))+ else parseErrorSDoc (getLoc $1) $ vcat [+ text "parse error" <> colon <+> quotes (ppr pkgFS),+ text "Version number or non-alphanumeric" <+>+ text "character in package name"] }+ | {- empty -} { ([],Nothing) }++optqualified :: { ([AddAnn],Bool) }+ : 'qualified' { ([mj AnnQualified $1],True) }+ | {- empty -} { ([],False) }++maybeas :: { ([AddAnn],Located (Maybe (Located ModuleName))) }+ : 'as' modid { ([mj AnnAs $1]+ ,sLL $1 $> (Just $2)) }+ | {- empty -} { ([],noLoc Nothing) }++maybeimpspec :: { Located (Maybe (Bool, Located [LIE RdrName])) }+ : impspec {% let (b, ie) = unLoc $1 in+ checkImportSpec ie+ >>= \checkedIe ->+ return (L (gl $1) (Just (b, checkedIe))) }+ | {- empty -} { noLoc Nothing }++impspec :: { Located (Bool, Located [LIE RdrName]) }+ : '(' exportlist ')' {% ams (sLL $1 $> (False,+ sLL $1 $> $ fromOL $2))+ [mop $1,mcp $3] }+ | 'hiding' '(' exportlist ')' {% ams (sLL $1 $> (True,+ sLL $1 $> $ fromOL $3))+ [mj AnnHiding $1,mop $2,mcp $4] }++-----------------------------------------------------------------------------+-- Fixity Declarations++prec :: { Located (SourceText,Int) }+ : {- empty -} { noLoc (NoSourceText,9) }+ | INTEGER+ {% checkPrecP (sL1 $1 (getINTEGERs $1,fromInteger (getINTEGER $1))) }++infix :: { Located FixityDirection }+ : 'infix' { sL1 $1 InfixN }+ | 'infixl' { sL1 $1 InfixL }+ | 'infixr' { sL1 $1 InfixR }++ops :: { Located (OrdList (Located RdrName)) }+ : ops ',' op {% addAnnotation (oll $ unLoc $1) AnnComma (gl $2) >>+ return (sLL $1 $> ((unLoc $1) `appOL` unitOL $3))}+ | op { sL1 $1 (unitOL $1) }++-----------------------------------------------------------------------------+-- Top-Level Declarations++-- No trailing semicolons, non-empty+topdecls :: { OrdList (LHsDecl RdrName) }+ : topdecls_semi topdecl { $1 `snocOL` $2 }++-- May have trailing semicolons, can be empty+topdecls_semi :: { OrdList (LHsDecl RdrName) }+ : topdecls_semi topdecl semis1 {% ams $2 $3 >> return ($1 `snocOL` $2) }+ | {- empty -} { nilOL }++topdecl :: { LHsDecl RdrName }+ : cl_decl { sL1 $1 (TyClD (unLoc $1)) }+ | ty_decl { sL1 $1 (TyClD (unLoc $1)) }+ | inst_decl { sL1 $1 (InstD (unLoc $1)) }+ | stand_alone_deriving { sLL $1 $> (DerivD (unLoc $1)) }+ | role_annot { sL1 $1 (RoleAnnotD (unLoc $1)) }+ | 'default' '(' comma_types0 ')' {% ams (sLL $1 $> (DefD (DefaultDecl $3)))+ [mj AnnDefault $1+ ,mop $2,mcp $4] }+ | 'foreign' fdecl {% ams (sLL $1 $> (snd $ unLoc $2))+ (mj AnnForeign $1:(fst $ unLoc $2)) }+ | '{-# DEPRECATED' deprecations '#-}' {% ams (sLL $1 $> $ WarningD (Warnings (getDEPRECATED_PRAGs $1) (fromOL $2)))+ [mo $1,mc $3] }+ | '{-# WARNING' warnings '#-}' {% ams (sLL $1 $> $ WarningD (Warnings (getWARNING_PRAGs $1) (fromOL $2)))+ [mo $1,mc $3] }+ | '{-# RULES' rules '#-}' {% ams (sLL $1 $> $ RuleD (HsRules (getRULES_PRAGs $1) (fromOL $2)))+ [mo $1,mc $3] }+ | '{-# VECTORISE' qvar '=' exp '#-}' {% ams (sLL $1 $> $ VectD (HsVect (getVECT_PRAGs $1) $2 $4))+ [mo $1,mj AnnEqual $3+ ,mc $5] }+ | '{-# NOVECTORISE' qvar '#-}' {% ams (sLL $1 $> $ VectD (HsNoVect (getNOVECT_PRAGs $1) $2))+ [mo $1,mc $3] }+ | '{-# VECTORISE' 'type' gtycon '#-}'+ {% ams (sLL $1 $> $+ VectD (HsVectTypeIn (getVECT_PRAGs $1) False $3 Nothing))+ [mo $1,mj AnnType $2,mc $4] }++ | '{-# VECTORISE_SCALAR' 'type' gtycon '#-}'+ {% ams (sLL $1 $> $+ VectD (HsVectTypeIn (getVECT_SCALAR_PRAGs $1) True $3 Nothing))+ [mo $1,mj AnnType $2,mc $4] }++ | '{-# VECTORISE' 'type' gtycon '=' gtycon '#-}'+ {% ams (sLL $1 $> $+ VectD (HsVectTypeIn (getVECT_PRAGs $1) False $3 (Just $5)))+ [mo $1,mj AnnType $2,mj AnnEqual $4,mc $6] }+ | '{-# VECTORISE_SCALAR' 'type' gtycon '=' gtycon '#-}'+ {% ams (sLL $1 $> $+ VectD (HsVectTypeIn (getVECT_SCALAR_PRAGs $1) True $3 (Just $5)))+ [mo $1,mj AnnType $2,mj AnnEqual $4,mc $6] }++ | '{-# VECTORISE' 'class' gtycon '#-}'+ {% ams (sLL $1 $> $ VectD (HsVectClassIn (getVECT_PRAGs $1) $3))+ [mo $1,mj AnnClass $2,mc $4] }+ | annotation { $1 }+ | decl_no_th { $1 }++ -- Template Haskell Extension+ -- The $(..) form is one possible form of infixexp+ -- but we treat an arbitrary expression just as if+ -- it had a $(..) wrapped around it+ | infixexp_top { sLL $1 $> $ mkSpliceDecl $1 }++-- Type classes+--+cl_decl :: { LTyClDecl RdrName }+ : 'class' tycl_hdr fds where_cls+ {% amms (mkClassDecl (comb4 $1 $2 $3 $4) $2 $3 (snd $ unLoc $4))+ (mj AnnClass $1:(fst $ unLoc $3)++(fst $ unLoc $4)) }++-- Type declarations (toplevel)+--+ty_decl :: { LTyClDecl RdrName }+ -- ordinary type synonyms+ : 'type' type '=' ctypedoc+ -- Note ctype, not sigtype, on the right of '='+ -- We allow an explicit for-all but we don't insert one+ -- in type Foo a = (b,b)+ -- Instead we just say b is out of scope+ --+ -- Note the use of type for the head; this allows+ -- infix type constructors to be declared+ {% amms (mkTySynonym (comb2 $1 $4) $2 $4)+ [mj AnnType $1,mj AnnEqual $3] }++ -- type family declarations+ | 'type' 'family' type opt_tyfam_kind_sig opt_injective_info+ where_type_family+ -- Note the use of type for the head; this allows+ -- infix type constructors to be declared+ {% amms (mkFamDecl (comb4 $1 $3 $4 $5) (snd $ unLoc $6) $3+ (snd $ unLoc $4) (snd $ unLoc $5))+ (mj AnnType $1:mj AnnFamily $2:(fst $ unLoc $4)+ ++ (fst $ unLoc $5) ++ (fst $ unLoc $6)) }++ -- ordinary data type or newtype declaration+ | data_or_newtype capi_ctype tycl_hdr constrs maybe_derivings+ {% amms (mkTyData (comb4 $1 $3 $4 $5) (snd $ unLoc $1) $2 $3+ Nothing (reverse (snd $ unLoc $4))+ (fmap reverse $5))+ -- We need the location on tycl_hdr in case+ -- constrs and deriving are both empty+ ((fst $ unLoc $1):(fst $ unLoc $4)) }++ -- ordinary GADT declaration+ | data_or_newtype capi_ctype tycl_hdr opt_kind_sig+ gadt_constrlist+ maybe_derivings+ {% amms (mkTyData (comb4 $1 $3 $5 $6) (snd $ unLoc $1) $2 $3+ (snd $ unLoc $4) (snd $ unLoc $5)+ (fmap reverse $6) )+ -- We need the location on tycl_hdr in case+ -- constrs and deriving are both empty+ ((fst $ unLoc $1):(fst $ unLoc $4)++(fst $ unLoc $5)) }++ -- data/newtype family+ | 'data' 'family' type opt_datafam_kind_sig+ {% amms (mkFamDecl (comb3 $1 $2 $4) DataFamily $3+ (snd $ unLoc $4) Nothing)+ (mj AnnData $1:mj AnnFamily $2:(fst $ unLoc $4)) }++inst_decl :: { LInstDecl RdrName }+ : 'instance' overlap_pragma inst_type where_inst+ {% do { (binds, sigs, _, ats, adts, _) <- cvBindsAndSigs (snd $ unLoc $4)+ ; let cid = ClsInstDecl { cid_poly_ty = $3, cid_binds = binds+ , cid_sigs = mkClassOpSigs sigs+ , cid_tyfam_insts = ats+ , cid_overlap_mode = $2+ , cid_datafam_insts = adts }+ ; ams (L (comb3 $1 (hsSigType $3) $4) (ClsInstD { cid_inst = cid }))+ (mj AnnInstance $1 : (fst $ unLoc $4)) } }++ -- type instance declarations+ | 'type' 'instance' ty_fam_inst_eqn+ {% ams $3 (fst $ unLoc $3)+ >> amms (mkTyFamInst (comb2 $1 $3) (snd $ unLoc $3))+ (mj AnnType $1:mj AnnInstance $2:(fst $ unLoc $3)) }++ -- data/newtype instance declaration+ | data_or_newtype 'instance' capi_ctype tycl_hdr constrs+ maybe_derivings+ {% amms (mkDataFamInst (comb4 $1 $4 $5 $6) (snd $ unLoc $1) $3 $4+ Nothing (reverse (snd $ unLoc $5))+ (fmap reverse $6))+ ((fst $ unLoc $1):mj AnnInstance $2:(fst $ unLoc $5)) }++ -- GADT instance declaration+ | data_or_newtype 'instance' capi_ctype tycl_hdr opt_kind_sig+ gadt_constrlist+ maybe_derivings+ {% amms (mkDataFamInst (comb4 $1 $4 $6 $7) (snd $ unLoc $1) $3 $4+ (snd $ unLoc $5) (snd $ unLoc $6)+ (fmap reverse $7))+ ((fst $ unLoc $1):mj AnnInstance $2+ :(fst $ unLoc $5)++(fst $ unLoc $6)) }++overlap_pragma :: { Maybe (Located OverlapMode) }+ : '{-# OVERLAPPABLE' '#-}' {% ajs (Just (sLL $1 $> (Overlappable (getOVERLAPPABLE_PRAGs $1))))+ [mo $1,mc $2] }+ | '{-# OVERLAPPING' '#-}' {% ajs (Just (sLL $1 $> (Overlapping (getOVERLAPPING_PRAGs $1))))+ [mo $1,mc $2] }+ | '{-# OVERLAPS' '#-}' {% ajs (Just (sLL $1 $> (Overlaps (getOVERLAPS_PRAGs $1))))+ [mo $1,mc $2] }+ | '{-# INCOHERENT' '#-}' {% ajs (Just (sLL $1 $> (Incoherent (getINCOHERENT_PRAGs $1))))+ [mo $1,mc $2] }+ | {- empty -} { Nothing }++deriv_strategy :: { Maybe (Located DerivStrategy) }+ : 'stock' {% ajs (Just (sL1 $1 StockStrategy))+ [mj AnnStock $1] }+ | 'anyclass' {% ajs (Just (sL1 $1 AnyclassStrategy))+ [mj AnnAnyclass $1] }+ | 'newtype' {% ajs (Just (sL1 $1 NewtypeStrategy))+ [mj AnnNewtype $1] }+ | {- empty -} { Nothing }++-- Injective type families++opt_injective_info :: { Located ([AddAnn], Maybe (LInjectivityAnn RdrName)) }+ : {- empty -} { noLoc ([], Nothing) }+ | '|' injectivity_cond { sLL $1 $> ([mj AnnVbar $1]+ , Just ($2)) }++injectivity_cond :: { LInjectivityAnn RdrName }+ : tyvarid '->' inj_varids+ {% ams (sLL $1 $> (InjectivityAnn $1 (reverse (unLoc $3))))+ [mu AnnRarrow $2] }++inj_varids :: { Located [Located RdrName] }+ : inj_varids tyvarid { sLL $1 $> ($2 : unLoc $1) }+ | tyvarid { sLL $1 $> [$1] }++-- Closed type families++where_type_family :: { Located ([AddAnn],FamilyInfo RdrName) }+ : {- empty -} { noLoc ([],OpenTypeFamily) }+ | 'where' ty_fam_inst_eqn_list+ { sLL $1 $> (mj AnnWhere $1:(fst $ unLoc $2)+ ,ClosedTypeFamily (fmap reverse $ snd $ unLoc $2)) }++ty_fam_inst_eqn_list :: { Located ([AddAnn],Maybe [LTyFamInstEqn RdrName]) }+ : '{' ty_fam_inst_eqns '}' { sLL $1 $> ([moc $1,mcc $3]+ ,Just (unLoc $2)) }+ | vocurly ty_fam_inst_eqns close { let L loc _ = $2 in+ L loc ([],Just (unLoc $2)) }+ | '{' '..' '}' { sLL $1 $> ([moc $1,mj AnnDotdot $2+ ,mcc $3],Nothing) }+ | vocurly '..' close { let L loc _ = $2 in+ L loc ([mj AnnDotdot $2],Nothing) }++ty_fam_inst_eqns :: { Located [LTyFamInstEqn RdrName] }+ : ty_fam_inst_eqns ';' ty_fam_inst_eqn+ {% asl (unLoc $1) $2 (snd $ unLoc $3)+ >> ams $3 (fst $ unLoc $3)+ >> return (sLL $1 $> ((snd $ unLoc $3) : unLoc $1)) }+ | ty_fam_inst_eqns ';' {% addAnnotation (gl $1) AnnSemi (gl $2)+ >> return (sLL $1 $> (unLoc $1)) }+ | ty_fam_inst_eqn {% ams $1 (fst $ unLoc $1)+ >> return (sLL $1 $> [snd $ unLoc $1]) }+ | {- empty -} { noLoc [] }++ty_fam_inst_eqn :: { Located ([AddAnn],LTyFamInstEqn RdrName) }+ : type '=' ctype+ -- Note the use of type for the head; this allows+ -- infix type constructors and type patterns+ {% do { (eqn,ann) <- mkTyFamInstEqn $1 $3+ ; return (sLL $1 $> (mj AnnEqual $2:ann, sLL $1 $> eqn)) } }++-- Associated type family declarations+--+-- * They have a different syntax than on the toplevel (no family special+-- identifier).+--+-- * They also need to be separate from instances; otherwise, data family+-- declarations without a kind signature cause parsing conflicts with empty+-- data declarations.+--+at_decl_cls :: { LHsDecl RdrName }+ : -- data family declarations, with optional 'family' keyword+ 'data' opt_family type opt_datafam_kind_sig+ {% amms (liftM mkTyClD (mkFamDecl (comb3 $1 $3 $4) DataFamily $3+ (snd $ unLoc $4) Nothing))+ (mj AnnData $1:$2++(fst $ unLoc $4)) }++ -- type family declarations, with optional 'family' keyword+ -- (can't use opt_instance because you get shift/reduce errors+ | 'type' type opt_at_kind_inj_sig+ {% amms (liftM mkTyClD+ (mkFamDecl (comb3 $1 $2 $3) OpenTypeFamily $2+ (fst . snd $ unLoc $3)+ (snd . snd $ unLoc $3)))+ (mj AnnType $1:(fst $ unLoc $3)) }+ | 'type' 'family' type opt_at_kind_inj_sig+ {% amms (liftM mkTyClD+ (mkFamDecl (comb3 $1 $3 $4) OpenTypeFamily $3+ (fst . snd $ unLoc $4)+ (snd . snd $ unLoc $4)))+ (mj AnnType $1:mj AnnFamily $2:(fst $ unLoc $4)) }++ -- default type instances, with optional 'instance' keyword+ | 'type' ty_fam_inst_eqn+ {% ams $2 (fst $ unLoc $2) >>+ amms (liftM mkInstD (mkTyFamInst (comb2 $1 $2) (snd $ unLoc $2)))+ (mj AnnType $1:(fst $ unLoc $2)) }+ | 'type' 'instance' ty_fam_inst_eqn+ {% ams $3 (fst $ unLoc $3) >>+ amms (liftM mkInstD (mkTyFamInst (comb2 $1 $3) (snd $ unLoc $3)))+ (mj AnnType $1:mj AnnInstance $2:(fst $ unLoc $3)) }++opt_family :: { [AddAnn] }+ : {- empty -} { [] }+ | 'family' { [mj AnnFamily $1] }++-- Associated type instances+--+at_decl_inst :: { LInstDecl RdrName }+ -- type instance declarations+ : 'type' ty_fam_inst_eqn+ -- Note the use of type for the head; this allows+ -- infix type constructors and type patterns+ {% ams $2 (fst $ unLoc $2) >>+ amms (mkTyFamInst (comb2 $1 $2) (snd $ unLoc $2))+ (mj AnnType $1:(fst $ unLoc $2)) }++ -- data/newtype instance declaration+ | data_or_newtype capi_ctype tycl_hdr constrs maybe_derivings+ {% amms (mkDataFamInst (comb4 $1 $3 $4 $5) (snd $ unLoc $1) $2 $3+ Nothing (reverse (snd $ unLoc $4))+ (fmap reverse $5))+ ((fst $ unLoc $1):(fst $ unLoc $4)) }++ -- GADT instance declaration+ | data_or_newtype capi_ctype tycl_hdr opt_kind_sig+ gadt_constrlist+ maybe_derivings+ {% amms (mkDataFamInst (comb4 $1 $3 $5 $6) (snd $ unLoc $1) $2+ $3 (snd $ unLoc $4) (snd $ unLoc $5)+ (fmap reverse $6))+ ((fst $ unLoc $1):(fst $ unLoc $4)++(fst $ unLoc $5)) }++data_or_newtype :: { Located (AddAnn, NewOrData) }+ : 'data' { sL1 $1 (mj AnnData $1,DataType) }+ | 'newtype' { sL1 $1 (mj AnnNewtype $1,NewType) }++-- Family result/return kind signatures++opt_kind_sig :: { Located ([AddAnn], Maybe (LHsKind RdrName)) }+ : { noLoc ([] , Nothing) }+ | '::' kind { sLL $1 $> ([mu AnnDcolon $1], Just $2) }++opt_datafam_kind_sig :: { Located ([AddAnn], LFamilyResultSig RdrName) }+ : { noLoc ([] , noLoc NoSig )}+ | '::' kind { sLL $1 $> ([mu AnnDcolon $1], sLL $1 $> (KindSig $2))}++opt_tyfam_kind_sig :: { Located ([AddAnn], LFamilyResultSig RdrName) }+ : { noLoc ([] , noLoc NoSig )}+ | '::' kind { sLL $1 $> ([mu AnnDcolon $1], sLL $1 $> (KindSig $2))}+ | '=' tv_bndr { sLL $1 $> ([mj AnnEqual $1] , sLL $1 $> (TyVarSig $2))}++opt_at_kind_inj_sig :: { Located ([AddAnn], ( LFamilyResultSig RdrName+ , Maybe (LInjectivityAnn RdrName)))}+ : { noLoc ([], (noLoc NoSig, Nothing)) }+ | '::' kind { sLL $1 $> ( [mu AnnDcolon $1]+ , (sLL $2 $> (KindSig $2), Nothing)) }+ | '=' tv_bndr '|' injectivity_cond+ { sLL $1 $> ([mj AnnEqual $1, mj AnnVbar $3]+ , (sLL $1 $2 (TyVarSig $2), Just $4))}++-- tycl_hdr parses the header of a class or data type decl,+-- which takes the form+-- T a b+-- Eq a => T a+-- (Eq a, Ord b) => T a b+-- T Int [a] -- for associated types+-- Rather a lot of inlining here, else we get reduce/reduce errors+tycl_hdr :: { Located (Maybe (LHsContext RdrName), LHsType RdrName) }+ : context '=>' type {% addAnnotation (gl $1) (toUnicodeAnn AnnDarrow $2) (gl $2)+ >> (return (sLL $1 $> (Just $1, $3)))+ }+ | type { sL1 $1 (Nothing, $1) }++capi_ctype :: { Maybe (Located CType) }+capi_ctype : '{-# CTYPE' STRING STRING '#-}'+ {% ajs (Just (sLL $1 $> (CType (getCTYPEs $1) (Just (Header (getSTRINGs $2) (getSTRING $2)))+ (getSTRINGs $3,getSTRING $3))))+ [mo $1,mj AnnHeader $2,mj AnnVal $3,mc $4] }++ | '{-# CTYPE' STRING '#-}'+ {% ajs (Just (sLL $1 $> (CType (getCTYPEs $1) Nothing (getSTRINGs $2, getSTRING $2))))+ [mo $1,mj AnnVal $2,mc $3] }++ | { Nothing }++-----------------------------------------------------------------------------+-- Stand-alone deriving++-- Glasgow extension: stand-alone deriving declarations+stand_alone_deriving :: { LDerivDecl RdrName }+ : 'deriving' deriv_strategy 'instance' overlap_pragma inst_type+ {% do { let { err = text "in the stand-alone deriving instance"+ <> colon <+> quotes (ppr $5) }+ ; ams (sLL $1 (hsSigType $>) (DerivDecl $5 $2 $4))+ [mj AnnDeriving $1, mj AnnInstance $3] } }++-----------------------------------------------------------------------------+-- Role annotations++role_annot :: { LRoleAnnotDecl RdrName }+role_annot : 'type' 'role' oqtycon maybe_roles+ {% amms (mkRoleAnnotDecl (comb3 $1 $3 $4) $3 (reverse (unLoc $4)))+ [mj AnnType $1,mj AnnRole $2] }++-- Reversed!+maybe_roles :: { Located [Located (Maybe FastString)] }+maybe_roles : {- empty -} { noLoc [] }+ | roles { $1 }++roles :: { Located [Located (Maybe FastString)] }+roles : role { sLL $1 $> [$1] }+ | roles role { sLL $1 $> $ $2 : unLoc $1 }++-- read it in as a varid for better error messages+role :: { Located (Maybe FastString) }+role : VARID { sL1 $1 $ Just $ getVARID $1 }+ | '_' { sL1 $1 Nothing }++-- Pattern synonyms++-- Glasgow extension: pattern synonyms+pattern_synonym_decl :: { LHsDecl RdrName }+ : 'pattern' pattern_synonym_lhs '=' pat+ {% let (name, args,as ) = $2 in+ ams (sLL $1 $> . ValD $ mkPatSynBind name args $4+ ImplicitBidirectional)+ (as ++ [mj AnnPattern $1, mj AnnEqual $3])+ }++ | 'pattern' pattern_synonym_lhs '<-' pat+ {% let (name, args, as) = $2 in+ ams (sLL $1 $> . ValD $ mkPatSynBind name args $4 Unidirectional)+ (as ++ [mj AnnPattern $1,mu AnnLarrow $3]) }++ | 'pattern' pattern_synonym_lhs '<-' pat where_decls+ {% do { let (name, args, as) = $2+ ; mg <- mkPatSynMatchGroup name (snd $ unLoc $5)+ ; ams (sLL $1 $> . ValD $+ mkPatSynBind name args $4 (ExplicitBidirectional mg))+ (as ++ ((mj AnnPattern $1:mu AnnLarrow $3:(fst $ unLoc $5))) )+ }}++pattern_synonym_lhs :: { (Located RdrName, HsPatSynDetails (Located RdrName), [AddAnn]) }+ : con vars0 { ($1, PrefixPatSyn $2, []) }+ | varid conop varid { ($2, InfixPatSyn $1 $3, []) }+ | con '{' cvars1 '}' { ($1, RecordPatSyn $3, [moc $2, mcc $4] ) }++vars0 :: { [Located RdrName] }+ : {- empty -} { [] }+ | varid vars0 { $1 : $2 }++cvars1 :: { [RecordPatSynField (Located RdrName)] }+ : varid { [RecordPatSynField $1 $1] }+ | varid ',' cvars1 {% addAnnotation (getLoc $1) AnnComma (getLoc $2) >>+ return ((RecordPatSynField $1 $1) : $3 )}++where_decls :: { Located ([AddAnn]+ , Located (OrdList (LHsDecl RdrName))) }+ : 'where' '{' decls '}' { sLL $1 $> ((mj AnnWhere $1:moc $2+ :mcc $4:(fst $ unLoc $3)),sL1 $3 (snd $ unLoc $3)) }+ | 'where' vocurly decls close { L (comb2 $1 $3) ((mj AnnWhere $1:(fst $ unLoc $3))+ ,sL1 $3 (snd $ unLoc $3)) }++pattern_synonym_sig :: { LSig RdrName }+ : 'pattern' con_list '::' sigtypedoc+ {% ams (sLL $1 $> $ PatSynSig (unLoc $2) (mkLHsSigType $4))+ [mj AnnPattern $1, mu AnnDcolon $3] }++-----------------------------------------------------------------------------+-- Nested declarations++-- Declaration in class bodies+--+decl_cls :: { LHsDecl RdrName }+decl_cls : at_decl_cls { $1 }+ | decl { $1 }++ -- A 'default' signature used with the generic-programming extension+ | 'default' infixexp '::' sigtypedoc+ {% do { v <- checkValSigLhs $2+ ; let err = text "in default signature" <> colon <+>+ quotes (ppr $2)+ ; ams (sLL $1 $> $ SigD $ ClassOpSig True [v] $ mkLHsSigType $4)+ [mj AnnDefault $1,mu AnnDcolon $3] } }++decls_cls :: { Located ([AddAnn],OrdList (LHsDecl RdrName)) } -- Reversed+ : decls_cls ';' decl_cls {% if isNilOL (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ , unitOL $3))+ else ams (lastOL (snd $ unLoc $1)) [mj AnnSemi $2]+ >> return (sLL $1 $> (fst $ unLoc $1+ ,(snd $ unLoc $1) `appOL` unitOL $3)) }+ | decls_cls ';' {% if isNilOL (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ ,snd $ unLoc $1))+ else ams (lastOL (snd $ unLoc $1)) [mj AnnSemi $2]+ >> return (sLL $1 $> (unLoc $1)) }+ | decl_cls { sL1 $1 ([], unitOL $1) }+ | {- empty -} { noLoc ([],nilOL) }++decllist_cls+ :: { Located ([AddAnn]+ , OrdList (LHsDecl RdrName)) } -- Reversed+ : '{' decls_cls '}' { sLL $1 $> (moc $1:mcc $3:(fst $ unLoc $2)+ ,snd $ unLoc $2) }+ | vocurly decls_cls close { $2 }++-- Class body+--+where_cls :: { Located ([AddAnn]+ ,(OrdList (LHsDecl RdrName))) } -- Reversed+ -- No implicit parameters+ -- May have type declarations+ : 'where' decllist_cls { sLL $1 $> (mj AnnWhere $1:(fst $ unLoc $2)+ ,snd $ unLoc $2) }+ | {- empty -} { noLoc ([],nilOL) }++-- Declarations in instance bodies+--+decl_inst :: { Located (OrdList (LHsDecl RdrName)) }+decl_inst : at_decl_inst { sLL $1 $> (unitOL (sL1 $1 (InstD (unLoc $1)))) }+ | decl { sLL $1 $> (unitOL $1) }++decls_inst :: { Located ([AddAnn],OrdList (LHsDecl RdrName)) } -- Reversed+ : decls_inst ';' decl_inst {% if isNilOL (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ , unLoc $3))+ else ams (lastOL $ snd $ unLoc $1) [mj AnnSemi $2]+ >> return+ (sLL $1 $> (fst $ unLoc $1+ ,(snd $ unLoc $1) `appOL` unLoc $3)) }+ | decls_inst ';' {% if isNilOL (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ ,snd $ unLoc $1))+ else ams (lastOL $ snd $ unLoc $1) [mj AnnSemi $2]+ >> return (sLL $1 $> (unLoc $1)) }+ | decl_inst { sL1 $1 ([],unLoc $1) }+ | {- empty -} { noLoc ([],nilOL) }++decllist_inst+ :: { Located ([AddAnn]+ , OrdList (LHsDecl RdrName)) } -- Reversed+ : '{' decls_inst '}' { sLL $1 $> (moc $1:mcc $3:(fst $ unLoc $2),snd $ unLoc $2) }+ | vocurly decls_inst close { L (gl $2) (unLoc $2) }++-- Instance body+--+where_inst :: { Located ([AddAnn]+ , OrdList (LHsDecl RdrName)) } -- Reversed+ -- No implicit parameters+ -- May have type declarations+ : 'where' decllist_inst { sLL $1 $> (mj AnnWhere $1:(fst $ unLoc $2)+ ,(snd $ unLoc $2)) }+ | {- empty -} { noLoc ([],nilOL) }++-- Declarations in binding groups other than classes and instances+--+decls :: { Located ([AddAnn],OrdList (LHsDecl RdrName)) }+ : decls ';' decl {% if isNilOL (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ , unitOL $3))+ else do ams (lastOL $ snd $ unLoc $1) [mj AnnSemi $2]+ >> return (+ let { this = unitOL $3;+ rest = snd $ unLoc $1;+ these = rest `appOL` this }+ in rest `seq` this `seq` these `seq`+ (sLL $1 $> (fst $ unLoc $1,these))) }+ | decls ';' {% if isNilOL (snd $ unLoc $1)+ then return (sLL $1 $> ((mj AnnSemi $2:(fst $ unLoc $1)+ ,snd $ unLoc $1)))+ else ams (lastOL $ snd $ unLoc $1) [mj AnnSemi $2]+ >> return (sLL $1 $> (unLoc $1)) }+ | decl { sL1 $1 ([], unitOL $1) }+ | {- empty -} { noLoc ([],nilOL) }++decllist :: { Located ([AddAnn],Located (OrdList (LHsDecl RdrName))) }+ : '{' decls '}' { sLL $1 $> (moc $1:mcc $3:(fst $ unLoc $2)+ ,sL1 $2 $ snd $ unLoc $2) }+ | vocurly decls close { L (gl $2) (fst $ unLoc $2,sL1 $2 $ snd $ unLoc $2) }++-- Binding groups other than those of class and instance declarations+--+binds :: { Located ([AddAnn],Located (HsLocalBinds RdrName)) }+ -- May have implicit parameters+ -- No type declarations+ : decllist {% do { val_binds <- cvBindGroup (unLoc $ snd $ unLoc $1)+ ; return (sL1 $1 (fst $ unLoc $1+ ,sL1 $1 $ HsValBinds val_binds)) } }++ | '{' dbinds '}' { sLL $1 $> ([moc $1,mcc $3]+ ,sL1 $2 $ HsIPBinds (IPBinds (reverse $ unLoc $2)+ emptyTcEvBinds)) }++ | vocurly dbinds close { L (getLoc $2) ([]+ ,sL1 $2 $ HsIPBinds (IPBinds (reverse $ unLoc $2)+ emptyTcEvBinds)) }+++wherebinds :: { Located ([AddAnn],Located (HsLocalBinds RdrName)) }+ -- May have implicit parameters+ -- No type declarations+ : 'where' binds { sLL $1 $> (mj AnnWhere $1 : (fst $ unLoc $2)+ ,snd $ unLoc $2) }+ | {- empty -} { noLoc ([],noLoc emptyLocalBinds) }+++-----------------------------------------------------------------------------+-- Transformation Rules++rules :: { OrdList (LRuleDecl RdrName) }+ : rules ';' rule {% addAnnotation (oll $1) AnnSemi (gl $2)+ >> return ($1 `snocOL` $3) }+ | rules ';' {% addAnnotation (oll $1) AnnSemi (gl $2)+ >> return $1 }+ | rule { unitOL $1 }+ | {- empty -} { nilOL }++rule :: { LRuleDecl RdrName }+ : STRING rule_activation rule_forall infixexp '=' exp+ {%ams (sLL $1 $> $ (HsRule (L (gl $1) (getSTRINGs $1,getSTRING $1))+ ((snd $2) `orElse` AlwaysActive)+ (snd $3) $4 placeHolderNames $6+ placeHolderNames))+ (mj AnnEqual $5 : (fst $2) ++ (fst $3)) }++-- Rules can be specified to be NeverActive, unlike inline/specialize pragmas+rule_activation :: { ([AddAnn],Maybe Activation) }+ : {- empty -} { ([],Nothing) }+ | rule_explicit_activation { (fst $1,Just (snd $1)) }++rule_explicit_activation :: { ([AddAnn]+ ,Activation) } -- In brackets+ : '[' INTEGER ']' { ([mos $1,mj AnnVal $2,mcs $3]+ ,ActiveAfter (getINTEGERs $2) (fromInteger (getINTEGER $2))) }+ | '[' '~' INTEGER ']' { ([mos $1,mj AnnTilde $2,mj AnnVal $3,mcs $4]+ ,ActiveBefore (getINTEGERs $3) (fromInteger (getINTEGER $3))) }+ | '[' '~' ']' { ([mos $1,mj AnnTilde $2,mcs $3]+ ,NeverActive) }++rule_forall :: { ([AddAnn],[LRuleBndr RdrName]) }+ : 'forall' rule_var_list '.' { ([mu AnnForall $1,mj AnnDot $3],$2) }+ | {- empty -} { ([],[]) }++rule_var_list :: { [LRuleBndr RdrName] }+ : rule_var { [$1] }+ | rule_var rule_var_list { $1 : $2 }++rule_var :: { LRuleBndr RdrName }+ : varid { sLL $1 $> (RuleBndr $1) }+ | '(' varid '::' ctype ')' {% ams (sLL $1 $> (RuleBndrSig $2+ (mkLHsSigWcType $4)))+ [mop $1,mu AnnDcolon $3,mcp $5] }++-----------------------------------------------------------------------------+-- Warnings and deprecations (c.f. rules)++warnings :: { OrdList (LWarnDecl RdrName) }+ : warnings ';' warning {% addAnnotation (oll $1) AnnSemi (gl $2)+ >> return ($1 `appOL` $3) }+ | warnings ';' {% addAnnotation (oll $1) AnnSemi (gl $2)+ >> return $1 }+ | warning { $1 }+ | {- empty -} { nilOL }++-- SUP: TEMPORARY HACK, not checking for `module Foo'+warning :: { OrdList (LWarnDecl RdrName) }+ : namelist strings+ {% amsu (sLL $1 $> (Warning (unLoc $1) (WarningTxt (noLoc NoSourceText) $ snd $ unLoc $2)))+ (fst $ unLoc $2) }++deprecations :: { OrdList (LWarnDecl RdrName) }+ : deprecations ';' deprecation+ {% addAnnotation (oll $1) AnnSemi (gl $2)+ >> return ($1 `appOL` $3) }+ | deprecations ';' {% addAnnotation (oll $1) AnnSemi (gl $2)+ >> return $1 }+ | deprecation { $1 }+ | {- empty -} { nilOL }++-- SUP: TEMPORARY HACK, not checking for `module Foo'+deprecation :: { OrdList (LWarnDecl RdrName) }+ : namelist strings+ {% amsu (sLL $1 $> $ (Warning (unLoc $1) (DeprecatedTxt (noLoc NoSourceText) $ snd $ unLoc $2)))+ (fst $ unLoc $2) }++strings :: { Located ([AddAnn],[Located StringLiteral]) }+ : STRING { sL1 $1 ([],[L (gl $1) (getStringLiteral $1)]) }+ | '[' stringlist ']' { sLL $1 $> $ ([mos $1,mcs $3],fromOL (unLoc $2)) }++stringlist :: { Located (OrdList (Located StringLiteral)) }+ : stringlist ',' STRING {% addAnnotation (oll $ unLoc $1) AnnComma (gl $2) >>+ return (sLL $1 $> (unLoc $1 `snocOL`+ (L (gl $3) (getStringLiteral $3)))) }+ | STRING { sLL $1 $> (unitOL (L (gl $1) (getStringLiteral $1))) }+ | {- empty -} { noLoc nilOL }++-----------------------------------------------------------------------------+-- Annotations+annotation :: { LHsDecl RdrName }+ : '{-# ANN' name_var aexp '#-}' {% ams (sLL $1 $> (AnnD $ HsAnnotation+ (getANN_PRAGs $1)+ (ValueAnnProvenance $2) $3))+ [mo $1,mc $4] }++ | '{-# ANN' 'type' tycon aexp '#-}' {% ams (sLL $1 $> (AnnD $ HsAnnotation+ (getANN_PRAGs $1)+ (TypeAnnProvenance $3) $4))+ [mo $1,mj AnnType $2,mc $5] }++ | '{-# ANN' 'module' aexp '#-}' {% ams (sLL $1 $> (AnnD $ HsAnnotation+ (getANN_PRAGs $1)+ ModuleAnnProvenance $3))+ [mo $1,mj AnnModule $2,mc $4] }+++-----------------------------------------------------------------------------+-- Foreign import and export declarations++fdecl :: { Located ([AddAnn],HsDecl RdrName) }+fdecl : 'import' callconv safety fspec+ {% mkImport $2 $3 (snd $ unLoc $4) >>= \i ->+ return (sLL $1 $> (mj AnnImport $1 : (fst $ unLoc $4),i)) }+ | 'import' callconv fspec+ {% do { d <- mkImport $2 (noLoc PlaySafe) (snd $ unLoc $3);+ return (sLL $1 $> (mj AnnImport $1 : (fst $ unLoc $3),d)) }}+ | 'export' callconv fspec+ {% mkExport $2 (snd $ unLoc $3) >>= \i ->+ return (sLL $1 $> (mj AnnExport $1 : (fst $ unLoc $3),i) ) }++callconv :: { Located CCallConv }+ : 'stdcall' { sLL $1 $> StdCallConv }+ | 'ccall' { sLL $1 $> CCallConv }+ | 'capi' { sLL $1 $> CApiConv }+ | 'prim' { sLL $1 $> PrimCallConv}+ | 'javascript' { sLL $1 $> JavaScriptCallConv }++safety :: { Located Safety }+ : 'unsafe' { sLL $1 $> PlayRisky }+ | 'safe' { sLL $1 $> PlaySafe }+ | 'interruptible' { sLL $1 $> PlayInterruptible }++fspec :: { Located ([AddAnn]+ ,(Located StringLiteral, Located RdrName, LHsSigType RdrName)) }+ : STRING var '::' sigtypedoc { sLL $1 $> ([mu AnnDcolon $3]+ ,(L (getLoc $1)+ (getStringLiteral $1), $2, mkLHsSigType $4)) }+ | var '::' sigtypedoc { sLL $1 $> ([mu AnnDcolon $2]+ ,(noLoc (StringLiteral NoSourceText nilFS), $1, mkLHsSigType $3)) }+ -- if the entity string is missing, it defaults to the empty string;+ -- the meaning of an empty entity string depends on the calling+ -- convention++-----------------------------------------------------------------------------+-- Type signatures++opt_sig :: { ([AddAnn], Maybe (LHsType RdrName)) }+ : {- empty -} { ([],Nothing) }+ | '::' sigtype { ([mu AnnDcolon $1],Just $2) }++opt_asig :: { ([AddAnn],Maybe (LHsType RdrName)) }+ : {- empty -} { ([],Nothing) }+ | '::' atype { ([mu AnnDcolon $1],Just $2) }++opt_tyconsig :: { ([AddAnn], Maybe (Located RdrName)) }+ : {- empty -} { ([], Nothing) }+ | '::' gtycon { ([mu AnnDcolon $1], Just $2) }++sigtype :: { LHsType RdrName }+ : ctype { $1 }++sigtypedoc :: { LHsType RdrName }+ : ctypedoc { $1 }+++sig_vars :: { Located [Located RdrName] } -- Returned in reversed order+ : sig_vars ',' var {% addAnnotation (gl $ head $ unLoc $1)+ AnnComma (gl $2)+ >> return (sLL $1 $> ($3 : unLoc $1)) }+ | var { sL1 $1 [$1] }++sigtypes1 :: { (OrdList (LHsSigType RdrName)) }+ : sigtype { unitOL (mkLHsSigType $1) }+ | sigtype ',' sigtypes1 {% addAnnotation (gl $1) AnnComma (gl $2)+ >> return (unitOL (mkLHsSigType $1) `appOL` $3) }++-----------------------------------------------------------------------------+-- Types++strict_mark :: { Located ([AddAnn],HsSrcBang) }+ : strictness { sL1 $1 (let (a, str) = unLoc $1 in (a, HsSrcBang NoSourceText NoSrcUnpack str)) }+ | unpackedness { sL1 $1 (let (a, prag, unpk) = unLoc $1 in (a, HsSrcBang prag unpk NoSrcStrict)) }+ | unpackedness strictness { sLL $1 $> (let { (a, prag, unpk) = unLoc $1+ ; (a', str) = unLoc $2 }+ in (a ++ a', HsSrcBang prag unpk str)) }+ -- Although UNPACK with no '!' without StrictData and UNPACK with '~' are illegal,+ -- we get a better error message if we parse them here++strictness :: { Located ([AddAnn], SrcStrictness) }+ : '!' { sL1 $1 ([mj AnnBang $1], SrcStrict) }+ | '~' { sL1 $1 ([mj AnnTilde $1], SrcLazy) }++unpackedness :: { Located ([AddAnn], SourceText, SrcUnpackedness) }+ : '{-# UNPACK' '#-}' { sLL $1 $> ([mo $1, mc $2], getUNPACK_PRAGs $1, SrcUnpack) }+ | '{-# NOUNPACK' '#-}' { sLL $1 $> ([mo $1, mc $2], getNOUNPACK_PRAGs $1, SrcNoUnpack) }++-- A ctype is a for-all type+ctype :: { LHsType RdrName }+ : 'forall' tv_bndrs '.' ctype {% hintExplicitForall (getLoc $1) >>+ ams (sLL $1 $> $+ HsForAllTy { hst_bndrs = $2+ , hst_body = $4 })+ [mu AnnForall $1, mj AnnDot $3] }+ | context '=>' ctype {% addAnnotation (gl $1) (toUnicodeAnn AnnDarrow $2) (gl $2)+ >> return (sLL $1 $> $+ HsQualTy { hst_ctxt = $1+ , hst_body = $3 }) }+ | ipvar '::' type {% ams (sLL $1 $> (HsIParamTy $1 $3))+ [mu AnnDcolon $2] }+ | type { $1 }++----------------------+-- Notes for 'ctypedoc'+-- It would have been nice to simplify the grammar by unifying `ctype` and+-- ctypedoc` into one production, allowing comments on types everywhere (and+-- rejecting them after parsing, where necessary). This is however not possible+-- since it leads to ambiguity. The reason is the support for comments on record+-- fields:+-- data R = R { field :: Int -- ^ comment on the field }+-- If we allow comments on types here, it's not clear if the comment applies+-- to 'field' or to 'Int'. So we must use `ctype` to describe the type.++ctypedoc :: { LHsType RdrName }+ : 'forall' tv_bndrs '.' ctypedoc {% hintExplicitForall (getLoc $1) >>+ ams (sLL $1 $> $+ HsForAllTy { hst_bndrs = $2+ , hst_body = $4 })+ [mu AnnForall $1,mj AnnDot $3] }+ | context '=>' ctypedoc {% addAnnotation (gl $1) (toUnicodeAnn AnnDarrow $2) (gl $2)+ >> return (sLL $1 $> $+ HsQualTy { hst_ctxt = $1+ , hst_body = $3 }) }+ | ipvar '::' type {% ams (sLL $1 $> (HsIParamTy $1 $3))+ [mu AnnDcolon $2] }+ | typedoc { $1 }++----------------------+-- Notes for 'context'+-- We parse a context as a btype so that we don't get reduce/reduce+-- errors in ctype. The basic problem is that+-- (Eq a, Ord a)+-- looks so much like a tuple type. We can't tell until we find the =>++-- We have the t1 ~ t2 form both in 'context' and in type,+-- to permit an individual equational constraint without parenthesis.+-- Thus for some reason we allow f :: a~b => blah+-- but not f :: ?x::Int => blah+-- See Note [Parsing ~]+context :: { LHsContext RdrName }+ : btype {% do { (anns,ctx) <- checkContext $1+ ; if null (unLoc ctx)+ then addAnnotation (gl $1) AnnUnit (gl $1)+ else return ()+ ; ams ctx anns+ } }++context_no_ops :: { LHsContext RdrName }+ : btype_no_ops {% do { ty <- splitTilde $1+ ; (anns,ctx) <- checkContext ty+ ; if null (unLoc ctx)+ then addAnnotation (gl ty) AnnUnit (gl ty)+ else return ()+ ; ams ctx anns+ } }++{- Note [GADT decl discards annotations]+~~~~~~~~~~~~~~~~~~~~~+The type production for++ btype `->` btype++adds the AnnRarrow annotation twice, in different places.++This is because if the type is processed as usual, it belongs on the annotations+for the type as a whole.++But if the type is passed to mkGadtDecl, it discards the top level SrcSpan, and+the top-level annotation will be disconnected. Hence for this specific case it+is connected to the first type too.+-}++type :: { LHsType RdrName }+ : btype { $1 }+ | btype '->' ctype {% ams $1 [mu AnnRarrow $2] -- See note [GADT decl discards annotations]+ >> ams (sLL $1 $> $ HsFunTy $1 $3)+ [mu AnnRarrow $2] }+++typedoc :: { LHsType RdrName }+ : btype { $1 }+ | btype docprev { sLL $1 $> $ HsDocTy $1 $2 }+ | btype '->' ctypedoc {% ams (sLL $1 $> $ HsFunTy $1 $3)+ [mu AnnRarrow $2] }+ | btype docprev '->' ctypedoc {% ams (sLL $1 $> $+ HsFunTy (L (comb2 $1 $2) (HsDocTy $1 $2))+ $4)+ [mu AnnRarrow $3] }++-- See Note [Parsing ~]+btype :: { LHsType RdrName }+ : tyapps {% splitTildeApps (reverse (unLoc $1)) >>=+ \ts -> return $ sL1 $1 $ HsAppsTy ts }++-- Used for parsing Haskell98-style data constructors,+-- in order to forbid the blasphemous+-- > data Foo = Int :+ Char :* Bool+-- See also Note [Parsing data constructors is hard] in RdrHsSyn+btype_no_ops :: { LHsType RdrName }+ : btype_no_ops atype { sLL $1 $> $ HsAppTy $1 $2 }+ | atype { $1 }++tyapps :: { Located [LHsAppType RdrName] } -- NB: This list is reversed+ : tyapp { sL1 $1 [$1] }+ | tyapps tyapp { sLL $1 $> $ $2 : (unLoc $1) }++-- See Note [HsAppsTy] in HsTypes+tyapp :: { LHsAppType RdrName }+ : atype { sL1 $1 $ HsAppPrefix $1 }+ | qtyconop { sL1 $1 $ HsAppInfix $1 }+ | tyvarop { sL1 $1 $ HsAppInfix $1 }+ | SIMPLEQUOTE qconop {% ams (sLL $1 $> $ HsAppInfix $2)+ [mj AnnSimpleQuote $1] }+ | SIMPLEQUOTE varop {% ams (sLL $1 $> $ HsAppInfix $2)+ [mj AnnSimpleQuote $1] }++atype :: { LHsType RdrName }+ : ntgtycon { sL1 $1 (HsTyVar NotPromoted $1) } -- Not including unit tuples+ | tyvar { sL1 $1 (HsTyVar NotPromoted $1) } -- (See Note [Unit tuples])+ | strict_mark atype {% ams (sLL $1 $> (HsBangTy (snd $ unLoc $1) $2))+ (fst $ unLoc $1) } -- Constructor sigs only+ | '{' fielddecls '}' {% amms (checkRecordSyntax+ (sLL $1 $> $ HsRecTy $2))+ -- Constructor sigs only+ [moc $1,mcc $3] }+ | '(' ')' {% ams (sLL $1 $> $ HsTupleTy+ HsBoxedOrConstraintTuple [])+ [mop $1,mcp $2] }+ | '(' ctype ',' comma_types1 ')' {% addAnnotation (gl $2) AnnComma+ (gl $3) >>+ ams (sLL $1 $> $ HsTupleTy+ HsBoxedOrConstraintTuple ($2 : $4))+ [mop $1,mcp $5] }+ | '(#' '#)' {% ams (sLL $1 $> $ HsTupleTy HsUnboxedTuple [])+ [mo $1,mc $2] }+ | '(#' comma_types1 '#)' {% ams (sLL $1 $> $ HsTupleTy HsUnboxedTuple $2)+ [mo $1,mc $3] }+ | '(#' bar_types2 '#)' {% ams (sLL $1 $> $ HsSumTy $2)+ [mo $1,mc $3] }+ | '[' ctype ']' {% ams (sLL $1 $> $ HsListTy $2) [mos $1,mcs $3] }+ | '[:' ctype ':]' {% ams (sLL $1 $> $ HsPArrTy $2) [mo $1,mc $3] }+ | '(' ctype ')' {% ams (sLL $1 $> $ HsParTy $2) [mop $1,mcp $3] }+ | '(' ctype '::' kind ')' {% ams (sLL $1 $> $ HsKindSig $2 $4)+ [mop $1,mu AnnDcolon $3,mcp $5] }+ | quasiquote { sL1 $1 (HsSpliceTy (unLoc $1) placeHolderKind) }+ | '$(' exp ')' {% ams (sLL $1 $> $ mkHsSpliceTy HasParens $2)+ [mj AnnOpenPE $1,mj AnnCloseP $3] }+ | TH_ID_SPLICE {%ams (sLL $1 $> $ mkHsSpliceTy HasDollar $ sL1 $1 $ HsVar $+ (sL1 $1 (mkUnqual varName (getTH_ID_SPLICE $1))))+ [mj AnnThIdSplice $1] }+ -- see Note [Promotion] for the followings+ | SIMPLEQUOTE qcon_nowiredlist {% ams (sLL $1 $> $ HsTyVar Promoted $2) [mj AnnSimpleQuote $1,mj AnnName $2] }+ | SIMPLEQUOTE '(' ctype ',' comma_types1 ')'+ {% addAnnotation (gl $3) AnnComma (gl $4) >>+ ams (sLL $1 $> $ HsExplicitTupleTy [] ($3 : $5))+ [mj AnnSimpleQuote $1,mop $2,mcp $6] }+ | SIMPLEQUOTE '[' comma_types0 ']' {% ams (sLL $1 $> $ HsExplicitListTy Promoted+ placeHolderKind $3)+ [mj AnnSimpleQuote $1,mos $2,mcs $4] }+ | SIMPLEQUOTE var {% ams (sLL $1 $> $ HsTyVar Promoted $2)+ [mj AnnSimpleQuote $1,mj AnnName $2] }++ -- Two or more [ty, ty, ty] must be a promoted list type, just as+ -- if you had written '[ty, ty, ty]+ -- (One means a list type, zero means the list type constructor,+ -- so you have to quote those.)+ | '[' ctype ',' comma_types1 ']' {% addAnnotation (gl $2) AnnComma+ (gl $3) >>+ ams (sLL $1 $> $ HsExplicitListTy NotPromoted+ placeHolderKind ($2 : $4))+ [mos $1,mcs $5] }+ | INTEGER { sLL $1 $> $ HsTyLit $ HsNumTy (getINTEGERs $1)+ (getINTEGER $1) }+ | STRING { sLL $1 $> $ HsTyLit $ HsStrTy (getSTRINGs $1)+ (getSTRING $1) }+ | '_' { sL1 $1 $ mkAnonWildCardTy }++-- An inst_type is what occurs in the head of an instance decl+-- e.g. (Foo a, Gaz b) => Wibble a b+-- It's kept as a single type for convenience.+inst_type :: { LHsSigType RdrName }+ : sigtype { mkLHsSigType $1 }++deriv_types :: { [LHsSigType RdrName] }+ : typedoc { [mkLHsSigType $1] }++ | typedoc ',' deriv_types {% addAnnotation (gl $1) AnnComma (gl $2)+ >> return (mkLHsSigType $1 : $3) }++comma_types0 :: { [LHsType RdrName] } -- Zero or more: ty,ty,ty+ : comma_types1 { $1 }+ | {- empty -} { [] }++comma_types1 :: { [LHsType RdrName] } -- One or more: ty,ty,ty+ : ctype { [$1] }+ | ctype ',' comma_types1 {% addAnnotation (gl $1) AnnComma (gl $2)+ >> return ($1 : $3) }++bar_types2 :: { [LHsType RdrName] } -- Two or more: ty|ty|ty+ : ctype '|' ctype {% addAnnotation (gl $1) AnnVbar (gl $2)+ >> return [$1,$3] }+ | ctype '|' bar_types2 {% addAnnotation (gl $1) AnnVbar (gl $2)+ >> return ($1 : $3) }++tv_bndrs :: { [LHsTyVarBndr RdrName] }+ : tv_bndr tv_bndrs { $1 : $2 }+ | {- empty -} { [] }++tv_bndr :: { LHsTyVarBndr RdrName }+ : tyvar { sL1 $1 (UserTyVar $1) }+ | '(' tyvar '::' kind ')' {% ams (sLL $1 $> (KindedTyVar $2 $4))+ [mop $1,mu AnnDcolon $3+ ,mcp $5] }++fds :: { Located ([AddAnn],[Located (FunDep (Located RdrName))]) }+ : {- empty -} { noLoc ([],[]) }+ | '|' fds1 { (sLL $1 $> ([mj AnnVbar $1]+ ,reverse (unLoc $2))) }++fds1 :: { Located [Located (FunDep (Located RdrName))] }+ : fds1 ',' fd {% addAnnotation (gl $ head $ unLoc $1) AnnComma (gl $2)+ >> return (sLL $1 $> ($3 : unLoc $1)) }+ | fd { sL1 $1 [$1] }++fd :: { Located (FunDep (Located RdrName)) }+ : varids0 '->' varids0 {% ams (L (comb3 $1 $2 $3)+ (reverse (unLoc $1), reverse (unLoc $3)))+ [mu AnnRarrow $2] }++varids0 :: { Located [Located RdrName] }+ : {- empty -} { noLoc [] }+ | varids0 tyvar { sLL $1 $> ($2 : unLoc $1) }++{-+Note [Parsing ~]+~~~~~~~~~~~~~~~~++Due to parsing conflicts between laziness annotations in data type+declarations (see strict_mark) and equality types ~'s are always+parsed as laziness annotations, and turned into HsEqTy's in the+correct places using RdrHsSyn.splitTilde.++Since strict_mark is parsed as part of atype which is part of type,+typedoc and context (where HsEqTy previously appeared) it made most+sense and was simplest to parse ~ as part of strict_mark and later+turn them into HsEqTy's.++-}+++-----------------------------------------------------------------------------+-- Kinds++kind :: { LHsKind RdrName }+ : ctype { $1 }++{- Note [Promotion]+ ~~~~~~~~~~~~~~~~++- Syntax of promoted qualified names+We write 'Nat.Zero instead of Nat.'Zero when dealing with qualified+names. Moreover ticks are only allowed in types, not in kinds, for a+few reasons:+ 1. we don't need quotes since we cannot define names in kinds+ 2. if one day we merge types and kinds, tick would mean look in DataName+ 3. we don't have a kind namespace anyway++- Name resolution+When the user write Zero instead of 'Zero in types, we parse it a+HsTyVar ("Zero", TcClsName) instead of HsTyVar ("Zero", DataName). We+deal with this in the renamer. If a HsTyVar ("Zero", TcClsName) is not+bounded in the type level, then we look for it in the term level (we+change its namespace to DataName, see Note [Demotion] in OccName). And+both become a HsTyVar ("Zero", DataName) after the renamer.++-}+++-----------------------------------------------------------------------------+-- Datatype declarations++gadt_constrlist :: { Located ([AddAnn]+ ,[LConDecl RdrName]) } -- Returned in order+ : 'where' '{' gadt_constrs '}' { L (comb2 $1 $3)+ ([mj AnnWhere $1+ ,moc $2+ ,mcc $4]+ , unLoc $3) }+ | 'where' vocurly gadt_constrs close { L (comb2 $1 $3)+ ([mj AnnWhere $1]+ , unLoc $3) }+ | {- empty -} { noLoc ([],[]) }++gadt_constrs :: { Located [LConDecl RdrName] }+ : gadt_constr_with_doc ';' gadt_constrs+ {% addAnnotation (gl $1) AnnSemi (gl $2)+ >> return (L (comb2 $1 $3) ($1 : unLoc $3)) }+ | gadt_constr_with_doc { L (gl $1) [$1] }+ | {- empty -} { noLoc [] }++-- We allow the following forms:+-- C :: Eq a => a -> T a+-- C :: forall a. Eq a => !a -> T a+-- D { x,y :: a } :: T a+-- forall a. Eq a => D { x,y :: a } :: T a++gadt_constr_with_doc :: { LConDecl RdrName }+gadt_constr_with_doc+ : maybe_docnext ';' gadt_constr+ {% return $ addConDoc $3 $1 }+ | gadt_constr+ {% return $1 }++gadt_constr :: { LConDecl RdrName }+ -- see Note [Difference in parsing GADT and data constructors]+ -- Returns a list because of: C,D :: ty+ : con_list '::' sigtype+ {% ams (sLL $1 $> (mkGadtDecl (unLoc $1) (mkLHsSigType $3)))+ [mu AnnDcolon $2] }++{- Note [Difference in parsing GADT and data constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GADT constructors have simpler syntax than usual data constructors:+in GADTs, types cannot occur to the left of '::', so they cannot be mixed+with constructor names (see Note [Parsing data constructors is hard]).++Due to simplified syntax, GADT constructor names (left-hand side of '::')+use simpler grammar production than usual data constructor names. As a+consequence, GADT constructor names are resticted (names like '(*)' are+allowed in usual data constructors, but not in GADTs).+-}++constrs :: { Located ([AddAnn],[LConDecl RdrName]) }+ : maybe_docnext '=' constrs1 { L (comb2 $2 $3) ([mj AnnEqual $2]+ ,addConDocs (unLoc $3) $1)}++constrs1 :: { Located [LConDecl RdrName] }+ : constrs1 maybe_docnext '|' maybe_docprev constr+ {% addAnnotation (gl $ head $ unLoc $1) AnnVbar (gl $3)+ >> return (sLL $1 $> (addConDoc $5 $2 : addConDocFirst (unLoc $1) $4)) }+ | constr { sL1 $1 [$1] }++constr :: { LConDecl RdrName }+ : maybe_docnext forall context_no_ops '=>' constr_stuff maybe_docprev+ {% ams (let (con,details) = unLoc $5 in+ addConDoc (L (comb4 $2 $3 $4 $5) (mkConDeclH98 con+ (snd $ unLoc $2) $3 details))+ ($1 `mplus` $6))+ (mu AnnDarrow $4:(fst $ unLoc $2)) }+ | maybe_docnext forall constr_stuff maybe_docprev+ {% ams ( let (con,details) = unLoc $3 in+ addConDoc (L (comb2 $2 $3) (mkConDeclH98 con+ (snd $ unLoc $2) (noLoc []) details))+ ($1 `mplus` $4))+ (fst $ unLoc $2) }++forall :: { Located ([AddAnn], Maybe [LHsTyVarBndr RdrName]) }+ : 'forall' tv_bndrs '.' { sLL $1 $> ([mu AnnForall $1,mj AnnDot $3], Just $2) }+ | {- empty -} { noLoc ([], Nothing) }++constr_stuff :: { Located (Located RdrName, HsConDeclDetails RdrName) }+ -- See Note [Parsing data constructors is hard] in RdrHsSyn+ : btype_no_ops {% do { c <- splitCon $1+ ; return $ sLL $1 $> c } }+ | btype_no_ops conop btype_no_ops {% do { ty <- splitTilde $1+ ; return $ sLL $1 $> ($2, InfixCon ty $3) } }++fielddecls :: { [LConDeclField RdrName] }+ : {- empty -} { [] }+ | fielddecls1 { $1 }++fielddecls1 :: { [LConDeclField RdrName] }+ : fielddecl maybe_docnext ',' maybe_docprev fielddecls1+ {% addAnnotation (gl $1) AnnComma (gl $3) >>+ return ((addFieldDoc $1 $4) : addFieldDocs $5 $2) }+ | fielddecl { [$1] }++fielddecl :: { LConDeclField RdrName }+ -- A list because of f,g :: Int+ : maybe_docnext sig_vars '::' ctype maybe_docprev+ {% ams (L (comb2 $2 $4)+ (ConDeclField (reverse (map (\ln@(L l n) -> L l $ FieldOcc ln PlaceHolder) (unLoc $2))) $4 ($1 `mplus` $5)))+ [mu AnnDcolon $3] }++-- Reversed!+maybe_derivings :: { HsDeriving RdrName }+ : {- empty -} { noLoc [] }+ | derivings { $1 }++-- A list of one or more deriving clauses at the end of a datatype+derivings :: { HsDeriving RdrName }+ : derivings deriving { sLL $1 $> $ $2 : unLoc $1 }+ | deriving { sLL $1 $> [$1] }++-- The outer Located is just to allow the caller to+-- know the rightmost extremity of the 'deriving' clause+deriving :: { LHsDerivingClause RdrName }+ : 'deriving' deriv_strategy qtycondoc+ {% let { full_loc = comb2 $1 $> }+ in ams (L full_loc $ HsDerivingClause $2 $ L full_loc+ [mkLHsSigType $3])+ [mj AnnDeriving $1] }++ | 'deriving' deriv_strategy '(' ')'+ {% let { full_loc = comb2 $1 $> }+ in ams (L full_loc $ HsDerivingClause $2 $ L full_loc [])+ [mj AnnDeriving $1,mop $3,mcp $4] }++ | 'deriving' deriv_strategy '(' deriv_types ')'+ {% let { full_loc = comb2 $1 $> }+ in ams (L full_loc $ HsDerivingClause $2 $ L full_loc $4)+ [mj AnnDeriving $1,mop $3,mcp $5] }+ -- Glasgow extension: allow partial+ -- applications in derivings++-----------------------------------------------------------------------------+-- Value definitions++{- Note [Declaration/signature overlap]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There's an awkward overlap with a type signature. Consider+ f :: Int -> Int = ...rhs...+ Then we can't tell whether it's a type signature or a value+ definition with a result signature until we see the '='.+ So we have to inline enough to postpone reductions until we know.+-}++{-+ ATTENTION: Dirty Hackery Ahead! If the second alternative of vars is var+ instead of qvar, we get another shift/reduce-conflict. Consider the+ following programs:++ { (^^) :: Int->Int ; } Type signature; only var allowed++ { (^^) :: Int->Int = ... ; } Value defn with result signature;+ qvar allowed (because of instance decls)++ We can't tell whether to reduce var to qvar until after we've read the signatures.+-}++docdecl :: { LHsDecl RdrName }+ : docdecld { sL1 $1 (DocD (unLoc $1)) }++docdecld :: { LDocDecl }+ : docnext { sL1 $1 (DocCommentNext (unLoc $1)) }+ | docprev { sL1 $1 (DocCommentPrev (unLoc $1)) }+ | docnamed { sL1 $1 (case (unLoc $1) of (n, doc) -> DocCommentNamed n doc) }+ | docsection { sL1 $1 (case (unLoc $1) of (n, doc) -> DocGroup n doc) }++decl_no_th :: { LHsDecl RdrName }+ : sigdecl { $1 }++ | '!' aexp rhs {% do { let { e = sLL $1 $2 (SectionR (sL1 $1 (HsVar (sL1 $1 bang_RDR))) $2)+ -- Turn it all into an expression so that+ -- checkPattern can check that bangs are enabled+ ; l = comb2 $1 $> };+ (ann, r) <- checkValDef empty SrcStrict e Nothing $3 ;+ -- Depending upon what the pattern looks like we might get either+ -- a FunBind or PatBind back from checkValDef. See Note+ -- [Varieties of binding pattern matches]+ case r of {+ (FunBind n _ _ _ _) ->+ ams (L l ()) [mj AnnFunId n] >> return () ;+ (PatBind (L lh _lhs) _rhs _ _ _) ->+ ams (L lh ()) [] >> return () } ;++ _ <- ams (L l ()) (ann ++ fst (unLoc $3) ++ [mj AnnBang $1]) ;+ return $! (sL l $ ValD r) } }++ | infixexp_top opt_sig rhs {% do { (ann,r) <- checkValDef empty NoSrcStrict $1 (snd $2) $3;+ let { l = comb2 $1 $> };+ -- Depending upon what the pattern looks like we might get either+ -- a FunBind or PatBind back from checkValDef. See Note+ -- [Varieties of binding pattern matches]+ case r of {+ (FunBind n _ _ _ _) ->+ ams (L l ()) (mj AnnFunId n:(fst $2)) >> return () ;+ (PatBind (L lh _lhs) _rhs _ _ _) ->+ ams (L lh ()) (fst $2) >> return () } ;+ _ <- ams (L l ()) (ann ++ (fst $ unLoc $3));+ return $! (sL l $ ValD r) } }+ | pattern_synonym_decl { $1 }+ | docdecl { $1 }++decl :: { LHsDecl RdrName }+ : decl_no_th { $1 }++ -- Why do we only allow naked declaration splices in top-level+ -- declarations and not here? Short answer: because readFail009+ -- fails terribly with a panic in cvBindsAndSigs otherwise.+ | splice_exp { sLL $1 $> $ mkSpliceDecl $1 }++rhs :: { Located ([AddAnn],GRHSs RdrName (LHsExpr RdrName)) }+ : '=' exp wherebinds { sL (comb3 $1 $2 $3)+ ((mj AnnEqual $1 : (fst $ unLoc $3))+ ,GRHSs (unguardedRHS (comb3 $1 $2 $3) $2)+ (snd $ unLoc $3)) }+ | gdrhs wherebinds { sLL $1 $> (fst $ unLoc $2+ ,GRHSs (reverse (unLoc $1))+ (snd $ unLoc $2)) }++gdrhs :: { Located [LGRHS RdrName (LHsExpr RdrName)] }+ : gdrhs gdrh { sLL $1 $> ($2 : unLoc $1) }+ | gdrh { sL1 $1 [$1] }++gdrh :: { LGRHS RdrName (LHsExpr RdrName) }+ : '|' guardquals '=' exp {% ams (sL (comb2 $1 $>) $ GRHS (unLoc $2) $4)+ [mj AnnVbar $1,mj AnnEqual $3] }++sigdecl :: { LHsDecl RdrName }+ :+ -- See Note [Declaration/signature overlap] for why we need infixexp here+ infixexp_top '::' sigtypedoc+ {% do v <- checkValSigLhs $1+ ; _ <- ams (sLL $1 $> ()) [mu AnnDcolon $2]+ ; return (sLL $1 $> $ SigD $+ TypeSig [v] (mkLHsSigWcType $3)) }++ | var ',' sig_vars '::' sigtypedoc+ {% do { let sig = TypeSig ($1 : reverse (unLoc $3))+ (mkLHsSigWcType $5)+ ; addAnnotation (gl $1) AnnComma (gl $2)+ ; ams ( sLL $1 $> $ SigD sig )+ [mu AnnDcolon $4] } }++ | infix prec ops+ {% ams (sLL $1 $> $ SigD+ (FixSig (FixitySig (fromOL $ unLoc $3)+ (Fixity (fst $ unLoc $2) (snd $ unLoc $2) (unLoc $1)))))+ [mj AnnInfix $1,mj AnnVal $2] }++ | pattern_synonym_sig { sLL $1 $> . SigD . unLoc $ $1 }++ | '{-# COMPLETE' con_list opt_tyconsig '#-}'+ {% let (dcolon, tc) = $3+ in ams+ (sLL $1 $>+ (SigD (CompleteMatchSig (getCOMPLETE_PRAGs $1) $2 tc)))+ ([ mo $1 ] ++ dcolon ++ [mc $4]) }++ -- This rule is for both INLINE and INLINABLE pragmas+ | '{-# INLINE' activation qvar '#-}'+ {% ams ((sLL $1 $> $ SigD (InlineSig $3+ (mkInlinePragma (getINLINE_PRAGs $1) (getINLINE $1)+ (snd $2)))))+ ((mo $1:fst $2) ++ [mc $4]) }++ | '{-# SCC' qvar '#-}'+ {% ams (sLL $1 $> (SigD (SCCFunSig (getSCC_PRAGs $1) $2 Nothing)))+ [mo $1, mc $3] }++ | '{-# SCC' qvar STRING '#-}'+ {% do { scc <- getSCC $3+ ; let str_lit = StringLiteral (getSTRINGs $3) scc+ ; ams (sLL $1 $> (SigD (SCCFunSig (getSCC_PRAGs $1) $2 (Just ( sL1 $3 str_lit)))))+ [mo $1, mc $4] } }++ | '{-# SPECIALISE' activation qvar '::' sigtypes1 '#-}'+ {% ams (+ let inl_prag = mkInlinePragma (getSPEC_PRAGs $1)+ (EmptyInlineSpec, FunLike) (snd $2)+ in sLL $1 $> $ SigD (SpecSig $3 (fromOL $5) inl_prag))+ (mo $1:mu AnnDcolon $4:mc $6:(fst $2)) }++ | '{-# SPECIALISE_INLINE' activation qvar '::' sigtypes1 '#-}'+ {% ams (sLL $1 $> $ SigD (SpecSig $3 (fromOL $5)+ (mkInlinePragma (getSPEC_INLINE_PRAGs $1)+ (getSPEC_INLINE $1) (snd $2))))+ (mo $1:mu AnnDcolon $4:mc $6:(fst $2)) }++ | '{-# SPECIALISE' 'instance' inst_type '#-}'+ {% ams (sLL $1 $>+ $ SigD (SpecInstSig (getSPEC_PRAGs $1) $3))+ [mo $1,mj AnnInstance $2,mc $4] }++ -- A minimal complete definition+ | '{-# MINIMAL' name_boolformula_opt '#-}'+ {% ams (sLL $1 $> $ SigD (MinimalSig (getMINIMAL_PRAGs $1) $2))+ [mo $1,mc $3] }++activation :: { ([AddAnn],Maybe Activation) }+ : {- empty -} { ([],Nothing) }+ | explicit_activation { (fst $1,Just (snd $1)) }++explicit_activation :: { ([AddAnn],Activation) } -- In brackets+ : '[' INTEGER ']' { ([mj AnnOpenS $1,mj AnnVal $2,mj AnnCloseS $3]+ ,ActiveAfter (getINTEGERs $2) (fromInteger (getINTEGER $2))) }+ | '[' '~' INTEGER ']' { ([mj AnnOpenS $1,mj AnnTilde $2,mj AnnVal $3+ ,mj AnnCloseS $4]+ ,ActiveBefore (getINTEGERs $3) (fromInteger (getINTEGER $3))) }++-----------------------------------------------------------------------------+-- Expressions++quasiquote :: { Located (HsSplice RdrName) }+ : TH_QUASIQUOTE { let { loc = getLoc $1+ ; ITquasiQuote (quoter, quote, quoteSpan) = unLoc $1+ ; quoterId = mkUnqual varName quoter }+ in sL1 $1 (mkHsQuasiQuote quoterId (RealSrcSpan quoteSpan) quote) }+ | TH_QQUASIQUOTE { let { loc = getLoc $1+ ; ITqQuasiQuote (qual, quoter, quote, quoteSpan) = unLoc $1+ ; quoterId = mkQual varName (qual, quoter) }+ in sL (getLoc $1) (mkHsQuasiQuote quoterId (RealSrcSpan quoteSpan) quote) }++exp :: { LHsExpr RdrName }+ : infixexp '::' sigtype {% ams (sLL $1 $> $ ExprWithTySig $1 (mkLHsSigWcType $3))+ [mu AnnDcolon $2] }+ | infixexp '-<' exp {% ams (sLL $1 $> $ HsArrApp $1 $3 placeHolderType+ HsFirstOrderApp True)+ [mu Annlarrowtail $2] }+ | infixexp '>-' exp {% ams (sLL $1 $> $ HsArrApp $3 $1 placeHolderType+ HsFirstOrderApp False)+ [mu Annrarrowtail $2] }+ | infixexp '-<<' exp {% ams (sLL $1 $> $ HsArrApp $1 $3 placeHolderType+ HsHigherOrderApp True)+ [mu AnnLarrowtail $2] }+ | infixexp '>>-' exp {% ams (sLL $1 $> $ HsArrApp $3 $1 placeHolderType+ HsHigherOrderApp False)+ [mu AnnRarrowtail $2] }+ | infixexp { $1 }++infixexp :: { LHsExpr RdrName }+ : exp10 { $1 }+ | infixexp qop exp10 {% ams (sLL $1 $> (OpApp $1 $2 placeHolderFixity $3))+ [mj AnnVal $2] }+ -- AnnVal annotation for NPlusKPat, which discards the operator++infixexp_top :: { LHsExpr RdrName }+ : exp10_top { $1 }+ | infixexp_top qop exp10_top+ {% ams (sLL $1 $> (OpApp $1 $2 placeHolderFixity $3))+ [mj AnnVal $2] }++exp10_top :: { LHsExpr RdrName }+ : '\\' apat apats opt_asig '->' exp+ {% ams (sLL $1 $> $ HsLam (mkMatchGroup FromSource+ [sLL $1 $> $ Match { m_ctxt = LambdaExpr+ , m_pats = $2:$3+ , m_type = snd $4+ , m_grhss = unguardedGRHSs $6 }]))+ (mj AnnLam $1:mu AnnRarrow $5:(fst $4)) }++ | 'let' binds 'in' exp {% ams (sLL $1 $> $ HsLet (snd $ unLoc $2) $4)+ (mj AnnLet $1:mj AnnIn $3+ :(fst $ unLoc $2)) }+ | '\\' 'lcase' altslist+ {% ams (sLL $1 $> $ HsLamCase+ (mkMatchGroup FromSource (snd $ unLoc $3)))+ (mj AnnLam $1:mj AnnCase $2:(fst $ unLoc $3)) }+ | 'if' exp optSemi 'then' exp optSemi 'else' exp+ {% checkDoAndIfThenElse $2 (snd $3) $5 (snd $6) $8 >>+ ams (sLL $1 $> $ mkHsIf $2 $5 $8)+ (mj AnnIf $1:mj AnnThen $4+ :mj AnnElse $7+ :(map (\l -> mj AnnSemi l) (fst $3))+ ++(map (\l -> mj AnnSemi l) (fst $6))) }+ | 'if' ifgdpats {% hintMultiWayIf (getLoc $1) >>+ ams (sLL $1 $> $ HsMultiIf+ placeHolderType+ (reverse $ snd $ unLoc $2))+ (mj AnnIf $1:(fst $ unLoc $2)) }+ | 'case' exp 'of' altslist {% ams (sLL $1 $> $ HsCase $2 (mkMatchGroup+ FromSource (snd $ unLoc $4)))+ (mj AnnCase $1:mj AnnOf $3+ :(fst $ unLoc $4)) }+ | '-' fexp {% ams (sLL $1 $> $ NegApp $2 noSyntaxExpr)+ [mj AnnMinus $1] }++ | 'do' stmtlist {% ams (L (comb2 $1 $2)+ (mkHsDo DoExpr (snd $ unLoc $2)))+ (mj AnnDo $1:(fst $ unLoc $2)) }+ | 'mdo' stmtlist {% ams (L (comb2 $1 $2)+ (mkHsDo MDoExpr (snd $ unLoc $2)))+ (mj AnnMdo $1:(fst $ unLoc $2)) }++ | hpc_annot exp {% ams (sLL $1 $> $ HsTickPragma (snd $ fst $ fst $ unLoc $1)+ (snd $ fst $ unLoc $1) (snd $ unLoc $1) $2)+ (fst $ fst $ fst $ unLoc $1) }++ | 'proc' aexp '->' exp+ {% checkPattern empty $2 >>= \ p ->+ checkCommand $4 >>= \ cmd ->+ ams (sLL $1 $> $ HsProc p (sLL $1 $> $ HsCmdTop cmd placeHolderType+ placeHolderType []))+ -- TODO: is LL right here?+ [mj AnnProc $1,mu AnnRarrow $3] }++ | '{-# CORE' STRING '#-}' exp {% ams (sLL $1 $> $ HsCoreAnn (getCORE_PRAGs $1) (getStringLiteral $2) $4)+ [mo $1,mj AnnVal $2+ ,mc $3] }+ -- hdaume: core annotation+ | fexp { $1 }++exp10 :: { LHsExpr RdrName }+ : exp10_top { $1 }+ | scc_annot exp {% ams (sLL $1 $> $ HsSCC (snd $ fst $ unLoc $1) (snd $ unLoc $1) $2)+ (fst $ fst $ unLoc $1) }++optSemi :: { ([Located a],Bool) }+ : ';' { ([$1],True) }+ | {- empty -} { ([],False) }++scc_annot :: { Located (([AddAnn],SourceText),StringLiteral) }+ : '{-# SCC' STRING '#-}' {% do scc <- getSCC $2+ ; return $ sLL $1 $>+ (([mo $1,mj AnnValStr $2+ ,mc $3],getSCC_PRAGs $1),(StringLiteral (getSTRINGs $2) scc)) }+ | '{-# SCC' VARID '#-}' { sLL $1 $> (([mo $1,mj AnnVal $2+ ,mc $3],getSCC_PRAGs $1)+ ,(StringLiteral NoSourceText (getVARID $2))) }++hpc_annot :: { Located ( (([AddAnn],SourceText),(StringLiteral,(Int,Int),(Int,Int))),+ ((SourceText,SourceText),(SourceText,SourceText))+ ) }+ : '{-# GENERATED' STRING INTEGER ':' INTEGER '-' INTEGER ':' INTEGER '#-}'+ { sLL $1 $> $ ((([mo $1,mj AnnVal $2+ ,mj AnnVal $3,mj AnnColon $4+ ,mj AnnVal $5,mj AnnMinus $6+ ,mj AnnVal $7,mj AnnColon $8+ ,mj AnnVal $9,mc $10],+ getGENERATED_PRAGs $1)+ ,((getStringLiteral $2)+ ,( fromInteger $ getINTEGER $3+ , fromInteger $ getINTEGER $5+ )+ ,( fromInteger $ getINTEGER $7+ , fromInteger $ getINTEGER $9+ )+ ))+ , (( getINTEGERs $3+ , getINTEGERs $5+ )+ ,( getINTEGERs $7+ , getINTEGERs $9+ )))+ }++fexp :: { LHsExpr RdrName }+ : fexp aexp { sLL $1 $> $ HsApp $1 $2 }+ | fexp TYPEAPP atype {% ams (sLL $1 $> $ HsAppType $1 (mkHsWildCardBndrs $3))+ [mj AnnAt $2] }+ | 'static' aexp {% ams (sLL $1 $> $ HsStatic placeHolderNames $2)+ [mj AnnStatic $1] }+ | aexp { $1 }++aexp :: { LHsExpr RdrName }+ : qvar '@' aexp {% ams (sLL $1 $> $ EAsPat $1 $3) [mj AnnAt $2] }+ -- If you change the parsing, make sure to understand+ -- Note [Lexing type applications] in Lexer.x++ | '~' aexp {% ams (sLL $1 $> $ ELazyPat $2) [mj AnnTilde $1] }+ | aexp1 { $1 }++aexp1 :: { LHsExpr RdrName }+ : aexp1 '{' fbinds '}' {% do { r <- mkRecConstrOrUpdate $1 (comb2 $2 $4)+ (snd $3)+ ; _ <- ams (sLL $1 $> ()) (moc $2:mcc $4:(fst $3))+ ; checkRecordSyntax (sLL $1 $> r) }}+ | aexp2 { $1 }++aexp2 :: { LHsExpr RdrName }+ : qvar { sL1 $1 (HsVar $! $1) }+ | qcon { sL1 $1 (HsVar $! $1) }+ | ipvar { sL1 $1 (HsIPVar $! unLoc $1) }+ | overloaded_label { sL1 $1 (HsOverLabel Nothing $! unLoc $1) }+ | literal { sL1 $1 (HsLit $! unLoc $1) }+-- This will enable overloaded strings permanently. Normally the renamer turns HsString+-- into HsOverLit when -foverloaded-strings is on.+-- | STRING { sL (getLoc $1) (HsOverLit $! mkHsIsString (getSTRINGs $1)+-- (getSTRING $1) placeHolderType) }+ | INTEGER { sL (getLoc $1) (HsOverLit $! mkHsIntegral (getINTEGERs $1)+ (getINTEGER $1) placeHolderType) }+ | RATIONAL { sL (getLoc $1) (HsOverLit $! mkHsFractional+ (getRATIONAL $1) placeHolderType) }++ -- N.B.: sections get parsed by these next two productions.+ -- This allows you to write, e.g., '(+ 3, 4 -)', which isn't+ -- correct Haskell (you'd have to write '((+ 3), (4 -))')+ -- but the less cluttered version fell out of having texps.+ | '(' texp ')' {% ams (sLL $1 $> (HsPar $2)) [mop $1,mcp $3] }+ | '(' tup_exprs ')' {% do { e <- mkSumOrTuple Boxed (comb2 $1 $3) (snd $2)+ ; ams (sLL $1 $> e) ((mop $1:fst $2) ++ [mcp $3]) } }++ | '(#' texp '#)' {% ams (sLL $1 $> (ExplicitTuple [L (gl $2)+ (Present $2)] Unboxed))+ [mo $1,mc $3] }+ | '(#' tup_exprs '#)' {% do { e <- mkSumOrTuple Unboxed (comb2 $1 $3) (snd $2)+ ; ams (sLL $1 $> e) ((mo $1:fst $2) ++ [mc $3]) } }++ | '[' list ']' {% ams (sLL $1 $> (snd $2)) (mos $1:mcs $3:(fst $2)) }+ | '[:' parr ':]' {% ams (sLL $1 $> (snd $2)) (mo $1:mc $3:(fst $2)) }+ | '_' { sL1 $1 EWildPat }++ -- Template Haskell Extension+ | splice_exp { $1 }++ | SIMPLEQUOTE qvar {% ams (sLL $1 $> $ HsBracket (VarBr True (unLoc $2))) [mj AnnSimpleQuote $1,mj AnnName $2] }+ | SIMPLEQUOTE qcon {% ams (sLL $1 $> $ HsBracket (VarBr True (unLoc $2))) [mj AnnSimpleQuote $1,mj AnnName $2] }+ | TH_TY_QUOTE tyvar {% ams (sLL $1 $> $ HsBracket (VarBr False (unLoc $2))) [mj AnnThTyQuote $1,mj AnnName $2] }+ | TH_TY_QUOTE gtycon {% ams (sLL $1 $> $ HsBracket (VarBr False (unLoc $2))) [mj AnnThTyQuote $1,mj AnnName $2] }+ | '[|' exp '|]' {% ams (sLL $1 $> $ HsBracket (ExpBr $2))+ (if (hasE $1) then [mj AnnOpenE $1, mu AnnCloseQ $3]+ else [mu AnnOpenEQ $1,mu AnnCloseQ $3]) }+ | '[||' exp '||]' {% ams (sLL $1 $> $ HsBracket (TExpBr $2))+ (if (hasE $1) then [mj AnnOpenE $1,mc $3] else [mo $1,mc $3]) }+ | '[t|' ctype '|]' {% ams (sLL $1 $> $ HsBracket (TypBr $2)) [mo $1,mu AnnCloseQ $3] }+ | '[p|' infixexp '|]' {% checkPattern empty $2 >>= \p ->+ ams (sLL $1 $> $ HsBracket (PatBr p))+ [mo $1,mu AnnCloseQ $3] }+ | '[d|' cvtopbody '|]' {% ams (sLL $1 $> $ HsBracket (DecBrL (snd $2)))+ (mo $1:mu AnnCloseQ $3:fst $2) }+ | quasiquote { sL1 $1 (HsSpliceE (unLoc $1)) }++ -- arrow notation extension+ | '(|' aexp2 cmdargs '|)' {% ams (sLL $1 $> $ HsArrForm $2+ Nothing (reverse $3))+ [mu AnnOpenB $1,mu AnnCloseB $4] }++splice_exp :: { LHsExpr RdrName }+ : TH_ID_SPLICE {% ams (sL1 $1 $ mkHsSpliceE HasDollar+ (sL1 $1 $ HsVar (sL1 $1 (mkUnqual varName+ (getTH_ID_SPLICE $1)))))+ [mj AnnThIdSplice $1] }+ | '$(' exp ')' {% ams (sLL $1 $> $ mkHsSpliceE HasParens $2)+ [mj AnnOpenPE $1,mj AnnCloseP $3] }+ | TH_ID_TY_SPLICE {% ams (sL1 $1 $ mkHsSpliceTE HasDollar+ (sL1 $1 $ HsVar (sL1 $1 (mkUnqual varName+ (getTH_ID_TY_SPLICE $1)))))+ [mj AnnThIdTySplice $1] }+ | '$$(' exp ')' {% ams (sLL $1 $> $ mkHsSpliceTE HasParens $2)+ [mj AnnOpenPTE $1,mj AnnCloseP $3] }++cmdargs :: { [LHsCmdTop RdrName] }+ : cmdargs acmd { $2 : $1 }+ | {- empty -} { [] }++acmd :: { LHsCmdTop RdrName }+ : aexp2 {% checkCommand $1 >>= \ cmd ->+ return (sL1 $1 $ HsCmdTop cmd+ placeHolderType placeHolderType []) }++cvtopbody :: { ([AddAnn],[LHsDecl RdrName]) }+ : '{' cvtopdecls0 '}' { ([mj AnnOpenC $1+ ,mj AnnCloseC $3],$2) }+ | vocurly cvtopdecls0 close { ([],$2) }++cvtopdecls0 :: { [LHsDecl RdrName] }+ : topdecls_semi { cvTopDecls $1 }+ | topdecls { cvTopDecls $1 }++-----------------------------------------------------------------------------+-- Tuple expressions++-- "texp" is short for tuple expressions:+-- things that can appear unparenthesized as long as they're+-- inside parens or delimitted by commas+texp :: { LHsExpr RdrName }+ : exp { $1 }++ -- Note [Parsing sections]+ -- ~~~~~~~~~~~~~~~~~~~~~~~+ -- We include left and right sections here, which isn't+ -- technically right according to the Haskell standard.+ -- For example (3 +, True) isn't legal.+ -- However, we want to parse bang patterns like+ -- (!x, !y)+ -- and it's convenient to do so here as a section+ -- Then when converting expr to pattern we unravel it again+ -- Meanwhile, the renamer checks that real sections appear+ -- inside parens.+ | infixexp qop { sLL $1 $> $ SectionL $1 $2 }+ | qopm infixexp { sLL $1 $> $ SectionR $1 $2 }++ -- View patterns get parenthesized above+ | exp '->' texp {% ams (sLL $1 $> $ EViewPat $1 $3) [mu AnnRarrow $2] }++-- Always at least one comma or bar.+tup_exprs :: { ([AddAnn],SumOrTuple) }+ : texp commas_tup_tail+ {% do { addAnnotation (gl $1) AnnComma (fst $2)+ ; return ([],Tuple ((sL1 $1 (Present $1)) : snd $2)) } }++ | texp bars { (mvbars (fst $2), Sum 1 (snd $2 + 1) $1) }++ | commas tup_tail+ {% do { mapM_ (\ll -> addAnnotation ll AnnComma ll) (fst $1)+ ; return+ ([],Tuple (map (\l -> L l missingTupArg) (fst $1) ++ $2)) } }++ | bars texp bars0+ { (mvbars (fst $1) ++ mvbars (fst $3), Sum (snd $1 + 1) (snd $1 + snd $3 + 1) $2) }++-- Always starts with commas; always follows an expr+commas_tup_tail :: { (SrcSpan,[LHsTupArg RdrName]) }+commas_tup_tail : commas tup_tail+ {% do { mapM_ (\ll -> addAnnotation ll AnnComma ll) (tail $ fst $1)+ ; return (+ (head $ fst $1+ ,(map (\l -> L l missingTupArg) (tail $ fst $1)) ++ $2)) } }++-- Always follows a comma+tup_tail :: { [LHsTupArg RdrName] }+ : texp commas_tup_tail {% addAnnotation (gl $1) AnnComma (fst $2) >>+ return ((L (gl $1) (Present $1)) : snd $2) }+ | texp { [L (gl $1) (Present $1)] }+ | {- empty -} { [noLoc missingTupArg] }++-----------------------------------------------------------------------------+-- List expressions++-- The rules below are little bit contorted to keep lexps left-recursive while+-- avoiding another shift/reduce-conflict.+list :: { ([AddAnn],HsExpr RdrName) }+ : texp { ([],ExplicitList placeHolderType Nothing [$1]) }+ | lexps { ([],ExplicitList placeHolderType Nothing+ (reverse (unLoc $1))) }+ | texp '..' { ([mj AnnDotdot $2],+ ArithSeq noPostTcExpr Nothing (From $1)) }+ | texp ',' exp '..' { ([mj AnnComma $2,mj AnnDotdot $4],+ ArithSeq noPostTcExpr Nothing+ (FromThen $1 $3)) }+ | texp '..' exp { ([mj AnnDotdot $2],+ ArithSeq noPostTcExpr Nothing+ (FromTo $1 $3)) }+ | texp ',' exp '..' exp { ([mj AnnComma $2,mj AnnDotdot $4],+ ArithSeq noPostTcExpr Nothing+ (FromThenTo $1 $3 $5)) }+ | texp '|' flattenedpquals+ {% checkMonadComp >>= \ ctxt ->+ return ([mj AnnVbar $2],+ mkHsComp ctxt (unLoc $3) $1) }++lexps :: { Located [LHsExpr RdrName] }+ : lexps ',' texp {% addAnnotation (gl $ head $ unLoc $1)+ AnnComma (gl $2) >>+ return (sLL $1 $> (((:) $! $3) $! unLoc $1)) }+ | texp ',' texp {% addAnnotation (gl $1) AnnComma (gl $2) >>+ return (sLL $1 $> [$3,$1]) }++-----------------------------------------------------------------------------+-- List Comprehensions++flattenedpquals :: { Located [LStmt RdrName (LHsExpr RdrName)] }+ : pquals { case (unLoc $1) of+ [qs] -> sL1 $1 qs+ -- We just had one thing in our "parallel" list so+ -- we simply return that thing directly++ qss -> sL1 $1 [sL1 $1 $ ParStmt [ParStmtBlock qs [] noSyntaxExpr |+ qs <- qss]+ noExpr noSyntaxExpr placeHolderType]+ -- We actually found some actual parallel lists so+ -- we wrap them into as a ParStmt+ }++pquals :: { Located [[LStmt RdrName (LHsExpr RdrName)]] }+ : squals '|' pquals+ {% addAnnotation (gl $ head $ unLoc $1) AnnVbar (gl $2) >>+ return (sLL $1 $> (reverse (unLoc $1) : unLoc $3)) }+ | squals { L (getLoc $1) [reverse (unLoc $1)] }++squals :: { Located [LStmt RdrName (LHsExpr RdrName)] } -- In reverse order, because the last+ -- one can "grab" the earlier ones+ : squals ',' transformqual+ {% addAnnotation (gl $ head $ unLoc $1) AnnComma (gl $2) >>+ ams (sLL $1 $> ()) (fst $ unLoc $3) >>+ return (sLL $1 $> [sLL $1 $> ((snd $ unLoc $3) (reverse (unLoc $1)))]) }+ | squals ',' qual+ {% addAnnotation (gl $ head $ unLoc $1) AnnComma (gl $2) >>+ return (sLL $1 $> ($3 : unLoc $1)) }+ | transformqual {% ams $1 (fst $ unLoc $1) >>+ return (sLL $1 $> [L (getLoc $1) ((snd $ unLoc $1) [])]) }+ | qual { sL1 $1 [$1] }+-- | transformquals1 ',' '{|' pquals '|}' { sLL $1 $> ($4 : unLoc $1) }+-- | '{|' pquals '|}' { sL1 $1 [$2] }++-- It is possible to enable bracketing (associating) qualifier lists+-- by uncommenting the lines with {| |} above. Due to a lack of+-- consensus on the syntax, this feature is not being used until we+-- get user demand.++transformqual :: { Located ([AddAnn],[LStmt RdrName (LHsExpr RdrName)] -> Stmt RdrName (LHsExpr RdrName)) }+ -- Function is applied to a list of stmts *in order*+ : 'then' exp { sLL $1 $> ([mj AnnThen $1], \ss -> (mkTransformStmt ss $2)) }+ | 'then' exp 'by' exp { sLL $1 $> ([mj AnnThen $1,mj AnnBy $3],\ss -> (mkTransformByStmt ss $2 $4)) }+ | 'then' 'group' 'using' exp+ { sLL $1 $> ([mj AnnThen $1,mj AnnGroup $2,mj AnnUsing $3], \ss -> (mkGroupUsingStmt ss $4)) }++ | 'then' 'group' 'by' exp 'using' exp+ { sLL $1 $> ([mj AnnThen $1,mj AnnGroup $2,mj AnnBy $3,mj AnnUsing $5], \ss -> (mkGroupByUsingStmt ss $4 $6)) }++-- Note that 'group' is a special_id, which means that you can enable+-- TransformListComp while still using Data.List.group. However, this+-- introduces a shift/reduce conflict. Happy chooses to resolve the conflict+-- in by choosing the "group by" variant, which is what we want.++-----------------------------------------------------------------------------+-- Parallel array expressions++-- The rules below are little bit contorted; see the list case for details.+-- Note that, in contrast to lists, we only have finite arithmetic sequences.+-- Moreover, we allow explicit arrays with no element (represented by the nil+-- constructor in the list case).++parr :: { ([AddAnn],HsExpr RdrName) }+ : { ([],ExplicitPArr placeHolderType []) }+ | texp { ([],ExplicitPArr placeHolderType [$1]) }+ | lexps { ([],ExplicitPArr placeHolderType+ (reverse (unLoc $1))) }+ | texp '..' exp { ([mj AnnDotdot $2]+ ,PArrSeq noPostTcExpr (FromTo $1 $3)) }+ | texp ',' exp '..' exp+ { ([mj AnnComma $2,mj AnnDotdot $4]+ ,PArrSeq noPostTcExpr (FromThenTo $1 $3 $5)) }+ | texp '|' flattenedpquals+ { ([mj AnnVbar $2],mkHsComp PArrComp (unLoc $3) $1) }++-- We are reusing `lexps' and `flattenedpquals' from the list case.++-----------------------------------------------------------------------------+-- Guards++guardquals :: { Located [LStmt RdrName (LHsExpr RdrName)] }+ : guardquals1 { L (getLoc $1) (reverse (unLoc $1)) }++guardquals1 :: { Located [LStmt RdrName (LHsExpr RdrName)] }+ : guardquals1 ',' qual {% addAnnotation (gl $ head $ unLoc $1) AnnComma+ (gl $2) >>+ return (sLL $1 $> ($3 : unLoc $1)) }+ | qual { sL1 $1 [$1] }++-----------------------------------------------------------------------------+-- Case alternatives++altslist :: { Located ([AddAnn],[LMatch RdrName (LHsExpr RdrName)]) }+ : '{' alts '}' { sLL $1 $> ((moc $1:mcc $3:(fst $ unLoc $2))+ ,(reverse (snd $ unLoc $2))) }+ | vocurly alts close { L (getLoc $2) (fst $ unLoc $2+ ,(reverse (snd $ unLoc $2))) }+ | '{' '}' { noLoc ([moc $1,mcc $2],[]) }+ | vocurly close { noLoc ([],[]) }++alts :: { Located ([AddAnn],[LMatch RdrName (LHsExpr RdrName)]) }+ : alts1 { sL1 $1 (fst $ unLoc $1,snd $ unLoc $1) }+ | ';' alts { sLL $1 $> ((mj AnnSemi $1:(fst $ unLoc $2))+ ,snd $ unLoc $2) }++alts1 :: { Located ([AddAnn],[LMatch RdrName (LHsExpr RdrName)]) }+ : alts1 ';' alt {% if null (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ ,[$3]))+ else (ams (head $ snd $ unLoc $1)+ (mj AnnSemi $2:(fst $ unLoc $1))+ >> return (sLL $1 $> ([],$3 : (snd $ unLoc $1))) ) }+ | alts1 ';' {% if null (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ ,snd $ unLoc $1))+ else (ams (head $ snd $ unLoc $1)+ (mj AnnSemi $2:(fst $ unLoc $1))+ >> return (sLL $1 $> ([],snd $ unLoc $1))) }+ | alt { sL1 $1 ([],[$1]) }++alt :: { LMatch RdrName (LHsExpr RdrName) }+ : pat opt_asig alt_rhs {%ams (sLL $1 $> (Match { m_ctxt = CaseAlt+ , m_pats = [$1]+ , m_type = snd $2+ , m_grhss = snd $ unLoc $3 }))+ (fst $2 ++ (fst $ unLoc $3))}++alt_rhs :: { Located ([AddAnn],GRHSs RdrName (LHsExpr RdrName)) }+ : ralt wherebinds { sLL $1 $> (fst $ unLoc $2,+ GRHSs (unLoc $1) (snd $ unLoc $2)) }++ralt :: { Located [LGRHS RdrName (LHsExpr RdrName)] }+ : '->' exp {% ams (sLL $1 $> (unguardedRHS (comb2 $1 $2) $2))+ [mu AnnRarrow $1] }+ | gdpats { sL1 $1 (reverse (unLoc $1)) }++gdpats :: { Located [LGRHS RdrName (LHsExpr RdrName)] }+ : gdpats gdpat { sLL $1 $> ($2 : unLoc $1) }+ | gdpat { sL1 $1 [$1] }++-- layout for MultiWayIf doesn't begin with an open brace, because it's hard to+-- generate the open brace in addition to the vertical bar in the lexer, and+-- we don't need it.+ifgdpats :: { Located ([AddAnn],[LGRHS RdrName (LHsExpr RdrName)]) }+ : '{' gdpats '}' { sLL $1 $> ([moc $1,mcc $3],unLoc $2) }+ | gdpats close { sL1 $1 ([],unLoc $1) }++gdpat :: { LGRHS RdrName (LHsExpr RdrName) }+ : '|' guardquals '->' exp+ {% ams (sL (comb2 $1 $>) $ GRHS (unLoc $2) $4)+ [mj AnnVbar $1,mu AnnRarrow $3] }++-- 'pat' recognises a pattern, including one with a bang at the top+-- e.g. "!x" or "!(x,y)" or "C a b" etc+-- Bangs inside are parsed as infix operator applications, so that+-- we parse them right when bang-patterns are off+pat :: { LPat RdrName }+pat : exp {% checkPattern empty $1 }+ | '!' aexp {% amms (checkPattern empty (sLL $1 $> (SectionR+ (sL1 $1 (HsVar (sL1 $1 bang_RDR))) $2)))+ [mj AnnBang $1] }++bindpat :: { LPat RdrName }+bindpat : exp {% checkPattern+ (text "Possibly caused by a missing 'do'?") $1 }+ | '!' aexp {% amms (checkPattern+ (text "Possibly caused by a missing 'do'?")+ (sLL $1 $> (SectionR (sL1 $1 (HsVar (sL1 $1 bang_RDR))) $2)))+ [mj AnnBang $1] }++apat :: { LPat RdrName }+apat : aexp {% checkPattern empty $1 }+ | '!' aexp {% amms (checkPattern empty+ (sLL $1 $> (SectionR+ (sL1 $1 (HsVar (sL1 $1 bang_RDR))) $2)))+ [mj AnnBang $1] }++apats :: { [LPat RdrName] }+ : apat apats { $1 : $2 }+ | {- empty -} { [] }++-----------------------------------------------------------------------------+-- Statement sequences++stmtlist :: { Located ([AddAnn],[LStmt RdrName (LHsExpr RdrName)]) }+ : '{' stmts '}' { sLL $1 $> ((moc $1:mcc $3:(fst $ unLoc $2))+ ,(reverse $ snd $ unLoc $2)) } -- AZ:performance of reverse?+ | vocurly stmts close { L (gl $2) (fst $ unLoc $2+ ,reverse $ snd $ unLoc $2) }++-- do { ;; s ; s ; ; s ;; }+-- The last Stmt should be an expression, but that's hard to enforce+-- here, because we need too much lookahead if we see do { e ; }+-- So we use BodyStmts throughout, and switch the last one over+-- in ParseUtils.checkDo instead++stmts :: { Located ([AddAnn],[LStmt RdrName (LHsExpr RdrName)]) }+ : stmts ';' stmt {% if null (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1)+ ,$3 : (snd $ unLoc $1)))+ else do+ { ams (head $ snd $ unLoc $1) [mj AnnSemi $2]+ ; return $ sLL $1 $> (fst $ unLoc $1,$3 :(snd $ unLoc $1)) }}++ | stmts ';' {% if null (snd $ unLoc $1)+ then return (sLL $1 $> (mj AnnSemi $2:(fst $ unLoc $1),snd $ unLoc $1))+ else do+ { ams (head $ snd $ unLoc $1)+ [mj AnnSemi $2]+ ; return $1 } }+ | stmt { sL1 $1 ([],[$1]) }+ | {- empty -} { noLoc ([],[]) }+++-- For typing stmts at the GHCi prompt, where+-- the input may consist of just comments.+maybe_stmt :: { Maybe (LStmt RdrName (LHsExpr RdrName)) }+ : stmt { Just $1 }+ | {- nothing -} { Nothing }++stmt :: { LStmt RdrName (LHsExpr RdrName) }+ : qual { $1 }+ | 'rec' stmtlist {% ams (sLL $1 $> $ mkRecStmt (snd $ unLoc $2))+ (mj AnnRec $1:(fst $ unLoc $2)) }++qual :: { LStmt RdrName (LHsExpr RdrName) }+ : bindpat '<-' exp {% ams (sLL $1 $> $ mkBindStmt $1 $3)+ [mu AnnLarrow $2] }+ | exp { sL1 $1 $ mkBodyStmt $1 }+ | 'let' binds {% ams (sLL $1 $>$ LetStmt (snd $ unLoc $2))+ (mj AnnLet $1:(fst $ unLoc $2)) }++-----------------------------------------------------------------------------+-- Record Field Update/Construction++fbinds :: { ([AddAnn],([LHsRecField RdrName (LHsExpr RdrName)], Bool)) }+ : fbinds1 { $1 }+ | {- empty -} { ([],([], False)) }++fbinds1 :: { ([AddAnn],([LHsRecField RdrName (LHsExpr RdrName)], Bool)) }+ : fbind ',' fbinds1+ {% addAnnotation (gl $1) AnnComma (gl $2) >>+ return (case $3 of (ma,(flds, dd)) -> (ma,($1 : flds, dd))) }+ | fbind { ([],([$1], False)) }+ | '..' { ([mj AnnDotdot $1],([], True)) }++fbind :: { LHsRecField RdrName (LHsExpr RdrName) }+ : qvar '=' texp {% ams (sLL $1 $> $ HsRecField (sL1 $1 $ mkFieldOcc $1) $3 False)+ [mj AnnEqual $2] }+ -- RHS is a 'texp', allowing view patterns (Trac #6038)+ -- and, incidentally, sections. Eg+ -- f (R { x = show -> s }) = ...++ | qvar { sLL $1 $> $ HsRecField (sL1 $1 $ mkFieldOcc $1) placeHolderPunRhs True }+ -- In the punning case, use a place-holder+ -- The renamer fills in the final value++-----------------------------------------------------------------------------+-- Implicit Parameter Bindings++dbinds :: { Located [LIPBind RdrName] }+ : dbinds ';' dbind+ {% addAnnotation (gl $ last $ unLoc $1) AnnSemi (gl $2) >>+ return (let { this = $3; rest = unLoc $1 }+ in rest `seq` this `seq` sLL $1 $> (this : rest)) }+ | dbinds ';' {% addAnnotation (gl $ last $ unLoc $1) AnnSemi (gl $2) >>+ return (sLL $1 $> (unLoc $1)) }+ | dbind { let this = $1 in this `seq` sL1 $1 [this] }+-- | {- empty -} { [] }++dbind :: { LIPBind RdrName }+dbind : ipvar '=' exp {% ams (sLL $1 $> (IPBind (Left $1) $3))+ [mj AnnEqual $2] }++ipvar :: { Located HsIPName }+ : IPDUPVARID { sL1 $1 (HsIPName (getIPDUPVARID $1)) }++-----------------------------------------------------------------------------+-- Overloaded labels++overloaded_label :: { Located FastString }+ : LABELVARID { sL1 $1 (getLABELVARID $1) }++-----------------------------------------------------------------------------+-- Warnings and deprecations++name_boolformula_opt :: { LBooleanFormula (Located RdrName) }+ : name_boolformula { $1 }+ | {- empty -} { noLoc mkTrue }++name_boolformula :: { LBooleanFormula (Located RdrName) }+ : name_boolformula_and { $1 }+ | name_boolformula_and '|' name_boolformula+ {% aa $1 (AnnVbar, $2)+ >> return (sLL $1 $> (Or [$1,$3])) }++name_boolformula_and :: { LBooleanFormula (Located RdrName) }+ : name_boolformula_and_list+ { sLL (head $1) (last $1) (And ($1)) }++name_boolformula_and_list :: { [LBooleanFormula (Located RdrName)] }+ : name_boolformula_atom { [$1] }+ | name_boolformula_atom ',' name_boolformula_and_list+ {% aa $1 (AnnComma, $2) >> return ($1 : $3) }++name_boolformula_atom :: { LBooleanFormula (Located RdrName) }+ : '(' name_boolformula ')' {% ams (sLL $1 $> (Parens $2)) [mop $1,mcp $3] }+ | name_var { sL1 $1 (Var $1) }++namelist :: { Located [Located RdrName] }+namelist : name_var { sL1 $1 [$1] }+ | name_var ',' namelist {% addAnnotation (gl $1) AnnComma (gl $2) >>+ return (sLL $1 $> ($1 : unLoc $3)) }++name_var :: { Located RdrName }+name_var : var { $1 }+ | con { $1 }++-----------------------------------------+-- Data constructors+-- There are two different productions here as lifted list constructors+-- are parsed differently.++qcon_nowiredlist :: { Located RdrName }+ : gen_qcon { $1 }+ | sysdcon_nolist { sL1 $1 $ nameRdrName (dataConName (unLoc $1)) }++qcon :: { Located RdrName }+ : gen_qcon { $1}+ | sysdcon { sL1 $1 $ nameRdrName (dataConName (unLoc $1)) }++gen_qcon :: { Located RdrName }+ : qconid { $1 }+ | '(' qconsym ')' {% ams (sLL $1 $> (unLoc $2))+ [mop $1,mj AnnVal $2,mcp $3] }++-- The case of '[:' ':]' is part of the production `parr'++con :: { Located RdrName }+ : conid { $1 }+ | '(' consym ')' {% ams (sLL $1 $> (unLoc $2))+ [mop $1,mj AnnVal $2,mcp $3] }+ | sysdcon { sL1 $1 $ nameRdrName (dataConName (unLoc $1)) }++con_list :: { Located [Located RdrName] }+con_list : con { sL1 $1 [$1] }+ | con ',' con_list {% addAnnotation (gl $1) AnnComma (gl $2) >>+ return (sLL $1 $> ($1 : unLoc $3)) }++sysdcon_nolist :: { Located DataCon } -- Wired in data constructors+ : '(' ')' {% ams (sLL $1 $> unitDataCon) [mop $1,mcp $2] }+ | '(' commas ')' {% ams (sLL $1 $> $ tupleDataCon Boxed (snd $2 + 1))+ (mop $1:mcp $3:(mcommas (fst $2))) }+ | '(#' '#)' {% ams (sLL $1 $> $ unboxedUnitDataCon) [mo $1,mc $2] }+ | '(#' commas '#)' {% ams (sLL $1 $> $ tupleDataCon Unboxed (snd $2 + 1))+ (mo $1:mc $3:(mcommas (fst $2))) }++sysdcon :: { Located DataCon }+ : sysdcon_nolist { $1 }+ | '[' ']' {% ams (sLL $1 $> nilDataCon) [mos $1,mcs $2] }++conop :: { Located RdrName }+ : consym { $1 }+ | '`' conid '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++qconop :: { Located RdrName }+ : qconsym { $1 }+ | '`' qconid '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++----------------------------------------------------------------------------+-- Type constructors+++-- See Note [Unit tuples] in HsTypes for the distinction+-- between gtycon and ntgtycon+gtycon :: { Located RdrName } -- A "general" qualified tycon, including unit tuples+ : ntgtycon { $1 }+ | '(' ')' {% ams (sLL $1 $> $ getRdrName unitTyCon)+ [mop $1,mcp $2] }+ | '(#' '#)' {% ams (sLL $1 $> $ getRdrName unboxedUnitTyCon)+ [mo $1,mc $2] }++ntgtycon :: { Located RdrName } -- A "general" qualified tycon, excluding unit tuples+ : oqtycon { $1 }+ | '(' commas ')' {% ams (sLL $1 $> $ getRdrName (tupleTyCon Boxed+ (snd $2 + 1)))+ (mop $1:mcp $3:(mcommas (fst $2))) }+ | '(#' commas '#)' {% ams (sLL $1 $> $ getRdrName (tupleTyCon Unboxed+ (snd $2 + 1)))+ (mo $1:mc $3:(mcommas (fst $2))) }+ | '(' '->' ')' {% ams (sLL $1 $> $ getRdrName funTyCon)+ [mop $1,mu AnnRarrow $2,mcp $3] }+ | '[' ']' {% ams (sLL $1 $> $ listTyCon_RDR) [mos $1,mcs $2] }+ | '[:' ':]' {% ams (sLL $1 $> $ parrTyCon_RDR) [mo $1,mc $2] }+ | '(' '~#' ')' {% ams (sLL $1 $> $ getRdrName eqPrimTyCon)+ [mop $1,mj AnnTildehsh $2,mcp $3] }++oqtycon :: { Located RdrName } -- An "ordinary" qualified tycon;+ -- These can appear in export lists+ : qtycon { $1 }+ | '(' qtyconsym ')' {% ams (sLL $1 $> (unLoc $2))+ [mop $1,mj AnnVal $2,mcp $3] }+ | '(' '~' ')' {% ams (sLL $1 $> $ eqTyCon_RDR)+ [mop $1,mj AnnVal $2,mcp $3] }++oqtycon_no_varcon :: { Located RdrName } -- Type constructor which cannot be mistaken+ -- for variable constructor in export lists+ -- see Note [Type constructors in export list]+ : qtycon { $1 }+ | '(' QCONSYM ')' {% let name = sL1 $2 $! mkQual tcClsName (getQCONSYM $2)+ in ams (sLL $1 $> (unLoc name)) [mop $1,mj AnnVal name,mcp $3] }+ | '(' CONSYM ')' {% let name = sL1 $2 $! mkUnqual tcClsName (getCONSYM $2)+ in ams (sLL $1 $> (unLoc name)) [mop $1,mj AnnVal name,mcp $3] }+ | '(' ':' ')' {% let name = sL1 $2 $! consDataCon_RDR+ in ams (sLL $1 $> (unLoc name)) [mop $1,mj AnnVal name,mcp $3] }+ | '(' '~' ')' {% ams (sLL $1 $> $ eqTyCon_RDR) [mop $1,mj AnnTilde $2,mcp $3] }++{- Note [Type constructors in export list]+~~~~~~~~~~~~~~~~~~~~~+Mixing type constructors and data constructors in export lists introduces+ambiguity in grammar: e.g. (*) may be both a type constructor and a function.++-XExplicitNamespaces allows to disambiguate by explicitly prefixing type+constructors with 'type' keyword.++This ambiguity causes reduce/reduce conflicts in parser, which are always+resolved in favour of data constructors. To get rid of conflicts we demand+that ambiguous type constructors (those, which are formed by the same+productions as variable constructors) are always prefixed with 'type' keyword.+Unambiguous type constructors may occur both with or without 'type' keyword.++Note that in the parser we still parse data constructors as type+constructors. As such, they still end up in the type constructor namespace+until after renaming when we resolve the proper namespace for each exported+child.+-}++qtyconop :: { Located RdrName } -- Qualified or unqualified+ : qtyconsym { $1 }+ | '`' qtycon '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++qtycon :: { Located RdrName } -- Qualified or unqualified+ : QCONID { sL1 $1 $! mkQual tcClsName (getQCONID $1) }+ | tycon { $1 }++qtycondoc :: { LHsType RdrName } -- Qualified or unqualified+ : qtycon { sL1 $1 (HsTyVar NotPromoted $1) }+ | qtycon docprev { sLL $1 $> (HsDocTy (sL1 $1 (HsTyVar NotPromoted $1)) $2) }++tycon :: { Located RdrName } -- Unqualified+ : CONID { sL1 $1 $! mkUnqual tcClsName (getCONID $1) }++qtyconsym :: { Located RdrName }+ : QCONSYM { sL1 $1 $! mkQual tcClsName (getQCONSYM $1) }+ | QVARSYM { sL1 $1 $! mkQual tcClsName (getQVARSYM $1) }+ | tyconsym { $1 }++-- Does not include "!", because that is used for strictness marks+-- or ".", because that separates the quantified type vars from the rest+tyconsym :: { Located RdrName }+ : CONSYM { sL1 $1 $! mkUnqual tcClsName (getCONSYM $1) }+ | VARSYM { sL1 $1 $! mkUnqual tcClsName (getVARSYM $1) }+ | ':' { sL1 $1 $! consDataCon_RDR }+ | '-' { sL1 $1 $! mkUnqual tcClsName (fsLit "-") }+++-----------------------------------------------------------------------------+-- Operators++op :: { Located RdrName } -- used in infix decls+ : varop { $1 }+ | conop { $1 }++varop :: { Located RdrName }+ : varsym { $1 }+ | '`' varid '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++qop :: { LHsExpr RdrName } -- used in sections+ : qvarop { sL1 $1 $ HsVar $1 }+ | qconop { sL1 $1 $ HsVar $1 }+ | '`' '_' '`' {% ams (sLL $1 $> EWildPat)+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++qopm :: { LHsExpr RdrName } -- used in sections+ : qvaropm { sL1 $1 $ HsVar $1 }+ | qconop { sL1 $1 $ HsVar $1 }++qvarop :: { Located RdrName }+ : qvarsym { $1 }+ | '`' qvarid '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++qvaropm :: { Located RdrName }+ : qvarsym_no_minus { $1 }+ | '`' qvarid '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }++-----------------------------------------------------------------------------+-- Type variables++tyvar :: { Located RdrName }+tyvar : tyvarid { $1 }++tyvarop :: { Located RdrName }+tyvarop : '`' tyvarid '`' {% ams (sLL $1 $> (unLoc $2))+ [mj AnnBackquote $1,mj AnnVal $2+ ,mj AnnBackquote $3] }+ | '.' {% hintExplicitForall' (getLoc $1) }++tyvarid :: { Located RdrName }+ : VARID { sL1 $1 $! mkUnqual tvName (getVARID $1) }+ | special_id { sL1 $1 $! mkUnqual tvName (unLoc $1) }+ | 'unsafe' { sL1 $1 $! mkUnqual tvName (fsLit "unsafe") }+ | 'safe' { sL1 $1 $! mkUnqual tvName (fsLit "safe") }+ | 'interruptible' { sL1 $1 $! mkUnqual tvName (fsLit "interruptible") }++-----------------------------------------------------------------------------+-- Variables++var :: { Located RdrName }+ : varid { $1 }+ | '(' varsym ')' {% ams (sLL $1 $> (unLoc $2))+ [mop $1,mj AnnVal $2,mcp $3] }++ -- Lexing type applications depends subtly on what characters can possibly+ -- end a qvar. Currently (June 2015), only $idchars and ")" can end a qvar.+ -- If you're changing this, please see Note [Lexing type applications] in+ -- Lexer.x.+qvar :: { Located RdrName }+ : qvarid { $1 }+ | '(' varsym ')' {% ams (sLL $1 $> (unLoc $2))+ [mop $1,mj AnnVal $2,mcp $3] }+ | '(' qvarsym1 ')' {% ams (sLL $1 $> (unLoc $2))+ [mop $1,mj AnnVal $2,mcp $3] }+-- We've inlined qvarsym here so that the decision about+-- whether it's a qvar or a var can be postponed until+-- *after* we see the close paren.++qvarid :: { Located RdrName }+ : varid { $1 }+ | QVARID { sL1 $1 $! mkQual varName (getQVARID $1) }++-- Note that 'role' and 'family' get lexed separately regardless of+-- the use of extensions. However, because they are listed here,+-- this is OK and they can be used as normal varids.+-- See Note [Lexing type pseudo-keywords] in Lexer.x+varid :: { Located RdrName }+ : VARID { sL1 $1 $! mkUnqual varName (getVARID $1) }+ | special_id { sL1 $1 $! mkUnqual varName (unLoc $1) }+ | 'unsafe' { sL1 $1 $! mkUnqual varName (fsLit "unsafe") }+ | 'safe' { sL1 $1 $! mkUnqual varName (fsLit "safe") }+ | 'interruptible' { sL1 $1 $! mkUnqual varName (fsLit "interruptible")}+ | 'forall' { sL1 $1 $! mkUnqual varName (fsLit "forall") }+ | 'family' { sL1 $1 $! mkUnqual varName (fsLit "family") }+ | 'role' { sL1 $1 $! mkUnqual varName (fsLit "role") }++qvarsym :: { Located RdrName }+ : varsym { $1 }+ | qvarsym1 { $1 }++qvarsym_no_minus :: { Located RdrName }+ : varsym_no_minus { $1 }+ | qvarsym1 { $1 }++qvarsym1 :: { Located RdrName }+qvarsym1 : QVARSYM { sL1 $1 $ mkQual varName (getQVARSYM $1) }++varsym :: { Located RdrName }+ : varsym_no_minus { $1 }+ | '-' { sL1 $1 $ mkUnqual varName (fsLit "-") }++varsym_no_minus :: { Located RdrName } -- varsym not including '-'+ : VARSYM { sL1 $1 $ mkUnqual varName (getVARSYM $1) }+ | special_sym { sL1 $1 $ mkUnqual varName (unLoc $1) }+++-- These special_ids are treated as keywords in various places,+-- but as ordinary ids elsewhere. 'special_id' collects all these+-- except 'unsafe', 'interruptible', 'forall', 'family', 'role', 'stock', and+-- 'anyclass', whose treatment differs depending on context+special_id :: { Located FastString }+special_id+ : 'as' { sL1 $1 (fsLit "as") }+ | 'qualified' { sL1 $1 (fsLit "qualified") }+ | 'hiding' { sL1 $1 (fsLit "hiding") }+ | 'export' { sL1 $1 (fsLit "export") }+ | 'label' { sL1 $1 (fsLit "label") }+ | 'dynamic' { sL1 $1 (fsLit "dynamic") }+ | 'stdcall' { sL1 $1 (fsLit "stdcall") }+ | 'ccall' { sL1 $1 (fsLit "ccall") }+ | 'capi' { sL1 $1 (fsLit "capi") }+ | 'prim' { sL1 $1 (fsLit "prim") }+ | 'javascript' { sL1 $1 (fsLit "javascript") }+ | 'group' { sL1 $1 (fsLit "group") }+ | 'stock' { sL1 $1 (fsLit "stock") }+ | 'anyclass' { sL1 $1 (fsLit "anyclass") }+ | 'unit' { sL1 $1 (fsLit "unit") }+ | 'dependency' { sL1 $1 (fsLit "dependency") }+ | 'signature' { sL1 $1 (fsLit "signature") }++special_sym :: { Located FastString }+special_sym : '!' {% ams (sL1 $1 (fsLit "!")) [mj AnnBang $1] }+ | '.' { sL1 $1 (fsLit ".") }++-----------------------------------------------------------------------------+-- Data constructors++qconid :: { Located RdrName } -- Qualified or unqualified+ : conid { $1 }+ | QCONID { sL1 $1 $! mkQual dataName (getQCONID $1) }++conid :: { Located RdrName }+ : CONID { sL1 $1 $ mkUnqual dataName (getCONID $1) }++qconsym :: { Located RdrName } -- Qualified or unqualified+ : consym { $1 }+ | QCONSYM { sL1 $1 $ mkQual dataName (getQCONSYM $1) }++consym :: { Located RdrName }+ : CONSYM { sL1 $1 $ mkUnqual dataName (getCONSYM $1) }++ -- ':' means only list cons+ | ':' { sL1 $1 $ consDataCon_RDR }+++-----------------------------------------------------------------------------+-- Literals++literal :: { Located HsLit }+ : CHAR { sL1 $1 $ HsChar (getCHARs $1) $ getCHAR $1 }+ | STRING { sL1 $1 $ HsString (getSTRINGs $1)+ $ getSTRING $1 }+ | PRIMINTEGER { sL1 $1 $ HsIntPrim (getPRIMINTEGERs $1)+ $ getPRIMINTEGER $1 }+ | PRIMWORD { sL1 $1 $ HsWordPrim (getPRIMWORDs $1)+ $ getPRIMWORD $1 }+ | PRIMCHAR { sL1 $1 $ HsCharPrim (getPRIMCHARs $1)+ $ getPRIMCHAR $1 }+ | PRIMSTRING { sL1 $1 $ HsStringPrim (getPRIMSTRINGs $1)+ $ getPRIMSTRING $1 }+ | PRIMFLOAT { sL1 $1 $ HsFloatPrim $ getPRIMFLOAT $1 }+ | PRIMDOUBLE { sL1 $1 $ HsDoublePrim $ getPRIMDOUBLE $1 }++-----------------------------------------------------------------------------+-- Layout++close :: { () }+ : vccurly { () } -- context popped in lexer.+ | error {% popContext }++-----------------------------------------------------------------------------+-- Miscellaneous (mostly renamings)++modid :: { Located ModuleName }+ : CONID { sL1 $1 $ mkModuleNameFS (getCONID $1) }+ | QCONID { sL1 $1 $ let (mod,c) = getQCONID $1 in+ mkModuleNameFS+ (mkFastString+ (unpackFS mod ++ '.':unpackFS c))+ }++commas :: { ([SrcSpan],Int) } -- One or more commas+ : commas ',' { ((fst $1)++[gl $2],snd $1 + 1) }+ | ',' { ([gl $1],1) }++bars0 :: { ([SrcSpan],Int) } -- Zero or more bars+ : bars { $1 }+ | { ([], 0) }++bars :: { ([SrcSpan],Int) } -- One or more bars+ : bars '|' { ((fst $1)++[gl $2],snd $1 + 1) }+ | '|' { ([gl $1],1) }++-----------------------------------------------------------------------------+-- Documentation comments++docnext :: { LHsDocString }+ : DOCNEXT {% return (sL1 $1 (HsDocString (mkFastString (getDOCNEXT $1)))) }++docprev :: { LHsDocString }+ : DOCPREV {% return (sL1 $1 (HsDocString (mkFastString (getDOCPREV $1)))) }++docnamed :: { Located (String, HsDocString) }+ : DOCNAMED {%+ let string = getDOCNAMED $1+ (name, rest) = break isSpace string+ in return (sL1 $1 (name, HsDocString (mkFastString rest))) }++docsection :: { Located (Int, HsDocString) }+ : DOCSECTION {% let (n, doc) = getDOCSECTION $1 in+ return (sL1 $1 (n, HsDocString (mkFastString doc))) }++moduleheader :: { Maybe LHsDocString }+ : DOCNEXT {% let string = getDOCNEXT $1 in+ return (Just (sL1 $1 (HsDocString (mkFastString string)))) }++maybe_docprev :: { Maybe LHsDocString }+ : docprev { Just $1 }+ | {- empty -} { Nothing }++maybe_docnext :: { Maybe LHsDocString }+ : docnext { Just $1 }+ | {- empty -} { Nothing }++{+happyError :: P a+happyError = srcParseFail++getVARID (L _ (ITvarid x)) = x+getCONID (L _ (ITconid x)) = x+getVARSYM (L _ (ITvarsym x)) = x+getCONSYM (L _ (ITconsym x)) = x+getQVARID (L _ (ITqvarid x)) = x+getQCONID (L _ (ITqconid x)) = x+getQVARSYM (L _ (ITqvarsym x)) = x+getQCONSYM (L _ (ITqconsym x)) = x+getIPDUPVARID (L _ (ITdupipvarid x)) = x+getLABELVARID (L _ (ITlabelvarid x)) = x+getCHAR (L _ (ITchar _ x)) = x+getSTRING (L _ (ITstring _ x)) = x+getINTEGER (L _ (ITinteger _ x)) = x+getRATIONAL (L _ (ITrational x)) = x+getPRIMCHAR (L _ (ITprimchar _ x)) = x+getPRIMSTRING (L _ (ITprimstring _ x)) = x+getPRIMINTEGER (L _ (ITprimint _ x)) = x+getPRIMWORD (L _ (ITprimword _ x)) = x+getPRIMFLOAT (L _ (ITprimfloat x)) = x+getPRIMDOUBLE (L _ (ITprimdouble x)) = x+getTH_ID_SPLICE (L _ (ITidEscape x)) = x+getTH_ID_TY_SPLICE (L _ (ITidTyEscape x)) = x+getINLINE (L _ (ITinline_prag _ inl conl)) = (inl,conl)+getSPEC_INLINE (L _ (ITspec_inline_prag _ True)) = (Inline, FunLike)+getSPEC_INLINE (L _ (ITspec_inline_prag _ False)) = (NoInline,FunLike)+getCOMPLETE_PRAGs (L _ (ITcomplete_prag x)) = x++getDOCNEXT (L _ (ITdocCommentNext x)) = x+getDOCPREV (L _ (ITdocCommentPrev x)) = x+getDOCNAMED (L _ (ITdocCommentNamed x)) = x+getDOCSECTION (L _ (ITdocSection n x)) = (n, x)++getCHARs (L _ (ITchar src _)) = src+getSTRINGs (L _ (ITstring src _)) = src+getINTEGERs (L _ (ITinteger src _)) = src+getPRIMCHARs (L _ (ITprimchar src _)) = src+getPRIMSTRINGs (L _ (ITprimstring src _)) = src+getPRIMINTEGERs (L _ (ITprimint src _)) = src+getPRIMWORDs (L _ (ITprimword src _)) = src++-- See Note [Pragma source text] in BasicTypes for the following+getINLINE_PRAGs (L _ (ITinline_prag src _ _)) = src+getSPEC_PRAGs (L _ (ITspec_prag src)) = src+getSPEC_INLINE_PRAGs (L _ (ITspec_inline_prag src _)) = src+getSOURCE_PRAGs (L _ (ITsource_prag src)) = src+getRULES_PRAGs (L _ (ITrules_prag src)) = src+getWARNING_PRAGs (L _ (ITwarning_prag src)) = src+getDEPRECATED_PRAGs (L _ (ITdeprecated_prag src)) = src+getSCC_PRAGs (L _ (ITscc_prag src)) = src+getGENERATED_PRAGs (L _ (ITgenerated_prag src)) = src+getCORE_PRAGs (L _ (ITcore_prag src)) = src+getUNPACK_PRAGs (L _ (ITunpack_prag src)) = src+getNOUNPACK_PRAGs (L _ (ITnounpack_prag src)) = src+getANN_PRAGs (L _ (ITann_prag src)) = src+getVECT_PRAGs (L _ (ITvect_prag src)) = src+getVECT_SCALAR_PRAGs (L _ (ITvect_scalar_prag src)) = src+getNOVECT_PRAGs (L _ (ITnovect_prag src)) = src+getMINIMAL_PRAGs (L _ (ITminimal_prag src)) = src+getOVERLAPPABLE_PRAGs (L _ (IToverlappable_prag src)) = src+getOVERLAPPING_PRAGs (L _ (IToverlapping_prag src)) = src+getOVERLAPS_PRAGs (L _ (IToverlaps_prag src)) = src+getINCOHERENT_PRAGs (L _ (ITincoherent_prag src)) = src+getCTYPEs (L _ (ITctype src)) = src++getStringLiteral l = StringLiteral (getSTRINGs l) (getSTRING l)++isUnicode :: Located Token -> Bool+isUnicode (L _ (ITforall iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITdarrow iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITdcolon iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITlarrow iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITrarrow iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITlarrowtail iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITrarrowtail iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITLarrowtail iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITRarrowtail iu)) = iu == UnicodeSyntax+isUnicode (L _ (IToparenbar iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITcparenbar iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITopenExpQuote _ iu)) = iu == UnicodeSyntax+isUnicode (L _ (ITcloseQuote iu)) = iu == UnicodeSyntax+isUnicode _ = False++hasE :: Located Token -> Bool+hasE (L _ (ITopenExpQuote HasE _)) = True+hasE (L _ (ITopenTExpQuote HasE)) = True+hasE _ = False++getSCC :: Located Token -> P FastString+getSCC lt = do let s = getSTRING lt+ err = "Spaces are not allowed in SCCs"+ -- We probably actually want to be more restrictive than this+ if ' ' `elem` unpackFS s+ then failSpanMsgP (getLoc lt) (text err)+ else return s++-- Utilities for combining source spans+comb2 :: Located a -> Located b -> SrcSpan+comb2 a b = a `seq` b `seq` combineLocs a b++comb3 :: Located a -> Located b -> Located c -> SrcSpan+comb3 a b c = a `seq` b `seq` c `seq`+ combineSrcSpans (getLoc a) (combineSrcSpans (getLoc b) (getLoc c))++comb4 :: Located a -> Located b -> Located c -> Located d -> SrcSpan+comb4 a b c d = a `seq` b `seq` c `seq` d `seq`+ (combineSrcSpans (getLoc a) $ combineSrcSpans (getLoc b) $+ combineSrcSpans (getLoc c) (getLoc d))++-- strict constructor version:+{-# INLINE sL #-}+sL :: SrcSpan -> a -> Located a+sL span a = span `seq` a `seq` L span a++-- See Note [Adding location info] for how these utility functions are used++-- replaced last 3 CPP macros in this file+{-# INLINE sL0 #-}+sL0 :: a -> Located a+sL0 = L noSrcSpan -- #define L0 L noSrcSpan++{-# INLINE sL1 #-}+sL1 :: Located a -> b -> Located b+sL1 x = sL (getLoc x) -- #define sL1 sL (getLoc $1)++{-# INLINE sLL #-}+sLL :: Located a -> Located b -> c -> Located c+sLL x y = sL (comb2 x y) -- #define LL sL (comb2 $1 $>)++{- Note [Adding location info]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~++This is done using the three functions below, sL0, sL1+and sLL. Note that these functions were mechanically+converted from the three macros that used to exist before,+namely L0, L1 and LL.++They each add a SrcSpan to their argument.++ sL0 adds 'noSrcSpan', used for empty productions+ -- This doesn't seem to work anymore -=chak++ sL1 for a production with a single token on the lhs. Grabs the SrcSpan+ from that token.++ sLL for a production with >1 token on the lhs. Makes up a SrcSpan from+ the first and last tokens.++These suffice for the majority of cases. However, we must be+especially careful with empty productions: sLL won't work if the first+or last token on the lhs can represent an empty span. In these cases,+we have to calculate the span using more of the tokens from the lhs, eg.++ | 'newtype' tycl_hdr '=' newconstr deriving+ { L (comb3 $1 $4 $5)+ (mkTyData NewType (unLoc $2) $4 (unLoc $5)) }++We provide comb3 and comb4 functions which are useful in such cases.++Be careful: there's no checking that you actually got this right, the+only symptom will be that the SrcSpans of your syntax will be+incorrect.++-}++-- Make a source location for the file. We're a bit lazy here and just+-- make a point SrcSpan at line 1, column 0. Strictly speaking we should+-- try to find the span of the whole file (ToDo).+fileSrcSpan :: P SrcSpan+fileSrcSpan = do+ l <- getSrcLoc;+ let loc = mkSrcLoc (srcLocFile l) 1 1;+ return (mkSrcSpan loc loc)++-- Hint about the MultiWayIf extension+hintMultiWayIf :: SrcSpan -> P ()+hintMultiWayIf span = do+ mwiEnabled <- liftM ((LangExt.MultiWayIf `extopt`) . options) getPState+ unless mwiEnabled $ parseErrorSDoc span $+ text "Multi-way if-expressions need MultiWayIf turned on"++-- Hint about if usage for beginners+hintIf :: SrcSpan -> String -> P (LHsExpr RdrName)+hintIf span msg = do+ mwiEnabled <- liftM ((LangExt.MultiWayIf `extopt`) . options) getPState+ if mwiEnabled+ then parseErrorSDoc span $ text $ "parse error in if statement"+ else parseErrorSDoc span $ text $ "parse error in if statement: "++msg++-- Hint about explicit-forall, assuming UnicodeSyntax is on+hintExplicitForall :: SrcSpan -> P ()+hintExplicitForall span = do+ forall <- extension explicitForallEnabled+ rulePrag <- extension inRulePrag+ unless (forall || rulePrag) $ parseErrorSDoc span $ vcat+ [ text "Illegal symbol '\x2200' in type" -- U+2200 FOR ALL+ , text "Perhaps you intended to use RankNTypes or a similar language"+ , text "extension to enable explicit-forall syntax: \x2200 <tvs>. <type>"+ ]++-- Hint about explicit-forall, assuming UnicodeSyntax is off+hintExplicitForall' :: SrcSpan -> P (GenLocated SrcSpan RdrName)+hintExplicitForall' span = do+ forall <- extension explicitForallEnabled+ let illegalDot = "Illegal symbol '.' in type"+ if forall+ then parseErrorSDoc span $ vcat+ [ text illegalDot+ , text "Perhaps you meant to write 'forall <tvs>. <type>'?"+ ]+ else parseErrorSDoc span $ vcat+ [ text illegalDot+ , text "Perhaps you intended to use RankNTypes or a similar language"+ , text "extension to enable explicit-forall syntax: forall <tvs>. <type>"+ ]++{-+%************************************************************************+%* *+ Helper functions for generating annotations in the parser+%* *+%************************************************************************++For the general principles of the following routines, see Note [Api annotations]+in ApiAnnotation.hs++-}++-- |Construct an AddAnn from the annotation keyword and the location+-- of the keyword itself+mj :: AnnKeywordId -> Located e -> AddAnn+mj a l s = addAnnotation s a (gl l)++-- |Construct an AddAnn from the annotation keyword and the Located Token. If+-- the token has a unicode equivalent and this has been used, provide the+-- unicode variant of the annotation.+mu :: AnnKeywordId -> Located Token -> AddAnn+mu a lt@(L l t) = (\s -> addAnnotation s (toUnicodeAnn a lt) l)++-- | If the 'Token' is using its unicode variant return the unicode variant of+-- the annotation+toUnicodeAnn :: AnnKeywordId -> Located Token -> AnnKeywordId+toUnicodeAnn a t = if isUnicode t then unicodeAnn a else a++gl = getLoc++-- |Add an annotation to the located element, and return the located+-- element as a pass through+aa :: Located a -> (AnnKeywordId,Located c) -> P (Located a)+aa a@(L l _) (b,s) = addAnnotation l b (gl s) >> return a++-- |Add an annotation to a located element resulting from a monadic action+am :: P (Located a) -> (AnnKeywordId, Located b) -> P (Located a)+am a (b,s) = do+ av@(L l _) <- a+ addAnnotation l b (gl s)+ return av++-- | Add a list of AddAnns to the given AST element. For example,+-- the parsing rule for @let@ looks like:+--+-- @+-- | 'let' binds 'in' exp {% ams (sLL $1 $> $ HsLet (snd $ unLoc $2) $4)+-- (mj AnnLet $1:mj AnnIn $3+-- :(fst $ unLoc $2)) }+-- @+--+-- This adds an AnnLet annotation for @let@, an AnnIn for @in@, as well+-- as any annotations that may arise in the binds. This will include open+-- and closing braces if they are used to delimit the let expressions.+--+ams :: Located a -> [AddAnn] -> P (Located a)+ams a@(L l _) bs = addAnnsAt l bs >> return a++-- |Add all [AddAnn] to an AST element wrapped in a Just+aljs :: Located (Maybe a) -> [AddAnn] -> P (Located (Maybe a))+aljs a@(L l _) bs = addAnnsAt l bs >> return a++-- |Add all [AddAnn] to an AST element wrapped in a Just+ajs a@(Just (L l _)) bs = addAnnsAt l bs >> return a++-- |Add a list of AddAnns to the given AST element, where the AST element is the+-- result of a monadic action+amms :: P (Located a) -> [AddAnn] -> P (Located a)+amms a bs = do { av@(L l _) <- a+ ; addAnnsAt l bs+ ; return av }++-- |Add a list of AddAnns to the AST element, and return the element as a+-- OrdList+amsu :: Located a -> [AddAnn] -> P (OrdList (Located a))+amsu a@(L l _) bs = addAnnsAt l bs >> return (unitOL a)++-- |Synonyms for AddAnn versions of AnnOpen and AnnClose+mo,mc :: Located Token -> AddAnn+mo ll = mj AnnOpen ll+mc ll = mj AnnClose ll++moc,mcc :: Located Token -> AddAnn+moc ll = mj AnnOpenC ll+mcc ll = mj AnnCloseC ll++mop,mcp :: Located Token -> AddAnn+mop ll = mj AnnOpenP ll+mcp ll = mj AnnCloseP ll++mos,mcs :: Located Token -> AddAnn+mos ll = mj AnnOpenS ll+mcs ll = mj AnnCloseS ll++-- |Given a list of the locations of commas, provide a [AddAnn] with an AnnComma+-- entry for each SrcSpan+mcommas :: [SrcSpan] -> [AddAnn]+mcommas ss = map (\s -> mj AnnCommaTuple (L s ())) ss++-- |Given a list of the locations of '|'s, provide a [AddAnn] with an AnnVbar+-- entry for each SrcSpan+mvbars :: [SrcSpan] -> [AddAnn]+mvbars ss = map (\s -> mj AnnVbar (L s ())) ss++-- |Get the location of the last element of a OrdList, or noSrcSpan+oll :: OrdList (Located a) -> SrcSpan+oll l =+ if isNilOL l then noSrcSpan+ else getLoc (lastOL l)++-- |Add a semicolon annotation in the right place in a list. If the+-- leading list is empty, add it to the tail+asl :: [Located a] -> Located b -> Located a -> P()+asl [] (L ls _) (L l _) = addAnnotation l AnnSemi ls+asl (x:_xs) (L ls _) _x = addAnnotation (getLoc x) AnnSemi ls+}
+ parser/RdrHsSyn.hs view
@@ -0,0 +1,1562 @@+--+-- (c) The University of Glasgow 2002-2006+--++-- Functions over HsSyn specialised to RdrName.++{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}++module RdrHsSyn (+ mkHsOpApp,+ mkHsIntegral, mkHsFractional, mkHsIsString,+ mkHsDo, mkSpliceDecl,+ mkRoleAnnotDecl,+ mkClassDecl,+ mkTyData, mkDataFamInst,+ mkTySynonym, mkTyFamInstEqn,+ mkTyFamInst,+ mkFamDecl, mkLHsSigType,+ splitCon, mkInlinePragma,+ mkPatSynMatchGroup,+ mkRecConstrOrUpdate, -- HsExp -> [HsFieldUpdate] -> P HsExp+ mkTyClD, mkInstD,+ mkRdrRecordCon, mkRdrRecordUpd,+ setRdrNameSpace,++ cvBindGroup,+ cvBindsAndSigs,+ cvTopDecls,+ placeHolderPunRhs,++ -- Stuff to do with Foreign declarations+ mkImport,+ parseCImport,+ mkExport,+ mkExtName, -- RdrName -> CLabelString+ mkGadtDecl, -- [Located RdrName] -> LHsType RdrName -> ConDecl RdrName+ mkConDeclH98,+ mkATDefault,++ -- Bunch of functions in the parser monad for+ -- checking and constructing values+ checkPrecP, -- Int -> P Int+ checkContext, -- HsType -> P HsContext+ checkPattern, -- HsExp -> P HsPat+ bang_RDR,+ checkPatterns, -- SrcLoc -> [HsExp] -> P [HsPat]+ checkMonadComp, -- P (HsStmtContext RdrName)+ checkCommand, -- LHsExpr RdrName -> P (LHsCmd RdrName)+ checkValDef, -- (SrcLoc, HsExp, HsRhs, [HsDecl]) -> P HsDecl+ checkValSigLhs,+ checkDoAndIfThenElse,+ checkRecordSyntax,+ parseErrorSDoc,+ splitTilde, splitTildeApps,++ -- Help with processing exports+ ImpExpSubSpec(..),+ ImpExpQcSpec(..),+ mkModuleImpExp,+ mkTypeImpExp,+ mkImpExpSubSpec,+ checkImportSpec,++ SumOrTuple (..), mkSumOrTuple++ ) where++import HsSyn -- Lots of it+import Class ( FunDep )+import TyCon ( TyCon, isTupleTyCon, tyConSingleDataCon_maybe )+import DataCon ( DataCon, dataConTyCon )+import ConLike ( ConLike(..) )+import CoAxiom ( Role, fsFromRole )+import RdrName+import Name+import BasicTypes+import TcEvidence ( idHsWrapper )+import Lexer+import Lexeme ( isLexCon )+import Type ( TyThing(..) )+import TysWiredIn ( cTupleTyConName, tupleTyCon, tupleDataCon,+ nilDataConName, nilDataConKey,+ listTyConName, listTyConKey,+ starKindTyConName, unicodeStarKindTyConName )+import ForeignCall+import PrelNames ( forall_tv_RDR, eqTyCon_RDR, allNameStrings )+import SrcLoc+import Unique ( hasKey )+import OrdList ( OrdList, fromOL )+import Bag ( emptyBag, consBag )+import Outputable+import FastString+import Maybes+import Util+import ApiAnnotation+import Data.List+import qualified GHC.LanguageExtensions as LangExt+import MonadUtils++import Control.Monad+import Text.ParserCombinators.ReadP as ReadP+import Data.Char++import Data.Data ( dataTypeOf, fromConstr, dataTypeConstrs )++#include "HsVersions.h"+++{- **********************************************************************++ Construction functions for Rdr stuff++ ********************************************************************* -}++-- | mkClassDecl builds a RdrClassDecl, filling in the names for tycon and+-- datacon by deriving them from the name of the class. We fill in the names+-- for the tycon and datacon corresponding to the class, by deriving them+-- from the name of the class itself. This saves recording the names in the+-- interface file (which would be equally good).++-- Similarly for mkConDecl, mkClassOpSig and default-method names.++-- *** See Note [The Naming story] in HsDecls ****++mkTyClD :: LTyClDecl n -> LHsDecl n+mkTyClD (L loc d) = L loc (TyClD d)++mkInstD :: LInstDecl n -> LHsDecl n+mkInstD (L loc d) = L loc (InstD d)++mkClassDecl :: SrcSpan+ -> Located (Maybe (LHsContext RdrName), LHsType RdrName)+ -> Located (a,[Located (FunDep (Located RdrName))])+ -> OrdList (LHsDecl RdrName)+ -> P (LTyClDecl RdrName)++mkClassDecl loc (L _ (mcxt, tycl_hdr)) fds where_cls+ = do { (binds, sigs, ats, at_insts, _, docs) <- cvBindsAndSigs where_cls+ ; let cxt = fromMaybe (noLoc []) mcxt+ ; (cls, tparams, fixity, ann) <- checkTyClHdr True tycl_hdr+ ; mapM_ (\a -> a loc) ann -- Add any API Annotations to the top SrcSpan+ ; tyvars <- checkTyVarsP (text "class") whereDots cls tparams+ ; at_defs <- mapM (eitherToP . mkATDefault) at_insts+ ; return (L loc (ClassDecl { tcdCtxt = cxt, tcdLName = cls, tcdTyVars = tyvars+ , tcdFixity = fixity+ , tcdFDs = snd (unLoc fds)+ , tcdSigs = mkClassOpSigs sigs+ , tcdMeths = binds+ , tcdATs = ats, tcdATDefs = at_defs, tcdDocs = docs+ , tcdFVs = placeHolderNames })) }++mkATDefault :: LTyFamInstDecl RdrName+ -> Either (SrcSpan, SDoc) (LTyFamDefltEqn RdrName)+-- Take a type-family instance declaration and turn it into+-- a type-family default equation for a class declaration+-- We parse things as the former and use this function to convert to the latter+--+-- We use the Either monad because this also called+-- from Convert.hs+mkATDefault (L loc (TyFamInstDecl { tfid_eqn = L _ e }))+ | TyFamEqn { tfe_tycon = tc, tfe_pats = pats, tfe_fixity = fixity+ , tfe_rhs = rhs } <- e+ = do { tvs <- checkTyVars (text "default") equalsDots tc (hsib_body pats)+ ; return (L loc (TyFamEqn { tfe_tycon = tc+ , tfe_pats = tvs+ , tfe_fixity = fixity+ , tfe_rhs = rhs })) }++mkTyData :: SrcSpan+ -> NewOrData+ -> Maybe (Located CType)+ -> Located (Maybe (LHsContext RdrName), LHsType RdrName)+ -> Maybe (LHsKind RdrName)+ -> [LConDecl RdrName]+ -> HsDeriving RdrName+ -> P (LTyClDecl RdrName)+mkTyData loc new_or_data cType (L _ (mcxt, tycl_hdr)) ksig data_cons maybe_deriv+ = do { (tc, tparams, fixity, ann) <- checkTyClHdr False tycl_hdr+ ; mapM_ (\a -> a loc) ann -- Add any API Annotations to the top SrcSpan+ ; tyvars <- checkTyVarsP (ppr new_or_data) equalsDots tc tparams+ ; defn <- mkDataDefn new_or_data cType mcxt ksig data_cons maybe_deriv+ ; return (L loc (DataDecl { tcdLName = tc, tcdTyVars = tyvars,+ tcdFixity = fixity,+ tcdDataDefn = defn,+ tcdDataCusk = PlaceHolder,+ tcdFVs = placeHolderNames })) }++mkDataDefn :: NewOrData+ -> Maybe (Located CType)+ -> Maybe (LHsContext RdrName)+ -> Maybe (LHsKind RdrName)+ -> [LConDecl RdrName]+ -> HsDeriving RdrName+ -> P (HsDataDefn RdrName)+mkDataDefn new_or_data cType mcxt ksig data_cons maybe_deriv+ = do { checkDatatypeContext mcxt+ ; let cxt = fromMaybe (noLoc []) mcxt+ ; return (HsDataDefn { dd_ND = new_or_data, dd_cType = cType+ , dd_ctxt = cxt+ , dd_cons = data_cons+ , dd_kindSig = ksig+ , dd_derivs = maybe_deriv }) }+++mkTySynonym :: SrcSpan+ -> LHsType RdrName -- LHS+ -> LHsType RdrName -- RHS+ -> P (LTyClDecl RdrName)+mkTySynonym loc lhs rhs+ = do { (tc, tparams, fixity, ann) <- checkTyClHdr False lhs+ ; mapM_ (\a -> a loc) ann -- Add any API Annotations to the top SrcSpan+ ; tyvars <- checkTyVarsP (text "type") equalsDots tc tparams+ ; return (L loc (SynDecl { tcdLName = tc, tcdTyVars = tyvars+ , tcdFixity = fixity+ , tcdRhs = rhs, tcdFVs = placeHolderNames })) }++mkTyFamInstEqn :: LHsType RdrName+ -> LHsType RdrName+ -> P (TyFamInstEqn RdrName,[AddAnn])+mkTyFamInstEqn lhs rhs+ = do { (tc, tparams, fixity, ann) <- checkTyClHdr False lhs+ ; return (TyFamEqn { tfe_tycon = tc+ , tfe_pats = mkHsImplicitBndrs tparams+ , tfe_fixity = fixity+ , tfe_rhs = rhs },+ ann) }++mkDataFamInst :: SrcSpan+ -> NewOrData+ -> Maybe (Located CType)+ -> Located (Maybe (LHsContext RdrName), LHsType RdrName)+ -> Maybe (LHsKind RdrName)+ -> [LConDecl RdrName]+ -> HsDeriving RdrName+ -> P (LInstDecl RdrName)+mkDataFamInst loc new_or_data cType (L _ (mcxt, tycl_hdr)) ksig data_cons maybe_deriv+ = do { (tc, tparams, fixity, ann) <- checkTyClHdr False tycl_hdr+ ; mapM_ (\a -> a loc) ann -- Add any API Annotations to the top SrcSpan+ ; defn <- mkDataDefn new_or_data cType mcxt ksig data_cons maybe_deriv+ ; return (L loc (DataFamInstD (+ DataFamInstDecl { dfid_tycon = tc+ , dfid_pats = mkHsImplicitBndrs tparams+ , dfid_fixity = fixity+ , dfid_defn = defn, dfid_fvs = placeHolderNames }))) }++mkTyFamInst :: SrcSpan+ -> LTyFamInstEqn RdrName+ -> P (LInstDecl RdrName)+mkTyFamInst loc eqn+ = return (L loc (TyFamInstD (TyFamInstDecl { tfid_eqn = eqn+ , tfid_fvs = placeHolderNames })))++mkFamDecl :: SrcSpan+ -> FamilyInfo RdrName+ -> LHsType RdrName -- LHS+ -> Located (FamilyResultSig RdrName) -- Optional result signature+ -> Maybe (LInjectivityAnn RdrName) -- Injectivity annotation+ -> P (LTyClDecl RdrName)+mkFamDecl loc info lhs ksig injAnn+ = do { (tc, tparams, fixity, ann) <- checkTyClHdr False lhs+ ; mapM_ (\a -> a loc) ann -- Add any API Annotations to the top SrcSpan+ ; tyvars <- checkTyVarsP (ppr info) equals_or_where tc tparams+ ; return (L loc (FamDecl (FamilyDecl{ fdInfo = info, fdLName = tc+ , fdTyVars = tyvars+ , fdFixity = fixity+ , fdResultSig = ksig+ , fdInjectivityAnn = injAnn }))) }+ where+ equals_or_where = case info of+ DataFamily -> empty+ OpenTypeFamily -> empty+ ClosedTypeFamily {} -> whereDots++mkSpliceDecl :: LHsExpr RdrName -> HsDecl RdrName+-- If the user wrote+-- [pads| ... ] then return a QuasiQuoteD+-- $(e) then return a SpliceD+-- but if she wrote, say,+-- f x then behave as if she'd written $(f x)+-- ie a SpliceD+--+-- Typed splices are not allowed at the top level, thus we do not represent them+-- as spliced declaration. See #10945+mkSpliceDecl lexpr@(L loc expr)+ | HsSpliceE splice@(HsUntypedSplice {}) <- expr+ = SpliceD (SpliceDecl (L loc splice) ExplicitSplice)++ | HsSpliceE splice@(HsQuasiQuote {}) <- expr+ = SpliceD (SpliceDecl (L loc splice) ExplicitSplice)++ | otherwise+ = SpliceD (SpliceDecl (L loc (mkUntypedSplice NoParens lexpr)) ImplicitSplice)++mkRoleAnnotDecl :: SrcSpan+ -> Located RdrName -- type being annotated+ -> [Located (Maybe FastString)] -- roles+ -> P (LRoleAnnotDecl RdrName)+mkRoleAnnotDecl loc tycon roles+ = do { roles' <- mapM parse_role roles+ ; return $ L loc $ RoleAnnotDecl tycon roles' }+ where+ role_data_type = dataTypeOf (undefined :: Role)+ all_roles = map fromConstr $ dataTypeConstrs role_data_type+ possible_roles = [(fsFromRole role, role) | role <- all_roles]++ parse_role (L loc_role Nothing) = return $ L loc_role Nothing+ parse_role (L loc_role (Just role))+ = case lookup role possible_roles of+ Just found_role -> return $ L loc_role $ Just found_role+ Nothing ->+ let nearby = fuzzyLookup (unpackFS role) (mapFst unpackFS possible_roles) in+ parseErrorSDoc loc_role+ (text "Illegal role name" <+> quotes (ppr role) $$+ suggestions nearby)++ suggestions [] = empty+ suggestions [r] = text "Perhaps you meant" <+> quotes (ppr r)+ -- will this last case ever happen??+ suggestions list = hang (text "Perhaps you meant one of these:")+ 2 (pprWithCommas (quotes . ppr) list)++{- **********************************************************************++ #cvBinds-etc# Converting to @HsBinds@, etc.++ ********************************************************************* -}++-- | Function definitions are restructured here. Each is assumed to be recursive+-- initially, and non recursive definitions are discovered by the dependency+-- analyser.+++-- | Groups together bindings for a single function+cvTopDecls :: OrdList (LHsDecl RdrName) -> [LHsDecl RdrName]+cvTopDecls decls = go (fromOL decls)+ where+ go :: [LHsDecl RdrName] -> [LHsDecl RdrName]+ go [] = []+ go (L l (ValD b) : ds) = L l' (ValD b') : go ds'+ where (L l' b', ds') = getMonoBind (L l b) ds+ go (d : ds) = d : go ds++-- Declaration list may only contain value bindings and signatures.+cvBindGroup :: OrdList (LHsDecl RdrName) -> P (HsValBinds RdrName)+cvBindGroup binding+ = do { (mbs, sigs, fam_ds, tfam_insts, dfam_insts, _) <- cvBindsAndSigs binding+ ; ASSERT( null fam_ds && null tfam_insts && null dfam_insts)+ return $ ValBindsIn mbs sigs }++cvBindsAndSigs :: OrdList (LHsDecl RdrName)+ -> P (LHsBinds RdrName, [LSig RdrName], [LFamilyDecl RdrName]+ , [LTyFamInstDecl RdrName], [LDataFamInstDecl RdrName], [LDocDecl])+-- Input decls contain just value bindings and signatures+-- and in case of class or instance declarations also+-- associated type declarations. They might also contain Haddock comments.+cvBindsAndSigs fb = go (fromOL fb)+ where+ go [] = return (emptyBag, [], [], [], [], [])+ go (L l (ValD b) : ds)+ = do { (bs, ss, ts, tfis, dfis, docs) <- go ds'+ ; return (b' `consBag` bs, ss, ts, tfis, dfis, docs) }+ where+ (b', ds') = getMonoBind (L l b) ds+ go (L l decl : ds)+ = do { (bs, ss, ts, tfis, dfis, docs) <- go ds+ ; case decl of+ SigD s+ -> return (bs, L l s : ss, ts, tfis, dfis, docs)+ TyClD (FamDecl t)+ -> return (bs, ss, L l t : ts, tfis, dfis, docs)+ InstD (TyFamInstD { tfid_inst = tfi })+ -> return (bs, ss, ts, L l tfi : tfis, dfis, docs)+ InstD (DataFamInstD { dfid_inst = dfi })+ -> return (bs, ss, ts, tfis, L l dfi : dfis, docs)+ DocD d+ -> return (bs, ss, ts, tfis, dfis, L l d : docs)+ SpliceD d+ -> parseErrorSDoc l $+ hang (text "Declaration splices are allowed only" <+>+ text "at the top level:")+ 2 (ppr d)+ _ -> pprPanic "cvBindsAndSigs" (ppr decl) }++-----------------------------------------------------------------------------+-- Group function bindings into equation groups++getMonoBind :: LHsBind RdrName -> [LHsDecl RdrName]+ -> (LHsBind RdrName, [LHsDecl RdrName])+-- Suppose (b',ds') = getMonoBind b ds+-- ds is a list of parsed bindings+-- b is a MonoBinds that has just been read off the front++-- Then b' is the result of grouping more equations from ds that+-- belong with b into a single MonoBinds, and ds' is the depleted+-- list of parsed bindings.+--+-- All Haddock comments between equations inside the group are+-- discarded.+--+-- No AndMonoBinds or EmptyMonoBinds here; just single equations++getMonoBind (L loc1 (FunBind { fun_id = fun_id1@(L _ f1),+ fun_matches+ = MG { mg_alts = L _ mtchs1 } })) binds+ | has_args mtchs1+ = go mtchs1 loc1 binds []+ where+ go mtchs loc+ (L loc2 (ValD (FunBind { fun_id = L _ f2,+ fun_matches+ = MG { mg_alts = L _ mtchs2 } })) : binds) _+ | f1 == f2 = go (mtchs2 ++ mtchs)+ (combineSrcSpans loc loc2) binds []+ go mtchs loc (doc_decl@(L loc2 (DocD _)) : binds) doc_decls+ = let doc_decls' = doc_decl : doc_decls+ in go mtchs (combineSrcSpans loc loc2) binds doc_decls'+ go mtchs loc binds doc_decls+ = ( L loc (makeFunBind fun_id1 (reverse mtchs))+ , (reverse doc_decls) ++ binds)+ -- Reverse the final matches, to get it back in the right order+ -- Do the same thing with the trailing doc comments++getMonoBind bind binds = (bind, binds)++has_args :: [LMatch RdrName (LHsExpr RdrName)] -> Bool+has_args [] = panic "RdrHsSyn:has_args"+has_args ((L _ (Match _ args _ _)) : _) = not (null args)+ -- Don't group together FunBinds if they have+ -- no arguments. This is necessary now that variable bindings+ -- with no arguments are now treated as FunBinds rather+ -- than pattern bindings (tests/rename/should_fail/rnfail002).++{- **********************************************************************++ #PrefixToHS-utils# Utilities for conversion++ ********************************************************************* -}++{- Note [Parsing data constructors is hard]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We parse the RHS of the constructor declaration+ data T = C t1 t2+as a btype_no_ops (treating C as a type constructor) and then convert C to be+a data constructor. Reason: it might continue like this:+ data T = C t1 t2 :% D Int+in which case C really /would/ be a type constructor. We can't resolve this+ambiguity till we come across the constructor oprerator :% (or not, more usually)++So the plan is:++* Parse the data constructor declration as a type (actually btype_no_ops)++* Use 'splitCon' to rejig it into the data constructor and the args++* In doing so, we use 'tyConToDataCon' to convert the RdrName for+ the data con, which has been parsed as a tycon, back to a datacon.+ This is more than just adjusting the name space; for operators we+ need to check that it begins with a colon. E.g.+ data T = (+++)+ will parse ok (since tycons can be operators), but we should reject+ it (Trac #12051).+-}++splitCon :: LHsType RdrName+ -> P (Located RdrName, HsConDeclDetails RdrName)+-- See Note [Parsing data constructors is hard]+-- This gets given a "type" that should look like+-- C Int Bool+-- or C { x::Int, y::Bool }+-- and returns the pieces+splitCon ty+ = split ty []+ where+ -- This is used somewhere where HsAppsTy is not used+ split (L _ (HsAppTy t u)) ts = split t (u : ts)+ split (L l (HsTyVar _ (L _ tc))) ts = do data_con <- tyConToDataCon l tc+ return (data_con, mk_rest ts)+ split (L l (HsTupleTy HsBoxedOrConstraintTuple ts)) []+ = return (L l (getRdrName (tupleDataCon Boxed (length ts))), PrefixCon ts)+ split (L l _) _ = parseErrorSDoc l (text "Cannot parse data constructor in a data/newtype declaration:" <+> ppr ty)++ mk_rest [L l (HsRecTy flds)] = RecCon (L l flds)+ mk_rest ts = PrefixCon ts++tyConToDataCon :: SrcSpan -> RdrName -> P (Located RdrName)+-- See Note [Parsing data constructors is hard]+-- Data constructor RHSs are parsed as types+tyConToDataCon loc tc+ | isTcOcc occ+ , isLexCon (occNameFS occ)+ = return (L loc (setRdrNameSpace tc srcDataName))++ | otherwise+ = parseErrorSDoc loc (msg $$ extra)+ where+ occ = rdrNameOcc tc++ msg = text "Not a data constructor:" <+> quotes (ppr tc)+ extra | tc == forall_tv_RDR+ = text "Perhaps you intended to use ExistentialQuantification"+ | otherwise = empty++mkPatSynMatchGroup :: Located RdrName+ -> Located (OrdList (LHsDecl RdrName))+ -> P (MatchGroup RdrName (LHsExpr RdrName))+mkPatSynMatchGroup (L loc patsyn_name) (L _ decls) =+ do { matches <- mapM fromDecl (fromOL decls)+ ; when (null matches) (wrongNumberErr loc)+ ; return $ mkMatchGroup FromSource matches }+ where+ fromDecl (L loc decl@(ValD (PatBind pat@(L _ (ConPatIn ln@(L _ name) details)) rhs _ _ _))) =+ do { unless (name == patsyn_name) $+ wrongNameBindingErr loc decl+ ; match <- case details of+ PrefixCon pats ->+ return $ Match (FunRhs ln Prefix NoSrcStrict) pats Nothing rhs+ InfixCon pat1 pat2 ->+ return $ Match (FunRhs ln Infix NoSrcStrict) [pat1, pat2] Nothing rhs+ RecCon{} -> recordPatSynErr loc pat+ ; return $ L loc match }+ fromDecl (L loc decl) = extraDeclErr loc decl++ extraDeclErr loc decl =+ parseErrorSDoc loc $+ text "pattern synonym 'where' clause must contain a single binding:" $$+ ppr decl++ wrongNameBindingErr loc decl =+ parseErrorSDoc loc $+ text "pattern synonym 'where' clause must bind the pattern synonym's name" <+>+ quotes (ppr patsyn_name) $$ ppr decl++ wrongNumberErr loc =+ parseErrorSDoc loc $+ text "pattern synonym 'where' clause cannot be empty" $$+ text "In the pattern synonym declaration for: " <+> ppr (patsyn_name)++recordPatSynErr :: SrcSpan -> LPat RdrName -> P a+recordPatSynErr loc pat =+ parseErrorSDoc loc $+ text "record syntax not supported for pattern synonym declarations:" $$+ ppr pat++mkConDeclH98 :: Located RdrName -> Maybe [LHsTyVarBndr RdrName]+ -> LHsContext RdrName -> HsConDeclDetails RdrName+ -> ConDecl RdrName++mkConDeclH98 name mb_forall cxt details+ = ConDeclH98 { con_name = name+ , con_qvars = fmap mkHsQTvs mb_forall+ , con_cxt = Just cxt+ -- AZ:TODO: when can cxt be Nothing?+ -- remembering that () is a valid context.+ , con_details = details+ , con_doc = Nothing }++mkGadtDecl :: [Located RdrName]+ -> LHsSigType RdrName -- Always a HsForAllTy+ -> ConDecl RdrName+mkGadtDecl names ty = ConDeclGADT { con_names = names+ , con_type = ty+ , con_doc = Nothing }++setRdrNameSpace :: RdrName -> NameSpace -> RdrName+-- ^ This rather gruesome function is used mainly by the parser.+-- When parsing:+--+-- > data T a = T | T1 Int+--+-- we parse the data constructors as /types/ because of parser ambiguities,+-- so then we need to change the /type constr/ to a /data constr/+--+-- The exact-name case /can/ occur when parsing:+--+-- > data [] a = [] | a : [a]+--+-- For the exact-name case we return an original name.+setRdrNameSpace (Unqual occ) ns = Unqual (setOccNameSpace ns occ)+setRdrNameSpace (Qual m occ) ns = Qual m (setOccNameSpace ns occ)+setRdrNameSpace (Orig m occ) ns = Orig m (setOccNameSpace ns occ)+setRdrNameSpace (Exact n) ns+ | Just thing <- wiredInNameTyThing_maybe n+ = setWiredInNameSpace thing ns+ -- Preserve Exact Names for wired-in things,+ -- notably tuples and lists++ | isExternalName n+ = Orig (nameModule n) occ++ | otherwise -- This can happen when quoting and then+ -- splicing a fixity declaration for a type+ = Exact (mkSystemNameAt (nameUnique n) occ (nameSrcSpan n))+ where+ occ = setOccNameSpace ns (nameOccName n)++setWiredInNameSpace :: TyThing -> NameSpace -> RdrName+setWiredInNameSpace (ATyCon tc) ns+ | isDataConNameSpace ns+ = ty_con_data_con tc+ | isTcClsNameSpace ns+ = Exact (getName tc) -- No-op++setWiredInNameSpace (AConLike (RealDataCon dc)) ns+ | isTcClsNameSpace ns+ = data_con_ty_con dc+ | isDataConNameSpace ns+ = Exact (getName dc) -- No-op++setWiredInNameSpace thing ns+ = pprPanic "setWiredinNameSpace" (pprNameSpace ns <+> ppr thing)++ty_con_data_con :: TyCon -> RdrName+ty_con_data_con tc+ | isTupleTyCon tc+ , Just dc <- tyConSingleDataCon_maybe tc+ = Exact (getName dc)++ | tc `hasKey` listTyConKey+ = Exact nilDataConName++ | otherwise -- See Note [setRdrNameSpace for wired-in names]+ = Unqual (setOccNameSpace srcDataName (getOccName tc))++data_con_ty_con :: DataCon -> RdrName+data_con_ty_con dc+ | let tc = dataConTyCon dc+ , isTupleTyCon tc+ = Exact (getName tc)++ | dc `hasKey` nilDataConKey+ = Exact listTyConName++ | otherwise -- See Note [setRdrNameSpace for wired-in names]+ = Unqual (setOccNameSpace tcClsName (getOccName dc))+++{- Note [setRdrNameSpace for wired-in names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In GHC.Types, which declares (:), we have+ infixr 5 :+The ambiguity about which ":" is meant is resolved by parsing it as a+data constructor, but then using dataTcOccs to try the type constructor too;+and that in turn calls setRdrNameSpace to change the name-space of ":" to+tcClsName. There isn't a corresponding ":" type constructor, but it's painful+to make setRdrNameSpace partial, so we just make an Unqual name instead. It+really doesn't matter!+-}++-- | Note [Sorting out the result type]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- In a GADT declaration which is not a record, we put the whole constr type+-- into the res_ty for a ConDeclGADT for now; the renamer will unravel it once+-- it has sorted out operator fixities. Consider for example+-- C :: a :*: b -> a :*: b -> a :+: b+-- Initially this type will parse as+-- a :*: (b -> (a :*: (b -> (a :+: b))))+--+-- so it's hard to split up the arguments until we've done the precedence+-- resolution (in the renamer). On the other hand, for a record+-- { x,y :: Int } -> a :*: b+-- there is no doubt. AND we need to sort records out so that+-- we can bring x,y into scope. So:+-- * For PrefixCon we keep all the args in the res_ty+-- * For RecCon we do not++checkTyVarsP :: SDoc -> SDoc -> Located RdrName -> [LHsType RdrName] -> P (LHsQTyVars RdrName)+-- Same as checkTyVars, but in the P monad+checkTyVarsP pp_what equals_or_where tc tparms+ = eitherToP $ checkTyVars pp_what equals_or_where tc tparms++eitherToP :: Either (SrcSpan, SDoc) a -> P a+-- Adapts the Either monad to the P monad+eitherToP (Left (loc, doc)) = parseErrorSDoc loc doc+eitherToP (Right thing) = return thing++checkTyVars :: SDoc -> SDoc -> Located RdrName -> [LHsType RdrName]+ -> Either (SrcSpan, SDoc) (LHsQTyVars RdrName)+-- Check whether the given list of type parameters are all type variables+-- (possibly with a kind signature)+-- We use the Either monad because it's also called (via mkATDefault) from+-- Convert.hs+checkTyVars pp_what equals_or_where tc tparms+ = do { tvs <- mapM chk tparms+ ; return (mkHsQTvs tvs) }+ where++ chk (L _ (HsParTy ty)) = chk ty+ chk (L _ (HsAppsTy [L _ (HsAppPrefix ty)])) = chk ty++ -- Check that the name space is correct!+ chk (L l (HsKindSig+ (L _ (HsAppsTy [L _ (HsAppPrefix (L lv (HsTyVar _ (L _ tv))))])) k))+ | isRdrTyVar tv = return (L l (KindedTyVar (L lv tv) k))+ chk (L l (HsTyVar _ (L ltv tv)))+ | isRdrTyVar tv = return (L l (UserTyVar (L ltv tv)))+ chk t@(L loc _)+ = Left (loc,+ vcat [ text "Unexpected type" <+> quotes (ppr t)+ , text "In the" <+> pp_what <+> ptext (sLit "declaration for") <+> quotes (ppr tc)+ , vcat[ (text "A" <+> pp_what <+> ptext (sLit "declaration should have form"))+ , nest 2 (pp_what <+> ppr tc+ <+> hsep (map text (takeList tparms allNameStrings))+ <+> equals_or_where) ] ])++whereDots, equalsDots :: SDoc+-- Second argument to checkTyVars+whereDots = text "where ..."+equalsDots = text "= ..."++checkDatatypeContext :: Maybe (LHsContext RdrName) -> P ()+checkDatatypeContext Nothing = return ()+checkDatatypeContext (Just (L loc c))+ = do allowed <- extension datatypeContextsEnabled+ unless allowed $+ parseErrorSDoc loc+ (text "Illegal datatype context (use DatatypeContexts):" <+>+ pprHsContext c)++checkRecordSyntax :: Outputable a => Located a -> P (Located a)+checkRecordSyntax lr@(L loc r)+ = do allowed <- extension traditionalRecordSyntaxEnabled+ if allowed+ then return lr+ else parseErrorSDoc loc+ (text "Illegal record syntax (use TraditionalRecordSyntax):" <+>+ ppr r)++checkTyClHdr :: Bool -- True <=> class header+ -- False <=> type header+ -> LHsType RdrName+ -> P (Located RdrName, -- the head symbol (type or class name)+ [LHsType RdrName], -- parameters of head symbol+ LexicalFixity, -- the declaration is in infix format+ [AddAnn]) -- API Annotation for HsParTy when stripping parens+-- Well-formedness check and decomposition of type and class heads.+-- Decomposes T ty1 .. tyn into (T, [ty1, ..., tyn])+-- Int :*: Bool into (:*:, [Int, Bool])+-- returning the pieces+checkTyClHdr is_cls ty+ = goL ty [] [] Prefix+ where+ goL (L l ty) acc ann fix = go l ty acc ann fix++ go l (HsTyVar _ (L _ tc)) acc ann fix+ | isRdrTc tc = return (L l tc, acc, fix, ann)+ go _ (HsOpTy t1 ltc@(L _ tc) t2) acc ann _fix+ | isRdrTc tc = return (ltc, t1:t2:acc, Infix, ann)+ go l (HsParTy ty) acc ann fix = goL ty acc (ann ++ mkParensApiAnn l) fix+ go _ (HsAppTy t1 t2) acc ann fix = goL t1 (t2:acc) ann fix+ go _ (HsAppsTy ts) acc ann _fix+ | Just (head, args, fixity) <- getAppsTyHead_maybe ts+ = goL head (args ++ acc) ann fixity++ go _ (HsAppsTy [L _ (HsAppInfix (L loc star))]) [] ann fix+ | occNameFS (rdrNameOcc star) == fsLit "*"+ = return (L loc (nameRdrName starKindTyConName), [], fix, ann)+ | occNameFS (rdrNameOcc star) == fsLit "★"+ = return (L loc (nameRdrName unicodeStarKindTyConName), [], fix, ann)++ go l (HsTupleTy HsBoxedOrConstraintTuple ts) [] ann fix+ = return (L l (nameRdrName tup_name), ts, fix, ann)+ where+ arity = length ts+ tup_name | is_cls = cTupleTyConName arity+ | otherwise = getName (tupleTyCon Boxed arity)+ -- See Note [Unit tuples] in HsTypes (TODO: is this still relevant?)+ go l _ _ _ _+ = parseErrorSDoc l (text "Malformed head of type or class declaration:"+ <+> ppr ty)++checkContext :: LHsType RdrName -> P ([AddAnn],LHsContext RdrName)+checkContext (L l orig_t)+ = check [] (L l orig_t)+ where+ check anns (L lp (HsTupleTy _ ts)) -- (Eq a, Ord b) shows up as a tuple type+ = return (anns ++ mkParensApiAnn lp,L l ts) -- Ditto ()++ -- don't let HsAppsTy get in the way+ check anns (L _ (HsAppsTy [L _ (HsAppPrefix ty)]))+ = check anns ty++ check anns (L lp1 (HsParTy ty))-- to be sure HsParTy doesn't get into the way+ = check anns' ty+ where anns' = if l == lp1 then anns+ else (anns ++ mkParensApiAnn lp1)++ check _anns _+ = return ([],L l [L l orig_t]) -- no need for anns, returning original++-- -------------------------------------------------------------------------+-- Checking Patterns.++-- We parse patterns as expressions and check for valid patterns below,+-- converting the expression into a pattern at the same time.++checkPattern :: SDoc -> LHsExpr RdrName -> P (LPat RdrName)+checkPattern msg e = checkLPat msg e++checkPatterns :: SDoc -> [LHsExpr RdrName] -> P [LPat RdrName]+checkPatterns msg es = mapM (checkPattern msg) es++checkLPat :: SDoc -> LHsExpr RdrName -> P (LPat RdrName)+checkLPat msg e@(L l _) = checkPat msg l e []++checkPat :: SDoc -> SrcSpan -> LHsExpr RdrName -> [LPat RdrName]+ -> P (LPat RdrName)+checkPat _ loc (L l (HsVar (L _ c))) args+ | isRdrDataCon c = return (L loc (ConPatIn (L l c) (PrefixCon args)))+checkPat msg loc e args -- OK to let this happen even if bang-patterns+ -- are not enabled, because there is no valid+ -- non-bang-pattern parse of (C ! e)+ | Just (e', args') <- splitBang e+ = do { args'' <- checkPatterns msg args'+ ; checkPat msg loc e' (args'' ++ args) }+checkPat msg loc (L _ (HsApp f e)) args+ = do p <- checkLPat msg e+ checkPat msg loc f (p : args)+checkPat msg loc (L _ e) []+ = do p <- checkAPat msg loc e+ return (L loc p)+checkPat msg loc e _+ = patFail msg loc (unLoc e)++checkAPat :: SDoc -> SrcSpan -> HsExpr RdrName -> P (Pat RdrName)+checkAPat msg loc e0 = do+ pState <- getPState+ let opts = options pState+ case e0 of+ EWildPat -> return (WildPat placeHolderType)+ HsVar x -> return (VarPat x)+ HsLit (HsStringPrim _ _) -- (#13260)+ -> parseErrorSDoc loc (text "Illegal unboxed string literal in pattern:" $$ ppr e0)++ HsLit l -> return (LitPat l)++ -- Overloaded numeric patterns (e.g. f 0 x = x)+ -- Negation is recorded separately, so that the literal is zero or +ve+ -- NB. Negative *primitive* literals are already handled by the lexer+ HsOverLit pos_lit -> return (mkNPat (L loc pos_lit) Nothing)+ NegApp (L l (HsOverLit pos_lit)) _+ -> return (mkNPat (L l pos_lit) (Just noSyntaxExpr))++ SectionR (L lb (HsVar (L _ bang))) e -- (! x)+ | bang == bang_RDR+ -> do { bang_on <- extension bangPatEnabled+ ; if bang_on then do { e' <- checkLPat msg e+ ; addAnnotation loc AnnBang lb+ ; return (BangPat e') }+ else parseErrorSDoc loc (text "Illegal bang-pattern (use BangPatterns):" $$ ppr e0) }++ ELazyPat e -> checkLPat msg e >>= (return . LazyPat)+ EAsPat n e -> checkLPat msg e >>= (return . AsPat n)+ -- view pattern is well-formed if the pattern is+ EViewPat expr patE -> checkLPat msg patE >>=+ (return . (\p -> ViewPat expr p placeHolderType))+ ExprWithTySig e t -> do e <- checkLPat msg e+ return (SigPatIn e t)++ -- n+k patterns+ OpApp (L nloc (HsVar (L _ n))) (L _ (HsVar (L _ plus))) _+ (L lloc (HsOverLit lit@(OverLit {ol_val = HsIntegral {}})))+ | extopt LangExt.NPlusKPatterns opts && (plus == plus_RDR)+ -> return (mkNPlusKPat (L nloc n) (L lloc lit))++ OpApp l op _fix r -> do l <- checkLPat msg l+ r <- checkLPat msg r+ case op of+ L cl (HsVar (L _ c)) | isDataOcc (rdrNameOcc c)+ -> return (ConPatIn (L cl c) (InfixCon l r))+ _ -> patFail msg loc e0++ HsPar e -> checkLPat msg e >>= (return . ParPat)+ ExplicitList _ _ es -> do ps <- mapM (checkLPat msg) es+ return (ListPat ps placeHolderType Nothing)+ ExplicitPArr _ es -> do ps <- mapM (checkLPat msg) es+ return (PArrPat ps placeHolderType)++ ExplicitTuple es b+ | all tupArgPresent es -> do ps <- mapM (checkLPat msg)+ [e | L _ (Present e) <- es]+ return (TuplePat ps b [])+ | otherwise -> parseErrorSDoc loc (text "Illegal tuple section in pattern:" $$ ppr e0)++ ExplicitSum alt arity expr _ -> do+ p <- checkLPat msg expr+ return (SumPat p alt arity placeHolderType)++ RecordCon { rcon_con_name = c, rcon_flds = HsRecFields fs dd }+ -> do fs <- mapM (checkPatField msg) fs+ return (ConPatIn c (RecCon (HsRecFields fs dd)))+ HsSpliceE s | not (isTypedSplice s)+ -> return (SplicePat s)+ _ -> patFail msg loc e0++placeHolderPunRhs :: LHsExpr RdrName+-- The RHS of a punned record field will be filled in by the renamer+-- It's better not to make it an error, in case we want to print it when debugging+placeHolderPunRhs = noLoc (HsVar (noLoc pun_RDR))++plus_RDR, bang_RDR, pun_RDR :: RdrName+plus_RDR = mkUnqual varName (fsLit "+") -- Hack+bang_RDR = mkUnqual varName (fsLit "!") -- Hack+pun_RDR = mkUnqual varName (fsLit "pun-right-hand-side")++checkPatField :: SDoc -> LHsRecField RdrName (LHsExpr RdrName)+ -> P (LHsRecField RdrName (LPat RdrName))+checkPatField msg (L l fld) = do p <- checkLPat msg (hsRecFieldArg fld)+ return (L l (fld { hsRecFieldArg = p }))++patFail :: SDoc -> SrcSpan -> HsExpr RdrName -> P a+patFail msg loc e = parseErrorSDoc loc err+ where err = text "Parse error in pattern:" <+> ppr e+ $$ msg+++---------------------------------------------------------------------------+-- Check Equation Syntax++checkValDef :: SDoc+ -> SrcStrictness+ -> LHsExpr RdrName+ -> Maybe (LHsType RdrName)+ -> Located (a,GRHSs RdrName (LHsExpr RdrName))+ -> P ([AddAnn],HsBind RdrName)++checkValDef msg _strictness lhs (Just sig) grhss+ -- x :: ty = rhs parses as a *pattern* binding+ = checkPatBind msg (L (combineLocs lhs sig)+ (ExprWithTySig lhs (mkLHsSigWcType sig))) grhss++checkValDef msg strictness lhs opt_sig g@(L l (_,grhss))+ = do { mb_fun <- isFunLhs lhs+ ; case mb_fun of+ Just (fun, is_infix, pats, ann) ->+ checkFunBind msg strictness ann (getLoc lhs)+ fun is_infix pats opt_sig (L l grhss)+ Nothing -> checkPatBind msg lhs g }++checkFunBind :: SDoc+ -> SrcStrictness+ -> [AddAnn]+ -> SrcSpan+ -> Located RdrName+ -> LexicalFixity+ -> [LHsExpr RdrName]+ -> Maybe (LHsType RdrName)+ -> Located (GRHSs RdrName (LHsExpr RdrName))+ -> P ([AddAnn],HsBind RdrName)+checkFunBind msg strictness ann lhs_loc fun is_infix pats opt_sig (L rhs_span grhss)+ = do ps <- checkPatterns msg pats+ let match_span = combineSrcSpans lhs_loc rhs_span+ -- Add back the annotations stripped from any HsPar values in the lhs+ -- mapM_ (\a -> a match_span) ann+ return (ann, makeFunBind fun+ [L match_span (Match { m_ctxt = FunRhs fun is_infix strictness+ , m_pats = ps+ , m_type = opt_sig+ , m_grhss = grhss })])+ -- The span of the match covers the entire equation.+ -- That isn't quite right, but it'll do for now.++makeFunBind :: Located RdrName -> [LMatch RdrName (LHsExpr RdrName)]+ -> HsBind RdrName+-- Like HsUtils.mkFunBind, but we need to be able to set the fixity too+makeFunBind fn ms+ = FunBind { fun_id = fn,+ fun_matches = mkMatchGroup FromSource ms,+ fun_co_fn = idHsWrapper,+ bind_fvs = placeHolderNames,+ fun_tick = [] }++checkPatBind :: SDoc+ -> LHsExpr RdrName+ -> Located (a,GRHSs RdrName (LHsExpr RdrName))+ -> P ([AddAnn],HsBind RdrName)+checkPatBind msg lhs (L _ (_,grhss))+ = do { lhs <- checkPattern msg lhs+ ; return ([],PatBind lhs grhss placeHolderType placeHolderNames+ ([],[])) }++checkValSigLhs :: LHsExpr RdrName -> P (Located RdrName)+checkValSigLhs (L _ (HsVar lrdr@(L _ v)))+ | isUnqual v+ , not (isDataOcc (rdrNameOcc v))+ = return lrdr++checkValSigLhs lhs@(L l _)+ = parseErrorSDoc l ((text "Invalid type signature:" <+>+ ppr lhs <+> text ":: ...")+ $$ text hint)+ where+ hint | foreign_RDR `looks_like` lhs+ = "Perhaps you meant to use ForeignFunctionInterface?"+ | default_RDR `looks_like` lhs+ = "Perhaps you meant to use DefaultSignatures?"+ | pattern_RDR `looks_like` lhs+ = "Perhaps you meant to use PatternSynonyms?"+ | otherwise+ = "Should be of form <variable> :: <type>"++ -- A common error is to forget the ForeignFunctionInterface flag+ -- so check for that, and suggest. cf Trac #3805+ -- Sadly 'foreign import' still barfs 'parse error' because 'import' is a keyword+ looks_like s (L _ (HsVar (L _ v))) = v == s+ looks_like s (L _ (HsApp lhs _)) = looks_like s lhs+ looks_like _ _ = False++ foreign_RDR = mkUnqual varName (fsLit "foreign")+ default_RDR = mkUnqual varName (fsLit "default")+ pattern_RDR = mkUnqual varName (fsLit "pattern")+++checkDoAndIfThenElse :: LHsExpr RdrName+ -> Bool+ -> LHsExpr RdrName+ -> Bool+ -> LHsExpr RdrName+ -> P ()+checkDoAndIfThenElse guardExpr semiThen thenExpr semiElse elseExpr+ | semiThen || semiElse+ = do pState <- getPState+ unless (extopt LangExt.DoAndIfThenElse (options pState)) $ do+ parseErrorSDoc (combineLocs guardExpr elseExpr)+ (text "Unexpected semi-colons in conditional:"+ $$ nest 4 expr+ $$ text "Perhaps you meant to use DoAndIfThenElse?")+ | otherwise = return ()+ where pprOptSemi True = semi+ pprOptSemi False = empty+ expr = text "if" <+> ppr guardExpr <> pprOptSemi semiThen <+>+ text "then" <+> ppr thenExpr <> pprOptSemi semiElse <+>+ text "else" <+> ppr elseExpr+++ -- The parser left-associates, so there should+ -- not be any OpApps inside the e's+splitBang :: LHsExpr RdrName -> Maybe (LHsExpr RdrName, [LHsExpr RdrName])+-- Splits (f ! g a b) into (f, [(! g), a, b])+splitBang (L _ (OpApp l_arg bang@(L _ (HsVar (L _ op))) _ r_arg))+ | op == bang_RDR = Just (l_arg, L l' (SectionR bang arg1) : argns)+ where+ l' = combineLocs bang arg1+ (arg1,argns) = split_bang r_arg []+ split_bang (L _ (HsApp f e)) es = split_bang f (e:es)+ split_bang e es = (e,es)+splitBang _ = Nothing++isFunLhs :: LHsExpr RdrName+ -> P (Maybe (Located RdrName, LexicalFixity, [LHsExpr RdrName],[AddAnn]))+-- A variable binding is parsed as a FunBind.+-- Just (fun, is_infix, arg_pats) if e is a function LHS+--+-- The whole LHS is parsed as a single expression.+-- Any infix operators on the LHS will parse left-associatively+-- E.g. f !x y !z+-- will parse (rather strangely) as+-- (f ! x y) ! z+-- It's up to isFunLhs to sort out the mess+--+-- a .!. !b++isFunLhs e = go e [] []+ where+ go (L loc (HsVar (L _ f))) es ann+ | not (isRdrDataCon f) = return (Just (L loc f, Prefix, es, ann))+ go (L _ (HsApp f e)) es ann = go f (e:es) ann+ go (L l (HsPar e)) es@(_:_) ann = go e es (ann ++ mkParensApiAnn l)++ -- Things of the form `!x` are also FunBinds+ -- See Note [Varieties of binding pattern matches]+ go (L _ (SectionR (L _ (HsVar (L _ bang))) (L l (HsVar (L _ var))))) [] ann+ | bang == bang_RDR+ , not (isRdrDataCon var) = return (Just (L l var, Prefix, [], ann))++ -- For infix function defns, there should be only one infix *function*+ -- (though there may be infix *datacons* involved too). So we don't+ -- need fixity info to figure out which function is being defined.+ -- a `K1` b `op` c `K2` d+ -- must parse as+ -- (a `K1` b) `op` (c `K2` d)+ -- The renamer checks later that the precedences would yield such a parse.+ --+ -- There is a complication to deal with bang patterns.+ --+ -- ToDo: what about this?+ -- x + 1 `op` y = ...++ go e@(L loc (OpApp l (L loc' (HsVar (L _ op))) fix r)) es ann+ | Just (e',es') <- splitBang e+ = do { bang_on <- extension bangPatEnabled+ ; if bang_on then go e' (es' ++ es) ann+ else return (Just (L loc' op, Infix, (l:r:es), ann)) }+ -- No bangs; behave just like the next case+ | not (isRdrDataCon op) -- We have found the function!+ = return (Just (L loc' op, Infix, (l:r:es), ann))+ | otherwise -- Infix data con; keep going+ = do { mb_l <- go l es ann+ ; case mb_l of+ Just (op', Infix, j : k : es', ann')+ -> return (Just (op', Infix, j : op_app : es', ann'))+ where+ op_app = L loc (OpApp k (L loc' (HsVar (L loc' op))) fix r)+ _ -> return Nothing }+ go _ _ _ = return Nothing+++-- | Transform btype_no_ops with strict_mark's into HsEqTy's+-- (((~a) ~b) c) ~d ==> ((~a) ~ (b c)) ~ d+splitTilde :: LHsType RdrName -> P (LHsType RdrName)+splitTilde t = go t+ where go (L loc (HsAppTy t1 t2))+ | L lo (HsBangTy (HsSrcBang NoSourceText NoSrcUnpack SrcLazy) t2')+ <- t2+ = do+ moveAnnotations lo loc+ t1' <- go t1+ return (L loc (HsEqTy t1' t2'))+ | otherwise+ = do+ t1' <- go t1+ case t1' of+ (L lo (HsEqTy tl tr)) -> do+ let lr = combineLocs tr t2+ moveAnnotations lo loc+ return (L loc (HsEqTy tl (L lr (HsAppTy tr t2))))+ t -> do+ return (L loc (HsAppTy t t2))++ go t = return t+++-- | Transform tyapps with strict_marks into uses of twiddle+-- [~a, ~b, c, ~d] ==> (~a) ~ b c ~ d+splitTildeApps :: [LHsAppType RdrName] -> P [LHsAppType RdrName]+splitTildeApps [] = return []+splitTildeApps (t : rest) = do+ rest' <- concatMapM go rest+ return (t : rest')+ where go (L l (HsAppPrefix+ (L loc (HsBangTy+ (HsSrcBang NoSourceText NoSrcUnpack SrcLazy)+ ty))))+ = addAnnotation l AnnTilde tilde_loc >>+ return+ [L tilde_loc (HsAppInfix (L tilde_loc eqTyCon_RDR)),+ L l (HsAppPrefix ty)]+ -- NOTE: no annotation is attached to an HsAppPrefix, so the+ -- surrounding SrcSpan is not critical+ where+ tilde_loc = srcSpanFirstCharacter loc++ go t = return [t]++++---------------------------------------------------------------------------+-- Check for monad comprehensions+--+-- If the flag MonadComprehensions is set, return a `MonadComp' context,+-- otherwise use the usual `ListComp' context++checkMonadComp :: P (HsStmtContext Name)+checkMonadComp = do+ pState <- getPState+ return $ if extopt LangExt.MonadComprehensions (options pState)+ then MonadComp+ else ListComp++-- -------------------------------------------------------------------------+-- Checking arrow syntax.++-- We parse arrow syntax as expressions and check for valid syntax below,+-- converting the expression into a pattern at the same time.++checkCommand :: LHsExpr RdrName -> P (LHsCmd RdrName)+checkCommand lc = locMap checkCmd lc++locMap :: (SrcSpan -> a -> P b) -> Located a -> P (Located b)+locMap f (L l a) = f l a >>= (\b -> return $ L l b)++checkCmd :: SrcSpan -> HsExpr RdrName -> P (HsCmd RdrName)+checkCmd _ (HsArrApp e1 e2 ptt haat b) =+ return $ HsCmdArrApp e1 e2 ptt haat b+checkCmd _ (HsArrForm e mf args) =+ return $ HsCmdArrForm e Prefix mf args+checkCmd _ (HsApp e1 e2) =+ checkCommand e1 >>= (\c -> return $ HsCmdApp c e2)+checkCmd _ (HsLam mg) =+ checkCmdMatchGroup mg >>= (\mg' -> return $ HsCmdLam mg')+checkCmd _ (HsPar e) =+ checkCommand e >>= (\c -> return $ HsCmdPar c)+checkCmd _ (HsCase e mg) =+ checkCmdMatchGroup mg >>= (\mg' -> return $ HsCmdCase e mg')+checkCmd _ (HsIf cf ep et ee) = do+ pt <- checkCommand et+ pe <- checkCommand ee+ return $ HsCmdIf cf ep pt pe+checkCmd _ (HsLet lb e) =+ checkCommand e >>= (\c -> return $ HsCmdLet lb c)+checkCmd _ (HsDo DoExpr (L l stmts) ty) =+ mapM checkCmdLStmt stmts >>= (\ss -> return $ HsCmdDo (L l ss) ty)++checkCmd _ (OpApp eLeft op _fixity eRight) = do+ -- OpApp becomes a HsCmdArrForm with a (Just fixity) in it+ c1 <- checkCommand eLeft+ c2 <- checkCommand eRight+ let arg1 = L (getLoc c1) $ HsCmdTop c1 placeHolderType placeHolderType []+ arg2 = L (getLoc c2) $ HsCmdTop c2 placeHolderType placeHolderType []+ return $ HsCmdArrForm op Infix Nothing [arg1, arg2]++checkCmd l e = cmdFail l e++checkCmdLStmt :: ExprLStmt RdrName -> P (CmdLStmt RdrName)+checkCmdLStmt = locMap checkCmdStmt++checkCmdStmt :: SrcSpan -> ExprStmt RdrName -> P (CmdStmt RdrName)+checkCmdStmt _ (LastStmt e s r) =+ checkCommand e >>= (\c -> return $ LastStmt c s r)+checkCmdStmt _ (BindStmt pat e b f t) =+ checkCommand e >>= (\c -> return $ BindStmt pat c b f t)+checkCmdStmt _ (BodyStmt e t g ty) =+ checkCommand e >>= (\c -> return $ BodyStmt c t g ty)+checkCmdStmt _ (LetStmt bnds) = return $ LetStmt bnds+checkCmdStmt _ stmt@(RecStmt { recS_stmts = stmts }) = do+ ss <- mapM checkCmdLStmt stmts+ return $ stmt { recS_stmts = ss }+checkCmdStmt l stmt = cmdStmtFail l stmt++checkCmdMatchGroup :: MatchGroup RdrName (LHsExpr RdrName) -> P (MatchGroup RdrName (LHsCmd RdrName))+checkCmdMatchGroup mg@(MG { mg_alts = L l ms }) = do+ ms' <- mapM (locMap $ const convert) ms+ return $ mg { mg_alts = L l ms' }+ where convert (Match mf pat mty grhss) = do+ grhss' <- checkCmdGRHSs grhss+ return $ Match mf pat mty grhss'++checkCmdGRHSs :: GRHSs RdrName (LHsExpr RdrName) -> P (GRHSs RdrName (LHsCmd RdrName))+checkCmdGRHSs (GRHSs grhss binds) = do+ grhss' <- mapM checkCmdGRHS grhss+ return $ GRHSs grhss' binds++checkCmdGRHS :: LGRHS RdrName (LHsExpr RdrName) -> P (LGRHS RdrName (LHsCmd RdrName))+checkCmdGRHS = locMap $ const convert+ where+ convert (GRHS stmts e) = do+ c <- checkCommand e+-- cmdStmts <- mapM checkCmdLStmt stmts+ return $ GRHS {- cmdStmts -} stmts c+++cmdFail :: SrcSpan -> HsExpr RdrName -> P a+cmdFail loc e = parseErrorSDoc loc (text "Parse error in command:" <+> ppr e)+cmdStmtFail :: SrcSpan -> Stmt RdrName (LHsExpr RdrName) -> P a+cmdStmtFail loc e = parseErrorSDoc loc+ (text "Parse error in command statement:" <+> ppr e)++---------------------------------------------------------------------------+-- Miscellaneous utilities++checkPrecP :: Located (SourceText,Int) -> P (Located (SourceText,Int))+checkPrecP (L l (src,i))+ | 0 <= i && i <= maxPrecedence = return (L l (src,i))+ | otherwise+ = parseErrorSDoc l (text ("Precedence out of range: " ++ show i))++mkRecConstrOrUpdate+ :: LHsExpr RdrName+ -> SrcSpan+ -> ([LHsRecField RdrName (LHsExpr RdrName)], Bool)+ -> P (HsExpr RdrName)++mkRecConstrOrUpdate (L l (HsVar (L _ c))) _ (fs,dd)+ | isRdrDataCon c+ = return (mkRdrRecordCon (L l c) (mk_rec_fields fs dd))+mkRecConstrOrUpdate exp@(L l _) _ (fs,dd)+ | dd = parseErrorSDoc l (text "You cannot use `..' in a record update")+ | otherwise = return (mkRdrRecordUpd exp (map (fmap mk_rec_upd_field) fs))++mkRdrRecordUpd :: LHsExpr RdrName -> [LHsRecUpdField RdrName] -> HsExpr RdrName+mkRdrRecordUpd exp flds+ = RecordUpd { rupd_expr = exp+ , rupd_flds = flds+ , rupd_cons = PlaceHolder, rupd_in_tys = PlaceHolder+ , rupd_out_tys = PlaceHolder, rupd_wrap = PlaceHolder }++mkRdrRecordCon :: Located RdrName -> HsRecordBinds RdrName -> HsExpr RdrName+mkRdrRecordCon con flds+ = RecordCon { rcon_con_name = con, rcon_flds = flds+ , rcon_con_expr = noPostTcExpr, rcon_con_like = PlaceHolder }++mk_rec_fields :: [LHsRecField id arg] -> Bool -> HsRecFields id arg+mk_rec_fields fs False = HsRecFields { rec_flds = fs, rec_dotdot = Nothing }+mk_rec_fields fs True = HsRecFields { rec_flds = fs, rec_dotdot = Just (length fs) }++mk_rec_upd_field :: HsRecField RdrName (LHsExpr RdrName) -> HsRecUpdField RdrName+mk_rec_upd_field (HsRecField (L loc (FieldOcc rdr _)) arg pun)+ = HsRecField (L loc (Unambiguous rdr PlaceHolder)) arg pun++mkInlinePragma :: SourceText -> (InlineSpec, RuleMatchInfo) -> Maybe Activation+ -> InlinePragma+-- The (Maybe Activation) is because the user can omit+-- the activation spec (and usually does)+mkInlinePragma src (inl, match_info) mb_act+ = InlinePragma { inl_src = src -- Note [Pragma source text] in BasicTypes+ , inl_inline = inl+ , inl_sat = Nothing+ , inl_act = act+ , inl_rule = match_info }+ where+ act = case mb_act of+ Just act -> act+ Nothing -> -- No phase specified+ case inl of+ NoInline -> NeverActive+ _other -> AlwaysActive++-----------------------------------------------------------------------------+-- utilities for foreign declarations++-- construct a foreign import declaration+--+mkImport :: Located CCallConv+ -> Located Safety+ -> (Located StringLiteral, Located RdrName, LHsSigType RdrName)+ -> P (HsDecl RdrName)+mkImport cconv safety (L loc (StringLiteral esrc entity), v, ty) =+ case cconv of+ L _ CCallConv -> mkCImport+ L _ CApiConv -> mkCImport+ L _ StdCallConv -> mkCImport+ L _ PrimCallConv -> mkOtherImport+ L _ JavaScriptCallConv -> mkOtherImport+ where+ -- Parse a C-like entity string of the following form:+ -- "[static] [chname] [&] [cid]" | "dynamic" | "wrapper"+ -- If 'cid' is missing, the function name 'v' is used instead as symbol+ -- name (cf section 8.5.1 in Haskell 2010 report).+ mkCImport = do+ let e = unpackFS entity+ case parseCImport cconv safety (mkExtName (unLoc v)) e (L loc esrc) of+ Nothing -> parseErrorSDoc loc (text "Malformed entity string")+ Just importSpec -> returnSpec importSpec++ -- currently, all the other import conventions only support a symbol name in+ -- the entity string. If it is missing, we use the function name instead.+ mkOtherImport = returnSpec importSpec+ where+ entity' = if nullFS entity+ then mkExtName (unLoc v)+ else entity+ funcTarget = CFunction (StaticTarget esrc entity' Nothing True)+ importSpec = CImport cconv safety Nothing funcTarget (L loc esrc)++ returnSpec spec = return $ ForD $ ForeignImport+ { fd_name = v+ , fd_sig_ty = ty+ , fd_co = noForeignImportCoercionYet+ , fd_fi = spec+ }++++-- the string "foo" is ambiguous: either a header or a C identifier. The+-- C identifier case comes first in the alternatives below, so we pick+-- that one.+parseCImport :: Located CCallConv -> Located Safety -> FastString -> String+ -> Located SourceText+ -> Maybe ForeignImport+parseCImport cconv safety nm str sourceText =+ listToMaybe $ map fst $ filter (null.snd) $+ readP_to_S parse str+ where+ parse = do+ skipSpaces+ r <- choice [+ string "dynamic" >> return (mk Nothing (CFunction DynamicTarget)),+ string "wrapper" >> return (mk Nothing CWrapper),+ do optional (token "static" >> skipSpaces)+ ((mk Nothing <$> cimp nm) ++++ (do h <- munch1 hdr_char+ skipSpaces+ mk (Just (Header (SourceText h) (mkFastString h)))+ <$> cimp nm))+ ]+ skipSpaces+ return r++ token str = do _ <- string str+ toks <- look+ case toks of+ c : _+ | id_char c -> pfail+ _ -> return ()++ mk h n = CImport cconv safety h n sourceText++ hdr_char c = not (isSpace c) -- header files are filenames, which can contain+ -- pretty much any char (depending on the platform),+ -- so just accept any non-space character+ id_first_char c = isAlpha c || c == '_'+ id_char c = isAlphaNum c || c == '_'++ cimp nm = (ReadP.char '&' >> skipSpaces >> CLabel <$> cid)+ +++ (do isFun <- case cconv of+ L _ CApiConv ->+ option True+ (do token "value"+ skipSpaces+ return False)+ _ -> return True+ cid' <- cid+ return (CFunction (StaticTarget NoSourceText cid'+ Nothing isFun)))+ where+ cid = return nm ++++ (do c <- satisfy id_first_char+ cs <- many (satisfy id_char)+ return (mkFastString (c:cs)))+++-- construct a foreign export declaration+--+mkExport :: Located CCallConv+ -> (Located StringLiteral, Located RdrName, LHsSigType RdrName)+ -> P (HsDecl RdrName)+mkExport (L lc cconv) (L le (StringLiteral esrc entity), v, ty)+ = return $ ForD $+ ForeignExport { fd_name = v, fd_sig_ty = ty+ , fd_co = noForeignExportCoercionYet+ , fd_fe = CExport (L lc (CExportStatic esrc entity' cconv))+ (L le esrc) }+ where+ entity' | nullFS entity = mkExtName (unLoc v)+ | otherwise = entity++-- Supplying the ext_name in a foreign decl is optional; if it+-- isn't there, the Haskell name is assumed. Note that no transformation+-- of the Haskell name is then performed, so if you foreign export (++),+-- it's external name will be "++". Too bad; it's important because we don't+-- want z-encoding (e.g. names with z's in them shouldn't be doubled)+--+mkExtName :: RdrName -> CLabelString+mkExtName rdrNm = mkFastString (occNameString (rdrNameOcc rdrNm))++--------------------------------------------------------------------------------+-- Help with module system imports/exports++data ImpExpSubSpec = ImpExpAbs+ | ImpExpAll+ | ImpExpList [Located ImpExpQcSpec]+ | ImpExpAllWith [Located ImpExpQcSpec]++data ImpExpQcSpec = ImpExpQcName (Located RdrName)+ | ImpExpQcType (Located RdrName)+ | ImpExpQcWildcard++mkModuleImpExp :: Located ImpExpQcSpec -> ImpExpSubSpec -> P (IE RdrName)+mkModuleImpExp (L l specname) subs =+ case subs of+ ImpExpAbs+ | isVarNameSpace (rdrNameSpace name)+ -> return $ IEVar (L l (ieNameFromSpec specname))+ | otherwise -> IEThingAbs . L l <$> nameT+ ImpExpAll -> IEThingAll . L l <$> nameT+ ImpExpList xs ->+ (\newName -> IEThingWith (L l newName) NoIEWildcard (wrapped xs) [])+ <$> nameT+ ImpExpAllWith xs ->+ do allowed <- extension patternSynonymsEnabled+ if allowed+ then+ let withs = map unLoc xs+ pos = maybe NoIEWildcard IEWildcard+ (findIndex isImpExpQcWildcard withs)+ ies = wrapped $ filter (not . isImpExpQcWildcard . unLoc) xs+ in (\newName -> IEThingWith (L l newName) pos ies []) <$> nameT+ else parseErrorSDoc l+ (text "Illegal export form (use PatternSynonyms to enable)")+ where+ name = ieNameVal specname+ nameT =+ if isVarNameSpace (rdrNameSpace name)+ then parseErrorSDoc l+ (text "Expecting a type constructor but found a variable,"+ <+> quotes (ppr name) <> text "."+ $$ if isSymOcc $ rdrNameOcc name+ then text "If" <+> quotes (ppr name) <+> text "is a type constructor"+ <+> text "then enable ExplicitNamespaces and use the 'type' keyword."+ else empty)+ else return $ ieNameFromSpec specname++ ieNameVal (ImpExpQcName ln) = unLoc ln+ ieNameVal (ImpExpQcType ln) = unLoc ln+ ieNameVal (ImpExpQcWildcard) = panic "ieNameVal got wildcard"++ ieNameFromSpec (ImpExpQcName ln) = IEName ln+ ieNameFromSpec (ImpExpQcType ln) = IEType ln+ ieNameFromSpec (ImpExpQcWildcard) = panic "ieName got wildcard"++ wrapped = map (\(L l x) -> L l (ieNameFromSpec x))++mkTypeImpExp :: Located RdrName -- TcCls or Var name space+ -> P (Located RdrName)+mkTypeImpExp name =+ do allowed <- extension explicitNamespacesEnabled+ if allowed+ then return (fmap (`setRdrNameSpace` tcClsName) name)+ else parseErrorSDoc (getLoc name)+ (text "Illegal keyword 'type' (use ExplicitNamespaces to enable)")++checkImportSpec :: Located [LIE RdrName] -> P (Located [LIE RdrName])+checkImportSpec ie@(L _ specs) =+ case [l | (L l (IEThingWith _ (IEWildcard _) _ _)) <- specs] of+ [] -> return ie+ (l:_) -> importSpecError l+ where+ importSpecError l =+ parseErrorSDoc l+ (text "Illegal import form, this syntax can only be used to bundle"+ $+$ text "pattern synonyms with types in module exports.")++-- In the correct order+mkImpExpSubSpec :: [Located ImpExpQcSpec] -> P ([AddAnn], ImpExpSubSpec)+mkImpExpSubSpec [] = return ([], ImpExpList [])+mkImpExpSubSpec [L _ ImpExpQcWildcard] =+ return ([], ImpExpAll)+mkImpExpSubSpec xs =+ if (any (isImpExpQcWildcard . unLoc) xs)+ then return $ ([], ImpExpAllWith xs)+ else return $ ([], ImpExpList xs)++isImpExpQcWildcard :: ImpExpQcSpec -> Bool+isImpExpQcWildcard ImpExpQcWildcard = True+isImpExpQcWildcard _ = False++-----------------------------------------------------------------------------+-- Misc utils++parseErrorSDoc :: SrcSpan -> SDoc -> P a+parseErrorSDoc span s = failSpanMsgP span s++data SumOrTuple+ = Sum ConTag Arity (LHsExpr RdrName)+ | Tuple [LHsTupArg RdrName]++mkSumOrTuple :: Boxity -> SrcSpan -> SumOrTuple -> P (HsExpr RdrName)++-- Tuple+mkSumOrTuple boxity _ (Tuple es) = return (ExplicitTuple es boxity)++-- Sum+mkSumOrTuple Unboxed _ (Sum alt arity e) =+ return (ExplicitSum alt arity e PlaceHolder)+mkSumOrTuple Boxed l (Sum alt arity (L _ e)) =+ parseErrorSDoc l (hang (text "Boxed sums not supported:") 2 (ppr_boxed_sum alt arity e))+ where+ ppr_boxed_sum :: ConTag -> Arity -> HsExpr RdrName -> SDoc+ ppr_boxed_sum alt arity e =+ text "(" <+> ppr_bars (alt - 1) <+> ppr e <+> ppr_bars (arity - alt) <+> text ")"++ ppr_bars n = hsep (replicate n (Outputable.char '|'))
+ parser/cutils.c view
@@ -0,0 +1,47 @@+/*+These utility routines are used various+places in the GHC library.+*/++#include "Rts.h"++#include "HsFFI.h"++#include <string.h>++#ifdef HAVE_UNISTD_H+#include <unistd.h>+#endif++/*+Calling 'strlen' and 'memcpy' directly gives problems with GCC's inliner,+and causes gcc to require too many registers on x84+*/++HsInt+ghc_strlen( HsPtr a )+{+ return (strlen((char *)a));+}++HsInt+ghc_memcmp( HsPtr a1, HsPtr a2, HsInt len )+{+ return (memcmp((char *)a1, a2, len));+}++void+enableTimingStats( void ) /* called from the driver */+{+ RtsFlags.GcFlags.giveStats = ONELINE_GC_STATS;+}++void+setHeapSize( HsInt size )+{+ RtsFlags.GcFlags.heapSizeSuggestion = size / BLOCK_SIZE;+ if (RtsFlags.GcFlags.maxHeapSize != 0 &&+ RtsFlags.GcFlags.heapSizeSuggestion > RtsFlags.GcFlags.maxHeapSize) {+ RtsFlags.GcFlags.maxHeapSize = RtsFlags.GcFlags.heapSizeSuggestion;+ }+}
+ parser/cutils.h view
@@ -0,0 +1,15 @@+/* -----------------------------------------------------------------------------+ *+ * Utility C functions.+ *+ * -------------------------------------------------------------------------- */++#include "HsFFI.h"++// Out-of-line string functions, see compiler/utils/FastString.hs+HsInt ghc_strlen( HsAddr a );+HsInt ghc_memcmp( HsAddr a1, HsAddr a2, HsInt len );+++void enableTimingStats( void );+void setHeapSize( HsInt size );
+ prelude/ForeignCall.hs view
@@ -0,0 +1,346 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[Foreign]{Foreign calls}+-}++{-# LANGUAGE DeriveDataTypeable #-}++module ForeignCall (+ ForeignCall(..), isSafeForeignCall,+ Safety(..), playSafe, playInterruptible,++ CExportSpec(..), CLabelString, isCLabelString, pprCLabelString,+ CCallSpec(..),+ CCallTarget(..), isDynamicTarget,+ CCallConv(..), defaultCCallConv, ccallConvToInt, ccallConvAttribute,++ Header(..), CType(..),+ ) where++import FastString+import Binary+import Outputable+import Module+import BasicTypes ( SourceText, pprWithSourceText )++import Data.Char+import Data.Data++{-+************************************************************************+* *+\subsubsection{Data types}+* *+************************************************************************+-}++newtype ForeignCall = CCall CCallSpec+ deriving Eq++isSafeForeignCall :: ForeignCall -> Bool+isSafeForeignCall (CCall (CCallSpec _ _ safe)) = playSafe safe++-- We may need more clues to distinguish foreign calls+-- but this simple printer will do for now+instance Outputable ForeignCall where+ ppr (CCall cc) = ppr cc++data Safety+ = PlaySafe -- Might invoke Haskell GC, or do a call back, or+ -- switch threads, etc. So make sure things are+ -- tidy before the call. Additionally, in the threaded+ -- RTS we arrange for the external call to be executed+ -- by a separate OS thread, i.e., _concurrently_ to the+ -- execution of other Haskell threads.++ | PlayInterruptible -- Like PlaySafe, but additionally+ -- the worker thread running this foreign call may+ -- be unceremoniously killed, so it must be scheduled+ -- on an unbound thread.++ | PlayRisky -- None of the above can happen; the call will return+ -- without interacting with the runtime system at all+ deriving ( Eq, Show, Data )+ -- Show used just for Show Lex.Token, I think++instance Outputable Safety where+ ppr PlaySafe = text "safe"+ ppr PlayInterruptible = text "interruptible"+ ppr PlayRisky = text "unsafe"++playSafe :: Safety -> Bool+playSafe PlaySafe = True+playSafe PlayInterruptible = True+playSafe PlayRisky = False++playInterruptible :: Safety -> Bool+playInterruptible PlayInterruptible = True+playInterruptible _ = False++{-+************************************************************************+* *+\subsubsection{Calling C}+* *+************************************************************************+-}++data CExportSpec+ = CExportStatic -- foreign export ccall foo :: ty+ SourceText -- of the CLabelString.+ -- See note [Pragma source text] in BasicTypes+ CLabelString -- C Name of exported function+ CCallConv+ deriving Data++data CCallSpec+ = CCallSpec CCallTarget -- What to call+ CCallConv -- Calling convention to use.+ Safety+ deriving( Eq )++-- The call target:++-- | How to call a particular function in C-land.+data CCallTarget+ -- An "unboxed" ccall# to named function in a particular package.+ = StaticTarget+ SourceText -- of the CLabelString.+ -- See note [Pragma source text] in BasicTypes+ CLabelString -- C-land name of label.++ (Maybe UnitId) -- What package the function is in.+ -- If Nothing, then it's taken to be in the current package.+ -- Note: This information is only used for PrimCalls on Windows.+ -- See CLabel.labelDynamic and CoreToStg.coreToStgApp+ -- for the difference in representation between PrimCalls+ -- and ForeignCalls. If the CCallTarget is representing+ -- a regular ForeignCall then it's safe to set this to Nothing.++ -- The first argument of the import is the name of a function pointer (an Addr#).+ -- Used when importing a label as "foreign import ccall "dynamic" ..."+ Bool -- True => really a function+ -- False => a value; only+ -- allowed in CAPI imports+ | DynamicTarget++ deriving( Eq, Data )++isDynamicTarget :: CCallTarget -> Bool+isDynamicTarget DynamicTarget = True+isDynamicTarget _ = False++{-+Stuff to do with calling convention:++ccall: Caller allocates parameters, *and* deallocates them.++stdcall: Caller allocates parameters, callee deallocates.+ Function name has @N after it, where N is number of arg bytes+ e.g. _Foo@8. This convention is x86 (win32) specific.++See: http://www.programmersheaven.com/2/Calling-conventions+-}++-- any changes here should be replicated in the CallConv type in template haskell+data CCallConv = CCallConv | CApiConv | StdCallConv | PrimCallConv | JavaScriptCallConv+ deriving (Eq, Data)++instance Outputable CCallConv where+ ppr StdCallConv = text "stdcall"+ ppr CCallConv = text "ccall"+ ppr CApiConv = text "capi"+ ppr PrimCallConv = text "prim"+ ppr JavaScriptCallConv = text "javascript"++defaultCCallConv :: CCallConv+defaultCCallConv = CCallConv++ccallConvToInt :: CCallConv -> Int+ccallConvToInt StdCallConv = 0+ccallConvToInt CCallConv = 1+ccallConvToInt CApiConv = panic "ccallConvToInt CApiConv"+ccallConvToInt (PrimCallConv {}) = panic "ccallConvToInt PrimCallConv"+ccallConvToInt JavaScriptCallConv = panic "ccallConvToInt JavaScriptCallConv"++{-+Generate the gcc attribute corresponding to the given+calling convention (used by PprAbsC):+-}++ccallConvAttribute :: CCallConv -> SDoc+ccallConvAttribute StdCallConv = text "__attribute__((__stdcall__))"+ccallConvAttribute CCallConv = empty+ccallConvAttribute CApiConv = empty+ccallConvAttribute (PrimCallConv {}) = panic "ccallConvAttribute PrimCallConv"+ccallConvAttribute JavaScriptCallConv = panic "ccallConvAttribute JavaScriptCallConv"++type CLabelString = FastString -- A C label, completely unencoded++pprCLabelString :: CLabelString -> SDoc+pprCLabelString lbl = ftext lbl++isCLabelString :: CLabelString -> Bool -- Checks to see if this is a valid C label+isCLabelString lbl+ = all ok (unpackFS lbl)+ where+ ok c = isAlphaNum c || c == '_' || c == '.'+ -- The '.' appears in e.g. "foo.so" in the+ -- module part of a ExtName. Maybe it should be separate++-- Printing into C files:++instance Outputable CExportSpec where+ ppr (CExportStatic _ str _) = pprCLabelString str++instance Outputable CCallSpec where+ ppr (CCallSpec fun cconv safety)+ = hcat [ ifPprDebug callconv, ppr_fun fun ]+ where+ callconv = text "{-" <> ppr cconv <> text "-}"++ gc_suf | playSafe safety = text "_GC"+ | otherwise = empty++ ppr_fun (StaticTarget st _fn mPkgId isFun)+ = text (if isFun then "__pkg_ccall"+ else "__pkg_ccall_value")+ <> gc_suf+ <+> (case mPkgId of+ Nothing -> empty+ Just pkgId -> ppr pkgId)+ <+> (pprWithSourceText st empty)++ ppr_fun DynamicTarget+ = text "__dyn_ccall" <> gc_suf <+> text "\"\""++-- The filename for a C header file+-- Note [Pragma source text] in BasicTypes+data Header = Header SourceText FastString+ deriving (Eq, Data)++instance Outputable Header where+ ppr (Header st h) = pprWithSourceText st (doubleQuotes $ ppr h)++-- | A C type, used in CAPI FFI calls+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnOpen' @'{-\# CTYPE'@,+-- 'ApiAnnotation.AnnHeader','ApiAnnotation.AnnVal',+-- 'ApiAnnotation.AnnClose' @'\#-}'@,++-- For details on above see note [Api annotations] in ApiAnnotation+data CType = CType SourceText -- Note [Pragma source text] in BasicTypes+ (Maybe Header) -- header to include for this type+ (SourceText,FastString) -- the type itself+ deriving (Eq, Data)++instance Outputable CType where+ ppr (CType stp mh (stct,ct))+ = pprWithSourceText stp (text "{-# CTYPE") <+> hDoc+ <+> pprWithSourceText stct (doubleQuotes (ftext ct)) <+> text "#-}"+ where hDoc = case mh of+ Nothing -> empty+ Just h -> ppr h++{-+************************************************************************+* *+\subsubsection{Misc}+* *+************************************************************************+-}++instance Binary ForeignCall where+ put_ bh (CCall aa) = put_ bh aa+ get bh = do aa <- get bh; return (CCall aa)++instance Binary Safety where+ put_ bh PlaySafe = do+ putByte bh 0+ put_ bh PlayInterruptible = do+ putByte bh 1+ put_ bh PlayRisky = do+ putByte bh 2+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return PlaySafe+ 1 -> do return PlayInterruptible+ _ -> do return PlayRisky++instance Binary CExportSpec where+ put_ bh (CExportStatic ss aa ab) = do+ put_ bh ss+ put_ bh aa+ put_ bh ab+ get bh = do+ ss <- get bh+ aa <- get bh+ ab <- get bh+ return (CExportStatic ss aa ab)++instance Binary CCallSpec where+ put_ bh (CCallSpec aa ab ac) = do+ put_ bh aa+ put_ bh ab+ put_ bh ac+ get bh = do+ aa <- get bh+ ab <- get bh+ ac <- get bh+ return (CCallSpec aa ab ac)++instance Binary CCallTarget where+ put_ bh (StaticTarget ss aa ab ac) = do+ putByte bh 0+ put_ bh ss+ put_ bh aa+ put_ bh ab+ put_ bh ac+ put_ bh DynamicTarget = do+ putByte bh 1+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do ss <- get bh+ aa <- get bh+ ab <- get bh+ ac <- get bh+ return (StaticTarget ss aa ab ac)+ _ -> do return DynamicTarget++instance Binary CCallConv where+ put_ bh CCallConv = do+ putByte bh 0+ put_ bh StdCallConv = do+ putByte bh 1+ put_ bh PrimCallConv = do+ putByte bh 2+ put_ bh CApiConv = do+ putByte bh 3+ put_ bh JavaScriptCallConv = do+ putByte bh 4+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return CCallConv+ 1 -> do return StdCallConv+ 2 -> do return PrimCallConv+ 3 -> do return CApiConv+ _ -> do return JavaScriptCallConv++instance Binary CType where+ put_ bh (CType s mh fs) = do put_ bh s+ put_ bh mh+ put_ bh fs+ get bh = do s <- get bh+ mh <- get bh+ fs <- get bh+ return (CType s mh fs)++instance Binary Header where+ put_ bh (Header s h) = put_ bh s >> put_ bh h+ get bh = do s <- get bh+ h <- get bh+ return (Header s h)
+ prelude/KnownUniques.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE CPP #-}++-- | This is where we define a mapping from Uniques to their associated+-- known-key Names for things associated with tuples and sums. We use this+-- mapping while deserializing known-key Names in interface file symbol tables,+-- which are encoded as their Unique. See Note [Symbol table representation of+-- names] for details.+--++module KnownUniques+ ( -- * Looking up known-key names+ knownUniqueName++ -- * Getting the 'Unique's of 'Name's+ -- ** Anonymous sums+ , mkSumTyConUnique+ , mkSumDataConUnique+ -- ** Tuples+ -- *** Vanilla+ , mkTupleTyConUnique+ , mkTupleDataConUnique+ -- *** Constraint+ , mkCTupleTyConUnique+ , mkCTupleDataConUnique+ ) where++#include "HsVersions.h"++import TysWiredIn+import TyCon+import DataCon+import Id+import BasicTypes+import Outputable+import Unique+import Name+import Util++import Data.Bits+import Data.Maybe++-- | Get the 'Name' associated with a known-key 'Unique'.+knownUniqueName :: Unique -> Maybe Name+knownUniqueName u =+ case tag of+ 'z' -> Just $ getUnboxedSumName n+ '4' -> Just $ getTupleTyConName Boxed n+ '5' -> Just $ getTupleTyConName Unboxed n+ '7' -> Just $ getTupleDataConName Boxed n+ '8' -> Just $ getTupleDataConName Unboxed n+ 'k' -> Just $ getCTupleTyConName n+ 'm' -> Just $ getCTupleDataConUnique n+ _ -> Nothing+ where+ (tag, n) = unpkUnique u++--------------------------------------------------+-- Anonymous sums+--+-- Sum arities start from 2. The encoding is a bit funny: we break up the+-- integral part into bitfields for the arity, an alternative index (which is+-- taken to be 0xff in the case of the TyCon), and, in the case of a datacon, a+-- tag (used to identify the sum's TypeRep binding).+--+-- This layout is chosen to remain compatible with the usual unique allocation+-- for wired-in data constructors described in Unique.hs+--+-- TyCon for sum of arity k:+-- 00000000 kkkkkkkk 11111100++-- TypeRep of TyCon for sum of arity k:+-- 00000000 kkkkkkkk 11111101+--+-- DataCon for sum of arity k and alternative n (zero-based):+-- 00000000 kkkkkkkk nnnnnn00+--+-- TypeRep for sum DataCon of arity k and alternative n (zero-based):+-- 00000000 kkkkkkkk nnnnnn10++mkSumTyConUnique :: Arity -> Unique+mkSumTyConUnique arity =+ ASSERT(arity < 0xff)+ mkUnique 'z' (arity `shiftL` 8 .|. 0xfc)++mkSumDataConUnique :: ConTagZ -> Arity -> Unique+mkSumDataConUnique alt arity+ | alt >= arity+ = panic ("mkSumDataConUnique: " ++ show alt ++ " >= " ++ show arity)+ | otherwise+ = mkUnique 'z' (arity `shiftL` 8 + alt `shiftL` 2) {- skip the tycon -}++getUnboxedSumName :: Int -> Name+getUnboxedSumName n+ | n .&. 0xfc == 0xfc+ = case tag of+ 0x0 -> tyConName $ sumTyCon arity+ 0x1 -> getRep $ sumTyCon arity+ _ -> pprPanic "getUnboxedSumName: invalid tag" (ppr tag)+ | tag == 0x0+ = dataConName $ sumDataCon (alt + 1) arity+ | tag == 0x2+ = getRep $ promoteDataCon $ sumDataCon (alt + 1) arity+ | otherwise+ = pprPanic "getUnboxedSumName" (ppr n)+ where+ arity = n `shiftR` 8+ alt = (n .&. 0xff) `shiftR` 2+ tag = 0x3 .&. n+ getRep tycon =+ fromMaybe (pprPanic "getUnboxedSumName" (ppr tycon))+ $ tyConRepName_maybe tycon++-- Note [Uniques for tuple type and data constructors]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Wired-in type constructor keys occupy *two* slots:+-- * u: the TyCon itself+-- * u+1: the TyConRepName of the TyCon+--+-- Wired-in tuple data constructor keys occupy *three* slots:+-- * u: the DataCon itself+-- * u+1: its worker Id+-- * u+2: the TyConRepName of the promoted TyCon++--------------------------------------------------+-- Constraint tuples++mkCTupleTyConUnique :: Arity -> Unique+mkCTupleTyConUnique a = mkUnique 'k' (2*a)++mkCTupleDataConUnique :: Arity -> Unique+mkCTupleDataConUnique a = mkUnique 'm' (3*a)++getCTupleTyConName :: Int -> Name+getCTupleTyConName n =+ case n `divMod` 2 of+ (arity, 0) -> cTupleTyConName arity+ (arity, 1) -> mkPrelTyConRepName $ cTupleTyConName arity+ _ -> panic "getCTupleTyConName: impossible"++getCTupleDataConUnique :: Int -> Name+getCTupleDataConUnique n =+ case n `divMod` 3 of+ (arity, 0) -> cTupleDataConName arity+ (_arity, 1) -> panic "getCTupleDataConName: no worker"+ (arity, 2) -> mkPrelTyConRepName $ cTupleDataConName arity+ _ -> panic "getCTupleDataConName: impossible"++--------------------------------------------------+-- Normal tuples++mkTupleDataConUnique :: Boxity -> Arity -> Unique+mkTupleDataConUnique Boxed a = mkUnique '7' (3*a) -- may be used in C labels+mkTupleDataConUnique Unboxed a = mkUnique '8' (3*a)++mkTupleTyConUnique :: Boxity -> Arity -> Unique+mkTupleTyConUnique Boxed a = mkUnique '4' (2*a)+mkTupleTyConUnique Unboxed a = mkUnique '5' (2*a)++getTupleTyConName :: Boxity -> Int -> Name+getTupleTyConName boxity n =+ case n `divMod` 2 of+ (arity, 0) -> tyConName $ tupleTyCon boxity arity+ (arity, 1) -> fromMaybe (panic "getTupleTyConName")+ $ tyConRepName_maybe $ tupleTyCon boxity arity+ _ -> panic "getTupleTyConName: impossible"++getTupleDataConName :: Boxity -> Int -> Name+getTupleDataConName boxity n =+ case n `divMod` 3 of+ (arity, 0) -> dataConName $ tupleDataCon boxity arity+ (arity, 1) -> idName $ dataConWorkId $ tupleDataCon boxity arity+ (arity, 2) -> fromMaybe (panic "getTupleDataCon")+ $ tyConRepName_maybe $ promotedTupleDataCon boxity arity+ _ -> panic "getTupleDataConName: impossible"
+ prelude/KnownUniques.hs-boot view
@@ -0,0 +1,17 @@+module KnownUniques where++import Unique+import Name+import BasicTypes++-- Needed by TysWiredIn+knownUniqueName :: Unique -> Maybe Name++mkSumTyConUnique :: Arity -> Unique+mkSumDataConUnique :: ConTagZ -> Arity -> Unique++mkCTupleTyConUnique :: Arity -> Unique+mkCTupleDataConUnique :: Arity -> Unique++mkTupleTyConUnique :: Boxity -> Arity -> Unique+mkTupleDataConUnique :: Boxity -> Arity -> Unique
+ prelude/PrelInfo.hs view
@@ -0,0 +1,266 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++-}++{-# LANGUAGE CPP #-}++-- | The @PrelInfo@ interface to the compiler's prelude knowledge.+--+-- This module serves as the central gathering point for names which the+-- compiler knows something about. This includes functions for,+--+-- * discerning whether a 'Name' is known-key+--+-- * given a 'Unique', looking up its corresponding known-key 'Name'+--+-- See Note [Known-key names] and Note [About wired-in things] for information+-- about the two types of prelude things in GHC.+--+module PrelInfo (+ -- * Known-key names+ isKnownKeyName,+ lookupKnownKeyName,++ -- ** Internal use+ -- | 'knownKeyNames' is exported to seed the original name cache only;+ -- if you find yourself wanting to look at it you might consider using+ -- 'lookupKnownKeyName' or 'isKnownKeyName'.+ knownKeyNames,++ -- * Miscellaneous+ wiredInIds, ghcPrimIds,+ primOpRules, builtinRules,++ ghcPrimExports,+ primOpId,++ -- * Random other things+ maybeCharLikeCon, maybeIntLikeCon,++ -- * Class categories+ isNumericClass, isStandardClass++ ) where++#include "HsVersions.h"++import KnownUniques+import Unique ( isValidKnownKeyUnique )++import ConLike ( ConLike(..) )+import THNames ( templateHaskellNames )+import PrelNames+import PrelRules+import Avail+import PrimOp+import DataCon+import Id+import Name+import NameEnv+import MkId+import TysPrim+import TysWiredIn+import HscTypes+import Class+import TyCon+import UniqFM+import Util+import Panic+import {-# SOURCE #-} TcTypeNats ( typeNatTyCons )++import Control.Applicative ((<|>))+import Data.List ( intercalate )+import Data.Array+import Data.Maybe++{-+************************************************************************+* *+\subsection[builtinNameInfo]{Lookup built-in names}+* *+************************************************************************++Note [About wired-in things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Wired-in things are Ids\/TyCons that are completely known to the compiler.+ They are global values in GHC, (e.g. listTyCon :: TyCon).++* A wired in Name contains the thing itself inside the Name:+ see Name.wiredInNameTyThing_maybe+ (E.g. listTyConName contains listTyCon.++* The name cache is initialised with (the names of) all wired-in things+ (except tuples and sums; see Note [Known-])++* The type environment itself contains no wired in things. The type+ checker sees if the Name is wired in before looking up the name in+ the type environment.++* MkIface prunes out wired-in things before putting them in an interface file.+ So interface files never contain wired-in things.+-}+++-- | This list is used to ensure that when you say "Prelude.map" in your source+-- code, or in an interface file, you get a Name with the correct known key (See+-- Note [Known-key names] in PrelNames)+knownKeyNames :: [Name]+knownKeyNames+ | debugIsOn+ , Just badNamesStr <- knownKeyNamesOkay all_names+ = panic ("badAllKnownKeyNames:\n" ++ badNamesStr)+ -- NB: We can't use ppr here, because this is sometimes evaluated in a+ -- context where there are no DynFlags available, leading to a cryptic+ -- "<<details unavailable>>" error. (This seems to happen only in the+ -- stage 2 compiler, for reasons I [Richard] have no clue of.)+ | otherwise+ = all_names+ where+ all_names =+ concat [ wired_tycon_kk_names funTyCon+ , concatMap wired_tycon_kk_names primTyCons++ , concatMap wired_tycon_kk_names wiredInTyCons+ -- Does not include tuples++ , concatMap wired_tycon_kk_names typeNatTyCons++ , map idName wiredInIds+ , map (idName . primOpId) allThePrimOps+ , basicKnownKeyNames+ , templateHaskellNames+ ]+ -- All of the names associated with a wired-in TyCon.+ -- This includes the TyCon itself, its DataCons and promoted TyCons.+ wired_tycon_kk_names :: TyCon -> [Name]+ wired_tycon_kk_names tc =+ tyConName tc : (rep_names tc ++ implicits)+ where implicits = concatMap thing_kk_names (implicitTyConThings tc)++ wired_datacon_kk_names :: DataCon -> [Name]+ wired_datacon_kk_names dc =+ dataConName dc : rep_names (promoteDataCon dc)++ thing_kk_names :: TyThing -> [Name]+ thing_kk_names (ATyCon tc) = wired_tycon_kk_names tc+ thing_kk_names (AConLike (RealDataCon dc)) = wired_datacon_kk_names dc+ thing_kk_names thing = [getName thing]++ -- The TyConRepName for a known-key TyCon has a known key,+ -- but isn't itself an implicit thing. Yurgh.+ -- NB: if any of the wired-in TyCons had record fields, the record+ -- field names would be in a similar situation. Ditto class ops.+ -- But it happens that there aren't any+ rep_names tc = case tyConRepName_maybe tc of+ Just n -> [n]+ Nothing -> []++-- | Check the known-key names list of consistency.+knownKeyNamesOkay :: [Name] -> Maybe String+knownKeyNamesOkay all_names+ | ns@(_:_) <- filter (not . isValidKnownKeyUnique . getUnique) all_names+ = Just $ " Out-of-range known-key uniques: ["+ ++ intercalate ", " (map (occNameString . nameOccName) ns) +++ "]"+ | null badNamesPairs+ = Nothing+ | otherwise+ = Just badNamesStr+ where+ namesEnv = foldl (\m n -> extendNameEnv_Acc (:) singleton m n n)+ emptyUFM all_names+ badNamesEnv = filterNameEnv (\ns -> length ns > 1) namesEnv+ badNamesPairs = nonDetUFMToList badNamesEnv+ -- It's OK to use nonDetUFMToList here because the ordering only affects+ -- the message when we get a panic+ badNamesStrs = map pairToStr badNamesPairs+ badNamesStr = unlines badNamesStrs++ pairToStr (uniq, ns) = " " +++ show uniq +++ ": [" +++ intercalate ", " (map (occNameString . nameOccName) ns) +++ "]"++-- | Given a 'Unique' lookup its associated 'Name' if it corresponds to a+-- known-key thing.+lookupKnownKeyName :: Unique -> Maybe Name+lookupKnownKeyName u =+ knownUniqueName u <|> lookupUFM knownKeysMap u++-- | Is a 'Name' known-key?+isKnownKeyName :: Name -> Bool+isKnownKeyName n =+ isJust (knownUniqueName $ nameUnique n) || elemUFM n knownKeysMap++knownKeysMap :: UniqFM Name+knownKeysMap = listToUFM [ (nameUnique n, n) | n <- knownKeyNames ]++{-+We let a lot of "non-standard" values be visible, so that we can make+sense of them in interface pragmas. It's cool, though they all have+"non-standard" names, so they won't get past the parser in user code.++************************************************************************+* *+ PrimOpIds+* *+************************************************************************+-}++primOpIds :: Array Int Id+-- A cache of the PrimOp Ids, indexed by PrimOp tag+primOpIds = array (1,maxPrimOpTag) [ (primOpTag op, mkPrimOpId op)+ | op <- allThePrimOps ]++primOpId :: PrimOp -> Id+primOpId op = primOpIds ! primOpTag op++{-+************************************************************************+* *+ Export lists for pseudo-modules (GHC.Prim)+* *+************************************************************************++GHC.Prim "exports" all the primops and primitive types, some+wired-in Ids.+-}++ghcPrimExports :: [IfaceExport]+ghcPrimExports+ = map (avail . idName) ghcPrimIds +++ map (avail . idName . primOpId) allThePrimOps +++ [ AvailTC n [n] []+ | tc <- funTyCon : primTyCons, let n = tyConName tc ]++{-+************************************************************************+* *+ Built-in keys+* *+************************************************************************++ToDo: make it do the ``like'' part properly (as in 0.26 and before).+-}++maybeCharLikeCon, maybeIntLikeCon :: DataCon -> Bool+maybeCharLikeCon con = con `hasKey` charDataConKey+maybeIntLikeCon con = con `hasKey` intDataConKey++{-+************************************************************************+* *+ Class predicates+* *+************************************************************************+-}++isNumericClass, isStandardClass :: Class -> Bool++isNumericClass clas = classKey clas `is_elem` numericClassKeys+isStandardClass clas = classKey clas `is_elem` standardClassKeys++is_elem :: Eq a => a -> [a] -> Bool+is_elem = isIn "is_X_Class"
+ prelude/PrelNames.hs view
@@ -0,0 +1,2457 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[PrelNames]{Definitions of prelude modules and names}+++Nota Bene: all Names defined in here should come from the base package++ - ModuleNames for prelude modules,+ e.g. pREL_BASE_Name :: ModuleName++ - Modules for prelude modules+ e.g. pREL_Base :: Module++ - Uniques for Ids, DataCons, TyCons and Classes that the compiler+ "knows about" in some way+ e.g. intTyConKey :: Unique+ minusClassOpKey :: Unique++ - Names for Ids, DataCons, TyCons and Classes that the compiler+ "knows about" in some way+ e.g. intTyConName :: Name+ minusName :: Name+ One of these Names contains+ (a) the module and occurrence name of the thing+ (b) its Unique+ The may way the compiler "knows about" one of these things is+ where the type checker or desugarer needs to look it up. For+ example, when desugaring list comprehensions the desugarer+ needs to conjure up 'foldr'. It does this by looking up+ foldrName in the environment.++ - RdrNames for Ids, DataCons etc that the compiler may emit into+ generated code (e.g. for deriving). It's not necessary to know+ the uniques for these guys, only their names+++Note [Known-key names]+~~~~~~~~~~~~~~~~~~~~~~+It is *very* important that the compiler gives wired-in things and+things with "known-key" names the correct Uniques wherever they+occur. We have to be careful about this in exactly two places:++ 1. When we parse some source code, renaming the AST better yield an+ AST whose Names have the correct uniques++ 2. When we read an interface file, the read-in gubbins better have+ the right uniques++This is accomplished through a combination of mechanisms:++ 1. When parsing source code, the RdrName-decorated AST has some+ RdrNames which are Exact. These are wired-in RdrNames where the+ we could directly tell from the parsed syntax what Name to+ use. For example, when we parse a [] in a type we can just insert+ an Exact RdrName Name with the listTyConKey.++ Currently, I believe this is just an optimisation: it would be+ equally valid to just output Orig RdrNames that correctly record+ the module etc we expect the final Name to come from. However,+ were we to eliminate isBuiltInOcc_maybe it would become essential+ (see point 3).++ 2. The knownKeyNames (which consist of the basicKnownKeyNames from+ the module, and those names reachable via the wired-in stuff from+ TysWiredIn) are used to initialise the "OrigNameCache" in+ IfaceEnv. This initialization ensures that when the type checker+ or renamer (both of which use IfaceEnv) look up an original name+ (i.e. a pair of a Module and an OccName) for a known-key name+ they get the correct Unique.++ This is the most important mechanism for ensuring that known-key+ stuff gets the right Unique, and is why it is so important to+ place your known-key names in the appropriate lists.++ 3. For "infinite families" of known-key names (i.e. tuples and sums), we+ have to be extra careful. Because there are an infinite number of+ these things, we cannot add them to the list of known-key names+ used to initialise the OrigNameCache. Instead, we have to+ rely on never having to look them up in that cache. See+ Note [Infinite families of known-key names] for details.+++Note [Infinite families of known-key names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Infinite families of known-key things (e.g. tuples and sums) pose a tricky+problem: we can't add them to the knownKeyNames finite map which we use to+ensure that, e.g., a reference to (,) gets assigned the right unique (if this+doesn't sound familiar see Note [Known-key names] above).++We instead handle tuples and sums separately from the "vanilla" known-key+things,++ a) The parser recognises them specially and generates an Exact Name (hence not+ looked up in the orig-name cache)++ b) The known infinite families of names are specially serialised by+ BinIface.putName, with that special treatment detected when we read back to+ ensure that we get back to the correct uniques. See Note [Symbol table+ representation of names] in BinIface and Note [How tuples work] in+ TysWiredIn.++Most of the infinite families cannot occur in source code, so mechanisms (a) and (b)+suffice to ensure that they always have the right Unique. In particular,+implicit param TyCon names, constraint tuples and Any TyCons cannot be mentioned+by the user. For those things that *can* appear in source programs,++ c) IfaceEnv.lookupOrigNameCache uses isBuiltInOcc_maybe to map built-in syntax+ directly onto the corresponding name, rather than trying to find it in the+ original-name cache.++ See also Note [Built-in syntax and the OrigNameCache]+-}++{-# LANGUAGE CPP #-}++module PrelNames (+ Unique, Uniquable(..), hasKey, -- Re-exported for convenience++ -----------------------------------------------------------+ module PrelNames, -- A huge bunch of (a) Names, e.g. intTyConName+ -- (b) Uniques e.g. intTyConKey+ -- (c) Groups of classes and types+ -- (d) miscellaneous things+ -- So many that we export them all+ ) where++#include "HsVersions.h"++import Module+import OccName+import RdrName+import Unique+import Name+import SrcLoc+import FastString+import Config ( cIntegerLibraryType, IntegerLibrary(..) )+import Panic ( panic )++{-+************************************************************************+* *+ allNameStrings+* *+************************************************************************+-}++allNameStrings :: [String]+-- Infinite list of a,b,c...z, aa, ab, ac, ... etc+allNameStrings = [ c:cs | cs <- "" : allNameStrings, c <- ['a'..'z'] ]++{-+************************************************************************+* *+\subsection{Local Names}+* *+************************************************************************++This *local* name is used by the interactive stuff+-}++itName :: Unique -> SrcSpan -> Name+itName uniq loc = mkInternalName uniq (mkOccNameFS varName (fsLit "it")) loc++-- mkUnboundName makes a place-holder Name; it shouldn't be looked at except possibly+-- during compiler debugging.+mkUnboundName :: OccName -> Name+mkUnboundName occ = mkInternalName unboundKey occ noSrcSpan++isUnboundName :: Name -> Bool+isUnboundName name = name `hasKey` unboundKey++{-+************************************************************************+* *+\subsection{Known key Names}+* *+************************************************************************++This section tells what the compiler knows about the association of+names with uniques. These ones are the *non* wired-in ones. The+wired in ones are defined in TysWiredIn etc.+-}++basicKnownKeyNames :: [Name]+basicKnownKeyNames+ = genericTyConNames+ ++ [ -- Classes. *Must* include:+ -- classes that are grabbed by key (e.g., eqClassKey)+ -- classes in "Class.standardClassKeys" (quite a few)+ eqClassName, -- mentioned, derivable+ ordClassName, -- derivable+ boundedClassName, -- derivable+ numClassName, -- mentioned, numeric+ enumClassName, -- derivable+ monadClassName,+ functorClassName,+ realClassName, -- numeric+ integralClassName, -- numeric+ fractionalClassName, -- numeric+ floatingClassName, -- numeric+ realFracClassName, -- numeric+ realFloatClassName, -- numeric+ dataClassName,+ isStringClassName,+ applicativeClassName,+ alternativeClassName,+ foldableClassName,+ traversableClassName,+ semigroupClassName, sappendName,+ monoidClassName, memptyName, mappendName, mconcatName,++ -- The IO type+ -- See Note [TyConRepNames for non-wired-in TyCons]+ ioTyConName, ioDataConName,+ runMainIOName,++ -- Type representation types+ trModuleTyConName, trModuleDataConName,+ trNameTyConName, trNameSDataConName, trNameDDataConName,+ trTyConTyConName, trTyConDataConName,++ -- Typeable+ typeableClassName,+ typeRepTyConName,+ someTypeRepTyConName,+ someTypeRepDataConName,+ kindRepTyConName,+ kindRepTyConAppDataConName,+ kindRepVarDataConName,+ kindRepAppDataConName,+ kindRepFunDataConName,+ kindRepTYPEDataConName,+ kindRepTypeLitSDataConName,+ kindRepTypeLitDDataConName,+ typeLitSortTyConName,+ typeLitSymbolDataConName,+ typeLitNatDataConName,+ typeRepIdName,+ mkTrConName,+ mkTrAppName,+ mkTrFunName,+ typeSymbolTypeRepName, typeNatTypeRepName,+ trGhcPrimModuleName,++ -- KindReps for common cases+ starKindRepName,+ starArrStarKindRepName,+ starArrStarArrStarKindRepName,++ -- Dynamic+ toDynName,++ -- Numeric stuff+ negateName, minusName, geName, eqName,++ -- Conversion functions+ rationalTyConName,+ ratioTyConName, ratioDataConName,+ fromRationalName, fromIntegerName,+ toIntegerName, toRationalName,+ fromIntegralName, realToFracName,++ -- Int# stuff+ divIntName, modIntName,++ -- String stuff+ fromStringName,++ -- Enum stuff+ enumFromName, enumFromThenName,+ enumFromThenToName, enumFromToName,++ -- Applicative stuff+ pureAName, apAName, thenAName,++ -- Functor stuff+ fmapName,++ -- Monad stuff+ thenIOName, bindIOName, returnIOName, failIOName, bindMName, thenMName,+ returnMName, joinMName,++ -- MonadFail+ monadFailClassName, failMName, failMName_preMFP,++ -- MonadFix+ monadFixClassName, mfixName,++ -- Arrow stuff+ arrAName, composeAName, firstAName,+ appAName, choiceAName, loopAName,++ -- Ix stuff+ ixClassName,++ -- Show stuff+ showClassName,++ -- Read stuff+ readClassName,++ -- Stable pointers+ newStablePtrName,++ -- GHC Extensions+ groupWithName,++ -- Strings and lists+ unpackCStringName,+ unpackCStringFoldrName, unpackCStringUtf8Name,++ -- Overloaded lists+ isListClassName,+ fromListName,+ fromListNName,+ toListName,++ -- List operations+ concatName, filterName, mapName,+ zipName, foldrName, buildName, augmentName, appendName,++ -- FFI primitive types that are not wired-in.+ stablePtrTyConName, ptrTyConName, funPtrTyConName,+ int8TyConName, int16TyConName, int32TyConName, int64TyConName,+ word16TyConName, word32TyConName, word64TyConName,++ -- Others+ otherwiseIdName, inlineIdName,+ eqStringName, assertName, breakpointName, breakpointCondName,+ breakpointAutoName, opaqueTyConName,+ assertErrorName,+ printName, fstName, sndName,++ -- Integer+ integerTyConName, mkIntegerName,+ integerToWord64Name, integerToInt64Name,+ word64ToIntegerName, int64ToIntegerName,+ plusIntegerName, timesIntegerName, smallIntegerName,+ wordToIntegerName,+ integerToWordName, integerToIntName, minusIntegerName,+ negateIntegerName, eqIntegerPrimName, neqIntegerPrimName,+ absIntegerName, signumIntegerName,+ leIntegerPrimName, gtIntegerPrimName, ltIntegerPrimName, geIntegerPrimName,+ compareIntegerName, quotRemIntegerName, divModIntegerName,+ quotIntegerName, remIntegerName, divIntegerName, modIntegerName,+ floatFromIntegerName, doubleFromIntegerName,+ encodeFloatIntegerName, encodeDoubleIntegerName,+ decodeDoubleIntegerName,+ gcdIntegerName, lcmIntegerName,+ andIntegerName, orIntegerName, xorIntegerName, complementIntegerName,+ shiftLIntegerName, shiftRIntegerName, bitIntegerName,++ -- Natural+ naturalTyConName,+ naturalFromIntegerName,++ -- Float/Double+ rationalToFloatName,+ rationalToDoubleName,++ -- Other classes+ randomClassName, randomGenClassName, monadPlusClassName,++ -- Type-level naturals+ knownNatClassName, knownSymbolClassName,++ -- Overloaded labels+ isLabelClassName,++ -- Implicit Parameters+ ipClassName,++ -- Overloaded record fields+ hasFieldClassName,++ -- Call Stacks+ callStackTyConName,+ emptyCallStackName, pushCallStackName,++ -- Source Locations+ srcLocDataConName,++ -- Annotation type checking+ toAnnotationWrapperName++ -- The Ordering type+ , orderingTyConName+ , ltDataConName, eqDataConName, gtDataConName++ -- The SPEC type for SpecConstr+ , specTyConName++ -- The Either type+ , eitherTyConName, leftDataConName, rightDataConName++ -- Plugins+ , pluginTyConName+ , frontendPluginTyConName++ -- Generics+ , genClassName, gen1ClassName+ , datatypeClassName, constructorClassName, selectorClassName++ -- Monad comprehensions+ , guardMName+ , liftMName+ , mzipName++ -- GHCi Sandbox+ , ghciIoClassName, ghciStepIoMName++ -- StaticPtr+ , makeStaticName+ , staticPtrTyConName+ , staticPtrDataConName, staticPtrInfoDataConName+ , fromStaticPtrName++ -- Fingerprint+ , fingerprintDataConName++ -- Custom type errors+ , errorMessageTypeErrorFamName+ , typeErrorTextDataConName+ , typeErrorAppendDataConName+ , typeErrorVAppendDataConName+ , typeErrorShowTypeDataConName++ -- homogeneous equality+ , eqTyConName++ ] ++ case cIntegerLibraryType of+ IntegerGMP -> [integerSDataConName]+ IntegerSimple -> []++genericTyConNames :: [Name]+genericTyConNames = [+ v1TyConName, u1TyConName, par1TyConName, rec1TyConName,+ k1TyConName, m1TyConName, sumTyConName, prodTyConName,+ compTyConName, rTyConName, dTyConName,+ cTyConName, sTyConName, rec0TyConName,+ d1TyConName, c1TyConName, s1TyConName, noSelTyConName,+ repTyConName, rep1TyConName, uRecTyConName,+ uAddrTyConName, uCharTyConName, uDoubleTyConName,+ uFloatTyConName, uIntTyConName, uWordTyConName,+ prefixIDataConName, infixIDataConName, leftAssociativeDataConName,+ rightAssociativeDataConName, notAssociativeDataConName,+ sourceUnpackDataConName, sourceNoUnpackDataConName,+ noSourceUnpackednessDataConName, sourceLazyDataConName,+ sourceStrictDataConName, noSourceStrictnessDataConName,+ decidedLazyDataConName, decidedStrictDataConName, decidedUnpackDataConName,+ metaDataDataConName, metaConsDataConName, metaSelDataConName+ ]++{-+************************************************************************+* *+\subsection{Module names}+* *+************************************************************************+++--MetaHaskell Extension Add a new module here+-}++pRELUDE :: Module+pRELUDE = mkBaseModule_ pRELUDE_NAME++gHC_PRIM, gHC_TYPES, gHC_GENERICS, gHC_MAGIC,+ gHC_CLASSES, gHC_BASE, gHC_ENUM, gHC_GHCI, gHC_CSTRING,+ gHC_SHOW, gHC_READ, gHC_NUM, gHC_INTEGER_TYPE, gHC_NATURAL, gHC_LIST,+ gHC_TUPLE, dATA_TUPLE, dATA_EITHER, dATA_STRING,+ dATA_FOLDABLE, dATA_TRAVERSABLE, dATA_MONOID, dATA_SEMIGROUP,+ gHC_CONC, gHC_IO, gHC_IO_Exception,+ gHC_ST, gHC_ARR, gHC_STABLE, gHC_PTR, gHC_ERR, gHC_REAL,+ gHC_FLOAT, gHC_TOP_HANDLER, sYSTEM_IO, dYNAMIC,+ tYPEABLE, tYPEABLE_INTERNAL, gENERICS,+ rEAD_PREC, lEX, gHC_INT, gHC_WORD, mONAD, mONAD_FIX, mONAD_ZIP, mONAD_FAIL,+ aRROW, cONTROL_APPLICATIVE, gHC_DESUGAR, rANDOM, gHC_EXTS,+ cONTROL_EXCEPTION_BASE, gHC_TYPELITS, gHC_TYPENATS, dATA_TYPE_EQUALITY,+ dATA_COERCE :: Module++gHC_PRIM = mkPrimModule (fsLit "GHC.Prim") -- Primitive types and values+gHC_TYPES = mkPrimModule (fsLit "GHC.Types")+gHC_MAGIC = mkPrimModule (fsLit "GHC.Magic")+gHC_CSTRING = mkPrimModule (fsLit "GHC.CString")+gHC_CLASSES = mkPrimModule (fsLit "GHC.Classes")++gHC_BASE = mkBaseModule (fsLit "GHC.Base")+gHC_ENUM = mkBaseModule (fsLit "GHC.Enum")+gHC_GHCI = mkBaseModule (fsLit "GHC.GHCi")+gHC_SHOW = mkBaseModule (fsLit "GHC.Show")+gHC_READ = mkBaseModule (fsLit "GHC.Read")+gHC_NUM = mkBaseModule (fsLit "GHC.Num")+gHC_INTEGER_TYPE= mkIntegerModule (fsLit "GHC.Integer.Type")+gHC_NATURAL = mkBaseModule (fsLit "GHC.Natural")+gHC_LIST = mkBaseModule (fsLit "GHC.List")+gHC_TUPLE = mkPrimModule (fsLit "GHC.Tuple")+dATA_TUPLE = mkBaseModule (fsLit "Data.Tuple")+dATA_EITHER = mkBaseModule (fsLit "Data.Either")+dATA_STRING = mkBaseModule (fsLit "Data.String")+dATA_FOLDABLE = mkBaseModule (fsLit "Data.Foldable")+dATA_TRAVERSABLE= mkBaseModule (fsLit "Data.Traversable")+dATA_SEMIGROUP = mkBaseModule (fsLit "Data.Semigroup")+dATA_MONOID = mkBaseModule (fsLit "Data.Monoid")+gHC_CONC = mkBaseModule (fsLit "GHC.Conc")+gHC_IO = mkBaseModule (fsLit "GHC.IO")+gHC_IO_Exception = mkBaseModule (fsLit "GHC.IO.Exception")+gHC_ST = mkBaseModule (fsLit "GHC.ST")+gHC_ARR = mkBaseModule (fsLit "GHC.Arr")+gHC_STABLE = mkBaseModule (fsLit "GHC.Stable")+gHC_PTR = mkBaseModule (fsLit "GHC.Ptr")+gHC_ERR = mkBaseModule (fsLit "GHC.Err")+gHC_REAL = mkBaseModule (fsLit "GHC.Real")+gHC_FLOAT = mkBaseModule (fsLit "GHC.Float")+gHC_TOP_HANDLER = mkBaseModule (fsLit "GHC.TopHandler")+sYSTEM_IO = mkBaseModule (fsLit "System.IO")+dYNAMIC = mkBaseModule (fsLit "Data.Dynamic")+tYPEABLE = mkBaseModule (fsLit "Data.Typeable")+tYPEABLE_INTERNAL = mkBaseModule (fsLit "Data.Typeable.Internal")+gENERICS = mkBaseModule (fsLit "Data.Data")+rEAD_PREC = mkBaseModule (fsLit "Text.ParserCombinators.ReadPrec")+lEX = mkBaseModule (fsLit "Text.Read.Lex")+gHC_INT = mkBaseModule (fsLit "GHC.Int")+gHC_WORD = mkBaseModule (fsLit "GHC.Word")+mONAD = mkBaseModule (fsLit "Control.Monad")+mONAD_FIX = mkBaseModule (fsLit "Control.Monad.Fix")+mONAD_ZIP = mkBaseModule (fsLit "Control.Monad.Zip")+mONAD_FAIL = mkBaseModule (fsLit "Control.Monad.Fail")+aRROW = mkBaseModule (fsLit "Control.Arrow")+cONTROL_APPLICATIVE = mkBaseModule (fsLit "Control.Applicative")+gHC_DESUGAR = mkBaseModule (fsLit "GHC.Desugar")+rANDOM = mkBaseModule (fsLit "System.Random")+gHC_EXTS = mkBaseModule (fsLit "GHC.Exts")+cONTROL_EXCEPTION_BASE = mkBaseModule (fsLit "Control.Exception.Base")+gHC_GENERICS = mkBaseModule (fsLit "GHC.Generics")+gHC_TYPELITS = mkBaseModule (fsLit "GHC.TypeLits")+gHC_TYPENATS = mkBaseModule (fsLit "GHC.TypeNats")+dATA_TYPE_EQUALITY = mkBaseModule (fsLit "Data.Type.Equality")+dATA_COERCE = mkBaseModule (fsLit "Data.Coerce")++gHC_PARR' :: Module+gHC_PARR' = mkBaseModule (fsLit "GHC.PArr")++gHC_SRCLOC :: Module+gHC_SRCLOC = mkBaseModule (fsLit "GHC.SrcLoc")++gHC_STACK, gHC_STACK_TYPES :: Module+gHC_STACK = mkBaseModule (fsLit "GHC.Stack")+gHC_STACK_TYPES = mkBaseModule (fsLit "GHC.Stack.Types")++gHC_STATICPTR :: Module+gHC_STATICPTR = mkBaseModule (fsLit "GHC.StaticPtr")++gHC_STATICPTR_INTERNAL :: Module+gHC_STATICPTR_INTERNAL = mkBaseModule (fsLit "GHC.StaticPtr.Internal")++gHC_FINGERPRINT_TYPE :: Module+gHC_FINGERPRINT_TYPE = mkBaseModule (fsLit "GHC.Fingerprint.Type")++gHC_OVER_LABELS :: Module+gHC_OVER_LABELS = mkBaseModule (fsLit "GHC.OverloadedLabels")++gHC_RECORDS :: Module+gHC_RECORDS = mkBaseModule (fsLit "GHC.Records")++mAIN, rOOT_MAIN :: Module+mAIN = mkMainModule_ mAIN_NAME+rOOT_MAIN = mkMainModule (fsLit ":Main") -- Root module for initialisation++mkInteractiveModule :: Int -> Module+-- (mkInteractiveMoudule 9) makes module 'interactive:M9'+mkInteractiveModule n = mkModule interactiveUnitId (mkModuleName ("Ghci" ++ show n))++pRELUDE_NAME, mAIN_NAME :: ModuleName+pRELUDE_NAME = mkModuleNameFS (fsLit "Prelude")+mAIN_NAME = mkModuleNameFS (fsLit "Main")++dATA_ARRAY_PARALLEL_NAME, dATA_ARRAY_PARALLEL_PRIM_NAME :: ModuleName+dATA_ARRAY_PARALLEL_NAME = mkModuleNameFS (fsLit "Data.Array.Parallel")+dATA_ARRAY_PARALLEL_PRIM_NAME = mkModuleNameFS (fsLit "Data.Array.Parallel.Prim")++mkPrimModule :: FastString -> Module+mkPrimModule m = mkModule primUnitId (mkModuleNameFS m)++mkIntegerModule :: FastString -> Module+mkIntegerModule m = mkModule integerUnitId (mkModuleNameFS m)++mkBaseModule :: FastString -> Module+mkBaseModule m = mkModule baseUnitId (mkModuleNameFS m)++mkBaseModule_ :: ModuleName -> Module+mkBaseModule_ m = mkModule baseUnitId m++mkThisGhcModule :: FastString -> Module+mkThisGhcModule m = mkModule thisGhcUnitId (mkModuleNameFS m)++mkThisGhcModule_ :: ModuleName -> Module+mkThisGhcModule_ m = mkModule thisGhcUnitId m++mkMainModule :: FastString -> Module+mkMainModule m = mkModule mainUnitId (mkModuleNameFS m)++mkMainModule_ :: ModuleName -> Module+mkMainModule_ m = mkModule mainUnitId m++{-+************************************************************************+* *+ RdrNames+* *+************************************************************************+-}++main_RDR_Unqual :: RdrName+main_RDR_Unqual = mkUnqual varName (fsLit "main")+ -- We definitely don't want an Orig RdrName, because+ -- main might, in principle, be imported into module Main++forall_tv_RDR, dot_tv_RDR :: RdrName+forall_tv_RDR = mkUnqual tvName (fsLit "forall")+dot_tv_RDR = mkUnqual tvName (fsLit ".")++eq_RDR, ge_RDR, ne_RDR, le_RDR, lt_RDR, gt_RDR, compare_RDR,+ ltTag_RDR, eqTag_RDR, gtTag_RDR :: RdrName+eq_RDR = nameRdrName eqName+ge_RDR = nameRdrName geName+ne_RDR = varQual_RDR gHC_CLASSES (fsLit "/=")+le_RDR = varQual_RDR gHC_CLASSES (fsLit "<=")+lt_RDR = varQual_RDR gHC_CLASSES (fsLit "<")+gt_RDR = varQual_RDR gHC_CLASSES (fsLit ">")+compare_RDR = varQual_RDR gHC_CLASSES (fsLit "compare")+ltTag_RDR = dataQual_RDR gHC_TYPES (fsLit "LT")+eqTag_RDR = dataQual_RDR gHC_TYPES (fsLit "EQ")+gtTag_RDR = dataQual_RDR gHC_TYPES (fsLit "GT")++eqClass_RDR, numClass_RDR, ordClass_RDR, enumClass_RDR, monadClass_RDR+ :: RdrName+eqClass_RDR = nameRdrName eqClassName+numClass_RDR = nameRdrName numClassName+ordClass_RDR = nameRdrName ordClassName+enumClass_RDR = nameRdrName enumClassName+monadClass_RDR = nameRdrName monadClassName++map_RDR, append_RDR :: RdrName+map_RDR = varQual_RDR gHC_BASE (fsLit "map")+append_RDR = varQual_RDR gHC_BASE (fsLit "++")++foldr_RDR, build_RDR, returnM_RDR, bindM_RDR, failM_RDR_preMFP, failM_RDR:: RdrName+foldr_RDR = nameRdrName foldrName+build_RDR = nameRdrName buildName+returnM_RDR = nameRdrName returnMName+bindM_RDR = nameRdrName bindMName+failM_RDR_preMFP = nameRdrName failMName_preMFP+failM_RDR = nameRdrName failMName++left_RDR, right_RDR :: RdrName+left_RDR = nameRdrName leftDataConName+right_RDR = nameRdrName rightDataConName++fromEnum_RDR, toEnum_RDR :: RdrName+fromEnum_RDR = varQual_RDR gHC_ENUM (fsLit "fromEnum")+toEnum_RDR = varQual_RDR gHC_ENUM (fsLit "toEnum")++enumFrom_RDR, enumFromTo_RDR, enumFromThen_RDR, enumFromThenTo_RDR :: RdrName+enumFrom_RDR = nameRdrName enumFromName+enumFromTo_RDR = nameRdrName enumFromToName+enumFromThen_RDR = nameRdrName enumFromThenName+enumFromThenTo_RDR = nameRdrName enumFromThenToName++ratioDataCon_RDR, plusInteger_RDR, timesInteger_RDR :: RdrName+ratioDataCon_RDR = nameRdrName ratioDataConName+plusInteger_RDR = nameRdrName plusIntegerName+timesInteger_RDR = nameRdrName timesIntegerName++ioDataCon_RDR :: RdrName+ioDataCon_RDR = nameRdrName ioDataConName++eqString_RDR, unpackCString_RDR, unpackCStringFoldr_RDR,+ unpackCStringUtf8_RDR :: RdrName+eqString_RDR = nameRdrName eqStringName+unpackCString_RDR = nameRdrName unpackCStringName+unpackCStringFoldr_RDR = nameRdrName unpackCStringFoldrName+unpackCStringUtf8_RDR = nameRdrName unpackCStringUtf8Name++newStablePtr_RDR :: RdrName+newStablePtr_RDR = nameRdrName newStablePtrName++bindIO_RDR, returnIO_RDR :: RdrName+bindIO_RDR = nameRdrName bindIOName+returnIO_RDR = nameRdrName returnIOName++fromInteger_RDR, fromRational_RDR, minus_RDR, times_RDR, plus_RDR :: RdrName+fromInteger_RDR = nameRdrName fromIntegerName+fromRational_RDR = nameRdrName fromRationalName+minus_RDR = nameRdrName minusName+times_RDR = varQual_RDR gHC_NUM (fsLit "*")+plus_RDR = varQual_RDR gHC_NUM (fsLit "+")++toInteger_RDR, toRational_RDR, fromIntegral_RDR :: RdrName+toInteger_RDR = nameRdrName toIntegerName+toRational_RDR = nameRdrName toRationalName+fromIntegral_RDR = nameRdrName fromIntegralName++stringTy_RDR, fromString_RDR :: RdrName+stringTy_RDR = tcQual_RDR gHC_BASE (fsLit "String")+fromString_RDR = nameRdrName fromStringName++fromList_RDR, fromListN_RDR, toList_RDR :: RdrName+fromList_RDR = nameRdrName fromListName+fromListN_RDR = nameRdrName fromListNName+toList_RDR = nameRdrName toListName++compose_RDR :: RdrName+compose_RDR = varQual_RDR gHC_BASE (fsLit ".")++not_RDR, getTag_RDR, succ_RDR, pred_RDR, minBound_RDR, maxBound_RDR,+ and_RDR, range_RDR, inRange_RDR, index_RDR,+ unsafeIndex_RDR, unsafeRangeSize_RDR :: RdrName+and_RDR = varQual_RDR gHC_CLASSES (fsLit "&&")+not_RDR = varQual_RDR gHC_CLASSES (fsLit "not")+getTag_RDR = varQual_RDR gHC_BASE (fsLit "getTag")+succ_RDR = varQual_RDR gHC_ENUM (fsLit "succ")+pred_RDR = varQual_RDR gHC_ENUM (fsLit "pred")+minBound_RDR = varQual_RDR gHC_ENUM (fsLit "minBound")+maxBound_RDR = varQual_RDR gHC_ENUM (fsLit "maxBound")+range_RDR = varQual_RDR gHC_ARR (fsLit "range")+inRange_RDR = varQual_RDR gHC_ARR (fsLit "inRange")+index_RDR = varQual_RDR gHC_ARR (fsLit "index")+unsafeIndex_RDR = varQual_RDR gHC_ARR (fsLit "unsafeIndex")+unsafeRangeSize_RDR = varQual_RDR gHC_ARR (fsLit "unsafeRangeSize")++readList_RDR, readListDefault_RDR, readListPrec_RDR, readListPrecDefault_RDR,+ readPrec_RDR, parens_RDR, choose_RDR, lexP_RDR, expectP_RDR :: RdrName+readList_RDR = varQual_RDR gHC_READ (fsLit "readList")+readListDefault_RDR = varQual_RDR gHC_READ (fsLit "readListDefault")+readListPrec_RDR = varQual_RDR gHC_READ (fsLit "readListPrec")+readListPrecDefault_RDR = varQual_RDR gHC_READ (fsLit "readListPrecDefault")+readPrec_RDR = varQual_RDR gHC_READ (fsLit "readPrec")+parens_RDR = varQual_RDR gHC_READ (fsLit "parens")+choose_RDR = varQual_RDR gHC_READ (fsLit "choose")+lexP_RDR = varQual_RDR gHC_READ (fsLit "lexP")+expectP_RDR = varQual_RDR gHC_READ (fsLit "expectP")++punc_RDR, ident_RDR, symbol_RDR :: RdrName+punc_RDR = dataQual_RDR lEX (fsLit "Punc")+ident_RDR = dataQual_RDR lEX (fsLit "Ident")+symbol_RDR = dataQual_RDR lEX (fsLit "Symbol")++step_RDR, alt_RDR, reset_RDR, prec_RDR, pfail_RDR :: RdrName+step_RDR = varQual_RDR rEAD_PREC (fsLit "step")+alt_RDR = varQual_RDR rEAD_PREC (fsLit "+++")+reset_RDR = varQual_RDR rEAD_PREC (fsLit "reset")+prec_RDR = varQual_RDR rEAD_PREC (fsLit "prec")+pfail_RDR = varQual_RDR rEAD_PREC (fsLit "pfail")++showList_RDR, showList___RDR, showsPrec_RDR, shows_RDR, showString_RDR,+ showSpace_RDR, showCommaSpace_RDR, showParen_RDR :: RdrName+showList_RDR = varQual_RDR gHC_SHOW (fsLit "showList")+showList___RDR = varQual_RDR gHC_SHOW (fsLit "showList__")+showsPrec_RDR = varQual_RDR gHC_SHOW (fsLit "showsPrec")+shows_RDR = varQual_RDR gHC_SHOW (fsLit "shows")+showString_RDR = varQual_RDR gHC_SHOW (fsLit "showString")+showSpace_RDR = varQual_RDR gHC_SHOW (fsLit "showSpace")+showCommaSpace_RDR = varQual_RDR gHC_SHOW (fsLit "showCommaSpace")+showParen_RDR = varQual_RDR gHC_SHOW (fsLit "showParen")++undefined_RDR :: RdrName+undefined_RDR = varQual_RDR gHC_ERR (fsLit "undefined")++error_RDR :: RdrName+error_RDR = varQual_RDR gHC_ERR (fsLit "error")++-- Generics (constructors and functions)+u1DataCon_RDR, par1DataCon_RDR, rec1DataCon_RDR,+ k1DataCon_RDR, m1DataCon_RDR, l1DataCon_RDR, r1DataCon_RDR,+ prodDataCon_RDR, comp1DataCon_RDR,+ unPar1_RDR, unRec1_RDR, unK1_RDR, unComp1_RDR,+ from_RDR, from1_RDR, to_RDR, to1_RDR,+ datatypeName_RDR, moduleName_RDR, packageName_RDR, isNewtypeName_RDR,+ conName_RDR, conFixity_RDR, conIsRecord_RDR, selName_RDR,+ prefixDataCon_RDR, infixDataCon_RDR, leftAssocDataCon_RDR,+ rightAssocDataCon_RDR, notAssocDataCon_RDR,+ uAddrDataCon_RDR, uCharDataCon_RDR, uDoubleDataCon_RDR,+ uFloatDataCon_RDR, uIntDataCon_RDR, uWordDataCon_RDR,+ uAddrHash_RDR, uCharHash_RDR, uDoubleHash_RDR,+ uFloatHash_RDR, uIntHash_RDR, uWordHash_RDR :: RdrName++u1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "U1")+par1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "Par1")+rec1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "Rec1")+k1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "K1")+m1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "M1")++l1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "L1")+r1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "R1")++prodDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit ":*:")+comp1DataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "Comp1")++unPar1_RDR = varQual_RDR gHC_GENERICS (fsLit "unPar1")+unRec1_RDR = varQual_RDR gHC_GENERICS (fsLit "unRec1")+unK1_RDR = varQual_RDR gHC_GENERICS (fsLit "unK1")+unComp1_RDR = varQual_RDR gHC_GENERICS (fsLit "unComp1")++from_RDR = varQual_RDR gHC_GENERICS (fsLit "from")+from1_RDR = varQual_RDR gHC_GENERICS (fsLit "from1")+to_RDR = varQual_RDR gHC_GENERICS (fsLit "to")+to1_RDR = varQual_RDR gHC_GENERICS (fsLit "to1")++datatypeName_RDR = varQual_RDR gHC_GENERICS (fsLit "datatypeName")+moduleName_RDR = varQual_RDR gHC_GENERICS (fsLit "moduleName")+packageName_RDR = varQual_RDR gHC_GENERICS (fsLit "packageName")+isNewtypeName_RDR = varQual_RDR gHC_GENERICS (fsLit "isNewtype")+selName_RDR = varQual_RDR gHC_GENERICS (fsLit "selName")+conName_RDR = varQual_RDR gHC_GENERICS (fsLit "conName")+conFixity_RDR = varQual_RDR gHC_GENERICS (fsLit "conFixity")+conIsRecord_RDR = varQual_RDR gHC_GENERICS (fsLit "conIsRecord")++prefixDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "Prefix")+infixDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "Infix")+leftAssocDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "LeftAssociative")+rightAssocDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "RightAssociative")+notAssocDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "NotAssociative")++uAddrDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UAddr")+uCharDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UChar")+uDoubleDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UDouble")+uFloatDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UFloat")+uIntDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UInt")+uWordDataCon_RDR = dataQual_RDR gHC_GENERICS (fsLit "UWord")++uAddrHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uAddr#")+uCharHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uChar#")+uDoubleHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uDouble#")+uFloatHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uFloat#")+uIntHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uInt#")+uWordHash_RDR = varQual_RDR gHC_GENERICS (fsLit "uWord#")++fmap_RDR, replace_RDR, pure_RDR, ap_RDR, liftA2_RDR, foldable_foldr_RDR,+ foldMap_RDR, traverse_RDR, mempty_RDR, mappend_RDR :: RdrName+fmap_RDR = varQual_RDR gHC_BASE (fsLit "fmap")+replace_RDR = varQual_RDR gHC_BASE (fsLit "<$")+pure_RDR = nameRdrName pureAName+ap_RDR = nameRdrName apAName+liftA2_RDR = varQual_RDR gHC_BASE (fsLit "liftA2")+foldable_foldr_RDR = varQual_RDR dATA_FOLDABLE (fsLit "foldr")+foldMap_RDR = varQual_RDR dATA_FOLDABLE (fsLit "foldMap")+traverse_RDR = varQual_RDR dATA_TRAVERSABLE (fsLit "traverse")+mempty_RDR = varQual_RDR gHC_BASE (fsLit "mempty")+mappend_RDR = varQual_RDR gHC_BASE (fsLit "mappend")++eqTyCon_RDR :: RdrName+eqTyCon_RDR = tcQual_RDR dATA_TYPE_EQUALITY (fsLit "~")++----------------------+varQual_RDR, tcQual_RDR, clsQual_RDR, dataQual_RDR+ :: Module -> FastString -> RdrName+varQual_RDR mod str = mkOrig mod (mkOccNameFS varName str)+tcQual_RDR mod str = mkOrig mod (mkOccNameFS tcName str)+clsQual_RDR mod str = mkOrig mod (mkOccNameFS clsName str)+dataQual_RDR mod str = mkOrig mod (mkOccNameFS dataName str)++{-+************************************************************************+* *+\subsection{Known-key names}+* *+************************************************************************++Many of these Names are not really "built in", but some parts of the+compiler (notably the deriving mechanism) need to mention their names,+and it's convenient to write them all down in one place.++--MetaHaskell Extension add the constrs and the lower case case+-- guys as well (perhaps) e.g. see trueDataConName below+-}++wildCardName :: Name+wildCardName = mkSystemVarName wildCardKey (fsLit "wild")++runMainIOName :: Name+runMainIOName = varQual gHC_TOP_HANDLER (fsLit "runMainIO") runMainKey++orderingTyConName, ltDataConName, eqDataConName, gtDataConName :: Name+orderingTyConName = tcQual gHC_TYPES (fsLit "Ordering") orderingTyConKey+ltDataConName = dcQual gHC_TYPES (fsLit "LT") ltDataConKey+eqDataConName = dcQual gHC_TYPES (fsLit "EQ") eqDataConKey+gtDataConName = dcQual gHC_TYPES (fsLit "GT") gtDataConKey++specTyConName :: Name+specTyConName = tcQual gHC_TYPES (fsLit "SPEC") specTyConKey++eitherTyConName, leftDataConName, rightDataConName :: Name+eitherTyConName = tcQual dATA_EITHER (fsLit "Either") eitherTyConKey+leftDataConName = dcQual dATA_EITHER (fsLit "Left") leftDataConKey+rightDataConName = dcQual dATA_EITHER (fsLit "Right") rightDataConKey++-- Generics (types)+v1TyConName, u1TyConName, par1TyConName, rec1TyConName,+ k1TyConName, m1TyConName, sumTyConName, prodTyConName,+ compTyConName, rTyConName, dTyConName,+ cTyConName, sTyConName, rec0TyConName,+ d1TyConName, c1TyConName, s1TyConName, noSelTyConName,+ repTyConName, rep1TyConName, uRecTyConName,+ uAddrTyConName, uCharTyConName, uDoubleTyConName,+ uFloatTyConName, uIntTyConName, uWordTyConName,+ prefixIDataConName, infixIDataConName, leftAssociativeDataConName,+ rightAssociativeDataConName, notAssociativeDataConName,+ sourceUnpackDataConName, sourceNoUnpackDataConName,+ noSourceUnpackednessDataConName, sourceLazyDataConName,+ sourceStrictDataConName, noSourceStrictnessDataConName,+ decidedLazyDataConName, decidedStrictDataConName, decidedUnpackDataConName,+ metaDataDataConName, metaConsDataConName, metaSelDataConName :: Name++v1TyConName = tcQual gHC_GENERICS (fsLit "V1") v1TyConKey+u1TyConName = tcQual gHC_GENERICS (fsLit "U1") u1TyConKey+par1TyConName = tcQual gHC_GENERICS (fsLit "Par1") par1TyConKey+rec1TyConName = tcQual gHC_GENERICS (fsLit "Rec1") rec1TyConKey+k1TyConName = tcQual gHC_GENERICS (fsLit "K1") k1TyConKey+m1TyConName = tcQual gHC_GENERICS (fsLit "M1") m1TyConKey++sumTyConName = tcQual gHC_GENERICS (fsLit ":+:") sumTyConKey+prodTyConName = tcQual gHC_GENERICS (fsLit ":*:") prodTyConKey+compTyConName = tcQual gHC_GENERICS (fsLit ":.:") compTyConKey++rTyConName = tcQual gHC_GENERICS (fsLit "R") rTyConKey+dTyConName = tcQual gHC_GENERICS (fsLit "D") dTyConKey+cTyConName = tcQual gHC_GENERICS (fsLit "C") cTyConKey+sTyConName = tcQual gHC_GENERICS (fsLit "S") sTyConKey++rec0TyConName = tcQual gHC_GENERICS (fsLit "Rec0") rec0TyConKey+d1TyConName = tcQual gHC_GENERICS (fsLit "D1") d1TyConKey+c1TyConName = tcQual gHC_GENERICS (fsLit "C1") c1TyConKey+s1TyConName = tcQual gHC_GENERICS (fsLit "S1") s1TyConKey+noSelTyConName = tcQual gHC_GENERICS (fsLit "NoSelector") noSelTyConKey++repTyConName = tcQual gHC_GENERICS (fsLit "Rep") repTyConKey+rep1TyConName = tcQual gHC_GENERICS (fsLit "Rep1") rep1TyConKey++uRecTyConName = tcQual gHC_GENERICS (fsLit "URec") uRecTyConKey+uAddrTyConName = tcQual gHC_GENERICS (fsLit "UAddr") uAddrTyConKey+uCharTyConName = tcQual gHC_GENERICS (fsLit "UChar") uCharTyConKey+uDoubleTyConName = tcQual gHC_GENERICS (fsLit "UDouble") uDoubleTyConKey+uFloatTyConName = tcQual gHC_GENERICS (fsLit "UFloat") uFloatTyConKey+uIntTyConName = tcQual gHC_GENERICS (fsLit "UInt") uIntTyConKey+uWordTyConName = tcQual gHC_GENERICS (fsLit "UWord") uWordTyConKey++prefixIDataConName = dcQual gHC_GENERICS (fsLit "PrefixI") prefixIDataConKey+infixIDataConName = dcQual gHC_GENERICS (fsLit "InfixI") infixIDataConKey+leftAssociativeDataConName = dcQual gHC_GENERICS (fsLit "LeftAssociative") leftAssociativeDataConKey+rightAssociativeDataConName = dcQual gHC_GENERICS (fsLit "RightAssociative") rightAssociativeDataConKey+notAssociativeDataConName = dcQual gHC_GENERICS (fsLit "NotAssociative") notAssociativeDataConKey++sourceUnpackDataConName = dcQual gHC_GENERICS (fsLit "SourceUnpack") sourceUnpackDataConKey+sourceNoUnpackDataConName = dcQual gHC_GENERICS (fsLit "SourceNoUnpack") sourceNoUnpackDataConKey+noSourceUnpackednessDataConName = dcQual gHC_GENERICS (fsLit "NoSourceUnpackedness") noSourceUnpackednessDataConKey+sourceLazyDataConName = dcQual gHC_GENERICS (fsLit "SourceLazy") sourceLazyDataConKey+sourceStrictDataConName = dcQual gHC_GENERICS (fsLit "SourceStrict") sourceStrictDataConKey+noSourceStrictnessDataConName = dcQual gHC_GENERICS (fsLit "NoSourceStrictness") noSourceStrictnessDataConKey+decidedLazyDataConName = dcQual gHC_GENERICS (fsLit "DecidedLazy") decidedLazyDataConKey+decidedStrictDataConName = dcQual gHC_GENERICS (fsLit "DecidedStrict") decidedStrictDataConKey+decidedUnpackDataConName = dcQual gHC_GENERICS (fsLit "DecidedUnpack") decidedUnpackDataConKey++metaDataDataConName = dcQual gHC_GENERICS (fsLit "MetaData") metaDataDataConKey+metaConsDataConName = dcQual gHC_GENERICS (fsLit "MetaCons") metaConsDataConKey+metaSelDataConName = dcQual gHC_GENERICS (fsLit "MetaSel") metaSelDataConKey++-- Primitive Int+divIntName, modIntName :: Name+divIntName = varQual gHC_CLASSES (fsLit "divInt#") divIntIdKey+modIntName = varQual gHC_CLASSES (fsLit "modInt#") modIntIdKey++-- Base strings Strings+unpackCStringName, unpackCStringFoldrName,+ unpackCStringUtf8Name, eqStringName :: Name+unpackCStringName = varQual gHC_CSTRING (fsLit "unpackCString#") unpackCStringIdKey+unpackCStringFoldrName = varQual gHC_CSTRING (fsLit "unpackFoldrCString#") unpackCStringFoldrIdKey+unpackCStringUtf8Name = varQual gHC_CSTRING (fsLit "unpackCStringUtf8#") unpackCStringUtf8IdKey+eqStringName = varQual gHC_BASE (fsLit "eqString") eqStringIdKey++-- The 'inline' function+inlineIdName :: Name+inlineIdName = varQual gHC_MAGIC (fsLit "inline") inlineIdKey++-- Base classes (Eq, Ord, Functor)+fmapName, eqClassName, eqName, ordClassName, geName, functorClassName :: Name+eqClassName = clsQual gHC_CLASSES (fsLit "Eq") eqClassKey+eqName = varQual gHC_CLASSES (fsLit "==") eqClassOpKey+ordClassName = clsQual gHC_CLASSES (fsLit "Ord") ordClassKey+geName = varQual gHC_CLASSES (fsLit ">=") geClassOpKey+functorClassName = clsQual gHC_BASE (fsLit "Functor") functorClassKey+fmapName = varQual gHC_BASE (fsLit "fmap") fmapClassOpKey++-- Class Monad+monadClassName, thenMName, bindMName, returnMName, failMName_preMFP :: Name+monadClassName = clsQual gHC_BASE (fsLit "Monad") monadClassKey+thenMName = varQual gHC_BASE (fsLit ">>") thenMClassOpKey+bindMName = varQual gHC_BASE (fsLit ">>=") bindMClassOpKey+returnMName = varQual gHC_BASE (fsLit "return") returnMClassOpKey+failMName_preMFP = varQual gHC_BASE (fsLit "fail") failMClassOpKey_preMFP++-- Class MonadFail+monadFailClassName, failMName :: Name+monadFailClassName = clsQual mONAD_FAIL (fsLit "MonadFail") monadFailClassKey+failMName = varQual mONAD_FAIL (fsLit "fail") failMClassOpKey++-- Class Applicative+applicativeClassName, pureAName, apAName, thenAName :: Name+applicativeClassName = clsQual gHC_BASE (fsLit "Applicative") applicativeClassKey+apAName = varQual gHC_BASE (fsLit "<*>") apAClassOpKey+pureAName = varQual gHC_BASE (fsLit "pure") pureAClassOpKey+thenAName = varQual gHC_BASE (fsLit "*>") thenAClassOpKey++-- Classes (Foldable, Traversable)+foldableClassName, traversableClassName :: Name+foldableClassName = clsQual dATA_FOLDABLE (fsLit "Foldable") foldableClassKey+traversableClassName = clsQual dATA_TRAVERSABLE (fsLit "Traversable") traversableClassKey++-- Classes (Semigroup, Monoid)+semigroupClassName, sappendName :: Name+semigroupClassName = clsQual dATA_SEMIGROUP (fsLit "Semigroup") semigroupClassKey+sappendName = varQual dATA_SEMIGROUP (fsLit "<>") sappendClassOpKey+monoidClassName, memptyName, mappendName, mconcatName :: Name+monoidClassName = clsQual gHC_BASE (fsLit "Monoid") monoidClassKey+memptyName = varQual gHC_BASE (fsLit "mempty") memptyClassOpKey+mappendName = varQual gHC_BASE (fsLit "mappend") mappendClassOpKey+mconcatName = varQual gHC_BASE (fsLit "mconcat") mconcatClassOpKey++++-- AMP additions++joinMName, alternativeClassName :: Name+joinMName = varQual gHC_BASE (fsLit "join") joinMIdKey+alternativeClassName = clsQual mONAD (fsLit "Alternative") alternativeClassKey++--+joinMIdKey, apAClassOpKey, pureAClassOpKey, thenAClassOpKey,+ alternativeClassKey :: Unique+joinMIdKey = mkPreludeMiscIdUnique 750+apAClassOpKey = mkPreludeMiscIdUnique 751 -- <*>+pureAClassOpKey = mkPreludeMiscIdUnique 752+thenAClassOpKey = mkPreludeMiscIdUnique 753+alternativeClassKey = mkPreludeMiscIdUnique 754+++-- Functions for GHC extensions+groupWithName :: Name+groupWithName = varQual gHC_EXTS (fsLit "groupWith") groupWithIdKey++-- Random PrelBase functions+fromStringName, otherwiseIdName, foldrName, buildName, augmentName,+ mapName, appendName, assertName,+ breakpointName, breakpointCondName, breakpointAutoName,+ opaqueTyConName :: Name+fromStringName = varQual dATA_STRING (fsLit "fromString") fromStringClassOpKey+otherwiseIdName = varQual gHC_BASE (fsLit "otherwise") otherwiseIdKey+foldrName = varQual gHC_BASE (fsLit "foldr") foldrIdKey+buildName = varQual gHC_BASE (fsLit "build") buildIdKey+augmentName = varQual gHC_BASE (fsLit "augment") augmentIdKey+mapName = varQual gHC_BASE (fsLit "map") mapIdKey+appendName = varQual gHC_BASE (fsLit "++") appendIdKey+assertName = varQual gHC_BASE (fsLit "assert") assertIdKey+breakpointName = varQual gHC_BASE (fsLit "breakpoint") breakpointIdKey+breakpointCondName= varQual gHC_BASE (fsLit "breakpointCond") breakpointCondIdKey+breakpointAutoName= varQual gHC_BASE (fsLit "breakpointAuto") breakpointAutoIdKey+opaqueTyConName = tcQual gHC_BASE (fsLit "Opaque") opaqueTyConKey++breakpointJumpName :: Name+breakpointJumpName+ = mkInternalName+ breakpointJumpIdKey+ (mkOccNameFS varName (fsLit "breakpointJump"))+ noSrcSpan+breakpointCondJumpName :: Name+breakpointCondJumpName+ = mkInternalName+ breakpointCondJumpIdKey+ (mkOccNameFS varName (fsLit "breakpointCondJump"))+ noSrcSpan+breakpointAutoJumpName :: Name+breakpointAutoJumpName+ = mkInternalName+ breakpointAutoJumpIdKey+ (mkOccNameFS varName (fsLit "breakpointAutoJump"))+ noSrcSpan++-- PrelTup+fstName, sndName :: Name+fstName = varQual dATA_TUPLE (fsLit "fst") fstIdKey+sndName = varQual dATA_TUPLE (fsLit "snd") sndIdKey++-- Module GHC.Num+numClassName, fromIntegerName, minusName, negateName :: Name+numClassName = clsQual gHC_NUM (fsLit "Num") numClassKey+fromIntegerName = varQual gHC_NUM (fsLit "fromInteger") fromIntegerClassOpKey+minusName = varQual gHC_NUM (fsLit "-") minusClassOpKey+negateName = varQual gHC_NUM (fsLit "negate") negateClassOpKey++integerTyConName, mkIntegerName, integerSDataConName,+ integerToWord64Name, integerToInt64Name,+ word64ToIntegerName, int64ToIntegerName,+ plusIntegerName, timesIntegerName, smallIntegerName,+ wordToIntegerName,+ integerToWordName, integerToIntName, minusIntegerName,+ negateIntegerName, eqIntegerPrimName, neqIntegerPrimName,+ absIntegerName, signumIntegerName,+ leIntegerPrimName, gtIntegerPrimName, ltIntegerPrimName, geIntegerPrimName,+ compareIntegerName, quotRemIntegerName, divModIntegerName,+ quotIntegerName, remIntegerName, divIntegerName, modIntegerName,+ floatFromIntegerName, doubleFromIntegerName,+ encodeFloatIntegerName, encodeDoubleIntegerName,+ decodeDoubleIntegerName,+ gcdIntegerName, lcmIntegerName,+ andIntegerName, orIntegerName, xorIntegerName, complementIntegerName,+ shiftLIntegerName, shiftRIntegerName, bitIntegerName :: Name+integerTyConName = tcQual gHC_INTEGER_TYPE (fsLit "Integer") integerTyConKey+integerSDataConName = dcQual gHC_INTEGER_TYPE (fsLit n) integerSDataConKey+ where n = case cIntegerLibraryType of+ IntegerGMP -> "S#"+ IntegerSimple -> panic "integerSDataConName evaluated for integer-simple"+mkIntegerName = varQual gHC_INTEGER_TYPE (fsLit "mkInteger") mkIntegerIdKey+integerToWord64Name = varQual gHC_INTEGER_TYPE (fsLit "integerToWord64") integerToWord64IdKey+integerToInt64Name = varQual gHC_INTEGER_TYPE (fsLit "integerToInt64") integerToInt64IdKey+word64ToIntegerName = varQual gHC_INTEGER_TYPE (fsLit "word64ToInteger") word64ToIntegerIdKey+int64ToIntegerName = varQual gHC_INTEGER_TYPE (fsLit "int64ToInteger") int64ToIntegerIdKey+plusIntegerName = varQual gHC_INTEGER_TYPE (fsLit "plusInteger") plusIntegerIdKey+timesIntegerName = varQual gHC_INTEGER_TYPE (fsLit "timesInteger") timesIntegerIdKey+smallIntegerName = varQual gHC_INTEGER_TYPE (fsLit "smallInteger") smallIntegerIdKey+wordToIntegerName = varQual gHC_INTEGER_TYPE (fsLit "wordToInteger") wordToIntegerIdKey+integerToWordName = varQual gHC_INTEGER_TYPE (fsLit "integerToWord") integerToWordIdKey+integerToIntName = varQual gHC_INTEGER_TYPE (fsLit "integerToInt") integerToIntIdKey+minusIntegerName = varQual gHC_INTEGER_TYPE (fsLit "minusInteger") minusIntegerIdKey+negateIntegerName = varQual gHC_INTEGER_TYPE (fsLit "negateInteger") negateIntegerIdKey+eqIntegerPrimName = varQual gHC_INTEGER_TYPE (fsLit "eqInteger#") eqIntegerPrimIdKey+neqIntegerPrimName = varQual gHC_INTEGER_TYPE (fsLit "neqInteger#") neqIntegerPrimIdKey+absIntegerName = varQual gHC_INTEGER_TYPE (fsLit "absInteger") absIntegerIdKey+signumIntegerName = varQual gHC_INTEGER_TYPE (fsLit "signumInteger") signumIntegerIdKey+leIntegerPrimName = varQual gHC_INTEGER_TYPE (fsLit "leInteger#") leIntegerPrimIdKey+gtIntegerPrimName = varQual gHC_INTEGER_TYPE (fsLit "gtInteger#") gtIntegerPrimIdKey+ltIntegerPrimName = varQual gHC_INTEGER_TYPE (fsLit "ltInteger#") ltIntegerPrimIdKey+geIntegerPrimName = varQual gHC_INTEGER_TYPE (fsLit "geInteger#") geIntegerPrimIdKey+compareIntegerName = varQual gHC_INTEGER_TYPE (fsLit "compareInteger") compareIntegerIdKey+quotRemIntegerName = varQual gHC_INTEGER_TYPE (fsLit "quotRemInteger") quotRemIntegerIdKey+divModIntegerName = varQual gHC_INTEGER_TYPE (fsLit "divModInteger") divModIntegerIdKey+quotIntegerName = varQual gHC_INTEGER_TYPE (fsLit "quotInteger") quotIntegerIdKey+remIntegerName = varQual gHC_INTEGER_TYPE (fsLit "remInteger") remIntegerIdKey+divIntegerName = varQual gHC_INTEGER_TYPE (fsLit "divInteger") divIntegerIdKey+modIntegerName = varQual gHC_INTEGER_TYPE (fsLit "modInteger") modIntegerIdKey+floatFromIntegerName = varQual gHC_INTEGER_TYPE (fsLit "floatFromInteger") floatFromIntegerIdKey+doubleFromIntegerName = varQual gHC_INTEGER_TYPE (fsLit "doubleFromInteger") doubleFromIntegerIdKey+encodeFloatIntegerName = varQual gHC_INTEGER_TYPE (fsLit "encodeFloatInteger") encodeFloatIntegerIdKey+encodeDoubleIntegerName = varQual gHC_INTEGER_TYPE (fsLit "encodeDoubleInteger") encodeDoubleIntegerIdKey+decodeDoubleIntegerName = varQual gHC_INTEGER_TYPE (fsLit "decodeDoubleInteger") decodeDoubleIntegerIdKey+gcdIntegerName = varQual gHC_INTEGER_TYPE (fsLit "gcdInteger") gcdIntegerIdKey+lcmIntegerName = varQual gHC_INTEGER_TYPE (fsLit "lcmInteger") lcmIntegerIdKey+andIntegerName = varQual gHC_INTEGER_TYPE (fsLit "andInteger") andIntegerIdKey+orIntegerName = varQual gHC_INTEGER_TYPE (fsLit "orInteger") orIntegerIdKey+xorIntegerName = varQual gHC_INTEGER_TYPE (fsLit "xorInteger") xorIntegerIdKey+complementIntegerName = varQual gHC_INTEGER_TYPE (fsLit "complementInteger") complementIntegerIdKey+shiftLIntegerName = varQual gHC_INTEGER_TYPE (fsLit "shiftLInteger") shiftLIntegerIdKey+shiftRIntegerName = varQual gHC_INTEGER_TYPE (fsLit "shiftRInteger") shiftRIntegerIdKey+bitIntegerName = varQual gHC_INTEGER_TYPE (fsLit "bitInteger") bitIntegerIdKey++-- GHC.Natural types+naturalTyConName :: Name+naturalTyConName = tcQual gHC_NATURAL (fsLit "Natural") naturalTyConKey++naturalFromIntegerName :: Name+naturalFromIntegerName = varQual gHC_NATURAL (fsLit "naturalFromInteger") naturalFromIntegerIdKey++-- GHC.Real types and classes+rationalTyConName, ratioTyConName, ratioDataConName, realClassName,+ integralClassName, realFracClassName, fractionalClassName,+ fromRationalName, toIntegerName, toRationalName, fromIntegralName,+ realToFracName :: Name+rationalTyConName = tcQual gHC_REAL (fsLit "Rational") rationalTyConKey+ratioTyConName = tcQual gHC_REAL (fsLit "Ratio") ratioTyConKey+ratioDataConName = dcQual gHC_REAL (fsLit ":%") ratioDataConKey+realClassName = clsQual gHC_REAL (fsLit "Real") realClassKey+integralClassName = clsQual gHC_REAL (fsLit "Integral") integralClassKey+realFracClassName = clsQual gHC_REAL (fsLit "RealFrac") realFracClassKey+fractionalClassName = clsQual gHC_REAL (fsLit "Fractional") fractionalClassKey+fromRationalName = varQual gHC_REAL (fsLit "fromRational") fromRationalClassOpKey+toIntegerName = varQual gHC_REAL (fsLit "toInteger") toIntegerClassOpKey+toRationalName = varQual gHC_REAL (fsLit "toRational") toRationalClassOpKey+fromIntegralName = varQual gHC_REAL (fsLit "fromIntegral")fromIntegralIdKey+realToFracName = varQual gHC_REAL (fsLit "realToFrac") realToFracIdKey++-- PrelFloat classes+floatingClassName, realFloatClassName :: Name+floatingClassName = clsQual gHC_FLOAT (fsLit "Floating") floatingClassKey+realFloatClassName = clsQual gHC_FLOAT (fsLit "RealFloat") realFloatClassKey++-- other GHC.Float functions+rationalToFloatName, rationalToDoubleName :: Name+rationalToFloatName = varQual gHC_FLOAT (fsLit "rationalToFloat") rationalToFloatIdKey+rationalToDoubleName = varQual gHC_FLOAT (fsLit "rationalToDouble") rationalToDoubleIdKey++-- Class Ix+ixClassName :: Name+ixClassName = clsQual gHC_ARR (fsLit "Ix") ixClassKey++-- Typeable representation types+trModuleTyConName+ , trModuleDataConName+ , trNameTyConName+ , trNameSDataConName+ , trNameDDataConName+ , trTyConTyConName+ , trTyConDataConName+ :: Name+trModuleTyConName = tcQual gHC_TYPES (fsLit "Module") trModuleTyConKey+trModuleDataConName = dcQual gHC_TYPES (fsLit "Module") trModuleDataConKey+trNameTyConName = tcQual gHC_TYPES (fsLit "TrName") trNameTyConKey+trNameSDataConName = dcQual gHC_TYPES (fsLit "TrNameS") trNameSDataConKey+trNameDDataConName = dcQual gHC_TYPES (fsLit "TrNameD") trNameDDataConKey+trTyConTyConName = tcQual gHC_TYPES (fsLit "TyCon") trTyConTyConKey+trTyConDataConName = dcQual gHC_TYPES (fsLit "TyCon") trTyConDataConKey++kindRepTyConName+ , kindRepTyConAppDataConName+ , kindRepVarDataConName+ , kindRepAppDataConName+ , kindRepFunDataConName+ , kindRepTYPEDataConName+ , kindRepTypeLitSDataConName+ , kindRepTypeLitDDataConName+ :: Name+kindRepTyConName = tcQual gHC_TYPES (fsLit "KindRep") kindRepTyConKey+kindRepTyConAppDataConName = dcQual gHC_TYPES (fsLit "KindRepTyConApp") kindRepTyConAppDataConKey+kindRepVarDataConName = dcQual gHC_TYPES (fsLit "KindRepVar") kindRepVarDataConKey+kindRepAppDataConName = dcQual gHC_TYPES (fsLit "KindRepApp") kindRepAppDataConKey+kindRepFunDataConName = dcQual gHC_TYPES (fsLit "KindRepFun") kindRepFunDataConKey+kindRepTYPEDataConName = dcQual gHC_TYPES (fsLit "KindRepTYPE") kindRepTYPEDataConKey+kindRepTypeLitSDataConName = dcQual gHC_TYPES (fsLit "KindRepTypeLitS") kindRepTypeLitSDataConKey+kindRepTypeLitDDataConName = dcQual gHC_TYPES (fsLit "KindRepTypeLitD") kindRepTypeLitDDataConKey++typeLitSortTyConName+ , typeLitSymbolDataConName+ , typeLitNatDataConName+ :: Name+typeLitSortTyConName = tcQual gHC_TYPES (fsLit "TypeLitSort") typeLitSortTyConKey+typeLitSymbolDataConName = dcQual gHC_TYPES (fsLit "TypeLitSymbol") typeLitSymbolDataConKey+typeLitNatDataConName = dcQual gHC_TYPES (fsLit "TypeLitNat") typeLitNatDataConKey++-- Class Typeable, and functions for constructing `Typeable` dictionaries+typeableClassName+ , typeRepTyConName+ , someTypeRepTyConName+ , someTypeRepDataConName+ , mkTrConName+ , mkTrAppName+ , mkTrFunName+ , typeRepIdName+ , typeNatTypeRepName+ , typeSymbolTypeRepName+ , trGhcPrimModuleName+ :: Name+typeableClassName = clsQual tYPEABLE_INTERNAL (fsLit "Typeable") typeableClassKey+typeRepTyConName = tcQual tYPEABLE_INTERNAL (fsLit "TypeRep") typeRepTyConKey+someTypeRepTyConName = tcQual tYPEABLE_INTERNAL (fsLit "SomeTypeRep") someTypeRepTyConKey+someTypeRepDataConName = dcQual tYPEABLE_INTERNAL (fsLit "SomeTypeRep") someTypeRepDataConKey+typeRepIdName = varQual tYPEABLE_INTERNAL (fsLit "typeRep#") typeRepIdKey+mkTrConName = varQual tYPEABLE_INTERNAL (fsLit "mkTrCon") mkTrConKey+mkTrAppName = varQual tYPEABLE_INTERNAL (fsLit "mkTrApp") mkTrAppKey+mkTrFunName = varQual tYPEABLE_INTERNAL (fsLit "mkTrFun") mkTrFunKey+typeNatTypeRepName = varQual tYPEABLE_INTERNAL (fsLit "typeNatTypeRep") typeNatTypeRepKey+typeSymbolTypeRepName = varQual tYPEABLE_INTERNAL (fsLit "typeSymbolTypeRep") typeSymbolTypeRepKey+-- this is the Typeable 'Module' for GHC.Prim (which has no code, so we place in GHC.Types)+-- See Note [Grand plan for Typeable] in TcTypeable.+trGhcPrimModuleName = varQual gHC_TYPES (fsLit "tr$ModuleGHCPrim") trGhcPrimModuleKey++-- Typeable KindReps for some common cases+starKindRepName, starArrStarKindRepName, starArrStarArrStarKindRepName :: Name+starKindRepName = varQual gHC_TYPES (fsLit "krep$*") starKindRepKey+starArrStarKindRepName = varQual gHC_TYPES (fsLit "krep$*Arr*") starArrStarKindRepKey+starArrStarArrStarKindRepName = varQual gHC_TYPES (fsLit "krep$*->*->*") starArrStarArrStarKindRepKey++-- Custom type errors+errorMessageTypeErrorFamName+ , typeErrorTextDataConName+ , typeErrorAppendDataConName+ , typeErrorVAppendDataConName+ , typeErrorShowTypeDataConName+ :: Name++errorMessageTypeErrorFamName =+ tcQual gHC_TYPELITS (fsLit "TypeError") errorMessageTypeErrorFamKey++typeErrorTextDataConName =+ dcQual gHC_TYPELITS (fsLit "Text") typeErrorTextDataConKey++typeErrorAppendDataConName =+ dcQual gHC_TYPELITS (fsLit ":<>:") typeErrorAppendDataConKey++typeErrorVAppendDataConName =+ dcQual gHC_TYPELITS (fsLit ":$$:") typeErrorVAppendDataConKey++typeErrorShowTypeDataConName =+ dcQual gHC_TYPELITS (fsLit "ShowType") typeErrorShowTypeDataConKey++++-- Dynamic+toDynName :: Name+toDynName = varQual dYNAMIC (fsLit "toDyn") toDynIdKey++-- Class Data+dataClassName :: Name+dataClassName = clsQual gENERICS (fsLit "Data") dataClassKey++-- Error module+assertErrorName :: Name+assertErrorName = varQual gHC_IO_Exception (fsLit "assertError") assertErrorIdKey++-- Enum module (Enum, Bounded)+enumClassName, enumFromName, enumFromToName, enumFromThenName,+ enumFromThenToName, boundedClassName :: Name+enumClassName = clsQual gHC_ENUM (fsLit "Enum") enumClassKey+enumFromName = varQual gHC_ENUM (fsLit "enumFrom") enumFromClassOpKey+enumFromToName = varQual gHC_ENUM (fsLit "enumFromTo") enumFromToClassOpKey+enumFromThenName = varQual gHC_ENUM (fsLit "enumFromThen") enumFromThenClassOpKey+enumFromThenToName = varQual gHC_ENUM (fsLit "enumFromThenTo") enumFromThenToClassOpKey+boundedClassName = clsQual gHC_ENUM (fsLit "Bounded") boundedClassKey++-- List functions+concatName, filterName, zipName :: Name+concatName = varQual gHC_LIST (fsLit "concat") concatIdKey+filterName = varQual gHC_LIST (fsLit "filter") filterIdKey+zipName = varQual gHC_LIST (fsLit "zip") zipIdKey++-- Overloaded lists+isListClassName, fromListName, fromListNName, toListName :: Name+isListClassName = clsQual gHC_EXTS (fsLit "IsList") isListClassKey+fromListName = varQual gHC_EXTS (fsLit "fromList") fromListClassOpKey+fromListNName = varQual gHC_EXTS (fsLit "fromListN") fromListNClassOpKey+toListName = varQual gHC_EXTS (fsLit "toList") toListClassOpKey++-- Class Show+showClassName :: Name+showClassName = clsQual gHC_SHOW (fsLit "Show") showClassKey++-- Class Read+readClassName :: Name+readClassName = clsQual gHC_READ (fsLit "Read") readClassKey++-- Classes Generic and Generic1, Datatype, Constructor and Selector+genClassName, gen1ClassName, datatypeClassName, constructorClassName,+ selectorClassName :: Name+genClassName = clsQual gHC_GENERICS (fsLit "Generic") genClassKey+gen1ClassName = clsQual gHC_GENERICS (fsLit "Generic1") gen1ClassKey++datatypeClassName = clsQual gHC_GENERICS (fsLit "Datatype") datatypeClassKey+constructorClassName = clsQual gHC_GENERICS (fsLit "Constructor") constructorClassKey+selectorClassName = clsQual gHC_GENERICS (fsLit "Selector") selectorClassKey++genericClassNames :: [Name]+genericClassNames = [genClassName, gen1ClassName]++-- GHCi things+ghciIoClassName, ghciStepIoMName :: Name+ghciIoClassName = clsQual gHC_GHCI (fsLit "GHCiSandboxIO") ghciIoClassKey+ghciStepIoMName = varQual gHC_GHCI (fsLit "ghciStepIO") ghciStepIoMClassOpKey++-- IO things+ioTyConName, ioDataConName,+ thenIOName, bindIOName, returnIOName, failIOName :: Name+ioTyConName = tcQual gHC_TYPES (fsLit "IO") ioTyConKey+ioDataConName = dcQual gHC_TYPES (fsLit "IO") ioDataConKey+thenIOName = varQual gHC_BASE (fsLit "thenIO") thenIOIdKey+bindIOName = varQual gHC_BASE (fsLit "bindIO") bindIOIdKey+returnIOName = varQual gHC_BASE (fsLit "returnIO") returnIOIdKey+failIOName = varQual gHC_IO (fsLit "failIO") failIOIdKey++-- IO things+printName :: Name+printName = varQual sYSTEM_IO (fsLit "print") printIdKey++-- Int, Word, and Addr things+int8TyConName, int16TyConName, int32TyConName, int64TyConName :: Name+int8TyConName = tcQual gHC_INT (fsLit "Int8") int8TyConKey+int16TyConName = tcQual gHC_INT (fsLit "Int16") int16TyConKey+int32TyConName = tcQual gHC_INT (fsLit "Int32") int32TyConKey+int64TyConName = tcQual gHC_INT (fsLit "Int64") int64TyConKey++-- Word module+word16TyConName, word32TyConName, word64TyConName :: Name+word16TyConName = tcQual gHC_WORD (fsLit "Word16") word16TyConKey+word32TyConName = tcQual gHC_WORD (fsLit "Word32") word32TyConKey+word64TyConName = tcQual gHC_WORD (fsLit "Word64") word64TyConKey++-- PrelPtr module+ptrTyConName, funPtrTyConName :: Name+ptrTyConName = tcQual gHC_PTR (fsLit "Ptr") ptrTyConKey+funPtrTyConName = tcQual gHC_PTR (fsLit "FunPtr") funPtrTyConKey++-- Foreign objects and weak pointers+stablePtrTyConName, newStablePtrName :: Name+stablePtrTyConName = tcQual gHC_STABLE (fsLit "StablePtr") stablePtrTyConKey+newStablePtrName = varQual gHC_STABLE (fsLit "newStablePtr") newStablePtrIdKey++-- Recursive-do notation+monadFixClassName, mfixName :: Name+monadFixClassName = clsQual mONAD_FIX (fsLit "MonadFix") monadFixClassKey+mfixName = varQual mONAD_FIX (fsLit "mfix") mfixIdKey++-- Arrow notation+arrAName, composeAName, firstAName, appAName, choiceAName, loopAName :: Name+arrAName = varQual aRROW (fsLit "arr") arrAIdKey+composeAName = varQual gHC_DESUGAR (fsLit ">>>") composeAIdKey+firstAName = varQual aRROW (fsLit "first") firstAIdKey+appAName = varQual aRROW (fsLit "app") appAIdKey+choiceAName = varQual aRROW (fsLit "|||") choiceAIdKey+loopAName = varQual aRROW (fsLit "loop") loopAIdKey++-- Monad comprehensions+guardMName, liftMName, mzipName :: Name+guardMName = varQual mONAD (fsLit "guard") guardMIdKey+liftMName = varQual mONAD (fsLit "liftM") liftMIdKey+mzipName = varQual mONAD_ZIP (fsLit "mzip") mzipIdKey+++-- Annotation type checking+toAnnotationWrapperName :: Name+toAnnotationWrapperName = varQual gHC_DESUGAR (fsLit "toAnnotationWrapper") toAnnotationWrapperIdKey++-- Other classes, needed for type defaulting+monadPlusClassName, randomClassName, randomGenClassName,+ isStringClassName :: Name+monadPlusClassName = clsQual mONAD (fsLit "MonadPlus") monadPlusClassKey+randomClassName = clsQual rANDOM (fsLit "Random") randomClassKey+randomGenClassName = clsQual rANDOM (fsLit "RandomGen") randomGenClassKey+isStringClassName = clsQual dATA_STRING (fsLit "IsString") isStringClassKey++-- Type-level naturals+knownNatClassName :: Name+knownNatClassName = clsQual gHC_TYPENATS (fsLit "KnownNat") knownNatClassNameKey+knownSymbolClassName :: Name+knownSymbolClassName = clsQual gHC_TYPELITS (fsLit "KnownSymbol") knownSymbolClassNameKey++-- Overloaded labels+isLabelClassName :: Name+isLabelClassName+ = clsQual gHC_OVER_LABELS (fsLit "IsLabel") isLabelClassNameKey++-- Implicit Parameters+ipClassName :: Name+ipClassName+ = clsQual gHC_CLASSES (fsLit "IP") ipClassKey++-- Overloaded record fields+hasFieldClassName :: Name+hasFieldClassName+ = clsQual gHC_RECORDS (fsLit "HasField") hasFieldClassNameKey++-- Source Locations+callStackTyConName, emptyCallStackName, pushCallStackName,+ srcLocDataConName :: Name+callStackTyConName+ = tcQual gHC_STACK_TYPES (fsLit "CallStack") callStackTyConKey+emptyCallStackName+ = varQual gHC_STACK_TYPES (fsLit "emptyCallStack") emptyCallStackKey+pushCallStackName+ = varQual gHC_STACK_TYPES (fsLit "pushCallStack") pushCallStackKey+srcLocDataConName+ = dcQual gHC_STACK_TYPES (fsLit "SrcLoc") srcLocDataConKey++-- plugins+pLUGINS :: Module+pLUGINS = mkThisGhcModule (fsLit "Plugins")+pluginTyConName :: Name+pluginTyConName = tcQual pLUGINS (fsLit "Plugin") pluginTyConKey+frontendPluginTyConName :: Name+frontendPluginTyConName = tcQual pLUGINS (fsLit "FrontendPlugin") frontendPluginTyConKey++-- Static pointers+makeStaticName :: Name+makeStaticName =+ varQual gHC_STATICPTR_INTERNAL (fsLit "makeStatic") makeStaticKey++staticPtrInfoTyConName :: Name+staticPtrInfoTyConName =+ tcQual gHC_STATICPTR (fsLit "StaticPtrInfo") staticPtrInfoTyConKey++staticPtrInfoDataConName :: Name+staticPtrInfoDataConName =+ dcQual gHC_STATICPTR (fsLit "StaticPtrInfo") staticPtrInfoDataConKey++staticPtrTyConName :: Name+staticPtrTyConName =+ tcQual gHC_STATICPTR (fsLit "StaticPtr") staticPtrTyConKey++staticPtrDataConName :: Name+staticPtrDataConName =+ dcQual gHC_STATICPTR (fsLit "StaticPtr") staticPtrDataConKey++fromStaticPtrName :: Name+fromStaticPtrName =+ varQual gHC_STATICPTR (fsLit "fromStaticPtr") fromStaticPtrClassOpKey++fingerprintDataConName :: Name+fingerprintDataConName =+ dcQual gHC_FINGERPRINT_TYPE (fsLit "Fingerprint") fingerprintDataConKey++-- homogeneous equality. See Note [The equality types story] in TysPrim+eqTyConName :: Name+eqTyConName = tcQual dATA_TYPE_EQUALITY (fsLit "~") eqTyConKey++{-+************************************************************************+* *+\subsection{Local helpers}+* *+************************************************************************++All these are original names; hence mkOrig+-}++varQual, tcQual, clsQual, dcQual :: Module -> FastString -> Unique -> Name+varQual = mk_known_key_name varName+tcQual = mk_known_key_name tcName+clsQual = mk_known_key_name clsName+dcQual = mk_known_key_name dataName++mk_known_key_name :: NameSpace -> Module -> FastString -> Unique -> Name+mk_known_key_name space modu str unique+ = mkExternalName unique modu (mkOccNameFS space str) noSrcSpan+++{-+************************************************************************+* *+\subsubsection[Uniques-prelude-Classes]{@Uniques@ for wired-in @Classes@}+* *+************************************************************************+--MetaHaskell extension hand allocate keys here+-}++boundedClassKey, enumClassKey, eqClassKey, floatingClassKey,+ fractionalClassKey, integralClassKey, monadClassKey, dataClassKey,+ functorClassKey, numClassKey, ordClassKey, readClassKey, realClassKey,+ realFloatClassKey, realFracClassKey, showClassKey, ixClassKey :: Unique+boundedClassKey = mkPreludeClassUnique 1+enumClassKey = mkPreludeClassUnique 2+eqClassKey = mkPreludeClassUnique 3+floatingClassKey = mkPreludeClassUnique 5+fractionalClassKey = mkPreludeClassUnique 6+integralClassKey = mkPreludeClassUnique 7+monadClassKey = mkPreludeClassUnique 8+dataClassKey = mkPreludeClassUnique 9+functorClassKey = mkPreludeClassUnique 10+numClassKey = mkPreludeClassUnique 11+ordClassKey = mkPreludeClassUnique 12+readClassKey = mkPreludeClassUnique 13+realClassKey = mkPreludeClassUnique 14+realFloatClassKey = mkPreludeClassUnique 15+realFracClassKey = mkPreludeClassUnique 16+showClassKey = mkPreludeClassUnique 17+ixClassKey = mkPreludeClassUnique 18++typeableClassKey, typeable1ClassKey, typeable2ClassKey, typeable3ClassKey,+ typeable4ClassKey, typeable5ClassKey, typeable6ClassKey, typeable7ClassKey+ :: Unique+typeableClassKey = mkPreludeClassUnique 20+typeable1ClassKey = mkPreludeClassUnique 21+typeable2ClassKey = mkPreludeClassUnique 22+typeable3ClassKey = mkPreludeClassUnique 23+typeable4ClassKey = mkPreludeClassUnique 24+typeable5ClassKey = mkPreludeClassUnique 25+typeable6ClassKey = mkPreludeClassUnique 26+typeable7ClassKey = mkPreludeClassUnique 27++monadFixClassKey :: Unique+monadFixClassKey = mkPreludeClassUnique 28++monadFailClassKey :: Unique+monadFailClassKey = mkPreludeClassUnique 29++monadPlusClassKey, randomClassKey, randomGenClassKey :: Unique+monadPlusClassKey = mkPreludeClassUnique 30+randomClassKey = mkPreludeClassUnique 31+randomGenClassKey = mkPreludeClassUnique 32++isStringClassKey :: Unique+isStringClassKey = mkPreludeClassUnique 33++applicativeClassKey, foldableClassKey, traversableClassKey :: Unique+applicativeClassKey = mkPreludeClassUnique 34+foldableClassKey = mkPreludeClassUnique 35+traversableClassKey = mkPreludeClassUnique 36++genClassKey, gen1ClassKey, datatypeClassKey, constructorClassKey,+ selectorClassKey :: Unique+genClassKey = mkPreludeClassUnique 37+gen1ClassKey = mkPreludeClassUnique 38++datatypeClassKey = mkPreludeClassUnique 39+constructorClassKey = mkPreludeClassUnique 40+selectorClassKey = mkPreludeClassUnique 41++-- KnownNat: see Note [KnowNat & KnownSymbol and EvLit] in TcEvidence+knownNatClassNameKey :: Unique+knownNatClassNameKey = mkPreludeClassUnique 42++-- KnownSymbol: see Note [KnownNat & KnownSymbol and EvLit] in TcEvidence+knownSymbolClassNameKey :: Unique+knownSymbolClassNameKey = mkPreludeClassUnique 43++ghciIoClassKey :: Unique+ghciIoClassKey = mkPreludeClassUnique 44++isLabelClassNameKey :: Unique+isLabelClassNameKey = mkPreludeClassUnique 45++semigroupClassKey, monoidClassKey :: Unique+semigroupClassKey = mkPreludeClassUnique 46+monoidClassKey = mkPreludeClassUnique 47++-- Implicit Parameters+ipClassKey :: Unique+ipClassKey = mkPreludeClassUnique 48++-- Overloaded record fields+hasFieldClassNameKey :: Unique+hasFieldClassNameKey = mkPreludeClassUnique 49+++---------------- Template Haskell -------------------+-- THNames.hs: USES ClassUniques 200-299+-----------------------------------------------------++{-+************************************************************************+* *+\subsubsection[Uniques-prelude-TyCons]{@Uniques@ for wired-in @TyCons@}+* *+************************************************************************+-}++addrPrimTyConKey, arrayPrimTyConKey, arrayArrayPrimTyConKey, boolTyConKey,+ byteArrayPrimTyConKey, charPrimTyConKey, charTyConKey, doublePrimTyConKey,+ doubleTyConKey, floatPrimTyConKey, floatTyConKey, funTyConKey,+ intPrimTyConKey, intTyConKey, int8TyConKey, int16TyConKey,+ int32PrimTyConKey, int32TyConKey, int64PrimTyConKey, int64TyConKey,+ integerTyConKey, naturalTyConKey,+ listTyConKey, foreignObjPrimTyConKey, maybeTyConKey,+ weakPrimTyConKey, mutableArrayPrimTyConKey, mutableArrayArrayPrimTyConKey,+ mutableByteArrayPrimTyConKey, orderingTyConKey, mVarPrimTyConKey,+ ratioTyConKey, rationalTyConKey, realWorldTyConKey, stablePtrPrimTyConKey,+ stablePtrTyConKey, eqTyConKey, heqTyConKey,+ smallArrayPrimTyConKey, smallMutableArrayPrimTyConKey :: Unique+addrPrimTyConKey = mkPreludeTyConUnique 1+arrayPrimTyConKey = mkPreludeTyConUnique 3+boolTyConKey = mkPreludeTyConUnique 4+byteArrayPrimTyConKey = mkPreludeTyConUnique 5+charPrimTyConKey = mkPreludeTyConUnique 7+charTyConKey = mkPreludeTyConUnique 8+doublePrimTyConKey = mkPreludeTyConUnique 9+doubleTyConKey = mkPreludeTyConUnique 10+floatPrimTyConKey = mkPreludeTyConUnique 11+floatTyConKey = mkPreludeTyConUnique 12+funTyConKey = mkPreludeTyConUnique 13+intPrimTyConKey = mkPreludeTyConUnique 14+intTyConKey = mkPreludeTyConUnique 15+int8TyConKey = mkPreludeTyConUnique 16+int16TyConKey = mkPreludeTyConUnique 17+int32PrimTyConKey = mkPreludeTyConUnique 18+int32TyConKey = mkPreludeTyConUnique 19+int64PrimTyConKey = mkPreludeTyConUnique 20+int64TyConKey = mkPreludeTyConUnique 21+integerTyConKey = mkPreludeTyConUnique 22+naturalTyConKey = mkPreludeTyConUnique 23++listTyConKey = mkPreludeTyConUnique 24+foreignObjPrimTyConKey = mkPreludeTyConUnique 25+maybeTyConKey = mkPreludeTyConUnique 26+weakPrimTyConKey = mkPreludeTyConUnique 27+mutableArrayPrimTyConKey = mkPreludeTyConUnique 28+mutableByteArrayPrimTyConKey = mkPreludeTyConUnique 29+orderingTyConKey = mkPreludeTyConUnique 30+mVarPrimTyConKey = mkPreludeTyConUnique 31+ratioTyConKey = mkPreludeTyConUnique 32+rationalTyConKey = mkPreludeTyConUnique 33+realWorldTyConKey = mkPreludeTyConUnique 34+stablePtrPrimTyConKey = mkPreludeTyConUnique 35+stablePtrTyConKey = mkPreludeTyConUnique 36+eqTyConKey = mkPreludeTyConUnique 38+heqTyConKey = mkPreludeTyConUnique 39+arrayArrayPrimTyConKey = mkPreludeTyConUnique 40+mutableArrayArrayPrimTyConKey = mkPreludeTyConUnique 41++statePrimTyConKey, stableNamePrimTyConKey, stableNameTyConKey,+ mutVarPrimTyConKey, ioTyConKey,+ wordPrimTyConKey, wordTyConKey, word8TyConKey, word16TyConKey,+ word32PrimTyConKey, word32TyConKey, word64PrimTyConKey, word64TyConKey,+ liftedConKey, unliftedConKey, anyBoxConKey, kindConKey, boxityConKey,+ typeConKey, threadIdPrimTyConKey, bcoPrimTyConKey, ptrTyConKey,+ funPtrTyConKey, tVarPrimTyConKey, eqPrimTyConKey,+ eqReprPrimTyConKey, eqPhantPrimTyConKey, voidPrimTyConKey,+ compactPrimTyConKey :: Unique+statePrimTyConKey = mkPreludeTyConUnique 50+stableNamePrimTyConKey = mkPreludeTyConUnique 51+stableNameTyConKey = mkPreludeTyConUnique 52+eqPrimTyConKey = mkPreludeTyConUnique 53+eqReprPrimTyConKey = mkPreludeTyConUnique 54+eqPhantPrimTyConKey = mkPreludeTyConUnique 55+mutVarPrimTyConKey = mkPreludeTyConUnique 56+ioTyConKey = mkPreludeTyConUnique 57+voidPrimTyConKey = mkPreludeTyConUnique 58+wordPrimTyConKey = mkPreludeTyConUnique 59+wordTyConKey = mkPreludeTyConUnique 60+word8TyConKey = mkPreludeTyConUnique 61+word16TyConKey = mkPreludeTyConUnique 62+word32PrimTyConKey = mkPreludeTyConUnique 63+word32TyConKey = mkPreludeTyConUnique 64+word64PrimTyConKey = mkPreludeTyConUnique 65+word64TyConKey = mkPreludeTyConUnique 66+liftedConKey = mkPreludeTyConUnique 67+unliftedConKey = mkPreludeTyConUnique 68+anyBoxConKey = mkPreludeTyConUnique 69+kindConKey = mkPreludeTyConUnique 70+boxityConKey = mkPreludeTyConUnique 71+typeConKey = mkPreludeTyConUnique 72+threadIdPrimTyConKey = mkPreludeTyConUnique 73+bcoPrimTyConKey = mkPreludeTyConUnique 74+ptrTyConKey = mkPreludeTyConUnique 75+funPtrTyConKey = mkPreludeTyConUnique 76+tVarPrimTyConKey = mkPreludeTyConUnique 77+compactPrimTyConKey = mkPreludeTyConUnique 78++-- Parallel array type constructor+parrTyConKey :: Unique+parrTyConKey = mkPreludeTyConUnique 82++-- dotnet interop+objectTyConKey :: Unique+objectTyConKey = mkPreludeTyConUnique 83++eitherTyConKey :: Unique+eitherTyConKey = mkPreludeTyConUnique 84++-- Kind constructors+liftedTypeKindTyConKey, tYPETyConKey,+ constraintKindTyConKey,+ starKindTyConKey, unicodeStarKindTyConKey, runtimeRepTyConKey,+ vecCountTyConKey, vecElemTyConKey :: Unique+liftedTypeKindTyConKey = mkPreludeTyConUnique 87+tYPETyConKey = mkPreludeTyConUnique 88+constraintKindTyConKey = mkPreludeTyConUnique 92+starKindTyConKey = mkPreludeTyConUnique 93+unicodeStarKindTyConKey = mkPreludeTyConUnique 94+runtimeRepTyConKey = mkPreludeTyConUnique 95+vecCountTyConKey = mkPreludeTyConUnique 96+vecElemTyConKey = mkPreludeTyConUnique 97++pluginTyConKey, frontendPluginTyConKey :: Unique+pluginTyConKey = mkPreludeTyConUnique 102+frontendPluginTyConKey = mkPreludeTyConUnique 103++unknownTyConKey, unknown1TyConKey, unknown2TyConKey, unknown3TyConKey,+ opaqueTyConKey :: Unique+unknownTyConKey = mkPreludeTyConUnique 129+unknown1TyConKey = mkPreludeTyConUnique 130+unknown2TyConKey = mkPreludeTyConUnique 131+unknown3TyConKey = mkPreludeTyConUnique 132+opaqueTyConKey = mkPreludeTyConUnique 133++-- Generics (Unique keys)+v1TyConKey, u1TyConKey, par1TyConKey, rec1TyConKey,+ k1TyConKey, m1TyConKey, sumTyConKey, prodTyConKey,+ compTyConKey, rTyConKey, dTyConKey,+ cTyConKey, sTyConKey, rec0TyConKey,+ d1TyConKey, c1TyConKey, s1TyConKey, noSelTyConKey,+ repTyConKey, rep1TyConKey, uRecTyConKey,+ uAddrTyConKey, uCharTyConKey, uDoubleTyConKey,+ uFloatTyConKey, uIntTyConKey, uWordTyConKey :: Unique++v1TyConKey = mkPreludeTyConUnique 135+u1TyConKey = mkPreludeTyConUnique 136+par1TyConKey = mkPreludeTyConUnique 137+rec1TyConKey = mkPreludeTyConUnique 138+k1TyConKey = mkPreludeTyConUnique 139+m1TyConKey = mkPreludeTyConUnique 140++sumTyConKey = mkPreludeTyConUnique 141+prodTyConKey = mkPreludeTyConUnique 142+compTyConKey = mkPreludeTyConUnique 143++rTyConKey = mkPreludeTyConUnique 144+dTyConKey = mkPreludeTyConUnique 146+cTyConKey = mkPreludeTyConUnique 147+sTyConKey = mkPreludeTyConUnique 148++rec0TyConKey = mkPreludeTyConUnique 149+d1TyConKey = mkPreludeTyConUnique 151+c1TyConKey = mkPreludeTyConUnique 152+s1TyConKey = mkPreludeTyConUnique 153+noSelTyConKey = mkPreludeTyConUnique 154++repTyConKey = mkPreludeTyConUnique 155+rep1TyConKey = mkPreludeTyConUnique 156++uRecTyConKey = mkPreludeTyConUnique 157+uAddrTyConKey = mkPreludeTyConUnique 158+uCharTyConKey = mkPreludeTyConUnique 159+uDoubleTyConKey = mkPreludeTyConUnique 160+uFloatTyConKey = mkPreludeTyConUnique 161+uIntTyConKey = mkPreludeTyConUnique 162+uWordTyConKey = mkPreludeTyConUnique 163++-- Type-level naturals+typeNatKindConNameKey, typeSymbolKindConNameKey,+ typeNatAddTyFamNameKey, typeNatMulTyFamNameKey, typeNatExpTyFamNameKey,+ typeNatLeqTyFamNameKey, typeNatSubTyFamNameKey+ , typeSymbolCmpTyFamNameKey, typeNatCmpTyFamNameKey+ :: Unique+typeNatKindConNameKey = mkPreludeTyConUnique 164+typeSymbolKindConNameKey = mkPreludeTyConUnique 165+typeNatAddTyFamNameKey = mkPreludeTyConUnique 166+typeNatMulTyFamNameKey = mkPreludeTyConUnique 167+typeNatExpTyFamNameKey = mkPreludeTyConUnique 168+typeNatLeqTyFamNameKey = mkPreludeTyConUnique 169+typeNatSubTyFamNameKey = mkPreludeTyConUnique 170+typeSymbolCmpTyFamNameKey = mkPreludeTyConUnique 171+typeNatCmpTyFamNameKey = mkPreludeTyConUnique 172++-- Custom user type-errors+errorMessageTypeErrorFamKey :: Unique+errorMessageTypeErrorFamKey = mkPreludeTyConUnique 173++++ntTyConKey:: Unique+ntTyConKey = mkPreludeTyConUnique 174+coercibleTyConKey :: Unique+coercibleTyConKey = mkPreludeTyConUnique 175++proxyPrimTyConKey :: Unique+proxyPrimTyConKey = mkPreludeTyConUnique 176++specTyConKey :: Unique+specTyConKey = mkPreludeTyConUnique 177++anyTyConKey :: Unique+anyTyConKey = mkPreludeTyConUnique 178++smallArrayPrimTyConKey = mkPreludeTyConUnique 179+smallMutableArrayPrimTyConKey = mkPreludeTyConUnique 180++staticPtrTyConKey :: Unique+staticPtrTyConKey = mkPreludeTyConUnique 181++staticPtrInfoTyConKey :: Unique+staticPtrInfoTyConKey = mkPreludeTyConUnique 182++callStackTyConKey :: Unique+callStackTyConKey = mkPreludeTyConUnique 183++-- Typeables+typeRepTyConKey, someTypeRepTyConKey, someTypeRepDataConKey :: Unique+typeRepTyConKey = mkPreludeTyConUnique 184+someTypeRepTyConKey = mkPreludeTyConUnique 185+someTypeRepDataConKey = mkPreludeTyConUnique 186+++typeSymbolAppendFamNameKey :: Unique+typeSymbolAppendFamNameKey = mkPreludeTyConUnique 187++---------------- Template Haskell -------------------+-- THNames.hs: USES TyConUniques 200-299+-----------------------------------------------------++----------------------- SIMD ------------------------+-- USES TyConUniques 300-399+-----------------------------------------------------++#include "primop-vector-uniques.hs-incl"++{-+************************************************************************+* *+\subsubsection[Uniques-prelude-DataCons]{@Uniques@ for wired-in @DataCons@}+* *+************************************************************************+-}++charDataConKey, consDataConKey, doubleDataConKey, falseDataConKey,+ floatDataConKey, intDataConKey, integerSDataConKey, nilDataConKey,+ ratioDataConKey, stableNameDataConKey, trueDataConKey, wordDataConKey,+ word8DataConKey, ioDataConKey, integerDataConKey, heqDataConKey,+ coercibleDataConKey, nothingDataConKey, justDataConKey :: Unique++charDataConKey = mkPreludeDataConUnique 1+consDataConKey = mkPreludeDataConUnique 2+doubleDataConKey = mkPreludeDataConUnique 3+falseDataConKey = mkPreludeDataConUnique 4+floatDataConKey = mkPreludeDataConUnique 5+intDataConKey = mkPreludeDataConUnique 6+integerSDataConKey = mkPreludeDataConUnique 7+nothingDataConKey = mkPreludeDataConUnique 8+justDataConKey = mkPreludeDataConUnique 9+nilDataConKey = mkPreludeDataConUnique 11+ratioDataConKey = mkPreludeDataConUnique 12+word8DataConKey = mkPreludeDataConUnique 13+stableNameDataConKey = mkPreludeDataConUnique 14+trueDataConKey = mkPreludeDataConUnique 15+wordDataConKey = mkPreludeDataConUnique 16+ioDataConKey = mkPreludeDataConUnique 17+integerDataConKey = mkPreludeDataConUnique 18+heqDataConKey = mkPreludeDataConUnique 19++-- Generic data constructors+crossDataConKey, inlDataConKey, inrDataConKey, genUnitDataConKey :: Unique+crossDataConKey = mkPreludeDataConUnique 20+inlDataConKey = mkPreludeDataConUnique 21+inrDataConKey = mkPreludeDataConUnique 22+genUnitDataConKey = mkPreludeDataConUnique 23++-- Data constructor for parallel arrays+parrDataConKey :: Unique+parrDataConKey = mkPreludeDataConUnique 24++leftDataConKey, rightDataConKey :: Unique+leftDataConKey = mkPreludeDataConUnique 25+rightDataConKey = mkPreludeDataConUnique 26++ltDataConKey, eqDataConKey, gtDataConKey :: Unique+ltDataConKey = mkPreludeDataConUnique 27+eqDataConKey = mkPreludeDataConUnique 28+gtDataConKey = mkPreludeDataConUnique 29++coercibleDataConKey = mkPreludeDataConUnique 32++staticPtrDataConKey :: Unique+staticPtrDataConKey = mkPreludeDataConUnique 33++staticPtrInfoDataConKey :: Unique+staticPtrInfoDataConKey = mkPreludeDataConUnique 34++fingerprintDataConKey :: Unique+fingerprintDataConKey = mkPreludeDataConUnique 35++srcLocDataConKey :: Unique+srcLocDataConKey = mkPreludeDataConUnique 37++trTyConTyConKey, trTyConDataConKey,+ trModuleTyConKey, trModuleDataConKey,+ trNameTyConKey, trNameSDataConKey, trNameDDataConKey,+ trGhcPrimModuleKey, kindRepTyConKey,+ typeLitSortTyConKey :: Unique+trTyConTyConKey = mkPreludeDataConUnique 40+trTyConDataConKey = mkPreludeDataConUnique 41+trModuleTyConKey = mkPreludeDataConUnique 42+trModuleDataConKey = mkPreludeDataConUnique 43+trNameTyConKey = mkPreludeDataConUnique 44+trNameSDataConKey = mkPreludeDataConUnique 45+trNameDDataConKey = mkPreludeDataConUnique 46+trGhcPrimModuleKey = mkPreludeDataConUnique 47+kindRepTyConKey = mkPreludeDataConUnique 48+typeLitSortTyConKey = mkPreludeDataConUnique 49++typeErrorTextDataConKey,+ typeErrorAppendDataConKey,+ typeErrorVAppendDataConKey,+ typeErrorShowTypeDataConKey+ :: Unique+typeErrorTextDataConKey = mkPreludeDataConUnique 50+typeErrorAppendDataConKey = mkPreludeDataConUnique 51+typeErrorVAppendDataConKey = mkPreludeDataConUnique 52+typeErrorShowTypeDataConKey = mkPreludeDataConUnique 53++prefixIDataConKey, infixIDataConKey, leftAssociativeDataConKey,+ rightAssociativeDataConKey, notAssociativeDataConKey,+ sourceUnpackDataConKey, sourceNoUnpackDataConKey,+ noSourceUnpackednessDataConKey, sourceLazyDataConKey,+ sourceStrictDataConKey, noSourceStrictnessDataConKey,+ decidedLazyDataConKey, decidedStrictDataConKey, decidedUnpackDataConKey,+ metaDataDataConKey, metaConsDataConKey, metaSelDataConKey :: Unique+prefixIDataConKey = mkPreludeDataConUnique 54+infixIDataConKey = mkPreludeDataConUnique 55+leftAssociativeDataConKey = mkPreludeDataConUnique 56+rightAssociativeDataConKey = mkPreludeDataConUnique 57+notAssociativeDataConKey = mkPreludeDataConUnique 58+sourceUnpackDataConKey = mkPreludeDataConUnique 59+sourceNoUnpackDataConKey = mkPreludeDataConUnique 60+noSourceUnpackednessDataConKey = mkPreludeDataConUnique 61+sourceLazyDataConKey = mkPreludeDataConUnique 62+sourceStrictDataConKey = mkPreludeDataConUnique 63+noSourceStrictnessDataConKey = mkPreludeDataConUnique 64+decidedLazyDataConKey = mkPreludeDataConUnique 65+decidedStrictDataConKey = mkPreludeDataConUnique 66+decidedUnpackDataConKey = mkPreludeDataConUnique 67+metaDataDataConKey = mkPreludeDataConUnique 68+metaConsDataConKey = mkPreludeDataConUnique 69+metaSelDataConKey = mkPreludeDataConUnique 70++vecRepDataConKey, tupleRepDataConKey, sumRepDataConKey :: Unique+vecRepDataConKey = mkPreludeDataConUnique 71+tupleRepDataConKey = mkPreludeDataConUnique 72+sumRepDataConKey = mkPreludeDataConUnique 73++-- See Note [Wiring in RuntimeRep] in TysWiredIn+runtimeRepSimpleDataConKeys :: [Unique]+liftedRepDataConKey :: Unique+runtimeRepSimpleDataConKeys@(+ liftedRepDataConKey : _)+ = map mkPreludeDataConUnique [74..82]++-- See Note [Wiring in RuntimeRep] in TysWiredIn+-- VecCount+vecCountDataConKeys :: [Unique]+vecCountDataConKeys = map mkPreludeDataConUnique [83..88]++-- See Note [Wiring in RuntimeRep] in TysWiredIn+-- VecElem+vecElemDataConKeys :: [Unique]+vecElemDataConKeys = map mkPreludeDataConUnique [89..98]++-- Typeable things+kindRepTyConAppDataConKey, kindRepVarDataConKey, kindRepAppDataConKey,+ kindRepFunDataConKey, kindRepTYPEDataConKey,+ kindRepTypeLitSDataConKey, kindRepTypeLitDDataConKey+ :: Unique+kindRepTyConAppDataConKey = mkPreludeDataConUnique 100+kindRepVarDataConKey = mkPreludeDataConUnique 101+kindRepAppDataConKey = mkPreludeDataConUnique 102+kindRepFunDataConKey = mkPreludeDataConUnique 103+kindRepTYPEDataConKey = mkPreludeDataConUnique 104+kindRepTypeLitSDataConKey = mkPreludeDataConUnique 105+kindRepTypeLitDDataConKey = mkPreludeDataConUnique 106++typeLitSymbolDataConKey, typeLitNatDataConKey :: Unique+typeLitSymbolDataConKey = mkPreludeDataConUnique 107+typeLitNatDataConKey = mkPreludeDataConUnique 108+++---------------- Template Haskell -------------------+-- THNames.hs: USES DataUniques 200-250+-----------------------------------------------------+++{-+************************************************************************+* *+\subsubsection[Uniques-prelude-Ids]{@Uniques@ for wired-in @Ids@ (except @DataCons@)}+* *+************************************************************************+-}++wildCardKey, absentErrorIdKey, augmentIdKey, appendIdKey,+ buildIdKey, errorIdKey, foldrIdKey, recSelErrorIdKey,+ seqIdKey, irrefutPatErrorIdKey, eqStringIdKey,+ noMethodBindingErrorIdKey, nonExhaustiveGuardsErrorIdKey,+ runtimeErrorIdKey, patErrorIdKey, voidPrimIdKey,+ realWorldPrimIdKey, recConErrorIdKey,+ unpackCStringUtf8IdKey, unpackCStringAppendIdKey,+ unpackCStringFoldrIdKey, unpackCStringIdKey,+ typeErrorIdKey, divIntIdKey, modIntIdKey :: Unique++wildCardKey = mkPreludeMiscIdUnique 0 -- See Note [WildCard binders]+absentErrorIdKey = mkPreludeMiscIdUnique 1+augmentIdKey = mkPreludeMiscIdUnique 2+appendIdKey = mkPreludeMiscIdUnique 3+buildIdKey = mkPreludeMiscIdUnique 4+errorIdKey = mkPreludeMiscIdUnique 5+foldrIdKey = mkPreludeMiscIdUnique 6+recSelErrorIdKey = mkPreludeMiscIdUnique 7+seqIdKey = mkPreludeMiscIdUnique 8+irrefutPatErrorIdKey = mkPreludeMiscIdUnique 9+eqStringIdKey = mkPreludeMiscIdUnique 10+noMethodBindingErrorIdKey = mkPreludeMiscIdUnique 11+nonExhaustiveGuardsErrorIdKey = mkPreludeMiscIdUnique 12+runtimeErrorIdKey = mkPreludeMiscIdUnique 13+patErrorIdKey = mkPreludeMiscIdUnique 14+realWorldPrimIdKey = mkPreludeMiscIdUnique 15+recConErrorIdKey = mkPreludeMiscIdUnique 16+unpackCStringUtf8IdKey = mkPreludeMiscIdUnique 17+unpackCStringAppendIdKey = mkPreludeMiscIdUnique 18+unpackCStringFoldrIdKey = mkPreludeMiscIdUnique 19+unpackCStringIdKey = mkPreludeMiscIdUnique 20+voidPrimIdKey = mkPreludeMiscIdUnique 21+typeErrorIdKey = mkPreludeMiscIdUnique 22+divIntIdKey = mkPreludeMiscIdUnique 23+modIntIdKey = mkPreludeMiscIdUnique 24++unsafeCoerceIdKey, concatIdKey, filterIdKey, zipIdKey, bindIOIdKey,+ returnIOIdKey, newStablePtrIdKey,+ printIdKey, failIOIdKey, nullAddrIdKey, voidArgIdKey,+ fstIdKey, sndIdKey, otherwiseIdKey, assertIdKey :: Unique+unsafeCoerceIdKey = mkPreludeMiscIdUnique 30+concatIdKey = mkPreludeMiscIdUnique 31+filterIdKey = mkPreludeMiscIdUnique 32+zipIdKey = mkPreludeMiscIdUnique 33+bindIOIdKey = mkPreludeMiscIdUnique 34+returnIOIdKey = mkPreludeMiscIdUnique 35+newStablePtrIdKey = mkPreludeMiscIdUnique 36+printIdKey = mkPreludeMiscIdUnique 37+failIOIdKey = mkPreludeMiscIdUnique 38+nullAddrIdKey = mkPreludeMiscIdUnique 39+voidArgIdKey = mkPreludeMiscIdUnique 40+fstIdKey = mkPreludeMiscIdUnique 41+sndIdKey = mkPreludeMiscIdUnique 42+otherwiseIdKey = mkPreludeMiscIdUnique 43+assertIdKey = mkPreludeMiscIdUnique 44++mkIntegerIdKey, smallIntegerIdKey, wordToIntegerIdKey,+ integerToWordIdKey, integerToIntIdKey,+ integerToWord64IdKey, integerToInt64IdKey,+ word64ToIntegerIdKey, int64ToIntegerIdKey,+ plusIntegerIdKey, timesIntegerIdKey, minusIntegerIdKey,+ negateIntegerIdKey,+ eqIntegerPrimIdKey, neqIntegerPrimIdKey, absIntegerIdKey, signumIntegerIdKey,+ leIntegerPrimIdKey, gtIntegerPrimIdKey, ltIntegerPrimIdKey, geIntegerPrimIdKey,+ compareIntegerIdKey, quotRemIntegerIdKey, divModIntegerIdKey,+ quotIntegerIdKey, remIntegerIdKey, divIntegerIdKey, modIntegerIdKey,+ floatFromIntegerIdKey, doubleFromIntegerIdKey,+ encodeFloatIntegerIdKey, encodeDoubleIntegerIdKey,+ decodeDoubleIntegerIdKey,+ gcdIntegerIdKey, lcmIntegerIdKey,+ andIntegerIdKey, orIntegerIdKey, xorIntegerIdKey, complementIntegerIdKey,+ shiftLIntegerIdKey, shiftRIntegerIdKey :: Unique+mkIntegerIdKey = mkPreludeMiscIdUnique 60+smallIntegerIdKey = mkPreludeMiscIdUnique 61+integerToWordIdKey = mkPreludeMiscIdUnique 62+integerToIntIdKey = mkPreludeMiscIdUnique 63+integerToWord64IdKey = mkPreludeMiscIdUnique 64+integerToInt64IdKey = mkPreludeMiscIdUnique 65+plusIntegerIdKey = mkPreludeMiscIdUnique 66+timesIntegerIdKey = mkPreludeMiscIdUnique 67+minusIntegerIdKey = mkPreludeMiscIdUnique 68+negateIntegerIdKey = mkPreludeMiscIdUnique 69+eqIntegerPrimIdKey = mkPreludeMiscIdUnique 70+neqIntegerPrimIdKey = mkPreludeMiscIdUnique 71+absIntegerIdKey = mkPreludeMiscIdUnique 72+signumIntegerIdKey = mkPreludeMiscIdUnique 73+leIntegerPrimIdKey = mkPreludeMiscIdUnique 74+gtIntegerPrimIdKey = mkPreludeMiscIdUnique 75+ltIntegerPrimIdKey = mkPreludeMiscIdUnique 76+geIntegerPrimIdKey = mkPreludeMiscIdUnique 77+compareIntegerIdKey = mkPreludeMiscIdUnique 78+quotIntegerIdKey = mkPreludeMiscIdUnique 79+remIntegerIdKey = mkPreludeMiscIdUnique 80+divIntegerIdKey = mkPreludeMiscIdUnique 81+modIntegerIdKey = mkPreludeMiscIdUnique 82+divModIntegerIdKey = mkPreludeMiscIdUnique 83+quotRemIntegerIdKey = mkPreludeMiscIdUnique 84+floatFromIntegerIdKey = mkPreludeMiscIdUnique 85+doubleFromIntegerIdKey = mkPreludeMiscIdUnique 86+encodeFloatIntegerIdKey = mkPreludeMiscIdUnique 87+encodeDoubleIntegerIdKey = mkPreludeMiscIdUnique 88+gcdIntegerIdKey = mkPreludeMiscIdUnique 89+lcmIntegerIdKey = mkPreludeMiscIdUnique 90+andIntegerIdKey = mkPreludeMiscIdUnique 91+orIntegerIdKey = mkPreludeMiscIdUnique 92+xorIntegerIdKey = mkPreludeMiscIdUnique 93+complementIntegerIdKey = mkPreludeMiscIdUnique 94+shiftLIntegerIdKey = mkPreludeMiscIdUnique 95+shiftRIntegerIdKey = mkPreludeMiscIdUnique 96+wordToIntegerIdKey = mkPreludeMiscIdUnique 97+word64ToIntegerIdKey = mkPreludeMiscIdUnique 98+int64ToIntegerIdKey = mkPreludeMiscIdUnique 99+decodeDoubleIntegerIdKey = mkPreludeMiscIdUnique 100++rootMainKey, runMainKey :: Unique+rootMainKey = mkPreludeMiscIdUnique 101+runMainKey = mkPreludeMiscIdUnique 102++thenIOIdKey, lazyIdKey, assertErrorIdKey, oneShotKey, runRWKey :: Unique+thenIOIdKey = mkPreludeMiscIdUnique 103+lazyIdKey = mkPreludeMiscIdUnique 104+assertErrorIdKey = mkPreludeMiscIdUnique 105+oneShotKey = mkPreludeMiscIdUnique 106+runRWKey = mkPreludeMiscIdUnique 107++breakpointIdKey, breakpointCondIdKey, breakpointAutoIdKey,+ breakpointJumpIdKey, breakpointCondJumpIdKey,+ breakpointAutoJumpIdKey :: Unique+breakpointIdKey = mkPreludeMiscIdUnique 110+breakpointCondIdKey = mkPreludeMiscIdUnique 111+breakpointAutoIdKey = mkPreludeMiscIdUnique 112+breakpointJumpIdKey = mkPreludeMiscIdUnique 113+breakpointCondJumpIdKey = mkPreludeMiscIdUnique 114+breakpointAutoJumpIdKey = mkPreludeMiscIdUnique 115++inlineIdKey, noinlineIdKey :: Unique+inlineIdKey = mkPreludeMiscIdUnique 120+-- see below++mapIdKey, groupWithIdKey, dollarIdKey :: Unique+mapIdKey = mkPreludeMiscIdUnique 121+groupWithIdKey = mkPreludeMiscIdUnique 122+dollarIdKey = mkPreludeMiscIdUnique 123++coercionTokenIdKey :: Unique+coercionTokenIdKey = mkPreludeMiscIdUnique 124++noinlineIdKey = mkPreludeMiscIdUnique 125++rationalToFloatIdKey, rationalToDoubleIdKey :: Unique+rationalToFloatIdKey = mkPreludeMiscIdUnique 130+rationalToDoubleIdKey = mkPreludeMiscIdUnique 131++-- dotnet interop+unmarshalObjectIdKey, marshalObjectIdKey, marshalStringIdKey,+ unmarshalStringIdKey, checkDotnetResNameIdKey :: Unique+unmarshalObjectIdKey = mkPreludeMiscIdUnique 150+marshalObjectIdKey = mkPreludeMiscIdUnique 151+marshalStringIdKey = mkPreludeMiscIdUnique 152+unmarshalStringIdKey = mkPreludeMiscIdUnique 153+checkDotnetResNameIdKey = mkPreludeMiscIdUnique 154++undefinedKey :: Unique+undefinedKey = mkPreludeMiscIdUnique 155++magicDictKey :: Unique+magicDictKey = mkPreludeMiscIdUnique 156++coerceKey :: Unique+coerceKey = mkPreludeMiscIdUnique 157++{-+Certain class operations from Prelude classes. They get their own+uniques so we can look them up easily when we want to conjure them up+during type checking.+-}++-- Just a placeholder for unbound variables produced by the renamer:+unboundKey :: Unique+unboundKey = mkPreludeMiscIdUnique 158++fromIntegerClassOpKey, minusClassOpKey, fromRationalClassOpKey,+ enumFromClassOpKey, enumFromThenClassOpKey, enumFromToClassOpKey,+ enumFromThenToClassOpKey, eqClassOpKey, geClassOpKey, negateClassOpKey,+ failMClassOpKey_preMFP, bindMClassOpKey, thenMClassOpKey, returnMClassOpKey,+ fmapClassOpKey+ :: Unique+fromIntegerClassOpKey = mkPreludeMiscIdUnique 160+minusClassOpKey = mkPreludeMiscIdUnique 161+fromRationalClassOpKey = mkPreludeMiscIdUnique 162+enumFromClassOpKey = mkPreludeMiscIdUnique 163+enumFromThenClassOpKey = mkPreludeMiscIdUnique 164+enumFromToClassOpKey = mkPreludeMiscIdUnique 165+enumFromThenToClassOpKey = mkPreludeMiscIdUnique 166+eqClassOpKey = mkPreludeMiscIdUnique 167+geClassOpKey = mkPreludeMiscIdUnique 168+negateClassOpKey = mkPreludeMiscIdUnique 169+failMClassOpKey_preMFP = mkPreludeMiscIdUnique 170+bindMClassOpKey = mkPreludeMiscIdUnique 171 -- (>>=)+thenMClassOpKey = mkPreludeMiscIdUnique 172 -- (>>)+fmapClassOpKey = mkPreludeMiscIdUnique 173+returnMClassOpKey = mkPreludeMiscIdUnique 174++-- Recursive do notation+mfixIdKey :: Unique+mfixIdKey = mkPreludeMiscIdUnique 175++-- MonadFail operations+failMClassOpKey :: Unique+failMClassOpKey = mkPreludeMiscIdUnique 176++-- Arrow notation+arrAIdKey, composeAIdKey, firstAIdKey, appAIdKey, choiceAIdKey,+ loopAIdKey :: Unique+arrAIdKey = mkPreludeMiscIdUnique 180+composeAIdKey = mkPreludeMiscIdUnique 181 -- >>>+firstAIdKey = mkPreludeMiscIdUnique 182+appAIdKey = mkPreludeMiscIdUnique 183+choiceAIdKey = mkPreludeMiscIdUnique 184 -- |||+loopAIdKey = mkPreludeMiscIdUnique 185++fromStringClassOpKey :: Unique+fromStringClassOpKey = mkPreludeMiscIdUnique 186++-- Annotation type checking+toAnnotationWrapperIdKey :: Unique+toAnnotationWrapperIdKey = mkPreludeMiscIdUnique 187++-- Conversion functions+fromIntegralIdKey, realToFracIdKey, toIntegerClassOpKey, toRationalClassOpKey :: Unique+fromIntegralIdKey = mkPreludeMiscIdUnique 190+realToFracIdKey = mkPreludeMiscIdUnique 191+toIntegerClassOpKey = mkPreludeMiscIdUnique 192+toRationalClassOpKey = mkPreludeMiscIdUnique 193++-- Monad comprehensions+guardMIdKey, liftMIdKey, mzipIdKey :: Unique+guardMIdKey = mkPreludeMiscIdUnique 194+liftMIdKey = mkPreludeMiscIdUnique 195+mzipIdKey = mkPreludeMiscIdUnique 196++-- GHCi+ghciStepIoMClassOpKey :: Unique+ghciStepIoMClassOpKey = mkPreludeMiscIdUnique 197++-- Overloaded lists+isListClassKey, fromListClassOpKey, fromListNClassOpKey, toListClassOpKey :: Unique+isListClassKey = mkPreludeMiscIdUnique 198+fromListClassOpKey = mkPreludeMiscIdUnique 199+fromListNClassOpKey = mkPreludeMiscIdUnique 500+toListClassOpKey = mkPreludeMiscIdUnique 501++proxyHashKey :: Unique+proxyHashKey = mkPreludeMiscIdUnique 502++---------------- Template Haskell -------------------+-- THNames.hs: USES IdUniques 200-499+-----------------------------------------------------++-- Used to make `Typeable` dictionaries+mkTyConKey+ , mkTrConKey+ , mkTrAppKey+ , mkTrFunKey+ , typeNatTypeRepKey+ , typeSymbolTypeRepKey+ , typeRepIdKey+ :: Unique+mkTyConKey = mkPreludeMiscIdUnique 503+mkTrConKey = mkPreludeMiscIdUnique 504+mkTrAppKey = mkPreludeMiscIdUnique 505+typeNatTypeRepKey = mkPreludeMiscIdUnique 506+typeSymbolTypeRepKey = mkPreludeMiscIdUnique 507+typeRepIdKey = mkPreludeMiscIdUnique 508+mkTrFunKey = mkPreludeMiscIdUnique 509++-- Representations for primitive types+trTYPEKey+ ,trTYPE'PtrRepLiftedKey+ , trRuntimeRepKey+ , tr'PtrRepLiftedKey+ :: Unique+trTYPEKey = mkPreludeMiscIdUnique 510+trTYPE'PtrRepLiftedKey = mkPreludeMiscIdUnique 511+trRuntimeRepKey = mkPreludeMiscIdUnique 512+tr'PtrRepLiftedKey = mkPreludeMiscIdUnique 513++-- KindReps for common cases+starKindRepKey, starArrStarKindRepKey, starArrStarArrStarKindRepKey :: Unique+starKindRepKey = mkPreludeMiscIdUnique 520+starArrStarKindRepKey = mkPreludeMiscIdUnique 521+starArrStarArrStarKindRepKey = mkPreludeMiscIdUnique 522++-- Dynamic+toDynIdKey :: Unique+toDynIdKey = mkPreludeMiscIdUnique 550++bitIntegerIdKey :: Unique+bitIntegerIdKey = mkPreludeMiscIdUnique 551++heqSCSelIdKey, coercibleSCSelIdKey :: Unique+heqSCSelIdKey = mkPreludeMiscIdUnique 552+coercibleSCSelIdKey = mkPreludeMiscIdUnique 553++sappendClassOpKey :: Unique+sappendClassOpKey = mkPreludeMiscIdUnique 554++memptyClassOpKey, mappendClassOpKey, mconcatClassOpKey :: Unique+memptyClassOpKey = mkPreludeMiscIdUnique 555+mappendClassOpKey = mkPreludeMiscIdUnique 556+mconcatClassOpKey = mkPreludeMiscIdUnique 557++emptyCallStackKey, pushCallStackKey :: Unique+emptyCallStackKey = mkPreludeMiscIdUnique 558+pushCallStackKey = mkPreludeMiscIdUnique 559++fromStaticPtrClassOpKey :: Unique+fromStaticPtrClassOpKey = mkPreludeMiscIdUnique 560++makeStaticKey :: Unique+makeStaticKey = mkPreludeMiscIdUnique 561++-- Natural+naturalFromIntegerIdKey :: Unique+naturalFromIntegerIdKey = mkPreludeMiscIdUnique 562++{-+************************************************************************+* *+\subsection[Class-std-groups]{Standard groups of Prelude classes}+* *+************************************************************************++NOTE: @Eq@ and @Text@ do need to appear in @standardClasses@+even though every numeric class has these two as a superclass,+because the list of ambiguous dictionaries hasn't been simplified.+-}++numericClassKeys :: [Unique]+numericClassKeys =+ [ numClassKey+ , realClassKey+ , integralClassKey+ ]+ ++ fractionalClassKeys++fractionalClassKeys :: [Unique]+fractionalClassKeys =+ [ fractionalClassKey+ , floatingClassKey+ , realFracClassKey+ , realFloatClassKey+ ]++-- The "standard classes" are used in defaulting (Haskell 98 report 4.3.4),+-- and are: "classes defined in the Prelude or a standard library"+standardClassKeys :: [Unique]+standardClassKeys = derivableClassKeys ++ numericClassKeys+ ++ [randomClassKey, randomGenClassKey,+ functorClassKey,+ monadClassKey, monadPlusClassKey, monadFailClassKey,+ semigroupClassKey, monoidClassKey,+ isStringClassKey,+ applicativeClassKey, foldableClassKey,+ traversableClassKey, alternativeClassKey+ ]++{-+@derivableClassKeys@ is also used in checking \tr{deriving} constructs+(@TcDeriv@).+-}++derivableClassKeys :: [Unique]+derivableClassKeys+ = [ eqClassKey, ordClassKey, enumClassKey, ixClassKey,+ boundedClassKey, showClassKey, readClassKey ]+++-- These are the "interactive classes" that are consulted when doing+-- defaulting. Does not include Num or IsString, which have special+-- handling.+interactiveClassNames :: [Name]+interactiveClassNames+ = [ showClassName, eqClassName, ordClassName, foldableClassName+ , traversableClassName ]++interactiveClassKeys :: [Unique]+interactiveClassKeys = map getUnique interactiveClassNames++{-+************************************************************************+* *+ Semi-builtin names+* *+************************************************************************++The following names should be considered by GHCi to be in scope always.++-}++pretendNameIsInScope :: Name -> Bool+pretendNameIsInScope n+ = any (n `hasKey`)+ [ starKindTyConKey, liftedTypeKindTyConKey, tYPETyConKey+ , runtimeRepTyConKey, liftedRepDataConKey ]
+ prelude/PrelNames.hs-boot view
@@ -0,0 +1,8 @@+module PrelNames where++import Module+import Unique++mAIN :: Module+starKindTyConKey :: Unique+unicodeStarKindTyConKey :: Unique
+ prelude/PrelRules.hs view
@@ -0,0 +1,1477 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[ConFold]{Constant Folder}++Conceptually, constant folding should be parameterized with the kind+of target machine to get identical behaviour during compilation time+and runtime. We cheat a little bit here...++ToDo:+ check boundaries before folding, e.g. we can fold the Float addition+ (i1 + i2) only if it results in a valid Float.+-}++{-# LANGUAGE CPP, RankNTypes #-}+{-# OPTIONS_GHC -optc-DNON_POSIX_SOURCE #-}++module PrelRules+ ( primOpRules+ , builtinRules+ , caseRules+ )+where++#include "HsVersions.h"+#include "MachDeps.h"++import {-# SOURCE #-} MkId ( mkPrimOpId, magicDictId )++import CoreSyn+import MkCore+import Id+import Literal+import CoreOpt ( exprIsLiteral_maybe )+import PrimOp ( PrimOp(..), tagToEnumKey )+import TysWiredIn+import TysPrim+import TyCon ( tyConDataCons_maybe, isEnumerationTyCon, isNewTyCon, unwrapNewTyCon_maybe )+import DataCon ( dataConTag, dataConTyCon, dataConWorkId )+import CoreUtils ( cheapEqExpr, exprIsHNF )+import CoreUnfold ( exprIsConApp_maybe )+import Type+import OccName ( occNameFS )+import PrelNames+import Maybes ( orElse )+import Name ( Name, nameOccName )+import Outputable+import FastString+import BasicTypes+import DynFlags+import Platform+import Util+import Coercion (mkUnbranchedAxInstCo,mkSymCo,Role(..))++import Control.Applicative ( Alternative(..) )++import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif+import Data.Bits as Bits+import qualified Data.ByteString as BS+import Data.Int+import Data.Ratio+import Data.Word++{-+Note [Constant folding]+~~~~~~~~~~~~~~~~~~~~~~~+primOpRules generates a rewrite rule for each primop+These rules do what is often called "constant folding"+E.g. the rules for +# might say+ 4 +# 5 = 9+Well, of course you'd need a lot of rules if you did it+like that, so we use a BuiltinRule instead, so that we+can match in any two literal values. So the rule is really+more like+ (Lit x) +# (Lit y) = Lit (x+#y)+where the (+#) on the rhs is done at compile time++That is why these rules are built in here.+-}++primOpRules :: Name -> PrimOp -> Maybe CoreRule+ -- ToDo: something for integer-shift ops?+ -- NotOp+primOpRules nm TagToEnumOp = mkPrimOpRule nm 2 [ tagToEnumRule ]+primOpRules nm DataToTagOp = mkPrimOpRule nm 2 [ dataToTagRule ]++-- Int operations+primOpRules nm IntAddOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (+))+ , identityDynFlags zeroi ]+primOpRules nm IntSubOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (-))+ , rightIdentityDynFlags zeroi+ , equalArgs >> retLit zeroi ]+primOpRules nm IntMulOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (*))+ , zeroElem zeroi+ , identityDynFlags onei ]+primOpRules nm IntQuotOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 quot)+ , leftZero zeroi+ , rightIdentityDynFlags onei+ , equalArgs >> retLit onei ]+primOpRules nm IntRemOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (intOp2 rem)+ , leftZero zeroi+ , do l <- getLiteral 1+ dflags <- getDynFlags+ guard (l == onei dflags)+ retLit zeroi+ , equalArgs >> retLit zeroi+ , equalArgs >> retLit zeroi ]+primOpRules nm AndIOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (.&.))+ , idempotent+ , zeroElem zeroi ]+primOpRules nm OrIOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 (.|.))+ , idempotent+ , identityDynFlags zeroi ]+primOpRules nm XorIOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 xor)+ , identityDynFlags zeroi+ , equalArgs >> retLit zeroi ]+primOpRules nm NotIOp = mkPrimOpRule nm 1 [ unaryLit complementOp+ , inversePrimOp NotIOp ]+primOpRules nm IntNegOp = mkPrimOpRule nm 1 [ unaryLit negOp+ , inversePrimOp IntNegOp ]+primOpRules nm ISllOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 Bits.shiftL)+ , rightIdentityDynFlags zeroi ]+primOpRules nm ISraOp = mkPrimOpRule nm 2 [ binaryLit (intOp2 Bits.shiftR)+ , rightIdentityDynFlags zeroi ]+primOpRules nm ISrlOp = mkPrimOpRule nm 2 [ binaryLit (intOp2' shiftRightLogical)+ , rightIdentityDynFlags zeroi ]++-- Word operations+primOpRules nm WordAddOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (+))+ , identityDynFlags zerow ]+primOpRules nm WordSubOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (-))+ , rightIdentityDynFlags zerow+ , equalArgs >> retLit zerow ]+primOpRules nm WordMulOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (*))+ , identityDynFlags onew ]+primOpRules nm WordQuotOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 quot)+ , rightIdentityDynFlags onew ]+primOpRules nm WordRemOp = mkPrimOpRule nm 2 [ nonZeroLit 1 >> binaryLit (wordOp2 rem)+ , leftZero zerow+ , do l <- getLiteral 1+ dflags <- getDynFlags+ guard (l == onew dflags)+ retLit zerow+ , equalArgs >> retLit zerow ]+primOpRules nm AndOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.&.))+ , idempotent+ , zeroElem zerow ]+primOpRules nm OrOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 (.|.))+ , idempotent+ , identityDynFlags zerow ]+primOpRules nm XorOp = mkPrimOpRule nm 2 [ binaryLit (wordOp2 xor)+ , identityDynFlags zerow+ , equalArgs >> retLit zerow ]+primOpRules nm NotOp = mkPrimOpRule nm 1 [ unaryLit complementOp+ , inversePrimOp NotOp ]+primOpRules nm SllOp = mkPrimOpRule nm 2 [ wordShiftRule (const Bits.shiftL) ]+primOpRules nm SrlOp = mkPrimOpRule nm 2 [ wordShiftRule shiftRightLogical ]++-- coercions+primOpRules nm Word2IntOp = mkPrimOpRule nm 1 [ liftLitDynFlags word2IntLit+ , inversePrimOp Int2WordOp ]+primOpRules nm Int2WordOp = mkPrimOpRule nm 1 [ liftLitDynFlags int2WordLit+ , inversePrimOp Word2IntOp ]+primOpRules nm Narrow8IntOp = mkPrimOpRule nm 1 [ liftLit narrow8IntLit+ , subsumedByPrimOp Narrow8IntOp+ , Narrow8IntOp `subsumesPrimOp` Narrow16IntOp+ , Narrow8IntOp `subsumesPrimOp` Narrow32IntOp ]+primOpRules nm Narrow16IntOp = mkPrimOpRule nm 1 [ liftLit narrow16IntLit+ , subsumedByPrimOp Narrow8IntOp+ , subsumedByPrimOp Narrow16IntOp+ , Narrow16IntOp `subsumesPrimOp` Narrow32IntOp ]+primOpRules nm Narrow32IntOp = mkPrimOpRule nm 1 [ liftLit narrow32IntLit+ , subsumedByPrimOp Narrow8IntOp+ , subsumedByPrimOp Narrow16IntOp+ , subsumedByPrimOp Narrow32IntOp+ , removeOp32 ]+primOpRules nm Narrow8WordOp = mkPrimOpRule nm 1 [ liftLit narrow8WordLit+ , subsumedByPrimOp Narrow8WordOp+ , Narrow8WordOp `subsumesPrimOp` Narrow16WordOp+ , Narrow8WordOp `subsumesPrimOp` Narrow32WordOp ]+primOpRules nm Narrow16WordOp = mkPrimOpRule nm 1 [ liftLit narrow16WordLit+ , subsumedByPrimOp Narrow8WordOp+ , subsumedByPrimOp Narrow16WordOp+ , Narrow16WordOp `subsumesPrimOp` Narrow32WordOp ]+primOpRules nm Narrow32WordOp = mkPrimOpRule nm 1 [ liftLit narrow32WordLit+ , subsumedByPrimOp Narrow8WordOp+ , subsumedByPrimOp Narrow16WordOp+ , subsumedByPrimOp Narrow32WordOp+ , removeOp32 ]+primOpRules nm OrdOp = mkPrimOpRule nm 1 [ liftLit char2IntLit+ , inversePrimOp ChrOp ]+primOpRules nm ChrOp = mkPrimOpRule nm 1 [ do [Lit lit] <- getArgs+ guard (litFitsInChar lit)+ liftLit int2CharLit+ , inversePrimOp OrdOp ]+primOpRules nm Float2IntOp = mkPrimOpRule nm 1 [ liftLit float2IntLit ]+primOpRules nm Int2FloatOp = mkPrimOpRule nm 1 [ liftLit int2FloatLit ]+primOpRules nm Double2IntOp = mkPrimOpRule nm 1 [ liftLit double2IntLit ]+primOpRules nm Int2DoubleOp = mkPrimOpRule nm 1 [ liftLit int2DoubleLit ]+-- SUP: Not sure what the standard says about precision in the following 2 cases+primOpRules nm Float2DoubleOp = mkPrimOpRule nm 1 [ liftLit float2DoubleLit ]+primOpRules nm Double2FloatOp = mkPrimOpRule nm 1 [ liftLit double2FloatLit ]++-- Float+primOpRules nm FloatAddOp = mkPrimOpRule nm 2 [ binaryLit (floatOp2 (+))+ , identity zerof ]+primOpRules nm FloatSubOp = mkPrimOpRule nm 2 [ binaryLit (floatOp2 (-))+ , rightIdentity zerof ]+primOpRules nm FloatMulOp = mkPrimOpRule nm 2 [ binaryLit (floatOp2 (*))+ , identity onef+ , strengthReduction twof FloatAddOp ]+ -- zeroElem zerof doesn't hold because of NaN+primOpRules nm FloatDivOp = mkPrimOpRule nm 2 [ guardFloatDiv >> binaryLit (floatOp2 (/))+ , rightIdentity onef ]+primOpRules nm FloatNegOp = mkPrimOpRule nm 1 [ unaryLit negOp+ , inversePrimOp FloatNegOp ]++-- Double+primOpRules nm DoubleAddOp = mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (+))+ , identity zerod ]+primOpRules nm DoubleSubOp = mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (-))+ , rightIdentity zerod ]+primOpRules nm DoubleMulOp = mkPrimOpRule nm 2 [ binaryLit (doubleOp2 (*))+ , identity oned+ , strengthReduction twod DoubleAddOp ]+ -- zeroElem zerod doesn't hold because of NaN+primOpRules nm DoubleDivOp = mkPrimOpRule nm 2 [ guardDoubleDiv >> binaryLit (doubleOp2 (/))+ , rightIdentity oned ]+primOpRules nm DoubleNegOp = mkPrimOpRule nm 1 [ unaryLit negOp+ , inversePrimOp DoubleNegOp ]++-- Relational operators++primOpRules nm IntEqOp = mkRelOpRule nm (==) [ litEq True ]+primOpRules nm IntNeOp = mkRelOpRule nm (/=) [ litEq False ]+primOpRules nm CharEqOp = mkRelOpRule nm (==) [ litEq True ]+primOpRules nm CharNeOp = mkRelOpRule nm (/=) [ litEq False ]++primOpRules nm IntGtOp = mkRelOpRule nm (>) [ boundsCmp Gt ]+primOpRules nm IntGeOp = mkRelOpRule nm (>=) [ boundsCmp Ge ]+primOpRules nm IntLeOp = mkRelOpRule nm (<=) [ boundsCmp Le ]+primOpRules nm IntLtOp = mkRelOpRule nm (<) [ boundsCmp Lt ]++primOpRules nm CharGtOp = mkRelOpRule nm (>) [ boundsCmp Gt ]+primOpRules nm CharGeOp = mkRelOpRule nm (>=) [ boundsCmp Ge ]+primOpRules nm CharLeOp = mkRelOpRule nm (<=) [ boundsCmp Le ]+primOpRules nm CharLtOp = mkRelOpRule nm (<) [ boundsCmp Lt ]++primOpRules nm FloatGtOp = mkFloatingRelOpRule nm (>)+primOpRules nm FloatGeOp = mkFloatingRelOpRule nm (>=)+primOpRules nm FloatLeOp = mkFloatingRelOpRule nm (<=)+primOpRules nm FloatLtOp = mkFloatingRelOpRule nm (<)+primOpRules nm FloatEqOp = mkFloatingRelOpRule nm (==)+primOpRules nm FloatNeOp = mkFloatingRelOpRule nm (/=)++primOpRules nm DoubleGtOp = mkFloatingRelOpRule nm (>)+primOpRules nm DoubleGeOp = mkFloatingRelOpRule nm (>=)+primOpRules nm DoubleLeOp = mkFloatingRelOpRule nm (<=)+primOpRules nm DoubleLtOp = mkFloatingRelOpRule nm (<)+primOpRules nm DoubleEqOp = mkFloatingRelOpRule nm (==)+primOpRules nm DoubleNeOp = mkFloatingRelOpRule nm (/=)++primOpRules nm WordGtOp = mkRelOpRule nm (>) [ boundsCmp Gt ]+primOpRules nm WordGeOp = mkRelOpRule nm (>=) [ boundsCmp Ge ]+primOpRules nm WordLeOp = mkRelOpRule nm (<=) [ boundsCmp Le ]+primOpRules nm WordLtOp = mkRelOpRule nm (<) [ boundsCmp Lt ]+primOpRules nm WordEqOp = mkRelOpRule nm (==) [ litEq True ]+primOpRules nm WordNeOp = mkRelOpRule nm (/=) [ litEq False ]++primOpRules nm AddrAddOp = mkPrimOpRule nm 2 [ rightIdentityDynFlags zeroi ]++primOpRules nm SeqOp = mkPrimOpRule nm 4 [ seqRule ]+primOpRules nm SparkOp = mkPrimOpRule nm 4 [ sparkRule ]++primOpRules _ _ = Nothing++{-+************************************************************************+* *+\subsection{Doing the business}+* *+************************************************************************+-}++-- useful shorthands+mkPrimOpRule :: Name -> Int -> [RuleM CoreExpr] -> Maybe CoreRule+mkPrimOpRule nm arity rules = Just $ mkBasicRule nm arity (msum rules)++mkRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool)+ -> [RuleM CoreExpr] -> Maybe CoreRule+mkRelOpRule nm cmp extra+ = mkPrimOpRule nm 2 $+ binaryCmpLit cmp : equal_rule : extra+ where+ -- x `cmp` x does not depend on x, so+ -- compute it for the arbitrary value 'True'+ -- and use that result+ equal_rule = do { equalArgs+ ; dflags <- getDynFlags+ ; return (if cmp True True+ then trueValInt dflags+ else falseValInt dflags) }++{- Note [Rules for floating-point comparisons]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need different rules for floating-point values because for floats+it is not true that x = x (for NaNs); so we do not want the equal_rule+rule that mkRelOpRule uses.++Note also that, in the case of equality/inequality, we do /not/+want to switch to a case-expression. For example, we do not want+to convert+ case (eqFloat# x 3.8#) of+ True -> this+ False -> that+to+ case x of+ 3.8#::Float# -> this+ _ -> that+See Trac #9238. Reason: comparing floating-point values for equality+delicate, and we don't want to implement that delicacy in the code for+case expressions. So we make it an invariant of Core that a case+expression never scrutinises a Float# or Double#.++This transformation is what the litEq rule does;+see Note [The litEq rule: converting equality to case].+So we /refrain/ from using litEq for mkFloatingRelOpRule.+-}++mkFloatingRelOpRule :: Name -> (forall a . Ord a => a -> a -> Bool)+ -> Maybe CoreRule+-- See Note [Rules for floating-point comparisons]+mkFloatingRelOpRule nm cmp+ = mkPrimOpRule nm 2 [binaryCmpLit cmp]++-- common constants+zeroi, onei, zerow, onew :: DynFlags -> Literal+zeroi dflags = mkMachInt dflags 0+onei dflags = mkMachInt dflags 1+zerow dflags = mkMachWord dflags 0+onew dflags = mkMachWord dflags 1++zerof, onef, twof, zerod, oned, twod :: Literal+zerof = mkMachFloat 0.0+onef = mkMachFloat 1.0+twof = mkMachFloat 2.0+zerod = mkMachDouble 0.0+oned = mkMachDouble 1.0+twod = mkMachDouble 2.0++cmpOp :: DynFlags -> (forall a . Ord a => a -> a -> Bool)+ -> Literal -> Literal -> Maybe CoreExpr+cmpOp dflags cmp = go+ where+ done True = Just $ trueValInt dflags+ done False = Just $ falseValInt dflags++ -- These compares are at different types+ go (MachChar i1) (MachChar i2) = done (i1 `cmp` i2)+ go (MachInt i1) (MachInt i2) = done (i1 `cmp` i2)+ go (MachInt64 i1) (MachInt64 i2) = done (i1 `cmp` i2)+ go (MachWord i1) (MachWord i2) = done (i1 `cmp` i2)+ go (MachWord64 i1) (MachWord64 i2) = done (i1 `cmp` i2)+ go (MachFloat i1) (MachFloat i2) = done (i1 `cmp` i2)+ go (MachDouble i1) (MachDouble i2) = done (i1 `cmp` i2)+ go _ _ = Nothing++--------------------------++negOp :: DynFlags -> Literal -> Maybe CoreExpr -- Negate+negOp _ (MachFloat 0.0) = Nothing -- can't represent -0.0 as a Rational+negOp dflags (MachFloat f) = Just (mkFloatVal dflags (-f))+negOp _ (MachDouble 0.0) = Nothing+negOp dflags (MachDouble d) = Just (mkDoubleVal dflags (-d))+negOp dflags (MachInt i) = intResult dflags (-i)+negOp _ _ = Nothing++complementOp :: DynFlags -> Literal -> Maybe CoreExpr -- Binary complement+complementOp dflags (MachWord i) = wordResult dflags (complement i)+complementOp dflags (MachInt i) = intResult dflags (complement i)+complementOp _ _ = Nothing++--------------------------+intOp2 :: (Integral a, Integral b)+ => (a -> b -> Integer)+ -> DynFlags -> Literal -> Literal -> Maybe CoreExpr+intOp2 = intOp2' . const++intOp2' :: (Integral a, Integral b)+ => (DynFlags -> a -> b -> Integer)+ -> DynFlags -> Literal -> Literal -> Maybe CoreExpr+intOp2' op dflags (MachInt i1) (MachInt i2) =+ let o = op dflags+ in intResult dflags (fromInteger i1 `o` fromInteger i2)+intOp2' _ _ _ _ = Nothing -- Could find LitLit++shiftRightLogical :: DynFlags -> Integer -> Int -> Integer+-- Shift right, putting zeros in rather than sign-propagating as Bits.shiftR would do+-- Do this by converting to Word and back. Obviously this won't work for big+-- values, but its ok as we use it here+shiftRightLogical dflags x n+ | wordSizeInBits dflags == 32 = fromIntegral (fromInteger x `shiftR` n :: Word32)+ | wordSizeInBits dflags == 64 = fromIntegral (fromInteger x `shiftR` n :: Word64)+ | otherwise = panic "shiftRightLogical: unsupported word size"++--------------------------+retLit :: (DynFlags -> Literal) -> RuleM CoreExpr+retLit l = do dflags <- getDynFlags+ return $ Lit $ l dflags++wordOp2 :: (Integral a, Integral b)+ => (a -> b -> Integer)+ -> DynFlags -> Literal -> Literal -> Maybe CoreExpr+wordOp2 op dflags (MachWord w1) (MachWord w2)+ = wordResult dflags (fromInteger w1 `op` fromInteger w2)+wordOp2 _ _ _ _ = Nothing -- Could find LitLit++wordShiftRule :: (DynFlags -> Integer -> Int -> Integer) -> RuleM CoreExpr+ -- Shifts take an Int; hence third arg of op is Int+-- See Note [Guarding against silly shifts]+wordShiftRule shift_op+ = do { dflags <- getDynFlags+ ; [e1, Lit (MachInt shift_len)] <- getArgs+ ; case e1 of+ _ | shift_len == 0+ -> return e1+ | shift_len < 0 || wordSizeInBits dflags < shift_len+ -> return (mkRuntimeErrorApp rUNTIME_ERROR_ID wordPrimTy+ ("Bad shift length" ++ show shift_len))+ Lit (MachWord x)+ -> let op = shift_op dflags+ in liftMaybe $ wordResult dflags (x `op` fromInteger shift_len)+ -- Do the shift at type Integer, but shift length is Int+ _ -> mzero }++wordSizeInBits :: DynFlags -> Integer+wordSizeInBits dflags = toInteger (platformWordSize (targetPlatform dflags) `shiftL` 3)++--------------------------+floatOp2 :: (Rational -> Rational -> Rational)+ -> DynFlags -> Literal -> Literal+ -> Maybe (Expr CoreBndr)+floatOp2 op dflags (MachFloat f1) (MachFloat f2)+ = Just (mkFloatVal dflags (f1 `op` f2))+floatOp2 _ _ _ _ = Nothing++--------------------------+doubleOp2 :: (Rational -> Rational -> Rational)+ -> DynFlags -> Literal -> Literal+ -> Maybe (Expr CoreBndr)+doubleOp2 op dflags (MachDouble f1) (MachDouble f2)+ = Just (mkDoubleVal dflags (f1 `op` f2))+doubleOp2 _ _ _ _ = Nothing++--------------------------+{- Note [The litEq rule: converting equality to case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This stuff turns+ n ==# 3#+into+ case n of+ 3# -> True+ m -> False++This is a Good Thing, because it allows case-of case things+to happen, and case-default absorption to happen. For+example:++ if (n ==# 3#) || (n ==# 4#) then e1 else e2+will transform to+ case n of+ 3# -> e1+ 4# -> e1+ m -> e2+(modulo the usual precautions to avoid duplicating e1)+-}++litEq :: Bool -- True <=> equality, False <=> inequality+ -> RuleM CoreExpr+litEq is_eq = msum+ [ do [Lit lit, expr] <- getArgs+ dflags <- getDynFlags+ do_lit_eq dflags lit expr+ , do [expr, Lit lit] <- getArgs+ dflags <- getDynFlags+ do_lit_eq dflags lit expr ]+ where+ do_lit_eq dflags lit expr = do+ guard (not (litIsLifted lit))+ return (mkWildCase expr (literalType lit) intPrimTy+ [(DEFAULT, [], val_if_neq),+ (LitAlt lit, [], val_if_eq)])+ where+ val_if_eq | is_eq = trueValInt dflags+ | otherwise = falseValInt dflags+ val_if_neq | is_eq = falseValInt dflags+ | otherwise = trueValInt dflags+++-- | Check if there is comparison with minBound or maxBound, that is+-- always true or false. For instance, an Int cannot be smaller than its+-- minBound, so we can replace such comparison with False.+boundsCmp :: Comparison -> RuleM CoreExpr+boundsCmp op = do+ dflags <- getDynFlags+ [a, b] <- getArgs+ liftMaybe $ mkRuleFn dflags op a b++data Comparison = Gt | Ge | Lt | Le++mkRuleFn :: DynFlags -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr+mkRuleFn dflags Gt (Lit lit) _ | isMinBound dflags lit = Just $ falseValInt dflags+mkRuleFn dflags Le (Lit lit) _ | isMinBound dflags lit = Just $ trueValInt dflags+mkRuleFn dflags Ge _ (Lit lit) | isMinBound dflags lit = Just $ trueValInt dflags+mkRuleFn dflags Lt _ (Lit lit) | isMinBound dflags lit = Just $ falseValInt dflags+mkRuleFn dflags Ge (Lit lit) _ | isMaxBound dflags lit = Just $ trueValInt dflags+mkRuleFn dflags Lt (Lit lit) _ | isMaxBound dflags lit = Just $ falseValInt dflags+mkRuleFn dflags Gt _ (Lit lit) | isMaxBound dflags lit = Just $ falseValInt dflags+mkRuleFn dflags Le _ (Lit lit) | isMaxBound dflags lit = Just $ trueValInt dflags+mkRuleFn _ _ _ _ = Nothing++isMinBound :: DynFlags -> Literal -> Bool+isMinBound _ (MachChar c) = c == minBound+isMinBound dflags (MachInt i) = i == tARGET_MIN_INT dflags+isMinBound _ (MachInt64 i) = i == toInteger (minBound :: Int64)+isMinBound _ (MachWord i) = i == 0+isMinBound _ (MachWord64 i) = i == 0+isMinBound _ _ = False++isMaxBound :: DynFlags -> Literal -> Bool+isMaxBound _ (MachChar c) = c == maxBound+isMaxBound dflags (MachInt i) = i == tARGET_MAX_INT dflags+isMaxBound _ (MachInt64 i) = i == toInteger (maxBound :: Int64)+isMaxBound dflags (MachWord i) = i == tARGET_MAX_WORD dflags+isMaxBound _ (MachWord64 i) = i == toInteger (maxBound :: Word64)+isMaxBound _ _ = False+++-- Note [Word/Int underflow/overflow]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- According to the Haskell Report 2010 (Sections 18.1 and 23.1 about signed and+-- unsigned integral types): "All arithmetic is performed modulo 2^n, where n is+-- the number of bits in the type."+--+-- GHC stores Word# and Int# constant values as Integer. Core optimizations such+-- as constant folding must ensure that the Integer value remains in the valid+-- target Word/Int range (see #13172). The following functions are used to+-- ensure this.+--+-- Note that we *don't* warn the user about overflow. It's not done at runtime+-- either, and compilation of completely harmless things like+-- ((124076834 :: Word32) + (2147483647 :: Word32))+-- doesn't yield a warning. Instead we simply squash the value into the *target*+-- Int/Word range.++-- | Ensure the given Integer is in the target Int range+intResult' :: DynFlags -> Integer -> Integer+intResult' dflags result = case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (fromInteger result :: Int32)+ 8 -> toInteger (fromInteger result :: Int64)+ w -> panic ("intResult: Unknown platformWordSize: " ++ show w)++-- | Ensure the given Integer is in the target Word range+wordResult' :: DynFlags -> Integer -> Integer+wordResult' dflags result = case platformWordSize (targetPlatform dflags) of+ 4 -> toInteger (fromInteger result :: Word32)+ 8 -> toInteger (fromInteger result :: Word64)+ w -> panic ("wordResult: Unknown platformWordSize: " ++ show w)++-- | Create an Int literal expression while ensuring the given Integer is in the+-- target Int range+intResult :: DynFlags -> Integer -> Maybe CoreExpr+intResult dflags result = Just (mkIntVal dflags (intResult' dflags result))++-- | Create a Word literal expression while ensuring the given Integer is in the+-- target Word range+wordResult :: DynFlags -> Integer -> Maybe CoreExpr+wordResult dflags result = Just (mkWordVal dflags (wordResult' dflags result))+++++inversePrimOp :: PrimOp -> RuleM CoreExpr+inversePrimOp primop = do+ [Var primop_id `App` e] <- getArgs+ matchPrimOpId primop primop_id+ return e++subsumesPrimOp :: PrimOp -> PrimOp -> RuleM CoreExpr+this `subsumesPrimOp` that = do+ [Var primop_id `App` e] <- getArgs+ matchPrimOpId that primop_id+ return (Var (mkPrimOpId this) `App` e)++subsumedByPrimOp :: PrimOp -> RuleM CoreExpr+subsumedByPrimOp primop = do+ [e@(Var primop_id `App` _)] <- getArgs+ matchPrimOpId primop primop_id+ return e++idempotent :: RuleM CoreExpr+idempotent = do [e1, e2] <- getArgs+ guard $ cheapEqExpr e1 e2+ return e1++{-+Note [Guarding against silly shifts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this code:++ import Data.Bits( (.|.), shiftL )+ chunkToBitmap :: [Bool] -> Word32+ chunkToBitmap chunk = foldr (.|.) 0 [ 1 `shiftL` n | (True,n) <- zip chunk [0..] ]++This optimises to:+Shift.$wgo = \ (w_sCS :: GHC.Prim.Int#) (w1_sCT :: [GHC.Types.Bool]) ->+ case w1_sCT of _ {+ [] -> 0##;+ : x_aAW xs_aAX ->+ case x_aAW of _ {+ GHC.Types.False ->+ case w_sCS of wild2_Xh {+ __DEFAULT -> Shift.$wgo (GHC.Prim.+# wild2_Xh 1) xs_aAX;+ 9223372036854775807 -> 0## };+ GHC.Types.True ->+ case GHC.Prim.>=# w_sCS 64 of _ {+ GHC.Types.False ->+ case w_sCS of wild3_Xh {+ __DEFAULT ->+ case Shift.$wgo (GHC.Prim.+# wild3_Xh 1) xs_aAX of ww_sCW { __DEFAULT ->+ GHC.Prim.or# (GHC.Prim.narrow32Word#+ (GHC.Prim.uncheckedShiftL# 1## wild3_Xh))+ ww_sCW+ };+ 9223372036854775807 ->+ GHC.Prim.narrow32Word#+!!!!--> (GHC.Prim.uncheckedShiftL# 1## 9223372036854775807)+ };+ GHC.Types.True ->+ case w_sCS of wild3_Xh {+ __DEFAULT -> Shift.$wgo (GHC.Prim.+# wild3_Xh 1) xs_aAX;+ 9223372036854775807 -> 0##+ } } } }++Note the massive shift on line "!!!!". It can't happen, because we've checked+that w < 64, but the optimiser didn't spot that. We DO NO want to constant-fold this!+Moreover, if the programmer writes (n `uncheckedShiftL` 9223372036854775807), we+can't constant fold it, but if it gets to the assember we get+ Error: operand type mismatch for `shl'++So the best thing to do is to rewrite the shift with a call to error,+when the second arg is stupid.++************************************************************************+* *+\subsection{Vaguely generic functions}+* *+************************************************************************+-}++mkBasicRule :: Name -> Int -> RuleM CoreExpr -> CoreRule+-- Gives the Rule the same name as the primop itself+mkBasicRule op_name n_args rm+ = BuiltinRule { ru_name = occNameFS (nameOccName op_name),+ ru_fn = op_name,+ ru_nargs = n_args,+ ru_try = \ dflags in_scope _ -> runRuleM rm dflags in_scope }++newtype RuleM r = RuleM+ { runRuleM :: DynFlags -> InScopeEnv -> [CoreExpr] -> Maybe r }++instance Functor RuleM where+ fmap = liftM++instance Applicative RuleM where+ pure x = RuleM $ \_ _ _ -> Just x+ (<*>) = ap++instance Monad RuleM where+ RuleM f >>= g = RuleM $ \dflags iu e -> case f dflags iu e of+ Nothing -> Nothing+ Just r -> runRuleM (g r) dflags iu e+ fail _ = mzero++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail RuleM where+ fail _ = mzero+#endif++instance Alternative RuleM where+ empty = RuleM $ \_ _ _ -> Nothing+ RuleM f1 <|> RuleM f2 = RuleM $ \dflags iu args ->+ f1 dflags iu args <|> f2 dflags iu args++instance MonadPlus RuleM++instance HasDynFlags RuleM where+ getDynFlags = RuleM $ \dflags _ _ -> Just dflags++liftMaybe :: Maybe a -> RuleM a+liftMaybe Nothing = mzero+liftMaybe (Just x) = return x++liftLit :: (Literal -> Literal) -> RuleM CoreExpr+liftLit f = liftLitDynFlags (const f)++liftLitDynFlags :: (DynFlags -> Literal -> Literal) -> RuleM CoreExpr+liftLitDynFlags f = do+ dflags <- getDynFlags+ [Lit lit] <- getArgs+ return $ Lit (f dflags lit)++removeOp32 :: RuleM CoreExpr+removeOp32 = do+ dflags <- getDynFlags+ if wordSizeInBits dflags == 32+ then do+ [e] <- getArgs+ return e+ else mzero++getArgs :: RuleM [CoreExpr]+getArgs = RuleM $ \_ _ args -> Just args++getInScopeEnv :: RuleM InScopeEnv+getInScopeEnv = RuleM $ \_ iu _ -> Just iu++-- return the n-th argument of this rule, if it is a literal+-- argument indices start from 0+getLiteral :: Int -> RuleM Literal+getLiteral n = RuleM $ \_ _ exprs -> case drop n exprs of+ (Lit l:_) -> Just l+ _ -> Nothing++unaryLit :: (DynFlags -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr+unaryLit op = do+ dflags <- getDynFlags+ [Lit l] <- getArgs+ liftMaybe $ op dflags (convFloating dflags l)++binaryLit :: (DynFlags -> Literal -> Literal -> Maybe CoreExpr) -> RuleM CoreExpr+binaryLit op = do+ dflags <- getDynFlags+ [Lit l1, Lit l2] <- getArgs+ liftMaybe $ op dflags (convFloating dflags l1) (convFloating dflags l2)++binaryCmpLit :: (forall a . Ord a => a -> a -> Bool) -> RuleM CoreExpr+binaryCmpLit op = do+ dflags <- getDynFlags+ binaryLit (\_ -> cmpOp dflags op)++leftIdentity :: Literal -> RuleM CoreExpr+leftIdentity id_lit = leftIdentityDynFlags (const id_lit)++rightIdentity :: Literal -> RuleM CoreExpr+rightIdentity id_lit = rightIdentityDynFlags (const id_lit)++identity :: Literal -> RuleM CoreExpr+identity lit = leftIdentity lit `mplus` rightIdentity lit++leftIdentityDynFlags :: (DynFlags -> Literal) -> RuleM CoreExpr+leftIdentityDynFlags id_lit = do+ dflags <- getDynFlags+ [Lit l1, e2] <- getArgs+ guard $ l1 == id_lit dflags+ return e2++rightIdentityDynFlags :: (DynFlags -> Literal) -> RuleM CoreExpr+rightIdentityDynFlags id_lit = do+ dflags <- getDynFlags+ [e1, Lit l2] <- getArgs+ guard $ l2 == id_lit dflags+ return e1++identityDynFlags :: (DynFlags -> Literal) -> RuleM CoreExpr+identityDynFlags lit = leftIdentityDynFlags lit `mplus` rightIdentityDynFlags lit++leftZero :: (DynFlags -> Literal) -> RuleM CoreExpr+leftZero zero = do+ dflags <- getDynFlags+ [Lit l1, _] <- getArgs+ guard $ l1 == zero dflags+ return $ Lit l1++rightZero :: (DynFlags -> Literal) -> RuleM CoreExpr+rightZero zero = do+ dflags <- getDynFlags+ [_, Lit l2] <- getArgs+ guard $ l2 == zero dflags+ return $ Lit l2++zeroElem :: (DynFlags -> Literal) -> RuleM CoreExpr+zeroElem lit = leftZero lit `mplus` rightZero lit++equalArgs :: RuleM ()+equalArgs = do+ [e1, e2] <- getArgs+ guard $ e1 `cheapEqExpr` e2++nonZeroLit :: Int -> RuleM ()+nonZeroLit n = getLiteral n >>= guard . not . isZeroLit++-- When excess precision is not requested, cut down the precision of the+-- Rational value to that of Float/Double. We confuse host architecture+-- and target architecture here, but it's convenient (and wrong :-).+convFloating :: DynFlags -> Literal -> Literal+convFloating dflags (MachFloat f) | not (gopt Opt_ExcessPrecision dflags) =+ MachFloat (toRational (fromRational f :: Float ))+convFloating dflags (MachDouble d) | not (gopt Opt_ExcessPrecision dflags) =+ MachDouble (toRational (fromRational d :: Double))+convFloating _ l = l++guardFloatDiv :: RuleM ()+guardFloatDiv = do+ [Lit (MachFloat f1), Lit (MachFloat f2)] <- getArgs+ guard $ (f1 /=0 || f2 > 0) -- see Note [negative zero]+ && f2 /= 0 -- avoid NaN and Infinity/-Infinity++guardDoubleDiv :: RuleM ()+guardDoubleDiv = do+ [Lit (MachDouble d1), Lit (MachDouble d2)] <- getArgs+ guard $ (d1 /=0 || d2 > 0) -- see Note [negative zero]+ && d2 /= 0 -- avoid NaN and Infinity/-Infinity+-- Note [negative zero] Avoid (0 / -d), otherwise 0/(-1) reduces to+-- zero, but we might want to preserve the negative zero here which+-- is representable in Float/Double but not in (normalised)+-- Rational. (#3676) Perhaps we should generate (0 :% (-1)) instead?++strengthReduction :: Literal -> PrimOp -> RuleM CoreExpr+strengthReduction two_lit add_op = do -- Note [Strength reduction]+ arg <- msum [ do [arg, Lit mult_lit] <- getArgs+ guard (mult_lit == two_lit)+ return arg+ , do [Lit mult_lit, arg] <- getArgs+ guard (mult_lit == two_lit)+ return arg ]+ return $ Var (mkPrimOpId add_op) `App` arg `App` arg++-- Note [Strength reduction]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- This rule turns floating point multiplications of the form 2.0 * x and+-- x * 2.0 into x + x addition, because addition costs less than multiplication.+-- See #7116++-- Note [What's true and false]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- trueValInt and falseValInt represent true and false values returned by+-- comparison primops for Char, Int, Word, Integer, Double, Float and Addr.+-- True is represented as an unboxed 1# literal, while false is represented+-- as 0# literal.+-- We still need Bool data constructors (True and False) to use in a rule+-- for constant folding of equal Strings++trueValInt, falseValInt :: DynFlags -> Expr CoreBndr+trueValInt dflags = Lit $ onei dflags -- see Note [What's true and false]+falseValInt dflags = Lit $ zeroi dflags++trueValBool, falseValBool :: Expr CoreBndr+trueValBool = Var trueDataConId -- see Note [What's true and false]+falseValBool = Var falseDataConId++ltVal, eqVal, gtVal :: Expr CoreBndr+ltVal = Var ltDataConId+eqVal = Var eqDataConId+gtVal = Var gtDataConId++mkIntVal :: DynFlags -> Integer -> Expr CoreBndr+mkIntVal dflags i = Lit (mkMachInt dflags i)+mkWordVal :: DynFlags -> Integer -> Expr CoreBndr+mkWordVal dflags w = Lit (mkMachWord dflags w)+mkFloatVal :: DynFlags -> Rational -> Expr CoreBndr+mkFloatVal dflags f = Lit (convFloating dflags (MachFloat f))+mkDoubleVal :: DynFlags -> Rational -> Expr CoreBndr+mkDoubleVal dflags d = Lit (convFloating dflags (MachDouble d))++matchPrimOpId :: PrimOp -> Id -> RuleM ()+matchPrimOpId op id = do+ op' <- liftMaybe $ isPrimOpId_maybe id+ guard $ op == op'++{-+************************************************************************+* *+\subsection{Special rules for seq, tagToEnum, dataToTag}+* *+************************************************************************++Note [tagToEnum#]+~~~~~~~~~~~~~~~~~+Nasty check to ensure that tagToEnum# is applied to a type that is an+enumeration TyCon. Unification may refine the type later, but this+check won't see that, alas. It's crude but it works.++Here's are two cases that should fail+ f :: forall a. a+ f = tagToEnum# 0 -- Can't do tagToEnum# at a type variable++ g :: Int+ g = tagToEnum# 0 -- Int is not an enumeration++We used to make this check in the type inference engine, but it's quite+ugly to do so, because the delayed constraint solving means that we don't+really know what's going on until the end. It's very much a corner case+because we don't expect the user to call tagToEnum# at all; we merely+generate calls in derived instances of Enum. So we compromise: a+rewrite rule rewrites a bad instance of tagToEnum# to an error call,+and emits a warning.+-}++tagToEnumRule :: RuleM CoreExpr+-- If data T a = A | B | C+-- then tag2Enum# (T ty) 2# --> B ty+tagToEnumRule = do+ [Type ty, Lit (MachInt i)] <- getArgs+ case splitTyConApp_maybe ty of+ Just (tycon, tc_args) | isEnumerationTyCon tycon -> do+ let tag = fromInteger i+ correct_tag dc = (dataConTag dc - fIRST_TAG) == tag+ (dc:rest) <- return $ filter correct_tag (tyConDataCons_maybe tycon `orElse` [])+ ASSERT(null rest) return ()+ return $ mkTyApps (Var (dataConWorkId dc)) tc_args++ -- See Note [tagToEnum#]+ _ -> WARN( True, text "tagToEnum# on non-enumeration type" <+> ppr ty )+ return $ mkRuntimeErrorApp rUNTIME_ERROR_ID ty "tagToEnum# on non-enumeration type"++{-+For dataToTag#, we can reduce if either++ (a) the argument is a constructor+ (b) the argument is a variable whose unfolding is a known constructor+-}++dataToTagRule :: RuleM CoreExpr+dataToTagRule = a `mplus` b+ where+ a = do+ [Type ty1, Var tag_to_enum `App` Type ty2 `App` tag] <- getArgs+ guard $ tag_to_enum `hasKey` tagToEnumKey+ guard $ ty1 `eqType` ty2+ return tag -- dataToTag (tagToEnum x) ==> x+ b = do+ dflags <- getDynFlags+ [_, val_arg] <- getArgs+ in_scope <- getInScopeEnv+ (dc,_,_) <- liftMaybe $ exprIsConApp_maybe in_scope val_arg+ ASSERT( not (isNewTyCon (dataConTyCon dc)) ) return ()+ return $ mkIntVal dflags (toInteger (dataConTag dc - fIRST_TAG))++{-+************************************************************************+* *+\subsection{Rules for seq# and spark#}+* *+************************************************************************+-}++-- seq# :: forall a s . a -> State# s -> (# State# s, a #)+seqRule :: RuleM CoreExpr+seqRule = do+ [Type ty_a, Type ty_s, a, s] <- getArgs+ guard $ exprIsHNF a+ return $ mkCoreUbxTup [mkStatePrimTy ty_s, ty_a] [s, a]++-- spark# :: forall a s . a -> State# s -> (# State# s, a #)+sparkRule :: RuleM CoreExpr+sparkRule = seqRule -- reduce on HNF, just the same+ -- XXX perhaps we shouldn't do this, because a spark eliminated by+ -- this rule won't be counted as a dud at runtime?++{-+************************************************************************+* *+\subsection{Built in rules}+* *+************************************************************************++Note [Scoping for Builtin rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When compiling a (base-package) module that defines one of the+functions mentioned in the RHS of a built-in rule, there's a danger+that we'll see++ f = ...(eq String x)....++ ....and lower down...++ eqString = ...++Then a rewrite would give++ f = ...(eqString x)...+ ....and lower down...+ eqString = ...++and lo, eqString is not in scope. This only really matters when we get to code+generation. With -O we do a GlomBinds step that does a new SCC analysis on the whole+set of bindings, which sorts out the dependency. Without -O we don't do any rule+rewriting so again we are fine.++(This whole thing doesn't show up for non-built-in rules because their dependencies+are explicit.)+-}++builtinRules :: [CoreRule]+-- Rules for non-primops that can't be expressed using a RULE pragma+builtinRules+ = [BuiltinRule { ru_name = fsLit "AppendLitString",+ ru_fn = unpackCStringFoldrName,+ ru_nargs = 4, ru_try = match_append_lit },+ BuiltinRule { ru_name = fsLit "EqString", ru_fn = eqStringName,+ ru_nargs = 2, ru_try = match_eq_string },+ BuiltinRule { ru_name = fsLit "Inline", ru_fn = inlineIdName,+ ru_nargs = 2, ru_try = \_ _ _ -> match_inline },+ BuiltinRule { ru_name = fsLit "MagicDict", ru_fn = idName magicDictId,+ ru_nargs = 4, ru_try = \_ _ _ -> match_magicDict },+ mkBasicRule divIntName 2 $ msum+ [ nonZeroLit 1 >> binaryLit (intOp2 div)+ , leftZero zeroi+ , do+ [arg, Lit (MachInt d)] <- getArgs+ Just n <- return $ exactLog2 d+ dflags <- getDynFlags+ return $ Var (mkPrimOpId ISraOp) `App` arg `App` mkIntVal dflags n+ ],+ mkBasicRule modIntName 2 $ msum+ [ nonZeroLit 1 >> binaryLit (intOp2 mod)+ , leftZero zeroi+ , do+ [arg, Lit (MachInt d)] <- getArgs+ Just _ <- return $ exactLog2 d+ dflags <- getDynFlags+ return $ Var (mkPrimOpId AndIOp)+ `App` arg `App` mkIntVal dflags (d - 1)+ ]+ ]+ ++ builtinIntegerRules++builtinIntegerRules :: [CoreRule]+builtinIntegerRules =+ [rule_IntToInteger "smallInteger" smallIntegerName,+ rule_WordToInteger "wordToInteger" wordToIntegerName,+ rule_Int64ToInteger "int64ToInteger" int64ToIntegerName,+ rule_Word64ToInteger "word64ToInteger" word64ToIntegerName,+ rule_convert "integerToWord" integerToWordName mkWordLitWord,+ rule_convert "integerToInt" integerToIntName mkIntLitInt,+ rule_convert "integerToWord64" integerToWord64Name (\_ -> mkWord64LitWord64),+ rule_convert "integerToInt64" integerToInt64Name (\_ -> mkInt64LitInt64),+ rule_binop "plusInteger" plusIntegerName (+),+ rule_binop "minusInteger" minusIntegerName (-),+ rule_binop "timesInteger" timesIntegerName (*),+ rule_unop "negateInteger" negateIntegerName negate,+ rule_binop_Prim "eqInteger#" eqIntegerPrimName (==),+ rule_binop_Prim "neqInteger#" neqIntegerPrimName (/=),+ rule_unop "absInteger" absIntegerName abs,+ rule_unop "signumInteger" signumIntegerName signum,+ rule_binop_Prim "leInteger#" leIntegerPrimName (<=),+ rule_binop_Prim "gtInteger#" gtIntegerPrimName (>),+ rule_binop_Prim "ltInteger#" ltIntegerPrimName (<),+ rule_binop_Prim "geInteger#" geIntegerPrimName (>=),+ rule_binop_Ordering "compareInteger" compareIntegerName compare,+ rule_encodeFloat "encodeFloatInteger" encodeFloatIntegerName mkFloatLitFloat,+ rule_convert "floatFromInteger" floatFromIntegerName (\_ -> mkFloatLitFloat),+ rule_encodeFloat "encodeDoubleInteger" encodeDoubleIntegerName mkDoubleLitDouble,+ rule_decodeDouble "decodeDoubleInteger" decodeDoubleIntegerName,+ rule_convert "doubleFromInteger" doubleFromIntegerName (\_ -> mkDoubleLitDouble),+ rule_rationalTo "rationalToFloat" rationalToFloatName mkFloatExpr,+ rule_rationalTo "rationalToDouble" rationalToDoubleName mkDoubleExpr,+ rule_binop "gcdInteger" gcdIntegerName gcd,+ rule_binop "lcmInteger" lcmIntegerName lcm,+ rule_binop "andInteger" andIntegerName (.&.),+ rule_binop "orInteger" orIntegerName (.|.),+ rule_binop "xorInteger" xorIntegerName xor,+ rule_unop "complementInteger" complementIntegerName complement,+ rule_Int_binop "shiftLInteger" shiftLIntegerName shiftL,+ rule_Int_binop "shiftRInteger" shiftRIntegerName shiftR,+ rule_bitInteger "bitInteger" bitIntegerName,+ -- See Note [Integer division constant folding] in libraries/base/GHC/Real.hs+ rule_divop_one "quotInteger" quotIntegerName quot,+ rule_divop_one "remInteger" remIntegerName rem,+ rule_divop_one "divInteger" divIntegerName div,+ rule_divop_one "modInteger" modIntegerName mod,+ rule_divop_both "divModInteger" divModIntegerName divMod,+ rule_divop_both "quotRemInteger" quotRemIntegerName quotRem,+ -- These rules below don't actually have to be built in, but if we+ -- put them in the Haskell source then we'd have to duplicate them+ -- between all Integer implementations+ rule_XToIntegerToX "smallIntegerToInt" integerToIntName smallIntegerName,+ rule_XToIntegerToX "wordToIntegerToWord" integerToWordName wordToIntegerName,+ rule_XToIntegerToX "int64ToIntegerToInt64" integerToInt64Name int64ToIntegerName,+ rule_XToIntegerToX "word64ToIntegerToWord64" integerToWord64Name word64ToIntegerName,+ rule_smallIntegerTo "smallIntegerToWord" integerToWordName Int2WordOp,+ rule_smallIntegerTo "smallIntegerToFloat" floatFromIntegerName Int2FloatOp,+ rule_smallIntegerTo "smallIntegerToDouble" doubleFromIntegerName Int2DoubleOp+ ]+ where rule_convert str name convert+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_Integer_convert convert }+ rule_IntToInteger str name+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_IntToInteger }+ rule_WordToInteger str name+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_WordToInteger }+ rule_Int64ToInteger str name+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_Int64ToInteger }+ rule_Word64ToInteger str name+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_Word64ToInteger }+ rule_unop str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_Integer_unop op }+ rule_bitInteger str name+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_IntToInteger_unop (bit . fromIntegral) }+ rule_binop str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_binop op }+ rule_divop_both str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_divop_both op }+ rule_divop_one str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_divop_one op }+ rule_Int_binop str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_Int_binop op }+ rule_binop_Prim str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_binop_Prim op }+ rule_binop_Ordering str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_binop_Ordering op }+ rule_encodeFloat str name op+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_Integer_Int_encodeFloat op }+ rule_decodeDouble str name+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_decodeDouble }+ rule_XToIntegerToX str name toIntegerName+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_XToIntegerToX toIntegerName }+ rule_smallIntegerTo str name primOp+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 1,+ ru_try = match_smallIntegerTo primOp }+ rule_rationalTo str name mkLit+ = BuiltinRule { ru_name = fsLit str, ru_fn = name, ru_nargs = 2,+ ru_try = match_rationalTo mkLit }++---------------------------------------------------+-- The rule is this:+-- unpackFoldrCString# "foo" c (unpackFoldrCString# "baz" c n)+-- = unpackFoldrCString# "foobaz" c n++match_append_lit :: RuleFun+match_append_lit _ id_unf _+ [ Type ty1+ , lit1+ , c1+ , Var unpk `App` Type ty2+ `App` lit2+ `App` c2+ `App` n+ ]+ | unpk `hasKey` unpackCStringFoldrIdKey &&+ c1 `cheapEqExpr` c2+ , Just (MachStr s1) <- exprIsLiteral_maybe id_unf lit1+ , Just (MachStr s2) <- exprIsLiteral_maybe id_unf lit2+ = ASSERT( ty1 `eqType` ty2 )+ Just (Var unpk `App` Type ty1+ `App` Lit (MachStr (s1 `BS.append` s2))+ `App` c1+ `App` n)++match_append_lit _ _ _ _ = Nothing++---------------------------------------------------+-- The rule is this:+-- eqString (unpackCString# (Lit s1)) (unpackCString# (Lit s2) = s1==s2++match_eq_string :: RuleFun+match_eq_string _ id_unf _+ [Var unpk1 `App` lit1, Var unpk2 `App` lit2]+ | unpk1 `hasKey` unpackCStringIdKey+ , unpk2 `hasKey` unpackCStringIdKey+ , Just (MachStr s1) <- exprIsLiteral_maybe id_unf lit1+ , Just (MachStr s2) <- exprIsLiteral_maybe id_unf lit2+ = Just (if s1 == s2 then trueValBool else falseValBool)++match_eq_string _ _ _ _ = Nothing+++---------------------------------------------------+-- The rule is this:+-- inline f_ty (f a b c) = <f's unfolding> a b c+-- (if f has an unfolding, EVEN if it's a loop breaker)+--+-- It's important to allow the argument to 'inline' to have args itself+-- (a) because its more forgiving to allow the programmer to write+-- inline f a b c+-- or inline (f a b c)+-- (b) because a polymorphic f wll get a type argument that the+-- programmer can't avoid+--+-- Also, don't forget about 'inline's type argument!+match_inline :: [Expr CoreBndr] -> Maybe (Expr CoreBndr)+match_inline (Type _ : e : _)+ | (Var f, args1) <- collectArgs e,+ Just unf <- maybeUnfoldingTemplate (realIdUnfolding f)+ -- Ignore the IdUnfoldingFun here!+ = Just (mkApps unf args1)++match_inline _ = Nothing+++-- See Note [magicDictId magic] in `basicTypes/MkId.hs`+-- for a description of what is going on here.+match_magicDict :: [Expr CoreBndr] -> Maybe (Expr CoreBndr)+match_magicDict [Type _, Var wrap `App` Type a `App` Type _ `App` f, x, y ]+ | Just (fieldTy, _) <- splitFunTy_maybe $ dropForAlls $ idType wrap+ , Just (dictTy, _) <- splitFunTy_maybe fieldTy+ , Just dictTc <- tyConAppTyCon_maybe dictTy+ , Just (_,_,co) <- unwrapNewTyCon_maybe dictTc+ = Just+ $ f `App` Cast x (mkSymCo (mkUnbranchedAxInstCo Representational co [a] []))+ `App` y++match_magicDict _ = Nothing++-------------------------------------------------+-- Integer rules+-- smallInteger (79::Int#) = 79::Integer+-- wordToInteger (79::Word#) = 79::Integer+-- Similarly Int64, Word64++match_IntToInteger :: RuleFun+match_IntToInteger = match_IntToInteger_unop id++match_WordToInteger :: RuleFun+match_WordToInteger _ id_unf id [xl]+ | Just (MachWord x) <- exprIsLiteral_maybe id_unf xl+ = case splitFunTy_maybe (idType id) of+ Just (_, integerTy) ->+ Just (Lit (LitInteger x integerTy))+ _ ->+ panic "match_WordToInteger: Id has the wrong type"+match_WordToInteger _ _ _ _ = Nothing++match_Int64ToInteger :: RuleFun+match_Int64ToInteger _ id_unf id [xl]+ | Just (MachInt64 x) <- exprIsLiteral_maybe id_unf xl+ = case splitFunTy_maybe (idType id) of+ Just (_, integerTy) ->+ Just (Lit (LitInteger x integerTy))+ _ ->+ panic "match_Int64ToInteger: Id has the wrong type"+match_Int64ToInteger _ _ _ _ = Nothing++match_Word64ToInteger :: RuleFun+match_Word64ToInteger _ id_unf id [xl]+ | Just (MachWord64 x) <- exprIsLiteral_maybe id_unf xl+ = case splitFunTy_maybe (idType id) of+ Just (_, integerTy) ->+ Just (Lit (LitInteger x integerTy))+ _ ->+ panic "match_Word64ToInteger: Id has the wrong type"+match_Word64ToInteger _ _ _ _ = Nothing++-------------------------------------------------+match_Integer_convert :: Num a+ => (DynFlags -> a -> Expr CoreBndr)+ -> RuleFun+match_Integer_convert convert dflags id_unf _ [xl]+ | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl+ = Just (convert dflags (fromInteger x))+match_Integer_convert _ _ _ _ _ = Nothing++match_Integer_unop :: (Integer -> Integer) -> RuleFun+match_Integer_unop unop _ id_unf _ [xl]+ | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl+ = Just (Lit (LitInteger (unop x) i))+match_Integer_unop _ _ _ _ _ = Nothing++{- Note [Rewriting bitInteger]++For most types the bitInteger operation can be implemented in terms of shifts.+The integer-gmp package, however, can do substantially better than this if+allowed to provide its own implementation. However, in so doing it previously lost+constant-folding (see Trac #8832). The bitInteger rule above provides constant folding+specifically for this function.++There is, however, a bit of trickiness here when it comes to ranges. While the+AST encodes all integers (even MachInts) as Integers, `bit` expects the bit+index to be given as an Int. Hence we coerce to an Int in the rule definition.+This will behave a bit funny for constants larger than the word size, but the user+should expect some funniness given that they will have at very least ignored a+warning in this case.+-}++match_IntToInteger_unop :: (Integer -> Integer) -> RuleFun+match_IntToInteger_unop unop _ id_unf fn [xl]+ | Just (MachInt x) <- exprIsLiteral_maybe id_unf xl+ = case splitFunTy_maybe (idType fn) of+ Just (_, integerTy) ->+ Just (Lit (LitInteger (unop x) integerTy))+ _ ->+ panic "match_IntToInteger_unop: Id has the wrong type"+match_IntToInteger_unop _ _ _ _ _ = Nothing++match_Integer_binop :: (Integer -> Integer -> Integer) -> RuleFun+match_Integer_binop binop _ id_unf _ [xl,yl]+ | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl+ , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl+ = Just (Lit (LitInteger (x `binop` y) i))+match_Integer_binop _ _ _ _ _ = Nothing++-- This helper is used for the quotRem and divMod functions+match_Integer_divop_both+ :: (Integer -> Integer -> (Integer, Integer)) -> RuleFun+match_Integer_divop_both divop _ id_unf _ [xl,yl]+ | Just (LitInteger x t) <- exprIsLiteral_maybe id_unf xl+ , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl+ , y /= 0+ , (r,s) <- x `divop` y+ = Just $ mkCoreUbxTup [t,t] [Lit (LitInteger r t), Lit (LitInteger s t)]+match_Integer_divop_both _ _ _ _ _ = Nothing++-- This helper is used for the quot and rem functions+match_Integer_divop_one :: (Integer -> Integer -> Integer) -> RuleFun+match_Integer_divop_one divop _ id_unf _ [xl,yl]+ | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl+ , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl+ , y /= 0+ = Just (Lit (LitInteger (x `divop` y) i))+match_Integer_divop_one _ _ _ _ _ = Nothing++match_Integer_Int_binop :: (Integer -> Int -> Integer) -> RuleFun+match_Integer_Int_binop binop _ id_unf _ [xl,yl]+ | Just (LitInteger x i) <- exprIsLiteral_maybe id_unf xl+ , Just (MachInt y) <- exprIsLiteral_maybe id_unf yl+ = Just (Lit (LitInteger (x `binop` fromIntegral y) i))+match_Integer_Int_binop _ _ _ _ _ = Nothing++match_Integer_binop_Prim :: (Integer -> Integer -> Bool) -> RuleFun+match_Integer_binop_Prim binop dflags id_unf _ [xl, yl]+ | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl+ , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl+ = Just (if x `binop` y then trueValInt dflags else falseValInt dflags)+match_Integer_binop_Prim _ _ _ _ _ = Nothing++match_Integer_binop_Ordering :: (Integer -> Integer -> Ordering) -> RuleFun+match_Integer_binop_Ordering binop _ id_unf _ [xl, yl]+ | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl+ , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl+ = Just $ case x `binop` y of+ LT -> ltVal+ EQ -> eqVal+ GT -> gtVal+match_Integer_binop_Ordering _ _ _ _ _ = Nothing++match_Integer_Int_encodeFloat :: RealFloat a+ => (a -> Expr CoreBndr)+ -> RuleFun+match_Integer_Int_encodeFloat mkLit _ id_unf _ [xl,yl]+ | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl+ , Just (MachInt y) <- exprIsLiteral_maybe id_unf yl+ = Just (mkLit $ encodeFloat x (fromInteger y))+match_Integer_Int_encodeFloat _ _ _ _ _ = Nothing++---------------------------------------------------+-- constant folding for Float/Double+--+-- This turns+-- rationalToFloat n d+-- into a literal Float, and similarly for Doubles.+--+-- it's important to not match d == 0, because that may represent a+-- literal "0/0" or similar, and we can't produce a literal value for+-- NaN or +-Inf+match_rationalTo :: RealFloat a+ => (a -> Expr CoreBndr)+ -> RuleFun+match_rationalTo mkLit _ id_unf _ [xl, yl]+ | Just (LitInteger x _) <- exprIsLiteral_maybe id_unf xl+ , Just (LitInteger y _) <- exprIsLiteral_maybe id_unf yl+ , y /= 0+ = Just (mkLit (fromRational (x % y)))+match_rationalTo _ _ _ _ _ = Nothing++match_decodeDouble :: RuleFun+match_decodeDouble _ id_unf fn [xl]+ | Just (MachDouble x) <- exprIsLiteral_maybe id_unf xl+ = case splitFunTy_maybe (idType fn) of+ Just (_, res)+ | Just [_lev1, _lev2, integerTy, intHashTy] <- tyConAppArgs_maybe res+ -> case decodeFloat (fromRational x :: Double) of+ (y, z) ->+ Just $ mkCoreUbxTup [integerTy, intHashTy]+ [Lit (LitInteger y integerTy),+ Lit (MachInt (toInteger z))]+ _ ->+ pprPanic "match_decodeDouble: Id has the wrong type"+ (ppr fn <+> dcolon <+> ppr (idType fn))+match_decodeDouble _ _ _ _ = Nothing++match_XToIntegerToX :: Name -> RuleFun+match_XToIntegerToX n _ _ _ [App (Var x) y]+ | idName x == n+ = Just y+match_XToIntegerToX _ _ _ _ _ = Nothing++match_smallIntegerTo :: PrimOp -> RuleFun+match_smallIntegerTo primOp _ _ _ [App (Var x) y]+ | idName x == smallIntegerName+ = Just $ App (Var (mkPrimOpId primOp)) y+match_smallIntegerTo _ _ _ _ _ = Nothing++++--------------------------------------------------------+-- Constant folding through case-expressions+--+-- cf Scrutinee Constant Folding in simplCore/SimplUtils+--------------------------------------------------------++-- | Match the scrutinee of a case and potentially return a new scrutinee and a+-- function to apply to each literal alternative.+caseRules :: DynFlags -> CoreExpr -> Maybe (CoreExpr, Integer -> Integer)+caseRules dflags scrut = case scrut of++ -- We need to call wordResult' and intResult' to ensure that the literal+ -- alternatives remain in Word/Int target ranges (cf Note [Word/Int+ -- underflow/overflow] and #13172).++ -- v `op` x#+ App (App (Var f) v) (Lit l)+ | Just op <- isPrimOpId_maybe f+ , Just x <- isLitValue_maybe l ->+ case op of+ WordAddOp -> Just (v, \y -> wordResult' dflags $ y-x )+ IntAddOp -> Just (v, \y -> intResult' dflags $ y-x )+ WordSubOp -> Just (v, \y -> wordResult' dflags $ y+x )+ IntSubOp -> Just (v, \y -> intResult' dflags $ y+x )+ XorOp -> Just (v, \y -> wordResult' dflags $ y `xor` x)+ XorIOp -> Just (v, \y -> intResult' dflags $ y `xor` x)+ _ -> Nothing++ -- x# `op` v+ App (App (Var f) (Lit l)) v+ | Just op <- isPrimOpId_maybe f+ , Just x <- isLitValue_maybe l ->+ case op of+ WordAddOp -> Just (v, \y -> wordResult' dflags $ y-x )+ IntAddOp -> Just (v, \y -> intResult' dflags $ y-x )+ WordSubOp -> Just (v, \y -> wordResult' dflags $ x-y )+ IntSubOp -> Just (v, \y -> intResult' dflags $ x-y )+ XorOp -> Just (v, \y -> wordResult' dflags $ y `xor` x)+ XorIOp -> Just (v, \y -> intResult' dflags $ y `xor` x)+ _ -> Nothing++ -- op v+ App (Var f) v+ | Just op <- isPrimOpId_maybe f ->+ case op of+ NotOp -> Just (v, \y -> wordResult' dflags $ complement y)+ NotIOp -> Just (v, \y -> intResult' dflags $ complement y)+ IntNegOp -> Just (v, \y -> intResult' dflags $ negate y )+ _ -> Nothing++ _ -> Nothing
+ prelude/PrimOp.hs view
@@ -0,0 +1,629 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[PrimOp]{Primitive operations (machine-level)}+-}++{-# LANGUAGE CPP #-}++-- The default is a bit too low for the quite large primOpInfo definition+#if __GLASGOW_HASKELL__ >= 801+{-# OPTIONS_GHC -fmax-pmcheck-iterations=10000000 #-}+#endif++module PrimOp (+ PrimOp(..), PrimOpVecCat(..), allThePrimOps,+ primOpType, primOpSig,+ primOpTag, maxPrimOpTag, primOpOcc,++ tagToEnumKey,++ primOpOutOfLine, primOpCodeSize,+ primOpOkForSpeculation, primOpOkForSideEffects,+ primOpIsCheap, primOpFixity,++ getPrimOpResultInfo, PrimOpResultInfo(..),++ PrimCall(..)+ ) where++#include "HsVersions.h"++import TysPrim+import TysWiredIn++import CmmType+import Demand+import OccName ( OccName, pprOccName, mkVarOccFS )+import TyCon ( TyCon, isPrimTyCon, PrimRep(..) )+import Type+import RepType ( typePrimRep1, tyConPrimRep1 )+import BasicTypes ( Arity, Fixity(..), FixityDirection(..), Boxity(..),+ SourceText(..) )+import ForeignCall ( CLabelString )+import Unique ( Unique, mkPrimOpIdUnique )+import Outputable+import FastString+import Module ( UnitId )++{-+************************************************************************+* *+\subsection[PrimOp-datatype]{Datatype for @PrimOp@ (an enumeration)}+* *+************************************************************************++These are in \tr{state-interface.verb} order.+-}++-- supplies:+-- data PrimOp = ...+#include "primop-data-decl.hs-incl"++-- supplies+-- primOpTag :: PrimOp -> Int+#include "primop-tag.hs-incl"+primOpTag _ = error "primOpTag: unknown primop"+++instance Eq PrimOp where+ op1 == op2 = primOpTag op1 == primOpTag op2++instance Ord PrimOp where+ op1 < op2 = primOpTag op1 < primOpTag op2+ op1 <= op2 = primOpTag op1 <= primOpTag op2+ op1 >= op2 = primOpTag op1 >= primOpTag op2+ op1 > op2 = primOpTag op1 > primOpTag op2+ op1 `compare` op2 | op1 < op2 = LT+ | op1 == op2 = EQ+ | otherwise = GT++instance Outputable PrimOp where+ ppr op = pprPrimOp op++data PrimOpVecCat = IntVec+ | WordVec+ | FloatVec++-- An @Enum@-derived list would be better; meanwhile... (ToDo)++allThePrimOps :: [PrimOp]+allThePrimOps =+#include "primop-list.hs-incl"++tagToEnumKey :: Unique+tagToEnumKey = mkPrimOpIdUnique (primOpTag TagToEnumOp)++{-+************************************************************************+* *+\subsection[PrimOp-info]{The essential info about each @PrimOp@}+* *+************************************************************************++The @String@ in the @PrimOpInfos@ is the ``base name'' by which the user may+refer to the primitive operation. The conventional \tr{#}-for-+unboxed ops is added on later.++The reason for the funny characters in the names is so we do not+interfere with the programmer's Haskell name spaces.++We use @PrimKinds@ for the ``type'' information, because they're+(slightly) more convenient to use than @TyCons@.+-}++data PrimOpInfo+ = Dyadic OccName -- string :: T -> T -> T+ Type+ | Monadic OccName -- string :: T -> T+ Type+ | Compare OccName -- string :: T -> T -> Int#+ Type+ | GenPrimOp OccName -- string :: \/a1..an . T1 -> .. -> Tk -> T+ [TyVar]+ [Type]+ Type++mkDyadic, mkMonadic, mkCompare :: FastString -> Type -> PrimOpInfo+mkDyadic str ty = Dyadic (mkVarOccFS str) ty+mkMonadic str ty = Monadic (mkVarOccFS str) ty+mkCompare str ty = Compare (mkVarOccFS str) ty++mkGenPrimOp :: FastString -> [TyVar] -> [Type] -> Type -> PrimOpInfo+mkGenPrimOp str tvs tys ty = GenPrimOp (mkVarOccFS str) tvs tys ty++{-+************************************************************************+* *+\subsubsection{Strictness}+* *+************************************************************************++Not all primops are strict!+-}++primOpStrictness :: PrimOp -> Arity -> StrictSig+ -- See Demand.StrictnessInfo for discussion of what the results+ -- The arity should be the arity of the primop; that's why+ -- this function isn't exported.+#include "primop-strictness.hs-incl"++{-+************************************************************************+* *+\subsubsection{Fixity}+* *+************************************************************************+-}++primOpFixity :: PrimOp -> Maybe Fixity+#include "primop-fixity.hs-incl"++{-+************************************************************************+* *+\subsubsection[PrimOp-comparison]{PrimOpInfo basic comparison ops}+* *+************************************************************************++@primOpInfo@ gives all essential information (from which everything+else, notably a type, can be constructed) for each @PrimOp@.+-}++primOpInfo :: PrimOp -> PrimOpInfo+#include "primop-primop-info.hs-incl"+primOpInfo _ = error "primOpInfo: unknown primop"++{-+Here are a load of comments from the old primOp info:++A @Word#@ is an unsigned @Int#@.++@decodeFloat#@ is given w/ Integer-stuff (it's similar).++@decodeDouble#@ is given w/ Integer-stuff (it's similar).++Decoding of floating-point numbers is sorta Integer-related. Encoding+is done with plain ccalls now (see PrelNumExtra.hs).++A @Weak@ Pointer is created by the @mkWeak#@ primitive:++ mkWeak# :: k -> v -> f -> State# RealWorld+ -> (# State# RealWorld, Weak# v #)++In practice, you'll use the higher-level++ data Weak v = Weak# v+ mkWeak :: k -> v -> IO () -> IO (Weak v)++The following operation dereferences a weak pointer. The weak pointer+may have been finalized, so the operation returns a result code which+must be inspected before looking at the dereferenced value.++ deRefWeak# :: Weak# v -> State# RealWorld ->+ (# State# RealWorld, v, Int# #)++Only look at v if the Int# returned is /= 0 !!++The higher-level op is++ deRefWeak :: Weak v -> IO (Maybe v)++Weak pointers can be finalized early by using the finalize# operation:++ finalizeWeak# :: Weak# v -> State# RealWorld ->+ (# State# RealWorld, Int#, IO () #)++The Int# returned is either++ 0 if the weak pointer has already been finalized, or it has no+ finalizer (the third component is then invalid).++ 1 if the weak pointer is still alive, with the finalizer returned+ as the third component.++A {\em stable name/pointer} is an index into a table of stable name+entries. Since the garbage collector is told about stable pointers,+it is safe to pass a stable pointer to external systems such as C+routines.++\begin{verbatim}+makeStablePtr# :: a -> State# RealWorld -> (# State# RealWorld, StablePtr# a #)+freeStablePtr :: StablePtr# a -> State# RealWorld -> State# RealWorld+deRefStablePtr# :: StablePtr# a -> State# RealWorld -> (# State# RealWorld, a #)+eqStablePtr# :: StablePtr# a -> StablePtr# a -> Int#+\end{verbatim}++It may seem a bit surprising that @makeStablePtr#@ is a @IO@+operation since it doesn't (directly) involve IO operations. The+reason is that if some optimisation pass decided to duplicate calls to+@makeStablePtr#@ and we only pass one of the stable pointers over, a+massive space leak can result. Putting it into the IO monad+prevents this. (Another reason for putting them in a monad is to+ensure correct sequencing wrt the side-effecting @freeStablePtr@+operation.)++An important property of stable pointers is that if you call+makeStablePtr# twice on the same object you get the same stable+pointer back.++Note that we can implement @freeStablePtr#@ using @_ccall_@ (and,+besides, it's not likely to be used from Haskell) so it's not a+primop.++Question: Why @RealWorld@ - won't any instance of @_ST@ do the job? [ADR]++Stable Names+~~~~~~~~~~~~++A stable name is like a stable pointer, but with three important differences:++ (a) You can't deRef one to get back to the original object.+ (b) You can convert one to an Int.+ (c) You don't need to 'freeStableName'++The existence of a stable name doesn't guarantee to keep the object it+points to alive (unlike a stable pointer), hence (a).++Invariants:++ (a) makeStableName always returns the same value for a given+ object (same as stable pointers).++ (b) if two stable names are equal, it implies that the objects+ from which they were created were the same.++ (c) stableNameToInt always returns the same Int for a given+ stable name.+++These primops are pretty weird.++ dataToTag# :: a -> Int (arg must be an evaluated data type)+ tagToEnum# :: Int -> a (result type must be an enumerated type)++The constraints aren't currently checked by the front end, but the+code generator will fall over if they aren't satisfied.++************************************************************************+* *+ Which PrimOps are out-of-line+* *+************************************************************************++Some PrimOps need to be called out-of-line because they either need to+perform a heap check or they block.+-}++primOpOutOfLine :: PrimOp -> Bool+#include "primop-out-of-line.hs-incl"++{-+************************************************************************+* *+ Failure and side effects+* *+************************************************************************++Note [PrimOp can_fail and has_side_effects]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Both can_fail and has_side_effects mean that the primop has+some effect that is not captured entirely by its result value.++---------- has_side_effects ---------------------+A primop "has_side_effects" if it has some *write* effect, visible+elsewhere+ - writing to the world (I/O)+ - writing to a mutable data structure (writeIORef)+ - throwing a synchronous Haskell exception++Often such primops have a type like+ State -> input -> (State, output)+so the state token guarantees ordering. In general we rely *only* on+data dependencies of the state token to enforce write-effect ordering++ * NB1: if you inline unsafePerformIO, you may end up with+ side-effecting ops whose 'state' output is discarded.+ And programmers may do that by hand; see Trac #9390.+ That is why we (conservatively) do not discard write-effecting+ primops even if both their state and result is discarded.++ * NB2: We consider primops, such as raiseIO#, that can raise a+ (Haskell) synchronous exception to "have_side_effects" but not+ "can_fail". We must be careful about not discarding such things;+ see the paper "A semantics for imprecise exceptions".++ * NB3: *Read* effects (like reading an IORef) don't count here,+ because it doesn't matter if we don't do them, or do them more than+ once. *Sequencing* is maintained by the data dependency of the state+ token.++---------- can_fail ----------------------------+A primop "can_fail" if it can fail with an *unchecked* exception on+some elements of its input domain. Main examples:+ division (fails on zero demoninator)+ array indexing (fails if the index is out of bounds)++An "unchecked exception" is one that is an outright error, (not+turned into a Haskell exception,) such as seg-fault or+divide-by-zero error. Such can_fail primops are ALWAYS surrounded+with a test that checks for the bad cases, but we need to be+very careful about code motion that might move it out of+the scope of the test.++Note [Transformations affected by can_fail and has_side_effects]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The can_fail and has_side_effects properties have the following effect+on program transformations. Summary table is followed by details.++ can_fail has_side_effects+Discard YES NO+Float in YES YES+Float out NO NO+Duplicate YES NO++* Discarding. case (a `op` b) of _ -> rhs ===> rhs+ You should not discard a has_side_effects primop; e.g.+ case (writeIntArray# a i v s of (# _, _ #) -> True+ Arguably you should be able to discard this, since the+ returned stat token is not used, but that relies on NEVER+ inlining unsafePerformIO, and programmers sometimes write+ this kind of stuff by hand (Trac #9390). So we (conservatively)+ never discard a has_side_effects primop.++ However, it's fine to discard a can_fail primop. For example+ case (indexIntArray# a i) of _ -> True+ We can discard indexIntArray#; it has can_fail, but not+ has_side_effects; see Trac #5658 which was all about this.+ Notice that indexIntArray# is (in a more general handling of+ effects) read effect, but we don't care about that here, and+ treat read effects as *not* has_side_effects.++ Similarly (a `/#` b) can be discarded. It can seg-fault or+ cause a hardware exception, but not a synchronous Haskell+ exception.++++ Synchronous Haskell exceptions, e.g. from raiseIO#, are treated+ as has_side_effects and hence are not discarded.++* Float in. You can float a can_fail or has_side_effects primop+ *inwards*, but not inside a lambda (see Duplication below).++* Float out. You must not float a can_fail primop *outwards* lest+ you escape the dynamic scope of the test. Example:+ case d ># 0# of+ True -> case x /# d of r -> r +# 1+ False -> 0+ Here we must not float the case outwards to give+ case x/# d of r ->+ case d ># 0# of+ True -> r +# 1+ False -> 0++ Nor can you float out a has_side_effects primop. For example:+ if blah then case writeMutVar# v True s0 of (# s1 #) -> s1+ else s0+ Notice that s0 is mentioned in both branches of the 'if', but+ only one of these two will actually be consumed. But if we+ float out to+ case writeMutVar# v True s0 of (# s1 #) ->+ if blah then s1 else s0+ the writeMutVar will be performed in both branches, which is+ utterly wrong.++* Duplication. You cannot duplicate a has_side_effect primop. You+ might wonder how this can occur given the state token threading, but+ just look at Control.Monad.ST.Lazy.Imp.strictToLazy! We get+ something like this+ p = case readMutVar# s v of+ (# s', r #) -> (S# s', r)+ s' = case p of (s', r) -> s'+ r = case p of (s', r) -> r++ (All these bindings are boxed.) If we inline p at its two call+ sites, we get a catastrophe: because the read is performed once when+ s' is demanded, and once when 'r' is demanded, which may be much+ later. Utterly wrong. Trac #3207 is real example of this happening.++ However, it's fine to duplicate a can_fail primop. That is really+ the only difference between can_fail and has_side_effects.++Note [Implementation: how can_fail/has_side_effects affect transformations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+How do we ensure that that floating/duplication/discarding are done right+in the simplifier?++Two main predicates on primpops test these flags:+ primOpOkForSideEffects <=> not has_side_effects+ primOpOkForSpeculation <=> not (has_side_effects || can_fail)++ * The "no-float-out" thing is achieved by ensuring that we never+ let-bind a can_fail or has_side_effects primop. The RHS of a+ let-binding (which can float in and out freely) satisfies+ exprOkForSpeculation; this is the let/app invariant. And+ exprOkForSpeculation is false of can_fail and has_side_effects.++ * So can_fail and has_side_effects primops will appear only as the+ scrutinees of cases, and that's why the FloatIn pass is capable+ of floating case bindings inwards.++ * The no-duplicate thing is done via primOpIsCheap, by making+ has_side_effects things (very very very) not-cheap!+-}++primOpHasSideEffects :: PrimOp -> Bool+#include "primop-has-side-effects.hs-incl"++primOpCanFail :: PrimOp -> Bool+#include "primop-can-fail.hs-incl"++primOpOkForSpeculation :: PrimOp -> Bool+ -- See Note [PrimOp can_fail and has_side_effects]+ -- See comments with CoreUtils.exprOkForSpeculation+ -- primOpOkForSpeculation => primOpOkForSideEffects+primOpOkForSpeculation op+ = primOpOkForSideEffects op+ && not (primOpOutOfLine op || primOpCanFail op)+ -- I think the "out of line" test is because out of line things can+ -- be expensive (eg sine, cosine), and so we may not want to speculate them++primOpOkForSideEffects :: PrimOp -> Bool+primOpOkForSideEffects op+ = not (primOpHasSideEffects op)++{-+Note [primOpIsCheap]+~~~~~~~~~~~~~~~~~~~~+@primOpIsCheap@, as used in \tr{SimplUtils.hs}. For now (HACK+WARNING), we just borrow some other predicates for a+what-should-be-good-enough test. "Cheap" means willing to call it more+than once, and/or push it inside a lambda. The latter could change the+behaviour of 'seq' for primops that can fail, so we don't treat them as cheap.+-}++primOpIsCheap :: PrimOp -> Bool+-- See Note [PrimOp can_fail and has_side_effects]+primOpIsCheap op = primOpOkForSpeculation op+-- In March 2001, we changed this to+-- primOpIsCheap op = False+-- thereby making *no* primops seem cheap. But this killed eta+-- expansion on case (x ==# y) of True -> \s -> ...+-- which is bad. In particular a loop like+-- doLoop n = loop 0+-- where+-- loop i | i == n = return ()+-- | otherwise = bar i >> loop (i+1)+-- allocated a closure every time round because it doesn't eta expand.+--+-- The problem that originally gave rise to the change was+-- let x = a +# b *# c in x +# x+-- were we don't want to inline x. But primopIsCheap doesn't control+-- that (it's exprIsDupable that does) so the problem doesn't occur+-- even if primOpIsCheap sometimes says 'True'.++{-+************************************************************************+* *+ PrimOp code size+* *+************************************************************************++primOpCodeSize+~~~~~~~~~~~~~~+Gives an indication of the code size of a primop, for the purposes of+calculating unfolding sizes; see CoreUnfold.sizeExpr.+-}++primOpCodeSize :: PrimOp -> Int+#include "primop-code-size.hs-incl"++primOpCodeSizeDefault :: Int+primOpCodeSizeDefault = 1+ -- CoreUnfold.primOpSize already takes into account primOpOutOfLine+ -- and adds some further costs for the args in that case.++primOpCodeSizeForeignCall :: Int+primOpCodeSizeForeignCall = 4++{-+************************************************************************+* *+ PrimOp types+* *+************************************************************************+-}++primOpType :: PrimOp -> Type -- you may want to use primOpSig instead+primOpType op+ = case primOpInfo op of+ Dyadic _occ ty -> dyadic_fun_ty ty+ Monadic _occ ty -> monadic_fun_ty ty+ Compare _occ ty -> compare_fun_ty ty++ GenPrimOp _occ tyvars arg_tys res_ty ->+ mkSpecForAllTys tyvars (mkFunTys arg_tys res_ty)++primOpOcc :: PrimOp -> OccName+primOpOcc op = case primOpInfo op of+ Dyadic occ _ -> occ+ Monadic occ _ -> occ+ Compare occ _ -> occ+ GenPrimOp occ _ _ _ -> occ++-- primOpSig is like primOpType but gives the result split apart:+-- (type variables, argument types, result type)+-- It also gives arity, strictness info++primOpSig :: PrimOp -> ([TyVar], [Type], Type, Arity, StrictSig)+primOpSig op+ = (tyvars, arg_tys, res_ty, arity, primOpStrictness op arity)+ where+ arity = length arg_tys+ (tyvars, arg_tys, res_ty)+ = case (primOpInfo op) of+ Monadic _occ ty -> ([], [ty], ty )+ Dyadic _occ ty -> ([], [ty,ty], ty )+ Compare _occ ty -> ([], [ty,ty], intPrimTy)+ GenPrimOp _occ tyvars arg_tys res_ty -> (tyvars, arg_tys, res_ty )++data PrimOpResultInfo+ = ReturnsPrim PrimRep+ | ReturnsAlg TyCon++-- Some PrimOps need not return a manifest primitive or algebraic value+-- (i.e. they might return a polymorphic value). These PrimOps *must*+-- be out of line, or the code generator won't work.++getPrimOpResultInfo :: PrimOp -> PrimOpResultInfo+getPrimOpResultInfo op+ = case (primOpInfo op) of+ Dyadic _ ty -> ReturnsPrim (typePrimRep1 ty)+ Monadic _ ty -> ReturnsPrim (typePrimRep1 ty)+ Compare _ _ -> ReturnsPrim (tyConPrimRep1 intPrimTyCon)+ GenPrimOp _ _ _ ty | isPrimTyCon tc -> ReturnsPrim (tyConPrimRep1 tc)+ | otherwise -> ReturnsAlg tc+ where+ tc = tyConAppTyCon ty+ -- All primops return a tycon-app result+ -- The tycon can be an unboxed tuple or sum, though,+ -- which gives rise to a ReturnAlg++{-+We do not currently make use of whether primops are commutable.++We used to try to move constants to the right hand side for strength+reduction.+-}++{-+commutableOp :: PrimOp -> Bool+#include "primop-commutable.hs-incl"+-}++-- Utils:++dyadic_fun_ty, monadic_fun_ty, compare_fun_ty :: Type -> Type+dyadic_fun_ty ty = mkFunTys [ty, ty] ty+monadic_fun_ty ty = mkFunTy ty ty+compare_fun_ty ty = mkFunTys [ty, ty] intPrimTy++-- Output stuff:++pprPrimOp :: PrimOp -> SDoc+pprPrimOp other_op = pprOccName (primOpOcc other_op)++{-+************************************************************************+* *+\subsubsection[PrimCall]{User-imported primitive calls}+* *+************************************************************************+-}++data PrimCall = PrimCall CLabelString UnitId++instance Outputable PrimCall where+ ppr (PrimCall lbl pkgId)+ = text "__primcall" <+> ppr pkgId <+> ppr lbl
+ prelude/PrimOp.hs-boot view
@@ -0,0 +1,3 @@+module PrimOp where++data PrimOp
+ prelude/THNames.hs view
@@ -0,0 +1,1088 @@+-- %************************************************************************+-- %* *+-- The known-key names for Template Haskell+-- %* *+-- %************************************************************************++module THNames where++import PrelNames( mk_known_key_name )+import Module( Module, mkModuleNameFS, mkModule, thUnitId )+import Name( Name )+import OccName( tcName, clsName, dataName, varName )+import RdrName( RdrName, nameRdrName )+import Unique+import FastString++-- To add a name, do three things+--+-- 1) Allocate a key+-- 2) Make a "Name"+-- 3) Add the name to templateHaskellNames++templateHaskellNames :: [Name]+-- The names that are implicitly mentioned by ``bracket''+-- Should stay in sync with the import list of DsMeta++templateHaskellNames = [+ returnQName, bindQName, sequenceQName, newNameName, liftName,+ mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName, mkNameLName,+ mkNameSName,+ liftStringName,+ unTypeName,+ unTypeQName,+ unsafeTExpCoerceName,++ -- Lit+ charLName, stringLName, integerLName, intPrimLName, wordPrimLName,+ floatPrimLName, doublePrimLName, rationalLName, stringPrimLName,+ charPrimLName,+ -- Pat+ litPName, varPName, tupPName, unboxedTupPName, unboxedSumPName,+ conPName, tildePName, bangPName, infixPName,+ asPName, wildPName, recPName, listPName, sigPName, viewPName,+ -- FieldPat+ fieldPatName,+ -- Match+ matchName,+ -- Clause+ clauseName,+ -- Exp+ varEName, conEName, litEName, appEName, appTypeEName, infixEName,+ infixAppName, sectionLName, sectionRName, lamEName, lamCaseEName,+ tupEName, unboxedTupEName, unboxedSumEName,+ condEName, multiIfEName, letEName, caseEName, doEName, compEName,+ fromEName, fromThenEName, fromToEName, fromThenToEName,+ listEName, sigEName, recConEName, recUpdEName, staticEName, unboundVarEName,+ -- FieldExp+ fieldExpName,+ -- Body+ guardedBName, normalBName,+ -- Guard+ normalGEName, patGEName,+ -- Stmt+ bindSName, letSName, noBindSName, parSName,+ -- Dec+ funDName, valDName, dataDName, newtypeDName, tySynDName,+ classDName, instanceWithOverlapDName,+ standaloneDerivWithStrategyDName, sigDName, forImpDName,+ pragInlDName, pragSpecDName, pragSpecInlDName, pragSpecInstDName,+ pragRuleDName, pragCompleteDName, pragAnnDName, defaultSigDName,+ dataFamilyDName, openTypeFamilyDName, closedTypeFamilyDName,+ dataInstDName, newtypeInstDName, tySynInstDName,+ infixLDName, infixRDName, infixNDName,+ roleAnnotDName, patSynDName, patSynSigDName,+ -- Cxt+ cxtName,++ -- SourceUnpackedness+ noSourceUnpackednessName, sourceNoUnpackName, sourceUnpackName,+ -- SourceStrictness+ noSourceStrictnessName, sourceLazyName, sourceStrictName,+ -- Con+ normalCName, recCName, infixCName, forallCName, gadtCName, recGadtCName,+ -- Bang+ bangName,+ -- BangType+ bangTypeName,+ -- VarBangType+ varBangTypeName,+ -- PatSynDir (for pattern synonyms)+ unidirPatSynName, implBidirPatSynName, explBidirPatSynName,+ -- PatSynArgs (for pattern synonyms)+ prefixPatSynName, infixPatSynName, recordPatSynName,+ -- Type+ forallTName, varTName, conTName, appTName, equalityTName,+ tupleTName, unboxedTupleTName, unboxedSumTName,+ arrowTName, listTName, sigTName, litTName,+ promotedTName, promotedTupleTName, promotedNilTName, promotedConsTName,+ wildCardTName,+ -- TyLit+ numTyLitName, strTyLitName,+ -- TyVarBndr+ plainTVName, kindedTVName,+ -- Role+ nominalRName, representationalRName, phantomRName, inferRName,+ -- Kind+ varKName, conKName, tupleKName, arrowKName, listKName, appKName,+ starKName, constraintKName,+ -- FamilyResultSig+ noSigName, kindSigName, tyVarSigName,+ -- InjectivityAnn+ injectivityAnnName,+ -- Callconv+ cCallName, stdCallName, cApiCallName, primCallName, javaScriptCallName,+ -- Safety+ unsafeName,+ safeName,+ interruptibleName,+ -- Inline+ noInlineDataConName, inlineDataConName, inlinableDataConName,+ -- RuleMatch+ conLikeDataConName, funLikeDataConName,+ -- Phases+ allPhasesDataConName, fromPhaseDataConName, beforePhaseDataConName,+ -- Overlap+ overlappableDataConName, overlappingDataConName, overlapsDataConName,+ incoherentDataConName,+ -- DerivStrategy+ stockStrategyDataConName, anyclassStrategyDataConName,+ newtypeStrategyDataConName,+ -- TExp+ tExpDataConName,+ -- RuleBndr+ ruleVarName, typedRuleVarName,+ -- FunDep+ funDepName,+ -- FamFlavour+ typeFamName, dataFamName,+ -- TySynEqn+ tySynEqnName,+ -- AnnTarget+ valueAnnotationName, typeAnnotationName, moduleAnnotationName,+ -- DerivClause+ derivClauseName,++ -- The type classes+ liftClassName,++ -- And the tycons+ qTyConName, nameTyConName, patTyConName, fieldPatTyConName, matchQTyConName,+ clauseQTyConName, expQTyConName, fieldExpTyConName, predTyConName,+ stmtQTyConName, decQTyConName, conQTyConName, bangTypeQTyConName,+ varBangTypeQTyConName, typeQTyConName, expTyConName, decTyConName,+ typeTyConName, tyVarBndrTyConName, matchTyConName, clauseTyConName,+ patQTyConName, fieldPatQTyConName, fieldExpQTyConName, funDepTyConName,+ predQTyConName, decsQTyConName, ruleBndrQTyConName, tySynEqnQTyConName,+ roleTyConName, tExpTyConName, injAnnTyConName, kindTyConName,+ overlapTyConName, derivClauseQTyConName, derivStrategyTyConName,++ -- Quasiquoting+ quoteDecName, quoteTypeName, quoteExpName, quotePatName]++thSyn, thLib, qqLib :: Module+thSyn = mkTHModule (fsLit "Language.Haskell.TH.Syntax")+thLib = mkTHModule (fsLit "Language.Haskell.TH.Lib")+qqLib = mkTHModule (fsLit "Language.Haskell.TH.Quote")++mkTHModule :: FastString -> Module+mkTHModule m = mkModule thUnitId (mkModuleNameFS m)++libFun, libTc, thFun, thTc, thCls, thCon, qqFun :: FastString -> Unique -> Name+libFun = mk_known_key_name OccName.varName thLib+libTc = mk_known_key_name OccName.tcName thLib+thFun = mk_known_key_name OccName.varName thSyn+thTc = mk_known_key_name OccName.tcName thSyn+thCls = mk_known_key_name OccName.clsName thSyn+thCon = mk_known_key_name OccName.dataName thSyn+qqFun = mk_known_key_name OccName.varName qqLib++-------------------- TH.Syntax -----------------------+liftClassName :: Name+liftClassName = thCls (fsLit "Lift") liftClassKey++qTyConName, nameTyConName, fieldExpTyConName, patTyConName,+ fieldPatTyConName, expTyConName, decTyConName, typeTyConName,+ tyVarBndrTyConName, matchTyConName, clauseTyConName, funDepTyConName,+ predTyConName, tExpTyConName, injAnnTyConName, kindTyConName,+ overlapTyConName, derivStrategyTyConName :: Name+qTyConName = thTc (fsLit "Q") qTyConKey+nameTyConName = thTc (fsLit "Name") nameTyConKey+fieldExpTyConName = thTc (fsLit "FieldExp") fieldExpTyConKey+patTyConName = thTc (fsLit "Pat") patTyConKey+fieldPatTyConName = thTc (fsLit "FieldPat") fieldPatTyConKey+expTyConName = thTc (fsLit "Exp") expTyConKey+decTyConName = thTc (fsLit "Dec") decTyConKey+typeTyConName = thTc (fsLit "Type") typeTyConKey+tyVarBndrTyConName = thTc (fsLit "TyVarBndr") tyVarBndrTyConKey+matchTyConName = thTc (fsLit "Match") matchTyConKey+clauseTyConName = thTc (fsLit "Clause") clauseTyConKey+funDepTyConName = thTc (fsLit "FunDep") funDepTyConKey+predTyConName = thTc (fsLit "Pred") predTyConKey+tExpTyConName = thTc (fsLit "TExp") tExpTyConKey+injAnnTyConName = thTc (fsLit "InjectivityAnn") injAnnTyConKey+kindTyConName = thTc (fsLit "Kind") kindTyConKey+overlapTyConName = thTc (fsLit "Overlap") overlapTyConKey+derivStrategyTyConName = thTc (fsLit "DerivStrategy") derivStrategyTyConKey++returnQName, bindQName, sequenceQName, newNameName, liftName,+ mkNameName, mkNameG_vName, mkNameG_dName, mkNameG_tcName,+ mkNameLName, mkNameSName, liftStringName, unTypeName, unTypeQName,+ unsafeTExpCoerceName :: Name+returnQName = thFun (fsLit "returnQ") returnQIdKey+bindQName = thFun (fsLit "bindQ") bindQIdKey+sequenceQName = thFun (fsLit "sequenceQ") sequenceQIdKey+newNameName = thFun (fsLit "newName") newNameIdKey+liftName = thFun (fsLit "lift") liftIdKey+liftStringName = thFun (fsLit "liftString") liftStringIdKey+mkNameName = thFun (fsLit "mkName") mkNameIdKey+mkNameG_vName = thFun (fsLit "mkNameG_v") mkNameG_vIdKey+mkNameG_dName = thFun (fsLit "mkNameG_d") mkNameG_dIdKey+mkNameG_tcName = thFun (fsLit "mkNameG_tc") mkNameG_tcIdKey+mkNameLName = thFun (fsLit "mkNameL") mkNameLIdKey+mkNameSName = thFun (fsLit "mkNameS") mkNameSIdKey+unTypeName = thFun (fsLit "unType") unTypeIdKey+unTypeQName = thFun (fsLit "unTypeQ") unTypeQIdKey+unsafeTExpCoerceName = thFun (fsLit "unsafeTExpCoerce") unsafeTExpCoerceIdKey+++-------------------- TH.Lib -----------------------+-- data Lit = ...+charLName, stringLName, integerLName, intPrimLName, wordPrimLName,+ floatPrimLName, doublePrimLName, rationalLName, stringPrimLName,+ charPrimLName :: Name+charLName = libFun (fsLit "charL") charLIdKey+stringLName = libFun (fsLit "stringL") stringLIdKey+integerLName = libFun (fsLit "integerL") integerLIdKey+intPrimLName = libFun (fsLit "intPrimL") intPrimLIdKey+wordPrimLName = libFun (fsLit "wordPrimL") wordPrimLIdKey+floatPrimLName = libFun (fsLit "floatPrimL") floatPrimLIdKey+doublePrimLName = libFun (fsLit "doublePrimL") doublePrimLIdKey+rationalLName = libFun (fsLit "rationalL") rationalLIdKey+stringPrimLName = libFun (fsLit "stringPrimL") stringPrimLIdKey+charPrimLName = libFun (fsLit "charPrimL") charPrimLIdKey++-- data Pat = ...+litPName, varPName, tupPName, unboxedTupPName, unboxedSumPName, conPName,+ infixPName, tildePName, bangPName, asPName, wildPName, recPName, listPName,+ sigPName, viewPName :: Name+litPName = libFun (fsLit "litP") litPIdKey+varPName = libFun (fsLit "varP") varPIdKey+tupPName = libFun (fsLit "tupP") tupPIdKey+unboxedTupPName = libFun (fsLit "unboxedTupP") unboxedTupPIdKey+unboxedSumPName = libFun (fsLit "unboxedSumP") unboxedSumPIdKey+conPName = libFun (fsLit "conP") conPIdKey+infixPName = libFun (fsLit "infixP") infixPIdKey+tildePName = libFun (fsLit "tildeP") tildePIdKey+bangPName = libFun (fsLit "bangP") bangPIdKey+asPName = libFun (fsLit "asP") asPIdKey+wildPName = libFun (fsLit "wildP") wildPIdKey+recPName = libFun (fsLit "recP") recPIdKey+listPName = libFun (fsLit "listP") listPIdKey+sigPName = libFun (fsLit "sigP") sigPIdKey+viewPName = libFun (fsLit "viewP") viewPIdKey++-- type FieldPat = ...+fieldPatName :: Name+fieldPatName = libFun (fsLit "fieldPat") fieldPatIdKey++-- data Match = ...+matchName :: Name+matchName = libFun (fsLit "match") matchIdKey++-- data Clause = ...+clauseName :: Name+clauseName = libFun (fsLit "clause") clauseIdKey++-- data Exp = ...+varEName, conEName, litEName, appEName, appTypeEName, infixEName, infixAppName,+ sectionLName, sectionRName, lamEName, lamCaseEName, tupEName,+ unboxedTupEName, unboxedSumEName, condEName, multiIfEName, letEName,+ caseEName, doEName, compEName, staticEName, unboundVarEName :: Name+varEName = libFun (fsLit "varE") varEIdKey+conEName = libFun (fsLit "conE") conEIdKey+litEName = libFun (fsLit "litE") litEIdKey+appEName = libFun (fsLit "appE") appEIdKey+appTypeEName = libFun (fsLit "appTypeE") appTypeEIdKey+infixEName = libFun (fsLit "infixE") infixEIdKey+infixAppName = libFun (fsLit "infixApp") infixAppIdKey+sectionLName = libFun (fsLit "sectionL") sectionLIdKey+sectionRName = libFun (fsLit "sectionR") sectionRIdKey+lamEName = libFun (fsLit "lamE") lamEIdKey+lamCaseEName = libFun (fsLit "lamCaseE") lamCaseEIdKey+tupEName = libFun (fsLit "tupE") tupEIdKey+unboxedTupEName = libFun (fsLit "unboxedTupE") unboxedTupEIdKey+unboxedSumEName = libFun (fsLit "unboxedSumE") unboxedSumEIdKey+condEName = libFun (fsLit "condE") condEIdKey+multiIfEName = libFun (fsLit "multiIfE") multiIfEIdKey+letEName = libFun (fsLit "letE") letEIdKey+caseEName = libFun (fsLit "caseE") caseEIdKey+doEName = libFun (fsLit "doE") doEIdKey+compEName = libFun (fsLit "compE") compEIdKey+-- ArithSeq skips a level+fromEName, fromThenEName, fromToEName, fromThenToEName :: Name+fromEName = libFun (fsLit "fromE") fromEIdKey+fromThenEName = libFun (fsLit "fromThenE") fromThenEIdKey+fromToEName = libFun (fsLit "fromToE") fromToEIdKey+fromThenToEName = libFun (fsLit "fromThenToE") fromThenToEIdKey+-- end ArithSeq+listEName, sigEName, recConEName, recUpdEName :: Name+listEName = libFun (fsLit "listE") listEIdKey+sigEName = libFun (fsLit "sigE") sigEIdKey+recConEName = libFun (fsLit "recConE") recConEIdKey+recUpdEName = libFun (fsLit "recUpdE") recUpdEIdKey+staticEName = libFun (fsLit "staticE") staticEIdKey+unboundVarEName = libFun (fsLit "unboundVarE") unboundVarEIdKey++-- type FieldExp = ...+fieldExpName :: Name+fieldExpName = libFun (fsLit "fieldExp") fieldExpIdKey++-- data Body = ...+guardedBName, normalBName :: Name+guardedBName = libFun (fsLit "guardedB") guardedBIdKey+normalBName = libFun (fsLit "normalB") normalBIdKey++-- data Guard = ...+normalGEName, patGEName :: Name+normalGEName = libFun (fsLit "normalGE") normalGEIdKey+patGEName = libFun (fsLit "patGE") patGEIdKey++-- data Stmt = ...+bindSName, letSName, noBindSName, parSName :: Name+bindSName = libFun (fsLit "bindS") bindSIdKey+letSName = libFun (fsLit "letS") letSIdKey+noBindSName = libFun (fsLit "noBindS") noBindSIdKey+parSName = libFun (fsLit "parS") parSIdKey++-- data Dec = ...+funDName, valDName, dataDName, newtypeDName, tySynDName, classDName,+ instanceWithOverlapDName, sigDName, forImpDName, pragInlDName,+ pragSpecDName, pragSpecInlDName, pragSpecInstDName, pragRuleDName,+ pragAnnDName, standaloneDerivWithStrategyDName, defaultSigDName,+ dataInstDName, newtypeInstDName, tySynInstDName, dataFamilyDName,+ openTypeFamilyDName, closedTypeFamilyDName, infixLDName, infixRDName,+ infixNDName, roleAnnotDName, patSynDName, patSynSigDName,+ pragCompleteDName :: Name+funDName = libFun (fsLit "funD") funDIdKey+valDName = libFun (fsLit "valD") valDIdKey+dataDName = libFun (fsLit "dataD") dataDIdKey+newtypeDName = libFun (fsLit "newtypeD") newtypeDIdKey+tySynDName = libFun (fsLit "tySynD") tySynDIdKey+classDName = libFun (fsLit "classD") classDIdKey+instanceWithOverlapDName+ = libFun (fsLit "instanceWithOverlapD") instanceWithOverlapDIdKey+standaloneDerivWithStrategyDName = libFun+ (fsLit "standaloneDerivWithStrategyD") standaloneDerivWithStrategyDIdKey+sigDName = libFun (fsLit "sigD") sigDIdKey+defaultSigDName = libFun (fsLit "defaultSigD") defaultSigDIdKey+forImpDName = libFun (fsLit "forImpD") forImpDIdKey+pragInlDName = libFun (fsLit "pragInlD") pragInlDIdKey+pragSpecDName = libFun (fsLit "pragSpecD") pragSpecDIdKey+pragSpecInlDName = libFun (fsLit "pragSpecInlD") pragSpecInlDIdKey+pragSpecInstDName = libFun (fsLit "pragSpecInstD") pragSpecInstDIdKey+pragRuleDName = libFun (fsLit "pragRuleD") pragRuleDIdKey+pragCompleteDName = libFun (fsLit "pragCompleteD") pragCompleteDIdKey+pragAnnDName = libFun (fsLit "pragAnnD") pragAnnDIdKey+dataInstDName = libFun (fsLit "dataInstD") dataInstDIdKey+newtypeInstDName = libFun (fsLit "newtypeInstD") newtypeInstDIdKey+tySynInstDName = libFun (fsLit "tySynInstD") tySynInstDIdKey+openTypeFamilyDName = libFun (fsLit "openTypeFamilyD") openTypeFamilyDIdKey+closedTypeFamilyDName= libFun (fsLit "closedTypeFamilyD") closedTypeFamilyDIdKey+dataFamilyDName = libFun (fsLit "dataFamilyD") dataFamilyDIdKey+infixLDName = libFun (fsLit "infixLD") infixLDIdKey+infixRDName = libFun (fsLit "infixRD") infixRDIdKey+infixNDName = libFun (fsLit "infixND") infixNDIdKey+roleAnnotDName = libFun (fsLit "roleAnnotD") roleAnnotDIdKey+patSynDName = libFun (fsLit "patSynD") patSynDIdKey+patSynSigDName = libFun (fsLit "patSynSigD") patSynSigDIdKey++-- type Ctxt = ...+cxtName :: Name+cxtName = libFun (fsLit "cxt") cxtIdKey++-- data SourceUnpackedness = ...+noSourceUnpackednessName, sourceNoUnpackName, sourceUnpackName :: Name+noSourceUnpackednessName = libFun (fsLit "noSourceUnpackedness") noSourceUnpackednessKey+sourceNoUnpackName = libFun (fsLit "sourceNoUnpack") sourceNoUnpackKey+sourceUnpackName = libFun (fsLit "sourceUnpack") sourceUnpackKey++-- data SourceStrictness = ...+noSourceStrictnessName, sourceLazyName, sourceStrictName :: Name+noSourceStrictnessName = libFun (fsLit "noSourceStrictness") noSourceStrictnessKey+sourceLazyName = libFun (fsLit "sourceLazy") sourceLazyKey+sourceStrictName = libFun (fsLit "sourceStrict") sourceStrictKey++-- data Con = ...+normalCName, recCName, infixCName, forallCName, gadtCName, recGadtCName :: Name+normalCName = libFun (fsLit "normalC" ) normalCIdKey+recCName = libFun (fsLit "recC" ) recCIdKey+infixCName = libFun (fsLit "infixC" ) infixCIdKey+forallCName = libFun (fsLit "forallC" ) forallCIdKey+gadtCName = libFun (fsLit "gadtC" ) gadtCIdKey+recGadtCName = libFun (fsLit "recGadtC") recGadtCIdKey++-- data Bang = ...+bangName :: Name+bangName = libFun (fsLit "bang") bangIdKey++-- type BangType = ...+bangTypeName :: Name+bangTypeName = libFun (fsLit "bangType") bangTKey++-- type VarBangType = ...+varBangTypeName :: Name+varBangTypeName = libFun (fsLit "varBangType") varBangTKey++-- data PatSynDir = ...+unidirPatSynName, implBidirPatSynName, explBidirPatSynName :: Name+unidirPatSynName = libFun (fsLit "unidir") unidirPatSynIdKey+implBidirPatSynName = libFun (fsLit "implBidir") implBidirPatSynIdKey+explBidirPatSynName = libFun (fsLit "explBidir") explBidirPatSynIdKey++-- data PatSynArgs = ...+prefixPatSynName, infixPatSynName, recordPatSynName :: Name+prefixPatSynName = libFun (fsLit "prefixPatSyn") prefixPatSynIdKey+infixPatSynName = libFun (fsLit "infixPatSyn") infixPatSynIdKey+recordPatSynName = libFun (fsLit "recordPatSyn") recordPatSynIdKey++-- data Type = ...+forallTName, varTName, conTName, tupleTName, unboxedTupleTName,+ unboxedSumTName, arrowTName, listTName, appTName, sigTName, equalityTName,+ litTName, promotedTName, promotedTupleTName, promotedNilTName,+ promotedConsTName, wildCardTName :: Name+forallTName = libFun (fsLit "forallT") forallTIdKey+varTName = libFun (fsLit "varT") varTIdKey+conTName = libFun (fsLit "conT") conTIdKey+tupleTName = libFun (fsLit "tupleT") tupleTIdKey+unboxedTupleTName = libFun (fsLit "unboxedTupleT") unboxedTupleTIdKey+unboxedSumTName = libFun (fsLit "unboxedSumT") unboxedSumTIdKey+arrowTName = libFun (fsLit "arrowT") arrowTIdKey+listTName = libFun (fsLit "listT") listTIdKey+appTName = libFun (fsLit "appT") appTIdKey+sigTName = libFun (fsLit "sigT") sigTIdKey+equalityTName = libFun (fsLit "equalityT") equalityTIdKey+litTName = libFun (fsLit "litT") litTIdKey+promotedTName = libFun (fsLit "promotedT") promotedTIdKey+promotedTupleTName = libFun (fsLit "promotedTupleT") promotedTupleTIdKey+promotedNilTName = libFun (fsLit "promotedNilT") promotedNilTIdKey+promotedConsTName = libFun (fsLit "promotedConsT") promotedConsTIdKey+wildCardTName = libFun (fsLit "wildCardT") wildCardTIdKey++-- data TyLit = ...+numTyLitName, strTyLitName :: Name+numTyLitName = libFun (fsLit "numTyLit") numTyLitIdKey+strTyLitName = libFun (fsLit "strTyLit") strTyLitIdKey++-- data TyVarBndr = ...+plainTVName, kindedTVName :: Name+plainTVName = libFun (fsLit "plainTV") plainTVIdKey+kindedTVName = libFun (fsLit "kindedTV") kindedTVIdKey++-- data Role = ...+nominalRName, representationalRName, phantomRName, inferRName :: Name+nominalRName = libFun (fsLit "nominalR") nominalRIdKey+representationalRName = libFun (fsLit "representationalR") representationalRIdKey+phantomRName = libFun (fsLit "phantomR") phantomRIdKey+inferRName = libFun (fsLit "inferR") inferRIdKey++-- data Kind = ...+varKName, conKName, tupleKName, arrowKName, listKName, appKName,+ starKName, constraintKName :: Name+varKName = libFun (fsLit "varK") varKIdKey+conKName = libFun (fsLit "conK") conKIdKey+tupleKName = libFun (fsLit "tupleK") tupleKIdKey+arrowKName = libFun (fsLit "arrowK") arrowKIdKey+listKName = libFun (fsLit "listK") listKIdKey+appKName = libFun (fsLit "appK") appKIdKey+starKName = libFun (fsLit "starK") starKIdKey+constraintKName = libFun (fsLit "constraintK") constraintKIdKey++-- data FamilyResultSig = ...+noSigName, kindSigName, tyVarSigName :: Name+noSigName = libFun (fsLit "noSig") noSigIdKey+kindSigName = libFun (fsLit "kindSig") kindSigIdKey+tyVarSigName = libFun (fsLit "tyVarSig") tyVarSigIdKey++-- data InjectivityAnn = ...+injectivityAnnName :: Name+injectivityAnnName = libFun (fsLit "injectivityAnn") injectivityAnnIdKey++-- data Callconv = ...+cCallName, stdCallName, cApiCallName, primCallName, javaScriptCallName :: Name+cCallName = libFun (fsLit "cCall") cCallIdKey+stdCallName = libFun (fsLit "stdCall") stdCallIdKey+cApiCallName = libFun (fsLit "cApi") cApiCallIdKey+primCallName = libFun (fsLit "prim") primCallIdKey+javaScriptCallName = libFun (fsLit "javaScript") javaScriptCallIdKey++-- data Safety = ...+unsafeName, safeName, interruptibleName :: Name+unsafeName = libFun (fsLit "unsafe") unsafeIdKey+safeName = libFun (fsLit "safe") safeIdKey+interruptibleName = libFun (fsLit "interruptible") interruptibleIdKey++-- newtype TExp a = ...+tExpDataConName :: Name+tExpDataConName = thCon (fsLit "TExp") tExpDataConKey++-- data RuleBndr = ...+ruleVarName, typedRuleVarName :: Name+ruleVarName = libFun (fsLit ("ruleVar")) ruleVarIdKey+typedRuleVarName = libFun (fsLit ("typedRuleVar")) typedRuleVarIdKey++-- data FunDep = ...+funDepName :: Name+funDepName = libFun (fsLit "funDep") funDepIdKey++-- data FamFlavour = ...+typeFamName, dataFamName :: Name+typeFamName = libFun (fsLit "typeFam") typeFamIdKey+dataFamName = libFun (fsLit "dataFam") dataFamIdKey++-- data TySynEqn = ...+tySynEqnName :: Name+tySynEqnName = libFun (fsLit "tySynEqn") tySynEqnIdKey++-- data AnnTarget = ...+valueAnnotationName, typeAnnotationName, moduleAnnotationName :: Name+valueAnnotationName = libFun (fsLit "valueAnnotation") valueAnnotationIdKey+typeAnnotationName = libFun (fsLit "typeAnnotation") typeAnnotationIdKey+moduleAnnotationName = libFun (fsLit "moduleAnnotation") moduleAnnotationIdKey++-- type DerivClause = ...+derivClauseName :: Name+derivClauseName = libFun (fsLit "derivClause") derivClauseIdKey++matchQTyConName, clauseQTyConName, expQTyConName, stmtQTyConName,+ decQTyConName, conQTyConName, bangTypeQTyConName,+ varBangTypeQTyConName, typeQTyConName, fieldExpQTyConName,+ patQTyConName, fieldPatQTyConName, predQTyConName, decsQTyConName,+ ruleBndrQTyConName, tySynEqnQTyConName, roleTyConName,+ derivClauseQTyConName :: Name+matchQTyConName = libTc (fsLit "MatchQ") matchQTyConKey+clauseQTyConName = libTc (fsLit "ClauseQ") clauseQTyConKey+expQTyConName = libTc (fsLit "ExpQ") expQTyConKey+stmtQTyConName = libTc (fsLit "StmtQ") stmtQTyConKey+decQTyConName = libTc (fsLit "DecQ") decQTyConKey+decsQTyConName = libTc (fsLit "DecsQ") decsQTyConKey -- Q [Dec]+conQTyConName = libTc (fsLit "ConQ") conQTyConKey+bangTypeQTyConName = libTc (fsLit "BangTypeQ") bangTypeQTyConKey+varBangTypeQTyConName = libTc (fsLit "VarBangTypeQ") varBangTypeQTyConKey+typeQTyConName = libTc (fsLit "TypeQ") typeQTyConKey+fieldExpQTyConName = libTc (fsLit "FieldExpQ") fieldExpQTyConKey+patQTyConName = libTc (fsLit "PatQ") patQTyConKey+fieldPatQTyConName = libTc (fsLit "FieldPatQ") fieldPatQTyConKey+predQTyConName = libTc (fsLit "PredQ") predQTyConKey+ruleBndrQTyConName = libTc (fsLit "RuleBndrQ") ruleBndrQTyConKey+tySynEqnQTyConName = libTc (fsLit "TySynEqnQ") tySynEqnQTyConKey+roleTyConName = libTc (fsLit "Role") roleTyConKey+derivClauseQTyConName = libTc (fsLit "DerivClauseQ") derivClauseQTyConKey++-- quasiquoting+quoteExpName, quotePatName, quoteDecName, quoteTypeName :: Name+quoteExpName = qqFun (fsLit "quoteExp") quoteExpKey+quotePatName = qqFun (fsLit "quotePat") quotePatKey+quoteDecName = qqFun (fsLit "quoteDec") quoteDecKey+quoteTypeName = qqFun (fsLit "quoteType") quoteTypeKey++-- data Inline = ...+noInlineDataConName, inlineDataConName, inlinableDataConName :: Name+noInlineDataConName = thCon (fsLit "NoInline") noInlineDataConKey+inlineDataConName = thCon (fsLit "Inline") inlineDataConKey+inlinableDataConName = thCon (fsLit "Inlinable") inlinableDataConKey++-- data RuleMatch = ...+conLikeDataConName, funLikeDataConName :: Name+conLikeDataConName = thCon (fsLit "ConLike") conLikeDataConKey+funLikeDataConName = thCon (fsLit "FunLike") funLikeDataConKey++-- data Phases = ...+allPhasesDataConName, fromPhaseDataConName, beforePhaseDataConName :: Name+allPhasesDataConName = thCon (fsLit "AllPhases") allPhasesDataConKey+fromPhaseDataConName = thCon (fsLit "FromPhase") fromPhaseDataConKey+beforePhaseDataConName = thCon (fsLit "BeforePhase") beforePhaseDataConKey++-- data Overlap = ...+overlappableDataConName,+ overlappingDataConName,+ overlapsDataConName,+ incoherentDataConName :: Name+overlappableDataConName = thCon (fsLit "Overlappable") overlappableDataConKey+overlappingDataConName = thCon (fsLit "Overlapping") overlappingDataConKey+overlapsDataConName = thCon (fsLit "Overlaps") overlapsDataConKey+incoherentDataConName = thCon (fsLit "Incoherent") incoherentDataConKey++-- data DerivStrategy = ...+stockStrategyDataConName, anyclassStrategyDataConName,+ newtypeStrategyDataConName :: Name+stockStrategyDataConName = thCon (fsLit "StockStrategy") stockDataConKey+anyclassStrategyDataConName = thCon (fsLit "AnyclassStrategy") anyclassDataConKey+newtypeStrategyDataConName = thCon (fsLit "NewtypeStrategy") newtypeDataConKey++{- *********************************************************************+* *+ Class keys+* *+********************************************************************* -}++-- ClassUniques available: 200-299+-- Check in PrelNames if you want to change this++liftClassKey :: Unique+liftClassKey = mkPreludeClassUnique 200++{- *********************************************************************+* *+ TyCon keys+* *+********************************************************************* -}++-- TyConUniques available: 200-299+-- Check in PrelNames if you want to change this++expTyConKey, matchTyConKey, clauseTyConKey, qTyConKey, expQTyConKey,+ decQTyConKey, patTyConKey, matchQTyConKey, clauseQTyConKey,+ stmtQTyConKey, conQTyConKey, typeQTyConKey, typeTyConKey, tyVarBndrTyConKey,+ decTyConKey, bangTypeQTyConKey, varBangTypeQTyConKey,+ fieldExpTyConKey, fieldPatTyConKey, nameTyConKey, patQTyConKey,+ fieldPatQTyConKey, fieldExpQTyConKey, funDepTyConKey, predTyConKey,+ predQTyConKey, decsQTyConKey, ruleBndrQTyConKey, tySynEqnQTyConKey,+ roleTyConKey, tExpTyConKey, injAnnTyConKey, kindTyConKey,+ overlapTyConKey, derivClauseQTyConKey, derivStrategyTyConKey :: Unique+expTyConKey = mkPreludeTyConUnique 200+matchTyConKey = mkPreludeTyConUnique 201+clauseTyConKey = mkPreludeTyConUnique 202+qTyConKey = mkPreludeTyConUnique 203+expQTyConKey = mkPreludeTyConUnique 204+decQTyConKey = mkPreludeTyConUnique 205+patTyConKey = mkPreludeTyConUnique 206+matchQTyConKey = mkPreludeTyConUnique 207+clauseQTyConKey = mkPreludeTyConUnique 208+stmtQTyConKey = mkPreludeTyConUnique 209+conQTyConKey = mkPreludeTyConUnique 210+typeQTyConKey = mkPreludeTyConUnique 211+typeTyConKey = mkPreludeTyConUnique 212+decTyConKey = mkPreludeTyConUnique 213+bangTypeQTyConKey = mkPreludeTyConUnique 214+varBangTypeQTyConKey = mkPreludeTyConUnique 215+fieldExpTyConKey = mkPreludeTyConUnique 216+fieldPatTyConKey = mkPreludeTyConUnique 217+nameTyConKey = mkPreludeTyConUnique 218+patQTyConKey = mkPreludeTyConUnique 219+fieldPatQTyConKey = mkPreludeTyConUnique 220+fieldExpQTyConKey = mkPreludeTyConUnique 221+funDepTyConKey = mkPreludeTyConUnique 222+predTyConKey = mkPreludeTyConUnique 223+predQTyConKey = mkPreludeTyConUnique 224+tyVarBndrTyConKey = mkPreludeTyConUnique 225+decsQTyConKey = mkPreludeTyConUnique 226+ruleBndrQTyConKey = mkPreludeTyConUnique 227+tySynEqnQTyConKey = mkPreludeTyConUnique 228+roleTyConKey = mkPreludeTyConUnique 229+tExpTyConKey = mkPreludeTyConUnique 230+injAnnTyConKey = mkPreludeTyConUnique 231+kindTyConKey = mkPreludeTyConUnique 232+overlapTyConKey = mkPreludeTyConUnique 233+derivClauseQTyConKey = mkPreludeTyConUnique 234+derivStrategyTyConKey = mkPreludeTyConUnique 235++{- *********************************************************************+* *+ DataCon keys+* *+********************************************************************* -}++-- DataConUniques available: 100-150+-- If you want to change this, make sure you check in PrelNames++-- data Inline = ...+noInlineDataConKey, inlineDataConKey, inlinableDataConKey :: Unique+noInlineDataConKey = mkPreludeDataConUnique 200+inlineDataConKey = mkPreludeDataConUnique 201+inlinableDataConKey = mkPreludeDataConUnique 202++-- data RuleMatch = ...+conLikeDataConKey, funLikeDataConKey :: Unique+conLikeDataConKey = mkPreludeDataConUnique 203+funLikeDataConKey = mkPreludeDataConUnique 204++-- data Phases = ...+allPhasesDataConKey, fromPhaseDataConKey, beforePhaseDataConKey :: Unique+allPhasesDataConKey = mkPreludeDataConUnique 205+fromPhaseDataConKey = mkPreludeDataConUnique 206+beforePhaseDataConKey = mkPreludeDataConUnique 207++-- newtype TExp a = ...+tExpDataConKey :: Unique+tExpDataConKey = mkPreludeDataConUnique 208++-- data Overlap = ..+overlappableDataConKey,+ overlappingDataConKey,+ overlapsDataConKey,+ incoherentDataConKey :: Unique+overlappableDataConKey = mkPreludeDataConUnique 209+overlappingDataConKey = mkPreludeDataConUnique 210+overlapsDataConKey = mkPreludeDataConUnique 211+incoherentDataConKey = mkPreludeDataConUnique 212++-- data DerivStrategy = ...+stockDataConKey, anyclassDataConKey, newtypeDataConKey :: Unique+stockDataConKey = mkPreludeDataConUnique 213+anyclassDataConKey = mkPreludeDataConUnique 214+newtypeDataConKey = mkPreludeDataConUnique 215++{- *********************************************************************+* *+ Id keys+* *+********************************************************************* -}++-- IdUniques available: 200-499+-- If you want to change this, make sure you check in PrelNames++returnQIdKey, bindQIdKey, sequenceQIdKey, liftIdKey, newNameIdKey,+ mkNameIdKey, mkNameG_vIdKey, mkNameG_dIdKey, mkNameG_tcIdKey,+ mkNameLIdKey, mkNameSIdKey, unTypeIdKey, unTypeQIdKey,+ unsafeTExpCoerceIdKey :: Unique+returnQIdKey = mkPreludeMiscIdUnique 200+bindQIdKey = mkPreludeMiscIdUnique 201+sequenceQIdKey = mkPreludeMiscIdUnique 202+liftIdKey = mkPreludeMiscIdUnique 203+newNameIdKey = mkPreludeMiscIdUnique 204+mkNameIdKey = mkPreludeMiscIdUnique 205+mkNameG_vIdKey = mkPreludeMiscIdUnique 206+mkNameG_dIdKey = mkPreludeMiscIdUnique 207+mkNameG_tcIdKey = mkPreludeMiscIdUnique 208+mkNameLIdKey = mkPreludeMiscIdUnique 209+mkNameSIdKey = mkPreludeMiscIdUnique 210+unTypeIdKey = mkPreludeMiscIdUnique 211+unTypeQIdKey = mkPreludeMiscIdUnique 212+unsafeTExpCoerceIdKey = mkPreludeMiscIdUnique 213+++-- data Lit = ...+charLIdKey, stringLIdKey, integerLIdKey, intPrimLIdKey, wordPrimLIdKey,+ floatPrimLIdKey, doublePrimLIdKey, rationalLIdKey, stringPrimLIdKey,+ charPrimLIdKey:: Unique+charLIdKey = mkPreludeMiscIdUnique 220+stringLIdKey = mkPreludeMiscIdUnique 221+integerLIdKey = mkPreludeMiscIdUnique 222+intPrimLIdKey = mkPreludeMiscIdUnique 223+wordPrimLIdKey = mkPreludeMiscIdUnique 224+floatPrimLIdKey = mkPreludeMiscIdUnique 225+doublePrimLIdKey = mkPreludeMiscIdUnique 226+rationalLIdKey = mkPreludeMiscIdUnique 227+stringPrimLIdKey = mkPreludeMiscIdUnique 228+charPrimLIdKey = mkPreludeMiscIdUnique 229++liftStringIdKey :: Unique+liftStringIdKey = mkPreludeMiscIdUnique 230++-- data Pat = ...+litPIdKey, varPIdKey, tupPIdKey, unboxedTupPIdKey, unboxedSumPIdKey, conPIdKey,+ infixPIdKey, tildePIdKey, bangPIdKey, asPIdKey, wildPIdKey, recPIdKey,+ listPIdKey, sigPIdKey, viewPIdKey :: Unique+litPIdKey = mkPreludeMiscIdUnique 240+varPIdKey = mkPreludeMiscIdUnique 241+tupPIdKey = mkPreludeMiscIdUnique 242+unboxedTupPIdKey = mkPreludeMiscIdUnique 243+unboxedSumPIdKey = mkPreludeMiscIdUnique 244+conPIdKey = mkPreludeMiscIdUnique 245+infixPIdKey = mkPreludeMiscIdUnique 246+tildePIdKey = mkPreludeMiscIdUnique 247+bangPIdKey = mkPreludeMiscIdUnique 248+asPIdKey = mkPreludeMiscIdUnique 249+wildPIdKey = mkPreludeMiscIdUnique 250+recPIdKey = mkPreludeMiscIdUnique 251+listPIdKey = mkPreludeMiscIdUnique 252+sigPIdKey = mkPreludeMiscIdUnique 253+viewPIdKey = mkPreludeMiscIdUnique 254++-- type FieldPat = ...+fieldPatIdKey :: Unique+fieldPatIdKey = mkPreludeMiscIdUnique 260++-- data Match = ...+matchIdKey :: Unique+matchIdKey = mkPreludeMiscIdUnique 261++-- data Clause = ...+clauseIdKey :: Unique+clauseIdKey = mkPreludeMiscIdUnique 262+++-- data Exp = ...+varEIdKey, conEIdKey, litEIdKey, appEIdKey, appTypeEIdKey, infixEIdKey,+ infixAppIdKey, sectionLIdKey, sectionRIdKey, lamEIdKey, lamCaseEIdKey,+ tupEIdKey, unboxedTupEIdKey, unboxedSumEIdKey, condEIdKey, multiIfEIdKey,+ letEIdKey, caseEIdKey, doEIdKey, compEIdKey,+ fromEIdKey, fromThenEIdKey, fromToEIdKey, fromThenToEIdKey,+ listEIdKey, sigEIdKey, recConEIdKey, recUpdEIdKey, staticEIdKey,+ unboundVarEIdKey :: Unique+varEIdKey = mkPreludeMiscIdUnique 270+conEIdKey = mkPreludeMiscIdUnique 271+litEIdKey = mkPreludeMiscIdUnique 272+appEIdKey = mkPreludeMiscIdUnique 273+appTypeEIdKey = mkPreludeMiscIdUnique 274+infixEIdKey = mkPreludeMiscIdUnique 275+infixAppIdKey = mkPreludeMiscIdUnique 276+sectionLIdKey = mkPreludeMiscIdUnique 277+sectionRIdKey = mkPreludeMiscIdUnique 278+lamEIdKey = mkPreludeMiscIdUnique 279+lamCaseEIdKey = mkPreludeMiscIdUnique 280+tupEIdKey = mkPreludeMiscIdUnique 281+unboxedTupEIdKey = mkPreludeMiscIdUnique 282+unboxedSumEIdKey = mkPreludeMiscIdUnique 283+condEIdKey = mkPreludeMiscIdUnique 284+multiIfEIdKey = mkPreludeMiscIdUnique 285+letEIdKey = mkPreludeMiscIdUnique 286+caseEIdKey = mkPreludeMiscIdUnique 287+doEIdKey = mkPreludeMiscIdUnique 288+compEIdKey = mkPreludeMiscIdUnique 289+fromEIdKey = mkPreludeMiscIdUnique 290+fromThenEIdKey = mkPreludeMiscIdUnique 291+fromToEIdKey = mkPreludeMiscIdUnique 292+fromThenToEIdKey = mkPreludeMiscIdUnique 293+listEIdKey = mkPreludeMiscIdUnique 294+sigEIdKey = mkPreludeMiscIdUnique 295+recConEIdKey = mkPreludeMiscIdUnique 296+recUpdEIdKey = mkPreludeMiscIdUnique 297+staticEIdKey = mkPreludeMiscIdUnique 298+unboundVarEIdKey = mkPreludeMiscIdUnique 299++-- type FieldExp = ...+fieldExpIdKey :: Unique+fieldExpIdKey = mkPreludeMiscIdUnique 305++-- data Body = ...+guardedBIdKey, normalBIdKey :: Unique+guardedBIdKey = mkPreludeMiscIdUnique 306+normalBIdKey = mkPreludeMiscIdUnique 307++-- data Guard = ...+normalGEIdKey, patGEIdKey :: Unique+normalGEIdKey = mkPreludeMiscIdUnique 308+patGEIdKey = mkPreludeMiscIdUnique 309++-- data Stmt = ...+bindSIdKey, letSIdKey, noBindSIdKey, parSIdKey :: Unique+bindSIdKey = mkPreludeMiscIdUnique 310+letSIdKey = mkPreludeMiscIdUnique 311+noBindSIdKey = mkPreludeMiscIdUnique 312+parSIdKey = mkPreludeMiscIdUnique 313++-- data Dec = ...+funDIdKey, valDIdKey, dataDIdKey, newtypeDIdKey, tySynDIdKey, classDIdKey,+ instanceWithOverlapDIdKey, instanceDIdKey, sigDIdKey, forImpDIdKey,+ pragInlDIdKey, pragSpecDIdKey, pragSpecInlDIdKey, pragSpecInstDIdKey,+ pragRuleDIdKey, pragAnnDIdKey, defaultSigDIdKey, dataFamilyDIdKey,+ openTypeFamilyDIdKey, closedTypeFamilyDIdKey, dataInstDIdKey,+ newtypeInstDIdKey, tySynInstDIdKey, standaloneDerivWithStrategyDIdKey,+ infixLDIdKey, infixRDIdKey, infixNDIdKey, roleAnnotDIdKey, patSynDIdKey,+ patSynSigDIdKey, pragCompleteDIdKey :: Unique+funDIdKey = mkPreludeMiscIdUnique 320+valDIdKey = mkPreludeMiscIdUnique 321+dataDIdKey = mkPreludeMiscIdUnique 322+newtypeDIdKey = mkPreludeMiscIdUnique 323+tySynDIdKey = mkPreludeMiscIdUnique 324+classDIdKey = mkPreludeMiscIdUnique 325+instanceWithOverlapDIdKey = mkPreludeMiscIdUnique 326+instanceDIdKey = mkPreludeMiscIdUnique 327+sigDIdKey = mkPreludeMiscIdUnique 328+forImpDIdKey = mkPreludeMiscIdUnique 329+pragInlDIdKey = mkPreludeMiscIdUnique 330+pragSpecDIdKey = mkPreludeMiscIdUnique 331+pragSpecInlDIdKey = mkPreludeMiscIdUnique 332+pragSpecInstDIdKey = mkPreludeMiscIdUnique 333+pragRuleDIdKey = mkPreludeMiscIdUnique 334+pragAnnDIdKey = mkPreludeMiscIdUnique 335+dataFamilyDIdKey = mkPreludeMiscIdUnique 336+openTypeFamilyDIdKey = mkPreludeMiscIdUnique 337+dataInstDIdKey = mkPreludeMiscIdUnique 338+newtypeInstDIdKey = mkPreludeMiscIdUnique 339+tySynInstDIdKey = mkPreludeMiscIdUnique 340+closedTypeFamilyDIdKey = mkPreludeMiscIdUnique 341+infixLDIdKey = mkPreludeMiscIdUnique 342+infixRDIdKey = mkPreludeMiscIdUnique 343+infixNDIdKey = mkPreludeMiscIdUnique 344+roleAnnotDIdKey = mkPreludeMiscIdUnique 345+standaloneDerivWithStrategyDIdKey = mkPreludeMiscIdUnique 346+defaultSigDIdKey = mkPreludeMiscIdUnique 347+patSynDIdKey = mkPreludeMiscIdUnique 348+patSynSigDIdKey = mkPreludeMiscIdUnique 349+pragCompleteDIdKey = mkPreludeMiscIdUnique 350++-- type Cxt = ...+cxtIdKey :: Unique+cxtIdKey = mkPreludeMiscIdUnique 351++-- data SourceUnpackedness = ...+noSourceUnpackednessKey, sourceNoUnpackKey, sourceUnpackKey :: Unique+noSourceUnpackednessKey = mkPreludeMiscIdUnique 352+sourceNoUnpackKey = mkPreludeMiscIdUnique 353+sourceUnpackKey = mkPreludeMiscIdUnique 354++-- data SourceStrictness = ...+noSourceStrictnessKey, sourceLazyKey, sourceStrictKey :: Unique+noSourceStrictnessKey = mkPreludeMiscIdUnique 355+sourceLazyKey = mkPreludeMiscIdUnique 356+sourceStrictKey = mkPreludeMiscIdUnique 357++-- data Con = ...+normalCIdKey, recCIdKey, infixCIdKey, forallCIdKey, gadtCIdKey,+ recGadtCIdKey :: Unique+normalCIdKey = mkPreludeMiscIdUnique 358+recCIdKey = mkPreludeMiscIdUnique 359+infixCIdKey = mkPreludeMiscIdUnique 360+forallCIdKey = mkPreludeMiscIdUnique 361+gadtCIdKey = mkPreludeMiscIdUnique 362+recGadtCIdKey = mkPreludeMiscIdUnique 363++-- data Bang = ...+bangIdKey :: Unique+bangIdKey = mkPreludeMiscIdUnique 364++-- type BangType = ...+bangTKey :: Unique+bangTKey = mkPreludeMiscIdUnique 365++-- type VarBangType = ...+varBangTKey :: Unique+varBangTKey = mkPreludeMiscIdUnique 366++-- data PatSynDir = ...+unidirPatSynIdKey, implBidirPatSynIdKey, explBidirPatSynIdKey :: Unique+unidirPatSynIdKey = mkPreludeMiscIdUnique 367+implBidirPatSynIdKey = mkPreludeMiscIdUnique 368+explBidirPatSynIdKey = mkPreludeMiscIdUnique 369++-- data PatSynArgs = ...+prefixPatSynIdKey, infixPatSynIdKey, recordPatSynIdKey :: Unique+prefixPatSynIdKey = mkPreludeMiscIdUnique 370+infixPatSynIdKey = mkPreludeMiscIdUnique 371+recordPatSynIdKey = mkPreludeMiscIdUnique 372++-- data Type = ...+forallTIdKey, varTIdKey, conTIdKey, tupleTIdKey, unboxedTupleTIdKey,+ unboxedSumTIdKey, arrowTIdKey, listTIdKey, appTIdKey, sigTIdKey,+ equalityTIdKey, litTIdKey, promotedTIdKey, promotedTupleTIdKey,+ promotedNilTIdKey, promotedConsTIdKey, wildCardTIdKey :: Unique+forallTIdKey = mkPreludeMiscIdUnique 381+varTIdKey = mkPreludeMiscIdUnique 382+conTIdKey = mkPreludeMiscIdUnique 383+tupleTIdKey = mkPreludeMiscIdUnique 384+unboxedTupleTIdKey = mkPreludeMiscIdUnique 385+unboxedSumTIdKey = mkPreludeMiscIdUnique 386+arrowTIdKey = mkPreludeMiscIdUnique 387+listTIdKey = mkPreludeMiscIdUnique 388+appTIdKey = mkPreludeMiscIdUnique 389+sigTIdKey = mkPreludeMiscIdUnique 390+equalityTIdKey = mkPreludeMiscIdUnique 391+litTIdKey = mkPreludeMiscIdUnique 392+promotedTIdKey = mkPreludeMiscIdUnique 393+promotedTupleTIdKey = mkPreludeMiscIdUnique 394+promotedNilTIdKey = mkPreludeMiscIdUnique 395+promotedConsTIdKey = mkPreludeMiscIdUnique 396+wildCardTIdKey = mkPreludeMiscIdUnique 397++-- data TyLit = ...+numTyLitIdKey, strTyLitIdKey :: Unique+numTyLitIdKey = mkPreludeMiscIdUnique 400+strTyLitIdKey = mkPreludeMiscIdUnique 401++-- data TyVarBndr = ...+plainTVIdKey, kindedTVIdKey :: Unique+plainTVIdKey = mkPreludeMiscIdUnique 402+kindedTVIdKey = mkPreludeMiscIdUnique 403++-- data Role = ...+nominalRIdKey, representationalRIdKey, phantomRIdKey, inferRIdKey :: Unique+nominalRIdKey = mkPreludeMiscIdUnique 404+representationalRIdKey = mkPreludeMiscIdUnique 405+phantomRIdKey = mkPreludeMiscIdUnique 406+inferRIdKey = mkPreludeMiscIdUnique 407++-- data Kind = ...+varKIdKey, conKIdKey, tupleKIdKey, arrowKIdKey, listKIdKey, appKIdKey,+ starKIdKey, constraintKIdKey :: Unique+varKIdKey = mkPreludeMiscIdUnique 408+conKIdKey = mkPreludeMiscIdUnique 409+tupleKIdKey = mkPreludeMiscIdUnique 410+arrowKIdKey = mkPreludeMiscIdUnique 411+listKIdKey = mkPreludeMiscIdUnique 412+appKIdKey = mkPreludeMiscIdUnique 413+starKIdKey = mkPreludeMiscIdUnique 414+constraintKIdKey = mkPreludeMiscIdUnique 415++-- data FamilyResultSig = ...+noSigIdKey, kindSigIdKey, tyVarSigIdKey :: Unique+noSigIdKey = mkPreludeMiscIdUnique 416+kindSigIdKey = mkPreludeMiscIdUnique 417+tyVarSigIdKey = mkPreludeMiscIdUnique 418++-- data InjectivityAnn = ...+injectivityAnnIdKey :: Unique+injectivityAnnIdKey = mkPreludeMiscIdUnique 419++-- data Callconv = ...+cCallIdKey, stdCallIdKey, cApiCallIdKey, primCallIdKey,+ javaScriptCallIdKey :: Unique+cCallIdKey = mkPreludeMiscIdUnique 420+stdCallIdKey = mkPreludeMiscIdUnique 421+cApiCallIdKey = mkPreludeMiscIdUnique 422+primCallIdKey = mkPreludeMiscIdUnique 423+javaScriptCallIdKey = mkPreludeMiscIdUnique 424++-- data Safety = ...+unsafeIdKey, safeIdKey, interruptibleIdKey :: Unique+unsafeIdKey = mkPreludeMiscIdUnique 430+safeIdKey = mkPreludeMiscIdUnique 431+interruptibleIdKey = mkPreludeMiscIdUnique 432++-- data FunDep = ...+funDepIdKey :: Unique+funDepIdKey = mkPreludeMiscIdUnique 440++-- data FamFlavour = ...+typeFamIdKey, dataFamIdKey :: Unique+typeFamIdKey = mkPreludeMiscIdUnique 450+dataFamIdKey = mkPreludeMiscIdUnique 451++-- data TySynEqn = ...+tySynEqnIdKey :: Unique+tySynEqnIdKey = mkPreludeMiscIdUnique 460++-- quasiquoting+quoteExpKey, quotePatKey, quoteDecKey, quoteTypeKey :: Unique+quoteExpKey = mkPreludeMiscIdUnique 470+quotePatKey = mkPreludeMiscIdUnique 471+quoteDecKey = mkPreludeMiscIdUnique 472+quoteTypeKey = mkPreludeMiscIdUnique 473++-- data RuleBndr = ...+ruleVarIdKey, typedRuleVarIdKey :: Unique+ruleVarIdKey = mkPreludeMiscIdUnique 480+typedRuleVarIdKey = mkPreludeMiscIdUnique 481++-- data AnnTarget = ...+valueAnnotationIdKey, typeAnnotationIdKey, moduleAnnotationIdKey :: Unique+valueAnnotationIdKey = mkPreludeMiscIdUnique 490+typeAnnotationIdKey = mkPreludeMiscIdUnique 491+moduleAnnotationIdKey = mkPreludeMiscIdUnique 492++-- type DerivPred = ...+derivClauseIdKey :: Unique+derivClauseIdKey = mkPreludeMiscIdUnique 493++{-+************************************************************************+* *+ RdrNames+* *+************************************************************************+-}++lift_RDR, mkNameG_dRDR, mkNameG_vRDR :: RdrName+lift_RDR = nameRdrName liftName+mkNameG_dRDR = nameRdrName mkNameG_dName+mkNameG_vRDR = nameRdrName mkNameG_vName++-- data Exp = ...+conE_RDR, litE_RDR, appE_RDR, infixApp_RDR :: RdrName+conE_RDR = nameRdrName conEName+litE_RDR = nameRdrName litEName+appE_RDR = nameRdrName appEName+infixApp_RDR = nameRdrName infixAppName++-- data Lit = ...+stringL_RDR, intPrimL_RDR, wordPrimL_RDR, floatPrimL_RDR,+ doublePrimL_RDR, stringPrimL_RDR, charPrimL_RDR :: RdrName+stringL_RDR = nameRdrName stringLName+intPrimL_RDR = nameRdrName intPrimLName+wordPrimL_RDR = nameRdrName wordPrimLName+floatPrimL_RDR = nameRdrName floatPrimLName+doublePrimL_RDR = nameRdrName doublePrimLName+stringPrimL_RDR = nameRdrName stringPrimLName+charPrimL_RDR = nameRdrName charPrimLName
+ prelude/TysPrim.hs view
@@ -0,0 +1,1003 @@+{-+(c) The AQUA Project, Glasgow University, 1994-1998+++\section[TysPrim]{Wired-in knowledge about primitive types}+-}++{-# LANGUAGE CPP #-}++-- | This module defines TyCons that can't be expressed in Haskell.+-- They are all, therefore, wired-in TyCons. C.f module TysWiredIn+module TysPrim(+ mkPrimTyConName, -- For implicit parameters in TysWiredIn only++ mkTemplateKindVars, mkTemplateTyVars, mkTemplateTyVarsFrom,+ mkTemplateKiTyVars,++ mkTemplateTyConBinders, mkTemplateKindTyConBinders,+ mkTemplateAnonTyConBinders,++ alphaTyVars, alphaTyVar, betaTyVar, gammaTyVar, deltaTyVar,+ alphaTys, alphaTy, betaTy, gammaTy, deltaTy,+ runtimeRep1TyVar, runtimeRep2TyVar, runtimeRep1Ty, runtimeRep2Ty,+ openAlphaTy, openBetaTy, openAlphaTyVar, openBetaTyVar,++ -- Kind constructors...+ tYPETyCon, tYPETyConName,++ -- Kinds+ tYPE, primRepToRuntimeRep,++ funTyCon, funTyConName,+ primTyCons,++ charPrimTyCon, charPrimTy, charPrimTyConName,+ intPrimTyCon, intPrimTy, intPrimTyConName,+ wordPrimTyCon, wordPrimTy, wordPrimTyConName,+ addrPrimTyCon, addrPrimTy, addrPrimTyConName,+ floatPrimTyCon, floatPrimTy, floatPrimTyConName,+ doublePrimTyCon, doublePrimTy, doublePrimTyConName,++ voidPrimTyCon, voidPrimTy,+ statePrimTyCon, mkStatePrimTy,+ realWorldTyCon, realWorldTy, realWorldStatePrimTy,++ proxyPrimTyCon, mkProxyPrimTy,++ arrayPrimTyCon, mkArrayPrimTy,+ byteArrayPrimTyCon, byteArrayPrimTy,+ arrayArrayPrimTyCon, mkArrayArrayPrimTy,+ smallArrayPrimTyCon, mkSmallArrayPrimTy,+ mutableArrayPrimTyCon, mkMutableArrayPrimTy,+ mutableByteArrayPrimTyCon, mkMutableByteArrayPrimTy,+ mutableArrayArrayPrimTyCon, mkMutableArrayArrayPrimTy,+ smallMutableArrayPrimTyCon, mkSmallMutableArrayPrimTy,+ mutVarPrimTyCon, mkMutVarPrimTy,++ mVarPrimTyCon, mkMVarPrimTy,+ tVarPrimTyCon, mkTVarPrimTy,+ stablePtrPrimTyCon, mkStablePtrPrimTy,+ stableNamePrimTyCon, mkStableNamePrimTy,+ compactPrimTyCon, compactPrimTy,+ bcoPrimTyCon, bcoPrimTy,+ weakPrimTyCon, mkWeakPrimTy,+ threadIdPrimTyCon, threadIdPrimTy,++ int32PrimTyCon, int32PrimTy,+ word32PrimTyCon, word32PrimTy,++ int64PrimTyCon, int64PrimTy,+ word64PrimTyCon, word64PrimTy,++ eqPrimTyCon, -- ty1 ~# ty2+ eqReprPrimTyCon, -- ty1 ~R# ty2 (at role Representational)+ eqPhantPrimTyCon, -- ty1 ~P# ty2 (at role Phantom)++ -- * SIMD+#include "primop-vector-tys-exports.hs-incl"+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} TysWiredIn+ ( runtimeRepTy, unboxedTupleKind, liftedTypeKind+ , vecRepDataConTyCon, tupleRepDataConTyCon+ , liftedRepDataConTy, unliftedRepDataConTy, intRepDataConTy+ , wordRepDataConTy, int64RepDataConTy, word64RepDataConTy, addrRepDataConTy+ , floatRepDataConTy, doubleRepDataConTy+ , vec2DataConTy, vec4DataConTy, vec8DataConTy, vec16DataConTy, vec32DataConTy+ , vec64DataConTy+ , int8ElemRepDataConTy, int16ElemRepDataConTy, int32ElemRepDataConTy+ , int64ElemRepDataConTy, word8ElemRepDataConTy, word16ElemRepDataConTy+ , word32ElemRepDataConTy, word64ElemRepDataConTy, floatElemRepDataConTy+ , doubleElemRepDataConTy+ , mkPromotedListTy )++import Var ( TyVar, TyVarBndr(TvBndr), mkTyVar )+import Name+import TyCon+import SrcLoc+import Unique+import PrelNames+import FastString+import Outputable+import TyCoRep -- Doesn't need special access, but this is easier to avoid+ -- import loops which show up if you import Type instead++import Data.Char++{-+************************************************************************+* *+\subsection{Primitive type constructors}+* *+************************************************************************+-}++primTyCons :: [TyCon]+primTyCons+ = [ addrPrimTyCon+ , arrayPrimTyCon+ , byteArrayPrimTyCon+ , arrayArrayPrimTyCon+ , smallArrayPrimTyCon+ , charPrimTyCon+ , doublePrimTyCon+ , floatPrimTyCon+ , intPrimTyCon+ , int32PrimTyCon+ , int64PrimTyCon+ , bcoPrimTyCon+ , weakPrimTyCon+ , mutableArrayPrimTyCon+ , mutableByteArrayPrimTyCon+ , mutableArrayArrayPrimTyCon+ , smallMutableArrayPrimTyCon+ , mVarPrimTyCon+ , tVarPrimTyCon+ , mutVarPrimTyCon+ , realWorldTyCon+ , stablePtrPrimTyCon+ , stableNamePrimTyCon+ , compactPrimTyCon+ , statePrimTyCon+ , voidPrimTyCon+ , proxyPrimTyCon+ , threadIdPrimTyCon+ , wordPrimTyCon+ , word32PrimTyCon+ , word64PrimTyCon+ , eqPrimTyCon+ , eqReprPrimTyCon+ , eqPhantPrimTyCon++ , tYPETyCon++#include "primop-vector-tycons.hs-incl"+ ]++mkPrimTc :: FastString -> Unique -> TyCon -> Name+mkPrimTc fs unique tycon+ = mkWiredInName gHC_PRIM (mkTcOccFS fs)+ unique+ (ATyCon tycon) -- Relevant TyCon+ UserSyntax++mkBuiltInPrimTc :: FastString -> Unique -> TyCon -> Name+mkBuiltInPrimTc fs unique tycon+ = mkWiredInName gHC_PRIM (mkTcOccFS fs)+ unique+ (ATyCon tycon) -- Relevant TyCon+ BuiltInSyntax+++charPrimTyConName, intPrimTyConName, int32PrimTyConName, int64PrimTyConName, wordPrimTyConName, word32PrimTyConName, word64PrimTyConName, addrPrimTyConName, floatPrimTyConName, doublePrimTyConName, statePrimTyConName, proxyPrimTyConName, realWorldTyConName, arrayPrimTyConName, arrayArrayPrimTyConName, smallArrayPrimTyConName, byteArrayPrimTyConName, mutableArrayPrimTyConName, mutableByteArrayPrimTyConName, mutableArrayArrayPrimTyConName, smallMutableArrayPrimTyConName, mutVarPrimTyConName, mVarPrimTyConName, tVarPrimTyConName, stablePtrPrimTyConName, stableNamePrimTyConName, compactPrimTyConName, bcoPrimTyConName, weakPrimTyConName, threadIdPrimTyConName, eqPrimTyConName, eqReprPrimTyConName, eqPhantPrimTyConName, voidPrimTyConName :: Name+charPrimTyConName = mkPrimTc (fsLit "Char#") charPrimTyConKey charPrimTyCon+intPrimTyConName = mkPrimTc (fsLit "Int#") intPrimTyConKey intPrimTyCon+int32PrimTyConName = mkPrimTc (fsLit "Int32#") int32PrimTyConKey int32PrimTyCon+int64PrimTyConName = mkPrimTc (fsLit "Int64#") int64PrimTyConKey int64PrimTyCon+wordPrimTyConName = mkPrimTc (fsLit "Word#") wordPrimTyConKey wordPrimTyCon+word32PrimTyConName = mkPrimTc (fsLit "Word32#") word32PrimTyConKey word32PrimTyCon+word64PrimTyConName = mkPrimTc (fsLit "Word64#") word64PrimTyConKey word64PrimTyCon+addrPrimTyConName = mkPrimTc (fsLit "Addr#") addrPrimTyConKey addrPrimTyCon+floatPrimTyConName = mkPrimTc (fsLit "Float#") floatPrimTyConKey floatPrimTyCon+doublePrimTyConName = mkPrimTc (fsLit "Double#") doublePrimTyConKey doublePrimTyCon+statePrimTyConName = mkPrimTc (fsLit "State#") statePrimTyConKey statePrimTyCon+voidPrimTyConName = mkPrimTc (fsLit "Void#") voidPrimTyConKey voidPrimTyCon+proxyPrimTyConName = mkPrimTc (fsLit "Proxy#") proxyPrimTyConKey proxyPrimTyCon+eqPrimTyConName = mkPrimTc (fsLit "~#") eqPrimTyConKey eqPrimTyCon+eqReprPrimTyConName = mkBuiltInPrimTc (fsLit "~R#") eqReprPrimTyConKey eqReprPrimTyCon+eqPhantPrimTyConName = mkBuiltInPrimTc (fsLit "~P#") eqPhantPrimTyConKey eqPhantPrimTyCon+realWorldTyConName = mkPrimTc (fsLit "RealWorld") realWorldTyConKey realWorldTyCon+arrayPrimTyConName = mkPrimTc (fsLit "Array#") arrayPrimTyConKey arrayPrimTyCon+byteArrayPrimTyConName = mkPrimTc (fsLit "ByteArray#") byteArrayPrimTyConKey byteArrayPrimTyCon+arrayArrayPrimTyConName = mkPrimTc (fsLit "ArrayArray#") arrayArrayPrimTyConKey arrayArrayPrimTyCon+smallArrayPrimTyConName = mkPrimTc (fsLit "SmallArray#") smallArrayPrimTyConKey smallArrayPrimTyCon+mutableArrayPrimTyConName = mkPrimTc (fsLit "MutableArray#") mutableArrayPrimTyConKey mutableArrayPrimTyCon+mutableByteArrayPrimTyConName = mkPrimTc (fsLit "MutableByteArray#") mutableByteArrayPrimTyConKey mutableByteArrayPrimTyCon+mutableArrayArrayPrimTyConName= mkPrimTc (fsLit "MutableArrayArray#") mutableArrayArrayPrimTyConKey mutableArrayArrayPrimTyCon+smallMutableArrayPrimTyConName= mkPrimTc (fsLit "SmallMutableArray#") smallMutableArrayPrimTyConKey smallMutableArrayPrimTyCon+mutVarPrimTyConName = mkPrimTc (fsLit "MutVar#") mutVarPrimTyConKey mutVarPrimTyCon+mVarPrimTyConName = mkPrimTc (fsLit "MVar#") mVarPrimTyConKey mVarPrimTyCon+tVarPrimTyConName = mkPrimTc (fsLit "TVar#") tVarPrimTyConKey tVarPrimTyCon+stablePtrPrimTyConName = mkPrimTc (fsLit "StablePtr#") stablePtrPrimTyConKey stablePtrPrimTyCon+stableNamePrimTyConName = mkPrimTc (fsLit "StableName#") stableNamePrimTyConKey stableNamePrimTyCon+compactPrimTyConName = mkPrimTc (fsLit "Compact#") compactPrimTyConKey compactPrimTyCon+bcoPrimTyConName = mkPrimTc (fsLit "BCO#") bcoPrimTyConKey bcoPrimTyCon+weakPrimTyConName = mkPrimTc (fsLit "Weak#") weakPrimTyConKey weakPrimTyCon+threadIdPrimTyConName = mkPrimTc (fsLit "ThreadId#") threadIdPrimTyConKey threadIdPrimTyCon++{-+************************************************************************+* *+\subsection{Support code}+* *+************************************************************************++alphaTyVars is a list of type variables for use in templates:+ ["a", "b", ..., "z", "t1", "t2", ... ]+-}++mkTemplateKindVars :: [Kind] -> [TyVar]+-- k0 with unique (mkAlphaTyVarUnique 0)+-- k1 with unique (mkAlphaTyVarUnique 1)+-- ... etc+mkTemplateKindVars kinds+ = [ mkTyVar name kind+ | (kind, u) <- kinds `zip` [0..]+ , let occ = mkTyVarOccFS (mkFastString ('k' : show u))+ name = mkInternalName (mkAlphaTyVarUnique u) occ noSrcSpan+ ]++mkTemplateTyVarsFrom :: Int -> [Kind] -> [TyVar]+-- a with unique (mkAlphaTyVarUnique n)+-- b with unique (mkAlphaTyVarUnique n+1)+-- ... etc+-- Typically called as+-- mkTemplateTyVarsFrom (legth kv_bndrs) kinds+-- where kv_bndrs are the kind-level binders of a TyCon+mkTemplateTyVarsFrom n kinds+ = [ mkTyVar name kind+ | (kind, index) <- zip kinds [0..],+ let ch_ord = index + ord 'a'+ name_str | ch_ord <= ord 'z' = [chr ch_ord]+ | otherwise = 't':show index+ uniq = mkAlphaTyVarUnique (index + n)+ name = mkInternalName uniq occ noSrcSpan+ occ = mkTyVarOccFS (mkFastString name_str)+ ]++mkTemplateTyVars :: [Kind] -> [TyVar]+mkTemplateTyVars = mkTemplateTyVarsFrom 1++mkTemplateTyConBinders+ :: [Kind] -- [k1, .., kn] Kinds of kind-forall'd vars+ -> ([Kind] -> [Kind]) -- Arg is [kv1:k1, ..., kvn:kn]+ -- same length as first arg+ -- Result is anon arg kinds+ -> [TyConBinder]+mkTemplateTyConBinders kind_var_kinds mk_anon_arg_kinds+ = kv_bndrs ++ tv_bndrs+ where+ kv_bndrs = mkTemplateKindTyConBinders kind_var_kinds+ anon_kinds = mk_anon_arg_kinds (mkTyVarTys (binderVars kv_bndrs))+ tv_bndrs = mkTemplateAnonTyConBindersFrom (length kv_bndrs) anon_kinds++mkTemplateKiTyVars+ :: [Kind] -- [k1, .., kn] Kinds of kind-forall'd vars+ -> ([Kind] -> [Kind]) -- Arg is [kv1:k1, ..., kvn:kn]+ -- same length as first arg+ -- Result is anon arg kinds [ak1, .., akm]+ -> [TyVar] -- [kv1:k1, ..., kvn:kn, av1:ak1, ..., avm:akm]+-- Example: if you want the tyvars for+-- forall (r:RuntimeRep) (a:TYPE r) (b:*). blah+-- call mkTemplateKiTyVars [RuntimeRep] (\[r]. [TYPE r, *)+mkTemplateKiTyVars kind_var_kinds mk_arg_kinds+ = kv_bndrs ++ tv_bndrs+ where+ kv_bndrs = mkTemplateKindVars kind_var_kinds+ anon_kinds = mk_arg_kinds (mkTyVarTys kv_bndrs)+ tv_bndrs = mkTemplateTyVarsFrom (length kv_bndrs) anon_kinds++mkTemplateKindTyConBinders :: [Kind] -> [TyConBinder]+-- Makes named, Specified binders+mkTemplateKindTyConBinders kinds = [mkNamedTyConBinder Specified tv | tv <- mkTemplateKindVars kinds]++mkTemplateAnonTyConBinders :: [Kind] -> [TyConBinder]+mkTemplateAnonTyConBinders kinds = map mkAnonTyConBinder (mkTemplateTyVars kinds)++mkTemplateAnonTyConBindersFrom :: Int -> [Kind] -> [TyConBinder]+mkTemplateAnonTyConBindersFrom n kinds = map mkAnonTyConBinder (mkTemplateTyVarsFrom n kinds)++alphaTyVars :: [TyVar]+alphaTyVars = mkTemplateTyVars $ repeat liftedTypeKind++alphaTyVar, betaTyVar, gammaTyVar, deltaTyVar :: TyVar+(alphaTyVar:betaTyVar:gammaTyVar:deltaTyVar:_) = alphaTyVars++alphaTys :: [Type]+alphaTys = mkTyVarTys alphaTyVars+alphaTy, betaTy, gammaTy, deltaTy :: Type+(alphaTy:betaTy:gammaTy:deltaTy:_) = alphaTys++runtimeRep1TyVar, runtimeRep2TyVar :: TyVar+(runtimeRep1TyVar : runtimeRep2TyVar : _)+ = drop 16 (mkTemplateTyVars (repeat runtimeRepTy)) -- selects 'q','r'++runtimeRep1Ty, runtimeRep2Ty :: Type+runtimeRep1Ty = mkTyVarTy runtimeRep1TyVar+runtimeRep2Ty = mkTyVarTy runtimeRep2TyVar++openAlphaTyVar, openBetaTyVar :: TyVar+[openAlphaTyVar,openBetaTyVar]+ = mkTemplateTyVars [tYPE runtimeRep1Ty, tYPE runtimeRep2Ty]++openAlphaTy, openBetaTy :: Type+openAlphaTy = mkTyVarTy openAlphaTyVar+openBetaTy = mkTyVarTy openBetaTyVar++{-+************************************************************************+* *+ FunTyCon+* *+************************************************************************+-}++funTyConName :: Name+funTyConName = mkPrimTyConName (fsLit "(->)") funTyConKey funTyCon++-- | The @(->)@ type constructor.+--+-- @+-- (->) :: forall (rep1 :: RuntimeRep) (rep2 :: RuntimeRep).+-- TYPE rep1 -> TYPE rep2 -> *+-- @+funTyCon :: TyCon+funTyCon = mkFunTyCon funTyConName tc_bndrs tc_rep_nm+ where+ tc_bndrs = [ TvBndr runtimeRep1TyVar (NamedTCB Inferred)+ , TvBndr runtimeRep2TyVar (NamedTCB Inferred)+ ]+ ++ mkTemplateAnonTyConBinders [ tYPE runtimeRep1Ty+ , tYPE runtimeRep2Ty+ ]+ tc_rep_nm = mkPrelTyConRepName funTyConName++{-+************************************************************************+* *+ Kinds+* *+************************************************************************++Note [TYPE and RuntimeRep]+~~~~~~~~~~~~~~~~~~~~~~~~~~+All types that classify values have a kind of the form (TYPE rr), where++ data RuntimeRep -- Defined in ghc-prim:GHC.Types+ = LiftedRep+ | UnliftedRep+ | IntRep+ | FloatRep+ .. etc ..++ rr :: RuntimeRep++ TYPE :: RuntimeRep -> TYPE 'LiftedRep -- Built in++So for example:+ Int :: TYPE 'LiftedRep+ Array# Int :: TYPE 'UnliftedRep+ Int# :: TYPE 'IntRep+ Float# :: TYPE 'FloatRep+ Maybe :: TYPE 'LiftedRep -> TYPE 'LiftedRep+ (# , #) :: TYPE r1 -> TYPE r2 -> TYPE (TupleRep [r1, r2])++We abbreviate '*' specially:+ type * = TYPE 'LiftedRep++The 'rr' parameter tells us how the value is represented at runime.++Generally speaking, you can't be polymorphic in 'rr'. E.g+ f :: forall (rr:RuntimeRep) (a:TYPE rr). a -> [a]+ f = /\(rr:RuntimeRep) (a:rr) \(a:rr). ...+This is no good: we could not generate code code for 'f', because the+calling convention for 'f' varies depending on whether the argument is+a a Int, Int#, or Float#. (You could imagine generating specialised+code, one for each instantiation of 'rr', but we don't do that.)++Certain functions CAN be runtime-rep-polymorphic, because the code+generator never has to manipulate a value of type 'a :: TYPE rr'.++* error :: forall (rr:RuntimeRep) (a:TYPE rr). String -> a+ Code generator never has to manipulate the return value.++* unsafeCoerce#, defined in MkId.unsafeCoerceId:+ Always inlined to be a no-op+ unsafeCoerce# :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep)+ (a :: TYPE r1) (b :: TYPE r2).+ a -> b++* Unboxed tuples, and unboxed sums, defined in TysWiredIn+ Always inlined, and hence specialised to the call site+ (#,#) :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep)+ (a :: TYPE r1) (b :: TYPE r2).+ a -> b -> TYPE ('TupleRep '[r1, r2])++Note [PrimRep and kindPrimRep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As part of its source code, in TyCon, GHC has+ data PrimRep = LiftedRep | UnliftedRep | IntRep | FloatRep | ...etc...++Notice that+ * RuntimeRep is part of the syntax tree of the program being compiled+ (defined in a library: ghc-prim:GHC.Types)+ * PrimRep is part of GHC's source code.+ (defined in TyCon)++We need to get from one to the other; that is what kindPrimRep does.+Suppose we have a value+ (v :: t) where (t :: k)+Given this kind+ k = TyConApp "TYPE" [rep]+GHC needs to be able to figure out how 'v' is represented at runtime.+It expects 'rep' to be form+ TyConApp rr_dc args+where 'rr_dc' is a promoteed data constructor from RuntimeRep. So+now we need to go from 'dc' to the corresponding PrimRep. We store this+PrimRep in the promoted data constructor itself: see TyCon.promDcRepInfo.++-}++tYPETyCon :: TyCon+tYPETyConName :: Name++tYPETyCon = mkKindTyCon tYPETyConName+ (mkTemplateAnonTyConBinders [runtimeRepTy])+ liftedTypeKind+ [Nominal]+ (mkPrelTyConRepName tYPETyConName)++--------------------------+-- ... and now their names++-- If you edit these, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+tYPETyConName = mkPrimTyConName (fsLit "TYPE") tYPETyConKey tYPETyCon++mkPrimTyConName :: FastString -> Unique -> TyCon -> Name+mkPrimTyConName = mkPrimTcName BuiltInSyntax+ -- All of the super kinds and kinds are defined in Prim,+ -- and use BuiltInSyntax, because they are never in scope in the source++mkPrimTcName :: BuiltInSyntax -> FastString -> Unique -> TyCon -> Name+mkPrimTcName built_in_syntax occ key tycon+ = mkWiredInName gHC_PRIM (mkTcOccFS occ) key (ATyCon tycon) built_in_syntax++-----------------------------+-- | Given a RuntimeRep, applies TYPE to it.+-- see Note [TYPE and RuntimeRep]+tYPE :: Type -> Type+tYPE rr = TyConApp tYPETyCon [rr]++{-+************************************************************************+* *+\subsection[TysPrim-basic]{Basic primitive types (@Char#@, @Int#@, etc.)}+* *+************************************************************************+-}++-- only used herein+pcPrimTyCon :: Name -> [Role] -> PrimRep -> TyCon+pcPrimTyCon name roles rep+ = mkPrimTyCon name binders result_kind roles+ where+ binders = mkTemplateAnonTyConBinders (map (const liftedTypeKind) roles)+ result_kind = tYPE (primRepToRuntimeRep rep)++-- | Convert a 'PrimRep' to a 'Type' of kind RuntimeRep+-- Defined here to avoid (more) module loops+primRepToRuntimeRep :: PrimRep -> Type+primRepToRuntimeRep rep = case rep of+ VoidRep -> TyConApp tupleRepDataConTyCon [mkPromotedListTy runtimeRepTy []]+ LiftedRep -> liftedRepDataConTy+ UnliftedRep -> unliftedRepDataConTy+ IntRep -> intRepDataConTy+ WordRep -> wordRepDataConTy+ Int64Rep -> int64RepDataConTy+ Word64Rep -> word64RepDataConTy+ AddrRep -> addrRepDataConTy+ FloatRep -> floatRepDataConTy+ DoubleRep -> doubleRepDataConTy+ VecRep n elem -> TyConApp vecRepDataConTyCon [n', elem']+ where+ n' = case n of+ 2 -> vec2DataConTy+ 4 -> vec4DataConTy+ 8 -> vec8DataConTy+ 16 -> vec16DataConTy+ 32 -> vec32DataConTy+ 64 -> vec64DataConTy+ _ -> pprPanic "Disallowed VecCount" (ppr n)++ elem' = case elem of+ Int8ElemRep -> int8ElemRepDataConTy+ Int16ElemRep -> int16ElemRepDataConTy+ Int32ElemRep -> int32ElemRepDataConTy+ Int64ElemRep -> int64ElemRepDataConTy+ Word8ElemRep -> word8ElemRepDataConTy+ Word16ElemRep -> word16ElemRepDataConTy+ Word32ElemRep -> word32ElemRepDataConTy+ Word64ElemRep -> word64ElemRepDataConTy+ FloatElemRep -> floatElemRepDataConTy+ DoubleElemRep -> doubleElemRepDataConTy++pcPrimTyCon0 :: Name -> PrimRep -> TyCon+pcPrimTyCon0 name rep+ = pcPrimTyCon name [] rep++charPrimTy :: Type+charPrimTy = mkTyConTy charPrimTyCon+charPrimTyCon :: TyCon+charPrimTyCon = pcPrimTyCon0 charPrimTyConName WordRep++intPrimTy :: Type+intPrimTy = mkTyConTy intPrimTyCon+intPrimTyCon :: TyCon+intPrimTyCon = pcPrimTyCon0 intPrimTyConName IntRep++int32PrimTy :: Type+int32PrimTy = mkTyConTy int32PrimTyCon+int32PrimTyCon :: TyCon+int32PrimTyCon = pcPrimTyCon0 int32PrimTyConName IntRep++int64PrimTy :: Type+int64PrimTy = mkTyConTy int64PrimTyCon+int64PrimTyCon :: TyCon+int64PrimTyCon = pcPrimTyCon0 int64PrimTyConName Int64Rep++wordPrimTy :: Type+wordPrimTy = mkTyConTy wordPrimTyCon+wordPrimTyCon :: TyCon+wordPrimTyCon = pcPrimTyCon0 wordPrimTyConName WordRep++word32PrimTy :: Type+word32PrimTy = mkTyConTy word32PrimTyCon+word32PrimTyCon :: TyCon+word32PrimTyCon = pcPrimTyCon0 word32PrimTyConName WordRep++word64PrimTy :: Type+word64PrimTy = mkTyConTy word64PrimTyCon+word64PrimTyCon :: TyCon+word64PrimTyCon = pcPrimTyCon0 word64PrimTyConName Word64Rep++addrPrimTy :: Type+addrPrimTy = mkTyConTy addrPrimTyCon+addrPrimTyCon :: TyCon+addrPrimTyCon = pcPrimTyCon0 addrPrimTyConName AddrRep++floatPrimTy :: Type+floatPrimTy = mkTyConTy floatPrimTyCon+floatPrimTyCon :: TyCon+floatPrimTyCon = pcPrimTyCon0 floatPrimTyConName FloatRep++doublePrimTy :: Type+doublePrimTy = mkTyConTy doublePrimTyCon+doublePrimTyCon :: TyCon+doublePrimTyCon = pcPrimTyCon0 doublePrimTyConName DoubleRep++{-+************************************************************************+* *+\subsection[TysPrim-state]{The @State#@ type (and @_RealWorld@ types)}+* *+************************************************************************++Note [The equality types story]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC sports a veritable menagerie of equality types:++ Hetero? Levity Result Role Defining module+ ------------------------------------------------------------+ ~# hetero unlifted # nominal GHC.Prim+ ~~ hetero lifted Constraint nominal GHC.Types+ ~ homo lifted Constraint nominal Data.Type.Equality+ :~: homo lifted * nominal Data.Type.Equality++ ~R# hetero unlifted # repr GHC.Prim+ Coercible homo lifted Constraint repr GHC.Types+ Coercion homo lifted * repr Data.Type.Coercion++ ~P# hetero unlifted phantom GHC.Prim++Recall that "hetero" means the equality can related types of different+kinds. Knowing that (t1 ~# t2) or (t1 ~R# t2) or even that (t1 ~P# t2)+also means that (k1 ~# k2), where (t1 :: k1) and (t2 :: k2).++To produce less confusion for end users, when not dumping and without+-fprint-equality-relations, each of these groups is printed as the bottommost+listed equality. That is, (~#) and (~~) are both rendered as (~) in+error messages, and (~R#) is rendered as Coercible.++Let's take these one at a time:++ --------------------------+ (~#) :: forall k1 k2. k1 -> k2 -> #+ --------------------------+This is The Type Of Equality in GHC. It classifies nominal coercions.+This type is used in the solver for recording equality constraints.+It responds "yes" to Type.isEqPred and classifies as an EqPred in+Type.classifyPredType.++All wanted constraints of this type are built with coercion holes.+(See Note [Coercion holes] in TyCoRep.) But see also+Note [Deferred errors for coercion holes] in TcErrors to see how+equality constraints are deferred.++Within GHC, ~# is called eqPrimTyCon, and it is defined in TysPrim.+++ --------------------------+ (~~) :: forall k1 k2. k1 -> k2 -> Constraint+ --------------------------+This is (almost) an ordinary class, defined as if by+ class a ~# b => a ~~ b+ instance a ~# b => a ~~ b+Here's what's unusual about it:+ * We can't actually declare it that way because we don't have syntax for ~#.+ And ~# isn't a constraint, so even if we could write it, it wouldn't kind+ check.++ * Users cannot write instances of it.++ * It is "naturally coherent". This means that the solver won't hesitate to+ solve a goal of type (a ~~ b) even if there is, say (Int ~~ c) in the+ context. (Normally, it waits to learn more, just in case the given+ influences what happens next.) This is quite like having+ IncoherentInstances enabled.++ * It always terminates. That is, in the UndecidableInstances checks, we+ don't worry if a (~~) constraint is too big, as we know that solving+ equality terminates.++On the other hand, this behaves just like any class w.r.t. eager superclass+unpacking in the solver. So a lifted equality given quickly becomes an unlifted+equality given. This is good, because the solver knows all about unlifted+equalities. There is some special-casing in TcInteract.matchClassInst to+pretend that there is an instance of this class, as we can't write the instance+in Haskell.++Within GHC, ~~ is called heqTyCon, and it is defined in TysWiredIn.+++ --------------------------+ (~) :: forall k. k -> k -> Constraint+ --------------------------+This is defined in Data.Type.Equality:+ class a ~~ b => (a :: k) ~ (b :: k)+ instance a ~~ b => a ~ b+This is even more so an ordinary class than (~~), with the following exceptions:+ * Users cannot write instances of it.++ * It is "naturally coherent". (See (~~).)++ * (~) is magical syntax, as ~ is a reserved symbol. It cannot be exported+ or imported.++ * It always terminates.++Within GHC, ~ is called eqTyCon, and it is defined in PrelNames. Note that+it is *not* wired in.+++ --------------------------+ (:~:) :: forall k. k -> k -> *+ --------------------------+This is a perfectly ordinary GADT, wrapping (~). It is not defined within+GHC at all.+++ --------------------------+ (~R#) :: forall k1 k2. k1 -> k2 -> #+ --------------------------+The is the representational analogue of ~#. This is the type of representational+equalities that the solver works on. All wanted constraints of this type are+built with coercion holes.++Within GHC, ~R# is called eqReprPrimTyCon, and it is defined in TysPrim.+++ --------------------------+ Coercible :: forall k. k -> k -> Constraint+ --------------------------+This is quite like (~~) in the way it's defined and treated within GHC, but+it's homogeneous. Homogeneity helps with type inference (as GHC can solve one+kind from the other) and, in my (Richard's) estimation, will be more intuitive+for users.++An alternative design included HCoercible (like (~~)) and Coercible (like (~)).+One annoyance was that we want `coerce :: Coercible a b => a -> b`, and+we need the type of coerce to be fully wired-in. So the HCoercible/Coercible+split required that both types be fully wired-in. Instead of doing this,+I just got rid of HCoercible, as I'm not sure who would use it, anyway.++Within GHC, Coercible is called coercibleTyCon, and it is defined in+TysWiredIn.+++ --------------------------+ Coercion :: forall k. k -> k -> *+ --------------------------+This is a perfectly ordinary GADT, wrapping Coercible. It is not defined+within GHC at all.+++ --------------------------+ (~P#) :: forall k1 k2. k1 -> k2 -> #+ --------------------------+This is the phantom analogue of ~# and it is barely used at all.+(The solver has no idea about this one.) Here is the motivation:++ data Phant a = MkPhant+ type role Phant phantom++ Phant <Int, Bool>_P :: Phant Int ~P# Phant Bool++We just need to have something to put on that last line. You probably+don't need to worry about it.++++Note [The State# TyCon]+~~~~~~~~~~~~~~~~~~~~~~~+State# is the primitive, unlifted type of states. It has one type parameter,+thus+ State# RealWorld+or+ State# s++where s is a type variable. The only purpose of the type parameter is to+keep different state threads separate. It is represented by nothing at all.++The type parameter to State# is intended to keep separate threads separate.+Even though this parameter is not used in the definition of State#, it is+given role Nominal to enforce its intended use.+-}++mkStatePrimTy :: Type -> Type+mkStatePrimTy ty = TyConApp statePrimTyCon [ty]++statePrimTyCon :: TyCon -- See Note [The State# TyCon]+statePrimTyCon = pcPrimTyCon statePrimTyConName [Nominal] VoidRep++{-+RealWorld is deeply magical. It is *primitive*, but it is not+*unlifted* (hence ptrArg). We never manipulate values of type+RealWorld; it's only used in the type system, to parameterise State#.+-}++realWorldTyCon :: TyCon+realWorldTyCon = mkLiftedPrimTyCon realWorldTyConName [] liftedTypeKind []+realWorldTy :: Type+realWorldTy = mkTyConTy realWorldTyCon+realWorldStatePrimTy :: Type+realWorldStatePrimTy = mkStatePrimTy realWorldTy -- State# RealWorld++-- Note: the ``state-pairing'' types are not truly primitive,+-- so they are defined in \tr{TysWiredIn.hs}, not here.+++voidPrimTy :: Type+voidPrimTy = TyConApp voidPrimTyCon []++voidPrimTyCon :: TyCon+voidPrimTyCon = pcPrimTyCon voidPrimTyConName [] VoidRep++mkProxyPrimTy :: Type -> Type -> Type+mkProxyPrimTy k ty = TyConApp proxyPrimTyCon [k, ty]++proxyPrimTyCon :: TyCon+proxyPrimTyCon = mkPrimTyCon proxyPrimTyConName binders res_kind [Nominal,Nominal]+ where+ -- Kind: forall k. k -> Void#+ binders = mkTemplateTyConBinders [liftedTypeKind] (\ks-> ks)+ res_kind = unboxedTupleKind []+++{- *********************************************************************+* *+ Primitive equality constraints+ See Note [The equality types story]+* *+********************************************************************* -}++eqPrimTyCon :: TyCon -- The representation type for equality predicates+ -- See Note [The equality types story]+eqPrimTyCon = mkPrimTyCon eqPrimTyConName binders res_kind roles+ where+ -- Kind :: forall k1 k2. k1 -> k2 -> Void#+ binders = mkTemplateTyConBinders [liftedTypeKind, liftedTypeKind] (\ks -> ks)+ res_kind = unboxedTupleKind []+ roles = [Nominal, Nominal, Nominal, Nominal]++-- like eqPrimTyCon, but the type for *Representational* coercions+-- this should only ever appear as the type of a covar. Its role is+-- interpreted in coercionRole+eqReprPrimTyCon :: TyCon -- See Note [The equality types story]+eqReprPrimTyCon = mkPrimTyCon eqReprPrimTyConName binders res_kind roles+ where+ -- Kind :: forall k1 k2. k1 -> k2 -> Void#+ binders = mkTemplateTyConBinders [liftedTypeKind, liftedTypeKind] (\ks -> ks)+ res_kind = unboxedTupleKind []+ roles = [Nominal, Nominal, Representational, Representational]++-- like eqPrimTyCon, but the type for *Phantom* coercions.+-- This is only used to make higher-order equalities. Nothing+-- should ever actually have this type!+eqPhantPrimTyCon :: TyCon+eqPhantPrimTyCon = mkPrimTyCon eqPhantPrimTyConName binders res_kind roles+ where+ -- Kind :: forall k1 k2. k1 -> k2 -> Void#+ binders = mkTemplateTyConBinders [liftedTypeKind, liftedTypeKind] (\ks -> ks)+ res_kind = unboxedTupleKind []+ roles = [Nominal, Nominal, Phantom, Phantom]++{- *********************************************************************+* *+ The primitive array types+* *+********************************************************************* -}++arrayPrimTyCon, mutableArrayPrimTyCon, mutableByteArrayPrimTyCon,+ byteArrayPrimTyCon, arrayArrayPrimTyCon, mutableArrayArrayPrimTyCon,+ smallArrayPrimTyCon, smallMutableArrayPrimTyCon :: TyCon+arrayPrimTyCon = pcPrimTyCon arrayPrimTyConName [Representational] UnliftedRep+mutableArrayPrimTyCon = pcPrimTyCon mutableArrayPrimTyConName [Nominal, Representational] UnliftedRep+mutableByteArrayPrimTyCon = pcPrimTyCon mutableByteArrayPrimTyConName [Nominal] UnliftedRep+byteArrayPrimTyCon = pcPrimTyCon0 byteArrayPrimTyConName UnliftedRep+arrayArrayPrimTyCon = pcPrimTyCon0 arrayArrayPrimTyConName UnliftedRep+mutableArrayArrayPrimTyCon = pcPrimTyCon mutableArrayArrayPrimTyConName [Nominal] UnliftedRep+smallArrayPrimTyCon = pcPrimTyCon smallArrayPrimTyConName [Representational] UnliftedRep+smallMutableArrayPrimTyCon = pcPrimTyCon smallMutableArrayPrimTyConName [Nominal, Representational] UnliftedRep++mkArrayPrimTy :: Type -> Type+mkArrayPrimTy elt = TyConApp arrayPrimTyCon [elt]+byteArrayPrimTy :: Type+byteArrayPrimTy = mkTyConTy byteArrayPrimTyCon+mkArrayArrayPrimTy :: Type+mkArrayArrayPrimTy = mkTyConTy arrayArrayPrimTyCon+mkSmallArrayPrimTy :: Type -> Type+mkSmallArrayPrimTy elt = TyConApp smallArrayPrimTyCon [elt]+mkMutableArrayPrimTy :: Type -> Type -> Type+mkMutableArrayPrimTy s elt = TyConApp mutableArrayPrimTyCon [s, elt]+mkMutableByteArrayPrimTy :: Type -> Type+mkMutableByteArrayPrimTy s = TyConApp mutableByteArrayPrimTyCon [s]+mkMutableArrayArrayPrimTy :: Type -> Type+mkMutableArrayArrayPrimTy s = TyConApp mutableArrayArrayPrimTyCon [s]+mkSmallMutableArrayPrimTy :: Type -> Type -> Type+mkSmallMutableArrayPrimTy s elt = TyConApp smallMutableArrayPrimTyCon [s, elt]+++{- *********************************************************************+* *+ The mutable variable type+* *+********************************************************************* -}++mutVarPrimTyCon :: TyCon+mutVarPrimTyCon = pcPrimTyCon mutVarPrimTyConName [Nominal, Representational] UnliftedRep++mkMutVarPrimTy :: Type -> Type -> Type+mkMutVarPrimTy s elt = TyConApp mutVarPrimTyCon [s, elt]++{-+************************************************************************+* *+\subsection[TysPrim-synch-var]{The synchronizing variable type}+* *+************************************************************************+-}++mVarPrimTyCon :: TyCon+mVarPrimTyCon = pcPrimTyCon mVarPrimTyConName [Nominal, Representational] UnliftedRep++mkMVarPrimTy :: Type -> Type -> Type+mkMVarPrimTy s elt = TyConApp mVarPrimTyCon [s, elt]++{-+************************************************************************+* *+\subsection[TysPrim-stm-var]{The transactional variable type}+* *+************************************************************************+-}++tVarPrimTyCon :: TyCon+tVarPrimTyCon = pcPrimTyCon tVarPrimTyConName [Nominal, Representational] UnliftedRep++mkTVarPrimTy :: Type -> Type -> Type+mkTVarPrimTy s elt = TyConApp tVarPrimTyCon [s, elt]++{-+************************************************************************+* *+\subsection[TysPrim-stable-ptrs]{The stable-pointer type}+* *+************************************************************************+-}++stablePtrPrimTyCon :: TyCon+stablePtrPrimTyCon = pcPrimTyCon stablePtrPrimTyConName [Representational] AddrRep++mkStablePtrPrimTy :: Type -> Type+mkStablePtrPrimTy ty = TyConApp stablePtrPrimTyCon [ty]++{-+************************************************************************+* *+\subsection[TysPrim-stable-names]{The stable-name type}+* *+************************************************************************+-}++stableNamePrimTyCon :: TyCon+stableNamePrimTyCon = pcPrimTyCon stableNamePrimTyConName [Representational] UnliftedRep++mkStableNamePrimTy :: Type -> Type+mkStableNamePrimTy ty = TyConApp stableNamePrimTyCon [ty]++{-+************************************************************************+* *+\subsection[TysPrim-compact-nfdata]{The Compact NFData (CNF) type}+* *+************************************************************************+-}++compactPrimTyCon :: TyCon+compactPrimTyCon = pcPrimTyCon0 compactPrimTyConName UnliftedRep++compactPrimTy :: Type+compactPrimTy = mkTyConTy compactPrimTyCon++{-+************************************************************************+* *+\subsection[TysPrim-BCOs]{The ``bytecode object'' type}+* *+************************************************************************+-}++bcoPrimTy :: Type+bcoPrimTy = mkTyConTy bcoPrimTyCon+bcoPrimTyCon :: TyCon+bcoPrimTyCon = pcPrimTyCon0 bcoPrimTyConName UnliftedRep++{-+************************************************************************+* *+\subsection[TysPrim-Weak]{The ``weak pointer'' type}+* *+************************************************************************+-}++weakPrimTyCon :: TyCon+weakPrimTyCon = pcPrimTyCon weakPrimTyConName [Representational] UnliftedRep++mkWeakPrimTy :: Type -> Type+mkWeakPrimTy v = TyConApp weakPrimTyCon [v]++{-+************************************************************************+* *+\subsection[TysPrim-thread-ids]{The ``thread id'' type}+* *+************************************************************************++A thread id is represented by a pointer to the TSO itself, to ensure+that they are always unique and we can always find the TSO for a given+thread id. However, this has the unfortunate consequence that a+ThreadId# for a given thread is treated as a root by the garbage+collector and can keep TSOs around for too long.++Hence the programmer API for thread manipulation uses a weak pointer+to the thread id internally.+-}++threadIdPrimTy :: Type+threadIdPrimTy = mkTyConTy threadIdPrimTyCon+threadIdPrimTyCon :: TyCon+threadIdPrimTyCon = pcPrimTyCon0 threadIdPrimTyConName UnliftedRep++{-+************************************************************************+* *+\subsection{SIMD vector types}+* *+************************************************************************+-}++#include "primop-vector-tys.hs-incl"
+ prelude/TysWiredIn.hs view
@@ -0,0 +1,1652 @@+{-+(c) The GRASP Project, Glasgow University, 1994-1998++\section[TysWiredIn]{Wired-in knowledge about {\em non-primitive} types}+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}++-- | This module is about types that can be defined in Haskell, but which+-- must be wired into the compiler nonetheless. C.f module TysPrim+module TysWiredIn (+ -- * Helper functions defined here+ mkWiredInTyConName, -- This is used in TcTypeNats to define the+ -- built-in functions for evaluation.++ mkWiredInIdName, -- used in MkId++ mkFunKind, mkForAllKind,++ -- * All wired in things+ wiredInTyCons, isBuiltInOcc_maybe,++ -- * Bool+ boolTy, boolTyCon, boolTyCon_RDR, boolTyConName,+ trueDataCon, trueDataConId, true_RDR,+ falseDataCon, falseDataConId, false_RDR,+ promotedFalseDataCon, promotedTrueDataCon,++ -- * Ordering+ orderingTyCon,+ ltDataCon, ltDataConId,+ eqDataCon, eqDataConId,+ gtDataCon, gtDataConId,+ promotedLTDataCon, promotedEQDataCon, promotedGTDataCon,++ -- * Boxing primitive types+ boxingDataCon_maybe,++ -- * Char+ charTyCon, charDataCon, charTyCon_RDR,+ charTy, stringTy, charTyConName,++ -- * Double+ doubleTyCon, doubleDataCon, doubleTy, doubleTyConName,++ -- * Float+ floatTyCon, floatDataCon, floatTy, floatTyConName,++ -- * Int+ intTyCon, intDataCon, intTyCon_RDR, intDataCon_RDR, intTyConName,+ intTy,++ -- * Word+ wordTyCon, wordDataCon, wordTyConName, wordTy,++ -- * Word8+ word8TyCon, word8DataCon, word8TyConName, word8Ty,++ -- * List+ listTyCon, listTyCon_RDR, listTyConName, listTyConKey,+ nilDataCon, nilDataConName, nilDataConKey,+ consDataCon_RDR, consDataCon, consDataConName,+ promotedNilDataCon, promotedConsDataCon,+ mkListTy, mkPromotedListTy,++ -- * Maybe+ maybeTyCon, maybeTyConName,+ nothingDataCon, nothingDataConName, promotedNothingDataCon,+ justDataCon, justDataConName, promotedJustDataCon,++ -- * Tuples+ mkTupleTy, mkBoxedTupleTy,+ tupleTyCon, tupleDataCon, tupleTyConName,+ promotedTupleDataCon,+ unitTyCon, unitDataCon, unitDataConId, unitTy, unitTyConKey,+ pairTyCon,+ unboxedUnitTyCon, unboxedUnitDataCon,+ unboxedTupleKind, unboxedSumKind,++ -- ** Constraint tuples+ cTupleTyConName, cTupleTyConNames, isCTupleTyConName,+ cTupleDataConName, cTupleDataConNames,++ -- * Any+ anyTyCon, anyTy, anyTypeOfKind,++ -- * Sums+ mkSumTy, sumTyCon, sumDataCon,++ -- * Kinds+ typeNatKindCon, typeNatKind, typeSymbolKindCon, typeSymbolKind,+ isLiftedTypeKindTyConName, liftedTypeKind, constraintKind,+ starKindTyCon, starKindTyConName,+ unicodeStarKindTyCon, unicodeStarKindTyConName,+ liftedTypeKindTyCon, constraintKindTyCon,++ -- * Parallel arrays+ mkPArrTy,+ parrTyCon, parrFakeCon, isPArrTyCon, isPArrFakeCon,+ parrTyCon_RDR, parrTyConName,++ -- * Equality predicates+ heqTyCon, heqClass, heqDataCon,+ coercibleTyCon, coercibleDataCon, coercibleClass,++ -- * RuntimeRep and friends+ runtimeRepTyCon, vecCountTyCon, vecElemTyCon,++ runtimeRepTy, liftedRepTy, liftedRepDataCon, liftedRepDataConTyCon,++ vecRepDataConTyCon, tupleRepDataConTyCon, sumRepDataConTyCon,++ liftedRepDataConTy, unliftedRepDataConTy, intRepDataConTy,+ wordRepDataConTy, int64RepDataConTy, word64RepDataConTy, addrRepDataConTy,+ floatRepDataConTy, doubleRepDataConTy,++ vec2DataConTy, vec4DataConTy, vec8DataConTy, vec16DataConTy, vec32DataConTy,+ vec64DataConTy,++ int8ElemRepDataConTy, int16ElemRepDataConTy, int32ElemRepDataConTy,+ int64ElemRepDataConTy, word8ElemRepDataConTy, word16ElemRepDataConTy,+ word32ElemRepDataConTy, word64ElemRepDataConTy, floatElemRepDataConTy,+ doubleElemRepDataConTy++ ) where++#include "HsVersions.h"+#include "MachDeps.h"++import {-# SOURCE #-} MkId( mkDataConWorkId, mkDictSelId )++-- friends:+import PrelNames+import TysPrim+import {-# SOURCE #-} KnownUniques++-- others:+import CoAxiom+import Id+import Constants ( mAX_TUPLE_SIZE, mAX_CTUPLE_SIZE, mAX_SUM_SIZE )+import Module ( Module )+import Type+import RepType+import DataCon+import {-# SOURCE #-} ConLike+import TyCon+import Class ( Class, mkClass )+import RdrName+import Name+import NameEnv ( NameEnv, mkNameEnv, lookupNameEnv )+import NameSet ( NameSet, mkNameSet, elemNameSet )+import BasicTypes ( Arity, Boxity(..), TupleSort(..), ConTagZ,+ SourceText(..) )+import ForeignCall+import SrcLoc ( noSrcSpan )+import Unique+import Data.Array+import FastString+import Outputable+import Util+import BooleanFormula ( mkAnd )++import qualified Data.ByteString.Char8 as BS+#if !MIN_VERSION_bytestring(0,10,8)+import qualified Data.ByteString.Internal as BSI+import qualified Data.ByteString.Unsafe as BSU+#endif++alpha_tyvar :: [TyVar]+alpha_tyvar = [alphaTyVar]++alpha_ty :: [Type]+alpha_ty = [alphaTy]++{-+Note [Wiring in RuntimeRep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+The RuntimeRep type (and friends) in GHC.Types has a bunch of constructors,+making it a pain to wire in. To ease the pain somewhat, we use lists of+the different bits, like Uniques, Names, DataCons. These lists must be+kept in sync with each other. The rule is this: use the order as declared+in GHC.Types. All places where such lists exist should contain a reference+to this Note, so a search for this Note's name should find all the lists.++************************************************************************+* *+\subsection{Wired in type constructors}+* *+************************************************************************++If you change which things are wired in, make sure you change their+names in PrelNames, so they use wTcQual, wDataQual, etc+-}++-- This list is used only to define PrelInfo.wiredInThings. That in turn+-- is used to initialise the name environment carried around by the renamer.+-- This means that if we look up the name of a TyCon (or its implicit binders)+-- that occurs in this list that name will be assigned the wired-in key we+-- define here.+--+-- Because of their infinite nature, this list excludes tuples, Any and implicit+-- parameter TyCons (see Note [Built-in syntax and the OrigNameCache]).+--+-- See also Note [Known-key names]+wiredInTyCons :: [TyCon]++wiredInTyCons = [ -- Units are not treated like other tuples, because then+ -- are defined in GHC.Base, and there's only a few of them. We+ -- put them in wiredInTyCons so that they will pre-populate+ -- the name cache, so the parser in isBuiltInOcc_maybe doesn't+ -- need to look out for them.+ unitTyCon+ , unboxedUnitTyCon+ , anyTyCon+ , boolTyCon+ , charTyCon+ , doubleTyCon+ , floatTyCon+ , intTyCon+ , wordTyCon+ , word8TyCon+ , listTyCon+ , maybeTyCon+ , parrTyCon+ , heqTyCon+ , coercibleTyCon+ , typeNatKindCon+ , typeSymbolKindCon+ , runtimeRepTyCon+ , vecCountTyCon+ , vecElemTyCon+ , constraintKindTyCon+ , liftedTypeKindTyCon+ , starKindTyCon+ , unicodeStarKindTyCon+ ]++mkWiredInTyConName :: BuiltInSyntax -> Module -> FastString -> Unique -> TyCon -> Name+mkWiredInTyConName built_in modu fs unique tycon+ = mkWiredInName modu (mkTcOccFS fs) unique+ (ATyCon tycon) -- Relevant TyCon+ built_in++mkWiredInDataConName :: BuiltInSyntax -> Module -> FastString -> Unique -> DataCon -> Name+mkWiredInDataConName built_in modu fs unique datacon+ = mkWiredInName modu (mkDataOccFS fs) unique+ (AConLike (RealDataCon datacon)) -- Relevant DataCon+ built_in++mkWiredInIdName :: Module -> FastString -> Unique -> Id -> Name+mkWiredInIdName mod fs uniq id+ = mkWiredInName mod (mkOccNameFS Name.varName fs) uniq (AnId id) UserSyntax++-- See Note [Kind-changing of (~) and Coercible]+-- in libraries/ghc-prim/GHC/Types.hs+heqTyConName, heqDataConName, heqSCSelIdName :: Name+heqTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "~~") heqTyConKey heqTyCon+heqDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "Eq#") heqDataConKey heqDataCon+heqSCSelIdName = mkWiredInIdName gHC_TYPES (fsLit "HEq_sc") heqSCSelIdKey heqSCSelId++-- See Note [Kind-changing of (~) and Coercible] in libraries/ghc-prim/GHC/Types.hs+coercibleTyConName, coercibleDataConName, coercibleSCSelIdName :: Name+coercibleTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Coercible") coercibleTyConKey coercibleTyCon+coercibleDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "MkCoercible") coercibleDataConKey coercibleDataCon+coercibleSCSelIdName = mkWiredInIdName gHC_TYPES (fsLit "Coercible_sc") coercibleSCSelIdKey coercibleSCSelId++charTyConName, charDataConName, intTyConName, intDataConName :: Name+charTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Char") charTyConKey charTyCon+charDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "C#") charDataConKey charDataCon+intTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Int") intTyConKey intTyCon+intDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "I#") intDataConKey intDataCon++boolTyConName, falseDataConName, trueDataConName :: Name+boolTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Bool") boolTyConKey boolTyCon+falseDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "False") falseDataConKey falseDataCon+trueDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "True") trueDataConKey trueDataCon++listTyConName, nilDataConName, consDataConName :: Name+listTyConName = mkWiredInTyConName BuiltInSyntax gHC_TYPES (fsLit "[]") listTyConKey listTyCon+nilDataConName = mkWiredInDataConName BuiltInSyntax gHC_TYPES (fsLit "[]") nilDataConKey nilDataCon+consDataConName = mkWiredInDataConName BuiltInSyntax gHC_TYPES (fsLit ":") consDataConKey consDataCon++maybeTyConName, nothingDataConName, justDataConName :: Name+maybeTyConName = mkWiredInTyConName UserSyntax gHC_BASE (fsLit "Maybe")+ maybeTyConKey maybeTyCon+nothingDataConName = mkWiredInDataConName UserSyntax gHC_BASE (fsLit "Nothing")+ nothingDataConKey nothingDataCon+justDataConName = mkWiredInDataConName UserSyntax gHC_BASE (fsLit "Just")+ justDataConKey justDataCon++wordTyConName, wordDataConName, word8TyConName, word8DataConName :: Name+wordTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Word") wordTyConKey wordTyCon+wordDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "W#") wordDataConKey wordDataCon+word8TyConName = mkWiredInTyConName UserSyntax gHC_WORD (fsLit "Word8") word8TyConKey word8TyCon+word8DataConName = mkWiredInDataConName UserSyntax gHC_WORD (fsLit "W8#") word8DataConKey word8DataCon++floatTyConName, floatDataConName, doubleTyConName, doubleDataConName :: Name+floatTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Float") floatTyConKey floatTyCon+floatDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "F#") floatDataConKey floatDataCon+doubleTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Double") doubleTyConKey doubleTyCon+doubleDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "D#") doubleDataConKey doubleDataCon++-- Any++{-+Note [Any types]+~~~~~~~~~~~~~~~~+The type constructor Any,++ type family Any :: k where { }++It has these properties:++ * Note that 'Any' is kind polymorphic since in some program we may+ need to use Any to fill in a type variable of some kind other than *+ (see #959 for examples). Its kind is thus `forall k. k``.++ * It is defined in module GHC.Types, and exported so that it is+ available to users. For this reason it's treated like any other+ wired-in type:+ - has a fixed unique, anyTyConKey,+ - lives in the global name cache++ * It is a *closed* type family, with no instances. This means that+ if ty :: '(k1, k2) we add a given coercion+ g :: ty ~ (Fst ty, Snd ty)+ If Any was a *data* type, then we'd get inconsistency because 'ty'+ could be (Any '(k1,k2)) and then we'd have an equality with Any on+ one side and '(,) on the other. See also #9097 and #9636.++ * When instantiated at a lifted type it is inhabited by at least one value,+ namely bottom++ * You can safely coerce any /lifted/ type to Any, and back with unsafeCoerce.++ * It does not claim to be a *data* type, and that's important for+ the code generator, because the code gen may *enter* a data value+ but never enters a function value.++ * It is wired-in so we can easily refer to it where we don't have a name+ environment (e.g. see Rules.matchRule for one example)++ * If (Any k) is the type of a value, it must be a /lifted/ value. So+ if we have (Any @(TYPE rr)) then rr must be 'LiftedRep. See+ Note [TYPE and RuntimeRep] in TysPrim. This is a convenient+ invariant, and makes isUnliftedTyCon well-defined; otherwise what+ would (isUnliftedTyCon Any) be?++It's used to instantiate un-constrained type variables after type checking. For+example, 'length' has type++ length :: forall a. [a] -> Int++and the list datacon for the empty list has type++ [] :: forall a. [a]++In order to compose these two terms as @length []@ a type+application is required, but there is no constraint on the+choice. In this situation GHC uses 'Any',++> length (Any *) ([] (Any *))++Above, we print kinds explicitly, as if with --fprint-explicit-kinds.++The Any tycon used to be quite magic, but we have since been able to+implement it merely with an empty kind polymorphic type family. See #10886 for a+bit of history.+-}+++anyTyConName :: Name+anyTyConName =+ mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Any") anyTyConKey anyTyCon++anyTyCon :: TyCon+anyTyCon = mkFamilyTyCon anyTyConName binders res_kind Nothing+ (ClosedSynFamilyTyCon Nothing)+ Nothing+ NotInjective+ where+ binders@[kv] = mkTemplateKindTyConBinders [liftedTypeKind]+ res_kind = mkTyVarTy (binderVar kv)++anyTy :: Type+anyTy = mkTyConTy anyTyCon++anyTypeOfKind :: Kind -> Type+anyTypeOfKind kind = mkTyConApp anyTyCon [kind]++-- Kinds+typeNatKindConName, typeSymbolKindConName :: Name+typeNatKindConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Nat") typeNatKindConNameKey typeNatKindCon+typeSymbolKindConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Symbol") typeSymbolKindConNameKey typeSymbolKindCon++constraintKindTyConName :: Name+constraintKindTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Constraint") constraintKindTyConKey constraintKindTyCon++liftedTypeKindTyConName, starKindTyConName, unicodeStarKindTyConName+ :: Name+liftedTypeKindTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "Type") liftedTypeKindTyConKey liftedTypeKindTyCon+starKindTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "*") starKindTyConKey starKindTyCon+unicodeStarKindTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "★") unicodeStarKindTyConKey unicodeStarKindTyCon++runtimeRepTyConName, vecRepDataConName, tupleRepDataConName, sumRepDataConName :: Name+runtimeRepTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "RuntimeRep") runtimeRepTyConKey runtimeRepTyCon+vecRepDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "VecRep") vecRepDataConKey vecRepDataCon+tupleRepDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "TupleRep") tupleRepDataConKey tupleRepDataCon+sumRepDataConName = mkWiredInDataConName UserSyntax gHC_TYPES (fsLit "SumRep") sumRepDataConKey sumRepDataCon++-- See Note [Wiring in RuntimeRep]+runtimeRepSimpleDataConNames :: [Name]+runtimeRepSimpleDataConNames+ = zipWith3Lazy mk_special_dc_name+ [ fsLit "LiftedRep", fsLit "UnliftedRep"+ , fsLit "IntRep"+ , fsLit "WordRep", fsLit "Int64Rep", fsLit "Word64Rep"+ , fsLit "AddrRep", fsLit "FloatRep", fsLit "DoubleRep" ]+ runtimeRepSimpleDataConKeys+ runtimeRepSimpleDataCons++vecCountTyConName :: Name+vecCountTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "VecCount") vecCountTyConKey vecCountTyCon++-- See Note [Wiring in RuntimeRep]+vecCountDataConNames :: [Name]+vecCountDataConNames = zipWith3Lazy mk_special_dc_name+ [ fsLit "Vec2", fsLit "Vec4", fsLit "Vec8"+ , fsLit "Vec16", fsLit "Vec32", fsLit "Vec64" ]+ vecCountDataConKeys+ vecCountDataCons++vecElemTyConName :: Name+vecElemTyConName = mkWiredInTyConName UserSyntax gHC_TYPES (fsLit "VecElem") vecElemTyConKey vecElemTyCon++-- See Note [Wiring in RuntimeRep]+vecElemDataConNames :: [Name]+vecElemDataConNames = zipWith3Lazy mk_special_dc_name+ [ fsLit "Int8ElemRep", fsLit "Int16ElemRep", fsLit "Int32ElemRep"+ , fsLit "Int64ElemRep", fsLit "Word8ElemRep", fsLit "Word16ElemRep"+ , fsLit "Word32ElemRep", fsLit "Word64ElemRep"+ , fsLit "FloatElemRep", fsLit "DoubleElemRep" ]+ vecElemDataConKeys+ vecElemDataCons++mk_special_dc_name :: FastString -> Unique -> DataCon -> Name+mk_special_dc_name fs u dc = mkWiredInDataConName UserSyntax gHC_TYPES fs u dc++parrTyConName, parrDataConName :: Name+parrTyConName = mkWiredInTyConName BuiltInSyntax+ gHC_PARR' (fsLit "[::]") parrTyConKey parrTyCon+parrDataConName = mkWiredInDataConName UserSyntax+ gHC_PARR' (fsLit "PArr") parrDataConKey parrDataCon++boolTyCon_RDR, false_RDR, true_RDR, intTyCon_RDR, charTyCon_RDR,+ intDataCon_RDR, listTyCon_RDR, consDataCon_RDR, parrTyCon_RDR :: RdrName+boolTyCon_RDR = nameRdrName boolTyConName+false_RDR = nameRdrName falseDataConName+true_RDR = nameRdrName trueDataConName+intTyCon_RDR = nameRdrName intTyConName+charTyCon_RDR = nameRdrName charTyConName+intDataCon_RDR = nameRdrName intDataConName+listTyCon_RDR = nameRdrName listTyConName+consDataCon_RDR = nameRdrName consDataConName+parrTyCon_RDR = nameRdrName parrTyConName++{-+************************************************************************+* *+\subsection{mkWiredInTyCon}+* *+************************************************************************+-}++pcNonEnumTyCon :: Name -> Maybe CType -> [TyVar] -> [DataCon] -> TyCon+-- Not an enumeration+pcNonEnumTyCon = pcTyCon False++-- This function assumes that the types it creates have all parameters at+-- Representational role, and that there is no kind polymorphism.+pcTyCon :: Bool -> Name -> Maybe CType -> [TyVar] -> [DataCon] -> TyCon+pcTyCon is_enum name cType tyvars cons+ = mkAlgTyCon name+ (mkAnonTyConBinders tyvars)+ liftedTypeKind+ (map (const Representational) tyvars)+ cType+ [] -- No stupid theta+ (DataTyCon cons is_enum)+ (VanillaAlgTyCon (mkPrelTyConRepName name))+ False -- Not in GADT syntax++pcDataCon :: Name -> [TyVar] -> [Type] -> TyCon -> DataCon+pcDataCon n univs = pcDataConWithFixity False n univs [] -- no ex_tvs++pcDataConWithFixity :: Bool -- ^ declared infix?+ -> Name -- ^ datacon name+ -> [TyVar] -- ^ univ tyvars+ -> [TyVar] -- ^ ex tyvars+ -> [Type] -- ^ args+ -> TyCon+ -> DataCon+pcDataConWithFixity infx n = pcDataConWithFixity' infx n (dataConWorkerUnique (nameUnique n))+ NoRRI+-- The Name's unique is the first of two free uniques;+-- the first is used for the datacon itself,+-- the second is used for the "worker name"+--+-- To support this the mkPreludeDataConUnique function "allocates"+-- one DataCon unique per pair of Ints.++pcDataConWithFixity' :: Bool -> Name -> Unique -> RuntimeRepInfo+ -> [TyVar] -> [TyVar]+ -> [Type] -> TyCon -> DataCon+-- The Name should be in the DataName name space; it's the name+-- of the DataCon itself.++pcDataConWithFixity' declared_infix dc_name wrk_key rri tyvars ex_tyvars arg_tys tycon+ = data_con+ where+ data_con = mkDataCon dc_name declared_infix prom_info+ (map (const no_bang) arg_tys)+ [] -- No labelled fields+ (mkTyVarBinders Specified tyvars)+ (mkTyVarBinders Specified ex_tyvars)+ [] -- No equality spec+ [] -- No theta+ arg_tys (mkTyConApp tycon (mkTyVarTys tyvars))+ rri+ tycon+ [] -- No stupid theta+ (mkDataConWorkId wrk_name data_con)+ NoDataConRep -- Wired-in types are too simple to need wrappers++ no_bang = HsSrcBang NoSourceText NoSrcUnpack NoSrcStrict++ wrk_name = mkDataConWorkerName data_con wrk_key++ prom_info = mkPrelTyConRepName dc_name++mkDataConWorkerName :: DataCon -> Unique -> Name+mkDataConWorkerName data_con wrk_key =+ mkWiredInName modu wrk_occ wrk_key+ (AnId (dataConWorkId data_con)) UserSyntax+ where+ modu = ASSERT( isExternalName dc_name )+ nameModule dc_name+ dc_name = dataConName data_con+ dc_occ = nameOccName dc_name+ wrk_occ = mkDataConWorkerOcc dc_occ++-- used for RuntimeRep and friends+pcSpecialDataCon :: Name -> [Type] -> TyCon -> RuntimeRepInfo -> DataCon+pcSpecialDataCon dc_name arg_tys tycon rri+ = pcDataConWithFixity' False dc_name (dataConWorkerUnique (nameUnique dc_name)) rri+ [] [] arg_tys tycon++{-+************************************************************************+* *+ Kinds+* *+************************************************************************+-}++typeNatKindCon, typeSymbolKindCon :: TyCon+-- data Nat+-- data Symbol+typeNatKindCon = pcTyCon False typeNatKindConName Nothing [] []+typeSymbolKindCon = pcTyCon False typeSymbolKindConName Nothing [] []++typeNatKind, typeSymbolKind :: Kind+typeNatKind = mkTyConTy typeNatKindCon+typeSymbolKind = mkTyConTy typeSymbolKindCon++constraintKindTyCon :: TyCon+constraintKindTyCon = pcTyCon False constraintKindTyConName+ Nothing [] []++liftedTypeKind, constraintKind :: Kind+liftedTypeKind = tYPE liftedRepTy+constraintKind = mkTyConApp constraintKindTyCon []++-- mkFunKind and mkForAllKind are defined here+-- solely so that TyCon can use them via a SOURCE import+mkFunKind :: Kind -> Kind -> Kind+mkFunKind = mkFunTy++mkForAllKind :: TyVar -> ArgFlag -> Kind -> Kind+mkForAllKind = mkForAllTy++{-+************************************************************************+* *+ Stuff for dealing with tuples+* *+************************************************************************++Note [How tuples work] See also Note [Known-key names] in PrelNames+~~~~~~~~~~~~~~~~~~~~~~+* There are three families of tuple TyCons and corresponding+ DataCons, expressed by the type BasicTypes.TupleSort:+ data TupleSort = BoxedTuple | UnboxedTuple | ConstraintTuple++* All three families are AlgTyCons, whose AlgTyConRhs is TupleTyCon++* BoxedTuples+ - A wired-in type+ - Data type declarations in GHC.Tuple+ - The data constructors really have an info table++* UnboxedTuples+ - A wired-in type+ - Have a pretend DataCon, defined in GHC.Prim,+ but no actual declaration and no info table++* ConstraintTuples+ - Are known-key rather than wired-in. Reason: it's awkward to+ have all the superclass selectors wired-in.+ - Declared as classes in GHC.Classes, e.g.+ class (c1,c2) => (c1,c2)+ - Given constraints: the superclasses automatically become available+ - Wanted constraints: there is a built-in instance+ instance (c1,c2) => (c1,c2)+ - Currently just go up to 16; beyond that+ you have to use manual nesting+ - Their OccNames look like (%,,,%), so they can easily be+ distinguished from term tuples. But (following Haskell) we+ pretty-print saturated constraint tuples with round parens; see+ BasicTypes.tupleParens.++* In quite a lot of places things are restrcted just to+ BoxedTuple/UnboxedTuple, and then we used BasicTypes.Boxity to distinguish+ E.g. tupleTyCon has a Boxity argument++* When looking up an OccName in the original-name cache+ (IfaceEnv.lookupOrigNameCache), we spot the tuple OccName to make sure+ we get the right wired-in name. This guy can't tell the difference+ between BoxedTuple and ConstraintTuple (same OccName!), so tuples+ are not serialised into interface files using OccNames at all.++* Serialization to interface files works via the usual mechanism for known-key+ things: instead of serializing the OccName we just serialize the key. During+ deserialization we lookup the Name associated with the unique with the logic+ in KnownUniques. See Note [Symbol table representation of names] for details.++Note [One-tuples]+~~~~~~~~~~~~~~~~~+GHC supports both boxed and unboxed one-tuples:+ - Unboxed one-tuples are sometimes useful when returning a+ single value after CPR analysis+ - A boxed one-tuple is used by DsUtils.mkSelectorBinds, when+ there is just one binder+Basically it keeps everythig uniform.++However the /naming/ of the type/data constructors for one-tuples is a+bit odd:+ 3-tuples: (,,) (,,)#+ 2-tuples: (,) (,)#+ 1-tuples: ??+ 0-tuples: () ()#++Zero-tuples have used up the logical name. So we use 'Unit' and 'Unit#'+for one-tuples. So in ghc-prim:GHC.Tuple we see the declarations:+ data () = ()+ data Unit a = Unit a+ data (a,b) = (a,b)++NB (Feb 16): for /constraint/ one-tuples I have 'Unit%' but no class+decl in GHC.Classes, so I think this part may not work properly. But+it's unused I think.+-}++-- | Built-in syntax isn't "in scope" so these OccNames map to wired-in Names+-- with BuiltInSyntax. However, this should only be necessary while resolving+-- names produced by Template Haskell splices since we take care to encode+-- built-in syntax names specially in interface files. See+-- Note [Symbol table representation of names].+--+-- Moreover, there is no need to include names of things that the user can't+-- write (e.g. type representation bindings like $tc(,,,)).+isBuiltInOcc_maybe :: OccName -> Maybe Name+isBuiltInOcc_maybe occ =+ case name of+ "[]" -> Just $ choose_ns listTyConName nilDataConName+ ":" -> Just consDataConName++ "[::]" -> Just parrTyConName++ -- boxed tuple data/tycon+ "()" -> Just $ tup_name Boxed 0+ _ | Just rest <- "(" `stripPrefix` name+ , (commas, rest') <- BS.span (==',') rest+ , ")" <- rest'+ -> Just $ tup_name Boxed (1+BS.length commas)++ -- unboxed tuple data/tycon+ "(##)" -> Just $ tup_name Unboxed 0+ "Unit#" -> Just $ tup_name Unboxed 1+ _ | Just rest <- "(#" `stripPrefix` name+ , (commas, rest') <- BS.span (==',') rest+ , "#)" <- rest'+ -> Just $ tup_name Unboxed (1+BS.length commas)++ -- unboxed sum tycon+ _ | Just rest <- "(#" `stripPrefix` name+ , (pipes, rest') <- BS.span (=='|') rest+ , "#)" <- rest'+ -> Just $ tyConName $ sumTyCon (1+BS.length pipes)++ -- unboxed sum datacon+ _ | Just rest <- "(#" `stripPrefix` name+ , (pipes1, rest') <- BS.span (=='|') rest+ , Just rest'' <- "_" `stripPrefix` rest'+ , (pipes2, rest''') <- BS.span (=='|') rest''+ , "#)" <- rest'''+ -> let arity = BS.length pipes1 + BS.length pipes2 + 1+ alt = BS.length pipes1 + 1+ in Just $ dataConName $ sumDataCon alt arity+ _ -> Nothing+ where+ -- TODO: Drop when bytestring 0.10.8 can be assumed+#if MIN_VERSION_bytestring(0,10,8)+ stripPrefix = BS.stripPrefix+#else+ stripPrefix bs1@(BSI.PS _ _ l1) bs2+ | bs1 `BS.isPrefixOf` bs2 = Just (BSU.unsafeDrop l1 bs2)+ | otherwise = Nothing+#endif++ name = fastStringToByteString $ occNameFS occ++ choose_ns :: Name -> Name -> Name+ choose_ns tc dc+ | isTcClsNameSpace ns = tc+ | isDataConNameSpace ns = dc+ | otherwise = pprPanic "tup_name" (ppr occ)+ where ns = occNameSpace occ++ tup_name boxity arity+ = choose_ns (getName (tupleTyCon boxity arity))+ (getName (tupleDataCon boxity arity))++mkTupleOcc :: NameSpace -> Boxity -> Arity -> OccName+-- No need to cache these, the caching is done in mk_tuple+mkTupleOcc ns Boxed ar = mkOccName ns (mkBoxedTupleStr ar)+mkTupleOcc ns Unboxed ar = mkOccName ns (mkUnboxedTupleStr ar)++mkCTupleOcc :: NameSpace -> Arity -> OccName+mkCTupleOcc ns ar = mkOccName ns (mkConstraintTupleStr ar)++mkBoxedTupleStr :: Arity -> String+mkBoxedTupleStr 0 = "()"+mkBoxedTupleStr 1 = "Unit" -- See Note [One-tuples]+mkBoxedTupleStr ar = '(' : commas ar ++ ")"++mkUnboxedTupleStr :: Arity -> String+mkUnboxedTupleStr 0 = "(##)"+mkUnboxedTupleStr 1 = "Unit#" -- See Note [One-tuples]+mkUnboxedTupleStr ar = "(#" ++ commas ar ++ "#)"++mkConstraintTupleStr :: Arity -> String+mkConstraintTupleStr 0 = "(%%)"+mkConstraintTupleStr 1 = "Unit%" -- See Note [One-tuples]+mkConstraintTupleStr ar = "(%" ++ commas ar ++ "%)"++commas :: Arity -> String+commas ar = take (ar-1) (repeat ',')++cTupleTyConName :: Arity -> Name+cTupleTyConName arity+ = mkExternalName (mkCTupleTyConUnique arity) gHC_CLASSES+ (mkCTupleOcc tcName arity) noSrcSpan++cTupleTyConNames :: [Name]+cTupleTyConNames = map cTupleTyConName (0 : [2..mAX_CTUPLE_SIZE])++cTupleTyConNameSet :: NameSet+cTupleTyConNameSet = mkNameSet cTupleTyConNames++isCTupleTyConName :: Name -> Bool+-- Use Type.isCTupleClass where possible+isCTupleTyConName n+ = ASSERT2( isExternalName n, ppr n )+ nameModule n == gHC_CLASSES+ && n `elemNameSet` cTupleTyConNameSet++cTupleDataConName :: Arity -> Name+cTupleDataConName arity+ = mkExternalName (mkCTupleDataConUnique arity) gHC_CLASSES+ (mkCTupleOcc dataName arity) noSrcSpan++cTupleDataConNames :: [Name]+cTupleDataConNames = map cTupleDataConName (0 : [2..mAX_CTUPLE_SIZE])++tupleTyCon :: Boxity -> Arity -> TyCon+tupleTyCon sort i | i > mAX_TUPLE_SIZE = fst (mk_tuple sort i) -- Build one specially+tupleTyCon Boxed i = fst (boxedTupleArr ! i)+tupleTyCon Unboxed i = fst (unboxedTupleArr ! i)++tupleTyConName :: TupleSort -> Arity -> Name+tupleTyConName ConstraintTuple a = cTupleTyConName a+tupleTyConName BoxedTuple a = tyConName (tupleTyCon Boxed a)+tupleTyConName UnboxedTuple a = tyConName (tupleTyCon Unboxed a)++promotedTupleDataCon :: Boxity -> Arity -> TyCon+promotedTupleDataCon boxity i = promoteDataCon (tupleDataCon boxity i)++tupleDataCon :: Boxity -> Arity -> DataCon+tupleDataCon sort i | i > mAX_TUPLE_SIZE = snd (mk_tuple sort i) -- Build one specially+tupleDataCon Boxed i = snd (boxedTupleArr ! i)+tupleDataCon Unboxed i = snd (unboxedTupleArr ! i)++boxedTupleArr, unboxedTupleArr :: Array Int (TyCon,DataCon)+boxedTupleArr = listArray (0,mAX_TUPLE_SIZE) [mk_tuple Boxed i | i <- [0..mAX_TUPLE_SIZE]]+unboxedTupleArr = listArray (0,mAX_TUPLE_SIZE) [mk_tuple Unboxed i | i <- [0..mAX_TUPLE_SIZE]]++-- | Given the TupleRep/SumRep tycon and list of RuntimeReps of the unboxed+-- tuple/sum arguments, produces the return kind of an unboxed tuple/sum type+-- constructor. @unboxedTupleSumKind [IntRep, LiftedRep] --> TYPE (TupleRep/SumRep+-- [IntRep, LiftedRep])@+unboxedTupleSumKind :: TyCon -> [Type] -> Kind+unboxedTupleSumKind tc rr_tys+ = tYPE (mkTyConApp tc [mkPromotedListTy runtimeRepTy rr_tys])++-- | Specialization of 'unboxedTupleSumKind' for tuples+unboxedTupleKind :: [Type] -> Kind+unboxedTupleKind = unboxedTupleSumKind tupleRepDataConTyCon++mk_tuple :: Boxity -> Int -> (TyCon,DataCon)+mk_tuple Boxed arity = (tycon, tuple_con)+ where+ tycon = mkTupleTyCon tc_name tc_binders tc_res_kind tc_arity tuple_con+ BoxedTuple flavour++ tc_binders = mkTemplateAnonTyConBinders (nOfThem arity liftedTypeKind)+ tc_res_kind = liftedTypeKind+ tc_arity = arity+ flavour = VanillaAlgTyCon (mkPrelTyConRepName tc_name)++ dc_tvs = binderVars tc_binders+ dc_arg_tys = mkTyVarTys dc_tvs+ tuple_con = pcDataCon dc_name dc_tvs dc_arg_tys tycon++ boxity = Boxed+ modu = gHC_TUPLE+ tc_name = mkWiredInName modu (mkTupleOcc tcName boxity arity) tc_uniq+ (ATyCon tycon) BuiltInSyntax+ dc_name = mkWiredInName modu (mkTupleOcc dataName boxity arity) dc_uniq+ (AConLike (RealDataCon tuple_con)) BuiltInSyntax+ tc_uniq = mkTupleTyConUnique boxity arity+ dc_uniq = mkTupleDataConUnique boxity arity++mk_tuple Unboxed arity = (tycon, tuple_con)+ where+ tycon = mkTupleTyCon tc_name tc_binders tc_res_kind tc_arity tuple_con+ UnboxedTuple flavour++ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ -- Kind: forall (k1:RuntimeRep) (k2:RuntimeRep). TYPE k1 -> TYPE k2 -> #+ tc_binders = mkTemplateTyConBinders (nOfThem arity runtimeRepTy)+ (\ks -> map tYPE ks)++ tc_res_kind = unboxedTupleKind rr_tys++ tc_arity = arity * 2+ flavour = UnboxedAlgTyCon $ Just (mkPrelTyConRepName tc_name)++ dc_tvs = binderVars tc_binders+ (rr_tys, dc_arg_tys) = splitAt arity (mkTyVarTys dc_tvs)+ tuple_con = pcDataCon dc_name dc_tvs dc_arg_tys tycon++ boxity = Unboxed+ modu = gHC_PRIM+ tc_name = mkWiredInName modu (mkTupleOcc tcName boxity arity) tc_uniq+ (ATyCon tycon) BuiltInSyntax+ dc_name = mkWiredInName modu (mkTupleOcc dataName boxity arity) dc_uniq+ (AConLike (RealDataCon tuple_con)) BuiltInSyntax+ tc_uniq = mkTupleTyConUnique boxity arity+ dc_uniq = mkTupleDataConUnique boxity arity++unitTyCon :: TyCon+unitTyCon = tupleTyCon Boxed 0++unitTyConKey :: Unique+unitTyConKey = getUnique unitTyCon++unitDataCon :: DataCon+unitDataCon = head (tyConDataCons unitTyCon)++unitDataConId :: Id+unitDataConId = dataConWorkId unitDataCon++pairTyCon :: TyCon+pairTyCon = tupleTyCon Boxed 2++unboxedUnitTyCon :: TyCon+unboxedUnitTyCon = tupleTyCon Unboxed 0++unboxedUnitDataCon :: DataCon+unboxedUnitDataCon = tupleDataCon Unboxed 0+++{- *********************************************************************+* *+ Unboxed sums+* *+********************************************************************* -}++-- | OccName for n-ary unboxed sum type constructor.+mkSumTyConOcc :: Arity -> OccName+mkSumTyConOcc n = mkOccName tcName str+ where+ -- No need to cache these, the caching is done in mk_sum+ str = '(' : '#' : bars ++ "#)"+ bars = replicate (n-1) '|'++-- | OccName for i-th alternative of n-ary unboxed sum data constructor.+mkSumDataConOcc :: ConTag -> Arity -> OccName+mkSumDataConOcc alt n = mkOccName dataName str+ where+ -- No need to cache these, the caching is done in mk_sum+ str = '(' : '#' : bars alt ++ '_' : bars (n - alt - 1) ++ "#)"+ bars i = replicate i '|'++-- | Type constructor for n-ary unboxed sum.+sumTyCon :: Arity -> TyCon+sumTyCon arity+ | arity > mAX_SUM_SIZE+ = fst (mk_sum arity) -- Build one specially++ | arity < 2+ = panic ("sumTyCon: Arity starts from 2. (arity: " ++ show arity ++ ")")++ | otherwise+ = fst (unboxedSumArr ! arity)++-- | Data constructor for i-th alternative of a n-ary unboxed sum.+sumDataCon :: ConTag -- Alternative+ -> Arity -- Arity+ -> DataCon+sumDataCon alt arity+ | alt > arity+ = panic ("sumDataCon: index out of bounds: alt: "+ ++ show alt ++ " > arity " ++ show arity)++ | alt <= 0+ = panic ("sumDataCon: Alts start from 1. (alt: " ++ show alt+ ++ ", arity: " ++ show arity ++ ")")++ | arity < 2+ = panic ("sumDataCon: Arity starts from 2. (alt: " ++ show alt+ ++ ", arity: " ++ show arity ++ ")")++ | arity > mAX_SUM_SIZE+ = snd (mk_sum arity) ! (alt - 1) -- Build one specially++ | otherwise+ = snd (unboxedSumArr ! arity) ! (alt - 1)++-- | Cached type and data constructors for sums. The outer array is+-- indexed by the arity of the sum and the inner array is indexed by+-- the alternative.+unboxedSumArr :: Array Int (TyCon, Array Int DataCon)+unboxedSumArr = listArray (2,mAX_SUM_SIZE) [mk_sum i | i <- [2..mAX_SUM_SIZE]]++-- | Specialization of 'unboxedTupleSumKind' for sums+unboxedSumKind :: [Type] -> Kind+unboxedSumKind = unboxedTupleSumKind sumRepDataConTyCon++-- | Create type constructor and data constructors for n-ary unboxed sum.+mk_sum :: Arity -> (TyCon, Array ConTagZ DataCon)+mk_sum arity = (tycon, sum_cons)+ where+ tycon = mkSumTyCon tc_name tc_binders tc_res_kind (arity * 2) tyvars (elems sum_cons)+ (UnboxedAlgTyCon rep_name)++ -- Unboxed sums are currently not Typeable due to efficiency concerns. See #13276.+ rep_name = Nothing -- Just $ mkPrelTyConRepName tc_name++ tc_binders = mkTemplateTyConBinders (nOfThem arity runtimeRepTy)+ (\ks -> map tYPE ks)++ tyvars = binderVars tc_binders++ tc_res_kind = unboxedSumKind rr_tys++ (rr_tys, tyvar_tys) = splitAt arity (mkTyVarTys tyvars)++ tc_name = mkWiredInName gHC_PRIM (mkSumTyConOcc arity) tc_uniq+ (ATyCon tycon) BuiltInSyntax++ sum_cons = listArray (0,arity-1) [sum_con i | i <- [0..arity-1]]+ sum_con i = let dc = pcDataCon dc_name+ tyvars -- univ tyvars+ [tyvar_tys !! i] -- arg types+ tycon++ dc_name = mkWiredInName gHC_PRIM+ (mkSumDataConOcc i arity)+ (dc_uniq i)+ (AConLike (RealDataCon dc))+ BuiltInSyntax+ in dc++ tc_uniq = mkSumTyConUnique arity+ dc_uniq i = mkSumDataConUnique i arity++{-+************************************************************************+* *+ Equality types and classes+* *+********************************************************************* -}++-- See Note [The equality types story] in TysPrim+-- (:~~: :: forall k1 k2 (a :: k1) (b :: k2). a -> b -> Constraint)+--+-- It's tempting to put functional dependencies on (~~), but it's not+-- necessary because the functional-dependency coverage check looks+-- through superclasses, and (~#) is handled in that check.++heqTyCon, coercibleTyCon :: TyCon+heqClass, coercibleClass :: Class+heqDataCon, coercibleDataCon :: DataCon+heqSCSelId, coercibleSCSelId :: Id++(heqTyCon, heqClass, heqDataCon, heqSCSelId)+ = (tycon, klass, datacon, sc_sel_id)+ where+ tycon = mkClassTyCon heqTyConName binders roles+ rhs klass+ (mkPrelTyConRepName heqTyConName)+ klass = mk_class tycon sc_pred sc_sel_id+ datacon = pcDataCon heqDataConName tvs [sc_pred] tycon++ -- Kind: forall k1 k2. k1 -> k2 -> Constraint+ binders = mkTemplateTyConBinders [liftedTypeKind, liftedTypeKind] (\ks -> ks)+ roles = [Nominal, Nominal, Nominal, Nominal]+ rhs = DataTyCon { data_cons = [datacon], is_enum = False }++ tvs = binderVars binders+ sc_pred = mkTyConApp eqPrimTyCon (mkTyVarTys tvs)+ sc_sel_id = mkDictSelId heqSCSelIdName klass++(coercibleTyCon, coercibleClass, coercibleDataCon, coercibleSCSelId)+ = (tycon, klass, datacon, sc_sel_id)+ where+ tycon = mkClassTyCon coercibleTyConName binders roles+ rhs klass+ (mkPrelTyConRepName coercibleTyConName)+ klass = mk_class tycon sc_pred sc_sel_id+ datacon = pcDataCon coercibleDataConName tvs [sc_pred] tycon++ -- Kind: forall k. k -> k -> Constraint+ binders = mkTemplateTyConBinders [liftedTypeKind] (\[k] -> [k,k])+ roles = [Nominal, Representational, Representational]+ rhs = DataTyCon { data_cons = [datacon], is_enum = False }++ tvs@[k,a,b] = binderVars binders+ sc_pred = mkTyConApp eqReprPrimTyCon (mkTyVarTys [k, k, a, b])+ sc_sel_id = mkDictSelId coercibleSCSelIdName klass++mk_class :: TyCon -> PredType -> Id -> Class+mk_class tycon sc_pred sc_sel_id+ = mkClass (tyConName tycon) (tyConTyVars tycon) [] [sc_pred] [sc_sel_id]+ [] [] (mkAnd []) tycon++{- *********************************************************************+* *+ Kinds and RuntimeRep+* *+********************************************************************* -}++-- For information about the usage of the following type,+-- see Note [TYPE and RuntimeRep] in module TysPrim+runtimeRepTy :: Type+runtimeRepTy = mkTyConTy runtimeRepTyCon++liftedTypeKindTyCon, starKindTyCon, unicodeStarKindTyCon :: TyCon++-- Type syononyms; see Note [TYPE and RuntimeRep] in TysPrim+-- type Type = tYPE 'LiftedRep+-- type * = tYPE 'LiftedRep+-- type * = tYPE 'LiftedRep -- Unicode variant++liftedTypeKindTyCon = buildSynTyCon liftedTypeKindTyConName+ [] liftedTypeKind []+ (tYPE liftedRepTy)++starKindTyCon = buildSynTyCon starKindTyConName+ [] liftedTypeKind []+ (tYPE liftedRepTy)++unicodeStarKindTyCon = buildSynTyCon unicodeStarKindTyConName+ [] liftedTypeKind []+ (tYPE liftedRepTy)++runtimeRepTyCon :: TyCon+runtimeRepTyCon = pcNonEnumTyCon runtimeRepTyConName Nothing []+ (vecRepDataCon : tupleRepDataCon :+ sumRepDataCon : runtimeRepSimpleDataCons)++vecRepDataCon :: DataCon+vecRepDataCon = pcSpecialDataCon vecRepDataConName [ mkTyConTy vecCountTyCon+ , mkTyConTy vecElemTyCon ]+ runtimeRepTyCon+ (RuntimeRep prim_rep_fun)+ where+ prim_rep_fun [count, elem]+ | VecCount n <- tyConRuntimeRepInfo (tyConAppTyCon count)+ , VecElem e <- tyConRuntimeRepInfo (tyConAppTyCon elem)+ = [VecRep n e]+ prim_rep_fun args+ = pprPanic "vecRepDataCon" (ppr args)++vecRepDataConTyCon :: TyCon+vecRepDataConTyCon = promoteDataCon vecRepDataCon++tupleRepDataCon :: DataCon+tupleRepDataCon = pcSpecialDataCon tupleRepDataConName [ mkListTy runtimeRepTy ]+ runtimeRepTyCon (RuntimeRep prim_rep_fun)+ where+ prim_rep_fun [rr_ty_list]+ = concatMap (runtimeRepPrimRep doc) rr_tys+ where+ rr_tys = extractPromotedList rr_ty_list+ doc = text "tupleRepDataCon" <+> ppr rr_tys+ prim_rep_fun args+ = pprPanic "tupleRepDataCon" (ppr args)++tupleRepDataConTyCon :: TyCon+tupleRepDataConTyCon = promoteDataCon tupleRepDataCon++sumRepDataCon :: DataCon+sumRepDataCon = pcSpecialDataCon sumRepDataConName [ mkListTy runtimeRepTy ]+ runtimeRepTyCon (RuntimeRep prim_rep_fun)+ where+ prim_rep_fun [rr_ty_list]+ = map slotPrimRep (ubxSumRepType prim_repss)+ where+ rr_tys = extractPromotedList rr_ty_list+ doc = text "sumRepDataCon" <+> ppr rr_tys+ prim_repss = map (runtimeRepPrimRep doc) rr_tys+ prim_rep_fun args+ = pprPanic "sumRepDataCon" (ppr args)++sumRepDataConTyCon :: TyCon+sumRepDataConTyCon = promoteDataCon sumRepDataCon++-- See Note [Wiring in RuntimeRep]+runtimeRepSimpleDataCons :: [DataCon]+liftedRepDataCon :: DataCon+runtimeRepSimpleDataCons@(liftedRepDataCon : _)+ = zipWithLazy mk_runtime_rep_dc+ [ LiftedRep, UnliftedRep, IntRep, WordRep, Int64Rep+ , Word64Rep, AddrRep, FloatRep, DoubleRep ]+ runtimeRepSimpleDataConNames+ where+ mk_runtime_rep_dc primrep name+ = pcSpecialDataCon name [] runtimeRepTyCon (RuntimeRep (\_ -> [primrep]))++-- See Note [Wiring in RuntimeRep]+liftedRepDataConTy, unliftedRepDataConTy,+ intRepDataConTy, wordRepDataConTy, int64RepDataConTy,+ word64RepDataConTy, addrRepDataConTy, floatRepDataConTy, doubleRepDataConTy :: Type+[liftedRepDataConTy, unliftedRepDataConTy,+ intRepDataConTy, wordRepDataConTy, int64RepDataConTy,+ word64RepDataConTy, addrRepDataConTy, floatRepDataConTy, doubleRepDataConTy]+ = map (mkTyConTy . promoteDataCon) runtimeRepSimpleDataCons++vecCountTyCon :: TyCon+vecCountTyCon = pcTyCon True vecCountTyConName Nothing []+ vecCountDataCons++-- See Note [Wiring in RuntimeRep]+vecCountDataCons :: [DataCon]+vecCountDataCons = zipWithLazy mk_vec_count_dc+ [ 2, 4, 8, 16, 32, 64 ]+ vecCountDataConNames+ where+ mk_vec_count_dc n name+ = pcSpecialDataCon name [] vecCountTyCon (VecCount n)++-- See Note [Wiring in RuntimeRep]+vec2DataConTy, vec4DataConTy, vec8DataConTy, vec16DataConTy, vec32DataConTy,+ vec64DataConTy :: Type+[vec2DataConTy, vec4DataConTy, vec8DataConTy, vec16DataConTy, vec32DataConTy,+ vec64DataConTy] = map (mkTyConTy . promoteDataCon) vecCountDataCons++vecElemTyCon :: TyCon+vecElemTyCon = pcTyCon True vecElemTyConName Nothing [] vecElemDataCons++-- See Note [Wiring in RuntimeRep]+vecElemDataCons :: [DataCon]+vecElemDataCons = zipWithLazy mk_vec_elem_dc+ [ Int8ElemRep, Int16ElemRep, Int32ElemRep, Int64ElemRep+ , Word8ElemRep, Word16ElemRep, Word32ElemRep, Word64ElemRep+ , FloatElemRep, DoubleElemRep ]+ vecElemDataConNames+ where+ mk_vec_elem_dc elem name+ = pcSpecialDataCon name [] vecElemTyCon (VecElem elem)++-- See Note [Wiring in RuntimeRep]+int8ElemRepDataConTy, int16ElemRepDataConTy, int32ElemRepDataConTy,+ int64ElemRepDataConTy, word8ElemRepDataConTy, word16ElemRepDataConTy,+ word32ElemRepDataConTy, word64ElemRepDataConTy, floatElemRepDataConTy,+ doubleElemRepDataConTy :: Type+[int8ElemRepDataConTy, int16ElemRepDataConTy, int32ElemRepDataConTy,+ int64ElemRepDataConTy, word8ElemRepDataConTy, word16ElemRepDataConTy,+ word32ElemRepDataConTy, word64ElemRepDataConTy, floatElemRepDataConTy,+ doubleElemRepDataConTy] = map (mkTyConTy . promoteDataCon)+ vecElemDataCons++liftedRepDataConTyCon :: TyCon+liftedRepDataConTyCon = promoteDataCon liftedRepDataCon++-- The type ('LiftedRep)+liftedRepTy :: Type+liftedRepTy = mkTyConTy liftedRepDataConTyCon++{- *********************************************************************+* *+ The boxed primitive types: Char, Int, etc+* *+********************************************************************* -}++boxingDataCon_maybe :: TyCon -> Maybe DataCon+-- boxingDataCon_maybe Char# = C#+-- boxingDataCon_maybe Int# = I#+-- ... etc ...+-- See Note [Boxing primitive types]+boxingDataCon_maybe tc+ = lookupNameEnv boxing_constr_env (tyConName tc)++boxing_constr_env :: NameEnv DataCon+boxing_constr_env+ = mkNameEnv [(charPrimTyConName , charDataCon )+ ,(intPrimTyConName , intDataCon )+ ,(wordPrimTyConName , wordDataCon )+ ,(floatPrimTyConName , floatDataCon )+ ,(doublePrimTyConName, doubleDataCon) ]++{- Note [Boxing primitive types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For a handful of primitive types (Int, Char, Word, Flaot, Double),+we can readily box and an unboxed version (Int#, Char# etc) using+the corresponding data constructor. This is useful in a couple+of places, notably let-floating -}+++charTy :: Type+charTy = mkTyConTy charTyCon++charTyCon :: TyCon+charTyCon = pcNonEnumTyCon charTyConName+ (Just (CType NoSourceText Nothing+ (NoSourceText,fsLit "HsChar")))+ [] [charDataCon]+charDataCon :: DataCon+charDataCon = pcDataCon charDataConName [] [charPrimTy] charTyCon++stringTy :: Type+stringTy = mkListTy charTy -- convenience only++intTy :: Type+intTy = mkTyConTy intTyCon++intTyCon :: TyCon+intTyCon = pcNonEnumTyCon intTyConName+ (Just (CType NoSourceText Nothing (NoSourceText,fsLit "HsInt")))+ [] [intDataCon]+intDataCon :: DataCon+intDataCon = pcDataCon intDataConName [] [intPrimTy] intTyCon++wordTy :: Type+wordTy = mkTyConTy wordTyCon++wordTyCon :: TyCon+wordTyCon = pcNonEnumTyCon wordTyConName+ (Just (CType NoSourceText Nothing (NoSourceText, fsLit "HsWord")))+ [] [wordDataCon]+wordDataCon :: DataCon+wordDataCon = pcDataCon wordDataConName [] [wordPrimTy] wordTyCon++word8Ty :: Type+word8Ty = mkTyConTy word8TyCon++word8TyCon :: TyCon+word8TyCon = pcNonEnumTyCon word8TyConName+ (Just (CType NoSourceText Nothing+ (NoSourceText, fsLit "HsWord8"))) []+ [word8DataCon]+word8DataCon :: DataCon+word8DataCon = pcDataCon word8DataConName [] [wordPrimTy] word8TyCon++floatTy :: Type+floatTy = mkTyConTy floatTyCon++floatTyCon :: TyCon+floatTyCon = pcNonEnumTyCon floatTyConName+ (Just (CType NoSourceText Nothing+ (NoSourceText, fsLit "HsFloat"))) []+ [floatDataCon]+floatDataCon :: DataCon+floatDataCon = pcDataCon floatDataConName [] [floatPrimTy] floatTyCon++doubleTy :: Type+doubleTy = mkTyConTy doubleTyCon++doubleTyCon :: TyCon+doubleTyCon = pcNonEnumTyCon doubleTyConName+ (Just (CType NoSourceText Nothing+ (NoSourceText,fsLit "HsDouble"))) []+ [doubleDataCon]++doubleDataCon :: DataCon+doubleDataCon = pcDataCon doubleDataConName [] [doublePrimTy] doubleTyCon++{-+************************************************************************+* *+ The Bool type+* *+************************************************************************++An ordinary enumeration type, but deeply wired in. There are no+magical operations on @Bool@ (just the regular Prelude code).++{\em BEGIN IDLE SPECULATION BY SIMON}++This is not the only way to encode @Bool@. A more obvious coding makes+@Bool@ just a boxed up version of @Bool#@, like this:+\begin{verbatim}+type Bool# = Int#+data Bool = MkBool Bool#+\end{verbatim}++Unfortunately, this doesn't correspond to what the Report says @Bool@+looks like! Furthermore, we get slightly less efficient code (I+think) with this coding. @gtInt@ would look like this:++\begin{verbatim}+gtInt :: Int -> Int -> Bool+gtInt x y = case x of I# x# ->+ case y of I# y# ->+ case (gtIntPrim x# y#) of+ b# -> MkBool b#+\end{verbatim}++Notice that the result of the @gtIntPrim@ comparison has to be turned+into an integer (here called @b#@), and returned in a @MkBool@ box.++The @if@ expression would compile to this:+\begin{verbatim}+case (gtInt x y) of+ MkBool b# -> case b# of { 1# -> e1; 0# -> e2 }+\end{verbatim}++I think this code is a little less efficient than the previous code,+but I'm not certain. At all events, corresponding with the Report is+important. The interesting thing is that the language is expressive+enough to describe more than one alternative; and that a type doesn't+necessarily need to be a straightforwardly boxed version of its+primitive counterpart.++{\em END IDLE SPECULATION BY SIMON}+-}++boolTy :: Type+boolTy = mkTyConTy boolTyCon++boolTyCon :: TyCon+boolTyCon = pcTyCon True boolTyConName+ (Just (CType NoSourceText Nothing+ (NoSourceText, fsLit "HsBool")))+ [] [falseDataCon, trueDataCon]++falseDataCon, trueDataCon :: DataCon+falseDataCon = pcDataCon falseDataConName [] [] boolTyCon+trueDataCon = pcDataCon trueDataConName [] [] boolTyCon++falseDataConId, trueDataConId :: Id+falseDataConId = dataConWorkId falseDataCon+trueDataConId = dataConWorkId trueDataCon++orderingTyCon :: TyCon+orderingTyCon = pcTyCon True orderingTyConName Nothing+ [] [ltDataCon, eqDataCon, gtDataCon]++ltDataCon, eqDataCon, gtDataCon :: DataCon+ltDataCon = pcDataCon ltDataConName [] [] orderingTyCon+eqDataCon = pcDataCon eqDataConName [] [] orderingTyCon+gtDataCon = pcDataCon gtDataConName [] [] orderingTyCon++ltDataConId, eqDataConId, gtDataConId :: Id+ltDataConId = dataConWorkId ltDataCon+eqDataConId = dataConWorkId eqDataCon+gtDataConId = dataConWorkId gtDataCon++{-+************************************************************************+* *+ The List type+ Special syntax, deeply wired in,+ but otherwise an ordinary algebraic data type+* *+************************************************************************++ data [] a = [] | a : (List a)+-}++mkListTy :: Type -> Type+mkListTy ty = mkTyConApp listTyCon [ty]++listTyCon :: TyCon+listTyCon = buildAlgTyCon listTyConName alpha_tyvar [Representational]+ Nothing []+ (DataTyCon [nilDataCon, consDataCon] False )+ False+ (VanillaAlgTyCon $ mkPrelTyConRepName listTyConName)++nilDataCon :: DataCon+nilDataCon = pcDataCon nilDataConName alpha_tyvar [] listTyCon++consDataCon :: DataCon+consDataCon = pcDataConWithFixity True {- Declared infix -}+ consDataConName+ alpha_tyvar [] [alphaTy, mkTyConApp listTyCon alpha_ty] listTyCon+-- Interesting: polymorphic recursion would help here.+-- We can't use (mkListTy alphaTy) in the defn of consDataCon, else mkListTy+-- gets the over-specific type (Type -> Type)++-- Wired-in type Maybe++maybeTyCon :: TyCon+maybeTyCon = pcTyCon False maybeTyConName Nothing alpha_tyvar+ [nothingDataCon, justDataCon]++nothingDataCon :: DataCon+nothingDataCon = pcDataCon nothingDataConName alpha_tyvar [] maybeTyCon++justDataCon :: DataCon+justDataCon = pcDataCon justDataConName alpha_tyvar [alphaTy] maybeTyCon++{-+** *********************************************************************+* *+ The tuple types+* *+************************************************************************++The tuple types are definitely magic, because they form an infinite+family.++\begin{itemize}+\item+They have a special family of type constructors, of type @TyCon@+These contain the tycon arity, but don't require a Unique.++\item+They have a special family of constructors, of type+@Id@. Again these contain their arity but don't need a Unique.++\item+There should be a magic way of generating the info tables and+entry code for all tuples.++But at the moment we just compile a Haskell source+file\srcloc{lib/prelude/...} containing declarations like:+\begin{verbatim}+data Tuple0 = Tup0+data Tuple2 a b = Tup2 a b+data Tuple3 a b c = Tup3 a b c+data Tuple4 a b c d = Tup4 a b c d+...+\end{verbatim}+The print-names associated with the magic @Id@s for tuple constructors+``just happen'' to be the same as those generated by these+declarations.++\item+The instance environment should have a magic way to know+that each tuple type is an instances of classes @Eq@, @Ix@, @Ord@ and+so on. \ToDo{Not implemented yet.}++\item+There should also be a way to generate the appropriate code for each+of these instances, but (like the info tables and entry code) it is+done by enumeration\srcloc{lib/prelude/InTup?.hs}.+\end{itemize}+-}++-- | Make a tuple type. The list of types should /not/ include any+-- RuntimeRep specifications.+mkTupleTy :: Boxity -> [Type] -> Type+-- Special case for *boxed* 1-tuples, which are represented by the type itself+mkTupleTy Boxed [ty] = ty+mkTupleTy Boxed tys = mkTyConApp (tupleTyCon Boxed (length tys)) tys+mkTupleTy Unboxed tys = mkTyConApp (tupleTyCon Unboxed (length tys))+ (map (getRuntimeRep "mkTupleTy") tys ++ tys)++-- | Build the type of a small tuple that holds the specified type of thing+mkBoxedTupleTy :: [Type] -> Type+mkBoxedTupleTy tys = mkTupleTy Boxed tys++unitTy :: Type+unitTy = mkTupleTy Boxed []++{- *********************************************************************+* *+ The sum types+* *+************************************************************************+-}++mkSumTy :: [Type] -> Type+mkSumTy tys = mkTyConApp (sumTyCon (length tys))+ (map (getRuntimeRep "mkSumTy") tys ++ tys)++{- *********************************************************************+* *+ The parallel-array type, [::]+* *+************************************************************************++Special syntax for parallel arrays needs some wired in definitions.+-}++-- | Construct a type representing the application of the parallel array constructor+mkPArrTy :: Type -> Type+mkPArrTy ty = mkTyConApp parrTyCon [ty]++-- | Represents the type constructor of parallel arrays+--+-- * This must match the definition in @PrelPArr@+--+-- NB: Although the constructor is given here, it will not be accessible in+-- user code as it is not in the environment of any compiled module except+-- @PrelPArr@.+--+parrTyCon :: TyCon+parrTyCon = pcNonEnumTyCon parrTyConName Nothing alpha_tyvar [parrDataCon]++parrDataCon :: DataCon+parrDataCon = pcDataCon+ parrDataConName+ alpha_tyvar -- forall'ed type variables+ [intTy, -- 1st argument: Int+ mkTyConApp -- 2nd argument: Array# a+ arrayPrimTyCon+ alpha_ty]+ parrTyCon++-- | Check whether a type constructor is the constructor for parallel arrays+isPArrTyCon :: TyCon -> Bool+isPArrTyCon tc = tyConName tc == parrTyConName++-- | Fake array constructors+--+-- * These constructors are never really used to represent array values;+-- however, they are very convenient during desugaring (and, in particular,+-- in the pattern matching compiler) to treat array pattern just like+-- yet another constructor pattern+--+parrFakeCon :: Arity -> DataCon+parrFakeCon i | i > mAX_TUPLE_SIZE = mkPArrFakeCon i -- build one specially+parrFakeCon i = parrFakeConArr!i++-- pre-defined set of constructors+--+parrFakeConArr :: Array Int DataCon+parrFakeConArr = array (0, mAX_TUPLE_SIZE) [(i, mkPArrFakeCon i)+ | i <- [0..mAX_TUPLE_SIZE]]++-- build a fake parallel array constructor for the given arity+--+mkPArrFakeCon :: Int -> DataCon+mkPArrFakeCon arity = data_con+ where+ data_con = pcDataCon name [tyvar] tyvarTys parrTyCon+ tyvar = head alphaTyVars+ tyvarTys = replicate arity $ mkTyVarTy tyvar+ nameStr = mkFastString ("MkPArr" ++ show arity)+ name = mkWiredInName gHC_PARR' (mkDataOccFS nameStr) unique+ (AConLike (RealDataCon data_con)) UserSyntax+ unique = mkPArrDataConUnique arity++-- | Checks whether a data constructor is a fake constructor for parallel arrays+isPArrFakeCon :: DataCon -> Bool+isPArrFakeCon dcon = dcon == parrFakeCon (dataConSourceArity dcon)++-- Promoted Booleans++promotedFalseDataCon, promotedTrueDataCon :: TyCon+promotedTrueDataCon = promoteDataCon trueDataCon+promotedFalseDataCon = promoteDataCon falseDataCon++-- Promoted Maybe+promotedNothingDataCon, promotedJustDataCon :: TyCon+promotedNothingDataCon = promoteDataCon nothingDataCon+promotedJustDataCon = promoteDataCon justDataCon++-- Promoted Ordering++promotedLTDataCon+ , promotedEQDataCon+ , promotedGTDataCon+ :: TyCon+promotedLTDataCon = promoteDataCon ltDataCon+promotedEQDataCon = promoteDataCon eqDataCon+promotedGTDataCon = promoteDataCon gtDataCon++-- Promoted List+promotedConsDataCon, promotedNilDataCon :: TyCon+promotedConsDataCon = promoteDataCon consDataCon+promotedNilDataCon = promoteDataCon nilDataCon++-- | Make a *promoted* list.+mkPromotedListTy :: Kind -- ^ of the elements of the list+ -> [Type] -- ^ elements+ -> Type+mkPromotedListTy k tys+ = foldr cons nil tys+ where+ cons :: Type -- element+ -> Type -- list+ -> Type+ cons elt list = mkTyConApp promotedConsDataCon [k, elt, list]++ nil :: Type+ nil = mkTyConApp promotedNilDataCon [k]++-- | Extract the elements of a promoted list. Panics if the type is not a+-- promoted list+extractPromotedList :: Type -- ^ The promoted list+ -> [Type]+extractPromotedList tys = go tys+ where+ go list_ty+ | Just (tc, [_k, t, ts]) <- splitTyConApp_maybe list_ty+ = ASSERT( tc `hasKey` consDataConKey )+ t : go ts++ | Just (tc, [_k]) <- splitTyConApp_maybe list_ty+ = ASSERT( tc `hasKey` nilDataConKey )+ []++ | otherwise+ = pprPanic "extractPromotedList" (ppr tys)
+ prelude/TysWiredIn.hs-boot view
@@ -0,0 +1,37 @@+module TysWiredIn where++import Var( TyVar, ArgFlag )+import {-# SOURCE #-} TyCon ( TyCon )+import {-# SOURCE #-} TyCoRep (Type, Kind)+++mkFunKind :: Kind -> Kind -> Kind+mkForAllKind :: TyVar -> ArgFlag -> Kind -> Kind++listTyCon :: TyCon+typeNatKind, typeSymbolKind :: Type+mkBoxedTupleTy :: [Type] -> Type++liftedTypeKind :: Kind+constraintKind :: Kind++runtimeRepTyCon, vecCountTyCon, vecElemTyCon :: TyCon+runtimeRepTy :: Type++liftedRepDataConTyCon, vecRepDataConTyCon, tupleRepDataConTyCon :: TyCon++liftedRepDataConTy, unliftedRepDataConTy, intRepDataConTy,+ wordRepDataConTy, int64RepDataConTy, word64RepDataConTy, addrRepDataConTy,+ floatRepDataConTy, doubleRepDataConTy :: Type++vec2DataConTy, vec4DataConTy, vec8DataConTy, vec16DataConTy, vec32DataConTy,+ vec64DataConTy :: Type++int8ElemRepDataConTy, int16ElemRepDataConTy, int32ElemRepDataConTy,+ int64ElemRepDataConTy, word8ElemRepDataConTy, word16ElemRepDataConTy,+ word32ElemRepDataConTy, word64ElemRepDataConTy, floatElemRepDataConTy,+ doubleElemRepDataConTy :: Type++anyTypeOfKind :: Kind -> Type+unboxedTupleKind :: [Type] -> Type+mkPromotedListTy :: Type -> [Type] -> Type
+ profiling/CostCentre.hs view
@@ -0,0 +1,326 @@+{-# LANGUAGE DeriveDataTypeable #-}+module CostCentre (+ CostCentre(..), CcName, IsCafCC(..),+ -- All abstract except to friend: ParseIface.y++ CostCentreStack,+ CollectedCCs,+ noCCS, currentCCS, dontCareCCS,+ noCCSAttached, isCurrentCCS,+ maybeSingletonCCS,++ mkUserCC, mkAutoCC, mkAllCafsCC,+ mkSingletonCCS,+ isCafCCS, isCafCC, isSccCountCC, sccAbleCC, ccFromThisModule,++ pprCostCentreCore,+ costCentreUserName, costCentreUserNameFS,+ costCentreSrcSpan,++ cmpCostCentre -- used for removing dups in a list+ ) where++import Binary+import Var+import Name+import Module+import Unique+import Outputable+import SrcLoc+import FastString+import Util++import Data.Data++-----------------------------------------------------------------------------+-- Cost Centres++-- | A Cost Centre is a single @{-# SCC #-}@ annotation.++data CostCentre+ = NormalCC {+ cc_key :: {-# UNPACK #-} !Int,+ -- ^ Two cost centres may have the same name and+ -- module but different SrcSpans, so we need a way to+ -- distinguish them easily and give them different+ -- object-code labels. So every CostCentre has a+ -- Unique that is distinct from every other+ -- CostCentre in the same module.+ --+ -- XXX: should really be using Unique here, but we+ -- need to derive Data below and there's no Data+ -- instance for Unique.+ cc_name :: CcName, -- ^ Name of the cost centre itself+ cc_mod :: Module, -- ^ Name of module defining this CC.+ cc_loc :: SrcSpan,+ cc_is_caf :: IsCafCC -- see below+ }++ | AllCafsCC {+ cc_mod :: Module, -- Name of module defining this CC.+ cc_loc :: SrcSpan+ }+ deriving Data++type CcName = FastString++data IsCafCC = NotCafCC | CafCC+ deriving (Eq, Ord, Data)+++instance Eq CostCentre where+ c1 == c2 = case c1 `cmpCostCentre` c2 of { EQ -> True; _ -> False }++instance Ord CostCentre where+ compare = cmpCostCentre++cmpCostCentre :: CostCentre -> CostCentre -> Ordering++cmpCostCentre (AllCafsCC {cc_mod = m1}) (AllCafsCC {cc_mod = m2})+ = m1 `compare` m2++cmpCostCentre NormalCC {cc_key = n1, cc_mod = m1}+ NormalCC {cc_key = n2, cc_mod = m2}+ -- first key is module name, then the integer key+ = (m1 `compare` m2) `thenCmp` (n1 `compare` n2)++cmpCostCentre other_1 other_2+ = let+ tag1 = tag_CC other_1+ tag2 = tag_CC other_2+ in+ if tag1 < tag2 then LT else GT+ where+ tag_CC :: CostCentre -> Int+ tag_CC (NormalCC {}) = 0+ tag_CC (AllCafsCC {}) = 1+++-----------------------------------------------------------------------------+-- Predicates on CostCentre++isCafCC :: CostCentre -> Bool+isCafCC (AllCafsCC {}) = True+isCafCC (NormalCC {cc_is_caf = CafCC}) = True+isCafCC _ = False++-- | Is this a cost-centre which records scc counts+isSccCountCC :: CostCentre -> Bool+isSccCountCC cc | isCafCC cc = False+ | otherwise = True++-- | Is this a cost-centre which can be sccd ?+sccAbleCC :: CostCentre -> Bool+sccAbleCC cc | isCafCC cc = False+ | otherwise = True++ccFromThisModule :: CostCentre -> Module -> Bool+ccFromThisModule cc m = cc_mod cc == m+++-----------------------------------------------------------------------------+-- Building cost centres++mkUserCC :: FastString -> Module -> SrcSpan -> Unique -> CostCentre+mkUserCC cc_name mod loc key+ = NormalCC { cc_key = getKey key, cc_name = cc_name, cc_mod = mod, cc_loc = loc,+ cc_is_caf = NotCafCC {-might be changed-}+ }++mkAutoCC :: Id -> Module -> IsCafCC -> CostCentre+mkAutoCC id mod is_caf+ = NormalCC { cc_key = getKey (getUnique id),+ cc_name = str, cc_mod = mod,+ cc_loc = nameSrcSpan (getName id),+ cc_is_caf = is_caf+ }+ where+ name = getName id+ -- beware: only external names are guaranteed to have unique+ -- Occnames. If the name is not external, we must append its+ -- Unique.+ -- See bug #249, tests prof001, prof002, also #2411+ str | isExternalName name = occNameFS (getOccName id)+ | otherwise = occNameFS (getOccName id)+ `appendFS`+ mkFastString ('_' : show (getUnique name))+mkAllCafsCC :: Module -> SrcSpan -> CostCentre+mkAllCafsCC m loc = AllCafsCC { cc_mod = m, cc_loc = loc }++-----------------------------------------------------------------------------+-- Cost Centre Stacks++-- | A Cost Centre Stack is something that can be attached to a closure.+-- This is either:+--+-- * the current cost centre stack (CCCS)+-- * a pre-defined cost centre stack (there are several+-- pre-defined CCSs, see below).++data CostCentreStack+ = NoCCS++ | CurrentCCS -- Pinned on a let(rec)-bound+ -- thunk/function/constructor, this says that the+ -- cost centre to be attached to the object, when it+ -- is allocated, is whatever is in the+ -- current-cost-centre-stack register.++ | DontCareCCS -- We need a CCS to stick in static closures+ -- (for data), but we *don't* expect them to+ -- accumulate any costs. But we still need+ -- the placeholder. This CCS is it.++ | SingletonCCS CostCentre++ deriving (Eq, Ord) -- needed for Ord on CLabel+++-- synonym for triple which describes the cost centre info in the generated+-- code for a module.+type CollectedCCs+ = ( [CostCentre] -- local cost-centres that need to be decl'd+ , [CostCentre] -- "extern" cost-centres+ , [CostCentreStack] -- pre-defined "singleton" cost centre stacks+ )+++noCCS, currentCCS, dontCareCCS :: CostCentreStack++noCCS = NoCCS+currentCCS = CurrentCCS+dontCareCCS = DontCareCCS++-----------------------------------------------------------------------------+-- Predicates on Cost-Centre Stacks++noCCSAttached :: CostCentreStack -> Bool+noCCSAttached NoCCS = True+noCCSAttached _ = False++isCurrentCCS :: CostCentreStack -> Bool+isCurrentCCS CurrentCCS = True+isCurrentCCS _ = False++isCafCCS :: CostCentreStack -> Bool+isCafCCS (SingletonCCS cc) = isCafCC cc+isCafCCS _ = False++maybeSingletonCCS :: CostCentreStack -> Maybe CostCentre+maybeSingletonCCS (SingletonCCS cc) = Just cc+maybeSingletonCCS _ = Nothing++mkSingletonCCS :: CostCentre -> CostCentreStack+mkSingletonCCS cc = SingletonCCS cc+++-----------------------------------------------------------------------------+-- Printing Cost Centre Stacks.++-- The outputable instance for CostCentreStack prints the CCS as a C+-- expression.++instance Outputable CostCentreStack where+ ppr NoCCS = text "NO_CCS"+ ppr CurrentCCS = text "CCCS"+ ppr DontCareCCS = text "CCS_DONT_CARE"+ ppr (SingletonCCS cc) = ppr cc <> text "_ccs"+++-----------------------------------------------------------------------------+-- Printing Cost Centres+--+-- There are several different ways in which we might want to print a+-- cost centre:+--+-- - the name of the cost centre, for profiling output (a C string)+-- - the label, i.e. C label for cost centre in .hc file.+-- - the debugging name, for output in -ddump things+-- - the interface name, for printing in _scc_ exprs in iface files.+--+-- The last 3 are derived from costCentreStr below. The first is given+-- by costCentreName.++instance Outputable CostCentre where+ ppr cc = getPprStyle $ \ sty ->+ if codeStyle sty+ then ppCostCentreLbl cc+ else text (costCentreUserName cc)++-- Printing in Core+pprCostCentreCore :: CostCentre -> SDoc+pprCostCentreCore (AllCafsCC {cc_mod = m})+ = text "__sccC" <+> braces (ppr m)+pprCostCentreCore (NormalCC {cc_key = key, cc_name = n, cc_mod = m, cc_loc = loc,+ cc_is_caf = caf})+ = text "__scc" <+> braces (hsep [+ ppr m <> char '.' <> ftext n,+ ifPprDebug (ppr key),+ pp_caf caf,+ ifPprDebug (ppr loc)+ ])++pp_caf :: IsCafCC -> SDoc+pp_caf CafCC = text "__C"+pp_caf _ = empty++-- Printing as a C label+ppCostCentreLbl :: CostCentre -> SDoc+ppCostCentreLbl (AllCafsCC {cc_mod = m}) = ppr m <> text "_CAFs_cc"+ppCostCentreLbl (NormalCC {cc_key = k, cc_name = n, cc_mod = m,+ cc_is_caf = is_caf})+ = ppr m <> char '_' <> ztext (zEncodeFS n) <> char '_' <>+ case is_caf of { CafCC -> text "CAF"; _ -> ppr (mkUniqueGrimily k)} <> text "_cc"++-- This is the name to go in the user-displayed string,+-- recorded in the cost centre declaration+costCentreUserName :: CostCentre -> String+costCentreUserName = unpackFS . costCentreUserNameFS++costCentreUserNameFS :: CostCentre -> FastString+costCentreUserNameFS (AllCafsCC {}) = mkFastString "CAF"+costCentreUserNameFS (NormalCC {cc_name = name, cc_is_caf = is_caf})+ = case is_caf of+ CafCC -> mkFastString "CAF:" `appendFS` name+ _ -> name++costCentreSrcSpan :: CostCentre -> SrcSpan+costCentreSrcSpan = cc_loc++instance Binary IsCafCC where+ put_ bh CafCC = do+ putByte bh 0+ put_ bh NotCafCC = do+ putByte bh 1+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return CafCC+ _ -> do return NotCafCC++instance Binary CostCentre where+ put_ bh (NormalCC aa ab ac _ad ae) = do+ putByte bh 0+ put_ bh aa+ put_ bh ab+ put_ bh ac+ put_ bh ae+ put_ bh (AllCafsCC ae _af) = do+ putByte bh 1+ put_ bh ae+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do aa <- get bh+ ab <- get bh+ ac <- get bh+ ae <- get bh+ return (NormalCC aa ab ac noSrcSpan ae)+ _ -> do ae <- get bh+ return (AllCafsCC ae noSrcSpan)++ -- We ignore the SrcSpans in CostCentres when we serialise them,+ -- and set the SrcSpans to noSrcSpan when deserialising. This is+ -- ok, because we only need the SrcSpan when declaring the+ -- CostCentre in the original module, it is not used by importing+ -- modules.
+ profiling/ProfInit.hs view
@@ -0,0 +1,46 @@+-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 2011+--+-- Generate code to initialise cost centres+--+-- -----------------------------------------------------------------------------++module ProfInit (profilingInitCode) where++import CLabel+import CostCentre+import DynFlags+import Outputable+import FastString+import Module++-- -----------------------------------------------------------------------------+-- Initialising cost centres++-- We must produce declarations for the cost-centres defined in this+-- module;++profilingInitCode :: Module -> CollectedCCs -> SDoc+profilingInitCode this_mod (local_CCs, ___extern_CCs, singleton_CCSs)+ = sdocWithDynFlags $ \dflags ->+ if not (gopt Opt_SccProfilingOn dflags)+ then empty+ else vcat+ [ text "static void prof_init_" <> ppr this_mod+ <> text "(void) __attribute__((constructor));"+ , text "static void prof_init_" <> ppr this_mod <> text "(void)"+ , braces (vcat (+ map emitRegisterCC local_CCs +++ map emitRegisterCCS singleton_CCSs+ ))+ ]+ where+ emitRegisterCC cc =+ text "extern CostCentre " <> cc_lbl <> ptext (sLit "[];") $$+ text "REGISTER_CC(" <> cc_lbl <> char ')' <> semi+ where cc_lbl = ppr (mkCCLabel cc)+ emitRegisterCCS ccs =+ text "extern CostCentreStack " <> ccs_lbl <> ptext (sLit "[];") $$+ text "REGISTER_CCS(" <> ccs_lbl <> char ')' <> semi+ where ccs_lbl = ppr (mkCCSLabel ccs)
+ profiling/SCCfinal.hs view
@@ -0,0 +1,285 @@+-- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998+{-# LANGUAGE CPP #-}++-----------------------------------------------------------------------------+-- Modify and collect code generation for final STG program++{-+ This is now a sort-of-normal STG-to-STG pass (WDP 94/06), run by stg2stg.++ - Traverses the STG program collecting the cost centres. These are required+ to declare the cost centres at the start of code generation.++ Note: because of cross-module unfolding, some of these cost centres may be+ from other modules.++ - Puts on CAF cost-centres if the user has asked for individual CAF+ cost-centres.+-}++module SCCfinal ( stgMassageForProfiling ) where++#include "HsVersions.h"++import StgSyn++import CostCentre -- lots of things+import Id+import Name+import Module+import UniqSupply ( UniqSupply )+import ListSetOps ( removeDups )+import Outputable+import DynFlags+import CoreSyn ( Tickish(..) )+import FastString+import SrcLoc+import Util++import Control.Monad (liftM, ap)++stgMassageForProfiling+ :: DynFlags+ -> Module -- module name+ -> UniqSupply -- unique supply+ -> [StgTopBinding] -- input+ -> (CollectedCCs, [StgTopBinding])++stgMassageForProfiling dflags mod_name _us stg_binds+ = let+ ((local_ccs, extern_ccs, cc_stacks),+ stg_binds2)+ = initMM mod_name (do_top_bindings stg_binds)++ (fixed_ccs, fixed_cc_stacks)+ = if gopt Opt_AutoSccsOnIndividualCafs dflags+ then ([],[]) -- don't need "all CAFs" CC+ else ([all_cafs_cc], [all_cafs_ccs])++ local_ccs_no_dups = fst (removeDups cmpCostCentre local_ccs)+ extern_ccs_no_dups = fst (removeDups cmpCostCentre extern_ccs)+ in+ ((fixed_ccs ++ local_ccs_no_dups,+ extern_ccs_no_dups,+ fixed_cc_stacks ++ cc_stacks), stg_binds2)+ where++ span = mkGeneralSrcSpan (mkFastString "<entire-module>") -- XXX do better+ all_cafs_cc = mkAllCafsCC mod_name span+ all_cafs_ccs = mkSingletonCCS all_cafs_cc++ ----------+ do_top_bindings :: [StgTopBinding] -> MassageM [StgTopBinding]++ do_top_bindings [] = return []++ do_top_bindings (StgTopLifted (StgNonRec b rhs) : bs) = do+ rhs' <- do_top_rhs b rhs+ bs' <- do_top_bindings bs+ return (StgTopLifted (StgNonRec b rhs') : bs')++ do_top_bindings (StgTopLifted (StgRec pairs) : bs) = do+ pairs2 <- mapM do_pair pairs+ bs' <- do_top_bindings bs+ return (StgTopLifted (StgRec pairs2) : bs')+ where+ do_pair (b, rhs) = do+ rhs2 <- do_top_rhs b rhs+ return (b, rhs2)++ do_top_bindings (b@StgTopStringLit{} : bs) = do+ bs' <- do_top_bindings bs+ return (b : bs')++ ----------+ do_top_rhs :: Id -> StgRhs -> MassageM StgRhs++ do_top_rhs _ (StgRhsClosure _ _ _ _ []+ (StgTick (ProfNote _cc False{-not tick-} _push)+ (StgConApp con args _)))+ | not (isDllConApp dflags mod_name con args)+ -- Trivial _scc_ around nothing but static data+ -- Eliminate _scc_ ... and turn into StgRhsCon++ -- isDllConApp checks for LitLit args too+ = return (StgRhsCon dontCareCCS con args)++ do_top_rhs binder (StgRhsClosure _ bi fv u [] body)+ = do+ -- Top level CAF without a cost centre attached+ -- Attach CAF cc (collect if individual CAF ccs)+ caf_ccs <- if gopt Opt_AutoSccsOnIndividualCafs dflags+ then let cc = mkAutoCC binder modl CafCC+ ccs = mkSingletonCCS cc+ -- careful: the binder might be :Main.main,+ -- which doesn't belong to module mod_name.+ -- bug #249, tests prof001, prof002+ modl | Just m <- nameModule_maybe (idName binder) = m+ | otherwise = mod_name+ in do+ collectNewCC cc+ collectCCS ccs+ return ccs+ else+ return all_cafs_ccs+ body' <- do_expr body+ return (StgRhsClosure caf_ccs bi fv u [] body')++ do_top_rhs _ (StgRhsClosure _no_ccs bi fv u args body)+ = do body' <- do_expr body+ return (StgRhsClosure dontCareCCS bi fv u args body')++ do_top_rhs _ (StgRhsCon _ con args)+ -- Top-level (static) data is not counted in heap+ -- profiles; nor do we set CCCS from it; so we+ -- just slam in dontCareCostCentre+ = return (StgRhsCon dontCareCCS con args)++ ------+ do_expr :: StgExpr -> MassageM StgExpr++ do_expr (StgLit l) = return (StgLit l)++ do_expr (StgApp fn args)+ = return (StgApp fn args)++ do_expr (StgConApp con args ty_args)+ = return (StgConApp con args ty_args)++ do_expr (StgOpApp con args res_ty)+ = return (StgOpApp con args res_ty)++ do_expr (StgTick note@(ProfNote cc _ _) expr) = do+ -- Ha, we found a cost centre!+ collectCC cc+ expr' <- do_expr expr+ return (StgTick note expr')++ do_expr (StgTick ti expr) = do+ expr' <- do_expr expr+ return (StgTick ti expr')++ do_expr (StgCase expr bndr alt_type alts) = do+ expr' <- do_expr expr+ alts' <- mapM do_alt alts+ return (StgCase expr' bndr alt_type alts')+ where+ do_alt (id, bs, e) = do+ e' <- do_expr e+ return (id, bs, e')++ do_expr (StgLet b e) = do+ (b,e) <- do_let b e+ return (StgLet b e)++ do_expr (StgLetNoEscape b e) = do+ (b,e) <- do_let b e+ return (StgLetNoEscape b e)++ do_expr other = pprPanic "SCCfinal.do_expr" (ppr other)++ ----------------------------------++ do_let (StgNonRec b rhs) e = do+ rhs' <- do_rhs rhs+ e' <- do_expr e+ return (StgNonRec b rhs',e')++ do_let (StgRec pairs) e = do+ pairs' <- mapM do_pair pairs+ e' <- do_expr e+ return (StgRec pairs', e')+ where+ do_pair (b, rhs) = do+ rhs2 <- do_rhs rhs+ return (b, rhs2)++ ----------------------------------+ do_rhs :: StgRhs -> MassageM StgRhs+ -- We play much the same game as we did in do_top_rhs above;+ -- but we don't have to worry about cafs etc.++ -- throw away the SCC if we don't have to count entries. This+ -- is a little bit wrong, because we're attributing the+ -- allocation of the constructor to the wrong place (XXX)+ -- We should really attach (PushCC cc CurrentCCS) to the rhs,+ -- but need to reinstate PushCC for that.+ do_rhs (StgRhsClosure _closure_cc _bi _fv _u []+ (StgTick (ProfNote cc False{-not tick-} _push)+ (StgConApp con args _)))+ = do collectCC cc+ return (StgRhsCon currentCCS con args)++ do_rhs (StgRhsClosure _ bi fv u args expr) = do+ expr' <- do_expr expr+ return (StgRhsClosure currentCCS bi fv u args expr')++ do_rhs (StgRhsCon _ con args)+ = return (StgRhsCon currentCCS con args)+++-- -----------------------------------------------------------------------------+-- Boring monad stuff for this++newtype MassageM result+ = MassageM {+ unMassageM :: Module -- module name+ -> CollectedCCs+ -> (CollectedCCs, result)+ }++instance Functor MassageM where+ fmap = liftM++instance Applicative MassageM where+ pure x = MassageM (\_ ccs -> (ccs, x))+ (<*>) = ap+ (*>) = thenMM_++instance Monad MassageM where+ (>>=) = thenMM+ (>>) = (*>)++-- the initMM function also returns the final CollectedCCs++initMM :: Module -- module name, which we may consult+ -> MassageM a+ -> (CollectedCCs, a)++initMM mod_name (MassageM m) = m mod_name ([],[],[])++thenMM :: MassageM a -> (a -> MassageM b) -> MassageM b+thenMM_ :: MassageM a -> (MassageM b) -> MassageM b++thenMM expr cont = MassageM $ \mod ccs ->+ case unMassageM expr mod ccs of { (ccs2, result) ->+ unMassageM (cont result) mod ccs2 }++thenMM_ expr cont = MassageM $ \mod ccs ->+ case unMassageM expr mod ccs of { (ccs2, _) ->+ unMassageM cont mod ccs2 }+++collectCC :: CostCentre -> MassageM ()+collectCC cc+ = MassageM $ \mod_name (local_ccs, extern_ccs, ccss)+ -> if (cc `ccFromThisModule` mod_name) then+ ((cc : local_ccs, extern_ccs, ccss), ())+ else -- must declare it "extern"+ ((local_ccs, cc : extern_ccs, ccss), ())++-- Version of collectCC used when we definitely want to declare this+-- CC as local, even if its module name is not the same as the current+-- module name (eg. the special :Main module) see bug #249, #1472,+-- test prof001,prof002.+collectNewCC :: CostCentre -> MassageM ()+collectNewCC cc+ = MassageM $ \_mod_name (local_ccs, extern_ccs, ccss)+ -> ((cc : local_ccs, extern_ccs, ccss), ())++collectCCS :: CostCentreStack -> MassageM ()++collectCCS ccs+ = MassageM $ \_mod_name (local_ccs, extern_ccs, ccss)+ -> ASSERT(not (noCCSAttached ccs))+ ((local_ccs, extern_ccs, ccs : ccss), ())
+ rename/RnBinds.hs view
@@ -0,0 +1,1234 @@+{-# LANGUAGE ScopedTypeVariables, BangPatterns #-}++{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[RnBinds]{Renaming and dependency analysis of bindings}++This module does renaming and dependency analysis on value bindings in+the abstract syntax. It does {\em not} do cycle-checks on class or+type-synonym declarations; those cannot be done at this stage because+they may be affected by renaming (which isn't fully worked out yet).+-}++module RnBinds (+ -- Renaming top-level bindings+ rnTopBindsLHS, rnTopBindsBoot, rnValBindsRHS,++ -- Renaming local bindings+ rnLocalBindsAndThen, rnLocalValBindsLHS, rnLocalValBindsRHS,++ -- Other bindings+ rnMethodBinds, renameSigs,+ rnMatchGroup, rnGRHSs, rnGRHS,+ makeMiniFixityEnv, MiniFixityEnv,+ HsSigCtxt(..)+ ) where++import {-# SOURCE #-} RnExpr( rnLExpr, rnStmts )++import HsSyn+import TcRnMonad+import TcEvidence ( emptyTcEvBinds )+import RnTypes+import RnPat+import RnNames+import RnEnv+import DynFlags+import Module+import Name+import NameEnv+import NameSet+import RdrName ( RdrName, rdrNameOcc )+import SrcLoc+import ListSetOps ( findDupsEq )+import BasicTypes ( RecFlag(..), LexicalFixity(..) )+import Digraph ( SCC(..) )+import Bag+import Util+import Outputable+import FastString+import UniqSet+import Maybes ( orElse )+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.List ( partition, sort )++{-+-- ToDo: Put the annotations into the monad, so that they arrive in the proper+-- place and can be used when complaining.++The code tree received by the function @rnBinds@ contains definitions+in where-clauses which are all apparently mutually recursive, but which may+not really depend upon each other. For example, in the top level program+\begin{verbatim}+f x = y where a = x+ y = x+\end{verbatim}+the definitions of @a@ and @y@ do not depend on each other at all.+Unfortunately, the typechecker cannot always check such definitions.+\footnote{Mycroft, A. 1984. Polymorphic type schemes and recursive+definitions. In Proceedings of the International Symposium on Programming,+Toulouse, pp. 217-39. LNCS 167. Springer Verlag.}+However, the typechecker usually can check definitions in which only the+strongly connected components have been collected into recursive bindings.+This is precisely what the function @rnBinds@ does.++ToDo: deal with case where a single monobinds binds the same variable+twice.++The vertag tag is a unique @Int@; the tags only need to be unique+within one @MonoBinds@, so that unique-Int plumbing is done explicitly+(heavy monad machinery not needed).+++************************************************************************+* *+* naming conventions *+* *+************************************************************************++\subsection[name-conventions]{Name conventions}++The basic algorithm involves walking over the tree and returning a tuple+containing the new tree plus its free variables. Some functions, such+as those walking polymorphic bindings (HsBinds) and qualifier lists in+list comprehensions (@Quals@), return the variables bound in local+environments. These are then used to calculate the free variables of the+expression evaluated in these environments.++Conventions for variable names are as follows:+\begin{itemize}+\item+new code is given a prime to distinguish it from the old.++\item+a set of variables defined in @Exp@ is written @dvExp@++\item+a set of variables free in @Exp@ is written @fvExp@+\end{itemize}++************************************************************************+* *+* analysing polymorphic bindings (HsBindGroup, HsBind)+* *+************************************************************************++\subsubsection[dep-HsBinds]{Polymorphic bindings}++Non-recursive expressions are reconstructed without any changes at top+level, although their component expressions may have to be altered.+However, non-recursive expressions are currently not expected as+\Haskell{} programs, and this code should not be executed.++Monomorphic bindings contain information that is returned in a tuple+(a @FlatMonoBinds@) containing:++\begin{enumerate}+\item+a unique @Int@ that serves as the ``vertex tag'' for this binding.++\item+the name of a function or the names in a pattern. These are a set+referred to as @dvLhs@, the defined variables of the left hand side.++\item+the free variables of the body. These are referred to as @fvBody@.++\item+the definition's actual code. This is referred to as just @code@.+\end{enumerate}++The function @nonRecDvFv@ returns two sets of variables. The first is+the set of variables defined in the set of monomorphic bindings, while the+second is the set of free variables in those bindings.++The set of variables defined in a non-recursive binding is just the+union of all of them, as @union@ removes duplicates. However, the+free variables in each successive set of cumulative bindings is the+union of those in the previous set plus those of the newest binding after+the defined variables of the previous set have been removed.++@rnMethodBinds@ deals only with the declarations in class and+instance declarations. It expects only to see @FunMonoBind@s, and+it expects the global environment to contain bindings for the binders+(which are all class operations).++************************************************************************+* *+\subsubsection{ Top-level bindings}+* *+************************************************************************+-}++-- for top-level bindings, we need to make top-level names,+-- so we have a different entry point than for local bindings+rnTopBindsLHS :: MiniFixityEnv+ -> HsValBinds RdrName+ -> RnM (HsValBindsLR Name RdrName)+rnTopBindsLHS fix_env binds+ = rnValBindsLHS (topRecNameMaker fix_env) binds++rnTopBindsBoot :: NameSet -> HsValBindsLR Name RdrName -> RnM (HsValBinds Name, DefUses)+-- A hs-boot file has no bindings.+-- Return a single HsBindGroup with empty binds and renamed signatures+rnTopBindsBoot bound_names (ValBindsIn mbinds sigs)+ = do { checkErr (isEmptyLHsBinds mbinds) (bindsInHsBootFile mbinds)+ ; (sigs', fvs) <- renameSigs (HsBootCtxt bound_names) sigs+ ; return (ValBindsOut [] sigs', usesOnly fvs) }+rnTopBindsBoot _ b = pprPanic "rnTopBindsBoot" (ppr b)++{-+*********************************************************+* *+ HsLocalBinds+* *+*********************************************************+-}++rnLocalBindsAndThen :: HsLocalBinds RdrName+ -> (HsLocalBinds Name -> FreeVars -> RnM (result, FreeVars))+ -> RnM (result, FreeVars)+-- This version (a) assumes that the binding vars are *not* already in scope+-- (b) removes the binders from the free vars of the thing inside+-- The parser doesn't produce ThenBinds+rnLocalBindsAndThen EmptyLocalBinds thing_inside =+ thing_inside EmptyLocalBinds emptyNameSet++rnLocalBindsAndThen (HsValBinds val_binds) thing_inside+ = rnLocalValBindsAndThen val_binds $ \ val_binds' ->+ thing_inside (HsValBinds val_binds')++rnLocalBindsAndThen (HsIPBinds binds) thing_inside = do+ (binds',fv_binds) <- rnIPBinds binds+ (thing, fvs_thing) <- thing_inside (HsIPBinds binds') fv_binds+ return (thing, fvs_thing `plusFV` fv_binds)++rnIPBinds :: HsIPBinds RdrName -> RnM (HsIPBinds Name, FreeVars)+rnIPBinds (IPBinds ip_binds _no_dict_binds) = do+ (ip_binds', fvs_s) <- mapAndUnzipM (wrapLocFstM rnIPBind) ip_binds+ return (IPBinds ip_binds' emptyTcEvBinds, plusFVs fvs_s)++rnIPBind :: IPBind RdrName -> RnM (IPBind Name, FreeVars)+rnIPBind (IPBind ~(Left n) expr) = do+ (expr',fvExpr) <- rnLExpr expr+ return (IPBind (Left n) expr', fvExpr)++{-+************************************************************************+* *+ ValBinds+* *+************************************************************************+-}++-- Renaming local binding groups+-- Does duplicate/shadow check+rnLocalValBindsLHS :: MiniFixityEnv+ -> HsValBinds RdrName+ -> RnM ([Name], HsValBindsLR Name RdrName)+rnLocalValBindsLHS fix_env binds+ = do { binds' <- rnValBindsLHS (localRecNameMaker fix_env) binds++ -- Check for duplicates and shadowing+ -- Must do this *after* renaming the patterns+ -- See Note [Collect binders only after renaming] in HsUtils++ -- We need to check for dups here because we+ -- don't don't bind all of the variables from the ValBinds at once+ -- with bindLocatedLocals any more.+ --+ -- Note that we don't want to do this at the top level, since+ -- sorting out duplicates and shadowing there happens elsewhere.+ -- The behavior is even different. For example,+ -- import A(f)+ -- f = ...+ -- should not produce a shadowing warning (but it will produce+ -- an ambiguity warning if you use f), but+ -- import A(f)+ -- g = let f = ... in f+ -- should.+ ; let bound_names = collectHsValBinders binds'+ -- There should be only Ids, but if there are any bogus+ -- pattern synonyms, we'll collect them anyway, so that+ -- we don't generate subsequent out-of-scope messages+ ; envs <- getRdrEnvs+ ; checkDupAndShadowedNames envs bound_names++ ; return (bound_names, binds') }++-- renames the left-hand sides+-- generic version used both at the top level and for local binds+-- does some error checking, but not what gets done elsewhere at the top level+rnValBindsLHS :: NameMaker+ -> HsValBinds RdrName+ -> RnM (HsValBindsLR Name RdrName)+rnValBindsLHS topP (ValBindsIn mbinds sigs)+ = do { mbinds' <- mapBagM (wrapLocM (rnBindLHS topP doc)) mbinds+ ; return $ ValBindsIn mbinds' sigs }+ where+ bndrs = collectHsBindsBinders mbinds+ doc = text "In the binding group for:" <+> pprWithCommas ppr bndrs++rnValBindsLHS _ b = pprPanic "rnValBindsLHSFromDoc" (ppr b)++-- General version used both from the top-level and for local things+-- Assumes the LHS vars are in scope+--+-- Does not bind the local fixity declarations+rnValBindsRHS :: HsSigCtxt+ -> HsValBindsLR Name RdrName+ -> RnM (HsValBinds Name, DefUses)++rnValBindsRHS ctxt (ValBindsIn mbinds sigs)+ = do { (sigs', sig_fvs) <- renameSigs ctxt sigs+ ; binds_w_dus <- mapBagM (rnLBind (mkSigTvFn sigs')) mbinds+ ; let !(anal_binds, anal_dus) = depAnalBinds binds_w_dus++ ; let patsyn_fvs = foldr (unionNameSet . psb_fvs) emptyNameSet $+ getPatSynBinds anal_binds+ -- The uses in binds_w_dus for PatSynBinds do not include+ -- variables used in the patsyn builders; see+ -- Note [Pattern synonym builders don't yield dependencies]+ -- But psb_fvs /does/ include those builder fvs. So we+ -- add them back in here to avoid bogus warnings about+ -- unused variables (Trac #12548)++ valbind'_dus = anal_dus `plusDU` usesOnly sig_fvs+ `plusDU` usesOnly patsyn_fvs+ -- Put the sig uses *after* the bindings+ -- so that the binders are removed from+ -- the uses in the sigs++ ; return (ValBindsOut anal_binds sigs', valbind'_dus) }++rnValBindsRHS _ b = pprPanic "rnValBindsRHS" (ppr b)++-- Wrapper for local binds+--+-- The *client* of this function is responsible for checking for unused binders;+-- it doesn't (and can't: we don't have the thing inside the binds) happen here+--+-- The client is also responsible for bringing the fixities into scope+rnLocalValBindsRHS :: NameSet -- names bound by the LHSes+ -> HsValBindsLR Name RdrName+ -> RnM (HsValBinds Name, DefUses)+rnLocalValBindsRHS bound_names binds+ = rnValBindsRHS (LocalBindCtxt bound_names) binds++-- for local binds+-- wrapper that does both the left- and right-hand sides+--+-- here there are no local fixity decls passed in;+-- the local fixity decls come from the ValBinds sigs+rnLocalValBindsAndThen+ :: HsValBinds RdrName+ -> (HsValBinds Name -> FreeVars -> RnM (result, FreeVars))+ -> RnM (result, FreeVars)+rnLocalValBindsAndThen binds@(ValBindsIn _ sigs) thing_inside+ = do { -- (A) Create the local fixity environment+ new_fixities <- makeMiniFixityEnv [L loc sig+ | L loc (FixSig sig) <- sigs]++ -- (B) Rename the LHSes+ ; (bound_names, new_lhs) <- rnLocalValBindsLHS new_fixities binds++ -- ...and bring them (and their fixities) into scope+ ; bindLocalNamesFV bound_names $+ addLocalFixities new_fixities bound_names $ do++ { -- (C) Do the RHS and thing inside+ (binds', dus) <- rnLocalValBindsRHS (mkNameSet bound_names) new_lhs+ ; (result, result_fvs) <- thing_inside binds' (allUses dus)++ -- Report unused bindings based on the (accurate)+ -- findUses. E.g.+ -- let x = x in 3+ -- should report 'x' unused+ ; let real_uses = findUses dus result_fvs+ -- Insert fake uses for variables introduced implicitly by+ -- wildcards (#4404)+ implicit_uses = hsValBindsImplicits binds'+ ; warnUnusedLocalBinds bound_names+ (real_uses `unionNameSet` implicit_uses)++ ; let+ -- The variables "used" in the val binds are:+ -- (1) the uses of the binds (allUses)+ -- (2) the FVs of the thing-inside+ all_uses = allUses dus `plusFV` result_fvs+ -- Note [Unused binding hack]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Note that *in contrast* to the above reporting of+ -- unused bindings, (1) above uses duUses to return *all*+ -- the uses, even if the binding is unused. Otherwise consider:+ -- x = 3+ -- y = let p = x in 'x' -- NB: p not used+ -- If we don't "see" the dependency of 'y' on 'x', we may put the+ -- bindings in the wrong order, and the type checker will complain+ -- that x isn't in scope+ --+ -- But note that this means we won't report 'x' as unused,+ -- whereas we would if we had { x = 3; p = x; y = 'x' }++ ; return (result, all_uses) }}+ -- The bound names are pruned out of all_uses+ -- by the bindLocalNamesFV call above++rnLocalValBindsAndThen bs _ = pprPanic "rnLocalValBindsAndThen" (ppr bs)+++---------------------++-- renaming a single bind++rnBindLHS :: NameMaker+ -> SDoc+ -> HsBind RdrName+ -- returns the renamed left-hand side,+ -- and the FreeVars *of the LHS*+ -- (i.e., any free variables of the pattern)+ -> RnM (HsBindLR Name RdrName)++rnBindLHS name_maker _ bind@(PatBind { pat_lhs = pat })+ = do+ -- we don't actually use the FV processing of rnPatsAndThen here+ (pat',pat'_fvs) <- rnBindPat name_maker pat+ return (bind { pat_lhs = pat', bind_fvs = pat'_fvs })+ -- We temporarily store the pat's FVs in bind_fvs;+ -- gets updated to the FVs of the whole bind+ -- when doing the RHS below++rnBindLHS name_maker _ bind@(FunBind { fun_id = rdr_name })+ = do { name <- applyNameMaker name_maker rdr_name+ ; return (bind { fun_id = name+ , bind_fvs = placeHolderNamesTc }) }++rnBindLHS name_maker _ (PatSynBind psb@PSB{ psb_id = rdrname })+ | isTopRecNameMaker name_maker+ = do { addLocM checkConName rdrname+ ; name <- lookupLocatedTopBndrRn rdrname -- Should be in scope already+ ; return (PatSynBind psb{ psb_id = name }) }++ | otherwise -- Pattern synonym, not at top level+ = do { addErr localPatternSynonymErr -- Complain, but make up a fake+ -- name so that we can carry on+ ; name <- applyNameMaker name_maker rdrname+ ; return (PatSynBind psb{ psb_id = name }) }+ where+ localPatternSynonymErr :: SDoc+ localPatternSynonymErr+ = hang (text "Illegal pattern synonym declaration for" <+> quotes (ppr rdrname))+ 2 (text "Pattern synonym declarations are only valid at top level")++rnBindLHS _ _ b = pprPanic "rnBindHS" (ppr b)++rnLBind :: (Name -> [Name]) -- Signature tyvar function+ -> LHsBindLR Name RdrName+ -> RnM (LHsBind Name, [Name], Uses)+rnLBind sig_fn (L loc bind)+ = setSrcSpan loc $+ do { (bind', bndrs, dus) <- rnBind sig_fn bind+ ; return (L loc bind', bndrs, dus) }++-- assumes the left-hands-side vars are in scope+rnBind :: (Name -> [Name]) -- Signature tyvar function+ -> HsBindLR Name RdrName+ -> RnM (HsBind Name, [Name], Uses)+rnBind _ bind@(PatBind { pat_lhs = pat+ , pat_rhs = grhss+ -- pat fvs were stored in bind_fvs+ -- after processing the LHS+ , bind_fvs = pat_fvs })+ = do { mod <- getModule+ ; (grhss', rhs_fvs) <- rnGRHSs PatBindRhs rnLExpr grhss++ -- No scoped type variables for pattern bindings+ ; let all_fvs = pat_fvs `plusFV` rhs_fvs+ fvs' = filterNameSet (nameIsLocalOrFrom mod) all_fvs+ -- Keep locally-defined Names+ -- As well as dependency analysis, we need these for the+ -- MonoLocalBinds test in TcBinds.decideGeneralisationPlan+ bndrs = collectPatBinders pat+ bind' = bind { pat_rhs = grhss',+ pat_rhs_ty = placeHolderType, bind_fvs = fvs' }+ is_wild_pat = case pat of+ L _ (WildPat {}) -> True+ L _ (BangPat (L _ (WildPat {}))) -> True -- #9127+ _ -> False++ -- Warn if the pattern binds no variables, except for the+ -- entirely-explicit idiom _ = rhs+ -- which (a) is not that different from _v = rhs+ -- (b) is sometimes used to give a type sig for,+ -- or an occurrence of, a variable on the RHS+ ; whenWOptM Opt_WarnUnusedPatternBinds $+ when (null bndrs && not is_wild_pat) $+ addWarn (Reason Opt_WarnUnusedPatternBinds) $ unusedPatBindWarn bind'++ ; fvs' `seq` -- See Note [Free-variable space leak]+ return (bind', bndrs, all_fvs) }++rnBind sig_fn bind@(FunBind { fun_id = name+ , fun_matches = matches })+ -- invariant: no free vars here when it's a FunBind+ = do { let plain_name = unLoc name++ ; (matches', rhs_fvs) <- bindSigTyVarsFV (sig_fn plain_name) $+ -- bindSigTyVars tests for LangExt.ScopedTyVars+ rnMatchGroup (mkPrefixFunRhs name)+ rnLExpr matches+ ; let is_infix = isInfixFunBind bind+ ; when is_infix $ checkPrecMatch plain_name matches'++ ; mod <- getModule+ ; let fvs' = filterNameSet (nameIsLocalOrFrom mod) rhs_fvs+ -- Keep locally-defined Names+ -- As well as dependency analysis, we need these for the+ -- MonoLocalBinds test in TcBinds.decideGeneralisationPlan++ ; fvs' `seq` -- See Note [Free-variable space leak]+ return (bind { fun_matches = matches'+ , bind_fvs = fvs' },+ [plain_name], rhs_fvs)+ }++rnBind sig_fn (PatSynBind bind)+ = do { (bind', name, fvs) <- rnPatSynBind sig_fn bind+ ; return (PatSynBind bind', name, fvs) }++rnBind _ b = pprPanic "rnBind" (ppr b)++{-+Note [Free-variable space leak]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We have+ fvs' = trim fvs+and we seq fvs' before turning it as part of a record.++The reason is that trim is sometimes something like+ \xs -> intersectNameSet (mkNameSet bound_names) xs+and we don't want to retain the list bound_names. This showed up in+trac ticket #1136.+-}++{- *********************************************************************+* *+ Dependency analysis and other support functions+* *+********************************************************************* -}++depAnalBinds :: Bag (LHsBind Name, [Name], Uses)+ -> ([(RecFlag, LHsBinds Name)], DefUses)+-- Dependency analysis; this is important so that+-- unused-binding reporting is accurate+depAnalBinds binds_w_dus+ = (map get_binds sccs, map get_du sccs)+ where+ sccs = depAnal (\(_, defs, _) -> defs)+ (\(_, _, uses) -> nonDetEltsUniqSet uses)+ -- It's OK to use nonDetEltsUniqSet here as explained in+ -- Note [depAnal determinism] in NameEnv.+ (bagToList binds_w_dus)++ get_binds (AcyclicSCC (bind, _, _)) = (NonRecursive, unitBag bind)+ get_binds (CyclicSCC binds_w_dus) = (Recursive, listToBag [b | (b,_,_) <- binds_w_dus])++ get_du (AcyclicSCC (_, bndrs, uses)) = (Just (mkNameSet bndrs), uses)+ get_du (CyclicSCC binds_w_dus) = (Just defs, uses)+ where+ defs = mkNameSet [b | (_,bs,_) <- binds_w_dus, b <- bs]+ uses = unionNameSets [u | (_,_,u) <- binds_w_dus]++---------------------+-- Bind the top-level forall'd type variables in the sigs.+-- E.g f :: a -> a+-- f = rhs+-- The 'a' scopes over the rhs+--+-- NB: there'll usually be just one (for a function binding)+-- but if there are many, one may shadow the rest; too bad!+-- e.g x :: [a] -> [a]+-- y :: [(a,a)] -> a+-- (x,y) = e+-- In e, 'a' will be in scope, and it'll be the one from 'y'!++mkSigTvFn :: [LSig Name] -> (Name -> [Name])+-- Return a lookup function that maps an Id Name to the names+-- of the type variables that should scope over its body.+mkSigTvFn sigs = \n -> lookupNameEnv env n `orElse` []+ where+ env = mkHsSigEnv get_scoped_tvs sigs++ get_scoped_tvs :: LSig Name -> Maybe ([Located Name], [Name])+ -- Returns (binders, scoped tvs for those binders)+ get_scoped_tvs (L _ (ClassOpSig _ names sig_ty))+ = Just (names, hsScopedTvs sig_ty)+ get_scoped_tvs (L _ (TypeSig names sig_ty))+ = Just (names, hsWcScopedTvs sig_ty)+ get_scoped_tvs (L _ (PatSynSig names sig_ty))+ = Just (names, hsScopedTvs sig_ty)+ get_scoped_tvs _ = Nothing++-- Process the fixity declarations, making a FastString -> (Located Fixity) map+-- (We keep the location around for reporting duplicate fixity declarations.)+--+-- Checks for duplicates, but not that only locally defined things are fixed.+-- Note: for local fixity declarations, duplicates would also be checked in+-- check_sigs below. But we also use this function at the top level.++makeMiniFixityEnv :: [LFixitySig RdrName] -> RnM MiniFixityEnv++makeMiniFixityEnv decls = foldlM add_one_sig emptyFsEnv decls+ where+ add_one_sig env (L loc (FixitySig names fixity)) =+ foldlM add_one env [ (loc,name_loc,name,fixity)+ | L name_loc name <- names ]++ add_one env (loc, name_loc, name,fixity) = do+ { -- this fixity decl is a duplicate iff+ -- the ReaderName's OccName's FastString is already in the env+ -- (we only need to check the local fix_env because+ -- definitions of non-local will be caught elsewhere)+ let { fs = occNameFS (rdrNameOcc name)+ ; fix_item = L loc fixity };++ case lookupFsEnv env fs of+ Nothing -> return $ extendFsEnv env fs fix_item+ Just (L loc' _) -> do+ { setSrcSpan loc $+ addErrAt name_loc (dupFixityDecl loc' name)+ ; return env}+ }++dupFixityDecl :: SrcSpan -> RdrName -> SDoc+dupFixityDecl loc rdr_name+ = vcat [text "Multiple fixity declarations for" <+> quotes (ppr rdr_name),+ text "also at " <+> ppr loc]+++{- *********************************************************************+* *+ Pattern synonym bindings+* *+********************************************************************* -}++rnPatSynBind :: (Name -> [Name]) -- Signature tyvar function+ -> PatSynBind Name RdrName+ -> RnM (PatSynBind Name Name, [Name], Uses)+rnPatSynBind sig_fn bind@(PSB { psb_id = L l name+ , psb_args = details+ , psb_def = pat+ , psb_dir = dir })+ -- invariant: no free vars here when it's a FunBind+ = do { pattern_synonym_ok <- xoptM LangExt.PatternSynonyms+ ; unless pattern_synonym_ok (addErr patternSynonymErr)+ ; let sig_tvs = sig_fn name++ ; ((pat', details'), fvs1) <- bindSigTyVarsFV sig_tvs $+ rnPat PatSyn pat $ \pat' ->+ -- We check the 'RdrName's instead of the 'Name's+ -- so that the binding locations are reported+ -- from the left-hand side+ case details of+ PrefixPatSyn vars ->+ do { checkDupRdrNames vars+ ; names <- mapM lookupVar vars+ ; return ( (pat', PrefixPatSyn names)+ , mkFVs (map unLoc names)) }+ InfixPatSyn var1 var2 ->+ do { checkDupRdrNames [var1, var2]+ ; name1 <- lookupVar var1+ ; name2 <- lookupVar var2+ -- ; checkPrecMatch -- TODO+ ; return ( (pat', InfixPatSyn name1 name2)+ , mkFVs (map unLoc [name1, name2])) }+ RecordPatSyn vars ->+ do { checkDupRdrNames (map recordPatSynSelectorId vars)+ ; let rnRecordPatSynField+ (RecordPatSynField { recordPatSynSelectorId = visible+ , recordPatSynPatVar = hidden })+ = do { visible' <- lookupLocatedTopBndrRn visible+ ; hidden' <- lookupVar hidden+ ; return $ RecordPatSynField { recordPatSynSelectorId = visible'+ , recordPatSynPatVar = hidden' } }+ ; names <- mapM rnRecordPatSynField vars+ ; return ( (pat', RecordPatSyn names)+ , mkFVs (map (unLoc . recordPatSynPatVar) names)) }++ ; (dir', fvs2) <- case dir of+ Unidirectional -> return (Unidirectional, emptyFVs)+ ImplicitBidirectional -> return (ImplicitBidirectional, emptyFVs)+ ExplicitBidirectional mg ->+ do { (mg', fvs) <- bindSigTyVarsFV sig_tvs $+ rnMatchGroup (mkPrefixFunRhs (L l name))+ rnLExpr mg+ ; return (ExplicitBidirectional mg', fvs) }++ ; mod <- getModule+ ; let fvs = fvs1 `plusFV` fvs2+ fvs' = filterNameSet (nameIsLocalOrFrom mod) fvs+ -- Keep locally-defined Names+ -- As well as dependency analysis, we need these for the+ -- MonoLocalBinds test in TcBinds.decideGeneralisationPlan++ bind' = bind{ psb_args = details'+ , psb_def = pat'+ , psb_dir = dir'+ , psb_fvs = fvs' }+ selector_names = case details' of+ RecordPatSyn names ->+ map (unLoc . recordPatSynSelectorId) names+ _ -> []++ ; fvs' `seq` -- See Note [Free-variable space leak]+ return (bind', name : selector_names , fvs1)+ -- Why fvs1? See Note [Pattern synonym builders don't yield dependencies]+ }+ where+ lookupVar = wrapLocM lookupOccRn++ patternSynonymErr :: SDoc+ patternSynonymErr+ = hang (text "Illegal pattern synonym declaration")+ 2 (text "Use -XPatternSynonyms to enable this extension")++{-+Note [Pattern synonym builders don't yield dependencies]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When renaming a pattern synonym that has an explicit builder,+references in the builder definition should not be used when+calculating dependencies. For example, consider the following pattern+synonym definition:++pattern P x <- C1 x where+ P x = f (C1 x)++f (P x) = C2 x++In this case, 'P' needs to be typechecked in two passes:++1. Typecheck the pattern definition of 'P', which fully determines the+ type of 'P'. This step doesn't require knowing anything about 'f',+ since the builder definition is not looked at.++2. Typecheck the builder definition, which needs the typechecked+ definition of 'f' to be in scope; done by calls oo tcPatSynBuilderBind+ in TcBinds.tcValBinds.++This behaviour is implemented in 'tcValBinds', but it crucially+depends on 'P' not being put in a recursive group with 'f' (which+would make it look like a recursive pattern synonym a la 'pattern P =+P' which is unsound and rejected).++So:+ * We do not include builder fvs in the Uses returned by rnPatSynBind+ (which is then used for dependency analysis)+ * But we /do/ include them in the psb_fvs for the PatSynBind+ * In rnValBinds we record these builder uses, to avoid bogus+ unused-variable warnings (Trac #12548)+-}++{- *********************************************************************+* *+ Class/instance method bindings+* *+********************************************************************* -}++{- @rnMethodBinds@ is used for the method bindings of a class and an instance+declaration. Like @rnBinds@ but without dependency analysis.++NOTA BENE: we record each {\em binder} of a method-bind group as a free variable.+That's crucial when dealing with an instance decl:+\begin{verbatim}+ instance Foo (T a) where+ op x = ...+\end{verbatim}+This might be the {\em sole} occurrence of @op@ for an imported class @Foo@,+and unless @op@ occurs we won't treat the type signature of @op@ in the class+decl for @Foo@ as a source of instance-decl gates. But we should! Indeed,+in many ways the @op@ in an instance decl is just like an occurrence, not+a binder.+-}++rnMethodBinds :: Bool -- True <=> is a class declaration+ -> Name -- Class name+ -> [Name] -- Type variables from the class/instance header+ -> LHsBinds RdrName -- Binds+ -> [LSig RdrName] -- and signatures/pragmas+ -> RnM (LHsBinds Name, [LSig Name], FreeVars)+-- Used for+-- * the default method bindings in a class decl+-- * the method bindings in an instance decl+rnMethodBinds is_cls_decl cls ktv_names binds sigs+ = do { checkDupRdrNames (collectMethodBinders binds)+ -- Check that the same method is not given twice in the+ -- same instance decl instance C T where+ -- f x = ...+ -- g y = ...+ -- f x = ...+ -- We must use checkDupRdrNames because the Name of the+ -- method is the Name of the class selector, whose SrcSpan+ -- points to the class declaration; and we use rnMethodBinds+ -- for instance decls too++ -- Rename the bindings LHSs+ ; binds' <- foldrBagM (rnMethodBindLHS is_cls_decl cls) emptyBag binds++ -- Rename the pragmas and signatures+ -- Annoyingly the type variables /are/ in scope for signatures, but+ -- /are not/ in scope in the SPECIALISE instance pramas; e.g.+ -- instance Eq a => Eq (T a) where+ -- (==) :: a -> a -> a+ -- {-# SPECIALISE instance Eq a => Eq (T [a]) #-}+ ; let (spec_inst_prags, other_sigs) = partition isSpecInstLSig sigs+ bound_nms = mkNameSet (collectHsBindsBinders binds')+ sig_ctxt | is_cls_decl = ClsDeclCtxt cls+ | otherwise = InstDeclCtxt bound_nms+ ; (spec_inst_prags', sip_fvs) <- renameSigs sig_ctxt spec_inst_prags+ ; (other_sigs', sig_fvs) <- extendTyVarEnvFVRn ktv_names $+ renameSigs sig_ctxt other_sigs++ -- Rename the bindings RHSs. Again there's an issue about whether the+ -- type variables from the class/instance head are in scope.+ -- Answer no in Haskell 2010, but yes if you have -XScopedTypeVariables+ ; scoped_tvs <- xoptM LangExt.ScopedTypeVariables+ ; (binds'', bind_fvs) <- maybe_extend_tyvar_env scoped_tvs $+ do { binds_w_dus <- mapBagM (rnLBind (mkSigTvFn other_sigs')) binds'+ ; let bind_fvs = foldrBag (\(_,_,fv1) fv2 -> fv1 `plusFV` fv2)+ emptyFVs binds_w_dus+ ; return (mapBag fstOf3 binds_w_dus, bind_fvs) }++ ; return ( binds'', spec_inst_prags' ++ other_sigs'+ , sig_fvs `plusFV` sip_fvs `plusFV` bind_fvs) }+ where+ -- For the method bindings in class and instance decls, we extend+ -- the type variable environment iff -XScopedTypeVariables+ maybe_extend_tyvar_env scoped_tvs thing_inside+ | scoped_tvs = extendTyVarEnvFVRn ktv_names thing_inside+ | otherwise = thing_inside++rnMethodBindLHS :: Bool -> Name+ -> LHsBindLR RdrName RdrName+ -> LHsBindsLR Name RdrName+ -> RnM (LHsBindsLR Name RdrName)+rnMethodBindLHS _ cls (L loc bind@(FunBind { fun_id = name })) rest+ = setSrcSpan loc $ do+ do { sel_name <- wrapLocM (lookupInstDeclBndr cls (text "method")) name+ -- We use the selector name as the binder+ ; let bind' = bind { fun_id = sel_name+ , bind_fvs = placeHolderNamesTc }++ ; return (L loc bind' `consBag` rest ) }++-- Report error for all other forms of bindings+-- This is why we use a fold rather than map+rnMethodBindLHS is_cls_decl _ (L loc bind) rest+ = do { addErrAt loc $+ vcat [ what <+> text "not allowed in" <+> decl_sort+ , nest 2 (ppr bind) ]+ ; return rest }+ where+ decl_sort | is_cls_decl = text "class declaration:"+ | otherwise = text "instance declaration:"+ what = case bind of+ PatBind {} -> text "Pattern bindings (except simple variables)"+ PatSynBind {} -> text "Pattern synonyms"+ -- Associated pattern synonyms are not implemented yet+ _ -> pprPanic "rnMethodBind" (ppr bind)++{-+************************************************************************+* *+\subsubsection[dep-Sigs]{Signatures (and user-pragmas for values)}+* *+************************************************************************++@renameSigs@ checks for:+\begin{enumerate}+\item more than one sig for one thing;+\item signatures given for things not bound here;+\end{enumerate}++At the moment we don't gather free-var info from the types in+signatures. We'd only need this if we wanted to report unused tyvars.+-}++renameSigs :: HsSigCtxt+ -> [LSig RdrName]+ -> RnM ([LSig Name], FreeVars)+-- Renames the signatures and performs error checks+renameSigs ctxt sigs+ = do { mapM_ dupSigDeclErr (findDupSigs sigs)++ ; checkDupMinimalSigs sigs++ ; (sigs', sig_fvs) <- mapFvRn (wrapLocFstM (renameSig ctxt)) sigs++ ; let (good_sigs, bad_sigs) = partition (okHsSig ctxt) sigs'+ ; mapM_ misplacedSigErr bad_sigs -- Misplaced++ ; return (good_sigs, sig_fvs) }++----------------------+-- We use lookupSigOccRn in the signatures, which is a little bit unsatisfactory+-- because this won't work for:+-- instance Foo T where+-- {-# INLINE op #-}+-- Baz.op = ...+-- We'll just rename the INLINE prag to refer to whatever other 'op'+-- is in scope. (I'm assuming that Baz.op isn't in scope unqualified.)+-- Doesn't seem worth much trouble to sort this.++renameSig :: HsSigCtxt -> Sig RdrName -> RnM (Sig Name, FreeVars)+-- FixitySig is renamed elsewhere.+renameSig _ (IdSig x)+ = return (IdSig x, emptyFVs) -- Actually this never occurs++renameSig ctxt sig@(TypeSig vs ty)+ = do { new_vs <- mapM (lookupSigOccRn ctxt sig) vs+ ; let doc = TypeSigCtx (ppr_sig_bndrs vs)+ ; (new_ty, fvs) <- rnHsSigWcType doc ty+ ; return (TypeSig new_vs new_ty, fvs) }++renameSig ctxt sig@(ClassOpSig is_deflt vs ty)+ = do { defaultSigs_on <- xoptM LangExt.DefaultSignatures+ ; when (is_deflt && not defaultSigs_on) $+ addErr (defaultSigErr sig)+ ; new_v <- mapM (lookupSigOccRn ctxt sig) vs+ ; (new_ty, fvs) <- rnHsSigType ty_ctxt ty+ ; return (ClassOpSig is_deflt new_v new_ty, fvs) }+ where+ (v1:_) = vs+ ty_ctxt = GenericCtx (text "a class method signature for"+ <+> quotes (ppr v1))++renameSig _ (SpecInstSig src ty)+ = do { (new_ty, fvs) <- rnHsSigType SpecInstSigCtx ty+ ; return (SpecInstSig src new_ty,fvs) }++-- {-# SPECIALISE #-} pragmas can refer to imported Ids+-- so, in the top-level case (when mb_names is Nothing)+-- we use lookupOccRn. If there's both an imported and a local 'f'+-- then the SPECIALISE pragma is ambiguous, unlike all other signatures+renameSig ctxt sig@(SpecSig v tys inl)+ = do { new_v <- case ctxt of+ TopSigCtxt {} -> lookupLocatedOccRn v+ _ -> lookupSigOccRn ctxt sig v+ ; (new_ty, fvs) <- foldM do_one ([],emptyFVs) tys+ ; return (SpecSig new_v new_ty inl, fvs) }+ where+ ty_ctxt = GenericCtx (text "a SPECIALISE signature for"+ <+> quotes (ppr v))+ do_one (tys,fvs) ty+ = do { (new_ty, fvs_ty) <- rnHsSigType ty_ctxt ty+ ; return ( new_ty:tys, fvs_ty `plusFV` fvs) }++renameSig ctxt sig@(InlineSig v s)+ = do { new_v <- lookupSigOccRn ctxt sig v+ ; return (InlineSig new_v s, emptyFVs) }++renameSig ctxt sig@(FixSig (FixitySig vs f))+ = do { new_vs <- mapM (lookupSigOccRn ctxt sig) vs+ ; return (FixSig (FixitySig new_vs f), emptyFVs) }++renameSig ctxt sig@(MinimalSig s (L l bf))+ = do new_bf <- traverse (lookupSigOccRn ctxt sig) bf+ return (MinimalSig s (L l new_bf), emptyFVs)++renameSig ctxt sig@(PatSynSig vs ty)+ = do { new_vs <- mapM (lookupSigOccRn ctxt sig) vs+ ; (ty', fvs) <- rnHsSigType ty_ctxt ty+ ; return (PatSynSig new_vs ty', fvs) }+ where+ ty_ctxt = GenericCtx (text "a pattern synonym signature for"+ <+> ppr_sig_bndrs vs)++renameSig ctxt sig@(SCCFunSig st v s)+ = do { new_v <- lookupSigOccRn ctxt sig v+ ; return (SCCFunSig st new_v s, emptyFVs) }++-- COMPLETE Sigs can refer to imported IDs which is why we use+-- lookupLocatedOccRn rather than lookupSigOccRn+renameSig _ctxt sig@(CompleteMatchSig s (L l bf) mty)+ = do new_bf <- traverse lookupLocatedOccRn bf+ new_mty <- traverse lookupLocatedOccRn mty++ this_mod <- fmap tcg_mod getGblEnv+ unless (any (nameIsLocalOrFrom this_mod . unLoc) new_bf) $ do+ -- Why 'any'? See Note [Orphan COMPLETE pragmas]+ addErrCtxt (text "In" <+> ppr sig) $ failWithTc orphanError++ return (CompleteMatchSig s (L l new_bf) new_mty, emptyFVs)+ where+ orphanError :: SDoc+ orphanError =+ text "Orphan COMPLETE pragmas not supported" $$+ text "A COMPLETE pragma must mention at least one data constructor" $$+ text "or pattern synonym defined in the same module."++{-+Note [Orphan COMPLETE pragmas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We define a COMPLETE pragma to be a non-orphan if it includes at least+one conlike defined in the current module. Why is this sufficient?+Well if you have a pattern match++ case expr of+ P1 -> ...+ P2 -> ...+ P3 -> ...++any COMPLETE pragma which mentions a conlike other than P1, P2 or P3+will not be of any use in verifying that the pattern match is+exhaustive. So as we have certainly read the interface files that+define P1, P2 and P3, we will have loaded all non-orphan COMPLETE+pragmas that could be relevant to this pattern match.++For now we simply disallow orphan COMPLETE pragmas, as the added+complexity of supporting them properly doesn't seem worthwhile.+-}++ppr_sig_bndrs :: [Located RdrName] -> SDoc+ppr_sig_bndrs bs = quotes (pprWithCommas ppr bs)++okHsSig :: HsSigCtxt -> LSig a -> Bool+okHsSig ctxt (L _ sig)+ = case (sig, ctxt) of+ (ClassOpSig {}, ClsDeclCtxt {}) -> True+ (ClassOpSig {}, InstDeclCtxt {}) -> True+ (ClassOpSig {}, _) -> False++ (TypeSig {}, ClsDeclCtxt {}) -> False+ (TypeSig {}, InstDeclCtxt {}) -> False+ (TypeSig {}, _) -> True++ (PatSynSig {}, TopSigCtxt{}) -> True+ (PatSynSig {}, _) -> False++ (FixSig {}, InstDeclCtxt {}) -> False+ (FixSig {}, _) -> True++ (IdSig {}, TopSigCtxt {}) -> True+ (IdSig {}, InstDeclCtxt {}) -> True+ (IdSig {}, _) -> False++ (InlineSig {}, HsBootCtxt {}) -> False+ (InlineSig {}, _) -> True++ (SpecSig {}, TopSigCtxt {}) -> True+ (SpecSig {}, LocalBindCtxt {}) -> True+ (SpecSig {}, InstDeclCtxt {}) -> True+ (SpecSig {}, _) -> False++ (SpecInstSig {}, InstDeclCtxt {}) -> True+ (SpecInstSig {}, _) -> False++ (MinimalSig {}, ClsDeclCtxt {}) -> True+ (MinimalSig {}, _) -> False++ (SCCFunSig {}, HsBootCtxt {}) -> False+ (SCCFunSig {}, _) -> True++ (CompleteMatchSig {}, TopSigCtxt {} ) -> True+ (CompleteMatchSig {}, _) -> False++-------------------+findDupSigs :: [LSig RdrName] -> [[(Located RdrName, Sig RdrName)]]+-- Check for duplicates on RdrName version,+-- because renamed version has unboundName for+-- not-in-scope binders, which gives bogus dup-sig errors+-- NB: in a class decl, a 'generic' sig is not considered+-- equal to an ordinary sig, so we allow, say+-- class C a where+-- op :: a -> a+-- default op :: Eq a => a -> a+findDupSigs sigs+ = findDupsEq matching_sig (concatMap (expand_sig . unLoc) sigs)+ where+ expand_sig sig@(FixSig (FixitySig ns _)) = zip ns (repeat sig)+ expand_sig sig@(InlineSig n _) = [(n,sig)]+ expand_sig sig@(TypeSig ns _) = [(n,sig) | n <- ns]+ expand_sig sig@(ClassOpSig _ ns _) = [(n,sig) | n <- ns]+ expand_sig sig@(PatSynSig ns _ ) = [(n,sig) | n <- ns]+ expand_sig sig@(SCCFunSig _ n _) = [(n,sig)]+ expand_sig _ = []++ matching_sig (L _ n1,sig1) (L _ n2,sig2) = n1 == n2 && mtch sig1 sig2+ mtch (FixSig {}) (FixSig {}) = True+ mtch (InlineSig {}) (InlineSig {}) = True+ mtch (TypeSig {}) (TypeSig {}) = True+ mtch (ClassOpSig d1 _ _) (ClassOpSig d2 _ _) = d1 == d2+ mtch (PatSynSig _ _) (PatSynSig _ _) = True+ mtch (SCCFunSig{}) (SCCFunSig{}) = True+ mtch _ _ = False++-- Warn about multiple MINIMAL signatures+checkDupMinimalSigs :: [LSig RdrName] -> RnM ()+checkDupMinimalSigs sigs+ = case filter isMinimalLSig sigs of+ minSigs@(_:_:_) -> dupMinimalSigErr minSigs+ _ -> return ()++{-+************************************************************************+* *+\subsection{Match}+* *+************************************************************************+-}++rnMatchGroup :: Outputable (body RdrName) => HsMatchContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> MatchGroup RdrName (Located (body RdrName))+ -> RnM (MatchGroup Name (Located (body Name)), FreeVars)+rnMatchGroup ctxt rnBody (MG { mg_alts = L _ ms, mg_origin = origin })+ = do { empty_case_ok <- xoptM LangExt.EmptyCase+ ; when (null ms && not empty_case_ok) (addErr (emptyCaseErr ctxt))+ ; (new_ms, ms_fvs) <- mapFvRn (rnMatch ctxt rnBody) ms+ ; return (mkMatchGroup origin new_ms, ms_fvs) }++rnMatch :: Outputable (body RdrName) => HsMatchContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> LMatch RdrName (Located (body RdrName))+ -> RnM (LMatch Name (Located (body Name)), FreeVars)+rnMatch ctxt rnBody = wrapLocFstM (rnMatch' ctxt rnBody)++rnMatch' :: Outputable (body RdrName) => HsMatchContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> Match RdrName (Located (body RdrName))+ -> RnM (Match Name (Located (body Name)), FreeVars)+rnMatch' ctxt rnBody match@(Match { m_ctxt = mf, m_pats = pats+ , m_type = maybe_rhs_sig, m_grhss = grhss })+ = do { -- Result type signatures are no longer supported+ case maybe_rhs_sig of+ Nothing -> return ()+ Just (L loc ty) -> addErrAt loc (resSigErr match ty)++ ; let fixity = if isInfixMatch match then Infix else Prefix+ -- Now the main event+ -- Note that there are no local fixity decls for matches+ ; rnPats ctxt pats $ \ pats' -> do+ { (grhss', grhss_fvs) <- rnGRHSs ctxt rnBody grhss+ ; let mf' = case (ctxt,mf) of+ (FunRhs (L _ funid) _ _,FunRhs (L lf _) _ strict)+ -> FunRhs (L lf funid) fixity strict+ _ -> ctxt+ ; return (Match { m_ctxt = mf', m_pats = pats'+ , m_type = Nothing, m_grhss = grhss'}, grhss_fvs ) }}++emptyCaseErr :: HsMatchContext Name -> SDoc+emptyCaseErr ctxt = hang (text "Empty list of alternatives in" <+> pp_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+++resSigErr :: Outputable body+ => Match RdrName body -> HsType RdrName -> SDoc+resSigErr match ty+ = vcat [ text "Illegal result type signature" <+> quotes (ppr ty)+ , nest 2 $ ptext (sLit+ "Result signatures are no longer supported in pattern matches")+ , pprMatchInCtxt match ]++{-+************************************************************************+* *+\subsubsection{Guarded right-hand sides (GRHSs)}+* *+************************************************************************+-}++rnGRHSs :: HsMatchContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> GRHSs RdrName (Located (body RdrName))+ -> RnM (GRHSs Name (Located (body Name)), FreeVars)+rnGRHSs ctxt rnBody (GRHSs grhss (L l binds))+ = rnLocalBindsAndThen binds $ \ binds' _ -> do+ (grhss', fvGRHSs) <- mapFvRn (rnGRHS ctxt rnBody) grhss+ return (GRHSs grhss' (L l binds'), fvGRHSs)++rnGRHS :: HsMatchContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> LGRHS RdrName (Located (body RdrName))+ -> RnM (LGRHS Name (Located (body Name)), FreeVars)+rnGRHS ctxt rnBody = wrapLocFstM (rnGRHS' ctxt rnBody)++rnGRHS' :: HsMatchContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> GRHS RdrName (Located (body RdrName))+ -> RnM (GRHS Name (Located (body Name)), FreeVars)+rnGRHS' ctxt rnBody (GRHS guards rhs)+ = do { pattern_guards_allowed <- xoptM LangExt.PatternGuards+ ; ((guards', rhs'), fvs) <- rnStmts (PatGuard ctxt) rnLExpr guards $ \ _ ->+ rnBody rhs++ ; unless (pattern_guards_allowed || is_standard_guard guards')+ (addWarn NoReason (nonStdGuardErr guards'))++ ; return (GRHS guards' rhs', fvs) }+ where+ -- Standard Haskell 1.4 guards are just a single boolean+ -- expression, rather than a list of qualifiers as in the+ -- Glasgow extension+ is_standard_guard [] = True+ is_standard_guard [L _ (BodyStmt _ _ _ _)] = True+ is_standard_guard _ = False++{-+************************************************************************+* *+\subsection{Error messages}+* *+************************************************************************+-}++dupSigDeclErr :: [(Located RdrName, Sig RdrName)] -> RnM ()+dupSigDeclErr pairs@((L loc name, sig) : _)+ = addErrAt loc $+ vcat [ text "Duplicate" <+> what_it_is+ <> text "s for" <+> quotes (ppr name)+ , text "at" <+> vcat (map ppr $ sort $ map (getLoc . fst) pairs) ]+ where+ what_it_is = hsSigDoc sig++dupSigDeclErr [] = panic "dupSigDeclErr"++misplacedSigErr :: LSig Name -> RnM ()+misplacedSigErr (L loc sig)+ = addErrAt loc $+ sep [text "Misplaced" <+> hsSigDoc sig <> colon, ppr sig]++defaultSigErr :: Sig RdrName -> SDoc+defaultSigErr sig = vcat [ hang (text "Unexpected default signature:")+ 2 (ppr sig)+ , text "Use DefaultSignatures to enable default signatures" ]++bindsInHsBootFile :: LHsBindsLR Name RdrName -> SDoc+bindsInHsBootFile mbinds+ = hang (text "Bindings in hs-boot files are not allowed")+ 2 (ppr mbinds)++nonStdGuardErr :: Outputable body => [LStmtLR Name Name body] -> SDoc+nonStdGuardErr guards+ = hang (text "accepting non-standard pattern guards (use PatternGuards to suppress this message)")+ 4 (interpp'SP guards)++unusedPatBindWarn :: HsBind Name -> SDoc+unusedPatBindWarn bind+ = hang (text "This pattern-binding binds no variables:")+ 2 (ppr bind)++dupMinimalSigErr :: [LSig RdrName] -> RnM ()+dupMinimalSigErr sigs@(L loc _ : _)+ = addErrAt loc $+ vcat [ text "Multiple minimal complete definitions"+ , text "at" <+> vcat (map ppr $ sort $ map getLoc sigs)+ , text "Combine alternative minimal complete definitions with `|'" ]+dupMinimalSigErr [] = panic "dupMinimalSigErr"
+ rename/RnEnv.hs view
@@ -0,0 +1,2350 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-2006++\section[RnEnv]{Environment manipulation for the renamer monad}+-}++{-# LANGUAGE CPP, MultiWayIf #-}++module RnEnv (+ newTopSrcBinder,+ lookupLocatedTopBndrRn, lookupTopBndrRn,+ lookupLocatedOccRn, lookupOccRn, lookupOccRn_maybe,+ lookupLocalOccRn_maybe, lookupInfoOccRn,+ lookupLocalOccThLvl_maybe,+ lookupTypeOccRn, lookupKindOccRn,+ lookupGlobalOccRn, lookupGlobalOccRn_maybe,+ lookupOccRn_overloaded, lookupGlobalOccRn_overloaded, lookupExactOcc,+ reportUnboundName, unknownNameSuggestions,+ addNameClashErrRn,++ HsSigCtxt(..), lookupLocalTcNames, lookupSigOccRn,+ lookupSigCtxtOccRn,++ lookupFixityRn, lookupFixityRn_help,+ lookupFieldFixityRn, lookupTyFixityRn,+ lookupInstDeclBndr, lookupRecFieldOcc, lookupFamInstName,+ lookupConstructorFields,+ lookupSyntaxName, lookupSyntaxName', lookupSyntaxNames,+ lookupIfThenElse,+ lookupGreAvailRn,+ getLookupOccRn,mkUnboundName, mkUnboundNameRdr, isUnboundName,+ addUsedGRE, addUsedGREs, addUsedDataCons,++ newLocalBndrRn, newLocalBndrsRn,+ bindLocalNames, bindLocalNamesFV,+ MiniFixityEnv,+ addLocalFixities,+ bindLocatedLocalsFV, bindLocatedLocalsRn,+ extendTyVarEnvFVRn,++ -- Role annotations+ RoleAnnotEnv, emptyRoleAnnotEnv, mkRoleAnnotEnv,+ lookupRoleAnnot, getRoleAnnots,++ checkDupRdrNames, checkShadowedRdrNames,+ checkDupNames, checkDupAndShadowedNames, dupNamesErr,+ checkTupSize,+ addFvRn, mapFvRn, mapMaybeFvRn, mapFvRnCPS,+ warnUnusedMatches, warnUnusedTypePatterns,+ warnUnusedTopBinds, warnUnusedLocalBinds,+ mkFieldEnv,+ dataTcOccs, kindSigErr, perhapsForallMsg, unknownSubordinateErr,+ HsDocContext(..), pprHsDocContext,+ inHsDocContext, withHsDocContext+ ) where++#include "HsVersions.h"++import LoadIface ( loadInterfaceForName, loadSrcInterface_maybe )+import IfaceEnv+import HsSyn+import RdrName+import HscTypes+import TcEnv+import TcRnMonad+import RdrHsSyn ( setRdrNameSpace )+import TysWiredIn ( starKindTyConName, unicodeStarKindTyConName )+import Name+import NameSet+import NameEnv+import Avail+import Module+import ConLike+import DataCon+import TyCon+import PrelNames ( mkUnboundName, isUnboundName, rOOT_MAIN, forall_tv_RDR )+import ErrUtils ( MsgDoc )+import BasicTypes ( Fixity(..), FixityDirection(..), minPrecedence,+ defaultFixity, pprWarningTxtForMsg, SourceText(..) )+import SrcLoc+import Outputable+import Util+import Maybes+import BasicTypes ( TopLevelFlag(..) )+import ListSetOps ( removeDups )+import DynFlags+import FastString+import Control.Monad+import Data.List+import Data.Function ( on )+import ListSetOps ( minusList )+import Constants ( mAX_TUPLE_SIZE )+import qualified GHC.LanguageExtensions as LangExt+import Data.Maybe (isJust)++{-+*********************************************************+* *+ Source-code binders+* *+*********************************************************++Note [Signature lazy interface loading]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++GHC's lazy interface loading can be a bit confusing, so this Note is an+empirical description of what happens in one interesting case. When+compiling a signature module against an its implementation, we do NOT+load interface files associated with its names until after the type+checking phase. For example:++ module ASig where+ data T+ f :: T -> T++Suppose we compile this with -sig-of "A is ASig":++ module B where+ data T = T+ f T = T++ module A(module B) where+ import B++During type checking, we'll load A.hi because we need to know what the+RdrEnv for the module is, but we DO NOT load the interface for B.hi!+It's wholly unnecessary: our local definition 'data T' in ASig is all+the information we need to finish type checking. This is contrast to+type checking of ordinary Haskell files, in which we would not have the+local definition "data T" and would need to consult B.hi immediately.+(Also, this situation never occurs for hs-boot files, since you're not+allowed to reexport from another module.)++After type checking, we then check that the types we provided are+consistent with the backing implementation (in checkHiBootOrHsigIface).+At this point, B.hi is loaded, because we need something to compare+against.++I discovered this behavior when trying to figure out why type class+instances for Data.Map weren't in the EPS when I was type checking a+test very much like ASig (sigof02dm): the associated interface hadn't+been loaded yet! (The larger issue is a moot point, since an instance+declared in a signature can never be a duplicate.)++This behavior might change in the future. Consider this+alternate module B:++ module B where+ {-# DEPRECATED T, f "Don't use" #-}+ data T = T+ f T = T++One might conceivably want to report deprecation warnings when compiling+ASig with -sig-of B, in which case we need to look at B.hi to find the+deprecation warnings during renaming. At the moment, you don't get any+warning until you use the identifier further downstream. This would+require adjusting addUsedGRE so that during signature compilation,+we do not report deprecation warnings for LocalDef. See also+Note [Handling of deprecations]+-}++newTopSrcBinder :: Located RdrName -> RnM Name+newTopSrcBinder (L loc rdr_name)+ | Just name <- isExact_maybe rdr_name+ = -- This is here to catch+ -- (a) Exact-name binders created by Template Haskell+ -- (b) The PrelBase defn of (say) [] and similar, for which+ -- the parser reads the special syntax and returns an Exact RdrName+ -- We are at a binding site for the name, so check first that it+ -- the current module is the correct one; otherwise GHC can get+ -- very confused indeed. This test rejects code like+ -- data T = (,) Int Int+ -- unless we are in GHC.Tup+ if isExternalName name then+ do { this_mod <- getModule+ ; unless (this_mod == nameModule name)+ (addErrAt loc (badOrigBinding rdr_name))+ ; return name }+ else -- See Note [Binders in Template Haskell] in Convert.hs+ do { this_mod <- getModule+ ; externaliseName this_mod name }++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ = do { this_mod <- getModule+ ; unless (rdr_mod == this_mod || rdr_mod == rOOT_MAIN)+ (addErrAt loc (badOrigBinding rdr_name))+ -- When reading External Core we get Orig names as binders,+ -- but they should agree with the module gotten from the monad+ --+ -- We can get built-in syntax showing up here too, sadly. If you type+ -- data T = (,,,)+ -- the constructor is parsed as a type, and then RdrHsSyn.tyConToDataCon+ -- uses setRdrNameSpace to make it into a data constructors. At that point+ -- the nice Exact name for the TyCon gets swizzled to an Orig name.+ -- Hence the badOrigBinding error message.+ --+ -- Except for the ":Main.main = ..." definition inserted into+ -- the Main module; ugh!++ -- Because of this latter case, we call newGlobalBinder with a module from+ -- the RdrName, not from the environment. In principle, it'd be fine to+ -- have an arbitrary mixture of external core definitions in a single module,+ -- (apart from module-initialisation issues, perhaps).+ ; newGlobalBinder rdr_mod rdr_occ loc }++ | otherwise+ = do { unless (not (isQual rdr_name))+ (addErrAt loc (badQualBndrErr rdr_name))+ -- Binders should not be qualified; if they are, and with a different+ -- module name, we we get a confusing "M.T is not in scope" error later++ ; stage <- getStage+ ; if isBrackStage stage then+ -- We are inside a TH bracket, so make an *Internal* name+ -- See Note [Top-level Names in Template Haskell decl quotes] in RnNames+ do { uniq <- newUnique+ ; return (mkInternalName uniq (rdrNameOcc rdr_name) loc) }+ else+ do { this_mod <- getModule+ ; traceRn "newTopSrcBinder" (ppr this_mod $$ ppr rdr_name $$ ppr loc)+ ; newGlobalBinder this_mod (rdrNameOcc rdr_name) loc }+ }++{-+*********************************************************+* *+ Source code occurrences+* *+*********************************************************++Looking up a name in the RnEnv.++Note [Type and class operator definitions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to reject all of these unless we have -XTypeOperators (Trac #3265)+ data a :*: b = ...+ class a :*: b where ...+ data (:*:) a b = ....+ class (:*:) a b where ...+The latter two mean that we are not just looking for a+*syntactically-infix* declaration, but one that uses an operator+OccName. We use OccName.isSymOcc to detect that case, which isn't+terribly efficient, but there seems to be no better way.+-}++lookupTopBndrRn :: RdrName -> RnM Name+lookupTopBndrRn n = do nopt <- lookupTopBndrRn_maybe n+ case nopt of+ Just n' -> return n'+ Nothing -> do traceRn "lookupTopBndrRn fail" (ppr n)+ unboundName WL_LocalTop n++lookupLocatedTopBndrRn :: Located RdrName -> RnM (Located Name)+lookupLocatedTopBndrRn = wrapLocM lookupTopBndrRn++lookupTopBndrRn_maybe :: RdrName -> RnM (Maybe Name)+-- Look up a top-level source-code binder. We may be looking up an unqualified 'f',+-- and there may be several imported 'f's too, which must not confuse us.+-- For example, this is OK:+-- import Foo( f )+-- infix 9 f -- The 'f' here does not need to be qualified+-- f x = x -- Nor here, of course+-- So we have to filter out the non-local ones.+--+-- A separate function (importsFromLocalDecls) reports duplicate top level+-- decls, so here it's safe just to choose an arbitrary one.+--+-- There should never be a qualified name in a binding position in Haskell,+-- but there can be if we have read in an external-Core file.+-- The Haskell parser checks for the illegal qualified name in Haskell+-- source files, so we don't need to do so here.++lookupTopBndrRn_maybe rdr_name+ | Just name <- isExact_maybe rdr_name+ = do { name' <- lookupExactOcc name; return (Just name') }++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ -- This deals with the case of derived bindings, where+ -- we don't bother to call newTopSrcBinder first+ -- We assume there is no "parent" name+ = do { loc <- getSrcSpanM+ ; n <- newGlobalBinder rdr_mod rdr_occ loc+ ; return (Just n)}++ | otherwise+ = do { -- Check for operators in type or class declarations+ -- See Note [Type and class operator definitions]+ let occ = rdrNameOcc rdr_name+ ; when (isTcOcc occ && isSymOcc occ)+ (do { op_ok <- xoptM LangExt.TypeOperators+ ; unless op_ok (addErr (opDeclErr rdr_name)) })++ ; env <- getGlobalRdrEnv+ ; case filter isLocalGRE (lookupGRE_RdrName rdr_name env) of+ [gre] -> return (Just (gre_name gre))+ _ -> return Nothing -- Ambiguous (can't happen) or unbound+ }++-----------------------------------------------+-- | Lookup an @Exact@ @RdrName@. See Note [Looking up Exact RdrNames].+-- This adds an error if the name cannot be found.+lookupExactOcc :: Name -> RnM Name+lookupExactOcc name+ = do { result <- lookupExactOcc_either name+ ; case result of+ Left err -> do { addErr err+ ; return name }+ Right name' -> return name' }++-- | Lookup an @Exact@ @RdrName@. See Note [Looking up Exact RdrNames].+-- This never adds an error, but it may return one.+lookupExactOcc_either :: Name -> RnM (Either MsgDoc Name)+-- See Note [Looking up Exact RdrNames]+lookupExactOcc_either name+ | Just thing <- wiredInNameTyThing_maybe name+ , Just tycon <- case thing of+ ATyCon tc -> Just tc+ AConLike (RealDataCon dc) -> Just (dataConTyCon dc)+ _ -> Nothing+ , isTupleTyCon tycon+ = do { checkTupSize (tyConArity tycon)+ ; return (Right name) }++ | isExternalName name+ = return (Right name)++ | otherwise+ = do { env <- getGlobalRdrEnv+ ; let -- See Note [Splicing Exact names]+ main_occ = nameOccName name+ demoted_occs = case demoteOccName main_occ of+ Just occ -> [occ]+ Nothing -> []+ gres = [ gre | occ <- main_occ : demoted_occs+ , gre <- lookupGlobalRdrEnv env occ+ , gre_name gre == name ]+ ; case gres of+ [gre] -> return (Right (gre_name gre))++ [] -> -- See Note [Splicing Exact names]+ do { lcl_env <- getLocalRdrEnv+ ; if name `inLocalRdrEnvScope` lcl_env+ then return (Right name)+ else+ do { th_topnames_var <- fmap tcg_th_topnames getGblEnv+ ; th_topnames <- readTcRef th_topnames_var+ ; if name `elemNameSet` th_topnames+ then return (Right name)+ else return (Left exact_nm_err)+ }+ }+ gres -> return (Left (sameNameErr gres)) -- Ugh! See Note [Template Haskell ambiguity]+ }+ where+ exact_nm_err = hang (text "The exact Name" <+> quotes (ppr name) <+> ptext (sLit "is not in scope"))+ 2 (vcat [ text "Probable cause: you used a unique Template Haskell name (NameU), "+ , text "perhaps via newName, but did not bind it"+ , text "If that's it, then -ddump-splices might be useful" ])++sameNameErr :: [GlobalRdrElt] -> MsgDoc+sameNameErr [] = panic "addSameNameErr: empty list"+sameNameErr gres@(_ : _)+ = hang (text "Same exact name in multiple name-spaces:")+ 2 (vcat (map pp_one sorted_names) $$ th_hint)+ where+ sorted_names = sortWith nameSrcLoc (map gre_name gres)+ pp_one name+ = hang (pprNameSpace (occNameSpace (getOccName name))+ <+> quotes (ppr name) <> comma)+ 2 (text "declared at:" <+> ppr (nameSrcLoc name))++ th_hint = vcat [ text "Probable cause: you bound a unique Template Haskell name (NameU),"+ , text "perhaps via newName, in different name-spaces."+ , text "If that's it, then -ddump-splices might be useful" ]+++-----------------------------------------------+lookupInstDeclBndr :: Name -> SDoc -> RdrName -> RnM Name+-- This is called on the method name on the left-hand side of an+-- instance declaration binding. eg. instance Functor T where+-- fmap = ...+-- ^^^^ called on this+-- Regardless of how many unqualified fmaps are in scope, we want+-- the one that comes from the Functor class.+--+-- Furthermore, note that we take no account of whether the+-- name is only in scope qualified. I.e. even if method op is+-- in scope as M.op, we still allow plain 'op' on the LHS of+-- an instance decl+--+-- The "what" parameter says "method" or "associated type",+-- depending on what we are looking up+lookupInstDeclBndr cls what rdr+ = do { when (isQual rdr)+ (addErr (badQualBndrErr rdr))+ -- In an instance decl you aren't allowed+ -- to use a qualified name for the method+ -- (Although it'd make perfect sense.)+ ; mb_name <- lookupSubBndrOcc+ False -- False => we don't give deprecated+ -- warnings when a deprecated class+ -- method is defined. We only warn+ -- when it's used+ cls doc rdr+ ; case mb_name of+ Left err -> do { addErr err; return (mkUnboundNameRdr rdr) }+ Right nm -> return nm }+ where+ doc = what <+> text "of class" <+> quotes (ppr cls)+++-----------------------------------------------+lookupFamInstName :: Maybe Name -> Located RdrName -> RnM (Located Name)+-- Used for TyData and TySynonym family instances only,+-- See Note [Family instance binders]+lookupFamInstName (Just cls) tc_rdr -- Associated type; c.f RnBinds.rnMethodBind+ = wrapLocM (lookupInstDeclBndr cls (text "associated type")) tc_rdr+lookupFamInstName Nothing tc_rdr -- Family instance; tc_rdr is an *occurrence*+ = lookupLocatedOccRn tc_rdr++-----------------------------------------------+lookupConstructorFields :: Name -> RnM [FieldLabel]+-- Look up the fields of a given constructor+-- * For constructors from this module, use the record field env,+-- which is itself gathered from the (as yet un-typechecked)+-- data type decls+--+-- * For constructors from imported modules, use the *type* environment+-- since imported modles are already compiled, the info is conveniently+-- right there++lookupConstructorFields con_name+ = do { this_mod <- getModule+ ; if nameIsLocalOrFrom this_mod con_name then+ do { field_env <- getRecFieldEnv+ ; traceTc "lookupCF" (ppr con_name $$ ppr (lookupNameEnv field_env con_name) $$ ppr field_env)+ ; return (lookupNameEnv field_env con_name `orElse` []) }+ else+ do { con <- tcLookupConLike con_name+ ; traceTc "lookupCF 2" (ppr con)+ ; return (conLikeFieldLabels con) } }++-----------------------------------------------+-- Used for record construction and pattern matching+-- When the -XDisambiguateRecordFields flag is on, take account of the+-- constructor name to disambiguate which field to use; it's just the+-- same as for instance decls+--+-- NB: Consider this:+-- module Foo where { data R = R { fld :: Int } }+-- module Odd where { import Foo; fld x = x { fld = 3 } }+-- Arguably this should work, because the reference to 'fld' is+-- unambiguous because there is only one field id 'fld' in scope.+-- But currently it's rejected.++lookupRecFieldOcc :: Maybe Name -- Nothing => just look it up as usual+ -- Just tycon => use tycon to disambiguate+ -> SDoc -> RdrName+ -> RnM Name+lookupRecFieldOcc parent doc rdr_name+ | Just tc_name <- parent+ = do { mb_name <- lookupSubBndrOcc True tc_name doc rdr_name+ ; case mb_name of+ Left err -> do { addErr err; return (mkUnboundNameRdr rdr_name) }+ Right n -> return n }++ | otherwise+ = lookupGlobalOccRn rdr_name++lookupSubBndrOcc :: Bool+ -> Name -- Parent+ -> SDoc+ -> RdrName+ -> RnM (Either MsgDoc Name)+-- Find all the things the rdr-name maps to+-- and pick the one with the right parent namep+lookupSubBndrOcc warn_if_deprec the_parent doc rdr_name+ | Just n <- isExact_maybe rdr_name -- This happens in derived code+ = do { n <- lookupExactOcc n+ ; return (Right n) }++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ = do { n <- lookupOrig rdr_mod rdr_occ+ ; return (Right n) }++ | isUnboundName the_parent+ -- Avoid an error cascade from malformed decls:+ -- instance Int where { foo = e }+ -- We have already generated an error in rnLHsInstDecl+ = return (Right (mkUnboundNameRdr rdr_name))++ | otherwise+ = do { env <- getGlobalRdrEnv+ ; let gres = lookupGlobalRdrEnv env (rdrNameOcc rdr_name)+ -- NB: lookupGlobalRdrEnv, not lookupGRE_RdrName!+ -- The latter does pickGREs, but we want to allow 'x'+ -- even if only 'M.x' is in scope+ ; traceRn "lookupSubBndrOcc"+ (vcat [ ppr the_parent, ppr rdr_name+ , ppr gres, ppr (pick_gres rdr_name gres)])+ ; case pick_gres rdr_name gres of+ (gre:_) -> do { addUsedGRE warn_if_deprec gre+ -- Add a usage; this is an *occurrence* site+ -- Note [Usage for sub-bndrs]+ ; return (Right (gre_name gre)) }+ -- If there is more than one local GRE for the+ -- same OccName 'f', that will be reported separately+ -- as a duplicate top-level binding for 'f'+ [] -> do { ns <- lookupQualifiedNameGHCi rdr_name+ ; case ns of+ (n:_) -> return (Right n) -- Unlikely to be more than one...?+ [] -> return (Left (unknownSubordinateErr doc rdr_name))+ } }+ where+ -- If Parent = NoParent, just do a normal lookup+ -- If Parent = Parent p then find all GREs that+ -- (a) have parent p+ -- (b) for Unqual, are in scope qualified or unqualified+ -- for Qual, are in scope with that qualification+ pick_gres rdr_name gres+ | isUnqual rdr_name = filter right_parent gres+ | otherwise = filter right_parent (pickGREs rdr_name gres)++ right_parent (GRE { gre_par = p })+ | ParentIs parent <- p = parent == the_parent+ | FldParent { par_is = parent } <- p = parent == the_parent+ | otherwise = False++{-+Note [Family instance binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data family F a+ data instance F T = X1 | X2++The 'data instance' decl has an *occurrence* of F (and T), and *binds*+X1 and X2. (This is unlike a normal data type declaration which would+bind F too.) So we want an AvailTC F [X1,X2].++Now consider a similar pair:+ class C a where+ data G a+ instance C S where+ data G S = Y1 | Y2++The 'data G S' *binds* Y1 and Y2, and has an *occurrence* of G.++But there is a small complication: in an instance decl, we don't use+qualified names on the LHS; instead we use the class to disambiguate.+Thus:+ module M where+ import Blib( G )+ class C a where+ data G a+ instance C S where+ data G S = Y1 | Y2+Even though there are two G's in scope (M.G and Blib.G), the occurrence+of 'G' in the 'instance C S' decl is unambiguous, because C has only+one associated type called G. This is exactly what happens for methods,+and it is only consistent to do the same thing for types. That's the+role of the function lookupTcdName; the (Maybe Name) give the class of+the encloseing instance decl, if any.++Note [Looking up Exact RdrNames]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Exact RdrNames are generated by Template Haskell. See Note [Binders+in Template Haskell] in Convert.++For data types and classes have Exact system Names in the binding+positions for constructors, TyCons etc. For example+ [d| data T = MkT Int |]+when we splice in and Convert to HsSyn RdrName, we'll get+ data (Exact (system Name "T")) = (Exact (system Name "MkT")) ...+These System names are generated by Convert.thRdrName++But, constructors and the like need External Names, not System Names!+So we do the following++ * In RnEnv.newTopSrcBinder we spot Exact RdrNames that wrap a+ non-External Name, and make an External name for it. This is+ the name that goes in the GlobalRdrEnv++ * When looking up an occurrence of an Exact name, done in+ RnEnv.lookupExactOcc, we find the Name with the right unique in the+ GlobalRdrEnv, and use the one from the envt -- it will be an+ External Name in the case of the data type/constructor above.++ * Exact names are also use for purely local binders generated+ by TH, such as \x_33. x_33+ Both binder and occurrence are Exact RdrNames. The occurrence+ gets looked up in the LocalRdrEnv by RnEnv.lookupOccRn, and+ misses, because lookupLocalRdrEnv always returns Nothing for+ an Exact Name. Now we fall through to lookupExactOcc, which+ will find the Name is not in the GlobalRdrEnv, so we just use+ the Exact supplied Name.++Note [Splicing Exact names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the splice $(do { x <- newName "x"; return (VarE x) })+This will generate a (HsExpr RdrName) term that mentions the+Exact RdrName "x_56" (or whatever), but does not bind it. So+when looking such Exact names we want to check that it's in scope,+otherwise the type checker will get confused. To do this we need to+keep track of all the Names in scope, and the LocalRdrEnv does just that;+we consult it with RdrName.inLocalRdrEnvScope.++There is another wrinkle. With TH and -XDataKinds, consider+ $( [d| data Nat = Zero+ data T = MkT (Proxy 'Zero) |] )+After splicing, but before renaming we get this:+ data Nat_77{tc} = Zero_78{d}+ data T_79{tc} = MkT_80{d} (Proxy 'Zero_78{tc}) |] )+The occurrence of 'Zero in the data type for T has the right unique,+but it has a TcClsName name-space in its OccName. (This is set by+the ctxt_ns argument of Convert.thRdrName.) When we check that is+in scope in the GlobalRdrEnv, we need to look up the DataName namespace+too. (An alternative would be to make the GlobalRdrEnv also have+a Name -> GRE mapping.)++Note [Template Haskell ambiguity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The GlobalRdrEnv invariant says that if+ occ -> [gre1, ..., gren]+then the gres have distinct Names (INVARIANT 1 of GlobalRdrEnv).+This is guaranteed by extendGlobalRdrEnvRn (the dups check in add_gre).++So how can we get multiple gres in lookupExactOcc_maybe? Because in+TH we might use the same TH NameU in two different name spaces.+eg (Trac #7241):+ $(newName "Foo" >>= \o -> return [DataD [] o [] [RecC o []] [''Show]])+Here we generate a type constructor and data constructor with the same+unique, but differnt name spaces.++It'd be nicer to rule this out in extendGlobalRdrEnvRn, but that would+mean looking up the OccName in every name-space, just in case, and that+seems a bit brutal. So it's just done here on lookup. But we might+need to revisit that choice.++Note [Usage for sub-bndrs]+~~~~~~~~~~~~~~~~~~~~~~~~~~+If you have this+ import qualified M( C( f ) )+ instance M.C T where+ f x = x+then is the qualified import M.f used? Obviously yes.+But the RdrName used in the instance decl is unqualified. In effect,+we fill in the qualification by looking for f's whose class is M.C+But when adding to the UsedRdrNames we must make that qualification+explicit (saying "used M.f"), otherwise we get "Redundant import of M.f".++So we make up a suitable (fake) RdrName. But be careful+ import qualified M+ import M( C(f) )+ instance C T where+ f x = x+Here we want to record a use of 'f', not of 'M.f', otherwise+we'll miss the fact that the qualified import is redundant.++--------------------------------------------------+-- Occurrences+--------------------------------------------------+-}++getLookupOccRn :: RnM (Name -> Maybe Name)+getLookupOccRn+ = do local_env <- getLocalRdrEnv+ return (lookupLocalRdrOcc local_env . nameOccName)++mkUnboundNameRdr :: RdrName -> Name+mkUnboundNameRdr rdr = mkUnboundName (rdrNameOcc rdr)++lookupLocatedOccRn :: Located RdrName -> RnM (Located Name)+lookupLocatedOccRn = wrapLocM lookupOccRn++lookupLocalOccRn_maybe :: RdrName -> RnM (Maybe Name)+-- Just look in the local environment+lookupLocalOccRn_maybe rdr_name+ = do { local_env <- getLocalRdrEnv+ ; return (lookupLocalRdrEnv local_env rdr_name) }++lookupLocalOccThLvl_maybe :: Name -> RnM (Maybe (TopLevelFlag, ThLevel))+-- Just look in the local environment+lookupLocalOccThLvl_maybe name+ = do { lcl_env <- getLclEnv+ ; return (lookupNameEnv (tcl_th_bndrs lcl_env) name) }++-- lookupOccRn looks up an occurrence of a RdrName+lookupOccRn :: RdrName -> RnM Name+lookupOccRn rdr_name+ = do { mb_name <- lookupOccRn_maybe rdr_name+ ; case mb_name of+ Just name -> return name+ Nothing -> reportUnboundName rdr_name }++lookupKindOccRn :: RdrName -> RnM Name+-- Looking up a name occurring in a kind+lookupKindOccRn rdr_name+ | isVarOcc (rdrNameOcc rdr_name) -- See Note [Promoted variables in types]+ = badVarInType rdr_name+ | otherwise+ = do { typeintype <- xoptM LangExt.TypeInType+ ; if | typeintype -> lookupTypeOccRn rdr_name+ -- With -XNoTypeInType, treat any usage of * in kinds as in scope+ -- this is a dirty hack, but then again so was the old * kind.+ | is_star rdr_name -> return starKindTyConName+ | is_uni_star rdr_name -> return unicodeStarKindTyConName+ | otherwise -> lookupOccRn rdr_name }++-- lookupPromotedOccRn looks up an optionally promoted RdrName.+lookupTypeOccRn :: RdrName -> RnM Name+-- see Note [Demotion]+lookupTypeOccRn rdr_name+ | isVarOcc (rdrNameOcc rdr_name) -- See Note [Promoted variables in types]+ = badVarInType rdr_name+ | otherwise+ = do { mb_name <- lookupOccRn_maybe rdr_name+ ; case mb_name of {+ Just name -> return name ;+ Nothing -> do { dflags <- getDynFlags+ ; lookup_demoted rdr_name dflags } } }++lookup_demoted :: RdrName -> DynFlags -> RnM Name+lookup_demoted rdr_name dflags+ | Just demoted_rdr <- demoteRdrName rdr_name+ -- Maybe it's the name of a *data* constructor+ = do { data_kinds <- xoptM LangExt.DataKinds+ ; if data_kinds+ then do { mb_demoted_name <- lookupOccRn_maybe demoted_rdr+ ; case mb_demoted_name of+ Nothing -> unboundNameX WL_Any rdr_name star_info+ Just demoted_name ->+ do { whenWOptM Opt_WarnUntickedPromotedConstructors $+ addWarn+ (Reason Opt_WarnUntickedPromotedConstructors)+ (untickedPromConstrWarn demoted_name)+ ; return demoted_name } }+ else do { -- We need to check if a data constructor of this name is+ -- in scope to give good error messages. However, we do+ -- not want to give an additional error if the data+ -- constructor happens to be out of scope! See #13947.+ mb_demoted_name <- discardErrs $+ lookupOccRn_maybe demoted_rdr+ ; let suggestion | isJust mb_demoted_name = suggest_dk+ | otherwise = star_info+ ; unboundNameX WL_Any rdr_name suggestion } }++ | otherwise+ = reportUnboundName rdr_name++ where+ suggest_dk = text "A data constructor of that name is in scope; did you mean DataKinds?"+ untickedPromConstrWarn name =+ text "Unticked promoted constructor" <> colon <+> quotes (ppr name) <> dot+ $$+ hsep [ text "Use"+ , quotes (char '\'' <> ppr name)+ , text "instead of"+ , quotes (ppr name) <> dot ]++ star_info+ | is_star rdr_name || is_uni_star rdr_name+ = if xopt LangExt.TypeInType dflags+ then text "NB: With TypeInType, you must import" <+>+ ppr rdr_name <+> text "from Data.Kind"+ else empty++ | otherwise+ = empty++is_star, is_uni_star :: RdrName -> Bool+is_star = (fsLit "*" ==) . occNameFS . rdrNameOcc+is_uni_star = (fsLit "★" ==) . occNameFS . rdrNameOcc++badVarInType :: RdrName -> RnM Name+badVarInType rdr_name+ = do { addErr (text "Illegal promoted term variable in a type:"+ <+> ppr rdr_name)+ ; return (mkUnboundNameRdr rdr_name) }++{- Note [Promoted variables in types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this (Trac #12686):+ x = True+ data Bad = Bad 'x++The parser treats the quote in 'x as saying "use the term+namespace", so we'll get (Bad x{v}), with 'x' in the+VarName namespace. If we don't test for this, the renamer+will happily rename it to the x bound at top level, and then+the typecheck falls over because it doesn't have 'x' in scope+when kind-checking.++Note [Demotion]+~~~~~~~~~~~~~~~+When the user writes:+ data Nat = Zero | Succ Nat+ foo :: f Zero -> Int++'Zero' in the type signature of 'foo' is parsed as:+ HsTyVar ("Zero", TcClsName)++When the renamer hits this occurrence of 'Zero' it's going to realise+that it's not in scope. But because it is renaming a type, it knows+that 'Zero' might be a promoted data constructor, so it will demote+its namespace to DataName and do a second lookup.++The final result (after the renamer) will be:+ HsTyVar ("Zero", DataName)+-}++-- Use this version to get tracing+--+-- lookupOccRn_maybe, lookupOccRn_maybe' :: RdrName -> RnM (Maybe Name)+-- lookupOccRn_maybe rdr_name+-- = do { mb_res <- lookupOccRn_maybe' rdr_name+-- ; gbl_rdr_env <- getGlobalRdrEnv+-- ; local_rdr_env <- getLocalRdrEnv+-- ; traceRn $ text "lookupOccRn_maybe" <+>+-- vcat [ ppr rdr_name <+> ppr (getUnique (rdrNameOcc rdr_name))+-- , ppr mb_res+-- , text "Lcl env" <+> ppr local_rdr_env+-- , text "Gbl env" <+> ppr [ (getUnique (nameOccName (gre_name (head gres'))),gres') | gres <- occEnvElts gbl_rdr_env+-- , let gres' = filter isLocalGRE gres, not (null gres') ] ]+-- ; return mb_res }++lookupOccRn_maybe :: RdrName -> RnM (Maybe Name)+-- lookupOccRn looks up an occurrence of a RdrName+lookupOccRn_maybe rdr_name+ = do { local_env <- getLocalRdrEnv+ ; case lookupLocalRdrEnv local_env rdr_name of {+ Just name -> return (Just name) ;+ Nothing -> do+ ; lookupGlobalOccRn_maybe rdr_name } }++lookupGlobalOccRn_maybe :: RdrName -> RnM (Maybe Name)+-- Looks up a RdrName occurrence in the top-level+-- environment, including using lookupQualifiedNameGHCi+-- for the GHCi case+-- No filter function; does not report an error on failure+-- Uses addUsedRdrName to record use and deprecations+lookupGlobalOccRn_maybe rdr_name+ | Just n <- isExact_maybe rdr_name -- This happens in derived code+ = do { n' <- lookupExactOcc n; return (Just n') }++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ = do { n <- lookupOrig rdr_mod rdr_occ+ ; return (Just n) }++ | otherwise+ = do { mb_gre <- lookupGreRn_maybe rdr_name+ ; case mb_gre of {+ Just gre -> return (Just (gre_name gre)) ;+ Nothing ->+ do { ns <- lookupQualifiedNameGHCi rdr_name+ -- This test is not expensive,+ -- and only happens for failed lookups+ ; case ns of+ (n:_) -> return (Just n) -- Unlikely to be more than one...?+ [] -> return Nothing } } }++lookupGlobalOccRn :: RdrName -> RnM Name+-- lookupGlobalOccRn is like lookupOccRn, except that it looks in the global+-- environment. Adds an error message if the RdrName is not in scope.+lookupGlobalOccRn rdr_name+ = do { mb_name <- lookupGlobalOccRn_maybe rdr_name+ ; case mb_name of+ Just n -> return n+ Nothing -> do { traceRn "lookupGlobalOccRn" (ppr rdr_name)+ ; unboundName WL_Global rdr_name } }++lookupInfoOccRn :: RdrName -> RnM [Name]+-- lookupInfoOccRn is intended for use in GHCi's ":info" command+-- It finds all the GREs that RdrName could mean, not complaining+-- about ambiguity, but rather returning them all+-- C.f. Trac #9881+lookupInfoOccRn rdr_name+ | Just n <- isExact_maybe rdr_name -- e.g. (->)+ = return [n]++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ = do { n <- lookupOrig rdr_mod rdr_occ+ ; return [n] }++ | otherwise+ = do { rdr_env <- getGlobalRdrEnv+ ; let ns = map gre_name (lookupGRE_RdrName rdr_name rdr_env)+ ; qual_ns <- lookupQualifiedNameGHCi rdr_name+ ; return (ns ++ (qual_ns `minusList` ns)) }++-- | Like 'lookupOccRn_maybe', but with a more informative result if+-- the 'RdrName' happens to be a record selector:+--+-- * Nothing -> name not in scope (no error reported)+-- * Just (Left x) -> name uniquely refers to x,+-- or there is a name clash (reported)+-- * Just (Right xs) -> name refers to one or more record selectors;+-- if overload_ok was False, this list will be+-- a singleton.+lookupOccRn_overloaded :: Bool -> RdrName -> RnM (Maybe (Either Name [FieldOcc Name]))+lookupOccRn_overloaded overload_ok rdr_name+ = do { local_env <- getLocalRdrEnv+ ; case lookupLocalRdrEnv local_env rdr_name of {+ Just name -> return (Just (Left name)) ;+ Nothing -> do+ { mb_name <- lookupGlobalOccRn_overloaded overload_ok rdr_name+ ; case mb_name of {+ Just name -> return (Just name) ;+ Nothing -> do+ { ns <- lookupQualifiedNameGHCi rdr_name+ -- This test is not expensive,+ -- and only happens for failed lookups+ ; case ns of+ (n:_) -> return $ Just $ Left n -- Unlikely to be more than one...?+ [] -> return Nothing } } } } }++lookupGlobalOccRn_overloaded :: Bool -> RdrName -> RnM (Maybe (Either Name [FieldOcc Name]))+lookupGlobalOccRn_overloaded overload_ok rdr_name+ | Just n <- isExact_maybe rdr_name -- This happens in derived code+ = do { n' <- lookupExactOcc n; return (Just (Left n')) }++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ = do { n <- lookupOrig rdr_mod rdr_occ+ ; return (Just (Left n)) }++ | otherwise+ = do { env <- getGlobalRdrEnv+ ; case lookupGRE_RdrName rdr_name env of+ [] -> return Nothing+ [gre] | isRecFldGRE gre+ -> do { addUsedGRE True gre+ ; let+ fld_occ :: FieldOcc Name+ fld_occ+ = FieldOcc (noLoc rdr_name) (gre_name gre)+ ; return (Just (Right [fld_occ])) }+ | otherwise+ -> do { addUsedGRE True gre+ ; return (Just (Left (gre_name gre))) }+ gres | all isRecFldGRE gres && overload_ok+ -- Don't record usage for ambiguous selectors+ -- until we know which is meant+ -> return+ (Just (Right+ (map (FieldOcc (noLoc rdr_name) . gre_name)+ gres)))+ gres -> do { addNameClashErrRn rdr_name gres+ ; return (Just (Left (gre_name (head gres)))) } }+++--------------------------------------------------+-- Lookup in the Global RdrEnv of the module+--------------------------------------------------++lookupGreRn_maybe :: RdrName -> RnM (Maybe GlobalRdrElt)+-- Look up the RdrName in the GlobalRdrEnv+-- Exactly one binding: records it as "used", return (Just gre)+-- No bindings: return Nothing+-- Many bindings: report "ambiguous", return an arbitrary (Just gre)+-- (This API is a bit strange; lookupGRERn2_maybe is simpler.+-- But it works and I don't want to fiddle too much.)+-- Uses addUsedRdrName to record use and deprecations+lookupGreRn_maybe rdr_name+ = do { env <- getGlobalRdrEnv+ ; case lookupGRE_RdrName rdr_name env of+ [] -> return Nothing+ [gre] -> do { addUsedGRE True gre+ ; return (Just gre) }+ gres -> do { addNameClashErrRn rdr_name gres+ ; traceRn "lookupGreRn:name clash"+ (ppr rdr_name $$ ppr gres $$ ppr env)+ ; return (Just (head gres)) } }++lookupGreRn2_maybe :: RdrName -> RnM (Maybe GlobalRdrElt)+-- Look up the RdrName in the GlobalRdrEnv+-- Exactly one binding: record it as "used", return (Just gre)+-- No bindings: report "not in scope", return Nothing+-- Many bindings: report "ambiguous", return Nothing+-- Uses addUsedRdrName to record use and deprecations+lookupGreRn2_maybe rdr_name+ = do { env <- getGlobalRdrEnv+ ; case lookupGRE_RdrName rdr_name env of+ [] -> do { _ <- unboundName WL_Global rdr_name+ ; return Nothing }+ [gre] -> do { addUsedGRE True gre+ ; return (Just gre) }+ gres -> do { addNameClashErrRn rdr_name gres+ ; traceRn "lookupGreRn_maybe:name clash"+ (ppr rdr_name $$ ppr gres $$ ppr env)+ ; return Nothing } }++lookupGreAvailRn :: RdrName -> RnM (Name, AvailInfo)+-- Used in export lists+-- If not found or ambiguous, add error message, and fake with UnboundName+-- Uses addUsedRdrName to record use and deprecations+lookupGreAvailRn rdr_name+ = do { mb_gre <- lookupGreRn2_maybe rdr_name+ ; case mb_gre of {+ Just gre -> return (gre_name gre, availFromGRE gre) ;+ Nothing ->+ do { traceRn "lookupGreAvailRn" (ppr rdr_name)+ ; let name = mkUnboundNameRdr rdr_name+ ; return (name, avail name) } } }++{-+*********************************************************+* *+ Deprecations+* *+*********************************************************++Note [Handling of deprecations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* We report deprecations at each *occurrence* of the deprecated thing+ (see Trac #5867)++* We do not report deprecations for locally-defined names. For a+ start, we may be exporting a deprecated thing. Also we may use a+ deprecated thing in the defn of another deprecated things. We may+ even use a deprecated thing in the defn of a non-deprecated thing,+ when changing a module's interface.++* addUsedGREs: we do not report deprecations for sub-binders:+ - the ".." completion for records+ - the ".." in an export item 'T(..)'+ - the things exported by a module export 'module M'+-}++addUsedDataCons :: GlobalRdrEnv -> TyCon -> RnM ()+-- Remember use of in-scope data constructors (Trac #7969)+addUsedDataCons rdr_env tycon+ = addUsedGREs [ gre+ | dc <- tyConDataCons tycon+ , Just gre <- [lookupGRE_Name rdr_env (dataConName dc)] ]++addUsedGRE :: Bool -> GlobalRdrElt -> RnM ()+-- Called for both local and imported things+-- Add usage *and* warn if deprecated+addUsedGRE warn_if_deprec gre+ = do { when warn_if_deprec (warnIfDeprecated gre)+ ; unless (isLocalGRE gre) $+ do { env <- getGblEnv+ ; traceRn "addUsedGRE" (ppr gre)+ ; updMutVar (tcg_used_gres env) (gre :) } }++addUsedGREs :: [GlobalRdrElt] -> RnM ()+-- Record uses of any *imported* GREs+-- Used for recording used sub-bndrs+-- NB: no call to warnIfDeprecated; see Note [Handling of deprecations]+addUsedGREs gres+ | null imp_gres = return ()+ | otherwise = do { env <- getGblEnv+ ; traceRn "addUsedGREs" (ppr imp_gres)+ ; updMutVar (tcg_used_gres env) (imp_gres ++) }+ where+ imp_gres = filterOut isLocalGRE gres++warnIfDeprecated :: GlobalRdrElt -> RnM ()+warnIfDeprecated gre@(GRE { gre_name = name, gre_imp = iss })+ | (imp_spec : _) <- iss+ = do { dflags <- getDynFlags+ ; this_mod <- getModule+ ; when (wopt Opt_WarnWarningsDeprecations dflags &&+ not (nameIsLocalOrFrom this_mod name)) $+ -- See Note [Handling of deprecations]+ do { iface <- loadInterfaceForName doc name+ ; case lookupImpDeprec iface gre of+ Just txt -> addWarn (Reason Opt_WarnWarningsDeprecations)+ (mk_msg imp_spec txt)+ Nothing -> return () } }+ | otherwise+ = return ()+ where+ occ = greOccName gre+ name_mod = ASSERT2( isExternalName name, ppr name ) nameModule name+ doc = text "The name" <+> quotes (ppr occ) <+> ptext (sLit "is mentioned explicitly")++ mk_msg imp_spec txt+ = sep [ sep [ text "In the use of"+ <+> pprNonVarNameSpace (occNameSpace occ)+ <+> quotes (ppr occ)+ , parens imp_msg <> colon ]+ , pprWarningTxtForMsg txt ]+ where+ imp_mod = importSpecModule imp_spec+ imp_msg = text "imported from" <+> ppr imp_mod <> extra+ extra | imp_mod == moduleName name_mod = Outputable.empty+ | otherwise = text ", but defined in" <+> ppr name_mod++lookupImpDeprec :: ModIface -> GlobalRdrElt -> Maybe WarningTxt+lookupImpDeprec iface gre+ = mi_warn_fn iface (greOccName gre) `mplus` -- Bleat if the thing,+ case gre_par gre of -- or its parent, is warn'd+ ParentIs p -> mi_warn_fn iface (nameOccName p)+ FldParent { par_is = p } -> mi_warn_fn iface (nameOccName p)+ NoParent -> Nothing++{-+Note [Used names with interface not loaded]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's (just) possible to find a used+Name whose interface hasn't been loaded:++a) It might be a WiredInName; in that case we may not load+ its interface (although we could).++b) It might be GHC.Real.fromRational, or GHC.Num.fromInteger+ These are seen as "used" by the renamer (if -XRebindableSyntax)+ is on), but the typechecker may discard their uses+ if in fact the in-scope fromRational is GHC.Read.fromRational,+ (see tcPat.tcOverloadedLit), and the typechecker sees that the type+ is fixed, say, to GHC.Base.Float (see Inst.lookupSimpleInst).+ In that obscure case it won't force the interface in.++In both cases we simply don't permit deprecations;+this is, after all, wired-in stuff.+++*********************************************************+* *+ GHCi support+* *+*********************************************************++A qualified name on the command line can refer to any module at+all: we try to load the interface if we don't already have it, just+as if there was an "import qualified M" declaration for every+module.++If we fail we just return Nothing, rather than bleating+about "attempting to use module ‘D’ (./D.hs) which is not loaded"+which is what loadSrcInterface does.++Note [Safe Haskell and GHCi]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We DONT do this Safe Haskell as we need to check imports. We can+and should instead check the qualified import but at the moment+this requires some refactoring so leave as a TODO+-}++lookupQualifiedNameGHCi :: RdrName -> RnM [Name]+lookupQualifiedNameGHCi rdr_name+ = -- We want to behave as we would for a source file import here,+ -- and respect hiddenness of modules/packages, hence loadSrcInterface.+ do { dflags <- getDynFlags+ ; is_ghci <- getIsGHCi+ ; go_for_it dflags is_ghci }++ where+ go_for_it dflags is_ghci+ | Just (mod,occ) <- isQual_maybe rdr_name+ , 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 False Nothing+ ; case res of+ Succeeded iface+ -> return [ name+ | avail <- mi_exports iface+ , name <- availNames avail+ , nameOccName name == occ ]++ _ -> -- Either we couldn't load the interface, or+ -- we could but we didn't find the name in it+ do { traceRn "lookupQualifiedNameGHCi" (ppr rdr_name)+ ; return [] } }++ | otherwise+ = do { traceRn "lookupQualifiedNameGHCi: off" (ppr rdr_name)+ ; return [] }++ doc = text "Need to find" <+> ppr rdr_name++{-+Note [Looking up signature names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+lookupSigOccRn is used for type signatures and pragmas+Is this valid?+ module A+ import M( f )+ f :: Int -> Int+ f x = x+It's clear that the 'f' in the signature must refer to A.f+The Haskell98 report does not stipulate this, but it will!+So we must treat the 'f' in the signature in the same way+as the binding occurrence of 'f', using lookupBndrRn++However, consider this case:+ import M( f )+ f :: Int -> Int+ g x = x+We don't want to say 'f' is out of scope; instead, we want to+return the imported 'f', so that later on the reanamer will+correctly report "misplaced type sig".++Note [Signatures for top level things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+data HsSigCtxt = ... | TopSigCtxt NameSet | ....++* The NameSet says what is bound in this group of bindings.+ We can't use isLocalGRE from the GlobalRdrEnv, because of this:+ f x = x+ $( ...some TH splice... )+ f :: Int -> Int+ When we encounter the signature for 'f', the binding for 'f'+ will be in the GlobalRdrEnv, and will be a LocalDef. Yet the+ signature is mis-placed++* For type signatures the NameSet should be the names bound by the+ value bindings; for fixity declarations, the NameSet should also+ include class sigs and record selectors++ infix 3 `f` -- Yes, ok+ f :: C a => a -> a -- No, not ok+ class C a where+ f :: a -> a+-}++data HsSigCtxt+ = TopSigCtxt NameSet -- At top level, binding these names+ -- See Note [Signatures for top level things]+ | LocalBindCtxt NameSet -- In a local binding, binding these names+ | ClsDeclCtxt Name -- Class decl for this class+ | InstDeclCtxt NameSet -- Instance decl whose user-written method+ -- bindings are for these methods+ | HsBootCtxt NameSet -- Top level of a hs-boot file, binding these names+ | RoleAnnotCtxt NameSet -- A role annotation, with the names of all types+ -- in the group++instance Outputable HsSigCtxt where+ ppr (TopSigCtxt ns) = text "TopSigCtxt" <+> ppr ns+ ppr (LocalBindCtxt ns) = text "LocalBindCtxt" <+> ppr ns+ ppr (ClsDeclCtxt n) = text "ClsDeclCtxt" <+> ppr n+ ppr (InstDeclCtxt ns) = text "InstDeclCtxt" <+> ppr ns+ ppr (HsBootCtxt ns) = text "HsBootCtxt" <+> ppr ns+ ppr (RoleAnnotCtxt ns) = text "RoleAnnotCtxt" <+> ppr ns++lookupSigOccRn :: HsSigCtxt+ -> Sig RdrName+ -> Located RdrName -> RnM (Located Name)+lookupSigOccRn ctxt sig = lookupSigCtxtOccRn ctxt (hsSigDoc sig)++-- | Lookup a name in relation to the names in a 'HsSigCtxt'+lookupSigCtxtOccRn :: HsSigCtxt+ -> SDoc -- ^ description of thing we're looking up,+ -- like "type family"+ -> Located RdrName -> RnM (Located Name)+lookupSigCtxtOccRn ctxt what+ = wrapLocM $ \ rdr_name ->+ do { mb_name <- lookupBindGroupOcc ctxt what rdr_name+ ; case mb_name of+ Left err -> do { addErr err; return (mkUnboundNameRdr rdr_name) }+ Right name -> return name }++lookupBindGroupOcc :: HsSigCtxt+ -> SDoc+ -> RdrName -> RnM (Either MsgDoc Name)+-- Looks up the RdrName, expecting it to resolve to one of the+-- bound names passed in. If not, return an appropriate error message+--+-- See Note [Looking up signature names]+lookupBindGroupOcc ctxt what rdr_name+ | Just n <- isExact_maybe rdr_name+ = lookupExactOcc_either n -- allow for the possibility of missing Exacts;+ -- see Note [dataTcOccs and Exact Names]+ -- Maybe we should check the side conditions+ -- but it's a pain, and Exact things only show+ -- up when you know what you are doing++ | Just (rdr_mod, rdr_occ) <- isOrig_maybe rdr_name+ = do { n' <- lookupOrig rdr_mod rdr_occ+ ; return (Right n') }++ | otherwise+ = case ctxt of+ HsBootCtxt ns -> lookup_top (`elemNameSet` ns)+ TopSigCtxt ns -> lookup_top (`elemNameSet` ns)+ RoleAnnotCtxt ns -> lookup_top (`elemNameSet` ns)+ LocalBindCtxt ns -> lookup_group ns+ ClsDeclCtxt cls -> lookup_cls_op cls+ InstDeclCtxt ns -> lookup_top (`elemNameSet` ns)+ where+ lookup_cls_op cls+ = lookupSubBndrOcc True cls doc rdr_name+ where+ doc = text "method of class" <+> quotes (ppr cls)++ lookup_top keep_me+ = do { env <- getGlobalRdrEnv+ ; let all_gres = lookupGlobalRdrEnv env (rdrNameOcc rdr_name)+ ; case filter (keep_me . gre_name) all_gres of+ [] | null all_gres -> bale_out_with Outputable.empty+ | otherwise -> bale_out_with local_msg+ (gre:_) -> return (Right (gre_name gre)) }++ lookup_group bound_names -- Look in the local envt (not top level)+ = do { local_env <- getLocalRdrEnv+ ; case lookupLocalRdrEnv local_env rdr_name of+ Just n+ | n `elemNameSet` bound_names -> return (Right n)+ | otherwise -> bale_out_with local_msg+ Nothing -> bale_out_with Outputable.empty }++ bale_out_with msg+ = return (Left (sep [ text "The" <+> what+ <+> text "for" <+> quotes (ppr rdr_name)+ , nest 2 $ text "lacks an accompanying binding"]+ $$ nest 2 msg))++ local_msg = parens $ text "The" <+> what <+> ptext (sLit "must be given where")+ <+> quotes (ppr rdr_name) <+> text "is declared"+++---------------+lookupLocalTcNames :: HsSigCtxt -> SDoc -> RdrName -> RnM [(RdrName, Name)]+-- GHC extension: look up both the tycon and data con or variable.+-- Used for top-level fixity signatures and deprecations.+-- Complain if neither is in scope.+-- See Note [Fixity signature lookup]+lookupLocalTcNames ctxt what rdr_name+ = do { mb_gres <- mapM lookup (dataTcOccs rdr_name)+ ; let (errs, names) = splitEithers mb_gres+ ; when (null names) $ addErr (head errs) -- Bleat about one only+ ; return names }+ where+ lookup rdr = do { name <- lookupBindGroupOcc ctxt what rdr+ ; return (fmap ((,) rdr) name) }++dataTcOccs :: RdrName -> [RdrName]+-- Return both the given name and the same name promoted to the TcClsName+-- namespace. This is useful when we aren't sure which we are looking at.+-- See also Note [dataTcOccs and Exact Names]+dataTcOccs rdr_name+ | isDataOcc occ || isVarOcc occ+ = [rdr_name, rdr_name_tc]+ | otherwise+ = [rdr_name]+ where+ occ = rdrNameOcc rdr_name+ rdr_name_tc = setRdrNameSpace rdr_name tcName++{-+Note [dataTcOccs and Exact Names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Exact RdrNames can occur in code generated by Template Haskell, and generally+those references are, well, exact. However, the TH `Name` type isn't expressive+enough to always track the correct namespace information, so we sometimes get+the right Unique but wrong namespace. Thus, we still have to do the double-lookup+for Exact RdrNames.++There is also an awkward situation for built-in syntax. Example in GHCi+ :info []+This parses as the Exact RdrName for nilDataCon, but we also want+the list type constructor.++Note that setRdrNameSpace on an Exact name requires the Name to be External,+which it always is for built in syntax.++*********************************************************+* *+ Fixities+* *+*********************************************************++Note [Fixity signature lookup]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A fixity declaration like++ infixr 2 ?++can refer to a value-level operator, e.g.:++ (?) :: String -> String -> String++or a type-level operator, like:++ data (?) a b = A a | B b++so we extend the lookup of the reader name '?' to the TcClsName namespace, as+well as the original namespace.++The extended lookup is also used in other places, like resolution of+deprecation declarations, and lookup of names in GHCi.+-}++--------------------------------+type MiniFixityEnv = FastStringEnv (Located Fixity)+ -- Mini fixity env for the names we're about+ -- to bind, in a single binding group+ --+ -- It is keyed by the *FastString*, not the *OccName*, because+ -- the single fixity decl infix 3 T+ -- affects both the data constructor T and the type constrctor T+ --+ -- We keep the location so that if we find+ -- a duplicate, we can report it sensibly++--------------------------------+-- Used for nested fixity decls to bind names along with their fixities.+-- the fixities are given as a UFM from an OccName's FastString to a fixity decl++addLocalFixities :: MiniFixityEnv -> [Name] -> RnM a -> RnM a+addLocalFixities mini_fix_env names thing_inside+ = extendFixityEnv (mapMaybe find_fixity names) thing_inside+ where+ find_fixity name+ = case lookupFsEnv mini_fix_env (occNameFS occ) of+ Just (L _ fix) -> Just (name, FixItem occ fix)+ Nothing -> Nothing+ where+ occ = nameOccName name++{-+--------------------------------+lookupFixity is a bit strange.++* Nested local fixity decls are put in the local fixity env, which we+ find with getFixtyEnv++* Imported fixities are found in the PIT++* Top-level fixity decls in this module may be for Names that are+ either Global (constructors, class operations)+ or Local/Exported (everything else)+ (See notes with RnNames.getLocalDeclBinders for why we have this split.)+ We put them all in the local fixity environment+-}++lookupFixityRn :: Name -> RnM Fixity+lookupFixityRn name = lookupFixityRn' name (nameOccName name)++lookupFixityRn' :: Name -> OccName -> RnM Fixity+lookupFixityRn' name = fmap snd . lookupFixityRn_help' name++-- | 'lookupFixityRn_help' returns @(True, fixity)@ if it finds a 'Fixity'+-- in a local environment or from an interface file. Otherwise, it returns+-- @(False, fixity)@ (e.g., for unbound 'Name's or 'Name's without+-- user-supplied fixity declarations).+lookupFixityRn_help :: Name+ -> RnM (Bool, Fixity)+lookupFixityRn_help name =+ lookupFixityRn_help' name (nameOccName name)++lookupFixityRn_help' :: Name+ -> OccName+ -> RnM (Bool, Fixity)+lookupFixityRn_help' name occ+ | isUnboundName name+ = return (False, Fixity NoSourceText minPrecedence InfixL)+ -- Minimise errors from ubound names; eg+ -- a>0 `foo` b>0+ -- where 'foo' is not in scope, should not give an error (Trac #7937)++ | otherwise+ = do { local_fix_env <- getFixityEnv+ ; case lookupNameEnv local_fix_env name of {+ Just (FixItem _ fix) -> return (True, fix) ;+ Nothing ->++ do { this_mod <- getModule+ ; if nameIsLocalOrFrom this_mod name+ -- Local (and interactive) names are all in the+ -- fixity env, and don't have entries in the HPT+ then return (False, defaultFixity)+ else lookup_imported } } }+ where+ lookup_imported+ -- For imported names, we have to get their fixities by doing a+ -- loadInterfaceForName, and consulting the Ifaces that comes back+ -- from that, because the interface file for the Name might not+ -- have been loaded yet. Why not? Suppose you import module A,+ -- which exports a function 'f', thus;+ -- module CurrentModule where+ -- import A( f )+ -- module A( f ) where+ -- import B( f )+ -- Then B isn't loaded right away (after all, it's possible that+ -- nothing from B will be used). When we come across a use of+ -- 'f', we need to know its fixity, and it's then, and only+ -- then, that we load B.hi. That is what's happening here.+ --+ -- loadInterfaceForName will find B.hi even if B is a hidden module,+ -- and that's what we want.+ = do { iface <- loadInterfaceForName doc name+ ; let mb_fix = mi_fix_fn iface occ+ ; let msg = case mb_fix of+ Nothing ->+ text "looking up name" <+> ppr name+ <+> text "in iface, but found no fixity for it."+ <+> text "Using default fixity instead."+ Just f ->+ text "looking up name in iface and found:"+ <+> vcat [ppr name, ppr f]+ ; traceRn "lookupFixityRn_either:" msg+ ; return (maybe (False, defaultFixity) (\f -> (True, f)) mb_fix) }++ doc = text "Checking fixity for" <+> ppr name++---------------+lookupTyFixityRn :: Located Name -> RnM Fixity+lookupTyFixityRn (L _ n) = lookupFixityRn n++-- | Look up the fixity of a (possibly ambiguous) occurrence of a record field+-- selector. We use 'lookupFixityRn'' so that we can specifiy the 'OccName' as+-- the field label, which might be different to the 'OccName' of the selector+-- 'Name' if @DuplicateRecordFields@ is in use (Trac #1173). If there are+-- multiple possible selectors with different fixities, generate an error.+lookupFieldFixityRn :: AmbiguousFieldOcc Name -> RnM Fixity+lookupFieldFixityRn (Unambiguous (L _ rdr) n)+ = lookupFixityRn' n (rdrNameOcc rdr)+lookupFieldFixityRn (Ambiguous (L _ rdr) _) = get_ambiguous_fixity rdr+ where+ get_ambiguous_fixity :: RdrName -> RnM Fixity+ get_ambiguous_fixity rdr_name = do+ traceRn "get_ambiguous_fixity" (ppr rdr_name)+ rdr_env <- getGlobalRdrEnv+ let elts = lookupGRE_RdrName rdr_name rdr_env++ fixities <- groupBy ((==) `on` snd) . zip elts+ <$> mapM lookup_gre_fixity elts++ case fixities of+ -- There should always be at least one fixity.+ -- Something's very wrong if there are no fixity candidates, so panic+ [] -> panic "get_ambiguous_fixity: no candidates for a given RdrName"+ [ (_, fix):_ ] -> return fix+ ambigs -> addErr (ambiguous_fixity_err rdr_name ambigs)+ >> return (Fixity NoSourceText minPrecedence InfixL)++ lookup_gre_fixity gre = lookupFixityRn' (gre_name gre) (greOccName gre)++ ambiguous_fixity_err rn ambigs+ = vcat [ text "Ambiguous fixity for record field" <+> quotes (ppr rn)+ , hang (text "Conflicts: ") 2 . vcat .+ map format_ambig $ concat ambigs ]++ format_ambig (elt, fix) = hang (ppr fix)+ 2 (pprNameProvenance elt)+++{- *********************************************************************+* *+ Role annotations+* *+********************************************************************* -}++type RoleAnnotEnv = NameEnv (LRoleAnnotDecl Name)++mkRoleAnnotEnv :: [LRoleAnnotDecl Name] -> RoleAnnotEnv+mkRoleAnnotEnv role_annot_decls+ = mkNameEnv [ (name, ra_decl)+ | ra_decl <- role_annot_decls+ , let name = roleAnnotDeclName (unLoc ra_decl)+ , not (isUnboundName name) ]+ -- Some of the role annots will be unbound;+ -- we don't wish to include these++emptyRoleAnnotEnv :: RoleAnnotEnv+emptyRoleAnnotEnv = emptyNameEnv++lookupRoleAnnot :: RoleAnnotEnv -> Name -> Maybe (LRoleAnnotDecl Name)+lookupRoleAnnot = lookupNameEnv++getRoleAnnots :: [Name] -> RoleAnnotEnv -> ([LRoleAnnotDecl Name], RoleAnnotEnv)+getRoleAnnots bndrs role_env+ = ( mapMaybe (lookupRoleAnnot role_env) bndrs+ , delListFromNameEnv role_env bndrs )+++{-+************************************************************************+* *+ Rebindable names+ Dealing with rebindable syntax is driven by the+ Opt_RebindableSyntax dynamic flag.++ In "deriving" code we don't want to use rebindable syntax+ so we switch off the flag locally++* *+************************************************************************++Haskell 98 says that when you say "3" you get the "fromInteger" from the+Standard Prelude, regardless of what is in scope. However, to experiment+with having a language that is less coupled to the standard prelude, we're+trying a non-standard extension that instead gives you whatever "Prelude.fromInteger"+happens to be in scope. Then you can+ import Prelude ()+ import MyPrelude as Prelude+to get the desired effect.++At the moment this just happens for+ * fromInteger, fromRational on literals (in expressions and patterns)+ * negate (in expressions)+ * minus (arising from n+k patterns)+ * "do" notation++We store the relevant Name in the HsSyn tree, in+ * HsIntegral/HsFractional/HsIsString+ * NegApp+ * NPlusKPat+ * HsDo+respectively. Initially, we just store the "standard" name (PrelNames.fromIntegralName,+fromRationalName etc), but the renamer changes this to the appropriate user+name if Opt_NoImplicitPrelude is on. That is what lookupSyntaxName does.++We treat the original (standard) names as free-vars too, because the type checker+checks the type of the user thing against the type of the standard thing.+-}++lookupIfThenElse :: RnM (Maybe (SyntaxExpr Name), FreeVars)+-- Different to lookupSyntaxName because in the non-rebindable+-- case we desugar directly rather than calling an existing function+-- Hence the (Maybe (SyntaxExpr Name)) return type+lookupIfThenElse+ = do { rebindable_on <- xoptM LangExt.RebindableSyntax+ ; if not rebindable_on+ then return (Nothing, emptyFVs)+ else do { ite <- lookupOccRn (mkVarUnqual (fsLit "ifThenElse"))+ ; return ( Just (mkRnSyntaxExpr ite)+ , unitFV ite ) } }++lookupSyntaxName' :: Name -- ^ The standard name+ -> RnM Name -- ^ Possibly a non-standard name+lookupSyntaxName' std_name+ = do { rebindable_on <- xoptM LangExt.RebindableSyntax+ ; if not rebindable_on then+ return std_name+ else+ -- Get the similarly named thing from the local environment+ lookupOccRn (mkRdrUnqual (nameOccName std_name)) }++lookupSyntaxName :: Name -- The standard name+ -> RnM (SyntaxExpr Name, FreeVars) -- Possibly a non-standard name+lookupSyntaxName std_name+ = do { rebindable_on <- xoptM LangExt.RebindableSyntax+ ; if not rebindable_on then+ return (mkRnSyntaxExpr std_name, emptyFVs)+ else+ -- Get the similarly named thing from the local environment+ do { usr_name <- lookupOccRn (mkRdrUnqual (nameOccName std_name))+ ; return (mkRnSyntaxExpr usr_name, unitFV usr_name) } }++lookupSyntaxNames :: [Name] -- Standard names+ -> RnM ([HsExpr Name], FreeVars) -- See comments with HsExpr.ReboundNames+ -- this works with CmdTop, which wants HsExprs, not SyntaxExprs+lookupSyntaxNames std_names+ = do { rebindable_on <- xoptM LangExt.RebindableSyntax+ ; if not rebindable_on then+ return (map (HsVar . noLoc) std_names, emptyFVs)+ else+ do { usr_names <- mapM (lookupOccRn . mkRdrUnqual . nameOccName) std_names+ ; return (map (HsVar . noLoc) usr_names, mkFVs usr_names) } }++{-+*********************************************************+* *+\subsection{Binding}+* *+*********************************************************+-}++newLocalBndrRn :: Located RdrName -> RnM Name+-- Used for non-top-level binders. These should+-- never be qualified.+newLocalBndrRn (L loc rdr_name)+ | Just name <- isExact_maybe rdr_name+ = return name -- This happens in code generated by Template Haskell+ -- See Note [Binders in Template Haskell] in Convert.hs+ | otherwise+ = do { unless (isUnqual rdr_name)+ (addErrAt loc (badQualBndrErr rdr_name))+ ; uniq <- newUnique+ ; return (mkInternalName uniq (rdrNameOcc rdr_name) loc) }++newLocalBndrsRn :: [Located RdrName] -> RnM [Name]+newLocalBndrsRn = mapM newLocalBndrRn++---------------------+bindLocatedLocalsRn :: [Located RdrName]+ -> ([Name] -> RnM a)+ -> RnM a+bindLocatedLocalsRn rdr_names_w_loc enclosed_scope+ = do { checkDupRdrNames rdr_names_w_loc+ ; checkShadowedRdrNames rdr_names_w_loc++ -- Make fresh Names and extend the environment+ ; names <- newLocalBndrsRn rdr_names_w_loc+ ; bindLocalNames names (enclosed_scope names) }++bindLocalNames :: [Name] -> RnM a -> RnM a+bindLocalNames names enclosed_scope+ = do { lcl_env <- getLclEnv+ ; let th_level = thLevel (tcl_th_ctxt lcl_env)+ th_bndrs' = extendNameEnvList (tcl_th_bndrs lcl_env)+ [ (n, (NotTopLevel, th_level)) | n <- names ]+ rdr_env' = extendLocalRdrEnvList (tcl_rdr lcl_env) names+ ; setLclEnv (lcl_env { tcl_th_bndrs = th_bndrs'+ , tcl_rdr = rdr_env' })+ enclosed_scope }++bindLocalNamesFV :: [Name] -> RnM (a, FreeVars) -> RnM (a, FreeVars)+bindLocalNamesFV names enclosed_scope+ = do { (result, fvs) <- bindLocalNames names enclosed_scope+ ; return (result, delFVs names fvs) }+++-------------------------------------+ -- binLocalsFVRn is the same as bindLocalsRn+ -- except that it deals with free vars+bindLocatedLocalsFV :: [Located RdrName]+ -> ([Name] -> RnM (a,FreeVars)) -> RnM (a, FreeVars)+bindLocatedLocalsFV rdr_names enclosed_scope+ = bindLocatedLocalsRn rdr_names $ \ names ->+ do (thing, fvs) <- enclosed_scope names+ return (thing, delFVs names fvs)++-------------------------------------++extendTyVarEnvFVRn :: [Name] -> RnM (a, FreeVars) -> RnM (a, FreeVars)+ -- This function is used only in rnSourceDecl on InstDecl+extendTyVarEnvFVRn tyvars thing_inside = bindLocalNamesFV tyvars thing_inside++-------------------------------------+checkDupRdrNames :: [Located RdrName] -> RnM ()+-- Check for duplicated names in a binding group+checkDupRdrNames rdr_names_w_loc+ = mapM_ (dupNamesErr getLoc) dups+ where+ (_, dups) = removeDups (\n1 n2 -> unLoc n1 `compare` unLoc n2) rdr_names_w_loc++checkDupNames :: [Name] -> RnM ()+-- Check for duplicated names in a binding group+checkDupNames names = check_dup_names (filterOut isSystemName names)+ -- See Note [Binders in Template Haskell] in Convert++check_dup_names :: [Name] -> RnM ()+check_dup_names names+ = mapM_ (dupNamesErr nameSrcSpan) dups+ where+ (_, dups) = removeDups (\n1 n2 -> nameOccName n1 `compare` nameOccName n2) names++---------------------+checkShadowedRdrNames :: [Located RdrName] -> RnM ()+checkShadowedRdrNames loc_rdr_names+ = do { envs <- getRdrEnvs+ ; checkShadowedOccs envs get_loc_occ filtered_rdrs }+ where+ filtered_rdrs = filterOut (isExact . unLoc) loc_rdr_names+ -- See Note [Binders in Template Haskell] in Convert+ get_loc_occ (L loc rdr) = (loc,rdrNameOcc rdr)++checkDupAndShadowedNames :: (GlobalRdrEnv, LocalRdrEnv) -> [Name] -> RnM ()+checkDupAndShadowedNames envs names+ = do { check_dup_names filtered_names+ ; checkShadowedOccs envs get_loc_occ filtered_names }+ where+ filtered_names = filterOut isSystemName names+ -- See Note [Binders in Template Haskell] in Convert+ get_loc_occ name = (nameSrcSpan name, nameOccName name)++-------------------------------------+checkShadowedOccs :: (GlobalRdrEnv, LocalRdrEnv)+ -> (a -> (SrcSpan, OccName))+ -> [a] -> RnM ()+checkShadowedOccs (global_env,local_env) get_loc_occ ns+ = whenWOptM Opt_WarnNameShadowing $+ do { traceRn "checkShadowedOccs:shadow" (ppr (map get_loc_occ ns))+ ; mapM_ check_shadow ns }+ where+ check_shadow n+ | startsWithUnderscore occ = return () -- Do not report shadowing for "_x"+ -- See Trac #3262+ | Just n <- mb_local = complain [text "bound at" <+> ppr (nameSrcLoc n)]+ | otherwise = do { gres' <- filterM is_shadowed_gre gres+ ; complain (map pprNameProvenance gres') }+ where+ (loc,occ) = get_loc_occ n+ mb_local = lookupLocalRdrOcc local_env occ+ gres = lookupGRE_RdrName (mkRdrUnqual occ) global_env+ -- Make an Unqualified RdrName and look that up, so that+ -- we don't find any GREs that are in scope qualified-only++ complain [] = return ()+ complain pp_locs = addWarnAt (Reason Opt_WarnNameShadowing)+ loc+ (shadowedNameWarn occ pp_locs)++ is_shadowed_gre :: GlobalRdrElt -> RnM Bool+ -- Returns False for record selectors that are shadowed, when+ -- punning or wild-cards are on (cf Trac #2723)+ is_shadowed_gre gre | isRecFldGRE gre+ = do { dflags <- getDynFlags+ ; return $ not (xopt LangExt.RecordPuns dflags+ || xopt LangExt.RecordWildCards dflags) }+ is_shadowed_gre _other = return True++{-+************************************************************************+* *+ What to do when a lookup fails+* *+************************************************************************+-}++data WhereLooking = WL_Any -- Any binding+ | WL_Global -- Any top-level binding (local or imported)+ | WL_LocalTop -- Any top-level binding in this module++reportUnboundName :: RdrName -> RnM Name+reportUnboundName rdr = unboundName WL_Any rdr++unboundName :: WhereLooking -> RdrName -> RnM Name+unboundName wl rdr = unboundNameX wl rdr Outputable.empty++unboundNameX :: WhereLooking -> RdrName -> SDoc -> RnM Name+unboundNameX where_look rdr_name extra+ = do { dflags <- getDynFlags+ ; let show_helpful_errors = gopt Opt_HelpfulErrors dflags+ what = pprNonVarNameSpace (occNameSpace (rdrNameOcc rdr_name))+ err = unknownNameErr what rdr_name $$ extra+ ; if not show_helpful_errors+ then addErr err+ else do { local_env <- getLocalRdrEnv+ ; global_env <- getGlobalRdrEnv+ ; impInfo <- getImports+ ; let suggestions = unknownNameSuggestions_ where_look+ dflags global_env local_env impInfo rdr_name+ ; addErr (err $$ suggestions) }+ ; return (mkUnboundNameRdr rdr_name) }++unknownNameErr :: SDoc -> RdrName -> SDoc+unknownNameErr what rdr_name+ = vcat [ hang (text "Not in scope:")+ 2 (what <+> quotes (ppr rdr_name))+ , extra ]+ where+ extra | rdr_name == forall_tv_RDR = perhapsForallMsg+ | otherwise = Outputable.empty++type HowInScope = Either SrcSpan ImpDeclSpec+ -- Left loc => locally bound at loc+ -- Right ispec => imported as specified by ispec+++-- | Called from the typechecker (TcErrors) when we find an unbound variable+unknownNameSuggestions :: DynFlags+ -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails+ -> RdrName -> SDoc+unknownNameSuggestions = unknownNameSuggestions_ WL_Any++unknownNameSuggestions_ :: WhereLooking -> DynFlags+ -> GlobalRdrEnv -> LocalRdrEnv -> ImportAvails+ -> RdrName -> SDoc+unknownNameSuggestions_ where_look dflags global_env local_env imports tried_rdr_name =+ similarNameSuggestions where_look dflags global_env local_env tried_rdr_name $$+ importSuggestions dflags imports tried_rdr_name+++similarNameSuggestions :: WhereLooking -> DynFlags+ -> GlobalRdrEnv -> LocalRdrEnv+ -> RdrName -> SDoc+similarNameSuggestions where_look dflags global_env+ local_env tried_rdr_name+ = case suggest of+ [] -> Outputable.empty+ [p] -> perhaps <+> pp_item p+ ps -> sep [ perhaps <+> text "one of these:"+ , nest 2 (pprWithCommas pp_item ps) ]+ where+ all_possibilities :: [(String, (RdrName, HowInScope))]+ all_possibilities+ = [ (showPpr dflags r, (r, Left loc))+ | (r,loc) <- local_possibilities local_env ]+ ++ [ (showPpr dflags r, rp) | (r, rp) <- global_possibilities global_env ]++ suggest = fuzzyLookup (showPpr dflags tried_rdr_name) all_possibilities+ perhaps = text "Perhaps you meant"++ pp_item :: (RdrName, HowInScope) -> SDoc+ pp_item (rdr, Left loc) = pp_ns rdr <+> quotes (ppr rdr) <+> loc' -- Locally defined+ where loc' = case loc of+ UnhelpfulSpan l -> parens (ppr l)+ RealSrcSpan l -> parens (text "line" <+> int (srcSpanStartLine l))+ pp_item (rdr, Right is) = pp_ns rdr <+> quotes (ppr rdr) <+> -- Imported+ parens (text "imported from" <+> ppr (is_mod is))++ pp_ns :: RdrName -> SDoc+ pp_ns rdr | ns /= tried_ns = pprNameSpace ns+ | otherwise = Outputable.empty+ where ns = rdrNameSpace rdr++ tried_occ = rdrNameOcc tried_rdr_name+ tried_is_sym = isSymOcc tried_occ+ tried_ns = occNameSpace tried_occ+ tried_is_qual = isQual tried_rdr_name++ correct_name_space occ = nameSpacesRelated (occNameSpace occ) tried_ns+ && isSymOcc occ == tried_is_sym+ -- Treat operator and non-operators as non-matching+ -- This heuristic avoids things like+ -- Not in scope 'f'; perhaps you meant '+' (from Prelude)++ local_ok = case where_look of { WL_Any -> True; _ -> False }+ local_possibilities :: LocalRdrEnv -> [(RdrName, SrcSpan)]+ local_possibilities env+ | tried_is_qual = []+ | not local_ok = []+ | otherwise = [ (mkRdrUnqual occ, nameSrcSpan name)+ | name <- localRdrEnvElts env+ , let occ = nameOccName name+ , correct_name_space occ]++ gre_ok :: GlobalRdrElt -> Bool+ gre_ok = case where_look of+ WL_LocalTop -> isLocalGRE+ _ -> \_ -> True++ global_possibilities :: GlobalRdrEnv -> [(RdrName, (RdrName, HowInScope))]+ global_possibilities global_env+ | tried_is_qual = [ (rdr_qual, (rdr_qual, how))+ | gre <- globalRdrEnvElts global_env+ , gre_ok gre+ , let name = gre_name gre+ occ = nameOccName name+ , correct_name_space occ+ , (mod, how) <- quals_in_scope gre+ , let rdr_qual = mkRdrQual mod occ ]++ | otherwise = [ (rdr_unqual, pair)+ | gre <- globalRdrEnvElts global_env+ , gre_ok gre+ , let name = gre_name gre+ occ = nameOccName name+ rdr_unqual = mkRdrUnqual occ+ , correct_name_space occ+ , pair <- case (unquals_in_scope gre, quals_only gre) of+ (how:_, _) -> [ (rdr_unqual, how) ]+ ([], pr:_) -> [ pr ] -- See Note [Only-quals]+ ([], []) -> [] ]++ -- Note [Only-quals]+ -- The second alternative returns those names with the same+ -- OccName as the one we tried, but live in *qualified* imports+ -- e.g. if you have:+ --+ -- > import qualified Data.Map as Map+ -- > foo :: Map+ --+ -- then we suggest @Map.Map@.++ --------------------+ unquals_in_scope :: GlobalRdrElt -> [HowInScope]+ unquals_in_scope (GRE { gre_name = n, gre_lcl = lcl, gre_imp = is })+ | lcl = [ Left (nameSrcSpan n) ]+ | otherwise = [ Right ispec+ | i <- is, let ispec = is_decl i+ , not (is_qual ispec) ]++ --------------------+ quals_in_scope :: GlobalRdrElt -> [(ModuleName, HowInScope)]+ -- Ones for which the qualified version is in scope+ quals_in_scope (GRE { gre_name = n, gre_lcl = lcl, gre_imp = is })+ | lcl = case nameModule_maybe n of+ Nothing -> []+ Just m -> [(moduleName m, Left (nameSrcSpan n))]+ | otherwise = [ (is_as ispec, Right ispec)+ | i <- is, let ispec = is_decl i ]++ --------------------+ quals_only :: GlobalRdrElt -> [(RdrName, HowInScope)]+ -- Ones for which *only* the qualified version is in scope+ quals_only (GRE { gre_name = n, gre_imp = is })+ = [ (mkRdrQual (is_as ispec) (nameOccName n), Right ispec)+ | i <- is, let ispec = is_decl i, is_qual ispec ]++-- | Generate helpful suggestions if a qualified name Mod.foo is not in scope.+importSuggestions :: DynFlags -> ImportAvails -> RdrName -> SDoc+importSuggestions _dflags imports rdr_name+ | not (isQual rdr_name || isUnqual rdr_name) = Outputable.empty+ | null interesting_imports+ , Just name <- mod_name+ = hsep+ [ text "No module named"+ , quotes (ppr name)+ , text "is imported."+ ]+ | is_qualified+ , null helpful_imports+ , [(mod,_)] <- interesting_imports+ = hsep+ [ text "Module"+ , quotes (ppr mod)+ , text "does not export"+ , quotes (ppr occ_name) <> dot+ ]+ | is_qualified+ , null helpful_imports+ , mods <- map fst interesting_imports+ = hsep+ [ text "Neither"+ , quotedListWithNor (map ppr mods)+ , text "exports"+ , quotes (ppr occ_name) <> dot+ ]+ | [(mod,imv)] <- helpful_imports_non_hiding+ = fsep+ [ text "Perhaps you want to add"+ , quotes (ppr occ_name)+ , text "to the import list"+ , text "in the import of"+ , quotes (ppr mod)+ , parens (ppr (imv_span imv)) <> dot+ ]+ | not (null helpful_imports_non_hiding)+ = fsep+ [ text "Perhaps you want to add"+ , quotes (ppr occ_name)+ , text "to one of these import lists:"+ ]+ $$+ nest 2 (vcat+ [ quotes (ppr mod) <+> parens (ppr (imv_span imv))+ | (mod,imv) <- helpful_imports_non_hiding+ ])+ | [(mod,imv)] <- helpful_imports_hiding+ = fsep+ [ text "Perhaps you want to remove"+ , quotes (ppr occ_name)+ , text "from the explicit hiding list"+ , text "in the import of"+ , quotes (ppr mod)+ , parens (ppr (imv_span imv)) <> dot+ ]+ | not (null helpful_imports_hiding)+ = fsep+ [ text "Perhaps you want to remove"+ , quotes (ppr occ_name)+ , text "from the hiding clauses"+ , text "in one of these imports:"+ ]+ $$+ nest 2 (vcat+ [ quotes (ppr mod) <+> parens (ppr (imv_span imv))+ | (mod,imv) <- helpful_imports_hiding+ ])+ | otherwise+ = Outputable.empty+ where+ is_qualified = isQual rdr_name+ (mod_name, occ_name) = case rdr_name of+ Unqual occ_name -> (Nothing, occ_name)+ Qual mod_name occ_name -> (Just mod_name, occ_name)+ _ -> error "importSuggestions: dead code"+++ -- What import statements provide "Mod" at all+ -- or, if this is an unqualified name, are not qualified imports+ interesting_imports = [ (mod, imp)+ | (mod, mod_imports) <- moduleEnvToList (imp_mods imports)+ , Just imp <- return $ pick (importedByUser mod_imports)+ ]++ -- We want to keep only one for each original module; preferably one with an+ -- explicit import list (for no particularly good reason)+ pick :: [ImportedModsVal] -> Maybe ImportedModsVal+ pick = listToMaybe . sortBy (compare `on` prefer) . filter select+ where select imv = case mod_name of Just name -> imv_name imv == name+ Nothing -> not (imv_qualified imv)+ prefer imv = (imv_is_hiding imv, imv_span imv)++ -- Which of these would export a 'foo'+ -- (all of these are restricted imports, because if they were not, we+ -- wouldn't have an out-of-scope error in the first place)+ helpful_imports = filter helpful interesting_imports+ where helpful (_,imv)+ = not . null $ lookupGlobalRdrEnv (imv_all_exports imv) occ_name++ -- Which of these do that because of an explicit hiding list resp. an+ -- explicit import list+ (helpful_imports_hiding, helpful_imports_non_hiding)+ = partition (imv_is_hiding . snd) helpful_imports++{-+************************************************************************+* *+\subsection{Free variable manipulation}+* *+************************************************************************+-}++-- A useful utility+addFvRn :: FreeVars -> RnM (thing, FreeVars) -> RnM (thing, FreeVars)+addFvRn fvs1 thing_inside = do { (res, fvs2) <- thing_inside+ ; return (res, fvs1 `plusFV` fvs2) }++mapFvRn :: (a -> RnM (b, FreeVars)) -> [a] -> RnM ([b], FreeVars)+mapFvRn f xs = do stuff <- mapM f xs+ case unzip stuff of+ (ys, fvs_s) -> return (ys, plusFVs fvs_s)++mapMaybeFvRn :: (a -> RnM (b, FreeVars)) -> Maybe a -> RnM (Maybe b, FreeVars)+mapMaybeFvRn _ Nothing = return (Nothing, emptyFVs)+mapMaybeFvRn f (Just x) = do { (y, fvs) <- f x; return (Just y, fvs) }++-- because some of the rename functions are CPSed:+-- maps the function across the list from left to right;+-- collects all the free vars into one set+mapFvRnCPS :: (a -> (b -> RnM c) -> RnM c)+ -> [a] -> ([b] -> RnM c) -> RnM c++mapFvRnCPS _ [] cont = cont []+mapFvRnCPS f (x:xs) cont = f x $ \ x' ->+ mapFvRnCPS f xs $ \ xs' ->+ cont (x':xs')++{-+************************************************************************+* *+\subsection{Envt utility functions}+* *+************************************************************************+-}++warnUnusedTopBinds :: [GlobalRdrElt] -> RnM ()+warnUnusedTopBinds gres+ = whenWOptM Opt_WarnUnusedTopBinds+ $ do env <- getGblEnv+ let isBoot = tcg_src env == HsBootFile+ let noParent gre = case gre_par gre of+ NoParent -> True+ _ -> False+ -- Don't warn about unused bindings with parents in+ -- .hs-boot files, as you are sometimes required to give+ -- unused bindings (trac #3449).+ -- HOWEVER, in a signature file, you are never obligated to put a+ -- definition in the main text. Thus, if you define something+ -- and forget to export it, we really DO want to warn.+ gres' = if isBoot then filter noParent gres+ else gres+ warnUnusedGREs gres'++warnUnusedLocalBinds, warnUnusedMatches, warnUnusedTypePatterns+ :: [Name] -> FreeVars -> RnM ()+warnUnusedLocalBinds = check_unused Opt_WarnUnusedLocalBinds+warnUnusedMatches = check_unused Opt_WarnUnusedMatches+warnUnusedTypePatterns = check_unused Opt_WarnUnusedTypePatterns++check_unused :: WarningFlag -> [Name] -> FreeVars -> RnM ()+check_unused flag bound_names used_names+ = whenWOptM flag (warnUnused flag (filterOut (`elemNameSet` used_names)+ bound_names))++-------------------------+-- Helpers+warnUnusedGREs :: [GlobalRdrElt] -> RnM ()+warnUnusedGREs gres = mapM_ warnUnusedGRE gres++warnUnused :: WarningFlag -> [Name] -> RnM ()+warnUnused flag names = do+ fld_env <- mkFieldEnv <$> getGlobalRdrEnv+ mapM_ (warnUnused1 flag fld_env) names++warnUnused1 :: WarningFlag -> NameEnv (FieldLabelString, Name) -> Name -> RnM ()+warnUnused1 flag fld_env name+ = when (reportable name occ) $+ addUnusedWarning flag+ occ (nameSrcSpan name)+ (text "Defined but not used")+ where+ occ = case lookupNameEnv fld_env name of+ Just (fl, _) -> mkVarOccFS fl+ Nothing -> nameOccName name++warnUnusedGRE :: GlobalRdrElt -> RnM ()+warnUnusedGRE gre@(GRE { gre_name = name, gre_lcl = lcl, gre_imp = is })+ | lcl = do fld_env <- mkFieldEnv <$> getGlobalRdrEnv+ warnUnused1 Opt_WarnUnusedTopBinds fld_env name+ | otherwise = when (reportable name occ) (mapM_ warn is)+ where+ occ = greOccName gre+ warn spec = addUnusedWarning Opt_WarnUnusedTopBinds occ span msg+ where+ span = importSpecLoc spec+ pp_mod = quotes (ppr (importSpecModule spec))+ msg = text "Imported from" <+> pp_mod <+> ptext (sLit "but not used")++-- | Make a map from selector names to field labels and parent tycon+-- names, to be used when reporting unused record fields.+mkFieldEnv :: GlobalRdrEnv -> NameEnv (FieldLabelString, Name)+mkFieldEnv rdr_env = mkNameEnv [ (gre_name gre, (lbl, par_is (gre_par gre)))+ | gres <- occEnvElts rdr_env+ , gre <- gres+ , Just lbl <- [greLabel gre]+ ]++-- | Should we report the fact that this 'Name' is unused? The+-- 'OccName' may differ from 'nameOccName' due to+-- DuplicateRecordFields.+reportable :: Name -> OccName -> Bool+reportable name occ+ | isWiredInName name = False -- Don't report unused wired-in names+ -- Otherwise we get a zillion warnings+ -- from Data.Tuple+ | otherwise = not (startsWithUnderscore occ)++addUnusedWarning :: WarningFlag -> OccName -> SrcSpan -> SDoc -> RnM ()+addUnusedWarning flag occ span msg+ = addWarnAt (Reason flag) span $+ sep [msg <> colon,+ nest 2 $ pprNonVarNameSpace (occNameSpace occ)+ <+> quotes (ppr occ)]++addNameClashErrRn :: RdrName -> [GlobalRdrElt] -> RnM ()+addNameClashErrRn rdr_name gres+ | all isLocalGRE gres && not (all isRecFldGRE gres)+ -- If there are two or more *local* defns, we'll have reported+ = return () -- that already, and we don't want an error cascade+ | otherwise+ = addErr (vcat [text "Ambiguous occurrence" <+> quotes (ppr rdr_name),+ text "It could refer to" <+> vcat (msg1 : msgs)])+ where+ (np1:nps) = gres+ msg1 = ptext (sLit "either") <+> mk_ref np1+ msgs = [text " or" <+> mk_ref np | np <- nps]+ mk_ref gre = sep [nom <> comma, pprNameProvenance gre]+ where nom = case gre_par gre of+ FldParent { par_lbl = Just lbl } -> text "the field" <+> quotes (ppr lbl)+ _ -> quotes (ppr (gre_name gre))++shadowedNameWarn :: OccName -> [SDoc] -> SDoc+shadowedNameWarn occ shadowed_locs+ = sep [text "This binding for" <+> quotes (ppr occ)+ <+> text "shadows the existing binding" <> plural shadowed_locs,+ nest 2 (vcat shadowed_locs)]++perhapsForallMsg :: SDoc+perhapsForallMsg+ = vcat [ text "Perhaps you intended to use ExplicitForAll or similar flag"+ , text "to enable explicit-forall syntax: forall <tvs>. <type>"]++unknownSubordinateErr :: SDoc -> RdrName -> SDoc+unknownSubordinateErr doc op -- Doc is "method of class" or+ -- "field of constructor"+ = quotes (ppr op) <+> text "is not a (visible)" <+> doc++badOrigBinding :: RdrName -> SDoc+badOrigBinding name+ = text "Illegal binding of built-in syntax:" <+> ppr (rdrNameOcc name)+ -- The rdrNameOcc is because we don't want to print Prelude.(,)++dupNamesErr :: Outputable n => (n -> SrcSpan) -> [n] -> RnM ()+dupNamesErr get_loc names+ = addErrAt big_loc $+ vcat [text "Conflicting definitions for" <+> quotes (ppr (head names)),+ locations]+ where+ locs = map get_loc names+ big_loc = foldr1 combineSrcSpans locs+ locations = text "Bound at:" <+> vcat (map ppr (sort locs))++kindSigErr :: Outputable a => a -> SDoc+kindSigErr thing+ = hang (text "Illegal kind signature for" <+> quotes (ppr thing))+ 2 (text "Perhaps you intended to use KindSignatures")++badQualBndrErr :: RdrName -> SDoc+badQualBndrErr rdr_name+ = text "Qualified name in binding position:" <+> ppr rdr_name++opDeclErr :: RdrName -> SDoc+opDeclErr n+ = hang (text "Illegal declaration of a type or class operator" <+> quotes (ppr n))+ 2 (text "Use TypeOperators to declare operators in type and declarations")++checkTupSize :: Int -> RnM ()+checkTupSize tup_size+ | tup_size <= mAX_TUPLE_SIZE+ = return ()+ | otherwise+ = addErr (sep [text "A" <+> int tup_size <> ptext (sLit "-tuple is too large for GHC"),+ nest 2 (parens (text "max size is" <+> int mAX_TUPLE_SIZE)),+ nest 2 (text "Workaround: use nested tuples or define a data type")])++{-+************************************************************************+* *+\subsection{Contexts for renaming errors}+* *+************************************************************************+-}++-- AZ:TODO: Change these all to be Name instead of RdrName.+-- Merge TcType.UserTypeContext in to it.+data HsDocContext+ = TypeSigCtx SDoc+ | PatCtx+ | SpecInstSigCtx+ | DefaultDeclCtx+ | ForeignDeclCtx (Located RdrName)+ | DerivDeclCtx+ | RuleCtx FastString+ | TyDataCtx (Located RdrName)+ | TySynCtx (Located RdrName)+ | TyFamilyCtx (Located RdrName)+ | FamPatCtx (Located RdrName) -- The patterns of a type/data family instance+ | ConDeclCtx [Located Name]+ | ClassDeclCtx (Located RdrName)+ | ExprWithTySigCtx+ | TypBrCtx+ | HsTypeCtx+ | GHCiCtx+ | SpliceTypeCtx (LHsType RdrName)+ | ClassInstanceCtx+ | VectDeclCtx (Located RdrName)+ | GenericCtx SDoc -- Maybe we want to use this more!++withHsDocContext :: HsDocContext -> SDoc -> SDoc+withHsDocContext ctxt doc = doc $$ inHsDocContext ctxt++inHsDocContext :: HsDocContext -> SDoc+inHsDocContext ctxt = text "In" <+> pprHsDocContext ctxt++pprHsDocContext :: HsDocContext -> SDoc+pprHsDocContext (GenericCtx doc) = doc+pprHsDocContext (TypeSigCtx doc) = text "the type signature for" <+> doc+pprHsDocContext PatCtx = text "a pattern type-signature"+pprHsDocContext SpecInstSigCtx = text "a SPECIALISE instance pragma"+pprHsDocContext DefaultDeclCtx = text "a `default' declaration"+pprHsDocContext DerivDeclCtx = text "a deriving declaration"+pprHsDocContext (RuleCtx name) = text "the transformation rule" <+> ftext name+pprHsDocContext (TyDataCtx tycon) = text "the data type declaration for" <+> quotes (ppr tycon)+pprHsDocContext (FamPatCtx tycon) = text "a type pattern of family instance for" <+> quotes (ppr tycon)+pprHsDocContext (TySynCtx name) = text "the declaration for type synonym" <+> quotes (ppr name)+pprHsDocContext (TyFamilyCtx name) = text "the declaration for type family" <+> quotes (ppr name)+pprHsDocContext (ClassDeclCtx name) = text "the declaration for class" <+> quotes (ppr name)+pprHsDocContext ExprWithTySigCtx = text "an expression type signature"+pprHsDocContext TypBrCtx = text "a Template-Haskell quoted type"+pprHsDocContext HsTypeCtx = text "a type argument"+pprHsDocContext GHCiCtx = text "GHCi input"+pprHsDocContext (SpliceTypeCtx hs_ty) = text "the spliced type" <+> quotes (ppr hs_ty)+pprHsDocContext ClassInstanceCtx = text "TcSplice.reifyInstances"++pprHsDocContext (ForeignDeclCtx name)+ = text "the foreign declaration for" <+> quotes (ppr name)+pprHsDocContext (ConDeclCtx [name])+ = text "the definition of data constructor" <+> quotes (ppr name)+pprHsDocContext (ConDeclCtx names)+ = text "the definition of data constructors" <+> interpp'SP names+pprHsDocContext (VectDeclCtx tycon)+ = text "the VECTORISE pragma for type constructor" <+> quotes (ppr tycon)
+ rename/RnExpr.hs view
@@ -0,0 +1,2064 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[RnExpr]{Renaming of expressions}++Basically dependency analysis.++Handles @Match@, @GRHSs@, @HsExpr@, and @Qualifier@ datatypes. In+general, all of these functions return a renamed thing, and a set of+free variables.+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE MultiWayIf #-}++module RnExpr (+ rnLExpr, rnExpr, rnStmts+ ) where++#include "HsVersions.h"++import RnBinds ( rnLocalBindsAndThen, rnLocalValBindsLHS, rnLocalValBindsRHS,+ rnMatchGroup, rnGRHS, makeMiniFixityEnv)+import HsSyn+import TcRnMonad+import Module ( getModule )+import RnEnv+import RnSplice ( rnBracket, rnSpliceExpr, checkThLocalName )+import RnTypes+import RnPat+import DynFlags+import PrelNames++import BasicTypes+import Name+import NameSet+import RdrName+import UniqSet+import Data.List+import Util+import ListSetOps ( removeDups )+import ErrUtils+import Outputable+import SrcLoc+import FastString+import Control.Monad+import TysWiredIn ( nilDataConName )+import qualified GHC.LanguageExtensions as LangExt++import Data.Ord+import Data.Array++{-+************************************************************************+* *+\subsubsection{Expressions}+* *+************************************************************************+-}++rnExprs :: [LHsExpr RdrName] -> RnM ([LHsExpr Name], FreeVars)+rnExprs ls = rnExprs' ls emptyUniqSet+ where+ rnExprs' [] acc = return ([], acc)+ rnExprs' (expr:exprs) acc =+ do { (expr', fvExpr) <- rnLExpr expr+ -- Now we do a "seq" on the free vars because typically it's small+ -- or empty, especially in very long lists of constants+ ; let acc' = acc `plusFV` fvExpr+ ; (exprs', fvExprs) <- acc' `seq` rnExprs' exprs acc'+ ; return (expr':exprs', fvExprs) }++-- Variables. We look up the variable and return the resulting name.++rnLExpr :: LHsExpr RdrName -> RnM (LHsExpr Name, FreeVars)+rnLExpr = wrapLocFstM rnExpr++rnExpr :: HsExpr RdrName -> RnM (HsExpr Name, FreeVars)++finishHsVar :: Located Name -> RnM (HsExpr Name, FreeVars)+-- Separated from rnExpr because it's also used+-- when renaming infix expressions+finishHsVar (L l name)+ = do { this_mod <- getModule+ ; when (nameIsLocalOrFrom this_mod name) $+ checkThLocalName name+ ; return (HsVar (L l name), unitFV name) }++rnUnboundVar :: RdrName -> RnM (HsExpr Name, FreeVars)+rnUnboundVar v+ = do { if isUnqual v+ then -- Treat this as a "hole"+ -- Do not fail right now; instead, return HsUnboundVar+ -- and let the type checker report the error+ do { let occ = rdrNameOcc v+ ; uv <- if startsWithUnderscore occ+ then return (TrueExprHole occ)+ else OutOfScope occ <$> getGlobalRdrEnv+ ; return (HsUnboundVar uv, emptyFVs) }++ else -- Fail immediately (qualified name)+ do { n <- reportUnboundName v+ ; return (HsVar (noLoc n), emptyFVs) } }++rnExpr (HsVar (L l v))+ = do { opt_DuplicateRecordFields <- xoptM LangExt.DuplicateRecordFields+ ; mb_name <- lookupOccRn_overloaded opt_DuplicateRecordFields v+ ; case mb_name of {+ Nothing -> rnUnboundVar v ;+ Just (Left name)+ | name == nilDataConName -- Treat [] as an ExplicitList, so that+ -- OverloadedLists works correctly+ -> rnExpr (ExplicitList placeHolderType Nothing [])++ | otherwise+ -> finishHsVar (L l name) ;+ Just (Right [f@(FieldOcc (L _ fn) s)]) ->+ return (HsRecFld (ambiguousFieldOcc (FieldOcc (L l fn) s))+ , unitFV (selectorFieldOcc f)) ;+ Just (Right fs@(_:_:_)) -> return (HsRecFld (Ambiguous (L l v)+ PlaceHolder)+ , mkFVs (map selectorFieldOcc fs));+ Just (Right []) -> panic "runExpr/HsVar" } }++rnExpr (HsIPVar v)+ = return (HsIPVar v, emptyFVs)++rnExpr (HsOverLabel _ v)+ = do { rebindable_on <- xoptM LangExt.RebindableSyntax+ ; if rebindable_on+ then do { fromLabel <- lookupOccRn (mkVarUnqual (fsLit "fromLabel"))+ ; return (HsOverLabel (Just fromLabel) v, unitFV fromLabel) }+ else return (HsOverLabel Nothing v, emptyFVs) }++rnExpr (HsLit lit@(HsString src s))+ = do { opt_OverloadedStrings <- xoptM LangExt.OverloadedStrings+ ; if opt_OverloadedStrings then+ rnExpr (HsOverLit (mkHsIsString src s placeHolderType))+ else do {+ ; rnLit lit+ ; return (HsLit lit, emptyFVs) } }++rnExpr (HsLit lit)+ = do { rnLit lit+ ; return (HsLit lit, emptyFVs) }++rnExpr (HsOverLit lit)+ = do { (lit', fvs) <- rnOverLit lit+ ; return (HsOverLit lit', fvs) }++rnExpr (HsApp fun arg)+ = do { (fun',fvFun) <- rnLExpr fun+ ; (arg',fvArg) <- rnLExpr arg+ ; return (HsApp fun' arg', fvFun `plusFV` fvArg) }++rnExpr (HsAppType fun arg)+ = do { (fun',fvFun) <- rnLExpr fun+ ; (arg',fvArg) <- rnHsWcType HsTypeCtx arg+ ; return (HsAppType fun' arg', fvFun `plusFV` fvArg) }++rnExpr (OpApp e1 op _ e2)+ = do { (e1', fv_e1) <- rnLExpr e1+ ; (e2', fv_e2) <- rnLExpr e2+ ; (op', fv_op) <- rnLExpr op++ -- Deal with fixity+ -- When renaming code synthesised from "deriving" declarations+ -- we used to avoid fixity stuff, but we can't easily tell any+ -- more, so I've removed the test. Adding HsPars in TcGenDeriv+ -- should prevent bad things happening.+ ; fixity <- case op' of+ L _ (HsVar (L _ n)) -> lookupFixityRn n+ L _ (HsRecFld f) -> lookupFieldFixityRn f+ _ -> return (Fixity NoSourceText minPrecedence InfixL)+ -- c.f. lookupFixity for unbound++ ; final_e <- mkOpAppRn e1' op' fixity e2'+ ; return (final_e, fv_e1 `plusFV` fv_op `plusFV` fv_e2) }++rnExpr (NegApp e _)+ = do { (e', fv_e) <- rnLExpr e+ ; (neg_name, fv_neg) <- lookupSyntaxName negateName+ ; final_e <- mkNegAppRn e' neg_name+ ; return (final_e, fv_e `plusFV` fv_neg) }++------------------------------------------+-- Template Haskell extensions+-- Don't ifdef-GHCI them because we want to fail gracefully+-- (not with an rnExpr crash) in a stage-1 compiler.+rnExpr e@(HsBracket br_body) = rnBracket e br_body++rnExpr (HsSpliceE splice) = rnSpliceExpr splice++---------------------------------------------+-- Sections+-- See Note [Parsing sections] in Parser.y+rnExpr (HsPar (L loc (section@(SectionL {}))))+ = do { (section', fvs) <- rnSection section+ ; return (HsPar (L loc section'), fvs) }++rnExpr (HsPar (L loc (section@(SectionR {}))))+ = do { (section', fvs) <- rnSection section+ ; return (HsPar (L loc section'), fvs) }++rnExpr (HsPar e)+ = do { (e', fvs_e) <- rnLExpr e+ ; return (HsPar e', fvs_e) }++rnExpr expr@(SectionL {})+ = do { addErr (sectionErr expr); rnSection expr }+rnExpr expr@(SectionR {})+ = do { addErr (sectionErr expr); rnSection expr }++---------------------------------------------+rnExpr (HsCoreAnn src ann expr)+ = do { (expr', fvs_expr) <- rnLExpr expr+ ; return (HsCoreAnn src ann expr', fvs_expr) }++rnExpr (HsSCC src lbl expr)+ = do { (expr', fvs_expr) <- rnLExpr expr+ ; return (HsSCC src lbl expr', fvs_expr) }+rnExpr (HsTickPragma src info srcInfo expr)+ = do { (expr', fvs_expr) <- rnLExpr expr+ ; return (HsTickPragma src info srcInfo expr', fvs_expr) }++rnExpr (HsLam matches)+ = do { (matches', fvMatch) <- rnMatchGroup LambdaExpr rnLExpr matches+ ; return (HsLam matches', fvMatch) }++rnExpr (HsLamCase matches)+ = do { (matches', fvs_ms) <- rnMatchGroup CaseAlt rnLExpr matches+ ; return (HsLamCase matches', fvs_ms) }++rnExpr (HsCase expr matches)+ = do { (new_expr, e_fvs) <- rnLExpr expr+ ; (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLExpr matches+ ; return (HsCase new_expr new_matches, e_fvs `plusFV` ms_fvs) }++rnExpr (HsLet (L l binds) expr)+ = rnLocalBindsAndThen binds $ \binds' _ -> do+ { (expr',fvExpr) <- rnLExpr expr+ ; return (HsLet (L l binds') expr', fvExpr) }++rnExpr (HsDo do_or_lc (L l stmts) _)+ = do { ((stmts', _), fvs) <-+ rnStmtsWithPostProcessing do_or_lc rnLExpr+ postProcessStmtsForApplicativeDo stmts+ (\ _ -> return ((), emptyFVs))+ ; return ( HsDo do_or_lc (L l stmts') placeHolderType, fvs ) }++rnExpr (ExplicitList _ _ exps)+ = do { opt_OverloadedLists <- xoptM LangExt.OverloadedLists+ ; (exps', fvs) <- rnExprs exps+ ; if opt_OverloadedLists+ then do {+ ; (from_list_n_name, fvs') <- lookupSyntaxName fromListNName+ ; return (ExplicitList placeHolderType (Just from_list_n_name) exps'+ , fvs `plusFV` fvs') }+ else+ return (ExplicitList placeHolderType Nothing exps', fvs) }++rnExpr (ExplicitPArr _ exps)+ = do { (exps', fvs) <- rnExprs exps+ ; return (ExplicitPArr placeHolderType exps', fvs) }++rnExpr (ExplicitTuple tup_args boxity)+ = do { checkTupleSection tup_args+ ; checkTupSize (length tup_args)+ ; (tup_args', fvs) <- mapAndUnzipM rnTupArg tup_args+ ; return (ExplicitTuple tup_args' boxity, plusFVs fvs) }+ where+ rnTupArg (L l (Present e)) = do { (e',fvs) <- rnLExpr e+ ; return (L l (Present e'), fvs) }+ rnTupArg (L l (Missing _)) = return (L l (Missing placeHolderType)+ , emptyFVs)++rnExpr (ExplicitSum alt arity expr _)+ = do { (expr', fvs) <- rnLExpr expr+ ; return (ExplicitSum alt arity expr' PlaceHolder, fvs) }++rnExpr (RecordCon { rcon_con_name = con_id+ , rcon_flds = rec_binds@(HsRecFields { rec_dotdot = dd }) })+ = do { con_lname@(L _ con_name) <- lookupLocatedOccRn con_id+ ; (flds, fvs) <- rnHsRecFields (HsRecFieldCon con_name) mk_hs_var rec_binds+ ; (flds', fvss) <- mapAndUnzipM rn_field flds+ ; let rec_binds' = HsRecFields { rec_flds = flds', rec_dotdot = dd }+ ; return (RecordCon { rcon_con_name = con_lname, rcon_flds = rec_binds'+ , rcon_con_expr = noPostTcExpr, rcon_con_like = PlaceHolder }+ , fvs `plusFV` plusFVs fvss `addOneFV` con_name) }+ where+ mk_hs_var l n = HsVar (L l n)+ rn_field (L l fld) = do { (arg', fvs) <- rnLExpr (hsRecFieldArg fld)+ ; return (L l (fld { hsRecFieldArg = arg' }), fvs) }++rnExpr (RecordUpd { rupd_expr = expr, rupd_flds = rbinds })+ = do { (expr', fvExpr) <- rnLExpr expr+ ; (rbinds', fvRbinds) <- rnHsRecUpdFields rbinds+ ; return (RecordUpd { rupd_expr = expr', rupd_flds = rbinds'+ , rupd_cons = PlaceHolder, rupd_in_tys = PlaceHolder+ , rupd_out_tys = PlaceHolder, rupd_wrap = PlaceHolder }+ , fvExpr `plusFV` fvRbinds) }++rnExpr (ExprWithTySig expr pty)+ = do { (pty', fvTy) <- rnHsSigWcType ExprWithTySigCtx pty+ ; (expr', fvExpr) <- bindSigTyVarsFV (hsWcScopedTvs pty') $+ rnLExpr expr+ ; return (ExprWithTySig expr' pty', fvExpr `plusFV` fvTy) }++rnExpr (HsIf _ p b1 b2)+ = do { (p', fvP) <- rnLExpr p+ ; (b1', fvB1) <- rnLExpr b1+ ; (b2', fvB2) <- rnLExpr b2+ ; (mb_ite, fvITE) <- lookupIfThenElse+ ; return (HsIf mb_ite p' b1' b2', plusFVs [fvITE, fvP, fvB1, fvB2]) }++rnExpr (HsMultiIf _ty alts)+ = do { (alts', fvs) <- mapFvRn (rnGRHS IfAlt rnLExpr) alts+ -- ; return (HsMultiIf ty alts', fvs) }+ ; return (HsMultiIf placeHolderType alts', fvs) }++rnExpr (ArithSeq _ _ seq)+ = do { opt_OverloadedLists <- xoptM LangExt.OverloadedLists+ ; (new_seq, fvs) <- rnArithSeq seq+ ; if opt_OverloadedLists+ then do {+ ; (from_list_name, fvs') <- lookupSyntaxName fromListName+ ; return (ArithSeq noPostTcExpr (Just from_list_name) new_seq, fvs `plusFV` fvs') }+ else+ return (ArithSeq noPostTcExpr Nothing new_seq, fvs) }++rnExpr (PArrSeq _ seq)+ = do { (new_seq, fvs) <- rnArithSeq seq+ ; return (PArrSeq noPostTcExpr new_seq, fvs) }++{-+These three are pattern syntax appearing in expressions.+Since all the symbols are reservedops we can simply reject them.+We return a (bogus) EWildPat in each case.+-}++rnExpr EWildPat = return (hsHoleExpr, emptyFVs) -- "_" is just a hole+rnExpr e@(EAsPat {})+ = do { opt_TypeApplications <- xoptM LangExt.TypeApplications+ ; let msg | opt_TypeApplications+ = "Type application syntax requires a space before '@'"+ | otherwise+ = "Did you mean to enable TypeApplications?"+ ; patSynErr e (text msg)+ }+rnExpr e@(EViewPat {}) = patSynErr e empty+rnExpr e@(ELazyPat {}) = patSynErr e empty++{-+************************************************************************+* *+ Static values+* *+************************************************************************++For the static form we check that the free variables are all top-level+value bindings. This is done by checking that the name is external or+wired-in. See the Notes about the NameSorts in Name.hs.+-}++rnExpr e@(HsStatic _ expr) = do+ (expr',fvExpr) <- rnLExpr expr+ stage <- getStage+ case stage of+ Splice _ -> addErr $ sep+ [ text "static forms cannot be used in splices:"+ , nest 2 $ ppr e+ ]+ _ -> return ()+ mod <- getModule+ let fvExpr' = filterNameSet (nameIsLocalOrFrom mod) fvExpr+ return (HsStatic fvExpr' expr', fvExpr)++{-+************************************************************************+* *+ Arrow notation+* *+************************************************************************+-}++rnExpr (HsProc pat body)+ = newArrowScope $+ rnPat ProcExpr pat $ \ pat' -> do+ { (body',fvBody) <- rnCmdTop body+ ; return (HsProc pat' body', fvBody) }++-- Ideally, these would be done in parsing, but to keep parsing simple, we do it here.+rnExpr e@(HsArrApp {}) = arrowFail e+rnExpr e@(HsArrForm {}) = arrowFail e++rnExpr other = pprPanic "rnExpr: unexpected expression" (ppr other)+ -- HsWrap++hsHoleExpr :: HsExpr id+hsHoleExpr = HsUnboundVar (TrueExprHole (mkVarOcc "_"))++arrowFail :: HsExpr RdrName -> RnM (HsExpr Name, FreeVars)+arrowFail e+ = do { addErr (vcat [ text "Arrow command found where an expression was expected:"+ , nest 2 (ppr e) ])+ -- Return a place-holder hole, so that we can carry on+ -- to report other errors+ ; return (hsHoleExpr, emptyFVs) }++----------------------+-- See Note [Parsing sections] in Parser.y+rnSection :: HsExpr RdrName -> RnM (HsExpr Name, FreeVars)+rnSection section@(SectionR op expr)+ = do { (op', fvs_op) <- rnLExpr op+ ; (expr', fvs_expr) <- rnLExpr expr+ ; checkSectionPrec InfixR section op' expr'+ ; return (SectionR op' expr', fvs_op `plusFV` fvs_expr) }++rnSection section@(SectionL expr op)+ = do { (expr', fvs_expr) <- rnLExpr expr+ ; (op', fvs_op) <- rnLExpr op+ ; checkSectionPrec InfixL section op' expr'+ ; return (SectionL expr' op', fvs_op `plusFV` fvs_expr) }++rnSection other = pprPanic "rnSection" (ppr other)++{-+************************************************************************+* *+ Arrow commands+* *+************************************************************************+-}++rnCmdArgs :: [LHsCmdTop RdrName] -> RnM ([LHsCmdTop Name], FreeVars)+rnCmdArgs [] = return ([], emptyFVs)+rnCmdArgs (arg:args)+ = do { (arg',fvArg) <- rnCmdTop arg+ ; (args',fvArgs) <- rnCmdArgs args+ ; return (arg':args', fvArg `plusFV` fvArgs) }++rnCmdTop :: LHsCmdTop RdrName -> RnM (LHsCmdTop Name, FreeVars)+rnCmdTop = wrapLocFstM rnCmdTop'+ where+ rnCmdTop' (HsCmdTop cmd _ _ _)+ = do { (cmd', fvCmd) <- rnLCmd cmd+ ; let cmd_names = [arrAName, composeAName, firstAName] +++ nameSetElemsStable (methodNamesCmd (unLoc cmd'))+ -- Generate the rebindable syntax for the monad+ ; (cmd_names', cmd_fvs) <- lookupSyntaxNames cmd_names++ ; return (HsCmdTop cmd' placeHolderType placeHolderType+ (cmd_names `zip` cmd_names'),+ fvCmd `plusFV` cmd_fvs) }++rnLCmd :: LHsCmd RdrName -> RnM (LHsCmd Name, FreeVars)+rnLCmd = wrapLocFstM rnCmd++rnCmd :: HsCmd RdrName -> RnM (HsCmd Name, FreeVars)++rnCmd (HsCmdArrApp arrow arg _ ho rtl)+ = do { (arrow',fvArrow) <- select_arrow_scope (rnLExpr arrow)+ ; (arg',fvArg) <- rnLExpr arg+ ; return (HsCmdArrApp arrow' arg' placeHolderType ho rtl,+ fvArrow `plusFV` fvArg) }+ where+ select_arrow_scope tc = case ho of+ HsHigherOrderApp -> tc+ HsFirstOrderApp -> escapeArrowScope tc+ -- See Note [Escaping the arrow scope] in TcRnTypes+ -- Before renaming 'arrow', use the environment of the enclosing+ -- proc for the (-<) case.+ -- Local bindings, inside the enclosing proc, are not in scope+ -- inside 'arrow'. In the higher-order case (-<<), they are.++-- infix form+rnCmd (HsCmdArrForm op _ (Just _) [arg1, arg2])+ = do { (op',fv_op) <- escapeArrowScope (rnLExpr op)+ ; let L _ (HsVar (L _ op_name)) = op'+ ; (arg1',fv_arg1) <- rnCmdTop arg1+ ; (arg2',fv_arg2) <- rnCmdTop arg2+ -- Deal with fixity+ ; fixity <- lookupFixityRn op_name+ ; final_e <- mkOpFormRn arg1' op' fixity arg2'+ ; return (final_e, fv_arg1 `plusFV` fv_op `plusFV` fv_arg2) }++rnCmd (HsCmdArrForm op f fixity cmds)+ = do { (op',fvOp) <- escapeArrowScope (rnLExpr op)+ ; (cmds',fvCmds) <- rnCmdArgs cmds+ ; return (HsCmdArrForm op' f fixity cmds', fvOp `plusFV` fvCmds) }++rnCmd (HsCmdApp fun arg)+ = do { (fun',fvFun) <- rnLCmd fun+ ; (arg',fvArg) <- rnLExpr arg+ ; return (HsCmdApp fun' arg', fvFun `plusFV` fvArg) }++rnCmd (HsCmdLam matches)+ = do { (matches', fvMatch) <- rnMatchGroup LambdaExpr rnLCmd matches+ ; return (HsCmdLam matches', fvMatch) }++rnCmd (HsCmdPar e)+ = do { (e', fvs_e) <- rnLCmd e+ ; return (HsCmdPar e', fvs_e) }++rnCmd (HsCmdCase expr matches)+ = do { (new_expr, e_fvs) <- rnLExpr expr+ ; (new_matches, ms_fvs) <- rnMatchGroup CaseAlt rnLCmd matches+ ; return (HsCmdCase new_expr new_matches, e_fvs `plusFV` ms_fvs) }++rnCmd (HsCmdIf _ p b1 b2)+ = do { (p', fvP) <- rnLExpr p+ ; (b1', fvB1) <- rnLCmd b1+ ; (b2', fvB2) <- rnLCmd b2+ ; (mb_ite, fvITE) <- lookupIfThenElse+ ; return (HsCmdIf mb_ite p' b1' b2', plusFVs [fvITE, fvP, fvB1, fvB2]) }++rnCmd (HsCmdLet (L l binds) cmd)+ = rnLocalBindsAndThen binds $ \ binds' _ -> do+ { (cmd',fvExpr) <- rnLCmd cmd+ ; return (HsCmdLet (L l binds') cmd', fvExpr) }++rnCmd (HsCmdDo (L l stmts) _)+ = do { ((stmts', _), fvs) <-+ rnStmts ArrowExpr rnLCmd stmts (\ _ -> return ((), emptyFVs))+ ; return ( HsCmdDo (L l stmts') placeHolderType, fvs ) }++rnCmd cmd@(HsCmdWrap {}) = pprPanic "rnCmd" (ppr cmd)++---------------------------------------------------+type CmdNeeds = FreeVars -- Only inhabitants are+ -- appAName, choiceAName, loopAName++-- find what methods the Cmd needs (loop, choice, apply)+methodNamesLCmd :: LHsCmd Name -> CmdNeeds+methodNamesLCmd = methodNamesCmd . unLoc++methodNamesCmd :: HsCmd Name -> CmdNeeds++methodNamesCmd (HsCmdArrApp _arrow _arg _ HsFirstOrderApp _rtl)+ = emptyFVs+methodNamesCmd (HsCmdArrApp _arrow _arg _ HsHigherOrderApp _rtl)+ = unitFV appAName+methodNamesCmd (HsCmdArrForm {}) = emptyFVs+methodNamesCmd (HsCmdWrap _ cmd) = methodNamesCmd cmd++methodNamesCmd (HsCmdPar c) = methodNamesLCmd c++methodNamesCmd (HsCmdIf _ _ c1 c2)+ = methodNamesLCmd c1 `plusFV` methodNamesLCmd c2 `addOneFV` choiceAName++methodNamesCmd (HsCmdLet _ c) = methodNamesLCmd c+methodNamesCmd (HsCmdDo (L _ stmts) _) = methodNamesStmts stmts+methodNamesCmd (HsCmdApp c _) = methodNamesLCmd c+methodNamesCmd (HsCmdLam match) = methodNamesMatch match++methodNamesCmd (HsCmdCase _ matches)+ = methodNamesMatch matches `addOneFV` choiceAName++--methodNamesCmd _ = emptyFVs+ -- Other forms can't occur in commands, but it's not convenient+ -- to error here so we just do what's convenient.+ -- The type checker will complain later++---------------------------------------------------+methodNamesMatch :: MatchGroup Name (LHsCmd Name) -> FreeVars+methodNamesMatch (MG { mg_alts = L _ ms })+ = plusFVs (map do_one ms)+ where+ do_one (L _ (Match _ _ _ grhss)) = methodNamesGRHSs grhss++-------------------------------------------------+-- gaw 2004+methodNamesGRHSs :: GRHSs Name (LHsCmd Name) -> FreeVars+methodNamesGRHSs (GRHSs grhss _) = plusFVs (map methodNamesGRHS grhss)++-------------------------------------------------++methodNamesGRHS :: Located (GRHS Name (LHsCmd Name)) -> CmdNeeds+methodNamesGRHS (L _ (GRHS _ rhs)) = methodNamesLCmd rhs++---------------------------------------------------+methodNamesStmts :: [Located (StmtLR Name Name (LHsCmd Name))] -> FreeVars+methodNamesStmts stmts = plusFVs (map methodNamesLStmt stmts)++---------------------------------------------------+methodNamesLStmt :: Located (StmtLR Name Name (LHsCmd Name)) -> FreeVars+methodNamesLStmt = methodNamesStmt . unLoc++methodNamesStmt :: StmtLR Name Name (LHsCmd Name) -> FreeVars+methodNamesStmt (LastStmt cmd _ _) = methodNamesLCmd cmd+methodNamesStmt (BodyStmt cmd _ _ _) = methodNamesLCmd cmd+methodNamesStmt (BindStmt _ cmd _ _ _) = methodNamesLCmd cmd+methodNamesStmt (RecStmt { recS_stmts = stmts }) =+ methodNamesStmts stmts `addOneFV` loopAName+methodNamesStmt (LetStmt {}) = emptyFVs+methodNamesStmt (ParStmt {}) = emptyFVs+methodNamesStmt (TransStmt {}) = emptyFVs+methodNamesStmt ApplicativeStmt{} = emptyFVs+ -- ParStmt and TransStmt can't occur in commands, but it's not+ -- convenient to error here so we just do what's convenient++{-+************************************************************************+* *+ Arithmetic sequences+* *+************************************************************************+-}++rnArithSeq :: ArithSeqInfo RdrName -> RnM (ArithSeqInfo Name, FreeVars)+rnArithSeq (From expr)+ = do { (expr', fvExpr) <- rnLExpr expr+ ; return (From expr', fvExpr) }++rnArithSeq (FromThen expr1 expr2)+ = do { (expr1', fvExpr1) <- rnLExpr expr1+ ; (expr2', fvExpr2) <- rnLExpr expr2+ ; return (FromThen expr1' expr2', fvExpr1 `plusFV` fvExpr2) }++rnArithSeq (FromTo expr1 expr2)+ = do { (expr1', fvExpr1) <- rnLExpr expr1+ ; (expr2', fvExpr2) <- rnLExpr expr2+ ; return (FromTo expr1' expr2', fvExpr1 `plusFV` fvExpr2) }++rnArithSeq (FromThenTo expr1 expr2 expr3)+ = do { (expr1', fvExpr1) <- rnLExpr expr1+ ; (expr2', fvExpr2) <- rnLExpr expr2+ ; (expr3', fvExpr3) <- rnLExpr expr3+ ; return (FromThenTo expr1' expr2' expr3',+ plusFVs [fvExpr1, fvExpr2, fvExpr3]) }++{-+************************************************************************+* *+\subsubsection{@Stmt@s: in @do@ expressions}+* *+************************************************************************+-}++{-+Note [Deterministic ApplicativeDo and RecursiveDo desugaring]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Both ApplicativeDo and RecursiveDo need to create tuples not+present in the source text.++For ApplicativeDo we create:++ (a,b,c) <- (\c b a -> (a,b,c)) <$>++For RecursiveDo we create:++ mfix (\ ~(a,b,c) -> do ...; return (a',b',c'))++The order of the components in those tuples needs to be stable+across recompilations, otherwise they can get optimized differently+and we end up with incompatible binaries.+To get a stable order we use nameSetElemsStable.+See Note [Deterministic UniqFM] to learn more about nondeterminism.+-}++-- | Rename some Stmts+rnStmts :: Outputable (body RdrName)+ => HsStmtContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -- ^ How to rename the body of each statement (e.g. rnLExpr)+ -> [LStmt RdrName (Located (body RdrName))]+ -- ^ Statements+ -> ([Name] -> RnM (thing, FreeVars))+ -- ^ if these statements scope over something, this renames it+ -- and returns the result.+ -> RnM (([LStmt Name (Located (body Name))], thing), FreeVars)+rnStmts ctxt rnBody = rnStmtsWithPostProcessing ctxt rnBody noPostProcessStmts++-- | like 'rnStmts' but applies a post-processing step to the renamed Stmts+rnStmtsWithPostProcessing+ :: Outputable (body RdrName)+ => HsStmtContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -- ^ How to rename the body of each statement (e.g. rnLExpr)+ -> (HsStmtContext Name+ -> [(LStmt Name (Located (body Name)), FreeVars)]+ -> RnM ([LStmt Name (Located (body Name))], FreeVars))+ -- ^ postprocess the statements+ -> [LStmt RdrName (Located (body RdrName))]+ -- ^ Statements+ -> ([Name] -> RnM (thing, FreeVars))+ -- ^ if these statements scope over something, this renames it+ -- and returns the result.+ -> RnM (([LStmt Name (Located (body Name))], thing), FreeVars)+rnStmtsWithPostProcessing ctxt rnBody ppStmts stmts thing_inside+ = do { ((stmts', thing), fvs) <-+ rnStmtsWithFreeVars ctxt rnBody stmts thing_inside+ ; (pp_stmts, fvs') <- ppStmts ctxt stmts'+ ; return ((pp_stmts, thing), fvs `plusFV` fvs')+ }++-- | maybe rearrange statements according to the ApplicativeDo transformation+postProcessStmtsForApplicativeDo+ :: HsStmtContext Name+ -> [(ExprLStmt Name, FreeVars)]+ -> RnM ([ExprLStmt Name], FreeVars)+postProcessStmtsForApplicativeDo ctxt stmts+ = do {+ -- rearrange the statements using ApplicativeStmt if+ -- -XApplicativeDo is on. Also strip out the FreeVars attached+ -- to each Stmt body.+ ado_is_on <- xoptM LangExt.ApplicativeDo+ ; let is_do_expr | DoExpr <- ctxt = True+ | otherwise = False+ ; if ado_is_on && is_do_expr+ then rearrangeForApplicativeDo ctxt stmts+ else noPostProcessStmts ctxt stmts }++-- | strip the FreeVars annotations from statements+noPostProcessStmts+ :: HsStmtContext Name+ -> [(LStmt Name (Located (body Name)), FreeVars)]+ -> RnM ([LStmt Name (Located (body Name))], FreeVars)+noPostProcessStmts _ stmts = return (map fst stmts, emptyNameSet)+++rnStmtsWithFreeVars :: Outputable (body RdrName)+ => HsStmtContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> [LStmt RdrName (Located (body RdrName))]+ -> ([Name] -> RnM (thing, FreeVars))+ -> RnM ( ([(LStmt Name (Located (body Name)), FreeVars)], thing)+ , FreeVars)+-- Each Stmt body is annotated with its FreeVars, so that+-- we can rearrange statements for ApplicativeDo.+--+-- Variables bound by the Stmts, and mentioned in thing_inside,+-- do not appear in the result FreeVars++rnStmtsWithFreeVars ctxt _ [] thing_inside+ = do { checkEmptyStmts ctxt+ ; (thing, fvs) <- thing_inside []+ ; return (([], thing), fvs) }++rnStmtsWithFreeVars MDoExpr rnBody stmts thing_inside -- Deal with mdo+ = -- Behave like do { rec { ...all but last... }; last }+ do { ((stmts1, (stmts2, thing)), fvs)+ <- rnStmt MDoExpr rnBody (noLoc $ mkRecStmt all_but_last) $ \ _ ->+ do { last_stmt' <- checkLastStmt MDoExpr last_stmt+ ; rnStmt MDoExpr rnBody last_stmt' thing_inside }+ ; return (((stmts1 ++ stmts2), thing), fvs) }+ where+ Just (all_but_last, last_stmt) = snocView stmts++rnStmtsWithFreeVars ctxt rnBody (lstmt@(L loc _) : lstmts) thing_inside+ | null lstmts+ = setSrcSpan loc $+ do { lstmt' <- checkLastStmt ctxt lstmt+ ; rnStmt ctxt rnBody lstmt' thing_inside }++ | otherwise+ = do { ((stmts1, (stmts2, thing)), fvs)+ <- setSrcSpan loc $+ do { checkStmt ctxt lstmt+ ; rnStmt ctxt rnBody lstmt $ \ bndrs1 ->+ rnStmtsWithFreeVars ctxt rnBody lstmts $ \ bndrs2 ->+ thing_inside (bndrs1 ++ bndrs2) }+ ; return (((stmts1 ++ stmts2), thing), fvs) }++----------------------++{-+Note [Failing pattern matches in Stmts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Many things desugar to HsStmts including monadic things like `do` and `mdo`+statements, pattern guards, and list comprehensions (see 'HsStmtContext' for an+exhaustive list). How we deal with pattern match failure is context-dependent.++ * In the case of list comprehensions and pattern guards we don't need any 'fail'+ function; the desugarer ignores the fail function field of 'BindStmt' entirely.+ * In the case of monadic contexts (e.g. monad comprehensions, do, and mdo+ expressions) we want pattern match failure to be desugared to the appropriate+ 'fail' function (either that of Monad or MonadFail, depending on whether+ -XMonadFailDesugaring is enabled.)++At one point we failed to make this distinction, leading to #11216.+-}++rnStmt :: Outputable (body RdrName)+ => HsStmtContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -- ^ How to rename the body of the statement+ -> LStmt RdrName (Located (body RdrName))+ -- ^ The statement+ -> ([Name] -> RnM (thing, FreeVars))+ -- ^ Rename the stuff that this statement scopes over+ -> RnM ( ([(LStmt Name (Located (body Name)), FreeVars)], thing)+ , FreeVars)+-- Variables bound by the Stmt, and mentioned in thing_inside,+-- do not appear in the result FreeVars++rnStmt ctxt rnBody (L loc (LastStmt body noret _)) thing_inside+ = do { (body', fv_expr) <- rnBody body+ ; (ret_op, fvs1) <- lookupStmtName ctxt returnMName+ ; (thing, fvs3) <- thing_inside []+ ; return (([(L loc (LastStmt body' noret ret_op), fv_expr)], thing),+ fv_expr `plusFV` fvs1 `plusFV` fvs3) }++rnStmt ctxt rnBody (L loc (BodyStmt body _ _ _)) thing_inside+ = do { (body', fv_expr) <- rnBody body+ ; (then_op, fvs1) <- lookupStmtName ctxt thenMName+ ; (guard_op, fvs2) <- if isListCompExpr ctxt+ then lookupStmtName ctxt guardMName+ else return (noSyntaxExpr, emptyFVs)+ -- Only list/parr/monad comprehensions use 'guard'+ -- Also for sub-stmts of same eg [ e | x<-xs, gd | blah ]+ -- Here "gd" is a guard+ ; (thing, fvs3) <- thing_inside []+ ; return (([(L loc (BodyStmt body'+ then_op guard_op placeHolderType), fv_expr)], thing),+ fv_expr `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) }++rnStmt ctxt rnBody (L loc (BindStmt pat body _ _ _)) thing_inside+ = do { (body', fv_expr) <- rnBody body+ -- The binders do not scope over the expression+ ; (bind_op, fvs1) <- lookupStmtName ctxt bindMName++ ; xMonadFailEnabled <- fmap (xopt LangExt.MonadFailDesugaring) getDynFlags+ ; let getFailFunction+ -- If the pattern is irrefutible (e.g.: wildcard, tuple,+ -- ~pat, etc.) we should not need to fail.+ | isIrrefutableHsPat pat+ = return (noSyntaxExpr, emptyFVs)+ -- For non-monadic contexts (e.g. guard patterns, list+ -- comprehensions, etc.) we should not need to fail.+ -- See Note [Failing pattern matches in Stmts]+ | not (isMonadFailStmtContext ctxt)+ = return (noSyntaxExpr, emptyFVs)+ | xMonadFailEnabled = lookupSyntaxName failMName+ | otherwise = lookupSyntaxName failMName_preMFP+ ; (fail_op, fvs2) <- getFailFunction++ ; rnPat (StmtCtxt ctxt) pat $ \ pat' -> do+ { (thing, fvs3) <- thing_inside (collectPatBinders pat')+ ; return (( [( L loc (BindStmt pat' body' bind_op fail_op PlaceHolder)+ , fv_expr )]+ , thing),+ fv_expr `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) }}+ -- fv_expr shouldn't really be filtered by the rnPatsAndThen+ -- but it does not matter because the names are unique++rnStmt _ _ (L loc (LetStmt (L l binds))) thing_inside+ = do { rnLocalBindsAndThen binds $ \binds' bind_fvs -> do+ { (thing, fvs) <- thing_inside (collectLocalBinders binds')+ ; return (([(L loc (LetStmt (L l binds')), bind_fvs)], thing), fvs) } }++rnStmt ctxt rnBody (L loc (RecStmt { recS_stmts = rec_stmts })) thing_inside+ = do { (return_op, fvs1) <- lookupStmtName ctxt returnMName+ ; (mfix_op, fvs2) <- lookupStmtName ctxt mfixName+ ; (bind_op, fvs3) <- lookupStmtName ctxt bindMName+ ; let empty_rec_stmt = emptyRecStmtName { recS_ret_fn = return_op+ , recS_mfix_fn = mfix_op+ , recS_bind_fn = bind_op }++ -- Step1: Bring all the binders of the mdo into scope+ -- (Remember that this also removes the binders from the+ -- finally-returned free-vars.)+ -- And rename each individual stmt, making a+ -- singleton segment. At this stage the FwdRefs field+ -- isn't finished: it's empty for all except a BindStmt+ -- for which it's the fwd refs within the bind itself+ -- (This set may not be empty, because we're in a recursive+ -- context.)+ ; rnRecStmtsAndThen rnBody rec_stmts $ \ segs -> do+ { let bndrs = nameSetElemsStable $+ foldr (unionNameSet . (\(ds,_,_,_) -> ds))+ emptyNameSet+ segs+ -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]+ ; (thing, fvs_later) <- thing_inside bndrs+ ; let (rec_stmts', fvs) = segmentRecStmts loc ctxt empty_rec_stmt segs fvs_later+ -- We aren't going to try to group RecStmts with+ -- ApplicativeDo, so attaching empty FVs is fine.+ ; return ( ((zip rec_stmts' (repeat emptyNameSet)), thing)+ , fvs `plusFV` fvs1 `plusFV` fvs2 `plusFV` fvs3) } }++rnStmt ctxt _ (L loc (ParStmt segs _ _ _)) thing_inside+ = do { (mzip_op, fvs1) <- lookupStmtNamePoly ctxt mzipName+ ; (bind_op, fvs2) <- lookupStmtName ctxt bindMName+ ; (return_op, fvs3) <- lookupStmtName ctxt returnMName+ ; ((segs', thing), fvs4) <- rnParallelStmts (ParStmtCtxt ctxt) return_op segs thing_inside+ ; return ( ([(L loc (ParStmt segs' mzip_op bind_op placeHolderType), fvs4)], thing)+ , fvs1 `plusFV` fvs2 `plusFV` fvs3 `plusFV` fvs4) }++rnStmt ctxt _ (L loc (TransStmt { trS_stmts = stmts, trS_by = by, trS_form = form+ , trS_using = using })) thing_inside+ = do { -- Rename the 'using' expression in the context before the transform is begun+ (using', fvs1) <- rnLExpr using++ -- Rename the stmts and the 'by' expression+ -- Keep track of the variables mentioned in the 'by' expression+ ; ((stmts', (by', used_bndrs, thing)), fvs2)+ <- rnStmts (TransStmtCtxt ctxt) rnLExpr stmts $ \ bndrs ->+ do { (by', fvs_by) <- mapMaybeFvRn rnLExpr by+ ; (thing, fvs_thing) <- thing_inside bndrs+ ; let fvs = fvs_by `plusFV` fvs_thing+ used_bndrs = filter (`elemNameSet` fvs) bndrs+ -- The paper (Fig 5) has a bug here; we must treat any free variable+ -- of the "thing inside", **or of the by-expression**, as used+ ; return ((by', used_bndrs, thing), fvs) }++ -- Lookup `return`, `(>>=)` and `liftM` for monad comprehensions+ ; (return_op, fvs3) <- lookupStmtName ctxt returnMName+ ; (bind_op, fvs4) <- lookupStmtName ctxt bindMName+ ; (fmap_op, fvs5) <- case form of+ ThenForm -> return (noExpr, emptyFVs)+ _ -> lookupStmtNamePoly ctxt fmapName++ ; let all_fvs = fvs1 `plusFV` fvs2 `plusFV` fvs3+ `plusFV` fvs4 `plusFV` fvs5+ bndr_map = used_bndrs `zip` used_bndrs+ -- See Note [TransStmt binder map] in HsExpr++ ; traceRn "rnStmt: implicitly rebound these used binders:" (ppr bndr_map)+ ; return (([(L loc (TransStmt { trS_stmts = stmts', trS_bndrs = bndr_map+ , trS_by = by', trS_using = using', trS_form = form+ , trS_ret = return_op, trS_bind = bind_op+ , trS_bind_arg_ty = PlaceHolder+ , trS_fmap = fmap_op }), fvs2)], thing), all_fvs) }++rnStmt _ _ (L _ ApplicativeStmt{}) _ =+ panic "rnStmt: ApplicativeStmt"++rnParallelStmts :: forall thing. HsStmtContext Name+ -> SyntaxExpr Name+ -> [ParStmtBlock RdrName RdrName]+ -> ([Name] -> RnM (thing, FreeVars))+ -> RnM (([ParStmtBlock Name Name], thing), FreeVars)+-- Note [Renaming parallel Stmts]+rnParallelStmts ctxt return_op segs thing_inside+ = do { orig_lcl_env <- getLocalRdrEnv+ ; rn_segs orig_lcl_env [] segs }+ where+ rn_segs :: LocalRdrEnv+ -> [Name] -> [ParStmtBlock RdrName RdrName]+ -> RnM (([ParStmtBlock Name Name], thing), FreeVars)+ rn_segs _ bndrs_so_far []+ = do { let (bndrs', dups) = removeDups cmpByOcc bndrs_so_far+ ; mapM_ dupErr dups+ ; (thing, fvs) <- bindLocalNames bndrs' (thing_inside bndrs')+ ; return (([], thing), fvs) }++ rn_segs env bndrs_so_far (ParStmtBlock stmts _ _ : segs)+ = do { ((stmts', (used_bndrs, segs', thing)), fvs)+ <- rnStmts ctxt rnLExpr stmts $ \ bndrs ->+ setLocalRdrEnv env $ do+ { ((segs', thing), fvs) <- rn_segs env (bndrs ++ bndrs_so_far) segs+ ; let used_bndrs = filter (`elemNameSet` fvs) bndrs+ ; return ((used_bndrs, segs', thing), fvs) }++ ; let seg' = ParStmtBlock stmts' used_bndrs return_op+ ; return ((seg':segs', thing), fvs) }++ cmpByOcc n1 n2 = nameOccName n1 `compare` nameOccName n2+ dupErr vs = addErr (text "Duplicate binding in parallel list comprehension for:"+ <+> quotes (ppr (head vs)))++lookupStmtName :: HsStmtContext Name -> Name -> RnM (SyntaxExpr Name, FreeVars)+-- Like lookupSyntaxName, but respects contexts+lookupStmtName ctxt n+ | rebindableContext ctxt+ = lookupSyntaxName n+ | otherwise+ = return (mkRnSyntaxExpr n, emptyFVs)++lookupStmtNamePoly :: HsStmtContext Name -> Name -> RnM (HsExpr Name, FreeVars)+lookupStmtNamePoly ctxt name+ | rebindableContext ctxt+ = do { rebindable_on <- xoptM LangExt.RebindableSyntax+ ; if rebindable_on+ then do { fm <- lookupOccRn (nameRdrName name)+ ; return (HsVar (noLoc fm), unitFV fm) }+ else not_rebindable }+ | otherwise+ = not_rebindable+ where+ not_rebindable = return (HsVar (noLoc name), emptyFVs)++-- | Is this a context where we respect RebindableSyntax?+-- but ListComp/PArrComp are never rebindable+-- Neither is ArrowExpr, which has its own desugarer in DsArrows+rebindableContext :: HsStmtContext Name -> Bool+rebindableContext ctxt = case ctxt of+ ListComp -> False+ PArrComp -> False+ ArrowExpr -> False+ PatGuard {} -> False++ DoExpr -> True+ MDoExpr -> True+ MonadComp -> True+ GhciStmtCtxt -> True -- I suppose?++ ParStmtCtxt c -> rebindableContext c -- Look inside to+ TransStmtCtxt c -> rebindableContext c -- the parent context++{-+Note [Renaming parallel Stmts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Renaming parallel statements is painful. Given, say+ [ a+c | a <- as, bs <- bss+ | c <- bs, a <- ds ]+Note that+ (a) In order to report "Defined but not used" about 'bs', we must+ rename each group of Stmts with a thing_inside whose FreeVars+ include at least {a,c}++ (b) We want to report that 'a' is illegally bound in both branches++ (c) The 'bs' in the second group must obviously not be captured by+ the binding in the first group++To satisfy (a) we nest the segements.+To satisfy (b) we check for duplicates just before thing_inside.+To satisfy (c) we reset the LocalRdrEnv each time.++************************************************************************+* *+\subsubsection{mdo expressions}+* *+************************************************************************+-}++type FwdRefs = NameSet+type Segment stmts = (Defs,+ Uses, -- May include defs+ FwdRefs, -- A subset of uses that are+ -- (a) used before they are bound in this segment, or+ -- (b) used here, and bound in subsequent segments+ stmts) -- Either Stmt or [Stmt]+++-- wrapper that does both the left- and right-hand sides+rnRecStmtsAndThen :: Outputable (body RdrName) =>+ (Located (body RdrName)+ -> RnM (Located (body Name), FreeVars))+ -> [LStmt RdrName (Located (body RdrName))]+ -- assumes that the FreeVars returned includes+ -- the FreeVars of the Segments+ -> ([Segment (LStmt Name (Located (body Name)))]+ -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+rnRecStmtsAndThen rnBody s cont+ = do { -- (A) Make the mini fixity env for all of the stmts+ fix_env <- makeMiniFixityEnv (collectRecStmtsFixities s)++ -- (B) Do the LHSes+ ; new_lhs_and_fv <- rn_rec_stmts_lhs fix_env s++ -- ...bring them and their fixities into scope+ ; let bound_names = collectLStmtsBinders (map fst new_lhs_and_fv)+ -- Fake uses of variables introduced implicitly (warning suppression, see #4404)+ implicit_uses = lStmtsImplicits (map fst new_lhs_and_fv)+ ; bindLocalNamesFV bound_names $+ addLocalFixities fix_env bound_names $ do++ -- (C) do the right-hand-sides and thing-inside+ { segs <- rn_rec_stmts rnBody bound_names new_lhs_and_fv+ ; (res, fvs) <- cont segs+ ; warnUnusedLocalBinds bound_names (fvs `unionNameSet` implicit_uses)+ ; return (res, fvs) }}++-- get all the fixity decls in any Let stmt+collectRecStmtsFixities :: [LStmtLR RdrName RdrName body] -> [LFixitySig RdrName]+collectRecStmtsFixities l =+ foldr (\ s -> \acc -> case s of+ (L _ (LetStmt (L _ (HsValBinds (ValBindsIn _ sigs))))) ->+ foldr (\ sig -> \ acc -> case sig of+ (L loc (FixSig s)) -> (L loc s) : acc+ _ -> acc) acc sigs+ _ -> acc) [] l++-- left-hand sides++rn_rec_stmt_lhs :: Outputable body => MiniFixityEnv+ -> LStmt RdrName body+ -- rename LHS, and return its FVs+ -- Warning: we will only need the FreeVars below in the case of a BindStmt,+ -- so we don't bother to compute it accurately in the other cases+ -> RnM [(LStmtLR Name RdrName body, FreeVars)]++rn_rec_stmt_lhs _ (L loc (BodyStmt body a b c))+ = return [(L loc (BodyStmt body a b c), emptyFVs)]++rn_rec_stmt_lhs _ (L loc (LastStmt body noret a))+ = return [(L loc (LastStmt body noret a), emptyFVs)]++rn_rec_stmt_lhs fix_env (L loc (BindStmt pat body a b t))+ = do+ -- should the ctxt be MDo instead?+ (pat', fv_pat) <- rnBindPat (localRecNameMaker fix_env) pat+ return [(L loc (BindStmt pat' body a b t),+ fv_pat)]++rn_rec_stmt_lhs _ (L _ (LetStmt (L _ binds@(HsIPBinds _))))+ = failWith (badIpBinds (text "an mdo expression") binds)++rn_rec_stmt_lhs fix_env (L loc (LetStmt (L l(HsValBinds binds))))+ = do (_bound_names, binds') <- rnLocalValBindsLHS fix_env binds+ return [(L loc (LetStmt (L l (HsValBinds binds'))),+ -- Warning: this is bogus; see function invariant+ emptyFVs+ )]++-- XXX Do we need to do something with the return and mfix names?+rn_rec_stmt_lhs fix_env (L _ (RecStmt { recS_stmts = stmts })) -- Flatten Rec inside Rec+ = rn_rec_stmts_lhs fix_env stmts++rn_rec_stmt_lhs _ stmt@(L _ (ParStmt {})) -- Syntactically illegal in mdo+ = pprPanic "rn_rec_stmt" (ppr stmt)++rn_rec_stmt_lhs _ stmt@(L _ (TransStmt {})) -- Syntactically illegal in mdo+ = pprPanic "rn_rec_stmt" (ppr stmt)++rn_rec_stmt_lhs _ stmt@(L _ (ApplicativeStmt {})) -- Shouldn't appear yet+ = pprPanic "rn_rec_stmt" (ppr stmt)++rn_rec_stmt_lhs _ (L _ (LetStmt (L _ EmptyLocalBinds)))+ = panic "rn_rec_stmt LetStmt EmptyLocalBinds"++rn_rec_stmts_lhs :: Outputable body => MiniFixityEnv+ -> [LStmt RdrName body]+ -> RnM [(LStmtLR Name RdrName body, FreeVars)]+rn_rec_stmts_lhs fix_env stmts+ = do { ls <- concatMapM (rn_rec_stmt_lhs fix_env) stmts+ ; let boundNames = collectLStmtsBinders (map fst ls)+ -- First do error checking: we need to check for dups here because we+ -- don't bind all of the variables from the Stmt at once+ -- with bindLocatedLocals.+ ; checkDupNames boundNames+ ; return ls }+++-- right-hand-sides++rn_rec_stmt :: (Outputable (body RdrName)) =>+ (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> [Name]+ -> (LStmtLR Name RdrName (Located (body RdrName)), FreeVars)+ -> RnM [Segment (LStmt Name (Located (body Name)))]+ -- Rename a Stmt that is inside a RecStmt (or mdo)+ -- Assumes all binders are already in scope+ -- Turns each stmt into a singleton Stmt+rn_rec_stmt rnBody _ (L loc (LastStmt body noret _), _)+ = do { (body', fv_expr) <- rnBody body+ ; (ret_op, fvs1) <- lookupSyntaxName returnMName+ ; return [(emptyNameSet, fv_expr `plusFV` fvs1, emptyNameSet,+ L loc (LastStmt body' noret ret_op))] }++rn_rec_stmt rnBody _ (L loc (BodyStmt body _ _ _), _)+ = do { (body', fvs) <- rnBody body+ ; (then_op, fvs1) <- lookupSyntaxName thenMName+ ; return [(emptyNameSet, fvs `plusFV` fvs1, emptyNameSet,+ L loc (BodyStmt body' then_op noSyntaxExpr placeHolderType))] }++rn_rec_stmt rnBody _ (L loc (BindStmt pat' body _ _ _), fv_pat)+ = do { (body', fv_expr) <- rnBody body+ ; (bind_op, fvs1) <- lookupSyntaxName bindMName++ ; xMonadFailEnabled <- fmap (xopt LangExt.MonadFailDesugaring) getDynFlags+ ; let failFunction | xMonadFailEnabled = failMName+ | otherwise = failMName_preMFP+ ; (fail_op, fvs2) <- lookupSyntaxName failFunction++ ; let bndrs = mkNameSet (collectPatBinders pat')+ fvs = fv_expr `plusFV` fv_pat `plusFV` fvs1 `plusFV` fvs2+ ; return [(bndrs, fvs, bndrs `intersectNameSet` fvs,+ L loc (BindStmt pat' body' bind_op fail_op PlaceHolder))] }++rn_rec_stmt _ _ (L _ (LetStmt (L _ binds@(HsIPBinds _))), _)+ = failWith (badIpBinds (text "an mdo expression") binds)++rn_rec_stmt _ all_bndrs (L loc (LetStmt (L l (HsValBinds binds'))), _)+ = do { (binds', du_binds) <- rnLocalValBindsRHS (mkNameSet all_bndrs) binds'+ -- fixities and unused are handled above in rnRecStmtsAndThen+ ; let fvs = allUses du_binds+ ; return [(duDefs du_binds, fvs, emptyNameSet,+ L loc (LetStmt (L l (HsValBinds binds'))))] }++-- no RecStmt case because they get flattened above when doing the LHSes+rn_rec_stmt _ _ stmt@(L _ (RecStmt {}), _)+ = pprPanic "rn_rec_stmt: RecStmt" (ppr stmt)++rn_rec_stmt _ _ stmt@(L _ (ParStmt {}), _) -- Syntactically illegal in mdo+ = pprPanic "rn_rec_stmt: ParStmt" (ppr stmt)++rn_rec_stmt _ _ stmt@(L _ (TransStmt {}), _) -- Syntactically illegal in mdo+ = pprPanic "rn_rec_stmt: TransStmt" (ppr stmt)++rn_rec_stmt _ _ (L _ (LetStmt (L _ EmptyLocalBinds)), _)+ = panic "rn_rec_stmt: LetStmt EmptyLocalBinds"++rn_rec_stmt _ _ stmt@(L _ (ApplicativeStmt {}), _)+ = pprPanic "rn_rec_stmt: ApplicativeStmt" (ppr stmt)++rn_rec_stmts :: Outputable (body RdrName) =>+ (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> [Name]+ -> [(LStmtLR Name RdrName (Located (body RdrName)), FreeVars)]+ -> RnM [Segment (LStmt Name (Located (body Name)))]+rn_rec_stmts rnBody bndrs stmts+ = do { segs_s <- mapM (rn_rec_stmt rnBody bndrs) stmts+ ; return (concat segs_s) }++---------------------------------------------+segmentRecStmts :: SrcSpan -> HsStmtContext Name+ -> Stmt Name body+ -> [Segment (LStmt Name body)] -> FreeVars+ -> ([LStmt Name body], FreeVars)++segmentRecStmts loc ctxt empty_rec_stmt segs fvs_later+ | null segs+ = ([], fvs_later)++ | MDoExpr <- ctxt+ = segsToStmts empty_rec_stmt grouped_segs fvs_later+ -- Step 4: Turn the segments into Stmts+ -- Use RecStmt when and only when there are fwd refs+ -- Also gather up the uses from the end towards the+ -- start, so we can tell the RecStmt which things are+ -- used 'after' the RecStmt++ | otherwise+ = ([ L loc $+ empty_rec_stmt { recS_stmts = ss+ , recS_later_ids = nameSetElemsStable+ (defs `intersectNameSet` fvs_later)+ , recS_rec_ids = nameSetElemsStable+ (defs `intersectNameSet` uses) }]+ -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]+ , uses `plusFV` fvs_later)++ where+ (defs_s, uses_s, _, ss) = unzip4 segs+ defs = plusFVs defs_s+ uses = plusFVs uses_s++ -- Step 2: Fill in the fwd refs.+ -- The segments are all singletons, but their fwd-ref+ -- field mentions all the things used by the segment+ -- that are bound after their use+ segs_w_fwd_refs = addFwdRefs segs++ -- Step 3: Group together the segments to make bigger segments+ -- Invariant: in the result, no segment uses a variable+ -- bound in a later segment+ grouped_segs = glomSegments ctxt segs_w_fwd_refs++----------------------------+addFwdRefs :: [Segment a] -> [Segment a]+-- So far the segments only have forward refs *within* the Stmt+-- (which happens for bind: x <- ...x...)+-- This function adds the cross-seg fwd ref info++addFwdRefs segs+ = fst (foldr mk_seg ([], emptyNameSet) segs)+ where+ mk_seg (defs, uses, fwds, stmts) (segs, later_defs)+ = (new_seg : segs, all_defs)+ where+ new_seg = (defs, uses, new_fwds, stmts)+ all_defs = later_defs `unionNameSet` defs+ new_fwds = fwds `unionNameSet` (uses `intersectNameSet` later_defs)+ -- Add the downstream fwd refs here++{-+Note [Segmenting mdo]+~~~~~~~~~~~~~~~~~~~~~+NB. June 7 2012: We only glom segments that appear in an explicit mdo;+and leave those found in "do rec"'s intact. See+http://ghc.haskell.org/trac/ghc/ticket/4148 for the discussion+leading to this design choice. Hence the test in segmentRecStmts.++Note [Glomming segments]+~~~~~~~~~~~~~~~~~~~~~~~~+Glomming the singleton segments of an mdo into minimal recursive groups.++At first I thought this was just strongly connected components, but+there's an important constraint: the order of the stmts must not change.++Consider+ mdo { x <- ...y...+ p <- z+ y <- ...x...+ q <- x+ z <- y+ r <- x }++Here, the first stmt mention 'y', which is bound in the third.+But that means that the innocent second stmt (p <- z) gets caught+up in the recursion. And that in turn means that the binding for+'z' has to be included... and so on.++Start at the tail { r <- x }+Now add the next one { z <- y ; r <- x }+Now add one more { q <- x ; z <- y ; r <- x }+Now one more... but this time we have to group a bunch into rec+ { rec { y <- ...x... ; q <- x ; z <- y } ; r <- x }+Now one more, which we can add on without a rec+ { p <- z ;+ rec { y <- ...x... ; q <- x ; z <- y } ;+ r <- x }+Finally we add the last one; since it mentions y we have to+glom it together with the first two groups+ { rec { x <- ...y...; p <- z ; y <- ...x... ;+ q <- x ; z <- y } ;+ r <- x }+-}++glomSegments :: HsStmtContext Name+ -> [Segment (LStmt Name body)]+ -> [Segment [LStmt Name body]] -- Each segment has a non-empty list of Stmts+-- See Note [Glomming segments]++glomSegments _ [] = []+glomSegments ctxt ((defs,uses,fwds,stmt) : segs)+ -- Actually stmts will always be a singleton+ = (seg_defs, seg_uses, seg_fwds, seg_stmts) : others+ where+ segs' = glomSegments ctxt segs+ (extras, others) = grab uses segs'+ (ds, us, fs, ss) = unzip4 extras++ seg_defs = plusFVs ds `plusFV` defs+ seg_uses = plusFVs us `plusFV` uses+ seg_fwds = plusFVs fs `plusFV` fwds+ seg_stmts = stmt : concat ss++ grab :: NameSet -- The client+ -> [Segment a]+ -> ([Segment a], -- Needed by the 'client'+ [Segment a]) -- Not needed by the client+ -- The result is simply a split of the input+ grab uses dus+ = (reverse yeses, reverse noes)+ where+ (noes, yeses) = span not_needed (reverse dus)+ not_needed (defs,_,_,_) = not (intersectsNameSet defs uses)++----------------------------------------------------+segsToStmts :: Stmt Name body -- A RecStmt with the SyntaxOps filled in+ -> [Segment [LStmt Name body]] -- Each Segment has a non-empty list of Stmts+ -> FreeVars -- Free vars used 'later'+ -> ([LStmt Name body], FreeVars)++segsToStmts _ [] fvs_later = ([], fvs_later)+segsToStmts empty_rec_stmt ((defs, uses, fwds, ss) : segs) fvs_later+ = ASSERT( not (null ss) )+ (new_stmt : later_stmts, later_uses `plusFV` uses)+ where+ (later_stmts, later_uses) = segsToStmts empty_rec_stmt segs fvs_later+ new_stmt | non_rec = head ss+ | otherwise = L (getLoc (head ss)) rec_stmt+ rec_stmt = empty_rec_stmt { recS_stmts = ss+ , recS_later_ids = nameSetElemsStable used_later+ , recS_rec_ids = nameSetElemsStable fwds }+ -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]+ non_rec = isSingleton ss && isEmptyNameSet fwds+ used_later = defs `intersectNameSet` later_uses+ -- The ones needed after the RecStmt++{-+************************************************************************+* *+ApplicativeDo+* *+************************************************************************++Note [ApplicativeDo]++= Example =++For a sequence of statements++ do+ x <- A+ y <- B x+ z <- C+ return (f x y z)++We want to transform this to++ (\(x,y) z -> f x y z) <$> (do x <- A; y <- B x; return (x,y)) <*> C++It would be easy to notice that "y <- B x" and "z <- C" are+independent and do something like this:++ do+ x <- A+ (y,z) <- (,) <$> B x <*> C+ return (f x y z)++But this isn't enough! A and C were also independent, and this+transformation loses the ability to do A and C in parallel.++The algorithm works by first splitting the sequence of statements into+independent "segments", and a separate "tail" (the final statement). In+our example above, the segements would be++ [ x <- A+ , y <- B x ]++ [ z <- C ]++and the tail is:++ return (f x y z)++Then we take these segments and make an Applicative expression from them:++ (\(x,y) z -> return (f x y z))+ <$> do { x <- A; y <- B x; return (x,y) }+ <*> C++Finally, we recursively apply the transformation to each segment, to+discover any nested parallelism.++= Syntax & spec =++ expr ::= ... | do {stmt_1; ..; stmt_n} expr | ...++ stmt ::= pat <- expr+ | (arg_1 | ... | arg_n) -- applicative composition, n>=1+ | ... -- other kinds of statement (e.g. let)++ arg ::= pat <- expr+ | {stmt_1; ..; stmt_n} {var_1..var_n}++(note that in the actual implementation,the expr in a do statement is+represented by a LastStmt as the final stmt, this is just a+representational issue and may change later.)++== Transformation to introduce applicative stmts ==++ado {} tail = tail+ado {pat <- expr} {return expr'} = (mkArg(pat <- expr)); return expr'+ado {one} tail = one : tail+ado stmts tail+ | n == 1 = ado before (ado after tail)+ where (before,after) = split(stmts_1)+ | n > 1 = (mkArg(stmts_1) | ... | mkArg(stmts_n)); tail+ where+ {stmts_1 .. stmts_n} = segments(stmts)++segments(stmts) =+ -- divide stmts into segments with no interdependencies++mkArg({pat <- expr}) = (pat <- expr)+mkArg({stmt_1; ...; stmt_n}) =+ {stmt_1; ...; stmt_n} {vars(stmt_1) u .. u vars(stmt_n)}++split({stmt_1; ..; stmt_n) =+ ({stmt_1; ..; stmt_i}, {stmt_i+1; ..; stmt_n})+ -- 1 <= i <= n+ -- i is a good place to insert a bind++== Desugaring for do ==++dsDo {} expr = expr++dsDo {pat <- rhs; stmts} expr =+ rhs >>= \pat -> dsDo stmts expr++dsDo {(arg_1 | ... | arg_n)} (return expr) =+ (\argpat (arg_1) .. argpat(arg_n) -> expr)+ <$> argexpr(arg_1)+ <*> ...+ <*> argexpr(arg_n)++dsDo {(arg_1 | ... | arg_n); stmts} expr =+ join (\argpat (arg_1) .. argpat(arg_n) -> dsDo stmts expr)+ <$> argexpr(arg_1)+ <*> ...+ <*> argexpr(arg_n)++-}++-- | The 'Name's of @return@ and @pure@. These may not be 'returnName' and+-- 'pureName' due to @RebindableSyntax@.+data MonadNames = MonadNames { return_name, pure_name :: Name }++-- | rearrange a list of statements using ApplicativeDoStmt. See+-- Note [ApplicativeDo].+rearrangeForApplicativeDo+ :: HsStmtContext Name+ -> [(ExprLStmt Name, FreeVars)]+ -> RnM ([ExprLStmt Name], FreeVars)++rearrangeForApplicativeDo _ [] = return ([], emptyNameSet)+rearrangeForApplicativeDo _ [(one,_)] = return ([one], emptyNameSet)+rearrangeForApplicativeDo ctxt stmts0 = do+ optimal_ado <- goptM Opt_OptimalApplicativeDo+ let stmt_tree | optimal_ado = mkStmtTreeOptimal stmts+ | otherwise = mkStmtTreeHeuristic stmts+ return_name <- lookupSyntaxName' returnMName+ pure_name <- lookupSyntaxName' pureAName+ let monad_names = MonadNames { return_name = return_name+ , pure_name = pure_name }+ stmtTreeToStmts monad_names ctxt stmt_tree [last] last_fvs+ where+ (stmts,(last,last_fvs)) = findLast stmts0+ findLast [] = error "findLast"+ findLast [last] = ([],last)+ findLast (x:xs) = (x:rest,last) where (rest,last) = findLast xs++-- | A tree of statements using a mixture of applicative and bind constructs.+data StmtTree a+ = StmtTreeOne a+ | StmtTreeBind (StmtTree a) (StmtTree a)+ | StmtTreeApplicative [StmtTree a]++flattenStmtTree :: StmtTree a -> [a]+flattenStmtTree t = go t []+ where+ go (StmtTreeOne a) as = a : as+ go (StmtTreeBind l r) as = go l (go r as)+ go (StmtTreeApplicative ts) as = foldr go as ts++type ExprStmtTree = StmtTree (ExprLStmt Name, FreeVars)+type Cost = Int++-- | Turn a sequence of statements into an ExprStmtTree using a+-- heuristic algorithm. /O(n^2)/+mkStmtTreeHeuristic :: [(ExprLStmt Name, FreeVars)] -> ExprStmtTree+mkStmtTreeHeuristic [one] = StmtTreeOne one+mkStmtTreeHeuristic stmts =+ case segments stmts of+ [one] -> split one+ segs -> StmtTreeApplicative (map split segs)+ where+ split [one] = StmtTreeOne one+ split stmts =+ StmtTreeBind (mkStmtTreeHeuristic before) (mkStmtTreeHeuristic after)+ where (before, after) = splitSegment stmts++-- | Turn a sequence of statements into an ExprStmtTree optimally,+-- using dynamic programming. /O(n^3)/+mkStmtTreeOptimal :: [(ExprLStmt Name, FreeVars)] -> ExprStmtTree+mkStmtTreeOptimal stmts =+ ASSERT(not (null stmts)) -- the empty case is handled by the caller;+ -- we don't support empty StmtTrees.+ fst (arr ! (0,n))+ where+ n = length stmts - 1+ stmt_arr = listArray (0,n) stmts++ -- lazy cache of optimal trees for subsequences of the input+ arr :: Array (Int,Int) (ExprStmtTree, Cost)+ arr = array ((0,0),(n,n))+ [ ((lo,hi), tree lo hi)+ | lo <- [0..n]+ , hi <- [lo..n] ]++ -- compute the optimal tree for the sequence [lo..hi]+ tree lo hi+ | hi == lo = (StmtTreeOne (stmt_arr ! lo), 1)+ | otherwise =+ case segments [ stmt_arr ! i | i <- [lo..hi] ] of+ [] -> panic "mkStmtTree"+ [_one] -> split lo hi+ segs -> (StmtTreeApplicative trees, maximum costs)+ where+ bounds = scanl (\(_,hi) a -> (hi+1, hi + length a)) (0,lo-1) segs+ (trees,costs) = unzip (map (uncurry split) (tail bounds))++ -- find the best place to split the segment [lo..hi]+ split :: Int -> Int -> (ExprStmtTree, Cost)+ split lo hi+ | hi == lo = (StmtTreeOne (stmt_arr ! lo), 1)+ | otherwise = (StmtTreeBind before after, c1+c2)+ where+ -- As per the paper, for a sequence s1...sn, we want to find+ -- the split with the minimum cost, where the cost is the+ -- sum of the cost of the left and right subsequences.+ --+ -- As an optimisation (also in the paper) if the cost of+ -- s1..s(n-1) is different from the cost of s2..sn, we know+ -- that the optimal solution is the lower of the two. Only+ -- in the case that these two have the same cost do we need+ -- to do the exhaustive search.+ --+ ((before,c1),(after,c2))+ | hi - lo == 1+ = ((StmtTreeOne (stmt_arr ! lo), 1),+ (StmtTreeOne (stmt_arr ! hi), 1))+ | left_cost < right_cost+ = ((left,left_cost), (StmtTreeOne (stmt_arr ! hi), 1))+ | otherwise -- left_cost > right_cost+ = ((StmtTreeOne (stmt_arr ! lo), 1), (right,right_cost))+ | otherwise = minimumBy (comparing cost) alternatives+ where+ (left, left_cost) = arr ! (lo,hi-1)+ (right, right_cost) = arr ! (lo+1,hi)+ cost ((_,c1),(_,c2)) = c1 + c2+ alternatives = [ (arr ! (lo,k), arr ! (k+1,hi))+ | k <- [lo .. hi-1] ]+++-- | Turn the ExprStmtTree back into a sequence of statements, using+-- ApplicativeStmt where necessary.+stmtTreeToStmts+ :: MonadNames+ -> HsStmtContext Name+ -> ExprStmtTree+ -> [ExprLStmt Name] -- ^ the "tail"+ -> FreeVars -- ^ free variables of the tail+ -> RnM ( [ExprLStmt Name] -- ( output statements,+ , FreeVars ) -- , things we needed++-- If we have a single bind, and we can do it without a join, transform+-- to an ApplicativeStmt. This corresponds to the rule+-- dsBlock [pat <- rhs] (return expr) = expr <$> rhs+-- In the spec, but we do it here rather than in the desugarer,+-- because we need the typechecker to typecheck the <$> form rather than+-- the bind form, which would give rise to a Monad constraint.+stmtTreeToStmts monad_names ctxt (StmtTreeOne (L _ (BindStmt pat rhs _ _ _),_))+ tail _tail_fvs+ | not (isStrictPattern pat), (False,tail') <- needJoin monad_names tail+ -- See Note [ApplicativeDo and strict patterns]+ = mkApplicativeStmt ctxt [ApplicativeArgOne pat rhs] False tail'++stmtTreeToStmts _monad_names _ctxt (StmtTreeOne (s,_)) tail _tail_fvs =+ return (s : tail, emptyNameSet)++stmtTreeToStmts monad_names ctxt (StmtTreeBind before after) tail tail_fvs = do+ (stmts1, fvs1) <- stmtTreeToStmts monad_names ctxt after tail tail_fvs+ let tail1_fvs = unionNameSets (tail_fvs : map snd (flattenStmtTree after))+ (stmts2, fvs2) <- stmtTreeToStmts monad_names ctxt before stmts1 tail1_fvs+ return (stmts2, fvs1 `plusFV` fvs2)++stmtTreeToStmts monad_names ctxt (StmtTreeApplicative trees) tail tail_fvs = do+ pairs <- mapM (stmtTreeArg ctxt tail_fvs) trees+ let (stmts', fvss) = unzip pairs+ let (need_join, tail') = needJoin monad_names tail+ (stmts, fvs) <- mkApplicativeStmt ctxt stmts' need_join tail'+ return (stmts, unionNameSets (fvs:fvss))+ where+ stmtTreeArg _ctxt _tail_fvs (StmtTreeOne (L _ (BindStmt pat exp _ _ _), _)) =+ return (ApplicativeArgOne pat exp, emptyFVs)+ stmtTreeArg ctxt tail_fvs tree = do+ let stmts = flattenStmtTree tree+ pvarset = mkNameSet (concatMap (collectStmtBinders.unLoc.fst) stmts)+ `intersectNameSet` tail_fvs+ pvars = nameSetElemsStable pvarset+ -- See Note [Deterministic ApplicativeDo and RecursiveDo desugaring]+ pat = mkBigLHsVarPatTup pvars+ tup = mkBigLHsVarTup pvars+ (stmts',fvs2) <- stmtTreeToStmts monad_names ctxt tree [] pvarset+ (mb_ret, fvs1) <-+ if | L _ ApplicativeStmt{} <- last stmts' ->+ return (unLoc tup, emptyNameSet)+ | otherwise -> do+ (ret,fvs) <- lookupStmtNamePoly ctxt returnMName+ return (HsApp (noLoc ret) tup, fvs)+ return ( ApplicativeArgMany stmts' mb_ret pat+ , fvs1 `plusFV` fvs2)+++-- | Divide a sequence of statements into segments, where no segment+-- depends on any variables defined by a statement in another segment.+segments+ :: [(ExprLStmt Name, FreeVars)]+ -> [[(ExprLStmt Name, FreeVars)]]+segments stmts = map fst $ merge $ reverse $ map reverse $ walk (reverse stmts)+ where+ allvars = mkNameSet (concatMap (collectStmtBinders.unLoc.fst) stmts)++ -- We would rather not have a segment that just has LetStmts in+ -- it, so combine those with an adjacent segment where possible.+ merge [] = []+ merge (seg : segs)+ = case rest of+ [] -> [(seg,all_lets)]+ ((s,s_lets):ss) | all_lets || s_lets+ -> (seg ++ s, all_lets && s_lets) : ss+ _otherwise -> (seg,all_lets) : rest+ where+ rest = merge segs+ all_lets = all (isLetStmt . fst) seg++ -- walk splits the statement sequence into segments, traversing+ -- the sequence from the back to the front, and keeping track of+ -- the set of free variables of the current segment. Whenever+ -- this set of free variables is empty, we have a complete segment.+ walk :: [(ExprLStmt Name, FreeVars)] -> [[(ExprLStmt Name, FreeVars)]]+ walk [] = []+ walk ((stmt,fvs) : stmts) = ((stmt,fvs) : seg) : walk rest+ where (seg,rest) = chunter fvs' stmts+ (_, fvs') = stmtRefs stmt fvs++ chunter _ [] = ([], [])+ chunter vars ((stmt,fvs) : rest)+ | not (isEmptyNameSet vars)+ || isStrictPatternBind stmt+ -- See Note [ApplicativeDo and strict patterns]+ = ((stmt,fvs) : chunk, rest')+ where (chunk,rest') = chunter vars' rest+ (pvars, evars) = stmtRefs stmt fvs+ vars' = (vars `minusNameSet` pvars) `unionNameSet` evars+ chunter _ rest = ([], rest)++ stmtRefs stmt fvs+ | isLetStmt stmt = (pvars, fvs' `minusNameSet` pvars)+ | otherwise = (pvars, fvs')+ where fvs' = fvs `intersectNameSet` allvars+ pvars = mkNameSet (collectStmtBinders (unLoc stmt))++ isStrictPatternBind :: ExprLStmt Name -> Bool+ isStrictPatternBind (L _ (BindStmt pat _ _ _ _)) = isStrictPattern pat+ isStrictPatternBind _ = False++{-+Note [ApplicativeDo and strict patterns]++A strict pattern match is really a dependency. For example,++do+ (x,y) <- A+ z <- B+ return C++The pattern (_,_) must be matched strictly before we do B. If we+allowed this to be transformed into++ (\(x,y) -> \z -> C) <$> A <*> B++then it could be lazier than the standard desuraging using >>=. See #13875+for more examples.++Thus, whenever we have a strict pattern match, we treat it as a+dependency between that statement and the following one. The+dependency prevents those two statements from being performed "in+parallel" in an ApplicativeStmt, but doesn't otherwise affect what we+can do with the rest of the statements in the same "do" expression.+-}++isStrictPattern :: LPat id -> Bool+isStrictPattern (L _ pat) =+ case pat of+ WildPat{} -> False+ VarPat{} -> False+ LazyPat{} -> False+ AsPat _ p -> isStrictPattern p+ ParPat p -> isStrictPattern p+ ViewPat _ p _ -> isStrictPattern p+ SigPatIn p _ -> isStrictPattern p+ SigPatOut p _ -> isStrictPattern p+ BangPat{} -> True+ TuplePat{} -> True+ SumPat{} -> True+ PArrPat{} -> True+ ConPatIn{} -> True+ ConPatOut{} -> True+ LitPat{} -> True+ NPat{} -> True+ NPlusKPat{} -> True+ SplicePat{} -> True+ _otherwise -> panic "isStrictPattern"++isLetStmt :: LStmt a b -> Bool+isLetStmt (L _ LetStmt{}) = True+isLetStmt _ = False++-- | Find a "good" place to insert a bind in an indivisible segment.+-- This is the only place where we use heuristics. The current+-- heuristic is to peel off the first group of independent statements+-- and put the bind after those.+splitSegment+ :: [(ExprLStmt Name, FreeVars)]+ -> ( [(ExprLStmt Name, FreeVars)]+ , [(ExprLStmt Name, FreeVars)] )+splitSegment [one,two] = ([one],[two])+ -- there is no choice when there are only two statements; this just saves+ -- some work in a common case.+splitSegment stmts+ | Just (lets,binds,rest) <- slurpIndependentStmts stmts+ = if not (null lets)+ then (lets, binds++rest)+ else (lets++binds, rest)+ | otherwise+ = case stmts of+ (x:xs) -> ([x],xs)+ _other -> (stmts,[])++slurpIndependentStmts+ :: [(LStmt Name (Located (body Name)), FreeVars)]+ -> Maybe ( [(LStmt Name (Located (body Name)), FreeVars)] -- LetStmts+ , [(LStmt Name (Located (body Name)), FreeVars)] -- BindStmts+ , [(LStmt Name (Located (body Name)), FreeVars)] )+slurpIndependentStmts stmts = go [] [] emptyNameSet stmts+ where+ -- If we encounter a BindStmt that doesn't depend on a previous BindStmt+ -- in this group, then add it to the group.+ go lets indep bndrs ((L loc (BindStmt pat body bind_op fail_op ty), fvs) : rest)+ | isEmptyNameSet (bndrs `intersectNameSet` fvs)+ = go lets ((L loc (BindStmt pat body bind_op fail_op ty), fvs) : indep)+ bndrs' rest+ where bndrs' = bndrs `unionNameSet` mkNameSet (collectPatBinders pat)+ -- If we encounter a LetStmt that doesn't depend on a BindStmt in this+ -- group, then move it to the beginning, so that it doesn't interfere with+ -- grouping more BindStmts.+ -- TODO: perhaps we shouldn't do this if there are any strict bindings,+ -- because we might be moving evaluation earlier.+ go lets indep bndrs ((L loc (LetStmt binds), fvs) : rest)+ | isEmptyNameSet (bndrs `intersectNameSet` fvs)+ = go ((L loc (LetStmt binds), fvs) : lets) indep bndrs rest+ go _ [] _ _ = Nothing+ go _ [_] _ _ = Nothing+ go lets indep _ stmts = Just (reverse lets, reverse indep, stmts)++-- | Build an ApplicativeStmt, and strip the "return" from the tail+-- if necessary.+--+-- For example, if we start with+-- do x <- E1; y <- E2; return (f x y)+-- then we get+-- do (E1[x] | E2[y]); f x y+--+-- the LastStmt in this case has the return removed, but we set the+-- flag on the LastStmt to indicate this, so that we can print out the+-- original statement correctly in error messages. It is easier to do+-- it this way rather than try to ignore the return later in both the+-- typechecker and the desugarer (I tried it that way first!).+mkApplicativeStmt+ :: HsStmtContext Name+ -> [ApplicativeArg Name Name] -- ^ The args+ -> Bool -- ^ True <=> need a join+ -> [ExprLStmt Name] -- ^ The body statements+ -> RnM ([ExprLStmt Name], FreeVars)+mkApplicativeStmt ctxt args need_join body_stmts+ = do { (fmap_op, fvs1) <- lookupStmtName ctxt fmapName+ ; (ap_op, fvs2) <- lookupStmtName ctxt apAName+ ; (mb_join, fvs3) <-+ if need_join then+ do { (join_op, fvs) <- lookupStmtName ctxt joinMName+ ; return (Just join_op, fvs) }+ else+ return (Nothing, emptyNameSet)+ ; let applicative_stmt = noLoc $ ApplicativeStmt+ (zip (fmap_op : repeat ap_op) args)+ mb_join+ placeHolderType+ ; return ( applicative_stmt : body_stmts+ , fvs1 `plusFV` fvs2 `plusFV` fvs3) }++-- | Given the statements following an ApplicativeStmt, determine whether+-- we need a @join@ or not, and remove the @return@ if necessary.+needJoin :: MonadNames+ -> [ExprLStmt Name]+ -> (Bool, [ExprLStmt Name])+needJoin _monad_names [] = (False, []) -- we're in an ApplicativeArg+needJoin monad_names [L loc (LastStmt e _ t)]+ | Just arg <- isReturnApp monad_names e =+ (False, [L loc (LastStmt arg True t)])+needJoin _monad_names stmts = (True, stmts)++-- | @Just e@, if the expression is @return e@ or @return $ e@,+-- otherwise @Nothing@+isReturnApp :: MonadNames+ -> LHsExpr Name+ -> Maybe (LHsExpr Name)+isReturnApp monad_names (L _ (HsPar expr)) = isReturnApp monad_names expr+isReturnApp monad_names (L _ e) = case e of+ OpApp l op _ r | is_return l, is_dollar op -> Just r+ HsApp f arg | is_return f -> Just arg+ _otherwise -> Nothing+ where+ is_var f (L _ (HsPar e)) = is_var f e+ is_var f (L _ (HsAppType e _)) = is_var f e+ is_var f (L _ (HsVar (L _ r))) = f r+ -- TODO: I don't know how to get this right for rebindable syntax+ is_var _ _ = False++ is_return = is_var (\n -> n == return_name monad_names+ || n == pure_name monad_names)+ is_dollar = is_var (`hasKey` dollarIdKey)++{-+************************************************************************+* *+\subsubsection{Errors}+* *+************************************************************************+-}++checkEmptyStmts :: HsStmtContext Name -> RnM ()+-- We've seen an empty sequence of Stmts... is that ok?+checkEmptyStmts ctxt+ = unless (okEmpty ctxt) (addErr (emptyErr ctxt))++okEmpty :: HsStmtContext a -> Bool+okEmpty (PatGuard {}) = True+okEmpty _ = False++emptyErr :: HsStmtContext Name -> SDoc+emptyErr (ParStmtCtxt {}) = text "Empty statement group in parallel comprehension"+emptyErr (TransStmtCtxt {}) = text "Empty statement group preceding 'group' or 'then'"+emptyErr ctxt = text "Empty" <+> pprStmtContext ctxt++----------------------+checkLastStmt :: Outputable (body RdrName) => HsStmtContext Name+ -> LStmt RdrName (Located (body RdrName))+ -> RnM (LStmt RdrName (Located (body RdrName)))+checkLastStmt ctxt lstmt@(L loc stmt)+ = case ctxt of+ ListComp -> check_comp+ MonadComp -> check_comp+ PArrComp -> check_comp+ ArrowExpr -> check_do+ DoExpr -> check_do+ MDoExpr -> check_do+ _ -> check_other+ where+ check_do -- Expect BodyStmt, and change it to LastStmt+ = case stmt of+ BodyStmt e _ _ _ -> return (L loc (mkLastStmt e))+ LastStmt {} -> return lstmt -- "Deriving" clauses may generate a+ -- LastStmt directly (unlike the parser)+ _ -> do { addErr (hang last_error 2 (ppr stmt)); return lstmt }+ last_error = (text "The last statement in" <+> pprAStmtContext ctxt+ <+> text "must be an expression")++ check_comp -- Expect LastStmt; this should be enforced by the parser!+ = case stmt of+ LastStmt {} -> return lstmt+ _ -> pprPanic "checkLastStmt" (ppr lstmt)++ check_other -- Behave just as if this wasn't the last stmt+ = do { checkStmt ctxt lstmt; return lstmt }++-- Checking when a particular Stmt is ok+checkStmt :: HsStmtContext Name+ -> LStmt RdrName (Located (body RdrName))+ -> RnM ()+checkStmt ctxt (L _ stmt)+ = do { dflags <- getDynFlags+ ; case okStmt dflags ctxt stmt of+ IsValid -> return ()+ NotValid extra -> addErr (msg $$ extra) }+ where+ msg = sep [ text "Unexpected" <+> pprStmtCat stmt <+> ptext (sLit "statement")+ , text "in" <+> pprAStmtContext ctxt ]++pprStmtCat :: Stmt a body -> SDoc+pprStmtCat (TransStmt {}) = text "transform"+pprStmtCat (LastStmt {}) = text "return expression"+pprStmtCat (BodyStmt {}) = text "body"+pprStmtCat (BindStmt {}) = text "binding"+pprStmtCat (LetStmt {}) = text "let"+pprStmtCat (RecStmt {}) = text "rec"+pprStmtCat (ParStmt {}) = text "parallel"+pprStmtCat (ApplicativeStmt {}) = panic "pprStmtCat: ApplicativeStmt"++------------+emptyInvalid :: Validity -- Payload is the empty document+emptyInvalid = NotValid Outputable.empty++okStmt, okDoStmt, okCompStmt, okParStmt, okPArrStmt+ :: DynFlags -> HsStmtContext Name+ -> Stmt RdrName (Located (body RdrName)) -> Validity+-- Return Nothing if OK, (Just extra) if not ok+-- The "extra" is an SDoc that is appended to an generic error message++okStmt dflags ctxt stmt+ = case ctxt of+ PatGuard {} -> okPatGuardStmt stmt+ ParStmtCtxt ctxt -> okParStmt dflags ctxt stmt+ DoExpr -> okDoStmt dflags ctxt stmt+ MDoExpr -> okDoStmt dflags ctxt stmt+ ArrowExpr -> okDoStmt dflags ctxt stmt+ GhciStmtCtxt -> okDoStmt dflags ctxt stmt+ ListComp -> okCompStmt dflags ctxt stmt+ MonadComp -> okCompStmt dflags ctxt stmt+ PArrComp -> okPArrStmt dflags ctxt stmt+ TransStmtCtxt ctxt -> okStmt dflags ctxt stmt++-------------+okPatGuardStmt :: Stmt RdrName (Located (body RdrName)) -> Validity+okPatGuardStmt stmt+ = case stmt of+ BodyStmt {} -> IsValid+ BindStmt {} -> IsValid+ LetStmt {} -> IsValid+ _ -> emptyInvalid++-------------+okParStmt dflags ctxt stmt+ = case stmt of+ LetStmt (L _ (HsIPBinds {})) -> emptyInvalid+ _ -> okStmt dflags ctxt stmt++----------------+okDoStmt dflags ctxt stmt+ = case stmt of+ RecStmt {}+ | LangExt.RecursiveDo `xopt` dflags -> IsValid+ | ArrowExpr <- ctxt -> IsValid -- Arrows allows 'rec'+ | otherwise -> NotValid (text "Use RecursiveDo")+ BindStmt {} -> IsValid+ LetStmt {} -> IsValid+ BodyStmt {} -> IsValid+ _ -> emptyInvalid++----------------+okCompStmt dflags _ stmt+ = case stmt of+ BindStmt {} -> IsValid+ LetStmt {} -> IsValid+ BodyStmt {} -> IsValid+ ParStmt {}+ | LangExt.ParallelListComp `xopt` dflags -> IsValid+ | otherwise -> NotValid (text "Use ParallelListComp")+ TransStmt {}+ | LangExt.TransformListComp `xopt` dflags -> IsValid+ | otherwise -> NotValid (text "Use TransformListComp")+ RecStmt {} -> emptyInvalid+ LastStmt {} -> emptyInvalid -- Should not happen (dealt with by checkLastStmt)+ ApplicativeStmt {} -> emptyInvalid++----------------+okPArrStmt dflags _ stmt+ = case stmt of+ BindStmt {} -> IsValid+ LetStmt {} -> IsValid+ BodyStmt {} -> IsValid+ ParStmt {}+ | LangExt.ParallelListComp `xopt` dflags -> IsValid+ | otherwise -> NotValid (text "Use ParallelListComp")+ TransStmt {} -> emptyInvalid+ RecStmt {} -> emptyInvalid+ LastStmt {} -> emptyInvalid -- Should not happen (dealt with by checkLastStmt)+ ApplicativeStmt {} -> emptyInvalid++---------+checkTupleSection :: [LHsTupArg RdrName] -> RnM ()+checkTupleSection args+ = do { tuple_section <- xoptM LangExt.TupleSections+ ; checkErr (all tupArgPresent args || tuple_section) msg }+ where+ msg = text "Illegal tuple section: use TupleSections"++---------+sectionErr :: HsExpr RdrName -> SDoc+sectionErr expr+ = hang (text "A section must be enclosed in parentheses")+ 2 (text "thus:" <+> (parens (ppr expr)))++patSynErr :: HsExpr RdrName -> SDoc -> RnM (HsExpr Name, FreeVars)+patSynErr e explanation = do { addErr (sep [text "Pattern syntax in expression context:",+ nest 4 (ppr e)] $$+ explanation)+ ; return (EWildPat, emptyFVs) }++badIpBinds :: Outputable a => SDoc -> a -> SDoc+badIpBinds what binds+ = hang (text "Implicit-parameter bindings illegal in" <+> what)+ 2 (ppr binds)
+ rename/RnExpr.hs-boot view
@@ -0,0 +1,18 @@+module RnExpr where+import HsSyn+import Name ( Name )+import NameSet ( FreeVars )+import RdrName ( RdrName )+import TcRnTypes+import SrcLoc ( Located )+import Outputable ( Outputable )++rnLExpr :: LHsExpr RdrName+ -> RnM (LHsExpr Name, FreeVars)++rnStmts :: --forall thing body.+ Outputable (body RdrName) => HsStmtContext Name+ -> (Located (body RdrName) -> RnM (Located (body Name), FreeVars))+ -> [LStmt RdrName (Located (body RdrName))]+ -> ([Name] -> RnM (thing, FreeVars))+ -> RnM (([LStmt Name (Located (body Name))], thing), FreeVars)
+ rename/RnHsDoc.hs view
@@ -0,0 +1,23 @@++module RnHsDoc ( rnHsDoc, rnLHsDoc, rnMbLHsDoc ) where++import TcRnTypes+import HsSyn+import SrcLoc+++rnMbLHsDoc :: Maybe LHsDocString -> RnM (Maybe LHsDocString)+rnMbLHsDoc mb_doc = case mb_doc of+ Just doc -> do+ doc' <- rnLHsDoc doc+ return (Just doc')+ Nothing -> return Nothing++rnLHsDoc :: LHsDocString -> RnM LHsDocString+rnLHsDoc (L pos doc) = do+ doc' <- rnHsDoc doc+ return (L pos doc')++rnHsDoc :: HsDocString -> RnM HsDocString+rnHsDoc (HsDocString s) = return (HsDocString s)+
+ rename/RnNames.hs view
@@ -0,0 +1,1627 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[RnNames]{Extracting imported and top-level names in scope}+-}++{-# LANGUAGE CPP, NondecreasingIndentation, MultiWayIf, NamedFieldPuns #-}++module RnNames (+ rnImports, getLocalNonValBinders, newRecordSelector,+ extendGlobalRdrEnvRn,+ gresFromAvails,+ calculateAvails,+ reportUnusedNames,+ checkConName,+ mkChildEnv,+ findChildren,+ dodgyMsg+ ) where++#include "HsVersions.h"++import DynFlags+import HsSyn+import TcEnv+import RnEnv+import LoadIface ( loadSrcInterface )+import TcRnMonad+import PrelNames+import Module+import Name+import NameEnv+import NameSet+import Avail+import FieldLabel+import HscTypes+import RdrName+import RdrHsSyn ( setRdrNameSpace )+import Outputable+import Maybes+import SrcLoc+import BasicTypes ( TopLevelFlag(..), StringLiteral(..) )+import Util+import FastString+import FastStringEnv+import Id+import Type+import PatSyn+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.Either ( partitionEithers, isRight, rights )+-- import qualified Data.Foldable as Foldable+import Data.Map ( Map )+import qualified Data.Map as Map+import Data.Ord ( comparing )+import Data.List ( partition, (\\), find, sortBy )+import qualified Data.Set as S+-- import qualified Data.Set as Set+import System.FilePath ((</>))++import System.IO++{-+************************************************************************+* *+\subsection{rnImports}+* *+************************************************************************++Note [Tracking Trust Transitively]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we import a package as well as checking that the direct imports are safe+according to the rules outlined in the Note [HscMain . Safe Haskell Trust Check]+we must also check that these rules hold transitively for all dependent modules+and packages. Doing this without caching any trust information would be very+slow as we would need to touch all packages and interface files a module depends+on. To avoid this we make use of the property that if a modules Safe Haskell+mode changes, this triggers a recompilation from that module in the dependcy+graph. So we can just worry mostly about direct imports.++There is one trust property that can change for a package though without+recompliation being triggered: package trust. So we must check that all+packages a module tranitively depends on to be trusted are still trusted when+we are compiling this module (as due to recompilation avoidance some modules+below may not be considered trusted any more without recompilation being+triggered).++We handle this by augmenting the existing transitive list of packages a module M+depends on with a bool for each package that says if it must be trusted when the+module M is being checked for trust. This list of trust required packages for a+single import is gathered in the rnImportDecl function and stored in an+ImportAvails data structure. The union of these trust required packages for all+imports is done by the rnImports function using the combine function which calls+the plusImportAvails function that is a union operation for the ImportAvails+type. This gives us in an ImportAvails structure all packages required to be+trusted for the module we are currently compiling. Checking that these packages+are still trusted (and that direct imports are trusted) is done in+HscMain.checkSafeImports.++See the note below, [Trust Own Package] for a corner case in this method and+how its handled.+++Note [Trust Own Package]+~~~~~~~~~~~~~~~~~~~~~~~~+There is a corner case of package trust checking that the usual transitive check+doesn't cover. (For how the usual check operates see the Note [Tracking Trust+Transitively] below). The case is when you import a -XSafe module M and M+imports a -XTrustworthy module N. If N resides in a different package than M,+then the usual check works as M will record a package dependency on N's package+and mark it as required to be trusted. If N resides in the same package as M+though, then importing M should require its own package be trusted due to N+(since M is -XSafe so doesn't create this requirement by itself). The usual+check fails as a module doesn't record a package dependency of its own package.+So instead we now have a bool field in a modules interface file that simply+states if the module requires its own package to be trusted. This field avoids+us having to load all interface files that the module depends on to see if one+is trustworthy.+++Note [Trust Transitive Property]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+So there is an interesting design question in regards to transitive trust+checking. Say I have a module B compiled with -XSafe. B is dependent on a bunch+of modules and packages, some packages it requires to be trusted as its using+-XTrustworthy modules from them. Now if I have a module A that doesn't use safe+haskell at all and simply imports B, should A inherit all the the trust+requirements from B? Should A now also require that a package p is trusted since+B required it?++We currently say no but saying yes also makes sense. The difference is, if a+module M that doesn't use Safe Haskell imports a module N that does, should all+the trusted package requirements be dropped since M didn't declare that it cares+about Safe Haskell (so -XSafe is more strongly associated with the module doing+the importing) or should it be done still since the author of the module N that+uses Safe Haskell said they cared (so -XSafe is more strongly associated with+the module that was compiled that used it).++Going with yes is a simpler semantics we think and harder for the user to stuff+up but it does mean that Safe Haskell will affect users who don't care about+Safe Haskell as they might grab a package from Cabal which uses safe haskell (say+network) and that packages imports -XTrustworthy modules from another package+(say bytestring), so requires that package is trusted. The user may now get+compilation errors in code that doesn't do anything with Safe Haskell simply+because they are using the network package. They will have to call 'ghc-pkg+trust network' to get everything working. Due to this invasive nature of going+with yes we have gone with no for now.+-}++-- | Process Import Decls. See 'rnImportDecl' for a description of what+-- the return types represent.+-- Note: Do the non SOURCE ones first, so that we get a helpful warning+-- for SOURCE ones that are unnecessary+rnImports :: [LImportDecl RdrName]+ -> RnM ([LImportDecl Name], GlobalRdrEnv, ImportAvails, AnyHpcUsage)+rnImports imports = do+ tcg_env <- getGblEnv+ -- NB: want an identity module here, because it's OK for a signature+ -- module to import from its implementor+ let this_mod = tcg_mod tcg_env+ let (source, ordinary) = partition is_source_import imports+ is_source_import d = ideclSource (unLoc d)+ stuff1 <- mapAndReportM (rnImportDecl this_mod) ordinary+ stuff2 <- mapAndReportM (rnImportDecl this_mod) source+ -- Safe Haskell: See Note [Tracking Trust Transitively]+ let (decls, rdr_env, imp_avails, hpc_usage) = combine (stuff1 ++ stuff2)+ return (decls, rdr_env, imp_avails, hpc_usage)++ where+ combine :: [(LImportDecl Name, GlobalRdrEnv, ImportAvails, AnyHpcUsage)]+ -> ([LImportDecl Name], GlobalRdrEnv, ImportAvails, AnyHpcUsage)+ combine = foldr plus ([], emptyGlobalRdrEnv, emptyImportAvails, False)++ plus (decl, gbl_env1, imp_avails1,hpc_usage1)+ (decls, gbl_env2, imp_avails2,hpc_usage2)+ = ( decl:decls,+ gbl_env1 `plusGlobalRdrEnv` gbl_env2,+ imp_avails1 `plusImportAvails` imp_avails2,+ hpc_usage1 || hpc_usage2 )++-- | Given a located import declaration @decl@ from @this_mod@,+-- calculate the following pieces of information:+--+-- 1. An updated 'LImportDecl', where all unresolved 'RdrName' in+-- the entity lists have been resolved into 'Name's,+--+-- 2. A 'GlobalRdrEnv' representing the new identifiers that were+-- brought into scope (taking into account module qualification+-- and hiding),+--+-- 3. 'ImportAvails' summarizing the identifiers that were imported+-- by this declaration, and+--+-- 4. A boolean 'AnyHpcUsage' which is true if the imported module+-- used HPC.+rnImportDecl :: Module -> LImportDecl RdrName+ -> RnM (LImportDecl Name, GlobalRdrEnv, ImportAvails, AnyHpcUsage)+rnImportDecl this_mod+ (L loc decl@(ImportDecl { ideclName = loc_imp_mod_name, ideclPkgQual = mb_pkg+ , ideclSource = want_boot, ideclSafe = mod_safe+ , ideclQualified = qual_only, ideclImplicit = implicit+ , ideclAs = as_mod, ideclHiding = imp_details }))+ = setSrcSpan loc $ do++ when (isJust mb_pkg) $ do+ pkg_imports <- xoptM LangExt.PackageImports+ when (not pkg_imports) $ addErr packageImportErr++ -- If there's an error in loadInterface, (e.g. interface+ -- file not found) we get lots of spurious errors from 'filterImports'+ let imp_mod_name = unLoc loc_imp_mod_name+ doc = ppr imp_mod_name <+> text "is directly imported"++ -- Check for self-import, which confuses the typechecker (Trac #9032)+ -- ghc --make rejects self-import cycles already, but batch-mode may not+ -- at least not until TcIface.tcHiBootIface, which is too late to avoid+ -- typechecker crashes. (Indirect self imports are not caught until+ -- TcIface, see #10337 tracking how to make this error better.)+ --+ -- Originally, we also allowed 'import {-# SOURCE #-} M', but this+ -- caused bug #10182: in one-shot mode, we should never load an hs-boot+ -- file for the module we are compiling into the EPS. In principle,+ -- it should be possible to support this mode of use, but we would have to+ -- 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 Trac #9997+ Nothing -> True+ Just (StringLiteral _ pkg_fs) -> pkg_fs == fsLit "this" ||+ fsToUnitId pkg_fs == moduleUnitId this_mod))+ (addErr (text "A module cannot import itself:" <+> ppr imp_mod_name))++ -- Check for a missing import list (Opt_WarnMissingImportList also+ -- checks for T(..) items but that is done in checkDodgyImport below)+ case imp_details of+ Just (False, _) -> return () -- Explicit import list+ _ | implicit -> return () -- Do not bleat for implicit imports+ | qual_only -> return ()+ | otherwise -> whenWOptM Opt_WarnMissingImportList $+ addWarn (Reason Opt_WarnMissingImportList)+ (missingImportListWarn imp_mod_name)++ iface <- loadSrcInterface doc imp_mod_name want_boot (fmap sl_fs mb_pkg)++ -- Compiler sanity check: if the import didn't say+ -- {-# SOURCE #-} we should not get a hi-boot file+ WARN( not want_boot && mi_boot iface, ppr imp_mod_name ) do++ -- Issue a user warning for a redundant {- SOURCE -} import+ -- NB that we arrange to read all the ordinary imports before+ -- any of the {- SOURCE -} imports.+ --+ -- in --make and GHCi, the compilation manager checks for this,+ -- and indeed we shouldn't do it here because the existence of+ -- the non-boot module depends on the compilation order, which+ -- is not deterministic. The hs-boot test can show this up.+ dflags <- getDynFlags+ warnIf NoReason+ (want_boot && not (mi_boot iface) && isOneShot (ghcMode dflags))+ (warnRedundantSourceImport imp_mod_name)+ when (mod_safe && not (safeImportsOn dflags)) $+ addErr (text "safe import can't be used as Safe Haskell isn't on!"+ $+$ ptext (sLit $ "please enable Safe Haskell through either "+ ++ "Safe, Trustworthy or Unsafe"))++ let+ qual_mod_name = fmap unLoc as_mod `orElse` imp_mod_name+ imp_spec = ImpDeclSpec { is_mod = imp_mod_name, is_qual = qual_only,+ is_dloc = loc, is_as = qual_mod_name }++ -- filter the imports according to the import declaration+ (new_imp_details, gres) <- filterImports iface imp_spec imp_details++ -- for certain error messages, we’d like to know what could be imported+ -- here, if everything were imported+ potential_gres <- mkGlobalRdrEnv . snd <$> filterImports iface imp_spec Nothing++ let gbl_env = mkGlobalRdrEnv gres++ is_hiding | Just (True,_) <- imp_details = True+ | otherwise = False++ -- should the import be safe?+ mod_safe' = mod_safe+ || (not implicit && safeDirectImpsReq dflags)+ || (implicit && safeImplicitImpsReq dflags)++ let imv = ImportedModsVal+ { imv_name = qual_mod_name+ , imv_span = loc+ , imv_is_safe = mod_safe'+ , imv_is_hiding = is_hiding+ , imv_all_exports = potential_gres+ , imv_qualified = qual_only+ }+ imports = calculateAvails dflags iface mod_safe' want_boot (ImportedByUser imv)++ -- Complain if we import a deprecated module+ whenWOptM Opt_WarnWarningsDeprecations (+ case (mi_warns iface) of+ WarnAll txt -> addWarn (Reason Opt_WarnWarningsDeprecations)+ (moduleWarn imp_mod_name txt)+ _ -> return ()+ )++ let new_imp_decl = L loc (decl { ideclSafe = mod_safe'+ , ideclHiding = new_imp_details })++ return (new_imp_decl, gbl_env, imports, mi_hpc iface)++-- | Calculate the 'ImportAvails' induced by an import of a particular+-- interface, but without 'imp_mods'.+calculateAvails :: DynFlags+ -> ModIface+ -> IsSafeImport+ -> IsBootInterface+ -> ImportedBy+ -> ImportAvails+calculateAvails dflags iface mod_safe' want_boot imported_by =+ let imp_mod = mi_module iface+ imp_sem_mod= mi_semantic_module iface+ orph_iface = mi_orphan iface+ has_finsts = mi_finsts iface+ deps = mi_deps iface+ trust = getSafeMode $ mi_trust iface+ trust_pkg = mi_trust_pkg iface++ -- If the module exports anything defined in this module, just+ -- ignore it. Reason: otherwise it looks as if there are two+ -- local definition sites for the thing, and an error gets+ -- reported. Easiest thing is just to filter them out up+ -- front. This situation only arises if a module imports+ -- itself, or another module that imported it. (Necessarily,+ -- this invoves a loop.)+ --+ -- We do this *after* filterImports, so that if you say+ -- module A where+ -- import B( AType )+ -- type AType = ...+ --+ -- module B( AType ) where+ -- import {-# SOURCE #-} A( AType )+ --+ -- then you won't get a 'B does not export AType' message.+++ -- Compute new transitive dependencies+ --+ -- 'dep_orphs' and 'dep_finsts' do NOT include the imported module+ -- itself, but we DO need to include this module in 'imp_orphs' and+ -- 'imp_finsts' if it defines an orphan or instance family; thus the+ -- orph_iface/has_iface tests.++ orphans | orph_iface = ASSERT2( not (imp_sem_mod `elem` dep_orphs deps), ppr imp_sem_mod <+> ppr (dep_orphs deps) )+ imp_sem_mod : dep_orphs deps+ | otherwise = dep_orphs deps++ finsts | has_finsts = ASSERT2( not (imp_sem_mod `elem` dep_finsts deps), ppr imp_sem_mod <+> ppr (dep_orphs deps) )+ imp_sem_mod : dep_finsts deps+ | otherwise = dep_finsts deps++ pkg = moduleUnitId (mi_module iface)+ ipkg = toInstalledUnitId pkg++ -- Does this import mean we now require our own pkg+ -- to be trusted? See Note [Trust Own Package]+ ptrust = trust == Sf_Trustworthy || trust_pkg++ (dependent_mods, dependent_pkgs, pkg_trust_req)+ | pkg == thisPackage dflags =+ -- Imported module is from the home package+ -- Take its dependent modules and add imp_mod itself+ -- Take its dependent packages unchanged+ --+ -- NB: (dep_mods deps) might include a hi-boot file+ -- for the module being compiled, CM. Do *not* filter+ -- this out (as we used to), because when we've+ -- finished dealing with the direct imports we want to+ -- know if any of them depended on CM.hi-boot, in+ -- which case we should do the hi-boot consistency+ -- check. See LoadIface.loadHiBootInterface+ ((moduleName imp_mod,want_boot):dep_mods deps,dep_pkgs deps,ptrust)++ | otherwise =+ -- Imported module is from another package+ -- Dump the dependent modules+ -- Add the package imp_mod comes from to the dependent packages+ ASSERT2( not (ipkg `elem` (map fst $ dep_pkgs deps))+ , ppr ipkg <+> ppr (dep_pkgs deps) )+ ([], (ipkg, False) : dep_pkgs deps, False)++ in ImportAvails {+ imp_mods = unitModuleEnv (mi_module iface) [imported_by],+ imp_orphs = orphans,+ imp_finsts = finsts,+ imp_dep_mods = mkModDeps dependent_mods,+ imp_dep_pkgs = S.fromList . map fst $ dependent_pkgs,+ -- Add in the imported modules trusted package+ -- requirements. ONLY do this though if we import the+ -- module as a safe import.+ -- See Note [Tracking Trust Transitively]+ -- and Note [Trust Transitive Property]+ imp_trust_pkgs = if mod_safe'+ then S.fromList . map fst $ filter snd dependent_pkgs+ else S.empty,+ -- Do we require our own pkg to be trusted?+ -- See Note [Trust Own Package]+ imp_trust_own_pkg = pkg_trust_req+ }+++warnRedundantSourceImport :: ModuleName -> SDoc+warnRedundantSourceImport mod_name+ = text "Unnecessary {-# SOURCE #-} in the import of module"+ <+> quotes (ppr mod_name)++{-+************************************************************************+* *+\subsection{importsFromLocalDecls}+* *+************************************************************************++From the top-level declarations of this module produce+ * the lexical environment+ * the ImportAvails+created by its bindings.++Note [Top-level Names in Template Haskell decl quotes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See also: Note [Interactively-bound Ids in GHCi] in HscTypes+ Note [Looking up Exact RdrNames] in RnEnv++Consider a Template Haskell declaration quotation like this:+ module M where+ f x = h [d| f = 3 |]+When renaming the declarations inside [d| ...|], we treat the+top level binders specially in two ways++1. We give them an Internal Name, not (as usual) an External one.+ This is done by RnEnv.newTopSrcBinder.++2. We make them *shadow* the outer bindings.+ See Note [GlobalRdrEnv shadowing]++3. We find out whether we are inside a [d| ... |] by testing the TH+ stage. This is a slight hack, because the stage field was really+ meant for the type checker, and here we are not interested in the+ fields of Brack, hence the error thunks in thRnBrack.+-}++extendGlobalRdrEnvRn :: [AvailInfo]+ -> MiniFixityEnv+ -> RnM (TcGblEnv, TcLclEnv)+-- Updates both the GlobalRdrEnv and the FixityEnv+-- We return a new TcLclEnv only because we might have to+-- delete some bindings from it;+-- see Note [Top-level Names in Template Haskell decl quotes]++extendGlobalRdrEnvRn avails new_fixities+ = do { (gbl_env, lcl_env) <- getEnvs+ ; stage <- getStage+ ; isGHCi <- getIsGHCi+ ; let rdr_env = tcg_rdr_env gbl_env+ fix_env = tcg_fix_env gbl_env+ th_bndrs = tcl_th_bndrs lcl_env+ th_lvl = thLevel stage++ -- Delete new_occs from global and local envs+ -- If we are in a TemplateHaskell decl bracket,+ -- we are going to shadow them+ -- See Note [GlobalRdrEnv shadowing]+ inBracket = isBrackStage stage++ lcl_env_TH = lcl_env { tcl_rdr = delLocalRdrEnvList (tcl_rdr lcl_env) new_occs }+ -- See Note [GlobalRdrEnv shadowing]++ lcl_env2 | inBracket = lcl_env_TH+ | otherwise = lcl_env++ -- Deal with shadowing: see Note [GlobalRdrEnv shadowing]+ want_shadowing = isGHCi || inBracket+ rdr_env1 | want_shadowing = shadowNames rdr_env new_names+ | otherwise = rdr_env++ lcl_env3 = lcl_env2 { tcl_th_bndrs = extendNameEnvList th_bndrs+ [ (n, (TopLevel, th_lvl))+ | n <- new_names ] }++ ; rdr_env2 <- foldlM add_gre rdr_env1 new_gres++ ; let fix_env' = foldl extend_fix_env fix_env new_gres+ gbl_env' = gbl_env { tcg_rdr_env = rdr_env2, tcg_fix_env = fix_env' }++ ; traceRn "extendGlobalRdrEnvRn 2" (pprGlobalRdrEnv True rdr_env2)+ ; return (gbl_env', lcl_env3) }+ where+ new_names = concatMap availNames avails+ new_occs = map nameOccName new_names++ -- If there is a fixity decl for the gre, add it to the fixity env+ extend_fix_env fix_env gre+ | Just (L _ fi) <- lookupFsEnv new_fixities (occNameFS occ)+ = extendNameEnv fix_env name (FixItem occ fi)+ | otherwise+ = fix_env+ where+ name = gre_name gre+ occ = greOccName gre++ new_gres :: [GlobalRdrElt] -- New LocalDef GREs, derived from avails+ new_gres = concatMap localGREsFromAvail avails++ add_gre :: GlobalRdrEnv -> GlobalRdrElt -> RnM GlobalRdrEnv+ -- Extend the GlobalRdrEnv with a LocalDef GRE+ -- If there is already a LocalDef GRE with the same OccName,+ -- report an error and discard the new GRE+ -- This establishes INVARIANT 1 of GlobalRdrEnvs+ add_gre env gre+ | not (null dups) -- Same OccName defined twice+ = do { addDupDeclErr (gre : dups); return env }++ | otherwise+ = return (extendGlobalRdrEnv env gre)+ where+ name = gre_name gre+ occ = nameOccName name+ dups = filter isLocalGRE (lookupGlobalRdrEnv env occ)+++{- *********************************************************************+* *+ getLocalDeclBindersd@ returns the names for an HsDecl+ It's used for source code.++ *** See Note [The Naming story] in HsDecls ****+* *+********************************************************************* -}++getLocalNonValBinders :: MiniFixityEnv -> HsGroup RdrName+ -> RnM ((TcGblEnv, TcLclEnv), NameSet)+-- Get all the top-level binders bound the group *except*+-- for value bindings, which are treated separately+-- Specifically we return AvailInfo for+-- * type decls (incl constructors and record selectors)+-- * class decls (including class ops)+-- * associated types+-- * foreign imports+-- * value signatures (in hs-boot files only)++getLocalNonValBinders fixity_env+ (HsGroup { hs_valds = binds,+ hs_tyclds = tycl_decls,+ hs_fords = foreign_decls })+ = do { -- Process all type/class decls *except* family instances+ ; let inst_decls = tycl_decls >>= group_instds+ ; overload_ok <- xoptM LangExt.DuplicateRecordFields+ ; (tc_avails, tc_fldss)+ <- fmap unzip $ mapM (new_tc overload_ok)+ (tyClGroupTyClDecls tycl_decls)+ ; traceRn "getLocalNonValBinders 1" (ppr tc_avails)+ ; envs <- extendGlobalRdrEnvRn tc_avails fixity_env+ ; setEnvs envs $ do {+ -- Bring these things into scope first+ -- See Note [Looking up family names in family instances]++ -- Process all family instances+ -- to bring new data constructors into scope+ ; (nti_availss, nti_fldss) <- mapAndUnzipM (new_assoc overload_ok)+ inst_decls++ -- Finish off with value binders:+ -- foreign decls and pattern synonyms for an ordinary module+ -- type sigs in case of a hs-boot file only+ ; is_boot <- tcIsHsBootOrSig+ ; let val_bndrs | is_boot = hs_boot_sig_bndrs+ | otherwise = for_hs_bndrs+ ; val_avails <- mapM new_simple val_bndrs++ ; let avails = concat nti_availss ++ val_avails+ new_bndrs = availsToNameSetWithSelectors avails `unionNameSet`+ availsToNameSetWithSelectors tc_avails+ flds = concat nti_fldss ++ concat tc_fldss+ ; traceRn "getLocalNonValBinders 2" (ppr avails)+ ; (tcg_env, tcl_env) <- extendGlobalRdrEnvRn avails fixity_env++ -- Extend tcg_field_env with new fields (this used to be the+ -- work of extendRecordFieldEnv)+ ; let field_env = extendNameEnvList (tcg_field_env tcg_env) flds+ envs = (tcg_env { tcg_field_env = field_env }, tcl_env)++ ; traceRn "getLocalNonValBinders 3" (vcat [ppr flds, ppr field_env])+ ; return (envs, new_bndrs) } }+ where+ ValBindsIn _val_binds val_sigs = binds++ for_hs_bndrs :: [Located RdrName]+ for_hs_bndrs = hsForeignDeclsBinders foreign_decls++ -- In a hs-boot file, the value binders come from the+ -- *signatures*, and there should be no foreign binders+ hs_boot_sig_bndrs = [ L decl_loc (unLoc n)+ | L decl_loc (TypeSig ns _) <- val_sigs, n <- ns]++ -- the SrcSpan attached to the input should be the span of the+ -- declaration, not just the name+ new_simple :: Located RdrName -> RnM AvailInfo+ new_simple rdr_name = do{ nm <- newTopSrcBinder rdr_name+ ; return (avail nm) }++ new_tc :: Bool -> LTyClDecl RdrName+ -> RnM (AvailInfo, [(Name, [FieldLabel])])+ new_tc overload_ok tc_decl -- NOT for type/data instances+ = do { let (bndrs, flds) = hsLTyClDeclBinders tc_decl+ ; names@(main_name : sub_names) <- mapM newTopSrcBinder bndrs+ ; flds' <- mapM (newRecordSelector overload_ok sub_names) flds+ ; let fld_env = case unLoc tc_decl of+ DataDecl { tcdDataDefn = d } -> mk_fld_env d names flds'+ _ -> []+ ; return (AvailTC main_name names flds', fld_env) }+++ -- Calculate the mapping from constructor names to fields, which+ -- will go in tcg_field_env. It's convenient to do this here where+ -- we are working with a single datatype definition.+ mk_fld_env :: HsDataDefn RdrName -> [Name] -> [FieldLabel] -> [(Name, [FieldLabel])]+ mk_fld_env d names flds = concatMap find_con_flds (dd_cons d)+ where+ find_con_flds (L _ (ConDeclH98 { con_name = L _ rdr+ , con_details = RecCon cdflds }))+ = [( find_con_name rdr+ , concatMap find_con_decl_flds (unLoc cdflds) )]+ find_con_flds (L _ (ConDeclGADT+ { con_names = rdrs+ , con_type = (HsIB { hsib_body = res_ty})}))+ = map (\ (L _ rdr) -> ( find_con_name rdr+ , concatMap find_con_decl_flds cdflds))+ rdrs+ where+ (_tvs, _cxt, tau) = splitLHsSigmaTy res_ty+ cdflds = case tau of+ L _ (HsFunTy+ (L _ (HsAppsTy+ [L _ (HsAppPrefix (L _ (HsRecTy flds)))])) _) -> flds+ L _ (HsFunTy (L _ (HsRecTy flds)) _) -> flds+ _ -> []+ find_con_flds _ = []++ find_con_name rdr+ = expectJust "getLocalNonValBinders/find_con_name" $+ find (\ n -> nameOccName n == rdrNameOcc rdr) names+ find_con_decl_flds (L _ x)+ = map find_con_decl_fld (cd_fld_names x)+ find_con_decl_fld (L _ (FieldOcc (L _ rdr) _))+ = expectJust "getLocalNonValBinders/find_con_decl_fld" $+ find (\ fl -> flLabel fl == lbl) flds+ where lbl = occNameFS (rdrNameOcc rdr)++ new_assoc :: Bool -> LInstDecl RdrName+ -> RnM ([AvailInfo], [(Name, [FieldLabel])])+ new_assoc _ (L _ (TyFamInstD {})) = return ([], [])+ -- type instances don't bind new names++ new_assoc overload_ok (L _ (DataFamInstD d))+ = do { (avail, flds) <- new_di overload_ok Nothing d+ ; return ([avail], flds) }+ new_assoc overload_ok (L _ (ClsInstD (ClsInstDecl { cid_poly_ty = inst_ty+ , cid_datafam_insts = adts })))+ | Just (L loc cls_rdr) <- getLHsInstDeclClass_maybe inst_ty+ = do { cls_nm <- setSrcSpan loc $ lookupGlobalOccRn cls_rdr+ ; (avails, fldss)+ <- mapAndUnzipM (new_loc_di overload_ok (Just cls_nm)) adts+ ; return (avails, concat fldss) }+ | otherwise+ = return ([], []) -- Do not crash on ill-formed instances+ -- Eg instance !Show Int Trac #3811c++ new_di :: Bool -> Maybe Name -> DataFamInstDecl RdrName+ -> RnM (AvailInfo, [(Name, [FieldLabel])])+ new_di overload_ok mb_cls ti_decl+ = do { main_name <- lookupFamInstName mb_cls (dfid_tycon ti_decl)+ ; let (bndrs, flds) = hsDataFamInstBinders ti_decl+ ; sub_names <- mapM newTopSrcBinder bndrs+ ; flds' <- mapM (newRecordSelector overload_ok sub_names) flds+ ; let avail = AvailTC (unLoc main_name) sub_names flds'+ -- main_name is not bound here!+ fld_env = mk_fld_env (dfid_defn ti_decl) sub_names flds'+ ; return (avail, fld_env) }++ new_loc_di :: Bool -> Maybe Name -> LDataFamInstDecl RdrName+ -> RnM (AvailInfo, [(Name, [FieldLabel])])+ new_loc_di overload_ok mb_cls (L _ d) = new_di overload_ok mb_cls d++newRecordSelector :: Bool -> [Name] -> LFieldOcc RdrName -> RnM FieldLabel+newRecordSelector _ [] _ = error "newRecordSelector: datatype has no constructors!"+newRecordSelector overload_ok (dc:_) (L loc (FieldOcc (L _ fld) _))+ = do { selName <- newTopSrcBinder $ L loc $ field+ ; return $ qualFieldLbl { flSelector = selName } }+ where+ fieldOccName = occNameFS $ rdrNameOcc fld+ qualFieldLbl = mkFieldLabelOccs fieldOccName (nameOccName dc) overload_ok+ field | isExact fld = fld+ -- use an Exact RdrName as is to preserve the bindings+ -- of an already renamer-resolved field and its use+ -- sites. This is needed to correctly support record+ -- selectors in Template Haskell. See Note [Binders in+ -- Template Haskell] in Convert.hs and Note [Looking up+ -- Exact RdrNames] in RnEnv.hs.+ | otherwise = mkRdrUnqual (flSelector qualFieldLbl)++{-+Note [Looking up family names in family instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ module M where+ type family T a :: *+ type instance M.T Int = Bool++We might think that we can simply use 'lookupOccRn' when processing the type+instance to look up 'M.T'. Alas, we can't! The type family declaration is in+the *same* HsGroup as the type instance declaration. Hence, as we are+currently collecting the binders declared in that HsGroup, these binders will+not have been added to the global environment yet.++Solution is simple: process the type family declarations first, extend+the environment, and then process the type instances.+++************************************************************************+* *+\subsection{Filtering imports}+* *+************************************************************************++@filterImports@ takes the @ExportEnv@ telling what the imported module makes+available, and filters it through the import spec (if any).++Note [Dealing with imports]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+For import M( ies ), we take the mi_exports of M, and make+ imp_occ_env :: OccEnv (Name, AvailInfo, Maybe Name)+One entry for each Name that M exports; the AvailInfo is the+AvailInfo exported from M that exports that Name.++The situation is made more complicated by associated types. E.g.+ module M where+ class C a where { data T a }+ instance C Int where { data T Int = T1 | T2 }+ instance C Bool where { data T Int = T3 }+Then M's export_avails are (recall the AvailTC invariant from Avails.hs)+ C(C,T), T(T,T1,T2,T3)+Notice that T appears *twice*, once as a child and once as a parent. From+this list we construt a raw list including+ T -> (T, T( T1, T2, T3 ), Nothing)+ T -> (C, C( C, T ), Nothing)+and we combine these (in function 'combine' in 'imp_occ_env' in+'filterImports') to get+ T -> (T, T(T,T1,T2,T3), Just C)++So the overall imp_occ_env is+ C -> (C, C(C,T), Nothing)+ T -> (T, T(T,T1,T2,T3), Just C)+ T1 -> (T1, T(T,T1,T2,T3), Nothing) -- similarly T2,T3++If we say+ import M( T(T1,T2) )+then we get *two* Avails: C(T), T(T1,T2)++Note that the imp_occ_env will have entries for data constructors too,+although we never look up data constructors.+-}++filterImports+ :: ModIface+ -> ImpDeclSpec -- The span for the entire import decl+ -> Maybe (Bool, Located [LIE RdrName]) -- Import spec; True => hiding+ -> RnM (Maybe (Bool, Located [LIE Name]), -- Import spec w/ Names+ [GlobalRdrElt]) -- Same again, but in GRE form+filterImports iface decl_spec Nothing+ = return (Nothing, gresFromAvails (Just imp_spec) (mi_exports iface))+ where+ imp_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }+++filterImports iface decl_spec (Just (want_hiding, L l import_items))+ = do -- check for errors, convert RdrNames to Names+ items1 <- mapM lookup_lie import_items++ let items2 :: [(LIE Name, AvailInfo)]+ items2 = concat items1+ -- NB the AvailInfo may have duplicates, and several items+ -- for the same parent; e.g N(x) and N(y)++ names = availsToNameSet (map snd items2)+ keep n = not (n `elemNameSet` names)+ pruned_avails = filterAvails keep all_avails+ hiding_spec = ImpSpec { is_decl = decl_spec, is_item = ImpAll }++ gres | want_hiding = gresFromAvails (Just hiding_spec) pruned_avails+ | otherwise = concatMap (gresFromIE decl_spec) items2++ return (Just (want_hiding, L l (map fst items2)), gres)+ where+ all_avails = mi_exports iface++ -- See Note [Dealing with imports]+ imp_occ_env :: OccEnv (Name, -- the name+ AvailInfo, -- the export item providing the name+ Maybe Name) -- the parent of associated types+ imp_occ_env = mkOccEnv_C combine [ (nameOccName n, (n, a, Nothing))+ | a <- all_avails, n <- availNames a]+ where+ -- See Note [Dealing with imports]+ -- 'combine' is only called for associated data types which appear+ -- twice in the all_avails. In the example, we combine+ -- T(T,T1,T2,T3) and C(C,T) to give (T, T(T,T1,T2,T3), Just C)+ -- NB: the AvailTC can have fields as well as data constructors (Trac #12127)+ combine (name1, a1@(AvailTC p1 _ _), mp1)+ (name2, a2@(AvailTC p2 _ _), mp2)+ = ASSERT2( name1 == name2 && isNothing mp1 && isNothing mp2+ , ppr name1 <+> ppr name2 <+> ppr mp1 <+> ppr mp2 )+ if p1 == name1 then (name1, a1, Just p2)+ else (name1, a2, Just p1)+ combine x y = pprPanic "filterImports/combine" (ppr x $$ ppr y)++ lookup_name :: RdrName -> IELookupM (Name, AvailInfo, Maybe Name)+ lookup_name rdr | isQual rdr = failLookupWith (QualImportError rdr)+ | Just succ <- mb_success = return succ+ | otherwise = failLookupWith BadImport+ where+ mb_success = lookupOccEnv imp_occ_env (rdrNameOcc rdr)++ lookup_lie :: LIE RdrName -> TcRn [(LIE Name, AvailInfo)]+ lookup_lie (L loc ieRdr)+ = do (stuff, warns) <- setSrcSpan loc $+ liftM (fromMaybe ([],[])) $+ run_lookup (lookup_ie ieRdr)+ mapM_ emit_warning warns+ return [ (L loc ie, avail) | (ie,avail) <- stuff ]+ where+ -- Warn when importing T(..) if T was exported abstractly+ emit_warning (DodgyImport n) = whenWOptM Opt_WarnDodgyImports $+ addWarn (Reason Opt_WarnDodgyImports) (dodgyImportWarn n)+ emit_warning MissingImportList = whenWOptM Opt_WarnMissingImportList $+ addWarn (Reason Opt_WarnMissingImportList) (missingImportListItem ieRdr)+ emit_warning BadImportW = whenWOptM Opt_WarnDodgyImports $+ addWarn (Reason Opt_WarnDodgyImports) (lookup_err_msg BadImport)++ run_lookup :: IELookupM a -> TcRn (Maybe a)+ run_lookup m = case m of+ Failed err -> addErr (lookup_err_msg err) >> return Nothing+ Succeeded a -> return (Just a)++ lookup_err_msg err = case err of+ BadImport -> badImportItemErr iface decl_spec ieRdr all_avails+ IllegalImport -> illegalImportItemErr+ QualImportError rdr -> qualImportItemErr rdr++ -- For each import item, we convert its RdrNames to Names,+ -- and at the same time construct an AvailInfo corresponding+ -- to what is actually imported by this item.+ -- Returns Nothing on error.+ -- We return a list here, because in the case of an import+ -- item like C, if we are hiding, then C refers to *both* a+ -- type/class and a data constructor. Moreover, when we import+ -- data constructors of an associated family, we need separate+ -- AvailInfos for the data constructors and the family (as they have+ -- different parents). See Note [Dealing with imports]+ lookup_ie :: IE RdrName -> IELookupM ([(IE Name, AvailInfo)], [IELookupWarning])+ lookup_ie ie = handle_bad_import $ do+ case ie of+ IEVar (L l n) -> do+ (name, avail, _) <- lookup_name $ ieWrappedName n+ return ([(IEVar (L l (replaceWrappedName n name)),+ trimAvail avail name)], [])++ IEThingAll (L l tc) -> do+ (name, avail, mb_parent) <- lookup_name $ ieWrappedName tc+ let warns = case avail of+ Avail {} -- e.g. f(..)+ -> [DodgyImport $ ieWrappedName tc]++ AvailTC _ subs fs+ | null (drop 1 subs) && null fs -- e.g. T(..) where T is a synonym+ -> [DodgyImport $ ieWrappedName tc]++ | not (is_qual decl_spec) -- e.g. import M( T(..) )+ -> [MissingImportList]++ | otherwise+ -> []++ renamed_ie = IEThingAll (L l (replaceWrappedName tc name))+ sub_avails = case avail of+ Avail {} -> []+ AvailTC name2 subs fs -> [(renamed_ie, AvailTC name2 (subs \\ [name]) fs)]+ case mb_parent of+ Nothing -> return ([(renamed_ie, avail)], warns)+ -- non-associated ty/cls+ Just parent -> return ((renamed_ie, AvailTC parent [name] []) : sub_avails, warns)+ -- associated type++ IEThingAbs (L l tc')+ | want_hiding -- hiding ( C )+ -- Here the 'C' can be a data constructor+ -- *or* a type/class, or even both+ -> let tc = ieWrappedName tc'+ tc_name = lookup_name tc+ dc_name = lookup_name (setRdrNameSpace tc srcDataName)+ in+ case catIELookupM [ tc_name, dc_name ] of+ [] -> failLookupWith BadImport+ names -> return ([mkIEThingAbs tc' l name | name <- names], [])+ | otherwise+ -> do nameAvail <- lookup_name (ieWrappedName tc')+ return ([mkIEThingAbs tc' l nameAvail]+ , [])++ IEThingWith (L l rdr_tc) wc rdr_ns' rdr_fs ->+ ASSERT2(null rdr_fs, ppr rdr_fs) do+ (name, AvailTC _ ns subflds, mb_parent)+ <- lookup_name (ieWrappedName rdr_tc)++ -- Look up the children in the sub-names of the parent+ let subnames = case ns of -- The tc is first in ns,+ [] -> [] -- if it is there at all+ -- See the AvailTC Invariant in Avail.hs+ (n1:ns1) | n1 == name -> ns1+ | otherwise -> ns+ rdr_ns = map ieLWrappedName rdr_ns'+ case lookupChildren (map Left subnames ++ map Right subflds) rdr_ns of+ Nothing -> failLookupWith BadImport+ Just (childnames, childflds) ->+ case mb_parent of+ -- non-associated ty/cls+ Nothing+ -> return ([(IEThingWith (L l name') wc childnames'+ childflds,+ AvailTC name (name:map unLoc childnames) (map unLoc childflds))],+ [])+ where name' = replaceWrappedName rdr_tc name+ childnames' = map to_ie_post_rn childnames+ -- childnames' = postrn_ies childnames+ -- associated ty+ Just parent+ -> return ([(IEThingWith (L l name') wc childnames'+ childflds,+ AvailTC name (map unLoc childnames) (map unLoc childflds)),+ (IEThingWith (L l name') wc childnames'+ childflds,+ AvailTC parent [name] [])],+ [])+ where name' = replaceWrappedName rdr_tc name+ childnames' = map to_ie_post_rn childnames++ _other -> failLookupWith IllegalImport+ -- could be IEModuleContents, IEGroup, IEDoc, IEDocNamed+ -- all errors.++ where+ mkIEThingAbs tc l (n, av, Nothing )+ = (IEThingAbs (L l (replaceWrappedName tc n)), trimAvail av n)+ mkIEThingAbs tc l (n, _, Just parent)+ = (IEThingAbs (L l (replaceWrappedName tc n)), AvailTC parent [n] [])++ handle_bad_import m = catchIELookup m $ \err -> case err of+ BadImport | want_hiding -> return ([], [BadImportW])+ _ -> failLookupWith err++type IELookupM = MaybeErr IELookupError++data IELookupWarning+ = BadImportW+ | MissingImportList+ | DodgyImport RdrName+ -- NB. use the RdrName for reporting a "dodgy" import++data IELookupError+ = QualImportError RdrName+ | BadImport+ | IllegalImport++failLookupWith :: IELookupError -> IELookupM a+failLookupWith err = Failed err++catchIELookup :: IELookupM a -> (IELookupError -> IELookupM a) -> IELookupM a+catchIELookup m h = case m of+ Succeeded r -> return r+ Failed err -> h err++catIELookupM :: [IELookupM a] -> [a]+catIELookupM ms = [ a | Succeeded a <- ms ]++{-+************************************************************************+* *+\subsection{Import/Export Utils}+* *+************************************************************************+-}++-- | Given an import\/export spec, construct the appropriate 'GlobalRdrElt's.+gresFromIE :: ImpDeclSpec -> (LIE Name, AvailInfo) -> [GlobalRdrElt]+gresFromIE decl_spec (L loc ie, avail)+ = gresFromAvail prov_fn avail+ where+ is_explicit = case ie of+ IEThingAll (L _ name) -> \n -> n == ieWrappedName name+ _ -> \_ -> True+ prov_fn name+ = Just (ImpSpec { is_decl = decl_spec, is_item = item_spec })+ where+ item_spec = ImpSome { is_explicit = is_explicit name, is_iloc = loc }+++{-+Note [Children for duplicate record fields]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the module++ {-# LANGUAGE DuplicateRecordFields #-}+ module M (F(foo, MkFInt, MkFBool)) where+ data family F a+ data instance F Int = MkFInt { foo :: Int }+ data instance F Bool = MkFBool { foo :: Bool }++The `foo` in the export list refers to *both* selectors! For this+reason, lookupChildren builds an environment that maps the FastString+to a list of items, rather than a single item.+-}++mkChildEnv :: [GlobalRdrElt] -> NameEnv [GlobalRdrElt]+mkChildEnv gres = foldr add emptyNameEnv gres+ where+ add gre env = case gre_par gre of+ FldParent p _ -> extendNameEnv_Acc (:) singleton env p gre+ ParentIs p -> extendNameEnv_Acc (:) singleton env p gre+ NoParent -> env++findChildren :: NameEnv [a] -> Name -> [a]+findChildren env n = lookupNameEnv env n `orElse` []++lookupChildren :: [Either Name FieldLabel] -> [Located RdrName]+ -> Maybe ([Located Name], [Located FieldLabel])+-- (lookupChildren all_kids rdr_items) maps each rdr_item to its+-- corresponding Name all_kids, if the former exists+-- The matching is done by FastString, not OccName, so that+-- Cls( meth, AssocTy )+-- will correctly find AssocTy among the all_kids of Cls, even though+-- the RdrName for AssocTy may have a (bogus) DataName namespace+-- (Really the rdr_items should be FastStrings in the first place.)+lookupChildren all_kids rdr_items+ = do xs <- mapM doOne rdr_items+ return (fmap concat (partitionEithers xs))+ where+ doOne (L l r) = case (lookupFsEnv kid_env . occNameFS . rdrNameOcc) r of+ Just [Left n] -> Just (Left (L l n))+ Just rs | all isRight rs -> Just (Right (map (L l) (rights rs)))+ _ -> Nothing++ -- See Note [Children for duplicate record fields]+ kid_env = extendFsEnvList_C (++) emptyFsEnv+ [(either (occNameFS . nameOccName) flLabel x, [x]) | x <- all_kids]++++-------------------------------++{-+*********************************************************+* *+\subsection{Unused names}+* *+*********************************************************+-}++reportUnusedNames :: Maybe (Located [LIE RdrName]) -- Export list+ -> TcGblEnv -> RnM ()+reportUnusedNames _export_decls gbl_env+ = do { traceRn "RUN" (ppr (tcg_dus gbl_env))+ ; warnUnusedImportDecls gbl_env+ ; warnUnusedTopBinds unused_locals+ ; warnMissingSignatures gbl_env }+ where+ used_names :: NameSet+ used_names = findUses (tcg_dus gbl_env) emptyNameSet+ -- NB: currently, if f x = g, we only treat 'g' as used if 'f' is used+ -- Hence findUses++ -- Collect the defined names from the in-scope environment+ defined_names :: [GlobalRdrElt]+ defined_names = globalRdrEnvElts (tcg_rdr_env gbl_env)++ -- Note that defined_and_used, defined_but_not_used+ -- are both [GRE]; that's why we need defined_and_used+ -- rather than just used_names+ _defined_and_used, defined_but_not_used :: [GlobalRdrElt]+ (_defined_and_used, defined_but_not_used)+ = partition (gre_is_used used_names) defined_names++ kids_env = mkChildEnv defined_names+ -- This is done in mkExports too; duplicated work++ gre_is_used :: NameSet -> GlobalRdrElt -> Bool+ gre_is_used used_names (GRE {gre_name = name})+ = name `elemNameSet` used_names+ || any (\ gre -> gre_name gre `elemNameSet` used_names) (findChildren kids_env name)+ -- A use of C implies a use of T,+ -- if C was brought into scope by T(..) or T(C)++ -- Filter out the ones that are+ -- (a) defined in this module, and+ -- (b) not defined by a 'deriving' clause+ -- The latter have an Internal Name, so we can filter them out easily+ unused_locals :: [GlobalRdrElt]+ unused_locals = filter is_unused_local defined_but_not_used+ is_unused_local :: GlobalRdrElt -> Bool+ is_unused_local gre = isLocalGRE gre && isExternalName (gre_name gre)++{-+*********************************************************+* *+\subsection{Unused imports}+* *+*********************************************************++This code finds which import declarations are unused. The+specification and implementation notes are here:+ http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/UnusedImports+-}++type ImportDeclUsage+ = ( LImportDecl Name -- The import declaration+ , [AvailInfo] -- What *is* used (normalised)+ , [Name] ) -- What is imported but *not* used++warnUnusedImportDecls :: TcGblEnv -> RnM ()+warnUnusedImportDecls gbl_env+ = do { uses <- readMutVar (tcg_used_gres gbl_env)+ ; let user_imports = filterOut (ideclImplicit . unLoc) (tcg_rn_imports gbl_env)+ -- This whole function deals only with *user* imports+ -- both for warning about unnecessary ones, and for+ -- deciding the minimal ones+ rdr_env = tcg_rdr_env gbl_env+ fld_env = mkFieldEnv rdr_env++ ; let usage :: [ImportDeclUsage]+ usage = findImportUsage user_imports uses++ ; traceRn "warnUnusedImportDecls" $+ (vcat [ text "Uses:" <+> ppr uses+ , text "Import usage" <+> ppr usage])+ ; whenWOptM Opt_WarnUnusedImports $+ mapM_ (warnUnusedImport Opt_WarnUnusedImports fld_env) usage++ ; whenGOptM Opt_D_dump_minimal_imports $+ printMinimalImports usage }++-- | Warn the user about top level binders that lack type signatures.+-- Called /after/ type inference, so that we can report the+-- inferred type of the function+warnMissingSignatures :: TcGblEnv -> RnM ()+warnMissingSignatures gbl_env+ = do { let exports = availsToNameSet (tcg_exports gbl_env)+ sig_ns = tcg_sigs gbl_env+ -- We use sig_ns to exclude top-level bindings that are generated by GHC+ binds = collectHsBindsBinders $ tcg_binds gbl_env+ pat_syns = tcg_patsyns gbl_env++ -- Warn about missing signatures+ -- Do this only when we we have a type to offer+ ; warn_missing_sigs <- woptM Opt_WarnMissingSignatures+ ; warn_only_exported <- woptM Opt_WarnMissingExportedSignatures+ ; warn_pat_syns <- woptM Opt_WarnMissingPatternSynonymSignatures++ ; let add_sig_warns+ | warn_only_exported = add_warns Opt_WarnMissingExportedSignatures+ | warn_missing_sigs = add_warns Opt_WarnMissingSignatures+ | warn_pat_syns = add_warns Opt_WarnMissingPatternSynonymSignatures+ | otherwise = return ()++ add_warns flag+ = when warn_pat_syns+ (mapM_ add_pat_syn_warn pat_syns) >>+ when (warn_missing_sigs || warn_only_exported)+ (mapM_ add_bind_warn binds)+ where+ add_pat_syn_warn p+ = add_warn name $+ hang (text "Pattern synonym with no type signature:")+ 2 (text "pattern" <+> pprPrefixName name <+> dcolon <+> pp_ty)+ where+ name = patSynName p+ pp_ty = pprPatSynType p++ add_bind_warn id+ = do { env <- tcInitTidyEnv -- Why not use emptyTidyEnv?+ ; let name = idName id+ (_, ty) = tidyOpenType env (idType id)+ ty_msg = pprSigmaType ty+ ; add_warn name $+ hang (text "Top-level binding with no type signature:")+ 2 (pprPrefixName name <+> dcolon <+> ty_msg) }++ add_warn name msg+ = when (name `elemNameSet` sig_ns && export_check name)+ (addWarnAt (Reason flag) (getSrcSpan name) msg)++ export_check name+ = not warn_only_exported || name `elemNameSet` exports++ ; add_sig_warns }++{-+Note [The ImportMap]+~~~~~~~~~~~~~~~~~~~~+The ImportMap is a short-lived intermediate data struture records, for+each import declaration, what stuff brought into scope by that+declaration is actually used in the module.++The SrcLoc is the location of the END of a particular 'import'+declaration. Why *END*? Because we don't want to get confused+by the implicit Prelude import. Consider (Trac #7476) the module+ import Foo( foo )+ main = print foo+There is an implicit 'import Prelude(print)', and it gets a SrcSpan+of line 1:1 (just the point, not a span). If we use the *START* of+the SrcSpan to identify the import decl, we'll confuse the implicit+import Prelude with the explicit 'import Foo'. So we use the END.+It's just a cheap hack; we could equally well use the Span too.++The AvailInfos are the things imported from that decl (just a list,+not normalised).+-}++type ImportMap = Map SrcLoc [AvailInfo] -- See [The ImportMap]++findImportUsage :: [LImportDecl Name]+ -> [GlobalRdrElt]+ -> [ImportDeclUsage]++findImportUsage imports used_gres+ = map unused_decl imports+ where+ import_usage :: ImportMap+ import_usage+ = foldr extendImportMap Map.empty used_gres++ unused_decl decl@(L loc (ImportDecl { ideclHiding = imps }))+ = (decl, nubAvails used_avails, nameSetElemsStable unused_imps)+ where+ used_avails = Map.lookup (srcSpanEnd loc) import_usage `orElse` []+ -- srcSpanEnd: see Note [The ImportMap]+ used_names = availsToNameSetWithSelectors used_avails+ used_parents = mkNameSet [n | AvailTC n _ _ <- used_avails]++ unused_imps -- Not trivial; see eg Trac #7454+ = case imps of+ Just (False, L _ imp_ies) ->+ foldr (add_unused . unLoc) emptyNameSet imp_ies+ _other -> emptyNameSet -- No explicit import list => no unused-name list++ add_unused :: IE Name -> NameSet -> NameSet+ add_unused (IEVar (L _ n)) acc+ = add_unused_name (ieWrappedName n) acc+ add_unused (IEThingAbs (L _ n)) acc+ = add_unused_name (ieWrappedName n) acc+ add_unused (IEThingAll (L _ n)) acc+ = add_unused_all (ieWrappedName n) acc+ add_unused (IEThingWith (L _ p) wc ns fs) acc =+ add_wc_all (add_unused_with (ieWrappedName p) xs acc)+ where xs = map (ieWrappedName . unLoc) ns+ ++ map (flSelector . unLoc) fs+ add_wc_all = case wc of+ NoIEWildcard -> id+ IEWildcard _ -> add_unused_all (ieWrappedName p)+ add_unused _ acc = acc++ add_unused_name n acc+ | n `elemNameSet` used_names = acc+ | otherwise = acc `extendNameSet` n+ add_unused_all n acc+ | n `elemNameSet` used_names = acc+ | n `elemNameSet` used_parents = acc+ | otherwise = acc `extendNameSet` n+ add_unused_with p ns acc+ | all (`elemNameSet` acc1) ns = add_unused_name p acc1+ | otherwise = acc1+ where+ acc1 = foldr add_unused_name acc ns+ -- If you use 'signum' from Num, then the user may well have+ -- imported Num(signum). We don't want to complain that+ -- Num is not itself mentioned. Hence the two cases in add_unused_with.++extendImportMap :: GlobalRdrElt -> ImportMap -> ImportMap+-- For each of a list of used GREs, find all the import decls that brought+-- it into scope; choose one of them (bestImport), and record+-- the RdrName in that import decl's entry in the ImportMap+extendImportMap gre imp_map+ = add_imp gre (bestImport (gre_imp gre)) imp_map+ where+ add_imp :: GlobalRdrElt -> ImportSpec -> ImportMap -> ImportMap+ add_imp gre (ImpSpec { is_decl = imp_decl_spec }) imp_map+ = Map.insertWith add decl_loc [avail] imp_map+ where+ add _ avails = avail : avails -- add is really just a specialised (++)+ decl_loc = srcSpanEnd (is_dloc imp_decl_spec)+ -- For srcSpanEnd see Note [The ImportMap]+ avail = availFromGRE gre++warnUnusedImport :: WarningFlag -> NameEnv (FieldLabelString, Name)+ -> ImportDeclUsage -> RnM ()+warnUnusedImport flag fld_env (L loc decl, used, unused)+ | Just (False,L _ []) <- ideclHiding decl+ = return () -- Do not warn for 'import M()'++ | Just (True, L _ hides) <- ideclHiding decl+ , not (null hides)+ , pRELUDE_NAME == unLoc (ideclName decl)+ = return () -- Note [Do not warn about Prelude hiding]+ | null used = addWarnAt (Reason flag) loc msg1 -- Nothing used; drop entire decl+ | null unused = return () -- Everything imported is used; nop+ | otherwise = addWarnAt (Reason flag) loc msg2 -- Some imports are unused+ where+ msg1 = vcat [pp_herald <+> quotes pp_mod <+> pp_not_used,+ nest 2 (text "except perhaps to import instances from"+ <+> quotes pp_mod),+ text "To import instances alone, use:"+ <+> text "import" <+> pp_mod <> parens Outputable.empty ]+ msg2 = sep [pp_herald <+> quotes sort_unused,+ text "from module" <+> quotes pp_mod <+> pp_not_used]+ pp_herald = text "The" <+> pp_qual <+> text "import of"+ pp_qual+ | ideclQualified decl = text "qualified"+ | otherwise = Outputable.empty+ pp_mod = ppr (unLoc (ideclName decl))+ pp_not_used = text "is redundant"++ ppr_possible_field n = case lookupNameEnv fld_env n of+ Just (fld, p) -> ppr p <> parens (ppr fld)+ Nothing -> ppr n++ -- Print unused names in a deterministic (lexicographic) order+ sort_unused = pprWithCommas ppr_possible_field $+ sortBy (comparing nameOccName) unused++{-+Note [Do not warn about Prelude hiding]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do not warn about+ import Prelude hiding( x, y )+because even if nothing else from Prelude is used, it may be essential to hide+x,y to avoid name-shadowing warnings. Example (Trac #9061)+ import Prelude hiding( log )+ f x = log where log = ()++++Note [Printing minimal imports]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To print the minimal imports we walk over the user-supplied import+decls, and simply trim their import lists. NB that++ * We do *not* change the 'qualified' or 'as' parts!++ * We do not disard a decl altogether; we might need instances+ from it. Instead we just trim to an empty import list+-}++printMinimalImports :: [ImportDeclUsage] -> RnM ()+-- See Note [Printing minimal imports]+printMinimalImports imports_w_usage+ = do { imports' <- mapM mk_minimal imports_w_usage+ ; this_mod <- getModule+ ; dflags <- getDynFlags+ ; liftIO $+ do { h <- openFile (mkFilename dflags this_mod) WriteMode+ ; printForUser dflags h neverQualify (vcat (map ppr imports')) }+ -- The neverQualify is important. We are printing Names+ -- but they are in the context of an 'import' decl, and+ -- we never qualify things inside there+ -- E.g. import Blag( f, b )+ -- not import Blag( Blag.f, Blag.g )!+ }+ where+ mkFilename dflags this_mod+ | Just d <- dumpDir dflags = d </> basefn+ | otherwise = basefn+ where+ basefn = moduleNameString (moduleName this_mod) ++ ".imports"++ mk_minimal (L l decl, used, unused)+ | null unused+ , Just (False, _) <- ideclHiding decl+ = return (L l decl)+ | 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)+ ; let lies = map (L l) (concatMap (to_ie iface) used)+ ; return (L l (decl { ideclHiding = Just (False, L l lies) })) }+ where+ doc = text "Compute minimal imports for" <+> ppr decl++ to_ie :: ModIface -> AvailInfo -> [IE Name]+ -- The main trick here is that if we're importing all the constructors+ -- we want to say "T(..)", but if we're importing only a subset we want+ -- to say "T(A,B,C)". So we have to find out what the module exports.+ to_ie _ (Avail n)+ = [IEVar (to_ie_post_rn $ noLoc n)]+ to_ie _ (AvailTC n [m] [])+ | n==m = [IEThingAbs (to_ie_post_rn $ noLoc n)]+ to_ie iface (AvailTC n ns fs)+ = case [(xs,gs) | AvailTC x xs gs <- mi_exports iface+ , x == n+ , x `elem` xs -- Note [Partial export]+ ] of+ [xs] | all_used xs -> [IEThingAll (to_ie_post_rn $ noLoc n)]+ | otherwise ->+ [IEThingWith (to_ie_post_rn $ noLoc n) NoIEWildcard+ (map (to_ie_post_rn . noLoc) (filter (/= n) ns))+ (map noLoc fs)]+ -- Note [Overloaded field import]+ _other | all_non_overloaded fs+ -> map (IEVar . to_ie_post_rn_var . noLoc) $ ns+ ++ map flSelector fs+ | otherwise ->+ [IEThingWith (to_ie_post_rn $ noLoc n) NoIEWildcard+ (map (to_ie_post_rn . noLoc) (filter (/= n) ns))+ (map noLoc fs)]+ where++ fld_lbls = map flLabel fs++ all_used (avail_occs, avail_flds)+ = all (`elem` ns) avail_occs+ && all (`elem` fld_lbls) (map flLabel avail_flds)++ all_non_overloaded = all (not . flIsOverloaded)++to_ie_post_rn_var :: (HasOccName name) => Located name -> LIEWrappedName name+to_ie_post_rn_var (L l n)+ | isDataOcc $ occName n = L l (IEPattern (L l n))+ | otherwise = L l (IEName (L l n))+++to_ie_post_rn :: (HasOccName name) => Located name -> LIEWrappedName name+to_ie_post_rn (L l n)+ | isTcOcc occ && isSymOcc occ = L l (IEType (L l n))+ | otherwise = L l (IEName (L l n))+ where occ = occName n++{-+Note [Partial export]+~~~~~~~~~~~~~~~~~~~~~+Suppose we have++ module A( op ) where+ class C a where+ op :: a -> a++ module B where+ import A+ f = ..op...++Then the minimal import for module B is+ import A( op )+not+ import A( C( op ) )+which we would usually generate if C was exported from B. Hence+the (x `elem` xs) test when deciding what to generate.+++Note [Overloaded field import]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+On the other hand, if we have++ {-# LANGUAGE DuplicateRecordFields #-}+ module A where+ data T = MkT { foo :: Int }++ module B where+ import A+ f = ...foo...++then the minimal import for module B must be+ import A ( T(foo) )+because when DuplicateRecordFields is enabled, field selectors are+not in scope without their enclosing datatype.+++************************************************************************+* *+\subsection{Errors}+* *+************************************************************************+-}++qualImportItemErr :: RdrName -> SDoc+qualImportItemErr rdr+ = hang (text "Illegal qualified name in import item:")+ 2 (ppr rdr)++badImportItemErrStd :: ModIface -> ImpDeclSpec -> IE RdrName -> SDoc+badImportItemErrStd iface decl_spec ie+ = sep [text "Module", quotes (ppr (is_mod decl_spec)), source_import,+ text "does not export", quotes (ppr ie)]+ where+ source_import | mi_boot iface = text "(hi-boot interface)"+ | otherwise = Outputable.empty++badImportItemErrDataCon :: OccName -> ModIface -> ImpDeclSpec -> IE RdrName -> SDoc+badImportItemErrDataCon dataType_occ iface decl_spec ie+ = vcat [ text "In module"+ <+> quotes (ppr (is_mod decl_spec))+ <+> source_import <> colon+ , nest 2 $ quotes datacon+ <+> text "is a data constructor of"+ <+> quotes dataType+ , text "To import it use"+ , nest 2 $ text "import"+ <+> ppr (is_mod decl_spec)+ <> parens_sp (dataType <> parens_sp datacon)+ , text "or"+ , nest 2 $ text "import"+ <+> ppr (is_mod decl_spec)+ <> parens_sp (dataType <> text "(..)")+ ]+ where+ datacon_occ = rdrNameOcc $ ieName ie+ datacon = parenSymOcc datacon_occ (ppr datacon_occ)+ dataType = parenSymOcc dataType_occ (ppr dataType_occ)+ source_import | mi_boot iface = text "(hi-boot interface)"+ | otherwise = Outputable.empty+ parens_sp d = parens (space <> d <> space) -- T( f,g )++badImportItemErr :: ModIface -> ImpDeclSpec -> IE RdrName -> [AvailInfo] -> SDoc+badImportItemErr iface decl_spec ie avails+ = case find checkIfDataCon avails of+ Just con -> badImportItemErrDataCon (availOccName con) iface decl_spec ie+ Nothing -> badImportItemErrStd iface decl_spec ie+ where+ checkIfDataCon (AvailTC _ ns _) =+ case find (\n -> importedFS == nameOccNameFS n) ns of+ Just n -> isDataConName n+ Nothing -> False+ checkIfDataCon _ = False+ availOccName = nameOccName . availName+ nameOccNameFS = occNameFS . nameOccName+ importedFS = occNameFS . rdrNameOcc $ ieName ie++illegalImportItemErr :: SDoc+illegalImportItemErr = text "Illegal import item"++dodgyImportWarn :: RdrName -> SDoc+dodgyImportWarn item = dodgyMsg (text "import") item++dodgyMsg :: (OutputableBndr n, HasOccName n) => SDoc -> n -> SDoc+dodgyMsg kind tc+ = sep [ text "The" <+> kind <+> ptext (sLit "item")+ <+> quotes (ppr (IEThingAll (noLoc (IEName $ noLoc tc))))+ <+> text "suggests that",+ quotes (ppr tc) <+> text "has (in-scope) constructors or class methods,",+ text "but it has none" ]+++addDupDeclErr :: [GlobalRdrElt] -> TcRn ()+addDupDeclErr [] = panic "addDupDeclErr: empty list"+addDupDeclErr gres@(gre : _)+ = addErrAt (getSrcSpan (last sorted_names)) $+ -- Report the error at the later location+ vcat [text "Multiple declarations of" <+>+ quotes (ppr (nameOccName name)),+ -- NB. print the OccName, not the Name, because the+ -- latter might not be in scope in the RdrEnv and so will+ -- be printed qualified.+ text "Declared at:" <+>+ vcat (map (ppr . nameSrcLoc) sorted_names)]+ where+ name = gre_name gre+ sorted_names = sortWith nameSrcLoc (map gre_name gres)++++missingImportListWarn :: ModuleName -> SDoc+missingImportListWarn mod+ = text "The module" <+> quotes (ppr mod) <+> ptext (sLit "does not have an explicit import list")++missingImportListItem :: IE RdrName -> SDoc+missingImportListItem ie+ = text "The import item" <+> quotes (ppr ie) <+> ptext (sLit "does not have an explicit import list")++moduleWarn :: ModuleName -> WarningTxt -> SDoc+moduleWarn mod (WarningTxt _ txt)+ = sep [ text "Module" <+> quotes (ppr mod) <> ptext (sLit ":"),+ nest 2 (vcat (map (ppr . sl_fs . unLoc) txt)) ]+moduleWarn mod (DeprecatedTxt _ txt)+ = sep [ text "Module" <+> quotes (ppr mod)+ <+> text "is deprecated:",+ nest 2 (vcat (map (ppr . sl_fs . unLoc) txt)) ]++packageImportErr :: SDoc+packageImportErr+ = text "Package-qualified imports are not enabled; use PackageImports"++-- This data decl will parse OK+-- data T = a Int+-- treating "a" as the constructor.+-- It is really hard to make the parser spot this malformation.+-- So the renamer has to check that the constructor is legal+--+-- We can get an operator as the constructor, even in the prefix form:+-- data T = :% Int Int+-- from interface files, which always print in prefix form++checkConName :: RdrName -> TcRn ()+checkConName name = checkErr (isRdrDataCon name) (badDataCon name)++badDataCon :: RdrName -> SDoc+badDataCon name+ = hsep [text "Illegal data constructor name", quotes (ppr name)]
+ rename/RnPat.hs view
@@ -0,0 +1,861 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[RnPat]{Renaming of patterns}++Basically dependency analysis.++Handles @Match@, @GRHSs@, @HsExpr@, and @Qualifier@ datatypes. In+general, all of these functions return a renamed thing, and a set of+free variables.+-}++{-# LANGUAGE CPP, RankNTypes, ScopedTypeVariables #-}++module RnPat (-- main entry points+ rnPat, rnPats, rnBindPat, rnPatAndThen,++ NameMaker, applyNameMaker, -- a utility for making names:+ localRecNameMaker, topRecNameMaker, -- sometimes we want to make local names,+ -- sometimes we want to make top (qualified) names.+ isTopRecNameMaker,++ rnHsRecFields, HsRecFieldContext(..),+ rnHsRecUpdFields,++ -- CpsRn monad+ CpsRn, liftCps,++ -- Literals+ rnLit, rnOverLit,++ -- Pattern Error messages that are also used elsewhere+ checkTupSize, patSigErr+ ) where++-- ENH: thin imports to only what is necessary for patterns++import {-# SOURCE #-} RnExpr ( rnLExpr )+import {-# SOURCE #-} RnSplice ( rnSplicePat )++#include "HsVersions.h"++import HsSyn+import TcRnMonad+import TcHsSyn ( hsOverLitName )+import RnEnv+import RnTypes+import PrelNames+import TyCon ( tyConName )+import ConLike+import Type ( TyThing(..) )+import Name+import NameSet+import RdrName+import BasicTypes+import Util+import ListSetOps ( removeDups )+import Outputable+import SrcLoc+import Literal ( inCharRange )+import TysWiredIn ( nilDataCon )+import DataCon+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad ( when, liftM, ap, unless )+import Data.Ratio++{-+*********************************************************+* *+ The CpsRn Monad+* *+*********************************************************++Note [CpsRn monad]+~~~~~~~~~~~~~~~~~~+The CpsRn monad uses continuation-passing style to support this+style of programming:++ do { ...+ ; ns <- bindNames rs+ ; ...blah... }++ where rs::[RdrName], ns::[Name]++The idea is that '...blah...'+ a) sees the bindings of ns+ b) returns the free variables it mentions+ so that bindNames can report unused ones++In particular,+ mapM rnPatAndThen [p1, p2, p3]+has a *left-to-right* scoping: it makes the binders in+p1 scope over p2,p3.+-}++newtype CpsRn b = CpsRn { unCpsRn :: forall r. (b -> RnM (r, FreeVars))+ -> RnM (r, FreeVars) }+ -- See Note [CpsRn monad]++instance Functor CpsRn where+ fmap = liftM++instance Applicative CpsRn where+ pure x = CpsRn (\k -> k x)+ (<*>) = ap++instance Monad CpsRn where+ (CpsRn m) >>= mk = CpsRn (\k -> m (\v -> unCpsRn (mk v) k))++runCps :: CpsRn a -> RnM (a, FreeVars)+runCps (CpsRn m) = m (\r -> return (r, emptyFVs))++liftCps :: RnM a -> CpsRn a+liftCps rn_thing = CpsRn (\k -> rn_thing >>= k)++liftCpsFV :: RnM (a, FreeVars) -> CpsRn a+liftCpsFV rn_thing = CpsRn (\k -> do { (v,fvs1) <- rn_thing+ ; (r,fvs2) <- k v+ ; return (r, fvs1 `plusFV` fvs2) })++wrapSrcSpanCps :: (a -> CpsRn b) -> Located a -> CpsRn (Located b)+-- Set the location, and also wrap it around the value returned+wrapSrcSpanCps fn (L loc a)+ = CpsRn (\k -> setSrcSpan loc $+ unCpsRn (fn a) $ \v ->+ k (L loc v))++lookupConCps :: Located RdrName -> CpsRn (Located Name)+lookupConCps con_rdr+ = CpsRn (\k -> do { con_name <- lookupLocatedOccRn con_rdr+ ; (r, fvs) <- k con_name+ ; return (r, addOneFV fvs (unLoc con_name)) })+ -- We add the constructor name to the free vars+ -- See Note [Patterns are uses]++{-+Note [Patterns are uses]+~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ module Foo( f, g ) where+ data T = T1 | T2++ f T1 = True+ f T2 = False++ g _ = T1++Arguably we should report T2 as unused, even though it appears in a+pattern, because it never occurs in a constructed position. See+Trac #7336.+However, implementing this in the face of pattern synonyms would be+less straightforward, since given two pattern synonyms++ pattern P1 <- P2+ pattern P2 <- ()++we need to observe the dependency between P1 and P2 so that type+checking can be done in the correct order (just like for value+bindings). Dependencies between bindings is analyzed in the renamer,+where we don't know yet whether P2 is a constructor or a pattern+synonym. So for now, we do report conid occurrences in patterns as+uses.++*********************************************************+* *+ Name makers+* *+*********************************************************++Externally abstract type of name makers,+which is how you go from a RdrName to a Name+-}++data NameMaker+ = LamMk -- Lambdas+ Bool -- True <=> report unused bindings+ -- (even if True, the warning only comes out+ -- if -Wunused-matches is on)++ | LetMk -- Let bindings, incl top level+ -- Do *not* check for unused bindings+ TopLevelFlag+ MiniFixityEnv++topRecNameMaker :: MiniFixityEnv -> NameMaker+topRecNameMaker fix_env = LetMk TopLevel fix_env++isTopRecNameMaker :: NameMaker -> Bool+isTopRecNameMaker (LetMk TopLevel _) = True+isTopRecNameMaker _ = False++localRecNameMaker :: MiniFixityEnv -> NameMaker+localRecNameMaker fix_env = LetMk NotTopLevel fix_env++matchNameMaker :: HsMatchContext a -> NameMaker+matchNameMaker ctxt = LamMk report_unused+ where+ -- Do not report unused names in interactive contexts+ -- i.e. when you type 'x <- e' at the GHCi prompt+ report_unused = case ctxt of+ StmtCtxt GhciStmtCtxt -> False+ -- also, don't warn in pattern quotes, as there+ -- is no RHS where the variables can be used!+ ThPatQuote -> False+ _ -> True++rnHsSigCps :: LHsSigWcType RdrName -> CpsRn (LHsSigWcType Name)+rnHsSigCps sig = CpsRn (rnHsSigWcTypeScoped PatCtx sig)++newPatLName :: NameMaker -> Located RdrName -> CpsRn (Located Name)+newPatLName name_maker rdr_name@(L loc _)+ = do { name <- newPatName name_maker rdr_name+ ; return (L loc name) }++newPatName :: NameMaker -> Located RdrName -> CpsRn Name+newPatName (LamMk report_unused) rdr_name+ = CpsRn (\ thing_inside ->+ do { name <- newLocalBndrRn rdr_name+ ; (res, fvs) <- bindLocalNames [name] (thing_inside name)+ ; when report_unused $ warnUnusedMatches [name] fvs+ ; return (res, name `delFV` fvs) })++newPatName (LetMk is_top fix_env) rdr_name+ = CpsRn (\ thing_inside ->+ do { name <- case is_top of+ NotTopLevel -> newLocalBndrRn rdr_name+ TopLevel -> newTopSrcBinder rdr_name+ ; bindLocalNames [name] $ -- Do *not* use bindLocalNameFV here+ -- See Note [View pattern usage]+ addLocalFixities fix_env [name] $+ thing_inside name })++ -- Note: the bindLocalNames is somewhat suspicious+ -- because it binds a top-level name as a local name.+ -- however, this binding seems to work, and it only exists for+ -- the duration of the patterns and the continuation;+ -- then the top-level name is added to the global env+ -- before going on to the RHSes (see RnSource.hs).++{-+Note [View pattern usage]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ let (r, (r -> x)) = x in ...+Here the pattern binds 'r', and then uses it *only* in the view pattern.+We want to "see" this use, and in let-bindings we collect all uses and+report unused variables at the binding level. So we must use bindLocalNames+here, *not* bindLocalNameFV. Trac #3943.+++Note [Don't report shadowing for pattern synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There is one special context where a pattern doesn't introduce any new binders -+pattern synonym declarations. Therefore we don't check to see if pattern+variables shadow existing identifiers as they are never bound to anything+and have no scope.++Without this check, there would be quite a cryptic warning that the `x`+in the RHS of the pattern synonym declaration shadowed the top level `x`.++```+x :: ()+x = ()++pattern P x = Just x+```++See #12615 for some more examples.++*********************************************************+* *+ External entry points+* *+*********************************************************++There are various entry points to renaming patterns, depending on+ (1) whether the names created should be top-level names or local names+ (2) whether the scope of the names is entirely given in a continuation+ (e.g., in a case or lambda, but not in a let or at the top-level,+ because of the way mutually recursive bindings are handled)+ (3) whether the a type signature in the pattern can bind+ lexically-scoped type variables (for unpacking existential+ type vars in data constructors)+ (4) whether we do duplicate and unused variable checking+ (5) whether there are fixity declarations associated with the names+ bound by the patterns that need to be brought into scope with them.++ Rather than burdening the clients of this module with all of these choices,+ we export the three points in this design space that we actually need:+-}++-- ----------- Entry point 1: rnPats -------------------+-- Binds local names; the scope of the bindings is entirely in the thing_inside+-- * allows type sigs to bind type vars+-- * local namemaker+-- * unused and duplicate checking+-- * no fixities+rnPats :: HsMatchContext Name -- for error messages+ -> [LPat RdrName]+ -> ([LPat Name] -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+rnPats ctxt pats thing_inside+ = do { envs_before <- getRdrEnvs++ -- (1) rename the patterns, bringing into scope all of the term variables+ -- (2) then do the thing inside.+ ; unCpsRn (rnLPatsAndThen (matchNameMaker ctxt) pats) $ \ pats' -> do+ { -- Check for duplicated and shadowed names+ -- Must do this *after* renaming the patterns+ -- See Note [Collect binders only after renaming] in HsUtils+ -- Because we don't bind the vars all at once, we can't+ -- check incrementally for duplicates;+ -- Nor can we check incrementally for shadowing, else we'll+ -- complain *twice* about duplicates e.g. f (x,x) = ...+ --+ -- See note [Don't report shadowing for pattern synonyms]+ ; unless (isPatSynCtxt ctxt)+ (addErrCtxt doc_pat $+ checkDupAndShadowedNames envs_before $+ collectPatsBinders pats')+ ; thing_inside pats' } }+ where+ doc_pat = text "In" <+> pprMatchContext ctxt++rnPat :: HsMatchContext Name -- for error messages+ -> LPat RdrName+ -> (LPat Name -> RnM (a, FreeVars))+ -> RnM (a, FreeVars) -- Variables bound by pattern do not+ -- appear in the result FreeVars+rnPat ctxt pat thing_inside+ = rnPats ctxt [pat] (\pats' -> let [pat'] = pats' in thing_inside pat')++applyNameMaker :: NameMaker -> Located RdrName -> RnM (Located Name)+applyNameMaker mk rdr = do { (n, _fvs) <- runCps (newPatLName mk rdr)+ ; return n }++-- ----------- Entry point 2: rnBindPat -------------------+-- Binds local names; in a recursive scope that involves other bound vars+-- e.g let { (x, Just y) = e1; ... } in ...+-- * does NOT allows type sig to bind type vars+-- * local namemaker+-- * no unused and duplicate checking+-- * fixities might be coming in+rnBindPat :: NameMaker+ -> LPat RdrName+ -> RnM (LPat Name, FreeVars)+ -- Returned FreeVars are the free variables of the pattern,+ -- of course excluding variables bound by this pattern++rnBindPat name_maker pat = runCps (rnLPatAndThen name_maker pat)++{-+*********************************************************+* *+ The main event+* *+*********************************************************+-}++-- ----------- Entry point 3: rnLPatAndThen -------------------+-- General version: parametrized by how you make new names++rnLPatsAndThen :: NameMaker -> [LPat RdrName] -> CpsRn [LPat Name]+rnLPatsAndThen mk = mapM (rnLPatAndThen mk)+ -- Despite the map, the monad ensures that each pattern binds+ -- variables that may be mentioned in subsequent patterns in the list++--------------------+-- The workhorse+rnLPatAndThen :: NameMaker -> LPat RdrName -> CpsRn (LPat Name)+rnLPatAndThen nm lpat = wrapSrcSpanCps (rnPatAndThen nm) lpat++rnPatAndThen :: NameMaker -> Pat RdrName -> CpsRn (Pat Name)+rnPatAndThen _ (WildPat _) = return (WildPat placeHolderType)+rnPatAndThen mk (ParPat pat) = do { pat' <- rnLPatAndThen mk pat; return (ParPat pat') }+rnPatAndThen mk (LazyPat pat) = do { pat' <- rnLPatAndThen mk pat; return (LazyPat pat') }+rnPatAndThen mk (BangPat pat) = do { pat' <- rnLPatAndThen mk pat; return (BangPat pat') }+rnPatAndThen mk (VarPat (L l rdr)) = do { loc <- liftCps getSrcSpanM+ ; name <- newPatName mk (L loc rdr)+ ; return (VarPat (L l name)) }+ -- we need to bind pattern variables for view pattern expressions+ -- (e.g. in the pattern (x, x -> y) x needs to be bound in the rhs of the tuple)++rnPatAndThen mk (SigPatIn pat sig)+ -- When renaming a pattern type signature (e.g. f (a :: T) = ...), it is+ -- important to rename its type signature _before_ renaming the rest of the+ -- pattern, so that type variables are first bound by the _outermost_ pattern+ -- type signature they occur in. This keeps the type checker happy when+ -- pattern type signatures happen to be nested (#7827)+ --+ -- f ((Just (x :: a) :: Maybe a)+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~^ `a' is first bound here+ -- ~~~~~~~~~~~~~~~^ the same `a' then used here+ = do { sig' <- rnHsSigCps sig+ ; pat' <- rnLPatAndThen mk pat+ ; return (SigPatIn pat' sig') }++rnPatAndThen mk (LitPat lit)+ | HsString src s <- lit+ = do { ovlStr <- liftCps (xoptM LangExt.OverloadedStrings)+ ; if ovlStr+ then rnPatAndThen mk+ (mkNPat (noLoc (mkHsIsString src s placeHolderType))+ Nothing)+ else normal_lit }+ | otherwise = normal_lit+ where+ normal_lit = do { liftCps (rnLit lit); return (LitPat lit) }++rnPatAndThen _ (NPat (L l lit) mb_neg _eq _)+ = do { lit' <- liftCpsFV $ rnOverLit lit+ ; mb_neg' <- liftCpsFV $ case mb_neg of+ Nothing -> return (Nothing, emptyFVs)+ Just _ -> do { (neg, fvs) <- lookupSyntaxName negateName+ ; return (Just neg, fvs) }+ ; eq' <- liftCpsFV $ lookupSyntaxName eqName+ ; return (NPat (L l lit') mb_neg' eq' placeHolderType) }++rnPatAndThen mk (NPlusKPat rdr (L l lit) _ _ _ _)+ = do { new_name <- newPatName mk rdr+ ; lit' <- liftCpsFV $ rnOverLit lit+ ; minus <- liftCpsFV $ lookupSyntaxName minusName+ ; ge <- liftCpsFV $ lookupSyntaxName geName+ ; return (NPlusKPat (L (nameSrcSpan new_name) new_name)+ (L l lit') lit' ge minus placeHolderType) }+ -- The Report says that n+k patterns must be in Integral++rnPatAndThen mk (AsPat rdr pat)+ = do { new_name <- newPatLName mk rdr+ ; pat' <- rnLPatAndThen mk pat+ ; return (AsPat new_name pat') }++rnPatAndThen mk p@(ViewPat expr pat _ty)+ = do { liftCps $ do { vp_flag <- xoptM LangExt.ViewPatterns+ ; checkErr vp_flag (badViewPat p) }+ -- Because of the way we're arranging the recursive calls,+ -- this will be in the right context+ ; expr' <- liftCpsFV $ rnLExpr expr+ ; pat' <- rnLPatAndThen mk pat+ -- Note: at this point the PreTcType in ty can only be a placeHolder+ -- ; return (ViewPat expr' pat' ty) }+ ; return (ViewPat expr' pat' placeHolderType) }++rnPatAndThen mk (ConPatIn con stuff)+ -- rnConPatAndThen takes care of reconstructing the pattern+ -- The pattern for the empty list needs to be replaced by an empty explicit list pattern when overloaded lists is turned on.+ = case unLoc con == nameRdrName (dataConName nilDataCon) of+ True -> do { ol_flag <- liftCps $ xoptM LangExt.OverloadedLists+ ; if ol_flag then rnPatAndThen mk (ListPat [] placeHolderType Nothing)+ else rnConPatAndThen mk con stuff}+ False -> rnConPatAndThen mk con stuff++rnPatAndThen mk (ListPat pats _ _)+ = do { opt_OverloadedLists <- liftCps $ xoptM LangExt.OverloadedLists+ ; pats' <- rnLPatsAndThen mk pats+ ; case opt_OverloadedLists of+ True -> do { (to_list_name,_) <- liftCps $ lookupSyntaxName toListName+ ; return (ListPat pats' placeHolderType+ (Just (placeHolderType, to_list_name)))}+ False -> return (ListPat pats' placeHolderType Nothing) }++rnPatAndThen mk (PArrPat pats _)+ = do { pats' <- rnLPatsAndThen mk pats+ ; return (PArrPat pats' placeHolderType) }++rnPatAndThen mk (TuplePat pats boxed _)+ = do { liftCps $ checkTupSize (length pats)+ ; pats' <- rnLPatsAndThen mk pats+ ; return (TuplePat pats' boxed []) }++rnPatAndThen mk (SumPat pat alt arity _)+ = do { pat <- rnLPatAndThen mk pat+ ; return (SumPat pat alt arity PlaceHolder)+ }++-- If a splice has been run already, just rename the result.+rnPatAndThen mk (SplicePat (HsSpliced mfs (HsSplicedPat pat)))+ = SplicePat . HsSpliced mfs . HsSplicedPat <$> rnPatAndThen mk pat++rnPatAndThen mk (SplicePat splice)+ = do { eith <- liftCpsFV $ rnSplicePat splice+ ; case eith of -- See Note [rnSplicePat] in RnSplice+ Left not_yet_renamed -> rnPatAndThen mk not_yet_renamed+ Right already_renamed -> return already_renamed }++rnPatAndThen _ pat = pprPanic "rnLPatAndThen" (ppr pat)+++--------------------+rnConPatAndThen :: NameMaker+ -> Located RdrName -- the constructor+ -> HsConPatDetails RdrName+ -> CpsRn (Pat Name)++rnConPatAndThen mk con (PrefixCon pats)+ = do { con' <- lookupConCps con+ ; pats' <- rnLPatsAndThen mk pats+ ; return (ConPatIn con' (PrefixCon pats')) }++rnConPatAndThen mk con (InfixCon pat1 pat2)+ = do { con' <- lookupConCps con+ ; pat1' <- rnLPatAndThen mk pat1+ ; pat2' <- rnLPatAndThen mk pat2+ ; fixity <- liftCps $ lookupFixityRn (unLoc con')+ ; liftCps $ mkConOpPatRn con' fixity pat1' pat2' }++rnConPatAndThen mk con (RecCon rpats)+ = do { con' <- lookupConCps con+ ; rpats' <- rnHsRecPatsAndThen mk con' rpats+ ; return (ConPatIn con' (RecCon rpats')) }++--------------------+rnHsRecPatsAndThen :: NameMaker+ -> Located Name -- Constructor+ -> HsRecFields RdrName (LPat RdrName)+ -> CpsRn (HsRecFields Name (LPat Name))+rnHsRecPatsAndThen mk (L _ con) hs_rec_fields@(HsRecFields { rec_dotdot = dd })+ = do { flds <- liftCpsFV $ rnHsRecFields (HsRecFieldPat con) mkVarPat+ hs_rec_fields+ ; flds' <- mapM rn_field (flds `zip` [1..])+ ; return (HsRecFields { rec_flds = flds', rec_dotdot = dd }) }+ where+ mkVarPat l n = VarPat (L l n)+ rn_field (L l fld, n') = do { arg' <- rnLPatAndThen (nested_mk dd mk n')+ (hsRecFieldArg fld)+ ; return (L l (fld { hsRecFieldArg = arg' })) }++ -- Suppress unused-match reporting for fields introduced by ".."+ nested_mk Nothing mk _ = mk+ nested_mk (Just _) mk@(LetMk {}) _ = mk+ nested_mk (Just n) (LamMk report_unused) n' = LamMk (report_unused && (n' <= n))++{-+************************************************************************+* *+ Record fields+* *+************************************************************************+-}++data HsRecFieldContext+ = HsRecFieldCon Name+ | HsRecFieldPat Name+ | HsRecFieldUpd++rnHsRecFields+ :: forall arg.+ HsRecFieldContext+ -> (SrcSpan -> RdrName -> arg)+ -- When punning, use this to build a new field+ -> HsRecFields RdrName (Located arg)+ -> RnM ([LHsRecField Name (Located arg)], FreeVars)++-- This surprisingly complicated pass+-- a) looks up the field name (possibly using disambiguation)+-- b) fills in puns and dot-dot stuff+-- When we we've finished, we've renamed the LHS, but not the RHS,+-- of each x=e binding+--+-- This is used for record construction and pattern-matching, but not updates.++rnHsRecFields ctxt mk_arg (HsRecFields { rec_flds = flds, rec_dotdot = dotdot })+ = do { pun_ok <- xoptM LangExt.RecordPuns+ ; disambig_ok <- xoptM LangExt.DisambiguateRecordFields+ ; parent <- check_disambiguation disambig_ok mb_con+ ; flds1 <- mapM (rn_fld pun_ok parent) flds+ ; mapM_ (addErr . dupFieldErr ctxt) dup_flds+ ; dotdot_flds <- rn_dotdot dotdot mb_con flds1+ ; let all_flds | null dotdot_flds = flds1+ | otherwise = flds1 ++ dotdot_flds+ ; return (all_flds, mkFVs (getFieldIds all_flds)) }+ where+ mb_con = case ctxt of+ HsRecFieldCon con | not (isUnboundName con) -> Just con+ HsRecFieldPat con | not (isUnboundName con) -> Just con+ _ {- update or isUnboundName con -} -> Nothing+ -- The unbound name test is because if the constructor+ -- isn't in scope the constructor lookup will add an error+ -- add an error, but still return an unbound name.+ -- We don't want that to screw up the dot-dot fill-in stuff.++ doc = case mb_con of+ Nothing -> text "constructor field name"+ Just con -> text "field of constructor" <+> quotes (ppr con)++ rn_fld :: Bool -> Maybe Name -> LHsRecField RdrName (Located arg)+ -> RnM (LHsRecField Name (Located arg))+ rn_fld pun_ok parent (L l (HsRecField { hsRecFieldLbl+ = L loc (FieldOcc (L ll lbl) _)+ , hsRecFieldArg = arg+ , hsRecPun = pun }))+ = do { sel <- setSrcSpan loc $ lookupRecFieldOcc parent doc lbl+ ; arg' <- if pun+ then do { checkErr pun_ok (badPun (L loc lbl))+ -- Discard any module qualifier (#11662)+ ; let arg_rdr = mkRdrUnqual (rdrNameOcc lbl)+ ; return (L loc (mk_arg loc arg_rdr)) }+ else return arg+ ; return (L l (HsRecField { hsRecFieldLbl+ = L loc (FieldOcc (L ll lbl) sel)+ , hsRecFieldArg = arg'+ , hsRecPun = pun })) }++ rn_dotdot :: Maybe Int -- See Note [DotDot fields] in HsPat+ -> Maybe Name -- The constructor (Nothing for an+ -- out of scope constructor)+ -> [LHsRecField Name (Located arg)] -- Explicit fields+ -> RnM [LHsRecField Name (Located arg)] -- Filled in .. fields+ rn_dotdot Nothing _mb_con _flds -- No ".." at all+ = return []+ rn_dotdot (Just {}) Nothing _flds -- Constructor out of scope+ = return []+ rn_dotdot (Just n) (Just con) flds -- ".." on record construction / pat match+ = ASSERT( n == length flds )+ do { loc <- getSrcSpanM -- Rather approximate+ ; dd_flag <- xoptM LangExt.RecordWildCards+ ; checkErr dd_flag (needFlagDotDot ctxt)+ ; (rdr_env, lcl_env) <- getRdrEnvs+ ; con_fields <- lookupConstructorFields con+ ; when (null con_fields) (addErr (badDotDotCon con))+ ; let present_flds = mkOccSet $ map rdrNameOcc (getFieldLbls flds)++ -- For constructor uses (but not patterns)+ -- the arg should be in scope locally;+ -- i.e. not top level or imported+ -- Eg. data R = R { x,y :: Int }+ -- f x = R { .. } -- Should expand to R {x=x}, not R{x=x,y=y}+ arg_in_scope lbl = mkRdrUnqual lbl `elemLocalRdrEnv` lcl_env++ (dot_dot_fields, dot_dot_gres)+ = unzip [ (fl, gre)+ | fl <- con_fields+ , let lbl = mkVarOccFS (flLabel fl)+ , not (lbl `elemOccSet` present_flds)+ , Just gre <- [lookupGRE_FieldLabel rdr_env fl]+ -- Check selector is in scope+ , case ctxt of+ HsRecFieldCon {} -> arg_in_scope lbl+ _other -> True ]++ ; addUsedGREs dot_dot_gres+ ; return [ L loc (HsRecField+ { hsRecFieldLbl = L loc (FieldOcc (L loc arg_rdr) sel)+ , hsRecFieldArg = L loc (mk_arg loc arg_rdr)+ , hsRecPun = False })+ | fl <- dot_dot_fields+ , let sel = flSelector fl+ , let arg_rdr = mkVarUnqual (flLabel fl) ] }++ check_disambiguation :: Bool -> Maybe Name -> RnM (Maybe Name)+ -- When disambiguation is on, return name of parent tycon.+ check_disambiguation disambig_ok mb_con+ | disambig_ok, Just con <- mb_con+ = do { env <- getGlobalRdrEnv; return (find_tycon env con) }+ | otherwise = return Nothing++ find_tycon :: GlobalRdrEnv -> Name {- DataCon -} -> Maybe Name {- TyCon -}+ -- Return the parent *type constructor* of the data constructor+ -- (that is, the parent of the data constructor),+ -- or 'Nothing' if it is a pattern synonym or not in scope.+ -- That's the parent to use for looking up record fields.+ find_tycon env con_name+ | Just (AConLike (RealDataCon dc)) <- wiredInNameTyThing_maybe con_name+ = Just (tyConName (dataConTyCon dc))+ -- Special case for [], which is built-in syntax+ -- and not in the GlobalRdrEnv (Trac #8448)++ | Just gre <- lookupGRE_Name env con_name+ = case gre_par gre of+ ParentIs p -> Just p+ _ -> Nothing -- Can happen if the con_name+ -- is for a pattern synonym++ | otherwise = Nothing+ -- Data constructor not lexically in scope at all+ -- See Note [Disambiguation and Template Haskell]++ dup_flds :: [[RdrName]]+ -- Each list represents a RdrName that occurred more than once+ -- (the list contains all occurrences)+ -- Each list in dup_fields is non-empty+ (_, dup_flds) = removeDups compare (getFieldLbls flds)+++{- Note [Disambiguation and Template Haskell]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #12130)+ module Foo where+ import M+ b = $(funny)++ module M(funny) where+ data T = MkT { x :: Int }+ funny :: Q Exp+ funny = [| MkT { x = 3 } |]++When we splice, neither T nor MkT are lexically in scope, so find_tycon will+fail. But there is no need for disambiguation anyway, so we just return Nothing+-}++rnHsRecUpdFields+ :: [LHsRecUpdField RdrName]+ -> RnM ([LHsRecUpdField Name], FreeVars)+rnHsRecUpdFields flds+ = do { pun_ok <- xoptM LangExt.RecordPuns+ ; overload_ok <- xoptM LangExt.DuplicateRecordFields+ ; (flds1, fvss) <- mapAndUnzipM (rn_fld pun_ok overload_ok) flds+ ; mapM_ (addErr . dupFieldErr HsRecFieldUpd) dup_flds++ -- Check for an empty record update e {}+ -- NB: don't complain about e { .. }, because rn_dotdot has done that already+ ; when (null flds) $ addErr emptyUpdateErr++ ; return (flds1, plusFVs fvss) }+ where+ doc = text "constructor field name"++ rn_fld :: Bool -> Bool -> LHsRecUpdField RdrName -> RnM (LHsRecUpdField Name, FreeVars)+ rn_fld pun_ok overload_ok (L l (HsRecField { hsRecFieldLbl = L loc f+ , hsRecFieldArg = arg+ , hsRecPun = pun }))+ = do { let lbl = rdrNameAmbiguousFieldOcc f+ ; sel <- setSrcSpan loc $+ -- Defer renaming of overloaded fields to the typechecker+ -- See Note [Disambiguating record fields] in TcExpr+ if overload_ok+ then do { mb <- lookupGlobalOccRn_overloaded overload_ok lbl+ ; case mb of+ Nothing -> do { addErr (unknownSubordinateErr doc lbl)+ ; return (Right []) }+ Just r -> return r }+ else fmap Left $ lookupGlobalOccRn lbl+ ; arg' <- if pun+ then do { checkErr pun_ok (badPun (L loc lbl))+ -- Discard any module qualifier (#11662)+ ; let arg_rdr = mkRdrUnqual (rdrNameOcc lbl)+ ; return (L loc (HsVar (L loc arg_rdr))) }+ else return arg+ ; (arg'', fvs) <- rnLExpr arg'++ ; let fvs' = case sel of+ Left sel_name -> fvs `addOneFV` sel_name+ Right [FieldOcc _ sel_name] -> fvs `addOneFV` sel_name+ Right _ -> fvs+ lbl' = case sel of+ Left sel_name ->+ L loc (Unambiguous (L loc lbl) sel_name)+ Right [FieldOcc lbl sel_name] ->+ L loc (Unambiguous lbl sel_name)+ Right _ -> L loc (Ambiguous (L loc lbl) PlaceHolder)++ ; return (L l (HsRecField { hsRecFieldLbl = lbl'+ , hsRecFieldArg = arg''+ , hsRecPun = pun }), fvs') }++ dup_flds :: [[RdrName]]+ -- Each list represents a RdrName that occurred more than once+ -- (the list contains all occurrences)+ -- Each list in dup_fields is non-empty+ (_, dup_flds) = removeDups compare (getFieldUpdLbls flds)++++getFieldIds :: [LHsRecField Name arg] -> [Name]+getFieldIds flds = map (unLoc . hsRecFieldSel . unLoc) flds++getFieldLbls :: [LHsRecField id arg] -> [RdrName]+getFieldLbls flds+ = map (unLoc . rdrNameFieldOcc . unLoc . hsRecFieldLbl . unLoc) flds++getFieldUpdLbls :: [LHsRecUpdField id] -> [RdrName]+getFieldUpdLbls flds = map (rdrNameAmbiguousFieldOcc . unLoc . hsRecFieldLbl . unLoc) flds++needFlagDotDot :: HsRecFieldContext -> SDoc+needFlagDotDot ctxt = vcat [text "Illegal `..' in record" <+> pprRFC ctxt,+ text "Use RecordWildCards to permit this"]++badDotDotCon :: Name -> SDoc+badDotDotCon con+ = vcat [ text "Illegal `..' notation for constructor" <+> quotes (ppr con)+ , nest 2 (text "The constructor has no labelled fields") ]++emptyUpdateErr :: SDoc+emptyUpdateErr = text "Empty record update"++badPun :: Located RdrName -> SDoc+badPun fld = vcat [text "Illegal use of punning for field" <+> quotes (ppr fld),+ text "Use NamedFieldPuns to permit this"]++dupFieldErr :: HsRecFieldContext -> [RdrName] -> SDoc+dupFieldErr ctxt dups+ = hsep [text "duplicate field name",+ quotes (ppr (head dups)),+ text "in record", pprRFC ctxt]++pprRFC :: HsRecFieldContext -> SDoc+pprRFC (HsRecFieldCon {}) = text "construction"+pprRFC (HsRecFieldPat {}) = text "pattern"+pprRFC (HsRecFieldUpd {}) = text "update"++{-+************************************************************************+* *+\subsubsection{Literals}+* *+************************************************************************++When literals occur we have to make sure+that the types and classes they involve+are made available.+-}++rnLit :: HsLit -> RnM ()+rnLit (HsChar _ c) = checkErr (inCharRange c) (bogusCharError c)+rnLit _ = return ()++-- Turn a Fractional-looking literal which happens to be an integer into an+-- Integer-looking literal.+generalizeOverLitVal :: OverLitVal -> OverLitVal+generalizeOverLitVal (HsFractional (FL {fl_text=src,fl_value=val}))+ | denominator val == 1 = HsIntegral (SourceText src) (numerator val)+generalizeOverLitVal lit = lit++rnOverLit :: HsOverLit t -> RnM (HsOverLit Name, FreeVars)+rnOverLit origLit+ = do { opt_NumDecimals <- xoptM LangExt.NumDecimals+ ; let { lit@(OverLit {ol_val=val})+ | opt_NumDecimals = origLit {ol_val = generalizeOverLitVal (ol_val origLit)}+ | otherwise = origLit+ }+ ; let std_name = hsOverLitName val+ ; (SyntaxExpr { syn_expr = from_thing_name }, fvs)+ <- lookupSyntaxName std_name+ ; let rebindable = case from_thing_name of+ HsVar (L _ v) -> v /= std_name+ _ -> panic "rnOverLit"+ ; return (lit { ol_witness = from_thing_name+ , ol_rebindable = rebindable+ , ol_type = placeHolderType }, fvs) }++{-+************************************************************************+* *+\subsubsection{Errors}+* *+************************************************************************+-}++patSigErr :: Outputable a => a -> SDoc+patSigErr ty+ = (text "Illegal signature in pattern:" <+> ppr ty)+ $$ nest 4 (text "Use ScopedTypeVariables to permit it")++bogusCharError :: Char -> SDoc+bogusCharError c+ = text "character literal out of range: '\\" <> char c <> char '\''++badViewPat :: Pat RdrName -> SDoc+badViewPat pat = vcat [text "Illegal view pattern: " <+> ppr pat,+ text "Use ViewPatterns to enable view patterns"]
+ rename/RnSource.hs view
@@ -0,0 +1,2285 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[RnSource]{Main pass of renamer}+-}++{-# LANGUAGE CPP, ScopedTypeVariables #-}++module RnSource (+ rnSrcDecls, addTcgDUs, findSplice+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} RnExpr( rnLExpr )+import {-# SOURCE #-} RnSplice ( rnSpliceDecl, rnTopSpliceDecls )++import HsSyn+import FieldLabel+import RdrName+import RnTypes+import RnBinds+import RnEnv+import RnNames+import RnHsDoc ( rnHsDoc, rnMbLHsDoc )+import TcAnnotations ( annCtxt )+import TcRnMonad++import ForeignCall ( CCallTarget(..) )+import Module+import HscTypes ( Warnings(..), plusWarns )+import Class ( FunDep )+import PrelNames ( applicativeClassName, pureAName, thenAName+ , monadClassName, returnMName, thenMName+ , monadFailClassName, failMName, failMName_preMFP+ , semigroupClassName, sappendName+ , monoidClassName, mappendName+ )+import Name+import NameSet+import NameEnv+import Avail+import Outputable+import Bag+import BasicTypes ( DerivStrategy, RuleName, pprRuleName )+import FastString+import SrcLoc+import DynFlags+import Util ( debugIsOn, lengthExceeds, partitionWith )+import HscTypes ( HscEnv, hsc_dflags )+import ListSetOps ( findDupsEq, removeDups, equivClasses )+import Digraph ( SCC, flattenSCC, flattenSCCs+ , stronglyConnCompFromEdgedVerticesUniq )+import UniqSet+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Control.Arrow ( first )+import Data.List ( sortBy, mapAccumL )+import Data.Maybe ( isJust )+import qualified Data.Set as Set ( difference, fromList, toList, null )++{- | @rnSourceDecl@ "renames" declarations.+It simultaneously performs dependency analysis and precedence parsing.+It also does the following error checks:++* Checks that tyvars are used properly. This includes checking+ for undefined tyvars, and tyvars in contexts that are ambiguous.+ (Some of this checking has now been moved to module @TcMonoType@,+ since we don't have functional dependency information at this point.)++* Checks that all variable occurrences are defined.++* Checks the @(..)@ etc constraints in the export list.++Brings the binders of the group into scope in the appropriate places;+does NOT assume that anything is in scope already+-}+rnSrcDecls :: HsGroup RdrName -> RnM (TcGblEnv, HsGroup Name)+-- Rename a top-level HsGroup; used for normal source files *and* hs-boot files+rnSrcDecls group@(HsGroup { hs_valds = val_decls,+ hs_splcds = splice_decls,+ hs_tyclds = tycl_decls,+ hs_derivds = deriv_decls,+ hs_fixds = fix_decls,+ hs_warnds = warn_decls,+ hs_annds = ann_decls,+ hs_fords = foreign_decls,+ hs_defds = default_decls,+ hs_ruleds = rule_decls,+ hs_vects = vect_decls,+ hs_docs = docs })+ = do {+ -- (A) Process the fixity declarations, creating a mapping from+ -- FastStrings to FixItems.+ -- Also checks for duplicates.+ local_fix_env <- makeMiniFixityEnv fix_decls ;++ -- (B) Bring top level binders (and their fixities) into scope,+ -- *except* for the value bindings, which get done in step (D)+ -- with collectHsIdBinders. However *do* include+ --+ -- * Class ops, data constructors, and record fields,+ -- because they do not have value declarations.+ -- Aso step (C) depends on datacons and record fields+ --+ -- * For hs-boot files, include the value signatures+ -- Again, they have no value declarations+ --+ (tc_envs, tc_bndrs) <- getLocalNonValBinders local_fix_env group ;+++ setEnvs tc_envs $ do {++ failIfErrsM ; -- No point in continuing if (say) we have duplicate declarations++ -- (D1) Bring pattern synonyms into scope.+ -- Need to do this before (D2) because rnTopBindsLHS+ -- looks up those pattern synonyms (Trac #9889)++ extendPatSynEnv val_decls local_fix_env $ \pat_syn_bndrs -> do {++ -- (D2) Rename the left-hand sides of the value bindings.+ -- This depends on everything from (B) being in scope,+ -- and on (C) for resolving record wild cards.+ -- It uses the fixity env from (A) to bind fixities for view patterns.+ new_lhs <- rnTopBindsLHS local_fix_env val_decls ;++ -- Bind the LHSes (and their fixities) in the global rdr environment+ let { id_bndrs = collectHsIdBinders new_lhs } ; -- Excludes pattern-synonym binders+ -- They are already in scope+ traceRn "rnSrcDecls" (ppr id_bndrs) ;+ tc_envs <- extendGlobalRdrEnvRn (map avail id_bndrs) local_fix_env ;+ traceRn "D2" (ppr (tcg_rdr_env (fst tc_envs)));+ setEnvs tc_envs $ do {++ -- Now everything is in scope, as the remaining renaming assumes.++ -- (E) Rename type and class decls+ -- (note that value LHSes need to be in scope for default methods)+ --+ -- You might think that we could build proper def/use information+ -- for type and class declarations, but they can be involved+ -- in mutual recursion across modules, and we only do the SCC+ -- analysis for them in the type checker.+ -- So we content ourselves with gathering uses only; that+ -- means we'll only report a declaration as unused if it isn't+ -- mentioned at all. Ah well.+ traceRn "Start rnTyClDecls" (ppr tycl_decls) ;+ (rn_tycl_decls, src_fvs1) <- rnTyClDecls tycl_decls ;++ -- (F) Rename Value declarations right-hand sides+ traceRn "Start rnmono" empty ;+ let { val_bndr_set = mkNameSet id_bndrs `unionNameSet` mkNameSet pat_syn_bndrs } ;+ is_boot <- tcIsHsBootOrSig ;+ (rn_val_decls, bind_dus) <- if is_boot+ -- For an hs-boot, use tc_bndrs (which collects how we're renamed+ -- signatures), since val_bndr_set is empty (there are no x = ...+ -- bindings in an hs-boot.)+ then rnTopBindsBoot tc_bndrs new_lhs+ else rnValBindsRHS (TopSigCtxt val_bndr_set) new_lhs ;+ traceRn "finish rnmono" (ppr rn_val_decls) ;++ -- (G) Rename Fixity and deprecations++ -- Rename fixity declarations and error if we try to+ -- fix something from another module (duplicates were checked in (A))+ let { all_bndrs = tc_bndrs `unionNameSet` val_bndr_set } ;+ rn_fix_decls <- rnSrcFixityDecls all_bndrs fix_decls ;++ -- Rename deprec decls;+ -- check for duplicates and ensure that deprecated things are defined locally+ -- at the moment, we don't keep these around past renaming+ rn_warns <- rnSrcWarnDecls all_bndrs warn_decls ;++ -- (H) Rename Everything else++ (rn_rule_decls, src_fvs2) <- setXOptM LangExt.ScopedTypeVariables $+ rnList rnHsRuleDecls rule_decls ;+ -- Inside RULES, scoped type variables are on+ (rn_vect_decls, src_fvs3) <- rnList rnHsVectDecl vect_decls ;+ (rn_foreign_decls, src_fvs4) <- rnList rnHsForeignDecl foreign_decls ;+ (rn_ann_decls, src_fvs5) <- rnList rnAnnDecl ann_decls ;+ (rn_default_decls, src_fvs6) <- rnList rnDefaultDecl default_decls ;+ (rn_deriv_decls, src_fvs7) <- rnList rnSrcDerivDecl deriv_decls ;+ (rn_splice_decls, src_fvs8) <- rnList rnSpliceDecl splice_decls ;+ -- Haddock docs; no free vars+ rn_docs <- mapM (wrapLocM rnDocDecl) docs ;++ last_tcg_env <- getGblEnv ;+ -- (I) Compute the results and return+ let {rn_group = HsGroup { hs_valds = rn_val_decls,+ hs_splcds = rn_splice_decls,+ hs_tyclds = rn_tycl_decls,+ hs_derivds = rn_deriv_decls,+ hs_fixds = rn_fix_decls,+ hs_warnds = [], -- warns are returned in the tcg_env+ -- (see below) not in the HsGroup+ hs_fords = rn_foreign_decls,+ hs_annds = rn_ann_decls,+ hs_defds = rn_default_decls,+ hs_ruleds = rn_rule_decls,+ hs_vects = rn_vect_decls,+ hs_docs = rn_docs } ;++ tcf_bndrs = hsTyClForeignBinders rn_tycl_decls rn_foreign_decls ;+ other_def = (Just (mkNameSet tcf_bndrs), emptyNameSet) ;+ other_fvs = plusFVs [src_fvs1, src_fvs2, src_fvs3, src_fvs4, src_fvs5,+ src_fvs6, src_fvs7, src_fvs8] ;+ -- It is tiresome to gather the binders from type and class decls++ src_dus = [other_def] `plusDU` bind_dus `plusDU` usesOnly other_fvs ;+ -- Instance decls may have occurrences of things bound in bind_dus+ -- so we must put other_fvs last++ final_tcg_env = let tcg_env' = (last_tcg_env `addTcgDUs` src_dus)+ in -- we return the deprecs in the env, not in the HsGroup above+ tcg_env' { tcg_warns = tcg_warns tcg_env' `plusWarns` rn_warns };+ } ;+ traceRn "last" (ppr (tcg_rdr_env final_tcg_env)) ;+ traceRn "finish rnSrc" (ppr rn_group) ;+ traceRn "finish Dus" (ppr src_dus ) ;+ return (final_tcg_env, rn_group)+ }}}}++addTcgDUs :: TcGblEnv -> DefUses -> TcGblEnv+-- This function could be defined lower down in the module hierarchy,+-- but there doesn't seem anywhere very logical to put it.+addTcgDUs tcg_env dus = tcg_env { tcg_dus = tcg_dus tcg_env `plusDU` dus }++rnList :: (a -> RnM (b, FreeVars)) -> [Located a] -> RnM ([Located b], FreeVars)+rnList f xs = mapFvRn (wrapLocFstM f) xs++{-+*********************************************************+* *+ HsDoc stuff+* *+*********************************************************+-}++rnDocDecl :: DocDecl -> RnM DocDecl+rnDocDecl (DocCommentNext doc) = do+ rn_doc <- rnHsDoc doc+ return (DocCommentNext rn_doc)+rnDocDecl (DocCommentPrev doc) = do+ rn_doc <- rnHsDoc doc+ return (DocCommentPrev rn_doc)+rnDocDecl (DocCommentNamed str doc) = do+ rn_doc <- rnHsDoc doc+ return (DocCommentNamed str rn_doc)+rnDocDecl (DocGroup lev doc) = do+ rn_doc <- rnHsDoc doc+ return (DocGroup lev rn_doc)++{-+*********************************************************+* *+ Source-code fixity declarations+* *+*********************************************************+-}++rnSrcFixityDecls :: NameSet -> [LFixitySig RdrName] -> RnM [LFixitySig Name]+-- Rename the fixity decls, so we can put+-- the renamed decls in the renamed syntax tree+-- Errors if the thing being fixed is not defined locally.+--+-- The returned FixitySigs are not actually used for anything,+-- except perhaps the GHCi API+rnSrcFixityDecls bndr_set fix_decls+ = do fix_decls <- mapM rn_decl fix_decls+ return (concat fix_decls)+ where+ sig_ctxt = TopSigCtxt bndr_set++ rn_decl :: LFixitySig RdrName -> RnM [LFixitySig Name]+ -- GHC extension: look up both the tycon and data con+ -- for con-like things; hence returning a list+ -- If neither are in scope, report an error; otherwise+ -- return a fixity sig for each (slightly odd)+ rn_decl (L loc (FixitySig fnames fixity))+ = do names <- mapM lookup_one fnames+ return [ L loc (FixitySig name fixity)+ | name <- names ]++ lookup_one :: Located RdrName -> RnM [Located Name]+ lookup_one (L name_loc rdr_name)+ = setSrcSpan name_loc $+ -- this lookup will fail if the definition isn't local+ do names <- lookupLocalTcNames sig_ctxt what rdr_name+ return [ L name_loc name | (_, name) <- names ]+ what = text "fixity signature"++{-+*********************************************************+* *+ Source-code deprecations declarations+* *+*********************************************************++Check that the deprecated names are defined, are defined locally, and+that there are no duplicate deprecations.++It's only imported deprecations, dealt with in RnIfaces, that we+gather them together.+-}++-- checks that the deprecations are defined locally, and that there are no duplicates+rnSrcWarnDecls :: NameSet -> [LWarnDecls RdrName] -> RnM Warnings+rnSrcWarnDecls _ []+ = return NoWarnings++rnSrcWarnDecls bndr_set decls'+ = do { -- check for duplicates+ ; mapM_ (\ dups -> let (L loc rdr:lrdr':_) = dups+ in addErrAt loc (dupWarnDecl lrdr' rdr))+ warn_rdr_dups+ ; pairs_s <- mapM (addLocM rn_deprec) decls+ ; return (WarnSome ((concat pairs_s))) }+ where+ decls = concatMap (\(L _ d) -> wd_warnings d) decls'++ sig_ctxt = TopSigCtxt bndr_set++ rn_deprec (Warning rdr_names txt)+ -- ensures that the names are defined locally+ = do { names <- concatMapM (lookupLocalTcNames sig_ctxt what . unLoc)+ rdr_names+ ; return [(rdrNameOcc rdr, txt) | (rdr, _) <- names] }++ what = text "deprecation"++ warn_rdr_dups = findDupRdrNames $ concatMap (\(L _ (Warning ns _)) -> ns)+ decls++findDupRdrNames :: [Located RdrName] -> [[Located RdrName]]+findDupRdrNames = findDupsEq (\ x -> \ y -> rdrNameOcc (unLoc x) == rdrNameOcc (unLoc y))++-- look for duplicates among the OccNames;+-- we check that the names are defined above+-- invt: the lists returned by findDupsEq always have at least two elements++dupWarnDecl :: Located RdrName -> RdrName -> SDoc+-- Located RdrName -> DeprecDecl RdrName -> SDoc+dupWarnDecl (L loc _) rdr_name+ = vcat [text "Multiple warning declarations for" <+> quotes (ppr rdr_name),+ text "also at " <+> ppr loc]++{-+*********************************************************+* *+\subsection{Annotation declarations}+* *+*********************************************************+-}++rnAnnDecl :: AnnDecl RdrName -> RnM (AnnDecl Name, FreeVars)+rnAnnDecl ann@(HsAnnotation s provenance expr)+ = addErrCtxt (annCtxt ann) $+ do { (provenance', provenance_fvs) <- rnAnnProvenance provenance+ ; (expr', expr_fvs) <- setStage (Splice Untyped) $+ rnLExpr expr+ ; return (HsAnnotation s provenance' expr',+ provenance_fvs `plusFV` expr_fvs) }++rnAnnProvenance :: AnnProvenance RdrName -> RnM (AnnProvenance Name, FreeVars)+rnAnnProvenance provenance = do+ provenance' <- traverse lookupTopBndrRn provenance+ return (provenance', maybe emptyFVs unitFV (annProvenanceName_maybe provenance'))++{-+*********************************************************+* *+\subsection{Default declarations}+* *+*********************************************************+-}++rnDefaultDecl :: DefaultDecl RdrName -> RnM (DefaultDecl Name, FreeVars)+rnDefaultDecl (DefaultDecl tys)+ = do { (tys', fvs) <- rnLHsTypes doc_str tys+ ; return (DefaultDecl tys', fvs) }+ where+ doc_str = DefaultDeclCtx++{-+*********************************************************+* *+\subsection{Foreign declarations}+* *+*********************************************************+-}++rnHsForeignDecl :: ForeignDecl RdrName -> RnM (ForeignDecl Name, FreeVars)+rnHsForeignDecl (ForeignImport { fd_name = name, fd_sig_ty = ty, fd_fi = spec })+ = do { topEnv :: HscEnv <- getTopEnv+ ; name' <- lookupLocatedTopBndrRn name+ ; (ty', fvs) <- rnHsSigType (ForeignDeclCtx name) ty++ -- Mark any PackageTarget style imports as coming from the current package+ ; let unitId = thisPackage $ hsc_dflags topEnv+ spec' = patchForeignImport unitId spec++ ; return (ForeignImport { fd_name = name', fd_sig_ty = ty'+ , fd_co = noForeignImportCoercionYet+ , fd_fi = spec' }, fvs) }++rnHsForeignDecl (ForeignExport { fd_name = name, fd_sig_ty = ty, fd_fe = spec })+ = do { name' <- lookupLocatedOccRn name+ ; (ty', fvs) <- rnHsSigType (ForeignDeclCtx name) ty+ ; return (ForeignExport { fd_name = name', fd_sig_ty = ty'+ , fd_co = noForeignExportCoercionYet+ , fd_fe = spec }+ , fvs `addOneFV` unLoc name') }+ -- NB: a foreign export is an *occurrence site* for name, so+ -- we add it to the free-variable list. It might, for example,+ -- be imported from another module++-- | For Windows DLLs we need to know what packages imported symbols are from+-- to generate correct calls. Imported symbols are tagged with the current+-- package, so if they get inlined across a package boundry we'll still+-- know where they're from.+--+patchForeignImport :: UnitId -> ForeignImport -> ForeignImport+patchForeignImport unitId (CImport cconv safety fs spec src)+ = CImport cconv safety fs (patchCImportSpec unitId spec) src++patchCImportSpec :: UnitId -> CImportSpec -> CImportSpec+patchCImportSpec unitId spec+ = case spec of+ CFunction callTarget -> CFunction $ patchCCallTarget unitId callTarget+ _ -> spec++patchCCallTarget :: UnitId -> CCallTarget -> CCallTarget+patchCCallTarget unitId callTarget =+ case callTarget of+ StaticTarget src label Nothing isFun+ -> StaticTarget src label (Just unitId) isFun+ _ -> callTarget++{-+*********************************************************+* *+\subsection{Instance declarations}+* *+*********************************************************+-}++rnSrcInstDecl :: InstDecl RdrName -> RnM (InstDecl Name, FreeVars)+rnSrcInstDecl (TyFamInstD { tfid_inst = tfi })+ = do { (tfi', fvs) <- rnTyFamInstDecl Nothing tfi+ ; return (TyFamInstD { tfid_inst = tfi' }, fvs) }++rnSrcInstDecl (DataFamInstD { dfid_inst = dfi })+ = do { (dfi', fvs) <- rnDataFamInstDecl Nothing dfi+ ; return (DataFamInstD { dfid_inst = dfi' }, fvs) }++rnSrcInstDecl (ClsInstD { cid_inst = cid })+ = do { (cid', fvs) <- rnClsInstDecl cid+ ; return (ClsInstD { cid_inst = cid' }, fvs) }++-- | Warn about non-canonical typeclass instance declarations+--+-- A "non-canonical" instance definition can occur for instances of a+-- class which redundantly defines an operation its superclass+-- provides as well (c.f. `return`/`pure`). In such cases, a canonical+-- instance is one where the subclass inherits its method+-- implementation from its superclass instance (usually the subclass+-- has a default method implementation to that effect). Consequently,+-- a non-canonical instance occurs when this is not the case.+--+-- See also descriptions of 'checkCanonicalMonadInstances' and+-- 'checkCanonicalMonoidInstances'+checkCanonicalInstances :: Name -> LHsSigType Name -> LHsBinds Name -> RnM ()+checkCanonicalInstances cls poly_ty mbinds = do+ whenWOptM Opt_WarnNonCanonicalMonadInstances+ checkCanonicalMonadInstances++ whenWOptM Opt_WarnNonCanonicalMonadFailInstances+ checkCanonicalMonadFailInstances++ whenWOptM Opt_WarnNonCanonicalMonoidInstances+ checkCanonicalMonoidInstances++ where+ -- | Warn about unsound/non-canonical 'Applicative'/'Monad' instance+ -- declarations. Specifically, the following conditions are verified:+ --+ -- In 'Monad' instances declarations:+ --+ -- * If 'return' is overridden it must be canonical (i.e. @return = pure@)+ -- * If '(>>)' is overridden it must be canonical (i.e. @(>>) = (*>)@)+ --+ -- In 'Applicative' instance declarations:+ --+ -- * Warn if 'pure' is defined backwards (i.e. @pure = return@).+ -- * Warn if '(*>)' is defined backwards (i.e. @(*>) = (>>)@).+ --+ checkCanonicalMonadInstances+ | cls == applicativeClassName = do+ forM_ (bagToList mbinds) $ \(L loc mbind) -> setSrcSpan loc $ do+ case mbind of+ FunBind { fun_id = L _ name, fun_matches = mg }+ | name == pureAName, isAliasMG mg == Just returnMName+ -> addWarnNonCanonicalMethod1+ Opt_WarnNonCanonicalMonadInstances "pure" "return"++ | name == thenAName, isAliasMG mg == Just thenMName+ -> addWarnNonCanonicalMethod1+ Opt_WarnNonCanonicalMonadInstances "(*>)" "(>>)"++ _ -> return ()++ | cls == monadClassName = do+ forM_ (bagToList mbinds) $ \(L loc mbind) -> setSrcSpan loc $ do+ case mbind of+ FunBind { fun_id = L _ name, fun_matches = mg }+ | name == returnMName, isAliasMG mg /= Just pureAName+ -> addWarnNonCanonicalMethod2+ Opt_WarnNonCanonicalMonadInstances "return" "pure"++ | name == thenMName, isAliasMG mg /= Just thenAName+ -> addWarnNonCanonicalMethod2+ Opt_WarnNonCanonicalMonadInstances "(>>)" "(*>)"++ _ -> return ()++ | otherwise = return ()++ -- | Warn about unsound/non-canonical 'Monad'/'MonadFail' instance+ -- declarations. Specifically, the following conditions are verified:+ --+ -- In 'Monad' instances declarations:+ --+ -- * If 'fail' is overridden it must be canonical+ -- (i.e. @fail = Control.Monad.Fail.fail@)+ --+ -- In 'MonadFail' instance declarations:+ --+ -- * Warn if 'fail' is defined backwards+ -- (i.e. @fail = Control.Monad.fail@).+ --+ checkCanonicalMonadFailInstances+ | cls == monadFailClassName = do+ forM_ (bagToList mbinds) $ \(L loc mbind) -> setSrcSpan loc $ do+ case mbind of+ FunBind { fun_id = L _ name, fun_matches = mg }+ | name == failMName, isAliasMG mg == Just failMName_preMFP+ -> addWarnNonCanonicalMethod1+ Opt_WarnNonCanonicalMonadFailInstances "fail"+ "Control.Monad.fail"++ _ -> return ()++ | cls == monadClassName = do+ forM_ (bagToList mbinds) $ \(L loc mbind) -> setSrcSpan loc $ do+ case mbind of+ FunBind { fun_id = L _ name, fun_matches = mg }+ | name == failMName_preMFP, isAliasMG mg /= Just failMName+ -> addWarnNonCanonicalMethod2+ Opt_WarnNonCanonicalMonadFailInstances "fail"+ "Control.Monad.Fail.fail"+ _ -> return ()++ | otherwise = return ()++ -- | Check whether Monoid(mappend) is defined in terms of+ -- Semigroup((<>)) (and not the other way round). Specifically,+ -- the following conditions are verified:+ --+ -- In 'Monoid' instances declarations:+ --+ -- * If 'mappend' is overridden it must be canonical+ -- (i.e. @mappend = (<>)@)+ --+ -- In 'Semigroup' instance declarations:+ --+ -- * Warn if '(<>)' is defined backwards (i.e. @(<>) = mappend@).+ --+ checkCanonicalMonoidInstances+ | cls == semigroupClassName = do+ forM_ (bagToList mbinds) $ \(L loc mbind) -> setSrcSpan loc $ do+ case mbind of+ FunBind { fun_id = L _ name, fun_matches = mg }+ | name == sappendName, isAliasMG mg == Just mappendName+ -> addWarnNonCanonicalMethod1+ Opt_WarnNonCanonicalMonoidInstances "(<>)" "mappend"++ _ -> return ()++ | cls == monoidClassName = do+ forM_ (bagToList mbinds) $ \(L loc mbind) -> setSrcSpan loc $ do+ case mbind of+ FunBind { fun_id = L _ name, fun_matches = mg }+ | name == mappendName, isAliasMG mg /= Just sappendName+ -> addWarnNonCanonicalMethod2NoDefault+ Opt_WarnNonCanonicalMonoidInstances "mappend" "(<>)"++ _ -> return ()++ | otherwise = return ()++ -- | test whether MatchGroup represents a trivial \"lhsName = rhsName\"+ -- binding, and return @Just rhsName@ if this is the case+ isAliasMG :: MatchGroup Name (LHsExpr Name) -> Maybe Name+ isAliasMG MG {mg_alts = L _ [L _ (Match { m_pats = [], m_grhss = grhss })]}+ | GRHSs [L _ (GRHS [] body)] lbinds <- grhss+ , L _ EmptyLocalBinds <- lbinds+ , L _ (HsVar (L _ rhsName)) <- body = Just rhsName+ isAliasMG _ = Nothing++ -- got "lhs = rhs" but expected something different+ addWarnNonCanonicalMethod1 flag lhs rhs = do+ addWarn (Reason flag) $ vcat+ [ text "Noncanonical" <+>+ quotes (text (lhs ++ " = " ++ rhs)) <+>+ text "definition detected"+ , instDeclCtxt1 poly_ty+ , text "Move definition from" <+>+ quotes (text rhs) <+>+ text "to" <+> quotes (text lhs)+ ]++ -- expected "lhs = rhs" but got something else+ addWarnNonCanonicalMethod2 flag lhs rhs = do+ addWarn (Reason flag) $ vcat+ [ text "Noncanonical" <+>+ quotes (text lhs) <+>+ text "definition detected"+ , instDeclCtxt1 poly_ty+ , text "Either remove definition for" <+>+ quotes (text lhs) <+> text "or define as" <+>+ quotes (text (lhs ++ " = " ++ rhs))+ ]++ -- like above, but method has no default impl+ addWarnNonCanonicalMethod2NoDefault flag lhs rhs = do+ addWarn (Reason flag) $ vcat+ [ text "Noncanonical" <+>+ quotes (text lhs) <+>+ text "definition detected"+ , instDeclCtxt1 poly_ty+ , text "Define as" <+>+ quotes (text (lhs ++ " = " ++ rhs))+ ]++ -- stolen from TcInstDcls+ instDeclCtxt1 :: LHsSigType Name -> SDoc+ instDeclCtxt1 hs_inst_ty+ = inst_decl_ctxt (ppr (getLHsInstDeclHead hs_inst_ty))++ inst_decl_ctxt :: SDoc -> SDoc+ inst_decl_ctxt doc = hang (text "in the instance declaration for")+ 2 (quotes doc <> text ".")+++rnClsInstDecl :: ClsInstDecl RdrName -> RnM (ClsInstDecl Name, FreeVars)+rnClsInstDecl (ClsInstDecl { cid_poly_ty = inst_ty, cid_binds = mbinds+ , cid_sigs = uprags, cid_tyfam_insts = ats+ , cid_overlap_mode = oflag+ , cid_datafam_insts = adts })+ = do { (inst_ty', inst_fvs) <- rnLHsInstType (text "an instance declaration") inst_ty+ ; let (ktv_names, _, head_ty') = splitLHsInstDeclTy inst_ty'+ ; let cls = case hsTyGetAppHead_maybe head_ty' of+ Nothing -> mkUnboundName (mkTcOccFS (fsLit "<class>"))+ Just (L _ cls, _) -> cls+ -- rnLHsInstType has added an error message+ -- if hsTyGetAppHead_maybe fails++ -- Rename the bindings+ -- The typechecker (not the renamer) checks that all+ -- the bindings are for the right class+ -- (Slightly strangely) when scoped type variables are on, the+ -- forall-d tyvars scope over the method bindings too+ ; (mbinds', uprags', meth_fvs) <- rnMethodBinds False cls ktv_names mbinds uprags++ ; checkCanonicalInstances cls inst_ty' mbinds'++ -- Rename the associated types, and type signatures+ -- Both need to have the instance type variables in scope+ ; traceRn "rnSrcInstDecl" (ppr inst_ty' $$ ppr ktv_names)+ ; ((ats', adts'), more_fvs)+ <- extendTyVarEnvFVRn ktv_names $+ do { (ats', at_fvs) <- rnATInstDecls rnTyFamInstDecl cls ktv_names ats+ ; (adts', adt_fvs) <- rnATInstDecls rnDataFamInstDecl cls ktv_names adts+ ; return ( (ats', adts'), at_fvs `plusFV` adt_fvs) }++ ; let all_fvs = meth_fvs `plusFV` more_fvs+ `plusFV` inst_fvs+ ; return (ClsInstDecl { cid_poly_ty = inst_ty', cid_binds = mbinds'+ , cid_sigs = uprags', cid_tyfam_insts = ats'+ , cid_overlap_mode = oflag+ , cid_datafam_insts = adts' },+ all_fvs) }+ -- We return the renamed associated data type declarations so+ -- that they can be entered into the list of type declarations+ -- for the binding group, but we also keep a copy in the instance.+ -- The latter is needed for well-formedness checks in the type+ -- checker (eg, to ensure that all ATs of the instance actually+ -- receive a declaration).+ -- NB: Even the copies in the instance declaration carry copies of+ -- the instance context after renaming. This is a bit+ -- strange, but should not matter (and it would be more work+ -- to remove the context).++rnFamInstDecl :: HsDocContext+ -> Maybe (Name, [Name]) -- Nothing => not associated+ -- Just (cls,tvs) => associated,+ -- and gives class and tyvars of the+ -- parent instance delc+ -> Located RdrName+ -> HsTyPats RdrName+ -> rhs+ -> (HsDocContext -> rhs -> RnM (rhs', FreeVars))+ -> RnM (Located Name, HsTyPats Name, rhs', FreeVars)+rnFamInstDecl doc mb_cls tycon (HsIB { hsib_body = pats }) payload rnPayload+ = do { tycon' <- lookupFamInstName (fmap fst mb_cls) tycon+ ; let loc = case pats of+ [] -> pprPanic "rnFamInstDecl" (ppr tycon)+ (L loc _ : []) -> loc+ (L loc _ : ps) -> combineSrcSpans loc (getLoc (last ps))++ ; pat_kity_vars_with_dups <- extractHsTysRdrTyVarsDups pats+ -- Use the "...Dups" form because it's needed+ -- below to report unsed binder on the LHS+ ; var_names <- mapM (newTyVarNameRn mb_cls . L loc . unLoc) $+ freeKiTyVarsAllVars $+ rmDupsInRdrTyVars pat_kity_vars_with_dups++ -- All the free vars of the family patterns+ -- with a sensible binding location+ ; ((pats', payload'), fvs)+ <- bindLocalNamesFV var_names $+ do { (pats', pat_fvs) <- rnLHsTypes (FamPatCtx tycon) pats+ ; (payload', rhs_fvs) <- rnPayload doc payload++ -- Report unused binders on the LHS+ -- See Note [Unused type variables in family instances]+ ; let groups :: [[Located RdrName]]+ groups = equivClasses cmpLocated $+ freeKiTyVarsAllVars pat_kity_vars_with_dups+ ; tv_nms_dups <- mapM (lookupOccRn . unLoc) $+ [ tv | (tv:_:_) <- groups ]+ -- Add to the used variables+ -- a) any variables that appear *more than once* on the LHS+ -- e.g. F a Int a = Bool+ -- b) for associated instances, the variables+ -- of the instance decl. See+ -- Note [Unused type variables in family instances]+ ; let tv_nms_used = extendNameSetList rhs_fvs $+ inst_tvs ++ tv_nms_dups+ inst_tvs = case mb_cls of+ Nothing -> []+ Just (_, inst_tvs) -> inst_tvs+ ; warnUnusedTypePatterns var_names tv_nms_used++ -- See Note [Renaming associated types]+ ; let bad_tvs = case mb_cls of+ Nothing -> []+ Just (_,cls_tkvs) -> filter is_bad cls_tkvs+ var_name_set = mkNameSet var_names++ is_bad cls_tkv = cls_tkv `elemNameSet` rhs_fvs+ && not (cls_tkv `elemNameSet` var_name_set)+ ; unless (null bad_tvs) (badAssocRhs bad_tvs)++ ; return ((pats', payload'), rhs_fvs `plusFV` pat_fvs) }++ ; let anon_wcs = concatMap collectAnonWildCards pats'+ all_ibs = anon_wcs ++ var_names+ -- all_ibs: include anonymous wildcards in the implicit+ -- binders In a type pattern they behave just like any+ -- other type variable except for being anoymous. See+ -- Note [Wildcards in family instances]+ all_fvs = fvs `addOneFV` unLoc tycon'++ ; return (tycon',+ HsIB { hsib_body = pats'+ , hsib_vars = all_ibs+ , hsib_closed = True },+ payload',+ all_fvs) }+ -- type instance => use, hence addOneFV++rnTyFamInstDecl :: Maybe (Name, [Name])+ -> TyFamInstDecl RdrName+ -> RnM (TyFamInstDecl Name, FreeVars)+rnTyFamInstDecl mb_cls (TyFamInstDecl { tfid_eqn = L loc eqn })+ = do { (eqn', fvs) <- rnTyFamInstEqn mb_cls eqn+ ; return (TyFamInstDecl { tfid_eqn = L loc eqn'+ , tfid_fvs = fvs }, fvs) }++rnTyFamInstEqn :: Maybe (Name, [Name])+ -> TyFamInstEqn RdrName+ -> RnM (TyFamInstEqn Name, FreeVars)+rnTyFamInstEqn mb_cls (TyFamEqn { tfe_tycon = tycon+ , tfe_pats = pats+ , tfe_fixity = fixity+ , tfe_rhs = rhs })+ = do { (tycon', pats', rhs', fvs) <-+ rnFamInstDecl (TySynCtx tycon) mb_cls tycon pats rhs rnTySyn+ ; return (TyFamEqn { tfe_tycon = tycon'+ , tfe_pats = pats'+ , tfe_fixity = fixity+ , tfe_rhs = rhs' }, fvs) }++rnTyFamDefltEqn :: Name+ -> TyFamDefltEqn RdrName+ -> RnM (TyFamDefltEqn Name, FreeVars)+rnTyFamDefltEqn cls (TyFamEqn { tfe_tycon = tycon+ , tfe_pats = tyvars+ , tfe_fixity = fixity+ , tfe_rhs = rhs })+ = bindHsQTyVars ctx Nothing (Just cls) [] tyvars $ \ tyvars' _ ->+ do { tycon' <- lookupFamInstName (Just cls) tycon+ ; (rhs', fvs) <- rnLHsType ctx rhs+ ; return (TyFamEqn { tfe_tycon = tycon'+ , tfe_pats = tyvars'+ , tfe_fixity = fixity+ , tfe_rhs = rhs' }, fvs) }+ where+ ctx = TyFamilyCtx tycon++rnDataFamInstDecl :: Maybe (Name, [Name])+ -> DataFamInstDecl RdrName+ -> RnM (DataFamInstDecl Name, FreeVars)+rnDataFamInstDecl mb_cls (DataFamInstDecl { dfid_tycon = tycon+ , dfid_pats = pats+ , dfid_fixity = fixity+ , dfid_defn = defn })+ = do { (tycon', pats', (defn', _), fvs) <-+ rnFamInstDecl (TyDataCtx tycon) mb_cls tycon pats defn rnDataDefn+ ; return (DataFamInstDecl { dfid_tycon = tycon'+ , dfid_pats = pats'+ , dfid_fixity = fixity+ , dfid_defn = defn'+ , dfid_fvs = fvs }, fvs) }++-- Renaming of the associated types in instances.++-- Rename associated type family decl in class+rnATDecls :: Name -- Class+ -> [LFamilyDecl RdrName]+ -> RnM ([LFamilyDecl Name], FreeVars)+rnATDecls cls at_decls+ = rnList (rnFamDecl (Just cls)) at_decls++rnATInstDecls :: (Maybe (Name, [Name]) -> -- The function that renames+ decl RdrName -> -- an instance. rnTyFamInstDecl+ RnM (decl Name, FreeVars)) -- or rnDataFamInstDecl+ -> Name -- Class+ -> [Name]+ -> [Located (decl RdrName)]+ -> RnM ([Located (decl Name)], FreeVars)+-- Used for data and type family defaults in a class decl+-- and the family instance declarations in an instance+--+-- NB: We allow duplicate associated-type decls;+-- See Note [Associated type instances] in TcInstDcls+rnATInstDecls rnFun cls tv_ns at_insts+ = rnList (rnFun (Just (cls, tv_ns))) at_insts+ -- See Note [Renaming associated types]++{- Note [Wildcards in family instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Wild cards can be used in type/data family instance declarations to indicate+that the name of a type variable doesn't matter. Each wild card will be+replaced with a new unique type variable. For instance:++ type family F a b :: *+ type instance F Int _ = Int++is the same as++ type family F a b :: *+ type instance F Int b = Int++This is implemented as follows: during renaming anonymous wild cards+'_' are given freshly generated names. These names are collected after+renaming (rnFamInstDecl) and used to make new type variables during+type checking (tc_fam_ty_pats). One should not confuse these wild+cards with the ones from partial type signatures. The latter generate+fresh meta-variables whereas the former generate fresh skolems.++Note [Unused type variables in family instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When the flag -fwarn-unused-type-patterns is on, the compiler reports+warnings about unused type variables in type-family instances. A+tpye variable is considered used (i.e. cannot be turned into a wildcard)+when++ * it occurs on the RHS of the family instance+ e.g. type instance F a b = a -- a is used on the RHS++ * it occurs multiple times in the patterns on the LHS+ e.g. type instance F a a = Int -- a appears more than once on LHS++ * it is one of the instance-decl variables, for associated types+ e.g. instance C (a,b) where+ type T (a,b) = a+ Here the type pattern in the type instance must be the same as that+ for the class instance, so+ type T (a,_) = a+ would be rejected. So we should not complain about an unused variable b++As usual, the warnings are not reported for for type variables with names+beginning with an underscore.++Extra-constraints wild cards are not supported in type/data family+instance declarations.++Relevant tickets: #3699, #10586, #10982 and #11451.++Note [Renaming associated types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Check that the RHS of the decl mentions only type variables+bound on the LHS. For example, this is not ok+ class C a b where+ type F a x :: *+ instance C (p,q) r where+ type F (p,q) x = (x, r) -- BAD: mentions 'r'+c.f. Trac #5515++The same thing applies to kind variables, of course (Trac #7938, #9574):+ class Funct f where+ type Codomain f :: *+ instance Funct ('KProxy :: KProxy o) where+ type Codomain 'KProxy = NatTr (Proxy :: o -> *)+Here 'o' is mentioned on the RHS of the Codomain function, but+not on the LHS.++All this applies only for *instance* declarations. In *class*+declarations there is no RHS to worry about, and the class variables+can all be in scope (Trac #5862):+ class Category (x :: k -> k -> *) where+ type Ob x :: k -> Constraint+ id :: Ob x a => x a a+ (.) :: (Ob x a, Ob x b, Ob x c) => x b c -> x a b -> x a c+Here 'k' is in scope in the kind signature, just like 'x'.+-}+++{-+*********************************************************+* *+\subsection{Stand-alone deriving declarations}+* *+*********************************************************+-}++rnSrcDerivDecl :: DerivDecl RdrName -> RnM (DerivDecl Name, FreeVars)+rnSrcDerivDecl (DerivDecl ty deriv_strat overlap)+ = do { standalone_deriv_ok <- xoptM LangExt.StandaloneDeriving+ ; deriv_strats_ok <- xoptM LangExt.DerivingStrategies+ ; unless standalone_deriv_ok (addErr standaloneDerivErr)+ ; failIfTc (isJust deriv_strat && not deriv_strats_ok) $+ illegalDerivStrategyErr $ fmap unLoc deriv_strat+ ; (ty', fvs) <- rnLHsInstType (text "In a deriving declaration") ty+ ; return (DerivDecl ty' deriv_strat overlap, fvs) }++standaloneDerivErr :: SDoc+standaloneDerivErr+ = hang (text "Illegal standalone deriving declaration")+ 2 (text "Use StandaloneDeriving to enable this extension")++{-+*********************************************************+* *+\subsection{Rules}+* *+*********************************************************+-}++rnHsRuleDecls :: RuleDecls RdrName -> RnM (RuleDecls Name, FreeVars)+rnHsRuleDecls (HsRules src rules)+ = do { (rn_rules,fvs) <- rnList rnHsRuleDecl rules+ ; return (HsRules src rn_rules,fvs) }++rnHsRuleDecl :: RuleDecl RdrName -> RnM (RuleDecl Name, FreeVars)+rnHsRuleDecl (HsRule rule_name act vars lhs _fv_lhs rhs _fv_rhs)+ = do { let rdr_names_w_loc = map get_var vars+ ; checkDupRdrNames rdr_names_w_loc+ ; checkShadowedRdrNames rdr_names_w_loc+ ; names <- newLocalBndrsRn rdr_names_w_loc+ ; bindHsRuleVars (snd $ unLoc rule_name) vars names $ \ vars' ->+ do { (lhs', fv_lhs') <- rnLExpr lhs+ ; (rhs', fv_rhs') <- rnLExpr rhs+ ; checkValidRule (snd $ unLoc rule_name) names lhs' fv_lhs'+ ; return (HsRule rule_name act vars' lhs' fv_lhs' rhs' fv_rhs',+ fv_lhs' `plusFV` fv_rhs') } }+ where+ get_var (L _ (RuleBndrSig v _)) = v+ get_var (L _ (RuleBndr v)) = v++bindHsRuleVars :: RuleName -> [LRuleBndr RdrName] -> [Name]+ -> ([LRuleBndr Name] -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+bindHsRuleVars rule_name vars names thing_inside+ = go vars names $ \ vars' ->+ bindLocalNamesFV names (thing_inside vars')+ where+ doc = RuleCtx rule_name++ go (L l (RuleBndr (L loc _)) : vars) (n : ns) thing_inside+ = go vars ns $ \ vars' ->+ thing_inside (L l (RuleBndr (L loc n)) : vars')++ go (L l (RuleBndrSig (L loc _) bsig) : vars) (n : ns) thing_inside+ = rnHsSigWcTypeScoped doc bsig $ \ bsig' ->+ go vars ns $ \ vars' ->+ thing_inside (L l (RuleBndrSig (L loc n) bsig') : vars')++ go [] [] thing_inside = thing_inside []+ go vars names _ = pprPanic "bindRuleVars" (ppr vars $$ ppr names)++{-+Note [Rule LHS validity checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Check the shape of a transformation rule LHS. Currently we only allow+LHSs of the form @(f e1 .. en)@, where @f@ is not one of the+@forall@'d variables.++We used restrict the form of the 'ei' to prevent you writing rules+with LHSs with a complicated desugaring (and hence unlikely to match);+(e.g. a case expression is not allowed: too elaborate.)++But there are legitimate non-trivial args ei, like sections and+lambdas. So it seems simmpler not to check at all, and that is why+check_e is commented out.+-}++checkValidRule :: FastString -> [Name] -> LHsExpr Name -> NameSet -> RnM ()+checkValidRule rule_name ids lhs' fv_lhs'+ = do { -- Check for the form of the LHS+ case (validRuleLhs ids lhs') of+ Nothing -> return ()+ Just bad -> failWithTc (badRuleLhsErr rule_name lhs' bad)++ -- Check that LHS vars are all bound+ ; let bad_vars = [var | var <- ids, not (var `elemNameSet` fv_lhs')]+ ; mapM_ (addErr . badRuleVar rule_name) bad_vars }++validRuleLhs :: [Name] -> LHsExpr Name -> Maybe (HsExpr Name)+-- Nothing => OK+-- Just e => Not ok, and e is the offending sub-expression+validRuleLhs foralls lhs+ = checkl lhs+ where+ checkl (L _ e) = check e++ check (OpApp e1 op _ e2) = checkl op `mplus` checkl_e e1 `mplus` checkl_e e2+ check (HsApp e1 e2) = checkl e1 `mplus` checkl_e e2+ check (HsAppType e _) = checkl e+ check (HsVar (L _ v)) | v `notElem` foralls = Nothing+ check other = Just other -- Failure++ -- Check an argument+ checkl_e (L _ _e) = Nothing -- Was (check_e e); see Note [Rule LHS validity checking]++{- Commented out; see Note [Rule LHS validity checking] above+ check_e (HsVar v) = Nothing+ check_e (HsPar e) = checkl_e e+ check_e (HsLit e) = Nothing+ check_e (HsOverLit e) = Nothing++ check_e (OpApp e1 op _ e2) = checkl_e e1 `mplus` checkl_e op `mplus` checkl_e e2+ check_e (HsApp e1 e2) = checkl_e e1 `mplus` checkl_e e2+ check_e (NegApp e _) = checkl_e e+ check_e (ExplicitList _ es) = checkl_es es+ check_e other = Just other -- Fails++ checkl_es es = foldr (mplus . checkl_e) Nothing es+-}++badRuleVar :: FastString -> Name -> SDoc+badRuleVar name var+ = sep [text "Rule" <+> doubleQuotes (ftext name) <> colon,+ text "Forall'd variable" <+> quotes (ppr var) <+>+ text "does not appear on left hand side"]++badRuleLhsErr :: FastString -> LHsExpr Name -> HsExpr Name -> SDoc+badRuleLhsErr name lhs bad_e+ = sep [text "Rule" <+> pprRuleName name <> colon,+ nest 4 (vcat [err,+ text "in left-hand side:" <+> ppr lhs])]+ $$+ text "LHS must be of form (f e1 .. en) where f is not forall'd"+ where+ err = case bad_e of+ HsUnboundVar uv -> text "Not in scope:" <+> ppr uv+ _ -> text "Illegal expression:" <+> ppr bad_e++{-+*********************************************************+* *+\subsection{Vectorisation declarations}+* *+*********************************************************+-}++rnHsVectDecl :: VectDecl RdrName -> RnM (VectDecl Name, FreeVars)+-- FIXME: For the moment, the right-hand side is restricted to be a variable as we cannot properly+-- typecheck a complex right-hand side without invoking 'vectType' from the vectoriser.+rnHsVectDecl (HsVect s var rhs@(L _ (HsVar _)))+ = do { var' <- lookupLocatedOccRn var+ ; (rhs', fv_rhs) <- rnLExpr rhs+ ; return (HsVect s var' rhs', fv_rhs `addOneFV` unLoc var')+ }+rnHsVectDecl (HsVect _ _var _rhs)+ = failWith $ vcat+ [ text "IMPLEMENTATION RESTRICTION: right-hand side of a VECTORISE pragma"+ , text "must be an identifier"+ ]+rnHsVectDecl (HsNoVect s var)+ = do { var' <- lookupLocatedTopBndrRn var -- only applies to local (not imported) names+ ; return (HsNoVect s var', unitFV (unLoc var'))+ }+rnHsVectDecl (HsVectTypeIn s isScalar tycon Nothing)+ = do { tycon' <- lookupLocatedOccRn tycon+ ; return (HsVectTypeIn s isScalar tycon' Nothing, unitFV (unLoc tycon'))+ }+rnHsVectDecl (HsVectTypeIn s isScalar tycon (Just rhs_tycon))+ = do { tycon' <- lookupLocatedOccRn tycon+ ; rhs_tycon' <- lookupLocatedOccRn rhs_tycon+ ; return ( HsVectTypeIn s isScalar tycon' (Just rhs_tycon')+ , mkFVs [unLoc tycon', unLoc rhs_tycon'])+ }+rnHsVectDecl (HsVectTypeOut _ _ _)+ = panic "RnSource.rnHsVectDecl: Unexpected 'HsVectTypeOut'"+rnHsVectDecl (HsVectClassIn s cls)+ = do { cls' <- lookupLocatedOccRn cls+ ; return (HsVectClassIn s cls', unitFV (unLoc cls'))+ }+rnHsVectDecl (HsVectClassOut _)+ = panic "RnSource.rnHsVectDecl: Unexpected 'HsVectClassOut'"+rnHsVectDecl (HsVectInstIn instTy)+ = do { (instTy', fvs) <- rnLHsInstType (text "a VECTORISE pragma") instTy+ ; return (HsVectInstIn instTy', fvs)+ }+rnHsVectDecl (HsVectInstOut _)+ = panic "RnSource.rnHsVectDecl: Unexpected 'HsVectInstOut'"++{- **************************************************************+ * *+ Renaming type, class, instance and role declarations+* *+*****************************************************************++@rnTyDecl@ uses the `global name function' to create a new type+declaration in which local names have been replaced by their original+names, reporting any unknown names.++Renaming type variables is a pain. Because they now contain uniques,+it is necessary to pass in an association list which maps a parsed+tyvar to its @Name@ representation.+In some cases (type signatures of values),+it is even necessary to go over the type first+in order to get the set of tyvars used by it, make an assoc list,+and then go over it again to rename the tyvars!+However, we can also do some scoping checks at the same time.++Note [Dependency analysis of type, class, and instance decls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A TyClGroup represents a strongly connected components of+type/class/instance decls, together with the role annotations for the+type/class declarations. The renamer uses strongly connected+comoponent analysis to build these groups. We do this for a number of+reasons:++* Improve kind error messages. Consider++ data T f a = MkT f a+ data S f a = MkS f (T f a)++ This has a kind error, but the error message is better if you+ check T first, (fixing its kind) and *then* S. If you do kind+ inference together, you might get an error reported in S, which+ is jolly confusing. See Trac #4875+++* Increase kind polymorphism. See TcTyClsDecls+ Note [Grouping of type and class declarations]++Why do the instance declarations participate? At least two reasons++* Consider (Trac #11348)++ type family F a+ type instance F Int = Bool++ data R = MkR (F Int)++ type Foo = 'MkR 'True++ For Foo to kind-check we need to know that (F Int) ~ Bool. But we won't+ know that unless we've looked at the type instance declaration for F+ before kind-checking Foo.++* Another example is this (Trac #3990).++ data family Complex a+ data instance Complex Double = CD {-# UNPACK #-} !Double+ {-# UNPACK #-} !Double++ data T = T {-# UNPACK #-} !(Complex Double)++ Here, to generate the right kind of unpacked implementation for T,+ we must have access to the 'data instance' declaration.++* Things become more complicated when we introduce transitive+ dependencies through imported definitions, like in this scenario:++ A.hs+ type family Closed (t :: Type) :: Type where+ Closed t = Open t++ type family Open (t :: Type) :: Type++ B.hs+ data Q where+ Q :: Closed Bool -> Q++ type instance Open Int = Bool++ type S = 'Q 'True++ Somehow, we must ensure that the instance Open Int = Bool is checked before+ the type synonym S. While we know that S depends upon 'Q depends upon Closed,+ we have no idea that Closed depends upon Open!++ To accomodate for these situations, we ensure that an instance is checked+ before every @TyClDecl@ on which it does not depend. That's to say, instances+ are checked as early as possible in @tcTyAndClassDecls@.++------------------------------------+So much for WHY. What about HOW? It's pretty easy:++(1) Rename the type/class, instance, and role declarations+ individually++(2) Do strongly-connected component analysis of the type/class decls,+ We'll make a TyClGroup for each SCC++ In this step we treat a reference to a (promoted) data constructor+ K as a dependency on its parent type. Thus+ data T = K1 | K2+ data S = MkS (Proxy 'K1)+ Here S depends on 'K1 and hence on its parent T.++ In this step we ignore instances; see+ Note [No dependencies on data instances]++(3) Attach roles to the appropriate SCC++(4) Attach instances to the appropriate SCC.+ We add an instance decl to SCC when:+ all its free types/classes are bound in this SCC or earlier ones++(5) We make an initial TyClGroup, with empty group_tyclds, for any+ (orphan) instances that affect only imported types/classes++Steps (3) and (4) are done by the (mapAccumL mk_group) call.++Note [No dependencies on data instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ data family D a+ data instance D Int = D1+ data S = MkS (Proxy 'D1)++Here the declaration of S depends on the /data instance/ declaration+for 'D Int'. That makes things a lot more complicated, especially+if the data instance is an associated type of an enclosing class instance.+(And the class instance might have several associated type instances+with different dependency structure!)++Ugh. For now we simply don't allow promotion of data constructors for+data instances. See Note [AFamDataCon: not promoting data family+constructors] in TcEnv+-}+++rnTyClDecls :: [TyClGroup RdrName]+ -> RnM ([TyClGroup Name], FreeVars)+-- Rename the declarations and do dependency analysis on them+rnTyClDecls tycl_ds+ = do { -- Rename the type/class, instance, and role declaraations+ tycls_w_fvs <- mapM (wrapLocFstM rnTyClDecl)+ (tyClGroupTyClDecls tycl_ds)+ ; let tc_names = mkNameSet (map (tcdName . unLoc . fst) tycls_w_fvs)++ ; instds_w_fvs <- mapM (wrapLocFstM rnSrcInstDecl) (tyClGroupInstDecls tycl_ds)+ ; role_annots <- rnRoleAnnots tc_names (tyClGroupRoleDecls tycl_ds)++ ; tycls_w_fvs <- addBootDeps tycls_w_fvs+ -- TBD must add_boot_deps to instds_w_fvs?++ -- Do SCC analysis on the type/class decls+ ; rdr_env <- getGlobalRdrEnv+ ; let tycl_sccs = depAnalTyClDecls rdr_env tycls_w_fvs+ role_annot_env = mkRoleAnnotEnv role_annots++ inst_ds_map = mkInstDeclFreeVarsMap rdr_env tc_names instds_w_fvs+ (init_inst_ds, rest_inst_ds) = getInsts [] inst_ds_map++ first_group+ | null init_inst_ds = []+ | otherwise = [TyClGroup { group_tyclds = []+ , group_roles = []+ , group_instds = init_inst_ds }]++ ((final_inst_ds, orphan_roles), groups)+ = mapAccumL mk_group (rest_inst_ds, role_annot_env) tycl_sccs+++ all_fvs = plusFV (foldr (plusFV . snd) emptyFVs tycls_w_fvs)+ (foldr (plusFV . snd) emptyFVs instds_w_fvs)++ all_groups = first_group ++ groups++ ; ASSERT2( null final_inst_ds, ppr instds_w_fvs $$ ppr inst_ds_map+ $$ ppr (flattenSCCs tycl_sccs) $$ ppr final_inst_ds )+ mapM_ orphanRoleAnnotErr (nameEnvElts orphan_roles)++ ; traceRn "rnTycl dependency analysis made groups" (ppr all_groups)+ ; return (all_groups, all_fvs) }+ where+ mk_group :: (InstDeclFreeVarsMap, RoleAnnotEnv)+ -> SCC (LTyClDecl Name)+ -> ( (InstDeclFreeVarsMap, RoleAnnotEnv)+ , TyClGroup Name )+ mk_group (inst_map, role_env) scc+ = ((inst_map', role_env'), group)+ where+ tycl_ds = flattenSCC scc+ bndrs = map (tcdName . unLoc) tycl_ds+ (inst_ds, inst_map') = getInsts bndrs inst_map+ (roles, role_env') = getRoleAnnots bndrs role_env+ group = TyClGroup { group_tyclds = tycl_ds+ , group_roles = roles+ , group_instds = inst_ds }+++depAnalTyClDecls :: GlobalRdrEnv+ -> [(LTyClDecl Name, FreeVars)]+ -> [SCC (LTyClDecl Name)]+-- See Note [Dependency analysis of type, class, and instance decls]+depAnalTyClDecls rdr_env ds_w_fvs+ = stronglyConnCompFromEdgedVerticesUniq edges+ where+ edges = [ (d, tcdName (unLoc d), map (getParent rdr_env) (nonDetEltsUniqSet fvs))+ | (d, fvs) <- ds_w_fvs ]+ -- It's OK to use nonDetEltsUFM here as+ -- stronglyConnCompFromEdgedVertices is still deterministic+ -- even if the edges are in nondeterministic order as explained+ -- in Note [Deterministic SCC] in Digraph.++toParents :: GlobalRdrEnv -> NameSet -> NameSet+toParents rdr_env ns+ = nonDetFoldUniqSet add emptyNameSet ns+ -- It's OK to use nonDetFoldUFM because we immediately forget the+ -- ordering by creating a set+ where+ add n s = extendNameSet s (getParent rdr_env n)++getParent :: GlobalRdrEnv -> Name -> Name+getParent rdr_env n+ = case lookupGRE_Name rdr_env n of+ Just gre -> case gre_par gre of+ ParentIs { par_is = p } -> p+ FldParent { par_is = p } -> p+ _ -> n+ Nothing -> n+++{- Note [Extra dependencies from .hs-boot files]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This is a long story, so buckle in.++**Dependencies via hs-boot files are not obvious.** Consider the following case:++A.hs-boot+ module A where+ data A1++B.hs+ module B where+ import {-# SOURCE #-} A+ type B1 = A1++A.hs+ module A where+ import B+ data A2 = MkA2 B1+ data A1 = MkA1 A2++Here A2 is really recursive (via B1), but we won't see that easily when+doing dependency analysis when compiling A.hs. When we look at A2,+we see that its free variables are simply B1, but without (recursively) digging+into the definition of B1 will we see that it actually refers to A1 via an+hs-boot file.++**Recursive declarations, even those broken by an hs-boot file, need to+be type-checked together.** Whenever we refer to a declaration via+an hs-boot file, we must be careful not to force the TyThing too early:+ala Note [Tying the knot] if we force the TyThing before we have+defined it ourselves in the local type environment, GHC will error.++Conservatively, then, it would make sense that we to typecheck A1+and A2 from the previous example together, because the two types are+truly mutually recursive through B1.++If we are being clever, we might observe that while kind-checking+A2, we don't actually need to force the TyThing for A1: B1+independently records its kind, so there is no need to go "deeper".+But then we are in an uncomfortable situation where we have+constructed a TyThing for A2 before we have checked A1, and we+have to be absolutely certain we don't force it too deeply until+we get around to kind checking A1, which could be for a very long+time.++Indeed, with datatype promotion, we may very well need to look+at the type of MkA2 before we have kind-checked A1: consider,++ data T = MkT (Proxy 'MkA2)++To promote MkA2, we need to lift its type to the kind level.+We never tested this, but it seems likely A1 would get poked+at this point.++**Here's what we do instead.** So it is expedient for us to+make sure A1 and A2 are kind checked together in a loop.+To ensure that our dependency analysis can catch this,+we add a dependency:++ - from every local declaration+ - to everything that comes from this module's .hs-boot file+ (this is gotten from sb_tcs in the SelfBootInfo).++In this case, we'll add an edges++ - from A1 to A2 (but that edge is there already)+ - from A2 to A1 (which is new)++Well, not quite *every* declaration. Imagine module A+above had another datatype declaration:++ data A3 = A3 Int++Even though A3 has a dependency (on Int), all its dependencies are from things+that live on other packages. Since we don't have mutual dependencies across+packages, it is safe not to add the dependencies on the .hs-boot stuff to A2.++Hence function nameIsHomePackageImport.++Note that this is fairly conservative: it essentially implies that+EVERY type declaration in this modules hs-boot file will be kind-checked+together in one giant loop (and furthermore makes every other type+in the module depend on this loop). This is perhaps less than ideal, because+the larger a recursive group, the less polymorphism available (we+cannot infer a type to be polymorphically instantiated while we+are inferring its kind), but no one has hollered about this (yet!)+-}++addBootDeps :: [(LTyClDecl Name, FreeVars)] -> RnM [(LTyClDecl Name, FreeVars)]+-- See Note [Extra dependencies from .hs-boot files]+addBootDeps ds_w_fvs+ = do { tcg_env <- getGblEnv+ ; let this_mod = tcg_mod tcg_env+ boot_info = tcg_self_boot tcg_env++ add_boot_deps :: [(LTyClDecl Name, FreeVars)] -> [(LTyClDecl Name, FreeVars)]+ add_boot_deps ds_w_fvs+ = case boot_info of+ SelfBoot { sb_tcs = tcs } | not (isEmptyNameSet tcs)+ -> map (add_one tcs) ds_w_fvs+ _ -> ds_w_fvs++ add_one :: NameSet -> (LTyClDecl Name, FreeVars) -> (LTyClDecl Name, FreeVars)+ add_one tcs pr@(decl,fvs)+ | has_local_imports fvs = (decl, fvs `plusFV` tcs)+ | otherwise = pr++ has_local_imports fvs+ = nameSetAny (nameIsHomePackageImport this_mod) fvs+ ; return (add_boot_deps ds_w_fvs) }++++{- ******************************************************+* *+ Role annotations+* *+****************************************************** -}++-- | Renames role annotations, returning them as the values in a NameEnv+-- and checks for duplicate role annotations.+-- It is quite convenient to do both of these in the same place.+-- See also Note [Role annotations in the renamer]+rnRoleAnnots :: NameSet+ -> [LRoleAnnotDecl RdrName]+ -> RnM [LRoleAnnotDecl Name]+rnRoleAnnots tc_names role_annots+ = do { -- Check for duplicates *before* renaming, to avoid+ -- lumping together all the unboundNames+ let (no_dups, dup_annots) = removeDups role_annots_cmp role_annots+ role_annots_cmp (L _ annot1) (L _ annot2)+ = roleAnnotDeclName annot1 `compare` roleAnnotDeclName annot2+ ; mapM_ dupRoleAnnotErr dup_annots+ ; mapM (wrapLocM rn_role_annot1) no_dups }+ where+ rn_role_annot1 (RoleAnnotDecl tycon roles)+ = do { -- the name is an *occurrence*, but look it up only in the+ -- decls defined in this group (see #10263)+ tycon' <- lookupSigCtxtOccRn (RoleAnnotCtxt tc_names)+ (text "role annotation")+ tycon+ ; return $ RoleAnnotDecl tycon' roles }++dupRoleAnnotErr :: [LRoleAnnotDecl RdrName] -> RnM ()+dupRoleAnnotErr [] = panic "dupRoleAnnotErr"+dupRoleAnnotErr list+ = addErrAt loc $+ hang (text "Duplicate role annotations for" <+>+ quotes (ppr $ roleAnnotDeclName first_decl) <> colon)+ 2 (vcat $ map pp_role_annot sorted_list)+ where+ sorted_list = sortBy cmp_annot list+ (L loc first_decl : _) = sorted_list++ pp_role_annot (L loc decl) = hang (ppr decl)+ 4 (text "-- written at" <+> ppr loc)++ cmp_annot (L loc1 _) (L loc2 _) = loc1 `compare` loc2++orphanRoleAnnotErr :: LRoleAnnotDecl Name -> RnM ()+orphanRoleAnnotErr (L loc decl)+ = addErrAt loc $+ hang (text "Role annotation for a type previously declared:")+ 2 (ppr decl) $$+ parens (text "The role annotation must be given where" <+>+ quotes (ppr $ roleAnnotDeclName decl) <+>+ text "is declared.")+++{- Note [Role annotations in the renamer]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must ensure that a type's role annotation is put in the same group as the+proper type declaration. This is because role annotations are needed during+type-checking when creating the type's TyCon. So, rnRoleAnnots builds a+NameEnv (LRoleAnnotDecl Name) that maps a name to a role annotation for that+type, if any. Then, this map can be used to add the role annotations to the+groups after dependency analysis.++This process checks for duplicate role annotations, where we must be careful+to do the check *before* renaming to avoid calling all unbound names duplicates+of one another.++The renaming process, as usual, might identify and report errors for unbound+names. We exclude the annotations for unbound names in the annotation+environment to avoid spurious errors for orphaned annotations.++We then (in rnTyClDecls) do a check for orphan role annotations (role+annotations without an accompanying type decl). The check works by folding+over components (of type [[Either (TyClDecl Name) (InstDecl Name)]]), selecting+out the relevant role declarations for each group, as well as diminishing the+annotation environment. After the fold is complete, anything left over in the+name environment must be an orphan, and errors are generated.++An earlier version of this algorithm short-cut the orphan check by renaming+only with names declared in this module. But, this check is insufficient in+the case of staged module compilation (Template Haskell, GHCi).+See #8485. With the new lookup process (which includes types declared in other+modules), we get better error messages, too.+-}+++{- ******************************************************+* *+ Dependency info for instances+* *+****************************************************** -}++----------------------------------------------------------+-- | 'InstDeclFreeVarsMap is an association of an+-- @InstDecl@ with @FreeVars@. The @FreeVars@ are+-- the tycon names that are both+-- a) free in the instance declaration+-- b) bound by this group of type/class/instance decls+type InstDeclFreeVarsMap = [(LInstDecl Name, FreeVars)]++-- | Construct an @InstDeclFreeVarsMap@ by eliminating any @Name@s from the+-- @FreeVars@ which are *not* the binders of a @TyClDecl@.+mkInstDeclFreeVarsMap :: GlobalRdrEnv+ -> NameSet+ -> [(LInstDecl Name, FreeVars)]+ -> InstDeclFreeVarsMap+mkInstDeclFreeVarsMap rdr_env tycl_bndrs inst_ds_fvs+ = [ (inst_decl, toParents rdr_env fvs `intersectFVs` tycl_bndrs)+ | (inst_decl, fvs) <- inst_ds_fvs ]++-- | Get the @LInstDecl@s which have empty @FreeVars@ sets, and the+-- @InstDeclFreeVarsMap@ with these entries removed.+-- We call (getInsts tcs instd_map) when we've completed the declarations+-- for 'tcs'. The call returns (inst_decls, instd_map'), where+-- inst_decls are the instance declarations all of+-- whose free vars are now defined+-- instd_map' is the inst-decl map with 'tcs' removed from+-- the free-var set+getInsts :: [Name] -> InstDeclFreeVarsMap -> ([LInstDecl Name], InstDeclFreeVarsMap)+getInsts bndrs inst_decl_map+ = partitionWith pick_me inst_decl_map+ where+ pick_me :: (LInstDecl Name, FreeVars)+ -> Either (LInstDecl Name) (LInstDecl Name, FreeVars)+ pick_me (decl, fvs)+ | isEmptyNameSet depleted_fvs = Left decl+ | otherwise = Right (decl, depleted_fvs)+ where+ depleted_fvs = delFVs bndrs fvs++{- ******************************************************+* *+ Renaming a type or class declaration+* *+****************************************************** -}++rnTyClDecl :: TyClDecl RdrName+ -> RnM (TyClDecl Name, FreeVars)++-- All flavours of type family declarations ("type family", "newtype family",+-- and "data family"), both top level and (for an associated type)+-- in a class decl+rnTyClDecl (FamDecl { tcdFam = decl })+ = do { (decl', fvs) <- rnFamDecl Nothing decl+ ; return (FamDecl decl', fvs) }++rnTyClDecl (SynDecl { tcdLName = tycon, tcdTyVars = tyvars,+ tcdFixity = fixity, tcdRhs = rhs })+ = do { tycon' <- lookupLocatedTopBndrRn tycon+ ; kvs <- freeKiTyVarsKindVars <$> extractHsTyRdrTyVars rhs+ ; let doc = TySynCtx tycon+ ; traceRn "rntycl-ty" (ppr tycon <+> ppr kvs)+ ; ((tyvars', rhs'), fvs) <- bindHsQTyVars doc Nothing Nothing kvs tyvars $+ \ tyvars' _ ->+ do { (rhs', fvs) <- rnTySyn doc rhs+ ; return ((tyvars', rhs'), fvs) }+ ; return (SynDecl { tcdLName = tycon', tcdTyVars = tyvars'+ , tcdFixity = fixity+ , tcdRhs = rhs', tcdFVs = fvs }, fvs) }++-- "data", "newtype" declarations+-- both top level and (for an associated type) in an instance decl+rnTyClDecl (DataDecl { tcdLName = tycon, tcdTyVars = tyvars,+ tcdFixity = fixity, tcdDataDefn = defn })+ = do { tycon' <- lookupLocatedTopBndrRn tycon+ ; kvs <- extractDataDefnKindVars defn+ ; let doc = TyDataCtx tycon+ ; traceRn "rntycl-data" (ppr tycon <+> ppr kvs)+ ; ((tyvars', defn', no_kvs), fvs)+ <- bindHsQTyVars doc Nothing Nothing kvs tyvars $ \ tyvars' dep_vars ->+ do { ((defn', kind_sig_fvs), fvs) <- rnDataDefn doc defn+ ; let sig_tvs = filterNameSet isTyVarName kind_sig_fvs+ unbound_sig_tvs = sig_tvs `minusNameSet` dep_vars+ ; return ((tyvars', defn', isEmptyNameSet unbound_sig_tvs), fvs) }+ -- See Note [Complete user-supplied kind signatures] in HsDecls+ ; typeintype <- xoptM LangExt.TypeInType+ ; let cusk = hsTvbAllKinded tyvars' &&+ (not typeintype || no_kvs)+ ; return (DataDecl { tcdLName = tycon', tcdTyVars = tyvars'+ , tcdFixity = fixity+ , tcdDataDefn = defn', tcdDataCusk = cusk+ , tcdFVs = fvs }, fvs) }++rnTyClDecl (ClassDecl { tcdCtxt = context, tcdLName = lcls,+ tcdTyVars = tyvars, tcdFixity = fixity,+ tcdFDs = fds, tcdSigs = sigs,+ tcdMeths = mbinds, tcdATs = ats, tcdATDefs = at_defs,+ tcdDocs = docs})+ = do { lcls' <- lookupLocatedTopBndrRn lcls+ ; let cls' = unLoc lcls'+ kvs = [] -- No scoped kind vars except those in+ -- kind signatures on the tyvars++ -- Tyvars scope over superclass context and method signatures+ ; ((tyvars', context', fds', ats'), stuff_fvs)+ <- bindHsQTyVars cls_doc Nothing Nothing kvs tyvars $ \ tyvars' _ -> do+ -- Checks for distinct tyvars+ { (context', cxt_fvs) <- rnContext cls_doc context+ ; fds' <- rnFds fds+ -- The fundeps have no free variables+ ; (ats', fv_ats) <- rnATDecls cls' ats+ ; let fvs = cxt_fvs `plusFV`+ fv_ats+ ; return ((tyvars', context', fds', ats'), fvs) }++ ; (at_defs', fv_at_defs) <- rnList (rnTyFamDefltEqn cls') at_defs++ -- No need to check for duplicate associated type decls+ -- since that is done by RnNames.extendGlobalRdrEnvRn++ -- Check the signatures+ -- First process the class op sigs (op_sigs), then the fixity sigs (non_op_sigs).+ ; let sig_rdr_names_w_locs = [op | L _ (ClassOpSig False ops _) <- sigs+ , op <- ops]+ ; checkDupRdrNames sig_rdr_names_w_locs+ -- Typechecker is responsible for checking that we only+ -- give default-method bindings for things in this class.+ -- The renamer *could* check this for class decls, but can't+ -- for instance decls.++ -- The newLocals call is tiresome: given a generic class decl+ -- class C a where+ -- op :: a -> a+ -- op {| x+y |} (Inl a) = ...+ -- op {| x+y |} (Inr b) = ...+ -- op {| a*b |} (a*b) = ...+ -- we want to name both "x" tyvars with the same unique, so that they are+ -- easy to group together in the typechecker.+ ; (mbinds', sigs', meth_fvs)+ <- rnMethodBinds True cls' (hsAllLTyVarNames tyvars') mbinds sigs+ -- No need to check for duplicate method signatures+ -- since that is done by RnNames.extendGlobalRdrEnvRn+ -- and the methods are already in scope++ -- Haddock docs+ ; docs' <- mapM (wrapLocM rnDocDecl) docs++ ; let all_fvs = meth_fvs `plusFV` stuff_fvs `plusFV` fv_at_defs+ ; return (ClassDecl { tcdCtxt = context', tcdLName = lcls',+ tcdTyVars = tyvars', tcdFixity = fixity,+ tcdFDs = fds', tcdSigs = sigs',+ tcdMeths = mbinds', tcdATs = ats', tcdATDefs = at_defs',+ tcdDocs = docs', tcdFVs = all_fvs },+ all_fvs ) }+ where+ cls_doc = ClassDeclCtx lcls++-- "type" and "type instance" declarations+rnTySyn :: HsDocContext -> LHsType RdrName -> RnM (LHsType Name, FreeVars)+rnTySyn doc rhs = rnLHsType doc rhs++rnDataDefn :: HsDocContext -> HsDataDefn RdrName+ -> RnM ((HsDataDefn Name, NameSet), FreeVars)+ -- the NameSet includes all Names free in the kind signature+ -- See Note [Complete user-supplied kind signatures]+rnDataDefn doc (HsDataDefn { dd_ND = new_or_data, dd_cType = cType+ , dd_ctxt = context, dd_cons = condecls+ , dd_kindSig = m_sig, dd_derivs = derivs })+ = do { checkTc (h98_style || null (unLoc context))+ (badGadtStupidTheta doc)++ ; (m_sig', sig_fvs) <- case m_sig of+ Just sig -> first Just <$> rnLHsKind doc sig+ Nothing -> return (Nothing, emptyFVs)+ ; (context', fvs1) <- rnContext doc context+ ; (derivs', fvs3) <- rn_derivs derivs++ -- For the constructor declarations, drop the LocalRdrEnv+ -- in the GADT case, where the type variables in the declaration+ -- do not scope over the constructor signatures+ -- data T a where { T1 :: forall b. b-> b }+ ; let { zap_lcl_env | h98_style = \ thing -> thing+ | otherwise = setLocalRdrEnv emptyLocalRdrEnv }+ ; (condecls', con_fvs) <- zap_lcl_env $ rnConDecls condecls+ -- No need to check for duplicate constructor decls+ -- since that is done by RnNames.extendGlobalRdrEnvRn++ ; let all_fvs = fvs1 `plusFV` fvs3 `plusFV`+ con_fvs `plusFV` sig_fvs+ ; return (( HsDataDefn { dd_ND = new_or_data, dd_cType = cType+ , dd_ctxt = context', dd_kindSig = m_sig'+ , dd_cons = condecls'+ , dd_derivs = derivs' }+ , sig_fvs )+ , all_fvs )+ }+ where+ h98_style = case condecls of -- Note [Stupid theta]+ L _ (ConDeclGADT {}) : _ -> False+ _ -> True++ rn_derivs (L loc ds)+ = do { deriv_strats_ok <- xoptM LangExt.DerivingStrategies+ ; failIfTc (lengthExceeds ds 1 && not deriv_strats_ok)+ multipleDerivClausesErr+ ; (ds', fvs) <- mapFvRn (rnLHsDerivingClause deriv_strats_ok doc) ds+ ; return (L loc ds', fvs) }++rnLHsDerivingClause :: Bool -> HsDocContext -> LHsDerivingClause RdrName+ -> RnM (LHsDerivingClause Name, FreeVars)+rnLHsDerivingClause deriv_strats_ok doc+ (L loc (HsDerivingClause { deriv_clause_strategy = dcs+ , deriv_clause_tys = L loc' dct }))+ = do { failIfTc (isJust dcs && not deriv_strats_ok) $+ illegalDerivStrategyErr $ fmap unLoc dcs+ ; (dct', fvs) <- mapFvRn (rnHsSigType doc) dct+ ; return ( L loc (HsDerivingClause { deriv_clause_strategy = dcs+ , deriv_clause_tys = L loc' dct' })+ , fvs ) }++badGadtStupidTheta :: HsDocContext -> SDoc+badGadtStupidTheta _+ = vcat [text "No context is allowed on a GADT-style data declaration",+ text "(You can put a context on each constructor, though.)"]++illegalDerivStrategyErr :: Maybe DerivStrategy -> SDoc+illegalDerivStrategyErr ds+ = vcat [ text "Illegal deriving strategy" <> colon <+> maybe empty ppr ds+ , text "Use DerivingStrategies to enable this extension" ]++multipleDerivClausesErr :: SDoc+multipleDerivClausesErr+ = vcat [ text "Illegal use of multiple, consecutive deriving clauses"+ , text "Use DerivingStrategies to allow this" ]++rnFamDecl :: Maybe Name -- Just cls => this FamilyDecl is nested+ -- inside an *class decl* for cls+ -- used for associated types+ -> FamilyDecl RdrName+ -> RnM (FamilyDecl Name, FreeVars)+rnFamDecl mb_cls (FamilyDecl { fdLName = tycon, fdTyVars = tyvars+ , fdFixity = fixity+ , fdInfo = info, fdResultSig = res_sig+ , fdInjectivityAnn = injectivity })+ = do { tycon' <- lookupLocatedTopBndrRn tycon+ ; kvs <- extractRdrKindSigVars res_sig+ ; ((tyvars', res_sig', injectivity'), fv1) <-+ bindHsQTyVars doc Nothing mb_cls kvs tyvars $+ \ tyvars'@(HsQTvs { hsq_implicit = rn_kvs }) _ ->+ do { let rn_sig = rnFamResultSig doc rn_kvs+ ; (res_sig', fv_kind) <- wrapLocFstM rn_sig res_sig+ ; injectivity' <- traverse (rnInjectivityAnn tyvars' res_sig')+ injectivity+ ; return ( (tyvars', res_sig', injectivity') , fv_kind ) }+ ; (info', fv2) <- rn_info info+ ; return (FamilyDecl { fdLName = tycon', fdTyVars = tyvars'+ , fdFixity = fixity+ , fdInfo = info', fdResultSig = res_sig'+ , fdInjectivityAnn = injectivity' }+ , fv1 `plusFV` fv2) }+ where+ doc = TyFamilyCtx tycon++ ----------------------+ rn_info (ClosedTypeFamily (Just eqns))+ = do { (eqns', fvs) <- rnList (rnTyFamInstEqn Nothing) eqns+ -- no class context,+ ; return (ClosedTypeFamily (Just eqns'), fvs) }+ rn_info (ClosedTypeFamily Nothing)+ = return (ClosedTypeFamily Nothing, emptyFVs)+ rn_info OpenTypeFamily = return (OpenTypeFamily, emptyFVs)+ rn_info DataFamily = return (DataFamily, emptyFVs)++rnFamResultSig :: HsDocContext+ -> [Name] -- kind variables already in scope+ -> FamilyResultSig RdrName+ -> RnM (FamilyResultSig Name, FreeVars)+rnFamResultSig _ _ NoSig+ = return (NoSig, emptyFVs)+rnFamResultSig doc _ (KindSig kind)+ = do { (rndKind, ftvs) <- rnLHsKind doc kind+ ; return (KindSig rndKind, ftvs) }+rnFamResultSig doc kv_names (TyVarSig tvbndr)+ = do { -- `TyVarSig` tells us that user named the result of a type family by+ -- writing `= tyvar` or `= (tyvar :: kind)`. In such case we want to+ -- be sure that the supplied result name is not identical to an+ -- already in-scope type variable from an enclosing class.+ --+ -- Example of disallowed declaration:+ -- class C a b where+ -- type F b = a | a -> b+ rdr_env <- getLocalRdrEnv+ ; let resName = hsLTyVarName tvbndr+ ; when (resName `elemLocalRdrEnv` rdr_env) $+ addErrAt (getLoc tvbndr) $+ (hsep [ text "Type variable", quotes (ppr resName) <> comma+ , text "naming a type family result,"+ ] $$+ text "shadows an already bound type variable")++ ; bindLHsTyVarBndr doc Nothing -- this might be a lie, but it's used for+ -- scoping checks that are irrelevant here+ (mkNameSet kv_names) emptyNameSet+ -- use of emptyNameSet here avoids+ -- redundant duplicate errors+ tvbndr $ \ _ _ tvbndr' ->+ return (TyVarSig tvbndr', unitFV (hsLTyVarName tvbndr')) }++-- Note [Renaming injectivity annotation]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- During renaming of injectivity annotation we have to make several checks to+-- make sure that it is well-formed. At the moment injectivity annotation+-- consists of a single injectivity condition, so the terms "injectivity+-- annotation" and "injectivity condition" might be used interchangeably. See+-- Note [Injectivity annotation] for a detailed discussion of currently allowed+-- injectivity annotations.+--+-- Checking LHS is simple because the only type variable allowed on the LHS of+-- injectivity condition is the variable naming the result in type family head.+-- Example of disallowed annotation:+--+-- type family Foo a b = r | b -> a+--+-- Verifying RHS of injectivity consists of checking that:+--+-- 1. only variables defined in type family head appear on the RHS (kind+-- variables are also allowed). Example of disallowed annotation:+--+-- type family Foo a = r | r -> b+--+-- 2. for associated types the result variable does not shadow any of type+-- class variables. Example of disallowed annotation:+--+-- class Foo a b where+-- type F a = b | b -> a+--+-- Breaking any of these assumptions results in an error.++-- | Rename injectivity annotation. Note that injectivity annotation is just the+-- part after the "|". Everything that appears before it is renamed in+-- rnFamDecl.+rnInjectivityAnn :: LHsQTyVars Name -- ^ Type variables declared in+ -- type family head+ -> LFamilyResultSig Name -- ^ Result signature+ -> LInjectivityAnn RdrName -- ^ Injectivity annotation+ -> RnM (LInjectivityAnn Name)+rnInjectivityAnn tvBndrs (L _ (TyVarSig resTv))+ (L srcSpan (InjectivityAnn injFrom injTo))+ = do+ { (injDecl'@(L _ (InjectivityAnn injFrom' injTo')), noRnErrors)+ <- askNoErrs $+ bindLocalNames [hsLTyVarName resTv] $+ -- The return type variable scopes over the injectivity annotation+ -- e.g. type family F a = (r::*) | r -> a+ do { injFrom' <- rnLTyVar injFrom+ ; injTo' <- mapM rnLTyVar injTo+ ; return $ L srcSpan (InjectivityAnn injFrom' injTo') }++ ; let tvNames = Set.fromList $ hsAllLTyVarNames tvBndrs+ resName = hsLTyVarName resTv+ -- See Note [Renaming injectivity annotation]+ lhsValid = EQ == (stableNameCmp resName (unLoc injFrom'))+ rhsValid = Set.fromList (map unLoc injTo') `Set.difference` tvNames++ -- if renaming of type variables ended with errors (eg. there were+ -- not-in-scope variables) don't check the validity of injectivity+ -- annotation. This gives better error messages.+ ; when (noRnErrors && not lhsValid) $+ addErrAt (getLoc injFrom)+ ( vcat [ text $ "Incorrect type variable on the LHS of "+ ++ "injectivity condition"+ , nest 5+ ( vcat [ text "Expected :" <+> ppr resName+ , text "Actual :" <+> ppr injFrom ])])++ ; when (noRnErrors && not (Set.null rhsValid)) $+ do { let errorVars = Set.toList rhsValid+ ; addErrAt srcSpan $ ( hsep+ [ text "Unknown type variable" <> plural errorVars+ , text "on the RHS of injectivity condition:"+ , interpp'SP errorVars ] ) }++ ; return injDecl' }++-- We can only hit this case when the user writes injectivity annotation without+-- naming the result:+--+-- type family F a | result -> a+-- type family F a :: * | result -> a+--+-- So we rename injectivity annotation like we normally would except that+-- this time we expect "result" to be reported not in scope by rnLTyVar.+rnInjectivityAnn _ _ (L srcSpan (InjectivityAnn injFrom injTo)) =+ setSrcSpan srcSpan $ do+ (injDecl', _) <- askNoErrs $ do+ injFrom' <- rnLTyVar injFrom+ injTo' <- mapM rnLTyVar injTo+ return $ L srcSpan (InjectivityAnn injFrom' injTo')+ return $ injDecl'++{-+Note [Stupid theta]+~~~~~~~~~~~~~~~~~~~+Trac #3850 complains about a regression wrt 6.10 for+ data Show a => T a+There is no reason not to allow the stupid theta if there are no data+constructors. It's still stupid, but does no harm, and I don't want+to cause programs to break unnecessarily (notably HList). So if there+are no data constructors we allow h98_style = True+-}+++{- *****************************************************+* *+ Support code for type/data declarations+* *+***************************************************** -}++---------------+badAssocRhs :: [Name] -> RnM ()+badAssocRhs ns+ = addErr (hang (text "The RHS of an associated type declaration mentions"+ <+> pprWithCommas (quotes . ppr) ns)+ 2 (text "All such variables must be bound on the LHS"))++-----------------+rnConDecls :: [LConDecl RdrName] -> RnM ([LConDecl Name], FreeVars)+rnConDecls = mapFvRn (wrapLocFstM rnConDecl)++rnConDecl :: ConDecl RdrName -> RnM (ConDecl Name, FreeVars)+rnConDecl decl@(ConDeclH98 { con_name = name, con_qvars = qtvs+ , con_cxt = mcxt, con_details = details+ , con_doc = mb_doc })+ = do { _ <- addLocM checkConName name+ ; new_name <- lookupLocatedTopBndrRn name+ ; let doc = ConDeclCtx [new_name]+ ; mb_doc' <- rnMbLHsDoc mb_doc+ ; (kvs, qtvs') <- get_con_qtvs (hsConDeclArgTys details)++ ; bindHsQTyVars doc (Just $ inHsDocContext doc) Nothing kvs qtvs' $+ \new_tyvars _ -> do+ { (new_context, fvs1) <- case mcxt of+ Nothing -> return (Nothing,emptyFVs)+ Just lcxt -> do { (lctx',fvs) <- rnContext doc lcxt+ ; return (Just lctx',fvs) }+ ; (new_details, fvs2) <- rnConDeclDetails (unLoc new_name) doc details+ ; let (new_details',fvs3) = (new_details,emptyFVs)+ ; traceRn "rnConDecl" (ppr name <+> vcat+ [ text "free_kvs:" <+> ppr kvs+ , text "qtvs:" <+> ppr qtvs+ , text "qtvs':" <+> ppr qtvs' ])+ ; let all_fvs = fvs1 `plusFV` fvs2 `plusFV` fvs3+ new_tyvars' = case qtvs of+ Nothing -> Nothing+ Just _ -> Just new_tyvars+ ; return (decl { con_name = new_name, con_qvars = new_tyvars'+ , con_cxt = new_context, con_details = new_details'+ , con_doc = mb_doc' },+ all_fvs) }}+ where+ cxt = maybe [] unLoc mcxt+ get_rdr_tvs tys = extractHsTysRdrTyVars (cxt ++ tys)++ get_con_qtvs :: [LHsType RdrName]+ -> RnM ([Located RdrName], LHsQTyVars RdrName)+ get_con_qtvs arg_tys+ | Just tvs <- qtvs -- data T = forall a. MkT (a -> a)+ = do { free_vars <- get_rdr_tvs arg_tys+ ; return (freeKiTyVarsKindVars free_vars, tvs) }+ | otherwise -- data T = MkT (a -> a)+ = return ([], mkHsQTvs [])++rnConDecl decl@(ConDeclGADT { con_names = names, con_type = ty+ , con_doc = mb_doc })+ = do { mapM_ (addLocM checkConName) names+ ; new_names <- mapM lookupLocatedTopBndrRn names+ ; let doc = ConDeclCtx new_names+ ; mb_doc' <- rnMbLHsDoc mb_doc++ ; (ty', fvs) <- rnHsSigType doc ty+ ; traceRn "rnConDecl" (ppr names <+> vcat+ [ text "fvs:" <+> ppr fvs ])+ ; return (decl { con_names = new_names, con_type = ty'+ , con_doc = mb_doc' },+ fvs) }++rnConDeclDetails+ :: Name+ -> HsDocContext+ -> HsConDetails (LHsType RdrName) (Located [LConDeclField RdrName])+ -> RnM (HsConDetails (LHsType Name) (Located [LConDeclField Name]), FreeVars)+rnConDeclDetails _ doc (PrefixCon tys)+ = do { (new_tys, fvs) <- rnLHsTypes doc tys+ ; return (PrefixCon new_tys, fvs) }++rnConDeclDetails _ doc (InfixCon ty1 ty2)+ = do { (new_ty1, fvs1) <- rnLHsType doc ty1+ ; (new_ty2, fvs2) <- rnLHsType doc ty2+ ; return (InfixCon new_ty1 new_ty2, fvs1 `plusFV` fvs2) }++rnConDeclDetails con doc (RecCon (L l fields))+ = do { fls <- lookupConstructorFields con+ ; (new_fields, fvs) <- rnConDeclFields doc fls fields+ -- No need to check for duplicate fields+ -- since that is done by RnNames.extendGlobalRdrEnvRn+ ; return (RecCon (L l new_fields), fvs) }++-------------------------------------------------++-- | Brings pattern synonym names and also pattern synonym selectors+-- from record pattern synonyms into scope.+extendPatSynEnv :: HsValBinds RdrName -> MiniFixityEnv+ -> ([Name] -> TcRnIf TcGblEnv TcLclEnv a) -> TcM a+extendPatSynEnv val_decls local_fix_env thing = do {+ names_with_fls <- new_ps val_decls+ ; let pat_syn_bndrs = concat [ name: map flSelector fields+ | (name, fields) <- names_with_fls ]+ ; let avails = map avail pat_syn_bndrs+ ; (gbl_env, lcl_env) <- extendGlobalRdrEnvRn avails local_fix_env++ ; let field_env' = extendNameEnvList (tcg_field_env gbl_env) names_with_fls+ final_gbl_env = gbl_env { tcg_field_env = field_env' }+ ; setEnvs (final_gbl_env, lcl_env) (thing pat_syn_bndrs) }+ where+ new_ps :: HsValBinds RdrName -> TcM [(Name, [FieldLabel])]+ new_ps (ValBindsIn binds _) = foldrBagM new_ps' [] binds+ new_ps _ = panic "new_ps"++ new_ps' :: LHsBindLR RdrName RdrName+ -> [(Name, [FieldLabel])]+ -> TcM [(Name, [FieldLabel])]+ new_ps' bind names+ | L bind_loc (PatSynBind (PSB { psb_id = L _ n+ , psb_args = RecordPatSyn as })) <- bind+ = do+ bnd_name <- newTopSrcBinder (L bind_loc n)+ let rnames = map recordPatSynSelectorId as+ mkFieldOcc :: Located RdrName -> LFieldOcc RdrName+ mkFieldOcc (L l name) = L l (FieldOcc (L l name) PlaceHolder)+ field_occs = map mkFieldOcc rnames+ flds <- mapM (newRecordSelector False [bnd_name]) field_occs+ return ((bnd_name, flds): names)+ | L bind_loc (PatSynBind (PSB { psb_id = L _ n})) <- bind+ = do+ bnd_name <- newTopSrcBinder (L bind_loc n)+ return ((bnd_name, []): names)+ | otherwise+ = return names++{-+*********************************************************+* *+\subsection{Support code to rename types}+* *+*********************************************************+-}++rnFds :: [Located (FunDep (Located RdrName))]+ -> RnM [Located (FunDep (Located Name))]+rnFds fds+ = mapM (wrapLocM rn_fds) fds+ where+ rn_fds (tys1, tys2)+ = do { tys1' <- rnHsTyVars tys1+ ; tys2' <- rnHsTyVars tys2+ ; return (tys1', tys2') }++rnHsTyVars :: [Located RdrName] -> RnM [Located Name]+rnHsTyVars tvs = mapM rnHsTyVar tvs++rnHsTyVar :: Located RdrName -> RnM (Located Name)+rnHsTyVar (L l tyvar) = do+ tyvar' <- lookupOccRn tyvar+ return (L l tyvar')++{-+*********************************************************+* *+ findSplice+* *+*********************************************************++This code marches down the declarations, looking for the first+Template Haskell splice. As it does so it+ a) groups the declarations into a HsGroup+ b) runs any top-level quasi-quotes+-}++findSplice :: [LHsDecl RdrName] -> RnM (HsGroup RdrName, Maybe (SpliceDecl RdrName, [LHsDecl RdrName]))+findSplice ds = addl emptyRdrGroup ds++addl :: HsGroup RdrName -> [LHsDecl RdrName]+ -> RnM (HsGroup RdrName, Maybe (SpliceDecl RdrName, [LHsDecl RdrName]))+-- This stuff reverses the declarations (again) but it doesn't matter+addl gp [] = return (gp, Nothing)+addl gp (L l d : ds) = add gp l d ds+++add :: HsGroup RdrName -> SrcSpan -> HsDecl RdrName -> [LHsDecl RdrName]+ -> RnM (HsGroup RdrName, Maybe (SpliceDecl RdrName, [LHsDecl RdrName]))++-- #10047: Declaration QuasiQuoters are expanded immediately, without+-- causing a group split+add gp _ (SpliceD (SpliceDecl (L _ qq@HsQuasiQuote{}) _)) ds+ = do { (ds', _) <- rnTopSpliceDecls qq+ ; addl gp (ds' ++ ds)+ }++add gp loc (SpliceD splice@(SpliceDecl _ flag)) ds+ = do { -- We've found a top-level splice. If it is an *implicit* one+ -- (i.e. a naked top level expression)+ case flag of+ ExplicitSplice -> return ()+ ImplicitSplice -> do { th_on <- xoptM LangExt.TemplateHaskell+ ; unless th_on $ setSrcSpan loc $+ failWith badImplicitSplice }++ ; return (gp, Just (splice, ds)) }+ where+ badImplicitSplice = text "Parse error: module header, import declaration"+ $$ text "or top-level declaration expected."++-- Class declarations: pull out the fixity signatures to the top+add gp@(HsGroup {hs_tyclds = ts, hs_fixds = fs}) l (TyClD d) ds+ | isClassDecl d+ = let fsigs = [ L l f | L l (FixSig f) <- tcdSigs d ] in+ addl (gp { hs_tyclds = add_tycld (L l d) ts, hs_fixds = fsigs ++ fs}) ds+ | otherwise+ = addl (gp { hs_tyclds = add_tycld (L l d) ts }) ds++-- Signatures: fixity sigs go a different place than all others+add gp@(HsGroup {hs_fixds = ts}) l (SigD (FixSig f)) ds+ = addl (gp {hs_fixds = L l f : ts}) ds+add gp@(HsGroup {hs_valds = ts}) l (SigD d) ds+ = addl (gp {hs_valds = add_sig (L l d) ts}) ds++-- Value declarations: use add_bind+add gp@(HsGroup {hs_valds = ts}) l (ValD d) ds+ = addl (gp { hs_valds = add_bind (L l d) ts }) ds++-- Role annotations: added to the TyClGroup+add gp@(HsGroup {hs_tyclds = ts}) l (RoleAnnotD d) ds+ = addl (gp { hs_tyclds = add_role_annot (L l d) ts }) ds++-- NB instance declarations go into TyClGroups. We throw them into the first+-- group, just as we do for the TyClD case. The renamer will go on to group+-- and order them later.+add gp@(HsGroup {hs_tyclds = ts}) l (InstD d) ds+ = addl (gp { hs_tyclds = add_instd (L l d) ts }) ds++-- The rest are routine+add gp@(HsGroup {hs_derivds = ts}) l (DerivD d) ds+ = addl (gp { hs_derivds = L l d : ts }) ds+add gp@(HsGroup {hs_defds = ts}) l (DefD d) ds+ = addl (gp { hs_defds = L l d : ts }) ds+add gp@(HsGroup {hs_fords = ts}) l (ForD d) ds+ = addl (gp { hs_fords = L l d : ts }) ds+add gp@(HsGroup {hs_warnds = ts}) l (WarningD d) ds+ = addl (gp { hs_warnds = L l d : ts }) ds+add gp@(HsGroup {hs_annds = ts}) l (AnnD d) ds+ = addl (gp { hs_annds = L l d : ts }) ds+add gp@(HsGroup {hs_ruleds = ts}) l (RuleD d) ds+ = addl (gp { hs_ruleds = L l d : ts }) ds+add gp@(HsGroup {hs_vects = ts}) l (VectD d) ds+ = addl (gp { hs_vects = L l d : ts }) ds+add gp l (DocD d) ds+ = addl (gp { hs_docs = (L l d) : (hs_docs gp) }) ds++add_tycld :: LTyClDecl a -> [TyClGroup a] -> [TyClGroup a]+add_tycld d [] = [TyClGroup { group_tyclds = [d]+ , group_roles = []+ , group_instds = []+ }+ ]+add_tycld d (ds@(TyClGroup { group_tyclds = tyclds }):dss)+ = ds { group_tyclds = d : tyclds } : dss++add_instd :: LInstDecl a -> [TyClGroup a] -> [TyClGroup a]+add_instd d [] = [TyClGroup { group_tyclds = []+ , group_roles = []+ , group_instds = [d]+ }+ ]+add_instd d (ds@(TyClGroup { group_instds = instds }):dss)+ = ds { group_instds = d : instds } : dss++add_role_annot :: LRoleAnnotDecl a -> [TyClGroup a] -> [TyClGroup a]+add_role_annot d [] = [TyClGroup { group_tyclds = []+ , group_roles = [d]+ , group_instds = []+ }+ ]+add_role_annot d (tycls@(TyClGroup { group_roles = roles }) : rest)+ = tycls { group_roles = d : roles } : rest++add_bind :: LHsBind a -> HsValBinds a -> HsValBinds a+add_bind b (ValBindsIn bs sigs) = ValBindsIn (bs `snocBag` b) sigs+add_bind _ (ValBindsOut {}) = panic "RdrHsSyn:add_bind"++add_sig :: LSig a -> HsValBinds a -> HsValBinds a+add_sig s (ValBindsIn bs sigs) = ValBindsIn bs (s:sigs)+add_sig _ (ValBindsOut {}) = panic "RdrHsSyn:add_sig"
+ rename/RnSplice.hs view
@@ -0,0 +1,866 @@+{-# LANGUAGE CPP #-}++module RnSplice (+ rnTopSpliceDecls,+ rnSpliceType, rnSpliceExpr, rnSplicePat, rnSpliceDecl,+ rnBracket,+ checkThLocalName+ , traceSplice, SpliceInfo(..)+ ) where++#include "HsVersions.h"++import Name+import NameSet+import HsSyn+import RdrName+import TcRnMonad+import Kind++import RnEnv+import RnSource ( rnSrcDecls, findSplice )+import RnPat ( rnPat )+import BasicTypes ( TopLevelFlag, isTopLevel, SourceText(..) )+import Outputable+import Module+import SrcLoc+import RnTypes ( rnLHsType )++import Control.Monad ( unless, when )++import {-# SOURCE #-} RnExpr ( rnLExpr )++import TcEnv ( checkWellStaged )+import THNames ( liftName )++import DynFlags+import FastString+import ErrUtils ( dumpIfSet_dyn_printer )+import TcEnv ( tcMetaTy )+import Hooks+import Var ( Id )+import THNames ( quoteExpName, quotePatName, quoteDecName, quoteTypeName+ , decsQTyConName, expQTyConName, patQTyConName, typeQTyConName, )++import {-# SOURCE #-} TcExpr ( tcPolyExpr )+import {-# SOURCE #-} TcSplice+ ( runMetaD+ , runMetaE+ , runMetaP+ , runMetaT+ , runRemoteModFinalizers+ , tcTopSpliceExpr+ )++import GHCi.RemoteTypes ( ForeignRef )+import qualified Language.Haskell.TH as TH (Q)++import qualified GHC.LanguageExtensions as LangExt++{-+************************************************************************+* *+ Template Haskell brackets+* *+************************************************************************+-}++rnBracket :: HsExpr RdrName -> HsBracket RdrName -> RnM (HsExpr Name, FreeVars)+rnBracket e br_body+ = addErrCtxt (quotationCtxtDoc br_body) $+ do { -- Check that -XTemplateHaskellQuotes is enabled and available+ thQuotesEnabled <- xoptM LangExt.TemplateHaskellQuotes+ ; unless thQuotesEnabled $+ failWith ( vcat+ [ text "Syntax error on" <+> ppr e+ , text ("Perhaps you intended to use TemplateHaskell"+ ++ " or TemplateHaskellQuotes") ] )++ -- Check for nested brackets+ ; cur_stage <- getStage+ ; case cur_stage of+ { Splice Typed -> checkTc (isTypedBracket br_body)+ illegalUntypedBracket+ ; Splice Untyped -> checkTc (not (isTypedBracket br_body))+ illegalTypedBracket+ ; RunSplice _ ->+ -- See Note [RunSplice ThLevel] in "TcRnTypes".+ pprPanic "rnBracket: Renaming bracket when running a splice"+ (ppr e)+ ; Comp -> return ()+ ; Brack {} -> failWithTc illegalBracket+ }++ -- Brackets are desugared to code that mentions the TH package+ ; recordThUse++ ; case isTypedBracket br_body of+ True -> do { traceRn "Renaming typed TH bracket" empty+ ; (body', fvs_e) <-+ setStage (Brack cur_stage RnPendingTyped) $+ rn_bracket cur_stage br_body+ ; return (HsBracket body', fvs_e) }++ False -> do { traceRn "Renaming untyped TH bracket" empty+ ; ps_var <- newMutVar []+ ; (body', fvs_e) <-+ setStage (Brack cur_stage (RnPendingUntyped ps_var)) $+ rn_bracket cur_stage br_body+ ; pendings <- readMutVar ps_var+ ; return (HsRnBracketOut body' pendings, fvs_e) }+ }++rn_bracket :: ThStage -> HsBracket RdrName -> RnM (HsBracket Name, FreeVars)+rn_bracket outer_stage br@(VarBr flg rdr_name)+ = do { name <- lookupOccRn rdr_name+ ; this_mod <- getModule++ ; when (flg && nameIsLocalOrFrom this_mod name) $+ -- Type variables can be quoted in TH. See #5721.+ do { mb_bind_lvl <- lookupLocalOccThLvl_maybe name+ ; case mb_bind_lvl of+ { Nothing -> return () -- Can happen for data constructors,+ -- but nothing needs to be done for them++ ; Just (top_lvl, bind_lvl) -- See Note [Quoting names]+ | isTopLevel top_lvl+ -> when (isExternalName name) (keepAlive name)+ | otherwise+ -> do { traceRn "rn_bracket VarBr"+ (ppr name <+> ppr bind_lvl+ <+> ppr outer_stage)+ ; checkTc (thLevel outer_stage + 1 == bind_lvl)+ (quotedNameStageErr br) }+ }+ }+ ; return (VarBr flg name, unitFV name) }++rn_bracket _ (ExpBr e) = do { (e', fvs) <- rnLExpr e+ ; return (ExpBr e', fvs) }++rn_bracket _ (PatBr p) = rnPat ThPatQuote p $ \ p' -> return (PatBr p', emptyFVs)++rn_bracket _ (TypBr t) = do { (t', fvs) <- rnLHsType TypBrCtx t+ ; return (TypBr t', fvs) }++rn_bracket _ (DecBrL decls)+ = do { group <- groupDecls decls+ ; gbl_env <- getGblEnv+ ; let new_gbl_env = gbl_env { tcg_dus = emptyDUs }+ -- The emptyDUs is so that we just collect uses for this+ -- group alone in the call to rnSrcDecls below+ ; (tcg_env, group') <- setGblEnv new_gbl_env $+ rnSrcDecls group++ -- Discard the tcg_env; it contains only extra info about fixity+ ; traceRn "rn_bracket dec" (ppr (tcg_dus tcg_env) $$+ ppr (duUses (tcg_dus tcg_env)))+ ; return (DecBrG group', duUses (tcg_dus tcg_env)) }+ where+ groupDecls :: [LHsDecl RdrName] -> RnM (HsGroup RdrName)+ groupDecls decls+ = do { (group, mb_splice) <- findSplice decls+ ; case mb_splice of+ { Nothing -> return group+ ; Just (splice, rest) ->+ do { group' <- groupDecls rest+ ; let group'' = appendGroups group group'+ ; return group'' { hs_splcds = noLoc splice : hs_splcds group' }+ }+ }}++rn_bracket _ (DecBrG _) = panic "rn_bracket: unexpected DecBrG"++rn_bracket _ (TExpBr e) = do { (e', fvs) <- rnLExpr e+ ; return (TExpBr e', fvs) }++quotationCtxtDoc :: HsBracket RdrName -> SDoc+quotationCtxtDoc br_body+ = hang (text "In the Template Haskell quotation")+ 2 (ppr br_body)++illegalBracket :: SDoc+illegalBracket =+ text "Template Haskell brackets cannot be nested" <+>+ text "(without intervening splices)"++illegalTypedBracket :: SDoc+illegalTypedBracket =+ text "Typed brackets may only appear in typed splices."++illegalUntypedBracket :: SDoc+illegalUntypedBracket =+ text "Untyped brackets may only appear in untyped splices."++quotedNameStageErr :: HsBracket RdrName -> SDoc+quotedNameStageErr br+ = sep [ text "Stage error: the non-top-level quoted name" <+> ppr br+ , text "must be used at the same stage at which it is bound" ]+++{-+*********************************************************+* *+ Splices+* *+*********************************************************++Note [Free variables of typed splices]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider renaming this:+ f = ...+ h = ...$(thing "f")...++where the splice is a *typed* splice. The splice can expand into+literally anything, so when we do dependency analysis we must assume+that it might mention 'f'. So we simply treat all locally-defined+names as mentioned by any splice. This is terribly brutal, but I+don't see what else to do. For example, it'll mean that every+locally-defined thing will appear to be used, so no unused-binding+warnings. But if we miss the dependency, then we might typecheck 'h'+before 'f', and that will crash the type checker because 'f' isn't in+scope.++Currently, I'm not treating a splice as also mentioning every import,+which is a bit inconsistent -- but there are a lot of them. We might+thereby get some bogus unused-import warnings, but we won't crash the+type checker. Not very satisfactory really.++Note [Renamer errors]+~~~~~~~~~~~~~~~~~~~~~+It's important to wrap renamer calls in checkNoErrs, because the+renamer does not fail for out of scope variables etc. Instead it+returns a bogus term/type, so that it can report more than one error.+We don't want the type checker to see these bogus unbound variables.+-}++rnSpliceGen :: (HsSplice Name -> RnM (a, FreeVars)) -- Outside brackets, run splice+ -> (HsSplice Name -> (PendingRnSplice, a)) -- Inside brackets, make it pending+ -> HsSplice RdrName+ -> RnM (a, FreeVars)+rnSpliceGen run_splice pend_splice splice+ = addErrCtxt (spliceCtxt splice) $ do+ { stage <- getStage+ ; case stage of+ Brack pop_stage RnPendingTyped+ -> do { checkTc is_typed_splice illegalUntypedSplice+ ; (splice', fvs) <- setStage pop_stage $+ rnSplice splice+ ; let (_pending_splice, result) = pend_splice splice'+ ; return (result, fvs) }++ Brack pop_stage (RnPendingUntyped ps_var)+ -> do { checkTc (not is_typed_splice) illegalTypedSplice+ ; (splice', fvs) <- setStage pop_stage $+ rnSplice splice+ ; let (pending_splice, result) = pend_splice splice'+ ; ps <- readMutVar ps_var+ ; writeMutVar ps_var (pending_splice : ps)+ ; return (result, fvs) }++ _ -> do { (splice', fvs1) <- checkNoErrs $+ setStage (Splice splice_type) $+ rnSplice splice+ -- checkNoErrs: don't attempt to run the splice if+ -- renaming it failed; otherwise we get a cascade of+ -- errors from e.g. unbound variables+ ; (result, fvs2) <- run_splice splice'+ ; return (result, fvs1 `plusFV` fvs2) } }+ where+ is_typed_splice = isTypedSplice splice+ splice_type = if is_typed_splice+ then Typed+ else Untyped++------------------++-- | Returns the result of running a splice and the modFinalizers collected+-- during the execution.+--+-- See Note [Delaying modFinalizers in untyped splices].+runRnSplice :: UntypedSpliceFlavour+ -> (LHsExpr Id -> TcRn res)+ -> (res -> SDoc) -- How to pretty-print res+ -- Usually just ppr, but not for [Decl]+ -> HsSplice Name -- Always untyped+ -> TcRn (res, [ForeignRef (TH.Q ())])+runRnSplice flavour run_meta ppr_res splice+ = do { splice' <- getHooked runRnSpliceHook return >>= ($ splice)++ ; let the_expr = case splice' of+ HsUntypedSplice _ _ e -> e+ HsQuasiQuote _ q qs str -> mkQuasiQuoteExpr flavour q qs str+ HsTypedSplice {} -> pprPanic "runRnSplice" (ppr splice)+ HsSpliced {} -> pprPanic "runRnSplice" (ppr splice)++ -- Typecheck the expression+ ; meta_exp_ty <- tcMetaTy meta_ty_name+ ; zonked_q_expr <- tcTopSpliceExpr Untyped $+ tcPolyExpr the_expr meta_exp_ty++ -- Run the expression+ ; mod_finalizers_ref <- newTcRef []+ ; result <- setStage (RunSplice mod_finalizers_ref) $+ run_meta zonked_q_expr+ ; mod_finalizers <- readTcRef mod_finalizers_ref+ ; traceSplice (SpliceInfo { spliceDescription = what+ , spliceIsDecl = is_decl+ , spliceSource = Just the_expr+ , spliceGenerated = ppr_res result })++ ; return (result, mod_finalizers) }++ where+ meta_ty_name = case flavour of+ UntypedExpSplice -> expQTyConName+ UntypedPatSplice -> patQTyConName+ UntypedTypeSplice -> typeQTyConName+ UntypedDeclSplice -> decsQTyConName+ what = case flavour of+ UntypedExpSplice -> "expression"+ UntypedPatSplice -> "pattern"+ UntypedTypeSplice -> "type"+ UntypedDeclSplice -> "declarations"+ is_decl = case flavour of+ UntypedDeclSplice -> True+ _ -> False++------------------+makePending :: UntypedSpliceFlavour+ -> HsSplice Name+ -> PendingRnSplice+makePending flavour (HsUntypedSplice _ n e)+ = PendingRnSplice flavour n e+makePending flavour (HsQuasiQuote n quoter q_span quote)+ = PendingRnSplice flavour n (mkQuasiQuoteExpr flavour quoter q_span quote)+makePending _ splice@(HsTypedSplice {})+ = pprPanic "makePending" (ppr splice)+makePending _ splice@(HsSpliced {})+ = pprPanic "makePending" (ppr splice)++------------------+mkQuasiQuoteExpr :: UntypedSpliceFlavour -> Name -> SrcSpan -> FastString -> LHsExpr Name+-- Return the expression (quoter "...quote...")+-- which is what we must run in a quasi-quote+mkQuasiQuoteExpr flavour quoter q_span quote+ = L q_span $ HsApp (L q_span $+ HsApp (L q_span (HsVar (L q_span quote_selector)))+ quoterExpr)+ quoteExpr+ where+ quoterExpr = L q_span $! HsVar $! (L q_span quoter)+ quoteExpr = L q_span $! HsLit $! HsString NoSourceText quote+ quote_selector = case flavour of+ UntypedExpSplice -> quoteExpName+ UntypedPatSplice -> quotePatName+ UntypedTypeSplice -> quoteTypeName+ UntypedDeclSplice -> quoteDecName++---------------------+rnSplice :: HsSplice RdrName -> RnM (HsSplice Name, FreeVars)+-- Not exported...used for all+rnSplice (HsTypedSplice hasParen splice_name expr)+ = do { checkTH expr "Template Haskell typed splice"+ ; loc <- getSrcSpanM+ ; n' <- newLocalBndrRn (L loc splice_name)+ ; (expr', fvs) <- rnLExpr expr+ ; return (HsTypedSplice hasParen n' expr', fvs) }++rnSplice (HsUntypedSplice hasParen splice_name expr)+ = do { checkTH expr "Template Haskell untyped splice"+ ; loc <- getSrcSpanM+ ; n' <- newLocalBndrRn (L loc splice_name)+ ; (expr', fvs) <- rnLExpr expr+ ; return (HsUntypedSplice hasParen n' expr', fvs) }++rnSplice (HsQuasiQuote splice_name quoter q_loc quote)+ = do { checkTH quoter "Template Haskell quasi-quote"+ ; loc <- getSrcSpanM+ ; splice_name' <- newLocalBndrRn (L loc splice_name)++ -- Rename the quoter; akin to the HsVar case of rnExpr+ ; quoter' <- lookupOccRn quoter+ ; this_mod <- getModule+ ; when (nameIsLocalOrFrom this_mod quoter') $+ checkThLocalName quoter'++ ; return (HsQuasiQuote splice_name' quoter' q_loc quote, unitFV quoter') }++rnSplice splice@(HsSpliced {}) = pprPanic "rnSplice" (ppr splice)++---------------------+rnSpliceExpr :: HsSplice RdrName -> RnM (HsExpr Name, FreeVars)+rnSpliceExpr splice+ = rnSpliceGen run_expr_splice pend_expr_splice splice+ where+ pend_expr_splice :: HsSplice Name -> (PendingRnSplice, HsExpr Name)+ pend_expr_splice rn_splice+ = (makePending UntypedExpSplice rn_splice, HsSpliceE rn_splice)++ run_expr_splice :: HsSplice Name -> RnM (HsExpr Name, FreeVars)+ run_expr_splice rn_splice+ | isTypedSplice rn_splice -- Run it later, in the type checker+ = do { -- Ugh! See Note [Splices] above+ traceRn "rnSpliceExpr: typed expression splice" empty+ ; lcl_rdr <- getLocalRdrEnv+ ; gbl_rdr <- getGlobalRdrEnv+ ; let gbl_names = mkNameSet [gre_name gre | gre <- globalRdrEnvElts gbl_rdr+ , isLocalGRE gre]+ lcl_names = mkNameSet (localRdrEnvElts lcl_rdr)++ ; return (HsSpliceE rn_splice, lcl_names `plusFV` gbl_names) }++ | otherwise -- Run it here, see Note [Running splices in the Renamer]+ = do { traceRn "rnSpliceExpr: untyped expression splice" empty+ ; (rn_expr, mod_finalizers) <-+ runRnSplice UntypedExpSplice runMetaE ppr rn_splice+ ; (lexpr3, fvs) <- checkNoErrs (rnLExpr rn_expr)+ -- See Note [Delaying modFinalizers in untyped splices].+ ; return ( HsPar $ HsSpliceE+ . HsSpliced (ThModFinalizers mod_finalizers)+ . HsSplicedExpr <$>+ lexpr3+ , fvs)+ }++{- Note [Running splices in the Renamer]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Splices used to be run in the typechecker, which led to (Trac #4364). Since the+renamer must decide which expressions depend on which others, and it cannot+reliably do this for arbitrary splices, we used to conservatively say that+splices depend on all other expressions in scope. Unfortunately, this led to+the problem of cyclic type declarations seen in (Trac #4364). Instead, by+running splices in the renamer, we side-step the problem of determining+dependencies: by the time the dependency analysis happens, any splices have+already been run, and expression dependencies can be determined as usual.++However, see (Trac #9813), for an example where we would like to run splices+*after* performing dependency analysis (that is, after renaming). It would be+desirable to typecheck "non-splicy" expressions (those expressions that do not+contain splices directly or via dependence on an expression that does) before+"splicy" expressions, such that types/expressions within the same declaration+group would be available to `reify` calls, for example consider the following:++> module M where+> data D = C+> f = 1+> g = $(mapM reify ['f, 'D, ''C] ...)++Compilation of this example fails since D/C/f are not in the type environment+and thus cannot be reified as they have not been typechecked by the time the+splice is renamed and thus run.++These requirements are at odds: we do not want to run splices in the renamer as+we wish to first determine dependencies and typecheck certain expressions,+making them available to reify, but cannot accurately determine dependencies+without running splices in the renamer!++Indeed, the conclusion of (Trac #9813) was that it is not worth the complexity+to try and+ a) implement and maintain the code for renaming/typechecking non-splicy+ expressions before splicy expressions,+ b) explain to TH users which expressions are/not available to reify at any+ given point.++-}++{- Note [Delaying modFinalizers in untyped splices]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When splices run in the renamer, 'reify' does not have access to the local+type environment (Trac #11832, [1]).++For instance, in++> let x = e in $(reify (mkName "x") >>= runIO . print >> [| return () |])++'reify' cannot find @x@, because the local type environment is not yet+populated. To address this, we allow 'reify' execution to be deferred with+'addModFinalizer'.++> let x = e in $(do addModFinalizer (reify (mkName "x") >>= runIO . print)+ [| return () |]+ )++The finalizer is run with the local type environment when type checking is+complete.++Since the local type environment is not available in the renamer, we annotate+the tree at the splice point [2] with @HsSpliceE (HsSpliced finalizers e)@ where+@e@ is the result of splicing and @finalizers@ are the finalizers that have been+collected during evaluation of the splice [3]. In our example,++> HsLet+> (x = e)+> (HsSpliceE $ HsSpliced [reify (mkName "x") >>= runIO . print]+> (HsSplicedExpr $ return ())+> )++When the typechecker finds the annotation, it inserts the finalizers in the+global environment and exposes the current local environment to them [4, 5, 6].++> addModFinalizersWithLclEnv [reify (mkName "x") >>= runIO . print]++References:++[1] https://ghc.haskell.org/trac/ghc/wiki/TemplateHaskell/Reify+[2] 'rnSpliceExpr'+[3] 'TcSplice.qAddModFinalizer'+[4] 'TcExpr.tcExpr' ('HsSpliceE' ('HsSpliced' ...))+[5] 'TcHsType.tc_hs_type' ('HsSpliceTy' ('HsSpliced' ...))+[6] 'TcPat.tc_pat' ('SplicePat' ('HsSpliced' ...))++-}++----------------------+rnSpliceType :: HsSplice RdrName -> PostTc Name Kind+ -> RnM (HsType Name, FreeVars)+rnSpliceType splice k+ = rnSpliceGen run_type_splice pend_type_splice splice+ where+ pend_type_splice rn_splice+ = (makePending UntypedTypeSplice rn_splice, HsSpliceTy rn_splice k)++ run_type_splice rn_splice+ = do { traceRn "rnSpliceType: untyped type splice" empty+ ; (hs_ty2, mod_finalizers) <-+ runRnSplice UntypedTypeSplice runMetaT ppr rn_splice+ ; (hs_ty3, fvs) <- do { let doc = SpliceTypeCtx hs_ty2+ ; checkNoErrs $ rnLHsType doc hs_ty2 }+ -- checkNoErrs: see Note [Renamer errors]+ -- See Note [Delaying modFinalizers in untyped splices].+ ; return ( HsParTy $ flip HsSpliceTy k+ . HsSpliced (ThModFinalizers mod_finalizers)+ . HsSplicedTy <$>+ hs_ty3+ , fvs+ ) }+ -- Wrap the result of the splice in parens so that we don't+ -- lose the outermost location set by runQuasiQuote (#7918)++{- Note [Partial Type Splices]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Partial Type Signatures are partially supported in TH type splices: only+anonymous wild cards are allowed.++ -- ToDo: SLPJ says: I don't understand all this++Normally, named wild cards are collected before renaming a (partial) type+signature. However, TH type splices are run during renaming, i.e. after the+initial traversal, leading to out of scope errors for named wild cards. We+can't just extend the initial traversal to collect the named wild cards in TH+type splices, as we'd need to expand them, which is supposed to happen only+once, during renaming.++Similarly, the extra-constraints wild card is handled right before renaming+too, and is therefore also not supported in a TH type splice. Another reason+to forbid extra-constraints wild cards in TH type splices is that a single+signature can contain many TH type splices, whereas it mustn't contain more+than one extra-constraints wild card. Enforcing would this be hard the way+things are currently organised.++Anonymous wild cards pose no problem, because they start out without names and+are given names during renaming. These names are collected right after+renaming. The names generated for anonymous wild cards in TH type splices will+thus be collected as well.++For more details about renaming wild cards, see RnTypes.rnHsSigWcType++Note that partial type signatures are fully supported in TH declaration+splices, e.g.:++ [d| foo :: _ => _+ foo x y = x == y |]++This is because in this case, the partial type signature can be treated as a+whole signature, instead of as an arbitrary type.++-}+++----------------------+-- | Rename a splice pattern. See Note [rnSplicePat]+rnSplicePat :: HsSplice RdrName -> RnM ( Either (Pat RdrName) (Pat Name)+ , FreeVars)+rnSplicePat splice+ = rnSpliceGen run_pat_splice pend_pat_splice splice+ where+ pend_pat_splice rn_splice+ = (makePending UntypedPatSplice rn_splice, Right (SplicePat rn_splice))++ run_pat_splice rn_splice+ = do { traceRn "rnSplicePat: untyped pattern splice" empty+ ; (pat, mod_finalizers) <-+ runRnSplice UntypedPatSplice runMetaP ppr rn_splice+ -- See Note [Delaying modFinalizers in untyped splices].+ ; return ( Left $ ParPat $ SplicePat+ . HsSpliced (ThModFinalizers mod_finalizers)+ . HsSplicedPat <$>+ pat+ , emptyFVs+ ) }+ -- Wrap the result of the quasi-quoter in parens so that we don't+ -- lose the outermost location set by runQuasiQuote (#7918)++----------------------+rnSpliceDecl :: SpliceDecl RdrName -> RnM (SpliceDecl Name, FreeVars)+rnSpliceDecl (SpliceDecl (L loc splice) flg)+ = rnSpliceGen run_decl_splice pend_decl_splice splice+ where+ pend_decl_splice rn_splice+ = (makePending UntypedDeclSplice rn_splice, SpliceDecl (L loc rn_splice) flg)++ run_decl_splice rn_splice = pprPanic "rnSpliceDecl" (ppr rn_splice)++rnTopSpliceDecls :: HsSplice RdrName -> RnM ([LHsDecl RdrName], FreeVars)+-- Declaration splice at the very top level of the module+rnTopSpliceDecls splice+ = do { (rn_splice, fvs) <- checkNoErrs $+ setStage (Splice Untyped) $+ rnSplice splice+ -- As always, be sure to checkNoErrs above lest we end up with+ -- holes making it to typechecking, hence #12584.+ ; traceRn "rnTopSpliceDecls: untyped declaration splice" empty+ ; (decls, mod_finalizers) <-+ runRnSplice UntypedDeclSplice runMetaD ppr_decls rn_splice+ ; add_mod_finalizers_now mod_finalizers+ ; return (decls,fvs) }+ where+ ppr_decls :: [LHsDecl RdrName] -> SDoc+ ppr_decls ds = vcat (map ppr ds)++ -- Adds finalizers to the global environment instead of delaying them+ -- to the type checker.+ --+ -- Declaration splices do not have an interesting local environment so+ -- there is no point in delaying them.+ --+ -- See Note [Delaying modFinalizers in untyped splices].+ add_mod_finalizers_now :: [ForeignRef (TH.Q ())] -> TcRn ()+ add_mod_finalizers_now [] = return ()+ add_mod_finalizers_now mod_finalizers = do+ th_modfinalizers_var <- fmap tcg_th_modfinalizers getGblEnv+ updTcRef th_modfinalizers_var $ \fins ->+ runRemoteModFinalizers (ThModFinalizers mod_finalizers) : fins+++{-+Note [rnSplicePat]+~~~~~~~~~~~~~~~~~~+Renaming a pattern splice is a bit tricky, because we need the variables+bound in the pattern to be in scope in the RHS of the pattern. This scope+management is effectively done by using continuation-passing style in+RnPat, through the CpsRn monad. We don't wish to be in that monad here+(it would create import cycles and generally conflict with renaming other+splices), so we really want to return a (Pat RdrName) -- the result of+running the splice -- which can then be further renamed in RnPat, in+the CpsRn monad.++The problem is that if we're renaming a splice within a bracket, we+*don't* want to run the splice now. We really do just want to rename+it to an HsSplice Name. Of course, then we can't know what variables+are bound within the splice. So we accept any unbound variables and+rename them again when the bracket is spliced in. If a variable is brought+into scope by a pattern splice all is fine. If it is not then an error is+reported.++In any case, when we're done in rnSplicePat, we'll either have a+Pat RdrName (the result of running a top-level splice) or a Pat Name+(the renamed nested splice). Thus, the awkward return type of+rnSplicePat.+-}++spliceCtxt :: HsSplice RdrName -> SDoc+spliceCtxt splice+ = hang (text "In the" <+> what) 2 (ppr splice)+ where+ what = case splice of+ HsUntypedSplice {} -> text "untyped splice:"+ HsTypedSplice {} -> text "typed splice:"+ HsQuasiQuote {} -> text "quasi-quotation:"+ HsSpliced {} -> text "spliced expression:"++-- | The splice data to be logged+data SpliceInfo+ = SpliceInfo+ { spliceDescription :: String+ , spliceSource :: Maybe (LHsExpr Name) -- Nothing <=> top-level decls+ -- added by addTopDecls+ , spliceIsDecl :: Bool -- True <=> put the generate code in a file+ -- when -dth-dec-file is on+ , spliceGenerated :: SDoc+ }+ -- Note that 'spliceSource' is *renamed* but not *typechecked*+ -- Reason (a) less typechecking crap+ -- (b) data constructors after type checking have been+ -- changed to their *wrappers*, and that makes them+ -- print always fully qualified++-- | outputs splice information for 2 flags which have different output formats:+-- `-ddump-splices` and `-dth-dec-file`+traceSplice :: SpliceInfo -> TcM ()+traceSplice (SpliceInfo { spliceDescription = sd, spliceSource = mb_src+ , spliceGenerated = gen, spliceIsDecl = is_decl })+ = do { loc <- case mb_src of+ Nothing -> getSrcSpanM+ Just (L loc _) -> return loc+ ; traceOptTcRn Opt_D_dump_splices (spliceDebugDoc loc)++ ; when is_decl $ -- Raw material for -dth-dec-file+ do { dflags <- getDynFlags+ ; liftIO $ dumpIfSet_dyn_printer alwaysQualify dflags Opt_D_th_dec_file+ (spliceCodeDoc loc) } }+ where+ -- `-ddump-splices`+ spliceDebugDoc :: SrcSpan -> SDoc+ spliceDebugDoc loc+ = let code = case mb_src of+ Nothing -> ending+ Just e -> nest 2 (ppr e) : ending+ ending = [ text "======>", nest 2 gen ]+ in hang (ppr loc <> colon <+> text "Splicing" <+> text sd)+ 2 (sep code)++ -- `-dth-dec-file`+ spliceCodeDoc :: SrcSpan -> SDoc+ spliceCodeDoc loc+ = vcat [ text "--" <+> ppr loc <> colon <+> text "Splicing" <+> text sd+ , gen ]++illegalTypedSplice :: SDoc+illegalTypedSplice = text "Typed splices may not appear in untyped brackets"++illegalUntypedSplice :: SDoc+illegalUntypedSplice = text "Untyped splices may not appear in typed brackets"++checkThLocalName :: Name -> RnM ()+checkThLocalName name+ | isUnboundName name -- Do not report two errors for+ = return () -- $(not_in_scope args)++ | otherwise+ = do { traceRn "checkThLocalName" (ppr name)+ ; mb_local_use <- getStageAndBindLevel name+ ; case mb_local_use of {+ Nothing -> return () ; -- Not a locally-bound thing+ Just (top_lvl, bind_lvl, use_stage) ->+ do { let use_lvl = thLevel use_stage+ ; checkWellStaged (quotes (ppr name)) bind_lvl use_lvl+ ; traceRn "checkThLocalName" (ppr name <+> ppr bind_lvl+ <+> ppr use_stage+ <+> ppr use_lvl)+ ; checkCrossStageLifting top_lvl bind_lvl use_stage use_lvl name } } }++--------------------------------------+checkCrossStageLifting :: TopLevelFlag -> ThLevel -> ThStage -> ThLevel+ -> Name -> TcM ()+-- We are inside brackets, and (use_lvl > bind_lvl)+-- Now we must check whether there's a cross-stage lift to do+-- Examples \x -> [| x |]+-- [| map |]+--+-- This code is similar to checkCrossStageLifting in TcExpr, but+-- this is only run on *untyped* brackets.++checkCrossStageLifting top_lvl bind_lvl use_stage use_lvl name+ | Brack _ (RnPendingUntyped ps_var) <- use_stage -- Only for untyped brackets+ , use_lvl > bind_lvl -- Cross-stage condition+ = check_cross_stage_lifting top_lvl name ps_var+ | otherwise+ = return ()++check_cross_stage_lifting :: TopLevelFlag -> Name -> TcRef [PendingRnSplice] -> TcM ()+check_cross_stage_lifting top_lvl name ps_var+ | isTopLevel top_lvl+ -- Top-level identifiers in this module,+ -- (which have External Names)+ -- are just like the imported case:+ -- no need for the 'lifting' treatment+ -- E.g. this is fine:+ -- f x = x+ -- g y = [| f 3 |]+ = when (isExternalName name) (keepAlive name)+ -- See Note [Keeping things alive for Template Haskell]++ | otherwise+ = -- Nested identifiers, such as 'x' in+ -- E.g. \x -> [| h x |]+ -- We must behave as if the reference to x was+ -- h $(lift x)+ -- We use 'x' itself as the SplicePointName, used by+ -- the desugarer to stitch it all back together.+ -- If 'x' occurs many times we may get many identical+ -- bindings of the same SplicePointName, but that doesn't+ -- matter, although it's a mite untidy.+ do { traceRn "checkCrossStageLifting" (ppr name)++ -- Construct the (lift x) expression+ ; let lift_expr = nlHsApp (nlHsVar liftName) (nlHsVar name)+ pend_splice = PendingRnSplice UntypedExpSplice name lift_expr++ -- Update the pending splices+ ; ps <- readMutVar ps_var+ ; writeMutVar ps_var (pend_splice : ps) }++{-+Note [Keeping things alive for Template Haskell]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f x = x+1+ g y = [| f 3 |]++Here 'f' is referred to from inside the bracket, which turns into data+and mentions only f's *name*, not 'f' itself. So we need some other+way to keep 'f' alive, lest it get dropped as dead code. That's what+keepAlive does. It puts it in the keep-alive set, which subsequently+ensures that 'f' stays as a top level binding.++This must be done by the renamer, not the type checker (as of old),+because the type checker doesn't typecheck the body of untyped+brackets (Trac #8540).++A thing can have a bind_lvl of outerLevel, but have an internal name:+ foo = [d| op = 3+ bop = op + 1 |]+Here the bind_lvl of 'op' is (bogusly) outerLevel, even though it is+bound inside a bracket. That is because we don't even even record+binding levels for top-level things; the binding levels are in the+LocalRdrEnv.++So the occurrence of 'op' in the rhs of 'bop' looks a bit like a+cross-stage thing, but it isn't really. And in fact we never need+to do anything here for top-level bound things, so all is fine, if+a bit hacky.++For these chaps (which have Internal Names) we don't want to put+them in the keep-alive set.++Note [Quoting names]+~~~~~~~~~~~~~~~~~~~~+A quoted name 'n is a bit like a quoted expression [| n |], except that we+have no cross-stage lifting (c.f. TcExpr.thBrackId). So, after incrementing+the use-level to account for the brackets, the cases are:++ bind > use Error+ bind = use+1 OK+ bind < use+ Imported things OK+ Top-level things OK+ Non-top-level Error++where 'use' is the binding level of the 'n quote. (So inside the implied+bracket the level would be use+1.)++Examples:++ f 'map -- OK; also for top-level defns of this module++ \x. f 'x -- Not ok (bind = 1, use = 1)+ -- (whereas \x. f [| x |] might have been ok, by+ -- cross-stage lifting++ \y. [| \x. $(f 'y) |] -- Not ok (bind =1, use = 1)++ [| \x. $(f 'x) |] -- OK (bind = 2, use = 1)+-}
+ rename/RnSplice.hs-boot view
@@ -0,0 +1,17 @@+module RnSplice where++import HsSyn+import TcRnMonad+import RdrName+import Name+import NameSet+import Kind+++rnSpliceType :: HsSplice RdrName -> PostTc Name Kind+ -> RnM (HsType Name, FreeVars)+rnSplicePat :: HsSplice RdrName -> RnM ( Either (Pat RdrName) (Pat Name)+ , FreeVars )+rnSpliceDecl :: SpliceDecl RdrName -> RnM (SpliceDecl Name, FreeVars)++rnTopSpliceDecls :: HsSplice RdrName -> RnM ([LHsDecl RdrName], FreeVars)
+ rename/RnTypes.hs view
@@ -0,0 +1,1741 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[RnSource]{Main pass of renamer}+-}++{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP #-}++module RnTypes (+ -- Type related stuff+ rnHsType, rnLHsType, rnLHsTypes, rnContext,+ rnHsKind, rnLHsKind,+ rnHsSigType, rnHsWcType,+ rnHsSigWcType, rnHsSigWcTypeScoped,+ rnLHsInstType,+ newTyVarNameRn, collectAnonWildCards,+ rnConDeclFields,+ rnLTyVar,++ -- Precence related stuff+ mkOpAppRn, mkNegAppRn, mkOpFormRn, mkConOpPatRn,+ checkPrecMatch, checkSectionPrec,++ -- Binding related stuff+ bindLHsTyVarBndr,+ bindSigTyVarsFV, bindHsQTyVars, bindLRdrNames,+ extractFilteredRdrTyVars,+ extractHsTyRdrTyVars, extractHsTysRdrTyVars,+ extractHsTysRdrTyVarsDups, rmDupsInRdrTyVars,+ extractRdrKindSigVars, extractDataDefnKindVars,+ freeKiTyVarsAllVars, freeKiTyVarsKindVars, freeKiTyVarsTypeVars+ ) where++import {-# SOURCE #-} RnSplice( rnSpliceType )++import DynFlags+import HsSyn+import RnHsDoc ( rnLHsDoc, rnMbLHsDoc )+import RnEnv+import TcRnMonad+import RdrName+import PrelNames+import TysPrim ( funTyConName )+import TysWiredIn ( starKindTyConName, unicodeStarKindTyConName )+import Name+import SrcLoc+import NameSet+import FieldLabel++import Util+import BasicTypes ( compareFixity, funTyFixity, negateFixity,+ Fixity(..), FixityDirection(..), LexicalFixity(..) )+import Outputable+import FastString+import Maybes+import qualified GHC.LanguageExtensions as LangExt++import Data.List ( nubBy, partition )+import Control.Monad ( unless, when )++#include "HsVersions.h"++{-+These type renamers are in a separate module, rather than in (say) RnSource,+to break several loop.++*********************************************************+* *+ HsSigWcType (i.e with wildcards)+* *+*********************************************************+-}++rnHsSigWcType :: HsDocContext -> LHsSigWcType RdrName+ -> RnM (LHsSigWcType Name, FreeVars)+rnHsSigWcType doc sig_ty+ = rn_hs_sig_wc_type True doc sig_ty $ \sig_ty' ->+ return (sig_ty', emptyFVs)++rnHsSigWcTypeScoped :: HsDocContext -> LHsSigWcType RdrName+ -> (LHsSigWcType Name -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+-- Used for+-- - Signatures on binders in a RULE+-- - Pattern type signatures+-- Wildcards are allowed+-- type signatures on binders only allowed with ScopedTypeVariables+rnHsSigWcTypeScoped ctx sig_ty thing_inside+ = do { ty_sig_okay <- xoptM LangExt.ScopedTypeVariables+ ; checkErr ty_sig_okay (unexpectedTypeSigErr sig_ty)+ ; rn_hs_sig_wc_type False ctx sig_ty thing_inside+ }+ -- False: for pattern type sigs and rules we /do/ want+ -- to bring those type variables into scope+ -- e.g \ (x :: forall a. a-> b) -> e+ -- Here we do bring 'b' into scope++rn_hs_sig_wc_type :: Bool -- see rnImplicitBndrs+ -> HsDocContext+ -> LHsSigWcType RdrName+ -> (LHsSigWcType Name -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+-- rn_hs_sig_wc_type is used for source-language type signatures+rn_hs_sig_wc_type no_implicit_if_forall ctxt+ (HsWC { hswc_body = HsIB { hsib_body = hs_ty }})+ thing_inside+ = do { free_vars <- extractFilteredRdrTyVars hs_ty+ ; (tv_rdrs, nwc_rdrs) <- partition_nwcs free_vars+ ; rnImplicitBndrs no_implicit_if_forall tv_rdrs hs_ty $ \ vars ->+ do { (wcs, hs_ty', fvs1) <- rnWcBody ctxt nwc_rdrs hs_ty+ ; let sig_ty' = HsWC { hswc_wcs = wcs, hswc_body = ib_ty' }+ ib_ty' = mk_implicit_bndrs vars hs_ty' fvs1+ ; (res, fvs2) <- thing_inside sig_ty'+ ; return (res, fvs1 `plusFV` fvs2) } }++rnHsWcType :: HsDocContext -> LHsWcType RdrName -> RnM (LHsWcType Name, FreeVars)+rnHsWcType ctxt (HsWC { hswc_body = hs_ty })+ = do { free_vars <- extractFilteredRdrTyVars hs_ty+ ; (_, nwc_rdrs) <- partition_nwcs free_vars+ ; (wcs, hs_ty', fvs) <- rnWcBody ctxt nwc_rdrs hs_ty+ ; let sig_ty' = HsWC { hswc_wcs = wcs, hswc_body = hs_ty' }+ ; return (sig_ty', fvs) }++rnWcBody :: HsDocContext -> [Located RdrName] -> LHsType RdrName+ -> RnM ([Name], LHsType Name, FreeVars)+rnWcBody ctxt nwc_rdrs hs_ty+ = do { nwcs <- mapM newLocalBndrRn nwc_rdrs+ ; let env = RTKE { rtke_level = TypeLevel+ , rtke_what = RnTypeBody+ , rtke_nwcs = mkNameSet nwcs+ , rtke_ctxt = ctxt }+ ; (hs_ty', fvs) <- bindLocalNamesFV nwcs $+ rn_lty env hs_ty+ ; let awcs = collectAnonWildCards hs_ty'+ ; return (nwcs ++ awcs, hs_ty', fvs) }+ where+ rn_lty env (L loc hs_ty)+ = setSrcSpan loc $+ do { (hs_ty', fvs) <- rn_ty env hs_ty+ ; return (L loc hs_ty', fvs) }++ rn_ty :: RnTyKiEnv -> HsType RdrName -> RnM (HsType Name, FreeVars)+ -- A lot of faff just to allow the extra-constraints wildcard to appear+ rn_ty env hs_ty@(HsForAllTy { hst_bndrs = tvs, hst_body = hs_body })+ = bindLHsTyVarBndrs (rtke_ctxt env) (Just $ inTypeDoc hs_ty)+ Nothing [] tvs $ \ _ tvs' _ _ ->+ do { (hs_body', fvs) <- rn_lty env hs_body+ ; return (HsForAllTy { hst_bndrs = tvs', hst_body = hs_body' }, fvs) }++ rn_ty env (HsQualTy { hst_ctxt = L cx hs_ctxt, hst_body = hs_ty })+ | Just (hs_ctxt1, hs_ctxt_last) <- snocView hs_ctxt+ , L lx (HsWildCardTy wc) <- ignoreParens hs_ctxt_last+ = do { (hs_ctxt1', fvs1) <- mapFvRn (rn_top_constraint env) hs_ctxt1+ ; wc' <- setSrcSpan lx $+ do { checkExtraConstraintWildCard env wc+ ; rnAnonWildCard wc }+ ; let hs_ctxt' = hs_ctxt1' ++ [L lx (HsWildCardTy wc')]+ ; (hs_ty', fvs2) <- rnLHsTyKi env hs_ty+ ; return (HsQualTy { hst_ctxt = L cx hs_ctxt', hst_body = hs_ty' }+ , fvs1 `plusFV` fvs2) }++ | otherwise+ = do { (hs_ctxt', fvs1) <- mapFvRn (rn_top_constraint env) hs_ctxt+ ; (hs_ty', fvs2) <- rnLHsTyKi env hs_ty+ ; return (HsQualTy { hst_ctxt = L cx hs_ctxt', hst_body = hs_ty' }+ , fvs1 `plusFV` fvs2) }++ rn_ty env hs_ty = rnHsTyKi env hs_ty++ rn_top_constraint env = rnLHsTyKi (env { rtke_what = RnTopConstraint })+++checkExtraConstraintWildCard :: RnTyKiEnv -> HsWildCardInfo RdrName+ -> RnM ()+-- Rename the extra-constraint spot in a type signature+-- (blah, _) => type+-- Check that extra-constraints are allowed at all, and+-- if so that it's an anonymous wildcard+checkExtraConstraintWildCard env wc+ = checkWildCard env mb_bad+ where+ mb_bad | not (extraConstraintWildCardsAllowed env)+ = Just (text "Extra-constraint wildcard" <+> quotes (ppr wc)+ <+> text "not allowed")+ | otherwise+ = Nothing++extraConstraintWildCardsAllowed :: RnTyKiEnv -> Bool+extraConstraintWildCardsAllowed env+ = case rtke_ctxt env of+ TypeSigCtx {} -> True+ ExprWithTySigCtx {} -> True+ _ -> False++-- | Finds free type and kind variables in a type,+-- without duplicates, and+-- without variables that are already in scope in LocalRdrEnv+-- NB: this includes named wildcards, which look like perfectly+-- ordinary type variables at this point+extractFilteredRdrTyVars :: LHsType RdrName -> RnM FreeKiTyVars+extractFilteredRdrTyVars hs_ty+ = do { rdr_env <- getLocalRdrEnv+ ; filterInScope rdr_env <$> extractHsTyRdrTyVars hs_ty }++-- | When the NamedWildCards extension is enabled, partition_nwcs+-- removes type variables that start with an underscore from the+-- FreeKiTyVars in the argument and returns them in a separate list.+-- When the extension is disabled, the function returns the argument+-- and empty list. See Note [Renaming named wild cards]+partition_nwcs :: FreeKiTyVars -> RnM (FreeKiTyVars, [Located RdrName])+partition_nwcs free_vars@(FKTV { fktv_tys = tys })+ = do { wildcards_enabled <- fmap (xopt LangExt.NamedWildCards) getDynFlags+ ; let (nwcs, no_nwcs) | wildcards_enabled = partition is_wildcard tys+ | otherwise = ([], tys)+ free_vars' = free_vars { fktv_tys = no_nwcs }+ ; return (free_vars', nwcs) }+ where+ is_wildcard :: Located RdrName -> Bool+ is_wildcard rdr = startsWithUnderscore (rdrNameOcc (unLoc rdr))++{- Note [Renaming named wild cards]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Identifiers starting with an underscore are always parsed as type variables.+It is only here in the renamer that we give the special treatment.+See Note [The wildcard story for types] in HsTypes.++It's easy! When we collect the implicitly bound type variables, ready+to bring them into scope, and NamedWildCards is on, we partition the+variables into the ones that start with an underscore (the named+wildcards) and the rest. Then we just add them to the hswc_wcs field+of the HsWildCardBndrs structure, and we are done.+++*********************************************************+* *+ HsSigtype (i.e. no wildcards)+* *+****************************************************** -}++rnHsSigType :: HsDocContext -> LHsSigType RdrName+ -> RnM (LHsSigType Name, FreeVars)+-- Used for source-language type signatures+-- that cannot have wildcards+rnHsSigType ctx (HsIB { hsib_body = hs_ty })+ = do { vars <- extractFilteredRdrTyVars hs_ty+ ; rnImplicitBndrs True vars hs_ty $ \ vars ->+ do { (body', fvs) <- rnLHsType ctx hs_ty+ ; return ( mk_implicit_bndrs vars body' fvs, fvs ) } }++rnImplicitBndrs :: Bool -- True <=> no implicit quantification+ -- if type is headed by a forall+ -- E.g. f :: forall a. a->b+ -- Do not quantify over 'b' too.+ -> FreeKiTyVars+ -> LHsType RdrName+ -> ([Name] -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+rnImplicitBndrs no_implicit_if_forall free_vars hs_ty@(L loc _) thing_inside+ = do { let real_tv_rdrs -- Implicit quantification only if+ -- there is no explicit forall+ | no_implicit_if_forall+ , L _ (HsForAllTy {}) <- hs_ty = []+ | otherwise = freeKiTyVarsTypeVars free_vars+ real_rdrs = freeKiTyVarsKindVars free_vars ++ real_tv_rdrs+ ; traceRn "rnSigType" (ppr hs_ty $$ ppr free_vars $$+ ppr real_rdrs)++ ; traceRn "" (text "rnSigType2" <+> ppr hs_ty $$ ppr free_vars $$+ ppr real_rdrs)+ ; vars <- mapM (newLocalBndrRn . L loc . unLoc) real_rdrs+ ; bindLocalNamesFV vars $+ thing_inside vars }++rnLHsInstType :: SDoc -> LHsSigType RdrName -> RnM (LHsSigType Name, FreeVars)+-- Rename the type in an instance or standalone deriving decl+-- The 'doc_str' is "an instance declaration" or "a VECTORISE pragma"+rnLHsInstType doc_str inst_ty+ | Just cls <- getLHsInstDeclClass_maybe inst_ty+ , isTcOcc (rdrNameOcc (unLoc cls))+ -- The guards check that the instance type looks like+ -- blah => C ty1 .. tyn+ = do { let full_doc = doc_str <+> text "for" <+> quotes (ppr cls)+ ; rnHsSigType (GenericCtx full_doc) inst_ty }++ | otherwise -- The instance is malformed, but we'd still like+ -- to make progress rather than failing outright, so+ -- we report more errors. So we rename it anyway.+ = do { addErrAt (getLoc (hsSigType inst_ty)) $+ text "Malformed instance:" <+> ppr inst_ty+ ; rnHsSigType (GenericCtx doc_str) inst_ty }++mk_implicit_bndrs :: [Name] -- implicitly bound+ -> a -- payload+ -> FreeVars -- FreeVars of payload+ -> HsImplicitBndrs Name a+mk_implicit_bndrs vars body fvs+ = HsIB { hsib_vars = vars+ , hsib_body = body+ , hsib_closed = nameSetAll (not . isTyVarName) (vars `delFVs` fvs) }+++{- ******************************************************+* *+ LHsType and HsType+* *+****************************************************** -}++{-+rnHsType is here because we call it from loadInstDecl, and I didn't+want a gratuitous knot.++Note [Context quantification]+-----------------------------+Variables in type signatures are implicitly quantified+when (1) they are in a type signature not beginning+with "forall" or (2) in any qualified type T => R.+We are phasing out (2) since it leads to inconsistencies+(Trac #4426):++data A = A (a -> a) is an error+data A = A (Eq a => a -> a) binds "a"+data A = A (Eq a => a -> b) binds "a" and "b"+data A = A (() => a -> b) binds "a" and "b"+f :: forall a. a -> b is an error+f :: forall a. () => a -> b is an error+f :: forall a. a -> (() => b) binds "a" and "b"++This situation is now considered to be an error. See rnHsTyKi for case+HsForAllTy Qualified.++Note [Dealing with *]+~~~~~~~~~~~~~~~~~~~~~+As a legacy from the days when types and kinds were different, we use+the type * to mean what we now call GHC.Types.Type. The problem is that+* should associate just like an identifier, *not* a symbol.+Running example: the user has written++ T (Int, Bool) b + c * d++At this point, we have a bunch of stretches of types++ [[T, (Int, Bool), b], [c], [d]]++these are the [[LHsType Name]] and a bunch of operators++ [GHC.TypeLits.+, GHC.Types.*]++Note that the * is GHC.Types.*. So, we want to rearrange to have++ [[T, (Int, Bool), b], [c, *, d]]++and++ [GHC.TypeLits.+]++as our lists. We can then do normal fixity resolution on these. The fixities+must come along for the ride just so that the list stays in sync with the+operators.++Note [QualTy in kinds]+~~~~~~~~~~~~~~~~~~~~~~+I was wondering whether QualTy could occur only at TypeLevel. But no,+we can have a qualified type in a kind too. Here is an example:++ type family F a where+ F Bool = Nat+ F Nat = Type++ type family G a where+ G Type = Type -> Type+ G () = Nat++ data X :: forall k1 k2. (F k1 ~ G k2) => k1 -> k2 -> Type where+ MkX :: X 'True '()++See that k1 becomes Bool and k2 becomes (), so the equality is+satisfied. If I write MkX :: X 'True 'False, compilation fails with a+suitable message:++ MkX :: X 'True '()+ • Couldn't match kind ‘G Bool’ with ‘Nat’+ Expected kind: G Bool+ Actual kind: F Bool++However: in a kind, the constraints in the QualTy must all be+equalities; or at least, any kinds with a class constraint are+uninhabited.+-}++data RnTyKiEnv+ = RTKE { rtke_ctxt :: HsDocContext+ , rtke_level :: TypeOrKind -- Am I renaming a type or a kind?+ , rtke_what :: RnTyKiWhat -- And within that what am I renaming?+ , rtke_nwcs :: NameSet -- These are the in-scope named wildcards+ }++data RnTyKiWhat = RnTypeBody+ | RnTopConstraint -- Top-level context of HsSigWcTypes+ | RnConstraint -- All other constraints++instance Outputable RnTyKiEnv where+ ppr (RTKE { rtke_level = lev, rtke_what = what+ , rtke_nwcs = wcs, rtke_ctxt = ctxt })+ = text "RTKE"+ <+> braces (sep [ ppr lev, ppr what, ppr wcs+ , pprHsDocContext ctxt ])++instance Outputable RnTyKiWhat where+ ppr RnTypeBody = text "RnTypeBody"+ ppr RnTopConstraint = text "RnTopConstraint"+ ppr RnConstraint = text "RnConstraint"++mkTyKiEnv :: HsDocContext -> TypeOrKind -> RnTyKiWhat -> RnTyKiEnv+mkTyKiEnv cxt level what+ = RTKE { rtke_level = level, rtke_nwcs = emptyNameSet+ , rtke_what = what, rtke_ctxt = cxt }++isRnKindLevel :: RnTyKiEnv -> Bool+isRnKindLevel (RTKE { rtke_level = KindLevel }) = True+isRnKindLevel _ = False++--------------+rnLHsType :: HsDocContext -> LHsType RdrName -> RnM (LHsType Name, FreeVars)+rnLHsType ctxt ty = rnLHsTyKi (mkTyKiEnv ctxt TypeLevel RnTypeBody) ty++rnLHsTypes :: HsDocContext -> [LHsType RdrName] -> RnM ([LHsType Name], FreeVars)+rnLHsTypes doc tys = mapFvRn (rnLHsType doc) tys++rnHsType :: HsDocContext -> HsType RdrName -> RnM (HsType Name, FreeVars)+rnHsType ctxt ty = rnHsTyKi (mkTyKiEnv ctxt TypeLevel RnTypeBody) ty++rnLHsKind :: HsDocContext -> LHsKind RdrName -> RnM (LHsKind Name, FreeVars)+rnLHsKind ctxt kind = rnLHsTyKi (mkTyKiEnv ctxt KindLevel RnTypeBody) kind++rnHsKind :: HsDocContext -> HsKind RdrName -> RnM (HsKind Name, FreeVars)+rnHsKind ctxt kind = rnHsTyKi (mkTyKiEnv ctxt KindLevel RnTypeBody) kind++--------------+rnTyKiContext :: RnTyKiEnv -> LHsContext RdrName -> RnM (LHsContext Name, FreeVars)+rnTyKiContext env (L loc cxt)+ = do { traceRn "rncontext" (ppr cxt)+ ; let env' = env { rtke_what = RnConstraint }+ ; (cxt', fvs) <- mapFvRn (rnLHsTyKi env') cxt+ ; return (L loc cxt', fvs) }++rnContext :: HsDocContext -> LHsContext RdrName -> RnM (LHsContext Name, FreeVars)+rnContext doc theta = rnTyKiContext (mkTyKiEnv doc TypeLevel RnConstraint) theta++--------------+rnLHsTyKi :: RnTyKiEnv -> LHsType RdrName -> RnM (LHsType Name, FreeVars)+rnLHsTyKi env (L loc ty)+ = setSrcSpan loc $+ do { (ty', fvs) <- rnHsTyKi env ty+ ; return (L loc ty', fvs) }++rnHsTyKi :: RnTyKiEnv -> HsType RdrName -> RnM (HsType Name, FreeVars)++rnHsTyKi env ty@(HsForAllTy { hst_bndrs = tyvars, hst_body = tau })+ = do { checkTypeInType env ty+ ; bindLHsTyVarBndrs (rtke_ctxt env) (Just $ inTypeDoc ty)+ Nothing [] tyvars $ \ _ tyvars' _ _ ->+ do { (tau', fvs) <- rnLHsTyKi env tau+ ; return ( HsForAllTy { hst_bndrs = tyvars', hst_body = tau' }+ , fvs) } }++rnHsTyKi env ty@(HsQualTy { hst_ctxt = lctxt, hst_body = tau })+ = do { checkTypeInType env ty -- See Note [QualTy in kinds]+ ; (ctxt', fvs1) <- rnTyKiContext env lctxt+ ; (tau', fvs2) <- rnLHsTyKi env tau+ ; return (HsQualTy { hst_ctxt = ctxt', hst_body = tau' }+ , fvs1 `plusFV` fvs2) }++rnHsTyKi env (HsTyVar ip (L loc rdr_name))+ = do { name <- rnTyVar env rdr_name+ ; return (HsTyVar ip (L loc name), unitFV name) }++rnHsTyKi env ty@(HsOpTy ty1 l_op ty2)+ = setSrcSpan (getLoc l_op) $+ do { (l_op', fvs1) <- rnHsTyOp env ty l_op+ ; fix <- lookupTyFixityRn l_op'+ ; (ty1', fvs2) <- rnLHsTyKi env ty1+ ; (ty2', fvs3) <- rnLHsTyKi env ty2+ ; res_ty <- mkHsOpTyRn (\t1 t2 -> HsOpTy t1 l_op' t2)+ (unLoc l_op') fix ty1' ty2'+ ; return (res_ty, plusFVs [fvs1, fvs2, fvs3]) }++rnHsTyKi env (HsParTy ty)+ = do { (ty', fvs) <- rnLHsTyKi env ty+ ; return (HsParTy ty', fvs) }++rnHsTyKi env (HsBangTy b ty)+ = do { (ty', fvs) <- rnLHsTyKi env ty+ ; return (HsBangTy b ty', fvs) }++rnHsTyKi env ty@(HsRecTy flds)+ = do { let ctxt = rtke_ctxt env+ ; fls <- get_fields ctxt+ ; (flds', fvs) <- rnConDeclFields ctxt fls flds+ ; return (HsRecTy flds', fvs) }+ where+ get_fields (ConDeclCtx names)+ = concatMapM (lookupConstructorFields . unLoc) names+ get_fields _+ = do { addErr (hang (text "Record syntax is illegal here:")+ 2 (ppr ty))+ ; return [] }++rnHsTyKi env (HsFunTy ty1 ty2)+ = do { (ty1', fvs1) <- rnLHsTyKi env ty1+ -- Might find a for-all as the arg of a function type+ ; (ty2', fvs2) <- rnLHsTyKi env ty2+ -- Or as the result. This happens when reading Prelude.hi+ -- when we find return :: forall m. Monad m -> forall a. a -> m a++ -- Check for fixity rearrangements+ ; res_ty <- mkHsOpTyRn HsFunTy funTyConName funTyFixity ty1' ty2'+ ; return (res_ty, fvs1 `plusFV` fvs2) }++rnHsTyKi env listTy@(HsListTy ty)+ = do { data_kinds <- xoptM LangExt.DataKinds+ ; when (not data_kinds && isRnKindLevel env)+ (addErr (dataKindsErr env listTy))+ ; (ty', fvs) <- rnLHsTyKi env ty+ ; return (HsListTy ty', fvs) }++rnHsTyKi env t@(HsKindSig ty k)+ = do { checkTypeInType env t+ ; kind_sigs_ok <- xoptM LangExt.KindSignatures+ ; unless kind_sigs_ok (badKindSigErr (rtke_ctxt env) ty)+ ; (ty', fvs1) <- rnLHsTyKi env ty+ ; (k', fvs2) <- rnLHsTyKi (env { rtke_level = KindLevel }) k+ ; return (HsKindSig ty' k', fvs1 `plusFV` fvs2) }++rnHsTyKi env t@(HsPArrTy ty)+ = do { notInKinds env t+ ; (ty', fvs) <- rnLHsTyKi env ty+ ; return (HsPArrTy ty', fvs) }++-- Unboxed tuples are allowed to have poly-typed arguments. These+-- sometimes crop up as a result of CPR worker-wrappering dictionaries.+rnHsTyKi env tupleTy@(HsTupleTy tup_con tys)+ = do { data_kinds <- xoptM LangExt.DataKinds+ ; when (not data_kinds && isRnKindLevel env)+ (addErr (dataKindsErr env tupleTy))+ ; (tys', fvs) <- mapFvRn (rnLHsTyKi env) tys+ ; return (HsTupleTy tup_con tys', fvs) }++rnHsTyKi env sumTy@(HsSumTy tys)+ = do { data_kinds <- xoptM LangExt.DataKinds+ ; when (not data_kinds && isRnKindLevel env)+ (addErr (dataKindsErr env sumTy))+ ; (tys', fvs) <- mapFvRn (rnLHsTyKi env) tys+ ; return (HsSumTy tys', fvs) }++-- Ensure that a type-level integer is nonnegative (#8306, #8412)+rnHsTyKi env tyLit@(HsTyLit t)+ = do { data_kinds <- xoptM LangExt.DataKinds+ ; unless data_kinds (addErr (dataKindsErr env tyLit))+ ; when (negLit t) (addErr negLitErr)+ ; checkTypeInType env tyLit+ ; return (HsTyLit t, emptyFVs) }+ where+ negLit (HsStrTy _ _) = False+ negLit (HsNumTy _ i) = i < 0+ negLitErr = text "Illegal literal in type (type literals must not be negative):" <+> ppr tyLit++rnHsTyKi env overall_ty@(HsAppsTy tys)+ = do { -- Step 1: Break up the HsAppsTy into symbols and non-symbol regions+ let (non_syms, syms) = splitHsAppsTy tys++ -- Step 2: rename the pieces+ ; (syms1, fvs1) <- mapFvRn (rnHsTyOp env overall_ty) syms+ ; (non_syms1, fvs2) <- (mapFvRn . mapFvRn) (rnLHsTyKi env) non_syms++ -- Step 3: deal with *. See Note [Dealing with *]+ ; let (non_syms2, syms2) = deal_with_star [] [] non_syms1 syms1++ -- Step 4: collapse the non-symbol regions with HsAppTy+ ; non_syms3 <- mapM deal_with_non_syms non_syms2++ -- Step 5: assemble the pieces, using mkHsOpTyRn+ ; L _ res_ty <- build_res_ty non_syms3 syms2++ -- all done. Phew.+ ; return (res_ty, fvs1 `plusFV` fvs2) }+ where+ -- See Note [Dealing with *]+ deal_with_star :: [[LHsType Name]] -> [Located Name]+ -> [[LHsType Name]] -> [Located Name]+ -> ([[LHsType Name]], [Located Name])+ deal_with_star acc1 acc2+ (non_syms1 : non_syms2 : non_syms) (L loc star : ops)+ | star `hasKey` starKindTyConKey || star `hasKey` unicodeStarKindTyConKey+ = deal_with_star acc1 acc2+ ((non_syms1 ++ L loc (HsTyVar NotPromoted (L loc star))+ : non_syms2) : non_syms)+ ops+ deal_with_star acc1 acc2 (non_syms1 : non_syms) (op1 : ops)+ = deal_with_star (non_syms1 : acc1) (op1 : acc2) non_syms ops+ deal_with_star acc1 acc2 [non_syms] []+ = (reverse (non_syms : acc1), reverse acc2)+ deal_with_star _ _ _ _+ = pprPanic "deal_with_star" (ppr overall_ty)++ -- collapse [LHsType Name] to LHsType Name by making applications+ -- monadic only for failure+ deal_with_non_syms :: [LHsType Name] -> RnM (LHsType Name)+ deal_with_non_syms (non_sym : non_syms) = return $ mkHsAppTys non_sym non_syms+ deal_with_non_syms [] = failWith (emptyNonSymsErr overall_ty)++ -- assemble a right-biased OpTy for use in mkHsOpTyRn+ build_res_ty :: [LHsType Name] -> [Located Name] -> RnM (LHsType Name)+ build_res_ty (arg1 : args) (op1 : ops)+ = do { rhs <- build_res_ty args ops+ ; fix <- lookupTyFixityRn op1+ ; res <-+ mkHsOpTyRn (\t1 t2 -> HsOpTy t1 op1 t2) (unLoc op1) fix arg1 rhs+ ; let loc = combineSrcSpans (getLoc arg1) (getLoc rhs)+ ; return (L loc res)+ }+ build_res_ty [arg] [] = return arg+ build_res_ty _ _ = pprPanic "build_op_ty" (ppr overall_ty)++rnHsTyKi env (HsAppTy ty1 ty2)+ = do { (ty1', fvs1) <- rnLHsTyKi env ty1+ ; (ty2', fvs2) <- rnLHsTyKi env ty2+ ; return (HsAppTy ty1' ty2', fvs1 `plusFV` fvs2) }++rnHsTyKi env t@(HsIParamTy n ty)+ = do { notInKinds env t+ ; (ty', fvs) <- rnLHsTyKi env ty+ ; return (HsIParamTy n ty', fvs) }++rnHsTyKi env t@(HsEqTy ty1 ty2)+ = do { checkTypeInType env t+ ; (ty1', fvs1) <- rnLHsTyKi env ty1+ ; (ty2', fvs2) <- rnLHsTyKi env ty2+ ; return (HsEqTy ty1' ty2', fvs1 `plusFV` fvs2) }++rnHsTyKi _ (HsSpliceTy sp k)+ = rnSpliceType sp k++rnHsTyKi env (HsDocTy ty haddock_doc)+ = do { (ty', fvs) <- rnLHsTyKi env ty+ ; haddock_doc' <- rnLHsDoc haddock_doc+ ; return (HsDocTy ty' haddock_doc', fvs) }++rnHsTyKi _ (HsCoreTy ty)+ = return (HsCoreTy ty, emptyFVs)+ -- The emptyFVs probably isn't quite right+ -- but I don't think it matters++rnHsTyKi env ty@(HsExplicitListTy ip k tys)+ = do { checkTypeInType env ty+ ; data_kinds <- xoptM LangExt.DataKinds+ ; unless data_kinds (addErr (dataKindsErr env ty))+ ; (tys', fvs) <- mapFvRn (rnLHsTyKi env) tys+ ; return (HsExplicitListTy ip k tys', fvs) }++rnHsTyKi env ty@(HsExplicitTupleTy kis tys)+ = do { checkTypeInType env ty+ ; data_kinds <- xoptM LangExt.DataKinds+ ; unless data_kinds (addErr (dataKindsErr env ty))+ ; (tys', fvs) <- mapFvRn (rnLHsTyKi env) tys+ ; return (HsExplicitTupleTy kis tys', fvs) }++rnHsTyKi env (HsWildCardTy wc)+ = do { checkAnonWildCard env wc+ ; wc' <- rnAnonWildCard wc+ ; return (HsWildCardTy wc', emptyFVs) }+ -- emptyFVs: this occurrence does not refer to a+ -- user-written binding site, so don't treat+ -- it as a free variable++--------------+rnTyVar :: RnTyKiEnv -> RdrName -> RnM Name+rnTyVar env rdr_name+ = do { name <- if isRnKindLevel env+ then lookupKindOccRn rdr_name+ else lookupTypeOccRn rdr_name+ ; checkNamedWildCard env name+ ; return name }++rnLTyVar :: Located RdrName -> RnM (Located Name)+-- Called externally; does not deal with wildards+rnLTyVar (L loc rdr_name)+ = do { tyvar <- lookupTypeOccRn rdr_name+ ; return (L loc tyvar) }++--------------+rnHsTyOp :: Outputable a+ => RnTyKiEnv -> a -> Located RdrName -> RnM (Located Name, FreeVars)+rnHsTyOp env overall_ty (L loc op)+ = do { ops_ok <- xoptM LangExt.TypeOperators+ ; op' <- rnTyVar env op+ ; unless (ops_ok+ || op' == starKindTyConName+ || op' == unicodeStarKindTyConName+ || op' `hasKey` eqTyConKey) $+ addErr (opTyErr op overall_ty)+ ; let l_op' = L loc op'+ ; return (l_op', unitFV op') }++--------------+notAllowed :: SDoc -> SDoc+notAllowed doc+ = text "Wildcard" <+> quotes doc <+> ptext (sLit "not allowed")++checkWildCard :: RnTyKiEnv -> Maybe SDoc -> RnM ()+checkWildCard env (Just doc)+ = addErr $ vcat [doc, nest 2 (text "in" <+> pprHsDocContext (rtke_ctxt env))]+checkWildCard _ Nothing+ = return ()++checkAnonWildCard :: RnTyKiEnv -> HsWildCardInfo RdrName -> RnM ()+-- Report an error if an anonymoous wildcard is illegal here+checkAnonWildCard env wc+ = checkWildCard env mb_bad+ where+ mb_bad :: Maybe SDoc+ mb_bad | not (wildCardsAllowed env)+ = Just (notAllowed (ppr wc))+ | otherwise+ = case rtke_what env of+ RnTypeBody -> Nothing+ RnConstraint -> Just constraint_msg+ RnTopConstraint -> Just constraint_msg++ constraint_msg = hang (notAllowed (ppr wc) <+> text "in a constraint")+ 2 hint_msg+ hint_msg = vcat [ text "except as the last top-level constraint of a type signature"+ , nest 2 (text "e.g f :: (Eq a, _) => blah") ]++checkNamedWildCard :: RnTyKiEnv -> Name -> RnM ()+-- Report an error if a named wildcard is illegal here+checkNamedWildCard env name+ = checkWildCard env mb_bad+ where+ mb_bad | not (name `elemNameSet` rtke_nwcs env)+ = Nothing -- Not a wildcard+ | not (wildCardsAllowed env)+ = Just (notAllowed (ppr name))+ | otherwise+ = case rtke_what env of+ RnTypeBody -> Nothing -- Allowed+ RnTopConstraint -> Nothing -- Allowed+ RnConstraint -> Just constraint_msg+ constraint_msg = notAllowed (ppr name) <+> text "in a constraint"++wildCardsAllowed :: RnTyKiEnv -> Bool+-- ^ In what contexts are wildcards permitted+wildCardsAllowed env+ = case rtke_ctxt env of+ TypeSigCtx {} -> True+ TypBrCtx {} -> True -- Template Haskell quoted type+ SpliceTypeCtx {} -> True -- Result of a Template Haskell splice+ ExprWithTySigCtx {} -> True+ PatCtx {} -> True+ RuleCtx {} -> True+ FamPatCtx {} -> True -- Not named wildcards though+ GHCiCtx {} -> True+ HsTypeCtx {} -> True+ _ -> False++rnAnonWildCard :: HsWildCardInfo RdrName -> RnM (HsWildCardInfo Name)+rnAnonWildCard (AnonWildCard _)+ = do { loc <- getSrcSpanM+ ; uniq <- newUnique+ ; let name = mkInternalName uniq (mkTyVarOcc "_") loc+ ; return (AnonWildCard (L loc name)) }++---------------+-- | Ensures either that we're in a type or that -XTypeInType is set+checkTypeInType :: Outputable ty+ => RnTyKiEnv+ -> ty -- ^ type+ -> RnM ()+checkTypeInType env ty+ | isRnKindLevel env+ = do { type_in_type <- xoptM LangExt.TypeInType+ ; unless type_in_type $+ addErr (text "Illegal kind:" <+> ppr ty $$+ text "Did you mean to enable TypeInType?") }+checkTypeInType _ _ = return ()++notInKinds :: Outputable ty+ => RnTyKiEnv+ -> ty+ -> RnM ()+notInKinds env ty+ | isRnKindLevel env+ = addErr (text "Illegal kind (even with TypeInType enabled):" <+> ppr ty)+notInKinds _ _ = return ()++{- *****************************************************+* *+ Binding type variables+* *+***************************************************** -}++bindSigTyVarsFV :: [Name]+ -> RnM (a, FreeVars)+ -> RnM (a, FreeVars)+-- Used just before renaming the defn of a function+-- with a separate type signature, to bring its tyvars into scope+-- With no -XScopedTypeVariables, this is a no-op+bindSigTyVarsFV tvs thing_inside+ = do { scoped_tyvars <- xoptM LangExt.ScopedTypeVariables+ ; if not scoped_tyvars then+ thing_inside+ else+ bindLocalNamesFV tvs thing_inside }++-- | Simply bring a bunch of RdrNames into scope. No checking for+-- validity, at all. The binding location is taken from the location+-- on each name.+bindLRdrNames :: [Located RdrName]+ -> ([Name] -> RnM (a, FreeVars))+ -> RnM (a, FreeVars)+bindLRdrNames rdrs thing_inside+ = do { var_names <- mapM (newTyVarNameRn Nothing) rdrs+ ; bindLocalNamesFV var_names $+ thing_inside var_names }++---------------+bindHsQTyVars :: forall a b.+ HsDocContext+ -> Maybe SDoc -- if we are to check for unused tvs,+ -- a phrase like "in the type ..."+ -> Maybe a -- Just _ => an associated type decl+ -> [Located RdrName] -- Kind variables from scope, in l-to-r+ -- order, but not from ...+ -> (LHsQTyVars RdrName) -- ... these user-written tyvars+ -> (LHsQTyVars Name -> NameSet -> RnM (b, FreeVars))+ -- also returns all names used in kind signatures, for the+ -- TypeInType clause of Note [Complete user-supplied kind+ -- signatures] in HsDecls+ -> RnM (b, FreeVars)+-- (a) Bring kind variables into scope+-- both (i) passed in (kv_bndrs)+-- and (ii) mentioned in the kinds of tv_bndrs+-- (b) Bring type variables into scope+bindHsQTyVars doc mb_in_doc mb_assoc kv_bndrs tv_bndrs thing_inside+ = do { bindLHsTyVarBndrs doc mb_in_doc+ mb_assoc kv_bndrs (hsQTvExplicit tv_bndrs) $+ \ rn_kvs rn_bndrs dep_var_set all_dep_vars ->+ thing_inside (HsQTvs { hsq_implicit = rn_kvs+ , hsq_explicit = rn_bndrs+ , hsq_dependent = dep_var_set }) all_dep_vars }++bindLHsTyVarBndrs :: forall a b.+ HsDocContext+ -> Maybe SDoc -- if we are to check for unused tvs,+ -- a phrase like "in the type ..."+ -> Maybe a -- Just _ => an associated type decl+ -> [Located RdrName] -- Unbound kind variables from scope,+ -- in l-to-r order, but not from ...+ -> [LHsTyVarBndr RdrName] -- ... these user-written tyvars+ -> ( [Name] -- all kv names+ -> [LHsTyVarBndr Name]+ -> NameSet -- which names, from the preceding list,+ -- are used dependently within that list+ -- See Note [Dependent LHsQTyVars] in TcHsType+ -> NameSet -- all names used in kind signatures+ -> RnM (b, FreeVars))+ -> RnM (b, FreeVars)+bindLHsTyVarBndrs doc mb_in_doc mb_assoc kv_bndrs tv_bndrs thing_inside+ = do { when (isNothing mb_assoc) (checkShadowedRdrNames tv_names_w_loc)+ ; go [] [] emptyNameSet emptyNameSet emptyNameSet tv_bndrs }+ where+ tv_names_w_loc = map hsLTyVarLocName tv_bndrs++ go :: [Name] -- kind-vars found (in reverse order)+ -> [LHsTyVarBndr Name] -- already renamed (in reverse order)+ -> NameSet -- kind vars already in scope (for dup checking)+ -> NameSet -- type vars already in scope (for dup checking)+ -> NameSet -- (all) variables used dependently+ -> [LHsTyVarBndr RdrName] -- still to be renamed, scoped+ -> RnM (b, FreeVars)+ go rn_kvs rn_tvs kv_names tv_names dep_vars (tv_bndr : tv_bndrs)+ = bindLHsTyVarBndr doc mb_assoc kv_names tv_names tv_bndr $+ \ kv_nms used_dependently tv_bndr' ->+ do { (b, fvs) <- go (reverse kv_nms ++ rn_kvs)+ (tv_bndr' : rn_tvs)+ (kv_names `extendNameSetList` kv_nms)+ (tv_names `extendNameSet` hsLTyVarName tv_bndr')+ (dep_vars `unionNameSet` used_dependently)+ tv_bndrs+ ; warn_unused tv_bndr' fvs+ ; return (b, fvs) }++ go rn_kvs rn_tvs _kv_names tv_names dep_vars []+ = -- still need to deal with the kv_bndrs passed in originally+ bindImplicitKvs doc mb_assoc kv_bndrs tv_names $ \ kv_nms others ->+ do { let all_rn_kvs = reverse (reverse kv_nms ++ rn_kvs)+ all_rn_tvs = reverse rn_tvs+ ; env <- getLocalRdrEnv+ ; let all_dep_vars = dep_vars `unionNameSet` others+ exp_dep_vars -- variables in all_rn_tvs that are in dep_vars+ = mkNameSet [ name+ | v <- all_rn_tvs+ , let name = hsLTyVarName v+ , name `elemNameSet` all_dep_vars ]+ ; traceRn "bindHsTyVars" (ppr env $$+ ppr all_rn_kvs $$+ ppr all_rn_tvs $$+ ppr exp_dep_vars)+ ; thing_inside all_rn_kvs all_rn_tvs exp_dep_vars all_dep_vars }++ warn_unused tv_bndr fvs = case mb_in_doc of+ Just in_doc -> warnUnusedForAll in_doc tv_bndr fvs+ Nothing -> return ()++bindLHsTyVarBndr :: HsDocContext+ -> Maybe a -- associated class+ -> NameSet -- kind vars already in scope+ -> NameSet -- type vars already in scope+ -> LHsTyVarBndr RdrName+ -> ([Name] -> NameSet -> LHsTyVarBndr Name -> RnM (b, FreeVars))+ -- passed the newly-bound implicitly-declared kind vars,+ -- any other names used in a kind+ -- and the renamed LHsTyVarBndr+ -> RnM (b, FreeVars)+bindLHsTyVarBndr doc mb_assoc kv_names tv_names hs_tv_bndr thing_inside+ = case hs_tv_bndr of+ L loc (UserTyVar lrdr@(L lv rdr)) ->+ do { check_dup loc rdr []+ ; nm <- newTyVarNameRn mb_assoc lrdr+ ; bindLocalNamesFV [nm] $+ thing_inside [] emptyNameSet (L loc (UserTyVar (L lv nm))) }+ L loc (KindedTyVar lrdr@(L lv rdr) kind) ->+ do { free_kvs <- freeKiTyVarsAllVars <$> extractHsTyRdrTyVars kind+ ; check_dup lv rdr (map unLoc free_kvs)++ -- check for -XKindSignatures+ ; sig_ok <- xoptM LangExt.KindSignatures+ ; unless sig_ok (badKindSigErr doc kind)++ -- deal with kind vars in the user-written kind+ ; bindImplicitKvs doc mb_assoc free_kvs tv_names $+ \ new_kv_nms other_kv_nms ->+ do { (kind', fvs1) <- rnLHsKind doc kind+ ; tv_nm <- newTyVarNameRn mb_assoc lrdr+ ; (b, fvs2) <- bindLocalNamesFV [tv_nm] $+ thing_inside new_kv_nms other_kv_nms+ (L loc (KindedTyVar (L lv tv_nm) kind'))+ ; return (b, fvs1 `plusFV` fvs2) }}+ where+ -- make sure that the RdrName isn't in the sets of+ -- names. We can't just check that it's not in scope at all+ -- because we might be inside an associated class.+ check_dup :: SrcSpan -> RdrName -> [RdrName] -> RnM ()+ check_dup loc rdr kindFreeVars+ = do { -- Disallow use of a type variable name in its+ -- kind signature (#11592).+ when (rdr `elem` kindFreeVars) $+ addErrAt loc (vcat [ ki_ty_self_err rdr+ , pprHsDocContext doc ])++ ; m_name <- lookupLocalOccRn_maybe rdr+ ; whenIsJust m_name $ \name ->+ do { when (name `elemNameSet` kv_names) $+ addErrAt loc (vcat [ ki_ty_err_msg name+ , pprHsDocContext doc ])+ ; when (name `elemNameSet` tv_names) $+ dupNamesErr getLoc [L loc name, L (nameSrcSpan name) name] }}++ ki_ty_err_msg n = text "Variable" <+> quotes (ppr n) <+>+ text "used as a kind variable before being bound" $$+ text "as a type variable. Perhaps reorder your variables?"++ ki_ty_self_err n = text "Variable" <+> quotes (ppr n) <+>+ text "is used in the kind signature of its" $$+ text "declaration as a type variable."+++bindImplicitKvs :: HsDocContext+ -> Maybe a+ -> [Located RdrName] -- ^ kind var *occurrences*, from which+ -- intent to bind is inferred+ -> NameSet -- ^ *type* variables, for type/kind+ -- misuse check for -XNoTypeInType+ -> ([Name] -> NameSet -> RnM (b, FreeVars))+ -- ^ passed new kv_names, and any other names used in a kind+ -> RnM (b, FreeVars)+bindImplicitKvs _ _ [] _ thing_inside+ = thing_inside [] emptyNameSet+bindImplicitKvs doc mb_assoc free_kvs tv_names thing_inside+ = do { rdr_env <- getLocalRdrEnv+ ; let part_kvs lrdr@(L loc kv_rdr)+ = case lookupLocalRdrEnv rdr_env kv_rdr of+ Just kv_name -> Left (L loc kv_name)+ _ -> Right lrdr+ (bound_kvs, new_kvs) = partitionWith part_kvs free_kvs++ -- check whether we're mixing types & kinds illegally+ ; type_in_type <- xoptM LangExt.TypeInType+ ; unless type_in_type $+ mapM_ (check_tv_used_in_kind tv_names) bound_kvs++ ; poly_kinds <- xoptM LangExt.PolyKinds+ ; unless poly_kinds $+ addErr (badKindBndrs doc new_kvs)++ -- bind the vars and move on+ ; kv_nms <- mapM (newTyVarNameRn mb_assoc) new_kvs+ ; bindLocalNamesFV kv_nms $+ thing_inside kv_nms (mkNameSet (map unLoc bound_kvs)) }+ where+ -- check to see if the variables free in a kind are bound as type+ -- variables. Assume -XNoTypeInType.+ check_tv_used_in_kind :: NameSet -- ^ *type* variables+ -> Located Name -- ^ renamed var used in kind+ -> RnM ()+ check_tv_used_in_kind tv_names (L loc kv_name)+ = when (kv_name `elemNameSet` tv_names) $+ addErrAt loc (vcat [ text "Type variable" <+> quotes (ppr kv_name) <+>+ text "used in a kind." $$+ text "Did you mean to use TypeInType?"+ , pprHsDocContext doc ])+++newTyVarNameRn :: Maybe a -> Located RdrName -> RnM Name+newTyVarNameRn mb_assoc (L loc rdr)+ = do { rdr_env <- getLocalRdrEnv+ ; case (mb_assoc, lookupLocalRdrEnv rdr_env rdr) of+ (Just _, Just n) -> return n+ -- Use the same Name as the parent class decl++ _ -> newLocalBndrRn (L loc rdr) }++---------------------+collectAnonWildCards :: LHsType Name -> [Name]+-- | Extract all wild cards from a type.+collectAnonWildCards lty = go lty+ where+ go (L _ ty) = case ty of+ HsWildCardTy (AnonWildCard (L _ wc)) -> [wc]+ HsAppsTy tys -> gos (mapMaybe (prefix_types_only . unLoc) tys)+ HsAppTy ty1 ty2 -> go ty1 `mappend` go ty2+ HsFunTy ty1 ty2 -> go ty1 `mappend` go ty2+ HsListTy ty -> go ty+ HsPArrTy ty -> go ty+ HsTupleTy _ tys -> gos tys+ HsSumTy tys -> gos tys+ HsOpTy ty1 _ ty2 -> go ty1 `mappend` go ty2+ HsParTy ty -> go ty+ HsIParamTy _ ty -> go ty+ HsEqTy ty1 ty2 -> go ty1 `mappend` go ty2+ HsKindSig ty kind -> go ty `mappend` go kind+ HsDocTy ty _ -> go ty+ HsBangTy _ ty -> go ty+ HsRecTy flds -> gos $ map (cd_fld_type . unLoc) flds+ HsExplicitListTy _ _ tys -> gos tys+ HsExplicitTupleTy _ tys -> gos tys+ HsForAllTy { hst_bndrs = bndrs+ , hst_body = ty } -> collectAnonWildCardsBndrs bndrs+ `mappend` go ty+ HsQualTy { hst_ctxt = L _ ctxt+ , hst_body = ty } -> gos ctxt `mappend` go ty+ HsSpliceTy (HsSpliced _ (HsSplicedTy ty)) _ -> go $ L noSrcSpan ty+ HsSpliceTy{} -> mempty+ HsCoreTy{} -> mempty+ HsTyLit{} -> mempty+ HsTyVar{} -> mempty++ gos = mconcat . map go++ prefix_types_only (HsAppPrefix ty) = Just ty+ prefix_types_only (HsAppInfix _) = Nothing++collectAnonWildCardsBndrs :: [LHsTyVarBndr Name] -> [Name]+collectAnonWildCardsBndrs ltvs = concatMap (go . unLoc) ltvs+ where+ go (UserTyVar _) = []+ go (KindedTyVar _ ki) = collectAnonWildCards ki++{-+*********************************************************+* *+ ConDeclField+* *+*********************************************************++When renaming a ConDeclField, we have to find the FieldLabel+associated with each field. But we already have all the FieldLabels+available (since they were brought into scope by+RnNames.getLocalNonValBinders), so we just take the list as an+argument, build a map and look them up.+-}++rnConDeclFields :: HsDocContext -> [FieldLabel] -> [LConDeclField RdrName]+ -> RnM ([LConDeclField Name], FreeVars)+-- Also called from RnSource+-- No wildcards can appear in record fields+rnConDeclFields ctxt fls fields+ = mapFvRn (rnField fl_env env) fields+ where+ env = mkTyKiEnv ctxt TypeLevel RnTypeBody+ fl_env = mkFsEnv [ (flLabel fl, fl) | fl <- fls ]++rnField :: FastStringEnv FieldLabel -> RnTyKiEnv -> LConDeclField RdrName+ -> RnM (LConDeclField Name, FreeVars)+rnField fl_env env (L l (ConDeclField names ty haddock_doc))+ = do { let new_names = map (fmap lookupField) names+ ; (new_ty, fvs) <- rnLHsTyKi env ty+ ; new_haddock_doc <- rnMbLHsDoc haddock_doc+ ; return (L l (ConDeclField new_names new_ty new_haddock_doc), fvs) }+ where+ lookupField :: FieldOcc RdrName -> FieldOcc Name+ lookupField (FieldOcc (L lr rdr) _) = FieldOcc (L lr rdr) (flSelector fl)+ where+ lbl = occNameFS $ rdrNameOcc rdr+ fl = expectJust "rnField" $ lookupFsEnv fl_env lbl++{-+************************************************************************+* *+ Fixities and precedence parsing+* *+************************************************************************++@mkOpAppRn@ deals with operator fixities. The argument expressions+are assumed to be already correctly arranged. It needs the fixities+recorded in the OpApp nodes, because fixity info applies to the things+the programmer actually wrote, so you can't find it out from the Name.++Furthermore, the second argument is guaranteed not to be another+operator application. Why? Because the parser parses all+operator applications left-associatively, EXCEPT negation, which+we need to handle specially.+Infix types are read in a *right-associative* way, so that+ a `op` b `op` c+is always read in as+ a `op` (b `op` c)++mkHsOpTyRn rearranges where necessary. The two arguments+have already been renamed and rearranged. It's made rather tiresome+by the presence of ->, which is a separate syntactic construct.+-}++---------------+-- Building (ty1 `op1` (ty21 `op2` ty22))+mkHsOpTyRn :: (LHsType Name -> LHsType Name -> HsType Name)+ -> Name -> Fixity -> LHsType Name -> LHsType Name+ -> RnM (HsType Name)++mkHsOpTyRn mk1 pp_op1 fix1 ty1 (L loc2 (HsOpTy ty21 op2 ty22))+ = do { fix2 <- lookupTyFixityRn op2+ ; mk_hs_op_ty mk1 pp_op1 fix1 ty1+ (\t1 t2 -> HsOpTy t1 op2 t2)+ (unLoc op2) fix2 ty21 ty22 loc2 }++mkHsOpTyRn mk1 pp_op1 fix1 ty1 (L loc2 (HsFunTy ty21 ty22))+ = mk_hs_op_ty mk1 pp_op1 fix1 ty1+ HsFunTy funTyConName funTyFixity ty21 ty22 loc2++mkHsOpTyRn mk1 _ _ ty1 ty2 -- Default case, no rearrangment+ = return (mk1 ty1 ty2)++---------------+mk_hs_op_ty :: (LHsType Name -> LHsType Name -> HsType Name)+ -> Name -> Fixity -> LHsType Name+ -> (LHsType Name -> LHsType Name -> HsType Name)+ -> Name -> Fixity -> LHsType Name -> LHsType Name -> SrcSpan+ -> RnM (HsType Name)+mk_hs_op_ty mk1 op1 fix1 ty1+ mk2 op2 fix2 ty21 ty22 loc2+ | nofix_error = do { precParseErr (NormalOp op1,fix1) (NormalOp op2,fix2)+ ; return (mk1 ty1 (L loc2 (mk2 ty21 ty22))) }+ | associate_right = return (mk1 ty1 (L loc2 (mk2 ty21 ty22)))+ | otherwise = do { -- Rearrange to ((ty1 `op1` ty21) `op2` ty22)+ new_ty <- mkHsOpTyRn mk1 op1 fix1 ty1 ty21+ ; return (mk2 (noLoc new_ty) ty22) }+ where+ (nofix_error, associate_right) = compareFixity fix1 fix2+++---------------------------+mkOpAppRn :: LHsExpr Name -- Left operand; already rearranged+ -> LHsExpr Name -> Fixity -- Operator and fixity+ -> LHsExpr Name -- Right operand (not an OpApp, but might+ -- be a NegApp)+ -> RnM (HsExpr Name)++-- (e11 `op1` e12) `op2` e2+mkOpAppRn e1@(L _ (OpApp e11 op1 fix1 e12)) op2 fix2 e2+ | nofix_error+ = do precParseErr (get_op op1,fix1) (get_op op2,fix2)+ return (OpApp e1 op2 fix2 e2)++ | associate_right = do+ new_e <- mkOpAppRn e12 op2 fix2 e2+ return (OpApp e11 op1 fix1 (L loc' new_e))+ where+ loc'= combineLocs e12 e2+ (nofix_error, associate_right) = compareFixity fix1 fix2++---------------------------+-- (- neg_arg) `op` e2+mkOpAppRn e1@(L _ (NegApp neg_arg neg_name)) op2 fix2 e2+ | nofix_error+ = do precParseErr (NegateOp,negateFixity) (get_op op2,fix2)+ return (OpApp e1 op2 fix2 e2)++ | associate_right+ = do new_e <- mkOpAppRn neg_arg op2 fix2 e2+ return (NegApp (L loc' new_e) neg_name)+ where+ loc' = combineLocs neg_arg e2+ (nofix_error, associate_right) = compareFixity negateFixity fix2++---------------------------+-- e1 `op` - neg_arg+mkOpAppRn e1 op1 fix1 e2@(L _ (NegApp _ _)) -- NegApp can occur on the right+ | not associate_right -- We *want* right association+ = do precParseErr (get_op op1, fix1) (NegateOp, negateFixity)+ return (OpApp e1 op1 fix1 e2)+ where+ (_, associate_right) = compareFixity fix1 negateFixity++---------------------------+-- Default case+mkOpAppRn e1 op fix e2 -- Default case, no rearrangment+ = ASSERT2( right_op_ok fix (unLoc e2),+ ppr e1 $$ text "---" $$ ppr op $$ text "---" $$ ppr fix $$ text "---" $$ ppr e2+ )+ return (OpApp e1 op fix e2)++----------------------------++-- | Name of an operator in an operator application or section+data OpName = NormalOp Name -- ^ A normal identifier+ | NegateOp -- ^ Prefix negation+ | UnboundOp UnboundVar -- ^ An unbound indentifier+ | RecFldOp (AmbiguousFieldOcc Name)+ -- ^ A (possibly ambiguous) record field occurrence++instance Outputable OpName where+ ppr (NormalOp n) = ppr n+ ppr NegateOp = ppr negateName+ ppr (UnboundOp uv) = ppr uv+ ppr (RecFldOp fld) = ppr fld++get_op :: LHsExpr Name -> OpName+-- An unbound name could be either HsVar or HsUnboundVar+-- See RnExpr.rnUnboundVar+get_op (L _ (HsVar (L _ n))) = NormalOp n+get_op (L _ (HsUnboundVar uv)) = UnboundOp uv+get_op (L _ (HsRecFld fld)) = RecFldOp fld+get_op other = pprPanic "get_op" (ppr other)++-- Parser left-associates everything, but+-- derived instances may have correctly-associated things to+-- in the right operand. So we just check that the right operand is OK+right_op_ok :: Fixity -> HsExpr Name -> Bool+right_op_ok fix1 (OpApp _ _ fix2 _)+ = not error_please && associate_right+ where+ (error_please, associate_right) = compareFixity fix1 fix2+right_op_ok _ _+ = True++-- Parser initially makes negation bind more tightly than any other operator+-- And "deriving" code should respect this (use HsPar if not)+mkNegAppRn :: LHsExpr id -> SyntaxExpr id -> RnM (HsExpr id)+mkNegAppRn neg_arg neg_name+ = ASSERT( not_op_app (unLoc neg_arg) )+ return (NegApp neg_arg neg_name)++not_op_app :: HsExpr id -> Bool+not_op_app (OpApp _ _ _ _) = False+not_op_app _ = True++---------------------------+mkOpFormRn :: LHsCmdTop Name -- Left operand; already rearranged+ -> LHsExpr Name -> Fixity -- Operator and fixity+ -> LHsCmdTop Name -- Right operand (not an infix)+ -> RnM (HsCmd Name)++-- (e11 `op1` e12) `op2` e2+mkOpFormRn a1@(L loc (HsCmdTop (L _ (HsCmdArrForm op1 f (Just fix1)+ [a11,a12])) _ _ _))+ op2 fix2 a2+ | nofix_error+ = do precParseErr (get_op op1,fix1) (get_op op2,fix2)+ return (HsCmdArrForm op2 f (Just fix2) [a1, a2])++ | associate_right+ = do new_c <- mkOpFormRn a12 op2 fix2 a2+ return (HsCmdArrForm op1 f (Just fix1)+ [a11, L loc (HsCmdTop (L loc new_c)+ placeHolderType placeHolderType [])])+ -- TODO: locs are wrong+ where+ (nofix_error, associate_right) = compareFixity fix1 fix2++-- Default case+mkOpFormRn arg1 op fix arg2 -- Default case, no rearrangment+ = return (HsCmdArrForm op Infix (Just fix) [arg1, arg2])+++--------------------------------------+mkConOpPatRn :: Located Name -> Fixity -> LPat Name -> LPat Name+ -> RnM (Pat Name)++mkConOpPatRn op2 fix2 p1@(L loc (ConPatIn op1 (InfixCon p11 p12))) p2+ = do { fix1 <- lookupFixityRn (unLoc op1)+ ; let (nofix_error, associate_right) = compareFixity fix1 fix2++ ; if nofix_error then do+ { precParseErr (NormalOp (unLoc op1),fix1)+ (NormalOp (unLoc op2),fix2)+ ; return (ConPatIn op2 (InfixCon p1 p2)) }++ else if associate_right then do+ { new_p <- mkConOpPatRn op2 fix2 p12 p2+ ; return (ConPatIn op1 (InfixCon p11 (L loc new_p))) } -- XXX loc right?+ else return (ConPatIn op2 (InfixCon p1 p2)) }++mkConOpPatRn op _ p1 p2 -- Default case, no rearrangment+ = ASSERT( not_op_pat (unLoc p2) )+ return (ConPatIn op (InfixCon p1 p2))++not_op_pat :: Pat Name -> Bool+not_op_pat (ConPatIn _ (InfixCon _ _)) = False+not_op_pat _ = True++--------------------------------------+checkPrecMatch :: Name -> MatchGroup Name body -> RnM ()+ -- Check precedence of a function binding written infix+ -- eg a `op` b `C` c = ...+ -- See comments with rnExpr (OpApp ...) about "deriving"++checkPrecMatch op (MG { mg_alts = L _ ms })+ = mapM_ check ms+ where+ check (L _ (Match _ (L l1 p1 : L l2 p2 :_) _ _))+ = setSrcSpan (combineSrcSpans l1 l2) $+ do checkPrec op p1 False+ checkPrec op p2 True++ check _ = return ()+ -- This can happen. Consider+ -- a `op` True = ...+ -- op = ...+ -- The infix flag comes from the first binding of the group+ -- but the second eqn has no args (an error, but not discovered+ -- until the type checker). So we don't want to crash on the+ -- second eqn.++checkPrec :: Name -> Pat Name -> Bool -> IOEnv (Env TcGblEnv TcLclEnv) ()+checkPrec op (ConPatIn op1 (InfixCon _ _)) right = do+ op_fix@(Fixity _ op_prec op_dir) <- lookupFixityRn op+ op1_fix@(Fixity _ op1_prec op1_dir) <- lookupFixityRn (unLoc op1)+ let+ inf_ok = op1_prec > op_prec ||+ (op1_prec == op_prec &&+ (op1_dir == InfixR && op_dir == InfixR && right ||+ op1_dir == InfixL && op_dir == InfixL && not right))++ info = (NormalOp op, op_fix)+ info1 = (NormalOp (unLoc op1), op1_fix)+ (infol, infor) = if right then (info, info1) else (info1, info)+ unless inf_ok (precParseErr infol infor)++checkPrec _ _ _+ = return ()++-- Check precedence of (arg op) or (op arg) respectively+-- If arg is itself an operator application, then either+-- (a) its precedence must be higher than that of op+-- (b) its precedency & associativity must be the same as that of op+checkSectionPrec :: FixityDirection -> HsExpr RdrName+ -> LHsExpr Name -> LHsExpr Name -> RnM ()+checkSectionPrec direction section op arg+ = case unLoc arg of+ OpApp _ op' fix _ -> go_for_it (get_op op') fix+ NegApp _ _ -> go_for_it NegateOp negateFixity+ _ -> return ()+ where+ op_name = get_op op+ go_for_it arg_op arg_fix@(Fixity _ arg_prec assoc) = do+ op_fix@(Fixity _ op_prec _) <- lookupFixityOp op_name+ unless (op_prec < arg_prec+ || (op_prec == arg_prec && direction == assoc))+ (sectionPrecErr (get_op op, op_fix)+ (arg_op, arg_fix) section)++-- | Look up the fixity for an operator name. Be careful to use+-- 'lookupFieldFixityRn' for (possibly ambiguous) record fields+-- (see Trac #13132).+lookupFixityOp :: OpName -> RnM Fixity+lookupFixityOp (NormalOp n) = lookupFixityRn n+lookupFixityOp NegateOp = lookupFixityRn negateName+lookupFixityOp (UnboundOp u) = lookupFixityRn (mkUnboundName (unboundVarOcc u))+lookupFixityOp (RecFldOp f) = lookupFieldFixityRn f+++-- Precedence-related error messages++precParseErr :: (OpName,Fixity) -> (OpName,Fixity) -> RnM ()+precParseErr op1@(n1,_) op2@(n2,_)+ | is_unbound n1 || is_unbound n2+ = return () -- Avoid error cascade+ | otherwise+ = addErr $ hang (text "Precedence parsing error")+ 4 (hsep [text "cannot mix", ppr_opfix op1, ptext (sLit "and"),+ ppr_opfix op2,+ text "in the same infix expression"])++sectionPrecErr :: (OpName,Fixity) -> (OpName,Fixity) -> HsExpr RdrName -> RnM ()+sectionPrecErr op@(n1,_) arg_op@(n2,_) section+ | is_unbound n1 || is_unbound n2+ = return () -- Avoid error cascade+ | otherwise+ = addErr $ vcat [text "The operator" <+> ppr_opfix op <+> ptext (sLit "of a section"),+ nest 4 (sep [text "must have lower precedence than that of the operand,",+ nest 2 (text "namely" <+> ppr_opfix arg_op)]),+ nest 4 (text "in the section:" <+> quotes (ppr section))]++is_unbound :: OpName -> Bool+is_unbound UnboundOp{} = True+is_unbound _ = False++ppr_opfix :: (OpName, Fixity) -> SDoc+ppr_opfix (op, fixity) = pp_op <+> brackets (ppr fixity)+ where+ pp_op | NegateOp <- op = text "prefix `-'"+ | otherwise = quotes (ppr op)+++{- *****************************************************+* *+ Errors+* *+***************************************************** -}++unexpectedTypeSigErr :: LHsSigWcType RdrName -> SDoc+unexpectedTypeSigErr ty+ = hang (text "Illegal type signature:" <+> quotes (ppr ty))+ 2 (text "Type signatures are only allowed in patterns with ScopedTypeVariables")++badKindBndrs :: HsDocContext -> [Located RdrName] -> SDoc+badKindBndrs doc kvs+ = withHsDocContext doc $+ hang (text "Unexpected kind variable" <> plural kvs+ <+> pprQuotedList kvs)+ 2 (text "Perhaps you intended to use PolyKinds")++badKindSigErr :: HsDocContext -> LHsType RdrName -> TcM ()+badKindSigErr doc (L loc ty)+ = setSrcSpan loc $ addErr $+ withHsDocContext doc $+ hang (text "Illegal kind signature:" <+> quotes (ppr ty))+ 2 (text "Perhaps you intended to use KindSignatures")++dataKindsErr :: RnTyKiEnv -> HsType RdrName -> SDoc+dataKindsErr env thing+ = hang (text "Illegal" <+> pp_what <> colon <+> quotes (ppr thing))+ 2 (text "Perhaps you intended to use DataKinds")+ where+ pp_what | isRnKindLevel env = text "kind"+ | otherwise = text "type"++inTypeDoc :: HsType RdrName -> SDoc+inTypeDoc ty = text "In the type" <+> quotes (ppr ty)++warnUnusedForAll :: SDoc -> LHsTyVarBndr Name -> FreeVars -> TcM ()+warnUnusedForAll in_doc (L loc tv) used_names+ = whenWOptM Opt_WarnUnusedForalls $+ unless (hsTyVarName tv `elemNameSet` used_names) $+ addWarnAt (Reason Opt_WarnUnusedForalls) loc $+ vcat [ text "Unused quantified type variable" <+> quotes (ppr tv)+ , in_doc ]++opTyErr :: Outputable a => RdrName -> a -> SDoc+opTyErr op overall_ty+ = hang (text "Illegal operator" <+> quotes (ppr op) <+> ptext (sLit "in type") <+> quotes (ppr overall_ty))+ 2 extra+ where+ extra | op == dot_tv_RDR+ = perhapsForallMsg+ | otherwise+ = text "Use TypeOperators to allow operators in types"++emptyNonSymsErr :: HsType RdrName -> SDoc+emptyNonSymsErr overall_ty+ = text "Operator applied to too few arguments:" <+> ppr overall_ty++{-+************************************************************************+* *+ Finding the free type variables of a (HsType RdrName)+* *+************************************************************************+++Note [Kind and type-variable binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a type signature we may implicitly bind type variable and, more+recently, kind variables. For example:+ * f :: a -> a+ f = ...+ Here we need to find the free type variables of (a -> a),+ so that we know what to quantify++ * class C (a :: k) where ...+ This binds 'k' in ..., as well as 'a'++ * f (x :: a -> [a]) = ....+ Here we bind 'a' in ....++ * f (x :: T a -> T (b :: k)) = ...+ Here we bind both 'a' and the kind variable 'k'++ * type instance F (T (a :: Maybe k)) = ...a...k...+ Here we want to constrain the kind of 'a', and bind 'k'.++In general we want to walk over a type, and find+ * Its free type variables+ * The free kind variables of any kind signatures in the type++Hence we returns a pair (kind-vars, type vars)+See also Note [HsBSig binder lists] in HsTypes+-}++data FreeKiTyVars = FKTV { fktv_kis :: [Located RdrName]+ , fktv_tys :: [Located RdrName] }++instance Outputable FreeKiTyVars where+ ppr (FKTV kis tys) = ppr (kis, tys)++emptyFKTV :: FreeKiTyVars+emptyFKTV = FKTV [] []++freeKiTyVarsAllVars :: FreeKiTyVars -> [Located RdrName]+freeKiTyVarsAllVars (FKTV tys kvs) = tys ++ kvs++freeKiTyVarsKindVars :: FreeKiTyVars -> [Located RdrName]+freeKiTyVarsKindVars = fktv_kis++freeKiTyVarsTypeVars :: FreeKiTyVars -> [Located RdrName]+freeKiTyVarsTypeVars = fktv_tys++filterInScope :: LocalRdrEnv -> FreeKiTyVars -> FreeKiTyVars+filterInScope rdr_env (FKTV kis tys)+ = FKTV (filterOut in_scope kis)+ (filterOut in_scope tys)+ where+ in_scope = inScope rdr_env . unLoc++inScope :: LocalRdrEnv -> RdrName -> Bool+inScope rdr_env rdr = rdr `elemLocalRdrEnv` rdr_env++extractHsTyRdrTyVars :: LHsType RdrName -> RnM FreeKiTyVars+-- extractHsTyRdrNames finds the free (kind, type) variables of a HsType+-- or the free (sort, kind) variables of a HsKind+-- It's used when making the for-alls explicit.+-- Does not return any wildcards+-- When the same name occurs multiple times in the types, only the first+-- occurrence is returned.+-- See Note [Kind and type-variable binders]+extractHsTyRdrTyVars ty+ = do { FKTV kis tys <- extract_lty TypeLevel ty emptyFKTV+ ; return (FKTV (nubL kis)+ (nubL tys)) }+++-- | Extracts free type and kind variables from types in a list.+-- When the same name occurs multiple times in the types, only the first+-- occurrence is returned and the rest is filtered out.+-- See Note [Kind and type-variable binders]+extractHsTysRdrTyVars :: [LHsType RdrName] -> RnM FreeKiTyVars+extractHsTysRdrTyVars tys+ = rmDupsInRdrTyVars <$> extractHsTysRdrTyVarsDups tys++-- | Extracts free type and kind variables from types in a list.+-- When the same name occurs multiple times in the types, all occurrences+-- are returned.+extractHsTysRdrTyVarsDups :: [LHsType RdrName] -> RnM FreeKiTyVars+extractHsTysRdrTyVarsDups tys+ = extract_ltys TypeLevel tys emptyFKTV++-- | Removes multiple occurrences of the same name from FreeKiTyVars.+rmDupsInRdrTyVars :: FreeKiTyVars -> FreeKiTyVars+rmDupsInRdrTyVars (FKTV kis tys)+ = FKTV (nubL kis) (nubL tys)++extractRdrKindSigVars :: LFamilyResultSig RdrName -> RnM [Located RdrName]+extractRdrKindSigVars (L _ resultSig)+ | KindSig k <- resultSig = kindRdrNameFromSig k+ | TyVarSig (L _ (KindedTyVar _ k)) <- resultSig = kindRdrNameFromSig k+ | otherwise = return []+ where kindRdrNameFromSig k = freeKiTyVarsAllVars <$> extractHsTyRdrTyVars k++extractDataDefnKindVars :: HsDataDefn RdrName -> RnM [Located RdrName]+-- Get the scoped kind variables mentioned free in the constructor decls+-- Eg data T a = T1 (S (a :: k) | forall (b::k). T2 (S b)+-- Here k should scope over the whole definition+extractDataDefnKindVars (HsDataDefn { dd_ctxt = ctxt, dd_kindSig = ksig+ , dd_cons = cons, dd_derivs = L _ derivs })+ = (nubL . freeKiTyVarsKindVars) <$>+ (extract_lctxt TypeLevel ctxt =<<+ extract_mb extract_lkind ksig =<<+ extract_sig_tys (concatMap (unLoc . deriv_clause_tys . unLoc) derivs) =<<+ foldrM (extract_con . unLoc) emptyFKTV cons)+ where+ extract_con (ConDeclGADT { }) acc = return acc+ extract_con (ConDeclH98 { con_qvars = qvs+ , con_cxt = ctxt, con_details = details }) acc+ = extract_hs_tv_bndrs (maybe [] hsQTvExplicit qvs) acc =<<+ extract_mlctxt ctxt =<<+ extract_ltys TypeLevel (hsConDeclArgTys details) emptyFKTV++extract_mlctxt :: Maybe (LHsContext RdrName) -> FreeKiTyVars -> RnM FreeKiTyVars+extract_mlctxt Nothing acc = return acc+extract_mlctxt (Just ctxt) acc = extract_lctxt TypeLevel ctxt acc++extract_lctxt :: TypeOrKind+ -> LHsContext RdrName -> FreeKiTyVars -> RnM FreeKiTyVars+extract_lctxt t_or_k ctxt = extract_ltys t_or_k (unLoc ctxt)++extract_sig_tys :: [LHsSigType RdrName] -> FreeKiTyVars -> RnM FreeKiTyVars+extract_sig_tys sig_tys acc+ = foldrM (\sig_ty acc -> extract_lty TypeLevel (hsSigType sig_ty) acc)+ acc sig_tys++extract_ltys :: TypeOrKind+ -> [LHsType RdrName] -> FreeKiTyVars -> RnM FreeKiTyVars+extract_ltys t_or_k tys acc = foldrM (extract_lty t_or_k) acc tys++extract_mb :: (a -> FreeKiTyVars -> RnM FreeKiTyVars)+ -> Maybe a -> FreeKiTyVars -> RnM FreeKiTyVars+extract_mb _ Nothing acc = return acc+extract_mb f (Just x) acc = f x acc++extract_lkind :: LHsType RdrName -> FreeKiTyVars -> RnM FreeKiTyVars+extract_lkind = extract_lty KindLevel++extract_lty :: TypeOrKind -> LHsType RdrName -> FreeKiTyVars -> RnM FreeKiTyVars+extract_lty t_or_k (L _ ty) acc+ = case ty of+ HsTyVar _ ltv -> extract_tv t_or_k ltv acc+ HsBangTy _ ty -> extract_lty t_or_k ty acc+ HsRecTy flds -> foldrM (extract_lty t_or_k+ . cd_fld_type . unLoc) acc+ flds+ HsAppsTy tys -> extract_apps t_or_k tys acc+ HsAppTy ty1 ty2 -> extract_lty t_or_k ty1 =<<+ extract_lty t_or_k ty2 acc+ HsListTy ty -> extract_lty t_or_k ty acc+ HsPArrTy ty -> extract_lty t_or_k ty acc+ HsTupleTy _ tys -> extract_ltys t_or_k tys acc+ HsSumTy tys -> extract_ltys t_or_k tys acc+ HsFunTy ty1 ty2 -> extract_lty t_or_k ty1 =<<+ extract_lty t_or_k ty2 acc+ HsIParamTy _ ty -> extract_lty t_or_k ty acc+ HsEqTy ty1 ty2 -> extract_lty t_or_k ty1 =<<+ extract_lty t_or_k ty2 acc+ HsOpTy ty1 tv ty2 -> extract_tv t_or_k tv =<<+ extract_lty t_or_k ty1 =<<+ extract_lty t_or_k ty2 acc+ HsParTy ty -> extract_lty t_or_k ty acc+ HsCoreTy {} -> return acc -- The type is closed+ HsSpliceTy {} -> return acc -- Type splices mention no tvs+ HsDocTy ty _ -> extract_lty t_or_k ty acc+ HsExplicitListTy _ _ tys -> extract_ltys t_or_k tys acc+ HsExplicitTupleTy _ tys -> extract_ltys t_or_k tys acc+ HsTyLit _ -> return acc+ HsKindSig ty ki -> extract_lty t_or_k ty =<<+ extract_lkind ki acc+ HsForAllTy { hst_bndrs = tvs, hst_body = ty }+ -> extract_hs_tv_bndrs tvs acc =<<+ extract_lty t_or_k ty emptyFKTV+ HsQualTy { hst_ctxt = ctxt, hst_body = ty }+ -> extract_lctxt t_or_k ctxt =<<+ extract_lty t_or_k ty acc+ -- We deal with these separately in rnLHsTypeWithWildCards+ HsWildCardTy {} -> return acc++extract_apps :: TypeOrKind+ -> [LHsAppType RdrName] -> FreeKiTyVars -> RnM FreeKiTyVars+extract_apps t_or_k tys acc = foldrM (extract_app t_or_k) acc tys++extract_app :: TypeOrKind -> LHsAppType RdrName -> FreeKiTyVars+ -> RnM FreeKiTyVars+extract_app t_or_k (L _ (HsAppInfix tv)) acc = extract_tv t_or_k tv acc+extract_app t_or_k (L _ (HsAppPrefix ty)) acc = extract_lty t_or_k ty acc++extract_hs_tv_bndrs :: [LHsTyVarBndr RdrName] -> FreeKiTyVars+ -> FreeKiTyVars -> RnM FreeKiTyVars+-- In (forall (a :: Maybe e). a -> b) we have+-- 'a' is bound by the forall+-- 'b' is a free type variable+-- 'e' is a free kind variable+extract_hs_tv_bndrs tvs+ (FKTV acc_kvs acc_tvs)+ -- Note accumulator comes first+ (FKTV body_kvs body_tvs)+ | null tvs+ = return $+ FKTV (body_kvs ++ acc_kvs) (body_tvs ++ acc_tvs)+ | otherwise+ = do { FKTV bndr_kvs _+ <- foldrM extract_lkind emptyFKTV [k | L _ (KindedTyVar _ k) <- tvs]++ ; let locals = map hsLTyVarName tvs+ ; return $+ FKTV (filterOut ((`elem` locals) . unLoc) (bndr_kvs ++ body_kvs)+ ++ acc_kvs)+ (filterOut ((`elem` locals) . unLoc) body_tvs ++ acc_tvs) }++extract_tv :: TypeOrKind -> Located RdrName -> FreeKiTyVars -> RnM FreeKiTyVars+extract_tv t_or_k ltv@(L _ tv) acc+ | isRdrTyVar tv = case acc of+ FKTV kvs tvs+ | isTypeLevel t_or_k+ -> do { when (ltv `elemRdr` kvs) $+ mixedVarsErr ltv+ ; return (FKTV kvs (ltv : tvs)) }+ | otherwise+ -> do { when (ltv `elemRdr` tvs) $+ mixedVarsErr ltv+ ; return (FKTV (ltv : kvs) tvs) }+ | otherwise = return acc+ where+ elemRdr x = any (eqLocated x)++mixedVarsErr :: Located RdrName -> RnM ()+mixedVarsErr (L loc tv)+ = do { typeintype <- xoptM LangExt.TypeInType+ ; unless typeintype $+ addErrAt loc $ text "Variable" <+> quotes (ppr tv) <+>+ text "used as both a kind and a type" $$+ text "Did you intend to use TypeInType?" }++-- just used in this module; seemed convenient here+nubL :: Eq a => [Located a] -> [Located a]+nubL = nubBy eqLocated
+ simplCore/CSE.hs view
@@ -0,0 +1,601 @@+{-+(c) The AQUA Project, Glasgow University, 1993-1998++\section{Common subexpression}+-}++{-# LANGUAGE CPP #-}++module CSE (cseProgram, cseOneExpr) where++#include "HsVersions.h"++import CoreSubst+import Var ( Var )+import VarEnv ( elemInScopeSet )+import Id ( Id, idType, idInlineActivation, isDeadBinder+ , zapIdOccInfo, zapIdUsageInfo, idInlinePragma+ , isJoinId )+import CoreUtils ( mkAltExpr, eqExpr+ , exprIsLiteralString+ , stripTicksE, stripTicksT, mkTicks )+import Type ( tyConAppArgs )+import CoreSyn+import Outputable+import BasicTypes ( TopLevelFlag(..), isTopLevel+ , isAlwaysActive, isAnyInlinePragma )+import TrieMap+import Util ( filterOut )+import Data.List ( mapAccumL )++{-+ Simple common sub-expression+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we see+ x1 = C a b+ x2 = C x1 b+we build up a reverse mapping: C a b -> x1+ C x1 b -> x2+and apply that to the rest of the program.++When we then see+ y1 = C a b+ y2 = C y1 b+we replace the C a b with x1. But then we *dont* want to+add x1 -> y1 to the mapping. Rather, we want the reverse, y1 -> x1+so that a subsequent binding+ y2 = C y1 b+will get transformed to C x1 b, and then to x2.++So we carry an extra var->var substitution which we apply *before* looking up in the+reverse mapping.+++Note [Shadowing]+~~~~~~~~~~~~~~~~+We have to be careful about shadowing.+For example, consider+ f = \x -> let y = x+x in+ h = \x -> x+x+ in ...++Here we must *not* do CSE on the inner x+x! The simplifier used to guarantee no+shadowing, but it doesn't any more (it proved too hard), so we clone as we go.+We can simply add clones to the substitution already described.+++Note [CSE for bindings]+~~~~~~~~~~~~~~~~~~~~~~~+Let-bindings have two cases, implemented by addBinding.++* SUBSTITUTE: applies when the RHS is a variable++ let x = y in ...(h x)....++ Here we want to extend the /substitution/ with x -> y, so that the+ (h x) in the body might CSE with an enclosing (let v = h y in ...).+ NB: the substitution maps InIds, so we extend the substitution with+ a binding for the original InId 'x'++ How can we have a variable on the RHS? Doesn't the simplifier inline them?++ - First, the original RHS might have been (g z) which has CSE'd+ with an enclosing (let y = g z in ...). This is super-important.+ See Trac #5996:+ x1 = C a b+ x2 = C x1 b+ y1 = C a b+ y2 = C y1 b+ Here we CSE y1's rhs to 'x1', and then we must add (y1->x1) to+ the substitution so that we can CSE the binding for y2.++ - Second, we use addBinding for case expression scrutinees too;+ see Note [CSE for case expressions]++* EXTEND THE REVERSE MAPPING: applies in all other cases++ let x = h y in ...(h y)...++ Here we want to extend the /reverse mapping (cs_map)/ so that+ we CSE the (h y) call to x.++ Note that we use EXTEND even for a trivial expression, provided it+ is not a variable or literal. In particular this /includes/ type+ applications. This can be important (Trac #13156); e.g.+ case f @ Int of { r1 ->+ case f @ Int of { r2 -> ...+ Here we want to common-up the two uses of (f @ Int) so we can+ remove one of the case expressions.++ See also Note [Corner case for case expressions] for another+ reason not to use SUBSTITUTE for all trivial expressions.++Notice that+ - The SUBSTITUTE situation extends the substitution (cs_subst)+ - The EXTEND situation extends the reverse mapping (cs_map)++Notice also that in the SUBSTITUTE case we leave behind a binding+ x = y+even though we /also/ carry a substitution x -> y. Can we just drop+the binding instead? Well, not at top level! See SimplUtils+Note [Top level and postInlineUnconditionally]; and in any case CSE+applies only to the /bindings/ of the program, and we leave it to the+simplifier to propate effects to the RULES. Finally, it doesn't seem+worth the effort to discard the nested bindings because the simplifier+will do it next.++Note [CSE for case expressions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ case scrut_expr of x { ...alts... }+This is very like a strict let-binding+ let !x = scrut_expr in ...+So we use (addBinding x scrut_expr) to process scrut_expr and x, and as a+result all the stuff under Note [CSE for bindings] applies directly.++For example:++* Trivial scrutinee+ f = \x -> case x of wild {+ (a:as) -> case a of wild1 {+ (p,q) -> ...(wild1:as)...++ Here, (wild1:as) is morally the same as (a:as) and hence equal to+ wild. But that's not quite obvious. In the rest of the compiler we+ want to keep it as (wild1:as), but for CSE purpose that's a bad+ idea.++ By using addBinding we add the binding (wild1 -> a) to the substitution,+ which does exactly the right thing.++ (Notice this is exactly backwards to what the simplifier does, which+ is to try to replaces uses of 'a' with uses of 'wild1'.)++ This is the main reason that addBinding is called with a trivial rhs.++* Non-trivial scrutinee+ case (f x) of y { pat -> ...let y = f x in ... }++ By using addBinding we'll add (f x :-> y) to the cs_map, and+ thereby CSE the inner (f x) to y.++Note [CSE for INLINE and NOINLINE]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There are some subtle interactions of CSE with functions that the user+has marked as INLINE or NOINLINE. (Examples from Roman Leshchinskiy.)+Consider++ yes :: Int {-# NOINLINE yes #-}+ yes = undefined++ no :: Int {-# NOINLINE no #-}+ no = undefined++ foo :: Int -> Int -> Int {-# NOINLINE foo #-}+ foo m n = n++ {-# RULES "foo/no" foo no = id #-}++ bar :: Int -> Int+ bar = foo yes++We do not expect the rule to fire. But if we do CSE, then we risk+getting yes=no, and the rule does fire. Actually, it won't because+NOINLINE means that 'yes' will never be inlined, not even if we have+yes=no. So that's fine (now; perhaps in the olden days, yes=no would+have substituted even if 'yes' was NOINLINE).++But we do need to take care. Consider++ {-# NOINLINE bar #-}+ bar = <rhs> -- Same rhs as foo++ foo = <rhs>++If CSE produces+ foo = bar+then foo will never be inlined to <rhs> (when it should be, if <rhs>+is small). The conclusion here is this:++ We should not add+ <rhs> :-> bar+ to the CSEnv if 'bar' has any constraints on when it can inline;+ that is, if its 'activation' not always active. Otherwise we+ might replace <rhs> by 'bar', and then later be unable to see that it+ really was <rhs>.++Note that we do not (currently) do CSE on the unfolding stored inside+an Id, even if is a 'stable' unfolding. That means that when an+unfolding happens, it is always faithful to what the stable unfolding+originally was.++Note [CSE for stable unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ {-# Unf = Stable (\pq. build blah) #-}+ foo = x++Here 'foo' has a stable unfolding, but its (optimised) RHS is trivial.+(Turns out that this actually happens for the enumFromTo method of+the Integer instance of Enum in GHC.Enum.) Suppose moreover that foo's+stable unfolding originates from an INLINE or INLINEABLE pragma on foo.+Then we obviously do NOT want to extend the substitution with (foo->x),+because we promised to inline foo as what the user wrote. See similar+SimplUtils Note [Stable unfoldings and postInlineUnconditionally].++Nor do we want to change the reverse mapping. Suppose we have++ {-# Unf = Stable (\pq. build blah) #-}+ foo = <expr>+ bar = <expr>++There could conceivably be merit in rewriting the RHS of bar:+ bar = foo+but now bar's inlining behaviour will change, and importing+modules might see that. So it seems dodgy and we don't do it.++Stable unfoldings are also created during worker/wrapper when we decide+that a function's definition is so small that it should always inline.+In this case we still want to do CSE (#13340). Hence the use of+isAnyInlinePragma rather than isStableUnfolding.++Note [Corner case for case expressions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is another reason that we do not use SUBSTITUTE for+all trivial expressions. Consider+ case x |> co of (y::Array# Int) { ... }++We do not want to extend the substitution with (y -> x |> co); since y+is of unlifted type, this would destroy the let/app invariant if (x |>+co) was not ok-for-speculation.++But surely (x |> co) is ok-for-speculation, becasue it's a trivial+expression, and x's type is also unlifted, presumably. Well, maybe+not if you are using unsafe casts. I actually found a case where we+had+ (x :: HValue) |> (UnsafeCo :: HValue ~ Array# Int)++Note [CSE for join points?]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must not be naive about join points in CSE:+ join j = e in+ if b then jump j else 1 + e+The expression (1 + jump j) is not good (see Note [Invariants on join points] in+CoreSyn). This seems to come up quite seldom, but it happens (first seen+compiling ppHtml in Haddock.Backends.Xhtml).++We could try and be careful by tracking which join points are still valid at+each subexpression, but since join points aren't allocated or shared, there's+less to gain by trying to CSE them.++Note [CSE for recursive bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f = \x ... f....+ g = \y ... g ...+where the "..." are identical. Could we CSE them? In full generality+with mutual recursion it's quite hard; but for self-recursive bindings+(which are very common) it's rather easy:++* Maintain a separate cs_rec_map, that maps+ (\f. (\x. ...f...) ) -> f+ Note the \f in the domain of the mapping!++* When we come across the binding for 'g', look up (\g. (\y. ...g...))+ Bingo we get a hit. So we can replace the 'g' binding with+ g = f++We can't use cs_map for this, because the key isn't an expression of+the program; it's a kind of synthetic key for recursive bindings.+++************************************************************************+* *+\section{Common subexpression}+* *+************************************************************************+-}++cseProgram :: CoreProgram -> CoreProgram+cseProgram binds = snd (mapAccumL (cseBind TopLevel) emptyCSEnv binds)++cseBind :: TopLevelFlag -> CSEnv -> CoreBind -> (CSEnv, CoreBind)+cseBind toplevel env (NonRec b e)+ = (env2, NonRec b2 e2)+ where+ (env1, b1) = addBinder env b+ (env2, (b2, e2)) = cse_bind toplevel env1 (b,e) b1++cseBind _ env (Rec [(in_id, rhs)])+ | noCSE in_id+ = (env1, Rec [(out_id, rhs')])++ -- See Note [CSE for recursive bindings]+ | Just previous <- lookupCSRecEnv env out_id rhs''+ , let previous' = mkTicks ticks previous+ = (extendCSSubst env1 in_id previous', NonRec out_id previous')++ | otherwise+ = (extendCSRecEnv env1 out_id rhs'' id_expr', Rec [(zapped_id, rhs')])++ where+ (env1, [out_id]) = addRecBinders env [in_id]+ rhs' = cseExpr env1 rhs+ rhs'' = stripTicksE tickishFloatable rhs'+ ticks = stripTicksT tickishFloatable rhs'+ id_expr' = varToCoreExpr out_id+ zapped_id = zapIdUsageInfo out_id++cseBind toplevel env (Rec pairs)+ = (env2, Rec pairs')+ where+ (env1, bndrs1) = addRecBinders env (map fst pairs)+ (env2, pairs') = mapAccumL do_one env1 (zip pairs bndrs1)++ do_one env (pr, b1) = cse_bind toplevel env pr b1++cse_bind :: TopLevelFlag -> CSEnv -> (InId, InExpr) -> OutId -> (CSEnv, (OutId, OutExpr))+cse_bind toplevel env (in_id, in_rhs) out_id+ | isTopLevel toplevel, exprIsLiteralString in_rhs+ -- See Note [Take care with literal strings]+ = (env', (out_id, in_rhs))++ | otherwise+ = (env', (out_id', out_rhs))+ where+ out_rhs = tryForCSE env in_rhs+ (env', out_id') = addBinding env in_id out_id out_rhs++addBinding :: CSEnv -- Includes InId->OutId cloning+ -> InVar -- Could be a let-bound type+ -> OutId -> OutExpr -- Processed binding+ -> (CSEnv, OutId) -- Final env, final bndr+-- Extend the CSE env with a mapping [rhs -> out-id]+-- unless we can instead just substitute [in-id -> rhs]+--+-- It's possible for the binder to be a type variable (see+-- Note [Type-let] in CoreSyn), in which case we can just substitute.+addBinding env in_id out_id rhs'+ | not (isId in_id) = (extendCSSubst env in_id rhs', out_id)+ | noCSE in_id = (env, out_id)+ | use_subst = (extendCSSubst env in_id rhs', out_id)+ | otherwise = (extendCSEnv env rhs' id_expr', zapped_id)+ where+ id_expr' = varToCoreExpr out_id+ zapped_id = zapIdUsageInfo out_id+ -- Putting the Id into the cs_map makes it possible that+ -- it'll become shared more than it is now, which would+ -- invalidate (the usage part of) its demand info.+ -- This caused Trac #100218.+ -- Easiest thing is to zap the usage info; subsequently+ -- performing late demand-analysis will restore it. Don't zap+ -- the strictness info; it's not necessary to do so, and losing+ -- it is bad for performance if you don't do late demand+ -- analysis++ -- Should we use SUBSTITUTE or EXTEND?+ -- See Note [CSE for bindings]+ use_subst = case rhs' of+ Var {} -> True+ _ -> False++noCSE :: InId -> Bool+noCSE id = not (isAlwaysActive (idInlineActivation id))+ -- See Note [CSE for INLINE and NOINLINE]+ || isAnyInlinePragma (idInlinePragma id)+ -- See Note [CSE for stable unfoldings]+ || isJoinId id+ -- See Note [CSE for join points?]+++{- Note [Take care with literal strings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this example:++ x = "foo"#+ y = "foo"#+ ...x...y...x...y....++We would normally turn this into:++ x = "foo"#+ y = x+ ...x...x...x...x....++But this breaks an invariant of Core, namely that the RHS of a top-level binding+of type Addr# must be a string literal, not another variable. See Note+[CoreSyn top-level string literals] in CoreSyn.++For this reason, we special case top-level bindings to literal strings and leave+the original RHS unmodified. This produces:++ x = "foo"#+ y = "foo"#+ ...x...x...x...x....++Now 'y' will be discarded as dead code, and we are done.++The net effect is that for the y-binding we want to+ - Use SUBSTITUTE, by extending the substitution with y :-> x+ - but leave the original binding for y undisturbed++This is done by cse_bind. I got it wrong the first time (Trac #13367).+-}++tryForCSE :: CSEnv -> InExpr -> OutExpr+tryForCSE env expr+ | Just e <- lookupCSEnv env expr'' = mkTicks ticks e+ | otherwise = expr'+ -- The varToCoreExpr is needed if we have+ -- case e of xco { ...case e of yco { ... } ... }+ -- Then CSE will substitute yco -> xco;+ -- but these are /coercion/ variables+ where+ expr' = cseExpr env expr+ expr'' = stripTicksE tickishFloatable expr'+ ticks = stripTicksT tickishFloatable expr'+ -- We don't want to lose the source notes when a common sub+ -- expression gets eliminated. Hence we push all (!) of them on+ -- top of the replaced sub-expression. This is probably not too+ -- useful in practice, but upholds our semantics.++cseOneExpr :: InExpr -> OutExpr+cseOneExpr = cseExpr emptyCSEnv++cseExpr :: CSEnv -> InExpr -> OutExpr+cseExpr env (Type t) = Type (substTy (csEnvSubst env) t)+cseExpr env (Coercion c) = Coercion (substCo (csEnvSubst env) c)+cseExpr _ (Lit lit) = Lit lit+cseExpr env (Var v) = lookupSubst env v+cseExpr env (App f a) = App (cseExpr env f) (tryForCSE env a)+cseExpr env (Tick t e) = Tick t (cseExpr env e)+cseExpr env (Cast e co) = Cast (cseExpr env e) (substCo (csEnvSubst env) co)+cseExpr env (Lam b e) = let (env', b') = addBinder env b+ in Lam b' (cseExpr env' e)+cseExpr env (Let bind e) = let (env', bind') = cseBind NotTopLevel env bind+ in Let bind' (cseExpr env' e)+cseExpr env (Case e bndr ty alts) = cseCase env e bndr ty alts++cseCase :: CSEnv -> InExpr -> InId -> InType -> [InAlt] -> OutExpr+cseCase env scrut bndr ty alts+ = Case scrut1 bndr3 ty' $+ combineAlts alt_env (map cse_alt alts)+ where+ ty' = substTy (csEnvSubst env) ty+ scrut1 = tryForCSE env scrut++ bndr1 = zapIdOccInfo bndr+ -- Zapping the OccInfo is needed because the extendCSEnv+ -- in cse_alt may mean that a dead case binder+ -- becomes alive, and Lint rejects that+ (env1, bndr2) = addBinder env bndr1+ (alt_env, bndr3) = addBinding env1 bndr bndr2 scrut1+ -- addBinding: see Note [CSE for case expressions]++ con_target :: OutExpr+ con_target = lookupSubst alt_env bndr++ arg_tys :: [OutType]+ arg_tys = tyConAppArgs (idType bndr3)++ cse_alt (DataAlt con, args, rhs)+ | not (null args)+ -- Don't try CSE if there are no args; it just increases the number+ -- of live vars. E.g.+ -- case x of { True -> ....True.... }+ -- Don't replace True by x!+ -- Hence the 'null args', which also deal with literals and DEFAULT+ = (DataAlt con, args', tryForCSE new_env rhs)+ where+ (env', args') = addBinders alt_env args+ new_env = extendCSEnv env' con_expr con_target+ con_expr = mkAltExpr (DataAlt con) args' arg_tys++ cse_alt (con, args, rhs)+ = (con, args', tryForCSE env' rhs)+ where+ (env', args') = addBinders alt_env args++combineAlts :: CSEnv -> [InAlt] -> [InAlt]+-- See Note [Combine case alternatives]+combineAlts env ((_,bndrs1,rhs1) : rest_alts)+ | all isDeadBinder bndrs1+ = (DEFAULT, [], rhs1) : filtered_alts+ where+ in_scope = substInScope (csEnvSubst env)+ filtered_alts = filterOut identical rest_alts+ identical (_con, bndrs, rhs) = all ok bndrs && eqExpr in_scope rhs1 rhs+ ok bndr = isDeadBinder bndr || not (bndr `elemInScopeSet` in_scope)++combineAlts _ alts = alts -- Default case++{- Note [Combine case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+combineAlts is just a more heavyweight version of the use of+combineIdentialAlts in SimplUtils.prepareAlts. The basic idea is+to transform++ DEFAULT -> e1+ K x -> e1+ W y z -> e2+===>+ DEFAULT -> e1+ W y z -> e2++In the simplifier we use cheapEqExpr, because it is called a lot.+But here in CSE we use the full eqExpr. After all, two alterantives usually+differ near the root, so it probably isn't expensive to compare the full+alternative. It seems like the the same kind of thing that CSE is supposed+to be doing, which is why I put it here.++I acutally saw some examples in the wild, where some inlining made e1 too+big for cheapEqExpr to catch it.+++************************************************************************+* *+\section{The CSE envt}+* *+************************************************************************+-}++data CSEnv+ = CS { cs_subst :: Subst -- Maps InBndrs to OutExprs+ -- The substitution variables to+ -- /trivial/ OutExprs, not arbitrary expressions++ , cs_map :: CoreMap OutExpr -- The reverse mapping+ -- Maps a OutExpr to a /trivial/ OutExpr+ -- The key of cs_map is stripped of all Ticks++ , cs_rec_map :: CoreMap OutExpr+ -- See Note [CSE for recursive bindings]+ }++emptyCSEnv :: CSEnv+emptyCSEnv = CS { cs_map = emptyCoreMap, cs_rec_map = emptyCoreMap+ , cs_subst = emptySubst }++lookupCSEnv :: CSEnv -> OutExpr -> Maybe OutExpr+lookupCSEnv (CS { cs_map = csmap }) expr+ = lookupCoreMap csmap expr++extendCSEnv :: CSEnv -> OutExpr -> OutExpr -> CSEnv+extendCSEnv cse expr triv_expr+ = cse { cs_map = extendCoreMap (cs_map cse) sexpr triv_expr }+ where+ sexpr = stripTicksE tickishFloatable expr++extendCSRecEnv :: CSEnv -> OutId -> OutExpr -> OutExpr -> CSEnv+-- See Note [CSE for recursive bindings]+extendCSRecEnv cse bndr expr triv_expr+ = cse { cs_rec_map = extendCoreMap (cs_rec_map cse) (Lam bndr expr) triv_expr }++lookupCSRecEnv :: CSEnv -> OutId -> OutExpr -> Maybe OutExpr+-- See Note [CSE for recursive bindings]+lookupCSRecEnv (CS { cs_rec_map = csmap }) bndr expr+ = lookupCoreMap csmap (Lam bndr expr)++csEnvSubst :: CSEnv -> Subst+csEnvSubst = cs_subst++lookupSubst :: CSEnv -> Id -> OutExpr+lookupSubst (CS { cs_subst = sub}) x = lookupIdSubst (text "CSE.lookupSubst") sub x++extendCSSubst :: CSEnv -> Id -> CoreExpr -> CSEnv+extendCSSubst cse x rhs = cse { cs_subst = extendSubst (cs_subst cse) x rhs }++addBinder :: CSEnv -> Var -> (CSEnv, Var)+addBinder cse v = (cse { cs_subst = sub' }, v')+ where+ (sub', v') = substBndr (cs_subst cse) v++addBinders :: CSEnv -> [Var] -> (CSEnv, [Var])+addBinders cse vs = (cse { cs_subst = sub' }, vs')+ where+ (sub', vs') = substBndrs (cs_subst cse) vs++addRecBinders :: CSEnv -> [Id] -> (CSEnv, [Id])+addRecBinders cse vs = (cse { cs_subst = sub' }, vs')+ where+ (sub', vs') = substRecBndrs (cs_subst cse) vs
+ simplCore/CallArity.hs view
@@ -0,0 +1,739 @@+--+-- Copyright (c) 2014 Joachim Breitner+--++module CallArity+ ( callArityAnalProgram+ , callArityRHS -- for testing+ ) where++import VarSet+import VarEnv+import DynFlags ( DynFlags )++import BasicTypes+import CoreSyn+import Id+import CoreArity ( typeArity )+import CoreUtils ( exprIsCheap, exprIsTrivial )+--import Outputable+import UnVarGraph+import Demand++import Control.Arrow ( first, second )+++{-+%************************************************************************+%* *+ Call Arity Analyis+%* *+%************************************************************************++Note [Call Arity: The goal]+~~~~~~~~~~~~~~~~~~~~~~~~~~~++The goal of this analysis is to find out if we can eta-expand a local function,+based on how it is being called. The motivating example is this code,+which comes up when we implement foldl using foldr, and do list fusion:++ let go = \x -> let d = case ... of+ False -> go (x+1)+ True -> id+ in \z -> d (x + z)+ in go 1 0++If we do not eta-expand `go` to have arity 2, we are going to allocate a lot of+partial function applications, which would be bad.++The function `go` has a type of arity two, but only one lambda is manifest.+Furthermore, an analysis that only looks at the RHS of go cannot be sufficient+to eta-expand go: If `go` is ever called with one argument (and the result used+multiple times), we would be doing the work in `...` multiple times.++So `callArityAnalProgram` looks at the whole let expression to figure out if+all calls are nice, i.e. have a high enough arity. It then stores the result in+the `calledArity` field of the `IdInfo` of `go`, which the next simplifier+phase will eta-expand.++The specification of the `calledArity` field is:++ No work will be lost if you eta-expand me to the arity in `calledArity`.++What we want to know for a variable+-----------------------------------++For every let-bound variable we'd like to know:+ 1. A lower bound on the arity of all calls to the variable, and+ 2. whether the variable is being called at most once or possible multiple+ times.++It is always ok to lower the arity, or pretend that there are multiple calls.+In particular, "Minimum arity 0 and possible called multiple times" is always+correct.+++What we want to know from an expression+---------------------------------------++In order to obtain that information for variables, we analyize expression and+obtain bits of information:++ I. The arity analysis:+ For every variable, whether it is absent, or called,+ and if called, which what arity.++ II. The Co-Called analysis:+ For every two variables, whether there is a possibility that both are being+ called.+ We obtain as a special case: For every variables, whether there is a+ possibility that it is being called twice.++For efficiency reasons, we gather this information only for a set of+*interesting variables*, to avoid spending time on, e.g., variables from pattern matches.++The two analysis are not completely independent, as a higher arity can improve+the information about what variables are being called once or multiple times.++Note [Analysis I: The arity analyis]+------------------------------------++The arity analysis is quite straight forward: The information about an+expression is an+ VarEnv Arity+where absent variables are bound to Nothing and otherwise to a lower bound to+their arity.++When we analyize an expression, we analyize it with a given context arity.+Lambdas decrease and applications increase the incoming arity. Analysizing a+variable will put that arity in the environment. In lets or cases all the+results from the various subexpressions are lubed, which takes the point-wise+minimum (considering Nothing an infinity).+++Note [Analysis II: The Co-Called analysis]+------------------------------------------++The second part is more sophisticated. For reasons explained below, it is not+sufficient to simply know how often an expression evaluates a variable. Instead+we need to know which variables are possibly called together.++The data structure here is an undirected graph of variables, which is provided+by the abstract+ UnVarGraph++It is safe to return a larger graph, i.e. one with more edges. The worst case+(i.e. the least useful and always correct result) is the complete graph on all+free variables, which means that anything can be called together with anything+(including itself).++Notation for the following:+C(e) is the co-called result for e.+G₁∪G₂ is the union of two graphs+fv is the set of free variables (conveniently the domain of the arity analysis result)+S₁×S₂ is the complete bipartite graph { {a,b} | a ∈ S₁, b ∈ S₂ }+S² is the complete graph on the set of variables S, S² = S×S+C'(e) is a variant for bound expression:+ If e is called at most once, or it is and stays a thunk (after the analysis),+ it is simply C(e). Otherwise, the expression can be called multiple times+ and we return (fv e)²++The interesting cases of the analysis:+ * Var v:+ No other variables are being called.+ Return {} (the empty graph)+ * Lambda v e, under arity 0:+ This means that e can be evaluated many times and we cannot get+ any useful co-call information.+ Return (fv e)²+ * Case alternatives alt₁,alt₂,...:+ Only one can be execuded, so+ Return (alt₁ ∪ alt₂ ∪...)+ * App e₁ e₂ (and analogously Case scrut alts), with non-trivial e₂:+ We get the results from both sides, with the argument evaluated at most once.+ Additionally, anything called by e₁ can possibly be called with anything+ from e₂.+ Return: C(e₁) ∪ C(e₂) ∪ (fv e₁) × (fv e₂)+ * App e₁ x:+ As this is already in A-normal form, CorePrep will not separately lambda+ bind (and hence share) x. So we conservatively assume multiple calls to x here+ Return: C(e₁) ∪ (fv e₁) × {x} ∪ {(x,x)}+ * Let v = rhs in body:+ In addition to the results from the subexpressions, add all co-calls from+ everything that the body calls together with v to everthing that is called+ by v.+ Return: C'(rhs) ∪ C(body) ∪ (fv rhs) × {v'| {v,v'} ∈ C(body)}+ * Letrec v₁ = rhs₁ ... vₙ = rhsₙ in body+ Tricky.+ We assume that it is really mutually recursive, i.e. that every variable+ calls one of the others, and that this is strongly connected (otherwise we+ return an over-approximation, so that's ok), see note [Recursion and fixpointing].++ Let V = {v₁,...vₙ}.+ Assume that the vs have been analysed with an incoming demand and+ cardinality consistent with the final result (this is the fixed-pointing).+ Again we can use the results from all subexpressions.+ In addition, for every variable vᵢ, we need to find out what it is called+ with (call this set Sᵢ). There are two cases:+ * If vᵢ is a function, we need to go through all right-hand-sides and bodies,+ and collect every variable that is called together with any variable from V:+ Sᵢ = {v' | j ∈ {1,...,n}, {v',vⱼ} ∈ C'(rhs₁) ∪ ... ∪ C'(rhsₙ) ∪ C(body) }+ * If vᵢ is a thunk, then its rhs is evaluated only once, so we need to+ exclude it from this set:+ Sᵢ = {v' | j ∈ {1,...,n}, j≠i, {v',vⱼ} ∈ C'(rhs₁) ∪ ... ∪ C'(rhsₙ) ∪ C(body) }+ Finally, combine all this:+ Return: C(body) ∪+ C'(rhs₁) ∪ ... ∪ C'(rhsₙ) ∪+ (fv rhs₁) × S₁) ∪ ... ∪ (fv rhsₙ) × Sₙ)++Using the result: Eta-Expansion+-------------------------------++We use the result of these two analyses to decide whether we can eta-expand the+rhs of a let-bound variable.++If the variable is already a function (exprIsCheap), and all calls to the+variables have a higher arity than the current manifest arity (i.e. the number+of lambdas), expand.++If the variable is a thunk we must be careful: Eta-Expansion will prevent+sharing of work, so this is only safe if there is at most one call to the+function. Therefore, we check whether {v,v} ∈ G.++ Example:++ let n = case .. of .. -- A thunk!+ in n 0 + n 1++ vs.++ let n = case .. of ..+ in case .. of T -> n 0+ F -> n 1++ We are only allowed to eta-expand `n` if it is going to be called at most+ once in the body of the outer let. So we need to know, for each variable+ individually, that it is going to be called at most once.+++Why the co-call graph?+----------------------++Why is it not sufficient to simply remember which variables are called once and+which are called multiple times? It would be in the previous example, but consider++ let n = case .. of ..+ in case .. of+ True -> let go = \y -> case .. of+ True -> go (y + n 1)+ False > n+ in go 1+ False -> n++vs.++ let n = case .. of ..+ in case .. of+ True -> let go = \y -> case .. of+ True -> go (y+1)+ False > n+ in go 1+ False -> n++In both cases, the body and the rhs of the inner let call n at most once.+But only in the second case that holds for the whole expression! The+crucial difference is that in the first case, the rhs of `go` can call+*both* `go` and `n`, and hence can call `n` multiple times as it recurses,+while in the second case find out that `go` and `n` are not called together.+++Why co-call information for functions?+--------------------------------------++Although for eta-expansion we need the information only for thunks, we still+need to know whether functions are being called once or multiple times, and+together with what other functions.++ Example:++ let n = case .. of ..+ f x = n (x+1)+ in f 1 + f 2++ vs.++ let n = case .. of ..+ f x = n (x+1)+ in case .. of T -> f 0+ F -> f 1++ Here, the body of f calls n exactly once, but f itself is being called+ multiple times, so eta-expansion is not allowed.+++Note [Analysis type signature]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The work-hourse of the analysis is the function `callArityAnal`, with the+following type:++ type CallArityRes = (UnVarGraph, VarEnv Arity)+ callArityAnal ::+ Arity -> -- The arity this expression is called with+ VarSet -> -- The set of interesting variables+ CoreExpr -> -- The expression to analyse+ (CallArityRes, CoreExpr)++and the following specification:++ ((coCalls, callArityEnv), expr') = callArityEnv arity interestingIds expr++ <=>++ Assume the expression `expr` is being passed `arity` arguments. Then it holds that+ * The domain of `callArityEnv` is a subset of `interestingIds`.+ * Any variable from `interestingIds` that is not mentioned in the `callArityEnv`+ is absent, i.e. not called at all.+ * Every call from `expr` to a variable bound to n in `callArityEnv` has at+ least n value arguments.+ * For two interesting variables `v1` and `v2`, they are not adjacent in `coCalls`,+ then in no execution of `expr` both are being called.+ Furthermore, expr' is expr with the callArity field of the `IdInfo` updated.+++Note [Which variables are interesting]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The analysis would quickly become prohibitive expensive if we would analyse all+variables; for most variables we simply do not care about how often they are+called, i.e. variables bound in a pattern match. So interesting are variables that are+ * top-level or let bound+ * and possibly functions (typeArity > 0)++Note [Taking boring variables into account]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++If we decide that the variable bound in `let x = e1 in e2` is not interesting,+the analysis of `e2` will not report anything about `x`. To ensure that+`callArityBind` does still do the right thing we have to take that into account+everytime we would be lookup up `x` in the analysis result of `e2`.+ * Instead of calling lookupCallArityRes, we return (0, True), indicating+ that this variable might be called many times with no arguments.+ * Instead of checking `calledWith x`, we assume that everything can be called+ with it.+ * In the recursive case, when calclulating the `cross_calls`, if there is+ any boring variable in the recursive group, we ignore all co-call-results+ and directly go to a very conservative assumption.++The last point has the nice side effect that the relatively expensive+integration of co-call results in a recursive groups is often skipped. This+helped to avoid the compile time blowup in some real-world code with large+recursive groups (#10293).++Note [Recursion and fixpointing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++For a mutually recursive let, we begin by+ 1. analysing the body, using the same incoming arity as for the whole expression.+ 2. Then we iterate, memoizing for each of the bound variables the last+ analysis call, i.e. incoming arity, whether it is called once, and the CallArityRes.+ 3. We combine the analysis result from the body and the memoized results for+ the arguments (if already present).+ 4. For each variable, we find out the incoming arity and whether it is called+ once, based on the the current analysis result. If this differs from the+ memoized results, we re-analyse the rhs and update the memoized table.+ 5. If nothing had to be reanalyzed, we are done.+ Otherwise, repeat from step 3.+++Note [Thunks in recursive groups]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We never eta-expand a thunk in a recursive group, on the grounds that if it is+part of a recursive group, then it will be called multipe times.++This is not necessarily true, e.g. it would be safe to eta-expand t2 (but not+t1) in the following code:++ let go x = t1+ t1 = if ... then t2 else ...+ t2 = if ... then go 1 else ...+ in go 0++Detecting this would require finding out what variables are only ever called+from thunks. While this is certainly possible, we yet have to see this to be+relevant in the wild.+++Note [Analysing top-level binds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We can eta-expand top-level-binds if they are not exported, as we see all calls+to them. The plan is as follows: Treat the top-level binds as nested lets around+a body representing “all external calls”, which returns a pessimistic+CallArityRes (the co-call graph is the complete graph, all arityies 0).++Note [Trimming arity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++In the Call Arity papers, we are working on an untyped lambda calculus with no+other id annotations, where eta-expansion is always possible. But this is not+the case for Core!+ 1. We need to ensure the invariant+ callArity e <= typeArity (exprType e)+ for the same reasons that exprArity needs this invariant (see Note+ [exprArity invariant] in CoreArity).++ If we are not doing that, a too-high arity annotation will be stored with+ the id, confusing the simplifier later on.++ 2. Eta-expanding a right hand side might invalidate existing annotations. In+ particular, if an id has a strictness annotation of <...><...>b, then+ passing two arguments to it will definitely bottom out, so the simplifier+ will throw away additional parameters. This conflicts with Call Arity! So+ we ensure that we never eta-expand such a value beyond the number of+ arguments mentioned in the strictness signature.+ See #10176 for a real-world-example.++Note [What is a thunk]+~~~~~~~~~~~~~~~~~~~~~~++Originally, everything that is not in WHNF (`exprIsWHNF`) is considered a+thunk, not eta-expanded, to avoid losing any sharing. This is also how the+published papers on Call Arity describe it.++In practice, there are thunks that do a just little work, such as+pattern-matching on a variable, and the benefits of eta-expansion likely+oughtweigh the cost of doing that repeatedly. Therefore, this implementation of+Call Arity considers everything that is not cheap (`exprIsCheap`) as a thunk.+-}++-- Main entry point++callArityAnalProgram :: DynFlags -> CoreProgram -> CoreProgram+callArityAnalProgram _dflags binds = binds'+ where+ (_, binds') = callArityTopLvl [] emptyVarSet binds++-- See Note [Analysing top-level-binds]+callArityTopLvl :: [Var] -> VarSet -> [CoreBind] -> (CallArityRes, [CoreBind])+callArityTopLvl exported _ []+ = ( calledMultipleTimes $ (emptyUnVarGraph, mkVarEnv $ [(v, 0) | v <- exported])+ , [] )+callArityTopLvl exported int1 (b:bs)+ = (ae2, b':bs')+ where+ int2 = bindersOf b+ exported' = filter isExportedId int2 ++ exported+ int' = int1 `addInterestingBinds` b+ (ae1, bs') = callArityTopLvl exported' int' bs+ (ae2, b') = callArityBind (boringBinds b) ae1 int1 b+++callArityRHS :: CoreExpr -> CoreExpr+callArityRHS = snd . callArityAnal 0 emptyVarSet++-- The main analysis function. See Note [Analysis type signature]+callArityAnal ::+ Arity -> -- The arity this expression is called with+ VarSet -> -- The set of interesting variables+ CoreExpr -> -- The expression to analyse+ (CallArityRes, CoreExpr)+ -- How this expression uses its interesting variables+ -- and the expression with IdInfo updated++-- The trivial base cases+callArityAnal _ _ e@(Lit _)+ = (emptyArityRes, e)+callArityAnal _ _ e@(Type _)+ = (emptyArityRes, e)+callArityAnal _ _ e@(Coercion _)+ = (emptyArityRes, e)+-- The transparent cases+callArityAnal arity int (Tick t e)+ = second (Tick t) $ callArityAnal arity int e+callArityAnal arity int (Cast e co)+ = second (\e -> Cast e co) $ callArityAnal arity int e++-- The interesting case: Variables, Lambdas, Lets, Applications, Cases+callArityAnal arity int e@(Var v)+ | v `elemVarSet` int+ = (unitArityRes v arity, e)+ | otherwise+ = (emptyArityRes, e)++-- Non-value lambdas are ignored+callArityAnal arity int (Lam v e) | not (isId v)+ = second (Lam v) $ callArityAnal arity (int `delVarSet` v) e++-- We have a lambda that may be called multiple times, so its free variables+-- can all be co-called.+callArityAnal 0 int (Lam v e)+ = (ae', Lam v e')+ where+ (ae, e') = callArityAnal 0 (int `delVarSet` v) e+ ae' = calledMultipleTimes ae+-- We have a lambda that we are calling. decrease arity.+callArityAnal arity int (Lam v e)+ = (ae, Lam v e')+ where+ (ae, e') = callArityAnal (arity - 1) (int `delVarSet` v) e++-- Application. Increase arity for the called expression, nothing to know about+-- the second+callArityAnal arity int (App e (Type t))+ = second (\e -> App e (Type t)) $ callArityAnal arity int e+callArityAnal arity int (App e1 e2)+ = (final_ae, App e1' e2')+ where+ (ae1, e1') = callArityAnal (arity + 1) int e1+ (ae2, e2') = callArityAnal 0 int e2+ -- If the argument is trivial (e.g. a variable), then it will _not_ be+ -- let-bound in the Core to STG transformation (CorePrep actually),+ -- so no sharing will happen here, and we have to assume many calls.+ ae2' | exprIsTrivial e2 = calledMultipleTimes ae2+ | otherwise = ae2+ final_ae = ae1 `both` ae2'++-- Case expression.+callArityAnal arity int (Case scrut bndr ty alts)+ = -- pprTrace "callArityAnal:Case"+ -- (vcat [ppr scrut, ppr final_ae])+ (final_ae, Case scrut' bndr ty alts')+ where+ (alt_aes, alts') = unzip $ map go alts+ go (dc, bndrs, e) = let (ae, e') = callArityAnal arity int e+ in (ae, (dc, bndrs, e'))+ alt_ae = lubRess alt_aes+ (scrut_ae, scrut') = callArityAnal 0 int scrut+ final_ae = scrut_ae `both` alt_ae++-- For lets, use callArityBind+callArityAnal arity int (Let bind e)+ = -- pprTrace "callArityAnal:Let"+ -- (vcat [ppr v, ppr arity, ppr n, ppr final_ae ])+ (final_ae, Let bind' e')+ where+ int_body = int `addInterestingBinds` bind+ (ae_body, e') = callArityAnal arity int_body e+ (final_ae, bind') = callArityBind (boringBinds bind) ae_body int bind++-- Which bindings should we look at?+-- See Note [Which variables are interesting]+isInteresting :: Var -> Bool+isInteresting v = not $ null (typeArity (idType v))++interestingBinds :: CoreBind -> [Var]+interestingBinds = filter isInteresting . bindersOf++boringBinds :: CoreBind -> VarSet+boringBinds = mkVarSet . filter (not . isInteresting) . bindersOf++addInterestingBinds :: VarSet -> CoreBind -> VarSet+addInterestingBinds int bind+ = int `delVarSetList` bindersOf bind -- Possible shadowing+ `extendVarSetList` interestingBinds bind++-- Used for both local and top-level binds+-- Second argument is the demand from the body+callArityBind :: VarSet -> CallArityRes -> VarSet -> CoreBind -> (CallArityRes, CoreBind)+-- Non-recursive let+callArityBind boring_vars ae_body int (NonRec v rhs)+ | otherwise+ = -- pprTrace "callArityBind:NonRec"+ -- (vcat [ppr v, ppr ae_body, ppr int, ppr ae_rhs, ppr safe_arity])+ (final_ae, NonRec v' rhs')+ where+ is_thunk = not (exprIsCheap rhs) -- see note [What is a thunk]+ -- If v is boring, we will not find it in ae_body, but always assume (0, False)+ boring = v `elemVarSet` boring_vars++ (arity, called_once)+ | boring = (0, False) -- See Note [Taking boring variables into account]+ | otherwise = lookupCallArityRes ae_body v+ safe_arity | called_once = arity+ | is_thunk = 0 -- A thunk! Do not eta-expand+ | otherwise = arity++ -- See Note [Trimming arity]+ trimmed_arity = trimArity v safe_arity++ (ae_rhs, rhs') = callArityAnal trimmed_arity int rhs+++ ae_rhs'| called_once = ae_rhs+ | safe_arity == 0 = ae_rhs -- If it is not a function, its body is evaluated only once+ | otherwise = calledMultipleTimes ae_rhs++ called_by_v = domRes ae_rhs'+ called_with_v+ | boring = domRes ae_body+ | otherwise = calledWith ae_body v `delUnVarSet` v+ final_ae = addCrossCoCalls called_by_v called_with_v $ ae_rhs' `lubRes` resDel v ae_body++ v' = v `setIdCallArity` trimmed_arity+++-- Recursive let. See Note [Recursion and fixpointing]+callArityBind boring_vars ae_body int b@(Rec binds)+ = -- (if length binds > 300 then+ -- pprTrace "callArityBind:Rec"+ -- (vcat [ppr (Rec binds'), ppr ae_body, ppr int, ppr ae_rhs]) else id) $+ (final_ae, Rec binds')+ where+ -- See Note [Taking boring variables into account]+ any_boring = any (`elemVarSet` boring_vars) [ i | (i, _) <- binds]++ int_body = int `addInterestingBinds` b+ (ae_rhs, binds') = fix initial_binds+ final_ae = bindersOf b `resDelList` ae_rhs++ initial_binds = [(i,Nothing,e) | (i,e) <- binds]++ fix :: [(Id, Maybe (Bool, Arity, CallArityRes), CoreExpr)] -> (CallArityRes, [(Id, CoreExpr)])+ fix ann_binds+ | -- pprTrace "callArityBind:fix" (vcat [ppr ann_binds, ppr any_change, ppr ae]) $+ any_change+ = fix ann_binds'+ | otherwise+ = (ae, map (\(i, _, e) -> (i, e)) ann_binds')+ where+ aes_old = [ (i,ae) | (i, Just (_,_,ae), _) <- ann_binds ]+ ae = callArityRecEnv any_boring aes_old ae_body++ rerun (i, mbLastRun, rhs)+ | i `elemVarSet` int_body && not (i `elemUnVarSet` domRes ae)+ -- No call to this yet, so do nothing+ = (False, (i, Nothing, rhs))++ | Just (old_called_once, old_arity, _) <- mbLastRun+ , called_once == old_called_once+ , new_arity == old_arity+ -- No change, no need to re-analyze+ = (False, (i, mbLastRun, rhs))++ | otherwise+ -- We previously analyzed this with a different arity (or not at all)+ = let is_thunk = not (exprIsCheap rhs) -- see note [What is a thunk]++ safe_arity | is_thunk = 0 -- See Note [Thunks in recursive groups]+ | otherwise = new_arity++ -- See Note [Trimming arity]+ trimmed_arity = trimArity i safe_arity++ (ae_rhs, rhs') = callArityAnal trimmed_arity int_body rhs++ ae_rhs' | called_once = ae_rhs+ | safe_arity == 0 = ae_rhs -- If it is not a function, its body is evaluated only once+ | otherwise = calledMultipleTimes ae_rhs++ in (True, (i `setIdCallArity` trimmed_arity, Just (called_once, new_arity, ae_rhs'), rhs'))+ where+ -- See Note [Taking boring variables into account]+ (new_arity, called_once) | i `elemVarSet` boring_vars = (0, False)+ | otherwise = lookupCallArityRes ae i++ (changes, ann_binds') = unzip $ map rerun ann_binds+ any_change = or changes++-- Combining the results from body and rhs, (mutually) recursive case+-- See Note [Analysis II: The Co-Called analysis]+callArityRecEnv :: Bool -> [(Var, CallArityRes)] -> CallArityRes -> CallArityRes+callArityRecEnv any_boring ae_rhss ae_body+ = -- (if length ae_rhss > 300 then pprTrace "callArityRecEnv" (vcat [ppr ae_rhss, ppr ae_body, ppr ae_new]) else id) $+ ae_new+ where+ vars = map fst ae_rhss++ ae_combined = lubRess (map snd ae_rhss) `lubRes` ae_body++ cross_calls+ -- See Note [Taking boring variables into account]+ | any_boring = completeGraph (domRes ae_combined)+ -- Also, calculating cross_calls is expensive. Simply be conservative+ -- if the mutually recursive group becomes too large.+ | length ae_rhss > 25 = completeGraph (domRes ae_combined)+ | otherwise = unionUnVarGraphs $ map cross_call ae_rhss+ cross_call (v, ae_rhs) = completeBipartiteGraph called_by_v called_with_v+ where+ is_thunk = idCallArity v == 0+ -- What rhs are relevant as happening before (or after) calling v?+ -- If v is a thunk, everything from all the _other_ variables+ -- If v is not a thunk, everything can happen.+ ae_before_v | is_thunk = lubRess (map snd $ filter ((/= v) . fst) ae_rhss) `lubRes` ae_body+ | otherwise = ae_combined+ -- What do we want to know from these?+ -- Which calls can happen next to any recursive call.+ called_with_v+ = unionUnVarSets $ map (calledWith ae_before_v) vars+ called_by_v = domRes ae_rhs++ ae_new = first (cross_calls `unionUnVarGraph`) ae_combined++-- See Note [Trimming arity]+trimArity :: Id -> Arity -> Arity+trimArity v a = minimum [a, max_arity_by_type, max_arity_by_strsig]+ where+ max_arity_by_type = length (typeArity (idType v))+ max_arity_by_strsig+ | isBotRes result_info = length demands+ | otherwise = a++ (demands, result_info) = splitStrictSig (idStrictness v)++---------------------------------------+-- Functions related to CallArityRes --+---------------------------------------++-- Result type for the two analyses.+-- See Note [Analysis I: The arity analyis]+-- and Note [Analysis II: The Co-Called analysis]+type CallArityRes = (UnVarGraph, VarEnv Arity)++emptyArityRes :: CallArityRes+emptyArityRes = (emptyUnVarGraph, emptyVarEnv)++unitArityRes :: Var -> Arity -> CallArityRes+unitArityRes v arity = (emptyUnVarGraph, unitVarEnv v arity)++resDelList :: [Var] -> CallArityRes -> CallArityRes+resDelList vs ae = foldr resDel ae vs++resDel :: Var -> CallArityRes -> CallArityRes+resDel v (g, ae) = (g `delNode` v, ae `delVarEnv` v)++domRes :: CallArityRes -> UnVarSet+domRes (_, ae) = varEnvDom ae++-- In the result, find out the minimum arity and whether the variable is called+-- at most once.+lookupCallArityRes :: CallArityRes -> Var -> (Arity, Bool)+lookupCallArityRes (g, ae) v+ = case lookupVarEnv ae v of+ Just a -> (a, not (v `elemUnVarSet` (neighbors g v)))+ Nothing -> (0, False)++calledWith :: CallArityRes -> Var -> UnVarSet+calledWith (g, _) v = neighbors g v++addCrossCoCalls :: UnVarSet -> UnVarSet -> CallArityRes -> CallArityRes+addCrossCoCalls set1 set2 = first (completeBipartiteGraph set1 set2 `unionUnVarGraph`)++-- Replaces the co-call graph by a complete graph (i.e. no information)+calledMultipleTimes :: CallArityRes -> CallArityRes+calledMultipleTimes res = first (const (completeGraph (domRes res))) res++-- Used for application and cases+both :: CallArityRes -> CallArityRes -> CallArityRes+both r1 r2 = addCrossCoCalls (domRes r1) (domRes r2) $ r1 `lubRes` r2++-- Used when combining results from alternative cases; take the minimum+lubRes :: CallArityRes -> CallArityRes -> CallArityRes+lubRes (g1, ae1) (g2, ae2) = (g1 `unionUnVarGraph` g2, ae1 `lubArityEnv` ae2)++lubArityEnv :: VarEnv Arity -> VarEnv Arity -> VarEnv Arity+lubArityEnv = plusVarEnv_C min++lubRess :: [CallArityRes] -> CallArityRes+lubRess = foldl lubRes emptyArityRes
+ simplCore/CoreMonad.hs view
@@ -0,0 +1,814 @@+{-+(c) The AQUA Project, Glasgow University, 1993-1998++\section[CoreMonad]{The core pipeline monad}+-}++{-# LANGUAGE CPP #-}++module CoreMonad (+ -- * Configuration of the core-to-core passes+ CoreToDo(..), runWhen, runMaybe,+ SimplifierMode(..),+ FloatOutSwitches(..),+ pprPassDetails,++ -- * Plugins+ PluginPass, bindsOnlyPass,++ -- * Counting+ SimplCount, doSimplTick, doFreeSimplTick, simplCountN,+ pprSimplCount, plusSimplCount, zeroSimplCount,+ isZeroSimplCount, hasDetailedCounts, Tick(..),++ -- * The monad+ CoreM, runCoreM,++ -- ** Reading from the monad+ getHscEnv, getRuleBase, getModule,+ getDynFlags, getOrigNameCache, getPackageFamInstEnv,+ getVisibleOrphanMods,+ getPrintUnqualified, getSrcSpanM,++ -- ** Writing to the monad+ addSimplCount,++ -- ** Lifting into the monad+ liftIO, liftIOWithCount,+ liftIO1, liftIO2, liftIO3, liftIO4,++ -- ** Global initialization+ reinitializeGlobals,++ -- ** Dealing with annotations+ getAnnotations, getFirstAnnotations,++ -- ** Screen output+ putMsg, putMsgS, errorMsg, errorMsgS, warnMsg,+ fatalErrorMsg, fatalErrorMsgS,+ debugTraceMsg, debugTraceMsgS,+ dumpIfSet_dyn,++ -- * Getting 'Name's+ thNameToGhcName+ ) where++import Name( Name )+import TcRnMonad ( initTcForLookup )+import CoreSyn+import HscTypes+import Module+import DynFlags+import BasicTypes ( CompilerPhase(..) )+import Annotations++import IOEnv hiding ( liftIO, failM, failWithM )+import qualified IOEnv ( liftIO )+import TcEnv ( lookupGlobal )+import Var+import Outputable+import FastString+import qualified ErrUtils as Err+import ErrUtils( Severity(..) )+import Maybes+import UniqSupply+import UniqFM ( UniqFM, mapUFM, filterUFM )+import MonadUtils+import NameCache+import SrcLoc+import ListSetOps ( runs )+import Data.List+import Data.Ord+import Data.Dynamic+import Data.IORef+import Data.Map (Map)+import qualified Data.Map as Map+import qualified Data.Map.Strict as MapStrict+import Data.Word+import Control.Monad+import Control.Applicative ( Alternative(..) )++import Prelude hiding ( read )++import {-# SOURCE #-} TcSplice ( lookupThName_maybe )+import qualified Language.Haskell.TH as TH++{-+************************************************************************+* *+ The CoreToDo type and related types+ Abstraction of core-to-core passes to run.+* *+************************************************************************+-}++data CoreToDo -- These are diff core-to-core passes,+ -- which may be invoked in any order,+ -- as many times as you like.++ = CoreDoSimplify -- The core-to-core simplifier.+ Int -- Max iterations+ SimplifierMode+ | CoreDoPluginPass String PluginPass+ | CoreDoFloatInwards+ | CoreDoFloatOutwards FloatOutSwitches+ | CoreLiberateCase+ | CoreDoPrintCore+ | CoreDoStaticArgs+ | CoreDoCallArity+ | CoreDoStrictness+ | CoreDoWorkerWrapper+ | CoreDoSpecialising+ | CoreDoSpecConstr+ | CoreCSE+ | CoreDoRuleCheck CompilerPhase String -- Check for non-application of rules+ -- matching this string+ | CoreDoVectorisation+ | CoreDoNothing -- Useful when building up+ | CoreDoPasses [CoreToDo] -- lists of these things++ | CoreDesugar -- Right after desugaring, no simple optimisation yet!+ | CoreDesugarOpt -- CoreDesugarXXX: Not strictly a core-to-core pass, but produces+ -- Core output, and hence useful to pass to endPass++ | CoreTidy+ | CorePrep+ | CoreOccurAnal++instance Outputable CoreToDo where+ ppr (CoreDoSimplify _ _) = text "Simplifier"+ ppr (CoreDoPluginPass s _) = text "Core plugin: " <+> text s+ ppr CoreDoFloatInwards = text "Float inwards"+ ppr (CoreDoFloatOutwards f) = text "Float out" <> parens (ppr f)+ ppr CoreLiberateCase = text "Liberate case"+ ppr CoreDoStaticArgs = text "Static argument"+ ppr CoreDoCallArity = text "Called arity analysis"+ ppr CoreDoStrictness = text "Demand analysis"+ ppr CoreDoWorkerWrapper = text "Worker Wrapper binds"+ ppr CoreDoSpecialising = text "Specialise"+ ppr CoreDoSpecConstr = text "SpecConstr"+ ppr CoreCSE = text "Common sub-expression"+ ppr CoreDoVectorisation = text "Vectorisation"+ ppr CoreDesugar = text "Desugar (before optimization)"+ ppr CoreDesugarOpt = text "Desugar (after optimization)"+ ppr CoreTidy = text "Tidy Core"+ ppr CorePrep = text "CorePrep"+ ppr CoreOccurAnal = text "Occurrence analysis"+ ppr CoreDoPrintCore = text "Print core"+ ppr (CoreDoRuleCheck {}) = text "Rule check"+ ppr CoreDoNothing = text "CoreDoNothing"+ ppr (CoreDoPasses passes) = text "CoreDoPasses" <+> ppr passes++pprPassDetails :: CoreToDo -> SDoc+pprPassDetails (CoreDoSimplify n md) = vcat [ text "Max iterations =" <+> int n+ , ppr md ]+pprPassDetails _ = Outputable.empty++data SimplifierMode -- See comments in SimplMonad+ = SimplMode+ { sm_names :: [String] -- Name(s) of the phase+ , sm_phase :: CompilerPhase+ , sm_rules :: Bool -- Whether RULES are enabled+ , sm_inline :: Bool -- Whether inlining is enabled+ , sm_case_case :: Bool -- Whether case-of-case is enabled+ , sm_eta_expand :: Bool -- Whether eta-expansion is enabled+ }++instance Outputable SimplifierMode where+ ppr (SimplMode { sm_phase = p, sm_names = ss+ , sm_rules = r, sm_inline = i+ , sm_eta_expand = eta, sm_case_case = cc })+ = text "SimplMode" <+> braces (+ sep [ text "Phase =" <+> ppr p <+>+ brackets (text (concat $ intersperse "," ss)) <> comma+ , pp_flag i (sLit "inline") <> comma+ , pp_flag r (sLit "rules") <> comma+ , pp_flag eta (sLit "eta-expand") <> comma+ , pp_flag cc (sLit "case-of-case") ])+ where+ pp_flag f s = ppUnless f (text "no") <+> ptext s++data FloatOutSwitches = FloatOutSwitches {+ floatOutLambdas :: Maybe Int, -- ^ Just n <=> float lambdas to top level, if+ -- doing so will abstract over n or fewer+ -- value variables+ -- Nothing <=> float all lambdas to top level,+ -- regardless of how many free variables+ -- Just 0 is the vanilla case: float a lambda+ -- iff it has no free vars++ floatOutConstants :: Bool, -- ^ True <=> float constants to top level,+ -- even if they do not escape a lambda+ floatOutOverSatApps :: Bool,+ -- ^ True <=> float out over-saturated applications+ -- based on arity information.+ -- See Note [Floating over-saturated applications]+ -- in SetLevels+ floatToTopLevelOnly :: Bool -- ^ Allow floating to the top level only.+ }+instance Outputable FloatOutSwitches where+ ppr = pprFloatOutSwitches++pprFloatOutSwitches :: FloatOutSwitches -> SDoc+pprFloatOutSwitches sw+ = text "FOS" <+> (braces $+ sep $ punctuate comma $+ [ text "Lam =" <+> ppr (floatOutLambdas sw)+ , text "Consts =" <+> ppr (floatOutConstants sw)+ , text "OverSatApps =" <+> ppr (floatOutOverSatApps sw) ])++-- The core-to-core pass ordering is derived from the DynFlags:+runWhen :: Bool -> CoreToDo -> CoreToDo+runWhen True do_this = do_this+runWhen False _ = CoreDoNothing++runMaybe :: Maybe a -> (a -> CoreToDo) -> CoreToDo+runMaybe (Just x) f = f x+runMaybe Nothing _ = CoreDoNothing++{-++************************************************************************+* *+ Types for Plugins+* *+************************************************************************+-}++-- | A description of the plugin pass itself+type PluginPass = ModGuts -> CoreM ModGuts++bindsOnlyPass :: (CoreProgram -> CoreM CoreProgram) -> ModGuts -> CoreM ModGuts+bindsOnlyPass pass guts+ = do { binds' <- pass (mg_binds guts)+ ; return (guts { mg_binds = binds' }) }++{-+************************************************************************+* *+ Counting and logging+* *+************************************************************************+-}++getVerboseSimplStats :: (Bool -> SDoc) -> SDoc+getVerboseSimplStats = sdocWithPprDebug -- For now, anyway++zeroSimplCount :: DynFlags -> SimplCount+isZeroSimplCount :: SimplCount -> Bool+hasDetailedCounts :: SimplCount -> Bool+pprSimplCount :: SimplCount -> SDoc+doSimplTick :: DynFlags -> Tick -> SimplCount -> SimplCount+doFreeSimplTick :: Tick -> SimplCount -> SimplCount+plusSimplCount :: SimplCount -> SimplCount -> SimplCount++data SimplCount+ = VerySimplCount !Int -- Used when don't want detailed stats++ | SimplCount {+ ticks :: !Int, -- Total ticks+ details :: !TickCounts, -- How many of each type++ n_log :: !Int, -- N+ log1 :: [Tick], -- Last N events; <= opt_HistorySize,+ -- most recent first+ log2 :: [Tick] -- Last opt_HistorySize events before that+ -- Having log1, log2 lets us accumulate the+ -- recent history reasonably efficiently+ }++type TickCounts = Map Tick Int++simplCountN :: SimplCount -> Int+simplCountN (VerySimplCount n) = n+simplCountN (SimplCount { ticks = n }) = n++zeroSimplCount dflags+ -- This is where we decide whether to do+ -- the VerySimpl version or the full-stats version+ | dopt Opt_D_dump_simpl_stats dflags+ = SimplCount {ticks = 0, details = Map.empty,+ n_log = 0, log1 = [], log2 = []}+ | otherwise+ = VerySimplCount 0++isZeroSimplCount (VerySimplCount n) = n==0+isZeroSimplCount (SimplCount { ticks = n }) = n==0++hasDetailedCounts (VerySimplCount {}) = False+hasDetailedCounts (SimplCount {}) = True++doFreeSimplTick tick sc@SimplCount { details = dts }+ = sc { details = dts `addTick` tick }+doFreeSimplTick _ sc = sc++doSimplTick dflags tick+ sc@(SimplCount { ticks = tks, details = dts, n_log = nl, log1 = l1 })+ | nl >= historySize dflags = sc1 { n_log = 1, log1 = [tick], log2 = l1 }+ | otherwise = sc1 { n_log = nl+1, log1 = tick : l1 }+ where+ sc1 = sc { ticks = tks+1, details = dts `addTick` tick }++doSimplTick _ _ (VerySimplCount n) = VerySimplCount (n+1)+++addTick :: TickCounts -> Tick -> TickCounts+addTick fm tick = MapStrict.insertWith (+) tick 1 fm++plusSimplCount sc1@(SimplCount { ticks = tks1, details = dts1 })+ sc2@(SimplCount { ticks = tks2, details = dts2 })+ = log_base { ticks = tks1 + tks2+ , details = MapStrict.unionWith (+) dts1 dts2 }+ where+ -- A hackish way of getting recent log info+ log_base | null (log1 sc2) = sc1 -- Nothing at all in sc2+ | null (log2 sc2) = sc2 { log2 = log1 sc1 }+ | otherwise = sc2++plusSimplCount (VerySimplCount n) (VerySimplCount m) = VerySimplCount (n+m)+plusSimplCount _ _ = panic "plusSimplCount"+ -- We use one or the other consistently++pprSimplCount (VerySimplCount n) = text "Total ticks:" <+> int n+pprSimplCount (SimplCount { ticks = tks, details = dts, log1 = l1, log2 = l2 })+ = vcat [text "Total ticks: " <+> int tks,+ blankLine,+ pprTickCounts dts,+ getVerboseSimplStats $ \dbg -> if dbg+ then+ vcat [blankLine,+ text "Log (most recent first)",+ nest 4 (vcat (map ppr l1) $$ vcat (map ppr l2))]+ else Outputable.empty+ ]++pprTickCounts :: Map Tick Int -> SDoc+pprTickCounts counts+ = vcat (map pprTickGroup groups)+ where+ groups :: [[(Tick,Int)]] -- Each group shares a comon tag+ -- toList returns common tags adjacent+ groups = runs same_tag (Map.toList counts)+ same_tag (tick1,_) (tick2,_) = tickToTag tick1 == tickToTag tick2++pprTickGroup :: [(Tick, Int)] -> SDoc+pprTickGroup group@((tick1,_):_)+ = hang (int (sum [n | (_,n) <- group]) <+> text (tickString tick1))+ 2 (vcat [ int n <+> pprTickCts tick+ -- flip as we want largest first+ | (tick,n) <- sortBy (flip (comparing snd)) group])+pprTickGroup [] = panic "pprTickGroup"++data Tick+ = PreInlineUnconditionally Id+ | PostInlineUnconditionally Id++ | UnfoldingDone Id+ | RuleFired FastString -- Rule name++ | LetFloatFromLet+ | EtaExpansion Id -- LHS binder+ | EtaReduction Id -- Binder on outer lambda+ | BetaReduction Id -- Lambda binder+++ | CaseOfCase Id -- Bndr on *inner* case+ | KnownBranch Id -- Case binder+ | CaseMerge Id -- Binder on outer case+ | AltMerge Id -- Case binder+ | CaseElim Id -- Case binder+ | CaseIdentity Id -- Case binder+ | FillInCaseDefault Id -- Case binder++ | BottomFound+ | SimplifierDone -- Ticked at each iteration of the simplifier++instance Outputable Tick where+ ppr tick = text (tickString tick) <+> pprTickCts tick++instance Eq Tick where+ a == b = case a `cmpTick` b of+ EQ -> True+ _ -> False++instance Ord Tick where+ compare = cmpTick++tickToTag :: Tick -> Int+tickToTag (PreInlineUnconditionally _) = 0+tickToTag (PostInlineUnconditionally _) = 1+tickToTag (UnfoldingDone _) = 2+tickToTag (RuleFired _) = 3+tickToTag LetFloatFromLet = 4+tickToTag (EtaExpansion _) = 5+tickToTag (EtaReduction _) = 6+tickToTag (BetaReduction _) = 7+tickToTag (CaseOfCase _) = 8+tickToTag (KnownBranch _) = 9+tickToTag (CaseMerge _) = 10+tickToTag (CaseElim _) = 11+tickToTag (CaseIdentity _) = 12+tickToTag (FillInCaseDefault _) = 13+tickToTag BottomFound = 14+tickToTag SimplifierDone = 16+tickToTag (AltMerge _) = 17++tickString :: Tick -> String+tickString (PreInlineUnconditionally _) = "PreInlineUnconditionally"+tickString (PostInlineUnconditionally _)= "PostInlineUnconditionally"+tickString (UnfoldingDone _) = "UnfoldingDone"+tickString (RuleFired _) = "RuleFired"+tickString LetFloatFromLet = "LetFloatFromLet"+tickString (EtaExpansion _) = "EtaExpansion"+tickString (EtaReduction _) = "EtaReduction"+tickString (BetaReduction _) = "BetaReduction"+tickString (CaseOfCase _) = "CaseOfCase"+tickString (KnownBranch _) = "KnownBranch"+tickString (CaseMerge _) = "CaseMerge"+tickString (AltMerge _) = "AltMerge"+tickString (CaseElim _) = "CaseElim"+tickString (CaseIdentity _) = "CaseIdentity"+tickString (FillInCaseDefault _) = "FillInCaseDefault"+tickString BottomFound = "BottomFound"+tickString SimplifierDone = "SimplifierDone"++pprTickCts :: Tick -> SDoc+pprTickCts (PreInlineUnconditionally v) = ppr v+pprTickCts (PostInlineUnconditionally v)= ppr v+pprTickCts (UnfoldingDone v) = ppr v+pprTickCts (RuleFired v) = ppr v+pprTickCts LetFloatFromLet = Outputable.empty+pprTickCts (EtaExpansion v) = ppr v+pprTickCts (EtaReduction v) = ppr v+pprTickCts (BetaReduction v) = ppr v+pprTickCts (CaseOfCase v) = ppr v+pprTickCts (KnownBranch v) = ppr v+pprTickCts (CaseMerge v) = ppr v+pprTickCts (AltMerge v) = ppr v+pprTickCts (CaseElim v) = ppr v+pprTickCts (CaseIdentity v) = ppr v+pprTickCts (FillInCaseDefault v) = ppr v+pprTickCts _ = Outputable.empty++cmpTick :: Tick -> Tick -> Ordering+cmpTick a b = case (tickToTag a `compare` tickToTag b) of+ GT -> GT+ EQ -> cmpEqTick a b+ LT -> LT++cmpEqTick :: Tick -> Tick -> Ordering+cmpEqTick (PreInlineUnconditionally a) (PreInlineUnconditionally b) = a `compare` b+cmpEqTick (PostInlineUnconditionally a) (PostInlineUnconditionally b) = a `compare` b+cmpEqTick (UnfoldingDone a) (UnfoldingDone b) = a `compare` b+cmpEqTick (RuleFired a) (RuleFired b) = a `compare` b+cmpEqTick (EtaExpansion a) (EtaExpansion b) = a `compare` b+cmpEqTick (EtaReduction a) (EtaReduction b) = a `compare` b+cmpEqTick (BetaReduction a) (BetaReduction b) = a `compare` b+cmpEqTick (CaseOfCase a) (CaseOfCase b) = a `compare` b+cmpEqTick (KnownBranch a) (KnownBranch b) = a `compare` b+cmpEqTick (CaseMerge a) (CaseMerge b) = a `compare` b+cmpEqTick (AltMerge a) (AltMerge b) = a `compare` b+cmpEqTick (CaseElim a) (CaseElim b) = a `compare` b+cmpEqTick (CaseIdentity a) (CaseIdentity b) = a `compare` b+cmpEqTick (FillInCaseDefault a) (FillInCaseDefault b) = a `compare` b+cmpEqTick _ _ = EQ++{-+************************************************************************+* *+ Monad and carried data structure definitions+* *+************************************************************************+-}++newtype CoreState = CoreState {+ cs_uniq_supply :: UniqSupply+}++data CoreReader = CoreReader {+ cr_hsc_env :: HscEnv,+ cr_rule_base :: RuleBase,+ cr_module :: Module,+ cr_print_unqual :: PrintUnqualified,+ cr_loc :: SrcSpan, -- Use this for log/error messages so they+ -- are at least tagged with the right source file+ cr_visible_orphan_mods :: !ModuleSet+}++-- Note: CoreWriter used to be defined with data, rather than newtype. If it+-- is defined that way again, the cw_simpl_count field, at least, must be+-- strict to avoid a space leak (Trac #7702).+newtype CoreWriter = CoreWriter {+ cw_simpl_count :: SimplCount+}++emptyWriter :: DynFlags -> CoreWriter+emptyWriter dflags = CoreWriter {+ cw_simpl_count = zeroSimplCount dflags+ }++plusWriter :: CoreWriter -> CoreWriter -> CoreWriter+plusWriter w1 w2 = CoreWriter {+ cw_simpl_count = (cw_simpl_count w1) `plusSimplCount` (cw_simpl_count w2)+ }++type CoreIOEnv = IOEnv CoreReader++-- | The monad used by Core-to-Core passes to access common state, register simplification+-- statistics and so on+newtype CoreM a = CoreM { unCoreM :: CoreState -> CoreIOEnv (a, CoreState, CoreWriter) }++instance Functor CoreM where+ fmap = liftM++instance Monad CoreM where+ mx >>= f = CoreM $ \s -> do+ (x, s', w1) <- unCoreM mx s+ (y, s'', w2) <- unCoreM (f x) s'+ let w = w1 `plusWriter` w2+ return $ seq w (y, s'', w)+ -- forcing w before building the tuple avoids a space leak+ -- (Trac #7702)++instance Applicative CoreM where+ pure x = CoreM $ \s -> nop s x+ (<*>) = ap+ m *> k = m >>= \_ -> k++instance Alternative CoreM where+ empty = CoreM (const Control.Applicative.empty)+ m <|> n = CoreM (\rs -> unCoreM m rs <|> unCoreM n rs)++instance MonadPlus CoreM++instance MonadUnique CoreM where+ getUniqueSupplyM = do+ us <- getS cs_uniq_supply+ let (us1, us2) = splitUniqSupply us+ modifyS (\s -> s { cs_uniq_supply = us2 })+ return us1++ getUniqueM = do+ us <- getS cs_uniq_supply+ let (u,us') = takeUniqFromSupply us+ modifyS (\s -> s { cs_uniq_supply = us' })+ return u++runCoreM :: HscEnv+ -> RuleBase+ -> UniqSupply+ -> Module+ -> ModuleSet+ -> PrintUnqualified+ -> SrcSpan+ -> CoreM a+ -> IO (a, SimplCount)+runCoreM hsc_env rule_base us mod orph_imps print_unqual loc m+ = liftM extract $ runIOEnv reader $ unCoreM m state+ where+ reader = CoreReader {+ cr_hsc_env = hsc_env,+ cr_rule_base = rule_base,+ cr_module = mod,+ cr_visible_orphan_mods = orph_imps,+ cr_print_unqual = print_unqual,+ cr_loc = loc+ }+ state = CoreState {+ cs_uniq_supply = us+ }++ extract :: (a, CoreState, CoreWriter) -> (a, SimplCount)+ extract (value, _, writer) = (value, cw_simpl_count writer)++{-+************************************************************************+* *+ Core combinators, not exported+* *+************************************************************************+-}++nop :: CoreState -> a -> CoreIOEnv (a, CoreState, CoreWriter)+nop s x = do+ r <- getEnv+ return (x, s, emptyWriter $ (hsc_dflags . cr_hsc_env) r)++read :: (CoreReader -> a) -> CoreM a+read f = CoreM (\s -> getEnv >>= (\r -> nop s (f r)))++getS :: (CoreState -> a) -> CoreM a+getS f = CoreM (\s -> nop s (f s))++modifyS :: (CoreState -> CoreState) -> CoreM ()+modifyS f = CoreM (\s -> nop (f s) ())++write :: CoreWriter -> CoreM ()+write w = CoreM (\s -> return ((), s, w))++-- \subsection{Lifting IO into the monad}++-- | Lift an 'IOEnv' operation into 'CoreM'+liftIOEnv :: CoreIOEnv a -> CoreM a+liftIOEnv mx = CoreM (\s -> mx >>= (\x -> nop s x))++instance MonadIO CoreM where+ liftIO = liftIOEnv . IOEnv.liftIO++-- | Lift an 'IO' operation into 'CoreM' while consuming its 'SimplCount'+liftIOWithCount :: IO (SimplCount, a) -> CoreM a+liftIOWithCount what = liftIO what >>= (\(count, x) -> addSimplCount count >> return x)++{-+************************************************************************+* *+ Reader, writer and state accessors+* *+************************************************************************+-}++getHscEnv :: CoreM HscEnv+getHscEnv = read cr_hsc_env++getRuleBase :: CoreM RuleBase+getRuleBase = read cr_rule_base++getVisibleOrphanMods :: CoreM ModuleSet+getVisibleOrphanMods = read cr_visible_orphan_mods++getPrintUnqualified :: CoreM PrintUnqualified+getPrintUnqualified = read cr_print_unqual++getSrcSpanM :: CoreM SrcSpan+getSrcSpanM = read cr_loc++addSimplCount :: SimplCount -> CoreM ()+addSimplCount count = write (CoreWriter { cw_simpl_count = count })++-- Convenience accessors for useful fields of HscEnv++instance HasDynFlags CoreM where+ getDynFlags = fmap hsc_dflags getHscEnv++instance HasModule CoreM where+ getModule = read cr_module++-- | The original name cache is the current mapping from 'Module' and+-- 'OccName' to a compiler-wide unique 'Name'+getOrigNameCache :: CoreM OrigNameCache+getOrigNameCache = do+ nameCacheRef <- fmap hsc_NC getHscEnv+ liftIO $ fmap nsNames $ readIORef nameCacheRef++getPackageFamInstEnv :: CoreM PackageFamInstEnv+getPackageFamInstEnv = do+ hsc_env <- getHscEnv+ eps <- liftIO $ hscEPS hsc_env+ return $ eps_fam_inst_env eps++{-# DEPRECATED reinitializeGlobals "It is not necessary to call reinitializeGlobals. Since GHC 8.2, this function is a no-op and will be removed in GHC 8.4" #-}+reinitializeGlobals :: CoreM ()+reinitializeGlobals = return ()++{-+************************************************************************+* *+ Dealing with annotations+* *+************************************************************************+-}++-- | Get all annotations of a given type. This happens lazily, that is+-- no deserialization will take place until the [a] is actually demanded and+-- the [a] can also be empty (the UniqFM is not filtered).+--+-- This should be done once at the start of a Core-to-Core pass that uses+-- annotations.+--+-- See Note [Annotations]+getAnnotations :: Typeable a => ([Word8] -> a) -> ModGuts -> CoreM (UniqFM [a])+getAnnotations deserialize guts = do+ hsc_env <- getHscEnv+ ann_env <- liftIO $ prepareAnnotations hsc_env (Just guts)+ return (deserializeAnns deserialize ann_env)++-- | Get at most one annotation of a given type per Unique.+getFirstAnnotations :: Typeable a => ([Word8] -> a) -> ModGuts -> CoreM (UniqFM a)+getFirstAnnotations deserialize guts+ = liftM (mapUFM head . filterUFM (not . null))+ $ getAnnotations deserialize guts++{-+Note [Annotations]+~~~~~~~~~~~~~~~~~~+A Core-to-Core pass that wants to make use of annotations calls+getAnnotations or getFirstAnnotations at the beginning to obtain a UniqFM with+annotations of a specific type. This produces all annotations from interface+files read so far. However, annotations from interface files read during the+pass will not be visible until getAnnotations is called again. This is similar+to how rules work and probably isn't too bad.++The current implementation could be optimised a bit: when looking up+annotations for a thing from the HomePackageTable, we could search directly in+the module where the thing is defined rather than building one UniqFM which+contains all annotations we know of. This would work because annotations can+only be given to things defined in the same module. However, since we would+only want to deserialise every annotation once, we would have to build a cache+for every module in the HTP. In the end, it's probably not worth it as long as+we aren't using annotations heavily.++************************************************************************+* *+ Direct screen output+* *+************************************************************************+-}++msg :: Severity -> SDoc -> CoreM ()+msg sev doc+ = do { dflags <- getDynFlags+ ; loc <- getSrcSpanM+ ; unqual <- getPrintUnqualified+ ; let sty = case sev of+ SevError -> err_sty+ SevWarning -> err_sty+ SevDump -> dump_sty+ _ -> user_sty+ err_sty = mkErrStyle dflags unqual+ user_sty = mkUserStyle dflags unqual AllTheWay+ dump_sty = mkDumpStyle dflags unqual+ ; liftIO $ putLogMsg dflags NoReason sev loc sty doc }++-- | Output a String message to the screen+putMsgS :: String -> CoreM ()+putMsgS = putMsg . text++-- | Output a message to the screen+putMsg :: SDoc -> CoreM ()+putMsg = msg SevInfo++-- | Output an error to the screen. Does not cause the compiler to die.+errorMsgS :: String -> CoreM ()+errorMsgS = errorMsg . text++-- | Output an error to the screen. Does not cause the compiler to die.+errorMsg :: SDoc -> CoreM ()+errorMsg = msg SevError++warnMsg :: SDoc -> CoreM ()+warnMsg = msg SevWarning++-- | Output a fatal error to the screen. Does not cause the compiler to die.+fatalErrorMsgS :: String -> CoreM ()+fatalErrorMsgS = fatalErrorMsg . text++-- | Output a fatal error to the screen. Does not cause the compiler to die.+fatalErrorMsg :: SDoc -> CoreM ()+fatalErrorMsg = msg SevFatal++-- | Output a string debugging message at verbosity level of @-v@ or higher+debugTraceMsgS :: String -> CoreM ()+debugTraceMsgS = debugTraceMsg . text++-- | Outputs a debugging message at verbosity level of @-v@ or higher+debugTraceMsg :: SDoc -> CoreM ()+debugTraceMsg = msg SevDump++-- | Show some labelled 'SDoc' if a particular flag is set or at a verbosity level of @-v -ddump-most@ or higher+dumpIfSet_dyn :: DumpFlag -> String -> SDoc -> CoreM ()+dumpIfSet_dyn flag str doc+ = do { dflags <- getDynFlags+ ; unqual <- getPrintUnqualified+ ; when (dopt flag dflags) $ liftIO $+ Err.dumpSDoc dflags unqual flag str doc }++{-+************************************************************************+* *+ Finding TyThings+* *+************************************************************************+-}++instance MonadThings CoreM where+ lookupThing name = do { hsc_env <- getHscEnv+ ; liftIO $ lookupGlobal hsc_env name }++{-+************************************************************************+* *+ Template Haskell interoperability+* *+************************************************************************+-}++-- | Attempt to convert a Template Haskell name to one that GHC can+-- understand. Original TH names such as those you get when you use+-- the @'foo@ syntax will be translated to their equivalent GHC name+-- exactly. Qualified or unqualified TH names will be dynamically bound+-- to names in the module being compiled, if possible. Exact TH names+-- will be bound to the name they represent, exactly.+thNameToGhcName :: TH.Name -> CoreM (Maybe Name)+thNameToGhcName th_name = do+ hsc_env <- getHscEnv+ liftIO $ initTcForLookup hsc_env (lookupThName_maybe th_name)
+ simplCore/FloatIn.hs view
@@ -0,0 +1,659 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++************************************************************************+* *+\section[FloatIn]{Floating Inwards pass}+* *+************************************************************************++The main purpose of @floatInwards@ is floating into branches of a+case, so that we don't allocate things, save them on the stack, and+then discover that they aren't needed in the chosen branch.+-}++{-# LANGUAGE CPP #-}++module FloatIn ( floatInwards ) where++#include "HsVersions.h"++import CoreSyn+import MkCore+import HscTypes ( ModGuts(..) )+import CoreUtils ( exprIsDupable, exprIsExpandable,+ exprOkForSideEffects, mkTicks )+import CoreFVs+import CoreMonad ( CoreM )+import Id ( isOneShotBndr, idType, isJoinId, isJoinId_maybe )+import Var+import Type ( isUnliftedType )+import VarSet+import Util+import DynFlags+import Outputable+import Data.List ( mapAccumL )+import BasicTypes ( RecFlag(..), isRec )++{-+Top-level interface function, @floatInwards@. Note that we do not+actually float any bindings downwards from the top-level.+-}++floatInwards :: ModGuts -> CoreM ModGuts+floatInwards pgm@(ModGuts { mg_binds = binds })+ = do { dflags <- getDynFlags+ ; return (pgm { mg_binds = map (fi_top_bind dflags) binds }) }+ where+ fi_top_bind dflags (NonRec binder rhs)+ = NonRec binder (fiExpr dflags [] (freeVars rhs))+ fi_top_bind dflags (Rec pairs)+ = Rec [ (b, fiExpr dflags [] (freeVars rhs)) | (b, rhs) <- pairs ]+++{-+************************************************************************+* *+\subsection{Mail from Andr\'e [edited]}+* *+************************************************************************++{\em Will wrote: What??? I thought the idea was to float as far+inwards as possible, no matter what. This is dropping all bindings+every time it sees a lambda of any kind. Help! }++You are assuming we DO DO full laziness AFTER floating inwards! We+have to [not float inside lambdas] if we don't.++If we indeed do full laziness after the floating inwards (we could+check the compilation flags for that) then I agree we could be more+aggressive and do float inwards past lambdas.++Actually we are not doing a proper full laziness (see below), which+was another reason for not floating inwards past a lambda.++This can easily be fixed. The problem is that we float lets outwards,+but there are a few expressions which are not let bound, like case+scrutinees and case alternatives. After floating inwards the+simplifier could decide to inline the let and the laziness would be+lost, e.g.++\begin{verbatim}+let a = expensive ==> \b -> case expensive of ...+in \ b -> case a of ...+\end{verbatim}+The fix is+\begin{enumerate}+\item+to let bind the algebraic case scrutinees (done, I think) and+the case alternatives (except the ones with an+unboxed type)(not done, I think). This is best done in the+SetLevels.hs module, which tags things with their level numbers.+\item+do the full laziness pass (floating lets outwards).+\item+simplify. The simplifier inlines the (trivial) lets that were+ created but were not floated outwards.+\end{enumerate}++With the fix I think Will's suggestion that we can gain even more from+strictness by floating inwards past lambdas makes sense.++We still gain even without going past lambdas, as things may be+strict in the (new) context of a branch (where it was floated to) or+of a let rhs, e.g.+\begin{verbatim}+let a = something case x of+in case x of alt1 -> case something of a -> a + a+ alt1 -> a + a ==> alt2 -> b+ alt2 -> b++let a = something let b = case something of a -> a + a+in let b = a + a ==> in (b,b)+in (b,b)+\end{verbatim}+Also, even if a is not found to be strict in the new context and is+still left as a let, if the branch is not taken (or b is not entered)+the closure for a is not built.++************************************************************************+* *+\subsection{Main floating-inwards code}+* *+************************************************************************+-}++type FreeVarSet = DIdSet+type BoundVarSet = DIdSet++data FloatInBind = FB BoundVarSet FreeVarSet FloatBind+ -- The FreeVarSet is the free variables of the binding. In the case+ -- of recursive bindings, the set doesn't include the bound+ -- variables.++type FloatInBinds = [FloatInBind]+ -- In reverse dependency order (innermost binder first)++fiExpr :: DynFlags+ -> FloatInBinds -- Binds we're trying to drop+ -- as far "inwards" as possible+ -> CoreExprWithFVs -- Input expr+ -> CoreExpr -- Result++fiExpr _ to_drop (_, AnnLit lit) = ASSERT( null to_drop ) Lit lit+fiExpr _ to_drop (_, AnnType ty) = ASSERT( null to_drop ) Type ty+fiExpr _ to_drop (_, AnnVar v) = wrapFloats to_drop (Var v)+fiExpr _ to_drop (_, AnnCoercion co) = wrapFloats to_drop (Coercion co)+fiExpr dflags to_drop (_, AnnCast expr (co_ann, co))+ = wrapFloats (drop_here ++ co_drop) $+ Cast (fiExpr dflags e_drop expr) co+ where+ [drop_here, e_drop, co_drop]+ = sepBindsByDropPoint dflags False+ [freeVarsOf expr, freeVarsOfAnn co_ann]+ (freeVarsOfType expr `unionDVarSet` freeVarsOfTypeAnn co_ann)+ to_drop++{-+Applications: we do float inside applications, mainly because we+need to get at all the arguments. The next simplifier run will+pull out any silly ones.+-}++fiExpr dflags to_drop ann_expr@(_,AnnApp {})+ = mkTicks ticks $ wrapFloats drop_here $ wrapFloats extra_drop $+ mkApps (fiExpr dflags fun_drop ann_fun)+ (zipWith (fiExpr dflags) arg_drops ann_args)+ where+ (ann_fun, ann_args, ticks) = collectAnnArgsTicks tickishFloatable ann_expr+ (extra_fvs0, fun_fvs)+ | (_, AnnVar _) <- ann_fun = (freeVarsOf ann_fun, emptyDVarSet)+ -- Don't float the binding for f into f x y z; see Note [Join points]+ -- for why we *can't* do it when f is a join point. (If f isn't a+ -- join point, floating it in isn't especially harmful but it's+ -- useless since the simplifier will immediately float it back out.)+ | otherwise = (emptyDVarSet, freeVarsOf ann_fun)+ (extra_fvs, arg_fvs) = mapAccumL mk_arg_fvs extra_fvs0 ann_args++ mk_arg_fvs :: FreeVarSet -> CoreExprWithFVs -> (FreeVarSet, FreeVarSet)+ mk_arg_fvs extra_fvs ann_arg+ | noFloatIntoRhs False NonRecursive ann_arg+ = (extra_fvs `unionDVarSet` freeVarsOf ann_arg, emptyDVarSet)+ | otherwise+ = (extra_fvs, freeVarsOf ann_arg)++ drop_here : extra_drop : fun_drop : arg_drops+ = sepBindsByDropPoint dflags False+ (extra_fvs : fun_fvs : arg_fvs)+ (freeVarsOfType ann_fun `unionDVarSet`+ mapUnionDVarSet freeVarsOfType ann_args)+ to_drop++{-+Note [Do not destroy the let/app invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Watch out for+ f (x +# y)+We don't want to float bindings into here+ f (case ... of { x -> x +# y })+because that might destroy the let/app invariant, which requires+unlifted function arguments to be ok-for-speculation.++Note [Join points]+~~~~~~~~~~~~~~~~~~+Generally, we don't need to worry about join points - there are places we're+not allowed to float them, but since they can't have occurrences in those+places, we're not tempted.++We do need to be careful about jumps, however:++ joinrec j x y z = ... in+ jump j a b c++Previous versions often floated the definition of a recursive function into its+only non-recursive occurrence. But for a join point, this is a disaster:++ (joinrec j x y z = ... in+ jump j) a b c -- wrong!++Every jump must be exact, so the jump to j must have three arguments. Hence+we're careful not to float into the target of a jump (though we can float into+the arguments just fine).++Note [Floating in past a lambda group]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* We must be careful about floating inside a value lambda.+ That risks losing laziness.+ The float-out pass might rescue us, but then again it might not.++* We must be careful about type lambdas too. At one time we did, and+ there is no risk of duplicating work thereby, but we do need to be+ careful. In particular, here is a bad case (it happened in the+ cichelli benchmark:+ let v = ...+ in let f = /\t -> \a -> ...+ ==>+ let f = /\t -> let v = ... in \a -> ...+ This is bad as now f is an updatable closure (update PAP)+ and has arity 0.++* Hack alert! We only float in through one-shot lambdas,+ not (as you might guess) through lone big lambdas.+ Reason: we float *out* past big lambdas (see the test in the Lam+ case of FloatOut.floatExpr) and we don't want to float straight+ back in again.++ It *is* important to float into one-shot lambdas, however;+ see the remarks with noFloatIntoRhs.++So we treat lambda in groups, using the following rule:++ Float in if (a) there is at least one Id,+ and (b) there are no non-one-shot Ids++ Otherwise drop all the bindings outside the group.++This is what the 'go' function in the AnnLam case is doing.++(Join points are handled similarly: a join point is considered one-shot iff+it's non-recursive, so we float only into non-recursive join points.)++Urk! if all are tyvars, and we don't float in, we may miss an+ opportunity to float inside a nested case branch+-}++fiExpr dflags to_drop lam@(_, AnnLam _ _)+ | okToFloatInside bndrs -- Float in+ -- NB: Must line up with noFloatIntoRhs (AnnLam...); see Trac #7088+ = mkLams bndrs (fiExpr dflags to_drop body)++ | otherwise -- Dump it all here+ = wrapFloats to_drop (mkLams bndrs (fiExpr dflags [] body))++ where+ (bndrs, body) = collectAnnBndrs lam++{-+We don't float lets inwards past an SCC.+ ToDo: keep info on current cc, and when passing+ one, if it is not the same, annotate all lets in binds with current+ cc, change current cc to the new one and float binds into expr.+-}++fiExpr dflags to_drop (_, AnnTick tickish expr)+ | tickish `tickishScopesLike` SoftScope+ = Tick tickish (fiExpr dflags to_drop expr)++ | otherwise -- Wimp out for now - we could push values in+ = wrapFloats to_drop (Tick tickish (fiExpr dflags [] expr))++{-+For @Lets@, the possible ``drop points'' for the \tr{to_drop}+bindings are: (a)~in the body, (b1)~in the RHS of a NonRec binding,+or~(b2), in each of the RHSs of the pairs of a @Rec@.++Note that we do {\em weird things} with this let's binding. Consider:+\begin{verbatim}+let+ w = ...+in {+ let v = ... w ...+ in ... v .. w ...+}+\end{verbatim}+Look at the inner \tr{let}. As \tr{w} is used in both the bind and+body of the inner let, we could panic and leave \tr{w}'s binding where+it is. But \tr{v} is floatable further into the body of the inner let, and+{\em then} \tr{w} will also be only in the body of that inner let.++So: rather than drop \tr{w}'s binding here, we add it onto the list of+things to drop in the outer let's body, and let nature take its+course.++Note [extra_fvs (1): avoid floating into RHS]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider let x=\y....t... in body. We do not necessarily want to float+a binding for t into the RHS, because it'll immediately be floated out+again. (It won't go inside the lambda else we risk losing work.)+In letrec, we need to be more careful still. We don't want to transform+ let x# = y# +# 1#+ in+ letrec f = \z. ...x#...f...+ in ...+into+ letrec f = let x# = y# +# 1# in \z. ...x#...f... in ...+because now we can't float the let out again, because a letrec+can't have unboxed bindings.++So we make "extra_fvs" which is the rhs_fvs of such bindings, and+arrange to dump bindings that bind extra_fvs before the entire let.++Note [extra_fvs (2): free variables of rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ let x{rule mentioning y} = rhs in body+Here y is not free in rhs or body; but we still want to dump bindings+that bind y outside the let. So we augment extra_fvs with the+idRuleAndUnfoldingVars of x. No need for type variables, hence not using+idFreeVars.+-}++fiExpr dflags to_drop (_,AnnLet bind body)+ = fiExpr dflags (after ++ new_float : before) body+ -- to_drop is in reverse dependency order+ where+ (before, new_float, after) = fiBind dflags to_drop bind body_fvs body_ty_fvs+ body_fvs = freeVarsOf body+ body_ty_fvs = freeVarsOfType body++{-+For @Case@, the possible ``drop points'' for the \tr{to_drop}+bindings are: (a)~inside the scrutinee, (b)~inside one of the+alternatives/default [default FVs always {\em first}!].++Floating case expressions inward was added to fix Trac #5658: strict bindings+not floated in. In particular, this change allows array indexing operations,+which have a single DEFAULT alternative without any binders, to be floated+inward. SIMD primops for unpacking SIMD vectors into an unboxed tuple of unboxed+scalars also need to be floated inward, but unpacks have a single non-DEFAULT+alternative that binds the elements of the tuple. We now therefore also support+floating in cases with a single alternative that may bind values.+-}++fiExpr dflags to_drop (_, AnnCase scrut case_bndr _ [(con,alt_bndrs,rhs)])+ | isUnliftedType (idType case_bndr)+ , exprOkForSideEffects (deAnnotate scrut)+ -- See PrimOp, Note [PrimOp can_fail and has_side_effects]+ = wrapFloats shared_binds $+ fiExpr dflags (case_float : rhs_binds) rhs+ where+ case_float = FB (mkDVarSet (case_bndr : alt_bndrs)) scrut_fvs+ (FloatCase scrut' case_bndr con alt_bndrs)+ scrut' = fiExpr dflags scrut_binds scrut+ [shared_binds, scrut_binds, rhs_binds]+ = sepBindsByDropPoint dflags False+ [scrut_fvs, rhs_fvs]+ (freeVarsOfType scrut `unionDVarSet` rhs_ty_fvs)+ to_drop+ rhs_fvs = freeVarsOf rhs `delDVarSetList` (case_bndr : alt_bndrs)+ rhs_ty_fvs = freeVarsOfType rhs `delDVarSetList` (case_bndr : alt_bndrs)+ scrut_fvs = freeVarsOf scrut++fiExpr dflags to_drop (_, AnnCase scrut case_bndr ty alts)+ = wrapFloats drop_here1 $+ wrapFloats drop_here2 $+ Case (fiExpr dflags scrut_drops scrut) case_bndr ty+ (zipWith fi_alt alts_drops_s alts)+ where+ -- Float into the scrut and alts-considered-together just like App+ [drop_here1, scrut_drops, alts_drops]+ = sepBindsByDropPoint dflags False+ [scrut_fvs, all_alts_fvs]+ (freeVarsOfType scrut `unionDVarSet` all_alts_ty_fvs)+ to_drop++ -- Float into the alts with the is_case flag set+ (drop_here2 : alts_drops_s)+ = sepBindsByDropPoint dflags True alts_fvs all_alts_ty_fvs+ alts_drops++ scrut_fvs = freeVarsOf scrut+ alts_fvs = map alt_fvs alts+ all_alts_fvs = unionDVarSets alts_fvs+ alts_ty_fvs = map alt_ty_fvs alts+ all_alts_ty_fvs = unionDVarSets alts_ty_fvs+ alt_fvs (_con, args, rhs)+ = foldl delDVarSet (freeVarsOf rhs) (case_bndr:args)+ alt_ty_fvs (_con, args, rhs)+ = foldl delDVarSet (freeVarsOfType rhs) (case_bndr:args)+ -- Delete case_bndr and args from free vars of rhs+ -- to get free vars of alt++ fi_alt to_drop (con, args, rhs) = (con, args, fiExpr dflags to_drop rhs)++------------------+fiBind :: DynFlags+ -> FloatInBinds -- Binds we're trying to drop+ -- as far "inwards" as possible+ -> CoreBindWithFVs -- Input binding+ -> DVarSet -- Free in scope of binding+ -> DVarSet -- Free in type of body of binding+ -> ( FloatInBinds -- Land these before+ , FloatInBind -- The binding itself+ , FloatInBinds) -- Land these after++fiBind dflags to_drop (AnnNonRec id rhs) body_fvs body_ty_fvs+ = ( extra_binds ++ shared_binds -- Land these before+ -- See Note [extra_fvs (1,2)]+ , FB (unitDVarSet id) rhs_fvs' -- The new binding itself+ (FloatLet (NonRec id rhs'))+ , body_binds ) -- Land these after++ where+ body_fvs2 = body_fvs `delDVarSet` id+ rhs_fvs = freeVarsOf rhs++ rule_fvs = bndrRuleAndUnfoldingVarsDSet id -- See Note [extra_fvs (2): free variables of rules]+ extra_fvs | noFloatIntoRhs (isJoinId id) NonRecursive rhs+ = rule_fvs `unionDVarSet` freeVarsOf rhs+ | otherwise+ = rule_fvs+ -- See Note [extra_fvs (1): avoid floating into RHS]+ -- No point in floating in only to float straight out again+ -- We *can't* float into ok-for-speculation unlifted RHSs+ -- But do float into join points++ [shared_binds, extra_binds, rhs_binds, body_binds]+ = sepBindsByDropPoint dflags False+ [extra_fvs, rhs_fvs, body_fvs2]+ (freeVarsOfType rhs `unionDVarSet` body_ty_fvs)+ to_drop++ -- Push rhs_binds into the right hand side of the binding+ rhs' = fiRhs dflags rhs_binds id rhs+ rhs_fvs' = rhs_fvs `unionDVarSet` floatedBindsFVs rhs_binds `unionDVarSet` rule_fvs+ -- Don't forget the rule_fvs; the binding mentions them!++fiBind dflags to_drop (AnnRec bindings) body_fvs body_ty_fvs+ = ( extra_binds ++ shared_binds+ , FB (mkDVarSet ids) rhs_fvs'+ (FloatLet (Rec (fi_bind rhss_binds bindings)))+ , body_binds )+ where+ (ids, rhss) = unzip bindings+ rhss_fvs = map freeVarsOf rhss++ -- See Note [extra_fvs (1,2)]+ rule_fvs = mapUnionDVarSet bndrRuleAndUnfoldingVarsDSet ids+ extra_fvs = rule_fvs `unionDVarSet`+ unionDVarSets [ freeVarsOf rhs | (bndr, rhs) <- bindings+ , noFloatIntoRhs (isJoinId bndr) Recursive rhs ]++ (shared_binds:extra_binds:body_binds:rhss_binds)+ = sepBindsByDropPoint dflags False+ (extra_fvs:body_fvs:rhss_fvs)+ (body_ty_fvs `unionDVarSet` mapUnionDVarSet freeVarsOfType rhss)+ to_drop++ rhs_fvs' = unionDVarSets rhss_fvs `unionDVarSet`+ unionDVarSets (map floatedBindsFVs rhss_binds) `unionDVarSet`+ rule_fvs -- Don't forget the rule variables!++ -- Push rhs_binds into the right hand side of the binding+ fi_bind :: [FloatInBinds] -- one per "drop pt" conjured w/ fvs_of_rhss+ -> [(Id, CoreExprWithFVs)]+ -> [(Id, CoreExpr)]++ fi_bind to_drops pairs+ = [ (binder, fiRhs dflags to_drop binder rhs)+ | ((binder, rhs), to_drop) <- zipEqual "fi_bind" pairs to_drops ]++------------------+fiRhs :: DynFlags -> FloatInBinds -> CoreBndr -> CoreExprWithFVs -> CoreExpr+fiRhs dflags to_drop bndr rhs+ | Just join_arity <- isJoinId_maybe bndr+ , let (bndrs, body) = collectNAnnBndrs join_arity rhs+ = mkLams bndrs (fiExpr dflags to_drop body)+ | otherwise+ = fiExpr dflags to_drop rhs++------------------+okToFloatInside :: [Var] -> Bool+okToFloatInside bndrs = all ok bndrs+ where+ ok b = not (isId b) || isOneShotBndr b+ -- Push the floats inside there are no non-one-shot value binders++noFloatIntoRhs :: Bool -> RecFlag -> CoreExprWithFVs -> Bool+-- ^ True if it's a bad idea to float bindings into this RHS+-- Preconditio: rhs :: rhs_ty+noFloatIntoRhs is_join is_rec rhs@(_, rhs')+ | is_join+ = isRec is_rec -- Joins are one-shot iff non-recursive+ | otherwise+ = isUnliftedType rhs_ty+ -- See Note [Do not destroy the let/app invariant]+ || noFloatIntoExpr rhs'+ where+ rhs_ty = exprTypeFV rhs++noFloatIntoExpr :: CoreExprWithFVs' -> Bool+noFloatIntoExpr (AnnLam bndr e)+ = not (okToFloatInside (bndr:bndrs))+ -- NB: Must line up with fiExpr (AnnLam...); see Trac #7088+ where+ (bndrs, _) = collectAnnBndrs e+ -- IMPORTANT: don't say 'True' for a RHS with a one-shot lambda at the top.+ -- This makes a big difference for things like+ -- f x# = let x = I# x#+ -- in let j = \() -> ...x...+ -- in if <condition> then normal-path else j ()+ -- If x is used only in the error case join point, j, we must float the+ -- boxing constructor into it, else we box it every time which is very bad+ -- news indeed.++noFloatIntoExpr rhs = exprIsExpandable (deAnnotate' rhs)+ -- We'd just float right back out again...+ -- Should match the test in SimplEnv.doFloatFromRhs++{-+************************************************************************+* *+\subsection{@sepBindsByDropPoint@}+* *+************************************************************************++This is the crucial function. The idea is: We have a wad of bindings+that we'd like to distribute inside a collection of {\em drop points};+insides the alternatives of a \tr{case} would be one example of some+drop points; the RHS and body of a non-recursive \tr{let} binding+would be another (2-element) collection.++So: We're given a list of sets-of-free-variables, one per drop point,+and a list of floating-inwards bindings. If a binding can go into+only one drop point (without suddenly making something out-of-scope),+in it goes. If a binding is used inside {\em multiple} drop points,+then it has to go in a you-must-drop-it-above-all-these-drop-points+point.++But, with coercions appearing in types, there is a complication: we+might be floating in a "strict let" -- that is, a case. Case expressions+mention their return type. We absolutely can't float a coercion binding+inward to the point that the type of the expression it's about to wrap+mentions the coercion. So we include the union of the sets of free variables+of the types of all the drop points involved. If any of the floaters+bind a coercion variable mentioned in any of the types, that binder must+be dropped right away.++We have to maintain the order on these drop-point-related lists.+-}++sepBindsByDropPoint+ :: DynFlags+ -> Bool -- True <=> is case expression+ -> [FreeVarSet] -- One set of FVs per drop point+ -> FreeVarSet -- Vars free in all the types of the drop points+ -> FloatInBinds -- Candidate floaters+ -> [FloatInBinds] -- FIRST one is bindings which must not be floated+ -- inside any drop point; the rest correspond+ -- one-to-one with the input list of FV sets++-- Every input floater is returned somewhere in the result;+-- none are dropped, not even ones which don't seem to be+-- free in *any* of the drop-point fvs. Why? Because, for example,+-- a binding (let x = E in B) might have a specialised version of+-- x (say x') stored inside x, but x' isn't free in E or B.++type DropBox = (FreeVarSet, FloatInBinds)++sepBindsByDropPoint _ _is_case drop_pts _ty_fvs []+ = [] : [[] | _ <- drop_pts] -- cut to the chase scene; it happens++sepBindsByDropPoint dflags is_case drop_pts ty_fvs floaters+ = go floaters (map (\fvs -> (fvs, [])) (emptyDVarSet : drop_pts))+ where+ go :: FloatInBinds -> [DropBox] -> [FloatInBinds]+ -- The *first* one in the argument list is the drop_here set+ -- The FloatInBinds in the lists are in the reverse of+ -- the normal FloatInBinds order; that is, they are the right way round!++ go [] drop_boxes = map (reverse . snd) drop_boxes++ go (bind_w_fvs@(FB bndrs bind_fvs bind) : binds) drop_boxes@(here_box : fork_boxes)+ = go binds new_boxes+ where+ -- "here" means the group of bindings dropped at the top of the fork++ (used_here : used_in_flags) = [ fvs `intersectsDVarSet` bndrs+ | (fvs, _) <- drop_boxes]+ used_in_ty = ty_fvs `intersectsDVarSet` bndrs++ drop_here = used_here || not can_push || used_in_ty++ -- For case expressions we duplicate the binding if it is+ -- reasonably small, and if it is not used in all the RHSs+ -- This is good for situations like+ -- let x = I# y in+ -- case e of+ -- C -> error x+ -- D -> error x+ -- E -> ...not mentioning x...++ n_alts = length used_in_flags+ n_used_alts = count id used_in_flags -- returns number of Trues in list.++ can_push = n_used_alts == 1 -- Used in just one branch+ || (is_case && -- We are looking at case alternatives+ n_used_alts > 1 && -- It's used in more than one+ n_used_alts < n_alts && -- ...but not all+ floatIsDupable dflags bind) -- and we can duplicate the binding++ new_boxes | drop_here = (insert here_box : fork_boxes)+ | otherwise = (here_box : new_fork_boxes)++ new_fork_boxes = zipWithEqual "FloatIn.sepBinds" insert_maybe fork_boxes used_in_flags++ insert :: DropBox -> DropBox+ insert (fvs,drops) = (fvs `unionDVarSet` bind_fvs, bind_w_fvs:drops)++ insert_maybe box True = insert box+ insert_maybe box False = box++ go _ _ = panic "sepBindsByDropPoint/go"+++floatedBindsFVs :: FloatInBinds -> FreeVarSet+floatedBindsFVs binds = mapUnionDVarSet fbFVs binds++fbFVs :: FloatInBind -> DVarSet+fbFVs (FB _ fvs _) = fvs++wrapFloats :: FloatInBinds -> CoreExpr -> CoreExpr+-- Remember FloatInBinds is in *reverse* dependency order+wrapFloats [] e = e+wrapFloats (FB _ _ fl : bs) e = wrapFloats bs (wrapFloat fl e)++floatIsDupable :: DynFlags -> FloatBind -> Bool+floatIsDupable dflags (FloatCase scrut _ _ _) = exprIsDupable dflags scrut+floatIsDupable dflags (FloatLet (Rec prs)) = all (exprIsDupable dflags . snd) prs+floatIsDupable dflags (FloatLet (NonRec _ r)) = exprIsDupable dflags r
+ simplCore/FloatOut.hs view
@@ -0,0 +1,755 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[FloatOut]{Float bindings outwards (towards the top level)}++``Long-distance'' floating of bindings towards the top level.+-}++{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module FloatOut ( floatOutwards ) where++import CoreSyn+import CoreUtils+import MkCore+import CoreArity ( etaExpand )+import CoreMonad ( FloatOutSwitches(..) )++import DynFlags+import ErrUtils ( dumpIfSet_dyn )+import Id ( Id, idArity, idType, isBottomingId,+ isJoinId, isJoinId_maybe )+import Var ( Var )+import SetLevels+import UniqSupply ( UniqSupply )+import Bag+import Util+import Maybes+import Outputable+import Type+import qualified Data.IntMap as M++import Data.List ( partition )++#include "HsVersions.h"++{-+ -----------------+ Overall game plan+ -----------------++The Big Main Idea is:++ To float out sub-expressions that can thereby get outside+ a non-one-shot value lambda, and hence may be shared.+++To achieve this we may need to do two thing:++ a) Let-bind the sub-expression:++ f (g x) ==> let lvl = f (g x) in lvl++ Now we can float the binding for 'lvl'.++ b) More than that, we may need to abstract wrt a type variable++ \x -> ... /\a -> let v = ...a... in ....++ Here the binding for v mentions 'a' but not 'x'. So we+ abstract wrt 'a', to give this binding for 'v':++ vp = /\a -> ...a...+ v = vp a++ Now the binding for vp can float out unimpeded.+ I can't remember why this case seemed important enough to+ deal with, but I certainly found cases where important floats+ didn't happen if we did not abstract wrt tyvars.++With this in mind we can also achieve another goal: lambda lifting.+We can make an arbitrary (function) binding float to top level by+abstracting wrt *all* local variables, not just type variables, leaving+a binding that can be floated right to top level. Whether or not this+happens is controlled by a flag.+++Random comments+~~~~~~~~~~~~~~~++At the moment we never float a binding out to between two adjacent+lambdas. For example:++@+ \x y -> let t = x+x in ...+===>+ \x -> let t = x+x in \y -> ...+@+Reason: this is less efficient in the case where the original lambda+is never partially applied.++But there's a case I've seen where this might not be true. Consider:+@+elEm2 x ys+ = elem' x ys+ where+ elem' _ [] = False+ elem' x (y:ys) = x==y || elem' x ys+@+It turns out that this generates a subexpression of the form+@+ \deq x ys -> let eq = eqFromEqDict deq in ...+@+vwhich might usefully be separated to+@+ \deq -> let eq = eqFromEqDict deq in \xy -> ...+@+Well, maybe. We don't do this at the moment.++Note [Join points]+~~~~~~~~~~~~~~~~~~+Every occurrence of a join point must be a tail call (see Note [Invariants on+join points] in CoreSyn), so we must be careful with how far we float them. The+mechanism for doing so is the *join ceiling*, detailed in Note [Join ceiling]+in SetLevels. For us, the significance is that a binder might be marked to be+dropped at the nearest boundary between tail calls and non-tail calls. For+example:++ (< join j = ... in+ let x = < ... > in+ case < ... > of+ A -> ...+ B -> ...+ >) < ... > < ... >++Here the join ceilings are marked with angle brackets. Either side of an+application is a join ceiling, as is the scrutinee position of a case+expression or the RHS of a let binding (but not a join point).++Why do we *want* do float join points at all? After all, they're never+allocated, so there's no sharing to be gained by floating them. However, the+other benefit of floating is making RHSes small, and this can have a significant+impact. In particular, stream fusion has been known to produce nested loops like+this:++ joinrec j1 x1 =+ joinrec j2 x2 =+ joinrec j3 x3 = ... jump j1 (x3 + 1) ... jump j2 (x3 + 1) ...+ in jump j3 x2+ in jump j2 x1+ in jump j1 x++(Assume x1 and x2 do *not* occur free in j3.)++Here j1 and j2 are wholly superfluous---each of them merely forwards its+argument to j3. Since j3 only refers to x3, we can float j2 and j3 to make+everything one big mutual recursion:++ joinrec j1 x1 = jump j2 x1+ j2 x2 = jump j3 x2+ j3 x3 = ... jump j1 (x3 + 1) ... jump j2 (x3 + 1) ...+ in jump j1 x++Now the simplifier will happily inline the trivial j1 and j2, leaving only j3.+Without floating, we're stuck with three loops instead of one.++************************************************************************+* *+\subsection[floatOutwards]{@floatOutwards@: let-floating interface function}+* *+************************************************************************+-}++floatOutwards :: FloatOutSwitches+ -> DynFlags+ -> UniqSupply+ -> CoreProgram -> IO CoreProgram++floatOutwards float_sws dflags us pgm+ = do {+ let { annotated_w_levels = setLevels float_sws pgm us ;+ (fss, binds_s') = unzip (map floatTopBind annotated_w_levels)+ } ;++ dumpIfSet_dyn dflags Opt_D_verbose_core2core "Levels added:"+ (vcat (map ppr annotated_w_levels));++ let { (tlets, ntlets, lams) = get_stats (sum_stats fss) };++ dumpIfSet_dyn dflags Opt_D_dump_simpl_stats "FloatOut stats:"+ (hcat [ int tlets, text " Lets floated to top level; ",+ int ntlets, text " Lets floated elsewhere; from ",+ int lams, text " Lambda groups"]);++ return (bagToList (unionManyBags binds_s'))+ }++floatTopBind :: LevelledBind -> (FloatStats, Bag CoreBind)+floatTopBind bind+ = case (floatBind bind) of { (fs, floats, bind') ->+ let float_bag = flattenTopFloats floats+ in case bind' of+ -- bind' can't have unlifted values or join points, so can only be one+ -- value bind, rec or non-rec (see comment on floatBind)+ [Rec prs] -> (fs, unitBag (Rec (addTopFloatPairs float_bag prs)))+ [NonRec b e] -> (fs, float_bag `snocBag` NonRec b e)+ _ -> pprPanic "floatTopBind" (ppr bind') }++{-+************************************************************************+* *+\subsection[FloatOut-Bind]{Floating in a binding (the business end)}+* *+************************************************************************+-}++floatBind :: LevelledBind -> (FloatStats, FloatBinds, [CoreBind])+ -- Returns a list with either+ -- * A single non-recursive binding (value or join point), or+ -- * The following, in order:+ -- * Zero or more non-rec unlifted bindings+ -- * One or both of:+ -- * A recursive group of join binds+ -- * A recursive group of value binds+ -- See Note [Floating out of Rec rhss] for why things get arranged this way.+floatBind (NonRec (TB var _) rhs)+ = case (floatRhs var rhs) of { (fs, rhs_floats, rhs') ->++ -- A tiresome hack:+ -- see Note [Bottoming floats: eta expansion] in SetLevels+ let rhs'' | isBottomingId var = etaExpand (idArity var) rhs'+ | otherwise = rhs'++ in (fs, rhs_floats, [NonRec var rhs'']) }++floatBind (Rec pairs)+ = case floatList do_pair pairs of { (fs, rhs_floats, new_pairs) ->+ let (new_ul_pairss, new_other_pairss) = unzip new_pairs+ (new_join_pairs, new_l_pairs) = partition (isJoinId . fst)+ (concat new_other_pairss)+ -- Can't put the join points and the values in the same rec group+ new_rec_binds | null new_join_pairs = [ Rec new_l_pairs ]+ | null new_l_pairs = [ Rec new_join_pairs ]+ | otherwise = [ Rec new_l_pairs+ , Rec new_join_pairs ]+ new_non_rec_binds = [ NonRec b e | (b, e) <- concat new_ul_pairss ]+ in+ (fs, rhs_floats, new_non_rec_binds ++ new_rec_binds) }+ where+ do_pair :: (LevelledBndr, LevelledExpr)+ -> (FloatStats, FloatBinds,+ ([(Id,CoreExpr)], -- Non-recursive unlifted value bindings+ [(Id,CoreExpr)])) -- Join points and lifted value bindings+ do_pair (TB name spec, rhs)+ | isTopLvl dest_lvl -- See Note [floatBind for top level]+ = case (floatRhs name rhs) of { (fs, rhs_floats, rhs') ->+ (fs, emptyFloats, ([], addTopFloatPairs (flattenTopFloats rhs_floats)+ [(name, rhs')]))}+ | otherwise -- Note [Floating out of Rec rhss]+ = case (floatRhs name rhs) of { (fs, rhs_floats, rhs') ->+ case (partitionByLevel dest_lvl rhs_floats) of { (rhs_floats', heres) ->+ case (splitRecFloats heres) of { (ul_pairs, pairs, case_heres) ->+ let pairs' = (name, installUnderLambdas case_heres rhs') : pairs in+ (fs, rhs_floats', (ul_pairs, pairs')) }}}+ where+ dest_lvl = floatSpecLevel spec++splitRecFloats :: Bag FloatBind+ -> ([(Id,CoreExpr)], -- Non-recursive unlifted value bindings+ [(Id,CoreExpr)], -- Join points and lifted value bindings+ Bag FloatBind) -- A tail of further bindings+-- The "tail" begins with a case+-- See Note [Floating out of Rec rhss]+splitRecFloats fs+ = go [] [] (bagToList fs)+ where+ go ul_prs prs (FloatLet (NonRec b r) : fs) | isUnliftedType (idType b)+ , not (isJoinId b)+ = go ((b,r):ul_prs) prs fs+ | otherwise+ = go ul_prs ((b,r):prs) fs+ go ul_prs prs (FloatLet (Rec prs') : fs) = go ul_prs (prs' ++ prs) fs+ go ul_prs prs fs = (reverse ul_prs, prs,+ listToBag fs)+ -- Order only matters for+ -- non-rec++installUnderLambdas :: Bag FloatBind -> CoreExpr -> CoreExpr+-- Note [Floating out of Rec rhss]+installUnderLambdas floats e+ | isEmptyBag floats = e+ | otherwise = go e+ where+ go (Lam b e) = Lam b (go e)+ go e = install floats e++---------------+floatList :: (a -> (FloatStats, FloatBinds, b)) -> [a] -> (FloatStats, FloatBinds, [b])+floatList _ [] = (zeroStats, emptyFloats, [])+floatList f (a:as) = case f a of { (fs_a, binds_a, b) ->+ case floatList f as of { (fs_as, binds_as, bs) ->+ (fs_a `add_stats` fs_as, binds_a `plusFloats` binds_as, b:bs) }}++{-+Note [Floating out of Rec rhss]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider Rec { f<1,0> = \xy. body }+From the body we may get some floats. The ones with level <1,0> must+stay here, since they may mention f. Ideally we'd like to make them+part of the Rec block pairs -- but we can't if there are any+FloatCases involved.++Nor is it a good idea to dump them in the rhs, but outside the lambda+ f = case x of I# y -> \xy. body+because now f's arity might get worse, which is Not Good. (And if+there's an SCC around the RHS it might not get better again.+See Trac #5342.)++So, gruesomely, we split the floats into+ * the outer FloatLets, which can join the Rec, and+ * an inner batch starting in a FloatCase, which are then+ pushed *inside* the lambdas.+This loses full-laziness the rare situation where there is a+FloatCase and a Rec interacting.++If there are unlifted FloatLets (that *aren't* join points) among the floats,+we can't add them to the recursive group without angering Core Lint, but since+they must be ok-for-speculation, they can't actually be making any recursive+calls, so we can safely pull them out and keep them non-recursive.++(Why is something getting floated to <1,0> that doesn't make a recursive call?+The case that came up in testing was that f *and* the unlifted binding were+getting floated *to the same place*:++ \x<2,0> ->+ ... <3,0>+ letrec { f<F<2,0>> =+ ... let x'<F<2,0>> = x +# 1# in ...+ } in ...++Everything gets labeled "float to <2,0>" because it all depends on x, but this+makes f and x' look mutually recursive when they're not.++The test was shootout/k-nucleotide, as compiled using commit 47d5dd68 on the+wip/join-points branch.++TODO: This can probably be solved somehow in SetLevels. The difference between+"this *is at* level <2,0>" and "this *depends on* level <2,0>" is very+important.)++Note [floatBind for top level]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We may have a *nested* binding whose destination level is (FloatMe tOP_LEVEL), thus+ letrec { foo <0,0> = .... (let bar<0,0> = .. in ..) .... }+The binding for bar will be in the "tops" part of the floating binds,+and thus not partioned by floatBody.++We could perhaps get rid of the 'tops' component of the floating binds,+but this case works just as well.+++************************************************************************++\subsection[FloatOut-Expr]{Floating in expressions}+* *+************************************************************************+-}++floatBody :: Level+ -> LevelledExpr+ -> (FloatStats, FloatBinds, CoreExpr)++floatBody lvl arg -- Used rec rhss, and case-alternative rhss+ = case (floatExpr arg) of { (fsa, floats, arg') ->+ case (partitionByLevel lvl floats) of { (floats', heres) ->+ -- Dump bindings are bound here+ (fsa, floats', install heres arg') }}++-----------------++{- Note [Floating past breakpoints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We used to disallow floating out of breakpoint ticks (see #10052). However, I+think this is too restrictive.++Consider the case of an expression scoped over by a breakpoint tick,++ tick<...> (let x = ... in f x)++In this case it is completely legal to float out x, despite the fact that+breakpoint ticks are scoped,++ let x = ... in (tick<...> f x)++The reason here is that we know that the breakpoint will still be hit when the+expression is entered since the tick still scopes over the RHS.++-}++floatExpr :: LevelledExpr+ -> (FloatStats, FloatBinds, CoreExpr)+floatExpr (Var v) = (zeroStats, emptyFloats, Var v)+floatExpr (Type ty) = (zeroStats, emptyFloats, Type ty)+floatExpr (Coercion co) = (zeroStats, emptyFloats, Coercion co)+floatExpr (Lit lit) = (zeroStats, emptyFloats, Lit lit)++floatExpr (App e a)+ = case (atJoinCeiling $ floatExpr e) of { (fse, floats_e, e') ->+ case (atJoinCeiling $ floatExpr a) of { (fsa, floats_a, a') ->+ (fse `add_stats` fsa, floats_e `plusFloats` floats_a, App e' a') }}++floatExpr lam@(Lam (TB _ lam_spec) _)+ = let (bndrs_w_lvls, body) = collectBinders lam+ bndrs = [b | TB b _ <- bndrs_w_lvls]+ bndr_lvl = asJoinCeilLvl (floatSpecLevel lam_spec)+ -- All the binders have the same level+ -- See SetLevels.lvlLamBndrs+ -- Use asJoinCeilLvl to make this the join ceiling+ in+ case (floatBody bndr_lvl body) of { (fs, floats, body') ->+ (add_to_stats fs floats, floats, mkLams bndrs body') }++floatExpr (Tick tickish expr)+ | tickish `tickishScopesLike` SoftScope -- not scoped, can just float+ = case (atJoinCeiling $ floatExpr expr) of { (fs, floating_defns, expr') ->+ (fs, floating_defns, Tick tickish expr') }++ | not (tickishCounts tickish) || tickishCanSplit tickish+ = case (atJoinCeiling $ floatExpr expr) of { (fs, floating_defns, expr') ->+ let -- Annotate bindings floated outwards past an scc expression+ -- with the cc. We mark that cc as "duplicated", though.+ annotated_defns = wrapTick (mkNoCount tickish) floating_defns+ in+ (fs, annotated_defns, Tick tickish expr') }++ -- Note [Floating past breakpoints]+ | Breakpoint{} <- tickish+ = case (floatExpr expr) of { (fs, floating_defns, expr') ->+ (fs, floating_defns, Tick tickish expr') }++ | otherwise+ = pprPanic "floatExpr tick" (ppr tickish)++floatExpr (Cast expr co)+ = case (atJoinCeiling $ floatExpr expr) of { (fs, floating_defns, expr') ->+ (fs, floating_defns, Cast expr' co) }++floatExpr (Let bind body)+ = case bind_spec of+ FloatMe dest_lvl+ -> case (floatBind bind) of { (fsb, bind_floats, binds') ->+ case (floatExpr body) of { (fse, body_floats, body') ->+ let new_bind_floats = foldr plusFloats emptyFloats+ (map (unitLetFloat dest_lvl) binds') in+ ( add_stats fsb fse+ , bind_floats `plusFloats` new_bind_floats+ `plusFloats` body_floats+ , body') }}++ StayPut bind_lvl -- See Note [Avoiding unnecessary floating]+ -> case (floatBind bind) of { (fsb, bind_floats, binds') ->+ case (floatBody bind_lvl body) of { (fse, body_floats, body') ->+ ( add_stats fsb fse+ , bind_floats `plusFloats` body_floats+ , foldr Let body' binds' ) }}+ where+ bind_spec = case bind of+ NonRec (TB _ s) _ -> s+ Rec ((TB _ s, _) : _) -> s+ Rec [] -> panic "floatExpr:rec"++floatExpr (Case scrut (TB case_bndr case_spec) ty alts)+ = case case_spec of+ FloatMe dest_lvl -- Case expression moves+ | [(con@(DataAlt {}), bndrs, rhs)] <- alts+ -> case atJoinCeiling $ floatExpr scrut of { (fse, fde, scrut') ->+ case floatExpr rhs of { (fsb, fdb, rhs') ->+ let+ float = unitCaseFloat dest_lvl scrut'+ case_bndr con [b | TB b _ <- bndrs]+ in+ (add_stats fse fsb, fde `plusFloats` float `plusFloats` fdb, rhs') }}+ | otherwise+ -> pprPanic "Floating multi-case" (ppr alts)++ StayPut bind_lvl -- Case expression stays put+ -> case atJoinCeiling $ floatExpr scrut of { (fse, fde, scrut') ->+ case floatList (float_alt bind_lvl) alts of { (fsa, fda, alts') ->+ (add_stats fse fsa, fda `plusFloats` fde, Case scrut' case_bndr ty alts')+ }}+ where+ float_alt bind_lvl (con, bs, rhs)+ = case (floatBody bind_lvl rhs) of { (fs, rhs_floats, rhs') ->+ (fs, rhs_floats, (con, [b | TB b _ <- bs], rhs')) }++floatRhs :: CoreBndr+ -> LevelledExpr+ -> (FloatStats, FloatBinds, CoreExpr)+floatRhs bndr rhs+ | Just join_arity <- isJoinId_maybe bndr+ , Just (bndrs, body) <- try_collect join_arity rhs []+ = case bndrs of+ [] -> floatExpr rhs+ (TB _ lam_spec):_ ->+ let lvl = floatSpecLevel lam_spec in+ case floatBody lvl body of { (fs, floats, body') ->+ (fs, floats, mkLams [b | TB b _ <- bndrs] body') }+ | otherwise+ = atJoinCeiling $ floatExpr rhs+ where+ try_collect 0 expr acc = Just (reverse acc, expr)+ try_collect n (Lam b e) acc = try_collect (n-1) e (b:acc)+ try_collect _ _ _ = Nothing++{-+Note [Avoiding unnecessary floating]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general we want to avoid floating a let unnecessarily, because+it might worsen strictness:+ let+ x = ...(let y = e in y+y)....+Here y is demanded. If we float it outside the lazy 'x=..' then+we'd have to zap its demand info, and it may never be restored.++So at a 'let' we leave the binding right where the are unless+the binding will escape a value lambda, e.g.++(\x -> let y = fac 100 in y)++That's what the partitionByMajorLevel does in the floatExpr (Let ...)+case.++Notice, though, that we must take care to drop any bindings+from the body of the let that depend on the staying-put bindings.++We used instead to do the partitionByMajorLevel on the RHS of an '=',+in floatRhs. But that was quite tiresome. We needed to test for+values or trival rhss, because (in particular) we don't want to insert+new bindings between the "=" and the "\". E.g.+ f = \x -> let <bind> in <body>+We do not want+ f = let <bind> in \x -> <body>+(a) The simplifier will immediately float it further out, so we may+ as well do so right now; in general, keeping rhss as manifest+ values is good+(b) If a float-in pass follows immediately, it might add yet more+ bindings just after the '='. And some of them might (correctly)+ be strict even though the 'let f' is lazy, because f, being a value,+ gets its demand-info zapped by the simplifier.+And even all that turned out to be very fragile, and broke+altogether when profiling got in the way.++So now we do the partition right at the (Let..) itself.++************************************************************************+* *+\subsection{Utility bits for floating stats}+* *+************************************************************************++I didn't implement this with unboxed numbers. I don't want to be too+strict in this stuff, as it is rarely turned on. (WDP 95/09)+-}++data FloatStats+ = FlS Int -- Number of top-floats * lambda groups they've been past+ Int -- Number of non-top-floats * lambda groups they've been past+ Int -- Number of lambda (groups) seen++get_stats :: FloatStats -> (Int, Int, Int)+get_stats (FlS a b c) = (a, b, c)++zeroStats :: FloatStats+zeroStats = FlS 0 0 0++sum_stats :: [FloatStats] -> FloatStats+sum_stats xs = foldr add_stats zeroStats xs++add_stats :: FloatStats -> FloatStats -> FloatStats+add_stats (FlS a1 b1 c1) (FlS a2 b2 c2)+ = FlS (a1 + a2) (b1 + b2) (c1 + c2)++add_to_stats :: FloatStats -> FloatBinds -> FloatStats+add_to_stats (FlS a b c) (FB tops ceils others)+ = FlS (a + lengthBag tops)+ (b + lengthBag ceils + lengthBag (flattenMajor others))+ (c + 1)++{-+************************************************************************+* *+\subsection{Utility bits for floating}+* *+************************************************************************++Note [Representation of FloatBinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The FloatBinds types is somewhat important. We can get very large numbers+of floating bindings, often all destined for the top level. A typical example+is x = [4,2,5,2,5, .... ]+Then we get lots of small expressions like (fromInteger 4), which all get+lifted to top level.++The trouble is that+ (a) we partition these floating bindings *at every binding site*+ (b) SetLevels introduces a new bindings site for every float+So we had better not look at each binding at each binding site!++That is why MajorEnv is represented as a finite map.++We keep the bindings destined for the *top* level separate, because+we float them out even if they don't escape a *value* lambda; see+partitionByMajorLevel.+-}++type FloatLet = CoreBind -- INVARIANT: a FloatLet is always lifted+type MajorEnv = M.IntMap MinorEnv -- Keyed by major level+type MinorEnv = M.IntMap (Bag FloatBind) -- Keyed by minor level++data FloatBinds = FB !(Bag FloatLet) -- Destined for top level+ !(Bag FloatBind) -- Destined for join ceiling+ !MajorEnv -- Other levels+ -- See Note [Representation of FloatBinds]++instance Outputable FloatBinds where+ ppr (FB fbs ceils defs)+ = text "FB" <+> (braces $ vcat+ [ text "tops =" <+> ppr fbs+ , text "ceils =" <+> ppr ceils+ , text "non-tops =" <+> ppr defs ])++flattenTopFloats :: FloatBinds -> Bag CoreBind+flattenTopFloats (FB tops ceils defs)+ = ASSERT2( isEmptyBag (flattenMajor defs), ppr defs )+ ASSERT2( isEmptyBag ceils, ppr ceils )+ tops++addTopFloatPairs :: Bag CoreBind -> [(Id,CoreExpr)] -> [(Id,CoreExpr)]+addTopFloatPairs float_bag prs+ = foldrBag add prs float_bag+ where+ add (NonRec b r) prs = (b,r):prs+ add (Rec prs1) prs2 = prs1 ++ prs2++flattenMajor :: MajorEnv -> Bag FloatBind+flattenMajor = M.foldr (unionBags . flattenMinor) emptyBag++flattenMinor :: MinorEnv -> Bag FloatBind+flattenMinor = M.foldr unionBags emptyBag++emptyFloats :: FloatBinds+emptyFloats = FB emptyBag emptyBag M.empty++unitCaseFloat :: Level -> CoreExpr -> Id -> AltCon -> [Var] -> FloatBinds+unitCaseFloat (Level major minor t) e b con bs+ | t == JoinCeilLvl+ = FB emptyBag floats M.empty+ | otherwise+ = FB emptyBag emptyBag (M.singleton major (M.singleton minor floats))+ where+ floats = unitBag (FloatCase e b con bs)++unitLetFloat :: Level -> FloatLet -> FloatBinds+unitLetFloat lvl@(Level major minor t) b+ | isTopLvl lvl = FB (unitBag b) emptyBag M.empty+ | t == JoinCeilLvl = FB emptyBag floats M.empty+ | otherwise = FB emptyBag emptyBag (M.singleton major+ (M.singleton minor floats))+ where+ floats = unitBag (FloatLet b)++plusFloats :: FloatBinds -> FloatBinds -> FloatBinds+plusFloats (FB t1 c1 l1) (FB t2 c2 l2)+ = FB (t1 `unionBags` t2) (c1 `unionBags` c2) (l1 `plusMajor` l2)++plusMajor :: MajorEnv -> MajorEnv -> MajorEnv+plusMajor = M.unionWith plusMinor++plusMinor :: MinorEnv -> MinorEnv -> MinorEnv+plusMinor = M.unionWith unionBags++install :: Bag FloatBind -> CoreExpr -> CoreExpr+install defn_groups expr+ = foldrBag wrapFloat expr defn_groups++partitionByLevel+ :: Level -- Partitioning level+ -> FloatBinds -- Defns to be divided into 2 piles...+ -> (FloatBinds, -- Defns with level strictly < partition level,+ Bag FloatBind) -- The rest++{-+-- ---- partitionByMajorLevel ----+-- Float it if we escape a value lambda,+-- *or* if we get to the top level+-- *or* if it's a case-float and its minor level is < current+--+-- If we can get to the top level, say "yes" anyway. This means that+-- x = f e+-- transforms to+-- lvl = e+-- x = f lvl+-- which is as it should be++partitionByMajorLevel (Level major _) (FB tops defns)+ = (FB tops outer, heres `unionBags` flattenMajor inner)+ where+ (outer, mb_heres, inner) = M.splitLookup major defns+ heres = case mb_heres of+ Nothing -> emptyBag+ Just h -> flattenMinor h+-}++partitionByLevel (Level major minor typ) (FB tops ceils defns)+ = (FB tops ceils' (outer_maj `plusMajor` M.singleton major outer_min),+ here_min `unionBags` here_ceil+ `unionBags` flattenMinor inner_min+ `unionBags` flattenMajor inner_maj)++ where+ (outer_maj, mb_here_maj, inner_maj) = M.splitLookup major defns+ (outer_min, mb_here_min, inner_min) = case mb_here_maj of+ Nothing -> (M.empty, Nothing, M.empty)+ Just min_defns -> M.splitLookup minor min_defns+ here_min = mb_here_min `orElse` emptyBag+ (here_ceil, ceils') | typ == JoinCeilLvl = (ceils, emptyBag)+ | otherwise = (emptyBag, ceils)++-- Like partitionByLevel, but instead split out the bindings that are marked+-- to float to the nearest join ceiling (see Note [Join points])+partitionAtJoinCeiling :: FloatBinds -> (FloatBinds, Bag FloatBind)+partitionAtJoinCeiling (FB tops ceils defs)+ = (FB tops emptyBag defs, ceils)++-- Perform some action at a join ceiling, i.e., don't let join points float out+-- (see Note [Join points])+atJoinCeiling :: (FloatStats, FloatBinds, CoreExpr)+ -> (FloatStats, FloatBinds, CoreExpr)+atJoinCeiling (fs, floats, expr')+ = (fs, floats', install ceils expr')+ where+ (floats', ceils) = partitionAtJoinCeiling floats++wrapTick :: Tickish Id -> FloatBinds -> FloatBinds+wrapTick t (FB tops ceils defns)+ = FB (mapBag wrap_bind tops) (wrap_defns ceils)+ (M.map (M.map wrap_defns) defns)+ where+ wrap_defns = mapBag wrap_one++ wrap_bind (NonRec binder rhs) = NonRec binder (maybe_tick rhs)+ wrap_bind (Rec pairs) = Rec (mapSnd maybe_tick pairs)++ wrap_one (FloatLet bind) = FloatLet (wrap_bind bind)+ wrap_one (FloatCase e b c bs) = FloatCase (maybe_tick e) b c bs++ maybe_tick e | exprIsHNF e = tickHNFArgs t e+ | otherwise = mkTick t e+ -- we don't need to wrap a tick around an HNF when we float it+ -- outside a tick: that is an invariant of the tick semantics+ -- Conversely, inlining of HNFs inside an SCC is allowed, and+ -- indeed the HNF we're floating here might well be inlined back+ -- again, and we don't want to end up with duplicate ticks.
+ simplCore/LiberateCase.hs view
@@ -0,0 +1,422 @@+{-+(c) The AQUA Project, Glasgow University, 1994-1998++\section[LiberateCase]{Unroll recursion to allow evals to be lifted from a loop}+-}++{-# LANGUAGE CPP #-}+module LiberateCase ( liberateCase ) where++#include "HsVersions.h"++import DynFlags+import CoreSyn+import CoreUnfold ( couldBeSmallEnoughToInline )+import Id+import VarEnv+import Util ( notNull )++{-+The liberate-case transformation+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This module walks over @Core@, and looks for @case@ on free variables.+The criterion is:+ if there is case on a free on the route to the recursive call,+ then the recursive call is replaced with an unfolding.++Example++ f = \ t -> case v of+ V a b -> a : f t++=> the inner f is replaced.++ f = \ t -> case v of+ V a b -> a : (letrec+ f = \ t -> case v of+ V a b -> a : f t+ in f) t+(note the NEED for shadowing)++=> Simplify++ f = \ t -> case v of+ V a b -> a : (letrec+ f = \ t -> a : f t+ in f t)++Better code, because 'a' is free inside the inner letrec, rather+than needing projection from v.++Note that this deals with *free variables*. SpecConstr deals with+*arguments* that are of known form. E.g.++ last [] = error+ last (x:[]) = x+ last (x:xs) = last xs+++Note [Scrutinee with cast]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:+ f = \ t -> case (v `cast` co) of+ V a b -> a : f t++Exactly the same optimisation (unrolling one call to f) will work here,+despite the cast. See mk_alt_env in the Case branch of libCase.+++Note [Only functions!]+~~~~~~~~~~~~~~~~~~~~~~+Consider the following code++ f = g (case v of V a b -> a : t f)++where g is expensive. If we aren't careful, liberate case will turn this into++ f = g (case v of+ V a b -> a : t (letrec f = g (case v of V a b -> a : f t)+ in f)+ )++Yikes! We evaluate g twice. This leads to a O(2^n) explosion+if g calls back to the same code recursively.++Solution: make sure that we only do the liberate-case thing on *functions*++To think about (Apr 94)+~~~~~~~~~~~~~~+Main worry: duplicating code excessively. At the moment we duplicate+the entire binding group once at each recursive call. But there may+be a group of recursive calls which share a common set of evaluated+free variables, in which case the duplication is a plain waste.++Another thing we could consider adding is some unfold-threshold thing,+so that we'll only duplicate if the size of the group rhss isn't too+big.++Data types+~~~~~~~~~~+The ``level'' of a binder tells how many+recursive defns lexically enclose the binding+A recursive defn "encloses" its RHS, not its+scope. For example:+\begin{verbatim}+ letrec f = let g = ... in ...+ in+ let h = ...+ in ...+\end{verbatim}+Here, the level of @f@ is zero, the level of @g@ is one,+and the level of @h@ is zero (NB not one).+++************************************************************************+* *+ Top-level code+* *+************************************************************************+-}++liberateCase :: DynFlags -> CoreProgram -> CoreProgram+liberateCase dflags binds = do_prog (initEnv dflags) binds+ where+ do_prog _ [] = []+ do_prog env (bind:binds) = bind' : do_prog env' binds+ where+ (env', bind') = libCaseBind env bind++{-+************************************************************************+* *+ Main payload+* *+************************************************************************++Bindings+~~~~~~~~+-}++libCaseBind :: LibCaseEnv -> CoreBind -> (LibCaseEnv, CoreBind)++libCaseBind env (NonRec binder rhs)+ = (addBinders env [binder], NonRec binder (libCase env rhs))++libCaseBind env (Rec pairs)+ = (env_body, Rec pairs')+ where+ binders = map fst pairs++ env_body = addBinders env binders++ pairs' = [(binder, libCase env_rhs rhs) | (binder,rhs) <- pairs]++ -- We extend the rec-env by binding each Id to its rhs, first+ -- processing the rhs with an *un-extended* environment, so+ -- that the same process doesn't occur for ever!+ env_rhs = addRecBinds env [ (localiseId binder, libCase env_body rhs)+ | (binder, rhs) <- pairs+ , rhs_small_enough binder rhs ]+ -- localiseID : see Note [Need to localiseId in libCaseBind]+++ rhs_small_enough id rhs -- Note [Small enough]+ = idArity id > 0 -- Note [Only functions!]+ && maybe True (\size -> couldBeSmallEnoughToInline (lc_dflags env) size rhs)+ (bombOutSize env)++{-+Note [Need to localiseId in libCaseBind]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The call to localiseId is needed for two subtle reasons+(a) Reset the export flags on the binders so+ that we don't get name clashes on exported things if the+ local binding floats out to top level. This is most unlikely+ to happen, since the whole point concerns free variables.+ But resetting the export flag is right regardless.++(b) Make the name an Internal one. External Names should never be+ nested; if it were floated to the top level, we'd get a name+ clash at code generation time.++Note [Small enough]+~~~~~~~~~~~~~~~~~~~+Consider+ \fv. letrec+ f = \x. BIG...(case fv of { (a,b) -> ...g.. })...+ g = \y. SMALL...f...+Then we *can* do liberate-case on g (small RHS) but not for f (too big).+But we can choose on a item-by-item basis, and that's what the+rhs_small_enough call in the comprehension for env_rhs does.++Expressions+~~~~~~~~~~~+-}++libCase :: LibCaseEnv+ -> CoreExpr+ -> CoreExpr++libCase env (Var v) = libCaseApp env v []+libCase _ (Lit lit) = Lit lit+libCase _ (Type ty) = Type ty+libCase _ (Coercion co) = Coercion co+libCase env e@(App {}) | let (fun, args) = collectArgs e+ , Var v <- fun+ = libCaseApp env v args+libCase env (App fun arg) = App (libCase env fun) (libCase env arg)+libCase env (Tick tickish body) = Tick tickish (libCase env body)+libCase env (Cast e co) = Cast (libCase env e) co++libCase env (Lam binder body)+ = Lam binder (libCase (addBinders env [binder]) body)++libCase env (Let bind body)+ = Let bind' (libCase env_body body)+ where+ (env_body, bind') = libCaseBind env bind++libCase env (Case scrut bndr ty alts)+ = Case (libCase env scrut) bndr ty (map (libCaseAlt env_alts) alts)+ where+ env_alts = addBinders (mk_alt_env scrut) [bndr]+ mk_alt_env (Var scrut_var) = addScrutedVar env scrut_var+ mk_alt_env (Cast scrut _) = mk_alt_env scrut -- Note [Scrutinee with cast]+ mk_alt_env _ = env++libCaseAlt :: LibCaseEnv -> (AltCon, [CoreBndr], CoreExpr)+ -> (AltCon, [CoreBndr], CoreExpr)+libCaseAlt env (con,args,rhs) = (con, args, libCase (addBinders env args) rhs)++{-+Ids+~~~++To unfold, we can't just wrap the id itself in its binding if it's a join point:++ jump j a b c => (joinrec j x y z = ... in jump j) a b c -- wrong!!!++Every jump must provide all arguments, so we have to be careful to wrap the+whole jump instead:++ jump j a b c => joinrec j x y z = ... in jump j a b c -- right++-}++libCaseApp :: LibCaseEnv -> Id -> [CoreExpr] -> CoreExpr+libCaseApp env v args+ | Just the_bind <- lookupRecId env v -- It's a use of a recursive thing+ , notNull free_scruts -- with free vars scrutinised in RHS+ = Let the_bind expr'++ | otherwise+ = expr'++ where+ rec_id_level = lookupLevel env v+ free_scruts = freeScruts env rec_id_level+ expr' = mkApps (Var v) (map (libCase env) args)++freeScruts :: LibCaseEnv+ -> LibCaseLevel -- Level of the recursive Id+ -> [Id] -- Ids that are scrutinised between the binding+ -- of the recursive Id and here+freeScruts env rec_bind_lvl+ = [v | (v, scrut_bind_lvl, scrut_at_lvl) <- lc_scruts env+ , scrut_bind_lvl <= rec_bind_lvl+ , scrut_at_lvl > rec_bind_lvl]+ -- Note [When to specialise]+ -- Note [Avoiding fruitless liberate-case]++{-+Note [When to specialise]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f = \x. letrec g = \y. case x of+ True -> ... (f a) ...+ False -> ... (g b) ...++We get the following levels+ f 0+ x 1+ g 1+ y 2++Then 'x' is being scrutinised at a deeper level than its binding, so+it's added to lc_sruts: [(x,1)]++We do *not* want to specialise the call to 'f', because 'x' is not free+in 'f'. So here the bind-level of 'x' (=1) is not <= the bind-level of 'f' (=0).++We *do* want to specialise the call to 'g', because 'x' is free in g.+Here the bind-level of 'x' (=1) is <= the bind-level of 'g' (=1).++Note [Avoiding fruitless liberate-case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider also:+ f = \x. case top_lvl_thing of+ I# _ -> let g = \y. ... g ...+ in ...++Here, top_lvl_thing is scrutinised at a level (1) deeper than its+binding site (0). Nevertheless, we do NOT want to specialise the call+to 'g' because all the structure in its free variables is already+visible at the definition site for g. Hence, when considering specialising+an occurrence of 'g', we want to check that there's a scruted-var v st++ a) v's binding site is *outside* g+ b) v's scrutinisation site is *inside* g+++************************************************************************+* *+ Utility functions+* *+************************************************************************+-}++addBinders :: LibCaseEnv -> [CoreBndr] -> LibCaseEnv+addBinders env@(LibCaseEnv { lc_lvl = lvl, lc_lvl_env = lvl_env }) binders+ = env { lc_lvl_env = lvl_env' }+ where+ lvl_env' = extendVarEnvList lvl_env (binders `zip` repeat lvl)++addRecBinds :: LibCaseEnv -> [(Id,CoreExpr)] -> LibCaseEnv+addRecBinds env@(LibCaseEnv {lc_lvl = lvl, lc_lvl_env = lvl_env,+ lc_rec_env = rec_env}) pairs+ = env { lc_lvl = lvl', lc_lvl_env = lvl_env', lc_rec_env = rec_env' }+ where+ lvl' = lvl + 1+ lvl_env' = extendVarEnvList lvl_env [(binder,lvl) | (binder,_) <- pairs]+ rec_env' = extendVarEnvList rec_env [(binder, Rec pairs) | (binder,_) <- pairs]++addScrutedVar :: LibCaseEnv+ -> Id -- This Id is being scrutinised by a case expression+ -> LibCaseEnv++addScrutedVar env@(LibCaseEnv { lc_lvl = lvl, lc_lvl_env = lvl_env,+ lc_scruts = scruts }) scrut_var+ | bind_lvl < lvl+ = env { lc_scruts = scruts' }+ -- Add to scruts iff the scrut_var is being scrutinised at+ -- a deeper level than its defn++ | otherwise = env+ where+ scruts' = (scrut_var, bind_lvl, lvl) : scruts+ bind_lvl = case lookupVarEnv lvl_env scrut_var of+ Just lvl -> lvl+ Nothing -> topLevel++lookupRecId :: LibCaseEnv -> Id -> Maybe CoreBind+lookupRecId env id = lookupVarEnv (lc_rec_env env) id++lookupLevel :: LibCaseEnv -> Id -> LibCaseLevel+lookupLevel env id+ = case lookupVarEnv (lc_lvl_env env) id of+ Just lvl -> lvl+ Nothing -> topLevel++{-+************************************************************************+* *+ The environment+* *+************************************************************************+-}++type LibCaseLevel = Int++topLevel :: LibCaseLevel+topLevel = 0++data LibCaseEnv+ = LibCaseEnv {+ lc_dflags :: DynFlags,++ lc_lvl :: LibCaseLevel, -- Current level+ -- The level is incremented when (and only when) going+ -- inside the RHS of a (sufficiently small) recursive+ -- function.++ lc_lvl_env :: IdEnv LibCaseLevel,+ -- Binds all non-top-level in-scope Ids (top-level and+ -- imported things have a level of zero)++ lc_rec_env :: IdEnv CoreBind,+ -- Binds *only* recursively defined ids, to their own+ -- binding group, and *only* in their own RHSs++ lc_scruts :: [(Id, LibCaseLevel, LibCaseLevel)]+ -- Each of these Ids was scrutinised by an enclosing+ -- case expression, at a level deeper than its binding+ -- level.+ --+ -- The first LibCaseLevel is the *binding level* of+ -- the scrutinised Id,+ -- The second is the level *at which it was scrutinised*.+ -- (see Note [Avoiding fruitless liberate-case])+ -- The former is a bit redundant, since you could always+ -- look it up in lc_lvl_env, but it's just cached here+ --+ -- The order is insignificant; it's a bag really+ --+ -- There's one element per scrutinisation;+ -- in principle the same Id may appear multiple times,+ -- although that'd be unusual:+ -- case x of { (a,b) -> ....(case x of ...) .. }+ }++initEnv :: DynFlags -> LibCaseEnv+initEnv dflags+ = LibCaseEnv { lc_dflags = dflags,+ lc_lvl = 0,+ lc_lvl_env = emptyVarEnv,+ lc_rec_env = emptyVarEnv,+ lc_scruts = [] }++-- Bomb-out size for deciding if+-- potential liberatees are too big.+-- (passed in from cmd-line args)+bombOutSize :: LibCaseEnv -> Maybe Int+bombOutSize = liberateCaseThreshold . lc_dflags
+ simplCore/OccurAnal.hs view
@@ -0,0 +1,2772 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++************************************************************************+* *+\section[OccurAnal]{Occurrence analysis pass}+* *+************************************************************************++The occurrence analyser re-typechecks a core expression, returning a new+core expression with (hopefully) improved usage information.+-}++{-# LANGUAGE CPP, BangPatterns, MultiWayIf #-}++module OccurAnal (+ occurAnalysePgm, occurAnalyseExpr, occurAnalyseExpr_NoBinderSwap+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreFVs+import CoreUtils ( exprIsTrivial, isDefaultAlt, isExpandableApp,+ stripTicksTopE, mkTicks )+import Id+import IdInfo+import Name( localiseName )+import BasicTypes+import Module( Module )+import Coercion+import Type++import VarSet+import VarEnv+import Var+import Demand ( argOneShots, argsOneShots )+import Digraph ( SCC(..), Node+ , stronglyConnCompFromEdgedVerticesUniq+ , stronglyConnCompFromEdgedVerticesUniqR )+import Unique+import UniqFM+import UniqSet+import Util+import Outputable+import Data.List+import Control.Arrow ( second )++{-+************************************************************************+* *+ occurAnalysePgm, occurAnalyseExpr, occurAnalyseExpr_NoBinderSwap+* *+************************************************************************++Here's the externally-callable interface:+-}++occurAnalysePgm :: Module -- Used only in debug output+ -> (Activation -> Bool)+ -> [CoreRule] -> [CoreVect] -> VarSet+ -> CoreProgram -> CoreProgram+occurAnalysePgm this_mod active_rule imp_rules vects vectVars binds+ | isEmptyDetails final_usage+ = occ_anald_binds++ | otherwise -- See Note [Glomming]+ = WARN( True, hang (text "Glomming in" <+> ppr this_mod <> colon)+ 2 (ppr final_usage ) )+ occ_anald_glommed_binds+ where+ init_env = initOccEnv active_rule+ (final_usage, occ_anald_binds) = go init_env binds+ (_, occ_anald_glommed_binds) = occAnalRecBind init_env TopLevel+ imp_rule_edges+ (flattenBinds occ_anald_binds)+ initial_uds+ -- It's crucial to re-analyse the glommed-together bindings+ -- so that we establish the right loop breakers. Otherwise+ -- we can easily create an infinite loop (Trac #9583 is an example)++ initial_uds = addManyOccsSet emptyDetails+ (rulesFreeVars imp_rules `unionVarSet`+ vectsFreeVars vects `unionVarSet`+ vectVars)+ -- The RULES and VECTORISE declarations keep things alive! (For VECTORISE declarations,+ -- we only get them *until* the vectoriser runs. Afterwards, these dependencies are+ -- reflected in 'vectors' — see Note [Vectorisation declarations and occurrences].)++ -- Note [Preventing loops due to imported functions rules]+ imp_rule_edges = foldr (plusVarEnv_C unionVarSet) emptyVarEnv+ [ mapVarEnv (const maps_to) $+ getUniqSet (exprFreeIds arg `delVarSetList` ru_bndrs imp_rule)+ | imp_rule <- imp_rules+ , not (isBuiltinRule imp_rule) -- See Note [Plugin rules]+ , let maps_to = exprFreeIds (ru_rhs imp_rule)+ `delVarSetList` ru_bndrs imp_rule+ , arg <- ru_args imp_rule ]++ go :: OccEnv -> [CoreBind] -> (UsageDetails, [CoreBind])+ go _ []+ = (initial_uds, [])+ go env (bind:binds)+ = (final_usage, bind' ++ binds')+ where+ (bs_usage, binds') = go env binds+ (final_usage, bind') = occAnalBind env TopLevel imp_rule_edges bind+ bs_usage++occurAnalyseExpr :: CoreExpr -> CoreExpr+ -- Do occurrence analysis, and discard occurrence info returned+occurAnalyseExpr = occurAnalyseExpr' True -- do binder swap++occurAnalyseExpr_NoBinderSwap :: CoreExpr -> CoreExpr+occurAnalyseExpr_NoBinderSwap = occurAnalyseExpr' False -- do not do binder swap++occurAnalyseExpr' :: Bool -> CoreExpr -> CoreExpr+occurAnalyseExpr' enable_binder_swap expr+ = snd (occAnal env expr)+ where+ env = (initOccEnv all_active_rules) {occ_binder_swap = enable_binder_swap}+ -- To be conservative, we say that all inlines and rules are active+ all_active_rules = \_ -> True++{- Note [Plugin rules]+~~~~~~~~~~~~~~~~~~~~~~+Conal Elliott (Trac #11651) built a GHC plugin that added some+BuiltinRules (for imported Ids) to the mg_rules field of ModGuts, to+do some domain-specific transformations that could not be expressed+with an ordinary pattern-matching CoreRule. But then we can't extract+the dependencies (in imp_rule_edges) from ru_rhs etc, because a+BuiltinRule doesn't have any of that stuff.++So we simply assume that BuiltinRules have no dependencies, and filter+them out from the imp_rule_edges comprehension.+-}++{-+************************************************************************+* *+ Bindings+* *+************************************************************************++Note [Recursive bindings: the grand plan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we come across a binding group+ Rec { x1 = r1; ...; xn = rn }+we treat it like this (occAnalRecBind):++1. Occurrence-analyse each right hand side, and build a+ "Details" for each binding to capture the results.++ Wrap the details in a Node (details, node-id, dep-node-ids),+ where node-id is just the unique of the binder, and+ dep-node-ids lists all binders on which this binding depends.+ We'll call these the "scope edges".+ See Note [Forming the Rec groups].++ All this is done by makeNode.++2. Do SCC-analysis on these Nodes. Each SCC will become a new Rec or+ NonRec. The key property is that every free variable of a binding+ is accounted for by the scope edges, so that when we are done+ everything is still in scope.++3. For each Cyclic SCC of the scope-edge SCC-analysis in (2), we+ identify suitable loop-breakers to ensure that inlining terminates.+ This is done by occAnalRec.++4. To do so we form a new set of Nodes, with the same details, but+ different edges, the "loop-breaker nodes". The loop-breaker nodes+ have both more and fewer depedencies than the scope edges+ (see Note [Choosing loop breakers])++ More edges: if f calls g, and g has an active rule that mentions h+ then we add an edge from f -> h++ Fewer edges: we only include dependencies on active rules, on rule+ RHSs (not LHSs) and if there is an INLINE pragma only+ on the stable unfolding (and vice versa). The scope+ edges must be much more inclusive.++5. The "weak fvs" of a node are, by definition:+ the scope fvs - the loop-breaker fvs+ See Note [Weak loop breakers], and the nd_weak field of Details++6. Having formed the loop-breaker nodes++Note [Dead code]+~~~~~~~~~~~~~~~~+Dropping dead code for a cyclic Strongly Connected Component is done+in a very simple way:++ the entire SCC is dropped if none of its binders are mentioned+ in the body; otherwise the whole thing is kept.++The key observation is that dead code elimination happens after+dependency analysis: so 'occAnalBind' processes SCCs instead of the+original term's binding groups.++Thus 'occAnalBind' does indeed drop 'f' in an example like++ letrec f = ...g...+ g = ...(...g...)...+ in+ ...g...++when 'g' no longer uses 'f' at all (eg 'f' does not occur in a RULE in+'g'). 'occAnalBind' first consumes 'CyclicSCC g' and then it consumes+'AcyclicSCC f', where 'body_usage' won't contain 'f'.++------------------------------------------------------------+Note [Forming Rec groups]+~~~~~~~~~~~~~~~~~~~~~~~~~+We put bindings {f = ef; g = eg } in a Rec group if "f uses g"+and "g uses f", no matter how indirectly. We do a SCC analysis+with an edge f -> g if "f uses g".++More precisely, "f uses g" iff g should be in scope wherever f is.+That is, g is free in:+ a) the rhs 'ef'+ b) or the RHS of a rule for f (Note [Rules are extra RHSs])+ c) or the LHS or a rule for f (Note [Rule dependency info])++These conditions apply regardless of the activation of the RULE (eg it might be+inactive in this phase but become active later). Once a Rec is broken up+it can never be put back together, so we must be conservative.++The principle is that, regardless of rule firings, every variable is+always in scope.++ * Note [Rules are extra RHSs]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~+ A RULE for 'f' is like an extra RHS for 'f'. That way the "parent"+ keeps the specialised "children" alive. If the parent dies+ (because it isn't referenced any more), then the children will die+ too (unless they are already referenced directly).++ To that end, we build a Rec group for each cyclic strongly+ connected component,+ *treating f's rules as extra RHSs for 'f'*.+ More concretely, the SCC analysis runs on a graph with an edge+ from f -> g iff g is mentioned in+ (a) f's rhs+ (b) f's RULES+ These are rec_edges.++ Under (b) we include variables free in *either* LHS *or* RHS of+ the rule. The former might seems silly, but see Note [Rule+ dependency info]. So in Example [eftInt], eftInt and eftIntFB+ will be put in the same Rec, even though their 'main' RHSs are+ both non-recursive.++ * Note [Rule dependency info]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~+ The VarSet in a RuleInfo is used for dependency analysis in the+ occurrence analyser. We must track free vars in *both* lhs and rhs.+ Hence use of idRuleVars, rather than idRuleRhsVars in occAnalBind.+ Why both? Consider+ x = y+ RULE f x = v+4+ Then if we substitute y for x, we'd better do so in the+ rule's LHS too, so we'd better ensure the RULE appears to mention 'x'+ as well as 'v'++ * Note [Rules are visible in their own rec group]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ We want the rules for 'f' to be visible in f's right-hand side.+ And we'd like them to be visible in other functions in f's Rec+ group. E.g. in Note [Specialisation rules] we want f' rule+ to be visible in both f's RHS, and fs's RHS.++ This means that we must simplify the RULEs first, before looking+ at any of the definitions. This is done by Simplify.simplRecBind,+ when it calls addLetIdInfo.++------------------------------------------------------------+Note [Choosing loop breakers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Loop breaking is surprisingly subtle. First read the section 4 of+"Secrets of the GHC inliner". This describes our basic plan.+We avoid infinite inlinings by choosing loop breakers, and+ensuring that a loop breaker cuts each loop.++See also Note [Inlining and hs-boot files] in ToIface, which deals+with a closely related source of infinite loops.++Fundamentally, we do SCC analysis on a graph. For each recursive+group we choose a loop breaker, delete all edges to that node,+re-analyse the SCC, and iterate.++But what is the graph? NOT the same graph as was used for Note+[Forming Rec groups]! In particular, a RULE is like an equation for+'f' that is *always* inlined if it is applicable. We do *not* disable+rules for loop-breakers. It's up to whoever makes the rules to make+sure that the rules themselves always terminate. See Note [Rules for+recursive functions] in Simplify.hs++Hence, if+ f's RHS (or its INLINE template if it has one) mentions g, and+ g has a RULE that mentions h, and+ h has a RULE that mentions f++then we *must* choose f to be a loop breaker. Example: see Note+[Specialisation rules].++In general, take the free variables of f's RHS, and augment it with+all the variables reachable by RULES from those starting points. That+is the whole reason for computing rule_fv_env in occAnalBind. (Of+course we only consider free vars that are also binders in this Rec+group.) See also Note [Finding rule RHS free vars]++Note that when we compute this rule_fv_env, we only consider variables+free in the *RHS* of the rule, in contrast to the way we build the+Rec group in the first place (Note [Rule dependency info])++Note that if 'g' has RHS that mentions 'w', we should add w to+g's loop-breaker edges. More concretely there is an edge from f -> g+iff+ (a) g is mentioned in f's RHS `xor` f's INLINE rhs+ (see Note [Inline rules])+ (b) or h is mentioned in f's RHS, and+ g appears in the RHS of an active RULE of h+ or a transitive sequence of active rules starting with h++Why "active rules"? See Note [Finding rule RHS free vars]++Note that in Example [eftInt], *neither* eftInt *nor* eftIntFB is+chosen as a loop breaker, because their RHSs don't mention each other.+And indeed both can be inlined safely.++Note again that the edges of the graph we use for computing loop breakers+are not the same as the edges we use for computing the Rec blocks.+That's why we compute++- rec_edges for the Rec block analysis+- loop_breaker_nodes for the loop breaker analysis++ * Note [Finding rule RHS free vars]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ Consider this real example from Data Parallel Haskell+ tagZero :: Array Int -> Array Tag+ {-# INLINE [1] tagZeroes #-}+ tagZero xs = pmap (\x -> fromBool (x==0)) xs++ {-# RULES "tagZero" [~1] forall xs n.+ pmap fromBool <blah blah> = tagZero xs #-}+ So tagZero's RHS mentions pmap, and pmap's RULE mentions tagZero.+ However, tagZero can only be inlined in phase 1 and later, while+ the RULE is only active *before* phase 1. So there's no problem.++ To make this work, we look for the RHS free vars only for+ *active* rules. That's the reason for the occ_rule_act field+ of the OccEnv.++ * Note [Weak loop breakers]+ ~~~~~~~~~~~~~~~~~~~~~~~~~+ There is a last nasty wrinkle. Suppose we have++ Rec { f = f_rhs+ RULE f [] = g++ h = h_rhs+ g = h+ ...more...+ }++ Remember that we simplify the RULES before any RHS (see Note+ [Rules are visible in their own rec group] above).++ So we must *not* postInlineUnconditionally 'g', even though+ its RHS turns out to be trivial. (I'm assuming that 'g' is+ not choosen as a loop breaker.) Why not? Because then we+ drop the binding for 'g', which leaves it out of scope in the+ RULE!++ Here's a somewhat different example of the same thing+ Rec { g = h+ ; h = ...f...+ ; f = f_rhs+ RULE f [] = g }+ Here the RULE is "below" g, but we *still* can't postInlineUnconditionally+ g, because the RULE for f is active throughout. So the RHS of h+ might rewrite to h = ...g...+ So g must remain in scope in the output program!++ We "solve" this by:++ Make g a "weak" loop breaker (OccInfo = IAmLoopBreaker True)+ iff g is a "missing free variable" of the Rec group++ A "missing free variable" x is one that is mentioned in an RHS or+ INLINE or RULE of a binding in the Rec group, but where the+ dependency on x may not show up in the loop_breaker_nodes (see+ note [Choosing loop breakers} above).++ A normal "strong" loop breaker has IAmLoopBreaker False. So++ Inline postInlineUnconditionally+ strong IAmLoopBreaker False no no+ weak IAmLoopBreaker True yes no+ other yes yes++ The **sole** reason for this kind of loop breaker is so that+ postInlineUnconditionally does not fire. Ugh. (Typically it'll+ inline via the usual callSiteInline stuff, so it'll be dead in the+ next pass, so the main Ugh is the tiresome complication.)++Note [Rules for imported functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ f = /\a. B.g a+ RULE B.g Int = 1 + f Int+Note that+ * The RULE is for an imported function.+ * f is non-recursive+Now we+can get+ f Int --> B.g Int Inlining f+ --> 1 + f Int Firing RULE+and so the simplifier goes into an infinite loop. This+would not happen if the RULE was for a local function,+because we keep track of dependencies through rules. But+that is pretty much impossible to do for imported Ids. Suppose+f's definition had been+ f = /\a. C.h a+where (by some long and devious process), C.h eventually inlines to+B.g. We could only spot such loops by exhaustively following+unfoldings of C.h etc, in case we reach B.g, and hence (via the RULE)+f.++Note that RULES for imported functions are important in practice; they+occur a lot in the libraries.++We regard this potential infinite loop as a *programmer* error.+It's up the programmer not to write silly rules like+ RULE f x = f x+and the example above is just a more complicated version.++Note [Preventing loops due to imported functions rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider:+ import GHC.Base (foldr)++ {-# RULES "filterList" forall p. foldr (filterFB (:) p) [] = filter p #-}+ filter p xs = build (\c n -> foldr (filterFB c p) n xs)+ filterFB c p = ...++ f = filter p xs++Note that filter is not a loop-breaker, so what happens is:+ f = filter p xs+ = {inline} build (\c n -> foldr (filterFB c p) n xs)+ = {inline} foldr (filterFB (:) p) [] xs+ = {RULE} filter p xs++We are in an infinite loop.++A more elaborate example (that I actually saw in practice when I went to+mark GHC.List.filter as INLINABLE) is as follows. Say I have this module:+ {-# LANGUAGE RankNTypes #-}+ module GHCList where++ import Prelude hiding (filter)+ import GHC.Base (build)++ {-# INLINABLE filter #-}+ filter :: (a -> Bool) -> [a] -> [a]+ filter p [] = []+ filter p (x:xs) = if p x then x : filter p xs else filter p xs++ {-# NOINLINE [0] filterFB #-}+ filterFB :: (a -> b -> b) -> (a -> Bool) -> a -> b -> b+ filterFB c p x r | p x = x `c` r+ | otherwise = r++ {-# RULES+ "filter" [~1] forall p xs. filter p xs = build (\c n -> foldr+ (filterFB c p) n xs)+ "filterList" [1] forall p. foldr (filterFB (:) p) [] = filter p+ #-}++Then (because RULES are applied inside INLINABLE unfoldings, but inlinings+are not), the unfolding given to "filter" in the interface file will be:+ filter p [] = []+ filter p (x:xs) = if p x then x : build (\c n -> foldr (filterFB c p) n xs)+ else build (\c n -> foldr (filterFB c p) n xs++Note that because this unfolding does not mention "filter", filter is not+marked as a strong loop breaker. Therefore at a use site in another module:+ filter p xs+ = {inline}+ case xs of [] -> []+ (x:xs) -> if p x then x : build (\c n -> foldr (filterFB c p) n xs)+ else build (\c n -> foldr (filterFB c p) n xs)++ build (\c n -> foldr (filterFB c p) n xs)+ = {inline} foldr (filterFB (:) p) [] xs+ = {RULE} filter p xs++And we are in an infinite loop again, except that this time the loop is producing an+infinitely large *term* (an unrolling of filter) and so the simplifier finally+dies with "ticks exhausted"++Because of this problem, we make a small change in the occurrence analyser+designed to mark functions like "filter" as strong loop breakers on the basis that:+ 1. The RHS of filter mentions the local function "filterFB"+ 2. We have a rule which mentions "filterFB" on the LHS and "filter" on the RHS++So for each RULE for an *imported* function we are going to add+dependency edges between the *local* FVS of the rule LHS and the+*local* FVS of the rule RHS. We don't do anything special for RULES on+local functions because the standard occurrence analysis stuff is+pretty good at getting loop-breakerness correct there.++It is important to note that even with this extra hack we aren't always going to get+things right. For example, it might be that the rule LHS mentions an imported Id,+and another module has a RULE that can rewrite that imported Id to one of our local+Ids.++Note [Specialising imported functions] (referred to from Specialise)+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+BUT for *automatically-generated* rules, the programmer can't be+responsible for the "programmer error" in Note [Rules for imported+functions]. In paricular, consider specialising a recursive function+defined in another module. If we specialise a recursive function B.g,+we get+ g_spec = .....(B.g Int).....+ RULE B.g Int = g_spec+Here, g_spec doesn't look recursive, but when the rule fires, it+becomes so. And if B.g was mutually recursive, the loop might+not be as obvious as it is here.++To avoid this,+ * When specialising a function that is a loop breaker,+ give a NOINLINE pragma to the specialised function++Note [Glomming]+~~~~~~~~~~~~~~~+RULES for imported Ids can make something at the top refer to something at the bottom:+ f = \x -> B.g (q x)+ h = \y -> 3++ RULE: B.g (q x) = h x++Applying this rule makes f refer to h, although f doesn't appear to+depend on h. (And, as in Note [Rules for imported functions], the+dependency might be more indirect. For example, f might mention C.t+rather than B.g, where C.t eventually inlines to B.g.)++NOTICE that this cannot happen for rules whose head is a+locally-defined function, because we accurately track dependencies+through RULES. It only happens for rules whose head is an imported+function (B.g in the example above).++Solution:+ - When simplifying, bring all top level identifiers into+ scope at the start, ignoring the Rec/NonRec structure, so+ that when 'h' pops up in f's rhs, we find it in the in-scope set+ (as the simplifier generally expects). This happens in simplTopBinds.++ - In the occurrence analyser, if there are any out-of-scope+ occurrences that pop out of the top, which will happen after+ firing the rule: f = \x -> h x+ h = \y -> 3+ then just glom all the bindings into a single Rec, so that+ the *next* iteration of the occurrence analyser will sort+ them all out. This part happens in occurAnalysePgm.++------------------------------------------------------------+Note [Inline rules]+~~~~~~~~~~~~~~~~~~~+None of the above stuff about RULES applies to Inline Rules,+stored in a CoreUnfolding. The unfolding, if any, is simplified+at the same time as the regular RHS of the function (ie *not* like+Note [Rules are visible in their own rec group]), so it should be+treated *exactly* like an extra RHS.++Or, rather, when computing loop-breaker edges,+ * If f has an INLINE pragma, and it is active, we treat the+ INLINE rhs as f's rhs+ * If it's inactive, we treat f as having no rhs+ * If it has no INLINE pragma, we look at f's actual rhs+++There is a danger that we'll be sub-optimal if we see this+ f = ...f...+ [INLINE f = ..no f...]+where f is recursive, but the INLINE is not. This can just about+happen with a sufficiently odd set of rules; eg++ foo :: Int -> Int+ {-# INLINE [1] foo #-}+ foo x = x+1++ bar :: Int -> Int+ {-# INLINE [1] bar #-}+ bar x = foo x + 1++ {-# RULES "foo" [~1] forall x. foo x = bar x #-}++Here the RULE makes bar recursive; but it's INLINE pragma remains+non-recursive. It's tempting to then say that 'bar' should not be+a loop breaker, but an attempt to do so goes wrong in two ways:+ a) We may get+ $df = ...$cfoo...+ $cfoo = ...$df....+ [INLINE $cfoo = ...no-$df...]+ But we want $cfoo to depend on $df explicitly so that we+ put the bindings in the right order to inline $df in $cfoo+ and perhaps break the loop altogether. (Maybe this+ b)+++Example [eftInt]+~~~~~~~~~~~~~~~+Example (from GHC.Enum):++ eftInt :: Int# -> Int# -> [Int]+ eftInt x y = ...(non-recursive)...++ {-# INLINE [0] eftIntFB #-}+ eftIntFB :: (Int -> r -> r) -> r -> Int# -> Int# -> r+ eftIntFB c n x y = ...(non-recursive)...++ {-# RULES+ "eftInt" [~1] forall x y. eftInt x y = build (\ c n -> eftIntFB c n x y)+ "eftIntList" [1] eftIntFB (:) [] = eftInt+ #-}++Note [Specialisation rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this group, which is typical of what SpecConstr builds:++ fs a = ....f (C a)....+ f x = ....f (C a)....+ {-# RULE f (C a) = fs a #-}++So 'f' and 'fs' are in the same Rec group (since f refers to fs via its RULE).++But watch out! If 'fs' is not chosen as a loop breaker, we may get an infinite loop:+ - the RULE is applied in f's RHS (see Note [Self-recursive rules] in Simplify+ - fs is inlined (say it's small)+ - now there's another opportunity to apply the RULE++This showed up when compiling Control.Concurrent.Chan.getChanContents.++------------------------------------------------------------+Note [Finding join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~+It's the occurrence analyser's job to find bindings that we can turn into join+points, but it doesn't perform that transformation right away. Rather, it marks+the eligible bindings as part of their occurrence data, leaving it to the+simplifier (or to simpleOptPgm) to actually change the binder's 'IdDetails'.+The simplifier then eta-expands the RHS if needed and then updates the+occurrence sites. Dividing the work this way means that the occurrence analyser+still only takes one pass, yet one can always tell the difference between a+function call and a jump by looking at the occurrence (because the same pass+changes the 'IdDetails' and propagates the binders to their occurrence sites).++To track potential join points, we use the 'occ_tail' field of OccInfo. A value+of `AlwaysTailCalled n` indicates that every occurrence of the variable is a+tail call with `n` arguments (counting both value and type arguments). Otherwise+'occ_tail' will be 'NoTailCallInfo'. The tail call info flows bottom-up with the+rest of 'OccInfo' until it goes on the binder.++Note [Rules and join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Things get fiddly with rules. Suppose we have:++ let j :: Int -> Int+ j y = 2 * y+ k :: Int -> Int -> Int+ {-# RULES "SPEC k 0" k 0 = j #-}+ k x y = x + 2 * y+ in ...++Now suppose that both j and k appear only as saturated tail calls in the body.+Thus we would like to make them both join points. The rule complicates matters,+though, as its RHS has an unapplied occurrence of j. *However*, if we were to+eta-expand the rule, all would be well:++ {-# RULES "SPEC k 0" forall a. k 0 a = j a #-}++So conceivably we could notice that a potential join point would have an+"undersaturated" rule and account for it. This would mean we could make+something that's been specialised a join point, for instance. But local bindings+are rarely specialised, and being overly cautious about rules only+costs us anything when, for some `j`:++ * Before specialisation, `j` has non-tail calls, so it can't be a join point.+ * During specialisation, `j` gets specialised and thus acquires rules.+ * Sometime afterward, the non-tail calls to `j` disappear (as dead code, say),+ and so now `j` *could* become a join point.++This appears to be very rare in practice. TODO Perhaps we should gather+statistics to be sure.++Note [Excess polymorphism and join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++In principle, if a function would be a join point except that it fails+the polymorphism rule (see Note [The polymorphism rule of join points] in+CoreSyn), it can still be made a join point with some effort. This is because+all tail calls must return the same type (they return to the same context!), and+thus if the return type depends on an argument, that argument must always be the+same.++For instance, consider:++ let f :: forall a. a -> Char -> [a]+ f @a x c = ... f @a x 'a' ...+ in ... f @Int 1 'b' ... f @Int 2 'c' ...++(where the calls are tail calls). `f` fails the polymorphism rule because its+return type is [a], where [a] is bound. But since the type argument is always+'Int', we can rewrite it as:++ let f' :: Int -> Char -> [Int]+ f' x c = ... f' x 'a' ...+ in ... f' 1 'b' ... f 2 'c' ...++and now we can make f' a join point:++ join f' :: Int -> Char -> [Int]+ f' x c = ... jump f' x 'a' ...+ in ... jump f' 1 'b' ... jump f' 2 'c' ...++It's not clear that this comes up often, however. TODO: Measure how often and+add this analysis if necessary.++------------------------------------------------------------+Note [Adjusting for lambdas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There's a bit of a dance we need to do after analysing a lambda expression or+a right-hand side. In particular, we need to++ a) call 'markAllInsideLam' *unless* the binding is for a thunk, a one-shot+ lambda, or a non-recursive join point; and+ b) call 'markAllNonTailCalled' *unless* the binding is for a join point.++Some examples, with how the free occurrences in e (assumed not to be a value+lambda) get marked:++ inside lam non-tail-called+ ------------------------------------------------------------+ let x = e No Yes+ let f = \x -> e Yes Yes+ let f = \x{OneShot} -> e No Yes+ \x -> e Yes Yes+ join j x = e No No+ joinrec j x = e Yes No++There are a few other caveats; most importantly, if we're marking a binding as+'AlwaysTailCalled', it's *going* to be a join point, so we treat it as one so+that the effect cascades properly. Consequently, at the time the RHS is+analysed, we won't know what adjustments to make; thus 'occAnalLamOrRhs' must+return the unadjusted 'UsageDetails', to be adjusted by 'adjustRhsUsage' once+join-point-hood has been decided.++Thus the overall sequence taking place in 'occAnalNonRecBind' and+'occAnalRecBind' is as follows:++ 1. Call 'occAnalLamOrRhs' to find usage information for the RHS.+ 2. Call 'tagNonRecBinder' or 'tagRecBinders', which decides whether to make+ the binding a join point.+ 3. Call 'adjustRhsUsage' accordingly. (Done as part of 'tagRecBinders' when+ recursive.)++(In the recursive case, this logic is spread between 'makeNode' and+'occAnalRec'.)+-}++------------------------------------------------------------------+-- occAnalBind+------------------------------------------------------------------++occAnalBind :: OccEnv -- The incoming OccEnv+ -> TopLevelFlag+ -> ImpRuleEdges+ -> CoreBind+ -> UsageDetails -- Usage details of scope+ -> (UsageDetails, -- Of the whole let(rec)+ [CoreBind])++occAnalBind env lvl top_env (NonRec binder rhs) body_usage+ = occAnalNonRecBind env lvl top_env binder rhs body_usage+occAnalBind env lvl top_env (Rec pairs) body_usage+ = occAnalRecBind env lvl top_env pairs body_usage++-----------------+occAnalNonRecBind :: OccEnv -> TopLevelFlag -> ImpRuleEdges -> Var -> CoreExpr+ -> UsageDetails -> (UsageDetails, [CoreBind])+occAnalNonRecBind env lvl imp_rule_edges binder rhs body_usage+ | isTyVar binder -- A type let; we don't gather usage info+ = (body_usage, [NonRec binder rhs])++ | not (binder `usedIn` body_usage) -- It's not mentioned+ = (body_usage, [])++ | otherwise -- It's mentioned in the body+ = (body_usage' +++ rhs_usage', [NonRec tagged_binder rhs'])+ where+ (body_usage', tagged_binder) = tagNonRecBinder lvl body_usage binder+ mb_join_arity = willBeJoinId_maybe tagged_binder++ (bndrs, body) = collectBinders rhs++ (rhs_usage1, bndrs', body') = occAnalNonRecRhs env tagged_binder bndrs body+ rhs' = mkLams (markJoinOneShots mb_join_arity bndrs') body'+ -- For a /non-recursive/ join point we can mark all+ -- its join-lambda as one-shot; and it's a good idea to do so++ -- Unfoldings+ -- See Note [Unfoldings and join points]+ rhs_usage2 = case occAnalUnfolding env NonRecursive binder of+ Just unf_usage -> rhs_usage1 +++ unf_usage+ Nothing -> rhs_usage1++ -- Rules+ -- See Note [Rules are extra RHSs] and Note [Rule dependency info]+ rules_w_uds = occAnalRules env mb_join_arity NonRecursive tagged_binder+ rhs_usage3 = rhs_usage2 +++ combineUsageDetailsList+ (map (\(_, l, r) -> l +++ r) rules_w_uds)+ rhs_usage4 = maybe rhs_usage3 (addManyOccsSet rhs_usage3) $+ lookupVarEnv imp_rule_edges binder+ -- See Note [Preventing loops due to imported functions rules]++ -- Final adjustment+ rhs_usage' = adjustRhsUsage mb_join_arity NonRecursive bndrs' rhs_usage4++-----------------+occAnalRecBind :: OccEnv -> TopLevelFlag -> ImpRuleEdges -> [(Var,CoreExpr)]+ -> UsageDetails -> (UsageDetails, [CoreBind])+occAnalRecBind env lvl imp_rule_edges pairs body_usage+ = foldr (occAnalRec lvl) (body_usage, []) sccs+ -- For a recursive group, we+ -- * occ-analyse all the RHSs+ -- * compute strongly-connected components+ -- * feed those components to occAnalRec+ -- See Note [Recursive bindings: the grand plan]+ where+ sccs :: [SCC Details]+ sccs = {-# SCC "occAnalBind.scc" #-}+ stronglyConnCompFromEdgedVerticesUniq nodes++ nodes :: [LetrecNode]+ nodes = {-# SCC "occAnalBind.assoc" #-}+ map (makeNode env imp_rule_edges bndr_set) pairs++ bndr_set = mkVarSet (map fst pairs)++{-+Note [Unfoldings and join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We assume that anything in an unfolding occurs multiple times, since unfoldings+are often copied (that's the whole point!). But we still need to track tail+calls for the purpose of finding join points.+-}++-----------------------------+occAnalRec :: TopLevelFlag+ -> SCC Details+ -> (UsageDetails, [CoreBind])+ -> (UsageDetails, [CoreBind])++ -- The NonRec case is just like a Let (NonRec ...) above+occAnalRec lvl (AcyclicSCC (ND { nd_bndr = bndr, nd_rhs = rhs+ , nd_uds = rhs_uds, nd_rhs_bndrs = rhs_bndrs }))+ (body_uds, binds)+ | not (bndr `usedIn` body_uds)+ = (body_uds, binds) -- See Note [Dead code]++ | otherwise -- It's mentioned in the body+ = (body_uds' +++ rhs_uds',+ NonRec tagged_bndr rhs : binds)+ where+ (body_uds', tagged_bndr) = tagNonRecBinder lvl body_uds bndr+ rhs_uds' = adjustRhsUsage (willBeJoinId_maybe tagged_bndr) NonRecursive+ rhs_bndrs rhs_uds++ -- The Rec case is the interesting one+ -- See Note [Recursive bindings: the grand plan]+ -- See Note [Loop breaking]+occAnalRec lvl (CyclicSCC details_s) (body_uds, binds)+ | not (any (`usedIn` body_uds) bndrs) -- NB: look at body_uds, not total_uds+ = (body_uds, binds) -- See Note [Dead code]++ | otherwise -- At this point we always build a single Rec+ = -- pprTrace "occAnalRec" (vcat+ -- [ text "weak_fvs" <+> ppr weak_fvs+ -- , text "tagged details" <+> ppr tagged_details_s+ -- , text "lb nodes" <+> ppr loop_breaker_nodes])+ (final_uds, Rec pairs : binds)++ where+ bndrs = map nd_bndr details_s+ bndr_set = mkVarSet bndrs++ ------------------------------+ -- See Note [Choosing loop breakers] for loop_breaker_nodes+ final_uds :: UsageDetails+ loop_breaker_nodes :: [LetrecNode]+ (final_uds, loop_breaker_nodes)+ = mkLoopBreakerNodes lvl bndr_set body_uds details_s++ ------------------------------+ weak_fvs :: VarSet+ weak_fvs = mapUnionVarSet nd_weak details_s++ ---------------------------+ -- Now reconstruct the cycle+ pairs :: [(Id,CoreExpr)]+ pairs | isEmptyVarSet weak_fvs = reOrderNodes 0 bndr_set weak_fvs loop_breaker_nodes []+ | otherwise = loopBreakNodes 0 bndr_set weak_fvs loop_breaker_nodes []+ -- If weak_fvs is empty, the loop_breaker_nodes will include+ -- all the edges in the original scope edges [remember,+ -- weak_fvs is the difference between scope edges and+ -- lb-edges], so a fresh SCC computation would yield a+ -- single CyclicSCC result; and reOrderNodes deals with+ -- exactly that case+++------------------------------------------------------------------+-- Loop breaking+------------------------------------------------------------------++type Binding = (Id,CoreExpr)++loopBreakNodes :: Int+ -> VarSet -- All binders+ -> VarSet -- Binders whose dependencies may be "missing"+ -- See Note [Weak loop breakers]+ -> [LetrecNode]+ -> [Binding] -- Append these to the end+ -> [Binding]+{-+loopBreakNodes is applied to the list of nodes for a cyclic strongly+connected component (there's guaranteed to be a cycle). It returns+the same nodes, but+ a) in a better order,+ b) with some of the Ids having a IAmALoopBreaker pragma++The "loop-breaker" Ids are sufficient to break all cycles in the SCC. This means+that the simplifier can guarantee not to loop provided it never records an inlining+for these no-inline guys.++Furthermore, the order of the binds is such that if we neglect dependencies+on the no-inline Ids then the binds are topologically sorted. This means+that the simplifier will generally do a good job if it works from top bottom,+recording inlinings for any Ids which aren't marked as "no-inline" as it goes.+-}++-- Return the bindings sorted into a plausible order, and marked with loop breakers.+loopBreakNodes depth bndr_set weak_fvs nodes binds+ = go (stronglyConnCompFromEdgedVerticesUniqR nodes) binds+ where+ go [] binds = binds+ go (scc:sccs) binds = loop_break_scc scc (go sccs binds)++ loop_break_scc scc binds+ = case scc of+ AcyclicSCC node -> mk_non_loop_breaker weak_fvs node : binds+ CyclicSCC nodes -> reOrderNodes depth bndr_set weak_fvs nodes binds++----------------------------------+reOrderNodes :: Int -> VarSet -> VarSet -> [LetrecNode] -> [Binding] -> [Binding]+ -- Choose a loop breaker, mark it no-inline,+ -- and call loopBreakNodes on the rest+reOrderNodes _ _ _ [] _ = panic "reOrderNodes"+reOrderNodes _ _ _ [node] binds = mk_loop_breaker node : binds+reOrderNodes depth bndr_set weak_fvs (node : nodes) binds+ = -- pprTrace "reOrderNodes" (text "unchosen" <+> ppr unchosen $$+ -- text "chosen" <+> ppr chosen_nodes) $+ loopBreakNodes new_depth bndr_set weak_fvs unchosen $+ (map mk_loop_breaker chosen_nodes ++ binds)+ where+ (chosen_nodes, unchosen) = chooseLoopBreaker approximate_lb+ (nd_score (fstOf3 node))+ [node] [] nodes++ approximate_lb = depth >= 2+ new_depth | approximate_lb = 0+ | otherwise = depth+1+ -- After two iterations (d=0, d=1) give up+ -- and approximate, returning to d=0++mk_loop_breaker :: LetrecNode -> Binding+mk_loop_breaker (ND { nd_bndr = bndr, nd_rhs = rhs}, _, _)+ = (bndr `setIdOccInfo` strongLoopBreaker { occ_tail = tail_info }, rhs)+ where+ tail_info = tailCallInfo (idOccInfo bndr)++mk_non_loop_breaker :: VarSet -> LetrecNode -> Binding+-- See Note [Weak loop breakers]+mk_non_loop_breaker weak_fvs (ND { nd_bndr = bndr, nd_rhs = rhs}, _, _)+ | bndr `elemVarSet` weak_fvs = (setIdOccInfo bndr occ', rhs)+ | otherwise = (bndr, rhs)+ where+ occ' = weakLoopBreaker { occ_tail = tail_info }+ tail_info = tailCallInfo (idOccInfo bndr)++----------------------------------+chooseLoopBreaker :: Bool -- True <=> Too many iterations,+ -- so approximate+ -> NodeScore -- Best score so far+ -> [LetrecNode] -- Nodes with this score+ -> [LetrecNode] -- Nodes with higher scores+ -> [LetrecNode] -- Unprocessed nodes+ -> ([LetrecNode], [LetrecNode])+ -- This loop looks for the bind with the lowest score+ -- to pick as the loop breaker. The rest accumulate in+chooseLoopBreaker _ _ loop_nodes acc []+ = (loop_nodes, acc) -- Done++ -- If approximate_loop_breaker is True, we pick *all*+ -- nodes with lowest score, else just one+ -- See Note [Complexity of loop breaking]+chooseLoopBreaker approx_lb loop_sc loop_nodes acc (node : nodes)+ | approx_lb+ , rank sc == rank loop_sc+ = chooseLoopBreaker approx_lb loop_sc (node : loop_nodes) acc nodes++ | sc `betterLB` loop_sc -- Better score so pick this new one+ = chooseLoopBreaker approx_lb sc [node] (loop_nodes ++ acc) nodes++ | otherwise -- Worse score so don't pick it+ = chooseLoopBreaker approx_lb loop_sc loop_nodes (node : acc) nodes+ where+ sc = nd_score (fstOf3 node)++{-+Note [Complexity of loop breaking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The loop-breaking algorithm knocks out one binder at a time, and+performs a new SCC analysis on the remaining binders. That can+behave very badly in tightly-coupled groups of bindings; in the+worst case it can be (N**2)*log N, because it does a full SCC+on N, then N-1, then N-2 and so on.++To avoid this, we switch plans after 2 (or whatever) attempts:+ Plan A: pick one binder with the lowest score, make it+ a loop breaker, and try again+ Plan B: pick *all* binders with the lowest score, make them+ all loop breakers, and try again+Since there are only a small finite number of scores, this will+terminate in a constant number of iterations, rather than O(N)+iterations.++You might thing that it's very unlikely, but RULES make it much+more likely. Here's a real example from Trac #1969:+ Rec { $dm = \d.\x. op d+ {-# RULES forall d. $dm Int d = $s$dm1+ forall d. $dm Bool d = $s$dm2 #-}++ dInt = MkD .... opInt ...+ dInt = MkD .... opBool ...+ opInt = $dm dInt+ opBool = $dm dBool++ $s$dm1 = \x. op dInt+ $s$dm2 = \x. op dBool }+The RULES stuff means that we can't choose $dm as a loop breaker+(Note [Choosing loop breakers]), so we must choose at least (say)+opInt *and* opBool, and so on. The number of loop breakders is+linear in the number of instance declarations.++Note [Loop breakers and INLINE/INLINABLE pragmas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Avoid choosing a function with an INLINE pramga as the loop breaker!+If such a function is mutually-recursive with a non-INLINE thing,+then the latter should be the loop-breaker.++It's vital to distinguish between INLINE and INLINABLE (the+Bool returned by hasStableCoreUnfolding_maybe). If we start with+ Rec { {-# INLINABLE f #-}+ f x = ...f... }+and then worker/wrapper it through strictness analysis, we'll get+ Rec { {-# INLINABLE $wf #-}+ $wf p q = let x = (p,q) in ...f...++ {-# INLINE f #-}+ f x = case x of (p,q) -> $wf p q }++Now it is vital that we choose $wf as the loop breaker, so we can+inline 'f' in '$wf'.++Note [DFuns should not be loop breakers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's particularly bad to make a DFun into a loop breaker. See+Note [How instance declarations are translated] in TcInstDcls++We give DFuns a higher score than ordinary CONLIKE things because+if there's a choice we want the DFun to be the non-loop breaker. Eg++rec { sc = /\ a \$dC. $fBWrap (T a) ($fCT @ a $dC)++ $fCT :: forall a_afE. (Roman.C a_afE) => Roman.C (Roman.T a_afE)+ {-# DFUN #-}+ $fCT = /\a \$dC. MkD (T a) ((sc @ a $dC) |> blah) ($ctoF @ a $dC)+ }++Here 'sc' (the superclass) looks CONLIKE, but we'll never get to it+if we can't unravel the DFun first.++Note [Constructor applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's really really important to inline dictionaries. Real+example (the Enum Ordering instance from GHC.Base):++ rec f = \ x -> case d of (p,q,r) -> p x+ g = \ x -> case d of (p,q,r) -> q x+ d = (v, f, g)++Here, f and g occur just once; but we can't inline them into d.+On the other hand we *could* simplify those case expressions if+we didn't stupidly choose d as the loop breaker.+But we won't because constructor args are marked "Many".+Inlining dictionaries is really essential to unravelling+the loops in static numeric dictionaries, see GHC.Float.++Note [Closure conversion]+~~~~~~~~~~~~~~~~~~~~~~~~~+We treat (\x. C p q) as a high-score candidate in the letrec scoring algorithm.+The immediate motivation came from the result of a closure-conversion transformation+which generated code like this:++ data Clo a b = forall c. Clo (c -> a -> b) c++ ($:) :: Clo a b -> a -> b+ Clo f env $: x = f env x++ rec { plus = Clo plus1 ()++ ; plus1 _ n = Clo plus2 n++ ; plus2 Zero n = n+ ; plus2 (Succ m) n = Succ (plus $: m $: n) }++If we inline 'plus' and 'plus1', everything unravels nicely. But if+we choose 'plus1' as the loop breaker (which is entirely possible+otherwise), the loop does not unravel nicely.+++@occAnalUnfolding@ deals with the question of bindings where the Id is marked+by an INLINE pragma. For these we record that anything which occurs+in its RHS occurs many times. This pessimistically assumes that this+inlined binder also occurs many times in its scope, but if it doesn't+we'll catch it next time round. At worst this costs an extra simplifier pass.+ToDo: try using the occurrence info for the inline'd binder.++[March 97] We do the same for atomic RHSs. Reason: see notes with loopBreakSCC.+[June 98, SLPJ] I've undone this change; I don't understand it. See notes with loopBreakSCC.+++************************************************************************+* *+ Making nodes+* *+************************************************************************+-}++type ImpRuleEdges = IdEnv IdSet -- Mapping from FVs of imported RULE LHSs to RHS FVs++noImpRuleEdges :: ImpRuleEdges+noImpRuleEdges = emptyVarEnv++type LetrecNode = Node Unique Details -- Node comes from Digraph+ -- The Unique key is gotten from the Id+data Details+ = ND { nd_bndr :: Id -- Binder+ , nd_rhs :: CoreExpr -- RHS, already occ-analysed+ , nd_rhs_bndrs :: [CoreBndr] -- Outer lambdas of RHS+ -- INVARIANT: (nd_rhs_bndrs nd, _) ==+ -- collectBinders (nd_rhs nd)++ , nd_uds :: UsageDetails -- Usage from RHS, and RULES, and stable unfoldings+ -- ignoring phase (ie assuming all are active)+ -- See Note [Forming Rec groups]++ , nd_inl :: IdSet -- Free variables of+ -- the stable unfolding (if present and active)+ -- or the RHS (if not)+ -- but excluding any RULES+ -- This is the IdSet that may be used if the Id is inlined++ , nd_weak :: IdSet -- Binders of this Rec that are mentioned in nd_uds+ -- but are *not* in nd_inl. These are the ones whose+ -- dependencies might not be respected by loop_breaker_nodes+ -- See Note [Weak loop breakers]++ , nd_active_rule_fvs :: IdSet -- Free variables of the RHS of active RULES++ , nd_score :: NodeScore+ }++instance Outputable Details where+ ppr nd = text "ND" <> braces+ (sep [ text "bndr =" <+> ppr (nd_bndr nd)+ , text "uds =" <+> ppr (nd_uds nd)+ , text "inl =" <+> ppr (nd_inl nd)+ , text "weak =" <+> ppr (nd_weak nd)+ , text "rule =" <+> ppr (nd_active_rule_fvs nd)+ ])++-- The NodeScore is compared lexicographically;+-- e.g. lower rank wins regardless of size+type NodeScore = ( Int -- Rank: lower => more likely to be picked as loop breaker+ , Int -- Size of rhs: higher => more likely to be picked as LB+ -- Maxes out at maxExprSize; we just use it to prioritise+ -- small functions+ , Bool ) -- Was it a loop breaker before?+ -- True => more likely to be picked+ -- Note [Loop breakers, node scoring, and stability]++rank :: NodeScore -> Int+rank (r, _, _) = r++makeNode :: OccEnv -> ImpRuleEdges -> VarSet+ -> (Var, CoreExpr) -> LetrecNode+-- See Note [Recursive bindings: the grand plan]+makeNode env imp_rule_edges bndr_set (bndr, rhs)+ = (details, varUnique bndr, nonDetKeysUniqSet node_fvs)+ -- It's OK to use nonDetKeysUniqSet here as stronglyConnCompFromEdgedVerticesR+ -- is still deterministic with edges in nondeterministic order as+ -- explained in Note [Deterministic SCC] in Digraph.+ where+ details = ND { nd_bndr = bndr+ , nd_rhs = rhs'+ , nd_rhs_bndrs = bndrs'+ , nd_uds = rhs_usage3+ , nd_inl = inl_fvs+ , nd_weak = node_fvs `minusVarSet` inl_fvs+ , nd_active_rule_fvs = active_rule_fvs+ , nd_score = pprPanic "makeNodeDetails" (ppr bndr) }++ -- Constructing the edges for the main Rec computation+ -- See Note [Forming Rec groups]+ (bndrs, body) = collectBinders rhs+ (rhs_usage1, bndrs', body') = occAnalRecRhs env bndrs body+ rhs' = mkLams bndrs' body'+ rhs_usage2 = rhs_usage1 +++ all_rule_uds+ -- Note [Rules are extra RHSs]+ -- Note [Rule dependency info]+ rhs_usage3 = case mb_unf_uds of+ Just unf_uds -> rhs_usage2 +++ unf_uds+ Nothing -> rhs_usage2+ node_fvs = udFreeVars bndr_set rhs_usage3++ -- Finding the free variables of the rules+ is_active = occ_rule_act env :: Activation -> Bool++ rules_w_uds :: [(CoreRule, UsageDetails, UsageDetails)]+ rules_w_uds = occAnalRules env (Just (length bndrs)) Recursive bndr++ rules_w_rhs_fvs :: [(Activation, VarSet)] -- Find the RHS fvs+ rules_w_rhs_fvs = maybe id (\ids -> ((AlwaysActive, ids):))+ (lookupVarEnv imp_rule_edges bndr)+ -- See Note [Preventing loops due to imported functions rules]+ [ (ru_act rule, udFreeVars bndr_set rhs_uds)+ | (rule, _, rhs_uds) <- rules_w_uds ]+ all_rule_uds = combineUsageDetailsList $+ concatMap (\(_, l, r) -> [l, r]) rules_w_uds+ active_rule_fvs = unionVarSets [fvs | (a,fvs) <- rules_w_rhs_fvs+ , is_active a]++ -- Finding the usage details of the INLINE pragma (if any)+ mb_unf_uds = occAnalUnfolding env Recursive bndr++ -- Find the "nd_inl" free vars; for the loop-breaker phase+ inl_fvs = case mb_unf_uds of+ Nothing -> udFreeVars bndr_set rhs_usage1 -- No INLINE, use RHS+ Just unf_uds -> udFreeVars bndr_set unf_uds+ -- We could check for an *active* INLINE (returning+ -- emptyVarSet for an inactive one), but is_active+ -- isn't the right thing (it tells about+ -- RULE activation), so we'd need more plumbing++mkLoopBreakerNodes :: TopLevelFlag+ -> VarSet+ -> UsageDetails -- for BODY of let+ -> [Details]+ -> (UsageDetails, -- adjusted+ [LetrecNode])+-- Does four things+-- a) tag each binder with its occurrence info+-- b) add a NodeScore to each node+-- c) make a Node with the right dependency edges for+-- the loop-breaker SCC analysis+-- d) adjust each RHS's usage details according to+-- the binder's (new) shotness and join-point-hood+mkLoopBreakerNodes lvl bndr_set body_uds details_s+ = (final_uds, zipWith mk_lb_node details_s bndrs')+ where+ (final_uds, bndrs') = tagRecBinders lvl body_uds+ [ (nd_bndr nd, nd_uds nd, nd_rhs_bndrs nd)+ | nd <- details_s ]+ mk_lb_node nd@(ND { nd_bndr = bndr, nd_rhs = rhs, nd_inl = inl_fvs }) bndr'+ = (nd', varUnique bndr, nonDetKeysUniqSet lb_deps)+ -- It's OK to use nonDetKeysUniqSet here as+ -- stronglyConnCompFromEdgedVerticesR is still deterministic with edges+ -- in nondeterministic order as explained in+ -- Note [Deterministic SCC] in Digraph.+ where+ nd' = nd { nd_bndr = bndr', nd_score = score }+ score = nodeScore bndr bndr' rhs lb_deps+ lb_deps = extendFvs_ rule_fv_env inl_fvs++ rule_fv_env :: IdEnv IdSet+ -- Maps a variable f to the variables from this group+ -- mentioned in RHS of active rules for f+ -- Domain is *subset* of bound vars (others have no rule fvs)+ rule_fv_env = transClosureFV (mkVarEnv init_rule_fvs)+ init_rule_fvs -- See Note [Finding rule RHS free vars]+ = [ (b, trimmed_rule_fvs)+ | ND { nd_bndr = b, nd_active_rule_fvs = rule_fvs } <- details_s+ , let trimmed_rule_fvs = rule_fvs `intersectVarSet` bndr_set+ , not (isEmptyVarSet trimmed_rule_fvs) ]+++------------------------------------------+nodeScore :: Id -- Binder has old occ-info (just for loop-breaker-ness)+ -> Id -- Binder with new occ-info+ -> CoreExpr -- RHS+ -> VarSet -- Loop-breaker dependencies+ -> NodeScore+nodeScore old_bndr new_bndr bind_rhs lb_deps+ | not (isId old_bndr) -- A type or cercion variable is never a loop breaker+ = (100, 0, False)++ | old_bndr `elemVarSet` lb_deps -- Self-recursive things are great loop breakers+ = (0, 0, True) -- See Note [Self-recursion and loop breakers]++ | exprIsTrivial rhs+ = mk_score 10 -- Practically certain to be inlined+ -- Used to have also: && not (isExportedId bndr)+ -- But I found this sometimes cost an extra iteration when we have+ -- rec { d = (a,b); a = ...df...; b = ...df...; df = d }+ -- where df is the exported dictionary. Then df makes a really+ -- bad choice for loop breaker++ | DFunUnfolding { df_args = args } <- id_unfolding+ -- Never choose a DFun as a loop breaker+ -- Note [DFuns should not be loop breakers]+ = (9, length args, is_lb)++ -- Data structures are more important than INLINE pragmas+ -- so that dictionary/method recursion unravels++ | CoreUnfolding { uf_guidance = UnfWhen {} } <- id_unfolding+ = mk_score 6++ | is_con_app rhs -- Data types help with cases:+ = mk_score 5 -- Note [Constructor applications]++ | isStableUnfolding id_unfolding+ , can_unfold+ = mk_score 3++ | isOneOcc (idOccInfo new_bndr)+ = mk_score 2 -- Likely to be inlined++ | can_unfold -- The Id has some kind of unfolding+ = mk_score 1++ | otherwise+ = (0, 0, is_lb)++ where+ mk_score :: Int -> NodeScore+ mk_score rank = (rank, rhs_size, is_lb)++ is_lb = isStrongLoopBreaker (idOccInfo old_bndr)+ rhs = case id_unfolding of+ CoreUnfolding { uf_src = src, uf_tmpl = unf_rhs }+ | isStableSource src+ -> unf_rhs+ _ -> bind_rhs+ -- 'bind_rhs' is irrelevant for inlining things with a stable unfolding+ rhs_size = case id_unfolding of+ CoreUnfolding { uf_guidance = guidance }+ | UnfIfGoodArgs { ug_size = size } <- guidance+ -> size+ _ -> cheapExprSize rhs++ can_unfold = canUnfold id_unfolding+ id_unfolding = realIdUnfolding old_bndr+ -- realIdUnfolding: Ignore loop-breaker-ness here because+ -- that is what we are setting!++ -- Checking for a constructor application+ -- Cheap and cheerful; the simplifier moves casts out of the way+ -- The lambda case is important to spot x = /\a. C (f a)+ -- which comes up when C is a dictionary constructor and+ -- f is a default method.+ -- Example: the instance for Show (ST s a) in GHC.ST+ --+ -- However we *also* treat (\x. C p q) as a con-app-like thing,+ -- Note [Closure conversion]+ is_con_app (Var v) = isConLikeId v+ is_con_app (App f _) = is_con_app f+ is_con_app (Lam _ e) = is_con_app e+ is_con_app (Tick _ e) = is_con_app e+ is_con_app _ = False++maxExprSize :: Int+maxExprSize = 20 -- Rather arbitrary++cheapExprSize :: CoreExpr -> Int+-- Maxes out at maxExprSize+cheapExprSize e+ = go 0 e+ where+ go n e | n >= maxExprSize = n+ | otherwise = go1 n e++ go1 n (Var {}) = n+1+ go1 n (Lit {}) = n+1+ go1 n (Type {}) = n+ go1 n (Coercion {}) = n+ go1 n (Tick _ e) = go1 n e+ go1 n (Cast e _) = go1 n e+ go1 n (App f a) = go (go1 n f) a+ go1 n (Lam b e)+ | isTyVar b = go1 n e+ | otherwise = go (n+1) e+ go1 n (Let b e) = gos (go1 n e) (rhssOfBind b)+ go1 n (Case e _ _ as) = gos (go1 n e) (rhssOfAlts as)++ gos n [] = n+ gos n (e:es) | n >= maxExprSize = n+ | otherwise = gos (go1 n e) es++betterLB :: NodeScore -> NodeScore -> Bool+-- If n1 `betterLB` n2 then choose n1 as the loop breaker+betterLB (rank1, size1, lb1) (rank2, size2, _)+ | rank1 < rank2 = True+ | rank1 > rank2 = False+ | size1 < size2 = False -- Make the bigger n2 into the loop breaker+ | size1 > size2 = True+ | lb1 = True -- Tie-break: if n1 was a loop breaker before, choose it+ | otherwise = False -- See Note [Loop breakers, node scoring, and stability]++{- Note [Self-recursion and loop breakers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have+ rec { f = ...f...g...+ ; g = .....f... }+then 'f' has to be a loop breaker anyway, so we may as well choose it+right away, so that g can inline freely.++This is really just a cheap hack. Consider+ rec { f = ...g...+ ; g = ..f..h...+ ; h = ...f....}+Here f or g are better loop breakers than h; but we might accidentally+choose h. Finding the minimal set of loop breakers is hard.++Note [Loop breakers, node scoring, and stability]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To choose a loop breaker, we give a NodeScore to each node in the SCC,+and pick the one with the best score (according to 'betterLB').++We need to be jolly careful (Trac #12425, #12234) about the stability+of this choice. Suppose we have++ let rec { f = ...g...g...+ ; g = ...f...f... }+ in+ case x of+ True -> ...f..+ False -> ..f...++In each iteration of the simplifier the occurrence analyser OccAnal+chooses a loop breaker. Suppose in iteration 1 it choose g as the loop+breaker. That means it is free to inline f.++Suppose that GHC decides to inline f in the branches of the case, but+(for some reason; eg it is not saturated) in the rhs of g. So we get++ let rec { f = ...g...g...+ ; g = ...f...f... }+ in+ case x of+ True -> ...g...g.....+ False -> ..g..g....++Now suppose that, for some reason, in the next iteration the occurrence+analyser chooses f as the loop breaker, so it can freely inline g. And+again for some reason the simplifier inlines g at its calls in the case+branches, but not in the RHS of f. Then we get++ let rec { f = ...g...g...+ ; g = ...f...f... }+ in+ case x of+ True -> ...(...f...f...)...(...f..f..).....+ False -> ..(...f...f...)...(..f..f...)....++You can see where this is going! Each iteration of the simplifier+doubles the number of calls to f or g. No wonder GHC is slow!++(In the particular example in comment:3 of #12425, f and g are the two+mutually recursive fmap instances for CondT and Result. They are both+marked INLINE which, oddly, is why they don't inline in each other's+RHS, because the call there is not saturated.)++The root cause is that we flip-flop on our choice of loop breaker. I+always thought it didn't matter, and indeed for any single iteration+to terminate, it doesn't matter. But when we iterate, it matters a+lot!!++So The Plan is this:+ If there is a tie, choose the node that+ was a loop breaker last time round++Hence the is_lb field of NodeScore++************************************************************************+* *+ Right hand sides+* *+************************************************************************+-}++occAnalRhs :: OccEnv -> RecFlag -> Id -> [CoreBndr] -> CoreExpr+ -> (UsageDetails, [CoreBndr], CoreExpr)+ -- Returned usage details covers only the RHS,+ -- and *not* the RULE or INLINE template for the Id+occAnalRhs env Recursive _ bndrs body+ = occAnalRecRhs env bndrs body+occAnalRhs env NonRecursive id bndrs body+ = occAnalNonRecRhs env id bndrs body++occAnalRecRhs :: OccEnv -> [CoreBndr] -> CoreExpr -- Rhs lambdas, body+ -> (UsageDetails, [CoreBndr], CoreExpr)+ -- Returned usage details covers only the RHS,+ -- and *not* the RULE or INLINE template for the Id+occAnalRecRhs env bndrs body = occAnalLamOrRhs (rhsCtxt env) bndrs body++occAnalNonRecRhs :: OccEnv+ -> Id -> [CoreBndr] -> CoreExpr -- Binder; rhs lams, body+ -- Binder is already tagged with occurrence info+ -> (UsageDetails, [CoreBndr], CoreExpr)+ -- Returned usage details covers only the RHS,+ -- and *not* the RULE or INLINE template for the Id+occAnalNonRecRhs env bndr bndrs body+ = occAnalLamOrRhs rhs_env bndrs body+ where+ -- See Note [Cascading inlines]+ env1 | certainly_inline = env+ | otherwise = rhsCtxt env++ -- See Note [Sources of one-shot information]+ rhs_env = env1 { occ_one_shots = argOneShots dmd }++ certainly_inline -- See Note [Cascading inlines]+ = case idOccInfo bndr of+ OneOcc { occ_in_lam = in_lam, occ_one_br = one_br }+ -> not in_lam && one_br && active && not_stable+ _ -> False++ dmd = idDemandInfo bndr+ active = isAlwaysActive (idInlineActivation bndr)+ not_stable = not (isStableUnfolding (idUnfolding bndr))++occAnalUnfolding :: OccEnv+ -> RecFlag+ -> Id+ -> Maybe UsageDetails+ -- Just the analysis, not a new unfolding. The unfolding+ -- got analysed when it was created and we don't need to+ -- update it.+occAnalUnfolding env rec_flag id+ = case realIdUnfolding id of -- ignore previous loop-breaker flag+ CoreUnfolding { uf_tmpl = rhs, uf_src = src }+ | not (isStableSource src)+ -> Nothing+ | otherwise+ -> Just $ markAllMany usage+ where+ (bndrs, body) = collectBinders rhs+ (usage, _, _) = occAnalRhs env rec_flag id bndrs body++ DFunUnfolding { df_bndrs = bndrs, df_args = args }+ -> Just $ zapDetails (delDetailsList usage bndrs)+ where+ usage = foldr (+++) emptyDetails (map (fst . occAnal env) args)++ _ -> Nothing++occAnalRules :: OccEnv+ -> Maybe JoinArity -- If the binder is (or MAY become) a join+ -- point, what its join arity is (or WOULD+ -- become). See Note [Rules and join points].+ -> RecFlag+ -> Id+ -> [(CoreRule, -- Each (non-built-in) rule+ UsageDetails, -- Usage details for LHS+ UsageDetails)] -- Usage details for RHS+occAnalRules env mb_expected_join_arity rec_flag id+ = [ (rule, lhs_uds, rhs_uds) | rule@Rule {} <- idCoreRules id+ , let (lhs_uds, rhs_uds) = occ_anal_rule rule ]+ where+ occ_anal_rule (Rule { ru_bndrs = bndrs, ru_args = args, ru_rhs = rhs })+ = (lhs_uds, final_rhs_uds)+ where+ lhs_uds = addManyOccsSet emptyDetails $+ (exprsFreeVars args `delVarSetList` bndrs)+ (rhs_bndrs, rhs_body) = collectBinders rhs+ (rhs_uds, _, _) = occAnalRhs env rec_flag id rhs_bndrs rhs_body+ -- Note [Rules are extra RHSs]+ -- Note [Rule dependency info]+ final_rhs_uds = adjust_tail_info args $ markAllMany $+ (rhs_uds `delDetailsList` bndrs)+ occ_anal_rule _+ = (emptyDetails, emptyDetails)++ adjust_tail_info args uds -- see Note [Rules and join points]+ = case mb_expected_join_arity of+ Just ar | args `lengthIs` ar -> uds+ _ -> markAllNonTailCalled uds+{-+Note [Cascading inlines]+~~~~~~~~~~~~~~~~~~~~~~~~+By default we use an rhsCtxt for the RHS of a binding. This tells the+occ anal n that it's looking at an RHS, which has an effect in+occAnalApp. In particular, for constructor applications, it makes+the arguments appear to have NoOccInfo, so that we don't inline into+them. Thus x = f y+ k = Just x+we do not want to inline x.++But there's a problem. Consider+ x1 = a0 : []+ x2 = a1 : x1+ x3 = a2 : x2+ g = f x3+First time round, it looks as if x1 and x2 occur as an arg of a+let-bound constructor ==> give them a many-occurrence.+But then x3 is inlined (unconditionally as it happens) and+next time round, x2 will be, and the next time round x1 will be+Result: multiple simplifier iterations. Sigh.++So, when analysing the RHS of x3 we notice that x3 will itself+definitely inline the next time round, and so we analyse x3's rhs in+an ordinary context, not rhsCtxt. Hence the "certainly_inline" stuff.++Annoyingly, we have to approximate SimplUtils.preInlineUnconditionally.+If we say "yes" when preInlineUnconditionally says "no" the simplifier iterates+indefinitely:+ x = f y+ k = Just x+inline ==>+ k = Just (f y)+float ==>+ x1 = f y+ k = Just x1++This is worse than the slow cascade, so we only want to say "certainly_inline"+if it really is certain. Look at the note with preInlineUnconditionally+for the various clauses.+++************************************************************************+* *+ Expressions+* *+************************************************************************+-}++occAnal :: OccEnv+ -> CoreExpr+ -> (UsageDetails, -- Gives info only about the "interesting" Ids+ CoreExpr)++occAnal _ expr@(Type _) = (emptyDetails, expr)+occAnal _ expr@(Lit _) = (emptyDetails, expr)+occAnal env expr@(Var _) = occAnalApp env (expr, [], [])+ -- At one stage, I gathered the idRuleVars for the variable here too,+ -- which in a way is the right thing to do.+ -- But that went wrong right after specialisation, when+ -- the *occurrences* of the overloaded function didn't have any+ -- rules in them, so the *specialised* versions looked as if they+ -- weren't used at all.++occAnal _ (Coercion co)+ = (addManyOccsSet emptyDetails (coVarsOfCo co), Coercion co)+ -- See Note [Gather occurrences of coercion variables]++{-+Note [Gather occurrences of coercion variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to gather info about what coercion variables appear, so that+we can sort them into the right place when doing dependency analysis.+-}++occAnal env (Tick tickish body)+ | tickish `tickishScopesLike` SoftScope+ = (markAllNonTailCalled usage, Tick tickish body')++ | Breakpoint _ ids <- tickish+ = (usage_lam +++ foldr addManyOccs emptyDetails ids, Tick tickish body')+ -- never substitute for any of the Ids in a Breakpoint++ | otherwise+ = (usage_lam, Tick tickish body')+ where+ !(usage,body') = occAnal env body+ -- for a non-soft tick scope, we can inline lambdas only+ usage_lam = markAllNonTailCalled (markAllInsideLam usage)+ -- TODO There may be ways to make ticks and join points play+ -- nicer together, but right now there are problems:+ -- let j x = ... in tick<t> (j 1)+ -- Making j a join point may cause the simplifier to drop t+ -- (if the tick is put into the continuation). So we don't+ -- count j 1 as a tail call.++occAnal env (Cast expr co)+ = case occAnal env expr of { (usage, expr') ->+ let usage1 = zapDetailsIf (isRhsEnv env) usage+ usage2 = addManyOccsSet usage1 (coVarsOfCo co)+ -- See Note [Gather occurrences of coercion variables]+ in (markAllNonTailCalled usage2, Cast expr' co)+ -- If we see let x = y `cast` co+ -- then mark y as 'Many' so that we don't+ -- immediately inline y again.+ }++occAnal env app@(App _ _)+ = occAnalApp env (collectArgsTicks tickishFloatable app)++-- Ignore type variables altogether+-- (a) occurrences inside type lambdas only not marked as InsideLam+-- (b) type variables not in environment++occAnal env (Lam x body)+ | isTyVar x+ = case occAnal env body of { (body_usage, body') ->+ (markAllNonTailCalled body_usage, Lam x body')+ }++-- For value lambdas we do a special hack. Consider+-- (\x. \y. ...x...)+-- If we did nothing, x is used inside the \y, so would be marked+-- as dangerous to dup. But in the common case where the abstraction+-- is applied to two arguments this is over-pessimistic.+-- So instead, we just mark each binder with its occurrence+-- info in the *body* of the multiple lambda.+-- Then, the simplifier is careful when partially applying lambdas.++occAnal env expr@(Lam _ _)+ = case occAnalLamOrRhs env binders body of { (usage, tagged_binders, body') ->+ let+ expr' = mkLams tagged_binders body'+ usage1 = markAllNonTailCalled usage+ one_shot_gp = all isOneShotBndr tagged_binders+ final_usage | one_shot_gp = usage1+ | otherwise = markAllInsideLam usage1+ in+ (final_usage, expr') }+ where+ (binders, body) = collectBinders expr++occAnal env (Case scrut bndr ty alts)+ = case occ_anal_scrut scrut alts of { (scrut_usage, scrut') ->+ case mapAndUnzip occ_anal_alt alts of { (alts_usage_s, alts') ->+ let+ alts_usage = foldr combineAltsUsageDetails emptyDetails alts_usage_s+ (alts_usage1, tagged_bndr) = tag_case_bndr alts_usage bndr+ total_usage = markAllNonTailCalled scrut_usage +++ alts_usage1+ -- Alts can have tail calls, but the scrutinee can't+ in+ total_usage `seq` (total_usage, Case scrut' tagged_bndr ty alts') }}+ where+ -- Note [Case binder usage]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~+ -- The case binder gets a usage of either "many" or "dead", never "one".+ -- Reason: we like to inline single occurrences, to eliminate a binding,+ -- but inlining a case binder *doesn't* eliminate a binding.+ -- We *don't* want to transform+ -- case x of w { (p,q) -> f w }+ -- into+ -- case x of w { (p,q) -> f (p,q) }+ tag_case_bndr usage bndr+ = (usage', setIdOccInfo bndr final_occ_info)+ where+ occ_info = lookupDetails usage bndr+ usage' = usage `delDetails` bndr+ final_occ_info = case occ_info of IAmDead -> IAmDead+ _ -> noOccInfo++ alt_env = mkAltEnv env scrut bndr+ occ_anal_alt = occAnalAlt alt_env++ occ_anal_scrut (Var v) (alt1 : other_alts)+ | not (null other_alts) || not (isDefaultAlt alt1)+ = (mkOneOcc env v True 0, Var v)+ -- The 'True' says that the variable occurs in an interesting+ -- context; the case has at least one non-default alternative+ occ_anal_scrut (Tick t e) alts+ | t `tickishScopesLike` SoftScope+ -- No reason to not look through all ticks here, but only+ -- for soft-scoped ticks we can do so without having to+ -- update returned occurance info (see occAnal)+ = second (Tick t) $ occ_anal_scrut e alts++ occ_anal_scrut scrut _alts+ = occAnal (vanillaCtxt env) scrut -- No need for rhsCtxt++occAnal env (Let bind body)+ = case occAnal env body of { (body_usage, body') ->+ case occAnalBind env NotTopLevel+ noImpRuleEdges bind+ body_usage of { (final_usage, new_binds) ->+ (final_usage, mkLets new_binds body') }}++occAnalArgs :: OccEnv -> [CoreExpr] -> [OneShots] -> (UsageDetails, [CoreExpr])+occAnalArgs _ [] _+ = (emptyDetails, [])++occAnalArgs env (arg:args) one_shots+ | isTypeArg arg+ = case occAnalArgs env args one_shots of { (uds, args') ->+ (uds, arg:args') }++ | otherwise+ = case argCtxt env one_shots of { (arg_env, one_shots') ->+ case occAnal arg_env arg of { (uds1, arg') ->+ case occAnalArgs env args one_shots' of { (uds2, args') ->+ (uds1 +++ uds2, arg':args') }}}++{-+Applications are dealt with specially because we want+the "build hack" to work.++Note [Arguments of let-bound constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f x = let y = expensive x in+ let z = (True,y) in+ (case z of {(p,q)->q}, case z of {(p,q)->q})+We feel free to duplicate the WHNF (True,y), but that means+that y may be duplicated thereby.++If we aren't careful we duplicate the (expensive x) call!+Constructors are rather like lambdas in this way.+-}++occAnalApp :: OccEnv+ -> (Expr CoreBndr, [Arg CoreBndr], [Tickish Id])+ -> (UsageDetails, Expr CoreBndr)+occAnalApp env (Var fun, args, ticks)+ | null ticks = (uds, mkApps (Var fun) args')+ | otherwise = (uds, mkTicks ticks $ mkApps (Var fun) args')+ where+ uds = fun_uds +++ final_args_uds++ !(args_uds, args') = occAnalArgs env args one_shots+ !final_args_uds+ | isRhsEnv env && is_exp = markAllNonTailCalled $+ markAllInsideLam args_uds+ | otherwise = markAllNonTailCalled args_uds+ -- We mark the free vars of the argument of a constructor or PAP+ -- as "inside-lambda", if it is the RHS of a let(rec).+ -- This means that nothing gets inlined into a constructor or PAP+ -- argument position, which is what we want. Typically those+ -- constructor arguments are just variables, or trivial expressions.+ -- We use inside-lam because it's like eta-expanding the PAP.+ --+ -- This is the *whole point* of the isRhsEnv predicate+ -- See Note [Arguments of let-bound constructors]++ n_val_args = valArgCount args+ n_args = length args+ fun_uds = mkOneOcc env fun (n_val_args > 0) n_args+ is_exp = isExpandableApp fun n_val_args+ -- See Note [CONLIKE pragma] in BasicTypes+ -- The definition of is_exp should match that in Simplify.prepareRhs++ one_shots = argsOneShots (idStrictness fun) guaranteed_val_args+ guaranteed_val_args = n_val_args + length (takeWhile isOneShotInfo+ (occ_one_shots env))+ -- See Note [Sources of one-shot information], bullet point A']++occAnalApp env (fun, args, ticks)+ = (markAllNonTailCalled (fun_uds +++ args_uds),+ mkTicks ticks $ mkApps fun' args')+ where+ !(fun_uds, fun') = occAnal (addAppCtxt env args) fun+ -- The addAppCtxt is a bit cunning. One iteration of the simplifier+ -- often leaves behind beta redexs like+ -- (\x y -> e) a1 a2+ -- Here we would like to mark x,y as one-shot, and treat the whole+ -- thing much like a let. We do this by pushing some True items+ -- onto the context stack.+ !(args_uds, args') = occAnalArgs env args []++zapDetailsIf :: Bool -- If this is true+ -> UsageDetails -- Then do zapDetails on this+ -> UsageDetails+zapDetailsIf True uds = zapDetails uds+zapDetailsIf False uds = uds++{-+Note [Sources of one-shot information]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The occurrence analyser obtains one-shot-lambda information from two sources:++A: Saturated applications: eg f e1 .. en++ In general, given a call (f e1 .. en) we can propagate one-shot info from+ f's strictness signature into e1 .. en, but /only/ if n is enough to+ saturate the strictness signature. A strictness signature like++ f :: C1(C1(L))LS++ means that *if f is applied to three arguments* then it will guarantee to+ call its first argument at most once, and to call the result of that at+ most once. But if f has fewer than three arguments, all bets are off; e.g.++ map (f (\x y. expensive) e2) xs++ Here the \x y abstraction may be called many times (once for each element of+ xs) so we should not mark x and y as one-shot. But if it was++ map (f (\x y. expensive) 3 2) xs++ then the first argument of f will be called at most once.++ The one-shot info, derived from f's strictness signature, is+ computed by 'argsOneShots', called in occAnalApp.++A': Non-obviously saturated applications: eg build (f (\x y -> expensive))+ where f is as above.++ In this case, f is only manifestly applied to one argument, so it does not+ look saturated. So by the previous point, we should not use its strictness+ signature to learn about the one-shotness of \x y. But in this case we can:+ build is fully applied, so we may use its strictness signature; and from+ that we learn that build calls its argument with two arguments *at most once*.++ So there is really only one call to f, and it will have three arguments. In+ that sense, f is saturated, and we may proceed as described above.++ Hence the computation of 'guaranteed_val_args' in occAnalApp, using+ '(occ_one_shots env)'. See also Trac #13227, comment:9++B: Let-bindings: eg let f = \c. let ... in \n -> blah+ in (build f, build f)++ Propagate one-shot info from the demanand-info on 'f' to the+ lambdas in its RHS (which may not be syntactically at the top)++ This information must have come from a previous run of the demanand+ analyser.++Previously, the demand analyser would *also* set the one-shot information, but+that code was buggy (see #11770), so doing it only in on place, namely here, is+saner.++Note [OneShots]+~~~~~~~~~~~~~~~+When analysing an expression, the occ_one_shots argument contains information+about how the function is being used. The length of the list indicates+how many arguments will eventually be passed to the analysed expression,+and the OneShotInfo indicates whether this application is once or multiple times.++Example:++ Context of f occ_one_shots when analysing f++ f 1 2 [OneShot, OneShot]+ map (f 1) [OneShot, NoOneShotInfo]+ build f [OneShot, OneShot]+ f 1 2 `seq` f 2 1 [NoOneShotInfo, OneShot]++Note [Binders in case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ case x of y { (a,b) -> f y }+We treat 'a', 'b' as dead, because they don't physically occur in the+case alternative. (Indeed, a variable is dead iff it doesn't occur in+its scope in the output of OccAnal.) It really helps to know when+binders are unused. See esp the call to isDeadBinder in+Simplify.mkDupableAlt++In this example, though, the Simplifier will bring 'a' and 'b' back to+life, beause it binds 'y' to (a,b) (imagine got inlined and+scrutinised y).+-}++occAnalLamOrRhs :: OccEnv -> [CoreBndr] -> CoreExpr+ -> (UsageDetails, [CoreBndr], CoreExpr)+occAnalLamOrRhs env [] body+ = case occAnal env body of (body_usage, body') -> (body_usage, [], body')+ -- RHS of thunk or nullary join point+occAnalLamOrRhs env (bndr:bndrs) body+ | isTyVar bndr+ = -- Important: Keep the environment so that we don't inline into an RHS like+ -- \(@ x) -> C @x (f @x)+ -- (see the beginning of Note [Cascading inlines]).+ case occAnalLamOrRhs env bndrs body of+ (body_usage, bndrs', body') -> (body_usage, bndr:bndrs', body')+occAnalLamOrRhs env binders body+ = case occAnal env_body body of { (body_usage, body') ->+ let+ (final_usage, tagged_binders) = tagLamBinders body_usage binders'+ -- Use binders' to put one-shot info on the lambdas+ in+ (final_usage, tagged_binders, body') }+ where+ (env_body, binders') = oneShotGroup env binders++occAnalAlt :: (OccEnv, Maybe (Id, CoreExpr))+ -> CoreAlt+ -> (UsageDetails, Alt IdWithOccInfo)+occAnalAlt (env, scrut_bind) (con, bndrs, rhs)+ = case occAnal env rhs of { (rhs_usage1, rhs1) ->+ let+ (alt_usg, tagged_bndrs) = tagLamBinders rhs_usage1 bndrs+ -- See Note [Binders in case alternatives]+ (alt_usg', rhs2) =+ wrapAltRHS env scrut_bind alt_usg tagged_bndrs rhs1+ in+ (alt_usg', (con, tagged_bndrs, rhs2)) }++wrapAltRHS :: OccEnv+ -> Maybe (Id, CoreExpr) -- proxy mapping generated by mkAltEnv+ -> UsageDetails -- usage for entire alt (p -> rhs)+ -> [Var] -- alt binders+ -> CoreExpr -- alt RHS+ -> (UsageDetails, CoreExpr)+wrapAltRHS env (Just (scrut_var, let_rhs)) alt_usg bndrs alt_rhs+ | occ_binder_swap env+ , scrut_var `usedIn` alt_usg -- bndrs are not be present in alt_usg so this+ -- handles condition (a) in Note [Binder swap]+ , not captured -- See condition (b) in Note [Binder swap]+ = ( alt_usg' +++ let_rhs_usg+ , Let (NonRec tagged_scrut_var let_rhs') alt_rhs )+ where+ captured = any (`usedIn` let_rhs_usg) bndrs+ -- The rhs of the let may include coercion variables+ -- if the scrutinee was a cast, so we must gather their+ -- usage. See Note [Gather occurrences of coercion variables]+ (let_rhs_usg, let_rhs') = occAnal env let_rhs+ (alt_usg', [tagged_scrut_var]) = tagLamBinders alt_usg [scrut_var]++wrapAltRHS _ _ alt_usg _ alt_rhs+ = (alt_usg, alt_rhs)++{-+************************************************************************+* *+ OccEnv+* *+************************************************************************+-}++data OccEnv+ = OccEnv { occ_encl :: !OccEncl -- Enclosing context information+ , occ_one_shots :: !OneShots -- See Note [OneShots]+ , occ_gbl_scrut :: GlobalScruts+ , occ_rule_act :: Activation -> Bool -- Which rules are active+ -- See Note [Finding rule RHS free vars]+ , occ_binder_swap :: !Bool -- enable the binder_swap+ -- See CorePrep Note [Dead code in CorePrep]+ }++type GlobalScruts = IdSet -- See Note [Binder swap on GlobalId scrutinees]++-----------------------------+-- OccEncl is used to control whether to inline into constructor arguments+-- For example:+-- x = (p,q) -- Don't inline p or q+-- y = /\a -> (p a, q a) -- Still don't inline p or q+-- z = f (p,q) -- Do inline p,q; it may make a rule fire+-- So OccEncl tells enought about the context to know what to do when+-- we encounter a constructor application or PAP.++data OccEncl+ = OccRhs -- RHS of let(rec), albeit perhaps inside a type lambda+ -- Don't inline into constructor args here+ | OccVanilla -- Argument of function, body of lambda, scruintee of case etc.+ -- Do inline into constructor args here++instance Outputable OccEncl where+ ppr OccRhs = text "occRhs"+ ppr OccVanilla = text "occVanilla"++-- See note [OneShots]+type OneShots = [OneShotInfo]++initOccEnv :: (Activation -> Bool) -> OccEnv+initOccEnv active_rule+ = OccEnv { occ_encl = OccVanilla+ , occ_one_shots = []+ , occ_gbl_scrut = emptyVarSet+ , occ_rule_act = active_rule+ , occ_binder_swap = True }++vanillaCtxt :: OccEnv -> OccEnv+vanillaCtxt env = env { occ_encl = OccVanilla, occ_one_shots = [] }++rhsCtxt :: OccEnv -> OccEnv+rhsCtxt env = env { occ_encl = OccRhs, occ_one_shots = [] }++argCtxt :: OccEnv -> [OneShots] -> (OccEnv, [OneShots])+argCtxt env []+ = (env { occ_encl = OccVanilla, occ_one_shots = [] }, [])+argCtxt env (one_shots:one_shots_s)+ = (env { occ_encl = OccVanilla, occ_one_shots = one_shots }, one_shots_s)++isRhsEnv :: OccEnv -> Bool+isRhsEnv (OccEnv { occ_encl = OccRhs }) = True+isRhsEnv (OccEnv { occ_encl = OccVanilla }) = False++oneShotGroup :: OccEnv -> [CoreBndr]+ -> ( OccEnv+ , [CoreBndr] )+ -- The result binders have one-shot-ness set that they might not have had originally.+ -- This happens in (build (\c n -> e)). Here the occurrence analyser+ -- linearity context knows that c,n are one-shot, and it records that fact in+ -- the binder. This is useful to guide subsequent float-in/float-out tranformations++oneShotGroup env@(OccEnv { occ_one_shots = ctxt }) bndrs+ = go ctxt bndrs []+ where+ go ctxt [] rev_bndrs+ = ( env { occ_one_shots = ctxt, occ_encl = OccVanilla }+ , reverse rev_bndrs )++ go [] bndrs rev_bndrs+ = ( env { occ_one_shots = [], occ_encl = OccVanilla }+ , reverse rev_bndrs ++ bndrs )++ go ctxt@(one_shot : ctxt') (bndr : bndrs) rev_bndrs+ | isId bndr = go ctxt' bndrs (bndr': rev_bndrs)+ | otherwise = go ctxt bndrs (bndr : rev_bndrs)+ where+ bndr' = updOneShotInfo bndr one_shot+ -- Use updOneShotInfo, not setOneShotInfo, as pre-existing+ -- one-shot info might be better than what we can infer, e.g.+ -- due to explicit use of the magic 'oneShot' function.+ -- See Note [The oneShot function]+++markJoinOneShots :: Maybe JoinArity -> [Var] -> [Var]+-- Mark the lambdas of a non-recursive join point as one-shot.+-- This is good to prevent gratuitous float-out etc+markJoinOneShots mb_join_arity bndrs+ = case mb_join_arity of+ Nothing -> bndrs+ Just n -> go n bndrs+ where+ go 0 bndrs = bndrs+ go _ [] = WARN( True, ppr mb_join_arity <+> ppr bndrs ) []+ go n (b:bs) = b' : go (n-1) bs+ where+ b' | isId b = setOneShotLambda b+ | otherwise = b++addAppCtxt :: OccEnv -> [Arg CoreBndr] -> OccEnv+addAppCtxt env@(OccEnv { occ_one_shots = ctxt }) args+ = env { occ_one_shots = replicate (valArgCount args) OneShotLam ++ ctxt }++transClosureFV :: UniqFM VarSet -> UniqFM VarSet+-- If (f,g), (g,h) are in the input, then (f,h) is in the output+-- as well as (f,g), (g,h)+transClosureFV env+ | no_change = env+ | otherwise = transClosureFV (listToUFM new_fv_list)+ where+ (no_change, new_fv_list) = mapAccumL bump True (nonDetUFMToList env)+ -- It's OK to use nonDetUFMToList here because we'll forget the+ -- ordering by creating a new set with listToUFM+ bump no_change (b,fvs)+ | no_change_here = (no_change, (b,fvs))+ | otherwise = (False, (b,new_fvs))+ where+ (new_fvs, no_change_here) = extendFvs env fvs++-------------+extendFvs_ :: UniqFM VarSet -> VarSet -> VarSet+extendFvs_ env s = fst (extendFvs env s) -- Discard the Bool flag++extendFvs :: UniqFM VarSet -> VarSet -> (VarSet, Bool)+-- (extendFVs env s) returns+-- (s `union` env(s), env(s) `subset` s)+extendFvs env s+ | isNullUFM env+ = (s, True)+ | otherwise+ = (s `unionVarSet` extras, extras `subVarSet` s)+ where+ extras :: VarSet -- env(s)+ extras = nonDetFoldUFM unionVarSet emptyVarSet $+ -- It's OK to use nonDetFoldUFM here because unionVarSet commutes+ intersectUFM_C (\x _ -> x) env (getUniqSet s)++{-+************************************************************************+* *+ Binder swap+* *+************************************************************************++Note [Binder swap]+~~~~~~~~~~~~~~~~~~+We do these two transformations right here:++ (1) case x of b { pi -> ri }+ ==>+ case x of b { pi -> let x=b in ri }++ (2) case (x |> co) of b { pi -> ri }+ ==>+ case (x |> co) of b { pi -> let x = b |> sym co in ri }++ Why (2)? See Note [Case of cast]++In both cases, in a particular alternative (pi -> ri), we only+add the binding if+ (a) x occurs free in (pi -> ri)+ (ie it occurs in ri, but is not bound in pi)+ (b) the pi does not bind b (or the free vars of co)+We need (a) and (b) for the inserted binding to be correct.++For the alternatives where we inject the binding, we can transfer+all x's OccInfo to b. And that is the point.++Notice that+ * The deliberate shadowing of 'x'.+ * That (a) rapidly becomes false, so no bindings are injected.++The reason for doing these transformations here is because it allows+us to adjust the OccInfo for 'x' and 'b' as we go.++ * Suppose the only occurrences of 'x' are the scrutinee and in the+ ri; then this transformation makes it occur just once, and hence+ get inlined right away.++ * If we do this in the Simplifier, we don't know whether 'x' is used+ in ri, so we are forced to pessimistically zap b's OccInfo even+ though it is typically dead (ie neither it nor x appear in the+ ri). There's nothing actually wrong with zapping it, except that+ it's kind of nice to know which variables are dead. My nose+ tells me to keep this information as robustly as possible.++The Maybe (Id,CoreExpr) passed to occAnalAlt is the extra let-binding+{x=b}; it's Nothing if the binder-swap doesn't happen.++There is a danger though. Consider+ let v = x +# y+ in case (f v) of w -> ...v...v...+And suppose that (f v) expands to just v. Then we'd like to+use 'w' instead of 'v' in the alternative. But it may be too+late; we may have substituted the (cheap) x+#y for v in the+same simplifier pass that reduced (f v) to v.++I think this is just too bad. CSE will recover some of it.++Note [Case of cast]+~~~~~~~~~~~~~~~~~~~+Consider case (x `cast` co) of b { I# ->+ ... (case (x `cast` co) of {...}) ...+We'd like to eliminate the inner case. That is the motivation for+equation (2) in Note [Binder swap]. When we get to the inner case, we+inline x, cancel the casts, and away we go.++Note [Binder swap on GlobalId scrutinees]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When the scrutinee is a GlobalId we must take care in two ways++ i) In order to *know* whether 'x' occurs free in the RHS, we need its+ occurrence info. BUT, we don't gather occurrence info for+ GlobalIds. That's the reason for the (small) occ_gbl_scrut env in+ OccEnv is for: it says "gather occurrence info for these".++ ii) We must call localiseId on 'x' first, in case it's a GlobalId, or+ has an External Name. See, for example, SimplEnv Note [Global Ids in+ the substitution].++Note [Zap case binders in proxy bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+From the original+ case x of cb(dead) { p -> ...x... }+we will get+ case x of cb(live) { p -> let x = cb in ...x... }++Core Lint never expects to find an *occurrence* of an Id marked+as Dead, so we must zap the OccInfo on cb before making the+binding x = cb. See Trac #5028.++Historical note [no-case-of-case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We *used* to suppress the binder-swap in case expressions when+-fno-case-of-case is on. Old remarks:+ "This happens in the first simplifier pass,+ and enhances full laziness. Here's the bad case:+ f = \ y -> ...(case x of I# v -> ...(case x of ...) ... )+ If we eliminate the inner case, we trap it inside the I# v -> arm,+ which might prevent some full laziness happening. I've seen this+ in action in spectral/cichelli/Prog.hs:+ [(m,n) | m <- [1..max], n <- [1..max]]+ Hence the check for NoCaseOfCase."+However, now the full-laziness pass itself reverses the binder-swap, so this+check is no longer necessary.++Historical note [Suppressing the case binder-swap]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This old note describes a problem that is also fixed by doing the+binder-swap in OccAnal:++ There is another situation when it might make sense to suppress the+ case-expression binde-swap. If we have++ case x of w1 { DEFAULT -> case x of w2 { A -> e1; B -> e2 }+ ...other cases .... }++ We'll perform the binder-swap for the outer case, giving++ case x of w1 { DEFAULT -> case w1 of w2 { A -> e1; B -> e2 }+ ...other cases .... }++ But there is no point in doing it for the inner case, because w1 can't+ be inlined anyway. Furthermore, doing the case-swapping involves+ zapping w2's occurrence info (see paragraphs that follow), and that+ forces us to bind w2 when doing case merging. So we get++ case x of w1 { A -> let w2 = w1 in e1+ B -> let w2 = w1 in e2+ ...other cases .... }++ This is plain silly in the common case where w2 is dead.++ Even so, I can't see a good way to implement this idea. I tried+ not doing the binder-swap if the scrutinee was already evaluated+ but that failed big-time:++ data T = MkT !Int++ case v of w { MkT x ->+ case x of x1 { I# y1 ->+ case x of x2 { I# y2 -> ...++ Notice that because MkT is strict, x is marked "evaluated". But to+ eliminate the last case, we must either make sure that x (as well as+ x1) has unfolding MkT y1. The straightforward thing to do is to do+ the binder-swap. So this whole note is a no-op.++It's fixed by doing the binder-swap in OccAnal because we can do the+binder-swap unconditionally and still get occurrence analysis+information right.+-}++mkAltEnv :: OccEnv -> CoreExpr -> Id -> (OccEnv, Maybe (Id, CoreExpr))+-- Does two things: a) makes the occ_one_shots = OccVanilla+-- b) extends the GlobalScruts if possible+-- c) returns a proxy mapping, binding the scrutinee+-- to the case binder, if possible+mkAltEnv env@(OccEnv { occ_gbl_scrut = pe }) scrut case_bndr+ = case stripTicksTopE (const True) scrut of+ Var v -> add_scrut v case_bndr'+ Cast (Var v) co -> add_scrut v (Cast case_bndr' (mkSymCo co))+ -- See Note [Case of cast]+ _ -> (env { occ_encl = OccVanilla }, Nothing)++ where+ add_scrut v rhs = ( env { occ_encl = OccVanilla, occ_gbl_scrut = pe `extendVarSet` v }+ , Just (localise v, rhs) )++ case_bndr' = Var (zapIdOccInfo case_bndr) -- See Note [Zap case binders in proxy bindings]+ localise scrut_var = mkLocalIdOrCoVar (localiseName (idName scrut_var)) (idType scrut_var)+ -- Localise the scrut_var before shadowing it; we're making a+ -- new binding for it, and it might have an External Name, or+ -- even be a GlobalId; Note [Binder swap on GlobalId scrutinees]+ -- Also we don't want any INLINE or NOINLINE pragmas!++{-+************************************************************************+* *+\subsection[OccurAnal-types]{OccEnv}+* *+************************************************************************++Note [UsageDetails and zapping]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++On many occasions, we must modify all gathered occurrence data at once. For+instance, all occurrences underneath a (non-one-shot) lambda set the+'occ_in_lam' flag to become 'True'. We could use 'mapVarEnv' to do this, but+that takes O(n) time and we will do this often---in particular, there are many+places where tail calls are not allowed, and each of these causes all variables+to get marked with 'NoTailCallInfo'.++Instead of relying on `mapVarEnv`, then, we carry three 'IdEnv's around along+with the 'OccInfoEnv'. Each of these extra environments is a "zapped set"+recording which variables have been zapped in some way. Zapping all occurrence+info then simply means setting the corresponding zapped set to the whole+'OccInfoEnv', a fast O(1) operation.+-}++type OccInfoEnv = IdEnv OccInfo -- A finite map from ids to their usage+ -- INVARIANT: never IAmDead+ -- (Deadness is signalled by not being in the map at all)++type ZappedSet = OccInfoEnv -- Values are ignored++data UsageDetails+ = UD { ud_env :: !OccInfoEnv+ , ud_z_many :: ZappedSet -- apply 'markMany' to these+ , ud_z_in_lam :: ZappedSet -- apply 'markInsideLam' to these+ , ud_z_no_tail :: ZappedSet } -- apply 'markNonTailCalled' to these+ -- INVARIANT: All three zapped sets are subsets of the OccInfoEnv++instance Outputable UsageDetails where+ ppr ud = ppr (ud_env (flattenUsageDetails ud))++-------------------+-- UsageDetails API++(+++), combineAltsUsageDetails+ :: UsageDetails -> UsageDetails -> UsageDetails+(+++) = combineUsageDetailsWith addOccInfo+combineAltsUsageDetails = combineUsageDetailsWith orOccInfo++combineUsageDetailsList :: [UsageDetails] -> UsageDetails+combineUsageDetailsList = foldl (+++) emptyDetails++mkOneOcc :: OccEnv -> Id -> InterestingCxt -> JoinArity -> UsageDetails+mkOneOcc env id int_cxt arity+ | isLocalId id+ = singleton $ OneOcc { occ_in_lam = False+ , occ_one_br = True+ , occ_int_cxt = int_cxt+ , occ_tail = AlwaysTailCalled arity }+ | id `elemVarSet` occ_gbl_scrut env+ = singleton noOccInfo++ | otherwise+ = emptyDetails+ where+ singleton info = emptyDetails { ud_env = unitVarEnv id info }++addOneOcc :: UsageDetails -> Id -> OccInfo -> UsageDetails+addOneOcc ud id info+ = ud { ud_env = extendVarEnv_C plus_zapped (ud_env ud) id info }+ `alterZappedSets` (`delVarEnv` id)+ where+ plus_zapped old new = doZapping ud id old `addOccInfo` new++addManyOccsSet :: UsageDetails -> VarSet -> UsageDetails+addManyOccsSet usage id_set = nonDetFoldUniqSet addManyOccs usage id_set+ -- It's OK to use nonDetFoldUFM here because addManyOccs commutes++-- Add several occurrences, assumed not to be tail calls+addManyOccs :: Var -> UsageDetails -> UsageDetails+addManyOccs v u | isId v = addOneOcc u v noOccInfo+ | otherwise = u+ -- Give a non-committal binder info (i.e noOccInfo) because+ -- a) Many copies of the specialised thing can appear+ -- b) We don't want to substitute a BIG expression inside a RULE+ -- even if that's the only occurrence of the thing+ -- (Same goes for INLINE.)++delDetails :: UsageDetails -> Id -> UsageDetails+delDetails ud bndr+ = ud `alterUsageDetails` (`delVarEnv` bndr)++delDetailsList :: UsageDetails -> [Id] -> UsageDetails+delDetailsList ud bndrs+ = ud `alterUsageDetails` (`delVarEnvList` bndrs)++emptyDetails :: UsageDetails+emptyDetails = UD { ud_env = emptyVarEnv+ , ud_z_many = emptyVarEnv+ , ud_z_in_lam = emptyVarEnv+ , ud_z_no_tail = emptyVarEnv }++isEmptyDetails :: UsageDetails -> Bool+isEmptyDetails = isEmptyVarEnv . ud_env++markAllMany, markAllInsideLam, markAllNonTailCalled, zapDetails+ :: UsageDetails -> UsageDetails+markAllMany ud = ud { ud_z_many = ud_env ud }+markAllInsideLam ud = ud { ud_z_in_lam = ud_env ud }+markAllNonTailCalled ud = ud { ud_z_no_tail = ud_env ud }++zapDetails = markAllMany . markAllNonTailCalled -- effectively sets to noOccInfo++lookupDetails :: UsageDetails -> Id -> OccInfo+lookupDetails ud id+ = case lookupVarEnv (ud_env ud) id of+ Just occ -> doZapping ud id occ+ Nothing -> IAmDead++usedIn :: Id -> UsageDetails -> Bool+v `usedIn` ud = isExportedId v || v `elemVarEnv` ud_env ud++udFreeVars :: VarSet -> UsageDetails -> VarSet+-- Find the subset of bndrs that are mentioned in uds+udFreeVars bndrs ud = restrictUniqSetToUFM bndrs (ud_env ud)++-------------------+-- Auxiliary functions for UsageDetails implementation++combineUsageDetailsWith :: (OccInfo -> OccInfo -> OccInfo)+ -> UsageDetails -> UsageDetails -> UsageDetails+combineUsageDetailsWith plus_occ_info ud1 ud2+ | isEmptyDetails ud1 = ud2+ | isEmptyDetails ud2 = ud1+ | otherwise+ = UD { ud_env = plusVarEnv_C plus_occ_info (ud_env ud1) (ud_env ud2)+ , ud_z_many = plusVarEnv (ud_z_many ud1) (ud_z_many ud2)+ , ud_z_in_lam = plusVarEnv (ud_z_in_lam ud1) (ud_z_in_lam ud2)+ , ud_z_no_tail = plusVarEnv (ud_z_no_tail ud1) (ud_z_no_tail ud2) }++doZapping :: UsageDetails -> Var -> OccInfo -> OccInfo+doZapping ud var occ+ = doZappingByUnique ud (varUnique var) occ++doZappingByUnique :: UsageDetails -> Unique -> OccInfo -> OccInfo+doZappingByUnique ud uniq+ = (if | in_subset ud_z_many -> markMany+ | in_subset ud_z_in_lam -> markInsideLam+ | otherwise -> id) .+ (if | in_subset ud_z_no_tail -> markNonTailCalled+ | otherwise -> id)+ where+ in_subset field = uniq `elemVarEnvByKey` field ud++alterZappedSets :: UsageDetails -> (ZappedSet -> ZappedSet) -> UsageDetails+alterZappedSets ud f+ = ud { ud_z_many = f (ud_z_many ud)+ , ud_z_in_lam = f (ud_z_in_lam ud)+ , ud_z_no_tail = f (ud_z_no_tail ud) }++alterUsageDetails :: UsageDetails -> (OccInfoEnv -> OccInfoEnv) -> UsageDetails+alterUsageDetails ud f+ = ud { ud_env = f (ud_env ud) }+ `alterZappedSets` f++flattenUsageDetails :: UsageDetails -> UsageDetails+flattenUsageDetails ud+ = ud { ud_env = mapUFM_Directly (doZappingByUnique ud) (ud_env ud) }+ `alterZappedSets` const emptyVarEnv++-------------------+-- See Note [Adjusting right-hand sides]+adjustRhsUsage :: Maybe JoinArity -> RecFlag+ -> [CoreBndr] -- Outer lambdas, AFTER occ anal+ -> UsageDetails -> UsageDetails+adjustRhsUsage mb_join_arity rec_flag bndrs usage+ = maybe_mark_lam (maybe_drop_tails usage)+ where+ maybe_mark_lam ud | one_shot = ud+ | otherwise = markAllInsideLam ud+ maybe_drop_tails ud | exact_join = ud+ | otherwise = markAllNonTailCalled ud++ one_shot = case mb_join_arity of+ Just join_arity+ | isRec rec_flag -> False+ | otherwise -> all isOneShotBndr (drop join_arity bndrs)+ Nothing -> all isOneShotBndr bndrs++ exact_join = case mb_join_arity of+ Just join_arity -> join_arity == length bndrs+ _ -> False++type IdWithOccInfo = Id++tagLamBinders :: UsageDetails -- Of scope+ -> [Id] -- Binders+ -> (UsageDetails, -- Details with binders removed+ [IdWithOccInfo]) -- Tagged binders+-- Used for lambda and case binders+-- It copes with the fact that lambda bindings can have a+-- stable unfolding, used for join points+tagLamBinders usage binders = usage' `seq` (usage', bndrs')+ where+ (usage', bndrs') = mapAccumR tag_lam usage binders+ tag_lam usage bndr = (usage2, bndr')+ where+ occ = lookupDetails usage bndr+ bndr' = setBinderOcc (markNonTailCalled occ) bndr+ -- Don't try to make an argument into a join point+ usage1 = usage `delDetails` bndr+ usage2 | isId bndr = addManyOccsSet usage1 (idUnfoldingVars bndr)+ -- This is effectively the RHS of a+ -- non-join-point binding, so it's okay to use+ -- addManyOccsSet, which assumes no tail calls+ | otherwise = usage1++tagNonRecBinder :: TopLevelFlag -- At top level?+ -> UsageDetails -- Of scope+ -> CoreBndr -- Binder+ -> (UsageDetails, -- Details with binder removed+ IdWithOccInfo) -- Tagged binder++tagNonRecBinder lvl usage binder+ = let+ occ = lookupDetails usage binder+ will_be_join = decideJoinPointHood lvl usage [binder]+ occ' | will_be_join = occ -- must already be marked AlwaysTailCalled+ | otherwise = markNonTailCalled occ+ binder' = setBinderOcc occ' binder+ usage' = usage `delDetails` binder+ in+ usage' `seq` (usage', binder')++tagRecBinders :: TopLevelFlag -- At top level?+ -> UsageDetails -- Of body of let ONLY+ -> [(CoreBndr, -- Binder+ UsageDetails, -- RHS usage details+ [CoreBndr])] -- Lambdas in new RHS+ -> (UsageDetails, -- Adjusted details for whole scope,+ -- with binders removed+ [IdWithOccInfo]) -- Tagged binders+-- Substantially more complicated than non-recursive case. Need to adjust RHS+-- details *before* tagging binders (because the tags depend on the RHSes).+tagRecBinders lvl body_uds triples+ = let+ (bndrs, rhs_udss, _) = unzip3 triples++ -- 1. Determine join-point-hood of whole group, as determined by+ -- the *unadjusted* usage details+ unadj_uds = body_uds +++ combineUsageDetailsList rhs_udss+ will_be_joins = decideJoinPointHood lvl unadj_uds bndrs++ -- 2. Adjust usage details of each RHS, taking into account the+ -- join-point-hood decision+ rhs_udss' = map adjust triples+ adjust (bndr, rhs_uds, rhs_bndrs)+ = adjustRhsUsage mb_join_arity Recursive rhs_bndrs rhs_uds+ where+ -- Can't use willBeJoinId_maybe here because we haven't tagged the+ -- binder yet (the tag depends on these adjustments!)+ mb_join_arity+ | will_be_joins+ , let occ = lookupDetails unadj_uds bndr+ , AlwaysTailCalled arity <- tailCallInfo occ+ = Just arity+ | otherwise+ = ASSERT(not will_be_joins) -- Should be AlwaysTailCalled if we're+ -- making join points!+ Nothing++ -- 3. Compute final usage details from adjusted RHS details+ adj_uds = body_uds +++ combineUsageDetailsList rhs_udss'++ -- 4. Tag each binder with its adjusted details modulo the+ -- join-point-hood decision+ occs = map (lookupDetails adj_uds) bndrs+ occs' | will_be_joins = occs+ | otherwise = map markNonTailCalled occs+ bndrs' = zipWith setBinderOcc occs' bndrs++ -- 5. Drop the binders from the adjusted details and return+ usage' = adj_uds `delDetailsList` bndrs+ in+ (usage', bndrs')++setBinderOcc :: OccInfo -> CoreBndr -> CoreBndr+setBinderOcc occ_info bndr+ | isTyVar bndr = bndr+ | isExportedId bndr = if isManyOccs (idOccInfo bndr)+ then bndr+ else setIdOccInfo bndr noOccInfo+ -- Don't use local usage info for visible-elsewhere things+ -- BUT *do* erase any IAmALoopBreaker annotation, because we're+ -- about to re-generate it and it shouldn't be "sticky"++ | otherwise = setIdOccInfo bndr occ_info++-- | Decide whether some bindings should be made into join points or not.+-- Returns `False` if they can't be join points. Note that it's an+-- all-or-nothing decision, as if multiple binders are given, they're assumed to+-- be mutually recursive.+--+-- See Note [Invariants for join points] in CoreSyn.+decideJoinPointHood :: TopLevelFlag -> UsageDetails+ -> [CoreBndr]+ -> Bool+decideJoinPointHood TopLevel _ _+ = False+decideJoinPointHood NotTopLevel usage bndrs+ | isJoinId (head bndrs)+ = WARN(not all_ok, text "OccurAnal failed to rediscover join point(s):" <+>+ ppr bndrs)+ all_ok+ | otherwise+ = all_ok+ where+ -- See Note [Invariants on join points]; invariants cited by number below.+ -- Invariant 2 is always satisfiable by the simplifier by eta expansion.+ all_ok = -- Invariant 3: Either all are join points or none are+ all ok bndrs++ ok bndr+ | -- Invariant 1: Only tail calls, all same join arity+ AlwaysTailCalled arity <- tailCallInfo (lookupDetails usage bndr)+ , -- Invariant 1 as applied to LHSes of rules+ all (ok_rule arity) (idCoreRules bndr)+ -- Invariant 4: Satisfies polymorphism rule+ , isValidJoinPointType arity (idType bndr)+ = True+ | otherwise+ = False++ ok_rule _ BuiltinRule{} = False -- only possible with plugin shenanigans+ ok_rule join_arity (Rule { ru_args = args })+ = length args == join_arity+ -- Invariant 1 as applied to LHSes of rules++willBeJoinId_maybe :: CoreBndr -> Maybe JoinArity+willBeJoinId_maybe bndr+ | AlwaysTailCalled arity <- tailCallInfo (idOccInfo bndr)+ = Just arity+ | otherwise+ = isJoinId_maybe bndr++{-+************************************************************************+* *+\subsection{Operations over OccInfo}+* *+************************************************************************+-}++markMany, markInsideLam, markNonTailCalled :: OccInfo -> OccInfo++markMany IAmDead = IAmDead+markMany occ = ManyOccs { occ_tail = occ_tail occ }++markInsideLam occ@(OneOcc {}) = occ { occ_in_lam = True }+markInsideLam occ = occ++markNonTailCalled IAmDead = IAmDead+markNonTailCalled occ = occ { occ_tail = NoTailCallInfo }++addOccInfo, orOccInfo :: OccInfo -> OccInfo -> OccInfo++addOccInfo a1 a2 = ASSERT( not (isDeadOcc a1 || isDeadOcc a2) )+ ManyOccs { occ_tail = tailCallInfo a1 `andTailCallInfo`+ tailCallInfo a2 }+ -- Both branches are at least One+ -- (Argument is never IAmDead)++-- (orOccInfo orig new) is used+-- when combining occurrence info from branches of a case++orOccInfo (OneOcc { occ_in_lam = in_lam1, occ_int_cxt = int_cxt1+ , occ_tail = tail1 })+ (OneOcc { occ_in_lam = in_lam2, occ_int_cxt = int_cxt2+ , occ_tail = tail2 })+ = OneOcc { occ_in_lam = in_lam1 || in_lam2+ , occ_one_br = False -- False, because it occurs in both branches+ , occ_int_cxt = int_cxt1 && int_cxt2+ , occ_tail = tail1 `andTailCallInfo` tail2 }+orOccInfo a1 a2 = ASSERT( not (isDeadOcc a1 || isDeadOcc a2) )+ ManyOccs { occ_tail = tailCallInfo a1 `andTailCallInfo`+ tailCallInfo a2 }++andTailCallInfo :: TailCallInfo -> TailCallInfo -> TailCallInfo+andTailCallInfo info@(AlwaysTailCalled arity1) (AlwaysTailCalled arity2)+ | arity1 == arity2 = info+andTailCallInfo _ _ = NoTailCallInfo
+ simplCore/SAT.hs view
@@ -0,0 +1,431 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++************************************************************************++ Static Argument Transformation pass++************************************************************************++May be seen as removing invariants from loops:+Arguments of recursive functions that do not change in recursive+calls are removed from the recursion, which is done locally+and only passes the arguments which effectively change.++Example:+map = /\ ab -> \f -> \xs -> case xs of+ [] -> []+ (a:b) -> f a : map f b++as map is recursively called with the same argument f (unmodified)+we transform it to++map = /\ ab -> \f -> \xs -> let map' ys = case ys of+ [] -> []+ (a:b) -> f a : map' b+ in map' xs++Notice that for a compiler that uses lambda lifting this is+useless as map' will be transformed back to what map was.++We could possibly do the same for big lambdas, but we don't as+they will eventually be removed in later stages of the compiler,+therefore there is no penalty in keeping them.++We only apply the SAT when the number of static args is > 2. This+produces few bad cases. See+ should_transform+in saTransform.++Here are the headline nofib results:+ Size Allocs Runtime+Min +0.0% -13.7% -21.4%+Max +0.1% +0.0% +5.4%+Geometric Mean +0.0% -0.2% -6.9%++The previous patch, to fix polymorphic floatout demand signatures, is+essential to make this work well!+-}++{-# LANGUAGE CPP #-}+module SAT ( doStaticArgs ) where++import Var+import CoreSyn+import CoreUtils+import Type+import Coercion+import Id+import Name+import VarEnv+import UniqSupply+import Util+import UniqFM+import VarSet+import Unique+import UniqSet+import Outputable++import Data.List+import FastString++#include "HsVersions.h"++doStaticArgs :: UniqSupply -> CoreProgram -> CoreProgram+doStaticArgs us binds = snd $ mapAccumL sat_bind_threaded_us us binds+ where+ sat_bind_threaded_us us bind =+ let (us1, us2) = splitUniqSupply us+ in (us1, fst $ runSAT us2 (satBind bind emptyUniqSet))++-- We don't bother to SAT recursive groups since it can lead+-- to massive code expansion: see Andre Santos' thesis for details.+-- This means we only apply the actual SAT to Rec groups of one element,+-- but we want to recurse into the others anyway to discover other binds+satBind :: CoreBind -> IdSet -> SatM (CoreBind, IdSATInfo)+satBind (NonRec binder expr) interesting_ids = do+ (expr', sat_info_expr, expr_app) <- satExpr expr interesting_ids+ return (NonRec binder expr', finalizeApp expr_app sat_info_expr)+satBind (Rec [(binder, rhs)]) interesting_ids = do+ let interesting_ids' = interesting_ids `addOneToUniqSet` binder+ (rhs_binders, rhs_body) = collectBinders rhs+ (rhs_body', sat_info_rhs_body) <- satTopLevelExpr rhs_body interesting_ids'+ let sat_info_rhs_from_args = unitVarEnv binder (bindersToSATInfo rhs_binders)+ sat_info_rhs' = mergeIdSATInfo sat_info_rhs_from_args sat_info_rhs_body++ shadowing = binder `elementOfUniqSet` interesting_ids+ sat_info_rhs'' = if shadowing+ then sat_info_rhs' `delFromUFM` binder -- For safety+ else sat_info_rhs'++ bind' <- saTransformMaybe binder (lookupUFM sat_info_rhs' binder)+ rhs_binders rhs_body'+ return (bind', sat_info_rhs'')+satBind (Rec pairs) interesting_ids = do+ let (binders, rhss) = unzip pairs+ rhss_SATed <- mapM (\e -> satTopLevelExpr e interesting_ids) rhss+ let (rhss', sat_info_rhss') = unzip rhss_SATed+ return (Rec (zipEqual "satBind" binders rhss'), mergeIdSATInfos sat_info_rhss')++data App = VarApp Id | TypeApp Type | CoApp Coercion+data Staticness a = Static a | NotStatic++type IdAppInfo = (Id, SATInfo)++type SATInfo = [Staticness App]+type IdSATInfo = IdEnv SATInfo+emptyIdSATInfo :: IdSATInfo+emptyIdSATInfo = emptyUFM++{-+pprIdSATInfo id_sat_info = vcat (map pprIdAndSATInfo (Map.toList id_sat_info))+ where pprIdAndSATInfo (v, sat_info) = hang (ppr v <> colon) 4 (pprSATInfo sat_info)+-}++pprSATInfo :: SATInfo -> SDoc+pprSATInfo staticness = hcat $ map pprStaticness staticness++pprStaticness :: Staticness App -> SDoc+pprStaticness (Static (VarApp _)) = text "SV"+pprStaticness (Static (TypeApp _)) = text "ST"+pprStaticness (Static (CoApp _)) = text "SC"+pprStaticness NotStatic = text "NS"+++mergeSATInfo :: SATInfo -> SATInfo -> SATInfo+mergeSATInfo l r = zipWith mergeSA l r+ where+ mergeSA NotStatic _ = NotStatic+ mergeSA _ NotStatic = NotStatic+ mergeSA (Static (VarApp v)) (Static (VarApp v'))+ | v == v' = Static (VarApp v)+ | otherwise = NotStatic+ mergeSA (Static (TypeApp t)) (Static (TypeApp t'))+ | t `eqType` t' = Static (TypeApp t)+ | otherwise = NotStatic+ mergeSA (Static (CoApp c)) (Static (CoApp c'))+ | c `eqCoercion` c' = Static (CoApp c)+ | otherwise = NotStatic+ mergeSA _ _ = pprPanic "mergeSATInfo" $+ text "Left:"+ <> pprSATInfo l <> text ", "+ <> text "Right:"+ <> pprSATInfo r++mergeIdSATInfo :: IdSATInfo -> IdSATInfo -> IdSATInfo+mergeIdSATInfo = plusUFM_C mergeSATInfo++mergeIdSATInfos :: [IdSATInfo] -> IdSATInfo+mergeIdSATInfos = foldl' mergeIdSATInfo emptyIdSATInfo++bindersToSATInfo :: [Id] -> SATInfo+bindersToSATInfo vs = map (Static . binderToApp) vs+ where binderToApp v | isId v = VarApp v+ | isTyVar v = TypeApp $ mkTyVarTy v+ | otherwise = CoApp $ mkCoVarCo v++finalizeApp :: Maybe IdAppInfo -> IdSATInfo -> IdSATInfo+finalizeApp Nothing id_sat_info = id_sat_info+finalizeApp (Just (v, sat_info')) id_sat_info =+ let sat_info'' = case lookupUFM id_sat_info v of+ Nothing -> sat_info'+ Just sat_info -> mergeSATInfo sat_info sat_info'+ in extendVarEnv id_sat_info v sat_info''++satTopLevelExpr :: CoreExpr -> IdSet -> SatM (CoreExpr, IdSATInfo)+satTopLevelExpr expr interesting_ids = do+ (expr', sat_info_expr, expr_app) <- satExpr expr interesting_ids+ return (expr', finalizeApp expr_app sat_info_expr)++satExpr :: CoreExpr -> IdSet -> SatM (CoreExpr, IdSATInfo, Maybe IdAppInfo)+satExpr var@(Var v) interesting_ids = do+ let app_info = if v `elementOfUniqSet` interesting_ids+ then Just (v, [])+ else Nothing+ return (var, emptyIdSATInfo, app_info)++satExpr lit@(Lit _) _ = do+ return (lit, emptyIdSATInfo, Nothing)++satExpr (Lam binders body) interesting_ids = do+ (body', sat_info, this_app) <- satExpr body interesting_ids+ return (Lam binders body', finalizeApp this_app sat_info, Nothing)++satExpr (App fn arg) interesting_ids = do+ (fn', sat_info_fn, fn_app) <- satExpr fn interesting_ids+ let satRemainder = boring fn' sat_info_fn+ case fn_app of+ Nothing -> satRemainder Nothing+ Just (fn_id, fn_app_info) ->+ -- TODO: remove this use of append somehow (use a data structure with O(1) append but a left-to-right kind of interface)+ let satRemainderWithStaticness arg_staticness = satRemainder $ Just (fn_id, fn_app_info ++ [arg_staticness])+ in case arg of+ Type t -> satRemainderWithStaticness $ Static (TypeApp t)+ Coercion c -> satRemainderWithStaticness $ Static (CoApp c)+ Var v -> satRemainderWithStaticness $ Static (VarApp v)+ _ -> satRemainderWithStaticness $ NotStatic+ where+ boring :: CoreExpr -> IdSATInfo -> Maybe IdAppInfo -> SatM (CoreExpr, IdSATInfo, Maybe IdAppInfo)+ boring fn' sat_info_fn app_info =+ do (arg', sat_info_arg, arg_app) <- satExpr arg interesting_ids+ let sat_info_arg' = finalizeApp arg_app sat_info_arg+ sat_info = mergeIdSATInfo sat_info_fn sat_info_arg'+ return (App fn' arg', sat_info, app_info)++satExpr (Case expr bndr ty alts) interesting_ids = do+ (expr', sat_info_expr, expr_app) <- satExpr expr interesting_ids+ let sat_info_expr' = finalizeApp expr_app sat_info_expr++ zipped_alts' <- mapM satAlt alts+ let (alts', sat_infos_alts) = unzip zipped_alts'+ return (Case expr' bndr ty alts', mergeIdSATInfo sat_info_expr' (mergeIdSATInfos sat_infos_alts), Nothing)+ where+ satAlt (con, bndrs, expr) = do+ (expr', sat_info_expr) <- satTopLevelExpr expr interesting_ids+ return ((con, bndrs, expr'), sat_info_expr)++satExpr (Let bind body) interesting_ids = do+ (body', sat_info_body, body_app) <- satExpr body interesting_ids+ (bind', sat_info_bind) <- satBind bind interesting_ids+ return (Let bind' body', mergeIdSATInfo sat_info_body sat_info_bind, body_app)++satExpr (Tick tickish expr) interesting_ids = do+ (expr', sat_info_expr, expr_app) <- satExpr expr interesting_ids+ return (Tick tickish expr', sat_info_expr, expr_app)++satExpr ty@(Type _) _ = do+ return (ty, emptyIdSATInfo, Nothing)++satExpr co@(Coercion _) _ = do+ return (co, emptyIdSATInfo, Nothing)++satExpr (Cast expr coercion) interesting_ids = do+ (expr', sat_info_expr, expr_app) <- satExpr expr interesting_ids+ return (Cast expr' coercion, sat_info_expr, expr_app)++{-+************************************************************************++ Static Argument Transformation Monad++************************************************************************+-}++type SatM result = UniqSM result++runSAT :: UniqSupply -> SatM a -> a+runSAT = initUs_++newUnique :: SatM Unique+newUnique = getUniqueM++{-+************************************************************************++ Static Argument Transformation Monad++************************************************************************++To do the transformation, the game plan is to:++1. Create a small nonrecursive RHS that takes the+ original arguments to the function but discards+ the ones that are static and makes a call to the+ SATed version with the remainder. We intend that+ this will be inlined later, removing the overhead++2. Bind this nonrecursive RHS over the original body+ WITH THE SAME UNIQUE as the original body so that+ any recursive calls to the original now go via+ the small wrapper++3. Rebind the original function to a new one which contains+ our SATed function and just makes a call to it:+ we call the thing making this call the local body++Example: transform this++ map :: forall a b. (a->b) -> [a] -> [b]+ map = /\ab. \(f:a->b) (as:[a]) -> body[map]+to+ map :: forall a b. (a->b) -> [a] -> [b]+ map = /\ab. \(f:a->b) (as:[a]) ->+ letrec map' :: [a] -> [b]+ -- The "worker function+ map' = \(as:[a]) ->+ let map :: forall a' b'. (a -> b) -> [a] -> [b]+ -- The "shadow function+ map = /\a'b'. \(f':(a->b) (as:[a]).+ map' as+ in body[map]+ in map' as++Note [Shadow binding]+~~~~~~~~~~~~~~~~~~~~~+The calls to the inner map inside body[map] should get inlined+by the local re-binding of 'map'. We call this the "shadow binding".++But we can't use the original binder 'map' unchanged, because+it might be exported, in which case the shadow binding won't be+discarded as dead code after it is inlined.++So we use a hack: we make a new SysLocal binder with the *same* unique+as binder. (Another alternative would be to reset the export flag.)++Note [Binder type capture]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Notice that in the inner map (the "shadow function"), the static arguments+are discarded -- it's as if they were underscores. Instead, mentions+of these arguments (notably in the types of dynamic arguments) are bound+by the *outer* lambdas of the main function. So we must make up fresh+names for the static arguments so that they do not capture variables+mentioned in the types of dynamic args.++In the map example, the shadow function must clone the static type+argument a,b, giving a',b', to ensure that in the \(as:[a]), the 'a'+is bound by the outer forall. We clone f' too for consistency, but+that doesn't matter either way because static Id arguments aren't+mentioned in the shadow binding at all.++If we don't we get something like this:++[Exported]+[Arity 3]+GHC.Base.until =+ \ (@ a_aiK)+ (p_a6T :: a_aiK -> GHC.Types.Bool)+ (f_a6V :: a_aiK -> a_aiK)+ (x_a6X :: a_aiK) ->+ letrec {+ sat_worker_s1aU :: a_aiK -> a_aiK+ []+ sat_worker_s1aU =+ \ (x_a6X :: a_aiK) ->+ let {+ sat_shadow_r17 :: forall a_a3O.+ (a_a3O -> GHC.Types.Bool) -> (a_a3O -> a_a3O) -> a_a3O -> a_a3O+ []+ sat_shadow_r17 =+ \ (@ a_aiK)+ (p_a6T :: a_aiK -> GHC.Types.Bool)+ (f_a6V :: a_aiK -> a_aiK)+ (x_a6X :: a_aiK) ->+ sat_worker_s1aU x_a6X } in+ case p_a6T x_a6X of wild_X3y [ALWAYS Dead Nothing] {+ GHC.Types.False -> GHC.Base.until @ a_aiK p_a6T f_a6V (f_a6V x_a6X);+ GHC.Types.True -> x_a6X+ }; } in+ sat_worker_s1aU x_a6X++Where sat_shadow has captured the type variables of x_a6X etc as it has a a_aiK+type argument. This is bad because it means the application sat_worker_s1aU x_a6X+is not well typed.+-}++saTransformMaybe :: Id -> Maybe SATInfo -> [Id] -> CoreExpr -> SatM CoreBind+saTransformMaybe binder maybe_arg_staticness rhs_binders rhs_body+ | Just arg_staticness <- maybe_arg_staticness+ , should_transform arg_staticness+ = saTransform binder arg_staticness rhs_binders rhs_body+ | otherwise+ = return (Rec [(binder, mkLams rhs_binders rhs_body)])+ where+ should_transform staticness = n_static_args > 1 -- THIS IS THE DECISION POINT+ where+ n_static_args = count isStaticValue staticness++saTransform :: Id -> SATInfo -> [Id] -> CoreExpr -> SatM CoreBind+saTransform binder arg_staticness rhs_binders rhs_body+ = do { shadow_lam_bndrs <- mapM clone binders_w_staticness+ ; uniq <- newUnique+ ; return (NonRec binder (mk_new_rhs uniq shadow_lam_bndrs)) }+ where+ -- Running example: foldr+ -- foldr \alpha \beta c n xs = e, for some e+ -- arg_staticness = [Static TypeApp, Static TypeApp, Static VarApp, Static VarApp, NonStatic]+ -- rhs_binders = [\alpha, \beta, c, n, xs]+ -- rhs_body = e++ binders_w_staticness = rhs_binders `zip` (arg_staticness ++ repeat NotStatic)+ -- Any extra args are assumed NotStatic++ non_static_args :: [Var]+ -- non_static_args = [xs]+ -- rhs_binders_without_type_capture = [\alpha', \beta', c, n, xs]+ non_static_args = [v | (v, NotStatic) <- binders_w_staticness]++ clone (bndr, NotStatic) = return bndr+ clone (bndr, _ ) = do { uniq <- newUnique+ ; return (setVarUnique bndr uniq) }++ -- new_rhs = \alpha beta c n xs ->+ -- let sat_worker = \xs -> let sat_shadow = \alpha' beta' c n xs ->+ -- sat_worker xs+ -- in e+ -- in sat_worker xs+ mk_new_rhs uniq shadow_lam_bndrs+ = mkLams rhs_binders $+ Let (Rec [(rec_body_bndr, rec_body)])+ local_body+ where+ local_body = mkVarApps (Var rec_body_bndr) non_static_args++ rec_body = mkLams non_static_args $+ Let (NonRec shadow_bndr shadow_rhs) rhs_body++ -- See Note [Binder type capture]+ shadow_rhs = mkLams shadow_lam_bndrs local_body+ -- nonrec_rhs = \alpha' beta' c n xs -> sat_worker xs++ rec_body_bndr = mkSysLocal (fsLit "sat_worker") uniq (exprType rec_body)+ -- rec_body_bndr = sat_worker++ -- See Note [Shadow binding]; make a SysLocal+ shadow_bndr = mkSysLocal (occNameFS (getOccName binder))+ (idUnique binder)+ (exprType shadow_rhs)++isStaticValue :: Staticness App -> Bool+isStaticValue (Static (VarApp _)) = True+isStaticValue _ = False
+ simplCore/SetLevels.hs view
@@ -0,0 +1,1643 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section{SetLevels}++ ***************************+ Overview+ ***************************++1. We attach binding levels to Core bindings, in preparation for floating+ outwards (@FloatOut@).++2. We also let-ify many expressions (notably case scrutinees), so they+ will have a fighting chance of being floated sensible.++3. Note [Need for cloning during float-out]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ We clone the binders of any floatable let-binding, so that when it is+ floated out it will be unique. Example+ (let x=2 in x) + (let x=3 in x)+ we must clone before floating so we get+ let x1=2 in+ let x2=3 in+ x1+x2++ NOTE: this can't be done using the uniqAway idea, because the variable+ must be unique in the whole program, not just its current scope,+ because two variables in different scopes may float out to the+ same top level place++ NOTE: Very tiresomely, we must apply this substitution to+ the rules stored inside a variable too.++ We do *not* clone top-level bindings, because some of them must not change,+ but we *do* clone bindings that are heading for the top level++4. Note [Binder-swap during float-out]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ In the expression+ case x of wild { p -> ...wild... }+ we substitute x for wild in the RHS of the case alternatives:+ case x of wild { p -> ...x... }+ This means that a sub-expression involving x is not "trapped" inside the RHS.+ And it's not inconvenient because we already have a substitution.++ Note that this is EXACTLY BACKWARDS from the what the simplifier does.+ The simplifier tries to get rid of occurrences of x, in favour of wild,+ in the hope that there will only be one remaining occurrence of x, namely+ the scrutinee of the case, and we can inline it.+-}++{-# LANGUAGE CPP, MultiWayIf #-}+module SetLevels (+ setLevels,++ Level(..), LevelType(..), tOP_LEVEL, isJoinCeilLvl, asJoinCeilLvl,+ LevelledBind, LevelledExpr, LevelledBndr,+ FloatSpec(..), floatSpecLevel,++ incMinorLvl, ltMajLvl, ltLvl, isTopLvl+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreMonad ( FloatOutSwitches(..) )+import CoreUtils ( exprType, exprIsHNF+ , exprOkForSpeculation+ , exprIsTopLevelBindable+ , isExprLevPoly+ , collectMakeStaticArgs+ )+import CoreArity ( exprBotStrictness_maybe )+import CoreFVs -- all of it+import CoreSubst+import MkCore ( sortQuantVars )++import Id+import IdInfo+import Var+import VarSet+import VarEnv+import Literal ( litIsTrivial )+import Demand ( StrictSig, isStrictDmd, splitStrictSig, increaseStrictSigArity )+import Name ( getOccName, mkSystemVarName )+import OccName ( occNameString )+import Type ( isUnliftedType, Type, mkLamTypes, splitTyConApp_maybe )+import BasicTypes ( Arity, RecFlag(..), isRec )+import DataCon ( dataConOrigResTy )+import TysWiredIn+import UniqSupply+import Util+import Outputable+import FastString+import UniqDFM+import FV+import Data.Maybe+import Control.Monad ( zipWithM )++{-+************************************************************************+* *+\subsection{Level numbers}+* *+************************************************************************+-}++type LevelledExpr = TaggedExpr FloatSpec+type LevelledBind = TaggedBind FloatSpec+type LevelledBndr = TaggedBndr FloatSpec++data Level = Level Int -- Level number of enclosing lambdas+ Int -- Number of big-lambda and/or case expressions and/or+ -- context boundaries between+ -- here and the nearest enclosing lambda+ LevelType -- Binder or join ceiling?+data LevelType = BndrLvl | JoinCeilLvl deriving (Eq)++data FloatSpec+ = FloatMe Level -- Float to just inside the binding+ -- tagged with this level+ | StayPut Level -- Stay where it is; binding is+ -- tagged with tihs level++floatSpecLevel :: FloatSpec -> Level+floatSpecLevel (FloatMe l) = l+floatSpecLevel (StayPut l) = l++{-+The {\em level number} on a (type-)lambda-bound variable is the+nesting depth of the (type-)lambda which binds it. The outermost lambda+has level 1, so (Level 0 0) means that the variable is bound outside any lambda.++On an expression, it's the maximum level number of its free+(type-)variables. On a let(rec)-bound variable, it's the level of its+RHS. On a case-bound variable, it's the number of enclosing lambdas.++Top-level variables: level~0. Those bound on the RHS of a top-level+definition but ``before'' a lambda; e.g., the \tr{x} in (levels shown+as ``subscripts'')...+\begin{verbatim}+a_0 = let b_? = ... in+ x_1 = ... b ... in ...+\end{verbatim}++The main function @lvlExpr@ carries a ``context level'' (@le_ctxt_lvl@).+That's meant to be the level number of the enclosing binder in the+final (floated) program. If the level number of a sub-expression is+less than that of the context, then it might be worth let-binding the+sub-expression so that it will indeed float.++If you can float to level @Level 0 0@ worth doing so because then your+allocation becomes static instead of dynamic. We always start with+context @Level 0 0@.+++Note [FloatOut inside INLINE]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+@InlineCtxt@ very similar to @Level 0 0@, but is used for one purpose:+to say "don't float anything out of here". That's exactly what we+want for the body of an INLINE, where we don't want to float anything+out at all. See notes with lvlMFE below.++But, check this out:++-- At one time I tried the effect of not float anything out of an InlineMe,+-- but it sometimes works badly. For example, consider PrelArr.done. It+-- has the form __inline (\d. e)+-- where e doesn't mention d. If we float this to+-- __inline (let x = e in \d. x)+-- things are bad. The inliner doesn't even inline it because it doesn't look+-- like a head-normal form. So it seems a lesser evil to let things float.+-- In SetLevels we do set the context to (Level 0 0) when we get to an InlineMe+-- which discourages floating out.++So the conclusion is: don't do any floating at all inside an InlineMe.+(In the above example, don't float the {x=e} out of the \d.)++One particular case is that of workers: we don't want to float the+call to the worker outside the wrapper, otherwise the worker might get+inlined into the floated expression, and an importing module won't see+the worker at all.++Note [Join ceiling]+~~~~~~~~~~~~~~~~~~~+Join points can't float very far; too far, and they can't remain join points+So, suppose we have:++ f x = (joinrec j y = ... x ... in jump j x) + 1++One may be tempted to float j out to the top of f's RHS, but then the jump+would not be a tail call. Thus we keep track of a level called the *join+ceiling* past which join points are not allowed to float.++The troublesome thing is that, unlike most levels to which something might+float, there is not necessarily an identifier to which the join ceiling is+attached. Fortunately, if something is to be floated to a join ceiling, it must+be dropped at the *nearest* join ceiling. Thus each level is marked as to+whether it is a join ceiling, so that FloatOut can tell which binders are being+floated to the nearest join ceiling and which to a particular binder (or set of+binders).+-}++instance Outputable FloatSpec where+ ppr (FloatMe l) = char 'F' <> ppr l+ ppr (StayPut l) = ppr l++tOP_LEVEL :: Level+tOP_LEVEL = Level 0 0 BndrLvl++incMajorLvl :: Level -> Level+incMajorLvl (Level major _ _) = Level (major + 1) 0 BndrLvl++incMinorLvl :: Level -> Level+incMinorLvl (Level major minor _) = Level major (minor+1) BndrLvl++asJoinCeilLvl :: Level -> Level+asJoinCeilLvl (Level major minor _) = Level major minor JoinCeilLvl++maxLvl :: Level -> Level -> Level+maxLvl l1@(Level maj1 min1 _) l2@(Level maj2 min2 _)+ | (maj1 > maj2) || (maj1 == maj2 && min1 > min2) = l1+ | otherwise = l2++ltLvl :: Level -> Level -> Bool+ltLvl (Level maj1 min1 _) (Level maj2 min2 _)+ = (maj1 < maj2) || (maj1 == maj2 && min1 < min2)++ltMajLvl :: Level -> Level -> Bool+ -- Tells if one level belongs to a difft *lambda* level to another+ltMajLvl (Level maj1 _ _) (Level maj2 _ _) = maj1 < maj2++isTopLvl :: Level -> Bool+isTopLvl (Level 0 0 _) = True+isTopLvl _ = False++isJoinCeilLvl :: Level -> Bool+isJoinCeilLvl (Level _ _ t) = t == JoinCeilLvl++instance Outputable Level where+ ppr (Level maj min typ)+ = hcat [ char '<', int maj, char ',', int min, char '>'+ , ppWhen (typ == JoinCeilLvl) (char 'C') ]++instance Eq Level where+ (Level maj1 min1 _) == (Level maj2 min2 _) = maj1 == maj2 && min1 == min2++{-+************************************************************************+* *+\subsection{Main level-setting code}+* *+************************************************************************+-}++setLevels :: FloatOutSwitches+ -> CoreProgram+ -> UniqSupply+ -> [LevelledBind]++setLevels float_lams binds us+ = initLvl us (do_them init_env binds)+ where+ init_env = initialEnv float_lams++ 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+ ; return (lvld_bind : lvld_binds) }++lvlTopBind :: LevelEnv -> Bind Id -> LvlM (LevelledBind, LevelEnv)+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') }++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') }++lvl_top :: LevelEnv -> RecFlag -> Id -> CoreExpr -> LvlM LevelledExpr+lvl_top env is_rec bndr rhs+ = lvlRhs env is_rec+ (isBottomingId bndr)+ Nothing -- Not a join point+ (freeVars rhs)++{-+************************************************************************+* *+\subsection{Setting expression levels}+* *+************************************************************************++Note [Floating over-saturated applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we see (f x y), and (f x) is a redex (ie f's arity is 1),+we call (f x) an "over-saturated application"++Should we float out an over-sat app, if can escape a value lambda?+It is sometimes very beneficial (-7% runtime -4% alloc over nofib -O2).+But we don't want to do it for class selectors, because the work saved+is minimal, and the extra local thunks allocated cost money.++Arguably we could float even class-op applications if they were going to+top level -- but then they must be applied to a constant dictionary and+will almost certainly be optimised away anyway.+-}++lvlExpr :: LevelEnv -- Context+ -> CoreExprWithFVs -- Input expression+ -> LvlM LevelledExpr -- Result expression++{-+The @le_ctxt_lvl@ is, roughly, the level of the innermost enclosing+binder. Here's an example++ v = \x -> ...\y -> let r = case (..x..) of+ ..x..+ in ..++When looking at the rhs of @r@, @le_ctxt_lvl@ will be 1 because that's+the level of @r@, even though it's inside a level-2 @\y@. It's+important that @le_ctxt_lvl@ is 1 and not 2 in @r@'s rhs, because we+don't want @lvlExpr@ to turn the scrutinee of the @case@ into an MFE+--- because it isn't a *maximal* free expression.++If there were another lambda in @r@'s rhs, it would get level-2 as well.+-}++lvlExpr env (_, AnnType ty) = return (Type (CoreSubst.substTy (le_subst env) ty))+lvlExpr env (_, AnnCoercion co) = return (Coercion (substCo (le_subst env) co))+lvlExpr env (_, AnnVar v) = return (lookupVar env v)+lvlExpr _ (_, AnnLit lit) = return (Lit lit)++lvlExpr env (_, AnnCast expr (_, co)) = do+ expr' <- lvlNonTailExpr env expr+ return (Cast expr' (substCo (le_subst env) co))++lvlExpr env (_, AnnTick tickish expr) = do+ expr' <- lvlNonTailExpr env expr+ let tickish' = substTickish (le_subst env) tickish+ return (Tick tickish' expr')++lvlExpr env expr@(_, AnnApp _ _) = lvlApp env expr (collectAnnArgs expr)++-- We don't split adjacent lambdas. That is, given+-- \x y -> (x+1,y)+-- we don't float to give+-- \x -> let v = x+1 in \y -> (v,y)+-- Why not? Because partial applications are fairly rare, and splitting+-- lambdas makes them more expensive.++lvlExpr env expr@(_, AnnLam {})+ = do { new_body <- lvlNonTailMFE new_env True body+ ; return (mkLams new_bndrs new_body) }+ where+ (bndrs, body) = collectAnnBndrs expr+ (env1, bndrs1) = substBndrsSL NonRecursive env bndrs+ (new_env, new_bndrs) = lvlLamBndrs env1 (le_ctxt_lvl env) bndrs1+ -- At one time we called a special verion of collectBinders,+ -- which ignored coercions, because we don't want to split+ -- a lambda like this (\x -> coerce t (\s -> ...))+ -- This used to happen quite a bit in state-transformer programs,+ -- but not nearly so much now non-recursive newtypes are transparent.+ -- [See SetLevels rev 1.50 for a version with this approach.]++lvlExpr env (_, AnnLet bind body)+ = do { (bind', new_env) <- lvlBind env bind+ ; body' <- lvlExpr new_env body+ -- No point in going via lvlMFE here. If the binding is alive+ -- (mentioned in body), and the whole let-expression doesn't+ -- float, then neither will the body+ ; return (Let bind' body') }++lvlExpr env (_, AnnCase scrut case_bndr ty alts)+ = do { scrut' <- lvlNonTailMFE env True scrut+ ; lvlCase env (freeVarsOf scrut) scrut' case_bndr ty alts }++lvlNonTailExpr :: LevelEnv -- Context+ -> CoreExprWithFVs -- Input expression+ -> LvlM LevelledExpr -- Result expression+lvlNonTailExpr env expr+ = lvlExpr (placeJoinCeiling env) expr++-------------------------------------------+lvlApp :: LevelEnv+ -> CoreExprWithFVs+ -> (CoreExprWithFVs, [CoreExprWithFVs]) -- Input application+ -> LvlM LevelledExpr -- Result expression+lvlApp env orig_expr ((_,AnnVar fn), args)+ | floatOverSat env -- See Note [Floating over-saturated applications]+ , arity > 0+ , arity < n_val_args+ , Nothing <- isClassOpId_maybe fn+ = do { rargs' <- mapM (lvlNonTailMFE env False) rargs+ ; lapp' <- lvlNonTailMFE env False lapp+ ; return (foldl App lapp' rargs') }++ | otherwise+ = do { args' <- zipWithM (lvlMFE env) stricts args+ -- Take account of argument strictness; see+ -- Note [Floating to the top]+ ; return (foldl App (lookupVar env fn) args') }+ where+ n_val_args = count (isValArg . deAnnotate) args+ arity = idArity fn++ stricts :: [Bool] -- True for strict argument+ stricts = case splitStrictSig (idStrictness fn) of+ (arg_ds, _) | not (arg_ds `lengthExceeds` n_val_args)+ -> map isStrictDmd arg_ds ++ repeat False+ | otherwise+ -> repeat False++ -- Separate out the PAP that we are floating from the extra+ -- arguments, by traversing the spine until we have collected+ -- (n_val_args - arity) value arguments.+ (lapp, rargs) = left (n_val_args - arity) orig_expr []++ left 0 e rargs = (e, rargs)+ left n (_, AnnApp f a) rargs+ | isValArg (deAnnotate a) = left (n-1) f (a:rargs)+ | otherwise = left n f (a:rargs)+ left _ _ _ = panic "SetLevels.lvlExpr.left"++lvlApp env _ (fun, args)+ = -- No PAPs that we can float: just carry on with the+ -- arguments and the function.+ do { args' <- mapM (lvlNonTailMFE env False) args+ ; fun' <- lvlNonTailExpr env fun+ ; return (foldl App fun' args') }++-------------------------------------------+lvlCase :: LevelEnv -- Level of in-scope names/tyvars+ -> DVarSet -- Free vars of input scrutinee+ -> LevelledExpr -- Processed scrutinee+ -> Id -> Type -- Case binder and result type+ -> [CoreAltWithFVs] -- Input alternatives+ -> LvlM LevelledExpr -- Result expression+lvlCase env scrut_fvs scrut' case_bndr ty alts+ | [(con@(DataAlt {}), bs, body)] <- alts+ , exprOkForSpeculation scrut' -- See Note [Check the output scrutinee for okForSpec]+ , not (isTopLvl dest_lvl) -- Can't have top-level cases+ , not (floatTopLvlOnly env) -- Can float anywhere+ = -- See Note [Floating cases]+ -- Always float the case if possible+ -- Unlike lets we don't insist that it escapes a value lambda+ do { (env1, (case_bndr' : bs')) <- cloneCaseBndrs env dest_lvl (case_bndr : bs)+ ; let rhs_env = extendCaseBndrEnv env1 case_bndr scrut'+ ; body' <- lvlMFE rhs_env True body+ ; let alt' = (con, map (stayPut dest_lvl) bs', body')+ ; return (Case scrut' (TB case_bndr' (FloatMe dest_lvl)) ty' [alt']) }++ | otherwise -- Stays put+ = do { let (alts_env1, [case_bndr']) = substAndLvlBndrs NonRecursive env incd_lvl [case_bndr]+ alts_env = extendCaseBndrEnv alts_env1 case_bndr scrut'+ ; alts' <- mapM (lvl_alt alts_env) alts+ ; return (Case scrut' case_bndr' ty' alts') }+ where+ ty' = substTy (le_subst env) ty++ incd_lvl = incMinorLvl (le_ctxt_lvl env)+ dest_lvl = maxFvLevel (const True) env scrut_fvs+ -- Don't abstract over type variables, hence const True++ lvl_alt alts_env (con, bs, rhs)+ = do { rhs' <- lvlMFE new_env True rhs+ ; return (con, bs', rhs') }+ where+ (new_env, bs') = substAndLvlBndrs NonRecursive alts_env incd_lvl bs++{-+Note [Floating cases]+~~~~~~~~~~~~~~~~~~~~~+Consider this:+ data T a = MkT !a+ f :: T Int -> blah+ f x vs = case x of { MkT y ->+ let f vs = ...(case y of I# w -> e)...f..+ in f vs+Here we can float the (case y ...) out, because y is sure+to be evaluated, to give+ f x vs = case x of { MkT y ->+ caes y of I# w ->+ let f vs = ...(e)...f..+ in f vs++That saves unboxing it every time round the loop. It's important in+some DPH stuff where we really want to avoid that repeated unboxing in+the inner loop.++Things to note+ * We can't float a case to top level+ * It's worth doing this float even if we don't float+ the case outside a value lambda. Example+ case x of {+ MkT y -> (case y of I# w2 -> ..., case y of I# w2 -> ...)+ If we floated the cases out we could eliminate one of them.+ * We only do this with a single-alternative case++Note [Check the output scrutinee for okForSpec]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:+ case x of y {+ A -> ....(case y of alts)....+ }+Because of the binder-swap, the inner case will get substituted to+(case x of ..). So when testing whether the scrutinee is+okForSpeculation we must be careful to test the *result* scrutinee ('x'+in this case), not the *input* one 'y'. The latter *is* ok for+speculation here, but the former is not -- and indeed we can't float+the inner case out, at least not unless x is also evaluated at its+binding site.++That's why we apply exprOkForSpeculation to scrut' and not to scrut.+-}++lvlNonTailMFE :: LevelEnv -- Level of in-scope names/tyvars+ -> Bool -- True <=> strict context [body of case+ -- or let]+ -> CoreExprWithFVs -- input expression+ -> LvlM LevelledExpr -- Result expression+lvlNonTailMFE env strict_ctxt ann_expr+ = lvlMFE (placeJoinCeiling env) strict_ctxt ann_expr++lvlMFE :: LevelEnv -- Level of in-scope names/tyvars+ -> Bool -- True <=> strict context [body of case or let]+ -> CoreExprWithFVs -- input expression+ -> LvlM LevelledExpr -- Result expression+-- lvlMFE is just like lvlExpr, except that it might let-bind+-- the expression, so that it can itself be floated.++lvlMFE env _ (_, AnnType ty)+ = return (Type (CoreSubst.substTy (le_subst env) ty))++-- No point in floating out an expression wrapped in a coercion or note+-- If we do we'll transform lvl = e |> co+-- to lvl' = e; lvl = lvl' |> co+-- and then inline lvl. Better just to float out the payload.+lvlMFE env strict_ctxt (_, AnnTick t e)+ = do { e' <- lvlMFE env strict_ctxt e+ ; return (Tick t e') }++lvlMFE env strict_ctxt (_, AnnCast e (_, co))+ = do { e' <- lvlMFE env strict_ctxt e+ ; return (Cast e' (substCo (le_subst env) co)) }++lvlMFE env strict_ctxt e@(_, AnnCase {})+ | strict_ctxt -- Don't share cases in a strict context+ = lvlExpr env e -- See Note [Case MFEs]++lvlMFE env strict_ctxt ann_expr+ | floatTopLvlOnly env && not (isTopLvl dest_lvl)+ -- Only floating to the top level is allowed.+ || anyDVarSet isJoinId fvs -- If there is a free join, don't float+ -- See Note [Free join points]+ || isExprLevPoly expr+ -- We can't let-bind levity polymorphic expressions+ -- See Note [Levity polymorphism invariants] in CoreSyn+ || notWorthFloating expr abs_vars+ || not float_me+ = -- Don't float it out+ lvlExpr env ann_expr++ | float_is_new_lam || exprIsTopLevelBindable expr expr_ty+ -- No wrapping needed if the type is lifted, or is a literal string+ -- or if we are wrapping it in one or more value lambdas+ = do { expr1 <- lvlFloatRhs abs_vars dest_lvl rhs_env NonRecursive+ (isJust mb_bot_str)+ join_arity_maybe+ ann_expr+ -- Treat the expr just like a right-hand side+ ; var <- newLvlVar expr1 join_arity_maybe is_mk_static+ ; let var2 = annotateBotStr var float_n_lams mb_bot_str+ ; return (Let (NonRec (TB var2 (FloatMe dest_lvl)) expr1)+ (mkVarApps (Var var2) abs_vars)) }++ -- OK, so the float has an unlifted type (not top-level bindable)+ -- and no new value lambdas (float_is_new_lam is False)+ -- Try for the boxing strategy+ -- See Note [Floating MFEs of unlifted type]+ | escapes_value_lam+ , not expr_ok_for_spec -- Boxing/unboxing isn't worth it for cheap expressions+ -- See Note [Test cheapness with exprOkForSpeculation]+ , Just (tc, _) <- splitTyConApp_maybe expr_ty+ , Just dc <- boxingDataCon_maybe tc+ , let dc_res_ty = dataConOrigResTy dc -- No free type variables+ [bx_bndr, ubx_bndr] = mkTemplateLocals [dc_res_ty, expr_ty]+ = do { expr1 <- lvlExpr rhs_env ann_expr+ ; let l1r = incMinorLvlFrom rhs_env+ float_rhs = mkLams abs_vars_w_lvls $+ Case expr1 (stayPut l1r ubx_bndr) dc_res_ty+ [(DEFAULT, [], mkConApp dc [Var ubx_bndr])]++ ; var <- newLvlVar float_rhs Nothing is_mk_static+ ; let l1u = incMinorLvlFrom env+ use_expr = Case (mkVarApps (Var var) abs_vars)+ (stayPut l1u bx_bndr) expr_ty+ [(DataAlt dc, [stayPut l1u ubx_bndr], Var ubx_bndr)]+ ; return (Let (NonRec (TB var (FloatMe dest_lvl)) float_rhs)+ use_expr) }++ | otherwise -- e.g. do not float unboxed tuples+ = lvlExpr env ann_expr++ where+ expr = deAnnotate ann_expr+ expr_ty = exprType expr+ fvs = freeVarsOf ann_expr+ is_bot = isBottomThunk mb_bot_str+ is_function = isFunction ann_expr+ mb_bot_str = exprBotStrictness_maybe expr+ -- See Note [Bottoming floats]+ -- esp Bottoming floats (2)+ expr_ok_for_spec = exprOkForSpeculation expr+ dest_lvl = destLevel env fvs is_function is_bot False+ abs_vars = abstractVars dest_lvl env fvs++ -- float_is_new_lam: the floated thing will be a new value lambda+ -- replacing, say (g (x+4)) by (lvl x). No work is saved, nor is+ -- allocation saved. The benefit is to get it to the top level+ -- and hence out of the body of this function altogether, making+ -- it smaller and more inlinable+ float_is_new_lam = float_n_lams > 0+ float_n_lams = count isId abs_vars++ (rhs_env, abs_vars_w_lvls) = lvlLamBndrs env dest_lvl abs_vars++ join_arity_maybe = Nothing++ is_mk_static = isJust (collectMakeStaticArgs expr)+ -- Yuk: See Note [Grand plan for static forms] in main/StaticPtrTable++ -- A decision to float entails let-binding this thing, and we only do+ -- that if we'll escape a value lambda, or will go to the top level.+ float_me = saves_work || saves_alloc || is_mk_static++ -- We can save work if we can move a redex outside a value lambda+ -- But if float_is_new_lam is True, then the redex is wrapped in a+ -- a new lambda, so no work is saved+ saves_work = escapes_value_lam && not float_is_new_lam++ escapes_value_lam = dest_lvl `ltMajLvl` (le_ctxt_lvl env)+ -- See Note [Escaping a value lambda]++ -- See Note [Floating to the top]+ saves_alloc = isTopLvl dest_lvl+ && floatConsts env+ && (not strict_ctxt || is_bot || exprIsHNF expr)++isBottomThunk :: Maybe (Arity, s) -> Bool+-- See Note [Bottoming floats] (2)+isBottomThunk (Just (0, _)) = True -- Zero arity+isBottomThunk _ = False++{- Note [Floating to the top]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We are keen to float something to the top level, even if it does not+escape a value lambda (and hence save work), for two reasons:++ * Doing so makes the function smaller, by floating out+ bottoming expressions, or integer or string literals. That in+ turn makes it easier to inline, with less duplication.++ * (Minor) Doing so may turn a dynamic allocation (done by machine+ instructions) into a static one. Minor because we are assuming+ we are not escaping a value lambda.++But do not so if:+ - the context is a strict, and+ - the expression is not a HNF, and+ - the expression is not bottoming++Exammples:++* Bottoming+ f x = case x of+ 0 -> error <big thing>+ _ -> x+1+ Here we want to float (error <big thing>) to top level, abstracting+ over 'x', so as to make f's RHS smaller.++* HNF+ f = case y of+ True -> p:q+ False -> blah+ We may as well float the (p:q) so it becomes a static data structure.++* Case scrutinee+ f = case g True of ....+ Don't float (g True) to top level; then we have the admin of a+ top-level thunk to worry about, with zero gain.++* Case alternative+ h = case y of+ True -> g True+ False -> False+ Don't float (g True) to the top level++* Arguments+ t = f (g True)+ If f is lazy, we /do/ float (g True) because then we can allocate+ the thunk statically rather than dynamically. But if f is strict+ we don't (see the use of idStrictness in lvlApp). It's not clear+ if this test is worth the bother: it's only about CAFs!++It's controlled by a flag (floatConsts), because doing this too+early loses opportunities for RULES which (needless to say) are+important in some nofib programs (gcd is an example). [SPJ note:+I think this is obselete; the flag seems always on.]++Note [Floating join point bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Mostly we only float a join point if it can /stay/ a join point. But+there is one exception: if it can go to the top level (Trac #13286).+Consider+ f x = joinrec j y n = <...j y' n'...>+ in jump j x 0++Here we may just as well produce+ j y n = <....j y' n'...>+ f x = j x 0++and now there is a chance that 'f' will be inlined at its call sites.+It shouldn't make a lot of difference, but thes tests+ perf/should_run/MethSharing+ simplCore/should_compile/spec-inline+and one nofib program, all improve if you do float to top, because+of the resulting inlining of f. So ok, let's do it.++Note [Free join points]+~~~~~~~~~~~~~~~~~~~~~~~+We never float a MFE that has a free join-point variable. You mght think+this can never occur. After all, consider+ join j x = ...+ in ....(jump j x)....+How might we ever want to float that (jump j x)?+ * If it would escape a value lambda, thus+ join j x = ... in (\y. ...(jump j x)... )+ then 'j' isn't a valid join point in the first place.++But consider+ join j x = .... in+ joinrec j2 y = ...(jump j x)...(a+b)....++Since j2 is recursive, it /is/ worth floating (a+b) out of the joinrec.+But it is emphatically /not/ good to float the (jump j x) out:+ (a) 'j' will stop being a join point+ (b) In any case, jumping to 'j' must be an exit of the j2 loop, so no+ work would be saved by floating it out of the \y.++Even if we floated 'j' to top level, (b) would still hold.++Bottom line: never float a MFE that has a free JoinId.++Note [Floating MFEs of unlifted type]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+ case f x of (r::Int#) -> blah+we'd like to float (f x). But it's not trivial because it has type+Int#, and we don't want to evaluate it too early. But we can instead+float a boxed version+ y = case f x of r -> I# r+and replace the original (f x) with+ case (case y of I# r -> r) of r -> blah++Being able to float unboxed expressions is sometimes important; see+Trac #12603. I'm not sure how /often/ it is important, but it's+not hard to achieve.++We only do it for a fixed collection of types for which we have a+convenient boxing constructor (see boxingDataCon_maybe). In+particular we /don't/ do it for unboxed tuples; it's better to float+the components of the tuple individually.++I did experiment with a form of boxing that works for any type, namely+wrapping in a function. In our example++ let y = case f x of r -> \v. f x+ in case y void of r -> blah++It works fine, but it's 50% slower (based on some crude benchmarking).+I suppose we could do it for types not covered by boxingDataCon_maybe,+but it's more code and I'll wait to see if anyone wants it.++Note [Test cheapness with exprOkForSpeculation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't want to float very cheap expressions by boxing and unboxing.+But we use exprOkForSpeculation for the test, not exprIsCheap.+Why? Because it's important /not/ to transform+ f (a /# 3)+to+ f (case bx of I# a -> a /# 3)+and float bx = I# (a /# 3), because the application of f no+longer obeys the let/app invariant. But (a /# 3) is ok-for-spec+due to a special hack that says division operators can't fail+when the denominator is definitely non-zero. And yet that+same expression says False to exprIsCheap. Simplest way to+guarantee the let/app invariant is to use the same function!++If an expression is okay for speculation, we could also float it out+*without* boxing and unboxing, since evaluating it early is okay.+However, it turned out to usually be better not to float such expressions,+since they tend to be extremely cheap things like (x +# 1#). Even the+cost of spilling the let-bound variable to the stack across a call may+exceed the cost of recomputing such an expression. (And we can't float+unlifted bindings to top-level.)++We could try to do something smarter here, and float out expensive yet+okay-for-speculation things, such as division by non-zero constants.+But I suspect it's a narrow target.++Note [Bottoming floats]+~~~~~~~~~~~~~~~~~~~~~~~+If we see+ f = \x. g (error "urk")+we'd like to float the call to error, to get+ lvl = error "urk"+ f = \x. g lvl++But, as ever, we need to be careful:++(1) We want to float a bottoming+ expression even if it has free variables:+ f = \x. g (let v = h x in error ("urk" ++ v))+ Then we'd like to abstract over 'x' can float the whole arg of g:+ lvl = \x. let v = h x in error ("urk" ++ v)+ f = \x. g (lvl x)+ To achieve this we pass is_bot to destLevel++(2) We do not do this for lambdas that return+ bottom. Instead we treat the /body/ of such a function specially,+ via point (1). For example:+ f = \x. ....(\y z. if x then error y else error z)....+ ===>+ lvl = \x z y. if b then error y else error z+ f = \x. ...(\y z. lvl x z y)...+ (There is no guarantee that we'll choose the perfect argument order.)++(3) If we have a /binding/ that returns bottom, we want to float it to top+ level, even if it has free vars (point (1)), and even it has lambdas.+ Example:+ ... let { v = \y. error (show x ++ show y) } in ...+ We want to abstract over x and float the whole thing to top:+ lvl = \xy. errror (show x ++ show y)+ ...let {v = lvl x} in ...++ Then of course we don't want to separately float the body (error ...)+ as /another/ MFE, so we tell lvlFloatRhs not to do that, via the is_bot+ argument.++See Maessen's paper 1999 "Bottom extraction: factoring error handling out+of functional programs" (unpublished I think).++When we do this, we set the strictness and arity of the new bottoming+Id, *immediately*, for three reasons:++ * To prevent the abstracted thing being immediately inlined back in again+ via preInlineUnconditionally. The latter has a test for bottoming Ids+ to stop inlining them, so we'd better make sure it *is* a bottoming Id!++ * So that it's properly exposed as such in the interface file, even if+ this is all happening after strictness analysis.++ * In case we do CSE with the same expression that *is* marked bottom+ lvl = error "urk"+ x{str=bot) = error "urk"+ Here we don't want to replace 'x' with 'lvl', else we may get Lint+ errors, e.g. via a case with empty alternatives: (case x of {})+ Lint complains unless the scrutinee of such a case is clearly bottom.++ This was reported in Trac #11290. But since the whole bottoming-float+ thing is based on the cheap-and-cheerful exprIsBottom, I'm not sure+ that it'll nail all such cases.++Note [Bottoming floats: eta expansion] c.f Note [Bottoming floats]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Tiresomely, though, the simplifier has an invariant that the manifest+arity of the RHS should be the same as the arity; but we can't call+etaExpand during SetLevels because it works over a decorated form of+CoreExpr. So we do the eta expansion later, in FloatOut.++Note [Case MFEs]+~~~~~~~~~~~~~~~~+We don't float a case expression as an MFE from a strict context. Why not?+Because in doing so we share a tiny bit of computation (the switch) but+in exchange we build a thunk, which is bad. This case reduces allocation+by 7% in spectral/puzzle (a rather strange benchmark) and 1.2% in real/fem.+Doesn't change any other allocation at all.++We will make a separate decision for the scrutinees and alternatives.+-}++annotateBotStr :: Id -> Arity -> Maybe (Arity, StrictSig) -> Id+-- See Note [Bottoming floats] for why we want to add+-- bottoming information right now+--+-- n_extra are the number of extra value arguments added during floating+annotateBotStr id n_extra mb_str+ = case mb_str of+ Nothing -> id+ Just (arity, sig) -> id `setIdArity` (arity + n_extra)+ `setIdStrictness` (increaseStrictSigArity n_extra sig)++notWorthFloating :: CoreExpr -> [Var] -> Bool+-- Returns True if the expression would be replaced by+-- something bigger than it is now. For example:+-- abs_vars = tvars only: return True if e is trivial,+-- but False for anything bigger+-- abs_vars = [x] (an Id): return True for trivial, or an application (f x)+-- but False for (f x x)+--+-- One big goal is that floating should be idempotent. Eg if+-- we replace e with (lvl79 x y) and then run FloatOut again, don't want+-- to replace (lvl79 x y) with (lvl83 x y)!++notWorthFloating e abs_vars+ = go e (count isId abs_vars)+ where+ go (Var {}) n = n >= 0+ go (Lit lit) n = ASSERT( n==0 )+ litIsTrivial lit -- Note [Floating literals]+ go (Tick t e) n = not (tickishIsCode t) && go e n+ go (Cast e _) n = go e n+ go (App e arg) n+ | Type {} <- arg = go e n+ | Coercion {} <- arg = go e n+ | n==0 = False+ | is_triv arg = go e (n-1)+ | otherwise = False+ go _ _ = False++ is_triv (Lit {}) = True -- Treat all literals as trivial+ is_triv (Var {}) = True -- (ie not worth floating)+ is_triv (Cast e _) = is_triv e+ is_triv (App e (Type {})) = is_triv e+ is_triv (App e (Coercion {})) = is_triv e+ is_triv (Tick t e) = not (tickishIsCode t) && is_triv e+ is_triv _ = False++{-+Note [Floating literals]+~~~~~~~~~~~~~~~~~~~~~~~~+It's important to float Integer literals, so that they get shared,+rather than being allocated every time round the loop.+Hence the litIsTrivial.++Ditto literal strings (MachStr), which we'd like to float to top+level, which is now possible.+++Note [Escaping a value lambda]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to float even cheap expressions out of value lambdas,+because that saves allocation. Consider+ f = \x. .. (\y.e) ...+Then we'd like to avoid allocating the (\y.e) every time we call f,+(assuming e does not mention x). An example where this really makes a+difference is simplrun009.++Another reason it's good is because it makes SpecContr fire on functions.+Consider+ f = \x. ....(f (\y.e))....+After floating we get+ lvl = \y.e+ f = \x. ....(f lvl)...+and that is much easier for SpecConstr to generate a robust+specialisation for.++However, if we are wrapping the thing in extra value lambdas (in+abs_vars), then nothing is saved. E.g.+ f = \xyz. ...(e1[y],e2)....+If we float+ lvl = \y. (e1[y],e2)+ f = \xyz. ...(lvl y)...+we have saved nothing: one pair will still be allocated for each+call of 'f'. Hence the (not float_is_lam) in float_me.+++************************************************************************+* *+\subsection{Bindings}+* *+************************************************************************++The binding stuff works for top level too.+-}++lvlBind :: LevelEnv+ -> CoreBindWithFVs+ -> LvlM (LevelledBind, LevelEnv)++lvlBind env (AnnNonRec bndr rhs)+ | isTyVar bndr -- Don't do anything for TyVar binders+ -- (simplifier gets rid of them pronto)+ || isCoVar bndr -- Difficult to fix up CoVar occurrences (see extendPolyLvlEnv)+ -- so we will ignore this case for now+ || not (profitableFloat env dest_lvl)+ || (isTopLvl dest_lvl && isUnliftedType (idType bndr))+ -- We can't float an unlifted binding to top level, so we don't+ -- float it at all. It's a bit brutal, but unlifted bindings+ -- aren't expensive either++ = -- No float+ do { rhs' <- lvlRhs env NonRecursive is_bot mb_join_arity rhs+ ; let bind_lvl = incMinorLvl (le_ctxt_lvl env)+ (env', [bndr']) = substAndLvlBndrs NonRecursive env bind_lvl [bndr]+ ; return (NonRec bndr' rhs', env') }++ -- Otherwise we are going to float+ | null abs_vars+ = do { -- No type abstraction; clone existing binder+ rhs' <- lvlFloatRhs [] dest_lvl env NonRecursive+ is_bot mb_join_arity rhs+ ; (env', [bndr']) <- cloneLetVars NonRecursive env dest_lvl [bndr]+ ; let bndr2 = annotateBotStr bndr' 0 mb_bot_str+ ; return (NonRec (TB bndr2 (FloatMe dest_lvl)) rhs', env') }++ | otherwise+ = do { -- Yes, type abstraction; create a new binder, extend substitution, etc+ rhs' <- lvlFloatRhs abs_vars dest_lvl env NonRecursive+ is_bot mb_join_arity rhs+ ; (env', [bndr']) <- newPolyBndrs dest_lvl env abs_vars [bndr]+ ; let bndr2 = annotateBotStr bndr' n_extra mb_bot_str+ ; return (NonRec (TB bndr2 (FloatMe dest_lvl)) rhs', env') }++ where+ rhs_fvs = freeVarsOf rhs+ bind_fvs = rhs_fvs `unionDVarSet` dIdFreeVars bndr+ abs_vars = abstractVars dest_lvl env bind_fvs+ dest_lvl = destLevel env bind_fvs (isFunction rhs) is_bot is_join++ mb_bot_str = exprBotStrictness_maybe (deAnnotate rhs)+ is_bot = isJust mb_bot_str+ -- NB: not isBottomThunk! See Note [Bottoming floats] point (3)++ n_extra = count isId abs_vars+ mb_join_arity = isJoinId_maybe bndr+ is_join = isJust mb_join_arity++lvlBind env (AnnRec pairs)+ | floatTopLvlOnly env && not (isTopLvl dest_lvl)+ -- Only floating to the top level is allowed.+ || not (profitableFloat env dest_lvl)+ = do { let bind_lvl = incMinorLvl (le_ctxt_lvl env)+ (env', bndrs') = substAndLvlBndrs Recursive env bind_lvl bndrs+ lvl_rhs (b,r) = lvlRhs env' Recursive is_bot (isJoinId_maybe b) r+ ; rhss' <- mapM lvl_rhs pairs+ ; return (Rec (bndrs' `zip` rhss'), env') }++ | null abs_vars+ = do { (new_env, new_bndrs) <- cloneLetVars Recursive env dest_lvl bndrs+ ; new_rhss <- mapM (do_rhs new_env) pairs+ ; return ( Rec ([TB b (FloatMe dest_lvl) | b <- new_bndrs] `zip` new_rhss)+ , new_env) }++-- ToDo: when enabling the floatLambda stuff,+-- I think we want to stop doing this+ | [(bndr,rhs)] <- pairs+ , count isId abs_vars > 1+ = do -- Special case for self recursion where there are+ -- several variables carried around: build a local loop:+ -- poly_f = \abs_vars. \lam_vars . letrec f = \lam_vars. rhs in f lam_vars+ -- This just makes the closures a bit smaller. If we don't do+ -- this, allocation rises significantly on some programs+ --+ -- We could elaborate it for the case where there are several+ -- mutually functions, but it's quite a bit more complicated+ --+ -- This all seems a bit ad hoc -- sigh+ let (rhs_env, abs_vars_w_lvls) = lvlLamBndrs env dest_lvl abs_vars+ rhs_lvl = le_ctxt_lvl rhs_env++ (rhs_env', [new_bndr]) <- cloneLetVars Recursive rhs_env rhs_lvl [bndr]+ let+ (lam_bndrs, rhs_body) = collectAnnBndrs rhs+ (body_env1, lam_bndrs1) = substBndrsSL NonRecursive rhs_env' lam_bndrs+ (body_env2, lam_bndrs2) = lvlLamBndrs body_env1 rhs_lvl lam_bndrs1+ new_rhs_body <- lvlRhs body_env2 Recursive is_bot (get_join bndr) rhs_body+ (poly_env, [poly_bndr]) <- newPolyBndrs dest_lvl env abs_vars [bndr]+ return (Rec [(TB poly_bndr (FloatMe dest_lvl)+ , mkLams abs_vars_w_lvls $+ mkLams lam_bndrs2 $+ Let (Rec [( TB new_bndr (StayPut rhs_lvl)+ , mkLams lam_bndrs2 new_rhs_body)])+ (mkVarApps (Var new_bndr) lam_bndrs1))]+ , poly_env)++ | otherwise -- Non-null abs_vars+ = do { (new_env, new_bndrs) <- newPolyBndrs dest_lvl env abs_vars bndrs+ ; new_rhss <- mapM (do_rhs new_env) pairs+ ; return ( Rec ([TB b (FloatMe dest_lvl) | b <- new_bndrs] `zip` new_rhss)+ , new_env) }++ where+ (bndrs,rhss) = unzip pairs+ is_join = isJoinId (head bndrs)+ -- bndrs is always non-empty and if one is a join they all are+ -- Both are checked by Lint+ is_fun = all isFunction rhss+ is_bot = False -- It's odd to have an unconditionally divergent+ -- function in a Rec, and we don't much care what+ -- happens to it. False is simple!++ do_rhs env (bndr,rhs) = lvlFloatRhs abs_vars dest_lvl env Recursive+ is_bot (get_join bndr)+ rhs++ get_join bndr | need_zap = Nothing+ | otherwise = isJoinId_maybe bndr+ need_zap = dest_lvl `ltLvl` joinCeilingLevel env++ -- Finding the free vars of the binding group is annoying+ bind_fvs = ((unionDVarSets [ freeVarsOf rhs | (_, rhs) <- pairs])+ `unionDVarSet`+ (fvDVarSet $ unionsFV [ idFVs bndr+ | (bndr, (_,_)) <- pairs]))+ `delDVarSetList`+ bndrs++ dest_lvl = destLevel env bind_fvs is_fun is_bot is_join+ abs_vars = abstractVars dest_lvl env bind_fvs++profitableFloat :: LevelEnv -> Level -> Bool+profitableFloat env dest_lvl+ = (dest_lvl `ltMajLvl` le_ctxt_lvl env) -- Escapes a value lambda+ || isTopLvl dest_lvl -- Going all the way to top level+++----------------------------------------------------+-- Three help functions for the type-abstraction case++lvlRhs :: LevelEnv+ -> RecFlag+ -> Bool -- Is this a bottoming function+ -> Maybe JoinArity+ -> CoreExprWithFVs+ -> LvlM LevelledExpr+lvlRhs env rec_flag is_bot mb_join_arity expr+ = lvlFloatRhs [] (le_ctxt_lvl env) env+ rec_flag is_bot mb_join_arity expr++lvlFloatRhs :: [OutVar] -> Level -> LevelEnv -> RecFlag+ -> Bool -- Binding is for a bottoming function+ -> Maybe JoinArity+ -> CoreExprWithFVs+ -> LvlM (Expr LevelledBndr)+-- Ignores the le_ctxt_lvl in env; treats dest_lvl as the baseline+lvlFloatRhs abs_vars dest_lvl env rec is_bot mb_join_arity rhs+ = do { body' <- if not is_bot -- See Note [Floating from a RHS]+ && any isId bndrs+ then lvlMFE body_env True body+ else lvlExpr body_env body+ ; return (mkLams bndrs' body') }+ where+ (bndrs, body) | Just join_arity <- mb_join_arity+ = collectNAnnBndrs join_arity rhs+ | otherwise+ = collectAnnBndrs rhs+ (env1, bndrs1) = substBndrsSL NonRecursive env bndrs+ all_bndrs = abs_vars ++ bndrs1+ (body_env, bndrs') | Just _ <- mb_join_arity+ = lvlJoinBndrs env1 dest_lvl rec all_bndrs+ | otherwise+ = case lvlLamBndrs env1 dest_lvl all_bndrs of+ (env2, bndrs') -> (placeJoinCeiling env2, bndrs')+ -- The important thing here is that we call lvlLamBndrs on+ -- all these binders at once (abs_vars and bndrs), so they+ -- all get the same major level. Otherwise we create stupid+ -- let-bindings inside, joyfully thinking they can float; but+ -- in the end they don't because we never float bindings in+ -- between lambdas++{- Note [Floating from a RHS]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When float the RHS of a let-binding, we don't always want to apply+lvlMFE to the body of a lambda, as we usually do, because the entire+binding body is already going to the right place (dest_lvl).++A particular example is the top level. Consider+ concat = /\ a -> foldr ..a.. (++) []+We don't want to float the body of the lambda to get+ lvl = /\ a -> foldr ..a.. (++) []+ concat = /\ a -> lvl a+That would be stupid.++Previously this was avoided in a much nastier way, by testing strict_ctxt+in float_me in lvlMFE. But that wasn't even right because it would fail+to float out the error sub-expression in+ f = \x. case x of+ True -> error ("blah" ++ show x)+ False -> ...++But we must be careful:++* If we had+ f = \x -> factorial 20+ we /would/ want to float that (factorial 20) out! Functions are treated+ differently: see the use of isFunction in the calls to destLevel. If+ there are only type lambdas, then destLevel will say "go to top, and+ abstract over the free tyvars" and we don't want that here.++* But if we had+ f = \x -> error (...x....)+ we would NOT want to float the bottoming expression out to give+ lvl = \x -> error (...x...)+ f = \x -> lvl x++Conclusion: use lvlMFE if there are+ * any value lambdas in the original function, and+ * this is not a bottoming function (the is_bot argument)+Use lvlExpr otherwise. A little subtle, and I got it wrong at least twice+(e.g. Trac #13369).+-}++{-+************************************************************************+* *+\subsection{Deciding floatability}+* *+************************************************************************+-}++substAndLvlBndrs :: RecFlag -> LevelEnv -> Level -> [InVar] -> (LevelEnv, [LevelledBndr])+substAndLvlBndrs is_rec env lvl bndrs+ = lvlBndrs subst_env lvl subst_bndrs+ where+ (subst_env, subst_bndrs) = substBndrsSL is_rec env bndrs++substBndrsSL :: RecFlag -> LevelEnv -> [InVar] -> (LevelEnv, [OutVar])+-- So named only to avoid the name clash with CoreSubst.substBndrs+substBndrsSL is_rec env@(LE { le_subst = subst, le_env = id_env }) bndrs+ = ( env { le_subst = subst'+ , le_env = foldl add_id id_env (bndrs `zip` bndrs') }+ , bndrs')+ where+ (subst', bndrs') = case is_rec of+ NonRecursive -> substBndrs subst bndrs+ Recursive -> substRecBndrs subst bndrs++lvlLamBndrs :: LevelEnv -> Level -> [OutVar] -> (LevelEnv, [LevelledBndr])+-- Compute the levels for the binders of a lambda group+lvlLamBndrs env lvl bndrs+ = lvlBndrs env new_lvl bndrs+ where+ new_lvl | any is_major bndrs = incMajorLvl lvl+ | otherwise = incMinorLvl lvl++ is_major bndr = isId bndr && not (isProbablyOneShotLambda bndr)+ -- The "probably" part says "don't float things out of a+ -- probable one-shot lambda"+ -- See Note [Computing one-shot info] in Demand.hs++lvlJoinBndrs :: LevelEnv -> Level -> RecFlag -> [OutVar]+ -> (LevelEnv, [LevelledBndr])+lvlJoinBndrs env lvl rec bndrs+ = lvlBndrs env new_lvl bndrs+ where+ new_lvl | isRec rec = incMajorLvl lvl+ | otherwise = incMinorLvl lvl+ -- Non-recursive join points are one-shot; recursive ones are not++lvlBndrs :: LevelEnv -> Level -> [CoreBndr] -> (LevelEnv, [LevelledBndr])+-- The binders returned are exactly the same as the ones passed,+-- apart from applying the substitution, but they are now paired+-- with a (StayPut level)+--+-- The returned envt has le_ctxt_lvl updated to the new_lvl+--+-- All the new binders get the same level, because+-- any floating binding is either going to float past+-- all or none. We never separate binders.+lvlBndrs env@(LE { le_lvl_env = lvl_env }) new_lvl bndrs+ = ( env { le_ctxt_lvl = new_lvl+ , le_join_ceil = new_lvl+ , le_lvl_env = addLvls new_lvl lvl_env bndrs }+ , map (stayPut new_lvl) bndrs)++stayPut :: Level -> OutVar -> LevelledBndr+stayPut new_lvl bndr = TB bndr (StayPut new_lvl)++ -- Destination level is the max Id level of the expression+ -- (We'll abstract the type variables, if any.)+destLevel :: LevelEnv -> DVarSet+ -> Bool -- True <=> is function+ -> Bool -- True <=> is bottom+ -> Bool -- True <=> is a join point+ -> Level+-- INVARIANT: if is_join=True then result >= join_ceiling+destLevel env fvs is_function is_bot is_join+ | isTopLvl max_fv_id_level -- Float even joins if they get to top level+ -- See Note [Floating join point bindings]+ = tOP_LEVEL++ | is_join -- Never float a join point past the join ceiling+ -- See Note [Join points] in FloatOut+ = if max_fv_id_level `ltLvl` join_ceiling+ then join_ceiling+ else max_fv_id_level++ | is_bot -- Send bottoming bindings to the top+ = tOP_LEVEL -- regardless; see Note [Bottoming floats]+ -- Esp Bottoming floats (1)++ | Just n_args <- floatLams env+ , n_args > 0 -- n=0 case handled uniformly by the 'otherwise' case+ , is_function+ , countFreeIds fvs <= n_args+ = tOP_LEVEL -- Send functions to top level; see+ -- the comments with isFunction++ | otherwise = max_fv_id_level+ where+ max_fv_id_level = maxFvLevel isId env fvs -- Max over Ids only; the tyvars+ -- will be abstracted+ join_ceiling = joinCeilingLevel env++isFunction :: CoreExprWithFVs -> Bool+-- The idea here is that we want to float *functions* to+-- the top level. This saves no work, but+-- (a) it can make the host function body a lot smaller,+-- and hence inlinable.+-- (b) it can also save allocation when the function is recursive:+-- h = \x -> letrec f = \y -> ...f...y...x...+-- in f x+-- becomes+-- f = \x y -> ...(f x)...y...x...+-- h = \x -> f x x+-- No allocation for f now.+-- We may only want to do this if there are sufficiently few free+-- variables. We certainly only want to do it for values, and not for+-- constructors. So the simple thing is just to look for lambdas+isFunction (_, AnnLam b e) | isId b = True+ | otherwise = isFunction e+-- isFunction (_, AnnTick _ e) = isFunction e -- dubious+isFunction _ = False++countFreeIds :: DVarSet -> Int+countFreeIds = nonDetFoldUDFM add 0+ -- It's OK to use nonDetFoldUDFM here because we're just counting things.+ where+ add :: Var -> Int -> Int+ add v n | isId v = n+1+ | otherwise = n++{-+************************************************************************+* *+\subsection{Free-To-Level Monad}+* *+************************************************************************+-}++data LevelEnv+ = LE { le_switches :: FloatOutSwitches+ , le_ctxt_lvl :: Level -- The current level+ , le_lvl_env :: VarEnv Level -- Domain is *post-cloned* TyVars and Ids+ , le_join_ceil:: Level -- Highest level to which joins float+ -- Invariant: always >= le_ctxt_lvl++ -- See Note [le_subst and le_env]+ , le_subst :: Subst -- Domain is pre-cloned TyVars and Ids+ -- The Id -> CoreExpr in the Subst is ignored+ -- (since we want to substitute a LevelledExpr for+ -- an Id via le_env) but we do use the Co/TyVar substs+ , le_env :: IdEnv ([OutVar], LevelledExpr) -- Domain is pre-cloned Ids+ }++{- 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+variable polymorphic because we want to float it out past a big+lambda.++The le_subst and le_env always implement the same mapping,+ in_x :-> out_x a b+where out_x is an OutVar, and a,b are its arguments (when+we perform abstraction at the same time as floating).++ le_subst maps to CoreExpr+ le_env maps to LevelledExpr++Since the range is always a variable or application, there is never+any difference between the two, but sadly the types differ. The+le_subst is used when substituting in a variable's IdInfo; the le_env+when we find a Var.++In addition the le_env records a [OutVar] of variables free in the+OutExpr/LevelledExpr, just so we don't have to call freeVars+repeatedly. This list is always non-empty, and the first element is+out_x++The domain of the both envs is *pre-cloned* Ids, though++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+ , le_join_ceil = panic "initialEnv"+ , le_lvl_env = emptyVarEnv+ , le_subst = emptySubst+ , le_env = emptyVarEnv }++addLvl :: Level -> VarEnv Level -> OutVar -> VarEnv Level+addLvl dest_lvl env v' = extendVarEnv env v' dest_lvl++addLvls :: Level -> VarEnv Level -> [OutVar] -> VarEnv Level+addLvls dest_lvl env vs = foldl (addLvl dest_lvl) env vs++floatLams :: LevelEnv -> Maybe Int+floatLams le = floatOutLambdas (le_switches le)++floatConsts :: LevelEnv -> Bool+floatConsts le = floatOutConstants (le_switches le)++floatOverSat :: LevelEnv -> Bool+floatOverSat le = floatOutOverSatApps (le_switches le)++floatTopLvlOnly :: LevelEnv -> Bool+floatTopLvlOnly le = floatToTopLevelOnly (le_switches le)++incMinorLvlFrom :: LevelEnv -> Level+incMinorLvlFrom env = incMinorLvl (le_ctxt_lvl env)++-- extendCaseBndrEnv adds the mapping case-bndr->scrut-var if it can+-- See Note [Binder-swap during float-out]+extendCaseBndrEnv :: LevelEnv+ -> Id -- Pre-cloned case binder+ -> Expr LevelledBndr -- Post-cloned scrutinee+ -> LevelEnv+extendCaseBndrEnv le@(LE { le_subst = subst, le_env = id_env })+ case_bndr (Var scrut_var)+ = le { le_subst = extendSubstWithVar subst case_bndr scrut_var+ , le_env = add_id id_env (case_bndr, scrut_var) }+extendCaseBndrEnv env _ _ = env++-- See Note [Join ceiling]+placeJoinCeiling :: LevelEnv -> LevelEnv+placeJoinCeiling le@(LE { le_ctxt_lvl = lvl })+ = le { le_ctxt_lvl = lvl', le_join_ceil = lvl' }+ where+ lvl' = asJoinCeilLvl (incMinorLvl lvl)++maxFvLevel :: (Var -> Bool) -> LevelEnv -> DVarSet -> Level+maxFvLevel max_me (LE { le_lvl_env = lvl_env, le_env = id_env }) var_set+ = foldDVarSet max_in tOP_LEVEL var_set+ where+ max_in in_var lvl+ = foldr max_out lvl (case lookupVarEnv id_env in_var of+ Just (abs_vars, _) -> abs_vars+ Nothing -> [in_var])++ max_out out_var lvl+ | max_me out_var = case lookupVarEnv lvl_env out_var of+ Just lvl' -> maxLvl lvl' lvl+ Nothing -> lvl+ | otherwise = lvl -- Ignore some vars depending on max_me++lookupVar :: LevelEnv -> Id -> LevelledExpr+lookupVar le v = case lookupVarEnv (le_env le) v of+ Just (_, expr) -> expr+ _ -> Var v++-- Level to which join points are allowed to float (boundary of current tail+-- context). See Note [Join ceiling]+joinCeilingLevel :: LevelEnv -> Level+joinCeilingLevel = le_join_ceil++abstractVars :: Level -> LevelEnv -> DVarSet -> [OutVar]+ -- Find the variables in fvs, free vars of the target expression,+ -- whose level is greater than the destination level+ -- These are the ones we are going to abstract out+ --+ -- Note that to get reproducible builds, the variables need to be+ -- abstracted in deterministic order, not dependent on the values of+ -- Uniques. This is achieved by using DVarSets, deterministic free+ -- variable computation and deterministic sort.+ -- See Note [Unique Determinism] in Unique for explanation of why+ -- Uniques are not deterministic.+abstractVars dest_lvl (LE { le_subst = subst, le_lvl_env = lvl_env }) in_fvs+ = -- NB: sortQuantVars might not put duplicates next to each other+ map zap $ sortQuantVars $ uniq+ [out_var | out_fv <- dVarSetElems (substDVarSet subst in_fvs)+ , out_var <- dVarSetElems (close out_fv)+ , abstract_me out_var ]+ -- NB: it's important to call abstract_me only on the OutIds the+ -- come from substDVarSet (not on fv, which is an InId)+ where+ uniq :: [Var] -> [Var]+ -- Remove duplicates, preserving order+ uniq = dVarSetElems . mkDVarSet++ abstract_me v = case lookupVarEnv lvl_env v of+ Just lvl -> dest_lvl `ltLvl` lvl+ Nothing -> False++ -- We are going to lambda-abstract, so nuke any IdInfo,+ -- and add the tyvars of the Id (if necessary)+ zap v | isId v = WARN( isStableUnfolding (idUnfolding v) ||+ not (isEmptyRuleInfo (idSpecialisation v)),+ text "absVarsOf: discarding info on" <+> ppr v )+ setIdInfo v vanillaIdInfo+ | otherwise = v++ close :: Var -> DVarSet -- Close over variables free in the type+ -- Result includes the input variable itself+ close v = foldDVarSet (unionDVarSet . close)+ (unitDVarSet v)+ (fvDVarSet $ varTypeTyCoFVs v)++type LvlM result = UniqSM result++initLvl :: UniqSupply -> UniqSM a -> a+initLvl = initUs_++newPolyBndrs :: Level -> LevelEnv -> [OutVar] -> [InId]+ -> LvlM (LevelEnv, [OutId])+-- The envt is extended to bind the new bndrs to dest_lvl, but+-- the le_ctxt_lvl is unaffected+newPolyBndrs dest_lvl+ env@(LE { le_lvl_env = lvl_env, le_subst = subst, le_env = id_env })+ abs_vars bndrs+ = ASSERT( all (not . isCoVar) bndrs ) -- What would we add to the CoSubst in this case. No easy answer.+ do { uniqs <- getUniquesM+ ; let new_bndrs = zipWith mk_poly_bndr bndrs uniqs+ bndr_prs = bndrs `zip` new_bndrs+ env' = env { le_lvl_env = addLvls dest_lvl lvl_env new_bndrs+ , le_subst = foldl add_subst subst bndr_prs+ , le_env = foldl add_id id_env bndr_prs }+ ; return (env', new_bndrs) }+ where+ add_subst env (v, v') = extendIdSubst env v (mkVarApps (Var v') abs_vars)+ add_id env (v, v') = extendVarEnv env v ((v':abs_vars), mkVarApps (Var v') abs_vars)++ mk_poly_bndr bndr uniq = transferPolyIdInfo bndr abs_vars $ -- Note [transferPolyIdInfo] in Id.hs+ transfer_join_info bndr $+ mkSysLocalOrCoVar (mkFastString str) uniq poly_ty+ where+ str = "poly_" ++ occNameString (getOccName bndr)+ poly_ty = mkLamTypes abs_vars (CoreSubst.substTy subst (idType bndr))++ -- If we are floating a join point to top level, it stops being+ -- a join point. Otherwise it continues to be a join point,+ -- but we may need to adjust its arity+ dest_is_top = isTopLvl dest_lvl+ transfer_join_info bndr new_bndr+ | Just join_arity <- isJoinId_maybe bndr+ , not dest_is_top+ = new_bndr `asJoinId` join_arity + length abs_vars+ | otherwise+ = new_bndr++newLvlVar :: LevelledExpr -- The RHS of the new binding+ -> Maybe JoinArity -- Its join arity, if it is a join point+ -> Bool -- True <=> the RHS looks like (makeStatic ...)+ -> LvlM Id+newLvlVar lvld_rhs join_arity_maybe is_mk_static+ = do { uniq <- getUniqueM+ ; return (add_join_info (mk_id uniq rhs_ty))+ }+ where+ add_join_info var = var `asJoinId_maybe` join_arity_maybe+ de_tagged_rhs = deTagExpr lvld_rhs+ rhs_ty = exprType de_tagged_rhs++ mk_id uniq rhs_ty+ -- See Note [Grand plan for static forms] in StaticPtrTable.+ | is_mk_static+ = mkExportedVanillaId (mkSystemVarName uniq (mkFastString "static_ptr"))+ rhs_ty+ | otherwise+ = mkLocalIdOrCoVar (mkSystemVarName uniq (mkFastString "lvl")) rhs_ty++cloneCaseBndrs :: LevelEnv -> Level -> [Var] -> LvlM (LevelEnv, [Var])+cloneCaseBndrs env@(LE { le_subst = subst, le_lvl_env = lvl_env, le_env = id_env })+ new_lvl vs+ = do { us <- getUniqueSupplyM+ ; let (subst', vs') = cloneBndrs subst us vs+ env' = env { le_ctxt_lvl = new_lvl+ , le_join_ceil = new_lvl+ , le_lvl_env = addLvls new_lvl lvl_env vs'+ , le_subst = subst'+ , le_env = foldl add_id id_env (vs `zip` vs') }++ ; return (env', vs') }++cloneLetVars :: RecFlag -> LevelEnv -> Level -> [InVar]+ -> LvlM (LevelEnv, [OutVar])+-- See Note [Need for cloning during float-out]+-- Works for Ids bound by let(rec)+-- The dest_lvl is attributed to the binders in the new env,+-- but cloneVars doesn't affect the le_ctxt_lvl of the incoming env+cloneLetVars is_rec+ env@(LE { le_subst = subst, le_lvl_env = lvl_env, le_env = id_env })+ dest_lvl vs+ = do { us <- getUniqueSupplyM+ ; let vs1 = map zap vs+ -- See Note [Zapping the demand info]+ (subst', vs2) = case is_rec of+ NonRecursive -> cloneBndrs subst us vs1+ Recursive -> cloneRecIdBndrs subst us vs1+ prs = vs `zip` vs2+ env' = env { le_lvl_env = addLvls dest_lvl lvl_env vs2+ , le_subst = subst'+ , le_env = foldl add_id id_env prs }++ ; return (env', vs2) }+ where+ zap :: Var -> Var+ zap v | isId v = zap_join (zapIdDemandInfo v)+ | otherwise = v++ zap_join | isTopLvl dest_lvl = zapJoinId+ | otherwise = \v -> v++add_id :: IdEnv ([Var], LevelledExpr) -> (Var, Var) -> IdEnv ([Var], LevelledExpr)+add_id id_env (v, v1)+ | isTyVar v = delVarEnv id_env v+ | otherwise = extendVarEnv id_env v ([v1], ASSERT(not (isCoVar v1)) Var v1)++{-+Note [Zapping the demand info]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+VERY IMPORTANT: we must zap the demand info if the thing is going to+float out, because it may be less demanded than at its original+binding site. Eg+ f :: Int -> Int+ f x = let v = 3*4 in v+x+Here v is strict; but if we float v to top level, it isn't any more.++Similarly, if we're floating a join point, it won't be one anymore, so we zap+join point information as well.+-}
+ simplCore/SimplCore.hs view
@@ -0,0 +1,1061 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[SimplCore]{Driver for simplifying @Core@ programs}+-}++{-# LANGUAGE CPP #-}++module SimplCore ( core2core, simplifyExpr ) where++#include "HsVersions.h"++import DynFlags+import CoreSyn+import HscTypes+import CSE ( cseProgram )+import Rules ( mkRuleBase, unionRuleBase,+ extendRuleBaseList, ruleCheckProgram, addRuleInfo, )+import PprCore ( pprCoreBindings, pprCoreExpr )+import OccurAnal ( occurAnalysePgm, occurAnalyseExpr )+import IdInfo+import CoreStats ( coreBindsSize, coreBindsStats, exprSize )+import CoreUtils ( mkTicks, stripTicksTop )+import CoreLint ( endPass, lintPassResult, dumpPassResult,+ lintAnnots )+import Simplify ( simplTopBinds, simplExpr, simplRules )+import SimplUtils ( simplEnvForGHCi, activeRule )+import SimplEnv+import SimplMonad+import CoreMonad+import qualified ErrUtils as Err+import FloatIn ( floatInwards )+import FloatOut ( floatOutwards )+import FamInstEnv+import Id+import ErrUtils ( withTiming )+import BasicTypes ( CompilerPhase(..), isDefaultInlinePragma )+import VarSet+import VarEnv+import LiberateCase ( liberateCase )+import SAT ( doStaticArgs )+import Specialise ( specProgram)+import SpecConstr ( specConstrProgram)+import DmdAnal ( dmdAnalProgram )+import CallArity ( callArityAnalProgram )+import WorkWrap ( wwTopBinds )+import Vectorise ( vectorise )+import SrcLoc+import Util+import Module++import Maybes+import UniqSupply ( UniqSupply, mkSplitUniqSupply, splitUniqSupply )+import UniqFM+import Outputable+import Control.Monad+import qualified GHC.LanguageExtensions as LangExt++#ifdef GHCI+import DynamicLoading ( loadPlugins )+import Plugins ( installCoreToDos )+#else+import DynamicLoading ( pluginError )+#endif++{-+************************************************************************+* *+\subsection{The driver for the simplifier}+* *+************************************************************************+-}++core2core :: HscEnv -> ModGuts -> IO ModGuts+core2core hsc_env guts@(ModGuts { mg_module = mod+ , mg_loc = loc+ , mg_deps = deps+ , mg_rdr_env = rdr_env })+ = do { us <- mkSplitUniqSupply 's'+ -- make sure all plugins are loaded++ ; let builtin_passes = getCoreToDo dflags+ orph_mods = mkModuleSet (mod : dep_orphs deps)+ ;+ ; (guts2, stats) <- runCoreM hsc_env hpt_rule_base us mod+ orph_mods print_unqual loc $+ do { all_passes <- addPluginPasses builtin_passes+ ; runCorePasses all_passes guts }++ ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl_stats+ "Grand total simplifier statistics"+ (pprSimplCount stats)++ ; return guts2 }+ where+ dflags = hsc_dflags hsc_env+ home_pkg_rules = hptRules hsc_env (dep_mods deps)+ hpt_rule_base = mkRuleBase home_pkg_rules+ print_unqual = mkPrintUnqualified dflags rdr_env+ -- mod: get the module out of the current HscEnv so we can retrieve it from the monad.+ -- This is very convienent for the users of the monad (e.g. plugins do not have to+ -- consume the ModGuts to find the module) but somewhat ugly because mg_module may+ -- _theoretically_ be changed during the Core pipeline (it's part of ModGuts), which+ -- would mean our cached value would go out of date.++{-+************************************************************************+* *+ Generating the main optimisation pipeline+* *+************************************************************************+-}++getCoreToDo :: DynFlags -> [CoreToDo]+getCoreToDo dflags+ = flatten_todos core_todo+ where+ opt_level = optLevel dflags+ phases = simplPhases dflags+ max_iter = maxSimplIterations dflags+ rule_check = ruleCheck dflags+ call_arity = gopt Opt_CallArity dflags+ strictness = gopt Opt_Strictness dflags+ full_laziness = gopt Opt_FullLaziness dflags+ do_specialise = gopt Opt_Specialise dflags+ do_float_in = gopt Opt_FloatIn dflags+ cse = gopt Opt_CSE dflags+ spec_constr = gopt Opt_SpecConstr dflags+ liberate_case = gopt Opt_LiberateCase dflags+ late_dmd_anal = gopt Opt_LateDmdAnal dflags+ static_args = gopt Opt_StaticArgumentTransformation dflags+ rules_on = gopt Opt_EnableRewriteRules dflags+ eta_expand_on = gopt Opt_DoLambdaEtaExpansion dflags+ ww_on = gopt Opt_WorkerWrapper dflags+ vectorise_on = gopt Opt_Vectorise dflags+ static_ptrs = xopt LangExt.StaticPointers dflags++ maybe_rule_check phase = runMaybe rule_check (CoreDoRuleCheck phase)++ maybe_strictness_before phase+ = runWhen (phase `elem` strictnessBefore dflags) CoreDoStrictness++ base_mode = SimplMode { sm_phase = panic "base_mode"+ , sm_names = []+ , sm_rules = rules_on+ , sm_eta_expand = eta_expand_on+ , sm_inline = True+ , sm_case_case = True }++ simpl_phase phase names iter+ = CoreDoPasses+ $ [ maybe_strictness_before phase+ , CoreDoSimplify iter+ (base_mode { sm_phase = Phase phase+ , sm_names = names })++ , maybe_rule_check (Phase phase) ]++ -- Vectorisation can introduce a fair few common sub expressions involving+ -- DPH primitives. For example, see the Reverse test from dph-examples.+ -- We need to eliminate these common sub expressions before their definitions+ -- are inlined in phase 2. The CSE introduces lots of v1 = v2 bindings,+ -- so we also run simpl_gently to inline them.+ ++ (if vectorise_on && phase == 3+ then [CoreCSE, simpl_gently]+ else [])++ vectorisation+ = runWhen vectorise_on $+ CoreDoPasses [ simpl_gently, CoreDoVectorisation ]++ -- By default, we have 2 phases before phase 0.++ -- Want to run with inline phase 2 after the specialiser to give+ -- maximum chance for fusion to work before we inline build/augment+ -- in phase 1. This made a difference in 'ansi' where an+ -- overloaded function wasn't inlined till too late.++ -- Need phase 1 so that build/augment get+ -- inlined. I found that spectral/hartel/genfft lost some useful+ -- strictness in the function sumcode' if augment is not inlined+ -- before strictness analysis runs+ simpl_phases = CoreDoPasses [ simpl_phase phase ["main"] max_iter+ | phase <- [phases, phases-1 .. 1] ]+++ -- initial simplify: mk specialiser happy: minimum effort please+ simpl_gently = CoreDoSimplify max_iter+ (base_mode { sm_phase = InitialPhase+ , sm_names = ["Gentle"]+ , sm_rules = rules_on -- Note [RULEs enabled in SimplGently]+ , sm_inline = not vectorise_on+ -- See Note [Inline in InitialPhase]+ , sm_case_case = False })+ -- Don't do case-of-case transformations.+ -- This makes full laziness work better++ strictness_pass = if ww_on+ then [CoreDoStrictness,CoreDoWorkerWrapper]+ else [CoreDoStrictness]+++ -- New demand analyser+ demand_analyser = (CoreDoPasses (+ strictness_pass +++ [simpl_phase 0 ["post-worker-wrapper"] max_iter]+ ))++ -- Static forms are moved to the top level with the FloatOut pass.+ -- See Note [Grand plan for static forms] in StaticPtrTable.+ static_ptrs_float_outwards =+ runWhen static_ptrs $ CoreDoPasses+ [ simpl_gently -- Float Out can't handle type lets (sometimes created+ -- by simpleOptPgm via mkParallelBindings)+ , CoreDoFloatOutwards FloatOutSwitches+ { floatOutLambdas = Just 0+ , floatOutConstants = True+ , floatOutOverSatApps = False+ , floatToTopLevelOnly = True+ }+ ]++ core_todo =+ if opt_level == 0 then+ [ vectorisation,+ static_ptrs_float_outwards,+ CoreDoSimplify max_iter+ (base_mode { sm_phase = Phase 0+ , sm_names = ["Non-opt simplification"] })+ ]++ else {- opt_level >= 1 -} [++ -- We want to do the static argument transform before full laziness as it+ -- may expose extra opportunities to float things outwards. However, to fix+ -- up the output of the transformation we need at do at least one simplify+ -- after this before anything else+ runWhen static_args (CoreDoPasses [ simpl_gently, CoreDoStaticArgs ]),++ -- We run vectorisation here for now, but we might also try to run+ -- it later+ vectorisation,++ -- initial simplify: mk specialiser happy: minimum effort please+ simpl_gently,++ -- Specialisation is best done before full laziness+ -- so that overloaded functions have all their dictionary lambdas manifest+ runWhen do_specialise CoreDoSpecialising,++ if full_laziness then+ CoreDoFloatOutwards FloatOutSwitches {+ floatOutLambdas = Just 0,+ floatOutConstants = True,+ floatOutOverSatApps = False,+ floatToTopLevelOnly = False }+ -- Was: gentleFloatOutSwitches+ --+ -- I have no idea why, but not floating constants to+ -- top level is very bad in some cases.+ --+ -- Notably: p_ident in spectral/rewrite+ -- Changing from "gentle" to "constantsOnly"+ -- improved rewrite's allocation by 19%, and+ -- made 0.0% difference to any other nofib+ -- benchmark+ --+ -- Not doing floatOutOverSatApps yet, we'll do+ -- that later on when we've had a chance to get more+ -- accurate arity information. In fact it makes no+ -- difference at all to performance if we do it here,+ -- but maybe we save some unnecessary to-and-fro in+ -- the simplifier.+ else+ -- Even with full laziness turned off, we still need to float static+ -- forms to the top level. See Note [Grand plan for static forms] in+ -- StaticPtrTable.+ static_ptrs_float_outwards,++ simpl_phases,++ -- Phase 0: allow all Ids to be inlined now+ -- This gets foldr inlined before strictness analysis++ -- At least 3 iterations because otherwise we land up with+ -- huge dead expressions because of an infelicity in the+ -- simpifier.+ -- let k = BIG in foldr k z xs+ -- ==> let k = BIG in letrec go = \xs -> ...(k x).... in go xs+ -- ==> let k = BIG in letrec go = \xs -> ...(BIG x).... in go xs+ -- Don't stop now!+ simpl_phase 0 ["main"] (max max_iter 3),++ runWhen do_float_in CoreDoFloatInwards,+ -- Run float-inwards immediately before the strictness analyser+ -- Doing so pushes bindings nearer their use site and hence makes+ -- them more likely to be strict. These bindings might only show+ -- up after the inlining from simplification. Example in fulsom,+ -- Csg.calc, where an arg of timesDouble thereby becomes strict.++ runWhen call_arity $ CoreDoPasses+ [ CoreDoCallArity+ , simpl_phase 0 ["post-call-arity"] max_iter+ ],++ runWhen strictness demand_analyser,++ runWhen full_laziness $+ CoreDoFloatOutwards FloatOutSwitches {+ floatOutLambdas = floatLamArgs dflags,+ floatOutConstants = True,+ floatOutOverSatApps = True,+ floatToTopLevelOnly = False },+ -- nofib/spectral/hartel/wang doubles in speed if you+ -- do full laziness late in the day. It only happens+ -- after fusion and other stuff, so the early pass doesn't+ -- catch it. For the record, the redex is+ -- f_el22 (f_el21 r_midblock)+++ runWhen cse CoreCSE,+ -- We want CSE to follow the final full-laziness pass, because it may+ -- succeed in commoning up things floated out by full laziness.+ -- CSE used to rely on the no-shadowing invariant, but it doesn't any more++ runWhen do_float_in CoreDoFloatInwards,++ maybe_rule_check (Phase 0),++ -- Case-liberation for -O2. This should be after+ -- strictness analysis and the simplification which follows it.+ runWhen liberate_case (CoreDoPasses [+ CoreLiberateCase,+ simpl_phase 0 ["post-liberate-case"] max_iter+ ]), -- Run the simplifier after LiberateCase to vastly+ -- reduce the possibility of shadowing+ -- Reason: see Note [Shadowing] in SpecConstr.hs++ runWhen spec_constr CoreDoSpecConstr,++ maybe_rule_check (Phase 0),++ -- Final clean-up simplification:+ simpl_phase 0 ["final"] max_iter,++ runWhen late_dmd_anal $ CoreDoPasses (+ strictness_pass +++ [simpl_phase 0 ["post-late-ww"] max_iter]+ ),++ -- Final run of the demand_analyser, ensures that one-shot thunks are+ -- really really one-shot thunks. Only needed if the demand analyser+ -- has run at all. See Note [Final Demand Analyser run] in DmdAnal+ -- It is EXTREMELY IMPORTANT to run this pass, otherwise execution+ -- can become /exponentially/ more expensive. See Trac #11731, #12996.+ runWhen (strictness || late_dmd_anal) CoreDoStrictness,++ maybe_rule_check (Phase 0)+ ]++ -- Remove 'CoreDoNothing' and flatten 'CoreDoPasses' for clarity.+ flatten_todos [] = []+ flatten_todos (CoreDoNothing : rest) = flatten_todos rest+ flatten_todos (CoreDoPasses passes : rest) =+ flatten_todos passes ++ flatten_todos rest+ flatten_todos (todo : rest) = todo : flatten_todos rest++-- Loading plugins++addPluginPasses :: [CoreToDo] -> CoreM [CoreToDo]+#ifndef GHCI+addPluginPasses builtin_passes+ = do { dflags <- getDynFlags+ ; let pluginMods = pluginModNames dflags+ ; unless (null pluginMods) (pluginError pluginMods)+ ; return builtin_passes }+#else+addPluginPasses builtin_passes+ = do { hsc_env <- getHscEnv+ ; named_plugins <- liftIO (loadPlugins hsc_env)+ ; foldM query_plug builtin_passes named_plugins }+ where+ query_plug todos (_, plug, options) = installCoreToDos plug options todos+#endif++{- Note [Inline in InitialPhase]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In GHC 8 and earlier we did not inline anything in the InitialPhase. But that is+confusing for users because when they say INLINE they expect the function to inline+right away.++So now we do inlining immediately, even in the InitialPhase, assuming that the+Id's Activation allows it.++This is a surprisingly big deal. Compiler performance improved a lot+when I made this change:++ perf/compiler/T5837.run T5837 [stat too good] (normal)+ perf/compiler/parsing001.run parsing001 [stat too good] (normal)+ perf/compiler/T12234.run T12234 [stat too good] (optasm)+ perf/compiler/T9020.run T9020 [stat too good] (optasm)+ perf/compiler/T3064.run T3064 [stat too good] (normal)+ perf/compiler/T9961.run T9961 [stat too good] (normal)+ perf/compiler/T13056.run T13056 [stat too good] (optasm)+ perf/compiler/T9872d.run T9872d [stat too good] (normal)+ perf/compiler/T783.run T783 [stat too good] (normal)+ perf/compiler/T12227.run T12227 [stat too good] (normal)+ perf/should_run/lazy-bs-alloc.run lazy-bs-alloc [stat too good] (normal)+ perf/compiler/T1969.run T1969 [stat too good] (normal)+ perf/compiler/T9872a.run T9872a [stat too good] (normal)+ perf/compiler/T9872c.run T9872c [stat too good] (normal)+ perf/compiler/T9872b.run T9872b [stat too good] (normal)+ perf/compiler/T9872d.run T9872d [stat too good] (normal)++Note [RULEs enabled in SimplGently]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+RULES are enabled when doing "gentle" simplification. Two reasons:++ * We really want the class-op cancellation to happen:+ op (df d1 d2) --> $cop3 d1 d2+ because this breaks the mutual recursion between 'op' and 'df'++ * I wanted the RULE+ lift String ===> ...+ to work in Template Haskell when simplifying+ splices, so we get simpler code for literal strings++But watch out: list fusion can prevent floating. So use phase control+to switch off those rules until after floating.++************************************************************************+* *+ The CoreToDo interpreter+* *+************************************************************************+-}++runCorePasses :: [CoreToDo] -> ModGuts -> CoreM ModGuts+runCorePasses passes guts+ = foldM do_pass guts passes+ where+ do_pass guts CoreDoNothing = return guts+ do_pass guts (CoreDoPasses ps) = runCorePasses ps guts+ do_pass guts pass+ = withTiming getDynFlags+ (ppr pass <+> brackets (ppr mod))+ (const ()) $ do+ { guts' <- lintAnnots (ppr pass) (doCorePass pass) guts+ ; endPass pass (mg_binds guts') (mg_rules guts')+ ; return guts' }++ mod = mg_module guts++doCorePass :: CoreToDo -> ModGuts -> CoreM ModGuts+doCorePass pass@(CoreDoSimplify {}) = {-# SCC "Simplify" #-}+ simplifyPgm pass++doCorePass CoreCSE = {-# SCC "CommonSubExpr" #-}+ doPass cseProgram++doCorePass CoreLiberateCase = {-# SCC "LiberateCase" #-}+ doPassD liberateCase++doCorePass CoreDoFloatInwards = {-# SCC "FloatInwards" #-}+ floatInwards++doCorePass (CoreDoFloatOutwards f) = {-# SCC "FloatOutwards" #-}+ doPassDUM (floatOutwards f)++doCorePass CoreDoStaticArgs = {-# SCC "StaticArgs" #-}+ doPassU doStaticArgs++doCorePass CoreDoCallArity = {-# SCC "CallArity" #-}+ doPassD callArityAnalProgram++doCorePass CoreDoStrictness = {-# SCC "NewStranal" #-}+ doPassDFM dmdAnalProgram++doCorePass CoreDoWorkerWrapper = {-# SCC "WorkWrap" #-}+ doPassDFU wwTopBinds++doCorePass CoreDoSpecialising = {-# SCC "Specialise" #-}+ specProgram++doCorePass CoreDoSpecConstr = {-# SCC "SpecConstr" #-}+ specConstrProgram++doCorePass CoreDoVectorisation = {-# SCC "Vectorise" #-}+ vectorise++doCorePass CoreDoPrintCore = observe printCore+doCorePass (CoreDoRuleCheck phase pat) = ruleCheckPass phase pat+doCorePass CoreDoNothing = return+doCorePass (CoreDoPasses passes) = runCorePasses passes++#ifdef GHCI+doCorePass (CoreDoPluginPass _ pass) = {-# SCC "Plugin" #-} pass+#endif++doCorePass pass = pprPanic "doCorePass" (ppr pass)++{-+************************************************************************+* *+\subsection{Core pass combinators}+* *+************************************************************************+-}++printCore :: DynFlags -> CoreProgram -> IO ()+printCore dflags binds+ = Err.dumpIfSet dflags True "Print Core" (pprCoreBindings binds)++ruleCheckPass :: CompilerPhase -> String -> ModGuts -> CoreM ModGuts+ruleCheckPass current_phase pat guts =+ withTiming getDynFlags+ (text "RuleCheck"<+>brackets (ppr $ mg_module guts))+ (const ()) $ do+ { rb <- getRuleBase+ ; dflags <- getDynFlags+ ; vis_orphs <- getVisibleOrphanMods+ ; liftIO $ putLogMsg dflags NoReason Err.SevDump noSrcSpan+ (defaultDumpStyle dflags)+ (ruleCheckProgram current_phase pat+ (RuleEnv rb vis_orphs) (mg_binds guts))+ ; return guts }++doPassDUM :: (DynFlags -> UniqSupply -> CoreProgram -> IO CoreProgram) -> ModGuts -> CoreM ModGuts+doPassDUM do_pass = doPassM $ \binds -> do+ dflags <- getDynFlags+ us <- getUniqueSupplyM+ liftIO $ do_pass dflags us binds++doPassDM :: (DynFlags -> CoreProgram -> IO CoreProgram) -> ModGuts -> CoreM ModGuts+doPassDM do_pass = doPassDUM (\dflags -> const (do_pass dflags))++doPassD :: (DynFlags -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts+doPassD do_pass = doPassDM (\dflags -> return . do_pass dflags)++doPassDU :: (DynFlags -> UniqSupply -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts+doPassDU do_pass = doPassDUM (\dflags us -> return . do_pass dflags us)++doPassU :: (UniqSupply -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts+doPassU do_pass = doPassDU (const do_pass)++doPassDFM :: (DynFlags -> FamInstEnvs -> CoreProgram -> IO CoreProgram) -> ModGuts -> CoreM ModGuts+doPassDFM do_pass guts = do+ dflags <- getDynFlags+ p_fam_env <- getPackageFamInstEnv+ let fam_envs = (p_fam_env, mg_fam_inst_env guts)+ doPassM (liftIO . do_pass dflags fam_envs) guts++doPassDFU :: (DynFlags -> FamInstEnvs -> UniqSupply -> CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts+doPassDFU do_pass guts = do+ dflags <- getDynFlags+ us <- getUniqueSupplyM+ p_fam_env <- getPackageFamInstEnv+ let fam_envs = (p_fam_env, mg_fam_inst_env guts)+ doPass (do_pass dflags fam_envs us) guts++-- Most passes return no stats and don't change rules: these combinators+-- let us lift them to the full blown ModGuts+CoreM world+doPassM :: Monad m => (CoreProgram -> m CoreProgram) -> ModGuts -> m ModGuts+doPassM bind_f guts = do+ binds' <- bind_f (mg_binds guts)+ return (guts { mg_binds = binds' })++doPass :: (CoreProgram -> CoreProgram) -> ModGuts -> CoreM ModGuts+doPass bind_f guts = return $ guts { mg_binds = bind_f (mg_binds guts) }++-- Observer passes just peek; don't modify the bindings at all+observe :: (DynFlags -> CoreProgram -> IO a) -> ModGuts -> CoreM ModGuts+observe do_pass = doPassM $ \binds -> do+ dflags <- getDynFlags+ _ <- liftIO $ do_pass dflags binds+ return binds++{-+************************************************************************+* *+ Gentle simplification+* *+************************************************************************+-}++simplifyExpr :: DynFlags -- includes spec of what core-to-core passes to do+ -> CoreExpr+ -> IO CoreExpr+-- simplifyExpr is called by the driver to simplify an+-- expression typed in at the interactive prompt+--+-- Also used by Template Haskell+simplifyExpr dflags expr+ = withTiming (pure dflags) (text "Simplify [expr]") (const ()) $+ do {+ ; us <- mkSplitUniqSupply 's'++ ; let sz = exprSize expr++ ; (expr', counts) <- initSmpl dflags emptyRuleEnv+ emptyFamInstEnvs us sz+ (simplExprGently (simplEnvForGHCi dflags) expr)++ ; Err.dumpIfSet dflags (dopt Opt_D_dump_simpl_stats dflags)+ "Simplifier statistics" (pprSimplCount counts)++ ; Err.dumpIfSet_dyn dflags Opt_D_dump_simpl "Simplified expression"+ (pprCoreExpr expr')++ ; return expr'+ }++simplExprGently :: SimplEnv -> CoreExpr -> SimplM CoreExpr+-- Simplifies an expression+-- does occurrence analysis, then simplification+-- and repeats (twice currently) because one pass+-- alone leaves tons of crud.+-- Used (a) for user expressions typed in at the interactive prompt+-- (b) the LHS and RHS of a RULE+-- (c) Template Haskell splices+--+-- The name 'Gently' suggests that the SimplifierMode is SimplGently,+-- and in fact that is so.... but the 'Gently' in simplExprGently doesn't+-- enforce that; it just simplifies the expression twice++-- It's important that simplExprGently does eta reduction; see+-- Note [Simplifying the left-hand side of a RULE] above. The+-- simplifier does indeed do eta reduction (it's in Simplify.completeLam)+-- but only if -O is on.++simplExprGently env expr = do+ expr1 <- simplExpr env (occurAnalyseExpr expr)+ simplExpr env (occurAnalyseExpr expr1)++{-+************************************************************************+* *+\subsection{The driver for the simplifier}+* *+************************************************************************+-}++simplifyPgm :: CoreToDo -> ModGuts -> CoreM ModGuts+simplifyPgm pass guts+ = do { hsc_env <- getHscEnv+ ; us <- getUniqueSupplyM+ ; rb <- getRuleBase+ ; liftIOWithCount $+ simplifyPgmIO pass hsc_env us rb guts }++simplifyPgmIO :: CoreToDo+ -> HscEnv+ -> UniqSupply+ -> RuleBase+ -> ModGuts+ -> IO (SimplCount, ModGuts) -- New bindings++simplifyPgmIO pass@(CoreDoSimplify max_iterations mode)+ hsc_env us hpt_rule_base+ guts@(ModGuts { mg_module = this_mod+ , mg_rdr_env = rdr_env+ , mg_deps = deps+ , mg_binds = binds, mg_rules = rules+ , mg_fam_inst_env = fam_inst_env })+ = do { (termination_msg, it_count, counts_out, guts')+ <- do_iteration us 1 [] binds rules++ ; Err.dumpIfSet dflags (dopt Opt_D_verbose_core2core dflags &&+ dopt Opt_D_dump_simpl_stats dflags)+ "Simplifier statistics for following pass"+ (vcat [text termination_msg <+> text "after" <+> ppr it_count+ <+> text "iterations",+ blankLine,+ pprSimplCount counts_out])++ ; return (counts_out, guts')+ }+ where+ dflags = hsc_dflags hsc_env+ print_unqual = mkPrintUnqualified dflags rdr_env+ simpl_env = mkSimplEnv mode+ active_rule = activeRule simpl_env++ do_iteration :: UniqSupply+ -> Int -- Counts iterations+ -> [SimplCount] -- Counts from earlier iterations, reversed+ -> CoreProgram -- Bindings in+ -> [CoreRule] -- and orphan rules+ -> IO (String, Int, SimplCount, ModGuts)++ do_iteration us iteration_no counts_so_far binds rules+ -- iteration_no is the number of the iteration we are+ -- about to begin, with '1' for the first+ | iteration_no > max_iterations -- Stop if we've run out of iterations+ = WARN( debugIsOn && (max_iterations > 2)+ , hang (text "Simplifier bailing out after" <+> int max_iterations+ <+> text "iterations"+ <+> (brackets $ hsep $ punctuate comma $+ map (int . simplCountN) (reverse counts_so_far)))+ 2 (text "Size =" <+> ppr (coreBindsStats binds)))++ -- Subtract 1 from iteration_no to get the+ -- number of iterations we actually completed+ return ( "Simplifier baled out", iteration_no - 1+ , totalise counts_so_far+ , guts { mg_binds = binds, mg_rules = rules } )++ -- Try and force thunks off the binds; significantly reduces+ -- space usage, especially with -O. JRS, 000620.+ | let sz = coreBindsSize binds+ , () <- sz `seq` () -- Force it+ = do {+ -- Occurrence analysis+ let { -- Note [Vectorisation declarations and occurrences]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- During the 'InitialPhase' (i.e., before vectorisation), we need to make sure+ -- that the right-hand sides of vectorisation declarations are taken into+ -- account during occurrence analysis. After the 'InitialPhase', we need to ensure+ -- that the binders representing variable vectorisation declarations are kept alive.+ -- (In contrast to automatically vectorised variables, their unvectorised versions+ -- don't depend on them.)+ vectVars = mkVarSet $+ catMaybes [ fmap snd $ lookupDVarEnv (vectInfoVar (mg_vect_info guts)) bndr+ | Vect bndr _ <- mg_vect_decls guts]+ +++ catMaybes [ fmap snd $ lookupDVarEnv (vectInfoVar (mg_vect_info guts)) bndr+ | bndr <- bindersOfBinds binds]+ -- FIXME: This second comprehensions is only needed as long as we+ -- have vectorised bindings where we get "Could NOT call+ -- vectorised from original version".+ ; (maybeVects, maybeVectVars)+ = case sm_phase mode of+ InitialPhase -> (mg_vect_decls guts, vectVars)+ _ -> ([], vectVars)+ ; tagged_binds = {-# SCC "OccAnal" #-}+ occurAnalysePgm this_mod active_rule rules+ maybeVects maybeVectVars binds+ } ;+ Err.dumpIfSet_dyn dflags Opt_D_dump_occur_anal "Occurrence analysis"+ (pprCoreBindings tagged_binds);++ -- Get any new rules, and extend the rule base+ -- See Note [Overall plumbing for rules] in Rules.hs+ -- We need to do this regularly, because simplification can+ -- poke on IdInfo thunks, which in turn brings in new rules+ -- behind the scenes. Otherwise there's a danger we'll simply+ -- miss the rules for Ids hidden inside imported inlinings+ eps <- hscEPS hsc_env ;+ let { rule_base1 = unionRuleBase hpt_rule_base (eps_rule_base eps)+ ; rule_base2 = extendRuleBaseList rule_base1 rules+ ; fam_envs = (eps_fam_inst_env eps, fam_inst_env)+ ; vis_orphs = this_mod : dep_orphs deps } ;++ -- Simplify the program+ ((binds1, rules1), counts1) <-+ initSmpl dflags (mkRuleEnv rule_base2 vis_orphs) fam_envs us1 sz $+ do { env1 <- {-# SCC "SimplTopBinds" #-}+ simplTopBinds simpl_env tagged_binds++ -- Apply the substitution to rules defined in this module+ -- for imported Ids. Eg RULE map my_f = blah+ -- If we have a substitution my_f :-> other_f, we'd better+ -- apply it to the rule to, or it'll never match+ ; rules1 <- simplRules env1 Nothing rules++ ; return (getFloatBinds env1, rules1) } ;++ -- Stop if nothing happened; don't dump output+ if isZeroSimplCount counts1 then+ return ( "Simplifier reached fixed point", iteration_no+ , totalise (counts1 : counts_so_far) -- Include "free" ticks+ , guts { mg_binds = binds1, mg_rules = rules1 } )+ else do {+ -- Short out indirections+ -- We do this *after* at least one run of the simplifier+ -- because indirection-shorting uses the export flag on *occurrences*+ -- and that isn't guaranteed to be ok until after the first run propagates+ -- stuff from the binding site to its occurrences+ --+ -- ToDo: alas, this means that indirection-shorting does not happen at all+ -- if the simplifier does nothing (not common, I know, but unsavoury)+ let { binds2 = {-# SCC "ZapInd" #-} shortOutIndirections binds1 } ;++ -- Dump the result of this iteration+ dump_end_iteration dflags print_unqual iteration_no counts1 binds2 rules1 ;+ lintPassResult hsc_env pass binds2 ;++ -- Loop+ do_iteration us2 (iteration_no + 1) (counts1:counts_so_far) binds2 rules1+ } }+ | otherwise = panic "do_iteration"+ where+ (us1, us2) = splitUniqSupply us++ -- Remember the counts_so_far are reversed+ totalise :: [SimplCount] -> SimplCount+ totalise = foldr (\c acc -> acc `plusSimplCount` c)+ (zeroSimplCount dflags)++simplifyPgmIO _ _ _ _ _ = panic "simplifyPgmIO"++-------------------+dump_end_iteration :: DynFlags -> PrintUnqualified -> Int+ -> SimplCount -> CoreProgram -> [CoreRule] -> IO ()+dump_end_iteration dflags print_unqual iteration_no counts binds rules+ = dumpPassResult dflags print_unqual mb_flag hdr pp_counts binds rules+ where+ mb_flag | dopt Opt_D_dump_simpl_iterations dflags = Just Opt_D_dump_simpl_iterations+ | otherwise = Nothing+ -- Show details if Opt_D_dump_simpl_iterations is on++ hdr = text "Simplifier iteration=" <> int iteration_no+ pp_counts = vcat [ text "---- Simplifier counts for" <+> hdr+ , pprSimplCount counts+ , text "---- End of simplifier counts for" <+> hdr ]++{-+************************************************************************+* *+ Shorting out indirections+* *+************************************************************************++If we have this:++ x_local = <expression>+ ...bindings...+ x_exported = x_local++where x_exported is exported, and x_local is not, then we replace it with this:++ x_exported = <expression>+ x_local = x_exported+ ...bindings...++Without this we never get rid of the x_exported = x_local thing. This+save a gratuitous jump (from \tr{x_exported} to \tr{x_local}), and+makes strictness information propagate better. This used to happen in+the final phase, but it's tidier to do it here.++Note [Transferring IdInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to propagage any useful IdInfo on x_local to x_exported.++STRICTNESS: if we have done strictness analysis, we want the strictness info on+x_local to transfer to x_exported. Hence the copyIdInfo call.++RULES: we want to *add* any RULES for x_local to x_exported.+++Note [Messing up the exported Id's RULES]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must be careful about discarding (obviously) or even merging the+RULES on the exported Id. The example that went bad on me at one stage+was this one:++ iterate :: (a -> a) -> a -> [a]+ [Exported]+ iterate = iterateList++ iterateFB c f x = x `c` iterateFB c f (f x)+ iterateList f x = x : iterateList f (f x)+ [Not exported]++ {-# RULES+ "iterate" forall f x. iterate f x = build (\c _n -> iterateFB c f x)+ "iterateFB" iterateFB (:) = iterateList+ #-}++This got shorted out to:++ iterateList :: (a -> a) -> a -> [a]+ iterateList = iterate++ iterateFB c f x = x `c` iterateFB c f (f x)+ iterate f x = x : iterate f (f x)++ {-# RULES+ "iterate" forall f x. iterate f x = build (\c _n -> iterateFB c f x)+ "iterateFB" iterateFB (:) = iterate+ #-}++And now we get an infinite loop in the rule system+ iterate f x -> build (\cn -> iterateFB c f x)+ -> iterateFB (:) f x+ -> iterate f x++Old "solution":+ use rule switching-off pragmas to get rid+ of iterateList in the first place++But in principle the user *might* want rules that only apply to the Id+he says. And inline pragmas are similar+ {-# NOINLINE f #-}+ f = local+ local = <stuff>+Then we do not want to get rid of the NOINLINE.++Hence hasShortableIdinfo.+++Note [Rules and indirection-zapping]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Problem: what if x_exported has a RULE that mentions something in ...bindings...?+Then the things mentioned can be out of scope! Solution+ a) Make sure that in this pass the usage-info from x_exported is+ available for ...bindings...+ b) If there are any such RULES, rec-ify the entire top-level.+ It'll get sorted out next time round++Other remarks+~~~~~~~~~~~~~+If more than one exported thing is equal to a local thing (i.e., the+local thing really is shared), then we do one only:+\begin{verbatim}+ x_local = ....+ x_exported1 = x_local+ x_exported2 = x_local+==>+ x_exported1 = ....++ x_exported2 = x_exported1+\end{verbatim}++We rely on prior eta reduction to simplify things like+\begin{verbatim}+ x_exported = /\ tyvars -> x_local tyvars+==>+ x_exported = x_local+\end{verbatim}+Hence,there's a possibility of leaving unchanged something like this:+\begin{verbatim}+ x_local = ....+ x_exported1 = x_local Int+\end{verbatim}+By the time we've thrown away the types in STG land this+could be eliminated. But I don't think it's very common+and it's dangerous to do this fiddling in STG land+because we might elminate a binding that's mentioned in the+unfolding for something.++Note [Indirection zapping and ticks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Unfortunately this is another place where we need a special case for+ticks. The following happens quite regularly:++ x_local = <expression>+ x_exported = tick<x> x_local++Which we want to become:++ x_exported = tick<x> <expression>++As it makes no sense to keep the tick and the expression on separate+bindings. Note however that that this might increase the ticks scoping+over the execution of x_local, so we can only do this for floatable+ticks. More often than not, other references will be unfoldings of+x_exported, and therefore carry the tick anyway.+-}++type IndEnv = IdEnv (Id, [Tickish Var]) -- Maps local_id -> exported_id, ticks++shortOutIndirections :: CoreProgram -> CoreProgram+shortOutIndirections binds+ | isEmptyVarEnv ind_env = binds+ | no_need_to_flatten = binds' -- See Note [Rules and indirect-zapping]+ | otherwise = [Rec (flattenBinds binds')] -- for this no_need_to_flatten stuff+ where+ ind_env = makeIndEnv binds+ -- These exported Ids are the subjects of the indirection-elimination+ exp_ids = map fst $ nonDetEltsUFM ind_env+ -- It's OK to use nonDetEltsUFM here because we forget the ordering+ -- by immediately converting to a set or check if all the elements+ -- satisfy a predicate.+ exp_id_set = mkVarSet exp_ids+ no_need_to_flatten = all (null . ruleInfoRules . idSpecialisation) exp_ids+ binds' = concatMap zap binds++ zap (NonRec bndr rhs) = [NonRec b r | (b,r) <- zapPair (bndr,rhs)]+ zap (Rec pairs) = [Rec (concatMap zapPair pairs)]++ zapPair (bndr, rhs)+ | bndr `elemVarSet` exp_id_set = []+ | Just (exp_id, ticks) <- lookupVarEnv ind_env bndr+ = [(transferIdInfo exp_id bndr,+ mkTicks ticks rhs),+ (bndr, Var exp_id)]+ | otherwise = [(bndr,rhs)]++makeIndEnv :: [CoreBind] -> IndEnv+makeIndEnv binds+ = foldr add_bind emptyVarEnv binds+ where+ add_bind :: CoreBind -> IndEnv -> IndEnv+ add_bind (NonRec exported_id rhs) env = add_pair (exported_id, rhs) env+ add_bind (Rec pairs) env = foldr add_pair env pairs++ add_pair :: (Id,CoreExpr) -> IndEnv -> IndEnv+ add_pair (exported_id, exported) env+ | (ticks, Var local_id) <- stripTicksTop tickishFloatable exported+ , shortMeOut env exported_id local_id+ = extendVarEnv env local_id (exported_id, ticks)+ add_pair _ env = env++-----------------+shortMeOut :: IndEnv -> Id -> Id -> Bool+shortMeOut ind_env exported_id local_id+-- The if-then-else stuff is just so I can get a pprTrace to see+-- how often I don't get shorting out because of IdInfo stuff+ = if isExportedId exported_id && -- Only if this is exported++ isLocalId local_id && -- Only if this one is defined in this+ -- module, so that we *can* change its+ -- binding to be the exported thing!++ not (isExportedId local_id) && -- Only if this one is not itself exported,+ -- since the transformation will nuke it++ not (local_id `elemVarEnv` ind_env) -- Only if not already substituted for+ then+ if hasShortableIdInfo exported_id+ then True -- See Note [Messing up the exported Id's IdInfo]+ else WARN( True, text "Not shorting out:" <+> ppr exported_id )+ False+ else+ False++-----------------+hasShortableIdInfo :: Id -> Bool+-- True if there is no user-attached IdInfo on exported_id,+-- so we can safely discard it+-- See Note [Messing up the exported Id's IdInfo]+hasShortableIdInfo id+ = isEmptyRuleInfo (ruleInfo info)+ && isDefaultInlinePragma (inlinePragInfo info)+ && not (isStableUnfolding (unfoldingInfo info))+ where+ info = idInfo id++-----------------+transferIdInfo :: Id -> Id -> Id+-- See Note [Transferring IdInfo]+-- If we have+-- lcl_id = e; exp_id = lcl_id+-- and lcl_id has useful IdInfo, we don't want to discard it by going+-- gbl_id = e; lcl_id = gbl_id+-- Instead, transfer IdInfo from lcl_id to exp_id+-- Overwriting, rather than merging, seems to work ok.+transferIdInfo exported_id local_id+ = modifyIdInfo transfer exported_id+ where+ local_info = idInfo local_id+ transfer exp_info = exp_info `setStrictnessInfo` strictnessInfo local_info+ `setUnfoldingInfo` unfoldingInfo local_info+ `setInlinePragInfo` inlinePragInfo local_info+ `setRuleInfo` addRuleInfo (ruleInfo exp_info) new_info+ new_info = setRuleInfoHead (idName exported_id)+ (ruleInfo local_info)+ -- Remember to set the function-name field of the+ -- rules as we transfer them from one function to another
+ simplCore/SimplEnv.hs view
@@ -0,0 +1,838 @@+{-+(c) The AQUA Project, Glasgow University, 1993-1998++\section[SimplMonad]{The simplifier Monad}+-}++{-# LANGUAGE CPP #-}++module SimplEnv (+ -- * The simplifier mode+ setMode, getMode, updMode,++ -- * Environments+ SimplEnv(..), StaticEnv, pprSimplEnv, -- Temp not abstract+ mkSimplEnv, extendIdSubst,+ SimplEnv.extendTvSubst, SimplEnv.extendCvSubst,+ zapSubstEnv, setSubstEnv,+ getInScope, setInScopeAndZapFloats,+ setInScopeSet, modifyInScope, addNewInScopeIds,+ getSimplRules,++ -- * Substitution results+ SimplSR(..), mkContEx, substId, lookupRecBndr, refineFromInScope,+ isJoinIdInEnv_maybe,++ -- * Simplifying 'Id' binders+ simplNonRecBndr, simplNonRecJoinBndr, simplRecBndrs, simplRecJoinBndrs,+ simplBinder, simplBinders,+ substTy, substTyVar, getTCvSubst,+ substCo, substCoVar,++ -- * Floats+ Floats, emptyFloats, isEmptyFloats,+ addNonRec, addFloats, extendFloats,+ wrapFloats, setFloats, zapFloats, addRecFloats, mapFloats,+ doFloatFromRhs, getFloatBinds,++ JoinFloats, emptyJoinFloats, isEmptyJoinFloats,+ wrapJoinFloats, zapJoinFloats, restoreJoinFloats, getJoinFloatBinds,+ ) where++#include "HsVersions.h"++import SimplMonad+import CoreMonad ( SimplifierMode(..) )+import CoreSyn+import CoreUtils+import Var+import VarEnv+import VarSet+import OrdList+import Id+import MkCore ( mkWildValBinder )+import TysWiredIn+import qualified Type+import Type hiding ( substTy, substTyVar, substTyVarBndr )+import qualified Coercion+import Coercion hiding ( substCo, substCoVar, substCoVarBndr )+import BasicTypes+import MonadUtils+import Outputable+import Util+import UniqFM ( pprUniqFM )++import Data.List++{-+************************************************************************+* *+\subsubsection{The @SimplEnv@ type}+* *+************************************************************************+-}++data SimplEnv+ = SimplEnv {+ ----------- Static part of the environment -----------+ -- Static in the sense of lexically scoped,+ -- wrt the original expression++ seMode :: SimplifierMode,++ -- The current substitution+ seTvSubst :: TvSubstEnv, -- InTyVar |--> OutType+ seCvSubst :: CvSubstEnv, -- InCoVar |--> OutCoercion+ seIdSubst :: SimplIdSubst, -- InId |--> OutExpr++ ----------- Dynamic part of the environment -----------+ -- Dynamic in the sense of describing the setup where+ -- the expression finally ends up++ -- The current set of in-scope variables+ -- They are all OutVars, and all bound in this module+ seInScope :: InScopeSet, -- OutVars only+ -- Includes all variables bound by seFloats+ seFloats :: Floats,+ -- See Note [Simplifier floats]+ seJoinFloats :: JoinFloats+ -- Handled separately; they don't go very far+ }++type StaticEnv = SimplEnv -- Just the static part is relevant++pprSimplEnv :: SimplEnv -> SDoc+-- Used for debugging; selective+pprSimplEnv env+ = vcat [text "TvSubst:" <+> ppr (seTvSubst env),+ text "CvSubst:" <+> ppr (seCvSubst env),+ text "IdSubst:" <+> id_subst_doc,+ text "InScope:" <+> in_scope_vars_doc+ ]+ where+ id_subst_doc = pprUniqFM ppr_id_subst (seIdSubst env)+ ppr_id_subst (m_ar, sr) = arity_part <+> ppr sr+ where arity_part = case m_ar of Just ar -> brackets $+ text "join" <+> int ar+ Nothing -> empty++ in_scope_vars_doc = pprVarSet (getInScopeVars (seInScope env))+ (vcat . map ppr_one)+ ppr_one v | isId v = ppr v <+> ppr (idUnfolding v)+ | otherwise = ppr v++type SimplIdSubst = IdEnv (Maybe JoinArity, SimplSR) -- IdId |--> OutExpr+ -- See Note [Extending the Subst] in CoreSubst+ -- See Note [Join arity in SimplIdSubst]++-- | A substitution result.+data SimplSR+ = DoneEx OutExpr -- Completed term+ | DoneId OutId -- Completed term variable+ | ContEx TvSubstEnv -- A suspended substitution+ CvSubstEnv+ SimplIdSubst+ InExpr++instance Outputable SimplSR where+ ppr (DoneEx e) = text "DoneEx" <+> ppr e+ ppr (DoneId v) = text "DoneId" <+> ppr v+ ppr (ContEx _tv _cv _id e) = vcat [text "ContEx" <+> ppr e {-,+ ppr (filter_env tv), ppr (filter_env id) -}]+ -- where+ -- fvs = exprFreeVars e+ -- filter_env env = filterVarEnv_Directly keep env+ -- keep uniq _ = uniq `elemUFM_Directly` fvs++{-+Note [SimplEnv invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~+seInScope:+ The in-scope part of Subst includes *all* in-scope TyVars and Ids+ The elements of the set may have better IdInfo than the+ occurrences of in-scope Ids, and (more important) they will+ have a correctly-substituted type. So we use a lookup in this+ set to replace occurrences++ The Ids in the InScopeSet are replete with their Rules,+ and as we gather info about the unfolding of an Id, we replace+ it in the in-scope set.++ The in-scope set is actually a mapping OutVar -> OutVar, and+ in case expressions we sometimes bind++seIdSubst:+ The substitution is *apply-once* only, because InIds and OutIds+ can overlap.+ For example, we generally omit mappings+ a77 -> a77+ from the substitution, when we decide not to clone a77, but it's quite+ legitimate to put the mapping in the substitution anyway.++ Furthermore, consider+ let x = case k of I# x77 -> ... in+ let y = case k of I# x77 -> ... in ...+ and suppose the body is strict in both x and y. Then the simplifier+ will pull the first (case k) to the top; so the second (case k) will+ cancel out, mapping x77 to, well, x77! But one is an in-Id and the+ other is an out-Id.++ Of course, the substitution *must* applied! Things in its domain+ simply aren't necessarily bound in the result.++* substId adds a binding (DoneId new_id) to the substitution if+ the Id's unique has changed++ Note, though that the substitution isn't necessarily extended+ if the type of the Id changes. Why not? Because of the next point:++* We *always, always* finish by looking up in the in-scope set+ any variable that doesn't get a DoneEx or DoneVar hit in the substitution.+ Reason: so that we never finish up with a "old" Id in the result.+ An old Id might point to an old unfolding and so on... which gives a space+ leak.++ [The DoneEx and DoneVar hits map to "new" stuff.]++* It follows that substExpr must not do a no-op if the substitution is empty.+ substType is free to do so, however.++* When we come to a let-binding (say) we generate new IdInfo, including an+ unfolding, attach it to the binder, and add this newly adorned binder to+ the in-scope set. So all subsequent occurrences of the binder will get+ mapped to the full-adorned binder, which is also the one put in the+ binding site.++* The in-scope "set" usually maps x->x; we use it simply for its domain.+ But sometimes we have two in-scope Ids that are synomyms, and should+ map to the same target: x->x, y->x. Notably:+ case y of x { ... }+ That's why the "set" is actually a VarEnv Var++Note [Join arity in SimplIdSubst]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We have to remember which incoming variables are join points (the occurrences+may not be marked correctly yet; we're in change of propagating the change if+OccurAnal makes something a join point). Normally the in-scope set is where we+keep the latest information, but the in-scope set tracks only OutVars; if a+binding is unconditionally inlined, it never makes it into the in-scope set,+and we need to know at the occurrence site that the variable is a join point so+that we know to drop the context. Thus we remember which join points we're+substituting. Clumsily, finding whether an InVar is a join variable may require+looking in both the substitution *and* the in-scope set (see+'isJoinIdInEnv_maybe').+-}++mkSimplEnv :: SimplifierMode -> SimplEnv+mkSimplEnv mode+ = SimplEnv { seMode = mode+ , seInScope = init_in_scope+ , seFloats = emptyFloats+ , seJoinFloats = emptyJoinFloats+ , seTvSubst = emptyVarEnv+ , seCvSubst = emptyVarEnv+ , seIdSubst = emptyVarEnv }+ -- The top level "enclosing CC" is "SUBSUMED".++init_in_scope :: InScopeSet+init_in_scope = mkInScopeSet (unitVarSet (mkWildValBinder unitTy))+ -- See Note [WildCard binders]++{-+Note [WildCard binders]+~~~~~~~~~~~~~~~~~~~~~~~+The program to be simplified may have wild binders+ case e of wild { p -> ... }+We want to *rename* them away, so that there are no+occurrences of 'wild-id' (with wildCardKey). The easy+way to do that is to start of with a representative+Id in the in-scope set++There can be be *occurrences* of wild-id. For example,+MkCore.mkCoreApp transforms+ e (a /# b) --> case (a /# b) of wild { DEFAULT -> e wild }+This is ok provided 'wild' isn't free in 'e', and that's the delicate+thing. Generally, you want to run the simplifier to get rid of the+wild-ids before doing much else.++It's a very dark corner of GHC. Maybe it should be cleaned up.+-}++getMode :: SimplEnv -> SimplifierMode+getMode env = seMode env++setMode :: SimplifierMode -> SimplEnv -> SimplEnv+setMode mode env = env { seMode = mode }++updMode :: (SimplifierMode -> SimplifierMode) -> SimplEnv -> SimplEnv+updMode upd env = env { seMode = upd (seMode env) }++---------------------+extendIdSubst :: SimplEnv -> Id -> SimplSR -> SimplEnv+extendIdSubst env@(SimplEnv {seIdSubst = subst}) var res+ = ASSERT2( isId var && not (isCoVar var), ppr var )+ env { seIdSubst = extendVarEnv subst var (isJoinId_maybe var, res) }++extendTvSubst :: SimplEnv -> TyVar -> Type -> SimplEnv+extendTvSubst env@(SimplEnv {seTvSubst = tsubst}) var res+ = ASSERT( isTyVar var )+ env {seTvSubst = extendVarEnv tsubst var res}++extendCvSubst :: SimplEnv -> CoVar -> Coercion -> SimplEnv+extendCvSubst env@(SimplEnv {seCvSubst = csubst}) var co+ = ASSERT( isCoVar var )+ env {seCvSubst = extendVarEnv csubst var co}++---------------------+getInScope :: SimplEnv -> InScopeSet+getInScope env = seInScope env++setInScopeSet :: SimplEnv -> InScopeSet -> SimplEnv+setInScopeSet env in_scope = env {seInScope = in_scope}++setInScopeAndZapFloats :: SimplEnv -> SimplEnv -> SimplEnv+-- Set the in-scope set, and *zap* the floats+setInScopeAndZapFloats env env_with_scope+ = env { seInScope = seInScope env_with_scope,+ seFloats = emptyFloats,+ seJoinFloats = emptyJoinFloats }++setFloats :: SimplEnv -> SimplEnv -> SimplEnv+-- Set the in-scope set *and* the floats+setFloats env env_with_floats+ = env { seInScope = seInScope env_with_floats,+ seFloats = seFloats env_with_floats,+ seJoinFloats = seJoinFloats env_with_floats }++restoreJoinFloats :: SimplEnv -> SimplEnv -> SimplEnv+-- Put back floats previously zapped+-- Unlike 'setFloats', does *not* update the in-scope set, since the right-hand+-- env is assumed to be *older*+restoreJoinFloats env old_env+ = env { seJoinFloats = seJoinFloats old_env }++addNewInScopeIds :: SimplEnv -> [CoreBndr] -> SimplEnv+ -- The new Ids are guaranteed to be freshly allocated+addNewInScopeIds env@(SimplEnv { seInScope = in_scope, seIdSubst = id_subst }) vs+ = env { seInScope = in_scope `extendInScopeSetList` vs,+ seIdSubst = id_subst `delVarEnvList` vs }+ -- Why delete? Consider+ -- let x = a*b in (x, \x -> x+3)+ -- We add [x |-> a*b] to the substitution, but we must+ -- _delete_ it from the substitution when going inside+ -- the (\x -> ...)!++modifyInScope :: SimplEnv -> CoreBndr -> SimplEnv+-- The variable should already be in scope, but+-- replace the existing version with this new one+-- which has more information+modifyInScope env@(SimplEnv {seInScope = in_scope}) v+ = env {seInScope = extendInScopeSet in_scope v}++---------------------+zapSubstEnv :: SimplEnv -> SimplEnv+zapSubstEnv env = env {seTvSubst = emptyVarEnv, seCvSubst = emptyVarEnv, seIdSubst = emptyVarEnv}++setSubstEnv :: SimplEnv -> TvSubstEnv -> CvSubstEnv -> SimplIdSubst -> SimplEnv+setSubstEnv env tvs cvs ids = env { seTvSubst = tvs, seCvSubst = cvs, seIdSubst = ids }++mkContEx :: SimplEnv -> InExpr -> SimplSR+mkContEx (SimplEnv { seTvSubst = tvs, seCvSubst = cvs, seIdSubst = ids }) e = ContEx tvs cvs ids e++{-+************************************************************************+* *+\subsection{Floats}+* *+************************************************************************++Note [Simplifier floats]+~~~~~~~~~~~~~~~~~~~~~~~~~+The Floats is a bunch of bindings, classified by a FloatFlag.++* All of them satisfy the let/app invariant++Examples++ NonRec x (y:ys) FltLifted+ Rec [(x,rhs)] FltLifted++ NonRec x* (p:q) FltOKSpec -- RHS is WHNF. Question: why not FltLifted?+ NonRec x# (y +# 3) FltOkSpec -- Unboxed, but ok-for-spec'n++ NonRec x* (f y) FltCareful -- Strict binding; might fail or diverge++Can't happen:+ NonRec x# (a /# b) -- Might fail; does not satisfy let/app+ NonRec x# (f y) -- Might diverge; does not satisfy let/app+-}++data Floats = Floats (OrdList OutBind) FloatFlag+ -- See Note [Simplifier floats]++type JoinFloats = OrdList OutBind++data FloatFlag+ = FltLifted -- All bindings are lifted and lazy *or*+ -- consist of a single primitive string literal+ -- Hence ok to float to top level, or recursive++ | FltOkSpec -- All bindings are FltLifted *or*+ -- strict (perhaps because unlifted,+ -- perhaps because of a strict binder),+ -- *and* ok-for-speculation+ -- Hence ok to float out of the RHS+ -- of a lazy non-recursive let binding+ -- (but not to top level, or into a rec group)++ | FltCareful -- At least one binding is strict (or unlifted)+ -- and not guaranteed cheap+ -- Do not float these bindings out of a lazy let++instance Outputable Floats where+ ppr (Floats binds ff) = ppr ff $$ ppr (fromOL binds)++instance Outputable FloatFlag where+ ppr FltLifted = text "FltLifted"+ ppr FltOkSpec = text "FltOkSpec"+ ppr FltCareful = text "FltCareful"++andFF :: FloatFlag -> FloatFlag -> FloatFlag+andFF FltCareful _ = FltCareful+andFF FltOkSpec FltCareful = FltCareful+andFF FltOkSpec _ = FltOkSpec+andFF FltLifted flt = flt++doFloatFromRhs :: TopLevelFlag -> RecFlag -> Bool -> OutExpr -> SimplEnv -> Bool+-- If you change this function look also at FloatIn.noFloatFromRhs+doFloatFromRhs lvl rec str rhs (SimplEnv {seFloats = Floats fs ff})+ = not (isNilOL fs) && want_to_float && can_float+ where+ want_to_float = isTopLevel lvl || exprIsCheap rhs || exprIsExpandable rhs+ -- See Note [Float when cheap or expandable]+ can_float = case ff of+ FltLifted -> True+ FltOkSpec -> isNotTopLevel lvl && isNonRec rec+ FltCareful -> isNotTopLevel lvl && isNonRec rec && str++{-+Note [Float when cheap or expandable]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to float a let from a let if the residual RHS is+ a) cheap, such as (\x. blah)+ b) expandable, such as (f b) if f is CONLIKE+But there are+ - cheap things that are not expandable (eg \x. expensive)+ - expandable things that are not cheap (eg (f b) where b is CONLIKE)+so we must take the 'or' of the two.+-}++emptyFloats :: Floats+emptyFloats = Floats nilOL FltLifted++emptyJoinFloats :: JoinFloats+emptyJoinFloats = nilOL++unitFloat :: OutBind -> Floats+-- This key function constructs a singleton float with the right form+unitFloat bind = ASSERT(all (not . isJoinId) (bindersOf bind))+ Floats (unitOL bind) (flag bind)+ where+ flag (Rec {}) = FltLifted+ flag (NonRec bndr rhs)+ | not (isStrictId bndr) = FltLifted+ | exprIsLiteralString rhs = FltLifted+ -- String literals can be floated freely.+ -- See Note [CoreSyn top-level string ltierals] in CoreSyn.+ | exprOkForSpeculation rhs = FltOkSpec -- Unlifted, and lifted but ok-for-spec (eg HNF)+ | otherwise = ASSERT2( not (isUnliftedType (idType bndr)), ppr bndr )+ FltCareful+ -- Unlifted binders can only be let-bound if exprOkForSpeculation holds++unitJoinFloat :: OutBind -> JoinFloats+unitJoinFloat bind = ASSERT(all isJoinId (bindersOf bind))+ unitOL bind++addNonRec :: SimplEnv -> OutId -> OutExpr -> SimplEnv+-- Add a non-recursive binding and extend the in-scope set+-- The latter is important; the binder may already be in the+-- in-scope set (although it might also have been created with newId)+-- but it may now have more IdInfo+addNonRec env id rhs+ = id `seq` -- This seq forces the Id, and hence its IdInfo,+ -- and hence any inner substitutions+ env { seFloats = floats',+ seJoinFloats = jfloats',+ seInScope = extendInScopeSet (seInScope env) id }+ where+ bind = NonRec id rhs++ floats' | isJoinId id = seFloats env+ | otherwise = seFloats env `addFlts` unitFloat bind+ jfloats' | isJoinId id = seJoinFloats env `addJoinFlts` unitJoinFloat bind+ | otherwise = seJoinFloats env++extendFloats :: SimplEnv -> OutBind -> SimplEnv+-- Add these bindings to the floats, and extend the in-scope env too+extendFloats env bind+ = ASSERT(all (not . isJoinId) (bindersOf bind))+ env { seFloats = floats',+ seJoinFloats = jfloats',+ seInScope = extendInScopeSetList (seInScope env) bndrs }+ where+ bndrs = bindersOf bind++ floats' | isJoinBind bind = seFloats env+ | otherwise = seFloats env `addFlts` unitFloat bind+ jfloats' | isJoinBind bind = seJoinFloats env `addJoinFlts`+ unitJoinFloat bind+ | otherwise = seJoinFloats env++addFloats :: SimplEnv -> SimplEnv -> SimplEnv+-- Add the floats for env2 to env1;+-- *plus* the in-scope set for env2, which is bigger+-- than that for env1+addFloats env1 env2+ = env1 {seFloats = seFloats env1 `addFlts` seFloats env2,+ seJoinFloats = seJoinFloats env1 `addJoinFlts` seJoinFloats env2,+ seInScope = seInScope env2 }++addFlts :: Floats -> Floats -> Floats+addFlts (Floats bs1 l1) (Floats bs2 l2)+ = Floats (bs1 `appOL` bs2) (l1 `andFF` l2)++addJoinFlts :: JoinFloats -> JoinFloats -> JoinFloats+addJoinFlts = appOL++zapFloats :: SimplEnv -> SimplEnv+zapFloats env = env { seFloats = emptyFloats+ , seJoinFloats = emptyJoinFloats }++zapJoinFloats :: SimplEnv -> SimplEnv+zapJoinFloats env = env { seJoinFloats = emptyJoinFloats }++addRecFloats :: SimplEnv -> SimplEnv -> SimplEnv+-- Flattens the floats from env2 into a single Rec group,+-- prepends the floats from env1, and puts the result back in env2+-- This is all very specific to the way recursive bindings are+-- handled; see Simplify.simplRecBind+addRecFloats env1 env2@(SimplEnv {seFloats = Floats bs ff+ ,seJoinFloats = jbs })+ = ASSERT2( case ff of { FltLifted -> True; _ -> False }, ppr (fromOL bs) )+ env2 {seFloats = seFloats env1 `addFlts` floats'+ ,seJoinFloats = seJoinFloats env1 `addJoinFlts` jfloats'}+ where+ floats' | isNilOL bs = emptyFloats+ | otherwise = unitFloat (Rec (flattenBinds (fromOL bs)))+ jfloats' | isNilOL jbs = emptyJoinFloats+ | otherwise = unitJoinFloat (Rec (flattenBinds (fromOL jbs)))++wrapFloats :: SimplEnv -> OutExpr -> OutExpr+-- Wrap the floats around the expression; they should all+-- satisfy the let/app invariant, so mkLets should do the job just fine+wrapFloats env@(SimplEnv {seFloats = Floats bs _}) body+ = foldrOL Let (wrapJoinFloats env body) bs+ -- Note: Always safe to put the joins on the inside since the values+ -- can't refer to them++wrapJoinFloats :: SimplEnv -> OutExpr -> OutExpr+wrapJoinFloats (SimplEnv {seJoinFloats = jbs}) body+ = foldrOL Let body jbs++getFloatBinds :: SimplEnv -> [CoreBind]+getFloatBinds env@(SimplEnv {seFloats = Floats bs _})+ = fromOL bs ++ getJoinFloatBinds env++getJoinFloatBinds :: SimplEnv -> [CoreBind]+getJoinFloatBinds (SimplEnv {seJoinFloats = jbs})+ = fromOL jbs++isEmptyFloats :: SimplEnv -> Bool+isEmptyFloats env@(SimplEnv {seFloats = Floats bs _})+ = isNilOL bs && isEmptyJoinFloats env++isEmptyJoinFloats :: SimplEnv -> Bool+isEmptyJoinFloats (SimplEnv {seJoinFloats = jbs})+ = isNilOL jbs++mapFloats :: SimplEnv -> ((Id,CoreExpr) -> (Id,CoreExpr)) -> SimplEnv+mapFloats env@SimplEnv { seFloats = Floats fs ff, seJoinFloats = jfs } fun+ = env { seFloats = Floats (mapOL app fs) ff+ , seJoinFloats = mapOL app jfs }+ where+ app (NonRec b e) = case fun (b,e) of (b',e') -> NonRec b' e'+ app (Rec bs) = Rec (map fun bs)++{-+************************************************************************+* *+ Substitution of Vars+* *+************************************************************************++Note [Global Ids in the substitution]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We look up even a global (eg imported) Id in the substitution. Consider+ case X.g_34 of b { (a,b) -> ... case X.g_34 of { (p,q) -> ...} ... }+The binder-swap in the occurrence analyser will add a binding+for a LocalId version of g (with the same unique though):+ case X.g_34 of b { (a,b) -> let g_34 = b in+ ... case X.g_34 of { (p,q) -> ...} ... }+So we want to look up the inner X.g_34 in the substitution, where we'll+find that it has been substituted by b. (Or conceivably cloned.)+-}++substId :: SimplEnv -> InId -> SimplSR+-- Returns DoneEx only on a non-Var expression+substId (SimplEnv { seInScope = in_scope, seIdSubst = ids }) v+ = case snd <$> lookupVarEnv ids v of -- Note [Global Ids in the substitution]+ Nothing -> DoneId (refineFromInScope in_scope v)+ Just (DoneId v) -> DoneId (refineFromInScope in_scope v)+ Just (DoneEx (Var v)) -> DoneId (refineFromInScope in_scope v)+ Just res -> res -- DoneEx non-var, or ContEx++ -- Get the most up-to-date thing from the in-scope set+ -- Even though it isn't in the substitution, it may be in+ -- the in-scope set with better IdInfo++isJoinIdInEnv_maybe :: SimplEnv -> InId -> Maybe JoinArity+isJoinIdInEnv_maybe (SimplEnv { seInScope = inScope, seIdSubst = ids }) v+ | not (isLocalId v) = Nothing+ | Just (m_ar, _) <- lookupVarEnv ids v = m_ar+ | Just v' <- lookupInScope inScope v = isJoinId_maybe v'+ | otherwise = WARN( True , ppr v )+ isJoinId_maybe v++refineFromInScope :: InScopeSet -> Var -> Var+refineFromInScope in_scope v+ | isLocalId v = case lookupInScope in_scope v of+ Just v' -> v'+ Nothing -> WARN( True, ppr v ) v -- This is an error!+ | otherwise = v++lookupRecBndr :: SimplEnv -> InId -> OutId+-- Look up an Id which has been put into the envt by simplRecBndrs,+-- but where we have not yet done its RHS+lookupRecBndr (SimplEnv { seInScope = in_scope, seIdSubst = ids }) v+ = case lookupVarEnv ids v of+ Just (_, DoneId v) -> v+ Just _ -> pprPanic "lookupRecBndr" (ppr v)+ Nothing -> refineFromInScope in_scope v++{-+************************************************************************+* *+\section{Substituting an Id binder}+* *+************************************************************************+++These functions are in the monad only so that they can be made strict via seq.+-}++simplBinders :: SimplEnv -> [InBndr] -> SimplM (SimplEnv, [OutBndr])+simplBinders env bndrs = mapAccumLM simplBinder env bndrs++-------------+simplBinder :: SimplEnv -> InBndr -> SimplM (SimplEnv, OutBndr)+-- Used for lambda and case-bound variables+-- Clone Id if necessary, substitute type+-- Return with IdInfo already substituted, but (fragile) occurrence info zapped+-- The substitution is extended only if the variable is cloned, because+-- we *don't* need to use it to track occurrence info.+simplBinder env bndr+ | isTyVar bndr = do { let (env', tv) = substTyVarBndr env bndr+ ; seqTyVar tv `seq` return (env', tv) }+ | otherwise = do { let (env', id) = substIdBndr Nothing env bndr+ ; seqId id `seq` return (env', id) }++---------------+simplNonRecBndr :: SimplEnv -> InBndr -> SimplM (SimplEnv, OutBndr)+-- A non-recursive let binder+simplNonRecBndr env id+ = do { let (env1, id1) = substIdBndr Nothing env id+ ; seqId id1 `seq` return (env1, id1) }++---------------+simplNonRecJoinBndr :: SimplEnv -> OutType -> InBndr+ -> SimplM (SimplEnv, OutBndr)+-- A non-recursive let binder for a join point; context being pushed inward may+-- change the type+simplNonRecJoinBndr env res_ty id+ = do { let (env1, id1) = substIdBndr (Just res_ty) env id+ ; seqId id1 `seq` return (env1, id1) }++---------------+simplRecBndrs :: SimplEnv -> [InBndr] -> SimplM SimplEnv+-- Recursive let binders+simplRecBndrs env@(SimplEnv {}) ids+ = ASSERT(all (not . isJoinId) ids)+ do { let (env1, ids1) = mapAccumL (substIdBndr Nothing) env ids+ ; seqIds ids1 `seq` return env1 }++---------------+simplRecJoinBndrs :: SimplEnv -> OutType -> [InBndr] -> SimplM SimplEnv+-- Recursive let binders for join points; context being pushed inward may+-- change types+simplRecJoinBndrs env@(SimplEnv {}) res_ty ids+ = ASSERT(all isJoinId ids)+ do { let (env1, ids1) = mapAccumL (substIdBndr (Just res_ty)) env ids+ ; seqIds ids1 `seq` return env1 }++---------------+substIdBndr :: Maybe OutType -> SimplEnv -> InBndr -> (SimplEnv, OutBndr)+-- Might be a coercion variable+substIdBndr new_res_ty env bndr+ | isCoVar bndr = substCoVarBndr env bndr+ | otherwise = substNonCoVarIdBndr new_res_ty env bndr++---------------+substNonCoVarIdBndr+ :: Maybe OutType -- New result type, if a join binder+ -> SimplEnv+ -> InBndr -- Env and binder to transform+ -> (SimplEnv, OutBndr)+-- Clone Id if necessary, substitute its type+-- Return an Id with its+-- * Type substituted+-- * UnfoldingInfo, Rules, WorkerInfo zapped+-- * Fragile OccInfo (only) zapped: Note [Robust OccInfo]+-- * Robust info, retained especially arity and demand info,+-- so that they are available to occurrences that occur in an+-- earlier binding of a letrec+--+-- For the robust info, see Note [Arity robustness]+--+-- Augment the substitution if the unique changed+-- Extend the in-scope set with the new Id+--+-- Similar to CoreSubst.substIdBndr, except that+-- the type of id_subst differs+-- all fragile info is zapped+substNonCoVarIdBndr new_res_ty+ env@(SimplEnv { seInScope = in_scope+ , seIdSubst = id_subst })+ old_id+ = ASSERT2( not (isCoVar old_id), ppr old_id )+ (env { seInScope = in_scope `extendInScopeSet` new_id,+ seIdSubst = new_subst }, new_id)+ where+ id1 = uniqAway in_scope old_id+ id2 = substIdType env id1+ id3 | Just res_ty <- new_res_ty+ = id2 `setIdType` setJoinResTy (idJoinArity id2) res_ty (idType id2)+ | otherwise+ = id2+ new_id = zapFragileIdInfo id3 -- Zaps rules, worker-info, unfolding+ -- and fragile OccInfo++ -- Extend the substitution if the unique has changed,+ -- or there's some useful occurrence information+ -- See the notes with substTyVarBndr for the delSubstEnv+ new_subst | new_id /= old_id+ = extendVarEnv id_subst old_id+ (isJoinId_maybe new_id, DoneId new_id)+ | otherwise+ = delVarEnv id_subst old_id++------------------------------------+seqTyVar :: TyVar -> ()+seqTyVar b = b `seq` ()++seqId :: Id -> ()+seqId id = seqType (idType id) `seq`+ idInfo id `seq`+ ()++seqIds :: [Id] -> ()+seqIds [] = ()+seqIds (id:ids) = seqId id `seq` seqIds ids++{-+Note [Arity robustness]+~~~~~~~~~~~~~~~~~~~~~~~+We *do* transfer the arity from from the in_id of a let binding to the+out_id. This is important, so that the arity of an Id is visible in+its own RHS. For example:+ f = \x. ....g (\y. f y)....+We can eta-reduce the arg to g, because f is a value. But that+needs to be visible.++This interacts with the 'state hack' too:+ f :: Bool -> IO Int+ f = \x. case x of+ True -> f y+ False -> \s -> ...+Can we eta-expand f? Only if we see that f has arity 1, and then we+take advantage of the 'state hack' on the result of+(f y) :: State# -> (State#, Int) to expand the arity one more.++There is a disadvantage though. Making the arity visible in the RHS+allows us to eta-reduce+ f = \x -> f x+to+ f = f+which technically is not sound. This is very much a corner case, so+I'm not worried about it. Another idea is to ensure that f's arity+never decreases; its arity started as 1, and we should never eta-reduce+below that.+++Note [Robust OccInfo]+~~~~~~~~~~~~~~~~~~~~~+It's important that we *do* retain the loop-breaker OccInfo, because+that's what stops the Id getting inlined infinitely, in the body of+the letrec.+-}+++{-+************************************************************************+* *+ Impedance matching to type substitution+* *+************************************************************************+-}++getTCvSubst :: SimplEnv -> TCvSubst+getTCvSubst (SimplEnv { seInScope = in_scope, seTvSubst = tv_env+ , seCvSubst = cv_env })+ = mkTCvSubst in_scope (tv_env, cv_env)++substTy :: SimplEnv -> Type -> Type+substTy env ty = Type.substTy (getTCvSubst env) ty++substTyVar :: SimplEnv -> TyVar -> Type+substTyVar env tv = Type.substTyVar (getTCvSubst env) tv++substTyVarBndr :: SimplEnv -> TyVar -> (SimplEnv, TyVar)+substTyVarBndr env tv+ = case Type.substTyVarBndr (getTCvSubst env) tv of+ (TCvSubst in_scope' tv_env' cv_env', tv')+ -> (env { seInScope = in_scope', seTvSubst = tv_env', seCvSubst = cv_env' }, tv')++substCoVar :: SimplEnv -> CoVar -> Coercion+substCoVar env tv = Coercion.substCoVar (getTCvSubst env) tv++substCoVarBndr :: SimplEnv -> CoVar -> (SimplEnv, CoVar)+substCoVarBndr env cv+ = case Coercion.substCoVarBndr (getTCvSubst env) cv of+ (TCvSubst in_scope' tv_env' cv_env', cv')+ -> (env { seInScope = in_scope', seTvSubst = tv_env', seCvSubst = cv_env' }, cv')++substCo :: SimplEnv -> Coercion -> Coercion+substCo env co = Coercion.substCo (getTCvSubst env) co++------------------+substIdType :: SimplEnv -> Id -> Id+substIdType (SimplEnv { seInScope = in_scope, seTvSubst = tv_env, seCvSubst = cv_env }) id+ | (isEmptyVarEnv tv_env && isEmptyVarEnv cv_env)+ || noFreeVarsOfType old_ty+ = id+ | otherwise = Id.setIdType id (Type.substTy (TCvSubst in_scope tv_env cv_env) old_ty)+ -- The tyCoVarsOfType is cheaper than it looks+ -- because we cache the free tyvars of the type+ -- in a Note in the id's type itself+ where+ old_ty = idType id
+ simplCore/SimplMonad.hs view
@@ -0,0 +1,218 @@+{-+(c) The AQUA Project, Glasgow University, 1993-1998++\section[SimplMonad]{The simplifier Monad}+-}++module SimplMonad (+ -- The monad+ SimplM,+ initSmpl, traceSmpl,+ getSimplRules, getFamEnvs,++ -- Unique supply+ MonadUnique(..), newId,++ -- Counting+ SimplCount, tick, freeTick, checkedTick,+ getSimplCount, zeroSimplCount, pprSimplCount,+ plusSimplCount, isZeroSimplCount+ ) where++import Id ( Id, mkSysLocalOrCoVar )+import Type ( Type )+import FamInstEnv ( FamInstEnv )+import CoreSyn ( RuleEnv(..) )+import UniqSupply+import DynFlags+import CoreMonad+import Outputable+import FastString+import MonadUtils+import ErrUtils+import BasicTypes ( IntWithInf, treatZeroAsInf, mkIntWithInf )+import Control.Monad ( when, liftM, ap )++{-+************************************************************************+* *+\subsection{Monad plumbing}+* *+************************************************************************++For the simplifier monad, we want to {\em thread} a unique supply and a counter.+(Command-line switches move around through the explicitly-passed SimplEnv.)+-}++newtype SimplM result+ = SM { unSM :: SimplTopEnv -- Envt that does not change much+ -> UniqSupply -- We thread the unique supply because+ -- constantly splitting it is rather expensive+ -> SimplCount+ -> IO (result, UniqSupply, SimplCount)}+ -- we only need IO here for dump output++data SimplTopEnv+ = STE { st_flags :: DynFlags+ , st_max_ticks :: IntWithInf -- Max #ticks in this simplifier run+ , st_rules :: RuleEnv+ , st_fams :: (FamInstEnv, FamInstEnv) }++initSmpl :: DynFlags -> RuleEnv -> (FamInstEnv, FamInstEnv)+ -> UniqSupply -- No init count; set to 0+ -> Int -- Size of the bindings, used to limit+ -- the number of ticks we allow+ -> SimplM a+ -> IO (a, SimplCount)++initSmpl dflags rules fam_envs us size m+ = do (result, _, count) <- unSM m env us (zeroSimplCount dflags)+ return (result, count)+ where+ env = STE { st_flags = dflags, st_rules = rules+ , st_max_ticks = computeMaxTicks dflags size+ , st_fams = fam_envs }++computeMaxTicks :: DynFlags -> Int -> IntWithInf+-- Compute the max simplifier ticks as+-- (base-size + pgm-size) * magic-multiplier * tick-factor/100+-- where+-- magic-multiplier is a constant that gives reasonable results+-- base-size is a constant to deal with size-zero programs+computeMaxTicks dflags size+ = treatZeroAsInf $+ fromInteger ((toInteger (size + base_size)+ * toInteger (tick_factor * magic_multiplier))+ `div` 100)+ where+ tick_factor = simplTickFactor dflags+ base_size = 100+ magic_multiplier = 40+ -- MAGIC NUMBER, multiplies the simplTickFactor+ -- We can afford to be generous; this is really+ -- just checking for loops, and shouldn't usually fire+ -- A figure of 20 was too small: see Trac #5539.++{-# INLINE thenSmpl #-}+{-# INLINE thenSmpl_ #-}+{-# INLINE returnSmpl #-}+++instance Functor SimplM where+ fmap = liftM++instance Applicative SimplM where+ pure = returnSmpl+ (<*>) = ap+ (*>) = thenSmpl_++instance Monad SimplM where+ (>>) = (*>)+ (>>=) = thenSmpl++returnSmpl :: a -> SimplM a+returnSmpl e = SM (\_st_env us sc -> return (e, us, sc))++thenSmpl :: SimplM a -> (a -> SimplM b) -> SimplM b+thenSmpl_ :: SimplM a -> SimplM b -> SimplM b++thenSmpl m k+ = SM $ \st_env us0 sc0 -> do+ (m_result, us1, sc1) <- unSM m st_env us0 sc0+ unSM (k m_result) st_env us1 sc1++thenSmpl_ m k+ = SM $ \st_env us0 sc0 -> do+ (_, us1, sc1) <- unSM m st_env us0 sc0+ unSM k st_env us1 sc1++-- TODO: this specializing is not allowed+-- {-# SPECIALIZE mapM :: (a -> SimplM b) -> [a] -> SimplM [b] #-}+-- {-# SPECIALIZE mapAndUnzipM :: (a -> SimplM (b, c)) -> [a] -> SimplM ([b],[c]) #-}+-- {-# SPECIALIZE mapAccumLM :: (acc -> b -> SimplM (acc,c)) -> acc -> [b] -> SimplM (acc, [c]) #-}++traceSmpl :: String -> SDoc -> SimplM ()+traceSmpl herald doc+ = do { dflags <- getDynFlags+ ; when (dopt Opt_D_dump_simpl_trace dflags) $ liftIO $+ printOutputForUser dflags alwaysQualify $+ hang (text herald) 2 doc }++{-+************************************************************************+* *+\subsection{The unique supply}+* *+************************************************************************+-}++instance MonadUnique SimplM where+ getUniqueSupplyM+ = SM (\_st_env us sc -> case splitUniqSupply us of+ (us1, us2) -> return (us1, us2, sc))++ getUniqueM+ = SM (\_st_env us sc -> case takeUniqFromSupply us of+ (u, us') -> return (u, us', sc))++ getUniquesM+ = SM (\_st_env us sc -> case splitUniqSupply us of+ (us1, us2) -> return (uniqsFromSupply us1, us2, sc))++instance HasDynFlags SimplM where+ getDynFlags = SM (\st_env us sc -> return (st_flags st_env, us, sc))++instance MonadIO SimplM where+ liftIO m = SM $ \_ us sc -> do+ x <- m+ return (x, us, sc)++getSimplRules :: SimplM RuleEnv+getSimplRules = SM (\st_env us sc -> return (st_rules st_env, us, sc))++getFamEnvs :: SimplM (FamInstEnv, FamInstEnv)+getFamEnvs = SM (\st_env us sc -> return (st_fams st_env, us, sc))++newId :: FastString -> Type -> SimplM Id+newId fs ty = do uniq <- getUniqueM+ return (mkSysLocalOrCoVar fs uniq ty)++{-+************************************************************************+* *+\subsection{Counting up what we've done}+* *+************************************************************************+-}++getSimplCount :: SimplM SimplCount+getSimplCount = SM (\_st_env us sc -> return (sc, us, sc))++tick :: Tick -> SimplM ()+tick t = SM (\st_env us sc -> let sc' = doSimplTick (st_flags st_env) t sc+ in sc' `seq` return ((), us, sc'))++checkedTick :: Tick -> SimplM ()+-- Try to take a tick, but fail if too many+checkedTick t+ = SM (\st_env us sc -> if st_max_ticks st_env <= mkIntWithInf (simplCountN sc)+ then pprPanic "Simplifier ticks exhausted" (msg sc)+ else let sc' = doSimplTick (st_flags st_env) t sc+ in sc' `seq` return ((), us, sc'))+ where+ msg sc = vcat [ text "When trying" <+> ppr t+ , text "To increase the limit, use -fsimpl-tick-factor=N (default 100)"+ , text "If you need to do this, let GHC HQ know, and what factor you needed"+ , pp_details sc+ , pprSimplCount sc ]+ pp_details sc+ | hasDetailedCounts sc = empty+ | otherwise = text "To see detailed counts use -ddump-simpl-stats"+++freeTick :: Tick -> SimplM ()+-- Record a tick, but don't add to the total tick count, which is+-- used to decide when nothing further has happened+freeTick t+ = SM (\_st_env us sc -> let sc' = doFreeSimplTick t sc+ in sc' `seq` return ((), us, sc'))
+ simplCore/SimplUtils.hs view
@@ -0,0 +1,2048 @@+{-+(c) The AQUA Project, Glasgow University, 1993-1998++\section[SimplUtils]{The simplifier utilities}+-}++{-# LANGUAGE CPP #-}++module SimplUtils (+ -- Rebuilding+ mkLam, mkCase, prepareAlts, tryEtaExpandRhs,++ -- Inlining,+ preInlineUnconditionally, postInlineUnconditionally,+ activeUnfolding, activeRule,+ getUnfoldingInRuleMatch,+ simplEnvForGHCi, updModeForStableUnfoldings, updModeForRules,++ -- The continuation type+ SimplCont(..), DupFlag(..),+ isSimplified,+ contIsDupable, contResultType, contHoleType,+ contIsTrivial, contArgs,+ countArgs,+ mkBoringStop, mkRhsStop, mkLazyArgStop, contIsRhsOrArg,+ interestingCallContext,++ -- ArgInfo+ ArgInfo(..), ArgSpec(..), mkArgInfo,+ addValArgTo, addCastTo, addTyArgTo,+ argInfoExpr, argInfoAppArgs, pushSimplifiedArgs,++ abstractFloats+ ) where++#include "HsVersions.h"++import SimplEnv+import CoreMonad ( SimplifierMode(..), Tick(..) )+import DynFlags+import CoreSyn+import qualified CoreSubst+import PprCore+import CoreFVs+import CoreUtils+import CoreArity+import CoreUnfold+import Name+import Id+import IdInfo+import Var+import Demand+import SimplMonad+import Type hiding( substTy )+import Coercion hiding( substCo )+import DataCon ( dataConWorkId )+import VarEnv+import VarSet+import BasicTypes+import Util+import MonadUtils+import Outputable+import Pair+import PrelRules+import Literal++import Control.Monad ( when )+import Data.List ( sortBy )++{-+************************************************************************+* *+ The SimplCont and DupFlag types+* *+************************************************************************++A SimplCont allows the simplifier to traverse the expression in a+zipper-like fashion. The SimplCont represents the rest of the expression,+"above" the point of interest.++You can also think of a SimplCont as an "evaluation context", using+that term in the way it is used for operational semantics. This is the+way I usually think of it, For example you'll often see a syntax for+evaluation context looking like+ C ::= [] | C e | case C of alts | C `cast` co+That's the kind of thing we are doing here, and I use that syntax in+the comments.+++Key points:+ * A SimplCont describes a *strict* context (just like+ evaluation contexts do). E.g. Just [] is not a SimplCont++ * A SimplCont describes a context that *does not* bind+ any variables. E.g. \x. [] is not a SimplCont+-}++data SimplCont+ = Stop -- An empty context, or <hole>+ OutType -- Type of the <hole>+ CallCtxt -- Tells if there is something interesting about+ -- the context, and hence the inliner+ -- should be a bit keener (see interestingCallContext)+ -- Specifically:+ -- This is an argument of a function that has RULES+ -- Inlining the call might allow the rule to fire+ -- Never ValAppCxt (use ApplyToVal instead)+ -- or CaseCtxt (use Select instead)++ | CastIt -- <hole> `cast` co+ OutCoercion -- The coercion simplified+ -- Invariant: never an identity coercion+ SimplCont++ | ApplyToVal { -- <hole> arg+ sc_dup :: DupFlag, -- See Note [DupFlag invariants]+ sc_arg :: InExpr, -- The argument,+ sc_env :: StaticEnv, -- and its static env+ sc_cont :: SimplCont }++ | ApplyToTy { -- <hole> ty+ sc_arg_ty :: OutType, -- Argument type+ sc_hole_ty :: OutType, -- Type of the function, presumably (forall a. blah)+ -- See Note [The hole type in ApplyToTy]+ sc_cont :: SimplCont }++ | Select { -- case <hole> of alts+ sc_dup :: DupFlag, -- See Note [DupFlag invariants]+ sc_bndr :: InId, -- case binder+ sc_alts :: [InAlt], -- Alternatives+ sc_env :: StaticEnv, -- and their static environment+ sc_cont :: SimplCont }++ -- The two strict forms have no DupFlag, because we never duplicate them+ | StrictBind -- (\x* \xs. e) <hole>+ InId [InBndr] -- let x* = <hole> in e+ InExpr StaticEnv -- is a special case+ SimplCont++ | StrictArg -- f e1 ..en <hole>+ ArgInfo -- Specifies f, e1..en, Whether f has rules, etc+ -- plus strictness flags for *further* args+ CallCtxt -- Whether *this* argument position is interesting+ SimplCont++ | TickIt+ (Tickish Id) -- Tick tickish <hole>+ SimplCont++data DupFlag = NoDup -- Unsimplified, might be big+ | Simplified -- Simplified+ | OkToDup -- Simplified and small++isSimplified :: DupFlag -> Bool+isSimplified NoDup = False+isSimplified _ = True -- Invariant: the subst-env is empty++perhapsSubstTy :: DupFlag -> StaticEnv -> Type -> Type+perhapsSubstTy dup env ty+ | isSimplified dup = ty+ | otherwise = substTy env ty++{-+Note [DupFlag invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~+In both (ApplyToVal dup _ env k)+ and (Select dup _ _ env k)+the following invariants hold++ (a) if dup = OkToDup, then continuation k is also ok-to-dup+ (b) if dup = OkToDup or Simplified, the subst-env is empty+ (and and hence no need to re-simplify)+-}++instance Outputable DupFlag where+ ppr OkToDup = text "ok"+ ppr NoDup = text "nodup"+ ppr Simplified = text "simpl"++instance Outputable SimplCont where+ ppr (Stop ty interesting) = text "Stop" <> brackets (ppr interesting) <+> ppr ty+ ppr (CastIt co cont ) = (text "CastIt" <+> pprOptCo co) $$ ppr cont+ ppr (TickIt t cont) = (text "TickIt" <+> ppr t) $$ ppr cont+ ppr (ApplyToTy { sc_arg_ty = ty, sc_cont = cont })+ = (text "ApplyToTy" <+> pprParendType ty) $$ ppr cont+ ppr (ApplyToVal { sc_arg = arg, sc_dup = dup, sc_cont = cont })+ = (text "ApplyToVal" <+> ppr dup <+> pprParendExpr arg)+ $$ ppr cont+ ppr (StrictBind b _ _ _ cont) = (text "StrictBind" <+> ppr b) $$ ppr cont+ ppr (StrictArg ai _ cont) = (text "StrictArg" <+> ppr (ai_fun ai)) $$ ppr cont+ ppr (Select { sc_dup = dup, sc_bndr = bndr, sc_alts = alts, sc_env = se, sc_cont = cont })+ = (text "Select" <+> ppr dup <+> ppr bndr) $$+ ifPprDebug (nest 2 $ vcat [ppr (seTvSubst se), ppr alts]) $$ ppr cont+++{- Note [The hole type in ApplyToTy]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The sc_hole_ty field of ApplyToTy records the type of the "hole" in the+continuation. It is absolutely necessary to compute contHoleType, but it is+not used for anything else (and hence may not be evaluated).++Why is it necessary for contHoleType? Consider the continuation+ ApplyToType Int (Stop Int)+corresponding to+ (<hole> @Int) :: Int+What is the type of <hole>? It could be (forall a. Int) or (forall a. a),+and there is no way to know which, so we must record it.++In a chain of applications (f @t1 @t2 @t3) we'll lazily compute exprType+for (f @t1) and (f @t1 @t2), which is potentially non-linear; but it probably+doesn't matter because we'll never compute them all.++************************************************************************+* *+ ArgInfo and ArgSpec+* *+************************************************************************+-}++data ArgInfo+ = ArgInfo {+ ai_fun :: OutId, -- The function+ ai_args :: [ArgSpec], -- ...applied to these args (which are in *reverse* order)++ ai_type :: OutType, -- Type of (f a1 ... an)++ ai_rules :: FunRules, -- Rules for this function++ ai_encl :: Bool, -- Flag saying whether this function+ -- or an enclosing one has rules (recursively)+ -- True => be keener to inline in all args++ ai_strs :: [Bool], -- Strictness of remaining arguments+ -- Usually infinite, but if it is finite it guarantees+ -- that the function diverges after being given+ -- that number of args+ ai_discs :: [Int] -- Discounts for remaining arguments; non-zero => be keener to inline+ -- Always infinite+ }++data ArgSpec+ = ValArg OutExpr -- Apply to this (coercion or value); c.f. ApplyToVal+ | TyArg { as_arg_ty :: OutType -- Apply to this type; c.f. ApplyToTy+ , as_hole_ty :: OutType } -- Type of the function (presumably forall a. blah)+ | CastBy OutCoercion -- Cast by this; c.f. CastIt++instance Outputable ArgSpec where+ ppr (ValArg e) = text "ValArg" <+> ppr e+ ppr (TyArg { as_arg_ty = ty }) = text "TyArg" <+> ppr ty+ ppr (CastBy c) = text "CastBy" <+> ppr c++addValArgTo :: ArgInfo -> OutExpr -> ArgInfo+addValArgTo ai arg = ai { ai_args = ValArg arg : ai_args ai+ , ai_type = applyTypeToArg (ai_type ai) arg+ , ai_rules = decRules (ai_rules ai) }++addTyArgTo :: ArgInfo -> OutType -> ArgInfo+addTyArgTo ai arg_ty = ai { ai_args = arg_spec : ai_args ai+ , ai_type = piResultTy poly_fun_ty arg_ty+ , ai_rules = decRules (ai_rules ai) }+ where+ poly_fun_ty = ai_type ai+ arg_spec = TyArg { as_arg_ty = arg_ty, as_hole_ty = poly_fun_ty }++addCastTo :: ArgInfo -> OutCoercion -> ArgInfo+addCastTo ai co = ai { ai_args = CastBy co : ai_args ai+ , ai_type = pSnd (coercionKind co) }++argInfoAppArgs :: [ArgSpec] -> [OutExpr]+argInfoAppArgs [] = []+argInfoAppArgs (CastBy {} : _) = [] -- Stop at a cast+argInfoAppArgs (ValArg e : as) = e : argInfoAppArgs as+argInfoAppArgs (TyArg { as_arg_ty = ty } : as) = Type ty : argInfoAppArgs as++pushSimplifiedArgs :: SimplEnv -> [ArgSpec] -> SimplCont -> SimplCont+pushSimplifiedArgs _env [] k = k+pushSimplifiedArgs env (arg : args) k+ = case arg of+ TyArg { as_arg_ty = arg_ty, as_hole_ty = hole_ty }+ -> ApplyToTy { sc_arg_ty = arg_ty, sc_hole_ty = hole_ty, sc_cont = rest }+ ValArg e -> ApplyToVal { sc_arg = e, sc_env = env, sc_dup = Simplified, sc_cont = rest }+ CastBy c -> CastIt c rest+ where+ rest = pushSimplifiedArgs env args k+ -- The env has an empty SubstEnv++argInfoExpr :: OutId -> [ArgSpec] -> OutExpr+-- NB: the [ArgSpec] is reversed so that the first arg+-- in the list is the last one in the application+argInfoExpr fun rev_args+ = go rev_args+ where+ go [] = Var fun+ go (ValArg a : as) = go as `App` a+ go (TyArg { as_arg_ty = ty } : as) = go as `App` Type ty+ go (CastBy co : as) = mkCast (go as) co+++type FunRules = Maybe (Int, [CoreRule]) -- Remaining rules for this function+ -- Nothing => No rules+ -- Just (n, rules) => some rules, requiring at least n more type/value args++decRules :: FunRules -> FunRules+decRules (Just (n, rules)) = Just (n-1, rules)+decRules Nothing = Nothing++mkFunRules :: [CoreRule] -> FunRules+mkFunRules [] = Nothing+mkFunRules rs = Just (n_required, rs)+ where+ n_required = maximum (map ruleArity rs)++{-+************************************************************************+* *+ Functions on SimplCont+* *+************************************************************************+-}++mkBoringStop :: OutType -> SimplCont+mkBoringStop ty = Stop ty BoringCtxt++mkRhsStop :: OutType -> SimplCont -- See Note [RHS of lets] in CoreUnfold+mkRhsStop ty = Stop ty RhsCtxt++mkLazyArgStop :: OutType -> CallCtxt -> SimplCont+mkLazyArgStop ty cci = Stop ty cci++-------------------+contIsRhsOrArg :: SimplCont -> Bool+contIsRhsOrArg (Stop {}) = True+contIsRhsOrArg (StrictBind {}) = True+contIsRhsOrArg (StrictArg {}) = True+contIsRhsOrArg _ = False++contIsRhs :: SimplCont -> Bool+contIsRhs (Stop _ RhsCtxt) = True+contIsRhs _ = False++-------------------+contIsDupable :: SimplCont -> Bool+contIsDupable (Stop {}) = True+contIsDupable (ApplyToTy { sc_cont = k }) = contIsDupable k+contIsDupable (ApplyToVal { sc_dup = OkToDup }) = True -- See Note [DupFlag invariants]+contIsDupable (Select { sc_dup = OkToDup }) = True -- ...ditto...+contIsDupable (CastIt _ k) = contIsDupable k+contIsDupable _ = False++-------------------+contIsTrivial :: SimplCont -> Bool+contIsTrivial (Stop {}) = True+contIsTrivial (ApplyToTy { sc_cont = k }) = contIsTrivial k+contIsTrivial (ApplyToVal { sc_arg = Coercion _, sc_cont = k }) = contIsTrivial k+contIsTrivial (CastIt _ k) = contIsTrivial k+contIsTrivial _ = False++-------------------+contResultType :: SimplCont -> OutType+contResultType (Stop ty _) = ty+contResultType (CastIt _ k) = contResultType k+contResultType (StrictBind _ _ _ _ k) = contResultType k+contResultType (StrictArg _ _ k) = contResultType k+contResultType (Select { sc_cont = k }) = contResultType k+contResultType (ApplyToTy { sc_cont = k }) = contResultType k+contResultType (ApplyToVal { sc_cont = k }) = contResultType k+contResultType (TickIt _ k) = contResultType k++contHoleType :: SimplCont -> OutType+contHoleType (Stop ty _) = ty+contHoleType (TickIt _ k) = contHoleType k+contHoleType (CastIt co _) = pFst (coercionKind co)+contHoleType (StrictBind b _ _ se _) = substTy se (idType b)+contHoleType (StrictArg ai _ _) = funArgTy (ai_type ai)+contHoleType (ApplyToTy { sc_hole_ty = ty }) = ty -- See Note [The hole type in ApplyToTy]+contHoleType (ApplyToVal { sc_arg = e, sc_env = se, sc_dup = dup, sc_cont = k })+ = mkFunTy (perhapsSubstTy dup se (exprType e))+ (contHoleType k)+contHoleType (Select { sc_dup = d, sc_bndr = b, sc_env = se })+ = perhapsSubstTy d se (idType b)++-------------------+countArgs :: SimplCont -> Int+-- Count all arguments, including types, coercions, and other values+countArgs (ApplyToTy { sc_cont = cont }) = 1 + countArgs cont+countArgs (ApplyToVal { sc_cont = cont }) = 1 + countArgs cont+countArgs _ = 0++contArgs :: SimplCont -> (Bool, [ArgSummary], SimplCont)+-- Summarises value args, discards type args and coercions+-- The returned continuation of the call is only used to+-- answer questions like "are you interesting?"+contArgs cont+ | lone cont = (True, [], cont)+ | otherwise = go [] cont+ where+ lone (ApplyToTy {}) = False -- See Note [Lone variables] in CoreUnfold+ lone (ApplyToVal {}) = False+ lone (CastIt {}) = False+ lone _ = True++ go args (ApplyToVal { sc_arg = arg, sc_env = se, sc_cont = k })+ = go (is_interesting arg se : args) k+ go args (ApplyToTy { sc_cont = k }) = go args k+ go args (CastIt _ k) = go args k+ go args k = (False, reverse args, k)++ is_interesting arg se = interestingArg se arg+ -- Do *not* use short-cutting substitution here+ -- because we want to get as much IdInfo as possible+++-------------------+mkArgInfo :: Id+ -> [CoreRule] -- Rules for function+ -> Int -- Number of value args+ -> SimplCont -- Context of the call+ -> ArgInfo++mkArgInfo fun rules n_val_args call_cont+ | n_val_args < idArity fun -- Note [Unsaturated functions]+ = ArgInfo { ai_fun = fun, ai_args = [], ai_type = fun_ty+ , ai_rules = fun_rules, ai_encl = False+ , ai_strs = vanilla_stricts+ , ai_discs = vanilla_discounts }+ | otherwise+ = ArgInfo { ai_fun = fun, ai_args = [], ai_type = fun_ty+ , ai_rules = fun_rules+ , ai_encl = interestingArgContext rules call_cont+ , ai_strs = add_type_str fun_ty arg_stricts+ , ai_discs = arg_discounts }+ where+ fun_ty = idType fun++ fun_rules = mkFunRules rules++ vanilla_discounts, arg_discounts :: [Int]+ vanilla_discounts = repeat 0+ arg_discounts = case idUnfolding fun of+ CoreUnfolding {uf_guidance = UnfIfGoodArgs {ug_args = discounts}}+ -> discounts ++ vanilla_discounts+ _ -> vanilla_discounts++ vanilla_stricts, arg_stricts :: [Bool]+ vanilla_stricts = repeat False++ arg_stricts+ = case splitStrictSig (idStrictness fun) of+ (demands, result_info)+ | not (demands `lengthExceeds` n_val_args)+ -> -- Enough args, use the strictness given.+ -- For bottoming functions we used to pretend that the arg+ -- is lazy, so that we don't treat the arg as an+ -- interesting context. This avoids substituting+ -- top-level bindings for (say) strings into+ -- calls to error. But now we are more careful about+ -- inlining lone variables, so its ok (see SimplUtils.analyseCont)+ if isBotRes result_info then+ map isStrictDmd demands -- Finite => result is bottom+ else+ map isStrictDmd demands ++ vanilla_stricts+ | otherwise+ -> WARN( True, text "More demands than arity" <+> ppr fun <+> ppr (idArity fun)+ <+> ppr n_val_args <+> ppr demands )+ vanilla_stricts -- Not enough args, or no strictness++ add_type_str :: Type -> [Bool] -> [Bool]+ -- If the function arg types are strict, record that in the 'strictness bits'+ -- No need to instantiate because unboxed types (which dominate the strict+ -- types) can't instantiate type variables.+ -- add_type_str is done repeatedly (for each call); might be better+ -- once-for-all in the function+ -- But beware primops/datacons with no strictness++ add_type_str+ = go+ where+ go _ [] = []+ go fun_ty strs -- Look through foralls+ | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty -- Includes coercions+ = go fun_ty' strs+ go fun_ty (str:strs) -- Add strict-type info+ | Just (arg_ty, fun_ty') <- splitFunTy_maybe fun_ty+ = (str || Just False == isLiftedType_maybe arg_ty) : go fun_ty' strs+ -- If the type is levity-polymorphic, we can't know whether it's+ -- strict. isLiftedType_maybe will return Just False only when+ -- we're sure the type is unlifted.+ go _ strs+ = strs++{- Note [Unsaturated functions]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (test eyeball/inline4)+ x = a:as+ y = f x+where f has arity 2. Then we do not want to inline 'x', because+it'll just be floated out again. Even if f has lots of discounts+on its first argument -- it must be saturated for these to kick in+-}+++{-+************************************************************************+* *+ Interesting arguments+* *+************************************************************************++Note [Interesting call context]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to avoid inlining an expression where there can't possibly be+any gain, such as in an argument position. Hence, if the continuation+is interesting (eg. a case scrutinee, application etc.) then we+inline, otherwise we don't.++Previously some_benefit used to return True only if the variable was+applied to some value arguments. This didn't work:++ let x = _coerce_ (T Int) Int (I# 3) in+ case _coerce_ Int (T Int) x of+ I# y -> ....++we want to inline x, but can't see that it's a constructor in a case+scrutinee position, and some_benefit is False.++Another example:++dMonadST = _/\_ t -> :Monad (g1 _@_ t, g2 _@_ t, g3 _@_ t)++.... case dMonadST _@_ x0 of (a,b,c) -> ....++we'd really like to inline dMonadST here, but we *don't* want to+inline if the case expression is just++ case x of y { DEFAULT -> ... }++since we can just eliminate this case instead (x is in WHNF). Similar+applies when x is bound to a lambda expression. Hence+contIsInteresting looks for case expressions with just a single+default case.+-}++interestingCallContext :: SimplCont -> CallCtxt+-- See Note [Interesting call context]+interestingCallContext cont+ = interesting cont+ where+ interesting (Select {}) = CaseCtxt+ interesting (ApplyToVal {}) = ValAppCtxt+ -- Can happen if we have (f Int |> co) y+ -- If f has an INLINE prag we need to give it some+ -- motivation to inline. See Note [Cast then apply]+ -- in CoreUnfold++ interesting (StrictArg _ BoringCtxt _) = RhsCtxt+ interesting (StrictArg _ cci _) = cci+ interesting (StrictBind {}) = BoringCtxt+ interesting (Stop _ cci) = cci+ interesting (TickIt _ k) = interesting k+ interesting (ApplyToTy { sc_cont = k }) = interesting k+ interesting (CastIt _ k) = interesting k+ -- If this call is the arg of a strict function, the context+ -- is a bit interesting. If we inline here, we may get useful+ -- evaluation information to avoid repeated evals: e.g.+ -- x + (y * z)+ -- Here the contIsInteresting makes the '*' keener to inline,+ -- which in turn exposes a constructor which makes the '+' inline.+ -- Assuming that +,* aren't small enough to inline regardless.+ --+ -- It's also very important to inline in a strict context for things+ -- like+ -- foldr k z (f x)+ -- Here, the context of (f x) is strict, and if f's unfolding is+ -- a build it's *great* to inline it here. So we must ensure that+ -- the context for (f x) is not totally uninteresting.++interestingArgContext :: [CoreRule] -> SimplCont -> Bool+-- If the argument has form (f x y), where x,y are boring,+-- and f is marked INLINE, then we don't want to inline f.+-- But if the context of the argument is+-- g (f x y)+-- where g has rules, then we *do* want to inline f, in case it+-- exposes a rule that might fire. Similarly, if the context is+-- h (g (f x x))+-- where h has rules, then we do want to inline f; hence the+-- call_cont argument to interestingArgContext+--+-- The ai-rules flag makes this happen; if it's+-- set, the inliner gets just enough keener to inline f+-- regardless of how boring f's arguments are, if it's marked INLINE+--+-- The alternative would be to *always* inline an INLINE function,+-- regardless of how boring its context is; but that seems overkill+-- For example, it'd mean that wrapper functions were always inlined+--+-- The call_cont passed to interestingArgContext is the context of+-- the call itself, e.g. g <hole> in the example above+interestingArgContext rules call_cont+ = notNull rules || enclosing_fn_has_rules+ where+ enclosing_fn_has_rules = go call_cont++ go (Select {}) = False+ go (ApplyToVal {}) = False -- Shouldn't really happen+ go (ApplyToTy {}) = False -- Ditto+ go (StrictArg _ cci _) = interesting cci+ go (StrictBind {}) = False -- ??+ go (CastIt _ c) = go c+ go (Stop _ cci) = interesting cci+ go (TickIt _ c) = go c++ interesting RuleArgCtxt = True+ interesting _ = False+++{- Note [Interesting arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+An argument is interesting if it deserves a discount for unfoldings+with a discount in that argument position. The idea is to avoid+unfolding a function that is applied only to variables that have no+unfolding (i.e. they are probably lambda bound): f x y z There is+little point in inlining f here.++Generally, *values* (like (C a b) and (\x.e)) deserve discounts. But+we must look through lets, eg (let x = e in C a b), because the let will+float, exposing the value, if we inline. That makes it different to+exprIsHNF.++Before 2009 we said it was interesting if the argument had *any* structure+at all; i.e. (hasSomeUnfolding v). But does too much inlining; see Trac #3016.++But we don't regard (f x y) as interesting, unless f is unsaturated.+If it's saturated and f hasn't inlined, then it's probably not going+to now!++Note [Conlike is interesting]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f d = ...((*) d x y)...+ ... f (df d')...+where df is con-like. Then we'd really like to inline 'f' so that the+rule for (*) (df d) can fire. To do this+ a) we give a discount for being an argument of a class-op (eg (*) d)+ b) we say that a con-like argument (eg (df d)) is interesting+-}++interestingArg :: SimplEnv -> CoreExpr -> ArgSummary+-- See Note [Interesting arguments]+interestingArg env e = go env 0 e+ where+ -- n is # value args to which the expression is applied+ go env n (Var v)+ | SimplEnv { seIdSubst = ids, seInScope = in_scope } <- env+ = case snd <$> lookupVarEnv ids v of+ Nothing -> go_var n (refineFromInScope in_scope v)+ Just (DoneId v') -> go_var n (refineFromInScope in_scope v')+ Just (DoneEx e) -> go (zapSubstEnv env) n e+ Just (ContEx tvs cvs ids e) -> go (setSubstEnv env tvs cvs ids) n e++ go _ _ (Lit {}) = ValueArg+ go _ _ (Type _) = TrivArg+ go _ _ (Coercion _) = TrivArg+ go env n (App fn (Type _)) = go env n fn+ go env n (App fn _) = go env (n+1) fn+ go env n (Tick _ a) = go env n a+ go env n (Cast e _) = go env n e+ go env n (Lam v e)+ | isTyVar v = go env n e+ | n>0 = NonTrivArg -- (\x.b) e is NonTriv+ | otherwise = ValueArg+ go _ _ (Case {}) = NonTrivArg+ go env n (Let b e) = case go env' n e of+ ValueArg -> ValueArg+ _ -> NonTrivArg+ where+ env' = env `addNewInScopeIds` bindersOf b++ go_var n v+ | isConLikeId v = ValueArg -- Experimenting with 'conlike' rather that+ -- data constructors here+ | idArity v > n = ValueArg -- Catches (eg) primops with arity but no unfolding+ | n > 0 = NonTrivArg -- Saturated or unknown call+ | conlike_unfolding = ValueArg -- n==0; look for an interesting unfolding+ -- See Note [Conlike is interesting]+ | otherwise = TrivArg -- n==0, no useful unfolding+ where+ conlike_unfolding = isConLikeUnfolding (idUnfolding v)++{-+************************************************************************+* *+ SimplifierMode+* *+************************************************************************++The SimplifierMode controls several switches; see its definition in+CoreMonad+ sm_rules :: Bool -- Whether RULES are enabled+ sm_inline :: Bool -- Whether inlining is enabled+ sm_case_case :: Bool -- Whether case-of-case is enabled+ sm_eta_expand :: Bool -- Whether eta-expansion is enabled+-}++simplEnvForGHCi :: DynFlags -> SimplEnv+simplEnvForGHCi dflags+ = mkSimplEnv $ SimplMode { sm_names = ["GHCi"]+ , sm_phase = InitialPhase+ , sm_rules = rules_on+ , sm_inline = False+ , sm_eta_expand = eta_expand_on+ , sm_case_case = True }+ where+ rules_on = gopt Opt_EnableRewriteRules dflags+ eta_expand_on = gopt Opt_DoLambdaEtaExpansion dflags+ -- Do not do any inlining, in case we expose some unboxed+ -- tuple stuff that confuses the bytecode interpreter++updModeForStableUnfoldings :: Activation -> SimplifierMode -> SimplifierMode+-- See Note [Simplifying inside stable unfoldings]+updModeForStableUnfoldings inline_rule_act current_mode+ = current_mode { sm_phase = phaseFromActivation inline_rule_act+ , sm_inline = True+ , sm_eta_expand = False }+ -- sm_eta_expand: see Note [No eta expansion in stable unfoldings]+ -- For sm_rules, just inherit; sm_rules might be "off"+ -- because of -fno-enable-rewrite-rules+ where+ phaseFromActivation (ActiveAfter _ n) = Phase n+ phaseFromActivation _ = InitialPhase++updModeForRules :: SimplifierMode -> SimplifierMode+-- See Note [Simplifying rules]+updModeForRules current_mode+ = current_mode { sm_phase = InitialPhase+ , sm_inline = False+ , sm_rules = False+ , sm_eta_expand = False }++{- Note [Simplifying rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When simplifying a rule LHS, refrain from /any/ inlining or applying+of other RULES.++Doing anything to the LHS is plain confusing, because it means that what the+rule matches is not what the user wrote. c.f. Trac #10595, and #10528.+Moreover, inlining (or applying rules) on rule LHSs risks introducing+Ticks into the LHS, which makes matching trickier. Trac #10665, #10745.++Doing this to either side confounds tools like HERMIT, which seek to reason+about and apply the RULES as originally written. See Trac #10829.++Note [No eta expansion in stable unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have a stable unfolding++ f :: Ord a => a -> IO ()+ -- Unfolding template+ -- = /\a \(d:Ord a) (x:a). bla++we do not want to eta-expand to++ f :: Ord a => a -> IO ()+ -- Unfolding template+ -- = (/\a \(d:Ord a) (x:a) (eta:State#). bla eta) |> co++because not specialisation of the overloading doesn't work properly+(see Note [Specialisation shape] in Specialise), Trac #9509.++So we disable eta-expansion in stable unfoldings.++Note [Inlining in gentle mode]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Something is inlined if+ (i) the sm_inline flag is on, AND+ (ii) the thing has an INLINE pragma, AND+ (iii) the thing is inlinable in the earliest phase.++Example of why (iii) is important:+ {-# INLINE [~1] g #-}+ g = ...++ {-# INLINE f #-}+ f x = g (g x)++If we were to inline g into f's inlining, then an importing module would+never be able to do+ f e --> g (g e) ---> RULE fires+because the stable unfolding for f has had g inlined into it.++On the other hand, it is bad not to do ANY inlining into an+stable unfolding, because then recursive knots in instance declarations+don't get unravelled.++However, *sometimes* SimplGently must do no call-site inlining at all+(hence sm_inline = False). Before full laziness we must be careful+not to inline wrappers, because doing so inhibits floating+ e.g. ...(case f x of ...)...+ ==> ...(case (case x of I# x# -> fw x#) of ...)...+ ==> ...(case x of I# x# -> case fw x# of ...)...+and now the redex (f x) isn't floatable any more.++The no-inlining thing is also important for Template Haskell. You might be+compiling in one-shot mode with -O2; but when TH compiles a splice before+running it, we don't want to use -O2. Indeed, we don't want to inline+anything, because the byte-code interpreter might get confused about+unboxed tuples and suchlike.++Note [Simplifying inside stable unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must take care with simplification inside stable unfoldings (which come from+INLINE pragmas).++First, consider the following example+ let f = \pq -> BIG+ in+ let g = \y -> f y y+ {-# INLINE g #-}+ in ...g...g...g...g...g...+Now, if that's the ONLY occurrence of f, it might be inlined inside g,+and thence copied multiple times when g is inlined. HENCE we treat+any occurrence in a stable unfolding as a multiple occurrence, not a single+one; see OccurAnal.addRuleUsage.++Second, we do want *do* to some modest rules/inlining stuff in stable+unfoldings, partly to eliminate senseless crap, and partly to break+the recursive knots generated by instance declarations.++However, suppose we have+ {-# INLINE <act> f #-}+ f = <rhs>+meaning "inline f in phases p where activation <act>(p) holds".+Then what inlinings/rules can we apply to the copy of <rhs> captured in+f's stable unfolding? Our model is that literally <rhs> is substituted for+f when it is inlined. So our conservative plan (implemented by+updModeForStableUnfoldings) is this:++ -------------------------------------------------------------+ When simplifying the RHS of an stable unfolding, set the phase+ to the phase in which the stable unfolding first becomes active+ -------------------------------------------------------------++That ensures that++ a) Rules/inlinings that *cease* being active before p will+ not apply to the stable unfolding, consistent with it being+ inlined in its *original* form in phase p.++ b) Rules/inlinings that only become active *after* p will+ not apply to the stable unfolding, again to be consistent with+ inlining the *original* rhs in phase p.++For example,+ {-# INLINE f #-}+ f x = ...g...++ {-# NOINLINE [1] g #-}+ g y = ...++ {-# RULE h g = ... #-}+Here we must not inline g into f's RHS, even when we get to phase 0,+because when f is later inlined into some other module we want the+rule for h to fire.++Similarly, consider+ {-# INLINE f #-}+ f x = ...g...++ g y = ...+and suppose that there are auto-generated specialisations and a strictness+wrapper for g. The specialisations get activation AlwaysActive, and the+strictness wrapper get activation (ActiveAfter 0). So the strictness+wrepper fails the test and won't be inlined into f's stable unfolding. That+means f can inline, expose the specialised call to g, so the specialisation+rules can fire.++A note about wrappers+~~~~~~~~~~~~~~~~~~~~~+It's also important not to inline a worker back into a wrapper.+A wrapper looks like+ wraper = inline_me (\x -> ...worker... )+Normally, the inline_me prevents the worker getting inlined into+the wrapper (initially, the worker's only call site!). But,+if the wrapper is sure to be called, the strictness analyser will+mark it 'demanded', so when the RHS is simplified, it'll get an ArgOf+continuation.+-}++activeUnfolding :: SimplEnv -> Id -> Bool+activeUnfolding env id+ | isCompulsoryUnfolding (realIdUnfolding id)+ = True -- Even sm_inline can't override compulsory unfoldings+ | otherwise+ = isActive (sm_phase mode) (idInlineActivation id)+ && sm_inline mode+ -- `or` isStableUnfolding (realIdUnfolding id)+ -- Inline things when+ -- (a) they are active+ -- (b) sm_inline says so, except that for stable unfoldings+ -- (ie pragmas) we inline anyway+ where+ mode = getMode env++getUnfoldingInRuleMatch :: SimplEnv -> InScopeEnv+-- When matching in RULE, we want to "look through" an unfolding+-- (to see a constructor) if *rules* are on, even if *inlinings*+-- are not. A notable example is DFuns, which really we want to+-- match in rules like (op dfun) in gentle mode. Another example+-- is 'otherwise' which we want exprIsConApp_maybe to be able to+-- see very early on+getUnfoldingInRuleMatch env+ = (in_scope, id_unf)+ where+ in_scope = seInScope env+ mode = getMode env+ id_unf id | unf_is_active id = idUnfolding id+ | otherwise = NoUnfolding+ unf_is_active id+ | not (sm_rules mode) = -- active_unfolding_minimal id+ isStableUnfolding (realIdUnfolding id)+ -- Do we even need to test this? I think this InScopeEnv+ -- is only consulted if activeRule returns True, which+ -- never happens if sm_rules is False+ | otherwise = isActive (sm_phase mode) (idInlineActivation id)++----------------------+activeRule :: SimplEnv -> Activation -> Bool+-- Nothing => No rules at all+activeRule env+ | not (sm_rules mode) = \_ -> False -- Rewriting is off+ | otherwise = isActive (sm_phase mode)+ where+ mode = getMode env++{-+************************************************************************+* *+ preInlineUnconditionally+* *+************************************************************************++preInlineUnconditionally+~~~~~~~~~~~~~~~~~~~~~~~~+@preInlineUnconditionally@ examines a bndr to see if it is used just+once in a completely safe way, so that it is safe to discard the+binding inline its RHS at the (unique) usage site, REGARDLESS of how+big the RHS might be. If this is the case we don't simplify the RHS+first, but just inline it un-simplified.++This is much better than first simplifying a perhaps-huge RHS and then+inlining and re-simplifying it. Indeed, it can be at least quadratically+better. Consider++ x1 = e1+ x2 = e2[x1]+ x3 = e3[x2]+ ...etc...+ xN = eN[xN-1]++We may end up simplifying e1 N times, e2 N-1 times, e3 N-3 times etc.+This can happen with cascades of functions too:++ f1 = \x1.e1+ f2 = \xs.e2[f1]+ f3 = \xs.e3[f3]+ ...etc...++THE MAIN INVARIANT is this:++ ---- preInlineUnconditionally invariant -----+ IF preInlineUnconditionally chooses to inline x = <rhs>+ THEN doing the inlining should not change the occurrence+ info for the free vars of <rhs>+ ----------------------------------------------++For example, it's tempting to look at trivial binding like+ x = y+and inline it unconditionally. But suppose x is used many times,+but this is the unique occurrence of y. Then inlining x would change+y's occurrence info, which breaks the invariant. It matters: y+might have a BIG rhs, which will now be dup'd at every occurrenc of x.+++Even RHSs labelled InlineMe aren't caught here, because there might be+no benefit from inlining at the call site.++[Sept 01] Don't unconditionally inline a top-level thing, because that+can simply make a static thing into something built dynamically. E.g.+ x = (a,b)+ main = \s -> h x++[Remember that we treat \s as a one-shot lambda.] No point in+inlining x unless there is something interesting about the call site.++But watch out: if you aren't careful, some useful foldr/build fusion+can be lost (most notably in spectral/hartel/parstof) because the+foldr didn't see the build. Doing the dynamic allocation isn't a big+deal, in fact, but losing the fusion can be. But the right thing here+seems to be to do a callSiteInline based on the fact that there is+something interesting about the call site (it's strict). Hmm. That+seems a bit fragile.++Conclusion: inline top level things gaily until Phase 0 (the last+phase), at which point don't.++Note [pre/postInlineUnconditionally in gentle mode]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Even in gentle mode we want to do preInlineUnconditionally. The+reason is that too little clean-up happens if you don't inline+use-once things. Also a bit of inlining is *good* for full laziness;+it can expose constant sub-expressions. Example in+spectral/mandel/Mandel.hs, where the mandelset function gets a useful+let-float if you inline windowToViewport++However, as usual for Gentle mode, do not inline things that are+inactive in the intial stages. See Note [Gentle mode].++Note [Stable unfoldings and preInlineUnconditionally]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Surprisingly, do not pre-inline-unconditionally Ids with INLINE pragmas!+Example++ {-# INLINE f #-}+ f :: Eq a => a -> a+ f x = ...++ fInt :: Int -> Int+ fInt = f Int dEqInt++ ...fInt...fInt...fInt...++Here f occurs just once, in the RHS of fInt. But if we inline it there+it might make fInt look big, and we'll lose the opportunity to inline f+at each of fInt's call sites. The INLINE pragma will only inline when+the application is saturated for exactly this reason; and we don't+want PreInlineUnconditionally to second-guess it. A live example is+Trac #3736.+ c.f. Note [Stable unfoldings and postInlineUnconditionally]++Note [Top-level bottoming Ids]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Don't inline top-level Ids that are bottoming, even if they are used just+once, because FloatOut has gone to some trouble to extract them out.+Inlining them won't make the program run faster!++Note [Do not inline CoVars unconditionally]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Coercion variables appear inside coercions, and the RHS of a let-binding+is a term (not a coercion) so we can't necessarily inline the latter in+the former.+-}++preInlineUnconditionally :: DynFlags -> SimplEnv -> TopLevelFlag -> InId -> InExpr -> Bool+-- Precondition: rhs satisfies the let/app invariant+-- See Note [CoreSyn let/app invariant] in CoreSyn+-- Reason: we don't want to inline single uses, or discard dead bindings,+-- for unlifted, side-effect-ful bindings+preInlineUnconditionally dflags env top_lvl bndr rhs+ | not active = False+ | isStableUnfolding (idUnfolding bndr) = False -- Note [Stable unfoldings and preInlineUnconditionally]+ | isTopLevel top_lvl && isBottomingId bndr = False -- Note [Top-level bottoming Ids]+ | not (gopt Opt_SimplPreInlining dflags) = False+ | isCoVar bndr = False -- Note [Do not inline CoVars unconditionally]+ | otherwise = case idOccInfo bndr of+ IAmDead -> True -- Happens in ((\x.1) v)+ occ@OneOcc { occ_one_br = True }+ -> try_once (occ_in_lam occ)+ (occ_int_cxt occ)+ _ -> False+ where+ mode = getMode env+ active = isActive (sm_phase mode) act+ -- See Note [pre/postInlineUnconditionally in gentle mode]+ act = idInlineActivation bndr+ try_once in_lam int_cxt -- There's one textual occurrence+ | not in_lam = isNotTopLevel top_lvl || early_phase+ | otherwise = int_cxt && canInlineInLam rhs++-- Be very careful before inlining inside a lambda, because (a) we must not+-- invalidate occurrence information, and (b) we want to avoid pushing a+-- single allocation (here) into multiple allocations (inside lambda).+-- Inlining a *function* with a single *saturated* call would be ok, mind you.+-- || (if is_cheap && not (canInlineInLam rhs) then pprTrace "preinline" (ppr bndr <+> ppr rhs) ok else ok)+-- where+-- is_cheap = exprIsCheap rhs+-- ok = is_cheap && int_cxt++ -- int_cxt The context isn't totally boring+ -- E.g. let f = \ab.BIG in \y. map f xs+ -- Don't want to substitute for f, because then we allocate+ -- its closure every time the \y is called+ -- But: let f = \ab.BIG in \y. map (f y) xs+ -- Now we do want to substitute for f, even though it's not+ -- saturated, because we're going to allocate a closure for+ -- (f y) every time round the loop anyhow.++ -- canInlineInLam => free vars of rhs are (Once in_lam) or Many,+ -- so substituting rhs inside a lambda doesn't change the occ info.+ -- Sadly, not quite the same as exprIsHNF.+ canInlineInLam (Lit _) = True+ canInlineInLam (Lam b e) = isRuntimeVar b || canInlineInLam e+ canInlineInLam (Tick t e) = not (tickishIsCode t) && canInlineInLam e+ canInlineInLam _ = False+ -- not ticks. Counting ticks cannot be duplicated, and non-counting+ -- ticks around a Lam will disappear anyway.++ early_phase = case sm_phase mode of+ Phase 0 -> False+ _ -> True+-- If we don't have this early_phase test, consider+-- x = length [1,2,3]+-- The full laziness pass carefully floats all the cons cells to+-- top level, and preInlineUnconditionally floats them all back in.+-- Result is (a) static allocation replaced by dynamic allocation+-- (b) many simplifier iterations because this tickles+-- a related problem; only one inlining per pass+--+-- On the other hand, I have seen cases where top-level fusion is+-- lost if we don't inline top level thing (e.g. string constants)+-- Hence the test for phase zero (which is the phase for all the final+-- simplifications). Until phase zero we take no special notice of+-- top level things, but then we become more leery about inlining+-- them.++{-+************************************************************************+* *+ postInlineUnconditionally+* *+************************************************************************++postInlineUnconditionally+~~~~~~~~~~~~~~~~~~~~~~~~~+@postInlineUnconditionally@ decides whether to unconditionally inline+a thing based on the form of its RHS; in particular if it has a+trivial RHS. If so, we can inline and discard the binding altogether.++NB: a loop breaker has must_keep_binding = True and non-loop-breakers+only have *forward* references. Hence, it's safe to discard the binding++NOTE: This isn't our last opportunity to inline. We're at the binding+site right now, and we'll get another opportunity when we get to the+occurrence(s)++Note that we do this unconditional inlining only for trival RHSs.+Don't inline even WHNFs inside lambdas; doing so may simply increase+allocation when the function is called. This isn't the last chance; see+NOTE above.++NB: Even inline pragmas (e.g. IMustBeINLINEd) are ignored here Why?+Because we don't even want to inline them into the RHS of constructor+arguments. See NOTE above++NB: At one time even NOINLINE was ignored here: if the rhs is trivial+it's best to inline it anyway. We often get a=E; b=a from desugaring,+with both a and b marked NOINLINE. But that seems incompatible with+our new view that inlining is like a RULE, so I'm sticking to the 'active'+story for now.+-}++postInlineUnconditionally+ :: DynFlags -> SimplEnv -> TopLevelFlag+ -> OutId -- The binder (an InId would be fine too)+ -- (*not* a CoVar)+ -> OccInfo -- From the InId+ -> OutExpr+ -> Unfolding+ -> Bool+-- Precondition: rhs satisfies the let/app invariant+-- See Note [CoreSyn let/app invariant] in CoreSyn+-- Reason: we don't want to inline single uses, or discard dead bindings,+-- for unlifted, side-effect-ful bindings+postInlineUnconditionally dflags env top_lvl bndr occ_info rhs unfolding+ | not active = False+ | isWeakLoopBreaker occ_info = False -- If it's a loop-breaker of any kind, don't inline+ -- because it might be referred to "earlier"+ | isStableUnfolding unfolding = False -- Note [Stable unfoldings and postInlineUnconditionally]+ | isTopLevel top_lvl = False -- Note [Top level and postInlineUnconditionally]+ | exprIsTrivial rhs = True+ | otherwise+ = case occ_info of+ -- The point of examining occ_info here is that for *non-values*+ -- that occur outside a lambda, the call-site inliner won't have+ -- a chance (because it doesn't know that the thing+ -- only occurs once). The pre-inliner won't have gotten+ -- it either, if the thing occurs in more than one branch+ -- So the main target is things like+ -- let x = f y in+ -- case v of+ -- True -> case x of ...+ -- False -> case x of ...+ -- This is very important in practice; e.g. wheel-seive1 doubles+ -- in allocation if you miss this out+ OneOcc { occ_in_lam = in_lam, occ_int_cxt = int_cxt }+ -- OneOcc => no code-duplication issue+ -> smallEnoughToInline dflags unfolding -- Small enough to dup+ -- ToDo: consider discount on smallEnoughToInline if int_cxt is true+ --+ -- NB: Do NOT inline arbitrarily big things, even if one_br is True+ -- Reason: doing so risks exponential behaviour. We simplify a big+ -- expression, inline it, and simplify it again. But if the+ -- very same thing happens in the big expression, we get+ -- exponential cost!+ -- PRINCIPLE: when we've already simplified an expression once,+ -- make sure that we only inline it if it's reasonably small.++ && (not in_lam ||+ -- Outside a lambda, we want to be reasonably aggressive+ -- about inlining into multiple branches of case+ -- e.g. let x = <non-value>+ -- in case y of { C1 -> ..x..; C2 -> ..x..; C3 -> ... }+ -- Inlining can be a big win if C3 is the hot-spot, even if+ -- the uses in C1, C2 are not 'interesting'+ -- An example that gets worse if you add int_cxt here is 'clausify'++ (isCheapUnfolding unfolding && int_cxt))+ -- isCheap => acceptable work duplication; in_lam may be true+ -- int_cxt to prevent us inlining inside a lambda without some+ -- good reason. See the notes on int_cxt in preInlineUnconditionally++ IAmDead -> True -- This happens; for example, the case_bndr during case of+ -- known constructor: case (a,b) of x { (p,q) -> ... }+ -- Here x isn't mentioned in the RHS, so we don't want to+ -- create the (dead) let-binding let x = (a,b) in ...++ _ -> False++-- Here's an example that we don't handle well:+-- let f = if b then Left (\x.BIG) else Right (\y.BIG)+-- in \y. ....case f of {...} ....+-- Here f is used just once, and duplicating the case work is fine (exprIsCheap).+-- But+-- - We can't preInlineUnconditionally because that woud invalidate+-- the occ info for b.+-- - We can't postInlineUnconditionally because the RHS is big, and+-- that risks exponential behaviour+-- - We can't call-site inline, because the rhs is big+-- Alas!++ where+ active = isActive (sm_phase (getMode env)) (idInlineActivation bndr)+ -- See Note [pre/postInlineUnconditionally in gentle mode]++{-+Note [Top level and postInlineUnconditionally]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't do postInlineUnconditionally for top-level things (even for+ones that are trivial):++ * Doing so will inline top-level error expressions that have been+ carefully floated out by FloatOut. More generally, it might+ replace static allocation with dynamic.++ * Even for trivial expressions there's a problem. Consider+ {-# RULE "foo" forall (xs::[T]). reverse xs = ruggle xs #-}+ blah xs = reverse xs+ ruggle = sort+ In one simplifier pass we might fire the rule, getting+ blah xs = ruggle xs+ but in *that* simplifier pass we must not do postInlineUnconditionally+ on 'ruggle' because then we'll have an unbound occurrence of 'ruggle'++ If the rhs is trivial it'll be inlined by callSiteInline, and then+ the binding will be dead and discarded by the next use of OccurAnal++ * There is less point, because the main goal is to get rid of local+ bindings used in multiple case branches.++ * The inliner should inline trivial things at call sites anyway.++ * The Id might be exported. We could check for that separately,+ but since we aren't going to postInlineUnconditionally /any/+ top-level bindings, we don't need to test.++Note [Stable unfoldings and postInlineUnconditionally]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Do not do postInlineUnconditionally if the Id has an stable unfolding,+otherwise we lose the unfolding. Example++ -- f has stable unfolding with rhs (e |> co)+ -- where 'e' is big+ f = e |> co++Then there's a danger we'll optimise to++ f' = e+ f = f' |> co++and now postInlineUnconditionally, losing the stable unfolding on f. Now f'+won't inline because 'e' is too big.++ c.f. Note [Stable unfoldings and preInlineUnconditionally]+++************************************************************************+* *+ Rebuilding a lambda+* *+************************************************************************+-}++mkLam :: SimplEnv -> [OutBndr] -> OutExpr -> SimplCont -> SimplM OutExpr+-- mkLam tries three things+-- a) eta reduction, if that gives a trivial expression+-- b) eta expansion [only if there are some value lambdas]++mkLam _env [] body _cont+ = return body+mkLam env bndrs body cont+ = do { dflags <- getDynFlags+ ; mkLam' dflags bndrs body }+ where+ mkLam' :: DynFlags -> [OutBndr] -> OutExpr -> SimplM OutExpr+ mkLam' dflags bndrs (Cast body co)+ | not (any bad bndrs)+ -- Note [Casts and lambdas]+ = do { lam <- mkLam' dflags bndrs body+ ; return (mkCast lam (mkPiCos Representational bndrs co)) }+ where+ co_vars = tyCoVarsOfCo co+ bad bndr = isCoVar bndr && bndr `elemVarSet` co_vars++ mkLam' dflags bndrs body@(Lam {})+ = mkLam' dflags (bndrs ++ bndrs1) body1+ where+ (bndrs1, body1) = collectBinders body++ mkLam' dflags bndrs (Tick t expr)+ | tickishFloatable t+ = mkTick t <$> mkLam' dflags bndrs expr++ mkLam' dflags bndrs body+ | gopt Opt_DoEtaReduction dflags+ , Just etad_lam <- tryEtaReduce bndrs body+ = do { tick (EtaReduction (head bndrs))+ ; return etad_lam }++ | not (contIsRhs cont) -- See Note [Eta-expanding lambdas]+ , sm_eta_expand (getMode env)+ , any isRuntimeVar bndrs+ , let body_arity = exprEtaExpandArity dflags body+ , body_arity > 0+ = do { tick (EtaExpansion (head bndrs))+ ; let res = mkLams bndrs (etaExpand body_arity body)+ ; traceSmpl "eta expand" (vcat [text "before" <+> ppr (mkLams bndrs body)+ , text "after" <+> ppr res])+ ; return res }++ | otherwise+ = return (mkLams bndrs body)++{-+Note [Eta expanding lambdas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general we *do* want to eta-expand lambdas. Consider+ f (\x -> case x of (a,b) -> \s -> blah)+where 's' is a state token, and hence can be eta expanded. This+showed up in the code for GHc.IO.Handle.Text.hPutChar, a rather+important function!++The eta-expansion will never happen unless we do it now. (Well, it's+possible that CorePrep will do it, but CorePrep only has a half-baked+eta-expander that can't deal with casts. So it's much better to do it+here.)++However, when the lambda is let-bound, as the RHS of a let, we have a+better eta-expander (in the form of tryEtaExpandRhs), so we don't+bother to try expansion in mkLam in that case; hence the contIsRhs+guard.++NB: We check the SimplEnv (sm_eta_expand), not DynFlags.+ See Note [No eta expansion in stable unfoldings]++Note [Casts and lambdas]+~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ (\x. (\y. e) `cast` g1) `cast` g2+There is a danger here that the two lambdas look separated, and the+full laziness pass might float an expression to between the two.++So this equation in mkLam' floats the g1 out, thus:+ (\x. e `cast` g1) --> (\x.e) `cast` (tx -> g1)+where x:tx.++In general, this floats casts outside lambdas, where (I hope) they+might meet and cancel with some other cast:+ \x. e `cast` co ===> (\x. e) `cast` (tx -> co)+ /\a. e `cast` co ===> (/\a. e) `cast` (/\a. co)+ /\g. e `cast` co ===> (/\g. e) `cast` (/\g. co)+ (if not (g `in` co))++Notice that it works regardless of 'e'. Originally it worked only+if 'e' was itself a lambda, but in some cases that resulted in+fruitless iteration in the simplifier. A good example was when+compiling Text.ParserCombinators.ReadPrec, where we had a definition+like (\x. Get `cast` g)+where Get is a constructor with nonzero arity. Then mkLam eta-expanded+the Get, and the next iteration eta-reduced it, and then eta-expanded+it again.++Note also the side condition for the case of coercion binders.+It does not make sense to transform+ /\g. e `cast` g ==> (/\g.e) `cast` (/\g.g)+because the latter is not well-kinded.++************************************************************************+* *+ Eta expansion+* *+************************************************************************+-}++tryEtaExpandRhs :: SimplEnv -> RecFlag -> OutId -> OutExpr+ -> SimplM (Arity, OutExpr)+-- See Note [Eta-expanding at let bindings]+tryEtaExpandRhs env is_rec bndr rhs+ = do { dflags <- getDynFlags+ ; (new_arity, new_rhs) <- try_expand dflags++ ; WARN( new_arity < old_id_arity,+ (text "Arity decrease:" <+> (ppr bndr <+> ppr old_id_arity+ <+> ppr old_arity <+> ppr new_arity) $$ ppr new_rhs) )+ -- Note [Arity decrease] in Simplify+ return (new_arity, new_rhs) }+ where+ try_expand dflags+ | exprIsTrivial rhs+ = return (exprArity rhs, rhs)++ | sm_eta_expand (getMode env) -- Provided eta-expansion is on+ , let new_arity1 = findRhsArity dflags bndr rhs old_arity+ new_arity2 = idCallArity bndr+ new_arity = max new_arity1 new_arity2+ , new_arity > old_arity -- And the current manifest arity isn't enough+ = if is_rec == Recursive && isJoinId bndr+ then WARN(True, text "Can't eta-expand recursive join point:" <+>+ ppr bndr)+ return (old_arity, rhs)+ else do { tick (EtaExpansion bndr)+ ; return (new_arity, etaExpand new_arity rhs) }+ | otherwise+ = return (old_arity, rhs)++ old_arity = exprArity rhs -- See Note [Do not expand eta-expand PAPs]+ old_id_arity = idArity bndr++{-+Note [Eta-expanding at let bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We now eta expand at let-bindings, which is where the payoff comes.+The most significant thing is that we can do a simple arity analysis+(in CoreArity.findRhsArity), which we can't do for free-floating lambdas++One useful consequence of not eta-expanding lambdas is this example:+ genMap :: C a => ...+ {-# INLINE genMap #-}+ genMap f xs = ...++ myMap :: D a => ...+ {-# INLINE myMap #-}+ myMap = genMap++Notice that 'genMap' should only inline if applied to two arguments.+In the stable unfolding for myMap we'll have the unfolding+ (\d -> genMap Int (..d..))+We do not want to eta-expand to+ (\d f xs -> genMap Int (..d..) f xs)+because then 'genMap' will inline, and it really shouldn't: at least+as far as the programmer is concerned, it's not applied to two+arguments!++Note [Do not eta-expand PAPs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We used to have old_arity = manifestArity rhs, which meant that we+would eta-expand even PAPs. But this gives no particular advantage,+and can lead to a massive blow-up in code size, exhibited by Trac #9020.+Suppose we have a PAP+ foo :: IO ()+ foo = returnIO ()+Then we can eta-expand do+ foo = (\eta. (returnIO () |> sym g) eta) |> g+where+ g :: IO () ~ State# RealWorld -> (# State# RealWorld, () #)++But there is really no point in doing this, and it generates masses of+coercions and whatnot that eventually disappear again. For T9020, GHC+allocated 6.6G beore, and 0.8G afterwards; and residency dropped from+1.8G to 45M.++But note that this won't eta-expand, say+ f = \g -> map g+Does it matter not eta-expanding such functions? I'm not sure. Perhaps+strictness analysis will have less to bite on?+++************************************************************************+* *+\subsection{Floating lets out of big lambdas}+* *+************************************************************************++Note [Floating and type abstraction]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:+ x = /\a. C e1 e2+We'd like to float this to+ y1 = /\a. e1+ y2 = /\a. e2+ x = /\a. C (y1 a) (y2 a)+for the usual reasons: we want to inline x rather vigorously.++You may think that this kind of thing is rare. But in some programs it is+common. For example, if you do closure conversion you might get:++ data a :-> b = forall e. (e -> a -> b) :$ e++ f_cc :: forall a. a :-> a+ f_cc = /\a. (\e. id a) :$ ()++Now we really want to inline that f_cc thing so that the+construction of the closure goes away.++So I have elaborated simplLazyBind to understand right-hand sides that look+like+ /\ a1..an. body++and treat them specially. The real work is done in SimplUtils.abstractFloats,+but there is quite a bit of plumbing in simplLazyBind as well.++The same transformation is good when there are lets in the body:++ /\abc -> let(rec) x = e in b+ ==>+ let(rec) x' = /\abc -> let x = x' a b c in e+ in+ /\abc -> let x = x' a b c in b++This is good because it can turn things like:++ let f = /\a -> letrec g = ... g ... in g+into+ letrec g' = /\a -> ... g' a ...+ in+ let f = /\ a -> g' a++which is better. In effect, it means that big lambdas don't impede+let-floating.++This optimisation is CRUCIAL in eliminating the junk introduced by+desugaring mutually recursive definitions. Don't eliminate it lightly!++[May 1999] If we do this transformation *regardless* then we can+end up with some pretty silly stuff. For example,++ let+ st = /\ s -> let { x1=r1 ; x2=r2 } in ...+ in ..+becomes+ let y1 = /\s -> r1+ y2 = /\s -> r2+ st = /\s -> ...[y1 s/x1, y2 s/x2]+ in ..++Unless the "..." is a WHNF there is really no point in doing this.+Indeed it can make things worse. Suppose x1 is used strictly,+and is of the form++ x1* = case f y of { (a,b) -> e }++If we abstract this wrt the tyvar we then can't do the case inline+as we would normally do.++That's why the whole transformation is part of the same process that+floats let-bindings and constructor arguments out of RHSs. In particular,+it is guarded by the doFloatFromRhs call in simplLazyBind.++Note [Which type variables to abstract over]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Abstract only over the type variables free in the rhs wrt which the+new binding is abstracted. Note that++ * The naive approach of abstracting wrt the+ tyvars free in the Id's /type/ fails. Consider:+ /\ a b -> let t :: (a,b) = (e1, e2)+ x :: a = fst t+ in ...+ Here, b isn't free in x's type, but we must nevertheless+ abstract wrt b as well, because t's type mentions b.+ Since t is floated too, we'd end up with the bogus:+ poly_t = /\ a b -> (e1, e2)+ poly_x = /\ a -> fst (poly_t a *b*)++ * We must do closeOverKinds. Example (Trac #10934):+ f = /\k (f:k->*) (a:k). let t = AccFailure @ (f a) in ...+ Here we want to float 't', but we must remember to abstract over+ 'k' as well, even though it is not explicitly mentioned in the RHS,+ otherwise we get+ t = /\ (f:k->*) (a:k). AccFailure @ (f a)+ which is obviously bogus.+-}++abstractFloats :: [OutTyVar] -> SimplEnv -> OutExpr -> SimplM ([OutBind], OutExpr)+abstractFloats main_tvs body_env body+ = ASSERT( notNull body_floats )+ do { (subst, float_binds) <- mapAccumLM abstract empty_subst body_floats+ ; return (float_binds, CoreSubst.substExpr (text "abstract_floats1") subst body) }+ where+ main_tv_set = mkVarSet main_tvs+ body_floats = getFloatBinds body_env+ empty_subst = CoreSubst.mkEmptySubst (seInScope body_env)++ abstract :: CoreSubst.Subst -> OutBind -> SimplM (CoreSubst.Subst, OutBind)+ abstract subst (NonRec id rhs)+ = do { (poly_id, poly_app) <- mk_poly tvs_here id+ ; let poly_rhs = mkLams tvs_here rhs'+ subst' = CoreSubst.extendIdSubst subst id poly_app+ ; return (subst', (NonRec poly_id poly_rhs)) }+ where+ rhs' = CoreSubst.substExpr (text "abstract_floats2") subst rhs++ -- tvs_here: see Note [Which type variables to abstract over]+ tvs_here = toposortTyVars $+ filter (`elemVarSet` main_tv_set) $+ closeOverKindsList $+ exprSomeFreeVarsList isTyVar rhs'++ abstract subst (Rec prs)+ = do { (poly_ids, poly_apps) <- mapAndUnzipM (mk_poly tvs_here) ids+ ; let subst' = CoreSubst.extendSubstList subst (ids `zip` poly_apps)+ poly_rhss = [mkLams tvs_here (CoreSubst.substExpr (text "abstract_floats3") subst' rhs)+ | rhs <- rhss]+ ; return (subst', Rec (poly_ids `zip` poly_rhss)) }+ where+ (ids,rhss) = unzip prs+ -- For a recursive group, it's a bit of a pain to work out the minimal+ -- set of tyvars over which to abstract:+ -- /\ a b c. let x = ...a... in+ -- letrec { p = ...x...q...+ -- q = .....p...b... } in+ -- ...+ -- Since 'x' is abstracted over 'a', the {p,q} group must be abstracted+ -- over 'a' (because x is replaced by (poly_x a)) as well as 'b'.+ -- Since it's a pain, we just use the whole set, which is always safe+ --+ -- If you ever want to be more selective, remember this bizarre case too:+ -- x::a = x+ -- Here, we must abstract 'x' over 'a'.+ tvs_here = toposortTyVars main_tvs++ mk_poly tvs_here var+ = do { uniq <- getUniqueM+ ; let poly_name = setNameUnique (idName var) uniq -- Keep same name+ poly_ty = mkInvForAllTys tvs_here (idType var) -- But new type of course+ poly_id = transferPolyIdInfo var tvs_here $ -- Note [transferPolyIdInfo] in Id.hs+ mkLocalIdOrCoVar poly_name poly_ty+ ; return (poly_id, mkTyApps (Var poly_id) (mkTyVarTys tvs_here)) }+ -- In the olden days, it was crucial to copy the occInfo of the original var,+ -- because we were looking at occurrence-analysed but as yet unsimplified code!+ -- In particular, we mustn't lose the loop breakers. BUT NOW we are looking+ -- at already simplified code, so it doesn't matter+ --+ -- It's even right to retain single-occurrence or dead-var info:+ -- Suppose we started with /\a -> let x = E in B+ -- where x occurs once in B. Then we transform to:+ -- let x' = /\a -> E in /\a -> let x* = x' a in B+ -- where x* has an INLINE prag on it. Now, once x* is inlined,+ -- the occurrences of x' will be just the occurrences originally+ -- pinned on x.++{-+Note [Abstract over coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If a coercion variable (g :: a ~ Int) is free in the RHS, then so is the+type variable a. Rather than sort this mess out, we simply bale out and abstract+wrt all the type variables if any of them are coercion variables.+++Historical note: if you use let-bindings instead of a substitution, beware of this:++ -- Suppose we start with:+ --+ -- x = /\ a -> let g = G in E+ --+ -- Then we'll float to get+ --+ -- x = let poly_g = /\ a -> G+ -- in /\ a -> let g = poly_g a in E+ --+ -- But now the occurrence analyser will see just one occurrence+ -- of poly_g, not inside a lambda, so the simplifier will+ -- PreInlineUnconditionally poly_g back into g! Badk to square 1!+ -- (I used to think that the "don't inline lone occurrences" stuff+ -- would stop this happening, but since it's the *only* occurrence,+ -- PreInlineUnconditionally kicks in first!)+ --+ -- Solution: put an INLINE note on g's RHS, so that poly_g seems+ -- to appear many times. (NB: mkInlineMe eliminates+ -- such notes on trivial RHSs, so do it manually.)++************************************************************************+* *+ prepareAlts+* *+************************************************************************++prepareAlts tries these things:++1. Eliminate alternatives that cannot match, including the+ DEFAULT alternative.++2. If the DEFAULT alternative can match only one possible constructor,+ then make that constructor explicit.+ e.g.+ case e of x { DEFAULT -> rhs }+ ===>+ case e of x { (a,b) -> rhs }+ where the type is a single constructor type. This gives better code+ when rhs also scrutinises x or e.++3. Returns a list of the constructors that cannot holds in the+ DEFAULT alternative (if there is one)++Here "cannot match" includes knowledge from GADTs++It's a good idea to do this stuff before simplifying the alternatives, to+avoid simplifying alternatives we know can't happen, and to come up with+the list of constructors that are handled, to put into the IdInfo of the+case binder, for use when simplifying the alternatives.++Eliminating the default alternative in (1) isn't so obvious, but it can+happen:++data Colour = Red | Green | Blue++f x = case x of+ Red -> ..+ Green -> ..+ DEFAULT -> h x++h y = case y of+ Blue -> ..+ DEFAULT -> [ case y of ... ]++If we inline h into f, the default case of the inlined h can't happen.+If we don't notice this, we may end up filtering out *all* the cases+of the inner case y, which give us nowhere to go!+-}++prepareAlts :: OutExpr -> OutId -> [InAlt] -> SimplM ([AltCon], [InAlt])+-- The returned alternatives can be empty, none are possible+prepareAlts scrut case_bndr' alts+ | Just (tc, tys) <- splitTyConApp_maybe (varType case_bndr')+ -- Case binder is needed just for its type. Note that as an+ -- OutId, it has maximum information; this is important.+ -- Test simpl013 is an example+ = do { us <- getUniquesM+ ; let (idcs1, alts1) = filterAlts tc tys imposs_cons alts+ (yes2, alts2) = refineDefaultAlt us tc tys idcs1 alts1+ (yes3, idcs3, alts3) = combineIdenticalAlts idcs1 alts2+ -- "idcs" stands for "impossible default data constructors"+ -- i.e. the constructors that can't match the default case+ ; when yes2 $ tick (FillInCaseDefault case_bndr')+ ; when yes3 $ tick (AltMerge case_bndr')+ ; return (idcs3, alts3) }++ | otherwise -- Not a data type, so nothing interesting happens+ = return ([], alts)+ where+ imposs_cons = case scrut of+ Var v -> otherCons (idUnfolding v)+ _ -> []+++{-+************************************************************************+* *+ mkCase+* *+************************************************************************++mkCase tries these things++1. Merge Nested Cases++ case e of b { ==> case e of b {+ p1 -> rhs1 p1 -> rhs1+ ... ...+ pm -> rhsm pm -> rhsm+ _ -> case b of b' { pn -> let b'=b in rhsn+ pn -> rhsn ...+ ... po -> let b'=b in rhso+ po -> rhso _ -> let b'=b in rhsd+ _ -> rhsd+ }++ which merges two cases in one case when -- the default alternative of+ the outer case scrutises the same variable as the outer case. This+ transformation is called Case Merging. It avoids that the same+ variable is scrutinised multiple times.++2. Eliminate Identity Case++ case e of ===> e+ True -> True;+ False -> False++ and similar friends.++3. Scrutinee Constant Folding++ case x op# k# of _ { ===> case x of _ {+ a1# -> e1 (a1# inv_op# k#) -> e1+ a2# -> e2 (a2# inv_op# k#) -> e2+ ... ...+ DEFAULT -> ed DEFAULT -> ed++ where (x op# k#) inv_op# k# == x++ And similarly for commuted arguments and for some unary operations.++ The purpose of this transformation is not only to avoid an arithmetic+ operation at runtime but to allow other transformations to apply in cascade.++ Example with the "Merge Nested Cases" optimization (from #12877):++ main = case t of t0+ 0## -> ...+ DEFAULT -> case t0 `minusWord#` 1## of t1+ 0## -> ...+ DEFAUT -> case t1 `minusWord#` 1## of t2+ 0## -> ...+ DEFAULT -> case t2 `minusWord#` 1## of _+ 0## -> ...+ DEFAULT -> ...++ becomes:++ main = case t of _+ 0## -> ...+ 1## -> ...+ 2## -> ...+ 3## -> ...+ DEFAULT -> ...++-}++mkCase, mkCase1, mkCase2, mkCase3+ :: DynFlags+ -> OutExpr -> OutId+ -> OutType -> [OutAlt] -- Alternatives in standard (increasing) order+ -> SimplM OutExpr++--------------------------------------------------+-- 1. Merge Nested Cases+--------------------------------------------------++mkCase dflags scrut outer_bndr alts_ty ((DEFAULT, _, deflt_rhs) : outer_alts)+ | gopt Opt_CaseMerge dflags+ , (ticks, Case (Var inner_scrut_var) inner_bndr _ inner_alts)+ <- stripTicksTop tickishFloatable deflt_rhs+ , inner_scrut_var == outer_bndr+ = do { tick (CaseMerge outer_bndr)++ ; let wrap_alt (con, args, rhs) = ASSERT( outer_bndr `notElem` args )+ (con, args, wrap_rhs rhs)+ -- Simplifier's no-shadowing invariant should ensure+ -- that outer_bndr is not shadowed by the inner patterns+ wrap_rhs rhs = Let (NonRec inner_bndr (Var outer_bndr)) rhs+ -- The let is OK even for unboxed binders,++ wrapped_alts | isDeadBinder inner_bndr = inner_alts+ | otherwise = map wrap_alt inner_alts++ merged_alts = mergeAlts outer_alts wrapped_alts+ -- NB: mergeAlts gives priority to the left+ -- case x of+ -- A -> e1+ -- DEFAULT -> case x of+ -- A -> e2+ -- B -> e3+ -- When we merge, we must ensure that e1 takes+ -- precedence over e2 as the value for A!++ ; fmap (mkTicks ticks) $+ mkCase1 dflags scrut outer_bndr alts_ty merged_alts+ }+ -- Warning: don't call mkCase recursively!+ -- Firstly, there's no point, because inner alts have already had+ -- mkCase applied to them, so they won't have a case in their default+ -- Secondly, if you do, you get an infinite loop, because the bindCaseBndr+ -- in munge_rhs may put a case into the DEFAULT branch!++mkCase dflags scrut bndr alts_ty alts = mkCase1 dflags scrut bndr alts_ty alts++--------------------------------------------------+-- 2. Eliminate Identity Case+--------------------------------------------------++mkCase1 _dflags scrut case_bndr _ alts@((_,_,rhs1) : _) -- Identity case+ | all identity_alt alts+ = do { tick (CaseIdentity case_bndr)+ ; return (mkTicks ticks $ re_cast scrut rhs1) }+ where+ ticks = concatMap (stripTicksT tickishFloatable . thdOf3) (tail alts)+ identity_alt (con, args, rhs) = check_eq rhs con args++ check_eq (Cast rhs co) con args -- See Note [RHS casts]+ = not (any (`elemVarSet` tyCoVarsOfCo co) args) && check_eq rhs con args+ check_eq (Tick t e) alt args+ = tickishFloatable t && check_eq e alt args++ check_eq (Lit lit) (LitAlt lit') _ = lit == lit'+ check_eq (Var v) _ _ | v == case_bndr = True+ check_eq (Var v) (DataAlt con) args+ | null arg_tys, null args = v == dataConWorkId con+ -- Optimisation only+ check_eq rhs (DataAlt con) args = cheapEqExpr' tickishFloatable rhs $+ mkConApp2 con arg_tys args+ check_eq _ _ _ = False++ arg_tys = tyConAppArgs (idType case_bndr)++ -- Note [RHS casts]+ -- ~~~~~~~~~~~~~~~~+ -- We've seen this:+ -- case e of x { _ -> x `cast` c }+ -- And we definitely want to eliminate this case, to give+ -- e `cast` c+ -- So we throw away the cast from the RHS, and reconstruct+ -- it at the other end. All the RHS casts must be the same+ -- if (all identity_alt alts) holds.+ --+ -- Don't worry about nested casts, because the simplifier combines them++ re_cast scrut (Cast rhs co) = Cast (re_cast scrut rhs) co+ re_cast scrut _ = scrut++mkCase1 dflags scrut bndr alts_ty alts = mkCase2 dflags scrut bndr alts_ty alts++--------------------------------------------------+-- 2. Scrutinee Constant Folding+--------------------------------------------------++mkCase2 dflags scrut bndr alts_ty alts+ | gopt Opt_CaseFolding dflags+ , Just (scrut',f) <- caseRules dflags scrut+ = mkCase3 dflags scrut' bndr alts_ty (new_alts f)+ | otherwise+ = mkCase3 dflags scrut bndr alts_ty alts+ where+ -- We need to keep the correct association between the scrutinee and its+ -- binder if the latter isn't dead. Hence we wrap rhs of alternatives with+ -- "let bndr = ... in":+ --+ -- case v + 10 of y =====> case v of y+ -- 20 -> e1 10 -> let y = 20 in e1+ -- DEFAULT -> e2 DEFAULT -> let y = v + 10 in e2+ --+ -- Other transformations give: =====> case v of y'+ -- 10 -> let y = 20 in e1+ -- DEFAULT -> let y = y' + 10 in e2+ --+ wrap_rhs l rhs+ | isDeadBinder bndr = rhs+ | otherwise = Let (NonRec bndr l) rhs++ -- We need to re-sort the alternatives to preserve the #case_invariants#+ new_alts f = sortBy cmpAlt (map (mapAlt f) alts)++ mapAlt f alt@(c,bs,e) = case c of+ DEFAULT -> (c, bs, wrap_rhs scrut e)+ LitAlt l+ | isLitValue l -> (LitAlt (mapLitValue dflags f l),+ bs, wrap_rhs (Lit l) e)+ _ -> pprPanic "Unexpected alternative (mkCase2)" (ppr alt)++--------------------------------------------------+-- Catch-all+--------------------------------------------------+mkCase3 _dflags scrut bndr alts_ty alts+ = return (Case scrut bndr alts_ty alts)++{-+Note [Dead binders]+~~~~~~~~~~~~~~~~~~~~+Note that dead-ness is maintained by the simplifier, so that it is+accurate after simplification as well as before.+++Note [Cascading case merge]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Case merging should cascade in one sweep, because it+happens bottom-up++ case e of a {+ DEFAULT -> case a of b+ DEFAULT -> case b of c {+ DEFAULT -> e+ A -> ea+ B -> eb+ C -> ec+==>+ case e of a {+ DEFAULT -> case a of b+ DEFAULT -> let c = b in e+ A -> let c = b in ea+ B -> eb+ C -> ec+==>+ case e of a {+ DEFAULT -> let b = a in let c = b in e+ A -> let b = a in let c = b in ea+ B -> let b = a in eb+ C -> ec+++However here's a tricky case that we still don't catch, and I don't+see how to catch it in one pass:++ case x of c1 { I# a1 ->+ case a1 of c2 ->+ 0 -> ...+ DEFAULT -> case x of c3 { I# a2 ->+ case a2 of ...++After occurrence analysis (and its binder-swap) we get this++ case x of c1 { I# a1 ->+ let x = c1 in -- Binder-swap addition+ case a1 of c2 ->+ 0 -> ...+ DEFAULT -> case x of c3 { I# a2 ->+ case a2 of ...++When we simplify the inner case x, we'll see that+x=c1=I# a1. So we'll bind a2 to a1, and get++ case x of c1 { I# a1 ->+ case a1 of c2 ->+ 0 -> ...+ DEFAULT -> case a1 of ...++This is corect, but we can't do a case merge in this sweep+because c2 /= a1. Reason: the binding c1=I# a1 went inwards+without getting changed to c1=I# c2.++I don't think this is worth fixing, even if I knew how. It'll+all come out in the next pass anyway.+-}
+ simplCore/Simplify.hs view
@@ -0,0 +1,3461 @@+{-+(c) The AQUA Project, Glasgow University, 1993-1998++\section[Simplify]{The main module of the simplifier}+-}++{-# LANGUAGE CPP #-}++module Simplify ( simplTopBinds, simplExpr, simplRules ) where++#include "HsVersions.h"++import DynFlags+import SimplMonad+import Type hiding ( substTy, substTyVar, extendTvSubst, extendCvSubst )+import SimplEnv+import SimplUtils+import OccurAnal ( occurAnalyseExpr )+import FamInstEnv ( FamInstEnv )+import Literal ( litIsLifted ) --, mkMachInt ) -- temporalily commented out. See #8326+import Id+import MkId ( seqId )+import MkCore ( mkImpossibleExpr, castBottomExpr )+import IdInfo+import Name ( Name, mkSystemVarName, isExternalName, getOccFS )+import Coercion hiding ( substCo, substCoVar )+import OptCoercion ( optCoercion )+import FamInstEnv ( topNormaliseType_maybe )+import DataCon ( DataCon, dataConWorkId, dataConRepStrictness, dataConRepArgTys )+--import TyCon ( isEnumerationTyCon ) -- temporalily commented out. See #8326+import CoreMonad ( Tick(..), SimplifierMode(..) )+import CoreSyn+import Demand ( StrictSig(..), dmdTypeDepth, isStrictDmd )+import PprCore ( pprCoreExpr )+import CoreUnfold+import CoreUtils+import CoreArity+import CoreOpt ( pushCoTyArg, pushCoValArg+ , joinPointBinding_maybe, joinPointBindings_maybe )+--import PrimOp ( tagToEnumKey ) -- temporalily commented out. See #8326+import Rules ( mkRuleInfo, lookupRule, getRules )+--import TysPrim ( intPrimTy ) -- temporalily commented out. See #8326+import BasicTypes ( TopLevelFlag(..), isNotTopLevel, isTopLevel,+ RecFlag(..) )+import MonadUtils ( foldlM, mapAccumLM, liftIO )+import Maybes ( isJust, fromJust, orElse )+--import Unique ( hasKey ) -- temporalily commented out. See #8326+import Control.Monad+import Outputable+import FastString+import Pair+import Util+import ErrUtils+import Module ( moduleName, pprModuleName )++{-+The guts of the simplifier is in this module, but the driver loop for+the simplifier is in SimplCore.hs.+++-----------------------------------------+ *** IMPORTANT NOTE ***+-----------------------------------------+The simplifier used to guarantee that the output had no shadowing, but+it does not do so any more. (Actually, it never did!) The reason is+documented with simplifyArgs.+++-----------------------------------------+ *** IMPORTANT NOTE ***+-----------------------------------------+Many parts of the simplifier return a bunch of "floats" as well as an+expression. This is wrapped as a datatype SimplUtils.FloatsWith.++All "floats" are let-binds, not case-binds, but some non-rec lets may+be unlifted (with RHS ok-for-speculation).++++-----------------------------------------+ ORGANISATION OF FUNCTIONS+-----------------------------------------+simplTopBinds+ - simplify all top-level binders+ - for NonRec, call simplRecOrTopPair+ - for Rec, call simplRecBind+++ ------------------------------+simplExpr (applied lambda) ==> simplNonRecBind+simplExpr (Let (NonRec ...) ..) ==> simplNonRecBind+simplExpr (Let (Rec ...) ..) ==> simplify binders; simplRecBind++ ------------------------------+simplRecBind [binders already simplfied]+ - use simplRecOrTopPair on each pair in turn++simplRecOrTopPair [binder already simplified]+ Used for: recursive bindings (top level and nested)+ top-level non-recursive bindings+ Returns:+ - check for PreInlineUnconditionally+ - simplLazyBind++simplNonRecBind+ Used for: non-top-level non-recursive bindings+ beta reductions (which amount to the same thing)+ Because it can deal with strict arts, it takes a+ "thing-inside" and returns an expression++ - check for PreInlineUnconditionally+ - simplify binder, including its IdInfo+ - if strict binding+ simplStrictArg+ mkAtomicArgs+ completeNonRecX+ else+ simplLazyBind+ addFloats++simplNonRecX: [given a *simplified* RHS, but an *unsimplified* binder]+ Used for: binding case-binder and constr args in a known-constructor case+ - check for PreInLineUnconditionally+ - simplify binder+ - completeNonRecX++ ------------------------------+simplLazyBind: [binder already simplified, RHS not]+ Used for: recursive bindings (top level and nested)+ top-level non-recursive bindings+ non-top-level, but *lazy* non-recursive bindings+ [must not be strict or unboxed]+ Returns floats + an augmented environment, not an expression+ - substituteIdInfo and add result to in-scope+ [so that rules are available in rec rhs]+ - simplify rhs+ - mkAtomicArgs+ - float if exposes constructor or PAP+ - completeBind+++completeNonRecX: [binder and rhs both simplified]+ - if the the thing needs case binding (unlifted and not ok-for-spec)+ build a Case+ else+ completeBind+ addFloats++completeBind: [given a simplified RHS]+ [used for both rec and non-rec bindings, top level and not]+ - try PostInlineUnconditionally+ - add unfolding [this is the only place we add an unfolding]+ - add arity++++Right hand sides and arguments+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In many ways we want to treat+ (a) the right hand side of a let(rec), and+ (b) a function argument+in the same way. But not always! In particular, we would+like to leave these arguments exactly as they are, so they+will match a RULE more easily.++ f (g x, h x)+ g (+ x)++It's harder to make the rule match if we ANF-ise the constructor,+or eta-expand the PAP:++ f (let { a = g x; b = h x } in (a,b))+ g (\y. + x y)++On the other hand if we see the let-defns++ p = (g x, h x)+ q = + x++then we *do* want to ANF-ise and eta-expand, so that p and q+can be safely inlined.++Even floating lets out is a bit dubious. For let RHS's we float lets+out if that exposes a value, so that the value can be inlined more vigorously.+For example++ r = let x = e in (x,x)++Here, if we float the let out we'll expose a nice constructor. We did experiments+that showed this to be a generally good thing. But it was a bad thing to float+lets out unconditionally, because that meant they got allocated more often.++For function arguments, there's less reason to expose a constructor (it won't+get inlined). Just possibly it might make a rule match, but I'm pretty skeptical.+So for the moment we don't float lets out of function arguments either.+++Eta expansion+~~~~~~~~~~~~~~+For eta expansion, we want to catch things like++ case e of (a,b) -> \x -> case a of (p,q) -> \y -> r++If the \x was on the RHS of a let, we'd eta expand to bring the two+lambdas together. And in general that's a good thing to do. Perhaps+we should eta expand wherever we find a (value) lambda? Then the eta+expansion at a let RHS can concentrate solely on the PAP case.+++Case-of-case and join points+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we perform the case-of-case transform (or otherwise push continuations+inward), we want to treat join points specially. Since they're always+tail-called and we want to maintain this invariant, we can do this (for any+evaluation context E):++ E[join j = e+ in case ... of+ A -> jump j 1+ B -> jump j 2+ C -> f 3]++ -->++ join j = E[e]+ in case ... of+ A -> jump j 1+ B -> jump j 2+ C -> E[f 3]++As is evident from the example, there are two components to this behavior:++ 1. When entering the RHS of a join point, copy the context inside.+ 2. When a join point is invoked, discard the outer context.++Clearly we need to be very careful here to remain consistent---neither part is+optional!++************************************************************************+* *+\subsection{Bindings}+* *+************************************************************************+-}++simplTopBinds :: SimplEnv -> [InBind] -> SimplM SimplEnv++simplTopBinds env0 binds0+ = do { -- Put all the top-level binders into scope at the start+ -- so that if a transformation rule has unexpectedly brought+ -- anything into scope, then we don't get a complaint about that.+ -- It's rather as if the top-level binders were imported.+ -- See note [Glomming] in OccurAnal.+ ; env1 <- simplRecBndrs env0 (bindersOfBinds binds0)+ ; env2 <- simpl_binds env1 binds0+ ; freeTick SimplifierDone+ ; return env2 }+ where+ -- We need to track the zapped top-level binders, because+ -- they should have their fragile IdInfo zapped (notably occurrence info)+ -- That's why we run down binds and bndrs' simultaneously.+ --+ simpl_binds :: SimplEnv -> [InBind] -> SimplM SimplEnv+ simpl_binds env [] = return env+ simpl_binds env (bind:binds) = do { env' <- simpl_bind env bind+ ; simpl_binds env' binds }++ simpl_bind env (Rec pairs) = simplRecBind env TopLevel Nothing pairs+ simpl_bind env (NonRec b r) = do { (env', b') <- addBndrRules env b (lookupRecBndr env b)+ ; simplRecOrTopPair env' TopLevel+ NonRecursive Nothing+ b b' r }++{-+************************************************************************+* *+\subsection{Lazy bindings}+* *+************************************************************************++simplRecBind is used for+ * recursive bindings only+-}++simplRecBind :: SimplEnv -> TopLevelFlag -> Maybe SimplCont+ -> [(InId, InExpr)]+ -> SimplM SimplEnv+simplRecBind env0 top_lvl mb_cont pairs0+ = do { (env_with_info, triples) <- mapAccumLM add_rules env0 pairs0+ ; env1 <- go (zapFloats env_with_info) triples+ ; return (env0 `addRecFloats` env1) }+ -- addFloats adds the floats from env1,+ -- _and_ updates env0 with the in-scope set from env1+ where+ add_rules :: SimplEnv -> (InBndr,InExpr) -> SimplM (SimplEnv, (InBndr, OutBndr, InExpr))+ -- Add the (substituted) rules to the binder+ add_rules env (bndr, rhs)+ = do { (env', bndr') <- addBndrRules env bndr (lookupRecBndr env bndr)+ ; return (env', (bndr, bndr', rhs)) }++ go env [] = return env++ go env ((old_bndr, new_bndr, rhs) : pairs)+ = do { env' <- simplRecOrTopPair env top_lvl Recursive mb_cont+ old_bndr new_bndr rhs+ ; go env' pairs }++{-+simplOrTopPair is used for+ * recursive bindings (whether top level or not)+ * top-level non-recursive bindings++It assumes the binder has already been simplified, but not its IdInfo.+-}++simplRecOrTopPair :: SimplEnv+ -> TopLevelFlag -> RecFlag -> Maybe SimplCont+ -> InId -> OutBndr -> InExpr -- Binder and rhs+ -> SimplM SimplEnv -- Returns an env that includes the binding++simplRecOrTopPair env top_lvl is_rec mb_cont old_bndr new_bndr rhs+ = do { dflags <- getDynFlags+ ; trace_bind dflags $+ if preInlineUnconditionally dflags env top_lvl old_bndr rhs+ -- Check for unconditional inline+ then do tick (PreInlineUnconditionally old_bndr)+ return (extendIdSubst env old_bndr (mkContEx env rhs))+ else simplBind env top_lvl is_rec mb_cont old_bndr new_bndr rhs env }+ where+ trace_bind dflags thing_inside+ | not (dopt Opt_D_verbose_core2core dflags)+ = thing_inside+ | otherwise+ = pprTrace "SimplBind" (ppr old_bndr) thing_inside+ -- trace_bind emits a trace for each top-level binding, which+ -- helps to locate the tracing for inlining and rule firing++{-+simplBind is used for+ * [simplRecOrTopPair] recursive bindings (whether top level or not)+ * [simplRecOrTopPair] top-level non-recursive bindings+ * [simplNonRecE] non-top-level *lazy* non-recursive bindings++Nota bene:+ 1. It assumes that the binder is *already* simplified,+ and is in scope, and its IdInfo too, except unfolding++ 2. It assumes that the binder type is lifted.++ 3. It does not check for pre-inline-unconditionally;+ that should have been done already.+-}++simplBind :: SimplEnv+ -> TopLevelFlag -> RecFlag -> Maybe SimplCont+ -> InId -> OutId -- Binder, both pre-and post simpl+ -- The OutId has IdInfo, except arity, unfolding+ -- Ids only, no TyVars+ -> InExpr -> SimplEnv -- The RHS and its environment+ -> SimplM SimplEnv+simplBind env top_lvl is_rec mb_cont bndr bndr1 rhs rhs_se+ | ASSERT( isId bndr1 )+ isJoinId bndr1+ = ASSERT(isNotTopLevel top_lvl && isJust mb_cont)+ simplJoinBind env is_rec (fromJust mb_cont) bndr bndr1 rhs rhs_se+ | otherwise+ = simplLazyBind env top_lvl is_rec bndr bndr1 rhs rhs_se++simplLazyBind :: SimplEnv+ -> TopLevelFlag -> RecFlag+ -> InId -> OutId -- Binder, both pre-and post simpl+ -- The OutId has IdInfo, except arity, unfolding+ -- Ids only, no TyVars+ -> InExpr -> SimplEnv -- The RHS and its environment+ -> SimplM SimplEnv+-- Precondition: rhs obeys the let/app invariant+-- NOT used for JoinIds+simplLazyBind env top_lvl is_rec bndr bndr1 rhs rhs_se+ = ASSERT( isId bndr )+ ASSERT2( not (isJoinId bndr), ppr bndr )+ -- pprTrace "simplLazyBind" ((ppr bndr <+> ppr bndr1) $$ ppr rhs $$ ppr (seIdSubst rhs_se)) $+ do { let rhs_env = rhs_se `setInScopeAndZapFloats` env+ (tvs, body) = case collectTyAndValBinders rhs of+ (tvs, [], body)+ | surely_not_lam body -> (tvs, body)+ _ -> ([], rhs)++ surely_not_lam (Lam {}) = False+ surely_not_lam (Tick t e)+ | not (tickishFloatable t) = surely_not_lam e+ -- eta-reduction could float+ surely_not_lam _ = True+ -- Do not do the "abstract tyyvar" thing if there's+ -- a lambda inside, because it defeats eta-reduction+ -- f = /\a. \x. g a x+ -- should eta-reduce.+++ ; (body_env, tvs') <- simplBinders rhs_env tvs+ -- See Note [Floating and type abstraction] in SimplUtils++ -- Simplify the RHS+ ; let rhs_cont = mkRhsStop (substTy body_env (exprType body))+ ; (body_env0, body0) <- simplExprF body_env body rhs_cont+ ; let body1 = wrapJoinFloats body_env0 body0+ body_env1 = body_env0 `restoreJoinFloats` body_env++ -- ANF-ise a constructor or PAP rhs+ ; (body_env2, body2) <- prepareRhs top_lvl body_env1 bndr1 body1++ ; (env', rhs')+ <- if not (doFloatFromRhs top_lvl is_rec False body2 body_env2)+ then -- No floating, revert to body1+ do { rhs' <- mkLam env tvs' (wrapFloats body_env1 body1) rhs_cont+ ; return (env, rhs') }++ else if null tvs then -- Simple floating+ do { tick LetFloatFromLet+ ; return (addFloats env body_env2, body2) }++ else -- Do type-abstraction first+ do { tick LetFloatFromLet+ ; (poly_binds, body3) <- abstractFloats tvs' body_env2 body2+ ; rhs' <- mkLam env tvs' body3 rhs_cont+ ; env' <- foldlM (addPolyBind top_lvl) env poly_binds+ ; return (env', rhs') }++ ; completeBind env' top_lvl is_rec Nothing bndr bndr1 rhs' }++simplJoinBind :: SimplEnv+ -> RecFlag+ -> SimplCont+ -> InId -> OutId -- Binder, both pre-and post simpl+ -- The OutId has IdInfo, except arity,+ -- unfolding+ -> InExpr -> SimplEnv -- The RHS and its environment+ -> SimplM SimplEnv+simplJoinBind env is_rec cont bndr bndr1 rhs rhs_se+ = -- pprTrace "simplLazyBind" ((ppr bndr <+> ppr bndr1) $$+ -- ppr rhs $$ ppr (seIdSubst rhs_se)) $+ do { let rhs_env = rhs_se `setInScopeAndZapFloats` env++ -- Simplify the RHS+ ; rhs' <- simplJoinRhs rhs_env bndr rhs cont+ ; completeBind env NotTopLevel is_rec (Just cont) bndr bndr1 rhs' }++{-+A specialised variant of simplNonRec used when the RHS is already simplified,+notably in knownCon. It uses case-binding where necessary.+-}++simplNonRecX :: SimplEnv+ -> InId -- Old binder+ -> OutExpr -- Simplified RHS+ -> SimplM SimplEnv+-- Precondition: rhs satisfies the let/app invariant+simplNonRecX env bndr new_rhs+ | isDeadBinder bndr -- Not uncommon; e.g. case (a,b) of c { (p,q) -> p }+ = return env -- Here c is dead, and we avoid creating+ -- the binding c = (a,b)++ | Coercion co <- new_rhs+ = return (extendCvSubst env bndr co)++ | otherwise+ = do { (env', bndr') <- simplBinder env bndr+ ; completeNonRecX NotTopLevel env' (isStrictId bndr) bndr bndr' new_rhs }+ -- simplNonRecX is only used for NotTopLevel things++completeNonRecX :: TopLevelFlag -> SimplEnv+ -> Bool+ -> InId -- Old binder+ -> OutId -- New binder+ -> OutExpr -- Simplified RHS+ -> SimplM SimplEnv+-- Precondition: rhs satisfies the let/app invariant+-- See Note [CoreSyn let/app invariant] in CoreSyn++completeNonRecX top_lvl env is_strict old_bndr new_bndr new_rhs+ = ASSERT(not (isJoinId new_bndr))+ do { (env1, rhs1) <- prepareRhs top_lvl (zapFloats env) new_bndr new_rhs+ ; (env2, rhs2) <-+ if doFloatFromRhs NotTopLevel NonRecursive is_strict rhs1 env1+ then do { tick LetFloatFromLet+ ; return (addFloats env env1, rhs1) } -- Add the floats to the main env+ else return (env, wrapFloats env1 rhs1) -- Wrap the floats around the RHS+ ; completeBind env2 NotTopLevel NonRecursive Nothing+ old_bndr new_bndr rhs2 }++{- No, no, no! Do not try preInlineUnconditionally in completeNonRecX+ Doing so risks exponential behaviour, because new_rhs has been simplified once already+ In the cases described by the folowing commment, postInlineUnconditionally will+ catch many of the relevant cases.+ -- This happens; for example, the case_bndr during case of+ -- known constructor: case (a,b) of x { (p,q) -> ... }+ -- Here x isn't mentioned in the RHS, so we don't want to+ -- create the (dead) let-binding let x = (a,b) in ...+ --+ -- Similarly, single occurrences can be inlined vigourously+ -- e.g. case (f x, g y) of (a,b) -> ....+ -- If a,b occur once we can avoid constructing the let binding for them.++ Furthermore in the case-binding case preInlineUnconditionally risks extra thunks+ -- Consider case I# (quotInt# x y) of+ -- I# v -> let w = J# v in ...+ -- If we gaily inline (quotInt# x y) for v, we end up building an+ -- extra thunk:+ -- let w = J# (quotInt# x y) in ...+ -- because quotInt# can fail.++ | preInlineUnconditionally env NotTopLevel bndr new_rhs+ = thing_inside (extendIdSubst env bndr (DoneEx new_rhs))+-}++----------------------------------+{- 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+an expression. That is why completeNonRecX does not try+preInlineUnconditionally.++Example:+ f BIG, where f has a RULE+Then+ * We simplify BIG before trying the rule; but the rule does not fire+ * We inline f = \x. x True+ * So if we did preInlineUnconditionally we'd re-simplify (BIG True)++However, if BIG has /not/ already been simplified, we'd /like/ to+simplify BIG True; maybe good things happen. That is why++* simplLam has+ - a case for (isSimplified dup), which goes via simplNonRecX, and+ - a case for the un-simplified case, which goes via simplNonRecE++* We go to some efforts to avoid unnecessarily simplifying ApplyToVal,+ in at least two places+ - In simplCast/addCoerce, where we check for isReflCo+ - In rebuildCall we avoid simplifying arguments before we have to+ (see Note [Trying rewrite rules])++Note [prepareRhs]+~~~~~~~~~~~~~~~~~~~~+prepareRhs takes a putative RHS, checks whether it's a PAP or+constructor application and, if so, converts it to ANF, so that the+resulting thing can be inlined more easily. Thus+ x = (f a, g b)+becomes+ t1 = f a+ t2 = g b+ x = (t1,t2)++We also want to deal well cases like this+ v = (f e1 `cast` co) e2+Here we want to make e1,e2 trivial and get+ x1 = e1; x2 = e2; v = (f x1 `cast` co) v2+That's what the 'go' loop in prepareRhs does+-}++prepareRhs :: TopLevelFlag -> SimplEnv -> OutId -> OutExpr -> SimplM (SimplEnv, OutExpr)+-- Adds new floats to the env iff that allows us to return a good RHS+-- See Note [prepareRhs]+prepareRhs top_lvl env id (Cast rhs co) -- Note [Float coercions]+ | Pair ty1 _ty2 <- coercionKind co -- Do *not* do this if rhs has an unlifted type+ , not (isUnliftedType ty1) -- see Note [Float coercions (unlifted)]+ = do { (env', rhs') <- makeTrivialWithInfo top_lvl env (getOccFS id) sanitised_info rhs+ ; return (env', Cast rhs' co) }+ where+ sanitised_info = vanillaIdInfo `setStrictnessInfo` strictnessInfo info+ `setDemandInfo` demandInfo info+ info = idInfo id++prepareRhs top_lvl env0 id rhs0+ = do { (_is_exp, env1, rhs1) <- go 0 env0 rhs0+ ; return (env1, rhs1) }+ where+ go n_val_args env (Cast rhs co)+ = do { (is_exp, env', rhs') <- go n_val_args env rhs+ ; return (is_exp, env', Cast rhs' co) }+ go n_val_args env (App fun (Type ty))+ = do { (is_exp, env', rhs') <- go n_val_args env fun+ ; return (is_exp, env', App rhs' (Type ty)) }+ go n_val_args env (App fun arg)+ = do { (is_exp, env', fun') <- go (n_val_args+1) env fun+ ; case is_exp of+ True -> do { (env'', arg') <- makeTrivial top_lvl env' (getOccFS id) arg+ ; return (True, env'', App fun' arg') }+ False -> return (False, env, App fun arg) }+ go n_val_args env (Var fun)+ = return (is_exp, env, Var fun)+ where+ is_exp = isExpandableApp fun n_val_args -- The fun a constructor or PAP+ -- See Note [CONLIKE pragma] in BasicTypes+ -- The definition of is_exp should match that in+ -- OccurAnal.occAnalApp++ go n_val_args env (Tick t rhs)+ -- We want to be able to float bindings past this+ -- tick. Non-scoping ticks don't care.+ | tickishScoped t == NoScope+ = do { (is_exp, env', rhs') <- go n_val_args env rhs+ ; return (is_exp, env', Tick t rhs') }+ -- On the other hand, for scoping ticks we need to be able to+ -- copy them on the floats, which in turn is only allowed if+ -- we can obtain non-counting ticks.+ | not (tickishCounts t) || tickishCanSplit t+ = do { (is_exp, env', rhs') <- go n_val_args (zapFloats env) rhs+ ; let tickIt (id, expr) = (id, mkTick (mkNoCount t) expr)+ floats' = seFloats $ env `addFloats` mapFloats env' tickIt+ ; return (is_exp, env' { seFloats = floats' }, Tick t rhs') }++ go _ env other+ = return (False, env, other)++{-+Note [Float coercions]+~~~~~~~~~~~~~~~~~~~~~~+When we find the binding+ x = e `cast` co+we'd like to transform it to+ x' = e+ x = x `cast` co -- A trivial binding+There's a chance that e will be a constructor application or function, or something+like that, so moving the coercion to the usage site may well cancel the coercions+and lead to further optimisation. Example:++ data family T a :: *+ data instance T Int = T Int++ foo :: Int -> Int -> Int+ foo m n = ...+ where+ x = T m+ go 0 = 0+ go n = case x of { T m -> go (n-m) }+ -- This case should optimise++Note [Preserve strictness when floating coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the Note [Float coercions] transformation, keep the strictness info.+Eg+ f = e `cast` co -- f has strictness SSL+When we transform to+ f' = e -- f' also has strictness SSL+ f = f' `cast` co -- f still has strictness SSL++Its not wrong to drop it on the floor, but better to keep it.++Note [Float coercions (unlifted)]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+BUT don't do [Float coercions] if 'e' has an unlifted type.+This *can* happen:++ foo :: Int = (error (# Int,Int #) "urk")+ `cast` CoUnsafe (# Int,Int #) Int++If do the makeTrivial thing to the error call, we'll get+ foo = case error (# Int,Int #) "urk" of v -> v `cast` ...+But 'v' isn't in scope!++These strange casts can happen as a result of case-of-case+ bar = case (case x of { T -> (# 2,3 #); F -> error "urk" }) of+ (# p,q #) -> p+q+-}++makeTrivialArg :: SimplEnv -> ArgSpec -> SimplM (SimplEnv, ArgSpec)+makeTrivialArg env (ValArg e) = do+ { (env', e') <- makeTrivial NotTopLevel env (fsLit "arg") e+ ; return (env', ValArg e') }+makeTrivialArg env arg = return (env, arg) -- CastBy, TyArg++makeTrivial :: TopLevelFlag -> SimplEnv+ -> FastString -- ^ a "friendly name" to build the new binder from+ -> OutExpr -> SimplM (SimplEnv, OutExpr)+-- Binds the expression to a variable, if it's not trivial, returning the variable+makeTrivial top_lvl env context expr =+ makeTrivialWithInfo top_lvl env context vanillaIdInfo expr++makeTrivialWithInfo :: TopLevelFlag -> SimplEnv+ -> FastString+ -- ^ a "friendly name" to build the new binder from+ -> IdInfo -> OutExpr -> SimplM (SimplEnv, OutExpr)+-- Propagate strictness and demand info to the new binder+-- Note [Preserve strictness when floating coercions]+-- Returned SimplEnv has same substitution as incoming one+makeTrivialWithInfo top_lvl env context info expr+ | exprIsTrivial expr -- Already trivial+ || not (bindingOk top_lvl expr expr_ty) -- Cannot trivialise+ -- See Note [Cannot trivialise]+ = return (env, expr)+ | otherwise -- See Note [Take care] below+ = do { uniq <- getUniqueM+ ; let name = mkSystemVarName uniq context+ var = mkLocalIdOrCoVarWithInfo name expr_ty info+ ; env' <- completeNonRecX top_lvl env False var var expr+ ; expr' <- simplVar env' var+ ; return (env', expr') }+ -- The simplVar is needed because we're constructing a new binding+ -- a = rhs+ -- And if rhs is of form (rhs1 |> co), then we might get+ -- a1 = rhs1+ -- a = a1 |> co+ -- and now a's RHS is trivial and can be substituted out, and that+ -- is what completeNonRecX will do+ -- To put it another way, it's as if we'd simplified+ -- let var = e in var+ where+ expr_ty = exprType expr++bindingOk :: TopLevelFlag -> CoreExpr -> Type -> Bool+-- True iff we can have a binding of this expression at this level+-- Precondition: the type is the type of the expression+bindingOk top_lvl expr expr_ty+ | isTopLevel top_lvl = exprIsTopLevelBindable expr expr_ty+ | otherwise = True++{-+Note [Cannot trivialise]+~~~~~~~~~~~~~~~~~~~~~~~~+Consider tih+ f :: Int -> Addr#++ foo :: Bar+ foo = Bar (f 3)++Then we can't ANF-ise foo, even though we'd like to, because+we can't make a top-level binding for the Addr# (f 3). And if+so we don't want to turn it into+ foo = let x = f 3 in Bar x+because we'll just end up inlining x back, and that makes the+simplifier loop. Better not to ANF-ise it at all.++Literal strings are an exception.++ foo = Ptr "blob"#++We want to turn this into:++ foo1 = "blob"#+ foo = Ptr foo1++See Note [CoreSyn top-level string literals] in CoreSyn.++************************************************************************+* *+\subsection{Completing a lazy binding}+* *+************************************************************************++completeBind+ * deals only with Ids, not TyVars+ * takes an already-simplified binder and RHS+ * is used for both recursive and non-recursive bindings+ * is used for both top-level and non-top-level bindings++It does the following:+ - tries discarding a dead binding+ - tries PostInlineUnconditionally+ - add unfolding [this is the only place we add an unfolding]+ - add arity++It does *not* attempt to do let-to-case. Why? Because it is used for+ - top-level bindings (when let-to-case is impossible)+ - many situations where the "rhs" is known to be a WHNF+ (so let-to-case is inappropriate).++Nor does it do the atomic-argument thing+-}++completeBind :: SimplEnv+ -> TopLevelFlag -- Flag stuck into unfolding+ -> RecFlag -- Recursive binding?+ -> Maybe SimplCont -- Required only for join point+ -> InId -- Old binder+ -> OutId -> OutExpr -- New binder and RHS+ -> SimplM SimplEnv+-- completeBind may choose to do its work+-- * by extending the substitution (e.g. let x = y in ...)+-- * or by adding to the floats in the envt+--+-- Precondition: rhs obeys the let/app invariant+completeBind env top_lvl is_rec mb_cont old_bndr new_bndr new_rhs+ | isCoVar old_bndr+ = case new_rhs of+ Coercion co -> return (extendCvSubst env old_bndr co)+ _ -> return (addNonRec env new_bndr new_rhs)++ | otherwise+ = ASSERT( isId new_bndr )+ do { let old_info = idInfo old_bndr+ old_unf = unfoldingInfo old_info+ occ_info = occInfo old_info++ -- Do eta-expansion on the RHS of the binding+ -- See Note [Eta-expanding at let bindings] in SimplUtils+ ; (new_arity, final_rhs) <- if isJoinId new_bndr+ then return (manifestArity new_rhs, new_rhs)+ -- Note [Don't eta-expand join points]+ else tryEtaExpandRhs env is_rec+ new_bndr new_rhs++ -- Simplify the unfolding+ ; new_unfolding <- simplLetUnfolding env top_lvl mb_cont old_bndr+ final_rhs old_unf++ ; dflags <- getDynFlags+ ; if postInlineUnconditionally dflags env top_lvl new_bndr occ_info+ final_rhs new_unfolding++ -- Inline and discard the binding+ then do { tick (PostInlineUnconditionally old_bndr)+ ; return (extendIdSubst env old_bndr (DoneEx final_rhs)) }+ -- Use the substitution to make quite, quite sure that the+ -- substitution will happen, since we are going to discard the binding+ else+ do { let info1 = idInfo new_bndr `setArityInfo` new_arity++ -- Unfolding info: Note [Setting the new unfolding]+ info2 = info1 `setUnfoldingInfo` new_unfolding++ -- 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_unfolding+ || (case strictnessInfo info2 of+ StrictSig dmd_ty -> new_arity < dmdTypeDepth dmd_ty)+ = zapDemandInfo info2 `orElse` info2+ | otherwise+ = info2++ -- Zap call arity info. We have used it by now (via+ -- `tryEtaExpandRhs`), and the simplifier can invalidate this+ -- information, leading to broken code later (e.g. #13479)+ info4 = zapCallArityInfo info3++ final_id = new_bndr `setIdInfo` info4++ ; -- pprTrace "Binding" (ppr final_id <+> ppr new_unfolding) $+ return (addNonRec env final_id final_rhs) } }+ -- The addNonRec adds it to the in-scope set too++------------------------------+addPolyBind :: TopLevelFlag -> SimplEnv -> OutBind -> SimplM SimplEnv+-- Add a new binding to the environment, complete with its unfolding+-- but *do not* do postInlineUnconditionally, because we have already+-- processed some of the scope of the binding+-- We still want the unfolding though. Consider+-- let+-- x = /\a. let y = ... in Just y+-- in body+-- Then we float the y-binding out (via abstractFloats and addPolyBind)+-- but 'x' may well then be inlined in 'body' in which case we'd like the+-- opportunity to inline 'y' too.+--+-- INVARIANT: the arity is correct on the incoming binders++addPolyBind top_lvl env (NonRec poly_id rhs)+ = do { unfolding <- simplLetUnfolding env top_lvl Nothing poly_id rhs+ noUnfolding+ -- Assumes that poly_id did not have an INLINE prag+ -- which is perhaps wrong. ToDo: think about this+ ; let final_id = setIdInfo poly_id $+ idInfo poly_id `setUnfoldingInfo` unfolding++ ; return (addNonRec env final_id rhs) }++addPolyBind _ env bind@(Rec _)+ = return (extendFloats env bind)+ -- Hack: letrecs are more awkward, so we extend "by steam"+ -- without adding unfoldings etc. At worst this leads to+ -- more simplifier iterations++{- 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 [Setting the demand info]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the unfolding is a value, the demand info may+go pear-shaped, so we nuke it. Example:+ let x = (a,b) in+ case x of (p,q) -> h p q x+Here x is certainly demanded. But after we've nuked+the case, we'll get just+ let x = (a,b) in h a b x+and now x is not demanded (I'm assuming h is lazy)+This really happens. Similarly+ let f = \x -> e in ...f..f...+After inlining f at some of its call sites the original binding may+(for example) be no longer strictly demanded.+The solution here is a bit ad hoc...++Note [Don't eta-expand join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Similarly to CPR (see Note [Don't CPR join points] in WorkWrap), a join point+stands well to gain from its outer binding's eta-expansion, and eta-expanding a+join point is fraught with issues like how to deal with a cast:++ let join $j1 :: IO ()+ $j1 = ...+ $j2 :: Int -> IO ()+ $j2 n = if n > 0 then $j1+ else ...++ =>++ let join $j1 :: IO ()+ $j1 = (\eta -> ...)+ `cast` N:IO :: State# RealWorld -> (# State# RealWorld, ())+ ~ IO ()+ $j2 :: Int -> IO ()+ $j2 n = (\eta -> if n > 0 then $j1+ else ...)+ `cast` N:IO :: State# RealWorld -> (# State# RealWorld, ())+ ~ IO ()++The cast here can't be pushed inside the lambda (since it's not casting to a+function type), so the lambda has to stay, but it can't because it contains a+reference to a join point. In fact, $j2 can't be eta-expanded at all. Rather+than try and detect this situation (and whatever other situations crop up!), we+don't bother; again, any surrounding eta-expansion will improve these join+points anyway, since an outer cast can *always* be pushed inside. By the time+CorePrep comes around, the code is very likely to look more like this:++ let join $j1 :: State# RealWorld -> (# State# RealWorld, ())+ $j1 = (...) eta+ $j2 :: Int -> State# RealWorld -> (# State# RealWorld, ())+ $j2 = if n > 0 then $j1+ else (...) eta++************************************************************************+* *+\subsection[Simplify-simplExpr]{The main function: simplExpr}+* *+************************************************************************++The reason for this OutExprStuff stuff is that we want to float *after*+simplifying a RHS, not before. If we do so naively we get quadratic+behaviour as things float out.++To see why it's important to do it after, consider this (real) example:++ let t = f x+ in fst t+==>+ let t = let a = e1+ b = e2+ in (a,b)+ in fst t+==>+ let a = e1+ b = e2+ t = (a,b)+ in+ a -- Can't inline a this round, cos it appears twice+==>+ e1++Each of the ==> steps is a round of simplification. We'd save a+whole round if we float first. This can cascade. Consider++ let f = g d+ in \x -> ...f...+==>+ let f = let d1 = ..d.. in \y -> e+ in \x -> ...f...+==>+ let d1 = ..d..+ in \x -> ...(\y ->e)...++Only in this second round can the \y be applied, and it+might do the same again.+-}++simplExpr :: SimplEnv -> CoreExpr -> SimplM CoreExpr+simplExpr env (Type ty)+ = do { ty' <- simplType env ty -- See Note [Avoiding space leaks in OutType]+ ; return (Type ty') }++simplExpr env expr+ = simplExprC env expr (mkBoringStop expr_out_ty)+ where+ expr_out_ty :: OutType+ expr_out_ty = substTy env (exprType expr)+ -- NB: Since 'expr' is term-valued, not (Type ty), this call+ -- to exprType will succeed. exprType fails on (Type ty).++simplExprC :: SimplEnv+ -> InExpr -- A term-valued expression, never (Type ty)+ -> SimplCont+ -> SimplM OutExpr+ -- Simplify an expression, given a continuation+simplExprC env expr cont+ = -- pprTrace "simplExprC" (ppr expr $$ ppr cont {- $$ ppr (seIdSubst env) -} $$ ppr (seFloats env) ) $+ do { (env', expr') <- simplExprF (zapFloats env) expr cont+ ; -- pprTrace "simplExprC ret" (ppr expr $$ ppr expr') $+ -- pprTrace "simplExprC ret3" (ppr (seInScope env')) $+ -- pprTrace "simplExprC ret4" (ppr (seFloats env')) $+ return (wrapFloats env' expr') }++--------------------------------------------------+simplExprF :: SimplEnv+ -> InExpr -- A term-valued expression, never (Type ty)+ -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++simplExprF env e cont+ = -- pprTrace "simplExprF" (vcat+-- [ ppr e+-- , text "cont =" <+> ppr cont+-- , text "inscope =" <+> ppr (seInScope env)+-- , text "tvsubst =" <+> ppr (seTvSubst env)+-- , text "idsubst =" <+> ppr (seIdSubst env)+-- , text "cvsubst =" <+> ppr (seCvSubst env)+-- {- , ppr (seFloats env) -}+-- ]) $+ simplExprF1 env e cont++simplExprF1 :: SimplEnv -> InExpr -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++simplExprF1 _ (Type ty) _+ = pprPanic "simplExprF: type" (ppr ty)+ -- simplExprF does only with term-valued expressions+ -- The (Type ty) case is handled separately by simplExpr+ -- and by the other callers of simplExprF++simplExprF1 env (Var v) cont = simplIdF env v cont+simplExprF1 env (Lit lit) cont = rebuild env (Lit lit) cont+simplExprF1 env (Tick t expr) cont = simplTick env t expr cont+simplExprF1 env (Cast body co) cont = simplCast env body co cont+simplExprF1 env (Coercion co) cont = simplCoercionF env co cont++simplExprF1 env (App fun arg) cont+ = case arg of+ Type ty -> do { -- The argument type will (almost) certainly be used+ -- in the output program, so just force it now.+ -- See Note [Avoiding space leaks in OutType]+ arg' <- simplType env ty++ -- But use substTy, not simplType, to avoid forcing+ -- the hole type; it will likely not be needed.+ -- See Note [The hole type in ApplyToTy]+ ; let hole' = substTy env (exprType fun)++ ; simplExprF env fun $+ ApplyToTy { sc_arg_ty = arg'+ , sc_hole_ty = hole'+ , sc_cont = cont } }+ _ -> simplExprF env fun $+ ApplyToVal { sc_arg = arg, sc_env = env+ , sc_dup = NoDup, sc_cont = cont }++simplExprF1 env expr@(Lam {}) cont+ = simplLam env zapped_bndrs body cont+ -- The main issue here is under-saturated lambdas+ -- (\x1. \x2. e) arg1+ -- Here x1 might have "occurs-once" occ-info, because occ-info+ -- is computed assuming that a group of lambdas is applied+ -- all at once. If there are too few args, we must zap the+ -- occ-info, UNLESS the remaining binders are one-shot+ where+ (bndrs, body) = collectBinders expr+ zapped_bndrs | need_to_zap = map zap bndrs+ | otherwise = bndrs++ need_to_zap = any zappable_bndr (drop n_args bndrs)+ n_args = countArgs cont+ -- NB: countArgs counts all the args (incl type args)+ -- and likewise drop counts all binders (incl type lambdas)++ zappable_bndr b = isId b && not (isOneShotBndr b)+ zap b | isTyVar b = b+ | otherwise = zapLamIdInfo b++simplExprF1 env (Case scrut bndr _ alts) cont+ = simplExprF env scrut (Select { sc_dup = NoDup, sc_bndr = bndr+ , sc_alts = alts+ , sc_env = env, sc_cont = cont })++simplExprF1 env (Let (Rec pairs) body) cont+ = simplRecE env pairs body cont++simplExprF1 env (Let (NonRec bndr rhs) body) cont+ | Type ty <- rhs -- First deal with type lets (let a = Type ty in e)+ = ASSERT( isTyVar bndr )+ do { ty' <- simplType env ty+ ; simplExprF (extendTvSubst env bndr ty') body cont }++ | otherwise+ = simplNonRecE env bndr (rhs, env) ([], body) cont++{- Note [Avoiding space leaks in OutType]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Since the simplifier is run for multiple iterations, we need to ensure+that any thunks in the output of one simplifier iteration are forced+by the evaluation of the next simplifier iteration. Otherwise we may+retain multiple copies of the Core program and leak a terrible amount+of memory (as in #13426).++The simplifier is naturally strict in the entire "Expr part" of the+input Core program, because any expression may contain binders, which+we must find in order to extend the SimplEnv accordingly. But types+do not contain binders and so it is tempting to write things like++ simplExpr env (Type ty) = return (Type (substTy env ty)) -- Bad!++This is Bad because the result includes a thunk (substTy env ty) which+retains a reference to the whole simplifier environment; and the next+simplifier iteration will not force this thunk either, because the+line above is not strict in ty.++So instead our strategy is for the simplifier to fully evaluate+OutTypes when it emits them into the output Core program, for example++ simplExpr env (Type ty) = do { ty' <- simplType env ty -- Good+ ; return (Type ty') }++where the only difference from above is that simplType calls seqType+on the result of substTy.++However, SimplCont can also contain OutTypes and it's not necessarily+a good idea to force types on the way in to SimplCont, because they+may end up not being used and forcing them could be a lot of wasted+work. T5631 is a good example of this.++- For ApplyToTy's sc_arg_ty, we force the type on the way in because+ the type will almost certainly appear as a type argument in the+ output program.++- For the hole types in Stop and ApplyToTy, we force the type when we+ emit it into the output program, after obtaining it from+ contResultType. (The hole type in ApplyToTy is only directly used+ to form the result type in a new Stop continuation.)+-}++---------------------------------+-- Simplify a join point, adding the context.+-- Context goes *inside* the lambdas. IOW, if the join point has arity n, we do:+-- \x1 .. xn -> e => \x1 .. xn -> E[e]+-- Note that we need the arity of the join point, since e may be a lambda+-- (though this is unlikely). See Note [Case-of-case and join points].+simplJoinRhs :: SimplEnv -> InId -> InExpr -> SimplCont+ -> SimplM OutExpr+simplJoinRhs env bndr expr cont+ | Just arity <- isJoinId_maybe bndr+ = do { let (join_bndrs, join_body) = collectNBinders arity expr+ ; (env', join_bndrs') <- simplLamBndrs env join_bndrs+ ; join_body' <- simplExprC env' join_body cont+ ; return $ mkLams join_bndrs' join_body' }++ | otherwise+ = pprPanic "simplJoinRhs" (ppr bndr)++---------------------------------+simplType :: SimplEnv -> InType -> SimplM OutType+ -- Kept monadic just so we can do the seqType+ -- See Note [Avoiding space leaks in OutType]+simplType env ty+ = -- pprTrace "simplType" (ppr ty $$ ppr (seTvSubst env)) $+ seqType new_ty `seq` return new_ty+ where+ new_ty = substTy env ty++---------------------------------+simplCoercionF :: SimplEnv -> InCoercion -> SimplCont+ -> SimplM (SimplEnv, OutExpr)+simplCoercionF env co cont+ = do { co' <- simplCoercion env co+ ; rebuild env (Coercion co') cont }++simplCoercion :: SimplEnv -> InCoercion -> SimplM OutCoercion+simplCoercion env co+ = let opt_co = optCoercion (getTCvSubst env) co+ in seqCo opt_co `seq` return opt_co++-----------------------------------+-- | Push a TickIt context outwards past applications and cases, as+-- long as this is a non-scoping tick, to let case and application+-- optimisations apply.++simplTick :: SimplEnv -> Tickish Id -> InExpr -> SimplCont+ -> SimplM (SimplEnv, OutExpr)+simplTick env tickish expr cont+ -- A scoped tick turns into a continuation, so that we can spot+ -- (scc t (\x . e)) in simplLam and eliminate the scc. If we didn't do+ -- it this way, then it would take two passes of the simplifier to+ -- reduce ((scc t (\x . e)) e').+ -- NB, don't do this with counting ticks, because if the expr is+ -- bottom, then rebuildCall will discard the continuation.++-- XXX: we cannot do this, because the simplifier assumes that+-- the context can be pushed into a case with a single branch. e.g.+-- scc<f> case expensive of p -> e+-- becomes+-- case expensive of p -> scc<f> e+--+-- So I'm disabling this for now. It just means we will do more+-- simplifier iterations that necessary in some cases.++-- | tickishScoped tickish && not (tickishCounts tickish)+-- = simplExprF env expr (TickIt tickish cont)++ -- For unscoped or soft-scoped ticks, we are allowed to float in new+ -- cost, so we simply push the continuation inside the tick. This+ -- has the effect of moving the tick to the outside of a case or+ -- application context, allowing the normal case and application+ -- optimisations to fire.+ | tickish `tickishScopesLike` SoftScope+ = do { (env', expr') <- simplExprF env expr cont+ ; return (env', mkTick tickish expr')+ }++ -- Push tick inside if the context looks like this will allow us to+ -- do a case-of-case - see Note [case-of-scc-of-case]+ | Select {} <- cont, Just expr' <- push_tick_inside+ = simplExprF env expr' cont++ -- We don't want to move the tick, but we might still want to allow+ -- floats to pass through with appropriate wrapping (or not, see+ -- wrap_floats below)+ --- | not (tickishCounts tickish) || tickishCanSplit tickish+ -- = wrap_floats++ | otherwise+ = no_floating_past_tick++ where++ -- Try to push tick inside a case, see Note [case-of-scc-of-case].+ push_tick_inside =+ case expr0 of+ Case scrut bndr ty alts+ -> Just $ Case (tickScrut scrut) bndr ty (map tickAlt alts)+ _other -> Nothing+ where (ticks, expr0) = stripTicksTop movable (Tick tickish expr)+ movable t = not (tickishCounts t) ||+ t `tickishScopesLike` NoScope ||+ tickishCanSplit t+ tickScrut e = foldr mkTick e ticks+ -- Alternatives get annotated with all ticks that scope in some way,+ -- but we don't want to count entries.+ tickAlt (c,bs,e) = (c,bs, foldr mkTick e ts_scope)+ ts_scope = map mkNoCount $+ filter (not . (`tickishScopesLike` NoScope)) ticks++ no_floating_past_tick =+ do { let (inc,outc) = splitCont cont+ ; (env', expr') <- simplExprF (zapFloats env) expr inc+ ; let tickish' = simplTickish env tickish+ ; (env'', expr'') <- rebuild (zapFloats env')+ (wrapFloats env' expr')+ (TickIt tickish' outc)+ ; return (addFloats env env'', expr'')+ }++-- Alternative version that wraps outgoing floats with the tick. This+-- results in ticks being duplicated, as we don't make any attempt to+-- eliminate the tick if we re-inline the binding (because the tick+-- semantics allows unrestricted inlining of HNFs), so I'm not doing+-- this any more. FloatOut will catch any real opportunities for+-- floating.+--+-- wrap_floats =+-- do { let (inc,outc) = splitCont cont+-- ; (env', expr') <- simplExprF (zapFloats env) expr inc+-- ; let tickish' = simplTickish env tickish+-- ; let wrap_float (b,rhs) = (zapIdStrictness (setIdArity b 0),+-- mkTick (mkNoCount tickish') rhs)+-- -- when wrapping a float with mkTick, we better zap the Id's+-- -- strictness info and arity, because it might be wrong now.+-- ; let env'' = addFloats env (mapFloats env' wrap_float)+-- ; rebuild env'' expr' (TickIt tickish' outc)+-- }+++ simplTickish env tickish+ | Breakpoint n ids <- tickish+ = Breakpoint n (map (getDoneId . substId env) ids)+ | otherwise = tickish++ -- Push type application and coercion inside a tick+ splitCont :: SimplCont -> (SimplCont, SimplCont)+ splitCont cont@(ApplyToTy { sc_cont = tail }) = (cont { sc_cont = inc }, outc)+ where (inc,outc) = splitCont tail+ splitCont (CastIt co c) = (CastIt co inc, outc)+ where (inc,outc) = splitCont c+ splitCont other = (mkBoringStop (contHoleType other), other)++ getDoneId (DoneId id) = id+ getDoneId (DoneEx e) = getIdFromTrivialExpr e -- Note [substTickish] in CoreSubst+ getDoneId other = pprPanic "getDoneId" (ppr other)++-- Note [case-of-scc-of-case]+-- It's pretty important to be able to transform case-of-case when+-- there's an SCC in the way. For example, the following comes up+-- in nofib/real/compress/Encode.hs:+--+-- case scctick<code_string.r1>+-- case $wcode_string_r13s wild_XC w1_s137 w2_s138 l_aje+-- of _ { (# ww1_s13f, ww2_s13g, ww3_s13h #) ->+-- (ww1_s13f, ww2_s13g, ww3_s13h)+-- }+-- of _ { (ww_s12Y, ww1_s12Z, ww2_s130) ->+-- tick<code_string.f1>+-- (ww_s12Y,+-- ww1_s12Z,+-- PTTrees.PT+-- @ GHC.Types.Char @ GHC.Types.Int wild2_Xj ww2_s130 r_ajf)+-- }+--+-- We really want this case-of-case to fire, because then the 3-tuple+-- will go away (indeed, the CPR optimisation is relying on this+-- happening). But the scctick is in the way - we need to push it+-- inside to expose the case-of-case. So we perform this+-- transformation on the inner case:+--+-- scctick c (case e of { p1 -> e1; ...; pn -> en })+-- ==>+-- case (scctick c e) of { p1 -> scc c e1; ...; pn -> scc c en }+--+-- So we've moved a constant amount of work out of the scc to expose+-- the case. We only do this when the continuation is interesting: in+-- for now, it has to be another Case (maybe generalise this later).++{-+************************************************************************+* *+\subsection{The main rebuilder}+* *+************************************************************************+-}++rebuild :: SimplEnv -> OutExpr -> SimplCont -> SimplM (SimplEnv, OutExpr)+-- At this point the substitution in the SimplEnv should be irrelevant+-- only the in-scope set and floats should matter+rebuild env expr cont+ = case cont of+ Stop {} -> return (env, expr)+ TickIt t cont -> rebuild env (mkTick t expr) cont+ CastIt co cont -> rebuild env (mkCast expr co) cont+ -- NB: mkCast implements the (Coercion co |> g) optimisation++ Select { sc_bndr = bndr, sc_alts = alts, sc_env = se, sc_cont = cont }+ -> rebuildCase (se `setFloats` env) expr bndr alts cont++ StrictArg info _ cont -> rebuildCall env (info `addValArgTo` expr) cont+ StrictBind b bs body se cont -> do { env' <- simplNonRecX (se `setFloats` env) b expr+ -- expr satisfies let/app since it started life+ -- in a call to simplNonRecE+ ; simplLam env' bs body cont }++ ApplyToTy { sc_arg_ty = ty, sc_cont = cont}+ -> rebuild env (App expr (Type ty)) cont++ ApplyToVal { sc_arg = arg, sc_env = se, sc_dup = dup_flag, sc_cont = cont}+ -- See Note [Avoid redundant simplification]+ | isSimplified dup_flag+ -> rebuild env (App expr arg) cont++ | otherwise+ -> do { arg' <- simplExpr (se `setInScopeAndZapFloats` env) arg+ ; rebuild env (App expr arg') cont }+++{-+************************************************************************+* *+\subsection{Lambdas}+* *+************************************************************************+-}++simplCast :: SimplEnv -> InExpr -> Coercion -> SimplCont+ -> SimplM (SimplEnv, OutExpr)+simplCast env body co0 cont0+ = do { co1 <- simplCoercion env co0+ ; cont1 <- addCoerce co1 cont0+ ; simplExprF env body cont1 }+ where+ addCoerce :: OutCoercion -> SimplCont -> SimplM SimplCont+ addCoerce co1 (CastIt co2 cont)+ = addCoerce (mkTransCo co1 co2) cont++ addCoerce co cont@(ApplyToTy { sc_arg_ty = arg_ty, sc_cont = tail })+ | Just (arg_ty', co') <- pushCoTyArg co arg_ty+ = do { tail' <- addCoerce co' tail+ ; return (cont { sc_arg_ty = arg_ty', sc_cont = tail' }) }++ addCoerce co cont@(ApplyToVal { sc_arg = arg, sc_env = arg_se+ , sc_dup = dup, sc_cont = tail })+ | Just (co1, co2) <- pushCoValArg co+ , Pair _ new_ty <- coercionKind co1+ , not (isTypeLevPoly new_ty) -- without this check, we get a lev-poly arg+ -- See Note [Levity polymorphism invariants] in CoreSyn+ -- test: typecheck/should_run/EtaExpandLevPoly+ = do { tail' <- addCoerce co2 tail+ ; if isReflCo co1+ then return (cont { sc_cont = tail' })+ -- Avoid simplifying if possible;+ -- See Note [Avoiding exponential behaviour]+ else do+ { (dup', arg_se', arg') <- simplArg env dup arg_se arg+ -- When we build the ApplyTo we can't mix the OutCoercion+ -- 'co' with the InExpr 'arg', so we simplify+ -- to make it all consistent. It's a bit messy.+ -- But it isn't a common case.+ -- Example of use: Trac #995+ ; return (ApplyToVal { sc_arg = mkCast arg' co1+ , sc_env = arg_se'+ , sc_dup = dup'+ , sc_cont = tail' }) } }++ addCoerce co cont+ | isReflexiveCo co = return cont+ | otherwise = return (CastIt co cont)+ -- It's worth checking isReflexiveCo.+ -- For example, in the initial form of a worker+ -- we may find (coerce T (coerce S (\x.e))) y+ -- and we'd like it to simplify to e[y/x] in one round+ -- of simplification++simplArg :: SimplEnv -> DupFlag -> StaticEnv -> CoreExpr+ -> SimplM (DupFlag, StaticEnv, OutExpr)+simplArg env dup_flag arg_env arg+ | isSimplified dup_flag+ = return (dup_flag, arg_env, arg)+ | otherwise+ = do { arg' <- simplExpr (arg_env `setInScopeAndZapFloats` env) arg+ ; return (Simplified, zapSubstEnv arg_env, arg') }++{-+************************************************************************+* *+\subsection{Lambdas}+* *+************************************************************************++Note [Zap unfolding when beta-reducing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Lambda-bound variables can have stable unfoldings, such as+ $j = \x. \b{Unf=Just x}. e+See Note [Case binders and join points] below; the unfolding for lets+us optimise e better. However when we beta-reduce it we want to+revert to using the actual value, otherwise we can end up in the+stupid situation of+ let x = blah in+ let b{Unf=Just x} = y+ in ...b...+Here it'd be far better to drop the unfolding and use the actual RHS.+-}++simplLam :: SimplEnv -> [InId] -> InExpr -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++simplLam env [] body cont = simplExprF env body cont++ -- Beta reduction++simplLam env (bndr:bndrs) body (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = cont })+ = do { tick (BetaReduction bndr)+ ; simplLam (extendTvSubst env bndr arg_ty) bndrs body cont }++simplLam env (bndr:bndrs) body (ApplyToVal { sc_arg = arg, sc_env = arg_se+ , sc_cont = cont, sc_dup = dup })+ | isSimplified dup -- Don't re-simplify if we've simplified it once+ -- See Note [Avoiding exponential behaviour]+ = do { tick (BetaReduction bndr)+ ; env' <- simplNonRecX env zapped_bndr arg+ ; simplLam env' bndrs body cont }++ | otherwise+ = do { tick (BetaReduction bndr)+ ; simplNonRecE env zapped_bndr (arg, arg_se) (bndrs, body) cont }+ where+ zapped_bndr -- See Note [Zap unfolding when beta-reducing]+ | isId bndr, isStableUnfolding (realIdUnfolding bndr)+ = setIdUnfolding bndr NoUnfolding+ | otherwise = bndr++ -- discard a non-counting tick on a lambda. This may change the+ -- cost attribution slightly (moving the allocation of the+ -- lambda elsewhere), but we don't care: optimisation changes+ -- cost attribution all the time.+simplLam env bndrs body (TickIt tickish cont)+ | not (tickishCounts tickish)+ = simplLam env bndrs body cont++ -- Not enough args, so there are real lambdas left to put in the result+simplLam env bndrs body cont+ = do { (env', bndrs') <- simplLamBndrs env bndrs+ ; body' <- simplExpr env' body+ ; new_lam <- mkLam env bndrs' body' cont+ ; rebuild env' new_lam cont }++simplLamBndrs :: SimplEnv -> [InBndr] -> SimplM (SimplEnv, [OutBndr])+simplLamBndrs env bndrs = mapAccumLM simplLamBndr env bndrs++-------------+simplLamBndr :: SimplEnv -> InBndr -> SimplM (SimplEnv, OutBndr)+-- Used for lambda binders. These sometimes have unfoldings added by+-- the worker/wrapper pass that must be preserved, because they can't+-- be reconstructed from context. For example:+-- f x = case x of (a,b) -> fw a b x+-- fw a b x{=(a,b)} = ...+-- The "{=(a,b)}" is an unfolding we can't reconstruct otherwise.+simplLamBndr env bndr+ | isId bndr && isFragileUnfolding old_unf -- Special case+ = do { (env1, bndr1) <- simplBinder env bndr+ ; unf' <- simplUnfolding env1 NotTopLevel Nothing bndr old_unf+ ; let bndr2 = bndr1 `setIdUnfolding` unf'+ ; return (modifyInScope env1 bndr2, bndr2) }++ | otherwise+ = simplBinder env bndr -- Normal case+ where+ old_unf = idUnfolding bndr++------------------+simplNonRecE :: SimplEnv+ -> InId -- The binder, always an Id+ -- Can be a join point+ -> (InExpr, SimplEnv) -- Rhs of binding (or arg of lambda)+ -> ([InBndr], InExpr) -- Body of the let/lambda+ -- \xs.e+ -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++-- simplNonRecE is used for+-- * non-top-level non-recursive lets in expressions+-- * beta reduction+--+-- It deals with strict bindings, via the StrictBind continuation,+-- which may abort the whole process+--+-- Precondition: rhs satisfies the let/app invariant+-- Note [CoreSyn let/app invariant] in CoreSyn+--+-- The "body" of the binding comes as a pair of ([InId],InExpr)+-- representing a lambda; so we recurse back to simplLam+-- Why? Because of the binder-occ-info-zapping done before+-- the call to simplLam in simplExprF (Lam ...)++simplNonRecE env bndr (rhs, rhs_se) (bndrs, body) cont+ = ASSERT( isId bndr )+ do dflags <- getDynFlags+ case () of+ _ | preInlineUnconditionally dflags env NotTopLevel bndr rhs+ -> do { tick (PreInlineUnconditionally bndr)+ ; -- pprTrace "preInlineUncond" (ppr bndr <+> ppr rhs) $+ simplLam (extendIdSubst env bndr (mkContEx rhs_se rhs)) bndrs body cont }++ | isStrictId bndr -- Includes coercions+ -> simplExprF (rhs_se `setFloats` env) rhs+ (StrictBind bndr bndrs body env cont)++ | Just (bndr', rhs') <- joinPointBinding_maybe bndr rhs+ -> do { let cont_dup_res_ty = resultTypeOfDupableCont (getMode env)+ [bndr'] cont+ ; (env1, bndr1) <- simplNonRecJoinBndr env+ cont_dup_res_ty bndr'+ ; (env2, bndr2) <- addBndrRules env1 bndr' bndr1+ ; (env3, cont_dup, cont_nodup)+ <- prepareLetCont (zapJoinFloats env2) [bndr'] cont+ ; MASSERT2(cont_dup_res_ty `eqType` contResultType cont_dup,+ ppr cont_dup_res_ty $$ blankLine $$+ ppr cont $$ blankLine $$+ ppr cont_dup $$ blankLine $$+ ppr cont_nodup)+ ; env4 <- simplJoinBind env3 NonRecursive cont_dup bndr' bndr2+ rhs' rhs_se+ ; (env5, expr) <- simplLam env4 bndrs body cont_dup+ ; rebuild (env5 `restoreJoinFloats` env2)+ (wrapJoinFloats env5 expr) cont_nodup }++ | otherwise+ -> ASSERT( not (isTyVar bndr) )+ do { (env1, bndr1) <- simplNonRecBndr env bndr+ ; (env2, bndr2) <- addBndrRules env1 bndr bndr1+ ; env3 <- simplLazyBind env2 NotTopLevel NonRecursive bndr bndr2 rhs rhs_se+ ; simplLam env3 bndrs body cont }++------------------+simplRecE :: SimplEnv+ -> [(InId, InExpr)]+ -> InExpr+ -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++-- simplRecE is used for+-- * non-top-level recursive lets in expressions+simplRecE env pairs body cont+ | Just pairs' <- joinPointBindings_maybe pairs+ = do { let bndrs' = map fst pairs'+ cont_dup_res_ty = resultTypeOfDupableCont (getMode env)+ bndrs' cont+ ; env1 <- simplRecJoinBndrs env cont_dup_res_ty bndrs'+ -- NB: bndrs' don't have unfoldings or rules+ -- We add them as we go down+ ; (env2, cont_dup, cont_nodup) <- prepareLetCont (zapJoinFloats env1)+ bndrs' cont+ ; MASSERT2(cont_dup_res_ty `eqType` contResultType cont_dup,+ ppr cont_dup_res_ty $$ blankLine $$+ ppr cont $$ blankLine $$+ ppr cont_dup $$ blankLine $$+ ppr cont_nodup)+ ; env3 <- simplRecBind env2 NotTopLevel (Just cont_dup) pairs'+ ; (env4, expr) <- simplExprF env3 body cont_dup+ ; rebuild (env4 `restoreJoinFloats` env1)+ (wrapJoinFloats env4 expr) cont_nodup }+ | otherwise+ = do { let bndrs = map fst pairs+ ; MASSERT(all (not . isJoinId) bndrs)+ ; env1 <- simplRecBndrs env bndrs+ -- NB: bndrs' don't have unfoldings or rules+ -- We add them as we go down+ ; env2 <- simplRecBind env1 NotTopLevel Nothing pairs+ ; simplExprF env2 body cont }+++{-+************************************************************************+* *+ Variables+* *+************************************************************************+-}++simplVar :: SimplEnv -> InVar -> SimplM OutExpr+-- Look up an InVar in the environment+simplVar env var+ | isTyVar var = return (Type (substTyVar env var))+ | isCoVar var = return (Coercion (substCoVar env var))+ | otherwise+ = case substId env var of+ DoneId var1 -> return (Var var1)+ DoneEx e -> return e+ ContEx tvs cvs ids e -> simplExpr (setSubstEnv env tvs cvs ids) e++simplIdF :: SimplEnv -> InId -> SimplCont -> SimplM (SimplEnv, OutExpr)+simplIdF env var cont+ = case substId env var of+ DoneEx e -> simplExprF (zapSubstEnv env) e trimmed_cont+ ContEx tvs cvs ids e -> simplExprF (setSubstEnv env tvs cvs ids) e cont+ -- Don't trim; haven't already simplified+ -- the join, so the cont was never copied+ DoneId var1 -> completeCall env var1 trimmed_cont+ -- Note [zapSubstEnv]+ -- The template is already simplified, so don't re-substitute.+ -- This is VITAL. Consider+ -- let x = e in+ -- let y = \z -> ...x... in+ -- \ x -> ...y...+ -- We'll clone the inner \x, adding x->x' in the id_subst+ -- Then when we inline y, we must *not* replace x by x' in+ -- the inlined copy!!+ where+ trimmed_cont | Just arity <- isJoinIdInEnv_maybe env var+ = trim_cont arity cont+ | otherwise+ = cont++ -- Drop outer context from join point invocation+ -- Note [Case-of-case and join points]+ trim_cont 0 cont@(Stop {})+ = cont+ trim_cont 0 cont+ = mkBoringStop (contResultType cont)+ trim_cont n cont@(ApplyToVal { sc_cont = k })+ = cont { sc_cont = trim_cont (n-1) k }+ trim_cont n cont@(ApplyToTy { sc_cont = k })+ = cont { sc_cont = trim_cont (n-1) k } -- join arity counts types!+ trim_cont _ cont+ = pprPanic "completeCall" $ ppr var $$ ppr cont++---------------------------------------------------------+-- Dealing with a call site++completeCall :: SimplEnv -> OutId -> SimplCont -> SimplM (SimplEnv, OutExpr)+completeCall env var cont+ = do { ------------- Try inlining ----------------+ dflags <- getDynFlags+ ; let (lone_variable, arg_infos, call_cont) = contArgs cont+ n_val_args = length arg_infos+ interesting_cont = interestingCallContext call_cont+ unfolding = activeUnfolding env var+ maybe_inline = callSiteInline dflags var unfolding+ lone_variable arg_infos interesting_cont+ ; case maybe_inline of+ Just expr -- There is an inlining!+ -> do { checkedTick (UnfoldingDone var)+ ; dump_inline dflags expr cont+ ; simplExprF (zapSubstEnv env) expr cont }++ ; Nothing -> do { rule_base <- getSimplRules+ ; let info = mkArgInfo var (getRules rule_base var)+ n_val_args call_cont+ ; rebuildCall env info cont }+ }+ where+ dump_inline dflags unfolding cont+ | not (dopt Opt_D_dump_inlinings dflags) = return ()+ | not (dopt Opt_D_verbose_core2core dflags)+ = when (isExternalName (idName var)) $+ liftIO $ printOutputForUser dflags alwaysQualify $+ sep [text "Inlining done:", nest 4 (ppr var)]+ | otherwise+ = liftIO $ printOutputForUser dflags alwaysQualify $+ sep [text "Inlining done: " <> ppr var,+ nest 4 (vcat [text "Inlined fn: " <+> nest 2 (ppr unfolding),+ text "Cont: " <+> ppr cont])]++rebuildCall :: SimplEnv+ -> ArgInfo+ -> SimplCont+ -> SimplM (SimplEnv, OutExpr)+-- We decided not to inline, so+-- - simplify the arguments+-- - try rewrite rules+-- - and rebuild++---------- Bottoming applications --------------+rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args, ai_strs = [] }) cont+ -- When we run out of strictness args, it means+ -- that the call is definitely bottom; see SimplUtils.mkArgInfo+ -- Then we want to discard the entire strict continuation. E.g.+ -- * case (error "hello") of { ... }+ -- * (error "Hello") arg+ -- * f (error "Hello") where f is strict+ -- etc+ -- Then, especially in the first of these cases, we'd like to discard+ -- the continuation, leaving just the bottoming expression. But the+ -- type might not be right, so we may have to add a coerce.+ | not (contIsTrivial cont) -- Only do this if there is a non-trivial+ -- continuation to discard, else we do it+ -- again and again!+ = seqType cont_ty `seq` -- See Note [Avoiding space leaks in OutType]+ return (env, castBottomExpr res cont_ty)+ where+ res = argInfoExpr fun rev_args+ cont_ty = contResultType cont++---------- Try rewrite RULES --------------+-- See Note [Trying rewrite rules]+rebuildCall env info@(ArgInfo { ai_fun = fun, ai_args = rev_args+ , ai_rules = Just (nr_wanted, rules) }) cont+ | nr_wanted == 0 || no_more_args+ , let info' = info { ai_rules = Nothing }+ = -- We've accumulated a simplified call in <fun,rev_args>+ -- so try rewrite rules; see Note [RULEs apply to simplified arguments]+ -- See also Note [Rules for recursive functions]+ do { mb_match <- tryRules env rules fun (reverse rev_args) cont+ ; case mb_match of+ Just (env', rhs, cont') -> simplExprF env' rhs cont'+ Nothing -> rebuildCall env info' cont }+ where+ no_more_args = case cont of+ ApplyToTy {} -> False+ ApplyToVal {} -> False+ _ -> True+++---------- Simplify applications and casts --------------+rebuildCall env info (CastIt co cont)+ = rebuildCall env (addCastTo info co) cont++rebuildCall env info (ApplyToTy { sc_arg_ty = arg_ty, sc_cont = cont })+ = rebuildCall env (addTyArgTo info arg_ty) cont++rebuildCall env info@(ArgInfo { ai_encl = encl_rules, ai_type = fun_ty+ , ai_strs = str:strs, ai_discs = disc:discs })+ (ApplyToVal { sc_arg = arg, sc_env = arg_se+ , sc_dup = dup_flag, sc_cont = cont })+ | isSimplified dup_flag -- See Note [Avoid redundant simplification]+ = rebuildCall env (addValArgTo info' arg) cont++ | str -- Strict argument+ = -- pprTrace "Strict Arg" (ppr arg $$ ppr (seIdSubst env) $$ ppr (seInScope env)) $+ simplExprF (arg_se `setFloats` env) arg+ (StrictArg info' cci_strict cont)+ -- Note [Shadowing]++ | otherwise -- Lazy argument+ -- DO NOT float anything outside, hence simplExprC+ -- There is no benefit (unlike in a let-binding), and we'd+ -- have to be very careful about bogus strictness through+ -- floating a demanded let.+ = do { arg' <- simplExprC (arg_se `setInScopeAndZapFloats` env) arg+ (mkLazyArgStop arg_ty cci_lazy)+ ; rebuildCall env (addValArgTo info' arg') cont }+ where+ info' = info { ai_strs = strs, ai_discs = discs }+ arg_ty = funArgTy fun_ty++ -- Use this for lazy arguments+ cci_lazy | encl_rules = RuleArgCtxt+ | disc > 0 = DiscArgCtxt -- Be keener here+ | otherwise = BoringCtxt -- Nothing interesting++ -- ..and this for strict arguments+ cci_strict | encl_rules = RuleArgCtxt+ | disc > 0 = DiscArgCtxt+ | otherwise = RhsCtxt+ -- Why RhsCtxt? if we see f (g x) (h x), and f is strict, we+ -- want to be a bit more eager to inline g, because it may+ -- expose an eval (on x perhaps) that can be eliminated or+ -- shared. I saw this in nofib 'boyer2', RewriteFuns.onewayunify1+ -- It's worth an 18% improvement in allocation for this+ -- particular benchmark; 5% on 'mate' and 1.3% on 'multiplier'++---------- No further useful info, revert to generic rebuild ------------+rebuildCall env (ArgInfo { ai_fun = fun, ai_args = rev_args }) cont+ = rebuild env (argInfoExpr fun rev_args) cont++{- Note [Trying rewrite rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider an application (f e1 e2 e3) where the e1,e2,e3 are not yet+simplified. We want to simplify enough arguments to allow the rules+to apply, but it's more efficient to avoid simplifying e2,e3 if e1 alone+is sufficient. Example: class ops+ (+) dNumInt e2 e3+If we rewrite ((+) dNumInt) to plusInt, we can take advantage of the+latter's strictness when simplifying e2, e3. Moreover, suppose we have+ RULE f Int = \x. x True++Then given (f Int e1) we rewrite to+ (\x. x True) e1+without simpifying e1. Now we can inline x into its unique call site,+and absorb the True into it all in the same pass. If we simplified+e1 first, we couldn't do that; see Note [Avoiding exponential behaviour].++So we try to apply rules if either+ (a) no_more_args: we've run out of argument that the rules can "see"+ (b) nr_wanted: none of the rules wants any more arguments+++Note [RULES apply to simplified arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's very desirable to try RULES once the arguments have been simplified, because+doing so ensures that rule cascades work in one pass. Consider+ {-# RULES g (h x) = k x+ f (k x) = x #-}+ ...f (g (h x))...+Then we want to rewrite (g (h x)) to (k x) and only then try f's rules. If+we match f's rules against the un-simplified RHS, it won't match. This+makes a particularly big difference when superclass selectors are involved:+ op ($p1 ($p2 (df d)))+We want all this to unravel in one sweep.++Note [Avoid redundant simplification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because RULES apply to simplified arguments, there's a danger of repeatedly+simplifying already-simplified arguments. An important example is that of+ (>>=) d e1 e2+Here e1, e2 are simplified before the rule is applied, but don't really+participate in the rule firing. So we mark them as Simplified to avoid+re-simplifying them.++Note [Shadowing]+~~~~~~~~~~~~~~~~+This part of the simplifier may break the no-shadowing invariant+Consider+ f (...(\a -> e)...) (case y of (a,b) -> e')+where f is strict in its second arg+If we simplify the innermost one first we get (...(\a -> e)...)+Simplifying the second arg makes us float the case out, so we end up with+ case y of (a,b) -> f (...(\a -> e)...) e'+So the output does not have the no-shadowing invariant. However, there is+no danger of getting name-capture, because when the first arg was simplified+we used an in-scope set that at least mentioned all the variables free in its+static environment, and that is enough.++We can't just do innermost first, or we'd end up with a dual problem:+ case x of (a,b) -> f e (...(\a -> e')...)++I spent hours trying to recover the no-shadowing invariant, but I just could+not think of an elegant way to do it. The simplifier is already knee-deep in+continuations. We have to keep the right in-scope set around; AND we have+to get the effect that finding (error "foo") in a strict arg position will+discard the entire application and replace it with (error "foo"). Getting+all this at once is TOO HARD!+++************************************************************************+* *+ Rewrite rules+* *+************************************************************************+-}++tryRules :: SimplEnv -> [CoreRule]+ -> Id -> [ArgSpec]+ -> SimplCont+ -> SimplM (Maybe (SimplEnv, CoreExpr, SimplCont))++tryRules env rules fn args call_cont+ | null rules+ = return Nothing+{- Disabled until we fix #8326+ | fn `hasKey` tagToEnumKey -- See Note [Optimising tagToEnum#]+ , [_type_arg, val_arg] <- args+ , Select dup bndr ((_,[],rhs1) : rest_alts) se cont <- call_cont+ , isDeadBinder bndr+ = do { dflags <- getDynFlags+ ; let enum_to_tag :: CoreAlt -> CoreAlt+ -- Takes K -> e into tagK# -> e+ -- where tagK# is the tag of constructor K+ enum_to_tag (DataAlt con, [], rhs)+ = ASSERT( isEnumerationTyCon (dataConTyCon con) )+ (LitAlt tag, [], rhs)+ where+ tag = mkMachInt dflags (toInteger (dataConTag con - fIRST_TAG))+ enum_to_tag alt = pprPanic "tryRules: tagToEnum" (ppr alt)++ new_alts = (DEFAULT, [], rhs1) : map enum_to_tag rest_alts+ new_bndr = setIdType bndr intPrimTy+ -- The binder is dead, but should have the right type+ ; return (Just (val_arg, Select dup new_bndr new_alts se cont)) }+-}+ | otherwise+ = do { dflags <- getDynFlags+ ; case lookupRule dflags (getUnfoldingInRuleMatch env) (activeRule env)+ fn (argInfoAppArgs args) rules of {+ Nothing ->+ do { nodump dflags -- This ensures that an empty file is written+ ; return Nothing } ; -- No rule matches+ Just (rule, rule_rhs) ->+ do { checkedTick (RuleFired (ruleName rule))+ ; let cont' = pushSimplifiedArgs zapped_env+ (drop (ruleArity rule) args)+ call_cont+ -- (ruleArity rule) says how+ -- many args the rule consumed++ occ_anald_rhs = occurAnalyseExpr rule_rhs+ -- See Note [Occurrence-analyse after rule firing]+ ; dump dflags rule rule_rhs+ ; return (Just (zapped_env, occ_anald_rhs, cont')) }}}+ -- The occ_anald_rhs and cont' are all Out things+ -- hence zapping the environment+ where+ zapped_env = zapSubstEnv env -- See Note [zapSubstEnv]++ printRuleModule rule =+ parens+ (maybe (text "BUILTIN") (pprModuleName . moduleName) (ruleModule rule))++ dump dflags rule rule_rhs+ | dopt Opt_D_dump_rule_rewrites dflags+ = log_rule dflags Opt_D_dump_rule_rewrites "Rule fired" $ vcat+ [ text "Rule:" <+> ftext (ruleName rule)+ , text "Module:" <+> printRuleModule rule+ , text "Before:" <+> hang (ppr fn) 2 (sep (map ppr args))+ , text "After: " <+> pprCoreExpr rule_rhs+ , text "Cont: " <+> ppr call_cont ]++ | dopt Opt_D_dump_rule_firings dflags+ = log_rule dflags Opt_D_dump_rule_firings "Rule fired:" $+ ftext (ruleName rule)+ <+> printRuleModule rule++ | otherwise+ = return ()++ nodump dflags+ | dopt Opt_D_dump_rule_rewrites dflags+ = liftIO $ dumpSDoc dflags alwaysQualify Opt_D_dump_rule_rewrites "" empty++ | dopt Opt_D_dump_rule_firings dflags+ = liftIO $ dumpSDoc dflags alwaysQualify Opt_D_dump_rule_firings "" empty++ | otherwise+ = return ()++ log_rule dflags flag hdr details+ = liftIO . dumpSDoc dflags alwaysQualify flag "" $+ sep [text hdr, nest 4 details]++trySeqRules :: SimplEnv+ -> OutExpr -> InExpr -- Scrutinee and RHS+ -> SimplCont+ -> SimplM (Maybe (SimplEnv, CoreExpr, SimplCont))+-- See Note [User-defined RULES for seq]+trySeqRules in_env scrut rhs cont+ = do { rule_base <- getSimplRules+ ; tryRules in_env (getRules rule_base seqId) seqId out_args rule_cont }+ where+ no_cast_scrut = drop_casts scrut+ scrut_ty = exprType no_cast_scrut+ seq_id_ty = idType seqId+ rhs_ty = substTy in_env (exprType rhs)+ out_args = [ TyArg { as_arg_ty = scrut_ty+ , as_hole_ty = seq_id_ty }+ , TyArg { as_arg_ty = rhs_ty+ , as_hole_ty = piResultTy seq_id_ty scrut_ty }+ , ValArg no_cast_scrut]+ rule_cont = ApplyToVal { sc_dup = NoDup, sc_arg = rhs+ , sc_env = in_env, sc_cont = cont }+ -- Lazily evaluated, so we don't do most of this++ drop_casts (Cast e _) = drop_casts e+ drop_casts e = e++{- Note [User-defined RULES for seq]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Given+ case (scrut |> co) of _ -> rhs+look for rules that match the expression+ seq @t1 @t2 scrut+where scrut :: t1+ rhs :: t2++If you find a match, rewrite it, and apply to 'rhs'.++Notice that we can simply drop casts on the fly here, which+makes it more likely that a rule will match.++See Note [User-defined RULES for seq] in MkId.++Note [Occurrence-analyse after rule firing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+After firing a rule, we occurrence-analyse the instantiated RHS before+simplifying it. Usually this doesn't make much difference, but it can+be huge. Here's an example (simplCore/should_compile/T7785)++ map f (map f (map f xs)++= -- Use build/fold form of map, twice+ map f (build (\cn. foldr (mapFB c f) n+ (build (\cn. foldr (mapFB c f) n xs))))++= -- Apply fold/build rule+ map f (build (\cn. (\cn. foldr (mapFB c f) n xs) (mapFB c f) n))++= -- Beta-reduce+ -- Alas we have no occurrence-analysed, so we don't know+ -- that c is used exactly once+ map f (build (\cn. let c1 = mapFB c f in+ foldr (mapFB c1 f) n xs))++= -- Use mapFB rule: mapFB (mapFB c f) g = mapFB c (f.g)+ -- We can do this because (mapFB c n) is a PAP and hence expandable+ map f (build (\cn. let c1 = mapFB c n in+ foldr (mapFB c (f.f)) n x))++This is not too bad. But now do the same with the outer map, and+we get another use of mapFB, and t can interact with /both/ remaining+mapFB calls in the above expression. This is stupid because actually+that 'c1' binding is dead. The outer map introduces another c2. If+there is a deep stack of maps we get lots of dead bindings, and lots+of redundant work as we repeatedly simplify the result of firing rules.++The easy thing to do is simply to occurrence analyse the result of+the rule firing. Note that this occ-anals not only the RHS of the+rule, but also the function arguments, which by now are OutExprs.+E.g.+ RULE f (g x) = x+1++Call f (g BIG) --> (\x. x+1) BIG++The rule binders are lambda-bound and applied to the OutExpr arguments+(here BIG) which lack all internal occurrence info.++Is this inefficient? Not really: we are about to walk over the result+of the rule firing to simplify it, so occurrence analysis is at most+a constant factor.++Possible improvement: occ-anal the rules when putting them in the+database; and in the simplifier just occ-anal the OutExpr arguments.+But that's more complicated and the rule RHS is usually tiny; so I'm+just doing the simple thing.++Historical note: previously we did occ-anal the rules in Rule.hs,+but failed to occ-anal the OutExpr arguments, which led to the+nasty performance problem described above.+++Note [Optimising tagToEnum#]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have an enumeration data type:++ data Foo = A | B | C++Then we want to transform++ case tagToEnum# x of ==> case x of+ A -> e1 DEFAULT -> e1+ B -> e2 1# -> e2+ C -> e3 2# -> e3++thereby getting rid of the tagToEnum# altogether. If there was a DEFAULT+alternative we retain it (remember it comes first). If not the case must+be exhaustive, and we reflect that in the transformed version by adding+a DEFAULT. Otherwise Lint complains that the new case is not exhaustive.+See #8317.++Note [Rules for recursive functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+You might think that we shouldn't apply rules for a loop breaker:+doing so might give rise to an infinite loop, because a RULE is+rather like an extra equation for the function:+ RULE: f (g x) y = x+y+ Eqn: f a y = a-y++But it's too drastic to disable rules for loop breakers.+Even the foldr/build rule would be disabled, because foldr+is recursive, and hence a loop breaker:+ foldr k z (build g) = g k z+So it's up to the programmer: rules can cause divergence+++************************************************************************+* *+ Rebuilding a case expression+* *+************************************************************************++Note [Case elimination]+~~~~~~~~~~~~~~~~~~~~~~~+The case-elimination transformation discards redundant case expressions.+Start with a simple situation:++ case x# of ===> let y# = x# in e+ y# -> e++(when x#, y# are of primitive type, of course). We can't (in general)+do this for algebraic cases, because we might turn bottom into+non-bottom!++The code in SimplUtils.prepareAlts has the effect of generalise this+idea to look for a case where we're scrutinising a variable, and we+know that only the default case can match. For example:++ case x of+ 0# -> ...+ DEFAULT -> ...(case x of+ 0# -> ...+ DEFAULT -> ...) ...++Here the inner case is first trimmed to have only one alternative, the+DEFAULT, after which it's an instance of the previous case. This+really only shows up in eliminating error-checking code.++Note that SimplUtils.mkCase combines identical RHSs. So++ case e of ===> case e of DEFAULT -> r+ True -> r+ False -> r++Now again the case may be elminated by the CaseElim transformation.+This includes things like (==# a# b#)::Bool so that we simplify+ case ==# a# b# of { True -> x; False -> x }+to just+ x+This particular example shows up in default methods for+comparison operations (e.g. in (>=) for Int.Int32)++Note [Case elimination: lifted case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If a case over a lifted type has a single alternative, and is being used+as a strict 'let' (all isDeadBinder bndrs), we may want to do this+transformation:++ case e of r ===> let r = e in ...r...+ _ -> ...r...++ (a) 'e' is already evaluated (it may so if e is a variable)+ Specifically we check (exprIsHNF e). In this case+ we can just allocate the WHNF directly with a let.+or+ (b) 'x' is not used at all and e is ok-for-speculation+ The ok-for-spec bit checks that we don't lose any+ exceptions or divergence.++ NB: it'd be *sound* to switch from case to let if the+ scrutinee was not yet WHNF but was guaranteed to+ converge; but sticking with case means we won't build a+ thunk++or+ (c) 'x' is used strictly in the body, and 'e' is a variable+ Then we can just substitute 'e' for 'x' in the body.+ See Note [Eliminating redundant seqs]++For (b), the "not used at all" test is important. Consider+ case (case a ># b of { True -> (p,q); False -> (q,p) }) of+ r -> blah+The scrutinee is ok-for-speculation (it looks inside cases), but we do+not want to transform to+ let r = case a ># b of { True -> (p,q); False -> (q,p) }+ in blah+because that builds an unnecessary thunk.++Note [Eliminating redundant seqs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have this:+ case x of r { _ -> ..r.. }+where 'r' is used strictly in (..r..), the case is effectively a 'seq'+on 'x', but since 'r' is used strictly anyway, we can safely transform to+ (...x...)++Note that this can change the error behaviour. For example, we might+transform+ case x of { _ -> error "bad" }+ --> error "bad"+which is might be puzzling if 'x' currently lambda-bound, but later gets+let-bound to (error "good").++Nevertheless, the paper "A semantics for imprecise exceptions" allows+this transformation. If you want to fix the evaluation order, use+'pseq'. See Trac #8900 for an example where the loss of this+transformation bit us in practice.++See also Note [Empty case alternatives] in CoreSyn.++Just for reference, the original code (added Jan 13) looked like this:+ || case_bndr_evald_next rhs++ case_bndr_evald_next :: CoreExpr -> Bool+ -- See Note [Case binder next]+ case_bndr_evald_next (Var v) = v == case_bndr+ case_bndr_evald_next (Cast e _) = case_bndr_evald_next e+ case_bndr_evald_next (App e _) = case_bndr_evald_next e+ case_bndr_evald_next (Case e _ _ _) = case_bndr_evald_next e+ case_bndr_evald_next _ = False++(This came up when fixing Trac #7542. See also Note [Eta reduction of+an eval'd function] in CoreUtils.)+++Note [Case elimination: unlifted case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ case a +# b of r -> ...r...+Then we do case-elimination (to make a let) followed by inlining,+to get+ .....(a +# b)....+If we have+ case indexArray# a i of r -> ...r...+we might like to do the same, and inline the (indexArray# a i).+But indexArray# is not okForSpeculation, so we don't build a let+in rebuildCase (lest it get floated *out*), so the inlining doesn't+happen either.++This really isn't a big deal I think. The let can be+++Further notes about case elimination+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider: test :: Integer -> IO ()+ test = print++Turns out that this compiles to:+ Print.test+ = \ eta :: Integer+ eta1 :: Void# ->+ case PrelNum.< eta PrelNum.zeroInteger of wild { __DEFAULT ->+ case hPutStr stdout+ (PrelNum.jtos eta ($w[] @ Char))+ eta1+ of wild1 { (# new_s, a4 #) -> PrelIO.lvl23 new_s }}++Notice the strange '<' which has no effect at all. This is a funny one.+It started like this:++f x y = if x < 0 then jtos x+ else if y==0 then "" else jtos x++At a particular call site we have (f v 1). So we inline to get++ if v < 0 then jtos x+ else if 1==0 then "" else jtos x++Now simplify the 1==0 conditional:++ if v<0 then jtos v else jtos v++Now common-up the two branches of the case:++ case (v<0) of DEFAULT -> jtos v++Why don't we drop the case? Because it's strict in v. It's technically+wrong to drop even unnecessary evaluations, and in practice they+may be a result of 'seq' so we *definitely* don't want to drop those.+I don't really know how to improve this situation.+-}++---------------------------------------------------------+-- Eliminate the case if possible++rebuildCase, reallyRebuildCase+ :: SimplEnv+ -> OutExpr -- Scrutinee+ -> InId -- Case binder+ -> [InAlt] -- Alternatives (inceasing order)+ -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++--------------------------------------------------+-- 1. Eliminate the case if there's a known constructor+--------------------------------------------------++rebuildCase env scrut case_bndr alts cont+ | Lit lit <- scrut -- No need for same treatment as constructors+ -- because literals are inlined more vigorously+ , not (litIsLifted lit)+ = do { tick (KnownBranch case_bndr)+ ; case findAlt (LitAlt lit) alts of+ Nothing -> missingAlt env case_bndr alts cont+ Just (_, bs, rhs) -> simple_rhs bs rhs }++ | Just (con, ty_args, other_args) <- exprIsConApp_maybe (getUnfoldingInRuleMatch env) scrut+ -- Works when the scrutinee is a variable with a known unfolding+ -- as well as when it's an explicit constructor application+ = do { tick (KnownBranch case_bndr)+ ; case findAlt (DataAlt con) alts of+ Nothing -> missingAlt env case_bndr alts cont+ Just (DEFAULT, bs, rhs) -> simple_rhs bs rhs+ Just (_, bs, rhs) -> knownCon env scrut con ty_args other_args+ case_bndr bs rhs cont+ }+ where+ simple_rhs bs rhs = ASSERT( null bs )+ do { env' <- simplNonRecX env case_bndr scrut+ -- scrut is a constructor application,+ -- hence satisfies let/app invariant+ ; simplExprF env' rhs cont }+++--------------------------------------------------+-- 2. Eliminate the case if scrutinee is evaluated+--------------------------------------------------++rebuildCase env scrut case_bndr alts@[(_, bndrs, rhs)] cont+ -- See if we can get rid of the case altogether+ -- See Note [Case elimination]+ -- mkCase made sure that if all the alternatives are equal,+ -- then there is now only one (DEFAULT) rhs++ -- 2a. Dropping the case altogether, if+ -- a) it binds nothing (so it's really just a 'seq')+ -- b) evaluating the scrutinee has no side effects+ | is_plain_seq+ , exprOkForSideEffects scrut+ -- The entire case is dead, so we can drop it+ -- if the scrutinee converges without having imperative+ -- side effects or raising a Haskell exception+ -- See Note [PrimOp can_fail and has_side_effects] in PrimOp+ = simplExprF env rhs cont++ -- 2b. Turn the case into a let, if+ -- a) it binds only the case-binder+ -- b) unlifted case: the scrutinee is ok-for-speculation+ -- lifted case: the scrutinee is in HNF (or will later be demanded)+ | all_dead_bndrs+ , if is_unlifted+ then exprOkForSpeculation scrut -- See Note [Case elimination: unlifted case]+ else exprIsHNF scrut -- See Note [Case elimination: lifted case]+ || scrut_is_demanded_var scrut+ = do { tick (CaseElim case_bndr)+ ; env' <- simplNonRecX env case_bndr scrut+ ; simplExprF env' rhs cont }++ -- 2c. Try the seq rules if+ -- a) it binds only the case binder+ -- b) a rule for seq applies+ -- See Note [User-defined RULES for seq] in MkId+ | is_plain_seq+ = do { mb_rule <- trySeqRules env scrut rhs cont+ ; case mb_rule of+ Just (env', rule_rhs, cont') -> simplExprF env' rule_rhs cont'+ Nothing -> reallyRebuildCase env scrut case_bndr alts cont }+ where+ is_unlifted = isUnliftedType (idType case_bndr)+ all_dead_bndrs = all isDeadBinder bndrs -- bndrs are [InId]+ is_plain_seq = all_dead_bndrs && isDeadBinder case_bndr -- Evaluation *only* for effect++ scrut_is_demanded_var :: CoreExpr -> Bool+ -- See Note [Eliminating redundant seqs]+ scrut_is_demanded_var (Cast s _) = scrut_is_demanded_var s+ scrut_is_demanded_var (Var _) = isStrictDmd (idDemandInfo case_bndr)+ scrut_is_demanded_var _ = False+++rebuildCase env scrut case_bndr alts cont+ = reallyRebuildCase env scrut case_bndr alts cont++--------------------------------------------------+-- 3. Catch-all case+--------------------------------------------------++reallyRebuildCase env scrut case_bndr alts cont+ = do { -- Prepare the continuation;+ -- The new subst_env is in place+ (env', dup_cont, nodup_cont) <- prepareCaseCont (zapJoinFloats env)+ alts cont++ -- Simplify the alternatives+ ; (scrut', case_bndr', alts') <- simplAlts env' scrut case_bndr alts dup_cont++ ; dflags <- getDynFlags+ ; let alts_ty' = contResultType dup_cont+ -- See Note [Avoiding space leaks in OutType]+ ; case_expr <- seqType alts_ty' `seq`+ mkCase dflags scrut' case_bndr' alts_ty' alts'++ -- Notice that rebuild gets the in-scope set from env', not alt_env+ -- (which in any case is only build in simplAlts)+ -- The case binder *not* scope over the whole returned case-expression+ ; rebuild (env' `restoreJoinFloats` env)+ (wrapJoinFloats env' case_expr) nodup_cont }++{-+simplCaseBinder checks whether the scrutinee is a variable, v. If so,+try to eliminate uses of v in the RHSs in favour of case_bndr; that+way, there's a chance that v will now only be used once, and hence+inlined.++Historical note: we use to do the "case binder swap" in the Simplifier+so there were additional complications if the scrutinee was a variable.+Now the binder-swap stuff is done in the occurrence analyer; see+OccurAnal Note [Binder swap].++Note [knownCon occ info]+~~~~~~~~~~~~~~~~~~~~~~~~+If the case binder is not dead, then neither are the pattern bound+variables:+ case <any> of x { (a,b) ->+ case x of { (p,q) -> p } }+Here (a,b) both look dead, but come alive after the inner case is eliminated.+The point is that we bring into the envt a binding+ let x = (a,b)+after the outer case, and that makes (a,b) alive. At least we do unless+the case binder is guaranteed dead.++Note [Case alternative occ info]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we are simply reconstructing a case (the common case), we always+zap the occurrence info on the binders in the alternatives. Even+if the case binder is dead, the scrutinee is usually a variable, and *that*+can bring the case-alternative binders back to life.+See Note [Add unfolding for scrutinee]++Note [Improving seq]+~~~~~~~~~~~~~~~~~~~+Consider+ type family F :: * -> *+ type instance F Int = Int++We'd like to transform+ case e of (x :: F Int) { DEFAULT -> rhs }+===>+ case e `cast` co of (x'::Int)+ I# x# -> let x = x' `cast` sym co+ in rhs++so that 'rhs' can take advantage of the form of x'. Notice that Note+[Case of cast] (in OccurAnal) may then apply to the result.++We'd also like to eliminate empty types (Trac #13468). So if++ data Void+ type instance F Bool = Void++then we'd like to transform+ case (x :: F Bool) of { _ -> error "urk" }+===>+ case (x |> co) of (x' :: Void) of {}++Nota Bene: we used to have a built-in rule for 'seq' that dropped+casts, so that+ case (x |> co) of { _ -> blah }+dropped the cast; in order to imporove the chances of trySeqRules+firing. But that works in the /opposite/ direction to Note [Improving+seq] so there's a danger of flip/flopping. Better to make trySeqRules+insensitive to the cast, which is now is.++The need for [Improving seq] showed up in Roman's experiments. Example:+ foo :: F Int -> Int -> Int+ foo t n = t `seq` bar n+ where+ bar 0 = 0+ bar n = bar (n - case t of TI i -> i)+Here we'd like to avoid repeated evaluating t inside the loop, by+taking advantage of the `seq`.++At one point I did transformation in LiberateCase, but it's more+robust here. (Otherwise, there's a danger that we'll simply drop the+'seq' altogether, before LiberateCase gets to see it.)+-}++simplAlts :: SimplEnv+ -> OutExpr+ -> InId -- Case binder+ -> [InAlt] -- Non-empty+ -> SimplCont+ -> SimplM (OutExpr, OutId, [OutAlt]) -- Includes the continuation+-- Like simplExpr, this just returns the simplified alternatives;+-- it does not return an environment+-- The returned alternatives can be empty, none are possible++simplAlts env scrut case_bndr alts cont'+ = do { let env0 = zapFloats env++ ; (env1, case_bndr1) <- simplBinder env0 case_bndr+ ; let case_bndr2 = case_bndr1 `setIdUnfolding` evaldUnfolding+ env2 = modifyInScope env1 case_bndr2+ -- See Note [Case binder evaluated-ness]++ ; fam_envs <- getFamEnvs+ ; (alt_env', scrut', case_bndr') <- improveSeq fam_envs env2 scrut+ case_bndr case_bndr2 alts++ ; (imposs_deflt_cons, in_alts) <- prepareAlts scrut' case_bndr' alts+ -- NB: it's possible that the returned in_alts is empty: this is handled+ -- by the caller (rebuildCase) in the missingAlt function++ ; alts' <- mapM (simplAlt alt_env' (Just scrut') imposs_deflt_cons case_bndr' cont') in_alts+ ; -- pprTrace "simplAlts" (ppr case_bndr $$ ppr alts_ty $$ ppr alts_ty' $$ ppr alts $$ ppr cont') $+ return (scrut', case_bndr', alts') }+++------------------------------------+improveSeq :: (FamInstEnv, FamInstEnv) -> SimplEnv+ -> OutExpr -> InId -> OutId -> [InAlt]+ -> SimplM (SimplEnv, OutExpr, OutId)+-- Note [Improving seq]+improveSeq fam_envs env scrut case_bndr case_bndr1 [(DEFAULT,_,_)]+ | Just (co, ty2) <- topNormaliseType_maybe fam_envs (idType case_bndr1)+ = do { case_bndr2 <- newId (fsLit "nt") ty2+ ; let rhs = DoneEx (Var case_bndr2 `Cast` mkSymCo co)+ env2 = extendIdSubst env case_bndr rhs+ ; return (env2, scrut `Cast` co, case_bndr2) }++improveSeq _ env scrut _ case_bndr1 _+ = return (env, scrut, case_bndr1)+++------------------------------------+simplAlt :: SimplEnv+ -> Maybe OutExpr -- The scrutinee+ -> [AltCon] -- These constructors can't be present when+ -- matching the DEFAULT alternative+ -> OutId -- The case binder+ -> SimplCont+ -> InAlt+ -> SimplM OutAlt++simplAlt env _ imposs_deflt_cons case_bndr' cont' (DEFAULT, bndrs, rhs)+ = ASSERT( null bndrs )+ do { let env' = addBinderUnfolding env case_bndr'+ (mkOtherCon imposs_deflt_cons)+ -- Record the constructors that the case-binder *can't* be.+ ; rhs' <- simplExprC env' rhs cont'+ ; return (DEFAULT, [], rhs') }++simplAlt env scrut' _ case_bndr' cont' (LitAlt lit, bndrs, rhs)+ = ASSERT( null bndrs )+ do { env' <- addAltUnfoldings env scrut' case_bndr' (Lit lit)+ ; rhs' <- simplExprC env' rhs cont'+ ; return (LitAlt lit, [], rhs') }++simplAlt env scrut' _ case_bndr' cont' (DataAlt con, vs, rhs)+ = do { -- Deal with the pattern-bound variables+ -- Mark the ones that are in ! positions in the+ -- data constructor as certainly-evaluated.+ -- NB: simplLamBinders preserves this eval info+ ; let vs_with_evals = add_evals (dataConRepStrictness con)+ ; (env', vs') <- simplLamBndrs env vs_with_evals++ -- Bind the case-binder to (con args)+ ; let inst_tys' = tyConAppArgs (idType case_bndr')+ con_app :: OutExpr+ con_app = mkConApp2 con inst_tys' vs'++ ; env'' <- addAltUnfoldings env' scrut' case_bndr' con_app+ ; rhs' <- simplExprC env'' rhs cont'+ ; return (DataAlt con, vs', rhs') }+ where+ -- add_evals records the evaluated-ness of the bound variables of+ -- a case pattern. This is *important*. Consider+ -- data T = T !Int !Int+ --+ -- case x of { T a b -> T (a+1) b }+ --+ -- We really must record that b is already evaluated so that we don't+ -- go and re-evaluate it when constructing the result.+ -- See Note [Data-con worker strictness] in MkId.hs+ add_evals the_strs+ = go vs the_strs+ where+ go [] [] = []+ go (v:vs') strs | isTyVar v = v : go vs' strs+ go (v:vs') (str:strs) = zap str v : go vs' strs+ go _ _ = pprPanic "cat_evals"+ (ppr con $$+ ppr vs $$+ ppr_with_length the_strs $$+ ppr_with_length (dataConRepArgTys con) $$+ ppr_with_length (dataConRepStrictness con))+ where+ ppr_with_length list+ = ppr list <+> parens (text "length =" <+> ppr (length list))+ -- NB: If this panic triggers, note that+ -- NoStrictnessMark doesn't print!++ zap str v = setCaseBndrEvald str $ -- Add eval'dness info+ zapIdOccInfo v -- And kill occ info;+ -- see Note [Case alternative occ info]++addAltUnfoldings :: SimplEnv -> Maybe OutExpr -> OutId -> OutExpr -> SimplM SimplEnv+addAltUnfoldings env scrut case_bndr con_app+ = do { dflags <- getDynFlags+ ; let con_app_unf = mkSimpleUnfolding dflags con_app+ env1 = addBinderUnfolding env case_bndr con_app_unf++ -- See Note [Add unfolding for scrutinee]+ env2 = case scrut of+ Just (Var v) -> addBinderUnfolding env1 v con_app_unf+ Just (Cast (Var v) co) -> addBinderUnfolding env1 v $+ mkSimpleUnfolding dflags (Cast con_app (mkSymCo co))+ _ -> env1++ ; traceSmpl "addAltUnf" (vcat [ppr case_bndr <+> ppr scrut, ppr con_app])+ ; return env2 }++addBinderUnfolding :: SimplEnv -> Id -> Unfolding -> SimplEnv+addBinderUnfolding env bndr unf+ | debugIsOn, Just tmpl <- maybeUnfoldingTemplate unf+ = WARN( not (eqType (idType bndr) (exprType tmpl)),+ ppr bndr $$ ppr (idType bndr) $$ ppr tmpl $$ ppr (exprType tmpl) )+ modifyInScope env (bndr `setIdUnfolding` unf)++ | otherwise+ = modifyInScope env (bndr `setIdUnfolding` unf)++zapBndrOccInfo :: Bool -> Id -> Id+-- Consider case e of b { (a,b) -> ... }+-- Then if we bind b to (a,b) in "...", and b is not dead,+-- then we must zap the deadness info on a,b+zapBndrOccInfo keep_occ_info pat_id+ | keep_occ_info = pat_id+ | otherwise = zapIdOccInfo pat_id++{- Note [Case binder evaluated-ness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We pin on a (OtherCon []) unfolding to the case-binder of a Case,+even though it'll be over-ridden in every case alternative with a more+informative unfolding. Why? Because suppose a later, less clever, pass+simply replaces all occurrences of the case binder with the binder itself;+then Lint may complain about the let/app invariant. Example+ case e of b { DEFAULT -> let v = reallyUnsafePtrEq# b y in ....+ ; K -> blah }++The let/app invariant requires that y is evaluated in the call to+reallyUnsafePtrEq#, which it is. But we still want that to be true if we+propagate binders to occurrences.++This showed up in Trac #13027.++Note [Add unfolding for scrutinee]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general it's unlikely that a variable scrutinee will appear+in the case alternatives case x of { ...x unlikely to appear... }+because the binder-swap in OccAnal has got rid of all such occcurrences+See Note [Binder swap] in OccAnal.++BUT it is still VERY IMPORTANT to add a suitable unfolding for a+variable scrutinee, in simplAlt. Here's why+ case x of y+ (a,b) -> case b of c+ I# v -> ...(f y)...+There is no occurrence of 'b' in the (...(f y)...). But y gets+the unfolding (a,b), and *that* mentions b. If f has a RULE+ RULE f (p, I# q) = ...+we want that rule to match, so we must extend the in-scope env with a+suitable unfolding for 'y'. It's *essential* for rule matching; but+it's also good for case-elimintation -- suppose that 'f' was inlined+and did multi-level case analysis, then we'd solve it in one+simplifier sweep instead of two.++Exactly the same issue arises in SpecConstr;+see Note [Add scrutinee to ValueEnv too] in SpecConstr++HOWEVER, given+ case x of y { Just a -> r1; Nothing -> r2 }+we do not want to add the unfolding x -> y to 'x', which might seem cool,+since 'y' itself has different unfoldings in r1 and r2. Reason: if we+did that, we'd have to zap y's deadness info and that is a very useful+piece of information.++So instead we add the unfolding x -> Just a, and x -> Nothing in the+respective RHSs.+++************************************************************************+* *+\subsection{Known constructor}+* *+************************************************************************++We are a bit careful with occurrence info. Here's an example++ (\x* -> case x of (a*, b) -> f a) (h v, e)++where the * means "occurs once". This effectively becomes+ case (h v, e) of (a*, b) -> f a)+and then+ let a* = h v; b = e in f a+and then+ f (h v)++All this should happen in one sweep.+-}++knownCon :: SimplEnv+ -> OutExpr -- The scrutinee+ -> DataCon -> [OutType] -> [OutExpr] -- The scrutinee (in pieces)+ -> InId -> [InBndr] -> InExpr -- The alternative+ -> SimplCont+ -> SimplM (SimplEnv, OutExpr)++knownCon env scrut dc dc_ty_args dc_args bndr bs rhs cont+ = do { env' <- bind_args env bs dc_args+ ; env'' <- bind_case_bndr env'+ ; simplExprF env'' rhs cont }+ where+ zap_occ = zapBndrOccInfo (isDeadBinder bndr) -- bndr is an InId++ -- Ugh!+ bind_args env' [] _ = return env'++ bind_args env' (b:bs') (Type ty : args)+ = ASSERT( isTyVar b )+ bind_args (extendTvSubst env' b ty) bs' args++ bind_args env' (b:bs') (Coercion co : args)+ = ASSERT( isCoVar b )+ bind_args (extendCvSubst env' b co) bs' args++ bind_args env' (b:bs') (arg : args)+ = ASSERT( isId b )+ do { let b' = zap_occ b+ -- Note that the binder might be "dead", because it doesn't+ -- occur in the RHS; and simplNonRecX may therefore discard+ -- it via postInlineUnconditionally.+ -- Nevertheless we must keep it if the case-binder is alive,+ -- because it may be used in the con_app. See Note [knownCon occ info]+ ; env'' <- simplNonRecX env' b' arg -- arg satisfies let/app invariant+ ; bind_args env'' bs' args }++ bind_args _ _ _ =+ pprPanic "bind_args" $ ppr dc $$ ppr bs $$ ppr dc_args $$+ text "scrut:" <+> ppr scrut++ -- It's useful to bind bndr to scrut, rather than to a fresh+ -- binding x = Con arg1 .. argn+ -- because very often the scrut is a variable, so we avoid+ -- creating, and then subsequently eliminating, a let-binding+ -- BUT, if scrut is a not a variable, we must be careful+ -- about duplicating the arg redexes; in that case, make+ -- a new con-app from the args+ bind_case_bndr env+ | isDeadBinder bndr = return env+ | exprIsTrivial scrut = return (extendIdSubst env bndr (DoneEx scrut))+ | otherwise = do { dc_args <- mapM (simplVar env) bs+ -- dc_ty_args are aready OutTypes,+ -- but bs are InBndrs+ ; let con_app = Var (dataConWorkId dc)+ `mkTyApps` dc_ty_args+ `mkApps` dc_args+ ; simplNonRecX env bndr con_app }++-------------------+missingAlt :: SimplEnv -> Id -> [InAlt] -> SimplCont -> SimplM (SimplEnv, OutExpr)+ -- This isn't strictly an error, although it is unusual.+ -- It's possible that the simplifier might "see" that+ -- an inner case has no accessible alternatives before+ -- it "sees" that the entire branch of an outer case is+ -- inaccessible. So we simply put an error case here instead.+missingAlt env case_bndr _ cont+ = WARN( True, text "missingAlt" <+> ppr case_bndr )+ -- See Note [Avoiding space leaks in OutType]+ let cont_ty = contResultType cont+ in seqType cont_ty `seq` return (env, mkImpossibleExpr cont_ty)++{-+************************************************************************+* *+\subsection{Duplicating continuations}+* *+************************************************************************+-}++prepareCaseCont :: SimplEnv+ -> [InAlt] -> SimplCont+ -> SimplM (SimplEnv,+ SimplCont, -- Dupable part+ SimplCont) -- Non-dupable part+-- We are considering+-- K[case _ of { p1 -> r1; ...; pn -> rn }]+-- where K is some enclosing continuation for the case+-- Goal: split K into two pieces Kdup,Knodup so that+-- a) Kdup can be duplicated+-- b) Knodup[Kdup[e]] = K[e]+-- The idea is that we'll transform thus:+-- Knodup[ (case _ of { p1 -> Kdup[r1]; ...; pn -> Kdup[rn] }+--+-- We may also return some extra value bindings in SimplEnv (that scope over+-- the entire continuation) as well as some join points (thus must *not* float+-- past the continuation!).+-- Hence, the full story is this:+-- K[case _ of { p1 -> r1; ...; pn -> rn }] ==>+-- F_v[Knodup[F_j[ (case _ of { p1 -> Kdup[r1]; ...; pn -> Kdup[rn] }) ]]]+-- Here F_v represents some values that got floated out and F_j represents some+-- join points that got floated out.+--+-- When case-of-case is off, just make the entire continuation non-dupable++prepareCaseCont env alts cont+ | not (sm_case_case (getMode env))+ = return (env, mkBoringStop (contHoleType cont), cont)+ | not (altsWouldDup alts)+ = return (env, cont, mkBoringStop (contResultType cont))+ | otherwise+ = mkDupableCont env cont++prepareLetCont :: SimplEnv+ -> [InBndr] -> SimplCont+ -> SimplM (SimplEnv,+ SimplCont, -- Dupable part+ SimplCont) -- Non-dupable part++-- Similar to prepareCaseCont, only for+-- K[let { j1 = r1; ...; jn -> rn } in _]+-- If the js are join points, this will turn into+-- Knodup[join { j1 = Kdup[r1]; ...; jn = Kdup[rn] } in Kdup[_]].+--+-- When case-of-case is off and it's a join binding, just make the entire+-- continuation non-dupable. This is necessary because otherwise+-- case (join j = ... in case e of { A -> jump j 1; ... }) of { B -> ... }+-- becomes+-- join j = case ... of { B -> ... } in+-- case (case e of { A -> jump j 1; ... }) of { B -> ... },+-- and the reference to j is invalid.++prepareLetCont env bndrs cont+ | not (isJoinId (head bndrs))+ = return (env, cont, mkBoringStop (contResultType cont))+ | not (sm_case_case (getMode env))+ = return (env, mkBoringStop (contHoleType cont), cont)+ | otherwise+ = mkDupableCont env cont++-- Predict the result type of the dupable cont returned by prepareLetCont (= the+-- hole type of the non-dupable part). Ugly, but sadly necessary so that we can+-- know what the new type of a recursive join point will be before we start+-- simplifying it.+resultTypeOfDupableCont :: SimplifierMode+ -> [InBndr]+ -> SimplCont+ -> OutType -- INVARIANT: Result type of dupable cont+ -- returned by prepareLetCont+-- IMPORTANT: This must be kept in sync with mkDupableCont!+resultTypeOfDupableCont mode bndrs cont+ | not (any isJoinId bndrs) = contResultType cont+ | not (sm_case_case mode) = contHoleType cont+ | otherwise = go cont+ where+ go cont | contIsDupable cont = contResultType cont+ go (Stop {}) = panic "typeOfDupableCont" -- Handled by previous eqn+ go (CastIt _ cont) = go cont+ go cont@(TickIt {}) = contHoleType cont+ go cont@(StrictBind {}) = contHoleType cont+ go (StrictArg _ _ cont) = go cont+ go cont@(ApplyToTy {}) = go (sc_cont cont)+ go cont@(ApplyToVal {}) = go (sc_cont cont)+ go (Select { sc_alts = alts, sc_cont = cont })+ | not (sm_case_case mode) = contHoleType cont+ | not (altsWouldDup alts) = contResultType cont+ | otherwise = go cont++altsWouldDup :: [InAlt] -> Bool -- True iff strictly > 1 non-bottom alternative+altsWouldDup [] = False -- See Note [Bottom alternatives]+altsWouldDup [_] = False+altsWouldDup (alt:alts)+ | is_bot_alt alt = altsWouldDup alts+ | otherwise = not (all is_bot_alt alts)+ where+ is_bot_alt (_,_,rhs) = exprIsBottom rhs++{-+Note [Bottom alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~+When we have+ case (case x of { A -> error .. ; B -> e; C -> error ..)+ of alts+then we can just duplicate those alts because the A and C cases+will disappear immediately. This is more direct than creating+join points and inlining them away. See Trac #4930.+-}++mkDupableCont :: SimplEnv -> SimplCont+ -> SimplM (SimplEnv, SimplCont, SimplCont)++mkDupableCont env cont+ | contIsDupable cont+ = return (env, cont, mkBoringStop (contResultType cont))++mkDupableCont _ (Stop {}) = panic "mkDupableCont" -- Handled by previous eqn++mkDupableCont env (CastIt ty cont)+ = do { (env', dup, nodup) <- mkDupableCont env cont+ ; return (env', CastIt ty dup, nodup) }++-- Duplicating ticks for now, not sure if this is good or not+mkDupableCont env cont@(TickIt{})+ = return (env, mkBoringStop (contHoleType cont), cont)++mkDupableCont env cont@(StrictBind {})+ = return (env, mkBoringStop (contHoleType cont), cont)+ -- See Note [Duplicating StrictBind]++mkDupableCont env (StrictArg info cci cont)+ -- See Note [Duplicating StrictArg]+ = do { (env', dup, nodup) <- mkDupableCont env cont+ ; (env'', args') <- mapAccumLM makeTrivialArg env' (ai_args info)+ ; return (env'', StrictArg (info { ai_args = args' }) cci dup, nodup) }++mkDupableCont env cont@(ApplyToTy { sc_cont = tail })+ = do { (env', dup_cont, nodup_cont) <- mkDupableCont env tail+ ; return (env', cont { sc_cont = dup_cont }, nodup_cont ) }++mkDupableCont env (ApplyToVal { sc_arg = arg, sc_dup = dup, sc_env = se, sc_cont = cont })+ = -- e.g. [...hole...] (...arg...)+ -- ==>+ -- let a = ...arg...+ -- in [...hole...] a+ do { (env', dup_cont, nodup_cont) <- mkDupableCont env cont+ ; (_, se', arg') <- simplArg env' dup se arg+ ; (env'', arg'') <- makeTrivial NotTopLevel env' (fsLit "karg") arg'+ ; let app_cont = ApplyToVal { sc_arg = arg'', sc_env = se'+ , sc_dup = OkToDup, sc_cont = dup_cont }+ ; return (env'', app_cont, nodup_cont) }++mkDupableCont env (Select { sc_bndr = case_bndr, sc_alts = alts+ , sc_env = se, sc_cont = cont })+ = -- e.g. (case [...hole...] of { pi -> ei })+ -- ===>+ -- let ji = \xij -> ei+ -- in case [...hole...] of { pi -> ji xij }+ do { tick (CaseOfCase case_bndr)+ ; (env', dup_cont, nodup_cont) <- prepareCaseCont env alts cont+ -- NB: We call prepareCaseCont here. If there is only one+ -- alternative, then dup_cont may be big, but that's ok+ -- because we push it into the single alternative, and then+ -- use mkDupableAlt to turn that simplified alternative into+ -- a join point if it's too big to duplicate.+ -- And this is important: see Note [Fusing case continuations]++ ; let alt_env = se `setInScopeAndZapFloats` env'++ ; (alt_env', case_bndr') <- simplBinder alt_env case_bndr+ ; alts' <- mapM (simplAlt alt_env' Nothing [] case_bndr' dup_cont) alts+ -- Safe to say that there are no handled-cons for the DEFAULT case+ -- NB: simplBinder does not zap deadness occ-info, so+ -- a dead case_bndr' will still advertise its deadness+ -- This is really important because in+ -- case e of b { (# p,q #) -> ... }+ -- b is always dead, and indeed we are not allowed to bind b to (# p,q #),+ -- which might happen if e was an explicit unboxed pair and b wasn't marked dead.+ -- In the new alts we build, we have the new case binder, so it must retain+ -- its deadness.+ -- NB: we don't use alt_env further; it has the substEnv for+ -- the alternatives, and we don't want that++ ; (env'', alts'') <- mkDupableAlts env' case_bndr' alts'+ ; return (env'', -- Note [Duplicated env]+ Select { sc_dup = OkToDup+ , sc_bndr = case_bndr', sc_alts = alts''+ , sc_env = zapSubstEnv env''+ , sc_cont = mkBoringStop (contHoleType nodup_cont) },+ nodup_cont) }+++mkDupableAlts :: SimplEnv -> OutId -> [InAlt]+ -> SimplM (SimplEnv, [InAlt])+-- Absorbs the continuation into the new alternatives++mkDupableAlts env case_bndr' the_alts+ = go env the_alts+ where+ go env0 [] = return (env0, [])+ go env0 (alt:alts)+ = do { (env1, alt') <- mkDupableAlt env0 case_bndr' alt+ ; (env2, alts') <- go env1 alts+ ; return (env2, alt' : alts' ) }++mkDupableAlt :: SimplEnv -> OutId -> (AltCon, [CoreBndr], CoreExpr)+ -> SimplM (SimplEnv, (AltCon, [CoreBndr], CoreExpr))+mkDupableAlt env case_bndr (con, bndrs', rhs') = do+ dflags <- getDynFlags+ if exprIsDupable dflags rhs' -- Note [Small alternative rhs]+ then return (env, (con, bndrs', rhs'))+ else+ do { let rhs_ty' = exprType rhs'+ scrut_ty = idType case_bndr+ case_bndr_w_unf+ = case con of+ DEFAULT -> case_bndr+ DataAlt dc -> setIdUnfolding case_bndr unf+ where+ -- See Note [Case binders and join points]+ unf = mkInlineUnfolding rhs+ rhs = mkConApp2 dc (tyConAppArgs scrut_ty) bndrs'++ LitAlt {} -> WARN( True, text "mkDupableAlt"+ <+> ppr case_bndr <+> ppr con )+ case_bndr+ -- The case binder is alive but trivial, so why has+ -- it not been substituted away?++ final_bndrs'+ | isDeadBinder case_bndr = filter abstract_over bndrs'+ | otherwise = bndrs' ++ [case_bndr_w_unf]++ abstract_over bndr+ | isTyVar bndr = True -- Abstract over all type variables just in case+ | otherwise = not (isDeadBinder bndr)+ -- The deadness info on the new Ids is preserved by simplBinders+ final_args -- Note [Join point abstraction]+ = varsToCoreExprs final_bndrs'++ ; join_bndr <- newId (fsLit "$j") (mkLamTypes final_bndrs' rhs_ty')+ -- Note [Funky mkLamTypes]++ ; let -- We make the lambdas into one-shot-lambdas. The+ -- join point is sure to be applied at most once, and doing so+ -- prevents the body of the join point being floated out by+ -- the full laziness pass+ really_final_bndrs = map one_shot final_bndrs'+ one_shot v | isId v = setOneShotLambda v+ | otherwise = v+ join_rhs = mkLams really_final_bndrs rhs'+ arity = length (filter (not . isTyVar) final_bndrs')+ join_arity = length final_bndrs'+ final_join_bndr = (join_bndr `setIdArity` arity)+ `asJoinId` join_arity+ join_call = mkApps (Var final_join_bndr) final_args+ final_join_bind = NonRec final_join_bndr join_rhs++ ; env' <- addPolyBind NotTopLevel env final_join_bind+ ; return (env', (con, bndrs', join_call)) }+ -- See Note [Duplicated env]++{-+Note [Fusing case continuations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's important to fuse two successive case continuations when the+first has one alternative. That's why we call prepareCaseCont here.+Consider this, which arises from thunk splitting (see Note [Thunk+splitting] in WorkWrap):++ let+ x* = case (case v of {pn -> rn}) of+ I# a -> I# a+ in body++The simplifier will find+ (Var v) with continuation+ Select (pn -> rn) (+ Select [I# a -> I# a] (+ StrictBind body Stop++So we'll call mkDupableCont on+ Select [I# a -> I# a] (StrictBind body Stop)+There is just one alternative in the first Select, so we want to+simplify the rhs (I# a) with continuation (StricgtBind body Stop)+Supposing that body is big, we end up with+ let $j a = <let x = I# a in body>+ in case v of { pn -> case rn of+ I# a -> $j a }+This is just what we want because the rn produces a box that+the case rn cancels with.++See Trac #4957 a fuller example.++Note [Case binders and join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ case (case .. ) of c {+ I# c# -> ....c....++If we make a join point with c but not c# we get+ $j = \c -> ....c....++But if later inlining scrutinises the c, thus++ $j = \c -> ... case c of { I# y -> ... } ...++we won't see that 'c' has already been scrutinised. This actually+happens in the 'tabulate' function in wave4main, and makes a significant+difference to allocation.++An alternative plan is this:++ $j = \c# -> let c = I# c# in ...c....++but that is bad if 'c' is *not* later scrutinised.++So instead we do both: we pass 'c' and 'c#' , and record in c's inlining+(a stable unfolding) that it's really I# c#, thus++ $j = \c# -> \c[=I# c#] -> ...c....++Absence analysis may later discard 'c'.++NB: take great care when doing strictness analysis;+ see Note [Lambda-bound unfoldings] in DmdAnal.++Also note that we can still end up passing stuff that isn't used. Before+strictness analysis we have+ let $j x y c{=(x,y)} = (h c, ...)+ in ...+After strictness analysis we see that h is strict, we end up with+ let $j x y c{=(x,y)} = ($wh x y, ...)+and c is unused.++Note [Duplicated env]+~~~~~~~~~~~~~~~~~~~~~+Some of the alternatives are simplified, but have not been turned into a join point+So they *must* have an zapped subst-env. So we can't use completeNonRecX to+bind the join point, because it might to do PostInlineUnconditionally, and+we'd lose that when zapping the subst-env. We could have a per-alt subst-env,+but zapping it (as we do in mkDupableCont, the Select case) is safe, and+at worst delays the join-point inlining.++Note [Small alternative rhs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It is worth checking for a small RHS because otherwise we+get extra let bindings that may cause an extra iteration of the simplifier to+inline back in place. Quite often the rhs is just a variable or constructor.+The Ord instance of Maybe in PrelMaybe.hs, for example, took several extra+iterations because the version with the let bindings looked big, and so wasn't+inlined, but after the join points had been inlined it looked smaller, and so+was inlined.++NB: we have to check the size of rhs', not rhs.+Duplicating a small InAlt might invalidate occurrence information+However, if it *is* dupable, we return the *un* simplified alternative,+because otherwise we'd need to pair it up with an empty subst-env....+but we only have one env shared between all the alts.+(Remember we must zap the subst-env before re-simplifying something).+Rather than do this we simply agree to re-simplify the original (small) thing later.++Note [Funky mkLamTypes]+~~~~~~~~~~~~~~~~~~~~~~+Notice the funky mkLamTypes. If the constructor has existentials+it's possible that the join point will be abstracted over+type variables as well as term variables.+ Example: Suppose we have+ data T = forall t. C [t]+ Then faced with+ case (case e of ...) of+ C t xs::[t] -> rhs+ We get the join point+ let j :: forall t. [t] -> ...+ j = /\t \xs::[t] -> rhs+ in+ case (case e of ...) of+ C t xs::[t] -> j t xs++Note [Join point abstraction]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++NB: This note is now historical. Now that "join point" is not a fuzzy concept+but a formal syntactic construct (as distinguished by the JoinId constructor of+IdDetails), each of these concerns is handled separately, with no need for a+vestigial extra argument.++Join points always have at least one value argument,+for several reasons++* If we try to lift a primitive-typed something out+ for let-binding-purposes, we will *caseify* it (!),+ with potentially-disastrous strictness results. So+ instead we turn it into a function: \v -> e+ where v::Void#. The value passed to this function is void,+ which generates (almost) no code.++* CPR. We used to say "&& isUnliftedType rhs_ty'" here, but now+ we make the join point into a function whenever used_bndrs'+ is empty. This makes the join-point more CPR friendly.+ Consider: let j = if .. then I# 3 else I# 4+ in case .. of { A -> j; B -> j; C -> ... }++ Now CPR doesn't w/w j because it's a thunk, so+ that means that the enclosing function can't w/w either,+ which is a lose. Here's the example that happened in practice:+ kgmod :: Int -> Int -> Int+ kgmod x y = if x > 0 && y < 0 || x < 0 && y > 0+ then 78+ else 5++* Let-no-escape. We want a join point to turn into a let-no-escape+ so that it is implemented as a jump, and one of the conditions+ for LNE is that it's not updatable. In CoreToStg, see+ Note [What is a non-escaping let]++* Floating. Since a join point will be entered once, no sharing is+ gained by floating out, but something might be lost by doing+ so because it might be allocated.++I have seen a case alternative like this:+ True -> \v -> ...+It's a bit silly to add the realWorld dummy arg in this case, making+ $j = \s v -> ...+ True -> $j s+(the \v alone is enough to make CPR happy) but I think it's rare++There's a slight infelicity here: we pass the overall+case_bndr to all the join points if it's used in *any* RHS,+because we don't know its usage in each RHS separately+++Note [Duplicating StrictArg]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The original plan had (where E is a big argument)+e.g. f E [..hole..]+ ==> let $j = \a -> f E a+ in $j [..hole..]++But this is terrible! Here's an example:+ && E (case x of { T -> F; F -> T })+Now, && is strict so we end up simplifying the case with++an ArgOf continuation. If we let-bind it, we get+ let $j = \v -> && E v+ in simplExpr (case x of { T -> F; F -> T })+ (ArgOf (\r -> $j r)+And after simplifying more we get+ let $j = \v -> && E v+ in case x of { T -> $j F; F -> $j T }+Which is a Very Bad Thing++What we do now is this+ f E [..hole..]+ ==> let a = E+ in f a [..hole..]+Now if the thing in the hole is a case expression (which is when+we'll call mkDupableCont), we'll push the function call into the+branches, which is what we want. Now RULES for f may fire, and+call-pattern specialisation. Here's an example from Trac #3116+ go (n+1) (case l of+ 1 -> bs'+ _ -> Chunk p fpc (o+1) (l-1) bs')+If we can push the call for 'go' inside the case, we get+call-pattern specialisation for 'go', which is *crucial* for+this program.++Here is the (&&) example:+ && E (case x of { T -> F; F -> T })+ ==> let a = E in+ case x of { T -> && a F; F -> && a T }+Much better!++Notice that+ * Arguments to f *after* the strict one are handled by+ the ApplyToVal case of mkDupableCont. Eg+ f [..hole..] E++ * We can only do the let-binding of E because the function+ part of a StrictArg continuation is an explicit syntax+ tree. In earlier versions we represented it as a function+ (CoreExpr -> CoreEpxr) which we couldn't take apart.++Do *not* duplicate StrictBind and StritArg continuations. We gain+nothing by propagating them into the expressions, and we do lose a+lot.++The desire not to duplicate is the entire reason that+mkDupableCont returns a pair of continuations.++Note [Duplicating StrictBind]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Unlike StrictArg, there doesn't seem anything to gain from+duplicating a StrictBind continuation, so we don't.+++************************************************************************+* *+ Unfoldings+* *+************************************************************************+-}++simplLetUnfolding :: SimplEnv-> TopLevelFlag+ -> Maybe SimplCont+ -> InId+ -> OutExpr+ -> Unfolding -> SimplM Unfolding+simplLetUnfolding env top_lvl cont_mb id new_rhs unf+ | isStableUnfolding unf+ = simplUnfolding env top_lvl cont_mb id unf+ | otherwise+ = is_bottoming `seq` -- See Note [Force bottoming field]+ do { dflags <- getDynFlags+ ; return (mkUnfolding dflags InlineRhs is_top_lvl is_bottoming new_rhs) }+ -- We make an unfolding *even for loop-breakers*.+ -- Reason: (a) It might be useful to know that they are WHNF+ -- (b) In TidyPgm we currently assume that, if we want to+ -- expose the unfolding then indeed we *have* an unfolding+ -- to expose. (We could instead use the RHS, but currently+ -- we don't.) The simple thing is always to have one.+ where+ is_top_lvl = isTopLevel top_lvl+ is_bottoming = isBottomingId id++simplUnfolding :: SimplEnv -> TopLevelFlag+ -> Maybe SimplCont -- Just k => a join point with continuation k+ -> InId+ -> Unfolding -> SimplM Unfolding+-- Note [Setting the new unfolding]+simplUnfolding env top_lvl mb_cont id unf+ = case unf of+ NoUnfolding -> return unf+ BootUnfolding -> return unf+ OtherCon {} -> return unf++ DFunUnfolding { df_bndrs = bndrs, df_con = con, df_args = args }+ -> do { (env', bndrs') <- simplBinders rule_env bndrs+ ; args' <- mapM (simplExpr env') args+ ; return (mkDFunUnfolding bndrs' con args') }++ CoreUnfolding { uf_tmpl = expr, uf_src = src, uf_guidance = guide }+ | isStableSource src+ -> do { expr' <- case mb_cont of+ Just cont -> simplJoinRhs rule_env id expr cont+ Nothing -> simplExpr rule_env expr+ ; case guide of+ UnfWhen { ug_arity = arity, ug_unsat_ok = sat_ok } -- Happens for INLINE things+ -> let guide' = UnfWhen { ug_arity = arity, ug_unsat_ok = sat_ok+ , ug_boring_ok = inlineBoringOk expr' }+ -- Refresh the boring-ok flag, in case expr'+ -- has got small. This happens, notably in the inlinings+ -- for dfuns for single-method classes; see+ -- Note [Single-method classes] in TcInstDcls.+ -- A test case is Trac #4138+ in return (mkCoreUnfolding src is_top_lvl expr' guide')+ -- See Note [Top-level flag on inline rules] in CoreUnfold++ _other -- Happens for INLINABLE things+ -> is_bottoming `seq` -- See Note [Force bottoming field]+ do { dflags <- getDynFlags+ ; return (mkUnfolding dflags src is_top_lvl is_bottoming expr') } }+ -- If the guidance is UnfIfGoodArgs, this is an INLINABLE+ -- unfolding, and we need to make sure the guidance is kept up+ -- to date with respect to any changes in the unfolding.++ | otherwise -> return noUnfolding -- Discard unstable unfoldings+ where+ is_top_lvl = isTopLevel top_lvl+ is_bottoming = isBottomingId id+ act = idInlineActivation id+ rule_env = updMode (updModeForStableUnfoldings act) env+ -- See Note [Simplifying inside stable unfoldings] in SimplUtils++{-+Note [Force bottoming field]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to force bottoming, or the new unfolding holds+on to the old unfolding (which is part of the id).++Note [Setting the new unfolding]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* If there's an INLINE pragma, we simplify the RHS gently. Maybe we+ should do nothing at all, but simplifying gently might get rid of+ more crap.++* If not, we make an unfolding from the new RHS. But *only* for+ non-loop-breakers. Making loop breakers not have an unfolding at all+ means that we can avoid tests in exprIsConApp, for example. This is+ important: if exprIsConApp says 'yes' for a recursive thing, then we+ can get into an infinite loop++If there's an stable unfolding on a loop breaker (which happens for+INLINABLE), we hang on to the inlining. It's pretty dodgy, but the+user did say 'INLINE'. May need to revisit this choice.++************************************************************************+* *+ Rules+* *+************************************************************************++Note [Rules in a letrec]+~~~~~~~~~~~~~~~~~~~~~~~~+After creating fresh binders for the binders of a letrec, we+substitute the RULES and add them back onto the binders; this is done+*before* processing any of the RHSs. This is important. Manuel found+cases where he really, really wanted a RULE for a recursive function+to apply in that function's own right-hand side.++See Note [Forming Rec groups] in OccurAnal+-}++addBndrRules :: SimplEnv -> InBndr -> OutBndr -> SimplM (SimplEnv, OutBndr)+-- Rules are added back into the bin+addBndrRules env in_id out_id+ | null old_rules+ = return (env, out_id)+ | otherwise+ = do { new_rules <- simplRules env (Just (idName out_id)) old_rules+ ; let final_id = out_id `setIdSpecialisation` mkRuleInfo new_rules+ ; return (modifyInScope env final_id, final_id) }+ where+ old_rules = ruleInfoRules (idSpecialisation in_id)++simplRules :: SimplEnv -> Maybe Name -> [CoreRule] -> SimplM [CoreRule]+simplRules env mb_new_nm rules+ = mapM simpl_rule rules+ where+ simpl_rule rule@(BuiltinRule {})+ = return rule++ simpl_rule rule@(Rule { ru_bndrs = bndrs, ru_args = args+ , ru_fn = fn_name, ru_rhs = rhs })+ = do { (env', bndrs') <- simplBinders env bndrs+ ; let rhs_ty = substTy env' (exprType rhs)+ rule_cont = mkBoringStop rhs_ty+ rule_env = updMode updModeForRules env'+ ; args' <- mapM (simplExpr rule_env) args+ ; rhs' <- simplExprC rule_env rhs rule_cont+ ; return (rule { ru_bndrs = bndrs'+ , ru_fn = mb_new_nm `orElse` fn_name+ , ru_args = args'+ , ru_rhs = rhs' }) }
+ simplStg/RepType.hs view
@@ -0,0 +1,365 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}++module RepType+ (+ -- * Code generator views onto Types+ UnaryType, NvUnaryType, isNvUnaryType,+ unwrapType,++ -- * Predicates on types+ isVoidTy,++ -- * Type representation for the code generator+ typePrimRep, typePrimRep1,+ runtimeRepPrimRep, typePrimRepArgs,+ PrimRep(..), primRepToType,+ countFunRepArgs, countConRepArgs, tyConPrimRep, tyConPrimRep1,++ -- * Unboxed sum representation type+ ubxSumRepType, layoutUbxSum, typeSlotTy, SlotTy (..),+ slotPrimRep, primRepSlot+ ) where++#include "HsVersions.h"++import BasicTypes (Arity, RepArity)+import DataCon+import Outputable+import PrelNames+import Coercion+import TyCon+import TyCoRep+import Type+import Util+import TysPrim+import {-# SOURCE #-} TysWiredIn ( anyTypeOfKind )++import Data.List (foldl', sort)+import qualified Data.IntSet as IS++{- **********************************************************************+* *+ Representation types+* *+********************************************************************** -}++type NvUnaryType = Type+type UnaryType = Type+ -- Both are always a value type; i.e. its kind is TYPE rr+ -- for some rr; moreover the rr is never a variable.+ --+ -- NvUnaryType : never an unboxed tuple or sum, or void+ --+ -- UnaryType : never an unboxed tuple or sum;+ -- can be Void# or (# #)++isNvUnaryType :: Type -> Bool+isNvUnaryType ty+ | [_] <- typePrimRep ty+ = True+ | otherwise+ = False++-- INVARIANT: the result list is never empty.+typePrimRepArgs :: Type -> [PrimRep]+typePrimRepArgs ty+ | [] <- reps+ = [VoidRep]+ | otherwise+ = reps+ where+ reps = typePrimRep ty++-- | Gets rid of the stuff that prevents us from understanding the+-- runtime representation of a type. Including:+-- 1. Casts+-- 2. Newtypes+-- 3. Foralls+-- 4. Synonyms+-- But not type/data families, because we don't have the envs to hand.+unwrapType :: Type -> Type+unwrapType ty+ | Just (_, unwrapped)+ <- topNormaliseTypeX stepper mappend inner_ty+ = unwrapped+ | otherwise+ = inner_ty+ where+ inner_ty = go ty++ go t | Just t' <- coreView t = go t'+ go (ForAllTy _ t) = go t+ go (CastTy t _) = go t+ go t = t++ -- cf. Coercion.unwrapNewTypeStepper+ stepper rec_nts tc tys+ | Just (ty', _) <- instNewTyCon_maybe tc tys+ = case checkRecTc rec_nts tc of+ Just rec_nts' -> NS_Step rec_nts' (go ty') ()+ Nothing -> NS_Abort -- infinite newtypes+ | otherwise+ = NS_Done++countFunRepArgs :: Arity -> Type -> RepArity+countFunRepArgs 0 _+ = 0+countFunRepArgs n ty+ | FunTy arg res <- unwrapType ty+ = length (typePrimRepArgs arg) + countFunRepArgs (n - 1) res+ | otherwise+ = pprPanic "countFunRepArgs: arity greater than type can handle" (ppr (n, ty, typePrimRep ty))++countConRepArgs :: DataCon -> RepArity+countConRepArgs dc = go (dataConRepArity dc) (dataConRepType dc)+ where+ go :: Arity -> Type -> RepArity+ go 0 _+ = 0+ go n ty+ | FunTy arg res <- unwrapType ty+ = length (typePrimRep arg) + go (n - 1) res+ | otherwise+ = pprPanic "countConRepArgs: arity greater than type can handle" (ppr (n, ty, typePrimRep ty))++-- | True if the type has zero width.+isVoidTy :: Type -> Bool+isVoidTy = null . typePrimRep+++{- **********************************************************************+* *+ Unboxed sums+ See Note [Translating unboxed sums to unboxed tuples] in UnariseStg.hs+* *+********************************************************************** -}++type SortedSlotTys = [SlotTy]++-- | Given the arguments of a sum type constructor application,+-- return the unboxed sum rep type.+--+-- E.g.+--+-- (# Int# | Maybe Int | (# Int#, Float# #) #)+--+-- We call `ubxSumRepType [ [IntRep], [LiftedRep], [IntRep, FloatRep] ]`,+-- which returns [WordSlot, PtrSlot, WordSlot, FloatSlot]+--+-- INVARIANT: Result slots are sorted (via Ord SlotTy), except that at the head+-- of the list we have the slot for the tag.+ubxSumRepType :: [[PrimRep]] -> [SlotTy]+ubxSumRepType constrs0+ -- These first two cases never classify an actual unboxed sum, which always+ -- has at least two disjuncts. But it could happen if a user writes, e.g.,+ -- forall (a :: TYPE (SumRep [IntRep])). ...+ -- which could never be instantiated. We still don't want to panic.+ | length constrs0 < 2+ = [WordSlot]++ | otherwise+ = let+ combine_alts :: [SortedSlotTys] -- slots of constructors+ -> SortedSlotTys -- final slots+ combine_alts constrs = foldl' merge [] constrs++ merge :: SortedSlotTys -> SortedSlotTys -> SortedSlotTys+ merge existing_slots []+ = existing_slots+ merge [] needed_slots+ = needed_slots+ merge (es : ess) (s : ss)+ | Just s' <- s `fitsIn` es+ = -- found a slot, use it+ s' : merge ess ss+ | s < es+ = -- we need a new slot and this is the right place for it+ s : merge (es : ess) ss+ | otherwise+ = -- keep searching for a slot+ es : merge ess (s : ss)++ -- Nesting unboxed tuples and sums is OK, so we need to flatten first.+ rep :: [PrimRep] -> SortedSlotTys+ rep ty = sort (map primRepSlot ty)++ sumRep = WordSlot : combine_alts (map rep constrs0)+ -- WordSlot: for the tag of the sum+ in+ sumRep++layoutUbxSum :: SortedSlotTys -- Layout of sum. Does not include tag.+ -- We assume that they are in increasing order+ -> [SlotTy] -- Slot types of things we want to map to locations in the+ -- sum layout+ -> [Int] -- Where to map 'things' in the sum layout+layoutUbxSum sum_slots0 arg_slots0 =+ go arg_slots0 IS.empty+ where+ go :: [SlotTy] -> IS.IntSet -> [Int]+ go [] _+ = []+ go (arg : args) used+ = let slot_idx = findSlot arg 0 sum_slots0 used+ in slot_idx : go args (IS.insert slot_idx used)++ findSlot :: SlotTy -> Int -> SortedSlotTys -> IS.IntSet -> Int+ findSlot arg slot_idx (slot : slots) useds+ | not (IS.member slot_idx useds)+ , Just slot == arg `fitsIn` slot+ = slot_idx+ | otherwise+ = findSlot arg (slot_idx + 1) slots useds+ findSlot _ _ [] _+ = pprPanic "findSlot" (text "Can't find slot" $$ ppr sum_slots0 $$ ppr arg_slots0)++--------------------------------------------------------------------------------++-- We have 3 kinds of slots:+--+-- - Pointer slot: Only shared between actual pointers to Haskell heap (i.e.+-- boxed objects)+--+-- - Word slots: Shared between IntRep, WordRep, Int64Rep, Word64Rep, AddrRep.+--+-- - Float slots: Shared between floating point types.+--+-- - Void slots: Shared between void types. Not used in sums.+data SlotTy = PtrSlot | WordSlot | Word64Slot | FloatSlot | DoubleSlot+ deriving (Eq, Ord)+ -- Constructor order is important! If slot A could fit into slot B+ -- then slot A must occur first. E.g. FloatSlot before DoubleSlot+ --+ -- We are assuming that WordSlot is smaller than or equal to Word64Slot+ -- (would not be true on a 128-bit machine)++instance Outputable SlotTy where+ ppr PtrSlot = text "PtrSlot"+ ppr Word64Slot = text "Word64Slot"+ ppr WordSlot = text "WordSlot"+ ppr DoubleSlot = text "DoubleSlot"+ ppr FloatSlot = text "FloatSlot"++typeSlotTy :: UnaryType -> Maybe SlotTy+typeSlotTy ty+ | isVoidTy ty+ = Nothing+ | otherwise+ = Just (primRepSlot (typePrimRep1 ty))++primRepSlot :: PrimRep -> SlotTy+primRepSlot VoidRep = pprPanic "primRepSlot" (text "No slot for VoidRep")+primRepSlot LiftedRep = PtrSlot+primRepSlot UnliftedRep = PtrSlot+primRepSlot IntRep = WordSlot+primRepSlot WordRep = WordSlot+primRepSlot Int64Rep = Word64Slot+primRepSlot Word64Rep = Word64Slot+primRepSlot AddrRep = WordSlot+primRepSlot FloatRep = FloatSlot+primRepSlot DoubleRep = DoubleSlot+primRepSlot VecRep{} = pprPanic "primRepSlot" (text "No slot for VecRep")++slotPrimRep :: SlotTy -> PrimRep+slotPrimRep PtrSlot = LiftedRep -- choice between lifted & unlifted seems arbitrary+slotPrimRep Word64Slot = Word64Rep+slotPrimRep WordSlot = WordRep+slotPrimRep DoubleSlot = DoubleRep+slotPrimRep FloatSlot = FloatRep++-- | Returns the bigger type if one fits into the other. (commutative)+fitsIn :: SlotTy -> SlotTy -> Maybe SlotTy+fitsIn ty1 ty2+ | isWordSlot ty1 && isWordSlot ty2+ = Just (max ty1 ty2)+ | isFloatSlot ty1 && isFloatSlot ty2+ = Just (max ty1 ty2)+ | isPtrSlot ty1 && isPtrSlot ty2+ = Just PtrSlot+ | otherwise+ = Nothing+ where+ isPtrSlot PtrSlot = True+ isPtrSlot _ = False++ isWordSlot Word64Slot = True+ isWordSlot WordSlot = True+ isWordSlot _ = False++ isFloatSlot DoubleSlot = True+ isFloatSlot FloatSlot = True+ isFloatSlot _ = False+++{- **********************************************************************+* *+ PrimRep+* *+********************************************************************** -}++-- | Discovers the primitive representation of a 'Type'. Returns+-- a list of 'PrimRep': it's a list because of the possibility of+-- no runtime representation (void) or multiple (unboxed tuple/sum)+typePrimRep :: HasDebugCallStack => Type -> [PrimRep]+typePrimRep ty = kindPrimRep (text "typePrimRep" <+>+ parens (ppr ty <+> dcolon <+> ppr (typeKind ty)))+ (typeKind ty)++-- | Like 'typePrimRep', but assumes that there is precisely one 'PrimRep' output;+-- an empty list of PrimReps becomes a VoidRep+typePrimRep1 :: HasDebugCallStack => UnaryType -> PrimRep+typePrimRep1 ty = case typePrimRep ty of+ [] -> VoidRep+ [rep] -> rep+ _ -> pprPanic "typePrimRep1" (ppr ty $$ ppr (typePrimRep ty))++-- | Find the runtime representation of a 'TyCon'. Defined here to+-- avoid module loops. Returns a list of the register shapes necessary.+tyConPrimRep :: HasDebugCallStack => TyCon -> [PrimRep]+tyConPrimRep tc+ = kindPrimRep (text "kindRep tc" <+> ppr tc $$ ppr res_kind)+ res_kind+ where+ res_kind = tyConResKind tc++-- | Like 'tyConPrimRep', but assumed that there is precisely zero or+-- one 'PrimRep' output+tyConPrimRep1 :: HasDebugCallStack => TyCon -> PrimRep+tyConPrimRep1 tc = case tyConPrimRep tc of+ [] -> VoidRep+ [rep] -> rep+ _ -> pprPanic "tyConPrimRep1" (ppr tc $$ ppr (tyConPrimRep tc))++-- | Take a kind (of shape @TYPE rr@) and produce the 'PrimRep's+-- of values of types of this kind.+kindPrimRep :: HasDebugCallStack => SDoc -> Kind -> [PrimRep]+kindPrimRep doc ki+ | Just ki' <- coreView ki+ = kindPrimRep doc ki'+kindPrimRep doc (TyConApp typ [runtime_rep])+ = ASSERT( typ `hasKey` tYPETyConKey )+ runtimeRepPrimRep doc runtime_rep+kindPrimRep doc ki+ = pprPanic "kindPrimRep" (ppr ki $$ doc)++ -- TODO (RAE): Remove:+ -- WARN( True, text "kindPrimRep defaulting to LiftedRep on" <+> ppr ki $$ doc )+ -- [LiftedRep] -- this can happen legitimately for, e.g., Any++-- | Take a type of kind RuntimeRep and extract the list of 'PrimRep' that+-- it encodes.+runtimeRepPrimRep :: HasDebugCallStack => SDoc -> Type -> [PrimRep]+runtimeRepPrimRep doc rr_ty+ | Just rr_ty' <- coreView rr_ty+ = runtimeRepPrimRep doc rr_ty'+ | TyConApp rr_dc args <- rr_ty+ , RuntimeRep fun <- tyConRuntimeRepInfo rr_dc+ = fun args+ | otherwise+ = pprPanic "runtimeRepPrimRep" (doc $$ ppr rr_ty)++-- | Convert a PrimRep back to a Type. Used only in the unariser to give types+-- to fresh Ids. Really, only the type's representation matters.+primRepToType :: PrimRep -> Type+primRepToType = anyTypeOfKind . tYPE . primRepToRuntimeRep
+ simplStg/SimplStg.hs view
@@ -0,0 +1,117 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[SimplStg]{Driver for simplifying @STG@ programs}+-}++{-# LANGUAGE CPP #-}++module SimplStg ( stg2stg ) where++#include "HsVersions.h"++import StgSyn++import CostCentre ( CollectedCCs )+import SCCfinal ( stgMassageForProfiling )+import StgLint ( lintStgTopBindings )+import StgStats ( showStgStats )+import UnariseStg ( unarise )+import StgCse ( stgCse )++import DynFlags+import Module ( Module )+import ErrUtils+import SrcLoc+import UniqSupply ( mkSplitUniqSupply, splitUniqSupply )+import Outputable+import Control.Monad++stg2stg :: DynFlags -- includes spec of what stg-to-stg passes to do+ -> Module -- module name (profiling only)+ -> [StgTopBinding] -- input...+ -> IO ( [StgTopBinding] -- output program...+ , CollectedCCs) -- cost centre information (declared and used)++stg2stg dflags module_name binds+ = do { showPass dflags "Stg2Stg"+ ; us <- mkSplitUniqSupply 'g'++ ; when (dopt Opt_D_verbose_stg2stg dflags)+ (putLogMsg dflags NoReason SevDump noSrcSpan+ (defaultDumpStyle dflags) (text "VERBOSE STG-TO-STG:"))++ ; (binds', us', ccs) <- end_pass us "Stg2Stg" ([],[],[]) binds++ -- Do the main business!+ ; let (us0, us1) = splitUniqSupply us'+ ; (processed_binds, _, cost_centres)+ <- foldM do_stg_pass (binds', us0, ccs) (getStgToDo dflags)++ ; dumpIfSet_dyn dflags Opt_D_dump_stg "Pre unarise:"+ (pprStgTopBindings processed_binds)++ ; let un_binds = unarise us1 processed_binds++ ; dumpIfSet_dyn dflags Opt_D_dump_stg "STG syntax:"+ (pprStgTopBindings un_binds)++ ; return (un_binds, cost_centres)+ }++ where+ stg_linter = if gopt Opt_DoStgLinting dflags+ then lintStgTopBindings+ else ( \ _whodunnit binds -> binds )++ -------------------------------------------+ do_stg_pass (binds, us, ccs) to_do+ = case to_do of+ D_stg_stats ->+ trace (showStgStats binds)+ end_pass us "StgStats" ccs binds++ StgDoMassageForProfiling ->+ {-# SCC "ProfMassage" #-}+ let+ (us1, us2) = splitUniqSupply us+ (collected_CCs, binds3)+ = stgMassageForProfiling dflags module_name us1 binds+ in+ end_pass us2 "ProfMassage" collected_CCs binds3++ StgCSE ->+ {-# SCC "StgCse" #-}+ let+ binds' = stgCse binds+ in+ end_pass us "StgCse" ccs binds'++ end_pass us2 what ccs binds2+ = do -- report verbosely, if required+ dumpIfSet_dyn dflags Opt_D_verbose_stg2stg what+ (vcat (map ppr binds2))+ let linted_binds = stg_linter what binds2+ return (linted_binds, us2, ccs)+ -- return: processed binds+ -- UniqueSupply for the next guy to use+ -- cost-centres to be declared/registered (specialised)+ -- add to description of what's happened (reverse order)++-- -----------------------------------------------------------------------------+-- StgToDo: abstraction of stg-to-stg passes to run.++-- | Optional Stg-to-Stg passes.+data StgToDo+ = StgCSE+ | StgDoMassageForProfiling -- should be (next to) last+ | D_stg_stats++-- | Which optional Stg-to-Stg passes to run. Depends on flags, ways etc.+getStgToDo :: DynFlags -> [StgToDo]+getStgToDo dflags+ = [ StgCSE | gopt Opt_StgCSE dflags] +++ [ StgDoMassageForProfiling | WayProf `elem` ways dflags] +++ [ D_stg_stats | stg_stats ]+ where+ stg_stats = gopt Opt_StgStats dflags
+ simplStg/StgCse.hs view
@@ -0,0 +1,430 @@+{-# LANGUAGE TypeFamilies #-}++{-|+Note [CSE for Stg]+~~~~~~~~~~~~~~~~~~+This module implements a simple common subexpression elimination pass for STG.+This is useful because there are expressions that we want to common up (because+they are operational equivalent), but that we cannot common up in Core, because+their types differ.+This was original reported as #9291.++There are two types of common code occurrences that we aim for, see+note [Case 1: CSEing allocated closures] and+note [Case 2: CSEing case binders] below.+++Note [Case 1: CSEing allocated closures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The fist kind of CSE opportunity we aim for is generated by this Haskell code:++ bar :: a -> (Either Int a, Either Bool a)+ bar x = (Right x, Right x)++which produces this Core:++ bar :: forall a. a -> (Either Int a, Either Bool a)+ bar @a x = (Right @Int @a x, Right @Bool @a x)++where the two components of the tuple are differnt terms, and cannot be+commoned up (easily). On the STG level we have++ bar [x] = let c1 = Right [x]+ c2 = Right [x]+ in (c1,c2)++and now it is obvious that we can write++ bar [x] = let c1 = Right [x]+ in (c1,c1)++instead.+++Note [Case 2: CSEing case binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The second kind of CSE opportunity we aim for is more interesting, and+came up in #9291 and #5344: The Haskell code++ foo :: Either Int a -> Either Bool a+ foo (Right x) = Right x+ foo _ = Left False++produces this Core++ foo :: forall a. Either Int a -> Either Bool a+ foo @a e = case e of b { Left n -> …+ , Right x -> Right @Bool @a x }++where we cannot CSE `Right @Bool @a x` with the case binder `b` as they have+different types. But in STG we have++ foo [e] = case e of b { Left [n] -> …+ , Right [x] -> Right [x] }++and nothing stops us from transforming that to++ foo [e] = case e of b { Left [n] -> …+ , Right [x] -> b}++-}+module StgCse (stgCse) where++import DataCon+import Id+import StgSyn+import Outputable+import VarEnv+import CoreSyn (AltCon(..))+import Data.List (mapAccumL)+import Data.Maybe (fromMaybe)+import TrieMap+import NameEnv+import Control.Monad( (>=>) )++--------------+-- The Trie --+--------------++-- A lookup trie for data constructor applications, i.e.+-- keys of type `(DataCon, [StgArg])`, following the patterns in TrieMap.++data StgArgMap a = SAM+ { sam_var :: DVarEnv a+ , sam_lit :: LiteralMap a+ }++instance TrieMap StgArgMap where+ type Key StgArgMap = StgArg+ emptyTM = SAM { sam_var = emptyTM+ , sam_lit = emptyTM }+ lookupTM (StgVarArg var) = sam_var >.> lkDFreeVar var+ lookupTM (StgLitArg lit) = sam_lit >.> lookupTM lit+ alterTM (StgVarArg var) f m = m { sam_var = sam_var m |> xtDFreeVar var f }+ alterTM (StgLitArg lit) f m = m { sam_lit = sam_lit m |> alterTM lit f }+ foldTM k m = foldTM k (sam_var m) . foldTM k (sam_lit m)+ mapTM f (SAM {sam_var = varm, sam_lit = litm}) =+ SAM { sam_var = mapTM f varm, sam_lit = mapTM f litm }++newtype ConAppMap a = CAM { un_cam :: DNameEnv (ListMap StgArgMap a) }++instance TrieMap ConAppMap where+ type Key ConAppMap = (DataCon, [StgArg])+ emptyTM = CAM emptyTM+ lookupTM (dataCon, args) = un_cam >.> lkDNamed dataCon >=> lookupTM args+ alterTM (dataCon, args) f m =+ m { un_cam = un_cam m |> xtDNamed dataCon |>> alterTM args f }+ foldTM k = un_cam >.> foldTM (foldTM k)+ mapTM f = un_cam >.> mapTM (mapTM f) >.> CAM++-----------------+-- The CSE Env --+-----------------++-- | The CSE environment. See note [CseEnv Example]+data CseEnv = CseEnv+ { ce_conAppMap :: ConAppMap OutId+ -- ^ The main component of the environment is the trie that maps+ -- data constructor applications (with their `OutId` arguments)+ -- to an in-scope name that can be used instead.+ -- This name is always either a let-bound variable or a case binder.+ , ce_subst :: IdEnv OutId+ -- ^ This substitution is applied to the code as we traverse it.+ -- Entries have one of two reasons:+ --+ -- * The input might have shadowing (see Note [Shadowing]), so we have+ -- to rename some binders as we traverse the tree.+ -- * If we remove `let x = Con z` because `let y = Con z` is in scope,+ -- we note this here as x ↦ y.+ , ce_bndrMap :: IdEnv OutId+ -- If we come across a case expression case x as b of … with a trivial+ -- binder, we add b ↦ x to this.+ -- This map is *only* used when looking something up in the ce_conAppMap.+ -- See Note [Trivial case scrutinee]+ , ce_in_scope :: InScopeSet+ -- ^ The third component is an in-scope set, to rename away any+ -- shadowing binders+ }++{-|+Note [CseEnv Example]+~~~~~~~~~~~~~~~~~~~~~+The following tables shows how the CseEnvironment changes as code is traversed,+as well as the changes to that code.++ InExpr OutExpr+ conAppMap subst in_scope+ ───────────────────────────────────────────────────────────+ -- empty {} {}+ case … as a of {Con x y -> case … as a of {Con x y ->+ -- Con x y ↦ a {} {a,x,y}+ let b = Con x y (removed)+ -- Con x y ↦ a b↦a {a,x,y,b}+ let c = Bar a let c = Bar a+ -- Con x y ↦ a, Bar a ↦ c b↦a {a,x,y,b,c}+ let c = some expression let c' = some expression+ -- Con x y ↦ a, Bar a ↦ c b↦a, c↦c', {a,x,y,b,c,c'}+ let d = Bar b (removed)+ -- Con x y ↦ a, Bar a ↦ c b↦a, c↦c', d↦c {a,x,y,b,c,c',d}+ (a, b, c d) (a, a, c' c)+-}++initEnv :: InScopeSet -> CseEnv+initEnv in_scope = CseEnv+ { ce_conAppMap = emptyTM+ , ce_subst = emptyVarEnv+ , ce_bndrMap = emptyVarEnv+ , ce_in_scope = in_scope+ }++envLookup :: DataCon -> [OutStgArg] -> CseEnv -> Maybe OutId+envLookup dataCon args env = lookupTM (dataCon, args') (ce_conAppMap env)+ where args' = map go args -- See Note [Trivial case scrutinee]+ go (StgVarArg v ) = StgVarArg (fromMaybe v $ lookupVarEnv (ce_bndrMap env) v)+ go (StgLitArg lit) = StgLitArg lit++addDataCon :: OutId -> DataCon -> [OutStgArg] -> CseEnv -> CseEnv+-- do not bother with nullary data constructors, they are static anyways+addDataCon _ _ [] env = env+addDataCon bndr dataCon args env = env { ce_conAppMap = new_env }+ where+ new_env = insertTM (dataCon, args) bndr (ce_conAppMap env)++forgetCse :: CseEnv -> CseEnv+forgetCse env = env { ce_conAppMap = emptyTM }+ -- See note [Free variables of an StgClosure]++addSubst :: OutId -> OutId -> CseEnv -> CseEnv+addSubst from to env+ = env { ce_subst = extendVarEnv (ce_subst env) from to }++addTrivCaseBndr :: OutId -> OutId -> CseEnv -> CseEnv+addTrivCaseBndr from to env+ = env { ce_bndrMap = extendVarEnv (ce_bndrMap env) from to }++substArgs :: CseEnv -> [InStgArg] -> [OutStgArg]+substArgs env = map (substArg env)++substArg :: CseEnv -> InStgArg -> OutStgArg+substArg env (StgVarArg from) = StgVarArg (substVar env from)+substArg _ (StgLitArg lit) = StgLitArg lit++substVars :: CseEnv -> [InId] -> [OutId]+substVars env = map (substVar env)++substVar :: CseEnv -> InId -> OutId+substVar env id = fromMaybe id $ lookupVarEnv (ce_subst env) id++-- Functions to enter binders++-- This is much simpler than the requivalent code in CoreSubst:+-- * We do not substitute type variables, and+-- * There is nothing relevant in IdInfo at this stage+-- that needs substitutions.+-- Therefore, no special treatment for a recursive group is required.++substBndr :: CseEnv -> InId -> (CseEnv, OutId)+substBndr env old_id+ = (new_env, new_id)+ where+ new_id = uniqAway (ce_in_scope env) old_id+ no_change = new_id == old_id+ env' = env { ce_in_scope = ce_in_scope env `extendInScopeSet` new_id }+ new_env | no_change = env' { ce_subst = extendVarEnv (ce_subst env) old_id new_id }+ | otherwise = env'++substBndrs :: CseEnv -> [InVar] -> (CseEnv, [OutVar])+substBndrs env bndrs = mapAccumL substBndr env bndrs++substPairs :: CseEnv -> [(InVar, a)] -> (CseEnv, [(OutVar, a)])+substPairs env bndrs = mapAccumL go env bndrs+ where go env (id, x) = let (env', id') = substBndr env id+ in (env', (id', x))++-- Main entry point++stgCse :: [InStgTopBinding] -> [OutStgTopBinding]+stgCse binds = snd $ mapAccumL stgCseTopLvl emptyInScopeSet binds++-- Top level bindings.+--+-- We do not CSE these, as top-level closures are allocated statically anyways.+-- Also, they might be exported.+-- But we still have to collect the set of in-scope variables, otherwise+-- uniqAway might shadow a top-level closure.++stgCseTopLvl :: InScopeSet -> InStgTopBinding -> (InScopeSet, OutStgTopBinding)+stgCseTopLvl in_scope t@(StgTopStringLit _ _) = (in_scope, t)+stgCseTopLvl in_scope (StgTopLifted (StgNonRec bndr rhs))+ = (in_scope'+ , StgTopLifted (StgNonRec bndr (stgCseTopLvlRhs in_scope rhs)))+ where in_scope' = in_scope `extendInScopeSet` bndr++stgCseTopLvl in_scope (StgTopLifted (StgRec eqs))+ = ( in_scope'+ , StgTopLifted (StgRec [ (bndr, stgCseTopLvlRhs in_scope' rhs) | (bndr, rhs) <- eqs ]))+ where in_scope' = in_scope `extendInScopeSetList` [ bndr | (bndr, _) <- eqs ]++stgCseTopLvlRhs :: InScopeSet -> InStgRhs -> OutStgRhs+stgCseTopLvlRhs in_scope (StgRhsClosure ccs info occs upd args body)+ = let body' = stgCseExpr (initEnv in_scope) body+ in StgRhsClosure ccs info occs upd args body'+stgCseTopLvlRhs _ (StgRhsCon ccs dataCon args)+ = StgRhsCon ccs dataCon args++------------------------------+-- The actual AST traversal --+------------------------------++-- Trivial cases+stgCseExpr :: CseEnv -> InStgExpr -> OutStgExpr+stgCseExpr env (StgApp fun args)+ = StgApp fun' args'+ where fun' = substVar env fun+ args' = substArgs env args+stgCseExpr _ (StgLit lit)+ = StgLit lit+stgCseExpr env (StgOpApp op args tys)+ = StgOpApp op args' tys+ where args' = substArgs env args+stgCseExpr _ (StgLam _ _)+ = pprPanic "stgCseExp" (text "StgLam")+stgCseExpr env (StgTick tick body)+ = let body' = stgCseExpr env body+ in StgTick tick body'+stgCseExpr env (StgCase scrut bndr ty alts)+ = StgCase scrut' bndr' ty alts'+ where+ scrut' = stgCseExpr env scrut+ (env1, bndr') = substBndr env bndr+ env2 | StgApp trivial_scrut [] <- scrut' = addTrivCaseBndr bndr trivial_scrut env1+ -- See Note [Trivial case scrutinee]+ | otherwise = env1+ alts' = map (stgCseAlt env2 bndr') alts+++-- A constructor application.+-- To be removed by a variable use when found in the CSE environment+stgCseExpr env (StgConApp dataCon args tys)+ | Just bndr' <- envLookup dataCon args' env+ = StgApp bndr' []+ | otherwise+ = StgConApp dataCon args' tys+ where args' = substArgs env args++-- Let bindings+-- The binding might be removed due to CSE (we do not want trivial bindings on+-- the STG level), so use the smart constructor `mkStgLet` to remove the binding+-- if empty.+stgCseExpr env (StgLet binds body)+ = let (binds', env') = stgCseBind env binds+ body' = stgCseExpr env' body+ in mkStgLet StgLet binds' body'+stgCseExpr env (StgLetNoEscape binds body)+ = let (binds', env') = stgCseBind env binds+ body' = stgCseExpr env' body+ in mkStgLet StgLetNoEscape binds' body'++-- Case alternatives+-- Extend the CSE environment+stgCseAlt :: CseEnv -> OutId -> InStgAlt -> OutStgAlt+stgCseAlt env case_bndr (DataAlt dataCon, args, rhs)+ = let (env1, args') = substBndrs env args+ env2 = addDataCon case_bndr dataCon (map StgVarArg args') env1+ -- see note [Case 2: CSEing case binders]+ rhs' = stgCseExpr env2 rhs+ in (DataAlt dataCon, args', rhs')+stgCseAlt env _ (altCon, args, rhs)+ = let (env1, args') = substBndrs env args+ rhs' = stgCseExpr env1 rhs+ in (altCon, args', rhs')++-- Bindings+stgCseBind :: CseEnv -> InStgBinding -> (Maybe OutStgBinding, CseEnv)+stgCseBind env (StgNonRec b e)+ = let (env1, b') = substBndr env b+ in case stgCseRhs env1 b' e of+ (Nothing, env2) -> (Nothing, env2)+ (Just (b2,e'), env2) -> (Just (StgNonRec b2 e'), env2)+stgCseBind env (StgRec pairs)+ = let (env1, pairs1) = substPairs env pairs+ in case stgCsePairs env1 pairs1 of+ ([], env2) -> (Nothing, env2)+ (pairs2, env2) -> (Just (StgRec pairs2), env2)++stgCsePairs :: CseEnv -> [(OutId, InStgRhs)] -> ([(OutId, OutStgRhs)], CseEnv)+stgCsePairs env [] = ([], env)+stgCsePairs env0 ((b,e):pairs)+ = let (pairMB, env1) = stgCseRhs env0 b e+ (pairs', env2) = stgCsePairs env1 pairs+ in (pairMB `mbCons` pairs', env2)+ where+ mbCons = maybe id (:)++-- The RHS of a binding.+-- If it is an constructor application, either short-cut it or extend the environment+stgCseRhs :: CseEnv -> OutId -> InStgRhs -> (Maybe (OutId, OutStgRhs), CseEnv)+stgCseRhs env bndr (StgRhsCon ccs dataCon args)+ | Just other_bndr <- envLookup dataCon args' env+ = let env' = addSubst bndr other_bndr env+ in (Nothing, env')+ | otherwise+ = let env' = addDataCon bndr dataCon args' env+ -- see note [Case 1: CSEing allocated closures]+ pair = (bndr, StgRhsCon ccs dataCon args')+ in (Just pair, env')+ where args' = substArgs env args+stgCseRhs env bndr (StgRhsClosure ccs info occs upd args body)+ = let (env1, args') = substBndrs env args+ env2 = forgetCse env1 -- See note [Free variables of an StgClosure]+ body' = stgCseExpr env2 body+ in (Just (substVar env bndr, StgRhsClosure ccs info occs' upd args' body'), env)+ where occs' = substVars env occs++-- Utilities++-- | This function short-cuts let-bindings that are now obsolete+mkStgLet :: (a -> b -> b) -> Maybe a -> b -> b+mkStgLet _ Nothing body = body+mkStgLet stgLet (Just binds) body = stgLet binds body+++{-+Note [Trivial case scrutinee]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We wnat to be able to handle nested reconstruction of constructors as in++ nested :: Either Int (Either Int a) -> Either Bool (Either Bool a)+ nested (Right (Right v)) = Right (Right v)+ nested _ = Left True++So if we come across++ case x of r1+ Right a -> case a of r2+ Right b -> let v = Right b+ in Right v++we first replace v with r2. Next we want to replace Right r2 with r1. But the+ce_conAppMap contains Right a!++Therefore, we add r1 ↦ x to ce_bndrMap when analysing the outer case, and use+this subsitution before looking Right r2 up in ce_conAppMap, and everything+works out.++Note [Free variables of an StgClosure]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+StgClosures (function and thunks) have an explicit list of free variables:++foo [x] =+ let not_a_free_var = Left [x]+ let a_free_var = Right [x]+ let closure = \[x a_free_var] -> \[y] -> bar y (Left [x]) a_free_var+ in closure++If we were to CSE `Left [x]` in the body of `closure` with `not_a_free_var`,+then the list of free variables would be wrong, so for now, we do not CSE+across such a closure, simply because I (Joachim) was not sure about possible+knock-on effects. If deemed safe and worth the slight code complication of+re-calculating this list during or after this pass, this can surely be done.+-}
+ simplStg/StgStats.hs view
@@ -0,0 +1,175 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[StgStats]{Gathers statistical information about programs}+++The program gather statistics about+\begin{enumerate}+\item number of boxed cases+\item number of unboxed cases+\item number of let-no-escapes+\item number of non-updatable lets+\item number of updatable lets+\item number of applications+\item number of primitive applications+\item number of closures (does not include lets bound to constructors)+\item number of free variables in closures+%\item number of top-level functions+%\item number of top-level CAFs+\item number of constructors+\end{enumerate}+-}++{-# LANGUAGE CPP #-}++module StgStats ( showStgStats ) where++#include "HsVersions.h"++import StgSyn++import Id (Id)+import Panic++import Data.Map (Map)+import qualified Data.Map as Map++data CounterType+ = Literals+ | Applications+ | ConstructorApps+ | PrimitiveApps+ | LetNoEscapes+ | StgCases+ | FreeVariables+ | ConstructorBinds Bool{-True<=>top-level-}+ | ReEntrantBinds Bool{-ditto-}+ | SingleEntryBinds Bool{-ditto-}+ | UpdatableBinds Bool{-ditto-}+ deriving (Eq, Ord)++type Count = Int+type StatEnv = Map CounterType Count++emptySE :: StatEnv+emptySE = Map.empty++combineSE :: StatEnv -> StatEnv -> StatEnv+combineSE = Map.unionWith (+)++combineSEs :: [StatEnv] -> StatEnv+combineSEs = foldr combineSE emptySE++countOne :: CounterType -> StatEnv+countOne c = Map.singleton c 1++countN :: CounterType -> Int -> StatEnv+countN = Map.singleton++{-+************************************************************************+* *+\subsection{Top-level list of bindings (a ``program'')}+* *+************************************************************************+-}++showStgStats :: [StgTopBinding] -> String++showStgStats prog+ = "STG Statistics:\n\n"+ ++ concat (map showc (Map.toList (gatherStgStats prog)))+ where+ showc (x,n) = (showString (s x) . shows n) "\n"++ s Literals = "Literals "+ s Applications = "Applications "+ s ConstructorApps = "ConstructorApps "+ s PrimitiveApps = "PrimitiveApps "+ s LetNoEscapes = "LetNoEscapes "+ s StgCases = "StgCases "+ s FreeVariables = "FreeVariables "+ s (ConstructorBinds True) = "ConstructorBinds_Top "+ s (ReEntrantBinds True) = "ReEntrantBinds_Top "+ s (SingleEntryBinds True) = "SingleEntryBinds_Top "+ s (UpdatableBinds True) = "UpdatableBinds_Top "+ s (ConstructorBinds _) = "ConstructorBinds_Nested "+ s (ReEntrantBinds _) = "ReEntrantBindsBinds_Nested "+ s (SingleEntryBinds _) = "SingleEntryBinds_Nested "+ s (UpdatableBinds _) = "UpdatableBinds_Nested "++gatherStgStats :: [StgTopBinding] -> StatEnv+gatherStgStats binds = combineSEs (map statTopBinding binds)++{-+************************************************************************+* *+\subsection{Bindings}+* *+************************************************************************+-}++statTopBinding :: StgTopBinding -> StatEnv+statTopBinding (StgTopStringLit _ _) = countOne Literals+statTopBinding (StgTopLifted bind) = statBinding True bind++statBinding :: Bool -- True <=> top-level; False <=> nested+ -> StgBinding+ -> StatEnv++statBinding top (StgNonRec b rhs)+ = statRhs top (b, rhs)++statBinding top (StgRec pairs)+ = combineSEs (map (statRhs top) pairs)++statRhs :: Bool -> (Id, StgRhs) -> StatEnv++statRhs top (_, StgRhsCon _ _ _)+ = countOne (ConstructorBinds top)++statRhs top (_, StgRhsClosure _ _ fv u _ body)+ = statExpr body `combineSE`+ countN FreeVariables (length fv) `combineSE`+ countOne (+ case u of+ ReEntrant -> ReEntrantBinds top+ Updatable -> UpdatableBinds top+ SingleEntry -> SingleEntryBinds top+ )++{-+************************************************************************+* *+\subsection{Expressions}+* *+************************************************************************+-}++statExpr :: StgExpr -> StatEnv++statExpr (StgApp _ _) = countOne Applications+statExpr (StgLit _) = countOne Literals+statExpr (StgConApp _ _ _)= countOne ConstructorApps+statExpr (StgOpApp _ _ _) = countOne PrimitiveApps+statExpr (StgTick _ e) = statExpr e++statExpr (StgLetNoEscape binds body)+ = statBinding False{-not top-level-} binds `combineSE`+ statExpr body `combineSE`+ countOne LetNoEscapes++statExpr (StgLet binds body)+ = statBinding False{-not top-level-} binds `combineSE`+ statExpr body++statExpr (StgCase expr _ _ alts)+ = statExpr expr `combineSE`+ stat_alts alts `combineSE`+ countOne StgCases+ where+ stat_alts alts+ = combineSEs (map statExpr [ e | (_,_,e) <- alts ])++statExpr (StgLam {}) = panic "statExpr StgLam"
+ simplStg/UnariseStg.hs view
@@ -0,0 +1,761 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-2012++Note [Unarisation]+~~~~~~~~~~~~~~~~~~+The idea of this pass is to translate away *all* unboxed-tuple and unboxed-sum+binders. So for example:++ f (x :: (# Int, Bool #)) = f x + f (# 1, True #)++ ==>++ f (x1 :: Int) (x2 :: Bool) = f x1 x2 + f 1 True++It is important that we do this at the STG level and NOT at the Core level+because it would be very hard to make this pass Core-type-preserving. In this+example the type of 'f' changes, for example.++STG fed to the code generators *must* be unarised because the code generators do+not support unboxed tuple and unboxed sum binders natively.++In more detail: (see next note for unboxed sums)++Suppose that a variable x : (# t1, t2 #).++ * At the binding site for x, make up fresh vars x1:t1, x2:t2++ * Extend the UnariseEnv x :-> MultiVal [x1,x2]++ * Replace the binding with a curried binding for x1,x2++ Lambda: \x.e ==> \x1 x2. e+ Case alt: MkT a b x c d -> e ==> MkT a b x1 x2 c d -> e++ * Replace argument occurrences with a sequence of args via a lookup in+ UnariseEnv++ f a b x c d ==> f a b x1 x2 c d++ * Replace tail-call occurrences with an unboxed tuple via a lookup in+ UnariseEnv++ x ==> (# x1, x2 #)++ So, for example++ f x = x ==> f x1 x2 = (# x1, x2 #)++ * We /always/ eliminate a case expression when++ - It scrutinises an unboxed tuple or unboxed sum++ - The scrutinee is a variable (or when it is an explicit tuple, but the+ simplifier eliminates those)++ The case alternative (there can be only one) can be one of these two+ things:++ - An unboxed tuple pattern. e.g.++ case v of x { (# x1, x2, x3 #) -> ... }++ Scrutinee has to be in form `(# t1, t2, t3 #)` so we just extend the+ environment with++ x :-> MultiVal [t1,t2,t3]+ x1 :-> UnaryVal t1, x2 :-> UnaryVal t2, x3 :-> UnaryVal t3++ - A DEFAULT alternative. Just the same, without the bindings for x1,x2,x3++By the end of this pass, we only have unboxed tuples in return positions.+Unboxed sums are completely eliminated, see next note.++Note [Translating unboxed sums to unboxed tuples]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Unarise also eliminates unboxed sum binders, and translates unboxed sums in+return positions to unboxed tuples. We want to overlap fields of a sum when+translating it to a tuple to have efficient memory layout. When translating a+sum pattern to a tuple pattern, we need to translate it so that binders of sum+alternatives will be mapped to right arguments after the term translation. So+translation of sum DataCon applications to tuple DataCon applications and+translation of sum patterns to tuple patterns need to be in sync.++These translations work like this. Suppose we have++ (# x1 | | ... #) :: (# t1 | t2 | ... #)++remember that t1, t2 ... can be sums and tuples too. So we first generate+layouts of those. Then we "merge" layouts of each alternative, which gives us a+sum layout with best overlapping possible.++Layout of a flat type 'ty1' is just [ty1].+Layout of a tuple is just concatenation of layouts of its fields.++For layout of a sum type,++ - We first get layouts of all alternatives.+ - We sort these layouts based on their "slot types".+ - We merge all the alternatives.++For example, say we have (# (# Int#, Char #) | (# Int#, Int# #) | Int# #)++ - Layouts of alternatives: [ [Word, Ptr], [Word, Word], [Word] ]+ - Sorted: [ [Ptr, Word], [Word, Word], [Word] ]+ - Merge all alternatives together: [ Ptr, Word, Word ]++We add a slot for the tag to the first position. So our tuple type is++ (# Tag#, Any, Word#, Word# #)+ (we use Any for pointer slots)++Now, any term of this sum type needs to generate a tuple of this type instead.+The translation works by simply putting arguments to first slots that they fit+in. Suppose we had++ (# (# 42#, 'c' #) | | #)++42# fits in Word#, 'c' fits in Any, so we generate this application:++ (# 1#, 'c', 42#, rubbish #)++Another example using the same type: (# | (# 2#, 3# #) | #). 2# fits in Word#,+3# fits in Word #, so we get:++ (# 2#, rubbish, 2#, 3# #).++Note [Types in StgConApp]+~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have this unboxed sum term:++ (# 123 | #)++What will be the unboxed tuple representation? We can't tell without knowing the+type of this term. For example, these are all valid tuples for this:++ (# 1#, 123 #) -- when type is (# Int | String #)+ (# 1#, 123, rubbish #) -- when type is (# Int | Float# #)+ (# 1#, 123, rubbish, rubbish #)+ -- when type is (# Int | (# Int, Int, Int #) #)++So we pass type arguments of the DataCon's TyCon in StgConApp to decide what+layout to use. Note that unlifted values can't be let-bound, so we don't need+types in StgRhsCon.++Note [UnariseEnv can map to literals]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To avoid redundant case expressions when unarising unboxed sums, UnariseEnv+needs to map variables to literals too. Suppose we have this Core:++ f (# x | #)++ ==> (CorePrep)++ case (# x | #) of y {+ _ -> f y+ }++ ==> (MultiVal)++ case (# 1#, x #) of [x1, x2] {+ _ -> f x1 x2+ }++To eliminate this case expression we need to map x1 to 1# in UnariseEnv:++ x1 :-> UnaryVal 1#, x2 :-> UnaryVal x++so that `f x1 x2` becomes `f 1# x`.++Note [Unarisation and arity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because of unarisation, the arity that will be recorded in the generated info+table for an Id may be larger than the idArity. Instead we record what we call+the RepArity, which is the Arity taking into account any expanded arguments, and+corresponds to the number of (possibly-void) *registers* arguments will arrive+in.++Note [Post-unarisation invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+STG programs after unarisation have these invariants:++ * No unboxed sums at all.++ * No unboxed tuple binders. Tuples only appear in return position.++ * DataCon applications (StgRhsCon and StgConApp) don't have void arguments.+ This means that it's safe to wrap `StgArg`s of DataCon applications with+ `StgCmmEnv.NonVoid`, for example.++ * Alt binders (binders in patterns) are always non-void.+-}++{-# LANGUAGE CPP, TupleSections #-}++module UnariseStg (unarise) where++#include "HsVersions.h"++import BasicTypes+import CoreSyn+import DataCon+import FastString (FastString, mkFastString)+import Id+import Literal (Literal (..))+import MkCore (aBSENT_ERROR_ID)+import MkId (voidPrimId, voidArgId)+import MonadUtils (mapAccumLM)+import Outputable+import RepType+import StgSyn+import Type+import TysPrim (intPrimTy)+import TysWiredIn+import UniqSupply+import Util+import VarEnv++import Data.Bifunctor (second)+import Data.Maybe (mapMaybe)+import qualified Data.IntMap as IM++--------------------------------------------------------------------------------++-- | A mapping from binders to the Ids they were expanded/renamed to.+--+-- x :-> MultiVal [a,b,c] in rho+--+-- iff x's typePrimRep is not a singleton, or equivalently+-- x's type is an unboxed tuple, sum or void.+--+-- x :-> UnaryVal x'+--+-- iff x's RepType is UnaryRep or equivalently+-- x's type is not unboxed tuple, sum or void.+--+-- So+-- x :-> MultiVal [a] in rho+-- means x is represented by singleton tuple.+--+-- x :-> MultiVal [] in rho+-- means x is void.+--+-- INVARIANT: OutStgArgs in the range only have NvUnaryTypes+-- (i.e. no unboxed tuples, sums or voids)+--+type UnariseEnv = VarEnv UnariseVal++data UnariseVal+ = MultiVal [OutStgArg] -- MultiVal to tuple. Can be empty list (void).+ | UnaryVal OutStgArg -- See NOTE [Renaming during unarisation].++instance Outputable UnariseVal where+ ppr (MultiVal args) = text "MultiVal" <+> ppr args+ ppr (UnaryVal arg) = text "UnaryVal" <+> ppr arg++-- | Extend the environment, checking the UnariseEnv invariant.+extendRho :: UnariseEnv -> Id -> UnariseVal -> UnariseEnv+extendRho rho x (MultiVal args)+ = ASSERT(all (isNvUnaryType . stgArgType) args)+ extendVarEnv rho x (MultiVal args)+extendRho rho x (UnaryVal val)+ = ASSERT(isNvUnaryType (stgArgType val))+ extendVarEnv rho x (UnaryVal val)++--------------------------------------------------------------------------------++unarise :: UniqSupply -> [StgTopBinding] -> [StgTopBinding]+unarise us binds = initUs_ us (mapM (unariseTopBinding emptyVarEnv) binds)++unariseTopBinding :: UnariseEnv -> StgTopBinding -> UniqSM StgTopBinding+unariseTopBinding rho (StgTopLifted bind)+ = StgTopLifted <$> unariseBinding rho bind+unariseTopBinding _ bind@StgTopStringLit{} = return bind++unariseBinding :: UnariseEnv -> StgBinding -> UniqSM StgBinding+unariseBinding rho (StgNonRec x rhs)+ = StgNonRec x <$> unariseRhs rho rhs+unariseBinding rho (StgRec xrhss)+ = StgRec <$> mapM (\(x, rhs) -> (x,) <$> unariseRhs rho rhs) xrhss++unariseRhs :: UnariseEnv -> StgRhs -> UniqSM StgRhs+unariseRhs rho (StgRhsClosure ccs b_info fvs update_flag args expr)+ = do (rho', args1) <- unariseFunArgBinders rho args+ expr' <- unariseExpr rho' expr+ let fvs' = unariseFreeVars rho fvs+ return (StgRhsClosure ccs b_info fvs' update_flag args1 expr')++unariseRhs rho (StgRhsCon ccs con args)+ = ASSERT(not (isUnboxedTupleCon con || isUnboxedSumCon con))+ return (StgRhsCon ccs con (unariseConArgs rho args))++--------------------------------------------------------------------------------++unariseExpr :: UnariseEnv -> StgExpr -> UniqSM StgExpr++unariseExpr rho e@(StgApp f [])+ = case lookupVarEnv rho f of+ Just (MultiVal args) -- Including empty tuples+ -> return (mkTuple args)+ Just (UnaryVal (StgVarArg f'))+ -> return (StgApp f' [])+ Just (UnaryVal (StgLitArg f'))+ -> return (StgLit f')+ Nothing+ -> return e++unariseExpr rho e@(StgApp f args)+ = return (StgApp f' (unariseFunArgs rho args))+ where+ f' = case lookupVarEnv rho f of+ Just (UnaryVal (StgVarArg f')) -> f'+ Nothing -> f+ err -> pprPanic "unariseExpr - app2" (ppr e $$ ppr err)+ -- Can't happen because 'args' is non-empty, and+ -- a tuple or sum cannot be applied to anything++unariseExpr _ (StgLit l)+ = return (StgLit l)++unariseExpr rho (StgConApp dc args ty_args)+ | Just args' <- unariseMulti_maybe rho dc args ty_args+ = return (mkTuple args')++ | otherwise+ , let args' = unariseConArgs rho args+ = return (StgConApp dc args' (map stgArgType args'))++unariseExpr rho (StgOpApp op args ty)+ = return (StgOpApp op (unariseFunArgs rho args) ty)++unariseExpr _ e@StgLam{}+ = pprPanic "unariseExpr: found lambda" (ppr e)++unariseExpr rho (StgCase scrut bndr alt_ty alts)+ -- a tuple/sum binders in the scrutinee can always be eliminated+ | StgApp v [] <- scrut+ , Just (MultiVal xs) <- lookupVarEnv rho v+ = elimCase rho xs bndr alt_ty alts++ -- Handle strict lets for tuples and sums:+ -- case (# a,b #) of r -> rhs+ -- and analogously for sums+ | StgConApp dc args ty_args <- scrut+ , Just args' <- unariseMulti_maybe rho dc args ty_args+ = elimCase rho args' bndr alt_ty alts++ -- general case+ | otherwise+ = do scrut' <- unariseExpr rho scrut+ alts' <- unariseAlts rho alt_ty bndr alts+ return (StgCase scrut' bndr alt_ty alts')+ -- bndr will be dead after unarise++unariseExpr rho (StgLet bind e)+ = StgLet <$> unariseBinding rho bind <*> unariseExpr rho e++unariseExpr rho (StgLetNoEscape bind e)+ = StgLetNoEscape <$> unariseBinding rho bind <*> unariseExpr rho e++unariseExpr rho (StgTick tick e)+ = StgTick tick <$> unariseExpr rho e++-- Doesn't return void args.+unariseMulti_maybe :: UnariseEnv -> DataCon -> [InStgArg] -> [Type] -> Maybe [OutStgArg]+unariseMulti_maybe rho dc args ty_args+ | isUnboxedTupleCon dc+ = Just (unariseConArgs rho args)++ | isUnboxedSumCon dc+ , let args1 = ASSERT(isSingleton args) (unariseConArgs rho args)+ = Just (mkUbxSum dc ty_args args1)++ | otherwise+ = Nothing++--------------------------------------------------------------------------------++elimCase :: UnariseEnv+ -> [OutStgArg] -- non-void args+ -> InId -> AltType -> [InStgAlt] -> UniqSM OutStgExpr++elimCase rho args bndr (MultiValAlt _) [(_, bndrs, rhs)]+ = do let rho1 = extendRho rho bndr (MultiVal args)+ rho2+ | isUnboxedTupleBndr bndr+ = mapTupleIdBinders bndrs args rho1+ | otherwise+ = ASSERT(isUnboxedSumBndr bndr)+ if null bndrs then rho1+ else mapSumIdBinders bndrs args rho1++ unariseExpr rho2 rhs++elimCase rho args bndr (MultiValAlt _) alts+ | isUnboxedSumBndr bndr+ = do let (tag_arg : real_args) = args+ tag_bndr <- mkId (mkFastString "tag") tagTy+ -- this won't be used but we need a binder anyway+ let rho1 = extendRho rho bndr (MultiVal args)+ scrut' = case tag_arg of+ StgVarArg v -> StgApp v []+ StgLitArg l -> StgLit l++ alts' <- unariseSumAlts rho1 real_args alts+ return (StgCase scrut' tag_bndr tagAltTy alts')++elimCase _ args bndr alt_ty alts+ = pprPanic "elimCase - unhandled case"+ (ppr args <+> ppr bndr <+> ppr alt_ty $$ ppr alts)++--------------------------------------------------------------------------------++unariseAlts :: UnariseEnv -> AltType -> InId -> [StgAlt] -> UniqSM [StgAlt]+unariseAlts rho (MultiValAlt n) bndr [(DEFAULT, [], e)]+ | isUnboxedTupleBndr bndr+ = do (rho', ys) <- unariseConArgBinder rho bndr+ e' <- unariseExpr rho' e+ return [(DataAlt (tupleDataCon Unboxed n), ys, e')]++unariseAlts rho (MultiValAlt n) bndr [(DataAlt _, ys, e)]+ | isUnboxedTupleBndr bndr+ = do (rho', ys1) <- unariseConArgBinders rho ys+ MASSERT(n == length ys1)+ let rho'' = extendRho rho' bndr (MultiVal (map StgVarArg ys1))+ e' <- unariseExpr rho'' e+ return [(DataAlt (tupleDataCon Unboxed n), ys1, e')]++unariseAlts _ (MultiValAlt _) bndr alts+ | isUnboxedTupleBndr bndr+ = pprPanic "unariseExpr: strange multi val alts" (ppr alts)++-- In this case we don't need to scrutinize the tag bit+unariseAlts rho (MultiValAlt _) bndr [(DEFAULT, _, rhs)]+ | isUnboxedSumBndr bndr+ = do (rho_sum_bndrs, sum_bndrs) <- unariseConArgBinder rho bndr+ rhs' <- unariseExpr rho_sum_bndrs rhs+ return [(DataAlt (tupleDataCon Unboxed (length sum_bndrs)), sum_bndrs, rhs')]++unariseAlts rho (MultiValAlt _) bndr alts+ | isUnboxedSumBndr bndr+ = do (rho_sum_bndrs, scrt_bndrs@(tag_bndr : real_bndrs)) <- unariseConArgBinder rho bndr+ alts' <- unariseSumAlts rho_sum_bndrs (map StgVarArg real_bndrs) alts+ let inner_case = StgCase (StgApp tag_bndr []) tag_bndr tagAltTy alts'+ return [ (DataAlt (tupleDataCon Unboxed (length scrt_bndrs)),+ scrt_bndrs,+ inner_case) ]++unariseAlts rho _ _ alts+ = mapM (\alt -> unariseAlt rho alt) alts++unariseAlt :: UnariseEnv -> StgAlt -> UniqSM StgAlt+unariseAlt rho (con, xs, e)+ = do (rho', xs') <- unariseConArgBinders rho xs+ (con, xs',) <$> unariseExpr rho' e++--------------------------------------------------------------------------------++-- | Make alternatives that match on the tag of a sum+-- (i.e. generate LitAlts for the tag)+unariseSumAlts :: UnariseEnv+ -> [StgArg] -- sum components _excluding_ the tag bit.+ -> [StgAlt] -- original alternative with sum LHS+ -> UniqSM [StgAlt]+unariseSumAlts env args alts+ = do alts' <- mapM (unariseSumAlt env args) alts+ return (mkDefaultLitAlt alts')++unariseSumAlt :: UnariseEnv+ -> [StgArg] -- sum components _excluding_ the tag bit.+ -> StgAlt -- original alternative with sum LHS+ -> UniqSM StgAlt+unariseSumAlt rho _ (DEFAULT, _, e)+ = ( DEFAULT, [], ) <$> unariseExpr rho e++unariseSumAlt rho args (DataAlt sumCon, bs, e)+ = do let rho' = mapSumIdBinders bs args rho+ e' <- unariseExpr rho' e+ return ( LitAlt (MachInt (fromIntegral (dataConTag sumCon))), [], e' )++unariseSumAlt _ scrt alt+ = pprPanic "unariseSumAlt" (ppr scrt $$ ppr alt)++--------------------------------------------------------------------------------++mapTupleIdBinders+ :: [InId] -- Un-processed binders of a tuple alternative.+ -- Can have void binders.+ -> [OutStgArg] -- Arguments that form the tuple (after unarisation).+ -- Can't have void args.+ -> UnariseEnv+ -> UnariseEnv+mapTupleIdBinders ids args0 rho0+ = ASSERT(not (any (isVoidTy . stgArgType) args0))+ let+ ids_unarised :: [(Id, [PrimRep])]+ ids_unarised = map (\id -> (id, typePrimRep (idType id))) ids++ map_ids :: UnariseEnv -> [(Id, [PrimRep])] -> [StgArg] -> UnariseEnv+ map_ids rho [] _ = rho+ map_ids rho ((x, x_reps) : xs) args =+ let+ x_arity = length x_reps+ (x_args, args') =+ ASSERT(args `lengthAtLeast` x_arity)+ splitAt x_arity args++ rho'+ | x_arity == 1+ = ASSERT(x_args `lengthIs` 1)+ extendRho rho x (UnaryVal (head x_args))+ | otherwise+ = extendRho rho x (MultiVal x_args)+ in+ map_ids rho' xs args'+ in+ map_ids rho0 ids_unarised args0++mapSumIdBinders+ :: [InId] -- Binder of a sum alternative (remember that sum patterns+ -- only have one binder, so this list should be a singleton)+ -> [OutStgArg] -- Arguments that form the sum (NOT including the tag).+ -- Can't have void args.+ -> UnariseEnv+ -> UnariseEnv++mapSumIdBinders [id] args rho0+ = ASSERT(not (any (isVoidTy . stgArgType) args))+ let+ arg_slots = map primRepSlot $ concatMap (typePrimRep . stgArgType) args+ id_slots = map primRepSlot $ typePrimRep (idType id)+ layout1 = layoutUbxSum arg_slots id_slots+ in+ if isMultiValBndr id+ then extendRho rho0 id (MultiVal [ args !! i | i <- layout1 ])+ else ASSERT(layout1 `lengthIs` 1)+ extendRho rho0 id (UnaryVal (args !! head layout1))++mapSumIdBinders ids sum_args _+ = pprPanic "mapSumIdBinders" (ppr ids $$ ppr sum_args)++-- | Build a unboxed sum term from arguments of an alternative.+--+-- Example, for (# x | #) :: (# (# #) | Int #) we call+--+-- mkUbxSum (# _ | #) [ (# #), Int ] [ voidPrimId ]+--+-- which returns+--+-- [ 1#, rubbish ]+--+mkUbxSum+ :: DataCon -- Sum data con+ -> [Type] -- Type arguments of the sum data con+ -> [OutStgArg] -- Actual arguments of the alternative.+ -> [OutStgArg] -- Final tuple arguments+mkUbxSum dc ty_args args0+ = let+ (_ : sum_slots) = ubxSumRepType (map typePrimRep ty_args)+ -- drop tag slot++ tag = dataConTag dc++ layout' = layoutUbxSum sum_slots (mapMaybe (typeSlotTy . stgArgType) args0)+ tag_arg = StgLitArg (MachInt (fromIntegral tag))+ arg_idxs = IM.fromList (zipEqual "mkUbxSum" layout' args0)++ mkTupArgs :: Int -> [SlotTy] -> IM.IntMap StgArg -> [StgArg]+ mkTupArgs _ [] _+ = []+ mkTupArgs arg_idx (slot : slots_left) arg_map+ | Just stg_arg <- IM.lookup arg_idx arg_map+ = stg_arg : mkTupArgs (arg_idx + 1) slots_left arg_map+ | otherwise+ = slotRubbishArg slot : mkTupArgs (arg_idx + 1) slots_left arg_map++ slotRubbishArg :: SlotTy -> StgArg+ slotRubbishArg PtrSlot = StgVarArg aBSENT_ERROR_ID+ slotRubbishArg WordSlot = StgLitArg (MachWord 0)+ slotRubbishArg Word64Slot = StgLitArg (MachWord64 0)+ slotRubbishArg FloatSlot = StgLitArg (MachFloat 0)+ slotRubbishArg DoubleSlot = StgLitArg (MachDouble 0)+ in+ tag_arg : mkTupArgs 0 sum_slots arg_idxs++--------------------------------------------------------------------------------++{-+For arguments (StgArg) and binders (Id) we have two kind of unarisation:++ - When unarising function arg binders and arguments, we don't want to remove+ void binders and arguments. For example,++ f :: (# (# #), (# #) #) -> Void# -> RealWorld# -> ...+ f x y z = <body>++ Here after unarise we should still get a function with arity 3. Similarly+ in the call site we shouldn't remove void arguments:++ f (# (# #), (# #) #) voidId rw++ When unarising <body>, we extend the environment with these binders:++ x :-> MultiVal [], y :-> MultiVal [], z :-> MultiVal []++ Because their rep types are `MultiRep []` (aka. void). This means that when+ we see `x` in a function argument position, we actually replace it with a+ void argument. When we see it in a DataCon argument position, we just get+ rid of it, because DataCon applications in STG are always saturated.++ - When unarising case alternative binders we remove void binders, but we+ still update the environment the same way, because those binders may be+ used in the RHS. Example:++ case x of y {+ (# x1, x2, x3 #) -> <RHS>+ }++ We know that y can't be void, because we don't scrutinize voids, so x will+ be unarised to some number of arguments, and those arguments will have at+ least one non-void thing. So in the rho we will have something like:++ x :-> MultiVal [xu1, xu2]++ Now, after we eliminate void binders in the pattern, we get exactly the same+ number of binders, and extend rho again with these:++ x1 :-> UnaryVal xu1+ x2 :-> MultiVal [] -- x2 is void+ x3 :-> UnaryVal xu2++ Now when we see x2 in a function argument position or in return position, we+ generate void#. In constructor argument position, we just remove it.++So in short, when we have a void id,++ - We keep it if it's a lambda argument binder or+ in argument position of an application.++ - We remove it if it's a DataCon field binder or+ in argument position of a DataCon application.+-}++--------------------------------------------------------------------------------++-- | MultiVal a function argument. Never returns an empty list.+unariseFunArg :: UnariseEnv -> StgArg -> [StgArg]+unariseFunArg rho (StgVarArg x) =+ case lookupVarEnv rho x of+ Just (MultiVal []) -> [voidArg] -- NB: do not remove void args+ Just (MultiVal as) -> as+ Just (UnaryVal arg) -> [arg]+ Nothing -> [StgVarArg x]+unariseFunArg _ arg = [arg]++unariseFunArgs :: UnariseEnv -> [StgArg] -> [StgArg]+unariseFunArgs = concatMap . unariseFunArg++unariseFunArgBinders :: UnariseEnv -> [Id] -> UniqSM (UnariseEnv, [Id])+unariseFunArgBinders rho xs = second concat <$> mapAccumLM unariseFunArgBinder rho xs++unariseFunArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id])+-- Result list of binders is never empty+unariseFunArgBinder rho x =+ case typePrimRep (idType x) of+ [] -> return (extendRho rho x (MultiVal []), [voidArgId])+ -- NB: do not remove void binders+ [_] -> return (rho, [x])+ reps -> do+ xs <- mkIds (mkFastString "us") (map primRepToType reps)+ return (extendRho rho x (MultiVal (map StgVarArg xs)), xs)++--------------------------------------------------------------------------------++-- | MultiVal a DataCon argument. Returns an empty list when argument is void.+unariseConArg :: UnariseEnv -> InStgArg -> [OutStgArg]+unariseConArg rho (StgVarArg x) =+ case lookupVarEnv rho x of+ Just (UnaryVal arg) -> [arg]+ Just (MultiVal as) -> as -- 'as' can be empty+ Nothing+ | isVoidTy (idType x) -> [] -- e.g. C realWorld#+ -- Here realWorld# is not in the envt, but+ -- is a void, and so should be eliminated+ | otherwise -> [StgVarArg x]+unariseConArg _ arg = [arg] -- We have no void literals++unariseConArgs :: UnariseEnv -> [InStgArg] -> [OutStgArg]+unariseConArgs = concatMap . unariseConArg++unariseConArgBinders :: UnariseEnv -> [Id] -> UniqSM (UnariseEnv, [Id])+unariseConArgBinders rho xs = second concat <$> mapAccumLM unariseConArgBinder rho xs++unariseConArgBinder :: UnariseEnv -> Id -> UniqSM (UnariseEnv, [Id])+unariseConArgBinder rho x =+ case typePrimRep (idType x) of+ [_] -> return (rho, [x])+ reps -> do+ xs <- mkIds (mkFastString "us") (map primRepToType reps)+ return (extendRho rho x (MultiVal (map StgVarArg xs)), xs)++unariseFreeVars :: UnariseEnv -> [InId] -> [OutId]+unariseFreeVars rho fvs+ = [ v | fv <- fvs, StgVarArg v <- unariseFreeVar rho fv ]+ -- Notice that we filter out any StgLitArgs+ -- e.g. case e of (x :: (# Int | Bool #))+ -- (# v | #) -> ... let {g = \y. ..x...} in ...+ -- (# | w #) -> ...+ -- Here 'x' is free in g's closure, and the env will have+ -- x :-> [1, v]+ -- we want to capture 'v', but not 1, in the free vars++unariseFreeVar :: UnariseEnv -> Id -> [StgArg]+unariseFreeVar rho x =+ case lookupVarEnv rho x of+ Just (MultiVal args) -> args+ Just (UnaryVal arg) -> [arg]+ Nothing -> [StgVarArg x]++--------------------------------------------------------------------------------++mkIds :: FastString -> [UnaryType] -> UniqSM [Id]+mkIds fs tys = mapM (mkId fs) tys++mkId :: FastString -> UnaryType -> UniqSM Id+mkId = mkSysLocalOrCoVarM++isMultiValBndr :: Id -> Bool+isMultiValBndr id+ | [_] <- typePrimRep (idType id)+ = False+ | otherwise+ = True++isUnboxedSumBndr :: Id -> Bool+isUnboxedSumBndr = isUnboxedSumType . idType++isUnboxedTupleBndr :: Id -> Bool+isUnboxedTupleBndr = isUnboxedTupleType . idType++mkTuple :: [StgArg] -> StgExpr+mkTuple args = StgConApp (tupleDataCon Unboxed (length args)) args (map stgArgType args)++tagAltTy :: AltType+tagAltTy = PrimAlt IntRep++tagTy :: Type+tagTy = intPrimTy++voidArg :: StgArg+voidArg = StgVarArg voidPrimId++mkDefaultLitAlt :: [StgAlt] -> [StgAlt]+-- We have an exhauseive list of literal alternatives+-- 1# -> e1+-- 2# -> e2+-- Since they are exhaustive, we can replace one with DEFAULT, to avoid+-- generating a final test. Remember, the DEFAULT comes first if it exists.+mkDefaultLitAlt [] = pprPanic "elimUbxSumExpr.mkDefaultAlt" (text "Empty alts")+mkDefaultLitAlt alts@((DEFAULT, _, _) : _) = alts+mkDefaultLitAlt ((LitAlt{}, [], rhs) : alts) = (DEFAULT, [], rhs) : alts+mkDefaultLitAlt alts = pprPanic "mkDefaultLitAlt" (text "Not a lit alt:" <+> ppr alts)
+ specialise/Rules.hs view
@@ -0,0 +1,1256 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[CoreRules]{Transformation rules}+-}++{-# LANGUAGE CPP #-}++-- | Functions for collecting together and applying rewrite rules to a module.+-- The 'CoreRule' datatype itself is declared elsewhere.+module Rules (+ -- ** Constructing+ emptyRuleBase, mkRuleBase, extendRuleBaseList,+ unionRuleBase, pprRuleBase,++ -- ** Checking rule applications+ ruleCheckProgram,++ -- ** Manipulating 'RuleInfo' rules+ mkRuleInfo, extendRuleInfo, addRuleInfo,+ addIdSpecialisations,++ -- * Misc. CoreRule helpers+ rulesOfBinds, getRules, pprRulesForUser,++ lookupRule, mkRule, roughTopNames+ ) where++#include "HsVersions.h"++import CoreSyn -- All of it+import Module ( Module, ModuleSet, elemModuleSet )+import CoreSubst+import CoreOpt ( exprIsLambda_maybe )+import CoreFVs ( exprFreeVars, exprsFreeVars, bindFreeVars+ , rulesFreeVarsDSet, exprsOrphNames, exprFreeVarsList )+import CoreUtils ( exprType, eqExpr, mkTick, mkTicks,+ stripTicksTopT, stripTicksTopE,+ isJoinBind )+import PprCore ( pprRules )+import Type ( Type, substTy, mkTCvSubst )+import TcType ( tcSplitTyConApp_maybe )+import TysWiredIn ( anyTypeOfKind )+import Coercion+import CoreTidy ( tidyRules )+import Id+import IdInfo ( RuleInfo( RuleInfo ) )+import Var+import VarEnv+import VarSet+import Name ( Name, NamedThing(..), nameIsLocalOrFrom )+import NameSet+import NameEnv+import UniqFM+import Unify ( ruleMatchTyKiX )+import BasicTypes ( Activation, CompilerPhase, isActive, pprRuleName )+import DynFlags ( DynFlags )+import Outputable+import FastString+import Maybes+import Bag+import Util+import Data.List+import Data.Ord+import Control.Monad ( guard )++{-+Note [Overall plumbing for rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* After the desugarer:+ - The ModGuts initially contains mg_rules :: [CoreRule] of+ locally-declared rules for imported Ids.+ - Locally-declared rules for locally-declared Ids are attached to+ the IdInfo for that Id. See Note [Attach rules to local ids] in+ DsBinds++* TidyPgm strips off all the rules from local Ids and adds them to+ mg_rules, so that the ModGuts has *all* the locally-declared rules.++* The HomePackageTable contains a ModDetails for each home package+ module. Each contains md_rules :: [CoreRule] of rules declared in+ that module. The HomePackageTable grows as ghc --make does its+ up-sweep. In batch mode (ghc -c), the HPT is empty; all imported modules+ are treated by the "external" route, discussed next, regardless of+ which package they come from.++* The ExternalPackageState has a single eps_rule_base :: RuleBase for+ Ids in other packages. This RuleBase simply grow monotonically, as+ ghc --make compiles one module after another.++ During simplification, interface files may get demand-loaded,+ as the simplifier explores the unfoldings for Ids it has in+ its hand. (Via an unsafePerformIO; the EPS is really a cache.)+ That in turn may make the EPS rule-base grow. In contrast, the+ HPT never grows in this way.++* The result of all this is that during Core-to-Core optimisation+ there are four sources of rules:++ (a) Rules in the IdInfo of the Id they are a rule for. These are+ easy: fast to look up, and if you apply a substitution then+ it'll be applied to the IdInfo as a matter of course.++ (b) Rules declared in this module for imported Ids, kept in the+ ModGuts. If you do a substitution, you'd better apply the+ substitution to these. There are seldom many of these.++ (c) Rules declared in the HomePackageTable. These never change.++ (d) Rules in the ExternalPackageTable. These can grow in response+ to lazy demand-loading of interfaces.++* At the moment (c) is carried in a reader-monad way by the CoreMonad.+ The HomePackageTable doesn't have a single RuleBase because technically+ we should only be able to "see" rules "below" this module; so we+ generate a RuleBase for (c) by combing rules from all the modules+ "below" us. That's why we can't just select the home-package RuleBase+ from HscEnv.++ [NB: we are inconsistent here. We should do the same for external+ packages, but we don't. Same for type-class instances.]++* So in the outer simplifier loop, we combine (b-d) into a single+ RuleBase, reading+ (b) from the ModGuts,+ (c) from the CoreMonad, and+ (d) from its mutable variable+ [Of coures this means that we won't see new EPS rules that come in+ during a single simplifier iteration, but that probably does not+ matter.]+++************************************************************************+* *+\subsection[specialisation-IdInfo]{Specialisation info about an @Id@}+* *+************************************************************************++A @CoreRule@ holds details of one rule for an @Id@, which+includes its specialisations.++For example, if a rule for @f@ contains the mapping:+\begin{verbatim}+ forall a b d. [Type (List a), Type b, Var d] ===> f' a b+\end{verbatim}+then when we find an application of f to matching types, we simply replace+it by the matching RHS:+\begin{verbatim}+ f (List Int) Bool dict ===> f' Int Bool+\end{verbatim}+All the stuff about how many dictionaries to discard, and what types+to apply the specialised function to, are handled by the fact that the+Rule contains a template for the result of the specialisation.++There is one more exciting case, which is dealt with in exactly the same+way. If the specialised value is unboxed then it is lifted at its+definition site and unlifted at its uses. For example:++ pi :: forall a. Num a => a++might have a specialisation++ [Int#] ===> (case pi' of Lift pi# -> pi#)++where pi' :: Lift Int# is the specialised version of pi.+-}++mkRule :: Module -> Bool -> Bool -> RuleName -> Activation+ -> Name -> [CoreBndr] -> [CoreExpr] -> CoreExpr -> CoreRule+-- ^ Used to make 'CoreRule' for an 'Id' defined in the module being+-- compiled. See also 'CoreSyn.CoreRule'+mkRule this_mod is_auto is_local name act fn bndrs args rhs+ = Rule { ru_name = name, ru_fn = fn, ru_act = act,+ ru_bndrs = bndrs, ru_args = args,+ ru_rhs = rhs,+ ru_rough = roughTopNames args,+ ru_origin = this_mod,+ ru_orphan = orph,+ ru_auto = is_auto, ru_local = is_local }+ where+ -- Compute orphanhood. See Note [Orphans] in InstEnv+ -- A rule is an orphan only if none of the variables+ -- mentioned on its left-hand side are locally defined+ lhs_names = extendNameSet (exprsOrphNames args) fn++ -- Since rules get eventually attached to one of the free names+ -- from the definition when compiling the ABI hash, we should make+ -- it deterministic. This chooses the one with minimal OccName+ -- as opposed to uniq value.+ local_lhs_names = filterNameSet (nameIsLocalOrFrom this_mod) lhs_names+ orph = chooseOrphanAnchor local_lhs_names++--------------+roughTopNames :: [CoreExpr] -> [Maybe Name]+-- ^ Find the \"top\" free names of several expressions.+-- Such names are either:+--+-- 1. The function finally being applied to in an application chain+-- (if that name is a GlobalId: see "Var#globalvslocal"), or+--+-- 2. The 'TyCon' if the expression is a 'Type'+--+-- This is used for the fast-match-check for rules;+-- if the top names don't match, the rest can't+roughTopNames args = map roughTopName args++roughTopName :: CoreExpr -> Maybe Name+roughTopName (Type ty) = case tcSplitTyConApp_maybe ty of+ Just (tc,_) -> Just (getName tc)+ Nothing -> Nothing+roughTopName (Coercion _) = Nothing+roughTopName (App f _) = roughTopName f+roughTopName (Var f) | isGlobalId f -- Note [Care with roughTopName]+ , isDataConWorkId f || idArity f > 0+ = Just (idName f)+roughTopName (Tick t e) | tickishFloatable t+ = roughTopName e+roughTopName _ = Nothing++ruleCantMatch :: [Maybe Name] -> [Maybe Name] -> Bool+-- ^ @ruleCantMatch tpl actual@ returns True only if @actual@+-- definitely can't match @tpl@ by instantiating @tpl@.+-- It's only a one-way match; unlike instance matching we+-- don't consider unification.+--+-- Notice that [_$_]+-- @ruleCantMatch [Nothing] [Just n2] = False@+-- Reason: a template variable can be instantiated by a constant+-- Also:+-- @ruleCantMatch [Just n1] [Nothing] = False@+-- Reason: a local variable @v@ in the actuals might [_$_]++ruleCantMatch (Just n1 : ts) (Just n2 : as) = n1 /= n2 || ruleCantMatch ts as+ruleCantMatch (_ : ts) (_ : as) = ruleCantMatch ts as+ruleCantMatch _ _ = False++{-+Note [Care with roughTopName]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ module M where { x = a:b }+ module N where { ...f x...+ RULE f (p:q) = ... }+You'd expect the rule to match, because the matcher can+look through the unfolding of 'x'. So we must avoid roughTopName+returning 'M.x' for the call (f x), or else it'll say "can't match"+and we won't even try!!++However, suppose we have+ RULE g (M.h x) = ...+ foo = ...(g (M.k v))....+where k is a *function* exported by M. We never really match+functions (lambdas) except by name, so in this case it seems like+a good idea to treat 'M.k' as a roughTopName of the call.+-}++pprRulesForUser :: DynFlags -> [CoreRule] -> SDoc+-- (a) tidy the rules+-- (b) sort them into order based on the rule name+-- (c) suppress uniques (unless -dppr-debug is on)+-- This combination makes the output stable so we can use in testing+-- It's here rather than in PprCore because it calls tidyRules+pprRulesForUser dflags rules+ = withPprStyle (defaultUserStyle dflags) $+ pprRules $+ sortBy (comparing ruleName) $+ tidyRules emptyTidyEnv rules++{-+************************************************************************+* *+ RuleInfo: the rules in an IdInfo+* *+************************************************************************+-}++-- | Make a 'RuleInfo' containing a number of 'CoreRule's, suitable+-- for putting into an 'IdInfo'+mkRuleInfo :: [CoreRule] -> RuleInfo+mkRuleInfo rules = RuleInfo rules (rulesFreeVarsDSet rules)++extendRuleInfo :: RuleInfo -> [CoreRule] -> RuleInfo+extendRuleInfo (RuleInfo rs1 fvs1) rs2+ = RuleInfo (rs2 ++ rs1) (rulesFreeVarsDSet rs2 `unionDVarSet` fvs1)++addRuleInfo :: RuleInfo -> RuleInfo -> RuleInfo+addRuleInfo (RuleInfo rs1 fvs1) (RuleInfo rs2 fvs2)+ = RuleInfo (rs1 ++ rs2) (fvs1 `unionDVarSet` fvs2)++addIdSpecialisations :: Id -> [CoreRule] -> Id+addIdSpecialisations id []+ = id+addIdSpecialisations id rules+ = setIdSpecialisation id $+ extendRuleInfo (idSpecialisation id) rules++-- | Gather all the rules for locally bound identifiers from the supplied bindings+rulesOfBinds :: [CoreBind] -> [CoreRule]+rulesOfBinds binds = concatMap (concatMap idCoreRules . bindersOf) binds++getRules :: RuleEnv -> Id -> [CoreRule]+-- See Note [Where rules are found]+getRules (RuleEnv { re_base = rule_base, re_visible_orphs = orphs }) fn+ = idCoreRules fn ++ filter (ruleIsVisible orphs) imp_rules+ where+ imp_rules = lookupNameEnv rule_base (idName fn) `orElse` []++ruleIsVisible :: ModuleSet -> CoreRule -> Bool+ruleIsVisible _ BuiltinRule{} = True+ruleIsVisible vis_orphs Rule { ru_orphan = orph, ru_origin = origin }+ = notOrphan orph || origin `elemModuleSet` vis_orphs++{-+Note [Where rules are found]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The rules for an Id come from two places:+ (a) the ones it is born with, stored inside the Id iself (idCoreRules fn),+ (b) rules added in other modules, stored in the global RuleBase (imp_rules)++It's tempting to think that+ - LocalIds have only (a)+ - non-LocalIds have only (b)++but that isn't quite right:++ - PrimOps and ClassOps are born with a bunch of rules inside the Id,+ even when they are imported++ - The rules in PrelRules.builtinRules should be active even+ in the module defining the Id (when it's a LocalId), but+ the rules are kept in the global RuleBase+++************************************************************************+* *+ RuleBase+* *+************************************************************************+-}++-- RuleBase itself is defined in CoreSyn, along with CoreRule++emptyRuleBase :: RuleBase+emptyRuleBase = emptyNameEnv++mkRuleBase :: [CoreRule] -> RuleBase+mkRuleBase rules = extendRuleBaseList emptyRuleBase rules++extendRuleBaseList :: RuleBase -> [CoreRule] -> RuleBase+extendRuleBaseList rule_base new_guys+ = foldl extendRuleBase rule_base new_guys++unionRuleBase :: RuleBase -> RuleBase -> RuleBase+unionRuleBase rb1 rb2 = plusNameEnv_C (++) rb1 rb2++extendRuleBase :: RuleBase -> CoreRule -> RuleBase+extendRuleBase rule_base rule+ = extendNameEnv_Acc (:) singleton rule_base (ruleIdName rule) rule++pprRuleBase :: RuleBase -> SDoc+pprRuleBase rules = pprUFM rules $ \rss ->+ vcat [ pprRules (tidyRules emptyTidyEnv rs)+ | rs <- rss ]++{-+************************************************************************+* *+ Matching+* *+************************************************************************+-}++-- | The main rule matching function. Attempts to apply all (active)+-- supplied rules to this instance of an application in a given+-- context, returning the rule applied and the resulting expression if+-- successful.+lookupRule :: DynFlags -> InScopeEnv+ -> (Activation -> Bool) -- When rule is active+ -> Id -> [CoreExpr]+ -> [CoreRule] -> Maybe (CoreRule, CoreExpr)++-- See Note [Extra args in rule matching]+-- See comments on matchRule+lookupRule dflags in_scope is_active fn args rules+ = -- pprTrace "matchRules" (ppr fn <+> ppr args $$ ppr rules ) $+ case go [] rules of+ [] -> Nothing+ (m:ms) -> Just (findBest (fn,args') m ms)+ where+ rough_args = map roughTopName args++ -- Strip ticks from arguments, see note [Tick annotations in RULE+ -- matching]. We only collect ticks if a rule actually matches -+ -- this matters for performance tests.+ args' = map (stripTicksTopE tickishFloatable) args+ ticks = concatMap (stripTicksTopT tickishFloatable) args++ go :: [(CoreRule,CoreExpr)] -> [CoreRule] -> [(CoreRule,CoreExpr)]+ go ms [] = ms+ go ms (r:rs)+ | Just e <- matchRule dflags in_scope is_active fn args' rough_args r+ = go ((r,mkTicks ticks e):ms) rs+ | otherwise+ = -- pprTrace "match failed" (ppr r $$ ppr args $$+ -- ppr [ (arg_id, unfoldingTemplate unf)+ -- | Var arg_id <- args+ -- , let unf = idUnfolding arg_id+ -- , isCheapUnfolding unf] )+ go ms rs++findBest :: (Id, [CoreExpr])+ -> (CoreRule,CoreExpr) -> [(CoreRule,CoreExpr)] -> (CoreRule,CoreExpr)+-- All these pairs matched the expression+-- Return the pair the the most specific rule+-- The (fn,args) is just for overlap reporting++findBest _ (rule,ans) [] = (rule,ans)+findBest target (rule1,ans1) ((rule2,ans2):prs)+ | rule1 `isMoreSpecific` rule2 = findBest target (rule1,ans1) prs+ | rule2 `isMoreSpecific` rule1 = findBest target (rule2,ans2) prs+ | debugIsOn = let pp_rule rule = sdocWithPprDebug $ \dbg -> if dbg+ then ppr rule+ else doubleQuotes (ftext (ruleName rule))+ in pprTrace "Rules.findBest: rule overlap (Rule 1 wins)"+ (vcat [ sdocWithPprDebug $ \dbg -> if dbg+ then text "Expression to match:" <+> ppr fn+ <+> sep (map ppr args)+ else empty+ , text "Rule 1:" <+> pp_rule rule1+ , text "Rule 2:" <+> pp_rule rule2]) $+ findBest target (rule1,ans1) prs+ | otherwise = findBest target (rule1,ans1) prs+ where+ (fn,args) = target++isMoreSpecific :: CoreRule -> CoreRule -> Bool+-- This tests if one rule is more specific than another+-- We take the view that a BuiltinRule is less specific than+-- anything else, because we want user-define rules to "win"+-- In particular, class ops have a built-in rule, but we+-- any user-specific rules to win+-- eg (Trac #4397)+-- truncate :: (RealFrac a, Integral b) => a -> b+-- {-# RULES "truncate/Double->Int" truncate = double2Int #-}+-- double2Int :: Double -> Int+-- We want the specific RULE to beat the built-in class-op rule+isMoreSpecific (BuiltinRule {}) _ = False+isMoreSpecific (Rule {}) (BuiltinRule {}) = True+isMoreSpecific (Rule { ru_bndrs = bndrs1, ru_args = args1 })+ (Rule { ru_bndrs = bndrs2, ru_args = args2, ru_name = rule_name2 })+ = isJust (matchN (in_scope, id_unfolding_fun) rule_name2 bndrs2 args2 args1)+ where+ id_unfolding_fun _ = NoUnfolding -- Don't expand in templates+ in_scope = mkInScopeSet (mkVarSet bndrs1)+ -- Actually we should probably include the free vars+ -- of rule1's args, but I can't be bothered++noBlackList :: Activation -> Bool+noBlackList _ = False -- Nothing is black listed++{-+Note [Extra args in rule matching]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we find a matching rule, we return (Just (rule, rhs)),+but the rule firing has only consumed as many of the input args+as the ruleArity says. It's up to the caller to keep track+of any left-over args. E.g. if you call+ lookupRule ... f [e1, e2, e3]+and it returns Just (r, rhs), where r has ruleArity 2+then the real rewrite is+ f e1 e2 e3 ==> rhs e3++You might think it'd be cleaner for lookupRule to deal with the+leftover arguments, by applying 'rhs' to them, but the main call+in the Simplifier works better as it is. Reason: the 'args' passed+to lookupRule are the result of a lazy substitution+-}++------------------------------------+matchRule :: DynFlags -> InScopeEnv -> (Activation -> Bool)+ -> Id -> [CoreExpr] -> [Maybe Name]+ -> CoreRule -> Maybe CoreExpr++-- If (matchRule rule args) returns Just (name,rhs)+-- then (f args) matches the rule, and the corresponding+-- rewritten RHS is rhs+--+-- The returned expression is occurrence-analysed+--+-- Example+--+-- The rule+-- forall f g x. map f (map g x) ==> map (f . g) x+-- is stored+-- CoreRule "map/map"+-- [f,g,x] -- tpl_vars+-- [f,map g x] -- tpl_args+-- map (f.g) x) -- rhs+--+-- Then the call: matchRule the_rule [e1,map e2 e3]+-- = Just ("map/map", (\f,g,x -> rhs) e1 e2 e3)+--+-- Any 'surplus' arguments in the input are simply put on the end+-- of the output.++matchRule dflags rule_env _is_active fn args _rough_args+ (BuiltinRule { ru_try = match_fn })+-- Built-in rules can't be switched off, it seems+ = case match_fn dflags rule_env fn args of+ Nothing -> Nothing+ Just expr -> Just expr++matchRule _ in_scope is_active _ args rough_args+ (Rule { ru_name = rule_name, ru_act = act, ru_rough = tpl_tops+ , ru_bndrs = tpl_vars, ru_args = tpl_args, ru_rhs = rhs })+ | not (is_active act) = Nothing+ | ruleCantMatch tpl_tops rough_args = Nothing+ | otherwise+ = case matchN in_scope rule_name tpl_vars tpl_args args of+ Nothing -> Nothing+ Just (bind_wrapper, tpl_vals) -> Just (bind_wrapper $+ rule_fn `mkApps` tpl_vals)+ where+ rule_fn = mkLams tpl_vars rhs++---------------------------------------+matchN :: InScopeEnv+ -> RuleName -> [Var] -> [CoreExpr]+ -> [CoreExpr] -- ^ Target; can have more elements than the template+ -> Maybe (BindWrapper, -- Floated bindings; see Note [Matching lets]+ [CoreExpr])+-- For a given match template and context, find bindings to wrap around+-- the entire result and what should be substituted for each template variable.+-- Fail if there are two few actual arguments from the target to match the template++matchN (in_scope, id_unf) rule_name tmpl_vars tmpl_es target_es+ = do { subst <- go init_menv emptyRuleSubst tmpl_es target_es+ ; let (_, matched_es) = mapAccumL lookup_tmpl subst tmpl_vars+ ; return (rs_binds subst, matched_es) }+ where+ init_rn_env = mkRnEnv2 (extendInScopeSetList in_scope tmpl_vars)+ -- See Note [Template binders]++ init_menv = RV { rv_tmpls = mkVarSet tmpl_vars, rv_lcl = init_rn_env+ , rv_fltR = mkEmptySubst (rnInScopeSet init_rn_env)+ , rv_unf = id_unf }++ go _ subst [] _ = Just subst+ go _ _ _ [] = Nothing -- Fail if too few actual args+ go menv subst (t:ts) (e:es) = do { subst1 <- match menv subst t e+ ; go menv subst1 ts es }++ lookup_tmpl :: RuleSubst -> Var -> (RuleSubst, CoreExpr)+ lookup_tmpl rs@(RS { rs_tv_subst = tv_subst, rs_id_subst = id_subst }) tmpl_var+ | isId tmpl_var+ = case lookupVarEnv id_subst tmpl_var of+ Just e -> (rs, e)+ Nothing | Just refl_co <- isReflCoVar_maybe tmpl_var+ , let co_expr = Coercion refl_co+ -> (rs { rs_id_subst = extendVarEnv id_subst tmpl_var co_expr }, co_expr)+ | otherwise+ -> unbound tmpl_var+ | otherwise+ = case lookupVarEnv tv_subst tmpl_var of+ Just ty -> (rs, Type ty)+ Nothing -> (rs { rs_tv_subst = extendVarEnv tv_subst tmpl_var fake_ty }, Type fake_ty)+ -- See Note [Unbound RULE binders]+ where+ fake_ty = anyTypeOfKind kind+ cv_subst = to_co_env id_subst+ kind = Type.substTy (mkTCvSubst in_scope (tv_subst, cv_subst))+ (tyVarKind tmpl_var)++ to_co_env env = nonDetFoldUFM_Directly to_co emptyVarEnv env+ -- It's OK to use nonDetFoldUFM_Directly because we forget the+ -- order immediately by creating a new env+ to_co uniq expr env+ | Just co <- exprToCoercion_maybe expr+ = extendVarEnv_Directly env uniq co++ | otherwise+ = env++ unbound var = pprPanic "Template variable unbound in rewrite rule" $+ vcat [ text "Variable:" <+> ppr var+ , text "Rule" <+> pprRuleName rule_name+ , text "Rule bndrs:" <+> ppr tmpl_vars+ , text "LHS args:" <+> ppr tmpl_es+ , text "Actual args:" <+> ppr target_es ]++{- Note [Unbound RULE binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It can be the case that the binder in a rule is not actually+bound on the LHS:++* Type variables. Type synonyms with phantom args can give rise to+ unbound template type variables. Consider this (Trac #10689,+ simplCore/should_compile/T10689):++ type Foo a b = b++ f :: Eq a => a -> Bool+ f x = x==x++ {-# RULES "foo" forall (x :: Foo a Char). f x = True #-}+ finkle = f 'c'++ The rule looks like+ forall (a::*) (d::Eq Char) (x :: Foo a Char).+ f (Foo a Char) d x = True++ Matching the rule won't bind 'a', and legitimately so. We fudge by+ pretending that 'a' is bound to (Any :: *).++* Coercion variables. On the LHS of a RULE for a local binder+ we might have+ RULE forall (c :: a~b). f (x |> c) = e+ Now, if that binding is inlined, so that a=b=Int, we'd get+ RULE forall (c :: Int~Int). f (x |> c) = e+ and now when we simpilfy the LHS (Simplify.simplRule) we+ optCoercion will turn that 'c' into Refl:+ RULE forall (c :: Int~Int). f (x |> <Int>) = e+ and then perhaps drop it altogether. Now 'c' is unbound.++ It's tricky to be sure this never happens, so instead I+ say it's OK to have an unbound coercion binder in a RULE+ provided its type is (c :: t~t). Then, when the RULE+ fires we can substitute <t> for c.++ This actually happened (in a RULE for a local function)+ in Trac #13410, and also in test T10602.+++Note [Template binders]+~~~~~~~~~~~~~~~~~~~~~~~+Consider the following match (example 1):+ Template: forall x. f x+ Target: f (x+1)+This should succeed, because the template variable 'x' has nothing to+do with the 'x' in the target.++Likewise this one (example 2):+ Template: forall x. f (\x.x)+ Target: f (\y.y)++We achieve this simply by:+ * Adding forall'd template binders to the in-scope set++This works even if the template binder are already in scope+(in the target) because++ * The RuleSubst rs_tv_subst, rs_id_subst maps LHS template vars to+ the target world. It is not applied recursively.++ * Having the template vars in the in-scope set ensures that in+ example 2 above, the (\x.x) is cloned to (\x'. x').++In the past we used rnBndrL to clone the template variables if+they were already in scope. But (a) that's not necessary and (b)+it complicate the fancy footwork for Note [Unbound template type variables]+++************************************************************************+* *+ The main matcher+* *+********************************************************************* -}++-- * The domain of the TvSubstEnv and IdSubstEnv are the template+-- variables passed into the match.+--+-- * The BindWrapper in a RuleSubst are the bindings floated out+-- from nested matches; see the Let case of match, below+--+data RuleMatchEnv+ = RV { rv_tmpls :: VarSet -- Template variables+ , rv_lcl :: RnEnv2 -- Renamings for *local bindings*+ -- (lambda/case)+ , rv_fltR :: Subst -- Renamings for floated let-bindings+ -- domain disjoint from envR of rv_lcl+ -- See Note [Matching lets]+ , rv_unf :: IdUnfoldingFun+ }++rvInScopeEnv :: RuleMatchEnv -> InScopeEnv+rvInScopeEnv renv = (rnInScopeSet (rv_lcl renv), rv_unf renv)++data RuleSubst = RS { rs_tv_subst :: TvSubstEnv -- Range is the+ , rs_id_subst :: IdSubstEnv -- template variables+ , rs_binds :: BindWrapper -- Floated bindings+ , rs_bndrs :: VarSet -- Variables bound by floated lets+ }++type BindWrapper = CoreExpr -> CoreExpr+ -- See Notes [Matching lets] and [Matching cases]+ -- we represent the floated bindings as a core-to-core function++emptyRuleSubst :: RuleSubst+emptyRuleSubst = RS { rs_tv_subst = emptyVarEnv, rs_id_subst = emptyVarEnv+ , rs_binds = \e -> e, rs_bndrs = emptyVarSet }++-- At one stage I tried to match even if there are more+-- template args than real args.++-- I now think this is probably a bad idea.+-- Should the template (map f xs) match (map g)? I think not.+-- For a start, in general eta expansion wastes work.+-- SLPJ July 99+++match :: RuleMatchEnv+ -> RuleSubst+ -> CoreExpr -- Template+ -> CoreExpr -- Target+ -> Maybe RuleSubst++-- We look through certain ticks. See note [Tick annotations in RULE matching]+match renv subst e1 (Tick t e2)+ | tickishFloatable t+ = match renv subst' e1 e2+ where subst' = subst { rs_binds = rs_binds subst . mkTick t }+match _ _ e@Tick{} _+ = pprPanic "Tick in rule" (ppr e)++-- See the notes with Unify.match, which matches types+-- Everything is very similar for terms++-- Interesting examples:+-- Consider matching+-- \x->f against \f->f+-- When we meet the lambdas we must remember to rename f to f' in the+-- second expression. The RnEnv2 does that.+--+-- Consider matching+-- forall a. \b->b against \a->3+-- We must rename the \a. Otherwise when we meet the lambdas we+-- might substitute [a/b] in the template, and then erroneously+-- succeed in matching what looks like the template variable 'a' against 3.++-- The Var case follows closely what happens in Unify.match+match renv subst (Var v1) e2 = match_var renv subst v1 e2++match renv subst e1 (Var v2) -- Note [Expanding variables]+ | not (inRnEnvR rn_env v2) -- Note [Do not expand locally-bound variables]+ , Just e2' <- expandUnfolding_maybe (rv_unf renv v2')+ = match (renv { rv_lcl = nukeRnEnvR rn_env }) subst e1 e2'+ where+ v2' = lookupRnInScope rn_env v2+ rn_env = rv_lcl renv+ -- Notice that we look up v2 in the in-scope set+ -- See Note [Lookup in-scope]+ -- No need to apply any renaming first (hence no rnOccR)+ -- because of the not-inRnEnvR++match renv subst e1 (Let bind e2)+ | -- pprTrace "match:Let" (vcat [ppr bind, ppr $ okToFloat (rv_lcl renv) (bindFreeVars bind)]) $+ not (isJoinBind bind) -- can't float join point out of argument position+ , okToFloat (rv_lcl renv) (bindFreeVars bind) -- See Note [Matching lets]+ = match (renv { rv_fltR = flt_subst' })+ (subst { rs_binds = rs_binds subst . Let bind'+ , rs_bndrs = extendVarSetList (rs_bndrs subst) new_bndrs })+ e1 e2+ where+ flt_subst = addInScopeSet (rv_fltR renv) (rs_bndrs subst)+ (flt_subst', bind') = substBind flt_subst bind+ new_bndrs = bindersOf bind'++{- Disabled: see Note [Matching cases] below+match renv (tv_subst, id_subst, binds) e1+ (Case scrut case_bndr ty [(con, alt_bndrs, rhs)])+ | exprOkForSpeculation scrut -- See Note [Matching cases]+ , okToFloat rn_env bndrs (exprFreeVars scrut)+ = match (renv { me_env = rn_env' })+ (tv_subst, id_subst, binds . case_wrap)+ e1 rhs+ where+ rn_env = me_env renv+ rn_env' = extendRnInScopeList rn_env bndrs+ bndrs = case_bndr : alt_bndrs+ case_wrap rhs' = Case scrut case_bndr ty [(con, alt_bndrs, rhs')]+-}++match _ subst (Lit lit1) (Lit lit2)+ | lit1 == lit2+ = Just subst++match renv subst (App f1 a1) (App f2 a2)+ = do { subst' <- match renv subst f1 f2+ ; match renv subst' a1 a2 }++match renv subst (Lam x1 e1) e2+ | Just (x2, e2, ts) <- exprIsLambda_maybe (rvInScopeEnv renv) e2+ = let renv' = renv { rv_lcl = rnBndr2 (rv_lcl renv) x1 x2+ , rv_fltR = delBndr (rv_fltR renv) x2 }+ subst' = subst { rs_binds = rs_binds subst . flip (foldr mkTick) ts }+ in match renv' subst' e1 e2++match renv subst (Case e1 x1 ty1 alts1) (Case e2 x2 ty2 alts2)+ = do { subst1 <- match_ty renv subst ty1 ty2+ ; subst2 <- match renv subst1 e1 e2+ ; let renv' = rnMatchBndr2 renv subst x1 x2+ ; match_alts renv' subst2 alts1 alts2 -- Alts are both sorted+ }++match renv subst (Type ty1) (Type ty2)+ = match_ty renv subst ty1 ty2+match renv subst (Coercion co1) (Coercion co2)+ = match_co renv subst co1 co2++match renv subst (Cast e1 co1) (Cast e2 co2)+ = do { subst1 <- match_co renv subst co1 co2+ ; match renv subst1 e1 e2 }++-- Everything else fails+match _ _ _e1 _e2 = -- pprTrace "Failing at" ((text "e1:" <+> ppr _e1) $$ (text "e2:" <+> ppr _e2)) $+ Nothing++-------------+match_co :: RuleMatchEnv+ -> RuleSubst+ -> Coercion+ -> Coercion+ -> Maybe RuleSubst+match_co renv subst co1 co2+ | Just cv <- getCoVar_maybe co1+ = match_var renv subst cv (Coercion co2)+ | Just (ty1, r1) <- isReflCo_maybe co1+ = do { (ty2, r2) <- isReflCo_maybe co2+ ; guard (r1 == r2)+ ; match_ty renv subst ty1 ty2 }+match_co renv subst co1 co2+ | Just (tc1, cos1) <- splitTyConAppCo_maybe co1+ = case splitTyConAppCo_maybe co2 of+ Just (tc2, cos2)+ | tc1 == tc2+ -> match_cos renv subst cos1 cos2+ _ -> Nothing+match_co renv subst co1 co2+ | Just (arg1, res1) <- splitFunCo_maybe co1+ = case splitFunCo_maybe co2 of+ Just (arg2, res2)+ -> match_cos renv subst [arg1, res1] [arg2, res2]+ _ -> Nothing+match_co _ _ _co1 _co2+ -- Currently just deals with CoVarCo, TyConAppCo and Refl+#ifdef DEBUG+ = pprTrace "match_co: needs more cases" (ppr _co1 $$ ppr _co2) Nothing+#else+ = Nothing+#endif++match_cos :: RuleMatchEnv+ -> RuleSubst+ -> [Coercion]+ -> [Coercion]+ -> Maybe RuleSubst+match_cos renv subst (co1:cos1) (co2:cos2) =+ do { subst' <- match_co renv subst co1 co2+ ; match_cos renv subst' cos1 cos2 }+match_cos _ subst [] [] = Just subst+match_cos _ _ cos1 cos2 = pprTrace "match_cos: not same length" (ppr cos1 $$ ppr cos2) Nothing++-------------+rnMatchBndr2 :: RuleMatchEnv -> RuleSubst -> Var -> Var -> RuleMatchEnv+rnMatchBndr2 renv subst x1 x2+ = renv { rv_lcl = rnBndr2 rn_env x1 x2+ , rv_fltR = delBndr (rv_fltR renv) x2 }+ where+ rn_env = addRnInScopeSet (rv_lcl renv) (rs_bndrs subst)+ -- Typically this is a no-op, but it may matter if+ -- there are some floated let-bindings++------------------------------------------+match_alts :: RuleMatchEnv+ -> RuleSubst+ -> [CoreAlt] -- Template+ -> [CoreAlt] -- Target+ -> Maybe RuleSubst+match_alts _ subst [] []+ = return subst+match_alts renv subst ((c1,vs1,r1):alts1) ((c2,vs2,r2):alts2)+ | c1 == c2+ = do { subst1 <- match renv' subst r1 r2+ ; match_alts renv subst1 alts1 alts2 }+ where+ renv' = foldl mb renv (vs1 `zip` vs2)+ mb renv (v1,v2) = rnMatchBndr2 renv subst v1 v2++match_alts _ _ _ _+ = Nothing++------------------------------------------+okToFloat :: RnEnv2 -> VarSet -> Bool+okToFloat rn_env bind_fvs+ = allVarSet not_captured bind_fvs+ where+ not_captured fv = not (inRnEnvR rn_env fv)++------------------------------------------+match_var :: RuleMatchEnv+ -> RuleSubst+ -> Var -- Template+ -> CoreExpr -- Target+ -> Maybe RuleSubst+match_var renv@(RV { rv_tmpls = tmpls, rv_lcl = rn_env, rv_fltR = flt_env })+ subst v1 e2+ | v1' `elemVarSet` tmpls+ = match_tmpl_var renv subst v1' e2++ | otherwise -- v1' is not a template variable; check for an exact match with e2+ = case e2 of -- Remember, envR of rn_env is disjoint from rv_fltR+ Var v2 | v1' == rnOccR rn_env v2+ -> Just subst++ | Var v2' <- lookupIdSubst (text "match_var") flt_env v2+ , v1' == v2'+ -> Just subst++ _ -> Nothing++ where+ v1' = rnOccL rn_env v1+ -- If the template is+ -- forall x. f x (\x -> x) = ...+ -- Then the x inside the lambda isn't the+ -- template x, so we must rename first!++------------------------------------------+match_tmpl_var :: RuleMatchEnv+ -> RuleSubst+ -> Var -- Template+ -> CoreExpr -- Target+ -> Maybe RuleSubst++match_tmpl_var renv@(RV { rv_lcl = rn_env, rv_fltR = flt_env })+ subst@(RS { rs_id_subst = id_subst, rs_bndrs = let_bndrs })+ v1' e2+ | any (inRnEnvR rn_env) (exprFreeVarsList e2)+ = Nothing -- Occurs check failure+ -- e.g. match forall a. (\x-> a x) against (\y. y y)++ | Just e1' <- lookupVarEnv id_subst v1'+ = if eqExpr (rnInScopeSet rn_env) e1' e2'+ then Just subst+ else Nothing++ | otherwise+ = -- Note [Matching variable types]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- However, we must match the *types*; e.g.+ -- forall (c::Char->Int) (x::Char).+ -- f (c x) = "RULE FIRED"+ -- We must only match on args that have the right type+ -- It's actually quite difficult to come up with an example that shows+ -- you need type matching, esp since matching is left-to-right, so type+ -- args get matched first. But it's possible (e.g. simplrun008) and+ -- this is the Right Thing to do+ do { subst' <- match_ty renv subst (idType v1') (exprType e2)+ ; return (subst' { rs_id_subst = id_subst' }) }+ where+ -- e2' is the result of applying flt_env to e2+ e2' | isEmptyVarSet let_bndrs = e2+ | otherwise = substExpr (text "match_tmpl_var") flt_env e2++ id_subst' = extendVarEnv (rs_id_subst subst) v1' e2'+ -- No further renaming to do on e2',+ -- because no free var of e2' is in the rnEnvR of the envt++------------------------------------------+match_ty :: RuleMatchEnv+ -> RuleSubst+ -> Type -- Template+ -> Type -- Target+ -> Maybe RuleSubst+-- Matching Core types: use the matcher in TcType.+-- Notice that we treat newtypes as opaque. For example, suppose+-- we have a specialised version of a function at a newtype, say+-- newtype T = MkT Int+-- We only want to replace (f T) with f', not (f Int).++match_ty renv subst ty1 ty2+ = do { tv_subst'+ <- Unify.ruleMatchTyKiX (rv_tmpls renv) (rv_lcl renv) tv_subst ty1 ty2+ ; return (subst { rs_tv_subst = tv_subst' }) }+ where+ tv_subst = rs_tv_subst subst++{-+Note [Expanding variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is another Very Important rule: if the term being matched is a+variable, we expand it so long as its unfolding is "expandable". (Its+occurrence information is not necessarily up to date, so we don't use+it.) By "expandable" we mean a WHNF or a "constructor-like" application.+This is the key reason for "constructor-like" Ids. If we have+ {-# NOINLINE [1] CONLIKE g #-}+ {-# RULE f (g x) = h x #-}+then in the term+ let v = g 3 in ....(f v)....+we want to make the rule fire, to replace (f v) with (h 3).++Note [Do not expand locally-bound variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Do *not* expand locally-bound variables, else there's a worry that the+unfolding might mention variables that are themselves renamed.+Example+ case x of y { (p,q) -> ...y... }+Don't expand 'y' to (p,q) because p,q might themselves have been+renamed. Essentially we only expand unfoldings that are "outside"+the entire match.++Hence, (a) the guard (not (isLocallyBoundR v2))+ (b) when we expand we nuke the renaming envt (nukeRnEnvR).++Note [Tick annotations in RULE matching]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We used to unconditionally look through Notes in both template and+expression being matched. This is actually illegal for counting or+cost-centre-scoped ticks, because we have no place to put them without+changing entry counts and/or costs. So now we just fail the match in+these cases.++On the other hand, where we are allowed to insert new cost into the+tick scope, we can float them upwards to the rule application site.++cf Note [Notes in call patterns] in SpecConstr++Note [Matching lets]+~~~~~~~~~~~~~~~~~~~~+Matching a let-expression. Consider+ RULE forall x. f (g x) = <rhs>+and target expression+ f (let { w=R } in g E))+Then we'd like the rule to match, to generate+ let { w=R } in (\x. <rhs>) E+In effect, we want to float the let-binding outward, to enable+the match to happen. This is the WHOLE REASON for accumulating+bindings in the RuleSubst++We can only do this if the free variables of R are not bound by the+part of the target expression outside the let binding; e.g.+ f (\v. let w = v+1 in g E)+Here we obviously cannot float the let-binding for w. Hence the+use of okToFloat.++There are a couple of tricky points.+ (a) What if floating the binding captures a variable?+ f (let v = x+1 in v) v+ --> NOT!+ let v = x+1 in f (x+1) v++ (b) What if two non-nested let bindings bind the same variable?+ f (let v = e1 in b1) (let v = e2 in b2)+ --> NOT!+ let v = e1 in let v = e2 in (f b2 b2)+ See testsuite test "RuleFloatLet".++Our cunning plan is this:+ * Along with the growing substitution for template variables+ we maintain a growing set of floated let-bindings (rs_binds)+ plus the set of variables thus bound.++ * The RnEnv2 in the MatchEnv binds only the local binders+ in the term (lambdas, case)++ * When we encounter a let in the term to be matched, we+ check that does not mention any locally bound (lambda, case)+ variables. If so we fail++ * We use CoreSubst.substBind to freshen the binding, using an+ in-scope set that is the original in-scope variables plus the+ rs_bndrs (currently floated let-bindings). So in (a) above+ we'll freshen the 'v' binding; in (b) above we'll freshen+ the *second* 'v' binding.++ * We apply that freshening substitution, in a lexically-scoped+ way to the term, although lazily; this is the rv_fltR field.+++Note [Matching cases]+~~~~~~~~~~~~~~~~~~~~~+{- NOTE: This idea is currently disabled. It really only works if+ the primops involved are OkForSpeculation, and, since+ they have side effects readIntOfAddr and touch are not.+ Maybe we'll get back to this later . -}++Consider+ f (case readIntOffAddr# p# i# realWorld# of { (# s#, n# #) ->+ case touch# fp s# of { _ ->+ I# n# } } )+This happened in a tight loop generated by stream fusion that+Roman encountered. We'd like to treat this just like the let+case, because the primops concerned are ok-for-speculation.+That is, we'd like to behave as if it had been+ case readIntOffAddr# p# i# realWorld# of { (# s#, n# #) ->+ case touch# fp s# of { _ ->+ f (I# n# } } )++Note [Lookup in-scope]+~~~~~~~~~~~~~~~~~~~~~~+Consider this example+ foo :: Int -> Maybe Int -> Int+ foo 0 (Just n) = n+ foo m (Just n) = foo (m-n) (Just n)++SpecConstr sees this fragment:++ case w_smT of wild_Xf [Just A] {+ Data.Maybe.Nothing -> lvl_smf;+ Data.Maybe.Just n_acT [Just S(L)] ->+ case n_acT of wild1_ams [Just A] { GHC.Base.I# y_amr [Just L] ->+ \$wfoo_smW (GHC.Prim.-# ds_Xmb y_amr) wild_Xf+ }};++and correctly generates the rule++ RULES: "SC:$wfoo1" [0] __forall {y_amr [Just L] :: GHC.Prim.Int#+ sc_snn :: GHC.Prim.Int#}+ \$wfoo_smW sc_snn (Data.Maybe.Just @ GHC.Base.Int (GHC.Base.I# y_amr))+ = \$s\$wfoo_sno y_amr sc_snn ;]++BUT we must ensure that this rule matches in the original function!+Note that the call to \$wfoo is+ \$wfoo_smW (GHC.Prim.-# ds_Xmb y_amr) wild_Xf++During matching we expand wild_Xf to (Just n_acT). But then we must also+expand n_acT to (I# y_amr). And we can only do that if we look up n_acT+in the in-scope set, because in wild_Xf's unfolding it won't have an unfolding+at all.++That is why the 'lookupRnInScope' call in the (Var v2) case of 'match'+is so important.+++************************************************************************+* *+ Rule-check the program+* *+************************************************************************++ We want to know what sites have rules that could have fired but didn't.+ This pass runs over the tree (without changing it) and reports such.+-}++-- | Report partial matches for rules beginning with the specified+-- string for the purposes of error reporting+ruleCheckProgram :: CompilerPhase -- ^ Rule activation test+ -> String -- ^ Rule pattern+ -> RuleEnv -- ^ Database of rules+ -> CoreProgram -- ^ Bindings to check in+ -> SDoc -- ^ Resulting check message+ruleCheckProgram phase rule_pat rule_base binds+ | isEmptyBag results+ = text "Rule check results: no rule application sites"+ | otherwise+ = vcat [text "Rule check results:",+ line,+ vcat [ p $$ line | p <- bagToList results ]+ ]+ where+ env = RuleCheckEnv { rc_is_active = isActive phase+ , rc_id_unf = idUnfolding -- Not quite right+ -- Should use activeUnfolding+ , rc_pattern = rule_pat+ , rc_rule_base = rule_base }+ results = unionManyBags (map (ruleCheckBind env) binds)+ line = text (replicate 20 '-')++data RuleCheckEnv = RuleCheckEnv {+ rc_is_active :: Activation -> Bool,+ rc_id_unf :: IdUnfoldingFun,+ rc_pattern :: String,+ rc_rule_base :: RuleEnv+}++ruleCheckBind :: RuleCheckEnv -> CoreBind -> Bag SDoc+ -- The Bag returned has one SDoc for each call site found+ruleCheckBind env (NonRec _ r) = ruleCheck env r+ruleCheckBind env (Rec prs) = unionManyBags [ruleCheck env r | (_,r) <- prs]++ruleCheck :: RuleCheckEnv -> CoreExpr -> Bag SDoc+ruleCheck _ (Var _) = emptyBag+ruleCheck _ (Lit _) = emptyBag+ruleCheck _ (Type _) = emptyBag+ruleCheck _ (Coercion _) = emptyBag+ruleCheck env (App f a) = ruleCheckApp env (App f a) []+ruleCheck env (Tick _ e) = ruleCheck env e+ruleCheck env (Cast e _) = ruleCheck env e+ruleCheck env (Let bd e) = ruleCheckBind env bd `unionBags` ruleCheck env e+ruleCheck env (Lam _ e) = ruleCheck env e+ruleCheck env (Case e _ _ as) = ruleCheck env e `unionBags`+ unionManyBags [ruleCheck env r | (_,_,r) <- as]++ruleCheckApp :: RuleCheckEnv -> Expr CoreBndr -> [Arg CoreBndr] -> Bag SDoc+ruleCheckApp env (App f a) as = ruleCheck env a `unionBags` ruleCheckApp env f (a:as)+ruleCheckApp env (Var f) as = ruleCheckFun env f as+ruleCheckApp env other _ = ruleCheck env other++ruleCheckFun :: RuleCheckEnv -> Id -> [CoreExpr] -> Bag SDoc+-- Produce a report for all rules matching the predicate+-- saying why it doesn't match the specified application++ruleCheckFun env fn args+ | null name_match_rules = emptyBag+ | otherwise = unitBag (ruleAppCheck_help env fn args name_match_rules)+ where+ name_match_rules = filter match (getRules (rc_rule_base env) fn)+ match rule = (rc_pattern env) `isPrefixOf` unpackFS (ruleName rule)++ruleAppCheck_help :: RuleCheckEnv -> Id -> [CoreExpr] -> [CoreRule] -> SDoc+ruleAppCheck_help env fn args rules+ = -- The rules match the pattern, so we want to print something+ vcat [text "Expression:" <+> ppr (mkApps (Var fn) args),+ vcat (map check_rule rules)]+ where+ n_args = length args+ i_args = args `zip` [1::Int ..]+ rough_args = map roughTopName args++ check_rule rule = sdocWithDynFlags $ \dflags ->+ rule_herald rule <> colon <+> rule_info dflags rule++ rule_herald (BuiltinRule { ru_name = name })+ = text "Builtin rule" <+> doubleQuotes (ftext name)+ rule_herald (Rule { ru_name = name })+ = text "Rule" <+> doubleQuotes (ftext name)++ rule_info dflags rule+ | Just _ <- matchRule dflags (emptyInScopeSet, rc_id_unf env)+ noBlackList fn args rough_args rule+ = text "matches (which is very peculiar!)"++ rule_info _ (BuiltinRule {}) = text "does not match"++ rule_info _ (Rule { ru_act = act,+ ru_bndrs = rule_bndrs, ru_args = rule_args})+ | not (rc_is_active env act) = text "active only in later phase"+ | n_args < n_rule_args = text "too few arguments"+ | n_mismatches == n_rule_args = text "no arguments match"+ | n_mismatches == 0 = text "all arguments match (considered individually), but rule as a whole does not"+ | otherwise = text "arguments" <+> ppr mismatches <+> text "do not match (1-indexing)"+ where+ n_rule_args = length rule_args+ n_mismatches = length mismatches+ mismatches = [i | (rule_arg, (arg,i)) <- rule_args `zip` i_args,+ not (isJust (match_fn rule_arg arg))]++ lhs_fvs = exprsFreeVars rule_args -- Includes template tyvars+ match_fn rule_arg arg = match renv emptyRuleSubst rule_arg arg+ where+ in_scope = mkInScopeSet (lhs_fvs `unionVarSet` exprFreeVars arg)+ renv = RV { rv_lcl = mkRnEnv2 in_scope+ , rv_tmpls = mkVarSet rule_bndrs+ , rv_fltR = mkEmptySubst in_scope+ , rv_unf = rc_id_unf env }
+ specialise/SpecConstr.hs view
@@ -0,0 +1,2256 @@+{-+ToDo [Oct 2013]+~~~~~~~~~~~~~~~+1. Nuke ForceSpecConstr for good (it is subsumed by GHC.Types.SPEC in ghc-prim)+2. Nuke NoSpecConstr+++(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[SpecConstr]{Specialise over constructors}+-}++{-# LANGUAGE CPP #-}++module SpecConstr(+ specConstrProgram,+ SpecConstrAnnotation(..)+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreSubst+import CoreUtils+import CoreUnfold ( couldBeSmallEnoughToInline )+import CoreFVs ( exprsFreeVarsList )+import CoreMonad+import Literal ( litIsLifted )+import HscTypes ( ModGuts(..) )+import WwLib ( isWorkerSmallEnough, mkWorkerArgs )+import DataCon+import Coercion hiding( substCo )+import Rules+import Type hiding ( substTy )+import TyCon ( tyConName )+import Id+import PprCore ( pprParendExpr )+import MkCore ( mkImpossibleExpr )+import Var+import VarEnv+import VarSet+import Name+import BasicTypes+import DynFlags ( DynFlags(..), GeneralFlag( Opt_SpecConstrKeen )+ , gopt, hasPprDebug )+import Maybes ( orElse, catMaybes, isJust, isNothing )+import Demand+import GHC.Serialized ( deserializeWithData )+import Util+import Pair+import UniqSupply+import Outputable+import FastString+import UniqFM+import MonadUtils+import Control.Monad ( zipWithM )+import Data.List+import PrelNames ( specTyConName )+import Module++-- See Note [Forcing specialisation]++import TyCon ( TyCon )+import GHC.Exts( SpecConstrAnnotation(..) )+import Data.Ord( comparing )++{-+-----------------------------------------------------+ Game plan+-----------------------------------------------------++Consider+ drop n [] = []+ drop 0 xs = []+ drop n (x:xs) = drop (n-1) xs++After the first time round, we could pass n unboxed. This happens in+numerical code too. Here's what it looks like in Core:++ drop n xs = case xs of+ [] -> []+ (y:ys) -> case n of+ I# n# -> case n# of+ 0 -> []+ _ -> drop (I# (n# -# 1#)) xs++Notice that the recursive call has an explicit constructor as argument.+Noticing this, we can make a specialised version of drop++ RULE: drop (I# n#) xs ==> drop' n# xs++ drop' n# xs = let n = I# n# in ...orig RHS...++Now the simplifier will apply the specialisation in the rhs of drop', giving++ drop' n# xs = case xs of+ [] -> []+ (y:ys) -> case n# of+ 0 -> []+ _ -> drop' (n# -# 1#) xs++Much better!++We'd also like to catch cases where a parameter is carried along unchanged,+but evaluated each time round the loop:++ f i n = if i>0 || i>n then i else f (i*2) n++Here f isn't strict in n, but we'd like to avoid evaluating it each iteration.+In Core, by the time we've w/wd (f is strict in i) we get++ f i# n = case i# ># 0 of+ False -> I# i#+ True -> case n of { I# n# ->+ case i# ># n# of+ False -> I# i#+ True -> f (i# *# 2#) n++At the call to f, we see that the argument, n is known to be (I# n#),+and n is evaluated elsewhere in the body of f, so we can play the same+trick as above.+++Note [Reboxing]+~~~~~~~~~~~~~~~+We must be careful not to allocate the same constructor twice. Consider+ f p = (...(case p of (a,b) -> e)...p...,+ ...let t = (r,s) in ...t...(f t)...)+At the recursive call to f, we can see that t is a pair. But we do NOT want+to make a specialised copy:+ f' a b = let p = (a,b) in (..., ...)+because now t is allocated by the caller, then r and s are passed to the+recursive call, which allocates the (r,s) pair again.++This happens if+ (a) the argument p is used in other than a case-scrutinisation way.+ (b) the argument to the call is not a 'fresh' tuple; you have to+ look into its unfolding to see that it's a tuple++Hence the "OR" part of Note [Good arguments] below.++ALTERNATIVE 2: pass both boxed and unboxed versions. This no longer saves+allocation, but does perhaps save evals. In the RULE we'd have+something like++ f (I# x#) = f' (I# x#) x#++If at the call site the (I# x) was an unfolding, then we'd have to+rely on CSE to eliminate the duplicate allocation.... This alternative+doesn't look attractive enough to pursue.++ALTERNATIVE 3: ignore the reboxing problem. The trouble is that+the conservative reboxing story prevents many useful functions from being+specialised. Example:+ foo :: Maybe Int -> Int -> Int+ foo (Just m) 0 = 0+ foo x@(Just m) n = foo x (n-m)+Here the use of 'x' will clearly not require boxing in the specialised function.++The strictness analyser has the same problem, in fact. Example:+ f p@(a,b) = ...+If we pass just 'a' and 'b' to the worker, it might need to rebox the+pair to create (a,b). A more sophisticated analysis might figure out+precisely the cases in which this could happen, but the strictness+analyser does no such analysis; it just passes 'a' and 'b', and hopes+for the best.++So my current choice is to make SpecConstr similarly aggressive, and+ignore the bad potential of reboxing.+++Note [Good arguments]+~~~~~~~~~~~~~~~~~~~~~+So we look for++* A self-recursive function. Ignore mutual recursion for now,+ because it's less common, and the code is simpler for self-recursion.++* EITHER++ a) At a recursive call, one or more parameters is an explicit+ constructor application+ AND+ That same parameter is scrutinised by a case somewhere in+ the RHS of the function++ OR++ b) At a recursive call, one or more parameters has an unfolding+ that is an explicit constructor application+ AND+ That same parameter is scrutinised by a case somewhere in+ the RHS of the function+ AND+ Those are the only uses of the parameter (see Note [Reboxing])+++What to abstract over+~~~~~~~~~~~~~~~~~~~~~+There's a bit of a complication with type arguments. If the call+site looks like++ f p = ...f ((:) [a] x xs)...++then our specialised function look like++ f_spec x xs = let p = (:) [a] x xs in ....as before....++This only makes sense if either+ a) the type variable 'a' is in scope at the top of f, or+ b) the type variable 'a' is an argument to f (and hence fs)++Actually, (a) may hold for value arguments too, in which case+we may not want to pass them. Suppose 'x' is in scope at f's+defn, but xs is not. Then we'd like++ f_spec xs = let p = (:) [a] x xs in ....as before....++Similarly (b) may hold too. If x is already an argument at the+call, no need to pass it again.++Finally, if 'a' is not in scope at the call site, we could abstract+it as we do the term variables:++ f_spec a x xs = let p = (:) [a] x xs in ...as before...++So the grand plan is:++ * abstract the call site to a constructor-only pattern+ e.g. C x (D (f p) (g q)) ==> C s1 (D s2 s3)++ * Find the free variables of the abstracted pattern++ * Pass these variables, less any that are in scope at+ the fn defn. But see Note [Shadowing] below.+++NOTICE that we only abstract over variables that are not in scope,+so we're in no danger of shadowing variables used in "higher up"+in f_spec's RHS.+++Note [Shadowing]+~~~~~~~~~~~~~~~~+In this pass we gather up usage information that may mention variables+that are bound between the usage site and the definition site; or (more+seriously) may be bound to something different at the definition site.+For example:++ f x = letrec g y v = let x = ...+ in ...(g (a,b) x)...++Since 'x' is in scope at the call site, we may make a rewrite rule that+looks like+ RULE forall a,b. g (a,b) x = ...+But this rule will never match, because it's really a different 'x' at+the call site -- and that difference will be manifest by the time the+simplifier gets to it. [A worry: the simplifier doesn't *guarantee*+no-shadowing, so perhaps it may not be distinct?]++Anyway, the rule isn't actually wrong, it's just not useful. One possibility+is to run deShadowBinds before running SpecConstr, but instead we run the+simplifier. That gives the simplest possible program for SpecConstr to+chew on; and it virtually guarantees no shadowing.++Note [Specialising for constant parameters]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This one is about specialising on a *constant* (but not necessarily+constructor) argument++ foo :: Int -> (Int -> Int) -> Int+ foo 0 f = 0+ foo m f = foo (f m) (+1)++It produces++ lvl_rmV :: GHC.Base.Int -> GHC.Base.Int+ lvl_rmV =+ \ (ds_dlk :: GHC.Base.Int) ->+ case ds_dlk of wild_alH { GHC.Base.I# x_alG ->+ GHC.Base.I# (GHC.Prim.+# x_alG 1)++ T.$wfoo :: GHC.Prim.Int# -> (GHC.Base.Int -> GHC.Base.Int) ->+ GHC.Prim.Int#+ T.$wfoo =+ \ (ww_sme :: GHC.Prim.Int#) (w_smg :: GHC.Base.Int -> GHC.Base.Int) ->+ case ww_sme of ds_Xlw {+ __DEFAULT ->+ case w_smg (GHC.Base.I# ds_Xlw) of w1_Xmo { GHC.Base.I# ww1_Xmz ->+ T.$wfoo ww1_Xmz lvl_rmV+ };+ 0 -> 0+ }++The recursive call has lvl_rmV as its argument, so we could create a specialised copy+with that argument baked in; that is, not passed at all. Now it can perhaps be inlined.++When is this worth it? Call the constant 'lvl'+- If 'lvl' has an unfolding that is a constructor, see if the corresponding+ parameter is scrutinised anywhere in the body.++- If 'lvl' has an unfolding that is a inlinable function, see if the corresponding+ parameter is applied (...to enough arguments...?)++ Also do this is if the function has RULES?++Also++Note [Specialising for lambda parameters]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ foo :: Int -> (Int -> Int) -> Int+ foo 0 f = 0+ foo m f = foo (f m) (\n -> n-m)++This is subtly different from the previous one in that we get an+explicit lambda as the argument:++ T.$wfoo :: GHC.Prim.Int# -> (GHC.Base.Int -> GHC.Base.Int) ->+ GHC.Prim.Int#+ T.$wfoo =+ \ (ww_sm8 :: GHC.Prim.Int#) (w_sma :: GHC.Base.Int -> GHC.Base.Int) ->+ case ww_sm8 of ds_Xlr {+ __DEFAULT ->+ case w_sma (GHC.Base.I# ds_Xlr) of w1_Xmf { GHC.Base.I# ww1_Xmq ->+ T.$wfoo+ ww1_Xmq+ (\ (n_ad3 :: GHC.Base.Int) ->+ case n_ad3 of wild_alB { GHC.Base.I# x_alA ->+ GHC.Base.I# (GHC.Prim.-# x_alA ds_Xlr)+ })+ };+ 0 -> 0+ }++I wonder if SpecConstr couldn't be extended to handle this? After all,+lambda is a sort of constructor for functions and perhaps it already+has most of the necessary machinery?++Furthermore, there's an immediate win, because you don't need to allocate the lambda+at the call site; and if perchance it's called in the recursive call, then you+may avoid allocating it altogether. Just like for constructors.++Looks cool, but probably rare...but it might be easy to implement.+++Note [SpecConstr for casts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data family T a :: *+ data instance T Int = T Int++ foo n = ...+ where+ go (T 0) = 0+ go (T n) = go (T (n-1))++The recursive call ends up looking like+ go (T (I# ...) `cast` g)+So we want to spot the constructor application inside the cast.+That's why we have the Cast case in argToPat++Note [Local recursive groups]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For a *local* recursive group, we can see all the calls to the+function, so we seed the specialisation loop from the calls in the+body, not from the calls in the RHS. Consider:++ bar m n = foo n (n,n) (n,n) (n,n) (n,n)+ where+ foo n p q r s+ | n == 0 = m+ | n > 3000 = case p of { (p1,p2) -> foo (n-1) (p2,p1) q r s }+ | n > 2000 = case q of { (q1,q2) -> foo (n-1) p (q2,q1) r s }+ | n > 1000 = case r of { (r1,r2) -> foo (n-1) p q (r2,r1) s }+ | otherwise = case s of { (s1,s2) -> foo (n-1) p q r (s2,s1) }++If we start with the RHSs of 'foo', we get lots and lots of specialisations,+most of which are not needed. But if we start with the (single) call+in the rhs of 'bar' we get exactly one fully-specialised copy, and all+the recursive calls go to this fully-specialised copy. Indeed, the original+function is later collected as dead code. This is very important in+specialising the loops arising from stream fusion, for example in NDP where+we were getting literally hundreds of (mostly unused) specialisations of+a local function.++In a case like the above we end up never calling the original un-specialised+function. (Although we still leave its code around just in case.)++However, if we find any boring calls in the body, including *unsaturated*+ones, such as+ letrec foo x y = ....foo...+ in map foo xs+then we will end up calling the un-specialised function, so then we *should*+use the calls in the un-specialised RHS as seeds. We call these+"boring call patterns", and callsToPats reports if it finds any of these.++Note [Seeding top-level recursive groups]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This seeding is done in the binding for seed_calls in specRec.++1. If all the bindings in a top-level recursive group are local (not+ exported), then all the calls are in the rest of the top-level+ bindings. This means we can specialise with those call patterns+ ONLY, and NOT with the RHSs of the recursive group (exactly like+ Note [Local recursive groups])++2. But if any of the bindings are exported, the function may be called+ with any old arguments, so (for lack of anything better) we specialise+ based on+ (a) the call patterns in the RHS+ (b) the call patterns in the rest of the top-level bindings+ NB: before Apr 15 we used (a) only, but Dimitrios had an example+ where (b) was crucial, so I added that.+ Adding (b) also improved nofib allocation results:+ multiplier: 4% better+ minimax: 2.8% better++Actually in case (2), instead of using the calls from the RHS, it+would be better to specialise in the importing module. We'd need to+add an INLINABLE pragma to the function, and then it can be+specialised in the importing scope, just as is done for type classes+in Specialise.specImports. This remains to be done (#10346).++Note [Top-level recursive groups]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To get the call usage information from "the rest of the top level+bindings" (c.f. Note [Seeding top-level recursive groups]), we work+backwards through the top-level bindings so we see the usage before we+get to the binding of the function. Before we can collect the usage+though, we go through all the bindings and add them to the+environment. This is necessary because usage is only tracked for+functions in the environment. These two passes are called+ 'go' and 'goEnv'+in specConstrProgram. (Looks a bit revolting to me.)++Note [Do not specialise diverging functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Specialising a function that just diverges is a waste of code.+Furthermore, it broke GHC (simpl014) thus:+ {-# STR Sb #-}+ f = \x. case x of (a,b) -> f x+If we specialise f we get+ f = \x. case x of (a,b) -> fspec a b+But fspec doesn't have decent strictness info. As it happened,+(f x) :: IO t, so the state hack applied and we eta expanded fspec,+and hence f. But now f's strictness is less than its arity, which+breaks an invariant.+++Note [Forcing specialisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+With stream fusion and in other similar cases, we want to fully+specialise some (but not necessarily all!) loops regardless of their+size and the number of specialisations.++We allow a library to do this, in one of two ways (one which is+deprecated):++ 1) Add a parameter of type GHC.Types.SPEC (from ghc-prim) to the loop body.++ 2) (Deprecated) Annotate a type with ForceSpecConstr from GHC.Exts,+ and then add *that* type as a parameter to the loop body++The reason #2 is deprecated is because it requires GHCi, which isn't+available for things like a cross compiler using stage1.++Here's a (simplified) example from the `vector` package. You may bring+the special 'force specialization' type into scope by saying:++ import GHC.Types (SPEC(..))++or by defining your own type (again, deprecated):++ data SPEC = SPEC | SPEC2+ {-# ANN type SPEC ForceSpecConstr #-}++(Note this is the exact same definition of GHC.Types.SPEC, just+without the annotation.)++After that, you say:++ foldl :: (a -> b -> a) -> a -> Stream b -> a+ {-# INLINE foldl #-}+ foldl f z (Stream step s _) = foldl_loop SPEC z s+ where+ foldl_loop !sPEC z s = case step s of+ Yield x s' -> foldl_loop sPEC (f z x) s'+ Skip -> foldl_loop sPEC z s'+ Done -> z++SpecConstr will spot the SPEC parameter and always fully specialise+foldl_loop. Note that++ * We have to prevent the SPEC argument from being removed by+ w/w which is why (a) SPEC is a sum type, and (b) we have to seq on+ the SPEC argument.++ * And lastly, the SPEC argument is ultimately eliminated by+ SpecConstr itself so there is no runtime overhead.++This is all quite ugly; we ought to come up with a better design.++ForceSpecConstr arguments are spotted in scExpr' and scTopBinds which then set+sc_force to True when calling specLoop. This flag does four things:+ * Ignore specConstrThreshold, to specialise functions of arbitrary size+ (see scTopBind)+ * Ignore specConstrCount, to make arbitrary numbers of specialisations+ (see specialise)+ * Specialise even for arguments that are not scrutinised in the loop+ (see argToPat; Trac #4488)+ * Only specialise on recursive types a finite number of times+ (see is_too_recursive; Trac #5550; Note [Limit recursive specialisation])++This flag is inherited for nested non-recursive bindings (which are likely to+be join points and hence should be fully specialised) but reset for nested+recursive bindings.++What alternatives did I consider? Annotating the loop itself doesn't+work because (a) it is local and (b) it will be w/w'ed and having+w/w propagating annotations somehow doesn't seem like a good idea. The+types of the loop arguments really seem to be the most persistent+thing.++Annotating the types that make up the loop state doesn't work,+either, because (a) it would prevent us from using types like Either+or tuples here, (b) we don't want to restrict the set of types that+can be used in Stream states and (c) some types are fixed by the user+(e.g., the accumulator here) but we still want to specialise as much+as possible.++Alternatives to ForceSpecConstr+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Instead of giving the loop an extra argument of type SPEC, we+also considered *wrapping* arguments in SPEC, thus+ data SPEC a = SPEC a | SPEC2++ loop = \arg -> case arg of+ SPEC state ->+ case state of (x,y) -> ... loop (SPEC (x',y')) ...+ S2 -> error ...+The idea is that a SPEC argument says "specialise this argument+regardless of whether the function case-analyses it". But this+doesn't work well:+ * SPEC must still be a sum type, else the strictness analyser+ eliminates it+ * But that means that 'loop' won't be strict in its real payload+This loss of strictness in turn screws up specialisation, because+we may end up with calls like+ loop (SPEC (case z of (p,q) -> (q,p)))+Without the SPEC, if 'loop' were strict, the case would move out+and we'd see loop applied to a pair. But if 'loop' isn't strict+this doesn't look like a specialisable call.++Note [Limit recursive specialisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It is possible for ForceSpecConstr to cause an infinite loop of specialisation.+Because there is no limit on the number of specialisations, a recursive call with+a recursive constructor as an argument (for example, list cons) will generate+a specialisation for that constructor. If the resulting specialisation also+contains a recursive call with the constructor, this could proceed indefinitely.++For example, if ForceSpecConstr is on:+ loop :: [Int] -> [Int] -> [Int]+ loop z [] = z+ loop z (x:xs) = loop (x:z) xs+this example will create a specialisation for the pattern+ loop (a:b) c = loop' a b c++ loop' a b [] = (a:b)+ loop' a b (x:xs) = loop (x:(a:b)) xs+and a new pattern is found:+ loop (a:(b:c)) d = loop'' a b c d+which can continue indefinitely.++Roman's suggestion to fix this was to stop after a couple of times on recursive types,+but still specialising on non-recursive types as much as possible.++To implement this, we count the number of times we have gone round the+"specialise recursively" loop ('go' in 'specRec'). Once have gone round+more than N times (controlled by -fspec-constr-recursive=N) we check++ - If sc_force is off, and sc_count is (Just max) then we don't+ need to do anything: trim_pats will limit the number of specs++ - Otherwise check if any function has now got more than (sc_count env)+ specialisations. If sc_count is "no limit" then we arbitrarily+ choose 10 as the limit (ugh).++See Trac #5550. Also Trac #13623, where this test had become over-agressive,+and we lost a wonderful specialisation that we really wanted!++Note [NoSpecConstr]+~~~~~~~~~~~~~~~~~~~+The ignoreDataCon stuff allows you to say+ {-# ANN type T NoSpecConstr #-}+to mean "don't specialise on arguments of this type". It was added+before we had ForceSpecConstr. Lacking ForceSpecConstr we specialised+regardless of size; and then we needed a way to turn that *off*. Now+that we have ForceSpecConstr, this NoSpecConstr is probably redundant.+(Used only for PArray.)++-----------------------------------------------------+ Stuff not yet handled+-----------------------------------------------------++Here are notes arising from Roman's work that I don't want to lose.++Example 1+~~~~~~~~~+ data T a = T !a++ foo :: Int -> T Int -> Int+ foo 0 t = 0+ foo x t | even x = case t of { T n -> foo (x-n) t }+ | otherwise = foo (x-1) t++SpecConstr does no specialisation, because the second recursive call+looks like a boxed use of the argument. A pity.++ $wfoo_sFw :: GHC.Prim.Int# -> T.T GHC.Base.Int -> GHC.Prim.Int#+ $wfoo_sFw =+ \ (ww_sFo [Just L] :: GHC.Prim.Int#) (w_sFq [Just L] :: T.T GHC.Base.Int) ->+ case ww_sFo of ds_Xw6 [Just L] {+ __DEFAULT ->+ case GHC.Prim.remInt# ds_Xw6 2 of wild1_aEF [Dead Just A] {+ __DEFAULT -> $wfoo_sFw (GHC.Prim.-# ds_Xw6 1) w_sFq;+ 0 ->+ case w_sFq of wild_Xy [Just L] { T.T n_ad5 [Just U(L)] ->+ case n_ad5 of wild1_aET [Just A] { GHC.Base.I# y_aES [Just L] ->+ $wfoo_sFw (GHC.Prim.-# ds_Xw6 y_aES) wild_Xy+ } } };+ 0 -> 0++Example 2+~~~~~~~~~+ data a :*: b = !a :*: !b+ data T a = T !a++ foo :: (Int :*: T Int) -> Int+ foo (0 :*: t) = 0+ foo (x :*: t) | even x = case t of { T n -> foo ((x-n) :*: t) }+ | otherwise = foo ((x-1) :*: t)++Very similar to the previous one, except that the parameters are now in+a strict tuple. Before SpecConstr, we have++ $wfoo_sG3 :: GHC.Prim.Int# -> T.T GHC.Base.Int -> GHC.Prim.Int#+ $wfoo_sG3 =+ \ (ww_sFU [Just L] :: GHC.Prim.Int#) (ww_sFW [Just L] :: T.T+ GHC.Base.Int) ->+ case ww_sFU of ds_Xws [Just L] {+ __DEFAULT ->+ case GHC.Prim.remInt# ds_Xws 2 of wild1_aEZ [Dead Just A] {+ __DEFAULT ->+ case ww_sFW of tpl_B2 [Just L] { T.T a_sFo [Just A] ->+ $wfoo_sG3 (GHC.Prim.-# ds_Xws 1) tpl_B2 -- $wfoo1+ };+ 0 ->+ case ww_sFW of wild_XB [Just A] { T.T n_ad7 [Just S(L)] ->+ case n_ad7 of wild1_aFd [Just L] { GHC.Base.I# y_aFc [Just L] ->+ $wfoo_sG3 (GHC.Prim.-# ds_Xws y_aFc) wild_XB -- $wfoo2+ } } };+ 0 -> 0 }++We get two specialisations:+"SC:$wfoo1" [0] __forall {a_sFB :: GHC.Base.Int sc_sGC :: GHC.Prim.Int#}+ Foo.$wfoo sc_sGC (Foo.T @ GHC.Base.Int a_sFB)+ = Foo.$s$wfoo1 a_sFB sc_sGC ;+"SC:$wfoo2" [0] __forall {y_aFp :: GHC.Prim.Int# sc_sGC :: GHC.Prim.Int#}+ Foo.$wfoo sc_sGC (Foo.T @ GHC.Base.Int (GHC.Base.I# y_aFp))+ = Foo.$s$wfoo y_aFp sc_sGC ;++But perhaps the first one isn't good. After all, we know that tpl_B2 is+a T (I# x) really, because T is strict and Int has one constructor. (We can't+unbox the strict fields, because T is polymorphic!)++************************************************************************+* *+\subsection{Top level wrapper stuff}+* *+************************************************************************+-}++specConstrProgram :: ModGuts -> CoreM ModGuts+specConstrProgram guts+ = do+ dflags <- getDynFlags+ us <- getUniqueSupplyM+ annos <- getFirstAnnotations deserializeWithData guts+ this_mod <- getModule+ let binds' = reverse $ fst $ initUs us $ do+ -- Note [Top-level recursive groups]+ (env, binds) <- goEnv (initScEnv dflags this_mod annos)+ (mg_binds guts)+ -- binds is identical to (mg_binds guts), except that the+ -- binders on the LHS have been replaced by extendBndr+ -- (SPJ this seems like overkill; I don't think the binders+ -- will change at all; and we don't substitute in the RHSs anyway!!)+ go env nullUsage (reverse binds)++ return (guts { mg_binds = binds' })+ where+ -- See Note [Top-level recursive groups]+ goEnv env [] = return (env, [])+ goEnv env (bind:binds) = do (env', bind') <- scTopBindEnv env bind+ (env'', binds') <- goEnv env' binds+ return (env'', bind' : binds')++ -- Arg list of bindings is in reverse order+ go _ _ [] = return []+ go env usg (bind:binds) = do (usg', bind') <- scTopBind env usg bind+ binds' <- go env usg' binds+ return (bind' : binds')++{-+************************************************************************+* *+\subsection{Environment: goes downwards}+* *+************************************************************************++Note [Work-free values only in environment]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The sc_vals field keeps track of in-scope value bindings, so+that if we come across (case x of Just y ->...) we can reduce the+case from knowing that x is bound to a pair.++But only *work-free* values are ok here. For example if the envt had+ x -> Just (expensive v)+then we do NOT want to expand to+ let y = expensive v in ...+because the x-binding still exists and we've now duplicated (expensive v).++This seldom happens because let-bound constructor applications are+ANF-ised, but it can happen as a result of on-the-fly transformations in+SpecConstr itself. Here is Trac #7865:++ let {+ a'_shr =+ case xs_af8 of _ {+ [] -> acc_af6;+ : ds_dgt [Dmd=<L,A>] ds_dgu [Dmd=<L,A>] ->+ (expensive x_af7, x_af7+ } } in+ let {+ ds_sht =+ case a'_shr of _ { (p'_afd, q'_afe) ->+ TSpecConstr_DoubleInline.recursive+ (GHC.Types.: @ GHC.Types.Int x_af7 wild_X6) (q'_afe, p'_afd)+ } } in++When processed knowing that xs_af8 was bound to a cons, we simplify to+ a'_shr = (expensive x_af7, x_af7)+and we do NOT want to inline that at the occurrence of a'_shr in ds_sht.+(There are other occurrences of a'_shr.) No no no.++It would be possible to do some on-the-fly ANF-ising, so that a'_shr turned+into a work-free value again, thus+ a1 = expensive x_af7+ a'_shr = (a1, x_af7)+but that's more work, so until its shown to be important I'm going to+leave it for now.++Note [Making SpecConstr keener]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this, in (perf/should_run/T9339)+ last (filter odd [1..1000])++After optimisation, including SpecConstr, we get:+ f :: Int# -> Int -> Int+ f x y = case case remInt# x 2# of+ __DEFAULT -> case x of+ __DEFAULT -> f (+# wild_Xp 1#) (I# x)+ 1000000# -> ...+ 0# -> case x of+ __DEFAULT -> f (+# wild_Xp 1#) y+ 1000000# -> y++Not good! We build an (I# x) box every time around the loop.+SpecConstr (as described in the paper) does not specialise f, despite+the call (f ... (I# x)) because 'y' is not scrutinied in the body.+But it is much better to specialise f for the case where the argument+is of form (I# x); then we build the box only when returning y, which+is on the cold path.++Another example:++ f x = ...(g x)....++Here 'x' is not scrutinised in f's body; but if we did specialise 'f'+then the call (g x) might allow 'g' to be specialised in turn.++So sc_keen controls whether or not we take account of whether argument is+scrutinised in the body. True <=> ignore that, and speicalise whenever+the function is applied to a data constructor.+-}++data ScEnv = SCE { sc_dflags :: DynFlags,+ sc_module :: !Module,+ sc_size :: Maybe Int, -- Size threshold+ -- Nothing => no limit++ sc_count :: Maybe Int, -- Max # of specialisations for any one fn+ -- Nothing => no limit+ -- See Note [Avoiding exponential blowup]++ sc_recursive :: Int, -- Max # of specialisations over recursive type.+ -- Stops ForceSpecConstr from diverging.++ sc_keen :: Bool, -- Specialise on arguments that are known+ -- constructors, even if they are not+ -- scrutinised in the body. See+ -- Note [Making SpecConstr keener]++ sc_force :: Bool, -- Force specialisation?+ -- See Note [Forcing specialisation]++ sc_subst :: Subst, -- Current substitution+ -- Maps InIds to OutExprs++ sc_how_bound :: HowBoundEnv,+ -- Binds interesting non-top-level variables+ -- Domain is OutVars (*after* applying the substitution)++ sc_vals :: ValueEnv,+ -- Domain is OutIds (*after* applying the substitution)+ -- Used even for top-level bindings (but not imported ones)+ -- The range of the ValueEnv is *work-free* values+ -- such as (\x. blah), or (Just v)+ -- but NOT (Just (expensive v))+ -- See Note [Work-free values only in environment]++ sc_annotations :: UniqFM SpecConstrAnnotation+ }++---------------------+type HowBoundEnv = VarEnv HowBound -- Domain is OutVars++---------------------+type ValueEnv = IdEnv Value -- Domain is OutIds+data Value = ConVal AltCon [CoreArg] -- _Saturated_ constructors+ -- The AltCon is never DEFAULT+ | LambdaVal -- Inlinable lambdas or PAPs++instance Outputable Value where+ ppr (ConVal con args) = ppr con <+> interpp'SP args+ ppr LambdaVal = text "<Lambda>"++---------------------+initScEnv :: DynFlags -> Module -> UniqFM SpecConstrAnnotation -> ScEnv+initScEnv dflags this_mod anns+ = SCE { sc_dflags = dflags,+ sc_module = this_mod,+ sc_size = specConstrThreshold dflags,+ sc_count = specConstrCount dflags,+ sc_recursive = specConstrRecursive dflags,+ sc_keen = gopt Opt_SpecConstrKeen dflags,+ sc_force = False,+ sc_subst = emptySubst,+ sc_how_bound = emptyVarEnv,+ sc_vals = emptyVarEnv,+ sc_annotations = anns }++data HowBound = RecFun -- These are the recursive functions for which+ -- we seek interesting call patterns++ | RecArg -- These are those functions' arguments, or their sub-components;+ -- we gather occurrence information for these++instance Outputable HowBound where+ ppr RecFun = text "RecFun"+ ppr RecArg = text "RecArg"++scForce :: ScEnv -> Bool -> ScEnv+scForce env b = env { sc_force = b }++lookupHowBound :: ScEnv -> Id -> Maybe HowBound+lookupHowBound env id = lookupVarEnv (sc_how_bound env) id++scSubstId :: ScEnv -> Id -> CoreExpr+scSubstId env v = lookupIdSubst (text "scSubstId") (sc_subst env) v++scSubstTy :: ScEnv -> Type -> Type+scSubstTy env ty = substTy (sc_subst env) ty++scSubstCo :: ScEnv -> Coercion -> Coercion+scSubstCo env co = substCo (sc_subst env) co++zapScSubst :: ScEnv -> ScEnv+zapScSubst env = env { sc_subst = zapSubstEnv (sc_subst env) }++extendScInScope :: ScEnv -> [Var] -> ScEnv+ -- Bring the quantified variables into scope+extendScInScope env qvars = env { sc_subst = extendInScopeList (sc_subst env) qvars }++ -- Extend the substitution+extendScSubst :: ScEnv -> Var -> OutExpr -> ScEnv+extendScSubst env var expr = env { sc_subst = extendSubst (sc_subst env) var expr }++extendScSubstList :: ScEnv -> [(Var,OutExpr)] -> ScEnv+extendScSubstList env prs = env { sc_subst = extendSubstList (sc_subst env) prs }++extendHowBound :: ScEnv -> [Var] -> HowBound -> ScEnv+extendHowBound env bndrs how_bound+ = env { sc_how_bound = extendVarEnvList (sc_how_bound env)+ [(bndr,how_bound) | bndr <- bndrs] }++extendBndrsWith :: HowBound -> ScEnv -> [Var] -> (ScEnv, [Var])+extendBndrsWith how_bound env bndrs+ = (env { sc_subst = subst', sc_how_bound = hb_env' }, bndrs')+ where+ (subst', bndrs') = substBndrs (sc_subst env) bndrs+ hb_env' = sc_how_bound env `extendVarEnvList`+ [(bndr,how_bound) | bndr <- bndrs']++extendBndrWith :: HowBound -> ScEnv -> Var -> (ScEnv, Var)+extendBndrWith how_bound env bndr+ = (env { sc_subst = subst', sc_how_bound = hb_env' }, bndr')+ where+ (subst', bndr') = substBndr (sc_subst env) bndr+ hb_env' = extendVarEnv (sc_how_bound env) bndr' how_bound++extendRecBndrs :: ScEnv -> [Var] -> (ScEnv, [Var])+extendRecBndrs env bndrs = (env { sc_subst = subst' }, bndrs')+ where+ (subst', bndrs') = substRecBndrs (sc_subst env) bndrs++extendBndr :: ScEnv -> Var -> (ScEnv, Var)+extendBndr env bndr = (env { sc_subst = subst' }, bndr')+ where+ (subst', bndr') = substBndr (sc_subst env) bndr++extendValEnv :: ScEnv -> Id -> Maybe Value -> ScEnv+extendValEnv env _ Nothing = env+extendValEnv env id (Just cv)+ | valueIsWorkFree cv -- Don't duplicate work!! Trac #7865+ = env { sc_vals = extendVarEnv (sc_vals env) id cv }+extendValEnv env _ _ = env++extendCaseBndrs :: ScEnv -> OutExpr -> OutId -> AltCon -> [Var] -> (ScEnv, [Var])+-- When we encounter+-- case scrut of b+-- C x y -> ...+-- we want to bind b, to (C x y)+-- NB1: Extends only the sc_vals part of the envt+-- NB2: Kill the dead-ness info on the pattern binders x,y, since+-- they are potentially made alive by the [b -> C x y] binding+extendCaseBndrs env scrut case_bndr con alt_bndrs+ = (env2, alt_bndrs')+ where+ live_case_bndr = not (isDeadBinder case_bndr)+ env1 | Var v <- stripTicksTopE (const True) scrut+ = extendValEnv env v cval+ | otherwise = env -- See Note [Add scrutinee to ValueEnv too]+ env2 | live_case_bndr = extendValEnv env1 case_bndr cval+ | otherwise = env1++ alt_bndrs' | case scrut of { Var {} -> True; _ -> live_case_bndr }+ = map zap alt_bndrs+ | otherwise+ = alt_bndrs++ cval = case con of+ DEFAULT -> Nothing+ LitAlt {} -> Just (ConVal con [])+ DataAlt {} -> Just (ConVal con vanilla_args)+ where+ vanilla_args = map Type (tyConAppArgs (idType case_bndr)) +++ varsToCoreExprs alt_bndrs++ zap v | isTyVar v = v -- See NB2 above+ | otherwise = zapIdOccInfo v+++decreaseSpecCount :: ScEnv -> Int -> ScEnv+-- See Note [Avoiding exponential blowup]+decreaseSpecCount env n_specs+ = env { sc_count = case sc_count env of+ Nothing -> Nothing+ Just n -> Just (n `div` (n_specs + 1)) }+ -- The "+1" takes account of the original function;+ -- See Note [Avoiding exponential blowup]++---------------------------------------------------+-- See Note [Forcing specialisation]+ignoreType :: ScEnv -> Type -> Bool+ignoreDataCon :: ScEnv -> DataCon -> Bool+forceSpecBndr :: ScEnv -> Var -> Bool++ignoreDataCon env dc = ignoreTyCon env (dataConTyCon dc)++ignoreType env ty+ = case tyConAppTyCon_maybe ty of+ Just tycon -> ignoreTyCon env tycon+ _ -> False++ignoreTyCon :: ScEnv -> TyCon -> Bool+ignoreTyCon env tycon+ = lookupUFM (sc_annotations env) tycon == Just NoSpecConstr++forceSpecBndr env var = forceSpecFunTy env . snd . splitForAllTys . varType $ var++forceSpecFunTy :: ScEnv -> Type -> Bool+forceSpecFunTy env = any (forceSpecArgTy env) . fst . splitFunTys++forceSpecArgTy :: ScEnv -> Type -> Bool+forceSpecArgTy env ty+ | Just ty' <- coreView ty = forceSpecArgTy env ty'++forceSpecArgTy env ty+ | Just (tycon, tys) <- splitTyConApp_maybe ty+ , tycon /= funTyCon+ = tyConName tycon == specTyConName+ || lookupUFM (sc_annotations env) tycon == Just ForceSpecConstr+ || any (forceSpecArgTy env) tys++forceSpecArgTy _ _ = False++{-+Note [Add scrutinee to ValueEnv too]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:+ case x of y+ (a,b) -> case b of c+ I# v -> ...(f y)...+By the time we get to the call (f y), the ValueEnv+will have a binding for y, and for c+ y -> (a,b)+ c -> I# v+BUT that's not enough! Looking at the call (f y) we+see that y is pair (a,b), but we also need to know what 'b' is.+So in extendCaseBndrs we must *also* add the binding+ b -> I# v+else we lose a useful specialisation for f. This is necessary even+though the simplifier has systematically replaced uses of 'x' with 'y'+and 'b' with 'c' in the code. The use of 'b' in the ValueEnv came+from outside the case. See Trac #4908 for the live example.++Note [Avoiding exponential blowup]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The sc_count field of the ScEnv says how many times we are prepared to+duplicate a single function. But we must take care with recursive+specialisations. Consider++ let $j1 = let $j2 = let $j3 = ...+ in+ ...$j3...+ in+ ...$j2...+ in+ ...$j1...++If we specialise $j1 then in each specialisation (as well as the original)+we can specialise $j2, and similarly $j3. Even if we make just *one*+specialisation of each, because we also have the original we'll get 2^n+copies of $j3, which is not good.++So when recursively specialising we divide the sc_count by the number of+copies we are making at this level, including the original.+++************************************************************************+* *+\subsection{Usage information: flows upwards}+* *+************************************************************************+-}++data ScUsage+ = SCU {+ scu_calls :: CallEnv, -- Calls+ -- The functions are a subset of the+ -- RecFuns in the ScEnv++ scu_occs :: !(IdEnv ArgOcc) -- Information on argument occurrences+ } -- The domain is OutIds++type CallEnv = IdEnv [Call]+data Call = Call Id [CoreArg] ValueEnv+ -- The arguments of the call, together with the+ -- env giving the constructor bindings at the call site+ -- We keep the function mainly for debug output++instance Outputable ScUsage where+ ppr (SCU { scu_calls = calls, scu_occs = occs })+ = text "SCU" <+> braces (sep [ ptext (sLit "calls =") <+> ppr calls+ , text "occs =" <+> ppr occs ])++instance Outputable Call where+ ppr (Call fn args _) = ppr fn <+> fsep (map pprParendExpr args)++nullUsage :: ScUsage+nullUsage = SCU { scu_calls = emptyVarEnv, scu_occs = emptyVarEnv }++combineCalls :: CallEnv -> CallEnv -> CallEnv+combineCalls = plusVarEnv_C (++)+ where+-- plus cs ds | length res > 1+-- = pprTrace "combineCalls" (vcat [ text "cs:" <+> ppr cs+-- , text "ds:" <+> ppr ds])+-- res+-- | otherwise = res+-- where+-- res = cs ++ ds++combineUsage :: ScUsage -> ScUsage -> ScUsage+combineUsage u1 u2 = SCU { scu_calls = combineCalls (scu_calls u1) (scu_calls u2),+ scu_occs = plusVarEnv_C combineOcc (scu_occs u1) (scu_occs u2) }++combineUsages :: [ScUsage] -> ScUsage+combineUsages [] = nullUsage+combineUsages us = foldr1 combineUsage us++lookupOccs :: ScUsage -> [OutVar] -> (ScUsage, [ArgOcc])+lookupOccs (SCU { scu_calls = sc_calls, scu_occs = sc_occs }) bndrs+ = (SCU {scu_calls = sc_calls, scu_occs = delVarEnvList sc_occs bndrs},+ [lookupVarEnv sc_occs b `orElse` NoOcc | b <- bndrs])++data ArgOcc = NoOcc -- Doesn't occur at all; or a type argument+ | UnkOcc -- Used in some unknown way++ | ScrutOcc -- See Note [ScrutOcc]+ (DataConEnv [ArgOcc]) -- How the sub-components are used++type DataConEnv a = UniqFM a -- Keyed by DataCon++{- Note [ScrutOcc]+~~~~~~~~~~~~~~~~~~~+An occurrence of ScrutOcc indicates that the thing, or a `cast` version of the thing,+is *only* taken apart or applied.++ Functions, literal: ScrutOcc emptyUFM+ Data constructors: ScrutOcc subs,++where (subs :: UniqFM [ArgOcc]) gives usage of the *pattern-bound* components,+The domain of the UniqFM is the Unique of the data constructor++The [ArgOcc] is the occurrences of the *pattern-bound* components+of the data structure. E.g.+ data T a = forall b. MkT a b (b->a)+A pattern binds b, x::a, y::b, z::b->a, but not 'a'!++-}++instance Outputable ArgOcc where+ ppr (ScrutOcc xs) = text "scrut-occ" <> ppr xs+ ppr UnkOcc = text "unk-occ"+ ppr NoOcc = text "no-occ"++evalScrutOcc :: ArgOcc+evalScrutOcc = ScrutOcc emptyUFM++-- Experimentally, this vesion of combineOcc makes ScrutOcc "win", so+-- that if the thing is scrutinised anywhere then we get to see that+-- in the overall result, even if it's also used in a boxed way+-- This might be too aggressive; see Note [Reboxing] Alternative 3+combineOcc :: ArgOcc -> ArgOcc -> ArgOcc+combineOcc NoOcc occ = occ+combineOcc occ NoOcc = occ+combineOcc (ScrutOcc xs) (ScrutOcc ys) = ScrutOcc (plusUFM_C combineOccs xs ys)+combineOcc UnkOcc (ScrutOcc ys) = ScrutOcc ys+combineOcc (ScrutOcc xs) UnkOcc = ScrutOcc xs+combineOcc UnkOcc UnkOcc = UnkOcc++combineOccs :: [ArgOcc] -> [ArgOcc] -> [ArgOcc]+combineOccs xs ys = zipWithEqual "combineOccs" combineOcc xs ys++setScrutOcc :: ScEnv -> ScUsage -> OutExpr -> ArgOcc -> ScUsage+-- _Overwrite_ the occurrence info for the scrutinee, if the scrutinee+-- is a variable, and an interesting variable+setScrutOcc env usg (Cast e _) occ = setScrutOcc env usg e occ+setScrutOcc env usg (Tick _ e) occ = setScrutOcc env usg e occ+setScrutOcc env usg (Var v) occ+ | Just RecArg <- lookupHowBound env v = usg { scu_occs = extendVarEnv (scu_occs usg) v occ }+ | otherwise = usg+setScrutOcc _env usg _other _occ -- Catch-all+ = usg++{-+************************************************************************+* *+\subsection{The main recursive function}+* *+************************************************************************++The main recursive function gathers up usage information, and+creates specialised versions of functions.+-}++scExpr, scExpr' :: ScEnv -> CoreExpr -> UniqSM (ScUsage, CoreExpr)+ -- The unique supply is needed when we invent+ -- a new name for the specialised function and its args++scExpr env e = scExpr' env e++scExpr' env (Var v) = case scSubstId env v of+ Var v' -> return (mkVarUsage env v' [], Var v')+ e' -> scExpr (zapScSubst env) e'++scExpr' env (Type t) = return (nullUsage, Type (scSubstTy env t))+scExpr' env (Coercion c) = return (nullUsage, Coercion (scSubstCo env c))+scExpr' _ e@(Lit {}) = return (nullUsage, e)+scExpr' env (Tick t e) = do (usg, e') <- scExpr env e+ return (usg, Tick t e')+scExpr' env (Cast e co) = do (usg, e') <- scExpr env e+ return (usg, mkCast e' (scSubstCo env co))+ -- Important to use mkCast here+ -- See Note [SpecConstr call patterns]+scExpr' env e@(App _ _) = scApp env (collectArgs e)+scExpr' env (Lam b e) = do let (env', b') = extendBndr env b+ (usg, e') <- scExpr env' e+ return (usg, Lam b' e')++scExpr' env (Case scrut b ty alts)+ = do { (scrut_usg, scrut') <- scExpr env scrut+ ; case isValue (sc_vals env) scrut' of+ Just (ConVal con args) -> sc_con_app con args scrut'+ _other -> sc_vanilla scrut_usg scrut'+ }+ where+ sc_con_app con args scrut' -- Known constructor; simplify+ = do { let (_, bs, rhs) = findAlt con alts+ `orElse` (DEFAULT, [], mkImpossibleExpr ty)+ alt_env' = extendScSubstList env ((b,scrut') : bs `zip` trimConArgs con args)+ ; scExpr alt_env' rhs }++ sc_vanilla scrut_usg scrut' -- Normal case+ = do { let (alt_env,b') = extendBndrWith RecArg env b+ -- Record RecArg for the components++ ; (alt_usgs, alt_occs, alts')+ <- mapAndUnzip3M (sc_alt alt_env scrut' b') alts++ ; let scrut_occ = foldr combineOcc NoOcc alt_occs+ scrut_usg' = setScrutOcc env scrut_usg scrut' scrut_occ+ -- The combined usage of the scrutinee is given+ -- by scrut_occ, which is passed to scScrut, which+ -- in turn treats a bare-variable scrutinee specially++ ; return (foldr combineUsage scrut_usg' alt_usgs,+ Case scrut' b' (scSubstTy env ty) alts') }++ sc_alt env scrut' b' (con,bs,rhs)+ = do { let (env1, bs1) = extendBndrsWith RecArg env bs+ (env2, bs2) = extendCaseBndrs env1 scrut' b' con bs1+ ; (usg, rhs') <- scExpr env2 rhs+ ; let (usg', b_occ:arg_occs) = lookupOccs usg (b':bs2)+ scrut_occ = case con of+ DataAlt dc -> ScrutOcc (unitUFM dc arg_occs)+ _ -> ScrutOcc emptyUFM+ ; return (usg', b_occ `combineOcc` scrut_occ, (con, bs2, rhs')) }++scExpr' env (Let (NonRec bndr rhs) body)+ | isTyVar bndr -- Type-lets may be created by doBeta+ = scExpr' (extendScSubst env bndr rhs) body++ | otherwise+ = do { let (body_env, bndr') = extendBndr env bndr+ ; rhs_info <- scRecRhs env (bndr',rhs)++ ; let body_env2 = extendHowBound body_env [bndr'] RecFun+ -- Note [Local let bindings]+ rhs' = ri_new_rhs rhs_info+ body_env3 = extendValEnv body_env2 bndr' (isValue (sc_vals env) rhs')++ ; (body_usg, body') <- scExpr body_env3 body++ -- NB: For non-recursive bindings we inherit sc_force flag from+ -- the parent function (see Note [Forcing specialisation])+ ; (spec_usg, specs) <- specNonRec env body_usg rhs_info++ ; return (body_usg { scu_calls = scu_calls body_usg `delVarEnv` bndr' }+ `combineUsage` spec_usg, -- Note [spec_usg includes rhs_usg]+ mkLets [NonRec b r | (b,r) <- ruleInfoBinds rhs_info specs] body')+ }+++-- A *local* recursive group: see Note [Local recursive groups]+scExpr' env (Let (Rec prs) body)+ = do { let (bndrs,rhss) = unzip prs+ (rhs_env1,bndrs') = extendRecBndrs env bndrs+ rhs_env2 = extendHowBound rhs_env1 bndrs' RecFun+ force_spec = any (forceSpecBndr env) bndrs'+ -- Note [Forcing specialisation]++ ; rhs_infos <- mapM (scRecRhs rhs_env2) (bndrs' `zip` rhss)+ ; (body_usg, body') <- scExpr rhs_env2 body++ -- NB: start specLoop from body_usg+ ; (spec_usg, specs) <- specRec NotTopLevel (scForce rhs_env2 force_spec)+ body_usg rhs_infos+ -- Do not unconditionally generate specialisations from rhs_usgs+ -- Instead use them only if we find an unspecialised call+ -- See Note [Local recursive groups]++ ; let all_usg = spec_usg `combineUsage` body_usg -- Note [spec_usg includes rhs_usg]+ bind' = Rec (concat (zipWith ruleInfoBinds rhs_infos specs))++ ; return (all_usg { scu_calls = scu_calls all_usg `delVarEnvList` bndrs' },+ Let bind' body') }++{-+Note [Local let bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~+It is not uncommon to find this++ let $j = \x. <blah> in ...$j True...$j True...++Here $j is an arbitrary let-bound function, but it often comes up for+join points. We might like to specialise $j for its call patterns.+Notice the difference from a letrec, where we look for call patterns+in the *RHS* of the function. Here we look for call patterns in the+*body* of the let.++At one point I predicated this on the RHS mentioning the outer+recursive function, but that's not essential and might even be+harmful. I'm not sure.+-}++scApp :: ScEnv -> (InExpr, [InExpr]) -> UniqSM (ScUsage, CoreExpr)++scApp env (Var fn, args) -- Function is a variable+ = ASSERT( not (null args) )+ do { args_w_usgs <- mapM (scExpr env) args+ ; let (arg_usgs, args') = unzip args_w_usgs+ arg_usg = combineUsages arg_usgs+ ; case scSubstId env fn of+ fn'@(Lam {}) -> scExpr (zapScSubst env) (doBeta fn' args')+ -- Do beta-reduction and try again++ Var fn' -> return (arg_usg `combineUsage` mkVarUsage env fn' args',+ mkApps (Var fn') args')++ other_fn' -> return (arg_usg, mkApps other_fn' args') }+ -- NB: doing this ignores any usage info from the substituted+ -- function, but I don't think that matters. If it does+ -- we can fix it.+ where+ doBeta :: OutExpr -> [OutExpr] -> OutExpr+ -- ToDo: adjust for System IF+ doBeta (Lam bndr body) (arg : args) = Let (NonRec bndr arg) (doBeta body args)+ doBeta fn args = mkApps fn args++-- The function is almost always a variable, but not always.+-- In particular, if this pass follows float-in,+-- which it may, we can get+-- (let f = ...f... in f) arg1 arg2+scApp env (other_fn, args)+ = do { (fn_usg, fn') <- scExpr env other_fn+ ; (arg_usgs, args') <- mapAndUnzipM (scExpr env) args+ ; return (combineUsages arg_usgs `combineUsage` fn_usg, mkApps fn' args') }++----------------------+mkVarUsage :: ScEnv -> Id -> [CoreExpr] -> ScUsage+mkVarUsage env fn args+ = case lookupHowBound env fn of+ Just RecFun -> SCU { scu_calls = unitVarEnv fn [Call fn args (sc_vals env)]+ , scu_occs = emptyVarEnv }+ Just RecArg -> SCU { scu_calls = emptyVarEnv+ , scu_occs = unitVarEnv fn arg_occ }+ Nothing -> nullUsage+ where+ -- I rather think we could use UnkOcc all the time+ arg_occ | null args = UnkOcc+ | otherwise = evalScrutOcc++----------------------+scTopBindEnv :: ScEnv -> CoreBind -> UniqSM (ScEnv, CoreBind)+scTopBindEnv env (Rec prs)+ = do { let (rhs_env1,bndrs') = extendRecBndrs env bndrs+ rhs_env2 = extendHowBound rhs_env1 bndrs RecFun++ prs' = zip bndrs' rhss+ ; return (rhs_env2, Rec prs') }+ where+ (bndrs,rhss) = unzip prs++scTopBindEnv env (NonRec bndr rhs)+ = do { let (env1, bndr') = extendBndr env bndr+ env2 = extendValEnv env1 bndr' (isValue (sc_vals env) rhs)+ ; return (env2, NonRec bndr' rhs) }++----------------------+scTopBind :: ScEnv -> ScUsage -> CoreBind -> UniqSM (ScUsage, CoreBind)++{-+scTopBind _ usage _+ | pprTrace "scTopBind_usage" (ppr (scu_calls usage)) False+ = error "false"+-}++scTopBind env body_usage (Rec prs)+ | Just threshold <- sc_size env+ , not force_spec+ , not (all (couldBeSmallEnoughToInline (sc_dflags env) threshold) rhss)+ -- No specialisation+ = -- pprTrace "scTopBind: nospec" (ppr bndrs) $+ do { (rhs_usgs, rhss') <- mapAndUnzipM (scExpr env) rhss+ ; return (body_usage `combineUsage` combineUsages rhs_usgs, Rec (bndrs `zip` rhss')) }++ | otherwise -- Do specialisation+ = do { rhs_infos <- mapM (scRecRhs env) prs++ ; (spec_usage, specs) <- specRec TopLevel (scForce env force_spec)+ body_usage rhs_infos++ ; return (body_usage `combineUsage` spec_usage,+ Rec (concat (zipWith ruleInfoBinds rhs_infos specs))) }+ where+ (bndrs,rhss) = unzip prs+ force_spec = any (forceSpecBndr env) bndrs+ -- Note [Forcing specialisation]++scTopBind env usage (NonRec bndr rhs) -- Oddly, we don't seem to specialise top-level non-rec functions+ = do { (rhs_usg', rhs') <- scExpr env rhs+ ; return (usage `combineUsage` rhs_usg', NonRec bndr rhs') }++----------------------+scRecRhs :: ScEnv -> (OutId, InExpr) -> UniqSM RhsInfo+scRecRhs env (bndr,rhs)+ = do { let (arg_bndrs,body) = collectBinders rhs+ (body_env, arg_bndrs') = extendBndrsWith RecArg env arg_bndrs+ ; (body_usg, body') <- scExpr body_env body+ ; let (rhs_usg, arg_occs) = lookupOccs body_usg arg_bndrs'+ ; return (RI { ri_rhs_usg = rhs_usg+ , ri_fn = bndr, ri_new_rhs = mkLams arg_bndrs' body'+ , ri_lam_bndrs = arg_bndrs, ri_lam_body = body+ , ri_arg_occs = arg_occs }) }+ -- The arg_occs says how the visible,+ -- lambda-bound binders of the RHS are used+ -- (including the TyVar binders)+ -- Two pats are the same if they match both ways++----------------------+ruleInfoBinds :: RhsInfo -> SpecInfo -> [(Id,CoreExpr)]+ruleInfoBinds (RI { ri_fn = fn, ri_new_rhs = new_rhs })+ (SI { si_specs = specs })+ = [(id,rhs) | OS { os_id = id, os_rhs = rhs } <- specs] +++ -- First the specialised bindings++ [(fn `addIdSpecialisations` rules, new_rhs)]+ -- And now the original binding+ where+ rules = [r | OS { os_rule = r } <- specs]++{-+************************************************************************+* *+ The specialiser itself+* *+************************************************************************+-}++data RhsInfo+ = RI { ri_fn :: OutId -- The binder+ , ri_new_rhs :: OutExpr -- The specialised RHS (in current envt)+ , ri_rhs_usg :: ScUsage -- Usage info from specialising RHS++ , ri_lam_bndrs :: [InVar] -- The *original* RHS (\xs.body)+ , ri_lam_body :: InExpr -- Note [Specialise original body]+ , ri_arg_occs :: [ArgOcc] -- Info on how the xs occur in body+ }++data SpecInfo -- Info about specialisations for a particular Id+ = SI { si_specs :: [OneSpec] -- The specialisations we have generated++ , si_n_specs :: Int -- Length of si_specs; used for numbering them++ , si_mb_unspec :: Maybe ScUsage -- Just cs => we have not yet used calls in the+ } -- from calls in the *original* RHS as+ -- seeds for new specialisations;+ -- if you decide to do so, here is the+ -- RHS usage (which has not yet been+ -- unleashed)+ -- Nothing => we have+ -- See Note [Local recursive groups]+ -- See Note [spec_usg includes rhs_usg]++ -- One specialisation: Rule plus definition+data OneSpec =+ OS { os_pat :: CallPat -- Call pattern that generated this specialisation+ , os_rule :: CoreRule -- Rule connecting original id with the specialisation+ , os_id :: OutId -- Spec id+ , os_rhs :: OutExpr } -- Spec rhs++noSpecInfo :: SpecInfo+noSpecInfo = SI { si_specs = [], si_n_specs = 0, si_mb_unspec = Nothing }++----------------------+specNonRec :: ScEnv+ -> ScUsage -- Body usage+ -> RhsInfo -- Structure info usage info for un-specialised RHS+ -> UniqSM (ScUsage, SpecInfo) -- Usage from RHSs (specialised and not)+ -- plus details of specialisations++specNonRec env body_usg rhs_info+ = specialise env (scu_calls body_usg) rhs_info+ (noSpecInfo { si_mb_unspec = Just (ri_rhs_usg rhs_info) })++----------------------+specRec :: TopLevelFlag -> ScEnv+ -> ScUsage -- Body usage+ -> [RhsInfo] -- Structure info and usage info for un-specialised RHSs+ -> UniqSM (ScUsage, [SpecInfo]) -- Usage from all RHSs (specialised and not)+ -- plus details of specialisations++specRec top_lvl env body_usg rhs_infos+ = go 1 seed_calls nullUsage init_spec_infos+ where+ (seed_calls, init_spec_infos) -- Note [Seeding top-level recursive groups]+ | isTopLevel top_lvl+ , any (isExportedId . ri_fn) rhs_infos -- Seed from body and RHSs+ = (all_calls, [noSpecInfo | _ <- rhs_infos])+ | otherwise -- Seed from body only+ = (calls_in_body, [noSpecInfo { si_mb_unspec = Just (ri_rhs_usg ri) }+ | ri <- rhs_infos])++ calls_in_body = scu_calls body_usg+ calls_in_rhss = foldr (combineCalls . scu_calls . ri_rhs_usg) emptyVarEnv rhs_infos+ all_calls = calls_in_rhss `combineCalls` calls_in_body++ -- Loop, specialising, until you get no new specialisations+ go :: Int -- Which iteration of the "until no new specialisations"+ -- loop we are on; first iteration is 1+ -> CallEnv -- Seed calls+ -- Two accumulating parameters:+ -> ScUsage -- Usage from earlier specialisations+ -> [SpecInfo] -- Details of specialisations so far+ -> UniqSM (ScUsage, [SpecInfo])+ go n_iter seed_calls usg_so_far spec_infos+ | isEmptyVarEnv seed_calls+ = -- pprTrace "specRec1" (vcat [ ppr (map ri_fn rhs_infos)+ -- , ppr seed_calls+ -- , ppr body_usg ]) $+ return (usg_so_far, spec_infos)++ -- Limit recursive specialisation+ -- See Note [Limit recursive specialisation]+ | n_iter > sc_recursive env -- Too many iterations of the 'go' loop+ , sc_force env || isNothing (sc_count env)+ -- If both of these are false, the sc_count+ -- threshold will prevent non-termination+ , any ((> the_limit) . si_n_specs) spec_infos+ = -- pprTrace "specRec2" (ppr (map (map os_pat . si_specs) spec_infos)) $+ return (usg_so_far, spec_infos)++ | otherwise+ = do { specs_w_usg <- zipWithM (specialise env seed_calls) rhs_infos spec_infos+ ; let (extra_usg_s, new_spec_infos) = unzip specs_w_usg+ extra_usg = combineUsages extra_usg_s+ all_usg = usg_so_far `combineUsage` extra_usg+ ; go (n_iter + 1) (scu_calls extra_usg) all_usg new_spec_infos }++ -- See Note [Limit recursive specialisation]+ the_limit = case sc_count env of+ Nothing -> 10 -- Ugh!+ Just max -> max+++----------------------+specialise+ :: ScEnv+ -> CallEnv -- Info on newly-discovered calls to this function+ -> RhsInfo+ -> SpecInfo -- Original RHS plus patterns dealt with+ -> UniqSM (ScUsage, SpecInfo) -- New specialised versions and their usage++-- See Note [spec_usg includes rhs_usg]++-- Note: this only generates *specialised* bindings+-- The original binding is added by ruleInfoBinds+--+-- Note: the rhs here is the optimised version of the original rhs+-- So when we make a specialised copy of the RHS, we're starting+-- from an RHS whose nested functions have been optimised already.++specialise env bind_calls (RI { ri_fn = fn, ri_lam_bndrs = arg_bndrs+ , ri_lam_body = body, ri_arg_occs = arg_occs })+ spec_info@(SI { si_specs = specs, si_n_specs = spec_count+ , si_mb_unspec = mb_unspec })+ | isBottomingId fn -- Note [Do not specialise diverging functions]+ -- and do not generate specialisation seeds from its RHS+ = -- pprTrace "specialise bot" (ppr fn) $+ return (nullUsage, spec_info)++ | isNeverActive (idInlineActivation fn) -- See Note [Transfer activation]+ || null arg_bndrs -- Only specialise functions+ = -- pprTrace "specialise inactive" (ppr fn) $+ case mb_unspec of -- Behave as if there was a single, boring call+ Just rhs_usg -> return (rhs_usg, spec_info { si_mb_unspec = Nothing })+ -- See Note [spec_usg includes rhs_usg]+ Nothing -> return (nullUsage, spec_info)++ | Just all_calls <- lookupVarEnv bind_calls fn+ = -- pprTrace "specialise entry {" (ppr fn <+> ppr all_calls) $+ do { (boring_call, new_pats) <- callsToNewPats env fn spec_info arg_occs all_calls++ ; let n_pats = length new_pats+-- ; if (not (null new_pats) || isJust mb_unspec) then+-- pprTrace "specialise" (vcat [ ppr fn <+> text "with" <+> int n_pats <+> text "good patterns"+-- , text "mb_unspec" <+> ppr (isJust mb_unspec)+-- , text "arg_occs" <+> ppr arg_occs+-- , text "good pats" <+> ppr new_pats]) $+-- return ()+-- else return ()++ ; let spec_env = decreaseSpecCount env n_pats+ ; (spec_usgs, new_specs) <- mapAndUnzipM (spec_one spec_env fn arg_bndrs body)+ (new_pats `zip` [spec_count..])+ -- See Note [Specialise original body]++ ; let spec_usg = combineUsages spec_usgs++ -- If there were any boring calls among the seeds (= all_calls), then those+ -- calls will call the un-specialised function. So we should use the seeds+ -- from the _unspecialised_ function's RHS, which are in mb_unspec, by returning+ -- then in new_usg.+ (new_usg, mb_unspec')+ = case mb_unspec of+ Just rhs_usg | boring_call -> (spec_usg `combineUsage` rhs_usg, Nothing)+ _ -> (spec_usg, mb_unspec)++-- ; pprTrace "specialise return }"+-- (vcat [ ppr fn+-- , text "boring_call:" <+> ppr boring_call+-- , text "new calls:" <+> ppr (scu_calls new_usg)]) $+-- return ()++ ; return (new_usg, SI { si_specs = new_specs ++ specs+ , si_n_specs = spec_count + n_pats+ , si_mb_unspec = mb_unspec' }) }++ | otherwise -- No new seeds, so return nullUsage+ = return (nullUsage, spec_info)+++++---------------------+spec_one :: ScEnv+ -> OutId -- Function+ -> [InVar] -- Lambda-binders of RHS; should match patterns+ -> InExpr -- Body of the original function+ -> (CallPat, Int)+ -> UniqSM (ScUsage, OneSpec) -- Rule and binding++-- spec_one creates a specialised copy of the function, together+-- with a rule for using it. I'm very proud of how short this+-- function is, considering what it does :-).++{-+ Example++ In-scope: a, x::a+ f = /\b \y::[(a,b)] -> ....f (b,c) ((:) (a,(b,c)) (x,v) (h w))...+ [c::*, v::(b,c) are presumably bound by the (...) part]+ ==>+ f_spec = /\ b c \ v::(b,c) hw::[(a,(b,c))] ->+ (...entire body of f...) [b -> (b,c),+ y -> ((:) (a,(b,c)) (x,v) hw)]++ RULE: forall b::* c::*, -- Note, *not* forall a, x+ v::(b,c),+ hw::[(a,(b,c))] .++ f (b,c) ((:) (a,(b,c)) (x,v) hw) = f_spec b c v hw+-}++spec_one env fn arg_bndrs body (call_pat@(qvars, pats), rule_number)+ = do { spec_uniq <- getUniqueM+ ; let spec_env = extendScSubstList (extendScInScope env qvars)+ (arg_bndrs `zip` pats)+ fn_name = idName fn+ fn_loc = nameSrcSpan fn_name+ fn_occ = nameOccName fn_name+ spec_occ = mkSpecOcc fn_occ+ -- We use fn_occ rather than fn in the rule_name string+ -- as we don't want the uniq to end up in the rule, and+ -- hence in the ABI, as that can cause spurious ABI+ -- changes (#4012).+ rule_name = mkFastString ("SC:" ++ occNameString fn_occ ++ show rule_number)+ spec_name = mkInternalName spec_uniq spec_occ fn_loc+-- ; pprTrace "{spec_one" (ppr (sc_count env) <+> ppr fn+-- <+> ppr pats <+> text "-->" <+> ppr spec_name) $+-- return ()++ -- Specialise the body+ ; (spec_usg, spec_body) <- scExpr spec_env body++-- ; pprTrace "done spec_one}" (ppr fn) $+-- return ()++ -- And build the results+ ; let (spec_lam_args, spec_call_args) = mkWorkerArgs (sc_dflags env)+ qvars body_ty+ -- Usual w/w hack to avoid generating+ -- a spec_rhs of unlifted type and no args++ spec_lam_args_str = handOutStrictnessInformation (fst (splitStrictSig spec_str)) spec_lam_args+ -- Annotate the variables with the strictness information from+ -- the function (see Note [Strictness information in worker binders])++ spec_join_arity | isJoinId fn = Just (length spec_lam_args)+ | otherwise = Nothing+ spec_id = mkLocalIdOrCoVar spec_name+ (mkLamTypes spec_lam_args body_ty)+ -- See Note [Transfer strictness]+ `setIdStrictness` spec_str+ `setIdArity` count isId spec_lam_args+ `asJoinId_maybe` spec_join_arity+ spec_str = calcSpecStrictness fn spec_lam_args pats+++ -- Conditionally use result of new worker-wrapper transform+ spec_rhs = mkLams spec_lam_args_str spec_body+ body_ty = exprType spec_body+ rule_rhs = mkVarApps (Var spec_id) spec_call_args+ inline_act = idInlineActivation fn+ this_mod = sc_module spec_env+ rule = mkRule this_mod True {- Auto -} True {- Local -}+ rule_name inline_act fn_name qvars pats rule_rhs+ -- See Note [Transfer activation]+ ; return (spec_usg, OS { os_pat = call_pat, os_rule = rule+ , os_id = spec_id+ , os_rhs = spec_rhs }) }+++-- See Note [Strictness information in worker binders]+handOutStrictnessInformation :: [Demand] -> [Var] -> [Var]+handOutStrictnessInformation = go+ where+ go _ [] = []+ go [] vs = vs+ go (d:dmds) (v:vs) | isId v = setIdDemandInfo v d : go dmds vs+ go dmds (v:vs) = v : go dmds vs++calcSpecStrictness :: Id -- The original function+ -> [Var] -> [CoreExpr] -- Call pattern+ -> StrictSig -- Strictness of specialised thing+-- See Note [Transfer strictness]+calcSpecStrictness fn qvars pats+ = mkClosedStrictSig spec_dmds topRes+ where+ spec_dmds = [ lookupVarEnv dmd_env qv `orElse` topDmd | qv <- qvars, isId qv ]+ StrictSig (DmdType _ dmds _) = idStrictness fn++ dmd_env = go emptyVarEnv dmds pats++ go :: DmdEnv -> [Demand] -> [CoreExpr] -> DmdEnv+ go env ds (Type {} : pats) = go env ds pats+ go env ds (Coercion {} : pats) = go env ds pats+ go env (d:ds) (pat : pats) = go (go_one env d pat) ds pats+ go env _ _ = env++ go_one :: DmdEnv -> Demand -> CoreExpr -> DmdEnv+ go_one env d (Var v) = extendVarEnv_C bothDmd env v d+ go_one env d e+ | Just ds <- splitProdDmd_maybe d -- NB: d does not have to be strict+ , (Var _, args) <- collectArgs e = go env ds args+ go_one env _ _ = env++{-+Note [spec_usg includes rhs_usg]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In calls to 'specialise', the returned ScUsage must include the rhs_usg in+the passed-in SpecInfo, unless there are no calls at all to the function.++The caller can, indeed must, assume this. He should not combine in rhs_usg+himself, or he'll get rhs_usg twice -- and that can lead to an exponential+blowup of duplicates in the CallEnv. This is what gave rise to the massive+performace loss in Trac #8852.++Note [Specialise original body]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The RhsInfo for a binding keeps the *original* body of the binding. We+must specialise that, *not* the result of applying specExpr to the RHS+(which is also kept in RhsInfo). Otherwise we end up specialising a+specialised RHS, and that can lead directly to exponential behaviour.++Note [Transfer activation]+~~~~~~~~~~~~~~~~~~~~~~~~~~+ This note is for SpecConstr, but exactly the same thing+ happens in the overloading specialiser; see+ Note [Auto-specialisation and RULES] in Specialise.++In which phase should the specialise-constructor rules be active?+Originally I made them always-active, but Manuel found that this+defeated some clever user-written rules. Then I made them active only+in Phase 0; after all, currently, the specConstr transformation is+only run after the simplifier has reached Phase 0, but that meant+that specialisations didn't fire inside wrappers; see test+simplCore/should_compile/spec-inline.++So now I just use the inline-activation of the parent Id, as the+activation for the specialiation RULE, just like the main specialiser;++This in turn means there is no point in specialising NOINLINE things,+so we test for that.++Note [Transfer strictness]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We must transfer strictness information from the original function to+the specialised one. Suppose, for example++ f has strictness SS+ and a RULE f (a:as) b = f_spec a as b++Now we want f_spec to have strictness LLS, otherwise we'll use call-by-need+when calling f_spec instead of call-by-value. And that can result in+unbounded worsening in space (cf the classic foldl vs foldl')++See Trac #3437 for a good example.++The function calcSpecStrictness performs the calculation.++Note [Strictness information in worker binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++After having calculated the strictness annotation for the worker (see Note+[Transfer strictness] above), we also want to have this information attached to+the worker’s arguments, for the benefit of later passes. The function+handOutStrictnessInformation decomposes the strictness annotation calculated by+calcSpecStrictness and attaches them to the variables.++************************************************************************+* *+\subsection{Argument analysis}+* *+************************************************************************++This code deals with analysing call-site arguments to see whether+they are constructor applications.++Note [Free type variables of the qvar types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a call (f @a x True), that we want to specialise, what variables should+we quantify over. Clearly over 'a' and 'x', but what about any type variables+free in x's type? In fact we don't need to worry about them because (f @a)+can only be a well-typed application if its type is compatible with x, so any+variables free in x's type must be free in (f @a), and hence either be gathered+via 'a' itself, or be in scope at f's defn. Hence we just take+ (exprsFreeVars pats).++BUT phantom type synonyms can mess this reasoning up,+ eg x::T b with type T b = Int+So we apply expandTypeSynonyms to the bound Ids.+See Trac # 5458. Yuk.++Note [SpecConstr call patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A "call patterns" that we collect is going to become the LHS of a RULE.+It's important that it doesn't have+ e |> Refl+or+ e |> g1 |> g2+because both of these will be optimised by Simplify.simplRule. In the+former case such optimisation benign, because the rule will match more+terms; but in the latter we may lose a binding of 'g1' or 'g2', and+end up with a rule LHS that doesn't bind the template variables+(Trac #10602).++The simplifier eliminates such things, but SpecConstr itself constructs+new terms by substituting. So the 'mkCast' in the Cast case of scExpr+is very important!++Note [Choosing patterns]+~~~~~~~~~~~~~~~~~~~~~~~~+If we get lots of patterns we may not want to make a specialisation+for each of them (code bloat), so we choose as follows, implemented+by trim_pats.++* The flag -fspec-constr-count-N sets the sc_count field+ of the ScEnv to (Just n). This limits the total number+ of specialisations for a given function to N.++* -fno-spec-constr-count sets the sc_count field to Nothing,+ which switches of the limit.++* The ghastly ForceSpecConstr trick also switches of the limit+ for a particular function++* Otherwise we sort the patterns to choose the most general+ ones first; more general => more widely applicable.+-}++type CallPat = ([Var], [CoreExpr]) -- Quantified variables and arguments+ -- See Note [SpecConstr call patterns]++callsToNewPats :: ScEnv -> Id+ -> SpecInfo+ -> [ArgOcc] -> [Call]+ -> UniqSM (Bool, [CallPat])+ -- Result has no duplicate patterns,+ -- nor ones mentioned in done_pats+ -- Bool indicates that there was at least one boring pattern+callsToNewPats env fn spec_info@(SI { si_specs = done_specs }) bndr_occs calls+ = do { mb_pats <- mapM (callToPats env bndr_occs) calls++ ; let have_boring_call = any isNothing mb_pats++ good_pats :: [CallPat]+ good_pats = catMaybes mb_pats++ -- Remove patterns we have already done+ new_pats = filterOut is_done good_pats+ is_done p = any (samePat p . os_pat) done_specs++ -- Remove duplicates+ non_dups = nubBy samePat new_pats++ -- Remove ones that have too many worker variables+ small_pats = filterOut too_big non_dups+ too_big (vars,_) = not (isWorkerSmallEnough (sc_dflags env) vars)+ -- We are about to construct w/w pair in 'spec_one'.+ -- Omit specialisation leading to high arity workers.+ -- See Note [Limit w/w arity] in WwLib++ -- Discard specialisations if there are too many of them+ trimmed_pats = trim_pats env fn spec_info small_pats++-- ; pprTrace "callsToPats" (vcat [ text "calls:" <+> ppr calls+-- , text "good_pats:" <+> ppr good_pats ]) $+-- return ()++ ; return (have_boring_call, trimmed_pats) }+++trim_pats :: ScEnv -> Id -> SpecInfo -> [CallPat] -> [CallPat]+-- See Note [Choosing patterns]+trim_pats env fn (SI { si_n_specs = done_spec_count }) pats+ | sc_force env+ || isNothing mb_scc+ || n_remaining >= n_pats+ = pats -- No need to trim++ | otherwise+ = emit_trace $ -- Need to trim, so keep the best ones+ take n_remaining sorted_pats++ where+ n_pats = length pats+ spec_count' = n_pats + done_spec_count+ n_remaining = max_specs - done_spec_count+ mb_scc = sc_count env+ Just max_specs = mb_scc++ sorted_pats = map fst $+ sortBy (comparing snd) $+ [(pat, pat_cons pat) | pat <- pats]+ -- Sort in order of increasing number of constructors+ -- (i.e. decreasing generality) and pick the initial+ -- segment of this list++ pat_cons :: CallPat -> Int+ -- How many data consturorst of literals are in+ -- the patten. More data-cons => less general+ pat_cons (qs, ps) = foldr ((+) . n_cons) 0 ps+ where+ q_set = mkVarSet qs+ n_cons (Var v) | v `elemVarSet` q_set = 0+ | otherwise = 1+ n_cons (Cast e _) = n_cons e+ n_cons (App e1 e2) = n_cons e1 + n_cons e2+ n_cons (Lit {}) = 1+ n_cons _ = 0++ emit_trace result+ | debugIsOn || hasPprDebug (sc_dflags env)+ -- Suppress this scary message for ordinary users! Trac #5125+ = pprTrace "SpecConstr" msg result+ | otherwise+ = result+ msg = vcat [ sep [ text "Function" <+> quotes (ppr fn)+ , nest 2 (text "has" <+>+ speakNOf spec_count' (text "call pattern") <> comma <+>+ text "but the limit is" <+> int max_specs) ]+ , text "Use -fspec-constr-count=n to set the bound"+ , text "Discarding:" <+> ppr (drop n_remaining sorted_pats) ]+++callToPats :: ScEnv -> [ArgOcc] -> Call -> UniqSM (Maybe CallPat)+ -- The [Var] is the variables to quantify over in the rule+ -- Type variables come first, since they may scope+ -- over the following term variables+ -- The [CoreExpr] are the argument patterns for the rule+callToPats env bndr_occs (Call _ args con_env)+ | length args < length bndr_occs -- Check saturated+ = return Nothing+ | otherwise+ = do { let in_scope = substInScope (sc_subst env)+ ; (interesting, pats) <- argsToPats env in_scope con_env args bndr_occs+ ; let pat_fvs = exprsFreeVarsList pats+ -- To get determinism we need the list of free variables in+ -- deterministic order. Otherwise we end up creating+ -- lambdas with different argument orders. See+ -- determinism/simplCore/should_compile/spec-inline-determ.hs+ -- for an example. For explanation of determinism+ -- considerations See Note [Unique Determinism] in Unique.+ in_scope_vars = getInScopeVars in_scope+ qvars = filterOut (`elemVarSet` in_scope_vars) pat_fvs+ -- Quantify over variables that are not in scope+ -- at the call site+ -- See Note [Free type variables of the qvar types]+ -- See Note [Shadowing] at the top++ (ktvs, ids) = partition isTyVar qvars+ qvars' = toposortTyVars ktvs ++ map sanitise ids+ -- Order into kind variables, type variables, term variables+ -- The kind of a type variable may mention a kind variable+ -- and the type of a term variable may mention a type variable++ sanitise id = id `setIdType` expandTypeSynonyms (idType id)+ -- See Note [Free type variables of the qvar types]++ ; -- pprTrace "callToPats" (ppr args $$ ppr bndr_occs) $+ if interesting+ then return (Just (qvars', pats))+ else return Nothing }++ -- argToPat takes an actual argument, and returns an abstracted+ -- version, consisting of just the "constructor skeleton" of the+ -- argument, with non-constructor sub-expression replaced by new+ -- placeholder variables. For example:+ -- C a (D (f x) (g y)) ==> C p1 (D p2 p3)++argToPat :: ScEnv+ -> InScopeSet -- What's in scope at the fn defn site+ -> ValueEnv -- ValueEnv at the call site+ -> CoreArg -- A call arg (or component thereof)+ -> ArgOcc+ -> UniqSM (Bool, CoreArg)++-- Returns (interesting, pat),+-- where pat is the pattern derived from the argument+-- interesting=True if the pattern is non-trivial (not a variable or type)+-- E.g. x:xs --> (True, x:xs)+-- f xs --> (False, w) where w is a fresh wildcard+-- (f xs, 'c') --> (True, (w, 'c')) where w is a fresh wildcard+-- \x. x+y --> (True, \x. x+y)+-- lvl7 --> (True, lvl7) if lvl7 is bound+-- somewhere further out++argToPat _env _in_scope _val_env arg@(Type {}) _arg_occ+ = return (False, arg)++argToPat env in_scope val_env (Tick _ arg) arg_occ+ = argToPat env in_scope val_env arg arg_occ+ -- Note [Notes in call patterns]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Ignore Notes. In particular, we want to ignore any InlineMe notes+ -- Perhaps we should not ignore profiling notes, but I'm going to+ -- ride roughshod over them all for now.+ --- See Note [Notes in RULE matching] in Rules++argToPat env in_scope val_env (Let _ arg) arg_occ+ = argToPat env in_scope val_env arg arg_occ+ -- See Note [Matching lets] in Rule.hs+ -- Look through let expressions+ -- e.g. f (let v = rhs in (v,w))+ -- Here we can specialise for f (v,w)+ -- because the rule-matcher will look through the let.++{- Disabled; see Note [Matching cases] in Rule.hs+argToPat env in_scope val_env (Case scrut _ _ [(_, _, rhs)]) arg_occ+ | exprOkForSpeculation scrut -- See Note [Matching cases] in Rule.hhs+ = argToPat env in_scope val_env rhs arg_occ+-}++argToPat env in_scope val_env (Cast arg co) arg_occ+ | not (ignoreType env ty2)+ = do { (interesting, arg') <- argToPat env in_scope val_env arg arg_occ+ ; if not interesting then+ wildCardPat ty2+ else do+ { -- Make a wild-card pattern for the coercion+ uniq <- getUniqueM+ ; let co_name = mkSysTvName uniq (fsLit "sg")+ co_var = mkCoVar co_name (mkCoercionType Representational ty1 ty2)+ ; return (interesting, Cast arg' (mkCoVarCo co_var)) } }+ where+ Pair ty1 ty2 = coercionKind co++++{- Disabling lambda specialisation for now+ It's fragile, and the spec_loop can be infinite+argToPat in_scope val_env arg arg_occ+ | is_value_lam arg+ = return (True, arg)+ where+ is_value_lam (Lam v e) -- Spot a value lambda, even if+ | isId v = True -- it is inside a type lambda+ | otherwise = is_value_lam e+ is_value_lam other = False+-}++ -- Check for a constructor application+ -- NB: this *precedes* the Var case, so that we catch nullary constrs+argToPat env in_scope val_env arg arg_occ+ | Just (ConVal (DataAlt dc) args) <- isValue val_env arg+ , not (ignoreDataCon env dc) -- See Note [NoSpecConstr]+ , Just arg_occs <- mb_scrut dc+ = do { let (ty_args, rest_args) = splitAtList (dataConUnivTyVars dc) args+ ; (_, args') <- argsToPats env in_scope val_env rest_args arg_occs+ ; return (True,+ mkConApp dc (ty_args ++ args')) }+ where+ mb_scrut dc = case arg_occ of+ ScrutOcc bs | Just occs <- lookupUFM bs dc+ -> Just (occs) -- See Note [Reboxing]+ _other | sc_force env || sc_keen env+ -> Just (repeat UnkOcc)+ | otherwise+ -> Nothing++ -- Check if the argument is a variable that+ -- (a) is used in an interesting way in the function body+ -- (b) we know what its value is+ -- In that case it counts as "interesting"+argToPat env in_scope val_env (Var v) arg_occ+ | sc_force env || case arg_occ of { UnkOcc -> False; _other -> True }, -- (a)+ is_value, -- (b)+ -- Ignoring sc_keen here to avoid gratuitously incurring Note [Reboxing]+ -- So sc_keen focused just on f (I# x), where we have freshly-allocated+ -- box that we can eliminate in the caller+ not (ignoreType env (varType v))+ = return (True, Var v)+ where+ is_value+ | isLocalId v = v `elemInScopeSet` in_scope+ && isJust (lookupVarEnv val_env v)+ -- Local variables have values in val_env+ | otherwise = isValueUnfolding (idUnfolding v)+ -- Imports have unfoldings++-- I'm really not sure what this comment means+-- And by not wild-carding we tend to get forall'd+-- variables that are in scope, which in turn can+-- expose the weakness in let-matching+-- See Note [Matching lets] in Rules++ -- Check for a variable bound inside the function.+ -- Don't make a wild-card, because we may usefully share+ -- e.g. f a = let x = ... in f (x,x)+ -- NB: this case follows the lambda and con-app cases!!+-- argToPat _in_scope _val_env (Var v) _arg_occ+-- = return (False, Var v)+ -- SLPJ : disabling this to avoid proliferation of versions+ -- also works badly when thinking about seeding the loop+ -- from the body of the let+ -- f x y = letrec g z = ... in g (x,y)+ -- We don't want to specialise for that *particular* x,y++ -- The default case: make a wild-card+ -- We use this for coercions too+argToPat _env _in_scope _val_env arg _arg_occ+ = wildCardPat (exprType arg)++wildCardPat :: Type -> UniqSM (Bool, CoreArg)+wildCardPat ty+ = do { uniq <- getUniqueM+ ; let id = mkSysLocalOrCoVar (fsLit "sc") uniq ty+ ; return (False, varToCoreExpr id) }++argsToPats :: ScEnv -> InScopeSet -> ValueEnv+ -> [CoreArg] -> [ArgOcc] -- Should be same length+ -> UniqSM (Bool, [CoreArg])+argsToPats env in_scope val_env args occs+ = do { stuff <- zipWithM (argToPat env in_scope val_env) args occs+ ; let (interesting_s, args') = unzip stuff+ ; return (or interesting_s, args') }++isValue :: ValueEnv -> CoreExpr -> Maybe Value+isValue _env (Lit lit)+ | litIsLifted lit = Nothing+ | otherwise = Just (ConVal (LitAlt lit) [])++isValue env (Var v)+ | Just cval <- lookupVarEnv env v+ = Just cval -- You might think we could look in the idUnfolding here+ -- but that doesn't take account of which branch of a+ -- case we are in, which is the whole point++ | not (isLocalId v) && isCheapUnfolding unf+ = isValue env (unfoldingTemplate unf)+ where+ unf = idUnfolding v+ -- However we do want to consult the unfolding+ -- as well, for let-bound constructors!++isValue env (Lam b e)+ | isTyVar b = case isValue env e of+ Just _ -> Just LambdaVal+ Nothing -> Nothing+ | otherwise = Just LambdaVal++isValue env (Tick t e)+ | not (tickishIsCode t)+ = isValue env e++isValue _env expr -- Maybe it's a constructor application+ | (Var fun, args, _) <- collectArgsTicks (not . tickishIsCode) expr+ = case isDataConWorkId_maybe fun of++ Just con | args `lengthAtLeast` dataConRepArity con+ -- Check saturated; might be > because the+ -- arity excludes type args+ -> Just (ConVal (DataAlt con) args)++ _other | valArgCount args < idArity fun+ -- Under-applied function+ -> Just LambdaVal -- Partial application++ _other -> Nothing++isValue _env _expr = Nothing++valueIsWorkFree :: Value -> Bool+valueIsWorkFree LambdaVal = True+valueIsWorkFree (ConVal _ args) = all exprIsWorkFree args++samePat :: CallPat -> CallPat -> Bool+samePat (vs1, as1) (vs2, as2)+ = all2 same as1 as2+ where+ same (Var v1) (Var v2)+ | v1 `elem` vs1 = v2 `elem` vs2+ | v2 `elem` vs2 = False+ | otherwise = v1 == v2++ same (Lit l1) (Lit l2) = l1==l2+ same (App f1 a1) (App f2 a2) = same f1 f2 && same a1 a2++ same (Type {}) (Type {}) = True -- Note [Ignore type differences]+ same (Coercion {}) (Coercion {}) = True+ same (Tick _ e1) e2 = same e1 e2 -- Ignore casts and notes+ same (Cast e1 _) e2 = same e1 e2+ same e1 (Tick _ e2) = same e1 e2+ same e1 (Cast e2 _) = same e1 e2++ same e1 e2 = WARN( bad e1 || bad e2, ppr e1 $$ ppr e2)+ False -- Let, lambda, case should not occur+ bad (Case {}) = True+ bad (Let {}) = True+ bad (Lam {}) = True+ bad _other = False++{-+Note [Ignore type differences]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do not want to generate specialisations where the call patterns+differ only in their type arguments! Not only is it utterly useless,+but it also means that (with polymorphic recursion) we can generate+an infinite number of specialisations. Example is Data.Sequence.adjustTree,+I think.+-}
+ specialise/Specialise.hs view
@@ -0,0 +1,2456 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[Specialise]{Stamping out overloading, and (optionally) polymorphism}+-}++{-# LANGUAGE CPP #-}+module Specialise ( specProgram, specUnfolding ) where++#include "HsVersions.h"++import Id+import TcType hiding( substTy )+import Type hiding( substTy, extendTvSubstList )+import Module( Module, HasModule(..) )+import Coercion( Coercion )+import CoreMonad+import qualified CoreSubst+import CoreUnfold+import Var ( isLocalVar )+import VarSet+import VarEnv+import CoreSyn+import Rules+import CoreOpt ( collectBindersPushingCo )+import CoreUtils ( exprIsTrivial, applyTypeToArgs, mkCast )+import CoreFVs+import FV ( InterestingVarFun )+import CoreArity ( etaExpandToJoinPointRule )+import UniqSupply+import Name+import MkId ( voidArgId, voidPrimId )+import Maybes ( catMaybes, isJust )+import MonadUtils ( foldlM )+import BasicTypes+import HscTypes+import Bag+import DynFlags+import Util+import Outputable+import FastString+import State+import UniqDFM++import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif++{-+************************************************************************+* *+\subsection[notes-Specialise]{Implementation notes [SLPJ, Aug 18 1993]}+* *+************************************************************************++These notes describe how we implement specialisation to eliminate+overloading.++The specialisation pass works on Core+syntax, complete with all the explicit dictionary application,+abstraction and construction as added by the type checker. The+existing type checker remains largely as it is.++One important thought: the {\em types} passed to an overloaded+function, and the {\em dictionaries} passed are mutually redundant.+If the same function is applied to the same type(s) then it is sure to+be applied to the same dictionary(s)---or rather to the same {\em+values}. (The arguments might look different but they will evaluate+to the same value.)++Second important thought: we know that we can make progress by+treating dictionary arguments as static and worth specialising on. So+we can do without binding-time analysis, and instead specialise on+dictionary arguments and no others.++The basic idea+~~~~~~~~~~~~~~+Suppose we have++ let f = <f_rhs>+ in <body>++and suppose f is overloaded.++STEP 1: CALL-INSTANCE COLLECTION++We traverse <body>, accumulating all applications of f to types and+dictionaries.++(Might there be partial applications, to just some of its types and+dictionaries? In principle yes, but in practice the type checker only+builds applications of f to all its types and dictionaries, so partial+applications could only arise as a result of transformation, and even+then I think it's unlikely. In any case, we simply don't accumulate such+partial applications.)+++STEP 2: EQUIVALENCES++So now we have a collection of calls to f:+ f t1 t2 d1 d2+ f t3 t4 d3 d4+ ...+Notice that f may take several type arguments. To avoid ambiguity, we+say that f is called at type t1/t2 and t3/t4.++We take equivalence classes using equality of the *types* (ignoring+the dictionary args, which as mentioned previously are redundant).++STEP 3: SPECIALISATION++For each equivalence class, choose a representative (f t1 t2 d1 d2),+and create a local instance of f, defined thus:++ f@t1/t2 = <f_rhs> t1 t2 d1 d2++f_rhs presumably has some big lambdas and dictionary lambdas, so lots+of simplification will now result. However we don't actually *do* that+simplification. Rather, we leave it for the simplifier to do. If we+*did* do it, though, we'd get more call instances from the specialised+RHS. We can work out what they are by instantiating the call-instance+set from f's RHS with the types t1, t2.++Add this new id to f's IdInfo, to record that f has a specialised version.++Before doing any of this, check that f's IdInfo doesn't already+tell us about an existing instance of f at the required type/s.+(This might happen if specialisation was applied more than once, or+it might arise from user SPECIALIZE pragmas.)++Recursion+~~~~~~~~~+Wait a minute! What if f is recursive? Then we can't just plug in+its right-hand side, can we?++But it's ok. The type checker *always* creates non-recursive definitions+for overloaded recursive functions. For example:++ f x = f (x+x) -- Yes I know its silly++becomes++ f a (d::Num a) = let p = +.sel a d+ in+ letrec fl (y::a) = fl (p y y)+ in+ fl++We still have recusion for non-overloaded functions which we+specialise, but the recursive call should get specialised to the+same recursive version.+++Polymorphism 1+~~~~~~~~~~~~~~++All this is crystal clear when the function is applied to *constant+types*; that is, types which have no type variables inside. But what if+it is applied to non-constant types? Suppose we find a call of f at type+t1/t2. There are two possibilities:++(a) The free type variables of t1, t2 are in scope at the definition point+of f. In this case there's no problem, we proceed just as before. A common+example is as follows. Here's the Haskell:++ g y = let f x = x+x+ in f y + f y++After typechecking we have++ g a (d::Num a) (y::a) = let f b (d'::Num b) (x::b) = +.sel b d' x x+ in +.sel a d (f a d y) (f a d y)++Notice that the call to f is at type type "a"; a non-constant type.+Both calls to f are at the same type, so we can specialise to give:++ g a (d::Num a) (y::a) = let f@a (x::a) = +.sel a d x x+ in +.sel a d (f@a y) (f@a y)+++(b) The other case is when the type variables in the instance types+are *not* in scope at the definition point of f. The example we are+working with above is a good case. There are two instances of (+.sel a d),+but "a" is not in scope at the definition of +.sel. Can we do anything?+Yes, we can "common them up", a sort of limited common sub-expression deal.+This would give:++ g a (d::Num a) (y::a) = let +.sel@a = +.sel a d+ f@a (x::a) = +.sel@a x x+ in +.sel@a (f@a y) (f@a y)++This can save work, and can't be spotted by the type checker, because+the two instances of +.sel weren't originally at the same type.++Further notes on (b)++* There are quite a few variations here. For example, the defn of+ +.sel could be floated ouside the \y, to attempt to gain laziness.+ It certainly mustn't be floated outside the \d because the d has to+ be in scope too.++* We don't want to inline f_rhs in this case, because+that will duplicate code. Just commoning up the call is the point.++* Nothing gets added to +.sel's IdInfo.++* Don't bother unless the equivalence class has more than one item!++Not clear whether this is all worth it. It is of course OK to+simply discard call-instances when passing a big lambda.++Polymorphism 2 -- Overloading+~~~~~~~~~~~~~~+Consider a function whose most general type is++ f :: forall a b. Ord a => [a] -> b -> b++There is really no point in making a version of g at Int/Int and another+at Int/Bool, because it's only instantiating the type variable "a" which+buys us any efficiency. Since g is completely polymorphic in b there+ain't much point in making separate versions of g for the different+b types.++That suggests that we should identify which of g's type variables+are constrained (like "a") and which are unconstrained (like "b").+Then when taking equivalence classes in STEP 2, we ignore the type args+corresponding to unconstrained type variable. In STEP 3 we make+polymorphic versions. Thus:++ f@t1/ = /\b -> <f_rhs> t1 b d1 d2++We do this.+++Dictionary floating+~~~~~~~~~~~~~~~~~~~+Consider this++ f a (d::Num a) = let g = ...+ in+ ...(let d1::Ord a = Num.Ord.sel a d in g a d1)...++Here, g is only called at one type, but the dictionary isn't in scope at the+definition point for g. Usually the type checker would build a+definition for d1 which enclosed g, but the transformation system+might have moved d1's defn inward. Solution: float dictionary bindings+outwards along with call instances.++Consider++ f x = let g p q = p==q+ h r s = (r+s, g r s)+ in+ h x x+++Before specialisation, leaving out type abstractions we have++ f df x = let g :: Eq a => a -> a -> Bool+ g dg p q = == dg p q+ h :: Num a => a -> a -> (a, Bool)+ h dh r s = let deq = eqFromNum dh+ in (+ dh r s, g deq r s)+ in+ h df x x++After specialising h we get a specialised version of h, like this:++ h' r s = let deq = eqFromNum df+ in (+ df r s, g deq r s)++But we can't naively make an instance for g from this, because deq is not in scope+at the defn of g. Instead, we have to float out the (new) defn of deq+to widen its scope. Notice that this floating can't be done in advance -- it only+shows up when specialisation is done.++User SPECIALIZE pragmas+~~~~~~~~~~~~~~~~~~~~~~~+Specialisation pragmas can be digested by the type checker, and implemented+by adding extra definitions along with that of f, in the same way as before++ f@t1/t2 = <f_rhs> t1 t2 d1 d2++Indeed the pragmas *have* to be dealt with by the type checker, because+only it knows how to build the dictionaries d1 and d2! For example++ g :: Ord a => [a] -> [a]+ {-# SPECIALIZE f :: [Tree Int] -> [Tree Int] #-}++Here, the specialised version of g is an application of g's rhs to the+Ord dictionary for (Tree Int), which only the type checker can conjure+up. There might not even *be* one, if (Tree Int) is not an instance of+Ord! (All the other specialision has suitable dictionaries to hand+from actual calls.)++Problem. The type checker doesn't have to hand a convenient <f_rhs>, because+it is buried in a complex (as-yet-un-desugared) binding group.+Maybe we should say++ f@t1/t2 = f* t1 t2 d1 d2++where f* is the Id f with an IdInfo which says "inline me regardless!".+Indeed all the specialisation could be done in this way.+That in turn means that the simplifier has to be prepared to inline absolutely+any in-scope let-bound thing.+++Again, the pragma should permit polymorphism in unconstrained variables:++ h :: Ord a => [a] -> b -> b+ {-# SPECIALIZE h :: [Int] -> b -> b #-}++We *insist* that all overloaded type variables are specialised to ground types,+(and hence there can be no context inside a SPECIALIZE pragma).+We *permit* unconstrained type variables to be specialised to+ - a ground type+ - or left as a polymorphic type variable+but nothing in between. So++ {-# SPECIALIZE h :: [Int] -> [c] -> [c] #-}++is *illegal*. (It can be handled, but it adds complication, and gains the+programmer nothing.)+++SPECIALISING INSTANCE DECLARATIONS+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ instance Foo a => Foo [a] where+ ...+ {-# SPECIALIZE instance Foo [Int] #-}++The original instance decl creates a dictionary-function+definition:++ dfun.Foo.List :: forall a. Foo a -> Foo [a]++The SPECIALIZE pragma just makes a specialised copy, just as for+ordinary function definitions:++ dfun.Foo.List@Int :: Foo [Int]+ dfun.Foo.List@Int = dfun.Foo.List Int dFooInt++The information about what instance of the dfun exist gets added to+the dfun's IdInfo in the same way as a user-defined function too.+++Automatic instance decl specialisation?+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Can instance decls be specialised automatically? It's tricky.+We could collect call-instance information for each dfun, but+then when we specialised their bodies we'd get new call-instances+for ordinary functions; and when we specialised their bodies, we might get+new call-instances of the dfuns, and so on. This all arises because of+the unrestricted mutual recursion between instance decls and value decls.++Still, there's no actual problem; it just means that we may not do all+the specialisation we could theoretically do.++Furthermore, instance decls are usually exported and used non-locally,+so we'll want to compile enough to get those specialisations done.++Lastly, there's no such thing as a local instance decl, so we can+survive solely by spitting out *usage* information, and then reading that+back in as a pragma when next compiling the file. So for now,+we only specialise instance decls in response to pragmas.+++SPITTING OUT USAGE INFORMATION+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++To spit out usage information we need to traverse the code collecting+call-instance information for all imported (non-prelude?) functions+and data types. Then we equivalence-class it and spit it out.++This is done at the top-level when all the call instances which escape+must be for imported functions and data types.++*** Not currently done ***+++Partial specialisation by pragmas+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+What about partial specialisation:++ k :: (Ord a, Eq b) => [a] -> b -> b -> [a]+ {-# SPECIALIZE k :: Eq b => [Int] -> b -> b -> [a] #-}++or even++ {-# SPECIALIZE k :: Eq b => [Int] -> [b] -> [b] -> [a] #-}++Seems quite reasonable. Similar things could be done with instance decls:++ instance (Foo a, Foo b) => Foo (a,b) where+ ...+ {-# SPECIALIZE instance Foo a => Foo (a,Int) #-}+ {-# SPECIALIZE instance Foo b => Foo (Int,b) #-}++Ho hum. Things are complex enough without this. I pass.+++Requirements for the simplifier+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The simplifier has to be able to take advantage of the specialisation.++* When the simplifier finds an application of a polymorphic f, it looks in+f's IdInfo in case there is a suitable instance to call instead. This converts++ f t1 t2 d1 d2 ===> f_t1_t2++Note that the dictionaries get eaten up too!++* Dictionary selection operations on constant dictionaries must be+ short-circuited:++ +.sel Int d ===> +Int++The obvious way to do this is in the same way as other specialised+calls: +.sel has inside it some IdInfo which tells that if it's applied+to the type Int then it should eat a dictionary and transform to +Int.++In short, dictionary selectors need IdInfo inside them for constant+methods.++* Exactly the same applies if a superclass dictionary is being+ extracted:++ Eq.sel Int d ===> dEqInt++* Something similar applies to dictionary construction too. Suppose+dfun.Eq.List is the function taking a dictionary for (Eq a) to+one for (Eq [a]). Then we want++ dfun.Eq.List Int d ===> dEq.List_Int++Where does the Eq [Int] dictionary come from? It is built in+response to a SPECIALIZE pragma on the Eq [a] instance decl.++In short, dfun Ids need IdInfo with a specialisation for each+constant instance of their instance declaration.++All this uses a single mechanism: the SpecEnv inside an Id+++What does the specialisation IdInfo look like?+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The SpecEnv of an Id maps a list of types (the template) to an expression++ [Type] |-> Expr++For example, if f has this RuleInfo:++ [Int, a] -> \d:Ord Int. f' a++it means that we can replace the call++ f Int t ===> (\d. f' t)++This chucks one dictionary away and proceeds with the+specialised version of f, namely f'.+++What can't be done this way?+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There is no way, post-typechecker, to get a dictionary for (say)+Eq a from a dictionary for Eq [a]. So if we find++ ==.sel [t] d++we can't transform to++ eqList (==.sel t d')++where+ eqList :: (a->a->Bool) -> [a] -> [a] -> Bool++Of course, we currently have no way to automatically derive+eqList, nor to connect it to the Eq [a] instance decl, but you+can imagine that it might somehow be possible. Taking advantage+of this is permanently ruled out.++Still, this is no great hardship, because we intend to eliminate+overloading altogether anyway!++A note about non-tyvar dictionaries+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Some Ids have types like++ forall a,b,c. Eq a -> Ord [a] -> tau++This seems curious at first, because we usually only have dictionary+args whose types are of the form (C a) where a is a type variable.+But this doesn't hold for the functions arising from instance decls,+which sometimes get arguments with types of form (C (T a)) for some+type constructor T.++Should we specialise wrt this compound-type dictionary? We used to say+"no", saying:+ "This is a heuristic judgement, as indeed is the fact that we+ specialise wrt only dictionaries. We choose *not* to specialise+ wrt compound dictionaries because at the moment the only place+ they show up is in instance decls, where they are simply plugged+ into a returned dictionary. So nothing is gained by specialising+ wrt them."++But it is simpler and more uniform to specialise wrt these dicts too;+and in future GHC is likely to support full fledged type signatures+like+ f :: Eq [(a,b)] => ...+++************************************************************************+* *+\subsubsection{The new specialiser}+* *+************************************************************************++Our basic game plan is this. For let(rec) bound function+ f :: (C a, D c) => (a,b,c,d) -> Bool++* Find any specialised calls of f, (f ts ds), where+ ts are the type arguments t1 .. t4, and+ ds are the dictionary arguments d1 .. d2.++* Add a new definition for f1 (say):++ f1 = /\ b d -> (..body of f..) t1 b t3 d d1 d2++ Note that we abstract over the unconstrained type arguments.++* Add the mapping++ [t1,b,t3,d] |-> \d1 d2 -> f1 b d++ to the specialisations of f. This will be used by the+ simplifier to replace calls+ (f t1 t2 t3 t4) da db+ by+ (\d1 d1 -> f1 t2 t4) da db++ All the stuff about how many dictionaries to discard, and what types+ to apply the specialised function to, are handled by the fact that the+ SpecEnv contains a template for the result of the specialisation.++We don't build *partial* specialisations for f. For example:++ f :: Eq a => a -> a -> Bool+ {-# SPECIALISE f :: (Eq b, Eq c) => (b,c) -> (b,c) -> Bool #-}++Here, little is gained by making a specialised copy of f.+There's a distinct danger that the specialised version would+first build a dictionary for (Eq b, Eq c), and then select the (==)+method from it! Even if it didn't, not a great deal is saved.++We do, however, generate polymorphic, but not overloaded, specialisations:++ f :: Eq a => [a] -> b -> b -> b+ ... SPECIALISE f :: [Int] -> b -> b -> b ...++Hence, the invariant is this:++ *** no specialised version is overloaded ***+++************************************************************************+* *+\subsubsection{The exported function}+* *+************************************************************************+-}++-- | Specialise calls to type-class overloaded functions occuring in a program.+specProgram :: ModGuts -> CoreM ModGuts+specProgram guts@(ModGuts { mg_module = this_mod+ , mg_rules = local_rules+ , mg_binds = binds })+ = do { dflags <- getDynFlags++ -- Specialise the bindings of this module+ ; (binds', uds) <- runSpecM dflags this_mod (go binds)++ -- Specialise imported functions+ ; hpt_rules <- getRuleBase+ ; let rule_base = extendRuleBaseList hpt_rules local_rules+ ; (new_rules, spec_binds) <- specImports dflags this_mod top_env emptyVarSet+ [] rule_base uds++ ; let final_binds+ | null spec_binds = binds'+ | otherwise = Rec (flattenBinds spec_binds) : binds'+ -- Note [Glom the bindings if imported functions are specialised]++ ; return (guts { mg_binds = final_binds+ , mg_rules = new_rules ++ local_rules }) }+ where+ -- We need to start with a Subst that knows all the things+ -- that are in scope, so that the substitution engine doesn't+ -- accidentally re-use a unique that's already in use+ -- Easiest thing is to do it all at once, as if all the top-level+ -- decls were mutually recursive+ top_env = SE { se_subst = CoreSubst.mkEmptySubst $ mkInScopeSet $ mkVarSet $+ bindersOfBinds binds+ , se_interesting = emptyVarSet }++ go [] = return ([], emptyUDs)+ go (bind:binds) = do (binds', uds) <- go binds+ (bind', uds') <- specBind top_env bind uds+ return (bind' ++ binds', uds')++{-+Note [Wrap bindings returned by specImports]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+'specImports' returns a set of specialized bindings. However, these are lacking+necessary floated dictionary bindings, which are returned by+UsageDetails(ud_binds). These dictionaries need to be brought into scope with+'wrapDictBinds' before the bindings returned by 'specImports' can be used. See,+for instance, the 'specImports' call in 'specProgram'.+++Note [Disabling cross-module specialisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Since GHC 7.10 we have performed specialisation of INLINABLE bindings living+in modules outside of the current module. This can sometimes uncover user code+which explodes in size when aggressively optimized. The+-fno-cross-module-specialise option was introduced to allow users to being+bitten by such instances to revert to the pre-7.10 behavior.++See Trac #10491+-}++-- | Specialise a set of calls to imported bindings+specImports :: DynFlags+ -> Module+ -> SpecEnv -- Passed in so that all top-level Ids are in scope+ -> VarSet -- Don't specialise these ones+ -- See Note [Avoiding recursive specialisation]+ -> [Id] -- Stack of imported functions being specialised+ -> RuleBase -- Rules from this module and the home package+ -- (but not external packages, which can change)+ -> UsageDetails -- Calls for imported things, and floating bindings+ -> CoreM ( [CoreRule] -- New rules+ , [CoreBind] ) -- Specialised bindings+ -- See Note [Wrapping bindings returned by specImports]+specImports dflags this_mod top_env done callers rule_base+ (MkUD { ud_binds = dict_binds, ud_calls = calls })+ -- See Note [Disabling cross-module specialisation]+ | not $ gopt Opt_CrossModuleSpecialise dflags+ = return ([], [])++ | otherwise+ = do { let import_calls = dVarEnvElts calls+ ; (rules, spec_binds) <- go rule_base import_calls++ -- Don't forget to wrap the specialized bindings with+ -- bindings for the needed dictionaries.+ -- See Note [Wrap bindings returned by specImports]+ ; let spec_binds' = wrapDictBinds dict_binds spec_binds++ ; return (rules, spec_binds') }+ where+ go :: RuleBase -> [CallInfoSet] -> CoreM ([CoreRule], [CoreBind])+ go _ [] = return ([], [])+ go rb (cis@(CIS fn _) : other_calls)+ = do { let ok_calls = filterCalls cis dict_binds+ -- Drop calls that (directly or indirectly) refer to fn+ -- See Note [Avoiding loops]+-- ; debugTraceMsg (text "specImport" <+> vcat [ ppr fn+-- , text "calls" <+> ppr cis+-- , text "ud_binds =" <+> ppr dict_binds+-- , text "dump set =" <+> ppr dump_set+-- , text "filtered calls =" <+> ppr ok_calls ])+ ; (rules1, spec_binds1) <- specImport dflags this_mod top_env+ done callers rb fn ok_calls++ ; (rules2, spec_binds2) <- go (extendRuleBaseList rb rules1) other_calls+ ; return (rules1 ++ rules2, spec_binds1 ++ spec_binds2) }++specImport :: DynFlags+ -> Module+ -> SpecEnv -- Passed in so that all top-level Ids are in scope+ -> VarSet -- Don't specialise these+ -- See Note [Avoiding recursive specialisation]+ -> [Id] -- Stack of imported functions being specialised+ -> RuleBase -- Rules from this module+ -> Id -> [CallInfo] -- Imported function and calls for it+ -> CoreM ( [CoreRule] -- New rules+ , [CoreBind] ) -- Specialised bindings+specImport dflags this_mod top_env done callers rb fn calls_for_fn+ | fn `elemVarSet` done+ = return ([], []) -- No warning. This actually happens all the time+ -- when specialising a recursive function, because+ -- the RHS of the specialised function contains a recursive+ -- call to the original function++ | null calls_for_fn -- We filtered out all the calls in deleteCallsMentioning+ = return ([], [])++ | wantSpecImport dflags unfolding+ , Just rhs <- maybeUnfoldingTemplate unfolding+ = do { -- Get rules from the external package state+ -- We keep doing this in case we "page-fault in"+ -- more rules as we go along+ ; hsc_env <- getHscEnv+ ; eps <- liftIO $ hscEPS hsc_env+ ; vis_orphs <- getVisibleOrphanMods+ ; let full_rb = unionRuleBase rb (eps_rule_base eps)+ rules_for_fn = getRules (RuleEnv full_rb vis_orphs) fn++ ; (rules1, spec_pairs, uds)+ <- -- pprTrace "specImport1" (vcat [ppr fn, ppr calls_for_fn, ppr rhs]) $+ runSpecM dflags this_mod $+ specCalls (Just this_mod) top_env rules_for_fn calls_for_fn fn rhs+ ; let spec_binds1 = [NonRec b r | (b,r) <- spec_pairs]+ -- After the rules kick in we may get recursion, but+ -- we rely on a global GlomBinds to sort that out later+ -- See Note [Glom the bindings if imported functions are specialised]++ -- Now specialise any cascaded calls+ ; (rules2, spec_binds2) <- -- pprTrace "specImport 2" (ppr fn $$ ppr rules1 $$ ppr spec_binds1) $+ specImports dflags this_mod top_env+ (extendVarSet done fn)+ (fn:callers)+ (extendRuleBaseList rb rules1)+ uds++ ; let final_binds = spec_binds2 ++ spec_binds1++ ; return (rules2 ++ rules1, final_binds) }++ | warnMissingSpecs dflags callers+ = do { warnMsg (vcat [ hang (text "Could not specialise imported function" <+> quotes (ppr fn))+ 2 (vcat [ text "when specialising" <+> quotes (ppr caller)+ | caller <- callers])+ , ifPprDebug (text "calls:" <+> vcat (map (pprCallInfo fn) calls_for_fn))+ , text "Probable fix: add INLINABLE pragma on" <+> quotes (ppr fn) ])+ ; return ([], []) }++ | otherwise+ = return ([], [])+ where+ unfolding = realIdUnfolding fn -- We want to see the unfolding even for loop breakers++warnMissingSpecs :: DynFlags -> [Id] -> Bool+-- See Note [Warning about missed specialisations]+warnMissingSpecs dflags callers+ | wopt Opt_WarnAllMissedSpecs dflags = True+ | not (wopt Opt_WarnMissedSpecs dflags) = False+ | null callers = False+ | otherwise = all has_inline_prag callers+ where+ has_inline_prag id = isAnyInlinePragma (idInlinePragma id)++wantSpecImport :: DynFlags -> Unfolding -> Bool+-- See Note [Specialise imported INLINABLE things]+wantSpecImport dflags unf+ = case unf of+ NoUnfolding -> False+ BootUnfolding -> False+ OtherCon {} -> False+ DFunUnfolding {} -> True+ CoreUnfolding { uf_src = src, uf_guidance = _guidance }+ | gopt Opt_SpecialiseAggressively dflags -> True+ | isStableSource src -> True+ -- Specialise even INLINE things; it hasn't inlined yet,+ -- so perhaps it never will. Moreover it may have calls+ -- inside it that we want to specialise+ | otherwise -> False -- Stable, not INLINE, hence INLINABLE++{- Note [Warning about missed specialisations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose+ * In module Lib, you carefully mark a function 'foo' INLINABLE+ * Import Lib(foo) into another module M+ * Call 'foo' at some specialised type in M+Then you jolly well expect it to be specialised in M. But what if+'foo' calls another function 'Lib.bar'. Then you'd like 'bar' to be+specialised too. But if 'bar' is not marked INLINABLE it may well+not be specialised. The warning Opt_WarnMissedSpecs warns about this.++It's more noisy to warning about a missed specialisation opportunity+for /every/ overloaded imported function, but sometimes useful. That+is what Opt_WarnAllMissedSpecs does.++ToDo: warn about missed opportunities for local functions.++Note [Specialise imported INLINABLE things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+What imported functions do we specialise? The basic set is+ * DFuns and things with INLINABLE pragmas.+but with -fspecialise-aggressively we add+ * Anything with an unfolding template++Trac #8874 has a good example of why we want to auto-specialise DFuns.++We have the -fspecialise-aggressively flag (usually off), because we+risk lots of orphan modules from over-vigorous specialisation.+However it's not a big deal: anything non-recursive with an+unfolding-template will probably have been inlined already.++Note [Glom the bindings if imported functions are specialised]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have an imported, *recursive*, INLINABLE function+ f :: Eq a => a -> a+ f = /\a \d x. ...(f a d)...+In the module being compiled we have+ g x = f (x::Int)+Now we'll make a specialised function+ f_spec :: Int -> Int+ f_spec = \x -> ...(f Int dInt)...+ {-# RULE f Int _ = f_spec #-}+ g = \x. f Int dInt x+Note that f_spec doesn't look recursive+After rewriting with the RULE, we get+ f_spec = \x -> ...(f_spec)...+BUT since f_spec was non-recursive before it'll *stay* non-recursive.+The occurrence analyser never turns a NonRec into a Rec. So we must+make sure that f_spec is recursive. Easiest thing is to make all+the specialisations for imported bindings recursive.+++Note [Avoiding recursive specialisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we specialise 'f' we may find new overloaded calls to 'g', 'h' in+'f's RHS. So we want to specialise g,h. But we don't want to+specialise f any more! It's possible that f's RHS might have a+recursive yet-more-specialised call, so we'd diverge in that case.+And if the call is to the same type, one specialisation is enough.+Avoiding this recursive specialisation loop is the reason for the+'done' VarSet passed to specImports and specImport.++************************************************************************+* *+\subsubsection{@specExpr@: the main function}+* *+************************************************************************+-}++data SpecEnv+ = SE { se_subst :: CoreSubst.Subst+ -- We carry a substitution down:+ -- a) we must clone any binding that might float outwards,+ -- to avoid name clashes+ -- b) we carry a type substitution to use when analysing+ -- the RHS of specialised bindings (no type-let!)+++ , se_interesting :: VarSet+ -- Dict Ids that we know something about+ -- and hence may be worth specialising against+ -- See Note [Interesting dictionary arguments]+ }++specVar :: SpecEnv -> Id -> CoreExpr+specVar env v = CoreSubst.lookupIdSubst (text "specVar") (se_subst env) v++specExpr :: SpecEnv -> CoreExpr -> SpecM (CoreExpr, UsageDetails)++---------------- First the easy cases --------------------+specExpr env (Type ty) = return (Type (substTy env ty), emptyUDs)+specExpr env (Coercion co) = return (Coercion (substCo env co), emptyUDs)+specExpr env (Var v) = return (specVar env v, emptyUDs)+specExpr _ (Lit lit) = return (Lit lit, emptyUDs)+specExpr env (Cast e co)+ = do { (e', uds) <- specExpr env e+ ; return ((mkCast e' (substCo env co)), uds) }+specExpr env (Tick tickish body)+ = do { (body', uds) <- specExpr env body+ ; return (Tick (specTickish env tickish) body', uds) }++---------------- Applications might generate a call instance --------------------+specExpr env expr@(App {})+ = go expr []+ where+ go (App fun arg) args = do (arg', uds_arg) <- specExpr env arg+ (fun', uds_app) <- go fun (arg':args)+ return (App fun' arg', uds_arg `plusUDs` uds_app)++ go (Var f) args = case specVar env f of+ Var f' -> return (Var f', mkCallUDs env f' args)+ e' -> return (e', emptyUDs) -- I don't expect this!+ go other _ = specExpr env other++---------------- Lambda/case require dumping of usage details --------------------+specExpr env e@(Lam _ _) = do+ (body', uds) <- specExpr env' body+ let (free_uds, dumped_dbs) = dumpUDs bndrs' uds+ return (mkLams bndrs' (wrapDictBindsE dumped_dbs body'), free_uds)+ where+ (bndrs, body) = collectBinders e+ (env', bndrs') = substBndrs env bndrs+ -- More efficient to collect a group of binders together all at once+ -- and we don't want to split a lambda group with dumped bindings++specExpr env (Case scrut case_bndr ty alts)+ = do { (scrut', scrut_uds) <- specExpr env scrut+ ; (scrut'', case_bndr', alts', alts_uds)+ <- specCase env scrut' case_bndr alts+ ; return (Case scrut'' case_bndr' (substTy env ty) alts'+ , scrut_uds `plusUDs` alts_uds) }++---------------- Finally, let is the interesting case --------------------+specExpr env (Let bind body)+ = do { -- Clone binders+ (rhs_env, body_env, bind') <- cloneBindSM env bind++ -- Deal with the body+ ; (body', body_uds) <- specExpr body_env body++ -- Deal with the bindings+ ; (binds', uds) <- specBind rhs_env bind' body_uds++ -- All done+ ; return (foldr Let body' binds', uds) }++specTickish :: SpecEnv -> Tickish Id -> Tickish Id+specTickish env (Breakpoint ix ids)+ = Breakpoint ix [ id' | id <- ids, Var id' <- [specVar env id]]+ -- drop vars from the list if they have a non-variable substitution.+ -- should never happen, but it's harmless to drop them anyway.+specTickish _ other_tickish = other_tickish++specCase :: SpecEnv+ -> CoreExpr -- Scrutinee, already done+ -> Id -> [CoreAlt]+ -> SpecM ( CoreExpr -- New scrutinee+ , Id+ , [CoreAlt]+ , UsageDetails)+specCase env scrut' case_bndr [(con, args, rhs)]+ | isDictId case_bndr -- See Note [Floating dictionaries out of cases]+ , interestingDict env scrut'+ , not (isDeadBinder case_bndr && null sc_args')+ = do { (case_bndr_flt : sc_args_flt) <- mapM clone_me (case_bndr' : sc_args')++ ; let sc_rhss = [ Case (Var case_bndr_flt) case_bndr' (idType sc_arg')+ [(con, args', Var sc_arg')]+ | sc_arg' <- sc_args' ]++ -- Extend the substitution for RHS to map the *original* binders+ -- to their floated verions.+ mb_sc_flts :: [Maybe DictId]+ mb_sc_flts = map (lookupVarEnv clone_env) args'+ clone_env = zipVarEnv sc_args' sc_args_flt+ subst_prs = (case_bndr, Var case_bndr_flt)+ : [ (arg, Var sc_flt)+ | (arg, Just sc_flt) <- args `zip` mb_sc_flts ]+ env_rhs' = env_rhs { se_subst = CoreSubst.extendIdSubstList (se_subst env_rhs) subst_prs+ , se_interesting = se_interesting env_rhs `extendVarSetList`+ (case_bndr_flt : sc_args_flt) }++ ; (rhs', rhs_uds) <- specExpr env_rhs' rhs+ ; let scrut_bind = mkDB (NonRec case_bndr_flt scrut')+ case_bndr_set = unitVarSet case_bndr_flt+ sc_binds = [(NonRec sc_arg_flt sc_rhs, case_bndr_set)+ | (sc_arg_flt, sc_rhs) <- sc_args_flt `zip` sc_rhss ]+ flt_binds = scrut_bind : sc_binds+ (free_uds, dumped_dbs) = dumpUDs (case_bndr':args') rhs_uds+ all_uds = flt_binds `addDictBinds` free_uds+ alt' = (con, args', wrapDictBindsE dumped_dbs rhs')+ ; return (Var case_bndr_flt, case_bndr', [alt'], all_uds) }+ where+ (env_rhs, (case_bndr':args')) = substBndrs env (case_bndr:args)+ sc_args' = filter is_flt_sc_arg args'++ clone_me bndr = do { uniq <- getUniqueM+ ; return (mkUserLocalOrCoVar occ uniq ty loc) }+ where+ name = idName bndr+ ty = idType bndr+ occ = nameOccName name+ loc = getSrcSpan name++ arg_set = mkVarSet args'+ is_flt_sc_arg var = isId var+ && not (isDeadBinder var)+ && isDictTy var_ty+ && not (tyCoVarsOfType var_ty `intersectsVarSet` arg_set)+ where+ var_ty = idType var+++specCase env scrut case_bndr alts+ = do { (alts', uds_alts) <- mapAndCombineSM spec_alt alts+ ; return (scrut, case_bndr', alts', uds_alts) }+ where+ (env_alt, case_bndr') = substBndr env case_bndr+ spec_alt (con, args, rhs) = do+ (rhs', uds) <- specExpr env_rhs rhs+ let (free_uds, dumped_dbs) = dumpUDs (case_bndr' : args') uds+ return ((con, args', wrapDictBindsE dumped_dbs rhs'), free_uds)+ where+ (env_rhs, args') = substBndrs env_alt args++{-+Note [Floating dictionaries out of cases]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ g = \d. case d of { MkD sc ... -> ...(f sc)... }+Naively we can't float d2's binding out of the case expression,+because 'sc' is bound by the case, and that in turn means we can't+specialise f, which seems a pity.++So we invert the case, by floating out a binding+for 'sc_flt' thus:+ sc_flt = case d of { MkD sc ... -> sc }+Now we can float the call instance for 'f'. Indeed this is just+what'll happen if 'sc' was originally bound with a let binding,+but case is more efficient, and necessary with equalities. So it's+good to work with both.++You might think that this won't make any difference, because the+call instance will only get nuked by the \d. BUT if 'g' itself is+specialised, then transitively we should be able to specialise f.++In general, given+ case e of cb { MkD sc ... -> ...(f sc)... }+we transform to+ let cb_flt = e+ sc_flt = case cb_flt of { MkD sc ... -> sc }+ in+ case cb_flt of bg { MkD sc ... -> ....(f sc_flt)... }++The "_flt" things are the floated binds; we use the current substitution+to substitute sc -> sc_flt in the RHS++************************************************************************+* *+ Dealing with a binding+* *+************************************************************************+-}++specBind :: SpecEnv -- Use this for RHSs+ -> CoreBind -- Binders are already cloned by cloneBindSM,+ -- but RHSs are un-processed+ -> UsageDetails -- Info on how the scope of the binding+ -> SpecM ([CoreBind], -- New bindings+ UsageDetails) -- And info to pass upstream++-- Returned UsageDetails:+-- No calls for binders of this bind+specBind rhs_env (NonRec fn rhs) body_uds+ = do { (rhs', rhs_uds) <- specExpr rhs_env rhs+ ; (fn', spec_defns, body_uds1) <- specDefn rhs_env body_uds fn rhs++ ; let pairs = spec_defns ++ [(fn', rhs')]+ -- fn' mentions the spec_defns in its rules,+ -- so put the latter first++ combined_uds = body_uds1 `plusUDs` rhs_uds++ (free_uds, dump_dbs, float_all) = dumpBindUDs [fn] combined_uds++ final_binds :: [DictBind]+ -- See Note [From non-recursive to recursive]+ final_binds+ | not (isEmptyBag dump_dbs)+ , not (null spec_defns)+ = [recWithDumpedDicts pairs dump_dbs]+ | otherwise+ = [mkDB $ NonRec b r | (b,r) <- pairs]+ ++ bagToList dump_dbs++ ; if float_all then+ -- Rather than discard the calls mentioning the bound variables+ -- we float this (dictionary) binding along with the others+ return ([], free_uds `snocDictBinds` final_binds)+ else+ -- No call in final_uds mentions bound variables,+ -- so we can just leave the binding here+ return (map fst final_binds, free_uds) }+++specBind rhs_env (Rec pairs) body_uds+ -- Note [Specialising a recursive group]+ = do { let (bndrs,rhss) = unzip pairs+ ; (rhss', rhs_uds) <- mapAndCombineSM (specExpr rhs_env) rhss+ ; let scope_uds = body_uds `plusUDs` rhs_uds+ -- Includes binds and calls arising from rhss++ ; (bndrs1, spec_defns1, uds1) <- specDefns rhs_env scope_uds pairs++ ; (bndrs3, spec_defns3, uds3)+ <- if null spec_defns1 -- Common case: no specialisation+ then return (bndrs1, [], uds1)+ else do { -- Specialisation occurred; do it again+ (bndrs2, spec_defns2, uds2)+ <- specDefns rhs_env uds1 (bndrs1 `zip` rhss)+ ; return (bndrs2, spec_defns2 ++ spec_defns1, uds2) }++ ; let (final_uds, dumped_dbs, float_all) = dumpBindUDs bndrs uds3+ final_bind = recWithDumpedDicts (spec_defns3 ++ zip bndrs3 rhss')+ dumped_dbs++ ; if float_all then+ return ([], final_uds `snocDictBind` final_bind)+ else+ return ([fst final_bind], final_uds) }+++---------------------------+specDefns :: SpecEnv+ -> UsageDetails -- Info on how it is used in its scope+ -> [(OutId,InExpr)] -- The things being bound and their un-processed RHS+ -> SpecM ([OutId], -- Original Ids with RULES added+ [(OutId,OutExpr)], -- Extra, specialised bindings+ UsageDetails) -- Stuff to fling upwards from the specialised versions++-- Specialise a list of bindings (the contents of a Rec), but flowing usages+-- upwards binding by binding. Example: { f = ...g ...; g = ...f .... }+-- Then if the input CallDetails has a specialised call for 'g', whose specialisation+-- in turn generates a specialised call for 'f', we catch that in this one sweep.+-- But not vice versa (it's a fixpoint problem).++specDefns _env uds []+ = return ([], [], uds)+specDefns env uds ((bndr,rhs):pairs)+ = do { (bndrs1, spec_defns1, uds1) <- specDefns env uds pairs+ ; (bndr1, spec_defns2, uds2) <- specDefn env uds1 bndr rhs+ ; return (bndr1 : bndrs1, spec_defns1 ++ spec_defns2, uds2) }++---------------------------+specDefn :: SpecEnv+ -> UsageDetails -- Info on how it is used in its scope+ -> OutId -> InExpr -- The thing being bound and its un-processed RHS+ -> SpecM (Id, -- Original Id with added RULES+ [(Id,CoreExpr)], -- Extra, specialised bindings+ UsageDetails) -- Stuff to fling upwards from the specialised versions++specDefn env body_uds fn rhs+ = do { let (body_uds_without_me, calls_for_me) = callsForMe fn body_uds+ rules_for_me = idCoreRules fn+ ; (rules, spec_defns, spec_uds) <- specCalls Nothing env rules_for_me+ calls_for_me fn rhs+ ; return ( fn `addIdSpecialisations` rules+ , spec_defns+ , body_uds_without_me `plusUDs` spec_uds) }+ -- It's important that the `plusUDs` is this way+ -- round, because body_uds_without_me may bind+ -- dictionaries that are used in calls_for_me passed+ -- to specDefn. So the dictionary bindings in+ -- spec_uds may mention dictionaries bound in+ -- body_uds_without_me++---------------------------+specCalls :: Maybe Module -- Just this_mod => specialising imported fn+ -- Nothing => specialising local fn+ -> SpecEnv+ -> [CoreRule] -- Existing RULES for the fn+ -> [CallInfo]+ -> OutId -> InExpr+ -> SpecM SpecInfo -- New rules, specialised bindings, and usage details++-- This function checks existing rules, and does not create+-- duplicate ones. So the caller does not need to do this filtering.+-- See 'already_covered'++type SpecInfo = ( [CoreRule] -- Specialisation rules+ , [(Id,CoreExpr)] -- Specialised definition+ , UsageDetails ) -- Usage details from specialised RHSs++specCalls mb_mod env existing_rules calls_for_me fn rhs+ -- The first case is the interesting one+ | rhs_tyvars `lengthIs` n_tyvars -- Rhs of fn's defn has right number of big lambdas+ && rhs_bndrs1 `lengthAtLeast` n_dicts -- and enough dict args+ && notNull calls_for_me -- And there are some calls to specialise+ && not (isNeverActive (idInlineActivation fn))+ -- Don't specialise NOINLINE things+ -- See Note [Auto-specialisation and RULES]++-- && not (certainlyWillInline (idUnfolding fn)) -- And it's not small+-- See Note [Inline specialisation] for why we do not+-- switch off specialisation for inline functions++ = -- pprTrace "specDefn: some" (ppr fn $$ ppr calls_for_me $$ ppr existing_rules) $+ foldlM spec_call ([], [], emptyUDs) calls_for_me++ | otherwise -- No calls or RHS doesn't fit our preconceptions+ = WARN( not (exprIsTrivial rhs) && notNull calls_for_me,+ text "Missed specialisation opportunity for"+ <+> ppr fn $$ _trace_doc )+ -- Note [Specialisation shape]+ -- pprTrace "specDefn: none" (ppr fn <+> ppr calls_for_me) $+ return ([], [], emptyUDs)+ where+ _trace_doc = sep [ ppr rhs_tyvars, ppr n_tyvars+ , ppr rhs_bndrs, ppr n_dicts+ , ppr (idInlineActivation fn) ]++ fn_type = idType fn+ fn_arity = idArity fn+ fn_unf = realIdUnfolding fn -- Ignore loop-breaker-ness here+ (tyvars, theta, _) = tcSplitSigmaTy fn_type+ n_tyvars = length tyvars+ n_dicts = length theta+ inl_prag = idInlinePragma fn+ inl_act = inlinePragmaActivation inl_prag+ is_local = isLocalId fn++ -- Figure out whether the function has an INLINE pragma+ -- See Note [Inline specialisations]++ (rhs_bndrs, rhs_body) = collectBindersPushingCo rhs+ -- See Note [Account for casts in binding]+ (rhs_tyvars, rhs_bndrs1) = span isTyVar rhs_bndrs+ (rhs_dict_ids, rhs_bndrs2) = splitAt n_dicts rhs_bndrs1+ body = mkLams rhs_bndrs2 rhs_body+ -- Glue back on the non-dict lambdas++ in_scope = CoreSubst.substInScope (se_subst env)++ already_covered :: DynFlags -> [CoreRule] -> [CoreExpr] -> Bool+ already_covered dflags new_rules args -- Note [Specialisations already covered]+ = isJust (lookupRule dflags (in_scope, realIdUnfolding)+ (const True) fn args+ (new_rules ++ existing_rules))+ -- NB: we look both in the new_rules (generated by this invocation+ -- of specCalls), and in existing_rules (passed in to specCalls)++ mk_ty_args :: [Maybe Type] -> [TyVar] -> [CoreExpr]+ mk_ty_args [] poly_tvs+ = ASSERT( null poly_tvs ) []+ mk_ty_args (Nothing : call_ts) (poly_tv : poly_tvs)+ = Type (mkTyVarTy poly_tv) : mk_ty_args call_ts poly_tvs+ mk_ty_args (Just ty : call_ts) poly_tvs+ = Type ty : mk_ty_args call_ts poly_tvs+ mk_ty_args (Nothing : _) [] = panic "mk_ty_args"++ ----------------------------------------------------------+ -- Specialise to one particular call pattern+ spec_call :: SpecInfo -- Accumulating parameter+ -> CallInfo -- Call instance+ -> SpecM SpecInfo+ spec_call spec_acc@(rules_acc, pairs_acc, uds_acc)+ (CI { ci_key = CallKey call_ts, ci_args = call_ds })+ = ASSERT( call_ts `lengthIs` n_tyvars && call_ds `lengthIs` n_dicts )++ -- Suppose f's defn is f = /\ a b c -> \ d1 d2 -> rhs+ -- Suppose the call is for f [Just t1, Nothing, Just t3] [dx1, dx2]++ -- Construct the new binding+ -- f1 = SUBST[a->t1,c->t3, d1->d1', d2->d2'] (/\ b -> rhs)+ -- PLUS the rule+ -- RULE "SPEC f" forall b d1' d2'. f b d1' d2' = f1 b+ -- In the rule, d1' and d2' are just wildcards, not used in the RHS+ -- PLUS the usage-details+ -- { d1' = dx1; d2' = dx2 }+ -- where d1', d2' are cloned versions of d1,d2, with the type substitution+ -- applied. These auxiliary bindings just avoid duplication of dx1, dx2+ --+ -- Note that the substitution is applied to the whole thing.+ -- This is convenient, but just slightly fragile. Notably:+ -- * There had better be no name clashes in a/b/c+ do { let+ -- poly_tyvars = [b] in the example above+ -- spec_tyvars = [a,c]+ -- ty_args = [t1,b,t3]+ spec_tv_binds = [(tv,ty) | (tv, Just ty) <- rhs_tyvars `zip` call_ts]+ env1 = extendTvSubstList env spec_tv_binds+ (rhs_env, poly_tyvars) = substBndrs env1+ [tv | (tv, Nothing) <- rhs_tyvars `zip` call_ts]++ -- Clone rhs_dicts, including instantiating their types+ ; inst_dict_ids <- mapM (newDictBndr rhs_env) rhs_dict_ids+ ; let (rhs_env2, dx_binds, spec_dict_args)+ = bindAuxiliaryDicts rhs_env rhs_dict_ids call_ds inst_dict_ids+ ty_args = mk_ty_args call_ts poly_tyvars+ ev_args = map varToCoreExpr inst_dict_ids -- ev_args, ev_bndrs:+ ev_bndrs = exprsFreeIdsList ev_args -- See Note [Evidence foralls]+ rule_args = ty_args ++ ev_args+ rule_bndrs = poly_tyvars ++ ev_bndrs++ ; dflags <- getDynFlags+ ; if already_covered dflags rules_acc rule_args+ then return spec_acc+ else -- pprTrace "spec_call" (vcat [ ppr _call_info, ppr fn, ppr rhs_dict_ids+ -- , text "rhs_env2" <+> ppr (se_subst rhs_env2)+ -- , ppr dx_binds ]) $+ do+ { -- Figure out the type of the specialised function+ let body_ty = applyTypeToArgs rhs fn_type rule_args+ (lam_args, app_args) -- Add a dummy argument if body_ty is unlifted+ | isUnliftedType body_ty -- C.f. WwLib.mkWorkerArgs+ , not (isJoinId fn)+ = (poly_tyvars ++ [voidArgId], poly_tyvars ++ [voidPrimId])+ | otherwise = (poly_tyvars, poly_tyvars)+ spec_id_ty = mkLamTypes lam_args body_ty+ join_arity_change = length app_args - length rule_args+ spec_join_arity | Just orig_join_arity <- isJoinId_maybe fn+ = Just (orig_join_arity + join_arity_change)+ | otherwise+ = Nothing++ ; spec_f <- newSpecIdSM fn spec_id_ty spec_join_arity+ ; (spec_rhs, rhs_uds) <- specExpr rhs_env2 (mkLams lam_args body)+ ; this_mod <- getModule+ ; let+ -- The rule to put in the function's specialisation is:+ -- forall b, d1',d2'. f t1 b t3 d1' d2' = f1 b+ herald = case mb_mod of+ Nothing -- Specialising local fn+ -> text "SPEC"+ Just this_mod -- Specialising imoprted fn+ -> text "SPEC/" <> ppr this_mod++ rule_name = mkFastString $ showSDoc dflags $+ herald <+> ftext (occNameFS (getOccName fn))+ <+> hsep (map ppr_call_key_ty call_ts)+ -- This name ends up in interface files, so use occNameString.+ -- Otherwise uniques end up there, making builds+ -- less deterministic (See #4012 comment:61 ff)++ rule_wout_eta = mkRule+ this_mod+ True {- Auto generated -}+ is_local+ rule_name+ inl_act -- Note [Auto-specialisation and RULES]+ (idName fn)+ rule_bndrs+ rule_args+ (mkVarApps (Var spec_f) app_args)++ spec_rule+ = case isJoinId_maybe fn of+ Just join_arity -> etaExpandToJoinPointRule join_arity+ rule_wout_eta+ Nothing -> rule_wout_eta++ -- Add the { d1' = dx1; d2' = dx2 } usage stuff+ spec_uds = foldr consDictBind rhs_uds dx_binds++ --------------------------------------+ -- Add a suitable unfolding if the spec_inl_prag says so+ -- See Note [Inline specialisations]+ (spec_inl_prag, spec_unf)+ | not is_local && isStrongLoopBreaker (idOccInfo fn)+ = (neverInlinePragma, noUnfolding)+ -- See Note [Specialising imported functions] in OccurAnal++ | InlinePragma { inl_inline = Inlinable } <- inl_prag+ = (inl_prag { inl_inline = EmptyInlineSpec }, noUnfolding)++ | otherwise+ = (inl_prag, specUnfolding poly_tyvars spec_app+ arity_decrease fn_unf)++ arity_decrease = length spec_dict_args+ spec_app e = (e `mkApps` ty_args) `mkApps` spec_dict_args++ --------------------------------------+ -- Adding arity information just propagates it a bit faster+ -- See Note [Arity decrease] in Simplify+ -- Copy InlinePragma information from the parent Id.+ -- So if f has INLINE[1] so does spec_f+ spec_f_w_arity = spec_f `setIdArity` max 0 (fn_arity - n_dicts)+ `setInlinePragma` spec_inl_prag+ `setIdUnfolding` spec_unf+ `asJoinId_maybe` spec_join_arity++ ; return ( spec_rule : rules_acc+ , (spec_f_w_arity, spec_rhs) : pairs_acc+ , spec_uds `plusUDs` uds_acc+ ) } }++{- Note [Account for casts in binding]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f :: Eq a => a -> IO ()+ {-# INLINABLE f+ StableUnf = (/\a \(d:Eq a) (x:a). blah) |> g+ #-}+ f = ...++In f's stable unfolding we have done some modest simplification which+has pushed the cast to the outside. (I wonder if this is the Right+Thing, but it's what happens now; see SimplUtils Note [Casts and+lambdas].) Now that stable unfolding must be specialised, so we want+to push the cast back inside. It would be terrible if the cast+defeated specialisation! Hence the use of collectBindersPushingCo.++Note [Evidence foralls]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose (Trac #12212) that we are specialising+ f :: forall a b. (Num a, F a ~ F b) => blah+with a=b=Int. Then the RULE will be something like+ RULE forall (d:Num Int) (g :: F Int ~ F Int).+ f Int Int d g = f_spec+But both varToCoreExpr (when constructing the LHS args), and the+simplifier (when simplifying the LHS args), will transform to+ RULE forall (d:Num Int) (g :: F Int ~ F Int).+ f Int Int d <F Int> = f_spec+by replacing g with Refl. So now 'g' is unbound, which results in a later+crash. So we use Refl right off the bat, and do not forall-quantify 'g':+ * varToCoreExpr generates a Refl+ * exprsFreeIdsList returns the Ids bound by the args,+ which won't include g++You might wonder if this will match as often, but the simplifier replaces+complicated Refl coercions with Refl pretty aggressively.++Note [Orphans and auto-generated rules]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we specialise an INLINABLE function, or when we have+-fspecialise-aggressively, we auto-generate RULES that are orphans.+We don't want to warn about these, or we'd generate a lot of warnings.+Thus, we only warn about user-specified orphan rules.++Indeed, we don't even treat the module as an orphan module if it has+auto-generated *rule* orphans. Orphan modules are read every time we+compile, so they are pretty obtrusive and slow down every compilation,+even non-optimised ones. (Reason: for type class instances it's a+type correctness issue.) But specialisation rules are strictly for+*optimisation* only so it's fine not to read the interface.++What this means is that a SPEC rules from auto-specialisation in+module M will be used in other modules only if M.hi has been read for+some other reason, which is actually pretty likely.+-}++bindAuxiliaryDicts+ :: SpecEnv+ -> [DictId] -> [CoreExpr] -- Original dict bndrs, and the witnessing expressions+ -> [DictId] -- A cloned dict-id for each dict arg+ -> (SpecEnv, -- Substitute for all orig_dicts+ [DictBind], -- Auxiliary dict bindings+ [CoreExpr]) -- Witnessing expressions (all trivial)+-- Bind any dictionary arguments to fresh names, to preserve sharing+bindAuxiliaryDicts env@(SE { se_subst = subst, se_interesting = interesting })+ orig_dict_ids call_ds inst_dict_ids+ = (env', dx_binds, spec_dict_args)+ where+ (dx_binds, spec_dict_args) = go call_ds inst_dict_ids+ env' = env { se_subst = subst `CoreSubst.extendSubstList`+ (orig_dict_ids `zip` spec_dict_args)+ `CoreSubst.extendInScopeList` dx_ids+ , se_interesting = interesting `unionVarSet` interesting_dicts }++ dx_ids = [dx_id | (NonRec dx_id _, _) <- dx_binds]+ interesting_dicts = mkVarSet [ dx_id | (NonRec dx_id dx, _) <- dx_binds+ , interestingDict env dx ]+ -- See Note [Make the new dictionaries interesting]++ go :: [CoreExpr] -> [CoreBndr] -> ([DictBind], [CoreExpr])+ go [] _ = ([], [])+ go (dx:dxs) (dx_id:dx_ids)+ | exprIsTrivial dx = (dx_binds, dx : args)+ | otherwise = (mkDB (NonRec dx_id dx) : dx_binds, Var dx_id : args)+ where+ (dx_binds, args) = go dxs dx_ids+ -- In the first case extend the substitution but not bindings;+ -- in the latter extend the bindings but not the substitution.+ -- For the former, note that we bind the *original* dict in the substitution,+ -- overriding any d->dx_id binding put there by substBndrs+ go _ _ = pprPanic "bindAuxiliaryDicts" (ppr orig_dict_ids $$ ppr call_ds $$ ppr inst_dict_ids)++{-+Note [Make the new dictionaries interesting]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Important! We're going to substitute dx_id1 for d+and we want it to look "interesting", else we won't gather *any*+consequential calls. E.g.+ f d = ...g d....+If we specialise f for a call (f (dfun dNumInt)), we'll get+a consequent call (g d') with an auxiliary definition+ d' = df dNumInt+We want that consequent call to look interesting+++Note [From non-recursive to recursive]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Even in the non-recursive case, if any dict-binds depend on 'fn' we might+have built a recursive knot++ f a d x = <blah>+ MkUD { ud_binds = NonRec d7 (MkD ..f..)+ , ud_calls = ...(f T d7)... }++The we generate++ Rec { fs x = <blah>[T/a, d7/d]+ f a d x = <blah>+ RULE f T _ = fs+ d7 = ...f... }++Here the recursion is only through the RULE.++However we definitely should /not/ make the Rec in this wildly common+case:+ d = ...+ MkUD { ud_binds = NonRec d7 (...d...)+ , ud_calls = ...(f T d7)... }++Here we want simply to add d to the floats, giving+ MkUD { ud_binds = NonRec d (...)+ NonRec d7 (...d...)+ , ud_calls = ...(f T d7)... }++In general, we need only make this Rec if+ - there are some specialisations (spec_binds non-empty)+ - there are some dict_binds that depend on f (dump_dbs non-empty)++Note [Avoiding loops]+~~~~~~~~~~~~~~~~~~~~~+When specialising /dictionary functions/ we must be very careful to+avoid building loops. Here is an example that bit us badly: Trac #3591++ class Eq a => C a+ instance Eq [a] => C [a]++This translates to+ dfun :: Eq [a] -> C [a]+ dfun a d = MkD a d (meth d)++ d4 :: Eq [T] = <blah>+ d2 :: C [T] = dfun T d4+ d1 :: Eq [T] = $p1 d2+ d3 :: C [T] = dfun T d1++None of these definitions is recursive. What happened was that we+generated a specialisation:++ RULE forall d. dfun T d = dT :: C [T]+ dT = (MkD a d (meth d)) [T/a, d1/d]+ = MkD T d1 (meth d1)++But now we use the RULE on the RHS of d2, to get++ d2 = dT = MkD d1 (meth d1)+ d1 = $p1 d2++and now d1 is bottom! The problem is that when specialising 'dfun' we+should first dump "below" the binding all floated dictionary bindings+that mention 'dfun' itself. So d2 and d3 (and hence d1) must be+placed below 'dfun', and thus unavailable to it when specialising+'dfun'. That in turn means that the call (dfun T d1) must be+discarded. On the other hand, the call (dfun T d4) is fine, assuming+d4 doesn't mention dfun.++Solution:+ Discard all calls that mention dictionaries that depend+ (directly or indirectly) on the dfun we are specialising.+ This is done by 'filterCalls'++--------------+Here's another example, this time for an imported dfun, so the call+to filterCalls is in specImports (Trac #13429). Suppose we have+ class Monoid v => C v a where ...++We start with a call+ f @ [Integer] @ Integer $fC[]Integer++Specialising call to 'f' gives dict bindings+ $dMonoid_1 :: Monoid [Integer]+ $dMonoid_1 = M.$p1C @ [Integer] $fC[]Integer++ $dC_1 :: C [Integer] (Node [Integer] Integer)+ $dC_1 = M.$fCvNode @ [Integer] $dMonoid_1++...plus a recursive call to+ f @ [Integer] @ (Node [Integer] Integer) $dC_1++Specialising that call gives+ $dMonoid_2 :: Monoid [Integer]+ $dMonoid_2 = M.$p1C @ [Integer] $dC_1++ $dC_2 :: C [Integer] (Node [Integer] Integer)+ $dC_2 = M.$fCvNode @ [Integer] $dMonoid_2++Now we have two calls to the imported function+ M.$fCvNode :: Monoid v => C v a+ M.$fCvNode @v @a m = C m some_fun++But we must /not/ use the call (M.$fCvNode @ [Integer] $dMonoid_2)+for specialisation, else we get:++ $dC_1 = M.$fCvNode @ [Integer] $dMonoid_1+ $dMonoid_2 = M.$p1C @ [Integer] $dC_1+ $s$fCvNode = C $dMonoid_2 ...+ RULE M.$fCvNode [Integer] _ _ = $s$fCvNode++Now use the rule to rewrite the call in the RHS of $dC_1+and we get a loop!++--------------+Here's yet another example++ class C a where { foo,bar :: [a] -> [a] }++ instance C Int where+ foo x = r_bar x+ bar xs = reverse xs++ r_bar :: C a => [a] -> [a]+ r_bar xs = bar (xs ++ xs)++That translates to:++ r_bar a (c::C a) (xs::[a]) = bar a d (xs ++ xs)++ Rec { $fCInt :: C Int = MkC foo_help reverse+ foo_help (xs::[Int]) = r_bar Int $fCInt xs }++The call (r_bar $fCInt) mentions $fCInt,+ which mentions foo_help,+ which mentions r_bar+But we DO want to specialise r_bar at Int:++ Rec { $fCInt :: C Int = MkC foo_help reverse+ foo_help (xs::[Int]) = r_bar Int $fCInt xs++ r_bar a (c::C a) (xs::[a]) = bar a d (xs ++ xs)+ RULE r_bar Int _ = r_bar_Int++ r_bar_Int xs = bar Int $fCInt (xs ++ xs)+ }++Note that, because of its RULE, r_bar joins the recursive+group. (In this case it'll unravel a short moment later.)+++Note [Specialising a recursive group]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ let rec { f x = ...g x'...+ ; g y = ...f y'.... }+ in f 'a'+Here we specialise 'f' at Char; but that is very likely to lead to+a specialisation of 'g' at Char. We must do the latter, else the+whole point of specialisation is lost.++But we do not want to keep iterating to a fixpoint, because in the+presence of polymorphic recursion we might generate an infinite number+of specialisations.++So we use the following heuristic:+ * Arrange the rec block in dependency order, so far as possible+ (the occurrence analyser already does this)++ * Specialise it much like a sequence of lets++ * Then go through the block a second time, feeding call-info from+ the RHSs back in the bottom, as it were++In effect, the ordering maxmimises the effectiveness of each sweep,+and we do just two sweeps. This should catch almost every case of+monomorphic recursion -- the exception could be a very knotted-up+recursion with multiple cycles tied up together.++This plan is implemented in the Rec case of specBindItself.++Note [Specialisations already covered]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We obviously don't want to generate two specialisations for the same+argument pattern. There are two wrinkles++1. We do the already-covered test in specDefn, not when we generate+the CallInfo in mkCallUDs. We used to test in the latter place, but+we now iterate the specialiser somewhat, and the Id at the call site+might therefore not have all the RULES that we can see in specDefn++2. What about two specialisations where the second is an *instance*+of the first? If the more specific one shows up first, we'll generate+specialisations for both. If the *less* specific one shows up first,+we *don't* currently generate a specialisation for the more specific+one. (See the call to lookupRule in already_covered.) Reasons:+ (a) lookupRule doesn't say which matches are exact (bad reason)+ (b) if the earlier specialisation is user-provided, it's+ far from clear that we should auto-specialise further++Note [Auto-specialisation and RULES]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider:+ g :: Num a => a -> a+ g = ...++ f :: (Int -> Int) -> Int+ f w = ...+ {-# RULE f g = 0 #-}++Suppose that auto-specialisation makes a specialised version of+g::Int->Int That version won't appear in the LHS of the RULE for f.+So if the specialisation rule fires too early, the rule for f may+never fire.++It might be possible to add new rules, to "complete" the rewrite system.+Thus when adding+ RULE forall d. g Int d = g_spec+also add+ RULE f g_spec = 0++But that's a bit complicated. For now we ask the programmer's help,+by *copying the INLINE activation pragma* to the auto-specialised+rule. So if g says {-# NOINLINE[2] g #-}, then the auto-spec rule+will also not be active until phase 2. And that's what programmers+should jolly well do anyway, even aside from specialisation, to ensure+that g doesn't inline too early.++This in turn means that the RULE would never fire for a NOINLINE+thing so not much point in generating a specialisation at all.++Note [Specialisation shape]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We only specialise a function if it has visible top-level lambdas+corresponding to its overloading. E.g. if+ f :: forall a. Eq a => ....+then its body must look like+ f = /\a. \d. ...++Reason: when specialising the body for a call (f ty dexp), we want to+substitute dexp for d, and pick up specialised calls in the body of f.++This doesn't always work. One example I came across was this:+ newtype Gen a = MkGen{ unGen :: Int -> a }++ choose :: Eq a => a -> Gen a+ choose n = MkGen (\r -> n)++ oneof = choose (1::Int)++It's a silly exapmle, but we get+ choose = /\a. g `cast` co+where choose doesn't have any dict arguments. Thus far I have not+tried to fix this (wait till there's a real example).++Mind you, then 'choose' will be inlined (since RHS is trivial) so+it doesn't matter. This comes up with single-method classes++ class C a where { op :: a -> a }+ instance C a => C [a] where ....+==>+ $fCList :: C a => C [a]+ $fCList = $copList |> (...coercion>...)+ ....(uses of $fCList at particular types)...++So we suppress the WARN if the rhs is trivial.++Note [Inline specialisations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is what we do with the InlinePragma of the original function+ * Activation/RuleMatchInfo: both transferred to the+ specialised function+ * InlineSpec:+ (a) An INLINE pragma is transferred+ (b) An INLINABLE pragma is *not* transferred++Why (a): transfer INLINE pragmas? The point of INLINE was precisely to+specialise the function at its call site, and arguably that's not so+important for the specialised copies. BUT *pragma-directed*+specialisation now takes place in the typechecker/desugarer, with+manually specified INLINEs. The specialisation here is automatic.+It'd be very odd if a function marked INLINE was specialised (because+of some local use), and then forever after (including importing+modules) the specialised version wasn't INLINEd. After all, the+programmer said INLINE!++You might wonder why we specialise INLINE functions at all. After+all they should be inlined, right? Two reasons:++ * Even INLINE functions are sometimes not inlined, when they aren't+ applied to interesting arguments. But perhaps the type arguments+ alone are enough to specialise (even though the args are too boring+ to trigger inlining), and it's certainly better to call the+ specialised version.++ * The RHS of an INLINE function might call another overloaded function,+ and we'd like to generate a specialised version of that function too.+ This actually happens a lot. Consider+ replicateM_ :: (Monad m) => Int -> m a -> m ()+ {-# INLINABLE replicateM_ #-}+ replicateM_ d x ma = ...+ The strictness analyser may transform to+ replicateM_ :: (Monad m) => Int -> m a -> m ()+ {-# INLINE replicateM_ #-}+ replicateM_ d x ma = case x of I# x' -> $wreplicateM_ d x' ma++ $wreplicateM_ :: (Monad m) => Int# -> m a -> m ()+ {-# INLINABLE $wreplicateM_ #-}+ $wreplicateM_ = ...+ Now an importing module has a specialised call to replicateM_, say+ (replicateM_ dMonadIO). We certainly want to specialise $wreplicateM_!+ This particular example had a huge effect on the call to replicateM_+ in nofib/shootout/n-body.++Why (b): discard INLINABLE pragmas? See Trac #4874 for persuasive examples.+Suppose we have+ {-# INLINABLE f #-}+ f :: Ord a => [a] -> Int+ f xs = letrec f' = ...f'... in f'+Then, when f is specialised and optimised we might get+ wgo :: [Int] -> Int#+ wgo = ...wgo...+ f_spec :: [Int] -> Int+ f_spec xs = case wgo xs of { r -> I# r }+and we clearly want to inline f_spec at call sites. But if we still+have the big, un-optimised of f (albeit specialised) captured in an+INLINABLE pragma for f_spec, we won't get that optimisation.++So we simply drop INLINABLE pragmas when specialising. It's not really+a complete solution; ignoring specialisation for now, INLINABLE functions+don't get properly strictness analysed, for example. But it works well+for examples involving specialisation, which is the dominant use of+INLINABLE. See Trac #4874.+++************************************************************************+* *+\subsubsection{UsageDetails and suchlike}+* *+************************************************************************+-}++data UsageDetails+ = MkUD {+ ud_binds :: !(Bag DictBind),+ -- See Note [Floated dictionary bindings]+ -- The order is important;+ -- in ds1 `union` ds2, bindings in ds2 can depend on those in ds1+ -- (Remember, Bags preserve order in GHC.)++ ud_calls :: !CallDetails++ -- INVARIANT: suppose bs = bindersOf ud_binds+ -- Then 'calls' may *mention* 'bs',+ -- but there should be no calls *for* bs+ }++-- | A 'DictBind' is a binding along with a cached set containing its free+-- variables (both type variables and dictionaries)+type DictBind = (CoreBind, VarSet)++{- Note [Floated dictionary bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We float out dictionary bindings for the reasons described under+"Dictionary floating" above. But not /just/ dictionary bindings.+Consider++ f :: Eq a => blah+ f a d = rhs++ $c== :: T -> T -> Bool+ $c== x y = ...++ $df :: Eq T+ $df = Eq $c== ...++ gurgle = ...(f @T $df)...++We gather the call info for (f @T $df), and we don't want to drop it+when we come across the binding for $df. So we add $df to the floats+and continue. But then we have to add $c== to the floats, and so on.+These all float above the binding for 'f', and and now we can+successfullly specialise 'f'.++So the DictBinds in (ud_binds :: Bag DictBind) may contain+non-dictionary bindings too.+-}++instance Outputable UsageDetails where+ ppr (MkUD { ud_binds = dbs, ud_calls = calls })+ = text "MkUD" <+> braces (sep (punctuate comma+ [text "binds" <+> equals <+> ppr dbs,+ text "calls" <+> equals <+> ppr calls]))++emptyUDs :: UsageDetails+emptyUDs = MkUD { ud_binds = emptyBag, ud_calls = emptyDVarEnv }++------------------------------------------------------------+type CallDetails = DIdEnv CallInfoSet+ -- The order of specialized binds and rules depends on how we linearize+ -- CallDetails, so to get determinism we must use a deterministic set here.+ -- See Note [Deterministic UniqFM] in UniqDFM++data CallInfoSet = CIS Id (Bag CallInfo)+ -- The list of types and dictionaries is guaranteed to+ -- match the type of f+ -- The Bag may contain duplicate calls (i.e. f @T and another f @T)+ -- These dups are eliminated by already_covered in specCalls++data CallInfo+ = CI { ci_key :: CallKey -- Type arguments+ , ci_args :: [DictExpr] -- Dictionary arguments+ , ci_fvs :: VarSet -- Free vars of the ci_key and ci_args+ -- call (including tyvars)+ -- [*not* include the main id itself, of course]+ }++newtype CallKey = CallKey [Maybe Type]+ -- Nothing => unconstrained type argument++type DictExpr = CoreExpr++ciSetFilter :: (CallInfo -> Bool) -> CallInfoSet -> CallInfoSet+ciSetFilter p (CIS id a) = CIS id (filterBag p a)++instance Outputable CallInfoSet where+ ppr (CIS fn map) = hang (text "CIS" <+> ppr fn)+ 2 (ppr map)++pprCallInfo :: Id -> CallInfo -> SDoc+pprCallInfo fn (CI { ci_key = key })+ = ppr fn <+> ppr key++ppr_call_key_ty :: Maybe Type -> SDoc+ppr_call_key_ty Nothing = char '_'+ppr_call_key_ty (Just ty) = char '@' <+> pprParendType ty++instance Outputable CallKey where+ ppr (CallKey ts) = brackets (fsep (map ppr_call_key_ty ts))++instance Outputable CallInfo where+ ppr (CI { ci_key = key, ci_args = args, ci_fvs = fvs })+ = text "CI" <> braces (hsep [ ppr key, ppr args, ppr fvs ])++unionCalls :: CallDetails -> CallDetails -> CallDetails+unionCalls c1 c2 = plusDVarEnv_C unionCallInfoSet c1 c2++unionCallInfoSet :: CallInfoSet -> CallInfoSet -> CallInfoSet+unionCallInfoSet (CIS f calls1) (CIS _ calls2) =+ CIS f (calls1 `unionBags` calls2)++callDetailsFVs :: CallDetails -> VarSet+callDetailsFVs calls =+ nonDetFoldUDFM (unionVarSet . callInfoFVs) emptyVarSet calls+ -- It's OK to use nonDetFoldUDFM here because we forget the ordering+ -- immediately by converting to a nondeterministic set.++callInfoFVs :: CallInfoSet -> VarSet+callInfoFVs (CIS _ call_info) =+ foldrBag (\(CI { ci_fvs = fv }) vs -> unionVarSet fv vs) emptyVarSet call_info++------------------------------------------------------------+singleCall :: Id -> [Maybe Type] -> [DictExpr] -> UsageDetails+singleCall id tys dicts+ = MkUD {ud_binds = emptyBag,+ ud_calls = unitDVarEnv id $ CIS id $+ unitBag (CI { ci_key = CallKey tys+ , ci_args = dicts+ , ci_fvs = call_fvs }) }+ where+ call_fvs = exprsFreeVars dicts `unionVarSet` tys_fvs+ tys_fvs = tyCoVarsOfTypes (catMaybes tys)+ -- The type args (tys) are guaranteed to be part of the dictionary+ -- types, because they are just the constrained types,+ -- and the dictionary is therefore sure to be bound+ -- inside the binding for any type variables free in the type;+ -- hence it's safe to neglect tyvars free in tys when making+ -- the free-var set for this call+ -- BUT I don't trust this reasoning; play safe and include tys_fvs+ --+ -- We don't include the 'id' itself.++mkCallUDs, mkCallUDs' :: SpecEnv -> Id -> [CoreExpr] -> UsageDetails+mkCallUDs env f args+ = -- pprTrace "mkCallUDs" (vcat [ ppr f, ppr args, ppr res ])+ res+ where+ res = mkCallUDs' env f args++mkCallUDs' env f args+ | not (want_calls_for f) -- Imported from elsewhere+ || null theta -- Not overloaded+ = emptyUDs++ | not (all type_determines_value theta)+ || not (spec_tys `lengthIs` n_tyvars)+ || not ( dicts `lengthIs` n_dicts)+ || not (any (interestingDict env) dicts) -- Note [Interesting dictionary arguments]+ -- See also Note [Specialisations already covered]+ = -- pprTrace "mkCallUDs: discarding" _trace_doc+ emptyUDs -- Not overloaded, or no specialisation wanted++ | otherwise+ = -- pprTrace "mkCallUDs: keeping" _trace_doc+ singleCall f spec_tys dicts+ where+ _trace_doc = vcat [ppr f, ppr args, ppr n_tyvars, ppr n_dicts+ , ppr (map (interestingDict env) dicts)]+ (tyvars, theta, _) = tcSplitSigmaTy (idType f)+ constrained_tyvars = tyCoVarsOfTypes theta+ n_tyvars = length tyvars+ n_dicts = length theta++ spec_tys = [mk_spec_ty tv ty | (tv, ty) <- tyvars `type_zip` args]+ dicts = [dict_expr | (_, dict_expr) <- theta `zip` (drop n_tyvars args)]++ -- ignores Coercion arguments+ type_zip :: [TyVar] -> [CoreExpr] -> [(TyVar, Type)]+ type_zip tvs (Coercion _ : args) = type_zip tvs args+ type_zip (tv:tvs) (Type ty : args) = (tv, ty) : type_zip tvs args+ type_zip _ _ = []++ mk_spec_ty tyvar ty+ | tyvar `elemVarSet` constrained_tyvars = Just ty+ | otherwise = Nothing++ want_calls_for f = isLocalId f || isJust (maybeUnfoldingTemplate (realIdUnfolding f))+ -- For imported things, we gather call instances if+ -- there is an unfolding that we could in principle specialise+ -- We might still decide not to use it (consulting dflags)+ -- in specImports+ -- Use 'realIdUnfolding' to ignore the loop-breaker flag!++ type_determines_value pred -- See Note [Type determines value]+ = case classifyPredType pred of+ ClassPred cls _ -> not (isIPClass cls) -- Superclasses can't be IPs+ EqPred {} -> True+ IrredPred {} -> True -- Things like (D []) where D is a+ -- Constraint-ranged family; Trac #7785++{-+Note [Type determines value]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Only specialise if all overloading is on non-IP *class* params,+because these are the ones whose *type* determines their *value*. In+parrticular, with implicit params, the type args *don't* say what the+value of the implicit param is! See Trac #7101++However, consider+ type family D (v::*->*) :: Constraint+ type instance D [] = ()+ f :: D v => v Char -> Int+If we see a call (f "foo"), we'll pass a "dictionary"+ () |> (g :: () ~ D [])+and it's good to specialise f at this dictionary.++So the question is: can an implicit parameter "hide inside" a+type-family constraint like (D a). Well, no. We don't allow+ type instance D Maybe = ?x:Int+Hence the IrredPred case in type_determines_value.+See Trac #7785.++Note [Interesting dictionary arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ \a.\d:Eq a. let f = ... in ...(f d)...+There really is not much point in specialising f wrt the dictionary d,+because the code for the specialised f is not improved at all, because+d is lambda-bound. We simply get junk specialisations.++What is "interesting"? Just that it has *some* structure. But what about+variables?++ * A variable might be imported, in which case its unfolding+ will tell us whether it has useful structure++ * Local variables are cloned on the way down (to avoid clashes when+ we float dictionaries), and cloning drops the unfolding+ (cloneIdBndr). Moreover, we make up some new bindings, and it's a+ nuisance to give them unfoldings. So we keep track of the+ "interesting" dictionaries as a VarSet in SpecEnv.+ We have to take care to put any new interesting dictionary+ bindings in the set.++We accidentally lost accurate tracking of local variables for a long+time, because cloned variables don't have unfoldings. But makes a+massive difference in a few cases, eg Trac #5113. For nofib as a+whole it's only a small win: 2.2% improvement in allocation for ansi,+1.2% for bspt, but mostly 0.0! Average 0.1% increase in binary size.+-}++interestingDict :: SpecEnv -> CoreExpr -> Bool+-- A dictionary argument is interesting if it has *some* structure+-- NB: "dictionary" arguments include constraints of all sorts,+-- including equality constraints; hence the Coercion case+interestingDict env (Var v) = hasSomeUnfolding (idUnfolding v)+ || isDataConWorkId v+ || v `elemVarSet` se_interesting env+interestingDict _ (Type _) = False+interestingDict _ (Coercion _) = False+interestingDict env (App fn (Type _)) = interestingDict env fn+interestingDict env (App fn (Coercion _)) = interestingDict env fn+interestingDict env (Tick _ a) = interestingDict env a+interestingDict env (Cast e _) = interestingDict env e+interestingDict _ _ = True++plusUDs :: UsageDetails -> UsageDetails -> UsageDetails+plusUDs (MkUD {ud_binds = db1, ud_calls = calls1})+ (MkUD {ud_binds = db2, ud_calls = calls2})+ = MkUD { ud_binds = db1 `unionBags` db2+ , ud_calls = calls1 `unionCalls` calls2 }++-----------------------------+_dictBindBndrs :: Bag DictBind -> [Id]+_dictBindBndrs dbs = foldrBag ((++) . bindersOf . fst) [] dbs++-- | Construct a 'DictBind' from a 'CoreBind'+mkDB :: CoreBind -> DictBind+mkDB bind = (bind, bind_fvs bind)++-- | Identify the free variables of a 'CoreBind'+bind_fvs :: CoreBind -> VarSet+bind_fvs (NonRec bndr rhs) = pair_fvs (bndr,rhs)+bind_fvs (Rec prs) = foldl delVarSet rhs_fvs bndrs+ where+ bndrs = map fst prs+ rhs_fvs = unionVarSets (map pair_fvs prs)++pair_fvs :: (Id, CoreExpr) -> VarSet+pair_fvs (bndr, rhs) = exprSomeFreeVars interesting rhs+ `unionVarSet` idFreeVars bndr+ -- idFreeVars: don't forget variables mentioned in+ -- the rules of the bndr. C.f. OccAnal.addRuleUsage+ -- Also tyvars mentioned in its type; they may not appear+ -- in the RHS+ -- type T a = Int+ -- x :: T a = 3+ where+ interesting :: InterestingVarFun+ interesting v = isLocalVar v || (isId v && isDFunId v)+ -- Very important: include DFunIds /even/ if it is imported+ -- Reason: See Note [Avoiding loops], the second exmaple+ -- involving an imported dfun. We must know whether+ -- a dictionary binding depends on an imported dfun,+ -- in case we try to specialise that imported dfun+ -- Trac #13429 illustrates++-- | Flatten a set of "dumped" 'DictBind's, and some other binding+-- pairs, into a single recursive binding.+recWithDumpedDicts :: [(Id,CoreExpr)] -> Bag DictBind ->DictBind+recWithDumpedDicts pairs dbs+ = (Rec bindings, fvs)+ where+ (bindings, fvs) = foldrBag add+ ([], emptyVarSet)+ (dbs `snocBag` mkDB (Rec pairs))+ add (NonRec b r, fvs') (pairs, fvs) =+ ((b,r) : pairs, fvs `unionVarSet` fvs')+ add (Rec prs1, fvs') (pairs, fvs) =+ (prs1 ++ pairs, fvs `unionVarSet` fvs')++snocDictBinds :: UsageDetails -> [DictBind] -> UsageDetails+-- Add ud_binds to the tail end of the bindings in uds+snocDictBinds uds dbs+ = uds { ud_binds = ud_binds uds `unionBags` listToBag dbs }++consDictBind :: DictBind -> UsageDetails -> UsageDetails+consDictBind bind uds = uds { ud_binds = bind `consBag` ud_binds uds }++addDictBinds :: [DictBind] -> UsageDetails -> UsageDetails+addDictBinds binds uds = uds { ud_binds = listToBag binds `unionBags` ud_binds uds }++snocDictBind :: UsageDetails -> DictBind -> UsageDetails+snocDictBind uds bind = uds { ud_binds = ud_binds uds `snocBag` bind }++wrapDictBinds :: Bag DictBind -> [CoreBind] -> [CoreBind]+wrapDictBinds dbs binds+ = foldrBag add binds dbs+ where+ add (bind,_) binds = bind : binds++wrapDictBindsE :: Bag DictBind -> CoreExpr -> CoreExpr+wrapDictBindsE dbs expr+ = foldrBag add expr dbs+ where+ add (bind,_) expr = Let bind expr++----------------------+dumpUDs :: [CoreBndr] -> UsageDetails -> (UsageDetails, Bag DictBind)+-- Used at a lambda or case binder; just dump anything mentioning the binder+dumpUDs bndrs uds@(MkUD { ud_binds = orig_dbs, ud_calls = orig_calls })+ | null bndrs = (uds, emptyBag) -- Common in case alternatives+ | otherwise = -- pprTrace "dumpUDs" (ppr bndrs $$ ppr free_uds $$ ppr dump_dbs) $+ (free_uds, dump_dbs)+ where+ free_uds = MkUD { ud_binds = free_dbs, ud_calls = free_calls }+ bndr_set = mkVarSet bndrs+ (free_dbs, dump_dbs, dump_set) = splitDictBinds orig_dbs bndr_set+ free_calls = deleteCallsMentioning dump_set $ -- Drop calls mentioning bndr_set on the floor+ deleteCallsFor bndrs orig_calls -- Discard calls for bndr_set; there should be+ -- no calls for any of the dicts in dump_dbs++dumpBindUDs :: [CoreBndr] -> UsageDetails -> (UsageDetails, Bag DictBind, Bool)+-- Used at a let(rec) binding.+-- We return a boolean indicating whether the binding itself is mentioned+-- is mentioned, directly or indirectly, by any of the ud_calls; in that+-- case we want to float the binding itself;+-- See Note [Floated dictionary bindings]+dumpBindUDs bndrs (MkUD { ud_binds = orig_dbs, ud_calls = orig_calls })+ = -- pprTrace "dumpBindUDs" (ppr bndrs $$ ppr free_uds $$ ppr dump_dbs) $+ (free_uds, dump_dbs, float_all)+ where+ free_uds = MkUD { ud_binds = free_dbs, ud_calls = free_calls }+ bndr_set = mkVarSet bndrs+ (free_dbs, dump_dbs, dump_set) = splitDictBinds orig_dbs bndr_set+ free_calls = deleteCallsFor bndrs orig_calls+ float_all = dump_set `intersectsVarSet` callDetailsFVs free_calls++callsForMe :: Id -> UsageDetails -> (UsageDetails, [CallInfo])+callsForMe fn (MkUD { ud_binds = orig_dbs, ud_calls = orig_calls })+ = -- pprTrace ("callsForMe")+ -- (vcat [ppr fn,+ -- text "Orig dbs =" <+> ppr (_dictBindBndrs orig_dbs),+ -- text "Orig calls =" <+> ppr orig_calls,+ -- text "Dep set =" <+> ppr dep_set,+ -- text "Calls for me =" <+> ppr calls_for_me]) $+ (uds_without_me, calls_for_me)+ where+ uds_without_me = MkUD { ud_binds = orig_dbs+ , ud_calls = delDVarEnv orig_calls fn }+ calls_for_me = case lookupDVarEnv orig_calls fn of+ Nothing -> []+ Just cis -> filterCalls cis orig_dbs+ -- filterCalls: drop calls that (directly or indirectly)+ -- refer to fn. See Note [Avoiding loops]++----------------------+filterCalls :: CallInfoSet -> Bag DictBind -> [CallInfo]+-- See Note [Avoiding loops]+filterCalls (CIS fn call_bag) dbs+ = filter ok_call (bagToList call_bag)+ where+ dump_set = foldlBag go (unitVarSet fn) dbs+ -- This dump-set could also be computed by splitDictBinds+ -- (_,_,dump_set) = splitDictBinds dbs {fn}+ -- But this variant is shorter++ go so_far (db,fvs) | fvs `intersectsVarSet` so_far+ = extendVarSetList so_far (bindersOf db)+ | otherwise = so_far++ ok_call (CI { ci_fvs = fvs }) = not (fvs `intersectsVarSet` dump_set)++----------------------+splitDictBinds :: Bag DictBind -> IdSet -> (Bag DictBind, Bag DictBind, IdSet)+-- splitDictBinds dbs bndrs returns+-- (free_dbs, dump_dbs, dump_set)+-- where+-- * dump_dbs depends, transitively on bndrs+-- * free_dbs does not depend on bndrs+-- * dump_set = bndrs `union` bndrs(dump_dbs)+splitDictBinds dbs bndr_set+ = foldlBag split_db (emptyBag, emptyBag, bndr_set) dbs+ -- Important that it's foldl not foldr;+ -- we're accumulating the set of dumped ids in dump_set+ where+ split_db (free_dbs, dump_dbs, dump_idset) db@(bind, fvs)+ | dump_idset `intersectsVarSet` fvs -- Dump it+ = (free_dbs, dump_dbs `snocBag` db,+ extendVarSetList dump_idset (bindersOf bind))++ | otherwise -- Don't dump it+ = (free_dbs `snocBag` db, dump_dbs, dump_idset)+++----------------------+deleteCallsMentioning :: VarSet -> CallDetails -> CallDetails+-- Remove calls *mentioning* bs in any way+deleteCallsMentioning bs calls+ = mapDVarEnv (ciSetFilter keep_call) calls+ where+ keep_call (CI { ci_fvs = fvs }) = not (fvs `intersectsVarSet` bs)++deleteCallsFor :: [Id] -> CallDetails -> CallDetails+-- Remove calls *for* bs+deleteCallsFor bs calls = delDVarEnvList calls bs++{-+************************************************************************+* *+\subsubsection{Boring helper functions}+* *+************************************************************************+-}++newtype SpecM a = SpecM (State SpecState a)++data SpecState = SpecState {+ spec_uniq_supply :: UniqSupply,+ spec_module :: Module,+ spec_dflags :: DynFlags+ }++instance Functor SpecM where+ fmap = liftM++instance Applicative SpecM where+ pure x = SpecM $ return x+ (<*>) = ap++instance Monad SpecM where+ SpecM x >>= f = SpecM $ do y <- x+ case f y of+ SpecM z ->+ z+ fail str = SpecM $ fail str++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail SpecM where+ fail str = SpecM $ fail str+#endif++instance MonadUnique SpecM where+ getUniqueSupplyM+ = SpecM $ do st <- get+ let (us1, us2) = splitUniqSupply $ spec_uniq_supply st+ put $ st { spec_uniq_supply = us2 }+ return us1++ getUniqueM+ = SpecM $ do st <- get+ let (u,us') = takeUniqFromSupply $ spec_uniq_supply st+ put $ st { spec_uniq_supply = us' }+ return u++instance HasDynFlags SpecM where+ getDynFlags = SpecM $ liftM spec_dflags get++instance HasModule SpecM where+ getModule = SpecM $ liftM spec_module get++runSpecM :: DynFlags -> Module -> SpecM a -> CoreM a+runSpecM dflags this_mod (SpecM spec)+ = do us <- getUniqueSupplyM+ let initialState = SpecState {+ spec_uniq_supply = us,+ spec_module = this_mod,+ spec_dflags = dflags+ }+ return $ evalState spec initialState++mapAndCombineSM :: (a -> SpecM (b, UsageDetails)) -> [a] -> SpecM ([b], UsageDetails)+mapAndCombineSM _ [] = return ([], emptyUDs)+mapAndCombineSM f (x:xs) = do (y, uds1) <- f x+ (ys, uds2) <- mapAndCombineSM f xs+ return (y:ys, uds1 `plusUDs` uds2)++extendTvSubstList :: SpecEnv -> [(TyVar,Type)] -> SpecEnv+extendTvSubstList env tv_binds+ = env { se_subst = CoreSubst.extendTvSubstList (se_subst env) tv_binds }++substTy :: SpecEnv -> Type -> Type+substTy env ty = CoreSubst.substTy (se_subst env) ty++substCo :: SpecEnv -> Coercion -> Coercion+substCo env co = CoreSubst.substCo (se_subst env) co++substBndr :: SpecEnv -> CoreBndr -> (SpecEnv, CoreBndr)+substBndr env bs = case CoreSubst.substBndr (se_subst env) bs of+ (subst', bs') -> (env { se_subst = subst' }, bs')++substBndrs :: SpecEnv -> [CoreBndr] -> (SpecEnv, [CoreBndr])+substBndrs env bs = case CoreSubst.substBndrs (se_subst env) bs of+ (subst', bs') -> (env { se_subst = subst' }, bs')++cloneBindSM :: SpecEnv -> CoreBind -> SpecM (SpecEnv, SpecEnv, CoreBind)+-- Clone the binders of the bind; return new bind with the cloned binders+-- Return the substitution to use for RHSs, and the one to use for the body+cloneBindSM env@(SE { se_subst = subst, se_interesting = interesting }) (NonRec bndr rhs)+ = do { us <- getUniqueSupplyM+ ; let (subst', bndr') = CoreSubst.cloneIdBndr subst us bndr+ interesting' | interestingDict env rhs+ = interesting `extendVarSet` bndr'+ | otherwise = interesting+ ; return (env, env { se_subst = subst', se_interesting = interesting' }+ , NonRec bndr' rhs) }++cloneBindSM env@(SE { se_subst = subst, se_interesting = interesting }) (Rec pairs)+ = do { us <- getUniqueSupplyM+ ; let (subst', bndrs') = CoreSubst.cloneRecIdBndrs subst us (map fst pairs)+ env' = env { se_subst = subst'+ , se_interesting = interesting `extendVarSetList`+ [ v | (v,r) <- pairs, interestingDict env r ] }+ ; return (env', env', Rec (bndrs' `zip` map snd pairs)) }++newDictBndr :: SpecEnv -> CoreBndr -> SpecM CoreBndr+-- Make up completely fresh binders for the dictionaries+-- Their bindings are going to float outwards+newDictBndr env b = do { uniq <- getUniqueM+ ; let n = idName b+ ty' = substTy env (idType b)+ ; return (mkUserLocalOrCoVar (nameOccName n) uniq ty' (getSrcSpan n)) }++newSpecIdSM :: Id -> Type -> Maybe JoinArity -> SpecM Id+ -- Give the new Id a similar occurrence name to the old one+newSpecIdSM old_id new_ty join_arity_maybe+ = do { uniq <- getUniqueM+ ; let name = idName old_id+ new_occ = mkSpecOcc (nameOccName name)+ new_id = mkUserLocalOrCoVar new_occ uniq new_ty (getSrcSpan name)+ `asJoinId_maybe` join_arity_maybe+ ; return new_id }++{-+ Old (but interesting) stuff about unboxed bindings+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++What should we do when a value is specialised to a *strict* unboxed value?++ map_*_* f (x:xs) = let h = f x+ t = map f xs+ in h:t++Could convert let to case:++ map_*_Int# f (x:xs) = case f x of h# ->+ let t = map f xs+ in h#:t++This may be undesirable since it forces evaluation here, but the value+may not be used in all branches of the body. In the general case this+transformation is impossible since the mutual recursion in a letrec+cannot be expressed as a case.++There is also a problem with top-level unboxed values, since our+implementation cannot handle unboxed values at the top level.++Solution: Lift the binding of the unboxed value and extract it when it+is used:++ map_*_Int# f (x:xs) = let h = case (f x) of h# -> _Lift h#+ t = map f xs+ in case h of+ _Lift h# -> h#:t++Now give it to the simplifier and the _Lifting will be optimised away.++The benefit is that we have given the specialised "unboxed" values a+very simple lifted semantics and then leave it up to the simplifier to+optimise it --- knowing that the overheads will be removed in nearly+all cases.++In particular, the value will only be evaluated in the branches of the+program which use it, rather than being forced at the point where the+value is bound. For example:++ filtermap_*_* p f (x:xs)+ = let h = f x+ t = ...+ in case p x of+ True -> h:t+ False -> t+ ==>+ filtermap_*_Int# p f (x:xs)+ = let h = case (f x) of h# -> _Lift h#+ t = ...+ in case p x of+ True -> case h of _Lift h#+ -> h#:t+ False -> t++The binding for h can still be inlined in the one branch and the+_Lifting eliminated.+++Question: When won't the _Lifting be eliminated?++Answer: When they at the top-level (where it is necessary) or when+inlining would duplicate work (or possibly code depending on+options). However, the _Lifting will still be eliminated if the+strictness analyser deems the lifted binding strict.+-}
+ stgSyn/CoreToStg.hs view
@@ -0,0 +1,1025 @@+{-# LANGUAGE CPP #-}++--+-- (c) The GRASP/AQUA Project, Glasgow University, 1993-1998+--++--------------------------------------------------------------+-- Converting Core to STG Syntax+--------------------------------------------------------------++-- And, as we have the info in hand, we may convert some lets to+-- let-no-escapes.++module CoreToStg ( coreToStg, coreExprToStg ) where++#include "HsVersions.h"++import CoreSyn+import CoreUtils ( exprType, findDefault, isJoinBind )+import CoreArity ( manifestArity )+import StgSyn++import Type+import RepType+import TyCon+import MkId ( coercionTokenId )+import Id+import IdInfo+import DataCon+import CostCentre ( noCCS )+import VarEnv+import Module+import Name ( isExternalName, nameOccName )+import OccName ( occNameFS )+import BasicTypes ( Arity )+import TysWiredIn ( unboxedUnitDataCon )+import Literal+import Outputable+import MonadUtils+import FastString+import Util+import DynFlags+import ForeignCall+import Demand ( isUsedOnce )+import PrimOp ( PrimCall(..) )+import UniqFM++import Data.Maybe (isJust, fromMaybe)+import Control.Monad (liftM, ap)++-- Note [Live vs free]+-- ~~~~~~~~~~~~~~~~~~~+--+-- The two are not the same. Liveness is an operational property rather+-- than a semantic one. A variable is live at a particular execution+-- point if it can be referred to directly again. In particular, a dead+-- variable's stack slot (if it has one):+--+-- - should be stubbed to avoid space leaks, and+-- - may be reused for something else.+--+-- There ought to be a better way to say this. Here are some examples:+--+-- let v = [q] \[x] -> e+-- in+-- ...v... (but no q's)+--+-- Just after the `in', v is live, but q is dead. If the whole of that+-- let expression was enclosed in a case expression, thus:+--+-- case (let v = [q] \[x] -> e in ...v...) of+-- alts[...q...]+--+-- (ie `alts' mention `q'), then `q' is live even after the `in'; because+-- we'll return later to the `alts' and need it.+--+-- Let-no-escapes make this a bit more interesting:+--+-- let-no-escape v = [q] \ [x] -> e+-- in+-- ...v...+--+-- Here, `q' is still live at the `in', because `v' is represented not by+-- a closure but by the current stack state. In other words, if `v' is+-- live then so is `q'. Furthermore, if `e' mentions an enclosing+-- let-no-escaped variable, then its free variables are also live if `v' is.++-- Note [What are these SRTs all about?]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- Consider the Core program,+--+-- fibs = go 1 1+-- where go a b = let c = a + c+-- in c : go b c+-- add x = map (\y -> x*y) fibs+--+-- In this case we have a CAF, 'fibs', which is quite large after evaluation and+-- has only one possible user, 'add'. Consequently, we want to ensure that when+-- all references to 'add' die we can garbage collect any bit of 'fibs' that we+-- have evaluated.+--+-- However, how do we know whether there are any references to 'fibs' still+-- around? Afterall, the only reference to it is buried in the code generated+-- for 'add'. The answer is that we record the CAFs referred to by a definition+-- in its info table, namely a part of it known as the Static Reference Table+-- (SRT).+--+-- Since SRTs are so common, we use a special compact encoding for them in: we+-- produce one table containing a list of CAFs in a module and then include a+-- bitmap in each info table describing which entries of this table the closure+-- references.+--+-- See also: Commentary/Rts/Storage/GC/CAFs on the GHC Wiki.++-- Note [Collecting live CAF info]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- In this pass we also collect information on which CAFs are live.+--+-- A top-level Id has CafInfo, which is+--+-- - MayHaveCafRefs, if it may refer indirectly to+-- one or more CAFs, or+-- - NoCafRefs if it definitely doesn't+--+-- The CafInfo has already been calculated during the CoreTidy pass.+--+-- During CoreToStg, we then pin onto each binding and case expression, a+-- list of Ids which represents the "live" CAFs at that point. The meaning+-- of "live" here is the same as for live variables, see above (which is+-- why it's convenient to collect CAF information here rather than elsewhere).+--+-- The later SRT pass takes these lists of Ids and uses them to construct+-- the actual nested SRTs, and replaces the lists of Ids with (offset,length)+-- pairs.++-- Note [What is a non-escaping let]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- NB: Nowadays this is recognized by the occurrence analyser by turning a+-- "non-escaping let" into a join point. The following is then an operational+-- account of join points.+--+-- Consider:+--+-- let x = fvs \ args -> e+-- in+-- if ... then x else+-- if ... then x else ...+--+-- `x' is used twice (so we probably can't unfold it), but when it is+-- entered, the stack is deeper than it was when the definition of `x'+-- happened. Specifically, if instead of allocating a closure for `x',+-- we saved all `x's fvs on the stack, and remembered the stack depth at+-- that moment, then whenever we enter `x' we can simply set the stack+-- pointer(s) to these remembered (compile-time-fixed) values, and jump+-- to the code for `x'.+--+-- All of this is provided x is:+-- 1. non-updatable;+-- 2. guaranteed to be entered before the stack retreats -- ie x is not+-- buried in a heap-allocated closure, or passed as an argument to+-- something;+-- 3. all the enters have exactly the right number of arguments,+-- no more no less;+-- 4. all the enters are tail calls; that is, they return to the+-- caller enclosing the definition of `x'.+--+-- Under these circumstances we say that `x' is non-escaping.+--+-- An example of when (4) does not hold:+--+-- let x = ...+-- in case x of ...alts...+--+-- Here, `x' is certainly entered only when the stack is deeper than when+-- `x' is defined, but here it must return to ...alts... So we can't just+-- adjust the stack down to `x''s recalled points, because that would lost+-- alts' context.+--+-- Things can get a little more complicated. Consider:+--+-- let y = ...+-- in let x = fvs \ args -> ...y...+-- in ...x...+--+-- Now, if `x' is used in a non-escaping way in ...x..., and `y' is used in a+-- non-escaping way in ...y..., then `y' is non-escaping.+--+-- `x' can even be recursive! Eg:+--+-- letrec x = [y] \ [v] -> if v then x True else ...+-- in+-- ...(x b)...++-- --------------------------------------------------------------+-- Setting variable info: top-level, binds, RHSs+-- --------------------------------------------------------------++coreToStg :: DynFlags -> Module -> CoreProgram -> [StgTopBinding]+coreToStg dflags this_mod pgm+ = pgm'+ where (_, _, pgm') = coreTopBindsToStg dflags this_mod emptyVarEnv pgm++coreExprToStg :: CoreExpr -> StgExpr+coreExprToStg expr+ = new_expr where (new_expr,_) = initCts emptyVarEnv (coreToStgExpr expr)+++coreTopBindsToStg+ :: DynFlags+ -> Module+ -> IdEnv HowBound -- environment for the bindings+ -> CoreProgram+ -> (IdEnv HowBound, FreeVarsInfo, [StgTopBinding])++coreTopBindsToStg _ _ env [] = (env, emptyFVInfo, [])+coreTopBindsToStg dflags this_mod env (b:bs)+ = (env2, fvs2, b':bs')+ where+ -- Notice the mutually-recursive "knot" here:+ -- env accumulates down the list of binds,+ -- fvs accumulates upwards+ (env1, fvs2, b' ) = coreTopBindToStg dflags this_mod env fvs1 b+ (env2, fvs1, bs') = coreTopBindsToStg dflags this_mod env1 bs++coreTopBindToStg+ :: DynFlags+ -> Module+ -> IdEnv HowBound+ -> FreeVarsInfo -- Info about the body+ -> CoreBind+ -> (IdEnv HowBound, FreeVarsInfo, StgTopBinding)++coreTopBindToStg _ _ env body_fvs (NonRec id (Lit (MachStr str)))+ -- top-level string literal+ = let+ env' = extendVarEnv env id how_bound+ how_bound = LetBound TopLet 0+ in (env', body_fvs, StgTopStringLit id str)++coreTopBindToStg dflags this_mod env body_fvs (NonRec id rhs)+ = let+ env' = extendVarEnv env id how_bound+ how_bound = LetBound TopLet $! manifestArity rhs++ (stg_rhs, fvs') =+ initCts env $ do+ (stg_rhs, fvs') <- coreToTopStgRhs dflags this_mod body_fvs (id,rhs)+ return (stg_rhs, fvs')++ bind = StgTopLifted $ StgNonRec id stg_rhs+ in+ ASSERT2(consistentCafInfo id bind, ppr id )+ -- NB: previously the assertion printed 'rhs' and 'bind'+ -- as well as 'id', but that led to a black hole+ -- where printing the assertion error tripped the+ -- assertion again!+ (env', fvs' `unionFVInfo` body_fvs, bind)++coreTopBindToStg dflags this_mod env body_fvs (Rec pairs)+ = ASSERT( not (null pairs) )+ let+ binders = map fst pairs++ extra_env' = [ (b, LetBound TopLet $! manifestArity rhs)+ | (b, rhs) <- pairs ]+ env' = extendVarEnvList env extra_env'++ (stg_rhss, fvs')+ = initCts env' $ do+ (stg_rhss, fvss') <- mapAndUnzipM (coreToTopStgRhs dflags this_mod body_fvs) pairs+ let fvs' = unionFVInfos fvss'+ return (stg_rhss, fvs')++ bind = StgTopLifted $ StgRec (zip binders stg_rhss)+ in+ ASSERT2(consistentCafInfo (head binders) bind, ppr binders)+ (env', fvs' `unionFVInfo` body_fvs, bind)+++-- Assertion helper: this checks that the CafInfo on the Id matches+-- what CoreToStg has figured out about the binding's SRT. The+-- CafInfo will be exact in all cases except when CorePrep has+-- floated out a binding, in which case it will be approximate.+consistentCafInfo :: Id -> GenStgTopBinding Var Id -> Bool+consistentCafInfo id bind+ = WARN( not (exact || is_sat_thing) , ppr id <+> ppr id_marked_caffy <+> ppr binding_is_caffy )+ safe+ where+ safe = id_marked_caffy || not binding_is_caffy+ exact = id_marked_caffy == binding_is_caffy+ id_marked_caffy = mayHaveCafRefs (idCafInfo id)+ binding_is_caffy = topStgBindHasCafRefs bind+ is_sat_thing = occNameFS (nameOccName (idName id)) == fsLit "sat"++coreToTopStgRhs+ :: DynFlags+ -> Module+ -> FreeVarsInfo -- Free var info for the scope of the binding+ -> (Id,CoreExpr)+ -> CtsM (StgRhs, FreeVarsInfo)++coreToTopStgRhs dflags this_mod scope_fv_info (bndr, rhs)+ = do { (new_rhs, rhs_fvs) <- coreToStgExpr rhs++ ; let stg_rhs = mkTopStgRhs dflags this_mod rhs_fvs bndr bndr_info new_rhs+ stg_arity = stgRhsArity stg_rhs+ ; return (ASSERT2( arity_ok stg_arity, mk_arity_msg stg_arity) stg_rhs,+ rhs_fvs) }+ where+ bndr_info = lookupFVInfo scope_fv_info bndr++ -- It's vital that the arity on a top-level Id matches+ -- the arity of the generated STG binding, else an importing+ -- module will use the wrong calling convention+ -- (Trac #2844 was an example where this happened)+ -- NB1: we can't move the assertion further out without+ -- blocking the "knot" tied in coreTopBindsToStg+ -- NB2: the arity check is only needed for Ids with External+ -- Names, because they are externally visible. The CorePrep+ -- pass introduces "sat" things with Local Names and does+ -- not bother to set their Arity info, so don't fail for those+ arity_ok stg_arity+ | isExternalName (idName bndr) = id_arity == stg_arity+ | otherwise = True+ id_arity = idArity bndr+ mk_arity_msg stg_arity+ = vcat [ppr bndr,+ text "Id arity:" <+> ppr id_arity,+ text "STG arity:" <+> ppr stg_arity]++mkTopStgRhs :: DynFlags -> Module -> FreeVarsInfo+ -> Id -> StgBinderInfo -> StgExpr+ -> StgRhs++mkTopStgRhs dflags this_mod = mkStgRhs' con_updateable+ -- Dynamic StgConApps are updatable+ where con_updateable con args = isDllConApp dflags this_mod con args++-- ---------------------------------------------------------------------------+-- Expressions+-- ---------------------------------------------------------------------------++coreToStgExpr+ :: CoreExpr+ -> CtsM (StgExpr, -- Decorated STG expr+ FreeVarsInfo) -- Its free vars (NB free, not live)++-- The second and third components can be derived in a simple bottom up pass, not+-- dependent on any decisions about which variables will be let-no-escaped or+-- not. The first component, that is, the decorated expression, may then depend+-- on these components, but it in turn is not scrutinised as the basis for any+-- decisions. Hence no black holes.++-- No LitInteger's should be left by the time this is called. CorePrep+-- should have converted them all to a real core representation.+coreToStgExpr (Lit (LitInteger {})) = panic "coreToStgExpr: LitInteger"+coreToStgExpr (Lit l) = return (StgLit l, emptyFVInfo)+coreToStgExpr (Var v) = coreToStgApp Nothing v [] []+coreToStgExpr (Coercion _) = coreToStgApp Nothing coercionTokenId [] []++coreToStgExpr expr@(App _ _)+ = coreToStgApp Nothing f args ticks+ where+ (f, args, ticks) = myCollectArgs expr++coreToStgExpr expr@(Lam _ _)+ = let+ (args, body) = myCollectBinders expr+ args' = filterStgBinders args+ in+ extendVarEnvCts [ (a, LambdaBound) | a <- args' ] $ do+ (body, body_fvs) <- coreToStgExpr body+ let+ fvs = args' `minusFVBinders` body_fvs+ result_expr | null args' = body+ | otherwise = StgLam args' body++ return (result_expr, fvs)++coreToStgExpr (Tick tick expr)+ = do case tick of+ HpcTick{} -> return ()+ ProfNote{} -> return ()+ SourceNote{} -> return ()+ Breakpoint{} -> panic "coreToStgExpr: breakpoint should not happen"+ (expr2, fvs) <- coreToStgExpr expr+ return (StgTick tick expr2, fvs)++coreToStgExpr (Cast expr _)+ = coreToStgExpr expr++-- Cases require a little more real work.++coreToStgExpr (Case scrut _ _ [])+ = coreToStgExpr scrut+ -- See Note [Empty case alternatives] in CoreSyn If the case+ -- alternatives are empty, the scrutinee must diverge or raise an+ -- exception, so we can just dive into it.+ --+ -- Of course this may seg-fault if the scrutinee *does* return. A+ -- belt-and-braces approach would be to move this case into the+ -- code generator, and put a return point anyway that calls a+ -- runtime system error function.+++coreToStgExpr (Case scrut bndr _ alts) = do+ (alts2, alts_fvs)+ <- extendVarEnvCts [(bndr, LambdaBound)] $ do+ (alts2, fvs_s) <- mapAndUnzipM vars_alt alts+ return ( alts2,+ unionFVInfos fvs_s )+ let+ -- Determine whether the default binder is dead or not+ -- This helps the code generator to avoid generating an assignment+ -- for the case binder (is extremely rare cases) ToDo: remove.+ bndr' | bndr `elementOfFVInfo` alts_fvs = bndr+ | otherwise = bndr `setIdOccInfo` IAmDead++ -- Don't consider the default binder as being 'live in alts',+ -- since this is from the point of view of the case expr, where+ -- the default binder is not free.+ alts_fvs_wo_bndr = bndr `minusFVBinder` alts_fvs++ -- We tell the scrutinee that everything+ -- live in the alts is live in it, too.+ (scrut2, scrut_fvs) <- coreToStgExpr scrut++ return (+ StgCase scrut2 bndr' (mkStgAltType bndr alts) alts2,+ scrut_fvs `unionFVInfo` alts_fvs_wo_bndr+ )+ where+ vars_alt (con, binders, rhs)+ | DataAlt c <- con, c == unboxedUnitDataCon+ = -- This case is a bit smelly.+ -- See Note [Nullary unboxed tuple] in Type.hs+ -- where a nullary tuple is mapped to (State# World#)+ ASSERT( null binders )+ do { (rhs2, rhs_fvs) <- coreToStgExpr rhs+ ; return ((DEFAULT, [], rhs2), rhs_fvs) }+ | otherwise+ = let -- Remove type variables+ binders' = filterStgBinders binders+ in+ extendVarEnvCts [(b, LambdaBound) | b <- binders'] $ do+ (rhs2, rhs_fvs) <- coreToStgExpr rhs+ return ( (con, binders', rhs2),+ binders' `minusFVBinders` rhs_fvs )++coreToStgExpr (Let bind body) = do+ coreToStgLet bind body++coreToStgExpr e = pprPanic "coreToStgExpr" (ppr e)++mkStgAltType :: Id -> [CoreAlt] -> AltType+mkStgAltType bndr alts+ | isUnboxedTupleType bndr_ty || isUnboxedSumType bndr_ty+ = MultiValAlt (length prim_reps) -- always use MultiValAlt for unboxed tuples++ | otherwise+ = case prim_reps of+ [LiftedRep] -> case tyConAppTyCon_maybe (unwrapType bndr_ty) of+ Just tc+ | isAbstractTyCon tc -> look_for_better_tycon+ | isAlgTyCon tc -> AlgAlt tc+ | otherwise -> ASSERT2( _is_poly_alt_tycon tc, ppr tc )+ PolyAlt+ Nothing -> PolyAlt+ [unlifted] -> PrimAlt unlifted+ not_unary -> MultiValAlt (length not_unary)+ where+ bndr_ty = idType bndr+ prim_reps = typePrimRep bndr_ty++ _is_poly_alt_tycon tc+ = isFunTyCon tc+ || isPrimTyCon tc -- "Any" is lifted but primitive+ || isFamilyTyCon tc -- Type family; e.g. Any, or arising from strict+ -- function application where argument has a+ -- type-family type++ -- Sometimes, the TyCon is a AbstractTyCon which may not have any+ -- constructors inside it. Then we may get a better TyCon by+ -- grabbing the one from a constructor alternative+ -- if one exists.+ look_for_better_tycon+ | ((DataAlt con, _, _) : _) <- data_alts =+ AlgAlt (dataConTyCon con)+ | otherwise =+ ASSERT(null data_alts)+ PolyAlt+ where+ (data_alts, _deflt) = findDefault alts++-- ---------------------------------------------------------------------------+-- Applications+-- ---------------------------------------------------------------------------++coreToStgApp+ :: Maybe UpdateFlag -- Just upd <=> this application is+ -- the rhs of a thunk binding+ -- x = [...] \upd [] -> the_app+ -- with specified update flag+ -> Id -- Function+ -> [CoreArg] -- Arguments+ -> [Tickish Id] -- Debug ticks+ -> CtsM (StgExpr, FreeVarsInfo)+++coreToStgApp _ f args ticks = do+ (args', args_fvs, ticks') <- coreToStgArgs args+ how_bound <- lookupVarCts f++ let+ n_val_args = valArgCount args+ not_letrec_bound = not (isLetBound how_bound)+ fun_fvs = singletonFVInfo f how_bound fun_occ+ -- e.g. (f :: a -> int) (x :: a)+ -- Here the free variables are "f", "x" AND the type variable "a"+ -- coreToStgArgs will deal with the arguments recursively++ -- Mostly, the arity info of a function is in the fn's IdInfo+ -- But new bindings introduced by CoreSat may not have no+ -- arity info; it would do us no good anyway. For example:+ -- let f = \ab -> e in f+ -- No point in having correct arity info for f!+ -- Hence the hasArity stuff below.+ -- NB: f_arity is only consulted for LetBound things+ f_arity = stgArity f how_bound+ saturated = f_arity <= n_val_args++ fun_occ+ | not_letrec_bound = noBinderInfo -- Uninteresting variable+ | f_arity > 0 && saturated = stgSatOcc -- Saturated or over-saturated function call+ | otherwise = stgUnsatOcc -- Unsaturated function or thunk++ res_ty = exprType (mkApps (Var f) args)+ app = case idDetails f of+ DataConWorkId dc+ | saturated -> StgConApp dc args'+ (dropRuntimeRepArgs (fromMaybe [] (tyConAppArgs_maybe res_ty)))++ -- Some primitive operator that might be implemented as a library call.+ PrimOpId op -> ASSERT( saturated )+ StgOpApp (StgPrimOp op) args' res_ty++ -- A call to some primitive Cmm function.+ FCallId (CCall (CCallSpec (StaticTarget _ lbl (Just pkgId) True)+ PrimCallConv _))+ -> ASSERT( saturated )+ StgOpApp (StgPrimCallOp (PrimCall lbl pkgId)) args' res_ty++ -- A regular foreign call.+ FCallId call -> ASSERT( saturated )+ StgOpApp (StgFCallOp call (idUnique f)) args' res_ty++ TickBoxOpId {} -> pprPanic "coreToStg TickBox" $ ppr (f,args')+ _other -> StgApp f args'+ fvs = fun_fvs `unionFVInfo` args_fvs++ tapp = foldr StgTick app (ticks ++ ticks')++ -- Forcing these fixes a leak in the code generator, noticed while+ -- profiling for trac #4367+ app `seq` fvs `seq` return (+ tapp,+ fvs+ )++++-- ---------------------------------------------------------------------------+-- Argument lists+-- This is the guy that turns applications into A-normal form+-- ---------------------------------------------------------------------------++coreToStgArgs :: [CoreArg] -> CtsM ([StgArg], FreeVarsInfo, [Tickish Id])+coreToStgArgs []+ = return ([], emptyFVInfo, [])++coreToStgArgs (Type _ : args) = do -- Type argument+ (args', fvs, ts) <- coreToStgArgs args+ return (args', fvs, ts)++coreToStgArgs (Coercion _ : args) -- Coercion argument; replace with place holder+ = do { (args', fvs, ts) <- coreToStgArgs args+ ; return (StgVarArg coercionTokenId : args', fvs, ts) }++coreToStgArgs (Tick t e : args)+ = ASSERT( not (tickishIsCode t) )+ do { (args', fvs, ts) <- coreToStgArgs (e : args)+ ; return (args', fvs, t:ts) }++coreToStgArgs (arg : args) = do -- Non-type argument+ (stg_args, args_fvs, ticks) <- coreToStgArgs args+ (arg', arg_fvs) <- coreToStgExpr arg+ let+ fvs = args_fvs `unionFVInfo` arg_fvs++ (aticks, arg'') = stripStgTicksTop tickishFloatable arg'+ stg_arg = case arg'' of+ StgApp v [] -> StgVarArg v+ StgConApp con [] _ -> StgVarArg (dataConWorkId con)+ StgLit lit -> StgLitArg lit+ _ -> pprPanic "coreToStgArgs" (ppr arg)++ -- WARNING: what if we have an argument like (v `cast` co)+ -- where 'co' changes the representation type?+ -- (This really only happens if co is unsafe.)+ -- Then all the getArgAmode stuff in CgBindery will set the+ -- cg_rep of the CgIdInfo based on the type of v, rather+ -- than the type of 'co'.+ -- This matters particularly when the function is a primop+ -- or foreign call.+ -- Wanted: a better solution than this hacky warning+ let+ arg_ty = exprType arg+ stg_arg_ty = stgArgType stg_arg+ bad_args = (isUnliftedType arg_ty && not (isUnliftedType stg_arg_ty))+ || (typePrimRep arg_ty /= typePrimRep stg_arg_ty)+ -- In GHCi we coerce an argument of type BCO# (unlifted) to HValue (lifted),+ -- and pass it to a function expecting an HValue (arg_ty). This is ok because+ -- we can treat an unlifted value as lifted. But the other way round+ -- we complain.+ -- We also want to check if a pointer is cast to a non-ptr etc++ WARN( bad_args, text "Dangerous-looking argument. Probable cause: bad unsafeCoerce#" $$ ppr arg )+ return (stg_arg : stg_args, fvs, ticks ++ aticks)+++-- ---------------------------------------------------------------------------+-- The magic for lets:+-- ---------------------------------------------------------------------------++coreToStgLet+ :: CoreBind -- bindings+ -> CoreExpr -- body+ -> CtsM (StgExpr, -- new let+ FreeVarsInfo) -- variables free in the whole let++coreToStgLet bind body = do+ (bind2, bind_fvs,+ body2, body_fvs)+ <- mfix $ \ ~(_, _, _, rec_body_fvs) -> do++ ( bind2, bind_fvs, env_ext)+ <- vars_bind rec_body_fvs bind++ -- Do the body+ extendVarEnvCts env_ext $ do+ (body2, body_fvs) <- coreToStgExpr body++ return (bind2, bind_fvs,+ body2, body_fvs)+++ -- Compute the new let-expression+ let+ new_let | isJoinBind bind = StgLetNoEscape bind2 body2+ | otherwise = StgLet bind2 body2++ free_in_whole_let+ = binders `minusFVBinders` (bind_fvs `unionFVInfo` body_fvs)++ return (+ new_let,+ free_in_whole_let+ )+ where+ binders = bindersOf bind++ mk_binding binder rhs+ = (binder, LetBound NestedLet (manifestArity rhs))++ vars_bind :: FreeVarsInfo -- Free var info for body of binding+ -> CoreBind+ -> CtsM (StgBinding,+ FreeVarsInfo,+ [(Id, HowBound)]) -- extension to environment+++ vars_bind body_fvs (NonRec binder rhs) = do+ (rhs2, bind_fvs) <- coreToStgRhs body_fvs (binder,rhs)+ let+ env_ext_item = mk_binding binder rhs++ return (StgNonRec binder rhs2,+ bind_fvs, [env_ext_item])+++ vars_bind body_fvs (Rec pairs)+ = mfix $ \ ~(_, rec_rhs_fvs, _) ->+ let+ rec_scope_fvs = unionFVInfo body_fvs rec_rhs_fvs+ binders = map fst pairs+ env_ext = [ mk_binding b rhs+ | (b,rhs) <- pairs ]+ in+ extendVarEnvCts env_ext $ do+ (rhss2, fvss)+ <- mapAndUnzipM (coreToStgRhs rec_scope_fvs) pairs+ let+ bind_fvs = unionFVInfos fvss++ return (StgRec (binders `zip` rhss2),+ bind_fvs, env_ext)++coreToStgRhs :: FreeVarsInfo -- Free var info for the scope of the binding+ -> (Id,CoreExpr)+ -> CtsM (StgRhs, FreeVarsInfo)++coreToStgRhs scope_fv_info (bndr, rhs) = do+ (new_rhs, rhs_fvs) <- coreToStgExpr rhs+ return (mkStgRhs rhs_fvs bndr bndr_info new_rhs, rhs_fvs)+ where+ bndr_info = lookupFVInfo scope_fv_info bndr++mkStgRhs :: FreeVarsInfo -> Id -> StgBinderInfo -> StgExpr -> StgRhs+mkStgRhs = mkStgRhs' con_updateable+ where con_updateable _ _ = False++mkStgRhs' :: (DataCon -> [StgArg] -> Bool)+ -> FreeVarsInfo -> Id -> StgBinderInfo -> StgExpr -> StgRhs+mkStgRhs' con_updateable rhs_fvs bndr binder_info rhs+ | StgLam bndrs body <- rhs+ = StgRhsClosure noCCS binder_info+ (getFVs rhs_fvs)+ ReEntrant+ bndrs body+ | isJoinId bndr -- must be nullary join point+ = ASSERT(idJoinArity bndr == 0)+ StgRhsClosure noCCS binder_info+ (getFVs rhs_fvs)+ ReEntrant -- ignored for LNE+ [] rhs+ | StgConApp con args _ <- unticked_rhs+ , not (con_updateable con args)+ = -- CorePrep does this right, but just to make sure+ ASSERT2( not (isUnboxedTupleCon con || isUnboxedSumCon con)+ , ppr bndr $$ ppr con $$ ppr args)+ StgRhsCon noCCS con args+ | otherwise+ = StgRhsClosure noCCS binder_info+ (getFVs rhs_fvs)+ upd_flag [] rhs+ where++ (_, unticked_rhs) = stripStgTicksTop (not . tickishIsCode) rhs++ upd_flag | isUsedOnce (idDemandInfo bndr) = SingleEntry+ | otherwise = Updatable++ {-+ SDM: disabled. Eval/Apply can't handle functions with arity zero very+ well; and making these into simple non-updatable thunks breaks other+ assumptions (namely that they will be entered only once).++ upd_flag | isPAP env rhs = ReEntrant+ | otherwise = Updatable++-- Detect thunks which will reduce immediately to PAPs, and make them+-- non-updatable. This has several advantages:+--+-- - the non-updatable thunk behaves exactly like the PAP,+--+-- - the thunk is more efficient to enter, because it is+-- specialised to the task.+--+-- - we save one update frame, one stg_update_PAP, one update+-- and lots of PAP_enters.+--+-- - in the case where the thunk is top-level, we save building+-- a black hole and furthermore the thunk isn't considered to+-- be a CAF any more, so it doesn't appear in any SRTs.+--+-- We do it here, because the arity information is accurate, and we need+-- to do it before the SRT pass to save the SRT entries associated with+-- any top-level PAPs.++isPAP env (StgApp f args) = listLengthCmp args arity == LT -- idArity f > length args+ where+ arity = stgArity f (lookupBinding env f)+isPAP env _ = False++-}++{- ToDo:+ upd = if isOnceDem dem+ then (if isNotTop toplev+ then SingleEntry -- HA! Paydirt for "dem"+ else+ (if debugIsOn then trace "WARNING: SE CAFs unsupported, forcing UPD instead" else id) $+ Updatable)+ else Updatable+ -- For now we forbid SingleEntry CAFs; they tickle the+ -- ASSERT in rts/Storage.c line 215 at newCAF() re mut_link,+ -- and I don't understand why. There's only one SE_CAF (well,+ -- only one that tickled a great gaping bug in an earlier attempt+ -- at ClosureInfo.getEntryConvention) in the whole of nofib,+ -- specifically Main.lvl6 in spectral/cryptarithm2.+ -- So no great loss. KSW 2000-07.+-}++-- ---------------------------------------------------------------------------+-- A monad for the core-to-STG pass+-- ---------------------------------------------------------------------------++-- There's a lot of stuff to pass around, so we use this CtsM+-- ("core-to-STG monad") monad to help. All the stuff here is only passed+-- *down*.++newtype CtsM a = CtsM+ { unCtsM :: IdEnv HowBound+ -> a+ }++data HowBound+ = ImportBound -- Used only as a response to lookupBinding; never+ -- exists in the range of the (IdEnv HowBound)++ | LetBound -- A let(rec) in this module+ LetInfo -- Whether top level or nested+ Arity -- Its arity (local Ids don't have arity info at this point)++ | LambdaBound -- Used for both lambda and case+ deriving (Eq)++data LetInfo+ = TopLet -- top level things+ | NestedLet+ deriving (Eq)++isLetBound :: HowBound -> Bool+isLetBound (LetBound _ _) = True+isLetBound _ = False++topLevelBound :: HowBound -> Bool+topLevelBound ImportBound = True+topLevelBound (LetBound TopLet _) = True+topLevelBound _ = False++-- For a let(rec)-bound variable, x, we record LiveInfo, the set of+-- variables that are live if x is live. This LiveInfo comprises+-- (a) dynamic live variables (ones with a non-top-level binding)+-- (b) static live variabes (CAFs or things that refer to CAFs)+--+-- For "normal" variables (a) is just x alone. If x is a let-no-escaped+-- variable then x is represented by a code pointer and a stack pointer+-- (well, one for each stack). So all of the variables needed in the+-- execution of x are live if x is, and are therefore recorded in the+-- LetBound constructor; x itself *is* included.+--+-- The set of dynamic live variables is guaranteed ot have no further+-- let-no-escaped variables in it.++-- The std monad functions:++initCts :: IdEnv HowBound -> CtsM a -> a+initCts env m = unCtsM m env++++{-# INLINE thenCts #-}+{-# INLINE returnCts #-}++returnCts :: a -> CtsM a+returnCts e = CtsM $ \_ -> e++thenCts :: CtsM a -> (a -> CtsM b) -> CtsM b+thenCts m k = CtsM $ \env+ -> unCtsM (k (unCtsM m env)) env++instance Functor CtsM where+ fmap = liftM++instance Applicative CtsM where+ pure = returnCts+ (<*>) = ap++instance Monad CtsM where+ (>>=) = thenCts++instance MonadFix CtsM where+ mfix expr = CtsM $ \env ->+ let result = unCtsM (expr result) env+ in result++-- Functions specific to this monad:++extendVarEnvCts :: [(Id, HowBound)] -> CtsM a -> CtsM a+extendVarEnvCts ids_w_howbound expr+ = CtsM $ \env+ -> unCtsM expr (extendVarEnvList env ids_w_howbound)++lookupVarCts :: Id -> CtsM HowBound+lookupVarCts v = CtsM $ \env -> lookupBinding env v++lookupBinding :: IdEnv HowBound -> Id -> HowBound+lookupBinding env v = case lookupVarEnv env v of+ Just xx -> xx+ Nothing -> ASSERT2( isGlobalId v, ppr v ) ImportBound+++-- ---------------------------------------------------------------------------+-- Free variable information+-- ---------------------------------------------------------------------------++type FreeVarsInfo = VarEnv (Var, HowBound, StgBinderInfo)+ -- The Var is so we can gather up the free variables+ -- as a set.+ --+ -- The HowBound info just saves repeated lookups;+ -- we look up just once when we encounter the occurrence.+ -- INVARIANT: Any ImportBound Ids are HaveCafRef Ids+ -- Imported Ids without CAF refs are simply+ -- not put in the FreeVarsInfo for an expression.+ -- See singletonFVInfo and freeVarsToLiveVars+ --+ -- StgBinderInfo records how it occurs; notably, we+ -- are interested in whether it only occurs in saturated+ -- applications, because then we don't need to build a+ -- curried version.+ -- If f is mapped to noBinderInfo, that means+ -- that f *is* mentioned (else it wouldn't be in the+ -- IdEnv at all), but perhaps in an unsaturated applications.+ --+ -- All case/lambda-bound things are also mapped to+ -- noBinderInfo, since we aren't interested in their+ -- occurrence info.+ --+ -- For ILX we track free var info for type variables too;+ -- hence VarEnv not IdEnv++emptyFVInfo :: FreeVarsInfo+emptyFVInfo = emptyVarEnv++singletonFVInfo :: Id -> HowBound -> StgBinderInfo -> FreeVarsInfo+-- Don't record non-CAF imports at all, to keep free-var sets small+singletonFVInfo id ImportBound info+ | mayHaveCafRefs (idCafInfo id) = unitVarEnv id (id, ImportBound, info)+ | otherwise = emptyVarEnv+singletonFVInfo id how_bound info = unitVarEnv id (id, how_bound, info)++unionFVInfo :: FreeVarsInfo -> FreeVarsInfo -> FreeVarsInfo+unionFVInfo fv1 fv2 = plusVarEnv_C plusFVInfo fv1 fv2++unionFVInfos :: [FreeVarsInfo] -> FreeVarsInfo+unionFVInfos fvs = foldr unionFVInfo emptyFVInfo fvs++minusFVBinders :: [Id] -> FreeVarsInfo -> FreeVarsInfo+minusFVBinders vs fv = foldr minusFVBinder fv vs++minusFVBinder :: Id -> FreeVarsInfo -> FreeVarsInfo+minusFVBinder v fv = fv `delVarEnv` v+ -- When removing a binder, remember to add its type variables+ -- c.f. CoreFVs.delBinderFV++elementOfFVInfo :: Id -> FreeVarsInfo -> Bool+elementOfFVInfo id fvs = isJust (lookupVarEnv fvs id)++lookupFVInfo :: FreeVarsInfo -> Id -> StgBinderInfo+-- Find how the given Id is used.+-- Externally visible things may be used any old how+lookupFVInfo fvs id+ | isExternalName (idName id) = noBinderInfo+ | otherwise = case lookupVarEnv fvs id of+ Nothing -> noBinderInfo+ Just (_,_,info) -> info++-- Non-top-level things only, both type variables and ids+getFVs :: FreeVarsInfo -> [Var]+getFVs fvs = [id | (id, how_bound, _) <- nonDetEltsUFM fvs,+ -- It's OK to use nonDetEltsUFM here because we're not aiming for+ -- bit-for-bit determinism.+ -- See Note [Unique Determinism and code generation]+ not (topLevelBound how_bound) ]++plusFVInfo :: (Var, HowBound, StgBinderInfo)+ -> (Var, HowBound, StgBinderInfo)+ -> (Var, HowBound, StgBinderInfo)+plusFVInfo (id1,hb1,info1) (id2,hb2,info2)+ = ASSERT(id1 == id2 && hb1 == hb2)+ (id1, hb1, combineStgBinderInfo info1 info2)++-- Misc.++filterStgBinders :: [Var] -> [Var]+filterStgBinders bndrs = filter isId bndrs++myCollectBinders :: Expr Var -> ([Var], Expr Var)+myCollectBinders expr+ = go [] expr+ where+ go bs (Lam b e) = go (b:bs) e+ go bs (Cast e _) = go bs e+ go bs e = (reverse bs, e)++myCollectArgs :: CoreExpr -> (Id, [CoreArg], [Tickish Id])+ -- We assume that we only have variables+ -- in the function position by now+myCollectArgs expr+ = go expr [] []+ where+ go (Var v) as ts = (v, as, ts)+ go (App f a) as ts = go f (a:as) ts+ go (Tick t e) as ts = ASSERT( all isTypeArg as )+ go e as (t:ts) -- ticks can appear in type apps+ go (Cast e _) as ts = go e as ts+ go (Lam b e) as ts+ | isTyVar b = go e as ts -- Note [Collect args]+ go _ _ _ = pprPanic "CoreToStg.myCollectArgs" (ppr expr)++-- Note [Collect args]+-- ~~~~~~~~~~~~~~~~~~~+--+-- This big-lambda case occurred following a rather obscure eta expansion.+-- It all seems a bit yukky to me.++stgArity :: Id -> HowBound -> Arity+stgArity _ (LetBound _ arity) = arity+stgArity f ImportBound = idArity f+stgArity _ LambdaBound = 0
+ stgSyn/StgLint.hs view
@@ -0,0 +1,537 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[StgLint]{A ``lint'' pass to check for Stg correctness}+-}++{-# LANGUAGE CPP #-}++module StgLint ( lintStgTopBindings ) where++import StgSyn++import Bag ( Bag, emptyBag, isEmptyBag, snocBag, bagToList )+import Id ( Id, idType, isLocalId )+import VarSet+import DataCon+import CoreSyn ( AltCon(..) )+import PrimOp ( primOpType )+import Literal ( literalType )+import Maybes+import Name ( getSrcLoc )+import ErrUtils ( MsgDoc, Severity(..), mkLocMessage )+import Type+import RepType+import TyCon+import Util+import SrcLoc+import Outputable+import Control.Monad++#include "HsVersions.h"++{-+Checks for+ (a) *some* type errors+ (b) locally-defined variables used but not defined+++Note: unless -dverbose-stg is on, display of lint errors will result+in "panic: bOGUS_LVs".++WARNING:+~~~~~~~~++This module has suffered bit-rot; it is likely to yield lint errors+for Stg code that is currently perfectly acceptable for code+generation. Solution: don't use it! (KSW 2000-05).+++************************************************************************+* *+\subsection{``lint'' for various constructs}+* *+************************************************************************++@lintStgTopBindings@ is the top-level interface function.+-}++lintStgTopBindings :: String -> [StgTopBinding] -> [StgTopBinding]++lintStgTopBindings whodunnit binds+ = {-# SCC "StgLint" #-}+ case (initL (lint_binds binds)) of+ Nothing -> binds+ Just msg -> pprPanic "" (vcat [+ text "*** Stg Lint ErrMsgs: in" <+>+ text whodunnit <+> text "***",+ msg,+ text "*** Offending Program ***",+ pprStgTopBindings binds,+ text "*** End of Offense ***"])+ where+ lint_binds :: [StgTopBinding] -> LintM ()++ lint_binds [] = return ()+ lint_binds (bind:binds) = do+ binders <- lint_bind bind+ addInScopeVars binders $+ lint_binds binds++ lint_bind (StgTopLifted bind) = lintStgBinds bind+ lint_bind (StgTopStringLit v _) = return [v]++lintStgArg :: StgArg -> LintM (Maybe Type)+lintStgArg (StgLitArg lit) = return (Just (literalType lit))+lintStgArg (StgVarArg v) = lintStgVar v++lintStgVar :: Id -> LintM (Maybe Kind)+lintStgVar v = do checkInScope v+ return (Just (idType v))++lintStgBinds :: StgBinding -> LintM [Id] -- Returns the binders+lintStgBinds (StgNonRec binder rhs) = do+ lint_binds_help (binder,rhs)+ return [binder]++lintStgBinds (StgRec pairs)+ = addInScopeVars binders $ do+ mapM_ lint_binds_help pairs+ return binders+ where+ binders = [b | (b,_) <- pairs]++lint_binds_help :: (Id, StgRhs) -> LintM ()+lint_binds_help (binder, rhs)+ = addLoc (RhsOf binder) $ do+ -- Check the rhs+ _maybe_rhs_ty <- lintStgRhs rhs++ -- Check binder doesn't have unlifted type+ checkL (not (isUnliftedType binder_ty))+ (mkUnliftedTyMsg binder rhs)++ -- Check match to RHS type+ -- Actually we *can't* check the RHS type, because+ -- unsafeCoerce means it really might not match at all+ -- notably; eg x::Int = (error @Bool "urk") |> unsafeCoerce...+ -- case maybe_rhs_ty of+ -- Nothing -> return ()+ -- Just rhs_ty -> checkTys binder_ty+ -- rhs_ty+ --- (mkRhsMsg binder rhs_ty)++ return ()+ where+ binder_ty = idType binder++lintStgRhs :: StgRhs -> LintM (Maybe Type) -- Just ty => type is exact++lintStgRhs (StgRhsClosure _ _ _ _ [] expr)+ = lintStgExpr expr++lintStgRhs (StgRhsClosure _ _ _ _ binders expr)+ = addLoc (LambdaBodyOf binders) $+ addInScopeVars binders $ runMaybeT $ do+ body_ty <- MaybeT $ lintStgExpr expr+ return (mkFunTys (map idType binders) body_ty)++lintStgRhs rhs@(StgRhsCon _ con args) = do+ -- TODO: Check arg_tys+ when (isUnboxedTupleCon con || isUnboxedSumCon con) $+ addErrL (text "StgRhsCon is an unboxed tuple or sum application" $$+ ppr rhs)+ runMaybeT $ do+ arg_tys <- mapM (MaybeT . lintStgArg) args+ MaybeT $ checkFunApp con_ty arg_tys (mkRhsConMsg con_ty arg_tys)+ where+ con_ty = dataConRepType con++lintStgExpr :: StgExpr -> LintM (Maybe Type) -- Just ty => type is exact++lintStgExpr (StgLit l) = return (Just (literalType l))++lintStgExpr e@(StgApp fun args) = runMaybeT $ do+ fun_ty <- MaybeT $ lintStgVar fun+ arg_tys <- mapM (MaybeT . lintStgArg) args+ MaybeT $ checkFunApp fun_ty arg_tys (mkFunAppMsg fun_ty arg_tys e)++lintStgExpr e@(StgConApp con args _arg_tys) = runMaybeT $ do+ -- TODO: Check arg_tys+ arg_tys <- mapM (MaybeT . lintStgArg) args+ MaybeT $ checkFunApp con_ty arg_tys (mkFunAppMsg con_ty arg_tys e)+ where+ con_ty = dataConRepType con++lintStgExpr e@(StgOpApp (StgPrimOp op) args _) = runMaybeT $ do+ arg_tys <- mapM (MaybeT . lintStgArg) args+ MaybeT $ checkFunApp op_ty arg_tys (mkFunAppMsg op_ty arg_tys e)+ where+ op_ty = primOpType op++lintStgExpr (StgOpApp _ args res_ty) = runMaybeT $ do+ -- We don't have enough type information to check+ -- the application for StgFCallOp and StgPrimCallOp; ToDo+ _maybe_arg_tys <- mapM (MaybeT . lintStgArg) args+ return res_ty++lintStgExpr (StgLam bndrs _) = do+ addErrL (text "Unexpected StgLam" <+> ppr bndrs)+ return Nothing++lintStgExpr (StgLet binds body) = do+ binders <- lintStgBinds binds+ addLoc (BodyOfLetRec binders) $+ addInScopeVars binders $+ lintStgExpr body++lintStgExpr (StgLetNoEscape binds body) = do+ binders <- lintStgBinds binds+ addLoc (BodyOfLetRec binders) $+ addInScopeVars binders $+ lintStgExpr body++lintStgExpr (StgTick _ expr) = lintStgExpr expr++lintStgExpr (StgCase scrut bndr alts_type alts) = runMaybeT $ do+ _ <- MaybeT $ lintStgExpr scrut++ in_scope <- MaybeT $ liftM Just $+ case alts_type of+ AlgAlt tc -> check_bndr (tyConPrimRep tc) >> return True+ PrimAlt rep -> check_bndr [rep] >> return True+ MultiValAlt _ -> return False -- Binder is always dead in this case+ PolyAlt -> return True++ MaybeT $ addInScopeVars [bndr | in_scope] $+ lintStgAlts alts scrut_ty+ where+ scrut_ty = idType bndr+ scrut_reps = typePrimRep scrut_ty+ check_bndr reps = checkL (scrut_reps == reps) bad_bndr+ where+ bad_bndr = mkDefltMsg bndr reps++lintStgAlts :: [StgAlt]+ -> Type -- Type of scrutinee+ -> LintM (Maybe Type) -- Just ty => type is accurage++lintStgAlts alts scrut_ty = do+ maybe_result_tys <- mapM (lintAlt scrut_ty) alts++ -- Check the result types+ case catMaybes (maybe_result_tys) of+ [] -> return Nothing++ (first_ty:_tys) -> do -- mapM_ check tys+ return (Just first_ty)+ where+ -- check ty = checkTys first_ty ty (mkCaseAltMsg alts)+ -- We can't check that the alternatives have the+ -- same type, because they don't, with unsafeCoerce#++lintAlt :: Type -> (AltCon, [Id], StgExpr) -> LintM (Maybe Type)+lintAlt _ (DEFAULT, _, rhs)+ = lintStgExpr rhs++lintAlt scrut_ty (LitAlt lit, _, rhs) = do+ checkTys (literalType lit) scrut_ty (mkAltMsg1 scrut_ty)+ lintStgExpr rhs++lintAlt scrut_ty (DataAlt con, args, rhs) = do+ case splitTyConApp_maybe scrut_ty of+ Just (tycon, tys_applied) | isAlgTyCon tycon &&+ not (isNewTyCon tycon) -> do+ let+ cons = tyConDataCons tycon+ arg_tys = dataConInstArgTys con tys_applied+ -- This does not work for existential constructors++ checkL (con `elem` cons) (mkAlgAltMsg2 scrut_ty con)+ checkL (length args == dataConRepArity con) (mkAlgAltMsg3 con args)+ when (isVanillaDataCon con) $+ mapM_ check (zipEqual "lintAlgAlt:stg" arg_tys args)+ return ()+ _ ->+ addErrL (mkAltMsg1 scrut_ty)++ addInScopeVars args $+ lintStgExpr rhs+ where+ check (ty, arg) = checkTys ty (idType arg) (mkAlgAltMsg4 ty arg)++ -- elem: yes, the elem-list here can sometimes be long-ish,+ -- but as it's use-once, probably not worth doing anything different+ -- We give it its own copy, so it isn't overloaded.+ elem _ [] = False+ elem x (y:ys) = x==y || elem x ys++{-+************************************************************************+* *+\subsection[lint-monad]{The Lint monad}+* *+************************************************************************+-}++newtype LintM a = LintM+ { unLintM :: [LintLocInfo] -- Locations+ -> IdSet -- Local vars in scope+ -> Bag MsgDoc -- Error messages so far+ -> (a, Bag MsgDoc) -- Result and error messages (if any)+ }++data LintLocInfo+ = RhsOf Id -- The variable bound+ | LambdaBodyOf [Id] -- The lambda-binder+ | BodyOfLetRec [Id] -- One of the binders++dumpLoc :: LintLocInfo -> (SrcSpan, SDoc)+dumpLoc (RhsOf v) =+ (srcLocSpan (getSrcLoc v), text " [RHS of " <> pp_binders [v] <> char ']' )+dumpLoc (LambdaBodyOf bs) =+ (srcLocSpan (getSrcLoc (head bs)), text " [in body of lambda with binders " <> pp_binders bs <> char ']' )++dumpLoc (BodyOfLetRec bs) =+ (srcLocSpan (getSrcLoc (head bs)), text " [in body of letrec with binders " <> pp_binders bs <> char ']' )+++pp_binders :: [Id] -> SDoc+pp_binders bs+ = sep (punctuate comma (map pp_binder bs))+ where+ pp_binder b+ = hsep [ppr b, dcolon, ppr (idType b)]++initL :: LintM a -> Maybe MsgDoc+initL (LintM m)+ = case (m [] emptyVarSet emptyBag) of { (_, errs) ->+ if isEmptyBag errs then+ Nothing+ else+ Just (vcat (punctuate blankLine (bagToList errs)))+ }++instance Functor LintM where+ fmap = liftM++instance Applicative LintM where+ pure a = LintM $ \_loc _scope errs -> (a, errs)+ (<*>) = ap+ (*>) = thenL_++instance Monad LintM where+ (>>=) = thenL+ (>>) = (*>)++thenL :: LintM a -> (a -> LintM b) -> LintM b+thenL m k = LintM $ \loc scope errs+ -> case unLintM m loc scope errs of+ (r, errs') -> unLintM (k r) loc scope errs'++thenL_ :: LintM a -> LintM b -> LintM b+thenL_ m k = LintM $ \loc scope errs+ -> case unLintM m loc scope errs of+ (_, errs') -> unLintM k loc scope errs'++checkL :: Bool -> MsgDoc -> LintM ()+checkL True _ = return ()+checkL False msg = addErrL msg++addErrL :: MsgDoc -> LintM ()+addErrL msg = LintM $ \loc _scope errs -> ((), addErr errs msg loc)++addErr :: Bag MsgDoc -> MsgDoc -> [LintLocInfo] -> Bag MsgDoc+addErr errs_so_far msg locs+ = errs_so_far `snocBag` mk_msg locs+ where+ mk_msg (loc:_) = let (l,hdr) = dumpLoc loc+ in mkLocMessage SevWarning l (hdr $$ msg)+ mk_msg [] = msg++addLoc :: LintLocInfo -> LintM a -> LintM a+addLoc extra_loc m = LintM $ \loc scope errs+ -> unLintM m (extra_loc:loc) scope errs++addInScopeVars :: [Id] -> LintM a -> LintM a+addInScopeVars ids m = LintM $ \loc scope errs+ -> let+ new_set = mkVarSet ids+ in unLintM m loc (scope `unionVarSet` new_set) errs++{-+Checking function applications: we only check that the type has the+right *number* of arrows, we don't actually compare the types. This+is because we can't expect the types to be equal - the type+applications and type lambdas that we use to calculate accurate types+have long since disappeared.+-}++checkFunApp :: Type -- The function type+ -> [Type] -- The arg type(s)+ -> MsgDoc -- Error message+ -> LintM (Maybe Type) -- Just ty => result type is accurate++checkFunApp fun_ty arg_tys msg+ = do { case mb_msg of+ Just msg -> addErrL msg+ Nothing -> return ()+ ; return mb_ty }+ where+ (mb_ty, mb_msg) = cfa True fun_ty arg_tys++ cfa :: Bool -> Type -> [Type] -> (Maybe Type -- Accurate result?+ , Maybe MsgDoc) -- Errors?++ cfa accurate fun_ty [] -- Args have run out; that's fine+ = (if accurate then Just fun_ty else Nothing, Nothing)++ cfa accurate fun_ty arg_tys@(arg_ty':arg_tys')+ | Just (arg_ty, res_ty) <- splitFunTy_maybe fun_ty+ = if accurate && not (arg_ty `stgEqType` arg_ty')+ then (Nothing, Just msg) -- Arg type mismatch+ else cfa accurate res_ty arg_tys'++ | Just (_, fun_ty') <- splitForAllTy_maybe fun_ty+ = cfa False fun_ty' arg_tys++ | Just (tc,tc_args) <- splitTyConApp_maybe fun_ty+ , isNewTyCon tc+ = if length tc_args < tyConArity tc+ then WARN( True, text "cfa: unsaturated newtype" <+> ppr fun_ty $$ msg )+ (Nothing, Nothing) -- This is odd, but I've seen it+ else cfa False (newTyConInstRhs tc tc_args) arg_tys++ | Just tc <- tyConAppTyCon_maybe fun_ty+ , not (isTypeFamilyTyCon tc) -- Definite error+ = (Nothing, Just msg) -- Too many args++ | otherwise+ = (Nothing, Nothing)++stgEqType :: Type -> Type -> Bool+-- Compare types, but crudely because we have discarded+-- both casts and type applications, so types might look+-- different but be the same. So reply "True" if in doubt.+-- "False" means that the types are definitely different.+--+-- Fundamentally this is a losing battle because of unsafeCoerce++stgEqType orig_ty1 orig_ty2+ = gos orig_ty1 orig_ty2+ where+ gos :: Type -> Type -> Bool+ gos ty1 ty2+ -- These have no prim rep+ | isRuntimeRepKindedTy ty1 && isRuntimeRepKindedTy ty2+ = True++ -- We have a unary type+ | [_] <- reps1, [_] <- reps2+ = go ty1 ty2++ -- In the case of a tuple just compare prim reps+ | otherwise+ = reps1 == reps2+ where+ reps1 = typePrimRep ty1+ reps2 = typePrimRep ty2++ go :: UnaryType -> UnaryType -> Bool+ go ty1 ty2+ | Just (tc1, tc_args1) <- splitTyConApp_maybe ty1+ , Just (tc2, tc_args2) <- splitTyConApp_maybe ty2+ , let res = if tc1 == tc2+ then equalLength tc_args1 tc_args2+ && and (zipWith gos tc_args1 tc_args2)+ else -- TyCons don't match; but don't bleat if either is a+ -- family TyCon because a coercion might have made it+ -- equal to something else+ (isFamilyTyCon tc1 || isFamilyTyCon tc2)+ = if res then True+ else+ pprTrace "stgEqType: unequal" (vcat [ppr ty1, ppr ty2])+ False++ | otherwise = True -- Conservatively say "fine".+ -- Type variables in particular++checkInScope :: Id -> LintM ()+checkInScope id = LintM $ \loc scope errs+ -> if isLocalId id && not (id `elemVarSet` scope) then+ ((), addErr errs (hsep [ppr id, text "is out of scope"]) loc)+ else+ ((), errs)++checkTys :: Type -> Type -> MsgDoc -> LintM ()+checkTys ty1 ty2 msg = LintM $ \loc _scope errs+ -> if (ty1 `stgEqType` ty2)+ then ((), errs)+ else ((), addErr errs msg loc)++_mkCaseAltMsg :: [StgAlt] -> MsgDoc+_mkCaseAltMsg _alts+ = ($$) (text "In some case alternatives, type of alternatives not all same:")+ (Outputable.empty) -- LATER: ppr alts++mkDefltMsg :: Id -> [PrimRep] -> MsgDoc+mkDefltMsg bndr reps+ = ($$) (text "Binder of a case expression doesn't match representation of scrutinee:")+ (ppr bndr $$ ppr (idType bndr) $$ ppr reps)++mkFunAppMsg :: Type -> [Type] -> StgExpr -> MsgDoc+mkFunAppMsg fun_ty arg_tys expr+ = vcat [text "In a function application, function type doesn't match arg types:",+ hang (text "Function type:") 4 (ppr fun_ty),+ hang (text "Arg types:") 4 (vcat (map (ppr) arg_tys)),+ hang (text "Expression:") 4 (ppr expr)]++mkRhsConMsg :: Type -> [Type] -> MsgDoc+mkRhsConMsg fun_ty arg_tys+ = vcat [text "In a RHS constructor application, con type doesn't match arg types:",+ hang (text "Constructor type:") 4 (ppr fun_ty),+ hang (text "Arg types:") 4 (vcat (map (ppr) arg_tys))]++mkAltMsg1 :: Type -> MsgDoc+mkAltMsg1 ty+ = ($$) (text "In a case expression, type of scrutinee does not match patterns")+ (ppr ty)++mkAlgAltMsg2 :: Type -> DataCon -> MsgDoc+mkAlgAltMsg2 ty con+ = vcat [+ text "In some algebraic case alternative, constructor is not a constructor of scrutinee type:",+ ppr ty,+ ppr con+ ]++mkAlgAltMsg3 :: DataCon -> [Id] -> MsgDoc+mkAlgAltMsg3 con alts+ = vcat [+ text "In some algebraic case alternative, number of arguments doesn't match constructor:",+ ppr con,+ ppr alts+ ]++mkAlgAltMsg4 :: Type -> Id -> MsgDoc+mkAlgAltMsg4 ty arg+ = vcat [+ text "In some algebraic case alternative, type of argument doesn't match data constructor:",+ ppr ty,+ ppr arg+ ]++_mkRhsMsg :: Id -> Type -> MsgDoc+_mkRhsMsg binder ty+ = vcat [hsep [text "The type of this binder doesn't match the type of its RHS:",+ ppr binder],+ hsep [text "Binder's type:", ppr (idType binder)],+ hsep [text "Rhs type:", ppr ty]+ ]++mkUnliftedTyMsg :: Id -> StgRhs -> SDoc+mkUnliftedTyMsg binder rhs+ = (text "Let(rec) binder" <+> quotes (ppr binder) <+>+ text "has unlifted type" <+> quotes (ppr (idType binder)))+ $$+ (text "RHS:" <+> ppr rhs)
+ stgSyn/StgSyn.hs view
@@ -0,0 +1,820 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[StgSyn]{Shared term graph (STG) syntax for spineless-tagless code generation}++This data type represents programs just before code generation (conversion to+@Cmm@): basically, what we have is a stylised form of @CoreSyntax@, the style+being one that happens to be ideally suited to spineless tagless code+generation.+-}++{-# LANGUAGE CPP #-}++module StgSyn (+ GenStgArg(..),++ GenStgTopBinding(..), GenStgBinding(..), GenStgExpr(..), GenStgRhs(..),+ GenStgAlt, AltType(..),++ UpdateFlag(..), isUpdatable,++ StgBinderInfo,+ noBinderInfo, stgSatOcc, stgUnsatOcc, satCallsOnly,+ combineStgBinderInfo,++ -- a set of synonyms for the most common (only :-) parameterisation+ StgArg,+ StgTopBinding, StgBinding, StgExpr, StgRhs, StgAlt,++ -- a set of synonyms to distinguish in- and out variants+ InStgArg, InStgTopBinding, InStgBinding, InStgExpr, InStgRhs, InStgAlt,+ OutStgArg, OutStgTopBinding, OutStgBinding, OutStgExpr, OutStgRhs, OutStgAlt,++ -- StgOp+ StgOp(..),++ -- utils+ topStgBindHasCafRefs, stgArgHasCafRefs, stgRhsArity,+ isDllConApp,+ stgArgType,+ stripStgTicksTop,++ pprStgBinding, pprStgTopBindings+ ) where++#include "HsVersions.h"++import CoreSyn ( AltCon, Tickish )+import CostCentre ( CostCentreStack )+import Data.ByteString ( ByteString )+import Data.List ( intersperse )+import DataCon+import DynFlags+import FastString+import ForeignCall ( ForeignCall )+import Id+import IdInfo ( mayHaveCafRefs )+import Literal ( Literal, literalType )+import Module ( Module )+import Outputable+import Packages ( isDllName )+import Platform+import PprCore ( {- instances -} )+import PrimOp ( PrimOp, PrimCall )+import TyCon ( PrimRep(..), TyCon )+import Type ( Type )+import RepType ( typePrimRep1 )+import Unique ( Unique )+import Util++{-+************************************************************************+* *+\subsection{@GenStgBinding@}+* *+************************************************************************++As usual, expressions are interesting; other things are boring. Here+are the boring things [except note the @GenStgRhs@], parameterised+with respect to binder and occurrence information (just as in+@CoreSyn@):+-}++-- | A top-level binding.+data GenStgTopBinding bndr occ+-- See Note [CoreSyn top-level string literals]+ = StgTopLifted (GenStgBinding bndr occ)+ | StgTopStringLit bndr ByteString++data GenStgBinding bndr occ+ = StgNonRec bndr (GenStgRhs bndr occ)+ | StgRec [(bndr, GenStgRhs bndr occ)]++{-+************************************************************************+* *+\subsection{@GenStgArg@}+* *+************************************************************************+-}++data GenStgArg occ+ = StgVarArg occ+ | StgLitArg Literal++-- | Does this constructor application refer to+-- anything in a different *Windows* DLL?+-- If so, we can't allocate it statically+isDllConApp :: DynFlags -> Module -> DataCon -> [StgArg] -> Bool+isDllConApp dflags this_mod con args+ | platformOS (targetPlatform dflags) == OSMinGW32+ = isDllName dflags this_mod (dataConName con) || any is_dll_arg args+ | otherwise = False+ where+ -- NB: typePrimRep1 is legit because any free variables won't have+ -- unlifted type (there are no unlifted things at top level)+ is_dll_arg :: StgArg -> Bool+ is_dll_arg (StgVarArg v) = isAddrRep (typePrimRep1 (idType v))+ && isDllName dflags this_mod (idName v)+ is_dll_arg _ = False++-- True of machine addresses; these are the things that don't+-- work across DLLs. The key point here is that VoidRep comes+-- out False, so that a top level nullary GADT constructor is+-- False for isDllConApp+-- data T a where+-- T1 :: T Int+-- gives+-- T1 :: forall a. (a~Int) -> T a+-- and hence the top-level binding+-- $WT1 :: T Int+-- $WT1 = T1 Int (Coercion (Refl Int))+-- The coercion argument here gets VoidRep+isAddrRep :: PrimRep -> Bool+isAddrRep AddrRep = True+isAddrRep LiftedRep = True+isAddrRep UnliftedRep = True+isAddrRep _ = False++-- | Type of an @StgArg@+--+-- Very half baked because we have lost the type arguments.+stgArgType :: StgArg -> Type+stgArgType (StgVarArg v) = idType v+stgArgType (StgLitArg lit) = literalType lit+++-- | Strip ticks of a given type from an STG expression+stripStgTicksTop :: (Tickish Id -> Bool) -> StgExpr -> ([Tickish Id], StgExpr)+stripStgTicksTop p = go []+ where go ts (StgTick t e) | p t = go (t:ts) e+ go ts other = (reverse ts, other)+++{-+************************************************************************+* *+\subsection{STG expressions}+* *+************************************************************************++The @GenStgExpr@ data type is parameterised on binder and occurrence+info, as before.++************************************************************************+* *+\subsubsection{@GenStgExpr@ application}+* *+************************************************************************++An application is of a function to a list of atoms [not expressions].+Operationally, we want to push the arguments on the stack and call the+function. (If the arguments were expressions, we would have to build+their closures first.)++There is no constructor for a lone variable; it would appear as+@StgApp var []@.+-}++data GenStgExpr bndr occ+ = StgApp+ occ -- function+ [GenStgArg occ] -- arguments; may be empty++{-+************************************************************************+* *+\subsubsection{@StgConApp@ and @StgPrimApp@---saturated applications}+* *+************************************************************************++There are specialised forms of application, for constructors,+primitives, and literals.+-}++ | StgLit Literal++ -- StgConApp is vital for returning unboxed tuples or sums+ -- which can't be let-bound first+ | StgConApp DataCon+ [GenStgArg occ] -- Saturated+ [Type] -- See Note [Types in StgConApp] in UnariseStg++ | StgOpApp StgOp -- Primitive op or foreign call+ [GenStgArg occ] -- Saturated.+ Type -- Result type+ -- We need to know this so that we can+ -- assign result registers++{-+************************************************************************+* *+\subsubsection{@StgLam@}+* *+************************************************************************++StgLam is used *only* during CoreToStg's work. Before CoreToStg has+finished it encodes (\x -> e) as (let f = \x -> e in f)+-}++ | StgLam+ [bndr]+ StgExpr -- Body of lambda++{-+************************************************************************+* *+\subsubsection{@GenStgExpr@: case-expressions}+* *+************************************************************************++This has the same boxed/unboxed business as Core case expressions.+-}++ | StgCase+ (GenStgExpr bndr occ)+ -- the thing to examine++ bndr -- binds the result of evaluating the scrutinee++ AltType++ [GenStgAlt bndr occ]+ -- The DEFAULT case is always *first*+ -- if it is there at all++{-+************************************************************************+* *+\subsubsection{@GenStgExpr@: @let(rec)@-expressions}+* *+************************************************************************++The various forms of let(rec)-expression encode most of the+interesting things we want to do.+\begin{enumerate}+\item+\begin{verbatim}+let-closure x = [free-vars] [args] expr+in e+\end{verbatim}+is equivalent to+\begin{verbatim}+let x = (\free-vars -> \args -> expr) free-vars+\end{verbatim}+\tr{args} may be empty (and is for most closures). It isn't under+circumstances like this:+\begin{verbatim}+let x = (\y -> y+z)+\end{verbatim}+This gets mangled to+\begin{verbatim}+let-closure x = [z] [y] (y+z)+\end{verbatim}+The idea is that we compile code for @(y+z)@ in an environment in which+@z@ is bound to an offset from \tr{Node}, and @y@ is bound to an+offset from the stack pointer.++(A let-closure is an @StgLet@ with a @StgRhsClosure@ RHS.)++\item+\begin{verbatim}+let-constructor x = Constructor [args]+in e+\end{verbatim}++(A let-constructor is an @StgLet@ with a @StgRhsCon@ RHS.)++\item+Letrec-expressions are essentially the same deal as+let-closure/let-constructor, so we use a common structure and+distinguish between them with an @is_recursive@ boolean flag.++\item+\begin{verbatim}+let-unboxed u = an arbitrary arithmetic expression in unboxed values+in e+\end{verbatim}+All the stuff on the RHS must be fully evaluated.+No function calls either!++(We've backed away from this toward case-expressions with+suitably-magical alts ...)++\item+~[Advanced stuff here! Not to start with, but makes pattern matching+generate more efficient code.]++\begin{verbatim}+let-escapes-not fail = expr+in e'+\end{verbatim}+Here the idea is that @e'@ guarantees not to put @fail@ in a data structure,+or pass it to another function. All @e'@ will ever do is tail-call @fail@.+Rather than build a closure for @fail@, all we need do is to record the stack+level at the moment of the @let-escapes-not@; then entering @fail@ is just+a matter of adjusting the stack pointer back down to that point and entering+the code for it.++Another example:+\begin{verbatim}+f x y = let z = huge-expression in+ if y==1 then z else+ if y==2 then z else+ 1+\end{verbatim}++(A let-escapes-not is an @StgLetNoEscape@.)++\item+We may eventually want:+\begin{verbatim}+let-literal x = Literal+in e+\end{verbatim}+\end{enumerate}++And so the code for let(rec)-things:+-}++ | StgLet+ (GenStgBinding bndr occ) -- right hand sides (see below)+ (GenStgExpr bndr occ) -- body++ | StgLetNoEscape+ (GenStgBinding bndr occ) -- right hand sides (see below)+ (GenStgExpr bndr occ) -- body++{-+%************************************************************************+%* *+\subsubsection{@GenStgExpr@: @hpc@, @scc@ and other debug annotations}+%* *+%************************************************************************++Finally for @hpc@ expressions we introduce a new STG construct.+-}++ | StgTick+ (Tickish bndr)+ (GenStgExpr bndr occ) -- sub expression++-- END of GenStgExpr++{-+************************************************************************+* *+\subsection{STG right-hand sides}+* *+************************************************************************++Here's the rest of the interesting stuff for @StgLet@s; the first+flavour is for closures:+-}++data GenStgRhs bndr occ+ = StgRhsClosure+ CostCentreStack -- CCS to be attached (default is CurrentCCS)+ StgBinderInfo -- Info about how this binder is used (see below)+ [occ] -- non-global free vars; a list, rather than+ -- a set, because order is important+ !UpdateFlag -- ReEntrant | Updatable | SingleEntry+ [bndr] -- arguments; if empty, then not a function;+ -- as above, order is important.+ (GenStgExpr bndr occ) -- body++{-+An example may be in order. Consider:+\begin{verbatim}+let t = \x -> \y -> ... x ... y ... p ... q in e+\end{verbatim}+Pulling out the free vars and stylising somewhat, we get the equivalent:+\begin{verbatim}+let t = (\[p,q] -> \[x,y] -> ... x ... y ... p ...q) p q+\end{verbatim}+Stg-operationally, the @[x,y]@ are on the stack, the @[p,q]@ are+offsets from @Node@ into the closure, and the code ptr for the closure+will be exactly that in parentheses above.++The second flavour of right-hand-side is for constructors (simple but important):+-}++ | StgRhsCon+ CostCentreStack -- CCS to be attached (default is CurrentCCS).+ -- Top-level (static) ones will end up with+ -- DontCareCCS, because we don't count static+ -- data in heap profiles, and we don't set CCCS+ -- from static closure.+ DataCon -- Constructor. Never an unboxed tuple or sum, as those+ -- are not allocated.+ [GenStgArg occ] -- Args++stgRhsArity :: StgRhs -> Int+stgRhsArity (StgRhsClosure _ _ _ _ bndrs _)+ = ASSERT( all isId bndrs ) length bndrs+ -- The arity never includes type parameters, but they should have gone by now+stgRhsArity (StgRhsCon _ _ _) = 0++-- Note [CAF consistency]+-- ~~~~~~~~~~~~~~~~~~~~~~+--+-- `topStgBindHasCafRefs` is only used by an assert (`consistentCafInfo` in+-- `CoreToStg`) to make sure CAF-ness predicted by `TidyPgm` is consistent with+-- reality.+--+-- Specifically, if the RHS mentions any Id that itself is marked+-- `MayHaveCafRefs`; or if the binding is a top-level updateable thunk; then the+-- `Id` for the binding should be marked `MayHaveCafRefs`. The potential trouble+-- is that `TidyPgm` computed the CAF info on the `Id` but some transformations+-- have taken place since then.++topStgBindHasCafRefs :: GenStgTopBinding bndr Id -> Bool+topStgBindHasCafRefs (StgTopLifted (StgNonRec _ rhs))+ = topRhsHasCafRefs rhs+topStgBindHasCafRefs (StgTopLifted (StgRec binds))+ = any topRhsHasCafRefs (map snd binds)+topStgBindHasCafRefs StgTopStringLit{}+ = False++topRhsHasCafRefs :: GenStgRhs bndr Id -> Bool+topRhsHasCafRefs (StgRhsClosure _ _ _ upd _ body)+ = -- See Note [CAF consistency]+ isUpdatable upd || exprHasCafRefs body+topRhsHasCafRefs (StgRhsCon _ _ args)+ = any stgArgHasCafRefs args++exprHasCafRefs :: GenStgExpr bndr Id -> Bool+exprHasCafRefs (StgApp f args)+ = stgIdHasCafRefs f || any stgArgHasCafRefs args+exprHasCafRefs StgLit{}+ = False+exprHasCafRefs (StgConApp _ args _)+ = any stgArgHasCafRefs args+exprHasCafRefs (StgOpApp _ args _)+ = any stgArgHasCafRefs args+exprHasCafRefs (StgLam _ body)+ = exprHasCafRefs body+exprHasCafRefs (StgCase scrt _ _ alts)+ = exprHasCafRefs scrt || any altHasCafRefs alts+exprHasCafRefs (StgLet bind body)+ = bindHasCafRefs bind || exprHasCafRefs body+exprHasCafRefs (StgLetNoEscape bind body)+ = bindHasCafRefs bind || exprHasCafRefs body+exprHasCafRefs (StgTick _ expr)+ = exprHasCafRefs expr++bindHasCafRefs :: GenStgBinding bndr Id -> Bool+bindHasCafRefs (StgNonRec _ rhs)+ = rhsHasCafRefs rhs+bindHasCafRefs (StgRec binds)+ = any rhsHasCafRefs (map snd binds)++rhsHasCafRefs :: GenStgRhs bndr Id -> Bool+rhsHasCafRefs (StgRhsClosure _ _ _ _ _ body)+ = exprHasCafRefs body+rhsHasCafRefs (StgRhsCon _ _ args)+ = any stgArgHasCafRefs args++altHasCafRefs :: GenStgAlt bndr Id -> Bool+altHasCafRefs (_, _, rhs) = exprHasCafRefs rhs++stgArgHasCafRefs :: GenStgArg Id -> Bool+stgArgHasCafRefs (StgVarArg id)+ = stgIdHasCafRefs id+stgArgHasCafRefs _+ = False++stgIdHasCafRefs :: Id -> Bool+stgIdHasCafRefs id =+ -- We are looking for occurrences of an Id that is bound at top level, and may+ -- have CAF refs. At this point (after TidyPgm) top-level Ids (whether+ -- imported or defined in this module) are GlobalIds, so the test is easy.+ isGlobalId id && mayHaveCafRefs (idCafInfo id)++-- Here's the @StgBinderInfo@ type, and its combining op:++data StgBinderInfo+ = NoStgBinderInfo+ | SatCallsOnly -- All occurrences are *saturated* *function* calls+ -- This means we don't need to build an info table and+ -- slow entry code for the thing+ -- Thunks never get this value++noBinderInfo, stgUnsatOcc, stgSatOcc :: StgBinderInfo+noBinderInfo = NoStgBinderInfo+stgUnsatOcc = NoStgBinderInfo+stgSatOcc = SatCallsOnly++satCallsOnly :: StgBinderInfo -> Bool+satCallsOnly SatCallsOnly = True+satCallsOnly NoStgBinderInfo = False++combineStgBinderInfo :: StgBinderInfo -> StgBinderInfo -> StgBinderInfo+combineStgBinderInfo SatCallsOnly SatCallsOnly = SatCallsOnly+combineStgBinderInfo _ _ = NoStgBinderInfo++--------------+pp_binder_info :: StgBinderInfo -> SDoc+pp_binder_info NoStgBinderInfo = empty+pp_binder_info SatCallsOnly = text "sat-only"++{-+************************************************************************+* *+\subsection[Stg-case-alternatives]{STG case alternatives}+* *+************************************************************************++Very like in @CoreSyntax@ (except no type-world stuff).++The type constructor is guaranteed not to be abstract; that is, we can+see its representation. This is important because the code generator+uses it to determine return conventions etc. But it's not trivial+where there's a module loop involved, because some versions of a type+constructor might not have all the constructors visible. So+mkStgAlgAlts (in CoreToStg) ensures that it gets the TyCon from the+constructors or literals (which are guaranteed to have the Real McCoy)+rather than from the scrutinee type.+-}++type GenStgAlt bndr occ+ = (AltCon, -- alts: data constructor,+ [bndr], -- constructor's parameters,+ GenStgExpr bndr occ) -- ...right-hand side.++data AltType+ = PolyAlt -- Polymorphic (a lifted type variable)+ | MultiValAlt Int -- Multi value of this arity (unboxed tuple or sum)+ -- the arity could indeed be 1 for unary unboxed tuple+ | AlgAlt TyCon -- Algebraic data type; the AltCons will be DataAlts+ | PrimAlt PrimRep -- Primitive data type; the AltCons (if any) will be LitAlts++{-+************************************************************************+* *+\subsection[Stg]{The Plain STG parameterisation}+* *+************************************************************************++This happens to be the only one we use at the moment.+-}++type StgTopBinding = GenStgTopBinding Id Id+type StgBinding = GenStgBinding Id Id+type StgArg = GenStgArg Id+type StgExpr = GenStgExpr Id Id+type StgRhs = GenStgRhs Id Id+type StgAlt = GenStgAlt Id Id++{- Many passes apply a substitution, and it's very handy to have type+ synonyms to remind us whether or not the substitution has been applied.+ See CoreSyn for precedence in Core land+-}++type InStgTopBinding = StgTopBinding+type InStgBinding = StgBinding+type InStgArg = StgArg+type InStgExpr = StgExpr+type InStgRhs = StgRhs+type InStgAlt = StgAlt+type OutStgTopBinding = StgTopBinding+type OutStgBinding = StgBinding+type OutStgArg = StgArg+type OutStgExpr = StgExpr+type OutStgRhs = StgRhs+type OutStgAlt = StgAlt++{-++************************************************************************+* *+\subsubsection[UpdateFlag-datatype]{@UpdateFlag@}+* *+************************************************************************++This is also used in @LambdaFormInfo@ in the @ClosureInfo@ module.++A @ReEntrant@ closure may be entered multiple times, but should not be+updated or blackholed. An @Updatable@ closure should be updated after+evaluation (and may be blackholed during evaluation). A @SingleEntry@+closure will only be entered once, and so need not be updated but may+safely be blackholed.+-}++data UpdateFlag = ReEntrant | Updatable | SingleEntry++instance Outputable UpdateFlag where+ ppr u = char $ case u of+ ReEntrant -> 'r'+ Updatable -> 'u'+ SingleEntry -> 's'++isUpdatable :: UpdateFlag -> Bool+isUpdatable ReEntrant = False+isUpdatable SingleEntry = False+isUpdatable Updatable = True++{-+************************************************************************+* *+\subsubsection{StgOp}+* *+************************************************************************++An StgOp allows us to group together PrimOps and ForeignCalls.+It's quite useful to move these around together, notably+in StgOpApp and COpStmt.+-}++data StgOp+ = StgPrimOp PrimOp++ | StgPrimCallOp PrimCall++ | StgFCallOp ForeignCall Unique+ -- The Unique is occasionally needed by the C pretty-printer+ -- (which lacks a unique supply), notably when generating a+ -- typedef for foreign-export-dynamic++{-+************************************************************************+* *+\subsection[Stg-pretty-printing]{Pretty-printing}+* *+************************************************************************++Robin Popplestone asked for semi-colon separators on STG binds; here's+hoping he likes terminators instead... Ditto for case alternatives.+-}++pprGenStgTopBinding :: (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => GenStgTopBinding bndr bdee -> SDoc++pprGenStgTopBinding (StgTopStringLit bndr str)+ = hang (hsep [pprBndr LetBind bndr, equals])+ 4 (pprHsBytes str <> semi)+pprGenStgTopBinding (StgTopLifted bind)+ = pprGenStgBinding bind++pprGenStgBinding :: (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => GenStgBinding bndr bdee -> SDoc++pprGenStgBinding (StgNonRec bndr rhs)+ = hang (hsep [pprBndr LetBind bndr, equals])+ 4 (ppr rhs <> semi)++pprGenStgBinding (StgRec pairs)+ = vcat $ ifPprDebug (text "{- StgRec (begin) -}") :+ map (ppr_bind) pairs ++ [ifPprDebug (text "{- StgRec (end) -}")]+ where+ ppr_bind (bndr, expr)+ = hang (hsep [pprBndr LetBind bndr, equals])+ 4 (ppr expr <> semi)++pprStgBinding :: StgBinding -> SDoc+pprStgBinding bind = pprGenStgBinding bind++pprStgTopBindings :: [StgTopBinding] -> SDoc+pprStgTopBindings binds+ = vcat $ intersperse blankLine (map pprGenStgTopBinding binds)++instance (Outputable bdee) => Outputable (GenStgArg bdee) where+ ppr = pprStgArg++instance (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => Outputable (GenStgTopBinding bndr bdee) where+ ppr = pprGenStgTopBinding++instance (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => Outputable (GenStgBinding bndr bdee) where+ ppr = pprGenStgBinding++instance (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => Outputable (GenStgExpr bndr bdee) where+ ppr = pprStgExpr++instance (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => Outputable (GenStgRhs bndr bdee) where+ ppr rhs = pprStgRhs rhs++pprStgArg :: (Outputable bdee) => GenStgArg bdee -> SDoc+pprStgArg (StgVarArg var) = ppr var+pprStgArg (StgLitArg con) = ppr con++pprStgExpr :: (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => GenStgExpr bndr bdee -> SDoc+-- special case+pprStgExpr (StgLit lit) = ppr lit++-- general case+pprStgExpr (StgApp func args)+ = hang (ppr func) 4 (sep (map (ppr) args))++pprStgExpr (StgConApp con args _)+ = hsep [ ppr con, brackets (interppSP args) ]++pprStgExpr (StgOpApp op args _)+ = hsep [ pprStgOp op, brackets (interppSP args)]++pprStgExpr (StgLam bndrs body)+ = sep [ char '\\' <+> ppr_list (map (pprBndr LambdaBind) bndrs)+ <+> text "->",+ pprStgExpr body ]+ where ppr_list = brackets . fsep . punctuate comma++-- special case: let v = <very specific thing>+-- in+-- let ...+-- in+-- ...+--+-- Very special! Suspicious! (SLPJ)++{-+pprStgExpr (StgLet srt (StgNonRec bndr (StgRhsClosure cc bi free_vars upd_flag args rhs))+ expr@(StgLet _ _))+ = ($$)+ (hang (hcat [text "let { ", ppr bndr, ptext (sLit " = "),+ ppr cc,+ pp_binder_info bi,+ text " [", ifPprDebug (interppSP free_vars), ptext (sLit "] \\"),+ ppr upd_flag, text " [",+ interppSP args, char ']'])+ 8 (sep [hsep [ppr rhs, text "} in"]]))+ (ppr expr)+-}++-- special case: let ... in let ...++pprStgExpr (StgLet bind expr@(StgLet _ _))+ = ($$)+ (sep [hang (text "let {")+ 2 (hsep [pprGenStgBinding bind, text "} in"])])+ (ppr expr)++-- general case+pprStgExpr (StgLet bind expr)+ = sep [hang (text "let {") 2 (pprGenStgBinding bind),+ hang (text "} in ") 2 (ppr expr)]++pprStgExpr (StgLetNoEscape bind expr)+ = sep [hang (text "let-no-escape {")+ 2 (pprGenStgBinding bind),+ hang (text "} in ")+ 2 (ppr expr)]++pprStgExpr (StgTick tickish expr)+ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_SuppressTicks dflags+ then pprStgExpr expr+ else sep [ ppr tickish, pprStgExpr expr ]+++pprStgExpr (StgCase expr bndr alt_type alts)+ = sep [sep [text "case",+ nest 4 (hsep [pprStgExpr expr,+ ifPprDebug (dcolon <+> ppr alt_type)]),+ text "of", pprBndr CaseBind bndr, char '{'],+ nest 2 (vcat (map pprStgAlt alts)),+ char '}']++pprStgAlt :: (OutputableBndr bndr, Outputable occ, Ord occ)+ => GenStgAlt bndr occ -> SDoc+pprStgAlt (con, params, expr)+ = hang (hsep [ppr con, sep (map (pprBndr CasePatBind) params), text "->"])+ 4 (ppr expr <> semi)++pprStgOp :: StgOp -> SDoc+pprStgOp (StgPrimOp op) = ppr op+pprStgOp (StgPrimCallOp op)= ppr op+pprStgOp (StgFCallOp op _) = ppr op++instance Outputable AltType where+ ppr PolyAlt = text "Polymorphic"+ ppr (MultiValAlt n) = text "MultiAlt" <+> ppr n+ ppr (AlgAlt tc) = text "Alg" <+> ppr tc+ ppr (PrimAlt tc) = text "Prim" <+> ppr tc++pprStgRhs :: (OutputableBndr bndr, Outputable bdee, Ord bdee)+ => GenStgRhs bndr bdee -> SDoc++-- special case+pprStgRhs (StgRhsClosure cc bi [free_var] upd_flag [{-no args-}] (StgApp func []))+ = hsep [ ppr cc,+ pp_binder_info bi,+ brackets (ifPprDebug (ppr free_var)),+ text " \\", ppr upd_flag, ptext (sLit " [] "), ppr func ]++-- general case+pprStgRhs (StgRhsClosure cc bi free_vars upd_flag args body)+ = sdocWithDynFlags $ \dflags ->+ hang (hsep [if gopt Opt_SccProfilingOn dflags then ppr cc else empty,+ pp_binder_info bi,+ ifPprDebug (brackets (interppSP free_vars)),+ char '\\' <> ppr upd_flag, brackets (interppSP args)])+ 4 (ppr body)++pprStgRhs (StgRhsCon cc con args)+ = hcat [ ppr cc,+ space, ppr con, text "! ", brackets (interppSP args)]
+ stranal/DmdAnal.hs view
@@ -0,0 +1,1482 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998+++ -----------------+ A demand analysis+ -----------------+-}++{-# LANGUAGE CPP #-}++module DmdAnal ( dmdAnalProgram ) where++#include "HsVersions.h"++import DynFlags+import WwLib ( findTypeShape, deepSplitProductType_maybe )+import Demand -- All of it+import CoreSyn+import CoreSeq ( seqBinds )+import Outputable+import VarEnv+import BasicTypes+import Data.List+import DataCon+import Id+import CoreUtils ( exprIsHNF, exprType, exprIsTrivial )+import TyCon+import Type+import Coercion ( Coercion, coVarsOfCo )+import FamInstEnv+import Util+import Maybes ( isJust )+import TysWiredIn+import TysPrim ( realWorldStatePrimTy )+import ErrUtils ( dumpIfSet_dyn )+import Name ( getName, stableNameCmp )+import Data.Function ( on )+import UniqSet++{-+************************************************************************+* *+\subsection{Top level stuff}+* *+************************************************************************+-}++dmdAnalProgram :: DynFlags -> FamInstEnvs -> CoreProgram -> IO CoreProgram+dmdAnalProgram dflags fam_envs binds+ = do {+ let { binds_plus_dmds = do_prog binds } ;+ dumpIfSet_dyn dflags Opt_D_dump_str_signatures+ "Strictness signatures" $+ dumpStrSig binds_plus_dmds ;+ -- See Note [Stamp out space leaks in demand analysis]+ seqBinds binds_plus_dmds `seq` return binds_plus_dmds+ }+ where+ do_prog :: CoreProgram -> CoreProgram+ do_prog binds = snd $ mapAccumL dmdAnalTopBind (emptyAnalEnv dflags fam_envs) binds++-- Analyse a (group of) top-level binding(s)+dmdAnalTopBind :: AnalEnv+ -> CoreBind+ -> (AnalEnv, CoreBind)+dmdAnalTopBind sigs (NonRec id rhs)+ = (extendAnalEnv TopLevel sigs id2 (idStrictness id2), NonRec id2 rhs2)+ where+ ( _, _, rhs1) = dmdAnalRhsLetDown TopLevel Nothing sigs id rhs+ ( _, id2, rhs2) = dmdAnalRhsLetDown TopLevel Nothing (nonVirgin sigs) id rhs1+ -- Do two passes to improve CPR information+ -- See Note [CPR for thunks]+ -- See Note [Optimistic CPR in the "virgin" case]+ -- See Note [Initial CPR for strict binders]++dmdAnalTopBind sigs (Rec pairs)+ = (sigs', Rec pairs')+ where+ (sigs', _, pairs') = dmdFix TopLevel sigs pairs+ -- We get two iterations automatically+ -- c.f. the NonRec case above++{- Note [Stamp out space leaks in demand analysis]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The demand analysis pass outputs a new copy of the Core program in+which binders have been annotated with demand and strictness+information. It's tiresome to ensure that this information is fully+evaluated everywhere that we produce it, so we just run a single+seqBinds over the output before returning it, to ensure that there are+no references holding on to the input Core program.++This is particularly important when we are doing late demand analysis,+since we don't do a seqBinds at any point thereafter. Hence code+generation would hold on to an extra copy of the Core program, via+unforced thunks in demand or strictness information; and it is the+most memory-intensive part of the compilation process, so this added+seqBinds makes a big difference in peak memory usage.+-}+++{-+************************************************************************+* *+\subsection{The analyser itself}+* *+************************************************************************++Note [Ensure demand is strict]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's important not to analyse e with a lazy demand because+a) When we encounter case s of (a,b) ->+ we demand s with U(d1d2)... but if the overall demand is lazy+ that is wrong, and we'd need to reduce the demand on s,+ which is inconvenient+b) More important, consider+ f (let x = R in x+x), where f is lazy+ We still want to mark x as demanded, because it will be when we+ enter the let. If we analyse f's arg with a Lazy demand, we'll+ just mark x as Lazy+c) The application rule wouldn't be right either+ Evaluating (f x) in a L demand does *not* cause+ evaluation of f in a C(L) demand!+-}++-- If e is complicated enough to become a thunk, its contents will be evaluated+-- at most once, so oneify it.+dmdTransformThunkDmd :: CoreExpr -> Demand -> Demand+dmdTransformThunkDmd e+ | exprIsTrivial e = id+ | otherwise = oneifyDmd++-- Do not process absent demands+-- Otherwise act like in a normal demand analysis+-- See ↦* relation in the Cardinality Analysis paper+dmdAnalStar :: AnalEnv+ -> Demand -- This one takes a *Demand*+ -> CoreExpr -> (BothDmdArg, CoreExpr)+dmdAnalStar env dmd e+ | (defer_and_use, cd) <- toCleanDmd dmd (exprType e)+ , (dmd_ty, e') <- dmdAnal env cd e+ = (postProcessDmdType defer_and_use dmd_ty, e')++-- Main Demand Analsysis machinery+dmdAnal, dmdAnal' :: AnalEnv+ -> CleanDemand -- The main one takes a *CleanDemand*+ -> CoreExpr -> (DmdType, CoreExpr)++-- The CleanDemand is always strict and not absent+-- See Note [Ensure demand is strict]++dmdAnal env d e = -- pprTrace "dmdAnal" (ppr d <+> ppr e) $+ dmdAnal' env d e++dmdAnal' _ _ (Lit lit) = (nopDmdType, Lit lit)+dmdAnal' _ _ (Type ty) = (nopDmdType, Type ty) -- Doesn't happen, in fact+dmdAnal' _ _ (Coercion co)+ = (unitDmdType (coercionDmdEnv co), Coercion co)++dmdAnal' env dmd (Var var)+ = (dmdTransform env var dmd, Var var)++dmdAnal' env dmd (Cast e co)+ = (dmd_ty `bothDmdType` mkBothDmdArg (coercionDmdEnv co), Cast e' co)+ where+ (dmd_ty, e') = dmdAnal env dmd e++{- ----- I don't get this, so commenting out -------+ to_co = pSnd (coercionKind co)+ dmd'+ | Just tc <- tyConAppTyCon_maybe to_co+ , isRecursiveTyCon tc = cleanEvalDmd+ | otherwise = dmd+ -- This coerce usually arises from a recursive+ -- newtype, and we don't want to look inside them+ -- for exactly the same reason that we don't look+ -- inside recursive products -- we might not reach+ -- a fixpoint. So revert to a vanilla Eval demand+-}++dmdAnal' env dmd (Tick t e)+ = (dmd_ty, Tick t e')+ where+ (dmd_ty, e') = dmdAnal env dmd e++dmdAnal' env dmd (App fun (Type ty))+ = (fun_ty, App fun' (Type ty))+ where+ (fun_ty, fun') = dmdAnal env dmd fun++-- Lots of the other code is there to make this+-- beautiful, compositional, application rule :-)+dmdAnal' env dmd (App fun arg)+ = -- This case handles value arguments (type args handled above)+ -- Crucially, coercions /are/ handled here, because they are+ -- value arguments (Trac #10288)+ let+ call_dmd = mkCallDmd dmd+ (fun_ty, fun') = dmdAnal env call_dmd fun+ (arg_dmd, res_ty) = splitDmdTy fun_ty+ (arg_ty, arg') = dmdAnalStar env (dmdTransformThunkDmd arg arg_dmd) arg+ in+-- pprTrace "dmdAnal:app" (vcat+-- [ text "dmd =" <+> ppr dmd+-- , text "expr =" <+> ppr (App fun arg)+-- , text "fun dmd_ty =" <+> ppr fun_ty+-- , text "arg dmd =" <+> ppr arg_dmd+-- , text "arg dmd_ty =" <+> ppr arg_ty+-- , text "res dmd_ty =" <+> ppr res_ty+-- , text "overall res dmd_ty =" <+> ppr (res_ty `bothDmdType` arg_ty) ])+ (res_ty `bothDmdType` arg_ty, App fun' arg')++-- this is an anonymous lambda, since @dmdAnalRhsLetDown@ uses @collectBinders@+dmdAnal' env dmd (Lam var body)+ | isTyVar var+ = let+ (body_ty, body') = dmdAnal env dmd body+ in+ (body_ty, Lam var body')++ | otherwise+ = let (body_dmd, defer_and_use) = peelCallDmd dmd+ -- body_dmd: a demand to analyze the body++ env' = extendSigsWithLam env var+ (body_ty, body') = dmdAnal env' body_dmd body+ (lam_ty, var') = annotateLamIdBndr env notArgOfDfun body_ty var+ in+ (postProcessUnsat defer_and_use lam_ty, Lam var' body')++dmdAnal' env dmd (Case scrut case_bndr ty [(DataAlt dc, bndrs, rhs)])+ -- Only one alternative with a product constructor+ | let tycon = dataConTyCon dc+ , isJust (isDataProductTyCon_maybe tycon)+ , Just rec_tc' <- checkRecTc (ae_rec_tc env) tycon+ = let+ env_w_tc = env { ae_rec_tc = rec_tc' }+ env_alt = extendEnvForProdAlt env_w_tc scrut case_bndr dc bndrs+ (rhs_ty, rhs') = dmdAnal env_alt dmd rhs+ (alt_ty1, dmds) = findBndrsDmds env rhs_ty bndrs+ (alt_ty2, case_bndr_dmd) = findBndrDmd env False alt_ty1 case_bndr+ id_dmds = addCaseBndrDmd case_bndr_dmd dmds+ alt_ty3 | io_hack_reqd scrut dc bndrs = deferAfterIO alt_ty2+ | otherwise = alt_ty2++ -- Compute demand on the scrutinee+ -- See Note [Demand on scrutinee of a product case]+ scrut_dmd = mkProdDmd (addDataConStrictness dc id_dmds)+ (scrut_ty, scrut') = dmdAnal env scrut_dmd scrut+ res_ty = alt_ty3 `bothDmdType` toBothDmdArg scrut_ty+ case_bndr' = setIdDemandInfo case_bndr case_bndr_dmd+ bndrs' = setBndrsDemandInfo bndrs id_dmds+ in+-- pprTrace "dmdAnal:Case1" (vcat [ text "scrut" <+> ppr scrut+-- , text "dmd" <+> ppr dmd+-- , text "case_bndr_dmd" <+> ppr (idDemandInfo case_bndr')+-- , text "scrut_dmd" <+> ppr scrut_dmd+-- , text "scrut_ty" <+> ppr scrut_ty+-- , text "alt_ty" <+> ppr alt_ty2+-- , text "res_ty" <+> ppr res_ty ]) $+ (res_ty, Case scrut' case_bndr' ty [(DataAlt dc, bndrs', rhs')])++dmdAnal' env dmd (Case scrut case_bndr ty alts)+ = let -- Case expression with multiple alternatives+ (alt_tys, alts') = mapAndUnzip (dmdAnalAlt env dmd case_bndr) alts+ (scrut_ty, scrut') = dmdAnal env cleanEvalDmd scrut+ (alt_ty, case_bndr') = annotateBndr env (foldr lubDmdType botDmdType alt_tys) case_bndr+ -- 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+ res_ty = alt_ty `bothDmdType` toBothDmdArg scrut_ty+ in+-- pprTrace "dmdAnal:Case2" (vcat [ text "scrut" <+> ppr scrut+-- , text "scrut_ty" <+> ppr scrut_ty+-- , text "alt_tys" <+> ppr alt_tys+-- , text "alt_ty" <+> ppr alt_ty+-- , text "res_ty" <+> ppr res_ty ]) $+ (res_ty, Case scrut' case_bndr' ty alts')++-- Let bindings can be processed in two ways:+-- Down (RHS before body) or Up (body before RHS).+-- The following case handle the up variant.+--+-- It is very simple. For let x = rhs in body+-- * Demand-analyse 'body' in the current environment+-- * Find the demand, 'rhs_dmd' placed on 'x' by 'body'+-- * Demand-analyse 'rhs' in 'rhs_dmd'+--+-- This is used for a non-recursive local let without manifest lambdas.+-- This is the LetUp rule in the paper “Higher-Order Cardinality Analysis”.+dmdAnal' env dmd (Let (NonRec id rhs) body)+ | useLetUp id rhs+ , Nothing <- unpackTrivial rhs+ -- dmdAnalRhsLetDown treats trivial right hand sides specially+ -- so if we have a trival right hand side, fall through to that.+ = (final_ty, Let (NonRec id' rhs') body')+ where+ (body_ty, body') = dmdAnal env dmd body+ (body_ty', id_dmd) = findBndrDmd env notArgOfDfun body_ty id+ id' = setIdDemandInfo id id_dmd++ (rhs_ty, rhs') = dmdAnalStar env (dmdTransformThunkDmd rhs id_dmd) rhs+ final_ty = body_ty' `bothDmdType` rhs_ty++dmdAnal' env dmd (Let (NonRec id rhs) body)+ = (body_ty2, Let (NonRec id2 rhs') body')+ where+ (lazy_fv, id1, rhs') = dmdAnalRhsLetDown NotTopLevel Nothing env id rhs+ env1 = extendAnalEnv NotTopLevel env id1 (idStrictness id1)+ (body_ty, body') = dmdAnal env1 dmd body+ (body_ty1, id2) = annotateBndr env body_ty id1+ body_ty2 = addLazyFVs body_ty1 lazy_fv -- see Note [Lazy and unleasheable free variables]++ -- If the actual demand is better than the vanilla call+ -- demand, you might think that we might do better to re-analyse+ -- the RHS with the stronger demand.+ -- But (a) That seldom happens, because it means that *every* path in+ -- the body of the let has to use that stronger demand+ -- (b) It often happens temporarily in when fixpointing, because+ -- the recursive function at first seems to place a massive demand.+ -- But we don't want to go to extra work when the function will+ -- probably iterate to something less demanding.+ -- In practice, all the times the actual demand on id2 is more than+ -- the vanilla call demand seem to be due to (b). So we don't+ -- bother to re-analyse the RHS.++dmdAnal' env dmd (Let (Rec pairs) body)+ = let+ (env', lazy_fv, pairs') = dmdFix NotTopLevel env pairs+ (body_ty, body') = dmdAnal env' dmd body+ body_ty1 = deleteFVs body_ty (map fst pairs)+ body_ty2 = addLazyFVs body_ty1 lazy_fv -- see Note [Lazy and unleasheable free variables]+ in+ body_ty2 `seq`+ (body_ty2, Let (Rec pairs') body')++io_hack_reqd :: CoreExpr -> DataCon -> [Var] -> Bool+-- See Note [IO hack in the demand analyser]+io_hack_reqd scrut con bndrs+ | (bndr:_) <- bndrs+ , con == tupleDataCon Unboxed 2+ , idType bndr `eqType` realWorldStatePrimTy+ , (fun, _) <- collectArgs scrut+ = case fun of+ Var f -> not (isPrimOpId f)+ _ -> True+ | otherwise+ = False++dmdAnalAlt :: AnalEnv -> CleanDemand -> Id -> Alt Var -> (DmdType, Alt Var)+dmdAnalAlt env dmd case_bndr (con,bndrs,rhs)+ | null bndrs -- Literals, DEFAULT, and nullary constructors+ , (rhs_ty, rhs') <- dmdAnal env dmd rhs+ = (rhs_ty, (con, [], rhs'))++ | otherwise -- Non-nullary data constructors+ , (rhs_ty, rhs') <- dmdAnal env dmd rhs+ , (alt_ty, dmds) <- findBndrsDmds env rhs_ty bndrs+ , let case_bndr_dmd = findIdDemand alt_ty case_bndr+ id_dmds = addCaseBndrDmd case_bndr_dmd dmds+ = (alt_ty, (con, setBndrsDemandInfo bndrs id_dmds, rhs'))+++{- Note [IO hack in the demand analyser]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There's a hack here for I/O operations. Consider++ case foo x s of { (# s', r #) -> y }++Is this strict in 'y'? Often not! If foo x s performs some observable action+(including raising an exception with raiseIO#, modifying a mutable variable, or+even ending the program normally), then we must not force 'y' (which may fail+to terminate) until we have performed foo x s.++Hackish solution: spot the IO-like situation and add a virtual branch,+as if we had+ case foo x s of+ (# s, r #) -> y+ other -> return ()+So the 'y' isn't necessarily going to be evaluated++A more complete example (Trac #148, #1592) where this shows up is:+ do { let len = <expensive> ;+ ; when (...) (exitWith ExitSuccess)+ ; print len }++However, consider+ f x s = case getMaskingState# s of+ (# s, r #) ->+ case x of I# x2 -> ...++Here it is terribly sad to make 'f' lazy in 's'. After all,+getMaskingState# is not going to diverge or throw an exception! This+situation actually arises in GHC.IO.Handle.Internals.wantReadableHandle+(on an MVar not an Int), and made a material difference.++So if the scrutinee is a primop call, we *don't* apply the+state hack:+ - If is a simple, terminating one like getMaskingState,+ applying the hack is over-conservative.+ - If the primop is raise# then it returns bottom, so+ the case alternatives are already discarded.+ - If the primop can raise a non-IO exception, like+ divide by zero or seg-fault (eg writing an array+ out of bounds) then we don't mind evaluating 'x' first.++Note [Demand on the scrutinee of a product case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When figuring out the demand on the scrutinee of a product case,+we use the demands of the case alternative, i.e. id_dmds.+But note that these include the demand on the case binder;+see Note [Demand on case-alternative binders] in Demand.hs.+This is crucial. Example:+ f x = case x of y { (a,b) -> k y a }+If we just take scrut_demand = U(L,A), then we won't pass x to the+worker, so the worker will rebuild+ x = (a, absent-error)+and that'll crash.++Note [Aggregated demand for cardinality]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We use different strategies for strictness and usage/cardinality to+"unleash" demands captured on free variables by bindings. Let us+consider the example:++f1 y = let {-# NOINLINE h #-}+ h = y+ in (h, h)++We are interested in obtaining cardinality demand U1 on |y|, as it is+used only in a thunk, and, therefore, is not going to be updated any+more. Therefore, the demand on |y|, captured and unleashed by usage of+|h| is U1. However, if we unleash this demand every time |h| is used,+and then sum up the effects, the ultimate demand on |y| will be U1 ++U1 = U. In order to avoid it, we *first* collect the aggregate demand+on |h| in the body of let-expression, and only then apply the demand+transformer:++transf[x](U) = {y |-> U1}++so the resulting demand on |y| is U1.++The situation is, however, different for strictness, where this+aggregating approach exhibits worse results because of the nature of+|both| operation for strictness. Consider the example:++f y c =+ let h x = y |seq| x+ in case of+ True -> h True+ False -> y++It is clear that |f| is strict in |y|, however, the suggested analysis+will infer from the body of |let| that |h| is used lazily (as it is+used in one branch only), therefore lazy demand will be put on its+free variable |y|. Conversely, if the demand on |h| is unleashed right+on the spot, we will get the desired result, namely, that |f| is+strict in |y|.+++************************************************************************+* *+ Demand transformer+* *+************************************************************************+-}++dmdTransform :: AnalEnv -- The strictness environment+ -> Id -- The function+ -> CleanDemand -- 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 env var dmd+ | isDataConWorkId var -- Data constructor+ = dmdTransformDataConSig (idArity var) (idStrictness var) dmd++ | gopt Opt_DmdTxDictSel (ae_dflags env),+ Just _ <- isClassOpId_maybe var -- Dictionary component selector+ = dmdTransformDictSelSig (idStrictness var) dmd++ | isGlobalId var -- Imported function+ = let res = dmdTransformSig (idStrictness var) dmd in+-- pprTrace "dmdTransform" (vcat [ppr var, ppr (idStrictness var), ppr dmd, ppr res])+ res++ | Just (sig, top_lvl) <- lookupSigEnv env var -- Local letrec bound thing+ , let fn_ty = dmdTransformSig sig dmd+ = -- pprTrace "dmdTransform" (vcat [ppr var, ppr sig, ppr dmd, ppr fn_ty]) $+ if isTopLevel top_lvl+ then fn_ty -- Don't record top level things+ else addVarDmd fn_ty var (mkOnceUsedDmd dmd)++ | otherwise -- Local non-letrec-bound thing+ = unitDmdType (unitVarEnv var (mkOnceUsedDmd dmd))++{-+************************************************************************+* *+\subsection{Bindings}+* *+************************************************************************+-}++-- Recursive bindings+dmdFix :: TopLevelFlag+ -> AnalEnv -- Does not include bindings for this binding+ -> [(Id,CoreExpr)]+ -> (AnalEnv, DmdEnv, [(Id,CoreExpr)]) -- Binders annotated with stricness info++dmdFix top_lvl env orig_pairs+ = loop 1 initial_pairs+ where+ bndrs = map fst orig_pairs++ -- See Note [Initialising strictness]+ initial_pairs | ae_virgin env = [(setIdStrictness id botSig, rhs) | (id, rhs) <- orig_pairs ]++ | otherwise = orig_pairs++ -- If fixed-point iteration does not yield a result we use this instead+ -- See Note [Safe abortion in the fixed-point iteration]+ abort :: (AnalEnv, DmdEnv, [(Id,CoreExpr)])+ abort = (env, lazy_fv', zapped_pairs)+ where (lazy_fv, pairs') = step True (zapIdStrictness orig_pairs)+ -- Note [Lazy and unleasheable free variables]+ non_lazy_fvs = plusVarEnvList $ map (strictSigDmdEnv . idStrictness . fst) pairs'+ lazy_fv' = lazy_fv `plusVarEnv` mapVarEnv (const topDmd) non_lazy_fvs+ zapped_pairs = zapIdStrictness pairs'++ -- The fixed-point varies the idStrictness field of the binders, and terminates if that+ -- annotation does not change any more.+ loop :: Int -> [(Id,CoreExpr)] -> (AnalEnv, DmdEnv, [(Id,CoreExpr)])+ loop n pairs+ | found_fixpoint = (final_anal_env, lazy_fv, pairs')+ | n == 10 = abort+ | otherwise = loop (n+1) pairs'+ where+ found_fixpoint = map (idStrictness . fst) pairs' == map (idStrictness . fst) pairs+ first_round = n == 1+ (lazy_fv, pairs') = step first_round pairs+ final_anal_env = extendAnalEnvs top_lvl env (map fst pairs')++ step :: Bool -> [(Id, CoreExpr)] -> (DmdEnv, [(Id, CoreExpr)])+ step first_round pairs = (lazy_fv, pairs')+ where+ -- In all but the first iteration, delete the virgin flag+ start_env | first_round = env+ | otherwise = nonVirgin env++ start = (extendAnalEnvs top_lvl start_env (map fst pairs), emptyDmdEnv)++ ((_,lazy_fv), pairs') = mapAccumL my_downRhs start pairs+ -- mapAccumL: Use the new signature to do the next pair+ -- The occurrence analyser has arranged them in a good order+ -- so this can significantly reduce the number of iterations needed++ my_downRhs (env, lazy_fv) (id,rhs)+ = ((env', lazy_fv'), (id', rhs'))+ where+ (lazy_fv1, id', rhs') = dmdAnalRhsLetDown top_lvl (Just bndrs) env id rhs+ lazy_fv' = plusVarEnv_C bothDmd lazy_fv lazy_fv1+ env' = extendAnalEnv top_lvl env id (idStrictness id')+++ zapIdStrictness :: [(Id, CoreExpr)] -> [(Id, CoreExpr)]+ zapIdStrictness pairs = [(setIdStrictness id nopSig, rhs) | (id, rhs) <- pairs ]++{-+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:++ * To get information on used free variables (both lazy and strict!)+ (see Note [Lazy and unleasheable free variables])+ * To ensure that all expressions have been traversed at least once, and any left-over+ strictness annotations have been updated.++This final iteration does not add the variables to the strictness signature+environment, which effectively assigns them 'nopSig' (see "getStrictness")++-}++-- Trivial RHS+-- See Note [Demand analysis for trivial right-hand sides]+dmdAnalTrivialRhs ::+ AnalEnv -> Id -> CoreExpr -> Var ->+ (DmdEnv, Id, CoreExpr)+dmdAnalTrivialRhs env id rhs fn+ = (fn_fv, set_idStrictness env id fn_str, rhs)+ where+ fn_str = getStrictness env fn+ fn_fv | isLocalId fn = unitVarEnv fn topDmd+ | otherwise = emptyDmdEnv+ -- Note [Remember to demand the function itself]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- fn_fv: don't forget to produce a demand for fn itself+ -- Lacking this caused Trac #9128+ -- The demand is very conservative (topDmd), but that doesn't+ -- matter; trivial bindings are usually inlined, so it only+ -- kicks in for top-level bindings and NOINLINE bindings++-- Let bindings can be processed in two ways:+-- Down (RHS before body) or Up (body before RHS).+-- dmdAnalRhsLetDown implements the Down variant:+-- * assuming a demand of <L,U>+-- * looking at the definition+-- * determining a strictness signature+--+-- It is used for toplevel definition, recursive definitions and local+-- non-recursive definitions that have manifest lambdas.+-- Local non-recursive definitions without a lambda are handled with LetUp.+--+-- This is the LetDown rule in the paper “Higher-Order Cardinality Analysis”.+dmdAnalRhsLetDown :: TopLevelFlag+ -> Maybe [Id] -- Just bs <=> recursive, Nothing <=> non-recursive+ -> AnalEnv -> Id -> CoreExpr+ -> (DmdEnv, Id, CoreExpr)+-- Process the RHS of the binding, add the strictness signature+-- to the Id, and augment the environment with the signature as well.+dmdAnalRhsLetDown top_lvl rec_flag env id rhs+ | Just fn <- unpackTrivial rhs -- See Note [Demand analysis for trivial right-hand sides]+ = dmdAnalTrivialRhs env id rhs fn++ | otherwise+ = (lazy_fv, id', mkLams bndrs' body')+ where+ (bndrs, body) = collectBinders rhs+ env_body = foldl extendSigsWithLam env bndrs+ (body_ty, body') = dmdAnal env_body body_dmd body+ body_ty' = removeDmdTyArgs body_ty -- zap possible deep CPR info+ (DmdType rhs_fv rhs_dmds rhs_res, bndrs')+ = annotateLamBndrs env (isDFunId id) body_ty' bndrs+ sig_ty = mkStrictSig (mkDmdType sig_fv rhs_dmds rhs_res')+ id' = set_idStrictness env id sig_ty+ -- See Note [NOINLINE and strictness]++ -- See Note [Product demands for function body]+ body_dmd = case deepSplitProductType_maybe (ae_fam_envs env) (exprType body) of+ Nothing -> cleanEvalDmd+ Just (dc, _, _, _) -> cleanEvalProdDmd (dataConRepArity dc)++ -- See Note [Aggregated demand for cardinality]+ rhs_fv1 = case rec_flag of+ Just bs -> reuseEnv (delVarEnvList rhs_fv bs)+ Nothing -> rhs_fv++ -- See Note [Lazy and unleashable free variables]+ (lazy_fv, sig_fv) = splitFVs is_thunk rhs_fv1++ rhs_res' = trimCPRInfo trim_all trim_sums rhs_res+ trim_all = is_thunk && not_strict+ trim_sums = not (isTopLevel top_lvl) -- See Note [CPR for sum types]++ -- See Note [CPR for thunks]+ is_thunk = not (exprIsHNF rhs) && not (isJoinId id)+ not_strict+ = isTopLevel top_lvl -- Top level and recursive things don't+ || isJust rec_flag -- get their demandInfo set at all+ || not (isStrictDmd (idDemandInfo id) || ae_virgin env)+ -- See Note [Optimistic CPR in the "virgin" case]++unpackTrivial :: CoreExpr -> Maybe Id+-- Returns (Just v) if the arg is really equal to v, modulo+-- casts, type applications etc+-- See Note [Demand analysis for trivial right-hand sides]+unpackTrivial (Var v) = Just v+unpackTrivial (Cast e _) = unpackTrivial e+unpackTrivial (Lam v e) | isTyVar v = unpackTrivial e+unpackTrivial (App e a) | isTypeArg a = unpackTrivial e+unpackTrivial _ = Nothing++-- | If given the RHS of a let-binding, this 'useLetUp' determines+-- whether we should process the binding up (body before rhs) or+-- down (rhs before body).+--+-- We use LetDown if there is a chance to get a useful strictness signature.+-- This is the case when there are manifest value lambdas or the binding is a+-- join point (hence always acts like a function, not a value).+useLetUp :: Var -> CoreExpr -> Bool+useLetUp f _ | isJoinId f = False+useLetUp f (Lam v e) | isTyVar v = useLetUp f e+useLetUp _ (Lam _ _) = False+useLetUp _ _ = True+++{-+Note [Demand analysis for trivial right-hand sides]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ foo = plusInt |> co+where plusInt is an arity-2 function with known strictness. Clearly+we want plusInt's strictness to propagate to foo! But because it has+no manifest lambdas, it won't do so automatically, and indeed 'co' might+have type (Int->Int->Int) ~ T, so we *can't* eta-expand. So we have a+special case for right-hand sides that are "trivial", namely variables,+casts, type applications, and the like.++Note that this can mean that 'foo' has an arity that is smaller than that+indicated by its demand info. e.g. if co :: (Int->Int->Int) ~ T, then+foo's arity will be zero (see Note [exprArity invariant] in CoreArity),+but its demand signature will be that of plusInt. A small example is the+test case of Trac #8963.+++Note [Product demands for function body]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This example comes from 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.++So for the demand on the body of a RHS we use a product demand if it's+a product type.++************************************************************************+* *+\subsection{Strictness signatures and types}+* *+************************************************************************+-}++unitDmdType :: DmdEnv -> DmdType+unitDmdType dmd_env = DmdType dmd_env [] topRes++coercionDmdEnv :: Coercion -> DmdEnv+coercionDmdEnv co = mapVarEnv (const topDmd) (getUniqSet $ coVarsOfCo co)+ -- The VarSet from coVarsOfCo is really a VarEnv Var++addVarDmd :: DmdType -> Var -> Demand -> DmdType+addVarDmd (DmdType fv ds res) var dmd+ = DmdType (extendVarEnv_C bothDmd fv var dmd) ds res++addLazyFVs :: DmdType -> DmdEnv -> DmdType+addLazyFVs dmd_ty lazy_fvs+ = dmd_ty `bothDmdType` mkBothDmdArg lazy_fvs+ -- Using bothDmdType (rather than just both'ing the envs)+ -- is vital. Consider+ -- let f = \x -> (x,y)+ -- in error (f 3)+ -- Here, y is treated as a lazy-fv of f, but we must `bothDmd` that L+ -- demand with the bottom coming up from 'error'+ --+ -- I got a loop in the fixpointer without this, due to an interaction+ -- with the lazy_fv filtering in dmdAnalRhsLetDown. Roughly, it was+ -- letrec f n x+ -- = letrec g y = x `fatbar`+ -- letrec h z = z + ...g...+ -- in h (f (n-1) x)+ -- in ...+ -- In the initial iteration for f, f=Bot+ -- Suppose h is found to be strict in z, but the occurrence of g in its RHS+ -- is lazy. Now consider the fixpoint iteration for g, esp the demands it+ -- places on its free variables. Suppose it places none. Then the+ -- x `fatbar` ...call to h...+ -- will give a x->V demand for x. That turns into a L demand for x,+ -- which floats out of the defn for h. Without the modifyEnv, that+ -- L demand doesn't get both'd with the Bot coming up from the inner+ -- call to f. So we just get an L demand for x for g.++{-+Note [Do not strictify the argument dictionaries of a dfun]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The typechecker can tie recursive knots involving dfuns, so we do the+conservative thing and refrain from strictifying a dfun's argument+dictionaries.+-}++setBndrsDemandInfo :: [Var] -> [Demand] -> [Var]+setBndrsDemandInfo (b:bs) (d:ds)+ | isTyVar b = b : setBndrsDemandInfo bs (d:ds)+ | otherwise = setIdDemandInfo b d : setBndrsDemandInfo bs ds+setBndrsDemandInfo [] ds = ASSERT( null ds ) []+setBndrsDemandInfo bs _ = pprPanic "setBndrsDemandInfo" (ppr bs)++annotateBndr :: AnalEnv -> DmdType -> Var -> (DmdType, 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 = (dmd_ty', setIdDemandInfo var dmd)+ | otherwise = (dmd_ty, var)+ where+ (dmd_ty', dmd) = findBndrDmd env False dmd_ty var++annotateLamBndrs :: AnalEnv -> DFunFlag -> DmdType -> [Var] -> (DmdType, [Var])+annotateLamBndrs env args_of_dfun ty bndrs = mapAccumR annotate ty bndrs+ where+ annotate dmd_ty bndr+ | isId bndr = annotateLamIdBndr env args_of_dfun dmd_ty bndr+ | otherwise = (dmd_ty, bndr)++annotateLamIdBndr :: AnalEnv+ -> DFunFlag -- is this lambda at the top of the RHS of a dfun?+ -> DmdType -- Demand type of body+ -> Id -- Lambda binder+ -> (DmdType, -- Demand type of lambda+ Id) -- and binder annotated with demand++annotateLamIdBndr env arg_of_dfun dmd_ty id+-- For lambdas we add the demand to the argument demands+-- Only called for Ids+ = ASSERT( isId id )+ -- pprTrace "annLamBndr" (vcat [ppr id, ppr _dmd_ty]) $+ (final_ty, setIdDemandInfo id dmd)+ where+ -- Watch out! See note [Lambda-bound unfoldings]+ final_ty = case maybeUnfoldingTemplate (idUnfolding id) of+ Nothing -> main_ty+ Just unf -> main_ty `bothDmdType` unf_ty+ where+ (unf_ty, _) = dmdAnalStar env dmd unf++ main_ty = addDemand dmd dmd_ty'+ (dmd_ty', dmd) = findBndrDmd env arg_of_dfun dmd_ty id++deleteFVs :: DmdType -> [Var] -> DmdType+deleteFVs (DmdType fvs dmds res) bndrs+ = DmdType (delVarEnvList fvs bndrs) dmds res++{-+Note [CPR for sum types]+~~~~~~~~~~~~~~~~~~~~~~~~+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]+~~~~~~~~~~~~~~~~~~~~~+If the rhs is a thunk, we usually forget the CPR info, because+it is presumably shared (else it would have been inlined, and+so we'd lose sharing if w/w'd it into a function). E.g.++ let r = case expensive of+ (a,b) -> (b,a)+ in ...++If we marked r as having the CPR property, then we'd w/w into++ let $wr = \() -> case expensive of+ (a,b) -> (# b, a #)+ r = case $wr () of+ (# b,a #) -> (b,a)+ in ...++But now r is a thunk, which won't be inlined, so we are no further ahead.+But consider++ f x = let r = case expensive of (a,b) -> (b,a)+ in if foo r then r else (x,x)++Does f have the CPR property? Well, no.++However, if the strictness analyser has figured out (in a previous+iteration) that it's strict, then we DON'T need to forget the CPR info.+Instead we can retain the CPR info and do the thunk-splitting transform+(see WorkWrap.splitThunk).++This made a big difference to PrelBase.modInt, which had something like+ modInt = \ x -> let r = ... -> I# v in+ ...body strict in r...+r's RHS isn't a value yet; but modInt returns r in various branches, so+if r doesn't have the CPR property then neither does modInt+Another case I found in practice (in Complex.magnitude), looks like this:+ let k = if ... then I# a else I# b+ in ... body strict in k ....+(For this example, it doesn't matter whether k is returned as part of+the overall result; but it does matter that k's RHS has the CPR property.)+Left to itself, the simplifier will make a join point thus:+ let $j k = ...body strict in k...+ if ... then $j (I# a) else $j (I# b)+With thunk-splitting, we get instead+ let $j x = let k = I#x in ...body strict in k...+ in if ... then $j a else $j b+This is much better; there's a good chance the I# won't get allocated.++The difficulty with this is that we need the strictness type to+look at the body... but we now need the body to calculate the demand+on the variable, so we can decide whether its strictness type should+have a CPR in it or not. Simple solution:+ a) use strictness info from the previous iteration+ b) make sure we do at least 2 iterations, by doing a second+ round for top-level non-recs. Top level recs will get at+ least 2 iterations except for totally-bottom functions+ which aren't very interesting anyway.++NB: strictly_demanded is never true of a top-level Id, or of a recursive Id.++Note [Optimistic CPR in the "virgin" case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Demand and strictness info are initialized by top elements. However,+this prevents from inferring a CPR property in the first pass of the+analyser, so we keep an explicit flag ae_virgin in the AnalEnv+datatype.++We can't start with 'not-demanded' (i.e., top) because then consider+ f x = let+ t = ... I# x+ in+ if ... then t else I# y else f x'++In the first iteration we'd have no demand info for x, so assume+not-demanded; then we'd get TopRes for f's CPR info. Next iteration+we'd see that t was demanded, and so give it the CPR property, but by+now f has TopRes, so it will stay TopRes. Instead, by checking the+ae_virgin flag at the first time round, we say 'yes t is demanded' the+first time.++However, this does mean that for non-recursive bindings we must+iterate twice to be sure of not getting over-optimistic CPR info,+in the case where t turns out to be not-demanded. This is handled+by dmdAnalTopBind.+++Note [NOINLINE and strictness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The strictness analyser used to have a HACK which ensured that NOINLNE+things were not strictness-analysed. The reason was unsafePerformIO.+Left to itself, the strictness analyser would discover this strictness+for unsafePerformIO:+ unsafePerformIO: C(U(AV))+But then consider this sub-expression+ unsafePerformIO (\s -> let r = f x in+ case writeIORef v r s of (# s1, _ #) ->+ (# s1, r #)+The strictness analyser will now find that r is sure to be eval'd,+and may then hoist it out. This makes tests/lib/should_run/memo002+deadlock.++Solving this by making all NOINLINE things have no strictness info is overkill.+In particular, it's overkill for runST, which is perfectly respectable.+Consider+ f x = runST (return x)+This should be strict in x.++So the new plan is to define unsafePerformIO using the 'lazy' combinator:++ unsafePerformIO (IO m) = lazy (case m realWorld# of (# _, r #) -> r)++Remember, 'lazy' is a wired-in identity-function Id, of type a->a, which is+magically NON-STRICT, and is inlined after strictness analysis. So+unsafePerformIO will look non-strict, and that's what we want.++Now we don't need the hack in the strictness analyser. HOWEVER, this+decision does mean that even a NOINLINE function is not entirely+opaque: some aspect of its implementation leaks out, notably its+strictness. For example, if you have a function implemented by an+error stub, but which has RULES, you may want it not to be eliminated+in favour of error!++Note [Lazy and unleasheable free variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We put the strict and once-used FVs in the DmdType of the Id, so+that at its call sites we unleash demands on its strict fvs.+An example is 'roll' in imaginary/wheel-sieve2+Something like this:+ roll x = letrec+ go y = if ... then roll (x-1) else x+1+ in+ go ms+We want to see that roll is strict in x, which is because+go is called. So we put the DmdEnv for x in go's DmdType.++Another example:++ f :: Int -> Int -> Int+ f x y = let t = x+1+ h z = if z==0 then t else+ if z==1 then x+1 else+ x + h (z-1)+ in h y++Calling h does indeed evaluate x, but we can only see+that if we unleash a demand on x at the call site for t.++Incidentally, here's a place where lambda-lifting h would+lose the cigar --- we couldn't see the joint strictness in t/x++ ON THE OTHER HAND++We don't want to put *all* the fv's from the RHS into the+DmdType. Because++ * it makes the strictness signatures larger, and hence slows down fixpointing++and++ * it is useless information at the call site anyways:+ For lazy, used-many times fv's we will never get any better result than+ that, no matter how good the actual demand on the function at the call site+ is (unless it is always absent, but then the whole binder is useless).++Therefore we exclude lazy multiple-used fv's from the environment in the+DmdType.++But now the signature lies! (Missing variables are assumed to be absent.) To+make up for this, the code that analyses the binding keeps the demand on those+variable separate (usually called "lazy_fv") and adds it to the demand of the+whole binding later.++What if we decide _not_ to store a strictness signature for a binding at all, as+we do when aborting a fixed-point iteration? The we risk losing the information+that the strict variables are being used. In that case, we take all free variables+mentioned in the (unsound) strictness signature, conservatively approximate the+demand put on them (topDmd), and add that to the "lazy_fv" returned by "dmdFix".+++Note [Lambda-bound unfoldings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We allow a lambda-bound variable to carry an unfolding, a facility that is used+exclusively for join points; see Note [Case binders and join points]. If so,+we must be careful to demand-analyse the RHS of the unfolding! Example+ \x. \y{=Just x}. <body>+Then if <body> uses 'y', then transitively it uses 'x', and we must not+forget that fact, otherwise we might make 'x' absent when it isn't.+++************************************************************************+* *+\subsection{Strictness signatures}+* *+************************************************************************+-}++type DFunFlag = Bool -- indicates if the lambda being considered is in the+ -- sequence of lambdas at the top of the RHS of a dfun+notArgOfDfun :: DFunFlag+notArgOfDfun = False++data AnalEnv+ = AE { ae_dflags :: DynFlags+ , ae_sigs :: SigEnv+ , ae_virgin :: Bool -- True on first iteration only+ -- See Note [Initialising strictness]+ , ae_rec_tc :: RecTcChecker+ , ae_fam_envs :: FamInstEnvs+ }++ -- We use the se_env to tell us whether to+ -- record info about a variable in the DmdEnv+ -- We do so if it's a LocalId, but not top-level+ --+ -- The DmdEnv gives the demand on the free vars of the function+ -- when it is given enough args to satisfy the strictness signature++type SigEnv = VarEnv (StrictSig, TopLevelFlag)++instance Outputable AnalEnv where+ ppr (AE { ae_sigs = env, ae_virgin = virgin })+ = text "AE" <+> braces (vcat+ [ text "ae_virgin =" <+> ppr virgin+ , text "ae_sigs =" <+> ppr env ])++emptyAnalEnv :: DynFlags -> FamInstEnvs -> AnalEnv+emptyAnalEnv dflags fam_envs+ = AE { ae_dflags = dflags+ , ae_sigs = emptySigEnv+ , ae_virgin = True+ , ae_rec_tc = initRecTc+ , ae_fam_envs = fam_envs+ }++emptySigEnv :: SigEnv+emptySigEnv = emptyVarEnv++-- | Extend an environment with the strictness IDs attached to the id+extendAnalEnvs :: TopLevelFlag -> AnalEnv -> [Id] -> AnalEnv+extendAnalEnvs top_lvl env vars+ = env { ae_sigs = extendSigEnvs top_lvl (ae_sigs env) vars }++extendSigEnvs :: TopLevelFlag -> SigEnv -> [Id] -> SigEnv+extendSigEnvs top_lvl sigs vars+ = extendVarEnvList sigs [ (var, (idStrictness var, top_lvl)) | var <- vars]++extendAnalEnv :: TopLevelFlag -> AnalEnv -> Id -> StrictSig -> AnalEnv+extendAnalEnv top_lvl env var sig+ = env { ae_sigs = extendSigEnv top_lvl (ae_sigs env) var sig }++extendSigEnv :: TopLevelFlag -> SigEnv -> Id -> StrictSig -> SigEnv+extendSigEnv top_lvl sigs var sig = extendVarEnv sigs var (sig, top_lvl)++lookupSigEnv :: AnalEnv -> Id -> Maybe (StrictSig, TopLevelFlag)+lookupSigEnv env id = lookupVarEnv (ae_sigs env) id++getStrictness :: AnalEnv -> Id -> StrictSig+getStrictness env fn+ | isGlobalId fn = idStrictness fn+ | Just (sig, _) <- lookupSigEnv env fn = sig+ | otherwise = nopSig++nonVirgin :: AnalEnv -> AnalEnv+nonVirgin env = env { ae_virgin = False }++extendSigsWithLam :: AnalEnv -> Id -> AnalEnv+-- Extend the AnalEnv when we meet a lambda binder+extendSigsWithLam env id+ | isId id+ , isStrictDmd (idDemandInfo id) || ae_virgin env+ -- See Note [Optimistic CPR in the "virgin" case]+ -- See Note [Initial CPR for strict binders]+ , Just (dc,_,_,_) <- deepSplitProductType_maybe (ae_fam_envs env) $ idType id+ = extendAnalEnv NotTopLevel env id (cprProdSig (dataConRepArity dc))++ | otherwise+ = env++extendEnvForProdAlt :: AnalEnv -> CoreExpr -> Id -> DataCon -> [Var] -> AnalEnv+-- See Note [CPR in a product case alternative]+extendEnvForProdAlt env scrut case_bndr dc bndrs+ = foldl do_con_arg env1 ids_w_strs+ where+ env1 = extendAnalEnv NotTopLevel env case_bndr case_bndr_sig++ ids_w_strs = filter isId bndrs `zip` dataConRepStrictness dc+ case_bndr_sig = cprProdSig (dataConRepArity dc)+ fam_envs = ae_fam_envs env++ do_con_arg env (id, str)+ | let is_strict = isStrictDmd (idDemandInfo id) || isMarkedStrict str+ , ae_virgin env || (is_var_scrut && is_strict) -- See Note [CPR in a product case alternative]+ , Just (dc,_,_,_) <- deepSplitProductType_maybe fam_envs $ idType id+ = extendAnalEnv NotTopLevel env id (cprProdSig (dataConRepArity dc))+ | otherwise+ = env++ is_var_scrut = is_var scrut+ is_var (Cast e _) = is_var e+ is_var (Var v) = isLocalId v+ is_var _ = False++addDataConStrictness :: DataCon -> [Demand] -> [Demand]+-- See Note [Add demands for strict constructors]+addDataConStrictness con ds+ = ASSERT2( equalLength strs ds, ppr con $$ ppr strs $$ ppr ds )+ zipWith add ds strs+ where+ strs = dataConRepStrictness con+ add dmd str | isMarkedStrict str+ , not (isAbsDmd dmd) = dmd `bothDmd` seqDmd+ | otherwise = dmd++findBndrsDmds :: AnalEnv -> DmdType -> [Var] -> (DmdType, [Demand])+-- Return the demands on the Ids in the [Var]+findBndrsDmds env dmd_ty bndrs+ = go dmd_ty bndrs+ where+ go dmd_ty [] = (dmd_ty, [])+ go dmd_ty (b:bs)+ | isId b = let (dmd_ty1, dmds) = go dmd_ty bs+ (dmd_ty2, dmd) = findBndrDmd env False dmd_ty1 b+ in (dmd_ty2, dmd : dmds)+ | otherwise = go dmd_ty bs++findBndrDmd :: AnalEnv -> Bool -> DmdType -> Id -> (DmdType, Demand)+-- See Note [Trimming a demand to a type] in Demand.hs+findBndrDmd env arg_of_dfun dmd_ty id+ = (dmd_ty', dmd')+ where+ dmd' = killUsageDemand (ae_dflags env) $+ strictify $+ trimToType starting_dmd (findTypeShape fam_envs id_ty)++ (dmd_ty', starting_dmd) = peelFV dmd_ty id++ id_ty = idType id++ strictify dmd+ | gopt Opt_DictsStrict (ae_dflags env)+ -- We never want to strictify a recursive let. At the moment+ -- annotateBndr is only call for non-recursive lets; if that+ -- changes, we need a RecFlag parameter and another guard here.+ , not arg_of_dfun -- See Note [Do not strictify the argument dictionaries of a dfun]+ = strictifyDictDmd id_ty dmd+ | otherwise+ = dmd++ fam_envs = ae_fam_envs env++set_idStrictness :: AnalEnv -> Id -> StrictSig -> Id+set_idStrictness env id sig+ = setIdStrictness id (killUsageSig (ae_dflags env) sig)++dumpStrSig :: CoreProgram -> SDoc+dumpStrSig binds = vcat (map printId ids)+ where+ ids = sortBy (stableNameCmp `on` getName) (concatMap getIds binds)+ getIds (NonRec i _) = [ i ]+ getIds (Rec bs) = map fst bs+ printId id | isExportedId id = ppr id <> colon <+> pprIfaceStrictSig (idStrictness id)+ | otherwise = empty++{- Note [CPR in a product case alternative]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a case alternative for a product type, we want to give some of the+binders the CPR property. Specifically++ * The case binder; inside the alternative, the case binder always has+ the CPR property, meaning that a case on it will successfully cancel.+ Example:+ f True x = case x of y { I# x' -> if x' ==# 3+ then y+ else I# 8 }+ f False x = I# 3++ By giving 'y' the CPR property, we ensure that 'f' does too, so we get+ f b x = case fw b x of { r -> I# r }+ fw True x = case x of y { I# x' -> if x' ==# 3 then x' else 8 }+ fw False x = 3++ Of course there is the usual risk of re-boxing: we have 'x' available+ boxed and unboxed, but we return the unboxed version for the wrapper to+ box. If the wrapper doesn't cancel with its caller, we'll end up+ re-boxing something that we did have available in boxed form.++ * Any strict binders with product type, can use+ Note [Initial CPR for strict binders]. But we can go a little+ further. Consider++ data T = MkT !Int Int++ f2 (MkT x y) | y>0 = f2 (MkT x (y-1))+ | otherwise = x++ For $wf2 we are going to unbox the MkT *and*, since it is strict, the+ first argument of the MkT; see Note [Add demands for strict constructors].+ But then we don't want box it up again when returning it! We want+ 'f2' to have the CPR property, so we give 'x' the CPR property.++ * It's a bit delicate because if this case is scrutinising something other+ than an argument the original function, we really don't have the unboxed+ version available. E.g+ g v = case foo v of+ MkT x y | y>0 -> ...+ | otherwise -> x+ Here we don't have the unboxed 'x' available. Hence the+ is_var_scrut test when making use of the strictness annotation.+ Slightly ad-hoc, because even if the scrutinee *is* a variable it+ might not be a onre of the arguments to the original function, or a+ sub-component thereof. But it's simple, and nothing terrible+ happens if we get it wrong. e.g. Trac #10694.++Note [Add demands for strict constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this program (due to Roman):++ data X a = X !a++ foo :: X Int -> Int -> Int+ foo (X a) n = go 0+ where+ go i | i < n = a + go (i+1)+ | otherwise = 0++We want the worker for 'foo' too look like this:++ $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:++ foo (X a) n = a `seq` go 0++because the seq is discarded (very early) since X is strict!++We achieve the effect using addDataConStrictness. It is called at a+case expression, such as the pattern match on (X a) in the example+above. After computing how 'a' is used in the alternatives, we add an+extra 'seqDmd' to it. The case alternative isn't itself strict in the+sub-components, but simply evaluating the scrutinee to HNF does force+those sub-components.++If the argument is not used at all in the alternative (i.e. it is+Absent), then *don't* add a 'seqDmd'. If we do, it makes it look used+and hence it'll be passed to the worker when it doesn't need to be.+Hence the isAbsDmd test in addDataConStrictness.++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!+++Note [Initial CPR for strict binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+CPR is initialized for a lambda binder in an optimistic manner, i.e,+if the binder is used strictly and at least some of its components as+a product are used, which is checked by the value of the absence+demand.++If the binder is marked demanded with a strict demand, then give it a+CPR signature. Here's a concrete example ('f1' in test T10482a),+assuming h is strict:++ f1 :: Int -> Int+ f1 x = case h x of+ A -> x+ B -> f1 (x-1)+ C -> x+1++If we notice that 'x' is used strictly, we can give it the CPR+property; and hence f1 gets the CPR property too. It's sound (doesn't+change strictness) to give it the CPR property because by the time 'x'+is returned (case A above), it'll have been evaluated (by the wrapper+of 'h' in the example).++Moreover, if f itself is strict in x, then we'll pass x unboxed to+f1, and so the boxed version *won't* be available; in that case it's+very helpful to give 'x' the CPR property.++Note that++ * We only want to do this for something that definitely+ has product type, else we may get over-optimistic CPR results+ (e.g. from \x -> x!).++ * See Note [CPR examples]++Note [CPR examples]+~~~~~~~~~~~~~~~~~~~~+Here are some examples (stranal/should_compile/T10482a) of the+usefulness of Note [CPR in a product case alternative]. The main+point: all of these functions can have the CPR property.++ ------- f1 -----------+ -- x is used strictly by h, so it'll be available+ -- unboxed before it is returned in the True branch++ f1 :: Int -> Int+ f1 x = case h x x of+ True -> x+ False -> f1 (x-1)+++ ------- f2 -----------+ -- x is a strict field of MkT2, so we'll pass it unboxed+ -- to $wf2, so it's available unboxed. This depends on+ -- the case expression analysing (a subcomponent of) one+ -- of the original arguments to the function, so it's+ -- a bit more delicate.++ data T2 = MkT2 !Int Int++ f2 :: T2 -> Int+ f2 (MkT2 x y) | y>0 = f2 (MkT2 x (y-1))+ | otherwise = x+++ ------- f3 -----------+ -- h is strict in x, so x will be unboxed before it+ -- is rerturned in the otherwise case.++ data T3 = MkT3 Int Int++ f1 :: T3 -> Int+ f1 (MkT3 x y) | h x y = f3 (MkT3 x (y-1))+ | otherwise = x+++ ------- f4 -----------+ -- Just like f2, but MkT4 can't unbox its strict+ -- argument automatically, as f2 can++ data family Foo a+ newtype instance Foo Int = Foo Int++ data T4 a = MkT4 !(Foo a) Int++ f4 :: T4 Int -> Int+ f4 (MkT4 x@(Foo v) y) | y>0 = f4 (MkT4 x (y-1))+ | otherwise = v+++Note [Initialising strictness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See section 9.2 (Finding fixpoints) of the paper.++Our basic plan is to initialise the strictness of each Id in a+recursive group to "bottom", and find a fixpoint from there. However,+this group B might be inside an *enclosing* recursive group A, in+which case we'll do the entire fixpoint shebang on for each iteration+of A. This can be illustrated by the following example:++Example:++ f [] = []+ f (x:xs) = let g [] = f xs+ g (y:ys) = y+1 : g ys+ in g (h x)++At each iteration of the fixpoint for f, the analyser has to find a+fixpoint for the enclosed function g. In the meantime, the demand+values for g at each iteration for f are *greater* than those we+encountered in the previous iteration for f. Therefore, we can begin+the fixpoint for g not with the bottom value but rather with the+result of the previous analysis. I.e., when beginning the fixpoint+process for g, we can start from the demand signature computed for g+previously and attached to the binding occurrence of g.++To speed things up, we initialise each iteration of A (the enclosing+one) from the result of the last one, which is neatly recorded in each+binder. That way we make use of earlier iterations of the fixpoint+algorithm. (Cunning plan.)++But on the *first* iteration we want to *ignore* the current strictness+of the Id, and start from "bottom". Nowadays the Id can have a current+strictness, because interface files record strictness for nested bindings.+To know when we are in the first iteration, we look at the ae_virgin+field of the AnalEnv.+++Note [Final Demand Analyser run]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Some of the information that the demand analyser determines is not always+preserved by the simplifier. For example, the simplifier will happily rewrite+ \y [Demand=1*U] let x = y in x + x+to+ \y [Demand=1*U] y + y+which is quite a lie.++The once-used information is (currently) only used by the code+generator, though. So:++ * We zap the used-once info in the worker-wrapper;+ see Note [Zapping Used Once info in WorkWrap] in WorkWrap. If it's+ not reliable, it's better not to have it at all.++ * Just before TidyCore, we add a pass of the demand analyser,+ but WITHOUT subsequent worker/wrapper and simplifier,+ right before TidyCore. See SimplCore.getCoreToDo.++ This way, correct information finds its way into the module interface+ (strictness signatures!) and the code generator (single-entry thunks!)++Note that, in contrast, the single-call information (C1(..)) /can/ be+relied upon, as the simplifier tends to be very careful about not+duplicating actual function calls.++Also see #11731.+-}
+ stranal/WorkWrap.hs view
@@ -0,0 +1,661 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[WorkWrap]{Worker/wrapper-generating back-end of strictness analyser}+-}++{-# LANGUAGE CPP #-}+module WorkWrap ( wwTopBinds ) where++import CoreSyn+import CoreUnfold ( certainlyWillInline, mkWwInlineRule, mkWorkerUnfolding )+import CoreUtils ( exprType, exprIsHNF )+import CoreFVs ( exprFreeVars )+import Var+import Id+import IdInfo+import Type+import UniqSupply+import BasicTypes+import DynFlags+import Demand+import WwLib+import Util+import Outputable+import FamInstEnv+import MonadUtils++#include "HsVersions.h"++{-+We take Core bindings whose binders have:++\begin{enumerate}++\item Strictness attached (by the front-end of the strictness+analyser), and / or++\item Constructed Product Result information attached by the CPR+analysis pass.++\end{enumerate}++and we return some ``plain'' bindings which have been+worker/wrapper-ified, meaning:++\begin{enumerate}++\item Functions have been split into workers and wrappers where+appropriate. If a function has both strictness and CPR properties+then only one worker/wrapper doing both transformations is produced;++\item Binders' @IdInfos@ have been updated to reflect the existence of+these workers/wrappers (this is where we get STRICTNESS and CPR pragma+info for exported values).+\end{enumerate}+-}++wwTopBinds :: DynFlags -> FamInstEnvs -> UniqSupply -> CoreProgram -> CoreProgram++wwTopBinds dflags fam_envs us top_binds+ = initUs_ us $ do+ top_binds' <- mapM (wwBind dflags fam_envs) top_binds+ return (concat top_binds')++{-+************************************************************************+* *+\subsection[wwBind-wwExpr]{@wwBind@ and @wwExpr@}+* *+************************************************************************++@wwBind@ works on a binding, trying each \tr{(binder, expr)} pair in+turn. Non-recursive case first, then recursive...+-}++wwBind :: DynFlags+ -> FamInstEnvs+ -> CoreBind+ -> UniqSM [CoreBind] -- returns a WwBinding intermediate form;+ -- the caller will convert to Expr/Binding,+ -- as appropriate.++wwBind dflags fam_envs (NonRec binder rhs) = do+ new_rhs <- wwExpr dflags fam_envs rhs+ new_pairs <- tryWW dflags fam_envs NonRecursive binder new_rhs+ return [NonRec b e | (b,e) <- new_pairs]+ -- Generated bindings must be non-recursive+ -- because the original binding was.++wwBind dflags fam_envs (Rec pairs)+ = return . Rec <$> concatMapM do_one pairs+ where+ do_one (binder, rhs) = do new_rhs <- wwExpr dflags fam_envs rhs+ tryWW dflags fam_envs Recursive binder new_rhs++{-+@wwExpr@ basically just walks the tree, looking for appropriate+annotations that can be used. Remember it is @wwBind@ that does the+matching by looking for strict arguments of the correct type.+@wwExpr@ is a version that just returns the ``Plain'' Tree.+-}++wwExpr :: DynFlags -> FamInstEnvs -> CoreExpr -> UniqSM CoreExpr++wwExpr _ _ e@(Type {}) = return e+wwExpr _ _ e@(Coercion {}) = return e+wwExpr _ _ e@(Lit {}) = return e+wwExpr _ _ e@(Var {}) = return e++wwExpr dflags fam_envs (Lam binder expr)+ = Lam new_binder <$> wwExpr dflags fam_envs expr+ where new_binder | isId binder = zapIdUsedOnceInfo binder+ | otherwise = binder+ -- See Note [Zapping Used Once info in WorkWrap]++wwExpr dflags fam_envs (App f a)+ = App <$> wwExpr dflags fam_envs f <*> wwExpr dflags fam_envs a++wwExpr dflags fam_envs (Tick note expr)+ = Tick note <$> wwExpr dflags fam_envs expr++wwExpr dflags fam_envs (Cast expr co) = do+ new_expr <- wwExpr dflags fam_envs expr+ return (Cast new_expr co)++wwExpr dflags fam_envs (Let bind expr)+ = mkLets <$> wwBind dflags fam_envs bind <*> wwExpr dflags fam_envs expr++wwExpr dflags fam_envs (Case expr binder ty alts) = do+ new_expr <- wwExpr dflags fam_envs expr+ new_alts <- mapM ww_alt alts+ let new_binder = zapIdUsedOnceInfo binder+ -- See Note [Zapping Used Once info in WorkWrap]+ return (Case new_expr new_binder ty new_alts)+ where+ ww_alt (con, binders, rhs) = do+ new_rhs <- wwExpr dflags fam_envs rhs+ let new_binders = [ if isId b then zapIdUsedOnceInfo b else b+ | b <- binders ]+ -- See Note [Zapping Used Once info in WorkWrap]+ return (con, new_binders, new_rhs)++{-+************************************************************************+* *+\subsection[tryWW]{@tryWW@: attempt a worker/wrapper pair}+* *+************************************************************************++@tryWW@ just accumulates arguments, converts strictness info from the+front-end into the proper form, then calls @mkWwBodies@ to do+the business.++The only reason this is monadised is for the unique supply.++Note [Don't w/w INLINE things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's very important to refrain from w/w-ing an INLINE function (ie one+with a stable unfolding) because the wrapper will then overwrite the+old stable unfolding with the wrapper code.++Furthermore, if the programmer has marked something as INLINE,+we may lose by w/w'ing it.++If the strictness analyser is run twice, this test also prevents+wrappers (which are INLINEd) from being re-done. (You can end up with+several liked-named Ids bouncing around at the same time---absolute+mischief.)++Notice that we refrain from w/w'ing an INLINE function even if it is+in a recursive group. It might not be the loop breaker. (We could+test for loop-breaker-hood, but I'm not sure that ever matters.)++Note [Worker-wrapper for INLINABLE functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have+ {-# INLINABLE f #-}+ f :: Ord a => [a] -> Int -> a+ f x y = ....f....++where f is strict in y, we might get a more efficient loop by w/w'ing+f. But that would make a new unfolding which would overwrite the old+one! So the function would no longer be ININABLE, and in particular+will not be specialised at call sites in other modules.++This comes in practice (Trac #6056).++Solution: do the w/w for strictness analysis, but transfer the Stable+unfolding to the *worker*. So we will get something like this:++ {-# INLINE[0] f #-}+ f :: Ord a => [a] -> Int -> a+ f d x y = case y of I# y' -> fw d x y'++ {-# INLINABLE[0] fw #-}+ fw :: Ord a => [a] -> Int# -> a+ fw d x y' = let y = I# y' in ...f...++How do we "transfer the unfolding"? Easy: by using the old one, wrapped+in work_fn! See CoreUnfold.mkWorkerUnfolding.++Note [Worker-wrapper for NOINLINE functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We used to disable worker/wrapper for NOINLINE things, but it turns out+this can cause unnecessary reboxing of values. Consider++ {-# NOINLINE f #-}+ f :: Int -> a+ f x = error (show x)++ g :: Bool -> Bool -> Int -> Int+ g True True p = f p+ g False True p = p + 1+ g b False p = g b True p++the strictness analysis will discover f and g are strict, but because f+has no wrapper, the worker for g will rebox p. So we get++ $wg x y p# =+ let p = I# p# in -- Yikes! Reboxing!+ case x of+ False ->+ case y of+ False -> $wg False True p#+ True -> +# p# 1#+ True ->+ case y of+ False -> $wg True True p#+ True -> case f p of { }++ g x y p = case p of (I# p#) -> $wg x y p#++Now, in this case the reboxing will float into the True branch, an so+the allocation will only happen on the error path. But it won't float+inwards if there are multiple branches that call (f p), so the reboxing+will happen on every call of g. Disaster.++Solution: do worker/wrapper even on NOINLINE things; but move the+NOINLINE pragma to the worker.++(See Trac #13143 for a real-world example.)++Note [Activation for workers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Follows on from Note [Worker-wrapper for INLINABLE functions]++It is *vital* that if the worker gets an INLINABLE pragma (from the+original function), then the worker has the same phase activation as+the wrapper (or later). That is necessary to allow the wrapper to+inline into the worker's unfolding: see SimplUtils+Note [Simplifying inside stable unfoldings].++If the original is NOINLINE, it's important that the work inherit the+original activation. Consider++ {-# NOINLINE expensive #-}+ expensive x = x + 1++ f y = let z = expensive y in ...++If expensive's worker inherits the wrapper's activation, we'll get++ {-# NOINLINE[0] $wexpensive #-}+ $wexpensive x = x + 1+ {-# INLINE[0] expensive #-}+ expensive x = $wexpensive x++ f y = let z = expensive y in ...++and $wexpensive will be immediately inlined into expensive, followed by+expensive into f. This effectively removes the original NOINLINE!++Otherwise, nothing is lost by giving the worker the same activation as the+wrapper, because the worker won't have any chance of inlining until the+wrapper does; there's no point in giving it an earlier activation.++Note [Don't w/w inline small non-loop-breaker things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general, we refrain from w/w-ing *small* functions, which are not+loop breakers, because they'll inline anyway. But we must take care:+it may look small now, but get to be big later after other inlining+has happened. So we take the precaution of adding an INLINE pragma to+any such functions.++I made this change when I observed a big function at the end of+compilation with a useful strictness signature but no w-w. (It was+small during demand analysis, we refrained from w/w, and then got big+when something was inlined in its rhs.) When I measured it on nofib,+it didn't make much difference; just a few percent improved allocation+on one benchmark (bspt/Euclid.space). But nothing got worse.++There is an infelicity though. We may get something like+ f = g val+==>+ g x = case gw x of r -> I# r++ f {- InlineStable, Template = g val -}+ f = case gw x of r -> I# r++The code for f duplicates that for g, without any real benefit. It+won't really be executed, because calls to f will go via the inlining.++Note [Don't CPR join points]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~++There's no point in doing CPR on a join point. If the whole function is getting+CPR'd, then the case expression around the worker function will get pushed into+the join point by the simplifier, which will have the same effect that CPR would+have - the result will be returned in an unboxed tuple.++ f z = let join j x y = (x+1, y+1)+ in case z of A -> j 1 2+ B -> j 2 3++ =>++ f z = case $wf z of (# a, b #) -> (a, b)+ $wf z = case (let join j x y = (x+1, y+1)+ in case z of A -> j 1 2+ B -> j 2 3) of (a, b) -> (# a, b #)++ =>++ f z = case $wf z of (# a, b #) -> (a, b)+ $wf z = let join j x y = (# x+1, y+1 #)+ in case z of A -> j 1 2+ B -> j 2 3++Doing CPR 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 body will make a tail+call:++ f z = let join j x y = x + y+ in ...++ =>++ f z = let join $wj x# y# = x# +# y#+ j x y = case x of I# x# ->+ case y of I# y# ->+ $wj x# y#+ in ...++Note [Wrapper activation]+~~~~~~~~~~~~~~~~~~~~~~~~~+When should the wrapper inlining be active? It must not be active+earlier than the current Activation of the Id (eg it might have a+NOINLINE pragma). But in fact strictness analysis happens fairly+late in the pipeline, and we want to prioritise specialisations over+strictness. Eg if we have+ module Foo where+ f :: Num a => a -> Int -> a+ f n 0 = n -- Strict in the Int, hence wrapper+ f n x = f (n+n) (x-1)++ g :: Int -> Int+ g x = f x x -- Provokes a specialisation for f++ module Bar where+ import Foo++ h :: Int -> Int+ h x = f 3 x++Then we want the specialisation for 'f' to kick in before the wrapper does.++Now in fact the 'gentle' simplification pass encourages this, by+having rules on, but inlinings off. But that's kind of lucky. It seems+more robust to give the wrapper an Activation of (ActiveAfter 0),+so that it becomes active in an importing module at the same time that+it appears in the first place in the defining module.++At one stage I tried making the wrapper inlining always-active, and+that had a very bad effect on nofib/imaginary/x2n1; a wrapper was+inlined before the specialisation fired.+-}++tryWW :: DynFlags+ -> FamInstEnvs+ -> RecFlag+ -> Id -- The fn binder+ -> CoreExpr -- The bound rhs; its innards+ -- are already ww'd+ -> UniqSM [(Id, CoreExpr)] -- either *one* or *two* pairs;+ -- if one, then no worker (only+ -- the orig "wrapper" lives on);+ -- if two, then a worker and a+ -- wrapper.+tryWW dflags fam_envs is_rec fn_id rhs+ -- See Note [Worker-wrapper for NOINLINE functions]++ | Just stable_unf <- certainlyWillInline dflags fn_info+ = return [ (fn_id `setIdUnfolding` stable_unf, rhs) ]+ -- See Note [Don't w/w INLINE things]+ -- See Note [Don't w/w inline small non-loop-breaker things]++ | is_fun+ = splitFun dflags fam_envs new_fn_id fn_info wrap_dmds res_info rhs++ | is_thunk -- See Note [Thunk splitting]+ = splitThunk dflags fam_envs is_rec new_fn_id rhs++ | otherwise+ = return [ (new_fn_id, rhs) ]++ where+ fn_info = idInfo fn_id+ (wrap_dmds, res_info) = splitStrictSig (strictnessInfo fn_info)++ new_fn_id = zapIdUsedOnceInfo (zapIdUsageEnvInfo fn_id)+ -- See Note [Zapping DmdEnv after Demand Analyzer] and+ -- See Note [Zapping Used Once info in WorkWrap]++ is_fun = notNull wrap_dmds || isJoinId fn_id+ is_thunk = not is_fun && not (exprIsHNF rhs) && not (isJoinId fn_id)+ && not (isUnliftedType (idType fn_id))++{-+Note [Zapping DmdEnv after Demand Analyzer]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the worker-wrapper pass we zap the DmdEnv. Why?+ (a) it is never used again+ (b) it wastes space+ (c) it becomes incorrect as things are cloned, because+ we don't push the substitution into it++Why here?+ * Because we don’t want to do it in the Demand Analyzer, as we never know+ there when we are doing the last pass.+ * We want them to be still there at the end of DmdAnal, so that+ -ddump-str-anal contains them.+ * We don’t want a second pass just for that.+ * WorkWrap looks at all bindings anyway.++We also need to do it in TidyCore.tidyLetBndr to clean up after the+final, worker/wrapper-less run of the demand analyser (see+Note [Final Demand Analyser run] in DmdAnal).++Note [Zapping Used Once info in WorkWrap]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the worker-wrapper pass we zap the used once info in demands and in+strictness signatures.++Why?+ * The simplifier may happen to transform code in a way that invalidates the+ data (see #11731 for an example).+ * It is not used in later passes, up to code generation.++So as the data is useless and possibly wrong, we want to remove it. The most+convenient place to do that is the worker wrapper phase, as it runs after every+run of the demand analyser besides the very last one (which is the one where we+want to _keep_ the info for the code generator).++We do not do it in the demand analyser for the same reasons outlined in+Note [Zapping DmdEnv after Demand Analyzer] above.+-}+++---------------------+splitFun :: DynFlags -> FamInstEnvs -> Id -> IdInfo -> [Demand] -> DmdResult -> CoreExpr+ -> UniqSM [(Id, CoreExpr)]+splitFun dflags fam_envs fn_id fn_info wrap_dmds res_info rhs+ = WARN( not (wrap_dmds `lengthIs` arity), ppr fn_id <+> (ppr arity $$ ppr wrap_dmds $$ ppr res_info) ) do+ -- The arity should match the signature+ stuff <- mkWwBodies dflags fam_envs rhs_fvs mb_join_arity fun_ty+ wrap_dmds use_res_info+ case stuff of+ Just (work_demands, join_arity, wrap_fn, work_fn) -> do+ work_uniq <- getUniqueM+ let work_rhs = work_fn rhs+ work_inline = inl_inline inl_prag+ work_act = case work_inline of+ -- See Note [Activation for workers]+ NoInline -> inl_act inl_prag+ _ -> wrap_act+ work_prag = InlinePragma { inl_src = SourceText "{-# INLINE"+ , inl_inline = work_inline+ , inl_sat = Nothing+ , inl_act = work_act+ , inl_rule = FunLike }+ -- idl_inline: copy from fn_id; see Note [Worker-wrapper for INLINABLE functions]+ -- idl_act: see Note [Activation for workers]+ -- inl_rule: it does not make sense for workers to be constructorlike.+ work_join_arity | isJoinId fn_id = Just join_arity+ | otherwise = Nothing+ -- worker is join point iff wrapper is join point+ -- (see Note [Don't CPR join points])+ work_id = mkWorkerId work_uniq fn_id (exprType work_rhs)+ `setIdOccInfo` occInfo fn_info+ -- Copy over occurrence info from parent+ -- Notably whether it's a loop breaker+ -- Doesn't matter much, since we will simplify next, but+ -- seems right-er to do so++ `setInlinePragma` work_prag++ `setIdUnfolding` mkWorkerUnfolding dflags work_fn (unfoldingInfo fn_info)+ -- See Note [Worker-wrapper for INLINABLE functions]++ `setIdStrictness` mkClosedStrictSig work_demands work_res_info+ -- Even though we may not be at top level,+ -- it's ok to give it an empty DmdEnv++ `setIdDemandInfo` worker_demand++ `setIdArity` work_arity+ -- Set the arity so that the Core Lint check that the+ -- arity is consistent with the demand type goes+ -- through+ `asJoinId_maybe` work_join_arity++ work_arity = length work_demands++ -- See Note [Demand on the Worker]+ single_call = saturatedByOneShots arity (demandInfo fn_info)+ worker_demand | single_call = mkWorkerDemand work_arity+ | otherwise = topDmd+++ wrap_act = ActiveAfter NoSourceText 0+ wrap_rhs = wrap_fn work_id+ wrap_prag = InlinePragma { inl_src = SourceText "{-# INLINE"+ , inl_inline = Inline+ , inl_sat = Nothing+ , inl_act = wrap_act+ , inl_rule = rule_match_info }+ -- See Note [Wrapper activation]+ -- The RuleMatchInfo is (and must be) unaffected++ wrap_id = fn_id `setIdUnfolding` mkWwInlineRule wrap_rhs arity+ `setInlinePragma` wrap_prag+ `setIdOccInfo` noOccInfo+ -- Zap any loop-breaker-ness, to avoid bleating from Lint+ -- about a loop breaker with an INLINE rule++++ return $ [(work_id, work_rhs), (wrap_id, wrap_rhs)]+ -- Worker first, because wrapper mentions it++ Nothing -> return [(fn_id, rhs)]+ where+ mb_join_arity = isJoinId_maybe fn_id+ rhs_fvs = exprFreeVars rhs+ fun_ty = idType fn_id+ inl_prag = inlinePragInfo fn_info+ rule_match_info = inlinePragmaRuleMatchInfo inl_prag+ arity = arityInfo fn_info+ -- The arity is set by the simplifier using exprEtaExpandArity+ -- So it may be more than the number of top-level-visible lambdas++ use_res_info | isJoinId fn_id = topRes -- Note [Don't CPR join points]+ | otherwise = res_info+ work_res_info | isJoinId fn_id = res_info -- Worker remains CPR-able+ | otherwise+ = case returnsCPR_maybe res_info of+ Just _ -> topRes -- Cpr stuff done by wrapper; kill it here+ Nothing -> res_info -- Preserve exception/divergence+++{-+Note [Demand on the worker]+~~~~~~~~~~~~~~~~~~~~~~~~~~~++If the original function is called once, according to its demand info, then+so is the worker. This is important so that the occurrence analyser can+attach OneShot annotations to the worker’s lambda binders.+++Example:++ -- Original function+ f [Demand=<L,1*C1(U)>] :: (a,a) -> a+ f = \p -> ...++ -- Wrapper+ f [Demand=<L,1*C1(U)>] :: a -> a -> a+ f = \p -> case p of (a,b) -> $wf a b++ -- Worker+ $wf [Demand=<L,1*C1(C1(U))>] :: Int -> Int+ $wf = \a b -> ...++We need to check whether the original function is called once, with+sufficiently many arguments. This is done using saturatedByOneShots, which+takes the arity of the original function (resp. the wrapper) and the demand on+the original function.++The demand on the worker is then calculated using mkWorkerDemand, and always of+the form [Demand=<L,1*(C1(...(C1(U))))>]+++Note [Do not split void functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this rather common form of binding:+ $j = \x:Void# -> ...no use of x...++Since x is not used it'll be marked as absent. But there is no point+in w/w-ing because we'll simply add (\y:Void#), see WwLib.mkWorerArgs.++If x has a more interesting type (eg Int, or Int#), there *is* a point+in w/w so that we don't pass the argument at all.++Note [Thunk splitting]+~~~~~~~~~~~~~~~~~~~~~~+Suppose x is used strictly (never mind whether it has the CPR+property).++ let+ x* = x-rhs+ in body++splitThunk transforms like this:++ let+ x* = case x-rhs of { I# a -> I# a }+ in body++Now simplifier will transform to++ case x-rhs of+ I# a -> let x* = I# a+ in body++which is what we want. Now suppose x-rhs is itself a case:++ x-rhs = case e of { T -> I# a; F -> I# b }++The join point will abstract over a, rather than over (which is+what would have happened before) which is fine.++Notice that x certainly has the CPR property now!++In fact, splitThunk uses the function argument w/w splitting+function, so that if x's demand is deeper (say U(U(L,L),L))+then the splitting will go deeper too.+-}++-- See Note [Thunk splitting]+-- splitThunk converts the *non-recursive* binding+-- x = e+-- into+-- x = let x = e+-- in case x of+-- I# y -> let x = I# y in x }+-- See comments above. Is it not beautifully short?+-- Moreover, it works just as well when there are+-- several binders, and if the binders are lifted+-- E.g. x = e+-- --> x = let x = e in+-- case x of (a,b) -> let x = (a,b) in x++splitThunk :: DynFlags -> FamInstEnvs -> RecFlag -> Var -> Expr Var -> UniqSM [(Var, Expr Var)]+splitThunk dflags fam_envs is_rec fn_id rhs+ = ASSERT(not (isJoinId fn_id))+ do { (useful,_, wrap_fn, work_fn) <- mkWWstr dflags fam_envs [fn_id]+ ; let res = [ (fn_id, Let (NonRec fn_id rhs) (wrap_fn (work_fn (Var fn_id)))) ]+ ; if useful then ASSERT2( isNonRec is_rec, ppr fn_id ) -- The thunk must be non-recursive+ return res+ else return [(fn_id, rhs)] }
+ stranal/WwLib.hs view
@@ -0,0 +1,952 @@+{-+(c) The GRASP/AQUA Project, Glasgow University, 1993-1998++\section[WwLib]{A library for the ``worker\/wrapper'' back-end to the strictness analyser}+-}++{-# LANGUAGE CPP #-}++module WwLib ( mkWwBodies, mkWWstr, mkWorkerArgs+ , deepSplitProductType_maybe, findTypeShape+ , isWorkerSmallEnough+ ) where++#include "HsVersions.h"++import CoreSyn+import CoreUtils ( exprType, mkCast )+import Id+import IdInfo ( JoinArity, vanillaIdInfo )+import DataCon+import Demand+import MkCore ( mkRuntimeErrorApp, aBSENT_ERROR_ID, mkCoreUbxTup+ , mkCoreApp, mkCoreLet )+import MkId ( voidArgId, voidPrimId )+import TysPrim ( voidPrimTy )+import TysWiredIn ( tupleDataCon )+import VarEnv ( mkInScopeSet )+import VarSet ( VarSet )+import Type+import RepType ( isVoidTy )+import Coercion+import FamInstEnv+import BasicTypes ( Boxity(..) )+import Literal ( absentLiteralOf )+import TyCon+import UniqSupply+import Unique+import Maybes+import Util+import Outputable+import DynFlags+import FastString+import ListSetOps++{-+************************************************************************+* *+\subsection[mkWrapperAndWorker]{@mkWrapperAndWorker@}+* *+************************************************************************++Here's an example. The original function is:++\begin{verbatim}+g :: forall a . Int -> [a] -> a++g = \/\ a -> \ x ys ->+ case x of+ 0 -> head ys+ _ -> head (tail ys)+\end{verbatim}++From this, we want to produce:+\begin{verbatim}+-- wrapper (an unfolding)+g :: forall a . Int -> [a] -> a++g = \/\ a -> \ x ys ->+ case x of+ I# x# -> $wg a x# ys+ -- call the worker; don't forget the type args!++-- worker+$wg :: forall a . Int# -> [a] -> a++$wg = \/\ a -> \ x# ys ->+ let+ x = I# x#+ in+ case x of -- note: body of g moved intact+ 0 -> head ys+ _ -> head (tail ys)+\end{verbatim}++Something we have to be careful about: Here's an example:++\begin{verbatim}+-- "f" strictness: U(P)U(P)+f (I# a) (I# b) = a +# b++g = f -- "g" strictness same as "f"+\end{verbatim}++\tr{f} will get a worker all nice and friendly-like; that's good.+{\em But we don't want a worker for \tr{g}}, even though it has the+same strictness as \tr{f}. Doing so could break laziness, at best.++Consequently, we insist that the number of strictness-info items is+exactly the same as the number of lambda-bound arguments. (This is+probably slightly paranoid, but OK in practice.) If it isn't the+same, we ``revise'' the strictness info, so that we won't propagate+the unusable strictness-info into the interfaces.+++************************************************************************+* *+\subsection{The worker wrapper core}+* *+************************************************************************++@mkWwBodies@ is called when doing the worker\/wrapper split inside a module.+-}++type WwResult+ = ([Demand], -- Demands for worker (value) args+ JoinArity, -- Number of worker (type OR value) args+ Id -> CoreExpr, -- Wrapper body, lacking only the worker Id+ CoreExpr -> CoreExpr) -- Worker body, lacking the original function rhs++mkWwBodies :: DynFlags+ -> FamInstEnvs+ -> VarSet -- Free vars of RHS+ -- See Note [Freshen WW arguments]+ -> Maybe JoinArity -- Just ar <=> is join point with join arity ar+ -> Type -- Type of original function+ -> [Demand] -- Strictness of original function+ -> DmdResult -- Info about function result+ -> UniqSM (Maybe WwResult)++-- wrap_fn_args E = \x y -> E+-- work_fn_args E = E x y++-- wrap_fn_str E = case x of { (a,b) ->+-- case a of { (a1,a2) ->+-- E a1 a2 b y }}+-- work_fn_str E = \a2 a2 b y ->+-- let a = (a1,a2) in+-- let x = (a,b) in+-- E++mkWwBodies dflags fam_envs rhs_fvs mb_join_arity fun_ty demands res_info+ = do { let empty_subst = mkEmptyTCvSubst (mkInScopeSet rhs_fvs)+ -- See Note [Freshen WW arguments]++ ; (wrap_args, wrap_fn_args, work_fn_args, res_ty) <- mkWWargs empty_subst fun_ty demands+ ; (useful1, work_args, wrap_fn_str, work_fn_str) <- mkWWstr dflags fam_envs wrap_args++ -- Do CPR w/w. See Note [Always do CPR w/w]+ ; (useful2, wrap_fn_cpr, work_fn_cpr, cpr_res_ty)+ <- mkWWcpr (gopt Opt_CprAnal dflags) fam_envs res_ty res_info++ ; let (work_lam_args, work_call_args) = mkWorkerArgs dflags work_args cpr_res_ty+ worker_args_dmds = [idDemandInfo v | v <- work_call_args, isId v]+ wrapper_body = wrap_fn_args . wrap_fn_cpr . wrap_fn_str . applyToVars work_call_args . Var+ worker_body = mkLams work_lam_args. work_fn_str . work_fn_cpr . work_fn_args++ ; if isWorkerSmallEnough dflags work_args+ && not (too_many_args_for_join_point wrap_args)+ && (useful1 && not only_one_void_argument || useful2)+ then return (Just (worker_args_dmds, length work_call_args,+ wrapper_body, worker_body))+ else return Nothing+ }+ -- We use an INLINE unconditionally, even if the wrapper turns out to be+ -- something trivial like+ -- fw = ...+ -- f = __inline__ (coerce T fw)+ -- The point is to propagate the coerce to f's call sites, so even though+ -- f's RHS is now trivial (size 1) we still want the __inline__ to prevent+ -- fw from being inlined into f's RHS+ where+ -- Note [Do not split void functions]+ only_one_void_argument+ | [d] <- demands+ , Just (arg_ty1, _) <- splitFunTy_maybe fun_ty+ , isAbsDmd d && isVoidTy arg_ty1+ = True+ | otherwise+ = False++ -- Note [Join points returning functions]+ too_many_args_for_join_point wrap_args+ | Just join_arity <- mb_join_arity+ , wrap_args `lengthExceeds` join_arity+ = WARN(True, text "Unable to worker/wrapper join point with arity " <+>+ int join_arity <+> text "but" <+>+ int (length wrap_args) <+> text "args")+ True+ | otherwise+ = False++-- See Note [Limit w/w arity]+isWorkerSmallEnough :: DynFlags -> [Var] -> Bool+isWorkerSmallEnough dflags vars = count isId vars <= maxWorkerArgs dflags+ -- We count only Free variables (isId) to skip Type, Kind+ -- variables which have no runtime representation.++{-+Note [Always do CPR w/w]+~~~~~~~~~~~~~~~~~~~~~~~~+At one time we refrained from doing CPR w/w for thunks, on the grounds that+we might duplicate work. But that is already handled by the demand analyser,+which doesn't give the CPR proprety if w/w might waste work: see+Note [CPR for thunks] in DmdAnal.++And if something *has* been given the CPR property and we don't w/w, it's+a disaster, because then the enclosing function might say it has the CPR+property, but now doesn't and there a cascade of disaster. A good example+is Trac #5920.++Note [Limit w/w arity]+~~~~~~~~~~~~~~~~~~~~~~~~+Guard against high worker arity as it generates a lot of stack traffic.+A simplified example is Trac #11565#comment:6++Current strategy is very simple: don't perform w/w transformation at all+if the result produces a wrapper with arity higher than -fmax-worker-args=.++It is a bit all or nothing, consider++ f (x,y) (a,b,c,d,e ... , z) = rhs++Currently we will remove all w/w ness entirely. But actually we could+w/w on the (x,y) pair... it's the huge product that is the problem.++Could we instead refrain from w/w on an arg-by-arg basis? Yes, that'd+solve f. But we can get a lot of args from deeply-nested products:++ g (a, (b, (c, (d, ...)))) = rhs++This is harder to spot on an arg-by-arg basis. Previously mkWwStr was+given some "fuel" saying how many arguments it could add; when we ran+out of fuel it would stop w/wing.+Still not very clever because it had a left-right bias.++************************************************************************+* *+\subsection{Making wrapper args}+* *+************************************************************************++During worker-wrapper stuff we may end up with an unlifted thing+which we want to let-bind without losing laziness. So we+add a void argument. E.g.++ f = /\a -> \x y z -> E::Int# -- E does not mention x,y,z+==>+ fw = /\ a -> \void -> E+ f = /\ a -> \x y z -> fw realworld++We use the state-token type which generates no code.+-}++mkWorkerArgs :: DynFlags -> [Var]+ -> Type -- Type of body+ -> ([Var], -- Lambda bound args+ [Var]) -- Args at call site+mkWorkerArgs dflags args res_ty+ | any isId args || not needsAValueLambda+ = (args, args)+ | otherwise+ = (args ++ [voidArgId], args ++ [voidPrimId])+ where+ needsAValueLambda =+ isUnliftedType res_ty+ || not (gopt Opt_FunToThunk dflags)+ -- see Note [Protecting the last value argument]++{-+Note [Protecting the last value argument]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the user writes (\_ -> E), they might be intentionally disallowing+the sharing of E. Since absence analysis and worker-wrapper are keen+to remove such unused arguments, we add in a void argument to prevent+the function from becoming a thunk.++The user can avoid adding the void argument with the -ffun-to-thunk+flag. However, this can create sharing, which may be bad in two ways. 1) It can+create a space leak. 2) It can prevent inlining *under a lambda*. If w/w+removes the last argument from a function f, then f now looks like a thunk, and+so f can't be inlined *under a lambda*.++Note [Join points and beta-redexes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Originally, the worker would invoke the original function by calling it with+arguments, thus producing a beta-redex for the simplifier to munch away:++ \x y z -> e => (\x y z -> e) wx wy wz++Now that we have special rules about join points, however, this is Not Good if+the original function is itself a join point, as then it may contain invocations+of other join points:++ join j1 x = ...+ join j2 y = if y == 0 then 0 else j1 y++ =>++ join j1 x = ...+ join $wj2 y# = let wy = I# y# in (\y -> if y == 0 then 0 else jump j1 y) wy+ join j2 y = case y of I# y# -> jump $wj2 y#++There can't be an intervening lambda between a join point's declaration and its+occurrences, so $wj2 here is wrong. But of course, this is easy enough to fix:++ ...+ let join $wj2 y# = let wy = I# y# in let y = wy in if y == 0 then 0 else j1 y+ ...++Hence we simply do the beta-reduction here. (This would be harder if we had to+worry about hygiene, but luckily wy is freshly generated.)++Note [Join points returning functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++It is crucial that the arity of a join point depends on its *callers,* not its+own syntax. What this means is that a join point can have "extra lambdas":++f :: Int -> Int -> (Int, Int) -> Int+f x y = join j (z, w) = \(u, v) -> ...+ in jump j (x, y)++Typically this happens with functions that are seen as computing functions,+rather than being curried. (The real-life example was GraphOps.addConflicts.)++When we create the wrapper, it *must* be in "eta-contracted" form so that the+jump has the right number of arguments:++f x y = join $wj z' w' = \u' v' -> let {z = z'; w = w'; u = u'; v = v'} in ...+ j (z, w) = jump $wj z w++(See Note [Join points and beta-redexes] for where the lets come from.) If j+were a function, we would instead say++f x y = let $wj = \z' w' u' v' -> let {z = z'; w = w'; u = u'; v = v'} in ...+ j (z, w) (u, v) = $wj z w u v++Notice that the worker ends up with the same lambdas; it's only the wrapper we+have to be concerned about.++FIXME Currently the functionality to produce "eta-contracted" wrappers is+unimplemented; we simply give up.++************************************************************************+* *+\subsection{Coercion stuff}+* *+************************************************************************++We really want to "look through" coerces.+Reason: I've seen this situation:++ let f = coerce T (\s -> E)+ in \x -> case x of+ p -> coerce T' f+ q -> \s -> E2+ r -> coerce T' f++If only we w/w'd f, we'd get+ let f = coerce T (\s -> fw s)+ fw = \s -> E+ in ...++Now we'll inline f to get++ let fw = \s -> E+ in \x -> case x of+ p -> fw+ q -> \s -> E2+ r -> fw++Now we'll see that fw has arity 1, and will arity expand+the \x to get what we want.+-}++-- mkWWargs just does eta expansion+-- is driven off the function type and arity.+-- It chomps bites off foralls, arrows, newtypes+-- and keeps repeating that until it's satisfied the supplied arity++mkWWargs :: TCvSubst -- Freshening substitution to apply to the type+ -- See Note [Freshen WW arguments]+ -> Type -- The type of the function+ -> [Demand] -- Demands and one-shot info for value arguments+ -> UniqSM ([Var], -- Wrapper args+ CoreExpr -> CoreExpr, -- Wrapper fn+ CoreExpr -> CoreExpr, -- Worker fn+ Type) -- Type of wrapper body++mkWWargs subst fun_ty demands+ | null demands+ = return ([], id, id, substTy subst fun_ty)++ | (dmd:demands') <- demands+ , Just (arg_ty, fun_ty') <- splitFunTy_maybe fun_ty+ = do { uniq <- getUniqueM+ ; let arg_ty' = substTy subst arg_ty+ id = mk_wrap_arg uniq arg_ty' dmd+ ; (wrap_args, wrap_fn_args, work_fn_args, res_ty)+ <- mkWWargs subst fun_ty' demands'+ ; return (id : wrap_args,+ Lam id . wrap_fn_args,+ apply_or_bind_then work_fn_args (varToCoreExpr id),+ res_ty) }++ | Just (tv, fun_ty') <- splitForAllTy_maybe fun_ty+ = do { uniq <- getUniqueM+ ; let (subst', tv') = cloneTyVarBndr subst tv uniq+ -- See Note [Freshen WW arguments]+ ; (wrap_args, wrap_fn_args, work_fn_args, res_ty)+ <- mkWWargs subst' fun_ty' demands+ ; return (tv' : wrap_args,+ Lam tv' . wrap_fn_args,+ apply_or_bind_then work_fn_args (mkTyArg (mkTyVarTy tv')),+ res_ty) }++ | Just (co, rep_ty) <- topNormaliseNewType_maybe fun_ty+ -- The newtype case is for when the function has+ -- a newtype after the arrow (rare)+ --+ -- It's also important when we have a function returning (say) a pair+ -- wrapped in a newtype, at least if CPR analysis can look+ -- through such newtypes, which it probably can since they are+ -- simply coerces.++ = do { (wrap_args, wrap_fn_args, work_fn_args, res_ty)+ <- mkWWargs subst rep_ty demands+ ; let co' = substCo subst co+ ; return (wrap_args,+ \e -> Cast (wrap_fn_args e) (mkSymCo co'),+ \e -> work_fn_args (Cast e co'),+ res_ty) }++ | otherwise+ = WARN( True, ppr fun_ty ) -- Should not happen: if there is a demand+ return ([], id, id, substTy subst fun_ty) -- then there should be a function arrow+ where+ -- See Note [Join points and beta-redexes]+ apply_or_bind_then k arg (Lam bndr body)+ = mkCoreLet (NonRec bndr arg) (k body) -- Important that arg is fresh!+ apply_or_bind_then k arg fun+ = k $ mkCoreApp (text "mkWWargs") fun arg+applyToVars :: [Var] -> CoreExpr -> CoreExpr+applyToVars vars fn = mkVarApps fn vars++mk_wrap_arg :: Unique -> Type -> Demand -> Id+mk_wrap_arg uniq ty dmd+ = mkSysLocalOrCoVar (fsLit "w") uniq ty+ `setIdDemandInfo` dmd++{- Note [Freshen WW arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Wen we do a worker/wrapper split, we must not in-scope names as the arguments+of the worker, else we'll get name capture. E.g.++ -- y1 is in scope from further out+ f x = ..y1..++If we accidentally choose y1 as a worker argument disaster results:++ fww y1 y2 = let x = (y1,y2) in ...y1...++To avoid this:++ * We use a fresh unique for both type-variable and term-variable binders+ Originally we lacked this freshness for type variables, and that led+ to the very obscure Trac #12562. (A type variable in the worker shadowed+ an outer term-variable binding.)++ * Because of this cloning we have to substitute in the type/kind of the+ new binders. That's why we carry the TCvSubst through mkWWargs.++ So we need a decent in-scope set, just in case that type/kind+ itself has foralls. We get this from the free vars of the RHS of the+ function since those are the only variables that might be captured.+ It's a lazy thunk, which will only be poked if the type/kind has a forall.++ Another tricky case was when f :: forall a. a -> forall a. a->a+ (i.e. with shadowing), and then the worker used the same 'a' twice.++************************************************************************+* *+\subsection{Strictness stuff}+* *+************************************************************************+-}++mkWWstr :: DynFlags+ -> FamInstEnvs+ -> [Var] -- Wrapper args; have their demand info on them+ -- *Includes type variables*+ -> UniqSM (Bool, -- Is this useful+ [Var], -- Worker args+ CoreExpr -> CoreExpr, -- Wrapper body, lacking the worker call+ -- and without its lambdas+ -- This fn adds the unboxing++ CoreExpr -> CoreExpr) -- Worker body, lacking the original body of the function,+ -- and lacking its lambdas.+ -- This fn does the reboxing+mkWWstr _ _ []+ = return (False, [], nop_fn, nop_fn)++mkWWstr dflags fam_envs (arg : args) = do+ (useful1, args1, wrap_fn1, work_fn1) <- mkWWstr_one dflags fam_envs arg+ (useful2, args2, wrap_fn2, work_fn2) <- mkWWstr dflags fam_envs args+ return (useful1 || useful2, args1 ++ args2, wrap_fn1 . wrap_fn2, work_fn1 . work_fn2)++{-+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 pkgState files.+-}++----------------------+-- mkWWstr_one wrap_arg = (useful, work_args, wrap_fn, work_fn)+-- * wrap_fn assumes wrap_arg is in scope,+-- brings into scope work_args (via cases)+-- * work_fn assumes work_args are in scope, a+-- brings into scope wrap_arg (via lets)+mkWWstr_one :: DynFlags -> FamInstEnvs -> Var+ -> UniqSM (Bool, [Var], CoreExpr -> CoreExpr, CoreExpr -> CoreExpr)+mkWWstr_one dflags fam_envs arg+ | isTyVar arg+ = return (False, [arg], nop_fn, nop_fn)++ -- See Note [Worker-wrapper for bottoming functions]+ | isAbsDmd dmd+ , Just work_fn <- mk_absent_let dflags arg+ -- Absent case. We can't always handle absence for arbitrary+ -- unlifted types, so we need to choose just the cases we can+ --- (that's what mk_absent_let does)+ = return (True, [], nop_fn, work_fn)++ -- See Note [Worthy functions for Worker-Wrapper split]+ | isSeqDmd dmd -- `seq` demand; evaluate in wrapper in the hope+ -- of dropping seqs in the worker+ = let arg_w_unf = arg `setIdUnfolding` evaldUnfolding+ -- Tell the worker arg that it's sure to be evaluated+ -- so that internal seqs can be dropped+ in return (True, [arg_w_unf], mk_seq_case arg, nop_fn)+ -- Pass the arg, anyway, even if it is in theory discarded+ -- Consider+ -- f x y = x `seq` y+ -- x gets a (Eval (Poly Abs)) demand, but if we fail to pass it to the worker+ -- we ABSOLUTELY MUST record that x is evaluated in the wrapper.+ -- Something like:+ -- f x y = x `seq` fw y+ -- fw y = let x{Evald} = error "oops" in (x `seq` y)+ -- If we don't pin on the "Evald" flag, the seq doesn't disappear, and+ -- we end up evaluating the absent thunk.+ -- But the Evald flag is pretty weird, and I worry that it might disappear+ -- during simplification, so for now I've just nuked this whole case++ | isStrictDmd dmd+ , Just cs <- splitProdDmd_maybe dmd+ -- See Note [Unpacking arguments with product and polymorphic demands]+ , Just (data_con, inst_tys, inst_con_arg_tys, co)+ <- deepSplitProductType_maybe fam_envs (idType arg)+ , cs `equalLength` inst_con_arg_tys+ -- See Note [mkWWstr and unsafeCoerce]+ = do { (uniq1:uniqs) <- getUniquesM+ ; let unpk_args = zipWith3 mk_ww_arg uniqs inst_con_arg_tys cs+ unbox_fn = mkUnpackCase (Var arg) co uniq1+ data_con unpk_args+ rebox_fn = Let (NonRec arg con_app)+ con_app = mkConApp2 data_con inst_tys unpk_args `mkCast` mkSymCo co+ ; (_, worker_args, wrap_fn, work_fn) <- mkWWstr dflags fam_envs unpk_args+ ; return (True, worker_args, unbox_fn . wrap_fn, work_fn . rebox_fn) }+ -- Don't pass the arg, rebox instead++ | otherwise -- Other cases+ = return (False, [arg], nop_fn, nop_fn)++ where+ dmd = idDemandInfo arg+ mk_ww_arg uniq ty sub_dmd = setIdDemandInfo (mk_ww_local uniq ty) sub_dmd++----------------------+nop_fn :: CoreExpr -> CoreExpr+nop_fn body = body++{-+Note [mkWWstr and unsafeCoerce]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+By using unsafeCoerce, it is possible to make the number of demands fail to+match the number of constructor arguments; this happened in Trac #8037.+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 [Record evaluated-ness in worker/wrapper]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have++ data T = MkT !Int Int++ f :: T -> T+ f x = e++and f's is strict, and has the CPR property. The we are going to generate+this w/w split++ f x = case x of+ MkT x1 x2 -> case $wf x1 x2 of+ (# r1, r2 #) -> MkT r1 r2++ $wfw x1 x2 = let x = MkT x1 x2 in+ case e of+ MkT r1 r2 -> (# r1, r2 #)++Note that++* In the worker $wf, inside 'e' we can be sure that x1 will be+ evaluated (it came from unpacking the argument MkT. But that's no+ immediately apparent in $wf++* In the wrapper 'f', which we'll inline at call sites, we can be sure+ that 'r1' has been evaluated (because it came from unpacking the result+ MkT. But that is not immediately apparent from the wrapper code.++Missing these facts isn't unsound, but it loses possible future+opportunities for optimisation.++Solution: use setCaseBndrEvald when creating+ (A) The arg binders x1,x2 in mkWstr_one+ See Trac #13077, test T13077+ (B) The result binders r1,r2 in mkWWcpr_help+ See Trace #13077, test T13077a+ And Trac #13027 comment:20, item (4)+to record that the relevant binder is evaluated.+++************************************************************************+* *+ Type scrutiny that is specific to demand analysis+* *+************************************************************************++Note [Do not unpack class dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have+ f :: Ord a => [a] -> Int -> a+ {-# INLINABLE f #-}+and we worker/wrapper f, we'll get a worker with an INLINABLE pragma+(see Note [Worker-wrapper for INLINABLE functions] in WorkWrap), which+can still be specialised by the type-class specialiser, something like+ fw :: Ord a => [a] -> Int# -> a++BUT if f is strict in the Ord dictionary, we might unpack it, to get+ fw :: (a->a->Bool) -> [a] -> Int# -> a+and the type-class specialiser can't specialise that. An example is+Trac #6056.++Moreover, dictionaries can have a lot of fields, so unpacking them can+increase closure sizes.++Conclusion: don't unpack dictionaries.+-}++deepSplitProductType_maybe+ :: FamInstEnvs -> Type+ -> Maybe (DataCon, [Type], [(Type, StrictnessMark)], Coercion)+-- If deepSplitProductType_maybe ty = Just (dc, tys, arg_tys, co)+-- then dc @ tys (args::arg_tys) :: rep_ty+-- co :: ty ~ rep_ty+-- Why do we return the strictness of the data-con arguments?+-- Answer: see Note [Record evaluated-ness in worker/wrapper]+deepSplitProductType_maybe fam_envs ty+ | let (co, ty1) = topNormaliseType_maybe fam_envs ty+ `orElse` (mkRepReflCo ty, ty)+ , Just (tc, tc_args) <- splitTyConApp_maybe ty1+ , Just con <- isDataProductTyCon_maybe tc+ , not (isClassTyCon tc) -- See Note [Do not unpack class dictionaries]+ , let arg_tys = dataConInstArgTys con tc_args+ strict_marks = dataConRepStrictness con+ = Just (con, tc_args, zipEqual "dspt" arg_tys strict_marks, co)+deepSplitProductType_maybe _ _ = Nothing++deepSplitCprType_maybe+ :: FamInstEnvs -> ConTag -> Type+ -> Maybe (DataCon, [Type], [(Type, StrictnessMark)], Coercion)+-- If deepSplitCprType_maybe n ty = Just (dc, tys, arg_tys, co)+-- then dc @ tys (args::arg_tys) :: rep_ty+-- co :: ty ~ rep_ty+-- Why do we return the strictness of the data-con arguments?+-- Answer: see Note [Record evaluated-ness in worker/wrapper]+deepSplitCprType_maybe fam_envs con_tag ty+ | let (co, ty1) = topNormaliseType_maybe fam_envs ty+ `orElse` (mkRepReflCo ty, ty)+ , Just (tc, tc_args) <- splitTyConApp_maybe ty1+ , isDataTyCon tc+ , let cons = tyConDataCons tc+ , cons `lengthAtLeast` con_tag -- This might not be true if we import the+ -- type constructor via a .hs-bool file (#8743)+ , let con = cons `getNth` (con_tag - fIRST_TAG)+ arg_tys = dataConInstArgTys con tc_args+ strict_marks = dataConRepStrictness con+ = Just (con, tc_args, zipEqual "dsct" arg_tys strict_marks, co)+deepSplitCprType_maybe _ _ _ = Nothing++findTypeShape :: FamInstEnvs -> Type -> TypeShape+-- Uncover the arrow and product shape of a type+-- The data type TypeShape is defined in Demand+-- See Note [Trimming a demand to a type] in Demand+findTypeShape fam_envs ty+ | Just (tc, tc_args) <- splitTyConApp_maybe ty+ , Just con <- isDataProductTyCon_maybe tc+ = TsProd (map (findTypeShape fam_envs) $ dataConInstArgTys con tc_args)++ | Just (_, res) <- splitFunTy_maybe ty+ = TsFun (findTypeShape fam_envs res)++ | Just (_, ty') <- splitForAllTy_maybe ty+ = findTypeShape fam_envs ty'++ | Just (_, ty') <- topNormaliseType_maybe fam_envs ty+ = findTypeShape fam_envs ty'++ | otherwise+ = TsUnk++{-+************************************************************************+* *+\subsection{CPR stuff}+* *+************************************************************************+++@mkWWcpr@ takes the worker/wrapper pair produced from the strictness+info and adds in the CPR transformation. The worker returns an+unboxed tuple containing non-CPR components. The wrapper takes this+tuple and re-produces the correct structured output.++The non-CPR results appear ordered in the unboxed tuple as if by a+left-to-right traversal of the result structure.+-}++mkWWcpr :: Bool+ -> FamInstEnvs+ -> Type -- function body type+ -> DmdResult -- CPR analysis results+ -> UniqSM (Bool, -- Is w/w'ing useful?+ CoreExpr -> CoreExpr, -- New wrapper+ CoreExpr -> CoreExpr, -- New worker+ Type) -- Type of worker's body++mkWWcpr opt_CprAnal fam_envs body_ty res+ -- CPR explicitly turned off (or in -O0)+ | not opt_CprAnal = return (False, id, id, body_ty)+ -- CPR is turned on by default for -O and O2+ | otherwise+ = case returnsCPR_maybe res of+ Nothing -> return (False, id, id, body_ty) -- No CPR info+ Just con_tag | Just stuff <- deepSplitCprType_maybe fam_envs con_tag body_ty+ -> mkWWcpr_help stuff+ | otherwise+ -- See Note [non-algebraic or open body type warning]+ -> WARN( True, text "mkWWcpr: non-algebraic or open body type" <+> ppr body_ty )+ return (False, id, id, body_ty)++mkWWcpr_help :: (DataCon, [Type], [(Type,StrictnessMark)], Coercion)+ -> UniqSM (Bool, CoreExpr -> CoreExpr, CoreExpr -> CoreExpr, Type)++mkWWcpr_help (data_con, inst_tys, arg_tys, co)+ | [arg1@(arg_ty1, _)] <- arg_tys+ , isUnliftedType arg_ty1+ -- Special case when there is a single result of unlifted type+ --+ -- Wrapper: case (..call worker..) of x -> C x+ -- Worker: case ( ..body.. ) of C x -> x+ = do { (work_uniq : arg_uniq : _) <- getUniquesM+ ; let arg = mk_ww_local arg_uniq arg1+ con_app = mkConApp2 data_con inst_tys [arg] `mkCast` mkSymCo co++ ; return ( True+ , \ wkr_call -> Case wkr_call arg (exprType con_app) [(DEFAULT, [], con_app)]+ , \ body -> mkUnpackCase body co work_uniq data_con [arg] (varToCoreExpr arg)+ -- varToCoreExpr important here: arg can be a coercion+ -- Lacking this caused Trac #10658+ , arg_ty1 ) }++ | otherwise -- The general case+ -- Wrapper: case (..call worker..) of (# a, b #) -> C a b+ -- Worker: case ( ...body... ) of C a b -> (# a, b #)+ = do { (work_uniq : wild_uniq : uniqs) <- getUniquesM+ ; let wrap_wild = mk_ww_local wild_uniq (ubx_tup_ty,MarkedStrict)+ args = zipWith mk_ww_local uniqs arg_tys+ ubx_tup_ty = exprType ubx_tup_app+ ubx_tup_app = mkCoreUbxTup (map fst arg_tys) (map varToCoreExpr args)+ con_app = mkConApp2 data_con inst_tys args `mkCast` mkSymCo co++ ; return (True+ , \ wkr_call -> Case wkr_call wrap_wild (exprType con_app) [(DataAlt (tupleDataCon Unboxed (length arg_tys)), args, con_app)]+ , \ body -> mkUnpackCase body co work_uniq data_con args ubx_tup_app+ , ubx_tup_ty ) }++mkUnpackCase :: CoreExpr -> Coercion -> Unique -> DataCon -> [Id] -> CoreExpr -> CoreExpr+-- (mkUnpackCase e co uniq Con args body)+-- returns+-- case e |> co of bndr { Con args -> body }++mkUnpackCase (Tick tickish e) co uniq con args body -- See Note [Profiling and unpacking]+ = Tick tickish (mkUnpackCase e co uniq con args body)+mkUnpackCase scrut co uniq boxing_con unpk_args body+ = Case casted_scrut bndr (exprType body)+ [(DataAlt boxing_con, unpk_args, body)]+ where+ casted_scrut = scrut `mkCast` co+ bndr = mk_ww_local uniq (exprType casted_scrut, MarkedStrict)++{-+Note [non-algebraic or open body type warning]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++There are a few cases where the W/W transformation is told that something+returns a constructor, but the type at hand doesn't really match this. One+real-world example involves unsafeCoerce:+ foo = IO a+ foo = unsafeCoerce c_exit+ foreign import ccall "c_exit" c_exit :: IO ()+Here CPR will tell you that `foo` returns a () constructor for sure, but trying+to create a worker/wrapper for type `a` obviously fails.+(This was a real example until ee8e792 in libraries/base.)++It does not seem feasible to avoid all such cases already in the analyser (and+after all, the analysis is not really wrong), so we simply do nothing here in+mkWWcpr. But we still want to emit warning with -DDEBUG, to hopefully catch+other cases where something went avoidably wrong.+++Note [Profiling and unpacking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the original function looked like+ f = \ x -> {-# SCC "foo" #-} E++then we want the CPR'd worker to look like+ \ x -> {-# SCC "foo" #-} (case E of I# x -> x)+and definitely not+ \ x -> case ({-# SCC "foo" #-} E) of I# x -> x)++This transform doesn't move work or allocation+from one cost centre to another.++Later [SDM]: presumably this is because we want the simplifier to+eliminate the case, and the scc would get in the way? I'm ok with+including the case itself in the cost centre, since it is morally+part of the function (post transformation) anyway.+++************************************************************************+* *+\subsection{Utilities}+* *+************************************************************************++Note [Absent errors]+~~~~~~~~~~~~~~~~~~~~+We make a new binding for Ids that are marked absent, thus+ let x = absentError "x :: Int"+The idea is that this binding will never be used; but if it+buggily is used we'll get a runtime error message.++Coping with absence for *unlifted* types is important; see, for+example, Trac #4306. For these we find a suitable literal,+using Literal.absentLiteralOf. We don't have literals for+every primitive type, so the function is partial.++ [I did try the experiment of using an error thunk for unlifted+ things too, relying on the simplifier to drop it as dead code,+ by making absentError+ (a) *not* be a bottoming Id,+ (b) be "ok for speculation"+ But that relies on the simplifier finding that it really+ is dead code, which is fragile, and indeed failed when+ profiling is on, which disables various optimisations. So+ using a literal will do.]+-}++mk_absent_let :: DynFlags -> Id -> Maybe (CoreExpr -> CoreExpr)+mk_absent_let dflags arg+ | not (isUnliftedType arg_ty)+ = Just (Let (NonRec lifted_arg abs_rhs))+ | Just tc <- tyConAppTyCon_maybe arg_ty+ , Just lit <- absentLiteralOf tc+ = Just (Let (NonRec arg (Lit lit)))+ | arg_ty `eqType` voidPrimTy+ = Just (Let (NonRec arg (Var voidPrimId)))+ | otherwise+ = WARN( True, text "No absent value for" <+> ppr arg_ty )+ Nothing+ where+ arg_ty = idType arg+ abs_rhs = mkRuntimeErrorApp aBSENT_ERROR_ID arg_ty msg+ lifted_arg = arg `setIdStrictness` exnSig+ -- Note in strictness signature that this is bottoming+ -- (for the sake of the "empty case scrutinee not known to+ -- diverge for sure lint" warning)+ msg = showSDoc (gopt_set dflags Opt_SuppressUniques)+ (ppr arg <+> ppr (idType arg))+ -- We need to suppress uniques here because otherwise they'd+ -- end up in the generated code as strings. This is bad for+ -- determinism, because with different uniques the strings+ -- will have different lengths and hence different costs for+ -- the inliner leading to different inlining.+ -- See also Note [Unique Determinism] in Unique++mk_seq_case :: Id -> CoreExpr -> CoreExpr+mk_seq_case arg body = Case (Var arg) (sanitiseCaseBndr arg) (exprType body) [(DEFAULT, [], body)]++sanitiseCaseBndr :: Id -> Id+-- The argument we are scrutinising has the right type to be+-- a case binder, so it's convenient to re-use it for that purpose.+-- But we *must* throw away all its IdInfo. In particular, the argument+-- will have demand info on it, and that demand info may be incorrect for+-- the case binder. e.g. case ww_arg of ww_arg { I# x -> ... }+-- Quite likely ww_arg isn't used in '...'. The case may get discarded+-- if the case binder says "I'm demanded". This happened in a situation+-- like (x+y) `seq` ....+sanitiseCaseBndr id = id `setIdInfo` vanillaIdInfo++mk_ww_local :: Unique -> (Type, StrictnessMark) -> Id+-- The StrictnessMark comes form the data constructor and says+-- whether this field is strict+-- See Note [Record evaluated-ness in worker/wrapper]+mk_ww_local uniq (ty,str)+ = setCaseBndrEvald str $+ mkSysLocalOrCoVar (fsLit "ww") uniq ty
+ typecheck/FamInst.hs view
@@ -0,0 +1,918 @@+-- The @FamInst@ type: family instance heads++{-# LANGUAGE CPP, GADTs #-}++module FamInst (+ FamInstEnvs, tcGetFamInstEnvs,+ checkFamInstConsistency, tcExtendLocalFamInstEnv,+ tcLookupDataFamInst, tcLookupDataFamInst_maybe,+ tcInstNewTyCon_maybe, tcTopNormaliseNewTypeTF_maybe,+ checkRecFamInstConsistency,+ newFamInst,++ -- * Injectivity+ makeInjectivityErrors, injTyVarsOfType, injTyVarsOfTypes+ ) where++import HscTypes+import FamInstEnv+import InstEnv( roughMatchTcs )+import Coercion+import TcEvidence+import LoadIface+import TcRnMonad+import SrcLoc+import TyCon+import TcType+import CoAxiom+import DynFlags+import Module+import Outputable+import Util+import RdrName+import DataCon ( dataConName )+import Maybes+import Type+import TyCoRep+import TcMType+import Name+import Pair+import Panic+import VarSet+import Bag( Bag, unionBags, unitBag )+import Control.Monad+import Unique+import NameEnv+import Data.Set (Set)+import qualified Data.Set as Set+import Data.List++#include "HsVersions.h"++{-++Note [The type family instance consistency story]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++To preserve type safety we must ensure that for any given module, all+the type family instances used either in that module or in any module+it directly or indirectly imports are consistent. For example, consider++ module F where+ type family F a++ module A where+ import F( F )+ type instance F Int = Bool+ f :: F Int -> Bool+ f x = x++ module B where+ import F( F )+ type instance F Int = Char+ g :: Char -> F Int+ g x = x++ module Bad where+ import A( f )+ import B( g )+ bad :: Char -> Int+ bad c = f (g c)++Even though module Bad never mentions the type family F at all, by+combining the functions f and g that were type checked in contradictory+type family instance environments, the function bad is able to coerce+from one type to another. So when we type check Bad we must verify that+the type family instances defined in module A are consistent with those+defined in module B.++How do we ensure that we maintain the necessary consistency?++* Call a module which defines at least one type family instance a+"family instance module". This flag `mi_finsts` is recorded in the+interface file.++* For every module we calculate the set of all of its direct and+indirect dependencies that are family instance modules. This list+`dep_finsts` is also recorded in the interface file so we can compute+this list for a module from the lists for its direct dependencies.++* When type checking a module M we check consistency of all the type+family instances that are either provided by its `dep_finsts` or+defined in the module M itself. This is a pairwise check, i.e., for+every pair of instances we must check that they are consistent.++- For family instances coming from `dep_finsts`, this is checked in+checkFamInstConsistency, called from tcRnImports, and in+checkRecFamInstConsistency, called from tcTyClGroup. See Note+[Checking family instance consistency] for details on this check (and+in particular how we avoid having to do all these checks for every+module we compile).++- That leaves checking the family instances defined in M itself+against instances defined in either M or its `dep_finsts`. This is+checked in `tcExtendLocalFamInstEnv'.++There are two subtle points in this scheme which have not been+addressed yet.++* We have checked consistency of the family instances *defined* by M+or its imports, but this is not by definition the same thing as the+family instances *used* by M or its imports. Specifically, we need to+ensure when we use a type family instance while compiling M that this+instance was really defined from either M or one of its imports,+rather than being an instance that we happened to know about from+reading an interface file in the course of compiling an unrelated+module. Otherwise, we'll end up with no record of the fact that M+depends on this family instance and type safety will be compromised.+See #13102.++* It can also happen that M uses a function defined in another module+which is not transitively imported by M. Examples include the+desugaring of various overloaded constructs, and references inserted+by Template Haskell splices. If that function's definition makes use+of type family instances which are not checked against those visible+from M, type safety can again be compromised. See #13251.++* When a module C imports a boot module B.hs-boot, we check that C's+type family instances are compatible with those visible from+B.hs-boot. However, C will eventually be linked against a different+module B.hs, which might define additional type family instances which+are inconsistent with C's. This can also lead to loss of type safety.+See #9562.++-}++{-+************************************************************************+* *+ Making a FamInst+* *+************************************************************************+-}++-- All type variables in a FamInst must be fresh. This function+-- creates the fresh variables and applies the necessary substitution+-- It is defined here to avoid a dependency from FamInstEnv on the monad+-- code.++newFamInst :: FamFlavor -> CoAxiom Unbranched -> TcRnIf gbl lcl FamInst+-- Freshen the type variables of the FamInst branches+-- Called from the vectoriser monad too, hence the rather general type+newFamInst flavor axiom@(CoAxiom { co_ax_tc = fam_tc })+ = ASSERT2( tyCoVarsOfTypes lhs `subVarSet` tcv_set, text "lhs" <+> pp_ax )+ ASSERT2( tyCoVarsOfType rhs `subVarSet` tcv_set, text "rhs" <+> pp_ax )+ ASSERT2( lhs_kind `eqType` rhs_kind, text "kind" <+> pp_ax $$ ppr lhs_kind $$ ppr rhs_kind )+ do { (subst, tvs') <- freshenTyVarBndrs tvs+ ; (subst, cvs') <- freshenCoVarBndrsX subst cvs+ ; return (FamInst { fi_fam = tyConName fam_tc+ , fi_flavor = flavor+ , fi_tcs = roughMatchTcs lhs+ , fi_tvs = tvs'+ , fi_cvs = cvs'+ , fi_tys = substTys subst lhs+ , fi_rhs = substTy subst rhs+ , fi_axiom = axiom }) }+ where+ lhs_kind = typeKind (mkTyConApp fam_tc lhs)+ rhs_kind = typeKind rhs+ tcv_set = mkVarSet (tvs ++ cvs)+ pp_ax = pprCoAxiom axiom+ CoAxBranch { cab_tvs = tvs+ , cab_cvs = cvs+ , cab_lhs = lhs+ , cab_rhs = rhs } = coAxiomSingleBranch axiom+++{-+************************************************************************+* *+ Optimised overlap checking for family instances+* *+************************************************************************++Note [Checking family instance consistency]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For any two family instance modules that we import directly or indirectly, we+check whether the instances in the two modules are consistent, *unless* we can+be certain that the instances of the two modules have already been checked for+consistency during the compilation of modules that we import.++Why do we need to check? Consider+ module X1 where module X2 where+ data T1 data T2+ type instance F T1 b = Int type instance F a T2 = Char+ f1 :: F T1 a -> Int f2 :: Char -> F a T2+ f1 x = x f2 x = x++Now if we import both X1 and X2 we could make (f2 . f1) :: Int -> Char.+Notice that neither instance is an orphan.++How do we know which pairs of modules have already been checked? For each+module M we directly import, we look up the family instance modules that M+imports (directly or indirectly), say F1, ..., FN. For any two modules+among M, F1, ..., FN, we know that the family instances defined in those+two modules are consistent--because we checked that when we compiled M.++For every other pair of family instance modules we import (directly or+indirectly), we check that they are consistent now. (So that we can be+certain that the modules in our `HscTypes.dep_finsts' are consistent.)++There is some fancy footwork regarding hs-boot module loops, see+Note [Don't check hs-boot type family instances too early]+-}++-- The optimisation of overlap tests is based on determining pairs of modules+-- whose family instances need to be checked for consistency.+--+data ModulePair = ModulePair Module Module+ -- Invariant: first Module < second Module+ -- use the smart constructor++-- | Smart constructor that establishes the invariant+modulePair :: Module -> Module -> ModulePair+modulePair a b+ | a < b = ModulePair a b+ | otherwise = ModulePair b a++instance Eq ModulePair where+ (ModulePair a1 b1) == (ModulePair a2 b2) = a1 == a2 && b1 == b2++instance Ord ModulePair where+ (ModulePair a1 b1) `compare` (ModulePair a2 b2) =+ nonDetCmpModule a1 a2 `thenCmp`+ nonDetCmpModule b1 b2+ -- See Note [ModulePairSet determinism and performance]++instance Outputable ModulePair where+ ppr (ModulePair m1 m2) = angleBrackets (ppr m1 <> comma <+> ppr m2)++-- Fast, nondeterministic comparison on Module. Don't use when the ordering+-- can change the ABI. See Note [ModulePairSet determinism and performance]+nonDetCmpModule :: Module -> Module -> Ordering+nonDetCmpModule a b =+ nonDetCmpUnique (getUnique $ moduleUnitId a) (getUnique $ moduleUnitId b)+ `thenCmp`+ nonDetCmpUnique (getUnique $ moduleName a) (getUnique $ moduleName b)++type ModulePairSet = Set ModulePair+{-+Note [ModulePairSet determinism and performance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The size of ModulePairSet is quadratic in the number of modules.+The Ord instance for Module uses string comparison which is linear in the+length of ModuleNames and UnitIds. This adds up to a significant cost, see+#12191.++To get reasonable performance ModulePairSet uses nondeterministic ordering+on Module based on Uniques. It doesn't affect the ABI, because it only+determines the order the modules are checked for family instance consistency.+See Note [Unique Determinism] in Unique+-}++listToSet :: [ModulePair] -> ModulePairSet+listToSet l = Set.fromList l++-- | Check family instance consistency, given:+--+-- 1. The list of all modules transitively imported by us+-- which define a family instance (these are the ones+-- we have to check for consistency), and+--+-- 2. The list of modules which we directly imported+-- (these specify the sets of family instance defining+-- modules which are already known to be consistent).+--+-- See Note [Checking family instance consistency] for more+-- details, and Note [The type family instance consistency story]+-- for the big picture.+--+-- This function doesn't check ALL instances for consistency,+-- only ones that aren't involved in recursive knot-tying+-- loops; see Note [Don't check hs-boot type family instances too early].+-- It returns a modified 'TcGblEnv' that has saved the+-- instances that need to be checked later; use 'checkRecFamInstConsistency'+-- to check those.+checkFamInstConsistency :: [Module] -> [Module] -> TcM TcGblEnv+checkFamInstConsistency famInstMods directlyImpMods+ = do { dflags <- getDynFlags+ ; (eps, hpt) <- getEpsAndHpt+ ; let { -- Fetch the iface of a given module. Must succeed as+ -- all directly imported modules must already have been loaded.+ modIface mod =+ case lookupIfaceByModule dflags hpt (eps_PIT eps) mod of+ Nothing -> panicDoc "FamInst.checkFamInstConsistency"+ (ppr mod $$ pprHPT hpt)+ Just iface -> iface++ -- Which modules were checked for consistency when we compiled+ -- `mod`? Itself and its dep_finsts.+ ; modConsistent mod = mod : (dep_finsts . mi_deps . modIface $ mod)++ ; hmiModule = mi_module . hm_iface+ ; hmiFamInstEnv = extendFamInstEnvList emptyFamInstEnv+ . md_fam_insts . hm_details+ ; hpt_fam_insts = mkModuleEnv [ (hmiModule hmi, hmiFamInstEnv hmi)+ | hmi <- eltsHpt hpt]+ ; groups = map modConsistent directlyImpMods+ ; okPairs = listToSet $ concatMap allPairs groups+ -- instances of okPairs are consistent+ ; criticalPairs = listToSet $ allPairs famInstMods+ -- all pairs that we need to consider+ ; toCheckPairs =+ Set.elems $ criticalPairs `Set.difference` okPairs+ -- the difference gives us the pairs we need to check now+ -- See Note [ModulePairSet determinism and performance]+ }++ ; pending_checks <- mapM (check hpt_fam_insts) toCheckPairs+ ; tcg_env <- getGblEnv+ ; return tcg_env { tcg_pending_fam_checks+ = foldl' (plusNameEnv_C (++)) emptyNameEnv pending_checks }+ }+ where+ allPairs [] = []+ allPairs (m:ms) = map (modulePair m) ms ++ allPairs ms++ check hpt_fam_insts (ModulePair m1 m2)+ = do { env1' <- getFamInsts hpt_fam_insts m1+ ; env2' <- getFamInsts hpt_fam_insts m2+ -- We're checking each element of env1 against env2.+ -- The cost of that is dominated by the size of env1, because+ -- for each instance in env1 we look it up in the type family+ -- environment env2, and lookup is cheap.+ -- The code below ensures that env1 is the smaller environment.+ ; let sizeE1 = famInstEnvSize env1'+ sizeE2 = famInstEnvSize env2'+ (env1, env2) = if sizeE1 < sizeE2 then (env1', env2')+ else (env2', env1')+ -- Note [Don't check hs-boot type family instances too early]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Family instance consistency checking involves checking that+ -- the family instances of our imported modules are consistent with+ -- one another; this might lead you to think that this process+ -- has nothing to do with the module we are about to typecheck.+ -- Not so! Consider the following case:+ --+ -- -- A.hs-boot+ -- type family F a+ --+ -- -- B.hs+ -- import {-# SOURCE #-} A+ -- type instance F Int = Bool+ --+ -- -- A.hs+ -- import B+ -- type family F a+ --+ -- When typechecking A, we are NOT allowed to poke the TyThing+ -- for for F until we have typechecked the family. Thus, we+ -- can't do consistency checking for the instance in B+ -- (checkFamInstConsistency is called during renaming).+ -- Failing to defer the consistency check lead to #11062.+ --+ -- Additionally, we should also defer consistency checking when+ -- type from the hs-boot file of the current module occurs on+ -- the left hand side, as we will poke its TyThing when checking+ -- for overlap.+ --+ -- -- F.hs+ -- type family F a+ --+ -- -- A.hs-boot+ -- import F+ -- data T+ --+ -- -- B.hs+ -- import {-# SOURCE #-} A+ -- import F+ -- type instance F T = Int+ --+ -- -- A.hs+ -- import B+ -- data T = MkT+ --+ -- However, this is not yet done; see #13981.+ --+ -- Note that it is NOT necessary to defer for occurrences in the+ -- RHS (e.g., type instance F Int = T, in the above example),+ -- since that never participates in consistency checking+ -- in any nontrivial way.+ --+ -- Why don't we defer ALL of the checks to later? Well, many+ -- instances aren't involved in the recursive loop at all. So+ -- we might as well check them immediately; and there isn't+ -- a good time to check them later in any case: every time+ -- we finish kind-checking a type declaration and add it to+ -- a context, we *then* consistency check all of the instances+ -- which mentioned that type. We DO want to check instances+ -- as quickly as possible, so that we aren't typechecking+ -- values with inconsistent axioms in scope.+ --+ -- See also Note [Tying the knot] and Note [Type-checking inside the knot]+ -- for why we are doing this at all.+ ; this_mod <- getModule+ -- NB: == this_mod only holds if there's an hs-boot file;+ -- otherwise we cannot possible see instances for families+ -- defined by the module we are compiling in imports.+ ; let shouldCheckNow = ((/= this_mod) . nameModule . fi_fam)+ (check_now, check_later) =+ partition shouldCheckNow (famInstEnvElts env1)+ ; mapM_ (checkForConflicts (emptyFamInstEnv, env2)) check_now+ ; mapM_ (checkForInjectivityConflicts (emptyFamInstEnv,env2)) check_now+ ; let check_later_map =+ extendNameEnvList_C (++) emptyNameEnv+ [(fi_fam finst, [finst]) | finst <- check_later]+ ; return (mapNameEnv (\xs -> [(xs, env2)]) check_later_map)+ }++-- | Given a 'TyCon' that has been incorporated into the type+-- environment (the knot is tied), if it is a type family, check+-- that all deferred instances for it are consistent.+-- See Note [Don't check hs-boot type family instances too early]+checkRecFamInstConsistency :: TyCon -> TcM ()+checkRecFamInstConsistency tc = do+ tcg_env <- getGblEnv+ let checkConsistency tc+ | isFamilyTyCon tc+ , Just pairs <- lookupNameEnv (tcg_pending_fam_checks tcg_env)+ (tyConName tc)+ = forM_ pairs $ \(check_now, env2) -> do+ mapM_ (checkForConflicts (emptyFamInstEnv, env2)) check_now+ mapM_ (checkForInjectivityConflicts (emptyFamInstEnv,env2)) check_now+ | otherwise+ = return ()+ checkConsistency tc+++getFamInsts :: ModuleEnv FamInstEnv -> Module -> TcM FamInstEnv+getFamInsts hpt_fam_insts mod+ | Just env <- lookupModuleEnv hpt_fam_insts mod = return env+ | otherwise = do { _ <- initIfaceTcRn (loadSysInterface doc mod)+ ; eps <- getEps+ ; return (expectJust "checkFamInstConsistency" $+ lookupModuleEnv (eps_mod_fam_inst_env eps) mod) }+ where+ doc = ppr mod <+> text "is a family-instance module"++{-+************************************************************************+* *+ Lookup+* *+************************************************************************++-}++-- | If @co :: T ts ~ rep_ty@ then:+--+-- > instNewTyCon_maybe T ts = Just (rep_ty, co)+--+-- Checks for a newtype, and for being saturated+-- Just like Coercion.instNewTyCon_maybe, but returns a TcCoercion+tcInstNewTyCon_maybe :: TyCon -> [TcType] -> Maybe (TcType, TcCoercion)+tcInstNewTyCon_maybe = instNewTyCon_maybe++-- | Like 'tcLookupDataFamInst_maybe', but returns the arguments back if+-- there is no data family to unwrap.+-- Returns a Representational coercion+tcLookupDataFamInst :: FamInstEnvs -> TyCon -> [TcType]+ -> (TyCon, [TcType], Coercion)+tcLookupDataFamInst fam_inst_envs tc tc_args+ | Just (rep_tc, rep_args, co)+ <- tcLookupDataFamInst_maybe fam_inst_envs tc tc_args+ = (rep_tc, rep_args, co)+ | otherwise+ = (tc, tc_args, mkRepReflCo (mkTyConApp tc tc_args))++tcLookupDataFamInst_maybe :: FamInstEnvs -> TyCon -> [TcType]+ -> Maybe (TyCon, [TcType], Coercion)+-- ^ Converts a data family type (eg F [a]) to its representation type (eg FList a)+-- and returns a coercion between the two: co :: F [a] ~R FList a.+tcLookupDataFamInst_maybe fam_inst_envs tc tc_args+ | isDataFamilyTyCon tc+ , match : _ <- lookupFamInstEnv fam_inst_envs tc tc_args+ , FamInstMatch { fim_instance = rep_fam@(FamInst { fi_axiom = ax+ , fi_cvs = cvs })+ , fim_tys = rep_args+ , fim_cos = rep_cos } <- match+ , let rep_tc = dataFamInstRepTyCon rep_fam+ co = mkUnbranchedAxInstCo Representational ax rep_args+ (mkCoVarCos cvs)+ = ASSERT( null rep_cos ) -- See Note [Constrained family instances] in FamInstEnv+ Just (rep_tc, rep_args, co)++ | otherwise+ = Nothing++-- | 'tcTopNormaliseNewTypeTF_maybe' gets rid of top-level newtypes,+-- potentially looking through newtype /instances/.+--+-- It is only used by the type inference engine (specifically, when+-- solving representational equality), and hence it is careful to unwrap+-- only if the relevant data constructor is in scope. That's why+-- it get a GlobalRdrEnv argument.+--+-- It is careful not to unwrap data/newtype instances if it can't+-- continue unwrapping. Such care is necessary for proper error+-- messages.+--+-- It does not look through type families.+-- It does not normalise arguments to a tycon.+--+-- If the result is Just (rep_ty, (co, gres), rep_ty), then+-- co : ty ~R rep_ty+-- gres are the GREs for the data constructors that+-- had to be in scope+tcTopNormaliseNewTypeTF_maybe :: FamInstEnvs+ -> GlobalRdrEnv+ -> Type+ -> Maybe ((Bag GlobalRdrElt, TcCoercion), Type)+tcTopNormaliseNewTypeTF_maybe faminsts rdr_env ty+-- cf. FamInstEnv.topNormaliseType_maybe and Coercion.topNormaliseNewType_maybe+ = topNormaliseTypeX stepper plus ty+ where+ plus :: (Bag GlobalRdrElt, TcCoercion) -> (Bag GlobalRdrElt, TcCoercion)+ -> (Bag GlobalRdrElt, TcCoercion)+ plus (gres1, co1) (gres2, co2) = ( gres1 `unionBags` gres2+ , co1 `mkTransCo` co2 )++ stepper :: NormaliseStepper (Bag GlobalRdrElt, TcCoercion)+ stepper = unwrap_newtype `composeSteppers` unwrap_newtype_instance++ -- For newtype instances we take a double step or nothing, so that+ -- we don't return the representation type of the newtype instance,+ -- which would lead to terrible error messages+ unwrap_newtype_instance rec_nts tc tys+ | Just (tc', tys', co) <- tcLookupDataFamInst_maybe faminsts tc tys+ = mapStepResult (\(gres, co1) -> (gres, co `mkTransCo` co1)) $+ unwrap_newtype rec_nts tc' tys'+ | otherwise = NS_Done++ unwrap_newtype rec_nts tc tys+ | Just con <- newTyConDataCon_maybe tc+ , Just gre <- lookupGRE_Name rdr_env (dataConName con)+ -- This is where we check that the+ -- data constructor is in scope+ = mapStepResult (\co -> (unitBag gre, co)) $+ unwrapNewTypeStepper rec_nts tc tys++ | otherwise+ = NS_Done++{-+************************************************************************+* *+ Extending the family instance environment+* *+************************************************************************+-}++-- Add new locally-defined family instances, checking consistency with+-- previous locally-defined family instances as well as all instances+-- available from imported modules. This requires loading all of our+-- imports that define family instances (if we haven't loaded them already).+tcExtendLocalFamInstEnv :: [FamInst] -> TcM a -> TcM a++-- If we weren't actually given any instances to add, then we don't want+-- to go to the bother of loading family instance module dependencies.+tcExtendLocalFamInstEnv [] thing_inside = thing_inside++-- Otherwise proceed...+tcExtendLocalFamInstEnv fam_insts thing_inside+ = do { env <- getGblEnv+ ; let this_mod = tcg_mod env+ imports = tcg_imports env++ -- Optimization: If we're only defining type family instances+ -- for type families *defined in the home package*, then we+ -- only have to load interface files that belong to the home+ -- package. The reason is that there's no recursion between+ -- packages, so modules in other packages can't possibly define+ -- instances for our type families.+ --+ -- (Within the home package, we could import a module M that+ -- imports us via an hs-boot file, and thereby defines an+ -- instance of a type family defined in this module. So we can't+ -- apply the same logic to avoid reading any interface files at+ -- all, when we define an instances for type family defined in+ -- the current module.)+ home_fams_only = all (nameIsHomePackage this_mod . fi_fam) fam_insts+ want_module mod+ | mod == this_mod = False+ | home_fams_only = moduleUnitId mod == moduleUnitId this_mod+ | otherwise = True+ ; loadModuleInterfaces (text "Loading family-instance modules")+ (filter want_module (imp_finsts imports))+ ; (inst_env', fam_insts') <- foldlM addLocalFamInst+ (tcg_fam_inst_env env, tcg_fam_insts env)+ fam_insts+ ; let env' = env { tcg_fam_insts = fam_insts'+ , tcg_fam_inst_env = inst_env' }+ ; setGblEnv env' thing_inside+ }++-- Check that the proposed new instance is OK,+-- and then add it to the home inst env+-- This must be lazy in the fam_inst arguments, see Note [Lazy axiom match]+-- in FamInstEnv.hs+addLocalFamInst :: (FamInstEnv,[FamInst])+ -> FamInst+ -> TcM (FamInstEnv, [FamInst])+addLocalFamInst (home_fie, my_fis) fam_inst+ -- home_fie includes home package and this module+ -- my_fies is just the ones from this module+ = do { traceTc "addLocalFamInst" (ppr fam_inst)++ -- Unlike the case of class instances, don't override existing+ -- instances in GHCi; it's unsound. See #7102.++ ; mod <- getModule+ ; traceTc "alfi" (ppr mod)++ -- Fetch imported instances, so that we report+ -- overlaps correctly.+ -- Really we ought to only check consistency with+ -- those instances which are transitively imported+ -- by the current module, rather than every instance+ -- we've ever seen. Fixing this is part of #13102.+ ; eps <- getEps+ ; let inst_envs = (eps_fam_inst_env eps, home_fie)+ home_fie' = extendFamInstEnv home_fie fam_inst++ -- Check for conflicting instance decls and injectivity violations+ ; no_conflict <- checkForConflicts inst_envs fam_inst+ ; injectivity_ok <- checkForInjectivityConflicts inst_envs fam_inst++ ; if no_conflict && injectivity_ok then+ return (home_fie', fam_inst : my_fis)+ else+ return (home_fie, my_fis) }++{-+************************************************************************+* *+ Checking an instance against conflicts with an instance env+* *+************************************************************************++Check whether a single family instance conflicts with those in two instance+environments (one for the EPS and one for the HPT).+-}++checkForConflicts :: FamInstEnvs -> FamInst -> TcM Bool+checkForConflicts inst_envs fam_inst+ = do { let conflicts = lookupFamInstEnvConflicts inst_envs fam_inst+ no_conflicts = null conflicts+ ; traceTc "checkForConflicts" $+ vcat [ ppr (map fim_instance conflicts)+ , ppr fam_inst+ -- , ppr inst_envs+ ]+ ; unless no_conflicts $ conflictInstErr fam_inst conflicts+ ; return no_conflicts }++-- | Check whether a new open type family equation can be added without+-- violating injectivity annotation supplied by the user. Returns True when+-- this is possible and False if adding this equation would violate injectivity+-- annotation.+checkForInjectivityConflicts :: FamInstEnvs -> FamInst -> TcM Bool+checkForInjectivityConflicts instEnvs famInst+ | isTypeFamilyTyCon tycon+ -- type family is injective in at least one argument+ , Injective inj <- familyTyConInjectivityInfo tycon = do+ { let axiom = coAxiomSingleBranch fi_ax+ conflicts = lookupFamInstEnvInjectivityConflicts inj instEnvs famInst+ -- see Note [Verifying injectivity annotation] in FamInstEnv+ errs = makeInjectivityErrors fi_ax axiom inj conflicts+ ; mapM_ (\(err, span) -> setSrcSpan span $ addErr err) errs+ ; return (null errs)+ }++ -- if there was no injectivity annotation or tycon does not represent a+ -- type family we report no conflicts+ | otherwise = return True+ where tycon = famInstTyCon famInst+ fi_ax = fi_axiom famInst++-- | Build a list of injectivity errors together with their source locations.+makeInjectivityErrors+ :: CoAxiom br -- ^ Type family for which we generate errors+ -> CoAxBranch -- ^ Currently checked equation (represented by axiom)+ -> [Bool] -- ^ Injectivity annotation+ -> [CoAxBranch] -- ^ List of injectivity conflicts+ -> [(SDoc, SrcSpan)]+makeInjectivityErrors fi_ax axiom inj conflicts+ = ASSERT2( any id inj, text "No injective type variables" )+ let lhs = coAxBranchLHS axiom+ rhs = coAxBranchRHS axiom++ are_conflicts = not $ null conflicts+ unused_inj_tvs = unusedInjTvsInRHS (coAxiomTyCon fi_ax) inj lhs rhs+ inj_tvs_unused = not $ and (isEmptyVarSet <$> unused_inj_tvs)+ tf_headed = isTFHeaded rhs+ bare_variables = bareTvInRHSViolated lhs rhs+ wrong_bare_rhs = not $ null bare_variables++ err_builder herald eqns+ = ( hang herald+ 2 (vcat (map (pprCoAxBranch fi_ax) eqns))+ , coAxBranchSpan (head eqns) )+ errorIf p f = if p then [f err_builder axiom] else []+ in errorIf are_conflicts (conflictInjInstErr conflicts )+ ++ errorIf inj_tvs_unused (unusedInjectiveVarsErr unused_inj_tvs)+ ++ errorIf tf_headed tfHeadedErr+ ++ errorIf wrong_bare_rhs (bareVariableInRHSErr bare_variables)+++-- | Return a list of type variables that the function is injective in and that+-- do not appear on injective positions in the RHS of a family instance+-- declaration. The returned Pair includes invisible vars followed by visible ones+unusedInjTvsInRHS :: TyCon -> [Bool] -> [Type] -> Type -> Pair TyVarSet+-- INVARIANT: [Bool] list contains at least one True value+-- See Note [Verifying injectivity annotation]. This function implements fourth+-- check described there.+-- In theory, instead of implementing this whole check in this way, we could+-- attempt to unify equation with itself. We would reject exactly the same+-- equations but this method gives us more precise error messages by returning+-- precise names of variables that are not mentioned in the RHS.+unusedInjTvsInRHS tycon injList lhs rhs =+ (`minusVarSet` injRhsVars) <$> injLHSVars+ where+ -- set of type and kind variables in which type family is injective+ (invis_pairs, vis_pairs)+ = partitionInvisibles tycon snd (zipEqual "unusedInjTvsInRHS" injList lhs)+ invis_lhs = uncurry filterByList $ unzip invis_pairs+ vis_lhs = uncurry filterByList $ unzip vis_pairs++ invis_vars = tyCoVarsOfTypes invis_lhs+ Pair invis_vars' vis_vars = splitVisVarsOfTypes vis_lhs+ injLHSVars+ = Pair (invis_vars `minusVarSet` vis_vars `unionVarSet` invis_vars')+ vis_vars++ -- set of type variables appearing in the RHS on an injective position.+ -- For all returned variables we assume their associated kind variables+ -- also appear in the RHS.+ injRhsVars = injTyVarsOfType rhs++injTyVarsOfType :: TcTauType -> TcTyVarSet+-- Collect all type variables that are either arguments to a type+-- constructor or to /injective/ type families.+-- Determining the overall type determines thes variables+--+-- E.g. Suppose F is injective in its second arg, but not its first+-- then injVarOfType (Either a (F [b] (a,c))) = {a,c}+-- Determining the overall type determines a,c but not b.+injTyVarsOfType (TyVarTy v)+ = unitVarSet v `unionVarSet` injTyVarsOfType (tyVarKind v)+injTyVarsOfType (TyConApp tc tys)+ | isTypeFamilyTyCon tc+ = case familyTyConInjectivityInfo tc of+ NotInjective -> emptyVarSet+ Injective inj -> injTyVarsOfTypes (filterByList inj tys)+ | otherwise+ = injTyVarsOfTypes tys+injTyVarsOfType (LitTy {})+ = emptyVarSet+injTyVarsOfType (FunTy arg res)+ = injTyVarsOfType arg `unionVarSet` injTyVarsOfType res+injTyVarsOfType (AppTy fun arg)+ = injTyVarsOfType fun `unionVarSet` injTyVarsOfType arg+-- No forall types in the RHS of a type family+injTyVarsOfType (CastTy ty _) = injTyVarsOfType ty+injTyVarsOfType (CoercionTy {}) = emptyVarSet+injTyVarsOfType (ForAllTy {}) =+ panic "unusedInjTvsInRHS.injTyVarsOfType"++injTyVarsOfTypes :: [Type] -> VarSet+injTyVarsOfTypes tys = mapUnionVarSet injTyVarsOfType tys++-- | Is type headed by a type family application?+isTFHeaded :: Type -> Bool+-- See Note [Verifying injectivity annotation]. This function implements third+-- check described there.+isTFHeaded ty | Just ty' <- coreView ty+ = isTFHeaded ty'+isTFHeaded ty | (TyConApp tc args) <- ty+ , isTypeFamilyTyCon tc+ = tyConArity tc == length args+isTFHeaded _ = False+++-- | If a RHS is a bare type variable return a set of LHS patterns that are not+-- bare type variables.+bareTvInRHSViolated :: [Type] -> Type -> [Type]+-- See Note [Verifying injectivity annotation]. This function implements second+-- check described there.+bareTvInRHSViolated pats rhs | isTyVarTy rhs+ = filter (not . isTyVarTy) pats+bareTvInRHSViolated _ _ = []+++conflictInstErr :: FamInst -> [FamInstMatch] -> TcRn ()+conflictInstErr fam_inst conflictingMatch+ | (FamInstMatch { fim_instance = confInst }) : _ <- conflictingMatch+ = let (err, span) = makeFamInstsErr+ (text "Conflicting family instance declarations:")+ [fam_inst, confInst]+ in setSrcSpan span $ addErr err+ | otherwise+ = panic "conflictInstErr"++-- | Type of functions that use error message and a list of axioms to build full+-- error message (with a source location) for injective type families.+type InjErrorBuilder = SDoc -> [CoAxBranch] -> (SDoc, SrcSpan)++-- | Build injecivity error herald common to all injectivity errors.+injectivityErrorHerald :: Bool -> SDoc+injectivityErrorHerald isSingular =+ text "Type family equation" <> s isSingular <+> text "violate" <>+ s (not isSingular) <+> text "injectivity annotation" <>+ if isSingular then dot else colon+ -- Above is an ugly hack. We want this: "sentence. herald:" (note the dot and+ -- colon). But if herald is empty we want "sentence:" (note the colon). We+ -- can't test herald for emptiness so we rely on the fact that herald is empty+ -- only when isSingular is False. If herald is non empty it must end with a+ -- colon.+ where+ s False = text "s"+ s True = empty++-- | Build error message for a pair of equations violating an injectivity+-- annotation.+conflictInjInstErr :: [CoAxBranch] -> InjErrorBuilder -> CoAxBranch+ -> (SDoc, SrcSpan)+conflictInjInstErr conflictingEqns errorBuilder tyfamEqn+ | confEqn : _ <- conflictingEqns+ = errorBuilder (injectivityErrorHerald False) [confEqn, tyfamEqn]+ | otherwise+ = panic "conflictInjInstErr"++-- | Build error message for equation with injective type variables unused in+-- the RHS.+unusedInjectiveVarsErr :: Pair TyVarSet -> InjErrorBuilder -> CoAxBranch+ -> (SDoc, SrcSpan)+unusedInjectiveVarsErr (Pair invis_vars vis_vars) errorBuilder tyfamEqn+ = errorBuilder (injectivityErrorHerald True $$ msg)+ [tyfamEqn]+ where+ tvs = invis_vars `unionVarSet` vis_vars+ has_types = not $ isEmptyVarSet vis_vars+ has_kinds = not $ isEmptyVarSet invis_vars++ doc = sep [ what <+> text "variable" <>+ pluralVarSet tvs <+> pprVarSet tvs (pprQuotedList . toposortTyVars)+ , text "cannot be inferred from the right-hand side." ]+ what = case (has_types, has_kinds) of+ (True, True) -> text "Type and kind"+ (True, False) -> text "Type"+ (False, True) -> text "Kind"+ (False, False) -> pprPanic "mkUnusedInjectiveVarsErr" $ ppr tvs+ print_kinds_info = ppWhen has_kinds ppSuggestExplicitKinds+ msg = doc $$ print_kinds_info $$+ text "In the type family equation:"++-- | Build error message for equation that has a type family call at the top+-- level of RHS+tfHeadedErr :: InjErrorBuilder -> CoAxBranch+ -> (SDoc, SrcSpan)+tfHeadedErr errorBuilder famInst+ = errorBuilder (injectivityErrorHerald True $$+ text "RHS of injective type family equation cannot" <+>+ text "be a type family:") [famInst]++-- | Build error message for equation that has a bare type variable in the RHS+-- but LHS pattern is not a bare type variable.+bareVariableInRHSErr :: [Type] -> InjErrorBuilder -> CoAxBranch+ -> (SDoc, SrcSpan)+bareVariableInRHSErr tys errorBuilder famInst+ = errorBuilder (injectivityErrorHerald True $$+ text "RHS of injective type family equation is a bare" <+>+ text "type variable" $$+ text "but these LHS type and kind patterns are not bare" <+>+ text "variables:" <+> pprQuotedList tys) [famInst]+++makeFamInstsErr :: SDoc -> [FamInst] -> (SDoc, SrcSpan)+makeFamInstsErr herald insts+ = ASSERT( not (null insts) )+ ( hang herald+ 2 (vcat [ pprCoAxBranchHdr (famInstAxiom fi) 0+ | fi <- sorted ])+ , srcSpan )+ where+ getSpan = getSrcLoc . famInstAxiom+ sorted = sortWith getSpan insts+ fi1 = head sorted+ srcSpan = coAxBranchSpan (coAxiomSingleBranch (famInstAxiom fi1))+ -- The sortWith just arranges that instances are dislayed in order+ -- of source location, which reduced wobbling in error messages,+ -- and is better for users++tcGetFamInstEnvs :: TcM FamInstEnvs+-- Gets both the external-package inst-env+-- and the home-pkg inst env (includes module being compiled)+tcGetFamInstEnvs+ = do { eps <- getEps; env <- getGblEnv+ ; return (eps_fam_inst_env eps, tcg_fam_inst_env env) }
+ typecheck/FunDeps.hs view
@@ -0,0 +1,666 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 2000+++FunDeps - functional dependencies++It's better to read it as: "if we know these, then we're going to know these"+-}++{-# LANGUAGE CPP #-}++module FunDeps (+ FunDepEqn(..), pprEquation,+ improveFromInstEnv, improveFromAnother,+ checkInstCoverage, checkFunDeps,+ pprFundeps+ ) where++#include "HsVersions.h"++import Name+import Var+import Class+import Type+import TcType( transSuperClasses )+import CoAxiom( TypeEqn )+import Unify+import FamInst( injTyVarsOfTypes )+import InstEnv+import VarSet+import VarEnv+import Outputable+import ErrUtils( Validity(..), allValid )+import SrcLoc+import Util++import Pair ( Pair(..) )+import Data.List ( nubBy )+import Data.Maybe+import Data.Foldable ( fold )++{-+************************************************************************+* *+\subsection{Generate equations from functional dependencies}+* *+************************************************************************+++Each functional dependency with one variable in the RHS is responsible+for generating a single equality. For instance:+ class C a b | a -> b+The constraints ([Wanted] C Int Bool) and [Wanted] C Int alpha+will generate the following FunDepEqn+ FDEqn { fd_qtvs = []+ , fd_eqs = [Pair Bool alpha]+ , fd_pred1 = C Int Bool+ , fd_pred2 = C Int alpha+ , fd_loc = ... }+However notice that a functional dependency may have more than one variable+in the RHS which will create more than one pair of types in fd_eqs. Example:+ class C a b c | a -> b c+ [Wanted] C Int alpha alpha+ [Wanted] C Int Bool beta+Will generate:+ FDEqn { fd_qtvs = []+ , fd_eqs = [Pair Bool alpha, Pair alpha beta]+ , fd_pred1 = C Int Bool+ , fd_pred2 = C Int alpha+ , fd_loc = ... }++INVARIANT: Corresponding types aren't already equal+That is, there exists at least one non-identity equality in FDEqs.++Assume:+ class C a b c | a -> b c+ instance C Int x x+And: [Wanted] C Int Bool alpha+We will /match/ the LHS of fundep equations, producing a matching substitution+and create equations for the RHS sides. In our last example we'd have generated:+ ({x}, [fd1,fd2])+where+ fd1 = FDEq 1 Bool x+ fd2 = FDEq 2 alpha x+To ``execute'' the equation, make fresh type variable for each tyvar in the set,+instantiate the two types with these fresh variables, and then unify or generate+a new constraint. In the above example we would generate a new unification+variable 'beta' for x and produce the following constraints:+ [Wanted] (Bool ~ beta)+ [Wanted] (alpha ~ beta)++Notice the subtle difference between the above class declaration and:+ class C a b c | a -> b, a -> c+where we would generate:+ ({x},[fd1]),({x},[fd2])+This means that the template variable would be instantiated to different+unification variables when producing the FD constraints.++Finally, the position parameters will help us rewrite the wanted constraint ``on the spot''+-}++data FunDepEqn loc+ = FDEqn { fd_qtvs :: [TyVar] -- Instantiate these type and kind vars+ -- to fresh unification vars,+ -- Non-empty only for FunDepEqns arising from instance decls++ , fd_eqs :: [TypeEqn] -- Make these pairs of types equal+ , fd_pred1 :: PredType -- The FunDepEqn arose from+ , fd_pred2 :: PredType -- combining these two constraints+ , fd_loc :: loc }++{-+Given a bunch of predicates that must hold, such as++ C Int t1, C Int t2, C Bool t3, ?x::t4, ?x::t5++improve figures out what extra equations must hold.+For example, if we have++ class C a b | a->b where ...++then improve will return++ [(t1,t2), (t4,t5)]++NOTA BENE:++ * improve does not iterate. It's possible that when we make+ t1=t2, for example, that will in turn trigger a new equation.+ This would happen if we also had+ C t1 t7, C t2 t8+ If t1=t2, we also get t7=t8.++ improve does *not* do this extra step. It relies on the caller+ doing so.++ * The equations unify types that are not already equal. So there+ is no effect iff the result of improve is empty+-}++instFD :: FunDep TyVar -> [TyVar] -> [Type] -> FunDep Type+-- (instFD fd tvs tys) returns fd instantiated with (tvs -> tys)+instFD (ls,rs) tvs tys+ = (map lookup ls, map lookup rs)+ where+ env = zipVarEnv tvs tys+ lookup tv = lookupVarEnv_NF env tv++zipAndComputeFDEqs :: (Type -> Type -> Bool) -- Discard this FDEq if true+ -> [Type] -> [Type]+ -> [TypeEqn]+-- Create a list of (Type,Type) pairs from two lists of types,+-- making sure that the types are not already equal+zipAndComputeFDEqs discard (ty1:tys1) (ty2:tys2)+ | discard ty1 ty2 = zipAndComputeFDEqs discard tys1 tys2+ | otherwise = Pair ty1 ty2 : zipAndComputeFDEqs discard tys1 tys2+zipAndComputeFDEqs _ _ _ = []++-- Improve a class constraint from another class constraint+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+improveFromAnother :: loc+ -> PredType -- Template item (usually given, or inert)+ -> PredType -- Workitem [that can be improved]+ -> [FunDepEqn loc]+-- Post: FDEqs always oriented from the other to the workitem+-- Equations have empty quantified variables+improveFromAnother loc pred1 pred2+ | Just (cls1, tys1) <- getClassPredTys_maybe pred1+ , Just (cls2, tys2) <- getClassPredTys_maybe pred2+ , cls1 == cls2+ = [ FDEqn { fd_qtvs = [], fd_eqs = eqs, fd_pred1 = pred1, fd_pred2 = pred2, fd_loc = loc }+ | let (cls_tvs, cls_fds) = classTvsFds cls1+ , fd <- cls_fds+ , let (ltys1, rs1) = instFD fd cls_tvs tys1+ (ltys2, rs2) = instFD fd cls_tvs tys2+ , eqTypes ltys1 ltys2 -- The LHSs match+ , let eqs = zipAndComputeFDEqs eqType rs1 rs2+ , not (null eqs) ]++improveFromAnother _ _ _ = []+++-- Improve a class constraint from instance declarations+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++instance Outputable (FunDepEqn a) where+ ppr = pprEquation++pprEquation :: FunDepEqn a -> SDoc+pprEquation (FDEqn { fd_qtvs = qtvs, fd_eqs = pairs })+ = vcat [text "forall" <+> braces (pprWithCommas ppr qtvs),+ nest 2 (vcat [ ppr t1 <+> text "~" <+> ppr t2+ | Pair t1 t2 <- pairs])]++improveFromInstEnv :: InstEnvs+ -> (PredType -> SrcSpan -> loc)+ -> PredType+ -> [FunDepEqn loc] -- Needs to be a FunDepEqn because+ -- of quantified variables+-- Post: Equations oriented from the template (matching instance) to the workitem!+improveFromInstEnv inst_env mk_loc pred+ | Just (cls, tys) <- ASSERT2( isClassPred pred, ppr pred )+ getClassPredTys_maybe pred+ , let (cls_tvs, cls_fds) = classTvsFds cls+ instances = classInstances inst_env cls+ rough_tcs = roughMatchTcs tys+ = [ FDEqn { fd_qtvs = meta_tvs, fd_eqs = eqs+ , fd_pred1 = p_inst, fd_pred2 = pred+ , fd_loc = mk_loc p_inst (getSrcSpan (is_dfun ispec)) }+ | fd <- cls_fds -- Iterate through the fundeps first,+ -- because there often are none!+ , let trimmed_tcs = trimRoughMatchTcs cls_tvs fd rough_tcs+ -- Trim the rough_tcs based on the head of the fundep.+ -- Remember that instanceCantMatch treats both arguments+ -- symmetrically, so it's ok to trim the rough_tcs,+ -- rather than trimming each inst_tcs in turn+ , ispec <- instances+ , (meta_tvs, eqs) <- improveClsFD cls_tvs fd ispec+ tys trimmed_tcs -- NB: orientation+ , let p_inst = mkClassPred cls (is_tys ispec)+ ]+improveFromInstEnv _ _ _ = []+++improveClsFD :: [TyVar] -> FunDep TyVar -- One functional dependency from the class+ -> ClsInst -- An instance template+ -> [Type] -> [Maybe Name] -- Arguments of this (C tys) predicate+ -> [([TyCoVar], [TypeEqn])] -- Empty or singleton++improveClsFD clas_tvs fd+ (ClsInst { is_tvs = qtvs, is_tys = tys_inst, is_tcs = rough_tcs_inst })+ tys_actual rough_tcs_actual++-- Compare instance {a,b} C sx sp sy sq+-- with wanted [W] C tx tp ty tq+-- for fundep (x,y -> p,q) from class (C x p y q)+-- If (sx,sy) unifies with (tx,ty), take the subst S++-- 'qtvs' are the quantified type variables, the ones which an be instantiated+-- to make the types match. For example, given+-- class C a b | a->b where ...+-- instance C (Maybe x) (Tree x) where ..+--+-- and a wanted constraint of form (C (Maybe t1) t2),+-- then we will call checkClsFD with+--+-- is_qtvs = {x}, is_tys = [Maybe x, Tree x]+-- tys_actual = [Maybe t1, t2]+--+-- We can instantiate x to t1, and then we want to force+-- (Tree x) [t1/x] ~ t2++ | instanceCantMatch rough_tcs_inst rough_tcs_actual+ = [] -- Filter out ones that can't possibly match,++ | otherwise+ = ASSERT2( length tys_inst == length tys_actual &&+ length tys_inst == length clas_tvs+ , ppr tys_inst <+> ppr tys_actual )++ case tcMatchTyKis ltys1 ltys2 of+ Nothing -> []+ Just subst | isJust (tcMatchTyKisX subst rtys1 rtys2)+ -- Don't include any equations that already hold.+ -- Reason: then we know if any actual improvement has happened,+ -- in which case we need to iterate the solver+ -- In making this check we must taking account of the fact that any+ -- qtvs that aren't already instantiated can be instantiated to anything+ -- at all+ -- NB: We can't do this 'is-useful-equation' check element-wise+ -- because of:+ -- class C a b c | a -> b c+ -- instance C Int x x+ -- [Wanted] C Int alpha Int+ -- We would get that x -> alpha (isJust) and x -> Int (isJust)+ -- so we would produce no FDs, which is clearly wrong.+ -> []++ | null fdeqs+ -> []++ | otherwise+ -> [(meta_tvs, fdeqs)]+ -- We could avoid this substTy stuff by producing the eqn+ -- (qtvs, ls1++rs1, ls2++rs2)+ -- which will re-do the ls1/ls2 unification when the equation is+ -- executed. What we're doing instead is recording the partial+ -- work of the ls1/ls2 unification leaving a smaller unification problem+ where+ rtys1' = map (substTyUnchecked subst) rtys1++ fdeqs = zipAndComputeFDEqs (\_ _ -> False) rtys1' rtys2+ -- Don't discard anything!+ -- We could discard equal types but it's an overkill to call+ -- eqType again, since we know for sure that /at least one/+ -- equation in there is useful)++ meta_tvs = [ setVarType tv (substTyUnchecked subst (varType tv))+ | tv <- qtvs, tv `notElemTCvSubst` subst ]+ -- meta_tvs are the quantified type variables+ -- that have not been substituted out+ --+ -- Eg. class C a b | a -> b+ -- instance C Int [y]+ -- Given constraint C Int z+ -- we generate the equation+ -- ({y}, [y], z)+ --+ -- But note (a) we get them from the dfun_id, so they are *in order*+ -- because the kind variables may be mentioned in the+ -- type variabes' kinds+ -- (b) we must apply 'subst' to the kinds, in case we have+ -- matched out a kind variable, but not a type variable+ -- whose kind mentions that kind variable!+ -- Trac #6015, #6068+ where+ (ltys1, rtys1) = instFD fd clas_tvs tys_inst+ (ltys2, rtys2) = instFD fd clas_tvs tys_actual++{-+%************************************************************************+%* *+ The Coverage condition for instance declarations+* *+************************************************************************++Note [Coverage condition]+~~~~~~~~~~~~~~~~~~~~~~~~~+Example+ class C a b | a -> b+ instance theta => C t1 t2++For the coverage condition, we check+ (normal) fv(t2) `subset` fv(t1)+ (liberal) fv(t2) `subset` oclose(fv(t1), theta)++The liberal version ensures the self-consistency of the instance, but+it does not guarantee termination. Example:++ class Mul a b c | a b -> c where+ (.*.) :: a -> b -> c++ instance Mul Int Int Int where (.*.) = (*)+ instance Mul Int Float Float where x .*. y = fromIntegral x * y+ instance Mul a b c => Mul a [b] [c] where x .*. v = map (x.*.) v++In the third instance, it's not the case that fv([c]) `subset` fv(a,[b]).+But it is the case that fv([c]) `subset` oclose( theta, fv(a,[b]) )++But it is a mistake to accept the instance because then this defn:+ f = \ b x y -> if b then x .*. [y] else y+makes instance inference go into a loop, because it requires the constraint+ Mul a [b] b+-}++checkInstCoverage :: Bool -- Be liberal+ -> Class -> [PredType] -> [Type]+ -> Validity+-- "be_liberal" flag says whether to use "liberal" coverage of+-- See Note [Coverage Condition] below+--+-- Return values+-- Nothing => no problems+-- Just msg => coverage problem described by msg++checkInstCoverage be_liberal clas theta inst_taus+ = allValid (map fundep_ok fds)+ where+ (tyvars, fds) = classTvsFds clas+ fundep_ok fd+ | and (isEmptyVarSet <$> undetermined_tvs) = IsValid+ | otherwise = NotValid msg+ where+ (ls,rs) = instFD fd tyvars inst_taus+ ls_tvs = tyCoVarsOfTypes ls+ rs_tvs = splitVisVarsOfTypes rs++ undetermined_tvs | be_liberal = liberal_undet_tvs+ | otherwise = conserv_undet_tvs++ closed_ls_tvs = oclose theta ls_tvs+ liberal_undet_tvs = (`minusVarSet` closed_ls_tvs) <$> rs_tvs+ conserv_undet_tvs = (`minusVarSet` ls_tvs) <$> rs_tvs++ undet_set = fold undetermined_tvs++ msg = vcat [ -- text "ls_tvs" <+> ppr ls_tvs+ -- , text "closed ls_tvs" <+> ppr (closeOverKinds ls_tvs)+ -- , text "theta" <+> ppr theta+ -- , text "oclose" <+> ppr (oclose theta (closeOverKinds ls_tvs))+ -- , text "rs_tvs" <+> ppr rs_tvs+ sep [ text "The"+ <+> ppWhen be_liberal (text "liberal")+ <+> text "coverage condition fails in class"+ <+> quotes (ppr clas)+ , nest 2 $ text "for functional dependency:"+ <+> quotes (pprFunDep fd) ]+ , sep [ text "Reason: lhs type"<>plural ls <+> pprQuotedList ls+ , nest 2 $+ (if isSingleton ls+ then text "does not"+ else text "do not jointly")+ <+> text "determine rhs type"<>plural rs+ <+> pprQuotedList rs ]+ , text "Un-determined variable" <> pluralVarSet undet_set <> colon+ <+> pprVarSet undet_set (pprWithCommas ppr)+ , ppWhen (isEmptyVarSet $ pSnd undetermined_tvs) $+ ppSuggestExplicitKinds+ , ppWhen (not be_liberal &&+ and (isEmptyVarSet <$> liberal_undet_tvs)) $+ text "Using UndecidableInstances might help" ]++{- Note [Closing over kinds in coverage]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have a fundep (a::k) -> b+Then if 'a' is instantiated to (x y), where x:k2->*, y:k2,+then fixing x really fixes k2 as well, and so k2 should be added to+the lhs tyvars in the fundep check.++Example (Trac #8391), using liberal coverage+ data Foo a = ... -- Foo :: forall k. k -> *+ class Bar a b | a -> b+ instance Bar a (Foo a)++ In the instance decl, (a:k) does fix (Foo k a), but only if we notice+ that (a:k) fixes k. Trac #10109 is another example.++Here is a more subtle example, from HList-0.4.0.0 (Trac #10564)++ class HasFieldM (l :: k) r (v :: Maybe *)+ | l r -> v where ...+ class HasFieldM1 (b :: Maybe [*]) (l :: k) r v+ | b l r -> v where ...+ class HMemberM (e1 :: k) (l :: [k]) (r :: Maybe [k])+ | e1 l -> r++ data Label :: k -> *+ type family LabelsOf (a :: [*]) :: *++ instance (HMemberM (Label {k} (l::k)) (LabelsOf xs) b,+ HasFieldM1 b l (r xs) v)+ => HasFieldM l (r xs) v where++Is the instance OK? Does {l,r,xs} determine v? Well:++ * From the instance constraint HMemberM (Label k l) (LabelsOf xs) b,+ plus the fundep "| el l -> r" in class HMameberM,+ we get {l,k,xs} -> b++ * Note the 'k'!! We must call closeOverKinds on the seed set+ ls_tvs = {l,r,xs}, BEFORE doing oclose, else the {l,k,xs}->b+ fundep won't fire. This was the reason for #10564.++ * So starting from seeds {l,r,xs,k} we do oclose to get+ first {l,r,xs,k,b}, via the HMemberM constraint, and then+ {l,r,xs,k,b,v}, via the HasFieldM1 constraint.++ * And that fixes v.++However, we must closeOverKinds whenever augmenting the seed set+in oclose! Consider Trac #10109:++ data Succ a -- Succ :: forall k. k -> *+ class Add (a :: k1) (b :: k2) (ab :: k3) | a b -> ab+ instance (Add a b ab) => Add (Succ {k1} (a :: k1))+ b+ (Succ {k3} (ab :: k3})++We start with seed set {a:k1,b:k2} and closeOverKinds to {a,k1,b,k2}.+Now use the fundep to extend to {a,k1,b,k2,ab}. But we need to+closeOverKinds *again* now to {a,k1,b,k2,ab,k3}, so that we fix all+the variables free in (Succ {k3} ab).++Bottom line:+ * closeOverKinds on initial seeds (done automatically+ by tyCoVarsOfTypes in checkInstCoverage)+ * and closeOverKinds whenever extending those seeds (in oclose)++Note [The liberal coverage condition]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(oclose preds tvs) closes the set of type variables tvs,+wrt functional dependencies in preds. The result is a superset+of the argument set. For example, if we have+ class C a b | a->b where ...+then+ oclose [C (x,y) z, C (x,p) q] {x,y} = {x,y,z}+because if we know x and y then that fixes z.++We also use equality predicates in the predicates; if we have an+assumption `t1 ~ t2`, then we use the fact that if we know `t1` we+also know `t2` and the other way.+ eg oclose [C (x,y) z, a ~ x] {a,y} = {a,y,z,x}++oclose is used (only) when checking the coverage condition for+an instance declaration++Note [Equality superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+ class (a ~ [b]) => C a b++Remember from Note [The equality types story] in TysPrim, that+ * (a ~~ b) is a superclass of (a ~ b)+ * (a ~# b) is a superclass of (a ~~ b)++So when oclose expands superclasses we'll get a (a ~# [b]) superclass.+But that's an EqPred not a ClassPred, and we jolly well do want to+account for the mutual functional dependencies implied by (t1 ~# t2).+Hence the EqPred handling in oclose. See Trac #10778.++Note [Care with type functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #12803)+ class C x y | x -> y+ type family F a b+ type family G c d = r | r -> d++Now consider+ oclose (C (F a b) (G c d)) {a,b}++Knowing {a,b} fixes (F a b) regardless of the injectivity of F.+But knowing (G c d) fixes only {d}, because G is only injective+in its second parameter.++Hence the tyCoVarsOfTypes/injTyVarsOfTypes dance in tv_fds.+-}++oclose :: [PredType] -> TyCoVarSet -> TyCoVarSet+-- See Note [The liberal coverage condition]+oclose preds fixed_tvs+ | null tv_fds = fixed_tvs -- Fast escape hatch for common case.+ | otherwise = fixVarSet extend fixed_tvs+ where+ extend fixed_tvs = foldl add fixed_tvs tv_fds+ where+ add fixed_tvs (ls,rs)+ | ls `subVarSet` fixed_tvs = fixed_tvs `unionVarSet` closeOverKinds rs+ | otherwise = fixed_tvs+ -- closeOverKinds: see Note [Closing over kinds in coverage]++ tv_fds :: [(TyCoVarSet,TyCoVarSet)]+ tv_fds = [ (tyCoVarsOfTypes ls, injTyVarsOfTypes rs)+ -- See Note [Care with type functions]+ | pred <- preds+ , pred' <- pred : transSuperClasses pred+ -- Look for fundeps in superclasses too+ , (ls, rs) <- determined pred' ]++ determined :: PredType -> [([Type],[Type])]+ determined pred+ = case classifyPredType pred of+ EqPred NomEq t1 t2 -> [([t1],[t2]), ([t2],[t1])]+ -- See Note [Equality superclasses]+ ClassPred cls tys -> [ instFD fd cls_tvs tys+ | let (cls_tvs, cls_fds) = classTvsFds cls+ , fd <- cls_fds ]+ _ -> []+++{- *********************************************************************+* *+ Check that a new instance decl is OK wrt fundeps+* *+************************************************************************++Here is the bad case:+ class C a b | a->b where ...+ instance C Int Bool where ...+ instance C Int Char where ...++The point is that a->b, so Int in the first parameter must uniquely+determine the second. In general, given the same class decl, and given++ instance C s1 s2 where ...+ instance C t1 t2 where ...++Then the criterion is: if U=unify(s1,t1) then U(s2) = U(t2).++Matters are a little more complicated if there are free variables in+the s2/t2.++ class D a b c | a -> b+ instance D a b => D [(a,a)] [b] Int+ instance D a b => D [a] [b] Bool++The instance decls don't overlap, because the third parameter keeps+them separate. But we want to make sure that given any constraint+ D s1 s2 s3+if s1 matches++Note [Bogus consistency check]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In checkFunDeps we check that a new ClsInst is consistent with all the+ClsInsts in the environment.++The bogus aspect is discussed in Trac #10675. Currenty it if the two+types are *contradicatory*, using (isNothing . tcUnifyTys). But all+the papers say we should check if the two types are *equal* thus+ not (substTys subst rtys1 `eqTypes` substTys subst rtys2)+For now I'm leaving the bogus form because that's the way it has+been for years.+-}++checkFunDeps :: InstEnvs -> ClsInst -> [ClsInst]+-- The Consistency Check.+-- Check whether adding DFunId would break functional-dependency constraints+-- Used only for instance decls defined in the module being compiled+-- Returns a list of the ClsInst in InstEnvs that are inconsistent+-- with the proposed new ClsInst+checkFunDeps inst_envs (ClsInst { is_tvs = qtvs1, is_cls = cls+ , is_tys = tys1, is_tcs = rough_tcs1 })+ | null fds+ = []+ | otherwise+ = nubBy eq_inst $+ [ ispec | ispec <- cls_insts+ , fd <- fds+ , is_inconsistent fd ispec ]+ where+ cls_insts = classInstances inst_envs cls+ (cls_tvs, fds) = classTvsFds cls+ qtv_set1 = mkVarSet qtvs1++ is_inconsistent fd (ClsInst { is_tvs = qtvs2, is_tys = tys2, is_tcs = rough_tcs2 })+ | instanceCantMatch trimmed_tcs rough_tcs2+ = False+ | otherwise+ = case tcUnifyTyKis bind_fn ltys1 ltys2 of+ Nothing -> False+ Just subst+ -> isNothing $ -- Bogus legacy test (Trac #10675)+ -- See Note [Bogus consistency check]+ tcUnifyTyKis bind_fn (substTysUnchecked subst rtys1) (substTysUnchecked subst rtys2)++ where+ trimmed_tcs = trimRoughMatchTcs cls_tvs fd rough_tcs1+ (ltys1, rtys1) = instFD fd cls_tvs tys1+ (ltys2, rtys2) = instFD fd cls_tvs tys2+ qtv_set2 = mkVarSet qtvs2+ bind_fn tv | tv `elemVarSet` qtv_set1 = BindMe+ | tv `elemVarSet` qtv_set2 = BindMe+ | otherwise = Skolem++ eq_inst i1 i2 = instanceDFunId i1 == instanceDFunId i2+ -- An single instance may appear twice in the un-nubbed conflict list+ -- because it may conflict with more than one fundep. E.g.+ -- class C a b c | a -> b, a -> c+ -- instance C Int Bool Bool+ -- instance C Int Char Char+ -- The second instance conflicts with the first by *both* fundeps++trimRoughMatchTcs :: [TyVar] -> FunDep TyVar -> [Maybe Name] -> [Maybe Name]+-- Computing rough_tcs for a particular fundep+-- class C a b c | a -> b where ...+-- For each instance .... => C ta tb tc+-- we want to match only on the type ta; so our+-- rough-match thing must similarly be filtered.+-- Hence, we Nothing-ise the tb and tc types right here+--+-- Result list is same length as input list, just with more Nothings+trimRoughMatchTcs clas_tvs (ltvs, _) mb_tcs+ = zipWith select clas_tvs mb_tcs+ where+ select clas_tv mb_tc | clas_tv `elem` ltvs = mb_tc+ | otherwise = Nothing
+ typecheck/Inst.hs view
@@ -0,0 +1,830 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++The @Inst@ type: dictionaries or method instances+-}++{-# LANGUAGE CPP, MultiWayIf, TupleSections #-}++module Inst (+ deeplySkolemise,+ topInstantiate, topInstantiateInferred, deeplyInstantiate,+ instCall, instDFunType, instStupidTheta,+ newWanted, newWanteds,++ tcInstBinders, tcInstBindersX, tcInstBinderX,++ newOverloadedLit, mkOverLit,++ newClsInst,+ tcGetInsts, tcGetInstEnvs, getOverlapFlag,+ tcExtendLocalInstEnv,+ instCallConstraints, newMethodFromName,+ tcSyntaxName,++ -- Simple functions over evidence variables+ tyCoVarsOfWC,+ tyCoVarsOfCt, tyCoVarsOfCts,+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} TcExpr( tcPolyExpr, tcSyntaxOp )+import {-# SOURCE #-} TcUnify( unifyType, unifyKind, noThing )++import BasicTypes ( SourceText(..) )+import FastString+import HsSyn+import TcHsSyn+import TcRnMonad+import TcEnv+import TcEvidence+import InstEnv+import TysWiredIn ( heqDataCon, coercibleDataCon )+import CoreSyn ( isOrphan )+import FunDeps+import TcMType+import Type+import TyCoRep ( TyBinder(..) )+import TcType+import HscTypes+import Class( Class )+import MkId( mkDictFunId )+import Id+import Name+import Var ( EvVar, mkTyVar, tyVarName, TyVarBndr(..) )+import DataCon+import TyCon+import VarEnv+import PrelNames+import SrcLoc+import DynFlags+import Util+import Outputable+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad( unless )++{-+************************************************************************+* *+ Creating and emittind constraints+* *+************************************************************************+-}++newMethodFromName :: CtOrigin -> Name -> TcRhoType -> TcM (HsExpr TcId)+-- Used when Name is the wired-in name for a wired-in class method,+-- so the caller knows its type for sure, which should be of form+-- forall a. C a => <blah>+-- newMethodFromName is supposed to instantiate just the outer+-- type variable and constraint++newMethodFromName origin name inst_ty+ = do { id <- tcLookupId name+ -- Use tcLookupId not tcLookupGlobalId; the method is almost+ -- always a class op, but with -XRebindableSyntax GHC is+ -- meant to find whatever thing is in scope, and that may+ -- be an ordinary function.++ ; let ty = piResultTy (idType id) inst_ty+ (theta, _caller_knows_this) = tcSplitPhiTy ty+ ; wrap <- ASSERT( not (isForAllTy ty) && isSingleton theta )+ instCall origin [inst_ty] theta++ ; return (mkHsWrap wrap (HsVar (noLoc id))) }++{-+************************************************************************+* *+ Deep instantiation and skolemisation+* *+************************************************************************++Note [Deep skolemisation]+~~~~~~~~~~~~~~~~~~~~~~~~~+deeplySkolemise decomposes and skolemises a type, returning a type+with all its arrows visible (ie not buried under foralls)++Examples:++ deeplySkolemise (Int -> forall a. Ord a => blah)+ = ( wp, [a], [d:Ord a], Int -> blah )+ where wp = \x:Int. /\a. \(d:Ord a). <hole> x++ deeplySkolemise (forall a. Ord a => Maybe a -> forall b. Eq b => blah)+ = ( wp, [a,b], [d1:Ord a,d2:Eq b], Maybe a -> blah )+ where wp = /\a.\(d1:Ord a).\(x:Maybe a)./\b.\(d2:Ord b). <hole> x++In general,+ if deeplySkolemise ty = (wrap, tvs, evs, rho)+ and e :: rho+ then wrap e :: ty+ and 'wrap' binds tvs, evs++ToDo: this eta-abstraction plays fast and loose with termination,+ because it can introduce extra lambdas. Maybe add a `seq` to+ fix this+-}++deeplySkolemise :: TcSigmaType+ -> TcM ( HsWrapper+ , [(Name,TyVar)] -- All skolemised variables+ , [EvVar] -- All "given"s+ , TcRhoType )++deeplySkolemise ty+ = go init_subst ty+ where+ init_subst = mkEmptyTCvSubst (mkInScopeSet (tyCoVarsOfType ty))++ go subst ty+ | Just (arg_tys, tvs, theta, ty') <- tcDeepSplitSigmaTy_maybe ty+ = do { let arg_tys' = substTys subst arg_tys+ ; ids1 <- newSysLocalIds (fsLit "dk") arg_tys'+ ; (subst', tvs1) <- tcInstSkolTyVarsX subst tvs+ ; ev_vars1 <- newEvVars (substTheta subst' theta)+ ; (wrap, tvs_prs2, ev_vars2, rho) <- go subst' ty'+ ; let tv_prs1 = map tyVarName tvs `zip` tvs1+ ; return ( mkWpLams ids1+ <.> mkWpTyLams tvs1+ <.> mkWpLams ev_vars1+ <.> wrap+ <.> mkWpEvVarApps ids1+ , tv_prs1 ++ tvs_prs2+ , ev_vars1 ++ ev_vars2+ , mkFunTys arg_tys' rho ) }++ | otherwise+ = return (idHsWrapper, [], [], substTy subst ty)+ -- substTy is a quick no-op on an empty substitution++-- | Instantiate all outer type variables+-- and any context. Never looks through arrows.+topInstantiate :: CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)+-- if topInstantiate ty = (wrap, rho)+-- and e :: ty+-- then wrap e :: rho (that is, wrap :: ty "->" rho)+topInstantiate = top_instantiate True++-- | Instantiate all outer 'Inferred' binders+-- and any context. Never looks through arrows or specified type variables.+-- Used for visible type application.+topInstantiateInferred :: CtOrigin -> TcSigmaType+ -> TcM (HsWrapper, TcSigmaType)+-- if topInstantiate ty = (wrap, rho)+-- and e :: ty+-- then wrap e :: rho+topInstantiateInferred = top_instantiate False++top_instantiate :: Bool -- True <=> instantiate *all* variables+ -- False <=> instantiate only the inferred ones+ -> CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)+top_instantiate inst_all orig ty+ | not (null binders && null theta)+ = do { let (inst_bndrs, leave_bndrs) = span should_inst binders+ (inst_theta, leave_theta)+ | null leave_bndrs = (theta, [])+ | otherwise = ([], theta)+ in_scope = mkInScopeSet (tyCoVarsOfType ty)+ empty_subst = mkEmptyTCvSubst in_scope+ inst_tvs = binderVars inst_bndrs+ ; (subst, inst_tvs') <- mapAccumLM newMetaTyVarX empty_subst inst_tvs+ ; let inst_theta' = substTheta subst inst_theta+ sigma' = substTy subst (mkForAllTys leave_bndrs $+ mkFunTys leave_theta rho)++ ; wrap1 <- instCall orig (mkTyVarTys inst_tvs') inst_theta'+ ; traceTc "Instantiating"+ (vcat [ text "all tyvars?" <+> ppr inst_all+ , text "origin" <+> pprCtOrigin orig+ , text "type" <+> ppr ty+ , text "theta" <+> ppr theta+ , text "leave_bndrs" <+> ppr leave_bndrs+ , text "with" <+> ppr inst_tvs'+ , text "theta:" <+> ppr inst_theta' ])++ ; (wrap2, rho2) <-+ if null leave_bndrs++ -- account for types like forall a. Num a => forall b. Ord b => ...+ then top_instantiate inst_all orig sigma'++ -- but don't loop if there were any un-inst'able tyvars+ else return (idHsWrapper, sigma')++ ; return (wrap2 <.> wrap1, rho2) }++ | otherwise = return (idHsWrapper, ty)+ where+ (binders, phi) = tcSplitForAllTyVarBndrs ty+ (theta, rho) = tcSplitPhiTy phi++ should_inst bndr+ | inst_all = True+ | otherwise = binderArgFlag bndr == Inferred++deeplyInstantiate :: CtOrigin -> TcSigmaType -> TcM (HsWrapper, TcRhoType)+-- Int -> forall a. a -> a ==> (\x:Int. [] x alpha) :: Int -> alpha+-- In general if+-- if deeplyInstantiate ty = (wrap, rho)+-- and e :: ty+-- then wrap e :: rho+-- That is, wrap :: ty ~> rho+--+-- If you don't need the HsWrapper returned from this function, consider+-- using tcSplitNestedSigmaTys in TcType, which is a pure alternative that+-- only computes the returned TcRhoType.++deeplyInstantiate orig ty =+ deeply_instantiate orig+ (mkEmptyTCvSubst (mkInScopeSet (tyCoVarsOfType ty)))+ ty++deeply_instantiate :: CtOrigin+ -> TCvSubst+ -> TcSigmaType -> TcM (HsWrapper, TcRhoType)+-- Internal function to deeply instantiate that builds on an existing subst.+-- It extends the input substitution and applies the final subtitution to+-- the types on return. See #12549.++deeply_instantiate orig subst ty+ | Just (arg_tys, tvs, theta, rho) <- tcDeepSplitSigmaTy_maybe ty+ = do { (subst', tvs') <- newMetaTyVarsX subst tvs+ ; ids1 <- newSysLocalIds (fsLit "di") (substTys subst' arg_tys)+ ; let theta' = substTheta subst' theta+ ; wrap1 <- instCall orig (mkTyVarTys tvs') theta'+ ; traceTc "Instantiating (deeply)" (vcat [ text "origin" <+> pprCtOrigin orig+ , text "type" <+> ppr ty+ , text "with" <+> ppr tvs'+ , text "args:" <+> ppr ids1+ , text "theta:" <+> ppr theta'+ , text "subst:" <+> ppr subst'])+ ; (wrap2, rho2) <- deeply_instantiate orig subst' rho+ ; return (mkWpLams ids1+ <.> wrap2+ <.> wrap1+ <.> mkWpEvVarApps ids1,+ mkFunTys arg_tys rho2) }++ | otherwise+ = do { let ty' = substTy subst ty+ ; traceTc "deeply_instantiate final subst"+ (vcat [ text "origin:" <+> pprCtOrigin orig+ , text "type:" <+> ppr ty+ , text "new type:" <+> ppr ty'+ , text "subst:" <+> ppr subst ])+ ; return (idHsWrapper, ty') }++{-+************************************************************************+* *+ Instantiating a call+* *+************************************************************************++Note [Handling boxed equality]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The solver deals entirely in terms of unboxed (primitive) equality.+There should never be a boxed Wanted equality. Ever. But, what if+we are calling `foo :: forall a. (F a ~ Bool) => ...`? That equality+is boxed, so naive treatment here would emit a boxed Wanted equality.++So we simply check for this case and make the right boxing of evidence.++-}++----------------+instCall :: CtOrigin -> [TcType] -> TcThetaType -> TcM HsWrapper+-- Instantiate the constraints of a call+-- (instCall o tys theta)+-- (a) Makes fresh dictionaries as necessary for the constraints (theta)+-- (b) Throws these dictionaries into the LIE+-- (c) Returns an HsWrapper ([.] tys dicts)++instCall orig tys theta+ = do { dict_app <- instCallConstraints orig theta+ ; return (dict_app <.> mkWpTyApps tys) }++----------------+instCallConstraints :: CtOrigin -> TcThetaType -> TcM HsWrapper+-- Instantiates the TcTheta, puts all constraints thereby generated+-- into the LIE, and returns a HsWrapper to enclose the call site.++instCallConstraints orig preds+ | null preds+ = return idHsWrapper+ | otherwise+ = do { evs <- mapM go preds+ ; traceTc "instCallConstraints" (ppr evs)+ ; return (mkWpEvApps evs) }+ where+ go pred+ | Just (Nominal, ty1, ty2) <- getEqPredTys_maybe pred -- Try short-cut #1+ = do { co <- unifyType noThing ty1 ty2+ ; return (EvCoercion co) }++ -- Try short-cut #2+ | Just (tc, args@[_, _, ty1, ty2]) <- splitTyConApp_maybe pred+ , tc `hasKey` heqTyConKey+ = do { co <- unifyType noThing ty1 ty2+ ; return (EvDFunApp (dataConWrapId heqDataCon) args [EvCoercion co]) }++ | otherwise+ = emitWanted orig pred++instDFunType :: DFunId -> [DFunInstType]+ -> TcM ( [TcType] -- instantiated argument types+ , TcThetaType ) -- instantiated constraint+-- See Note [DFunInstType: instantiating types] in InstEnv+instDFunType dfun_id dfun_inst_tys+ = do { (subst, inst_tys) <- go emptyTCvSubst dfun_tvs dfun_inst_tys+ ; return (inst_tys, substTheta subst dfun_theta) }+ where+ (dfun_tvs, dfun_theta, _) = tcSplitSigmaTy (idType dfun_id)++ go :: TCvSubst -> [TyVar] -> [DFunInstType] -> TcM (TCvSubst, [TcType])+ go subst [] [] = return (subst, [])+ go subst (tv:tvs) (Just ty : mb_tys)+ = do { (subst', tys) <- go (extendTvSubstAndInScope subst tv ty)+ tvs+ mb_tys+ ; return (subst', ty : tys) }+ go subst (tv:tvs) (Nothing : mb_tys)+ = do { (subst', tv') <- newMetaTyVarX subst tv+ ; (subst'', tys) <- go subst' tvs mb_tys+ ; return (subst'', mkTyVarTy tv' : tys) }+ go _ _ _ = pprPanic "instDFunTypes" (ppr dfun_id $$ ppr dfun_inst_tys)++----------------+instStupidTheta :: CtOrigin -> TcThetaType -> TcM ()+-- Similar to instCall, but only emit the constraints in the LIE+-- Used exclusively for the 'stupid theta' of a data constructor+instStupidTheta orig theta+ = do { _co <- instCallConstraints orig theta -- Discard the coercion+ ; return () }++{-+************************************************************************+* *+ Instantiating Kinds+* *+************************************************************************++-}++---------------------------+-- | This is used to instantiate binders when type-checking *types* only.+-- See also Note [Bidirectional type checking]+tcInstBinders :: [TyBinder] -> TcM (TCvSubst, [TcType])+tcInstBinders = tcInstBindersX emptyTCvSubst Nothing++-- | This is used to instantiate binders when type-checking *types* only.+-- The @VarEnv Kind@ gives some known instantiations.+-- See also Note [Bidirectional type checking]+tcInstBindersX :: TCvSubst -> Maybe (VarEnv Kind)+ -> [TyBinder] -> TcM (TCvSubst, [TcType])+tcInstBindersX subst mb_kind_info bndrs+ = do { (subst, args) <- mapAccumLM (tcInstBinderX mb_kind_info) subst bndrs+ ; traceTc "instantiating tybinders:"+ (vcat $ zipWith (\bndr arg -> ppr bndr <+> text ":=" <+> ppr arg)+ bndrs args)+ ; return (subst, args) }++-- | Used only in *types*+tcInstBinderX :: Maybe (VarEnv Kind)+ -> TCvSubst -> TyBinder -> TcM (TCvSubst, TcType)+tcInstBinderX mb_kind_info subst (Named (TvBndr tv _))+ = case lookup_tv tv of+ Just ki -> return (extendTvSubstAndInScope subst tv ki, ki)+ Nothing -> do { (subst', tv') <- newMetaTyVarX subst tv+ ; return (subst', mkTyVarTy tv') }+ where+ lookup_tv tv = do { env <- mb_kind_info -- `Maybe` monad+ ; lookupVarEnv env tv }+++tcInstBinderX _ subst (Anon ty)+ -- This is the *only* constraint currently handled in types.+ | Just (mk, role, k1, k2) <- get_pred_tys_maybe substed_ty+ = do { let origin = TypeEqOrigin { uo_actual = k1+ , uo_expected = k2+ , uo_thing = Nothing }+ ; co <- case role of+ Nominal -> unifyKind noThing k1 k2+ Representational -> emitWantedEq origin KindLevel role k1 k2+ Phantom -> pprPanic "tcInstBinderX Phantom" (ppr ty)+ ; arg' <- mk co k1 k2+ ; return (subst, arg') }++ | isPredTy substed_ty+ = do { let (env, tidy_ty) = tidyOpenType emptyTidyEnv substed_ty+ ; addErrTcM (env, text "Illegal constraint in a type:" <+> ppr tidy_ty)++ -- just invent a new variable so that we can continue+ ; u <- newUnique+ ; let name = mkSysTvName u (fsLit "dict")+ ; return (subst, mkTyVarTy $ mkTyVar name substed_ty) }+++ | otherwise+ = do { tv_ty <- newFlexiTyVarTy substed_ty+ ; return (subst, tv_ty) }++ where+ substed_ty = substTy subst ty++ -- handle boxed equality constraints, because it's so easy+ get_pred_tys_maybe ty+ | Just (r, k1, k2) <- getEqPredTys_maybe ty+ = Just (\co _ _ -> return $ mkCoercionTy co, r, k1, k2)+ | Just (tc, [_, _, k1, k2]) <- splitTyConApp_maybe ty+ = if | tc `hasKey` heqTyConKey+ -> Just (mkHEqBoxTy, Nominal, k1, k2)+ | otherwise+ -> Nothing+ | Just (tc, [_, k1, k2]) <- splitTyConApp_maybe ty+ = if | tc `hasKey` eqTyConKey+ -> Just (mkEqBoxTy, Nominal, k1, k2)+ | tc `hasKey` coercibleTyConKey+ -> Just (mkCoercibleBoxTy, Representational, k1, k2)+ | otherwise+ -> Nothing+ | otherwise+ = Nothing++-------------------------------+-- | This takes @a ~# b@ and returns @a ~~ b@.+mkHEqBoxTy :: TcCoercion -> Type -> Type -> TcM Type+-- monadic just for convenience with mkEqBoxTy+mkHEqBoxTy co ty1 ty2+ = return $+ mkTyConApp (promoteDataCon heqDataCon) [k1, k2, ty1, ty2, mkCoercionTy co]+ where k1 = typeKind ty1+ k2 = typeKind ty2++-- | This takes @a ~# b@ and returns @a ~ b@.+mkEqBoxTy :: TcCoercion -> Type -> Type -> TcM Type+mkEqBoxTy co ty1 ty2+ = do { eq_tc <- tcLookupTyCon eqTyConName+ ; let [datacon] = tyConDataCons eq_tc+ ; hetero <- mkHEqBoxTy co ty1 ty2+ ; return $ mkTyConApp (promoteDataCon datacon) [k, ty1, ty2, hetero] }+ where k = typeKind ty1++-- | This takes @a ~R# b@ and returns @Coercible a b@.+mkCoercibleBoxTy :: TcCoercion -> Type -> Type -> TcM Type+-- monadic just for convenience with mkEqBoxTy+mkCoercibleBoxTy co ty1 ty2+ = do { return $+ mkTyConApp (promoteDataCon coercibleDataCon)+ [k, ty1, ty2, mkCoercionTy co] }+ where k = typeKind ty1++{-+************************************************************************+* *+ Literals+* *+************************************************************************++-}++{-+In newOverloadedLit we convert directly to an Int or Integer if we+know that's what we want. This may save some time, by not+temporarily generating overloaded literals, but it won't catch all+cases (the rest are caught in lookupInst).++-}++newOverloadedLit :: HsOverLit Name+ -> ExpRhoType+ -> TcM (HsOverLit TcId)+newOverloadedLit+ lit@(OverLit { ol_val = val, ol_rebindable = rebindable }) res_ty+ | not rebindable+ -- all built-in overloaded lits are tau-types, so we can just+ -- tauify the ExpType+ = do { res_ty <- expTypeToType res_ty+ ; dflags <- getDynFlags+ ; case shortCutLit dflags val res_ty of+ -- Do not generate a LitInst for rebindable syntax.+ -- Reason: If we do, tcSimplify will call lookupInst, which+ -- will call tcSyntaxName, which does unification,+ -- which tcSimplify doesn't like+ Just expr -> return (lit { ol_witness = expr, ol_type = res_ty+ , ol_rebindable = False })+ Nothing -> newNonTrivialOverloadedLit orig lit+ (mkCheckExpType res_ty) }++ | otherwise+ = newNonTrivialOverloadedLit orig lit res_ty+ where+ orig = LiteralOrigin lit++-- Does not handle things that 'shortCutLit' can handle. See also+-- newOverloadedLit in TcUnify+newNonTrivialOverloadedLit :: CtOrigin+ -> HsOverLit Name+ -> ExpRhoType+ -> TcM (HsOverLit TcId)+newNonTrivialOverloadedLit orig+ lit@(OverLit { ol_val = val, ol_witness = HsVar (L _ meth_name)+ , ol_rebindable = rebindable }) res_ty+ = do { hs_lit <- mkOverLit val+ ; let lit_ty = hsLitType hs_lit+ ; (_, fi') <- tcSyntaxOp orig (mkRnSyntaxExpr meth_name)+ [synKnownType lit_ty] res_ty $+ \_ -> return ()+ ; let L _ witness = nlHsSyntaxApps fi' [nlHsLit hs_lit]+ ; res_ty <- readExpType res_ty+ ; return (lit { ol_witness = witness+ , ol_type = res_ty+ , ol_rebindable = rebindable }) }+newNonTrivialOverloadedLit _ lit _+ = pprPanic "newNonTrivialOverloadedLit" (ppr lit)++------------+mkOverLit :: OverLitVal -> TcM HsLit+mkOverLit (HsIntegral src i)+ = do { integer_ty <- tcMetaTy integerTyConName+ ; return (HsInteger src i integer_ty) }++mkOverLit (HsFractional r)+ = do { rat_ty <- tcMetaTy rationalTyConName+ ; return (HsRat r rat_ty) }++mkOverLit (HsIsString src s) = return (HsString src s)++{-+************************************************************************+* *+ Re-mappable syntax++ Used only for arrow syntax -- find a way to nuke this+* *+************************************************************************++Suppose we are doing the -XRebindableSyntax thing, and we encounter+a do-expression. We have to find (>>) in the current environment, which is+done by the rename. Then we have to check that it has the same type as+Control.Monad.(>>). Or, more precisely, a compatible type. One 'customer' had+this:++ (>>) :: HB m n mn => m a -> n b -> mn b++So the idea is to generate a local binding for (>>), thus:++ let then72 :: forall a b. m a -> m b -> m b+ then72 = ...something involving the user's (>>)...+ in+ ...the do-expression...++Now the do-expression can proceed using then72, which has exactly+the expected type.++In fact tcSyntaxName just generates the RHS for then72, because we only+want an actual binding in the do-expression case. For literals, we can+just use the expression inline.+-}++tcSyntaxName :: CtOrigin+ -> TcType -- Type to instantiate it at+ -> (Name, HsExpr Name) -- (Standard name, user name)+ -> TcM (Name, HsExpr TcId) -- (Standard name, suitable expression)+-- USED ONLY FOR CmdTop (sigh) ***+-- See Note [CmdSyntaxTable] in HsExpr++tcSyntaxName orig ty (std_nm, HsVar (L _ user_nm))+ | std_nm == user_nm+ = do rhs <- newMethodFromName orig std_nm ty+ return (std_nm, rhs)++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++ -- 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 <- tcPolyExpr (L span user_nm_expr) sigma1+ return (std_nm, unLoc expr)++syntaxNameCtxt :: HsExpr Name -> CtOrigin -> Type -> 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)+ <+> 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) }++{-+************************************************************************+* *+ Instances+* *+************************************************************************+-}++getOverlapFlag :: Maybe OverlapMode -> TcM OverlapFlag+-- Construct the OverlapFlag from the global module flags,+-- but if the overlap_mode argument is (Just m),+-- set the OverlapMode to 'm'+getOverlapFlag overlap_mode+ = do { dflags <- getDynFlags+ ; let overlap_ok = xopt LangExt.OverlappingInstances dflags+ incoherent_ok = xopt LangExt.IncoherentInstances dflags+ use x = OverlapFlag { isSafeOverlap = safeLanguageOn dflags+ , overlapMode = x }+ default_oflag | incoherent_ok = use (Incoherent NoSourceText)+ | overlap_ok = use (Overlaps NoSourceText)+ | otherwise = use (NoOverlap NoSourceText)++ final_oflag = setOverlapModeMaybe default_oflag overlap_mode+ ; return final_oflag }++tcGetInsts :: TcM [ClsInst]+-- Gets the local class instances.+tcGetInsts = fmap tcg_insts getGblEnv++newClsInst :: Maybe OverlapMode -> Name -> [TyVar] -> ThetaType+ -> Class -> [Type] -> TcM ClsInst+newClsInst overlap_mode dfun_name tvs theta clas tys+ = do { (subst, tvs') <- freshenTyVarBndrs tvs+ -- Be sure to freshen those type variables,+ -- so they are sure not to appear in any lookup+ ; let tys' = substTys subst tys++ dfun = mkDictFunId dfun_name tvs theta clas tys+ -- The dfun uses the original 'tvs' because+ -- (a) they don't need to be fresh+ -- (b) they may be mentioned in the ib_binds field of+ -- an InstInfo, and in TcEnv.pprInstInfoDetails it's+ -- helpful to use the same names++ ; oflag <- getOverlapFlag overlap_mode+ ; let inst = mkLocalInstance dfun oflag tvs' clas tys'+ ; warnIf (Reason Opt_WarnOrphans)+ (isOrphan (is_orphan inst))+ (instOrphWarn inst)+ ; return inst }++instOrphWarn :: ClsInst -> SDoc+instOrphWarn inst+ = hang (text "Orphan instance:") 2 (pprInstanceHdr inst)+ $$ text "To avoid this"+ $$ nest 4 (vcat possibilities)+ where+ possibilities =+ text "move the instance declaration to the module of the class or of the type, or" :+ text "wrap the type with a newtype and declare the instance on the new type." :+ []++tcExtendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a+ -- Add new locally-defined instances+tcExtendLocalInstEnv dfuns thing_inside+ = do { traceDFuns dfuns+ ; env <- getGblEnv+ ; (inst_env', cls_insts') <- foldlM addLocalInst+ (tcg_inst_env env, tcg_insts env)+ dfuns+ ; let env' = env { tcg_insts = cls_insts'+ , tcg_inst_env = inst_env' }+ ; setGblEnv env' thing_inside }++addLocalInst :: (InstEnv, [ClsInst]) -> ClsInst -> TcM (InstEnv, [ClsInst])+-- Check that the proposed new instance is OK,+-- and then add it to the home inst env+-- If overwrite_inst, then we can overwrite a direct match+addLocalInst (home_ie, my_insts) ispec+ = do {+ -- Load imported instances, so that we report+ -- duplicates correctly++ -- 'matches' are existing instance declarations that are less+ -- specific than the new one+ -- 'dups' are those 'matches' that are equal to the new one+ ; isGHCi <- getIsGHCi+ ; eps <- getEps+ ; tcg_env <- getGblEnv++ -- In GHCi, we *override* any identical instances+ -- that are also defined in the interactive context+ -- See Note [Override identical instances in GHCi]+ ; let home_ie'+ | isGHCi = deleteFromInstEnv home_ie ispec+ | otherwise = home_ie++ global_ie = eps_inst_env eps+ inst_envs = InstEnvs { ie_global = global_ie+ , ie_local = home_ie'+ , ie_visible = tcVisibleOrphanMods tcg_env }++ -- Check for inconsistent functional dependencies+ ; let inconsistent_ispecs = checkFunDeps inst_envs ispec+ ; unless (null inconsistent_ispecs) $+ funDepErr ispec inconsistent_ispecs++ -- Check for duplicate instance decls.+ ; let (_tvs, cls, tys) = instanceHead ispec+ (matches, _, _) = lookupInstEnv False inst_envs cls tys+ dups = filter (identicalClsInstHead ispec) (map fst matches)+ ; unless (null dups) $+ dupInstErr ispec (head dups)++ ; return (extendInstEnv home_ie' ispec, ispec : my_insts) }++{-+Note [Signature files and type class instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Instances in signature files do not have an effect when compiling:+when you compile a signature against an implementation, you will+see the instances WHETHER OR NOT the instance is declared in+the file (this is because the signatures go in the EPS and we+can't filter them out easily.) This is also why we cannot+place the instance in the hi file: it would show up as a duplicate,+and we don't have instance reexports anyway.++However, you might find them useful when typechecking against+a signature: the instance is a way of indicating to GHC that+some instance exists, in case downstream code uses it.++Implementing this is a little tricky. Consider the following+situation (sigof03):++ module A where+ instance C T where ...++ module ASig where+ instance C T++When compiling ASig, A.hi is loaded, which brings its instances+into the EPS. When we process the instance declaration in ASig,+we should ignore it for the purpose of doing a duplicate check,+since it's not actually a duplicate. But don't skip the check+entirely, we still want this to fail (tcfail221):++ module ASig where+ instance C T+ instance C T++Note that in some situations, the interface containing the type+class instances may not have been loaded yet at all. The usual+situation when A imports another module which provides the+instances (sigof02m):++ module A(module B) where+ import B++See also Note [Signature lazy interface loading]. We can't+rely on this, however, since sometimes we'll have spurious+type class instances in the EPS, see #9422 (sigof02dm)++************************************************************************+* *+ Errors and tracing+* *+************************************************************************+-}++traceDFuns :: [ClsInst] -> TcRn ()+traceDFuns ispecs+ = traceTc "Adding instances:" (vcat (map pp ispecs))+ where+ pp ispec = hang (ppr (instanceDFunId ispec) <+> colon)+ 2 (ppr ispec)+ -- Print the dfun name itself too++funDepErr :: ClsInst -> [ClsInst] -> TcRn ()+funDepErr ispec ispecs+ = addClsInstsErr (text "Functional dependencies conflict between instance declarations:")+ (ispec : ispecs)++dupInstErr :: ClsInst -> ClsInst -> TcRn ()+dupInstErr ispec dup_ispec+ = addClsInstsErr (text "Duplicate instance declarations:")+ [ispec, dup_ispec]++addClsInstsErr :: SDoc -> [ClsInst] -> TcRn ()+addClsInstsErr herald ispecs+ = setSrcSpan (getSrcSpan (head sorted)) $+ addErr (hang herald 2 (pprInstances sorted))+ where+ sorted = sortWith getSrcLoc ispecs+ -- The sortWith just arranges that instances are dislayed in order+ -- of source location, which reduced wobbling in error messages,+ -- and is better for users
+ typecheck/TcAnnotations.hs view
@@ -0,0 +1,74 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1993-1998++\section[TcAnnotations]{Typechecking annotations}+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}++module TcAnnotations ( tcAnnotations, annCtxt ) where++import {-# SOURCE #-} TcSplice ( runAnnotation )+import Module+import DynFlags+import Control.Monad ( when )++import HsSyn+import Annotations+import Name+import TcRnMonad+import SrcLoc+import Outputable++-- Some platforms don't support the external interpreter, and+-- compilation on those platforms shouldn't fail just due to+-- annotations+#ifndef GHCI+tcAnnotations :: [LAnnDecl Name] -> TcM [Annotation]+tcAnnotations anns = do+ dflags <- getDynFlags+ case gopt Opt_ExternalInterpreter dflags of+ True -> tcAnnotations' anns+ False -> warnAnns anns+warnAnns :: [LAnnDecl Name] -> TcM [Annotation]+--- No GHCI; emit a warning (not an error) and ignore. cf Trac #4268+warnAnns [] = return []+warnAnns anns@(L loc _ : _)+ = do { setSrcSpan loc $ addWarnTc NoReason $+ (text "Ignoring ANN annotation" <> plural anns <> comma+ <+> text "because this is a stage-1 compiler without -fexternal-interpreter or doesn't support GHCi")+ ; return [] }+#else+tcAnnotations :: [LAnnDecl Name] -> TcM [Annotation]+tcAnnotations = tcAnnotations'+#endif++tcAnnotations' :: [LAnnDecl Name] -> TcM [Annotation]+tcAnnotations' anns = mapM tcAnnotation anns++tcAnnotation :: LAnnDecl Name -> TcM Annotation+tcAnnotation (L loc ann@(HsAnnotation _ provenance expr)) = do+ -- Work out what the full target of this annotation was+ mod <- getModule+ let target = annProvenanceToTarget mod provenance++ -- Run that annotation and construct the full Annotation data structure+ setSrcSpan loc $ addErrCtxt (annCtxt ann) $ do+ -- See #10826 -- Annotations allow one to bypass Safe Haskell.+ dflags <- getDynFlags+ when (safeLanguageOn dflags) $ failWithTc safeHsErr+ runAnnotation target expr+ where+ safeHsErr = vcat [ text "Annotations are not compatible with Safe Haskell."+ , text "See https://ghc.haskell.org/trac/ghc/ticket/10826" ]++annProvenanceToTarget :: Module -> AnnProvenance Name -> AnnTarget Name+annProvenanceToTarget _ (ValueAnnProvenance (L _ name)) = NamedTarget name+annProvenanceToTarget _ (TypeAnnProvenance (L _ name)) = NamedTarget name+annProvenanceToTarget mod ModuleAnnProvenance = ModuleTarget mod++annCtxt :: (OutputableBndrId id) => AnnDecl id -> SDoc+annCtxt ann+ = hang (text "In the annotation:") 2 (ppr ann)
+ typecheck/TcArrows.hs view
@@ -0,0 +1,427 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++Typecheck arrow notation+-}++{-# LANGUAGE RankNTypes, TupleSections #-}++module TcArrows ( tcProc ) where++import {-# SOURCE #-} TcExpr( tcMonoExpr, tcInferRho, tcSyntaxOp, tcCheckId, tcPolyExpr )++import HsSyn+import TcMatches+import TcHsSyn( hsLPatType )+import TcType+import TcMType+import TcBinds+import TcPat+import TcUnify+import TcRnMonad+import TcEnv+import TcEvidence+import Id( mkLocalId )+import Inst+import Name+import TysWiredIn+import VarSet+import TysPrim+import BasicTypes( Arity )+import SrcLoc+import Outputable+import Util++import Control.Monad++{-+Note [Arrow overview]+~~~~~~~~~~~~~~~~~~~~~+Here's a summary of arrows and how they typecheck. First, here's+a cut-down syntax:++ expr ::= ....+ | proc pat cmd++ cmd ::= cmd exp -- Arrow application+ | \pat -> cmd -- Arrow abstraction+ | (| exp cmd1 ... cmdn |) -- Arrow form, n>=0+ | ... -- If, case in the usual way++ cmd_type ::= carg_type --> type++ carg_type ::= ()+ | (type, carg_type)++Note that+ * The 'exp' in an arrow form can mention only+ "arrow-local" variables++ * An "arrow-local" variable is bound by an enclosing+ cmd binding form (eg arrow abstraction)++ * A cmd_type is here written with a funny arrow "-->",+ The bit on the left is a carg_type (command argument type)+ which itself is a nested tuple, finishing with ()++ * The arrow-tail operator (e1 -< e2) means+ (| e1 <<< arr snd |) e2+++************************************************************************+* *+ Proc+* *+************************************************************************+-}++tcProc :: InPat Name -> LHsCmdTop Name -- proc pat -> expr+ -> ExpRhoType -- Expected type of whole proc expression+ -> TcM (OutPat TcId, LHsCmdTop TcId, TcCoercion)++tcProc pat cmd exp_ty+ = newArrowScope $+ 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+ ; let cmd_env = CmdEnv { cmd_arr = arr_ty }+ ; (pat', cmd') <- tcPat ProcExpr pat (mkCheckExpType arg_ty) $+ tcCmdTop cmd_env cmd (unitTy, res_ty)+ ; let res_co = mkTcTransCo co+ (mkTcAppCo co1 (mkTcNomReflCo res_ty))+ ; return (pat', cmd', res_co) }++{-+************************************************************************+* *+ Commands+* *+************************************************************************+-}++-- See Note [Arrow overview]+type CmdType = (CmdArgType, TcTauType) -- cmd_type+type CmdArgType = TcTauType -- carg_type, a nested tuple++data CmdEnv+ = CmdEnv {+ cmd_arr :: TcType -- arrow type constructor, of kind *->*->*+ }++mkCmdArrTy :: CmdEnv -> TcTauType -> TcTauType -> TcTauType+mkCmdArrTy env t1 t2 = mkAppTys (cmd_arr env) [t1, t2]++---------------------------------------+tcCmdTop :: CmdEnv+ -> LHsCmdTop Name+ -> CmdType+ -> TcM (LHsCmdTop TcId)++tcCmdTop env (L loc (HsCmdTop cmd _ _ names)) cmd_ty@(cmd_stk, res_ty)+ = setSrcSpan loc $+ do { cmd' <- tcCmd env cmd cmd_ty+ ; names' <- mapM (tcSyntaxName ProcOrigin (cmd_arr env)) names+ ; return (L loc $ HsCmdTop cmd' cmd_stk res_ty names') }+----------------------------------------+tcCmd :: CmdEnv -> LHsCmd Name -> CmdType -> TcM (LHsCmd TcId)+ -- The main recursive function+tcCmd env (L loc cmd) res_ty+ = setSrcSpan loc $ do+ { cmd' <- tc_cmd env cmd res_ty+ ; return (L loc cmd') }++tc_cmd :: CmdEnv -> HsCmd Name -> CmdType -> TcM (HsCmd TcId)+tc_cmd env (HsCmdPar cmd) res_ty+ = do { cmd' <- tcCmd env cmd res_ty+ ; return (HsCmdPar cmd') }++tc_cmd env (HsCmdLet (L l binds) (L body_loc body)) res_ty+ = do { (binds', body') <- tcLocalBinds binds $+ setSrcSpan body_loc $+ tc_cmd env body res_ty+ ; return (HsCmdLet (L l binds') (L body_loc body')) }++tc_cmd env in_cmd@(HsCmdCase scrut matches) (stk, res_ty)+ = addErrCtxt (cmdCtxt in_cmd) $ do+ (scrut', scrut_ty) <- tcInferRho scrut+ matches' <- tcMatchesCase match_ctxt scrut_ty matches (mkCheckExpType res_ty)+ return (HsCmdCase scrut' matches')+ where+ match_ctxt = MC { mc_what = CaseAlt,+ mc_body = mc_body }+ mc_body body res_ty' = do { res_ty' <- expTypeToType res_ty'+ ; tcCmd env body (stk, res_ty') }++tc_cmd env (HsCmdIf Nothing pred b1 b2) res_ty -- Ordinary 'if'+ = do { pred' <- tcMonoExpr pred (mkCheckExpType boolTy)+ ; b1' <- tcCmd env b1 res_ty+ ; b2' <- tcCmd env b2 res_ty+ ; return (HsCmdIf Nothing pred' b1' b2')+ }++tc_cmd env (HsCmdIf (Just fun) pred b1 b2) res_ty -- Rebindable syntax for if+ = do { pred_ty <- newOpenFlexiTyVarTy+ -- For arrows, need ifThenElse :: forall r. T -> r -> r -> r+ -- because we're going to apply it to the environment, not+ -- the return value.+ ; (_, [r_tv]) <- tcInstSkolTyVars [alphaTyVar]+ ; let r_ty = mkTyVarTy r_tv+ ; checkTc (not (r_tv `elemVarSet` tyCoVarsOfType pred_ty))+ (text "Predicate type of `ifThenElse' depends on result type")+ ; (pred', fun')+ <- tcSyntaxOp IfOrigin fun (map synKnownType [pred_ty, r_ty, r_ty])+ (mkCheckExpType r_ty) $ \ _ ->+ tcMonoExpr pred (mkCheckExpType pred_ty)++ ; b1' <- tcCmd env b1 res_ty+ ; b2' <- tcCmd env b2 res_ty+ ; return (HsCmdIf (Just fun') pred' b1' b2')+ }++-------------------------------------------+-- Arrow application+-- (f -< a) or (f -<< a)+--+-- D |- fun :: a t1 t2+-- D,G |- arg :: t1+-- ------------------------+-- D;G |-a fun -< arg :: stk --> t2+--+-- D,G |- fun :: a t1 t2+-- D,G |- arg :: t1+-- ------------------------+-- D;G |-a fun -<< arg :: stk --> t2+--+-- (plus -<< requires ArrowApply)++tc_cmd env cmd@(HsCmdArrApp fun arg _ ho_app lr) (_, res_ty)+ = addErrCtxt (cmdCtxt cmd) $+ do { arg_ty <- newOpenFlexiTyVarTy+ ; let fun_ty = mkCmdArrTy env arg_ty res_ty+ ; fun' <- select_arrow_scope (tcMonoExpr fun (mkCheckExpType fun_ty))++ ; arg' <- tcMonoExpr arg (mkCheckExpType arg_ty)++ ; return (HsCmdArrApp fun' arg' fun_ty ho_app lr) }+ where+ -- Before type-checking f, use the environment of the enclosing+ -- proc for the (-<) case.+ -- Local bindings, inside the enclosing proc, are not in scope+ -- inside f. In the higher-order case (-<<), they are.+ -- See Note [Escaping the arrow scope] in TcRnTypes+ select_arrow_scope tc = case ho_app of+ HsHigherOrderApp -> tc+ HsFirstOrderApp -> escapeArrowScope tc++-------------------------------------------+-- Command application+--+-- D,G |- exp : t+-- D;G |-a cmd : (t,stk) --> res+-- -----------------------------+-- D;G |-a cmd exp : stk --> res++tc_cmd env cmd@(HsCmdApp fun arg) (cmd_stk, res_ty)+ = addErrCtxt (cmdCtxt cmd) $+ do { arg_ty <- newOpenFlexiTyVarTy+ ; fun' <- tcCmd env fun (mkPairTy arg_ty cmd_stk, res_ty)+ ; arg' <- tcMonoExpr arg (mkCheckExpType arg_ty)+ ; return (HsCmdApp fun' arg') }++-------------------------------------------+-- Lambda+--+-- D;G,x:t |-a cmd : stk --> res+-- ------------------------------+-- D;G |-a (\x.cmd) : (t,stk) --> res++tc_cmd env+ (HsCmdLam (MG { mg_alts = L l [L mtch_loc+ (match@(Match _ pats _maybe_rhs_sig grhss))],+ mg_origin = origin }))+ (cmd_stk, res_ty)+ = addErrCtxt (pprMatchInCtxt match) $+ do { (co, arg_tys, cmd_stk') <- matchExpectedCmdArgs n_pats cmd_stk++ -- Check the patterns, and the GRHSs inside+ ; (pats', grhss') <- setSrcSpan mtch_loc $+ tcPats LambdaExpr pats (map mkCheckExpType arg_tys) $+ tc_grhss grhss cmd_stk' (mkCheckExpType res_ty)++ ; let match' = L mtch_loc (Match LambdaExpr pats' Nothing grhss')+ arg_tys = map hsLPatType pats'+ cmd' = HsCmdLam (MG { mg_alts = L l [match'], mg_arg_tys = arg_tys+ , mg_res_ty = res_ty, mg_origin = origin })+ ; return (mkHsCmdWrap (mkWpCastN co) cmd') }+ where+ n_pats = length pats+ match_ctxt = (LambdaExpr :: HsMatchContext Name) -- Maybe KappaExpr?+ pg_ctxt = PatGuard match_ctxt++ tc_grhss (GRHSs grhss (L l binds)) stk_ty res_ty+ = do { (binds', grhss') <- tcLocalBinds binds $+ mapM (wrapLocM (tc_grhs stk_ty res_ty)) grhss+ ; return (GRHSs grhss' (L l binds')) }++ tc_grhs stk_ty res_ty (GRHS guards body)+ = do { (guards', rhs') <- tcStmtsAndThen pg_ctxt tcGuardStmt guards res_ty $+ \ res_ty -> tcCmd env body+ (stk_ty, checkingExpType "tc_grhs" res_ty)+ ; return (GRHS guards' rhs') }++-------------------------------------------+-- Do notation++tc_cmd env (HsCmdDo (L l stmts) _) (cmd_stk, res_ty)+ = do { co <- unifyType noThing unitTy cmd_stk -- Expecting empty argument stack+ ; stmts' <- tcStmts ArrowExpr (tcArrDoStmt env) stmts res_ty+ ; return (mkHsCmdWrap (mkWpCastN co) (HsCmdDo (L l stmts') res_ty)) }+++-----------------------------------------------------------------+-- Arrow ``forms'' (| e c1 .. cn |)+--+-- D; G |-a1 c1 : stk1 --> r1+-- ...+-- D; G |-an cn : stkn --> rn+-- D |- e :: forall e. a1 (e, stk1) t1+-- ...+-- -> an (e, stkn) tn+-- -> a (e, stk) t+-- e \not\in (stk, stk1, ..., stkm, t, t1, ..., tn)+-- ----------------------------------------------+-- D; G |-a (| e c1 ... cn |) : stk --> t++tc_cmd env cmd@(HsCmdArrForm expr f fixity cmd_args) (cmd_stk, res_ty)+ = addErrCtxt (cmdCtxt cmd) $+ do { (cmd_args', cmd_tys) <- mapAndUnzipM tc_cmd_arg cmd_args+ -- We use alphaTyVar for 'w'+ ; let e_ty = mkInvForAllTy alphaTyVar $+ mkFunTys cmd_tys $+ mkCmdArrTy env (mkPairTy alphaTy cmd_stk) res_ty+ ; expr' <- tcPolyExpr expr e_ty+ ; return (HsCmdArrForm expr' f fixity cmd_args') }++ where+ tc_cmd_arg :: LHsCmdTop Name -> TcM (LHsCmdTop TcId, TcType)+ tc_cmd_arg cmd+ = do { arr_ty <- newFlexiTyVarTy arrowTyConKind+ ; stk_ty <- newFlexiTyVarTy liftedTypeKind+ ; res_ty <- newFlexiTyVarTy liftedTypeKind+ ; let env' = env { cmd_arr = arr_ty }+ ; cmd' <- tcCmdTop env' cmd (stk_ty, res_ty)+ ; return (cmd', mkCmdArrTy env' (mkPairTy alphaTy stk_ty) res_ty) }++-----------------------------------------------------------------+-- Base case for illegal commands+-- This is where expressions that aren't commands get rejected++tc_cmd _ cmd _+ = failWithTc (vcat [text "The expression", nest 2 (ppr cmd),+ text "was found where an arrow command was expected"])+++matchExpectedCmdArgs :: Arity -> TcType -> TcM (TcCoercionN, [TcType], TcType)+matchExpectedCmdArgs 0 ty+ = return (mkTcNomReflCo ty, [], ty)+matchExpectedCmdArgs n ty+ = do { (co1, [ty1, ty2]) <- matchExpectedTyConApp pairTyCon ty+ ; (co2, tys, res_ty) <- matchExpectedCmdArgs (n-1) ty2+ ; return (mkTcTyConAppCo Nominal pairTyCon [co1, co2], ty1:tys, res_ty) }++{-+************************************************************************+* *+ Stmts+* *+************************************************************************+-}++--------------------------------+-- Mdo-notation+-- The distinctive features here are+-- (a) RecStmts, and+-- (b) no rebindable syntax++tcArrDoStmt :: CmdEnv -> TcCmdStmtChecker+tcArrDoStmt env _ (LastStmt rhs noret _) res_ty thing_inside+ = do { rhs' <- tcCmd env rhs (unitTy, res_ty)+ ; thing <- thing_inside (panic "tcArrDoStmt")+ ; return (LastStmt rhs' noret noSyntaxExpr, thing) }++tcArrDoStmt env _ (BodyStmt rhs _ _ _) res_ty thing_inside+ = do { (rhs', elt_ty) <- tc_arr_rhs env rhs+ ; thing <- thing_inside res_ty+ ; return (BodyStmt rhs' noSyntaxExpr noSyntaxExpr elt_ty, thing) }++tcArrDoStmt env ctxt (BindStmt pat rhs _ _ _) res_ty thing_inside+ = do { (rhs', pat_ty) <- tc_arr_rhs env rhs+ ; (pat', thing) <- tcPat (StmtCtxt ctxt) pat (mkCheckExpType pat_ty) $+ thing_inside res_ty+ ; return (mkTcBindStmt pat' rhs', thing) }++tcArrDoStmt env ctxt (RecStmt { recS_stmts = stmts, recS_later_ids = later_names+ , recS_rec_ids = rec_names }) res_ty thing_inside+ = do { let tup_names = rec_names ++ filterOut (`elem` rec_names) later_names+ ; tup_elt_tys <- newFlexiTyVarTys (length tup_names) liftedTypeKind+ ; let tup_ids = zipWith mkLocalId tup_names tup_elt_tys+ ; tcExtendIdEnv tup_ids $ do+ { (stmts', tup_rets)+ <- tcStmtsAndThen ctxt (tcArrDoStmt env) stmts res_ty $ \ _res_ty' ->+ -- ToDo: res_ty not really right+ zipWithM tcCheckId tup_names (map mkCheckExpType tup_elt_tys)++ ; thing <- thing_inside res_ty+ -- NB: The rec_ids for the recursive things+ -- already scope over this part. This binding may shadow+ -- some of them with polymorphic things with the same Name+ -- (see note [RecStmt] in HsExpr)++ ; let rec_ids = takeList rec_names tup_ids+ ; later_ids <- tcLookupLocalIds later_names++ ; let rec_rets = takeList rec_names tup_rets+ ; let ret_table = zip tup_ids tup_rets+ ; let later_rets = [r | i <- later_ids, (j, r) <- ret_table, i == j]++ ; return (emptyRecStmtId { recS_stmts = stmts'+ , recS_later_ids = later_ids+ , recS_later_rets = later_rets+ , recS_rec_ids = rec_ids+ , recS_rec_rets = rec_rets+ , recS_ret_ty = res_ty }, thing)+ }}++tcArrDoStmt _ _ stmt _ _+ = pprPanic "tcArrDoStmt: unexpected Stmt" (ppr stmt)++tc_arr_rhs :: CmdEnv -> LHsCmd Name -> TcM (LHsCmd TcId, TcType)+tc_arr_rhs env rhs = do { ty <- newFlexiTyVarTy liftedTypeKind+ ; rhs' <- tcCmd env rhs (unitTy, ty)+ ; return (rhs', ty) }++{-+************************************************************************+* *+ Helpers+* *+************************************************************************+-}++mkPairTy :: Type -> Type -> Type+mkPairTy t1 t2 = mkTyConApp pairTyCon [t1,t2]++arrowTyConKind :: Kind -- *->*->*+arrowTyConKind = mkFunTys [liftedTypeKind, liftedTypeKind] liftedTypeKind++{-+************************************************************************+* *+ Errors+* *+************************************************************************+-}++cmdCtxt :: HsCmd Name -> SDoc+cmdCtxt cmd = text "In the command:" <+> ppr cmd
+ typecheck/TcBackpack.hs view
@@ -0,0 +1,903 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NondecreasingIndentation #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}+module TcBackpack (+ findExtraSigImports',+ findExtraSigImports,+ implicitRequirements',+ implicitRequirements,+ checkUnitId,+ tcRnCheckUnitId,+ tcRnMergeSignatures,+ mergeSignatures,+ tcRnInstantiateSignature,+ instantiateSignature,+) where++import BasicTypes (defaultFixity)+import Packages+import TcRnExports+import DynFlags+import HsSyn+import RdrName+import TcRnMonad+import TcTyDecls+import InstEnv+import FamInstEnv+import Inst+import TcIface+import TcMType+import TcType+import TcSimplify+import LoadIface+import RnNames+import ErrUtils+import Id+import Module+import Name+import NameEnv+import NameSet+import Avail+import SrcLoc+import HscTypes+import Outputable+import Type+import FastString+import RnEnv+import Maybes+import TcEnv+import Var+import IfaceSyn+import PrelNames+import qualified Data.Map as Map++import Finder+import UniqDSet+import NameShape+import TcErrors+import TcUnify+import RnModIface+import Util++import Control.Monad+import Data.List (find, foldl')++import {-# SOURCE #-} TcRnDriver++#include "HsVersions.h"++fixityMisMatch :: TyThing -> Fixity -> Fixity -> SDoc+fixityMisMatch real_thing real_fixity sig_fixity =+ vcat [ppr real_thing <+> text "has conflicting fixities in the module",+ text "and its hsig file",+ text "Main module:" <+> ppr_fix real_fixity,+ text "Hsig file:" <+> ppr_fix sig_fixity]+ where+ ppr_fix f =+ ppr f <+>+ (if f == defaultFixity+ then parens (text "default")+ else empty)++checkHsigDeclM :: ModIface -> TyThing -> TyThing -> TcRn ()+checkHsigDeclM sig_iface sig_thing real_thing = do+ let name = getName real_thing+ -- TODO: Distinguish between signature merging and signature+ -- implementation cases.+ checkBootDeclM False sig_thing real_thing+ real_fixity <- lookupFixityRn name+ let sig_fixity = case mi_fix_fn sig_iface (occName name) of+ Nothing -> defaultFixity+ Just f -> f+ when (real_fixity /= sig_fixity) $+ addErrAt (nameSrcSpan name)+ (fixityMisMatch real_thing real_fixity sig_fixity)++-- | Given a 'ModDetails' of an instantiated signature (note that the+-- 'ModDetails' must be knot-tied consistently with the actual implementation)+-- and a 'GlobalRdrEnv' constructed from the implementor of this interface,+-- verify that the actual implementation actually matches the original+-- interface.+--+-- Note that it is already assumed that the implementation *exports*+-- a sufficient set of entities, since otherwise the renaming and then+-- typechecking of the signature 'ModIface' would have failed.+checkHsigIface :: TcGblEnv -> GlobalRdrEnv -> ModIface -> ModDetails -> TcRn ()+checkHsigIface tcg_env gr sig_iface+ ModDetails { md_insts = sig_insts, md_fam_insts = sig_fam_insts,+ md_types = sig_type_env, md_exports = sig_exports } = do+ traceTc "checkHsigIface" $ vcat+ [ ppr sig_type_env, ppr sig_insts, ppr sig_exports ]+ mapM_ check_export (map availName sig_exports)+ unless (null sig_fam_insts) $+ panic ("TcRnDriver.checkHsigIface: Cannot handle family " +++ "instances in hsig files yet...")+ -- Delete instances so we don't look them up when+ -- checking instance satisfiability+ -- TODO: this should not be necessary+ tcg_env <- getGblEnv+ setGblEnv tcg_env { tcg_inst_env = emptyInstEnv,+ tcg_fam_inst_env = emptyFamInstEnv,+ tcg_insts = [],+ tcg_fam_insts = [] } $ do+ mapM_ check_inst sig_insts+ failIfErrsM+ where+ -- NB: the Names in sig_type_env are bogus. Let's say we have H.hsig+ -- in package p that defines T; and we implement with himpl:H. Then the+ -- Name is p[himpl:H]:H.T, NOT himplH:H.T. That's OK but we just+ -- have to look up the right name.+ sig_type_occ_env = mkOccEnv+ . map (\t -> (nameOccName (getName t), t))+ $ nameEnvElts sig_type_env+ dfun_names = map getName sig_insts+ check_export name+ -- Skip instances, we'll check them later+ -- TODO: Actually this should never happen, because DFuns are+ -- never exported...+ | name `elem` dfun_names = return ()+ -- See if we can find the type directly in the hsig ModDetails+ -- TODO: need to special case wired in names+ | Just sig_thing <- lookupOccEnv sig_type_occ_env (nameOccName name) = do+ -- NB: We use tcLookupImported_maybe because we want to EXCLUDE+ -- tcg_env (TODO: but maybe this isn't relevant anymore).+ r <- tcLookupImported_maybe name+ case r of+ Failed err -> addErr err+ Succeeded real_thing -> checkHsigDeclM sig_iface sig_thing real_thing++ -- The hsig did NOT define this function; that means it must+ -- be a reexport. In this case, make sure the 'Name' of the+ -- reexport matches the 'Name exported here.+ | [GRE { gre_name = name' }] <- lookupGlobalRdrEnv gr (nameOccName name) =+ when (name /= name') $ do+ -- See Note [Error reporting bad reexport]+ -- TODO: Actually this error swizzle doesn't work+ let p (L _ ie) = name `elem` ieNames ie+ loc = case tcg_rn_exports tcg_env of+ Just es | Just e <- find p es+ -- TODO: maybe we can be a little more+ -- precise here and use the Located+ -- info for the *specific* name we matched.+ -> getLoc e+ _ -> nameSrcSpan name+ dflags <- getDynFlags+ addErrAt loc+ (badReexportedBootThing dflags False name name')+ -- This should actually never happen, but whatever...+ | otherwise =+ addErrAt (nameSrcSpan name)+ (missingBootThing False name "exported by")++-- Note [Error reporting bad reexport]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- NB: You want to be a bit careful about what location you report on reexports.+-- If the name was declared in the hsig file, 'nameSrcSpan name' is indeed the+-- correct source location. However, if it was *reexported*, obviously the name+-- is not going to have the right location. In this case, we need to grovel in+-- tcg_rn_exports to figure out where the reexport came from.++++-- | Checks if a 'ClsInst' is "defined". In general, for hsig files we can't+-- assume that the implementing file actually implemented the instances (they+-- may be reexported from elsewhere). Where should we look for the instances?+-- We do the same as we would otherwise: consult the EPS. This isn't perfect+-- (we might conclude the module exports an instance when it doesn't, see+-- #9422), but we will never refuse to compile something.+check_inst :: ClsInst -> TcM ()+check_inst sig_inst = do+ -- TODO: This could be very well generalized to support instance+ -- declarations in boot files.+ tcg_env <- getGblEnv+ -- NB: Have to tug on the interface, not necessarily+ -- tugged... but it didn't work?+ mapM_ tcLookupImported_maybe (nameSetElemsStable (orphNamesOfClsInst sig_inst))+ -- Based off of 'simplifyDeriv'+ let ty = idType (instanceDFunId sig_inst)+ skol_info = InstSkol+ -- Based off of tcSplitDFunTy+ (tvs, theta, pred) =+ case tcSplitForAllTys ty of { (tvs, rho) ->+ case splitFunTys rho of { (theta, pred) ->+ (tvs, theta, pred) }}+ origin = InstProvidedOrigin (tcg_semantic_mod tcg_env) sig_inst+ (skol_subst, tvs_skols) <- tcInstSkolTyVars tvs -- Skolemize+ (cts, tclvl) <- pushTcLevelM $ do+ wanted <- newWanted origin+ (Just TypeLevel)+ (substTy skol_subst pred)+ givens <- forM theta $ \given -> do+ loc <- getCtLocM origin (Just TypeLevel)+ let given_pred = substTy skol_subst given+ new_ev <- newEvVar given_pred+ return CtGiven { ctev_pred = given_pred+ -- Doesn't matter, make something up+ , ctev_evar = new_ev+ , ctev_loc = loc+ }+ return $ wanted : givens+ unsolved <- simplifyWantedsTcM cts++ (implic, _) <- buildImplicationFor tclvl skol_info tvs_skols [] unsolved+ reportAllUnsolved (mkImplicWC implic)++-- | Return this list of requirement interfaces that need to be merged+-- to form @mod_name@, or @[]@ if this is not a requirement.+requirementMerges :: DynFlags -> ModuleName -> [IndefModule]+requirementMerges dflags mod_name =+ fromMaybe [] (Map.lookup mod_name (requirementContext (pkgState dflags)))++-- | For a module @modname@ of type 'HscSource', determine the list+-- of extra "imports" of other requirements which should be considered part of+-- the import of the requirement, because it transitively depends on those+-- requirements by imports of modules from other packages. The situation+-- is something like this:+--+-- unit p where+-- signature A+-- signature B+-- import A+--+-- unit q where+-- dependency p[A=<A>,B=<B>]+-- signature A+-- signature B+--+-- Although q's B does not directly import A, we still have to make sure we+-- 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 $ \(IndefModule iuid mod_name) ->+ (initIfaceLoad hsc_env+ . withException+ $ moduleFreeHolesPrecise (text "findExtraSigImports")+ (mkModule (IndefiniteUnitId iuid) mod_name)))+ where+ reqs = requirementMerges (hsc_dflags hsc_env) modname++findExtraSigImports' _ _ _ = return emptyUniqDSet++-- | 'findExtraSigImports', but in a convenient form for "GhcMake" and+-- "TcRnDriver".+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 ]++-- A version of 'implicitRequirements'' which is more friendly+-- for "GhcMake" and "TcRnDriver".+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 ]++-- 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>], then+-- they actually also import the local requirement B.+implicitRequirements' :: HscEnv+ -> [(Maybe FastString, Located ModuleName)]+ -> IO [ModuleName]+implicitRequirements' hsc_env normal_imports+ = fmap concat $+ forM normal_imports $ \(mb_pkg, L _ imp) -> do+ found <- findImportedModule hsc_env imp mb_pkg+ case found of+ Found _ mod | thisPackage dflags /= moduleUnitId mod ->+ return (uniqDSetToList (moduleFreeHoles mod))+ _ -> return []+ where dflags = hsc_dflags hsc_env++-- | Given a 'UnitId', make sure it is well typed. This is because+-- unit IDs come from Cabal, which does not know if things are well-typed or+-- not; a component may have been filled with implementations for the holes+-- that don't actually fulfill the requirements.+--+-- INVARIANT: the UnitId is NOT a InstalledUnitId+checkUnitId :: UnitId -> TcM ()+checkUnitId uid = do+ case splitUnitIdInsts uid of+ (_, Just indef) ->+ let insts = indefUnitIdInsts indef in+ forM_ insts $ \(mod_name, mod) ->+ -- NB: direct hole instantiations are well-typed by construction+ -- (because we FORCE things to be merged in), so don't check them+ when (not (isHoleModule mod)) $ do+ checkUnitId (moduleUnitId mod)+ _ <- mod `checkImplements` IndefModule indef mod_name+ return ()+ _ -> return () -- if it's hashed, must be well-typed++-- | Top-level driver for signature instantiation (run when compiling+-- an @hsig@ file.)+tcRnCheckUnitId ::+ HscEnv -> UnitId ->+ IO (Messages, Maybe ())+tcRnCheckUnitId hsc_env uid =+ withTiming (pure dflags)+ (text "Check unit id" <+> ppr uid)+ (const ()) $+ initTc hsc_env+ HsigFile -- bogus+ False+ mAIN -- bogus+ (realSrcLocSpan (mkRealSrcLoc (fsLit loc_str) 0 0)) -- bogus+ $ checkUnitId uid+ where+ dflags = hsc_dflags hsc_env+ loc_str = "Command line argument: -unit-id " ++ showSDoc dflags (ppr uid)++-- TODO: Maybe lcl_iface0 should be pre-renamed to the right thing? Unclear...++-- | Top-level driver for signature merging (run after typechecking+-- an @hsig@ file).+tcRnMergeSignatures :: HscEnv -> HsParsedModule -> TcGblEnv {- from local sig -} -> ModIface+ -> IO (Messages, Maybe TcGblEnv)+tcRnMergeSignatures hsc_env hpm orig_tcg_env iface =+ withTiming (pure dflags)+ (text "Signature merging" <+> brackets (ppr this_mod))+ (const ()) $+ initTc hsc_env HsigFile False this_mod real_loc $+ mergeSignatures hpm orig_tcg_env iface+ where+ dflags = hsc_dflags hsc_env+ this_mod = mi_module iface+ real_loc = tcg_top_loc orig_tcg_env++thinModIface :: [AvailInfo] -> ModIface -> ModIface+thinModIface avails iface =+ iface {+ mi_exports = avails,+ -- mi_fixities = ...,+ -- mi_warns = ...,+ -- mi_anns = ...,+ -- TODO: The use of nameOccName here is a bit dodgy, because+ -- perhaps there might be two IfaceTopBndr that are the same+ -- OccName but different Name. Requires better understanding+ -- of invariants here.+ mi_decls = exported_decls ++ non_exported_decls ++ dfun_decls+ -- mi_insts = ...,+ -- mi_fam_insts = ...,+ }+ where+ decl_pred occs decl = nameOccName (ifName decl) `elemOccSet` occs+ filter_decls occs = filter (decl_pred occs . snd) (mi_decls iface)++ exported_occs = mkOccSet [ occName n+ | a <- avails+ , n <- availNames a ]+ exported_decls = filter_decls exported_occs++ non_exported_occs = mkOccSet [ occName n+ | (_, d) <- exported_decls+ , n <- ifaceDeclNeverExportedRefs d ]+ non_exported_decls = filter_decls non_exported_occs++ dfun_pred IfaceId{ ifIdDetails = IfDFunId } = True+ dfun_pred _ = False+ dfun_decls = filter (dfun_pred . snd) (mi_decls iface)++-- | The list of 'Name's of *non-exported* 'IfaceDecl's which this+-- 'IfaceDecl' may refer to. A non-exported 'IfaceDecl' should be kept+-- after thinning if an *exported* 'IfaceDecl' (or 'mi_insts', perhaps)+-- refers to it; we can't decide to keep it by looking at the exports+-- of a module after thinning. Keep this synchronized with+-- 'rnIfaceDecl'.+ifaceDeclNeverExportedRefs :: IfaceDecl -> [Name]+ifaceDeclNeverExportedRefs d@IfaceFamily{} =+ case ifFamFlav d of+ IfaceClosedSynFamilyTyCon (Just (n, _))+ -> [n]+ _ -> []+ifaceDeclNeverExportedRefs _ = []+++-- Note [Blank hsigs for all requirements]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- One invariant that a client of GHC must uphold is that there+-- must be an hsig file for every requirement (according to+-- @-this-unit-id@); this ensures that for every interface+-- file (hi), there is a source file (hsig), which helps grease+-- the wheels of recompilation avoidance which assumes that+-- source files always exist.++{-+inheritedSigPvpWarning :: WarningTxt+inheritedSigPvpWarning =+ WarningTxt (noLoc NoSourceText) [noLoc (StringLiteral NoSourceText (fsLit msg))]+ where+ msg = "Inherited requirements from non-signature libraries (libraries " +++ "with modules) should not be used, as this mode of use is not " +++ "compatible with PVP-style version bounds. Instead, copy the " +++ "declaration to the local hsig file or move the signature to a " +++ "library of its own and add that library as a dependency."+-}++-- Note [Handling never-exported TyThings under Backpack]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- DEFINITION: A "never-exported TyThing" is a TyThing whose 'Name' will+-- never be mentioned in the export list of a module (mi_avails).+-- Unlike implicit TyThings (Note [Implicit TyThings]), non-exported+-- TyThings DO have a standalone IfaceDecl declaration in their+-- interface file.+--+-- Originally, Backpack was designed under the assumption that anything+-- you could declare in a module could also be exported; thus, merging+-- the export lists of two signatures is just merging the declarations+-- of two signatures writ small. Of course, in GHC Haskell, there are a+-- few important things which are not explicitly exported but still can+-- be used: in particular, dictionary functions for instances, Typeable+-- TyCon bindings, and coercion axioms for type families also count.+--+-- When handling these non-exported things, there two primary things+-- we need to watch out for:+--+-- * Signature matching/merging is done by comparing each+-- of the exported entities of a signature and a module. These exported+-- entities may refer to non-exported TyThings which must be tested for+-- consistency. For example, an instance (ClsInst) will refer to a+-- non-exported DFunId. In this case, 'checkBootDeclM' directly compares the+-- embedded 'DFunId' in 'is_dfun'.+--+-- For this to work at all, we must ensure that pointers in 'is_dfun' refer+-- to DISTINCT 'DFunId's, even though the 'Name's (may) be the same.+-- Unfortunately, this is the OPPOSITE of how we treat most other references+-- to 'Name's, so this case needs to be handled specially.+--+-- The details are in the documentation for 'typecheckIfacesForMerging'.+-- and the Note [Resolving never-exported Names in TcIface].+--+-- * When we rename modules and signatures, we use the export lists to+-- decide how the declarations should be renamed. However, this+-- means we don't get any guidance for how to rename non-exported+-- entities. Fortunately, we only need to rename these entities+-- *consistently*, so that 'typecheckIfacesForMerging' can wire them+-- up as needed.+--+-- The details are in Note [rnIfaceNeverExported] in 'RnModIface'.+--+-- The root cause for all of these complications is the fact that these+-- logically "implicit" entities are defined indirectly in an interface+-- file. #13151 gives a proposal to make these *truly* implicit.++merge_msg :: ModuleName -> [IndefModule] -> SDoc+merge_msg mod_name [] =+ text "while checking the local signature" <+> ppr mod_name <+>+ text "for consistency"+merge_msg mod_name reqs =+ hang (text "while merging the signatures from" <> colon)+ 2 (vcat [ bullet <+> ppr req | req <- reqs ] $$+ bullet <+> text "...and the local signature for" <+> ppr mod_name)++-- | Given a local 'ModIface', merge all inherited requirements+-- from 'requirementMerges' into this signature, producing+-- a final 'TcGblEnv' that matches the local signature and+-- all required signatures.+mergeSignatures :: HsParsedModule -> TcGblEnv -> ModIface -> TcRn TcGblEnv+mergeSignatures+ (HsParsedModule { hpm_module = L loc (HsModule { hsmodExports = mb_exports }),+ hpm_src_files = src_files })+ orig_tcg_env lcl_iface0 = setSrcSpan loc $ do+ -- The lcl_iface0 is the ModIface for the local hsig+ -- file, which is guaranteed to exist, see+ -- Note [Blank hsigs for all requirements]+ hsc_env <- getTopEnv+ dflags <- getDynFlags+ tcg_env <- getGblEnv+ let outer_mod = tcg_mod tcg_env+ inner_mod = tcg_semantic_mod tcg_env+ mod_name = moduleName (tcg_mod tcg_env)++ -- STEP 1: Figure out all of the external signature interfaces+ -- we are going to merge in.+ let reqs = requirementMerges dflags mod_name++ addErrCtxt (merge_msg mod_name reqs) $ do++ -- STEP 2: Read in the RAW forms of all of these interfaces+ ireq_ifaces0 <- forM reqs $ \(IndefModule iuid mod_name) ->+ let m = mkModule (IndefiniteUnitId iuid) mod_name+ im = fst (splitModuleInsts m)+ in fmap fst+ . withException+ $ findAndReadIface (text "mergeSignatures") im m False++ -- STEP 3: Get the unrenamed exports of all these interfaces,+ -- thin it according to the export list, and do shaping on them.+ let extend_ns nsubst as = liftIO $ extendNameShape hsc_env nsubst as+ -- This function gets run on every inherited interface, and+ -- it's responsible for:+ --+ -- 1. Merging the exports of the interface into @nsubst@,+ -- 2. Adding these exports to the "OK to import" set (@oks@)+ -- if they came from a package with no exposed modules+ -- (this means we won't report a PVP error in this case), and+ -- 3. Thinning the interface according to an explicit export+ -- list.+ --+ gen_subst (nsubst,oks,ifaces) (imod@(IndefModule iuid _), ireq_iface) = do+ let insts = indefUnitIdInsts iuid+ as1 <- tcRnModExports insts ireq_iface+ let inst_uid = fst (splitUnitIdInsts (IndefiniteUnitId iuid))+ pkg = getInstalledPackageDetails dflags inst_uid+ -- Setup the import spec correctly, so that when we apply+ -- IEModuleContents we pick up EVERYTHING+ ispec = ImpSpec+ ImpDeclSpec{+ is_mod = mod_name,+ is_as = mod_name,+ is_qual = False,+ is_dloc = loc+ } ImpAll+ rdr_env = mkGlobalRdrEnv (gresFromAvails (Just ispec) as1)+ (thinned_iface, as2) <- case mb_exports of+ Just (L loc _)+ | null (exposedModules pkg) -> setSrcSpan loc $ do+ -- Suppress missing errors; we'll pick em up+ -- when we test exports on the final thing+ (msgs, mb_r) <- tryTc $+ setGblEnv tcg_env {+ tcg_rdr_env = rdr_env+ } $ exports_from_avail mb_exports rdr_env+ (tcg_imports tcg_env) (tcg_semantic_mod tcg_env)+ case mb_r of+ Just (_, as2) -> return (thinModIface as2 ireq_iface, as2)+ Nothing -> addMessages msgs >> failM+ _ -> return (ireq_iface, as1)+ let oks' | null (exposedModules pkg)+ = extendOccSetList oks (exportOccs as2)+ | otherwise+ = oks+ mb_r <- extend_ns nsubst as2+ case mb_r of+ Left err -> failWithTc err+ Right nsubst' -> return (nsubst',oks',(imod, thinned_iface):ifaces)+ nsubst0 = mkNameShape (moduleName inner_mod) (mi_exports lcl_iface0)+ ok_to_use0 = mkOccSet (exportOccs (mi_exports lcl_iface0))+ -- Process each interface, getting the thinned interfaces as well as+ -- the final, full set of exports @nsubst@ and the exports which are+ -- "ok to use" (we won't attach 'inheritedSigPvpWarning' to them.)+ (nsubst, ok_to_use, rev_thinned_ifaces)+ <- foldM gen_subst (nsubst0, ok_to_use0, []) (zip reqs ireq_ifaces0)+ let thinned_ifaces = reverse rev_thinned_ifaces+ exports = nameShapeExports nsubst+ rdr_env = mkGlobalRdrEnv (gresFromAvails Nothing exports)+ _warn_occs = filter (not . (`elemOccSet` ok_to_use)) (exportOccs exports)+ warns = NoWarnings+ {-+ -- TODO: Warnings are transitive, but this is not what we want here:+ -- if a module reexports an entity from a signature, that should be OK.+ -- Not supported in current warning framework+ warns | null warn_occs = NoWarnings+ | otherwise = WarnSome $ map (\o -> (o, inheritedSigPvpWarning)) warn_occs+ -}+ setGblEnv tcg_env {+ -- The top-level GlobalRdrEnv is quite interesting. It consists+ -- of two components:+ -- 1. First, we reuse the GlobalRdrEnv of the local signature.+ -- This is very useful, because it means that if we have+ -- to print a message involving some entity that the local+ -- signature imported, we'll qualify it accordingly.+ -- 2. Second, we need to add all of the declarations we are+ -- going to merge in (as they need to be in scope for the+ -- final test of the export list.)+ tcg_rdr_env = rdr_env `plusGlobalRdrEnv` tcg_rdr_env orig_tcg_env,+ -- Inherit imports from the local signature, so that module+ -- rexports are picked up correctly+ tcg_imports = tcg_imports orig_tcg_env,+ tcg_exports = exports,+ tcg_dus = usesOnly (availsToNameSetWithSelectors exports),+ tcg_warns = warns+ } $ do+ tcg_env <- getGblEnv++ -- Make sure we didn't refer to anything that doesn't actually exist+ -- pprTrace "mergeSignatures: exports_from_avail" (ppr exports) $ return ()+ (mb_lies, _) <- exports_from_avail mb_exports rdr_env+ (tcg_imports tcg_env) (tcg_semantic_mod tcg_env)++ -- If you tried to explicitly export an identifier that has a warning+ -- attached to it, that's probably a mistake. Warn about it.+ case mb_lies of+ Nothing -> return ()+ Just lies ->+ forM_ (concatMap (\(L loc x) -> map (L loc) (ieNames x)) lies) $ \(L loc n) ->+ setSrcSpan loc $+ unless (nameOccName n `elemOccSet` ok_to_use) $+ addWarn NoReason $ vcat [+ text "Exported identifier" <+> quotes (ppr n) <+> text "will cause warnings if used.",+ parens (text "To suppress this warning, remove" <+> quotes (ppr n) <+> text "from the export list of this signature.")+ ]++ failIfErrsM++ -- STEP 4: Rename the interfaces+ ext_ifaces <- forM thinned_ifaces $ \((IndefModule iuid _), ireq_iface) ->+ tcRnModIface (indefUnitIdInsts iuid) (Just nsubst) ireq_iface+ lcl_iface <- tcRnModIface (thisUnitIdInsts dflags) (Just nsubst) lcl_iface0+ let ifaces = lcl_iface : ext_ifaces++ -- STEP 4.1: Merge fixities (we'll verify shortly) tcg_fix_env+ let fix_env = mkNameEnv [ (gre_name rdr_elt, FixItem occ f)+ | (occ, f) <- concatMap mi_fixities ifaces+ , rdr_elt <- lookupGlobalRdrEnv rdr_env occ ]++ -- STEP 5: Typecheck the interfaces+ let type_env_var = tcg_type_env_var tcg_env++ -- typecheckIfacesForMerging does two things:+ -- 1. It merges the all of the ifaces together, and typechecks the+ -- result to type_env.+ -- 2. It typechecks each iface individually, but with their 'Name's+ -- resolving to the merged type_env from (1).+ -- See typecheckIfacesForMerging for more details.+ (type_env, detailss) <- initIfaceTcRn $+ typecheckIfacesForMerging inner_mod ifaces type_env_var+ let infos = zip ifaces detailss++ -- Test for cycles+ checkSynCycles (thisPackage dflags) (typeEnvTyCons type_env) []++ -- NB on type_env: it contains NO dfuns. DFuns are recorded inside+ -- detailss, and given a Name that doesn't correspond to anything real. See+ -- also Note [Signature merging DFuns]++ -- Add the merged type_env to TcGblEnv, so that it gets serialized+ -- out when we finally write out the interface.+ --+ -- NB: Why do we set tcg_tcs/tcg_patsyns/tcg_type_env directly,+ -- rather than use tcExtendGlobalEnv (the normal method to add newly+ -- defined types to TcGblEnv?) tcExtendGlobalEnv adds these+ -- TyThings to 'tcg_type_env_var', which is consulted when+ -- we read in interfaces to tie the knot. But *these TyThings themselves+ -- come from interface*, so that would result in deadlock. Don't+ -- update it!+ setGblEnv tcg_env {+ tcg_tcs = typeEnvTyCons type_env,+ tcg_patsyns = typeEnvPatSyns type_env,+ tcg_type_env = type_env,+ tcg_fix_env = fix_env+ } $ do+ tcg_env <- getGblEnv++ -- STEP 6: Check for compatibility/merge things+ tcg_env <- (\x -> foldM x tcg_env infos)+ $ \tcg_env (iface, details) -> do++ let check_export name+ | Just sig_thing <- lookupTypeEnv (md_types details) name+ = case lookupTypeEnv type_env (getName sig_thing) of+ Just thing -> checkHsigDeclM iface sig_thing thing+ Nothing -> panic "mergeSignatures: check_export"+ -- Oops! We're looking for this export but it's+ -- not actually in the type environment of the signature's+ -- ModDetails.+ --+ -- NB: This case happens because the we're iterating+ -- over the union of all exports, so some interfaces+ -- won't have everything. Note that md_exports is nonsense+ -- (it's the same as exports); maybe we should fix this+ -- eventually.+ | otherwise+ = return ()+ mapM_ check_export (map availName exports)++ -- Note [Signature merging instances]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Merge instances into the global environment. The algorithm here is+ -- dumb and simple: if an instance has exactly the same DFun type+ -- (tested by 'memberInstEnv') as an existing instance, we drop it;+ -- otherwise, we add it even, even if this would cause overlap.+ --+ -- Why don't we deduplicate instances with identical heads? There's no+ -- good choice if they have premises:+ --+ -- instance K1 a => K (T a)+ -- instance K2 a => K (T a)+ --+ -- Why not eagerly error in this case? The overlapping head does not+ -- necessarily mean that the instances are unimplementable: in fact,+ -- they may be implemented without overlap (if, for example, the+ -- implementing module has 'instance K (T a)'; both are implemented in+ -- this case.) The implements test just checks that the wanteds are+ -- derivable assuming the givens.+ --+ -- Still, overlapping instances with hypotheses like above are going+ -- to be a bad deal, because instance resolution when we're typechecking+ -- against the merged signature is going to have a bad time when+ -- there are overlapping heads like this: we never backtrack, so it+ -- may be difficult to see that a wanted is derivable. For now,+ -- we hope that we get lucky / the overlapping instances never+ -- get used, but it is not a very good situation to be in.+ --+ let merge_inst (insts, inst_env) inst+ | memberInstEnv inst_env inst -- test DFun Type equality+ = (insts, inst_env)+ | otherwise+ -- NB: is_dfun_name inst is still nonsense here,+ -- see Note [Signature merging DFuns]+ = (inst:insts, extendInstEnv inst_env inst)+ (insts, inst_env) = foldl' merge_inst+ (tcg_insts tcg_env, tcg_inst_env tcg_env)+ (md_insts details)+ -- This is a HACK to prevent calculateAvails from including imp_mod+ -- in the listing. We don't want it because a module is NOT+ -- supposed to include itself in its dep_orphs/dep_finsts. See #13214+ iface' = iface { mi_orphan = False, mi_finsts = False }+ avails = plusImportAvails (tcg_imports tcg_env) $+ calculateAvails dflags iface' False False ImportedBySystem+ return tcg_env {+ tcg_inst_env = inst_env,+ tcg_insts = insts,+ tcg_imports = avails,+ tcg_merged =+ if outer_mod == mi_module iface+ -- Don't add ourselves!+ then tcg_merged tcg_env+ else (mi_module iface, mi_mod_hash iface) : tcg_merged tcg_env+ }++ -- Note [Signature merging DFuns]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Once we know all of instances which will be defined by this merged+ -- signature, we go through each of the DFuns and rename them with a fresh,+ -- new, unique DFun Name, and add these DFuns to tcg_type_env (thus fixing+ -- up the "bogus" names that were setup in 'typecheckIfacesForMerging'.+ --+ -- We can't do this fixup earlier, because we need a way to identify each+ -- source DFun (from each of the signatures we are merging in) so that+ -- when we have a ClsInst, we can pull up the correct DFun to check if+ -- the types match.+ --+ -- See also Note [rnIfaceNeverExported] in RnModIface+ dfun_insts <- forM (tcg_insts tcg_env) $ \inst -> do+ n <- newDFunName (is_cls inst) (is_tys inst) (nameSrcSpan (is_dfun_name inst))+ let dfun = setVarName (is_dfun inst) n+ return (dfun, inst { is_dfun_name = n, is_dfun = dfun })+ tcg_env <- return tcg_env {+ tcg_insts = map snd dfun_insts,+ tcg_type_env = extendTypeEnvWithIds (tcg_type_env tcg_env) (map fst dfun_insts)+ }++ addDependentFiles src_files++ return tcg_env++-- | Top-level driver for signature instantiation (run when compiling+-- an @hsig@ file.)+tcRnInstantiateSignature ::+ HscEnv -> Module -> RealSrcSpan ->+ IO (Messages, Maybe TcGblEnv)+tcRnInstantiateSignature hsc_env this_mod real_loc =+ withTiming (pure dflags)+ (text "Signature instantiation"<+>brackets (ppr this_mod))+ (const ()) $+ initTc hsc_env HsigFile False this_mod real_loc $ instantiateSignature+ where+ dflags = hsc_dflags hsc_env++exportOccs :: [AvailInfo] -> [OccName]+exportOccs = concatMap (map occName . availNames)++impl_msg :: Module -> IndefModule -> SDoc+impl_msg impl_mod (IndefModule req_uid req_mod_name) =+ text "while checking that" <+> ppr impl_mod <+>+ text "implements signature" <+> ppr req_mod_name <+>+ text "in" <+> ppr req_uid++-- | Check if module implements a signature. (The signature is+-- always un-hashed, which is why its components are specified+-- explicitly.)+checkImplements :: Module -> IndefModule -> TcRn TcGblEnv+checkImplements impl_mod req_mod@(IndefModule uid mod_name) =+ addErrCtxt (impl_msg impl_mod req_mod) $ do+ let insts = indefUnitIdInsts uid++ -- STEP 1: Load the implementing interface, and make a RdrEnv+ -- for its exports. Also, add its 'ImportAvails' to 'tcg_imports',+ -- so that we treat all orphan instances it provides as visible+ -- when we verify that all instances are checked (see #12945), and so that+ -- when we eventually write out the interface we record appropriate+ -- dependency information.+ impl_iface <- initIfaceTcRn $+ loadSysInterface (text "checkImplements 1") impl_mod+ let impl_gr = mkGlobalRdrEnv+ (gresFromAvails Nothing (mi_exports impl_iface))+ nsubst = mkNameShape (moduleName impl_mod) (mi_exports impl_iface)++ -- Load all the orphans, so the subsequent 'checkHsigIface' sees+ -- all the instances it needs to+ loadModuleInterfaces (text "Loading orphan modules (from implementor of hsig)")+ (dep_orphs (mi_deps impl_iface))++ dflags <- getDynFlags+ let avails = calculateAvails dflags+ impl_iface False{- safe -} False{- boot -} ImportedBySystem+ fix_env = mkNameEnv [ (gre_name rdr_elt, FixItem occ f)+ | (occ, f) <- mi_fixities impl_iface+ , rdr_elt <- lookupGlobalRdrEnv impl_gr occ ]+ updGblEnv (\tcg_env -> tcg_env {+ -- Setting tcg_rdr_env to treat all exported entities from+ -- the implementing module as in scope improves error messages,+ -- as it reduces the amount of qualification we need. Unfortunately,+ -- we still end up qualifying references to external modules+ -- (see bkpfail07 for an example); we'd need to record more+ -- information in ModIface to solve this.+ tcg_rdr_env = tcg_rdr_env tcg_env `plusGlobalRdrEnv` impl_gr,+ tcg_imports = tcg_imports tcg_env `plusImportAvails` avails,+ -- This is here so that when we call 'lookupFixityRn' for something+ -- directly implemented by the module, we grab the right thing+ tcg_fix_env = fix_env+ }) $ do++ -- STEP 2: Load the *unrenamed, uninstantiated* interface for+ -- the ORIGINAL signature. We are going to eventually rename it,+ -- but we must proceed slowly, because it is NOT known if the+ -- instantiation is correct.+ let sig_mod = mkModule (IndefiniteUnitId uid) mod_name+ isig_mod = fst (splitModuleInsts sig_mod)+ mb_isig_iface <- findAndReadIface (text "checkImplements 2") isig_mod sig_mod False+ isig_iface <- case mb_isig_iface of+ Succeeded (iface, _) -> return iface+ Failed err -> failWithTc $+ hang (text "Could not find hi interface for signature" <+>+ quotes (ppr isig_mod) <> colon) 4 err++ -- STEP 3: Check that the implementing interface exports everything+ -- we need. (Notice we IGNORE the Modules in the AvailInfos.)+ forM_ (exportOccs (mi_exports isig_iface)) $ \occ ->+ case lookupGlobalRdrEnv impl_gr occ of+ [] -> addErr $ quotes (ppr occ)+ <+> text "is exported by the hsig file, but not"+ <+> text "exported by the implementing module"+ <+> quotes (ppr impl_mod)+ _ -> return ()+ failIfErrsM++ -- STEP 4: Now that the export is complete, rename the interface...+ sig_iface <- tcRnModIface insts (Just nsubst) isig_iface++ -- STEP 5: ...and typecheck it. (Note that in both cases, the nsubst+ -- lets us determine how top-level identifiers should be handled.)+ sig_details <- initIfaceTcRn $ typecheckIfaceForInstantiate nsubst sig_iface++ -- STEP 6: Check that it's sufficient+ tcg_env <- getGblEnv+ checkHsigIface tcg_env impl_gr sig_iface sig_details++ -- STEP 7: Return the updated 'TcGblEnv' with the signature exports,+ -- so we write them out.+ return tcg_env {+ tcg_exports = mi_exports sig_iface+ }++-- | Given 'tcg_mod', instantiate a 'ModIface' from the indefinite+-- library to use the actual implementations of the relevant entities,+-- checking that the implementation matches the signature.+instantiateSignature :: TcRn TcGblEnv+instantiateSignature = do+ tcg_env <- getGblEnv+ dflags <- getDynFlags+ let outer_mod = tcg_mod tcg_env+ inner_mod = tcg_semantic_mod tcg_env+ -- TODO: setup the local RdrEnv so the error messages look a little better.+ -- But this information isn't stored anywhere. Should we RETYPECHECK+ -- the local one just to get the information? Hmm...+ MASSERT( moduleUnitId outer_mod == thisPackage dflags )+ inner_mod `checkImplements`+ IndefModule+ (newIndefUnitId (thisComponentId dflags)+ (thisUnitIdInsts dflags))+ (moduleName outer_mod)
+ typecheck/TcBinds.hs view
@@ -0,0 +1,1730 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[TcBinds]{TcBinds}+-}++{-# LANGUAGE CPP, RankNTypes, ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}++module TcBinds ( tcLocalBinds, tcTopBinds, tcRecSelBinds,+ tcHsBootSigs, tcPolyCheck,+ tcVectDecls, addTypecheckedBinds,+ chooseInferredQuantifiers,+ badBootDeclErr ) where++import {-# SOURCE #-} TcMatches ( tcGRHSsPat, tcMatchesFun )+import {-# SOURCE #-} TcExpr ( tcMonoExpr )+import {-# SOURCE #-} TcPatSyn ( tcInferPatSynDecl, tcCheckPatSynDecl+ , tcPatSynBuilderBind )+import CoreSyn (Tickish (..))+import CostCentre (mkUserCC)+import DynFlags+import FastString+import HsSyn+import HscTypes( isHsBootOrSig )+import TcSigs+import TcRnMonad+import TcEnv+import TcUnify+import TcSimplify+import TcEvidence+import TcHsType+import TcPat+import TcMType+import FamInstEnv( normaliseType )+import FamInst( tcGetFamInstEnvs )+import TyCon+import TcType+import Type( mkStrLitTy, tidyOpenType, mkTyVarBinder, splitTyConApp_maybe)+import TysPrim+import TysWiredIn( cTupleTyConName )+import Id+import Var+import VarSet+import VarEnv( TidyEnv )+import Module+import Name+import NameSet+import NameEnv+import SrcLoc+import Bag+import ListSetOps+import ErrUtils+import Digraph+import Maybes+import Util+import BasicTypes+import Outputable+import PrelNames( ipClassName )+import TcValidity (checkValidType)+import Unique (getUnique)+import UniqFM+import UniqSet+import qualified GHC.LanguageExtensions as LangExt+import ConLike++import Control.Monad++#include "HsVersions.h"++{- *********************************************************************+* *+ A useful helper function+* *+********************************************************************* -}++addTypecheckedBinds :: TcGblEnv -> [LHsBinds Id] -> TcGblEnv+addTypecheckedBinds tcg_env binds+ | isHsBootOrSig (tcg_src tcg_env) = tcg_env+ -- Do not add the code for record-selector bindings+ -- when compiling hs-boot files+ | otherwise = tcg_env { tcg_binds = foldr unionBags+ (tcg_binds tcg_env)+ binds }++{-+************************************************************************+* *+\subsection{Type-checking bindings}+* *+************************************************************************++@tcBindsAndThen@ typechecks a @HsBinds@. The "and then" part is because+it needs to know something about the {\em usage} of the things bound,+so that it can create specialisations of them. So @tcBindsAndThen@+takes a function which, given an extended environment, E, typechecks+the scope of the bindings returning a typechecked thing and (most+important) an LIE. It is this LIE which is then used as the basis for+specialising the things bound.++@tcBindsAndThen@ also takes a "combiner" which glues together the+bindings and the "thing" to make a new "thing".++The real work is done by @tcBindWithSigsAndThen@.++Recursive and non-recursive binds are handled in essentially the same+way: because of uniques there are no scoping issues left. The only+difference is that non-recursive bindings can bind primitive values.++Even for non-recursive binding groups we add typings for each binder+to the LVE for the following reason. When each individual binding is+checked the type of its LHS is unified with that of its RHS; and+type-checking the LHS of course requires that the binder is in scope.++At the top-level the LIE is sure to contain nothing but constant+dictionaries, which we resolve at the module level.++Note [Polymorphic recursion]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The game plan for polymorphic recursion in the code above is++ * Bind any variable for which we have a type signature+ to an Id with a polymorphic type. Then when type-checking+ the RHSs we'll make a full polymorphic call.++This fine, but if you aren't a bit careful you end up with a horrendous+amount of partial application and (worse) a huge space leak. For example:++ f :: Eq a => [a] -> [a]+ f xs = ...f...++If we don't take care, after typechecking we get++ f = /\a -> \d::Eq a -> let f' = f a d+ in+ \ys:[a] -> ...f'...++Notice the the stupid construction of (f a d), which is of course+identical to the function we're executing. In this case, the+polymorphic recursion isn't being used (but that's a very common case).+This can lead to a massive space leak, from the following top-level defn+(post-typechecking)++ ff :: [Int] -> [Int]+ ff = f Int dEqInt++Now (f dEqInt) evaluates to a lambda that has f' as a free variable; but+f' is another thunk which evaluates to the same thing... and you end+up with a chain of identical values all hung onto by the CAF ff.++ ff = f Int dEqInt++ = let f' = f Int dEqInt in \ys. ...f'...++ = let f' = let f' = f Int dEqInt in \ys. ...f'...+ in \ys. ...f'...++Etc.++NOTE: a bit of arity anaysis would push the (f a d) inside the (\ys...),+which would make the space leak go away in this case++Solution: when typechecking the RHSs we always have in hand the+*monomorphic* Ids for each binding. So we just need to make sure that+if (Method f a d) shows up in the constraints emerging from (...f...)+we just use the monomorphic Id. We achieve this by adding monomorphic Ids+to the "givens" when simplifying constraints. That's what the "lies_avail"+is doing.++Then we get++ f = /\a -> \d::Eq a -> letrec+ fm = \ys:[a] -> ...fm...+ in+ fm+-}++tcTopBinds :: [(RecFlag, LHsBinds Name)] -> [LSig Name] -> TcM (TcGblEnv, TcLclEnv)+-- The TcGblEnv contains the new tcg_binds and tcg_spects+-- The TcLclEnv has an extended type envt for the new bindings+tcTopBinds binds sigs+ = do { -- Pattern synonym bindings populate the global environment+ (binds', (tcg_env, tcl_env)) <- tcValBinds TopLevel binds sigs $+ do { gbl <- getGblEnv+ ; lcl <- getLclEnv+ ; return (gbl, lcl) }+ ; specs <- tcImpPrags sigs -- SPECIALISE prags for imported Ids++ ; complete_matches <- setEnvs (tcg_env, tcl_env) $ tcCompleteSigs sigs+ ; traceTc "complete_matches" (ppr binds $$ ppr sigs)+ ; traceTc "complete_matches" (ppr complete_matches)++ ; let { tcg_env' = tcg_env { tcg_imp_specs+ = specs ++ tcg_imp_specs tcg_env+ , tcg_complete_matches+ = complete_matches+ ++ tcg_complete_matches tcg_env }+ `addTypecheckedBinds` map snd binds' }++ ; return (tcg_env', tcl_env) }+ -- The top level bindings are flattened into a giant+ -- implicitly-mutually-recursive LHsBinds+++-- Note [Typechecking Complete Matches]+-- Much like when a user bundled a pattern synonym, the result types of+-- all the constructors in the match pragma must be consistent.+--+-- If we allowed pragmas with inconsistent types then it would be+-- impossible to ever match every constructor in the list and so+-- the pragma would be useless.++++++-- This is only used in `tcCompleteSig`. We fold over all the conlikes,+-- this accumulator keeps track of the first `ConLike` with a concrete+-- return type. After fixing the return type, all other constructors with+-- a fixed return type must agree with this.+--+-- The fields of `Fixed` cache the first conlike and its return type so+-- that that we can compare all the other conlikes to it. The conlike is+-- stored for error messages.+--+-- `Nothing` in the case that the type is fixed by a type signature+data CompleteSigType = AcceptAny | Fixed (Maybe ConLike) TyCon++tcCompleteSigs :: [LSig Name] -> TcM [CompleteMatch]+tcCompleteSigs sigs =+ let+ doOne :: Sig Name -> TcM (Maybe CompleteMatch)+ doOne c@(CompleteMatchSig _ lns mtc)+ = fmap Just $ do+ addErrCtxt (text "In" <+> ppr c) $+ case mtc of+ Nothing -> infer_complete_match+ Just tc -> check_complete_match tc+ where++ checkCLTypes acc = foldM checkCLType (acc, []) (unLoc lns)++ infer_complete_match = do+ (res, cls) <- checkCLTypes AcceptAny+ case res of+ AcceptAny -> failWithTc ambiguousError+ Fixed _ tc -> return $ mkMatch cls tc++ check_complete_match tc_name = do+ ty_con <- tcLookupLocatedTyCon tc_name+ (_, cls) <- checkCLTypes (Fixed Nothing ty_con)+ return $ mkMatch cls ty_con++ mkMatch :: [ConLike] -> TyCon -> CompleteMatch+ mkMatch cls ty_con = CompleteMatch {+ completeMatchConLikes = map conLikeName cls,+ completeMatchTyCon = tyConName ty_con+ }+ doOne _ = return Nothing++ ambiguousError :: SDoc+ ambiguousError =+ text "A type signature must be provided for a set of polymorphic"+ <+> text "pattern synonyms."+++ -- See note [Typechecking Complete Matches]+ checkCLType :: (CompleteSigType, [ConLike]) -> Located Name+ -> TcM (CompleteSigType, [ConLike])+ checkCLType (cst, cs) n = do+ cl <- addLocM tcLookupConLike n+ let (_,_,_,_,_,_, res_ty) = conLikeFullSig cl+ res_ty_con = fst <$> splitTyConApp_maybe res_ty+ case (cst, res_ty_con) of+ (AcceptAny, Nothing) -> return (AcceptAny, cl:cs)+ (AcceptAny, Just tc) -> return (Fixed (Just cl) tc, cl:cs)+ (Fixed mfcl tc, Nothing) -> return (Fixed mfcl tc, cl:cs)+ (Fixed mfcl tc, Just tc') ->+ if tc == tc'+ then return (Fixed mfcl tc, cl:cs)+ else case mfcl of+ Nothing ->+ addErrCtxt (text "In" <+> ppr cl) $+ failWithTc typeSigErrMsg+ Just cl -> failWithTc (errMsg cl)+ where+ typeSigErrMsg :: SDoc+ typeSigErrMsg =+ text "Couldn't match expected type"+ <+> quotes (ppr tc)+ <+> text "with"+ <+> quotes (ppr tc')++ errMsg :: ConLike -> SDoc+ errMsg fcl =+ text "Cannot form a group of complete patterns from patterns"+ <+> quotes (ppr fcl) <+> text "and" <+> quotes (ppr cl)+ <+> text "as they match different type constructors"+ <+> parens (quotes (ppr tc)+ <+> text "resp."+ <+> quotes (ppr tc'))+ in mapMaybeM (addLocM doOne) sigs++tcRecSelBinds :: HsValBinds Name -> TcM TcGblEnv+tcRecSelBinds (ValBindsOut binds sigs)+ = tcExtendGlobalValEnv [sel_id | L _ (IdSig sel_id) <- sigs] $+ do { (rec_sel_binds, tcg_env) <- discardWarnings $+ tcValBinds TopLevel binds sigs getGblEnv+ ; let tcg_env' = tcg_env `addTypecheckedBinds` map snd rec_sel_binds+ ; return tcg_env' }+tcRecSelBinds (ValBindsIn {}) = panic "tcRecSelBinds"++tcHsBootSigs :: [(RecFlag, LHsBinds Name)] -> [LSig Name] -> TcM [Id]+-- A hs-boot file has only one BindGroup, and it only has type+-- signatures in it. The renamer checked all this+tcHsBootSigs binds sigs+ = do { checkTc (null binds) badBootDeclErr+ ; concat <$> mapM (addLocM tc_boot_sig) (filter isTypeLSig sigs) }+ where+ tc_boot_sig (TypeSig lnames hs_ty) = mapM f lnames+ where+ f (L _ name)+ = do { sigma_ty <- tcHsSigWcType (FunSigCtxt name False) hs_ty+ ; return (mkVanillaGlobal name sigma_ty) }+ -- Notice that we make GlobalIds, not LocalIds+ tc_boot_sig s = pprPanic "tcHsBootSigs/tc_boot_sig" (ppr s)++badBootDeclErr :: MsgDoc+badBootDeclErr = text "Illegal declarations in an hs-boot file"++------------------------+tcLocalBinds :: HsLocalBinds Name -> TcM thing+ -> TcM (HsLocalBinds TcId, thing)++tcLocalBinds EmptyLocalBinds thing_inside+ = do { thing <- thing_inside+ ; return (EmptyLocalBinds, thing) }++tcLocalBinds (HsValBinds (ValBindsOut binds sigs)) thing_inside+ = do { (binds', thing) <- tcValBinds NotTopLevel binds sigs thing_inside+ ; return (HsValBinds (ValBindsOut binds' sigs), thing) }+tcLocalBinds (HsValBinds (ValBindsIn {})) _ = panic "tcLocalBinds"++tcLocalBinds (HsIPBinds (IPBinds ip_binds _)) thing_inside+ = do { ipClass <- tcLookupClass ipClassName+ ; (given_ips, ip_binds') <-+ mapAndUnzipM (wrapLocSndM (tc_ip_bind ipClass)) ip_binds++ -- If the binding binds ?x = E, we must now+ -- discharge any ?x constraints in expr_lie+ -- See Note [Implicit parameter untouchables]+ ; (ev_binds, result) <- checkConstraints (IPSkol ips)+ [] given_ips thing_inside++ ; return (HsIPBinds (IPBinds ip_binds' ev_binds), result) }+ where+ ips = [ip | L _ (IPBind (Left (L _ ip)) _) <- ip_binds]++ -- I wonder if we should do these one at at time+ -- Consider ?x = 4+ -- ?y = ?x + 1+ tc_ip_bind ipClass (IPBind (Left (L _ ip)) expr)+ = do { ty <- newOpenFlexiTyVarTy+ ; let p = mkStrLitTy $ hsIPNameFS ip+ ; ip_id <- newDict ipClass [ p, ty ]+ ; expr' <- tcMonoExpr expr (mkCheckExpType ty)+ ; let d = toDict ipClass p ty `fmap` expr'+ ; return (ip_id, (IPBind (Right ip_id) d)) }+ tc_ip_bind _ (IPBind (Right {}) _) = panic "tc_ip_bind"++ -- Coerces a `t` into a dictionry for `IP "x" t`.+ -- co : t -> IP "x" t+ toDict ipClass x ty = HsWrap $ mkWpCastR $+ wrapIP $ mkClassPred ipClass [x,ty]++{- Note [Implicit parameter untouchables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We add the type variables in the types of the implicit parameters+as untouchables, not so much because we really must not unify them,+but rather because we otherwise end up with constraints like this+ Num alpha, Implic { wanted = alpha ~ Int }+The constraint solver solves alpha~Int by unification, but then+doesn't float that solved constraint out (it's not an unsolved+wanted). Result disaster: the (Num alpha) is again solved, this+time by defaulting. No no no.++However [Oct 10] this is all handled automatically by the+untouchable-range idea.+-}++tcValBinds :: TopLevelFlag+ -> [(RecFlag, LHsBinds Name)] -> [LSig Name]+ -> TcM thing+ -> TcM ([(RecFlag, LHsBinds TcId)], thing)++tcValBinds top_lvl binds sigs thing_inside+ = do { let patsyns = getPatSynBinds binds++ -- Typecheck the signature+ ; (poly_ids, sig_fn) <- tcAddPatSynPlaceholders patsyns $+ tcTySigs sigs++ ; let prag_fn = mkPragEnv sigs (foldr (unionBags . snd) emptyBag binds)++ -- Extend the envt right away with all the Ids+ -- declared with complete type signatures+ -- Do not extend the TcIdBinderStack; instead+ -- we extend it on a per-rhs basis in tcExtendForRhs+ ; tcExtendSigIds top_lvl poly_ids $ do+ { (binds', (extra_binds', thing)) <- tcBindGroups top_lvl sig_fn prag_fn binds $ do+ { thing <- thing_inside+ -- See Note [Pattern synonym builders don't yield dependencies]+ -- in RnBinds+ ; patsyn_builders <- mapM tcPatSynBuilderBind patsyns+ ; let extra_binds = [ (NonRecursive, builder) | builder <- patsyn_builders ]+ ; return (extra_binds, thing) }+ ; return (binds' ++ extra_binds', thing) }}++------------------------+tcBindGroups :: TopLevelFlag -> TcSigFun -> TcPragEnv+ -> [(RecFlag, LHsBinds Name)] -> TcM thing+ -> TcM ([(RecFlag, LHsBinds TcId)], thing)+-- Typecheck a whole lot of value bindings,+-- one strongly-connected component at a time+-- Here a "strongly connected component" has the strightforward+-- meaning of a group of bindings that mention each other,+-- ignoring type signatures (that part comes later)++tcBindGroups _ _ _ [] thing_inside+ = do { thing <- thing_inside+ ; return ([], thing) }++tcBindGroups top_lvl sig_fn prag_fn (group : groups) thing_inside+ = do { -- See Note [Closed binder groups]+ type_env <- getLclTypeEnv+ ; let closed = isClosedBndrGroup type_env (snd group)+ ; (group', (groups', thing))+ <- tc_group top_lvl sig_fn prag_fn group closed $+ tcBindGroups top_lvl sig_fn prag_fn groups thing_inside+ ; return (group' ++ groups', thing) }++-- Note [Closed binder groups]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- A mutually recursive group is "closed" if all of the free variables of+-- the bindings are closed. For example+--+-- > h = \x -> let f = ...g...+-- > g = ....f...x...+-- > in ...+--+-- Here @g@ is not closed because it mentions @x@; and hence neither is @f@+-- closed.+--+-- So we need to compute closed-ness on each strongly connected components,+-- before we sub-divide it based on what type signatures it has.+--++------------------------+tc_group :: forall thing.+ TopLevelFlag -> TcSigFun -> TcPragEnv+ -> (RecFlag, LHsBinds Name) -> IsGroupClosed -> TcM thing+ -> TcM ([(RecFlag, LHsBinds TcId)], thing)++-- Typecheck one strongly-connected component of the original program.+-- We get a list of groups back, because there may+-- be specialisations etc as well++tc_group top_lvl sig_fn prag_fn (NonRecursive, binds) closed thing_inside+ -- A single non-recursive binding+ -- We want to keep non-recursive things non-recursive+ -- so that we desugar unlifted bindings correctly+ = do { let bind = case bagToList binds of+ [bind] -> bind+ [] -> panic "tc_group: empty list of binds"+ _ -> panic "tc_group: NonRecursive binds is not a singleton bag"+ ; (bind', thing) <- tc_single top_lvl sig_fn prag_fn bind closed+ thing_inside+ ; return ( [(NonRecursive, bind')], thing) }++tc_group top_lvl sig_fn prag_fn (Recursive, binds) closed thing_inside+ = -- To maximise polymorphism, we do a new+ -- strongly-connected-component analysis, this time omitting+ -- any references to variables with type signatures.+ -- (This used to be optional, but isn't now.)+ -- See Note [Polymorphic recursion] in HsBinds.+ do { traceTc "tc_group rec" (pprLHsBinds binds)+ ; when hasPatSyn $ recursivePatSynErr binds+ ; (binds1, thing) <- go sccs+ ; return ([(Recursive, binds1)], thing) }+ -- Rec them all together+ where+ hasPatSyn = anyBag (isPatSyn . unLoc) binds+ isPatSyn PatSynBind{} = True+ isPatSyn _ = False++ sccs :: [SCC (LHsBind Name)]+ sccs = stronglyConnCompFromEdgedVerticesUniq (mkEdges sig_fn binds)++ go :: [SCC (LHsBind Name)] -> TcM (LHsBinds TcId, thing)+ go (scc:sccs) = do { (binds1, ids1) <- tc_scc scc+ ; (binds2, thing) <- tcExtendLetEnv top_lvl sig_fn+ closed ids1 $+ go sccs+ ; return (binds1 `unionBags` binds2, thing) }+ go [] = do { thing <- thing_inside; return (emptyBag, thing) }++ tc_scc (AcyclicSCC bind) = tc_sub_group NonRecursive [bind]+ tc_scc (CyclicSCC binds) = tc_sub_group Recursive binds++ tc_sub_group rec_tc binds =+ tcPolyBinds sig_fn prag_fn Recursive rec_tc closed binds++recursivePatSynErr :: OutputableBndr name => LHsBinds name -> TcM a+recursivePatSynErr binds+ = failWithTc $+ hang (text "Recursive pattern synonym definition with following bindings:")+ 2 (vcat $ map pprLBind . bagToList $ binds)+ where+ pprLoc loc = parens (text "defined at" <+> ppr loc)+ pprLBind (L loc bind) = pprWithCommas ppr (collectHsBindBinders bind) <+>+ pprLoc loc++tc_single :: forall thing.+ TopLevelFlag -> TcSigFun -> TcPragEnv+ -> LHsBind Name -> IsGroupClosed -> TcM thing+ -> TcM (LHsBinds TcId, thing)+tc_single _top_lvl sig_fn _prag_fn+ (L _ (PatSynBind psb@PSB{ psb_id = L _ name }))+ _ thing_inside+ = do { (aux_binds, tcg_env) <- tc_pat_syn_decl+ ; thing <- setGblEnv tcg_env thing_inside+ ; return (aux_binds, thing)+ }+ where+ tc_pat_syn_decl :: TcM (LHsBinds TcId, TcGblEnv)+ tc_pat_syn_decl = case sig_fn name of+ Nothing -> tcInferPatSynDecl psb+ Just (TcPatSynSig tpsi) -> tcCheckPatSynDecl psb tpsi+ Just _ -> panic "tc_single"++tc_single top_lvl sig_fn prag_fn lbind closed thing_inside+ = do { (binds1, ids) <- tcPolyBinds sig_fn prag_fn+ NonRecursive NonRecursive+ closed+ [lbind]+ ; thing <- tcExtendLetEnv top_lvl sig_fn closed ids thing_inside+ ; return (binds1, thing) }++------------------------+type BKey = Int -- Just number off the bindings++mkEdges :: TcSigFun -> LHsBinds Name -> [Node BKey (LHsBind Name)]+-- See Note [Polymorphic recursion] in HsBinds.+mkEdges sig_fn binds+ = [ (bind, key, [key | n <- nonDetEltsUniqSet (bind_fvs (unLoc bind)),+ Just key <- [lookupNameEnv key_map n], no_sig n ])+ | (bind, key) <- keyd_binds+ ]+ -- It's OK to use nonDetEltsUFM here as stronglyConnCompFromEdgedVertices+ -- is still deterministic even if the edges are in nondeterministic order+ -- as explained in Note [Deterministic SCC] in Digraph.+ where+ no_sig :: Name -> Bool+ no_sig n = not (hasCompleteSig sig_fn n)++ keyd_binds = bagToList binds `zip` [0::BKey ..]++ key_map :: NameEnv BKey -- Which binding it comes from+ key_map = mkNameEnv [(bndr, key) | (L _ bind, key) <- keyd_binds+ , bndr <- collectHsBindBinders bind ]++------------------------+tcPolyBinds :: TcSigFun -> TcPragEnv+ -> RecFlag -- Whether the group is really recursive+ -> RecFlag -- Whether it's recursive after breaking+ -- dependencies based on type signatures+ -> IsGroupClosed -- Whether the group is closed+ -> [LHsBind Name] -- None are PatSynBind+ -> TcM (LHsBinds TcId, [TcId])++-- Typechecks a single bunch of values bindings all together,+-- and generalises them. The bunch may be only part of a recursive+-- group, because we use type signatures to maximise polymorphism+--+-- Returns a list because the input may be a single non-recursive binding,+-- in which case the dependency order of the resulting bindings is+-- important.+--+-- Knows nothing about the scope of the bindings+-- None of the bindings are pattern synonyms++tcPolyBinds sig_fn prag_fn rec_group rec_tc closed bind_list+ = setSrcSpan loc $+ recoverM (recoveryCode binder_names sig_fn) $ do+ -- Set up main recover; take advantage of any type sigs++ { traceTc "------------------------------------------------" Outputable.empty+ ; traceTc "Bindings for {" (ppr binder_names)+ ; dflags <- getDynFlags+ ; let plan = decideGeneralisationPlan dflags bind_list closed sig_fn+ ; traceTc "Generalisation plan" (ppr plan)+ ; result@(_, poly_ids) <- case plan of+ NoGen -> tcPolyNoGen rec_tc prag_fn sig_fn bind_list+ InferGen mn -> tcPolyInfer rec_tc prag_fn sig_fn mn bind_list+ CheckGen lbind sig -> tcPolyCheck prag_fn sig lbind++ ; traceTc "} End of bindings for" (vcat [ ppr binder_names, ppr rec_group+ , vcat [ppr id <+> ppr (idType id) | id <- poly_ids]+ ])++ ; return result }+ where+ binder_names = collectHsBindListBinders bind_list+ loc = foldr1 combineSrcSpans (map getLoc bind_list)+ -- The mbinds have been dependency analysed and+ -- may no longer be adjacent; so find the narrowest+ -- span that includes them all++--------------+-- If typechecking the binds fails, then return with each+-- signature-less binder given type (forall a.a), to minimise+-- subsequent error messages+recoveryCode :: [Name] -> TcSigFun -> TcM (LHsBinds TcId, [Id])+recoveryCode binder_names sig_fn+ = do { traceTc "tcBindsWithSigs: error recovery" (ppr binder_names)+ ; let poly_ids = map mk_dummy binder_names+ ; return (emptyBag, poly_ids) }+ where+ mk_dummy name+ | Just sig <- sig_fn name+ , Just poly_id <- completeSigPolyId_maybe sig+ = poly_id+ | otherwise+ = mkLocalId name forall_a_a++forall_a_a :: TcType+forall_a_a = mkSpecForAllTys [runtimeRep1TyVar, openAlphaTyVar] openAlphaTy++{- *********************************************************************+* *+ tcPolyNoGen+* *+********************************************************************* -}++tcPolyNoGen -- No generalisation whatsoever+ :: RecFlag -- Whether it's recursive after breaking+ -- dependencies based on type signatures+ -> TcPragEnv -> TcSigFun+ -> [LHsBind Name]+ -> TcM (LHsBinds TcId, [TcId])++tcPolyNoGen rec_tc prag_fn tc_sig_fn bind_list+ = do { (binds', mono_infos) <- tcMonoBinds rec_tc tc_sig_fn+ (LetGblBndr prag_fn)+ bind_list+ ; mono_ids' <- mapM tc_mono_info mono_infos+ ; return (binds', mono_ids') }+ where+ tc_mono_info (MBI { mbi_poly_name = name, mbi_mono_id = mono_id })+ = do { _specs <- tcSpecPrags mono_id (lookupPragEnv prag_fn name)+ ; return mono_id }+ -- NB: tcPrags generates error messages for+ -- specialisation pragmas for non-overloaded sigs+ -- Indeed that is why we call it here!+ -- So we can safely ignore _specs+++{- *********************************************************************+* *+ tcPolyCheck+* *+********************************************************************* -}++tcPolyCheck :: TcPragEnv+ -> TcIdSigInfo -- Must be a complete signature+ -> LHsBind Name -- Must be a FunBind+ -> TcM (LHsBinds TcId, [TcId])+-- There is just one binding,+-- it is a Funbind+-- it has a complete type signature,+tcPolyCheck prag_fn+ (CompleteSig { sig_bndr = poly_id+ , sig_ctxt = ctxt+ , sig_loc = sig_loc })+ (L loc (FunBind { fun_id = L nm_loc name+ , fun_matches = matches }))+ = setSrcSpan sig_loc $+ do { traceTc "tcPolyCheck" (ppr poly_id $$ ppr sig_loc)+ ; (tv_prs, theta, tau) <- tcInstType tcInstSkolTyVars poly_id+ -- See Note [Instantiate sig with fresh variables]++ ; mono_name <- newNameAt (nameOccName name) nm_loc+ ; ev_vars <- newEvVars theta+ ; let mono_id = mkLocalId mono_name tau+ skol_info = SigSkol ctxt (idType poly_id) tv_prs+ skol_tvs = map snd tv_prs++ ; (ev_binds, (co_fn, matches'))+ <- checkConstraints skol_info skol_tvs ev_vars $+ tcExtendIdBndrs [TcIdBndr mono_id NotTopLevel] $+ tcExtendTyVarEnv2 tv_prs $+ setSrcSpan loc $+ tcMatchesFun (L nm_loc mono_name) matches (mkCheckExpType tau)++ ; let prag_sigs = lookupPragEnv prag_fn name+ ; spec_prags <- tcSpecPrags poly_id prag_sigs+ ; poly_id <- addInlinePrags poly_id prag_sigs++ ; mod <- getModule+ ; let bind' = FunBind { fun_id = L nm_loc mono_id+ , fun_matches = matches'+ , fun_co_fn = co_fn+ , bind_fvs = placeHolderNamesTc+ , fun_tick = funBindTicks nm_loc mono_id mod prag_sigs }++ abs_bind = L loc $ AbsBindsSig+ { abs_sig_export = poly_id+ , abs_tvs = skol_tvs+ , abs_ev_vars = ev_vars+ , abs_sig_prags = SpecPrags spec_prags+ , abs_sig_ev_bind = ev_binds+ , abs_sig_bind = L loc bind' }++ ; return (unitBag abs_bind, [poly_id]) }++tcPolyCheck _prag_fn sig bind+ = pprPanic "tcPolyCheck" (ppr sig $$ ppr bind)++funBindTicks :: SrcSpan -> TcId -> Module -> [LSig Name] -> [Tickish TcId]+funBindTicks loc fun_id mod sigs+ | (mb_cc_str : _) <- [ cc_name | L _ (SCCFunSig _ _ cc_name) <- sigs ]+ -- this can only be a singleton list, as duplicate pragmas are rejected+ -- by the renamer+ , let cc_str+ | Just cc_str <- mb_cc_str+ = sl_fs $ unLoc cc_str+ | otherwise+ = getOccFS (Var.varName fun_id)+ cc_name = moduleNameFS (moduleName mod) `appendFS` consFS '.' cc_str+ cc = mkUserCC cc_name mod loc (getUnique fun_id)+ = [ProfNote cc True True]+ | otherwise+ = []++{- Note [Instantiate sig with fresh variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's vital to instantiate a type signature with fresh variables.+For example:+ type T = forall a. [a] -> [a]+ f :: T;+ f = g where { g :: T; g = <rhs> }++ We must not use the same 'a' from the defn of T at both places!!+(Instantiation is only necessary because of type synonyms. Otherwise,+it's all cool; each signature has distinct type variables from the renamer.)+-}+++{- *********************************************************************+* *+ tcPolyInfer+* *+********************************************************************* -}++tcPolyInfer+ :: RecFlag -- Whether it's recursive after breaking+ -- dependencies based on type signatures+ -> TcPragEnv -> TcSigFun+ -> Bool -- True <=> apply the monomorphism restriction+ -> [LHsBind Name]+ -> TcM (LHsBinds TcId, [TcId])+tcPolyInfer rec_tc prag_fn tc_sig_fn mono bind_list+ = do { (tclvl, wanted, (binds', mono_infos))+ <- pushLevelAndCaptureConstraints $+ tcMonoBinds rec_tc tc_sig_fn LetLclBndr bind_list++ ; let name_taus = [ (mbi_poly_name info, idType (mbi_mono_id info))+ | info <- mono_infos ]+ sigs = [ sig | MBI { mbi_sig = Just sig } <- mono_infos ]+ infer_mode = if mono then ApplyMR else NoRestrictions++ ; mapM_ (checkOverloadedSig mono) sigs++ ; traceTc "simplifyInfer call" (ppr tclvl $$ ppr name_taus $$ ppr wanted)+ ; (qtvs, givens, ev_binds)+ <- simplifyInfer tclvl infer_mode sigs name_taus wanted++ ; let inferred_theta = map evVarPred givens+ ; exports <- checkNoErrs $+ mapM (mkExport prag_fn qtvs inferred_theta) mono_infos++ ; loc <- getSrcSpanM+ ; let poly_ids = map abe_poly exports+ abs_bind = L loc $+ AbsBinds { abs_tvs = qtvs+ , abs_ev_vars = givens, abs_ev_binds = [ev_binds]+ , abs_exports = exports, abs_binds = binds' }++ ; traceTc "Binding:" (ppr (poly_ids `zip` map idType poly_ids))+ ; return (unitBag abs_bind, poly_ids) }+ -- poly_ids are guaranteed zonked by mkExport++--------------+mkExport :: TcPragEnv+ -> [TyVar] -> TcThetaType -- Both already zonked+ -> MonoBindInfo+ -> TcM (ABExport Id)+-- Only called for generalisation plan InferGen, not by CheckGen or NoGen+--+-- mkExport generates exports with+-- zonked type variables,+-- zonked poly_ids+-- The former is just because no further unifications will change+-- the quantified type variables, so we can fix their final form+-- right now.+-- The latter is needed because the poly_ids are used to extend the+-- type environment; see the invariant on TcEnv.tcExtendIdEnv++-- Pre-condition: the qtvs and theta are already zonked++mkExport prag_fn qtvs theta+ mono_info@(MBI { mbi_poly_name = poly_name+ , mbi_sig = mb_sig+ , mbi_mono_id = mono_id })+ = do { mono_ty <- zonkTcType (idType mono_id)+ ; poly_id <- mkInferredPolyId qtvs theta poly_name mb_sig mono_ty++ -- NB: poly_id has a zonked type+ ; poly_id <- addInlinePrags poly_id prag_sigs+ ; spec_prags <- tcSpecPrags poly_id prag_sigs+ -- tcPrags requires a zonked poly_id++ -- See Note [Impedance matching]+ -- NB: we have already done checkValidType, including an ambiguity check,+ -- on the type; either when we checked the sig or in mkInferredPolyId+ ; let poly_ty = idType poly_id+ sel_poly_ty = mkInfSigmaTy qtvs theta mono_ty+ -- This type is just going into tcSubType,+ -- so Inferred vs. Specified doesn't matter++ ; wrap <- if sel_poly_ty `eqType` poly_ty -- NB: eqType ignores visibility+ then return idHsWrapper -- Fast path; also avoids complaint when we infer+ -- an ambiguouse type and have AllowAmbiguousType+ -- e..g infer x :: forall a. F a -> Int+ else addErrCtxtM (mk_impedance_match_msg mono_info sel_poly_ty poly_ty) $+ tcSubType_NC sig_ctxt sel_poly_ty poly_ty++ ; warn_missing_sigs <- woptM Opt_WarnMissingLocalSignatures+ ; when warn_missing_sigs $+ localSigWarn Opt_WarnMissingLocalSignatures poly_id mb_sig++ ; return (ABE { abe_wrap = wrap+ -- abe_wrap :: idType poly_id ~ (forall qtvs. theta => mono_ty)+ , abe_poly = poly_id+ , abe_mono = mono_id+ , abe_prags = SpecPrags spec_prags}) }+ where+ prag_sigs = lookupPragEnv prag_fn poly_name+ sig_ctxt = InfSigCtxt poly_name++mkInferredPolyId :: [TyVar] -> TcThetaType+ -> Name -> Maybe TcIdSigInst -> TcType+ -> TcM TcId+mkInferredPolyId qtvs inferred_theta poly_name mb_sig_inst mono_ty+ | Just (TISI { sig_inst_sig = sig }) <- mb_sig_inst+ , CompleteSig { sig_bndr = poly_id } <- sig+ = return poly_id++ | otherwise -- Either no type sig or partial type sig+ = checkNoErrs $ -- The checkNoErrs ensures that if the type is ambiguous+ -- we don't carry on to the impedance matching, and generate+ -- a duplicate ambiguity error. There is a similar+ -- checkNoErrs for complete type signatures too.+ do { fam_envs <- tcGetFamInstEnvs+ ; let (_co, mono_ty') = normaliseType fam_envs Nominal mono_ty+ -- Unification may not have normalised the type,+ -- (see Note [Lazy flattening] in TcFlatten) so do it+ -- here to make it as uncomplicated as possible.+ -- Example: f :: [F Int] -> Bool+ -- should be rewritten to f :: [Char] -> Bool, if possible+ --+ -- We can discard the coercion _co, because we'll reconstruct+ -- it in the call to tcSubType below++ ; (binders, theta') <- chooseInferredQuantifiers inferred_theta+ (tyCoVarsOfType mono_ty') qtvs mb_sig_inst++ ; let inferred_poly_ty = mkForAllTys binders (mkPhiTy theta' mono_ty')++ ; traceTc "mkInferredPolyId" (vcat [ppr poly_name, ppr qtvs, ppr theta'+ , ppr inferred_poly_ty])+ ; addErrCtxtM (mk_inf_msg poly_name inferred_poly_ty) $+ checkValidType (InfSigCtxt poly_name) inferred_poly_ty+ -- See Note [Validity of inferred types]++ ; return (mkLocalIdOrCoVar poly_name inferred_poly_ty) }+++chooseInferredQuantifiers :: TcThetaType -- inferred+ -> TcTyVarSet -- tvs free in tau type+ -> [TcTyVar] -- inferred quantified tvs+ -> Maybe TcIdSigInst+ -> TcM ([TyVarBinder], TcThetaType)+chooseInferredQuantifiers inferred_theta tau_tvs qtvs Nothing+ = -- No type signature (partial or complete) for this binder,+ do { let free_tvs = closeOverKinds (growThetaTyVars inferred_theta tau_tvs)+ -- Include kind variables! Trac #7916+ my_theta = pickCapturedPreds free_tvs inferred_theta+ binders = [ mkTyVarBinder Inferred tv+ | tv <- qtvs+ , tv `elemVarSet` free_tvs ]+ ; return (binders, my_theta) }++chooseInferredQuantifiers inferred_theta tau_tvs qtvs+ (Just (TISI { sig_inst_sig = sig -- Always PartialSig+ , sig_inst_wcx = wcx+ , sig_inst_theta = annotated_theta+ , sig_inst_skols = annotated_tvs }))+ | Nothing <- wcx+ = do { annotated_theta <- zonkTcTypes annotated_theta+ ; let free_tvs = closeOverKinds (tyCoVarsOfTypes annotated_theta+ `unionVarSet` tau_tvs)+ ; traceTc "ciq" (vcat [ ppr sig, ppr annotated_theta, ppr free_tvs])+ ; psig_qtvs <- mk_psig_qtvs annotated_tvs+ ; return (mk_final_qtvs psig_qtvs free_tvs, annotated_theta) }++ | Just wc_var <- wcx+ = do { annotated_theta <- zonkTcTypes annotated_theta+ ; let free_tvs = closeOverKinds (growThetaTyVars inferred_theta seed_tvs)+ -- growThetaVars just like the no-type-sig case+ -- Omitting this caused #12844+ seed_tvs = tyCoVarsOfTypes annotated_theta -- These are put there+ `unionVarSet` tau_tvs -- by the user++ ; psig_qtvs <- mk_psig_qtvs annotated_tvs+ ; let my_qtvs = mk_final_qtvs psig_qtvs free_tvs+ keep_me = psig_qtvs `unionVarSet` free_tvs+ my_theta = pickCapturedPreds keep_me inferred_theta++ -- Report the inferred constraints for an extra-constraints wildcard/hole as+ -- an error message, unless the PartialTypeSignatures flag is enabled. In this+ -- case, the extra inferred constraints are accepted without complaining.+ -- NB: inferred_theta already includes all the annotated constraints+ inferred_diff = [ pred+ | pred <- my_theta+ , all (not . (`eqType` pred)) annotated_theta ]+ ; ctuple <- mk_ctuple inferred_diff+ ; writeMetaTyVar wc_var ctuple+ ; traceTc "completeTheta" $+ vcat [ ppr sig+ , ppr annotated_theta, ppr inferred_theta+ , ppr inferred_diff ]++ ; return (my_qtvs, my_theta) }++ | otherwise -- A complete type signature is dealt with in mkInferredPolyId+ = pprPanic "chooseInferredQuantifiers" (ppr sig)++ where+ mk_final_qtvs psig_qtvs free_tvs+ = [ mkTyVarBinder vis tv+ | tv <- qtvs -- Pulling from qtvs maintains original order+ , tv `elemVarSet` keep_me+ , let vis | tv `elemVarSet` psig_qtvs = Specified+ | otherwise = Inferred ]+ where+ keep_me = free_tvs `unionVarSet` psig_qtvs++ mk_ctuple [pred] = return pred+ mk_ctuple preds = do { tc <- tcLookupTyCon (cTupleTyConName (length preds))+ ; return (mkTyConApp tc preds) }++ mk_psig_qtvs :: [(Name,TcTyVar)] -> TcM TcTyVarSet+ mk_psig_qtvs annotated_tvs+ = do { psig_qtvs <- mapM (zonkTcTyVarToTyVar . snd) annotated_tvs+ ; return (mkVarSet psig_qtvs) }++mk_impedance_match_msg :: MonoBindInfo+ -> TcType -> TcType+ -> TidyEnv -> TcM (TidyEnv, SDoc)+-- This is a rare but rather awkward error messages+mk_impedance_match_msg (MBI { mbi_poly_name = name, mbi_sig = mb_sig })+ inf_ty sig_ty tidy_env+ = do { (tidy_env1, inf_ty) <- zonkTidyTcType tidy_env inf_ty+ ; (tidy_env2, sig_ty) <- zonkTidyTcType tidy_env1 sig_ty+ ; let msg = vcat [ text "When checking that the inferred type"+ , nest 2 $ ppr name <+> dcolon <+> ppr inf_ty+ , text "is as general as its" <+> what <+> text "signature"+ , nest 2 $ ppr name <+> dcolon <+> ppr sig_ty ]+ ; return (tidy_env2, msg) }+ where+ what = case mb_sig of+ Nothing -> text "inferred"+ Just sig | isPartialSig sig -> text "(partial)"+ | otherwise -> empty+++mk_inf_msg :: Name -> TcType -> TidyEnv -> TcM (TidyEnv, SDoc)+mk_inf_msg poly_name poly_ty tidy_env+ = do { (tidy_env1, poly_ty) <- zonkTidyTcType tidy_env poly_ty+ ; let msg = vcat [ text "When checking the inferred type"+ , nest 2 $ ppr poly_name <+> dcolon <+> ppr poly_ty ]+ ; return (tidy_env1, msg) }+++-- | Warn the user about polymorphic local binders that lack type signatures.+localSigWarn :: WarningFlag -> Id -> Maybe TcIdSigInst -> TcM ()+localSigWarn flag id mb_sig+ | Just _ <- mb_sig = return ()+ | not (isSigmaTy (idType id)) = return ()+ | otherwise = warnMissingSignatures flag msg id+ where+ msg = text "Polymorphic local binding with no type signature:"++warnMissingSignatures :: WarningFlag -> SDoc -> Id -> TcM ()+warnMissingSignatures flag msg id+ = do { env0 <- tcInitTidyEnv+ ; let (env1, tidy_ty) = tidyOpenType env0 (idType id)+ ; addWarnTcM (Reason flag) (env1, mk_msg tidy_ty) }+ where+ mk_msg ty = sep [ msg, nest 2 $ pprPrefixName (idName id) <+> dcolon <+> ppr ty ]++checkOverloadedSig :: Bool -> TcIdSigInst -> TcM ()+-- Example:+-- f :: Eq a => a -> a+-- K f = e+-- The MR applies, but the signature is overloaded, and it's+-- best to complain about this directly+-- c.f Trac #11339+checkOverloadedSig monomorphism_restriction_applies sig+ | not (null (sig_inst_theta sig))+ , monomorphism_restriction_applies+ , let orig_sig = sig_inst_sig sig+ = setSrcSpan (sig_loc orig_sig) $+ failWith $+ hang (text "Overloaded signature conflicts with monomorphism restriction")+ 2 (ppr orig_sig)+ | otherwise+ = return ()++{- Note [Partial type signatures and generalisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If /any/ of the signatures in the gropu is a partial type signature+ f :: _ -> Int+then we *always* use the InferGen plan, and hence tcPolyInfer.+We do this even for a local binding with -XMonoLocalBinds, when+we normally use NoGen.++Reasons:+ * The TcSigInfo for 'f' has a unification variable for the '_',+ whose TcLevel is one level deeper than the current level.+ (See pushTcLevelM in tcTySig.) But NoGen doesn't increase+ the TcLevel like InferGen, so we lose the level invariant.++ * The signature might be f :: forall a. _ -> a+ so it really is polymorphic. It's not clear what it would+ mean to use NoGen on this, and indeed the ASSERT in tcLhs,+ in the (Just sig) case, checks that if there is a signature+ then we are using LetLclBndr, and hence a nested AbsBinds with+ increased TcLevel++It might be possible to fix these difficulties somehow, but there+doesn't seem much point. Indeed, adding a partial type signature is a+way to get per-binding inferred generalisation.++We apply the MR if /all/ of the partial signatures lack a context.+In particular (Trac #11016):+ f2 :: (?loc :: Int) => _+ f2 = ?loc+It's stupid to apply the MR here. This test includes an extra-constraints+wildcard; that is, we don't apply the MR if you write+ f3 :: _ => blah++Note [Validity of inferred types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to check inferred type for validity, in case it uses language+extensions that are not turned on. The principle is that if the user+simply adds the inferred type to the program source, it'll compile fine.+See #8883.++Examples that might fail:+ - the type might be ambiguous++ - an inferred theta that requires type equalities e.g. (F a ~ G b)+ or multi-parameter type classes+ - an inferred type that includes unboxed tuples+++Note [Impedance matching]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f 0 x = x+ f n x = g [] (not x)++ g [] y = f 10 y+ g _ y = f 9 y++After typechecking we'll get+ f_mono_ty :: a -> Bool -> Bool+ g_mono_ty :: [b] -> Bool -> Bool+with constraints+ (Eq a, Num a)++Note that f is polymorphic in 'a' and g in 'b'; and these are not linked.+The types we really want for f and g are+ f :: forall a. (Eq a, Num a) => a -> Bool -> Bool+ g :: forall b. [b] -> Bool -> Bool++We can get these by "impedance matching":+ tuple :: forall a b. (Eq a, Num a) => (a -> Bool -> Bool, [b] -> Bool -> Bool)+ tuple a b d1 d1 = let ...bind f_mono, g_mono in (f_mono, g_mono)++ f a d1 d2 = case tuple a Any d1 d2 of (f, g) -> f+ g b = case tuple Integer b dEqInteger dNumInteger of (f,g) -> g++Suppose the shared quantified tyvars are qtvs and constraints theta.+Then we want to check that+ forall qtvs. theta => f_mono_ty is more polymorphic than f's polytype+and the proof is the impedance matcher.++Notice that the impedance matcher may do defaulting. See Trac #7173.++It also cleverly does an ambiguity check; for example, rejecting+ f :: F a -> F a+where F is a non-injective type function.+-}++{- *********************************************************************+* *+ Vectorisation+* *+********************************************************************* -}++tcVectDecls :: [LVectDecl Name] -> TcM ([LVectDecl TcId])+tcVectDecls decls+ = do { decls' <- mapM (wrapLocM tcVect) decls+ ; let ids = [lvectDeclName decl | decl <- decls', not $ lvectInstDecl decl]+ dups = findDupsEq (==) ids+ ; mapM_ reportVectDups dups+ ; traceTcConstraints "End of tcVectDecls"+ ; return decls'+ }+ where+ reportVectDups (first:_second:_more)+ = addErrAt (getSrcSpan first) $+ text "Duplicate vectorisation declarations for" <+> ppr first+ reportVectDups _ = return ()++--------------+tcVect :: VectDecl Name -> TcM (VectDecl TcId)+-- FIXME: We can't typecheck the expression of a vectorisation declaration against the vectorised+-- type of the original definition as this requires internals of the vectoriser not available+-- during type checking. Instead, constrain the rhs of a vectorisation declaration to be a single+-- identifier (this is checked in 'rnHsVectDecl'). Fix this by enabling the use of 'vectType'+-- from the vectoriser here.+tcVect (HsVect s name rhs)+ = addErrCtxt (vectCtxt name) $+ do { var <- wrapLocM tcLookupId name+ ; let L rhs_loc (HsVar (L lv rhs_var_name)) = rhs+ ; rhs_id <- tcLookupId rhs_var_name+ ; return $ HsVect s var (L rhs_loc (HsVar (L lv rhs_id)))+ }++tcVect (HsNoVect s name)+ = addErrCtxt (vectCtxt name) $+ do { var <- wrapLocM tcLookupId name+ ; return $ HsNoVect s var+ }+tcVect (HsVectTypeIn _ isScalar lname rhs_name)+ = addErrCtxt (vectCtxt lname) $+ do { tycon <- tcLookupLocatedTyCon lname+ ; checkTc ( not isScalar -- either we have a non-SCALAR declaration+ || isJust rhs_name -- or we explicitly provide a vectorised type+ || tyConArity tycon == 0 -- otherwise the type constructor must be nullary+ )+ scalarTyConMustBeNullary++ ; rhs_tycon <- fmapMaybeM (tcLookupTyCon . unLoc) rhs_name+ ; return $ HsVectTypeOut isScalar tycon rhs_tycon+ }+tcVect (HsVectTypeOut _ _ _)+ = panic "TcBinds.tcVect: Unexpected 'HsVectTypeOut'"+tcVect (HsVectClassIn _ lname)+ = addErrCtxt (vectCtxt lname) $+ do { cls <- tcLookupLocatedClass lname+ ; return $ HsVectClassOut cls+ }+tcVect (HsVectClassOut _)+ = panic "TcBinds.tcVect: Unexpected 'HsVectClassOut'"+tcVect (HsVectInstIn linstTy)+ = addErrCtxt (vectCtxt linstTy) $+ do { (cls, tys) <- tcHsVectInst linstTy+ ; inst <- tcLookupInstance cls tys+ ; return $ HsVectInstOut inst+ }+tcVect (HsVectInstOut _)+ = panic "TcBinds.tcVect: Unexpected 'HsVectInstOut'"++vectCtxt :: Outputable thing => thing -> SDoc+vectCtxt thing = text "When checking the vectorisation declaration for" <+> ppr thing++scalarTyConMustBeNullary :: MsgDoc+scalarTyConMustBeNullary = text "VECTORISE SCALAR type constructor must be nullary"++{-+Note [SPECIALISE pragmas]+~~~~~~~~~~~~~~~~~~~~~~~~~+There is no point in a SPECIALISE pragma for a non-overloaded function:+ reverse :: [a] -> [a]+ {-# SPECIALISE reverse :: [Int] -> [Int] #-}++But SPECIALISE INLINE *can* make sense for GADTS:+ data Arr e where+ ArrInt :: !Int -> ByteArray# -> Arr Int+ ArrPair :: !Int -> Arr e1 -> Arr e2 -> Arr (e1, e2)++ (!:) :: Arr e -> Int -> e+ {-# SPECIALISE INLINE (!:) :: Arr Int -> Int -> Int #-}+ {-# SPECIALISE INLINE (!:) :: Arr (a, b) -> Int -> (a, b) #-}+ (ArrInt _ ba) !: (I# i) = I# (indexIntArray# ba i)+ (ArrPair _ a1 a2) !: i = (a1 !: i, a2 !: i)++When (!:) is specialised it becomes non-recursive, and can usefully+be inlined. Scary! So we only warn for SPECIALISE *without* INLINE+for a non-overloaded function.++************************************************************************+* *+ tcMonoBinds+* *+************************************************************************++@tcMonoBinds@ deals with a perhaps-recursive group of HsBinds.+The signatures have been dealt with already.+-}++data MonoBindInfo = MBI { mbi_poly_name :: Name+ , mbi_sig :: Maybe TcIdSigInst+ , mbi_mono_id :: TcId }++tcMonoBinds :: RecFlag -- Whether the binding is recursive for typechecking purposes+ -- i.e. the binders are mentioned in their RHSs, and+ -- we are not rescued by a type signature+ -> TcSigFun -> LetBndrSpec+ -> [LHsBind Name]+ -> TcM (LHsBinds TcId, [MonoBindInfo])+tcMonoBinds is_rec sig_fn no_gen+ [ L b_loc (FunBind { fun_id = L nm_loc name,+ fun_matches = matches, bind_fvs = fvs })]+ -- Single function binding,+ | NonRecursive <- is_rec -- ...binder isn't mentioned in RHS+ , Nothing <- sig_fn name -- ...with no type signature+ = -- Note [Single function non-recursive binding special-case]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- In this very special case we infer the type of the+ -- right hand side first (it may have a higher-rank type)+ -- and *then* make the monomorphic Id for the LHS+ -- e.g. f = \(x::forall a. a->a) -> <body>+ -- We want to infer a higher-rank type for f+ setSrcSpan b_loc $+ do { ((co_fn, matches'), rhs_ty)+ <- tcInferInst $ \ exp_ty ->+ -- tcInferInst: see TcUnify,+ -- Note [Deep instantiation of InferResult]+ tcExtendIdBndrs [TcIdBndr_ExpType name exp_ty NotTopLevel] $+ -- We extend the error context even for a non-recursive+ -- function so that in type error messages we show the+ -- type of the thing whose rhs we are type checking+ tcMatchesFun (L nm_loc name) matches exp_ty++ ; mono_id <- newLetBndr no_gen name rhs_ty+ ; return (unitBag $ L b_loc $+ FunBind { fun_id = L nm_loc mono_id,+ fun_matches = matches', bind_fvs = fvs,+ fun_co_fn = co_fn, fun_tick = [] },+ [MBI { mbi_poly_name = name+ , mbi_sig = Nothing+ , mbi_mono_id = mono_id }]) }++tcMonoBinds _ sig_fn no_gen binds+ = do { tc_binds <- mapM (wrapLocM (tcLhs sig_fn no_gen)) binds++ -- Bring the monomorphic Ids, into scope for the RHSs+ ; let mono_infos = getMonoBindInfo tc_binds+ rhs_id_env = [ (name, mono_id)+ | MBI { mbi_poly_name = name+ , mbi_sig = mb_sig+ , mbi_mono_id = mono_id } <- mono_infos+ , case mb_sig of+ Just sig -> isPartialSig sig+ Nothing -> True ]+ -- A monomorphic binding for each term variable that lacks+ -- a complete type sig. (Ones with a sig are already in scope.)++ ; traceTc "tcMonoBinds" $ vcat [ ppr n <+> ppr id <+> ppr (idType id)+ | (n,id) <- rhs_id_env]+ ; binds' <- tcExtendRecIds rhs_id_env $+ mapM (wrapLocM tcRhs) tc_binds++ ; return (listToBag binds', mono_infos) }+++------------------------+-- tcLhs typechecks the LHS of the bindings, to construct the environment in which+-- we typecheck the RHSs. Basically what we are doing is this: for each binder:+-- if there's a signature for it, use the instantiated signature type+-- otherwise invent a type variable+-- You see that quite directly in the FunBind case.+--+-- But there's a complication for pattern bindings:+-- data T = MkT (forall a. a->a)+-- MkT f = e+-- Here we can guess a type variable for the entire LHS (which will be refined to T)+-- but we want to get (f::forall a. a->a) as the RHS environment.+-- The simplest way to do this is to typecheck the pattern, and then look up the+-- bound mono-ids. Then we want to retain the typechecked pattern to avoid re-doing+-- it; hence the TcMonoBind data type in which the LHS is done but the RHS isn't++data TcMonoBind -- Half completed; LHS done, RHS not done+ = TcFunBind MonoBindInfo SrcSpan (MatchGroup Name (LHsExpr Name))+ | TcPatBind [MonoBindInfo] (LPat TcId) (GRHSs Name (LHsExpr Name)) TcSigmaType++tcLhs :: TcSigFun -> LetBndrSpec -> HsBind Name -> TcM TcMonoBind+-- Only called with plan InferGen (LetBndrSpec = LetLclBndr)+-- or NoGen (LetBndrSpec = LetGblBndr)+-- CheckGen is used only for functions with a complete type signature,+-- and tcPolyCheck doesn't use tcMonoBinds at all++tcLhs sig_fn no_gen (FunBind { fun_id = L nm_loc name, fun_matches = matches })+ | Just (TcIdSig sig) <- sig_fn name+ = -- There is a type signature.+ -- It must be partial; if complete we'd be in tcPolyCheck!+ -- e.g. f :: _ -> _+ -- f x = ...g...+ -- Just g = ...f...+ -- Hence always typechecked with InferGen+ do { mono_info <- tcLhsSigId no_gen (name, sig)+ ; return (TcFunBind mono_info nm_loc matches) }++ | otherwise -- No type signature+ = do { mono_ty <- newOpenFlexiTyVarTy+ ; mono_id <- newLetBndr no_gen name mono_ty+ ; let mono_info = MBI { mbi_poly_name = name+ , mbi_sig = Nothing+ , mbi_mono_id = mono_id }+ ; return (TcFunBind mono_info nm_loc matches) }++tcLhs sig_fn no_gen (PatBind { pat_lhs = pat, pat_rhs = grhss })+ = -- See Note [Typechecking pattern bindings]+ do { sig_mbis <- mapM (tcLhsSigId no_gen) sig_names++ ; let inst_sig_fun = lookupNameEnv $ mkNameEnv $+ [ (mbi_poly_name mbi, mbi_mono_id mbi)+ | mbi <- sig_mbis ]++ -- See Note [Existentials in pattern bindings]+ ; ((pat', nosig_mbis), pat_ty)+ <- addErrCtxt (patMonoBindsCtxt pat grhss) $+ tcInferNoInst $ \ exp_ty ->+ tcLetPat inst_sig_fun no_gen pat exp_ty $+ mapM lookup_info nosig_names++ ; let mbis = sig_mbis ++ nosig_mbis++ ; traceTc "tcLhs" (vcat [ ppr id <+> dcolon <+> ppr (idType id)+ | mbi <- mbis, let id = mbi_mono_id mbi ]+ $$ ppr no_gen)++ ; return (TcPatBind mbis pat' grhss pat_ty) }+ where+ bndr_names = collectPatBinders pat+ (nosig_names, sig_names) = partitionWith find_sig bndr_names++ find_sig :: Name -> Either Name (Name, TcIdSigInfo)+ find_sig name = case sig_fn name of+ Just (TcIdSig sig) -> Right (name, sig)+ _ -> Left name++ -- After typechecking the pattern, look up the binder+ -- names that lack a signature, which the pattern has brought+ -- into scope.+ lookup_info :: Name -> TcM MonoBindInfo+ lookup_info name+ = do { mono_id <- tcLookupId name+ ; return (MBI { mbi_poly_name = name+ , mbi_sig = Nothing+ , mbi_mono_id = mono_id }) }++tcLhs _ _ other_bind = pprPanic "tcLhs" (ppr other_bind)+ -- AbsBind, VarBind impossible++-------------------+tcLhsSigId :: LetBndrSpec -> (Name, TcIdSigInfo) -> TcM MonoBindInfo+tcLhsSigId no_gen (name, sig)+ = do { inst_sig <- tcInstSig sig+ ; mono_id <- newSigLetBndr no_gen name inst_sig+ ; return (MBI { mbi_poly_name = name+ , mbi_sig = Just inst_sig+ , mbi_mono_id = mono_id }) }++------------+newSigLetBndr :: LetBndrSpec -> Name -> TcIdSigInst -> TcM TcId+newSigLetBndr (LetGblBndr prags) name (TISI { sig_inst_sig = id_sig })+ | CompleteSig { sig_bndr = poly_id } <- id_sig+ = addInlinePrags poly_id (lookupPragEnv prags name)+newSigLetBndr no_gen name (TISI { sig_inst_tau = tau })+ = newLetBndr no_gen name tau++-------------------+tcRhs :: TcMonoBind -> TcM (HsBind TcId)+tcRhs (TcFunBind info@(MBI { mbi_sig = mb_sig, mbi_mono_id = mono_id })+ loc matches)+ = tcExtendIdBinderStackForRhs [info] $+ tcExtendTyVarEnvForRhs mb_sig $+ do { traceTc "tcRhs: fun bind" (ppr mono_id $$ ppr (idType mono_id))+ ; (co_fn, matches') <- tcMatchesFun (L loc (idName mono_id))+ matches (mkCheckExpType $ idType mono_id)+ ; return ( FunBind { fun_id = L loc mono_id+ , fun_matches = matches'+ , fun_co_fn = co_fn+ , bind_fvs = placeHolderNamesTc+ , fun_tick = [] } ) }++tcRhs (TcPatBind infos pat' grhss pat_ty)+ = -- When we are doing pattern bindings we *don't* bring any scoped+ -- type variables into scope unlike function bindings+ -- Wny not? They are not completely rigid.+ -- That's why we have the special case for a single FunBind in tcMonoBinds+ tcExtendIdBinderStackForRhs infos $+ do { traceTc "tcRhs: pat bind" (ppr pat' $$ ppr pat_ty)+ ; grhss' <- addErrCtxt (patMonoBindsCtxt pat' grhss) $+ tcGRHSsPat grhss pat_ty+ ; return ( PatBind { pat_lhs = pat', pat_rhs = grhss'+ , pat_rhs_ty = pat_ty+ , bind_fvs = placeHolderNamesTc+ , pat_ticks = ([],[]) } )}++tcExtendTyVarEnvForRhs :: Maybe TcIdSigInst -> TcM a -> TcM a+tcExtendTyVarEnvForRhs Nothing thing_inside+ = thing_inside+tcExtendTyVarEnvForRhs (Just sig) thing_inside+ = tcExtendTyVarEnvFromSig sig thing_inside++tcExtendTyVarEnvFromSig :: TcIdSigInst -> TcM a -> TcM a+tcExtendTyVarEnvFromSig sig_inst thing_inside+ | TISI { sig_inst_skols = skol_prs, sig_inst_wcs = wcs } <- sig_inst+ = tcExtendTyVarEnv2 wcs $+ tcExtendTyVarEnv2 skol_prs $+ thing_inside++tcExtendIdBinderStackForRhs :: [MonoBindInfo] -> TcM a -> TcM a+-- Extend the TcIdBinderStack for the RHS of the binding, with+-- the monomorphic Id. That way, if we have, say+-- f = \x -> blah+-- and something goes wrong in 'blah', we get a "relevant binding"+-- looking like f :: alpha -> beta+-- This applies if 'f' has a type signature too:+-- f :: forall a. [a] -> [a]+-- f x = True+-- We can't unify True with [a], and a relevant binding is f :: [a] -> [a]+-- If we had the *polymorphic* version of f in the TcIdBinderStack, it+-- would not be reported as relevant, because its type is closed+tcExtendIdBinderStackForRhs infos thing_inside+ = tcExtendIdBndrs [ TcIdBndr mono_id NotTopLevel+ | MBI { mbi_mono_id = mono_id } <- infos ]+ thing_inside+ -- NotTopLevel: it's a monomorphic binding++---------------------+getMonoBindInfo :: [Located TcMonoBind] -> [MonoBindInfo]+getMonoBindInfo tc_binds+ = foldr (get_info . unLoc) [] tc_binds+ where+ get_info (TcFunBind info _ _) rest = info : rest+ get_info (TcPatBind infos _ _ _) rest = infos ++ rest+++{- Note [Typechecking pattern bindings]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Look at:+ - typecheck/should_compile/ExPat+ - Trac #12427, typecheck/should_compile/T12427{a,b}++ data T where+ MkT :: Integral a => a -> Int -> T++and suppose t :: T. Which of these pattern bindings are ok?++ E1. let { MkT p _ = t } in <body>++ E2. let { MkT _ q = t } in <body>++ E3. let { MkT (toInteger -> r) _ = t } in <body>++* (E1) is clearly wrong because the existential 'a' escapes.+ What type could 'p' possibly have?++* (E2) is fine, despite the existential pattern, because+ q::Int, and nothing escapes.++* Even (E3) is fine. The existential pattern binds a dictionary+ for (Integral a) which the view pattern can use to convert the+ a-valued field to an Integer, so r :: Integer.++An easy way to see all three is to imagine the desugaring.+For (E2) it would look like+ let q = case t of MkT _ q' -> q'+ in <body>+++We typecheck pattern bindings as follows. First tcLhs does this:++ 1. Take each type signature q :: ty, partial or complete, and+ instantiate it (with tcLhsSigId) to get a MonoBindInfo. This+ gives us a fresh "mono_id" qm :: instantiate(ty), where qm has+ a fresh name.++ Any fresh unification variables in instantiate(ty) born here, not+ deep under implications as would happen if we allocated them when+ we encountered q during tcPat.++ 2. Build a little environment mapping "q" -> "qm" for those Ids+ with signatures (inst_sig_fun)++ 3. Invoke tcLetPat to typecheck the pattern.++ - We pass in the current TcLevel. This is captured by+ TcPat.tcLetPat, and put into the pc_lvl field of PatCtxt, in+ PatEnv.++ - When tcPat finds an existential constructor, it binds fresh+ type variables and dictionaries as usual, increments the TcLevel,+ and emits an implication constraint.++ - When we come to a binder (TcPat.tcPatBndr), it looks it up+ in the little environment (the pc_sig_fn field of PatCtxt).++ Success => There was a type signature, so just use it,+ checking compatibility with the expected type.++ Failure => No type sigature.+ Infer case: (happens only outside any constructor pattern)+ use a unification variable+ at the outer level pc_lvl++ Check case: use promoteTcType to promote the type+ to the outer level pc_lvl. This is the+ place where we emit a constraint that'll blow+ up if existential capture takes place++ Result: the type of the binder is always at pc_lvl. This is+ crucial.++ 4. Throughout, when we are making up an Id for the pattern-bound variables+ (newLetBndr), we have two cases:++ - If we are generalising (generalisation plan is InferGen or+ CheckGen), then the let_bndr_spec will be LetLclBndr. In that case+ we want to bind a cloned, local version of the variable, with the+ type given by the pattern context, *not* by the signature (even if+ there is one; see Trac #7268). The mkExport part of the+ generalisation step will do the checking and impedance matching+ against the signature.++ - If for some some reason we are not generalising (plan = NoGen), the+ LetBndrSpec will be LetGblBndr. In that case we must bind the+ global version of the Id, and do so with precisely the type given+ in the signature. (Then we unify with the type from the pattern+ context type.)+++And that's it! The implication constraints check for the skolem+escape. It's quite simple and neat, and more expressive than before+e.g. GHC 8.0 rejects (E2) and (E3).++Example for (E1), starting at level 1. We generate+ p :: beta:1, with constraints (forall:3 a. Integral a => a ~ beta)+The (a~beta) can't float (because of the 'a'), nor be solved (because+beta is untouchable.)++Example for (E2), we generate+ q :: beta:1, with constraint (forall:3 a. Integral a => Int ~ beta)+The beta is untoucable, but floats out of the constraint and can+be solved absolutely fine.++************************************************************************+* *+ Generalisation+* *+********************************************************************* -}++data GeneralisationPlan+ = NoGen -- No generalisation, no AbsBinds++ | InferGen -- Implicit generalisation; there is an AbsBinds+ Bool -- True <=> apply the MR; generalise only unconstrained type vars++ | CheckGen (LHsBind Name) TcIdSigInfo+ -- One FunBind with a signature+ -- Explicit generalisation; there is an AbsBindsSig++-- A consequence of the no-AbsBinds choice (NoGen) is that there is+-- no "polymorphic Id" and "monmomorphic Id"; there is just the one++instance Outputable GeneralisationPlan where+ ppr NoGen = text "NoGen"+ ppr (InferGen b) = text "InferGen" <+> ppr b+ ppr (CheckGen _ s) = text "CheckGen" <+> ppr s++decideGeneralisationPlan+ :: DynFlags -> [LHsBind Name] -> IsGroupClosed -> TcSigFun+ -> GeneralisationPlan+decideGeneralisationPlan dflags lbinds closed sig_fn+ | has_partial_sigs = InferGen (and partial_sig_mrs)+ | Just (bind, sig) <- one_funbind_with_sig = CheckGen bind sig+ | do_not_generalise closed = NoGen+ | otherwise = InferGen mono_restriction+ where+ binds = map unLoc lbinds++ partial_sig_mrs :: [Bool]+ -- One for each parital signature (so empty => no partial sigs)+ -- The Bool is True if the signature has no constraint context+ -- so we should apply the MR+ -- See Note [Partial type signatures and generalisation]+ partial_sig_mrs+ = [ null theta+ | TcIdSig (PartialSig { psig_hs_ty = hs_ty })+ <- mapMaybe sig_fn (collectHsBindListBinders lbinds)+ , let (_, L _ theta, _) = splitLHsSigmaTy (hsSigWcType hs_ty) ]++ has_partial_sigs = not (null partial_sig_mrs)++ mono_restriction = xopt LangExt.MonomorphismRestriction dflags+ && any restricted binds++ do_not_generalise (IsGroupClosed _ True) = False+ -- The 'True' means that all of the group's+ -- free vars have ClosedTypeId=True; so we can ignore+ -- -XMonoLocalBinds, and generalise anyway+ do_not_generalise _ = xopt LangExt.MonoLocalBinds dflags++ -- With OutsideIn, all nested bindings are monomorphic+ -- except a single function binding with a signature+ one_funbind_with_sig+ | [lbind@(L _ (FunBind { fun_id = v }))] <- lbinds+ , Just (TcIdSig sig) <- sig_fn (unLoc v)+ = Just (lbind, sig)+ | otherwise+ = Nothing++ -- The Haskell 98 monomorphism restriction+ restricted (PatBind {}) = True+ restricted (VarBind { var_id = v }) = no_sig v+ restricted (FunBind { fun_id = v, fun_matches = m }) = restricted_match m+ && no_sig (unLoc v)+ restricted (PatSynBind {}) = panic "isRestrictedGroup/unrestricted PatSynBind"+ restricted (AbsBinds {}) = panic "isRestrictedGroup/unrestricted AbsBinds"+ restricted (AbsBindsSig {}) = panic "isRestrictedGroup/unrestricted AbsBindsSig"++ restricted_match (MG { mg_alts = L _ (L _ (Match _ [] _ _) : _ )}) = True+ restricted_match _ = False+ -- No args => like a pattern binding+ -- Some args => a function binding++ no_sig n = not (hasCompleteSig sig_fn n)++isClosedBndrGroup :: TcTypeEnv -> Bag (LHsBind Name) -> IsGroupClosed+isClosedBndrGroup type_env binds+ = IsGroupClosed fv_env type_closed+ where+ type_closed = allUFM (nameSetAll is_closed_type_id) fv_env++ fv_env :: NameEnv NameSet+ fv_env = mkNameEnv $ concatMap (bindFvs . unLoc) binds++ bindFvs :: HsBindLR Name idR -> [(Name, NameSet)]+ bindFvs (FunBind { fun_id = L _ f, bind_fvs = fvs })+ = let open_fvs = filterNameSet (not . is_closed) fvs+ in [(f, open_fvs)]+ bindFvs (PatBind { pat_lhs = pat, bind_fvs = fvs })+ = let open_fvs = filterNameSet (not . is_closed) fvs+ in [(b, open_fvs) | b <- collectPatBinders pat]+ bindFvs _+ = []++ is_closed :: Name -> ClosedTypeId+ is_closed name+ | Just thing <- lookupNameEnv type_env name+ = case thing of+ AGlobal {} -> True+ ATcId { tct_info = ClosedLet } -> True+ _ -> False++ | otherwise+ = True -- The free-var set for a top level binding mentions+++ is_closed_type_id :: Name -> Bool+ -- We're already removed Global and ClosedLet Ids+ is_closed_type_id name+ | Just thing <- lookupNameEnv type_env name+ = case thing of+ ATcId { tct_info = NonClosedLet _ cl } -> cl+ ATcId { tct_info = NotLetBound } -> False+ ATyVar {} -> False+ -- In-scope type variables are not closed!+ _ -> pprPanic "is_closed_id" (ppr name)++ | otherwise+ = True -- The free-var set for a top level binding mentions+ -- imported things too, so that we can report unused imports+ -- These won't be in the local type env.+ -- Ditto class method etc from the current module+++{- *********************************************************************+* *+ Error contexts and messages+* *+********************************************************************* -}++-- This one is called on LHS, when pat and grhss are both Name+-- and on RHS, when pat is TcId and grhss is still Name+patMonoBindsCtxt :: (OutputableBndrId id, Outputable body)+ => LPat id -> GRHSs Name body -> SDoc+patMonoBindsCtxt pat grhss+ = hang (text "In a pattern binding:") 2 (pprPatBind pat grhss)
+ typecheck/TcCanonical.hs view
@@ -0,0 +1,1949 @@+{-# LANGUAGE CPP #-}++module TcCanonical(+ canonicalize,+ unifyDerived,+ makeSuperClasses, maybeSym,+ StopOrContinue(..), stopWith, continueWith+ ) where++#include "HsVersions.h"++import TcRnTypes+import TcUnify( swapOverTyVars, metaTyVarUpdateOK )+import TcType+import Type+import TcFlatten+import TcSMonad+import TcEvidence+import Class+import TyCon+import TyCoRep -- cleverly decomposes types, good for completeness checking+import Coercion+import FamInstEnv ( FamInstEnvs )+import FamInst ( tcTopNormaliseNewTypeTF_maybe )+import Var+import VarEnv( mkInScopeSet )+import VarSet( extendVarSetList )+import Outputable+import DynFlags( DynFlags )+import NameSet+import RdrName++import Pair+import Util+import Bag+import MonadUtils+import Control.Monad+import Data.Maybe ( isJust )+import Data.List ( zip4, foldl' )+import BasicTypes++import Data.Bifunctor ( bimap )++{-+************************************************************************+* *+* The Canonicaliser *+* *+************************************************************************++Note [Canonicalization]+~~~~~~~~~~~~~~~~~~~~~~~++Canonicalization converts a simple constraint to a canonical form. It is+unary (i.e. treats individual constraints one at a time).++Constraints originating from user-written code come into being as+CNonCanonicals (except for CHoleCans, arising from holes). We know nothing+about these constraints. So, first:++ Classify CNonCanoncal constraints, depending on whether they+ are equalities, class predicates, or other.++Then proceed depending on the shape of the constraint. Generally speaking,+each constraint gets flattened and then decomposed into one of several forms+(see type Ct in TcRnTypes).++When an already-canonicalized constraint gets kicked out of the inert set,+it must be recanonicalized. But we know a bit about its shape from the+last time through, so we can skip the classification step.++-}++-- Top-level canonicalization+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++canonicalize :: Ct -> TcS (StopOrContinue Ct)+canonicalize ct@(CNonCanonical { cc_ev = ev })+ = do { traceTcS "canonicalize (non-canonical)" (ppr ct)+ ; {-# SCC "canEvVar" #-}+ canEvNC ev }++canonicalize (CDictCan { cc_ev = ev, cc_class = cls+ , cc_tyargs = xis, cc_pend_sc = pend_sc })+ = {-# SCC "canClass" #-}+ canClass ev cls xis pend_sc++canonicalize (CTyEqCan { cc_ev = ev+ , cc_tyvar = tv+ , cc_rhs = xi+ , cc_eq_rel = eq_rel })+ = {-# SCC "canEqLeafTyVarEq" #-}+ canEqNC ev eq_rel (mkTyVarTy tv) xi+ -- NB: Don't use canEqTyVar because that expects flattened types,+ -- and tv and xi may not be flat w.r.t. an updated inert set++canonicalize (CFunEqCan { cc_ev = ev+ , cc_fun = fn+ , cc_tyargs = xis1+ , cc_fsk = fsk })+ = {-# SCC "canEqLeafFunEq" #-}+ canCFunEqCan ev fn xis1 fsk++canonicalize (CIrredEvCan { cc_ev = ev })+ = canIrred ev+canonicalize (CHoleCan { cc_ev = ev, cc_hole = hole })+ = canHole ev hole++canEvNC :: CtEvidence -> TcS (StopOrContinue Ct)+-- Called only for non-canonical EvVars+canEvNC ev+ = case classifyPredType (ctEvPred ev) of+ ClassPred cls tys -> do traceTcS "canEvNC:cls" (ppr cls <+> ppr tys)+ canClassNC ev cls tys+ EqPred eq_rel ty1 ty2 -> do traceTcS "canEvNC:eq" (ppr ty1 $$ ppr ty2)+ canEqNC ev eq_rel ty1 ty2+ IrredPred {} -> do traceTcS "canEvNC:irred" (ppr (ctEvPred ev))+ canIrred ev+{-+************************************************************************+* *+* Class Canonicalization+* *+************************************************************************+-}++canClassNC :: CtEvidence -> Class -> [Type] -> TcS (StopOrContinue Ct)+-- "NC" means "non-canonical"; that is, we have got here+-- from a NonCanonical constrataint, not from a CDictCan+-- Precondition: EvVar is class evidence+canClassNC ev cls tys+ | isGiven ev -- See Note [Eagerly expand given superclasses]+ = do { sc_cts <- mkStrictSuperClasses ev cls tys+ ; emitWork sc_cts+ ; canClass ev cls tys False }+ | otherwise+ = canClass ev cls tys (has_scs cls)+ where+ has_scs cls = not (null (classSCTheta cls))++canClass :: CtEvidence+ -> Class -> [Type]+ -> Bool -- True <=> un-explored superclasses+ -> TcS (StopOrContinue Ct)+-- Precondition: EvVar is class evidence++canClass ev cls tys pend_sc+ = -- all classes do *nominal* matching+ ASSERT2( ctEvRole ev == Nominal, ppr ev $$ ppr cls $$ ppr tys )+ do { (xis, cos) <- flattenManyNom ev tys+ ; let co = mkTcTyConAppCo Nominal (classTyCon cls) cos+ xi = mkClassPred cls xis+ mk_ct new_ev = CDictCan { cc_ev = new_ev+ , cc_tyargs = xis+ , cc_class = cls+ , cc_pend_sc = pend_sc }+ ; mb <- rewriteEvidence ev xi co+ ; traceTcS "canClass" (vcat [ ppr ev+ , ppr xi, ppr mb ])+ ; return (fmap mk_ct mb) }++{- Note [The superclass story]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to add superclass constraints for two reasons:++* For givens [G], they give us a route to to proof. E.g.+ f :: Ord a => a -> Bool+ f x = x == x+ We get a Wanted (Eq a), which can only be solved from the superclass+ of the Given (Ord a).++* For wanteds [W], and deriveds [WD], [D], they may give useful+ functional dependencies. E.g.+ class C a b | a -> b where ...+ class C a b => D a b where ...+ Now a [W] constraint (D Int beta) has (C Int beta) as a superclass+ and that might tell us about beta, via C's fundeps. We can get this+ by generating a [D] (C Int beta) constraint. It's derived because+ we don't actually have to cough up any evidence for it; it's only there+ to generate fundep equalities.++See Note [Why adding superclasses can help].++For these reasons we want to generate superclass constraints for both+Givens and Wanteds. But:++* (Minor) they are often not needed, so generating them aggressively+ is a waste of time.++* (Major) if we want recursive superclasses, there would be an infinite+ number of them. Here is a real-life example (Trac #10318);++ class (Frac (Frac a) ~ Frac a,+ Fractional (Frac a),+ IntegralDomain (Frac a))+ => IntegralDomain a where+ type Frac a :: *++ Notice that IntegralDomain has an associated type Frac, and one+ of IntegralDomain's superclasses is another IntegralDomain constraint.++So here's the plan:++1. Eagerly generate superclasses for given (but not wanted)+ constraints; see Note [Eagerly expand given superclasses].+ This is done in canClassNC, when we take a non-canonical constraint+ and cannonicalise it.++ However stop if you encounter the same class twice. That is,+ expand eagerly, but have a conservative termination condition: see+ Note [Expanding superclasses] in TcType.++2. Solve the wanteds as usual, but do no further expansion of+ superclasses for canonical CDictCans in solveSimpleGivens or+ solveSimpleWanteds; Note [Danger of adding superclasses during solving]++ However, /do/ continue to eagerly expand superlasses for /given/+ non-canonical constraints (canClassNC does this). As Trac #12175+ showed, a type-family application can expand to a class constraint,+ and we want to see its superclasses for just the same reason as+ Note [Eagerly expand given superclasses].++3. If we have any remaining unsolved wanteds+ (see Note [When superclasses help] in TcRnTypes)+ try harder: take both the Givens and Wanteds, and expand+ superclasses again. This may succeed in generating (a finite+ number of) extra Givens, and extra Deriveds. Both may help the+ proof. This is done in TcSimplify.expandSuperClasses.++4. Go round to (2) again. This loop (2,3,4) is implemented+ in TcSimplify.simpl_loop.++The cc_pend_sc flag in a CDictCan records whether the superclasses of+this constraint have been expanded. Specifically, in Step 3 we only+expand superclasses for constraints with cc_pend_sc set to true (i.e.+isPendingScDict holds).++Why do we do this? Two reasons:++* To avoid repeated work, by repeatedly expanding the superclasses of+ same constraint,++* To terminate the above loop, at least in the -XNoRecursiveSuperClasses+ case. If there are recursive superclasses we could, in principle,+ expand forever, always encountering new constraints.++When we take a CNonCanonical or CIrredCan, but end up classifying it+as a CDictCan, we set the cc_pend_sc flag to False.++Note [Eagerly expand given superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In step (1) of Note [The superclass story], why do we eagerly expand+Given superclasses by one layer? Mainly because of some very obscure+cases like this:++ instance Bad a => Eq (T a)++ f :: (Ord (T a)) => blah+ f x = ....needs Eq (T a), Ord (T a)....++Here if we can't satisfy (Eq (T a)) from the givens we'll use the+instance declaration; but then we are stuck with (Bad a). Sigh.+This is really a case of non-confluent proofs, but to stop our users+complaining we expand one layer in advance.++Note [Instance and Given overlap] in TcInteract.++We also want to do this if we have++ f :: F (T a) => blah++where+ type instance F (T a) = Ord (T a)++So we may need to do a little work on the givens to expose the+class that has the superclasses. That's why the superclass+expansion for Givens happens in canClassNC.++Note [Why adding superclasses can help]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Examples of how adding superclasses can help:++ --- Example 1+ class C a b | a -> b+ Suppose we want to solve+ [G] C a b+ [W] C a beta+ Then adding [D] beta~b will let us solve it.++ -- Example 2 (similar but using a type-equality superclass)+ class (F a ~ b) => C a b+ And try to sllve:+ [G] C a b+ [W] C a beta+ Follow the superclass rules to add+ [G] F a ~ b+ [D] F a ~ beta+ Now we we get [D] beta ~ b, and can solve that.++ -- Example (tcfail138)+ class L a b | a -> b+ class (G a, L a b) => C a b++ instance C a b' => G (Maybe a)+ instance C a b => C (Maybe a) a+ instance L (Maybe a) a++ When solving the superclasses of the (C (Maybe a) a) instance, we get+ [G] C a b, and hance by superclasses, [G] G a, [G] L a b+ [W] G (Maybe a)+ Use the instance decl to get+ [W] C a beta+ Generate its derived superclass+ [D] L a beta. Now using fundeps, combine with [G] L a b to get+ [D] beta ~ b+ which is what we want.++Note [Danger of adding superclasses during solving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here's a serious, but now out-dated example, from Trac #4497:++ class Num (RealOf t) => Normed t+ type family RealOf x++Assume the generated wanted constraint is:+ [W] RealOf e ~ e+ [W] Normed e++If we were to be adding the superclasses during simplification we'd get:+ [W] RealOf e ~ e+ [W] Normed e+ [D] RealOf e ~ fuv+ [D] Num fuv+==>+ e := fuv, Num fuv, Normed fuv, RealOf fuv ~ fuv++While looks exactly like our original constraint. If we add the+superclass of (Normed fuv) again we'd loop. By adding superclasses+definitely only once, during canonicalisation, this situation can't+happen.++Mind you, now that Wanteds cannot rewrite Derived, I think this particular+situation can't happen.+ -}++makeSuperClasses :: [Ct] -> TcS [Ct]+-- Returns strict superclasses, transitively, see Note [The superclasses story]+-- See Note [The superclass story]+-- The loop-breaking here follows Note [Expanding superclasses] in TcType+-- Specifically, for an incoming (C t) constraint, we return all of (C t)'s+-- superclasses, up to /and including/ the first repetition of C+--+-- Example: class D a => C a+-- class C [a] => D a+-- makeSuperClasses (C x) will return (D x, C [x])+--+-- NB: the incoming constraints have had their cc_pend_sc flag already+-- flipped to False, by isPendingScDict, so we are /obliged/ to at+-- least produce the immediate superclasses+makeSuperClasses cts = concatMapM go cts+ where+ go (CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys })+ = mkStrictSuperClasses ev cls tys+ go ct = pprPanic "makeSuperClasses" (ppr ct)++mkStrictSuperClasses :: CtEvidence -> Class -> [Type] -> TcS [Ct]+-- Return constraints for the strict superclasses of (c tys)+mkStrictSuperClasses ev cls tys+ = mk_strict_superclasses (unitNameSet (className cls)) ev cls tys++mk_superclasses :: NameSet -> CtEvidence -> TcS [Ct]+-- Return this constraint, plus its superclasses, if any+mk_superclasses rec_clss ev+ | ClassPred cls tys <- classifyPredType (ctEvPred ev)+ = mk_superclasses_of rec_clss ev cls tys++ | otherwise -- Superclass is not a class predicate+ = return [mkNonCanonical ev]++mk_superclasses_of :: NameSet -> CtEvidence -> Class -> [Type] -> TcS [Ct]+-- Always return this class constraint,+-- and expand its superclasses+mk_superclasses_of rec_clss ev cls tys+ | loop_found = do { traceTcS "mk_superclasses_of: loop" (ppr cls <+> ppr tys)+ ; return [this_ct] } -- cc_pend_sc of this_ct = True+ | otherwise = do { traceTcS "mk_superclasses_of" (vcat [ ppr cls <+> ppr tys+ , ppr (isCTupleClass cls)+ , ppr rec_clss+ ])+ ; sc_cts <- mk_strict_superclasses rec_clss' ev cls tys+ ; return (this_ct : sc_cts) }+ -- cc_pend_sc of this_ct = False+ where+ cls_nm = className cls+ loop_found = not (isCTupleClass cls) && cls_nm `elemNameSet` rec_clss+ -- Tuples never contribute to recursion, and can be nested+ rec_clss' = rec_clss `extendNameSet` cls_nm+ this_ct = CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys+ , cc_pend_sc = loop_found }+ -- NB: If there is a loop, we cut off, so we have not+ -- added the superclasses, hence cc_pend_sc = True++mk_strict_superclasses :: NameSet -> CtEvidence -> Class -> [Type] -> TcS [Ct]+-- Always return the immediate superclasses of (cls tys);+-- and expand their superclasses, provided none of them are in rec_clss+-- nor are repeated+mk_strict_superclasses rec_clss ev cls tys+ | CtGiven { ctev_evar = evar, ctev_loc = loc } <- ev+ = do { sc_evs <- newGivenEvVars (mk_given_loc loc)+ (mkEvScSelectors (EvId evar) cls tys)+ ; concatMapM (mk_superclasses rec_clss) sc_evs }++ | all noFreeVarsOfType tys+ = return [] -- Wanteds with no variables yield no deriveds.+ -- See Note [Improvement from Ground Wanteds]++ | otherwise -- Wanted/Derived case, just add Derived superclasses+ -- that can lead to improvement.+ = do { let loc = ctEvLoc ev+ ; sc_evs <- mapM (newDerivedNC loc) (immSuperClasses cls tys)+ ; concatMapM (mk_superclasses rec_clss) sc_evs }+ where+ size = sizeTypes tys+ mk_given_loc loc+ | isCTupleClass cls+ = loc -- For tuple predicates, just take them apart, without+ -- adding their (large) size into the chain. When we+ -- get down to a base predicate, we'll include its size.+ -- Trac #10335++ | GivenOrigin skol_info <- ctLocOrigin loc+ -- See Note [Solving superclass constraints] in TcInstDcls+ -- for explantation of this transformation for givens+ = case skol_info of+ InstSkol -> loc { ctl_origin = GivenOrigin (InstSC size) }+ InstSC n -> loc { ctl_origin = GivenOrigin (InstSC (n `max` size)) }+ _ -> loc++ | otherwise -- Probably doesn't happen, since this function+ = loc -- is only used for Givens, but does no harm+++{-+************************************************************************+* *+* Irreducibles canonicalization+* *+************************************************************************+-}++canIrred :: CtEvidence -> TcS (StopOrContinue Ct)+-- Precondition: ty not a tuple and no other evidence form+canIrred old_ev+ = do { let old_ty = ctEvPred old_ev+ ; traceTcS "can_pred" (text "IrredPred = " <+> ppr old_ty)+ ; (xi,co) <- flatten FM_FlattenAll old_ev old_ty -- co :: xi ~ old_ty+ ; rewriteEvidence old_ev xi co `andWhenContinue` \ new_ev ->+ do { -- Re-classify, in case flattening has improved its shape+ ; 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+ _ -> continueWith $+ CIrredEvCan { cc_ev = new_ev } } }++canHole :: CtEvidence -> Hole -> TcS (StopOrContinue Ct)+canHole ev hole+ = do { let ty = ctEvPred ev+ ; (xi,co) <- flatten FM_SubstOnly ev ty -- co :: xi ~ ty+ ; rewriteEvidence ev xi co `andWhenContinue` \ new_ev ->+ do { emitInsoluble (CHoleCan { cc_ev = new_ev+ , cc_hole = hole })+ ; stopWith new_ev "Emit insoluble hole" } }++{-+************************************************************************+* *+* Equalities+* *+************************************************************************++Note [Canonicalising equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In order to canonicalise an equality, we look at the structure of the+two types at hand, looking for similarities. A difficulty is that the+types may look dissimilar before flattening but similar after flattening.+However, we don't just want to jump in and flatten right away, because+this might be wasted effort. So, after looking for similarities and failing,+we flatten and then try again. Of course, we don't want to loop, so we+track whether or not we've already flattened.++It is conceivable to do a better job at tracking whether or not a type+is flattened, but this is left as future work. (Mar '15)+++Note [FunTy and decomposing tycon applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When can_eq_nc' attempts to decompose a tycon application we haven't yet zonked.+This means that we may very well have a FunTy containing a type of some unknown+kind. For instance, we may have,++ FunTy (a :: k) Int++Where k is a unification variable. tcRepSplitTyConApp_maybe panics in the event+that it sees such a type as it cannot determine the RuntimeReps which the (->)+is applied to. Consequently, it is vital that we instead use+tcRepSplitTyConApp_maybe', which simply returns Nothing in such a case.++When this happens can_eq_nc' will fail to decompose, zonk, and try again.+Zonking should fill the variable k, meaning that decomposition will succeed the+second time around.+-}++canEqNC :: CtEvidence -> EqRel -> Type -> Type -> TcS (StopOrContinue Ct)+canEqNC ev eq_rel ty1 ty2+ = do { result <- zonk_eq_types ty1 ty2+ ; case result of+ Left (Pair ty1' ty2') -> can_eq_nc False ev eq_rel ty1' ty1 ty2' ty2+ Right ty -> canEqReflexive ev eq_rel ty }++can_eq_nc+ :: Bool -- True => both types are flat+ -> CtEvidence+ -> EqRel+ -> Type -> Type -- LHS, after and before type-synonym expansion, resp+ -> Type -> Type -- RHS, after and before type-synonym expansion, resp+ -> TcS (StopOrContinue Ct)+can_eq_nc flat ev eq_rel ty1 ps_ty1 ty2 ps_ty2+ = do { traceTcS "can_eq_nc" $+ vcat [ ppr flat, ppr ev, ppr eq_rel, ppr ty1, ppr ps_ty1, ppr ty2, ppr ps_ty2 ]+ ; rdr_env <- getGlobalRdrEnvTcS+ ; fam_insts <- getFamInstEnvs+ ; can_eq_nc' flat rdr_env fam_insts ev eq_rel ty1 ps_ty1 ty2 ps_ty2 }++can_eq_nc'+ :: Bool -- True => both input types are flattened+ -> GlobalRdrEnv -- needed to see which newtypes are in scope+ -> FamInstEnvs -- needed to unwrap data instances+ -> CtEvidence+ -> EqRel+ -> Type -> Type -- LHS, after and before type-synonym expansion, resp+ -> Type -> Type -- RHS, after and before type-synonym expansion, resp+ -> TcS (StopOrContinue Ct)++-- Expand synonyms first; see Note [Type synonyms and canonicalization]+can_eq_nc' flat _rdr_env _envs ev eq_rel ty1 ps_ty1 ty2 ps_ty2+ | Just ty1' <- tcView ty1 = can_eq_nc flat ev eq_rel ty1' ps_ty1 ty2 ps_ty2+ | Just ty2' <- tcView ty2 = can_eq_nc flat ev eq_rel ty1 ps_ty1 ty2' ps_ty2++-- need to check for reflexivity in the ReprEq case.+-- See Note [Eager reflexivity check]+-- Check only when flat because the zonk_eq_types check in canEqNC takes+-- care of the non-flat case.+can_eq_nc' True _rdr_env _envs ev ReprEq ty1 _ ty2 _+ | ty1 `tcEqType` ty2+ = canEqReflexive ev ReprEq ty1++-- When working with ReprEq, unwrap newtypes.+can_eq_nc' _flat rdr_env envs ev ReprEq ty1 _ ty2 ps_ty2+ | Just stuff1 <- tcTopNormaliseNewTypeTF_maybe envs rdr_env ty1+ = can_eq_newtype_nc ev NotSwapped ty1 stuff1 ty2 ps_ty2+can_eq_nc' _flat rdr_env envs ev ReprEq ty1 ps_ty1 ty2 _+ | Just stuff2 <- tcTopNormaliseNewTypeTF_maybe envs rdr_env ty2+ = can_eq_newtype_nc ev IsSwapped ty2 stuff2 ty1 ps_ty1++-- Then, get rid of casts+can_eq_nc' flat _rdr_env _envs ev eq_rel (CastTy ty1 co1) _ ty2 ps_ty2+ = canEqCast flat ev eq_rel NotSwapped ty1 co1 ty2 ps_ty2+can_eq_nc' flat _rdr_env _envs ev eq_rel ty1 ps_ty1 (CastTy ty2 co2) _+ = canEqCast flat ev eq_rel IsSwapped ty2 co2 ty1 ps_ty1++----------------------+-- Otherwise try to decompose+----------------------++-- Literals+can_eq_nc' _flat _rdr_env _envs ev eq_rel ty1@(LitTy l1) _ (LitTy l2) _+ | l1 == l2+ = do { setEqIfWanted ev (mkReflCo (eqRelRole eq_rel) ty1)+ ; stopWith ev "Equal LitTy" }++-- Try to decompose type constructor applications+-- Including FunTy (s -> t)+can_eq_nc' _flat _rdr_env _envs ev eq_rel ty1 _ ty2 _+ --- See Note [FunTy and decomposing type constructor applications].+ | Just (tc1, tys1) <- tcRepSplitTyConApp_maybe' ty1+ , Just (tc2, tys2) <- tcRepSplitTyConApp_maybe' ty2+ , not (isTypeFamilyTyCon tc1)+ , not (isTypeFamilyTyCon tc2)+ = canTyConApp ev eq_rel tc1 tys1 tc2 tys2++can_eq_nc' _flat _rdr_env _envs ev eq_rel+ s1@(ForAllTy {}) _ s2@(ForAllTy {}) _+ = can_eq_nc_forall ev eq_rel s1 s2++-- See Note [Canonicalising type applications] about why we require flat types+can_eq_nc' True _rdr_env _envs ev eq_rel (AppTy t1 s1) _ ty2 _+ | Just (t2, s2) <- tcSplitAppTy_maybe ty2+ = can_eq_app ev eq_rel t1 s1 t2 s2+can_eq_nc' True _rdr_env _envs ev eq_rel ty1 _ (AppTy t2 s2) _+ | Just (t1, s1) <- tcSplitAppTy_maybe ty1+ = can_eq_app ev eq_rel t1 s1 t2 s2++-- No similarity in type structure detected. Flatten and try again.+can_eq_nc' False rdr_env envs ev eq_rel _ ps_ty1 _ ps_ty2+ = do { (xi1, co1) <- flatten FM_FlattenAll ev ps_ty1+ ; (xi2, co2) <- flatten FM_FlattenAll ev ps_ty2+ ; rewriteEqEvidence ev NotSwapped xi1 xi2 co1 co2+ `andWhenContinue` \ new_ev ->+ can_eq_nc' True rdr_env envs new_ev eq_rel xi1 xi1 xi2 xi2 }++-- Type variable on LHS or RHS are last.+-- NB: pattern match on True: we want only flat types sent to canEqTyVar.+-- See also Note [No top-level newtypes on RHS of representational equalities]+can_eq_nc' True _rdr_env _envs ev eq_rel (TyVarTy tv1) ps_ty1 ty2 ps_ty2+ = canEqTyVar ev eq_rel NotSwapped tv1 ps_ty1 ty2 ps_ty2+can_eq_nc' True _rdr_env _envs ev eq_rel ty1 ps_ty1 (TyVarTy tv2) ps_ty2+ = canEqTyVar ev eq_rel IsSwapped tv2 ps_ty2 ty1 ps_ty1++-- We've flattened and the types don't match. Give up.+can_eq_nc' True _rdr_env _envs ev _eq_rel _ ps_ty1 _ ps_ty2+ = do { traceTcS "can_eq_nc' catch-all case" (ppr ps_ty1 $$ ppr ps_ty2)+ ; canEqHardFailure ev ps_ty1 ps_ty2 }++---------------------------------+can_eq_nc_forall :: CtEvidence -> EqRel+ -> Type -> Type -- LHS and RHS+ -> TcS (StopOrContinue Ct)+-- (forall as. phi1) ~ (forall bs. phi2)+-- Check for length match of as, bs+-- Then build an implication constraint: forall as. phi1 ~ phi2[as/bs]+-- But remember also to unify the kinds of as and bs+-- (this is the 'go' loop), and actually substitute phi2[as |> cos / bs]+-- Remember also that we might have forall z (a:z). blah+-- so we must proceed one binder at a time (Trac #13879)++can_eq_nc_forall ev eq_rel s1 s2+ | CtWanted { ctev_loc = loc, ctev_dest = orig_dest } <- ev+ = do { let free_tvs1 = tyCoVarsOfType s1+ free_tvs2 = tyCoVarsOfType s2+ (bndrs1, phi1) = tcSplitForAllTyVarBndrs s1+ (bndrs2, phi2) = tcSplitForAllTyVarBndrs s2+ ; if not (equalLength bndrs1 bndrs2)+ then do { traceTcS "Forall failure" $+ vcat [ ppr s1, ppr s2, ppr bndrs1, ppr bndrs2+ , ppr (map binderArgFlag bndrs1)+ , ppr (map binderArgFlag bndrs2) ]+ ; canEqHardFailure ev s1 s2 }+ else+ do { traceTcS "Creating implication for polytype equality" $ ppr ev+ ; let empty_subst1 = mkEmptyTCvSubst $ mkInScopeSet free_tvs1+ ; (subst1, skol_tvs) <- tcInstSkolTyVarsX empty_subst1 $+ binderVars bndrs1++ ; let skol_info = UnifyForAllSkol phi1+ phi1' = substTy subst1 phi1++ -- Unify the kinds, extend the substitution+ go (skol_tv:skol_tvs) subst (bndr2:bndrs2)+ = do { let tv2 = binderVar bndr2+ ; kind_co <- unifyWanted loc Nominal+ (tyVarKind skol_tv)+ (substTy subst (tyVarKind tv2))+ ; let subst' = extendTvSubst subst tv2+ (mkCastTy (mkTyVarTy skol_tv) kind_co)+ ; co <- go skol_tvs subst' bndrs2+ ; return (mkForAllCo skol_tv kind_co co) }++ -- Done: unify phi1 ~ phi2+ go [] subst bndrs2+ = ASSERT( null bndrs2 )+ unifyWanted loc (eqRelRole eq_rel)+ phi1' (substTy subst phi2)++ go _ _ _ = panic "cna_eq_nc_forall" -- case (s:ss) []++ empty_subst2 = mkEmptyTCvSubst $ mkInScopeSet $+ free_tvs2 `extendVarSetList` skol_tvs++ ; (implic, _ev_binds, all_co) <- buildImplication skol_info skol_tvs [] $+ go skol_tvs empty_subst2 bndrs2+ -- We have nowhere to put these bindings+ -- but TcSimplify.setImplicationStatus+ -- checks that we don't actually use them+ -- when skol_info = UnifyForAllSkol++ ; updWorkListTcS (extendWorkListImplic implic)+ ; setWantedEq orig_dest all_co+ ; stopWith ev "Deferred polytype equality" } }++ | otherwise+ = do { traceTcS "Omitting decomposition of given polytype equality" $+ pprEq s1 s2 -- See Note [Do not decompose given polytype equalities]+ ; stopWith ev "Discard given polytype equality" }++---------------------------------+-- | Compare types for equality, while zonking as necessary. Gives up+-- as soon as it finds that two types are not equal.+-- This is quite handy when some unification has made two+-- types in an inert wanted to be equal. We can discover the equality without+-- flattening, which is sometimes very expensive (in the case of type functions).+-- In particular, this function makes a ~20% improvement in test case+-- perf/compiler/T5030.+--+-- Returns either the (partially zonked) types in the case of+-- inequality, or the one type in the case of equality. canEqReflexive is+-- a good next step in the 'Right' case. Returning 'Left' is always safe.+--+-- NB: This does *not* look through type synonyms. In fact, it treats type+-- synonyms as rigid constructors. In the future, it might be convenient+-- to look at only those arguments of type synonyms that actually appear+-- in the synonym RHS. But we're not there yet.+zonk_eq_types :: TcType -> TcType -> TcS (Either (Pair TcType) TcType)+zonk_eq_types = go+ where+ go (TyVarTy tv1) (TyVarTy tv2) = tyvar_tyvar tv1 tv2+ go (TyVarTy tv1) ty2 = tyvar NotSwapped tv1 ty2+ go ty1 (TyVarTy tv2) = tyvar IsSwapped tv2 ty1++ -- We handle FunTys explicitly here despite the fact that they could also be+ -- treated as an application. Why? Well, for one it's cheaper to just look+ -- at two types (the argument and result types) than four (the argument,+ -- result, and their RuntimeReps). Also, we haven't completely zonked yet,+ -- so we may run into an unzonked type variable while trying to compute the+ -- RuntimeReps of the argument and result types. This can be observed in+ -- testcase tc269.+ go ty1 ty2+ | Just (arg1, res1) <- split1+ , Just (arg2, res2) <- split2+ = do { res_a <- go arg1 arg2+ ; res_b <- go res1 res2+ ; return $ combine_rev mkFunTy res_b res_a+ }+ | isJust split1 || isJust split2+ = bale_out ty1 ty2+ where+ split1 = tcSplitFunTy_maybe ty1+ split2 = tcSplitFunTy_maybe ty2++ go ty1 ty2+ | Just (tc1, tys1) <- tcRepSplitTyConApp_maybe ty1+ , Just (tc2, tys2) <- tcRepSplitTyConApp_maybe ty2+ = if tc1 == tc2 && tys1 `equalLength` tys2+ -- Crucial to check for equal-length args, because+ -- we cannot assume that the two args to 'go' have+ -- the same kind. E.g go (Proxy * (Maybe Int))+ -- (Proxy (*->*) Maybe)+ -- We'll call (go (Maybe Int) Maybe)+ -- See Trac #13083+ then tycon tc1 tys1 tys2+ else bale_out ty1 ty2++ go ty1 ty2+ | Just (ty1a, ty1b) <- tcRepSplitAppTy_maybe ty1+ , Just (ty2a, ty2b) <- tcRepSplitAppTy_maybe ty2+ = do { res_a <- go ty1a ty2a+ ; res_b <- go ty1b ty2b+ ; return $ combine_rev mkAppTy res_b res_a }++ go ty1@(LitTy lit1) (LitTy lit2)+ | lit1 == lit2+ = return (Right ty1)++ go ty1 ty2 = bale_out ty1 ty2+ -- We don't handle more complex forms here++ bale_out ty1 ty2 = return $ Left (Pair ty1 ty2)++ tyvar :: SwapFlag -> TcTyVar -> TcType+ -> TcS (Either (Pair TcType) TcType)+ -- Try to do as little as possible, as anything we do here is redundant+ -- with flattening. In particular, no need to zonk kinds. That's why+ -- we don't use the already-defined zonking functions+ tyvar swapped tv ty+ = case tcTyVarDetails tv of+ MetaTv { mtv_ref = ref }+ -> do { cts <- readTcRef ref+ ; case cts of+ Flexi -> give_up+ Indirect ty' -> unSwap swapped go ty' ty }+ _ -> give_up+ where+ give_up = return $ Left $ unSwap swapped Pair (mkTyVarTy tv) ty++ tyvar_tyvar tv1 tv2+ | tv1 == tv2 = return (Right (mkTyVarTy tv1))+ | otherwise = do { (ty1', progress1) <- quick_zonk tv1+ ; (ty2', progress2) <- quick_zonk tv2+ ; if progress1 || progress2+ then go ty1' ty2'+ else return $ Left (Pair (TyVarTy tv1) (TyVarTy tv2)) }++ quick_zonk tv = case tcTyVarDetails tv of+ MetaTv { mtv_ref = ref }+ -> do { cts <- readTcRef ref+ ; case cts of+ Flexi -> return (TyVarTy tv, False)+ Indirect ty' -> return (ty', True) }+ _ -> return (TyVarTy tv, False)++ -- This happens for type families, too. But recall that failure+ -- here just means to try harder, so it's OK if the type function+ -- isn't injective.+ tycon :: TyCon -> [TcType] -> [TcType]+ -> TcS (Either (Pair TcType) TcType)+ tycon tc tys1 tys2+ = do { results <- zipWithM go tys1 tys2+ ; return $ case combine_results results of+ Left tys -> Left (mkTyConApp tc <$> tys)+ Right tys -> Right (mkTyConApp tc tys) }++ combine_results :: [Either (Pair TcType) TcType]+ -> Either (Pair [TcType]) [TcType]+ combine_results = bimap (fmap reverse) reverse .+ foldl' (combine_rev (:)) (Right [])++ -- combine (in reverse) a new result onto an already-combined result+ combine_rev :: (a -> b -> c)+ -> Either (Pair b) b+ -> Either (Pair a) a+ -> Either (Pair c) c+ combine_rev f (Left list) (Left elt) = Left (f <$> elt <*> list)+ combine_rev f (Left list) (Right ty) = Left (f <$> pure ty <*> list)+ combine_rev f (Right tys) (Left elt) = Left (f <$> elt <*> pure tys)+ combine_rev f (Right tys) (Right ty) = Right (f ty tys)++{-+Note [Newtypes can blow the stack]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have++ newtype X = MkX (Int -> X)+ newtype Y = MkY (Int -> Y)++and now wish to prove++ [W] X ~R Y++This Wanted will loop, expanding out the newtypes ever deeper looking+for a solid match or a solid discrepancy. Indeed, there is something+appropriate to this looping, because X and Y *do* have the same representation,+in the limit -- they're both (Fix ((->) Int)). However, no finitely-sized+coercion will ever witness it. This loop won't actually cause GHC to hang,+though, because we check our depth when unwrapping newtypes.++Note [Eager reflexivity check]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have++ newtype X = MkX (Int -> X)++and++ [W] X ~R X++Naively, we would start unwrapping X and end up in a loop. Instead,+we do this eager reflexivity check. This is necessary only for representational+equality because the flattener technology deals with the similar case+(recursive type families) for nominal equality.++Note that this check does not catch all cases, but it will catch the cases+we're most worried about, types like X above that are actually inhabited.++Here's another place where this reflexivity check is key:+Consider trying to prove (f a) ~R (f a). The AppTys in there can't+be decomposed, because representational equality isn't congruent with respect+to AppTy. So, when canonicalising the equality above, we get stuck and+would normally produce a CIrredEvCan. However, we really do want to+be able to solve (f a) ~R (f a). So, in the representational case only,+we do a reflexivity check.++(This would be sound in the nominal case, but unnecessary, and I [Richard+E.] am worried that it would slow down the common case.)+-}++------------------------+-- | We're able to unwrap a newtype. Update the bits accordingly.+can_eq_newtype_nc :: CtEvidence -- ^ :: ty1 ~ ty2+ -> SwapFlag+ -> TcType -- ^ ty1+ -> ((Bag GlobalRdrElt, TcCoercion), TcType) -- ^ :: ty1 ~ ty1'+ -> TcType -- ^ ty2+ -> TcType -- ^ ty2, with type synonyms+ -> TcS (StopOrContinue Ct)+can_eq_newtype_nc ev swapped ty1 ((gres, co), ty1') ty2 ps_ty2+ = do { traceTcS "can_eq_newtype_nc" $+ vcat [ ppr ev, ppr swapped, ppr co, ppr gres, ppr ty1', ppr ty2 ]++ -- check for blowing our stack:+ -- See Note [Newtypes can blow the stack]+ ; checkReductionDepth (ctEvLoc ev) ty1+ ; addUsedGREs (bagToList gres)+ -- we have actually used the newtype constructor here, so+ -- make sure we don't warn about importing it!++ ; rewriteEqEvidence ev swapped ty1' ps_ty2+ (mkTcSymCo co) (mkTcReflCo Representational ps_ty2)+ `andWhenContinue` \ new_ev ->+ can_eq_nc False new_ev ReprEq ty1' ty1' ty2 ps_ty2 }++---------+-- ^ Decompose a type application.+-- All input types must be flat. See Note [Canonicalising type applications]+can_eq_app :: CtEvidence -- :: s1 t1 ~r s2 t2+ -> EqRel -- r+ -> Xi -> Xi -- s1 t1+ -> Xi -> Xi -- s2 t2+ -> TcS (StopOrContinue Ct)++-- AppTys only decompose for nominal equality, so this case just leads+-- to an irreducible constraint; see typecheck/should_compile/T10494+-- See Note [Decomposing equality], note {4}+can_eq_app ev ReprEq _ _ _ _+ = do { traceTcS "failing to decompose representational AppTy equality" (ppr ev)+ ; continueWith (CIrredEvCan { cc_ev = ev }) }+ -- no need to call canEqFailure, because that flattens, and the+ -- types involved here are already flat++can_eq_app ev NomEq s1 t1 s2 t2+ | CtDerived { ctev_loc = loc } <- ev+ = do { unifyDeriveds loc [Nominal, Nominal] [s1, t1] [s2, t2]+ ; stopWith ev "Decomposed [D] AppTy" }+ | CtWanted { ctev_dest = dest, ctev_loc = loc } <- ev+ = do { co_s <- unifyWanted loc Nominal s1 s2+ ; co_t <- unifyWanted loc Nominal t1 t2+ ; let co = mkAppCo co_s co_t+ ; setWantedEq dest co+ ; stopWith ev "Decomposed [W] AppTy" }+ | CtGiven { ctev_evar = evar, ctev_loc = loc } <- ev+ = do { let co = mkTcCoVarCo evar+ co_s = mkTcLRCo CLeft co+ co_t = mkTcLRCo CRight co+ ; evar_s <- newGivenEvVar loc ( mkTcEqPredLikeEv ev s1 s2+ , EvCoercion co_s )+ ; evar_t <- newGivenEvVar loc ( mkTcEqPredLikeEv ev t1 t2+ , EvCoercion co_t )+ ; emitWorkNC [evar_t]+ ; canEqNC evar_s NomEq s1 s2 }+ | otherwise -- Can't happen+ = error "can_eq_app"++-----------------------+-- | Break apart an equality over a casted type+-- looking like (ty1 |> co1) ~ ty2 (modulo a swap-flag)+canEqCast :: Bool -- are both types flat?+ -> CtEvidence+ -> EqRel+ -> SwapFlag+ -> TcType -> Coercion -- LHS (res. RHS), ty1 |> co1+ -> TcType -> TcType -- RHS (res. LHS), ty2 both normal and pretty+ -> TcS (StopOrContinue Ct)+canEqCast flat ev eq_rel swapped ty1 co1 ty2 ps_ty2+ = do { traceTcS "Decomposing cast" (vcat [ ppr ev+ , ppr ty1 <+> text "|>" <+> ppr co1+ , ppr ps_ty2 ])+ ; rewriteEqEvidence ev swapped ty1 ps_ty2+ (mkTcReflCo role ty1+ `mkTcCoherenceRightCo` co1)+ (mkTcReflCo role ps_ty2)+ `andWhenContinue` \ new_ev ->+ can_eq_nc flat new_ev eq_rel ty1 ty1 ty2 ps_ty2 }+ where+ role = eqRelRole eq_rel++------------------------+canTyConApp :: CtEvidence -> EqRel+ -> TyCon -> [TcType]+ -> TyCon -> [TcType]+ -> TcS (StopOrContinue Ct)+-- See Note [Decomposing TyConApps]+canTyConApp ev eq_rel tc1 tys1 tc2 tys2+ | tc1 == tc2+ , length tys1 == length tys2+ = do { inerts <- getTcSInerts+ ; if can_decompose inerts+ then do { traceTcS "canTyConApp"+ (ppr ev $$ ppr eq_rel $$ ppr tc1 $$ ppr tys1 $$ ppr tys2)+ ; canDecomposableTyConAppOK ev eq_rel tc1 tys1 tys2+ ; stopWith ev "Decomposed TyConApp" }+ else canEqFailure ev eq_rel ty1 ty2 }++ -- See Note [Skolem abstract data] (at tyConSkolem)+ | tyConSkolem tc1 || tyConSkolem tc2+ = do { traceTcS "canTyConApp: skolem abstract" (ppr tc1 $$ ppr tc2)+ ; continueWith (CIrredEvCan { cc_ev = ev }) }++ -- Fail straight away for better error messages+ -- See Note [Use canEqFailure in canDecomposableTyConApp]+ | eq_rel == ReprEq && not (isGenerativeTyCon tc1 Representational &&+ isGenerativeTyCon tc2 Representational)+ = canEqFailure ev eq_rel ty1 ty2+ | otherwise+ = canEqHardFailure ev ty1 ty2+ where+ ty1 = mkTyConApp tc1 tys1+ ty2 = mkTyConApp tc2 tys2++ loc = ctEvLoc ev+ pred = ctEvPred ev++ -- See Note [Decomposing equality]+ can_decompose inerts+ = isInjectiveTyCon tc1 (eqRelRole eq_rel)+ || (ctEvFlavour ev /= Given && isEmptyBag (matchableGivens loc pred inerts))++{-+Note [Use canEqFailure in canDecomposableTyConApp]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must use canEqFailure, not canEqHardFailure here, because there is+the possibility of success if working with a representational equality.+Here is one case:++ type family TF a where TF Char = Bool+ data family DF a+ newtype instance DF Bool = MkDF Int++Suppose we are canonicalising (Int ~R DF (TF a)), where we don't yet+know `a`. This is *not* a hard failure, because we might soon learn+that `a` is, in fact, Char, and then the equality succeeds.++Here is another case:++ [G] Age ~R Int++where Age's constructor is not in scope. We don't want to report+an "inaccessible code" error in the context of this Given!++For example, see typecheck/should_compile/T10493, repeated here:++ import Data.Ord (Down) -- no constructor++ foo :: Coercible (Down Int) Int => Down Int -> Int+ foo = coerce++That should compile, but only because we use canEqFailure and not+canEqHardFailure.++Note [Decomposing equality]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have a constraint (of any flavour and role) that looks like+T tys1 ~ T tys2, what can we conclude about tys1 and tys2? The answer,+of course, is "it depends". This Note spells it all out.++In this Note, "decomposition" refers to taking the constraint+ [fl] (T tys1 ~X T tys2)+(for some flavour fl and some role X) and replacing it with+ [fls'] (tys1 ~Xs' tys2)+where that notation indicates a list of new constraints, where the+new constraints may have different flavours and different roles.++The key property to consider is injectivity. When decomposing a Given the+decomposition is sound if and only if T is injective in all of its type+arguments. When decomposing a Wanted, the decomposition is sound (assuming the+correct roles in the produced equality constraints), but it may be a guess --+that is, an unforced decision by the constraint solver. Decomposing Wanteds+over injective TyCons does not entail guessing. But sometimes we want to+decompose a Wanted even when the TyCon involved is not injective! (See below.)++So, in broad strokes, we want this rule:++(*) Decompose a constraint (T tys1 ~X T tys2) if and only if T is injective+at role X.++Pursuing the details requires exploring three axes:+* Flavour: Given vs. Derived vs. Wanted+* Role: Nominal vs. Representational+* TyCon species: datatype vs. newtype vs. data family vs. type family vs. type variable++(So a type variable isn't a TyCon, but it's convenient to put the AppTy case+in the same table.)++Right away, we can say that Derived behaves just as Wanted for the purposes+of decomposition. The difference between Derived and Wanted is the handling of+evidence. Since decomposition in these cases isn't a matter of soundness but of+guessing, we want the same behavior regardless of evidence.++Here is a table (discussion following) detailing where decomposition of+ (T s1 ... sn) ~r (T t1 .. tn)+is allowed. The first four lines (Data types ... type family) refer+to TyConApps with various TyCons T; the last line is for AppTy, where+there is presumably a type variable at the head, so it's actually+ (s s1 ... sn) ~r (t t1 .. tn)++NOMINAL GIVEN WANTED++Datatype YES YES+Newtype YES YES+Data family YES YES+Type family YES, in injective args{1} YES, in injective args{1}+Type variable YES YES++REPRESENTATIONAL GIVEN WANTED++Datatype YES YES+Newtype NO{2} MAYBE{2}+Data family NO{3} MAYBE{3}+Type family NO NO+Type variable NO{4} NO{4}++{1}: Type families can be injective in some, but not all, of their arguments,+so we want to do partial decomposition. This is quite different than the way+other decomposition is done, where the decomposed equalities replace the original+one. We thus proceed much like we do with superclasses: emitting new Givens+when "decomposing" a partially-injective type family Given and new Deriveds+when "decomposing" a partially-injective type family Wanted. (As of the time of+writing, 13 June 2015, the implementation of injective type families has not+been merged, but it should be soon. Please delete this parenthetical if the+implementation is indeed merged.)++{2}: See Note [Decomposing newtypes at representational role]++{3}: Because of the possibility of newtype instances, we must treat+data families like newtypes. See also Note [Decomposing newtypes at+representational role]. See #10534 and test case+typecheck/should_fail/T10534.++{4}: Because type variables can stand in for newtypes, we conservatively do not+decompose AppTys over representational equality.++In the implementation of can_eq_nc and friends, we don't directly pattern+match using lines like in the tables above, as those tables don't cover+all cases (what about PrimTyCon? tuples?). Instead we just ask about injectivity,+boiling the tables above down to rule (*). The exceptions to rule (*) are for+injective type families, which are handled separately from other decompositions,+and the MAYBE entries above.++Note [Decomposing newtypes at representational role]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+This note discusses the 'newtype' line in the REPRESENTATIONAL table+in Note [Decomposing equality]. (At nominal role, newtypes are fully+decomposable.)++Here is a representative example of why representational equality over+newtypes is tricky:++ newtype Nt a = Mk Bool -- NB: a is not used in the RHS,+ type role Nt representational -- but the user gives it an R role anyway++If we have [W] Nt alpha ~R Nt beta, we *don't* want to decompose to+[W] alpha ~R beta, because it's possible that alpha and beta aren't+representationally equal. Here's another example.++ newtype Nt a = MkNt (Id a)+ type family Id a where Id a = a++ [W] Nt Int ~R Nt Age++Because of its use of a type family, Nt's parameter will get inferred to have+a nominal role. Thus, decomposing the wanted will yield [W] Int ~N Age, which+is unsatisfiable. Unwrapping, though, leads to a solution.++Conclusion:+ * Unwrap newtypes before attempting to decompose them.+ This is done in can_eq_nc'.++It all comes from the fact that newtypes aren't necessarily injective+w.r.t. representational equality.++Furthermore, as explained in Note [NthCo and newtypes] in TyCoRep, we can't use+NthCo on representational coercions over newtypes. NthCo comes into play+only when decomposing givens.++Conclusion:+ * Do not decompose [G] N s ~R N t++Is it sensible to decompose *Wanted* constraints over newtypes? Yes!+It's the only way we could ever prove (IO Int ~R IO Age), recalling+that IO is a newtype.++However we must be careful. Consider++ type role Nt representational++ [G] Nt a ~R Nt b (1)+ [W] NT alpha ~R Nt b (2)+ [W] alpha ~ a (3)++If we focus on (3) first, we'll substitute in (2), and now it's+identical to the given (1), so we succeed. But if we focus on (2)+first, and decompose it, we'll get (alpha ~R b), which is not soluble.+This is exactly like the question of overlapping Givens for class+constraints: see Note [Instance and Given overlap] in TcInteract.++Conclusion:+ * Decompose [W] N s ~R N t iff there no given constraint that could+ later solve it.+-}++canDecomposableTyConAppOK :: CtEvidence -> EqRel+ -> TyCon -> [TcType] -> [TcType]+ -> TcS ()+-- Precondition: tys1 and tys2 are the same length, hence "OK"+canDecomposableTyConAppOK ev eq_rel tc tys1 tys2+ = case ev of+ CtDerived {}+ -> unifyDeriveds loc tc_roles tys1 tys2++ CtWanted { ctev_dest = dest }+ -> do { cos <- zipWith4M unifyWanted new_locs tc_roles tys1 tys2+ ; setWantedEq dest (mkTyConAppCo role tc cos) }++ CtGiven { ctev_evar = evar }+ -> do { let ev_co = mkCoVarCo evar+ ; given_evs <- newGivenEvVars loc $+ [ ( mkPrimEqPredRole r ty1 ty2+ , EvCoercion (mkNthCo i ev_co) )+ | (r, ty1, ty2, i) <- zip4 tc_roles tys1 tys2 [0..]+ , r /= Phantom+ , not (isCoercionTy ty1) && not (isCoercionTy ty2) ]+ ; emitWorkNC given_evs }+ where+ loc = ctEvLoc ev+ role = eqRelRole eq_rel+ tc_roles = tyConRolesX role tc++ -- the following makes a better distinction between "kind" and "type"+ -- in error messages+ bndrs = tyConBinders tc+ kind_loc = toKindLoc loc+ is_kinds = map isNamedTyConBinder bndrs+ new_locs | Just KindLevel <- ctLocTypeOrKind_maybe loc+ = repeat loc+ | otherwise+ = map (\is_kind -> if is_kind then kind_loc else loc) is_kinds+++-- | Call when canonicalizing an equality fails, but if the equality is+-- representational, there is some hope for the future.+-- Examples in Note [Use canEqFailure in canDecomposableTyConApp]+canEqFailure :: CtEvidence -> EqRel+ -> TcType -> TcType -> TcS (StopOrContinue Ct)+canEqFailure ev NomEq ty1 ty2+ = canEqHardFailure ev ty1 ty2+canEqFailure ev ReprEq ty1 ty2+ = do { (xi1, co1) <- flatten FM_FlattenAll ev ty1+ ; (xi2, co2) <- flatten FM_FlattenAll ev ty2+ -- We must flatten the types before putting them in the+ -- inert set, so that we are sure to kick them out when+ -- new equalities become available+ ; traceTcS "canEqFailure with ReprEq" $+ vcat [ ppr ev, ppr ty1, ppr ty2, ppr xi1, ppr xi2 ]+ ; rewriteEqEvidence ev NotSwapped xi1 xi2 co1 co2+ `andWhenContinue` \ new_ev ->+ continueWith (CIrredEvCan { cc_ev = new_ev }) }++-- | Call when canonicalizing an equality fails with utterly no hope.+canEqHardFailure :: CtEvidence+ -> TcType -> TcType -> TcS (StopOrContinue Ct)+-- See Note [Make sure that insolubles are fully rewritten]+canEqHardFailure ev ty1 ty2+ = do { (s1, co1) <- flatten FM_SubstOnly ev ty1+ ; (s2, co2) <- flatten FM_SubstOnly ev ty2+ ; rewriteEqEvidence ev NotSwapped s1 s2 co1 co2+ `andWhenContinue` \ new_ev ->+ do { emitInsoluble (mkNonCanonical new_ev)+ ; stopWith new_ev "Definitely not equal" }}++{-+Note [Decomposing TyConApps]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we see (T s1 t1 ~ T s2 t2), then we can just decompose to+ (s1 ~ s2, t1 ~ t2)+and push those back into the work list. But if+ s1 = K k1 s2 = K k2+then we will just decomopose s1~s2, and it might be better to+do so on the spot. An important special case is where s1=s2,+and we get just Refl.++So canDecomposableTyCon is a fast-path decomposition that uses+unifyWanted etc to short-cut that work.++Note [Canonicalising type applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Given (s1 t1) ~ ty2, how should we proceed?+The simple things is to see if ty2 is of form (s2 t2), and+decompose. By this time s1 and s2 can't be saturated type+function applications, because those have been dealt with+by an earlier equation in can_eq_nc, so it is always sound to+decompose.++However, over-eager decomposition gives bad error messages+for things like+ a b ~ Maybe c+ e f ~ p -> q+Suppose (in the first example) we already know a~Array. Then if we+decompose the application eagerly, yielding+ a ~ Maybe+ b ~ c+we get an error "Can't match Array ~ Maybe",+but we'd prefer to get "Can't match Array b ~ Maybe c".++So instead can_eq_wanted_app flattens the LHS and RHS, in the hope of+replacing (a b) by (Array b), before using try_decompose_app to+decompose it.++Note [Make sure that insolubles are fully rewritten]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When an equality fails, we still want to rewrite the equality+all the way down, so that it accurately reflects+ (a) the mutable reference substitution in force at start of solving+ (b) any ty-binds in force at this point in solving+See Note [Kick out insolubles] in TcSMonad.+And if we don't do this there is a bad danger that+TcSimplify.applyTyVarDefaulting will find a variable+that has in fact been substituted.++Note [Do not decompose Given polytype equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider [G] (forall a. t1 ~ forall a. t2). Can we decompose this?+No -- what would the evidence look like? So instead we simply discard+this given evidence.+++Note [Combining insoluble constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As this point we have an insoluble constraint, like Int~Bool.++ * If it is Wanted, delete it from the cache, so that subsequent+ Int~Bool constraints give rise to separate error messages++ * But if it is Derived, DO NOT delete from cache. A class constraint+ may get kicked out of the inert set, and then have its functional+ dependency Derived constraints generated a second time. In that+ case we don't want to get two (or more) error messages by+ generating two (or more) insoluble fundep constraints from the same+ class constraint.++Note [No top-level newtypes on RHS of representational equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we're in this situation:++ work item: [W] c1 : a ~R b+ inert: [G] c2 : b ~R Id a++where+ newtype Id a = Id a++We want to make sure canEqTyVar sees [W] a ~R a, after b is flattened+and the Id newtype is unwrapped. This is assured by requiring only flat+types in canEqTyVar *and* having the newtype-unwrapping check above+the tyvar check in can_eq_nc.++Note [Occurs check error]+~~~~~~~~~~~~~~~~~~~~~~~~~+If we have an occurs check error, are we necessarily hosed? Say our+tyvar is tv1 and the type it appears in is xi2. Because xi2 is function+free, then if we're computing w.r.t. nominal equality, then, yes, we're+hosed. Nothing good can come from (a ~ [a]). If we're computing w.r.t.+representational equality, this is a little subtler. Once again, (a ~R [a])+is a bad thing, but (a ~R N a) for a newtype N might be just fine. This+means also that (a ~ b a) might be fine, because `b` might become a newtype.++So, we must check: does tv1 appear in xi2 under any type constructor that+is generative w.r.t. representational equality? That's what isTyVarUnderDatatype+does. (The other name I considered, isTyVarUnderTyConGenerativeWrtReprEq was+a bit verbose. And the shorter name gets the point across.)++See also #10715, which induced this addition.++Note [No derived kind equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we're working with a heterogeneous derived equality++ [D] (t1 :: k1) ~ (t2 :: k2)++we want to homogenise to establish the kind invariant on CTyEqCans.+But we can't emit [D] k1 ~ k2 because we wouldn't then be able to+use the evidence in the homogenised types. So we emit a wanted+constraint, because we do really need the evidence here.++Thus: no derived kind equalities.++-}++canCFunEqCan :: CtEvidence+ -> TyCon -> [TcType] -- LHS+ -> TcTyVar -- RHS+ -> TcS (StopOrContinue Ct)+-- ^ Canonicalise a CFunEqCan. We know that+-- the arg types are already flat,+-- and the RHS is a fsk, which we must *not* substitute.+-- So just substitute in the LHS+canCFunEqCan ev fn tys fsk+ = do { (tys', cos) <- flattenManyNom ev tys+ -- cos :: tys' ~ tys+ ; let lhs_co = mkTcTyConAppCo Nominal fn cos+ -- :: F tys' ~ F tys+ new_lhs = mkTyConApp fn tys'+ fsk_ty = mkTyVarTy fsk+ ; rewriteEqEvidence ev NotSwapped new_lhs fsk_ty+ lhs_co (mkTcNomReflCo fsk_ty)+ `andWhenContinue` \ ev' ->+ do { extendFlatCache fn tys' (ctEvCoercion ev', fsk_ty, ctEvFlavour ev')+ ; continueWith (CFunEqCan { cc_ev = ev', cc_fun = fn+ , cc_tyargs = tys', cc_fsk = fsk }) } }++---------------------+canEqTyVar :: CtEvidence -- ev :: lhs ~ rhs+ -> EqRel -> SwapFlag+ -> TcTyVar -> TcType -- lhs: already flat, not a cast+ -> TcType -> TcType -- rhs: already flat, not a cast+ -> TcS (StopOrContinue Ct)+canEqTyVar ev eq_rel swapped tv1 ps_ty1 (TyVarTy tv2) _+ | tv1 == tv2+ = canEqReflexive ev eq_rel ps_ty1++ | swapOverTyVars tv1 tv2+ = do { traceTcS "canEqTyVar" (ppr tv1 $$ ppr tv2 $$ ppr swapped)+ -- FM_Avoid commented out: see Note [Lazy flattening] in TcFlatten+ -- let fmode = FE { fe_ev = ev, fe_mode = FM_Avoid tv1' True }+ -- Flatten the RHS less vigorously, to avoid gratuitous flattening+ -- True <=> xi2 should not itself be a type-function application+ ; dflags <- getDynFlags+ ; canEqTyVar2 dflags ev eq_rel (flipSwap swapped) tv2 ps_ty1 }++canEqTyVar ev eq_rel swapped tv1 _ _ ps_ty2+ = do { dflags <- getDynFlags+ ; canEqTyVar2 dflags ev eq_rel swapped tv1 ps_ty2 }++canEqTyVar2 :: DynFlags+ -> CtEvidence -- lhs ~ rhs (or, if swapped, orhs ~ olhs)+ -> EqRel+ -> SwapFlag+ -> TcTyVar -- lhs, flat+ -> TcType -- rhs, flat+ -> TcS (StopOrContinue Ct)+-- LHS is an inert type variable,+-- and RHS is fully rewritten, but with type synonyms+-- preserved as much as possible++canEqTyVar2 dflags ev eq_rel swapped tv1 xi2+ | Just xi2' <- metaTyVarUpdateOK dflags tv1 xi2 -- No occurs check+ -- Must do the occurs check even on tyvar/tyvar+ -- equalities, in case have x ~ (y :: ..x...)+ -- Trac #12593+ = rewriteEqEvidence ev swapped xi1 xi2' co1 co2+ `andWhenContinue` \ new_ev ->+ homogeniseRhsKind new_ev eq_rel xi1 xi2' $ \new_new_ev xi2'' ->+ CTyEqCan { cc_ev = new_new_ev, cc_tyvar = tv1+ , cc_rhs = xi2'', cc_eq_rel = eq_rel }++ | otherwise -- For some reason (occurs check, or forall) we can't unify+ -- We must not use it for further rewriting!+ = do { traceTcS "canEqTyVar2 can't unify" (ppr tv1 $$ ppr xi2)+ ; rewriteEqEvidence ev swapped xi1 xi2 co1 co2+ `andWhenContinue` \ new_ev ->+ if isInsolubleOccursCheck eq_rel tv1 xi2+ then do { emitInsoluble (mkNonCanonical new_ev)+ -- If we have a ~ [a], it is not canonical, and in particular+ -- we don't want to rewrite existing inerts with it, otherwise+ -- we'd risk divergence in the constraint solver+ ; stopWith new_ev "Occurs check" }++ -- A representational equality with an occurs-check problem isn't+ -- insoluble! For example:+ -- a ~R b a+ -- We might learn that b is the newtype Id.+ -- But, the occurs-check certainly prevents the equality from being+ -- canonical, and we might loop if we were to use it in rewriting.+ else do { traceTcS "Possibly-soluble occurs check"+ (ppr xi1 $$ ppr xi2)+ ; continueWith (CIrredEvCan { cc_ev = new_ev }) } }+ where+ role = eqRelRole eq_rel+ xi1 = mkTyVarTy tv1+ co1 = mkTcReflCo role xi1+ co2 = mkTcReflCo role xi2++-- | Solve a reflexive equality constraint+canEqReflexive :: CtEvidence -- ty ~ ty+ -> EqRel+ -> TcType -- ty+ -> TcS (StopOrContinue Ct) -- always Stop+canEqReflexive ev eq_rel ty+ = do { setEvBindIfWanted ev (EvCoercion $+ mkTcReflCo (eqRelRole eq_rel) ty)+ ; stopWith ev "Solved by reflexivity" }++-- See Note [Equalities with incompatible kinds]+homogeniseRhsKind :: CtEvidence -- ^ the evidence to homogenise+ -> EqRel+ -> TcType -- ^ original LHS+ -> Xi -- ^ original RHS+ -> (CtEvidence -> Xi -> Ct)+ -- ^ how to build the homogenised constraint;+ -- the 'Xi' is the new RHS+ -> TcS (StopOrContinue Ct)+homogeniseRhsKind ev eq_rel lhs rhs build_ct+ | k1 `tcEqType` k2+ = continueWith (build_ct ev rhs)++ | CtGiven { ctev_evar = evar } <- ev+ -- tm :: (lhs :: k1) ~ (rhs :: k2)+ = do { kind_ev_id <- newBoundEvVarId kind_pty+ (EvCoercion $+ mkTcKindCo $ mkTcCoVarCo evar)+ -- kind_ev_id :: (k1 :: *) ~# (k2 :: *)+ ; let kind_ev = CtGiven { ctev_pred = kind_pty+ , ctev_evar = kind_ev_id+ , ctev_loc = kind_loc }+ homo_co = mkSymCo $ mkCoVarCo kind_ev_id+ rhs' = mkCastTy rhs homo_co+ ; traceTcS "Hetero equality gives rise to given kind equality"+ (ppr kind_ev_id <+> dcolon <+> ppr kind_pty)+ ; emitWorkNC [kind_ev]+ ; type_ev <- newGivenEvVar loc+ ( mkTcEqPredLikeEv ev lhs rhs'+ , EvCoercion $+ mkTcCoherenceRightCo (mkTcCoVarCo evar) homo_co )+ -- type_ev :: (lhs :: k1) ~ ((rhs |> sym kind_ev_id) :: k1)+ ; continueWith (build_ct type_ev rhs') }++ | otherwise -- Wanted and Derived. See Note [No derived kind equalities]+ -- evar :: (lhs :: k1) ~ (rhs :: k2)+ = do { kind_co <- emitNewWantedEq kind_loc Nominal k1 k2+ -- kind_ev :: (k1 :: *) ~ (k2 :: *)+ ; traceTcS "Hetero equality gives rise to wanted kind equality" $+ ppr (kind_co)+ ; let homo_co = mkSymCo kind_co+ -- homo_co :: k2 ~ k1+ rhs' = mkCastTy rhs homo_co+ ; case ev of+ CtGiven {} -> panic "homogeniseRhsKind"+ CtDerived {} -> continueWith (build_ct (ev { ctev_pred = homo_pred })+ rhs')+ where homo_pred = mkTcEqPredLikeEv ev lhs rhs'+ CtWanted { ctev_dest = dest } -> do+ { (type_ev, hole_co) <- newWantedEq loc role lhs rhs'+ -- type_ev :: (lhs :: k1) ~ (rhs |> sym kind_co :: k1)+ ; setWantedEq dest+ (hole_co `mkTransCo`+ (mkReflCo role rhs+ `mkCoherenceLeftCo` homo_co))++ -- dest := hole ; <rhs> |> homo_co :: (lhs :: k1) ~ (rhs :: k2)+ ; continueWith (build_ct type_ev rhs') }}++ where+ k1 = typeKind lhs+ k2 = typeKind rhs++ kind_pty = mkHeteroPrimEqPred liftedTypeKind liftedTypeKind k1 k2+ kind_loc = mkKindLoc lhs rhs loc++ loc = ctev_loc ev+ role = eqRelRole eq_rel++{-+Note [Canonical orientation for tyvar/tyvar equality constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we have a ~ b where both 'a' and 'b' are TcTyVars, which way+round should be oriented in the CTyEqCan? The rules, implemented by+canEqTyVarTyVar, are these++ * If either is a flatten-meta-variables, it goes on the left.++ * Put a meta-tyvar on the left if possible+ alpha[3] ~ r++ * If both are meta-tyvars, put the more touchable one (deepest level+ number) on the left, so there is the best chance of unifying it+ alpha[3] ~ beta[2]++ * If both are meta-tyvars and both at the same level, put a SigTv+ on the right if possible+ alpha[2] ~ beta[2](sig-tv)+ That way, when we unify alpha := beta, we don't lose the SigTv flag.++ * Put a meta-tv with a System Name on the left if possible so it+ gets eliminated (improves error messages)++ * If one is a flatten-skolem, put it on the left so that it is+ substituted out Note [Elminate flat-skols]+ fsk ~ a++Note [Avoid unnecessary swaps]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we swap without actually improving matters, we can get an infnite loop.+Consider+ work item: a ~ b+ inert item: b ~ c+We canonicalise the work-time to (a ~ c). If we then swap it before+aeding to the inert set, we'll add (c ~ a), and therefore kick out the+inert guy, so we get+ new work item: b ~ c+ inert item: c ~ a+And now the cycle just repeats++Note [Eliminate flat-skols]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have [G] Num (F [a])+then we flatten to+ [G] Num fsk+ [G] F [a] ~ fsk+where fsk is a flatten-skolem (FlatSkol). Suppose we have+ type instance F [a] = a+then we'll reduce the second constraint to+ [G] a ~ fsk+and then replace all uses of 'a' with fsk. That's bad because+in error messages intead of saying 'a' we'll say (F [a]). In all+places, including those where the programmer wrote 'a' in the first+place. Very confusing! See Trac #7862.++Solution: re-orient a~fsk to fsk~a, so that we preferentially eliminate+the fsk.++Note [Equalities with incompatible kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+canEqLeaf is about to make a CTyEqCan or CFunEqCan; but both have the+invariant that LHS and RHS satisfy the kind invariants for CTyEqCan,+CFunEqCan. What if we try to unify two things with incompatible+kinds?++eg a ~ b where a::*, b::*->*+or a ~ b where a::*, b::k, k is a kind variable++The CTyEqCan compatKind invariant is important. If we make a CTyEqCan+for a~b, then we might well *substitute* 'b' for 'a', and that might make+a well-kinded type ill-kinded; and that is bad (eg typeKind can crash, see+Trac #7696).++So instead for these ill-kinded equalities we homogenise the RHS of the+equality, emitting new constraints as necessary.++Note [Type synonyms and canonicalization]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We treat type synonym applications as xi types, that is, they do not+count as type function applications. However, we do need to be a bit+careful with type synonyms: like type functions they may not be+generative or injective. However, unlike type functions, they are+parametric, so there is no problem in expanding them whenever we see+them, since we do not need to know anything about their arguments in+order to expand them; this is what justifies not having to treat them+as specially as type function applications. The thing that causes+some subtleties is that we prefer to leave type synonym applications+*unexpanded* whenever possible, in order to generate better error+messages.++If we encounter an equality constraint with type synonym applications+on both sides, or a type synonym application on one side and some sort+of type application on the other, we simply must expand out the type+synonyms in order to continue decomposing the equality constraint into+primitive equality constraints. For example, suppose we have++ type F a = [Int]++and we encounter the equality++ F a ~ [b]++In order to continue we must expand F a into [Int], giving us the+equality++ [Int] ~ [b]++which we can then decompose into the more primitive equality+constraint++ Int ~ b.++However, if we encounter an equality constraint with a type synonym+application on one side and a variable on the other side, we should+NOT (necessarily) expand the type synonym, since for the purpose of+good error messages we want to leave type synonyms unexpanded as much+as possible. Hence the ps_ty1, ps_ty2 argument passed to canEqTyVar.++-}++{-+************************************************************************+* *+ Evidence transformation+* *+************************************************************************+-}++data StopOrContinue a+ = ContinueWith a -- The constraint was not solved, although it may have+ -- been rewritten++ | Stop CtEvidence -- The (rewritten) constraint was solved+ SDoc -- Tells how it was solved+ -- Any new sub-goals have been put on the work list++instance Functor StopOrContinue where+ fmap f (ContinueWith x) = ContinueWith (f x)+ fmap _ (Stop ev s) = Stop ev s++instance Outputable a => Outputable (StopOrContinue a) where+ ppr (Stop ev s) = text "Stop" <> parens s <+> ppr ev+ ppr (ContinueWith w) = text "ContinueWith" <+> ppr w++continueWith :: a -> TcS (StopOrContinue a)+continueWith = return . ContinueWith++stopWith :: CtEvidence -> String -> TcS (StopOrContinue a)+stopWith ev s = return (Stop ev (text s))++andWhenContinue :: TcS (StopOrContinue a)+ -> (a -> TcS (StopOrContinue b))+ -> TcS (StopOrContinue b)+andWhenContinue tcs1 tcs2+ = do { r <- tcs1+ ; case r of+ Stop ev s -> return (Stop ev s)+ ContinueWith ct -> tcs2 ct }+infixr 0 `andWhenContinue` -- allow chaining with ($)++rewriteEvidence :: CtEvidence -- old evidence+ -> TcPredType -- new predicate+ -> TcCoercion -- Of type :: new predicate ~ <type of old evidence>+ -> TcS (StopOrContinue CtEvidence)+-- Returns Just new_ev iff either (i) 'co' is reflexivity+-- or (ii) 'co' is not reflexivity, and 'new_pred' not cached+-- In either case, there is nothing new to do with new_ev+{-+ rewriteEvidence old_ev new_pred co+Main purpose: create new evidence for new_pred;+ unless new_pred is cached already+* Returns a new_ev : new_pred, with same wanted/given/derived flag as old_ev+* If old_ev was wanted, create a binding for old_ev, in terms of new_ev+* If old_ev was given, AND not cached, create a binding for new_ev, in terms of old_ev+* Returns Nothing if new_ev is already cached++ Old evidence New predicate is Return new evidence+ flavour of same flavor+ -------------------------------------------------------------------+ Wanted Already solved or in inert Nothing+ or Derived Not Just new_evidence++ Given Already in inert Nothing+ Not Just new_evidence++Note [Rewriting with Refl]+~~~~~~~~~~~~~~~~~~~~~~~~~~+If the coercion is just reflexivity then you may re-use the same+variable. But be careful! Although the coercion is Refl, new_pred+may reflect the result of unification alpha := ty, so new_pred might+not _look_ the same as old_pred, and it's vital to proceed from now on+using new_pred.++qThe flattener preserves type synonyms, so they should appear in new_pred+as well as in old_pred; that is important for good error messages.+ -}+++rewriteEvidence old_ev@(CtDerived {}) new_pred _co+ = -- If derived, don't even look at the coercion.+ -- This is very important, DO NOT re-order the equations for+ -- rewriteEvidence to put the isTcReflCo test first!+ -- Why? Because for *Derived* constraints, c, the coercion, which+ -- was produced by flattening, may contain suspended calls to+ -- (ctEvTerm c), which fails for Derived constraints.+ -- (Getting this wrong caused Trac #7384.)+ continueWith (old_ev { ctev_pred = new_pred })++rewriteEvidence old_ev new_pred co+ | isTcReflCo co -- See Note [Rewriting with Refl]+ = continueWith (old_ev { ctev_pred = new_pred })++rewriteEvidence ev@(CtGiven { ctev_evar = old_evar , ctev_loc = loc }) new_pred co+ = do { new_ev <- newGivenEvVar loc (new_pred, new_tm)+ ; continueWith new_ev }+ where+ -- mkEvCast optimises ReflCo+ new_tm = mkEvCast (EvId old_evar) (tcDowngradeRole Representational+ (ctEvRole ev)+ (mkTcSymCo co))++rewriteEvidence ev@(CtWanted { ctev_dest = dest+ , ctev_loc = loc }) new_pred co+ = do { mb_new_ev <- newWanted loc new_pred+ ; MASSERT( tcCoercionRole co == ctEvRole ev )+ ; setWantedEvTerm dest+ (mkEvCast (getEvTerm mb_new_ev)+ (tcDowngradeRole Representational (ctEvRole ev) co))+ ; case mb_new_ev of+ Fresh new_ev -> continueWith new_ev+ Cached _ -> stopWith ev "Cached wanted" }+++rewriteEqEvidence :: CtEvidence -- Old evidence :: olhs ~ orhs (not swapped)+ -- or orhs ~ olhs (swapped)+ -> SwapFlag+ -> TcType -> TcType -- New predicate nlhs ~ nrhs+ -- Should be zonked, because we use typeKind on nlhs/nrhs+ -> TcCoercion -- lhs_co, of type :: nlhs ~ olhs+ -> TcCoercion -- rhs_co, of type :: nrhs ~ orhs+ -> TcS (StopOrContinue CtEvidence) -- Of type nlhs ~ nrhs+-- For (rewriteEqEvidence (Given g olhs orhs) False nlhs nrhs lhs_co rhs_co)+-- we generate+-- If not swapped+-- g1 : nlhs ~ nrhs = lhs_co ; g ; sym rhs_co+-- If 'swapped'+-- g1 : nlhs ~ nrhs = lhs_co ; Sym g ; sym rhs_co+--+-- For (Wanted w) we do the dual thing.+-- New w1 : nlhs ~ nrhs+-- If not swapped+-- w : olhs ~ orhs = sym lhs_co ; w1 ; rhs_co+-- If swapped+-- w : orhs ~ olhs = sym rhs_co ; sym w1 ; lhs_co+--+-- It's all a form of rewwriteEvidence, specialised for equalities+rewriteEqEvidence old_ev swapped nlhs nrhs lhs_co rhs_co+ | CtDerived {} <- old_ev -- Don't force the evidence for a Derived+ = continueWith (old_ev { ctev_pred = new_pred })++ | NotSwapped <- swapped+ , isTcReflCo lhs_co -- See Note [Rewriting with Refl]+ , isTcReflCo rhs_co+ = continueWith (old_ev { ctev_pred = new_pred })++ | CtGiven { ctev_evar = old_evar } <- old_ev+ = do { let new_tm = EvCoercion (lhs_co+ `mkTcTransCo` maybeSym swapped (mkTcCoVarCo old_evar)+ `mkTcTransCo` mkTcSymCo rhs_co)+ ; new_ev <- newGivenEvVar loc' (new_pred, new_tm)+ ; continueWith new_ev }++ | CtWanted { ctev_dest = dest } <- old_ev+ = do { (new_ev, hole_co) <- newWantedEq loc' (ctEvRole old_ev) nlhs nrhs+ ; let co = maybeSym swapped $+ mkSymCo lhs_co+ `mkTransCo` hole_co+ `mkTransCo` rhs_co+ ; setWantedEq dest co+ ; traceTcS "rewriteEqEvidence" (vcat [ppr old_ev, ppr nlhs, ppr nrhs, ppr co])+ ; continueWith new_ev }++ | otherwise+ = panic "rewriteEvidence"+ where+ new_pred = mkTcEqPredLikeEv old_ev nlhs nrhs++ -- equality is like a type class. Bumping the depth is necessary because+ -- of recursive newtypes, where "reducing" a newtype can actually make+ -- it bigger. See Note [Newtypes can blow the stack].+ loc = ctEvLoc old_ev+ loc' = bumpCtLocDepth loc++{- Note [unifyWanted and unifyDerived]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When decomposing equalities we often create new wanted constraints for+(s ~ t). But what if s=t? Then it'd be faster to return Refl right away.+Similar remarks apply for Derived.++Rather than making an equality test (which traverses the structure of the+type, perhaps fruitlessly, unifyWanted traverses the common structure, and+bales out when it finds a difference by creating a new Wanted constraint.+But where it succeeds in finding common structure, it just builds a coercion+to reflect it.+-}++unifyWanted :: CtLoc -> Role+ -> TcType -> TcType -> TcS Coercion+-- Return coercion witnessing the equality of the two types,+-- emitting new work equalities where necessary to achieve that+-- Very good short-cut when the two types are equal, or nearly so+-- See Note [unifyWanted and unifyDerived]+-- The returned coercion's role matches the input parameter+unifyWanted loc Phantom ty1 ty2+ = do { kind_co <- unifyWanted loc Nominal (typeKind ty1) (typeKind ty2)+ ; return (mkPhantomCo kind_co ty1 ty2) }++unifyWanted loc role orig_ty1 orig_ty2+ = go orig_ty1 orig_ty2+ where+ go ty1 ty2 | Just ty1' <- tcView ty1 = go ty1' ty2+ go ty1 ty2 | Just ty2' <- tcView ty2 = go ty1 ty2'++ go (FunTy s1 t1) (FunTy s2 t2)+ = do { co_s <- unifyWanted loc role s1 s2+ ; co_t <- unifyWanted loc role t1 t2+ ; return (mkFunCo role co_s co_t) }+ go (TyConApp tc1 tys1) (TyConApp tc2 tys2)+ | tc1 == tc2, tys1 `equalLength` tys2+ , isInjectiveTyCon tc1 role -- don't look under newtypes at Rep equality+ = do { cos <- zipWith3M (unifyWanted loc)+ (tyConRolesX role tc1) tys1 tys2+ ; return (mkTyConAppCo role tc1 cos) }++ go ty1@(TyVarTy tv) ty2+ = do { mb_ty <- isFilledMetaTyVar_maybe tv+ ; case mb_ty of+ Just ty1' -> go ty1' ty2+ Nothing -> bale_out ty1 ty2}+ go ty1 ty2@(TyVarTy tv)+ = do { mb_ty <- isFilledMetaTyVar_maybe tv+ ; case mb_ty of+ Just ty2' -> go ty1 ty2'+ Nothing -> bale_out ty1 ty2 }++ go ty1@(CoercionTy {}) (CoercionTy {})+ = return (mkReflCo role ty1) -- we just don't care about coercions!++ go ty1 ty2 = bale_out ty1 ty2++ bale_out ty1 ty2+ | ty1 `tcEqType` ty2 = return (mkTcReflCo role ty1)+ -- Check for equality; e.g. a ~ a, or (m a) ~ (m a)+ | otherwise = emitNewWantedEq loc role orig_ty1 orig_ty2++unifyDeriveds :: CtLoc -> [Role] -> [TcType] -> [TcType] -> TcS ()+-- See Note [unifyWanted and unifyDerived]+unifyDeriveds loc roles tys1 tys2 = zipWith3M_ (unify_derived loc) roles tys1 tys2++unifyDerived :: CtLoc -> Role -> Pair TcType -> TcS ()+-- See Note [unifyWanted and unifyDerived]+unifyDerived loc role (Pair ty1 ty2) = unify_derived loc role ty1 ty2++unify_derived :: CtLoc -> Role -> TcType -> TcType -> TcS ()+-- Create new Derived and put it in the work list+-- Should do nothing if the two types are equal+-- See Note [unifyWanted and unifyDerived]+unify_derived _ Phantom _ _ = return ()+unify_derived loc role orig_ty1 orig_ty2+ = go orig_ty1 orig_ty2+ where+ go ty1 ty2 | Just ty1' <- tcView ty1 = go ty1' ty2+ go ty1 ty2 | Just ty2' <- tcView ty2 = go ty1 ty2'++ go (FunTy s1 t1) (FunTy s2 t2)+ = do { unify_derived loc role s1 s2+ ; unify_derived loc role t1 t2 }+ go (TyConApp tc1 tys1) (TyConApp tc2 tys2)+ | tc1 == tc2, tys1 `equalLength` tys2+ , isInjectiveTyCon tc1 role+ = unifyDeriveds loc (tyConRolesX role tc1) tys1 tys2+ go ty1@(TyVarTy tv) ty2+ = do { mb_ty <- isFilledMetaTyVar_maybe tv+ ; case mb_ty of+ Just ty1' -> go ty1' ty2+ Nothing -> bale_out ty1 ty2 }+ go ty1 ty2@(TyVarTy tv)+ = do { mb_ty <- isFilledMetaTyVar_maybe tv+ ; case mb_ty of+ Just ty2' -> go ty1 ty2'+ Nothing -> bale_out ty1 ty2 }+ go ty1 ty2 = bale_out ty1 ty2++ bale_out ty1 ty2+ | ty1 `tcEqType` ty2 = return ()+ -- Check for equality; e.g. a ~ a, or (m a) ~ (m a)+ | otherwise = emitNewDerivedEq loc role orig_ty1 orig_ty2++maybeSym :: SwapFlag -> TcCoercion -> TcCoercion+maybeSym IsSwapped co = mkTcSymCo co+maybeSym NotSwapped co = co
+ typecheck/TcClassDcl.hs view
@@ -0,0 +1,524 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Typechecking class declarations+-}++{-# LANGUAGE CPP #-}++module TcClassDcl ( tcClassSigs, tcClassDecl2,+ findMethodBind, instantiateMethod,+ tcClassMinimalDef,+ HsSigFun, mkHsSigFun,+ tcMkDeclCtxt, tcAddDeclCtxt, badMethodErr,+ tcATDefault+ ) where++#include "HsVersions.h"++import HsSyn+import TcEnv+import TcSigs+import TcEvidence ( idHsWrapper )+import TcBinds+import TcUnify+import TcHsType+import TcMType+import Type ( getClassPredTys_maybe, piResultTys )+import TcType+import TcRnMonad+import DriverPhases (HscSource(..))+import BuildTyCl( TcMethInfo )+import Class+import Coercion ( pprCoAxiom )+import DynFlags+import FamInst+import FamInstEnv+import Id+import Name+import NameEnv+import NameSet+import Var+import VarEnv+import Outputable+import SrcLoc+import TyCon+import Maybes+import BasicTypes+import Bag+import FastString+import BooleanFormula+import Util++import Control.Monad+import Data.List ( mapAccumL, partition )++{-+Dictionary handling+~~~~~~~~~~~~~~~~~~~+Every class implicitly declares a new data type, corresponding to dictionaries+of that class. So, for example:++ class (D a) => C a where+ op1 :: a -> a+ op2 :: forall b. Ord b => a -> b -> b++would implicitly declare++ data CDict a = CDict (D a)+ (a -> a)+ (forall b. Ord b => a -> b -> b)++(We could use a record decl, but that means changing more of the existing apparatus.+One step at at time!)++For classes with just one superclass+method, we use a newtype decl instead:++ class C a where+ op :: forallb. a -> b -> b++generates++ newtype CDict a = CDict (forall b. a -> b -> b)++Now DictTy in Type is just a form of type synomym:+ DictTy c t = TyConTy CDict `AppTy` t++Death to "ExpandingDicts".+++************************************************************************+* *+ Type-checking the class op signatures+* *+************************************************************************+-}++illegalHsigDefaultMethod :: Name -> SDoc+illegalHsigDefaultMethod n =+ text "Illegal default method(s) in class definition of" <+> ppr n <+> text "in hsig file"++tcClassSigs :: Name -- Name of the class+ -> [LSig Name]+ -> LHsBinds Name+ -> TcM [TcMethInfo] -- Exactly one for each method+tcClassSigs clas sigs def_methods+ = do { traceTc "tcClassSigs 1" (ppr clas)++ ; gen_dm_prs <- concat <$> mapM (addLocM tc_gen_sig) gen_sigs+ ; let gen_dm_env :: NameEnv (SrcSpan, Type)+ gen_dm_env = mkNameEnv gen_dm_prs++ ; op_info <- concat <$> mapM (addLocM (tc_sig gen_dm_env)) vanilla_sigs++ ; let op_names = mkNameSet [ n | (n,_,_) <- op_info ]+ ; sequence_ [ failWithTc (badMethodErr clas n)+ | n <- dm_bind_names, not (n `elemNameSet` op_names) ]+ -- Value binding for non class-method (ie no TypeSig)++ ; tcg_env <- getGblEnv+ ; if tcg_src tcg_env == HsigFile+ then+ -- Error if we have value bindings+ -- (Generic signatures without value bindings indicate+ -- that a default of this form is expected to be+ -- provided.)+ when (not (null def_methods)) $+ failWithTc (illegalHsigDefaultMethod clas)+ else+ -- Error for each generic signature without value binding+ sequence_ [ failWithTc (badGenericMethod clas n)+ | (n,_) <- gen_dm_prs, not (n `elem` dm_bind_names) ]++ ; traceTc "tcClassSigs 2" (ppr clas)+ ; return op_info }+ where+ vanilla_sigs = [L loc (nm,ty) | L loc (ClassOpSig False nm ty) <- sigs]+ gen_sigs = [L loc (nm,ty) | L loc (ClassOpSig True nm ty) <- sigs]+ dm_bind_names :: [Name] -- These ones have a value binding in the class decl+ dm_bind_names = [op | L _ (FunBind {fun_id = L _ op}) <- bagToList def_methods]++ tc_sig :: NameEnv (SrcSpan, Type) -> ([Located Name], LHsSigType Name)+ -> TcM [TcMethInfo]+ tc_sig gen_dm_env (op_names, op_hs_ty)+ = do { traceTc "ClsSig 1" (ppr op_names)+ ; op_ty <- tcClassSigType op_names op_hs_ty -- Class tyvars already in scope+ ; traceTc "ClsSig 2" (ppr op_names)+ ; return [ (op_name, op_ty, f op_name) | L _ op_name <- op_names ] }+ where+ f nm | Just lty <- lookupNameEnv gen_dm_env nm = Just (GenericDM lty)+ | nm `elem` dm_bind_names = Just VanillaDM+ | otherwise = Nothing++ tc_gen_sig (op_names, gen_hs_ty)+ = do { gen_op_ty <- tcClassSigType op_names gen_hs_ty+ ; return [ (op_name, (loc, gen_op_ty)) | L loc op_name <- op_names ] }++{-+************************************************************************+* *+ Class Declarations+* *+************************************************************************+-}++tcClassDecl2 :: LTyClDecl Name -- The class declaration+ -> TcM (LHsBinds Id)++tcClassDecl2 (L _ (ClassDecl {tcdLName = class_name, tcdSigs = sigs,+ tcdMeths = default_binds}))+ = recoverM (return emptyLHsBinds) $+ setSrcSpan (getLoc class_name) $+ do { clas <- tcLookupLocatedClass class_name++ -- We make a separate binding for each default method.+ -- At one time I used a single AbsBinds for all of them, thus+ -- AbsBind [d] [dm1, dm2, dm3] { dm1 = ...; dm2 = ...; dm3 = ... }+ -- But that desugars into+ -- ds = \d -> (..., ..., ...)+ -- dm1 = \d -> case ds d of (a,b,c) -> a+ -- And since ds is big, it doesn't get inlined, so we don't get good+ -- default methods. Better to make separate AbsBinds for each+ ; let (tyvars, _, _, op_items) = classBigSig clas+ prag_fn = mkPragEnv sigs default_binds+ sig_fn = mkHsSigFun sigs+ clas_tyvars = snd (tcSuperSkolTyVars tyvars)+ pred = mkClassPred clas (mkTyVarTys clas_tyvars)+ ; this_dict <- newEvVar pred++ ; let tc_item = tcDefMeth clas clas_tyvars this_dict+ default_binds sig_fn prag_fn+ ; dm_binds <- tcExtendTyVarEnv clas_tyvars $+ mapM tc_item op_items++ ; return (unionManyBags dm_binds) }++tcClassDecl2 d = pprPanic "tcClassDecl2" (ppr d)++tcDefMeth :: Class -> [TyVar] -> EvVar -> LHsBinds Name+ -> HsSigFun -> TcPragEnv -> ClassOpItem+ -> TcM (LHsBinds TcId)+-- Generate code for default methods+-- This is incompatible with Hugs, which expects a polymorphic+-- default method for every class op, regardless of whether or not+-- the programmer supplied an explicit default decl for the class.+-- (If necessary we can fix that, but we don't have a convenient Id to hand.)++tcDefMeth _ _ _ _ _ prag_fn (sel_id, Nothing)+ = do { -- No default method+ mapM_ (addLocM (badDmPrag sel_id))+ (lookupPragEnv prag_fn (idName sel_id))+ ; return emptyBag }++tcDefMeth clas tyvars this_dict binds_in hs_sig_fn prag_fn+ (sel_id, Just (dm_name, dm_spec))+ | Just (L bind_loc dm_bind, bndr_loc, prags) <- findMethodBind sel_name binds_in prag_fn+ = do { -- First look up the default method; it should be there!+ -- It can be the orinary default method+ -- or the generic-default method. E.g of the latter+ -- class C a where+ -- op :: a -> a -> Bool+ -- default op :: Eq a => a -> a -> Bool+ -- op x y = x==y+ -- The default method we generate is+ -- $gm :: (C a, Eq a) => a -> a -> Bool+ -- $gm x y = x==y++ global_dm_id <- tcLookupId dm_name+ ; global_dm_id <- addInlinePrags global_dm_id prags+ ; local_dm_name <- newNameAt (getOccName sel_name) bndr_loc+ -- Base the local_dm_name on the selector name, because+ -- type errors from tcInstanceMethodBody come from here++ ; spec_prags <- discardConstraints $+ tcSpecPrags global_dm_id prags+ ; warnTc NoReason+ (not (null spec_prags))+ (text "Ignoring SPECIALISE pragmas on default method"+ <+> quotes (ppr sel_name))++ ; let hs_ty = hs_sig_fn sel_name+ `orElse` pprPanic "tc_dm" (ppr sel_name)+ -- We need the HsType so that we can bring the right+ -- type variables into scope+ --+ -- Eg. class C a where+ -- op :: forall b. Eq b => a -> [b] -> a+ -- gen_op :: a -> a+ -- generic gen_op :: D a => a -> a+ -- The "local_dm_ty" is precisely the type in the above+ -- type signatures, ie with no "forall a. C a =>" prefix++ local_dm_ty = instantiateMethod clas global_dm_id (mkTyVarTys tyvars)++ lm_bind = dm_bind { fun_id = L bind_loc local_dm_name }+ -- Substitute the local_meth_name for the binder+ -- NB: the binding is always a FunBind++ warn_redundant = case dm_spec of+ GenericDM {} -> True+ VanillaDM -> False+ -- For GenericDM, warn if the user specifies a signature+ -- with redundant constraints; but not for VanillaDM, where+ -- the default method may well be 'error' or something++ ctxt = FunSigCtxt sel_name warn_redundant++ ; let local_dm_id = mkLocalId local_dm_name local_dm_ty+ local_dm_sig = CompleteSig { sig_bndr = local_dm_id+ , sig_ctxt = ctxt+ , sig_loc = getLoc (hsSigType hs_ty) }++ ; (ev_binds, (tc_bind, _))+ <- checkConstraints (ClsSkol clas) tyvars [this_dict] $+ tcPolyCheck no_prag_fn local_dm_sig+ (L bind_loc lm_bind)++ ; let export = ABE { abe_poly = global_dm_id+ , abe_mono = local_dm_id+ , abe_wrap = idHsWrapper+ , abe_prags = IsDefaultMethod }+ full_bind = AbsBinds { abs_tvs = tyvars+ , abs_ev_vars = [this_dict]+ , abs_exports = [export]+ , abs_ev_binds = [ev_binds]+ , abs_binds = tc_bind }++ ; return (unitBag (L bind_loc full_bind)) }++ | otherwise = pprPanic "tcDefMeth" (ppr sel_id)+ where+ sel_name = idName sel_id+ no_prag_fn = emptyPragEnv -- No pragmas for local_meth_id;+ -- they are all for meth_id++---------------+tcClassMinimalDef :: Name -> [LSig Name] -> [TcMethInfo] -> TcM ClassMinimalDef+tcClassMinimalDef _clas sigs op_info+ = case findMinimalDef sigs of+ Nothing -> return defMindef+ Just mindef -> do+ -- Warn if the given mindef does not imply the default one+ -- That is, the given mindef should at least ensure that the+ -- class ops without default methods are required, since we+ -- have no way to fill them in otherwise+ tcg_env <- getGblEnv+ -- However, only do this test when it's not an hsig file,+ -- since you can't write a default implementation.+ when (tcg_src tcg_env /= HsigFile) $+ whenIsJust (isUnsatisfied (mindef `impliesAtom`) defMindef) $+ (\bf -> addWarnTc NoReason (warningMinimalDefIncomplete bf))+ return mindef+ where+ -- By default require all methods without a default implementation+ defMindef :: ClassMinimalDef+ defMindef = mkAnd [ noLoc (mkVar name)+ | (name, _, Nothing) <- op_info ]++instantiateMethod :: Class -> Id -> [TcType] -> TcType+-- Take a class operation, say+-- op :: forall ab. C a => forall c. Ix c => (b,c) -> a+-- Instantiate it at [ty1,ty2]+-- Return the "local method type":+-- forall c. Ix x => (ty2,c) -> ty1+instantiateMethod clas sel_id inst_tys+ = ASSERT( ok_first_pred ) local_meth_ty+ where+ rho_ty = piResultTys (idType sel_id) inst_tys+ (first_pred, local_meth_ty) = tcSplitPredFunTy_maybe rho_ty+ `orElse` pprPanic "tcInstanceMethod" (ppr sel_id)++ ok_first_pred = case getClassPredTys_maybe first_pred of+ Just (clas1, _tys) -> clas == clas1+ Nothing -> False+ -- The first predicate should be of form (C a b)+ -- where C is the class in question+++---------------------------+type HsSigFun = Name -> Maybe (LHsSigType Name)++mkHsSigFun :: [LSig Name] -> HsSigFun+mkHsSigFun sigs = lookupNameEnv env+ where+ env = mkHsSigEnv get_classop_sig sigs++ get_classop_sig :: LSig Name -> Maybe ([Located Name], LHsSigType Name)+ get_classop_sig (L _ (ClassOpSig _ ns hs_ty)) = Just (ns, hs_ty)+ get_classop_sig _ = Nothing++---------------------------+findMethodBind :: Name -- Selector+ -> LHsBinds Name -- A group of bindings+ -> TcPragEnv+ -> Maybe (LHsBind Name, SrcSpan, [LSig Name])+ -- Returns the binding, the binding+ -- site of the method binder, and any inline or+ -- specialisation pragmas+findMethodBind sel_name binds prag_fn+ = foldlBag mplus Nothing (mapBag f binds)+ where+ prags = lookupPragEnv prag_fn sel_name++ f bind@(L _ (FunBind { fun_id = L bndr_loc op_name }))+ | op_name == sel_name+ = Just (bind, bndr_loc, prags)+ f _other = Nothing++---------------------------+findMinimalDef :: [LSig Name] -> Maybe ClassMinimalDef+findMinimalDef = firstJusts . map toMinimalDef+ where+ toMinimalDef :: LSig Name -> Maybe ClassMinimalDef+ toMinimalDef (L _ (MinimalSig _ (L _ bf))) = Just (fmap unLoc bf)+ toMinimalDef _ = Nothing++{-+Note [Polymorphic methods]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ class Foo a where+ op :: forall b. Ord b => a -> b -> b -> b+ instance Foo c => Foo [c] where+ op = e++When typechecking the binding 'op = e', we'll have a meth_id for op+whose type is+ op :: forall c. Foo c => forall b. Ord b => [c] -> b -> b -> b++So tcPolyBinds must be capable of dealing with nested polytypes;+and so it is. See TcBinds.tcMonoBinds (with type-sig case).++Note [Silly default-method bind]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we pass the default method binding to the type checker, it must+look like op2 = e+not $dmop2 = e+otherwise the "$dm" stuff comes out error messages. But we want the+"$dm" to come out in the interface file. So we typecheck the former,+and wrap it in a let, thus+ $dmop2 = let op2 = e in op2+This makes the error messages right.+++************************************************************************+* *+ Error messages+* *+************************************************************************+-}++tcMkDeclCtxt :: TyClDecl Name -> SDoc+tcMkDeclCtxt decl = hsep [text "In the", pprTyClDeclFlavour decl,+ text "declaration for", quotes (ppr (tcdName decl))]++tcAddDeclCtxt :: TyClDecl Name -> TcM a -> TcM a+tcAddDeclCtxt decl thing_inside+ = addErrCtxt (tcMkDeclCtxt decl) thing_inside++badMethodErr :: Outputable a => a -> Name -> SDoc+badMethodErr clas op+ = hsep [text "Class", quotes (ppr clas),+ text "does not have a method", quotes (ppr op)]++badGenericMethod :: Outputable a => a -> Name -> SDoc+badGenericMethod clas op+ = hsep [text "Class", quotes (ppr clas),+ text "has a generic-default signature without a binding", quotes (ppr op)]++{-+badGenericInstanceType :: LHsBinds Name -> SDoc+badGenericInstanceType binds+ = vcat [text "Illegal type pattern in the generic bindings",+ nest 2 (ppr binds)]++missingGenericInstances :: [Name] -> SDoc+missingGenericInstances missing+ = text "Missing type patterns for" <+> pprQuotedList missing++dupGenericInsts :: [(TyCon, InstInfo a)] -> SDoc+dupGenericInsts tc_inst_infos+ = vcat [text "More than one type pattern for a single generic type constructor:",+ nest 2 (vcat (map ppr_inst_ty tc_inst_infos)),+ text "All the type patterns for a generic type constructor must be identical"+ ]+ where+ ppr_inst_ty (_,inst) = ppr (simpleInstInfoTy inst)+-}+badDmPrag :: Id -> Sig Name -> TcM ()+badDmPrag sel_id prag+ = addErrTc (text "The" <+> hsSigDoc prag <+> ptext (sLit "for default method")+ <+> quotes (ppr sel_id)+ <+> text "lacks an accompanying binding")++warningMinimalDefIncomplete :: ClassMinimalDef -> SDoc+warningMinimalDefIncomplete mindef+ = vcat [ text "The MINIMAL pragma does not require:"+ , nest 2 (pprBooleanFormulaNice mindef)+ , text "but there is no default implementation." ]++tcATDefault :: Bool -- If a warning should be emitted when a default instance+ -- definition is not provided by the user+ -> SrcSpan+ -> TCvSubst+ -> NameSet+ -> ClassATItem+ -> TcM [FamInst]+-- ^ Construct default instances for any associated types that+-- aren't given a user definition+-- Returns [] or singleton+tcATDefault emit_warn loc inst_subst defined_ats (ATI fam_tc defs)+ -- User supplied instances ==> everything is OK+ | tyConName fam_tc `elemNameSet` defined_ats+ = return []++ -- No user instance, have defaults ==> instantiate them+ -- Example: class C a where { type F a b :: *; type F a b = () }+ -- instance C [x]+ -- Then we want to generate the decl: type F [x] b = ()+ | Just (rhs_ty, _loc) <- defs+ = do { let (subst', pat_tys') = mapAccumL subst_tv inst_subst+ (tyConTyVars fam_tc)+ rhs' = substTyUnchecked subst' rhs_ty+ tcv' = tyCoVarsOfTypesList pat_tys'+ (tv', cv') = partition isTyVar tcv'+ tvs' = toposortTyVars tv'+ cvs' = toposortTyVars cv'+ ; rep_tc_name <- newFamInstTyConName (L loc (tyConName fam_tc)) pat_tys'+ ; let axiom = mkSingleCoAxiom Nominal rep_tc_name tvs' cvs'+ fam_tc pat_tys' rhs'+ -- NB: no validity check. We check validity of default instances+ -- in the class definition. Because type instance arguments cannot+ -- be type family applications and cannot be polytypes, the+ -- validity check is redundant.++ ; traceTc "mk_deflt_at_instance" (vcat [ ppr fam_tc, ppr rhs_ty+ , pprCoAxiom axiom ])+ ; fam_inst <- newFamInst SynFamilyInst axiom+ ; return [fam_inst] }++ -- No defaults ==> generate a warning+ | otherwise -- defs = Nothing+ = do { when emit_warn $ warnMissingAT (tyConName fam_tc)+ ; return [] }+ where+ subst_tv subst tc_tv+ | Just ty <- lookupVarEnv (getTvSubstEnv subst) tc_tv+ = (subst, ty)+ | otherwise+ = (extendTvSubst subst tc_tv ty', ty')+ where+ ty' = mkTyVarTy (updateTyVarKind (substTyUnchecked subst) tc_tv)++warnMissingAT :: Name -> TcM ()+warnMissingAT name+ = do { warn <- woptM Opt_WarnMissingMethods+ ; traceTc "warn" (ppr name <+> ppr warn)+ ; hsc_src <- fmap tcg_src getGblEnv+ -- Warn only if -Wmissing-methods AND not a signature+ ; warnTc (Reason Opt_WarnMissingMethods) (warn && hsc_src /= HsigFile)+ (text "No explicit" <+> text "associated type"+ <+> text "or default declaration for "+ <+> quotes (ppr name)) }
+ typecheck/TcDefaults.hs view
@@ -0,0 +1,104 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1993-1998++\section[TcDefaults]{Typechecking \tr{default} declarations}+-}++module TcDefaults ( tcDefaults ) where++import HsSyn+import Name+import Class+import TcRnMonad+import TcEnv+import TcHsType+import TcHsSyn+import TcSimplify+import TcValidity+import TcType+import PrelNames+import SrcLoc+import Outputable+import FastString+import qualified GHC.LanguageExtensions as LangExt++tcDefaults :: [LDefaultDecl Name]+ -> TcM (Maybe [Type]) -- Defaulting types to heave+ -- into Tc monad for later use+ -- in Disambig.++tcDefaults []+ = getDeclaredDefaultTys -- No default declaration, so get the+ -- default types from the envt;+ -- i.e. use the current ones+ -- (the caller will put them back there)+ -- It's important not to return defaultDefaultTys here (which+ -- we used to do) because in a TH program, tcDefaults [] is called+ -- repeatedly, once for each group of declarations between top-level+ -- splices. We don't want to carefully set the default types in+ -- one group, only for the next group to ignore them and install+ -- defaultDefaultTys++tcDefaults [L _ (DefaultDecl [])]+ = return (Just []) -- Default declaration specifying no types++tcDefaults [L locn (DefaultDecl mono_tys)]+ = setSrcSpan locn $+ addErrCtxt defaultDeclCtxt $+ do { ovl_str <- xoptM LangExt.OverloadedStrings+ ; ext_deflt <- xoptM LangExt.ExtendedDefaultRules+ ; num_class <- tcLookupClass numClassName+ ; deflt_str <- if ovl_str+ then mapM tcLookupClass [isStringClassName]+ else return []+ ; deflt_interactive <- if ext_deflt+ then mapM tcLookupClass interactiveClassNames+ else return []+ ; let deflt_clss = num_class : deflt_str ++ deflt_interactive++ ; tau_tys <- mapAndReportM (tc_default_ty deflt_clss) mono_tys++ ; return (Just tau_tys) }++tcDefaults decls@(L locn (DefaultDecl _) : _)+ = setSrcSpan locn $+ failWithTc (dupDefaultDeclErr decls)+++tc_default_ty :: [Class] -> LHsType Name -> TcM Type+tc_default_ty deflt_clss hs_ty+ = do { (ty, _kind) <- solveEqualities $+ tcLHsType hs_ty+ ; ty <- zonkTcTypeToType emptyZonkEnv ty -- establish Type invariants+ ; checkValidType DefaultDeclCtxt ty++ -- Check that the type is an instance of at least one of the deflt_clss+ ; oks <- mapM (check_instance ty) deflt_clss+ ; checkTc (or oks) (badDefaultTy ty deflt_clss)+ ; return ty }++check_instance :: Type -> Class -> TcM Bool+ -- Check that ty is an instance of cls+ -- We only care about whether it worked or not; return a boolean+check_instance ty cls+ = do { (_, success) <- discardErrs $+ askNoErrs $+ simplifyDefault [mkClassPred cls [ty]]+ ; return success }++defaultDeclCtxt :: SDoc+defaultDeclCtxt = text "When checking the types in a default declaration"++dupDefaultDeclErr :: [Located (DefaultDecl Name)] -> SDoc+dupDefaultDeclErr (L _ (DefaultDecl _) : dup_things)+ = hang (text "Multiple default declarations")+ 2 (vcat (map pp dup_things))+ where+ pp (L locn (DefaultDecl _)) = text "here was another default declaration" <+> ppr locn+dupDefaultDeclErr [] = panic "dupDefaultDeclErr []"++badDefaultTy :: Type -> [Class] -> SDoc+badDefaultTy ty deflt_clss+ = hang (text "The default type" <+> quotes (ppr ty) <+> ptext (sLit "is not an instance of"))+ 2 (foldr1 (\a b -> a <+> text "or" <+> b) (map (quotes. ppr) deflt_clss))
+ typecheck/TcDeriv.hs view
@@ -0,0 +1,1843 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Handles @deriving@ clauses on @data@ declarations.+-}++{-# LANGUAGE CPP #-}++module TcDeriv ( tcDeriving, DerivInfo(..), mkDerivInfos ) where++#include "HsVersions.h"++import HsSyn+import DynFlags++import TcRnMonad+import FamInst+import TcDerivInfer+import TcDerivUtils+import TcValidity( allDistinctTyVars )+import TcClassDcl( tcATDefault, tcMkDeclCtxt )+import TcEnv+import TcGenDeriv -- Deriv stuff+import InstEnv+import Inst+import FamInstEnv+import TcHsType+import TcMType++import RnNames( extendGlobalRdrEnvRn )+import RnBinds+import RnEnv+import RnSource ( addTcgDUs )+import Avail++import Unify( tcUnifyTy )+import BasicTypes ( DerivStrategy(..) )+import Class+import Type+import ErrUtils+import DataCon+import Maybes+import RdrName+import Name+import NameSet+import TyCon+import TcType+import Var+import VarEnv+import VarSet+import PrelNames+import SrcLoc+import Util+import Outputable+import FastString+import Bag+import Pair+import FV (fvVarList, unionFV, mkFVs)+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.List++{-+************************************************************************+* *+ Overview+* *+************************************************************************++Overall plan+~~~~~~~~~~~~+1. Convert the decls (i.e. data/newtype deriving clauses,+ plus standalone deriving) to [EarlyDerivSpec]++2. Infer the missing contexts for the InferTheta's++3. Add the derived bindings, generating InstInfos+-}++data EarlyDerivSpec = InferTheta (DerivSpec [ThetaOrigin])+ | GivenTheta (DerivSpec ThetaType)+ -- InferTheta ds => the context for the instance should be inferred+ -- In this case ds_theta is the list of all the sets of+ -- constraints needed, such as (Eq [a], Eq a), together with a+ -- suitable CtLoc to get good error messages.+ -- The inference process is to reduce this to a+ -- simpler form (e.g. Eq a)+ --+ -- GivenTheta ds => the exact context for the instance is supplied+ -- by the programmer; it is ds_theta+ -- See Note [Inferring the instance context] in TcDerivInfer++earlyDSLoc :: EarlyDerivSpec -> SrcSpan+earlyDSLoc (InferTheta spec) = ds_loc spec+earlyDSLoc (GivenTheta spec) = ds_loc spec++splitEarlyDerivSpec :: [EarlyDerivSpec]+ -> ([DerivSpec [ThetaOrigin]], [DerivSpec ThetaType])+splitEarlyDerivSpec [] = ([],[])+splitEarlyDerivSpec (InferTheta spec : specs) =+ case splitEarlyDerivSpec specs of (is, gs) -> (spec : is, gs)+splitEarlyDerivSpec (GivenTheta spec : specs) =+ case splitEarlyDerivSpec specs of (is, gs) -> (is, spec : gs)++instance Outputable EarlyDerivSpec where+ ppr (InferTheta spec) = ppr spec <+> text "(Infer)"+ ppr (GivenTheta spec) = ppr spec <+> text "(Given)"++{-+Note [Data decl contexts]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ data (RealFloat a) => Complex a = !a :+ !a deriving( Read )++We will need an instance decl like:++ instance (Read a, RealFloat a) => Read (Complex a) where+ ...++The RealFloat in the context is because the read method for Complex is bound+to construct a Complex, and doing that requires that the argument type is+in RealFloat.++But this ain't true for Show, Eq, Ord, etc, since they don't construct+a Complex; they only take them apart.++Our approach: identify the offending classes, and add the data type+context to the instance decl. The "offending classes" are++ Read, Enum?++FURTHER NOTE ADDED March 2002. In fact, Haskell98 now requires that+pattern matching against a constructor from a data type with a context+gives rise to the constraints for that context -- or at least the thinned+version. So now all classes are "offending".++Note [Newtype deriving]+~~~~~~~~~~~~~~~~~~~~~~~+Consider this:+ class C a b+ instance C [a] Char+ newtype T = T Char deriving( C [a] )++Notice the free 'a' in the deriving. We have to fill this out to+ newtype T = T Char deriving( forall a. C [a] )++And then translate it to:+ instance C [a] Char => C [a] T where ...+++Note [Newtype deriving superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(See also Trac #1220 for an interesting exchange on newtype+deriving and superclasses.)++The 'tys' here come from the partial application in the deriving+clause. The last arg is the new instance type.++We must pass the superclasses; the newtype might be an instance+of them in a different way than the representation type+E.g. newtype Foo a = Foo a deriving( Show, Num, Eq )+Then the Show instance is not done via Coercible; it shows+ Foo 3 as "Foo 3"+The Num instance is derived via Coercible, but the Show superclass+dictionary must the Show instance for Foo, *not* the Show dictionary+gotten from the Num dictionary. So we must build a whole new dictionary+not just use the Num one. The instance we want is something like:+ instance (Num a, Show (Foo a), Eq (Foo a)) => Num (Foo a) where+ (+) = ((+)@a)+ ...etc...+There may be a coercion needed which we get from the tycon for the newtype+when the dict is constructed in TcInstDcls.tcInstDecl2+++Note [Unused constructors and deriving clauses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See Trac #3221. Consider+ data T = T1 | T2 deriving( Show )+Are T1 and T2 unused? Well, no: the deriving clause expands to mention+both of them. So we gather defs/uses from deriving just like anything else.++-}++-- | Stuff needed to process a datatype's `deriving` clauses+data DerivInfo = DerivInfo { di_rep_tc :: TyCon+ -- ^ The data tycon for normal datatypes,+ -- or the *representation* tycon for data families+ , di_clauses :: [LHsDerivingClause Name]+ , di_ctxt :: SDoc -- ^ error context+ }++-- | Extract `deriving` clauses of proper data type (skips data families)+mkDerivInfos :: [LTyClDecl Name] -> TcM [DerivInfo]+mkDerivInfos decls = concatMapM (mk_deriv . unLoc) decls+ where++ mk_deriv decl@(DataDecl { tcdLName = L _ data_name+ , tcdDataDefn =+ HsDataDefn { dd_derivs = L _ clauses } })+ = do { tycon <- tcLookupTyCon data_name+ ; return [DerivInfo { di_rep_tc = tycon, di_clauses = clauses+ , di_ctxt = tcMkDeclCtxt decl }] }+ mk_deriv _ = return []++{-++************************************************************************+* *+\subsection[TcDeriv-driver]{Top-level function for \tr{derivings}}+* *+************************************************************************+-}++tcDeriving :: [DerivInfo] -- All `deriving` clauses+ -> [LDerivDecl Name] -- All stand-alone deriving declarations+ -> TcM (TcGblEnv, Bag (InstInfo Name), HsValBinds Name)+tcDeriving deriv_infos deriv_decls+ = recoverM (do { g <- getGblEnv+ ; return (g, emptyBag, emptyValBindsOut)}) $+ do { -- Fish the "deriving"-related information out of the TcEnv+ -- And make the necessary "equations".+ is_boot <- tcIsHsBootOrSig+ ; traceTc "tcDeriving" (ppr is_boot)++ ; early_specs <- makeDerivSpecs is_boot deriv_infos deriv_decls+ ; traceTc "tcDeriving 1" (ppr early_specs)++ ; let (infer_specs, given_specs) = splitEarlyDerivSpec early_specs+ ; insts1 <- mapM genInst given_specs+ ; insts2 <- mapM genInst infer_specs++ ; dflags <- getDynFlags++ ; let (_, deriv_stuff, maybe_fvs) = unzip3 (insts1 ++ insts2)+ ; loc <- getSrcSpanM+ ; let (binds, famInsts) = genAuxBinds dflags loc+ (unionManyBags deriv_stuff)++ ; let mk_inst_infos1 = map fstOf3 insts1+ ; inst_infos1 <- apply_inst_infos mk_inst_infos1 given_specs++ -- We must put all the derived type family instances (from both+ -- infer_specs and given_specs) in the local instance environment+ -- before proceeding, or else simplifyInstanceContexts might+ -- get stuck if it has to reason about any of those family instances.+ -- See Note [Staging of tcDeriving]+ ; tcExtendLocalFamInstEnv (bagToList famInsts) $+ -- NB: only call tcExtendLocalFamInstEnv once, as it performs+ -- validity checking for all of the family instances you give it.+ -- If the family instances have errors, calling it twice will result+ -- in duplicate error messages!++ do {+ -- the stand-alone derived instances (@inst_infos1@) are used when+ -- inferring the contexts for "deriving" clauses' instances+ -- (@infer_specs@)+ ; final_specs <- extendLocalInstEnv (map iSpec inst_infos1) $+ simplifyInstanceContexts infer_specs++ ; let mk_inst_infos2 = map fstOf3 insts2+ ; inst_infos2 <- apply_inst_infos mk_inst_infos2 final_specs+ ; let inst_infos = inst_infos1 ++ inst_infos2++ ; (inst_info, rn_binds, rn_dus) <-+ renameDeriv is_boot inst_infos binds++ ; unless (isEmptyBag inst_info) $+ liftIO (dumpIfSet_dyn dflags Opt_D_dump_deriv "Derived instances"+ (ddump_deriving inst_info rn_binds famInsts))++ ; gbl_env <- tcExtendLocalInstEnv (map iSpec (bagToList inst_info))+ getGblEnv+ ; let all_dus = rn_dus `plusDU` usesOnly (NameSet.mkFVs $ catMaybes maybe_fvs)+ ; return (addTcgDUs gbl_env all_dus, inst_info, rn_binds) } }+ where+ ddump_deriving :: Bag (InstInfo Name) -> HsValBinds Name+ -> Bag FamInst -- ^ Rep type family instances+ -> SDoc+ ddump_deriving inst_infos extra_binds repFamInsts+ = hang (text "Derived class instances:")+ 2 (vcat (map (\i -> pprInstInfoDetails i $$ text "") (bagToList inst_infos))+ $$ ppr extra_binds)+ $$ hangP "Derived type family instances:"+ (vcat (map pprRepTy (bagToList repFamInsts)))++ hangP s x = text "" $$ hang (ptext (sLit s)) 2 x++ -- Apply the suspended computations given by genInst calls.+ -- See Note [Staging of tcDeriving]+ apply_inst_infos :: [ThetaType -> TcM (InstInfo RdrName)]+ -> [DerivSpec ThetaType] -> TcM [InstInfo RdrName]+ apply_inst_infos = zipWithM (\f ds -> f (ds_theta ds))++-- Prints the representable type family instance+pprRepTy :: FamInst -> SDoc+pprRepTy fi@(FamInst { fi_tys = lhs })+ = text "type" <+> ppr (mkTyConApp (famInstTyCon fi) lhs) <+>+ equals <+> ppr rhs+ where rhs = famInstRHS fi++renameDeriv :: Bool+ -> [InstInfo RdrName]+ -> Bag (LHsBind RdrName, LSig RdrName)+ -> TcM (Bag (InstInfo Name), HsValBinds Name, DefUses)+renameDeriv is_boot inst_infos bagBinds+ | is_boot -- If we are compiling a hs-boot file, don't generate any derived bindings+ -- The inst-info bindings will all be empty, but it's easier to+ -- just use rn_inst_info to change the type appropriately+ = do { (rn_inst_infos, fvs) <- mapAndUnzipM rn_inst_info inst_infos+ ; return ( listToBag rn_inst_infos+ , emptyValBindsOut, usesOnly (plusFVs fvs)) }++ | otherwise+ = discardWarnings $+ -- Discard warnings about unused bindings etc+ setXOptM LangExt.EmptyCase $+ -- Derived decls (for empty types) can have+ -- case x of {}+ setXOptM LangExt.ScopedTypeVariables $+ setXOptM LangExt.KindSignatures $+ -- Derived decls (for newtype-deriving) can use ScopedTypeVariables &+ -- KindSignatures+ unsetXOptM LangExt.RebindableSyntax $+ -- See Note [Avoid RebindableSyntax when deriving]+ do {+ -- Bring the extra deriving stuff into scope+ -- before renaming the instances themselves+ ; traceTc "rnd" (vcat (map (\i -> pprInstInfoDetails i $$ text "") inst_infos))+ ; (aux_binds, aux_sigs) <- mapAndUnzipBagM return bagBinds+ ; let aux_val_binds = ValBindsIn aux_binds (bagToList aux_sigs)+ ; rn_aux_lhs <- rnTopBindsLHS emptyFsEnv aux_val_binds+ ; let bndrs = collectHsValBinders rn_aux_lhs+ ; envs <- extendGlobalRdrEnvRn (map avail bndrs) emptyFsEnv ;+ ; setEnvs envs $+ do { (rn_aux, dus_aux) <- rnValBindsRHS (TopSigCtxt (mkNameSet bndrs)) rn_aux_lhs+ ; (rn_inst_infos, fvs_insts) <- mapAndUnzipM rn_inst_info inst_infos+ ; return (listToBag rn_inst_infos, rn_aux,+ dus_aux `plusDU` usesOnly (plusFVs fvs_insts)) } }++ where+ rn_inst_info :: InstInfo RdrName -> TcM (InstInfo Name, FreeVars)+ rn_inst_info+ inst_info@(InstInfo { iSpec = inst+ , iBinds = InstBindings+ { ib_binds = binds+ , ib_tyvars = tyvars+ , ib_pragmas = sigs+ , ib_extensions = exts -- Only for type-checking+ , ib_derived = sa } })+ = ASSERT( null sigs )+ bindLocalNamesFV tyvars $+ do { (rn_binds,_, fvs) <- rnMethodBinds False (is_cls_nm inst) [] binds []+ ; let binds' = InstBindings { ib_binds = rn_binds+ , ib_tyvars = tyvars+ , ib_pragmas = []+ , ib_extensions = exts+ , ib_derived = sa }+ ; return (inst_info { iBinds = binds' }, fvs) }++{-+Note [Newtype deriving and unused constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this (see Trac #1954):++ module Bug(P) where+ newtype P a = MkP (IO a) deriving Monad++If you compile with -Wunused-binds you do not expect the warning+"Defined but not used: data constructor MkP". Yet the newtype deriving+code does not explicitly mention MkP, but it should behave as if you+had written+ instance Monad P where+ return x = MkP (return x)+ ...etc...++So we want to signal a user of the data constructor 'MkP'.+This is the reason behind the (Maybe Name) part of the return type+of genInst.++Note [Staging of tcDeriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here's a tricky corner case for deriving (adapted from Trac #2721):++ class C a where+ type T a+ foo :: a -> T a++ instance C Int where+ type T Int = Int+ foo = id++ newtype N = N Int deriving C++This will produce an instance something like this:++ instance C N where+ type T N = T Int+ foo = coerce (foo :: Int -> T Int) :: N -> T N++We must be careful in order to typecheck this code. When determining the+context for the instance (in simplifyInstanceContexts), we need to determine+that T N and T Int have the same representation, but to do that, the T N+instance must be in the local family instance environment. Otherwise, GHC+would be unable to conclude that T Int is representationally equivalent to+T Int, and simplifyInstanceContexts would get stuck.++Previously, tcDeriving would defer adding any derived type family instances to+the instance environment until the very end, which meant that+simplifyInstanceContexts would get called without all the type family instances+it needed in the environment in order to properly simplify instance like+the C N instance above.++To avoid this scenario, we carefully structure the order of events in+tcDeriving. We first call genInst on the standalone derived instance specs and+the instance specs obtained from deriving clauses. Note that the return type of+genInst is a triple:++ TcM (ThetaType -> TcM (InstInfo RdrName), BagDerivStuff, Maybe Name)++The type family instances are in the BagDerivStuff. The first field of the+triple is a suspended computation which, given an instance context, produces+the rest of the instance. The fact that it is suspended is important, because+right now, we don't have ThetaTypes for the instances that use deriving clauses+(only the standalone-derived ones).++Now we can can collect the type family instances and extend the local instance+environment. At this point, it is safe to run simplifyInstanceContexts on the+deriving-clause instance specs, which gives us the ThetaTypes for the+deriving-clause instances. Now we can feed all the ThetaTypes to the+suspended computations and obtain our InstInfos, at which point+tcDeriving is done.++An alternative design would be to split up genInst so that the+family instances are generated separately from the InstInfos. But this would+require carving up a lot of the GHC deriving internals to accommodate the+change. On the other hand, we can keep all of the InstInfo and type family+instance logic together in genInst simply by converting genInst to+continuation-returning style, so we opt for that route.++Note [Why we don't pass rep_tc into deriveTyData]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Down in the bowels of mkEqnHelp, we need to convert the fam_tc back into+the rep_tc by means of a lookup. And yet we have the rep_tc right here!+Why look it up again? Answer: it's just easier this way.+We drop some number of arguments from the end of the datatype definition+in deriveTyData. The arguments are dropped from the fam_tc.+This action may drop a *different* number of arguments+passed to the rep_tc, depending on how many free variables, etc., the+dropped patterns have.++Also, this technique carries over the kind substitution from deriveTyData+nicely.++Note [Avoid RebindableSyntax when deriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The RebindableSyntax extension interacts awkwardly with the derivation of+any stock class whose methods require the use of string literals. The Show+class is a simple example (see Trac #12688):++ {-# LANGUAGE RebindableSyntax, OverloadedStrings #-}+ newtype Text = Text String+ fromString :: String -> Text+ fromString = Text++ data Foo = Foo deriving Show++This will generate code to the effect of:++ instance Show Foo where+ showsPrec _ Foo = showString "Foo"++But because RebindableSyntax and OverloadedStrings are enabled, the "Foo"+string literal is now of type Text, not String, which showString doesn't+accept! This causes the generated Show instance to fail to typecheck.++To avoid this kind of scenario, we simply turn off RebindableSyntax entirely+in derived code.++************************************************************************+* *+ From HsSyn to DerivSpec+* *+************************************************************************++@makeDerivSpecs@ fishes around to find the info about needed derived instances.+-}++makeDerivSpecs :: Bool+ -> [DerivInfo]+ -> [LDerivDecl Name]+ -> TcM [EarlyDerivSpec]+makeDerivSpecs is_boot deriv_infos deriv_decls+ = do { eqns1 <- concatMapM (recoverM (return []) . deriveDerivInfo) deriv_infos+ ; eqns2 <- concatMapM (recoverM (return []) . deriveStandalone) deriv_decls+ ; let eqns = eqns1 ++ eqns2++ ; if is_boot then -- No 'deriving' at all in hs-boot files+ do { unless (null eqns) (add_deriv_err (head eqns))+ ; return [] }+ else return eqns }+ where+ add_deriv_err eqn+ = setSrcSpan (earlyDSLoc eqn) $+ addErr (hang (text "Deriving not permitted in hs-boot file")+ 2 (text "Use an instance declaration instead"))++------------------------------------------------------------------+-- | Process a `deriving` clause+deriveDerivInfo :: DerivInfo -> TcM [EarlyDerivSpec]+deriveDerivInfo (DerivInfo { di_rep_tc = rep_tc, di_clauses = clauses+ , di_ctxt = err_ctxt })+ = addErrCtxt err_ctxt $+ concatMapM (deriveForClause . unLoc) clauses+ where+ tvs = tyConTyVars rep_tc+ (tc, tys) = case tyConFamInstSig_maybe rep_tc of+ -- data family:+ Just (fam_tc, pats, _) -> (fam_tc, pats)+ -- NB: deriveTyData wants the *user-specified*+ -- name. See Note [Why we don't pass rep_tc into deriveTyData]++ _ -> (rep_tc, mkTyVarTys tvs) -- datatype++ deriveForClause :: HsDerivingClause Name -> TcM [EarlyDerivSpec]+ deriveForClause (HsDerivingClause { deriv_clause_strategy = dcs+ , deriv_clause_tys = L _ preds })+ = concatMapM (deriveTyData tvs tc tys (fmap unLoc dcs)) preds++------------------------------------------------------------------+deriveStandalone :: LDerivDecl Name -> TcM [EarlyDerivSpec]+-- Standalone deriving declarations+-- e.g. deriving instance Show a => Show (T a)+-- Rather like tcLocalInstDecl+deriveStandalone (L loc (DerivDecl deriv_ty deriv_strat' overlap_mode))+ = setSrcSpan loc $+ addErrCtxt (standaloneCtxt deriv_ty) $+ do { traceTc "Standalone deriving decl for" (ppr deriv_ty)+ ; let deriv_strat = fmap unLoc deriv_strat'+ ; traceTc "Deriving strategy (standalone deriving)" $+ vcat [ppr deriv_strat, ppr deriv_ty]+ ; (tvs, theta, cls, inst_tys) <- tcHsClsInstType TcType.InstDeclCtxt deriv_ty+ ; traceTc "Standalone deriving;" $ vcat+ [ text "tvs:" <+> ppr tvs+ , text "theta:" <+> ppr theta+ , text "cls:" <+> ppr cls+ , text "tys:" <+> ppr inst_tys ]+ -- C.f. TcInstDcls.tcLocalInstDecl1+ ; checkTc (not (null inst_tys)) derivingNullaryErr++ ; let cls_tys = take (length inst_tys - 1) inst_tys+ inst_ty = last inst_tys+ ; traceTc "Standalone deriving:" $ vcat+ [ text "class:" <+> ppr cls+ , text "class types:" <+> ppr cls_tys+ , text "type:" <+> ppr inst_ty ]++ ; let bale_out msg = failWithTc (derivingThingErr False cls cls_tys+ inst_ty deriv_strat msg)++ ; case tcSplitTyConApp_maybe inst_ty of+ Just (tc, tc_args)+ | className cls == typeableClassName+ -> do warnUselessTypeable+ return []++ | isUnboxedTupleTyCon tc+ -> bale_out $ unboxedTyConErr "tuple"++ | isUnboxedSumTyCon tc+ -> bale_out $ unboxedTyConErr "sum"++ | isAlgTyCon tc || isDataFamilyTyCon tc -- All other classes+ -> do { spec <- mkEqnHelp (fmap unLoc overlap_mode)+ tvs cls cls_tys tc tc_args+ (Just theta) deriv_strat+ ; return [spec] }++ _ -> -- Complain about functions, primitive types, etc,+ bale_out $+ text "The last argument of the instance must be a data or newtype application"+ }++warnUselessTypeable :: TcM ()+warnUselessTypeable+ = do { warn <- woptM Opt_WarnDerivingTypeable+ ; when warn $ addWarnTc (Reason Opt_WarnDerivingTypeable)+ $ text "Deriving" <+> quotes (ppr typeableClassName) <+>+ text "has no effect: all types now auto-derive Typeable" }++------------------------------------------------------------------+deriveTyData :: [TyVar] -> TyCon -> [Type] -- LHS of data or data instance+ -- Can be a data instance, hence [Type] args+ -> Maybe DerivStrategy -- The optional deriving strategy+ -> LHsSigType Name -- The deriving predicate+ -> TcM [EarlyDerivSpec]+-- The deriving clause of a data or newtype declaration+-- I.e. not standalone deriving+deriveTyData tvs tc tc_args deriv_strat deriv_pred+ = setSrcSpan (getLoc (hsSigType deriv_pred)) $ -- Use loc of the 'deriving' item+ do { (deriv_tvs, cls, cls_tys, cls_arg_kinds)+ <- tcExtendTyVarEnv tvs $+ tcHsDeriv deriv_pred+ -- Deriving preds may (now) mention+ -- the type variables for the type constructor, hence tcExtendTyVarenv+ -- The "deriv_pred" is a LHsType to take account of the fact that for+ -- newtype deriving we allow deriving (forall a. C [a]).++ -- Typeable is special, because Typeable :: forall k. k -> Constraint+ -- so the argument kind 'k' is not decomposable by splitKindFunTys+ -- as is the case for all other derivable type classes+ ; when (length cls_arg_kinds /= 1) $+ failWithTc (nonUnaryErr deriv_pred)+ ; let [cls_arg_kind] = cls_arg_kinds+ ; if className cls == typeableClassName+ then do warnUselessTypeable+ return []+ else++ do { -- Given data T a b c = ... deriving( C d ),+ -- we want to drop type variables from T so that (C d (T a)) is well-kinded+ let (arg_kinds, _) = splitFunTys cls_arg_kind+ n_args_to_drop = length arg_kinds+ n_args_to_keep = tyConArity tc - n_args_to_drop+ (tc_args_to_keep, args_to_drop)+ = splitAt n_args_to_keep tc_args+ inst_ty_kind = typeKind (mkTyConApp tc tc_args_to_keep)++ -- Match up the kinds, and apply the resulting kind substitution+ -- to the types. See Note [Unify kinds in deriving]+ -- We are assuming the tycon tyvars and the class tyvars are distinct+ mb_match = tcUnifyTy inst_ty_kind cls_arg_kind+ enough_args = n_args_to_keep >= 0++ -- Check that the result really is well-kinded+ ; checkTc (enough_args && isJust mb_match)+ (derivingKindErr tc cls cls_tys cls_arg_kind enough_args)++ ; let Just kind_subst = mb_match+ ki_subst_range = getTCvSubstRangeFVs kind_subst+ all_tkvs = toposortTyVars $+ fvVarList $ unionFV+ (tyCoFVsOfTypes tc_args_to_keep)+ (FV.mkFVs deriv_tvs)+ -- See Note [Unification of two kind variables in deriving]+ unmapped_tkvs = filter (\v -> v `notElemTCvSubst` kind_subst+ && not (v `elemVarSet` ki_subst_range))+ all_tkvs+ (subst, _) = mapAccumL substTyVarBndr+ kind_subst unmapped_tkvs+ final_tc_args = substTys subst tc_args_to_keep+ final_cls_tys = substTys subst cls_tys+ tkvs = tyCoVarsOfTypesWellScoped $+ final_cls_tys ++ final_tc_args++ ; traceTc "Deriving strategy (deriving clause)" $+ vcat [ppr deriv_strat, ppr deriv_pred]++ ; traceTc "derivTyData1" (vcat [ pprTyVars tvs, ppr tc, ppr tc_args+ , ppr deriv_pred+ , pprTyVars (tyCoVarsOfTypesList tc_args)+ , ppr n_args_to_keep, ppr n_args_to_drop+ , ppr inst_ty_kind, ppr cls_arg_kind, ppr mb_match+ , ppr final_tc_args, ppr final_cls_tys ])++ ; traceTc "derivTyData2" (vcat [ ppr tkvs ])++ ; checkTc (allDistinctTyVars (mkVarSet tkvs) args_to_drop) -- (a, b, c)+ (derivingEtaErr cls final_cls_tys (mkTyConApp tc final_tc_args))+ -- Check that+ -- (a) The args to drop are all type variables; eg reject:+ -- data instance T a Int = .... deriving( Monad )+ -- (b) The args to drop are all *distinct* type variables; eg reject:+ -- class C (a :: * -> * -> *) where ...+ -- data instance T a a = ... deriving( C )+ -- (c) The type class args, or remaining tycon args,+ -- do not mention any of the dropped type variables+ -- newtype T a s = ... deriving( ST s )+ -- newtype instance K a a = ... deriving( Monad )+ --+ -- It is vital that the implementation of allDistinctTyVars+ -- expand any type synonyms.+ -- See Note [Eta-reducing type synonyms]++ ; spec <- mkEqnHelp Nothing tkvs+ cls final_cls_tys tc final_tc_args+ Nothing deriv_strat+ ; traceTc "derivTyData" (ppr spec)+ ; return [spec] } }+++{-+Note [Unify kinds in deriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #8534)+ data T a b = MkT a deriving( Functor )+ -- where Functor :: (*->*) -> Constraint++So T :: forall k. * -> k -> *. We want to get+ instance Functor (T * (a:*)) where ...+Notice the '*' argument to T.++Moreover, as well as instantiating T's kind arguments, we may need to instantiate+C's kind args. Consider (Trac #8865):+ newtype T a b = MkT (Either a b) deriving( Category )+where+ Category :: forall k. (k -> k -> *) -> Constraint+We need to generate the instance+ instance Category * (Either a) where ...+Notice the '*' argument to Category.++So we need to+ * drop arguments from (T a b) to match the number of+ arrows in the (last argument of the) class;+ * and then *unify* kind of the remaining type against the+ expected kind, to figure out how to instantiate C's and T's+ kind arguments.++In the two examples,+ * we unify kind-of( T k (a:k) ) ~ kind-of( Functor )+ i.e. (k -> *) ~ (* -> *) to find k:=*.+ yielding k:=*++ * we unify kind-of( Either ) ~ kind-of( Category )+ i.e. (* -> * -> *) ~ (k -> k -> k)+ yielding k:=*++Now we get a kind substitution. We then need to:++ 1. Remove the substituted-out kind variables from the quantified kind vars++ 2. Apply the substitution to the kinds of quantified *type* vars+ (and extend the substitution to reflect this change)++ 3. Apply that extended substitution to the non-dropped args (types and+ kinds) of the type and class++Forgetting step (2) caused Trac #8893:+ data V a = V [a] deriving Functor+ data P (x::k->*) (a:k) = P (x a) deriving Functor+ data C (x::k->*) (a:k) = C (V (P x a)) deriving Functor++When deriving Functor for P, we unify k to *, but we then want+an instance $df :: forall (x:*->*). Functor x => Functor (P * (x:*->*))+and similarly for C. Notice the modified kind of x, both at binding+and occurrence sites.++This can lead to some surprising results when *visible* kind binder is+unified (in contrast to the above examples, in which only non-visible kind+binders were considered). Consider this example from Trac #11732:++ data T k (a :: k) = MkT deriving Functor++Since unification yields k:=*, this results in a generated instance of:++ instance Functor (T *) where ...++which looks odd at first glance, since one might expect the instance head+to be of the form Functor (T k). Indeed, one could envision an alternative+generated instance of:++ instance (k ~ *) => Functor (T k) where++But this does not typecheck as the result of a -XTypeInType design decision:+kind equalities are not allowed to be bound in types, only terms. But in+essence, the two instance declarations are entirely equivalent, since even+though (T k) matches any kind k, the only possibly value for k is *, since+anything else is ill-typed. As a result, we can just as comfortably use (T *).++Another way of thinking about is: deriving clauses often infer constraints.+For example:++ data S a = S a deriving Eq++infers an (Eq a) constraint in the derived instance. By analogy, when we+are deriving Functor, we might infer an equality constraint (e.g., k ~ *).+The only distinction is that GHC instantiates equality constraints directly+during the deriving process.++Another quirk of this design choice manifests when typeclasses have visible+kind parameters. Consider this code (also from Trac #11732):++ class Cat k (cat :: k -> k -> *) where+ catId :: cat a a+ catComp :: cat b c -> cat a b -> cat a c++ instance Cat * (->) where+ catId = id+ catComp = (.)++ newtype Fun a b = Fun (a -> b) deriving (Cat k)++Even though we requested an derived instance of the form (Cat k Fun), the+kind unification will actually generate (Cat * Fun) (i.e., the same thing as if+the user wrote deriving (Cat *)).++Note [Unification of two kind variables in deriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As a special case of the Note above, it is possible to derive an instance of+a poly-kinded typeclass for a poly-kinded datatype. For example:++ class Category (cat :: k -> k -> *) where+ newtype T (c :: k -> k -> *) a b = MkT (c a b) deriving Category++This case is suprisingly tricky. To see why, let's write out what instance GHC+will attempt to derive (using -fprint-explicit-kinds syntax):++ instance Category k1 (T k2 c) where ...++GHC will attempt to unify k1 and k2, which produces a substitution (kind_subst)+that looks like [k2 :-> k1]. Importantly, we need to apply this substitution to+the type variable binder for c, since its kind is (k2 -> k2 -> *).++We used to accomplish this by doing the following:++ unmapped_tkvs = filter (`notElemTCvSubst` kind_subst) all_tkvs+ (subst, _) = mapAccumL substTyVarBndr kind_subst unmapped_tkvs++Where all_tkvs contains all kind variables in the class and instance types (in+this case, all_tkvs = [k1,k2]). But since kind_subst only has one mapping,+this results in unmapped_tkvs being [k1], and as a consequence, k1 gets mapped+to another kind variable in subst! That is, subst = [k2 :-> k1, k1 :-> k_new].+This is bad, because applying that substitution yields the following instance:++ instance Category k_new (T k1 c) where ...++In other words, keeping k1 in unmapped_tvks taints the substitution, resulting+in an ill-kinded instance (this caused Trac #11837).++To prevent this, we need to filter out any variable from all_tkvs which either++1. Appears in the domain of kind_subst. notElemTCvSubst checks this.+2. Appears in the range of kind_subst. To do this, we compute the free+ variable set of the range of kind_subst with getTCvSubstRangeFVs, and check+ if a kind variable appears in that set.++Note [Eta-reducing type synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+One can instantiate a type in a data family instance with a type synonym that+mentions other type variables:++ type Const a b = a+ data family Fam (f :: * -> *) (a :: *)+ newtype instance Fam f (Const a f) = Fam (f a) deriving Functor++With -XTypeInType, it is also possible to define kind synonyms, and they can+mention other types in a datatype declaration. For example,++ type Const a b = a+ newtype T f (a :: Const * f) = T (f a) deriving Functor++When deriving, we need to perform eta-reduction analysis to ensure that none of+the eta-reduced type variables are mentioned elsewhere in the declaration. But+we need to be careful, because if we don't expand through the Const type+synonym, we will mistakenly believe that f is an eta-reduced type variable and+fail to derive Functor, even though the code above is correct (see Trac #11416,+where this was first noticed). For this reason, we expand the type synonyms in+the eta-reduced types before doing any analysis.+-}++mkEqnHelp :: Maybe OverlapMode+ -> [TyVar]+ -> Class -> [Type]+ -> TyCon -> [Type]+ -> DerivContext -- Just => context supplied (standalone deriving)+ -- Nothing => context inferred (deriving on data decl)+ -> Maybe DerivStrategy+ -> TcRn EarlyDerivSpec+-- Make the EarlyDerivSpec for an instance+-- forall tvs. theta => cls (tys ++ [ty])+-- where the 'theta' is optional (that's the Maybe part)+-- Assumes that this declaration is well-kinded++mkEqnHelp overlap_mode tvs cls cls_tys tycon tc_args mtheta deriv_strat+ = do { -- Find the instance of a data family+ -- Note [Looking up family instances for deriving]+ fam_envs <- tcGetFamInstEnvs+ ; let (rep_tc, rep_tc_args, _co) = tcLookupDataFamInst fam_envs tycon tc_args+ -- If it's still a data family, the lookup failed; i.e no instance exists+ ; when (isDataFamilyTyCon rep_tc)+ (bale_out (text "No family instance for" <+> quotes (pprTypeApp tycon tc_args)))++ ; dflags <- getDynFlags+ ; if isDataTyCon rep_tc then+ mkDataTypeEqn dflags overlap_mode tvs cls cls_tys+ tycon tc_args rep_tc rep_tc_args mtheta deriv_strat+ else+ mkNewTypeEqn dflags overlap_mode tvs cls cls_tys+ tycon tc_args rep_tc rep_tc_args mtheta deriv_strat }+ where+ bale_out msg = failWithTc (derivingThingErr False cls cls_tys+ (mkTyConApp tycon tc_args) deriv_strat msg)++{-+Note [Looking up family instances for deriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+tcLookupFamInstExact is an auxiliary lookup wrapper which requires+that looked-up family instances exist. If called with a vanilla+tycon, the old type application is simply returned.++If we have+ data instance F () = ... deriving Eq+ data instance F () = ... deriving Eq+then tcLookupFamInstExact will be confused by the two matches;+but that can't happen because tcInstDecls1 doesn't call tcDeriving+if there are any overlaps.++There are two other things that might go wrong with the lookup.+First, we might see a standalone deriving clause+ deriving Eq (F ())+when there is no data instance F () in scope.++Note that it's OK to have+ data instance F [a] = ...+ deriving Eq (F [(a,b)])+where the match is not exact; the same holds for ordinary data types+with standalone deriving declarations.++Note [Deriving, type families, and partial applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When there are no type families, it's quite easy:++ newtype S a = MkS [a]+ -- :CoS :: S ~ [] -- Eta-reduced++ instance Eq [a] => Eq (S a) -- by coercion sym (Eq (:CoS a)) : Eq [a] ~ Eq (S a)+ instance Monad [] => Monad S -- by coercion sym (Monad :CoS) : Monad [] ~ Monad S++When type familes are involved it's trickier:++ data family T a b+ newtype instance T Int a = MkT [a] deriving( Eq, Monad )+ -- :RT is the representation type for (T Int a)+ -- :Co:RT :: :RT ~ [] -- Eta-reduced!+ -- :CoF:RT a :: T Int a ~ :RT a -- Also eta-reduced!++ instance Eq [a] => Eq (T Int a) -- easy by coercion+ -- d1 :: Eq [a]+ -- d2 :: Eq (T Int a) = d1 |> Eq (sym (:Co:RT a ; :coF:RT a))++ instance Monad [] => Monad (T Int) -- only if we can eta reduce???+ -- d1 :: Monad []+ -- d2 :: Monad (T Int) = d1 |> Monad (sym (:Co:RT ; :coF:RT))++Note the need for the eta-reduced rule axioms. After all, we can+write it out+ instance Monad [] => Monad (T Int) -- only if we can eta reduce???+ return x = MkT [x]+ ... etc ...++See Note [Eta reduction for data families] in FamInstEnv++%************************************************************************+%* *+ Deriving data types+* *+************************************************************************+-}++mkDataTypeEqn :: DynFlags+ -> Maybe OverlapMode+ -> [TyVar] -- Universally quantified type variables in the instance+ -> Class -- Class for which we need to derive an instance+ -> [Type] -- Other parameters to the class except the last+ -> TyCon -- Type constructor for which the instance is requested+ -- (last parameter to the type class)+ -> [Type] -- Parameters to the type constructor+ -> TyCon -- rep of the above (for type families)+ -> [Type] -- rep of the above+ -> DerivContext -- Context of the instance, for standalone deriving+ -> Maybe DerivStrategy -- 'Just' if user requests a particular+ -- deriving strategy.+ -- Otherwise, 'Nothing'.+ -> TcRn EarlyDerivSpec -- Return 'Nothing' if error++mkDataTypeEqn dflags overlap_mode tvs cls cls_tys+ tycon tc_args rep_tc rep_tc_args mtheta deriv_strat+ = case deriv_strat of+ Just StockStrategy -> mk_eqn_stock dflags mtheta cls cls_tys rep_tc+ go_for_it bale_out+ Just AnyclassStrategy -> mk_eqn_anyclass dflags go_for_it bale_out+ -- GeneralizedNewtypeDeriving makes no sense for non-newtypes+ Just NewtypeStrategy -> bale_out gndNonNewtypeErr+ -- Lacking a user-requested deriving strategy, we will try to pick+ -- between the stock or anyclass strategies+ Nothing -> mk_eqn_no_mechanism dflags tycon mtheta cls cls_tys rep_tc+ go_for_it bale_out+ where+ go_for_it = mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args+ rep_tc rep_tc_args mtheta (isJust deriv_strat)+ bale_out msg = failWithTc (derivingThingErr False cls cls_tys+ (mkTyConApp tycon tc_args) deriv_strat msg)++mk_data_eqn :: Maybe OverlapMode -> [TyVar] -> Class -> [Type]+ -> TyCon -> [TcType] -> TyCon -> [TcType] -> DerivContext+ -> Bool -- True if an explicit deriving strategy keyword was+ -- provided+ -> DerivSpecMechanism -- How GHC should proceed attempting to+ -- derive this instance, determined in+ -- mkDataTypeEqn/mkNewTypeEqn+ -> TcM EarlyDerivSpec+mk_data_eqn overlap_mode tvs cls cls_tys tycon tc_args rep_tc rep_tc_args+ mtheta strat_used mechanism+ = do doDerivInstErrorChecks1 cls cls_tys tycon tc_args rep_tc mtheta+ strat_used mechanism+ loc <- getSrcSpanM+ dfun_name <- newDFunName' cls tycon+ case mtheta of+ Nothing -> -- Infer context+ do { (inferred_constraints, tvs', inst_tys')+ <- inferConstraints tvs cls cls_tys inst_ty+ rep_tc rep_tc_args mechanism+ ; return $ InferTheta $ DS+ { ds_loc = loc+ , ds_name = dfun_name, ds_tvs = tvs'+ , ds_cls = cls, ds_tys = inst_tys'+ , ds_tc = rep_tc+ , ds_theta = inferred_constraints+ , ds_overlap = overlap_mode+ , ds_mechanism = mechanism } }++ Just theta -> do -- Specified context+ return $ GivenTheta $ DS+ { ds_loc = loc+ , ds_name = dfun_name, ds_tvs = tvs+ , ds_cls = cls, ds_tys = inst_tys+ , ds_tc = rep_tc+ , ds_theta = theta+ , ds_overlap = overlap_mode+ , ds_mechanism = mechanism }+ where+ inst_ty = mkTyConApp tycon tc_args+ inst_tys = cls_tys ++ [inst_ty]++mk_eqn_stock :: DynFlags -> DerivContext -> Class -> [Type] -> TyCon+ -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)+ -> (SDoc -> TcRn EarlyDerivSpec)+ -> TcRn EarlyDerivSpec+mk_eqn_stock dflags mtheta cls cls_tys rep_tc go_for_it bale_out+ = case checkSideConditions dflags mtheta cls cls_tys rep_tc of+ CanDerive -> mk_eqn_stock' cls go_for_it+ DerivableClassError msg -> bale_out msg+ _ -> bale_out (nonStdErr cls)++mk_eqn_stock' :: Class -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)+ -> TcRn EarlyDerivSpec+mk_eqn_stock' cls go_for_it+ = go_for_it $ case hasStockDeriving cls of+ Just gen_fn -> DerivSpecStock gen_fn+ Nothing ->+ pprPanic "mk_eqn_stock': Not a stock class!" (ppr cls)++mk_eqn_anyclass :: DynFlags+ -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)+ -> (SDoc -> TcRn EarlyDerivSpec)+ -> TcRn EarlyDerivSpec+mk_eqn_anyclass dflags go_for_it bale_out+ = case canDeriveAnyClass dflags of+ IsValid -> go_for_it DerivSpecAnyClass+ NotValid msg -> bale_out msg++mk_eqn_no_mechanism :: DynFlags -> TyCon -> DerivContext+ -> Class -> [Type] -> TyCon+ -> (DerivSpecMechanism -> TcRn EarlyDerivSpec)+ -> (SDoc -> TcRn EarlyDerivSpec)+ -> TcRn EarlyDerivSpec+mk_eqn_no_mechanism dflags tc mtheta cls cls_tys rep_tc go_for_it bale_out+ = case checkSideConditions dflags mtheta cls cls_tys rep_tc of+ -- NB: pass the *representation* tycon to checkSideConditions+ NonDerivableClass msg -> bale_out (dac_error msg)+ DerivableClassError msg -> bale_out msg+ CanDerive -> mk_eqn_stock' cls go_for_it+ DerivableViaInstance -> go_for_it DerivSpecAnyClass+ where+ -- See Note [Deriving instances for classes themselves]+ dac_error msg+ | isClassTyCon rep_tc+ = quotes (ppr tc) <+> text "is a type class,"+ <+> text "and can only have a derived instance"+ $+$ text "if DeriveAnyClass is enabled"+ | otherwise+ = nonStdErr cls $$ msg++{-+************************************************************************+* *+ Deriving newtypes+* *+************************************************************************+-}++mkNewTypeEqn :: DynFlags -> Maybe OverlapMode -> [TyVar] -> Class+ -> [Type] -> TyCon -> [Type] -> TyCon -> [Type]+ -> DerivContext -> Maybe DerivStrategy+ -> TcRn EarlyDerivSpec+mkNewTypeEqn dflags overlap_mode tvs+ cls cls_tys tycon tc_args rep_tycon rep_tc_args+ mtheta deriv_strat+-- Want: instance (...) => cls (cls_tys ++ [tycon tc_args]) where ...+ = ASSERT( length cls_tys + 1 == classArity cls )+ case deriv_strat of+ Just StockStrategy -> mk_eqn_stock dflags mtheta cls cls_tys rep_tycon+ go_for_it_other bale_out+ Just AnyclassStrategy -> mk_eqn_anyclass dflags go_for_it_other bale_out+ Just NewtypeStrategy ->+ -- Since the user explicitly asked for GeneralizedNewtypeDeriving, we+ -- don't need to perform all of the checks we normally would, such as+ -- if the class being derived is known to produce ill-roled coercions+ -- (e.g., Traversable), since we can just derive the instance and let+ -- it error if need be.+ -- See Note [Determining whether newtype-deriving is appropriate]+ if coercion_looks_sensible && newtype_deriving+ then go_for_it_gnd+ else bale_out (cant_derive_err $$+ if newtype_deriving then empty else suggest_gnd)+ Nothing+ | might_derive_via_coercible+ && ((newtype_deriving && not deriveAnyClass)+ || std_class_via_coercible cls)+ -> go_for_it_gnd+ | otherwise+ -> case checkSideConditions dflags mtheta cls cls_tys rep_tycon of+ DerivableClassError msg+ -- There's a particular corner case where+ --+ -- 1. -XGeneralizedNewtypeDeriving and -XDeriveAnyClass are both+ -- enabled at the same time+ -- 2. We're deriving a particular stock derivable class+ -- (such as Functor)+ --+ -- and the previous cases won't catch it. This fixes the bug+ -- reported in Trac #10598.+ | might_derive_via_coercible && newtype_deriving+ -> go_for_it_gnd+ -- Otherwise, throw an error for a stock class+ | might_derive_via_coercible && not newtype_deriving+ -> bale_out (msg $$ suggest_gnd)+ | otherwise+ -> bale_out msg++ -- Must use newtype deriving or DeriveAnyClass+ NonDerivableClass _msg+ -- Too hard, even with newtype deriving+ | newtype_deriving -> bale_out cant_derive_err+ -- Try newtype deriving!+ -- Here we suggest GeneralizedNewtypeDeriving even in cases where+ -- it may not be applicable. See Trac #9600.+ | otherwise -> bale_out (non_std $$ suggest_gnd)++ -- DerivableViaInstance+ DerivableViaInstance -> do+ -- If both DeriveAnyClass and GeneralizedNewtypeDeriving are+ -- enabled, we take the diplomatic approach of defaulting to+ -- DeriveAnyClass, but emitting a warning about the choice.+ -- See Note [Deriving strategies]+ when (newtype_deriving && deriveAnyClass) $+ addWarnTc NoReason $ sep+ [ text "Both DeriveAnyClass and"+ <+> text "GeneralizedNewtypeDeriving are enabled"+ , text "Defaulting to the DeriveAnyClass strategy"+ <+> text "for instantiating" <+> ppr cls ]+ go_for_it_other DerivSpecAnyClass+ -- CanDerive+ CanDerive -> mk_eqn_stock' cls go_for_it_other+ where+ newtype_deriving = xopt LangExt.GeneralizedNewtypeDeriving dflags+ deriveAnyClass = xopt LangExt.DeriveAnyClass dflags+ go_for_it_gnd = do+ traceTc "newtype deriving:" $+ ppr tycon <+> ppr rep_tys <+> ppr all_thetas+ let mechanism = DerivSpecNewtype rep_inst_ty+ doDerivInstErrorChecks1 cls cls_tys tycon tc_args rep_tycon mtheta+ strat_used mechanism+ dfun_name <- newDFunName' cls tycon+ loc <- getSrcSpanM+ case mtheta of+ Just theta -> return $ GivenTheta $ DS+ { ds_loc = loc+ , ds_name = dfun_name, ds_tvs = tvs+ , ds_cls = cls, ds_tys = inst_tys+ , ds_tc = rep_tycon+ , ds_theta = theta+ , ds_overlap = overlap_mode+ , ds_mechanism = mechanism }+ Nothing -> return $ InferTheta $ DS+ { ds_loc = loc+ , ds_name = dfun_name, ds_tvs = tvs+ , ds_cls = cls, ds_tys = inst_tys+ , ds_tc = rep_tycon+ , ds_theta = all_thetas+ , ds_overlap = overlap_mode+ , ds_mechanism = mechanism }+ go_for_it_other = mk_data_eqn overlap_mode tvs cls cls_tys tycon+ tc_args rep_tycon rep_tc_args mtheta strat_used+ bale_out = bale_out' newtype_deriving+ bale_out' b = failWithTc . derivingThingErr b cls cls_tys inst_ty+ deriv_strat++ strat_used = isJust deriv_strat+ non_std = nonStdErr cls+ suggest_gnd = text "Try GeneralizedNewtypeDeriving for GHC's newtype-deriving extension"++ -- Here is the plan for newtype derivings. We see+ -- newtype T a1...an = MkT (t ak+1...an) deriving (.., C s1 .. sm, ...)+ -- where t is a type,+ -- ak+1...an is a suffix of a1..an, and are all tyvars+ -- ak+1...an do not occur free in t, nor in the s1..sm+ -- (C s1 ... sm) is a *partial applications* of class C+ -- with the last parameter missing+ -- (T a1 .. ak) matches the kind of C's last argument+ -- (and hence so does t)+ -- The latter kind-check has been done by deriveTyData already,+ -- and tc_args are already trimmed+ --+ -- We generate the instance+ -- instance forall ({a1..ak} u fvs(s1..sm)).+ -- C s1 .. sm t => C s1 .. sm (T a1...ak)+ -- where T a1...ap is the partial application of+ -- the LHS of the correct kind and p >= k+ --+ -- NB: the variables below are:+ -- tc_tvs = [a1, ..., an]+ -- tyvars_to_keep = [a1, ..., ak]+ -- rep_ty = t ak .. an+ -- deriv_tvs = fvs(s1..sm) \ tc_tvs+ -- tys = [s1, ..., sm]+ -- rep_fn' = t+ --+ -- Running example: newtype T s a = MkT (ST s a) deriving( Monad )+ -- We generate the instance+ -- instance Monad (ST s) => Monad (T s) where++ nt_eta_arity = newTyConEtadArity rep_tycon+ -- For newtype T a b = MkT (S a a b), the TyCon machinery already+ -- eta-reduces the representation type, so we know that+ -- T a ~ S a a+ -- That's convenient here, because we may have to apply+ -- it to fewer than its original complement of arguments++ -- Note [Newtype representation]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Need newTyConRhs (*not* a recursive representation finder)+ -- to get the representation type. For example+ -- newtype B = MkB Int+ -- newtype A = MkA B deriving( Num )+ -- We want the Num instance of B, *not* the Num instance of Int,+ -- when making the Num instance of A!+ rep_inst_ty = newTyConInstRhs rep_tycon rep_tc_args+ rep_tys = cls_tys ++ [rep_inst_ty]+ rep_pred = mkClassPred cls rep_tys+ rep_pred_o = mkPredOrigin DerivOrigin TypeLevel rep_pred+ -- rep_pred is the representation dictionary, from where+ -- we are gong to get all the methods for the newtype+ -- dictionary++ -- Next we figure out what superclass dictionaries to use+ -- See Note [Newtype deriving superclasses] above+ sc_preds :: [PredOrigin]+ cls_tyvars = classTyVars cls+ inst_ty = mkTyConApp tycon tc_args+ inst_tys = cls_tys ++ [inst_ty]+ sc_preds = map (mkPredOrigin DerivOrigin TypeLevel) $+ substTheta (zipTvSubst cls_tyvars inst_tys) $+ classSCTheta cls++ -- Next we collect constraints for the class methods+ -- If there are no methods, we don't need any constraints+ -- Otherwise we need (C rep_ty), for the representation methods,+ -- and constraints to coerce each individual method+ meth_preds :: [PredOrigin]+ meths = classMethods cls+ meth_preds | null meths = [] -- No methods => no constraints+ -- (Trac #12814)+ | otherwise = rep_pred_o : coercible_constraints+ coercible_constraints+ = [ mkPredOrigin (DerivOriginCoerce meth t1 t2) TypeLevel+ (mkReprPrimEqPred t1 t2)+ | meth <- meths+ , let (Pair t1 t2) = mkCoerceClassMethEqn cls tvs+ inst_tys rep_inst_ty meth ]++ all_thetas :: [ThetaOrigin]+ all_thetas = [mkThetaOriginFromPreds $ meth_preds ++ sc_preds]++ -------------------------------------------------------------------+ -- Figuring out whether we can only do this newtype-deriving thing++ -- See Note [Determining whether newtype-deriving is appropriate]+ might_derive_via_coercible+ = not (non_coercible_class cls)+ && coercion_looks_sensible+-- && not (isRecursiveTyCon tycon) -- Note [Recursive newtypes]+ coercion_looks_sensible+ = eta_ok+ -- Check (a) from Note [GND and associated type families]+ && ats_ok+ -- Check (b) from Note [GND and associated type families]+ && isNothing at_without_last_cls_tv++ -- Check that eta reduction is OK+ eta_ok = nt_eta_arity <= length rep_tc_args+ -- The newtype can be eta-reduced to match the number+ -- of type argument actually supplied+ -- newtype T a b = MkT (S [a] b) deriving( Monad )+ -- Here the 'b' must be the same in the rep type (S [a] b)+ -- And the [a] must not mention 'b'. That's all handled+ -- by nt_eta_rity.++ (adf_tcs, atf_tcs) = partition isDataFamilyTyCon at_tcs+ ats_ok = null adf_tcs+ -- We cannot newtype-derive data family instances++ at_without_last_cls_tv+ = find (\tc -> last_cls_tv `notElem` tyConTyVars tc) atf_tcs+ at_tcs = classATs cls+ last_cls_tv = ASSERT( notNull cls_tyvars )+ last cls_tyvars++ cant_derive_err+ = vcat [ ppUnless eta_ok eta_msg+ , ppUnless ats_ok ats_msg+ , maybe empty at_tv_msg+ at_without_last_cls_tv]+ eta_msg = text "cannot eta-reduce the representation type enough"+ ats_msg = text "the class has associated data types"+ at_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))++{-+Note [Recursive newtypes]+~~~~~~~~~~~~~~~~~~~~~~~~~+Newtype deriving works fine, even if the newtype is recursive.+e.g. newtype S1 = S1 [T1 ()]+ newtype T1 a = T1 (StateT S1 IO a ) deriving( Monad )+Remember, too, that type families are currently (conservatively) given+a recursive flag, so this also allows newtype deriving to work+for type famillies.++We used to exclude recursive types, because we had a rather simple+minded way of generating the instance decl:+ newtype A = MkA [A]+ instance Eq [A] => Eq A -- Makes typechecker loop!+But now we require a simple context, so it's ok.++Note [Determining whether newtype-deriving is appropriate]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we see+ newtype NT = MkNT Foo+ deriving C+we have to decide how to perform the deriving. Do we do newtype deriving,+or do we do normal deriving? In general, we prefer to do newtype deriving+wherever possible. So, we try newtype deriving unless there's a glaring+reason not to.++"Glaring reasons not to" include trying to derive a class for which a+coercion-based instance doesn't make sense. These classes are listed in+the definition of non_coercible_class. They include Show (since it must+show the name of the datatype) and Traversable (since a coercion-based+Traversable instance is ill-roled).++However, non_coercible_class is ignored if the user explicitly requests+to derive an instance with GeneralizedNewtypeDeriving using the newtype+deriving strategy. In such a scenario, GHC will unquestioningly try to+derive the instance via coercions (even if the final generated code is+ill-roled!). See Note [Deriving strategies].++Note that newtype deriving might fail, even after we commit to it. This+is because the derived instance uses `coerce`, which must satisfy its+`Coercible` constraint. This is different than other deriving scenarios,+where we're sure that the resulting instance will type-check.++Note [GND and associated type families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's possible to use GeneralizedNewtypeDeriving (GND) to derive instances for+classes with associated type families. A general recipe is:++ class C x y z where+ type T y z x+ op :: x -> [y] -> z++ newtype N a = MkN <rep-type> deriving( C )++ =====>++ instance C x y <rep-type> => C x y (N a) where+ type T y (N a) x = T y <rep-type> x+ op = coerce (op :: x -> [y] -> <rep-type>)++However, we must watch out for three things:++(a) The class must not contain any data families. If it did, we'd have to+ generate a fresh data constructor name for the derived data family+ instance, and it's not clear how to do this.++(b) Each associated type family's type variables must mention the last type+ variable of the class. As an example, you wouldn't be able to use GND to+ derive an instance of this class:++ class C a b where+ type T a++ But you would be able to derive an instance of this class:++ class C a b where+ type T b++ The difference is that in the latter T mentions the last parameter of C+ (i.e., it mentions b), but the former T does not. If you tried, e.g.,++ newtype Foo x = Foo x deriving (C a)++ with the former definition of C, you'd end up with something like this:++ instance C a (Foo x) where+ type T a = T ???++ This T family instance doesn't mention the newtype (or its representation+ type) at all, so we disallow such constructions with GND.++(c) UndecidableInstances might need to be enabled. Here's a case where it is+ most definitely necessary:++ class C a where+ type T a+ newtype Loop = Loop MkLoop deriving C++ =====>++ instance C Loop where+ type T Loop = T Loop++ Obviously, T Loop would send the typechecker into a loop. Unfortunately,+ you might even need UndecidableInstances even in cases where the+ typechecker would be guaranteed to terminate. For example:++ instance C Int where+ type C Int = Int+ newtype MyInt = MyInt Int deriving C++ =====>++ instance C MyInt where+ type T MyInt = T Int++ GHC's termination checker isn't sophisticated enough to conclude that the+ definition of T MyInt terminates, so UndecidableInstances is required.++************************************************************************+* *+\subsection[TcDeriv-normal-binds]{Bindings for the various classes}+* *+************************************************************************++After all the trouble to figure out the required context for the+derived instance declarations, all that's left is to chug along to+produce them. They will then be shoved into @tcInstDecls2@, which+will do all its usual business.++There are lots of possibilities for code to generate. Here are+various general remarks.++PRINCIPLES:+\begin{itemize}+\item+We want derived instances of @Eq@ and @Ord@ (both v common) to be+``you-couldn't-do-better-by-hand'' efficient.++\item+Deriving @Show@---also pretty common--- should also be reasonable good code.++\item+Deriving for the other classes isn't that common or that big a deal.+\end{itemize}++PRAGMATICS:++\begin{itemize}+\item+Deriving @Ord@ is done mostly with the 1.3 @compare@ method.++\item+Deriving @Eq@ also uses @compare@, if we're deriving @Ord@, too.++\item+We {\em normally} generate code only for the non-defaulted methods;+there are some exceptions for @Eq@ and (especially) @Ord@...++\item+Sometimes we use a @_con2tag_<tycon>@ function, which returns a data+constructor's numeric (@Int#@) tag. These are generated by+@gen_tag_n_con_binds@, and the heuristic for deciding if one of+these is around is given by @hasCon2TagFun@.++The examples under the different sections below will make this+clearer.++\item+Much less often (really just for deriving @Ix@), we use a+@_tag2con_<tycon>@ function. See the examples.++\item+We use the renamer!!! Reason: we're supposed to be+producing @LHsBinds Name@ for the methods, but that means+producing correctly-uniquified code on the fly. This is entirely+possible (the @TcM@ monad has a @UniqueSupply@), but it is painful.+So, instead, we produce @MonoBinds RdrName@ then heave 'em through+the renamer. What a great hack!+\end{itemize}+-}++-- Generate the InstInfo for the required instance paired with the+-- *representation* tycon for that instance,+-- plus any auxiliary bindings required+--+-- Representation tycons differ from the tycon in the instance signature in+-- case of instances for indexed families.+--+genInst :: DerivSpec theta+ -> TcM (ThetaType -> TcM (InstInfo RdrName), BagDerivStuff, Maybe Name)+-- We must use continuation-returning style here to get the order in which we+-- typecheck family instances and derived instances right.+-- See Note [Staging of tcDeriving]+genInst spec@(DS { ds_tvs = tvs, ds_tc = rep_tycon+ , ds_mechanism = mechanism, ds_tys = tys+ , ds_cls = clas, ds_loc = loc })+ = do (meth_binds, deriv_stuff) <- genDerivStuff mechanism loc clas+ rep_tycon tys tvs+ let mk_inst_info theta = do+ inst_spec <- newDerivClsInst theta spec+ doDerivInstErrorChecks2 clas inst_spec mechanism+ traceTc "newder" (ppr inst_spec)+ return $ InstInfo+ { iSpec = inst_spec+ , iBinds = InstBindings+ { ib_binds = meth_binds+ , ib_tyvars = map Var.varName tvs+ , ib_pragmas = []+ , ib_extensions = extensions+ , ib_derived = True } }+ return (mk_inst_info, deriv_stuff, unusedConName)+ where+ unusedConName :: Maybe Name+ unusedConName+ | isDerivSpecNewtype mechanism+ -- See Note [Newtype deriving and unused constructors]+ = Just $ getName $ head $ tyConDataCons rep_tycon+ | otherwise+ = Nothing++ extensions :: [LangExt.Extension]+ extensions+ | isDerivSpecNewtype mechanism+ -- Both these flags are needed for higher-rank uses of coerce+ -- See Note [Newtype-deriving instances] in TcGenDeriv+ = [LangExt.ImpredicativeTypes, LangExt.RankNTypes]+ | otherwise+ = []++doDerivInstErrorChecks1 :: Class -> [Type] -> TyCon -> [Type] -> TyCon+ -> DerivContext -> Bool -> DerivSpecMechanism+ -> TcM ()+doDerivInstErrorChecks1 cls cls_tys tc tc_args rep_tc mtheta+ strat_used mechanism = do+ -- For standalone deriving (mtheta /= Nothing),+ -- check that all the data constructors are in scope...+ rdr_env <- getGlobalRdrEnv+ let data_con_names = map dataConName (tyConDataCons rep_tc)+ hidden_data_cons = not (isWiredInName (tyConName rep_tc)) &&+ (isAbstractTyCon rep_tc ||+ any not_in_scope data_con_names)+ not_in_scope dc = isNothing (lookupGRE_Name rdr_env dc)++ addUsedDataCons rdr_env rep_tc+ -- ...however, we don't perform this check if we're using DeriveAnyClass,+ -- since it doesn't generate any code that requires use of a data+ -- constructor.+ unless (anyclass_strategy || isNothing mtheta || not hidden_data_cons) $+ bale_out $ derivingHiddenErr tc+ where+ anyclass_strategy = isDerivSpecAnyClass mechanism++ bale_out msg = failWithTc (derivingThingErrMechanism cls cls_tys+ (mkTyConApp tc tc_args) strat_used mechanism msg)++doDerivInstErrorChecks2 :: Class -> ClsInst -> DerivSpecMechanism -> TcM ()+doDerivInstErrorChecks2 clas clas_inst mechanism+ = do { traceTc "doDerivInstErrorChecks2" (ppr clas_inst)+ ; dflags <- getDynFlags+ -- 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+ ; when (safeInferOn dflags) (recordUnsafeInfer emptyBag) } }+ where+ exotic_mechanism = case mechanism of+ DerivSpecStock{} -> False+ _ -> True++ gen_inst_err = hang (text ("Generic instances can only be derived in "+ ++ "Safe Haskell using the stock strategy.") $+$+ text "In the following instance:")+ 2 (pprInstanceHdr clas_inst)++genDerivStuff :: DerivSpecMechanism -> SrcSpan -> Class+ -> TyCon -> [Type] -> [TyVar]+ -> TcM (LHsBinds RdrName, BagDerivStuff)+genDerivStuff mechanism loc clas tycon inst_tys tyvars+ = case mechanism of+ -- See Note [Bindings for Generalised Newtype Deriving]+ DerivSpecNewtype rhs_ty -> gen_Newtype_binds loc clas tyvars+ inst_tys rhs_ty++ -- Try a stock deriver+ DerivSpecStock gen_fn -> gen_fn loc tycon inst_tys++ -- If there isn't a stock deriver, our last resort is -XDeriveAnyClass+ -- (since -XGeneralizedNewtypeDeriving fell through).+ DerivSpecAnyClass -> do+ let mini_env = mkVarEnv (classTyVars clas `zip` inst_tys)+ mini_subst = mkTvSubst (mkInScopeSet (mkVarSet tyvars)) mini_env+ dflags <- getDynFlags+ tyfam_insts <-+ -- canDeriveAnyClass should ensure that this code can't be reached+ -- unless -XDeriveAnyClass is enabled.+ ASSERT2( isValid (canDeriveAnyClass dflags)+ , ppr "genDerivStuff: bad derived class" <+> ppr clas )+ mapM (tcATDefault False loc mini_subst emptyNameSet)+ (classATItems clas)+ return ( emptyBag -- No method bindings are needed...+ , listToBag (map DerivFamInst (concat tyfam_insts))+ -- ...but we may need to generate binding for associated type+ -- family default instances.+ -- See Note [DeriveAnyClass and default family instances]+ )++{-+Note [Bindings for Generalised Newtype Deriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ class Eq a => C a where+ f :: a -> a+ newtype N a = MkN [a] deriving( C )+ instance Eq (N a) where ...++The 'deriving C' clause generates, in effect+ instance (C [a], Eq a) => C (N a) where+ f = coerce (f :: [a] -> [a])++This generates a cast for each method, but allows the superclasse to+be worked out in the usual way. In this case the superclass (Eq (N+a)) will be solved by the explicit Eq (N a) instance. We do *not*+create the superclasses by casting the superclass dictionaries for the+representation type.++See the paper "Safe zero-cost coercions for Haskell".++Note [DeriveAnyClass and default family instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When a class has a associated type family with a default instance, e.g.:++ class C a where+ type T a+ type T a = Char++then there are a couple of scenarios in which a user would expect T a to+default to Char. One is when an instance declaration for C is given without+an implementation for T:++ instance C Int++Another scenario in which this can occur is when the -XDeriveAnyClass extension+is used:++ data Example = Example deriving (C, Generic)++In the latter case, we must take care to check if C has any associated type+families with default instances, because -XDeriveAnyClass will never provide+an implementation for them. We "fill in" the default instances using the+tcATDefault function from TcClsDcl (which is also used in TcInstDcls to handle+the empty instance declaration case).++Note [Deriving strategies]+~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC has a notion of deriving strategies, which allow the user to explicitly+request which approach to use when deriving an instance (enabled with the+-XDerivingStrategies language extension). For more information, refer to the+original Trac ticket (#10598) or the associated wiki page:+https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DerivingStrategies++A deriving strategy can be specified in a deriving clause:++ newtype Foo = MkFoo Bar+ deriving newtype C++Or in a standalone deriving declaration:++ deriving anyclass instance C Foo++-XDerivingStrategies also allows the use of multiple deriving clauses per data+declaration so that a user can derive some instance with one deriving strategy+and other instances with another deriving strategy. For example:++ newtype Baz = Baz Quux+ deriving (Eq, Ord)+ deriving stock (Read, Show)+ deriving newtype (Num, Floating)+ deriving anyclass C++Currently, the deriving strategies are:++* stock: Have GHC implement a "standard" instance for a data type, if possible+ (e.g., Eq, Ord, Generic, Data, Functor, etc.)++* anyclass: Use -XDeriveAnyClass++* newtype: Use -XGeneralizedNewtypeDeriving++If an explicit deriving strategy is not given, GHC has an algorithm it uses to+determine which strategy it will actually use. The algorithm is quite long,+so it lives in the Haskell wiki at+https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DerivingStrategies+("The deriving strategy resolution algorithm" section).++Internally, GHC uses the DerivStrategy datatype to denote a user-requested+deriving strategy, and it uses the DerivSpecMechanism datatype to denote what+GHC will use to derive the instance after taking the above steps. In other+words, GHC will always settle on a DerivSpecMechnism, even if the user did not+ask for a particular DerivStrategy (using the algorithm linked to above).++Note [Deriving instances for classes themselves]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Much of the code in TcDeriv assumes that deriving only works on data types.+But this assumption doesn't hold true for DeriveAnyClass, since it's perfectly+reasonable to do something like this:++ {-# LANGUAGE DeriveAnyClass #-}+ class C1 (a :: Constraint) where+ class C2 where+ deriving instance C1 C2+ -- This is equivalent to `instance C1 C2`++If DeriveAnyClass isn't enabled in the code above (i.e., it defaults to stock+deriving), we throw a special error message indicating that DeriveAnyClass is+the only way to go. We don't bother throwing this error if an explicit 'stock'+or 'newtype' keyword is used, since both options have their own perfectly+sensible error messages in the case of the above code (as C1 isn't a stock+derivable class, and C2 isn't a newtype).++************************************************************************+* *+\subsection[TcDeriv-taggery-Names]{What con2tag/tag2con functions are available?}+* *+************************************************************************+-}++nonUnaryErr :: LHsSigType Name -> SDoc+nonUnaryErr ct = 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 :: MsgDoc+derivingNullaryErr = text "Cannot derive instances for nullary classes"++derivingKindErr :: TyCon -> Class -> [Type] -> Kind -> Bool -> MsgDoc+derivingKindErr tc cls cls_tys cls_kind enough_args+ = 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++derivingEtaErr :: Class -> [Type] -> Type -> MsgDoc+derivingEtaErr cls cls_tys inst_ty+ = sep [text "Cannot eta-reduce to an instance of form",+ nest 2 (text "instance (...) =>"+ <+> pprClassPred cls (cls_tys ++ [inst_ty]))]++derivingThingErr :: Bool -> Class -> [Type] -> Type -> Maybe DerivStrategy+ -> MsgDoc -> MsgDoc+derivingThingErr newtype_deriving clas tys ty deriv_strat why+ = derivingThingErr' newtype_deriving clas tys ty (isJust deriv_strat)+ (maybe empty ppr deriv_strat) why++derivingThingErrMechanism :: Class -> [Type] -> Type+ -> Bool -- True if an explicit deriving strategy+ -- keyword was provided+ -> DerivSpecMechanism+ -> MsgDoc -> MsgDoc+derivingThingErrMechanism clas tys ty strat_used mechanism why+ = derivingThingErr' (isDerivSpecNewtype mechanism) clas tys ty strat_used+ (ppr mechanism) why++derivingThingErr' :: Bool -> Class -> [Type] -> Type -> Bool -> MsgDoc+ -> MsgDoc -> MsgDoc+derivingThingErr' newtype_deriving clas tys ty strat_used strat_msg why+ = sep [(hang (text "Can't make a derived instance of")+ 2 (quotes (ppr pred) <+> via_mechanism)+ $$ nest 2 extra) <> colon,+ nest 2 why]+ where+ extra | not strat_used, newtype_deriving+ = text "(even with cunning GeneralizedNewtypeDeriving)"+ | otherwise = empty+ pred = mkClassPred clas (tys ++ [ty])+ 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) <+> ptext (sLit "are not all in scope"))+ 2 (text "so you cannot derive an instance for it")++standaloneCtxt :: LHsSigType Name -> SDoc+standaloneCtxt ty = hang (text "In the stand-alone deriving instance for")+ 2 (quotes (ppr ty))++unboxedTyConErr :: String -> MsgDoc+unboxedTyConErr thing =+ text "The last argument of the instance cannot be an unboxed" <+> text thing
+ typecheck/TcDerivInfer.hs view
@@ -0,0 +1,876 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Functions for inferring (and simplifying) the context for derived instances.+-}++{-# LANGUAGE CPP #-}++module TcDerivInfer (inferConstraints, simplifyInstanceContexts) where++#include "HsVersions.h"++import Bag+import BasicTypes+import Class+import DataCon+-- import DynFlags+import ErrUtils+import Inst+import Outputable+import PrelNames+import TcDerivUtils+import TcEnv+-- import TcErrors (reportAllUnsolved)+import TcGenFunctor+import TcGenGenerics+import TcMType+import TcRnMonad+import TcType+import TyCon+import Type+import TcSimplify+import TcValidity (validDerivPred)+import TcUnify (buildImplicationFor)+import Unify (tcUnifyTy)+import Util+import Var+import VarEnv+import VarSet++import Control.Monad+import Data.List+import Data.Maybe++----------------------++inferConstraints :: [TyVar] -> Class -> [TcType] -> TcType+ -> TyCon -> [TcType] -> DerivSpecMechanism+ -> TcM ([ThetaOrigin], [TyVar], [TcType])+-- inferConstraints figures out the constraints needed for the+-- instance declaration generated by a 'deriving' clause on a+-- data type declaration. It also returns the new in-scope type+-- variables and instance types, in case they were changed due to+-- the presence of functor-like constraints.+-- See Note [Inferring the instance context]++-- e.g. inferConstraints+-- C Int (T [a]) -- Class and inst_tys+-- :RTList a -- Rep tycon and its arg tys+-- where T [a] ~R :RTList a+--+-- Generate a sufficiently large set of constraints that typechecking the+-- generated method definitions should succeed. This set will be simplified+-- before being used in the instance declaration+inferConstraints tvs main_cls cls_tys inst_ty+ rep_tc rep_tc_args+ mechanism+ | is_generic && not is_anyclass -- Generic constraints are easy+ = return ([], tvs, inst_tys)++ | is_generic1 && not is_anyclass -- Generic1 needs Functor+ = ASSERT( length rep_tc_tvs > 0 ) -- See Note [Getting base classes]+ ASSERT( length cls_tys == 1 ) -- Generic1 has a single kind variable+ do { functorClass <- tcLookupClass functorClassName+ ; con_arg_constraints (get_gen1_constraints functorClass) }++ | otherwise -- The others are a bit more complicated+ = -- See the comment with all_rep_tc_args for an explanation of+ -- this assertion+ ASSERT2( equalLength rep_tc_tvs all_rep_tc_args+ , ppr main_cls <+> ppr rep_tc+ $$ ppr rep_tc_tvs $$ ppr all_rep_tc_args )+ do { (arg_constraints, tvs', inst_tys') <- infer_constraints+ ; traceTc "inferConstraints" $ vcat+ [ ppr main_cls <+> ppr inst_tys'+ , ppr arg_constraints+ ]+ ; return (stupid_constraints ++ extra_constraints+ ++ sc_constraints ++ arg_constraints+ , tvs', inst_tys') }+ where+ is_anyclass = isDerivSpecAnyClass mechanism+ infer_constraints+ | is_anyclass = inferConstraintsDAC main_cls tvs inst_tys+ | otherwise = con_arg_constraints get_std_constrained_tys++ tc_binders = tyConBinders rep_tc+ choose_level bndr+ | isNamedTyConBinder bndr = KindLevel+ | otherwise = TypeLevel+ t_or_ks = map choose_level tc_binders ++ repeat TypeLevel+ -- want to report *kind* errors when possible++ -- Constraints arising from the arguments of each constructor+ con_arg_constraints :: (CtOrigin -> TypeOrKind+ -> Type+ -> [([PredOrigin], Maybe TCvSubst)])+ -> TcM ([ThetaOrigin], [TyVar], [TcType])+ con_arg_constraints get_arg_constraints+ = let (predss, mbSubsts) = unzip+ [ preds_and_mbSubst+ | data_con <- tyConDataCons rep_tc+ , (arg_n, arg_t_or_k, arg_ty)+ <- zip3 [1..] t_or_ks $+ dataConInstOrigArgTys data_con all_rep_tc_args+ -- No constraints for unlifted types+ -- See Note [Deriving and unboxed types]+ , not (isUnliftedType arg_ty)+ , let orig = DerivOriginDC data_con arg_n+ , preds_and_mbSubst <- get_arg_constraints orig arg_t_or_k arg_ty+ ]+ preds = concat predss+ -- If the constraints require a subtype to be of kind (* -> *)+ -- (which is the case for functor-like constraints), then we+ -- explicitly unify the subtype's kinds with (* -> *).+ -- See Note [Inferring the instance context]+ subst = foldl' composeTCvSubst+ emptyTCvSubst (catMaybes mbSubsts)+ unmapped_tvs = filter (\v -> v `notElemTCvSubst` subst+ && not (v `isInScope` subst)) tvs+ (subst', _) = mapAccumL substTyVarBndr subst unmapped_tvs+ preds' = map (substPredOrigin subst') preds+ inst_tys' = substTys subst' inst_tys+ tvs' = tyCoVarsOfTypesWellScoped inst_tys'+ in return ([mkThetaOriginFromPreds preds'], tvs', inst_tys')++ is_generic = main_cls `hasKey` genClassKey+ is_generic1 = main_cls `hasKey` gen1ClassKey+ -- is_functor_like: see Note [Inferring the instance context]+ is_functor_like = typeKind inst_ty `tcEqKind` typeToTypeKind+ || is_generic1++ get_gen1_constraints :: Class -> CtOrigin -> TypeOrKind -> Type+ -> [([PredOrigin], Maybe TCvSubst)]+ get_gen1_constraints functor_cls orig t_or_k ty+ = mk_functor_like_constraints orig t_or_k functor_cls $+ get_gen1_constrained_tys last_tv ty++ get_std_constrained_tys :: CtOrigin -> TypeOrKind -> Type+ -> [([PredOrigin], Maybe TCvSubst)]+ get_std_constrained_tys orig t_or_k ty+ | is_functor_like = mk_functor_like_constraints orig t_or_k main_cls $+ deepSubtypesContaining last_tv ty+ | otherwise = [( [mk_cls_pred orig t_or_k main_cls ty]+ , Nothing )]++ mk_functor_like_constraints :: CtOrigin -> TypeOrKind+ -> Class -> [Type]+ -> [([PredOrigin], Maybe TCvSubst)]+ -- 'cls' is usually main_cls (Functor or Traversable etc), but if+ -- main_cls = Generic1, then 'cls' can be Functor; see get_gen1_constraints+ --+ -- For each type, generate two constraints, [cls ty, kind(ty) ~ (*->*)],+ -- and a kind substitution that results from unifying kind(ty) with * -> *.+ -- If the unification is successful, it will ensure that the resulting+ -- instance is well kinded. If not, the second constraint will result+ -- in an error message which points out the kind mismatch.+ -- See Note [Inferring the instance context]+ mk_functor_like_constraints orig t_or_k cls+ = map $ \ty -> let ki = typeKind ty in+ ( [ mk_cls_pred orig t_or_k cls ty+ , mkPredOrigin orig KindLevel+ (mkPrimEqPred ki typeToTypeKind) ]+ , tcUnifyTy ki typeToTypeKind+ )++ rep_tc_tvs = tyConTyVars rep_tc+ last_tv = last rep_tc_tvs+ -- When we first gather up the constraints to solve, most of them contain+ -- rep_tc_tvs, i.e., the type variables from the derived datatype's type+ -- constructor. We don't want these type variables to appear in the final+ -- instance declaration, so we must substitute each type variable with its+ -- counterpart in the derived instance. rep_tc_args lists each of these+ -- counterpart types in the same order as the type variables.+ all_rep_tc_args = rep_tc_args ++ map mkTyVarTy+ (drop (length rep_tc_args) rep_tc_tvs)++ -- Constraints arising from superclasses+ -- See Note [Superclasses of derived instance]+ cls_tvs = classTyVars main_cls+ inst_tys = cls_tys ++ [inst_ty]+ sc_constraints = ASSERT2( equalLength cls_tvs inst_tys, ppr main_cls <+> ppr rep_tc)+ [ mkThetaOrigin DerivOrigin TypeLevel [] [] $+ substTheta cls_subst (classSCTheta main_cls) ]+ cls_subst = ASSERT( equalLength cls_tvs inst_tys )+ zipTvSubst cls_tvs inst_tys++ -- Stupid constraints+ stupid_constraints = [ mkThetaOrigin DerivOrigin TypeLevel [] [] $+ substTheta tc_subst (tyConStupidTheta rep_tc) ]+ tc_subst = -- See the comment with all_rep_tc_args for an explanation of+ -- this assertion+ ASSERT( equalLength rep_tc_tvs all_rep_tc_args )+ zipTvSubst rep_tc_tvs all_rep_tc_args++ -- Extra Data constraints+ -- The Data class (only) requires that for+ -- instance (...) => Data (T t1 t2)+ -- IF t1:*, t2:*+ -- THEN (Data t1, Data t2) are among the (...) constraints+ -- Reason: when the IF holds, we generate a method+ -- dataCast2 f = gcast2 f+ -- and we need the Data constraints to typecheck the method+ extra_constraints = [mkThetaOriginFromPreds constrs]+ where+ constrs+ | main_cls `hasKey` dataClassKey+ , all (isLiftedTypeKind . typeKind) rep_tc_args+ = [ mk_cls_pred DerivOrigin t_or_k main_cls ty+ | (t_or_k, ty) <- zip t_or_ks rep_tc_args]+ | otherwise+ = []++ mk_cls_pred orig t_or_k cls ty -- Don't forget to apply to cls_tys' too+ = mkPredOrigin orig t_or_k (mkClassPred cls (cls_tys' ++ [ty]))+ cls_tys' | is_generic1 = [] -- In the awkward Generic1 case, cls_tys'+ -- should be empty, since we are applying the+ -- class Functor.+ | otherwise = cls_tys++typeToTypeKind :: Kind+typeToTypeKind = liftedTypeKind `mkFunTy` liftedTypeKind++-- | Like 'inferConstraints', but used only in the case of @DeriveAnyClass@,+-- which gathers its constraints based on the type signatures of the class's+-- methods instead of the types of the data constructor's field.+--+-- See Note [Gathering and simplifying constraints for DeriveAnyClass]+-- for an explanation of how these constraints are used to determine the+-- derived instance context.+inferConstraintsDAC :: Class -> [TyVar] -> [TcType]+ -> TcM ([ThetaOrigin], [TyVar], [TcType])+inferConstraintsDAC cls tvs inst_tys+ = do { let gen_dms = [ (sel_id, dm_ty)+ | (sel_id, Just (_, GenericDM dm_ty)) <- classOpItems cls ]++ ; theta_origins <- pushTcLevelM_ (mapM do_one_meth gen_dms)+ -- Yuk: the pushTcLevel is to match the one wrapping the call+ -- to mk_wanteds in simplifyDeriv. If we omit this, the+ -- unification variables will wrongly be untouchable.++ ; return (theta_origins, tvs, inst_tys) }+ where+ cls_tvs = classTyVars cls+ empty_subst = mkEmptyTCvSubst (mkInScopeSet (mkVarSet tvs))++ do_one_meth :: (Id, Type) -> TcM ThetaOrigin+ -- (Id,Type) are the selector Id and the generic default method type+ -- NB: the latter is /not/ quantified over the class variables+ -- See Note [Gathering and simplifying constraints for DeriveAnyClass]+ do_one_meth (sel_id, gen_dm_ty)+ = do { let (sel_tvs, _cls_pred, meth_ty) = tcSplitMethodTy (varType sel_id)+ meth_ty' = substTyWith sel_tvs inst_tys meth_ty+ (meth_tvs, meth_theta, meth_tau) = tcSplitNestedSigmaTys meth_ty'++ gen_dm_ty' = substTyWith cls_tvs inst_tys gen_dm_ty+ (dm_tvs, dm_theta, dm_tau) = tcSplitNestedSigmaTys gen_dm_ty'++ ; (subst, _meta_tvs) <- pushTcLevelM_ $+ newMetaTyVarsX empty_subst dm_tvs+ -- Yuk: the pushTcLevel is to match the one in mk_wanteds+ -- simplifyDeriv. If we don't, the unification variables+ -- will bogusly be untouchable.+ ; let dm_theta' = substTheta subst dm_theta+ tau_eq = mkPrimEqPred meth_tau (substTy subst dm_tau)+ ; return (mkThetaOrigin DerivOrigin TypeLevel+ meth_tvs meth_theta (tau_eq:dm_theta')) }++{- Note [Inferring the instance context]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There are two sorts of 'deriving':++ * InferTheta: the deriving clause for a data type+ data T a = T1 a deriving( Eq )+ Here we must infer an instance context,+ and generate instance declaration+ instance Eq a => Eq (T a) where ...++ * CheckTheta: standalone deriving+ deriving instance Eq a => Eq (T a)+ Here we only need to fill in the bindings;+ the instance context is user-supplied++For a deriving clause (InferTheta) we must figure out the+instance context (inferConstraints). Suppose we are inferring+the instance context for+ C t1 .. tn (T s1 .. sm)+There are two cases++ * (T s1 .. sm) :: * (the normal case)+ Then we behave like Eq and guess (C t1 .. tn t)+ for each data constructor arg of type t. More+ details below.++ * (T s1 .. sm) :: * -> * (the functor-like case)+ Then we behave like Functor.++In both cases we produce a bunch of un-simplified constraints+and them simplify them in simplifyInstanceContexts; see+Note [Simplifying the instance context].++In the functor-like case, we may need to unify some kind variables with * in+order for the generated instance to be well-kinded. An example from+Trac #10524:++ newtype Compose (f :: k2 -> *) (g :: k1 -> k2) (a :: k1)+ = Compose (f (g a)) deriving Functor++Earlier in the deriving pipeline, GHC unifies the kind of Compose f g+(k1 -> *) with the kind of Functor's argument (* -> *), so k1 := *. But this+alone isn't enough, since k2 wasn't unified with *:++ instance (Functor (f :: k2 -> *), Functor (g :: * -> k2)) =>+ Functor (Compose f g) where ...++The two Functor constraints are ill-kinded. To ensure this doesn't happen, we:++ 1. Collect all of a datatype's subtypes which require functor-like+ constraints.+ 2. For each subtype, create a substitution by unifying the subtype's kind+ with (* -> *).+ 3. Compose all the substitutions into one, then apply that substitution to+ all of the in-scope type variables and the instance types.++Note [Getting base classes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Functor and Typeable are defined in package 'base', and that is not available+when compiling 'ghc-prim'. So we must be careful that 'deriving' for stuff in+ghc-prim does not use Functor or Typeable implicitly via these lookups.++Note [Deriving and unboxed types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We have some special hacks to support things like+ data T = MkT Int# deriving ( Show )++Specifically, we use TcGenDeriv.box to box the Int# into an Int+(which we know how to show), and append a '#'. Parenthesis are not required+for unboxed values (`MkT -3#` is a valid expression).++Note [Superclasses of derived instance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general, a derived instance decl needs the superclasses of the derived+class too. So if we have+ data T a = ...deriving( Ord )+then the initial context for Ord (T a) should include Eq (T a). Often this is+redundant; we'll also generate an Ord constraint for each constructor argument,+and that will probably generate enough constraints to make the Eq (T a) constraint+be satisfied too. But not always; consider:++ data S a = S+ instance Eq (S a)+ instance Ord (S a)++ data T a = MkT (S a) deriving( Ord )+ instance Num a => Eq (T a)++The derived instance for (Ord (T a)) must have a (Num a) constraint!+Similarly consider:+ data T a = MkT deriving( Data )+Here there *is* no argument field, but we must nevertheless generate+a context for the Data instances:+ instance Typeable a => Data (T a) where ...+++************************************************************************+* *+ Finding the fixed point of deriving equations+* *+************************************************************************++Note [Simplifying the instance context]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ data T a b = C1 (Foo a) (Bar b)+ | C2 Int (T b a)+ | C3 (T a a)+ deriving (Eq)++We want to come up with an instance declaration of the form++ instance (Ping a, Pong b, ...) => Eq (T a b) where+ x == y = ...++It is pretty easy, albeit tedious, to fill in the code "...". The+trick is to figure out what the context for the instance decl is,+namely Ping, Pong and friends.++Let's call the context reqd for the T instance of class C at types+(a,b, ...) C (T a b). Thus:++ Eq (T a b) = (Ping a, Pong b, ...)++Now we can get a (recursive) equation from the data decl. This part+is done by inferConstraints.++ Eq (T a b) = Eq (Foo a) u Eq (Bar b) -- From C1+ u Eq (T b a) u Eq Int -- From C2+ u Eq (T a a) -- From C3+++Foo and Bar may have explicit instances for Eq, in which case we can+just substitute for them. Alternatively, either or both may have+their Eq instances given by deriving clauses, in which case they+form part of the system of equations.++Now all we need do is simplify and solve the equations, iterating to+find the least fixpoint. This is done by simplifyInstanceConstraints.+Notice that the order of the arguments can+switch around, as here in the recursive calls to T.++Let's suppose Eq (Foo a) = Eq a, and Eq (Bar b) = Ping b.++We start with:++ Eq (T a b) = {} -- The empty set++Next iteration:+ Eq (T a b) = Eq (Foo a) u Eq (Bar b) -- From C1+ u Eq (T b a) u Eq Int -- From C2+ u Eq (T a a) -- From C3++ After simplification:+ = Eq a u Ping b u {} u {} u {}+ = Eq a u Ping b++Next iteration:++ Eq (T a b) = Eq (Foo a) u Eq (Bar b) -- From C1+ u Eq (T b a) u Eq Int -- From C2+ u Eq (T a a) -- From C3++ After simplification:+ = Eq a u Ping b+ u (Eq b u Ping a)+ u (Eq a u Ping a)++ = Eq a u Ping b u Eq b u Ping a++The next iteration gives the same result, so this is the fixpoint. We+need to make a canonical form of the RHS to ensure convergence. We do+this by simplifying the RHS to a form in which++ - the classes constrain only tyvars+ - the list is sorted by tyvar (major key) and then class (minor key)+ - no duplicates, of course++Note [Deterministic simplifyInstanceContexts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Canonicalisation uses nonDetCmpType which is nondeterministic. Sorting+with nonDetCmpType puts the returned lists in a nondeterministic order.+If we were to return them, we'd get class constraints in+nondeterministic order.++Consider:++ data ADT a b = Z a b deriving Eq++The generated code could be either:++ instance (Eq a, Eq b) => Eq (Z a b) where++Or:++ instance (Eq b, Eq a) => Eq (Z a b) where++To prevent the order from being nondeterministic we only+canonicalize when comparing and return them in the same order as+simplifyDeriv returned them.+See also Note [nonDetCmpType nondeterminism]+-}+++simplifyInstanceContexts :: [DerivSpec [ThetaOrigin]]+ -> TcM [DerivSpec ThetaType]+-- Used only for deriving clauses (InferTheta)+-- not for standalone deriving+-- See Note [Simplifying the instance context]++simplifyInstanceContexts [] = return []++simplifyInstanceContexts infer_specs+ = do { traceTc "simplifyInstanceContexts" $ vcat (map pprDerivSpec infer_specs)+ ; iterate_deriv 1 initial_solutions }+ where+ ------------------------------------------------------------------+ -- The initial solutions for the equations claim that each+ -- instance has an empty context; this solution is certainly+ -- in canonical form.+ initial_solutions :: [ThetaType]+ initial_solutions = [ [] | _ <- infer_specs ]++ ------------------------------------------------------------------+ -- iterate_deriv calculates the next batch of solutions,+ -- compares it with the current one; finishes if they are the+ -- same, otherwise recurses with the new solutions.+ -- It fails if any iteration fails+ iterate_deriv :: Int -> [ThetaType] -> TcM [DerivSpec ThetaType]+ iterate_deriv n current_solns+ | n > 20 -- Looks as if we are in an infinite loop+ -- This can happen if we have -XUndecidableInstances+ -- (See TcSimplify.tcSimplifyDeriv.)+ = pprPanic "solveDerivEqns: probable loop"+ (vcat (map pprDerivSpec infer_specs) $$ ppr current_solns)+ | otherwise+ = do { -- Extend the inst info from the explicit instance decls+ -- with the current set of solutions, and simplify each RHS+ inst_specs <- zipWithM newDerivClsInst current_solns infer_specs+ ; new_solns <- checkNoErrs $+ extendLocalInstEnv inst_specs $+ mapM gen_soln infer_specs++ ; if (current_solns `eqSolution` new_solns) then+ return [ spec { ds_theta = soln }+ | (spec, soln) <- zip infer_specs current_solns ]+ else+ iterate_deriv (n+1) new_solns }++ eqSolution a b = eqListBy (eqListBy eqType) (canSolution a) (canSolution b)+ -- Canonicalise for comparison+ -- See Note [Deterministic simplifyInstanceContexts]+ canSolution = map (sortBy nonDetCmpType)+ ------------------------------------------------------------------+ gen_soln :: DerivSpec [ThetaOrigin] -> TcM ThetaType+ gen_soln (DS { ds_loc = loc, ds_tvs = tyvars+ , ds_cls = clas, ds_tys = inst_tys, ds_theta = deriv_rhs })+ = setSrcSpan loc $+ addErrCtxt (derivInstCtxt the_pred) $+ do { theta <- simplifyDeriv the_pred tyvars deriv_rhs+ -- checkValidInstance tyvars theta clas inst_tys+ -- Not necessary; see Note [Exotic derived instance contexts]++ ; traceTc "TcDeriv" (ppr deriv_rhs $$ ppr theta)+ -- Claim: the result instance declaration is guaranteed valid+ -- Hence no need to call:+ -- checkValidInstance tyvars theta clas inst_tys+ ; return theta }+ where+ the_pred = mkClassPred clas inst_tys++derivInstCtxt :: PredType -> MsgDoc+derivInstCtxt pred+ = text "When deriving the instance for" <+> parens (ppr pred)++{-+***********************************************************************************+* *+* Simplify derived constraints+* *+***********************************************************************************+-}++-- | Given @instance (wanted) => C inst_ty@, simplify 'wanted' as much+-- as possible. Fail if not possible.+simplifyDeriv :: PredType -- ^ @C inst_ty@, head of the instance we are+ -- deriving. Only used for SkolemInfo.+ -> [TyVar] -- ^ The tyvars bound by @inst_ty@.+ -> [ThetaOrigin] -- ^ Given and wanted constraints+ -> TcM ThetaType -- ^ Needed constraints (after simplification),+ -- i.e. @['PredType']@.+simplifyDeriv pred tvs thetas+ = do { (skol_subst, tvs_skols) <- tcInstSkolTyVars tvs -- Skolemize+ -- The constraint solving machinery+ -- expects *TcTyVars* not TyVars.+ -- We use *non-overlappable* (vanilla) skolems+ -- See Note [Overlap and deriving]++ ; let skol_set = mkVarSet tvs_skols+ skol_info = DerivSkol pred+ doc = text "deriving" <+> parens (ppr pred)++ mk_given_ev :: PredType -> TcM EvVar+ mk_given_ev given =+ let given_pred = substTy skol_subst given+ in newEvVar given_pred++ mk_wanted_ct :: PredOrigin -> TcM CtEvidence+ mk_wanted_ct (PredOrigin wanted o t_or_k)+ = newWanted o (Just t_or_k) (substTyUnchecked skol_subst wanted)++ -- Create the implications we need to solve. For stock and newtype+ -- deriving, these implication constraints will be simple class+ -- constraints like (C a, Ord b).+ -- But with DeriveAnyClass, we make an implication constraint.+ -- See Note [Gathering and simplifying constraints for DeriveAnyClass]+ mk_wanteds :: ThetaOrigin -> TcM WantedConstraints+ mk_wanteds (ThetaOrigin { to_tvs = local_skols+ , to_givens = givens+ , to_wanted_origins = wanteds })+ | null local_skols, null givens+ = do { wanted_cts <- mapM mk_wanted_ct wanteds+ ; return (mkSimpleWC wanted_cts) }+ | otherwise+ = do { given_evs <- mapM mk_given_ev givens+ ; (wanted_cts, tclvl) <- pushTcLevelM $+ mapM mk_wanted_ct wanteds+ ; (implic, _) <- buildImplicationFor tclvl skol_info local_skols+ given_evs (mkSimpleWC wanted_cts)+ ; pure (mkImplicWC implic) }++ -- See [STEP DAC BUILD]+ -- Generate the implication constraints constraints to solve with the+ -- skolemized variables+ ; (wanteds, tclvl) <- pushTcLevelM $ mapM mk_wanteds thetas++ ; traceTc "simplifyDeriv inputs" $+ vcat [ pprTyVars tvs $$ ppr thetas $$ ppr wanteds, doc ]++ -- See [STEP DAC SOLVE]+ -- Simplify the constraints+ ; solved_implics <- runTcSDeriveds $ solveWantedsAndDrop+ $ unionsWC wanteds++ -- See [STEP DAC HOIST]+ -- Split the resulting constraints into bad and good constraints,+ -- building an @unsolved :: WantedConstraints@ representing all+ -- the constraints we can't just shunt to the predicates.+ -- See Note [Exotic derived instance contexts]+ ; let residual_simple = approximateWC True solved_implics+ (bad, good) = partitionBagWith get_good residual_simple++ get_good :: Ct -> Either Ct PredType+ get_good ct | validDerivPred skol_set p+ , isWantedCt ct+ = Right p+ -- TODO: This is wrong+ -- NB re 'isWantedCt': residual_wanted may contain+ -- unsolved CtDerived and we stick them into the+ -- bad set so that reportUnsolved may decide what+ -- to do with them+ | otherwise+ = Left ct+ where p = ctPred ct++ ; traceTc "simplifyDeriv outputs" $+ vcat [ ppr tvs_skols, ppr residual_simple, ppr good, ppr bad ]++ -- Return the good unsolved constraints (unskolemizing on the way out.)+ ; let min_theta = mkMinimalBySCs (bagToList good)+ -- An important property of mkMinimalBySCs (used above) is that in+ -- addition to removing constraints that are made redundant by+ -- superclass relationships, it also removes _duplicate_+ -- constraints.+ -- See Note [Gathering and simplifying constraints for+ -- DeriveAnyClass]+ subst_skol = zipTvSubst tvs_skols $ mkTyVarTys tvs+ -- The reverse substitution (sigh)++ -- See [STEP DAC RESIDUAL]+ ; min_theta_vars <- mapM newEvVar min_theta+ ; (leftover_implic, _) <- buildImplicationFor tclvl skol_info tvs_skols+ min_theta_vars solved_implics+ -- This call to simplifyTop is purely for error reporting+ -- See Note [Error reporting for deriving clauses]+ -- See also Note [Exotic derived instance contexts], which are caught+ -- in this line of code.+ ; simplifyTopImplic leftover_implic++ ; return (substTheta subst_skol min_theta) }++{-+Note [Overlap and deriving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider some overlapping instances:+ data Show a => Show [a] where ..+ data Show [Char] where ...++Now a data type with deriving:+ data T a = MkT [a] deriving( Show )++We want to get the derived instance+ instance Show [a] => Show (T a) where...+and NOT+ instance Show a => Show (T a) where...+so that the (Show (T Char)) instance does the Right Thing++It's very like the situation when we're inferring the type+of a function+ f x = show [x]+and we want to infer+ f :: Show [a] => a -> String++BOTTOM LINE: use vanilla, non-overlappable skolems when inferring+ the context for the derived instance.+ Hence tcInstSkolTyVars not tcInstSuperSkolTyVars++Note [Gathering and simplifying constraints for DeriveAnyClass]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+DeriveAnyClass works quite differently from stock and newtype deriving in+the way it gathers and simplifies constraints to be used in a derived+instance's context. Stock and newtype deriving gather constraints by looking+at the data constructors of the data type for which we are deriving an+instance. But DeriveAnyClass doesn't need to know about a data type's+definition at all!++To see why, consider this example of DeriveAnyClass:++ class Foo a where+ bar :: forall b. Ix b => a -> b -> String+ default bar :: (Show a, Ix c) => a -> c -> String+ bar x y = show x ++ show (range (y,y))++ baz :: Eq a => a -> a -> Bool+ default baz :: (Ord a, Show a) => a -> a -> Bool+ baz x y = compare x y == EQ++Because 'bar' and 'baz' have default signatures, this generates a top-level+definition for these generic default methods++ $gdm_bar :: forall a. Foo a+ => forall c. (Show a, Ix c)+ => a -> c -> String+ $gdm_bar x y = show x ++ show (range (y,y))++(and similarly for baz). Now consider a 'deriving' clause+ data Maybe s = ... deriving Foo++This derives an instance of the form:+ instance (CX) => Foo (Maybe s) where+ bar = $gdm_bar+ baz = $gdm_baz++Now it is GHC's job to fill in a suitable instance context (CX). If+GHC were typechecking the binding+ bar = $gdm bar+it would+ * skolemise the expected type of bar+ * instantiate the type of $dm_bar with meta-type variables+ * build an implication constraint++[STEP DAC BUILD]+So that's what we do. We build the constraint (call it C1)++ forall b. Ix b => (Show (Maybe s), Ix cc,+ Maybe s -> b -> String+ ~ Maybe s -> cc -> String)++The 'cc' is a unification variable that comes from instantiating+$dm_bar's type. The equality constraint comes from marrying up+the instantiated type of $dm_bar with the specified type of bar.+Notice that the type variables from the instance, 's' in this case,+are global to this constraint.++Similarly for 'baz', givng the constraint C2++ forall. Eq (Maybe s) => (Ord a, Show a,+ Maybe s -> Maybe s -> Bool+ ~ Maybe s -> Maybe s -> Bool)++In this case baz has no local quantification, so the implication+constraint has no local skolems and there are no unificaiton+variables.++[STEP DAC SOLVE]+We can combine these two implication constraints into a single+constraint (C1, C2), and simplify, unifying cc:=b, to get:++ forall b. Ix b => Show a+ /\+ forall. Eq (Maybe s) => (Ord a, Show a)++[STEP DAC HOIST]+Let's call that (C1', C2'). Now we need to hoist the unsolved+constraints out of the implications to become our candidate for+(CX). That is done by approximateWC, which will return:++ (Show a, Ord a, Show a)++Now we can use mkMinimalBySCs to remove superclasses and duplicates, giving++ (Show a, Ord a)++And that's what GHC uses for CX.++[STEP DAC RESIDUAL]+In this case we have solved all the leftover constraints, but what if+we don't? Simple! We just form the final residual constraint++ forall s. CX => (C1',C2')++and simplify that. In simple cases it'll succeed easily, because CX+literally contains the constraints in C1', C2', but if there is anything+more complicated it will be reported in a civilised way.++Note [Error reporting for deriving clauses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A suprisingly tricky aspect of deriving to get right is reporting sensible+error messages. In particular, if simplifyDeriv reaches a constraint that it+cannot solve, which might include:++1. Insoluble constraints+2. "Exotic" constraints (See Note [Exotic derived instance contexts])++Then we report an error immediately in simplifyDeriv.++Another possible choice is to punt and let another part of the typechecker+(e.g., simplifyInstanceContexts) catch the errors. But this tends to lead+to worse error messages, so we do it directly in simplifyDeriv.++simplifyDeriv checks for errors in a clever way. If the deriving machinery+infers the context (Foo a)--that is, if this instance is to be generated:++ instance Foo a => ...++Then we form an implication of the form:++ forall a. Foo a => <residual_wanted_constraints>++And pass it to the simplifier. If the context (Foo a) is enough to discharge+all the constraints in <residual_wanted_constraints>, then everything is+hunky-dory. But if <residual_wanted_constraints> contains, say, an insoluble+constraint, then (Foo a) won't be able to solve it, causing GHC to error.++Note [Exotic derived instance contexts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a 'derived' instance declaration, we *infer* the context. It's a+bit unclear what rules we should apply for this; the Haskell report is+silent. Obviously, constraints like (Eq a) are fine, but what about+ data T f a = MkT (f a) deriving( Eq )+where we'd get an Eq (f a) constraint. That's probably fine too.++One could go further: consider+ data T a b c = MkT (Foo a b c) deriving( Eq )+ instance (C Int a, Eq b, Eq c) => Eq (Foo a b c)++Notice that this instance (just) satisfies the Paterson termination+conditions. Then we *could* derive an instance decl like this:++ instance (C Int a, Eq b, Eq c) => Eq (T a b c)+even though there is no instance for (C Int a), because there just+*might* be an instance for, say, (C Int Bool) at a site where we+need the equality instance for T's.++However, this seems pretty exotic, and it's quite tricky to allow+this, and yet give sensible error messages in the (much more common)+case where we really want that instance decl for C.++So for now we simply require that the derived instance context+should have only type-variable constraints.++Here is another example:+ data Fix f = In (f (Fix f)) deriving( Eq )+Here, if we are prepared to allow -XUndecidableInstances we+could derive the instance+ instance Eq (f (Fix f)) => Eq (Fix f)+but this is so delicate that I don't think it should happen inside+'deriving'. If you want this, write it yourself!++NB: if you want to lift this condition, make sure you still meet the+termination conditions! If not, the deriving mechanism generates+larger and larger constraints. Example:+ data Succ a = S a+ data Seq a = Cons a (Seq (Succ a)) | Nil deriving Show++Note the lack of a Show instance for Succ. First we'll generate+ instance (Show (Succ a), Show a) => Show (Seq a)+and then+ instance (Show (Succ (Succ a)), Show (Succ a), Show a) => Show (Seq a)+and so on. Instead we want to complain of no instance for (Show (Succ a)).++The bottom line+~~~~~~~~~~~~~~~+Allow constraints which consist only of type variables, with no repeats.+-}
+ typecheck/TcDerivUtils.hs view
@@ -0,0 +1,669 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Error-checking and other utilities for @deriving@ clauses or declarations.+-}++{-# LANGUAGE ImplicitParams #-}++module TcDerivUtils (+ DerivSpec(..), pprDerivSpec,+ DerivSpecMechanism(..), isDerivSpecStock,+ isDerivSpecNewtype, isDerivSpecAnyClass,+ DerivContext, DerivStatus(..),+ PredOrigin(..), ThetaOrigin(..), mkPredOrigin,+ mkThetaOrigin, mkThetaOriginFromPreds, substPredOrigin,+ checkSideConditions, hasStockDeriving,+ canDeriveAnyClass,+ std_class_via_coercible, non_coercible_class,+ newDerivClsInst, extendLocalInstEnv+ ) where++import Bag+import BasicTypes+import Class+import DataCon+import DynFlags+import ErrUtils+import HscTypes (lookupFixity, mi_fix)+import HsSyn+import Inst+import InstEnv+import LoadIface (loadInterfaceForName)+import Module (getModule)+import Name+import Outputable+import PrelNames+import RdrName+import SrcLoc+import TcGenDeriv+import TcGenFunctor+import TcGenGenerics+import TcRnMonad+import TcType+import THNames (liftClassKey)+import TyCon+import Type+import Util+import VarSet++import qualified GHC.LanguageExtensions as LangExt+import ListSetOps (assocMaybe)++data DerivSpec theta = DS { ds_loc :: SrcSpan+ , ds_name :: Name -- DFun name+ , ds_tvs :: [TyVar]+ , ds_theta :: theta+ , ds_cls :: Class+ , ds_tys :: [Type]+ , ds_tc :: TyCon+ , ds_overlap :: Maybe OverlapMode+ , ds_mechanism :: DerivSpecMechanism }+ -- This spec implies a dfun declaration of the form+ -- df :: forall tvs. theta => C tys+ -- The Name is the name for the DFun we'll build+ -- The tyvars bind all the variables in the theta+ -- For type families, the tycon in+ -- in ds_tys is the *family* tycon+ -- in ds_tc is the *representation* type+ -- For non-family tycons, both are the same++ -- the theta is either the given and final theta, in standalone deriving,+ -- or the not-yet-simplified list of constraints together with their origin++ -- ds_mechanism specifies the means by which GHC derives the instance.+ -- See Note [Deriving strategies] in TcDeriv++{-+Example:++ newtype instance T [a] = MkT (Tree a) deriving( C s )+==>+ axiom T [a] = :RTList a+ axiom :RTList a = Tree a++ DS { ds_tvs = [a,s], ds_cls = C, ds_tys = [s, T [a]]+ , ds_tc = :RTList, ds_mechanism = DerivSpecNewtype (Tree a) }+-}++pprDerivSpec :: Outputable theta => DerivSpec theta -> SDoc+pprDerivSpec (DS { ds_loc = l, ds_name = n, ds_tvs = tvs, ds_cls = c,+ ds_tys = tys, ds_theta = rhs, ds_mechanism = mech })+ = hang (text "DerivSpec")+ 2 (vcat [ text "ds_loc =" <+> ppr l+ , text "ds_name =" <+> ppr n+ , text "ds_tvs =" <+> ppr tvs+ , text "ds_cls =" <+> ppr c+ , text "ds_tys =" <+> ppr tys+ , text "ds_theta =" <+> ppr rhs+ , text "ds_mechanism =" <+> ppr mech ])++instance Outputable theta => Outputable (DerivSpec theta) where+ ppr = pprDerivSpec++-- What action to take in order to derive a class instance.+-- See Note [Deriving strategies] in TcDeriv+-- NB: DerivSpecMechanism is purely local to this module+data DerivSpecMechanism+ = DerivSpecStock -- "Standard" classes+ (SrcSpan -> TyCon -> [Type] -> TcM (LHsBinds RdrName, BagDerivStuff))++ | DerivSpecNewtype -- -XGeneralizedNewtypeDeriving+ Type -- ^ The newtype rep type++ | DerivSpecAnyClass -- -XDeriveAnyClass++isDerivSpecStock, isDerivSpecNewtype, isDerivSpecAnyClass+ :: DerivSpecMechanism -> Bool+isDerivSpecStock (DerivSpecStock{}) = True+isDerivSpecStock _ = False++isDerivSpecNewtype (DerivSpecNewtype{}) = True+isDerivSpecNewtype _ = False++isDerivSpecAnyClass (DerivSpecAnyClass{}) = True+isDerivSpecAnyClass _ = False++-- A DerivSpecMechanism can be losslessly converted to a DerivStrategy.+mechanismToStrategy :: DerivSpecMechanism -> DerivStrategy+mechanismToStrategy (DerivSpecStock{}) = StockStrategy+mechanismToStrategy (DerivSpecNewtype{}) = NewtypeStrategy+mechanismToStrategy (DerivSpecAnyClass{}) = AnyclassStrategy++instance Outputable DerivSpecMechanism where+ ppr = ppr . mechanismToStrategy++type DerivContext = Maybe ThetaType+ -- Nothing <=> Vanilla deriving; infer the context of the instance decl+ -- Just theta <=> Standalone deriving: context supplied by programmer++data DerivStatus = CanDerive -- Stock class, can derive+ | DerivableClassError SDoc -- Stock class, but can't do it+ | DerivableViaInstance -- See Note [Deriving any class]+ | NonDerivableClass SDoc -- Non-stock class++-- 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+-- language extension), such as Eq, Ord, Ix, Data, Generic, etc.++-- | A 'PredType' annotated with the origin of the constraint 'CtOrigin',+-- and whether or the constraint deals in types or kinds.+data PredOrigin = PredOrigin PredType CtOrigin TypeOrKind++-- | A list of wanted 'PredOrigin' constraints ('to_wanted_origins') alongside+-- any corresponding given constraints ('to_givens') and locally quantified+-- type variables ('to_tvs').+--+-- In most cases, 'to_givens' will be empty, as most deriving mechanisms (e.g.,+-- stock and newtype deriving) do not require given constraints. The exception+-- is @DeriveAnyClass@, which can involve given constraints. For example,+-- if you tried to derive an instance for the following class using+-- @DeriveAnyClass@:+--+-- @+-- class Foo a where+-- bar :: a -> b -> String+-- default bar :: (Show a, Ix b) => a -> b -> String+-- bar = show+--+-- baz :: Eq a => a -> a -> Bool+-- default baz :: Ord a => a -> a -> Bool+-- baz x y = compare x y == EQ+-- @+--+-- Then it would generate two 'ThetaOrigin's, one for each method:+--+-- @+-- [ ThetaOrigin { to_tvs = [b]+-- , to_givens = []+-- , to_wanted_origins = [Show a, Ix b] }+-- , ThetaOrigin { to_tvs = []+-- , to_givens = [Eq a]+-- , to_wanted_origins = [Ord a] }+-- ]+-- @+data ThetaOrigin+ = ThetaOrigin { to_tvs :: [TyVar]+ , to_givens :: ThetaType+ , to_wanted_origins :: [PredOrigin] }++instance Outputable PredOrigin where+ ppr (PredOrigin ty _ _) = ppr ty -- The origin is not so interesting when debugging++instance Outputable ThetaOrigin where+ ppr (ThetaOrigin { to_tvs = tvs+ , to_givens = givens+ , to_wanted_origins = wanted_origins })+ = hang (text "ThetaOrigin")+ 2 (vcat [ text "to_tvs =" <+> ppr tvs+ , text "to_givens =" <+> ppr givens+ , text "to_wanted_origins =" <+> ppr wanted_origins ])++mkPredOrigin :: CtOrigin -> TypeOrKind -> PredType -> PredOrigin+mkPredOrigin origin t_or_k pred = PredOrigin pred origin t_or_k++mkThetaOrigin :: CtOrigin -> TypeOrKind -> [TyVar] -> ThetaType -> ThetaType+ -> ThetaOrigin+mkThetaOrigin origin t_or_k tvs givens+ = ThetaOrigin tvs givens . map (mkPredOrigin origin t_or_k)++-- A common case where the ThetaOrigin only contains wanted constraints, with+-- no givens or locally scoped type variables.+mkThetaOriginFromPreds :: [PredOrigin] -> ThetaOrigin+mkThetaOriginFromPreds = ThetaOrigin [] []++substPredOrigin :: HasCallStack => TCvSubst -> PredOrigin -> PredOrigin+substPredOrigin subst (PredOrigin pred origin t_or_k)+ = PredOrigin (substTy subst pred) origin t_or_k++{-+************************************************************************+* *+ Class deriving diagnostics+* *+************************************************************************++Only certain blessed classes can be used in a deriving clause (without the+assistance of GeneralizedNewtypeDeriving or DeriveAnyClass). These classes+are listed below in the definition of hasStockDeriving. The sideConditions+function determines the criteria that needs to be met in order for a particular+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.+-}++hasStockDeriving :: Class+ -> Maybe (SrcSpan+ -> TyCon+ -> [Type]+ -> TcM (LHsBinds RdrName, BagDerivStuff))+hasStockDeriving clas+ = assocMaybe gen_list (getUnique clas)+ where+ gen_list :: [(Unique, SrcSpan+ -> TyCon+ -> [Type]+ -> TcM (LHsBinds RdrName, BagDerivStuff))]+ gen_list = [ (eqClassKey, simpleM gen_Eq_binds)+ , (ordClassKey, simpleM gen_Ord_binds)+ , (enumClassKey, simpleM gen_Enum_binds)+ , (boundedClassKey, simple gen_Bounded_binds)+ , (ixClassKey, simpleM gen_Ix_binds)+ , (showClassKey, with_fix_env gen_Show_binds)+ , (readClassKey, with_fix_env gen_Read_binds)+ , (dataClassKey, simpleM gen_Data_binds)+ , (functorClassKey, simple gen_Functor_binds)+ , (foldableClassKey, simple gen_Foldable_binds)+ , (traversableClassKey, simple gen_Traversable_binds)+ , (liftClassKey, simple gen_Lift_binds)+ , (genClassKey, generic (gen_Generic_binds Gen0))+ , (gen1ClassKey, generic (gen_Generic_binds Gen1)) ]++ simple gen_fn loc tc _+ = return (gen_fn loc tc)++ simpleM gen_fn loc tc _+ = gen_fn loc tc++ with_fix_env gen_fn loc tc _+ = do { fix_env <- getDataConFixityFun tc+ ; return (gen_fn fix_env loc tc) }++ generic gen_fn _ tc inst_tys+ = do { (binds, faminst) <- gen_fn tc inst_tys+ ; return (binds, unitBag (DerivFamInst faminst)) }++getDataConFixityFun :: TyCon -> TcM (Name -> Fixity)+-- If the TyCon is locally defined, we want the local fixity env;+-- but if it is imported (which happens for standalone deriving)+-- we need to get the fixity env from the interface file+-- c.f. RnEnv.lookupFixity, and Trac #9830+getDataConFixityFun tc+ = do { this_mod <- getModule+ ; if nameIsLocalOrFrom this_mod name+ then do { fix_env <- getFixityEnv+ ; return (lookupFixity fix_env) }+ else do { iface <- loadInterfaceForName doc name+ -- Should already be loaded!+ ; return (mi_fix iface . nameOccName) } }+ where+ name = tyConName tc+ doc = text "Data con fixities for" <+> ppr name++------------------------------------------------------------------+-- Check side conditions that dis-allow derivability for particular classes+-- This is *apart* from the newtype-deriving mechanism+--+-- Here we get the representation tycon in case of family instances as it has+-- the data constructors - but we need to be careful to fall back to the+-- family tycon (with indexes) in error messages.++checkSideConditions :: DynFlags -> DerivContext -> Class -> [TcType]+ -> TyCon -- tycon+ -> DerivStatus+checkSideConditions dflags mtheta cls cls_tys rep_tc+ | Just cond <- sideConditions mtheta cls+ = case (cond dflags rep_tc) of+ NotValid err -> DerivableClassError err -- Class-specific error+ IsValid | null (filterOutInvisibleTypes (classTyCon cls) cls_tys)+ -> CanDerive+ -- All stock derivable classes are unary in the sense that+ -- there should be not types in cls_tys (i.e., no type args+ -- other than last). Note that cls_types can contain+ -- invisible types as well (e.g., for Generic1, which is+ -- poly-kinded), so make sure those are not counted.+ | otherwise -> DerivableClassError (classArgsErr cls cls_tys)+ -- e.g. deriving( Eq s )++ | NotValid err <- canDeriveAnyClass dflags+ = NonDerivableClass err -- DeriveAnyClass does not work++ | otherwise+ = DerivableViaInstance -- DeriveAnyClass should work++classArgsErr :: Class -> [Type] -> SDoc+classArgsErr cls cls_tys = quotes (ppr (mkClassPred cls cls_tys)) <+> text "is not a class"++-- 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+-- GeneralizedNewtypeDeriving or DeriveAnyClass). Returns Nothing for a+-- class for which stock deriving isn't possible.+sideConditions :: DerivContext -> Class -> Maybe Condition+sideConditions mtheta cls+ | cls_key == eqClassKey = Just (cond_std `andCond` cond_args cls)+ | cls_key == ordClassKey = Just (cond_std `andCond` cond_args cls)+ | cls_key == showClassKey = Just (cond_std `andCond` cond_args cls)+ | cls_key == readClassKey = Just (cond_std `andCond` cond_args cls)+ | cls_key == enumClassKey = Just (cond_std `andCond` cond_isEnumeration)+ | cls_key == ixClassKey = Just (cond_std `andCond` cond_enumOrProduct cls)+ | cls_key == boundedClassKey = Just (cond_std `andCond` cond_enumOrProduct cls)+ | cls_key == dataClassKey = Just (checkFlag LangExt.DeriveDataTypeable `andCond`+ cond_std `andCond`+ cond_args cls)+ | cls_key == functorClassKey = Just (checkFlag LangExt.DeriveFunctor `andCond`+ cond_vanilla `andCond`+ cond_functorOK True False)+ | cls_key == foldableClassKey = Just (checkFlag LangExt.DeriveFoldable `andCond`+ cond_vanilla `andCond`+ cond_functorOK False True)+ -- Functor/Fold/Trav works ok+ -- for rank-n types+ | cls_key == traversableClassKey = Just (checkFlag LangExt.DeriveTraversable `andCond`+ cond_vanilla `andCond`+ cond_functorOK False False)+ | cls_key == genClassKey = Just (checkFlag LangExt.DeriveGeneric `andCond`+ cond_vanilla `andCond`+ cond_RepresentableOk)+ | cls_key == gen1ClassKey = Just (checkFlag LangExt.DeriveGeneric `andCond`+ cond_vanilla `andCond`+ cond_Representable1Ok)+ | cls_key == liftClassKey = Just (checkFlag LangExt.DeriveLift `andCond`+ cond_vanilla `andCond`+ cond_args cls)+ | otherwise = Nothing+ where+ cls_key = getUnique cls+ cond_std = cond_stdOK mtheta False -- Vanilla data constructors, at least one,+ -- and monotype arguments+ cond_vanilla = cond_stdOK mtheta 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 -> TyCon -> Validity+ -- TyCon is the *representation* tycon if the data type is an indexed one+ -- Nothing => OK++orCond :: Condition -> Condition -> Condition+orCond c1 c2 dflags tc+ = case (c1 dflags tc, c2 dflags tc) of+ (IsValid, _) -> IsValid -- c1 succeeds+ (_, IsValid) -> IsValid -- c21 succeeds+ (NotValid x, NotValid y) -> NotValid (x $$ text " or" $$ y)+ -- Both fail++andCond :: Condition -> Condition -> Condition+andCond c1 c2 dflags tc = c1 dflags tc `andValid` c2 dflags tc++cond_stdOK :: DerivContext -- Says whether this is standalone deriving or not;+ -- if standalone, we just say "yes, go for it"+ -> Bool -- True <=> permissive: allow higher rank+ -- args and no data constructors+ -> Condition+cond_stdOK (Just _) _ _ _+ = IsValid -- Don't check these conservative conditions for+ -- standalone deriving; just generate the code+ -- and let the typechecker handle the result+cond_stdOK Nothing permissive _ rep_tc+ | null data_cons+ , not permissive = NotValid (no_cons_why rep_tc $$ suggestion)+ | not (null con_whys) = NotValid (vcat con_whys $$ suggestion)+ | otherwise = IsValid+ where+ suggestion = text "Possible fix: use a standalone deriving declaration instead"+ data_cons = tyConDataCons rep_tc+ con_whys = getInvalids (map check_con data_cons)++ check_con :: DataCon -> Validity+ check_con con+ | not (null eq_spec)+ = bad "is a GADT"+ | not (null ex_tvs)+ = bad "has existential type variables in its type"+ | not (null theta)+ = bad "has constraints in its type"+ | not (permissive || all isTauTy (dataConOrigArgTys con))+ = bad "has a higher-rank type"+ | otherwise+ = IsValid+ where+ (_, ex_tvs, eq_spec, theta, _, _) = dataConFullSig con+ bad msg = NotValid (badCon con (text msg))++no_cons_why :: TyCon -> SDoc+no_cons_why rep_tc = quotes (pprSourceTyCon rep_tc) <+>+ text "must have at least one data constructor"++cond_RepresentableOk :: Condition+cond_RepresentableOk _ tc = canDoGenerics tc++cond_Representable1Ok :: Condition+cond_Representable1Ok _ tc = canDoGenerics1 tc++cond_enumOrProduct :: Class -> Condition+cond_enumOrProduct cls = cond_isEnumeration `orCond`+ (cond_isProduct `andCond` cond_args cls)++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.+cond_args cls _ 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)))+ where+ bad_args = [ arg_ty | con <- tyConDataCons tc+ , arg_ty <- dataConOrigArgTys con+ , isUnliftedType arg_ty+ , not (ok_ty arg_ty) ]++ cls_key = classKey cls+ ok_ty arg_ty+ | cls_key == eqClassKey = check_in arg_ty ordOpTbl+ | cls_key == ordClassKey = check_in arg_ty ordOpTbl+ | cls_key == showClassKey = check_in arg_ty boxConTbl+ | cls_key == liftClassKey = check_in arg_ty litConTbl+ | otherwise = False -- Read, Ix etc++ check_in :: Type -> [(Type,a)] -> Bool+ check_in arg_ty tbl = any (eqType arg_ty . fst) tbl+++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 TyCon++cond_isProduct :: Condition+cond_isProduct _ rep_tc+ | isProductTyCon rep_tc = IsValid+ | otherwise = NotValid why+ where+ why = quotes (pprSourceTyCon rep_tc) <+>+ text "must have precisely one constructor"++cond_functorOK :: Bool -> Bool -> Condition+-- OK for Functor/Foldable/Traversable class+-- Currently: (a) at least one argument+-- (b) don't use argument contravariantly+-- (c) don't use argument in the wrong place, e.g. data T a = T (X a a)+-- (d) optionally: don't use function types+-- (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")++ | not (null bad_stupid_theta)+ = NotValid (text "Data type" <+> quotes (ppr rep_tc)+ <+> text "must not have a class context:" <+> pprTheta bad_stupid_theta)++ | otherwise+ = allValid (map check_con data_cons)+ where+ tc_tvs = tyConTyVars rep_tc+ Just (_, last_tv) = snocView tc_tvs+ bad_stupid_theta = filter is_bad (tyConStupidTheta rep_tc)+ is_bad pred = last_tv `elemVarSet` tyCoVarsOfType pred++ data_cons = tyConDataCons rep_tc+ check_con con = allValid (check_universal con : foldDataConArgs (ft_check con) con)++ check_universal :: DataCon -> Validity+ check_universal con+ | allowExQuantifiedLastTyVar+ = IsValid -- See Note [DeriveFoldable with ExistentialQuantification]+ -- in TcGenFunctor+ | Just tv <- getTyVar_maybe (last (tyConAppArgs (dataConOrigResTy con)))+ , tv `elem` dataConUnivTyVars con+ , not (tv `elemVarSet` tyCoVarsOfTypes (dataConTheta con))+ = IsValid -- See Note [Check that the type variable is truly universal]+ | otherwise+ = NotValid (badCon con existential)++ ft_check :: DataCon -> FFoldType Validity+ ft_check con = FT { ft_triv = IsValid, ft_var = IsValid+ , ft_co_var = NotValid (badCon con covariant)+ , ft_fun = \x y -> if allowFunctions then x `andValid` y+ else NotValid (badCon con functions)+ , ft_tup = \_ xs -> allValid xs+ , ft_ty_app = \_ x -> x+ , ft_bad_app = NotValid (badCon con wrong_arg)+ , 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+ [s] -> s+ other -> pprPanic "checkFlag" (ppr other)++std_class_via_coercible :: Class -> Bool+-- These standard classes can be derived for a newtype+-- using the coercible trick *even if no -XGeneralizedNewtypeDeriving+-- because giving so gives the same results as generating the boilerplate+std_class_via_coercible clas+ = classKey clas `elem` [eqClassKey, ordClassKey, ixClassKey, boundedClassKey]+ -- Not Read/Show because they respect the type+ -- Not Enum, because newtypes are never in Enum+++non_coercible_class :: Class -> Bool+-- *Never* derive Read, Show, Typeable, Data, Generic, Generic1, Lift+-- by Coercible, even with -XGeneralizedNewtypeDeriving+-- Also, avoid Traversable, as the Coercible-derived instance and the "normal"-derived+-- instance behave differently if there's a non-lawful Applicative out there.+-- Besides, with roles, Coercible-deriving Traversable is ill-roled.+non_coercible_class cls+ = classKey cls `elem` ([ readClassKey, showClassKey, dataClassKey+ , genClassKey, gen1ClassKey, typeableClassKey+ , traversableClassKey, liftClassKey ])++badCon :: DataCon -> SDoc -> SDoc+badCon con msg = text "Constructor" <+> quotes (ppr con) <+> msg++------------------------------------------------------------------++newDerivClsInst :: ThetaType -> DerivSpec theta -> TcM ClsInst+newDerivClsInst theta (DS { ds_name = dfun_name, ds_overlap = overlap_mode+ , ds_tvs = tvs, ds_cls = clas, ds_tys = tys })+ = newClsInst overlap_mode dfun_name tvs theta clas tys++extendLocalInstEnv :: [ClsInst] -> TcM a -> TcM a+-- Add new locally-defined instances; don't bother to check+-- for functional dependency errors -- that'll happen in TcInstDcls+extendLocalInstEnv dfuns thing_inside+ = do { env <- getGblEnv+ ; let inst_env' = extendInstEnvList (tcg_inst_env env) dfuns+ env' = env { tcg_inst_env = inst_env' }+ ; setGblEnv env' thing_inside }++{-+Note [Deriving any class]+~~~~~~~~~~~~~~~~~~~~~~~~~+Classic uses of a deriving clause, or a standalone-deriving declaration, are+for:+ * a stock class like Eq or Show, for which GHC knows how to generate+ the instance code+ * a newtype, via the mechanism enabled by GeneralizedNewtypeDeriving++The DeriveAnyClass extension adds a third way to derive instances, based on+empty instance declarations.++The canonical use case is in combination with GHC.Generics and default method+signatures. These allow us to have instance declarations being empty, but still+useful, e.g.++ data T a = ...blah..blah... deriving( Generic )+ instance C a => C (T a) -- No 'where' clause++where C is some "random" user-defined class.++This boilerplate code can be replaced by the more compact++ data T a = ...blah..blah... deriving( Generic, C )++if DeriveAnyClass is enabled.++This is not restricted to Generics; any class can be derived, simply giving+rise to an empty instance.++Unfortunately, it is not clear how to determine the context (when using a+deriving clause; in standalone deriving, the user provides the context).+GHC uses the same heuristic for figuring out the class context that it uses for+Eq in the case of *-kinded classes, and for Functor in the case of+* -> *-kinded classes. That may not be optimal or even wrong. But in such+cases, standalone deriving can still be used.++Note [Check that the type variable is truly universal]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For Functor and Traversable instances, we must check that the *last argument*+of the type constructor is used truly universally quantified. Example++ data T a b where+ T1 :: a -> b -> T a b -- Fine! Vanilla H-98+ T2 :: b -> c -> T a b -- Fine! Existential c, but we can still map over 'b'+ T3 :: b -> T Int b -- Fine! Constraint 'a', but 'b' is still polymorphic+ T4 :: Ord b => b -> T a b -- No! 'b' is constrained+ T5 :: b -> T b b -- No! 'b' is constrained+ T6 :: T a (b,b) -- No! 'b' is constrained++Notice that only the first of these constructors is vanilla H-98. We only+need to take care about the last argument (b in this case). See Trac #8678.+Eg. for T1-T3 we can write++ fmap f (T1 a b) = T1 a (f b)+ fmap f (T2 b c) = T2 (f b) c+ fmap f (T3 x) = T3 (f x)++We need not perform these checks for Foldable instances, however, since+functions in Foldable can only consume existentially quantified type variables,+rather than produce them (as is the case in Functor and Traversable functions.)+As a result, T can have a derived Foldable instance:++ foldr f z (T1 a b) = f b z+ foldr f z (T2 b c) = f b z+ foldr f z (T3 x) = f x z+ foldr f z (T4 x) = f x z+ foldr f z (T5 x) = f x z+ foldr _ z T6 = z++See Note [DeriveFoldable with ExistentialQuantification] in TcGenFunctor.+-}
+ typecheck/TcEnv.hs view
@@ -0,0 +1,1023 @@+-- (c) The University of Glasgow 2006+{-# LANGUAGE CPP, FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} -- instance MonadThings is necessarily an+ -- orphan+{-# LANGUAGE UndecidableInstances #-} -- Note [Pass sensitive types]+ -- in module PlaceHolder++module TcEnv(+ TyThing(..), TcTyThing(..), TcId,++ -- Instance environment, and InstInfo type+ InstInfo(..), iDFunId, pprInstInfoDetails,+ simpleInstInfoClsTy, simpleInstInfoTy, simpleInstInfoTyCon,+ InstBindings(..),++ -- Global environment+ tcExtendGlobalEnv, tcExtendTyConEnv,+ tcExtendGlobalEnvImplicit, setGlobalTypeEnv,+ tcExtendGlobalValEnv,+ tcLookupLocatedGlobal, tcLookupGlobal,+ tcLookupTyCon, tcLookupClass,+ tcLookupDataCon, tcLookupPatSyn, tcLookupConLike,+ tcLookupLocatedGlobalId, tcLookupLocatedTyCon,+ tcLookupLocatedClass, tcLookupAxiom,+ lookupGlobal,++ -- Local environment+ tcExtendKindEnv, tcExtendKindEnvList,+ tcExtendTyVarEnv, tcExtendTyVarEnv2,+ tcExtendLetEnv, tcExtendSigIds, tcExtendRecIds,+ tcExtendIdEnv, tcExtendIdEnv1, tcExtendIdEnv2,+ tcExtendIdBndrs, tcExtendLocalTypeEnv,+ isTypeClosedLetBndr,++ tcLookup, tcLookupLocated, tcLookupLocalIds,+ tcLookupId, tcLookupTyVar,+ tcLookupLcl_maybe,+ getInLocalScope,+ wrongThingErr, pprBinders,++ tcAddDataFamConPlaceholders, tcAddPatSynPlaceholders,+ getTypeSigNames,+ tcExtendRecEnv, -- For knot-tying++ -- Instances+ tcLookupInstance, tcGetInstEnvs,++ -- Rules+ tcExtendRules,++ -- Defaults+ tcGetDefaultTys,++ -- Global type variables+ tcGetGlobalTyCoVars,++ -- Template Haskell stuff+ checkWellStaged, tcMetaTy, thLevel,+ topIdLvl, isBrackStage,++ -- New Ids+ newDFunName, newDFunName', newFamInstTyConName,+ newFamInstAxiomName,+ mkStableIdFromString, mkStableIdFromName,+ mkWrapperName+ ) where++#include "HsVersions.h"++import HsSyn+import IfaceEnv+import TcRnMonad+import TcMType+import TcType+import LoadIface+import PrelNames+import TysWiredIn+import Id+import Var+import VarSet+import RdrName+import InstEnv+import DataCon ( DataCon )+import PatSyn ( PatSyn )+import ConLike+import TyCon+import CoAxiom+import Class+import Name+import NameSet+import NameEnv+import VarEnv+import HscTypes+import DynFlags+import SrcLoc+import BasicTypes hiding( SuccessFlag(..) )+import Module+import Outputable+import Encoding+import FastString+import ListSetOps+import Util+import Maybes( MaybeErr(..), orElse )+import qualified GHC.LanguageExtensions as LangExt++import Data.IORef+import Data.List+++{- *********************************************************************+* *+ An IO interface to looking up globals+* *+********************************************************************* -}++lookupGlobal :: HscEnv -> Name -> IO TyThing+-- An IO version, used outside the typechecker+-- It's more complicated than it looks, because it may+-- need to suck in an interface file+lookupGlobal hsc_env name+ = initTcForLookup hsc_env (tcLookupGlobal name)+ -- This initTcForLookup stuff is massive overkill+ -- but that's how it is right now, and at least+ -- this function localises it++{-+************************************************************************+* *+* tcLookupGlobal *+* *+************************************************************************++Using the Located versions (eg. tcLookupLocatedGlobal) is preferred,+unless you know that the SrcSpan in the monad is already set to the+span of the Name.+-}+++tcLookupLocatedGlobal :: Located Name -> TcM TyThing+-- c.f. IfaceEnvEnv.tcIfaceGlobal+tcLookupLocatedGlobal name+ = addLocM tcLookupGlobal name++tcLookupGlobal :: Name -> TcM TyThing+-- The Name is almost always an ExternalName, but not always+-- In GHCi, we may make command-line bindings (ghci> let x = True)+-- that bind a GlobalId, but with an InternalName+tcLookupGlobal name+ = do { -- Try local envt+ env <- getGblEnv+ ; case lookupNameEnv (tcg_type_env env) name of {+ Just thing -> return thing ;+ Nothing ->++ -- Should it have been in the local envt?+ -- (NB: use semantic mod here, since names never use+ -- identity module, see Note [Identity versus semantic module].)+ if nameIsLocalOrFrom (tcg_semantic_mod env) name+ then notFound name -- Internal names can happen in GHCi+ else++ -- Try home package table and external package table+ do { mb_thing <- tcLookupImported_maybe name+ ; case mb_thing of+ Succeeded thing -> return thing+ Failed msg -> failWithTc msg+ }}}++tcLookupDataCon :: Name -> TcM DataCon+tcLookupDataCon name = do+ thing <- tcLookupGlobal name+ case thing of+ AConLike (RealDataCon con) -> return con+ _ -> wrongThingErr "data constructor" (AGlobal thing) name++tcLookupPatSyn :: Name -> TcM PatSyn+tcLookupPatSyn name = do+ thing <- tcLookupGlobal name+ case thing of+ AConLike (PatSynCon ps) -> return ps+ _ -> wrongThingErr "pattern synonym" (AGlobal thing) name++tcLookupConLike :: Name -> TcM ConLike+tcLookupConLike name = do+ thing <- tcLookupGlobal name+ case thing of+ AConLike cl -> return cl+ _ -> wrongThingErr "constructor-like thing" (AGlobal thing) name++tcLookupClass :: Name -> TcM Class+tcLookupClass name = do+ thing <- tcLookupGlobal name+ case thing of+ ATyCon tc | Just cls <- tyConClass_maybe tc -> return cls+ _ -> wrongThingErr "class" (AGlobal thing) name++tcLookupTyCon :: Name -> TcM TyCon+tcLookupTyCon name = do+ thing <- tcLookupGlobal name+ case thing of+ ATyCon tc -> return tc+ _ -> wrongThingErr "type constructor" (AGlobal thing) name++tcLookupAxiom :: Name -> TcM (CoAxiom Branched)+tcLookupAxiom name = do+ thing <- tcLookupGlobal name+ case thing of+ ACoAxiom ax -> return ax+ _ -> wrongThingErr "axiom" (AGlobal thing) name++tcLookupLocatedGlobalId :: Located Name -> TcM Id+tcLookupLocatedGlobalId = addLocM tcLookupId++tcLookupLocatedClass :: Located Name -> TcM Class+tcLookupLocatedClass = addLocM tcLookupClass++tcLookupLocatedTyCon :: Located Name -> TcM TyCon+tcLookupLocatedTyCon = addLocM tcLookupTyCon++-- Find the instance that exactly matches a type class application. The class arguments must be precisely+-- the same as in the instance declaration (modulo renaming & casts).+--+tcLookupInstance :: Class -> [Type] -> TcM ClsInst+tcLookupInstance cls tys+ = do { instEnv <- tcGetInstEnvs+ ; case lookupUniqueInstEnv instEnv cls tys of+ Left err -> failWithTc $ text "Couldn't match instance:" <+> err+ Right (inst, tys)+ | uniqueTyVars tys -> return inst+ | otherwise -> failWithTc errNotExact+ }+ where+ errNotExact = text "Not an exact match (i.e., some variables get instantiated)"++ uniqueTyVars tys = all isTyVarTy tys+ && hasNoDups (map (getTyVar "tcLookupInstance") tys)++tcGetInstEnvs :: TcM InstEnvs+-- Gets both the external-package inst-env+-- and the home-pkg inst env (includes module being compiled)+tcGetInstEnvs = do { eps <- getEps+ ; env <- getGblEnv+ ; return (InstEnvs { ie_global = eps_inst_env eps+ , ie_local = tcg_inst_env env+ , ie_visible = tcVisibleOrphanMods env }) }++instance MonadThings (IOEnv (Env TcGblEnv TcLclEnv)) where+ lookupThing = tcLookupGlobal++{-+************************************************************************+* *+ Extending the global environment+* *+************************************************************************+-}++setGlobalTypeEnv :: TcGblEnv -> TypeEnv -> TcM TcGblEnv+-- Use this to update the global type env+-- It updates both * the normal tcg_type_env field+-- * the tcg_type_env_var field seen by interface files+setGlobalTypeEnv tcg_env new_type_env+ = do { -- Sync the type-envt variable seen by interface files+ writeMutVar (tcg_type_env_var tcg_env) new_type_env+ ; return (tcg_env { tcg_type_env = new_type_env }) }+++tcExtendGlobalEnvImplicit :: [TyThing] -> TcM r -> TcM r+ -- Just extend the global environment with some TyThings+ -- Do not extend tcg_tcs etc+tcExtendGlobalEnvImplicit things thing_inside+ = do { tcg_env <- getGblEnv+ ; let ge' = extendTypeEnvList (tcg_type_env tcg_env) things+ ; tcg_env' <- setGlobalTypeEnv tcg_env ge'+ ; setGblEnv tcg_env' thing_inside }++tcExtendGlobalEnv :: [TyThing] -> TcM r -> TcM r+ -- Given a mixture of Ids, TyCons, Classes, all defined in the+ -- module being compiled, extend the global environment+tcExtendGlobalEnv things thing_inside+ = do { env <- getGblEnv+ ; let env' = env { tcg_tcs = [tc | ATyCon tc <- things] ++ tcg_tcs env,+ tcg_patsyns = [ps | AConLike (PatSynCon ps) <- things] ++ tcg_patsyns env }+ ; setGblEnv env' $+ tcExtendGlobalEnvImplicit things thing_inside+ }++tcExtendTyConEnv :: [TyCon] -> TcM r -> TcM r+ -- Given a mixture of Ids, TyCons, Classes, all defined in the+ -- module being compiled, extend the global environment+tcExtendTyConEnv tycons thing_inside+ = do { env <- getGblEnv+ ; let env' = env { tcg_tcs = tycons ++ tcg_tcs env }+ ; setGblEnv env' $+ tcExtendGlobalEnvImplicit (map ATyCon tycons) thing_inside+ }++tcExtendGlobalValEnv :: [Id] -> TcM a -> TcM a+ -- Same deal as tcExtendGlobalEnv, but for Ids+tcExtendGlobalValEnv ids thing_inside+ = tcExtendGlobalEnvImplicit [AnId id | id <- ids] thing_inside++tcExtendRecEnv :: [(Name,TyThing)] -> TcM r -> TcM r+-- Extend the global environments for the type/class knot tying game+-- Just like tcExtendGlobalEnv, except the argument is a list of pairs+tcExtendRecEnv gbl_stuff thing_inside+ = do { tcg_env <- getGblEnv+ ; let ge' = extendNameEnvList (tcg_type_env tcg_env) gbl_stuff+ ; tcg_env' <- setGlobalTypeEnv tcg_env ge'+ ; setGblEnv tcg_env' thing_inside }++{-+************************************************************************+* *+\subsection{The local environment}+* *+************************************************************************+-}++tcLookupLocated :: Located Name -> TcM TcTyThing+tcLookupLocated = addLocM tcLookup++tcLookupLcl_maybe :: Name -> TcM (Maybe TcTyThing)+tcLookupLcl_maybe name+ = do { local_env <- getLclTypeEnv+ ; return (lookupNameEnv local_env name) }++tcLookup :: Name -> TcM TcTyThing+tcLookup name = do+ local_env <- getLclTypeEnv+ case lookupNameEnv local_env name of+ Just thing -> return thing+ Nothing -> AGlobal <$> tcLookupGlobal name++tcLookupTyVar :: Name -> TcM TcTyVar+tcLookupTyVar name+ = do { thing <- tcLookup name+ ; case thing of+ ATyVar _ tv -> return tv+ _ -> pprPanic "tcLookupTyVar" (ppr name) }++tcLookupId :: Name -> TcM Id+-- Used when we aren't interested in the binding level, nor refinement.+-- The "no refinement" part means that we return the un-refined Id regardless+--+-- The Id is never a DataCon. (Why does that matter? see TcExpr.tcId)+tcLookupId name = do+ thing <- tcLookup name+ case thing of+ ATcId { tct_id = id} -> return id+ AGlobal (AnId id) -> return id+ _ -> pprPanic "tcLookupId" (ppr name)++tcLookupLocalIds :: [Name] -> TcM [TcId]+-- We expect the variables to all be bound, and all at+-- the same level as the lookup. Only used in one place...+tcLookupLocalIds ns+ = do { env <- getLclEnv+ ; return (map (lookup (tcl_env env)) ns) }+ where+ lookup lenv name+ = case lookupNameEnv lenv name of+ Just (ATcId { tct_id = id }) -> id+ _ -> pprPanic "tcLookupLocalIds" (ppr name)++getInLocalScope :: TcM (Name -> Bool)+getInLocalScope = do { lcl_env <- getLclTypeEnv+ ; return (`elemNameEnv` lcl_env) }++tcExtendKindEnvList :: [(Name, TcTyThing)] -> TcM r -> TcM r+-- Used only during kind checking, for TcThings that are+-- ATcTyCon or APromotionErr+-- No need to update the global tyvars, or tcl_th_bndrs, or tcl_rdr+tcExtendKindEnvList things thing_inside+ = do { traceTc "txExtendKindEnvList" (ppr things)+ ; updLclEnv upd_env thing_inside }+ where+ upd_env env = env { tcl_env = extendNameEnvList (tcl_env env) things }++tcExtendKindEnv :: NameEnv TcTyThing -> TcM r -> TcM r+-- A variant of tcExtendKindEvnList+tcExtendKindEnv extra_env thing_inside+ = do { traceTc "txExtendKindEnv" (ppr extra_env)+ ; updLclEnv upd_env thing_inside }+ where+ upd_env env = env { tcl_env = tcl_env env `plusNameEnv` extra_env }++-----------------------+-- Scoped type and kind variables+tcExtendTyVarEnv :: [TyVar] -> TcM r -> TcM r+tcExtendTyVarEnv tvs thing_inside+ = tcExtendTyVarEnv2 [(tyVarName tv, tv) | tv <- tvs] thing_inside++tcExtendTyVarEnv2 :: [(Name,TcTyVar)] -> TcM r -> TcM r+tcExtendTyVarEnv2 binds thing_inside+ -- this should be used only for explicitly mentioned scoped variables.+ -- thus, no coercion variables+ = do { tc_extend_local_env NotTopLevel+ [(name, ATyVar name tv) | (name, tv) <- binds] $+ do { env <- getLclEnv+ ; let env' = env { tcl_tidy = add_tidy_tvs (tcl_tidy env) }+ ; setLclEnv env' thing_inside }}+ where+ add_tidy_tvs env = foldl add env binds++ -- We initialise the "tidy-env", used for tidying types before printing,+ -- by building a reverse map from the in-scope type variables to the+ -- OccName that the programmer originally used for them+ add :: TidyEnv -> (Name, TcTyVar) -> TidyEnv+ add (env,subst) (name, tyvar)+ = ASSERT( isTyVar tyvar )+ case tidyOccName env (nameOccName name) of+ (env', occ') -> (env', extendVarEnv subst tyvar tyvar')+ where+ tyvar' = setTyVarName tyvar name'+ name' = tidyNameOcc name occ'++isTypeClosedLetBndr :: Id -> Bool+-- See Note [Bindings with closed types] in TcRnTypes+isTypeClosedLetBndr = noFreeVarsOfType . idType++tcExtendRecIds :: [(Name, TcId)] -> TcM a -> TcM a+-- Used for binding the recurive uses of Ids in a binding+-- both top-level value bindings and and nested let/where-bindings+-- Does not extend the TcIdBinderStack+tcExtendRecIds pairs thing_inside+ = tc_extend_local_env NotTopLevel+ [ (name, ATcId { tct_id = let_id+ , tct_info = NonClosedLet emptyNameSet False })+ | (name, let_id) <- pairs ] $+ thing_inside++tcExtendSigIds :: TopLevelFlag -> [TcId] -> TcM a -> TcM a+-- Used for binding the Ids that have a complete user type signature+-- Does not extend the TcIdBinderStack+tcExtendSigIds top_lvl sig_ids thing_inside+ = tc_extend_local_env top_lvl+ [ (idName id, ATcId { tct_id = id+ , tct_info = info })+ | id <- sig_ids+ , let closed = isTypeClosedLetBndr id+ info = NonClosedLet emptyNameSet closed ]+ thing_inside+++tcExtendLetEnv :: TopLevelFlag -> TcSigFun -> IsGroupClosed+ -> [TcId] -> TcM a -> TcM a+-- Used for both top-level value bindings and and nested let/where-bindings+-- Adds to the TcIdBinderStack too+tcExtendLetEnv top_lvl sig_fn (IsGroupClosed fvs fv_type_closed)+ ids thing_inside+ = tcExtendIdBndrs [TcIdBndr id top_lvl | id <- ids] $+ tc_extend_local_env top_lvl+ [ (idName id, ATcId { tct_id = id+ , tct_info = mk_tct_info id })+ | id <- ids ]+ thing_inside+ where+ mk_tct_info id+ | type_closed && isEmptyNameSet rhs_fvs = ClosedLet+ | otherwise = NonClosedLet rhs_fvs type_closed+ where+ name = idName id+ rhs_fvs = lookupNameEnv fvs name `orElse` emptyNameSet+ type_closed = isTypeClosedLetBndr id &&+ (fv_type_closed || hasCompleteSig sig_fn name)++tcExtendIdEnv :: [TcId] -> TcM a -> TcM a+-- For lambda-bound and case-bound Ids+-- Extends the the TcIdBinderStack as well+tcExtendIdEnv ids thing_inside+ = tcExtendIdEnv2 [(idName id, id) | id <- ids] thing_inside++tcExtendIdEnv1 :: Name -> TcId -> TcM a -> TcM a+-- Exactly like tcExtendIdEnv2, but for a single (name,id) pair+tcExtendIdEnv1 name id thing_inside+ = tcExtendIdEnv2 [(name,id)] thing_inside++tcExtendIdEnv2 :: [(Name,TcId)] -> TcM a -> TcM a+tcExtendIdEnv2 names_w_ids thing_inside+ = tcExtendIdBndrs [ TcIdBndr mono_id NotTopLevel+ | (_,mono_id) <- names_w_ids ] $+ tc_extend_local_env NotTopLevel+ [ (name, ATcId { tct_id = id+ , tct_info = NotLetBound })+ | (name,id) <- names_w_ids]+ thing_inside++tc_extend_local_env :: TopLevelFlag -> [(Name, TcTyThing)] -> TcM a -> TcM a+tc_extend_local_env top_lvl extra_env thing_inside+-- Precondition: the argument list extra_env has TcTyThings+-- that ATcId or ATyVar, but nothing else+--+-- Invariant: the ATcIds are fully zonked. Reasons:+-- (a) The kinds of the forall'd type variables are defaulted+-- (see Kind.defaultKind, done in zonkQuantifiedTyVar)+-- (b) There are no via-Indirect occurrences of the bound variables+-- in the types, because instantiation does not look through such things+-- (c) The call to tyCoVarsOfTypes is ok without looking through refs++-- The second argument of type TyVarSet is a set of type variables+-- that are bound together with extra_env and should not be regarded+-- as free in the types of extra_env.+ = do { traceTc "env2" (ppr extra_env)+ ; env0 <- getLclEnv+ ; env1 <- tcExtendLocalTypeEnv env0 extra_env+ ; stage <- getStage+ ; let env2 = extend_local_env (top_lvl, thLevel stage) extra_env env1+ ; setLclEnv env2 thing_inside }+ where+ extend_local_env :: (TopLevelFlag, ThLevel) -> [(Name, TcTyThing)] -> TcLclEnv -> TcLclEnv+ -- Extend the local LocalRdrEnv and Template Haskell staging env simultaneously+ -- Reason for extending LocalRdrEnv: after running a TH splice we need+ -- to do renaming.+ extend_local_env thlvl pairs env@(TcLclEnv { tcl_rdr = rdr_env+ , tcl_th_bndrs = th_bndrs })+ = env { tcl_rdr = extendLocalRdrEnvList rdr_env+ [ n | (n, _) <- pairs, isInternalName n ]+ -- The LocalRdrEnv contains only non-top-level names+ -- (GlobalRdrEnv handles the top level)+ , tcl_th_bndrs = extendNameEnvList th_bndrs -- We only track Ids in tcl_th_bndrs+ [(n, thlvl) | (n, ATcId {}) <- pairs] }++tcExtendLocalTypeEnv :: TcLclEnv -> [(Name, TcTyThing)] -> TcM TcLclEnv+tcExtendLocalTypeEnv lcl_env@(TcLclEnv { tcl_env = lcl_type_env }) tc_ty_things+ | isEmptyVarSet extra_tvs+ = return (lcl_env { tcl_env = extendNameEnvList lcl_type_env tc_ty_things })+ | otherwise+ = do { global_tvs <- readMutVar (tcl_tyvars lcl_env)+ ; new_g_var <- newMutVar (global_tvs `unionVarSet` extra_tvs)+ ; return (lcl_env { tcl_tyvars = new_g_var+ , tcl_env = extendNameEnvList lcl_type_env tc_ty_things } ) }+ where+ extra_tvs = foldr get_tvs emptyVarSet tc_ty_things++ get_tvs (_, ATcId { tct_id = id, tct_info = closed }) tvs+ = case closed of+ ClosedLet ->+ ASSERT2( isEmptyVarSet id_tvs, ppr id $$ ppr (idType id) ) tvs+ _ ->+ tvs `unionVarSet` id_tvs+ where id_tvs = tyCoVarsOfType (idType id)++ get_tvs (_, ATyVar _ tv) tvs -- See Note [Global TyVars]+ = tvs `unionVarSet` tyCoVarsOfType (tyVarKind tv) `extendVarSet` tv++ get_tvs (_, ATcTyCon tc) tvs = tvs `unionVarSet` tyCoVarsOfType (tyConKind tc)++ get_tvs (_, AGlobal {}) tvs = tvs+ get_tvs (_, APromotionErr {}) tvs = tvs++ -- Note [Global TyVars]+ -- It's important to add the in-scope tyvars to the global tyvar set+ -- as well. Consider+ -- f (_::r) = let g y = y::r in ...+ -- Here, g mustn't be generalised. This is also important during+ -- class and instance decls, when we mustn't generalise the class tyvars+ -- when typechecking the methods.+ --+ -- Nor must we generalise g over any kind variables free in r's kind++-------------------------------------------------------------+-- Extending the TcIdBinderStack, used only for error messages++tcExtendIdBndrs :: [TcIdBinder] -> TcM a -> TcM a+tcExtendIdBndrs bndrs thing_inside+ = do { traceTc "tcExtendIdBndrs" (ppr bndrs)+ ; updLclEnv (\env -> env { tcl_bndrs = bndrs ++ tcl_bndrs env })+ thing_inside }+++{- *********************************************************************+* *+ Adding placeholders+* *+********************************************************************* -}++tcAddDataFamConPlaceholders :: [LInstDecl Name] -> TcM a -> TcM a+-- See Note [AFamDataCon: not promoting data family constructors]+tcAddDataFamConPlaceholders inst_decls thing_inside+ = tcExtendKindEnvList [ (con, APromotionErr FamDataConPE)+ | lid <- inst_decls, con <- get_cons lid ]+ thing_inside+ -- Note [AFamDataCon: not promoting data family constructors]+ where+ -- get_cons extracts the *constructor* bindings of the declaration+ get_cons :: LInstDecl Name -> [Name]+ get_cons (L _ (TyFamInstD {})) = []+ get_cons (L _ (DataFamInstD { dfid_inst = fid })) = get_fi_cons fid+ get_cons (L _ (ClsInstD { cid_inst = ClsInstDecl { cid_datafam_insts = fids } }))+ = concatMap (get_fi_cons . unLoc) fids++ get_fi_cons :: DataFamInstDecl Name -> [Name]+ get_fi_cons (DataFamInstDecl { dfid_defn = HsDataDefn { dd_cons = cons } })+ = map unLoc $ concatMap (getConNames . unLoc) cons+++tcAddPatSynPlaceholders :: [PatSynBind Name Name] -> TcM a -> TcM a+-- See Note [Don't promote pattern synonyms]+tcAddPatSynPlaceholders pat_syns thing_inside+ = tcExtendKindEnvList [ (name, APromotionErr PatSynPE)+ | PSB{ psb_id = L _ name } <- pat_syns ]+ thing_inside++getTypeSigNames :: [LSig Name] -> NameSet+-- Get the names that have a user type sig+getTypeSigNames sigs+ = foldr get_type_sig emptyNameSet sigs+ where+ get_type_sig :: LSig Name -> NameSet -> NameSet+ get_type_sig sig ns =+ case sig of+ L _ (TypeSig names _) -> extendNameSetList ns (map unLoc names)+ L _ (PatSynSig names _) -> extendNameSetList ns (map unLoc names)+ _ -> ns+++{- Note [AFamDataCon: not promoting data family constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data family T a+ data instance T Int = MkT+ data Proxy (a :: k)+ data S = MkS (Proxy 'MkT)++Is it ok to use the promoted data family instance constructor 'MkT' in+the data declaration for S (where both declarations live in the same module)?+No, we don't allow this. It *might* make sense, but at least it would mean that+we'd have to interleave typechecking instances and data types, whereas at+present we do data types *then* instances.++So to check for this we put in the TcLclEnv a binding for all the family+constructors, bound to AFamDataCon, so that if we trip over 'MkT' when+type checking 'S' we'll produce a decent error message.++Trac #12088 describes this limitation. Of course, when MkT and S live in+different modules then all is well.++Note [Don't promote pattern synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We never promote pattern synonyms.++Consider this (Trac #11265):+ pattern A = True+ instance Eq A+We want a civilised error message from the occurrence of 'A'+in the instance, yet 'A' really has not yet been type checked.++Similarly (Trac #9161)+ {-# LANGUAGE PatternSynonyms, DataKinds #-}+ pattern A = ()+ b :: A+ b = undefined+Here, the type signature for b mentions A. But A is a pattern+synonym, which is typechecked as part of a group of bindings (for very+good reasons; a view pattern in the RHS may mention a value binding).+It is entirely reasonable to reject this, but to do so we need A to be+in the kind environment when kind-checking the signature for B.++Hence tcAddPatSynPlaceholers adds a binding+ A -> APromotionErr PatSynPE+to the environment. Then TcHsType.tcTyVar will find A in the kind+environment, and will give a 'wrongThingErr' as a result. But the+lookup of A won't fail.+++************************************************************************+* *+\subsection{Rules}+* *+************************************************************************+-}++tcExtendRules :: [LRuleDecl Id] -> TcM a -> TcM a+ -- Just pop the new rules into the EPS and envt resp+ -- All the rules come from an interface file, not source+ -- Nevertheless, some may be for this module, if we read+ -- its interface instead of its source code+tcExtendRules lcl_rules thing_inside+ = do { env <- getGblEnv+ ; let+ env' = env { tcg_rules = lcl_rules ++ tcg_rules env }+ ; setGblEnv env' thing_inside }++{-+************************************************************************+* *+ Meta level+* *+************************************************************************+-}++checkWellStaged :: SDoc -- What the stage check is for+ -> ThLevel -- Binding level (increases inside brackets)+ -> ThLevel -- Use stage+ -> TcM () -- Fail if badly staged, adding an error+checkWellStaged pp_thing bind_lvl use_lvl+ | use_lvl >= bind_lvl -- OK! Used later than bound+ = return () -- E.g. \x -> [| $(f x) |]++ | bind_lvl == outerLevel -- GHC restriction on top level splices+ = stageRestrictionError pp_thing++ | otherwise -- Badly staged+ = failWithTc $ -- E.g. \x -> $(f x)+ text "Stage error:" <+> pp_thing <+>+ hsep [text "is bound at stage" <+> ppr bind_lvl,+ text "but used at stage" <+> ppr use_lvl]++stageRestrictionError :: SDoc -> TcM a+stageRestrictionError pp_thing+ = failWithTc $+ sep [ text "GHC stage restriction:"+ , nest 2 (vcat [ pp_thing <+> text "is used in a top-level splice, quasi-quote, or annotation,"+ , text "and must be imported, not defined locally"])]++topIdLvl :: Id -> ThLevel+-- Globals may either be imported, or may be from an earlier "chunk"+-- (separated by declaration splices) of this module. The former+-- *can* be used inside a top-level splice, but the latter cannot.+-- Hence we give the former impLevel, but the latter topLevel+-- E.g. this is bad:+-- x = [| foo |]+-- $( f x )+-- By the time we are prcessing the $(f x), the binding for "x"+-- will be in the global env, not the local one.+topIdLvl id | isLocalId id = outerLevel+ | otherwise = impLevel++tcMetaTy :: Name -> TcM Type+-- Given the name of a Template Haskell data type,+-- return the type+-- E.g. given the name "Expr" return the type "Expr"+tcMetaTy tc_name = do+ t <- tcLookupTyCon tc_name+ return (mkTyConApp t [])++isBrackStage :: ThStage -> Bool+isBrackStage (Brack {}) = True+isBrackStage _other = False++{-+************************************************************************+* *+ getDefaultTys+* *+************************************************************************+-}++tcGetDefaultTys :: TcM ([Type], -- Default types+ (Bool, -- True <=> Use overloaded strings+ Bool)) -- True <=> Use extended defaulting rules+tcGetDefaultTys+ = do { dflags <- getDynFlags+ ; let ovl_strings = xopt LangExt.OverloadedStrings dflags+ extended_defaults = xopt LangExt.ExtendedDefaultRules dflags+ -- See also Trac #1974+ flags = (ovl_strings, extended_defaults)++ ; mb_defaults <- getDeclaredDefaultTys+ ; case mb_defaults of {+ Just tys -> return (tys, flags) ;+ -- User-supplied defaults+ Nothing -> do++ -- No use-supplied default+ -- Use [Integer, Double], plus modifications+ { integer_ty <- tcMetaTy integerTyConName+ ; list_ty <- tcMetaTy listTyConName+ ; checkWiredInTyCon doubleTyCon+ ; let deflt_tys = opt_deflt extended_defaults [unitTy, list_ty]+ -- Note [Extended defaults]+ ++ [integer_ty, doubleTy]+ ++ opt_deflt ovl_strings [stringTy]+ ; return (deflt_tys, flags) } } }+ where+ opt_deflt True xs = xs+ opt_deflt False _ = []++{-+Note [Extended defaults]+~~~~~~~~~~~~~~~~~~~~~+In interative mode (or with -XExtendedDefaultRules) we add () as the first type we+try when defaulting. This has very little real impact, except in the following case.+Consider:+ Text.Printf.printf "hello"+This has type (forall a. IO a); it prints "hello", and returns 'undefined'. We don't+want the GHCi repl loop to try to print that 'undefined'. The neatest thing is to+default the 'a' to (), rather than to Integer (which is what would otherwise happen;+and then GHCi doesn't attempt to print the (). So in interactive mode, we add+() to the list of defaulting types. See Trac #1200.++Additonally, the list type [] is added as a default specialization for+Traversable and Foldable. As such the default default list now has types of+varying kinds, e.g. ([] :: * -> *) and (Integer :: *).++************************************************************************+* *+\subsection{The InstInfo type}+* *+************************************************************************++The InstInfo type summarises the information in an instance declaration++ instance c => k (t tvs) where b++It is used just for *local* instance decls (not ones from interface files).+But local instance decls includes+ - derived ones+ - generic ones+as well as explicit user written ones.+-}++data InstInfo a+ = InstInfo+ { iSpec :: ClsInst -- Includes the dfun id+ , iBinds :: InstBindings a+ }++iDFunId :: InstInfo a -> DFunId+iDFunId info = instanceDFunId (iSpec info)++data InstBindings a+ = InstBindings+ { ib_tyvars :: [Name] -- Names of the tyvars from the instance head+ -- that are lexically in scope in the bindings+ -- Must correspond 1-1 with the forall'd tyvars+ -- of the dfun Id. When typechecking, we are+ -- going to extend the typechecker's envt with+ -- ib_tyvars -> dfun_forall_tyvars++ , ib_binds :: LHsBinds a -- Bindings for the instance methods++ , ib_pragmas :: [LSig a] -- User pragmas recorded for generating+ -- specialised instances++ , ib_extensions :: [LangExt.Extension] -- Any extra extensions that should+ -- be enabled when type-checking+ -- this instance; needed for+ -- GeneralizedNewtypeDeriving++ , ib_derived :: Bool+ -- True <=> This code was generated by GHC from a deriving clause+ -- or standalone deriving declaration+ -- Used only to improve error messages+ }++instance (OutputableBndrId a) => Outputable (InstInfo a) where+ ppr = pprInstInfoDetails++pprInstInfoDetails :: (OutputableBndrId a) => InstInfo a -> SDoc+pprInstInfoDetails info+ = hang (pprInstanceHdr (iSpec info) <+> text "where")+ 2 (details (iBinds info))+ where+ details (InstBindings { ib_binds = b }) = pprLHsBinds b++simpleInstInfoClsTy :: InstInfo a -> (Class, Type)+simpleInstInfoClsTy info = case instanceHead (iSpec info) of+ (_, cls, [ty]) -> (cls, ty)+ _ -> panic "simpleInstInfoClsTy"++simpleInstInfoTy :: InstInfo a -> Type+simpleInstInfoTy info = snd (simpleInstInfoClsTy info)++simpleInstInfoTyCon :: InstInfo a -> TyCon+ -- Gets the type constructor for a simple instance declaration,+ -- i.e. one of the form instance (...) => C (T a b c) where ...+simpleInstInfoTyCon inst = tcTyConAppTyCon (simpleInstInfoTy inst)++-- | Make a name for the dict fun for an instance decl. It's an *external*+-- name, like other top-level names, and hence must be made with+-- newGlobalBinder.+newDFunName :: Class -> [Type] -> SrcSpan -> TcM Name+newDFunName clas tys loc+ = do { is_boot <- tcIsHsBootOrSig+ ; mod <- getModule+ ; let info_string = occNameString (getOccName clas) +++ concatMap (occNameString.getDFunTyKey) tys+ ; dfun_occ <- chooseUniqueOccTc (mkDFunOcc info_string is_boot)+ ; newGlobalBinder mod dfun_occ loc }++-- | Special case of 'newDFunName' to generate dict fun name for a single TyCon.+newDFunName' :: Class -> TyCon -> TcM Name+newDFunName' clas tycon -- Just a simple wrapper+ = do { loc <- getSrcSpanM -- The location of the instance decl,+ -- not of the tycon+ ; newDFunName clas [mkTyConApp tycon []] loc }+ -- The type passed to newDFunName is only used to generate+ -- a suitable string; hence the empty type arg list++{-+Make a name for the representation tycon of a family instance. It's an+*external* name, like other top-level names, and hence must be made with+newGlobalBinder.+-}++newFamInstTyConName :: Located Name -> [Type] -> TcM Name+newFamInstTyConName (L loc name) tys = mk_fam_inst_name id loc name [tys]++newFamInstAxiomName :: Located Name -> [[Type]] -> TcM Name+newFamInstAxiomName (L loc name) branches+ = mk_fam_inst_name mkInstTyCoOcc loc name branches++mk_fam_inst_name :: (OccName -> OccName) -> SrcSpan -> Name -> [[Type]] -> TcM Name+mk_fam_inst_name adaptOcc loc tc_name tyss+ = do { mod <- getModule+ ; let info_string = occNameString (getOccName tc_name) +++ intercalate "|" ty_strings+ ; occ <- chooseUniqueOccTc (mkInstTyTcOcc info_string)+ ; newGlobalBinder mod (adaptOcc occ) loc }+ where+ ty_strings = map (concatMap (occNameString . getDFunTyKey)) tyss++{-+Stable names used for foreign exports and annotations.+For stable names, the name must be unique (see #1533). If the+same thing has several stable Ids based on it, the+top-level bindings generated must not have the same name.+Hence we create an External name (doesn't change), and we+append a Unique to the string right here.+-}++mkStableIdFromString :: String -> Type -> SrcSpan -> (OccName -> OccName) -> TcM TcId+mkStableIdFromString str sig_ty loc occ_wrapper = do+ uniq <- newUnique+ mod <- getModule+ name <- mkWrapperName "stable" str+ let occ = mkVarOccFS name :: OccName+ gnm = mkExternalName uniq mod (occ_wrapper occ) loc :: Name+ id = mkExportedVanillaId gnm sig_ty :: Id+ return id++mkStableIdFromName :: Name -> Type -> SrcSpan -> (OccName -> OccName) -> TcM TcId+mkStableIdFromName nm = mkStableIdFromString (getOccString nm)++mkWrapperName :: (MonadIO m, HasDynFlags m, HasModule m)+ => String -> String -> m FastString+mkWrapperName what nameBase+ = do dflags <- getDynFlags+ thisMod <- getModule+ let -- Note [Generating fresh names for ccall wrapper]+ wrapperRef = nextWrapperNum dflags+ pkg = unitIdString (moduleUnitId thisMod)+ mod = moduleNameString (moduleName thisMod)+ wrapperNum <- liftIO $ atomicModifyIORef' wrapperRef $ \mod_env ->+ let num = lookupWithDefaultModuleEnv mod_env 0 thisMod+ mod_env' = extendModuleEnv mod_env thisMod (num+1)+ in (mod_env', num)+ let components = [what, show wrapperNum, pkg, mod, nameBase]+ return $ mkFastString $ zEncodeString $ intercalate ":" components++{-+Note [Generating fresh names for FFI wrappers]++We used to use a unique, rather than nextWrapperNum, to distinguish+between FFI wrapper functions. However, the wrapper names that we+generate are external names. This means that if a call to them ends up+in an unfolding, then we can't alpha-rename them, and thus if the+unique randomly changes from one compile to another then we get a+spurious ABI change (#4012).++The wrapper counter has to be per-module, not global, so that the number we end+up using is not dependent on the modules compiled before the current one.+-}++{-+************************************************************************+* *+\subsection{Errors}+* *+************************************************************************+-}++pprBinders :: [Name] -> SDoc+-- Used in error messages+-- Use quotes for a single one; they look a bit "busy" for several+pprBinders [bndr] = quotes (ppr bndr)+pprBinders bndrs = pprWithCommas ppr bndrs++notFound :: Name -> TcM TyThing+notFound name+ = do { lcl_env <- getLclEnv+ ; let stage = tcl_th_ctxt lcl_env+ ; case stage of -- See Note [Out of scope might be a staging error]+ Splice {}+ | isUnboundName name -> failM -- If the name really isn't in scope+ -- don't report it again (Trac #11941)+ | otherwise -> stageRestrictionError (quotes (ppr name))+ _ -> failWithTc $+ vcat[text "GHC internal error:" <+> quotes (ppr name) <+>+ text "is not in scope during type checking, but it passed the renamer",+ text "tcl_env of environment:" <+> ppr (tcl_env lcl_env)]+ -- Take care: printing the whole gbl env can+ -- cause an infinite loop, in the case where we+ -- are in the middle of a recursive TyCon/Class group;+ -- so let's just not print it! Getting a loop here is+ -- very unhelpful, because it hides one compiler bug with another+ }++wrongThingErr :: String -> TcTyThing -> Name -> TcM a+-- It's important that this only calls pprTcTyThingCategory, which in+-- turn does not look at the details of the TcTyThing.+-- See Note [Placeholder PatSyn kinds] in TcBinds+wrongThingErr expected thing name+ = failWithTc (pprTcTyThingCategory thing <+> quotes (ppr name) <+>+ text "used as a" <+> text expected)++{- Note [Out of scope might be a staging error]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ x = 3+ data T = MkT $(foo x)++where 'foo' is imported from somewhere.++This is really a staging error, because we can't run code involving 'x'.+But in fact the type checker processes types first, so 'x' won't even be+in the type envt when we look for it in $(foo x). So inside splices we+report something missing from the type env as a staging error.+See Trac #5752 and #5795.+-}
+ typecheck/TcEnv.hs-boot view
@@ -0,0 +1,6 @@+{-+>module TcEnv where+>import TcRnTypes+>+>tcExtendIdEnv :: [TcId] -> TcM a -> TcM a+-}
+ typecheck/TcErrors.hs view
@@ -0,0 +1,2843 @@+{-# LANGUAGE CPP, ScopedTypeVariables #-}++module TcErrors(+ reportUnsolved, reportAllUnsolved, warnAllUnsolved,+ warnDefaulting,++ solverDepthErrorTcS+ ) where++#include "HsVersions.h"++import TcRnTypes+import TcRnMonad+import TcMType+import TcUnify( occCheckForErrors, OccCheckResult(..) )+import TcType+import RnEnv( unknownNameSuggestions )+import Type+import TyCoRep+import Kind+import Unify ( tcMatchTys )+import Module+import FamInst+import FamInstEnv ( flattenTys )+import Inst+import InstEnv+import TyCon+import Class+import DataCon+import TcEvidence+import HsExpr ( UnboundVar(..) )+import HsBinds ( PatSynBind(..) )+import Name+import RdrName ( lookupGlobalRdrEnv, lookupGRE_Name, GlobalRdrEnv+ , mkRdrUnqual, isLocalGRE, greSrcSpan )+import PrelNames ( typeableClassName, hasKey, liftedRepDataConKey )+import Id+import Var+import VarSet+import VarEnv+import NameSet+import Bag+import ErrUtils ( ErrMsg, errDoc, pprLocErrMsg )+import BasicTypes+import ConLike ( ConLike(..) )+import Util+import FastString+import Outputable+import SrcLoc+import DynFlags+import ListSetOps ( equivClasses )+import Maybes+import qualified GHC.LanguageExtensions as LangExt+import FV ( fvVarList, unionFV )++import Control.Monad ( when )+import Data.List ( partition, mapAccumL, nub, sortBy, unfoldr )+import qualified Data.Set as Set++#if __GLASGOW_HASKELL__ > 710+import Data.Semigroup ( Semigroup )+import qualified Data.Semigroup as Semigroup+#endif+++{-+************************************************************************+* *+\section{Errors and contexts}+* *+************************************************************************++ToDo: for these error messages, should we note the location as coming+from the insts, or just whatever seems to be around in the monad just+now?++Note [Deferring coercion errors to runtime]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+While developing, sometimes it is desirable to allow compilation to succeed even+if there are type errors in the code. Consider the following case:++ module Main where++ a :: Int+ a = 'a'++ main = print "b"++Even though `a` is ill-typed, it is not used in the end, so if all that we're+interested in is `main` it is handy to be able to ignore the problems in `a`.++Since we treat type equalities as evidence, this is relatively simple. Whenever+we run into a type mismatch in TcUnify, we normally just emit an error. But it+is always safe to defer the mismatch to the main constraint solver. If we do+that, `a` will get transformed into++ co :: Int ~ Char+ co = ...++ a :: Int+ a = 'a' `cast` co++The constraint solver would realize that `co` is an insoluble constraint, and+emit an error with `reportUnsolved`. But we can also replace the right-hand side+of `co` with `error "Deferred type error: Int ~ Char"`. This allows the program+to compile, and it will run fine unless we evaluate `a`. This is what+`deferErrorsToRuntime` does.++It does this by keeping track of which errors correspond to which coercion+in TcErrors. TcErrors.reportTidyWanteds does not print the errors+and does not fail if -fdefer-type-errors is on, so that we can continue+compilation. The errors are turned into warnings in `reportUnsolved`.+-}++-- | Report unsolved goals as errors or warnings. We may also turn some into+-- deferred run-time errors if `-fdefer-type-errors` is on.+reportUnsolved :: WantedConstraints -> TcM (Bag EvBind)+reportUnsolved wanted+ = do { binds_var <- newTcEvBinds+ ; defer_errors <- goptM Opt_DeferTypeErrors+ ; warn_errors <- woptM Opt_WarnDeferredTypeErrors -- implement #10283+ ; let type_errors | not defer_errors = TypeError+ | warn_errors = TypeWarn+ | otherwise = TypeDefer++ ; defer_holes <- goptM Opt_DeferTypedHoles+ ; warn_holes <- woptM Opt_WarnTypedHoles+ ; let expr_holes | not defer_holes = HoleError+ | warn_holes = HoleWarn+ | otherwise = HoleDefer++ ; partial_sigs <- xoptM LangExt.PartialTypeSignatures+ ; warn_partial_sigs <- woptM Opt_WarnPartialTypeSignatures+ ; let type_holes | not partial_sigs = HoleError+ | warn_partial_sigs = HoleWarn+ | otherwise = HoleDefer++ ; defer_out_of_scope <- goptM Opt_DeferOutOfScopeVariables+ ; warn_out_of_scope <- woptM Opt_WarnDeferredOutOfScopeVariables+ ; let out_of_scope_holes | not defer_out_of_scope = HoleError+ | warn_out_of_scope = HoleWarn+ | otherwise = HoleDefer++ ; report_unsolved binds_var False type_errors expr_holes+ type_holes out_of_scope_holes wanted++ ; ev_binds <- getTcEvBindsMap binds_var+ ; return (evBindMapBinds ev_binds)}++-- | Report *all* unsolved goals as errors, even if -fdefer-type-errors is on+-- However, do not make any evidence bindings, because we don't+-- have any convenient place to put them.+-- See Note [Deferring coercion errors to runtime]+-- Used by solveEqualities for kind equalities+-- (see Note [Fail fast on kind errors] in TcSimplify]+-- and for simplifyDefault.+reportAllUnsolved :: WantedConstraints -> TcM ()+reportAllUnsolved wanted+ = do { ev_binds <- newTcEvBinds+ ; report_unsolved ev_binds False TypeError+ HoleError HoleError HoleError wanted }++-- | Report all unsolved goals as warnings (but without deferring any errors to+-- run-time). See Note [Safe Haskell Overlapping Instances Implementation] in+-- TcSimplify+warnAllUnsolved :: WantedConstraints -> TcM ()+warnAllUnsolved wanted+ = do { ev_binds <- newTcEvBinds+ ; report_unsolved ev_binds True TypeWarn+ HoleWarn HoleWarn HoleWarn wanted }++-- | Report unsolved goals as errors or warnings.+report_unsolved :: EvBindsVar -- cec_binds+ -> Bool -- Errors as warnings+ -> TypeErrorChoice -- Deferred type errors+ -> HoleChoice -- Expression holes+ -> HoleChoice -- Type holes+ -> HoleChoice -- Out of scope holes+ -> WantedConstraints -> TcM ()+report_unsolved mb_binds_var err_as_warn type_errors expr_holes+ type_holes out_of_scope_holes wanted+ | isEmptyWC wanted+ = return ()+ | otherwise+ = do { traceTc "reportUnsolved (before zonking and tidying)" (ppr wanted)++ ; wanted <- zonkWC wanted -- Zonk to reveal all information+ ; env0 <- tcInitTidyEnv+ -- If we are deferring we are going to need /all/ evidence around,+ -- including the evidence produced by unflattening (zonkWC)+ ; let tidy_env = tidyFreeTyCoVars env0 free_tvs+ free_tvs = tyCoVarsOfWCList wanted++ ; traceTc "reportUnsolved (after zonking):" $+ vcat [ text "Free tyvars:" <+> pprTyVars free_tvs+ , text "Wanted:" <+> ppr wanted ]++ ; warn_redundant <- woptM Opt_WarnRedundantConstraints+ ; let err_ctxt = CEC { cec_encl = []+ , cec_tidy = tidy_env+ , cec_defer_type_errors = type_errors+ , cec_errors_as_warns = err_as_warn+ , cec_expr_holes = expr_holes+ , cec_type_holes = type_holes+ , cec_out_of_scope_holes = out_of_scope_holes+ , cec_suppress = False -- See Note [Suppressing error messages]+ , cec_warn_redundant = warn_redundant+ , cec_binds = mb_binds_var }++ ; tc_lvl <- getTcLevel+ ; reportWanteds err_ctxt tc_lvl wanted }++--------------------------------------------+-- Internal functions+--------------------------------------------++-- | An error Report collects messages categorised by their importance.+-- See Note [Error report] for details.+data Report+ = Report { report_important :: [SDoc]+ , report_relevant_bindings :: [SDoc]+ }++instance Outputable Report where -- Debugging only+ ppr (Report { report_important = imp, report_relevant_bindings = rel })+ = vcat [ text "important:" <+> vcat imp+ , text "relevant:" <+> vcat rel ]++{- Note [Error report]+The idea is that error msgs are divided into three parts: the main msg, the+context block (\"In the second argument of ...\"), and the relevant bindings+block, which are displayed in that order, with a mark to divide them. The+idea is that the main msg ('report_important') varies depending on the error+in question, but context and relevant bindings are always the same, which+should simplify visual parsing.++The context is added when the the Report is passed off to 'mkErrorReport'.+Unfortunately, unlike the context, the relevant bindings are added in+multiple places so they have to be in the Report.+-}++#if __GLASGOW_HASKELL__ > 710+instance Semigroup Report where+ Report a1 b1 <> Report a2 b2 = Report (a1 ++ a2) (b1 ++ b2)+#endif++instance Monoid Report where+ mempty = Report [] []+ mappend (Report a1 b1) (Report a2 b2) = Report (a1 ++ a2) (b1 ++ b2)++-- | Put a doc into the important msgs block.+important :: SDoc -> Report+important doc = mempty { report_important = [doc] }++-- | Put a doc into the relevant bindings block.+relevant_bindings :: SDoc -> Report+relevant_bindings doc = mempty { report_relevant_bindings = [doc] }++data TypeErrorChoice -- What to do for type errors found by the type checker+ = TypeError -- A type error aborts compilation with an error message+ | TypeWarn -- A type error is deferred to runtime, plus a compile-time warning+ | TypeDefer -- A type error is deferred to runtime; no error or warning at compile time++data HoleChoice+ = HoleError -- A hole is a compile-time error+ | HoleWarn -- Defer to runtime, emit a compile-time warning+ | HoleDefer -- Defer to runtime, no warning++instance Outputable HoleChoice where+ ppr HoleError = text "HoleError"+ ppr HoleWarn = text "HoleWarn"+ ppr HoleDefer = text "HoleDefer"++instance Outputable TypeErrorChoice where+ ppr TypeError = text "TypeError"+ ppr TypeWarn = text "TypeWarn"+ ppr TypeDefer = text "TypeDefer"++data ReportErrCtxt+ = CEC { cec_encl :: [Implication] -- Enclosing implications+ -- (innermost first)+ -- ic_skols and givens are tidied, rest are not+ , cec_tidy :: TidyEnv++ , cec_binds :: EvBindsVar -- Make some errors (depending on cec_defer)+ -- into warnings, and emit evidence bindings+ -- into 'cec_binds' for unsolved constraints++ , cec_errors_as_warns :: Bool -- Turn all errors into warnings+ -- (except for Holes, which are+ -- controlled by cec_type_holes and+ -- cec_expr_holes)+ , cec_defer_type_errors :: TypeErrorChoice -- Defer type errors until runtime++ -- cec_expr_holes is a union of:+ -- cec_type_holes - a set of typed holes: '_', '_a', '_foo'+ -- cec_out_of_scope_holes - a set of variables which are+ -- out of scope: 'x', 'y', 'bar'+ , cec_expr_holes :: HoleChoice -- Holes in expressions+ , cec_type_holes :: HoleChoice -- Holes in types+ , cec_out_of_scope_holes :: HoleChoice -- Out of scope holes++ , cec_warn_redundant :: Bool -- True <=> -Wredundant-constraints++ , cec_suppress :: Bool -- True <=> More important errors have occurred,+ -- so create bindings if need be, but+ -- don't issue any more errors/warnings+ -- See Note [Suppressing error messages]+ }++instance Outputable ReportErrCtxt where+ ppr (CEC { cec_binds = bvar+ , cec_errors_as_warns = ew+ , cec_defer_type_errors = dte+ , cec_expr_holes = eh+ , cec_type_holes = th+ , cec_out_of_scope_holes = osh+ , cec_warn_redundant = wr+ , cec_suppress = sup })+ = text "CEC" <+> braces (vcat+ [ text "cec_binds" <+> equals <+> ppr bvar+ , text "cec_errors_as_warns" <+> equals <+> ppr ew+ , text "cec_defer_type_errors" <+> equals <+> ppr dte+ , text "cec_expr_holes" <+> equals <+> ppr eh+ , text "cec_type_holes" <+> equals <+> ppr th+ , text "cec_out_of_scope_holes" <+> equals <+> ppr osh+ , text "cec_warn_redundant" <+> equals <+> ppr wr+ , text "cec_suppress" <+> equals <+> ppr sup ])++{-+Note [Suppressing error messages]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The cec_suppress flag says "don't report any errors". Instead, just create+evidence bindings (as usual). It's used when more important errors have occurred.++Specifically (see reportWanteds)+ * If there are insoluble Givens, then we are in unreachable code and all bets+ are off. So don't report any further errors.+ * If there are any insolubles (eg Int~Bool), here or in a nested implication,+ then suppress errors from the simple constraints here. Sometimes the+ simple-constraint errors are a knock-on effect of the insolubles.+-}++reportImplic :: ReportErrCtxt -> Implication -> TcM ()+reportImplic ctxt implic@(Implic { ic_skols = tvs, ic_given = given+ , ic_wanted = wanted, ic_binds = evb+ , ic_status = status, ic_info = info+ , ic_env = tcl_env, ic_tclvl = tc_lvl })+ | BracketSkol <- info+ , not insoluble+ = return () -- For Template Haskell brackets report only+ -- definite errors. The whole thing will be re-checked+ -- later when we plug it in, and meanwhile there may+ -- certainly be un-satisfied constraints++ | otherwise+ = do { traceTc "reportImplic" (ppr implic')+ ; reportWanteds ctxt' tc_lvl wanted+ ; when (cec_warn_redundant ctxt) $+ warnRedundantConstraints ctxt' tcl_env info' dead_givens }+ where+ insoluble = isInsolubleStatus status+ (env1, tvs') = mapAccumL tidyTyCoVarBndr (cec_tidy ctxt) tvs+ info' = tidySkolemInfo env1 info+ implic' = implic { ic_skols = tvs'+ , ic_given = map (tidyEvVar env1) given+ , ic_info = info' }+ ctxt' = ctxt { cec_tidy = env1+ , cec_encl = implic' : cec_encl ctxt++ , cec_suppress = insoluble || cec_suppress ctxt+ -- Suppress inessential errors if there+ -- are are insolubles anywhere in the+ -- tree rooted here, or we've come across+ -- a suppress-worthy constraint higher up (Trac #11541)++ , cec_binds = evb }++ dead_givens = case status of+ IC_Solved { ics_dead = dead } -> dead+ _ -> []++warnRedundantConstraints :: ReportErrCtxt -> TcLclEnv -> SkolemInfo -> [EvVar] -> TcM ()+-- See Note [Tracking redundant constraints] in TcSimplify+warnRedundantConstraints ctxt env info ev_vars+ | null redundant_evs+ = return ()++ | SigSkol {} <- info+ = setLclEnv env $ -- We want to add "In the type signature for f"+ -- to the error context, which is a bit tiresome+ addErrCtxt (text "In" <+> ppr info) $+ do { env <- getLclEnv+ ; msg <- mkErrorReport ctxt env (important doc)+ ; reportWarning (Reason Opt_WarnRedundantConstraints) msg }++ | otherwise -- But for InstSkol there already *is* a surrounding+ -- "In the instance declaration for Eq [a]" context+ -- and we don't want to say it twice. Seems a bit ad-hoc+ = do { msg <- mkErrorReport ctxt env (important doc)+ ; reportWarning (Reason Opt_WarnRedundantConstraints) msg }+ where+ doc = text "Redundant constraint" <> plural redundant_evs <> colon+ <+> pprEvVarTheta redundant_evs++ redundant_evs = case info of -- See Note [Redundant constraints in instance decls]+ InstSkol -> filterOut improving ev_vars+ _ -> ev_vars++ improving ev_var = any isImprovementPred $+ transSuperClasses (idType ev_var)++{- Note [Redundant constraints in instance decls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For instance declarations, we don't report unused givens if+they can give rise to improvement. Example (Trac #10100):+ class Add a b ab | a b -> ab, a ab -> b+ instance Add Zero b b+ instance Add a b ab => Add (Succ a) b (Succ ab)+The context (Add a b ab) for the instance is clearly unused in terms+of evidence, since the dictionary has no feilds. But it is still+needed! With the context, a wanted constraint+ Add (Succ Zero) beta (Succ Zero)+we will reduce to (Add Zero beta Zero), and thence we get beta := Zero.+But without the context we won't find beta := Zero.++This only matters in instance declarations..+-}++reportWanteds :: ReportErrCtxt -> TcLevel -> WantedConstraints -> TcM ()+reportWanteds ctxt tc_lvl (WC { wc_simple = simples, wc_insol = insols, wc_impl = implics })+ = do { traceTc "reportWanteds" (vcat [ text "Simples =" <+> ppr simples+ , text "Insols =" <+> ppr insols+ , text "Suppress =" <+> ppr (cec_suppress ctxt)])+ ; let tidy_cts = bagToList (mapBag (tidyCt env) (insols `unionBags` simples))++ -- First deal with things that are utterly wrong+ -- Like Int ~ Bool (incl nullary TyCons)+ -- or Int ~ t a (AppTy on one side)+ -- These /ones/ are not suppressed by the incoming context+ ; let ctxt_for_insols = ctxt { cec_suppress = False }+ ; (ctxt1, cts1) <- tryReporters ctxt_for_insols report1 tidy_cts++ -- Now all the other constraints. We suppress errors here if+ -- any of the first batch failed, or if the enclosing context+ -- says to suppress+ ; let ctxt2 = ctxt { cec_suppress = cec_suppress ctxt || cec_suppress ctxt1 }+ ; (_, leftovers) <- tryReporters ctxt2 report2 cts1+ ; MASSERT2( null leftovers, ppr leftovers )++ -- All the Derived ones have been filtered out of simples+ -- by the constraint solver. This is ok; we don't want+ -- to report unsolved Derived goals as errors+ -- See Note [Do not report derived but soluble errors]++ ; mapBagM_ (reportImplic ctxt2) implics }+ -- NB ctxt1: don't suppress inner insolubles if there's only a+ -- wanted insoluble here; but do suppress inner insolubles+ -- if there's a *given* insoluble here (= inaccessible code)+ where+ env = cec_tidy ctxt++ -- report1: ones that should *not* be suppresed by+ -- an insoluble somewhere else in the tree+ -- It's crucial that anything that is considered insoluble+ -- (see TcRnTypes.trulyInsoluble) is caught here, otherwise+ -- we might suppress its error message, and proceed on past+ -- type checking to get a Lint error later+ report1 = [ ("custom_error", is_user_type_error,+ True, mkUserTypeErrorReporter)+ , given_eq_spec+ , ("insoluble2", utterly_wrong, True, mkGroupReporter mkEqErr)+ , ("skolem eq1", very_wrong, True, mkSkolReporter)+ , ("skolem eq2", skolem_eq, True, mkSkolReporter)+ , ("non-tv eq", non_tv_eq, True, mkSkolReporter)+ , ("Out of scope", is_out_of_scope, True, mkHoleReporter)+ , ("Holes", is_hole, False, mkHoleReporter)++ -- The only remaining equalities are alpha ~ ty,+ -- where alpha is untouchable; and representational equalities+ , ("Other eqs", is_equality, False, mkGroupReporter mkEqErr) ]++ -- 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)+ , ("Dicts", is_dict, False, mkGroupReporter mkDictErr) ]++ -- rigid_nom_eq, rigid_nom_tv_eq,+ is_hole, is_dict,+ is_equality, is_ip, is_irred :: Ct -> PredTree -> Bool++ is_given_eq ct pred+ | EqPred {} <- pred = arisesFromGivens ct+ | otherwise = False+ -- I think all given residuals are equalities++ -- Things like (Int ~N Bool)+ utterly_wrong _ (EqPred NomEq ty1 ty2) = isRigidTy ty1 && isRigidTy ty2+ utterly_wrong _ _ = False++ -- Things like (a ~N Int)+ very_wrong _ (EqPred NomEq ty1 ty2) = isSkolemTy tc_lvl ty1 && isRigidTy ty2+ very_wrong _ _ = False++ -- Things like (a ~N b) or (a ~N F Bool)+ skolem_eq _ (EqPred NomEq ty1 _) = isSkolemTy tc_lvl ty1+ skolem_eq _ _ = False++ -- Things like (F a ~N Int)+ non_tv_eq _ (EqPred NomEq ty1 _) = not (isTyVarTy ty1)+ non_tv_eq _ _ = False++ is_out_of_scope ct _ = isOutOfScopeCt ct+ is_hole ct _ = isHoleCt ct++ is_user_type_error ct _ = isUserTypeErrorCt ct++ is_equality _ (EqPred {}) = True+ is_equality _ _ = False++ is_dict _ (ClassPred {}) = True+ is_dict _ _ = False++ is_ip _ (ClassPred cls _) = isIPClass cls+ is_ip _ _ = False++ is_irred _ (IrredPred {}) = True+ is_irred _ _ = False++ given_eq_spec = case find_gadt_match (cec_encl ctxt) of+ Just imp -> ("insoluble1a", is_given_eq, True, mkGivenErrorReporter imp)+ Nothing -> ("insoluble1b", is_given_eq, False, ignoreErrorReporter)+ -- False means don't suppress subsequent errors+ -- Reason: we don't report all given errors+ -- (see mkGivenErrorReporter), and we should only suppress+ -- subsequent errors if we actually report this one!+ -- Trac #13446 is an example++ find_gadt_match [] = Nothing+ find_gadt_match (implic : implics)+ | PatSkol {} <- ic_info implic+ , not (ic_no_eqs implic)+ = Just implic+ | otherwise+ = find_gadt_match implics++---------------+isSkolemTy :: TcLevel -> Type -> Bool+-- The type is a skolem tyvar+isSkolemTy tc_lvl ty+ | Just tv <- getTyVar_maybe ty+ = isSkolemTyVar tv+ || (isSigTyVar tv && isTouchableMetaTyVar tc_lvl tv)+ -- The last case is for touchable SigTvs+ -- we postpone untouchables to a latter test (too obscure)++ | otherwise+ = False++isTyFun_maybe :: Type -> Maybe TyCon+isTyFun_maybe ty = case tcSplitTyConApp_maybe ty of+ Just (tc,_) | isTypeFamilyTyCon tc -> Just tc+ _ -> Nothing++--------------------------------------------+-- Reporters+--------------------------------------------++type Reporter+ = ReportErrCtxt -> [Ct] -> TcM ()+type ReporterSpec+ = ( String -- Name+ , Ct -> PredTree -> Bool -- Pick these ones+ , Bool -- True <=> suppress subsequent reporters+ , Reporter) -- The reporter itself++mkSkolReporter :: Reporter+-- Suppress duplicates with either the same LHS, or same location+mkSkolReporter ctxt cts+ = mapM_ (reportGroup mkEqErr ctxt) (group cts)+ where+ group [] = []+ group (ct:cts) = (ct : yeses) : group noes+ where+ (yeses, noes) = partition (group_with ct) cts++ group_with ct1 ct2+ | EQ <- cmp_loc ct1 ct2 = True+ | eq_lhs_type ct1 ct2 = True+ | otherwise = False++mkHoleReporter :: Reporter+-- Reports errors one at a time+mkHoleReporter ctxt+ = mapM_ $ \ct -> do { err <- mkHoleError ctxt ct+ ; maybeReportHoleError ctxt ct err+ ; maybeAddDeferredHoleBinding ctxt err ct }++mkUserTypeErrorReporter :: Reporter+mkUserTypeErrorReporter ctxt+ = mapM_ $ \ct -> do { err <- mkUserTypeError ctxt ct+ ; maybeReportError ctxt err+ ; addDeferredBinding ctxt err ct }++mkUserTypeError :: ReportErrCtxt -> Ct -> TcM ErrMsg+mkUserTypeError ctxt ct = mkErrorMsgFromCt ctxt ct+ $ important+ $ pprUserTypeErrorTy+ $ case getUserTypeErrorMsg ct of+ Just msg -> msg+ Nothing -> pprPanic "mkUserTypeError" (ppr ct)+++mkGivenErrorReporter :: Implication -> Reporter+-- See Note [Given errors]+mkGivenErrorReporter implic ctxt cts+ = do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct+ ; dflags <- getDynFlags+ ; let ct' = setCtLoc ct (setCtLocEnv (ctLoc ct) (ic_env implic))+ -- For given constraints we overwrite the env (and hence src-loc)+ -- with one from the implication. See Note [Inaccessible code]++ inaccessible_msg = hang (text "Inaccessible code in")+ 2 (ppr (ic_info implic))+ report = important inaccessible_msg `mappend`+ relevant_bindings binds_msg++ ; err <- mkEqErr_help dflags ctxt report ct'+ Nothing ty1 ty2++ ; traceTc "mkGivenErrorRporter" (ppr ct)+ ; maybeReportError ctxt err }+ where+ (ct : _ ) = cts -- Never empty+ (ty1, ty2) = getEqPredTys (ctPred ct)++ignoreErrorReporter :: Reporter+-- Discard Given errors that don't come from+-- a pattern match; maybe we should warn instead?ignoreErrorReporter ctxt cts+ignoreErrorReporter ctxt cts+ = do { traceTc "mkGivenErrorRporter no" (ppr cts $$ ppr (cec_encl ctxt))+ ; return () }+++{- Note [Given errors]+~~~~~~~~~~~~~~~~~~~~~~+Given constraints represent things for which we have (or will have)+evidence, so they aren't errors. But if a Given constraint is+insoluble, this code is inaccessible, and we might want to at least+warn about that. A classic case is++ data T a where+ T1 :: T Int+ T2 :: T a+ T3 :: T Bool++ f :: T Int -> Bool+ f T1 = ...+ f T2 = ...+ f T3 = ... -- We want to report this case as inaccessible++We'd like to point out that the T3 match is inaccessible. It+will have a Given constraint [G] Int ~ Bool.++But we don't want to report ALL insoluble Given constraints. See Trac+#12466 for a long discussion on. For example, if we aren't careful+we'll complain about+ f :: ((Int ~ Bool) => a -> a) -> Int+which arguably is OK. It's more debatable for+ g :: (Int ~ Bool) => Int -> Int+but it's tricky to distinguish these cases to we don't report+either.++The bottom line is this: find_gadt_match looks for an encosing+pattern match which binds some equality constraints. If we+find one, we report the insoluble Given.+-}++mkGroupReporter :: (ReportErrCtxt -> [Ct] -> TcM ErrMsg)+ -- Make error message for a group+ -> Reporter -- Deal with lots of constraints+-- Group together errors from same location,+-- and report only the first (to avoid a cascade)+mkGroupReporter mk_err ctxt cts+ = mapM_ (reportGroup mk_err ctxt) (equivClasses cmp_loc cts)++eq_lhs_type :: Ct -> Ct -> Bool+eq_lhs_type ct1 ct2+ = case (classifyPredType (ctPred ct1), classifyPredType (ctPred ct2)) of+ (EqPred eq_rel1 ty1 _, EqPred eq_rel2 ty2 _) ->+ (eq_rel1 == eq_rel2) && (ty1 `eqType` ty2)+ _ -> pprPanic "mkSkolReporter" (ppr ct1 $$ ppr ct2)++cmp_loc :: Ct -> Ct -> Ordering+cmp_loc ct1 ct2 = ctLocSpan (ctLoc ct1) `compare` ctLocSpan (ctLoc ct2)++reportGroup :: (ReportErrCtxt -> [Ct] -> TcM ErrMsg) -> ReportErrCtxt+ -> [Ct] -> TcM ()+reportGroup mk_err ctxt cts =+ case partition isMonadFailInstanceMissing cts of+ -- Only warn about missing MonadFail constraint when+ -- there are no other missing constraints!+ (monadFailCts, []) ->+ do { err <- mk_err ctxt monadFailCts+ ; reportWarning (Reason Opt_WarnMissingMonadFailInstances) err }++ (_, cts') -> do { err <- mk_err ctxt cts'+ ; maybeReportError ctxt err+ -- But see Note [Always warn with -fdefer-type-errors]+ ; traceTc "reportGroup" (ppr cts')+ ; mapM_ (addDeferredBinding ctxt err) cts' }+ -- Add deferred bindings for all+ -- Redundant if we are going to abort compilation,+ -- but that's hard to know for sure, and if we don't+ -- abort, we need bindings for all (e.g. Trac #12156)+ where+ isMonadFailInstanceMissing ct =+ case ctLocOrigin (ctLoc ct) of+ FailablePattern _pat -> True+ _otherwise -> False++maybeReportHoleError :: ReportErrCtxt -> Ct -> ErrMsg -> TcM ()+maybeReportHoleError ctxt ct err+ -- When -XPartialTypeSignatures is on, warnings (instead of errors) are+ -- generated for holes in partial type signatures.+ -- Unless -fwarn_partial_type_signatures is not on,+ -- in which case the messages are discarded.+ | isTypeHoleCt ct+ = -- For partial type signatures, generate warnings only, and do that+ -- only if -fwarn_partial_type_signatures is on+ case cec_type_holes ctxt of+ HoleError -> reportError err+ HoleWarn -> reportWarning (Reason Opt_WarnPartialTypeSignatures) err+ HoleDefer -> return ()++ -- Always report an error for out-of-scope variables+ -- Unless -fdefer-out-of-scope-variables is on,+ -- in which case the messages are discarded.+ -- See Trac #12170, #12406+ | isOutOfScopeCt ct+ = -- If deferring, report a warning only if -Wout-of-scope-variables is on+ case cec_out_of_scope_holes ctxt of+ HoleError -> reportError err+ HoleWarn ->+ reportWarning (Reason Opt_WarnDeferredOutOfScopeVariables) err+ HoleDefer -> return ()++ -- Otherwise this is a typed hole in an expression,+ -- but not for an out-of-scope variable+ | otherwise+ = -- If deferring, report a warning only if -Wtyped-holes is on+ case cec_expr_holes ctxt of+ HoleError -> reportError err+ HoleWarn -> reportWarning (Reason Opt_WarnTypedHoles) err+ HoleDefer -> return ()++maybeReportError :: ReportErrCtxt -> ErrMsg -> TcM ()+-- Report the error and/or make a deferred binding for it+maybeReportError ctxt err+ | cec_suppress ctxt -- Some worse error has occurred;+ = return () -- so suppress this error/warning++ | cec_errors_as_warns ctxt+ = reportWarning NoReason err++ | otherwise+ = case cec_defer_type_errors ctxt of+ TypeDefer -> return ()+ TypeWarn -> reportWarning (Reason Opt_WarnDeferredTypeErrors) err+ TypeError -> reportError err++addDeferredBinding :: ReportErrCtxt -> ErrMsg -> Ct -> TcM ()+-- See Note [Deferring coercion errors to runtime]+addDeferredBinding ctxt err ct+ | CtWanted { ctev_pred = pred, ctev_dest = dest } <- ctEvidence ct+ -- Only add deferred bindings for Wanted constraints+ = do { dflags <- getDynFlags+ ; let err_msg = pprLocErrMsg err+ err_fs = mkFastString $ showSDoc dflags $+ err_msg $$ text "(deferred type error)"+ err_tm = EvDelayedError pred err_fs+ ev_binds_var = cec_binds ctxt++ ; case dest of+ EvVarDest evar+ -> addTcEvBind ev_binds_var $ mkWantedEvBind evar err_tm+ HoleDest hole+ -> do { -- See Note [Deferred errors for coercion holes]+ evar <- newEvVar pred+ ; addTcEvBind ev_binds_var $ mkWantedEvBind evar err_tm+ ; fillCoercionHole hole (mkTcCoVarCo evar) }}++ | otherwise -- Do not set any evidence for Given/Derived+ = return ()++maybeAddDeferredHoleBinding :: ReportErrCtxt -> ErrMsg -> Ct -> TcM ()+maybeAddDeferredHoleBinding ctxt err ct+ | isExprHoleCt ct+ = addDeferredBinding ctxt err ct -- Only add bindings for holes in expressions+ | otherwise -- not for holes in partial type signatures+ = return ()++tryReporters :: ReportErrCtxt -> [ReporterSpec] -> [Ct] -> TcM (ReportErrCtxt, [Ct])+-- Use the first reporter in the list whose predicate says True+tryReporters ctxt reporters cts+ = do { traceTc "tryReporters {" (ppr cts)+ ; (ctxt', cts') <- go ctxt reporters cts+ ; traceTc "tryReporters }" (ppr cts')+ ; return (ctxt', cts') }+ where+ go ctxt [] cts+ = return (ctxt, cts)++ go ctxt (r : rs) cts+ = do { (ctxt', cts') <- tryReporter ctxt r cts+ ; go ctxt' rs cts' }+ -- Carry on with the rest, because we must make+ -- deferred bindings for them if we have -fdefer-type-errors+ -- But suppress their error messages++tryReporter :: ReportErrCtxt -> ReporterSpec -> [Ct] -> TcM (ReportErrCtxt, [Ct])+tryReporter ctxt (str, keep_me, suppress_after, reporter) cts+ | null yeses = return (ctxt, cts)+ | otherwise = do { traceTc "tryReporter{ " (text str <+> ppr yeses)+ ; reporter ctxt yeses+ ; let ctxt' = ctxt { cec_suppress = suppress_after || cec_suppress ctxt }+ ; traceTc "tryReporter end }" (text str <+> ppr (cec_suppress ctxt) <+> ppr suppress_after)+ ; return (ctxt', nos) }+ where+ (yeses, nos) = partition (\ct -> keep_me ct (classifyPredType (ctPred ct))) cts+++pprArising :: CtOrigin -> SDoc+-- Used for the main, top-level error message+-- We've done special processing for TypeEq, KindEq, Given+pprArising (TypeEqOrigin {}) = empty+pprArising (KindEqOrigin {}) = empty+pprArising (GivenOrigin {}) = empty+pprArising orig = pprCtOrigin orig++-- Add the "arising from..." part to a message about bunch of dicts+addArising :: CtOrigin -> SDoc -> SDoc+addArising orig msg = hang msg 2 (pprArising orig)++pprWithArising :: [Ct] -> (CtLoc, SDoc)+-- Print something like+-- (Eq a) arising from a use of x at y+-- (Show a) arising from a use of p at q+-- Also return a location for the error message+-- Works for Wanted/Derived only+pprWithArising []+ = panic "pprWithArising"+pprWithArising (ct:cts)+ | null cts+ = (loc, addArising (ctLocOrigin loc)+ (pprTheta [ctPred ct]))+ | otherwise+ = (loc, vcat (map ppr_one (ct:cts)))+ where+ loc = ctLoc ct+ ppr_one ct' = hang (parens (pprType (ctPred ct')))+ 2 (pprCtLoc (ctLoc ct'))++mkErrorMsgFromCt :: ReportErrCtxt -> Ct -> Report -> TcM ErrMsg+mkErrorMsgFromCt ctxt ct report+ = mkErrorReport ctxt (ctLocEnv (ctLoc ct)) report++mkErrorReport :: ReportErrCtxt -> TcLclEnv -> Report -> TcM ErrMsg+mkErrorReport ctxt tcl_env (Report important relevant_bindings)+ = do { context <- mkErrInfo (cec_tidy ctxt) (tcl_ctxt tcl_env)+ ; mkErrDocAt (RealSrcSpan (tcl_loc tcl_env))+ (errDoc important [context] relevant_bindings)+ }++type UserGiven = Implication++getUserGivens :: ReportErrCtxt -> [UserGiven]+-- One item for each enclosing implication+getUserGivens (CEC {cec_encl = implics}) = getUserGivensFromImplics implics++getUserGivensFromImplics :: [Implication] -> [UserGiven]+getUserGivensFromImplics implics+ = reverse (filterOut (null . ic_given) implics)++{-+Note [Always warn with -fdefer-type-errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When -fdefer-type-errors is on we warn about *all* type errors, even+if cec_suppress is on. This can lead to a lot more warnings than you+would get errors without -fdefer-type-errors, but if we suppress any of+them you might get a runtime error that wasn't warned about at compile+time.++This is an easy design choice to change; just flip the order of the+first two equations for maybeReportError++To be consistent, we should also report multiple warnings from a single+location in mkGroupReporter, when -fdefer-type-errors is on. But that+is perhaps a bit *over*-consistent! Again, an easy choice to change.++With #10283, you can now opt out of deferred type error warnings.++Note [Deferred errors for coercion holes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we need to defer a type error where the destination for the evidence+is a coercion hole. We can't just put the error in the hole, because we can't+make an erroneous coercion. (Remember that coercions are erased for runtime.)+Instead, we invent a new EvVar, bind it to an error and then make a coercion+from that EvVar, filling the hole with that coercion. Because coercions'+types are unlifted, the error is guaranteed to be hit before we get to the+coercion.++Note [Do not report derived but soluble errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The wc_simples include Derived constraints that have not been solved, but are+not insoluble (in that case they'd be in wc_insols). We do not want to report+these as errors:++* Superclass constraints. If we have an unsolved [W] Ord a, we'll also have+ an unsolved [D] Eq a, and we do not want to report that; it's just noise.++* Functional dependencies. For givens, consider+ class C a b | a -> b+ data T a where+ MkT :: C a d => [d] -> T a+ f :: C a b => T a -> F Int+ f (MkT xs) = length xs+ Then we get a [D] b~d. But there *is* a legitimate call to+ f, namely f (MkT [True]) :: T Bool, in which b=d. So we should+ not reject the program.++ For wanteds, something similar+ data T a where+ MkT :: C Int b => a -> b -> T a+ g :: C Int c => c -> ()+ f :: T a -> ()+ f (MkT x y) = g x+ Here we get [G] C Int b, [W] C Int a, hence [D] a~b.+ But again f (MkT True True) is a legitimate call.++(We leave the Deriveds in wc_simple until reportErrors, so that we don't lose+derived superclasses between iterations of the solver.)++For functional dependencies, here is a real example,+stripped off from libraries/utf8-string/Codec/Binary/UTF8/Generic.hs++ class C a b | a -> b+ g :: C a b => a -> b -> ()+ f :: C a b => a -> b -> ()+ f xa xb =+ let loop = g xa+ in loop xb++We will first try to infer a type for loop, and we will succeed:+ C a b' => b' -> ()+Subsequently, we will type check (loop xb) and all is good. But,+recall that we have to solve a final implication constraint:+ C a b => (C a b' => .... cts from body of loop .... ))+And now we have a problem as we will generate an equality b ~ b' and fail to+solve it.+++************************************************************************+* *+ Irreducible predicate errors+* *+************************************************************************+-}++mkIrredErr :: ReportErrCtxt -> [Ct] -> TcM ErrMsg+mkIrredErr ctxt cts+ = do { (ctxt, binds_msg, ct1) <- relevantBindings True ctxt ct1+ ; let orig = ctOrigin ct1+ msg = couldNotDeduce (getUserGivens ctxt) (map ctPred cts, orig)+ ; mkErrorMsgFromCt ctxt ct1 $+ important msg `mappend` relevant_bindings binds_msg }+ where+ (ct1:_) = cts++----------------+mkHoleError :: ReportErrCtxt -> Ct -> TcM ErrMsg+mkHoleError _ctxt ct@(CHoleCan { cc_hole = ExprHole (OutOfScope occ rdr_env0) })+ -- Out-of-scope variables, like 'a', where 'a' isn't bound; suggest possible+ -- in-scope variables in the message, and note inaccessible exact matches+ = do { dflags <- getDynFlags+ ; imp_info <- getImports+ ; let suggs_msg = unknownNameSuggestions dflags rdr_env0+ (tcl_rdr lcl_env) imp_info rdr+ ; rdr_env <- getGlobalRdrEnv+ ; splice_locs <- getTopLevelSpliceLocs+ ; let match_msgs = mk_match_msgs rdr_env splice_locs+ ; mkErrDocAt (RealSrcSpan err_loc) $+ errDoc [out_of_scope_msg] [] (match_msgs ++ [suggs_msg]) }++ where+ rdr = mkRdrUnqual occ+ ct_loc = ctLoc ct+ lcl_env = ctLocEnv ct_loc+ err_loc = tcl_loc lcl_env+ hole_ty = ctEvPred (ctEvidence ct)+ boring_type = isTyVarTy hole_ty++ out_of_scope_msg -- Print v :: ty only if the type has structure+ | boring_type = hang herald 2 (ppr occ)+ | otherwise = hang herald 2 (pp_with_type occ hole_ty)++ herald | isDataOcc occ = text "Data constructor not in scope:"+ | otherwise = text "Variable not in scope:"++ -- Indicate if the out-of-scope variable exactly (and unambiguously) matches+ -- a top-level binding in a later inter-splice group; see Note [OutOfScope+ -- exact matches]+ mk_match_msgs rdr_env splice_locs+ = let gres = filter isLocalGRE (lookupGlobalRdrEnv rdr_env occ)+ in case gres of+ [gre]+ | RealSrcSpan bind_loc <- greSrcSpan gre+ -- Find splice between the unbound variable and the match; use+ -- lookupLE, not lookupLT, since match could be in the splice+ , Just th_loc <- Set.lookupLE bind_loc splice_locs+ , err_loc < th_loc+ -> [mk_bind_scope_msg bind_loc th_loc]+ _ -> []++ mk_bind_scope_msg bind_loc th_loc+ | is_th_bind+ = hang (quotes (ppr occ) <+> parens (text "splice on" <+> th_rng))+ 2 (text "is not in scope before line" <+> int th_start_ln)+ | otherwise+ = hang (quotes (ppr occ) <+> bind_rng <+> text "is not in scope")+ 2 (text "before the splice on" <+> th_rng)+ where+ bind_rng = parens (text "line" <+> int bind_ln)+ th_rng+ | th_start_ln == th_end_ln = single+ | otherwise = multi+ single = text "line" <+> int th_start_ln+ multi = text "lines" <+> int th_start_ln <> text "-" <> int th_end_ln+ bind_ln = srcSpanStartLine bind_loc+ th_start_ln = srcSpanStartLine th_loc+ th_end_ln = srcSpanEndLine th_loc+ is_th_bind = th_loc `containsSpan` bind_loc++mkHoleError ctxt ct@(CHoleCan { cc_hole = hole })+ -- Explicit holes, like "_" or "_f"+ = do { (ctxt, binds_msg, ct) <- relevantBindings False ctxt ct+ -- The 'False' means "don't filter the bindings"; see Trac #8191++ ; show_hole_constraints <- goptM Opt_ShowHoleConstraints+ ; let constraints_msg+ | isExprHoleCt ct, show_hole_constraints+ = givenConstraintsMsg ctxt+ | otherwise = empty++ ; mkErrorMsgFromCt ctxt ct $+ important hole_msg `mappend`+ relevant_bindings (binds_msg $$ constraints_msg) }++ where+ occ = holeOcc hole+ hole_ty = ctEvPred (ctEvidence ct)+ tyvars = tyCoVarsOfTypeList hole_ty++ hole_msg = case hole of+ ExprHole {} -> vcat [ hang (text "Found hole:")+ 2 (pp_with_type occ hole_ty)+ , tyvars_msg, expr_hole_hint ]+ TypeHole {} -> vcat [ hang (text "Found type wildcard" <+>+ quotes (ppr occ))+ 2 (text "standing for" <+>+ quotes (pprType hole_ty))+ , tyvars_msg, type_hole_hint ]++ tyvars_msg = ppUnless (null tyvars) $+ text "Where:" <+> vcat (map loc_msg tyvars)++ type_hole_hint+ | HoleError <- cec_type_holes ctxt+ = text "To use the inferred type, enable PartialTypeSignatures"+ | otherwise+ = empty++ expr_hole_hint -- Give hint for, say, f x = _x+ | lengthFS (occNameFS occ) > 1 -- Don't give this hint for plain "_"+ = text "Or perhaps" <+> quotes (ppr occ)+ <+> text "is mis-spelled, or not in scope"+ | otherwise+ = empty++ loc_msg tv+ | isTyVar tv+ = case tcTyVarDetails tv of+ MetaTv {} -> quotes (ppr tv) <+> text "is an ambiguous type variable"+ _ -> extraTyVarInfo ctxt tv+ | otherwise+ = sdocWithDynFlags $ \dflags ->+ if gopt Opt_PrintExplicitCoercions dflags+ then quotes (ppr tv) <+> text "is a coercion variable"+ else empty++mkHoleError _ ct = pprPanic "mkHoleError" (ppr ct)+++-- See Note [Constraints include ...]+givenConstraintsMsg :: ReportErrCtxt -> SDoc+givenConstraintsMsg ctxt =+ let constraints :: [(Type, RealSrcSpan)]+ constraints =+ do { Implic{ ic_given = given, ic_env = env } <- cec_encl ctxt+ ; constraint <- given+ ; return (varType constraint, tcl_loc env) }++ pprConstraint (constraint, loc) =+ ppr constraint <+> nest 2 (parens (text "from" <+> ppr loc))++ in ppUnless (null constraints) $+ hang (text "Constraints include")+ 2 (vcat $ map pprConstraint constraints)++pp_with_type :: OccName -> Type -> SDoc+pp_with_type occ ty = hang (pprPrefixOcc occ) 2 (dcolon <+> pprType ty)++----------------+mkIPErr :: ReportErrCtxt -> [Ct] -> TcM ErrMsg+mkIPErr ctxt cts+ = do { (ctxt, binds_msg, ct1) <- relevantBindings True ctxt ct1+ ; let orig = ctOrigin ct1+ preds = map ctPred cts+ givens = getUserGivens ctxt+ msg | null givens+ = addArising orig $+ sep [ text "Unbound implicit parameter" <> plural cts+ , nest 2 (pprTheta preds) ]+ | otherwise+ = couldNotDeduce givens (preds, orig)++ ; mkErrorMsgFromCt ctxt ct1 $+ important msg `mappend` relevant_bindings binds_msg }+ where+ (ct1:_) = cts++{-+Note [Constraints include ...]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+'givenConstraintsMsg' returns the "Constraints include ..." message enabled by+-fshow-hole-constraints. For example, the following hole:++ foo :: (Eq a, Show a) => a -> String+ foo x = _++would generate the message:++ Constraints include+ Eq a (from foo.hs:1:1-36)+ Show a (from foo.hs:1:1-36)++Constraints are displayed in order from innermost (closest to the hole) to+outermost. There's currently no filtering or elimination of duplicates.+++Note [OutOfScope exact matches]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When constructing an out-of-scope error message, we not only generate a list of+possible in-scope alternatives but also search for an exact, unambiguous match+in a later inter-splice group. If we find such a match, we report its presence+(and indirectly, its scope) in the message. For example, if a module A contains+the following declarations,++ foo :: Int+ foo = x++ $(return []) -- Empty top-level splice++ x :: Int+ x = 23++we will issue an error similar to++ A.hs:6:7: error:+ • Variable not in scope: x :: Int+ • ‘x’ (line 11) is not in scope before the splice on line 8++By providing information about the match, we hope to clarify why declaring a+variable after a top-level splice but using it before the splice generates an+out-of-scope error (a situation which is often confusing to Haskell newcomers).++Note that if we find multiple exact matches to the out-of-scope variable+(hereafter referred to as x), we report nothing. Such matches can only be+duplicate record fields, as the presence of any other duplicate top-level+declarations would have already halted compilation. But if these record fields+are declared in a later inter-splice group, then so too are their corresponding+types. Thus, these types must not occur in the inter-splice group containing x+(any unknown types would have already been reported), and so the matches to the+record fields are most likely coincidental.++One oddity of the exact match portion of the error message is that we specify+where the match to x is NOT in scope. Why not simply state where the match IS+in scope? It most cases, this would be just as easy and perhaps a little+clearer for the user. But now consider the following example:++ {-# LANGUAGE TemplateHaskell #-}++ module A where++ import Language.Haskell.TH+ import Language.Haskell.TH.Syntax++ foo = x++ $(do -------------------------------------------------+ ds <- [d| ok1 = x+ |]+ addTopDecls ds+ return [])++ bar = $(do+ ds <- [d| x = 23+ ok2 = x+ |]+ addTopDecls ds+ litE $ stringL "hello")++ $(return []) -----------------------------------------++ ok3 = x++Here, x is out-of-scope in the declaration of foo, and so we report++ A.hs:8:7: error:+ • Variable not in scope: x+ • ‘x’ (line 16) is not in scope before the splice on lines 10-14++If we instead reported where x IS in scope, we would have to state that it is in+scope after the second top-level splice as well as among all the top-level+declarations added by both calls to addTopDecls. But doing so would not only+add complexity to the code but also overwhelm the user with unneeded+information.++The logic which determines where x is not in scope is straightforward: it simply+finds the last top-level splice which occurs after x but before (or at) the+match to x (assuming such a splice exists). In most cases, the check that the+splice occurs after x acts only as a sanity check. For example, when the match+to x is a non-TH top-level declaration and a splice S occurs before the match,+then x must precede S; otherwise, it would be in scope. But when dealing with+addTopDecls, this check serves a practical purpose. Consider the following+declarations:++ $(do+ ds <- [d| ok = x+ x = 23+ |]+ addTopDecls ds+ return [])++ foo = x++In this case, x is not in scope in the declaration for foo. Since x occurs+AFTER the splice containing the match, the logic does not find any splices after+x but before or at its match, and so we report nothing about x's scope. If we+had not checked whether x occurs before the splice, we would have instead+reported that x is not in scope before the splice. While correct, such an error+message is more likely to confuse than to enlighten.+-}++{-+************************************************************************+* *+ Equality errors+* *+************************************************************************++Note [Inaccessible code]+~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T a where+ T1 :: T a+ T2 :: T Bool++ f :: (a ~ Int) => T a -> Int+ f T1 = 3+ f T2 = 4 -- Unreachable code++Here the second equation is unreachable. The original constraint+(a~Int) from the signature gets rewritten by the pattern-match to+(Bool~Int), so the danger is that we report the error as coming from+the *signature* (Trac #7293). So, for Given errors we replace the+env (and hence src-loc) on its CtLoc with that from the immediately+enclosing implication.++Note [Error messages for untouchables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #9109)+ data G a where { GBool :: G Bool }+ foo x = case x of GBool -> True++Here we can't solve (t ~ Bool), where t is the untouchable result+meta-var 't', because of the (a ~ Bool) from the pattern match.+So we infer the type+ f :: forall a t. G a -> t+making the meta-var 't' into a skolem. So when we come to report+the unsolved (t ~ Bool), t won't look like an untouchable meta-var+any more. So we don't assert that it is.+-}++mkEqErr :: ReportErrCtxt -> [Ct] -> TcM ErrMsg+-- Don't have multiple equality errors from the same location+-- E.g. (Int,Bool) ~ (Bool,Int) one error will do!+mkEqErr ctxt (ct:_) = mkEqErr1 ctxt ct+mkEqErr _ [] = panic "mkEqErr"++mkEqErr1 :: ReportErrCtxt -> Ct -> TcM ErrMsg+mkEqErr1 ctxt ct -- Wanted or derived;+ -- givens handled in mkGivenErrorReporter+ = do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct+ ; rdr_env <- getGlobalRdrEnv+ ; fam_envs <- tcGetFamInstEnvs+ ; exp_syns <- goptM Opt_PrintExpandedSynonyms+ ; let (keep_going, is_oriented, wanted_msg)+ = mk_wanted_extra (ctLoc ct) exp_syns+ coercible_msg = case ctEqRel ct of+ NomEq -> empty+ ReprEq -> mkCoercibleExplanation rdr_env fam_envs ty1 ty2+ ; dflags <- getDynFlags+ ; traceTc "mkEqErr1" (ppr ct $$ pprCtOrigin (ctOrigin ct))+ ; let report = mconcat [important wanted_msg, important coercible_msg,+ relevant_bindings binds_msg]+ ; if keep_going+ then mkEqErr_help dflags ctxt report ct is_oriented ty1 ty2+ else mkErrorMsgFromCt ctxt ct report }+ where+ (ty1, ty2) = getEqPredTys (ctPred ct)++ -- If the types in the error message are the same as the types+ -- we are unifying, don't add the extra expected/actual message+ mk_wanted_extra :: CtLoc -> Bool -> (Bool, Maybe SwapFlag, SDoc)+ mk_wanted_extra loc expandSyns+ = case ctLocOrigin loc of+ orig@TypeEqOrigin {} -> mkExpectedActualMsg ty1 ty2 orig+ t_or_k expandSyns+ where+ t_or_k = ctLocTypeOrKind_maybe loc++ KindEqOrigin cty1 mb_cty2 sub_o sub_t_or_k+ -> (True, Nothing, msg1 $$ msg2)+ where+ sub_what = case sub_t_or_k of Just KindLevel -> text "kinds"+ _ -> text "types"+ msg1 = sdocWithDynFlags $ \dflags ->+ case mb_cty2 of+ Just cty2+ | gopt Opt_PrintExplicitCoercions dflags+ || not (cty1 `pickyEqType` cty2)+ -> hang (text "When matching" <+> sub_what)+ 2 (vcat [ ppr cty1 <+> dcolon <+>+ ppr (typeKind cty1)+ , ppr cty2 <+> dcolon <+>+ ppr (typeKind cty2) ])+ _ -> text "When matching the kind of" <+> quotes (ppr cty1)+ msg2 = case sub_o of+ TypeEqOrigin {}+ | Just cty2 <- mb_cty2 ->+ thdOf3 (mkExpectedActualMsg cty1 cty2 sub_o sub_t_or_k+ expandSyns)+ _ -> empty+ _ -> (True, Nothing, empty)++-- | This function tries to reconstruct why a "Coercible ty1 ty2" constraint+-- is left over.+mkCoercibleExplanation :: GlobalRdrEnv -> FamInstEnvs+ -> TcType -> TcType -> SDoc+mkCoercibleExplanation rdr_env fam_envs ty1 ty2+ | Just (tc, tys) <- tcSplitTyConApp_maybe ty1+ , (rep_tc, _, _) <- tcLookupDataFamInst fam_envs tc tys+ , Just msg <- coercible_msg_for_tycon rep_tc+ = msg+ | Just (tc, tys) <- splitTyConApp_maybe ty2+ , (rep_tc, _, _) <- tcLookupDataFamInst fam_envs tc tys+ , Just msg <- coercible_msg_for_tycon rep_tc+ = msg+ | Just (s1, _) <- tcSplitAppTy_maybe ty1+ , Just (s2, _) <- tcSplitAppTy_maybe ty2+ , s1 `eqType` s2+ , has_unknown_roles s1+ = hang (text "NB: We cannot know what roles the parameters to" <+>+ quotes (ppr s1) <+> text "have;")+ 2 (text "we must assume that the role is nominal")+ | otherwise+ = empty+ where+ coercible_msg_for_tycon tc+ | isAbstractTyCon tc+ = Just $ hsep [ text "NB: The type constructor"+ , quotes (pprSourceTyCon tc)+ , text "is abstract" ]+ | isNewTyCon tc+ , [data_con] <- tyConDataCons tc+ , let dc_name = dataConName data_con+ , isNothing (lookupGRE_Name rdr_env dc_name)+ = Just $ hang (text "The data constructor" <+> quotes (ppr dc_name))+ 2 (sep [ text "of newtype" <+> quotes (pprSourceTyCon tc)+ , text "is not in scope" ])+ | otherwise = Nothing++ has_unknown_roles ty+ | Just (tc, tys) <- tcSplitTyConApp_maybe ty+ = length tys >= tyConArity tc -- oversaturated tycon+ | Just (s, _) <- tcSplitAppTy_maybe ty+ = has_unknown_roles s+ | isTyVarTy ty+ = True+ | otherwise+ = False++{-+-- | Make a listing of role signatures for all the parameterised tycons+-- used in the provided types+++-- SLPJ Jun 15: I could not convince myself that these hints were really+-- useful. Maybe they are, but I think we need more work to make them+-- actually helpful.+mkRoleSigs :: Type -> Type -> SDoc+mkRoleSigs ty1 ty2+ = ppUnless (null role_sigs) $+ hang (text "Relevant role signatures:")+ 2 (vcat role_sigs)+ where+ tcs = nameEnvElts $ tyConsOfType ty1 `plusNameEnv` tyConsOfType ty2+ role_sigs = mapMaybe ppr_role_sig tcs++ ppr_role_sig tc+ | null roles -- if there are no parameters, don't bother printing+ = Nothing+ | isBuiltInSyntax (tyConName tc) -- don't print roles for (->), etc.+ = Nothing+ | otherwise+ = Just $ hsep $ [text "type role", ppr tc] ++ map ppr roles+ where+ roles = tyConRoles tc+-}++mkEqErr_help :: DynFlags -> ReportErrCtxt -> Report+ -> Ct+ -> Maybe SwapFlag -- Nothing <=> not sure+ -> TcType -> TcType -> TcM ErrMsg+mkEqErr_help dflags ctxt report ct oriented ty1 ty2+ | Just tv1 <- tcGetTyVar_maybe ty1 = mkTyVarEqErr dflags ctxt report ct oriented tv1 ty2+ | Just tv2 <- tcGetTyVar_maybe ty2 = mkTyVarEqErr dflags ctxt report ct swapped tv2 ty1+ | otherwise = reportEqErr ctxt report ct oriented ty1 ty2+ where+ swapped = fmap flipSwap oriented++reportEqErr :: ReportErrCtxt -> Report+ -> Ct+ -> Maybe SwapFlag -- Nothing <=> not sure+ -> TcType -> TcType -> TcM ErrMsg+reportEqErr ctxt report ct oriented ty1 ty2+ = mkErrorMsgFromCt ctxt ct (mconcat [misMatch, report, eqInfo])+ where misMatch = important $ misMatchOrCND ctxt ct oriented ty1 ty2+ eqInfo = important $ mkEqInfoMsg ct ty1 ty2++mkTyVarEqErr :: DynFlags -> ReportErrCtxt -> Report -> Ct+ -> Maybe SwapFlag -> TcTyVar -> TcType -> TcM ErrMsg+-- tv1 and ty2 are already tidied+mkTyVarEqErr dflags ctxt report ct oriented tv1 ty2+ | isUserSkolem ctxt tv1 -- ty2 won't be a meta-tyvar, or else the thing would+ -- be oriented the other way round;+ -- see TcCanonical.canEqTyVarTyVar+ || isSigTyVar tv1 && not (isTyVarTy ty2)+ || ctEqRel ct == ReprEq && not insoluble_occurs_check+ -- the cases below don't really apply to ReprEq (except occurs check)+ = mkErrorMsgFromCt ctxt ct $ mconcat+ [ important $ misMatchOrCND ctxt ct oriented ty1 ty2+ , important $ extraTyVarEqInfo ctxt tv1 ty2+ , report+ ]++ | OC_Occurs <- occ_check_expand+ -- We report an "occurs check" even for a ~ F t a, where F is a type+ -- function; it's not insouble (because in principle F could reduce)+ -- but we have certainly been unable to solve it+ -- See Note [Occurs check error] in TcCanonical+ = do { let main_msg = addArising (ctOrigin ct) $+ hang (text "Occurs check: cannot construct the infinite" <+> what <> colon)+ 2 (sep [ppr ty1, char '~', ppr ty2])++ extra2 = important $ mkEqInfoMsg ct ty1 ty2++ interesting_tyvars = filter (not . noFreeVarsOfType . tyVarKind) $+ filter isTyVar $+ fvVarList $+ tyCoFVsOfType ty1 `unionFV` tyCoFVsOfType ty2+ extra3 = relevant_bindings $+ ppWhen (not (null interesting_tyvars)) $+ hang (text "Type variable kinds:") 2 $+ vcat (map (tyvar_binding . tidyTyVarOcc (cec_tidy ctxt))+ interesting_tyvars)++ tyvar_binding tv = ppr tv <+> dcolon <+> ppr (tyVarKind tv)+ ; mkErrorMsgFromCt ctxt ct $+ mconcat [important main_msg, extra2, extra3, report] }++ | OC_Bad <- occ_check_expand+ = do { let msg = vcat [ text "Cannot instantiate unification variable"+ <+> quotes (ppr tv1)+ , hang (text "with a" <+> what <+> text "involving foralls:") 2 (ppr ty2)+ , nest 2 (text "GHC doesn't yet support impredicative polymorphism") ]+ -- Unlike the other reports, this discards the old 'report_important'+ -- instead of augmenting it. This is because the details are not likely+ -- to be helpful since this is just an unimplemented feature.+ ; mkErrorMsgFromCt ctxt ct $ report { report_important = [msg] } }++ -- If the immediately-enclosing implication has 'tv' a skolem, and+ -- we know by now its an InferSkol kind of skolem, then presumably+ -- it started life as a SigTv, else it'd have been unified, given+ -- that there's no occurs-check or forall problem+ | (implic:_) <- cec_encl ctxt+ , Implic { ic_skols = skols } <- implic+ , tv1 `elem` skols+ = mkErrorMsgFromCt ctxt ct $ mconcat+ [ important $ misMatchMsg ct oriented ty1 ty2+ , important $ extraTyVarEqInfo ctxt tv1 ty2+ , report+ ]++ -- Check for skolem escape+ | (implic:_) <- cec_encl ctxt -- Get the innermost context+ , Implic { ic_env = env, ic_skols = skols, ic_info = skol_info } <- implic+ , let esc_skols = filter (`elemVarSet` (tyCoVarsOfType ty2)) skols+ , not (null esc_skols)+ = do { let msg = important $ misMatchMsg ct oriented ty1 ty2+ esc_doc = sep [ text "because" <+> what <+> text "variable" <> plural esc_skols+ <+> pprQuotedList esc_skols+ , text "would escape" <+>+ if isSingleton esc_skols then text "its scope"+ else text "their scope" ]+ tv_extra = important $+ vcat [ nest 2 $ esc_doc+ , sep [ (if isSingleton esc_skols+ then text "This (rigid, skolem)" <+>+ what <+> text "variable is"+ else text "These (rigid, skolem)" <+>+ what <+> text "variables are")+ <+> text "bound by"+ , nest 2 $ ppr skol_info+ , nest 2 $ text "at" <+> ppr (tcl_loc env) ] ]+ ; mkErrorMsgFromCt ctxt ct (mconcat [msg, tv_extra, report]) }++ -- Nastiest case: attempt to unify an untouchable variable+ -- So tv is a meta tyvar (or started that way before we+ -- generalised it). So presumably it is an *untouchable*+ -- meta tyvar or a SigTv, else it'd have been unified+ -- See Note [Error messages for untouchables]+ | (implic:_) <- cec_encl ctxt -- Get the innermost context+ , Implic { ic_env = env, ic_given = given+ , ic_tclvl = lvl, ic_info = skol_info } <- implic+ = ASSERT2( not (isTouchableMetaTyVar lvl tv1)+ , ppr tv1 ) -- See Note [Error messages for untouchables]+ do { let msg = important $ misMatchMsg ct oriented ty1 ty2+ tclvl_extra = important $+ nest 2 $+ sep [ quotes (ppr tv1) <+> text "is untouchable"+ , nest 2 $ text "inside the constraints:" <+> pprEvVarTheta given+ , nest 2 $ text "bound by" <+> ppr skol_info+ , nest 2 $ text "at" <+> ppr (tcl_loc env) ]+ tv_extra = important $ extraTyVarEqInfo ctxt tv1 ty2+ add_sig = important $ suggestAddSig ctxt ty1 ty2+ ; mkErrorMsgFromCt ctxt ct $ mconcat+ [msg, tclvl_extra, tv_extra, add_sig, report] }++ | otherwise+ = reportEqErr ctxt report ct oriented (mkTyVarTy tv1) ty2+ -- This *can* happen (Trac #6123, and test T2627b)+ -- Consider an ambiguous top-level constraint (a ~ F a)+ -- Not an occurs check, because F is a type function.+ where+ ty1 = mkTyVarTy tv1+ occ_check_expand = occCheckForErrors dflags tv1 ty2+ insoluble_occurs_check = isInsolubleOccursCheck (ctEqRel ct) tv1 ty2++ what = case ctLocTypeOrKind_maybe (ctLoc ct) of+ Just KindLevel -> text "kind"+ _ -> text "type"++mkEqInfoMsg :: Ct -> TcType -> TcType -> SDoc+-- Report (a) ambiguity if either side is a type function application+-- e.g. F a0 ~ Int+-- (b) warning about injectivity if both sides are the same+-- type function application F a ~ F b+-- See Note [Non-injective type functions]+-- (c) warning about -fprint-explicit-kinds if that might be helpful+mkEqInfoMsg ct ty1 ty2+ = tyfun_msg $$ ambig_msg $$ invis_msg+ where+ mb_fun1 = isTyFun_maybe ty1+ mb_fun2 = isTyFun_maybe ty2++ ambig_msg | isJust mb_fun1 || isJust mb_fun2+ = snd (mkAmbigMsg False ct)+ | otherwise = empty++ -- better to check the exp/act types in the CtOrigin than the actual+ -- mismatched types for suggestion about -fprint-explicit-kinds+ (act_ty, exp_ty) = case ctOrigin ct of+ TypeEqOrigin { uo_actual = act+ , uo_expected = exp } -> (act, exp)+ _ -> (ty1, ty2)++ invis_msg | Just vis <- tcEqTypeVis act_ty exp_ty+ , not vis+ = ppSuggestExplicitKinds+ | otherwise+ = empty++ tyfun_msg | Just tc1 <- mb_fun1+ , Just tc2 <- mb_fun2+ , tc1 == tc2+ = text "NB:" <+> quotes (ppr tc1)+ <+> text "is a type function, and may not be injective"+ | otherwise = empty++isUserSkolem :: ReportErrCtxt -> TcTyVar -> Bool+-- See Note [Reporting occurs-check errors]+isUserSkolem ctxt tv+ = isSkolemTyVar tv && any is_user_skol_tv (cec_encl ctxt)+ where+ is_user_skol_tv (Implic { ic_skols = sks, ic_info = skol_info })+ = tv `elem` sks && is_user_skol_info skol_info++ is_user_skol_info (InferSkol {}) = False+ is_user_skol_info _ = True++misMatchOrCND :: ReportErrCtxt -> Ct+ -> Maybe SwapFlag -> TcType -> TcType -> SDoc+-- If oriented then ty1 is actual, ty2 is expected+misMatchOrCND ctxt ct oriented ty1 ty2+ | null givens ||+ (isRigidTy ty1 && isRigidTy ty2) ||+ isGivenCt ct+ -- If the equality is unconditionally insoluble+ -- or there is no context, don't report the context+ = misMatchMsg ct oriented ty1 ty2+ | otherwise+ = couldNotDeduce givens ([eq_pred], orig)+ where+ ev = ctEvidence ct+ eq_pred = ctEvPred ev+ orig = ctEvOrigin ev+ givens = [ given | given <- getUserGivens ctxt, not (ic_no_eqs given)]+ -- Keep only UserGivens that have some equalities++couldNotDeduce :: [UserGiven] -> (ThetaType, CtOrigin) -> SDoc+couldNotDeduce givens (wanteds, orig)+ = vcat [ addArising orig (text "Could not deduce:" <+> pprTheta wanteds)+ , vcat (pp_givens givens)]++pp_givens :: [UserGiven] -> [SDoc]+pp_givens givens+ = case givens of+ [] -> []+ (g:gs) -> ppr_given (text "from the context:") g+ : map (ppr_given (text "or from:")) gs+ where+ ppr_given herald (Implic { ic_given = gs, ic_info = skol_info+ , ic_env = env })+ = hang (herald <+> pprEvVarTheta gs)+ 2 (sep [ text "bound by" <+> ppr skol_info+ , text "at" <+> ppr (tcl_loc env) ])++extraTyVarEqInfo :: ReportErrCtxt -> TcTyVar -> TcType -> SDoc+-- Add on extra info about skolem constants+-- NB: The types themselves are already tidied+extraTyVarEqInfo ctxt tv1 ty2+ = extraTyVarInfo ctxt tv1 $$ ty_extra ty2+ where+ ty_extra ty = case tcGetTyVar_maybe ty of+ Just tv -> extraTyVarInfo ctxt tv+ Nothing -> empty++extraTyVarInfo :: ReportErrCtxt -> TcTyVar -> SDoc+extraTyVarInfo ctxt tv+ = ASSERT2( isTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ SkolemTv {} -> pprSkol implics tv+ FlatSkol {} -> pp_tv <+> text "is a flattening type variable"+ RuntimeUnk {} -> pp_tv <+> text "is an interactive-debugger skolem"+ MetaTv {} -> empty+ where+ implics = cec_encl ctxt+ pp_tv = quotes (ppr tv)++suggestAddSig :: ReportErrCtxt -> TcType -> TcType -> SDoc+-- See Note [Suggest adding a type signature]+suggestAddSig ctxt ty1 ty2+ | null inferred_bndrs+ = empty+ | [bndr] <- inferred_bndrs+ = text "Possible fix: add a type signature for" <+> quotes (ppr bndr)+ | otherwise+ = text "Possible fix: add type signatures for some or all of" <+> (ppr inferred_bndrs)+ where+ inferred_bndrs = nub (get_inf ty1 ++ get_inf ty2)+ get_inf ty | Just tv <- tcGetTyVar_maybe ty+ , isSkolemTyVar tv+ , InferSkol prs <- ic_info (getSkolemInfo (cec_encl ctxt) tv)+ = map fst prs+ | otherwise+ = []++--------------------+misMatchMsg :: Ct -> Maybe SwapFlag -> TcType -> TcType -> SDoc+-- Types are already tidy+-- If oriented then ty1 is actual, ty2 is expected+misMatchMsg ct oriented ty1 ty2+ | Just NotSwapped <- oriented+ = misMatchMsg ct (Just IsSwapped) ty2 ty1++ -- These next two cases are when we're about to report, e.g., that+ -- 'LiftedRep doesn't match 'VoidRep. Much better just to say+ -- lifted vs. unlifted+ | Just (tc1, []) <- splitTyConApp_maybe ty1+ , tc1 `hasKey` liftedRepDataConKey+ = lifted_vs_unlifted++ | Just (tc2, []) <- splitTyConApp_maybe ty2+ , tc2 `hasKey` liftedRepDataConKey+ = lifted_vs_unlifted++ | otherwise -- So now we have Nothing or (Just IsSwapped)+ -- For some reason we treat Nothing like IsSwapped+ = addArising orig $+ sep [ text herald1 <+> quotes (ppr ty1)+ , nest padding $+ text herald2 <+> quotes (ppr ty2)+ , sameOccExtra ty2 ty1 ]+ where+ herald1 = conc [ "Couldn't match"+ , if is_repr then "representation of" else ""+ , if is_oriented then "expected" else ""+ , what ]+ herald2 = conc [ "with"+ , if is_repr then "that of" else ""+ , if is_oriented then ("actual " ++ what) else "" ]+ padding = length herald1 - length herald2++ is_repr = case ctEqRel ct of { ReprEq -> True; NomEq -> False }+ is_oriented = isJust oriented++ orig = ctOrigin ct+ what = case ctLocTypeOrKind_maybe (ctLoc ct) of+ Just KindLevel -> "kind"+ _ -> "type"++ conc :: [String] -> String+ conc = foldr1 add_space++ add_space :: String -> String -> String+ add_space s1 s2 | null s1 = s2+ | null s2 = s1+ | otherwise = s1 ++ (' ' : s2)++ lifted_vs_unlifted+ = addArising orig $+ text "Couldn't match a lifted type with an unlifted type"++mkExpectedActualMsg :: Type -> Type -> CtOrigin -> Maybe TypeOrKind -> Bool+ -> (Bool, Maybe SwapFlag, SDoc)+-- NotSwapped means (actual, expected), IsSwapped is the reverse+-- First return val is whether or not to print a herald above this msg+mkExpectedActualMsg ty1 ty2 (TypeEqOrigin { uo_actual = act+ , uo_expected = exp+ , uo_thing = maybe_thing })+ m_level printExpanded+ | KindLevel <- level, occurs_check_error = (True, Nothing, empty)+ | isUnliftedTypeKind act, isLiftedTypeKind exp = (False, Nothing, msg2)+ | isLiftedTypeKind act, isUnliftedTypeKind exp = (False, Nothing, msg3)+ | isLiftedTypeKind exp && not (isConstraintKind exp)+ = (False, Nothing, msg4)+ | Just msg <- num_args_msg = (False, Nothing, msg $$ msg1)+ | KindLevel <- level, Just th <- maybe_thing = (False, Nothing, msg5 th)+ | act `pickyEqType` ty1, exp `pickyEqType` ty2 = (True, Just NotSwapped, empty)+ | exp `pickyEqType` ty1, act `pickyEqType` ty2 = (True, Just IsSwapped, empty)+ | otherwise = (True, Nothing, msg1)+ where+ level = m_level `orElse` TypeLevel++ occurs_check_error+ | Just act_tv <- tcGetTyVar_maybe act+ , act_tv `elemVarSet` tyCoVarsOfType exp+ = True+ | Just exp_tv <- tcGetTyVar_maybe exp+ , exp_tv `elemVarSet` tyCoVarsOfType act+ = True+ | otherwise+ = False++ sort = case level of+ TypeLevel -> text "type"+ KindLevel -> text "kind"++ msg1 = case level of+ KindLevel+ | Just th <- maybe_thing+ -> msg5 th++ _ | not (act `pickyEqType` exp)+ -> vcat [ text "Expected" <+> sort <> colon <+> ppr exp+ , text " Actual" <+> sort <> colon <+> ppr act+ , if printExpanded then expandedTys else empty ]++ | otherwise+ -> empty++ thing_msg = case maybe_thing of+ Just thing -> \_ -> quotes (ppr thing) <+> text "is"+ Nothing -> \vowel -> text "got a" <>+ if vowel then char 'n' else empty+ msg2 = sep [ text "Expecting a lifted type, but"+ , thing_msg True, text "unlifted" ]+ msg3 = sep [ text "Expecting an unlifted type, but"+ , thing_msg False, text "lifted" ]+ msg4 = maybe_num_args_msg $$+ sep [ text "Expected a type, but"+ , maybe (text "found something with kind")+ (\thing -> quotes (ppr thing) <+> text "has kind")+ maybe_thing+ , quotes (ppr act) ]++ msg5 th = hang (text "Expected" <+> kind_desc <> comma)+ 2 (text "but" <+> quotes (ppr th) <+> text "has kind" <+>+ quotes (ppr act))+ where+ kind_desc | isConstraintKind exp = text "a constraint"+ | otherwise = text "kind" <+> quotes (ppr exp)++ num_args_msg = case level of+ TypeLevel -> Nothing+ KindLevel+ -> let n_act = count_args act+ n_exp = count_args exp in+ case n_act - n_exp of+ n | n /= 0+ , Just thing <- maybe_thing+ , case errorThingNumArgs_maybe thing of+ Nothing -> n > 0+ Just num_act_args -> num_act_args >= -n+ -- don't report to strip off args that aren't there+ -> Just $ text "Expecting" <+> speakN (abs n) <+>+ more_or_fewer <+> quotes (ppr thing)+ where+ more_or_fewer+ | n < 0 = text "fewer arguments to"+ | n == 1 = text "more argument to"+ | otherwise = text "more arguments to" -- n > 1+ _ -> Nothing++ maybe_num_args_msg = case num_args_msg of+ Nothing -> empty+ Just m -> m++ count_args ty = count isVisibleBinder $ fst $ splitPiTys ty++ expandedTys =+ ppUnless (expTy1 `pickyEqType` exp && expTy2 `pickyEqType` act) $ vcat+ [ text "Type synonyms expanded:"+ , text "Expected type:" <+> ppr expTy1+ , text " Actual type:" <+> ppr expTy2+ ]++ (expTy1, expTy2) = expandSynonymsToMatch exp act++mkExpectedActualMsg _ _ _ _ _ = panic "mkExpectedAcutalMsg"++{-+Note [Expanding type synonyms to make types similar]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++In type error messages, if -fprint-expanded-types is used, we want to expand+type synonyms to make expected and found types as similar as possible, but we+shouldn't expand types too much to make type messages even more verbose and+harder to understand. The whole point here is to make the difference in expected+and found types clearer.++`expandSynonymsToMatch` does this, it takes two types, and expands type synonyms+only as much as necessary. Given two types t1 and t2:++ * If they're already same, it just returns the types.++ * If they're in form `C1 t1_1 .. t1_n` and `C2 t2_1 .. t2_m` (C1 and C2 are+ type constructors), it expands C1 and C2 if they're different type synonyms.+ Then it recursively does the same thing on expanded types. If C1 and C2 are+ same, then it applies the same procedure to arguments of C1 and arguments of+ C2 to make them as similar as possible.++ Most important thing here is to keep number of synonym expansions at+ minimum. For example, if t1 is `T (T3, T5, Int)` and t2 is `T (T5, T3,+ Bool)` where T5 = T4, T4 = T3, ..., T1 = X, it returns `T (T3, T3, Int)` and+ `T (T3, T3, Bool)`.++ * Otherwise types don't have same shapes and so the difference is clearly+ visible. It doesn't do any expansions and show these types.++Note that we only expand top-layer type synonyms. Only when top-layer+constructors are the same we start expanding inner type synonyms.++Suppose top-layer type synonyms of t1 and t2 can expand N and M times,+respectively. If their type-synonym-expanded forms will meet at some point (i.e.+will have same shapes according to `sameShapes` function), it's possible to find+where they meet in O(N+M) top-layer type synonym expansions and O(min(N,M))+comparisons. We first collect all the top-layer expansions of t1 and t2 in two+lists, then drop the prefix of the longer list so that they have same lengths.+Then we search through both lists in parallel, and return the first pair of+types that have same shapes. Inner types of these two types with same shapes+are then expanded using the same algorithm.++In case they don't meet, we return the last pair of types in the lists, which+has top-layer type synonyms completely expanded. (in this case the inner types+are not expanded at all, as the current form already shows the type error)+-}++-- | Expand type synonyms in given types only enough to make them as similar as+-- possible. Returned types are the same in terms of used type synonyms.+--+-- To expand all synonyms, see 'Type.expandTypeSynonyms'.+--+-- See `ExpandSynsFail` tests in tests testsuite/tests/typecheck/should_fail for+-- some examples of how this should work.+expandSynonymsToMatch :: Type -> Type -> (Type, Type)+expandSynonymsToMatch ty1 ty2 = (ty1_ret, ty2_ret)+ where+ (ty1_ret, ty2_ret) = go ty1 ty2++ -- | Returns (type synonym expanded version of first type,+ -- type synonym expanded version of second type)+ go :: Type -> Type -> (Type, Type)+ go t1 t2+ | t1 `pickyEqType` t2 =+ -- Types are same, nothing to do+ (t1, t2)++ go (TyConApp tc1 tys1) (TyConApp tc2 tys2)+ | tc1 == tc2 =+ -- Type constructors are same. They may be synonyms, but we don't+ -- expand further.+ let (tys1', tys2') =+ unzip (zipWith (\ty1 ty2 -> go ty1 ty2) tys1 tys2)+ in (TyConApp tc1 tys1', TyConApp tc2 tys2')++ go (AppTy t1_1 t1_2) (AppTy t2_1 t2_2) =+ let (t1_1', t2_1') = go t1_1 t2_1+ (t1_2', t2_2') = go t1_2 t2_2+ in (mkAppTy t1_1' t1_2', mkAppTy t2_1' t2_2')++ go (FunTy t1_1 t1_2) (FunTy t2_1 t2_2) =+ let (t1_1', t2_1') = go t1_1 t2_1+ (t1_2', t2_2') = go t1_2 t2_2+ in (mkFunTy t1_1' t1_2', mkFunTy t2_1' t2_2')++ go (ForAllTy b1 t1) (ForAllTy b2 t2) =+ -- NOTE: We may have a bug here, but we just can't reproduce it easily.+ -- See D1016 comments for details and our attempts at producing a test+ -- case. Short version: We probably need RnEnv2 to really get this right.+ let (t1', t2') = go t1 t2+ in (ForAllTy b1 t1', ForAllTy b2 t2')++ go (CastTy ty1 _) ty2 = go ty1 ty2+ go ty1 (CastTy ty2 _) = go ty1 ty2++ go t1 t2 =+ -- See Note [Expanding type synonyms to make types similar] for how this+ -- works+ let+ t1_exp_tys = t1 : tyExpansions t1+ t2_exp_tys = t2 : tyExpansions t2+ t1_exps = length t1_exp_tys+ t2_exps = length t2_exp_tys+ dif = abs (t1_exps - t2_exps)+ in+ followExpansions $+ zipEqual "expandSynonymsToMatch.go"+ (if t1_exps > t2_exps then drop dif t1_exp_tys else t1_exp_tys)+ (if t2_exps > t1_exps then drop dif t2_exp_tys else t2_exp_tys)++ -- | Expand the top layer type synonyms repeatedly, collect expansions in a+ -- list. The list does not include the original type.+ --+ -- Example, if you have:+ --+ -- type T10 = T9+ -- type T9 = T8+ -- ...+ -- type T0 = Int+ --+ -- `tyExpansions T10` returns [T9, T8, T7, ... Int]+ --+ -- This only expands the top layer, so if you have:+ --+ -- type M a = Maybe a+ --+ -- `tyExpansions (M T10)` returns [Maybe T10] (T10 is not expanded)+ tyExpansions :: Type -> [Type]+ tyExpansions = unfoldr (\t -> (\x -> (x, x)) `fmap` tcView t)++ -- | Drop the type pairs until types in a pair look alike (i.e. the outer+ -- constructors are the same).+ followExpansions :: [(Type, Type)] -> (Type, Type)+ followExpansions [] = pprPanic "followExpansions" empty+ followExpansions [(t1, t2)]+ | sameShapes t1 t2 = go t1 t2 -- expand subtrees+ | otherwise = (t1, t2) -- the difference is already visible+ followExpansions ((t1, t2) : tss)+ -- Traverse subtrees when the outer shapes are the same+ | sameShapes t1 t2 = go t1 t2+ -- Otherwise follow the expansions until they look alike+ | otherwise = followExpansions tss++ sameShapes :: Type -> Type -> Bool+ sameShapes AppTy{} AppTy{} = True+ sameShapes (TyConApp tc1 _) (TyConApp tc2 _) = tc1 == tc2+ sameShapes (FunTy {}) (FunTy {}) = True+ sameShapes (ForAllTy {}) (ForAllTy {}) = True+ sameShapes (CastTy ty1 _) ty2 = sameShapes ty1 ty2+ sameShapes ty1 (CastTy ty2 _) = sameShapes ty1 ty2+ sameShapes _ _ = False++sameOccExtra :: TcType -> TcType -> SDoc+-- See Note [Disambiguating (X ~ X) errors]+sameOccExtra ty1 ty2+ | Just (tc1, _) <- tcSplitTyConApp_maybe ty1+ , Just (tc2, _) <- tcSplitTyConApp_maybe ty2+ , let n1 = tyConName tc1+ n2 = tyConName tc2+ same_occ = nameOccName n1 == nameOccName n2+ same_pkg = moduleUnitId (nameModule n1) == moduleUnitId (nameModule n2)+ , n1 /= n2 -- Different Names+ , same_occ -- but same OccName+ = text "NB:" <+> (ppr_from same_pkg n1 $$ ppr_from same_pkg n2)+ | otherwise+ = empty+ where+ ppr_from same_pkg nm+ | isGoodSrcSpan loc+ = hang (quotes (ppr nm) <+> text "is defined at")+ 2 (ppr loc)+ | otherwise -- Imported things have an UnhelpfulSrcSpan+ = hang (quotes (ppr nm))+ 2 (sep [ text "is defined in" <+> quotes (ppr (moduleName mod))+ , ppUnless (same_pkg || pkg == mainUnitId) $+ nest 4 $ text "in package" <+> quotes (ppr pkg) ])+ where+ pkg = moduleUnitId mod+ mod = nameModule nm+ loc = nameSrcSpan nm++{-+Note [Suggest adding a type signature]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The OutsideIn algorithm rejects GADT programs that don't have a principal+type, and indeed some that do. Example:+ data T a where+ MkT :: Int -> T Int++ f (MkT n) = n++Does this have type f :: T a -> a, or f :: T a -> Int?+The error that shows up tends to be an attempt to unify an+untouchable type variable. So suggestAddSig sees if the offending+type variable is bound by an *inferred* signature, and suggests+adding a declared signature instead.++This initially came up in Trac #8968, concerning pattern synonyms.++Note [Disambiguating (X ~ X) errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See Trac #8278++Note [Reporting occurs-check errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Given (a ~ [a]), if 'a' is a rigid type variable bound by a user-supplied+type signature, then the best thing is to report that we can't unify+a with [a], because a is a skolem variable. That avoids the confusing+"occur-check" error message.++But nowadays when inferring the type of a function with no type signature,+even if there are errors inside, we still generalise its signature and+carry on. For example+ f x = x:x+Here we will infer something like+ f :: forall a. a -> [a]+with a deferred error of (a ~ [a]). So in the deferred unsolved constraint+'a' is now a skolem, but not one bound by the programmer in the context!+Here we really should report an occurs check.++So isUserSkolem distinguishes the two.++Note [Non-injective type functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's very confusing to get a message like+ Couldn't match expected type `Depend s'+ against inferred type `Depend s1'+so mkTyFunInfoMsg adds:+ NB: `Depend' is type function, and hence may not be injective++Warn of loopy local equalities that were dropped.+++************************************************************************+* *+ Type-class errors+* *+************************************************************************+-}++mkDictErr :: ReportErrCtxt -> [Ct] -> TcM ErrMsg+mkDictErr ctxt cts+ = ASSERT( not (null cts) )+ do { inst_envs <- tcGetInstEnvs+ ; let (ct1:_) = cts -- ct1 just for its location+ min_cts = elim_superclasses cts+ lookups = map (lookup_cls_inst inst_envs) min_cts+ (no_inst_cts, overlap_cts) = partition is_no_inst lookups++ -- Report definite no-instance errors,+ -- or (iff there are none) overlap errors+ -- But we report only one of them (hence 'head') because they all+ -- have the same source-location origin, to try avoid a cascade+ -- of error from one location+ ; (ctxt, err) <- mk_dict_err ctxt (head (no_inst_cts ++ overlap_cts))+ ; mkErrorMsgFromCt ctxt ct1 (important err) }+ where+ no_givens = null (getUserGivens ctxt)++ is_no_inst (ct, (matches, unifiers, _))+ = no_givens+ && null matches+ && (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))+ where+ (clas, tys) = getClassPredTys (ctPred ct)+++ -- When simplifying [W] Ord (Set a), we need+ -- [W] Eq a, [W] Ord a+ -- but we really only want to report the latter+ elim_superclasses cts+ = filter (\ct -> any (eqType (ctPred ct)) min_preds) cts+ where+ min_preds = mkMinimalBySCs (map ctPred cts)++mk_dict_err :: ReportErrCtxt -> (Ct, ClsInstLookupResult)+ -> TcM (ReportErrCtxt, SDoc)+-- Report an overlap error if this class constraint results+-- from an overlap (returning Left clas), otherwise return (Right pred)+mk_dict_err ctxt@(CEC {cec_encl = implics}) (ct, (matches, unifiers, unsafe_overlapped))+ | null matches -- No matches but perhaps several unifiers+ = do { (ctxt, binds_msg, ct) <- relevantBindings True ctxt ct+ ; candidate_insts <- get_candidate_instances+ ; return (ctxt, cannot_resolve_msg ct candidate_insts binds_msg) }++ | null unsafe_overlapped -- Some matches => overlap errors+ = return (ctxt, overlap_msg)++ | otherwise+ = return (ctxt, safe_haskell_msg)+ where+ orig = ctOrigin ct+ pred = ctPred ct+ (clas, tys) = getClassPredTys pred+ ispecs = [ispec | (ispec, _) <- matches]+ unsafe_ispecs = [ispec | (ispec, _) <- unsafe_overlapped]+ useful_givens = discardProvCtxtGivens orig (getUserGivensFromImplics implics)+ -- useful_givens are the enclosing implications with non-empty givens,+ -- modulo the horrid discardProvCtxtGivens++ get_candidate_instances :: TcM [ClsInst]+ -- See Note [Report candidate instances]+ get_candidate_instances+ | [ty] <- tys -- Only try for single-parameter classes+ = do { instEnvs <- tcGetInstEnvs+ ; return (filter (is_candidate_inst ty)+ (classInstances instEnvs clas)) }+ | otherwise = return []++ is_candidate_inst ty inst -- See Note [Report candidate instances]+ | [other_ty] <- is_tys inst+ , Just (tc1, _) <- tcSplitTyConApp_maybe ty+ , Just (tc2, _) <- tcSplitTyConApp_maybe other_ty+ = let n1 = tyConName tc1+ n2 = tyConName tc2+ different_names = n1 /= n2+ same_occ_names = nameOccName n1 == nameOccName n2+ in different_names && same_occ_names+ | otherwise = False++ cannot_resolve_msg :: Ct -> [ClsInst] -> SDoc -> SDoc+ cannot_resolve_msg ct candidate_insts binds_msg+ = vcat [ no_inst_msg+ , nest 2 extra_note+ , vcat (pp_givens useful_givens)+ , mb_patsyn_prov `orElse` empty+ , ppWhen (has_ambig_tvs && not (null unifiers && null useful_givens))+ (vcat [ ppUnless lead_with_ambig ambig_msg, binds_msg, potential_msg ])++ , ppWhen (isNothing mb_patsyn_prov) $+ -- Don't suggest fixes for the provided context of a pattern+ -- synonym; the right fix is to bind more in the pattern+ show_fixes (ctxtFixes has_ambig_tvs pred implics+ ++ drv_fixes)+ , ppWhen (not (null candidate_insts))+ (hang (text "There are instances for similar types:")+ 2 (vcat (map ppr candidate_insts))) ]+ -- See Note [Report candidate instances]+ where+ orig = ctOrigin ct+ -- See Note [Highlighting ambiguous type variables]+ lead_with_ambig = has_ambig_tvs && not (any isRuntimeUnkSkol ambig_tvs)+ && not (null unifiers) && null useful_givens++ (has_ambig_tvs, ambig_msg) = mkAmbigMsg lead_with_ambig ct+ ambig_tvs = uncurry (++) (getAmbigTkvs ct)++ no_inst_msg+ | lead_with_ambig+ = ambig_msg <+> pprArising orig+ $$ text "prevents the constraint" <+> quotes (pprParendType pred)+ <+> text "from being solved."++ | null useful_givens+ = addArising orig $ text "No instance for"+ <+> pprParendType pred++ | otherwise+ = addArising orig $ text "Could not deduce"+ <+> pprParendType pred++ potential_msg+ = ppWhen (not (null unifiers) && want_potential orig) $+ sdocWithDynFlags $ \dflags ->+ getPprStyle $ \sty ->+ pprPotentials dflags sty potential_hdr unifiers++ potential_hdr+ = vcat [ ppWhen lead_with_ambig $+ text "Probable fix: use a type annotation to specify what"+ <+> pprQuotedList ambig_tvs <+> text "should be."+ , text "These potential instance" <> plural unifiers+ <+> text "exist:"]++ mb_patsyn_prov :: Maybe SDoc+ mb_patsyn_prov+ | not lead_with_ambig+ , ProvCtxtOrigin PSB{ psb_def = L _ pat } <- orig+ = Just (vcat [ text "In other words, a successful match on the pattern"+ , nest 2 $ ppr pat+ , text "does not provide the constraint" <+> pprParendType pred ])+ | otherwise = Nothing++ -- Report "potential instances" only when the constraint arises+ -- directly from the user's use of an overloaded function+ want_potential (TypeEqOrigin {}) = False+ want_potential _ = True++ extra_note | any isFunTy (filterOutInvisibleTypes (classTyCon clas) tys)+ = text "(maybe you haven't applied a function to enough arguments?)"+ | className clas == typeableClassName -- Avoid mysterious "No instance for (Typeable T)+ , [_,ty] <- tys -- Look for (Typeable (k->*) (T k))+ , Just (tc,_) <- tcSplitTyConApp_maybe ty+ , not (isTypeFamilyTyCon tc)+ = hang (text "GHC can't yet do polykinded")+ 2 (text "Typeable" <+>+ parens (ppr ty <+> dcolon <+> ppr (typeKind ty)))+ | otherwise+ = empty++ drv_fixes = case orig of+ DerivOrigin -> [drv_fix]+ DerivOriginDC {} -> [drv_fix]+ DerivOriginCoerce {} -> [drv_fix]+ _ -> []++ drv_fix = hang (text "use a standalone 'deriving instance' declaration,")+ 2 (text "so you can specify the instance context yourself")++ -- Normal overlap error+ overlap_msg+ = ASSERT( not (null matches) )+ vcat [ addArising orig (text "Overlapping instances for"+ <+> pprType (mkClassPred clas tys))++ , ppUnless (null matching_givens) $+ sep [text "Matching givens (or their superclasses):"+ , nest 2 (vcat matching_givens)]++ , sdocWithDynFlags $ \dflags ->+ getPprStyle $ \sty ->+ pprPotentials dflags sty (text "Matching instances:") $+ ispecs ++ unifiers++ , ppWhen (null matching_givens && isSingleton matches && null unifiers) $+ -- Intuitively, some given matched the wanted in their+ -- flattened or rewritten (from given equalities) form+ -- but the matcher can't figure that out because the+ -- constraints are non-flat and non-rewritten so we+ -- simply report back the whole given+ -- context. Accelerate Smart.hs showed this problem.+ sep [ text "There exists a (perhaps superclass) match:"+ , 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))+ , ppWhen (null (matching_givens)) $+ vcat [ text "To pick the first instance above, use IncoherentInstances"+ , text "when compiling the other instance declarations"]+ ])]++ matching_givens = mapMaybe matchable useful_givens++ matchable (Implic { ic_given = evvars, ic_info = skol_info, ic_env = env })+ = case ev_vars_matching of+ [] -> Nothing+ _ -> Just $ hang (pprTheta ev_vars_matching)+ 2 (sep [ text "bound by" <+> ppr skol_info+ , text "at" <+> ppr (tcl_loc env) ])+ where ev_vars_matching = filter ev_var_matches (map evVarPred evvars)+ ev_var_matches ty = case getClassPredTys_maybe ty of+ Just (clas', tys')+ | clas' == clas+ , Just _ <- tcMatchTys tys tys'+ -> True+ | otherwise+ -> any ev_var_matches (immSuperClasses clas' tys')+ Nothing -> False++ -- Overlap error because of Safe Haskell (first+ -- match should be the most specific match)+ safe_haskell_msg+ = ASSERT( length matches == 1 && not (null unsafe_ispecs) )+ vcat [ addArising orig (text "Unsafe overlapping instances for"+ <+> pprType (mkClassPred clas tys))+ , sep [text "The matching instance is:",+ nest 2 (pprInstance $ head ispecs)]+ , vcat [ text "It is compiled in a Safe module and as such can only"+ , text "overlap instances from the same module, however it"+ , text "overlaps the following instances from different" <+>+ text "modules:"+ , nest 2 (vcat [pprInstances $ unsafe_ispecs])+ ]+ ]+++ctxtFixes :: Bool -> PredType -> [Implication] -> [SDoc]+ctxtFixes has_ambig_tvs pred implics+ | not has_ambig_tvs+ , isTyVarClassPred pred+ , (skol:skols) <- usefulContext implics pred+ , let what | null skols+ , SigSkol (PatSynCtxt {}) _ _ <- skol+ = text "\"required\""+ | otherwise+ = empty+ = [sep [ text "add" <+> pprParendType pred+ <+> text "to the" <+> what <+> text "context of"+ , nest 2 $ ppr_skol skol $$+ vcat [ text "or" <+> ppr_skol skol+ | skol <- skols ] ] ]+ | otherwise = []+ where+ ppr_skol (PatSkol (RealDataCon dc) _) = text "the data constructor" <+> quotes (ppr dc)+ ppr_skol (PatSkol (PatSynCon ps) _) = text "the pattern synonym" <+> quotes (ppr ps)+ ppr_skol skol_info = ppr skol_info++discardProvCtxtGivens :: CtOrigin -> [UserGiven] -> [UserGiven]+discardProvCtxtGivens orig givens -- See Note [discardProvCtxtGivens]+ | ProvCtxtOrigin (PSB {psb_id = L _ name}) <- orig+ = filterOut (discard name) givens+ | otherwise+ = givens+ where+ discard n (Implic { ic_info = SigSkol (PatSynCtxt n') _ _ }) = n == n'+ discard _ _ = False++usefulContext :: [Implication] -> PredType -> [SkolemInfo]+-- usefulContext picks out the implications whose context+-- the programmer might plausibly augment to solve 'pred'+usefulContext implics pred+ = go implics+ where+ pred_tvs = tyCoVarsOfType pred+ go [] = []+ go (ic : ics)+ | implausible ic = rest+ | otherwise = ic_info ic : rest+ where+ -- Stop when the context binds a variable free in the predicate+ rest | any (`elemVarSet` pred_tvs) (ic_skols ic) = []+ | otherwise = go ics++ implausible ic+ | null (ic_skols ic) = True+ | implausible_info (ic_info ic) = True+ | otherwise = False++ implausible_info (SigSkol (InfSigCtxt {}) _ _) = True+ implausible_info _ = False+ -- Do not suggest adding constraints to an *inferred* type signature++{- Note [Report candidate instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have an unsolved (Num Int), where `Int` is not the Prelude Int,+but comes from some other module, then it may be helpful to point out+that there are some similarly named instances elsewhere. So we get+something like+ No instance for (Num Int) arising from the literal ‘3’+ There are instances for similar types:+ instance Num GHC.Types.Int -- Defined in ‘GHC.Num’+Discussion in Trac #9611.++Note [Highlighting ambiguous type variables]+~-------------------------------------------+When we encounter ambiguous type variables (i.e. type variables+that remain metavariables after type inference), we need a few more+conditions before we can reason that *ambiguity* prevents constraints+from being solved:+ - We can't have any givens, as encountering a typeclass error+ with given constraints just means we couldn't deduce+ a solution satisfying those constraints and as such couldn't+ bind the type variable to a known type.+ - If we don't have any unifiers, we don't even have potential+ instances from which an ambiguity could arise.+ - Lastly, I don't want to mess with error reporting for+ unknown runtime types so we just fall back to the old message there.+Once these conditions are satisfied, we can safely say that ambiguity prevents+the constraint from being solved.++Note [discardProvCtxtGivens]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+In most situations we call all enclosing implications "useful". There is one+exception, and that is when the constraint that causes the error is from the+"provided" context of a pattern synonym declaration:++ pattern Pat :: (Num a, Eq a) => Show a => a -> Maybe a+ -- required => provided => type+ pattern Pat x <- (Just x, 4)++When checking the pattern RHS we must check that it does actually bind all+the claimed "provided" constraints; in this case, does the pattern (Just x, 4)+bind the (Show a) constraint. Answer: no!++But the implication we generate for this will look like+ forall a. (Num a, Eq a) => [W] Show a+because when checking the pattern we must make the required+constraints available, since they are needed to match the pattern (in+this case the literal '4' needs (Num a, Eq a)).++BUT we don't want to suggest adding (Show a) to the "required" constraints+of the pattern synonym, thus:+ pattern Pat :: (Num a, Eq a, Show a) => Show a => a -> Maybe a+It would then typecheck but it's silly. We want the /pattern/ to bind+the alleged "provided" constraints, Show a.++So we suppress that Implication in discardProvCtxtGivens. It's+painfully ad-hoc but the truth is that adding it to the "required"+constraints would work. Suprressing it solves two problems. First,+we never tell the user that we could not deduce a "provided"+constraint from the "required" context. Second, we never give a+possible fix that suggests to add a "provided" constraint to the+"required" context.++For example, without this distinction the above code gives a bad error+message (showing both problems):++ error: Could not deduce (Show a) ... from the context: (Eq a)+ ... Possible fix: add (Show a) to the context of+ the signature for pattern synonym `Pat' ...++-}++show_fixes :: [SDoc] -> SDoc+show_fixes [] = empty+show_fixes (f:fs) = sep [ text "Possible fix:"+ , nest 2 (vcat (f : map (text "or" <+>) fs))]++pprPotentials :: DynFlags -> PprStyle -> SDoc -> [ClsInst] -> SDoc+-- See Note [Displaying potential instances]+pprPotentials dflags sty herald insts+ | null insts+ = empty++ | null show_these+ = hang herald+ 2 (vcat [ not_in_scope_msg empty+ , flag_hint ])++ | otherwise+ = hang herald+ 2 (vcat [ pprInstances show_these+ , ppWhen (n_in_scope_hidden > 0) $+ text "...plus"+ <+> speakNOf n_in_scope_hidden (text "other")+ , not_in_scope_msg (text "...plus")+ , flag_hint ])+ where+ n_show = 3 :: Int+ show_potentials = gopt Opt_PrintPotentialInstances dflags++ (in_scope, not_in_scope) = partition inst_in_scope insts+ sorted = sortBy fuzzyClsInstCmp in_scope+ show_these | show_potentials = sorted+ | otherwise = take n_show sorted+ n_in_scope_hidden = length sorted - length show_these++ -- "in scope" means that all the type constructors+ -- are lexically in scope; these instances are likely+ -- to be more useful+ inst_in_scope :: ClsInst -> Bool+ inst_in_scope cls_inst = nameSetAll name_in_scope $+ orphNamesOfTypes (is_tys cls_inst)++ name_in_scope name+ | isBuiltInSyntax name+ = True -- E.g. (->)+ | Just mod <- nameModule_maybe name+ = qual_in_scope (qualName sty mod (nameOccName name))+ | otherwise+ = True++ qual_in_scope :: QualifyName -> Bool+ qual_in_scope NameUnqual = True+ qual_in_scope (NameQual {}) = True+ qual_in_scope _ = False++ not_in_scope_msg herald+ | null not_in_scope+ = empty+ | otherwise+ = hang (herald <+> speakNOf (length not_in_scope) (text "instance")+ <+> text "involving out-of-scope types")+ 2 (ppWhen show_potentials (pprInstances not_in_scope))++ flag_hint = ppUnless (show_potentials || length show_these == length insts) $+ text "(use -fprint-potential-instances to see them all)"++{- Note [Displaying potential instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When showing a list of instances for+ - overlapping instances (show ones that match)+ - no such instance (show ones that could match)+we want to give it a bit of structure. Here's the plan++* Say that an instance is "in scope" if all of the+ type constructors it mentions are lexically in scope.+ 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")++* Summarise the not-in-scope instances ("plus 4 not in scope")++* Add the flag -fshow-potential-instances which replaces the+ summary with the full list+-}++{-+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 (because of flattening) 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.++Re-flattening is pretty easy, because we don't need to keep track of+evidence. We don't re-use the code in TcCanonical because that's in+the TcS monad, and we are in TcM here.++Note [Suggest -fprint-explicit-kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It can be terribly confusing to get an error message like (Trac #9171)+ Couldn't match expected type ‘GetParam Base (GetParam Base Int)’+ with actual type ‘GetParam Base (GetParam Base Int)’+The reason may be that the kinds don't match up. Typically you'll get+more useful information, but not when it's as a result of ambiguity.+This test suggests -fprint-explicit-kinds when all the ambiguous type+variables are kind variables.+-}++mkAmbigMsg :: Bool -- True when message has to be at beginning of sentence+ -> Ct -> (Bool, SDoc)+mkAmbigMsg prepend_msg ct+ | null ambig_kvs && null ambig_tvs = (False, empty)+ | otherwise = (True, msg)+ where+ (ambig_kvs, ambig_tvs) = getAmbigTkvs ct++ msg | any isRuntimeUnkSkol ambig_kvs -- See Note [Runtime skolems]+ || any isRuntimeUnkSkol ambig_tvs+ = vcat [ text "Cannot resolve unknown runtime type"+ <> plural ambig_tvs <+> pprQuotedList ambig_tvs+ , text "Use :print or :force to determine these types"]++ | not (null ambig_tvs)+ = pp_ambig (text "type") ambig_tvs++ | otherwise -- All ambiguous kind variabes; suggest -fprint-explicit-kinds+ -- See Note [Suggest -fprint-explicit-kinds]+ = vcat [ pp_ambig (text "kind") ambig_kvs+ , ppSuggestExplicitKinds ]++ pp_ambig what tkvs+ | prepend_msg -- "Ambiguous type variable 't0'"+ = text "Ambiguous" <+> what <+> text "variable"+ <> plural tkvs <+> pprQuotedList tkvs++ | otherwise -- "The type variable 't0' is ambiguous"+ = text "The" <+> what <+> text "variable" <> plural tkvs+ <+> pprQuotedList tkvs <+> is_or_are tkvs <+> text "ambiguous"++ is_or_are [_] = text "is"+ is_or_are _ = text "are"++pprSkol :: [Implication] -> TcTyVar -> SDoc+pprSkol implics tv+ = case skol_info of+ UnkSkol -> quotes (ppr tv) <+> text "is an unknown type variable"+ _ -> ppr_rigid (pprSkolInfo skol_info)+ where+ Implic { ic_info = skol_info } = getSkolemInfo implics tv+ ppr_rigid pp_info+ = hang (quotes (ppr tv) <+> text "is a rigid type variable bound by")+ 2 (sep [ pp_info+ , text "at" <+> ppr (getSrcSpan tv) ])++getAmbigTkvs :: Ct -> ([Var],[Var])+getAmbigTkvs ct+ = partition (`elemVarSet` dep_tkv_set) ambig_tkvs+ where+ tkvs = tyCoVarsOfCtList ct+ ambig_tkvs = filter isAmbiguousTyVar tkvs+ dep_tkv_set = tyCoVarsOfTypes (map tyVarKind tkvs)++getSkolemInfo :: [Implication] -> TcTyVar -> Implication+-- Get the skolem info for a type variable+-- from the implication constraint that binds it+getSkolemInfo [] tv+ = pprPanic "No skolem info:" (ppr tv)++getSkolemInfo (implic:implics) tv+ | tv `elem` ic_skols implic = implic+ | otherwise = getSkolemInfo implics tv++-----------------------+-- relevantBindings looks at the value environment and finds values whose+-- types mention any of the offending type variables. It has to be+-- careful to zonk the Id's type first, so it has to be in the monad.+-- We must be careful to pass it a zonked type variable, too.+--+-- We always remove closed top-level bindings, though,+-- since they are never relevant (cf Trac #8233)++relevantBindings :: Bool -- True <=> filter by tyvar; False <=> no filtering+ -- See Trac #8191+ -> ReportErrCtxt -> Ct+ -> TcM (ReportErrCtxt, SDoc, Ct)+-- Also returns the zonked and tidied CtOrigin of the constraint+relevantBindings want_filtering ctxt ct+ = do { dflags <- getDynFlags+ ; (env1, tidy_orig) <- zonkTidyOrigin (cec_tidy ctxt) (ctLocOrigin loc)+ ; let ct_tvs = tyCoVarsOfCt ct `unionVarSet` extra_tvs++ -- For *kind* errors, report the relevant bindings of the+ -- enclosing *type* equality, because that's more useful for the programmer+ extra_tvs = case tidy_orig of+ KindEqOrigin t1 m_t2 _ _ -> tyCoVarsOfTypes $+ t1 : maybeToList m_t2+ _ -> emptyVarSet+ ; traceTc "relevantBindings" $+ vcat [ ppr ct+ , pprCtOrigin (ctLocOrigin loc)+ , ppr ct_tvs+ , pprWithCommas id [ ppr id <+> dcolon <+> ppr (idType id)+ | TcIdBndr id _ <- tcl_bndrs lcl_env ]+ , pprWithCommas id+ [ ppr id | TcIdBndr_ExpType id _ _ <- tcl_bndrs lcl_env ] ]++ ; (tidy_env', docs, discards)+ <- go dflags env1 ct_tvs (maxRelevantBinds dflags)+ emptyVarSet [] False+ (remove_shadowing $ tcl_bndrs lcl_env)+ -- tcl_bndrs has the innermost bindings first,+ -- which are probably the most relevant ones++ ; let doc = ppUnless (null docs) $+ hang (text "Relevant bindings include")+ 2 (vcat docs $$ ppWhen discards discardMsg)++ -- Put a zonked, tidied CtOrigin into the Ct+ loc' = setCtLocOrigin loc tidy_orig+ ct' = setCtLoc ct loc'+ ctxt' = ctxt { cec_tidy = tidy_env' }++ ; return (ctxt', doc, ct') }+ where+ ev = ctEvidence ct+ loc = ctEvLoc ev+ lcl_env = ctLocEnv loc++ run_out :: Maybe Int -> Bool+ run_out Nothing = False+ run_out (Just n) = n <= 0++ dec_max :: Maybe Int -> Maybe Int+ dec_max = fmap (\n -> n - 1)++ ---- fixes #12177+ ---- builds up a list of bindings whose OccName has not been seen before+ remove_shadowing :: [TcIdBinder] -> [TcIdBinder]+ remove_shadowing bindings = reverse $ fst $ foldl+ (\(bindingAcc, seenNames) binding ->+ if (occName binding) `elemOccSet` seenNames -- if we've seen it+ then (bindingAcc, seenNames) -- skip it+ else (binding:bindingAcc, extendOccSet seenNames (occName binding)))+ ([], emptyOccSet) bindings++ go :: DynFlags -> TidyEnv -> TcTyVarSet -> Maybe Int -> TcTyVarSet -> [SDoc]+ -> Bool -- True <=> some filtered out due to lack of fuel+ -> [TcIdBinder]+ -> TcM (TidyEnv, [SDoc], Bool) -- The bool says if we filtered any out+ -- because of lack of fuel+ go _ tidy_env _ _ _ docs discards []+ = return (tidy_env, reverse docs, discards)+ go dflags tidy_env ct_tvs n_left tvs_seen docs discards (tc_bndr : tc_bndrs)+ = case tc_bndr of+ TcIdBndr id top_lvl -> go2 (idName id) (idType id) top_lvl+ TcIdBndr_ExpType name et top_lvl ->+ do { mb_ty <- readExpType_maybe et+ -- et really should be filled in by now. But there's a chance+ -- it hasn't, if, say, we're reporting a kind error en route to+ -- checking a term. See test indexed-types/should_fail/T8129+ -- Or we are reporting errors from the ambiguity check on+ -- a local type signature+ ; case mb_ty of+ Just ty -> go2 name ty top_lvl+ Nothing -> discard_it -- No info; discard+ }+ where+ discard_it = go dflags tidy_env ct_tvs n_left tvs_seen docs+ discards tc_bndrs+ go2 id_name id_type top_lvl+ = do { (tidy_env', tidy_ty) <- zonkTidyTcType tidy_env id_type+ ; traceTc "relevantBindings 1" (ppr id_name <+> dcolon <+> ppr tidy_ty)+ ; let id_tvs = tyCoVarsOfType tidy_ty+ doc = sep [ pprPrefixOcc id_name <+> dcolon <+> ppr tidy_ty+ , nest 2 (parens (text "bound at"+ <+> ppr (getSrcLoc id_name)))]+ new_seen = tvs_seen `unionVarSet` id_tvs++ ; if (want_filtering && not (hasPprDebug dflags)+ && id_tvs `disjointVarSet` ct_tvs)+ -- We want to filter out this binding anyway+ -- so discard it silently+ then discard_it++ else if isTopLevel top_lvl && not (isNothing n_left)+ -- It's a top-level binding and we have not specified+ -- -fno-max-relevant-bindings, so discard it silently+ then discard_it++ else if run_out n_left && id_tvs `subVarSet` tvs_seen+ -- We've run out of n_left fuel and this binding only+ -- mentions already-seen type variables, so discard it+ then go dflags tidy_env ct_tvs n_left tvs_seen docs+ True -- Record that we have now discarded something+ tc_bndrs++ -- Keep this binding, decrement fuel+ else go dflags tidy_env' ct_tvs (dec_max n_left) new_seen+ (doc:docs) discards tc_bndrs }++discardMsg :: SDoc+discardMsg = text "(Some bindings suppressed;" <+>+ text "use -fmax-relevant-binds=N or -fno-max-relevant-binds)"++-----------------------+warnDefaulting :: [Ct] -> Type -> TcM ()+warnDefaulting 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+ (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) ])+ 2+ ppr_wanteds+ ; setCtLocM loc $ warnTc (Reason Opt_WarnTypeDefaults) warn_default warn_msg }++{-+Note [Runtime skolems]+~~~~~~~~~~~~~~~~~~~~~~+We want to give a reasonably helpful error message for ambiguity+arising from *runtime* skolems in the debugger. These+are created by in RtClosureInspect.zonkRTTIType.++************************************************************************+* *+ Error from the canonicaliser+ These ones are called *during* constraint simplification+* *+************************************************************************+-}++solverDepthErrorTcS :: CtLoc -> TcType -> TcM a+solverDepthErrorTcS loc ty+ = setCtLocM loc $+ do { ty <- zonkTcType ty+ ; env0 <- tcInitTidyEnv+ ; let tidy_env = tidyFreeTyCoVars env0 (tyCoVarsOfTypeList ty)+ tidy_ty = tidyType tidy_env ty+ msg+ = vcat [ text "Reduction stack overflow; size =" <+> ppr depth+ , hang (text "When simplifying the following type:")+ 2 (ppr tidy_ty)+ , note ]+ ; failWithTcM (tidy_env, msg) }+ where+ depth = ctLocDepth loc+ note = vcat+ [ text "Use -freduction-depth=0 to disable this check"+ , text "(any upper bound you could choose might fail unpredictably with"+ , text " minor updates to GHC, so disabling the check is recommended if"+ , text " you're sure that type checking should terminate)" ]
+ typecheck/TcEvidence.hs view
@@ -0,0 +1,946 @@+-- (c) The University of Glasgow 2006++{-# LANGUAGE CPP, DeriveDataTypeable #-}++module TcEvidence (++ -- HsWrapper+ HsWrapper(..),+ (<.>), mkWpTyApps, mkWpEvApps, mkWpEvVarApps, mkWpTyLams,+ mkWpLams, mkWpLet, mkWpCastN, mkWpCastR, collectHsWrapBinders,+ mkWpFun, mkWpFuns, idHsWrapper, isIdHsWrapper, pprHsWrapper,++ -- Evidence bindings+ TcEvBinds(..), EvBindsVar(..),+ EvBindMap(..), emptyEvBindMap, extendEvBinds,+ lookupEvBind, evBindMapBinds, foldEvBindMap, isEmptyEvBindMap,+ EvBind(..), emptyTcEvBinds, isEmptyTcEvBinds, mkGivenEvBind, mkWantedEvBind,+ sccEvBinds, evBindVar,+ EvTerm(..), mkEvCast, evVarsOfTerm, mkEvScSelectors,+ EvLit(..), evTermCoercion,+ EvCallStack(..),+ EvTypeable(..),++ -- TcCoercion+ TcCoercion, TcCoercionR, TcCoercionN, TcCoercionP, CoercionHole,+ Role(..), LeftOrRight(..), pickLR,+ mkTcReflCo, mkTcNomReflCo, mkTcRepReflCo,+ mkTcTyConAppCo, mkTcAppCo, mkTcFunCo,+ mkTcAxInstCo, mkTcUnbranchedAxInstCo, mkTcForAllCo, mkTcForAllCos,+ mkTcSymCo, mkTcTransCo, mkTcNthCo, mkTcLRCo, mkTcSubCo, maybeTcSubCo,+ tcDowngradeRole,+ mkTcAxiomRuleCo, mkTcCoherenceLeftCo, mkTcCoherenceRightCo, mkTcPhantomCo,+ mkTcKindCo,+ tcCoercionKind, coVarsOfTcCo,+ mkTcCoVarCo,+ isTcReflCo,+ tcCoercionRole,+ unwrapIP, wrapIP+ ) where+#include "HsVersions.h"++import Var+import CoAxiom+import Coercion+import PprCore () -- Instance OutputableBndr TyVar+import TcType+import Type+import TyCon+import Class( Class )+import PrelNames+import DynFlags ( gopt, GeneralFlag(Opt_PrintTypecheckerElaboration) )+import VarEnv+import VarSet+import Name+import Pair++import Util+import Bag+import Digraph+import qualified Data.Data as Data+import Outputable+import FastString+import SrcLoc+import Data.IORef( IORef )+import UniqSet++{-+Note [TcCoercions]+~~~~~~~~~~~~~~~~~~+| TcCoercions are a hack used by the typechecker. Normally,+Coercions have free variables of type (a ~# b): we call these+CoVars. However, the type checker passes around equality evidence+(boxed up) at type (a ~ b).++An TcCoercion is simply a Coercion whose free variables have may be either+boxed or unboxed. After we are done with typechecking the desugarer finds the+boxed free variables, unboxes them, and creates a resulting real Coercion with+kosher free variables.++-}++type TcCoercion = Coercion+type TcCoercionN = CoercionN -- A Nominal coercion ~N+type TcCoercionR = CoercionR -- A Representational coercion ~R+type TcCoercionP = CoercionP -- a phantom coercion++mkTcReflCo :: Role -> TcType -> TcCoercion+mkTcSymCo :: TcCoercion -> TcCoercion+mkTcTransCo :: TcCoercion -> TcCoercion -> TcCoercion+mkTcNomReflCo :: TcType -> TcCoercionN+mkTcRepReflCo :: TcType -> TcCoercionR+mkTcTyConAppCo :: Role -> TyCon -> [TcCoercion] -> TcCoercion+mkTcAppCo :: TcCoercion -> TcCoercionN -> TcCoercion+mkTcFunCo :: Role -> TcCoercion -> TcCoercion -> TcCoercion+mkTcAxInstCo :: Role -> CoAxiom br -> BranchIndex+ -> [TcType] -> [TcCoercion] -> TcCoercion+mkTcUnbranchedAxInstCo :: CoAxiom Unbranched -> [TcType]+ -> [TcCoercion] -> TcCoercionR+mkTcForAllCo :: TyVar -> TcCoercionN -> TcCoercion -> TcCoercion+mkTcForAllCos :: [(TyVar, TcCoercionN)] -> TcCoercion -> TcCoercion+mkTcNthCo :: Int -> TcCoercion -> TcCoercion+mkTcLRCo :: LeftOrRight -> TcCoercion -> TcCoercion+mkTcSubCo :: TcCoercionN -> TcCoercionR+maybeTcSubCo :: EqRel -> TcCoercion -> TcCoercion+tcDowngradeRole :: Role -> Role -> TcCoercion -> TcCoercion+mkTcAxiomRuleCo :: CoAxiomRule -> [TcCoercion] -> TcCoercionR+mkTcCoherenceLeftCo :: TcCoercion -> TcCoercionN -> TcCoercion+mkTcCoherenceRightCo :: TcCoercion -> TcCoercionN -> TcCoercion+mkTcPhantomCo :: TcCoercionN -> TcType -> TcType -> TcCoercionP+mkTcKindCo :: TcCoercion -> TcCoercionN+mkTcCoVarCo :: CoVar -> TcCoercion++tcCoercionKind :: TcCoercion -> Pair TcType+tcCoercionRole :: TcCoercion -> Role+coVarsOfTcCo :: TcCoercion -> TcTyCoVarSet+isTcReflCo :: TcCoercion -> Bool++mkTcReflCo = mkReflCo+mkTcSymCo = mkSymCo+mkTcTransCo = mkTransCo+mkTcNomReflCo = mkNomReflCo+mkTcRepReflCo = mkRepReflCo+mkTcTyConAppCo = mkTyConAppCo+mkTcAppCo = mkAppCo+mkTcFunCo = mkFunCo+mkTcAxInstCo = mkAxInstCo+mkTcUnbranchedAxInstCo = mkUnbranchedAxInstCo Representational+mkTcForAllCo = mkForAllCo+mkTcForAllCos = mkForAllCos+mkTcNthCo = mkNthCo+mkTcLRCo = mkLRCo+mkTcSubCo = mkSubCo+maybeTcSubCo = maybeSubCo+tcDowngradeRole = downgradeRole+mkTcAxiomRuleCo = mkAxiomRuleCo+mkTcCoherenceLeftCo = mkCoherenceLeftCo+mkTcCoherenceRightCo = mkCoherenceRightCo+mkTcPhantomCo = mkPhantomCo+mkTcKindCo = mkKindCo+mkTcCoVarCo = mkCoVarCo++tcCoercionKind = coercionKind+tcCoercionRole = coercionRole+coVarsOfTcCo = coVarsOfCo+isTcReflCo = isReflCo+++{-+%************************************************************************+%* *+ HsWrapper+* *+************************************************************************+-}++data HsWrapper+ = WpHole -- The identity coercion++ | WpCompose HsWrapper HsWrapper+ -- (wrap1 `WpCompose` wrap2)[e] = wrap1[ wrap2[ e ]]+ --+ -- Hence (\a. []) `WpCompose` (\b. []) = (\a b. [])+ -- But ([] a) `WpCompose` ([] b) = ([] b a)++ | WpFun HsWrapper HsWrapper TcType SDoc+ -- (WpFun wrap1 wrap2 t1)[e] = \(x:t1). wrap2[ e wrap1[x] ]+ -- So note that if wrap1 :: exp_arg <= act_arg+ -- wrap2 :: act_res <= exp_res+ -- then WpFun wrap1 wrap2 : (act_arg -> arg_res) <= (exp_arg -> exp_res)+ -- This isn't the same as for mkFunCo, but it has to be this way+ -- because we can't use 'sym' to flip around these HsWrappers+ -- The TcType is the "from" type of the first wrapper+ -- The SDoc explains the circumstances under which we have created this+ -- WpFun, in case we run afoul of levity polymorphism restrictions in+ -- the desugarer. See Note [Levity polymorphism checking] in DsMonad++ | WpCast TcCoercionR -- A cast: [] `cast` co+ -- Guaranteed not the identity coercion+ -- At role Representational++ -- Evidence abstraction and application+ -- (both dictionaries and coercions)+ | WpEvLam EvVar -- \d. [] the 'd' is an evidence variable+ | WpEvApp EvTerm -- [] d the 'd' is evidence for a constraint+ -- Kind and Type abstraction and application+ | WpTyLam TyVar -- \a. [] the 'a' is a type/kind variable (not coercion var)+ | WpTyApp KindOrType -- [] t the 't' is a type (not coercion)+++ | WpLet TcEvBinds -- Non-empty (or possibly non-empty) evidence bindings,+ -- so that the identity coercion is always exactly WpHole++-- Cannot derive Data instance because SDoc is not Data (it stores a function).+-- So we do it manually:+instance Data.Data HsWrapper where+ gfoldl _ z WpHole = z WpHole+ gfoldl k z (WpCompose a1 a2) = z WpCompose `k` a1 `k` a2+ gfoldl k z (WpFun a1 a2 a3 _) = z wpFunEmpty `k` a1 `k` a2 `k` a3+ gfoldl k z (WpCast a1) = z WpCast `k` a1+ gfoldl k z (WpEvLam a1) = z WpEvLam `k` a1+ gfoldl k z (WpEvApp a1) = z WpEvApp `k` a1+ gfoldl k z (WpTyLam a1) = z WpTyLam `k` a1+ gfoldl k z (WpTyApp a1) = z WpTyApp `k` a1+ gfoldl k z (WpLet a1) = z WpLet `k` a1++ gunfold k z c = case Data.constrIndex c of+ 1 -> z WpHole+ 2 -> k (k (z WpCompose))+ 3 -> k (k (k (z wpFunEmpty)))+ 4 -> k (z WpCast)+ 5 -> k (z WpEvLam)+ 6 -> k (z WpEvApp)+ 7 -> k (z WpTyLam)+ 8 -> k (z WpTyApp)+ _ -> k (z WpLet)++ toConstr WpHole = wpHole_constr+ toConstr (WpCompose _ _) = wpCompose_constr+ toConstr (WpFun _ _ _ _) = wpFun_constr+ toConstr (WpCast _) = wpCast_constr+ toConstr (WpEvLam _) = wpEvLam_constr+ toConstr (WpEvApp _) = wpEvApp_constr+ toConstr (WpTyLam _) = wpTyLam_constr+ toConstr (WpTyApp _) = wpTyApp_constr+ toConstr (WpLet _) = wpLet_constr++ dataTypeOf _ = hsWrapper_dataType++hsWrapper_dataType :: Data.DataType+hsWrapper_dataType+ = Data.mkDataType "HsWrapper"+ [ wpHole_constr, wpCompose_constr, wpFun_constr, wpCast_constr+ , wpEvLam_constr, wpEvApp_constr, wpTyLam_constr, wpTyApp_constr+ , wpLet_constr]++wpHole_constr, wpCompose_constr, wpFun_constr, wpCast_constr, wpEvLam_constr,+ wpEvApp_constr, wpTyLam_constr, wpTyApp_constr, wpLet_constr :: Data.Constr+wpHole_constr = mkHsWrapperConstr "WpHole"+wpCompose_constr = mkHsWrapperConstr "WpCompose"+wpFun_constr = mkHsWrapperConstr "WpFun"+wpCast_constr = mkHsWrapperConstr "WpCast"+wpEvLam_constr = mkHsWrapperConstr "WpEvLam"+wpEvApp_constr = mkHsWrapperConstr "WpEvApp"+wpTyLam_constr = mkHsWrapperConstr "WpTyLam"+wpTyApp_constr = mkHsWrapperConstr "WpTyApp"+wpLet_constr = mkHsWrapperConstr "WpLet"++mkHsWrapperConstr :: String -> Data.Constr+mkHsWrapperConstr name = Data.mkConstr hsWrapper_dataType name [] Data.Prefix++wpFunEmpty :: HsWrapper -> HsWrapper -> TcType -> HsWrapper+wpFunEmpty c1 c2 t1 = WpFun c1 c2 t1 empty++(<.>) :: HsWrapper -> HsWrapper -> HsWrapper+WpHole <.> c = c+c <.> WpHole = c+c1 <.> c2 = c1 `WpCompose` c2++mkWpFun :: HsWrapper -> HsWrapper+ -> TcType -- the "from" type of the first wrapper+ -> TcType -- either type of the second wrapper (used only when the+ -- second wrapper is the identity)+ -> SDoc -- what caused you to want a WpFun? Something like "When converting ..."+ -> HsWrapper+mkWpFun WpHole WpHole _ _ _ = WpHole+mkWpFun WpHole (WpCast co2) t1 _ _ = WpCast (mkTcFunCo Representational (mkTcRepReflCo t1) co2)+mkWpFun (WpCast co1) WpHole _ t2 _ = WpCast (mkTcFunCo Representational (mkTcSymCo co1) (mkTcRepReflCo t2))+mkWpFun (WpCast co1) (WpCast co2) _ _ _ = WpCast (mkTcFunCo Representational (mkTcSymCo co1) co2)+mkWpFun co1 co2 t1 _ d = WpFun co1 co2 t1 d++-- | @mkWpFuns [(ty1, wrap1), (ty2, wrap2)] ty_res wrap_res@,+-- where @wrap1 :: ty1 "->" ty1'@ and @wrap2 :: ty2 "->" ty2'@,+-- @wrap3 :: ty3 "->" ty3'@ and @ty_res@ is /either/ @ty3@ or @ty3'@,+-- gives a wrapper @(ty1' -> ty2' -> ty3) "->" (ty1 -> ty2 -> ty3')@.+-- Notice that the result wrapper goes the other way round to all+-- the others. This is a result of sub-typing contravariance.+-- The SDoc is a description of what you were doing when you called mkWpFuns.+mkWpFuns :: [(TcType, HsWrapper)] -> TcType -> HsWrapper -> SDoc -> HsWrapper+mkWpFuns args res_ty res_wrap doc = snd $ go args res_ty res_wrap+ where+ go [] res_ty res_wrap = (res_ty, res_wrap)+ go ((arg_ty, arg_wrap) : args) res_ty res_wrap+ = let (tail_ty, tail_wrap) = go args res_ty res_wrap in+ (arg_ty `mkFunTy` tail_ty, mkWpFun arg_wrap tail_wrap arg_ty tail_ty doc)++mkWpCastR :: TcCoercionR -> HsWrapper+mkWpCastR co+ | isTcReflCo co = WpHole+ | otherwise = ASSERT2(tcCoercionRole co == Representational, ppr co)+ WpCast co++mkWpCastN :: TcCoercionN -> HsWrapper+mkWpCastN co+ | isTcReflCo co = WpHole+ | otherwise = ASSERT2(tcCoercionRole co == Nominal, ppr co)+ WpCast (mkTcSubCo co)+ -- The mkTcSubCo converts Nominal to Representational++mkWpTyApps :: [Type] -> HsWrapper+mkWpTyApps tys = mk_co_app_fn WpTyApp tys++mkWpEvApps :: [EvTerm] -> HsWrapper+mkWpEvApps args = mk_co_app_fn WpEvApp args++mkWpEvVarApps :: [EvVar] -> HsWrapper+mkWpEvVarApps vs = mk_co_app_fn WpEvApp (map EvId vs)++mkWpTyLams :: [TyVar] -> HsWrapper+mkWpTyLams ids = mk_co_lam_fn WpTyLam ids++mkWpLams :: [Var] -> HsWrapper+mkWpLams ids = mk_co_lam_fn WpEvLam ids++mkWpLet :: TcEvBinds -> HsWrapper+-- This no-op is a quite a common case+mkWpLet (EvBinds b) | isEmptyBag b = WpHole+mkWpLet ev_binds = WpLet ev_binds++mk_co_lam_fn :: (a -> HsWrapper) -> [a] -> HsWrapper+mk_co_lam_fn f as = foldr (\x wrap -> f x <.> wrap) WpHole as++mk_co_app_fn :: (a -> HsWrapper) -> [a] -> HsWrapper+-- For applications, the *first* argument must+-- come *last* in the composition sequence+mk_co_app_fn f as = foldr (\x wrap -> wrap <.> f x) WpHole as++idHsWrapper :: HsWrapper+idHsWrapper = WpHole++isIdHsWrapper :: HsWrapper -> Bool+isIdHsWrapper WpHole = True+isIdHsWrapper _ = False++collectHsWrapBinders :: HsWrapper -> ([Var], HsWrapper)+-- Collect the outer lambda binders of a HsWrapper,+-- stopping as soon as you get to a non-lambda binder+collectHsWrapBinders wrap = go wrap []+ where+ -- go w ws = collectHsWrapBinders (w <.> w1 <.> ... <.> wn)+ go :: HsWrapper -> [HsWrapper] -> ([Var], HsWrapper)+ go (WpEvLam v) wraps = add_lam v (gos wraps)+ go (WpTyLam v) wraps = add_lam v (gos wraps)+ go (WpCompose w1 w2) wraps = go w1 (w2:wraps)+ go wrap wraps = ([], foldl (<.>) wrap wraps)++ gos [] = ([], WpHole)+ gos (w:ws) = go w ws++ add_lam v (vs,w) = (v:vs, w)++{-+************************************************************************+* *+ Evidence bindings+* *+************************************************************************+-}++data TcEvBinds+ = TcEvBinds -- Mutable evidence bindings+ EvBindsVar -- Mutable because they are updated "later"+ -- when an implication constraint is solved++ | EvBinds -- Immutable after zonking+ (Bag EvBind)++data EvBindsVar+ = EvBindsVar {+ ebv_uniq :: Unique,+ -- The Unique is for debug printing only++ ebv_binds :: IORef EvBindMap,+ -- The main payload: the value-level evidence bindings+ -- (dictionaries etc)++ ebv_tcvs :: IORef CoVarSet+ -- The free coercion vars of the (rhss of) the coercion bindings+ --+ -- Coercions don't actually have bindings+ -- because we plug them in-place (via a mutable+ -- variable); but we keep their free variables+ -- so that we can report unused given constraints+ -- See Note [Tracking redundant constraints] in TcSimplify+ }++instance Data.Data TcEvBinds where+ -- Placeholder; we can't travers into TcEvBinds+ toConstr _ = abstractConstr "TcEvBinds"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = Data.mkNoRepType "TcEvBinds"++-----------------+newtype EvBindMap+ = EvBindMap {+ ev_bind_varenv :: DVarEnv EvBind+ } -- Map from evidence variables to evidence terms+ -- We use @DVarEnv@ here to get deterministic ordering when we+ -- turn it into a Bag.+ -- If we don't do that, when we generate let bindings for+ -- dictionaries in dsTcEvBinds they will be generated in random+ -- order.+ --+ -- For example:+ --+ -- let $dEq = GHC.Classes.$fEqInt in+ -- let $$dNum = GHC.Num.$fNumInt in ...+ --+ -- vs+ --+ -- let $dNum = GHC.Num.$fNumInt in+ -- let $dEq = GHC.Classes.$fEqInt in ...+ --+ -- See Note [Deterministic UniqFM] in UniqDFM for explanation why+ -- @UniqFM@ can lead to nondeterministic order.++emptyEvBindMap :: EvBindMap+emptyEvBindMap = EvBindMap { ev_bind_varenv = emptyDVarEnv }++extendEvBinds :: EvBindMap -> EvBind -> EvBindMap+extendEvBinds bs ev_bind+ = EvBindMap { ev_bind_varenv = extendDVarEnv (ev_bind_varenv bs)+ (eb_lhs ev_bind)+ ev_bind }++isEmptyEvBindMap :: EvBindMap -> Bool+isEmptyEvBindMap (EvBindMap m) = isEmptyDVarEnv m++lookupEvBind :: EvBindMap -> EvVar -> Maybe EvBind+lookupEvBind bs = lookupDVarEnv (ev_bind_varenv bs)++evBindMapBinds :: EvBindMap -> Bag EvBind+evBindMapBinds = foldEvBindMap consBag emptyBag++foldEvBindMap :: (EvBind -> a -> a) -> a -> EvBindMap -> a+foldEvBindMap k z bs = foldDVarEnv k z (ev_bind_varenv bs)++instance Outputable EvBindMap where+ ppr (EvBindMap m) = ppr m++-----------------+-- All evidence is bound by EvBinds; no side effects+data EvBind+ = EvBind { eb_lhs :: EvVar+ , eb_rhs :: EvTerm+ , eb_is_given :: Bool -- True <=> given+ -- See Note [Tracking redundant constraints] in TcSimplify+ }++evBindVar :: EvBind -> EvVar+evBindVar = eb_lhs++mkWantedEvBind :: EvVar -> EvTerm -> EvBind+mkWantedEvBind ev tm = EvBind { eb_is_given = False, eb_lhs = ev, eb_rhs = tm }+++mkGivenEvBind :: EvVar -> EvTerm -> EvBind+mkGivenEvBind ev tm = EvBind { eb_is_given = True, eb_lhs = ev, eb_rhs = tm }++data EvTerm+ = EvId EvId -- Any sort of evidence Id, including coercions++ | EvCoercion TcCoercion -- coercion bindings+ -- See Note [Coercion evidence terms]++ | EvCast EvTerm TcCoercionR -- d |> co++ | EvDFunApp DFunId -- Dictionary instance application+ [Type] [EvTerm]++ | EvDelayedError Type FastString -- Used with Opt_DeferTypeErrors+ -- See Note [Deferring coercion errors to runtime]+ -- in TcSimplify++ | EvSuperClass EvTerm Int -- n'th superclass. Used for both equalities and+ -- dictionaries, even though the former have no+ -- selector Id. We count up from _0_++ | EvLit EvLit -- Dictionary for KnownNat and KnownSymbol classes.+ -- Note [KnownNat & KnownSymbol and EvLit]++ | EvCallStack EvCallStack -- Dictionary for CallStack implicit parameters++ | EvTypeable Type EvTypeable -- Dictionary for (Typeable ty)++ | EvSelector Id [Type] [EvTerm] -- Selector id plus the types at which it+ -- should be instantiated, used for HasField+ -- dictionaries; see Note [HasField instances]+ -- in TcInterface++ deriving Data.Data+++-- | Instructions on how to make a 'Typeable' dictionary.+-- See Note [Typeable evidence terms]+data EvTypeable+ = EvTypeableTyCon TyCon [EvTerm]+ -- ^ Dictionary for @Typeable T@ where @T@ is a type constructor with all of+ -- its kind variables saturated. The @[EvTerm]@ is @Typeable@ evidence for+ -- the applied kinds..++ | EvTypeableTyApp EvTerm EvTerm+ -- ^ Dictionary for @Typeable (s t)@,+ -- given a dictionaries for @s@ and @t@.++ | EvTypeableTrFun EvTerm EvTerm+ -- ^ Dictionary for @Typeable (s -> t)@,+ -- given a dictionaries for @s@ and @t@.++ | EvTypeableTyLit EvTerm+ -- ^ Dictionary for a type literal,+ -- e.g. @Typeable "foo"@ or @Typeable 3@+ -- The 'EvTerm' is evidence of, e.g., @KnownNat 3@+ -- (see Trac #10348)+ deriving Data.Data++data EvLit+ = EvNum Integer+ | EvStr FastString+ deriving Data.Data++-- | Evidence for @CallStack@ implicit parameters.+data EvCallStack+ -- See Note [Overview of implicit CallStacks]+ = EvCsEmpty+ | EvCsPushCall Name RealSrcSpan EvTerm+ -- ^ @EvCsPushCall name loc stk@ represents a call to @name@, occurring at+ -- @loc@, in a calling context @stk@.+ deriving Data.Data++{-+Note [Typeable evidence terms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The EvTypeable data type looks isomorphic to Type, but the EvTerms+inside can be EvIds. Eg+ f :: forall a. Typeable a => a -> TypeRep+ f x = typeRep (undefined :: Proxy [a])+Here for the (Typeable [a]) dictionary passed to typeRep we make+evidence+ dl :: Typeable [a] = EvTypeable [a]+ (EvTypeableTyApp (EvTypeableTyCon []) (EvId d))+where+ d :: Typable a+is the lambda-bound dictionary passed into f.++Note [Coercion evidence terms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A "coercion evidence term" takes one of these forms+ co_tm ::= EvId v where v :: t1 ~# t2+ | EvCoercion co+ | EvCast co_tm co++We do quite often need to get a TcCoercion from an EvTerm; see+'evTermCoercion'.++INVARIANT: The evidence for any constraint with type (t1 ~# t2) is+a coercion evidence term. Consider for example+ [G] d :: F Int a+If we have+ ax7 a :: F Int a ~ (a ~ Bool)+then we do NOT generate the constraint+ [G] (d |> ax7 a) :: a ~ Bool+because that does not satisfy the invariant (d is not a coercion variable).+Instead we make a binding+ g1 :: a~Bool = g |> ax7 a+and the constraint+ [G] g1 :: a~Bool+See Trac [7238] and Note [Bind new Givens immediately] in TcRnTypes++Note [EvBinds/EvTerm]+~~~~~~~~~~~~~~~~~~~~~+How evidence is created and updated. Bindings for dictionaries,+and coercions and implicit parameters are carried around in TcEvBinds+which during constraint generation and simplification is always of the+form (TcEvBinds ref). After constraint simplification is finished it+will be transformed to t an (EvBinds ev_bag).++Evidence for coercions *SHOULD* be filled in using the TcEvBinds+However, all EvVars that correspond to *wanted* coercion terms in+an EvBind must be mutable variables so that they can be readily+inlined (by zonking) after constraint simplification is finished.++Conclusion: a new wanted coercion variable should be made mutable.+[Notice though that evidence variables that bind coercion terms+ from super classes will be "given" and hence rigid]+++Note [KnownNat & KnownSymbol and EvLit]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A part of the type-level literals implementation are the classes+"KnownNat" and "KnownSymbol", which provide a "smart" constructor for+defining singleton values. Here is the key stuff from GHC.TypeLits++ class KnownNat (n :: Nat) where+ natSing :: SNat n++ newtype SNat (n :: Nat) = SNat Integer++Conceptually, this class has infinitely many instances:++ instance KnownNat 0 where natSing = SNat 0+ instance KnownNat 1 where natSing = SNat 1+ instance KnownNat 2 where natSing = SNat 2+ ...++In practice, we solve `KnownNat` predicates in the type-checker+(see typecheck/TcInteract.hs) because we can't have infinitely many instances.+The evidence (aka "dictionary") for `KnownNat` is of the form `EvLit (EvNum n)`.++We make the following assumptions about dictionaries in GHC:+ 1. The "dictionary" for classes with a single method---like `KnownNat`---is+ a newtype for the type of the method, so using a evidence amounts+ to a coercion, and+ 2. Newtypes use the same representation as their definition types.++So, the evidence for `KnownNat` is just a value of the representation type,+wrapped in two newtype constructors: one to make it into a `SNat` value,+and another to make it into a `KnownNat` dictionary.++Also note that `natSing` and `SNat` are never actually exposed from the+library---they are just an implementation detail. Instead, users see+a more convenient function, defined in terms of `natSing`:++ natVal :: KnownNat n => proxy n -> Integer++The reason we don't use this directly in the class is that it is simpler+and more efficient to pass around an integer rather than an entier function,+especially when the `KnowNat` evidence is packaged up in an existential.++The story for kind `Symbol` is analogous:+ * class KnownSymbol+ * newtype SSymbol+ * Evidence: EvLit (EvStr n)+++Note [Overview of implicit CallStacks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(See https://ghc.haskell.org/trac/ghc/wiki/ExplicitCallStack/ImplicitLocations)++The goal of CallStack evidence terms is to reify locations+in the program source as runtime values, without any support+from the RTS. We accomplish this by assigning a special meaning+to constraints of type GHC.Stack.Types.HasCallStack, an alias++ type HasCallStack = (?callStack :: CallStack)++Implicit parameters of type GHC.Stack.Types.CallStack (the name is not+important) are solved in three steps:++1. Occurrences of CallStack IPs are solved directly from the given IP,+ just like a regular IP. For example, the occurrence of `?stk` in++ error :: (?stk :: CallStack) => String -> a+ error s = raise (ErrorCall (s ++ prettyCallStack ?stk))++ will be solved for the `?stk` in `error`s context as before.++2. In a function call, instead of simply passing the given IP, we first+ append the current call-site to it. For example, consider a+ call to the callstack-aware `error` above.++ undefined :: (?stk :: CallStack) => a+ undefined = error "undefined!"++ Here we want to take the given `?stk` and append the current+ call-site, before passing it to `error`. In essence, we want to+ rewrite `error "undefined!"` to++ let ?stk = pushCallStack <error's location> ?stk+ in error "undefined!"++ We achieve this effect by emitting a NEW wanted++ [W] d :: IP "stk" CallStack++ from which we build the evidence term++ EvCsPushCall "error" <error's location> (EvId d)++ that we use to solve the call to `error`. The new wanted `d` will+ then be solved per rule (1), ie as a regular IP.++ (see TcInteract.interactDict)++3. We default any insoluble CallStacks to the empty CallStack. Suppose+ `undefined` did not request a CallStack, ie++ undefinedNoStk :: a+ undefinedNoStk = error "undefined!"++ Under the usual IP rules, the new wanted from rule (2) would be+ insoluble as there's no given IP from which to solve it, so we+ would get an "unbound implicit parameter" error.++ We don't ever want to emit an insoluble CallStack IP, so we add a+ defaulting pass to default any remaining wanted CallStacks to the+ empty CallStack with the evidence term++ EvCsEmpty++ (see TcSimplify.simpl_top and TcSimplify.defaultCallStacks)++This provides a lightweight mechanism for building up call-stacks+explicitly, but is notably limited by the fact that the stack will+stop at the first function whose type does not include a CallStack IP.+For example, using the above definition of `undefined`:++ head :: [a] -> a+ head [] = undefined+ head (x:_) = x++ g = head []++the resulting CallStack will include the call to `undefined` in `head`+and the call to `error` in `undefined`, but *not* the call to `head`+in `g`, because `head` did not explicitly request a CallStack.+++Important Details:+- GHC should NEVER report an insoluble CallStack constraint.++- GHC should NEVER infer a CallStack constraint unless one was requested+ with a partial type signature (See TcType.pickQuantifiablePreds).++- A CallStack (defined in GHC.Stack.Types) is a [(String, SrcLoc)],+ where the String is the name of the binder that is used at the+ SrcLoc. SrcLoc is also defined in GHC.Stack.Types and contains the+ package/module/file name, as well as the full source-span. Both+ CallStack and SrcLoc are kept abstract so only GHC can construct new+ values.++- We will automatically solve any wanted CallStack regardless of the+ name of the IP, i.e.++ f = show (?stk :: CallStack)+ g = show (?loc :: CallStack)++ are both valid. However, we will only push new SrcLocs onto existing+ CallStacks when the IP names match, e.g. in++ head :: (?loc :: CallStack) => [a] -> a+ head [] = error (show (?stk :: CallStack))++ the printed CallStack will NOT include head's call-site. This reflects the+ standard scoping rules of implicit-parameters.++- An EvCallStack term desugars to a CoreExpr of type `IP "some str" CallStack`.+ The desugarer will need to unwrap the IP newtype before pushing a new+ call-site onto a given stack (See DsBinds.dsEvCallStack)++- When we emit a new wanted CallStack from rule (2) we set its origin to+ `IPOccOrigin ip_name` instead of the original `OccurrenceOf func`+ (see TcInteract.interactDict).++ This is a bit shady, but is how we ensure that the new wanted is+ solved like a regular IP.++-}++mkEvCast :: EvTerm -> TcCoercion -> EvTerm+mkEvCast ev lco+ | ASSERT2(tcCoercionRole lco == Representational, (vcat [text "Coercion of wrong role passed to mkEvCast:", ppr ev, ppr lco]))+ isTcReflCo lco = ev+ | otherwise = EvCast ev lco++mkEvScSelectors :: EvTerm -> Class -> [TcType] -> [(TcPredType, EvTerm)]+mkEvScSelectors ev cls tys+ = zipWith mk_pr (immSuperClasses cls tys) [0..]+ where+ mk_pr pred i = (pred, EvSuperClass ev i)++emptyTcEvBinds :: TcEvBinds+emptyTcEvBinds = EvBinds emptyBag++isEmptyTcEvBinds :: TcEvBinds -> Bool+isEmptyTcEvBinds (EvBinds b) = isEmptyBag b+isEmptyTcEvBinds (TcEvBinds {}) = panic "isEmptyTcEvBinds"+++evTermCoercion :: EvTerm -> TcCoercion+-- Applied only to EvTerms of type (s~t)+-- See Note [Coercion evidence terms]+evTermCoercion (EvId v) = mkCoVarCo v+evTermCoercion (EvCoercion co) = co+evTermCoercion (EvCast tm co) = mkCoCast (evTermCoercion tm) co+evTermCoercion tm = pprPanic "evTermCoercion" (ppr tm)++evVarsOfTerm :: EvTerm -> VarSet+evVarsOfTerm (EvId v) = unitVarSet v+evVarsOfTerm (EvCoercion co) = coVarsOfCo co+evVarsOfTerm (EvDFunApp _ _ evs) = mapUnionVarSet evVarsOfTerm evs+evVarsOfTerm (EvSuperClass v _) = evVarsOfTerm v+evVarsOfTerm (EvCast tm co) = evVarsOfTerm tm `unionVarSet` coVarsOfCo co+evVarsOfTerm (EvDelayedError _ _) = emptyVarSet+evVarsOfTerm (EvLit _) = emptyVarSet+evVarsOfTerm (EvCallStack cs) = evVarsOfCallStack cs+evVarsOfTerm (EvTypeable _ ev) = evVarsOfTypeable ev+evVarsOfTerm (EvSelector _ _ evs) = mapUnionVarSet evVarsOfTerm evs++evVarsOfTerms :: [EvTerm] -> VarSet+evVarsOfTerms = mapUnionVarSet evVarsOfTerm++-- | Do SCC analysis on a bag of 'EvBind's.+sccEvBinds :: Bag EvBind -> [SCC EvBind]+sccEvBinds bs = stronglyConnCompFromEdgedVerticesUniq edges+ where+ edges :: [(EvBind, EvVar, [EvVar])]+ edges = foldrBag ((:) . mk_node) [] bs++ mk_node :: EvBind -> (EvBind, EvVar, [EvVar])+ mk_node b@(EvBind { eb_lhs = var, eb_rhs = term })+ = (b, var, nonDetEltsUniqSet (evVarsOfTerm term `unionVarSet`+ coVarsOfType (varType var)))+ -- It's OK to use nonDetEltsUniqSet here as stronglyConnCompFromEdgedVertices+ -- is still deterministic even if the edges are in nondeterministic order+ -- as explained in Note [Deterministic SCC] in Digraph.++evVarsOfCallStack :: EvCallStack -> VarSet+evVarsOfCallStack cs = case cs of+ EvCsEmpty -> emptyVarSet+ EvCsPushCall _ _ tm -> evVarsOfTerm tm++evVarsOfTypeable :: EvTypeable -> VarSet+evVarsOfTypeable ev =+ case ev of+ EvTypeableTyCon _ e -> mapUnionVarSet evVarsOfTerm e+ EvTypeableTyApp e1 e2 -> evVarsOfTerms [e1,e2]+ EvTypeableTrFun e1 e2 -> evVarsOfTerms [e1,e2]+ EvTypeableTyLit e -> evVarsOfTerm e++{-+************************************************************************+* *+ Pretty printing+* *+************************************************************************+-}++instance Outputable HsWrapper where+ ppr co_fn = pprHsWrapper co_fn (no_parens (text "<>"))++pprHsWrapper :: HsWrapper -> (Bool -> SDoc) -> SDoc+-- With -fprint-typechecker-elaboration, print the wrapper+-- otherwise just print what's inside+-- The pp_thing_inside function takes Bool to say whether+-- it's in a position that needs parens for a non-atomic thing+pprHsWrapper wrap pp_thing_inside+ = sdocWithDynFlags $ \ dflags ->+ if gopt Opt_PrintTypecheckerElaboration dflags+ then help pp_thing_inside wrap False+ else pp_thing_inside False+ where+ help :: (Bool -> SDoc) -> HsWrapper -> Bool -> SDoc+ -- True <=> appears in function application position+ -- False <=> appears as body of let or lambda+ help it WpHole = it+ help it (WpCompose f1 f2) = help (help it f2) f1+ help it (WpFun f1 f2 t1 _) = add_parens $ text "\\(x" <> dcolon <> ppr t1 <> text ")." <+>+ help (\_ -> it True <+> help (\_ -> text "x") f1 True) f2 False+ help it (WpCast co) = add_parens $ sep [it False, nest 2 (text "|>"+ <+> pprParendCo co)]+ help it (WpEvApp id) = no_parens $ sep [it True, nest 2 (ppr id)]+ help it (WpTyApp ty) = no_parens $ sep [it True, text "@" <+> pprParendType ty]+ help it (WpEvLam id) = add_parens $ sep [ text "\\" <> pp_bndr id, it False]+ help it (WpTyLam tv) = add_parens $ sep [text "/\\" <> pp_bndr tv, it False]+ help it (WpLet binds) = add_parens $ sep [text "let" <+> braces (ppr binds), it False]++ pp_bndr v = pprBndr LambdaBind v <> dot++add_parens, no_parens :: SDoc -> Bool -> SDoc+add_parens d True = parens d+add_parens d False = d+no_parens d _ = d++instance Outputable TcEvBinds where+ ppr (TcEvBinds v) = ppr v+ ppr (EvBinds bs) = text "EvBinds" <> braces (vcat (map ppr (bagToList bs)))++instance Outputable EvBindsVar where+ ppr (EvBindsVar { ebv_uniq = u })+ = text "EvBindsVar" <> angleBrackets (ppr u)++instance Uniquable EvBindsVar where+ getUnique (EvBindsVar { ebv_uniq = u }) = u++instance Outputable EvBind where+ ppr (EvBind { eb_lhs = v, eb_rhs = e, eb_is_given = is_given })+ = sep [ pp_gw <+> ppr v+ , nest 2 $ equals <+> ppr e ]+ where+ pp_gw = brackets (if is_given then char 'G' else char 'W')+ -- We cheat a bit and pretend EqVars are CoVars for the purposes of pretty printing++instance Outputable EvTerm where+ ppr (EvId v) = ppr v+ ppr (EvCast v co) = ppr v <+> (text "`cast`") <+> pprParendCo co+ ppr (EvCoercion co) = text "CO" <+> ppr co+ ppr (EvSuperClass d n) = text "sc" <> parens (ppr (d,n))+ ppr (EvDFunApp df tys ts) = ppr df <+> sep [ char '@' <> ppr tys, ppr ts ]+ ppr (EvLit l) = ppr l+ ppr (EvCallStack cs) = ppr cs+ ppr (EvDelayedError ty msg) = text "error"+ <+> sep [ char '@' <> ppr ty, ppr msg ]+ ppr (EvTypeable ty ev) = ppr ev <+> dcolon <+> text "Typeable" <+> ppr ty+ ppr (EvSelector sel tys ts) = ppr sel <+> sep [ char '@' <> ppr tys, ppr ts]++instance Outputable EvLit where+ ppr (EvNum n) = integer n+ ppr (EvStr s) = text (show s)++instance Outputable EvCallStack where+ ppr EvCsEmpty+ = text "[]"+ ppr (EvCsPushCall name loc tm)+ = ppr (name,loc) <+> text ":" <+> ppr tm++instance Outputable EvTypeable where+ ppr (EvTypeableTyCon ts _) = text "TyCon" <+> ppr ts+ ppr (EvTypeableTyApp t1 t2) = parens (ppr t1 <+> ppr t2)+ ppr (EvTypeableTrFun t1 t2) = parens (ppr t1 <+> arrow <+> ppr t2)+ ppr (EvTypeableTyLit t1) = text "TyLit" <> ppr t1+++----------------------------------------------------------------------+-- Helper functions for dealing with IP newtype-dictionaries+----------------------------------------------------------------------++-- | Create a 'Coercion' that unwraps an implicit-parameter or+-- overloaded-label dictionary to expose the underlying value. We+-- expect the 'Type' to have the form `IP sym ty` or `IsLabel sym ty`,+-- and return a 'Coercion' `co :: IP sym ty ~ ty` or+-- `co :: IsLabel sym ty ~ Proxy# sym -> ty`. See also+-- Note [Type-checking overloaded labels] in TcExpr.+unwrapIP :: Type -> CoercionR+unwrapIP ty =+ case unwrapNewTyCon_maybe tc of+ Just (_,_,ax) -> mkUnbranchedAxInstCo Representational ax tys []+ Nothing -> pprPanic "unwrapIP" $+ text "The dictionary for" <+> quotes (ppr tc)+ <+> text "is not a newtype!"+ where+ (tc, tys) = splitTyConApp ty++-- | Create a 'Coercion' that wraps a value in an implicit-parameter+-- dictionary. See 'unwrapIP'.+wrapIP :: Type -> CoercionR+wrapIP ty = mkSymCo (unwrapIP ty)
+ typecheck/TcExpr.hs view
@@ -0,0 +1,2727 @@+{-+%+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[TcExpr]{Typecheck an expression}+-}++{-# LANGUAGE CPP, TupleSections, ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}++module TcExpr ( tcPolyExpr, tcMonoExpr, tcMonoExprNC,+ tcInferSigma, tcInferSigmaNC, tcInferRho, tcInferRhoNC,+ tcSyntaxOp, tcSyntaxOpGen, SyntaxOpType(..), synKnownType,+ tcCheckId,+ addExprErrCtxt,+ getFixedTyVars ) where++#include "HsVersions.h"++import {-# SOURCE #-} TcSplice( tcSpliceExpr, tcTypedBracket, tcUntypedBracket )+import THNames( liftStringName, liftName )++import HsSyn+import TcHsSyn+import TcRnMonad+import TcUnify+import BasicTypes+import Inst+import TcBinds ( chooseInferredQuantifiers, tcLocalBinds )+import TcSigs ( tcUserTypeSig, tcInstSig )+import TcSimplify ( simplifyInfer, InferMode(..) )+import FamInst ( tcGetFamInstEnvs, tcLookupDataFamInst )+import FamInstEnv ( FamInstEnvs )+import RnEnv ( addUsedGRE, addNameClashErrRn+ , unknownSubordinateErr )+import TcEnv+import TcArrows+import TcMatches+import TcHsType+import TcPatSyn( tcPatSynBuilderOcc, nonBidirectionalErr )+import TcPat+import TcMType+import TcType+import DsMonad+import Id+import IdInfo+import ConLike+import DataCon+import PatSyn+import Name+import NameEnv+import NameSet+import RdrName+import TyCon+import Type+import TcEvidence+import VarSet+import TysWiredIn+import TysPrim( intPrimTy )+import PrimOp( tagToEnumKey )+import PrelNames+import DynFlags+import SrcLoc+import Util+import VarEnv ( emptyTidyEnv )+import ListSetOps+import Maybes+import Outputable+import FastString+import Control.Monad+import Class(classTyCon)+import UniqSet ( nonDetEltsUniqSet )+import qualified GHC.LanguageExtensions as LangExt++import Data.Function+import Data.List+import Data.Either+import qualified Data.Set as Set++{-+************************************************************************+* *+\subsection{Main wrappers}+* *+************************************************************************+-}++tcPolyExpr, tcPolyExprNC+ :: LHsExpr Name -- Expression to type check+ -> TcSigmaType -- Expected type (could be a polytype)+ -> TcM (LHsExpr TcId) -- Generalised expr with expected type++-- tcPolyExpr is a convenient place (frequent but not too frequent)+-- place to add context information.+-- The NC version does not do so, usually because the caller wants+-- to do so himself.++tcPolyExpr expr res_ty = tc_poly_expr expr (mkCheckExpType res_ty)+tcPolyExprNC expr res_ty = tc_poly_expr_nc expr (mkCheckExpType res_ty)++-- these versions take an ExpType+tc_poly_expr, tc_poly_expr_nc :: LHsExpr Name -> ExpSigmaType -> TcM (LHsExpr TcId)+tc_poly_expr expr res_ty+ = addExprErrCtxt expr $+ do { traceTc "tcPolyExpr" (ppr res_ty); tc_poly_expr_nc expr res_ty }++tc_poly_expr_nc (L loc expr) res_ty+ = do { traceTc "tcPolyExprNC" (ppr res_ty)+ ; (wrap, expr')+ <- tcSkolemiseET GenSigCtxt res_ty $ \ res_ty ->+ setSrcSpan loc $+ -- NB: setSrcSpan *after* skolemising, so we get better+ -- skolem locations+ tcExpr expr res_ty+ ; return $ L loc (mkHsWrap wrap expr') }++---------------+tcMonoExpr, tcMonoExprNC+ :: LHsExpr Name -- Expression to type check+ -> ExpRhoType -- Expected type+ -- Definitely no foralls at the top+ -> TcM (LHsExpr TcId)++tcMonoExpr expr res_ty+ = addErrCtxt (exprCtxt expr) $+ tcMonoExprNC expr res_ty++tcMonoExprNC (L loc expr) res_ty+ = setSrcSpan loc $+ do { expr' <- tcExpr expr res_ty+ ; return (L loc expr') }++---------------+tcInferSigma, tcInferSigmaNC :: LHsExpr Name -> TcM ( LHsExpr TcId+ , TcSigmaType )+-- Infer a *sigma*-type.+tcInferSigma expr = addErrCtxt (exprCtxt expr) (tcInferSigmaNC expr)++tcInferSigmaNC (L loc expr)+ = setSrcSpan loc $+ do { (expr', sigma) <- tcInferNoInst (tcExpr expr)+ ; return (L loc expr', sigma) }++tcInferRho, tcInferRhoNC :: LHsExpr Name -> TcM (LHsExpr TcId, TcRhoType)+-- Infer a *rho*-type. The return type is always (shallowly) instantiated.+tcInferRho expr = addErrCtxt (exprCtxt expr) (tcInferRhoNC expr)++tcInferRhoNC expr+ = do { (expr', sigma) <- tcInferSigmaNC expr+ ; (wrap, rho) <- topInstantiate (lexprCtOrigin expr) sigma+ ; return (mkLHsWrap wrap expr', rho) }+++{-+************************************************************************+* *+ tcExpr: the main expression typechecker+* *+************************************************************************++NB: The res_ty is always deeply skolemised.+-}++tcExpr :: HsExpr Name -> ExpRhoType -> TcM (HsExpr TcId)+tcExpr (HsVar (L _ name)) res_ty = tcCheckId name res_ty+tcExpr (HsUnboundVar uv) res_ty = tcUnboundId uv res_ty++tcExpr e@(HsApp {}) res_ty = tcApp1 e res_ty+tcExpr e@(HsAppType {}) res_ty = tcApp1 e res_ty++tcExpr e@(HsLit lit) res_ty = do { let lit_ty = hsLitType lit+ ; tcWrapResult e (HsLit lit) lit_ty res_ty }++tcExpr (HsPar expr) res_ty = do { expr' <- tcMonoExprNC expr res_ty+ ; return (HsPar expr') }++tcExpr (HsSCC src lbl expr) res_ty+ = do { expr' <- tcMonoExpr expr res_ty+ ; return (HsSCC src lbl expr') }++tcExpr (HsTickPragma src info srcInfo expr) res_ty+ = do { expr' <- tcMonoExpr expr res_ty+ ; return (HsTickPragma src info srcInfo expr') }++tcExpr (HsCoreAnn src lbl expr) res_ty+ = do { expr' <- tcMonoExpr expr res_ty+ ; return (HsCoreAnn src lbl expr') }++tcExpr (HsOverLit lit) res_ty+ = do { lit' <- newOverloadedLit lit res_ty+ ; return (HsOverLit lit') }++tcExpr (NegApp expr neg_expr) res_ty+ = do { (expr', neg_expr')+ <- tcSyntaxOp NegateOrigin neg_expr [SynAny] res_ty $+ \[arg_ty] ->+ tcMonoExpr expr (mkCheckExpType arg_ty)+ ; return (NegApp expr' neg_expr') }++tcExpr e@(HsIPVar x) res_ty+ = do { {- Implicit parameters must have a *tau-type* not a+ type scheme. We enforce this by creating a fresh+ type variable as its type. (Because res_ty may not+ be a tau-type.) -}+ ip_ty <- newOpenFlexiTyVarTy+ ; let ip_name = mkStrLitTy (hsIPNameFS x)+ ; ipClass <- tcLookupClass ipClassName+ ; ip_var <- emitWantedEvVar origin (mkClassPred ipClass [ip_name, ip_ty])+ ; tcWrapResult e (fromDict ipClass ip_name ip_ty (HsVar (noLoc ip_var)))+ ip_ty res_ty }+ where+ -- Coerces a dictionary for `IP "x" t` into `t`.+ fromDict ipClass x ty = HsWrap $ mkWpCastR $+ unwrapIP $ mkClassPred ipClass [x,ty]+ origin = IPOccOrigin x++tcExpr e@(HsOverLabel mb_fromLabel l) res_ty+ = do { -- See Note [Type-checking overloaded labels]+ loc <- getSrcSpanM+ ; case mb_fromLabel of+ Just fromLabel -> tcExpr (applyFromLabel loc fromLabel) res_ty+ Nothing -> do { isLabelClass <- tcLookupClass isLabelClassName+ ; alpha <- newFlexiTyVarTy liftedTypeKind+ ; let pred = mkClassPred isLabelClass [lbl, alpha]+ ; loc <- getSrcSpanM+ ; var <- emitWantedEvVar origin pred+ ; tcWrapResult e (fromDict pred (HsVar (L loc var)))+ alpha res_ty } }+ where+ -- Coerces a dictionary for `IsLabel "x" t` into `t`,+ -- or `HasField "x" r a into `r -> a`.+ fromDict pred = HsWrap $ mkWpCastR $ unwrapIP pred+ origin = OverLabelOrigin l+ lbl = mkStrLitTy l++ applyFromLabel loc fromLabel =+ L loc (HsVar (L loc fromLabel)) `HsAppType`+ mkEmptyWildCardBndrs (L loc (HsTyLit (HsStrTy NoSourceText l)))++tcExpr (HsLam match) res_ty+ = do { (match', wrap) <- tcMatchLambda herald match_ctxt match res_ty+ ; return (mkHsWrap wrap (HsLam match')) }+ where+ match_ctxt = MC { mc_what = LambdaExpr, mc_body = tcBody }+ herald = sep [ text "The lambda expression" <+>+ quotes (pprSetDepth (PartWay 1) $+ pprMatches match),+ -- The pprSetDepth makes the abstraction print briefly+ text "has"]++tcExpr e@(HsLamCase matches) res_ty+ = do { (matches', wrap)+ <- tcMatchLambda msg match_ctxt matches res_ty+ -- The laziness annotation is because we don't want to fail here+ -- if there are multiple arguments+ ; return (mkHsWrap wrap $ HsLamCase matches') }+ where+ msg = sep [ text "The function" <+> quotes (ppr e)+ , text "requires"]+ match_ctxt = MC { mc_what = CaseAlt, mc_body = tcBody }++tcExpr e@(ExprWithTySig expr sig_ty) res_ty+ = do { let loc = getLoc (hsSigWcType sig_ty)+ ; sig_info <- checkNoErrs $ -- Avoid error cascade+ tcUserTypeSig loc sig_ty Nothing+ ; (expr', poly_ty) <- tcExprSig expr sig_info+ ; let expr'' = ExprWithTySigOut expr' sig_ty+ ; tcWrapResult e expr'' poly_ty res_ty }++{-+Note [Type-checking overloaded labels]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Recall that we have++ module GHC.OverloadedLabels where+ class IsLabel (x :: Symbol) a where+ fromLabel :: a++We translate `#foo` to `fromLabel @"foo"`, where we use++ * the in-scope `fromLabel` if `RebindableSyntax` is enabled; or if not+ * `GHC.OverloadedLabels.fromLabel`.++In the `RebindableSyntax` case, the renamer will have filled in the+first field of `HsOverLabel` with the `fromLabel` function to use, and+we simply apply it to the appropriate visible type argument.++In the `OverloadedLabels` case, when we see an overloaded label like+`#foo`, we generate a fresh variable `alpha` for the type and emit an+`IsLabel "foo" alpha` constraint. Because the `IsLabel` class has a+single method, it is represented by a newtype, so we can coerce+`IsLabel "foo" alpha` to `alpha` (just like for implicit parameters).++-}+++{-+************************************************************************+* *+ Infix operators and sections+* *+************************************************************************++Note [Left sections]+~~~~~~~~~~~~~~~~~~~~+Left sections, like (4 *), are equivalent to+ \ x -> (*) 4 x,+or, if PostfixOperators is enabled, just+ (*) 4+With PostfixOperators we don't actually require the function to take+two arguments at all. For example, (x `not`) means (not x); you get+postfix operators! Not Haskell 98, but it's less work and kind of+useful.++Note [Typing rule for ($)]+~~~~~~~~~~~~~~~~~~~~~~~~~~+People write+ runST $ blah+so much, where+ runST :: (forall s. ST s a) -> a+that I have finally given in and written a special type-checking+rule just for saturated applications of ($).+ * Infer the type of the first argument+ * Decompose it; should be of form (arg2_ty -> res_ty),+ where arg2_ty might be a polytype+ * Use arg2_ty to typecheck arg2++Note [Typing rule for seq]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to allow+ x `seq` (# p,q #)+which suggests this type for seq:+ seq :: forall (a:*) (b:Open). a -> b -> b,+with (b:Open) meaning that be can be instantiated with an unboxed+tuple. The trouble is that this might accept a partially-applied+'seq', and I'm just not certain that would work. I'm only sure it's+only going to work when it's fully applied, so it turns into+ case x of _ -> (# p,q #)++So it seems more uniform to treat 'seq' as if it was a language+construct.++See also Note [seqId magic] in MkId+-}++tcExpr expr@(OpApp arg1 op fix arg2) res_ty+ | (L loc (HsVar (L lv op_name))) <- op+ , op_name `hasKey` seqIdKey -- Note [Typing rule for seq]+ = do { arg1_ty <- newFlexiTyVarTy liftedTypeKind+ ; let arg2_exp_ty = res_ty+ ; arg1' <- tcArg op arg1 arg1_ty 1+ ; arg2' <- addErrCtxt (funAppCtxt op arg2 2) $+ tc_poly_expr_nc arg2 arg2_exp_ty+ ; arg2_ty <- readExpType arg2_exp_ty+ ; op_id <- tcLookupId op_name+ ; let op' = L loc (HsWrap (mkWpTyApps [arg1_ty, arg2_ty])+ (HsVar (L lv op_id)))+ ; return $ OpApp arg1' op' fix arg2' }++ | (L loc (HsVar (L lv op_name))) <- op+ , op_name `hasKey` dollarIdKey -- Note [Typing rule for ($)]+ = do { traceTc "Application rule" (ppr op)+ ; (arg1', arg1_ty) <- tcInferSigma arg1++ ; let doc = text "The first argument of ($) takes"+ orig1 = lexprCtOrigin arg1+ ; (wrap_arg1, [arg2_sigma], op_res_ty) <-+ matchActualFunTys doc orig1 (Just arg1) 1 arg1_ty++ -- We have (arg1 $ arg2)+ -- So: arg1_ty = arg2_ty -> op_res_ty+ -- where arg2_sigma maybe polymorphic; that's the point++ ; arg2' <- tcArg op arg2 arg2_sigma 2++ -- Make sure that the argument type has kind '*'+ -- ($) :: forall (r:RuntimeRep) (a:*) (b:TYPE r). (a->b) -> a -> b+ -- Eg we do not want to allow (D# $ 4.0#) Trac #5570+ -- (which gives a seg fault)+ --+ -- The *result* type can have any kind (Trac #8739),+ -- so we don't need to check anything for that+ ; _ <- unifyKind (Just arg2_sigma) (typeKind arg2_sigma) liftedTypeKind+ -- ignore the evidence. arg2_sigma must have type * or #,+ -- because we know arg2_sigma -> or_res_ty is well-kinded+ -- (because otherwise matchActualFunTys would fail)+ -- There's no possibility here of, say, a kind family reducing to *.++ ; wrap_res <- tcSubTypeHR orig1 (Just expr) op_res_ty res_ty+ -- op_res -> res++ ; op_id <- tcLookupId op_name+ ; res_ty <- readExpType res_ty+ ; let op' = L loc (HsWrap (mkWpTyApps [ getRuntimeRep "tcExpr ($)" res_ty+ , arg2_sigma+ , res_ty])+ (HsVar (L lv op_id)))+ -- arg1' :: arg1_ty+ -- wrap_arg1 :: arg1_ty "->" (arg2_sigma -> op_res_ty)+ -- wrap_res :: op_res_ty "->" res_ty+ -- op' :: (a2_ty -> res_ty) -> a2_ty -> res_ty++ -- wrap1 :: arg1_ty "->" (arg2_sigma -> res_ty)+ wrap1 = mkWpFun idHsWrapper wrap_res arg2_sigma res_ty doc+ <.> wrap_arg1+ doc = text "When looking at the argument to ($)"++ ; return (OpApp (mkLHsWrap wrap1 arg1') op' fix arg2') }++ | (L loc (HsRecFld (Ambiguous lbl _))) <- op+ , Just sig_ty <- obviousSig (unLoc arg1)+ -- See Note [Disambiguating record fields]+ = do { sig_tc_ty <- tcHsSigWcType ExprSigCtxt sig_ty+ ; sel_name <- disambiguateSelector lbl sig_tc_ty+ ; let op' = L loc (HsRecFld (Unambiguous lbl sel_name))+ ; tcExpr (OpApp arg1 op' fix arg2) res_ty+ }++ | otherwise+ = do { traceTc "Non Application rule" (ppr op)+ ; (wrap, op', [Left arg1', Left arg2'])+ <- tcApp (Just $ mk_op_msg op)+ op [Left arg1, Left arg2] res_ty+ ; return (mkHsWrap wrap $ OpApp arg1' op' fix arg2') }++-- Right sections, equivalent to \ x -> x `op` expr, or+-- \ x -> op x expr++tcExpr expr@(SectionR op arg2) res_ty+ = do { (op', op_ty) <- tcInferFun op+ ; (wrap_fun, [arg1_ty, arg2_ty], op_res_ty)+ <- matchActualFunTys (mk_op_msg op) fn_orig (Just op) 2 op_ty+ ; wrap_res <- tcSubTypeHR SectionOrigin (Just expr)+ (mkFunTy arg1_ty op_res_ty) res_ty+ ; arg2' <- tcArg op arg2 arg2_ty 2+ ; return ( mkHsWrap wrap_res $+ SectionR (mkLHsWrap wrap_fun op') arg2' ) }+ where+ fn_orig = lexprCtOrigin op+ -- It's important to use the origin of 'op', so that call-stacks+ -- come out right; they are driven by the OccurrenceOf CtOrigin+ -- See Trac #13285++tcExpr expr@(SectionL arg1 op) res_ty+ = do { (op', op_ty) <- tcInferFun op+ ; dflags <- getDynFlags -- Note [Left sections]+ ; let n_reqd_args | xopt LangExt.PostfixOperators dflags = 1+ | otherwise = 2++ ; (wrap_fn, (arg1_ty:arg_tys), op_res_ty)+ <- matchActualFunTys (mk_op_msg op) fn_orig (Just op)+ n_reqd_args op_ty+ ; wrap_res <- tcSubTypeHR SectionOrigin (Just expr)+ (mkFunTys arg_tys op_res_ty) res_ty+ ; arg1' <- tcArg op arg1 arg1_ty 1+ ; return ( mkHsWrap wrap_res $+ SectionL arg1' (mkLHsWrap wrap_fn op') ) }+ where+ fn_orig = lexprCtOrigin op+ -- It's important to use the origin of 'op', so that call-stacks+ -- come out right; they are driven by the OccurrenceOf CtOrigin+ -- See Trac #13285++tcExpr expr@(ExplicitTuple tup_args boxity) res_ty+ | all tupArgPresent tup_args+ = do { let arity = length tup_args+ tup_tc = tupleTyCon boxity arity+ ; res_ty <- expTypeToType res_ty+ ; (coi, arg_tys) <- matchExpectedTyConApp tup_tc res_ty+ -- Unboxed tuples have RuntimeRep vars, which we+ -- don't care about here+ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ ; let arg_tys' = case boxity of Unboxed -> drop arity arg_tys+ Boxed -> arg_tys+ ; tup_args1 <- tcTupArgs tup_args arg_tys'+ ; return $ mkHsWrapCo coi (ExplicitTuple tup_args1 boxity) }++ | otherwise+ = -- The tup_args are a mixture of Present and Missing (for tuple sections)+ do { let arity = length tup_args++ ; arg_tys <- case boxity of+ { Boxed -> newFlexiTyVarTys arity liftedTypeKind+ ; Unboxed -> replicateM arity newOpenFlexiTyVarTy }+ ; let actual_res_ty+ = mkFunTys [ty | (ty, (L _ (Missing _))) <- arg_tys `zip` tup_args]+ (mkTupleTy boxity arg_tys)++ ; wrap <- tcSubTypeHR (Shouldn'tHappenOrigin "ExpTuple")+ (Just expr)+ actual_res_ty res_ty++ -- Handle tuple sections where+ ; tup_args1 <- tcTupArgs tup_args arg_tys++ ; return $ mkHsWrap wrap (ExplicitTuple tup_args1 boxity) }++tcExpr (ExplicitSum alt arity expr _) res_ty+ = do { let sum_tc = sumTyCon arity+ ; res_ty <- expTypeToType res_ty+ ; (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' <- tcPolyExpr expr (arg_tys' `getNth` (alt - 1))+ ; return $ mkHsWrapCo coi (ExplicitSum alt arity expr' arg_tys') }++tcExpr (ExplicitList _ witness exprs) res_ty+ = case witness of+ Nothing -> do { res_ty <- expTypeToType res_ty+ ; (coi, elt_ty) <- matchExpectedListTy res_ty+ ; exprs' <- mapM (tc_elt elt_ty) exprs+ ; return $+ mkHsWrapCo coi $ ExplicitList elt_ty Nothing exprs' }++ Just fln -> do { ((exprs', elt_ty), fln')+ <- tcSyntaxOp ListOrigin fln+ [synKnownType intTy, SynList] res_ty $+ \ [elt_ty] ->+ do { exprs' <-+ mapM (tc_elt elt_ty) exprs+ ; return (exprs', elt_ty) }++ ; return $ ExplicitList elt_ty (Just fln') exprs' }+ where tc_elt elt_ty expr = tcPolyExpr expr elt_ty++tcExpr (ExplicitPArr _ exprs) res_ty -- maybe empty+ = do { res_ty <- expTypeToType res_ty+ ; (coi, elt_ty) <- matchExpectedPArrTy res_ty+ ; exprs' <- mapM (tc_elt elt_ty) exprs+ ; return $+ mkHsWrapCo coi $ ExplicitPArr elt_ty exprs' }+ where+ tc_elt elt_ty expr = tcPolyExpr expr elt_ty++{-+************************************************************************+* *+ Let, case, if, do+* *+************************************************************************+-}++tcExpr (HsLet (L l binds) expr) res_ty+ = do { (binds', expr') <- tcLocalBinds binds $+ tcMonoExpr expr res_ty+ ; return (HsLet (L l binds') expr') }++tcExpr (HsCase scrut matches) res_ty+ = do { -- We used to typecheck the case alternatives first.+ -- The case patterns tend to give good type info to use+ -- when typechecking the scrutinee. For example+ -- case (map f) of+ -- (x:xs) -> ...+ -- will report that map is applied to too few arguments+ --+ -- But now, in the GADT world, we need to typecheck the scrutinee+ -- first, to get type info that may be refined in the case alternatives+ (scrut', scrut_ty) <- tcInferRho scrut++ ; traceTc "HsCase" (ppr scrut_ty)+ ; matches' <- tcMatchesCase match_ctxt scrut_ty matches res_ty+ ; return (HsCase scrut' matches') }+ where+ match_ctxt = MC { mc_what = CaseAlt,+ mc_body = tcBody }++tcExpr (HsIf Nothing pred b1 b2) res_ty -- Ordinary 'if'+ = do { pred' <- tcMonoExpr pred (mkCheckExpType boolTy)+ ; res_ty <- tauifyExpType res_ty+ -- Just like Note [Case branches must never infer a non-tau type]+ -- in TcMatches (See #10619)++ ; b1' <- tcMonoExpr b1 res_ty+ ; b2' <- tcMonoExpr b2 res_ty+ ; return (HsIf Nothing pred' b1' b2') }++tcExpr (HsIf (Just fun) pred b1 b2) res_ty+ = do { ((pred', b1', b2'), fun')+ <- tcSyntaxOp IfOrigin fun [SynAny, SynAny, SynAny] res_ty $+ \ [pred_ty, b1_ty, b2_ty] ->+ do { pred' <- tcPolyExpr pred pred_ty+ ; b1' <- tcPolyExpr b1 b1_ty+ ; b2' <- tcPolyExpr b2 b2_ty+ ; return (pred', b1', b2') }+ ; return (HsIf (Just fun') pred' b1' b2') }++tcExpr (HsMultiIf _ alts) res_ty+ = do { res_ty <- if isSingleton alts+ then return res_ty+ else tauifyExpType res_ty+ -- Just like TcMatches+ -- Note [Case branches must never infer a non-tau type]++ ; alts' <- mapM (wrapLocM $ tcGRHS match_ctxt res_ty) alts+ ; res_ty <- readExpType res_ty+ ; return (HsMultiIf res_ty alts') }+ where match_ctxt = MC { mc_what = IfAlt, mc_body = tcBody }++tcExpr (HsDo do_or_lc stmts _) res_ty+ = do { expr' <- tcDoStmts do_or_lc stmts res_ty+ ; return expr' }++tcExpr (HsProc pat cmd) res_ty+ = do { (pat', cmd', coi) <- tcProc pat cmd res_ty+ ; return $ mkHsWrapCo coi (HsProc pat' cmd') }++-- Typechecks the static form and wraps it with a call to 'fromStaticPtr'.+-- See Note [Grand plan for static forms] in StaticPtrTable for an overview.+tcExpr (HsStatic fvs expr) res_ty+ = do { res_ty <- expTypeToType res_ty+ ; (co, (p_ty, expr_ty)) <- matchExpectedAppTy res_ty+ ; (expr', lie) <- captureConstraints $+ addErrCtxt (hang (text "In the body of a static form:")+ 2 (ppr expr)+ ) $+ tcPolyExprNC expr expr_ty+ -- Check that the free variables of the static form are closed.+ -- It's OK to use nonDetEltsUniqSet here as the only side effects of+ -- checkClosedInStaticForm are error messages.+ ; mapM_ checkClosedInStaticForm $ nonDetEltsUniqSet fvs++ -- Require the type of the argument to be Typeable.+ -- The evidence is not used, but asking the constraint ensures that+ -- the current implementation is as restrictive as future versions+ -- of the StaticPointers extension.+ ; typeableClass <- tcLookupClass typeableClassName+ ; _ <- emitWantedEvVar StaticOrigin $+ mkTyConApp (classTyCon typeableClass)+ [liftedTypeKind, expr_ty]+ -- Insert the constraints of the static form in a global list for later+ -- validation.+ ; emitStaticConstraints lie++ -- Wrap the static form with the 'fromStaticPtr' call.+ ; fromStaticPtr <- newMethodFromName StaticOrigin fromStaticPtrName p_ty+ ; let wrap = mkWpTyApps [expr_ty]+ ; loc <- getSrcSpanM+ ; return $ mkHsWrapCo co $ HsApp (L loc $ mkHsWrap wrap fromStaticPtr)+ (L loc (HsStatic fvs expr'))+ }++{-+************************************************************************+* *+ Record construction and update+* *+************************************************************************+-}++tcExpr expr@(RecordCon { rcon_con_name = L loc con_name+ , rcon_flds = rbinds }) res_ty+ = do { con_like <- tcLookupConLike con_name++ -- Check for missing fields+ ; checkMissingFields con_like rbinds++ ; (con_expr, con_sigma) <- tcInferId con_name+ ; (con_wrap, con_tau) <-+ topInstantiate (OccurrenceOf con_name) con_sigma+ -- a shallow instantiation should really be enough for+ -- a data constructor.+ ; let arity = conLikeArity con_like+ Right (arg_tys, actual_res_ty) = tcSplitFunTysN arity con_tau+ ; case conLikeWrapId_maybe con_like of+ Nothing -> nonBidirectionalErr (conLikeName con_like)+ Just con_id -> do {+ res_wrap <- tcSubTypeHR (Shouldn'tHappenOrigin "RecordCon")+ (Just expr) actual_res_ty res_ty+ ; rbinds' <- tcRecordBinds con_like arg_tys rbinds+ ; return $+ mkHsWrap res_wrap $+ RecordCon { rcon_con_name = L loc con_id+ , rcon_con_expr = mkHsWrap con_wrap con_expr+ , rcon_con_like = con_like+ , rcon_flds = rbinds' } } }++{-+Note [Type of a record update]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The main complication with RecordUpd is that we need to explicitly+handle the *non-updated* fields. Consider:++ data T a b c = MkT1 { fa :: a, fb :: (b,c) }+ | MkT2 { fa :: a, fb :: (b,c), fc :: c -> c }+ | MkT3 { fd :: a }++ upd :: T a b c -> (b',c) -> T a b' c+ upd t x = t { fb = x}++The result type should be (T a b' c)+not (T a b c), because 'b' *is not* mentioned in a non-updated field+not (T a b' c'), because 'c' *is* mentioned in a non-updated field+NB that it's not good enough to look at just one constructor; we must+look at them all; cf Trac #3219++After all, upd should be equivalent to:+ upd t x = case t of+ MkT1 p q -> MkT1 p x+ MkT2 a b -> MkT2 p b+ MkT3 d -> error ...++So we need to give a completely fresh type to the result record,+and then constrain it by the fields that are *not* updated ("p" above).+We call these the "fixed" type variables, and compute them in getFixedTyVars.++Note that because MkT3 doesn't contain all the fields being updated,+its RHS is simply an error, so it doesn't impose any type constraints.+Hence the use of 'relevant_cont'.++Note [Implicit type sharing]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We also take into account any "implicit" non-update fields. For example+ data T a b where { MkT { f::a } :: T a a; ... }+So the "real" type of MkT is: forall ab. (a~b) => a -> T a b++Then consider+ upd t x = t { f=x }+We infer the type+ upd :: T a b -> a -> T a b+ upd (t::T a b) (x::a)+ = case t of { MkT (co:a~b) (_:a) -> MkT co x }+We can't give it the more general type+ upd :: T a b -> c -> T c b++Note [Criteria for update]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We want to allow update for existentials etc, provided the updated+field isn't part of the existential. For example, this should be ok.+ data T a where { MkT { f1::a, f2::b->b } :: T a }+ f :: T a -> b -> T b+ f t b = t { f1=b }++The criterion we use is this:++ The types of the updated fields+ mention only the universally-quantified type variables+ of the data constructor++NB: this is not (quite) the same as being a "naughty" record selector+(See Note [Naughty record selectors]) in TcTyClsDecls), at least+in the case of GADTs. Consider+ data T a where { MkT :: { f :: a } :: T [a] }+Then f is not "naughty" because it has a well-typed record selector.+But we don't allow updates for 'f'. (One could consider trying to+allow this, but it makes my head hurt. Badly. And no one has asked+for it.)++In principle one could go further, and allow+ g :: T a -> T a+ g t = t { f2 = \x -> x }+because the expression is polymorphic...but that seems a bridge too far.++Note [Data family example]+~~~~~~~~~~~~~~~~~~~~~~~~~~+ data instance T (a,b) = MkT { x::a, y::b }+ --->+ data :TP a b = MkT { a::a, y::b }+ coTP a b :: T (a,b) ~ :TP a b++Suppose r :: T (t1,t2), e :: t3+Then r { x=e } :: T (t3,t1)+ --->+ case r |> co1 of+ MkT x y -> MkT e y |> co2+ where co1 :: T (t1,t2) ~ :TP t1 t2+ co2 :: :TP t3 t2 ~ T (t3,t2)+The wrapping with co2 is done by the constructor wrapper for MkT++Outgoing invariants+~~~~~~~~~~~~~~~~~~~+In the outgoing (HsRecordUpd scrut binds cons in_inst_tys out_inst_tys):++ * cons are the data constructors to be updated++ * in_inst_tys, out_inst_tys have same length, and instantiate the+ *representation* tycon of the data cons. In Note [Data+ family example], in_inst_tys = [t1,t2], out_inst_tys = [t3,t2]++Note [Mixed Record Field Updates]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the following pattern synonym.++ data MyRec = MyRec { foo :: Int, qux :: String }++ pattern HisRec{f1, f2} = MyRec{foo = f1, qux=f2}++This allows updates such as the following++ updater :: MyRec -> MyRec+ updater a = a {f1 = 1 }++It would also make sense to allow the following update (which we reject).++ updater a = a {f1 = 1, qux = "two" } ==? MyRec 1 "two"++This leads to confusing behaviour when the selectors in fact refer the same+field.++ updater a = a {f1 = 1, foo = 2} ==? ???++For this reason, we reject a mixture of pattern synonym and normal record+selectors in the same update block. Although of course we still allow the+following.++ updater a = (a {f1 = 1}) {foo = 2}++ > updater (MyRec 0 "str")+ MyRec 2 "str"++-}++tcExpr expr@(RecordUpd { rupd_expr = record_expr, rupd_flds = rbnds }) res_ty+ = ASSERT( notNull rbnds )+ do { -- STEP -2: typecheck the record_expr, the record to be updated+ (record_expr', record_rho) <- tcInferRho record_expr++ -- STEP -1 See Note [Disambiguating record fields]+ -- After this we know that rbinds is unambiguous+ ; rbinds <- disambiguateRecordBinds record_expr record_rho rbnds res_ty+ ; let upd_flds = map (unLoc . hsRecFieldLbl . unLoc) rbinds+ upd_fld_occs = map (occNameFS . rdrNameOcc . rdrNameAmbiguousFieldOcc) upd_flds+ sel_ids = map selectorAmbiguousFieldOcc upd_flds+ -- STEP 0+ -- Check that the field names are really field names+ -- and they are all field names for proper records or+ -- all field names for pattern synonyms.+ ; let bad_guys = [ setSrcSpan loc $ addErrTc (notSelector fld_name)+ | fld <- rbinds,+ -- Excludes class ops+ let L loc sel_id = hsRecUpdFieldId (unLoc fld),+ not (isRecordSelector sel_id),+ let fld_name = idName sel_id ]+ ; unless (null bad_guys) (sequence bad_guys >> failM)+ -- See note [Mixed Record Selectors]+ ; let (data_sels, pat_syn_sels) =+ partition isDataConRecordSelector sel_ids+ ; MASSERT( all isPatSynRecordSelector pat_syn_sels )+ ; checkTc ( null data_sels || null pat_syn_sels )+ ( mixedSelectors data_sels pat_syn_sels )++ -- STEP 1+ -- Figure out the tycon and data cons from the first field name+ ; let -- It's OK to use the non-tc splitters here (for a selector)+ sel_id : _ = sel_ids++ mtycon :: Maybe TyCon+ mtycon = case idDetails sel_id of+ RecSelId (RecSelData tycon) _ -> Just tycon+ _ -> Nothing++ con_likes :: [ConLike]+ con_likes = case idDetails sel_id of+ RecSelId (RecSelData tc) _+ -> map RealDataCon (tyConDataCons tc)+ RecSelId (RecSelPatSyn ps) _+ -> [PatSynCon ps]+ _ -> panic "tcRecordUpd"+ -- NB: for a data type family, the tycon is the instance tycon++ relevant_cons = conLikesWithFields con_likes upd_fld_occs+ -- A constructor is only relevant to this process if+ -- it contains *all* the fields that are being updated+ -- Other ones will cause a runtime error if they occur++ -- Step 2+ -- Check that at least one constructor has all the named fields+ -- i.e. has an empty set of bad fields returned by badFields+ ; checkTc (not (null relevant_cons)) (badFieldsUpd rbinds con_likes)++ -- Take apart a representative constructor+ ; let con1 = ASSERT( not (null relevant_cons) ) head relevant_cons+ (con1_tvs, _, _, _prov_theta, req_theta, con1_arg_tys, _)+ = conLikeFullSig con1+ con1_flds = map flLabel $ conLikeFieldLabels con1+ con1_tv_tys = mkTyVarTys con1_tvs+ con1_res_ty = case mtycon of+ Just tc -> mkFamilyTyConApp tc con1_tv_tys+ Nothing -> conLikeResTy con1 con1_tv_tys++ -- Check that we're not dealing with a unidirectional pattern+ -- synonym+ ; unless (isJust $ conLikeWrapId_maybe con1)+ (nonBidirectionalErr (conLikeName con1))++ -- STEP 3 Note [Criteria for update]+ -- Check that each updated field is polymorphic; that is, its type+ -- mentions only the universally-quantified variables of the data con+ ; let flds1_w_tys = zipEqual "tcExpr:RecConUpd" con1_flds con1_arg_tys+ bad_upd_flds = filter bad_fld flds1_w_tys+ 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)++ -- STEP 4 Note [Type of a record update]+ -- Figure out types for the scrutinee and result+ -- Both are of form (T a b c), with fresh type variables, but with+ -- common variables where the scrutinee and result must have the same type+ -- These are variables that appear in *any* arg of *any* of the+ -- relevant constructors *except* in the updated fields+ --+ ; let fixed_tvs = getFixedTyVars upd_fld_occs con1_tvs relevant_cons+ is_fixed_tv tv = tv `elemVarSet` fixed_tvs++ mk_inst_ty :: TCvSubst -> (TyVar, TcType) -> TcM (TCvSubst, TcType)+ -- Deals with instantiation of kind variables+ -- c.f. TcMType.newMetaTyVars+ mk_inst_ty subst (tv, result_inst_ty)+ | is_fixed_tv tv -- Same as result type+ = return (extendTvSubst subst tv result_inst_ty, result_inst_ty)+ | otherwise -- Fresh type, of correct kind+ = do { (subst', new_tv) <- newMetaTyVarX subst tv+ ; return (subst', mkTyVarTy new_tv) }++ ; (result_subst, con1_tvs') <- newMetaTyVars con1_tvs+ ; let result_inst_tys = mkTyVarTys con1_tvs'+ init_subst = mkEmptyTCvSubst (getTCvInScope result_subst)++ ; (scrut_subst, scrut_inst_tys) <- mapAccumLM mk_inst_ty init_subst+ (con1_tvs `zip` result_inst_tys)++ ; let rec_res_ty = TcType.substTy result_subst con1_res_ty+ scrut_ty = TcType.substTy scrut_subst con1_res_ty+ con1_arg_tys' = map (TcType.substTy result_subst) con1_arg_tys++ ; wrap_res <- tcSubTypeHR (exprCtOrigin expr)+ (Just expr) rec_res_ty res_ty+ ; co_scrut <- unifyType (Just record_expr) record_rho scrut_ty+ -- NB: normal unification is OK here (as opposed to subsumption),+ -- because for this to work out, both record_rho and scrut_ty have+ -- to be normal datatypes -- no contravariant stuff can go on++ -- STEP 5+ -- Typecheck the bindings+ ; rbinds' <- tcRecordUpd con1 con1_arg_tys' rbinds++ -- STEP 6: Deal with the stupid theta+ ; let theta' = substThetaUnchecked scrut_subst (conLikeStupidTheta con1)+ ; instStupidTheta RecordUpdOrigin theta'++ -- Step 7: make a cast for the scrutinee, in the+ -- case that it's from a data family+ ; let fam_co :: HsWrapper -- RepT t1 .. tn ~R scrut_ty+ fam_co | Just tycon <- mtycon+ , Just co_con <- tyConFamilyCoercion_maybe tycon+ = mkWpCastR (mkTcUnbranchedAxInstCo co_con scrut_inst_tys [])+ | otherwise+ = idHsWrapper++ -- Step 8: Check that the req constraints are satisfied+ -- For normal data constructors req_theta is empty but we must do+ -- this check for pattern synonyms.+ ; let req_theta' = substThetaUnchecked scrut_subst req_theta+ ; req_wrap <- instCallConstraints RecordUpdOrigin req_theta'++ -- Phew!+ ; return $+ mkHsWrap wrap_res $+ RecordUpd { rupd_expr = mkLHsWrap fam_co (mkLHsWrapCo co_scrut record_expr')+ , rupd_flds = rbinds'+ , rupd_cons = relevant_cons, rupd_in_tys = scrut_inst_tys+ , rupd_out_tys = result_inst_tys, rupd_wrap = req_wrap } }++tcExpr (HsRecFld f) res_ty+ = tcCheckRecSelId f res_ty++{-+************************************************************************+* *+ Arithmetic sequences e.g. [a,b..]+ and their parallel-array counterparts e.g. [: a,b.. :]++* *+************************************************************************+-}++tcExpr (ArithSeq _ witness seq) res_ty+ = tcArithSeq witness seq res_ty++tcExpr (PArrSeq _ seq@(FromTo expr1 expr2)) res_ty+ = do { res_ty <- expTypeToType res_ty+ ; (coi, elt_ty) <- matchExpectedPArrTy res_ty+ ; expr1' <- tcPolyExpr expr1 elt_ty+ ; expr2' <- tcPolyExpr expr2 elt_ty+ ; enumFromToP <- initDsTc $ dsDPHBuiltin enumFromToPVar+ ; enum_from_to <- newMethodFromName (PArrSeqOrigin seq)+ (idName enumFromToP) elt_ty+ ; return $+ mkHsWrapCo coi $ PArrSeq enum_from_to (FromTo expr1' expr2') }++tcExpr (PArrSeq _ seq@(FromThenTo expr1 expr2 expr3)) res_ty+ = do { res_ty <- expTypeToType res_ty+ ; (coi, elt_ty) <- matchExpectedPArrTy res_ty+ ; expr1' <- tcPolyExpr expr1 elt_ty+ ; expr2' <- tcPolyExpr expr2 elt_ty+ ; expr3' <- tcPolyExpr expr3 elt_ty+ ; enumFromThenToP <- initDsTc $ dsDPHBuiltin enumFromThenToPVar+ ; eft <- newMethodFromName (PArrSeqOrigin seq)+ (idName enumFromThenToP) elt_ty -- !!!FIXME: chak+ ; return $+ mkHsWrapCo coi $+ PArrSeq eft (FromThenTo expr1' expr2' expr3') }++tcExpr (PArrSeq _ _) _+ = panic "TcExpr.tcExpr: Infinite parallel array!"+ -- the parser shouldn't have generated it and the renamer shouldn't have+ -- let it through++{-+************************************************************************+* *+ Template Haskell+* *+************************************************************************+-}++-- HsSpliced is an annotation produced by 'RnSplice.rnSpliceExpr'.+-- Here we get rid of it and add the finalizers to the global environment.+--+-- See Note [Delaying modFinalizers in untyped splices] in RnSplice.+tcExpr (HsSpliceE (HsSpliced mod_finalizers (HsSplicedExpr expr)))+ res_ty+ = do addModFinalizersWithLclEnv mod_finalizers+ tcExpr expr res_ty+tcExpr (HsSpliceE splice) res_ty+ = tcSpliceExpr splice res_ty+tcExpr (HsBracket brack) res_ty+ = tcTypedBracket brack res_ty+tcExpr (HsRnBracketOut brack ps) res_ty+ = tcUntypedBracket brack ps res_ty++{-+************************************************************************+* *+ Catch-all+* *+************************************************************************+-}++tcExpr other _ = pprPanic "tcMonoExpr" (ppr other)+ -- Include ArrForm, ArrApp, which shouldn't appear at all+ -- Also HsTcBracketOut, HsQuasiQuoteE++{-+************************************************************************+* *+ Arithmetic sequences [a..b] etc+* *+************************************************************************+-}++tcArithSeq :: Maybe (SyntaxExpr Name) -> ArithSeqInfo Name -> ExpRhoType+ -> TcM (HsExpr TcId)++tcArithSeq witness seq@(From expr) res_ty+ = do { (wrap, elt_ty, wit') <- arithSeqEltType witness res_ty+ ; expr' <- tcPolyExpr expr elt_ty+ ; enum_from <- newMethodFromName (ArithSeqOrigin seq)+ enumFromName elt_ty+ ; return $ mkHsWrap wrap $+ ArithSeq enum_from wit' (From expr') }++tcArithSeq witness seq@(FromThen expr1 expr2) res_ty+ = do { (wrap, elt_ty, wit') <- arithSeqEltType witness res_ty+ ; expr1' <- tcPolyExpr expr1 elt_ty+ ; expr2' <- tcPolyExpr expr2 elt_ty+ ; enum_from_then <- newMethodFromName (ArithSeqOrigin seq)+ enumFromThenName elt_ty+ ; return $ mkHsWrap wrap $+ ArithSeq enum_from_then wit' (FromThen expr1' expr2') }++tcArithSeq witness seq@(FromTo expr1 expr2) res_ty+ = do { (wrap, elt_ty, wit') <- arithSeqEltType witness res_ty+ ; expr1' <- tcPolyExpr expr1 elt_ty+ ; expr2' <- tcPolyExpr expr2 elt_ty+ ; enum_from_to <- newMethodFromName (ArithSeqOrigin seq)+ enumFromToName elt_ty+ ; return $ mkHsWrap wrap $+ ArithSeq enum_from_to wit' (FromTo expr1' expr2') }++tcArithSeq witness seq@(FromThenTo expr1 expr2 expr3) res_ty+ = do { (wrap, elt_ty, wit') <- arithSeqEltType witness res_ty+ ; expr1' <- tcPolyExpr expr1 elt_ty+ ; expr2' <- tcPolyExpr expr2 elt_ty+ ; expr3' <- tcPolyExpr expr3 elt_ty+ ; eft <- newMethodFromName (ArithSeqOrigin seq)+ enumFromThenToName elt_ty+ ; return $ mkHsWrap wrap $+ ArithSeq eft wit' (FromThenTo expr1' expr2' expr3') }++-----------------+arithSeqEltType :: Maybe (SyntaxExpr Name) -> ExpRhoType+ -> TcM (HsWrapper, TcType, Maybe (SyntaxExpr Id))+arithSeqEltType Nothing res_ty+ = do { res_ty <- expTypeToType res_ty+ ; (coi, elt_ty) <- matchExpectedListTy res_ty+ ; return (mkWpCastN coi, elt_ty, Nothing) }+arithSeqEltType (Just fl) res_ty+ = do { (elt_ty, fl')+ <- tcSyntaxOp ListOrigin fl [SynList] res_ty $+ \ [elt_ty] -> return elt_ty+ ; return (idHsWrapper, elt_ty, Just fl') }++{-+************************************************************************+* *+ Applications+* *+************************************************************************+-}++type LHsExprArgIn = Either (LHsExpr Name) (LHsWcType Name)+type LHsExprArgOut = Either (LHsExpr TcId) (LHsWcType Name)+ -- Left e => argument expression+ -- Right ty => visible type application++tcApp1 :: HsExpr Name -- either HsApp or HsAppType+ -> ExpRhoType -> TcM (HsExpr TcId)+tcApp1 e res_ty+ = do { (wrap, fun, args) <- tcApp Nothing (noLoc e) [] res_ty+ ; return (mkHsWrap wrap $ unLoc $ foldl mk_hs_app fun args) }+ where+ mk_hs_app f (Left a) = mkHsApp f a+ mk_hs_app f (Right a) = mkHsAppTypeOut f a++tcApp :: Maybe SDoc -- like "The function `f' is applied to"+ -- or leave out to get exactly that message+ -> LHsExpr Name -> [LHsExprArgIn] -- Function and args+ -> ExpRhoType -> TcM (HsWrapper, LHsExpr TcId, [LHsExprArgOut])+ -- (wrap, fun, args). For an ordinary function application,+ -- these should be assembled as (wrap (fun args)).+ -- But OpApp is slightly different, so that's why the caller+ -- must assemble++tcApp m_herald orig_fun orig_args res_ty+ = go orig_fun orig_args+ where+ go :: LHsExpr Name -> [LHsExprArgIn]+ -> TcM (HsWrapper, LHsExpr TcId, [LHsExprArgOut])+ go (L _ (HsPar e)) args = go e args+ go (L _ (HsApp e1 e2)) args = go e1 (Left e2:args)+ go (L _ (HsAppType e t)) args = go e (Right t:args)++ go (L loc (HsVar (L _ fun))) args+ | fun `hasKey` tagToEnumKey+ , count isLeft args == 1+ = do { (wrap, expr, args) <- tcTagToEnum loc fun args res_ty+ ; return (wrap, expr, args) }++ | fun `hasKey` seqIdKey+ , count isLeft args == 2+ = do { (wrap, expr, args) <- tcSeq loc fun args res_ty+ ; return (wrap, expr, args) }++ go (L loc (HsRecFld (Ambiguous lbl _))) args@(Left (L _ arg) : _)+ | Just sig_ty <- obviousSig arg+ = do { sig_tc_ty <- tcHsSigWcType ExprSigCtxt sig_ty+ ; sel_name <- disambiguateSelector lbl sig_tc_ty+ ; go (L loc (HsRecFld (Unambiguous lbl sel_name))) args }++ go fun args+ = do { -- Type-check the function+ ; (fun1, fun_sigma) <- tcInferFun fun+ ; let orig = lexprCtOrigin fun++ ; (wrap_fun, args1, actual_res_ty)+ <- tcArgs fun fun_sigma orig args+ (m_herald `orElse` mk_app_msg fun)++ -- this is just like tcWrapResult, but the types don't line+ -- up to call that function+ ; wrap_res <- addFunResCtxt True (unLoc fun) actual_res_ty res_ty $+ tcSubTypeDS_NC_O orig GenSigCtxt+ (Just $ foldl mk_hs_app fun args)+ actual_res_ty res_ty++ ; return (wrap_res, mkLHsWrap wrap_fun fun1, args1) }++ mk_hs_app f (Left a) = mkHsApp f a+ mk_hs_app f (Right a) = mkHsAppType f a++mk_app_msg :: LHsExpr Name -> SDoc+mk_app_msg fun = sep [ text "The function" <+> quotes (ppr fun)+ , text "is applied to"]++mk_op_msg :: LHsExpr Name -> SDoc+mk_op_msg op = text "The operator" <+> quotes (ppr op) <+> text "takes"++----------------+tcInferFun :: LHsExpr Name -> TcM (LHsExpr TcId, TcSigmaType)+-- Infer type of a function+tcInferFun (L loc (HsVar (L _ name)))+ = do { (fun, ty) <- setSrcSpan loc (tcInferId name)+ -- Don't wrap a context around a plain Id+ ; return (L loc fun, ty) }++tcInferFun (L loc (HsRecFld f))+ = do { (fun, ty) <- setSrcSpan loc (tcInferRecSelId f)+ -- Don't wrap a context around a plain Id+ ; return (L loc fun, ty) }++tcInferFun fun+ = tcInferSigma fun+ -- NB: tcInferSigma; see TcUnify+ -- Note [Deep instantiation of InferResult]+++----------------+-- | Type-check the arguments to a function, possibly including visible type+-- applications+tcArgs :: LHsExpr Name -- ^ The function itself (for err msgs only)+ -> TcSigmaType -- ^ the (uninstantiated) type of the function+ -> CtOrigin -- ^ the origin for the function's type+ -> [LHsExprArgIn] -- ^ the args+ -> SDoc -- ^ the herald for matchActualFunTys+ -> TcM (HsWrapper, [LHsExprArgOut], TcSigmaType)+ -- ^ (a wrapper for the function, the tc'd args, result type)+tcArgs fun orig_fun_ty fun_orig orig_args herald+ = go [] 1 orig_fun_ty orig_args+ where+ orig_arity = length orig_args++ go _ _ fun_ty [] = return (idHsWrapper, [], fun_ty)++ go acc_args n fun_ty (Right hs_ty_arg:args)+ = do { (wrap1, upsilon_ty) <- topInstantiateInferred fun_orig fun_ty+ -- wrap1 :: fun_ty "->" upsilon_ty+ ; case tcSplitForAllTy_maybe upsilon_ty of+ Just (tvb, inner_ty) ->+ do { let tv = binderVar tvb+ vis = binderArgFlag tvb+ kind = tyVarKind tv+ ; MASSERT2( vis == Specified+ , (vcat [ ppr fun_ty, ppr upsilon_ty, ppr tvb+ , ppr inner_ty, pprTyVar tv+ , ppr vis ]) )+ ; ty_arg <- tcHsTypeApp hs_ty_arg kind+ ; let insted_ty = substTyWithUnchecked [tv] [ty_arg] inner_ty+ ; (inner_wrap, args', res_ty)+ <- go acc_args (n+1) insted_ty args+ -- inner_wrap :: insted_ty "->" (map typeOf args') -> res_ty+ ; let inst_wrap = mkWpTyApps [ty_arg]+ ; return ( inner_wrap <.> inst_wrap <.> wrap1+ , Right hs_ty_arg : args'+ , res_ty ) }+ _ -> ty_app_err upsilon_ty hs_ty_arg }++ go acc_args n fun_ty (Left arg : args)+ = do { (wrap, [arg_ty], res_ty)+ <- matchActualFunTysPart herald fun_orig (Just fun) 1 fun_ty+ acc_args orig_arity+ -- wrap :: fun_ty "->" arg_ty -> res_ty+ ; arg' <- tcArg fun arg arg_ty n+ ; (inner_wrap, args', inner_res_ty)+ <- go (arg_ty : acc_args) (n+1) res_ty args+ -- inner_wrap :: res_ty "->" (map typeOf args') -> inner_res_ty+ ; return ( mkWpFun idHsWrapper inner_wrap arg_ty res_ty doc <.> wrap+ , Left arg' : args'+ , inner_res_ty ) }+ where+ doc = text "When checking the" <+> speakNth n <+>+ text "argument to" <+> quotes (ppr fun)++ ty_app_err ty arg+ = do { (_, ty) <- zonkTidyTcType emptyTidyEnv ty+ ; failWith $+ text "Cannot apply expression of type" <+> quotes (ppr ty) $$+ text "to a visible type argument" <+> quotes (ppr arg) }++----------------+tcArg :: LHsExpr Name -- The function (for error messages)+ -> LHsExpr Name -- Actual arguments+ -> TcRhoType -- expected arg type+ -> Int -- # of argument+ -> TcM (LHsExpr TcId) -- Resulting argument+tcArg fun arg ty arg_no = addErrCtxt (funAppCtxt fun arg arg_no) $+ tcPolyExprNC arg ty++----------------+tcTupArgs :: [LHsTupArg Name] -> [TcSigmaType] -> TcM [LHsTupArg TcId]+tcTupArgs args tys+ = ASSERT( equalLength args tys ) mapM go (args `zip` tys)+ where+ go (L l (Missing {}), arg_ty) = return (L l (Missing arg_ty))+ go (L l (Present expr), arg_ty) = do { expr' <- tcPolyExpr expr arg_ty+ ; return (L l (Present expr')) }++---------------------------+-- See TcType.SyntaxOpType also for commentary+tcSyntaxOp :: CtOrigin+ -> SyntaxExpr Name+ -> [SyntaxOpType] -- ^ shape of syntax operator arguments+ -> ExpRhoType -- ^ overall result type+ -> ([TcSigmaType] -> TcM a) -- ^ Type check any arguments+ -> TcM (a, SyntaxExpr TcId)+-- ^ Typecheck a syntax operator+-- The operator is always a variable at this stage (i.e. renamer output)+tcSyntaxOp orig expr arg_tys res_ty+ = tcSyntaxOpGen orig expr arg_tys (SynType res_ty)++-- | Slightly more general version of 'tcSyntaxOp' that allows the caller+-- to specify the shape of the result of the syntax operator+tcSyntaxOpGen :: CtOrigin+ -> SyntaxExpr Name+ -> [SyntaxOpType]+ -> SyntaxOpType+ -> ([TcSigmaType] -> TcM a)+ -> TcM (a, SyntaxExpr TcId)+tcSyntaxOpGen orig (SyntaxExpr { syn_expr = HsVar (L _ op) })+ arg_tys res_ty thing_inside+ = do { (expr, sigma) <- tcInferId op+ ; (result, expr_wrap, arg_wraps, res_wrap)+ <- tcSynArgA orig sigma arg_tys res_ty $+ thing_inside+ ; return (result, SyntaxExpr { syn_expr = mkHsWrap expr_wrap expr+ , syn_arg_wraps = arg_wraps+ , syn_res_wrap = res_wrap }) }++tcSyntaxOpGen _ other _ _ _ = pprPanic "tcSyntaxOp" (ppr other)++{-+Note [tcSynArg]+~~~~~~~~~~~~~~~+Because of the rich structure of SyntaxOpType, we must do the+contra-/covariant thing when working down arrows, to get the+instantiation vs. skolemisation decisions correct (and, more+obviously, the orientation of the HsWrappers). We thus have+two tcSynArgs.+-}++-- works on "expected" types, skolemising where necessary+-- See Note [tcSynArg]+tcSynArgE :: CtOrigin+ -> TcSigmaType+ -> SyntaxOpType -- ^ shape it is expected to have+ -> ([TcSigmaType] -> TcM a) -- ^ check the arguments+ -> TcM (a, HsWrapper)+ -- ^ 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+ ; return (result, skol_wrap <.> ty_wrapper) }+ where+ go rho_ty SynAny+ = do { result <- thing_inside [rho_ty]+ ; return (result, idHsWrapper) }++ go rho_ty SynRho -- same as SynAny, because we skolemise eagerly+ = do { result <- thing_inside [rho_ty]+ ; return (result, idHsWrapper) }++ go rho_ty SynList+ = do { (list_co, elt_ty) <- matchExpectedListTy rho_ty+ ; result <- thing_inside [elt_ty]+ ; return (result, mkWpCastN list_co) }++ go rho_ty (SynFun arg_shape res_shape)+ = do { ( ( ( (result, arg_ty, res_ty)+ , res_wrapper ) -- :: res_ty_out "->" res_ty+ , arg_wrapper1, [], arg_wrapper2 ) -- :: arg_ty "->" arg_ty_out+ , match_wrapper ) -- :: (arg_ty -> res_ty) "->" rho_ty+ <- matchExpectedFunTys herald 1 (mkCheckExpType rho_ty) $+ \ [arg_ty] res_ty ->+ do { arg_tc_ty <- expTypeToType arg_ty+ ; res_tc_ty <- expTypeToType res_ty++ -- another nested arrow is too much for now,+ -- but I bet we'll never need this+ ; MASSERT2( case arg_shape of+ SynFun {} -> False;+ _ -> True+ , text "Too many nested arrows in SyntaxOpType" $$+ pprCtOrigin orig )++ ; tcSynArgA orig arg_tc_ty [] arg_shape $+ \ arg_results ->+ tcSynArgE orig res_tc_ty res_shape $+ \ res_results ->+ do { result <- thing_inside (arg_results ++ res_results)+ ; return (result, arg_tc_ty, res_tc_ty) }}++ ; return ( result+ , match_wrapper <.>+ mkWpFun (arg_wrapper2 <.> arg_wrapper1) res_wrapper+ arg_ty res_ty doc ) }+ 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 <- tcSubTypeET orig GenSigCtxt the_ty rho_ty+ ; result <- thing_inside []+ ; return (result, wrap) }++-- works on "actual" types, instantiating where necessary+-- See Note [tcSynArg]+tcSynArgA :: CtOrigin+ -> TcSigmaType+ -> [SyntaxOpType] -- ^ argument shapes+ -> SyntaxOpType -- ^ result shape+ -> ([TcSigmaType] -> TcM a) -- ^ check the arguments+ -> TcM (a, HsWrapper, [HsWrapper], HsWrapper)+ -- ^ returns a wrapper to be applied to the original function,+ -- wrappers to be applied to arguments+ -- and a wrapper to be applied to the overall expression+tcSynArgA orig sigma_ty arg_shapes res_shape thing_inside+ = do { (match_wrapper, arg_tys, res_ty)+ <- matchActualFunTys herald orig noThing (length arg_shapes) sigma_ty+ -- match_wrapper :: sigma_ty "->" (arg_tys -> res_ty)+ ; ((result, res_wrapper), arg_wrappers)+ <- tc_syn_args_e arg_tys arg_shapes $ \ arg_results ->+ tc_syn_arg res_ty res_shape $ \ res_results ->+ thing_inside (arg_results ++ res_results)+ ; return (result, match_wrapper, arg_wrappers, res_wrapper) }+ where+ herald = text "This rebindable syntax expects a function with"++ tc_syn_args_e :: [TcSigmaType] -> [SyntaxOpType]+ -> ([TcSigmaType] -> TcM a)+ -> TcM (a, [HsWrapper])+ -- the wrappers are for arguments+ tc_syn_args_e (arg_ty : arg_tys) (arg_shape : arg_shapes) thing_inside+ = do { ((result, arg_wraps), arg_wrap)+ <- tcSynArgE orig arg_ty arg_shape $ \ arg1_results ->+ tc_syn_args_e arg_tys arg_shapes $ \ args_results ->+ thing_inside (arg1_results ++ args_results)+ ; return (result, arg_wrap : arg_wraps) }+ tc_syn_args_e _ _ thing_inside = (, []) <$> thing_inside []++ tc_syn_arg :: TcSigmaType -> SyntaxOpType+ -> ([TcSigmaType] -> TcM a)+ -> TcM (a, HsWrapper)+ -- the wrapper applies to the overall result+ tc_syn_arg res_ty SynAny thing_inside+ = do { result <- thing_inside [res_ty]+ ; return (result, idHsWrapper) }+ tc_syn_arg res_ty SynRho thing_inside+ = do { (inst_wrap, rho_ty) <- deeplyInstantiate orig res_ty+ -- inst_wrap :: res_ty "->" rho_ty+ ; result <- thing_inside [rho_ty]+ ; return (result, inst_wrap) }+ tc_syn_arg res_ty SynList thing_inside+ = do { (inst_wrap, rho_ty) <- topInstantiate orig res_ty+ -- inst_wrap :: res_ty "->" rho_ty+ ; (list_co, elt_ty) <- matchExpectedListTy rho_ty+ -- list_co :: [elt_ty] ~N rho_ty+ ; result <- thing_inside [elt_ty]+ ; return (result, mkWpCastN (mkTcSymCo list_co) <.> inst_wrap) }+ tc_syn_arg _ (SynFun {}) _+ = pprPanic "tcSynArgA hits a SynFun" (ppr orig)+ tc_syn_arg res_ty (SynType the_ty) thing_inside+ = do { wrap <- tcSubTypeO orig GenSigCtxt res_ty the_ty+ ; result <- thing_inside []+ ; return (result, wrap) }++{-+Note [Push result type in]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Unify with expected result before type-checking the args so that the+info from res_ty percolates to args. This is when we might detect a+too-few args situation. (One can think of cases when the opposite+order would give a better error message.)+experimenting with putting this first.++Here's an example where it actually makes a real difference++ class C t a b | t a -> b+ instance C Char a Bool++ data P t a = forall b. (C t a b) => MkP b+ data Q t = MkQ (forall a. P t a)++ f1, f2 :: Q Char;+ f1 = MkQ (MkP True)+ f2 = MkQ (MkP True :: forall a. P Char a)++With the change, f1 will type-check, because the 'Char' info from+the signature is propagated into MkQ's argument. With the check+in the other order, the extra signature in f2 is reqd.++************************************************************************+* *+ Expressions with a type signature+ expr :: type+* *+********************************************************************* -}++tcExprSig :: LHsExpr Name -> TcIdSigInfo -> TcM (LHsExpr TcId, TcType)+tcExprSig expr (CompleteSig { sig_bndr = poly_id, sig_loc = loc })+ = setSrcSpan loc $ -- Sets the location for the implication constraint+ do { (tv_prs, theta, tau) <- tcInstType tcInstSkolTyVars poly_id+ ; given <- newEvVars theta+ ; let skol_info = SigSkol ExprSigCtxt (idType poly_id) tv_prs+ skol_tvs = map snd tv_prs+ ; (ev_binds, expr') <- checkConstraints skol_info skol_tvs given $+ tcExtendTyVarEnv2 tv_prs $+ tcPolyExprNC expr tau++ ; let poly_wrap = mkWpTyLams skol_tvs+ <.> mkWpLams given+ <.> mkWpLet ev_binds+ ; return (mkLHsWrap poly_wrap expr', idType poly_id) }++tcExprSig expr sig@(PartialSig { psig_name = name, sig_loc = loc })+ = setSrcSpan loc $ -- Sets the location for the implication constraint+ do { (tclvl, wanted, (expr', sig_inst))+ <- pushLevelAndCaptureConstraints $+ do { sig_inst <- tcInstSig sig+ ; expr' <- tcExtendTyVarEnv2 (sig_inst_skols sig_inst) $+ tcExtendTyVarEnv2 (sig_inst_wcs sig_inst) $+ tcPolyExprNC expr (sig_inst_tau sig_inst)+ ; return (expr', sig_inst) }+ -- See Note [Partial expression signatures]+ ; let tau = sig_inst_tau sig_inst+ infer_mode | null (sig_inst_theta sig_inst)+ , isNothing (sig_inst_wcx sig_inst)+ = ApplyMR+ | otherwise+ = NoRestrictions+ ; (qtvs, givens, ev_binds)+ <- simplifyInfer tclvl infer_mode [sig_inst] [(name, tau)] wanted+ ; tau <- zonkTcType tau+ ; let inferred_theta = map evVarPred givens+ tau_tvs = tyCoVarsOfType tau+ ; (binders, my_theta) <- chooseInferredQuantifiers inferred_theta+ tau_tvs qtvs (Just sig_inst)+ ; let inferred_sigma = mkInfSigmaTy qtvs inferred_theta tau+ my_sigma = mkForAllTys binders (mkPhiTy my_theta tau)+ ; wrap <- if inferred_sigma `eqType` my_sigma -- NB: eqType ignores vis.+ then return idHsWrapper -- Fast path; also avoids complaint when we infer+ -- an ambiguouse type and have AllowAmbiguousType+ -- e..g infer x :: forall a. F a -> Int+ else tcSubType_NC ExprSigCtxt inferred_sigma my_sigma++ ; traceTc "tcExpSig" (ppr qtvs $$ ppr givens $$ ppr inferred_sigma $$ ppr my_sigma)+ ; let poly_wrap = wrap+ <.> mkWpTyLams qtvs+ <.> mkWpLams givens+ <.> mkWpLet ev_binds+ ; return (mkLHsWrap poly_wrap expr', my_sigma) }+++{- Note [Partial expression signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Partial type signatures on expressions are easy to get wrong. But+here is a guiding principile+ e :: ty+should behave like+ let x :: ty+ x = e+ in x++So for partial signatures we apply the MR if no context is given. So+ e :: IO _ apply the MR+ e :: _ => IO _ do not apply the MR+just like in TcBinds.decideGeneralisationPlan++This makes a difference (Trac #11670):+ peek :: Ptr a -> IO CLong+ peek ptr = peekElemOff undefined 0 :: _+from (peekElemOff undefined 0) we get+ type: IO w+ constraints: Storable w++We must NOT try to generalise over 'w' because the signature specifies+no constraints so we'll complain about not being able to solve+Storable w. Instead, don't generalise; then _ gets instantiated to+CLong, as it should.+-}++{- *********************************************************************+* *+ tcInferId+* *+********************************************************************* -}++tcCheckId :: Name -> ExpRhoType -> TcM (HsExpr TcId)+tcCheckId name res_ty+ = do { (expr, actual_res_ty) <- tcInferId name+ ; traceTc "tcCheckId" (vcat [ppr name, ppr actual_res_ty, ppr res_ty])+ ; addFunResCtxt False (HsVar (noLoc name)) actual_res_ty res_ty $+ tcWrapResultO (OccurrenceOf name) expr actual_res_ty res_ty }++tcCheckRecSelId :: AmbiguousFieldOcc Name -> ExpRhoType -> TcM (HsExpr TcId)+tcCheckRecSelId f@(Unambiguous (L _ lbl) _) res_ty+ = do { (expr, actual_res_ty) <- tcInferRecSelId f+ ; addFunResCtxt False (HsRecFld f) actual_res_ty res_ty $+ tcWrapResultO (OccurrenceOfRecSel lbl) expr actual_res_ty res_ty }+tcCheckRecSelId (Ambiguous lbl _) res_ty+ = case tcSplitFunTy_maybe =<< checkingExpType_maybe res_ty of+ Nothing -> ambiguousSelector lbl+ Just (arg, _) -> do { sel_name <- disambiguateSelector lbl arg+ ; tcCheckRecSelId (Unambiguous lbl sel_name) res_ty }++------------------------+tcInferRecSelId :: AmbiguousFieldOcc Name -> TcM (HsExpr TcId, TcRhoType)+tcInferRecSelId (Unambiguous (L _ lbl) sel)+ = do { (expr', ty) <- tc_infer_id lbl sel+ ; return (expr', ty) }+tcInferRecSelId (Ambiguous lbl _)+ = ambiguousSelector lbl++------------------------+tcInferId :: Name -> TcM (HsExpr TcId, TcSigmaType)+-- Look up an occurrence of an Id+-- Do not instantiate its type+tcInferId id_name+ | id_name `hasKey` tagToEnumKey+ = failWithTc (text "tagToEnum# must appear applied to one argument")+ -- tcApp catches the case (tagToEnum# arg)++ | id_name `hasKey` assertIdKey+ = do { dflags <- getDynFlags+ ; if gopt Opt_IgnoreAsserts dflags+ then tc_infer_id (nameRdrName id_name) id_name+ else tc_infer_assert id_name }++ | otherwise+ = do { (expr, ty) <- tc_infer_id (nameRdrName id_name) id_name+ ; traceTc "tcInferId" (ppr id_name <+> dcolon <+> ppr ty)+ ; return (expr, ty) }++tc_infer_assert :: Name -> TcM (HsExpr TcId, TcSigmaType)+-- Deal with an occurrence of 'assert'+-- See Note [Adding the implicit parameter to 'assert']+tc_infer_assert assert_name+ = do { assert_error_id <- tcLookupId assertErrorName+ ; (wrap, id_rho) <- topInstantiate (OccurrenceOf assert_name)+ (idType assert_error_id)+ ; return (mkHsWrap wrap (HsVar (noLoc assert_error_id)), id_rho)+ }++tc_infer_id :: RdrName -> Name -> TcM (HsExpr TcId, TcSigmaType)+tc_infer_id lbl id_name+ = do { thing <- tcLookup id_name+ ; case thing of+ ATcId { tct_id = id }+ -> do { check_naughty id -- Note [Local record selectors]+ ; checkThLocalId id+ ; return_id id }++ AGlobal (AnId id)+ -> do { check_naughty id+ ; return_id id }+ -- A global cannot possibly be ill-staged+ -- nor does it need the 'lifting' treatment+ -- hence no checkTh stuff here++ AGlobal (AConLike cl) -> case cl of+ RealDataCon con -> return_data_con con+ PatSynCon ps -> tcPatSynBuilderOcc ps++ _ -> failWithTc $+ ppr thing <+> text "used where a value identifier was expected" }+ where+ return_id id = return (HsVar (noLoc id), idType id)++ return_data_con con+ -- For data constructors, must perform the stupid-theta check+ | null stupid_theta+ = return (HsConLikeOut (RealDataCon con), con_ty)++ | otherwise+ -- See Note [Instantiating stupid theta]+ = do { let (tvs, theta, rho) = tcSplitSigmaTy con_ty+ ; (subst, tvs') <- newMetaTyVars tvs+ ; let tys' = mkTyVarTys tvs'+ theta' = substTheta subst theta+ rho' = substTy subst rho+ ; wrap <- instCall (OccurrenceOf id_name) tys' theta'+ ; addDataConStupidTheta con tys'+ ; return (mkHsWrap wrap (HsConLikeOut (RealDataCon con)), rho') }++ where+ con_ty = dataConUserType con+ stupid_theta = dataConStupidTheta con++ check_naughty id+ | isNaughtyRecordSelector id = failWithTc (naughtyRecordSel lbl)+ | otherwise = return ()+++tcUnboundId :: UnboundVar -> ExpRhoType -> TcM (HsExpr TcId)+-- Typecheck an occurrence of an unbound Id+--+-- Some of these started life as a true expression hole "_".+-- Others might simply be variables that accidentally have no binding site+--+-- We turn all of them into HsVar, since HsUnboundVar can't contain an+-- Id; and indeed the evidence for the CHoleCan does bind it, so it's+-- not unbound any more!+tcUnboundId unbound res_ty+ = do { ty <- newOpenFlexiTyVarTy -- Allow Int# etc (Trac #12531)+ ; let occ = unboundVarOcc unbound+ ; name <- newSysName occ+ ; let ev = mkLocalId name ty+ ; loc <- getCtLocM HoleOrigin Nothing+ ; let can = CHoleCan { cc_ev = CtWanted { ctev_pred = ty+ , ctev_dest = EvVarDest ev+ , ctev_nosh = WDeriv+ , ctev_loc = loc}+ , cc_hole = ExprHole unbound }+ ; emitInsoluble can+ ; tcWrapResultO (UnboundOccurrenceOf occ) (HsVar (noLoc ev)) ty res_ty }+++{-+Note [Adding the implicit parameter to 'assert']+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The typechecker transforms (assert e1 e2) to (assertError e1 e2).+This isn't really the Right Thing because there's no way to "undo"+if you want to see the original source code in the typechecker+output. We'll have fix this in due course, when we care more about+being able to reconstruct the exact original program.++Note [tagToEnum#]+~~~~~~~~~~~~~~~~~+Nasty check to ensure that tagToEnum# is applied to a type that is an+enumeration TyCon. Unification may refine the type later, but this+check won't see that, alas. It's crude, because it relies on our+knowing *now* that the type is ok, which in turn relies on the+eager-unification part of the type checker pushing enough information+here. In theory the Right Thing to do is to have a new form of+constraint but I definitely cannot face that! And it works ok as-is.++Here's are two cases that should fail+ f :: forall a. a+ f = tagToEnum# 0 -- Can't do tagToEnum# at a type variable++ g :: Int+ g = tagToEnum# 0 -- Int is not an enumeration++When data type families are involved it's a bit more complicated.+ data family F a+ data instance F [Int] = A | B | C+Then we want to generate something like+ tagToEnum# R:FListInt 3# |> co :: R:FListInt ~ F [Int]+Usually that coercion is hidden inside the wrappers for+constructors of F [Int] but here we have to do it explicitly.++It's all grotesquely complicated.++Note [Instantiating stupid theta]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Normally, when we infer the type of an Id, we don't instantiate,+because we wish to allow for visible type application later on.+But if a datacon has a stupid theta, we're a bit stuck. We need+to emit the stupid theta constraints with instantiated types. It's+difficult to defer this to the lazy instantiation, because a stupid+theta has no spot to put it in a type. So we just instantiate eagerly+in this case. Thus, users cannot use visible type application with+a data constructor sporting a stupid theta. I won't feel so bad for+the users that complain.++-}++tcSeq :: SrcSpan -> Name -> [LHsExprArgIn]+ -> ExpRhoType -> TcM (HsWrapper, LHsExpr TcId, [LHsExprArgOut])+-- (seq e1 e2) :: res_ty+-- We need a special typing rule because res_ty can be unboxed+-- See Note [Typing rule for seq]+tcSeq loc fun_name args res_ty+ = do { fun <- tcLookupId fun_name+ ; (arg1_ty, args1) <- case args of+ (Right hs_ty_arg1 : args1)+ -> do { ty_arg1 <- tcHsTypeApp hs_ty_arg1 liftedTypeKind+ ; return (ty_arg1, args1) }++ _ -> do { arg_ty1 <- newFlexiTyVarTy liftedTypeKind+ ; return (arg_ty1, args) }++ ; (arg1, arg2, arg2_exp_ty) <- case args1 of+ [Right hs_ty_arg2, Left term_arg1, Left term_arg2]+ -> do { arg2_kind <- newOpenTypeKind+ ; ty_arg2 <- tcHsTypeApp hs_ty_arg2 arg2_kind+ -- see Note [Typing rule for seq]+ ; _ <- tcSubTypeDS (OccurrenceOf fun_name) GenSigCtxt ty_arg2 res_ty+ ; return (term_arg1, term_arg2, mkCheckExpType ty_arg2) }+ [Left term_arg1, Left term_arg2]+ -> return (term_arg1, term_arg2, res_ty)+ _ -> too_many_args "seq" args++ ; arg1' <- tcMonoExpr arg1 (mkCheckExpType arg1_ty)+ ; arg2' <- tcMonoExpr arg2 arg2_exp_ty+ ; res_ty <- readExpType res_ty -- by now, it's surely filled in+ ; let fun' = L loc (HsWrap ty_args (HsVar (L loc fun)))+ ty_args = WpTyApp res_ty <.> WpTyApp arg1_ty+ ; return (idHsWrapper, fun', [Left arg1', Left arg2']) }++tcTagToEnum :: SrcSpan -> Name -> [LHsExprArgIn] -> ExpRhoType+ -> TcM (HsWrapper, LHsExpr TcId, [LHsExprArgOut])+-- tagToEnum# :: forall a. Int# -> a+-- See Note [tagToEnum#] Urgh!+tcTagToEnum loc fun_name args res_ty+ = do { fun <- tcLookupId fun_name++ ; arg <- case args of+ [Right hs_ty_arg, Left term_arg]+ -> do { ty_arg <- tcHsTypeApp hs_ty_arg liftedTypeKind+ ; _ <- tcSubTypeDS (OccurrenceOf fun_name) GenSigCtxt ty_arg res_ty+ -- other than influencing res_ty, we just+ -- don't care about a type arg passed in.+ -- So drop the evidence.+ ; return term_arg }+ [Left term_arg] -> do { _ <- expTypeToType res_ty+ ; return term_arg }+ _ -> too_many_args "tagToEnum#" args++ ; res_ty <- readExpType res_ty+ ; ty' <- zonkTcType res_ty++ -- Check that the type is algebraic+ ; let mb_tc_app = tcSplitTyConApp_maybe ty'+ Just (tc, tc_args) = mb_tc_app+ ; checkTc (isJust mb_tc_app)+ (mk_error ty' doc1)++ -- Look through any type family+ ; fam_envs <- tcGetFamInstEnvs+ ; let (rep_tc, rep_args, coi)+ = tcLookupDataFamInst fam_envs tc tc_args+ -- coi :: tc tc_args ~R rep_tc rep_args++ ; checkTc (isEnumerationTyCon rep_tc)+ (mk_error ty' doc2)++ ; arg' <- tcMonoExpr arg (mkCheckExpType intPrimTy)+ ; let fun' = L loc (HsWrap (WpTyApp rep_ty) (HsVar (L loc fun)))+ rep_ty = mkTyConApp rep_tc rep_args++ ; return (mkWpCastR (mkTcSymCo coi), fun', [Left arg']) }+ -- coi is a Representational coercion+ where+ doc1 = vcat [ text "Specify the type by giving a type signature"+ , text "e.g. (tagToEnum# x) :: Bool" ]+ doc2 = text "Result type must be an enumeration type"++ mk_error :: TcType -> SDoc -> SDoc+ mk_error ty what+ = hang (text "Bad call to tagToEnum#"+ <+> text "at type" <+> ppr ty)+ 2 what++too_many_args :: String -> [LHsExprArgIn] -> TcM a+too_many_args fun args+ = failWith $+ hang (text "Too many type arguments to" <+> text fun <> colon)+ 2 (sep (map pp args))+ where+ pp (Left e) = ppr e+ pp (Right (HsWC { hswc_body = L _ t })) = pprParendHsType t+++{-+************************************************************************+* *+ Template Haskell checks+* *+************************************************************************+-}++checkThLocalId :: Id -> TcM ()+checkThLocalId id+ = do { mb_local_use <- getStageAndBindLevel (idName id)+ ; case mb_local_use of+ Just (top_lvl, bind_lvl, use_stage)+ | thLevel use_stage > bind_lvl+ , isNotTopLevel top_lvl+ -> checkCrossStageLifting id use_stage+ _ -> return () -- Not a locally-bound thing, or+ -- no cross-stage link+ }++--------------------------------------+checkCrossStageLifting :: Id -> ThStage -> TcM ()+-- If we are inside typed brackets, and (use_lvl > bind_lvl)+-- we must check whether there's a cross-stage lift to do+-- Examples \x -> [|| x ||]+-- [|| map ||]+-- There is no error-checking to do, because the renamer did that+--+-- This is similar to checkCrossStageLifting in RnSplice, but+-- this code is applied to *typed* brackets.++checkCrossStageLifting id (Brack _ (TcPending ps_var lie_var))+ = -- Nested identifiers, such as 'x' in+ -- E.g. \x -> [|| h x ||]+ -- We must behave as if the reference to x was+ -- h $(lift x)+ -- We use 'x' itself as the splice proxy, used by+ -- the desugarer to stitch it all back together.+ -- If 'x' occurs many times we may get many identical+ -- bindings of the same splice proxy, but that doesn't+ -- matter, although it's a mite untidy.+ do { let id_ty = idType id+ ; checkTc (isTauTy id_ty) (polySpliceErr id)+ -- If x is polymorphic, its occurrence sites might+ -- have different instantiations, so we can't use plain+ -- 'x' as the splice proxy name. I don't know how to+ -- solve this, and it's probably unimportant, so I'm+ -- just going to flag an error for now++ ; lift <- if isStringTy id_ty then+ do { sid <- tcLookupId THNames.liftStringName+ -- See Note [Lifting strings]+ ; return (HsVar (noLoc sid)) }+ else+ setConstraintVar lie_var $+ -- Put the 'lift' constraint into the right LIE+ newMethodFromName (OccurrenceOf (idName id))+ THNames.liftName id_ty++ -- Update the pending splices+ ; ps <- readMutVar ps_var+ ; let pending_splice = PendingTcSplice (idName id) (nlHsApp (noLoc lift) (nlHsVar id))+ ; writeMutVar ps_var (pending_splice : ps)++ ; return () }++checkCrossStageLifting _ _ = return ()++polySpliceErr :: Id -> SDoc+polySpliceErr id+ = text "Can't splice the polymorphic local variable" <+> quotes (ppr id)++{-+Note [Lifting strings]+~~~~~~~~~~~~~~~~~~~~~~+If we see $(... [| s |] ...) where s::String, we don't want to+generate a mass of Cons (CharL 'x') (Cons (CharL 'y') ...)) etc.+So this conditional short-circuits the lifting mechanism to generate+(liftString "xy") in that case. I didn't want to use overlapping instances+for the Lift class in TH.Syntax, because that can lead to overlapping-instance+errors in a polymorphic situation.++If this check fails (which isn't impossible) we get another chance; see+Note [Converting strings] in Convert.hs++Local record selectors+~~~~~~~~~~~~~~~~~~~~~~+Record selectors for TyCons in this module are ordinary local bindings,+which show up as ATcIds rather than AGlobals. So we need to check for+naughtiness in both branches. c.f. TcTyClsBindings.mkAuxBinds.+++************************************************************************+* *+\subsection{Record bindings}+* *+************************************************************************+-}++getFixedTyVars :: [FieldLabelString] -> [TyVar] -> [ConLike] -> TyVarSet+-- These tyvars must not change across the updates+getFixedTyVars upd_fld_occs univ_tvs cons+ = mkVarSet [tv1 | con <- cons+ , let (u_tvs, _, eqspec, prov_theta+ , req_theta, arg_tys, _)+ = conLikeFullSig con+ theta = eqSpecPreds eqspec+ ++ prov_theta+ ++ req_theta+ flds = conLikeFieldLabels con+ fixed_tvs = exactTyCoVarsOfTypes fixed_tys+ -- fixed_tys: See Note [Type of a record update]+ `unionVarSet` tyCoVarsOfTypes theta+ -- Universally-quantified tyvars that+ -- appear in any of the *implicit*+ -- arguments to the constructor are fixed+ -- See Note [Implicit type sharing]++ fixed_tys = [ty | (fl, ty) <- zip flds arg_tys+ , not (flLabel fl `elem` upd_fld_occs)]+ , (tv1,tv) <- univ_tvs `zip` u_tvs+ , tv `elemVarSet` fixed_tvs ]++{-+Note [Disambiguating record fields]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When the -XDuplicateRecordFields extension is used, and the renamer+encounters a record selector or update that it cannot immediately+disambiguate (because it involves fields that belong to multiple+datatypes), it will defer resolution of the ambiguity to the+typechecker. In this case, the `Ambiguous` constructor of+`AmbiguousFieldOcc` is used.++Consider the following definitions:++ data S = MkS { foo :: Int }+ data T = MkT { foo :: Int, bar :: Int }+ data U = MkU { bar :: Int, baz :: Int }++When the renamer sees `foo` as a selector or an update, it will not+know which parent datatype is in use.++For selectors, there are two possible ways to disambiguate:++1. Check if the pushed-in type is a function whose domain is a+ datatype, for example:++ f s = (foo :: S -> Int) s++ g :: T -> Int+ g = foo++ This is checked by `tcCheckRecSelId` when checking `HsRecFld foo`.++2. Check if the selector is applied to an argument that has a type+ signature, for example:++ h = foo (s :: S)++ This is checked by `tcApp`.+++Updates are slightly more complex. The `disambiguateRecordBinds`+function tries to determine the parent datatype in three ways:++1. Check for types that have all the fields being updated. For example:++ f x = x { foo = 3, bar = 2 }++ Here `f` must be updating `T` because neither `S` nor `U` have+ both fields. This may also discover that no possible type exists.+ For example the following will be rejected:++ f' x = x { foo = 3, baz = 3 }++2. Use the type being pushed in, if it is already a TyConApp. The+ following are valid updates to `T`:++ g :: T -> T+ g x = x { foo = 3 }++ g' x = x { foo = 3 } :: T++3. Use the type signature of the record expression, if it exists and+ is a TyConApp. Thus this is valid update to `T`:++ h x = (x :: T) { foo = 3 }+++Note that we do not look up the types of variables being updated, and+no constraint-solving is performed, so for example the following will+be rejected as ambiguous:++ let bad (s :: S) = foo s++ let r :: T+ r = blah+ in r { foo = 3 }++ \r. (r { foo = 3 }, r :: T )++We could add further tests, of a more heuristic nature. For example,+rather than looking for an explicit signature, we could try to infer+the type of the argument to a selector or the record expression being+updated, in case we are lucky enough to get a TyConApp straight+away. However, it might be hard for programmers to predict whether a+particular update is sufficiently obvious for the signature to be+omitted. Moreover, this might change the behaviour of typechecker in+non-obvious ways.++See also Note [HsRecField and HsRecUpdField] in HsPat.+-}++-- Given a RdrName that refers to multiple record fields, and the type+-- of its argument, try to determine the name of the selector that is+-- meant.+disambiguateSelector :: Located RdrName -> Type -> TcM Name+disambiguateSelector lr@(L _ rdr) parent_type+ = do { fam_inst_envs <- tcGetFamInstEnvs+ ; case tyConOf fam_inst_envs parent_type of+ Nothing -> ambiguousSelector lr+ Just p ->+ do { xs <- lookupParents rdr+ ; let parent = RecSelData p+ ; case lookup parent xs of+ Just gre -> do { addUsedGRE True gre+ ; return (gre_name gre) }+ Nothing -> failWithTc (fieldNotInType parent rdr) } }++-- This field name really is ambiguous, so add a suitable "ambiguous+-- occurrence" error, then give up.+ambiguousSelector :: Located RdrName -> TcM a+ambiguousSelector (L _ rdr)+ = do { env <- getGlobalRdrEnv+ ; let gres = lookupGRE_RdrName rdr env+ ; setErrCtxt [] $ addNameClashErrRn rdr gres+ ; failM }++-- Disambiguate the fields in a record update.+-- See Note [Disambiguating record fields]+disambiguateRecordBinds :: LHsExpr Name -> TcRhoType+ -> [LHsRecUpdField Name] -> ExpRhoType+ -> TcM [LHsRecField' (AmbiguousFieldOcc Id) (LHsExpr Name)]+disambiguateRecordBinds record_expr record_rho rbnds res_ty+ -- Are all the fields unambiguous?+ = case mapM isUnambiguous rbnds of+ -- If so, just skip to looking up the Ids+ -- Always the case if DuplicateRecordFields is off+ Just rbnds' -> mapM lookupSelector rbnds'+ Nothing -> -- If not, try to identify a single parent+ do { fam_inst_envs <- tcGetFamInstEnvs+ -- Look up the possible parents for each field+ ; rbnds_with_parents <- getUpdFieldsParents+ ; let possible_parents = map (map fst . snd) rbnds_with_parents+ -- Identify a single parent+ ; p <- identifyParent fam_inst_envs possible_parents+ -- Pick the right selector with that parent for each field+ ; checkNoErrs $ mapM (pickParent p) rbnds_with_parents }+ where+ -- Extract the selector name of a field update if it is unambiguous+ isUnambiguous :: LHsRecUpdField Name -> Maybe (LHsRecUpdField Name, Name)+ isUnambiguous x = case unLoc (hsRecFieldLbl (unLoc x)) of+ Unambiguous _ sel_name -> Just (x, sel_name)+ Ambiguous{} -> Nothing++ -- Look up the possible parents and selector GREs for each field+ getUpdFieldsParents :: TcM [(LHsRecUpdField Name+ , [(RecSelParent, GlobalRdrElt)])]+ getUpdFieldsParents+ = fmap (zip rbnds) $ mapM+ (lookupParents . unLoc . hsRecUpdFieldRdr . unLoc)+ rbnds++ -- Given a the lists of possible parents for each field,+ -- identify a single parent+ identifyParent :: FamInstEnvs -> [[RecSelParent]] -> TcM RecSelParent+ 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)++ -- Exactly one datatype with all the fields: use that+ [p] -> return p++ -- Multiple possible parents: try harder to disambiguate+ -- Can we get a parent TyCon from the pushed-in type?+ _:_ | Just p <- tyConOfET fam_inst_envs res_ty -> return (RecSelData p)++ -- Does the expression being updated have a type signature?+ -- If so, try to extract a parent TyCon from it+ | Just {} <- obviousSig (unLoc record_expr)+ , Just tc <- tyConOf fam_inst_envs record_rho+ -> return (RecSelData tc)++ -- Nothing else we can try...+ _ -> failWithTc badOverloadedUpdate++ -- Make a field unambiguous by choosing the given parent.+ -- Emits an error if the field cannot have that parent,+ -- e.g. if the user writes+ -- r { x = e } :: T+ -- where T does not have field x.+ pickParent :: RecSelParent+ -> (LHsRecUpdField Name, [(RecSelParent, GlobalRdrElt)])+ -> TcM (LHsRecField' (AmbiguousFieldOcc Id) (LHsExpr Name))+ pickParent p (upd, xs)+ = case lookup p xs of+ -- Phew! The parent is valid for this field.+ -- Previously ambiguous fields must be marked as+ -- used now that we know which one is meant, but+ -- unambiguous ones shouldn't be recorded again+ -- (giving duplicate deprecation warnings).+ Just gre -> do { unless (null (tail xs)) $ do+ let L loc _ = hsRecFieldLbl (unLoc upd)+ setSrcSpan loc $ addUsedGRE True gre+ ; lookupSelector (upd, gre_name gre) }+ -- The field doesn't belong to this parent, so report+ -- an error but keep going through all the fields+ Nothing -> do { addErrTc (fieldNotInType p+ (unLoc (hsRecUpdFieldRdr (unLoc upd))))+ ; lookupSelector (upd, gre_name (snd (head xs))) }++ -- Given a (field update, selector name) pair, look up the+ -- selector to give a field update with an unambiguous Id+ lookupSelector :: (LHsRecUpdField Name, Name)+ -> TcM (LHsRecField' (AmbiguousFieldOcc Id) (LHsExpr Name))+ lookupSelector (L l upd, n)+ = do { i <- tcLookupId n+ ; let L loc af = hsRecFieldLbl upd+ lbl = rdrNameAmbiguousFieldOcc af+ ; return $ L l upd { hsRecFieldLbl+ = L loc (Unambiguous (L loc lbl) i) } }+++-- Extract the outermost TyCon of a type, if there is one; for+-- data families this is the representation tycon (because that's+-- where the fields live).+tyConOf :: FamInstEnvs -> TcSigmaType -> Maybe TyCon+tyConOf fam_inst_envs ty0+ = case tcSplitTyConApp_maybe ty of+ Just (tc, tys) -> Just (fstOf3 (tcLookupDataFamInst fam_inst_envs tc tys))+ Nothing -> Nothing+ where+ (_, _, ty) = tcSplitSigmaTy ty0++-- Variant of tyConOf that works for ExpTypes+tyConOfET :: FamInstEnvs -> ExpRhoType -> Maybe TyCon+tyConOfET fam_inst_envs ty0 = tyConOf fam_inst_envs =<< checkingExpType_maybe ty0++-- For an ambiguous record field, find all the candidate record+-- selectors (as GlobalRdrElts) and their parents.+lookupParents :: RdrName -> RnM [(RecSelParent, GlobalRdrElt)]+lookupParents rdr+ = do { env <- getGlobalRdrEnv+ ; let gres = lookupGRE_RdrName rdr env+ ; mapM lookupParent gres }+ where+ lookupParent :: GlobalRdrElt -> RnM (RecSelParent, GlobalRdrElt)+ lookupParent gre = do { id <- tcLookupId (gre_name gre)+ ; if isRecordSelector id+ then return (recordSelectorTyCon id, gre)+ else failWithTc (notSelector (gre_name gre)) }++-- A type signature on the argument of an ambiguous record selector or+-- the record expression in an update must be "obvious", i.e. the+-- outermost constructor ignoring parentheses.+obviousSig :: HsExpr Name -> Maybe (LHsSigWcType Name)+obviousSig (ExprWithTySig _ ty) = Just ty+obviousSig (HsPar p) = obviousSig (unLoc p)+obviousSig _ = Nothing+++{-+Game plan for record bindings+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+1. Find the TyCon for the bindings, from the first field label.++2. Instantiate its tyvars and unify (T a1 .. an) with expected_ty.++For each binding field = value++3. Instantiate the field type (from the field label) using the type+ envt from step 2.++4 Type check the value using tcArg, passing the field type as+ the expected argument type.++This extends OK when the field types are universally quantified.+-}++tcRecordBinds+ :: ConLike+ -> [TcType] -- Expected type for each field+ -> HsRecordBinds Name+ -> TcM (HsRecordBinds TcId)++tcRecordBinds con_like arg_tys (HsRecFields rbinds dd)+ = do { mb_binds <- mapM do_bind rbinds+ ; return (HsRecFields (catMaybes mb_binds) dd) }+ where+ fields = map flLabel $ conLikeFieldLabels con_like+ flds_w_tys = zipEqual "tcRecordBinds" fields arg_tys++ do_bind :: LHsRecField Name (LHsExpr Name)+ -> TcM (Maybe (LHsRecField TcId (LHsExpr TcId)))+ do_bind (L l fld@(HsRecField { hsRecFieldLbl = f+ , hsRecFieldArg = rhs }))++ = do { mb <- tcRecordField con_like flds_w_tys f rhs+ ; case mb of+ Nothing -> return Nothing+ Just (f', rhs') -> return (Just (L l (fld { hsRecFieldLbl = f'+ , hsRecFieldArg = rhs' }))) }++tcRecordUpd+ :: ConLike+ -> [TcType] -- Expected type for each field+ -> [LHsRecField' (AmbiguousFieldOcc Id) (LHsExpr Name)]+ -> TcM [LHsRecUpdField TcId]++tcRecordUpd con_like arg_tys rbinds = fmap catMaybes $ mapM do_bind rbinds+ where+ flds_w_tys = zipEqual "tcRecordUpd" (map flLabel $ conLikeFieldLabels con_like) arg_tys++ do_bind :: LHsRecField' (AmbiguousFieldOcc Id) (LHsExpr Name) -> TcM (Maybe (LHsRecUpdField TcId))+ do_bind (L l fld@(HsRecField { hsRecFieldLbl = L loc af+ , hsRecFieldArg = rhs }))+ = do { let lbl = rdrNameAmbiguousFieldOcc af+ sel_id = selectorAmbiguousFieldOcc af+ f = L loc (FieldOcc (L loc lbl) (idName sel_id))+ ; mb <- tcRecordField con_like flds_w_tys f rhs+ ; case mb of+ Nothing -> return Nothing+ Just (f', rhs') ->+ return (Just+ (L l (fld { hsRecFieldLbl+ = L loc (Unambiguous (L loc lbl)+ (selectorFieldOcc (unLoc f')))+ , hsRecFieldArg = rhs' }))) }++tcRecordField :: ConLike -> Assoc FieldLabelString Type -> LFieldOcc Name -> LHsExpr Name+ -> TcM (Maybe (LFieldOcc Id, LHsExpr Id))+tcRecordField con_like flds_w_tys (L loc (FieldOcc lbl sel_name)) rhs+ | Just field_ty <- assocMaybe flds_w_tys field_lbl+ = addErrCtxt (fieldCtxt field_lbl) $+ do { rhs' <- tcPolyExprNC rhs field_ty+ ; let field_id = mkUserLocal (nameOccName sel_name)+ (nameUnique sel_name)+ field_ty loc+ -- Yuk: the field_id has the *unique* of the selector Id+ -- (so we can find it easily)+ -- but is a LocalId with the appropriate type of the RHS+ -- (so the desugarer knows the type of local binder to make)+ ; return (Just (L loc (FieldOcc lbl field_id), rhs')) }+ | otherwise+ = do { addErrTc (badFieldCon con_like field_lbl)+ ; return Nothing }+ where+ field_lbl = occNameFS $ rdrNameOcc (unLoc lbl)+++checkMissingFields :: ConLike -> HsRecordBinds Name -> TcM ()+checkMissingFields con_like rbinds+ | null field_labels -- Not declared as a record;+ -- 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 [])+ else+ return ()++ | otherwise = do -- A record+ unless (null missing_s_fields)+ (addErrTc (missingStrictFields con_like missing_s_fields))++ warn <- woptM Opt_WarnMissingFields+ unless (not (warn && notNull missing_ns_fields))+ (warnTc (Reason Opt_WarnMissingFields) True+ (missingFields con_like missing_ns_fields))++ where+ missing_s_fields+ = [ flLabel fl | (fl, str) <- field_info,+ isBanged str,+ not (fl `elemField` field_names_used)+ ]+ missing_ns_fields+ = [ flLabel fl | (fl, str) <- field_info,+ not (isBanged str),+ not (fl `elemField` field_names_used)+ ]++ field_names_used = hsRecFields rbinds+ field_labels = conLikeFieldLabels con_like++ field_info = zipEqual "missingFields"+ field_labels+ field_strs++ field_strs = conLikeImplBangs con_like++ fl `elemField` flds = any (\ fl' -> flSelector fl == fl') flds++{-+************************************************************************+* *+\subsection{Errors and contexts}+* *+************************************************************************++Boring and alphabetical:+-}++addExprErrCtxt :: LHsExpr Name -> TcM a -> TcM a+addExprErrCtxt expr = addErrCtxt (exprCtxt expr)++exprCtxt :: LHsExpr Name -> SDoc+exprCtxt expr+ = hang (text "In the expression:") 2 (ppr expr)++fieldCtxt :: FieldLabelString -> SDoc+fieldCtxt field_name+ = text "In the" <+> quotes (ppr field_name) <+> ptext (sLit "field of a record")++addFunResCtxt :: Bool -- There is at least one argument+ -> HsExpr Name -> TcType -> ExpRhoType+ -> TcM a -> TcM a+-- When we have a mis-match in the return type of a function+-- try to give a helpful message about too many/few arguments+--+-- Used for naked variables too; but with has_args = False+addFunResCtxt has_args fun fun_res_ty env_ty+ = addLandmarkErrCtxtM (\env -> (env, ) <$> mk_msg)+ -- NB: use a landmark error context, so that an empty context+ -- doesn't suppress some more useful context+ where+ mk_msg+ = do { mb_env_ty <- readExpType_maybe env_ty+ -- by the time the message is rendered, the ExpType+ -- will be filled in (except if we're debugging)+ ; fun_res' <- zonkTcType fun_res_ty+ ; env' <- case mb_env_ty of+ Just env_ty -> zonkTcType env_ty+ Nothing ->+ do { dumping <- doptM Opt_D_dump_tc_trace+ ; MASSERT( dumping )+ ; newFlexiTyVarTy liftedTypeKind }+ ; let (_, _, fun_tau) = tcSplitSigmaTy fun_res'+ (_, _, env_tau) = tcSplitSigmaTy env'+ (args_fun, res_fun) = tcSplitFunTys fun_tau+ (args_env, res_env) = tcSplitFunTys env_tau+ n_fun = length args_fun+ n_env = length args_env+ info | n_fun == n_env = Outputable.empty+ | n_fun > n_env+ , not_fun res_env+ = text "Probable cause:" <+> quotes (ppr fun)+ <+> text "is applied to too few arguments"++ | has_args+ , not_fun res_fun+ = text "Possible cause:" <+> quotes (ppr fun)+ <+> text "is applied to too many arguments"++ | otherwise+ = Outputable.empty -- Never suggest that a naked variable is -- applied to too many args!+ ; return info }+ where+ not_fun ty -- ty is definitely not an arrow type,+ -- and cannot conceivably become one+ = case tcSplitTyConApp_maybe ty of+ Just (tc, _) -> isAlgTyCon tc+ Nothing -> False++badFieldTypes :: [(FieldLabelString,TcType)] -> SDoc+badFieldTypes prs+ = hang (text "Record update for insufficiently polymorphic field"+ <> plural prs <> colon)+ 2 (vcat [ ppr f <+> dcolon <+> ppr ty | (f,ty) <- prs ])++badFieldsUpd+ :: [LHsRecField' (AmbiguousFieldOcc Id) (LHsExpr Name)] -- Field names that don't belong to a single datacon+ -> [ConLike] -- Data cons of the type which the first field name belongs to+ -> SDoc+badFieldsUpd rbinds data_cons+ = hang (text "No constructor has all these fields:")+ 2 (pprQuotedList conflictingFields)+ -- See Note [Finding the conflicting fields]+ where+ -- A (preferably small) set of fields such that no constructor contains+ -- all of them. See Note [Finding the conflicting fields]+ conflictingFields = case nonMembers of+ -- nonMember belongs to a different type.+ (nonMember, _) : _ -> [aMember, nonMember]+ [] -> let+ -- All of rbinds belong to one type. In this case, repeatedly add+ -- a field to the set until no constructor contains the set.++ -- Each field, together with a list indicating which constructors+ -- have all the fields so far.+ growingSets :: [(FieldLabelString, [Bool])]+ growingSets = scanl1 combine membership+ combine (_, setMem) (field, fldMem)+ = (field, zipWith (&&) setMem fldMem)+ in+ -- Fields that don't change the membership status of the set+ -- are redundant and can be dropped.+ map (fst . head) $ groupBy ((==) `on` snd) growingSets++ aMember = ASSERT( not (null members) ) fst (head members)+ (members, nonMembers) = partition (or . snd) membership++ -- For each field, which constructors contain the field?+ membership :: [(FieldLabelString, [Bool])]+ membership = sortMembership $+ map (\fld -> (fld, map (Set.member fld) fieldLabelSets)) $+ map (occNameFS . rdrNameOcc . rdrNameAmbiguousFieldOcc . unLoc . hsRecFieldLbl . unLoc) rbinds++ fieldLabelSets :: [Set.Set FieldLabelString]+ fieldLabelSets = map (Set.fromList . map flLabel . conLikeFieldLabels) data_cons++ -- Sort in order of increasing number of True, so that a smaller+ -- conflicting set can be found.+ sortMembership =+ map snd .+ sortBy (compare `on` fst) .+ map (\ item@(_, membershipRow) -> (countTrue membershipRow, item))++ countTrue = count id++{-+Note [Finding the conflicting fields]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+ data A = A {a0, a1 :: Int}+ | B {b0, b1 :: Int}+and we see a record update+ x { a0 = 3, a1 = 2, b0 = 4, b1 = 5 }+Then we'd like to find the smallest subset of fields that no+constructor has all of. Here, say, {a0,b0}, or {a0,b1}, etc.+We don't really want to report that no constructor has all of+{a0,a1,b0,b1}, because when there are hundreds of fields it's+hard to see what was really wrong.++We may need more than two fields, though; eg+ data T = A { x,y :: Int, v::Int }+ | B { y,z :: Int, v::Int }+ | C { z,x :: Int, v::Int }+with update+ r { x=e1, y=e2, z=e3 }, we++Finding the smallest subset is hard, so the code here makes+a decent stab, no more. See Trac #7989.+-}++naughtyRecordSel :: RdrName -> SDoc+naughtyRecordSel sel_id+ = text "Cannot use record selector" <+> quotes (ppr sel_id) <+>+ text "as a function due to escaped type variables" $$+ text "Probable fix: use pattern-matching syntax instead"++notSelector :: Name -> SDoc+notSelector field+ = hsep [quotes (ppr field), text "is not a record selector"]++mixedSelectors :: [Id] -> [Id] -> SDoc+mixedSelectors data_sels@(dc_rep_id:_) pat_syn_sels@(ps_rep_id:_)+ = ptext+ (sLit "Cannot use a mixture of pattern synonym and record selectors") $$+ text "Record selectors defined by"+ <+> quotes (ppr (tyConName rep_dc))+ <> text ":"+ <+> pprWithCommas ppr data_sels $$+ text "Pattern synonym selectors defined by"+ <+> quotes (ppr (patSynName rep_ps))+ <> text ":"+ <+> pprWithCommas ppr pat_syn_sels+ where+ RecSelPatSyn rep_ps = recordSelectorTyCon ps_rep_id+ RecSelData rep_dc = recordSelectorTyCon dc_rep_id+mixedSelectors _ _ = panic "TcExpr: mixedSelectors emptylists"+++missingStrictFields :: ConLike -> [FieldLabelString] -> SDoc+missingStrictFields con fields+ = header <> rest+ where+ rest | null fields = Outputable.empty -- Happens for non-record constructors+ -- with strict fields+ | otherwise = colon <+> pprWithCommas ppr fields++ header = text "Constructor" <+> quotes (ppr con) <+>+ text "does not have the required strict field(s)"++missingFields :: ConLike -> [FieldLabelString] -> SDoc+missingFields con fields+ = text "Fields of" <+> quotes (ppr con) <+> ptext (sLit "not initialised:")+ <+> pprWithCommas ppr fields++-- callCtxt fun args = text "In the call" <+> parens (ppr (foldl mkHsApp fun args))++noPossibleParents :: [LHsRecUpdField Name] -> SDoc+noPossibleParents rbinds+ = hang (text "No type has all these fields:")+ 2 (pprQuotedList fields)+ where+ fields = map (hsRecFieldLbl . unLoc) rbinds++badOverloadedUpdate :: SDoc+badOverloadedUpdate = text "Record update is ambiguous, and requires a type signature"++fieldNotInType :: RecSelParent -> RdrName -> SDoc+fieldNotInType p rdr+ = unknownSubordinateErr (text "field of type" <+> quotes (ppr p)) rdr++{-+************************************************************************+* *+\subsection{Static Pointers}+* *+************************************************************************+-}++-- | 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].+checkClosedInStaticForm :: Name -> TcM ()+checkClosedInStaticForm name = do+ type_env <- getLclTypeEnv+ case checkClosed type_env name of+ Nothing -> return ()+ Just reason -> addErrTc $ explain name reason+ where+ -- See Note [Checking closedness].+ checkClosed :: TcTypeEnv -> Name -> Maybe NotClosedReason+ checkClosed type_env n = checkLoop type_env (unitNameSet n) n++ checkLoop :: TcTypeEnv -> NameSet -> Name -> Maybe NotClosedReason+ checkLoop type_env visited n = do+ -- The @visited@ set is an accumulating parameter that contains the set of+ -- visited nodes, so we avoid repeating cycles in the traversal.+ case lookupNameEnv type_env n of+ Just (ATcId { tct_id = tcid, tct_info = info }) -> case info of+ ClosedLet -> Nothing+ NotLetBound -> Just NotLetBoundReason+ NonClosedLet fvs type_closed -> listToMaybe $+ -- Look for a non-closed variable in fvs+ [ NotClosed n' reason+ | n' <- nameSetElemsStable fvs+ , not (elemNameSet n' visited)+ , Just reason <- [checkLoop type_env (extendNameSet visited n') n']+ ] +++ if type_closed then+ []+ else+ -- We consider non-let-bound variables easier to figure out than+ -- non-closed types, so we report non-closed types to the user+ -- only if we cannot spot the former.+ [ NotTypeClosed $ tyCoVarsOfType (idType tcid) ]+ -- The binding is closed.+ _ -> Nothing++ -- Converts a reason into a human-readable sentence.+ --+ -- @explain name reason@ starts with+ --+ -- "<name> is used in a static form but it is not closed because it"+ --+ -- and then follows a list of causes. For each id in the path, the text+ --+ -- "uses <id> which"+ --+ -- is appended, yielding something like+ --+ -- "uses <id> which uses <id1> which uses <id2> which"+ --+ -- until the end of the path is reached, which is reported as either+ --+ -- "is not let-bound"+ --+ -- when the final node is not let-bound, or+ --+ -- "has a non-closed type because it contains the type variables:+ -- v1, v2, v3"+ --+ -- when the final node has a non-closed type.+ --+ explain :: Name -> NotClosedReason -> SDoc+ explain name reason =+ 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++-- Note [Not-closed error messages]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- When variables in a static form are not closed, we go through the trouble+-- of explaining why they aren't.+--+-- Thus, the following program+--+-- > {-# LANGUAGE StaticPointers #-}+-- > module M where+-- >+-- > f x = static g+-- > where+-- > g = h+-- > h = x+--+-- produces the error+--+-- 'g' is used in a static form but it is not closed because it+-- uses 'h' which uses 'x' which is not let-bound.+--+-- And a program like+--+-- > {-# LANGUAGE StaticPointers #-}+-- > module M where+-- >+-- > import Data.Typeable+-- > import GHC.StaticPtr+-- >+-- > f :: Typeable a => a -> StaticPtr TypeRep+-- > f x = const (static (g undefined)) (h x)+-- > where+-- > g = h+-- > h = typeOf+--+-- produces the error+--+-- 'g' is used in a static form but it is not closed because it+-- uses 'h' which has a non-closed type because it contains the+-- type variables: 'a'+--++-- Note [Checking closedness]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- @checkClosed@ checks if a binding is closed and returns a reason if it is+-- not.+--+-- The bindings define a graph where the nodes are ids, and there is an edge+-- from @id1@ to @id2@ if the rhs of @id1@ contains @id2@ among its free+-- variables.+--+-- When @n@ is not closed, it has to exist in the graph some node reachable+-- from @n@ that it is not a let-bound variable or that it has a non-closed+-- type. Thus, the "reason" is a path from @n@ to this offending node.+--+-- When @n@ is not closed, we traverse the graph reachable from @n@ to build+-- the reason.+--
+ typecheck/TcExpr.hs-boot view
@@ -0,0 +1,40 @@+module TcExpr where+import HsSyn ( HsExpr, LHsExpr, SyntaxExpr )+import Name ( Name )+import TcType ( TcRhoType, TcSigmaType, SyntaxOpType, ExpType, ExpRhoType )+import TcRnTypes( TcM, TcId, CtOrigin )++tcPolyExpr ::+ LHsExpr Name+ -> TcSigmaType+ -> TcM (LHsExpr TcId)++tcMonoExpr, tcMonoExprNC ::+ LHsExpr Name+ -> ExpRhoType+ -> TcM (LHsExpr TcId)++tcInferSigma, tcInferSigmaNC ::+ LHsExpr Name+ -> TcM (LHsExpr TcId, TcSigmaType)++tcInferRho ::+ LHsExpr Name+ -> TcM (LHsExpr TcId, TcRhoType)++tcSyntaxOp :: CtOrigin+ -> SyntaxExpr Name+ -> [SyntaxOpType] -- ^ shape of syntax operator arguments+ -> ExpType -- ^ overall result type+ -> ([TcSigmaType] -> TcM a) -- ^ Type check any arguments+ -> TcM (a, SyntaxExpr TcId)++tcSyntaxOpGen :: CtOrigin+ -> SyntaxExpr Name+ -> [SyntaxOpType]+ -> SyntaxOpType+ -> ([TcSigmaType] -> TcM a)+ -> TcM (a, SyntaxExpr TcId)+++tcCheckId :: Name -> ExpRhoType -> TcM (HsExpr TcId)
+ typecheck/TcFlatten.hs view
@@ -0,0 +1,1647 @@+{-# LANGUAGE CPP, ViewPatterns #-}++module TcFlatten(+ FlattenMode(..),+ flatten, flattenManyNom,++ unflatten,+ ) where++#include "HsVersions.h"++import TcRnTypes+import TcType+import Type+import TcUnify( occCheckExpand )+import TcEvidence+import TyCon+import TyCoRep -- performs delicate algorithm on types+import Coercion+import Var+import VarEnv+import Outputable+import TcSMonad as TcS+import BasicTypes( SwapFlag(..) )++import Util+import Bag+import Pair+import Control.Monad+import MonadUtils ( zipWithAndUnzipM )+import GHC.Exts ( inline )++import Control.Arrow ( first )++{-+Note [The flattening story]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* A CFunEqCan is either of form+ [G] <F xis> : F xis ~ fsk -- fsk is a FlatSkol+ [W] x : F xis ~ fmv -- fmv is a unification variable,+ -- but untouchable,+ -- with MetaInfo = FlatMetaTv+ where+ x is the witness variable+ fsk/fmv is a flatten skolem+ xis are function-free+ CFunEqCans are always [Wanted], or [Given], never [Derived]++ fmv untouchable just means that in a CTyVarEq, say,+ fmv ~ Int+ we do NOT unify fmv.++* KEY INSIGHTS:++ - A given flatten-skolem, fsk, is known a-priori to be equal to+ F xis (the LHS), with <F xis> evidence++ - A unification flatten-skolem, fmv, stands for the as-yet-unknown+ type to which (F xis) will eventually reduce++* Inert set invariant: if F xis1 ~ fsk1, F xis2 ~ fsk2+ then xis1 /= xis2+ i.e. at most one CFunEqCan with a particular LHS++* Each canonical [G], [W], or [WD] CFunEqCan x : F xis ~ fsk/fmv+ has its own distinct evidence variable x and flatten-skolem fsk/fmv.+ Why? We make a fresh fsk/fmv when the constraint is born;+ and we never rewrite the RHS of a CFunEqCan.++ In contrast a [D] CFunEqCan shares its fmv with its partner [W],+ but does not "own" it. If we reduce a [D] F Int ~ fmv, where+ say type instance F Int = ty, then we don't discharge fmv := ty.+ Rather we simply generate [D] fmv ~ ty++* Function applications can occur in the RHS of a CTyEqCan. No reason+ not allow this, and it reduces the amount of flattening that must occur.++* Flattening a type (F xis):+ - If we are flattening in a Wanted/Derived constraint+ then create new [W] x : F xis ~ fmv+ else create new [G] x : F xis ~ fsk+ with fresh evidence variable x and flatten-skolem fsk/fmv++ - Add it to the work list++ - Replace (F xis) with fsk/fmv in the type you are flattening++ - You can also add the CFunEqCan to the "flat cache", which+ simply keeps track of all the function applications you+ have flattened.++ - If (F xis) is in the cache already, just+ use its fsk/fmv and evidence x, and emit nothing.++ - No need to substitute in the flat-cache. It's not the end+ of the world if we start with, say (F alpha ~ fmv1) and+ (F Int ~ fmv2) and then find alpha := Int. Athat will+ simply give rise to fmv1 := fmv2 via [Interacting rule] below++* Canonicalising a CFunEqCan [G/W] x : F xis ~ fsk/fmv+ - Flatten xis (to substitute any tyvars; there are already no functions)+ cos :: xis ~ flat_xis+ - New wanted x2 :: F flat_xis ~ fsk/fmv+ - Add new wanted to flat cache+ - Discharge x = F cos ; x2++* Unification flatten-skolems, fmv, ONLY get unified when either+ a) The CFunEqCan takes a step, using an axiom+ b) During un-flattening+ They are never unified in any other form of equality.+ For example [W] ffmv ~ Int is stuck; it does not unify with fmv.++* We *never* substitute in the RHS (i.e. the fsk/fmv) of a CFunEqCan.+ That would destroy the invariant about the shape of a CFunEqCan,+ and it would risk wanted/wanted interactions. The only way we+ learn information about fsk is when the CFunEqCan takes a step.++ However we *do* substitute in the LHS of a CFunEqCan (else it+ would never get to fire!)++* [Interacting rule]+ (inert) [W] x1 : F tys ~ fmv1+ (work item) [W] x2 : F tys ~ fmv2+ Just solve one from the other:+ x2 := x1+ fmv2 := fmv1+ This just unites the two fsks into one.+ Always solve given from wanted if poss.++* For top-level reductions, see Note [Top-level reductions for type functions]+ in TcInteract+++Why given-fsks, alone, doesn't work+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Could we get away with only flatten meta-tyvars, with no flatten-skolems? No.++ [W] w : alpha ~ [F alpha Int]++---> flatten+ w = ...w'...+ [W] w' : alpha ~ [fsk]+ [G] <F alpha Int> : F alpha Int ~ fsk++--> unify (no occurs check)+ alpha := [fsk]++But since fsk = F alpha Int, this is really an occurs check error. If+that is all we know about alpha, we will succeed in constraint+solving, producing a program with an infinite type.++Even if we did finally get (g : fsk ~ Bool) by solving (F alpha Int ~ fsk)+using axiom, zonking would not see it, so (x::alpha) sitting in the+tree will get zonked to an infinite type. (Zonking always only does+refl stuff.)++Why flatten-meta-vars, alone doesn't work+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Look at Simple13, with unification-fmvs only++ [G] g : a ~ [F a]++---> Flatten given+ g' = g;[x]+ [G] g' : a ~ [fmv]+ [W] x : F a ~ fmv++--> subst a in x+ g' = g;[x]+ x = F g' ; x2+ [W] x2 : F [fmv] ~ fmv++And now we have an evidence cycle between g' and x!++If we used a given instead (ie current story)++ [G] g : a ~ [F a]++---> Flatten given+ g' = g;[x]+ [G] g' : a ~ [fsk]+ [G] <F a> : F a ~ fsk++---> Substitute for a+ [G] g' : a ~ [fsk]+ [G] F (sym g'); <F a> : F [fsk] ~ fsk+++Why is it right to treat fmv's differently to ordinary unification vars?+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ f :: forall a. a -> a -> Bool+ g :: F Int -> F Int -> Bool++Consider+ f (x:Int) (y:Bool)+This gives alpha~Int, alpha~Bool. There is an inconsistency,+but really only one error. SherLoc may tell you which location+is most likely, based on other occurrences of alpha.++Consider+ g (x:Int) (y:Bool)+Here we get (F Int ~ Int, F Int ~ Bool), which flattens to+ (fmv ~ Int, fmv ~ Bool)+But there are really TWO separate errors.++ ** We must not complain about Int~Bool. **++Moreover these two errors could arise in entirely unrelated parts of+the code. (In the alpha case, there must be *some* connection (eg+v:alpha in common envt).)++Note [Unflattening can force the solver to iterate]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Look at Trac #10340:+ type family Any :: * -- No instances+ get :: MonadState s m => m s+ instance MonadState s (State s) where ...++ foo :: State Any Any+ foo = get++For 'foo' we instantiate 'get' at types mm ss+ [WD] MonadState ss mm, [WD] mm ss ~ State Any Any+Flatten, and decompose+ [WD] MonadState ss mm, [WD] Any ~ fmv+ [WD] mm ~ State fmv, [WD] fmv ~ ss+Unify mm := State fmv:+ [WD] MonadState ss (State fmv)+ [WD] Any ~ fmv, [WD] fmv ~ ss+Now we are stuck; the instance does not match!! So unflatten:+ fmv := Any+ ss := Any (*)+ [WD] MonadState Any (State Any)++The unification (*) represents progress, so we must do a second+round of solving; this time it succeeds. This is done by the 'go'+loop in solveSimpleWanteds.++This story does not feel right but it's the best I can do; and the+iteration only happens in pretty obscure circumstances.+++************************************************************************+* *+* Examples+ Here is a long series of examples I had to work through+* *+************************************************************************++Simple20+~~~~~~~~+axiom F [a] = [F a]++ [G] F [a] ~ a+-->+ [G] fsk ~ a+ [G] [F a] ~ fsk (nc)+-->+ [G] F a ~ fsk2+ [G] fsk ~ [fsk2]+ [G] fsk ~ a+-->+ [G] F a ~ fsk2+ [G] a ~ [fsk2]+ [G] fsk ~ a++----------------------------------------+indexed-types/should_compile/T44984++ [W] H (F Bool) ~ H alpha+ [W] alpha ~ F Bool+-->+ F Bool ~ fmv0+ H fmv0 ~ fmv1+ H alpha ~ fmv2++ fmv1 ~ fmv2+ fmv0 ~ alpha++flatten+~~~~~~~+ fmv0 := F Bool+ fmv1 := H (F Bool)+ fmv2 := H alpha+ alpha := F Bool+plus+ fmv1 ~ fmv2++But these two are equal under the above assumptions.+Solve by Refl.+++--- under plan B, namely solve fmv1:=fmv2 eagerly ---+ [W] H (F Bool) ~ H alpha+ [W] alpha ~ F Bool+-->+ F Bool ~ fmv0+ H fmv0 ~ fmv1+ H alpha ~ fmv2++ fmv1 ~ fmv2+ fmv0 ~ alpha+-->+ F Bool ~ fmv0+ H fmv0 ~ fmv1+ H alpha ~ fmv2 fmv2 := fmv1++ fmv0 ~ alpha++flatten+ fmv0 := F Bool+ fmv1 := H fmv0 = H (F Bool)+ retain H alpha ~ fmv2+ because fmv2 has been filled+ alpha := F Bool+++----------------------------+indexed-types/should_failt/T4179++after solving+ [W] fmv_1 ~ fmv_2+ [W] A3 (FCon x) ~ fmv_1 (CFunEqCan)+ [W] A3 (x (aoa -> fmv_2)) ~ fmv_2 (CFunEqCan)++----------------------------------------+indexed-types/should_fail/T7729a++a) [W] BasePrimMonad (Rand m) ~ m1+b) [W] tt m1 ~ BasePrimMonad (Rand m)++---> process (b) first+ BasePrimMonad (Ramd m) ~ fmv_atH+ fmv_atH ~ tt m1++---> now process (a)+ m1 ~ s_atH ~ tt m1 -- An obscure occurs check+++----------------------------------------+typecheck/TcTypeNatSimple++Original constraint+ [W] x + y ~ x + alpha (non-canonical)+==>+ [W] x + y ~ fmv1 (CFunEqCan)+ [W] x + alpha ~ fmv2 (CFuneqCan)+ [W] fmv1 ~ fmv2 (CTyEqCan)++(sigh)++----------------------------------------+indexed-types/should_fail/GADTwrong1++ [G] Const a ~ ()+==> flatten+ [G] fsk ~ ()+ work item: Const a ~ fsk+==> fire top rule+ [G] fsk ~ ()+ work item fsk ~ ()++Surely the work item should rewrite to () ~ ()? Well, maybe not;+it'a very special case. More generally, our givens look like+F a ~ Int, where (F a) is not reducible.+++----------------------------------------+indexed_types/should_fail/T8227:++Why using a different can-rewrite rule in CFunEqCan heads+does not work.++Assuming NOT rewriting wanteds with wanteds++ Inert: [W] fsk_aBh ~ fmv_aBk -> fmv_aBk+ [W] fmv_aBk ~ fsk_aBh++ [G] Scalar fsk_aBg ~ fsk_aBh+ [G] V a ~ f_aBg++ Worklist includes [W] Scalar fmv_aBi ~ fmv_aBk+ fmv_aBi, fmv_aBk are flatten unification variables++ Work item: [W] V fsk_aBh ~ fmv_aBi++Note that the inert wanteds are cyclic, because we do not rewrite+wanteds with wanteds.+++Then we go into a loop when normalise the work-item, because we+use rewriteOrSame on the argument of V.++Conclusion: Don't make canRewrite context specific; instead use+[W] a ~ ty to rewrite a wanted iff 'a' is a unification variable.+++----------------------------------------++Here is a somewhat similar case:++ type family G a :: *++ blah :: (G a ~ Bool, Eq (G a)) => a -> a+ blah = error "urk"++ foo x = blah x++For foo we get+ [W] Eq (G a), G a ~ Bool+Flattening+ [W] G a ~ fmv, Eq fmv, fmv ~ Bool+We can't simplify away the Eq Bool unless we substitute for fmv.+Maybe that doesn't matter: we would still be left with unsolved+G a ~ Bool.++--------------------------+Trac #9318 has a very simple program leading to++ [W] F Int ~ Int+ [W] F Int ~ Bool++We don't want to get "Error Int~Bool". But if fmv's can rewrite+wanteds, we will++ [W] fmv ~ Int+ [W] fmv ~ Bool+--->+ [W] Int ~ Bool+++************************************************************************+* *+* FlattenEnv & FlatM+* The flattening environment & monad+* *+************************************************************************++-}++type FlatWorkListRef = TcRef [Ct] -- See Note [The flattening work list]++data FlattenEnv+ = FE { fe_mode :: FlattenMode+ , fe_loc :: CtLoc -- See Note [Flattener CtLoc]+ , fe_flavour :: CtFlavour+ , fe_eq_rel :: EqRel -- See Note [Flattener EqRels]+ , fe_work :: FlatWorkListRef } -- See Note [The flattening work list]++data FlattenMode -- Postcondition for all three: inert wrt the type substitution+ = FM_FlattenAll -- Postcondition: function-free+ | FM_SubstOnly -- See Note [Flattening under a forall]++-- | FM_Avoid TcTyVar Bool -- See Note [Lazy flattening]+-- -- Postcondition:+-- -- * tyvar is only mentioned in result under a rigid path+-- -- e.g. [a] is ok, but F a won't happen+-- -- * If flat_top is True, top level is not a function application+-- -- (but under type constructors is ok e.g. [F a])++instance Outputable FlattenMode where+ ppr FM_FlattenAll = text "FM_FlattenAll"+ ppr FM_SubstOnly = text "FM_SubstOnly"++eqFlattenMode :: FlattenMode -> FlattenMode -> Bool+eqFlattenMode FM_FlattenAll FM_FlattenAll = True+eqFlattenMode FM_SubstOnly FM_SubstOnly = True+-- FM_Avoid tv1 b1 `eq` FM_Avoid tv2 b2 = tv1 == tv2 && b1 == b2+eqFlattenMode _ _ = False++mkFlattenEnv :: FlattenMode -> CtEvidence -> FlatWorkListRef -> FlattenEnv+mkFlattenEnv fm ctev ref = FE { fe_mode = fm+ , fe_loc = ctEvLoc ctev+ , fe_flavour = ctEvFlavour ctev+ , fe_eq_rel = ctEvEqRel ctev+ , fe_work = ref }++-- | The 'FlatM' monad is a wrapper around 'TcS' with the following+-- extra capabilities: (1) it offers access to a 'FlattenEnv';+-- and (2) it maintains the flattening worklist.+-- See Note [The flattening work list].+newtype FlatM a+ = FlatM { runFlatM :: FlattenEnv -> TcS a }++instance Monad FlatM where+ m >>= k = FlatM $ \env ->+ do { a <- runFlatM m env+ ; runFlatM (k a) env }++instance Functor FlatM where+ fmap = liftM++instance Applicative FlatM where+ pure x = FlatM $ const (pure x)+ (<*>) = ap++liftTcS :: TcS a -> FlatM a+liftTcS thing_inside+ = FlatM $ const thing_inside++emitFlatWork :: Ct -> FlatM ()+-- See Note [The flattening work list]+emitFlatWork ct = FlatM $ \env -> updTcRef (fe_work env) (ct :)++runFlatten :: FlattenMode -> CtEvidence -> FlatM a -> TcS a+-- Run thing_inside (which does flattening), and put all+-- the work it generates onto the main work list+-- See Note [The flattening work list]+-- NB: The returned evidence is always the same as the original, but with+-- perhaps a new CtLoc+runFlatten mode ev thing_inside+ = do { flat_ref <- newTcRef []+ ; let fmode = mkFlattenEnv mode ev flat_ref+ ; res <- runFlatM thing_inside fmode+ ; new_flats <- readTcRef flat_ref+ ; updWorkListTcS (add_flats new_flats)+ ; return res }+ where+ add_flats new_flats wl+ = wl { wl_funeqs = add_funeqs new_flats (wl_funeqs wl) }++ add_funeqs [] wl = wl+ add_funeqs (f:fs) wl = add_funeqs fs (f:wl)+ -- add_funeqs fs ws = reverse fs ++ ws+ -- e.g. add_funeqs [f1,f2,f3] [w1,w2,w3,w4]+ -- = [f3,f2,f1,w1,w2,w3,w4]++traceFlat :: String -> SDoc -> FlatM ()+traceFlat herald doc = liftTcS $ traceTcS herald doc++getFlatEnvField :: (FlattenEnv -> a) -> FlatM a+getFlatEnvField accessor+ = FlatM $ \env -> return (accessor env)++getEqRel :: FlatM EqRel+getEqRel = getFlatEnvField fe_eq_rel++getRole :: FlatM Role+getRole = eqRelRole <$> getEqRel++getFlavour :: FlatM CtFlavour+getFlavour = getFlatEnvField fe_flavour++getFlavourRole :: FlatM CtFlavourRole+getFlavourRole+ = do { flavour <- getFlavour+ ; eq_rel <- getEqRel+ ; return (flavour, eq_rel) }++getMode :: FlatM FlattenMode+getMode = getFlatEnvField fe_mode++getLoc :: FlatM CtLoc+getLoc = getFlatEnvField fe_loc++checkStackDepth :: Type -> FlatM ()+checkStackDepth ty+ = do { loc <- getLoc+ ; liftTcS $ checkReductionDepth loc ty }++-- | Change the 'EqRel' in a 'FlatM'.+setEqRel :: EqRel -> FlatM a -> FlatM a+setEqRel new_eq_rel thing_inside+ = FlatM $ \env ->+ if new_eq_rel == fe_eq_rel env+ then runFlatM thing_inside env+ else runFlatM thing_inside (env { fe_eq_rel = new_eq_rel })++-- | Change the 'FlattenMode' in a 'FlattenEnv'.+setMode :: FlattenMode -> FlatM a -> FlatM a+setMode new_mode thing_inside+ = FlatM $ \env ->+ if new_mode `eqFlattenMode` fe_mode env+ then runFlatM thing_inside env+ else runFlatM thing_inside (env { fe_mode = new_mode })++-- | Use when flattening kinds/kind coercions. See+-- Note [No derived kind equalities] in TcCanonical+flattenKinds :: FlatM a -> FlatM a+flattenKinds thing_inside+ = FlatM $ \env ->+ let kind_flav = case fe_flavour env of+ Given -> Given+ _ -> Wanted WDeriv+ in+ runFlatM thing_inside (env { fe_eq_rel = NomEq, fe_flavour = kind_flav })++bumpDepth :: FlatM a -> FlatM a+bumpDepth (FlatM thing_inside)+ = FlatM $ \env -> do { let env' = env { fe_loc = bumpCtLocDepth (fe_loc env) }+ ; thing_inside env' }++{-+Note [The flattening work list]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The "flattening work list", held in the fe_work field of FlattenEnv,+is a list of CFunEqCans generated during flattening. The key idea+is this. Consider flattening (Eq (F (G Int) (H Bool)):+ * The flattener recursively calls itself on sub-terms before building+ the main term, so it will encounter the terms in order+ G Int+ H Bool+ F (G Int) (H Bool)+ flattening to sub-goals+ w1: G Int ~ fuv0+ w2: H Bool ~ fuv1+ w3: F fuv0 fuv1 ~ fuv2++ * Processing w3 first is BAD, because we can't reduce i t,so it'll+ get put into the inert set, and later kicked out when w1, w2 are+ solved. In Trac #9872 this led to inert sets containing hundreds+ of suspended calls.++ * So we want to process w1, w2 first.++ * So you might think that we should just use a FIFO deque for the work-list,+ so that putting adding goals in order w1,w2,w3 would mean we processed+ w1 first.++ * BUT suppose we have 'type instance G Int = H Char'. Then processing+ w1 leads to a new goal+ w4: H Char ~ fuv0+ We do NOT want to put that on the far end of a deque! Instead we want+ to put it at the *front* of the work-list so that we continue to work+ on it.++So the work-list structure is this:++ * The wl_funeqs (in TcS) is a LIFO stack; we push new goals (such as w4) on+ top (extendWorkListFunEq), and take new work from the top+ (selectWorkItem).++ * When flattening, emitFlatWork pushes new flattening goals (like+ w1,w2,w3) onto the flattening work list, fe_work, another+ push-down stack.++ * When we finish flattening, we *reverse* the fe_work stack+ onto the wl_funeqs stack (which brings w1 to the top).++The function runFlatten initialises the fe_work stack, and reverses+it onto wl_fun_eqs at the end.++Note [Flattener EqRels]+~~~~~~~~~~~~~~~~~~~~~~~+When flattening, we need to know which equality relation -- nominal+or representation -- we should be respecting. The only difference is+that we rewrite variables by representational equalities when fe_eq_rel+is ReprEq, and that we unwrap newtypes when flattening w.r.t.+representational equality.++Note [Flattener CtLoc]+~~~~~~~~~~~~~~~~~~~~~~+The flattener does eager type-family reduction.+Type families might loop, and we+don't want GHC to do so. A natural solution is to have a bounded depth+to these processes. A central difficulty is that such a solution isn't+quite compositional. For example, say it takes F Int 10 steps to get to Bool.+How many steps does it take to get from F Int -> F Int to Bool -> Bool?+10? 20? What about getting from Const Char (F Int) to Char? 11? 1? Hard to+know and hard to track. So, we punt, essentially. We store a CtLoc in+the FlattenEnv and just update the environment when recurring. In the+TyConApp case, where there may be multiple type families to flatten,+we just copy the current CtLoc into each branch. If any branch hits the+stack limit, then the whole thing fails.++A consequence of this is that setting the stack limits appropriately+will be essentially impossible. So, the official recommendation if a+stack limit is hit is to disable the check entirely. Otherwise, there+will be baffling, unpredictable errors.++Note [Lazy flattening]+~~~~~~~~~~~~~~~~~~~~~~+The idea of FM_Avoid mode is to flatten less aggressively. If we have+ a ~ [F Int]+there seems to be no great merit in lifting out (F Int). But if it was+ a ~ [G a Int]+then we *do* want to lift it out, in case (G a Int) reduces to Bool, say,+which gets rid of the occurs-check problem. (For the flat_top Bool, see+comments above and at call sites.)++HOWEVER, the lazy flattening actually seems to make type inference go+*slower*, not faster. perf/compiler/T3064 is a case in point; it gets+*dramatically* worse with FM_Avoid. I think it may be because+floating the types out means we normalise them, and that often makes+them smaller and perhaps allows more re-use of previously solved+goals. But to be honest I'm not absolutely certain, so I am leaving+FM_Avoid in the code base. What I'm removing is the unique place+where it is *used*, namely in TcCanonical.canEqTyVar.++See also Note [Conservative unification check] in TcUnify, which gives+other examples where lazy flattening caused problems.++Bottom line: FM_Avoid is unused for now (Nov 14).+Note: T5321Fun got faster when I disabled FM_Avoid+ T5837 did too, but it's pathalogical anyway++Note [Phantoms in the flattener]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have++data Proxy p = Proxy++and we're flattening (Proxy ty) w.r.t. ReprEq. Then, we know that `ty`+is really irrelevant -- it will be ignored when solving for representational+equality later on. So, we omit flattening `ty` entirely. This may+violate the expectation of "xi"s for a bit, but the canonicaliser will+soon throw out the phantoms when decomposing a TyConApp. (Or, the+canonicaliser will emit an insoluble, in which case the unflattened version+yields a better error message anyway.)++-}++{- *********************************************************************+* *+* Externally callable flattening functions *+* *+* They are all wrapped in runFlatten, so their *+* flattening work gets put into the work list *+* *+********************************************************************* -}++flatten :: FlattenMode -> CtEvidence -> TcType+ -> TcS (Xi, TcCoercion)+flatten mode ev ty+ = do { traceTcS "flatten {" (ppr mode <+> ppr ty)+ ; (ty', co) <- runFlatten mode ev (flatten_one ty)+ ; traceTcS "flatten }" (ppr ty')+ ; return (ty', co) }++flattenManyNom :: CtEvidence -> [TcType] -> TcS ([Xi], [TcCoercion])+-- Externally-callable, hence runFlatten+-- Flatten a bunch of types all at once; in fact they are+-- always the arguments of a saturated type-family, so+-- ctEvFlavour ev = Nominal+-- and we want to flatten all at nominal role+flattenManyNom ev tys+ = do { traceTcS "flatten_many {" (vcat (map ppr tys))+ ; (tys', cos) <- runFlatten FM_FlattenAll ev (flatten_many_nom tys)+ ; traceTcS "flatten }" (vcat (map ppr tys'))+ ; return (tys', cos) }+++{- *********************************************************************+* *+* The main flattening functions+* *+********************************************************************* -}++{- Note [Flattening]+~~~~~~~~~~~~~~~~~~~~+ flatten ty ==> (xi, co)+ where+ xi has no type functions, unless they appear under ForAlls+ has no skolems that are mapped in the inert set+ has no filled-in metavariables+ co :: xi ~ ty++Note that it is flatten's job to flatten *every type function it sees*.+flatten is only called on *arguments* to type functions, by canEqGiven.++Flattening also:+ * zonks, removing any metavariables, and+ * applies the substitution embodied in the inert set++Because flattening zonks and the returned coercion ("co" above) is also+zonked, it's possible that (co :: xi ~ ty) isn't quite true. So, instead,+we can rely on these facts:+ (F1) typeKind(xi) succeeds and returns a fully zonked kind+ (F2) co :: xi ~ zonk(ty)+Note that the left-hand type of co is *always* precisely xi. The right-hand+type may or may not be ty, however: if ty has unzonked filled-in metavariables,+then the right-hand type of co will be the zonked version of ty.+It is for this reason that we+occasionally have to explicitly zonk, when (co :: xi ~ ty) is important+even before we zonk the whole program. For example, see the FTRNotFollowed+case in flattenTyVar.++Why have these invariants on flattening? Really, they're both to ensure+invariant (F1), which is a Good Thing because we sometimes use typeKind+during canonicalisation, and we want this kind to be zonked (e.g., see+TcCanonical.homogeniseRhsKind). Invariant (F2) is needed solely to support+(F1). It is relied on in one place:++ - The FTRNotFollowed case in flattenTyVar. Here, we have a tyvar+ that cannot be reduced any further (that is, no equality over the tyvar+ is in the inert set such that the inert equality can rewrite the constraint+ at hand, and it is not a filled-in metavariable).+ But its kind might still not be flat,+ if it mentions a type family or a variable that can be rewritten. Flattened+ types have flattened kinds (see below), so we must flatten the kind. Here is+ an example:++ let kappa be a filled-in metavariable such that kappa := k.+ [G] co :: k ~ Type++ We are flattening+ a :: kappa+ where a is a skolem.++ We end up in the FTRNotFollowed case, but we need to flatten the kind kappa.+ Flattening kappa yields (Type, kind_co), where kind_co :: Type ~ k. Note that the+ right-hand type of kind_co is *not* kappa, because (F1) tells us it's zonk(kappa),+ which is k. Now, we return (a |> sym kind_co). If we are to uphold (F1), then+ the right-hand type of (sym kind_co) had better be fully zonked. In other words,+ the left-hand type of kind_co needs to be zonked... which is precisely what (F2)+ guarantees.++In order to support (F2), we require that ctEvCoercion, when called on a+zonked CtEvidence, always returns a zonked coercion. See Note [Given in+ctEvCoercion]. This requirement comes into play in flatten_tyvar2. (I suppose+we could move the logic from ctEvCoercion to flatten_tyvar2, but it's much+easier to do in ctEvCoercion.)++Flattening a type also means flattening its kind. In the case of a type+variable whose kind mentions a type family, this might mean that the result+of flattening has a cast in it.++Recall that in comments we use alpha[flat = ty] to represent a+flattening skolem variable alpha which has been generated to stand in+for ty.++----- Example of flattening a constraint: ------+ flatten (List (F (G Int))) ==> (xi, cc)+ where+ xi = List alpha+ cc = { G Int ~ beta[flat = G Int],+ F beta ~ alpha[flat = F beta] }+Here+ * alpha and beta are 'flattening skolem variables'.+ * All the constraints in cc are 'given', and all their coercion terms+ are the identity.++NB: Flattening Skolems only occur in canonical constraints, which+are never zonked, so we don't need to worry about zonking doing+accidental unflattening.++Note that we prefer to leave type synonyms unexpanded when possible,+so when the flattener encounters one, it first asks whether its+transitive expansion contains any type function applications. If so,+it expands the synonym and proceeds; if not, it simply returns the+unexpanded synonym.++Note [flatten_many performance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In programs with lots of type-level evaluation, flatten_many becomes+part of a tight loop. For example, see test perf/compiler/T9872a, which+calls flatten_many a whopping 7,106,808 times. It is thus important+that flatten_many be efficient.++Performance testing showed that the current implementation is indeed+efficient. It's critically important that zipWithAndUnzipM be+specialized to TcS, and it's also quite helpful to actually `inline`+it. On test T9872a, here are the allocation stats (Dec 16, 2014):++ * Unspecialized, uninlined: 8,472,613,440 bytes allocated in the heap+ * Specialized, uninlined: 6,639,253,488 bytes allocated in the heap+ * Specialized, inlined: 6,281,539,792 bytes allocated in the heap++To improve performance even further, flatten_many_nom is split off+from flatten_many, as nominal equality is the common case. This would+be natural to write using mapAndUnzipM, but even inlined, that function+is not as performant as a hand-written loop.++ * mapAndUnzipM, inlined: 7,463,047,432 bytes allocated in the heap+ * hand-written recursion: 5,848,602,848 bytes allocated in the heap++If you make any change here, pay close attention to the T9872{a,b,c} tests+and T5321Fun.++If we need to make this yet more performant, a possible way forward is to+duplicate the flattener code for the nominal case, and make that case+faster. This doesn't seem quite worth it, yet.+-}++flatten_many :: [Role] -> [Type] -> FlatM ([Xi], [Coercion])+-- Coercions :: Xi ~ Type, at roles given+-- Returns True iff (no flattening happened)+-- NB: The EvVar inside the 'fe_ev :: CtEvidence' is unused,+-- we merely want (a) Given/Solved/Derived/Wanted info+-- (b) the GivenLoc/WantedLoc for when we create new evidence+flatten_many roles tys+-- See Note [flatten_many performance]+ = inline zipWithAndUnzipM go roles tys+ where+ go Nominal ty = setEqRel NomEq $ flatten_one ty+ go Representational ty = setEqRel ReprEq $ flatten_one ty+ go Phantom ty = -- See Note [Phantoms in the flattener]+ do { ty <- liftTcS $ zonkTcType ty+ ; return ( ty, mkReflCo Phantom ty ) }++-- | Like 'flatten_many', but assumes that every role is nominal.+flatten_many_nom :: [Type] -> FlatM ([Xi], [Coercion])+flatten_many_nom [] = return ([], [])+-- See Note [flatten_many performance]+flatten_many_nom (ty:tys)+ = do { (xi, co) <- flatten_one ty+ ; (xis, cos) <- flatten_many_nom tys+ ; return (xi:xis, co:cos) }+------------------+flatten_one :: TcType -> FlatM (Xi, Coercion)+-- Flatten a type to get rid of type function applications, returning+-- the new type-function-free type, and a collection of new equality+-- constraints. See Note [Flattening] for more detail.+--+-- Postcondition: Coercion :: Xi ~ TcType+-- The role on the result coercion matches the EqRel in the FlattenEnv++flatten_one xi@(LitTy {})+ = do { role <- getRole+ ; return (xi, mkReflCo role xi) }++flatten_one (TyVarTy tv)+ = flattenTyVar tv++flatten_one (AppTy ty1 ty2)+ = do { (xi1,co1) <- flatten_one ty1+ ; eq_rel <- getEqRel+ ; case (eq_rel, nextRole xi1) of+ (NomEq, _) -> flatten_rhs xi1 co1 NomEq+ (ReprEq, Nominal) -> flatten_rhs xi1 co1 NomEq+ (ReprEq, Representational) -> flatten_rhs xi1 co1 ReprEq+ (ReprEq, Phantom) -> -- See Note [Phantoms in the flattener]+ do { ty2 <- liftTcS $ zonkTcType ty2+ ; return ( mkAppTy xi1 ty2+ , mkAppCo co1 (mkNomReflCo ty2)) } }+ where+ flatten_rhs xi1 co1 eq_rel2+ = do { (xi2,co2) <- setEqRel eq_rel2 $ flatten_one ty2+ ; role1 <- getRole+ ; let role2 = eqRelRole eq_rel2+ ; traceFlat "flatten/appty"+ (ppr ty1 $$ ppr ty2 $$ ppr xi1 $$+ ppr xi2 $$ ppr role1 $$ ppr role2)++ ; return ( mkAppTy xi1 xi2+ , mkTransAppCo role1 co1 xi1 ty1+ role2 co2 xi2 ty2+ role1 ) } -- output should match fmode++flatten_one (TyConApp tc tys)+ -- Expand type synonyms that mention type families+ -- on the RHS; see Note [Flattening synonyms]+ | Just (tenv, rhs, tys') <- expandSynTyCon_maybe tc tys+ , let expanded_ty = mkAppTys (substTy (mkTvSubstPrs tenv) rhs) tys'+ = do { mode <- getMode+ ; case mode of+ FM_FlattenAll | not (isFamFreeTyCon tc)+ -> flatten_one expanded_ty+ _ -> flatten_ty_con_app tc tys }++ -- Otherwise, it's a type function application, and we have to+ -- flatten it away as well, and generate a new given equality constraint+ -- between the application and a newly generated flattening skolem variable.+ | isTypeFamilyTyCon tc+ = flatten_fam_app tc tys++ -- For * a normal data type application+ -- * data family application+ -- we just recursively flatten the arguments.+ | otherwise+-- FM_Avoid stuff commented out; see Note [Lazy flattening]+-- , let fmode' = case fmode of -- Switch off the flat_top bit in FM_Avoid+-- FE { fe_mode = FM_Avoid tv _ }+-- -> fmode { fe_mode = FM_Avoid tv False }+-- _ -> fmode+ = flatten_ty_con_app tc tys++flatten_one (FunTy ty1 ty2)+ = do { (xi1,co1) <- flatten_one ty1+ ; (xi2,co2) <- flatten_one ty2+ ; role <- getRole+ ; return (mkFunTy xi1 xi2, mkFunCo role co1 co2) }++flatten_one ty@(ForAllTy {})+-- TODO (RAE): This is inadequate, as it doesn't flatten the kind of+-- the bound tyvar. Doing so will require carrying around a substitution+-- and the usual substTyVarBndr-like silliness. Argh.++-- We allow for-alls when, but only when, no type function+-- applications inside the forall involve the bound type variables.+ = do { let (bndrs, rho) = splitForAllTyVarBndrs ty+ tvs = binderVars bndrs+ ; (rho', co) <- setMode FM_SubstOnly $ flatten_one rho+ -- Substitute only under a forall+ -- See Note [Flattening under a forall]+ ; return (mkForAllTys bndrs rho', mkHomoForAllCos tvs co) }++flatten_one (CastTy ty g)+ = do { (xi, co) <- flatten_one ty+ ; (g', _) <- flatten_co g++ ; return (mkCastTy xi g', castCoercionKind co g' g) }++flatten_one (CoercionTy co) = first mkCoercionTy <$> flatten_co co++-- | "Flatten" a coercion. Really, just flatten the types that it coerces+-- between and then use transitivity. See Note [Flattening coercions]+flatten_co :: Coercion -> FlatM (Coercion, Coercion)+flatten_co co+ = do { co <- liftTcS $ zonkCo co -- see Note [Zonking when flattening a coercion]+ ; let (Pair ty1 ty2, role) = coercionKindRole co+ ; (co1, co2) <- flattenKinds $+ do { (_, co1) <- flatten_one ty1+ ; (_, co2) <- flatten_one ty2+ ; return (co1, co2) }+ ; let co' = downgradeRole role Nominal co1 `mkTransCo`+ co `mkTransCo`+ mkSymCo (downgradeRole role Nominal co2)+ -- kco :: (ty1' ~r ty2') ~N (ty1 ~r ty2)+ kco = mkTyConAppCo Nominal (equalityTyCon role)+ [ mkKindCo co1, mkKindCo co2, co1, co2 ]+ ; traceFlat "flatten_co" (vcat [ ppr co, ppr co1, ppr co2, ppr co' ])+ ; env_role <- getRole+ ; return (co', mkProofIrrelCo env_role kco co' co) }++flatten_ty_con_app :: TyCon -> [TcType] -> FlatM (Xi, Coercion)+flatten_ty_con_app tc tys+ = do { eq_rel <- getEqRel+ ; let role = eqRelRole eq_rel+ ; (xis, cos) <- case eq_rel of+ NomEq -> flatten_many_nom tys+ ReprEq -> flatten_many (tyConRolesRepresentational tc) tys+ ; return (mkTyConApp tc xis, mkTyConAppCo role tc cos) }++{-+Note [Flattening coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because a flattened type has a flattened kind, we also must "flatten"+coercions as we walk through a type. Otherwise, the "from" type of+the coercion might not match the (now flattened) kind of the type+that it's casting. flatten_co does the work, taking a coercion of+type (ty1 ~ ty2) and flattening it to have type (fty1 ~ fty2),+where flatten(ty1) = fty1 and flatten(ty2) = fty2.++In other words:++ If r1 is a role+ co :: s ~r1 t+ flatten_co co = (fco, kco)+ r2 is the role in the FlatM++ then+ fco :: fs ~r1 ft+ fs, ft are flattened types+ kco :: fco ~r2 co++The second return value of flatten_co is always a ProofIrrelCo. As+such, it doesn't contain any information the caller doesn't have and+might not be necessary in whatever comes next.++Note that a flattened coercion might have unzonked metavariables or+type functions in it -- but its *kind* will not. Instead of just flattening+the kinds and using mkTransCo, we could actually flatten the coercion+structurally. But doing so seems harder than simply flattening the types.++Note [Zonking when flattening a coercion]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The first step in flatten_co (see Note [Flattening coercions]) is to+zonk the input. This is necessary because we want to ensure the following+invariants (c.f. the invariants (F1) and (F2) in Note [Flattening])+ If+ (co', kco) <- flatten_co co+ Then+ (FC1) coercionKind(co') succeeds and produces a fully zonked pair of kinds+ (FC2) kco :: co' ~ zonk(co)+We must zonk to ensure (1). This is because fco is built by using mkTransCo+to build up on the input co. But if the only action that happens during+flattening ty1 and ty2 is to zonk metavariables, the coercions returned+(co1 and co2) will be reflexive. The mkTransCo calls will drop the reflexive+coercions and co' will be the same as co -- with unzonked kinds.++These invariants are necessary to uphold (F1) and (F2) in the CastTy and+CoercionTy cases.++We zonk right at the beginning to avoid duplicating work when flattening the+ty1 and ty2.++Note [Flattening synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Not expanding synonyms aggressively improves error messages, and+keeps types smaller. But we need to take care.++Suppose+ type T a = a -> a+and we want to flatten the type (T (F a)). Then we can safely flatten+the (F a) to a skolem, and return (T fsk). We don't need to expand the+synonym. This works because TcTyConAppCo can deal with synonyms+(unlike TyConAppCo), see Note [TcCoercions] in TcEvidence.++But (Trac #8979) for+ type T a = (F a, a) where F is a type function+we must expand the synonym in (say) T Int, to expose the type function+to the flattener.+++Note [Flattening under a forall]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Under a forall, we+ (a) MUST apply the inert substitution+ (b) MUST NOT flatten type family applications+Hence FMSubstOnly.++For (a) consider c ~ a, a ~ T (forall b. (b, [c]))+If we don't apply the c~a substitution to the second constraint+we won't see the occurs-check error.++For (b) consider (a ~ forall b. F a b), we don't want to flatten+to (a ~ forall b.fsk, F a b ~ fsk)+because now the 'b' has escaped its scope. We'd have to flatten to+ (a ~ forall b. fsk b, forall b. F a b ~ fsk b)+and we have not begun to think about how to make that work!++************************************************************************+* *+ Flattening a type-family application+* *+************************************************************************+-}++flatten_fam_app :: TyCon -> [TcType] -> FlatM (Xi, Coercion)+ -- flatten_fam_app can be over-saturated+ -- flatten_exact_fam_app is exactly saturated+ -- flatten_exact_fam_app_fully lifts out the application to top level+ -- Postcondition: Coercion :: Xi ~ F tys+flatten_fam_app tc tys -- Can be over-saturated+ = ASSERT2( tyConArity tc <= length tys+ , ppr tc $$ ppr (tyConArity tc) $$ ppr tys)+ -- Type functions are saturated+ -- The type function might be *over* saturated+ -- in which case the remaining arguments should+ -- be dealt with by AppTys+ do { let (tys1, tys_rest) = splitAt (tyConArity tc) tys+ ; (xi1, co1) <- flatten_exact_fam_app tc tys1+ -- co1 :: xi1 ~ F tys1++ -- all Nominal roles b/c the tycon is oversaturated+ ; (xis_rest, cos_rest) <- flatten_many (repeat Nominal) tys_rest+ -- cos_res :: xis_rest ~ tys_rest++ ; return ( mkAppTys xi1 xis_rest -- NB mkAppTys: rhs_xi might not be a type variable+ -- cf Trac #5655+ , mkAppCos co1 cos_rest+ -- (rhs_xi :: F xis) ; (F cos :: F xis ~ F tys)+ ) }++flatten_exact_fam_app, flatten_exact_fam_app_fully ::+ TyCon -> [TcType] -> FlatM (Xi, Coercion)++flatten_exact_fam_app tc tys+ = do { mode <- getMode+ ; role <- getRole+ ; case mode of+ -- These roles are always going to be Nominal for now,+ -- but not if #8177 is implemented+ FM_SubstOnly -> do { let roles = tyConRolesX role tc+ ; (xis, cos) <- flatten_many roles tys+ ; return ( mkTyConApp tc xis+ , mkTyConAppCo role tc cos ) }++ FM_FlattenAll -> flatten_exact_fam_app_fully tc tys }++-- FM_Avoid tv flat_top ->+-- do { (xis, cos) <- flatten_many fmode roles tys+-- ; if flat_top || tv `elemVarSet` tyCoVarsOfTypes xis+-- then flatten_exact_fam_app_fully fmode tc tys+-- else return ( mkTyConApp tc xis+-- , mkTcTyConAppCo (feRole fmode) tc cos ) }++flatten_exact_fam_app_fully tc tys+ -- See Note [Reduce type family applications eagerly]+ = try_to_reduce tc tys False id $+ do { -- First, flatten the arguments+ ; (xis, cos) <- setEqRel NomEq $+ flatten_many_nom tys+ ; eq_rel <- getEqRel+ ; cur_flav <- getFlavour+ ; let role = eqRelRole eq_rel+ ret_co = mkTyConAppCo role tc cos+ -- ret_co :: F xis ~ F tys++ -- Now, look in the cache+ ; mb_ct <- liftTcS $ lookupFlatCache tc xis+ ; case mb_ct of+ Just (co, rhs_ty, flav) -- co :: F xis ~ fsk+ -- flav is [G] or [WD]+ -- See Note [Type family equations] in TcSMonad+ | (NotSwapped, _) <- flav `funEqCanDischargeF` cur_flav+ -> -- Usable hit in the flat-cache+ do { traceFlat "flatten/flat-cache hit" $ (ppr tc <+> ppr xis $$ ppr rhs_ty)+ ; (fsk_xi, fsk_co) <- flatten_one rhs_ty+ -- The fsk may already have been unified, so flatten it+ -- fsk_co :: fsk_xi ~ fsk+ ; return ( fsk_xi+ , fsk_co `mkTransCo`+ maybeSubCo eq_rel (mkSymCo co) `mkTransCo`+ ret_co ) }+ -- :: fsk_xi ~ F xis++ -- Try to reduce the family application right now+ -- See Note [Reduce type family applications eagerly]+ _ -> try_to_reduce tc xis True (`mkTransCo` ret_co) $+ do { loc <- getLoc+ ; (ev, co, fsk) <- liftTcS $ newFlattenSkolem cur_flav loc tc xis++ -- The new constraint (F xis ~ fsk) is not necessarily inert+ -- (e.g. the LHS may be a redex) so we must put it in the work list+ ; let ct = CFunEqCan { cc_ev = ev+ , cc_fun = tc+ , cc_tyargs = xis+ , cc_fsk = fsk }+ ; emitFlatWork ct++ ; traceFlat "flatten/flat-cache miss" $+ (ppr tc <+> ppr xis $$ ppr fsk $$ ppr ev)++ -- NB: fsk's kind is already flattend because+ -- the xis are flattened+ ; return (mkTyVarTy fsk, maybeSubCo eq_rel (mkSymCo co)+ `mkTransCo` ret_co ) }+ }++ where+ try_to_reduce :: TyCon -- F, family tycon+ -> [Type] -- args, not necessarily flattened+ -> Bool -- add to the flat cache?+ -> ( Coercion -- :: xi ~ F args+ -> Coercion ) -- what to return from outer function+ -> FlatM (Xi, Coercion) -- continuation upon failure+ -> FlatM (Xi, Coercion)+ try_to_reduce tc tys cache update_co k+ = do { checkStackDepth (mkTyConApp tc tys)+ ; mb_match <- liftTcS $ matchFam tc tys+ ; case mb_match of+ Just (norm_co, norm_ty)+ -> do { traceFlat "Eager T.F. reduction success" $+ vcat [ ppr tc, ppr tys, ppr norm_ty+ , ppr norm_co <+> dcolon+ <+> ppr (coercionKind norm_co)+ , ppr cache]+ ; (xi, final_co) <- bumpDepth $ flatten_one norm_ty+ ; eq_rel <- getEqRel+ ; let co = maybeSubCo eq_rel norm_co+ `mkTransCo` mkSymCo final_co+ ; flavour <- getFlavour+ -- NB: only extend cache with nominal equalities+ ; when (cache && eq_rel == NomEq) $+ liftTcS $+ extendFlatCache tc tys ( co, xi, flavour )+ ; return ( xi, update_co $ mkSymCo co ) }+ Nothing -> k }++{- Note [Reduce type family applications eagerly]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we come across a type-family application like (Append (Cons x Nil) t),+then, rather than flattening to a skolem etc, we may as well just reduce+it on the spot to (Cons x t). This saves a lot of intermediate steps.+Examples that are helped are tests T9872, and T5321Fun.++Performance testing indicates that it's best to try this *twice*, once+before flattening arguments and once after flattening arguments.+Adding the extra reduction attempt before flattening arguments cut+the allocation amounts for the T9872{a,b,c} tests by half.++An example of where the early reduction appears helpful:++ type family Last x where+ Last '[x] = x+ Last (h ': t) = Last t++ workitem: (x ~ Last '[1,2,3,4,5,6])++Flattening the argument never gets us anywhere, but trying to flatten+it at every step is quadratic in the length of the list. Reducing more+eagerly makes simplifying the right-hand type linear in its length.++Testing also indicated that the early reduction should *not* use the+flat-cache, but that the later reduction *should*. (Although the+effect was not large.) Hence the Bool argument to try_to_reduce. To+me (SLPJ) this seems odd; I get that eager reduction usually succeeds;+and if don't use the cache for eager reduction, we will miss most of+the opportunities for using it at all. More exploration would be good+here.++At the end, once we've got a flat rhs, we extend the flatten-cache to record+the result. Doing so can save lots of work when the same redex shows up more+than once. Note that we record the link from the redex all the way to its+*final* value, not just the single step reduction. Interestingly, using the+flat-cache for the first reduction resulted in an increase in allocations+of about 3% for the four T9872x tests. However, using the flat-cache in+the later reduction is a similar gain. I (Richard E) don't currently (Dec '14)+have any knowledge as to *why* these facts are true.++************************************************************************+* *+ Flattening a type variable+* *+********************************************************************* -}++-- | The result of flattening a tyvar "one step".+data FlattenTvResult+ = FTRNotFollowed+ -- ^ The inert set doesn't make the tyvar equal to anything else++ | FTRFollowed TcType Coercion+ -- ^ The tyvar flattens to a not-necessarily flat other type.+ -- co :: new type ~r old type, where the role is determined by+ -- the FlattenEnv++flattenTyVar :: TyVar -> FlatM (Xi, Coercion)+flattenTyVar tv+ = do { mb_yes <- flatten_tyvar1 tv+ ; case mb_yes of+ FTRFollowed ty1 co1 -- Recur+ -> do { (ty2, co2) <- flatten_one ty1+ -- ; traceFlat "flattenTyVar2" (ppr tv $$ ppr ty2)+ ; return (ty2, co2 `mkTransCo` co1) }++ FTRNotFollowed -- Done+ -> do { let orig_kind = tyVarKind tv+ ; (_new_kind, kind_co) <- setMode FM_SubstOnly $+ flattenKinds $+ flatten_one orig_kind+ ; let Pair _ zonked_kind = coercionKind kind_co+ -- NB: kind_co :: _new_kind ~ zonked_kind+ -- But zonked_kind is not necessarily the same as orig_kind+ -- because that may have filled-in metavars.+ -- Moreover the returned Xi type must be well-kinded+ -- (e.g. in canEqTyVarTyVar we use getCastedTyVar_maybe)+ -- If you remove it, then e.g. dependent/should_fail/T11407 panics+ -- See also Note [Flattening]+ -- An alternative would to use (zonkTcType orig_kind),+ -- but some simple measurements suggest that's a little slower+ ; let tv' = setTyVarKind tv zonked_kind+ tv_ty' = mkTyVarTy tv'+ ty' = tv_ty' `mkCastTy` mkSymCo kind_co++ ; role <- getRole+ ; return (ty', mkReflCo role tv_ty'+ `mkCoherenceLeftCo` mkSymCo kind_co) } }++flatten_tyvar1 :: TcTyVar -> FlatM FlattenTvResult+-- "Flattening" a type variable means to apply the substitution to it+-- Specifically, look up the tyvar in+-- * the internal MetaTyVar box+-- * the inerts+-- See also the documentation for FlattenTvResult++flatten_tyvar1 tv+ | not (isTcTyVar tv) -- Happens when flatten under a (forall a. ty)+ = return FTRNotFollowed+ -- So ty contains references to the non-TcTyVar a++ | otherwise+ = do { mb_ty <- liftTcS $ isFilledMetaTyVar_maybe tv+ ; role <- getRole+ ; case mb_ty of+ Just ty -> do { traceFlat "Following filled tyvar" (ppr tv <+> equals <+> ppr ty)+ ; return (FTRFollowed ty (mkReflCo role ty)) } ;+ Nothing -> do { traceFlat "Unfilled tyvar" (ppr tv)+ ; fr <- getFlavourRole+ ; flatten_tyvar2 tv fr } }++flatten_tyvar2 :: TcTyVar -> CtFlavourRole -> FlatM FlattenTvResult+-- The tyvar is not a filled-in meta-tyvar+-- Try in the inert equalities+-- See Definition [Applying a generalised substitution] in TcSMonad+-- See Note [Stability of flattening] in TcSMonad++flatten_tyvar2 tv fr@(_, eq_rel)+ = do { ieqs <- liftTcS $ getInertEqs+ ; mode <- getMode+ ; case lookupDVarEnv ieqs tv of+ Just (ct:_) -- If the first doesn't work,+ -- the subsequent ones won't either+ | CTyEqCan { cc_ev = ctev, cc_tyvar = tv, cc_rhs = rhs_ty } <- ct+ , let ct_fr = ctEvFlavourRole ctev+ , ct_fr `eqCanRewriteFR` fr -- This is THE key call of eqCanRewriteFR+ -> do { traceFlat "Following inert tyvar" (ppr mode <+> ppr tv <+> equals <+> ppr rhs_ty $$ ppr ctev)+ ; let rewrite_co1 = mkSymCo (ctEvCoercion ctev)+ rewrite_co = case (ctEvEqRel ctev, eq_rel) of+ (ReprEq, _rel) -> ASSERT( _rel == ReprEq )+ -- if this ASSERT fails, then+ -- eqCanRewriteFR answered incorrectly+ rewrite_co1+ (NomEq, NomEq) -> rewrite_co1+ (NomEq, ReprEq) -> mkSubCo rewrite_co1++ ; return (FTRFollowed rhs_ty rewrite_co) }+ -- NB: ct is Derived then fmode must be also, hence+ -- we are not going to touch the returned coercion+ -- so ctEvCoercion is fine.++ _other -> return FTRNotFollowed }++{-+Note [An alternative story for the inert substitution]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(This entire note is just background, left here in case we ever want+ to return the the previous state of affairs)++We used (GHC 7.8) to have this story for the inert substitution inert_eqs++ * 'a' is not in fvs(ty)+ * They are *inert* in the weaker sense that there is no infinite chain of+ (i1 `eqCanRewrite` i2), (i2 `eqCanRewrite` i3), etc++This means that flattening must be recursive, but it does allow+ [G] a ~ [b]+ [G] b ~ Maybe c++This avoids "saturating" the Givens, which can save a modest amount of work.+It is easy to implement, in TcInteract.kick_out, by only kicking out an inert+only if (a) the work item can rewrite the inert AND+ (b) the inert cannot rewrite the work item++This is significantly harder to think about. It can save a LOT of work+in occurs-check cases, but we don't care about them much. Trac #5837+is an example; all the constraints here are Givens++ [G] a ~ TF (a,Int)+ -->+ work TF (a,Int) ~ fsk+ inert fsk ~ a++ --->+ work fsk ~ (TF a, TF Int)+ inert fsk ~ a++ --->+ work a ~ (TF a, TF Int)+ inert fsk ~ a++ ---> (attempting to flatten (TF a) so that it does not mention a+ work TF a ~ fsk2+ inert a ~ (fsk2, TF Int)+ inert fsk ~ (fsk2, TF Int)++ ---> (substitute for a)+ work TF (fsk2, TF Int) ~ fsk2+ inert a ~ (fsk2, TF Int)+ inert fsk ~ (fsk2, TF Int)++ ---> (top-level reduction, re-orient)+ work fsk2 ~ (TF fsk2, TF Int)+ inert a ~ (fsk2, TF Int)+ inert fsk ~ (fsk2, TF Int)++ ---> (attempt to flatten (TF fsk2) to get rid of fsk2+ work TF fsk2 ~ fsk3+ work fsk2 ~ (fsk3, TF Int)+ inert a ~ (fsk2, TF Int)+ inert fsk ~ (fsk2, TF Int)++ --->+ work TF fsk2 ~ fsk3+ inert fsk2 ~ (fsk3, TF Int)+ inert a ~ ((fsk3, TF Int), TF Int)+ inert fsk ~ ((fsk3, TF Int), TF Int)++Because the incoming given rewrites all the inert givens, we get more and+more duplication in the inert set. But this really only happens in pathalogical+casee, so we don't care.+++************************************************************************+* *+ Unflattening+* *+************************************************************************++An unflattening example:+ [W] F a ~ alpha+flattens to+ [W] F a ~ fmv (CFunEqCan)+ [W] fmv ~ alpha (CTyEqCan)+We must solve both!+-}++unflatten :: Cts -> Cts -> TcS Cts+unflatten tv_eqs funeqs+ = do { tclvl <- getTcLevel++ ; traceTcS "Unflattening" $ braces $+ vcat [ text "Funeqs =" <+> pprCts funeqs+ , text "Tv eqs =" <+> pprCts tv_eqs ]++ -- Step 1: unflatten the CFunEqCans, except if that causes an occurs check+ -- Occurs check: consider [W] alpha ~ [F alpha]+ -- ==> (flatten) [W] F alpha ~ fmv, [W] alpha ~ [fmv]+ -- ==> (unify) [W] F [fmv] ~ fmv+ -- See Note [Unflatten using funeqs first]+ ; funeqs <- foldrBagM unflatten_funeq emptyCts funeqs+ ; traceTcS "Unflattening 1" $ braces (pprCts funeqs)++ -- Step 2: unify the tv_eqs, if possible+ ; tv_eqs <- foldrBagM (unflatten_eq tclvl) emptyCts tv_eqs+ ; traceTcS "Unflattening 2" $ braces (pprCts tv_eqs)++ -- Step 3: fill any remaining fmvs with fresh unification variables+ ; funeqs <- mapBagM finalise_funeq funeqs+ ; traceTcS "Unflattening 3" $ braces (pprCts funeqs)++ -- Step 4: remove any tv_eqs that look like ty ~ ty+ ; tv_eqs <- foldrBagM finalise_eq emptyCts tv_eqs++ ; let all_flat = tv_eqs `andCts` funeqs+ ; traceTcS "Unflattening done" $ braces (pprCts all_flat)++ -- Step 5: zonk the result+ -- Motivation: makes them nice and ready for the next step+ -- (see TcInteract.solveSimpleWanteds)+ ; zonkSimples all_flat }+ where+ ----------------+ unflatten_funeq :: Ct -> Cts -> TcS Cts+ unflatten_funeq ct@(CFunEqCan { cc_fun = tc, cc_tyargs = xis+ , cc_fsk = fmv, cc_ev = ev }) rest+ = do { -- fmv should be an un-filled flatten meta-tv;+ -- we now fix its final value by filling it, being careful+ -- to observe the occurs check. Zonking will eliminate it+ -- altogether in due course+ rhs' <- zonkTcType (mkTyConApp tc xis)+ ; case occCheckExpand fmv rhs' of+ Just rhs'' -- Normal case: fill the tyvar+ -> do { setReflEvidence ev NomEq rhs''+ ; unflattenFmv fmv rhs''+ ; return rest }++ Nothing -> -- Occurs check+ return (ct `consCts` rest) }++ unflatten_funeq other_ct _+ = pprPanic "unflatten_funeq" (ppr other_ct)++ ----------------+ finalise_funeq :: Ct -> TcS Ct+ finalise_funeq (CFunEqCan { cc_fsk = fmv, cc_ev = ev })+ = do { demoteUnfilledFmv fmv+ ; return (mkNonCanonical ev) }+ finalise_funeq ct = pprPanic "finalise_funeq" (ppr ct)++ ----------------+ unflatten_eq :: TcLevel -> Ct -> Cts -> TcS Cts+ unflatten_eq tclvl ct@(CTyEqCan { cc_ev = ev, cc_tyvar = tv+ , cc_rhs = rhs, cc_eq_rel = eq_rel }) rest+ | isFmvTyVar tv -- Previously these fmvs were untouchable,+ -- but now they are touchable+ -- NB: unlike unflattenFmv, filling a fmv here /does/+ -- bump the unification count; it is "improvement"+ -- Note [Unflattening can force the solver to iterate]+ = ASSERT2( tyVarKind tv `eqType` typeKind rhs, ppr ct )+ -- CTyEqCan invariant should ensure this is true+ do { is_filled <- isFilledMetaTyVar tv+ ; elim <- case is_filled of+ False -> do { traceTcS "unflatten_eq 2" (ppr ct)+ ; tryFill ev eq_rel tv rhs }+ True -> do { traceTcS "unflatten_eq 2" (ppr ct)+ ; try_fill_rhs ev eq_rel tclvl tv rhs }+ ; if elim then return rest+ else return (ct `consCts` rest) }++ | otherwise+ = return (ct `consCts` rest)++ unflatten_eq _ ct _ = pprPanic "unflatten_irred" (ppr ct)++ ----------------+ try_fill_rhs ev eq_rel tclvl lhs_tv rhs+ -- Constraint is lhs_tv ~ rhs_tv,+ -- and lhs_tv is filled, so try RHS+ | Just (rhs_tv, co) <- getCastedTyVar_maybe rhs+ -- co :: kind(rhs_tv) ~ kind(lhs_tv)+ , isFmvTyVar rhs_tv || (isTouchableMetaTyVar tclvl rhs_tv+ && not (isSigTyVar rhs_tv))+ -- LHS is a filled fmv, and so is a type+ -- family application, which a SigTv should+ -- not unify with+ = do { is_filled <- isFilledMetaTyVar rhs_tv+ ; if is_filled then return False+ else tryFill ev eq_rel rhs_tv+ (mkTyVarTy lhs_tv `mkCastTy` mkSymCo co) }++ | otherwise+ = return False++ ----------------+ finalise_eq :: Ct -> Cts -> TcS Cts+ finalise_eq (CTyEqCan { cc_ev = ev, cc_tyvar = tv+ , cc_rhs = rhs, cc_eq_rel = eq_rel }) rest+ | isFmvTyVar tv+ = do { ty1 <- zonkTcTyVar tv+ ; rhs' <- zonkTcType rhs+ ; if ty1 `tcEqType` rhs'+ then do { setReflEvidence ev eq_rel rhs'+ ; return rest }+ else return (mkNonCanonical ev `consCts` rest) }++ | otherwise+ = return (mkNonCanonical ev `consCts` rest)++ finalise_eq ct _ = pprPanic "finalise_irred" (ppr ct)++tryFill :: CtEvidence -> EqRel -> TcTyVar -> TcType -> TcS Bool+-- (tryFill tv rhs ev) assumes 'tv' is an /un-filled/ MetaTv+-- If tv does not appear in 'rhs', it set tv := rhs,+-- binds the evidence (which should be a CtWanted) to Refl<rhs>+-- and return True. Otherwise returns False+tryFill ev eq_rel tv rhs+ = ASSERT2( not (isGiven ev), ppr ev )+ do { rhs' <- zonkTcType rhs+ ; case tcGetTyVar_maybe rhs' of {+ Just tv' | tv == tv' -> do { setReflEvidence ev eq_rel rhs+ ; return True } ;+ _other ->+ do { case occCheckExpand tv rhs' of+ Just rhs'' -- Normal case: fill the tyvar+ -> do { setReflEvidence ev eq_rel rhs''+ ; unifyTyVar tv rhs''+ ; return True }++ Nothing -> -- Occurs check+ return False } } }++setReflEvidence :: CtEvidence -> EqRel -> TcType -> TcS ()+setReflEvidence ev eq_rel rhs+ = setEvBindIfWanted ev (EvCoercion refl_co)+ where+ refl_co = mkTcReflCo (eqRelRole eq_rel) rhs++{-+Note [Unflatten using funeqs first]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ [W] G a ~ Int+ [W] F (G a) ~ G a++do not want to end up with+ [W] F Int ~ Int+because that might actually hold! Better to end up with the two above+unsolved constraints. The flat form will be++ G a ~ fmv1 (CFunEqCan)+ F fmv1 ~ fmv2 (CFunEqCan)+ fmv1 ~ Int (CTyEqCan)+ fmv1 ~ fmv2 (CTyEqCan)++Flatten using the fun-eqs first.+-}
+ typecheck/TcForeign.hs view
@@ -0,0 +1,562 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1998++\section[TcForeign]{Typechecking \tr{foreign} declarations}++A foreign declaration is used to either give an externally+implemented function a Haskell type (and calling interface) or+give a Haskell function an external calling interface. Either way,+the range of argument and result types these functions can accommodate+is restricted to what the outside world understands (read C), and this+module checks to see if a foreign declaration has got a legal type.+-}++{-# LANGUAGE CPP #-}++module TcForeign+ ( tcForeignImports+ , tcForeignExports++ -- Low-level exports for hooks+ , isForeignImport, isForeignExport+ , tcFImport, tcFExport+ , tcForeignImports'+ , tcCheckFIType, checkCTarget, checkForeignArgs, checkForeignRes+ , normaliseFfiType+ , nonIOok, mustBeIO+ , checkSafe, noCheckSafe+ , tcForeignExports'+ , tcCheckFEType+ ) where++#include "HsVersions.h"++import HsSyn++import TcRnMonad+import TcHsType+import TcExpr+import TcEnv++import FamInst+import FamInstEnv+import Coercion+import Type+import ForeignCall+import ErrUtils+import Id+import Name+import RdrName+import DataCon+import TyCon+import TcType+import PrelNames+import DynFlags+import Outputable+import Platform+import SrcLoc+import Bag+import Hooks+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.Maybe++-- Defines a binding+isForeignImport :: LForeignDecl name -> Bool+isForeignImport (L _ (ForeignImport {})) = True+isForeignImport _ = False++-- Exports a binding+isForeignExport :: LForeignDecl name -> Bool+isForeignExport (L _ (ForeignExport {})) = True+isForeignExport _ = False++{-+Note [Don't recur in normaliseFfiType']+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+normaliseFfiType' is the workhorse for normalising a type used in a foreign+declaration. If we have++newtype Age = MkAge Int++we want to see that Age -> IO () is the same as Int -> IO (). But, we don't+need to recur on any type parameters, because no paramaterized types (with+interesting parameters) are marshalable! The full list of marshalable types+is in the body of boxedMarshalableTyCon in TcType. The only members of that+list not at kind * are Ptr, FunPtr, and StablePtr, all of which get marshaled+the same way regardless of type parameter. So, no need to recur into+parameters.++Similarly, we don't need to look in AppTy's, because nothing headed by+an AppTy will be marshalable.++Note [FFI type roles]+~~~~~~~~~~~~~~~~~~~~~+The 'go' helper function within normaliseFfiType' always produces+representational coercions. But, in the "children_only" case, we need to+use these coercions in a TyConAppCo. Accordingly, the roles on the coercions+must be twiddled to match the expectation of the enclosing TyCon. However,+we cannot easily go from an R coercion to an N one, so we forbid N roles+on FFI type constructors. Currently, only two such type constructors exist:+IO and FunPtr. Thus, this is not an onerous burden.++If we ever want to lift this restriction, we would need to make 'go' take+the target role as a parameter. This wouldn't be hard, but it's a complication+not yet necessary and so is not yet implemented.+-}++-- normaliseFfiType takes the type from an FFI declaration, and+-- evaluates any type synonyms, type functions, and newtypes. However,+-- we are only allowed to look through newtypes if the constructor is+-- in scope. We return a bag of all the newtype constructors thus found.+-- Always returns a Representational coercion+normaliseFfiType :: Type -> TcM (Coercion, Type, Bag GlobalRdrElt)+normaliseFfiType ty+ = do fam_envs <- tcGetFamInstEnvs+ normaliseFfiType' fam_envs ty++normaliseFfiType' :: FamInstEnvs -> Type -> TcM (Coercion, Type, Bag GlobalRdrElt)+normaliseFfiType' env ty0 = go initRecTc ty0+ where+ go :: RecTcChecker -> Type -> TcM (Coercion, Type, Bag GlobalRdrElt)+ go rec_nts ty+ | Just ty' <- tcView ty -- Expand synonyms+ = go rec_nts ty'++ | Just (tc, tys) <- splitTyConApp_maybe ty+ = go_tc_app rec_nts tc tys++ | (bndrs, inner_ty) <- splitForAllTyVarBndrs ty+ , not (null bndrs)+ = do (coi, nty1, gres1) <- go rec_nts inner_ty+ return ( mkHomoForAllCos (binderVars bndrs) coi+ , mkForAllTys bndrs nty1, gres1 )++ | otherwise -- see Note [Don't recur in normaliseFfiType']+ = return (mkRepReflCo ty, ty, emptyBag)++ go_tc_app :: RecTcChecker -> TyCon -> [Type]+ -> TcM (Coercion, Type, Bag GlobalRdrElt)+ go_tc_app rec_nts tc tys+ -- We don't want to look through the IO newtype, even if it is+ -- in scope, so we have a special case for it:+ | tc_key `elem` [ioTyConKey, funPtrTyConKey, funTyConKey]+ -- These *must not* have nominal roles on their parameters!+ -- See Note [FFI type roles]+ = children_only++ | isNewTyCon tc -- Expand newtypes+ , Just rec_nts' <- checkRecTc rec_nts tc+ -- See Note [Expanding newtypes] in TyCon.hs+ -- We can't just use isRecursiveTyCon; sometimes recursion is ok:+ -- newtype T = T (Ptr T)+ -- Here, we don't reject the type for being recursive.+ -- If this is a recursive newtype then it will normally+ -- be rejected later as not being a valid FFI type.+ = do { rdr_env <- getGlobalRdrEnv+ ; case checkNewtypeFFI rdr_env tc of+ Nothing -> nothing+ Just gre -> do { (co', ty', gres) <- go rec_nts' nt_rhs+ ; return (mkTransCo nt_co co', ty', gre `consBag` gres) } }++ | isFamilyTyCon tc -- Expand open tycons+ , (co, ty) <- normaliseTcApp env Representational tc tys+ , not (isReflexiveCo co)+ = do (co', ty', gres) <- go rec_nts ty+ return (mkTransCo co co', ty', gres)++ | otherwise+ = nothing -- see Note [Don't recur in normaliseFfiType']+ where+ tc_key = getUnique tc+ children_only+ = do xs <- mapM (go rec_nts) tys+ let (cos, tys', gres) = unzip3 xs+ -- the (repeat Representational) is because 'go' always+ -- returns R coercions+ cos' = zipWith3 downgradeRole (tyConRoles tc)+ (repeat Representational) cos+ return ( mkTyConAppCo Representational tc cos'+ , mkTyConApp tc tys', unionManyBags gres)+ nt_co = mkUnbranchedAxInstCo Representational (newTyConCo tc) tys []+ nt_rhs = newTyConInstRhs tc tys++ ty = mkTyConApp tc tys+ nothing = return (mkRepReflCo ty, ty, emptyBag)++checkNewtypeFFI :: GlobalRdrEnv -> TyCon -> Maybe GlobalRdrElt+checkNewtypeFFI rdr_env tc+ | Just con <- tyConSingleDataCon_maybe tc+ , Just gre <- lookupGRE_Name rdr_env (dataConName con)+ = Just gre -- See Note [Newtype constructor usage in foreign declarations]+ | otherwise+ = Nothing++{-+Note [Newtype constructor usage in foreign declarations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC automatically "unwraps" newtype constructors in foreign import/export+declarations. In effect that means that a newtype data constructor is+used even though it is not mentioned expclitly in the source, so we don't+want to report it as "defined but not used" or "imported but not used".+eg newtype D = MkD Int+ foreign import foo :: D -> IO ()+Here 'MkD' us used. See Trac #7408.++GHC also expands type functions during this process, so it's not enough+just to look at the free variables of the declaration.+eg type instance F Bool = D+ foreign import bar :: F Bool -> IO ()+Here again 'MkD' is used.++So we really have wait until the type checker to decide what is used.+That's why tcForeignImports and tecForeignExports return a (Bag GRE)+for the newtype constructors they see. Then TcRnDriver can add them+to the module's usages.+++************************************************************************+* *+\subsection{Imports}+* *+************************************************************************+-}++tcForeignImports :: [LForeignDecl Name] -> TcM ([Id], [LForeignDecl Id], Bag GlobalRdrElt)+tcForeignImports decls+ = getHooked tcForeignImportsHook tcForeignImports' >>= ($ decls)++tcForeignImports' :: [LForeignDecl Name] -> TcM ([Id], [LForeignDecl Id], Bag GlobalRdrElt)+-- For the (Bag GlobalRdrElt) result,+-- see Note [Newtype constructor usage in foreign declarations]+tcForeignImports' decls+ = do { (ids, decls, gres) <- mapAndUnzip3M tcFImport $+ filter isForeignImport decls+ ; return (ids, decls, unionManyBags gres) }++tcFImport :: LForeignDecl Name -> TcM (Id, LForeignDecl Id, Bag GlobalRdrElt)+tcFImport (L dloc fo@(ForeignImport { fd_name = L nloc nm, fd_sig_ty = hs_ty+ , fd_fi = imp_decl }))+ = setSrcSpan dloc $ addErrCtxt (foreignDeclCtxt fo) $+ do { sig_ty <- tcHsSigType (ForSigCtxt nm) hs_ty+ ; (norm_co, norm_sig_ty, gres) <- normaliseFfiType sig_ty+ ; let+ -- Drop the foralls before inspecting the+ -- structure of the foreign type.+ (bndrs, res_ty) = tcSplitPiTys norm_sig_ty+ arg_tys = mapMaybe binderRelevantType_maybe bndrs+ id = mkLocalId nm sig_ty+ -- Use a LocalId to obey the invariant that locally-defined+ -- things are LocalIds. However, it does not need zonking,+ -- (so TcHsSyn.zonkForeignExports ignores it).++ ; imp_decl' <- tcCheckFIType arg_tys res_ty imp_decl+ -- Can't use sig_ty here because sig_ty :: Type and+ -- we need HsType Id hence the undefined+ ; let fi_decl = ForeignImport { fd_name = L nloc id+ , fd_sig_ty = undefined+ , fd_co = mkSymCo norm_co+ , fd_fi = imp_decl' }+ ; return (id, L dloc fi_decl, gres) }+tcFImport d = pprPanic "tcFImport" (ppr d)++-- ------------ Checking types for foreign import ----------------------++tcCheckFIType :: [Type] -> Type -> ForeignImport -> TcM ForeignImport++tcCheckFIType arg_tys res_ty (CImport (L lc cconv) safety mh l@(CLabel _) src)+ -- Foreign import label+ = do checkCg checkCOrAsmOrLlvmOrInterp+ -- NB check res_ty not sig_ty!+ -- In case sig_ty is (forall a. ForeignPtr a)+ check (isFFILabelTy (mkFunTys arg_tys res_ty)) (illegalForeignTyErr Outputable.empty)+ cconv' <- checkCConv cconv+ return (CImport (L lc cconv') safety mh l src)++tcCheckFIType arg_tys res_ty (CImport (L lc cconv) safety mh CWrapper src) = do+ -- Foreign wrapper (former f.e.d.)+ -- The type must be of the form ft -> IO (FunPtr ft), where ft is a valid+ -- foreign type. For legacy reasons ft -> IO (Ptr ft) is accepted, too.+ -- The use of the latter form is DEPRECATED, though.+ checkCg checkCOrAsmOrLlvmOrInterp+ cconv' <- checkCConv cconv+ case arg_tys of+ [arg1_ty] -> do checkForeignArgs isFFIExternalTy arg1_tys+ checkForeignRes nonIOok checkSafe isFFIExportResultTy res1_ty+ checkForeignRes mustBeIO checkSafe (isFFIDynTy arg1_ty) res_ty+ where+ (arg1_tys, res1_ty) = tcSplitFunTys arg1_ty+ _ -> addErrTc (illegalForeignTyErr Outputable.empty (text "One argument expected"))+ return (CImport (L lc cconv') safety mh CWrapper src)++tcCheckFIType arg_tys res_ty idecl@(CImport (L lc cconv) (L ls safety) mh+ (CFunction target) src)+ | isDynamicTarget target = do -- Foreign import dynamic+ checkCg checkCOrAsmOrLlvmOrInterp+ cconv' <- checkCConv cconv+ case arg_tys of -- The first arg must be Ptr or FunPtr+ [] ->+ addErrTc (illegalForeignTyErr Outputable.empty (text "At least one argument expected"))+ (arg1_ty:arg_tys) -> do+ dflags <- getDynFlags+ let curried_res_ty = mkFunTys arg_tys res_ty+ check (isFFIDynTy curried_res_ty arg1_ty)+ (illegalForeignTyErr argument)+ checkForeignArgs (isFFIArgumentTy dflags safety) arg_tys+ checkForeignRes nonIOok checkSafe (isFFIImportResultTy dflags) res_ty+ return $ CImport (L lc cconv') (L ls safety) mh (CFunction target) src+ | cconv == PrimCallConv = do+ dflags <- getDynFlags+ checkTc (xopt LangExt.GHCForeignImportPrim dflags)+ (text "Use GHCForeignImportPrim to allow `foreign import prim'.")+ checkCg checkCOrAsmOrLlvmOrInterp+ checkCTarget target+ checkTc (playSafe safety)+ (text "The safe/unsafe annotation should not be used with `foreign import prim'.")+ checkForeignArgs (isFFIPrimArgumentTy dflags) arg_tys+ -- prim import result is more liberal, allows (#,,#)+ checkForeignRes nonIOok checkSafe (isFFIPrimResultTy dflags) res_ty+ return idecl+ | otherwise = do -- Normal foreign import+ checkCg checkCOrAsmOrLlvmOrInterp+ cconv' <- checkCConv cconv+ checkCTarget target+ dflags <- getDynFlags+ checkForeignArgs (isFFIArgumentTy dflags safety) arg_tys+ checkForeignRes nonIOok checkSafe (isFFIImportResultTy dflags) res_ty+ checkMissingAmpersand dflags arg_tys res_ty+ case target of+ StaticTarget _ _ _ False+ | not (null arg_tys) ->+ addErrTc (text "`value' imports cannot have function types")+ _ -> return ()+ return $ CImport (L lc cconv') (L ls safety) mh (CFunction target) src+++-- This makes a convenient place to check+-- that the C identifier is valid for C+checkCTarget :: CCallTarget -> TcM ()+checkCTarget (StaticTarget _ str _ _) = do+ checkCg checkCOrAsmOrLlvmOrInterp+ checkTc (isCLabelString str) (badCName str)++checkCTarget DynamicTarget = panic "checkCTarget DynamicTarget"+++checkMissingAmpersand :: DynFlags -> [Type] -> Type -> TcM ()+checkMissingAmpersand dflags arg_tys res_ty+ | null arg_tys && isFunPtrTy res_ty &&+ wopt Opt_WarnDodgyForeignImports dflags+ = addWarn (Reason Opt_WarnDodgyForeignImports)+ (text "possible missing & in foreign import of FunPtr")+ | otherwise+ = return ()++{-+************************************************************************+* *+\subsection{Exports}+* *+************************************************************************+-}++tcForeignExports :: [LForeignDecl Name]+ -> TcM (LHsBinds TcId, [LForeignDecl TcId], Bag GlobalRdrElt)+tcForeignExports decls =+ getHooked tcForeignExportsHook tcForeignExports' >>= ($ decls)++tcForeignExports' :: [LForeignDecl Name]+ -> TcM (LHsBinds TcId, [LForeignDecl TcId], Bag GlobalRdrElt)+-- For the (Bag GlobalRdrElt) result,+-- see Note [Newtype constructor usage in foreign declarations]+tcForeignExports' decls+ = foldlM combine (emptyLHsBinds, [], emptyBag) (filter isForeignExport decls)+ where+ combine (binds, fs, gres1) (L loc fe) = do+ (b, f, gres2) <- setSrcSpan loc (tcFExport fe)+ return (b `consBag` binds, L loc f : fs, gres1 `unionBags` gres2)++tcFExport :: ForeignDecl Name -> TcM (LHsBind Id, ForeignDecl Id, Bag GlobalRdrElt)+tcFExport fo@(ForeignExport { fd_name = L loc nm, fd_sig_ty = hs_ty, fd_fe = spec })+ = addErrCtxt (foreignDeclCtxt fo) $ do++ sig_ty <- tcHsSigType (ForSigCtxt nm) hs_ty+ rhs <- tcPolyExpr (nlHsVar nm) sig_ty++ (norm_co, norm_sig_ty, gres) <- normaliseFfiType sig_ty++ spec' <- tcCheckFEType norm_sig_ty spec++ -- we're exporting a function, but at a type possibly more+ -- constrained than its declared/inferred type. Hence the need+ -- to create a local binding which will call the exported function+ -- at a particular type (and, maybe, overloading).+++ -- We need to give a name to the new top-level binding that+ -- is *stable* (i.e. the compiler won't change it later),+ -- because this name will be referred to by the C code stub.+ id <- mkStableIdFromName nm sig_ty loc mkForeignExportOcc+ return ( mkVarBind id rhs+ , ForeignExport { fd_name = L loc id+ , fd_sig_ty = undefined+ , fd_co = norm_co, fd_fe = spec' }+ , gres)+tcFExport d = pprPanic "tcFExport" (ppr d)++-- ------------ Checking argument types for foreign export ----------------------++tcCheckFEType :: Type -> ForeignExport -> TcM ForeignExport+tcCheckFEType sig_ty (CExport (L l (CExportStatic esrc str cconv)) src) = do+ checkCg checkCOrAsmOrLlvm+ checkTc (isCLabelString str) (badCName str)+ cconv' <- checkCConv cconv+ checkForeignArgs isFFIExternalTy arg_tys+ checkForeignRes nonIOok noCheckSafe isFFIExportResultTy res_ty+ return (CExport (L l (CExportStatic esrc str cconv')) src)+ where+ -- Drop the foralls before inspecting n+ -- the structure of the foreign type.+ (bndrs, res_ty) = tcSplitPiTys sig_ty+ arg_tys = mapMaybe binderRelevantType_maybe bndrs++{-+************************************************************************+* *+\subsection{Miscellaneous}+* *+************************************************************************+-}++------------ Checking argument types for foreign import ----------------------+checkForeignArgs :: (Type -> Validity) -> [Type] -> TcM ()+checkForeignArgs pred tys = mapM_ go tys+ where+ go ty = check (pred ty) (illegalForeignTyErr argument)++------------ Checking result types for foreign calls ----------------------+-- | Check that the type has the form+-- (IO t) or (t) , and that t satisfies the given predicate.+-- When calling this function, any newtype wrappers (should) have been+-- already dealt with by normaliseFfiType.+--+-- We also check that the Safe Haskell condition of FFI imports having+-- results in the IO monad holds.+--+checkForeignRes :: Bool -> Bool -> (Type -> Validity) -> Type -> TcM ()+checkForeignRes non_io_result_ok check_safe pred_res_ty ty+ | Just (_, res_ty) <- tcSplitIOType_maybe ty+ = -- Got an IO result type, that's always fine!+ check (pred_res_ty res_ty) (illegalForeignTyErr result)++ -- Case for non-IO result type with FFI Import+ | not non_io_result_ok+ = addErrTc $ illegalForeignTyErr result (text "IO result type expected")++ | otherwise+ = do { dflags <- getDynFlags+ ; case pred_res_ty ty of+ -- Handle normal typecheck fail, we want to handle this first and+ -- only report safe haskell errors if the normal type check is OK.+ NotValid msg -> addErrTc $ illegalForeignTyErr result msg++ -- handle safe infer fail+ _ | check_safe && safeInferOn dflags+ -> recordUnsafeInfer emptyBag++ -- handle safe language typecheck fail+ _ | check_safe && safeLanguageOn dflags+ -> addErrTc (illegalForeignTyErr result safeHsErr)++ -- success! non-IO return is fine+ _ -> return () }+ where+ safeHsErr =+ text "Safe Haskell is on, all FFI imports must be in the IO monad"++nonIOok, mustBeIO :: Bool+nonIOok = True+mustBeIO = False++checkSafe, noCheckSafe :: Bool+checkSafe = True+noCheckSafe = False++-- Checking a supported backend is in use++checkCOrAsmOrLlvm :: HscTarget -> Validity+checkCOrAsmOrLlvm HscC = IsValid+checkCOrAsmOrLlvm HscAsm = IsValid+checkCOrAsmOrLlvm HscLlvm = IsValid+checkCOrAsmOrLlvm _+ = NotValid (text "requires unregisterised, llvm (-fllvm) or native code generation (-fasm)")++checkCOrAsmOrLlvmOrInterp :: HscTarget -> Validity+checkCOrAsmOrLlvmOrInterp HscC = IsValid+checkCOrAsmOrLlvmOrInterp HscAsm = IsValid+checkCOrAsmOrLlvmOrInterp HscLlvm = IsValid+checkCOrAsmOrLlvmOrInterp HscInterpreted = IsValid+checkCOrAsmOrLlvmOrInterp _+ = NotValid (text "requires interpreted, unregisterised, llvm or native code generation")++checkCg :: (HscTarget -> Validity) -> TcM ()+checkCg check = do+ dflags <- getDynFlags+ let target = hscTarget dflags+ case target of+ HscNothing -> return ()+ _ ->+ case check target of+ IsValid -> return ()+ NotValid err -> addErrTc (text "Illegal foreign declaration:" <+> err)++-- Calling conventions++checkCConv :: CCallConv -> TcM CCallConv+checkCConv CCallConv = return CCallConv+checkCConv CApiConv = return CApiConv+checkCConv StdCallConv = do dflags <- getDynFlags+ let platform = targetPlatform dflags+ if platformArch platform == ArchX86+ then return StdCallConv+ else do -- This is a warning, not an error. see #3336+ when (wopt Opt_WarnUnsupportedCallingConventions dflags) $+ addWarnTc (Reason Opt_WarnUnsupportedCallingConventions)+ (text "the 'stdcall' calling convention is unsupported on this platform," $$ text "treating as ccall")+ return CCallConv+checkCConv PrimCallConv = do addErrTc (text "The `prim' calling convention can only be used with `foreign import'")+ return PrimCallConv+checkCConv JavaScriptCallConv = do dflags <- getDynFlags+ if platformArch (targetPlatform dflags) == ArchJavaScript+ then return JavaScriptCallConv+ else do addErrTc (text "The `javascript' calling convention is unsupported on this platform")+ return JavaScriptCallConv++-- Warnings++check :: Validity -> (MsgDoc -> MsgDoc) -> TcM ()+check IsValid _ = return ()+check (NotValid doc) err_fn = addErrTc (err_fn doc)++illegalForeignTyErr :: SDoc -> SDoc -> SDoc+illegalForeignTyErr arg_or_res extra+ = hang msg 2 extra+ where+ msg = hsep [ text "Unacceptable", arg_or_res+ , text "type in foreign declaration:"]++-- Used for 'arg_or_res' argument to illegalForeignTyErr+argument, result :: SDoc+argument = text "argument"+result = text "result"++badCName :: CLabelString -> MsgDoc+badCName target+ = sep [quotes (ppr target) <+> text "is not a valid C identifier"]++foreignDeclCtxt :: ForeignDecl Name -> SDoc+foreignDeclCtxt fo+ = hang (text "When checking declaration:")+ 2 (ppr fo)
+ typecheck/TcGenDeriv.hs view
@@ -0,0 +1,2155 @@+{-+ %+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++TcGenDeriv: Generating derived instance declarations++This module is nominally ``subordinate'' to @TcDeriv@, which is the+``official'' interface to deriving-related things.++This is where we do all the grimy bindings' generation.+-}++{-# LANGUAGE CPP, ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}++module TcGenDeriv (+ BagDerivStuff, DerivStuff(..),++ gen_Eq_binds,+ gen_Ord_binds,+ gen_Enum_binds,+ gen_Bounded_binds,+ gen_Ix_binds,+ gen_Show_binds,+ gen_Read_binds,+ gen_Data_binds,+ gen_Lift_binds,+ gen_Newtype_binds,+ mkCoerceClassMethEqn,+ genAuxBinds,+ ordOpTbl, boxConTbl, litConTbl,+ mkRdrFunBind, error_Expr+ ) where++#include "HsVersions.h"++import TcRnMonad+import HsSyn+import RdrName+import BasicTypes+import DataCon+import Name+import Fingerprint+import Encoding++import DynFlags+import PrelInfo+import FamInst+import FamInstEnv+import PrelNames+import THNames+import Module ( moduleName, moduleNameString+ , moduleUnitId, unitIdString )+import MkId ( coerceId )+import PrimOp+import SrcLoc+import TyCon+import TcEnv+import TcType+import TcValidity ( checkValidTyFamEqn )+import TysPrim+import TysWiredIn+import Type+import Class+import VarSet+import VarEnv+import Util+import Var+import Outputable+import Lexeme+import FastString+import Pair+import Bag++import Data.List ( partition, intersperse )++type BagDerivStuff = Bag DerivStuff++data AuxBindSpec+ = DerivCon2Tag TyCon -- The con2Tag for given TyCon+ | DerivTag2Con TyCon -- ...ditto tag2Con+ | DerivMaxTag TyCon -- ...and maxTag+ deriving( Eq )+ -- All these generate ZERO-BASED tag operations+ -- I.e first constructor has tag 0++data DerivStuff -- Please add this auxiliary stuff+ = DerivAuxBind AuxBindSpec++ -- Generics and DeriveAnyClass+ | DerivFamInst FamInst -- New type family instances++ -- New top-level auxiliary bindings+ | DerivHsBind (LHsBind RdrName, LSig RdrName) -- Also used for SYB+++{-+************************************************************************+* *+ Eq instances+* *+************************************************************************++Here are the heuristics for the code we generate for @Eq@. Let's+assume we have a data type with some (possibly zero) nullary data+constructors and some ordinary, non-nullary ones (the rest, also+possibly zero of them). Here's an example, with both \tr{N}ullary and+\tr{O}rdinary data cons.++ data Foo ... = N1 | N2 ... | Nn | O1 a b | O2 Int | O3 Double b b | ...++* For the ordinary constructors (if any), we emit clauses to do The+ Usual Thing, e.g.,:++ (==) (O1 a1 b1) (O1 a2 b2) = a1 == a2 && b1 == b2+ (==) (O2 a1) (O2 a2) = a1 == a2+ (==) (O3 a1 b1 c1) (O3 a2 b2 c2) = a1 == a2 && b1 == b2 && c1 == c2++ Note: if we're comparing unlifted things, e.g., if 'a1' and+ 'a2' are Float#s, then we have to generate+ case (a1 `eqFloat#` a2) of r -> r+ for that particular test.++* If there are a lot of (more than en) nullary constructors, we emit a+ catch-all clause of the form:++ (==) a b = case (con2tag_Foo a) of { a# ->+ case (con2tag_Foo b) of { b# ->+ case (a# ==# b#) of {+ r -> r }}}++ If con2tag gets inlined this leads to join point stuff, so+ it's better to use regular pattern matching if there aren't too+ many nullary constructors. "Ten" is arbitrary, of course++* If there aren't any nullary constructors, we emit a simpler+ catch-all:++ (==) a b = False++* For the @(/=)@ method, we normally just use the default method.+ If the type is an enumeration type, we could/may/should? generate+ special code that calls @con2tag_Foo@, much like for @(==)@ shown+ above.++We thought about doing this: If we're also deriving 'Ord' for this+tycon, we generate:+ instance ... Eq (Foo ...) where+ (==) a b = case (compare a b) of { _LT -> False; _EQ -> True ; _GT -> False}+ (/=) a b = case (compare a b) of { _LT -> True ; _EQ -> False; _GT -> True }+However, that requires that (Ord <whatever>) was put in the context+for the instance decl, which it probably wasn't, so the decls+produced don't get through the typechecker.+-}++gen_Eq_binds :: SrcSpan -> TyCon -> TcM (LHsBinds RdrName, BagDerivStuff)+gen_Eq_binds loc tycon = do+ dflags <- getDynFlags+ return (method_binds dflags, aux_binds)+ where+ all_cons = tyConDataCons tycon+ (nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon all_cons++ -- If there are ten or more (arbitrary number) nullary constructors,+ -- use the con2tag stuff. For small types it's better to use+ -- ordinary pattern matching.+ (tag_match_cons, pat_match_cons)+ | nullary_cons `lengthExceeds` 10 = (nullary_cons, non_nullary_cons)+ | otherwise = ([], all_cons)++ no_tag_match_cons = null tag_match_cons++ fall_through_eqn dflags+ | no_tag_match_cons -- All constructors have arguments+ = case pat_match_cons of+ [] -> [] -- No constructors; no fall-though case+ [_] -> [] -- One constructor; no fall-though case+ _ -> -- Two or more constructors; add fall-through of+ -- (==) _ _ = False+ [([nlWildPat, nlWildPat], false_Expr)]++ | otherwise -- One or more tag_match cons; add fall-through of+ -- extract tags compare for equality+ = [([a_Pat, b_Pat],+ untag_Expr dflags tycon [(a_RDR,ah_RDR), (b_RDR,bh_RDR)]+ (genPrimOpApp (nlHsVar ah_RDR) eqInt_RDR (nlHsVar bh_RDR)))]++ aux_binds | no_tag_match_cons = emptyBag+ | otherwise = unitBag $ DerivAuxBind $ DerivCon2Tag tycon++ method_binds dflags = listToBag+ [ eq_bind dflags+ , ne_bind+ ]+ eq_bind dflags = mk_FunBind loc eq_RDR (map pats_etc pat_match_cons+ ++ fall_through_eqn dflags)+ ne_bind = mk_easy_FunBind loc ne_RDR [a_Pat, b_Pat] (+ nlHsApp (nlHsVar not_RDR) (nlHsPar (nlHsVarApps eq_RDR [a_RDR, b_RDR])))++ ------------------------------------------------------------------+ pats_etc data_con+ = let+ con1_pat = nlParPat $ nlConVarPat data_con_RDR as_needed+ con2_pat = nlParPat $ nlConVarPat data_con_RDR bs_needed++ data_con_RDR = getRdrName data_con+ con_arity = length tys_needed+ as_needed = take con_arity as_RDRs+ bs_needed = take con_arity bs_RDRs+ tys_needed = dataConOrigArgTys data_con+ in+ ([con1_pat, con2_pat], nested_eq_expr tys_needed as_needed bs_needed)+ where+ nested_eq_expr [] [] [] = true_Expr+ nested_eq_expr tys as bs+ = foldl1 and_Expr (zipWith3Equal "nested_eq" nested_eq tys as bs)+ where+ nested_eq ty a b = nlHsPar (eq_Expr tycon ty (nlHsVar a) (nlHsVar b))++{-+************************************************************************+* *+ Ord instances+* *+************************************************************************++Note [Generating Ord instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose constructors are K1..Kn, and some are nullary.+The general form we generate is:++* Do case on first argument+ case a of+ K1 ... -> rhs_1+ K2 ... -> rhs_2+ ...+ Kn ... -> rhs_n+ _ -> nullary_rhs++* To make rhs_i+ If i = 1, 2, n-1, n, generate a single case.+ rhs_2 case b of+ K1 {} -> LT+ K2 ... -> ...eq_rhs(K2)...+ _ -> GT++ Otherwise do a tag compare against the bigger range+ (because this is the one most likely to succeed)+ rhs_3 case tag b of tb ->+ if 3 <# tg then GT+ else case b of+ K3 ... -> ...eq_rhs(K3)....+ _ -> LT++* To make eq_rhs(K), which knows that+ a = K a1 .. av+ b = K b1 .. bv+ we just want to compare (a1,b1) then (a2,b2) etc.+ Take care on the last field to tail-call into comparing av,bv++* To make nullary_rhs generate this+ case con2tag a of a# ->+ case con2tag b of ->+ a# `compare` b#++Several special cases:++* Two or fewer nullary constructors: don't generate nullary_rhs++* Be careful about unlifted comparisons. When comparing unboxed+ values we can't call the overloaded functions.+ See function unliftedOrdOp++Note [Game plan for deriving Ord]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's a bad idea to define only 'compare', and build the other binary+comparisons on top of it; see Trac #2130, #4019. Reason: we don't+want to laboriously make a three-way comparison, only to extract a+binary result, something like this:+ (>) (I# x) (I# y) = case <# x y of+ True -> False+ False -> case ==# x y of+ True -> False+ False -> True++This being said, we can get away with generating full code only for+'compare' and '<' thus saving us generation of other three operators.+Other operators can be cheaply expressed through '<':+a <= b = not $ b < a+a > b = b < a+a >= b = not $ a < b++So for sufficiently small types (few constructors, or all nullary)+we generate all methods; for large ones we just use 'compare'.++-}++data OrdOp = OrdCompare | OrdLT | OrdLE | OrdGE | OrdGT++------------+ordMethRdr :: OrdOp -> RdrName+ordMethRdr op+ = case op of+ OrdCompare -> compare_RDR+ OrdLT -> lt_RDR+ OrdLE -> le_RDR+ OrdGE -> ge_RDR+ OrdGT -> gt_RDR++------------+ltResult :: OrdOp -> LHsExpr RdrName+-- Knowing a<b, what is the result for a `op` b?+ltResult OrdCompare = ltTag_Expr+ltResult OrdLT = true_Expr+ltResult OrdLE = true_Expr+ltResult OrdGE = false_Expr+ltResult OrdGT = false_Expr++------------+eqResult :: OrdOp -> LHsExpr RdrName+-- Knowing a=b, what is the result for a `op` b?+eqResult OrdCompare = eqTag_Expr+eqResult OrdLT = false_Expr+eqResult OrdLE = true_Expr+eqResult OrdGE = true_Expr+eqResult OrdGT = false_Expr++------------+gtResult :: OrdOp -> LHsExpr RdrName+-- Knowing a>b, what is the result for a `op` b?+gtResult OrdCompare = gtTag_Expr+gtResult OrdLT = false_Expr+gtResult OrdLE = false_Expr+gtResult OrdGE = true_Expr+gtResult OrdGT = true_Expr++------------+gen_Ord_binds :: SrcSpan -> TyCon -> TcM (LHsBinds RdrName, BagDerivStuff)+gen_Ord_binds loc tycon = do+ dflags <- getDynFlags+ return $ if null tycon_data_cons -- No data-cons => invoke bale-out case+ then ( unitBag $ mk_FunBind loc compare_RDR []+ , emptyBag)+ else ( unitBag (mkOrdOp dflags OrdCompare) `unionBags` other_ops dflags+ , aux_binds)+ where+ aux_binds | single_con_type = emptyBag+ | otherwise = unitBag $ DerivAuxBind $ DerivCon2Tag tycon++ -- Note [Game plan for deriving Ord]+ other_ops dflags+ | (last_tag - first_tag) <= 2 -- 1-3 constructors+ || null non_nullary_cons -- Or it's an enumeration+ = listToBag [mkOrdOp dflags OrdLT, lE, gT, gE]+ | otherwise+ = emptyBag++ negate_expr = nlHsApp (nlHsVar not_RDR)+ lE = mk_easy_FunBind loc le_RDR [a_Pat, b_Pat] $+ negate_expr (nlHsApp (nlHsApp (nlHsVar lt_RDR) b_Expr) a_Expr)+ gT = mk_easy_FunBind loc gt_RDR [a_Pat, b_Pat] $+ nlHsApp (nlHsApp (nlHsVar lt_RDR) b_Expr) a_Expr+ gE = mk_easy_FunBind loc ge_RDR [a_Pat, b_Pat] $+ negate_expr (nlHsApp (nlHsApp (nlHsVar lt_RDR) a_Expr) b_Expr)++ get_tag con = dataConTag con - fIRST_TAG+ -- We want *zero-based* tags, because that's what+ -- con2Tag returns (generated by untag_Expr)!++ tycon_data_cons = tyConDataCons tycon+ single_con_type = isSingleton tycon_data_cons+ (first_con : _) = tycon_data_cons+ (last_con : _) = reverse tycon_data_cons+ first_tag = get_tag first_con+ last_tag = get_tag last_con++ (nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon tycon_data_cons+++ mkOrdOp :: DynFlags -> OrdOp -> LHsBind RdrName+ -- Returns a binding op a b = ... compares a and b according to op ....+ mkOrdOp dflags op = mk_easy_FunBind loc (ordMethRdr op) [a_Pat, b_Pat]+ (mkOrdOpRhs dflags op)++ mkOrdOpRhs :: DynFlags -> OrdOp -> LHsExpr RdrName+ mkOrdOpRhs dflags op -- RHS for comparing 'a' and 'b' according to op+ | length nullary_cons <= 2 -- Two nullary or fewer, so use cases+ = nlHsCase (nlHsVar a_RDR) $+ map (mkOrdOpAlt dflags op) tycon_data_cons+ -- i.e. case a of { C1 x y -> case b of C1 x y -> ....compare x,y...+ -- C2 x -> case b of C2 x -> ....comopare x.... }++ | null non_nullary_cons -- All nullary, so go straight to comparing tags+ = mkTagCmp dflags op++ | otherwise -- Mixed nullary and non-nullary+ = nlHsCase (nlHsVar a_RDR) $+ (map (mkOrdOpAlt dflags op) non_nullary_cons+ ++ [mkHsCaseAlt nlWildPat (mkTagCmp dflags op)])+++ mkOrdOpAlt :: DynFlags -> OrdOp -> DataCon+ -> LMatch RdrName (LHsExpr RdrName)+ -- Make the alternative (Ki a1 a2 .. av ->+ mkOrdOpAlt dflags op data_con+ = mkHsCaseAlt (nlConVarPat data_con_RDR as_needed)+ (mkInnerRhs dflags op data_con)+ where+ as_needed = take (dataConSourceArity data_con) as_RDRs+ data_con_RDR = getRdrName data_con++ mkInnerRhs dflags op data_con+ | single_con_type+ = nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con ]++ | tag == first_tag+ = nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con+ , mkHsCaseAlt nlWildPat (ltResult op) ]+ | tag == last_tag+ = nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con+ , mkHsCaseAlt nlWildPat (gtResult op) ]++ | tag == first_tag + 1+ = nlHsCase (nlHsVar b_RDR) [ mkHsCaseAlt (nlConWildPat first_con)+ (gtResult op)+ , mkInnerEqAlt op data_con+ , mkHsCaseAlt nlWildPat (ltResult op) ]+ | tag == last_tag - 1+ = nlHsCase (nlHsVar b_RDR) [ mkHsCaseAlt (nlConWildPat last_con)+ (ltResult op)+ , mkInnerEqAlt op data_con+ , mkHsCaseAlt nlWildPat (gtResult op) ]++ | tag > last_tag `div` 2 -- lower range is larger+ = untag_Expr dflags tycon [(b_RDR, bh_RDR)] $+ nlHsIf (genPrimOpApp (nlHsVar bh_RDR) ltInt_RDR tag_lit)+ (gtResult op) $ -- Definitely GT+ nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con+ , mkHsCaseAlt nlWildPat (ltResult op) ]++ | otherwise -- upper range is larger+ = untag_Expr dflags tycon [(b_RDR, bh_RDR)] $+ nlHsIf (genPrimOpApp (nlHsVar bh_RDR) gtInt_RDR tag_lit)+ (ltResult op) $ -- Definitely LT+ nlHsCase (nlHsVar b_RDR) [ mkInnerEqAlt op data_con+ , mkHsCaseAlt nlWildPat (gtResult op) ]+ where+ tag = get_tag data_con+ tag_lit = noLoc (HsLit (HsIntPrim NoSourceText (toInteger tag)))++ mkInnerEqAlt :: OrdOp -> DataCon -> LMatch RdrName (LHsExpr RdrName)+ -- First argument 'a' known to be built with K+ -- Returns a case alternative Ki b1 b2 ... bv -> compare (a1,a2,...) with (b1,b2,...)+ mkInnerEqAlt op data_con+ = mkHsCaseAlt (nlConVarPat data_con_RDR bs_needed) $+ mkCompareFields tycon op (dataConOrigArgTys data_con)+ where+ data_con_RDR = getRdrName data_con+ bs_needed = take (dataConSourceArity data_con) bs_RDRs++ mkTagCmp :: DynFlags -> OrdOp -> LHsExpr RdrName+ -- Both constructors known to be nullary+ -- genreates (case data2Tag a of a# -> case data2Tag b of b# -> a# `op` b#+ mkTagCmp dflags op =+ untag_Expr dflags tycon[(a_RDR, ah_RDR),(b_RDR, bh_RDR)] $+ unliftedOrdOp tycon intPrimTy op ah_RDR bh_RDR++mkCompareFields :: TyCon -> OrdOp -> [Type] -> LHsExpr RdrName+-- Generates nested comparisons for (a1,a2...) against (b1,b2,...)+-- where the ai,bi have the given types+mkCompareFields tycon op tys+ = go tys as_RDRs bs_RDRs+ where+ go [] _ _ = eqResult op+ go [ty] (a:_) (b:_)+ | isUnliftedType ty = unliftedOrdOp tycon ty op a b+ | otherwise = genOpApp (nlHsVar a) (ordMethRdr op) (nlHsVar b)+ go (ty:tys) (a:as) (b:bs) = mk_compare ty a b+ (ltResult op)+ (go tys as bs)+ (gtResult op)+ go _ _ _ = panic "mkCompareFields"++ -- (mk_compare ty a b) generates+ -- (case (compare a b) of { LT -> <lt>; EQ -> <eq>; GT -> <bt> })+ -- but with suitable special cases for+ mk_compare ty a b lt eq gt+ | isUnliftedType ty+ = unliftedCompare lt_op eq_op a_expr b_expr lt eq gt+ | otherwise+ = nlHsCase (nlHsPar (nlHsApp (nlHsApp (nlHsVar compare_RDR) a_expr) b_expr))+ [mkHsCaseAlt (nlNullaryConPat ltTag_RDR) lt,+ mkHsCaseAlt (nlNullaryConPat eqTag_RDR) eq,+ mkHsCaseAlt (nlNullaryConPat gtTag_RDR) gt]+ where+ a_expr = nlHsVar a+ b_expr = nlHsVar b+ (lt_op, _, eq_op, _, _) = primOrdOps "Ord" tycon ty++unliftedOrdOp :: TyCon -> Type -> OrdOp -> RdrName -> RdrName -> LHsExpr RdrName+unliftedOrdOp tycon ty op a b+ = case op of+ OrdCompare -> unliftedCompare lt_op eq_op a_expr b_expr+ ltTag_Expr eqTag_Expr gtTag_Expr+ OrdLT -> wrap lt_op+ OrdLE -> wrap le_op+ OrdGE -> wrap ge_op+ OrdGT -> wrap gt_op+ where+ (lt_op, le_op, eq_op, ge_op, gt_op) = primOrdOps "Ord" tycon ty+ wrap prim_op = genPrimOpApp a_expr prim_op b_expr+ a_expr = nlHsVar a+ b_expr = nlHsVar b++unliftedCompare :: RdrName -> RdrName+ -> LHsExpr RdrName -> LHsExpr RdrName -- What to cmpare+ -> LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName -- Three results+ -> LHsExpr RdrName+-- Return (if a < b then lt else if a == b then eq else gt)+unliftedCompare lt_op eq_op a_expr b_expr lt eq gt+ = nlHsIf (ascribeBool $ genPrimOpApp a_expr lt_op b_expr) lt $+ -- Test (<) first, not (==), because the latter+ -- is true less often, so putting it first would+ -- mean more tests (dynamically)+ nlHsIf (ascribeBool $ genPrimOpApp a_expr eq_op b_expr) eq gt+ where+ ascribeBool e = nlExprWithTySig e boolTy++nlConWildPat :: DataCon -> LPat RdrName+-- The pattern (K {})+nlConWildPat con = noLoc (ConPatIn (noLoc (getRdrName con))+ (RecCon (HsRecFields { rec_flds = []+ , rec_dotdot = Nothing })))++{-+************************************************************************+* *+ Enum instances+* *+************************************************************************++@Enum@ can only be derived for enumeration types. For a type+\begin{verbatim}+data Foo ... = N1 | N2 | ... | Nn+\end{verbatim}++we use both @con2tag_Foo@ and @tag2con_Foo@ functions, as well as a+@maxtag_Foo@ variable (all generated by @gen_tag_n_con_binds@).++\begin{verbatim}+instance ... Enum (Foo ...) where+ succ x = toEnum (1 + fromEnum x)+ pred x = toEnum (fromEnum x - 1)++ toEnum i = tag2con_Foo i++ enumFrom a = map tag2con_Foo [con2tag_Foo a .. maxtag_Foo]++ -- or, really...+ enumFrom a+ = case con2tag_Foo a of+ a# -> map tag2con_Foo (enumFromTo (I# a#) maxtag_Foo)++ enumFromThen a b+ = map tag2con_Foo [con2tag_Foo a, con2tag_Foo b .. maxtag_Foo]++ -- or, really...+ enumFromThen a b+ = case con2tag_Foo a of { a# ->+ case con2tag_Foo b of { b# ->+ map tag2con_Foo (enumFromThenTo (I# a#) (I# b#) maxtag_Foo)+ }}+\end{verbatim}++For @enumFromTo@ and @enumFromThenTo@, we use the default methods.+-}++gen_Enum_binds :: SrcSpan -> TyCon -> TcM (LHsBinds RdrName, BagDerivStuff)+gen_Enum_binds loc tycon = do+ dflags <- getDynFlags+ return (method_binds dflags, aux_binds)+ where+ method_binds dflags = listToBag+ [ succ_enum dflags+ , pred_enum dflags+ , to_enum dflags+ , enum_from dflags+ , enum_from_then dflags+ , from_enum dflags+ ]+ aux_binds = listToBag $ map DerivAuxBind+ [DerivCon2Tag tycon, DerivTag2Con tycon, DerivMaxTag tycon]++ occ_nm = getOccString tycon++ succ_enum dflags+ = mk_easy_FunBind loc succ_RDR [a_Pat] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] $+ nlHsIf (nlHsApps eq_RDR [nlHsVar (maxtag_RDR dflags tycon),+ nlHsVarApps intDataCon_RDR [ah_RDR]])+ (illegal_Expr "succ" occ_nm "tried to take `succ' of last tag in enumeration")+ (nlHsApp (nlHsVar (tag2con_RDR dflags tycon))+ (nlHsApps plus_RDR [nlHsVarApps intDataCon_RDR [ah_RDR],+ nlHsIntLit 1]))++ pred_enum dflags+ = mk_easy_FunBind loc pred_RDR [a_Pat] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] $+ nlHsIf (nlHsApps eq_RDR [nlHsIntLit 0,+ nlHsVarApps intDataCon_RDR [ah_RDR]])+ (illegal_Expr "pred" occ_nm "tried to take `pred' of first tag in enumeration")+ (nlHsApp (nlHsVar (tag2con_RDR dflags tycon))+ (nlHsApps plus_RDR [nlHsVarApps intDataCon_RDR [ah_RDR],+ nlHsLit (HsInt NoSourceText (-1))]))++ to_enum dflags+ = mk_easy_FunBind loc toEnum_RDR [a_Pat] $+ nlHsIf (nlHsApps and_RDR+ [nlHsApps ge_RDR [nlHsVar a_RDR, nlHsIntLit 0],+ nlHsApps le_RDR [ nlHsVar a_RDR+ , nlHsVar (maxtag_RDR dflags tycon)]])+ (nlHsVarApps (tag2con_RDR dflags tycon) [a_RDR])+ (illegal_toEnum_tag occ_nm (maxtag_RDR dflags tycon))++ enum_from dflags+ = mk_easy_FunBind loc enumFrom_RDR [a_Pat] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] $+ nlHsApps map_RDR+ [nlHsVar (tag2con_RDR dflags tycon),+ nlHsPar (enum_from_to_Expr+ (nlHsVarApps intDataCon_RDR [ah_RDR])+ (nlHsVar (maxtag_RDR dflags tycon)))]++ enum_from_then dflags+ = mk_easy_FunBind loc enumFromThen_RDR [a_Pat, b_Pat] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR), (b_RDR, bh_RDR)] $+ nlHsApp (nlHsVarApps map_RDR [tag2con_RDR dflags tycon]) $+ nlHsPar (enum_from_then_to_Expr+ (nlHsVarApps intDataCon_RDR [ah_RDR])+ (nlHsVarApps intDataCon_RDR [bh_RDR])+ (nlHsIf (nlHsApps gt_RDR [nlHsVarApps intDataCon_RDR [ah_RDR],+ nlHsVarApps intDataCon_RDR [bh_RDR]])+ (nlHsIntLit 0)+ (nlHsVar (maxtag_RDR dflags tycon))+ ))++ from_enum dflags+ = mk_easy_FunBind loc fromEnum_RDR [a_Pat] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] $+ (nlHsVarApps intDataCon_RDR [ah_RDR])++{-+************************************************************************+* *+ Bounded instances+* *+************************************************************************+-}++gen_Bounded_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)+gen_Bounded_binds loc tycon+ | isEnumerationTyCon tycon+ = (listToBag [ min_bound_enum, max_bound_enum ], emptyBag)+ | otherwise+ = ASSERT(isSingleton data_cons)+ (listToBag [ min_bound_1con, max_bound_1con ], emptyBag)+ where+ data_cons = tyConDataCons tycon++ ----- enum-flavored: ---------------------------+ min_bound_enum = mkHsVarBind loc minBound_RDR (nlHsVar data_con_1_RDR)+ max_bound_enum = mkHsVarBind loc maxBound_RDR (nlHsVar data_con_N_RDR)++ data_con_1 = head data_cons+ data_con_N = last data_cons+ data_con_1_RDR = getRdrName data_con_1+ data_con_N_RDR = getRdrName data_con_N++ ----- single-constructor-flavored: -------------+ arity = dataConSourceArity data_con_1++ min_bound_1con = mkHsVarBind loc minBound_RDR $+ nlHsVarApps data_con_1_RDR (nOfThem arity minBound_RDR)+ max_bound_1con = mkHsVarBind loc maxBound_RDR $+ nlHsVarApps data_con_1_RDR (nOfThem arity maxBound_RDR)++{-+************************************************************************+* *+ Ix instances+* *+************************************************************************++Deriving @Ix@ is only possible for enumeration types and+single-constructor types. We deal with them in turn.++For an enumeration type, e.g.,+\begin{verbatim}+ data Foo ... = N1 | N2 | ... | Nn+\end{verbatim}+things go not too differently from @Enum@:+\begin{verbatim}+instance ... Ix (Foo ...) where+ range (a, b)+ = map tag2con_Foo [con2tag_Foo a .. con2tag_Foo b]++ -- or, really...+ range (a, b)+ = case (con2tag_Foo a) of { a# ->+ case (con2tag_Foo b) of { b# ->+ map tag2con_Foo (enumFromTo (I# a#) (I# b#))+ }}++ -- Generate code for unsafeIndex, because using index leads+ -- to lots of redundant range tests+ unsafeIndex c@(a, b) d+ = case (con2tag_Foo d -# con2tag_Foo a) of+ r# -> I# r#++ inRange (a, b) c+ = let+ p_tag = con2tag_Foo c+ in+ p_tag >= con2tag_Foo a && p_tag <= con2tag_Foo b++ -- or, really...+ inRange (a, b) c+ = case (con2tag_Foo a) of { a_tag ->+ case (con2tag_Foo b) of { b_tag ->+ case (con2tag_Foo c) of { c_tag ->+ if (c_tag >=# a_tag) then+ c_tag <=# b_tag+ else+ False+ }}}+\end{verbatim}+(modulo suitable case-ification to handle the unlifted tags)++For a single-constructor type (NB: this includes all tuples), e.g.,+\begin{verbatim}+ data Foo ... = MkFoo a b Int Double c c+\end{verbatim}+we follow the scheme given in Figure~19 of the Haskell~1.2 report+(p.~147).+-}++gen_Ix_binds :: SrcSpan -> TyCon -> TcM (LHsBinds RdrName, BagDerivStuff)++gen_Ix_binds loc tycon = do+ dflags <- getDynFlags+ return $ if isEnumerationTyCon tycon+ then (enum_ixes dflags, listToBag $ map DerivAuxBind+ [DerivCon2Tag tycon, DerivTag2Con tycon, DerivMaxTag tycon])+ else (single_con_ixes, unitBag (DerivAuxBind (DerivCon2Tag tycon)))+ where+ --------------------------------------------------------------+ enum_ixes dflags = listToBag+ [ enum_range dflags+ , enum_index dflags+ , enum_inRange dflags+ ]++ enum_range dflags+ = mk_easy_FunBind loc range_RDR [nlTuplePat [a_Pat, b_Pat] Boxed] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] $+ untag_Expr dflags tycon [(b_RDR, bh_RDR)] $+ nlHsApp (nlHsVarApps map_RDR [tag2con_RDR dflags tycon]) $+ nlHsPar (enum_from_to_Expr+ (nlHsVarApps intDataCon_RDR [ah_RDR])+ (nlHsVarApps intDataCon_RDR [bh_RDR]))++ enum_index dflags+ = mk_easy_FunBind loc unsafeIndex_RDR+ [noLoc (AsPat (noLoc c_RDR)+ (nlTuplePat [a_Pat, nlWildPat] Boxed)),+ d_Pat] (+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] (+ untag_Expr dflags tycon [(d_RDR, dh_RDR)] (+ let+ rhs = nlHsVarApps intDataCon_RDR [c_RDR]+ in+ nlHsCase+ (genOpApp (nlHsVar dh_RDR) minusInt_RDR (nlHsVar ah_RDR))+ [mkHsCaseAlt (nlVarPat c_RDR) rhs]+ ))+ )++ -- This produces something like `(ch >= ah) && (ch <= bh)`+ enum_inRange dflags+ = mk_easy_FunBind loc inRange_RDR [nlTuplePat [a_Pat, b_Pat] Boxed, c_Pat] $+ untag_Expr dflags tycon [(a_RDR, ah_RDR)] (+ untag_Expr dflags tycon [(b_RDR, bh_RDR)] (+ untag_Expr dflags tycon [(c_RDR, ch_RDR)] (+ -- This used to use `if`, which interacts badly with RebindableSyntax.+ -- See #11396.+ nlHsApps and_RDR+ [ genPrimOpApp (nlHsVar ch_RDR) geInt_RDR (nlHsVar ah_RDR)+ , genPrimOpApp (nlHsVar ch_RDR) leInt_RDR (nlHsVar bh_RDR)+ ]+ )))++ --------------------------------------------------------------+ single_con_ixes+ = listToBag [single_con_range, single_con_index, single_con_inRange]++ data_con+ = case tyConSingleDataCon_maybe tycon of -- just checking...+ Nothing -> panic "get_Ix_binds"+ Just dc -> dc++ con_arity = dataConSourceArity data_con+ data_con_RDR = getRdrName data_con++ as_needed = take con_arity as_RDRs+ bs_needed = take con_arity bs_RDRs+ cs_needed = take con_arity cs_RDRs++ con_pat xs = nlConVarPat data_con_RDR xs+ con_expr = nlHsVarApps data_con_RDR cs_needed++ --------------------------------------------------------------+ single_con_range+ = mk_easy_FunBind loc range_RDR+ [nlTuplePat [con_pat as_needed, con_pat bs_needed] Boxed] $+ noLoc (mkHsComp ListComp stmts con_expr)+ where+ stmts = zipWith3Equal "single_con_range" mk_qual as_needed bs_needed cs_needed++ mk_qual a b c = noLoc $ mkBindStmt (nlVarPat c)+ (nlHsApp (nlHsVar range_RDR)+ (mkLHsVarTuple [a,b]))++ ----------------+ single_con_index+ = mk_easy_FunBind loc unsafeIndex_RDR+ [nlTuplePat [con_pat as_needed, con_pat bs_needed] Boxed,+ con_pat cs_needed]+ -- We need to reverse the order we consider the components in+ -- so that+ -- range (l,u) !! index (l,u) i == i -- when i is in range+ -- (from http://haskell.org/onlinereport/ix.html) holds.+ (mk_index (reverse $ zip3 as_needed bs_needed cs_needed))+ where+ -- index (l1,u1) i1 + rangeSize (l1,u1) * (index (l2,u2) i2 + ...)+ mk_index [] = nlHsIntLit 0+ mk_index [(l,u,i)] = mk_one l u i+ mk_index ((l,u,i) : rest)+ = genOpApp (+ mk_one l u i+ ) plus_RDR (+ genOpApp (+ (nlHsApp (nlHsVar unsafeRangeSize_RDR)+ (mkLHsVarTuple [l,u]))+ ) times_RDR (mk_index rest)+ )+ mk_one l u i+ = nlHsApps unsafeIndex_RDR [mkLHsVarTuple [l,u], nlHsVar i]++ ------------------+ single_con_inRange+ = mk_easy_FunBind loc inRange_RDR+ [nlTuplePat [con_pat as_needed, con_pat bs_needed] Boxed,+ con_pat cs_needed] $+ if con_arity == 0+ -- If the product type has no fields, inRange is trivially true+ -- (see Trac #12853).+ then true_Expr+ else foldl1 and_Expr (zipWith3Equal "single_con_inRange" in_range+ as_needed bs_needed cs_needed)+ where+ in_range a b c = nlHsApps inRange_RDR [mkLHsVarTuple [a,b], nlHsVar c]++{-+************************************************************************+* *+ Read instances+* *+************************************************************************++Example++ infix 4 %%+ data T = Int %% Int+ | T1 { f1 :: Int }+ | T2 T++instance Read T where+ readPrec =+ parens+ ( prec 4 (+ do x <- ReadP.step Read.readPrec+ expectP (Symbol "%%")+ y <- ReadP.step Read.readPrec+ return (x %% y))+ ++++ prec (appPrec+1) (+ -- Note the "+1" part; "T2 T1 {f1=3}" should parse ok+ -- Record construction binds even more tightly than application+ do expectP (Ident "T1")+ expectP (Punc '{')+ expectP (Ident "f1")+ expectP (Punc '=')+ x <- ReadP.reset Read.readPrec+ expectP (Punc '}')+ return (T1 { f1 = x }))+ ++++ prec appPrec (+ do expectP (Ident "T2")+ x <- ReadP.step Read.readPrec+ return (T2 x))+ )++ readListPrec = readListPrecDefault+ readList = readListDefault+++Note [Use expectP]+~~~~~~~~~~~~~~~~~~+Note that we use+ expectP (Ident "T1")+rather than+ Ident "T1" <- lexP+The latter desugares to inline code for matching the Ident and the+string, and this can be very voluminous. The former is much more+compact. Cf Trac #7258, although that also concerned non-linearity in+the occurrence analyser, a separate issue.++Note [Read for empty data types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+What should we get for this? (Trac #7931)+ data Emp deriving( Read ) -- No data constructors++Here we want+ read "[]" :: [Emp] to succeed, returning []+So we do NOT want+ instance Read Emp where+ readPrec = error "urk"+Rather we want+ instance Read Emp where+ readPred = pfail -- Same as choose []++Because 'pfail' allows the parser to backtrack, but 'error' doesn't.+These instances are also useful for Read (Either Int Emp), where+we want to be able to parse (Left 3) just fine.+-}++gen_Read_binds :: (Name -> Fixity) -> SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)++gen_Read_binds get_fixity loc tycon+ = (listToBag [read_prec, default_readlist, default_readlistprec], emptyBag)+ where+ -----------------------------------------------------------------------+ default_readlist+ = mkHsVarBind loc readList_RDR (nlHsVar readListDefault_RDR)++ default_readlistprec+ = mkHsVarBind loc readListPrec_RDR (nlHsVar readListPrecDefault_RDR)+ -----------------------------------------------------------------------++ data_cons = tyConDataCons tycon+ (nullary_cons, non_nullary_cons) = partition isNullarySrcDataCon data_cons++ read_prec = mkHsVarBind loc readPrec_RDR+ (nlHsApp (nlHsVar parens_RDR) read_cons)++ read_cons | null data_cons = nlHsVar pfail_RDR -- See Note [Read for empty data types]+ | otherwise = foldr1 mk_alt (read_nullary_cons ++ read_non_nullary_cons)+ read_non_nullary_cons = map read_non_nullary_con non_nullary_cons++ read_nullary_cons+ = case nullary_cons of+ [] -> []+ [con] -> [nlHsDo DoExpr (match_con con ++ [noLoc $ mkLastStmt (result_expr con [])])]+ _ -> [nlHsApp (nlHsVar choose_RDR)+ (nlList (map mk_pair nullary_cons))]+ -- NB For operators the parens around (:=:) are matched by the+ -- enclosing "parens" call, so here we must match the naked+ -- data_con_str con++ match_con con | isSym con_str = [symbol_pat con_str]+ | otherwise = ident_h_pat con_str+ where+ con_str = data_con_str con+ -- For nullary constructors we must match Ident s for normal constrs+ -- and Symbol s for operators++ mk_pair con = mkLHsTupleExpr [nlHsLit (mkHsString (data_con_str con)),+ result_expr con []]++ read_non_nullary_con data_con+ | is_infix = mk_parser infix_prec infix_stmts body+ | is_record = mk_parser record_prec record_stmts body+-- Using these two lines instead allows the derived+-- read for infix and record bindings to read the prefix form+-- | is_infix = mk_alt prefix_parser (mk_parser infix_prec infix_stmts body)+-- | is_record = mk_alt prefix_parser (mk_parser record_prec record_stmts body)+ | otherwise = prefix_parser+ where+ body = result_expr data_con as_needed+ con_str = data_con_str data_con++ prefix_parser = mk_parser prefix_prec prefix_stmts body++ read_prefix_con+ | isSym con_str = [read_punc "(", symbol_pat con_str, read_punc ")"]+ | otherwise = ident_h_pat con_str++ read_infix_con+ | isSym con_str = [symbol_pat con_str]+ | otherwise = [read_punc "`"] ++ ident_h_pat con_str ++ [read_punc "`"]++ prefix_stmts -- T a b c+ = read_prefix_con ++ read_args++ infix_stmts -- a %% b, or a `T` b+ = [read_a1]+ ++ read_infix_con+ ++ [read_a2]++ record_stmts -- T { f1 = a, f2 = b }+ = read_prefix_con+ ++ [read_punc "{"]+ ++ concat (intersperse [read_punc ","] field_stmts)+ ++ [read_punc "}"]++ field_stmts = zipWithEqual "lbl_stmts" read_field labels as_needed++ con_arity = dataConSourceArity data_con+ labels = map flLabel $ dataConFieldLabels data_con+ dc_nm = getName data_con+ is_infix = dataConIsInfix data_con+ is_record = length labels > 0+ as_needed = take con_arity as_RDRs+ read_args = zipWithEqual "gen_Read_binds" read_arg as_needed (dataConOrigArgTys data_con)+ (read_a1:read_a2:_) = read_args++ prefix_prec = appPrecedence+ infix_prec = getPrecedence get_fixity dc_nm+ record_prec = appPrecedence + 1 -- Record construction binds even more tightly+ -- than application; e.g. T2 T1 {x=2} means T2 (T1 {x=2})++ ------------------------------------------------------------------------+ -- Helpers+ ------------------------------------------------------------------------+ mk_alt e1 e2 = genOpApp e1 alt_RDR e2 -- e1 +++ e2+ mk_parser p ss b = nlHsApps prec_RDR [nlHsIntLit p -- prec p (do { ss ; b })+ , nlHsDo DoExpr (ss ++ [noLoc $ mkLastStmt b])]+ con_app con as = nlHsVarApps (getRdrName con) as -- con as+ result_expr con as = nlHsApp (nlHsVar returnM_RDR) (con_app con as) -- return (con as)++ -- For constructors and field labels ending in '#', we hackily+ -- let the lexer generate two tokens, and look for both in sequence+ -- Thus [Ident "I"; Symbol "#"]. See Trac #5041+ ident_h_pat s | Just (ss, '#') <- snocView s = [ ident_pat ss, symbol_pat "#" ]+ | otherwise = [ ident_pat s ]++ bindLex pat = noLoc (mkBodyStmt (nlHsApp (nlHsVar expectP_RDR) pat)) -- expectP p+ -- See Note [Use expectP]+ ident_pat s = bindLex $ nlHsApps ident_RDR [nlHsLit (mkHsString s)] -- expectP (Ident "foo")+ symbol_pat s = bindLex $ nlHsApps symbol_RDR [nlHsLit (mkHsString s)] -- expectP (Symbol ">>")+ read_punc c = bindLex $ nlHsApps punc_RDR [nlHsLit (mkHsString c)] -- expectP (Punc "<")++ data_con_str con = occNameString (getOccName con)++ read_arg a ty = ASSERT( not (isUnliftedType ty) )+ noLoc (mkBindStmt (nlVarPat a) (nlHsVarApps step_RDR [readPrec_RDR]))++ read_field lbl a = read_lbl lbl +++ [read_punc "=",+ noLoc (mkBindStmt (nlVarPat a) (nlHsVarApps reset_RDR [readPrec_RDR]))]++ -- When reading field labels we might encounter+ -- a = 3+ -- _a = 3+ -- or (#) = 4+ -- Note the parens!+ read_lbl lbl | isSym lbl_str+ = [read_punc "(", symbol_pat lbl_str, read_punc ")"]+ | otherwise+ = ident_h_pat lbl_str+ where+ lbl_str = unpackFS lbl++{-+************************************************************************+* *+ Show instances+* *+************************************************************************++Example++ infixr 5 :^:++ data Tree a = Leaf a | Tree a :^: Tree a++ instance (Show a) => Show (Tree a) where++ showsPrec d (Leaf m) = showParen (d > app_prec) showStr+ where+ showStr = showString "Leaf " . showsPrec (app_prec+1) m++ showsPrec d (u :^: v) = showParen (d > up_prec) showStr+ where+ showStr = showsPrec (up_prec+1) u .+ showString " :^: " .+ showsPrec (up_prec+1) v+ -- Note: right-associativity of :^: ignored++ up_prec = 5 -- Precedence of :^:+ app_prec = 10 -- Application has precedence one more than+ -- the most tightly-binding operator+-}++gen_Show_binds :: (Name -> Fixity) -> SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)++gen_Show_binds get_fixity loc tycon+ = (listToBag [shows_prec, show_list], emptyBag)+ where+ -----------------------------------------------------------------------+ show_list = mkHsVarBind loc showList_RDR+ (nlHsApp (nlHsVar showList___RDR) (nlHsPar (nlHsApp (nlHsVar showsPrec_RDR) (nlHsIntLit 0))))+ -----------------------------------------------------------------------+ data_cons = tyConDataCons tycon+ shows_prec = mk_FunBind loc showsPrec_RDR (map pats_etc data_cons)+ comma_space = nlHsVar showCommaSpace_RDR++ pats_etc data_con+ | nullary_con = -- skip the showParen junk...+ ASSERT(null bs_needed)+ ([nlWildPat, con_pat], mk_showString_app op_con_str)+ | otherwise =+ ([a_Pat, con_pat],+ showParen_Expr (genOpApp a_Expr ge_RDR+ (nlHsLit (HsInt NoSourceText con_prec_plus_one)))+ (nlHsPar (nested_compose_Expr show_thingies)))+ where+ data_con_RDR = getRdrName data_con+ con_arity = dataConSourceArity data_con+ bs_needed = take con_arity bs_RDRs+ arg_tys = dataConOrigArgTys data_con -- Correspond 1-1 with bs_needed+ con_pat = nlConVarPat data_con_RDR bs_needed+ nullary_con = con_arity == 0+ labels = map flLabel $ dataConFieldLabels data_con+ lab_fields = length labels+ record_syntax = lab_fields > 0++ dc_nm = getName data_con+ dc_occ_nm = getOccName data_con+ con_str = occNameString dc_occ_nm+ op_con_str = wrapOpParens con_str+ backquote_str = wrapOpBackquotes con_str++ show_thingies+ | is_infix = [show_arg1, mk_showString_app (" " ++ backquote_str ++ " "), show_arg2]+ | record_syntax = mk_showString_app (op_con_str ++ " {") :+ show_record_args ++ [mk_showString_app "}"]+ | otherwise = mk_showString_app (op_con_str ++ " ") : show_prefix_args++ show_label l = mk_showString_app (nm ++ " = ")+ -- Note the spaces around the "=" sign. If we+ -- don't have them then we get Foo { x=-1 } and+ -- the "=-" parses as a single lexeme. Only the+ -- space after the '=' is necessary, but it+ -- seems tidier to have them both sides.+ where+ nm = wrapOpParens (unpackFS l)++ show_args = zipWith show_arg bs_needed arg_tys+ (show_arg1:show_arg2:_) = show_args+ show_prefix_args = intersperse (nlHsVar showSpace_RDR) show_args++ -- Assumption for record syntax: no of fields == no of+ -- labelled fields (and in same order)+ show_record_args = concat $+ intersperse [comma_space] $+ [ [show_label lbl, arg]+ | (lbl,arg) <- zipEqual "gen_Show_binds"+ labels show_args ]++ show_arg :: RdrName -> Type -> LHsExpr RdrName+ show_arg b arg_ty+ | isUnliftedType arg_ty+ -- See Note [Deriving and unboxed types] in TcDeriv+ = nlHsApps compose_RDR [mk_shows_app boxed_arg,+ mk_showString_app postfixMod]+ | otherwise+ = mk_showsPrec_app arg_prec arg+ where+ arg = nlHsVar b+ boxed_arg = box "Show" tycon arg arg_ty+ postfixMod = assoc_ty_id "Show" tycon postfixModTbl arg_ty++ -- Fixity stuff+ is_infix = dataConIsInfix data_con+ con_prec_plus_one = 1 + getPrec is_infix get_fixity dc_nm+ arg_prec | record_syntax = 0 -- Record fields don't need parens+ | otherwise = con_prec_plus_one++wrapOpParens :: String -> String+wrapOpParens s | isSym s = '(' : s ++ ")"+ | otherwise = s++wrapOpBackquotes :: String -> String+wrapOpBackquotes s | isSym s = s+ | otherwise = '`' : s ++ "`"++isSym :: String -> Bool+isSym "" = False+isSym (c : _) = startsVarSym c || startsConSym c++-- | showString :: String -> ShowS+mk_showString_app :: String -> LHsExpr RdrName+mk_showString_app str = nlHsApp (nlHsVar showString_RDR) (nlHsLit (mkHsString str))++-- | showsPrec :: Show a => Int -> a -> ShowS+mk_showsPrec_app :: Integer -> LHsExpr RdrName -> LHsExpr RdrName+mk_showsPrec_app p x+ = nlHsApps showsPrec_RDR [nlHsLit (HsInt NoSourceText p), x]++-- | shows :: Show a => a -> ShowS+mk_shows_app :: LHsExpr RdrName -> LHsExpr RdrName+mk_shows_app x = nlHsApp (nlHsVar shows_RDR) x++getPrec :: Bool -> (Name -> Fixity) -> Name -> Integer+getPrec is_infix get_fixity nm+ | not is_infix = appPrecedence+ | otherwise = getPrecedence get_fixity nm++appPrecedence :: Integer+appPrecedence = fromIntegral maxPrecedence + 1+ -- One more than the precedence of the most+ -- tightly-binding operator++getPrecedence :: (Name -> Fixity) -> Name -> Integer+getPrecedence get_fixity nm+ = case get_fixity nm of+ Fixity _ x _assoc -> fromIntegral x+ -- NB: the Report says that associativity is not taken+ -- into account for either Read or Show; hence we+ -- ignore associativity here++{-+************************************************************************+* *+ Data instances+* *+************************************************************************++From the data type++ data T a b = T1 a b | T2++we generate++ $cT1 = mkDataCon $dT "T1" Prefix+ $cT2 = mkDataCon $dT "T2" Prefix+ $dT = mkDataType "Module.T" [] [$con_T1, $con_T2]+ -- the [] is for field labels.++ instance (Data a, Data b) => Data (T a b) where+ gfoldl k z (T1 a b) = z T `k` a `k` b+ gfoldl k z T2 = z T2+ -- ToDo: add gmapT,Q,M, gfoldr++ gunfold k z c = case conIndex c of+ I# 1# -> k (k (z T1))+ I# 2# -> z T2++ toConstr (T1 _ _) = $cT1+ toConstr T2 = $cT2++ dataTypeOf _ = $dT++ dataCast1 = gcast1 -- If T :: * -> *+ dataCast2 = gcast2 -- if T :: * -> * -> *+-}++gen_Data_binds :: SrcSpan+ -> TyCon -- For data families, this is the+ -- *representation* TyCon+ -> TcM (LHsBinds RdrName, -- The method bindings+ BagDerivStuff) -- Auxiliary bindings+gen_Data_binds loc rep_tc+ = do { dflags <- getDynFlags++ -- Make unique names for the data type and constructor+ -- auxiliary bindings. Start with the name of the TyCon/DataCon+ -- but that might not be unique: see Trac #12245.+ ; dt_occ <- chooseUniqueOccTc (mkDataTOcc (getOccName rep_tc))+ ; dc_occs <- mapM (chooseUniqueOccTc . mkDataCOcc . getOccName)+ (tyConDataCons rep_tc)+ ; let dt_rdr = mkRdrUnqual dt_occ+ dc_rdrs = map mkRdrUnqual dc_occs++ -- OK, now do the work+ ; return (gen_data dflags dt_rdr dc_rdrs loc rep_tc) }++gen_data :: DynFlags -> RdrName -> [RdrName]+ -> SrcSpan -> TyCon+ -> (LHsBinds RdrName, -- The method bindings+ BagDerivStuff) -- Auxiliary bindings+gen_data dflags data_type_name constr_names loc rep_tc+ = (listToBag [gfoldl_bind, gunfold_bind, toCon_bind, dataTypeOf_bind]+ `unionBags` gcast_binds,+ -- Auxiliary definitions: the data type and constructors+ listToBag ( genDataTyCon+ : zipWith genDataDataCon data_cons constr_names ) )+ where+ data_cons = tyConDataCons rep_tc+ n_cons = length data_cons+ one_constr = n_cons == 1+ genDataTyCon :: DerivStuff+ genDataTyCon -- $dT+ = DerivHsBind (mkHsVarBind loc data_type_name rhs,+ L loc (TypeSig [L loc data_type_name] sig_ty))++ sig_ty = mkLHsSigWcType (nlHsTyVar dataType_RDR)+ rhs = nlHsVar mkDataType_RDR+ `nlHsApp` nlHsLit (mkHsString (showSDocOneLine dflags (ppr rep_tc)))+ `nlHsApp` nlList (map nlHsVar constr_names)++ genDataDataCon :: DataCon -> RdrName -> DerivStuff+ genDataDataCon dc constr_name -- $cT1 etc+ = DerivHsBind (mkHsVarBind loc constr_name rhs,+ L loc (TypeSig [L loc constr_name] sig_ty))+ where+ sig_ty = mkLHsSigWcType (nlHsTyVar constr_RDR)+ rhs = nlHsApps mkConstr_RDR constr_args++ constr_args+ = [ -- nlHsIntLit (toInteger (dataConTag dc)), -- Tag+ nlHsVar (data_type_name) -- DataType+ , nlHsLit (mkHsString (occNameString dc_occ)) -- String name+ , nlList labels -- Field labels+ , nlHsVar fixity ] -- Fixity++ labels = map (nlHsLit . mkHsString . unpackFS . flLabel)+ (dataConFieldLabels dc)+ dc_occ = getOccName dc+ is_infix = isDataSymOcc dc_occ+ fixity | is_infix = infix_RDR+ | otherwise = prefix_RDR++ ------------ gfoldl+ gfoldl_bind = mk_HRFunBind 2 loc gfoldl_RDR (map gfoldl_eqn data_cons)++ gfoldl_eqn con+ = ([nlVarPat k_RDR, nlVarPat z_RDR, nlConVarPat con_name as_needed],+ foldl mk_k_app (nlHsVar z_RDR `nlHsApp` nlHsVar con_name) as_needed)+ where+ con_name :: RdrName+ con_name = getRdrName con+ as_needed = take (dataConSourceArity con) as_RDRs+ mk_k_app e v = nlHsPar (nlHsOpApp e k_RDR (nlHsVar v))++ ------------ gunfold+ gunfold_bind = mk_HRFunBind 2 loc+ gunfold_RDR+ [([k_Pat, z_Pat, if one_constr then nlWildPat else c_Pat],+ gunfold_rhs)]++ gunfold_rhs+ | one_constr = mk_unfold_rhs (head data_cons) -- No need for case+ | otherwise = nlHsCase (nlHsVar conIndex_RDR `nlHsApp` c_Expr)+ (map gunfold_alt data_cons)++ gunfold_alt dc = mkHsCaseAlt (mk_unfold_pat dc) (mk_unfold_rhs dc)+ mk_unfold_rhs dc = foldr nlHsApp+ (nlHsVar z_RDR `nlHsApp` nlHsVar (getRdrName dc))+ (replicate (dataConSourceArity dc) (nlHsVar k_RDR))++ mk_unfold_pat dc -- Last one is a wild-pat, to avoid+ -- redundant test, and annoying warning+ | tag-fIRST_TAG == n_cons-1 = nlWildPat -- Last constructor+ | otherwise = nlConPat intDataCon_RDR+ [nlLitPat (HsIntPrim NoSourceText (toInteger tag))]+ where+ tag = dataConTag dc++ ------------ toConstr+ toCon_bind = mk_FunBind loc toConstr_RDR (zipWith to_con_eqn data_cons constr_names)+ to_con_eqn dc con_name = ([nlWildConPat dc], nlHsVar con_name)++ ------------ dataTypeOf+ dataTypeOf_bind = mk_easy_FunBind+ loc+ dataTypeOf_RDR+ [nlWildPat]+ (nlHsVar data_type_name)++ ------------ gcast1/2+ -- Make the binding dataCast1 x = gcast1 x -- if T :: * -> *+ -- or dataCast2 x = gcast2 s -- if T :: * -> * -> *+ -- (or nothing if T has neither of these two types)++ -- But care is needed for data families:+ -- If we have data family D a+ -- data instance D (a,b,c) = A | B deriving( Data )+ -- and we want instance ... => Data (D [(a,b,c)]) where ...+ -- then we need dataCast1 x = gcast1 x+ -- because D :: * -> *+ -- even though rep_tc has kind * -> * -> * -> *+ -- Hence looking for the kind of fam_tc not rep_tc+ -- See Trac #4896+ tycon_kind = case tyConFamInst_maybe rep_tc of+ Just (fam_tc, _) -> tyConKind fam_tc+ Nothing -> tyConKind rep_tc+ gcast_binds | tycon_kind `tcEqKind` kind1 = mk_gcast dataCast1_RDR gcast1_RDR+ | tycon_kind `tcEqKind` kind2 = mk_gcast dataCast2_RDR gcast2_RDR+ | otherwise = emptyBag+ mk_gcast dataCast_RDR gcast_RDR+ = unitBag (mk_easy_FunBind loc dataCast_RDR [nlVarPat f_RDR]+ (nlHsVar gcast_RDR `nlHsApp` nlHsVar f_RDR))+++kind1, kind2 :: Kind+kind1 = liftedTypeKind `mkFunTy` liftedTypeKind+kind2 = liftedTypeKind `mkFunTy` kind1++gfoldl_RDR, gunfold_RDR, toConstr_RDR, dataTypeOf_RDR, mkConstr_RDR,+ mkDataType_RDR, conIndex_RDR, prefix_RDR, infix_RDR,+ dataCast1_RDR, dataCast2_RDR, gcast1_RDR, gcast2_RDR,+ constr_RDR, dataType_RDR,+ eqChar_RDR , ltChar_RDR , geChar_RDR , gtChar_RDR , leChar_RDR ,+ eqInt_RDR , ltInt_RDR , geInt_RDR , gtInt_RDR , leInt_RDR ,+ eqWord_RDR , ltWord_RDR , geWord_RDR , gtWord_RDR , leWord_RDR ,+ eqAddr_RDR , ltAddr_RDR , geAddr_RDR , gtAddr_RDR , leAddr_RDR ,+ eqFloat_RDR , ltFloat_RDR , geFloat_RDR , gtFloat_RDR , leFloat_RDR ,+ eqDouble_RDR, ltDouble_RDR, geDouble_RDR, gtDouble_RDR, leDouble_RDR :: RdrName+gfoldl_RDR = varQual_RDR gENERICS (fsLit "gfoldl")+gunfold_RDR = varQual_RDR gENERICS (fsLit "gunfold")+toConstr_RDR = varQual_RDR gENERICS (fsLit "toConstr")+dataTypeOf_RDR = varQual_RDR gENERICS (fsLit "dataTypeOf")+dataCast1_RDR = varQual_RDR gENERICS (fsLit "dataCast1")+dataCast2_RDR = varQual_RDR gENERICS (fsLit "dataCast2")+gcast1_RDR = varQual_RDR tYPEABLE (fsLit "gcast1")+gcast2_RDR = varQual_RDR tYPEABLE (fsLit "gcast2")+mkConstr_RDR = varQual_RDR gENERICS (fsLit "mkConstr")+constr_RDR = tcQual_RDR gENERICS (fsLit "Constr")+mkDataType_RDR = varQual_RDR gENERICS (fsLit "mkDataType")+dataType_RDR = tcQual_RDR gENERICS (fsLit "DataType")+conIndex_RDR = varQual_RDR gENERICS (fsLit "constrIndex")+prefix_RDR = dataQual_RDR gENERICS (fsLit "Prefix")+infix_RDR = dataQual_RDR gENERICS (fsLit "Infix")++eqChar_RDR = varQual_RDR gHC_PRIM (fsLit "eqChar#")+ltChar_RDR = varQual_RDR gHC_PRIM (fsLit "ltChar#")+leChar_RDR = varQual_RDR gHC_PRIM (fsLit "leChar#")+gtChar_RDR = varQual_RDR gHC_PRIM (fsLit "gtChar#")+geChar_RDR = varQual_RDR gHC_PRIM (fsLit "geChar#")++eqInt_RDR = varQual_RDR gHC_PRIM (fsLit "==#")+ltInt_RDR = varQual_RDR gHC_PRIM (fsLit "<#" )+leInt_RDR = varQual_RDR gHC_PRIM (fsLit "<=#")+gtInt_RDR = varQual_RDR gHC_PRIM (fsLit ">#" )+geInt_RDR = varQual_RDR gHC_PRIM (fsLit ">=#")++eqWord_RDR = varQual_RDR gHC_PRIM (fsLit "eqWord#")+ltWord_RDR = varQual_RDR gHC_PRIM (fsLit "ltWord#")+leWord_RDR = varQual_RDR gHC_PRIM (fsLit "leWord#")+gtWord_RDR = varQual_RDR gHC_PRIM (fsLit "gtWord#")+geWord_RDR = varQual_RDR gHC_PRIM (fsLit "geWord#")++eqAddr_RDR = varQual_RDR gHC_PRIM (fsLit "eqAddr#")+ltAddr_RDR = varQual_RDR gHC_PRIM (fsLit "ltAddr#")+leAddr_RDR = varQual_RDR gHC_PRIM (fsLit "leAddr#")+gtAddr_RDR = varQual_RDR gHC_PRIM (fsLit "gtAddr#")+geAddr_RDR = varQual_RDR gHC_PRIM (fsLit "geAddr#")++eqFloat_RDR = varQual_RDR gHC_PRIM (fsLit "eqFloat#")+ltFloat_RDR = varQual_RDR gHC_PRIM (fsLit "ltFloat#")+leFloat_RDR = varQual_RDR gHC_PRIM (fsLit "leFloat#")+gtFloat_RDR = varQual_RDR gHC_PRIM (fsLit "gtFloat#")+geFloat_RDR = varQual_RDR gHC_PRIM (fsLit "geFloat#")++eqDouble_RDR = varQual_RDR gHC_PRIM (fsLit "==##")+ltDouble_RDR = varQual_RDR gHC_PRIM (fsLit "<##" )+leDouble_RDR = varQual_RDR gHC_PRIM (fsLit "<=##")+gtDouble_RDR = varQual_RDR gHC_PRIM (fsLit ">##" )+geDouble_RDR = varQual_RDR gHC_PRIM (fsLit ">=##")++{-+************************************************************************+* *+ Lift instances+* *+************************************************************************++Example:++ data Foo a = Foo a | a :^: a deriving Lift++ ==>++ instance (Lift a) => Lift (Foo a) where+ lift (Foo a)+ = appE+ (conE+ (mkNameG_d "package-name" "ModuleName" "Foo"))+ (lift a)+ lift (u :^: v)+ = infixApp+ (lift u)+ (conE+ (mkNameG_d "package-name" "ModuleName" ":^:"))+ (lift v)++Note that (mkNameG_d "package-name" "ModuleName" "Foo") is equivalent to what+'Foo would be when using the -XTemplateHaskell extension. To make sure that+-XDeriveLift can be used on stage-1 compilers, however, we explicitly invoke+makeG_d.+-}++gen_Lift_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)+gen_Lift_binds loc tycon+ | null data_cons = (unitBag (L loc $ mkFunBind (L loc lift_RDR)+ [mkMatch (mkPrefixFunRhs (L loc lift_RDR))+ [nlWildPat] errorMsg_Expr+ (noLoc emptyLocalBinds)])+ , emptyBag)+ | otherwise = (unitBag lift_bind, emptyBag)+ where+ errorMsg_Expr = nlHsVar error_RDR `nlHsApp` nlHsLit+ (mkHsString $ "Can't lift value of empty datatype " ++ tycon_str)++ lift_bind = mk_FunBind loc lift_RDR (map pats_etc data_cons)+ data_cons = tyConDataCons tycon+ tycon_str = occNameString . nameOccName . tyConName $ tycon++ pats_etc data_con+ = ([con_pat], lift_Expr)+ where+ con_pat = nlConVarPat data_con_RDR as_needed+ data_con_RDR = getRdrName data_con+ con_arity = dataConSourceArity data_con+ as_needed = take con_arity as_RDRs+ lifted_as = zipWithEqual "mk_lift_app" mk_lift_app+ tys_needed as_needed+ tycon_name = tyConName tycon+ is_infix = dataConIsInfix data_con+ tys_needed = dataConOrigArgTys data_con++ mk_lift_app ty a+ | not (isUnliftedType ty) = nlHsApp (nlHsVar lift_RDR)+ (nlHsVar a)+ | otherwise = nlHsApp (nlHsVar litE_RDR)+ (primLitOp (mkBoxExp (nlHsVar a)))+ where (primLitOp, mkBoxExp) = primLitOps "Lift" tycon ty++ pkg_name = unitIdString . moduleUnitId+ . nameModule $ tycon_name+ mod_name = moduleNameString . moduleName . nameModule $ tycon_name+ con_name = occNameString . nameOccName . dataConName $ data_con++ conE_Expr = nlHsApp (nlHsVar conE_RDR)+ (nlHsApps mkNameG_dRDR+ (map (nlHsLit . mkHsString)+ [pkg_name, mod_name, con_name]))++ lift_Expr+ | is_infix = nlHsApps infixApp_RDR [a1, conE_Expr, a2]+ | otherwise = foldl mk_appE_app conE_Expr lifted_as+ (a1:a2:_) = lifted_as++mk_appE_app :: LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName+mk_appE_app a b = nlHsApps appE_RDR [a, b]++{-+************************************************************************+* *+ Newtype-deriving instances+* *+************************************************************************++Note [Newtype-deriving instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We take every method in the original instance and `coerce` it to fit+into the derived instance. We need a type annotation on the argument+to `coerce` to make it obvious what instantiation of the method we're+coercing from. So from, say,+ class C a b where+ op :: a -> [b] -> Int++ newtype T x = MkT <rep-ty>++ instance C a <rep-ty> => C a (T x) where+ op = coerce @ (a -> [<rep-ty>] -> Int)+ @ (a -> [T x] -> Int)+ op++Notice that we give the 'coerce' two explicitly-visible type arguments+to say how it should be instantiated. Recall++ coerce :: Coeercible a b => a -> b++By giving it explicit type arguments we deal with the case where+'op' has a higher rank type, and so we must instantiate 'coerce' with+a polytype. E.g.+ class C a where op :: forall b. a -> b -> b+ newtype T x = MkT <rep-ty>+ instance C <rep-ty> => C (T x) where+ op = coerce @ (forall b. <rep-ty> -> b -> b)+ @ (forall b. T x -> b -> b)+ op++The type checker checks this code, and it currently requires+-XImpredicativeTypes to permit that polymorphic type instantiation,+so we have to switch that flag on locally in TcDeriv.genInst.++See #8503 for more discussion.++Note [Newtype-deriving trickiness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #12768):+ class C a where { op :: D a => a -> a }++ instance C a => C [a] where { op = opList }++ opList :: (C a, D [a]) => [a] -> [a]+ opList = ...++Now suppose we try GND on this:+ newtype N a = MkN [a] deriving( C )++The GND is expecting to get an implementation of op for N by+coercing opList, thus:++ instance C a => C (N a) where { op = opN }++ opN :: (C a, D (N a)) => N a -> N a+ opN = coerce @(D [a] => [a] -> [a])+ @(D (N a) => [N a] -> [N a]+ opList++But there is no reason to suppose that (D [a]) and (D (N a))+are inter-coercible; these instances might completely different.+So GHC rightly rejects this code.+-}++gen_Newtype_binds :: SrcSpan+ -> Class -- the class being derived+ -> [TyVar] -- the tvs in the instance head (this includes+ -- the tvs from both the class types and the+ -- newtype itself)+ -> [Type] -- instance head parameters (incl. newtype)+ -> Type -- the representation type+ -> TcM (LHsBinds RdrName, BagDerivStuff)+-- See Note [Newtype-deriving instances]+gen_Newtype_binds loc cls inst_tvs inst_tys rhs_ty+ = do let ats = classATs cls+ atf_insts <- ASSERT( all (not . isDataFamilyTyCon) ats )+ mapM mk_atf_inst ats+ return ( listToBag $ map mk_bind (classMethods cls)+ , listToBag $ map DerivFamInst atf_insts )+ where+ coerce_RDR = getRdrName coerceId++ mk_bind :: Id -> LHsBind RdrName+ mk_bind meth_id+ = mkRdrFunBind (L loc meth_RDR) [mkSimpleMatch+ (mkPrefixFunRhs (L loc meth_RDR))+ [] rhs_expr]+ where+ Pair from_ty to_ty = mkCoerceClassMethEqn cls inst_tvs inst_tys rhs_ty meth_id++ meth_RDR = getRdrName meth_id++ rhs_expr = nlHsVar coerce_RDR `nlHsAppType` from_ty+ `nlHsAppType` to_ty+ `nlHsApp` nlHsVar meth_RDR++ mk_atf_inst :: TyCon -> TcM FamInst+ mk_atf_inst fam_tc = do+ rep_tc_name <- newFamInstTyConName (L loc (tyConName fam_tc))+ rep_lhs_tys+ let axiom = mkSingleCoAxiom Nominal rep_tc_name rep_tvs' rep_cvs'+ fam_tc rep_lhs_tys rep_rhs_ty+ -- Check (c) from Note [GND and associated type families] in TcDeriv+ checkValidTyFamEqn (Just (cls, cls_tvs, lhs_env)) fam_tc rep_tvs'+ rep_cvs' rep_lhs_tys rep_rhs_ty loc+ newFamInst SynFamilyInst axiom+ where+ cls_tvs = classTyVars cls+ in_scope = mkInScopeSet $ mkVarSet inst_tvs+ lhs_env = zipTyEnv cls_tvs inst_tys+ lhs_subst = mkTvSubst in_scope lhs_env+ rhs_env = zipTyEnv cls_tvs $ changeLast inst_tys rhs_ty+ rhs_subst = mkTvSubst in_scope rhs_env+ fam_tvs = tyConTyVars fam_tc+ rep_lhs_tys = substTyVars lhs_subst fam_tvs+ rep_rhs_tys = substTyVars rhs_subst fam_tvs+ rep_rhs_ty = mkTyConApp fam_tc rep_rhs_tys+ rep_tcvs = tyCoVarsOfTypesList rep_lhs_tys+ (rep_tvs, rep_cvs) = partition isTyVar rep_tcvs+ rep_tvs' = toposortTyVars rep_tvs+ rep_cvs' = toposortTyVars rep_cvs++nlHsAppType :: LHsExpr RdrName -> Type -> LHsExpr RdrName+nlHsAppType e s = noLoc (e `HsAppType` hs_ty)+ where+ hs_ty = mkHsWildCardBndrs $ nlHsParTy (typeToLHsType s)++nlExprWithTySig :: LHsExpr RdrName -> Type -> LHsExpr RdrName+nlExprWithTySig e s = noLoc (e `ExprWithTySig` hs_ty)+ where+ hs_ty = mkLHsSigWcType (typeToLHsType s)++mkCoerceClassMethEqn :: Class -- the class being derived+ -> [TyVar] -- the tvs in the instance head (this includes+ -- the tvs from both the class types and the+ -- newtype itself)+ -> [Type] -- instance head parameters (incl. newtype)+ -> Type -- the representation type+ -> Id -- the method to look at+ -> Pair Type+-- See Note [Newtype-deriving instances]+-- See also Note [Newtype-deriving trickiness]+-- The pair is the (from_type, to_type), where to_type is+-- the type of the method we are tyrying to get+mkCoerceClassMethEqn cls inst_tvs inst_tys rhs_ty id+ = Pair (substTy rhs_subst user_meth_ty)+ (substTy lhs_subst user_meth_ty)+ where+ cls_tvs = classTyVars cls+ in_scope = mkInScopeSet $ mkVarSet inst_tvs+ lhs_subst = mkTvSubst in_scope (zipTyEnv cls_tvs inst_tys)+ rhs_subst = mkTvSubst in_scope (zipTyEnv cls_tvs (changeLast inst_tys rhs_ty))+ (_class_tvs, _class_constraint, user_meth_ty)+ = tcSplitMethodTy (varType id)++{-+************************************************************************+* *+\subsection{Generating extra binds (@con2tag@ and @tag2con@)}+* *+************************************************************************++\begin{verbatim}+data Foo ... = ...++con2tag_Foo :: Foo ... -> Int#+tag2con_Foo :: Int -> Foo ... -- easier if Int, not Int#+maxtag_Foo :: Int -- ditto (NB: not unlifted)+\end{verbatim}++The `tags' here start at zero, hence the @fIRST_TAG@ (currently one)+fiddling around.+-}++genAuxBindSpec :: DynFlags -> SrcSpan -> AuxBindSpec+ -> (LHsBind RdrName, LSig RdrName)+genAuxBindSpec dflags loc (DerivCon2Tag tycon)+ = (mk_FunBind loc rdr_name eqns,+ L loc (TypeSig [L loc rdr_name] sig_ty))+ where+ rdr_name = con2tag_RDR dflags tycon++ sig_ty = mkLHsSigWcType $ L loc $ HsCoreTy $+ mkSpecSigmaTy (tyConTyVars tycon) (tyConStupidTheta tycon) $+ mkParentType tycon `mkFunTy` intPrimTy++ lots_of_constructors = tyConFamilySize tycon > 8+ -- was: mAX_FAMILY_SIZE_FOR_VEC_RETURNS+ -- but we don't do vectored returns any more.++ eqns | lots_of_constructors = [get_tag_eqn]+ | otherwise = map mk_eqn (tyConDataCons tycon)++ get_tag_eqn = ([nlVarPat a_RDR], nlHsApp (nlHsVar getTag_RDR) a_Expr)++ mk_eqn :: DataCon -> ([LPat RdrName], LHsExpr RdrName)+ mk_eqn con = ([nlWildConPat con],+ nlHsLit (HsIntPrim NoSourceText+ (toInteger ((dataConTag con) - fIRST_TAG))))++genAuxBindSpec dflags loc (DerivTag2Con tycon)+ = (mk_FunBind loc rdr_name+ [([nlConVarPat intDataCon_RDR [a_RDR]],+ nlHsApp (nlHsVar tagToEnum_RDR) a_Expr)],+ L loc (TypeSig [L loc rdr_name] sig_ty))+ where+ sig_ty = mkLHsSigWcType $ L loc $+ HsCoreTy $ mkSpecForAllTys (tyConTyVars tycon) $+ intTy `mkFunTy` mkParentType tycon++ rdr_name = tag2con_RDR dflags tycon++genAuxBindSpec dflags loc (DerivMaxTag tycon)+ = (mkHsVarBind loc rdr_name rhs,+ L loc (TypeSig [L loc rdr_name] sig_ty))+ where+ rdr_name = maxtag_RDR dflags tycon+ sig_ty = mkLHsSigWcType (L loc (HsCoreTy intTy))+ rhs = nlHsApp (nlHsVar intDataCon_RDR)+ (nlHsLit (HsIntPrim NoSourceText max_tag))+ max_tag = case (tyConDataCons tycon) of+ data_cons -> toInteger ((length data_cons) - fIRST_TAG)++type SeparateBagsDerivStuff =+ -- AuxBinds and SYB bindings+ ( Bag (LHsBind RdrName, LSig RdrName)+ -- Extra family instances (used by Generic and DeriveAnyClass)+ , Bag (FamInst) )++genAuxBinds :: DynFlags -> SrcSpan -> BagDerivStuff -> SeparateBagsDerivStuff+genAuxBinds dflags loc b = genAuxBinds' b2 where+ (b1,b2) = partitionBagWith splitDerivAuxBind b+ splitDerivAuxBind (DerivAuxBind x) = Left x+ splitDerivAuxBind x = Right x++ rm_dups = foldrBag dup_check emptyBag+ dup_check a b = if anyBag (== a) b then b else consBag a b++ genAuxBinds' :: BagDerivStuff -> SeparateBagsDerivStuff+ genAuxBinds' = foldrBag f ( mapBag (genAuxBindSpec dflags loc) (rm_dups b1)+ , emptyBag )+ f :: DerivStuff -> SeparateBagsDerivStuff -> SeparateBagsDerivStuff+ f (DerivAuxBind _) = panic "genAuxBinds'" -- We have removed these before+ f (DerivHsBind b) = add1 b+ f (DerivFamInst t) = add2 t++ add1 x (a,b) = (x `consBag` a,b)+ add2 x (a,b) = (a,x `consBag` b)++mkParentType :: TyCon -> Type+-- Turn the representation tycon of a family into+-- a use of its family constructor+mkParentType tc+ = case tyConFamInst_maybe tc of+ Nothing -> mkTyConApp tc (mkTyVarTys (tyConTyVars tc))+ Just (fam_tc,tys) -> mkTyConApp fam_tc tys++{-+************************************************************************+* *+\subsection{Utility bits for generating bindings}+* *+************************************************************************+-}++mk_FunBind :: SrcSpan -> RdrName+ -> [([LPat RdrName], LHsExpr RdrName)]+ -> LHsBind RdrName+mk_FunBind = mk_HRFunBind 0 -- by using mk_FunBind and not mk_HRFunBind,+ -- the caller says that the Void case needs no+ -- patterns++-- | This variant of 'mk_FunBind' puts an 'Arity' number of wildcards before+-- the "=" in the empty-data-decl case. This is necessary if the function+-- has a higher-rank type, like foldl. (See deriving/should_compile/T4302)+mk_HRFunBind :: Arity -> SrcSpan -> RdrName+ -> [([LPat RdrName], LHsExpr RdrName)]+ -> LHsBind RdrName+mk_HRFunBind arity loc fun pats_and_exprs+ = mkHRRdrFunBind arity (L loc fun) matches+ where+ matches = [mkMatch (mkPrefixFunRhs (L loc fun)) p e+ (noLoc emptyLocalBinds)+ | (p,e) <-pats_and_exprs]++mkRdrFunBind :: Located RdrName -> [LMatch RdrName (LHsExpr RdrName)] -> LHsBind RdrName+mkRdrFunBind = mkHRRdrFunBind 0++mkHRRdrFunBind :: Arity -> Located RdrName -> [LMatch RdrName (LHsExpr RdrName)] -> LHsBind RdrName+mkHRRdrFunBind arity fun@(L loc fun_rdr) matches = L loc (mkFunBind fun matches')+ where+ -- Catch-all eqn looks like+ -- fmap = error "Void fmap"+ -- It's needed if there no data cons at all,+ -- which can happen with -XEmptyDataDecls+ -- See Trac #4302+ matches' = if null matches+ then [mkMatch (mkPrefixFunRhs fun)+ (replicate arity nlWildPat)+ (error_Expr str) (noLoc emptyLocalBinds)]+ else matches+ str = "Void " ++ occNameString (rdrNameOcc fun_rdr)++box :: String -- The class involved+ -> TyCon -- The tycon involved+ -> LHsExpr RdrName -- The argument+ -> Type -- The argument type+ -> LHsExpr RdrName -- Boxed version of the arg+-- See Note [Deriving and unboxed types] in TcDeriv+box cls_str tycon arg arg_ty = nlHsApp (nlHsVar box_con) arg+ where+ box_con = assoc_ty_id cls_str tycon boxConTbl arg_ty++---------------------+primOrdOps :: String -- The class involved+ -> TyCon -- The tycon involved+ -> Type -- The type+ -> (RdrName, RdrName, RdrName, RdrName, RdrName) -- (lt,le,eq,ge,gt)+-- See Note [Deriving and unboxed types] in TcDeriv+primOrdOps str tycon ty = assoc_ty_id str tycon ordOpTbl ty++primLitOps :: String -- The class involved+ -> TyCon -- The tycon involved+ -> Type -- The type+ -> ( LHsExpr RdrName -> LHsExpr RdrName -- Constructs a Q Exp value+ , LHsExpr RdrName -> LHsExpr RdrName -- Constructs a boxed value+ )+primLitOps str tycon ty = ( assoc_ty_id str tycon litConTbl ty+ , \v -> nlHsVar boxRDR `nlHsApp` v+ )+ where+ boxRDR+ | ty `eqType` addrPrimTy = unpackCString_RDR+ | otherwise = assoc_ty_id str tycon boxConTbl ty++ordOpTbl :: [(Type, (RdrName, RdrName, RdrName, RdrName, RdrName))]+ordOpTbl+ = [(charPrimTy , (ltChar_RDR , leChar_RDR , eqChar_RDR , geChar_RDR , gtChar_RDR ))+ ,(intPrimTy , (ltInt_RDR , leInt_RDR , eqInt_RDR , geInt_RDR , gtInt_RDR ))+ ,(wordPrimTy , (ltWord_RDR , leWord_RDR , eqWord_RDR , geWord_RDR , gtWord_RDR ))+ ,(addrPrimTy , (ltAddr_RDR , leAddr_RDR , eqAddr_RDR , geAddr_RDR , gtAddr_RDR ))+ ,(floatPrimTy , (ltFloat_RDR , leFloat_RDR , eqFloat_RDR , geFloat_RDR , gtFloat_RDR ))+ ,(doublePrimTy, (ltDouble_RDR, leDouble_RDR, eqDouble_RDR, geDouble_RDR, gtDouble_RDR)) ]++boxConTbl :: [(Type, RdrName)]+boxConTbl+ = [(charPrimTy , getRdrName charDataCon )+ ,(intPrimTy , getRdrName intDataCon )+ ,(wordPrimTy , getRdrName wordDataCon )+ ,(floatPrimTy , getRdrName floatDataCon )+ ,(doublePrimTy, getRdrName doubleDataCon)+ ]++-- | A table of postfix modifiers for unboxed values.+postfixModTbl :: [(Type, String)]+postfixModTbl+ = [(charPrimTy , "#" )+ ,(intPrimTy , "#" )+ ,(wordPrimTy , "##")+ ,(floatPrimTy , "#" )+ ,(doublePrimTy, "##")+ ]++litConTbl :: [(Type, LHsExpr RdrName -> LHsExpr RdrName)]+litConTbl+ = [(charPrimTy , nlHsApp (nlHsVar charPrimL_RDR))+ ,(intPrimTy , nlHsApp (nlHsVar intPrimL_RDR)+ . nlHsApp (nlHsVar toInteger_RDR))+ ,(wordPrimTy , nlHsApp (nlHsVar wordPrimL_RDR)+ . nlHsApp (nlHsVar toInteger_RDR))+ ,(addrPrimTy , nlHsApp (nlHsVar stringPrimL_RDR)+ . nlHsApp (nlHsApp+ (nlHsVar map_RDR)+ (compose_RDR `nlHsApps`+ [ nlHsVar fromIntegral_RDR+ , nlHsVar fromEnum_RDR+ ])))+ ,(floatPrimTy , nlHsApp (nlHsVar floatPrimL_RDR)+ . nlHsApp (nlHsVar toRational_RDR))+ ,(doublePrimTy, nlHsApp (nlHsVar doublePrimL_RDR)+ . nlHsApp (nlHsVar toRational_RDR))+ ]++-- | Lookup `Type` in an association list.+assoc_ty_id :: String -- The class involved+ -> TyCon -- The tycon involved+ -> [(Type,a)] -- The table+ -> Type -- The type+ -> a -- The result of the lookup+assoc_ty_id cls_str _ tbl ty+ | null res = pprPanic "Error in deriving:" (text "Can't derive" <+> text cls_str <+>+ text "for primitive type" <+> ppr ty)+ | otherwise = head res+ where+ res = [id | (ty',id) <- tbl, ty `eqType` ty']++-----------------------------------------------------------------------++and_Expr :: LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName+and_Expr a b = genOpApp a and_RDR b++-----------------------------------------------------------------------++eq_Expr :: TyCon -> Type -> LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName+eq_Expr tycon ty a b+ | not (isUnliftedType ty) = genOpApp a eq_RDR b+ | otherwise = genPrimOpApp a prim_eq b+ where+ (_, _, prim_eq, _, _) = primOrdOps "Eq" tycon ty++untag_Expr :: DynFlags -> TyCon -> [( RdrName, RdrName)]+ -> LHsExpr RdrName -> LHsExpr RdrName+untag_Expr _ _ [] expr = expr+untag_Expr dflags tycon ((untag_this, put_tag_here) : more) expr+ = nlHsCase (nlHsPar (nlHsVarApps (con2tag_RDR dflags tycon)+ [untag_this])) {-of-}+ [mkHsCaseAlt (nlVarPat put_tag_here) (untag_Expr dflags tycon more expr)]++enum_from_to_Expr+ :: LHsExpr RdrName -> LHsExpr RdrName+ -> LHsExpr RdrName+enum_from_then_to_Expr+ :: LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName+ -> LHsExpr RdrName++enum_from_to_Expr f t2 = nlHsApp (nlHsApp (nlHsVar enumFromTo_RDR) f) t2+enum_from_then_to_Expr f t t2 = nlHsApp (nlHsApp (nlHsApp (nlHsVar enumFromThenTo_RDR) f) t) t2++showParen_Expr+ :: LHsExpr RdrName -> LHsExpr RdrName+ -> LHsExpr RdrName++showParen_Expr e1 e2 = nlHsApp (nlHsApp (nlHsVar showParen_RDR) e1) e2++nested_compose_Expr :: [LHsExpr RdrName] -> LHsExpr RdrName++nested_compose_Expr [] = panic "nested_compose_expr" -- Arg is always non-empty+nested_compose_Expr [e] = parenify e+nested_compose_Expr (e:es)+ = nlHsApp (nlHsApp (nlHsVar compose_RDR) (parenify e)) (nested_compose_Expr es)++-- impossible_Expr is used in case RHSs that should never happen.+-- We generate these to keep the desugarer from complaining that they *might* happen!+error_Expr :: String -> LHsExpr RdrName+error_Expr string = nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString string))++-- illegal_Expr is used when signalling error conditions in the RHS of a derived+-- method. It is currently only used by Enum.{succ,pred}+illegal_Expr :: String -> String -> String -> LHsExpr RdrName+illegal_Expr meth tp msg =+ nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString (meth ++ '{':tp ++ "}: " ++ msg)))++-- illegal_toEnum_tag is an extended version of illegal_Expr, which also allows you+-- to include the value of a_RDR in the error string.+illegal_toEnum_tag :: String -> RdrName -> LHsExpr RdrName+illegal_toEnum_tag tp maxtag =+ nlHsApp (nlHsVar error_RDR)+ (nlHsApp (nlHsApp (nlHsVar append_RDR)+ (nlHsLit (mkHsString ("toEnum{" ++ tp ++ "}: tag ("))))+ (nlHsApp (nlHsApp (nlHsApp+ (nlHsVar showsPrec_RDR)+ (nlHsIntLit 0))+ (nlHsVar a_RDR))+ (nlHsApp (nlHsApp+ (nlHsVar append_RDR)+ (nlHsLit (mkHsString ") is outside of enumeration's range (0,")))+ (nlHsApp (nlHsApp (nlHsApp+ (nlHsVar showsPrec_RDR)+ (nlHsIntLit 0))+ (nlHsVar maxtag))+ (nlHsLit (mkHsString ")"))))))++parenify :: LHsExpr RdrName -> LHsExpr RdrName+parenify e@(L _ (HsVar _)) = e+parenify e = mkHsPar e++-- genOpApp wraps brackets round the operator application, so that the+-- renamer won't subsequently try to re-associate it.+genOpApp :: LHsExpr RdrName -> RdrName -> LHsExpr RdrName -> LHsExpr RdrName+genOpApp e1 op e2 = nlHsPar (nlHsOpApp e1 op e2)++genPrimOpApp :: LHsExpr RdrName -> RdrName -> LHsExpr RdrName -> LHsExpr RdrName+genPrimOpApp e1 op e2 = nlHsPar (nlHsApp (nlHsVar tagToEnum_RDR) (nlHsOpApp e1 op e2))++a_RDR, b_RDR, c_RDR, d_RDR, f_RDR, k_RDR, z_RDR, ah_RDR, bh_RDR, ch_RDR, dh_RDR+ :: RdrName+a_RDR = mkVarUnqual (fsLit "a")+b_RDR = mkVarUnqual (fsLit "b")+c_RDR = mkVarUnqual (fsLit "c")+d_RDR = mkVarUnqual (fsLit "d")+f_RDR = mkVarUnqual (fsLit "f")+k_RDR = mkVarUnqual (fsLit "k")+z_RDR = mkVarUnqual (fsLit "z")+ah_RDR = mkVarUnqual (fsLit "a#")+bh_RDR = mkVarUnqual (fsLit "b#")+ch_RDR = mkVarUnqual (fsLit "c#")+dh_RDR = mkVarUnqual (fsLit "d#")++as_RDRs, bs_RDRs, cs_RDRs :: [RdrName]+as_RDRs = [ mkVarUnqual (mkFastString ("a"++show i)) | i <- [(1::Int) .. ] ]+bs_RDRs = [ mkVarUnqual (mkFastString ("b"++show i)) | i <- [(1::Int) .. ] ]+cs_RDRs = [ mkVarUnqual (mkFastString ("c"++show i)) | i <- [(1::Int) .. ] ]++a_Expr, b_Expr, c_Expr, ltTag_Expr, eqTag_Expr, gtTag_Expr, false_Expr,+ true_Expr :: LHsExpr RdrName+a_Expr = nlHsVar a_RDR+b_Expr = nlHsVar b_RDR+c_Expr = nlHsVar c_RDR+ltTag_Expr = nlHsVar ltTag_RDR+eqTag_Expr = nlHsVar eqTag_RDR+gtTag_Expr = nlHsVar gtTag_RDR+false_Expr = nlHsVar false_RDR+true_Expr = nlHsVar true_RDR++a_Pat, b_Pat, c_Pat, d_Pat, k_Pat, z_Pat :: LPat RdrName+a_Pat = nlVarPat a_RDR+b_Pat = nlVarPat b_RDR+c_Pat = nlVarPat c_RDR+d_Pat = nlVarPat d_RDR+k_Pat = nlVarPat k_RDR+z_Pat = nlVarPat z_RDR++minusInt_RDR, tagToEnum_RDR :: RdrName+minusInt_RDR = getRdrName (primOpId IntSubOp )+tagToEnum_RDR = getRdrName (primOpId TagToEnumOp)++con2tag_RDR, tag2con_RDR, maxtag_RDR :: DynFlags -> TyCon -> RdrName+-- Generates Orig s RdrName, for the binding positions+con2tag_RDR dflags tycon = mk_tc_deriv_name dflags tycon mkCon2TagOcc+tag2con_RDR dflags tycon = mk_tc_deriv_name dflags tycon mkTag2ConOcc+maxtag_RDR dflags tycon = mk_tc_deriv_name dflags tycon mkMaxTagOcc++mk_tc_deriv_name :: DynFlags -> TyCon -> (OccName -> OccName) -> RdrName+mk_tc_deriv_name dflags tycon occ_fun =+ mkAuxBinderName dflags (tyConName tycon) occ_fun++mkAuxBinderName :: DynFlags -> Name -> (OccName -> OccName) -> RdrName+-- ^ Make a top-level binder name for an auxiliary binding for a parent name+-- See Note [Auxiliary binders]+mkAuxBinderName dflags parent occ_fun+ = mkRdrUnqual (occ_fun stable_parent_occ)+ where+ stable_parent_occ = mkOccName (occNameSpace parent_occ) stable_string+ stable_string+ | hasPprDebug dflags = parent_stable+ | otherwise = parent_stable_hash+ parent_stable = nameStableString parent+ parent_stable_hash =+ let Fingerprint high low = fingerprintString parent_stable+ in toBase62 high ++ toBase62Padded low+ -- See Note [Base 62 encoding 128-bit integers] in Encoding+ parent_occ = nameOccName parent+++{-+Note [Auxiliary binders]+~~~~~~~~~~~~~~~~~~~~~~~~+We often want to make a top-level auxiliary binding. E.g. for comparison we haev++ instance Ord T where+ compare a b = $con2tag a `compare` $con2tag b++ $con2tag :: T -> Int+ $con2tag = ...code....++Of course these top-level bindings should all have distinct name, and we are+generating RdrNames here. We can't just use the TyCon or DataCon to distinguish+because with standalone deriving two imported TyCons might both be called T!+(See Trac #7947.)++So we use package name, module name and the name of the parent+(T in this example) as part of the OccName we generate for the new binding.+To make the symbol names short we take a base62 hash of the full name.++In the past we used the *unique* from the parent, but that's not stable across+recompilations as uniques are nondeterministic.+-}
+ typecheck/TcGenFunctor.hs view
@@ -0,0 +1,1023 @@+{-+(c) The University of Glasgow 2011+++The deriving code for the Functor, Foldable, and Traversable classes+(equivalent to the code in TcGenDeriv, for other classes)+-}++{-# LANGUAGE ScopedTypeVariables #-}++module TcGenFunctor (+ FFoldType(..), functorLikeTraverse,+ deepSubtypesContaining, foldDataConArgs,++ gen_Functor_binds, gen_Foldable_binds, gen_Traversable_binds+ ) where++import Bag+import DataCon+import FastString+import HsSyn+import Panic+import PrelNames+import RdrName+import SrcLoc+import State+import TcGenDeriv+import TcType+import TyCon+import TyCoRep+import Type+import Util+import Var+import VarSet++import Data.Maybe (catMaybes, isJust)++{-+************************************************************************+* *+ Functor instances++ see http://www.mail-archive.com/haskell-prime@haskell.org/msg02116.html++* *+************************************************************************++For the data type:++ data T a = T1 Int a | T2 (T a)++We generate the instance:++ instance Functor T where+ fmap f (T1 b1 a) = T1 b1 (f a)+ fmap f (T2 ta) = T2 (fmap f ta)++Notice that we don't simply apply 'fmap' to the constructor arguments.+Rather+ - Do nothing to an argument whose type doesn't mention 'a'+ - Apply 'f' to an argument of type 'a'+ - Apply 'fmap f' to other arguments+That's why we have to recurse deeply into the constructor argument types,+rather than just one level, as we typically do.++What about types with more than one type parameter? In general, we only+derive Functor for the last position:++ data S a b = S1 [b] | S2 (a, T a b)+ instance Functor (S a) where+ fmap f (S1 bs) = S1 (fmap f bs)+ fmap f (S2 (p,q)) = S2 (a, fmap f q)++However, we have special cases for+ - tuples+ - functions++More formally, we write the derivation of fmap code over type variable+'a for type 'b as ($fmap 'a 'b). In this general notation the derived+instance for T is:++ instance Functor T where+ fmap f (T1 x1 x2) = T1 ($(fmap 'a 'b1) x1) ($(fmap 'a 'a) x2)+ fmap f (T2 x1) = T2 ($(fmap 'a '(T a)) x1)++ $(fmap 'a 'b) = \x -> x -- when b does not contain a+ $(fmap 'a 'a) = f+ $(fmap 'a '(b1,b2)) = \x -> case x of (x1,x2) -> ($(fmap 'a 'b1) x1, $(fmap 'a 'b2) x2)+ $(fmap 'a '(T b1 b2)) = fmap $(fmap 'a 'b2) -- when a only occurs in the last parameter, b2+ $(fmap 'a '(b -> c)) = \x b -> $(fmap 'a' 'c) (x ($(cofmap 'a 'b) b))++For functions, the type parameter 'a can occur in a contravariant position,+which means we need to derive a function like:++ cofmap :: (a -> b) -> (f b -> f a)++This is pretty much the same as $fmap, only without the $(cofmap 'a 'a) case:++ $(cofmap 'a 'b) = \x -> x -- when b does not contain a+ $(cofmap 'a 'a) = error "type variable in contravariant position"+ $(cofmap 'a '(b1,b2)) = \x -> case x of (x1,x2) -> ($(cofmap 'a 'b1) x1, $(cofmap 'a 'b2) x2)+ $(cofmap 'a '[b]) = map $(cofmap 'a 'b)+ $(cofmap 'a '(T b1 b2)) = fmap $(cofmap 'a 'b2) -- when a only occurs in the last parameter, b2+ $(cofmap 'a '(b -> c)) = \x b -> $(cofmap 'a' 'c) (x ($(fmap 'a 'c) b))++Note that the code produced by $(fmap _ _) is always a higher order function,+with type `(a -> b) -> (g a -> g b)` for some g. When we need to do pattern+matching on the type, this means create a lambda function (see the (,) case above).+The resulting code for fmap can look a bit weird, for example:++ data X a = X (a,Int)+ -- generated instance+ instance Functor X where+ fmap f (X x) = (\y -> case y of (x1,x2) -> X (f x1, (\z -> z) x2)) x++The optimizer should be able to simplify this code by simple inlining.++An older version of the deriving code tried to avoid these applied+lambda functions by producing a meta level function. But the function to+be mapped, `f`, is a function on the code level, not on the meta level,+so it was eta expanded to `\x -> [| f $x |]`. This resulted in too much eta expansion.+It is better to produce too many lambdas than to eta expand, see ticket #7436.+-}++gen_Functor_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)+gen_Functor_binds loc tycon+ = (listToBag [fmap_bind, replace_bind], emptyBag)+ where+ data_cons = tyConDataCons tycon+ fmap_name = L loc fmap_RDR+ fmap_bind = mkRdrFunBind fmap_name fmap_eqns+ fmap_match_ctxt = mkPrefixFunRhs fmap_name++ fmap_eqn con = flip evalState bs_RDRs $+ match_for_con fmap_match_ctxt [f_Pat] con =<< parts+ where+ parts = sequence $ foldDataConArgs ft_fmap con++ fmap_eqns+ | null data_cons = [mkSimpleMatch fmap_match_ctxt+ [nlWildPat, nlWildPat]+ (error_Expr "Void fmap")]+ | otherwise = map fmap_eqn data_cons++ ft_fmap :: FFoldType (State [RdrName] (LHsExpr RdrName))+ ft_fmap = FT { ft_triv = mkSimpleLam $ \x -> return x+ -- fmap f = \x -> x+ , ft_var = return f_Expr+ -- fmap f = f+ , ft_fun = \g h -> do+ gg <- g+ hh <- h+ mkSimpleLam2 $ \x b -> return $+ nlHsApp hh (nlHsApp x (nlHsApp gg b))+ -- fmap f = \x b -> h (x (g b))+ , ft_tup = \t gs -> do+ gg <- sequence gs+ mkSimpleLam $ mkSimpleTupleCase (match_for_con CaseAlt) t gg+ -- fmap f = \x -> case x of (a1,a2,..) -> (g1 a1,g2 a2,..)+ , ft_ty_app = \_ g -> nlHsApp fmap_Expr <$> g+ -- fmap f = fmap g+ , ft_forall = \_ g -> g+ , ft_bad_app = panic "in other argument"+ , ft_co_var = panic "contravariant" }++ -- See Note [deriving <$]+ replace_name = L loc replace_RDR+ replace_bind = mkRdrFunBind replace_name replace_eqns+ replace_match_ctxt = mkPrefixFunRhs replace_name++ replace_eqn con = flip evalState bs_RDRs $+ match_for_con replace_match_ctxt [z_Pat] con =<< parts+ where+ parts = traverse (fmap replace) $ foldDataConArgs ft_replace con++ replace_eqns+ | null data_cons = [mkSimpleMatch replace_match_ctxt+ [nlWildPat, nlWildPat]+ (error_Expr "Void <$")]+ | otherwise = map replace_eqn data_cons++ ft_replace :: FFoldType (State [RdrName] Replacer)+ ft_replace = FT { ft_triv = fmap Nested $ mkSimpleLam $ \x -> return x+ -- (p <$) = \x -> x+ , ft_var = fmap Immediate $ mkSimpleLam $ \_ -> return z_Expr+ -- (p <$) = const p+ , ft_fun = \g h -> do+ gg <- replace <$> g+ hh <- replace <$> h+ fmap Nested $ mkSimpleLam2 $ \x b -> return $+ nlHsApp hh (nlHsApp x (nlHsApp gg b))+ -- (<$) p = \x b -> h (x (g b))+ , ft_tup = \t gs -> do+ gg <- traverse (fmap replace) gs+ fmap Nested . mkSimpleLam $+ mkSimpleTupleCase (match_for_con CaseAlt) t gg+ -- (p <$) = \x -> case x of (a1,a2,..) -> (g1 a1,g2 a2,..)+ , ft_ty_app = \_ gm -> do+ g <- gm+ case g of+ Nested g' -> pure . Nested $+ nlHsApp fmap_Expr $ g'+ Immediate _ -> pure . Nested $+ nlHsApp replace_Expr z_Expr+ -- (p <$) = fmap (p <$)+ , ft_forall = \_ g -> g+ , ft_bad_app = panic "in other argument"+ , ft_co_var = panic "contravariant" }++ -- Con a1 a2 ... -> Con (f1 a1) (f2 a2) ...+ match_for_con :: HsMatchContext RdrName+ -> [LPat RdrName] -> DataCon -> [LHsExpr RdrName]+ -> State [RdrName] (LMatch RdrName (LHsExpr RdrName))+ match_for_con ctxt = mkSimpleConMatch ctxt $+ \con_name xs -> return $ nlHsApps con_name xs -- Con x1 x2 ..++-- See Note [deriving <$]+data Replacer = Immediate {replace :: LHsExpr RdrName}+ | Nested {replace :: LHsExpr RdrName}++{- Note [deriving <$]+ ~~~~~~~~~~~~~~~~~~++We derive the definition of <$. Allowing this to take the default definition+can lead to memory leaks: mapping over a structure with a constant function can+fill the result structure with trivial thunks that retain the values from the+original structure. The simplifier seems to handle this all right for simple+types, but not for recursive ones. Consider++data Tree a = Bin !(Tree a) a !(Tree a) | Tip deriving Functor++-- fmap _ Tip = Tip+-- fmap f (Bin l v r) = Bin (fmap f l) (f v) (fmap f r)++Using the default definition of <$, we get (<$) x = fmap (\_ -> x) and that+simplifies no further. Why is that? `fmap` is defined recursively, so GHC+cannot inline it. The static argument transformation would turn the definition+into a non-recursive one++-- fmap f = go where+-- go Tip = Tip+-- go (Bin l v r) = Bin (go l) (f v) (go r)++which GHC could inline, producing an efficient definion of `<$`. But there are+several problems. First, GHC does not perform the static argument transformation+by default, even with -O2. Second, even when it does perform the static argument+transformation, it does so only when there are at least two static arguments,+which is not the case for fmap. Finally, when the type in question is+non-regular, such as++data Nesty a = Z a | S (Nesty a) (Nest (a, a))++the function argument is no longer (entirely) static, so the static argument+transformation will do nothing for us.++Applying the default definition of `<$` will produce a tree full of thunks that+look like ((\_ -> x) x0), which represents unnecessary thunk allocation and+also retention of the previous value, potentially leaking memory. Instead, we+derive <$ separately. Two aspects are different from fmap: the case of the+sought type variable (ft_var) and the case of a type application (ft_ty_app).+The interesting one is ft_ty_app. We have to distinguish two cases: the+"immediate" case where the type argument *is* the sought type variable, and+the "nested" case where the type argument *contains* the sought type variable.++The immediate case:++Suppose we have++data Imm a = Imm (F ... a)++Then we want to define++x <$ Imm q = Imm (x <$ q)++The nested case:++Suppose we have++data Nes a = Nes (F ... (G a))++Then we want to define++x <$ Nes q = Nes (fmap (x <$) q)++We use the Replacer type to tag whether the expression derived for applying+<$ to the last type variable was the ft_var case (immediate) or one of the+others (letting ft_forall pass through as usual).++We could, but do not, give tuples special treatment to improve efficiency+in some cases. Suppose we have++data Nest a = Z a | S (Nest (a,a))++The optimal definition would be++x <$ Z _ = Z x+x <$ S t = S ((x, x) <$ t)++which produces a result with maximal internal sharing. The reason we do not+attempt to treat this case specially is that we have no way to give+user-provided tuple-like types similar treatment. If the user changed the+definition to++data Pair a = Pair a a+data Nest a = Z a | S (Nest (Pair a))++they would experience a surprising degradation in performance. -}+++{-+Utility functions related to Functor deriving.++Since several things use the same pattern of traversal, this is abstracted into functorLikeTraverse.+This function works like a fold: it makes a value of type 'a' in a bottom up way.+-}++-- Generic traversal for Functor deriving+-- See Note [FFoldType and functorLikeTraverse]+data FFoldType a -- Describes how to fold over a Type in a functor like way+ = FT { ft_triv :: a+ -- ^ Does not contain variable+ , ft_var :: a+ -- ^ The variable itself+ , ft_co_var :: a+ -- ^ The variable itself, contravariantly+ , ft_fun :: a -> a -> a+ -- ^ Function type+ , ft_tup :: TyCon -> [a] -> a+ -- ^ Tuple type+ , ft_ty_app :: Type -> a -> a+ -- ^ Type app, variable only in last argument+ , ft_bad_app :: a+ -- ^ Type app, variable other than in last argument+ , ft_forall :: TcTyVar -> a -> a+ -- ^ Forall type+ }++functorLikeTraverse :: forall a.+ TyVar -- ^ Variable to look for+ -> FFoldType a -- ^ How to fold+ -> Type -- ^ Type to process+ -> a+functorLikeTraverse var (FT { ft_triv = caseTrivial, ft_var = caseVar+ , ft_co_var = caseCoVar, ft_fun = caseFun+ , ft_tup = caseTuple, ft_ty_app = caseTyApp+ , ft_bad_app = caseWrongArg, ft_forall = caseForAll })+ ty+ = fst (go False ty)+ where+ go :: Bool -- Covariant or contravariant context+ -> Type+ -> (a, Bool) -- (result of type a, does type contain var)++ go co ty | Just ty' <- tcView ty = go co ty'+ go co (TyVarTy v) | v == var = (if co then caseCoVar else caseVar,True)+ go co (FunTy x y) | isPredTy x = go co y+ | xc || yc = (caseFun xr yr,True)+ where (xr,xc) = go (not co) x+ (yr,yc) = go co y+ go co (AppTy x y) | xc = (caseWrongArg, True)+ | yc = (caseTyApp x yr, True)+ where (_, xc) = go co x+ (yr,yc) = go co y+ go co ty@(TyConApp con args)+ | not (or xcs) = (caseTrivial, False) -- Variable does not occur+ -- At this point we know that xrs, xcs is not empty,+ -- and at least one xr is True+ | isTupleTyCon con = (caseTuple con xrs, True)+ | or (init xcs) = (caseWrongArg, True) -- T (..var..) ty+ | Just (fun_ty, _) <- splitAppTy_maybe ty -- T (..no var..) ty+ = (caseTyApp fun_ty (last xrs), True)+ | otherwise = (caseWrongArg, True) -- Non-decomposable (eg type function)+ where+ -- When folding over an unboxed tuple, we must explicitly drop the+ -- runtime rep arguments, or else GHC will generate twice as many+ -- variables in a unboxed tuple pattern match and expression as it+ -- actually needs. See Trac #12399+ (xrs,xcs) = unzip (map (go co) (dropRuntimeRepArgs args))+ go co (ForAllTy (TvBndr v vis) x)+ | isVisibleArgFlag vis = panic "unexpected visible binder"+ | v /= var && xc = (caseForAll v xr,True)+ where (xr,xc) = go co x++ go _ _ = (caseTrivial,False)++-- Return all syntactic subterms of ty that contain var somewhere+-- These are the things that should appear in instance constraints+deepSubtypesContaining :: TyVar -> Type -> [TcType]+deepSubtypesContaining tv+ = functorLikeTraverse tv+ (FT { ft_triv = []+ , ft_var = []+ , ft_fun = (++)+ , ft_tup = \_ xs -> concat xs+ , ft_ty_app = (:)+ , ft_bad_app = panic "in other argument"+ , ft_co_var = panic "contravariant"+ , ft_forall = \v xs -> filterOut ((v `elemVarSet`) . tyCoVarsOfType) xs })+++foldDataConArgs :: FFoldType a -> DataCon -> [a]+-- Fold over the arguments of the datacon+foldDataConArgs ft con+ = map foldArg (dataConOrigArgTys con)+ where+ foldArg+ = case getTyVar_maybe (last (tyConAppArgs (dataConOrigResTy con))) of+ Just tv -> functorLikeTraverse tv ft+ Nothing -> const (ft_triv ft)+ -- If we are deriving Foldable for a GADT, there is a chance that the last+ -- type variable in the data type isn't actually a type variable at all.+ -- (for example, this can happen if the last type variable is refined to+ -- be a concrete type such as Int). If the last type variable is refined+ -- to be a specific type, then getTyVar_maybe will return Nothing.+ -- See Note [DeriveFoldable with ExistentialQuantification]+ --+ -- The kind checks have ensured the last type parameter is of kind *.++-- Make a HsLam using a fresh variable from a State monad+mkSimpleLam :: (LHsExpr RdrName -> State [RdrName] (LHsExpr RdrName))+ -> State [RdrName] (LHsExpr RdrName)+-- (mkSimpleLam fn) returns (\x. fn(x))+mkSimpleLam lam = do+ (n:names) <- get+ put names+ body <- lam (nlHsVar n)+ return (mkHsLam [nlVarPat n] body)++mkSimpleLam2 :: (LHsExpr RdrName -> LHsExpr RdrName+ -> State [RdrName] (LHsExpr RdrName))+ -> State [RdrName] (LHsExpr RdrName)+mkSimpleLam2 lam = do+ (n1:n2:names) <- get+ put names+ body <- lam (nlHsVar n1) (nlHsVar n2)+ return (mkHsLam [nlVarPat n1,nlVarPat n2] body)++-- "Con a1 a2 a3 -> fold [x1 a1, x2 a2, x3 a3]"+--+-- @mkSimpleConMatch fold extra_pats con insides@ produces a match clause in+-- which the LHS pattern-matches on @extra_pats@, followed by a match on the+-- constructor @con@ and its arguments. The RHS folds (with @fold@) over @con@+-- and its arguments, applying an expression (from @insides@) to each of the+-- respective arguments of @con@.+mkSimpleConMatch :: Monad m => HsMatchContext RdrName+ -> (RdrName -> [LHsExpr RdrName] -> m (LHsExpr RdrName))+ -> [LPat RdrName]+ -> DataCon+ -> [LHsExpr RdrName]+ -> m (LMatch RdrName (LHsExpr RdrName))+mkSimpleConMatch ctxt fold extra_pats con insides = do+ let con_name = getRdrName con+ let vars_needed = takeList insides as_RDRs+ let bare_pat = nlConVarPat con_name vars_needed+ let pat = if null vars_needed+ then bare_pat+ else nlParPat bare_pat+ rhs <- fold con_name (zipWith nlHsApp insides (map nlHsVar vars_needed))+ return $ mkMatch ctxt (extra_pats ++ [pat]) rhs+ (noLoc emptyLocalBinds)++-- "Con a1 a2 a3 -> fmap (\b2 -> Con a1 b2 a3) (traverse f a2)"+--+-- @mkSimpleConMatch2 fold extra_pats con insides@ behaves very similarly to+-- 'mkSimpleConMatch', with two key differences:+--+-- 1. @insides@ is a @[Maybe (LHsExpr RdrName)]@ instead of a+-- @[LHsExpr RdrName]@. This is because it filters out the expressions+-- corresponding to arguments whose types do not mention the last type+-- variable in a derived 'Foldable' or 'Traversable' instance (i.e., the+-- 'Nothing' elements of @insides@).+--+-- 2. @fold@ takes an expression as its first argument instead of a+-- constructor name. This is because it uses a specialized+-- constructor function expression that only takes as many parameters as+-- there are argument types that mention the last type variable.+--+-- See Note [Generated code for DeriveFoldable and DeriveTraversable]+mkSimpleConMatch2 :: Monad m+ => HsMatchContext RdrName+ -> (LHsExpr RdrName -> [LHsExpr RdrName]+ -> m (LHsExpr RdrName))+ -> [LPat RdrName]+ -> DataCon+ -> [Maybe (LHsExpr RdrName)]+ -> m (LMatch RdrName (LHsExpr RdrName))+mkSimpleConMatch2 ctxt fold extra_pats con insides = do+ let con_name = getRdrName con+ vars_needed = takeList insides as_RDRs+ pat = nlConVarPat con_name vars_needed+ -- Make sure to zip BEFORE invoking catMaybes. We want the variable+ -- indicies in each expression to match up with the argument indices+ -- in con_expr (defined below).+ exps = catMaybes $ zipWith (\i v -> (`nlHsApp` v) <$> i)+ insides (map nlHsVar vars_needed)+ -- An element of argTysTyVarInfo is True if the constructor argument+ -- with the same index has a type which mentions the last type+ -- variable.+ argTysTyVarInfo = map isJust insides+ (asWithTyVar, asWithoutTyVar) = partitionByList argTysTyVarInfo as_RDRs++ con_expr+ | null asWithTyVar = nlHsApps con_name $ map nlHsVar asWithoutTyVar+ | otherwise =+ let bs = filterByList argTysTyVarInfo bs_RDRs+ vars = filterByLists argTysTyVarInfo+ (map nlHsVar bs_RDRs)+ (map nlHsVar as_RDRs)+ in mkHsLam (map nlVarPat bs) (nlHsApps con_name vars)++ rhs <- fold con_expr exps+ return $ mkMatch ctxt (extra_pats ++ [pat]) rhs+ (noLoc emptyLocalBinds)++-- "case x of (a1,a2,a3) -> fold [x1 a1, x2 a2, x3 a3]"+mkSimpleTupleCase :: Monad m => ([LPat RdrName] -> DataCon -> [a]+ -> m (LMatch RdrName (LHsExpr RdrName)))+ -> TyCon -> [a] -> LHsExpr RdrName -> m (LHsExpr RdrName)+mkSimpleTupleCase match_for_con tc insides x+ = do { let data_con = tyConSingleDataCon tc+ ; match <- match_for_con [] data_con insides+ ; return $ nlHsCase x [match] }++{-+************************************************************************+* *+ Foldable instances++ see http://www.mail-archive.com/haskell-prime@haskell.org/msg02116.html++* *+************************************************************************++Deriving Foldable instances works the same way as Functor instances,+only Foldable instances are not possible for function types at all.+Given (data T a = T a a (T a) deriving Foldable), we get:++ instance Foldable T where+ foldr f z (T x1 x2 x3) =+ $(foldr 'a 'a) x1 ( $(foldr 'a 'a) x2 ( $(foldr 'a '(T a)) x3 z ) )++-XDeriveFoldable is different from -XDeriveFunctor in that it filters out+arguments to the constructor that would produce useless code in a Foldable+instance. For example, the following datatype:++ data Foo a = Foo Int a Int deriving Foldable++would have the following generated Foldable instance:++ instance Foldable Foo where+ foldr f z (Foo x1 x2 x3) = $(foldr 'a 'a) x2++since neither of the two Int arguments are folded over.++The cases are:++ $(foldr 'a 'a) = f+ $(foldr 'a '(b1,b2)) = \x z -> case x of (x1,x2) -> $(foldr 'a 'b1) x1 ( $(foldr 'a 'b2) x2 z )+ $(foldr 'a '(T b1 b2)) = \x z -> foldr $(foldr 'a 'b2) z x -- when a only occurs in the last parameter, b2++Note that the arguments to the real foldr function are the wrong way around,+since (f :: a -> b -> b), while (foldr f :: b -> t a -> b).++One can envision a case for types that don't contain the last type variable:++ $(foldr 'a 'b) = \x z -> z -- when b does not contain a++But this case will never materialize, since the aforementioned filtering+removes all such types from consideration.+See Note [Generated code for DeriveFoldable and DeriveTraversable].++Foldable instances differ from Functor and Traversable instances in that+Foldable instances can be derived for data types in which the last type+variable is existentially quantified. In particular, if the last type variable+is refined to a more specific type in a GADT:++ data GADT a where+ G :: a ~ Int => a -> G Int++then the deriving machinery does not attempt to check that the type a contains+Int, since it is not syntactically equal to a type variable. That is, the+derived Foldable instance for GADT is:++ instance Foldable GADT where+ foldr _ z (GADT _) = z++See Note [DeriveFoldable with ExistentialQuantification].++-}++gen_Foldable_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)+gen_Foldable_binds loc tycon+ = (listToBag [foldr_bind, foldMap_bind], emptyBag)+ where+ data_cons = tyConDataCons tycon++ foldr_bind = mkRdrFunBind (L 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++ foldMap_bind = mkRdrFunBind (L loc foldMap_RDR) (map foldMap_eqn data_cons)+ foldMap_eqn con+ = evalState (match_foldMap [f_Pat] con =<< parts) bs_RDRs+ where+ parts = sequence $ foldDataConArgs ft_foldMap con++ -- Yields 'Just' an expression if we're folding over a type that mentions+ -- the last type parameter of the datatype. Otherwise, yields 'Nothing'.+ -- See Note [FFoldType and functorLikeTraverse]+ ft_foldr :: FFoldType (State [RdrName] (Maybe (LHsExpr RdrName)))+ ft_foldr+ = FT { ft_triv = return Nothing+ -- foldr f = \x z -> z+ , ft_var = return $ Just f_Expr+ -- foldr f = f+ , ft_tup = \t g -> do+ gg <- sequence g+ lam <- mkSimpleLam2 $ \x z ->+ mkSimpleTupleCase (match_foldr z) t gg x+ return (Just lam)+ -- foldr f = (\x z -> case x of ...)+ , ft_ty_app = \_ g -> do+ gg <- g+ mapM (\gg' -> mkSimpleLam2 $ \x z -> return $+ nlHsApps foldable_foldr_RDR [gg',z,x]) gg+ -- foldr f = (\x z -> foldr g z x)+ , ft_forall = \_ g -> g+ , ft_co_var = panic "contravariant"+ , ft_fun = panic "function"+ , ft_bad_app = panic "in other argument" }++ match_foldr :: LHsExpr RdrName+ -> [LPat RdrName]+ -> DataCon+ -> [Maybe (LHsExpr RdrName)]+ -> State [RdrName] (LMatch RdrName (LHsExpr RdrName))+ match_foldr z = mkSimpleConMatch2 LambdaExpr $ \_ xs -> return (mkFoldr xs)+ where+ -- g1 v1 (g2 v2 (.. z))+ mkFoldr :: [LHsExpr RdrName] -> LHsExpr RdrName+ mkFoldr = foldr nlHsApp z++ -- See Note [FFoldType and functorLikeTraverse]+ ft_foldMap :: FFoldType (State [RdrName] (Maybe (LHsExpr RdrName)))+ ft_foldMap+ = FT { ft_triv = return Nothing+ -- foldMap f = \x -> mempty+ , ft_var = return (Just f_Expr)+ -- foldMap f = f+ , ft_tup = \t g -> do+ gg <- sequence g+ lam <- mkSimpleLam $ mkSimpleTupleCase match_foldMap t gg+ return (Just lam)+ -- foldMap f = \x -> case x of (..,)+ , ft_ty_app = \_ g -> fmap (nlHsApp foldMap_Expr) <$> g+ -- foldMap f = foldMap g+ , ft_forall = \_ g -> g+ , ft_co_var = panic "contravariant"+ , ft_fun = panic "function"+ , ft_bad_app = panic "in other argument" }++ match_foldMap :: [LPat RdrName]+ -> DataCon+ -> [Maybe (LHsExpr RdrName)]+ -> State [RdrName] (LMatch RdrName (LHsExpr RdrName))+ match_foldMap = mkSimpleConMatch2 CaseAlt $ \_ xs -> return (mkFoldMap xs)+ where+ -- mappend v1 (mappend v2 ..)+ mkFoldMap :: [LHsExpr RdrName] -> LHsExpr RdrName+ mkFoldMap [] = mempty_Expr+ mkFoldMap xs = foldr1 (\x y -> nlHsApps mappend_RDR [x,y]) xs++{-+************************************************************************+* *+ Traversable instances++ see http://www.mail-archive.com/haskell-prime@haskell.org/msg02116.html+* *+************************************************************************++Again, Traversable is much like Functor and Foldable.++The cases are:++ $(traverse 'a 'a) = f+ $(traverse 'a '(b1,b2)) = \x -> case x of (x1,x2) ->+ liftA2 (,) ($(traverse 'a 'b1) x1) ($(traverse 'a 'b2) x2)+ $(traverse 'a '(T b1 b2)) = traverse $(traverse 'a 'b2) -- when a only occurs in the last parameter, b2++Like -XDeriveFoldable, -XDeriveTraversable filters out arguments whose types+do not mention the last type parameter. Therefore, the following datatype:++ data Foo a = Foo Int a Int++would have the following derived Traversable instance:++ instance Traversable Foo where+ traverse f (Foo x1 x2 x3) =+ fmap (\b2 -> Foo x1 b2 x3) ( $(traverse 'a 'a) x2 )++since the two Int arguments do not produce any effects in a traversal.++One can envision a case for types that do not mention the last type parameter:++ $(traverse 'a 'b) = pure -- when b does not contain a++But this case will never materialize, since the aforementioned filtering+removes all such types from consideration.+See Note [Generated code for DeriveFoldable and DeriveTraversable].+-}++gen_Traversable_binds :: SrcSpan -> TyCon -> (LHsBinds RdrName, BagDerivStuff)+gen_Traversable_binds loc tycon+ = (unitBag traverse_bind, emptyBag)+ where+ data_cons = tyConDataCons tycon++ traverse_bind = mkRdrFunBind (L loc traverse_RDR) eqns+ eqns = map traverse_eqn data_cons+ traverse_eqn con+ = evalState (match_for_con [f_Pat] con =<< parts) bs_RDRs+ where+ parts = sequence $ foldDataConArgs ft_trav con++ -- Yields 'Just' an expression if we're folding over a type that mentions+ -- the last type parameter of the datatype. Otherwise, yields 'Nothing'.+ -- See Note [FFoldType and functorLikeTraverse]+ ft_trav :: FFoldType (State [RdrName] (Maybe (LHsExpr RdrName)))+ ft_trav+ = FT { ft_triv = return Nothing+ -- traverse f = pure x+ , ft_var = return (Just f_Expr)+ -- traverse f = f x+ , ft_tup = \t gs -> do+ gg <- sequence gs+ lam <- mkSimpleLam $ mkSimpleTupleCase match_for_con t gg+ return (Just lam)+ -- traverse f = \x -> case x of (a1,a2,..) ->+ -- liftA2 (,,) (g1 a1) (g2 a2) <*> ..+ , ft_ty_app = \_ g -> fmap (nlHsApp traverse_Expr) <$> g+ -- traverse f = traverse g+ , ft_forall = \_ g -> g+ , ft_co_var = panic "contravariant"+ , ft_fun = panic "function"+ , ft_bad_app = panic "in other argument" }++ -- Con a1 a2 ... -> liftA2 (\b1 b2 ... -> Con b1 b2 ...) (g1 a1)+ -- (g2 a2) <*> ...+ match_for_con :: [LPat RdrName]+ -> DataCon+ -> [Maybe (LHsExpr RdrName)]+ -> State [RdrName] (LMatch RdrName (LHsExpr RdrName))+ match_for_con = mkSimpleConMatch2 CaseAlt $+ \con xs -> return (mkApCon con xs)+ where+ -- liftA2 (\b1 b2 ... -> Con b1 b2 ...) x1 x2 <*> ..+ mkApCon :: LHsExpr RdrName -> [LHsExpr RdrName] -> LHsExpr RdrName+ mkApCon con [] = nlHsApps pure_RDR [con]+ mkApCon con [x] = nlHsApps fmap_RDR [con,x]+ mkApCon con (x1:x2:xs) =+ foldl appAp (nlHsApps liftA2_RDR [con,x1,x2]) xs+ where appAp x y = nlHsApps ap_RDR [x,y]++-----------------------------------------------------------------------++f_Expr, z_Expr, fmap_Expr, replace_Expr, mempty_Expr, foldMap_Expr,+ traverse_Expr :: LHsExpr RdrName+f_Expr = nlHsVar f_RDR+z_Expr = nlHsVar z_RDR+fmap_Expr = nlHsVar fmap_RDR+replace_Expr = nlHsVar replace_RDR+mempty_Expr = nlHsVar mempty_RDR+foldMap_Expr = nlHsVar foldMap_RDR+traverse_Expr = nlHsVar traverse_RDR++f_RDR, z_RDR :: RdrName+f_RDR = mkVarUnqual (fsLit "f")+z_RDR = mkVarUnqual (fsLit "z")++as_RDRs, bs_RDRs :: [RdrName]+as_RDRs = [ mkVarUnqual (mkFastString ("a"++show i)) | i <- [(1::Int) .. ] ]+bs_RDRs = [ mkVarUnqual (mkFastString ("b"++show i)) | i <- [(1::Int) .. ] ]++f_Pat, z_Pat :: LPat RdrName+f_Pat = nlVarPat f_RDR+z_Pat = nlVarPat z_RDR++{-+Note [DeriveFoldable with ExistentialQuantification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Functor and Traversable instances can only be derived for data types whose+last type parameter is truly universally polymorphic. For example:++ data T a b where+ T1 :: b -> T a b -- YES, b is unconstrained+ T2 :: Ord b => b -> T a b -- NO, b is constrained by (Ord b)+ T3 :: b ~ Int => b -> T a b -- NO, b is constrained by (b ~ Int)+ T4 :: Int -> T a Int -- NO, this is just like T3+ T5 :: Ord a => a -> b -> T a b -- YES, b is unconstrained, even+ -- though a is existential+ T6 :: Int -> T Int b -- YES, b is unconstrained++For Foldable instances, however, we can completely lift the constraint that+the last type parameter be truly universally polymorphic. This means that T+(as defined above) can have a derived Foldable instance:++ instance Foldable (T a) where+ foldr f z (T1 b) = f b z+ foldr f z (T2 b) = f b z+ foldr f z (T3 b) = f b z+ foldr f z (T4 b) = z+ foldr f z (T5 a b) = f b z+ foldr f z (T6 a) = z++ foldMap f (T1 b) = f b+ foldMap f (T2 b) = f b+ foldMap f (T3 b) = f b+ foldMap f (T4 b) = mempty+ foldMap f (T5 a b) = f b+ foldMap f (T6 a) = mempty++In a Foldable instance, it is safe to fold over an occurrence of the last type+parameter that is not truly universally polymorphic. However, there is a bit+of subtlety in determining what is actually an occurrence of a type parameter.+T3 and T4, as defined above, provide one example:++ data T a b where+ ...+ T3 :: b ~ Int => b -> T a b+ T4 :: Int -> T a Int+ ...++ instance Foldable (T a) where+ ...+ foldr f z (T3 b) = f b z+ foldr f z (T4 b) = z+ ...+ foldMap f (T3 b) = f b+ foldMap f (T4 b) = mempty+ ...++Notice that the argument of T3 is folded over, whereas the argument of T4 is+not. This is because we only fold over constructor arguments that+syntactically mention the universally quantified type parameter of that+particular data constructor. See foldDataConArgs for how this is implemented.++As another example, consider the following data type. The argument of each+constructor has the same type as the last type parameter:++ data E a where+ E1 :: (a ~ Int) => a -> E a+ E2 :: Int -> E Int+ E3 :: (a ~ Int) => a -> E Int+ E4 :: (a ~ Int) => Int -> E a++Only E1's argument is an occurrence of a universally quantified type variable+that is syntactically equivalent to the last type parameter, so only E1's+argument will be be folded over in a derived Foldable instance.++See Trac #10447 for the original discussion on this feature. Also see+https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/DeriveFunctor+for a more in-depth explanation.++Note [FFoldType and functorLikeTraverse]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Deriving Functor, Foldable, and Traversable all require generating expressions+which perform an operation on each argument of a data constructor depending+on the argument's type. In particular, a generated operation can be different+depending on whether the type mentions the last type variable of the datatype+(e.g., if you have data T a = MkT a Int, then a generated foldr expression would+fold over the first argument of MkT, but not the second).++This pattern is abstracted with the FFoldType datatype, which provides hooks+for the user to specify how a constructor argument should be folded when it+has a type with a particular "shape". The shapes are as follows (assume that+a is the last type variable in a given datatype):++* ft_triv: The type does not mention the last type variable at all.+ Examples: Int, b++* ft_var: The type is syntactically equal to the last type variable.+ Moreover, the type appears in a covariant position (see+ the Deriving Functor instances section of the user's guide+ for an in-depth explanation of covariance vs. contravariance).+ Example: a (covariantly)++* ft_co_var: The type is syntactically equal to the last type variable.+ Moreover, the type appears in a contravariant position.+ Example: a (contravariantly)++* ft_fun: A function type which mentions the last type variable in+ the argument position, result position or both.+ Examples: a -> Int, Int -> a, Maybe a -> [a]++* ft_tup: A tuple type which mentions the last type variable in at least+ one of its fields. The TyCon argument of ft_tup represents the+ particular tuple's type constructor.+ Examples: (a, Int), (Maybe a, [a], Either a Int), (# Int, a #)++* ft_ty_app: A type is being applied to the last type parameter, where the+ applied type does not mention the last type parameter (if it+ did, it would fall under ft_bad_app). The Type argument to+ ft_ty_app represents the applied type.++ Note that functions, tuples, and foralls are distinct cases+ and take precedence of ft_ty_app. (For example, (Int -> a) would+ fall under (ft_fun Int a), not (ft_ty_app ((->) Int) a).+ Examples: Maybe a, Either b a++* ft_bad_app: A type application uses the last type parameter in a position+ other than the last argument. This case is singled out because+ Functor, Foldable, and Traversable instances cannot be derived+ for datatypes containing arguments with such types.+ Examples: Either a Int, Const a b++* ft_forall: A forall'd type mentions the last type parameter on its right-+ hand side (and is not quantified on the left-hand side). This+ case is present mostly for plumbing purposes.+ Example: forall b. Either b a++If FFoldType describes a strategy for folding subcomponents of a Type, then+functorLikeTraverse is the function that applies that strategy to the entirety+of a Type, returning the final folded-up result.++foldDataConArgs applies functorLikeTraverse to every argument type of a+constructor, returning a list of the fold results. This makes foldDataConArgs+a natural way to generate the subexpressions in a generated fmap, foldr,+foldMap, or traverse definition (the subexpressions must then be combined in+a method-specific fashion to form the final generated expression).++Deriving Generic1 also does validity checking by looking for the last type+variable in certain positions of a constructor's argument types, so it also+uses foldDataConArgs. See Note [degenerate use of FFoldType] in TcGenGenerics.++Note [Generated code for DeriveFoldable and DeriveTraversable]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We adapt the algorithms for -XDeriveFoldable and -XDeriveTraversable based on+that of -XDeriveFunctor. However, there an important difference between deriving+the former two typeclasses and the latter one, which is best illustrated by the+following scenario:++ data WithInt a = WithInt a Int# deriving (Functor, Foldable, Traversable)++The generated code for the Functor instance is straightforward:++ instance Functor WithInt where+ fmap f (WithInt a i) = WithInt (f a) i++But if we use too similar of a strategy for deriving the Foldable and+Traversable instances, we end up with this code:++ instance Foldable WithInt where+ foldMap f (WithInt a i) = f a <> mempty++ instance Traversable WithInt where+ traverse f (WithInt a i) = fmap WithInt (f a) <*> pure i++This is unsatisfying for two reasons:++1. The Traversable instance doesn't typecheck! Int# is of kind #, but pure+ expects an argument whose type is of kind *. This effectively prevents+ Traversable from being derived for any datatype with an unlifted argument+ type (Trac #11174).++2. The generated code contains superfluous expressions. By the Monoid laws,+ we can reduce (f a <> mempty) to (f a), and by the Applicative laws, we can+ reduce (fmap WithInt (f a) <*> pure i) to (fmap (\b -> WithInt b i) (f a)).++We can fix both of these issues by incorporating a slight twist to the usual+algorithm that we use for -XDeriveFunctor. The differences can be summarized+as follows:++1. In the generated expression, we only fold over arguments whose types+ mention the last type parameter. Any other argument types will simply+ produce useless 'mempty's or 'pure's, so they can be safely ignored.++2. In the case of -XDeriveTraversable, instead of applying ConName,+ we apply (\b_i ... b_k -> ConName a_1 ... a_n), where++ * ConName has n arguments+ * {b_i, ..., b_k} is a subset of {a_1, ..., a_n} whose indices correspond+ to the arguments whose types mention the last type parameter. As a+ consequence, taking the difference of {a_1, ..., a_n} and+ {b_i, ..., b_k} yields the all the argument values of ConName whose types+ do not mention the last type parameter. Note that [i, ..., k] is a+ strictly increasing—but not necessarily consecutive—integer sequence.++ For example, the datatype++ data Foo a = Foo Int a Int a++ would generate the following Traversable instance:++ instance Traversable Foo where+ traverse f (Foo a1 a2 a3 a4) =+ fmap (\b2 b4 -> Foo a1 b2 a3 b4) (f a2) <*> f a4++Technically, this approach would also work for -XDeriveFunctor as well, but we+decide not to do so because:++1. There's not much benefit to generating, e.g., ((\b -> WithInt b i) (f a))+ instead of (WithInt (f a) i).++2. There would be certain datatypes for which the above strategy would+ generate Functor code that would fail to typecheck. For example:++ data Bar f a = Bar (forall f. Functor f => f a) deriving Functor++ With the conventional algorithm, it would generate something like:++ fmap f (Bar a) = Bar (fmap f a)++ which typechecks. But with the strategy mentioned above, it would generate:++ fmap f (Bar a) = (\b -> Bar b) (fmap f a)++ which does not typecheck, since GHC cannot unify the rank-2 type variables+ in the types of b and (fmap f a).+-}
+ typecheck/TcGenGenerics.hs view
@@ -0,0 +1,1010 @@+{-+(c) The University of Glasgow 2011+++The deriving code for the Generic class+(equivalent to the code in TcGenDeriv, for other classes)+-}++{-# LANGUAGE CPP, ScopedTypeVariables, TupleSections #-}+{-# LANGUAGE FlexibleContexts #-}++module TcGenGenerics (canDoGenerics, canDoGenerics1,+ GenericKind(..),+ gen_Generic_binds, get_gen1_constrained_tys) where++import HsSyn+import Type+import TcType+import TcGenDeriv+import TcGenFunctor+import DataCon+import TyCon+import FamInstEnv ( FamInst, FamFlavor(..), mkSingleCoAxiom )+import FamInst+import Module ( moduleName, moduleNameFS+ , moduleUnitId, unitIdFS, getModule )+import IfaceEnv ( newGlobalBinder )+import Name hiding ( varName )+import RdrName+import BasicTypes+import TysPrim+import TysWiredIn+import PrelNames+import TcEnv+import TcRnMonad+import HscTypes+import ErrUtils( Validity(..), andValid )+import SrcLoc+import Bag+import VarEnv+import VarSet (elemVarSet)+import Outputable+import FastString+import Util++import Control.Monad (mplus)+import Data.List (zip4, partition)+import Data.Maybe (isJust)++#include "HsVersions.h"++{-+************************************************************************+* *+\subsection{Bindings for the new generic deriving mechanism}+* *+************************************************************************++For the generic representation we need to generate:+\begin{itemize}+\item A Generic instance+\item A Rep type instance+\item Many auxiliary datatypes and instances for them (for the meta-information)+\end{itemize}+-}++gen_Generic_binds :: GenericKind -> TyCon -> [Type]+ -> TcM (LHsBinds RdrName, FamInst)+gen_Generic_binds gk tc inst_tys = do+ repTyInsts <- tc_mkRepFamInsts gk tc inst_tys+ return (mkBindsRep gk tc, repTyInsts)++{-+************************************************************************+* *+\subsection{Generating representation types}+* *+************************************************************************+-}++get_gen1_constrained_tys :: TyVar -> Type -> [Type]+-- called by TcDeriv.inferConstraints; generates a list of types, each of which+-- must be a Functor in order for the Generic1 instance to work.+get_gen1_constrained_tys argVar+ = argTyFold argVar $ ArgTyAlg { ata_rec0 = const []+ , ata_par1 = [], ata_rec1 = const []+ , ata_comp = (:) }++{-++Note [Requirements for deriving Generic and Rep]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++In the following, T, Tfun, and Targ are "meta-variables" ranging over type+expressions.++(Generic T) and (Rep T) are derivable for some type expression T if the+following constraints are satisfied.++ (a) D is a type constructor *value*. In other words, D is either a type+ constructor or it is equivalent to the head of a data family instance (up to+ alpha-renaming).++ (b) D cannot have a "stupid context".++ (c) The right-hand side of D cannot include existential types, universally+ quantified types, or "exotic" unlifted types. An exotic unlifted type+ is one which is not listed in the definition of allowedUnliftedTy+ (i.e., one for which we have no representation type).+ See Note [Generics and unlifted types]++ (d) T :: *.++(Generic1 T) and (Rep1 T) are derivable for some type expression T if the+following constraints are satisfied.++ (a),(b),(c) As above.++ (d) T must expect arguments, and its last parameter must have kind *.++ We use `a' to denote the parameter of D that corresponds to the last+ parameter of T.++ (e) For any type-level application (Tfun Targ) in the right-hand side of D+ where the head of Tfun is not a tuple constructor:++ (b1) `a' must not occur in Tfun.++ (b2) If `a' occurs in Targ, then Tfun :: * -> *.++-}++canDoGenerics :: TyCon -> Validity+-- canDoGenerics determines if Generic/Rep can be derived.+--+-- Check (a) from Note [Requirements for deriving Generic and Rep] is taken+-- care of because canDoGenerics is applied to rep tycons.+--+-- It returns IsValid if deriving is possible. It returns (NotValid reason)+-- if not.+canDoGenerics tc+ = 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"))+ 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+ Just (ptc, _) -> ptc+ _ -> tc++ -- Check (c) from Note [Requirements for deriving Generic and Rep].+ --+ -- If any of the constructors has an exotic unlifted type as argument,+ -- 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 (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)++ -- Nor can we do the job if it's an existential data constructor,+ -- Nor if the args are polymorphic types (I don't think)+ bad_arg_type ty = (isUnliftedType ty && not (allowedUnliftedTy ty))+ || not (isTauTy ty)++-- Returns True the Type argument is an unlifted type which has a+-- corresponding generic representation type. For example,+-- (allowedUnliftedTy Int#) would return True since there is the UInt+-- representation type.+allowedUnliftedTy :: Type -> Bool+allowedUnliftedTy = isJust . unboxedRepRDRs++mergeErrors :: [Validity] -> Validity+mergeErrors [] = IsValid+mergeErrors (NotValid s:t) = case mergeErrors t of+ IsValid -> NotValid s+ NotValid s' -> NotValid (s <> text ", and" $$ s')+mergeErrors (IsValid : t) = mergeErrors t++-- 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+ }++{-++Note [degenerate use of FFoldType]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++We use foldDataConArgs here only for its ability to treat tuples+specially. foldDataConArgs also tracks covariance (though it assumes all+higher-order type parameters are covariant) and has hooks for special handling+of functions and polytypes, but we do *not* use those.++The key issue is that Generic1 deriving currently offers no sophisticated+support for functions. For example, we cannot handle++ data F a = F ((a -> Int) -> Int)++even though a is occurring covariantly.++In fact, our rule is harsh: a is simply not allowed to occur within the first+argument of (->). We treat (->) the same as any other non-tuple tycon.++Unfortunately, this means we have to track "the parameter occurs in this type"+explicitly, even though foldDataConArgs is also doing this internally.++-}++-- canDoGenerics1 determines if a Generic1/Rep1 can be derived.+--+-- Checks (a) through (c) from Note [Requirements for deriving Generic and Rep]+-- are taken care of by the call to canDoGenerics.+--+-- It returns IsValid if deriving is possible. It returns (NotValid reason)+-- if not.+canDoGenerics1 :: TyCon -> Validity+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"++ | otherwise = mergeErrors $ concatMap check_con data_cons++ data_cons = tyConDataCons rep_tc+ check_con con = case check_vanilla con of+ 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 con | isVanillaDataCon con = IsValid+ | otherwise = NotValid (bad con existential)++ bmzero = CCDG1 False IsValid+ bmbad con s = CCDG1 True $ NotValid $ bad con s+ bmplus (CCDG1 b1 m1) (CCDG1 b2 m2) = CCDG1 (b1 || b2) (m1 `andValid` m2)++ -- check (e) from Note [Requirements for deriving Generic and Rep]+ -- See also Note [degenerate use of FFoldType]+ ft_check :: DataCon -> FFoldType Check_for_CanDoGenerics1+ ft_check con = FT+ { ft_triv = bmzero++ , ft_var = caseVar, ft_co_var = caseVar++ -- (component_0,component_1,...,component_n)+ , ft_tup = \_ components -> if any _ccdg1_hasParam (init components)+ then bmbad con wrong_arg+ 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+ 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_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 * -> *"++{-+************************************************************************+* *+\subsection{Generating the RHS of a generic default method}+* *+************************************************************************+-}++type US = Int -- Local unique supply, just a plain Int+type Alt = (LPat RdrName, LHsExpr RdrName)++-- GenericKind serves to mark if a datatype derives Generic (Gen0) or+-- Generic1 (Gen1).+data GenericKind = Gen0 | Gen1++-- as above, but with a payload of the TyCon's name for "the" parameter+data GenericKind_ = Gen0_ | Gen1_ TyVar++-- as above, but using a single datacon's name for "the" parameter+data GenericKind_DC = Gen0_DC | Gen1_DC TyVar++forgetArgVar :: GenericKind_DC -> GenericKind+forgetArgVar Gen0_DC = Gen0+forgetArgVar Gen1_DC{} = Gen1++-- When working only within a single datacon, "the" parameter's name should+-- match that datacon's name for it.+gk2gkDC :: GenericKind_ -> DataCon -> GenericKind_DC+gk2gkDC Gen0_ _ = Gen0_DC+gk2gkDC Gen1_{} d = Gen1_DC $ last $ dataConUnivTyVars d+++-- Bindings for the Generic instance+mkBindsRep :: GenericKind -> TyCon -> LHsBinds RdrName+mkBindsRep gk tycon =+ unitBag (mkRdrFunBind (L loc from01_RDR) [from_eqn])+ `unionBags`+ unitBag (mkRdrFunBind (L loc to01_RDR) [to_eqn])+ where+ -- The topmost M1 (the datatype metadata) has the exact same type+ -- across all cases of a from/to definition, and can be factored out+ -- to save some allocations during typechecking.+ -- See Note [Generics compilation speed tricks]+ from_eqn = mkHsCaseAlt x_Pat $ mkM1_E+ $ nlHsPar $ nlHsCase x_Expr from_matches+ to_eqn = mkHsCaseAlt (mkM1_P x_Pat) $ nlHsCase x_Expr to_matches++ from_matches = [mkHsCaseAlt pat rhs | (pat,rhs) <- from_alts]+ to_matches = [mkHsCaseAlt pat rhs | (pat,rhs) <- to_alts ]+ loc = srcLocSpan (getSrcLoc tycon)+ datacons = tyConDataCons tycon++ (from01_RDR, to01_RDR) = case gk of+ Gen0 -> (from_RDR, to_RDR)+ Gen1 -> (from1_RDR, to1_RDR)++ -- Recurse over the sum first+ from_alts, to_alts :: [Alt]+ (from_alts, to_alts) = mkSum gk_ (1 :: US) tycon datacons+ where gk_ = case gk of+ Gen0 -> Gen0_+ Gen1 -> ASSERT(length tyvars >= 1)+ Gen1_ (last tyvars)+ where tyvars = tyConTyVars tycon++--------------------------------------------------------------------------------+-- The type synonym instance and synonym+-- type instance Rep (D a b) = Rep_D a b+-- type Rep_D a b = ...representation type for D ...+--------------------------------------------------------------------------------++tc_mkRepFamInsts :: GenericKind -- Gen0 or Gen1+ -> TyCon -- The type to generate representation for+ -> [Type] -- The type(s) to which Generic(1) is applied+ -- in the generated instance+ -> TcM FamInst -- Generated representation0 coercion+tc_mkRepFamInsts gk tycon inst_tys =+ -- Consider the example input tycon `D`, where data D a b = D_ a+ -- Also consider `R:DInt`, where { data family D x y :: * -> *+ -- ; data instance D Int a b = D_ a }+ do { -- `rep` = GHC.Generics.Rep or GHC.Generics.Rep1 (type family)+ fam_tc <- case gk of+ Gen0 -> tcLookupTyCon repTyConName+ Gen1 -> tcLookupTyCon rep1TyConName++ ; fam_envs <- tcGetFamInstEnvs++ ; let -- If the derived instance is+ -- instance Generic (Foo x)+ -- then:+ -- `arg_ki` = *, `inst_ty` = Foo x :: *+ --+ -- If the derived instance is+ -- instance Generic1 (Bar x :: k -> *)+ -- then:+ -- `arg_k` = k, `inst_ty` = Bar x :: k -> *+ (arg_ki, inst_ty) = case (gk, inst_tys) of+ (Gen0, [inst_t]) -> (liftedTypeKind, inst_t)+ (Gen1, [arg_k, inst_t]) -> (arg_k, inst_t)+ _ -> pprPanic "tc_mkRepFamInsts" (ppr inst_tys)++ ; let mbFamInst = tyConFamInst_maybe tycon+ -- If we're examining a data family instance, we grab the parent+ -- TyCon (ptc) and use it to determine the type arguments+ -- (inst_args) for the data family *instance*'s type variables.+ ptc = maybe tycon fst mbFamInst+ (_, inst_args, _) = tcLookupDataFamInst fam_envs ptc $ snd+ $ tcSplitTyConApp inst_ty++ ; let -- `tyvars` = [a,b]+ (tyvars, gk_) = case gk of+ Gen0 -> (all_tyvars, Gen0_)+ Gen1 -> ASSERT(not $ null all_tyvars)+ (init all_tyvars, Gen1_ $ last all_tyvars)+ where all_tyvars = tyConTyVars tycon++ -- `repTy` = D1 ... (C1 ... (S1 ... (Rec0 a))) :: * -> *+ ; repTy <- tc_mkRepTy gk_ tycon arg_ki++ -- `rep_name` is a name we generate for the synonym+ ; mod <- getModule+ ; loc <- getSrcSpanM+ ; let tc_occ = nameOccName (tyConName tycon)+ rep_occ = case gk of Gen0 -> mkGenR tc_occ; Gen1 -> mkGen1R tc_occ+ ; rep_name <- newGlobalBinder mod rep_occ loc++ -- We make sure to substitute the tyvars with their user-supplied+ -- type arguments before generating the Rep/Rep1 instance, since some+ -- of the tyvars might have been instantiated when deriving.+ -- See Note [Generating a correctly typed Rep instance].+ ; let env = zipTyEnv tyvars inst_args+ in_scope = mkInScopeSet (tyCoVarsOfTypes inst_tys)+ subst = mkTvSubst in_scope env+ repTy' = substTy subst repTy+ tcv' = tyCoVarsOfTypeList inst_ty+ (tv', cv') = partition isTyVar tcv'+ tvs' = toposortTyVars tv'+ cvs' = toposortTyVars cv'+ axiom = mkSingleCoAxiom Nominal rep_name tvs' cvs'+ fam_tc inst_tys repTy'++ ; newFamInst SynFamilyInst axiom }++--------------------------------------------------------------------------------+-- Type representation+--------------------------------------------------------------------------------++-- | See documentation of 'argTyFold'; that function uses the fields of this+-- type to interpret the structure of a type when that type is considered as an+-- argument to a constructor that is being represented with 'Rep1'.+data ArgTyAlg a = ArgTyAlg+ { ata_rec0 :: (Type -> a)+ , ata_par1 :: a, ata_rec1 :: (Type -> a)+ , ata_comp :: (Type -> a -> a)+ }++-- | @argTyFold@ implements a generalised and safer variant of the @arg@+-- function from Figure 3 in <http://dreixel.net/research/pdf/gdmh.pdf>. @arg@+-- is conceptually equivalent to:+--+-- > arg t = case t of+-- > _ | isTyVar t -> if (t == argVar) then Par1 else Par0 t+-- > App f [t'] |+-- > representable1 f &&+-- > t' == argVar -> Rec1 f+-- > App f [t'] |+-- > representable1 f &&+-- > t' has tyvars -> f :.: (arg t')+-- > _ -> Rec0 t+--+-- where @argVar@ is the last type variable in the data type declaration we are+-- finding the representation for.+--+-- @argTyFold@ is more general than @arg@ because it uses 'ArgTyAlg' to+-- abstract out the concrete invocations of @Par0@, @Rec0@, @Par1@, @Rec1@, and+-- @:.:@.+--+-- @argTyFold@ is safer than @arg@ because @arg@ would lead to a GHC panic for+-- some data types. The problematic case is when @t@ is an application of a+-- non-representable type @f@ to @argVar@: @App f [argVar]@ is caught by the+-- @_@ pattern, and ends up represented as @Rec0 t@. This type occurs /free/ in+-- the RHS of the eventual @Rep1@ instance, which is therefore ill-formed. Some+-- representable1 checks have been relaxed, and others were moved to+-- @canDoGenerics1@.+argTyFold :: forall a. TyVar -> ArgTyAlg a -> Type -> a+argTyFold argVar (ArgTyAlg {ata_rec0 = mkRec0,+ ata_par1 = mkPar1, ata_rec1 = mkRec1,+ ata_comp = mkComp}) =+ -- mkRec0 is the default; use it if there is no interesting structure+ -- (e.g. occurrences of parameters or recursive occurrences)+ \t -> maybe (mkRec0 t) id $ go t where+ go :: Type -> -- type to fold through+ Maybe a -- the result (e.g. representation type), unless it's trivial+ go t = isParam `mplus` isApp where++ isParam = do -- handles parameters+ t' <- getTyVar_maybe t+ Just $ if t' == argVar then mkPar1 -- moreover, it is "the" parameter+ else mkRec0 t -- NB mkRec0 instead of the conventional mkPar0++ isApp = do -- handles applications+ (phi, beta) <- tcSplitAppTy_maybe t++ let interesting = argVar `elemVarSet` exactTyCoVarsOfType beta++ -- Does it have no interesting structure to represent?+ if not interesting then Nothing+ else -- Is the argument the parameter? Special case for mkRec1.+ if Just argVar == getTyVar_maybe beta then Just $ mkRec1 phi+ else mkComp phi `fmap` go beta -- It must be a composition.+++tc_mkRepTy :: -- Gen0_ or Gen1_, for Rep or Rep1+ GenericKind_+ -- The type to generate representation for+ -> TyCon+ -- The kind of the representation type's argument+ -- See Note [Handling kinds in a Rep instance]+ -> Kind+ -- Generated representation0 type+ -> TcM Type+tc_mkRepTy gk_ tycon k =+ do+ d1 <- tcLookupTyCon d1TyConName+ c1 <- tcLookupTyCon c1TyConName+ s1 <- tcLookupTyCon s1TyConName+ rec0 <- tcLookupTyCon rec0TyConName+ rec1 <- tcLookupTyCon rec1TyConName+ par1 <- tcLookupTyCon par1TyConName+ u1 <- tcLookupTyCon u1TyConName+ v1 <- tcLookupTyCon v1TyConName+ plus <- tcLookupTyCon sumTyConName+ times <- tcLookupTyCon prodTyConName+ comp <- tcLookupTyCon compTyConName+ uAddr <- tcLookupTyCon uAddrTyConName+ uChar <- tcLookupTyCon uCharTyConName+ uDouble <- tcLookupTyCon uDoubleTyConName+ uFloat <- tcLookupTyCon uFloatTyConName+ uInt <- tcLookupTyCon uIntTyConName+ uWord <- tcLookupTyCon uWordTyConName++ let tcLookupPromDataCon = fmap promoteDataCon . tcLookupDataCon++ md <- tcLookupPromDataCon metaDataDataConName+ mc <- tcLookupPromDataCon metaConsDataConName+ ms <- tcLookupPromDataCon metaSelDataConName+ pPrefix <- tcLookupPromDataCon prefixIDataConName+ pInfix <- tcLookupPromDataCon infixIDataConName+ pLA <- tcLookupPromDataCon leftAssociativeDataConName+ pRA <- tcLookupPromDataCon rightAssociativeDataConName+ pNA <- tcLookupPromDataCon notAssociativeDataConName+ pSUpk <- tcLookupPromDataCon sourceUnpackDataConName+ pSNUpk <- tcLookupPromDataCon sourceNoUnpackDataConName+ pNSUpkness <- tcLookupPromDataCon noSourceUnpackednessDataConName+ pSLzy <- tcLookupPromDataCon sourceLazyDataConName+ pSStr <- tcLookupPromDataCon sourceStrictDataConName+ pNSStrness <- tcLookupPromDataCon noSourceStrictnessDataConName+ pDLzy <- tcLookupPromDataCon decidedLazyDataConName+ pDStr <- tcLookupPromDataCon decidedStrictDataConName+ pDUpk <- tcLookupPromDataCon decidedUnpackDataConName++ fix_env <- getFixityEnv++ let mkSum' a b = mkTyConApp plus [k,a,b]+ mkProd a b = mkTyConApp times [k,a,b]+ mkRec0 a = mkBoxTy uAddr uChar uDouble uFloat uInt uWord rec0 k a+ mkRec1 a = mkTyConApp rec1 [k,a]+ mkPar1 = mkTyConTy par1+ mkD a = mkTyConApp d1 [ k, metaDataTy, sumP (tyConDataCons a) ]+ mkC a = mkTyConApp c1 [ k+ , metaConsTy a+ , prod (dataConInstOrigArgTys a+ . mkTyVarTys . tyConTyVars $ tycon)+ (dataConSrcBangs a)+ (dataConImplBangs a)+ (dataConFieldLabels a)]+ mkS mlbl su ss ib a = mkTyConApp s1 [k, metaSelTy mlbl su ss ib, a]++ -- Sums and products are done in the same way for both Rep and Rep1+ sumP [] = mkTyConApp v1 [k]+ sumP l = foldBal mkSum' . map mkC $ l+ -- The Bool is True if this constructor has labelled fields+ prod :: [Type] -> [HsSrcBang] -> [HsImplBang] -> [FieldLabel] -> Type+ prod [] _ _ _ = mkTyConApp u1 [k]+ prod l sb ib fl = foldBal mkProd+ [ ASSERT(null fl || length fl > j)+ arg t sb' ib' (if null fl+ then Nothing+ else Just (fl !! j))+ | (t,sb',ib',j) <- zip4 l sb ib [0..] ]++ arg :: Type -> HsSrcBang -> HsImplBang -> Maybe FieldLabel -> Type+ arg t (HsSrcBang _ su ss) ib fl = mkS fl su ss ib $ case gk_ of+ -- Here we previously used Par0 if t was a type variable, but we+ -- realized that we can't always guarantee that we are wrapping-up+ -- all type variables in Par0. So we decided to stop using Par0+ -- altogether, and use Rec0 all the time.+ Gen0_ -> mkRec0 t+ Gen1_ argVar -> argPar argVar t+ where+ -- Builds argument representation for Rep1 (more complicated due to+ -- the presence of composition).+ argPar argVar = argTyFold argVar $ ArgTyAlg+ {ata_rec0 = mkRec0, ata_par1 = mkPar1,+ ata_rec1 = mkRec1, ata_comp = mkComp comp k}++ tyConName_user = case tyConFamInst_maybe tycon of+ Just (ptycon, _) -> tyConName ptycon+ Nothing -> tyConName tycon++ dtName = mkStrLitTy . occNameFS . nameOccName $ tyConName_user+ mdName = mkStrLitTy . moduleNameFS . moduleName+ . nameModule . tyConName $ tycon+ pkgName = mkStrLitTy . unitIdFS . moduleUnitId+ . nameModule . tyConName $ tycon+ isNT = mkTyConTy $ if isNewTyCon tycon+ then promotedTrueDataCon+ else promotedFalseDataCon++ ctName = mkStrLitTy . occNameFS . nameOccName . dataConName+ ctFix c+ | dataConIsInfix c+ = case lookupFixity fix_env (dataConName c) of+ Fixity _ n InfixL -> buildFix n pLA+ Fixity _ n InfixR -> buildFix n pRA+ Fixity _ n InfixN -> buildFix n pNA+ | otherwise = mkTyConTy pPrefix+ buildFix n assoc = mkTyConApp pInfix [ mkTyConTy assoc+ , mkNumLitTy (fromIntegral n)]++ isRec c = mkTyConTy $ if length (dataConFieldLabels c) > 0+ then promotedTrueDataCon+ else promotedFalseDataCon++ selName = mkStrLitTy . flLabel++ mbSel Nothing = mkTyConApp promotedNothingDataCon [typeSymbolKind]+ mbSel (Just s) = mkTyConApp promotedJustDataCon+ [typeSymbolKind, selName s]++ metaDataTy = mkTyConApp md [dtName, mdName, pkgName, isNT]+ metaConsTy c = mkTyConApp mc [ctName c, ctFix c, isRec c]+ metaSelTy mlbl su ss ib =+ mkTyConApp ms [mbSel mlbl, pSUpkness, pSStrness, pDStrness]+ where+ pSUpkness = mkTyConTy $ case su of+ SrcUnpack -> pSUpk+ SrcNoUnpack -> pSNUpk+ NoSrcUnpack -> pNSUpkness++ pSStrness = mkTyConTy $ case ss of+ SrcLazy -> pSLzy+ SrcStrict -> pSStr+ NoSrcStrict -> pNSStrness++ pDStrness = mkTyConTy $ case ib of+ HsLazy -> pDLzy+ HsStrict -> pDStr+ HsUnpack{} -> pDUpk++ return (mkD tycon)++mkComp :: TyCon -> Kind -> Type -> Type -> Type+mkComp comp k f g+ | k1_first = mkTyConApp comp [k,liftedTypeKind,f,g]+ | otherwise = mkTyConApp comp [liftedTypeKind,k,f,g]+ where+ -- Which of these is the case?+ -- newtype (:.:) {k1} {k2} (f :: k2->*) (g :: k1->k2) (p :: k1) = ...+ -- or newtype (:.:) {k2} {k1} (f :: k2->*) (g :: k1->k2) (p :: k1) = ...+ -- We want to instantiate with k1=k, and k2=*+ -- Reason for k2=*: see Note [Handling kinds in a Rep instance]+ -- But we need to know which way round!+ k1_first = k_first == p_kind_var+ [k_first,_,_,_,p] = tyConTyVars comp+ Just p_kind_var = getTyVar_maybe (tyVarKind p)++-- Given the TyCons for each URec-related type synonym, check to see if the+-- given type is an unlifted type that generics understands. If so, return+-- its representation type. Otherwise, return Rec0.+-- See Note [Generics and unlifted types]+mkBoxTy :: TyCon -- UAddr+ -> TyCon -- UChar+ -> TyCon -- UDouble+ -> TyCon -- UFloat+ -> TyCon -- UInt+ -> TyCon -- UWord+ -> TyCon -- Rec0+ -> Kind -- What to instantiate Rec0's kind variable with+ -> Type+ -> Type+mkBoxTy uAddr uChar uDouble uFloat uInt uWord rec0 k ty+ | ty `eqType` addrPrimTy = mkTyConApp uAddr [k]+ | ty `eqType` charPrimTy = mkTyConApp uChar [k]+ | ty `eqType` doublePrimTy = mkTyConApp uDouble [k]+ | ty `eqType` floatPrimTy = mkTyConApp uFloat [k]+ | ty `eqType` intPrimTy = mkTyConApp uInt [k]+ | ty `eqType` wordPrimTy = mkTyConApp uWord [k]+ | otherwise = mkTyConApp rec0 [k,ty]++--------------------------------------------------------------------------------+-- Dealing with sums+--------------------------------------------------------------------------------++mkSum :: GenericKind_ -- Generic or Generic1?+ -> US -- Base for generating unique names+ -> TyCon -- The type constructor+ -> [DataCon] -- The data constructors+ -> ([Alt], -- Alternatives for the T->Trep "from" function+ [Alt]) -- Alternatives for the Trep->T "to" function++-- Datatype without any constructors+mkSum _ _ tycon [] = ([from_alt], [to_alt])+ where+ from_alt = (nlWildPat, makeError errMsgFrom)+ to_alt = (nlWildPat, makeError errMsgTo)+ -- These M1s are meta-information for the datatype+ makeError s = nlHsApp (nlHsVar error_RDR) (nlHsLit (mkHsString s))+ tyConStr = occNameString (nameOccName (tyConName tycon))+ errMsgFrom = "No generic representation for empty datatype " ++ tyConStr+ errMsgTo = "No values for empty datatype " ++ tyConStr++-- Datatype with at least one constructor+mkSum gk_ us _ datacons =+ -- switch the payload of gk_ to be datacon-centric instead of tycon-centric+ unzip [ mk1Sum (gk2gkDC gk_ d) us i (length datacons) d+ | (d,i) <- zip datacons [1..] ]++-- Build the sum for a particular constructor+mk1Sum :: GenericKind_DC -- Generic or Generic1?+ -> US -- Base for generating unique names+ -> Int -- The index of this constructor+ -> Int -- Total number of constructors+ -> DataCon -- The data constructor+ -> (Alt, -- Alternative for the T->Trep "from" function+ Alt) -- Alternative for the Trep->T "to" function+mk1Sum gk_ us i n datacon = (from_alt, to_alt)+ where+ gk = forgetArgVar gk_++ -- Existentials already excluded+ argTys = dataConOrigArgTys datacon+ n_args = dataConSourceArity datacon++ datacon_varTys = zip (map mkGenericLocal [us .. us+n_args-1]) argTys+ datacon_vars = map fst datacon_varTys+ us' = us + n_args++ datacon_rdr = getRdrName datacon++ from_alt = (nlConVarPat datacon_rdr datacon_vars, from_alt_rhs)+ from_alt_rhs = genLR_E i n (mkProd_E gk_ us' datacon_varTys)++ to_alt = ( genLR_P i n (mkProd_P gk us' datacon_varTys)+ , to_alt_rhs+ ) -- These M1s are meta-information for the datatype+ to_alt_rhs = case gk_ of+ Gen0_DC -> nlHsVarApps datacon_rdr datacon_vars+ Gen1_DC argVar -> nlHsApps datacon_rdr $ map argTo datacon_varTys+ where+ argTo (var, ty) = converter ty `nlHsApp` nlHsVar var where+ converter = argTyFold argVar $ ArgTyAlg+ {ata_rec0 = nlHsVar . unboxRepRDR,+ ata_par1 = nlHsVar unPar1_RDR,+ ata_rec1 = const $ nlHsVar unRec1_RDR,+ ata_comp = \_ cnv -> (nlHsVar fmap_RDR `nlHsApp` cnv)+ `nlHsCompose` nlHsVar unComp1_RDR}+++-- Generates the L1/R1 sum pattern+genLR_P :: Int -> Int -> LPat RdrName -> LPat RdrName+genLR_P i n p+ | n == 0 = error "impossible"+ | n == 1 = p+ | i <= div n 2 = nlParPat $ nlConPat l1DataCon_RDR [genLR_P i (div n 2) p]+ | otherwise = nlParPat $ nlConPat r1DataCon_RDR [genLR_P (i-m) (n-m) p]+ where m = div n 2++-- Generates the L1/R1 sum expression+genLR_E :: Int -> Int -> LHsExpr RdrName -> LHsExpr RdrName+genLR_E i n e+ | n == 0 = error "impossible"+ | n == 1 = e+ | i <= div n 2 = nlHsVar l1DataCon_RDR `nlHsApp`+ nlHsPar (genLR_E i (div n 2) e)+ | otherwise = nlHsVar r1DataCon_RDR `nlHsApp`+ nlHsPar (genLR_E (i-m) (n-m) e)+ where m = div n 2++--------------------------------------------------------------------------------+-- Dealing with products+--------------------------------------------------------------------------------++-- Build a product expression+mkProd_E :: GenericKind_DC -- Generic or Generic1?+ -> US -- Base for unique names+ -> [(RdrName, Type)] -- List of variables matched on the lhs and their types+ -> LHsExpr RdrName -- Resulting product expression+mkProd_E _ _ [] = mkM1_E (nlHsVar u1DataCon_RDR)+mkProd_E gk_ _ varTys = mkM1_E (foldBal prod appVars)+ -- These M1s are meta-information for the constructor+ where+ appVars = map (wrapArg_E gk_) varTys+ prod a b = prodDataCon_RDR `nlHsApps` [a,b]++wrapArg_E :: GenericKind_DC -> (RdrName, Type) -> LHsExpr RdrName+wrapArg_E Gen0_DC (var, ty) = mkM1_E $+ boxRepRDR ty `nlHsVarApps` [var]+ -- This M1 is meta-information for the selector+wrapArg_E (Gen1_DC argVar) (var, ty) = mkM1_E $+ converter ty `nlHsApp` nlHsVar var+ -- This M1 is meta-information for the selector+ where converter = argTyFold argVar $ ArgTyAlg+ {ata_rec0 = nlHsVar . boxRepRDR,+ ata_par1 = nlHsVar par1DataCon_RDR,+ ata_rec1 = const $ nlHsVar rec1DataCon_RDR,+ ata_comp = \_ cnv -> nlHsVar comp1DataCon_RDR `nlHsCompose`+ (nlHsVar fmap_RDR `nlHsApp` cnv)}++boxRepRDR :: Type -> RdrName+boxRepRDR = maybe k1DataCon_RDR fst . unboxedRepRDRs++unboxRepRDR :: Type -> RdrName+unboxRepRDR = maybe unK1_RDR snd . unboxedRepRDRs++-- Retrieve the RDRs associated with each URec data family instance+-- constructor. See Note [Generics and unlifted types]+unboxedRepRDRs :: Type -> Maybe (RdrName, RdrName)+unboxedRepRDRs ty+ | ty `eqType` addrPrimTy = Just (uAddrDataCon_RDR, uAddrHash_RDR)+ | ty `eqType` charPrimTy = Just (uCharDataCon_RDR, uCharHash_RDR)+ | ty `eqType` doublePrimTy = Just (uDoubleDataCon_RDR, uDoubleHash_RDR)+ | ty `eqType` floatPrimTy = Just (uFloatDataCon_RDR, uFloatHash_RDR)+ | ty `eqType` intPrimTy = Just (uIntDataCon_RDR, uIntHash_RDR)+ | ty `eqType` wordPrimTy = Just (uWordDataCon_RDR, uWordHash_RDR)+ | otherwise = Nothing++-- Build a product pattern+mkProd_P :: GenericKind -- Gen0 or Gen1+ -> US -- Base for unique names+ -> [(RdrName, Type)] -- List of variables to match,+ -- along with their types+ -> LPat RdrName -- Resulting product pattern+mkProd_P _ _ [] = mkM1_P (nlNullaryConPat u1DataCon_RDR)+mkProd_P gk _ varTys = mkM1_P (foldBal prod appVars)+ -- These M1s are meta-information for the constructor+ where+ appVars = unzipWith (wrapArg_P gk) varTys+ prod a b = nlParPat $ prodDataCon_RDR `nlConPat` [a,b]++wrapArg_P :: GenericKind -> RdrName -> Type -> LPat RdrName+wrapArg_P Gen0 v ty = mkM1_P (nlParPat $ boxRepRDR ty `nlConVarPat` [v])+ -- This M1 is meta-information for the selector+wrapArg_P Gen1 v _ = nlParPat $ m1DataCon_RDR `nlConVarPat` [v]++mkGenericLocal :: US -> RdrName+mkGenericLocal u = mkVarUnqual (mkFastString ("g" ++ show u))++x_RDR :: RdrName+x_RDR = mkVarUnqual (fsLit "x")++x_Expr :: LHsExpr RdrName+x_Expr = nlHsVar x_RDR++x_Pat :: LPat RdrName+x_Pat = nlVarPat x_RDR++mkM1_E :: LHsExpr RdrName -> LHsExpr RdrName+mkM1_E e = nlHsVar m1DataCon_RDR `nlHsApp` e++mkM1_P :: LPat RdrName -> LPat RdrName+mkM1_P p = nlParPat $ m1DataCon_RDR `nlConPat` [p]++nlHsCompose :: LHsExpr RdrName -> LHsExpr RdrName -> LHsExpr RdrName+nlHsCompose x y = compose_RDR `nlHsApps` [x, y]++-- | Variant of foldr1 for producing balanced lists+foldBal :: (a -> a -> a) -> [a] -> a+foldBal op = foldBal' op (error "foldBal: empty list")++foldBal' :: (a -> a -> a) -> a -> [a] -> a+foldBal' _ x [] = x+foldBal' _ _ [y] = y+foldBal' op x l = let (a,b) = splitAt (length l `div` 2) l+ in foldBal' op x a `op` foldBal' op x b++{-+Note [Generics and unlifted types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Normally, all constants are marked with K1/Rec0. The exception to this rule is+when a data constructor has an unlifted argument (e.g., Int#, Char#, etc.). In+that case, we must use a data family instance of URec (from GHC.Generics) to+mark it. As a result, before we can generate K1 or unK1, we must first check+to see if the type is actually one of the unlifted types for which URec has a+data family instance; if so, we generate that instead.++See wiki:Commentary/Compiler/GenericDeriving#Handlingunliftedtypes for more+details on why URec is implemented the way it is.++Note [Generating a correctly typed Rep instance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+tc_mkRepTy derives the RHS of the Rep(1) type family instance when deriving+Generic(1). That is, it derives the ellipsis in the following:++ instance Generic Foo where+ type Rep Foo = ...++However, tc_mkRepTy only has knowledge of the *TyCon* of the type for which+a Generic(1) instance is being derived, not the fully instantiated type. As a+result, tc_mkRepTy builds the most generalized Rep(1) instance possible using+the type variables it learns from the TyCon (i.e., it uses tyConTyVars). This+can cause problems when the instance has instantiated type variables+(see Trac #11732). As an example:++ data T a = MkT a+ deriving instance Generic (T Int)+ ==>+ instance Generic (T Int) where+ type Rep (T Int) = (... (Rec0 a)) -- wrong!++-XStandaloneDeriving is one way for the type variables to become instantiated.+Another way is when Generic1 is being derived for a datatype with a visible+kind binder, e.g.,++ data P k (a :: k) = MkP k deriving Generic1+ ==>+ instance Generic1 (P *) where+ type Rep1 (P *) = (... (Rec0 k)) -- wrong!++See Note [Unify kinds in deriving] in TcDeriv.++In any such scenario, we must prevent a discrepancy between the LHS and RHS of+a Rep(1) instance. To do so, we create a type variable substitution that maps+the tyConTyVars of the TyCon to their counterparts in the fully instantiated+type. (For example, using T above as example, you'd map a :-> Int.) We then+apply the substitution to the RHS before generating the instance.++Note [Handling kinds in a Rep instance]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because Generic1 is poly-kinded, the representation types were generalized to+be kind-polymorphic as well. As a result, tc_mkRepTy must explicitly apply+the kind of the instance being derived to all the representation type+constructors. For instance, if you have++ data Empty (a :: k) = Empty deriving Generic1++Then the generated code is now approximately (with -fprint-explicit-kinds+syntax):++ instance Generic1 k (Empty k) where+ type Rep1 k (Empty k) = U1 k++Most representation types have only one kind variable, making them easy to deal+with. The only non-trivial case is (:.:), which is only used in Generic1+instances:++ newtype (:.:) (f :: k2 -> *) (g :: k1 -> k2) (p :: k1) =+ Comp1 { unComp1 :: f (g p) }++Here, we do something a bit counter-intuitive: we make k1 be the kind of the+instance being derived, and we always make k2 be *. Why *? It's because+the code that GHC generates using (:.:) is always of the form x :.: Rec1 y+for some types x and y. In other words, the second type to which (:.:) is+applied always has kind k -> *, for some kind k, so k2 cannot possibly be+anything other than * in a generated Generic1 instance.++Note [Generics compilation speed tricks]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Deriving Generic(1) is known to have a large constant factor during+compilation, which contributes to noticeable compilation slowdowns when+deriving Generic(1) for large datatypes (see Trac #5642).++To ease the pain, there is a trick one can play when generating definitions for+to(1) and from(1). If you have a datatype like:++ data Letter = A | B | C | D++then a naïve Generic instance for Letter would be:++ instance Generic Letter where+ type Rep Letter = D1 ('MetaData ...) ...++ to (M1 (L1 (L1 (M1 U1)))) = A+ to (M1 (L1 (R1 (M1 U1)))) = B+ to (M1 (R1 (L1 (M1 U1)))) = C+ to (M1 (R1 (R1 (M1 U1)))) = D++ from A = M1 (L1 (L1 (M1 U1)))+ from B = M1 (L1 (R1 (M1 U1)))+ from C = M1 (R1 (L1 (M1 U1)))+ from D = M1 (R1 (R1 (M1 U1)))++Notice that in every LHS pattern-match of the 'to' definition, and in every RHS+expression in the 'from' definition, the topmost constructor is M1. This+corresponds to the datatype-specific metadata (the D1 in the Rep Letter+instance). But this is wasteful from a typechecking perspective, since this+definition requires GHC to typecheck an application of M1 in every single case,+leading to an O(n) increase in the number of coercions the typechecker has to+solve, which in turn increases allocations and degrades compilation speed.++Luckily, since the topmost M1 has the exact same type across every case, we can+factor it out reduce the typechecker's burden:++ instance Generic Letter where+ type Rep Letter = D1 ('MetaData ...) ...++ to (M1 x) = case x of+ L1 (L1 (M1 U1)) -> A+ L1 (R1 (M1 U1)) -> B+ R1 (L1 (M1 U1)) -> C+ R1 (R1 (M1 U1)) -> D++ from x = M1 (case x of+ A -> L1 (L1 (M1 U1))+ B -> L1 (R1 (M1 U1))+ C -> R1 (L1 (M1 U1))+ D -> R1 (R1 (M1 U1)))++A simple change, but one that pays off, since it goes turns an O(n) amount of+coercions to an O(1) amount.+-}
+ typecheck/TcHsSyn.hs view
@@ -0,0 +1,1700 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1996-1998+++TcHsSyn: Specialisations of the @HsSyn@ syntax for the typechecker++This module is an extension of @HsSyn@ syntax, for use in the type+checker.+-}++{-# LANGUAGE CPP, TupleSections #-}++module TcHsSyn (+ -- * Extracting types from HsSyn+ hsLitType, hsLPatType, hsPatType,++ -- * Other HsSyn functions+ mkHsDictLet, mkHsApp,+ mkHsAppTy, mkHsCaseAlt,+ nlHsIntLit,+ shortCutLit, hsOverLitName,+ conLikeResTy,++ -- * re-exported from TcMonad+ TcId, TcIdSet,++ -- * Zonking+ -- | For a description of "zonking", see Note [What is zonking?]+ -- in TcMType+ zonkTopDecls, zonkTopExpr, zonkTopLExpr,+ zonkTopBndrs, zonkTyBndrsX,+ zonkTyVarBindersX, zonkTyVarBinderX,+ emptyZonkEnv, mkEmptyZonkEnv,+ zonkTcTypeToType, zonkTcTypeToTypes, zonkTyVarOcc,+ zonkCoToCo, zonkSigType,+ zonkEvBinds,+ ) where++#include "HsVersions.h"++import HsSyn+import Id+import IdInfo+import TcRnMonad+import PrelNames+import TcType+import TcMType+import TcEvidence+import TysPrim+import TyCon ( isUnboxedTupleTyCon )+import TysWiredIn+import Type+import Coercion+import ConLike+import DataCon+import HscTypes+import Name+import NameEnv+import Var+import VarEnv+import DynFlags+import Literal+import BasicTypes+import Maybes+import SrcLoc+import Bag+import Outputable+import Util+import UniqFM++import Control.Monad+import Data.List ( partition )+import Control.Arrow ( second )++{-+************************************************************************+* *+ Extracting the type from HsSyn+* *+************************************************************************++-}++hsLPatType :: OutPat Id -> Type+hsLPatType (L _ pat) = hsPatType pat++hsPatType :: Pat Id -> Type+hsPatType (ParPat pat) = hsLPatType pat+hsPatType (WildPat ty) = ty+hsPatType (VarPat (L _ var)) = idType var+hsPatType (BangPat pat) = hsLPatType pat+hsPatType (LazyPat pat) = hsLPatType pat+hsPatType (LitPat lit) = hsLitType lit+hsPatType (AsPat var _) = idType (unLoc var)+hsPatType (ViewPat _ _ ty) = ty+hsPatType (ListPat _ ty Nothing) = mkListTy ty+hsPatType (ListPat _ _ (Just (ty,_))) = ty+hsPatType (PArrPat _ ty) = mkPArrTy ty+hsPatType (TuplePat _ bx tys) = mkTupleTy bx tys+hsPatType (SumPat _ _ _ tys) = mkSumTy tys+hsPatType (ConPatOut { pat_con = L _ con, pat_arg_tys = tys })+ = conLikeResTy con tys+hsPatType (SigPatOut _ ty) = ty+hsPatType (NPat _ _ _ ty) = ty+hsPatType (NPlusKPat _ _ _ _ _ ty) = ty+hsPatType (CoPat _ _ ty) = ty+hsPatType p = pprPanic "hsPatType" (ppr p)++hsLitType :: HsLit -> TcType+hsLitType (HsChar _ _) = charTy+hsLitType (HsCharPrim _ _) = charPrimTy+hsLitType (HsString _ _) = stringTy+hsLitType (HsStringPrim _ _) = addrPrimTy+hsLitType (HsInt _ _) = intTy+hsLitType (HsIntPrim _ _) = intPrimTy+hsLitType (HsWordPrim _ _) = wordPrimTy+hsLitType (HsInt64Prim _ _) = int64PrimTy+hsLitType (HsWord64Prim _ _) = word64PrimTy+hsLitType (HsInteger _ _ ty) = ty+hsLitType (HsRat _ ty) = ty+hsLitType (HsFloatPrim _) = floatPrimTy+hsLitType (HsDoublePrim _) = doublePrimTy++-- Overloaded literals. Here mainly because it uses isIntTy etc++shortCutLit :: DynFlags -> OverLitVal -> TcType -> Maybe (HsExpr TcId)+shortCutLit dflags (HsIntegral src i) ty+ | isIntTy ty && inIntRange dflags i = Just (HsLit (HsInt src i))+ | isWordTy ty && inWordRange dflags i+ = Just (mkLit wordDataCon (HsWordPrim src i))+ | isIntegerTy ty = Just (HsLit (HsInteger src i ty))+ | otherwise = shortCutLit dflags (HsFractional (integralFractionalLit i)) ty+ -- The 'otherwise' case is important+ -- Consider (3 :: Float). Syntactically it looks like an IntLit,+ -- so we'll call shortCutIntLit, but of course it's a float+ -- This can make a big difference for programs with a lot of+ -- literals, compiled without -O++shortCutLit _ (HsFractional f) ty+ | isFloatTy ty = Just (mkLit floatDataCon (HsFloatPrim f))+ | isDoubleTy ty = Just (mkLit doubleDataCon (HsDoublePrim f))+ | otherwise = Nothing++shortCutLit _ (HsIsString src s) ty+ | isStringTy ty = Just (HsLit (HsString src s))+ | otherwise = Nothing++mkLit :: DataCon -> HsLit -> HsExpr Id+mkLit con lit = HsApp (nlHsDataCon con) (nlHsLit lit)++------------------------------+hsOverLitName :: OverLitVal -> Name+-- Get the canonical 'fromX' name for a particular OverLitVal+hsOverLitName (HsIntegral {}) = fromIntegerName+hsOverLitName (HsFractional {}) = fromRationalName+hsOverLitName (HsIsString {}) = fromStringName++{-+************************************************************************+* *+\subsection[BackSubst-HsBinds]{Running a substitution over @HsBinds@}+* *+************************************************************************++The rest of the zonking is done *after* typechecking.+The main zonking pass runs over the bindings++ a) to convert TcTyVars to TyVars etc, dereferencing any bindings etc+ b) convert unbound TcTyVar to Void+ c) convert each TcId to an Id by zonking its type++The type variables are converted by binding mutable tyvars to immutable ones+and then zonking as normal.++The Ids are converted by binding them in the normal Tc envt; that+way we maintain sharing; eg an Id is zonked at its binding site and they+all occurrences of that Id point to the common zonked copy++It's all pretty boring stuff, because HsSyn is such a large type, and+the environment manipulation is tiresome.+-}++-- Confused by zonking? See Note [What is zonking?] in TcMType.+type UnboundTyVarZonker = TcTyVar -> TcM Type+ -- How to zonk an unbound type variable+ -- The TcTyVar is+ -- (a) a MetaTv+ -- (b) Flexi and+ -- (c) its kind is already zonked+ -- Note [Zonking the LHS of a RULE]++-- | A ZonkEnv carries around several bits.+-- The UnboundTyVarZonker just zaps unbouned meta-tyvars to Any (as+-- defined in zonkTypeZapping), except on the LHS of rules. See+-- Note [Zonking the LHS of a RULE].+--+-- The (TyCoVarEnv TyVar) and is just an optimisation: when binding a+-- tyvar or covar, we zonk the kind right away and add a mapping to+-- the env. This prevents re-zonking the kind at every occurrence. But+-- this is *just* an optimisation.+--+-- The final (IdEnv Var) optimises zonking for Ids. It is+-- knot-tied. We must be careful never to put coercion variables+-- (which are Ids, after all) in the knot-tied env, because coercions+-- can appear in types, and we sometimes inspect a zonked type in this+-- module.+--+-- Confused by zonking? See Note [What is zonking?] in TcMType.+data ZonkEnv+ = ZonkEnv+ UnboundTyVarZonker+ (TyCoVarEnv TyVar)+ (IdEnv Var) -- What variables are in scope+ -- Maps an Id or EvVar to its zonked version; both have the same Name+ -- Note that all evidence (coercion variables as well as dictionaries)+ -- are kept in the ZonkEnv+ -- Only *type* abstraction is done by side effect+ -- Is only consulted lazily; hence knot-tying++instance Outputable ZonkEnv where+ ppr (ZonkEnv _ _ty_env var_env) = pprUFM var_env (vcat . map ppr)+++-- The EvBinds have to already be zonked, but that's usually the case.+emptyZonkEnv :: ZonkEnv+emptyZonkEnv = mkEmptyZonkEnv zonkTypeZapping++mkEmptyZonkEnv :: UnboundTyVarZonker -> ZonkEnv+mkEmptyZonkEnv zonker = ZonkEnv zonker emptyVarEnv emptyVarEnv++-- | Extend the knot-tied environment.+extendIdZonkEnvRec :: ZonkEnv -> [Var] -> ZonkEnv+extendIdZonkEnvRec (ZonkEnv zonk_ty ty_env id_env) ids+ -- NB: Don't look at the var to decide which env't to put it in. That+ -- would end up knot-tying all the env'ts.+ = ZonkEnv zonk_ty ty_env (extendVarEnvList id_env [(id,id) | id <- ids])+ -- Given coercion variables will actually end up here. That's OK though:+ -- coercion variables are never looked up in the knot-tied env't, so zonking+ -- them simply doesn't get optimised. No one gets hurt. An improvement (?)+ -- would be to do SCC analysis in zonkEvBinds and then only knot-tie the+ -- recursive groups. But perhaps the time it takes to do the analysis is+ -- more than the savings.++extendZonkEnv :: ZonkEnv -> [Var] -> ZonkEnv+extendZonkEnv (ZonkEnv zonk_ty tyco_env id_env) vars+ = ZonkEnv zonk_ty (extendVarEnvList tyco_env [(tv,tv) | tv <- tycovars])+ (extendVarEnvList id_env [(id,id) | id <- ids])+ where (tycovars, ids) = partition isTyCoVar vars++extendIdZonkEnv1 :: ZonkEnv -> Var -> ZonkEnv+extendIdZonkEnv1 (ZonkEnv zonk_ty ty_env id_env) id+ = ZonkEnv zonk_ty ty_env (extendVarEnv id_env id id)++extendTyZonkEnv1 :: ZonkEnv -> TyVar -> ZonkEnv+extendTyZonkEnv1 (ZonkEnv zonk_ty ty_env id_env) tv+ = ZonkEnv zonk_ty (extendVarEnv ty_env tv tv) id_env++setZonkType :: ZonkEnv -> UnboundTyVarZonker -> ZonkEnv+setZonkType (ZonkEnv _ ty_env id_env) zonk_ty+ = ZonkEnv zonk_ty ty_env id_env++zonkEnvIds :: ZonkEnv -> TypeEnv+zonkEnvIds (ZonkEnv _ _ id_env) =+ mkNameEnv [(getName id, AnId id) | id <- nonDetEltsUFM id_env]+ -- It's OK to use nonDetEltsUFM here because we forget the ordering+ -- immediately by creating a TypeEnv++zonkIdOcc :: ZonkEnv -> TcId -> Id+-- Ids defined in this module should be in the envt;+-- ignore others. (Actually, data constructors are also+-- not LocalVars, even when locally defined, but that is fine.)+-- (Also foreign-imported things aren't currently in the ZonkEnv;+-- that's ok because they don't need zonking.)+--+-- Actually, Template Haskell works in 'chunks' of declarations, and+-- an earlier chunk won't be in the 'env' that the zonking phase+-- carries around. Instead it'll be in the tcg_gbl_env, already fully+-- zonked. There's no point in looking it up there (except for error+-- checking), and it's not conveniently to hand; hence the simple+-- 'orElse' case in the LocalVar branch.+--+-- Even without template splices, in module Main, the checking of+-- 'main' is done as a separate chunk.+zonkIdOcc (ZonkEnv _zonk_ty _ty_env id_env) id+ | isLocalVar id = lookupVarEnv id_env id `orElse`+ id+ | otherwise = id++zonkIdOccs :: ZonkEnv -> [TcId] -> [Id]+zonkIdOccs env ids = map (zonkIdOcc env) ids++-- zonkIdBndr is used *after* typechecking to get the Id's type+-- to its final form. The TyVarEnv give+zonkIdBndr :: ZonkEnv -> TcId -> TcM Id+zonkIdBndr env v+ = do ty' <- zonkTcTypeToType env (idType v)+ ensureNotLevPoly ty'+ (text "In the type of binder" <+> quotes (ppr v))++ return (modifyIdInfo (`setLevityInfoWithType` ty') (setIdType v ty'))++zonkIdBndrs :: ZonkEnv -> [TcId] -> TcM [Id]+zonkIdBndrs env ids = mapM (zonkIdBndr env) ids++zonkTopBndrs :: [TcId] -> TcM [Id]+zonkTopBndrs ids = zonkIdBndrs emptyZonkEnv ids++zonkFieldOcc :: ZonkEnv -> FieldOcc TcId -> TcM (FieldOcc Id)+zonkFieldOcc env (FieldOcc lbl sel) = fmap (FieldOcc lbl) $ zonkIdBndr env sel++zonkEvBndrsX :: ZonkEnv -> [EvVar] -> TcM (ZonkEnv, [Var])+zonkEvBndrsX = mapAccumLM zonkEvBndrX++zonkEvBndrX :: ZonkEnv -> EvVar -> TcM (ZonkEnv, EvVar)+-- Works for dictionaries and coercions+zonkEvBndrX env var+ = do { var' <- zonkEvBndr env var+ ; return (extendZonkEnv env [var'], var') }++zonkEvBndr :: ZonkEnv -> EvVar -> TcM EvVar+-- Works for dictionaries and coercions+-- Does not extend the ZonkEnv+zonkEvBndr env var+ = do { let var_ty = varType var+ ; ty <-+ {-# SCC "zonkEvBndr_zonkTcTypeToType" #-}+ zonkTcTypeToType env var_ty+ ; return (setVarType var ty) }++zonkEvVarOcc :: ZonkEnv -> EvVar -> TcM EvTerm+zonkEvVarOcc env v+ | isCoVar v+ = EvCoercion <$> zonkCoVarOcc env v+ | otherwise+ = return (EvId $ zonkIdOcc env v)++zonkTyBndrsX :: ZonkEnv -> [TcTyVar] -> TcM (ZonkEnv, [TyVar])+zonkTyBndrsX = mapAccumLM zonkTyBndrX++zonkTyBndrX :: ZonkEnv -> TcTyVar -> TcM (ZonkEnv, TyVar)+-- This guarantees to return a TyVar (not a TcTyVar)+-- then we add it to the envt, so all occurrences are replaced+zonkTyBndrX env tv+ = ASSERT( isImmutableTyVar tv )+ do { ki <- zonkTcTypeToType env (tyVarKind tv)+ -- Internal names tidy up better, for iface files.+ ; let tv' = mkTyVar (tyVarName tv) ki+ ; return (extendTyZonkEnv1 env tv', tv') }++zonkTyVarBindersX :: ZonkEnv -> [TyVarBndr TcTyVar vis]+ -> TcM (ZonkEnv, [TyVarBndr TyVar vis])+zonkTyVarBindersX = mapAccumLM zonkTyVarBinderX++zonkTyVarBinderX :: ZonkEnv -> TyVarBndr TcTyVar vis+ -> TcM (ZonkEnv, TyVarBndr TyVar vis)+-- Takes a TcTyVar and guarantees to return a TyVar+zonkTyVarBinderX env (TvBndr tv vis)+ = do { (env', tv') <- zonkTyBndrX env tv+ ; return (env', TvBndr tv' vis) }++zonkTopExpr :: HsExpr TcId -> TcM (HsExpr Id)+zonkTopExpr e = zonkExpr emptyZonkEnv e++zonkTopLExpr :: LHsExpr TcId -> TcM (LHsExpr Id)+zonkTopLExpr e = zonkLExpr emptyZonkEnv e++zonkTopDecls :: Bag EvBind+ -> LHsBinds TcId+ -> [LRuleDecl TcId] -> [LVectDecl TcId] -> [LTcSpecPrag] -> [LForeignDecl TcId]+ -> TcM (TypeEnv,+ Bag EvBind,+ LHsBinds Id,+ [LForeignDecl Id],+ [LTcSpecPrag],+ [LRuleDecl Id],+ [LVectDecl Id])+zonkTopDecls ev_binds binds rules vects imp_specs fords+ = do { (env1, ev_binds') <- zonkEvBinds emptyZonkEnv ev_binds+ ; (env2, binds') <- zonkRecMonoBinds env1 binds+ -- Top level is implicitly recursive+ ; rules' <- zonkRules env2 rules+ ; vects' <- zonkVects env2 vects+ ; specs' <- zonkLTcSpecPrags env2 imp_specs+ ; fords' <- zonkForeignExports env2 fords+ ; return (zonkEnvIds env2, ev_binds', binds', fords', specs', rules', vects') }++---------------------------------------------+zonkLocalBinds :: ZonkEnv -> HsLocalBinds TcId -> TcM (ZonkEnv, HsLocalBinds Id)+zonkLocalBinds env EmptyLocalBinds+ = return (env, EmptyLocalBinds)++zonkLocalBinds _ (HsValBinds (ValBindsIn {}))+ = panic "zonkLocalBinds" -- Not in typechecker output++zonkLocalBinds env (HsValBinds (ValBindsOut binds sigs))+ = do { (env1, new_binds) <- go env binds+ ; return (env1, HsValBinds (ValBindsOut new_binds sigs)) }+ where+ go env []+ = return (env, [])+ go env ((r,b):bs)+ = do { (env1, b') <- zonkRecMonoBinds env b+ ; (env2, bs') <- go env1 bs+ ; return (env2, (r,b'):bs') }++zonkLocalBinds env (HsIPBinds (IPBinds binds dict_binds)) = do+ new_binds <- mapM (wrapLocM zonk_ip_bind) binds+ let+ env1 = extendIdZonkEnvRec env [ n | L _ (IPBind (Right n) _) <- new_binds]+ (env2, new_dict_binds) <- zonkTcEvBinds env1 dict_binds+ return (env2, HsIPBinds (IPBinds new_binds new_dict_binds))+ where+ zonk_ip_bind (IPBind n e)+ = do n' <- mapIPNameTc (zonkIdBndr env) n+ e' <- zonkLExpr env e+ return (IPBind n' e')++---------------------------------------------+zonkRecMonoBinds :: ZonkEnv -> LHsBinds TcId -> TcM (ZonkEnv, LHsBinds Id)+zonkRecMonoBinds env binds+ = fixM (\ ~(_, new_binds) -> do+ { let env1 = extendIdZonkEnvRec env (collectHsBindsBinders new_binds)+ ; binds' <- zonkMonoBinds env1 binds+ ; return (env1, binds') })++---------------------------------------------+zonkMonoBinds :: ZonkEnv -> LHsBinds TcId -> TcM (LHsBinds Id)+zonkMonoBinds env binds = mapBagM (zonk_lbind env) binds++zonk_lbind :: ZonkEnv -> LHsBind TcId -> TcM (LHsBind Id)+zonk_lbind env = wrapLocM (zonk_bind env)++zonk_bind :: ZonkEnv -> HsBind TcId -> TcM (HsBind Id)+zonk_bind env bind@(PatBind { pat_lhs = pat, pat_rhs = grhss, pat_rhs_ty = ty})+ = do { (_env, new_pat) <- zonkPat env pat -- Env already extended+ ; new_grhss <- zonkGRHSs env zonkLExpr grhss+ ; new_ty <- zonkTcTypeToType env ty+ ; return (bind { pat_lhs = new_pat, pat_rhs = new_grhss, pat_rhs_ty = new_ty }) }++zonk_bind env (VarBind { var_id = var, var_rhs = expr, var_inline = inl })+ = do { new_var <- zonkIdBndr env var+ ; new_expr <- zonkLExpr env expr+ ; return (VarBind { var_id = new_var, var_rhs = new_expr, var_inline = inl }) }++zonk_bind env bind@(FunBind { fun_id = L loc var, fun_matches = ms+ , fun_co_fn = co_fn })+ = do { new_var <- zonkIdBndr env var+ ; (env1, new_co_fn) <- zonkCoFn env co_fn+ ; new_ms <- zonkMatchGroup env1 zonkLExpr ms+ ; return (bind { fun_id = L loc new_var, fun_matches = new_ms+ , fun_co_fn = new_co_fn }) }++zonk_bind env (AbsBinds { abs_tvs = tyvars, abs_ev_vars = evs+ , abs_ev_binds = ev_binds+ , abs_exports = exports+ , abs_binds = val_binds })+ = ASSERT( all isImmutableTyVar tyvars )+ do { (env0, new_tyvars) <- zonkTyBndrsX env tyvars+ ; (env1, new_evs) <- zonkEvBndrsX env0 evs+ ; (env2, new_ev_binds) <- zonkTcEvBinds_s env1 ev_binds+ ; (new_val_bind, new_exports) <- fixM $ \ ~(new_val_binds, _) ->+ do { let env3 = extendIdZonkEnvRec env2+ (collectHsBindsBinders new_val_binds)+ ; new_val_binds <- zonkMonoBinds env3 val_binds+ ; new_exports <- mapM (zonkExport env3) exports+ ; return (new_val_binds, new_exports) }+ ; return (AbsBinds { abs_tvs = new_tyvars, abs_ev_vars = new_evs+ , abs_ev_binds = new_ev_binds+ , abs_exports = new_exports, abs_binds = new_val_bind }) }+ where+ zonkExport env (ABE{ abe_wrap = wrap+ , abe_poly = poly_id+ , abe_mono = mono_id, abe_prags = prags })+ = do new_poly_id <- zonkIdBndr env poly_id+ (_, new_wrap) <- zonkCoFn env wrap+ new_prags <- zonkSpecPrags env prags+ return (ABE{ abe_wrap = new_wrap+ , abe_poly = new_poly_id+ , abe_mono = zonkIdOcc env mono_id+ , abe_prags = new_prags })++zonk_bind env outer_bind@(AbsBindsSig { abs_tvs = tyvars+ , abs_ev_vars = evs+ , abs_sig_export = poly+ , abs_sig_prags = prags+ , abs_sig_ev_bind = ev_bind+ , abs_sig_bind = lbind })+ | L bind_loc bind@(FunBind { fun_id = L loc local+ , fun_matches = ms+ , fun_co_fn = co_fn }) <- lbind+ = ASSERT( all isImmutableTyVar tyvars )+ do { (env0, new_tyvars) <- zonkTyBndrsX env tyvars+ ; (env1, new_evs) <- zonkEvBndrsX env0 evs+ ; (env2, new_ev_bind) <- zonkTcEvBinds env1 ev_bind+ -- Inline zonk_bind (FunBind ...) because we wish to skip+ -- the check for representation-polymorphic binders. The+ -- local binder in the FunBind in an AbsBindsSig is never actually+ -- bound in Core -- indeed, that's the whole point of AbsBindsSig.+ -- just calling zonk_bind causes #11405.+ ; new_local <- updateVarTypeM (zonkTcTypeToType env2) local+ ; (env3, new_co_fn) <- zonkCoFn env2 co_fn+ ; new_ms <- zonkMatchGroup env3 zonkLExpr ms+ -- If there is a representation polymorphism problem, it will+ -- be caught here:+ ; new_poly_id <- zonkIdBndr env2 poly+ ; new_prags <- zonkSpecPrags env2 prags+ ; let new_val_bind = L bind_loc (bind { fun_id = L loc new_local+ , fun_matches = new_ms+ , fun_co_fn = new_co_fn })+ ; return (AbsBindsSig { abs_tvs = new_tyvars+ , abs_ev_vars = new_evs+ , abs_sig_export = new_poly_id+ , abs_sig_prags = new_prags+ , abs_sig_ev_bind = new_ev_bind+ , abs_sig_bind = new_val_bind }) }++ | otherwise+ = pprPanic "zonk_bind" (ppr outer_bind)++zonk_bind env (PatSynBind bind@(PSB { psb_id = L loc id+ , psb_args = details+ , psb_def = lpat+ , psb_dir = dir }))+ = do { id' <- zonkIdBndr env id+ ; details' <- zonkPatSynDetails env details+ ; (env1, lpat') <- zonkPat env lpat+ ; (_env2, dir') <- zonkPatSynDir env1 dir+ ; return $ PatSynBind $+ bind { psb_id = L loc id'+ , psb_args = details'+ , psb_def = lpat'+ , psb_dir = dir' } }++zonkPatSynDetails :: ZonkEnv+ -> HsPatSynDetails (Located TcId)+ -> TcM (HsPatSynDetails (Located Id))+zonkPatSynDetails env = traverse (wrapLocM $ zonkIdBndr env)++zonkPatSynDir :: ZonkEnv -> HsPatSynDir TcId -> TcM (ZonkEnv, HsPatSynDir Id)+zonkPatSynDir env Unidirectional = return (env, Unidirectional)+zonkPatSynDir env ImplicitBidirectional = return (env, ImplicitBidirectional)+zonkPatSynDir env (ExplicitBidirectional mg) = do+ mg' <- zonkMatchGroup env zonkLExpr mg+ return (env, ExplicitBidirectional mg')++zonkSpecPrags :: ZonkEnv -> TcSpecPrags -> TcM TcSpecPrags+zonkSpecPrags _ IsDefaultMethod = return IsDefaultMethod+zonkSpecPrags env (SpecPrags ps) = do { ps' <- zonkLTcSpecPrags env ps+ ; return (SpecPrags ps') }++zonkLTcSpecPrags :: ZonkEnv -> [LTcSpecPrag] -> TcM [LTcSpecPrag]+zonkLTcSpecPrags env ps+ = mapM zonk_prag ps+ where+ zonk_prag (L loc (SpecPrag id co_fn inl))+ = do { (_, co_fn') <- zonkCoFn env co_fn+ ; return (L loc (SpecPrag (zonkIdOcc env id) co_fn' inl)) }++{-+************************************************************************+* *+\subsection[BackSubst-Match-GRHSs]{Match and GRHSs}+* *+************************************************************************+-}++zonkMatchGroup :: ZonkEnv+ -> (ZonkEnv -> Located (body TcId) -> TcM (Located (body Id)))+ -> MatchGroup TcId (Located (body TcId)) -> TcM (MatchGroup Id (Located (body Id)))+zonkMatchGroup env zBody (MG { mg_alts = L l ms, mg_arg_tys = arg_tys+ , mg_res_ty = res_ty, mg_origin = origin })+ = do { ms' <- mapM (zonkMatch env zBody) ms+ ; arg_tys' <- zonkTcTypeToTypes env arg_tys+ ; res_ty' <- zonkTcTypeToType env res_ty+ ; return (MG { mg_alts = L l ms', mg_arg_tys = arg_tys'+ , mg_res_ty = res_ty', mg_origin = origin }) }++zonkMatch :: ZonkEnv+ -> (ZonkEnv -> Located (body TcId) -> TcM (Located (body Id)))+ -> LMatch TcId (Located (body TcId)) -> TcM (LMatch Id (Located (body Id)))+zonkMatch env zBody (L loc (Match mf pats _ grhss))+ = do { (env1, new_pats) <- zonkPats env pats+ ; new_grhss <- zonkGRHSs env1 zBody grhss+ ; return (L loc (Match mf new_pats Nothing new_grhss)) }++-------------------------------------------------------------------------+zonkGRHSs :: ZonkEnv+ -> (ZonkEnv -> Located (body TcId) -> TcM (Located (body Id)))+ -> GRHSs TcId (Located (body TcId)) -> TcM (GRHSs Id (Located (body Id)))++zonkGRHSs env zBody (GRHSs grhss (L l binds)) = do+ (new_env, new_binds) <- zonkLocalBinds env binds+ let+ zonk_grhs (GRHS guarded rhs)+ = do (env2, new_guarded) <- zonkStmts new_env zonkLExpr guarded+ new_rhs <- zBody env2 rhs+ return (GRHS new_guarded new_rhs)+ new_grhss <- mapM (wrapLocM zonk_grhs) grhss+ return (GRHSs new_grhss (L l new_binds))++{-+************************************************************************+* *+\subsection[BackSubst-HsExpr]{Running a zonkitution over a TypeCheckedExpr}+* *+************************************************************************+-}++zonkLExprs :: ZonkEnv -> [LHsExpr TcId] -> TcM [LHsExpr Id]+zonkLExpr :: ZonkEnv -> LHsExpr TcId -> TcM (LHsExpr Id)+zonkExpr :: ZonkEnv -> HsExpr TcId -> TcM (HsExpr Id)++zonkLExprs env exprs = mapM (zonkLExpr env) exprs+zonkLExpr env expr = wrapLocM (zonkExpr env) expr++zonkExpr env (HsVar (L l id))+ = ASSERT2( isNothing (isDataConId_maybe id), ppr id )+ return (HsVar (L l (zonkIdOcc env id)))++zonkExpr _ e@(HsConLikeOut {}) = return e++zonkExpr _ (HsIPVar id)+ = return (HsIPVar id)++zonkExpr _ e@HsOverLabel{} = return e++zonkExpr env (HsLit (HsRat f ty))+ = do new_ty <- zonkTcTypeToType env ty+ return (HsLit (HsRat f new_ty))++zonkExpr _ (HsLit lit)+ = return (HsLit lit)++zonkExpr env (HsOverLit lit)+ = do { lit' <- zonkOverLit env lit+ ; return (HsOverLit lit') }++zonkExpr env (HsLam matches)+ = do new_matches <- zonkMatchGroup env zonkLExpr matches+ return (HsLam new_matches)++zonkExpr env (HsLamCase matches)+ = do new_matches <- zonkMatchGroup env zonkLExpr matches+ return (HsLamCase new_matches)++zonkExpr env (HsApp e1 e2)+ = do new_e1 <- zonkLExpr env e1+ new_e2 <- zonkLExpr env e2+ return (HsApp new_e1 new_e2)++zonkExpr env (HsAppTypeOut e t)+ = do new_e <- zonkLExpr env e+ return (HsAppTypeOut new_e t)+ -- NB: the type is an HsType; can't zonk that!++zonkExpr _ e@(HsRnBracketOut _ _)+ = pprPanic "zonkExpr: HsRnBracketOut" (ppr e)++zonkExpr env (HsTcBracketOut body bs)+ = do bs' <- mapM zonk_b bs+ return (HsTcBracketOut body bs')+ where+ zonk_b (PendingTcSplice n e) = do e' <- zonkLExpr env e+ return (PendingTcSplice n e')++zonkExpr _ (HsSpliceE s) = WARN( True, ppr s ) -- Should not happen+ return (HsSpliceE s)++zonkExpr env (OpApp e1 op fixity e2)+ = do new_e1 <- zonkLExpr env e1+ new_op <- zonkLExpr env op+ new_e2 <- zonkLExpr env e2+ return (OpApp new_e1 new_op fixity new_e2)++zonkExpr env (NegApp expr op)+ = do (env', new_op) <- zonkSyntaxExpr env op+ new_expr <- zonkLExpr env' expr+ return (NegApp new_expr new_op)++zonkExpr env (HsPar e)+ = do new_e <- zonkLExpr env e+ return (HsPar new_e)++zonkExpr env (SectionL expr op)+ = do new_expr <- zonkLExpr env expr+ new_op <- zonkLExpr env op+ return (SectionL new_expr new_op)++zonkExpr env (SectionR op expr)+ = do new_op <- zonkLExpr env op+ new_expr <- zonkLExpr env expr+ return (SectionR new_op new_expr)++zonkExpr env (ExplicitTuple tup_args boxed)+ = do { new_tup_args <- mapM zonk_tup_arg tup_args+ ; return (ExplicitTuple new_tup_args boxed) }+ where+ zonk_tup_arg (L l (Present e)) = do { e' <- zonkLExpr env e+ ; return (L l (Present e')) }+ zonk_tup_arg (L l (Missing t)) = do { t' <- zonkTcTypeToType env t+ ; return (L l (Missing t')) }++zonkExpr env (ExplicitSum alt arity expr args)+ = do new_args <- mapM (zonkTcTypeToType env) args+ new_expr <- zonkLExpr env expr+ return (ExplicitSum alt arity new_expr new_args)++zonkExpr env (HsCase expr ms)+ = do new_expr <- zonkLExpr env expr+ new_ms <- zonkMatchGroup env zonkLExpr ms+ return (HsCase new_expr new_ms)++zonkExpr env (HsIf Nothing e1 e2 e3)+ = do new_e1 <- zonkLExpr env e1+ new_e2 <- zonkLExpr env e2+ new_e3 <- zonkLExpr env e3+ return (HsIf Nothing new_e1 new_e2 new_e3)++zonkExpr env (HsIf (Just fun) e1 e2 e3)+ = do (env1, new_fun) <- zonkSyntaxExpr env fun+ new_e1 <- zonkLExpr env1 e1+ new_e2 <- zonkLExpr env1 e2+ new_e3 <- zonkLExpr env1 e3+ return (HsIf (Just new_fun) new_e1 new_e2 new_e3)++zonkExpr env (HsMultiIf ty alts)+ = do { alts' <- mapM (wrapLocM zonk_alt) alts+ ; ty' <- zonkTcTypeToType env ty+ ; return $ HsMultiIf ty' alts' }+ where zonk_alt (GRHS guard expr)+ = do { (env', guard') <- zonkStmts env zonkLExpr guard+ ; expr' <- zonkLExpr env' expr+ ; return $ GRHS guard' expr' }++zonkExpr env (HsLet (L l binds) expr)+ = do (new_env, new_binds) <- zonkLocalBinds env binds+ new_expr <- zonkLExpr new_env expr+ return (HsLet (L l new_binds) new_expr)++zonkExpr env (HsDo do_or_lc (L l stmts) ty)+ = do (_, new_stmts) <- zonkStmts env zonkLExpr stmts+ new_ty <- zonkTcTypeToType env ty+ return (HsDo do_or_lc (L l new_stmts) new_ty)++zonkExpr env (ExplicitList ty wit exprs)+ = do (env1, new_wit) <- zonkWit env wit+ new_ty <- zonkTcTypeToType env1 ty+ new_exprs <- zonkLExprs env1 exprs+ return (ExplicitList new_ty new_wit new_exprs)+ where zonkWit env Nothing = return (env, Nothing)+ zonkWit env (Just fln) = second Just <$> zonkSyntaxExpr env fln++zonkExpr env (ExplicitPArr ty exprs)+ = do new_ty <- zonkTcTypeToType env ty+ new_exprs <- zonkLExprs env exprs+ return (ExplicitPArr new_ty new_exprs)++zonkExpr env expr@(RecordCon { rcon_con_expr = con_expr, rcon_flds = rbinds })+ = do { new_con_expr <- zonkExpr env con_expr+ ; new_rbinds <- zonkRecFields env rbinds+ ; return (expr { rcon_con_expr = new_con_expr+ , rcon_flds = new_rbinds }) }++zonkExpr env (RecordUpd { rupd_expr = expr, rupd_flds = rbinds+ , rupd_cons = cons, rupd_in_tys = in_tys+ , rupd_out_tys = out_tys, rupd_wrap = req_wrap })+ = do { new_expr <- zonkLExpr env expr+ ; new_in_tys <- mapM (zonkTcTypeToType env) in_tys+ ; new_out_tys <- mapM (zonkTcTypeToType env) out_tys+ ; new_rbinds <- zonkRecUpdFields env rbinds+ ; (_, new_recwrap) <- zonkCoFn env req_wrap+ ; return (RecordUpd { rupd_expr = new_expr, rupd_flds = new_rbinds+ , rupd_cons = cons, rupd_in_tys = new_in_tys+ , rupd_out_tys = new_out_tys, rupd_wrap = new_recwrap }) }++zonkExpr env (ExprWithTySigOut e ty)+ = do { e' <- zonkLExpr env e+ ; return (ExprWithTySigOut e' ty) }++zonkExpr env (ArithSeq expr wit info)+ = do (env1, new_wit) <- zonkWit env wit+ new_expr <- zonkExpr env expr+ new_info <- zonkArithSeq env1 info+ return (ArithSeq new_expr new_wit new_info)+ where zonkWit env Nothing = return (env, Nothing)+ zonkWit env (Just fln) = second Just <$> zonkSyntaxExpr env fln++zonkExpr env (PArrSeq expr info)+ = do new_expr <- zonkExpr env expr+ new_info <- zonkArithSeq env info+ return (PArrSeq new_expr new_info)++zonkExpr env (HsSCC src lbl expr)+ = do new_expr <- zonkLExpr env expr+ return (HsSCC src lbl new_expr)++zonkExpr env (HsTickPragma src info srcInfo expr)+ = do new_expr <- zonkLExpr env expr+ return (HsTickPragma src info srcInfo new_expr)++-- hdaume: core annotations+zonkExpr env (HsCoreAnn src lbl expr)+ = do new_expr <- zonkLExpr env expr+ return (HsCoreAnn src lbl new_expr)++-- arrow notation extensions+zonkExpr env (HsProc pat body)+ = do { (env1, new_pat) <- zonkPat env pat+ ; new_body <- zonkCmdTop env1 body+ ; return (HsProc new_pat new_body) }++-- StaticPointers extension+zonkExpr env (HsStatic fvs expr)+ = HsStatic fvs <$> zonkLExpr env expr++zonkExpr env (HsWrap co_fn expr)+ = do (env1, new_co_fn) <- zonkCoFn env co_fn+ new_expr <- zonkExpr env1 expr+ return (HsWrap new_co_fn new_expr)++zonkExpr _ e@(HsUnboundVar {}) = return e++zonkExpr _ expr = pprPanic "zonkExpr" (ppr expr)++-------------------------------------------------------------------------+{-+Note [Skolems in zonkSyntaxExpr]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider rebindable syntax with something like++ (>>=) :: (forall x. blah) -> (forall y. blah') -> blah''++The x and y become skolems that are in scope when type-checking the+arguments to the bind. This means that we must extend the ZonkEnv with+these skolems when zonking the arguments to the bind. But the skolems+are different between the two arguments, and so we should theoretically+carry around different environments to use for the different arguments.++However, this becomes a logistical nightmare, especially in dealing with+the more exotic Stmt forms. So, we simplify by making the critical+assumption that the uniques of the skolems are different. (This assumption+is justified by the use of newUnique in TcMType.instSkolTyCoVarX.)+Now, we can safely just extend one environment.+-}++-- See Note [Skolems in zonkSyntaxExpr]+zonkSyntaxExpr :: ZonkEnv -> SyntaxExpr TcId+ -> TcM (ZonkEnv, SyntaxExpr Id)+zonkSyntaxExpr env (SyntaxExpr { syn_expr = expr+ , syn_arg_wraps = arg_wraps+ , syn_res_wrap = res_wrap })+ = do { (env0, res_wrap') <- zonkCoFn env res_wrap+ ; expr' <- zonkExpr env0 expr+ ; (env1, arg_wraps') <- mapAccumLM zonkCoFn env0 arg_wraps+ ; return (env1, SyntaxExpr { syn_expr = expr'+ , syn_arg_wraps = arg_wraps'+ , syn_res_wrap = res_wrap' }) }++-------------------------------------------------------------------------++zonkLCmd :: ZonkEnv -> LHsCmd TcId -> TcM (LHsCmd Id)+zonkCmd :: ZonkEnv -> HsCmd TcId -> TcM (HsCmd Id)++zonkLCmd env cmd = wrapLocM (zonkCmd env) cmd++zonkCmd env (HsCmdWrap w cmd)+ = do { (env1, w') <- zonkCoFn env w+ ; cmd' <- zonkCmd env1 cmd+ ; return (HsCmdWrap w' cmd') }+zonkCmd env (HsCmdArrApp e1 e2 ty ho rl)+ = do new_e1 <- zonkLExpr env e1+ new_e2 <- zonkLExpr env e2+ new_ty <- zonkTcTypeToType env ty+ return (HsCmdArrApp new_e1 new_e2 new_ty ho rl)++zonkCmd env (HsCmdArrForm op f fixity args)+ = do new_op <- zonkLExpr env op+ new_args <- mapM (zonkCmdTop env) args+ return (HsCmdArrForm new_op f fixity new_args)++zonkCmd env (HsCmdApp c e)+ = do new_c <- zonkLCmd env c+ new_e <- zonkLExpr env e+ return (HsCmdApp new_c new_e)++zonkCmd env (HsCmdLam matches)+ = do new_matches <- zonkMatchGroup env zonkLCmd matches+ return (HsCmdLam new_matches)++zonkCmd env (HsCmdPar c)+ = do new_c <- zonkLCmd env c+ return (HsCmdPar new_c)++zonkCmd env (HsCmdCase expr ms)+ = do new_expr <- zonkLExpr env expr+ new_ms <- zonkMatchGroup env zonkLCmd ms+ return (HsCmdCase new_expr new_ms)++zonkCmd env (HsCmdIf eCond ePred cThen cElse)+ = do { (env1, new_eCond) <- zonkWit env eCond+ ; new_ePred <- zonkLExpr env1 ePred+ ; new_cThen <- zonkLCmd env1 cThen+ ; new_cElse <- zonkLCmd env1 cElse+ ; return (HsCmdIf new_eCond new_ePred new_cThen new_cElse) }+ where+ zonkWit env Nothing = return (env, Nothing)+ zonkWit env (Just w) = second Just <$> zonkSyntaxExpr env w++zonkCmd env (HsCmdLet (L l binds) cmd)+ = do (new_env, new_binds) <- zonkLocalBinds env binds+ new_cmd <- zonkLCmd new_env cmd+ return (HsCmdLet (L l new_binds) new_cmd)++zonkCmd env (HsCmdDo (L l stmts) ty)+ = do (_, new_stmts) <- zonkStmts env zonkLCmd stmts+ new_ty <- zonkTcTypeToType env ty+ return (HsCmdDo (L l new_stmts) new_ty)++++++zonkCmdTop :: ZonkEnv -> LHsCmdTop TcId -> TcM (LHsCmdTop Id)+zonkCmdTop env cmd = wrapLocM (zonk_cmd_top env) cmd++zonk_cmd_top :: ZonkEnv -> HsCmdTop TcId -> TcM (HsCmdTop Id)+zonk_cmd_top env (HsCmdTop cmd stack_tys ty ids)+ = do new_cmd <- zonkLCmd env cmd+ new_stack_tys <- zonkTcTypeToType env stack_tys+ new_ty <- zonkTcTypeToType env ty+ new_ids <- mapSndM (zonkExpr env) ids++ MASSERT( isLiftedTypeKind (typeKind new_stack_tys) )+ -- desugarer assumes that this is not levity polymorphic...+ -- but indeed it should always be lifted due to the typing+ -- rules for arrows++ return (HsCmdTop new_cmd new_stack_tys new_ty new_ids)++-------------------------------------------------------------------------+zonkCoFn :: ZonkEnv -> HsWrapper -> TcM (ZonkEnv, HsWrapper)+zonkCoFn env WpHole = return (env, WpHole)+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' <- zonkTcTypeToType env2 t1+ ; return (env2, WpFun c1' c2' t1' d) }+zonkCoFn env (WpCast co) = do { co' <- zonkCoToCo env co+ ; return (env, WpCast co') }+zonkCoFn env (WpEvLam ev) = do { (env', ev') <- zonkEvBndrX env ev+ ; return (env', WpEvLam ev') }+zonkCoFn env (WpEvApp arg) = do { arg' <- zonkEvTerm env arg+ ; return (env, WpEvApp arg') }+zonkCoFn env (WpTyLam tv) = ASSERT( isImmutableTyVar tv )+ do { (env', tv') <- zonkTyBndrX env tv+ ; return (env', WpTyLam tv') }+zonkCoFn env (WpTyApp ty) = do { ty' <- zonkTcTypeToType env ty+ ; return (env, WpTyApp ty') }+zonkCoFn env (WpLet bs) = do { (env1, bs') <- zonkTcEvBinds env bs+ ; return (env1, WpLet bs') }++-------------------------------------------------------------------------+zonkOverLit :: ZonkEnv -> HsOverLit TcId -> TcM (HsOverLit Id)+zonkOverLit env lit@(OverLit { ol_witness = e, ol_type = ty })+ = do { ty' <- zonkTcTypeToType env ty+ ; e' <- zonkExpr env e+ ; return (lit { ol_witness = e', ol_type = ty' }) }++-------------------------------------------------------------------------+zonkArithSeq :: ZonkEnv -> ArithSeqInfo TcId -> TcM (ArithSeqInfo Id)++zonkArithSeq env (From e)+ = do new_e <- zonkLExpr env e+ return (From new_e)++zonkArithSeq env (FromThen e1 e2)+ = do new_e1 <- zonkLExpr env e1+ new_e2 <- zonkLExpr env e2+ return (FromThen new_e1 new_e2)++zonkArithSeq env (FromTo e1 e2)+ = do new_e1 <- zonkLExpr env e1+ new_e2 <- zonkLExpr env e2+ return (FromTo new_e1 new_e2)++zonkArithSeq env (FromThenTo e1 e2 e3)+ = do new_e1 <- zonkLExpr env e1+ new_e2 <- zonkLExpr env e2+ new_e3 <- zonkLExpr env e3+ return (FromThenTo new_e1 new_e2 new_e3)+++-------------------------------------------------------------------------+zonkStmts :: ZonkEnv+ -> (ZonkEnv -> Located (body TcId) -> TcM (Located (body Id)))+ -> [LStmt TcId (Located (body TcId))] -> TcM (ZonkEnv, [LStmt Id (Located (body Id))])+zonkStmts env _ [] = return (env, [])+zonkStmts env zBody (s:ss) = do { (env1, s') <- wrapLocSndM (zonkStmt env zBody) s+ ; (env2, ss') <- zonkStmts env1 zBody ss+ ; return (env2, s' : ss') }++zonkStmt :: ZonkEnv+ -> (ZonkEnv -> Located (body TcId) -> TcM (Located (body Id)))+ -> Stmt TcId (Located (body TcId)) -> TcM (ZonkEnv, Stmt Id (Located (body Id)))+zonkStmt env _ (ParStmt stmts_w_bndrs mzip_op bind_op bind_ty)+ = do { (env1, new_bind_op) <- zonkSyntaxExpr env bind_op+ ; new_bind_ty <- zonkTcTypeToType env1 bind_ty+ ; new_stmts_w_bndrs <- mapM (zonk_branch env1) stmts_w_bndrs+ ; let new_binders = [b | ParStmtBlock _ bs _ <- new_stmts_w_bndrs, b <- bs]+ env2 = extendIdZonkEnvRec env1 new_binders+ ; new_mzip <- zonkExpr env2 mzip_op+ ; return (env2, ParStmt new_stmts_w_bndrs new_mzip new_bind_op new_bind_ty) }+ where+ zonk_branch env1 (ParStmtBlock stmts bndrs return_op)+ = do { (env2, new_stmts) <- zonkStmts env1 zonkLExpr stmts+ ; (env3, new_return) <- zonkSyntaxExpr env2 return_op+ ; return (ParStmtBlock new_stmts (zonkIdOccs env3 bndrs) new_return) }++zonkStmt env zBody (RecStmt { recS_stmts = segStmts, recS_later_ids = lvs, recS_rec_ids = rvs+ , recS_ret_fn = ret_id, recS_mfix_fn = mfix_id+ , recS_bind_fn = bind_id, recS_bind_ty = bind_ty+ , recS_later_rets = later_rets, recS_rec_rets = rec_rets+ , recS_ret_ty = ret_ty })+ = do { (env1, new_bind_id) <- zonkSyntaxExpr env bind_id+ ; (env2, new_mfix_id) <- zonkSyntaxExpr env1 mfix_id+ ; (env3, new_ret_id) <- zonkSyntaxExpr env2 ret_id+ ; new_bind_ty <- zonkTcTypeToType env3 bind_ty+ ; new_rvs <- zonkIdBndrs env3 rvs+ ; new_lvs <- zonkIdBndrs env3 lvs+ ; new_ret_ty <- zonkTcTypeToType env3 ret_ty+ ; let env4 = extendIdZonkEnvRec env3 new_rvs+ ; (env5, new_segStmts) <- zonkStmts env4 zBody segStmts+ -- Zonk the ret-expressions in an envt that+ -- has the polymorphic bindings in the envt+ ; new_later_rets <- mapM (zonkExpr env5) later_rets+ ; new_rec_rets <- mapM (zonkExpr env5) rec_rets+ ; return (extendIdZonkEnvRec env3 new_lvs, -- Only the lvs are needed+ RecStmt { recS_stmts = new_segStmts, recS_later_ids = new_lvs+ , recS_rec_ids = new_rvs, recS_ret_fn = new_ret_id+ , recS_mfix_fn = new_mfix_id, recS_bind_fn = new_bind_id+ , recS_bind_ty = new_bind_ty+ , recS_later_rets = new_later_rets+ , recS_rec_rets = new_rec_rets, recS_ret_ty = new_ret_ty }) }++zonkStmt env zBody (BodyStmt body then_op guard_op ty)+ = do (env1, new_then_op) <- zonkSyntaxExpr env then_op+ (env2, new_guard_op) <- zonkSyntaxExpr env1 guard_op+ new_body <- zBody env2 body+ new_ty <- zonkTcTypeToType env2 ty+ return (env2, BodyStmt new_body new_then_op new_guard_op new_ty)++zonkStmt env zBody (LastStmt body noret ret_op)+ = do (env1, new_ret) <- zonkSyntaxExpr env ret_op+ new_body <- zBody env1 body+ return (env, LastStmt new_body noret new_ret)++zonkStmt env _ (TransStmt { trS_stmts = stmts, trS_bndrs = binderMap+ , trS_by = by, trS_form = form, trS_using = using+ , trS_ret = return_op, trS_bind = bind_op+ , trS_bind_arg_ty = bind_arg_ty+ , trS_fmap = liftM_op })+ = do {+ ; (env1, bind_op') <- zonkSyntaxExpr env bind_op+ ; bind_arg_ty' <- zonkTcTypeToType env1 bind_arg_ty+ ; (env2, stmts') <- zonkStmts env1 zonkLExpr stmts+ ; by' <- fmapMaybeM (zonkLExpr env2) by+ ; using' <- zonkLExpr env2 using++ ; (env3, return_op') <- zonkSyntaxExpr env2 return_op+ ; binderMap' <- mapM (zonkBinderMapEntry env3) binderMap+ ; liftM_op' <- zonkExpr env3 liftM_op+ ; let env3' = extendIdZonkEnvRec env3 (map snd binderMap')+ ; return (env3', TransStmt { trS_stmts = stmts', trS_bndrs = binderMap'+ , trS_by = by', trS_form = form, trS_using = using'+ , trS_ret = return_op', trS_bind = bind_op'+ , trS_bind_arg_ty = bind_arg_ty'+ , trS_fmap = liftM_op' }) }+ where+ zonkBinderMapEntry env (oldBinder, newBinder) = do+ let oldBinder' = zonkIdOcc env oldBinder+ newBinder' <- zonkIdBndr env newBinder+ return (oldBinder', newBinder')++zonkStmt env _ (LetStmt (L l binds))+ = do (env1, new_binds) <- zonkLocalBinds env binds+ return (env1, LetStmt (L l new_binds))++zonkStmt env zBody (BindStmt pat body bind_op fail_op bind_ty)+ = do { (env1, new_bind) <- zonkSyntaxExpr env bind_op+ ; new_bind_ty <- zonkTcTypeToType env1 bind_ty+ ; new_body <- zBody env1 body+ ; (env2, new_pat) <- zonkPat env1 pat+ ; (_, new_fail) <- zonkSyntaxExpr env1 fail_op+ ; return (env2, BindStmt new_pat new_body new_bind new_fail new_bind_ty) }++-- Scopes: join > ops (in reverse order) > pats (in forward order)+-- > rest of stmts+zonkStmt env _zBody (ApplicativeStmt args mb_join body_ty)+ = do { (env1, new_mb_join) <- zonk_join env mb_join+ ; (env2, new_args) <- zonk_args env1 args+ ; new_body_ty <- zonkTcTypeToType env2 body_ty+ ; return (env2, ApplicativeStmt new_args new_mb_join new_body_ty) }+ where+ zonk_join env Nothing = return (env, Nothing)+ zonk_join env (Just j) = second Just <$> zonkSyntaxExpr env j++ get_pat (_, ApplicativeArgOne pat _) = pat+ get_pat (_, ApplicativeArgMany _ _ pat) = pat++ replace_pat pat (op, ApplicativeArgOne _ a)+ = (op, ApplicativeArgOne pat a)+ replace_pat pat (op, ApplicativeArgMany a b _)+ = (op, ApplicativeArgMany a b pat)++ zonk_args env args+ = do { (env1, new_args_rev) <- zonk_args_rev env (reverse args)+ ; (env2, new_pats) <- zonkPats env1 (map get_pat args)+ ; return (env2, zipWith replace_pat new_pats (reverse new_args_rev)) }++ -- these need to go backward, because if any operators are higher-rank,+ -- later operators may introduce skolems that are in scope for earlier+ -- arguments+ zonk_args_rev env ((op, arg) : args)+ = do { (env1, new_op) <- zonkSyntaxExpr env op+ ; new_arg <- zonk_arg env1 arg+ ; (env2, new_args) <- zonk_args_rev env1 args+ ; return (env2, (new_op, new_arg) : new_args) }+ zonk_args_rev env [] = return (env, [])++ zonk_arg env (ApplicativeArgOne pat expr)+ = do { new_expr <- zonkLExpr env expr+ ; return (ApplicativeArgOne pat new_expr) }+ zonk_arg env (ApplicativeArgMany stmts ret pat)+ = do { (env1, new_stmts) <- zonkStmts env zonkLExpr stmts+ ; new_ret <- zonkExpr env1 ret+ ; return (ApplicativeArgMany new_stmts new_ret pat) }++-------------------------------------------------------------------------+zonkRecFields :: ZonkEnv -> HsRecordBinds TcId -> TcM (HsRecordBinds TcId)+zonkRecFields env (HsRecFields flds dd)+ = do { flds' <- mapM zonk_rbind flds+ ; return (HsRecFields flds' dd) }+ where+ zonk_rbind (L l fld)+ = do { new_id <- wrapLocM (zonkFieldOcc env) (hsRecFieldLbl fld)+ ; new_expr <- zonkLExpr env (hsRecFieldArg fld)+ ; return (L l (fld { hsRecFieldLbl = new_id+ , hsRecFieldArg = new_expr })) }++zonkRecUpdFields :: ZonkEnv -> [LHsRecUpdField TcId] -> TcM [LHsRecUpdField TcId]+zonkRecUpdFields env = mapM zonk_rbind+ where+ zonk_rbind (L l fld)+ = do { new_id <- wrapLocM (zonkFieldOcc env) (hsRecUpdFieldOcc fld)+ ; new_expr <- zonkLExpr env (hsRecFieldArg fld)+ ; return (L l (fld { hsRecFieldLbl = fmap ambiguousFieldOcc new_id+ , hsRecFieldArg = new_expr })) }++-------------------------------------------------------------------------+mapIPNameTc :: (a -> TcM b) -> Either (Located HsIPName) a+ -> TcM (Either (Located HsIPName) b)+mapIPNameTc _ (Left x) = return (Left x)+mapIPNameTc f (Right x) = do r <- f x+ return (Right r)++{-+************************************************************************+* *+\subsection[BackSubst-Pats]{Patterns}+* *+************************************************************************+-}++zonkPat :: ZonkEnv -> OutPat TcId -> TcM (ZonkEnv, OutPat Id)+-- Extend the environment as we go, because it's possible for one+-- pattern to bind something that is used in another (inside or+-- to the right)+zonkPat env pat = wrapLocSndM (zonk_pat env) pat++zonk_pat :: ZonkEnv -> Pat TcId -> TcM (ZonkEnv, Pat Id)+zonk_pat env (ParPat p)+ = do { (env', p') <- zonkPat env p+ ; return (env', ParPat p') }++zonk_pat env (WildPat ty)+ = do { ty' <- zonkTcTypeToType env ty+ ; ensureNotLevPoly ty'+ (text "In a wildcard pattern")+ ; return (env, WildPat ty') }++zonk_pat env (VarPat (L l v))+ = do { v' <- zonkIdBndr env v+ ; return (extendIdZonkEnv1 env v', VarPat (L l v')) }++zonk_pat env (LazyPat pat)+ = do { (env', pat') <- zonkPat env pat+ ; return (env', LazyPat pat') }++zonk_pat env (BangPat pat)+ = do { (env', pat') <- zonkPat env pat+ ; return (env', BangPat pat') }++zonk_pat env (AsPat (L loc v) pat)+ = do { v' <- zonkIdBndr env v+ ; (env', pat') <- zonkPat (extendIdZonkEnv1 env v') pat+ ; return (env', AsPat (L loc v') pat') }++zonk_pat env (ViewPat expr pat ty)+ = do { expr' <- zonkLExpr env expr+ ; (env', pat') <- zonkPat env pat+ ; ty' <- zonkTcTypeToType env ty+ ; return (env', ViewPat expr' pat' ty') }++zonk_pat env (ListPat pats ty Nothing)+ = do { ty' <- zonkTcTypeToType env ty+ ; (env', pats') <- zonkPats env pats+ ; return (env', ListPat pats' ty' Nothing) }++zonk_pat env (ListPat pats ty (Just (ty2,wit)))+ = do { (env', wit') <- zonkSyntaxExpr env wit+ ; ty2' <- zonkTcTypeToType env' ty2+ ; ty' <- zonkTcTypeToType env' ty+ ; (env'', pats') <- zonkPats env' pats+ ; return (env'', ListPat pats' ty' (Just (ty2',wit'))) }++zonk_pat env (PArrPat pats ty)+ = do { ty' <- zonkTcTypeToType env ty+ ; (env', pats') <- zonkPats env pats+ ; return (env', PArrPat pats' ty') }++zonk_pat env (TuplePat pats boxed tys)+ = do { tys' <- mapM (zonkTcTypeToType env) tys+ ; (env', pats') <- zonkPats env pats+ ; return (env', TuplePat pats' boxed tys') }++zonk_pat env (SumPat pat alt arity tys)+ = do { tys' <- mapM (zonkTcTypeToType env) tys+ ; (env', pat') <- zonkPat env pat+ ; return (env', SumPat pat' alt arity tys') }++zonk_pat env p@(ConPatOut { pat_arg_tys = tys, pat_tvs = tyvars+ , pat_dicts = evs, pat_binds = binds+ , pat_args = args, pat_wrap = wrapper+ , pat_con = L _ con })+ = ASSERT( all isImmutableTyVar tyvars )+ do { new_tys <- mapM (zonkTcTypeToType env) tys++ -- an unboxed tuple pattern (but only an unboxed tuple pattern)+ -- might have levity-polymorphic arguments. Check for this badness.+ ; case con of+ RealDataCon dc+ | isUnboxedTupleTyCon (dataConTyCon dc)+ -> mapM_ (checkForLevPoly doc) (dropRuntimeRepArgs new_tys)+ _ -> return ()++ ; (env0, new_tyvars) <- zonkTyBndrsX env tyvars+ -- Must zonk the existential variables, because their+ -- /kind/ need potential zonking.+ -- cf typecheck/should_compile/tc221.hs+ ; (env1, new_evs) <- zonkEvBndrsX env0 evs+ ; (env2, new_binds) <- zonkTcEvBinds env1 binds+ ; (env3, new_wrapper) <- zonkCoFn env2 wrapper+ ; (env', new_args) <- zonkConStuff env3 args+ ; return (env', p { pat_arg_tys = new_tys,+ pat_tvs = new_tyvars,+ pat_dicts = new_evs,+ pat_binds = new_binds,+ pat_args = new_args,+ pat_wrap = new_wrapper}) }+ where+ doc = text "In the type of an element of an unboxed tuple pattern:" $$ ppr p++zonk_pat env (LitPat lit) = return (env, LitPat lit)++zonk_pat env (SigPatOut pat ty)+ = do { ty' <- zonkTcTypeToType env ty+ ; (env', pat') <- zonkPat env pat+ ; return (env', SigPatOut pat' ty') }++zonk_pat env (NPat (L l lit) mb_neg eq_expr ty)+ = do { (env1, eq_expr') <- zonkSyntaxExpr env eq_expr+ ; (env2, mb_neg') <- case mb_neg of+ Nothing -> return (env1, Nothing)+ Just n -> second Just <$> zonkSyntaxExpr env1 n++ ; lit' <- zonkOverLit env2 lit+ ; ty' <- zonkTcTypeToType env2 ty+ ; return (env2, NPat (L l lit') mb_neg' eq_expr' ty') }++zonk_pat env (NPlusKPat (L loc n) (L l lit1) lit2 e1 e2 ty)+ = do { (env1, e1') <- zonkSyntaxExpr env e1+ ; (env2, e2') <- zonkSyntaxExpr env1 e2+ ; n' <- zonkIdBndr env2 n+ ; lit1' <- zonkOverLit env2 lit1+ ; lit2' <- zonkOverLit env2 lit2+ ; ty' <- zonkTcTypeToType env2 ty+ ; return (extendIdZonkEnv1 env2 n',+ NPlusKPat (L loc n') (L l lit1') lit2' e1' e2' ty') }++zonk_pat env (CoPat co_fn pat ty)+ = do { (env', co_fn') <- zonkCoFn env co_fn+ ; (env'', pat') <- zonkPat env' (noLoc pat)+ ; ty' <- zonkTcTypeToType env'' ty+ ; return (env'', CoPat co_fn' (unLoc pat') ty') }++zonk_pat _ pat = pprPanic "zonk_pat" (ppr pat)++---------------------------+zonkConStuff :: ZonkEnv+ -> HsConDetails (OutPat TcId) (HsRecFields id (OutPat TcId))+ -> TcM (ZonkEnv,+ HsConDetails (OutPat Id) (HsRecFields id (OutPat Id)))+zonkConStuff env (PrefixCon pats)+ = do { (env', pats') <- zonkPats env pats+ ; return (env', PrefixCon pats') }++zonkConStuff env (InfixCon p1 p2)+ = do { (env1, p1') <- zonkPat env p1+ ; (env', p2') <- zonkPat env1 p2+ ; return (env', InfixCon p1' p2') }++zonkConStuff env (RecCon (HsRecFields rpats dd))+ = do { (env', pats') <- zonkPats env (map (hsRecFieldArg . unLoc) rpats)+ ; let rpats' = zipWith (\(L l rp) p' -> L l (rp { hsRecFieldArg = p' }))+ rpats pats'+ ; return (env', RecCon (HsRecFields rpats' dd)) }+ -- Field selectors have declared types; hence no zonking++---------------------------+zonkPats :: ZonkEnv -> [OutPat TcId] -> TcM (ZonkEnv, [OutPat Id])+zonkPats env [] = return (env, [])+zonkPats env (pat:pats) = do { (env1, pat') <- zonkPat env pat+ ; (env', pats') <- zonkPats env1 pats+ ; return (env', pat':pats') }++{-+************************************************************************+* *+\subsection[BackSubst-Foreign]{Foreign exports}+* *+************************************************************************+-}++zonkForeignExports :: ZonkEnv -> [LForeignDecl TcId] -> TcM [LForeignDecl Id]+zonkForeignExports env ls = mapM (wrapLocM (zonkForeignExport env)) ls++zonkForeignExport :: ZonkEnv -> ForeignDecl TcId -> TcM (ForeignDecl Id)+zonkForeignExport env (ForeignExport { fd_name = i, fd_co = co, fd_fe = spec })+ = return (ForeignExport { fd_name = fmap (zonkIdOcc env) i+ , fd_sig_ty = undefined, fd_co = co+ , fd_fe = spec })+zonkForeignExport _ for_imp+ = return for_imp -- Foreign imports don't need zonking++zonkRules :: ZonkEnv -> [LRuleDecl TcId] -> TcM [LRuleDecl Id]+zonkRules env rs = mapM (wrapLocM (zonkRule env)) rs++zonkRule :: ZonkEnv -> RuleDecl TcId -> TcM (RuleDecl Id)+zonkRule env (HsRule name act (vars{-::[RuleBndr TcId]-}) lhs fv_lhs rhs fv_rhs)+ = do { (env_inside, new_bndrs) <- mapAccumLM zonk_bndr env vars++ ; let env_lhs = setZonkType env_inside zonkTvSkolemising+ -- See Note [Zonking the LHS of a RULE]++ ; new_lhs <- zonkLExpr env_lhs lhs+ ; new_rhs <- zonkLExpr env_inside rhs++ ; return (HsRule name act new_bndrs new_lhs fv_lhs new_rhs fv_rhs) }+ where+ zonk_bndr env (L l (RuleBndr (L loc v)))+ = do { (env', v') <- zonk_it env v+ ; return (env', L l (RuleBndr (L loc v'))) }+ zonk_bndr _ (L _ (RuleBndrSig {})) = panic "zonk_bndr RuleBndrSig"++ zonk_it env v+ | isId v = do { v' <- zonkIdBndr env v+ ; return (extendIdZonkEnvRec env [v'], v') }+ | otherwise = ASSERT( isImmutableTyVar v)+ zonkTyBndrX env v+ -- DV: used to be return (env,v) but that is plain+ -- wrong because we may need to go inside the kind+ -- of v and zonk there!++zonkVects :: ZonkEnv -> [LVectDecl TcId] -> TcM [LVectDecl Id]+zonkVects env = mapM (wrapLocM (zonkVect env))++zonkVect :: ZonkEnv -> VectDecl TcId -> TcM (VectDecl Id)+zonkVect env (HsVect s v e)+ = do { v' <- wrapLocM (zonkIdBndr env) v+ ; e' <- zonkLExpr env e+ ; return $ HsVect s v' e'+ }+zonkVect env (HsNoVect s v)+ = do { v' <- wrapLocM (zonkIdBndr env) v+ ; return $ HsNoVect s v'+ }+zonkVect _env (HsVectTypeOut s t rt)+ = return $ HsVectTypeOut s t rt+zonkVect _ (HsVectTypeIn _ _ _ _) = panic "TcHsSyn.zonkVect: HsVectTypeIn"+zonkVect _env (HsVectClassOut c)+ = return $ HsVectClassOut c+zonkVect _ (HsVectClassIn _ _) = panic "TcHsSyn.zonkVect: HsVectClassIn"+zonkVect _env (HsVectInstOut i)+ = return $ HsVectInstOut i+zonkVect _ (HsVectInstIn _) = panic "TcHsSyn.zonkVect: HsVectInstIn"++{-+************************************************************************+* *+ Constraints and evidence+* *+************************************************************************+-}++zonkEvTerm :: ZonkEnv -> EvTerm -> TcM EvTerm+zonkEvTerm env (EvId v) = ASSERT2( isId v, ppr v )+ zonkEvVarOcc env v+zonkEvTerm env (EvCoercion co) = do { co' <- zonkCoToCo env co+ ; return (EvCoercion co') }+zonkEvTerm env (EvCast tm co) = do { tm' <- zonkEvTerm env tm+ ; co' <- zonkCoToCo env co+ ; return (mkEvCast tm' co') }+zonkEvTerm _ (EvLit l) = return (EvLit l)++zonkEvTerm env (EvTypeable ty ev) =+ do { ev' <- zonkEvTypeable env ev+ ; ty' <- zonkTcTypeToType env ty+ ; return (EvTypeable ty' ev') }+zonkEvTerm env (EvCallStack cs)+ = case cs of+ EvCsEmpty -> return (EvCallStack cs)+ EvCsPushCall n l tm -> do { tm' <- zonkEvTerm env tm+ ; return (EvCallStack (EvCsPushCall n l tm')) }++zonkEvTerm env (EvSuperClass d n) = do { d' <- zonkEvTerm env d+ ; return (EvSuperClass d' n) }+zonkEvTerm env (EvDFunApp df tys tms)+ = do { tys' <- zonkTcTypeToTypes env tys+ ; tms' <- mapM (zonkEvTerm env) tms+ ; return (EvDFunApp (zonkIdOcc env df) tys' tms') }+zonkEvTerm env (EvDelayedError ty msg)+ = do { ty' <- zonkTcTypeToType env ty+ ; return (EvDelayedError ty' msg) }+zonkEvTerm env (EvSelector sel_id tys tms)+ = do { sel_id' <- zonkIdBndr env sel_id+ ; tys' <- zonkTcTypeToTypes env tys+ ; tms' <- mapM (zonkEvTerm env) tms+ ; return (EvSelector sel_id' tys' tms') }++zonkEvTypeable :: ZonkEnv -> EvTypeable -> TcM EvTypeable+zonkEvTypeable env (EvTypeableTyCon tycon e)+ = do { e' <- mapM (zonkEvTerm env) e+ ; return $ EvTypeableTyCon tycon e' }+zonkEvTypeable env (EvTypeableTyApp t1 t2)+ = do { t1' <- zonkEvTerm env t1+ ; t2' <- zonkEvTerm env t2+ ; return (EvTypeableTyApp t1' t2') }+zonkEvTypeable env (EvTypeableTrFun t1 t2)+ = do { t1' <- zonkEvTerm env t1+ ; t2' <- zonkEvTerm env t2+ ; return (EvTypeableTrFun t1' t2') }+zonkEvTypeable env (EvTypeableTyLit t1)+ = do { t1' <- zonkEvTerm env t1+ ; return (EvTypeableTyLit t1') }++zonkTcEvBinds_s :: ZonkEnv -> [TcEvBinds] -> TcM (ZonkEnv, [TcEvBinds])+zonkTcEvBinds_s env bs = do { (env, bs') <- mapAccumLM zonk_tc_ev_binds env bs+ ; return (env, [EvBinds (unionManyBags bs')]) }++zonkTcEvBinds :: ZonkEnv -> TcEvBinds -> TcM (ZonkEnv, TcEvBinds)+zonkTcEvBinds env bs = do { (env', bs') <- zonk_tc_ev_binds env bs+ ; return (env', EvBinds bs') }++zonk_tc_ev_binds :: ZonkEnv -> TcEvBinds -> TcM (ZonkEnv, Bag EvBind)+zonk_tc_ev_binds env (TcEvBinds var) = zonkEvBindsVar env var+zonk_tc_ev_binds env (EvBinds bs) = zonkEvBinds env bs++zonkEvBindsVar :: ZonkEnv -> EvBindsVar -> TcM (ZonkEnv, Bag EvBind)+zonkEvBindsVar env (EvBindsVar { ebv_binds = ref })+ = do { bs <- readMutVar ref+ ; zonkEvBinds env (evBindMapBinds bs) }++zonkEvBinds :: ZonkEnv -> Bag EvBind -> TcM (ZonkEnv, Bag EvBind)+zonkEvBinds env binds+ = {-# SCC "zonkEvBinds" #-}+ fixM (\ ~( _, new_binds) -> do+ { let env1 = extendIdZonkEnvRec env (collect_ev_bndrs new_binds)+ ; binds' <- mapBagM (zonkEvBind env1) binds+ ; return (env1, binds') })+ where+ collect_ev_bndrs :: Bag EvBind -> [EvVar]+ collect_ev_bndrs = foldrBag add []+ add (EvBind { eb_lhs = var }) vars = var : vars++zonkEvBind :: ZonkEnv -> EvBind -> TcM EvBind+zonkEvBind env bind@(EvBind { eb_lhs = var, eb_rhs = term })+ = do { var' <- {-# SCC "zonkEvBndr" #-} zonkEvBndr env var++ -- Optimise the common case of Refl coercions+ -- See Note [Optimise coercion zonking]+ -- This has a very big effect on some programs (eg Trac #5030)++ ; term' <- case getEqPredTys_maybe (idType var') of+ Just (r, ty1, ty2) | ty1 `eqType` ty2+ -> return (EvCoercion (mkTcReflCo r ty1))+ _other -> zonkEvTerm env term++ ; return (bind { eb_lhs = var', eb_rhs = term' }) }++{-+************************************************************************+* *+ Zonking types+* *+************************************************************************++Note [Zonking mutable unbound type or kind variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In zonkTypeZapping, we zonk mutable but unbound type or kind variables to an+arbitrary type. We know if they are unbound even though we don't carry an+environment, because at the binding site for a variable we bind the mutable+var to a fresh immutable one. So the mutable store plays the role of an+environment. If we come across a mutable variable that isn't so bound, it+must be completely free. We zonk the expected kind to make sure we don't get+some unbound meta variable as the kind.++Note that since we have kind polymorphism, zonk_unbound_tyvar will handle both+type and kind variables. Consider the following datatype:++ data Phantom a = Phantom Int++The type of Phantom is (forall (k : *). forall (a : k). Int). Both `a` and+`k` are unbound variables. We want to zonk this to+(forall (k : Any *). forall (a : Any (Any *)). Int).++Note [Optimise coercion zonking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When optimising evidence binds we may come across situations where+a coercion looks like+ cv = ReflCo ty+or cv1 = cv2+where the type 'ty' is big. In such cases it is a waste of time to zonk both+ * The variable on the LHS+ * The coercion on the RHS+Rather, we can zonk the variable, and if its type is (ty ~ ty), we can just+use Refl on the right, ignoring the actual coercion on the RHS.++This can have a very big effect, because the constraint solver sometimes does go+to a lot of effort to prove Refl! (Eg when solving 10+3 = 10+3; cf Trac #5030)++-}++zonkTyVarOcc :: ZonkEnv -> TyVar -> TcM TcType+zonkTyVarOcc env@(ZonkEnv zonk_unbound_tyvar tv_env _) tv+ | isTcTyVar tv+ = case tcTyVarDetails tv of+ SkolemTv {} -> lookup_in_env+ RuntimeUnk {} -> lookup_in_env+ FlatSkol ty -> zonkTcTypeToType env ty+ MetaTv { mtv_ref = ref }+ -> do { cts <- readMutVar ref+ ; case cts of+ Flexi -> do { kind <- {-# SCC "zonkKind1" #-}+ zonkTcTypeToType env (tyVarKind tv)+ ; zonk_unbound_tyvar (setTyVarKind tv kind) }+ Indirect ty -> do { zty <- zonkTcTypeToType env ty+ -- Small optimisation: shortern-out indirect steps+ -- so that the old type may be more easily collected.+ ; writeMutVar ref (Indirect zty)+ ; return zty } }+ | otherwise+ = lookup_in_env+ where+ lookup_in_env -- Look up in the env just as we do for Ids+ = case lookupVarEnv tv_env tv of+ Nothing -> mkTyVarTy <$> updateTyVarKindM (zonkTcTypeToType env) tv+ Just tv' -> return (mkTyVarTy tv')++zonkCoVarOcc :: ZonkEnv -> CoVar -> TcM Coercion+zonkCoVarOcc env@(ZonkEnv _ tyco_env _) cv+ | Just cv' <- lookupVarEnv tyco_env cv -- don't look in the knot-tied env+ = return $ mkCoVarCo cv'+ | otherwise+ = mkCoVarCo <$> updateVarTypeM (zonkTcTypeToType env) cv++zonkCoHole :: ZonkEnv -> CoercionHole+ -> Role -> Type -> Type -- these are all redundant with+ -- the details in the hole,+ -- unzonked+ -> TcM Coercion+zonkCoHole env h r t1 t2+ = do { contents <- unpackCoercionHole_maybe h+ ; case contents of+ Just co -> do { co <- zonkCoToCo env co+ ; checkCoercionHole co h r t1 t2 }++ -- This next case should happen only in the presence of+ -- (undeferred) type errors. Originally, I put in a panic+ -- here, but that caused too many uses of `failIfErrsM`.+ Nothing -> do { traceTc "Zonking unfilled coercion hole" (ppr h)+ ; when debugIsOn $+ whenNoErrs $+ MASSERT2( False+ , text "Type-correct unfilled coercion hole"+ <+> ppr h )+ ; t1 <- zonkTcTypeToType env t1+ ; t2 <- zonkTcTypeToType env t2+ ; return $ mkHoleCo h r t1 t2 } }++zonk_tycomapper :: TyCoMapper ZonkEnv TcM+zonk_tycomapper = TyCoMapper+ { tcm_smart = True -- Establish type invariants+ -- See Note [Type-checking inside the knot] in TcHsType+ , tcm_tyvar = zonkTyVarOcc+ , tcm_covar = zonkCoVarOcc+ , tcm_hole = zonkCoHole+ , tcm_tybinder = \env tv _vis -> zonkTyBndrX env tv }++-- Confused by zonking? See Note [What is zonking?] in TcMType.+zonkTcTypeToType :: ZonkEnv -> TcType -> TcM Type+zonkTcTypeToType = mapType zonk_tycomapper++zonkTcTypeToTypes :: ZonkEnv -> [TcType] -> TcM [Type]+zonkTcTypeToTypes env tys = mapM (zonkTcTypeToType env) tys++zonkCoToCo :: ZonkEnv -> Coercion -> TcM Coercion+zonkCoToCo = mapCoercion zonk_tycomapper++zonkSigType :: TcType -> TcM Type+-- Zonk the type obtained from a user type signature+-- We want to turn any quantified (forall'd) variables into TyVars+-- but we may find some free TcTyVars, and we want to leave them+-- completely alone. They may even have unification variables inside+-- e.g. f (x::a) = ...(e :: a -> a)....+-- The type sig for 'e' mentions a free 'a' which will be a+-- unification SigTv variable.+zonkSigType = zonkTcTypeToType (mkEmptyZonkEnv zonk_unbound_tv)+ where+ zonk_unbound_tv :: UnboundTyVarZonker+ zonk_unbound_tv tv = return (mkTyVarTy tv)++zonkTvSkolemising :: UnboundTyVarZonker+-- This variant is used for the LHS of rules+-- See Note [Zonking the LHS of a RULE].+zonkTvSkolemising tv+ = do { let tv' = mkTyVar (tyVarName tv) (tyVarKind tv)+ -- NB: the kind of tv is already zonked+ ty = mkTyVarTy tv'+ -- Make a proper TyVar (remember we+ -- are now done with type checking)+ ; writeMetaTyVar tv ty+ ; return ty }++zonkTypeZapping :: UnboundTyVarZonker+-- This variant is used for everything except the LHS of rules+-- It zaps unbound type variables to Any, except for RuntimeRep+-- vars which it zonks to LiftedRep+-- Works on both types and kinds+zonkTypeZapping tv+ = do { let ty | isRuntimeRepVar tv = liftedRepTy+ | otherwise = anyTypeOfKind (tyVarKind tv)+ ; writeMetaTyVar tv ty+ ; return ty }++---------------------------------------+{- Note [Zonking the LHS of a RULE]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See also DsBinds Note [Free tyvars on rule LHS]++We need to gather the type variables mentioned on the LHS so we can+quantify over them. Example:+ data T a = C++ foo :: T a -> Int+ foo C = 1++ {-# RULES "myrule" foo C = 1 #-}++After type checking the LHS becomes (foo alpha (C alpha)) and we do+not want to zap the unbound meta-tyvar 'alpha' to Any, because that+limits the applicability of the rule. Instead, we want to quantify+over it!++We do this in two stages.++* During zonking, we skolemise the TcTyVar 'alpha' to TyVar 'a'. We+ do this by using zonkTvSkolemising as the UnboundTyVarZonker in the+ ZonkEnv. (This is in fact the whole reason that the ZonkEnv has a+ UnboundTyVarZonker.)++* In DsBinds, we quantify over it. See DsBinds+ Note [Free tyvars on rule LHS]++Quantifying here is awkward because (a) the data type is big and (b)+finding the free type vars of an expression is necessarily monadic+operation. (consider /\a -> f @ b, where b is side-effected to a)+-}
+ typecheck/TcHsType.hs view
@@ -0,0 +1,2161 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[TcMonoType]{Typechecking user-specified @MonoTypes@}+-}++{-# LANGUAGE CPP, TupleSections, MultiWayIf, RankNTypes #-}++module TcHsType (+ -- Type signatures+ kcHsSigType, tcClassSigType,+ tcHsSigType, tcHsSigWcType,+ tcHsPartialSigType,+ funsSigCtxt, addSigCtxt, pprSigCtxt,++ tcHsClsInstType,+ tcHsDeriv, tcHsVectInst,+ tcHsTypeApp,+ UserTypeCtxt(..),+ tcImplicitTKBndrs, tcImplicitTKBndrsType, tcExplicitTKBndrs,++ -- Type checking type and class decls+ kcLookupTcTyCon, kcTyClTyVars, tcTyClTyVars,+ tcDataKindSig,++ -- Kind-checking types+ -- No kind generalisation, no checkValidType+ tcWildCardBinders,+ kcHsTyVarBndrs,+ tcHsLiftedType, tcHsOpenType,+ tcHsLiftedTypeNC, tcHsOpenTypeNC,+ tcLHsType, tcCheckLHsType,+ tcHsContext, tcLHsPredType, tcInferApps, tcInferArgs,+ solveEqualities, -- useful re-export++ kindGeneralize,++ -- Sort-checking kinds+ tcLHsKindSig,++ -- Pattern type signatures+ tcHsPatSigType, tcPatSig, funAppCtxt+ ) where++#include "HsVersions.h"++import HsSyn+import TcRnMonad+import TcEvidence+import TcEnv+import TcMType+import TcValidity+import TcUnify+import TcIface+import TcSimplify ( solveEqualities )+import TcType+import TcHsSyn( zonkSigType )+import Inst ( tcInstBindersX, tcInstBinderX )+import Type+import Kind+import RdrName( lookupLocalRdrOcc )+import Var+import VarSet+import TyCon+import ConLike+import DataCon+import Class+import Name+import NameEnv+import NameSet+import VarEnv+import TysWiredIn+import BasicTypes+import SrcLoc+import Constants ( mAX_CTUPLE_SIZE )+import ErrUtils( MsgDoc )+import Unique+import Util+import UniqSupply+import Outputable+import FastString+import PrelNames hiding ( wildCardName )+import qualified GHC.LanguageExtensions as LangExt++import Maybes+import Data.List ( partition, zipWith4 )+import Control.Monad++{-+ ----------------------------+ General notes+ ----------------------------++Unlike with expressions, type-checking types both does some checking and+desugars at the same time. This is necessary because we often want to perform+equality checks on the types right away, and it would be incredibly painful+to do this on un-desugared types. Luckily, desugared types are close enough+to HsTypes to make the error messages sane.++During type-checking, we perform as little validity checking as possible.+This is because some type-checking is done in a mutually-recursive knot, and+if we look too closely at the tycons, we'll loop. This is why we always must+use mkNakedTyConApp and mkNakedAppTys, etc., which never look at a tycon.+The mkNamed... functions don't uphold Type invariants, but zonkTcTypeToType+will repair this for us. Note that zonkTcType *is* safe within a knot, and+can be done repeatedly with no ill effect: it just squeezes out metavariables.++Generally, after type-checking, you will want to do validity checking, say+with TcValidity.checkValidType.++Validity checking+~~~~~~~~~~~~~~~~~+Some of the validity check could in principle be done by the kind checker,+but not all:++- During desugaring, we normalise by expanding type synonyms. Only+ after this step can we check things like type-synonym saturation+ e.g. type T k = k Int+ type S a = a+ Then (T S) is ok, because T is saturated; (T S) expands to (S Int);+ and then S is saturated. This is a GHC extension.++- Similarly, also a GHC extension, we look through synonyms before complaining+ about the form of a class or instance declaration++- Ambiguity checks involve functional dependencies, and it's easier to wait+ until knots have been resolved before poking into them++Also, in a mutually recursive group of types, we can't look at the TyCon until we've+finished building the loop. So to keep things simple, we postpone most validity+checking until step (3).++Knot tying+~~~~~~~~~~+During step (1) we might fault in a TyCon defined in another module, and it might+(via a loop) refer back to a TyCon defined in this module. So when we tie a big+knot around type declarations with ARecThing, so that the fault-in code can get+the TyCon being defined.++%************************************************************************+%* *+ Check types AND do validity checking+* *+************************************************************************+-}++funsSigCtxt :: [Located Name] -> UserTypeCtxt+-- Returns FunSigCtxt, with no redundant-context-reporting,+-- form a list of located names+funsSigCtxt (L _ name1 : _) = FunSigCtxt name1 False+funsSigCtxt [] = panic "funSigCtxt"++addSigCtxt :: UserTypeCtxt -> LHsType Name -> TcM a -> TcM a+addSigCtxt ctxt hs_ty thing_inside+ = setSrcSpan (getLoc hs_ty) $+ addErrCtxt (pprSigCtxt ctxt hs_ty) $+ thing_inside++pprSigCtxt :: UserTypeCtxt -> LHsType Name -> SDoc+-- (pprSigCtxt ctxt <extra> <type>)+-- prints In the type signature for 'f':+-- f :: <type>+-- The <extra> is either empty or "the ambiguity check for"+pprSigCtxt ctxt hs_ty+ | Just n <- isSigMaybe ctxt+ = hang (text "In the type signature:")+ 2 (pprPrefixOcc n <+> dcolon <+> ppr hs_ty)++ | otherwise+ = hang (text "In" <+> pprUserTypeCtxt ctxt <> colon)+ 2 (ppr hs_ty)++tcHsSigWcType :: UserTypeCtxt -> LHsSigWcType Name -> TcM Type+-- This one is used when we have a LHsSigWcType, but in+-- a place where wildards aren't allowed. The renamer has+-- already checked this, so we can simply ignore it.+tcHsSigWcType ctxt sig_ty = tcHsSigType ctxt (dropWildCards sig_ty)++kcHsSigType :: [Located Name] -> LHsSigType Name -> TcM ()+kcHsSigType names (HsIB { hsib_body = hs_ty+ , hsib_vars = sig_vars })+ = addSigCtxt (funsSigCtxt names) hs_ty $+ discardResult $+ tcImplicitTKBndrsType sig_vars $+ tc_lhs_type typeLevelMode hs_ty liftedTypeKind++tcClassSigType :: [Located Name] -> LHsSigType Name -> TcM Type+-- Does not do validity checking; this must be done outside+-- the recursive class declaration "knot"+tcClassSigType names sig_ty+ = addSigCtxt (funsSigCtxt names) (hsSigType sig_ty) $+ tc_hs_sig_type_and_gen sig_ty liftedTypeKind++tcHsSigType :: UserTypeCtxt -> LHsSigType Name -> TcM Type+-- Does validity checking+tcHsSigType ctxt sig_ty+ = addSigCtxt ctxt (hsSigType sig_ty) $+ do { kind <- case expectedKindInCtxt ctxt of+ AnythingKind -> newMetaKindVar+ TheKind k -> return k+ OpenKind -> newOpenTypeKind+ -- The kind is checked by checkValidType, and isn't necessarily+ -- of kind * in a Template Haskell quote eg [t| Maybe |]++ -- Generalise here: see Note [Kind generalisation]+ ; do_kind_gen <- decideKindGeneralisationPlan sig_ty+ ; ty <- if do_kind_gen+ then tc_hs_sig_type_and_gen sig_ty kind+ else tc_hs_sig_type sig_ty kind >>= zonkTcType++ ; checkValidType ctxt ty+ ; return ty }++tc_hs_sig_type_and_gen :: LHsSigType Name -> Kind -> TcM Type+-- Kind-checks/desugars an 'LHsSigType',+-- solve equalities,+-- and then kind-generalizes.+-- This will never emit constraints, as it uses solveEqualities interally.+-- No validity checking, but it does zonk en route to generalization+tc_hs_sig_type_and_gen hs_ty kind+ = do { ty <- solveEqualities $+ tc_hs_sig_type hs_ty kind+ -- NB the call to solveEqualities, which unifies all those+ -- kind variables floating about, immediately prior to+ -- kind generalisation+ ; kindGeneralizeType ty }++tc_hs_sig_type :: LHsSigType Name -> Kind -> TcM Type+-- Kind-check/desugar a 'LHsSigType', but does not solve+-- the equalities that arise from doing so; instead it may+-- emit kind-equality constraints into the monad+-- No zonking or validity checking+tc_hs_sig_type (HsIB { hsib_vars = sig_vars+ , hsib_body = hs_ty }) kind+ = do { (tkvs, ty) <- tcImplicitTKBndrsType sig_vars $+ tc_lhs_type typeLevelMode hs_ty kind+ ; return (mkSpecForAllTys tkvs ty) }++-----------------+tcHsDeriv :: LHsSigType Name -> TcM ([TyVar], Class, [Type], [Kind])+-- Like tcHsSigType, but for the ...deriving( C t1 ty2 ) clause+-- Returns the C, [ty1, ty2, and the kinds of C's remaining arguments+-- E.g. class C (a::*) (b::k->k)+-- data T a b = ... deriving( C Int )+-- returns ([k], C, [k, Int], [k->k])+tcHsDeriv hs_ty+ = do { cls_kind <- newMetaKindVar+ -- always safe to kind-generalize, because there+ -- can be no covars in an outer scope+ ; ty <- checkNoErrs $+ -- avoid redundant error report with "illegal deriving", below+ tc_hs_sig_type_and_gen hs_ty cls_kind+ ; cls_kind <- zonkTcType cls_kind+ ; let (tvs, pred) = splitForAllTys ty+ ; let (args, _) = splitFunTys cls_kind+ ; case getClassPredTys_maybe pred of+ Just (cls, tys) -> return (tvs, cls, tys, args)+ Nothing -> failWithTc (text "Illegal deriving item" <+> quotes (ppr hs_ty)) }++tcHsClsInstType :: UserTypeCtxt -- InstDeclCtxt or SpecInstCtxt+ -> LHsSigType Name+ -> TcM ([TyVar], ThetaType, Class, [Type])+-- Like tcHsSigType, but for a class instance declaration+tcHsClsInstType user_ctxt hs_inst_ty+ = setSrcSpan (getLoc (hsSigType hs_inst_ty)) $+ do { inst_ty <- tc_hs_sig_type_and_gen hs_inst_ty constraintKind+ ; checkValidInstance user_ctxt hs_inst_ty inst_ty }++-- Used for 'VECTORISE [SCALAR] instance' declarations+tcHsVectInst :: LHsSigType Name -> TcM (Class, [Type])+tcHsVectInst ty+ | Just (L _ cls_name, tys) <- hsTyGetAppHead_maybe (hsSigType ty)+ -- Ignoring the binders looks pretty dodgy to me+ = do { (cls, cls_kind) <- tcClass cls_name+ ; (applied_class, _res_kind)+ <- tcInferApps typeLevelMode cls_name (mkClassPred cls []) cls_kind tys+ ; case tcSplitTyConApp_maybe applied_class of+ Just (_tc, args) -> ASSERT( _tc == classTyCon cls )+ return (cls, args)+ _ -> failWithTc (text "Too many arguments passed to" <+> ppr cls_name) }+ | otherwise+ = failWithTc $ text "Malformed instance type"++----------------------------------------------+-- | Type-check a visible type application+tcHsTypeApp :: LHsWcType Name -> Kind -> TcM Type+tcHsTypeApp wc_ty kind+ | HsWC { hswc_wcs = sig_wcs, hswc_body = hs_ty } <- wc_ty+ = do { ty <- tcWildCardBindersX newWildTyVar sig_wcs $ \ _ ->+ tcCheckLHsType hs_ty kind+ ; ty <- zonkTcType ty+ ; checkValidType TypeAppCtxt ty+ ; return ty }+ -- NB: we don't call emitWildcardHoleConstraints here, because+ -- we want any holes in visible type applications to be used+ -- without fuss. No errors, warnings, extensions, etc.++{-+************************************************************************+* *+ The main kind checker: no validity checks here+* *+************************************************************************++ First a couple of simple wrappers for kcHsType+-}++---------------------------+tcHsOpenType, tcHsLiftedType,+ tcHsOpenTypeNC, tcHsLiftedTypeNC :: LHsType Name -> TcM TcType+-- Used for type signatures+-- Do not do validity checking+tcHsOpenType ty = addTypeCtxt ty $ tcHsOpenTypeNC ty+tcHsLiftedType ty = addTypeCtxt ty $ tcHsLiftedTypeNC ty++tcHsOpenTypeNC ty = do { ek <- newOpenTypeKind+ ; tc_lhs_type typeLevelMode ty ek }+tcHsLiftedTypeNC ty = tc_lhs_type typeLevelMode ty liftedTypeKind++-- Like tcHsType, but takes an expected kind+tcCheckLHsType :: LHsType Name -> Kind -> TcM Type+tcCheckLHsType hs_ty exp_kind+ = addTypeCtxt hs_ty $+ tc_lhs_type typeLevelMode hs_ty exp_kind++tcLHsType :: LHsType Name -> TcM (TcType, TcKind)+-- Called from outside: set the context+tcLHsType ty = addTypeCtxt ty (tc_infer_lhs_type typeLevelMode ty)++---------------------------+-- | Should we generalise the kind of this type signature?+-- We *should* generalise if the type is closed+-- or if NoMonoLocalBinds is set. Otherwise, nope.+-- See Note [Kind generalisation plan]+decideKindGeneralisationPlan :: LHsSigType Name -> TcM Bool+decideKindGeneralisationPlan sig_ty@(HsIB { hsib_closed = closed })+ = do { mono_locals <- xoptM LangExt.MonoLocalBinds+ ; let should_gen = not mono_locals || closed+ ; traceTc "decideKindGeneralisationPlan"+ (ppr sig_ty $$ text "should gen?" <+> ppr should_gen)+ ; return should_gen }++{- Note [Kind generalisation plan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When should we do kind-generalisation for user-written type signature?+Answer: we use the same rule as for value bindings:++ * We always kind-generalise if the type signature is closed+ * Additionally, we attempt to generalise if we have NoMonoLocalBinds++Trac #13337 shows the problem if we kind-generalise an open type (i.e.+one that mentions in-scope tpe variable+ foo :: forall k (a :: k) proxy. (Typeable k, Typeable a)+ => proxy a -> String+ foo _ = case eqT :: Maybe (k :~: Type) of+ Nothing -> ...+ Just Refl -> case eqT :: Maybe (a :~: Int) of ...++In the expression type sig on the last line, we have (a :: k)+but (Int :: Type). Since (:~:) is kind-homogeneous, this requires+k ~ *, which is true in the Refl branch of the outer case.++That equality will be solved if we allow it to float out to the+implication constraint for the Refl match, bnot not if we aggressively+attempt to solve all equalities the moment they occur; that is, when+checking (Maybe (a :~: Int)). (NB: solveEqualities fails unless it+solves all the kind equalities, which is the right thing at top level.)++So here the right thing is simply not to do kind generalisation!++************************************************************************+* *+ Type-checking modes+* *+************************************************************************++The kind-checker is parameterised by a TcTyMode, which contains some+information about where we're checking a type.++The renamer issues errors about what it can. All errors issued here must+concern things that the renamer can't handle.++-}++-- | Info about the context in which we're checking a type. Currently,+-- differentiates only between types and kinds, but this will likely+-- grow, at least to include the distinction between patterns and+-- not-patterns.+newtype TcTyMode+ = TcTyMode { mode_level :: TypeOrKind -- True <=> type, False <=> kind+ }++typeLevelMode :: TcTyMode+typeLevelMode = TcTyMode { mode_level = TypeLevel }++kindLevelMode :: TcTyMode+kindLevelMode = TcTyMode { mode_level = KindLevel }++-- switch to kind level+kindLevel :: TcTyMode -> TcTyMode+kindLevel mode = mode { mode_level = KindLevel }++instance Outputable TcTyMode where+ ppr = ppr . mode_level++{-+Note [Bidirectional type checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In expressions, whenever we see a polymorphic identifier, say `id`, we are+free to instantiate it with metavariables, knowing that we can always+re-generalize with type-lambdas when necessary. For example:++ rank2 :: (forall a. a -> a) -> ()+ x = rank2 id++When checking the body of `x`, we can instantiate `id` with a metavariable.+Then, when we're checking the application of `rank2`, we notice that we really+need a polymorphic `id`, and then re-generalize over the unconstrained+metavariable.++In types, however, we're not so lucky, because *we cannot re-generalize*!+There is no lambda. So, we must be careful only to instantiate at the last+possible moment, when we're sure we're never going to want the lost polymorphism+again. This is done in calls to tcInstBinders and tcInstBindersX.++To implement this behavior, we use bidirectional type checking, where we+explicitly think about whether we know the kind of the type we're checking+or not. Note that there is a difference between not knowing a kind and+knowing a metavariable kind: the metavariables are TauTvs, and cannot become+forall-quantified kinds. Previously (before dependent types), there were+no higher-rank kinds, and so we could instantiate early and be sure that+no types would have polymorphic kinds, and so we could always assume that+the kind of a type was a fresh metavariable. Not so anymore, thus the+need for two algorithms.++For HsType forms that can never be kind-polymorphic, we implement only the+"down" direction, where we safely assume a metavariable kind. For HsType forms+that *can* be kind-polymorphic, we implement just the "up" (functions with+"infer" in their name) version, as we gain nothing by also implementing the+"down" version.++Note [Future-proofing the type checker]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As discussed in Note [Bidirectional type checking], each HsType form is+handled in *either* tc_infer_hs_type *or* tc_hs_type. These functions+are mutually recursive, so that either one can work for any type former.+But, we want to make sure that our pattern-matches are complete. So,+we have a bunch of repetitive code just so that we get warnings if we're+missing any patterns.+-}++------------------------------------------+-- | Check and desugar a type, returning the core type and its+-- possibly-polymorphic kind. Much like 'tcInferRho' at the expression+-- level.+tc_infer_lhs_type :: TcTyMode -> LHsType Name -> TcM (TcType, TcKind)+tc_infer_lhs_type mode (L span ty)+ = setSrcSpan span $+ do { (ty', kind) <- tc_infer_hs_type mode ty+ ; return (ty', kind) }++-- | Infer the kind of a type and desugar. This is the "up" type-checker,+-- as described in Note [Bidirectional type checking]+tc_infer_hs_type :: TcTyMode -> HsType Name -> TcM (TcType, TcKind)+tc_infer_hs_type mode (HsTyVar _ (L _ tv)) = tcTyVar mode tv+tc_infer_hs_type mode (HsAppTy ty1 ty2)+ = do { let (fun_ty, arg_tys) = splitHsAppTys ty1 [ty2]+ ; (fun_ty', fun_kind) <- tc_infer_lhs_type mode fun_ty+ ; fun_kind' <- zonkTcType fun_kind+ ; tcInferApps mode fun_ty fun_ty' fun_kind' arg_tys }+tc_infer_hs_type mode (HsParTy t) = tc_infer_lhs_type mode t+tc_infer_hs_type mode (HsOpTy lhs (L _ op) rhs)+ | not (op `hasKey` funTyConKey)+ = do { (op', op_kind) <- tcTyVar mode op+ ; op_kind' <- zonkTcType op_kind+ ; tcInferApps mode op op' op_kind' [lhs, rhs] }+tc_infer_hs_type mode (HsKindSig ty sig)+ = do { sig' <- tc_lhs_kind (kindLevel mode) sig+ ; ty' <- tc_lhs_type mode ty sig'+ ; return (ty', sig') }+-- HsSpliced is an annotation produced by 'RnSplice.rnSpliceType' to communicate+-- the splice location to the typechecker. Here we skip over it in order to have+-- the same kind inferred for a given expression whether it was produced from+-- splices or not.+--+-- See Note [Delaying modFinalizers in untyped splices].+tc_infer_hs_type mode (HsSpliceTy (HsSpliced _ (HsSplicedTy ty)) _)+ = tc_infer_hs_type mode ty+tc_infer_hs_type mode (HsDocTy ty _) = tc_infer_lhs_type mode ty+tc_infer_hs_type _ (HsCoreTy ty) = return (ty, typeKind ty)+tc_infer_hs_type mode other_ty+ = do { kv <- newMetaKindVar+ ; ty' <- tc_hs_type mode other_ty kv+ ; return (ty', kv) }++------------------------------------------+tc_lhs_type :: TcTyMode -> LHsType Name -> TcKind -> TcM TcType+tc_lhs_type mode (L span ty) exp_kind+ = setSrcSpan span $+ do { ty' <- tc_hs_type mode ty exp_kind+ ; return ty' }++------------------------------------------+tc_fun_type :: TcTyMode -> LHsType Name -> LHsType Name -> TcKind -> TcM TcType+tc_fun_type mode ty1 ty2 exp_kind = case mode_level mode of+ TypeLevel ->+ do { arg_k <- newOpenTypeKind+ ; res_k <- newOpenTypeKind+ ; ty1' <- tc_lhs_type mode ty1 arg_k+ ; ty2' <- tc_lhs_type mode ty2 res_k+ ; checkExpectedKind (mkFunTy ty1' ty2') liftedTypeKind exp_kind }+ KindLevel -> -- no representation polymorphism in kinds. yet.+ do { ty1' <- tc_lhs_type mode ty1 liftedTypeKind+ ; ty2' <- tc_lhs_type mode ty2 liftedTypeKind+ ; checkExpectedKind (mkFunTy ty1' ty2') liftedTypeKind exp_kind }++------------------------------------------+-- See also Note [Bidirectional type checking]+tc_hs_type :: TcTyMode -> HsType Name -> TcKind -> TcM TcType+tc_hs_type mode (HsParTy ty) exp_kind = tc_lhs_type mode ty exp_kind+tc_hs_type mode (HsDocTy ty _) exp_kind = tc_lhs_type mode ty exp_kind+tc_hs_type _ ty@(HsBangTy {}) _+ -- While top-level bangs at this point are eliminated (eg !(Maybe Int)),+ -- other kinds of bangs are not (eg ((!Maybe) Int)). These kinds of+ -- bangs are invalid, so fail. (#7210)+ = failWithTc (text "Unexpected strictness annotation:" <+> ppr ty)+tc_hs_type _ ty@(HsRecTy _) _+ -- Record types (which only show up temporarily in constructor+ -- signatures) should have been removed by now+ = failWithTc (text "Record syntax is illegal here:" <+> ppr ty)++-- HsSpliced is an annotation produced by 'RnSplice.rnSpliceType'.+-- Here we get rid of it and add the finalizers to the global environment+-- while capturing the local environment.+--+-- See Note [Delaying modFinalizers in untyped splices].+tc_hs_type mode (HsSpliceTy (HsSpliced mod_finalizers (HsSplicedTy ty))+ _+ )+ exp_kind+ = do addModFinalizersWithLclEnv mod_finalizers+ tc_hs_type mode ty exp_kind++-- This should never happen; type splices are expanded by the renamer+tc_hs_type _ ty@(HsSpliceTy {}) _exp_kind+ = failWithTc (text "Unexpected type splice:" <+> ppr ty)++---------- Functions and applications+tc_hs_type mode (HsFunTy ty1 ty2) exp_kind+ = tc_fun_type mode ty1 ty2 exp_kind++tc_hs_type mode (HsOpTy ty1 (L _ op) ty2) exp_kind+ | op `hasKey` funTyConKey+ = tc_fun_type mode ty1 ty2 exp_kind++--------- Foralls+tc_hs_type mode (HsForAllTy { hst_bndrs = hs_tvs, hst_body = ty }) exp_kind+ = fmap fst $+ tcExplicitTKBndrs hs_tvs $ \ tvs' ->+ -- Do not kind-generalise here! See Note [Kind generalisation]+ -- Why exp_kind? See Note [Body kind of HsForAllTy]+ do { ty' <- tc_lhs_type mode ty exp_kind+ ; let bound_vars = allBoundVariables ty'+ bndrs = mkTyVarBinders Specified tvs'+ ; return (mkForAllTys bndrs ty', bound_vars) }++tc_hs_type mode (HsQualTy { hst_ctxt = ctxt, hst_body = ty }) exp_kind+ | null (unLoc ctxt)+ = tc_lhs_type mode ty exp_kind++ | otherwise+ = do { ctxt' <- tc_hs_context mode ctxt++ -- See Note [Body kind of a HsQualTy]+ ; ty' <- if isConstraintKind exp_kind+ then tc_lhs_type mode ty constraintKind+ else do { ek <- newOpenTypeKind+ -- The body kind (result of the function)+ -- can be * or #, hence newOpenTypeKind+ ; ty <- tc_lhs_type mode ty ek+ ; checkExpectedKind ty liftedTypeKind exp_kind }++ ; return (mkPhiTy ctxt' ty') }++--------- Lists, arrays, and tuples+tc_hs_type mode (HsListTy elt_ty) exp_kind+ = do { tau_ty <- tc_lhs_type mode elt_ty liftedTypeKind+ ; checkWiredInTyCon listTyCon+ ; checkExpectedKind (mkListTy tau_ty) liftedTypeKind exp_kind }++tc_hs_type mode (HsPArrTy elt_ty) exp_kind+ = do { MASSERT( isTypeLevel (mode_level mode) )+ ; tau_ty <- tc_lhs_type mode elt_ty liftedTypeKind+ ; checkWiredInTyCon parrTyCon+ ; checkExpectedKind (mkPArrTy tau_ty) liftedTypeKind exp_kind }++-- See Note [Distinguishing tuple kinds] in HsTypes+-- See Note [Inferring tuple kinds]+tc_hs_type mode (HsTupleTy HsBoxedOrConstraintTuple hs_tys) exp_kind+ -- (NB: not zonking before looking at exp_k, to avoid left-right bias)+ | Just tup_sort <- tupKindSort_maybe exp_kind+ = traceTc "tc_hs_type tuple" (ppr hs_tys) >>+ tc_tuple mode tup_sort hs_tys exp_kind+ | otherwise+ = do { traceTc "tc_hs_type tuple 2" (ppr hs_tys)+ ; (tys, kinds) <- mapAndUnzipM (tc_infer_lhs_type mode) hs_tys+ ; kinds <- mapM zonkTcType kinds+ -- Infer each arg type separately, because errors can be+ -- confusing if we give them a shared kind. Eg Trac #7410+ -- (Either Int, Int), we do not want to get an error saying+ -- "the second argument of a tuple should have kind *->*"++ ; let (arg_kind, tup_sort)+ = case [ (k,s) | k <- kinds+ , Just s <- [tupKindSort_maybe k] ] of+ ((k,s) : _) -> (k,s)+ [] -> (liftedTypeKind, BoxedTuple)+ -- In the [] case, it's not clear what the kind is, so guess *++ ; tys' <- sequence [ setSrcSpan loc $+ checkExpectedKind ty kind arg_kind+ | ((L loc _),ty,kind) <- zip3 hs_tys tys kinds ]++ ; finish_tuple tup_sort tys' (map (const arg_kind) tys') exp_kind }+++tc_hs_type mode (HsTupleTy hs_tup_sort tys) exp_kind+ = tc_tuple mode tup_sort tys exp_kind+ where+ tup_sort = case hs_tup_sort of -- Fourth case dealt with above+ HsUnboxedTuple -> UnboxedTuple+ HsBoxedTuple -> BoxedTuple+ HsConstraintTuple -> ConstraintTuple+ _ -> panic "tc_hs_type HsTupleTy"++tc_hs_type mode (HsSumTy hs_tys) exp_kind+ = do { let arity = length hs_tys+ ; arg_kinds <- mapM (\_ -> newOpenTypeKind) hs_tys+ ; tau_tys <- zipWithM (tc_lhs_type mode) hs_tys arg_kinds+ ; let arg_reps = map (getRuntimeRepFromKind "tc_hs_type HsSumTy") arg_kinds+ arg_tys = arg_reps ++ tau_tys+ ; checkExpectedKind (mkTyConApp (sumTyCon arity) arg_tys)+ (unboxedSumKind arg_reps)+ exp_kind+ }++--------- Promoted lists and tuples+tc_hs_type mode (HsExplicitListTy _ _k tys) exp_kind+ = do { tks <- mapM (tc_infer_lhs_type mode) tys+ ; (taus', kind) <- unifyKinds tks+ ; let ty = (foldr (mk_cons kind) (mk_nil kind) taus')+ ; checkExpectedKind ty (mkListTy kind) exp_kind }+ where+ mk_cons k a b = mkTyConApp (promoteDataCon consDataCon) [k, a, b]+ mk_nil k = mkTyConApp (promoteDataCon nilDataCon) [k]++tc_hs_type mode (HsExplicitTupleTy _ tys) exp_kind+ -- using newMetaKindVar means that we force instantiations of any polykinded+ -- types. At first, I just used tc_infer_lhs_type, but that led to #11255.+ = do { ks <- replicateM arity newMetaKindVar+ ; taus <- zipWithM (tc_lhs_type mode) tys ks+ ; let kind_con = tupleTyCon Boxed arity+ ty_con = promotedTupleDataCon Boxed arity+ tup_k = mkTyConApp kind_con ks+ ; checkExpectedKind (mkTyConApp ty_con (ks ++ taus)) tup_k exp_kind }+ where+ arity = length tys++--------- Constraint types+tc_hs_type mode (HsIParamTy (L _ n) ty) exp_kind+ = do { MASSERT( isTypeLevel (mode_level mode) )+ ; ty' <- tc_lhs_type mode ty liftedTypeKind+ ; let n' = mkStrLitTy $ hsIPNameFS n+ ; ipClass <- tcLookupClass ipClassName+ ; checkExpectedKind (mkClassPred ipClass [n',ty'])+ constraintKind exp_kind }++tc_hs_type mode (HsEqTy ty1 ty2) exp_kind+ = do { (ty1', kind1) <- tc_infer_lhs_type mode ty1+ ; (ty2', kind2) <- tc_infer_lhs_type mode ty2+ ; ty2'' <- checkExpectedKind ty2' kind2 kind1+ ; eq_tc <- tcLookupTyCon eqTyConName+ ; let ty' = mkNakedTyConApp eq_tc [kind1, ty1', ty2'']+ ; checkExpectedKind ty' constraintKind exp_kind }++--------- Literals+tc_hs_type _ (HsTyLit (HsNumTy _ n)) exp_kind+ = do { checkWiredInTyCon typeNatKindCon+ ; checkExpectedKind (mkNumLitTy n) typeNatKind exp_kind }++tc_hs_type _ (HsTyLit (HsStrTy _ s)) exp_kind+ = do { checkWiredInTyCon typeSymbolKindCon+ ; checkExpectedKind (mkStrLitTy s) typeSymbolKind exp_kind }++--------- Potentially kind-polymorphic types: call the "up" checker+-- See Note [Future-proofing the type checker]+tc_hs_type mode ty@(HsTyVar {}) ek = tc_infer_hs_type_ek mode ty ek+tc_hs_type mode ty@(HsAppTy {}) ek = tc_infer_hs_type_ek mode ty ek+tc_hs_type mode ty@(HsOpTy {}) ek = tc_infer_hs_type_ek mode ty ek+tc_hs_type mode ty@(HsKindSig {}) ek = tc_infer_hs_type_ek mode ty ek+tc_hs_type mode ty@(HsCoreTy {}) ek = tc_infer_hs_type_ek mode ty ek++tc_hs_type _ (HsWildCardTy wc) exp_kind+ = do { wc_tv <- tcWildCardOcc wc exp_kind+ ; return (mkTyVarTy wc_tv) }++-- disposed of by renamer+tc_hs_type _ ty@(HsAppsTy {}) _+ = pprPanic "tc_hs_tyep HsAppsTy" (ppr ty)++tcWildCardOcc :: HsWildCardInfo Name -> Kind -> TcM TcTyVar+tcWildCardOcc wc_info exp_kind+ = do { wc_tv <- tcLookupTyVar (wildCardName wc_info)+ -- The wildcard's kind should be an un-filled-in meta tyvar+ ; let Just wc_kind_var = tcGetTyVar_maybe (tyVarKind wc_tv)+ ; writeMetaTyVar wc_kind_var exp_kind+ ; return wc_tv }++---------------------------+-- | Call 'tc_infer_hs_type' and check its result against an expected kind.+tc_infer_hs_type_ek :: TcTyMode -> HsType Name -> TcKind -> TcM TcType+tc_infer_hs_type_ek mode ty ek+ = do { (ty', k) <- tc_infer_hs_type mode ty+ ; checkExpectedKind ty' k ek }++---------------------------+tupKindSort_maybe :: TcKind -> Maybe TupleSort+tupKindSort_maybe k+ | Just (k', _) <- splitCastTy_maybe k = tupKindSort_maybe k'+ | Just k' <- tcView k = tupKindSort_maybe k'+ | isConstraintKind k = Just ConstraintTuple+ | isLiftedTypeKind k = Just BoxedTuple+ | otherwise = Nothing++tc_tuple :: TcTyMode -> TupleSort -> [LHsType Name] -> TcKind -> TcM TcType+tc_tuple mode tup_sort tys exp_kind+ = do { arg_kinds <- case tup_sort of+ BoxedTuple -> return (nOfThem arity liftedTypeKind)+ UnboxedTuple -> mapM (\_ -> newOpenTypeKind) tys+ ConstraintTuple -> return (nOfThem arity constraintKind)+ ; tau_tys <- zipWithM (tc_lhs_type mode) tys arg_kinds+ ; finish_tuple tup_sort tau_tys arg_kinds exp_kind }+ where+ arity = length tys++finish_tuple :: TupleSort+ -> [TcType] -- ^ argument types+ -> [TcKind] -- ^ of these kinds+ -> TcKind -- ^ expected kind of the whole tuple+ -> TcM TcType+finish_tuple tup_sort tau_tys tau_kinds exp_kind+ = do { traceTc "finish_tuple" (ppr res_kind $$ ppr tau_kinds $$ ppr exp_kind)+ ; let arg_tys = case tup_sort of+ -- See also Note [Unboxed tuple RuntimeRep vars] in TyCon+ UnboxedTuple -> tau_reps ++ tau_tys+ BoxedTuple -> tau_tys+ ConstraintTuple -> tau_tys+ ; tycon <- case tup_sort of+ ConstraintTuple+ | arity > mAX_CTUPLE_SIZE+ -> failWith (bigConstraintTuple arity)+ | otherwise -> tcLookupTyCon (cTupleTyConName arity)+ BoxedTuple -> do { let tc = tupleTyCon Boxed arity+ ; checkWiredInTyCon tc+ ; return tc }+ UnboxedTuple -> return (tupleTyCon Unboxed arity)+ ; checkExpectedKind (mkTyConApp tycon arg_tys) res_kind exp_kind }+ where+ arity = length tau_tys+ tau_reps = map (getRuntimeRepFromKind "finish_tuple") tau_kinds+ res_kind = case tup_sort of+ UnboxedTuple -> unboxedTupleKind tau_reps+ BoxedTuple -> liftedTypeKind+ ConstraintTuple -> constraintKind++bigConstraintTuple :: Arity -> MsgDoc+bigConstraintTuple arity+ = hang (text "Constraint tuple arity too large:" <+> int arity+ <+> parens (text "max arity =" <+> int mAX_CTUPLE_SIZE))+ 2 (text "Instead, use a nested tuple")++---------------------------+-- | Apply a type of a given kind to a list of arguments. This instantiates+-- invisible parameters as necessary. However, it does *not* necessarily+-- apply all the arguments, if the kind runs out of binders.+-- Never calls 'matchExpectedFunKind'; when the kind runs out of binders,+-- this stops processing.+-- This takes an optional @VarEnv Kind@ which maps kind variables to kinds.+-- These kinds should be used to instantiate invisible kind variables;+-- they come from an enclosing class for an associated type/data family.+-- This version will instantiate all invisible arguments left over after+-- the visible ones. Used only when typechecking type/data family patterns+-- (where we need to instantiate all remaining invisible parameters; for+-- example, consider @type family F :: k where F = Int; F = Maybe@. We+-- need to instantiate the @k@.)+tcInferArgs :: Outputable fun+ => fun -- ^ the function+ -> [TyConBinder] -- ^ function kind's binders+ -> Maybe (VarEnv Kind) -- ^ possibly, kind info (see above)+ -> [LHsType Name] -- ^ args+ -> TcM (TCvSubst, [TyBinder], [TcType], [LHsType Name], Int)+ -- ^ (instantiating subst, un-insted leftover binders,+ -- typechecked args, untypechecked args, n)+tcInferArgs fun tc_binders mb_kind_info args+ = do { let binders = tyConBindersTyBinders tc_binders -- UGH!+ ; (subst, leftover_binders, args', leftovers, n)+ <- tc_infer_args typeLevelMode fun binders mb_kind_info args 1+ -- now, we need to instantiate any remaining invisible arguments+ ; let (invis_bndrs, other_binders) = break isVisibleBinder leftover_binders+ ; (subst', invis_args)+ <- tcInstBindersX subst mb_kind_info invis_bndrs+ ; return ( subst'+ , other_binders+ , args' `chkAppend` invis_args+ , leftovers, n ) }++-- | See comments for 'tcInferArgs'. But this version does not instantiate+-- any remaining invisible arguments.+tc_infer_args :: Outputable fun+ => TcTyMode+ -> fun -- ^ the function+ -> [TyBinder] -- ^ function kind's binders (zonked)+ -> Maybe (VarEnv Kind) -- ^ possibly, kind info (see above)+ -> [LHsType Name] -- ^ args+ -> Int -- ^ number to start arg counter at+ -> TcM (TCvSubst, [TyBinder], [TcType], [LHsType Name], Int)+tc_infer_args mode orig_ty binders mb_kind_info orig_args n0+ = go emptyTCvSubst binders orig_args n0 []+ where+ go subst binders [] n acc+ = return ( subst, binders, reverse acc, [], n )+ -- when we call this when checking type family patterns, we really+ -- do want to instantiate all invisible arguments. During other+ -- typechecking, we don't.++ go subst (binder:binders) all_args@(arg:args) n acc+ | isInvisibleBinder binder+ = do { traceTc "tc_infer_args (invis)" (ppr binder)+ ; (subst', arg') <- tcInstBinderX mb_kind_info subst binder+ ; go subst' binders all_args n (arg' : acc) }++ | otherwise+ = do { traceTc "tc_infer_args (vis)" (ppr binder $$ ppr arg)+ ; arg' <- addErrCtxt (funAppCtxt orig_ty arg n) $+ tc_lhs_type mode arg (substTyUnchecked subst $+ tyBinderType binder)+ ; let subst' = extendTvSubstBinder subst binder arg'+ ; go subst' binders args (n+1) (arg' : acc) }++ go subst [] all_args n acc+ = return (subst, [], reverse acc, all_args, n)++-- | Applies a type to a list of arguments.+-- Always consumes all the arguments, using 'matchExpectedFunKind' as+-- necessary. If you wish to apply a type to a list of HsTypes, this is+-- your function.+-- Used for type-checking types only.+tcInferApps :: Outputable fun+ => TcTyMode+ -> fun -- ^ Function (for printing only)+ -> TcType -- ^ Function (could be knot-tied)+ -> TcKind -- ^ Function kind (zonked)+ -> [LHsType Name] -- ^ Args+ -> TcM (TcType, TcKind) -- ^ (f args, result kind)+tcInferApps mode orig_ty ty ki args = go ty ki args 1+ where+ go fun fun_kind [] _ = return (fun, fun_kind)+ go fun fun_kind args n+ | let (binders, res_kind) = splitPiTys fun_kind+ , not (null binders)+ = do { (subst, leftover_binders, args', leftover_args, n')+ <- tc_infer_args mode orig_ty binders Nothing args n+ ; let fun_kind' = substTyUnchecked subst $+ mkPiTys leftover_binders res_kind+ ; go (mkNakedAppTys fun args') fun_kind' leftover_args n' }++ go fun fun_kind all_args@(arg:args) n+ = do { (co, arg_k, res_k) <- matchExpectedFunKind (length all_args)+ fun fun_kind+ ; arg' <- addErrCtxt (funAppCtxt orig_ty arg n) $+ tc_lhs_type mode arg arg_k+ ; go (mkNakedAppTy (fun `mkNakedCastTy` co) arg')+ res_k args (n+1) }++--------------------------+checkExpectedKind :: TcType -- the type whose kind we're checking+ -> TcKind -- the known kind of that type, k+ -> TcKind -- the expected kind, exp_kind+ -> TcM TcType -- a possibly-inst'ed, casted type :: exp_kind+-- Instantiate a kind (if necessary) and then call unifyType+-- (checkExpectedKind ty act_kind exp_kind)+-- checks that the actual kind act_kind is compatible+-- with the expected kind exp_kind+checkExpectedKind ty act_kind exp_kind+ = do { (ty', act_kind') <- instantiate ty act_kind exp_kind+ ; let origin = TypeEqOrigin { uo_actual = act_kind'+ , uo_expected = exp_kind+ , uo_thing = Just $ mkTypeErrorThing ty'+ }+ ; co_k <- uType origin KindLevel act_kind' exp_kind+ ; traceTc "checkExpectedKind" (vcat [ ppr act_kind+ , ppr exp_kind+ , ppr co_k ])+ ; let result_ty = ty' `mkNakedCastTy` co_k+ ; return result_ty }+ where+ -- we need to make sure that both kinds have the same number of implicit+ -- foralls out front. If the actual kind has more, instantiate accordingly.+ -- Otherwise, just pass the type & kind through -- the errors are caught+ -- in unifyType.+ instantiate :: TcType -- the type+ -> TcKind -- of this kind+ -> TcKind -- but expected to be of this one+ -> TcM ( TcType -- the inst'ed type+ , TcKind ) -- its new kind+ instantiate ty act_ki exp_ki+ = let (exp_bndrs, _) = splitPiTysInvisible exp_ki in+ instantiateTyN (length exp_bndrs) ty act_ki++-- | Instantiate a type to have at most @n@ invisible arguments.+instantiateTyN :: Int -- ^ @n@+ -> TcType -- ^ the type+ -> TcKind -- ^ its kind+ -> TcM (TcType, TcKind) -- ^ The inst'ed type with kind+instantiateTyN n ty ki+ = let (bndrs, inner_ki) = splitPiTysInvisible ki+ num_to_inst = length bndrs - n+ -- NB: splitAt is forgiving with invalid numbers+ (inst_bndrs, leftover_bndrs) = splitAt num_to_inst bndrs+ empty_subst = mkEmptyTCvSubst (mkInScopeSet (tyCoVarsOfType ki))+ in+ if num_to_inst <= 0 then return (ty, ki) else+ do { (subst, inst_args) <- tcInstBindersX empty_subst Nothing inst_bndrs+ ; let rebuilt_ki = mkPiTys leftover_bndrs inner_ki+ ki' = substTy subst rebuilt_ki+ ; traceTc "instantiateTyN" (vcat [ ppr ty <+> dcolon <+> ppr ki+ , ppr subst+ , ppr rebuilt_ki+ , ppr ki' ])+ ; return (mkNakedAppTys ty inst_args, ki') }++---------------------------+tcHsContext :: LHsContext Name -> TcM [PredType]+tcHsContext = tc_hs_context typeLevelMode++tcLHsPredType :: LHsType Name -> TcM PredType+tcLHsPredType = tc_lhs_pred typeLevelMode++tc_hs_context :: TcTyMode -> LHsContext Name -> TcM [PredType]+tc_hs_context mode ctxt = mapM (tc_lhs_pred mode) (unLoc ctxt)++tc_lhs_pred :: TcTyMode -> LHsType Name -> TcM PredType+tc_lhs_pred mode pred = tc_lhs_type mode pred constraintKind++---------------------------+tcTyVar :: TcTyMode -> Name -> TcM (TcType, TcKind)+-- See Note [Type checking recursive type and class declarations]+-- in TcTyClsDecls+tcTyVar mode name -- Could be a tyvar, a tycon, or a datacon+ = do { traceTc "lk1" (ppr name)+ ; thing <- tcLookup name+ ; case thing of+ ATyVar _ tv -> return (mkTyVarTy tv, tyVarKind tv)++ ATcTyCon tc_tc -> do { -- See Note [GADT kind self-reference]+ unless+ (isTypeLevel (mode_level mode))+ (promotionErr name TyConPE)+ ; check_tc tc_tc+ ; tc <- get_loopy_tc name tc_tc+ ; handle_tyfams tc tc_tc }+ -- mkNakedTyConApp: see Note [Type-checking inside the knot]+ -- NB: we really should check if we're at the kind level+ -- and if the tycon is promotable if -XNoTypeInType is set.+ -- But this is a terribly large amount of work! Not worth it.++ AGlobal (ATyCon tc)+ -> do { check_tc tc+ ; handle_tyfams tc tc }++ AGlobal (AConLike (RealDataCon dc))+ -> do { data_kinds <- xoptM LangExt.DataKinds+ ; unless (data_kinds || specialPromotedDc dc) $+ promotionErr name NoDataKindsDC+ ; type_in_type <- xoptM LangExt.TypeInType+ ; unless ( type_in_type ||+ ( isTypeLevel (mode_level mode) &&+ isLegacyPromotableDataCon dc ) ||+ ( isKindLevel (mode_level mode) &&+ specialPromotedDc dc ) ) $+ promotionErr name NoTypeInTypeDC+ ; let tc = promoteDataCon dc+ ; return (mkNakedTyConApp tc [], tyConKind tc) }++ APromotionErr err -> promotionErr name err++ _ -> wrongThingErr "type" thing name }+ where+ check_tc :: TyCon -> TcM ()+ check_tc tc = do { type_in_type <- xoptM LangExt.TypeInType+ ; data_kinds <- xoptM LangExt.DataKinds+ ; unless (isTypeLevel (mode_level mode) ||+ data_kinds ||+ isKindTyCon tc) $+ promotionErr name NoDataKindsTC+ ; unless (isTypeLevel (mode_level mode) ||+ type_in_type ||+ isLegacyPromotableTyCon tc) $+ promotionErr name NoTypeInTypeTC }++ -- if we are type-checking a type family tycon, we must instantiate+ -- any invisible arguments right away. Otherwise, we get #11246+ handle_tyfams :: TyCon -- the tycon to instantiate (might be loopy)+ -> TyCon -- a non-loopy version of the tycon+ -> TcM (TcType, TcKind)+ handle_tyfams tc tc_tc+ | mightBeUnsaturatedTyCon tc_tc+ = do { traceTc "tcTyVar2a" (ppr tc_tc $$ ppr tc_kind)+ ; return (ty, tc_kind) }++ | otherwise+ = do { (tc_ty, kind) <- instantiateTyN 0 ty tc_kind+ -- tc and tc_ty must not be traced here, because that would+ -- force the evaluation of a potentially knot-tied variable (tc),+ -- and the typechecker would hang, as per #11708+ ; traceTc "tcTyVar2b" (vcat [ ppr tc_tc <+> dcolon <+> ppr tc_kind+ , ppr kind ])+ ; return (tc_ty, kind) }+ where+ ty = mkNakedTyConApp tc []+ tc_kind = tyConKind tc_tc++ get_loopy_tc :: Name -> TyCon -> TcM TyCon+ -- Return the knot-tied global TyCon if there is one+ -- Otherwise the local TcTyCon; we must be doing kind checking+ -- but we still want to return a TyCon of some sort to use in+ -- error messages+ get_loopy_tc name tc_tc+ = do { env <- getGblEnv+ ; case lookupNameEnv (tcg_type_env env) name of+ Just (ATyCon tc) -> return tc+ _ -> do { traceTc "lk1 (loopy)" (ppr name)+ ; return tc_tc } }++tcClass :: Name -> TcM (Class, TcKind)+tcClass cls -- Must be a class+ = do { thing <- tcLookup cls+ ; case thing of+ ATcTyCon tc -> return (aThingErr "tcClass" cls, tyConKind tc)+ AGlobal (ATyCon tc)+ | Just cls <- tyConClass_maybe tc+ -> return (cls, tyConKind tc)+ _ -> wrongThingErr "class" thing cls }+++aThingErr :: String -> Name -> b+-- The type checker for types is sometimes called simply to+-- do *kind* checking; and in that case it ignores the type+-- returned. Which is a good thing since it may not be available yet!+aThingErr str x = pprPanic "AThing evaluated unexpectedly" (text str <+> ppr x)++{-+Note [Type-checking inside the knot]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we are checking the argument types of a data constructor. We+must zonk the types before making the DataCon, because once built we+can't change it. So we must traverse the type.++BUT the parent TyCon is knot-tied, so we can't look at it yet.++So we must be careful not to use "smart constructors" for types that+look at the TyCon or Class involved.++ * Hence the use of mkNakedXXX functions. These do *not* enforce+ the invariants (for example that we use (FunTy s t) rather+ than (TyConApp (->) [s,t])).++ * The zonking functions establish invariants (even zonkTcType, a change from+ previous behaviour). So we must never inspect the result of a+ zonk that might mention a knot-tied TyCon. This is generally OK+ because we zonk *kinds* while kind-checking types. And the TyCons+ in kinds shouldn't be knot-tied, because they come from a previous+ mutually recursive group.++ * TcHsSyn.zonkTcTypeToType also can safely check/establish+ invariants.++This is horribly delicate. I hate it. A good example of how+delicate it is can be seen in Trac #7903.++Note [GADT kind self-reference]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++A promoted type cannot be used in the body of that type's declaration.+Trac #11554 shows this example, which made GHC loop:++ import Data.Kind+ data P (x :: k) = Q+ data A :: Type where+ B :: forall (a :: A). P a -> A++In order to check the constructor B, we need to have the promoted type A, but in+order to get that promoted type, B must first be checked. To prevent looping, a+TyConPE promotion error is given when tcTyVar checks an ATcTyCon in kind mode.+Any ATcTyCon is a TyCon being defined in the current recursive group (see data+type decl for TcTyThing), and all such TyCons are illegal in kinds.++Trac #11962 proposes checking the head of a data declaration separately from+its constructors. This would allow the example above to pass.++Note [Body kind of a HsForAllTy]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The body of a forall is usually a type, but in principle+there's no reason to prohibit *unlifted* types.+In fact, GHC can itself construct a function with an+unboxed tuple inside a for-all (via CPR analyis; see+typecheck/should_compile/tc170).++Moreover in instance heads we get forall-types with+kind Constraint.++It's tempting to check that the body kind is either * or #. But this is+wrong. For example:++ class C a b+ newtype N = Mk Foo deriving (C a)++We're doing newtype-deriving for C. But notice how `a` isn't in scope in+the predicate `C a`. So we quantify, yielding `forall a. C a` even though+`C a` has kind `* -> Constraint`. The `forall a. C a` is a bit cheeky, but+convenient. Bottom line: don't check for * or # here.++Note [Body kind of a HsQualTy]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If ctxt is non-empty, the HsQualTy really is a /function/, so the+kind of the result really is '*', and in that case the kind of the+body-type can be lifted or unlifted.++However, consider+ instance Eq a => Eq [a] where ...+or+ f :: (Eq a => Eq [a]) => blah+Here both body-kind of the HsQualTy is Constraint rather than *.+Rather crudely we tell the difference by looking at exp_kind. It's+very convenient to typecheck instance types like any other HsSigType.++Admittedly the '(Eq a => Eq [a]) => blah' case is erroneous, but it's+better to reject in checkValidType. If we say that the body kind+should be '*' we risk getting TWO error messages, one saying that Eq+[a] doens't have kind '*', and one saying that we need a Constraint to+the left of the outer (=>).++How do we figure out the right body kind? Well, it's a bit of a+kludge: I just look at the expected kind. If it's Constraint, we+must be in this instance situation context. It's a kludge because it+wouldn't work if any unification was involved to compute that result+kind -- but it isn't. (The true way might be to use the 'mode'+parameter, but that seemed like a sledgehammer to crack a nut.)++Note [Inferring tuple kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Give a tuple type (a,b,c), which the parser labels as HsBoxedOrConstraintTuple,+we try to figure out whether it's a tuple of kind * or Constraint.+ Step 1: look at the expected kind+ Step 2: infer argument kinds++If after Step 2 it's not clear from the arguments that it's+Constraint, then it must be *. Once having decided that we re-check+the Check the arguments again to give good error messages+in eg. `(Maybe, Maybe)`++Note that we will still fail to infer the correct kind in this case:++ type T a = ((a,a), D a)+ type family D :: Constraint -> Constraint++While kind checking T, we do not yet know the kind of D, so we will default the+kind of T to * -> *. It works if we annotate `a` with kind `Constraint`.++Note [Desugaring types]+~~~~~~~~~~~~~~~~~~~~~~~+The type desugarer is phase 2 of dealing with HsTypes. Specifically:++ * It transforms from HsType to Type++ * It zonks any kinds. The returned type should have no mutable kind+ or type variables (hence returning Type not TcType):+ - any unconstrained kind variables are defaulted to (Any *) just+ as in TcHsSyn.+ - there are no mutable type variables because we are+ kind-checking a type+ Reason: the returned type may be put in a TyCon or DataCon where+ it will never subsequently be zonked.++You might worry about nested scopes:+ ..a:kappa in scope..+ let f :: forall b. T '[a,b] -> Int+In this case, f's type could have a mutable kind variable kappa in it;+and we might then default it to (Any *) when dealing with f's type+signature. But we don't expect this to happen because we can't get a+lexically scoped type variable with a mutable kind variable in it. A+delicate point, this. If it becomes an issue we might need to+distinguish top-level from nested uses.++Moreover+ * it cannot fail,+ * it does no unifications+ * it does no validity checking, except for structural matters, such as+ (a) spurious ! annotations.+ (b) a class used as a type++Note [Kind of a type splice]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider these terms, each with TH type splice inside:+ [| e1 :: Maybe $(..blah..) |]+ [| e2 :: $(..blah..) |]+When kind-checking the type signature, we'll kind-check the splice+$(..blah..); we want to give it a kind that can fit in any context,+as if $(..blah..) :: forall k. k.++In the e1 example, the context of the splice fixes kappa to *. But+in the e2 example, we'll desugar the type, zonking the kind unification+variables as we go. When we encounter the unconstrained kappa, we+want to default it to '*', not to (Any *).+++Help functions for type applications+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-}++addTypeCtxt :: LHsType Name -> TcM a -> TcM a+ -- Wrap a context around only if we want to show that contexts.+ -- Omit invisble ones and ones user's won't grok+addTypeCtxt (L _ ty) thing+ = addErrCtxt doc thing+ where+ doc = text "In the type" <+> quotes (ppr ty)++{-+************************************************************************+* *+ Type-variable binders+%* *+%************************************************************************++Note [Scope-check inferred kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ data SameKind :: k -> k -> *+ foo :: forall a (b :: Proxy a) (c :: Proxy d). SameKind b c++d has no binding site. So it gets bound implicitly, at the top. The+problem is that d's kind mentions `a`. So it's all ill-scoped.++The way we check for this is to gather all variables *bound* in a+type variable's scope. The type variable's kind should not mention+any of these variables. That is, d's kind can't mention a, b, or c.+We can't just check to make sure that d's kind is in scope, because+we might be about to kindGeneralize.++A little messy, but it works.++Note [Dependent LHsQTyVars]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We track (in the renamer) which explicitly bound variables in a+LHsQTyVars are manifestly dependent; only precisely these variables+may be used within the LHsQTyVars. We must do this so that kcHsTyVarBndrs+can produce the right TyConBinders, and tell Anon vs. Named. Earlier,+I thought it would work simply to do a free-variable check during+kcHsTyVarBndrs, but this is bogus, because there may be unsolved+equalities about. And we don't want to eagerly solve the equalities,+because we may get further information after kcHsTyVarBndrs is called.+(Recall that kcHsTyVarBndrs is usually called from getInitialKind.+The only other case is in kcConDecl.) This is what implements the rule+that all variables intended to be dependent must be manifestly so.++Sidenote: It's quite possible that later, we'll consider (t -> s)+as a degenerate case of some (pi (x :: t) -> s) and then this will+all get more permissive.++-}++tcWildCardBinders :: [Name]+ -> ([(Name, TcTyVar)] -> TcM a)+ -> TcM a+tcWildCardBinders = tcWildCardBindersX new_tv+ where+ new_tv name = do { kind <- newMetaKindVar+ ; newSkolemTyVar name kind }++tcWildCardBindersX :: (Name -> TcM TcTyVar)+ -> [Name]+ -> ([(Name, TcTyVar)] -> TcM a)+ -> TcM a+tcWildCardBindersX new_wc wc_names thing_inside+ = do { wcs <- mapM new_wc wc_names+ ; let wc_prs = wc_names `zip` wcs+ ; tcExtendTyVarEnv2 wc_prs $+ thing_inside wc_prs }++-- | Kind-check a 'LHsQTyVars'. If the decl under consideration has a complete,+-- user-supplied kind signature (CUSK), generalise the result.+-- Used in 'getInitialKind' (for tycon kinds and other kinds)+-- and in kind-checking (but not for tycon kinds, which are checked with+-- tcTyClDecls). See also Note [Complete user-supplied kind signatures] in+-- HsDecls.+--+-- This function does not do telescope checking.+kcHsTyVarBndrs :: Name -- ^ of the thing being checked+ -> Bool -- ^ True <=> the TyCon being kind-checked can be unsaturated+ -> Bool -- ^ True <=> the decl being checked has a CUSK+ -> Bool -- ^ True <=> the decl is an open type/data family+ -> Bool -- ^ True <=> all the hsq_implicit are *kind* vars+ -- (will give these kind * if -XNoTypeInType)+ -> LHsQTyVars Name+ -> TcM (Kind, r) -- ^ The result kind, possibly with other info+ -> TcM (TcTyCon, r) -- ^ A suitably-kinded TcTyCon+kcHsTyVarBndrs name unsat cusk open_fam all_kind_vars+ (HsQTvs { hsq_implicit = kv_ns, hsq_explicit = hs_tvs+ , hsq_dependent = dep_names }) thing_inside+ | cusk+ = do { kv_kinds <- mk_kv_kinds+ ; lvl <- getTcLevel+ ; let scoped_kvs = zipWith (mk_skolem_tv lvl) kv_ns kv_kinds+ ; tcExtendTyVarEnv2 (kv_ns `zip` scoped_kvs) $+ do { (tc_binders, res_kind, stuff) <- solveEqualities $+ bind_telescope hs_tvs thing_inside++ -- Now, because we're in a CUSK, quantify over the mentioned+ -- kind vars, in dependency order.+ ; tc_binders <- mapM zonkTcTyVarBinder tc_binders+ ; res_kind <- zonkTcType res_kind+ ; let tc_tvs = binderVars tc_binders+ qkvs = tyCoVarsOfTypeWellScoped (mkTyConKind tc_binders res_kind)+ -- the visibility of tvs doesn't matter here; we just+ -- want the free variables not to include the tvs++ -- If there are any meta-tvs left, the user has+ -- lied about having a CUSK. Error.+ ; let (meta_tvs, good_tvs) = partition isMetaTyVar qkvs+ ; when (not (null meta_tvs)) $+ report_non_cusk_tvs (qkvs ++ tc_tvs)++ -- If any of the scoped_kvs aren't actually mentioned in a binder's+ -- kind (or the return kind), then we're in the CUSK case from+ -- Note [Free-floating kind vars]+ ; let all_tc_tvs = good_tvs ++ tc_tvs+ all_mentioned_tvs = mapUnionVarSet (tyCoVarsOfType . tyVarKind)+ all_tc_tvs+ `unionVarSet` tyCoVarsOfType res_kind+ unmentioned_kvs = filterOut (`elemVarSet` all_mentioned_tvs)+ scoped_kvs+ ; reportFloatingKvs name all_tc_tvs unmentioned_kvs++ ; let final_binders = map (mkNamedTyConBinder Specified) good_tvs+ ++ tc_binders+ tycon = mkTcTyCon name final_binders res_kind+ unsat (scoped_kvs ++ tc_tvs)+ -- the tvs contain the binders already+ -- in scope from an enclosing class, but+ -- re-adding tvs to the env't doesn't cause+ -- harm+ ; return (tycon, stuff) }}++ | otherwise+ = do { kv_kinds <- mk_kv_kinds+ ; scoped_kvs <- zipWithM newSigTyVar kv_ns kv_kinds+ -- the names must line up in splitTelescopeTvs+ ; (binders, res_kind, stuff)+ <- tcExtendTyVarEnv2 (kv_ns `zip` scoped_kvs) $+ bind_telescope hs_tvs thing_inside+ ; let -- NB: Don't add scoped_kvs to tyConTyVars, because they+ -- must remain lined up with the binders+ tycon = mkTcTyCon name binders res_kind unsat+ (scoped_kvs ++ binderVars binders)+ ; return (tycon, stuff) }+ where+ -- if -XNoTypeInType and we know all the implicits are kind vars,+ -- just give the kind *. This prevents test+ -- dependent/should_fail/KindLevelsB from compiling, as it should+ mk_kv_kinds :: TcM [Kind]+ mk_kv_kinds = do { typeintype <- xoptM LangExt.TypeInType+ ; if not typeintype && all_kind_vars+ then return (map (const liftedTypeKind) kv_ns)+ else mapM (const newMetaKindVar) kv_ns }++ -- there may be dependency between the explicit "ty" vars. So, we have+ -- to handle them one at a time.+ bind_telescope :: [LHsTyVarBndr Name]+ -> TcM (Kind, r)+ -> TcM ([TyConBinder], TcKind, r)+ bind_telescope [] thing+ = do { (res_kind, stuff) <- thing+ ; return ([], res_kind, stuff) }+ bind_telescope (L _ hs_tv : hs_tvs) thing+ = do { tv_pair@(tv, _) <- kc_hs_tv hs_tv+ -- NB: Bring all tvs into scope, even non-dependent ones,+ -- as they're needed in type synonyms, data constructors, etc.+ ; (binders, res_kind, stuff) <- bind_unless_scoped tv_pair $+ bind_telescope hs_tvs $+ thing+ -- See Note [Dependent LHsQTyVars]+ ; let new_binder | hsTyVarName hs_tv `elemNameSet` dep_names+ = mkNamedTyConBinder Required tv+ | otherwise+ = mkAnonTyConBinder tv+ ; return ( new_binder : binders+ , res_kind, stuff ) }++ -- | Bind the tyvar in the env't unless the bool is True+ bind_unless_scoped :: (TcTyVar, Bool) -> TcM a -> TcM a+ bind_unless_scoped (_, True) thing_inside = thing_inside+ bind_unless_scoped (tv, False) thing_inside+ = tcExtendTyVarEnv [tv] thing_inside++ kc_hs_tv :: HsTyVarBndr Name -> TcM (TcTyVar, Bool)+ kc_hs_tv (UserTyVar (L _ name))+ = do { tv_pair@(tv, scoped) <- tcHsTyVarName Nothing name++ -- Open type/data families default their variables to kind *.+ ; when (open_fam && not scoped) $ -- (don't default class tyvars)+ discardResult $ unifyKind (Just (mkTyVarTy tv)) liftedTypeKind+ (tyVarKind tv)++ ; return tv_pair }++ kc_hs_tv (KindedTyVar (L _ name) lhs_kind)+ = do { kind <- tcLHsKindSig lhs_kind+ ; tcHsTyVarName (Just kind) name }++ report_non_cusk_tvs all_tvs+ = do { all_tvs <- mapM zonkTyCoVarKind all_tvs+ ; let (_, tidy_tvs) = tidyOpenTyCoVars emptyTidyEnv all_tvs+ (meta_tvs, other_tvs) = partition isMetaTyVar tidy_tvs++ ; addErr $+ vcat [ text "You have written a *complete user-suppled kind signature*,"+ , hang (text "but the following variable" <> plural meta_tvs <+>+ isOrAre meta_tvs <+> text "undetermined:")+ 2 (vcat (map pp_tv meta_tvs))+ , text "Perhaps add a kind signature."+ , hang (text "Inferred kinds of user-written variables:")+ 2 (vcat (map pp_tv other_tvs)) ] }+ where+ pp_tv tv = ppr tv <+> dcolon <+> ppr (tyVarKind tv)+++tcImplicitTKBndrs :: [Name]+ -> TcM (a, TyVarSet) -- vars are bound somewhere in the scope+ -- see Note [Scope-check inferred kinds]+ -> TcM ([TcTyVar], a)+tcImplicitTKBndrs = tcImplicitTKBndrsX (tcHsTyVarName Nothing)++-- | Convenient specialization+tcImplicitTKBndrsType :: [Name]+ -> TcM Type+ -> TcM ([TcTyVar], Type)+tcImplicitTKBndrsType var_ns thing_inside+ = tcImplicitTKBndrs var_ns $+ do { res_ty <- thing_inside+ ; return (res_ty, allBoundVariables res_ty) }++-- this more general variant is needed in tcHsPatSigType.+-- See Note [Pattern signature binders]+tcImplicitTKBndrsX :: (Name -> TcM (TcTyVar, Bool)) -- new_tv function+ -> [Name]+ -> TcM (a, TyVarSet)+ -> TcM ([TcTyVar], a)+-- Returned TcTyVars have the supplied Names,+-- but may be in different order to the original [Name]+-- (because of sorting to respect dependency)+-- Returned TcTyVars have zonked kinds+tcImplicitTKBndrsX new_tv var_ns thing_inside+ = do { tkvs_pairs <- mapM new_tv var_ns+ ; let must_scope_tkvs = [ tkv | (tkv, False) <- tkvs_pairs ]+ tkvs = map fst tkvs_pairs+ ; (result, bound_tvs) <- tcExtendTyVarEnv must_scope_tkvs $+ thing_inside++ -- Check that the implicitly-bound kind variable+ -- really can go at the beginning.+ -- e.g. forall (a :: k) (b :: *). ...(forces k :: b)...+ ; tkvs <- mapM zonkTyCoVarKind tkvs+ -- NB: /not/ zonkTcTyVarToTyVar. tcImplicitTKBndrsX+ -- guarantees to return TcTyVars with the same Names+ -- as the var_ns. See [Pattern signature binders]++ ; let extra = text "NB: Implicitly-bound variables always come" <+>+ text "before other ones."+ ; checkValidInferredKinds tkvs bound_tvs extra++ ; let final_tvs = toposortTyVars tkvs+ ; traceTc "tcImplicitTKBndrs" (ppr var_ns $$ ppr final_tvs)++ ; return (final_tvs, result) }++tcExplicitTKBndrs :: [LHsTyVarBndr Name]+ -> ([TyVar] -> TcM (a, TyVarSet))+ -- ^ Thing inside returns the set of variables bound+ -- in the scope. See Note [Scope-check inferred kinds]+ -> TcM (a, TyVarSet) -- ^ returns augmented bound vars+-- No cloning: returned TyVars have the same Name as the incoming LHsTyVarBndrs+tcExplicitTKBndrs orig_hs_tvs thing_inside+ = tcExplicitTKBndrsX newSkolemTyVar orig_hs_tvs thing_inside++tcExplicitTKBndrsX :: (Name -> Kind -> TcM TyVar)+ -> [LHsTyVarBndr Name]+ -> ([TyVar] -> TcM (a, TyVarSet))+ -- ^ Thing inside returns the set of variables bound+ -- in the scope. See Note [Scope-check inferred kinds]+ -> TcM (a, TyVarSet) -- ^ returns augmented bound vars+tcExplicitTKBndrsX new_tv orig_hs_tvs thing_inside+ = go orig_hs_tvs $ \ tvs ->+ do { (result, bound_tvs) <- thing_inside tvs++ -- Issue an error if the ordering is bogus.+ -- See Note [Bad telescopes] in TcValidity.+ ; tvs <- checkZonkValidTelescope (interppSP orig_hs_tvs) tvs empty+ ; checkValidInferredKinds tvs bound_tvs empty++ ; traceTc "tcExplicitTKBndrs" $+ vcat [ text "Hs vars:" <+> ppr orig_hs_tvs+ , text "tvs:" <+> sep (map pprTyVar tvs) ]++ ; return (result, bound_tvs `unionVarSet` mkVarSet tvs)+ }+ where+ go [] thing = thing []+ go (L _ hs_tv : hs_tvs) thing+ = do { tv <- tcHsTyVarBndr new_tv hs_tv+ ; tcExtendTyVarEnv [tv] $+ go hs_tvs $ \ tvs ->+ thing (tv : tvs) }++tcHsTyVarBndr :: (Name -> Kind -> TcM TyVar)+ -> HsTyVarBndr Name -> TcM TcTyVar+-- Return a SkolemTv TcTyVar, initialised with a kind variable.+-- Typically the Kind inside the HsTyVarBndr will be a tyvar+-- with a mutable kind in it.+-- NB: These variables must not be in scope. This function+-- is not appropriate for use with associated types, for example.+--+-- Returned TcTyVar has the same name; no cloning+--+-- See also Note [Associated type tyvar names] in Class+--+tcHsTyVarBndr new_tv (UserTyVar (L _ name))+ = do { kind <- newMetaKindVar+ ; new_tv name kind }++tcHsTyVarBndr new_tv (KindedTyVar (L _ name) kind)+ = do { kind <- tcLHsKindSig kind+ ; new_tv name kind }++newWildTyVar :: Name -> TcM TcTyVar+-- ^ New unification variable for a wildcard+newWildTyVar _name+ = do { kind <- newMetaKindVar+ ; uniq <- newUnique+ ; details <- newMetaDetails TauTv+ ; let name = mkSysTvName uniq (fsLit "w")+ ; return (mkTcTyVar name kind details) }++-- | Produce a tyvar of the given name (with the kind provided, or+-- otherwise a meta-var kind). If+-- the name is already in scope, return the scoped variable, checking+-- to make sure the known kind matches any kind provided. The+-- second return value says whether the variable is in scope (True)+-- or not (False). (Use this for associated types, for example.)+tcHsTyVarName :: Maybe Kind -> Name -> TcM (TcTyVar, Bool)+tcHsTyVarName m_kind name+ = do { mb_tv <- tcLookupLcl_maybe name+ ; case mb_tv of+ Just (ATyVar _ tv)+ -> do { whenIsJust m_kind $ \ kind ->+ discardResult $+ unifyKind (Just (mkTyVarTy tv)) kind (tyVarKind tv)+ ; return (tv, True) }+ _ -> do { kind <- case m_kind of+ Just kind -> return kind+ Nothing -> newMetaKindVar+ ; tv <- newSkolemTyVar name kind+ ; return (tv, False) }}++-- makes a new skolem tv+newSkolemTyVar :: Name -> Kind -> TcM TcTyVar+newSkolemTyVar name kind = do { lvl <- getTcLevel+ ; return (mk_skolem_tv lvl name kind) }++mk_skolem_tv :: TcLevel -> Name -> Kind -> TcTyVar+mk_skolem_tv lvl n k = mkTcTyVar n k (SkolemTv lvl False)++------------------+kindGeneralizeType :: Type -> TcM Type+-- Result is zonked+kindGeneralizeType ty+ = do { kvs <- kindGeneralize ty+ ; ty <- zonkSigType (mkInvForAllTys kvs ty)+ ; return ty }++kindGeneralize :: TcType -> TcM [KindVar]+-- Quantify the free kind variables of a kind or type+-- In the latter case the type is closed, so it has no free+-- type variables. So in both cases, all the free vars are kind vars+kindGeneralize kind_or_type+ = do { kvs <- zonkTcTypeAndFV kind_or_type+ ; let dvs = DV { dv_kvs = kvs, dv_tvs = emptyDVarSet }+ ; gbl_tvs <- tcGetGlobalTyCoVars -- Already zonked+ ; quantifyZonkedTyVars gbl_tvs dvs }++{-+Note [Kind generalisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We do kind generalisation only at the outer level of a type signature.+For example, consider+ T :: forall k. k -> *+ f :: (forall a. T a -> Int) -> Int+When kind-checking f's type signature we generalise the kind at+the outermost level, thus:+ f1 :: forall k. (forall (a:k). T k a -> Int) -> Int -- YES!+and *not* at the inner forall:+ f2 :: (forall k. forall (a:k). T k a -> Int) -> Int -- NO!+Reason: same as for HM inference on value level declarations,+we want to infer the most general type. The f2 type signature+would be *less applicable* than f1, because it requires a more+polymorphic argument.++NB: There are no explicit kind variables written in f's signature.+When there are, the renamer adds these kind variables to the list of+variables bound by the forall, so you can indeed have a type that's+higher-rank in its kind. But only by explicit request.++Note [Kinds of quantified type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+tcTyVarBndrsGen quantifies over a specified list of type variables,+*and* over the kind variables mentioned in the kinds of those tyvars.++Note that we must zonk those kinds (obviously) but less obviously, we+must return type variables whose kinds are zonked too. Example+ (a :: k7) where k7 := k9 -> k9+We must return+ [k9, a:k9->k9]+and NOT+ [k9, a:k7]+Reason: we're going to turn this into a for-all type,+ forall k9. forall (a:k7). blah+which the type checker will then instantiate, and instantiate does not+look through unification variables!++Hence using zonked_kinds when forming tvs'.++Note [Free-floating kind vars]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ data T = MkT (forall (a :: k). Proxy a)+ -- from test ghci/scripts/T7873++This is not an existential datatype, but a higher-rank one. Note that+the forall to the right of MkT. Also consider++ data S a = MkS (Proxy (a :: k))++According to the rules around implicitly-bound kind variables, those+k's scope over the whole declarations. The renamer grabs it and adds it+to the hsq_implicits field of the HsQTyVars of the tycon. So it must+be in scope during type-checking, but we want to reject T while accepting+S.++Why reject T? Because the kind variable isn't fixed by anything. For+a variable like k to be implicit, it needs to be mentioned in the kind+of a tycon tyvar. But it isn't.++Why accept S? Because kind inference tells us that a has kind k, so it's+all OK.++Our approach depends on whether or not the datatype has a CUSK.++Non-CUSK: In the first pass (kcTyClTyVars) we just bring+k into scope. In the second pass (tcTyClTyVars),+we check to make sure that k has been unified with some other variable+(or generalized over, making k into a skolem). If it hasn't been, then+it must be a free-floating kind var. Error.++CUSK: When we determine the tycon's final, never-to-be-changed kind+in kcHsTyVarBndrs, we check to make sure all implicitly-bound kind+vars are indeed mentioned in a kind somewhere. If not, error.++-}++--------------------+-- getInitialKind has made a suitably-shaped kind for the type or class+-- Look it up in the local environment. This is used only for tycons+-- that we're currently type-checking, so we're sure to find a TcTyCon.+kcLookupTcTyCon :: Name -> TcM TcTyCon+kcLookupTcTyCon nm+ = do { tc_ty_thing <- tcLookup nm+ ; return $ case tc_ty_thing of+ ATcTyCon tc -> tc+ _ -> pprPanic "kcLookupTcTyCon" (ppr tc_ty_thing) }++-----------------------+-- | Bring tycon tyvars into scope. This is used during the "kind-checking"+-- pass in TcTyClsDecls. (Never in getInitialKind, never in the+-- "type-checking"/desugaring pass.)+-- Never emits constraints, though the thing_inside might.+kcTyClTyVars :: Name -> TcM a -> TcM a+kcTyClTyVars tycon_name thing_inside+ = do { tycon <- kcLookupTcTyCon tycon_name+ ; tcExtendTyVarEnv (tcTyConScopedTyVars tycon) $ thing_inside }++tcTyClTyVars :: Name+ -> ([TyConBinder] -> Kind -> TcM a) -> TcM a+-- ^ Used for the type variables of a type or class decl+-- on the second full pass (type-checking/desugaring) in TcTyClDecls.+-- This is *not* used in the initial-kind run, nor in the "kind-checking" pass.+-- Accordingly, everything passed to the continuation is fully zonked.+--+-- (tcTyClTyVars T [a,b] thing_inside)+-- where T : forall k1 k2 (a:k1 -> *) (b:k1). k2 -> *+-- calls thing_inside with arguments+-- [k1,k2,a,b] [k1:*, k2:*, Anon (k1 -> *), Anon k1] (k2 -> *)+-- having also extended the type environment with bindings+-- for k1,k2,a,b+--+-- Never emits constraints.+--+-- The LHsTyVarBndrs is always user-written, and the full, generalised+-- kind of the tycon is available in the local env.+tcTyClTyVars tycon_name thing_inside+ = do { tycon <- kcLookupTcTyCon tycon_name++ ; let scoped_tvs = tcTyConScopedTyVars tycon+ -- these are all zonked:+ binders = tyConBinders tycon+ res_kind = tyConResKind tycon++ -- See Note [Free-floating kind vars]+ ; zonked_scoped_tvs <- mapM zonkTcTyVarToTyVar scoped_tvs+ ; let still_sig_tvs = filter isSigTyVar zonked_scoped_tvs+ ; checkNoErrs $ reportFloatingKvs tycon_name+ zonked_scoped_tvs still_sig_tvs++ -- Add the *unzonked* tyvars to the env't, because those+ -- are the ones mentioned in the source.+ ; tcExtendTyVarEnv scoped_tvs $+ thing_inside binders res_kind }++-----------------------------------+tcDataKindSig :: Kind -> TcM ([TyConBinder], Kind)+-- GADT decls can have a (perhaps partial) kind signature+-- e.g. data T :: * -> * -> * where ...+-- This function makes up suitable (kinded) type variables for+-- the argument kinds, and checks that the result kind is indeed *.+-- We use it also to make up argument type variables for for data instances.+-- Never emits constraints.+-- Returns the new TyVars, the extracted TyBinders, and the new, reduced+-- result kind (which should always be Type or a synonym thereof)+tcDataKindSig kind+ = do { checkTc (isLiftedTypeKind res_kind) (badKindSig kind)+ ; span <- getSrcSpanM+ ; us <- newUniqueSupply+ ; rdr_env <- getLocalRdrEnv+ ; let uniqs = uniqsFromSupply us+ occs = [ occ | str <- allNameStrings+ , let occ = mkOccName tvName str+ , isNothing (lookupLocalRdrOcc rdr_env occ) ]+ -- Note [Avoid name clashes for associated data types]++ -- NB: Use the tv from a binder if there is one. Otherwise,+ -- we end up inventing a new Unique for it, and any other tv+ -- that mentions the first ends up with the wrong kind.+ extra_bndrs = zipWith4 mkTyBinderTyConBinder+ tv_bndrs (repeat span) uniqs occs++ ; return (extra_bndrs, res_kind) }+ where+ (tv_bndrs, res_kind) = splitPiTys kind++badKindSig :: Kind -> SDoc+badKindSig kind+ = hang (text "Kind signature on data type declaration has non-* return kind")+ 2 (ppr kind)++{-+Note [Avoid name clashes for associated data types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider class C a b where+ data D b :: * -> *+When typechecking the decl for D, we'll invent an extra type variable+for D, to fill out its kind. Ideally we don't want this type variable+to be 'a', because when pretty printing we'll get+ class C a b where+ data D b a0+(NB: the tidying happens in the conversion to IfaceSyn, which happens+as part of pretty-printing a TyThing.)++That's why we look in the LocalRdrEnv to see what's in scope. This is+important only to get nice-looking output when doing ":info C" in GHCi.+It isn't essential for correctness.+++************************************************************************+* *+ Partial signatures and pattern signatures+* *+************************************************************************++-}++tcHsPartialSigType+ :: UserTypeCtxt+ -> LHsSigWcType Name -- The type signature+ -> TcM ( [(Name, TcTyVar)] -- Wildcards+ , Maybe TcTyVar -- Extra-constraints wildcard+ , [TcTyVar] -- Implicitly and explicitly bound type variables+ , TcThetaType -- Theta part+ , TcType ) -- Tau part+tcHsPartialSigType ctxt sig_ty+ | HsWC { hswc_wcs = sig_wcs, hswc_body = ib_ty } <- sig_ty+ , HsIB { hsib_vars = implicit_hs_tvs, hsib_body = hs_ty } <- ib_ty+ , (explicit_hs_tvs, L _ hs_ctxt, hs_tau) <- splitLHsSigmaTy hs_ty+ = addSigCtxt ctxt hs_ty $+ do { (implicit_tvs, (wcs, wcx, explicit_tvs, theta, tau))+ <- tcWildCardBindersX newWildTyVar sig_wcs $ \ wcs ->+ tcImplicitTKBndrsX new_implicit_tv implicit_hs_tvs $+ tcExplicitTKBndrsX newSigTyVar explicit_hs_tvs $ \ explicit_tvs ->+ do { -- Instantiate the type-class context; but if there+ -- is an extra-constraints wildcard, just discard it here+ (theta, wcx) <- tcPartialContext hs_ctxt++ ; tau <- tcHsOpenType hs_tau++ ; let bound_tvs = unionVarSets [ allBoundVariables tau+ , mkVarSet explicit_tvs+ , mkVarSet (map snd wcs) ]++ ; return ( (wcs, wcx, explicit_tvs, theta, tau)+ , bound_tvs) }++ ; emitWildCardHoleConstraints wcs++ ; explicit_tvs <- mapM zonkTyCoVarKind explicit_tvs+ ; let all_tvs = implicit_tvs ++ explicit_tvs+ -- The implicit_tvs alraedy have zonked kinds++ ; theta <- mapM zonkTcType theta+ ; tau <- zonkTcType tau+ ; checkValidType ctxt (mkSpecForAllTys all_tvs $ mkPhiTy theta tau)++ ; traceTc "tcHsPartialSigType" (ppr all_tvs)+ ; return (wcs, wcx, all_tvs, theta, tau) }+ where+ new_implicit_tv name = do { kind <- newMetaKindVar+ ; tv <- newSigTyVar name kind+ ; return (tv, False) }++tcPartialContext :: HsContext Name -> TcM (TcThetaType, Maybe TcTyVar)+tcPartialContext hs_theta+ | Just (hs_theta1, hs_ctxt_last) <- snocView hs_theta+ , L _ (HsWildCardTy wc) <- ignoreParens hs_ctxt_last+ = do { wc_tv <- tcWildCardOcc wc constraintKind+ ; theta <- mapM tcLHsPredType hs_theta1+ ; return (theta, Just wc_tv) }+ | otherwise+ = do { theta <- mapM tcLHsPredType hs_theta+ ; return (theta, Nothing) }++tcHsPatSigType :: UserTypeCtxt+ -> LHsSigWcType Name -- The type signature+ -> TcM ( [(Name, TcTyVar)] -- Wildcards+ , [(Name, TcTyVar)] -- The new bit of type environment, binding+ -- the scoped type variables+ , TcType) -- The type+-- Used for type-checking type signatures in+-- (a) patterns e.g f (x::Int) = e+-- (b) RULE forall bndrs e.g. forall (x::Int). f x = x+--+-- This may emit constraints++tcHsPatSigType ctxt sig_ty+ | HsWC { hswc_wcs = sig_wcs, hswc_body = ib_ty } <- sig_ty+ , HsIB { hsib_vars = sig_vars, hsib_body = hs_ty } <- ib_ty+ = addSigCtxt ctxt hs_ty $+ do { (implicit_tvs, (wcs, sig_ty))+ <- tcWildCardBindersX newWildTyVar sig_wcs $ \ wcs ->+ tcImplicitTKBndrsX new_implicit_tv sig_vars $+ do { sig_ty <- tcHsOpenType hs_ty+ ; return ((wcs, sig_ty), allBoundVariables sig_ty) }++ ; emitWildCardHoleConstraints wcs++ ; sig_ty <- zonkTcType sig_ty+ ; checkValidType ctxt sig_ty++ ; tv_pairs <- mapM mk_tv_pair implicit_tvs++ ; traceTc "tcHsPatSigType" (ppr sig_vars)+ ; return (wcs, tv_pairs, sig_ty) }+ where+ new_implicit_tv name = do { kind <- newMetaKindVar+ ; tv <- new_tv name kind+ ; return (tv, False) }+ -- "False" means that these tyvars aren't yet in scope+ new_tv = case ctxt of+ RuleSigCtxt {} -> newSkolemTyVar+ _ -> newSigTyVar+ -- See Note [Pattern signature binders]+ -- See Note [Unifying SigTvs]++ mk_tv_pair tv = do { tv' <- zonkTcTyVarToTyVar tv+ ; return (tyVarName tv, tv') }+ -- The Name is one of sig_vars, the lexically scoped name+ -- But if it's a SigTyVar, it might have been unified+ -- with an existing in-scope skolem, so we must zonk+ -- here. See Note [Pattern signature binders]++tcPatSig :: Bool -- True <=> pattern binding+ -> LHsSigWcType Name+ -> ExpSigmaType+ -> TcM (TcType, -- The type to use for "inside" the signature+ [(Name,TcTyVar)], -- The new bit of type environment, binding+ -- the scoped type variables+ [(Name,TcTyVar)], -- The wildcards+ HsWrapper) -- Coercion due to unification with actual ty+ -- Of shape: res_ty ~ sig_ty+tcPatSig in_pat_bind sig res_ty+ = do { (sig_wcs, sig_tvs, sig_ty) <- tcHsPatSigType PatSigCtxt sig+ -- sig_tvs are the type variables free in 'sig',+ -- and not already in scope. These are the ones+ -- that should be brought into scope++ ; if null sig_tvs then do {+ -- Just do the subsumption check and return+ wrap <- addErrCtxtM (mk_msg sig_ty) $+ tcSubTypeET PatSigOrigin PatSigCtxt res_ty sig_ty+ ; return (sig_ty, [], sig_wcs, wrap)+ } else do+ -- Type signature binds at least one scoped type variable++ -- A pattern binding cannot bind scoped type variables+ -- It is more convenient to make the test here+ -- than in the renamer+ { when in_pat_bind (addErr (patBindSigErr sig_tvs))++ -- Check that all newly-in-scope tyvars are in fact+ -- constrained by the pattern. This catches tiresome+ -- cases like+ -- type T a = Int+ -- f :: Int -> Int+ -- f (x :: T a) = ...+ -- Here 'a' doesn't get a binding. Sigh+ ; let bad_tvs = [ tv | (_,tv) <- sig_tvs+ , not (tv `elemVarSet` exactTyCoVarsOfType sig_ty) ]+ ; checkTc (null bad_tvs) (badPatSigTvs sig_ty bad_tvs)++ -- Now do a subsumption check of the pattern signature against res_ty+ ; wrap <- addErrCtxtM (mk_msg sig_ty) $+ tcSubTypeET PatSigOrigin PatSigCtxt res_ty sig_ty++ -- Phew!+ ; return (sig_ty, sig_tvs, sig_wcs, wrap)+ } }+ where+ mk_msg sig_ty tidy_env+ = do { (tidy_env, sig_ty) <- zonkTidyTcType tidy_env sig_ty+ ; res_ty <- readExpType res_ty -- should be filled in by now+ ; (tidy_env, res_ty) <- zonkTidyTcType tidy_env res_ty+ ; let msg = vcat [ hang (text "When checking that the pattern signature:")+ 4 (ppr sig_ty)+ , nest 2 (hang (text "fits the type of its context:")+ 2 (ppr res_ty)) ]+ ; return (tidy_env, msg) }++patBindSigErr :: [(Name,TcTyVar)] -> SDoc+patBindSigErr sig_tvs+ = hang (text "You cannot bind scoped type variable" <> plural sig_tvs+ <+> pprQuotedList (map fst sig_tvs))+ 2 (text "in a pattern binding signature")++{- Note [Pattern signature binders]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T = forall a. T a (a->Int)+ f (T x (f :: b->Int)) = blah++Here+ * The pattern (T p1 p2) creates a *skolem* type variable 'a_sk',+ It must be a skolem so that that it retains its identity, and+ TcErrors.getSkolemInfo can thereby find the binding site for the skolem.++ * The type signature pattern (f :: b->Int) makes a fresh meta-tyvar b_sig+ (a SigTv), and binds "b" :-> b_sig in the envt++ * Then unification makes b_sig := a_sk+ That's why we must make b_sig a MetaTv (albeit a SigTv),+ not a SkolemTv, so that it can unify to a_sk.++ * Finally, in 'blah' we must have the envt "b" :-> a_sk. The pair+ ("b" :-> a_sk) is returned by tcHsPatSigType, constructed by+ mk_tv_pair in that funcion.++Another example (Trac #13881):+ fl :: forall (l :: [a]). Sing l -> Sing l+ fl (SNil :: Sing (l :: [y])) = SNil+When we reach the pattern signature, 'l' is in scope from the+outer 'forall':+ "a" :-> a_sk :: *+ "l" :-> l_sk :: [a_sk]+We make up a fresh meta-SigTv, y_sig, for 'y', and kind-check+the pattern signature+ Sing (l :: [y])+That unifies y_sig := a_sk. We return from tcHsPatSigType with+the pair ("y" :-> a_sk).++For RULE binders, though, things are a bit different (yuk).+ RULE "foo" forall (x::a) (y::[a]). f x y = ...+Here this really is the binding site of the type variable so we'd like+to use a skolem, so that we get a complaint if we unify two of them+together.++Note [Unifying SigTvs]+~~~~~~~~~~~~~~~~~~~~~~+ALAS we have no decent way of avoiding two SigTvs getting unified.+Consider+ f (x::(a,b)) (y::c)) = [fst x, y]+Here we'd really like to complain that 'a' and 'c' are unified. But+for the reasons above we can't make a,b,c into skolems, so they+are just SigTvs that can unify. And indeed, this would be ok,+ f x (y::c) = case x of+ (x1 :: a1, True) -> [x,y]+ (x1 :: a2, False) -> [x,y,y]+Here the type of x's first component is called 'a1' in one branch and+'a2' in the other. We could try insisting on the same OccName, but+they definitely won't have the sane lexical Name.++I think we could solve this by recording in a SigTv a list of all the+in-scope variables that it should not unify with, but it's fiddly.+++************************************************************************+* *+ Checking kinds+* *+************************************************************************++-}++unifyKinds :: [(TcType, TcKind)] -> TcM ([TcType], TcKind)+unifyKinds act_kinds+ = do { kind <- newMetaKindVar+ ; let check (ty, act_kind) = checkExpectedKind ty act_kind kind+ ; tys' <- mapM check act_kinds+ ; return (tys', kind) }++{-+************************************************************************+* *+ Sort checking kinds+* *+************************************************************************++tcLHsKindSig converts a user-written kind to an internal, sort-checked kind.+It does sort checking and desugaring at the same time, in one single pass.+-}++tcLHsKindSig :: LHsKind Name -> TcM Kind+tcLHsKindSig hs_kind+ = do { kind <- tc_lhs_kind kindLevelMode hs_kind+ ; zonkTcType kind }+ -- This zonk is very important in the case of higher rank kinds+ -- E.g. Trac #13879 f :: forall (p :: forall z (y::z). <blah>).+ -- <more blah>+ -- When instanting p's kind at occurrences of p in <more blah>+ -- it's crucial that the kind we instantiate is fully zonked,+ -- else we may fail to substitute properly++tc_lhs_kind :: TcTyMode -> LHsKind Name -> TcM Kind+tc_lhs_kind mode k+ = addErrCtxt (text "In the kind" <+> quotes (ppr k)) $+ tc_lhs_type (kindLevel mode) k liftedTypeKind++promotionErr :: Name -> PromotionErr -> TcM a+promotionErr name err+ = failWithTc (hang (pprPECategory err <+> quotes (ppr name) <+> text "cannot be used here")+ 2 (parens reason))+ where+ reason = case err of+ FamDataConPE -> text "it comes from a data family instance"+ NoDataKindsTC -> text "Perhaps you intended to use DataKinds"+ NoDataKindsDC -> text "Perhaps you intended to use DataKinds"+ NoTypeInTypeTC -> text "Perhaps you intended to use TypeInType"+ NoTypeInTypeDC -> text "Perhaps you intended to use TypeInType"+ PatSynPE -> text "Pattern synonyms cannot be promoted"+ _ -> text "it is defined and used in the same recursive group"++{-+************************************************************************+* *+ Scoped type variables+* *+************************************************************************+-}++badPatSigTvs :: TcType -> [TyVar] -> SDoc+badPatSigTvs sig_ty bad_tvs+ = vcat [ fsep [text "The type variable" <> plural bad_tvs,+ quotes (pprWithCommas ppr bad_tvs),+ text "should be bound by the pattern signature" <+> quotes (ppr sig_ty),+ text "but are actually discarded by a type synonym" ]+ , text "To fix this, expand the type synonym"+ , text "[Note: I hope to lift this restriction in due course]" ]++{-+************************************************************************+* *+ Error messages and such+* *+************************************************************************+-}++-- | Make an appropriate message for an error in a function argument.+-- Used for both expressions and types.+funAppCtxt :: (Outputable fun, Outputable arg) => fun -> arg -> Int -> SDoc+funAppCtxt fun arg arg_no+ = hang (hsep [ text "In the", speakNth arg_no, ptext (sLit "argument of"),+ quotes (ppr fun) <> text ", namely"])+ 2 (quotes (ppr arg))++-- See Note [Free-floating kind vars]+reportFloatingKvs :: Name -- of the tycon+ -> [TcTyVar] -- all tyvars, not necessarily zonked+ -> [TcTyVar] -- floating tyvars+ -> TcM ()+reportFloatingKvs tycon_name all_tvs bad_tvs+ = unless (null bad_tvs) $ -- don't bother zonking if there's no error+ do { all_tvs <- mapM zonkTcTyVarToTyVar all_tvs+ ; bad_tvs <- mapM zonkTcTyVarToTyVar bad_tvs+ ; let (tidy_env, tidy_all_tvs) = tidyOpenTyCoVars emptyTidyEnv all_tvs+ tidy_bad_tvs = map (tidyTyVarOcc tidy_env) bad_tvs+ ; typeintype <- xoptM LangExt.TypeInType+ ; mapM_ (report typeintype tidy_all_tvs) tidy_bad_tvs }+ where+ report typeintype tidy_all_tvs tidy_bad_tv+ = addErr $+ vcat [ text "Kind variable" <+> quotes (ppr tidy_bad_tv) <+>+ text "is implicitly bound in datatype"+ , quotes (ppr tycon_name) <> comma <+>+ text "but does not appear as the kind of any"+ , text "of its type variables. Perhaps you meant"+ , text "to bind it" <+> ppWhen (not typeintype)+ (text "(with TypeInType)") <+>+ text "explicitly somewhere?"+ , ppWhen (not (null tidy_all_tvs)) $+ hang (text "Type variables with inferred kinds:")+ 2 (ppr_tv_bndrs tidy_all_tvs) ]++ ppr_tv_bndrs tvs = sep (map pp_tv tvs)+ pp_tv tv = parens (ppr tv <+> dcolon <+> ppr (tyVarKind tv))
+ typecheck/TcInstDcls.hs view
@@ -0,0 +1,1840 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++TcInstDecls: Typechecking instance declarations+-}++{-# LANGUAGE CPP #-}++module TcInstDcls ( tcInstDecls1, tcInstDeclsDeriv, tcInstDecls2 ) where++#include "HsVersions.h"++import HsSyn+import TcBinds+import TcTyClsDecls+import TcClassDcl( tcClassDecl2, tcATDefault,+ HsSigFun, mkHsSigFun,+ findMethodBind, instantiateMethod )+import TcSigs+import TcRnMonad+import TcValidity+import TcHsSyn ( zonkTyBndrsX, emptyZonkEnv+ , zonkTcTypeToTypes, zonkTcTypeToType )+import TcMType+import TcType+import BuildTyCl+import Inst+import InstEnv+import FamInst+import FamInstEnv+import TcDeriv+import TcEnv+import TcHsType+import TcUnify+import CoreSyn ( Expr(..), mkApps, mkVarApps, mkLams )+import MkCore ( nO_METHOD_BINDING_ERROR_ID )+import CoreUnfold ( mkInlineUnfoldingWithArity, mkDFunUnfolding )+import Type+import TcEvidence+import TyCon+import CoAxiom+import DataCon+import ConLike+import Class+import Var+import VarEnv+import VarSet+import PrelNames ( typeableClassName, genericClassNames+ , knownNatClassName, knownSymbolClassName )+import Bag+import BasicTypes+import DynFlags+import ErrUtils+import FastString+import Id+import MkId+import Name+import NameSet+import Outputable+import SrcLoc+import Util+import BooleanFormula ( isUnsatisfied, pprBooleanFormulaNice )+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Maybes+++{-+Typechecking instance declarations is done in two passes. The first+pass, made by @tcInstDecls1@, collects information to be used in the+second pass.++This pre-processed info includes the as-yet-unprocessed bindings+inside the instance declaration. These are type-checked in the second+pass, when the class-instance envs and GVE contain all the info from+all the instance and value decls. Indeed that's the reason we need+two passes over the instance decls.+++Note [How instance declarations are translated]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here is how we translate instance declarations into Core++Running example:+ class C a where+ op1, op2 :: Ix b => a -> b -> b+ op2 = <dm-rhs>++ instance C a => C [a]+ {-# INLINE [2] op1 #-}+ op1 = <rhs>+===>+ -- Method selectors+ op1,op2 :: forall a. C a => forall b. Ix b => a -> b -> b+ op1 = ...+ op2 = ...++ -- Default methods get the 'self' dictionary as argument+ -- so they can call other methods at the same type+ -- Default methods get the same type as their method selector+ $dmop2 :: forall a. C a => forall b. Ix b => a -> b -> b+ $dmop2 = /\a. \(d:C a). /\b. \(d2: Ix b). <dm-rhs>+ -- NB: type variables 'a' and 'b' are *both* in scope in <dm-rhs>+ -- Note [Tricky type variable scoping]++ -- A top-level definition for each instance method+ -- Here op1_i, op2_i are the "instance method Ids"+ -- The INLINE pragma comes from the user pragma+ {-# INLINE [2] op1_i #-} -- From the instance decl bindings+ op1_i, op2_i :: forall a. C a => forall b. Ix b => [a] -> b -> b+ op1_i = /\a. \(d:C a).+ let this :: C [a]+ this = df_i a d+ -- Note [Subtle interaction of recursion and overlap]++ local_op1 :: forall b. Ix b => [a] -> b -> b+ local_op1 = <rhs>+ -- Source code; run the type checker on this+ -- NB: Type variable 'a' (but not 'b') is in scope in <rhs>+ -- Note [Tricky type variable scoping]++ in local_op1 a d++ op2_i = /\a \d:C a. $dmop2 [a] (df_i a d)++ -- The dictionary function itself+ {-# NOINLINE CONLIKE df_i #-} -- Never inline dictionary functions+ df_i :: forall a. C a -> C [a]+ df_i = /\a. \d:C a. MkC (op1_i a d) (op2_i a d)+ -- But see Note [Default methods in instances]+ -- We can't apply the type checker to the default-method call++ -- Use a RULE to short-circuit applications of the class ops+ {-# RULE "op1@C[a]" forall a, d:C a.+ op1 [a] (df_i d) = op1_i a d #-}++Note [Instances and loop breakers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Note that df_i may be mutually recursive with both op1_i and op2_i.+ It's crucial that df_i is not chosen as the loop breaker, even+ though op1_i has a (user-specified) INLINE pragma.++* Instead the idea is to inline df_i into op1_i, which may then select+ methods from the MkC record, and thereby break the recursion with+ df_i, leaving a *self*-recursive op1_i. (If op1_i doesn't call op at+ the same type, it won't mention df_i, so there won't be recursion in+ the first place.)++* If op1_i is marked INLINE by the user there's a danger that we won't+ inline df_i in it, and that in turn means that (since it'll be a+ loop-breaker because df_i isn't), op1_i will ironically never be+ inlined. But this is OK: the recursion breaking happens by way of+ a RULE (the magic ClassOp rule above), and RULES work inside InlineRule+ unfoldings. See Note [RULEs enabled in SimplGently] in SimplUtils++Note [ClassOp/DFun selection]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+One thing we see a lot is stuff like+ op2 (df d1 d2)+where 'op2' is a ClassOp and 'df' is DFun. Now, we could inline *both*+'op2' and 'df' to get+ case (MkD ($cop1 d1 d2) ($cop2 d1 d2) ... of+ MkD _ op2 _ _ _ -> op2+And that will reduce to ($cop2 d1 d2) which is what we wanted.++But it's tricky to make this work in practice, because it requires us to+inline both 'op2' and 'df'. But neither is keen to inline without having+seen the other's result; and it's very easy to get code bloat (from the+big intermediate) if you inline a bit too much.++Instead we use a cunning trick.+ * We arrange that 'df' and 'op2' NEVER inline.++ * We arrange that 'df' is ALWAYS defined in the sylised form+ df d1 d2 = MkD ($cop1 d1 d2) ($cop2 d1 d2) ...++ * We give 'df' a magical unfolding (DFunUnfolding [$cop1, $cop2, ..])+ that lists its methods.++ * We make CoreUnfold.exprIsConApp_maybe spot a DFunUnfolding and return+ a suitable constructor application -- inlining df "on the fly" as it+ were.++ * ClassOp rules: We give the ClassOp 'op2' a BuiltinRule that+ extracts the right piece iff its argument satisfies+ exprIsConApp_maybe. This is done in MkId mkDictSelId++ * We make 'df' CONLIKE, so that shared uses still match; eg+ let d = df d1 d2+ in ...(op2 d)...(op1 d)...++Note [Single-method classes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the class has just one method (or, more accurately, just one element+of {superclasses + methods}), then we use a different strategy.++ class C a where op :: a -> a+ instance C a => C [a] where op = <blah>++We translate the class decl into a newtype, which just gives a+top-level axiom. The "constructor" MkC expands to a cast, as does the+class-op selector.++ axiom Co:C a :: C a ~ (a->a)++ op :: forall a. C a -> (a -> a)+ op a d = d |> (Co:C a)++ MkC :: forall a. (a->a) -> C a+ MkC = /\a.\op. op |> (sym Co:C a)++The clever RULE stuff doesn't work now, because ($df a d) isn't+a constructor application, so exprIsConApp_maybe won't return+Just <blah>.++Instead, we simply rely on the fact that casts are cheap:++ $df :: forall a. C a => C [a]+ {-# INLINE df #-} -- NB: INLINE this+ $df = /\a. \d. MkC [a] ($cop_list a d)+ = $cop_list |> forall a. C a -> (sym (Co:C [a]))++ $cop_list :: forall a. C a => [a] -> [a]+ $cop_list = <blah>++So if we see+ (op ($df a d))+we'll inline 'op' and '$df', since both are simply casts, and+good things happen.++Why do we use this different strategy? Because otherwise we+end up with non-inlined dictionaries that look like+ $df = $cop |> blah+which adds an extra indirection to every use, which seems stupid. See+Trac #4138 for an example (although the regression reported there+wasn't due to the indirection).++There is an awkward wrinkle though: we want to be very+careful when we have+ instance C a => C [a] where+ {-# INLINE op #-}+ op = ...+then we'll get an INLINE pragma on $cop_list but it's important that+$cop_list only inlines when it's applied to *two* arguments (the+dictionary and the list argument). So we must not eta-expand $df+above. We ensure that this doesn't happen by putting an INLINE+pragma on the dfun itself; after all, it ends up being just a cast.++There is one more dark corner to the INLINE story, even more deeply+buried. Consider this (Trac #3772):++ class DeepSeq a => C a where+ gen :: Int -> a++ instance C a => C [a] where+ gen n = ...++ class DeepSeq a where+ deepSeq :: a -> b -> b++ instance DeepSeq a => DeepSeq [a] where+ {-# INLINE deepSeq #-}+ deepSeq xs b = foldr deepSeq b xs++That gives rise to these defns:++ $cdeepSeq :: DeepSeq a -> [a] -> b -> b+ -- User INLINE( 3 args )!+ $cdeepSeq a (d:DS a) b (x:[a]) (y:b) = ...++ $fDeepSeq[] :: DeepSeq a -> DeepSeq [a]+ -- DFun (with auto INLINE pragma)+ $fDeepSeq[] a d = $cdeepSeq a d |> blah++ $cp1 a d :: C a => DeepSep [a]+ -- We don't want to eta-expand this, lest+ -- $cdeepSeq gets inlined in it!+ $cp1 a d = $fDeepSep[] a (scsel a d)++ $fC[] :: C a => C [a]+ -- Ordinary DFun+ $fC[] a d = MkC ($cp1 a d) ($cgen a d)++Here $cp1 is the code that generates the superclass for C [a]. The+issue is this: we must not eta-expand $cp1 either, or else $fDeepSeq[]+and then $cdeepSeq will inline there, which is definitely wrong. Like+on the dfun, we solve this by adding an INLINE pragma to $cp1.++Note [Subtle interaction of recursion and overlap]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ class C a where { op1,op2 :: a -> a }+ instance C a => C [a] where+ op1 x = op2 x ++ op2 x+ op2 x = ...+ instance C [Int] where+ ...++When type-checking the C [a] instance, we need a C [a] dictionary (for+the call of op2). If we look up in the instance environment, we find+an overlap. And in *general* the right thing is to complain (see Note+[Overlapping instances] in InstEnv). But in *this* case it's wrong to+complain, because we just want to delegate to the op2 of this same+instance.++Why is this justified? Because we generate a (C [a]) constraint in+a context in which 'a' cannot be instantiated to anything that matches+other overlapping instances, or else we would not be executing this+version of op1 in the first place.++It might even be a bit disguised:++ nullFail :: C [a] => [a] -> [a]+ nullFail x = op2 x ++ op2 x++ instance C a => C [a] where+ op1 x = nullFail x++Precisely this is used in package 'regex-base', module Context.hs.+See the overlapping instances for RegexContext, and the fact that they+call 'nullFail' just like the example above. The DoCon package also+does the same thing; it shows up in module Fraction.hs.++Conclusion: when typechecking the methods in a C [a] instance, we want to+treat the 'a' as an *existential* type variable, in the sense described+by Note [Binding when looking up instances]. That is why isOverlappableTyVar+responds True to an InstSkol, which is the kind of skolem we use in+tcInstDecl2.+++Note [Tricky type variable scoping]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In our example+ class C a where+ op1, op2 :: Ix b => a -> b -> b+ op2 = <dm-rhs>++ instance C a => C [a]+ {-# INLINE [2] op1 #-}+ op1 = <rhs>++note that 'a' and 'b' are *both* in scope in <dm-rhs>, but only 'a' is+in scope in <rhs>. In particular, we must make sure that 'b' is in+scope when typechecking <dm-rhs>. This is achieved by subFunTys,+which brings appropriate tyvars into scope. This happens for both+<dm-rhs> and for <rhs>, but that doesn't matter: the *renamer* will have+complained if 'b' is mentioned in <rhs>.++++************************************************************************+* *+\subsection{Extracting instance decls}+* *+************************************************************************++Gather up the instance declarations from their various sources+-}++tcInstDecls1 -- Deal with both source-code and imported instance decls+ :: [LInstDecl Name] -- Source code instance decls+ -> TcM (TcGblEnv, -- The full inst env+ [InstInfo Name], -- Source-code instance decls to process;+ -- contains all dfuns for this module+ [DerivInfo]) -- From data family instances++tcInstDecls1 inst_decls+ = do { -- Do class and family instance declarations+ ; stuff <- mapAndRecoverM tcLocalInstDecl inst_decls++ ; let (local_infos_s, fam_insts_s, datafam_deriv_infos) = unzip3 stuff+ fam_insts = concat fam_insts_s+ local_infos = concat local_infos_s++ ; gbl_env <- addClsInsts local_infos $+ addFamInsts fam_insts $+ getGblEnv++ ; return ( gbl_env+ , local_infos+ , concat datafam_deriv_infos ) }++-- | Use DerivInfo for data family instances (produced by tcInstDecls1),+-- datatype declarations (TyClDecl), and standalone deriving declarations+-- (DerivDecl) to check and process all derived class instances.+tcInstDeclsDeriv+ :: [DerivInfo]+ -> [LTyClDecl Name]+ -> [LDerivDecl Name]+ -> TcM (TcGblEnv, [InstInfo Name], HsValBinds Name)+tcInstDeclsDeriv datafam_deriv_infos tyclds derivds+ = do th_stage <- getStage -- See Note [Deriving inside TH brackets]+ if isBrackStage th_stage+ then do { gbl_env <- getGblEnv+ ; return (gbl_env, bagToList emptyBag, emptyValBindsOut) }+ else do { data_deriv_infos <- mkDerivInfos tyclds+ ; let deriv_infos = datafam_deriv_infos ++ data_deriv_infos+ ; (tcg_env, info_bag, valbinds) <- tcDeriving deriv_infos derivds+ ; return (tcg_env, bagToList info_bag, valbinds) }++addClsInsts :: [InstInfo Name] -> TcM a -> TcM a+addClsInsts infos thing_inside+ = tcExtendLocalInstEnv (map iSpec infos) thing_inside++addFamInsts :: [FamInst] -> TcM a -> TcM a+-- Extend (a) the family instance envt+-- (b) the type envt with stuff from data type decls+addFamInsts fam_insts thing_inside+ = tcExtendLocalFamInstEnv fam_insts $+ tcExtendGlobalEnv axioms $+ tcExtendTyConEnv data_rep_tycons $+ do { traceTc "addFamInsts" (pprFamInsts fam_insts)+ ; tcg_env <- tcAddImplicits data_rep_tycons+ -- Does not add its axiom; that comes from+ -- adding the 'axioms' above+ ; setGblEnv tcg_env thing_inside }+ where+ axioms = map (ACoAxiom . toBranchedAxiom . famInstAxiom) fam_insts+ data_rep_tycons = famInstsRepTyCons fam_insts+ -- The representation tycons for 'data instances' declarations++{-+Note [Deriving inside TH brackets]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Given a declaration bracket+ [d| data T = A | B deriving( Show ) |]++there is really no point in generating the derived code for deriving(+Show) and then type-checking it. This will happen at the call site+anyway, and the type check should never fail! Moreover (Trac #6005)+the scoping of the generated code inside the bracket does not seem to+work out.++The easy solution is simply not to generate the derived instances at+all. (A less brutal solution would be to generate them with no+bindings.) This will become moot when we shift to the new TH plan, so+the brutal solution will do.+-}++tcLocalInstDecl :: LInstDecl Name+ -> TcM ([InstInfo Name], [FamInst], [DerivInfo])+ -- A source-file instance declaration+ -- Type-check all the stuff before the "where"+ --+ -- We check for respectable instance type, and context+tcLocalInstDecl (L loc (TyFamInstD { tfid_inst = decl }))+ = do { fam_inst <- tcTyFamInstDecl Nothing (L loc decl)+ ; return ([], [fam_inst], []) }++tcLocalInstDecl (L loc (DataFamInstD { dfid_inst = decl }))+ = do { (fam_inst, m_deriv_info) <- tcDataFamInstDecl Nothing (L loc decl)+ ; return ([], [fam_inst], maybeToList m_deriv_info) }++tcLocalInstDecl (L loc (ClsInstD { cid_inst = decl }))+ = do { (insts, fam_insts, deriv_infos) <- tcClsInstDecl (L loc decl)+ ; return (insts, fam_insts, deriv_infos) }++tcClsInstDecl :: LClsInstDecl Name+ -> TcM ([InstInfo Name], [FamInst], [DerivInfo])+-- The returned DerivInfos are for any associated data families+tcClsInstDecl (L loc (ClsInstDecl { cid_poly_ty = poly_ty, cid_binds = binds+ , cid_sigs = uprags, cid_tyfam_insts = ats+ , cid_overlap_mode = overlap_mode+ , cid_datafam_insts = adts }))+ = setSrcSpan loc $+ addErrCtxt (instDeclCtxt1 poly_ty) $+ do { (tyvars, theta, clas, inst_tys) <- tcHsClsInstType InstDeclCtxt poly_ty+ ; let mini_env = mkVarEnv (classTyVars clas `zip` inst_tys)+ mini_subst = mkTvSubst (mkInScopeSet (mkVarSet tyvars)) mini_env+ mb_info = Just (clas, tyvars, mini_env)++ -- Next, process any associated types.+ ; traceTc "tcLocalInstDecl" (ppr poly_ty)+ ; tyfam_insts0 <- tcExtendTyVarEnv tyvars $+ mapAndRecoverM (tcTyFamInstDecl mb_info) ats+ ; datafam_stuff <- tcExtendTyVarEnv tyvars $+ mapAndRecoverM (tcDataFamInstDecl mb_info) adts+ ; let (datafam_insts, m_deriv_infos) = unzip datafam_stuff+ deriv_infos = catMaybes m_deriv_infos++ -- Check for missing associated types and build them+ -- from their defaults (if available)+ ; let defined_ats = mkNameSet (map (tyFamInstDeclName . unLoc) ats)+ `unionNameSet`+ mkNameSet (map (unLoc . dfid_tycon . unLoc) adts)+ ; tyfam_insts1 <- mapM (tcATDefault True loc mini_subst defined_ats)+ (classATItems clas)++ -- Finally, construct the Core representation of the instance.+ -- (This no longer includes the associated types.)+ ; dfun_name <- newDFunName clas inst_tys (getLoc (hsSigType poly_ty))+ -- Dfun location is that of instance *header*++ ; ispec <- newClsInst (fmap unLoc overlap_mode) dfun_name tyvars theta+ clas inst_tys++ ; let inst_info = InstInfo { iSpec = ispec+ , iBinds = InstBindings+ { ib_binds = binds+ , ib_tyvars = map Var.varName tyvars -- Scope over bindings+ , ib_pragmas = uprags+ , ib_extensions = []+ , ib_derived = False } }++ ; doClsInstErrorChecks inst_info++ ; return ( [inst_info], tyfam_insts0 ++ concat tyfam_insts1 ++ datafam_insts+ , deriv_infos ) }+++doClsInstErrorChecks :: InstInfo Name -> TcM ()+doClsInstErrorChecks inst_info+ = do { traceTc "doClsInstErrorChecks" (ppr ispec)+ ; dflags <- getDynFlags+ ; is_boot <- tcIsHsBootOrSig++ -- In hs-boot files there should be no bindings+ ; failIfTc (is_boot && not no_binds) badBootDeclErr++ -- If not in an hs-boot file, abstract classes cannot have+ -- instances declared+ ; failIfTc (not is_boot && isAbstractClass clas) abstractClassInstErr++ -- Handwritten instances of any rejected+ -- class is always forbidden+ -- #12837+ ; failIfTc (clas_nm `elem` rejectedClassNames) clas_err++ -- Check for hand-written Generic instances (disallowed in Safe Haskell)+ ; when (clas_nm `elem` genericClassNames) $+ do { failIfTc (safeLanguageOn dflags) gen_inst_err+ ; when (safeInferOn dflags) (recordUnsafeInfer emptyBag) }+ }+ where+ ispec = iSpec inst_info+ binds = iBinds inst_info+ no_binds = isEmptyLHsBinds (ib_binds binds) && null (ib_pragmas binds)+ clas_nm = is_cls_nm ispec+ clas = is_cls ispec++ gen_inst_err = hang (text ("Generic instances can only be "+ ++ "derived in Safe Haskell.") $+$+ text "Replace the following instance:")+ 2 (pprInstanceHdr ispec)++ abstractClassInstErr =+ text "Cannot define instance for abstract class" <+> quotes (ppr clas_nm)++ -- Report an error or a warning for certain class instances.+ -- If we are working on an .hs-boot file, we just report a warning,+ -- and ignore the instance. We do this, to give users a chance to fix+ -- their code.+ rejectedClassNames = [ typeableClassName+ , knownNatClassName+ , knownSymbolClassName ]+ clas_err = text "Class" <+> quotes (ppr clas_nm)+ <+> text "does not support user-specified instances"++{-+************************************************************************+* *+ Type checking family instances+* *+************************************************************************++Family instances are somewhat of a hybrid. They are processed together with+class instance heads, but can contain data constructors and hence they share a+lot of kinding and type checking code with ordinary algebraic data types (and+GADTs).+-}++tcFamInstDeclCombined :: Maybe ClsInstInfo+ -> Located Name -> TcM TyCon+tcFamInstDeclCombined mb_clsinfo fam_tc_lname+ = do { -- Type family instances require -XTypeFamilies+ -- and can't (currently) be in an hs-boot file+ ; traceTc "tcFamInstDecl" (ppr fam_tc_lname)+ ; type_families <- xoptM LangExt.TypeFamilies+ ; is_boot <- tcIsHsBootOrSig -- Are we compiling an hs-boot file?+ ; checkTc type_families $ badFamInstDecl fam_tc_lname+ ; checkTc (not is_boot) $ badBootFamInstDeclErr++ -- Look up the family TyCon and check for validity including+ -- check that toplevel type instances are not for associated types.+ ; fam_tc <- tcLookupLocatedTyCon fam_tc_lname+ ; when (isNothing mb_clsinfo && -- Not in a class decl+ isTyConAssoc fam_tc) -- but an associated type+ (addErr $ assocInClassErr fam_tc_lname)++ ; return fam_tc }++tcTyFamInstDecl :: Maybe ClsInstInfo+ -> LTyFamInstDecl Name -> TcM FamInst+ -- "type instance"+tcTyFamInstDecl mb_clsinfo (L loc decl@(TyFamInstDecl { tfid_eqn = eqn }))+ = setSrcSpan loc $+ tcAddTyFamInstCtxt decl $+ do { let fam_lname = tfe_tycon (unLoc eqn)+ ; fam_tc <- tcFamInstDeclCombined mb_clsinfo fam_lname++ -- (0) Check it's an open type family+ ; checkTc (isFamilyTyCon fam_tc) (notFamily fam_tc)+ ; checkTc (isTypeFamilyTyCon fam_tc) (wrongKindOfFamily fam_tc)+ ; checkTc (isOpenTypeFamilyTyCon fam_tc) (notOpenFamily fam_tc)++ -- (1) do the work of verifying the synonym group+ ; co_ax_branch <- tcTyFamInstEqn (famTyConShape fam_tc) mb_clsinfo eqn++ -- (2) check for validity+ ; checkValidCoAxBranch mb_clsinfo fam_tc co_ax_branch++ -- (3) construct coercion axiom+ ; rep_tc_name <- newFamInstAxiomName fam_lname [coAxBranchLHS co_ax_branch]+ ; let axiom = mkUnbranchedCoAxiom rep_tc_name fam_tc co_ax_branch+ ; newFamInst SynFamilyInst axiom }++tcDataFamInstDecl :: Maybe ClsInstInfo+ -> LDataFamInstDecl Name -> TcM (FamInst, Maybe DerivInfo)+ -- "newtype instance" and "data instance"+tcDataFamInstDecl mb_clsinfo+ (L loc decl@(DataFamInstDecl+ { dfid_pats = pats+ , dfid_tycon = fam_tc_name+ , dfid_defn = defn@HsDataDefn { dd_ND = new_or_data, dd_cType = cType+ , dd_ctxt = ctxt, dd_cons = cons+ , dd_derivs = derivs } }))+ = setSrcSpan loc $+ tcAddDataFamInstCtxt decl $+ do { fam_tc <- tcFamInstDeclCombined mb_clsinfo fam_tc_name++ -- Check that the family declaration is for the right kind+ ; checkTc (isFamilyTyCon fam_tc) (notFamily fam_tc)+ ; checkTc (isDataFamilyTyCon fam_tc) (wrongKindOfFamily fam_tc)++ -- Kind check type patterns+ ; tcFamTyPats (famTyConShape fam_tc) mb_clsinfo pats+ (kcDataDefn (unLoc fam_tc_name) pats defn) $+ \tvs pats res_kind ->+ do { stupid_theta <- solveEqualities $ tcHsContext ctxt++ -- Zonk the patterns etc into the Type world+ ; (ze, tvs') <- zonkTyBndrsX emptyZonkEnv tvs+ ; pats' <- zonkTcTypeToTypes ze pats+ ; res_kind' <- zonkTcTypeToType ze res_kind+ ; stupid_theta' <- zonkTcTypeToTypes ze stupid_theta++ ; gadt_syntax <- dataDeclChecks (tyConName fam_tc) new_or_data stupid_theta' cons++ -- Construct representation tycon+ ; rep_tc_name <- newFamInstTyConName fam_tc_name pats'+ ; axiom_name <- newFamInstAxiomName fam_tc_name [pats']++ ; let (eta_pats, etad_tvs) = eta_reduce pats'+ eta_tvs = filterOut (`elem` etad_tvs) tvs'+ full_tvs = eta_tvs ++ etad_tvs+ -- Put the eta-removed tyvars at the end+ -- Remember, tvs' is in arbitrary order (except kind vars are+ -- first, so there is no reason to suppose that the etad_tvs+ -- (obtained from the pats) are at the end (Trac #11148)+ orig_res_ty = mkTyConApp fam_tc pats'++ ; (rep_tc, axiom) <- fixM $ \ ~(rec_rep_tc, _) ->+ do { let ty_binders = mkTyConBindersPreferAnon full_tvs liftedTypeKind+ ; data_cons <- tcConDecls rec_rep_tc+ (ty_binders, orig_res_ty) cons+ ; tc_rhs <- case new_or_data of+ DataType -> return (mkDataTyConRhs data_cons)+ NewType -> ASSERT( not (null data_cons) )+ mkNewTyConRhs rep_tc_name rec_rep_tc (head data_cons)+ -- freshen tyvars+ ; let axiom = mkSingleCoAxiom Representational+ axiom_name eta_tvs [] fam_tc eta_pats+ (mkTyConApp rep_tc (mkTyVarTys eta_tvs))+ parent = DataFamInstTyCon axiom fam_tc pats'+++ -- NB: Use the full_tvs from the pats. See bullet toward+ -- the end of Note [Data type families] in TyCon+ rep_tc = mkAlgTyCon rep_tc_name+ ty_binders liftedTypeKind+ (map (const Nominal) full_tvs)+ (fmap unLoc cType) stupid_theta+ tc_rhs parent+ gadt_syntax+ -- We always assume that indexed types are recursive. Why?+ -- (1) Due to their open nature, we can never be sure that a+ -- further instance might not introduce a new recursive+ -- dependency. (2) They are always valid loop breakers as+ -- they involve a coercion.+ ; return (rep_tc, axiom) }++ -- Remember to check validity; no recursion to worry about here+ -- Check that left-hand sides are ok (mono-types, no type families,+ -- consistent instantiations, etc)+ ; checkValidFamPats mb_clsinfo fam_tc tvs' [] pats'++ -- Result kind must be '*' (otherwise, we have too few patterns)+ ; checkTc (isLiftedTypeKind res_kind') $+ tooFewParmsErr (tyConArity fam_tc)++ ; checkValidTyCon rep_tc++ ; let m_deriv_info = case derivs of+ L _ [] -> Nothing+ L _ preds ->+ Just $ DerivInfo { di_rep_tc = rep_tc+ , di_clauses = preds+ , di_ctxt = tcMkDataFamInstCtxt decl }++ ; fam_inst <- newFamInst (DataFamilyInst rep_tc) axiom+ ; return (fam_inst, m_deriv_info) } }+ where+ eta_reduce :: [Type] -> ([Type], [TyVar])+ -- See Note [Eta reduction for data families] in FamInstEnv+ -- Splits the incoming patterns into two: the [TyVar]+ -- are the patterns that can be eta-reduced away.+ -- e.g. T [a] Int a d c ==> (T [a] Int a, [d,c])+ --+ -- NB: quadratic algorithm, but types are small here+ eta_reduce pats+ = go (reverse pats) []+ go (pat:pats) etad_tvs+ | Just tv <- getTyVar_maybe pat+ , not (tv `elemVarSet` tyCoVarsOfTypes pats)+ = go pats (tv : etad_tvs)+ go pats etad_tvs = (reverse pats, etad_tvs)+++{- *********************************************************************+* *+ Type-checking instance declarations, pass 2+* *+********************************************************************* -}++tcInstDecls2 :: [LTyClDecl Name] -> [InstInfo Name]+ -> TcM (LHsBinds Id)+-- (a) From each class declaration,+-- generate any default-method bindings+-- (b) From each instance decl+-- generate the dfun binding++tcInstDecls2 tycl_decls inst_decls+ = do { -- (a) Default methods from class decls+ let class_decls = filter (isClassDecl . unLoc) tycl_decls+ ; dm_binds_s <- mapM tcClassDecl2 class_decls+ ; let dm_binds = unionManyBags dm_binds_s++ -- (b) instance declarations+ ; let dm_ids = collectHsBindsBinders dm_binds+ -- Add the default method Ids (again)+ -- (they were arready added in TcTyDecls.tcAddImplicits)+ -- See Note [Default methods in the type environment]+ ; inst_binds_s <- tcExtendGlobalValEnv dm_ids $+ mapM tcInstDecl2 inst_decls++ -- Done+ ; return (dm_binds `unionBags` unionManyBags inst_binds_s) }++{- Note [Default methods in the type environment]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The default method Ids are already in the type environment (see Note+[Default method Ids and Template Haskell] in TcTyDcls), BUT they+don't have their InlinePragmas yet. Usually that would not matter,+because the simplifier propagates information from binding site to+use. But, unusually, when compiling instance decls we *copy* the+INLINE pragma from the default method to the method for that+particular operation (see Note [INLINE and default methods] below).++So right here in tcInstDecls2 we must re-extend the type envt with+the default method Ids replete with their INLINE pragmas. Urk.+-}++tcInstDecl2 :: InstInfo Name -> TcM (LHsBinds Id)+ -- Returns a binding for the dfun+tcInstDecl2 (InstInfo { iSpec = ispec, iBinds = ibinds })+ = recoverM (return emptyLHsBinds) $+ setSrcSpan loc $+ addErrCtxt (instDeclCtxt2 (idType dfun_id)) $+ do { -- Instantiate the instance decl with skolem constants+ ; (inst_tyvars, dfun_theta, inst_head) <- tcSkolDFunType dfun_id+ ; dfun_ev_vars <- newEvVars dfun_theta+ -- We instantiate the dfun_id with superSkolems.+ -- See Note [Subtle interaction of recursion and overlap]+ -- and Note [Binding when looking up instances]++ ; let (clas, inst_tys) = tcSplitDFunHead inst_head+ (class_tyvars, sc_theta, _, op_items) = classBigSig clas+ sc_theta' = substTheta (zipTvSubst class_tyvars inst_tys) sc_theta++ ; traceTc "tcInstDecl2" (vcat [ppr inst_tyvars, ppr inst_tys, ppr dfun_theta, ppr sc_theta'])++ -- Deal with 'SPECIALISE instance' pragmas+ -- See Note [SPECIALISE instance pragmas]+ ; spec_inst_info@(spec_inst_prags,_) <- tcSpecInstPrags dfun_id ibinds++ -- Typecheck superclasses and methods+ -- See Note [Typechecking plan for instance declarations]+ ; dfun_ev_binds_var <- newTcEvBinds+ ; let dfun_ev_binds = TcEvBinds dfun_ev_binds_var+ ; ((sc_meth_ids, sc_meth_binds, sc_meth_implics), tclvl)+ <- pushTcLevelM $+ do { (sc_ids, sc_binds, sc_implics)+ <- tcSuperClasses dfun_id clas inst_tyvars dfun_ev_vars+ inst_tys dfun_ev_binds+ sc_theta'++ -- Typecheck the methods+ ; (meth_ids, meth_binds, meth_implics)+ <- tcMethods dfun_id clas inst_tyvars dfun_ev_vars+ inst_tys dfun_ev_binds spec_inst_info+ op_items ibinds++ ; return ( sc_ids ++ meth_ids+ , sc_binds `unionBags` meth_binds+ , sc_implics `unionBags` meth_implics ) }++ ; env <- getLclEnv+ ; emitImplication $ Implic { ic_tclvl = tclvl+ , ic_skols = inst_tyvars+ , ic_no_eqs = False+ , ic_given = dfun_ev_vars+ , ic_wanted = mkImplicWC sc_meth_implics+ , ic_status = IC_Unsolved+ , ic_binds = dfun_ev_binds_var+ , ic_needed = emptyVarSet+ , ic_env = env+ , ic_info = InstSkol }++ -- Create the result bindings+ ; self_dict <- newDict clas inst_tys+ ; let class_tc = classTyCon clas+ [dict_constr] = tyConDataCons class_tc+ dict_bind = mkVarBind self_dict (L loc con_app_args)++ -- We don't produce a binding for the dict_constr; instead we+ -- rely on the simplifier to unfold this saturated application+ -- We do this rather than generate an HsCon directly, because+ -- it means that the special cases (e.g. dictionary with only one+ -- member) are dealt with by the common MkId.mkDataConWrapId+ -- code rather than needing to be repeated here.+ -- con_app_tys = MkD ty1 ty2+ -- con_app_scs = MkD ty1 ty2 sc1 sc2+ -- con_app_args = MkD ty1 ty2 sc1 sc2 op1 op2+ con_app_tys = mkHsWrap (mkWpTyApps inst_tys)+ (HsConLikeOut (RealDataCon dict_constr))+ -- NB: We *can* have covars in inst_tys, in the case of+ -- promoted GADT constructors.++ con_app_args = foldl app_to_meth con_app_tys sc_meth_ids++ app_to_meth :: HsExpr Id -> Id -> HsExpr Id+ app_to_meth fun meth_id = L loc fun `HsApp` L loc (wrapId arg_wrapper meth_id)++ inst_tv_tys = mkTyVarTys inst_tyvars+ arg_wrapper = mkWpEvVarApps dfun_ev_vars <.> mkWpTyApps inst_tv_tys++ is_newtype = isNewTyCon class_tc+ dfun_id_w_prags = addDFunPrags dfun_id sc_meth_ids+ dfun_spec_prags+ | is_newtype = SpecPrags []+ | otherwise = SpecPrags spec_inst_prags+ -- Newtype dfuns just inline unconditionally,+ -- so don't attempt to specialise them++ export = ABE { abe_wrap = idHsWrapper+ , abe_poly = dfun_id_w_prags+ , abe_mono = self_dict+ , abe_prags = dfun_spec_prags }+ -- NB: see Note [SPECIALISE instance pragmas]+ main_bind = AbsBinds { abs_tvs = inst_tyvars+ , abs_ev_vars = dfun_ev_vars+ , abs_exports = [export]+ , abs_ev_binds = []+ , abs_binds = unitBag dict_bind }++ ; return (unitBag (L loc main_bind) `unionBags` sc_meth_binds)+ }+ where+ dfun_id = instanceDFunId ispec+ loc = getSrcSpan dfun_id++addDFunPrags :: DFunId -> [Id] -> DFunId+-- DFuns need a special Unfolding and InlinePrag+-- See Note [ClassOp/DFun selection]+-- and Note [Single-method classes]+-- It's easiest to create those unfoldings right here, where+-- have all the pieces in hand, even though we are messing with+-- Core at this point, which the typechecker doesn't usually do+-- However we take care to build the unfolding using the TyVars from+-- the DFunId rather than from the skolem pieces that the typechecker+-- is messing with.+addDFunPrags dfun_id sc_meth_ids+ | is_newtype+ = dfun_id `setIdUnfolding` mkInlineUnfoldingWithArity 0 con_app+ `setInlinePragma` alwaysInlinePragma { inl_sat = Just 0 }+ | otherwise+ = dfun_id `setIdUnfolding` mkDFunUnfolding dfun_bndrs dict_con dict_args+ `setInlinePragma` dfunInlinePragma+ 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 [Levity polymorphism checking] in DsMonad+ dict_args = map Type inst_tys +++ [mkVarApps (Var id) dfun_bndrs | id <- sc_meth_ids]++ (dfun_tvs, dfun_theta, clas, inst_tys) = tcSplitDFunTy (idType dfun_id)+ ev_ids = mkTemplateLocalsNum 1 dfun_theta+ dfun_bndrs = dfun_tvs ++ ev_ids+ clas_tc = classTyCon clas+ [dict_con] = tyConDataCons clas_tc+ is_newtype = isNewTyCon clas_tc++wrapId :: HsWrapper -> id -> HsExpr id+wrapId wrapper id = mkHsWrap wrapper (HsVar (noLoc id))++{- Note [Typechecking plan for instance declarations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For instance declarations we generate the following bindings and implication+constraints. Example:++ instance Ord a => Ord [a] where compare = <compare-rhs>++generates this:++ Bindings:+ -- Method bindings+ $ccompare :: forall a. Ord a => a -> a -> Ordering+ $ccompare = /\a \(d:Ord a). let <meth-ev-binds> in ...++ -- Superclass bindings+ $cp1Ord :: forall a. Ord a => Eq [a]+ $cp1Ord = /\a \(d:Ord a). let <sc-ev-binds>+ in dfEqList (dw :: Eq a)++ Constraints:+ forall a. Ord a =>+ -- Method constraint+ (forall. (empty) => <constraints from compare-rhs>)+ -- Superclass constraint+ /\ (forall. (empty) => dw :: Eq a)++Notice that++ * Per-meth/sc implication. There is one inner implication per+ superclass or method, with no skolem variables or givens. The only+ reason for this one is to gather the evidence bindings privately+ for this superclass or method. This implication is generated+ by checkInstConstraints.++ * Overall instance implication. There is an overall enclosing+ implication for the whole instance declaratation, with the expected+ skolems and givens. We need this to get the correct "redundant+ constraint" warnings, gathering all the uses from all the methods+ and superclasses. See TcSimplify Note [Tracking redundant+ constraints]++ * The given constraints in the outer implication may generate+ evidence, notably by superclass selection. Since the method and+ superclass bindings are top-level, we want that evidence copied+ into *every* method or superclass definition. (Some of it will+ be usused in some, but dead-code elimination will drop it.)++ We achieve this by putting the the evidence variable for the overall+ instance implication into the AbsBinds for each method/superclass.+ Hence the 'dfun_ev_binds' passed into tcMethods and tcSuperClasses.+ (And that in turn is why the abs_ev_binds field of AbBinds is a+ [TcEvBinds] rather than simply TcEvBinds.++ This is a bit of a hack, but works very nicely in practice.++ * Note that if a method has a locally-polymorphic binding, there will+ be yet another implication for that, generated by tcPolyCheck+ in tcMethodBody. E.g.+ class C a where+ foo :: forall b. Ord b => blah+++************************************************************************+* *+ Type-checking superclasses+* *+************************************************************************+-}++tcSuperClasses :: DFunId -> Class -> [TcTyVar] -> [EvVar] -> [TcType]+ -> TcEvBinds+ -> TcThetaType+ -> TcM ([EvVar], LHsBinds Id, Bag Implication)+-- Make a new top-level function binding for each superclass,+-- something like+-- $Ordp1 :: forall a. Ord a => Eq [a]+-- $Ordp1 = /\a \(d:Ord a). dfunEqList a (sc_sel d)+--+-- See Note [Recursive superclasses] for why this is so hard!+-- In effect, we build a special-purpose solver for the first step+-- of solving each superclass constraint+tcSuperClasses dfun_id cls tyvars dfun_evs inst_tys dfun_ev_binds sc_theta+ = do { (ids, binds, implics) <- mapAndUnzip3M tc_super (zip sc_theta [fIRST_TAG..])+ ; return (ids, listToBag binds, listToBag implics) }+ where+ loc = getSrcSpan dfun_id+ size = sizeTypes inst_tys+ tc_super (sc_pred, n)+ = do { (sc_implic, ev_binds_var, sc_ev_tm)+ <- checkInstConstraints $ emitWanted (ScOrigin size) sc_pred++ ; sc_top_name <- newName (mkSuperDictAuxOcc n (getOccName cls))+ ; sc_ev_id <- newEvVar sc_pred+ ; addTcEvBind ev_binds_var $ mkWantedEvBind sc_ev_id sc_ev_tm+ ; let sc_top_ty = mkInvForAllTys tyvars (mkLamTypes dfun_evs sc_pred)+ sc_top_id = mkLocalId sc_top_name sc_top_ty+ export = ABE { abe_wrap = idHsWrapper+ , abe_poly = sc_top_id+ , abe_mono = sc_ev_id+ , abe_prags = noSpecPrags }+ local_ev_binds = TcEvBinds ev_binds_var+ bind = AbsBinds { abs_tvs = tyvars+ , abs_ev_vars = dfun_evs+ , abs_exports = [export]+ , abs_ev_binds = [dfun_ev_binds, local_ev_binds]+ , abs_binds = emptyBag }+ ; return (sc_top_id, L loc bind, sc_implic) }++-------------------+checkInstConstraints :: TcM result+ -> TcM (Implication, EvBindsVar, result)+-- See Note [Typechecking plan for instance declarations]+checkInstConstraints thing_inside+ = do { (tclvl, wanted, result) <- pushLevelAndCaptureConstraints $+ thing_inside++ ; ev_binds_var <- newTcEvBinds+ ; env <- getLclEnv+ ; let implic = Implic { ic_tclvl = tclvl+ , ic_skols = []+ , ic_no_eqs = False+ , ic_given = []+ , ic_wanted = wanted+ , ic_status = IC_Unsolved+ , ic_binds = ev_binds_var+ , ic_needed = emptyVarSet+ , ic_env = env+ , ic_info = InstSkol }++ ; return (implic, ev_binds_var, result) }++{-+Note [Recursive superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See Trac #3731, #4809, #5751, #5913, #6117, #6161, which all+describe somewhat more complicated situations, but ones+encountered in practice.++See also tests tcrun020, tcrun021, tcrun033, and Trac #11427.++----- THE PROBLEM --------+The problem is that it is all too easy to create a class whose+superclass is bottom when it should not be.++Consider the following (extreme) situation:+ class C a => D a where ...+ instance D [a] => D [a] where ... (dfunD)+ instance C [a] => C [a] where ... (dfunC)+Although this looks wrong (assume D [a] to prove D [a]), it is only a+more extreme case of what happens with recursive dictionaries, and it+can, just about, make sense because the methods do some work before+recursing.++To implement the dfunD we must generate code for the superclass C [a],+which we had better not get by superclass selection from the supplied+argument:+ dfunD :: forall a. D [a] -> D [a]+ dfunD = \d::D [a] -> MkD (scsel d) ..++Otherwise if we later encounter a situation where+we have a [Wanted] dw::D [a] we might solve it thus:+ dw := dfunD dw+Which is all fine except that now ** the superclass C is bottom **!++The instance we want is:+ dfunD :: forall a. D [a] -> D [a]+ dfunD = \d::D [a] -> MkD (dfunC (scsel d)) ...++----- THE SOLUTION --------+The basic solution is simple: be very careful about using superclass+selection to generate a superclass witness in a dictionary function+definition. More precisely:++ Superclass Invariant: in every class dictionary,+ every superclass dictionary field+ is non-bottom++To achieve the Superclass Invariant, in a dfun definition we can+generate a guaranteed-non-bottom superclass witness from:+ (sc1) one of the dictionary arguments itself (all non-bottom)+ (sc2) an immediate superclass of a smaller dictionary+ (sc3) a call of a dfun (always returns a dictionary constructor)++The tricky case is (sc2). We proceed by induction on the size of+the (type of) the dictionary, defined by TcValidity.sizeTypes.+Let's suppose we are building a dictionary of size 3, and+suppose the Superclass Invariant holds of smaller dictionaries.+Then if we have a smaller dictionary, its immediate superclasses+will be non-bottom by induction.++What does "we have a smaller dictionary" mean? It might be+one of the arguments of the instance, or one of its superclasses.+Here is an example, taken from CmmExpr:+ class Ord r => UserOfRegs r a where ...+(i1) instance UserOfRegs r a => UserOfRegs r (Maybe a) where+(i2) instance (Ord r, UserOfRegs r CmmReg) => UserOfRegs r CmmExpr where++For (i1) we can get the (Ord r) superclass by selection from (UserOfRegs r a),+since it is smaller than the thing we are building (UserOfRegs r (Maybe a).++But for (i2) that isn't the case, so we must add an explicit, and+perhaps surprising, (Ord r) argument to the instance declaration.++Here's another example from Trac #6161:++ class Super a => Duper a where ...+ class Duper (Fam a) => Foo a where ...+(i3) instance Foo a => Duper (Fam a) where ...+(i4) instance Foo Float where ...++It would be horribly wrong to define+ dfDuperFam :: Foo a -> Duper (Fam a) -- from (i3)+ dfDuperFam d = MkDuper (sc_sel1 (sc_sel2 d)) ...++ dfFooFloat :: Foo Float -- from (i4)+ dfFooFloat = MkFoo (dfDuperFam dfFooFloat) ...++Now the Super superclass of Duper is definitely bottom!++This won't happen because when processing (i3) we can use the+superclasses of (Foo a), which is smaller, namely Duper (Fam a). But+that is *not* smaller than the target so we can't take *its*+superclasses. As a result the program is rightly rejected, unless you+add (Super (Fam a)) to the context of (i3).++Note [Solving superclass constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+How do we ensure that every superclass witness is generated by+one of (sc1) (sc2) or (sc3) in Note [Recursive superclasses].+Answer:++ * Superclass "wanted" constraints have CtOrigin of (ScOrigin size)+ where 'size' is the size of the instance declaration. e.g.+ class C a => D a where...+ instance blah => D [a] where ...+ The wanted superclass constraint for C [a] has origin+ ScOrigin size, where size = size( D [a] ).++ * (sc1) When we rewrite such a wanted constraint, it retains its+ origin. But if we apply an instance declaration, we can set the+ origin to (ScOrigin infinity), thus lifting any restrictions by+ making prohibitedSuperClassSolve return False.++ * (sc2) ScOrigin wanted constraints can't be solved from a+ superclass selection, except at a smaller type. This test is+ implemented by TcInteract.prohibitedSuperClassSolve++ * The "given" constraints of an instance decl have CtOrigin+ GivenOrigin InstSkol.++ * When we make a superclass selection from InstSkol we use+ a SkolemInfo of (InstSC size), where 'size' is the size of+ the constraint whose superclass we are taking. An similarly+ when taking the superclass of an InstSC. This is implemented+ in TcCanonical.newSCWorkFromFlavored++Note [Silent superclass arguments] (historical interest only)+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+NB1: this note describes our *old* solution to the+ recursive-superclass problem. I'm keeping the Note+ for now, just as institutional memory.+ However, the code for silent superclass arguments+ was removed in late Dec 2014++NB2: the silent-superclass solution introduced new problems+ of its own, in the form of instance overlap. Tests+ SilentParametersOverlapping, T5051, and T7862 are examples++NB3: the silent-superclass solution also generated tons of+ extra dictionaries. For example, in monad-transformer+ code, when constructing a Monad dictionary you had to pass+ an Applicative dictionary; and to construct that you neede+ a Functor dictionary. Yet these extra dictionaries were+ often never used. Test T3064 compiled *far* faster after+ silent superclasses were eliminated.++Our solution to this problem "silent superclass arguments". We pass+to each dfun some ``silent superclass arguments’’, which are the+immediate superclasses of the dictionary we are trying to+construct. In our example:+ dfun :: forall a. C [a] -> D [a] -> D [a]+ dfun = \(dc::C [a]) (dd::D [a]) -> DOrd dc ...+Notice the extra (dc :: C [a]) argument compared to the previous version.++This gives us:++ -----------------------------------------------------------+ DFun Superclass Invariant+ ~~~~~~~~~~~~~~~~~~~~~~~~+ In the body of a DFun, every superclass argument to the+ returned dictionary is+ either * one of the arguments of the DFun,+ or * constant, bound at top level+ -----------------------------------------------------------++This net effect is that it is safe to treat a dfun application as+wrapping a dictionary constructor around its arguments (in particular,+a dfun never picks superclasses from the arguments under the+dictionary constructor). No superclass is hidden inside a dfun+application.++The extra arguments required to satisfy the DFun Superclass Invariant+always come first, and are called the "silent" arguments. You can+find out how many silent arguments there are using Id.dfunNSilent;+and then you can just drop that number of arguments to see the ones+that were in the original instance declaration.++DFun types are built (only) by MkId.mkDictFunId, so that is where we+decide what silent arguments are to be added.+-}++{-+************************************************************************+* *+ Type-checking an instance method+* *+************************************************************************++tcMethod+- Make the method bindings, as a [(NonRec, HsBinds)], one per method+- Remembering to use fresh Name (the instance method Name) as the binder+- Bring the instance method Ids into scope, for the benefit of tcInstSig+- Use sig_fn mapping instance method Name -> instance tyvars+- Ditto prag_fn+- Use tcValBinds to do the checking+-}++tcMethods :: DFunId -> Class+ -> [TcTyVar] -> [EvVar]+ -> [TcType]+ -> TcEvBinds+ -> ([Located TcSpecPrag], TcPragEnv)+ -> [ClassOpItem]+ -> InstBindings Name+ -> TcM ([Id], LHsBinds Id, Bag Implication)+ -- The returned inst_meth_ids all have types starting+ -- forall tvs. theta => ...+tcMethods dfun_id clas tyvars dfun_ev_vars inst_tys+ dfun_ev_binds (spec_inst_prags, prag_fn) op_items+ (InstBindings { ib_binds = binds+ , ib_tyvars = lexical_tvs+ , ib_pragmas = sigs+ , ib_extensions = exts+ , ib_derived = is_derived })+ = tcExtendTyVarEnv2 (lexical_tvs `zip` tyvars) $+ -- The lexical_tvs scope over the 'where' part+ do { traceTc "tcInstMeth" (ppr sigs $$ ppr binds)+ ; checkMinimalDefinition+ ; (ids, binds, mb_implics) <- set_exts exts $+ mapAndUnzip3M tc_item op_items+ ; return (ids, listToBag binds, listToBag (catMaybes mb_implics)) }+ where+ set_exts :: [LangExt.Extension] -> TcM a -> TcM a+ set_exts es thing = foldr setXOptM thing es++ hs_sig_fn = mkHsSigFun sigs+ inst_loc = getSrcSpan dfun_id++ ----------------------+ tc_item :: ClassOpItem -> TcM (Id, LHsBind Id, Maybe Implication)+ tc_item (sel_id, dm_info)+ | Just (user_bind, bndr_loc, prags) <- findMethodBind (idName sel_id) binds prag_fn+ = tcMethodBody clas tyvars dfun_ev_vars inst_tys+ dfun_ev_binds is_derived hs_sig_fn+ spec_inst_prags prags+ sel_id user_bind bndr_loc+ | otherwise+ = do { traceTc "tc_def" (ppr sel_id)+ ; tc_default sel_id dm_info }++ ----------------------+ tc_default :: Id -> DefMethInfo -> TcM (TcId, LHsBind Id, Maybe Implication)++ tc_default sel_id (Just (dm_name, _))+ = do { (meth_bind, inline_prags) <- mkDefMethBind clas inst_tys sel_id dm_name+ ; tcMethodBody clas tyvars dfun_ev_vars inst_tys+ dfun_ev_binds is_derived hs_sig_fn+ spec_inst_prags inline_prags+ sel_id meth_bind inst_loc }++ tc_default sel_id Nothing -- No default method at all+ = do { traceTc "tc_def: warn" (ppr sel_id)+ ; (meth_id, _) <- mkMethIds clas tyvars dfun_ev_vars+ inst_tys sel_id+ ; dflags <- getDynFlags+ ; let meth_bind = mkVarBind meth_id $+ mkLHsWrap lam_wrapper (error_rhs dflags)+ ; return (meth_id, meth_bind, Nothing) }+ where+ error_rhs dflags = L inst_loc $ HsApp error_fun (error_msg dflags)+ error_fun = L inst_loc $+ wrapId (mkWpTyApps+ [ getRuntimeRep "tcInstanceMethods.tc_default" meth_tau+ , meth_tau])+ nO_METHOD_BINDING_ERROR_ID+ error_msg dflags = L inst_loc (HsLit (HsStringPrim NoSourceText+ (unsafeMkByteString (error_string dflags))))+ meth_tau = funResultTy (piResultTys (idType sel_id) inst_tys)+ error_string dflags = showSDoc dflags+ (hcat [ppr inst_loc, vbar, ppr sel_id ])+ lam_wrapper = mkWpTyLams tyvars <.> mkWpLams dfun_ev_vars++ ----------------------+ -- Check if one of the minimal complete definitions is satisfied+ checkMinimalDefinition+ = whenIsJust (isUnsatisfied methodExists (classMinimalDef clas)) $+ warnUnsatisfiedMinimalDefinition++ methodExists meth = isJust (findMethodBind meth binds prag_fn)++------------------------+tcMethodBody :: Class -> [TcTyVar] -> [EvVar] -> [TcType]+ -> TcEvBinds -> Bool+ -> HsSigFun+ -> [LTcSpecPrag] -> [LSig Name]+ -> Id -> LHsBind Name -> SrcSpan+ -> TcM (TcId, LHsBind Id, Maybe Implication)+tcMethodBody clas tyvars dfun_ev_vars inst_tys+ dfun_ev_binds is_derived+ sig_fn spec_inst_prags prags+ sel_id (L bind_loc meth_bind) bndr_loc+ = add_meth_ctxt $+ do { traceTc "tcMethodBody" (ppr sel_id <+> ppr (idType sel_id) $$ ppr bndr_loc)+ ; (global_meth_id, local_meth_id) <- setSrcSpan bndr_loc $+ mkMethIds clas tyvars dfun_ev_vars+ inst_tys sel_id++ ; let lm_bind = meth_bind { fun_id = L bndr_loc (idName local_meth_id) }+ -- Substitute the local_meth_name for the binder+ -- NB: the binding is always a FunBind++ -- taking instance signature into account might change the type of+ -- the local_meth_id+ ; (meth_implic, ev_binds_var, tc_bind)+ <- checkInstConstraints $+ tcMethodBodyHelp sig_fn sel_id local_meth_id (L bind_loc lm_bind)++ ; global_meth_id <- addInlinePrags global_meth_id prags+ ; spec_prags <- tcSpecPrags global_meth_id prags++ ; let specs = mk_meth_spec_prags global_meth_id spec_inst_prags spec_prags+ export = ABE { abe_poly = global_meth_id+ , abe_mono = local_meth_id+ , abe_wrap = idHsWrapper+ , abe_prags = specs }++ local_ev_binds = TcEvBinds ev_binds_var+ full_bind = AbsBinds { abs_tvs = tyvars+ , abs_ev_vars = dfun_ev_vars+ , abs_exports = [export]+ , abs_ev_binds = [dfun_ev_binds, local_ev_binds]+ , abs_binds = tc_bind }++ ; return (global_meth_id, L bind_loc full_bind, Just meth_implic) }+ where+ -- For instance decls that come from deriving clauses+ -- we want to print out the full source code if there's an error+ -- because otherwise the user won't see the code at all+ add_meth_ctxt thing+ | is_derived = addLandmarkErrCtxt (derivBindCtxt sel_id clas inst_tys) thing+ | otherwise = thing++tcMethodBodyHelp :: HsSigFun -> Id -> TcId+ -> LHsBind Name -> TcM (LHsBinds TcId)+tcMethodBodyHelp hs_sig_fn sel_id local_meth_id meth_bind+ | Just hs_sig_ty <- hs_sig_fn sel_name+ -- There is a signature in the instance+ -- See Note [Instance method signatures]+ = do { let ctxt = FunSigCtxt sel_name True+ ; (sig_ty, hs_wrap)+ <- setSrcSpan (getLoc (hsSigType hs_sig_ty)) $+ do { inst_sigs <- xoptM LangExt.InstanceSigs+ ; checkTc inst_sigs (misplacedInstSig sel_name hs_sig_ty)+ ; sig_ty <- tcHsSigType (FunSigCtxt sel_name False) hs_sig_ty+ ; let local_meth_ty = idType local_meth_id+ ; hs_wrap <- addErrCtxtM (methSigCtxt sel_name sig_ty local_meth_ty) $+ tcSubType_NC ctxt sig_ty local_meth_ty+ ; return (sig_ty, hs_wrap) }++ ; inner_meth_name <- newName (nameOccName sel_name)+ ; let inner_meth_id = mkLocalId inner_meth_name sig_ty+ inner_meth_sig = CompleteSig { sig_bndr = inner_meth_id+ , sig_ctxt = ctxt+ , sig_loc = getLoc (hsSigType hs_sig_ty) }+++ ; (tc_bind, [inner_id]) <- tcPolyCheck no_prag_fn inner_meth_sig meth_bind++ ; let export = ABE { abe_poly = local_meth_id+ , abe_mono = inner_id+ , abe_wrap = hs_wrap+ , abe_prags = noSpecPrags }++ ; return (unitBag $ L (getLoc meth_bind) $+ AbsBinds { abs_tvs = [], abs_ev_vars = []+ , abs_exports = [export]+ , abs_binds = tc_bind, abs_ev_binds = [] }) }++ | otherwise -- No instance signature+ = do { let ctxt = FunSigCtxt sel_name False+ -- False <=> don't report redundant constraints+ -- The signature is not under the users control!+ tc_sig = completeSigFromId ctxt local_meth_id+ -- Absent a type sig, there are no new scoped type variables here+ -- Only the ones from the instance decl itself, which are already+ -- in scope. Example:+ -- class C a where { op :: forall b. Eq b => ... }+ -- instance C [c] where { op = <rhs> }+ -- In <rhs>, 'c' is scope but 'b' is not!++ ; (tc_bind, _) <- tcPolyCheck no_prag_fn tc_sig meth_bind+ ; return tc_bind }++ where+ sel_name = idName sel_id+ no_prag_fn = emptyPragEnv -- No pragmas for local_meth_id;+ -- they are all for meth_id+++------------------------+mkMethIds :: Class -> [TcTyVar] -> [EvVar]+ -> [TcType] -> Id -> TcM (TcId, TcId)+ -- returns (poly_id, local_id), but ignoring any instance signature+ -- See Note [Instance method signatures]+mkMethIds clas tyvars dfun_ev_vars inst_tys sel_id+ = do { poly_meth_name <- newName (mkClassOpAuxOcc sel_occ)+ ; local_meth_name <- newName sel_occ+ -- Base the local_meth_name on the selector name, because+ -- type errors from tcMethodBody come from here+ ; let poly_meth_id = mkLocalId poly_meth_name poly_meth_ty+ local_meth_id = mkLocalId local_meth_name local_meth_ty++ ; return (poly_meth_id, local_meth_id) }+ where+ sel_name = idName sel_id+ sel_occ = nameOccName sel_name+ local_meth_ty = instantiateMethod clas sel_id inst_tys+ poly_meth_ty = mkSpecSigmaTy tyvars theta local_meth_ty+ theta = map idType dfun_ev_vars++methSigCtxt :: Name -> TcType -> TcType -> TidyEnv -> TcM (TidyEnv, MsgDoc)+methSigCtxt sel_name sig_ty meth_ty env0+ = do { (env1, sig_ty) <- zonkTidyTcType env0 sig_ty+ ; (env2, meth_ty) <- zonkTidyTcType env1 meth_ty+ ; let msg = hang (text "When checking that instance signature for" <+> quotes (ppr sel_name))+ 2 (vcat [ text "is more general than its signature in the class"+ , text "Instance sig:" <+> ppr sig_ty+ , text " Class sig:" <+> ppr meth_ty ])+ ; return (env2, msg) }++misplacedInstSig :: Name -> LHsSigType Name -> SDoc+misplacedInstSig name hs_ty+ = vcat [ hang (text "Illegal type signature in instance declaration:")+ 2 (hang (pprPrefixName name)+ 2 (dcolon <+> ppr hs_ty))+ , text "(Use InstanceSigs to allow this)" ]++{- Note [Instance method signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+With -XInstanceSigs we allow the user to supply a signature for the+method in an instance declaration. Here is an artificial example:++ data T a = MkT a+ instance Ord a => Ord (T a) where+ (>) :: forall b. b -> b -> Bool+ (>) = error "You can't compare Ts"++The instance signature can be *more* polymorphic than the instantiated+class method (in this case: Age -> Age -> Bool), but it cannot be less+polymorphic. Moreover, if a signature is given, the implementation+code should match the signature, and type variables bound in the+singature should scope over the method body.++We achieve this by building a TcSigInfo for the method, whether or not+there is an instance method signature, and using that to typecheck+the declaration (in tcMethodBody). That means, conveniently,+that the type variables bound in the signature will scope over the body.++What about the check that the instance method signature is more+polymorphic than the instantiated class method type? We just do a+tcSubType call in tcMethodBodyHelp, and generate a nested AbsBind, like+this (for the example above++ AbsBind { abs_tvs = [a], abs_ev_vars = [d:Ord a]+ , abs_exports+ = ABExport { (>) :: forall a. Ord a => T a -> T a -> Bool+ , gr_lcl :: T a -> T a -> Bool }+ , abs_binds+ = AbsBind { abs_tvs = [], abs_ev_vars = []+ , abs_exports = ABExport { gr_lcl :: T a -> T a -> Bool+ , gr_inner :: forall b. b -> b -> Bool }+ , abs_binds = AbsBind { abs_tvs = [b], abs_ev_vars = []+ , ..etc.. }+ } }++Wow! Three nested AbsBinds!+ * The outer one abstracts over the tyvars and dicts for the instance+ * The middle one is only present if there is an instance signature,+ and does the impedance matching for that signature+ * The inner one is for the method binding itself against either the+ signature from the class, or the the instance signature.+-}++----------------------+mk_meth_spec_prags :: Id -> [LTcSpecPrag] -> [LTcSpecPrag] -> TcSpecPrags+ -- Adapt the 'SPECIALISE instance' pragmas to work for this method Id+ -- There are two sources:+ -- * spec_prags_for_me: {-# SPECIALISE op :: <blah> #-}+ -- * spec_prags_from_inst: derived from {-# SPECIALISE instance :: <blah> #-}+ -- These ones have the dfun inside, but [perhaps surprisingly]+ -- the correct wrapper.+ -- See Note [Handling SPECIALISE pragmas] in TcBinds+mk_meth_spec_prags meth_id spec_inst_prags spec_prags_for_me+ = SpecPrags (spec_prags_for_me ++ spec_prags_from_inst)+ where+ spec_prags_from_inst+ | isInlinePragma (idInlinePragma meth_id)+ = [] -- Do not inherit SPECIALISE from the instance if the+ -- method is marked INLINE, because then it'll be inlined+ -- and the specialisation would do nothing. (Indeed it'll provoke+ -- a warning from the desugarer+ | otherwise+ = [ L inst_loc (SpecPrag meth_id wrap inl)+ | L inst_loc (SpecPrag _ wrap inl) <- spec_inst_prags]+++mkDefMethBind :: Class -> [Type] -> Id -> Name -> TcM (LHsBind Name, [LSig Name])+-- The is a default method (vanailla or generic) defined in the class+-- So make a binding op = $dmop @t1 @t2+-- where $dmop is the name of the default method in the class,+-- and t1,t2 are the instance types.+-- See Note [Default methods in instances] for why we use+-- visible type application here+mkDefMethBind clas inst_tys sel_id dm_name+ = do { dflags <- getDynFlags+ ; dm_id <- tcLookupId dm_name+ ; let inline_prag = idInlinePragma dm_id+ inline_prags | isAnyInlinePragma inline_prag+ = [noLoc (InlineSig fn inline_prag)]+ | otherwise+ = []+ -- Copy the inline pragma (if any) from the default method+ -- to this version. Note [INLINE and default methods]++ fn = noLoc (idName sel_id)+ visible_inst_tys = [ ty | (tcb, ty) <- tyConBinders (classTyCon clas) `zip` inst_tys+ , tyConBinderArgFlag tcb /= Inferred ]+ rhs = foldl mk_vta (nlHsVar dm_name) visible_inst_tys+ bind = noLoc $ mkTopFunBind Generated fn $+ [mkSimpleMatch (mkPrefixFunRhs fn) [] rhs]++ ; liftIO (dumpIfSet_dyn dflags Opt_D_dump_deriv "Filling in method body"+ (vcat [ppr clas <+> ppr inst_tys,+ nest 2 (ppr sel_id <+> equals <+> ppr rhs)]))++ ; return (bind, inline_prags) }+ where+ mk_vta :: LHsExpr Name -> Type -> LHsExpr Name+ mk_vta fun ty = noLoc (HsAppType fun (mkEmptyWildCardBndrs $ noLoc $ HsCoreTy ty))+ -- NB: use visible type application+ -- See Note [Default methods in instances]++----------------------+derivBindCtxt :: Id -> Class -> [Type ] -> SDoc+derivBindCtxt sel_id clas tys+ = vcat [ text "When typechecking the code for" <+> quotes (ppr sel_id)+ , nest 2 (text "in a derived instance for"+ <+> quotes (pprClassPred clas tys) <> colon)+ , nest 2 $ text "To see the code I am typechecking, use -ddump-deriv" ]++warnUnsatisfiedMinimalDefinition :: ClassMinimalDef -> TcM ()+warnUnsatisfiedMinimalDefinition mindef+ = do { warn <- woptM Opt_WarnMissingMethods+ ; warnTc (Reason Opt_WarnMissingMethods) warn message+ }+ where+ message = vcat [text "No explicit implementation for"+ ,nest 2 $ pprBooleanFormulaNice mindef+ ]++{-+Note [Export helper functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We arrange to export the "helper functions" of an instance declaration,+so that they are not subject to preInlineUnconditionally, even if their+RHS is trivial. Reason: they are mentioned in the DFunUnfolding of+the dict fun as Ids, not as CoreExprs, so we can't substitute a+non-variable for them.++We could change this by making DFunUnfoldings have CoreExprs, but it+seems a bit simpler this way.++Note [Default methods in instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this++ class Baz v x where+ foo :: x -> x+ foo y = <blah>++ instance Baz Int Int++From the class decl we get++ $dmfoo :: forall v x. Baz v x => x -> x+ $dmfoo y = <blah>++Notice that the type is ambiguous. So we use Visible Type Application+to disambiguate:++ $dBazIntInt = MkBaz fooIntInt+ fooIntInt = $dmfoo @Int @Int++Lacking VTA we'd get ambiguity errors involving the default method. This applies+equally to vanilla default methods (Trac #1061) and generic default methods+(Trac #12220).++Historical note: before we had VTA we had to generate+post-type-checked code, which took a lot more code, and didn't work for+generic default methods.++Note [INLINE and default methods]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Default methods need special case. They are supposed to behave rather like+macros. For exmample++ class Foo a where+ op1, op2 :: Bool -> a -> a++ {-# INLINE op1 #-}+ op1 b x = op2 (not b) x++ instance Foo Int where+ -- op1 via default method+ op2 b x = <blah>++The instance declaration should behave++ just as if 'op1' had been defined with the+ code, and INLINE pragma, from its original+ definition.++That is, just as if you'd written++ instance Foo Int where+ op2 b x = <blah>++ {-# INLINE op1 #-}+ op1 b x = op2 (not b) x++So for the above example we generate:++ {-# INLINE $dmop1 #-}+ -- $dmop1 has an InlineCompulsory unfolding+ $dmop1 d b x = op2 d (not b) x++ $fFooInt = MkD $cop1 $cop2++ {-# INLINE $cop1 #-}+ $cop1 = $dmop1 $fFooInt++ $cop2 = <blah>++Note carefully:++* We *copy* any INLINE pragma from the default method $dmop1 to the+ instance $cop1. Otherwise we'll just inline the former in the+ latter and stop, which isn't what the user expected++* Regardless of its pragma, we give the default method an+ unfolding with an InlineCompulsory source. That means+ that it'll be inlined at every use site, notably in+ each instance declaration, such as $cop1. This inlining+ must happen even though+ a) $dmop1 is not saturated in $cop1+ b) $cop1 itself has an INLINE pragma++ It's vital that $dmop1 *is* inlined in this way, to allow the mutual+ recursion between $fooInt and $cop1 to be broken++* To communicate the need for an InlineCompulsory to the desugarer+ (which makes the Unfoldings), we use the IsDefaultMethod constructor+ in TcSpecPrags.+++************************************************************************+* *+ Specialise instance pragmas+* *+************************************************************************++Note [SPECIALISE instance pragmas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ instance (Ix a, Ix b) => Ix (a,b) where+ {-# SPECIALISE instance Ix (Int,Int) #-}+ range (x,y) = ...++We make a specialised version of the dictionary function, AND+specialised versions of each *method*. Thus we should generate+something like this:++ $dfIxPair :: (Ix a, Ix b) => Ix (a,b)+ {-# DFUN [$crangePair, ...] #-}+ {-# SPECIALISE $dfIxPair :: Ix (Int,Int) #-}+ $dfIxPair da db = Ix ($crangePair da db) (...other methods...)++ $crange :: (Ix a, Ix b) -> ((a,b),(a,b)) -> [(a,b)]+ {-# SPECIALISE $crange :: ((Int,Int),(Int,Int)) -> [(Int,Int)] #-}+ $crange da db = <blah>++The SPECIALISE pragmas are acted upon by the desugarer, which generate++ dii :: Ix Int+ dii = ...++ $s$dfIxPair :: Ix ((Int,Int),(Int,Int))+ {-# DFUN [$crangePair di di, ...] #-}+ $s$dfIxPair = Ix ($crangePair di di) (...)++ {-# RULE forall (d1,d2:Ix Int). $dfIxPair Int Int d1 d2 = $s$dfIxPair #-}++ $s$crangePair :: ((Int,Int),(Int,Int)) -> [(Int,Int)]+ $c$crangePair = ...specialised RHS of $crangePair...++ {-# RULE forall (d1,d2:Ix Int). $crangePair Int Int d1 d2 = $s$crangePair #-}++Note that++ * The specialised dictionary $s$dfIxPair is very much needed, in case we+ call a function that takes a dictionary, but in a context where the+ specialised dictionary can be used. See Trac #7797.++ * The ClassOp rule for 'range' works equally well on $s$dfIxPair, because+ it still has a DFunUnfolding. See Note [ClassOp/DFun selection]++ * A call (range ($dfIxPair Int Int d1 d2)) might simplify two ways:+ --> {ClassOp rule for range} $crangePair Int Int d1 d2+ --> {SPEC rule for $crangePair} $s$crangePair+ or thus:+ --> {SPEC rule for $dfIxPair} range $s$dfIxPair+ --> {ClassOpRule for range} $s$crangePair+ It doesn't matter which way.++ * We want to specialise the RHS of both $dfIxPair and $crangePair,+ but the SAME HsWrapper will do for both! We can call tcSpecPrag+ just once, and pass the result (in spec_inst_info) to tcMethods.+-}++tcSpecInstPrags :: DFunId -> InstBindings Name+ -> TcM ([Located TcSpecPrag], TcPragEnv)+tcSpecInstPrags dfun_id (InstBindings { ib_binds = binds, ib_pragmas = uprags })+ = do { spec_inst_prags <- mapM (wrapLocM (tcSpecInst dfun_id)) $+ filter isSpecInstLSig uprags+ -- The filter removes the pragmas for methods+ ; return (spec_inst_prags, mkPragEnv uprags binds) }++------------------------------+tcSpecInst :: Id -> Sig Name -> TcM TcSpecPrag+tcSpecInst dfun_id prag@(SpecInstSig _ hs_ty)+ = addErrCtxt (spec_ctxt prag) $+ do { (tyvars, theta, clas, tys) <- tcHsClsInstType SpecInstCtxt hs_ty+ ; let spec_dfun_ty = mkDictFunTy tyvars theta clas tys+ ; co_fn <- tcSpecWrapper SpecInstCtxt (idType dfun_id) spec_dfun_ty+ ; return (SpecPrag dfun_id co_fn defaultInlinePragma) }+ where+ spec_ctxt prag = hang (text "In the SPECIALISE pragma") 2 (ppr prag)++tcSpecInst _ _ = panic "tcSpecInst"++{-+************************************************************************+* *+\subsection{Error messages}+* *+************************************************************************+-}++instDeclCtxt1 :: LHsSigType Name -> SDoc+instDeclCtxt1 hs_inst_ty+ = inst_decl_ctxt (ppr (getLHsInstDeclHead hs_inst_ty))++instDeclCtxt2 :: Type -> SDoc+instDeclCtxt2 dfun_ty+ = inst_decl_ctxt (ppr (mkClassPred cls tys))+ where+ (_,_,cls,tys) = tcSplitDFunTy dfun_ty++inst_decl_ctxt :: SDoc -> SDoc+inst_decl_ctxt doc = hang (text "In the instance declaration for")+ 2 (quotes doc)++badBootFamInstDeclErr :: SDoc+badBootFamInstDeclErr+ = text "Illegal family instance in hs-boot file"++notFamily :: TyCon -> SDoc+notFamily tycon+ = vcat [ text "Illegal family instance for" <+> quotes (ppr tycon)+ , nest 2 $ parens (ppr tycon <+> text "is not an indexed type family")]++tooFewParmsErr :: Arity -> SDoc+tooFewParmsErr arity+ = text "Family instance has too few parameters; expected" <+>+ ppr arity++assocInClassErr :: Located Name -> SDoc+assocInClassErr name+ = text "Associated type" <+> quotes (ppr name) <+>+ text "must be inside a class instance"++badFamInstDecl :: Located Name -> SDoc+badFamInstDecl tc_name+ = vcat [ text "Illegal family instance for" <+>+ quotes (ppr tc_name)+ , nest 2 (parens $ text "Use TypeFamilies to allow indexed type families") ]++notOpenFamily :: TyCon -> SDoc+notOpenFamily tc+ = text "Illegal instance for closed family" <+> quotes (ppr tc)
+ typecheck/TcInstDcls.hs-boot view
@@ -0,0 +1,16 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++module TcInstDcls ( tcInstDecls1 ) where++import HsSyn+import TcRnTypes+import TcEnv( InstInfo )+import TcDeriv+import Name++-- We need this because of the mutual recursion+-- between TcTyClsDecls and TcInstDcls+tcInstDecls1 :: [LInstDecl Name] -> TcM (TcGblEnv, [InstInfo Name], [DerivInfo])
+ typecheck/TcInteract.hs view
@@ -0,0 +1,2665 @@+{-# LANGUAGE CPP #-}++module TcInteract (+ solveSimpleGivens, -- Solves [Ct]+ solveSimpleWanteds, -- Solves Cts++ solveCallStack, -- for use in TcSimplify+ ) where++#include "HsVersions.h"++import BasicTypes ( SwapFlag(..), isSwapped,+ infinity, IntWithInf, intGtLimit )+import HsTypes ( HsIPName(..) )+import TcCanonical+import TcFlatten+import TcUnify( canSolveByUnification )+import VarSet+import Type+import Kind( isConstraintKind )+import InstEnv( DFunInstType, lookupInstEnv, instanceDFunId )+import CoAxiom( sfInteractTop, sfInteractInert )++import TcMType (newMetaTyVars)++import Var+import TcType+import Name+import RdrName ( lookupGRE_FieldLabel )+import PrelNames ( knownNatClassName, knownSymbolClassName,+ typeableClassName, coercibleTyConKey,+ hasFieldClassName,+ heqTyConKey, ipClassKey )+import TysWiredIn ( typeNatKind, typeSymbolKind, heqDataCon,+ coercibleDataCon, constraintKindTyCon )+import TysPrim ( eqPrimTyCon, eqReprPrimTyCon )+import Id( idType, isNaughtyRecordSelector )+import CoAxiom ( TypeEqn, CoAxiom(..), CoAxBranch(..), fromBranches )+import Class+import TyCon+import DataCon( dataConWrapId )+import FieldLabel+import FunDeps+import FamInst+import FamInstEnv+import Unify ( tcUnifyTyWithTFs )++import TcEvidence+import Outputable++import TcRnTypes+import TcSMonad+import Bag+import MonadUtils ( concatMapM )++import Data.List( partition, foldl', deleteFirstsBy )+import SrcLoc+import VarEnv++import Control.Monad+import Maybes( isJust )+import Pair (Pair(..))+import Unique( hasKey )+import DynFlags+import Util+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad.Trans.Class+import Control.Monad.Trans.Maybe++{-+**********************************************************************+* *+* Main Interaction Solver *+* *+**********************************************************************++Note [Basic Simplifier Plan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+1. Pick an element from the WorkList if there exists one with depth+ less than our context-stack depth.++2. Run it down the 'stage' pipeline. Stages are:+ - canonicalization+ - inert reactions+ - spontaneous reactions+ - top-level intreactions+ Each stage returns a StopOrContinue and may have sideffected+ the inerts or worklist.++ The threading of the stages is as follows:+ - If (Stop) is returned by a stage then we start again from Step 1.+ - If (ContinueWith ct) is returned by a stage, we feed 'ct' on to+ the next stage in the pipeline.+4. If the element has survived (i.e. ContinueWith x) the last stage+ then we add him in the inerts and jump back to Step 1.++If in Step 1 no such element exists, we have exceeded our context-stack+depth and will simply fail.++Note [Unflatten after solving the simple wanteds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We unflatten after solving the wc_simples of an implication, and before attempting+to float. This means that++ * The fsk/fmv flatten-skolems only survive during solveSimples. We don't+ need to worry about them across successive passes over the constraint tree.+ (E.g. we don't need the old ic_fsk field of an implication.++ * When floating an equality outwards, we don't need to worry about floating its+ associated flattening constraints.++ * Another tricky case becomes easy: Trac #4935+ type instance F True a b = a+ type instance F False a b = b++ [w] F c a b ~ gamma+ (c ~ True) => a ~ gamma+ (c ~ False) => b ~ gamma++ Obviously this is soluble with gamma := F c a b, and unflattening+ will do exactly that after solving the simple constraints and before+ attempting the implications. Before, when we were not unflattening,+ we had to push Wanted funeqs in as new givens. Yuk!++ Another example that becomes easy: indexed_types/should_fail/T7786+ [W] BuriedUnder sub k Empty ~ fsk+ [W] Intersect fsk inv ~ s+ [w] xxx[1] ~ s+ [W] forall[2] . (xxx[1] ~ Empty)+ => Intersect (BuriedUnder sub k Empty) inv ~ Empty++Note [Running plugins on unflattened wanteds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There is an annoying mismatch between solveSimpleGivens and+solveSimpleWanteds, because the latter needs to fiddle with the inert+set, unflatten and zonk the wanteds. It passes the zonked wanteds+to runTcPluginsWanteds, which produces a replacement set of wanteds,+some additional insolubles and a flag indicating whether to go round+the loop again. If so, prepareInertsForImplications is used to remove+the previous wanteds (which will still be in the inert set). Note+that prepareInertsForImplications will discard the insolubles, so we+must keep track of them separately.+-}++solveSimpleGivens :: [Ct] -> TcS ()+solveSimpleGivens givens+ | null givens -- Shortcut for common case+ = return ()+ | otherwise+ = do { traceTcS "solveSimpleGivens {" (ppr givens)+ ; go givens+ ; traceTcS "End solveSimpleGivens }" empty }+ where+ go givens = do { solveSimples (listToBag givens)+ ; new_givens <- runTcPluginsGiven+ ; when (notNull new_givens) $+ go new_givens }++solveSimpleWanteds :: Cts -> TcS WantedConstraints+-- NB: 'simples' may contain /derived/ equalities, floated+-- out from a nested implication. So don't discard deriveds!+solveSimpleWanteds simples+ = do { traceTcS "solveSimpleWanteds {" (ppr simples)+ ; dflags <- getDynFlags+ ; (n,wc) <- go 1 (solverIterations dflags) (emptyWC { wc_simple = simples })+ ; traceTcS "solveSimpleWanteds end }" $+ vcat [ text "iterations =" <+> ppr n+ , text "residual =" <+> ppr wc ]+ ; return wc }+ where+ go :: Int -> IntWithInf -> WantedConstraints -> TcS (Int, WantedConstraints)+ go n limit wc+ | n `intGtLimit` limit+ = failTcS (hang (text "solveSimpleWanteds: too many iterations"+ <+> parens (text "limit =" <+> ppr limit))+ 2 (vcat [ text "Set limit with -fconstraint-solver-iterations=n; n=0 for no limit"+ , text "Simples =" <+> ppr simples+ , text "WC =" <+> ppr wc ]))++ | isEmptyBag (wc_simple wc)+ = return (n,wc)++ | otherwise+ = do { -- Solve+ (unif_count, wc1) <- solve_simple_wanteds wc++ -- Run plugins+ ; (rerun_plugin, wc2) <- runTcPluginsWanted wc1+ -- See Note [Running plugins on unflattened wanteds]++ ; if unif_count == 0 && not rerun_plugin+ then return (n, wc2) -- Done+ else do { traceTcS "solveSimple going round again:" $+ ppr unif_count $$ ppr rerun_plugin+ ; go (n+1) limit wc2 } } -- Loop+++solve_simple_wanteds :: WantedConstraints -> TcS (Int, WantedConstraints)+-- Try solving these constraints+-- Affects the unification state (of course) but not the inert set+solve_simple_wanteds (WC { wc_simple = simples1, wc_insol = insols1, wc_impl = implics1 })+ = nestTcS $+ do { solveSimples simples1+ ; (implics2, tv_eqs, fun_eqs, insols2, others) <- getUnsolvedInerts+ ; (unif_count, unflattened_eqs) <- reportUnifications $+ unflatten tv_eqs fun_eqs+ -- See Note [Unflatten after solving the simple wanteds]+ ; return ( unif_count+ , WC { wc_simple = others `andCts` unflattened_eqs+ , wc_insol = insols1 `andCts` insols2+ , wc_impl = implics1 `unionBags` implics2 }) }++{- Note [The solveSimpleWanteds loop]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Solving a bunch of simple constraints is done in a loop,+(the 'go' loop of 'solveSimpleWanteds'):+ 1. Try to solve them; unflattening may lead to improvement that+ was not exploitable during solving+ 2. Try the plugin+ 3. If step 1 did improvement during unflattening; or if the plugin+ wants to run again, go back to step 1++Non-obviously, improvement can also take place during+the unflattening that takes place in step (1). See TcFlatten,+See Note [Unflattening can force the solver to iterate]+-}++-- The main solver loop implements Note [Basic Simplifier Plan]+---------------------------------------------------------------+solveSimples :: Cts -> TcS ()+-- Returns the final InertSet in TcS+-- Has no effect on work-list or residual-implications+-- The constraints are initially examined in left-to-right order++solveSimples cts+ = {-# SCC "solveSimples" #-}+ do { updWorkListTcS (\wl -> foldrBag extendWorkListCt wl cts)+ ; solve_loop }+ where+ solve_loop+ = {-# SCC "solve_loop" #-}+ do { sel <- selectNextWorkItem+ ; case sel of+ Nothing -> return ()+ Just ct -> do { runSolverPipeline thePipeline ct+ ; solve_loop } }++-- | Extract the (inert) givens and invoke the plugins on them.+-- Remove solved givens from the inert set and emit insolubles, but+-- return new work produced so that 'solveSimpleGivens' can feed it back+-- into the main solver.+runTcPluginsGiven :: TcS [Ct]+runTcPluginsGiven+ = do { plugins <- getTcPlugins+ ; if null plugins then return [] else+ do { givens <- getInertGivens+ ; if null givens then return [] else+ do { p <- runTcPlugins plugins (givens,[],[])+ ; let (solved_givens, _, _) = pluginSolvedCts p+ ; updInertCans (removeInertCts solved_givens)+ ; mapM_ emitInsoluble (pluginBadCts p)+ ; return (pluginNewCts p) } } }++-- | Given a bag of (flattened, zonked) wanteds, invoke the plugins on+-- them and produce an updated bag of wanteds (possibly with some new+-- work) and a bag of insolubles. The boolean indicates whether+-- 'solveSimpleWanteds' should feed the updated wanteds back into the+-- main solver.+runTcPluginsWanted :: WantedConstraints -> TcS (Bool, WantedConstraints)+runTcPluginsWanted wc@(WC { wc_simple = simples1, wc_insol = insols1, wc_impl = implics1 })+ | isEmptyBag simples1+ = return (False, wc)+ | otherwise+ = do { plugins <- getTcPlugins+ ; if null plugins then return (False, wc) else++ do { given <- getInertGivens+ ; simples1 <- zonkSimples simples1 -- Plugin requires zonked inputs+ ; let (wanted, derived) = partition isWantedCt (bagToList simples1)+ ; p <- runTcPlugins plugins (given, derived, wanted)+ ; let (_, _, solved_wanted) = pluginSolvedCts p+ (_, unsolved_derived, unsolved_wanted) = pluginInputCts p+ new_wanted = pluginNewCts p++-- SLPJ: I'm deeply suspicious of this+-- ; updInertCans (removeInertCts $ solved_givens ++ solved_deriveds)++ ; mapM_ setEv solved_wanted+ ; return ( notNull (pluginNewCts p)+ , WC { wc_simple = listToBag new_wanted `andCts` listToBag unsolved_wanted+ `andCts` listToBag unsolved_derived+ , wc_insol = listToBag (pluginBadCts p) `andCts` insols1+ , wc_impl = implics1 } ) } }+ where+ setEv :: (EvTerm,Ct) -> TcS ()+ setEv (ev,ct) = case ctEvidence ct of+ CtWanted { ctev_dest = dest } -> setWantedEvTerm dest ev+ _ -> panic "runTcPluginsWanted.setEv: attempt to solve non-wanted!"++-- | A triple of (given, derived, wanted) constraints to pass to plugins+type SplitCts = ([Ct], [Ct], [Ct])++-- | A solved triple of constraints, with evidence for wanteds+type SolvedCts = ([Ct], [Ct], [(EvTerm,Ct)])++-- | Represents collections of constraints generated by typechecker+-- plugins+data TcPluginProgress = TcPluginProgress+ { pluginInputCts :: SplitCts+ -- ^ Original inputs to the plugins with solved/bad constraints+ -- removed, but otherwise unmodified+ , pluginSolvedCts :: SolvedCts+ -- ^ Constraints solved by plugins+ , pluginBadCts :: [Ct]+ -- ^ Constraints reported as insoluble by plugins+ , pluginNewCts :: [Ct]+ -- ^ New constraints emitted by plugins+ }++getTcPlugins :: TcS [TcPluginSolver]+getTcPlugins = do { tcg_env <- getGblEnv; return (tcg_tc_plugins tcg_env) }++-- | Starting from a triple of (given, derived, wanted) constraints,+-- invoke each of the typechecker plugins in turn and return+--+-- * the remaining unmodified constraints,+-- * constraints that have been solved,+-- * constraints that are insoluble, and+-- * new work.+--+-- Note that new work generated by one plugin will not be seen by+-- other plugins on this pass (but the main constraint solver will be+-- re-invoked and they will see it later). There is no check that new+-- work differs from the original constraints supplied to the plugin:+-- the plugin itself should perform this check if necessary.+runTcPlugins :: [TcPluginSolver] -> SplitCts -> TcS TcPluginProgress+runTcPlugins plugins all_cts+ = foldM do_plugin initialProgress plugins+ where+ do_plugin :: TcPluginProgress -> TcPluginSolver -> TcS TcPluginProgress+ do_plugin p solver = do+ result <- runTcPluginTcS (uncurry3 solver (pluginInputCts p))+ return $ progress p result++ progress :: TcPluginProgress -> TcPluginResult -> TcPluginProgress+ progress p (TcPluginContradiction bad_cts) =+ p { pluginInputCts = discard bad_cts (pluginInputCts p)+ , pluginBadCts = bad_cts ++ pluginBadCts p+ }+ progress p (TcPluginOk solved_cts new_cts) =+ p { pluginInputCts = discard (map snd solved_cts) (pluginInputCts p)+ , pluginSolvedCts = add solved_cts (pluginSolvedCts p)+ , pluginNewCts = new_cts ++ pluginNewCts p+ }++ initialProgress = TcPluginProgress all_cts ([], [], []) [] []++ discard :: [Ct] -> SplitCts -> SplitCts+ discard cts (xs, ys, zs) =+ (xs `without` cts, ys `without` cts, zs `without` cts)++ without :: [Ct] -> [Ct] -> [Ct]+ without = deleteFirstsBy eqCt++ eqCt :: Ct -> Ct -> Bool+ eqCt c c' = ctFlavour c == ctFlavour c'+ && ctPred c `tcEqType` ctPred c'++ add :: [(EvTerm,Ct)] -> SolvedCts -> SolvedCts+ add xs scs = foldl' addOne scs xs++ addOne :: SolvedCts -> (EvTerm,Ct) -> SolvedCts+ addOne (givens, deriveds, wanteds) (ev,ct) = case ctEvidence ct of+ CtGiven {} -> (ct:givens, deriveds, wanteds)+ CtDerived{} -> (givens, ct:deriveds, wanteds)+ CtWanted {} -> (givens, deriveds, (ev,ct):wanteds)+++type WorkItem = Ct+type SimplifierStage = WorkItem -> TcS (StopOrContinue Ct)++runSolverPipeline :: [(String,SimplifierStage)] -- The pipeline+ -> WorkItem -- The work item+ -> TcS ()+-- Run this item down the pipeline, leaving behind new work and inerts+runSolverPipeline pipeline workItem+ = do { wl <- getWorkList+ ; inerts <- getTcSInerts+ ; traceTcS "----------------------------- " empty+ ; traceTcS "Start solver pipeline {" $+ vcat [ text "work item =" <+> ppr workItem+ , text "inerts =" <+> ppr inerts+ , text "rest of worklist =" <+> ppr wl ]++ ; bumpStepCountTcS -- One step for each constraint processed+ ; final_res <- run_pipeline pipeline (ContinueWith workItem)++ ; case final_res of+ Stop ev s -> do { traceFireTcS ev s+ ; traceTcS "End solver pipeline (discharged) }" empty+ ; return () }+ ContinueWith ct -> do { addInertCan ct+ ; traceFireTcS (ctEvidence ct) (text "Kept as inert")+ ; traceTcS "End solver pipeline (kept as inert) }" $+ (text "final_item =" <+> ppr ct) }+ }+ where run_pipeline :: [(String,SimplifierStage)] -> StopOrContinue Ct+ -> TcS (StopOrContinue Ct)+ run_pipeline [] res = return res+ run_pipeline _ (Stop ev s) = return (Stop ev s)+ run_pipeline ((stg_name,stg):stgs) (ContinueWith ct)+ = do { traceTcS ("runStage " ++ stg_name ++ " {")+ (text "workitem = " <+> ppr ct)+ ; res <- stg ct+ ; traceTcS ("end stage " ++ stg_name ++ " }") empty+ ; run_pipeline stgs res }++{-+Example 1:+ Inert: {c ~ d, F a ~ t, b ~ Int, a ~ ty} (all given)+ Reagent: a ~ [b] (given)++React with (c~d) ==> IR (ContinueWith (a~[b])) True []+React with (F a ~ t) ==> IR (ContinueWith (a~[b])) False [F [b] ~ t]+React with (b ~ Int) ==> IR (ContinueWith (a~[Int]) True []++Example 2:+ Inert: {c ~w d, F a ~g t, b ~w Int, a ~w ty}+ Reagent: a ~w [b]++React with (c ~w d) ==> IR (ContinueWith (a~[b])) True []+React with (F a ~g t) ==> IR (ContinueWith (a~[b])) True [] (can't rewrite given with wanted!)+etc.++Example 3:+ Inert: {a ~ Int, F Int ~ b} (given)+ Reagent: F a ~ b (wanted)++React with (a ~ Int) ==> IR (ContinueWith (F Int ~ b)) True []+React with (F Int ~ b) ==> IR Stop True [] -- after substituting we re-canonicalize and get nothing+-}++thePipeline :: [(String,SimplifierStage)]+thePipeline = [ ("canonicalization", TcCanonical.canonicalize)+ , ("interact with inerts", interactWithInertsStage)+ , ("top-level reactions", topReactionsStage) ]++{-+*********************************************************************************+* *+ The interact-with-inert Stage+* *+*********************************************************************************++Note [The Solver Invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We always add Givens first. So you might think that the solver has+the invariant++ If the work-item is Given,+ then the inert item must Given++But this isn't quite true. Suppose we have,+ c1: [W] beta ~ [alpha], c2 : [W] blah, c3 :[W] alpha ~ Int+After processing the first two, we get+ c1: [G] beta ~ [alpha], c2 : [W] blah+Now, c3 does not interact with the the given c1, so when we spontaneously+solve c3, we must re-react it with the inert set. So we can attempt a+reaction between inert c2 [W] and work-item c3 [G].++It *is* true that [Solver Invariant]+ If the work-item is Given,+ AND there is a reaction+ then the inert item must Given+or, equivalently,+ If the work-item is Given,+ and the inert item is Wanted/Derived+ then there is no reaction+-}++-- Interaction result of WorkItem <~> Ct++type StopNowFlag = Bool -- True <=> stop after this interaction++interactWithInertsStage :: WorkItem -> TcS (StopOrContinue Ct)+-- Precondition: if the workitem is a CTyEqCan then it will not be able to+-- react with anything at this stage.++interactWithInertsStage wi+ = do { inerts <- getTcSInerts+ ; let ics = inert_cans inerts+ ; case wi of+ CTyEqCan {} -> interactTyVarEq ics wi+ CFunEqCan {} -> interactFunEq ics wi+ CIrredEvCan {} -> interactIrred ics wi+ CDictCan {} -> interactDict ics wi+ _ -> pprPanic "interactWithInerts" (ppr wi) }+ -- CHoleCan are put straight into inert_frozen, so never get here+ -- CNonCanonical have been canonicalised++data InteractResult+ = IRKeep -- Keep the existing inert constraint in the inert set+ | IRReplace -- Replace the existing inert constraint with the work item+ | IRDelete -- Delete the existing inert constraint from the inert set++instance Outputable InteractResult where+ ppr IRKeep = text "keep"+ ppr IRReplace = text "replace"+ ppr IRDelete = text "delete"++solveOneFromTheOther :: CtEvidence -- Inert+ -> CtEvidence -- WorkItem+ -> TcS (InteractResult, StopNowFlag)+-- Preconditions:+-- 1) inert and work item represent evidence for the /same/ predicate+-- 2) ip/class/irred constraints only; not used for equalities+solveOneFromTheOther ev_i ev_w+ | isDerived ev_w -- Work item is Derived; just discard it+ = return (IRKeep, True)++ | isDerived ev_i -- The inert item is Derived, we can just throw it away,+ = return (IRDelete, False) -- The ev_w is inert wrt earlier inert-set items,+ -- so it's safe to continue on from this point++ | CtWanted { ctev_loc = loc_w } <- ev_w+ , prohibitedSuperClassSolve (ctEvLoc ev_i) loc_w+ = return (IRDelete, False)++ | CtWanted { ctev_dest = dest } <- ev_w+ -- Inert is Given or Wanted+ = do { setWantedEvTerm dest (ctEvTerm ev_i)+ ; return (IRKeep, True) }++ | CtWanted { ctev_loc = loc_i } <- ev_i -- Work item is Given+ , prohibitedSuperClassSolve (ctEvLoc ev_w) loc_i+ = return (IRKeep, False) -- Just discard the un-usable Given+ -- This never actually happens because+ -- Givens get processed first++ | CtWanted { ctev_dest = dest } <- ev_i+ = do { setWantedEvTerm dest (ctEvTerm ev_w)+ ; return (IRReplace, True) }++ -- So they are both Given+ -- See Note [Replacement vs keeping]+ | lvl_i == lvl_w+ = do { binds <- getTcEvBindsMap+ ; return (same_level_strategy binds, True) }++ | otherwise -- Both are Given, levels differ+ = return (different_level_strategy, True)+ where+ pred = ctEvPred ev_i+ loc_i = ctEvLoc ev_i+ loc_w = ctEvLoc ev_w+ lvl_i = ctLocLevel loc_i+ lvl_w = ctLocLevel loc_w++ different_level_strategy+ | isIPPred pred, lvl_w > lvl_i = IRReplace+ | lvl_w < lvl_i = IRReplace+ | otherwise = IRKeep++ same_level_strategy binds -- Both Given+ | GivenOrigin (InstSC s_i) <- ctLocOrigin loc_i+ = case ctLocOrigin loc_w of+ GivenOrigin (InstSC s_w) | s_w < s_i -> IRReplace+ | otherwise -> IRKeep+ _ -> IRReplace++ | GivenOrigin (InstSC {}) <- ctLocOrigin loc_w+ = IRKeep++ | has_binding binds ev_w+ , not (has_binding binds ev_i)+ = IRReplace++ | otherwise = IRKeep++ has_binding binds ev = isJust (lookupEvBind binds (ctEvId ev))++{-+Note [Replacement vs keeping]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we have two Given constraints both of type (C tys), say, which should+we keep? More subtle than you might think!++ * Constraints come from different levels (different_level_strategy)++ - For implicit parameters we want to keep the innermost (deepest)+ one, so that it overrides the outer one.+ See Note [Shadowing of Implicit Parameters]++ - For everything else, we want to keep the outermost one. Reason: that+ makes it more likely that the inner one will turn out to be unused,+ and can be reported as redundant. See Note [Tracking redundant constraints]+ in TcSimplify.++ It transpires that using the outermost one is reponsible for an+ 8% performance improvement in nofib cryptarithm2, compared to+ just rolling the dice. I didn't investigate why.++ * Constraints coming from the same level (i.e. same implication)++ - Always get rid of InstSC ones if possible, since they are less+ useful for solving. If both are InstSC, choose the one with+ the smallest TypeSize+ See Note [Solving superclass constraints] in TcInstDcls++ - Keep the one that has a non-trivial evidence binding.+ Example: f :: (Eq a, Ord a) => blah+ then we may find [G] d3 :: Eq a+ [G] d2 :: Eq a+ with bindings d3 = sc_sel (d1::Ord a)+ We want to discard d2 in favour of the superclass selection from+ the Ord dictionary.+ Why? See Note [Tracking redundant constraints] in TcSimplify again.++ * Finally, when there is still a choice, use IRKeep rather than+ IRReplace, to avoid unnecessary munging of the inert set.++Doing the depth-check for implicit parameters, rather than making the work item+always override, is important. Consider++ data T a where { T1 :: (?x::Int) => T Int; T2 :: T a }++ f :: (?x::a) => T a -> Int+ f T1 = ?x+ f T2 = 3++We have a [G] (?x::a) in the inert set, and at the pattern match on T1 we add+two new givens in the work-list: [G] (?x::Int)+ [G] (a ~ Int)+Now consider these steps+ - process a~Int, kicking out (?x::a)+ - process (?x::Int), the inner given, adding to inert set+ - process (?x::a), the outer given, overriding the inner given+Wrong! The depth-check ensures that the inner implicit parameter wins.+(Actually I think that the order in which the work-list is processed means+that this chain of events won't happen, but that's very fragile.)++*********************************************************************************+* *+ interactIrred+* *+*********************************************************************************+-}++-- Two pieces of irreducible evidence: if their types are *exactly identical*+-- we can rewrite them. We can never improve using this:+-- if we want ty1 :: Constraint and have ty2 :: Constraint it clearly does not+-- mean that (ty1 ~ ty2)+interactIrred :: InertCans -> Ct -> TcS (StopOrContinue Ct)++interactIrred inerts workItem@(CIrredEvCan { cc_ev = ev_w })+ | let pred = ctEvPred ev_w+ (matching_irreds, others)+ = partitionBag (\ct -> ctPred ct `tcEqTypeNoKindCheck` pred)+ (inert_irreds inerts)+ , (ct_i : rest) <- bagToList matching_irreds+ , let ctev_i = ctEvidence ct_i+ = ASSERT( null rest )+ do { (inert_effect, stop_now) <- solveOneFromTheOther ctev_i ev_w+ ; case inert_effect of+ IRKeep -> return ()+ IRDelete -> updInertIrreds (\_ -> others)+ IRReplace -> updInertIrreds (\_ -> others `snocCts` workItem)+ -- These const upd's assume that solveOneFromTheOther+ -- has no side effects on InertCans+ ; if stop_now then+ return (Stop ev_w (text "Irred equal" <+> parens (ppr inert_effect)))+ ; else+ continueWith workItem }++ | otherwise+ = continueWith workItem++interactIrred _ wi = pprPanic "interactIrred" (ppr wi)++{-+*********************************************************************************+* *+ interactDict+* *+*********************************************************************************++Note [Solving from instances when interacting Dicts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we interact a [W] constraint with a [G] constraint that solves it, there is+a possibility that we could produce better code if instead we solved from a+top-level instance declaration (See #12791, #5835). For example:++ class M a b where m :: a -> b++ type C a b = (Num a, M a b)++ f :: C Int b => b -> Int -> Int+ f _ x = x + 1++The body of `f` requires a [W] `Num Int` instance. We could solve this+constraint from the givens because we have `C Int b` and that provides us a+solution for `Num Int`. This would let us produce core like the following+(with -O2):++ f :: forall b. C Int b => b -> Int -> Int+ f = \ (@ b) ($d(%,%) :: C Int b) _ (eta1 :: Int) ->+ + @ Int+ (GHC.Classes.$p1(%,%) @ (Num Int) @ (M Int b) $d(%,%))+ eta1+ A.f1++This is bad! We could do much better if we solved [W] `Num Int` directly from+the instance that we have in scope:++ f :: forall b. C Int b => b -> Int -> Int+ f = \ (@ b) _ _ (x :: Int) ->+ case x of { GHC.Types.I# x1 -> GHC.Types.I# (GHC.Prim.+# x1 1#) }++However, there is a reason why the solver does not simply try to solve such+constraints with top-level instances. If the solver finds a relevant instance+declaration in scope, that instance may require a context that can't be solved+for. A good example of this is:++ f :: Ord [a] => ...+ f x = ..Need Eq [a]...++If we have instance `Eq a => Eq [a]` in scope and we tried to use it, we would+be left with the obligation to solve the constraint Eq a, which we cannot. So we+must be conservative in our attempt to use an instance declaration to solve the+[W] constraint we're interested in. Our rule is that we try to solve all of the+instance's subgoals recursively all at once. Precisely: We only attempt to+solve constraints of the form `C1, ... Cm => C t1 ... t n`, where all the Ci are+themselves class constraints of the form `C1', ... Cm' => C' t1' ... tn'` and we+only succeed if the entire tree of constraints is solvable from instances.++An example that succeeds:++ class Eq a => C a b | b -> a where+ m :: b -> a++ f :: C [Int] b => b -> Bool+ f x = m x == []++We solve for `Eq [Int]`, which requires `Eq Int`, which we also have. This+produces the following core:++ f :: forall b. C [Int] b => b -> Bool+ f = \ (@ b) ($dC :: C [Int] b) (x :: b) ->+ GHC.Classes.$fEq[]_$s$c==+ (m @ [Int] @ b $dC x) (GHC.Types.[] @ Int)++An example that fails:++ class Eq a => C a b | b -> a where+ m :: b -> a++ f :: C [a] b => b -> Bool+ f x = m x == []++Which, because solving `Eq [a]` demands `Eq a` which we cannot solve, produces:++ f :: forall a b. C [a] b => b -> Bool+ f = \ (@ a) (@ b) ($dC :: C [a] b) (eta :: b) ->+ ==+ @ [a]+ (A.$p1C @ [a] @ b $dC)+ (m @ [a] @ b $dC eta)+ (GHC.Types.[] @ a)++This optimization relies on coherence of dictionaries to be correct. When we+cannot assume coherence because of IncoherentInstances then this optimization+can change the behavior of the user's code.++The following four modules produce a program whose output would change depending+on whether we apply this optimization when IncoherentInstances is in effect:++#########+ {-# LANGUAGE MultiParamTypeClasses #-}+ module A where++ class A a where+ int :: a -> Int++ class A a => C a b where+ m :: b -> a -> a++#########+ {-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}+ module B where++ import A++ instance A a where+ int _ = 1++ instance C a [b] where+ m _ = id++#########+ {-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FlexibleContexts #-}+ {-# LANGUAGE IncoherentInstances #-}+ module C where++ import A++ instance A Int where+ int _ = 2++ instance C Int [Int] where+ m _ = id++ intC :: C Int a => a -> Int -> Int+ intC _ x = int x++#########+ module Main where++ import A+ import B+ import C++ main :: IO ()+ main = print (intC [] (0::Int))++The output of `main` if we avoid the optimization under the effect of+IncoherentInstances is `1`. If we were to do the optimization, the output of+`main` would be `2`.++It is important to emphasize that failure means that we don't produce more+efficient code, NOT that we fail to typecheck at all! This is purely an+an optimization: exactly the same programs should typecheck with or without this+procedure.++-}++interactDict :: InertCans -> Ct -> TcS (StopOrContinue Ct)+interactDict inerts workItem@(CDictCan { cc_ev = ev_w, cc_class = cls, cc_tyargs = tys })+ | isWanted ev_w+ , Just ip_name <- isCallStackPred (ctPred workItem)+ , OccurrenceOf func <- ctLocOrigin (ctEvLoc ev_w)+ -- If we're given a CallStack constraint that arose from a function+ -- call, we need to push the current call-site onto the stack instead+ -- of solving it directly from a given.+ -- See Note [Overview of implicit CallStacks]+ = do { let loc = ctEvLoc ev_w++ -- First we emit a new constraint that will capture the+ -- given CallStack.+ ; let new_loc = setCtLocOrigin loc (IPOccOrigin (HsIPName ip_name))+ -- We change the origin to IPOccOrigin so+ -- this rule does not fire again.+ -- See Note [Overview of implicit CallStacks]++ ; mb_new <- newWantedEvVar new_loc (ctEvPred ev_w)+ ; emitWorkNC (freshGoals [mb_new])++ -- Then we solve the wanted by pushing the call-site onto the+ -- newly emitted CallStack.+ ; let ev_cs = EvCsPushCall func (ctLocSpan loc) (getEvTerm mb_new)+ ; solveCallStack ev_w ev_cs+ ; stopWith ev_w "Wanted CallStack IP" }+ | Just ctev_i <- lookupInertDict inerts cls tys+ = do+ { dflags <- getDynFlags+ -- See Note [Solving from instances when interacting Dicts]+ ; try_inst_res <- trySolveFromInstance dflags ev_w ctev_i+ ; case try_inst_res of+ Just evs -> do+ { flip mapM_ evs $ \(ev_t, ct_ev, cls, typ) -> do+ { setWantedEvBind (ctEvId ct_ev) ev_t+ ; addSolvedDict ct_ev cls typ }+ ; stopWith ev_w "interactDict/solved from instance" }+ -- We were unable to solve the [W] constraint from in-scope instances so+ -- we solve it from the solution in the inerts we just retrieved.+ Nothing -> do+ { (inert_effect, stop_now) <- solveOneFromTheOther ctev_i ev_w+ ; case inert_effect of+ IRKeep -> return ()+ IRDelete -> updInertDicts $ \ ds -> delDict ds cls tys+ IRReplace -> updInertDicts $ \ ds -> addDict ds cls tys workItem+ ; if stop_now then+ return $ Stop ev_w (text "Dict equal" <+> parens (ppr inert_effect))+ else+ continueWith workItem } }+ | cls `hasKey` ipClassKey+ , isGiven ev_w+ = interactGivenIP inerts workItem++ | otherwise+ = do { addFunDepWork inerts ev_w cls+ ; continueWith workItem }++interactDict _ wi = pprPanic "interactDict" (ppr wi)++-- See Note [Solving from instances when interacting Dicts]+trySolveFromInstance :: DynFlags+ -> CtEvidence -- Work item+ -> CtEvidence -- Inert we want to try to replace+ -> TcS (Maybe [(EvTerm, CtEvidence, Class, [TcPredType])])+ -- Everything we need to bind a solution for the work item+ -- and add the solved Dict to the cache in the main solver.+trySolveFromInstance dflags ev_w ctev_i+ | isWanted ev_w+ && isGiven ctev_i+ -- We are about to solve a [W] constraint from a [G] constraint. We take+ -- a moment to see if we can get a better solution using an instance.+ -- Note that we only do this for the sake of performance. Exactly the same+ -- programs should typecheck regardless of whether we take this step or+ -- not. See Note [Solving from instances when interacting Dicts]+ && not (xopt LangExt.IncoherentInstances dflags)+ -- If IncoherentInstances is on then we cannot rely on coherence of proofs+ -- in order to justify this optimization: The proof provided by the+ -- [G] constraint's superclass may be different from the top-level proof.+ && gopt Opt_SolveConstantDicts dflags+ -- Enabled by the -fsolve-constant-dicts flag+ = runMaybeT $ try_solve_from_instance emptyDictMap ev_w++ | otherwise = return Nothing+ where+ -- This `CtLoc` is used only to check the well-staged condition of any+ -- candidate DFun. Our subgoals all have the same stage as our root+ -- [W] constraint so it is safe to use this while solving them.+ loc_w = ctEvLoc ev_w++ -- Use a local cache of solved dicts while emitting EvVars for new work+ -- We bail out of the entire computation if we need to emit an EvVar for+ -- a subgoal that isn't a ClassPred.+ new_wanted_cached :: DictMap CtEvidence -> TcPredType -> MaybeT TcS MaybeNew+ new_wanted_cached cache pty+ | ClassPred cls tys <- classifyPredType pty+ = lift $ case findDict cache cls tys of+ Just ctev -> return $ Cached (ctEvTerm ctev)+ Nothing -> Fresh <$> newWantedNC loc_w pty+ | otherwise = mzero++ -- MaybeT manages early failure if we find a subgoal that cannot be solved+ -- from instances.+ -- Why do we need a local cache here?+ -- 1. We can't use the global cache because it contains givens that+ -- we specifically don't want to use to solve.+ -- 2. We need to be able to handle recursive super classes. The+ -- cache ensures that we remember what we have already tried to+ -- solve to avoid looping.+ try_solve_from_instance+ :: DictMap CtEvidence -> CtEvidence+ -> MaybeT TcS [(EvTerm, CtEvidence, Class, [TcPredType])]+ try_solve_from_instance cache ev+ | ClassPred cls tys <- classifyPredType (ctEvPred ev) = do+ -- It is important that we add our goal to the cache before we solve!+ -- Otherwise we may end up in a loop while solving recursive dictionaries.+ { let cache' = addDict cache cls tys ev+ ; inst_res <- lift $ match_class_inst dflags cls tys loc_w+ ; case inst_res of+ GenInst { lir_new_theta = preds+ , lir_mk_ev = mk_ev+ , lir_safe_over = safeOverlap }+ | safeOverlap -> do+ -- emit work for subgoals but use our local cache so that we can+ -- solve recursive dictionaries.+ { evc_vs <- mapM (new_wanted_cached cache') preds+ ; subgoalBinds <- mapM (try_solve_from_instance cache')+ (freshGoals evc_vs)+ ; return $ (mk_ev (map getEvTerm evc_vs), ev, cls, preds)+ : concat subgoalBinds }++ | otherwise -> mzero+ _ -> mzero }+ | otherwise = mzero++addFunDepWork :: InertCans -> CtEvidence -> Class -> TcS ()+-- Add derived constraints from type-class functional dependencies.+addFunDepWork inerts work_ev cls+ | isImprovable work_ev+ = mapBagM_ add_fds (findDictsByClass (inert_dicts inerts) cls)+ -- No need to check flavour; fundeps work between+ -- any pair of constraints, regardless of flavour+ -- Importantly we don't throw workitem back in the+ -- worklist because this can cause loops (see #5236)+ | otherwise+ = return ()+ where+ work_pred = ctEvPred work_ev+ work_loc = ctEvLoc work_ev++ add_fds inert_ct+ | isImprovable inert_ev+ = emitFunDepDeriveds $+ improveFromAnother derived_loc inert_pred work_pred+ -- We don't really rewrite tys2, see below _rewritten_tys2, so that's ok+ -- NB: We do create FDs for given to report insoluble equations that arise+ -- from pairs of Givens, and also because of floating when we approximate+ -- implications. The relevant test is: typecheck/should_fail/FDsFromGivens.hs+ | otherwise+ = return ()+ where+ inert_ev = ctEvidence inert_ct+ inert_pred = ctEvPred inert_ev+ inert_loc = ctEvLoc inert_ev+ derived_loc = work_loc { ctl_depth = ctl_depth work_loc `maxSubGoalDepth`+ ctl_depth inert_loc+ , ctl_origin = FunDepOrigin1 work_pred work_loc+ inert_pred inert_loc }++{-+**********************************************************************+* *+ Implicit parameters+* *+**********************************************************************+-}++interactGivenIP :: InertCans -> Ct -> TcS (StopOrContinue Ct)+-- Work item is Given (?x:ty)+-- See Note [Shadowing of Implicit Parameters]+interactGivenIP inerts workItem@(CDictCan { cc_ev = ev, cc_class = cls+ , cc_tyargs = tys@(ip_str:_) })+ = do { updInertCans $ \cans -> cans { inert_dicts = addDict filtered_dicts cls tys workItem }+ ; stopWith ev "Given IP" }+ where+ dicts = inert_dicts inerts+ ip_dicts = findDictsByClass dicts cls+ other_ip_dicts = filterBag (not . is_this_ip) ip_dicts+ filtered_dicts = addDictsByClass dicts cls other_ip_dicts++ -- Pick out any Given constraints for the same implicit parameter+ is_this_ip (CDictCan { cc_ev = ev, cc_tyargs = ip_str':_ })+ = isGiven ev && ip_str `tcEqType` ip_str'+ is_this_ip _ = False++interactGivenIP _ wi = pprPanic "interactGivenIP" (ppr wi)+++{- Note [Shadowing of Implicit Parameters]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the following example:++f :: (?x :: Char) => Char+f = let ?x = 'a' in ?x++The "let ?x = ..." generates an implication constraint of the form:++?x :: Char => ?x :: Char++Furthermore, the signature for `f` also generates an implication+constraint, so we end up with the following nested implication:++?x :: Char => (?x :: Char => ?x :: Char)++Note that the wanted (?x :: Char) constraint may be solved in+two incompatible ways: either by using the parameter from the+signature, or by using the local definition. Our intention is+that the local definition should "shadow" the parameter of the+signature, and we implement this as follows: when we add a new+*given* implicit parameter to the inert set, it replaces any existing+givens for the same implicit parameter.++Similarly, consider+ f :: (?x::a) => Bool -> a++ g v = let ?x::Int = 3+ in (f v, let ?x::Bool = True in f v)++This should probably be well typed, with+ g :: Bool -> (Int, Bool)++So the inner binding for ?x::Bool *overrides* the outer one.++All this works for the normal cases but it has an odd side effect in+some pathological programs like this:+-- This is accepted, the second parameter shadows+f1 :: (?x :: Int, ?x :: Char) => Char+f1 = ?x++-- This is rejected, the second parameter shadows+f2 :: (?x :: Int, ?x :: Char) => Int+f2 = ?x++Both of these are actually wrong: when we try to use either one,+we'll get two incompatible wnated constraints (?x :: Int, ?x :: Char),+which would lead to an error.++I can think of two ways to fix this:++ 1. Simply disallow multiple constraints for the same implicit+ parameter---this is never useful, and it can be detected completely+ syntactically.++ 2. Move the shadowing machinery to the location where we nest+ implications, and add some code here that will produce an+ error if we get multiple givens for the same implicit parameter.+++**********************************************************************+* *+ interactFunEq+* *+**********************************************************************+-}++interactFunEq :: InertCans -> Ct -> TcS (StopOrContinue Ct)+-- Try interacting the work item with the inert set+interactFunEq inerts work_item@(CFunEqCan { cc_ev = ev, cc_fun = tc+ , cc_tyargs = args, cc_fsk = fsk })+ | Just inert_ct@(CFunEqCan { cc_ev = ev_i+ , cc_fsk = fsk_i })+ <- findFunEq (inert_funeqs inerts) tc args+ , pr@(swap_flag, upgrade_flag) <- ev_i `funEqCanDischarge` ev+ = do { traceTcS "reactFunEq (rewrite inert item):" $+ vcat [ text "work_item =" <+> ppr work_item+ , text "inertItem=" <+> ppr ev_i+ , text "(swap_flag, upgrade)" <+> ppr pr ]+ ; if isSwapped swap_flag+ then do { -- Rewrite inert using work-item+ let work_item' | upgrade_flag = upgradeWanted work_item+ | otherwise = work_item+ ; updInertFunEqs $ \ feqs -> insertFunEq feqs tc args work_item'+ -- Do the updInertFunEqs before the reactFunEq, so that+ -- we don't kick out the inertItem as well as consuming it!+ ; reactFunEq ev fsk ev_i fsk_i+ ; stopWith ev "Work item rewrites inert" }+ else do { -- Rewrite work-item using inert+ ; when upgrade_flag $+ updInertFunEqs $ \ feqs -> insertFunEq feqs tc args+ (upgradeWanted inert_ct)+ ; reactFunEq ev_i fsk_i ev fsk+ ; stopWith ev "Inert rewrites work item" } }++ | otherwise -- Try improvement+ = do { improveLocalFunEqs ev inerts tc args fsk+ ; continueWith work_item }++interactFunEq _ work_item = pprPanic "interactFunEq" (ppr work_item)++upgradeWanted :: Ct -> Ct+-- We are combining a [W] F tys ~ fmv1 and [D] F tys ~ fmv2+-- so upgrade the [W] to [WD] before putting it in the inert set+upgradeWanted ct = ct { cc_ev = upgrade_ev (cc_ev ct) }+ where+ upgrade_ev ev = ASSERT2( isWanted ev, ppr ct )+ ev { ctev_nosh = WDeriv }++improveLocalFunEqs :: CtEvidence -> InertCans -> TyCon -> [TcType] -> TcTyVar+ -> TcS ()+-- Generate derived improvement equalities, by comparing+-- the current work item with inert CFunEqs+-- E.g. x + y ~ z, x + y' ~ z => [D] y ~ y'+--+-- See Note [FunDep and implicit parameter reactions]+improveLocalFunEqs work_ev inerts fam_tc args fsk+ | isGiven work_ev -- See Note [No FunEq improvement for Givens]+ || not (isImprovable work_ev)+ = return ()++ | not (null improvement_eqns)+ = do { traceTcS "interactFunEq improvements: " $+ vcat [ text "Eqns:" <+> ppr improvement_eqns+ , text "Candidates:" <+> ppr funeqs_for_tc+ , text "Inert eqs:" <+> ppr ieqs ]+ ; emitFunDepDeriveds improvement_eqns }++ | otherwise+ = return ()++ where+ ieqs = inert_eqs inerts+ funeqs = inert_funeqs inerts+ funeqs_for_tc = findFunEqsByTyCon funeqs fam_tc+ rhs = lookupFlattenTyVar ieqs fsk+ work_loc = ctEvLoc work_ev+ work_pred = ctEvPred work_ev+ fam_inj_info = familyTyConInjectivityInfo fam_tc++ --------------------+ improvement_eqns :: [FunDepEqn CtLoc]+ improvement_eqns+ | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc+ = -- Try built-in families, notably for arithmethic+ concatMap (do_one_built_in ops) funeqs_for_tc++ | Injective injective_args <- fam_inj_info+ = -- Try improvement from type families with injectivity annotations+ concatMap (do_one_injective injective_args) funeqs_for_tc++ | otherwise+ = []++ --------------------+ do_one_built_in ops (CFunEqCan { cc_tyargs = iargs, cc_fsk = ifsk, cc_ev = inert_ev })+ = mk_fd_eqns inert_ev (sfInteractInert ops args rhs iargs+ (lookupFlattenTyVar ieqs ifsk))++ do_one_built_in _ _ = pprPanic "interactFunEq 1" (ppr fam_tc)++ --------------------+ -- See Note [Type inference for type families with injectivity]+ do_one_injective inj_args (CFunEqCan { cc_tyargs = inert_args+ , cc_fsk = ifsk, cc_ev = inert_ev })+ | isImprovable inert_ev+ , rhs `tcEqType` lookupFlattenTyVar ieqs ifsk+ = mk_fd_eqns inert_ev $+ [ Pair arg iarg+ | (arg, iarg, True) <- zip3 args inert_args inj_args ]+ | otherwise+ = []++ do_one_injective _ _ = pprPanic "interactFunEq 2" (ppr fam_tc)++ --------------------+ mk_fd_eqns :: CtEvidence -> [TypeEqn] -> [FunDepEqn CtLoc]+ mk_fd_eqns inert_ev eqns+ | null eqns = []+ | otherwise = [ FDEqn { fd_qtvs = [], fd_eqs = eqns+ , fd_pred1 = work_pred+ , fd_pred2 = ctEvPred inert_ev+ , fd_loc = loc } ]+ where+ inert_loc = ctEvLoc inert_ev+ loc = inert_loc { ctl_depth = ctl_depth inert_loc `maxSubGoalDepth`+ ctl_depth work_loc }++-------------+reactFunEq :: CtEvidence -> TcTyVar -- From this :: F args1 ~ fsk1+ -> CtEvidence -> TcTyVar -- Solve this :: F args2 ~ fsk2+ -> TcS ()+reactFunEq from_this fsk1 solve_this fsk2+ | CtGiven { ctev_evar = evar, ctev_loc = loc } <- solve_this+ = do { let fsk_eq_co = mkTcSymCo (mkTcCoVarCo evar) `mkTcTransCo`+ ctEvCoercion from_this+ -- :: fsk2 ~ fsk1+ fsk_eq_pred = mkTcEqPredLikeEv solve_this+ (mkTyVarTy fsk2) (mkTyVarTy fsk1)++ ; new_ev <- newGivenEvVar loc (fsk_eq_pred, EvCoercion fsk_eq_co)+ ; emitWorkNC [new_ev] }++ | CtDerived { ctev_loc = loc } <- solve_this+ = do { traceTcS "reactFunEq (Derived)" (ppr from_this $$ ppr fsk1 $$+ ppr solve_this $$ ppr fsk2)+ ; emitNewDerivedEq loc Nominal (mkTyVarTy fsk1) (mkTyVarTy fsk2) }+ -- FunEqs are always at Nominal role++ | otherwise -- Wanted+ = do { traceTcS "reactFunEq" (ppr from_this $$ ppr fsk1 $$+ ppr solve_this $$ ppr fsk2)+ ; dischargeFmv solve_this fsk2 (ctEvCoercion from_this) (mkTyVarTy fsk1)+ ; traceTcS "reactFunEq done" (ppr from_this $$ ppr fsk1 $$+ ppr solve_this $$ ppr fsk2) }++{- Note [Type inference for type families with injectivity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have a type family with an injectivity annotation:+ type family F a b = r | r -> b++Then if we have two CFunEqCan constraints for F with the same RHS+ F s1 t1 ~ rhs+ F s2 t2 ~ rhs+then we can use the injectivity to get a new Derived constraint on+the injective argument+ [D] t1 ~ t2++That in turn can help GHC solve constraints that would otherwise require+guessing. For example, consider the ambiguity check for+ f :: F Int b -> Int+We get the constraint+ [W] F Int b ~ F Int beta+where beta is a unification variable. Injectivity lets us pick beta ~ b.++Injectivity information is also used at the call sites. For example:+ g = f True+gives rise to+ [W] F Int b ~ Bool+from which we can derive b. This requires looking at the defining equations of+a type family, ie. finding equation with a matching RHS (Bool in this example)+and infering values of type variables (b in this example) from the LHS patterns+of the matching equation. For closed type families we have to perform+additional apartness check for the selected equation to check that the selected+is guaranteed to fire for given LHS arguments.++These new constraints are simply *Derived* constraints; they have no evidence.+We could go further and offer evidence from decomposing injective type-function+applications, but that would require new evidence forms, and an extension to+FC, so we don't do that right now (Dec 14).++See also Note [Injective type families] in TyCon+++Note [Cache-caused loops]+~~~~~~~~~~~~~~~~~~~~~~~~~+It is very dangerous to cache a rewritten wanted family equation as 'solved' in our+solved cache (which is the default behaviour or xCtEvidence), because the interaction+may not be contributing towards a solution. Here is an example:++Initial inert set:+ [W] g1 : F a ~ beta1+Work item:+ [W] g2 : F a ~ beta2+The work item will react with the inert yielding the _same_ inert set plus:+ i) Will set g2 := g1 `cast` g3+ ii) Will add to our solved cache that [S] g2 : F a ~ beta2+ iii) Will emit [W] g3 : beta1 ~ beta2+Now, the g3 work item will be spontaneously solved to [G] g3 : beta1 ~ beta2+and then it will react the item in the inert ([W] g1 : F a ~ beta1). So it+will set+ g1 := g ; sym g3+and what is g? Well it would ideally be a new goal of type (F a ~ beta2) but+remember that we have this in our solved cache, and it is ... g2! In short we+created the evidence loop:++ g2 := g1 ; g3+ g3 := refl+ g1 := g2 ; sym g3++To avoid this situation we do not cache as solved any workitems (or inert)+which did not really made a 'step' towards proving some goal. Solved's are+just an optimization so we don't lose anything in terms of completeness of+solving.+++Note [Efficient Orientation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we are interacting two FunEqCans with the same LHS:+ (inert) ci :: (F ty ~ xi_i)+ (work) cw :: (F ty ~ xi_w)+We prefer to keep the inert (else we pass the work item on down+the pipeline, which is a bit silly). If we keep the inert, we+will (a) discharge 'cw'+ (b) produce a new equality work-item (xi_w ~ xi_i)+Notice the orientation (xi_w ~ xi_i) NOT (xi_i ~ xi_w):+ new_work :: xi_w ~ xi_i+ cw := ci ; sym new_work+Why? Consider the simplest case when xi1 is a type variable. If+we generate xi1~xi2, porcessing that constraint will kick out 'ci'.+If we generate xi2~xi1, there is less chance of that happening.+Of course it can and should still happen if xi1=a, xi1=Int, say.+But we want to avoid it happening needlessly.++Similarly, if we *can't* keep the inert item (because inert is Wanted,+and work is Given, say), we prefer to orient the new equality (xi_i ~+xi_w).++Note [Carefully solve the right CFunEqCan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ ---- OLD COMMENT, NOW NOT NEEDED+ ---- because we now allow multiple+ ---- wanted FunEqs with the same head+Consider the constraints+ c1 :: F Int ~ a -- Arising from an application line 5+ c2 :: F Int ~ Bool -- Arising from an application line 10+Suppose that 'a' is a unification variable, arising only from+flattening. So there is no error on line 5; it's just a flattening+variable. But there is (or might be) an error on line 10.++Two ways to combine them, leaving either (Plan A)+ c1 :: F Int ~ a -- Arising from an application line 5+ c3 :: a ~ Bool -- Arising from an application line 10+or (Plan B)+ c2 :: F Int ~ Bool -- Arising from an application line 10+ c4 :: a ~ Bool -- Arising from an application line 5++Plan A will unify c3, leaving c1 :: F Int ~ Bool as an error+on the *totally innocent* line 5. An example is test SimpleFail16+where the expected/actual message comes out backwards if we use+the wrong plan.++The second is the right thing to do. Hence the isMetaTyVarTy+test when solving pairwise CFunEqCan.+++**********************************************************************+* *+ interactTyVarEq+* *+**********************************************************************+-}++inertsCanDischarge :: InertCans -> TcTyVar -> TcType -> CtEvidence+ -> Maybe ( CtEvidence -- The evidence for the inert+ , SwapFlag -- Whether we need mkSymCo+ , Bool) -- True <=> keep a [D] version+ -- of the [WD] constraint+inertsCanDischarge inerts tv rhs ev+ | (ev_i : _) <- [ ev_i | CTyEqCan { cc_ev = ev_i, cc_rhs = rhs_i }+ <- findTyEqs inerts tv+ , ev_i `eqCanDischarge` ev+ , rhs_i `tcEqType` rhs ]+ = -- Inert: a ~ ty+ -- Work item: a ~ ty+ Just (ev_i, NotSwapped, keep_deriv ev_i)++ | Just tv_rhs <- getTyVar_maybe rhs+ , (ev_i : _) <- [ ev_i | CTyEqCan { cc_ev = ev_i, cc_rhs = rhs_i }+ <- findTyEqs inerts tv_rhs+ , ev_i `eqCanDischarge` ev+ , rhs_i `tcEqType` mkTyVarTy tv ]+ = -- Inert: a ~ b+ -- Work item: b ~ a+ Just (ev_i, IsSwapped, keep_deriv ev_i)++ | otherwise+ = Nothing++ where+ keep_deriv ev_i+ | Wanted WOnly <- ctEvFlavour ev_i -- inert is [W]+ , Wanted WDeriv <- ctEvFlavour ev -- work item is [WD]+ = True -- Keep a derived verison of the work item+ | otherwise+ = False -- Work item is fully discharged++interactTyVarEq :: InertCans -> Ct -> TcS (StopOrContinue Ct)+-- CTyEqCans are always consumed, so always returns Stop+interactTyVarEq inerts workItem@(CTyEqCan { cc_tyvar = tv+ , cc_rhs = rhs+ , cc_ev = ev+ , cc_eq_rel = eq_rel })+ | Just (ev_i, swapped, keep_deriv)+ <- inertsCanDischarge inerts tv rhs ev+ = do { setEvBindIfWanted ev $+ EvCoercion (maybeSym swapped $+ tcDowngradeRole (eqRelRole eq_rel)+ (ctEvRole ev_i)+ (ctEvCoercion ev_i))++ ; let deriv_ev = CtDerived { ctev_pred = ctEvPred ev+ , ctev_loc = ctEvLoc ev }+ ; when keep_deriv $+ emitWork [workItem { cc_ev = deriv_ev }]+ -- As a Derived it might not be fully rewritten,+ -- so we emit it as new work++ ; stopWith ev "Solved from inert" }++ | ReprEq <- eq_rel -- We never solve representational+ = unsolved_inert -- equalities by unification++ | isGiven ev -- See Note [Touchables and givens]+ = unsolved_inert++ | otherwise+ = do { tclvl <- getTcLevel+ ; if canSolveByUnification tclvl tv rhs+ then do { solveByUnification ev tv rhs+ ; n_kicked <- kickOutAfterUnification tv+ ; return (Stop ev (text "Solved by unification" <+> ppr_kicked n_kicked)) }++ else unsolved_inert }++ where+ unsolved_inert+ = do { traceTcS "Can't solve tyvar equality"+ (vcat [ text "LHS:" <+> ppr tv <+> dcolon <+> ppr (tyVarKind tv)+ , ppWhen (isMetaTyVar tv) $+ nest 4 (text "TcLevel of" <+> ppr tv+ <+> text "is" <+> ppr (metaTyVarTcLevel tv))+ , text "RHS:" <+> ppr rhs <+> dcolon <+> ppr (typeKind rhs) ])+ ; addInertEq workItem+ ; stopWith ev "Kept as inert" }++interactTyVarEq _ wi = pprPanic "interactTyVarEq" (ppr wi)++solveByUnification :: CtEvidence -> TcTyVar -> Xi -> TcS ()+-- Solve with the identity coercion+-- Precondition: kind(xi) equals kind(tv)+-- Precondition: CtEvidence is Wanted or Derived+-- Precondition: CtEvidence is nominal+-- Returns: workItem where+-- workItem = the new Given constraint+--+-- NB: No need for an occurs check here, because solveByUnification always+-- arises from a CTyEqCan, a *canonical* constraint. Its invariants+-- say that in (a ~ xi), the type variable a does not appear in xi.+-- See TcRnTypes.Ct invariants.+--+-- Post: tv is unified (by side effect) with xi;+-- we often write tv := xi+solveByUnification wd tv xi+ = do { let tv_ty = mkTyVarTy tv+ ; traceTcS "Sneaky unification:" $+ vcat [text "Unifies:" <+> ppr tv <+> text ":=" <+> ppr xi,+ text "Coercion:" <+> pprEq tv_ty xi,+ text "Left Kind is:" <+> ppr (typeKind tv_ty),+ text "Right Kind is:" <+> ppr (typeKind xi) ]++ ; unifyTyVar tv xi+ ; setEvBindIfWanted wd (EvCoercion (mkTcNomReflCo xi)) }++ppr_kicked :: Int -> SDoc+ppr_kicked 0 = empty+ppr_kicked n = parens (int n <+> text "kicked out")++{- Note [Avoid double unifications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The spontaneous solver has to return a given which mentions the unified unification+variable *on the left* of the equality. Here is what happens if not:+ Original wanted: (a ~ alpha), (alpha ~ Int)+We spontaneously solve the first wanted, without changing the order!+ given : a ~ alpha [having unified alpha := a]+Now the second wanted comes along, but he cannot rewrite the given, so we simply continue.+At the end we spontaneously solve that guy, *reunifying* [alpha := Int]++We avoid this problem by orienting the resulting given so that the unification+variable is on the left. [Note that alternatively we could attempt to+enforce this at canonicalization]++See also Note [No touchables as FunEq RHS] in TcSMonad; avoiding+double unifications is the main reason we disallow touchable+unification variables as RHS of type family equations: F xis ~ alpha.+++************************************************************************+* *+* Functional dependencies, instantiation of equations+* *+************************************************************************++When we spot an equality arising from a functional dependency,+we now use that equality (a "wanted") to rewrite the work-item+constraint right away. This avoids two dangers++ Danger 1: If we send the original constraint on down the pipeline+ it may react with an instance declaration, and in delicate+ situations (when a Given overlaps with an instance) that+ may produce new insoluble goals: see Trac #4952++ Danger 2: If we don't rewrite the constraint, it may re-react+ with the same thing later, and produce the same equality+ again --> termination worries.++To achieve this required some refactoring of FunDeps.hs (nicer+now!).++Note [FunDep and implicit parameter reactions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Currently, our story of interacting two dictionaries (or a dictionary+and top-level instances) for functional dependencies, and implicit+parameters, is that we simply produce new Derived equalities. So for example++ class D a b | a -> b where ...+ Inert:+ d1 :g D Int Bool+ WorkItem:+ d2 :w D Int alpha++ We generate the extra work item+ cv :d alpha ~ Bool+ where 'cv' is currently unused. However, this new item can perhaps be+ spontaneously solved to become given and react with d2,+ discharging it in favour of a new constraint d2' thus:+ d2' :w D Int Bool+ d2 := d2' |> D Int cv+ Now d2' can be discharged from d1++We could be more aggressive and try to *immediately* solve the dictionary+using those extra equalities, but that requires those equalities to carry+evidence and derived do not carry evidence.++If that were the case with the same inert set and work item we might dischard+d2 directly:++ cv :w alpha ~ Bool+ d2 := d1 |> D Int cv++But in general it's a bit painful to figure out the necessary coercion,+so we just take the first approach. Here is a better example. Consider:+ class C a b c | a -> b+And:+ [Given] d1 : C T Int Char+ [Wanted] d2 : C T beta Int+In this case, it's *not even possible* to solve the wanted immediately.+So we should simply output the functional dependency and add this guy+[but NOT its superclasses] back in the worklist. Even worse:+ [Given] d1 : C T Int beta+ [Wanted] d2: C T beta Int+Then it is solvable, but its very hard to detect this on the spot.++It's exactly the same with implicit parameters, except that the+"aggressive" approach would be much easier to implement.++Note [Weird fundeps]+~~~~~~~~~~~~~~~~~~~~+Consider class Het a b | a -> b where+ het :: m (f c) -> a -> m b++ class GHet (a :: * -> *) (b :: * -> *) | a -> b+ instance GHet (K a) (K [a])+ instance Het a b => GHet (K a) (K b)++The two instances don't actually conflict on their fundeps,+although it's pretty strange. So they are both accepted. Now+try [W] GHet (K Int) (K Bool)+This triggers fundeps from both instance decls;+ [D] K Bool ~ K [a]+ [D] K Bool ~ K beta+And there's a risk of complaining about Bool ~ [a]. But in fact+the Wanted matches the second instance, so we never get as far+as the fundeps.++Trac #7875 is a case in point.+-}++emitFunDepDeriveds :: [FunDepEqn CtLoc] -> TcS ()+-- See Note [FunDep and implicit parameter reactions]+emitFunDepDeriveds fd_eqns+ = mapM_ do_one_FDEqn fd_eqns+ where+ do_one_FDEqn (FDEqn { fd_qtvs = tvs, fd_eqs = eqs, fd_loc = loc })+ | null tvs -- Common shortcut+ = do { traceTcS "emitFunDepDeriveds 1" (ppr (ctl_depth loc) $$ ppr eqs)+ ; mapM_ (unifyDerived loc Nominal) eqs }+ | otherwise+ = do { traceTcS "emitFunDepDeriveds 2" (ppr (ctl_depth loc) $$ ppr eqs)+ ; subst <- instFlexi tvs -- Takes account of kind substitution+ ; mapM_ (do_one_eq loc subst) eqs }++ do_one_eq loc subst (Pair ty1 ty2)+ = unifyDerived loc Nominal $+ Pair (Type.substTyUnchecked subst ty1) (Type.substTyUnchecked subst ty2)++{-+**********************************************************************+* *+ The top-reaction Stage+* *+**********************************************************************+-}++topReactionsStage :: WorkItem -> TcS (StopOrContinue Ct)+topReactionsStage wi+ = do { tir <- doTopReact wi+ ; case tir of+ ContinueWith wi -> continueWith wi+ Stop ev s -> return (Stop ev (text "Top react:" <+> s)) }++doTopReact :: WorkItem -> TcS (StopOrContinue Ct)+-- The work item does not react with the inert set, so try interaction with top-level+-- instances. Note:+--+-- (a) The place to add superclasses in not here in doTopReact stage.+-- Instead superclasses are added in the worklist as part of the+-- canonicalization process. See Note [Adding superclasses].++doTopReact work_item+ = do { traceTcS "doTopReact" (ppr work_item)+ ; case work_item of+ CDictCan {} -> do { inerts <- getTcSInerts+ ; doTopReactDict inerts work_item }+ CFunEqCan {} -> doTopReactFunEq work_item+ _ -> -- Any other work item does not react with any top-level equations+ continueWith work_item }+++--------------------+doTopReactFunEq :: Ct -> TcS (StopOrContinue Ct)+doTopReactFunEq work_item@(CFunEqCan { cc_ev = old_ev, cc_fun = fam_tc+ , cc_tyargs = args, cc_fsk = fsk })++ | fsk `elemVarSet` tyCoVarsOfTypes args+ = no_reduction -- See Note [FunEq occurs-check principle]++ | otherwise -- Note [Reduction for Derived CFunEqCans]+ = do { match_res <- matchFam fam_tc args+ -- Look up in top-level instances, or built-in axiom+ -- See Note [MATCHING-SYNONYMS]+ ; case match_res of+ Nothing -> no_reduction+ Just match_info -> reduce_top_fun_eq old_ev fsk match_info }+ where+ no_reduction+ = do { improveTopFunEqs old_ev fam_tc args fsk+ ; continueWith work_item }++doTopReactFunEq w = pprPanic "doTopReactFunEq" (ppr w)++reduce_top_fun_eq :: CtEvidence -> TcTyVar -> (TcCoercion, TcType)+ -> TcS (StopOrContinue Ct)+-- We have found an applicable top-level axiom: use it to reduce+-- Precondition: fsk is not free in rhs_ty+-- old_ev is not Derived+reduce_top_fun_eq old_ev fsk (ax_co, rhs_ty)+ | isDerived old_ev+ = do { emitNewDerivedEq loc Nominal (mkTyVarTy fsk) rhs_ty+ ; stopWith old_ev "Fun/Top (derived)" }++ | Just (tc, tc_args) <- tcSplitTyConApp_maybe rhs_ty+ , isTypeFamilyTyCon tc+ , tc_args `lengthIs` tyConArity tc -- Short-cut+ = -- RHS is another type-family application+ -- Try shortcut; see Note [Top-level reductions for type functions]+ shortCutReduction old_ev fsk ax_co tc tc_args++ | isGiven old_ev -- Not shortcut+ = do { let final_co = mkTcSymCo (ctEvCoercion old_ev) `mkTcTransCo` ax_co+ -- final_co :: fsk ~ rhs_ty+ ; new_ev <- newGivenEvVar deeper_loc (mkPrimEqPred (mkTyVarTy fsk) rhs_ty,+ EvCoercion final_co)+ ; emitWorkNC [new_ev] -- Non-cannonical; that will mean we flatten rhs_ty+ ; stopWith old_ev "Fun/Top (given)" }++ | otherwise -- So old_ev is Wanted (cannot be Derived)+ = ASSERT2( not (fsk `elemVarSet` tyCoVarsOfType rhs_ty)+ , ppr old_ev $$ ppr rhs_ty )+ -- Guaranteed by Note [FunEq occurs-check principle]+ do { dischargeFmv old_ev fsk ax_co rhs_ty+ ; traceTcS "doTopReactFunEq" $+ vcat [ text "old_ev:" <+> ppr old_ev+ , nest 2 (text ":=") <+> ppr ax_co ]+ ; stopWith old_ev "Fun/Top (wanted)" }++ where+ loc = ctEvLoc old_ev+ deeper_loc = bumpCtLocDepth loc++improveTopFunEqs :: CtEvidence -> TyCon -> [TcType] -> TcTyVar -> TcS ()+-- See Note [FunDep and implicit parameter reactions]+improveTopFunEqs ev fam_tc args fsk+ | isGiven ev -- See Note [No FunEq improvement for Givens]+ || not (isImprovable ev)+ = return ()++ | otherwise+ = do { ieqs <- getInertEqs+ ; fam_envs <- getFamInstEnvs+ ; eqns <- improve_top_fun_eqs fam_envs fam_tc args+ (lookupFlattenTyVar ieqs fsk)+ ; traceTcS "improveTopFunEqs" (vcat [ ppr fam_tc <+> ppr args <+> ppr fsk+ , ppr eqns ])+ ; mapM_ (unifyDerived loc Nominal) eqns }+ where+ loc = ctEvLoc ev++improve_top_fun_eqs :: FamInstEnvs+ -> TyCon -> [TcType] -> TcType+ -> TcS [TypeEqn]+improve_top_fun_eqs fam_envs fam_tc args rhs_ty+ | Just ops <- isBuiltInSynFamTyCon_maybe fam_tc+ = return (sfInteractTop ops args rhs_ty)++ -- see Note [Type inference for type families with injectivity]+ | isOpenTypeFamilyTyCon fam_tc+ , Injective injective_args <- familyTyConInjectivityInfo fam_tc+ = -- it is possible to have several compatible equations in an open type+ -- family but we only want to derive equalities from one such equation.+ concatMapM (injImproveEqns injective_args) (take 1 $+ buildImprovementData (lookupFamInstEnvByTyCon fam_envs fam_tc)+ fi_tvs fi_tys fi_rhs (const Nothing))++ | Just ax <- isClosedSynFamilyTyConWithAxiom_maybe fam_tc+ , Injective injective_args <- familyTyConInjectivityInfo fam_tc+ = concatMapM (injImproveEqns injective_args) $+ buildImprovementData (fromBranches (co_ax_branches ax))+ cab_tvs cab_lhs cab_rhs Just++ | otherwise+ = return []++ where+ buildImprovementData+ :: [a] -- axioms for a TF (FamInst or CoAxBranch)+ -> (a -> [TyVar]) -- get bound tyvars of an axiom+ -> (a -> [Type]) -- get LHS of an axiom+ -> (a -> Type) -- get RHS of an axiom+ -> (a -> Maybe CoAxBranch) -- Just => apartness check required+ -> [( [Type], TCvSubst, [TyVar], Maybe CoAxBranch )]+ -- Result:+ -- ( [arguments of a matching axiom]+ -- , RHS-unifying substitution+ -- , axiom variables without substitution+ -- , Maybe matching axiom [Nothing - open TF, Just - closed TF ] )+ buildImprovementData axioms axiomTVs axiomLHS axiomRHS wrap =+ [ (ax_args, subst, unsubstTvs, wrap axiom)+ | axiom <- axioms+ , let ax_args = axiomLHS axiom+ ax_rhs = axiomRHS axiom+ ax_tvs = axiomTVs axiom+ , Just subst <- [tcUnifyTyWithTFs False ax_rhs rhs_ty]+ , let notInSubst tv = not (tv `elemVarEnv` getTvSubstEnv subst)+ unsubstTvs = filter (notInSubst <&&> isTyVar) ax_tvs ]+ -- The order of unsubstTvs is important; it must be+ -- in telescope order e.g. (k:*) (a:k)++ injImproveEqns :: [Bool]+ -> ([Type], TCvSubst, [TyCoVar], Maybe CoAxBranch)+ -> TcS [TypeEqn]+ injImproveEqns inj_args (ax_args, subst, unsubstTvs, cabr)+ = do { subst <- instFlexiX subst unsubstTvs+ -- If the current substitution bind [k -> *], and+ -- one of the un-substituted tyvars is (a::k), we'd better+ -- be sure to apply the current substitution to a's kind.+ -- Hence instFlexiX. Trac #13135 was an example.++ ; return [ Pair (substTyUnchecked subst ax_arg) arg+ -- NB: the ax_arg part is on the left+ -- see Note [Improvement orientation]+ | case cabr of+ Just cabr' -> apartnessCheck (substTys subst ax_args) cabr'+ _ -> True+ , (ax_arg, arg, True) <- zip3 ax_args args inj_args ] }+++shortCutReduction :: CtEvidence -> TcTyVar -> TcCoercion+ -> TyCon -> [TcType] -> TcS (StopOrContinue Ct)+-- See Note [Top-level reductions for type functions]+shortCutReduction old_ev fsk ax_co fam_tc tc_args+ = ASSERT( ctEvEqRel old_ev == NomEq)+ do { (xis, cos) <- flattenManyNom old_ev tc_args+ -- ax_co :: F args ~ G tc_args+ -- cos :: xis ~ tc_args+ -- old_ev :: F args ~ fsk+ -- G cos ; sym ax_co ; old_ev :: G xis ~ fsk++ ; new_ev <- case ctEvFlavour old_ev of+ Given -> newGivenEvVar deeper_loc+ ( mkPrimEqPred (mkTyConApp fam_tc xis) (mkTyVarTy fsk)+ , EvCoercion (mkTcTyConAppCo Nominal fam_tc cos+ `mkTcTransCo` mkTcSymCo ax_co+ `mkTcTransCo` ctEvCoercion old_ev) )++ Wanted {} ->+ do { (new_ev, new_co) <- newWantedEq deeper_loc Nominal+ (mkTyConApp fam_tc xis) (mkTyVarTy fsk)+ ; setWantedEq (ctev_dest old_ev) $+ ax_co `mkTcTransCo` mkTcSymCo (mkTcTyConAppCo Nominal+ fam_tc cos)+ `mkTcTransCo` new_co+ ; return new_ev }++ Derived -> pprPanic "shortCutReduction" (ppr old_ev)++ ; let new_ct = CFunEqCan { cc_ev = new_ev, cc_fun = fam_tc+ , cc_tyargs = xis, cc_fsk = fsk }+ ; updWorkListTcS (extendWorkListFunEq new_ct)+ ; stopWith old_ev "Fun/Top (shortcut)" }+ where+ deeper_loc = bumpCtLocDepth (ctEvLoc old_ev)++dischargeFmv :: CtEvidence -> TcTyVar -> TcCoercion -> TcType -> TcS ()+-- (dischargeFmv x fmv co ty)+-- [W] ev :: F tys ~ fmv+-- co :: F tys ~ xi+-- Precondition: fmv is not filled, and fmv `notElem` xi+-- ev is Wanted+--+-- Then set fmv := xi,+-- set ev := co+-- kick out any inert things that are now rewritable+--+-- Does not evaluate 'co' if 'ev' is Derived+dischargeFmv ev@(CtWanted { ctev_dest = dest }) fmv co xi+ = ASSERT2( not (fmv `elemVarSet` tyCoVarsOfType xi), ppr ev $$ ppr fmv $$ ppr xi )+ do { setWantedEvTerm dest (EvCoercion co)+ ; unflattenFmv fmv xi+ ; n_kicked <- kickOutAfterUnification fmv+ ; traceTcS "dischargeFmv" (ppr fmv <+> equals <+> ppr xi $$ ppr_kicked n_kicked) }+dischargeFmv ev _ _ _ = pprPanic "dischargeFmv" (ppr ev)++{- Note [Top-level reductions for type functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+c.f. Note [The flattening story] in TcFlatten++Suppose we have a CFunEqCan F tys ~ fmv/fsk, and a matching axiom.+Here is what we do, in four cases:++* Wanteds: general firing rule+ (work item) [W] x : F tys ~ fmv+ instantiate axiom: ax_co : F tys ~ rhs++ Then:+ Discharge fmv := rhs+ Discharge x := ax_co ; sym x2+ This is *the* way that fmv's get unified; even though they are+ "untouchable".++ NB: Given Note [FunEq occurs-check principle], fmv does not appear+ in tys, and hence does not appear in the instantiated RHS. So+ the unification can't make an infinite type.++* Wanteds: short cut firing rule+ Applies when the RHS of the axiom is another type-function application+ (work item) [W] x : F tys ~ fmv+ instantiate axiom: ax_co : F tys ~ G rhs_tys++ It would be a waste to create yet another fmv for (G rhs_tys).+ Instead (shortCutReduction):+ - Flatten rhs_tys (cos : rhs_tys ~ rhs_xis)+ - Add G rhs_xis ~ fmv to flat cache (note: the same old fmv)+ - New canonical wanted [W] x2 : G rhs_xis ~ fmv (CFunEqCan)+ - Discharge x := ax_co ; G cos ; x2++* Givens: general firing rule+ (work item) [G] g : F tys ~ fsk+ instantiate axiom: ax_co : F tys ~ rhs++ Now add non-canonical given (since rhs is not flat)+ [G] (sym g ; ax_co) : fsk ~ rhs (Non-canonical)++* Givens: short cut firing rule+ Applies when the RHS of the axiom is another type-function application+ (work item) [G] g : F tys ~ fsk+ instantiate axiom: ax_co : F tys ~ G rhs_tys++ It would be a waste to create yet another fsk for (G rhs_tys).+ Instead (shortCutReduction):+ - Flatten rhs_tys: flat_cos : tys ~ flat_tys+ - Add new Canonical given+ [G] (sym (G flat_cos) ; co ; g) : G flat_tys ~ fsk (CFunEqCan)++Note [FunEq occurs-check principle]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+I have spent a lot of time finding a good way to deal with+CFunEqCan constraints like+ F (fuv, a) ~ fuv+where flatten-skolem occurs on the LHS. Now in principle we+might may progress by doing a reduction, but in practice its+hard to find examples where it is useful, and easy to find examples+where we fall into an infinite reduction loop. A rule that works+very well is this:++ *** FunEq occurs-check principle ***++ Do not reduce a CFunEqCan+ F tys ~ fsk+ if fsk appears free in tys+ Instead we treat it as stuck.++Examples:++* Trac #5837 has [G] a ~ TF (a,Int), with an instance+ type instance TF (a,b) = (TF a, TF b)+ This readily loops when solving givens. But with the FunEq occurs+ check principle, it rapidly gets stuck which is fine.++* Trac #12444 is a good example, explained in comment:2. We have+ type instance F (Succ x) = Succ (F x)+ [W] alpha ~ Succ (F alpha)+ If we allow the reduction to happen, we get an infinite loop++Note [Cached solved FunEqs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+When trying to solve, say (FunExpensive big-type ~ ty), it's important+to see if we have reduced (FunExpensive big-type) before, lest we+simply repeat it. Hence the lookup in inert_solved_funeqs. Moreover+we must use `funEqCanDischarge` because both uses might (say) be Wanteds,+and we *still* want to save the re-computation.++Note [MATCHING-SYNONYMS]+~~~~~~~~~~~~~~~~~~~~~~~~+When trying to match a dictionary (D tau) to a top-level instance, or a+type family equation (F taus_1 ~ tau_2) to a top-level family instance,+we do *not* need to expand type synonyms because the matcher will do that for us.++Note [Improvement orientation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A very delicate point is the orientation of derived equalities+arising from injectivity improvement (Trac #12522). Suppse we have+ type family F x = t | t -> x+ type instance F (a, Int) = (Int, G a)+where G is injective; and wanted constraints++ [W] TF (alpha, beta) ~ fuv+ [W] fuv ~ (Int, <some type>)++The injectivity will give rise to derived constraints++ [D] gamma1 ~ alpha+ [D] Int ~ beta++The fresh unification variable gamma1 comes from the fact that we+can only do "partial improvement" here; see Section 5.2 of+"Injective type families for Haskell" (HS'15).++Now, it's very important to orient the equations this way round,+so that the fresh unification variable will be eliminated in+favour of alpha. If we instead had+ [D] alpha ~ gamma1+then we would unify alpha := gamma1; and kick out the wanted+constraint. But when we grough it back in, it'd look like+ [W] TF (gamma1, beta) ~ fuv+and exactly the same thing would happen again! Infnite loop.++This all sesms fragile, and it might seem more robust to avoid+introducing gamma1 in the first place, in the case where the+actual argument (alpha, beta) partly matches the improvement+template. But that's a bit tricky, esp when we remember that the+kinds much match too; so it's easier to let the normal machinery+handle it. Instead we are careful to orient the new derived+equality with the template on the left. Delicate, but it works.++Note [No FunEq improvement for Givens]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't do improvements (injectivity etc) for Givens. Why?++* It generates Derived constraints on skolems, which don't do us+ much good, except perhaps identify inaccessible branches.+ (They'd be perfectly valid though.)++* For type-nat stuff the derived constraints include type families;+ e.g. (a < b), (b < c) ==> a < c If we generate a Derived for this,+ we'll generate a Derived/Wanted CFunEqCan; and, since the same+ InertCans (after solving Givens) are used for each iteration, that+ massively confused the unflattening step (TcFlatten.unflatten).++ In fact it led to some infinite loops:+ indexed-types/should_compile/T10806+ indexed-types/should_compile/T10507+ polykinds/T10742++Note [Reduction for Derived CFunEqCans]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+You may wonder if it's important to use top-level instances to+simplify [D] CFunEqCan's. But it is. Here's an example (T10226).++ type instance F Int = Int+ type instance FInv Int = Int++Suppose we have to solve+ [WD] FInv (F alpha) ~ alpha+ [WD] F alpha ~ Int++ --> flatten+ [WD] F alpha ~ fuv0+ [WD] FInv fuv0 ~ fuv1 -- (A)+ [WD] fuv1 ~ alpha+ [WD] fuv0 ~ Int -- (B)++ --> Rewwrite (A) with (B), splitting it+ [WD] F alpha ~ fuv0+ [W] FInv fuv0 ~ fuv1+ [D] FInv Int ~ fuv1 -- (C)+ [WD] fuv1 ~ alpha+ [WD] fuv0 ~ Int++ --> Reduce (C) with top-level instance+ **** This is the key step ***+ [WD] F alpha ~ fuv0+ [W] FInv fuv0 ~ fuv1+ [D] fuv1 ~ Int -- (D)+ [WD] fuv1 ~ alpha -- (E)+ [WD] fuv0 ~ Int++ --> Rewrite (D) with (E)+ [WD] F alpha ~ fuv0+ [W] FInv fuv0 ~ fuv1+ [D] alpha ~ Int -- (F)+ [WD] fuv1 ~ alpha+ [WD] fuv0 ~ Int++ --> unify (F) alpha := Int, and that solves it++Another example is indexed-types/should_compile/T10634+-}++{- *******************************************************************+* *+ Top-level reaction for class constraints (CDictCan)+* *+**********************************************************************-}++doTopReactDict :: InertSet -> Ct -> TcS (StopOrContinue Ct)+-- Try to use type-class instance declarations to simplify the constraint+doTopReactDict inerts work_item@(CDictCan { cc_ev = fl, cc_class = cls+ , cc_tyargs = xis })+ | isGiven fl -- Never use instances for Given constraints+ = do { try_fundep_improvement+ ; continueWith work_item }++ | Just ev <- lookupSolvedDict inerts cls xis -- Cached+ = do { setEvBindIfWanted fl (ctEvTerm ev)+ ; stopWith fl "Dict/Top (cached)" }++ | otherwise -- Wanted or Derived, but not cached+ = do { dflags <- getDynFlags+ ; lkup_inst_res <- matchClassInst dflags inerts cls xis dict_loc+ ; case lkup_inst_res of+ GenInst { lir_new_theta = theta+ , lir_mk_ev = mk_ev+ , lir_safe_over = s } ->+ do { traceTcS "doTopReact/found instance for" $ ppr fl+ ; checkReductionDepth deeper_loc dict_pred+ ; unless s $ insertSafeOverlapFailureTcS work_item+ ; if isDerived fl then finish_derived theta+ else finish_wanted theta mk_ev }+ NoInstance ->+ do { when (isImprovable fl) $+ try_fundep_improvement+ ; continueWith work_item } }+ where+ dict_pred = mkClassPred cls xis+ dict_loc = ctEvLoc fl+ dict_origin = ctLocOrigin dict_loc+ deeper_loc = zap_origin (bumpCtLocDepth dict_loc)++ zap_origin loc -- After applying an instance we can set ScOrigin to+ -- infinity, so that prohibitedSuperClassSolve never fires+ | ScOrigin {} <- dict_origin+ = setCtLocOrigin loc (ScOrigin infinity)+ | otherwise+ = loc++ finish_wanted :: [TcPredType]+ -> ([EvTerm] -> EvTerm) -> TcS (StopOrContinue Ct)+ -- Precondition: evidence term matches the predicate workItem+ finish_wanted theta mk_ev+ = do { addSolvedDict fl cls xis+ ; evc_vars <- mapM (newWanted deeper_loc) theta+ ; setWantedEvBind (ctEvId fl) (mk_ev (map getEvTerm evc_vars))+ ; emitWorkNC (freshGoals evc_vars)+ ; stopWith fl "Dict/Top (solved wanted)" }++ finish_derived theta -- Use type-class instances for Deriveds, in the hope+ = -- of generating some improvements+ -- C.f. Example 3 of Note [The improvement story]+ -- It's easy because no evidence is involved+ do { emitNewDeriveds deeper_loc theta+ ; traceTcS "finish_derived" (ppr (ctl_depth deeper_loc))+ ; stopWith fl "Dict/Top (solved derived)" }++ -- We didn't solve it; so try functional dependencies with+ -- the instance environment, and return+ -- See also Note [Weird fundeps]+ try_fundep_improvement+ = do { traceTcS "try_fundeps" (ppr work_item)+ ; instEnvs <- getInstEnvs+ ; emitFunDepDeriveds $+ improveFromInstEnv instEnvs mk_ct_loc dict_pred }++ mk_ct_loc :: PredType -- From instance decl+ -> SrcSpan -- also from instance deol+ -> CtLoc+ mk_ct_loc inst_pred inst_loc+ = dict_loc { ctl_origin = FunDepOrigin2 dict_pred dict_origin+ inst_pred inst_loc }++doTopReactDict _ w = pprPanic "doTopReactDict" (ppr w)+++{- *******************************************************************+* *+ Class lookup+* *+**********************************************************************-}++-- | Indicates if Instance met the Safe Haskell overlapping instances safety+-- check.+--+-- See Note [Safe Haskell Overlapping Instances] in TcSimplify+-- See Note [Safe Haskell Overlapping Instances Implementation] in TcSimplify+type SafeOverlapping = Bool++data LookupInstResult+ = NoInstance+ | GenInst { lir_new_theta :: [TcPredType]+ , lir_mk_ev :: [EvTerm] -> EvTerm+ , lir_safe_over :: SafeOverlapping }++instance Outputable LookupInstResult where+ ppr NoInstance = text "NoInstance"+ ppr (GenInst { lir_new_theta = ev+ , lir_safe_over = s })+ = text "GenInst" <+> vcat [ppr ev, ss]+ where ss = text $ if s then "[safe]" else "[unsafe]"+++matchClassInst :: DynFlags -> InertSet -> Class -> [Type] -> CtLoc -> TcS LookupInstResult+matchClassInst dflags inerts clas tys loc+-- First check whether there is an in-scope Given that could+-- match this constraint. In that case, do not use top-level+-- instances. See Note [Instance and Given overlap]+ | not (xopt LangExt.IncoherentInstances dflags)+ , not (naturallyCoherentClass clas)+ , let matchable_givens = matchableGivens loc pred inerts+ , not (isEmptyBag matchable_givens)+ = do { traceTcS "Delaying instance application" $+ vcat [ text "Work item=" <+> pprClassPred clas tys+ , text "Potential matching givens:" <+> ppr matchable_givens ]+ ; return NoInstance }+ where+ pred = mkClassPred clas tys++matchClassInst dflags _ clas tys loc+ = do { traceTcS "matchClassInst" $ text "pred =" <+> ppr (mkClassPred clas tys) <+> char '{'+ ; res <- match_class_inst dflags clas tys loc+ ; traceTcS "} matchClassInst result" $ ppr res+ ; return res }++match_class_inst :: DynFlags -> Class -> [Type] -> CtLoc -> TcS LookupInstResult+match_class_inst dflags clas tys loc+ | cls_name == knownNatClassName = matchKnownNat clas tys+ | cls_name == knownSymbolClassName = matchKnownSymbol clas tys+ | isCTupleClass clas = matchCTuple clas tys+ | cls_name == typeableClassName = matchTypeable clas tys+ | clas `hasKey` heqTyConKey = matchLiftedEquality tys+ | clas `hasKey` coercibleTyConKey = matchLiftedCoercible tys+ | cls_name == hasFieldClassName = matchHasField dflags clas tys loc+ | otherwise = matchInstEnv dflags clas tys loc+ where+ cls_name = className clas++{- Note [Instance and Given overlap]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Example, from the OutsideIn(X) paper:+ instance P x => Q [x]+ instance (x ~ y) => R y [x]++ wob :: forall a b. (Q [b], R b a) => a -> Int++ g :: forall a. Q [a] => [a] -> Int+ g x = wob x++From 'g' we get the impliation constraint:+ forall a. Q [a] => (Q [beta], R beta [a])+If we react (Q [beta]) with its top-level axiom, we end up with a+(P beta), which we have no way of discharging. On the other hand,+if we react R beta [a] with the top-level we get (beta ~ a), which+is solvable and can help us rewrite (Q [beta]) to (Q [a]) which is+now solvable by the given Q [a].++The partial solution is that:+ In matchClassInst (and thus in topReact), we return a matching+ instance only when there is no Given in the inerts which is+ unifiable to this particular dictionary.++ We treat any meta-tyvar as "unifiable" for this purpose,+ *including* untouchable ones. But not skolems like 'a' in+ the implication constraint above.++The end effect is that, much as we do for overlapping instances, we+delay choosing a class instance if there is a possibility of another+instance OR a given to match our constraint later on. This fixes+Trac #4981 and #5002.++Other notes:++* The check is done *first*, so that it also covers classes+ with built-in instance solving, such as+ - constraint tuples+ - natural numbers+ - Typeable++* The given-overlap problem is arguably not easy to appear in practice+ due to our aggressive prioritization of equality solving over other+ constraints, but it is possible. I've added a test case in+ typecheck/should-compile/GivenOverlapping.hs++* Another "live" example is Trac #10195; another is #10177.++* We ignore the overlap problem if -XIncoherentInstances is in force:+ see Trac #6002 for a worked-out example where this makes a+ difference.++* Moreover notice that our goals here are different than the goals of+ the top-level overlapping checks. There we are interested in+ validating the following principle:++ If we inline a function f at a site where the same global+ instance environment is available as the instance environment at+ the definition site of f then we should get the same behaviour.++ But for the Given Overlap check our goal is just related to completeness of+ constraint solving.++* The solution is only a partial one. Consider the above example with+ g :: forall a. Q [a] => [a] -> Int+ g x = let v = wob x+ in v+ and suppose we have -XNoMonoLocalBinds, so that we attempt to find the most+ general type for 'v'. When generalising v's type we'll simplify its+ Q [alpha] constraint, but we don't have Q [a] in the 'givens', so we+ will use the instance declaration after all. Trac #11948 was a case+ in point.++All of this is disgustingly delicate, so to discourage people from writing+simplifiable class givens, we warn about signatures that contain them;#+see TcValidity Note [Simplifiable given constraints].+-}+++{- *******************************************************************+* *+ Class lookup in the instance environment+* *+**********************************************************************-}++matchInstEnv :: DynFlags -> Class -> [Type] -> CtLoc -> TcS LookupInstResult+matchInstEnv dflags clas tys loc+ = do { instEnvs <- getInstEnvs+ ; let safeOverlapCheck = safeHaskell dflags `elem` [Sf_Safe, Sf_Trustworthy]+ (matches, unify, unsafeOverlaps) = lookupInstEnv True instEnvs clas tys+ safeHaskFail = safeOverlapCheck && not (null unsafeOverlaps)+ ; case (matches, unify, safeHaskFail) of++ -- Nothing matches+ ([], _, _)+ -> do { traceTcS "matchClass not matching" $+ vcat [ text "dict" <+> ppr pred ]+ ; return NoInstance }++ -- A single match (& no safe haskell failure)+ ([(ispec, inst_tys)], [], False)+ -> do { let dfun_id = instanceDFunId ispec+ ; traceTcS "matchClass success" $+ vcat [text "dict" <+> ppr pred,+ text "witness" <+> ppr dfun_id+ <+> ppr (idType dfun_id) ]+ -- Record that this dfun is needed+ ; match_one (null unsafeOverlaps) dfun_id inst_tys }++ -- More than one matches (or Safe Haskell fail!). Defer any+ -- reactions of a multitude until we learn more about the reagent+ (matches, _, _)+ -> do { traceTcS "matchClass multiple matches, deferring choice" $+ vcat [text "dict" <+> ppr pred,+ text "matches" <+> ppr matches]+ ; return NoInstance } }+ where+ pred = mkClassPred clas tys++ match_one :: SafeOverlapping -> DFunId -> [DFunInstType] -> TcS LookupInstResult+ -- See Note [DFunInstType: instantiating types] in InstEnv+ match_one so dfun_id mb_inst_tys+ = do { checkWellStagedDFun pred dfun_id loc+ ; (tys, theta) <- instDFunType dfun_id mb_inst_tys+ ; return $ GenInst { lir_new_theta = theta+ , lir_mk_ev = EvDFunApp dfun_id tys+ , lir_safe_over = so } }+++{- ********************************************************************+* *+ Class lookup for CTuples+* *+***********************************************************************-}++matchCTuple :: Class -> [Type] -> TcS LookupInstResult+matchCTuple clas tys -- (isCTupleClass clas) holds+ = return (GenInst { lir_new_theta = tys+ , lir_mk_ev = tuple_ev+ , lir_safe_over = True })+ -- The dfun *is* the data constructor!+ where+ data_con = tyConSingleDataCon (classTyCon clas)+ tuple_ev = EvDFunApp (dataConWrapId data_con) tys++{- ********************************************************************+* *+ Class lookup for Literals+* *+***********************************************************************-}++matchKnownNat :: Class -> [Type] -> TcS LookupInstResult+matchKnownNat clas [ty] -- clas = KnownNat+ | Just n <- isNumLitTy ty = makeLitDict clas ty (EvNum n)+matchKnownNat _ _ = return NoInstance++matchKnownSymbol :: Class -> [Type] -> TcS LookupInstResult+matchKnownSymbol clas [ty] -- clas = KnownSymbol+ | Just n <- isStrLitTy ty = makeLitDict clas ty (EvStr n)+matchKnownSymbol _ _ = return NoInstance+++makeLitDict :: Class -> Type -> EvLit -> TcS LookupInstResult+-- makeLitDict adds a coercion that will convert the literal into a dictionary+-- of the appropriate type. See Note [KnownNat & KnownSymbol and EvLit]+-- in TcEvidence. The coercion happens in 2 steps:+--+-- Integer -> SNat n -- representation of literal to singleton+-- SNat n -> KnownNat n -- singleton to dictionary+--+-- The process is mirrored for Symbols:+-- String -> SSymbol n+-- SSymbol n -> KnownSymbol n -}+makeLitDict clas ty evLit+ | Just (_, co_dict) <- tcInstNewTyCon_maybe (classTyCon clas) [ty]+ -- co_dict :: KnownNat n ~ SNat n+ , [ meth ] <- classMethods clas+ , Just tcRep <- tyConAppTyCon_maybe -- SNat+ $ funResultTy -- SNat n+ $ dropForAlls -- KnownNat n => SNat n+ $ idType meth -- forall n. KnownNat n => SNat n+ , Just (_, co_rep) <- tcInstNewTyCon_maybe tcRep [ty]+ -- SNat n ~ Integer+ , let ev_tm = mkEvCast (EvLit evLit) (mkTcSymCo (mkTcTransCo co_dict co_rep))+ = return $ GenInst { lir_new_theta = []+ , lir_mk_ev = \_ -> ev_tm+ , lir_safe_over = True }++ | otherwise+ = panicTcS (text "Unexpected evidence for" <+> ppr (className clas)+ $$ vcat (map (ppr . idType) (classMethods clas)))+++{- ********************************************************************+* *+ Class lookup for Typeable+* *+***********************************************************************-}++-- | Assumes that we've checked that this is the 'Typeable' class,+-- and it was applied to the correct argument.+matchTypeable :: Class -> [Type] -> TcS LookupInstResult+matchTypeable clas [k,t] -- clas = Typeable+ -- For the first two cases, See Note [No Typeable for polytypes or qualified types]+ | isForAllTy k = return NoInstance -- Polytype+ | isJust (tcSplitPredFunTy_maybe t) = return NoInstance -- Qualified type++ -- Now cases that do work+ | k `eqType` typeNatKind = doTyLit knownNatClassName t+ | k `eqType` typeSymbolKind = doTyLit knownSymbolClassName t+ | isConstraintKind t = doTyConApp clas t constraintKindTyCon []+ | Just (arg,ret) <- splitFunTy_maybe t = doFunTy clas t arg ret+ | Just (tc, ks) <- splitTyConApp_maybe t -- See Note [Typeable (T a b c)]+ , onlyNamedBndrsApplied tc ks = doTyConApp clas t tc ks+ | Just (f,kt) <- splitAppTy_maybe t = doTyApp clas t f kt++matchTypeable _ _ = return NoInstance++-- | Representation for a type @ty@ of the form @arg -> ret@.+doFunTy :: Class -> Type -> Type -> Type -> TcS LookupInstResult+doFunTy clas ty arg_ty ret_ty+ = do { let preds = map (mk_typeable_pred clas) [arg_ty, ret_ty]+ build_ev [arg_ev, ret_ev] =+ EvTypeable ty $ EvTypeableTrFun arg_ev ret_ev+ build_ev _ = panic "TcInteract.doFunTy"+ ; return $ GenInst preds build_ev True+ }++-- | Representation for type constructor applied to some kinds.+-- 'onlyNamedBndrsApplied' has ensured that this application results in a type+-- of monomorphic kind (e.g. all kind variables have been instantiated).+doTyConApp :: Class -> Type -> TyCon -> [Kind] -> TcS LookupInstResult+doTyConApp clas ty tc kind_args+ = return $ GenInst (map (mk_typeable_pred clas) kind_args)+ (\kinds -> EvTypeable ty $ EvTypeableTyCon tc kinds)+ True++-- | Representation for TyCon applications of a concrete kind. We just use the+-- kind itself, but first we must make sure that we've instantiated all kind-+-- polymorphism, but no more.+onlyNamedBndrsApplied :: TyCon -> [KindOrType] -> Bool+onlyNamedBndrsApplied tc ks+ = all isNamedTyConBinder used_bndrs &&+ not (any isNamedTyConBinder leftover_bndrs)+ where+ bndrs = tyConBinders tc+ (used_bndrs, leftover_bndrs) = splitAtList ks bndrs++doTyApp :: Class -> Type -> Type -> KindOrType -> TcS LookupInstResult+-- Representation for an application of a type to a type-or-kind.+-- This may happen when the type expression starts with a type variable.+-- Example (ignoring kind parameter):+-- Typeable (f Int Char) -->+-- (Typeable (f Int), Typeable Char) -->+-- (Typeable f, Typeable Int, Typeable Char) --> (after some simp. steps)+-- Typeable f+doTyApp clas ty f tk+ | isForAllTy (typeKind f)+ = return NoInstance -- We can't solve until we know the ctr.+ | otherwise+ = return $ GenInst (map (mk_typeable_pred clas) [f, tk])+ (\[t1,t2] -> EvTypeable ty $ EvTypeableTyApp t1 t2)+ True++-- Emit a `Typeable` constraint for the given type.+mk_typeable_pred :: Class -> Type -> PredType+mk_typeable_pred clas ty = mkClassPred clas [ typeKind ty, ty ]++ -- Typeable is implied by KnownNat/KnownSymbol. In the case of a type literal+ -- we generate a sub-goal for the appropriate class. See #10348 for what+ -- happens when we fail to do this.+doTyLit :: Name -> Type -> TcS LookupInstResult+doTyLit kc t = do { kc_clas <- tcLookupClass kc+ ; let kc_pred = mkClassPred kc_clas [ t ]+ mk_ev [ev] = EvTypeable t $ EvTypeableTyLit ev+ mk_ev _ = panic "doTyLit"+ ; return (GenInst [kc_pred] mk_ev True) }++{- Note [Typeable (T a b c)]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For type applications we always decompose using binary application,+via doTyApp, until we get to a *kind* instantiation. Example+ Proxy :: forall k. k -> *++To solve Typeable (Proxy (* -> *) Maybe) we+ - First decompose with doTyApp,+ to get (Typeable (Proxy (* -> *))) and Typeable Maybe+ - Then solve (Typeable (Proxy (* -> *))) with doTyConApp++If we attempt to short-cut by solving it all at once, via+doTyConApp++(this note is sadly truncated FIXME)+++Note [No Typeable for polytypes or qualified types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do not support impredicative typeable, such as+ Typeable (forall a. a->a)+ Typeable (Eq a => a -> a)+ Typeable (() => Int)+ Typeable (((),()) => Int)++See Trac #9858. For forall's the case is clear: we simply don't have+a TypeRep for them. For qualified but not polymorphic types, like+(Eq a => a -> a), things are murkier. But:++ * We don't need a TypeRep for these things. TypeReps are for+ monotypes only.++ * Perhaps we could treat `=>` as another type constructor for `Typeable`+ purposes, and thus support things like `Eq Int => Int`, however,+ at the current state of affairs this would be an odd exception as+ no other class works with impredicative types.+ For now we leave it off, until we have a better story for impredicativity.+-}++solveCallStack :: CtEvidence -> EvCallStack -> TcS ()+solveCallStack ev ev_cs = do+ -- We're given ev_cs :: CallStack, but the evidence term should be a+ -- dictionary, so we have to coerce ev_cs to a dictionary for+ -- `IP ip CallStack`. See Note [Overview of implicit CallStacks]+ let ev_tm = mkEvCast (EvCallStack ev_cs) (wrapIP (ctEvPred ev))+ setWantedEvBind (ctEvId ev) ev_tm++{- ********************************************************************+* *+ Class lookup for lifted equality+* *+***********************************************************************-}++-- See also Note [The equality types story] in TysPrim+matchLiftedEquality :: [Type] -> TcS LookupInstResult+matchLiftedEquality args+ = return (GenInst { lir_new_theta = [ mkTyConApp eqPrimTyCon args ]+ , lir_mk_ev = EvDFunApp (dataConWrapId heqDataCon) args+ , lir_safe_over = True })++-- See also Note [The equality types story] in TysPrim+matchLiftedCoercible :: [Type] -> TcS LookupInstResult+matchLiftedCoercible args@[k, t1, t2]+ = return (GenInst { lir_new_theta = [ mkTyConApp eqReprPrimTyCon args' ]+ , lir_mk_ev = EvDFunApp (dataConWrapId coercibleDataCon)+ args+ , lir_safe_over = True })+ where+ args' = [k, k, t1, t2]+matchLiftedCoercible args = pprPanic "matchLiftedCoercible" (ppr args)+++{- ********************************************************************+* *+ Class lookup for overloaded record fields+* *+***********************************************************************-}++{-+Note [HasField instances]+~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have++ data T y = MkT { foo :: [y] }++and `foo` is in scope. Then GHC will automatically solve a constraint like++ HasField "foo" (T Int) b++by emitting a new wanted++ T alpha -> [alpha] ~# T Int -> b++and building a HasField dictionary out of the selector function `foo`,+appropriately cast.++The HasField class is defined (in GHC.Records) thus:++ class HasField (x :: k) r a | x r -> a where+ getField :: r -> a++Since this is a one-method class, it is represented as a newtype.+Hence we can solve `HasField "foo" (T Int) b` by taking an expression+of type `T Int -> b` and casting it using the newtype coercion.+Note that++ foo :: forall y . T y -> [y]++so the expression we construct is++ foo @alpha |> co++where++ co :: (T alpha -> [alpha]) ~# HasField "foo" (T Int) b++is built from++ co1 :: (T alpha -> [alpha]) ~# (T Int -> b)++which is the new wanted, and++ co2 :: (T Int -> b) ~# HasField "foo" (T Int) b++which can be derived from the newtype coercion.++If `foo` is not in scope, or has a higher-rank or existentially+quantified type, then the constraint is not solved automatically, but+may be solved by a user-supplied HasField instance. Similarly, if we+encounter a HasField constraint where the field is not a literal+string, or does not belong to the type, then we fall back on the+normal constraint solver behaviour.+-}++-- See Note [HasField instances]+matchHasField :: DynFlags -> Class -> [Type] -> CtLoc -> TcS LookupInstResult+matchHasField dflags clas tys loc+ = do { fam_inst_envs <- getFamInstEnvs+ ; rdr_env <- getGlobalRdrEnvTcS+ ; case tys of+ -- We are matching HasField {k} x r a...+ [_k_ty, x_ty, r_ty, a_ty]+ -- x should be a literal string+ | Just x <- isStrLitTy x_ty+ -- r should be an applied type constructor+ , Just (tc, args) <- tcSplitTyConApp_maybe r_ty+ -- use representation tycon (if data family); it has the fields+ , let r_tc = fstOf3 (tcLookupDataFamInst fam_inst_envs tc args)+ -- x should be a field of r+ , Just fl <- lookupTyConFieldLabel x r_tc+ -- the field selector should be in scope+ , Just gre <- lookupGRE_FieldLabel rdr_env fl++ -> do { sel_id <- tcLookupId (flSelector fl)+ ; (tv_prs, preds, sel_ty) <- tcInstType newMetaTyVars sel_id++ -- The first new wanted constraint equates the actual+ -- type of the selector with the type (r -> a) within+ -- the HasField x r a dictionary. The preds will+ -- typically be empty, but if the datatype has a+ -- "stupid theta" then we have to include it here.+ ; let theta = mkPrimEqPred sel_ty (mkFunTy r_ty a_ty) : preds++ -- Use the equality proof to cast the selector Id to+ -- type (r -> a), then use the newtype coercion to cast+ -- it to a HasField dictionary.+ mk_ev (ev1:evs) = EvSelector sel_id tvs evs `EvCast` co+ where+ co = mkTcSubCo (evTermCoercion ev1)+ `mkTcTransCo` mkTcSymCo co2+ mk_ev [] = panic "matchHasField.mk_ev"++ Just (_, co2) = tcInstNewTyCon_maybe (classTyCon clas)+ tys++ tvs = mkTyVarTys (map snd tv_prs)++ -- The selector must not be "naughty" (i.e. the field+ -- cannot have an existentially quantified type), and+ -- it must not be higher-rank.+ ; if not (isNaughtyRecordSelector sel_id) && isTauTy sel_ty+ then do { addUsedGRE True gre+ ; return GenInst { lir_new_theta = theta+ , lir_mk_ev = mk_ev+ , lir_safe_over = True+ } }+ else matchInstEnv dflags clas tys loc }++ _ -> matchInstEnv dflags clas tys loc }
+ typecheck/TcMType.hs view
@@ -0,0 +1,1703 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Monadic type operations++This module contains monadic operations over types that contain+mutable type variables+-}++{-# LANGUAGE CPP, TupleSections, MultiWayIf #-}++module TcMType (+ TcTyVar, TcKind, TcType, TcTauType, TcThetaType, TcTyVarSet,++ --------------------------------+ -- Creating new mutable type variables+ newFlexiTyVar,+ newFlexiTyVarTy, -- Kind -> TcM TcType+ newFlexiTyVarTys, -- Int -> Kind -> TcM [TcType]+ newOpenFlexiTyVarTy, newOpenTypeKind,+ newMetaKindVar, newMetaKindVars, newMetaTyVarTyAtLevel,+ cloneMetaTyVar,+ newFmvTyVar, newFskTyVar,++ readMetaTyVar, writeMetaTyVar, writeMetaTyVarRef,+ newMetaDetails, isFilledMetaTyVar, isUnfilledMetaTyVar,++ --------------------------------+ -- Expected types+ ExpType(..), ExpSigmaType, ExpRhoType,+ mkCheckExpType,+ newInferExpType, newInferExpTypeInst, newInferExpTypeNoInst,+ readExpType, readExpType_maybe,+ expTypeToType, checkingExpType_maybe, checkingExpType,+ tauifyExpType, inferResultToType,++ --------------------------------+ -- Creating fresh type variables for pm checking+ genInstSkolTyVarsX,++ --------------------------------+ -- Creating new evidence variables+ newEvVar, newEvVars, newDict,+ newWanted, newWanteds, cloneWanted, cloneWC,+ emitWanted, emitWantedEq, emitWantedEvVar, emitWantedEvVars,+ newTcEvBinds, addTcEvBind,++ newCoercionHole, fillCoercionHole, isFilledCoercionHole,+ unpackCoercionHole, unpackCoercionHole_maybe,+ checkCoercionHole,++ --------------------------------+ -- Instantiation+ newMetaTyVars, newMetaTyVarX, newMetaTyVarsX,+ newMetaSigTyVars, newMetaSigTyVarX,+ newSigTyVar, newWildCardX,+ tcInstType,+ tcInstSkolTyVars,tcInstSkolTyVarsX,+ tcInstSuperSkolTyVarsX,+ tcSkolDFunType, tcSuperSkolTyVars,++ instSkolTyCoVars, freshenTyVarBndrs, freshenCoVarBndrsX,++ --------------------------------+ -- Zonking and tidying+ zonkTidyTcType, zonkTidyOrigin,+ mkTypeErrorThing, mkTypeErrorThingArgs,+ tidyEvVar, tidyCt, tidySkolemInfo,+ skolemiseRuntimeUnk,+ zonkTcTyVar, zonkTcTyVars, zonkTcTyVarToTyVar,+ zonkTyCoVarsAndFV, zonkTcTypeAndFV,+ zonkTyCoVarsAndFVList,+ zonkTcTypeAndSplitDepVars, zonkTcTypesAndSplitDepVars,+ zonkQuantifiedTyVar, defaultTyVar,+ quantifyTyVars, quantifyZonkedTyVars,+ zonkTcTyCoVarBndr, zonkTcTyVarBinder,+ zonkTcType, zonkTcTypes, zonkCo,+ zonkTyCoVarKind, zonkTcTypeMapper,++ zonkEvVar, zonkWC, zonkSimples, zonkId, zonkCt, zonkSkolemInfo,++ tcGetGlobalTyCoVars,++ ------------------------------+ -- Levity polymorphism+ ensureNotLevPoly, checkForLevPoly, checkForLevPolyX, formatLevPolyErr+ ) where++#include "HsVersions.h"++-- friends:+import TyCoRep+import TcType+import Type+import Kind+import Coercion+import Class+import Var++-- others:+import TcRnMonad -- TcType, amongst others+import TcEvidence+import Id+import Name+import VarSet+import TysWiredIn+import TysPrim+import VarEnv+import NameEnv+import PrelNames+import Util+import Outputable+import FastString+import SrcLoc+import Bag+import Pair+import UniqSet+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Maybes+import Data.List ( mapAccumL )+import Control.Arrow ( second )++{-+************************************************************************+* *+ Kind variables+* *+************************************************************************+-}++mkKindName :: Unique -> Name+mkKindName unique = mkSystemName unique kind_var_occ++kind_var_occ :: OccName -- Just one for all MetaKindVars+ -- They may be jiggled by tidying+kind_var_occ = mkOccName tvName "k"++newMetaKindVar :: TcM TcKind+newMetaKindVar = do { uniq <- newUnique+ ; details <- newMetaDetails TauTv+ ; let kv = mkTcTyVar (mkKindName uniq) liftedTypeKind details+ ; return (mkTyVarTy kv) }++newMetaKindVars :: Int -> TcM [TcKind]+newMetaKindVars n = mapM (\ _ -> newMetaKindVar) (nOfThem n ())++{-+************************************************************************+* *+ Evidence variables; range over constraints we can abstract over+* *+************************************************************************+-}++newEvVars :: TcThetaType -> TcM [EvVar]+newEvVars theta = mapM newEvVar theta++--------------++newEvVar :: TcPredType -> TcRnIf gbl lcl EvVar+-- Creates new *rigid* variables for predicates+newEvVar ty = do { name <- newSysName (predTypeOccName ty)+ ; return (mkLocalIdOrCoVar name ty) }++newWanted :: CtOrigin -> Maybe TypeOrKind -> PredType -> TcM CtEvidence+-- Deals with both equality and non-equality predicates+newWanted orig t_or_k pty+ = do loc <- getCtLocM orig t_or_k+ d <- if isEqPred pty then HoleDest <$> newCoercionHole+ else EvVarDest <$> newEvVar pty+ return $ CtWanted { ctev_dest = d+ , ctev_pred = pty+ , ctev_nosh = WDeriv+ , ctev_loc = loc }++newWanteds :: CtOrigin -> ThetaType -> TcM [CtEvidence]+newWanteds orig = mapM (newWanted orig Nothing)++cloneWanted :: Ct -> TcM CtEvidence+cloneWanted ct+ = newWanted (ctEvOrigin ev) Nothing (ctEvPred ev)+ where+ ev = ctEvidence ct++cloneWC :: WantedConstraints -> TcM WantedConstraints+cloneWC wc@(WC { wc_simple = simples, wc_impl = implics })+ = do { simples' <- mapBagM clone_one simples+ ; implics' <- mapBagM clone_implic implics+ ; return (wc { wc_simple = simples', wc_impl = implics' }) }+ where+ clone_one ct = do { ev <- cloneWanted ct; return (mkNonCanonical ev) }++ clone_implic implic@(Implic { ic_wanted = inner_wanted })+ = do { inner_wanted' <- cloneWC inner_wanted+ ; return (implic { ic_wanted = inner_wanted' }) }++-- | Emits a new Wanted. Deals with both equalities and non-equalities.+emitWanted :: CtOrigin -> TcPredType -> TcM EvTerm+emitWanted origin pty+ = do { ev <- newWanted origin Nothing pty+ ; emitSimple $ mkNonCanonical ev+ ; return $ ctEvTerm ev }++-- | Emits a new equality constraint+emitWantedEq :: CtOrigin -> TypeOrKind -> Role -> TcType -> TcType -> TcM Coercion+emitWantedEq origin t_or_k role ty1 ty2+ = do { hole <- newCoercionHole+ ; loc <- getCtLocM origin (Just t_or_k)+ ; emitSimple $ mkNonCanonical $+ CtWanted { ctev_pred = pty, ctev_dest = HoleDest hole+ , ctev_nosh = WDeriv, ctev_loc = loc }+ ; return (mkHoleCo hole role ty1 ty2) }+ where+ pty = mkPrimEqPredRole role ty1 ty2++-- | Creates a new EvVar and immediately emits it as a Wanted.+-- No equality predicates here.+emitWantedEvVar :: CtOrigin -> TcPredType -> TcM EvVar+emitWantedEvVar origin ty+ = do { new_cv <- newEvVar ty+ ; loc <- getCtLocM origin Nothing+ ; let ctev = CtWanted { ctev_dest = EvVarDest new_cv+ , ctev_pred = ty+ , ctev_nosh = WDeriv+ , ctev_loc = loc }+ ; emitSimple $ mkNonCanonical ctev+ ; return new_cv }++emitWantedEvVars :: CtOrigin -> [TcPredType] -> TcM [EvVar]+emitWantedEvVars orig = mapM (emitWantedEvVar orig)++newDict :: Class -> [TcType] -> TcM DictId+newDict cls tys+ = do { name <- newSysName (mkDictOcc (getOccName cls))+ ; return (mkLocalId name (mkClassPred cls tys)) }++predTypeOccName :: PredType -> OccName+predTypeOccName ty = case classifyPredType ty of+ ClassPred cls _ -> mkDictOcc (getOccName cls)+ EqPred _ _ _ -> mkVarOccFS (fsLit "cobox")+ IrredPred _ -> mkVarOccFS (fsLit "irred")++{-+************************************************************************+* *+ Coercion holes+* *+************************************************************************+-}++newCoercionHole :: TcM CoercionHole+newCoercionHole+ = do { u <- newUnique+ ; traceTc "New coercion hole:" (ppr u)+ ; ref <- newMutVar Nothing+ ; return $ CoercionHole u ref }++-- | Put a value in a coercion hole+fillCoercionHole :: CoercionHole -> Coercion -> TcM ()+fillCoercionHole (CoercionHole u ref) co+ = do {+#ifdef DEBUG+ ; cts <- readTcRef ref+ ; whenIsJust cts $ \old_co ->+ pprPanic "Filling a filled coercion hole" (ppr u $$ ppr co $$ ppr old_co)+#endif+ ; traceTc "Filling coercion hole" (ppr u <+> text ":=" <+> ppr co)+ ; writeTcRef ref (Just co) }++-- | Is a coercion hole filled in?+isFilledCoercionHole :: CoercionHole -> TcM Bool+isFilledCoercionHole (CoercionHole _ ref) = isJust <$> readTcRef ref++-- | Retrieve the contents of a coercion hole. Panics if the hole+-- is unfilled+unpackCoercionHole :: CoercionHole -> TcM Coercion+unpackCoercionHole hole+ = do { contents <- unpackCoercionHole_maybe hole+ ; case contents of+ Just co -> return co+ Nothing -> pprPanic "Unfilled coercion hole" (ppr hole) }++-- | Retrieve the contents of a coercion hole, if it is filled+unpackCoercionHole_maybe :: CoercionHole -> TcM (Maybe Coercion)+unpackCoercionHole_maybe (CoercionHole _ ref) = readTcRef ref++-- | Check that a coercion is appropriate for filling a hole. (The hole+-- itself is needed only for printing. NB: This must be /lazy/ in the coercion,+-- as it's used in TcHsSyn in the presence of knots.+-- Always returns the checked coercion, but this return value is necessary+-- so that the input coercion is forced only when the output is forced.+checkCoercionHole :: Coercion -> CoercionHole -> Role -> Type -> Type -> TcM Coercion+checkCoercionHole co h r t1 t2+-- co is already zonked, but t1 and t2 might not be+ | debugIsOn+ = do { t1 <- zonkTcType t1+ ; t2 <- zonkTcType t2+ ; let (Pair _t1 _t2, _role) = coercionKindRole co+ ; return $+ ASSERT2( t1 `eqType` _t1 && t2 `eqType` _t2 && r == _role+ , (text "Bad coercion hole" <+>+ ppr h <> colon <+> vcat [ ppr _t1, ppr _t2, ppr _role+ , ppr co, ppr t1, ppr t2+ , ppr r ]) )+ co }+ | otherwise+ = return co++{-+************************************************************************+*+ Expected types+*+************************************************************************++Note [ExpType]+~~~~~~~~~~~~~~++An ExpType is used as the "expected type" when type-checking an expression.+An ExpType can hold a "hole" that can be filled in by the type-checker.+This allows us to have one tcExpr that works in both checking mode and+synthesis mode (that is, bidirectional type-checking). Previously, this+was achieved by using ordinary unification variables, but we don't need+or want that generality. (For example, #11397 was caused by doing the+wrong thing with unification variables.) Instead, we observe that these+holes should++1. never be nested+2. never appear as the type of a variable+3. be used linearly (never be duplicated)++By defining ExpType, separately from Type, we can achieve goals 1 and 2+statically.++See also [wiki:Typechecking]++Note [TcLevel of ExpType]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ data G a where+ MkG :: G Bool++ foo MkG = True++This is a classic untouchable-variable / ambiguous GADT return type+scenario. But, with ExpTypes, we'll be inferring the type of the RHS.+And, because there is only one branch of the case, we won't trigger+Note [Case branches must never infer a non-tau type] of TcMatches.+We thus must track a TcLevel in an Inferring ExpType. If we try to+fill the ExpType and find that the TcLevels don't work out, we+fill the ExpType with a tau-tv at the low TcLevel, hopefully to+be worked out later by some means. This is triggered in+test gadt/gadt-escape1.++-}++-- actual data definition is in TcType++-- | Make an 'ExpType' suitable for inferring a type of kind * or #.+newInferExpTypeNoInst :: TcM ExpSigmaType+newInferExpTypeNoInst = newInferExpType False++newInferExpTypeInst :: TcM ExpRhoType+newInferExpTypeInst = newInferExpType True++newInferExpType :: Bool -> TcM ExpType+newInferExpType inst+ = do { u <- newUnique+ ; tclvl <- getTcLevel+ ; traceTc "newOpenInferExpType" (ppr u <+> ppr inst <+> ppr tclvl)+ ; ref <- newMutVar Nothing+ ; return (Infer (IR { ir_uniq = u, ir_lvl = tclvl+ , ir_ref = ref, ir_inst = inst })) }++-- | Extract a type out of an ExpType, if one exists. But one should always+-- exist. Unless you're quite sure you know what you're doing.+readExpType_maybe :: ExpType -> TcM (Maybe TcType)+readExpType_maybe (Check ty) = return (Just ty)+readExpType_maybe (Infer (IR { ir_ref = ref})) = readMutVar ref++-- | Extract a type out of an ExpType. Otherwise, panics.+readExpType :: ExpType -> TcM TcType+readExpType exp_ty+ = do { mb_ty <- readExpType_maybe exp_ty+ ; case mb_ty of+ Just ty -> return ty+ Nothing -> pprPanic "Unknown expected type" (ppr exp_ty) }++-- | Returns the expected type when in checking mode.+checkingExpType_maybe :: ExpType -> Maybe TcType+checkingExpType_maybe (Check ty) = Just ty+checkingExpType_maybe _ = Nothing++-- | Returns the expected type when in checking mode. Panics if in inference+-- mode.+checkingExpType :: String -> ExpType -> TcType+checkingExpType _ (Check ty) = ty+checkingExpType err et = pprPanic "checkingExpType" (text err $$ ppr et)++tauifyExpType :: ExpType -> TcM ExpType+-- ^ Turn a (Infer hole) type into a (Check alpha),+-- where alpha is a fresh unification variable+tauifyExpType (Check ty) = return (Check ty) -- No-op for (Check ty)+tauifyExpType (Infer inf_res) = do { ty <- inferResultToType inf_res+ ; return (Check ty) }++-- | Extracts the expected type if there is one, or generates a new+-- TauTv if there isn't.+expTypeToType :: ExpType -> TcM TcType+expTypeToType (Check ty) = return ty+expTypeToType (Infer inf_res) = inferResultToType inf_res++inferResultToType :: InferResult -> TcM Type+inferResultToType (IR { ir_uniq = u, ir_lvl = tc_lvl+ , ir_ref = ref })+ = do { rr <- newMetaTyVarTyAtLevel tc_lvl runtimeRepTy+ ; tau <- newMetaTyVarTyAtLevel tc_lvl (tYPE rr)+ -- See Note [TcLevel of ExpType]+ ; writeMutVar ref (Just tau)+ ; traceTc "Forcing ExpType to be monomorphic:"+ (ppr u <+> text ":=" <+> ppr tau)+ ; return tau }+++{- *********************************************************************+* *+ SkolemTvs (immutable)+* *+********************************************************************* -}++tcInstType :: ([TyVar] -> TcM (TCvSubst, [TcTyVar]))+ -- ^ How to instantiate the type variables+ -> Id -- ^ Type to instantiate+ -> TcM ([(Name, TcTyVar)], TcThetaType, TcType) -- ^ Result+ -- (type vars, preds (incl equalities), rho)+tcInstType inst_tyvars id+ = case tcSplitForAllTys (idType id) of+ ([], rho) -> let -- There may be overloading despite no type variables;+ -- (?x :: Int) => Int -> Int+ (theta, tau) = tcSplitPhiTy rho+ in+ return ([], theta, tau)++ (tyvars, rho) -> do { (subst, tyvars') <- inst_tyvars tyvars+ ; let (theta, tau) = tcSplitPhiTy (substTyAddInScope subst rho)+ tv_prs = map tyVarName tyvars `zip` tyvars'+ ; return (tv_prs, theta, tau) }++tcSkolDFunType :: DFunId -> TcM ([TcTyVar], TcThetaType, TcType)+-- Instantiate a type signature with skolem constants.+-- We could give them fresh names, but no need to do so+tcSkolDFunType dfun+ = do { (tv_prs, theta, tau) <- tcInstType tcInstSuperSkolTyVars dfun+ ; return (map snd tv_prs, theta, tau) }++tcSuperSkolTyVars :: [TyVar] -> (TCvSubst, [TcTyVar])+-- Make skolem constants, but do *not* give them new names, as above+-- Moreover, make them "super skolems"; see comments with superSkolemTv+-- see Note [Kind substitution when instantiating]+-- Precondition: tyvars should be ordered by scoping+tcSuperSkolTyVars = mapAccumL tcSuperSkolTyVar emptyTCvSubst++tcSuperSkolTyVar :: TCvSubst -> TyVar -> (TCvSubst, TcTyVar)+tcSuperSkolTyVar subst tv+ = (extendTvSubstWithClone subst tv new_tv, new_tv)+ where+ kind = substTyUnchecked subst (tyVarKind tv)+ new_tv = mkTcTyVar (tyVarName tv) kind superSkolemTv++-- | Given a list of @['TyVar']@, skolemize the type variables,+-- returning a substitution mapping the original tyvars to the+-- skolems, and the list of newly bound skolems. See also+-- tcInstSkolTyVars' for a precondition. The resulting+-- skolems are non-overlappable; see Note [Overlap and deriving]+-- for an example where this matters.+tcInstSkolTyVars :: [TyVar] -> TcM (TCvSubst, [TcTyVar])+tcInstSkolTyVars = tcInstSkolTyVarsX emptyTCvSubst++tcInstSkolTyVarsX :: TCvSubst -> [TyVar] -> TcM (TCvSubst, [TcTyVar])+tcInstSkolTyVarsX = tcInstSkolTyVars' False++tcInstSuperSkolTyVars :: [TyVar] -> TcM (TCvSubst, [TcTyVar])+tcInstSuperSkolTyVars = tcInstSuperSkolTyVarsX emptyTCvSubst++tcInstSuperSkolTyVarsX :: TCvSubst -> [TyVar] -> TcM (TCvSubst, [TcTyVar])+tcInstSuperSkolTyVarsX subst = tcInstSkolTyVars' True subst++tcInstSkolTyVars' :: Bool -> TCvSubst -> [TyVar] -> TcM (TCvSubst, [TcTyVar])+-- Precondition: tyvars should be ordered (kind vars first)+-- see Note [Kind substitution when instantiating]+-- Get the location from the monad; this is a complete freshening operation+tcInstSkolTyVars' overlappable subst tvs+ = do { loc <- getSrcSpanM+ ; lvl <- getTcLevel+ ; instSkolTyCoVarsX (mkTcSkolTyVar lvl loc overlappable) subst tvs }++mkTcSkolTyVar :: TcLevel -> SrcSpan -> Bool -> TcTyVarMaker+mkTcSkolTyVar lvl loc overlappable+ = \ uniq old_name kind -> mkTcTyVar (mkInternalName uniq (getOccName old_name) loc)+ kind details+ where+ details = SkolemTv (pushTcLevel lvl) overlappable+ -- NB: skolems bump the level++------------------+freshenTyVarBndrs :: [TyVar] -> TcRnIf gbl lcl (TCvSubst, [TyVar])+-- ^ Give fresh uniques to a bunch of TyVars, but they stay+-- as TyVars, rather than becoming TcTyVars+-- Used in FamInst.newFamInst, and Inst.newClsInst+freshenTyVarBndrs = instSkolTyCoVars mk_tv+ where+ mk_tv uniq old_name kind = mkTyVar (setNameUnique old_name uniq) kind++freshenCoVarBndrsX :: TCvSubst -> [CoVar] -> TcRnIf gbl lcl (TCvSubst, [CoVar])+-- ^ Give fresh uniques to a bunch of CoVars+-- Used in FamInst.newFamInst+freshenCoVarBndrsX subst = instSkolTyCoVarsX mk_cv subst+ where+ mk_cv uniq old_name kind = mkCoVar (setNameUnique old_name uniq) kind++------------------+type TcTyVarMaker = Unique -> Name -> Kind -> TyCoVar+instSkolTyCoVars :: TcTyVarMaker -> [TyVar] -> TcRnIf gbl lcl (TCvSubst, [TyCoVar])+instSkolTyCoVars mk_tcv = instSkolTyCoVarsX mk_tcv emptyTCvSubst++instSkolTyCoVarsX :: TcTyVarMaker+ -> TCvSubst -> [TyCoVar] -> TcRnIf gbl lcl (TCvSubst, [TyCoVar])+instSkolTyCoVarsX mk_tcv = mapAccumLM (instSkolTyCoVarX mk_tcv)++instSkolTyCoVarX :: TcTyVarMaker+ -> TCvSubst -> TyCoVar -> TcRnIf gbl lcl (TCvSubst, TyCoVar)+instSkolTyCoVarX mk_tcv subst tycovar+ = do { uniq <- newUnique -- using a new unique is critical. See+ -- Note [Skolems in zonkSyntaxExpr] in TcHsSyn+ ; let new_tcv = mk_tcv uniq old_name kind+ subst1 | isTyVar new_tcv+ = extendTvSubstWithClone subst tycovar new_tcv+ | otherwise+ = extendCvSubstWithClone subst tycovar new_tcv+ ; return (subst1, new_tcv) }+ where+ old_name = tyVarName tycovar+ kind = substTyUnchecked subst (tyVarKind tycovar)++newFskTyVar :: TcType -> TcM TcTyVar+newFskTyVar fam_ty+ = do { uniq <- newUnique+ ; let name = mkSysTvName uniq (fsLit "fsk")+ ; return (mkTcTyVar name (typeKind fam_ty) (FlatSkol fam_ty)) }+{-+Note [Kind substitution when instantiating]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we instantiate a bunch of kind and type variables, first we+expect them to be topologically sorted.+Then we have to instantiate the kind variables, build a substitution+from old variables to the new variables, then instantiate the type+variables substituting the original kind.++Exemple: If we want to instantiate+ [(k1 :: *), (k2 :: *), (a :: k1 -> k2), (b :: k1)]+we want+ [(?k1 :: *), (?k2 :: *), (?a :: ?k1 -> ?k2), (?b :: ?k1)]+instead of the buggous+ [(?k1 :: *), (?k2 :: *), (?a :: k1 -> k2), (?b :: k1)]+++************************************************************************+* *+ MetaTvs (meta type variables; mutable)+* *+************************************************************************+-}++mkMetaTyVarName :: Unique -> FastString -> Name+-- Makes a /System/ Name, which is eagerly eliminated by+-- the unifier; see TcUnify.nicer_to_update_tv1, and+-- TcCanonical.canEqTyVarTyVar (nicer_to_update_tv2)+mkMetaTyVarName uniq str = mkSysTvName uniq str++newSigTyVar :: Name -> Kind -> TcM TcTyVar+newSigTyVar name kind+ = do { details <- newMetaDetails SigTv+ ; return (mkTcTyVar name kind details) }++newFmvTyVar :: TcType -> TcM TcTyVar+-- Very like newMetaTyVar, except sets mtv_tclvl to one less+-- so that the fmv is untouchable.+newFmvTyVar fam_ty+ = do { uniq <- newUnique+ ; ref <- newMutVar Flexi+ ; cur_lvl <- getTcLevel+ ; let details = MetaTv { mtv_info = FlatMetaTv+ , mtv_ref = ref+ , mtv_tclvl = fmvTcLevel cur_lvl }+ name = mkMetaTyVarName uniq (fsLit "s")+ ; return (mkTcTyVar name (typeKind fam_ty) details) }++newMetaDetails :: MetaInfo -> TcM TcTyVarDetails+newMetaDetails info+ = do { ref <- newMutVar Flexi+ ; tclvl <- getTcLevel+ ; return (MetaTv { mtv_info = info+ , mtv_ref = ref+ , mtv_tclvl = tclvl }) }++cloneMetaTyVar :: TcTyVar -> TcM TcTyVar+cloneMetaTyVar tv+ = ASSERT( isTcTyVar tv )+ do { uniq <- newUnique+ ; ref <- newMutVar Flexi+ ; let name' = setNameUnique (tyVarName tv) uniq+ details' = case tcTyVarDetails tv of+ details@(MetaTv {}) -> details { mtv_ref = ref }+ _ -> pprPanic "cloneMetaTyVar" (ppr tv)+ ; return (mkTcTyVar name' (tyVarKind tv) details') }++-- Works for both type and kind variables+readMetaTyVar :: TyVar -> TcM MetaDetails+readMetaTyVar tyvar = ASSERT2( isMetaTyVar tyvar, ppr tyvar )+ readMutVar (metaTyVarRef tyvar)++isFilledMetaTyVar :: TyVar -> TcM Bool+-- True of a filled-in (Indirect) meta type variable+isFilledMetaTyVar tv+ | MetaTv { mtv_ref = ref } <- tcTyVarDetails tv+ = do { details <- readMutVar ref+ ; return (isIndirect details) }+ | otherwise = return False++isUnfilledMetaTyVar :: TyVar -> TcM Bool+-- True of a un-filled-in (Flexi) meta type variable+isUnfilledMetaTyVar tv+ | MetaTv { mtv_ref = ref } <- tcTyVarDetails tv+ = do { details <- readMutVar ref+ ; return (isFlexi details) }+ | otherwise = return False++--------------------+-- Works with both type and kind variables+writeMetaTyVar :: TcTyVar -> TcType -> TcM ()+-- Write into a currently-empty MetaTyVar++writeMetaTyVar tyvar ty+ | not debugIsOn+ = writeMetaTyVarRef tyvar (metaTyVarRef tyvar) ty++-- Everything from here on only happens if DEBUG is on+ | not (isTcTyVar tyvar)+ = WARN( True, text "Writing to non-tc tyvar" <+> ppr tyvar )+ return ()++ | MetaTv { mtv_ref = ref } <- tcTyVarDetails tyvar+ = writeMetaTyVarRef tyvar ref ty++ | otherwise+ = WARN( True, text "Writing to non-meta tyvar" <+> ppr tyvar )+ return ()++--------------------+writeMetaTyVarRef :: TcTyVar -> TcRef MetaDetails -> TcType -> TcM ()+-- Here the tyvar is for error checking only;+-- the ref cell must be for the same tyvar+writeMetaTyVarRef tyvar ref ty+ | not debugIsOn+ = do { traceTc "writeMetaTyVar" (ppr tyvar <+> dcolon <+> ppr (tyVarKind tyvar)+ <+> text ":=" <+> ppr ty)+ ; writeTcRef ref (Indirect ty) }++ -- Everything from here on only happens if DEBUG is on+ | otherwise+ = do { meta_details <- readMutVar ref;+ -- Zonk kinds to allow the error check to work+ ; zonked_tv_kind <- zonkTcType tv_kind+ ; zonked_ty_kind <- zonkTcType ty_kind+ ; let kind_check_ok = isPredTy tv_kind -- Don't check kinds for updates+ -- to coercion variables+ || tcEqKind zonked_ty_kind zonked_tv_kind++ kind_msg = hang (text "Ill-kinded update to meta tyvar")+ 2 ( ppr tyvar <+> text "::" <+> (ppr tv_kind $$ ppr zonked_tv_kind)+ <+> text ":="+ <+> ppr ty <+> text "::" <+> (ppr ty_kind $$ ppr zonked_ty_kind) )++ ; traceTc "writeMetaTyVar" (ppr tyvar <+> text ":=" <+> ppr ty)++ -- Check for double updates+ ; MASSERT2( isFlexi meta_details, double_upd_msg meta_details )++ -- Check for level OK+ -- See Note [Level check when unifying]+ ; MASSERT2( level_check_ok, level_check_msg )++ -- Check Kinds ok+ ; MASSERT2( kind_check_ok, kind_msg )++ -- Do the write+ ; writeMutVar ref (Indirect ty) }+ where+ tv_kind = tyVarKind tyvar+ ty_kind = typeKind ty++ tv_lvl = tcTyVarLevel tyvar+ ty_lvl = tcTypeLevel ty++ level_check_ok = isFmvTyVar tyvar+ || not (ty_lvl `strictlyDeeperThan` tv_lvl)+ level_check_msg = ppr ty_lvl $$ ppr tv_lvl $$ ppr tyvar $$ ppr ty++ double_upd_msg details = hang (text "Double update of meta tyvar")+ 2 (ppr tyvar $$ ppr details)+++{- Note [Level check when unifying]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When unifying+ alpha:lvl := ty+we expect that the TcLevel of 'ty' will be <= lvl.+However, during unflatting we do+ fuv:l := ty:(l+1)+which is usually wrong; hence the check isFmmvTyVar in level_check_ok.+See Note [TcLevel assignment] in TcType.+-}++{-+% Generating fresh variables for pattern match check+-}++-- UNINSTANTIATED VERSION OF tcInstSkolTyCoVars+genInstSkolTyVarsX :: SrcSpan -> TCvSubst -> [TyVar]+ -> TcRnIf gbl lcl (TCvSubst, [TcTyVar])+-- Precondition: tyvars should be scoping-ordered+-- see Note [Kind substitution when instantiating]+-- Get the location from the monad; this is a complete freshening operation+genInstSkolTyVarsX loc subst tvs+ = instSkolTyCoVarsX (mkTcSkolTyVar topTcLevel loc False) subst tvs++{-+************************************************************************+* *+ MetaTvs: TauTvs+* *+************************************************************************++Note [Never need to instantiate coercion variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+With coercion variables sloshing around in types, it might seem that we+sometimes need to instantiate coercion variables. This would be problematic,+because coercion variables inhabit unboxed equality (~#), and the constraint+solver thinks in terms only of boxed equality (~). The solution is that+we never need to instantiate coercion variables in the first place.++The tyvars that we need to instantiate come from the types of functions,+data constructors, and patterns. These will never be quantified over+coercion variables, except for the special case of the promoted Eq#. But,+that can't ever appear in user code, so we're safe!+-}++newAnonMetaTyVar :: MetaInfo -> Kind -> TcM TcTyVar+-- Make a new meta tyvar out of thin air+newAnonMetaTyVar meta_info kind+ = do { uniq <- newUnique+ ; let name = mkMetaTyVarName uniq s+ s = case meta_info of+ TauTv -> fsLit "t"+ FlatMetaTv -> fsLit "fmv"+ SigTv -> fsLit "a"+ ; details <- newMetaDetails meta_info+ ; return (mkTcTyVar name kind details) }++newFlexiTyVar :: Kind -> TcM TcTyVar+newFlexiTyVar kind = newAnonMetaTyVar TauTv kind++newFlexiTyVarTy :: Kind -> TcM TcType+newFlexiTyVarTy kind = do+ tc_tyvar <- newFlexiTyVar kind+ return (mkTyVarTy tc_tyvar)++newFlexiTyVarTys :: Int -> Kind -> TcM [TcType]+newFlexiTyVarTys n kind = mapM newFlexiTyVarTy (nOfThem n kind)++newOpenTypeKind :: TcM TcKind+newOpenTypeKind+ = do { rr <- newFlexiTyVarTy runtimeRepTy+ ; return (tYPE rr) }++-- | Create a tyvar that can be a lifted or unlifted type.+-- Returns alpha :: TYPE kappa, where both alpha and kappa are fresh+newOpenFlexiTyVarTy :: TcM TcType+newOpenFlexiTyVarTy+ = do { kind <- newOpenTypeKind+ ; newFlexiTyVarTy kind }++newMetaSigTyVars :: [TyVar] -> TcM (TCvSubst, [TcTyVar])+newMetaSigTyVars = mapAccumLM newMetaSigTyVarX emptyTCvSubst++newMetaTyVars :: [TyVar] -> TcM (TCvSubst, [TcTyVar])+-- Instantiate with META type variables+-- Note that this works for a sequence of kind, type, and coercion variables+-- variables. Eg [ (k:*), (a:k->k) ]+-- Gives [ (k7:*), (a8:k7->k7) ]+newMetaTyVars = mapAccumLM newMetaTyVarX emptyTCvSubst+ -- emptyTCvSubst has an empty in-scope set, but that's fine here+ -- Since the tyvars are freshly made, they cannot possibly be+ -- captured by any existing for-alls.++newMetaTyVarX :: TCvSubst -> TyVar -> TcM (TCvSubst, TcTyVar)+-- Make a new unification variable tyvar whose Name and Kind come from+-- an existing TyVar. We substitute kind variables in the kind.+newMetaTyVarX subst tyvar = new_meta_tv_x TauTv subst tyvar++newMetaTyVarsX :: TCvSubst -> [TyVar] -> TcM (TCvSubst, [TcTyVar])+-- Just like newMetaTyVars, but start with an existing substitution.+newMetaTyVarsX subst = mapAccumLM newMetaTyVarX subst++newMetaSigTyVarX :: TCvSubst -> TyVar -> TcM (TCvSubst, TcTyVar)+-- Just like newMetaTyVarX, but make a SigTv+newMetaSigTyVarX subst tyvar = new_meta_tv_x SigTv subst tyvar++newWildCardX :: TCvSubst -> TyVar -> TcM (TCvSubst, TcTyVar)+newWildCardX subst tv+ = do { new_tv <- newAnonMetaTyVar TauTv (substTy subst (tyVarKind tv))+ ; return (extendTvSubstWithClone subst tv new_tv, new_tv) }++new_meta_tv_x :: MetaInfo -> TCvSubst -> TyVar -> TcM (TCvSubst, TcTyVar)+new_meta_tv_x info subst tv+ = do { uniq <- newUnique+ ; details <- newMetaDetails info+ ; let name = mkSystemName uniq (getOccName tv)+ -- See Note [Name of an instantiated type variable]+ kind = substTyUnchecked subst (tyVarKind tv)+ -- NOTE: Trac #12549 is fixed so we could use+ -- substTy here, but the tc_infer_args problem+ -- is not yet fixed so leaving as unchecked for now.+ -- OLD NOTE:+ -- Unchecked because we call newMetaTyVarX from+ -- tcInstBinderX, which is called from tc_infer_args+ -- which does not yet take enough trouble to ensure+ -- the in-scope set is right; e.g. Trac #12785 trips+ -- if we use substTy here+ new_tv = mkTcTyVar name kind details+ subst1 = extendTvSubstWithClone subst tv new_tv+ ; return (subst1, new_tv) }++newMetaTyVarTyAtLevel :: TcLevel -> TcKind -> TcM TcType+newMetaTyVarTyAtLevel tc_lvl kind+ = do { uniq <- newUnique+ ; ref <- newMutVar Flexi+ ; let name = mkMetaTyVarName uniq (fsLit "p")+ details = MetaTv { mtv_info = TauTv+ , mtv_ref = ref+ , mtv_tclvl = tc_lvl }+ ; return (mkTyVarTy (mkTcTyVar name kind details)) }++{- Note [Name of an instantiated type variable]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+At the moment we give a unification variable a System Name, which+influences the way it is tidied; see TypeRep.tidyTyVarBndr.++************************************************************************+* *+ Quantification+* *+************************************************************************++Note [quantifyTyVars]+~~~~~~~~~~~~~~~~~~~~~+quantifyTyVars is given the free vars of a type that we+are about to wrap in a forall.++It takes these free type/kind variables (partitioned into dependent and+non-dependent variables) and+ 1. Zonks them and remove globals and covars+ 2. Extends kvs1 with free kind vars in the kinds of tvs (removing globals)+ 3. Calls zonkQuantifiedTyVar on each++Step (2) is often unimportant, because the kind variable is often+also free in the type. Eg+ Typeable k (a::k)+has free vars {k,a}. But the type (see Trac #7916)+ (f::k->*) (a::k)+has free vars {f,a}, but we must add 'k' as well! Hence step (3).++* This function distinguishes between dependent and non-dependent+ variables only to keep correct defaulting behavior with -XNoPolyKinds.+ With -XPolyKinds, it treats both classes of variables identically.++* quantifyTyVars never quantifies over+ - a coercion variable+ - a runtime-rep variable++Note [quantifyTyVars determinism]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The results of quantifyTyVars are wrapped in a forall and can end up in the+interface file. One such example is inferred type signatures. They also affect+the results of optimizations, for example worker-wrapper. This means that to+get deterministic builds quantifyTyVars needs to be deterministic.++To achieve this CandidatesQTvs is backed by deterministic sets which allows them+to be later converted to a list in a deterministic order.++For more information about deterministic sets see+Note [Deterministic UniqFM] in UniqDFM.+-}++quantifyTyVars, quantifyZonkedTyVars+ :: TcTyCoVarSet -- global tvs+ -> CandidatesQTvs -- See Note [Dependent type variables] in TcType+ -> TcM [TcTyVar]+-- See Note [quantifyTyVars]+-- Can be given a mixture of TcTyVars and TyVars, in the case of+-- associated type declarations. Also accepts covars, but *never* returns any.++-- The zonked variant assumes everything is already zonked.++quantifyTyVars gbl_tvs (DV { dv_kvs = dep_tkvs, dv_tvs = nondep_tkvs })+ = do { dep_tkvs <- zonkTyCoVarsAndFVDSet dep_tkvs+ ; nondep_tkvs <- zonkTyCoVarsAndFVDSet nondep_tkvs+ ; gbl_tvs <- zonkTyCoVarsAndFV gbl_tvs+ ; quantifyZonkedTyVars gbl_tvs (DV { dv_kvs = dep_tkvs, dv_tvs = nondep_tkvs }) }++quantifyZonkedTyVars gbl_tvs dvs@(DV{ dv_kvs = dep_tkvs, dv_tvs = nondep_tkvs })+ = do { traceTc "quantifyZonkedTyVars" (vcat [ppr dvs, ppr gbl_tvs])+ ; let all_cvs = filterVarSet isCoVar $ dVarSetToVarSet dep_tkvs+ dep_kvs = dVarSetElemsWellScoped $+ dep_tkvs `dVarSetMinusVarSet` gbl_tvs+ `dVarSetMinusVarSet` closeOverKinds all_cvs+ -- dVarSetElemsWellScoped: put the kind variables into+ -- well-scoped order.+ -- E.g. [k, (a::k)] not the other way roud+ -- closeOverKinds all_cvs: do not quantify over coercion+ -- variables, or any any tvs that a covar depends on++ nondep_tvs = dVarSetElems $+ (nondep_tkvs `minusDVarSet` dep_tkvs)+ `dVarSetMinusVarSet` gbl_tvs+ -- See Note [Dependent type variables] in TcType+ -- The `minus` dep_tkvs removes any kind-level vars+ -- e.g. T k (a::k) Since k appear in a kind it'll+ -- be in dv_kvs, and is dependent. So remove it from+ -- dv_tvs which will also contain k+ -- No worry about dependent covars here;+ -- they are all in dep_tkvs+ -- No worry about scoping, because these are all+ -- type variables+ -- NB kinds of tvs are zonked by zonkTyCoVarsAndFV++ -- In the non-PolyKinds case, default the kind variables+ -- to *, and zonk the tyvars as usual. Notice that this+ -- may make quantifyTyVars return a shorter list+ -- than it was passed, but that's ok+ ; poly_kinds <- xoptM LangExt.PolyKinds+ ; dep_kvs' <- mapMaybeM (zonk_quant (not poly_kinds)) dep_kvs+ ; nondep_tvs' <- mapMaybeM (zonk_quant False) nondep_tvs+ -- Because of the order, any kind variables+ -- mentioned in the kinds of the nondep_tvs'+ -- now refer to the dep_kvs'++ ; traceTc "quantifyZonkedTyVars"+ (vcat [ text "globals:" <+> ppr gbl_tvs+ , text "nondep:" <+> pprTyVars nondep_tvs+ , text "dep:" <+> pprTyVars dep_kvs+ , text "dep_kvs'" <+> pprTyVars dep_kvs'+ , text "nondep_tvs'" <+> pprTyVars nondep_tvs' ])++ ; return (dep_kvs' ++ nondep_tvs') }+ where+ zonk_quant default_kind tkv+ | isTcTyVar tkv = zonkQuantifiedTyVar default_kind tkv+ | otherwise = return $ Just tkv+ -- For associated types, we have the class variables+ -- in scope, and they are TyVars not TcTyVars++zonkQuantifiedTyVar :: Bool -- True <=> this is a kind var and -XNoPolyKinds+ -- False <=> not a kind var or -XPolyKinds+ -> TcTyVar+ -> TcM (Maybe TcTyVar)+-- The quantified type variables often include meta type variables+-- we want to freeze them into ordinary type variables, and+-- default their kind (e.g. from TYPE v to TYPE Lifted)+-- The meta tyvar is updated to point to the new skolem TyVar. Now any+-- bound occurrences of the original type variable will get zonked to+-- the immutable version.+--+-- We leave skolem TyVars alone; they are immutable.+--+-- This function is called on both kind and type variables,+-- but kind variables *only* if PolyKinds is on.+--+-- This returns a tyvar if it should be quantified over;+-- otherwise, it returns Nothing. The latter case happens for+-- * Kind variables, with -XNoPolyKinds: don't quantify over these+-- * RuntimeRep variables: we never quantify over these++zonkQuantifiedTyVar default_kind tv+ = case tcTyVarDetails tv of+ SkolemTv {} -> do { kind <- zonkTcType (tyVarKind tv)+ ; return $ Just (setTyVarKind tv kind) }+ -- It might be a skolem type variable,+ -- for example from a user type signature++ MetaTv {}+ -> do { mb_tv <- defaultTyVar default_kind tv+ ; case mb_tv of+ True -> return Nothing+ False -> do { tv' <- skolemiseUnboundMetaTyVar tv+ ; return (Just tv') } }++ _other -> pprPanic "zonkQuantifiedTyVar" (ppr tv) -- FlatSkol, RuntimeUnk++defaultTyVar :: Bool -- True <=> please default this kind variable to *+ -> TcTyVar -- Always an unbound meta tyvar+ -> TcM Bool -- True <=> defaulted away altogether++defaultTyVar default_kind tv+ | isRuntimeRepVar tv && not_sig_tv -- We never quantify over a RuntimeRep var+ = do { traceTc "Defaulting a RuntimeRep var to LiftedRep" (ppr tv)+ ; writeMetaTyVar tv liftedRepTy+ ; return True }++ | default_kind && not_sig_tv -- -XNoPolyKinds and this is a kind var+ = do { default_kind_var tv -- so default it to * if possible+ ; return True }++ | otherwise+ = return False++ where+ -- Do not default SigTvs. Doing so would violate the invariants+ -- on SigTvs; see Note [Signature skolems] in TcType.+ -- Trac #13343 is an example+ not_sig_tv = not (isSigTyVar tv)++ default_kind_var :: TyVar -> TcM ()+ -- defaultKindVar is used exclusively with -XNoPolyKinds+ -- See Note [Defaulting with -XNoPolyKinds]+ -- It takes an (unconstrained) meta tyvar and defaults it.+ -- Works only on vars of type *; for other kinds, it issues an error.+ default_kind_var kv+ | isStarKind (tyVarKind kv)+ = do { traceTc "Defaulting a kind var to *" (ppr kv)+ ; writeMetaTyVar kv liftedTypeKind }+ | otherwise+ = addErr (vcat [ text "Cannot default kind variable" <+> quotes (ppr kv')+ , text "of kind:" <+> ppr (tyVarKind kv')+ , text "Perhaps enable PolyKinds or add a kind signature" ])+ where+ (_, kv') = tidyOpenTyCoVar emptyTidyEnv kv++skolemiseRuntimeUnk :: TcTyVar -> TcM TyVar+skolemiseRuntimeUnk tv+ = skolemise_tv tv RuntimeUnk++skolemiseUnboundMetaTyVar :: TcTyVar -> TcM TyVar+skolemiseUnboundMetaTyVar tv+ = skolemise_tv tv (SkolemTv (metaTyVarTcLevel tv) False)++skolemise_tv :: TcTyVar -> TcTyVarDetails -> TcM TyVar+-- We have a Meta tyvar with a ref-cell inside it+-- Skolemise it, so that+-- we are totally out of Meta-tyvar-land+-- We create a skolem TyVar, not a regular TyVar+-- See Note [Zonking to Skolem]+skolemise_tv tv details+ = ASSERT2( isMetaTyVar tv, ppr tv )+ do { when debugIsOn (check_empty tv)+ ; span <- getSrcSpanM -- Get the location from "here"+ -- ie where we are generalising+ ; kind <- zonkTcType (tyVarKind tv)+ ; let uniq = getUnique tv+ -- NB: Use same Unique as original tyvar. This is+ -- important for TcHsType.splitTelescopeTvs to work properly++ tv_name = getOccName tv+ final_name = mkInternalName uniq tv_name span+ final_tv = mkTcTyVar final_name kind details++ ; traceTc "Skolemising" (ppr tv <+> text ":=" <+> ppr final_tv)+ ; writeMetaTyVar tv (mkTyVarTy final_tv)+ ; return final_tv }++ where+ check_empty tv -- [Sept 04] Check for non-empty.+ = when debugIsOn $ -- See note [Silly Type Synonym]+ do { cts <- readMetaTyVar tv+ ; case cts of+ Flexi -> return ()+ Indirect ty -> WARN( True, ppr tv $$ ppr ty )+ return () }++{- Note [Defaulting with -XNoPolyKinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ data Compose f g a = Mk (f (g a))++We infer++ Compose :: forall k1 k2. (k2 -> *) -> (k1 -> k2) -> k1 -> *+ Mk :: forall k1 k2 (f :: k2 -> *) (g :: k1 -> k2) (a :: k1).+ f (g a) -> Compose k1 k2 f g a++Now, in another module, we have -XNoPolyKinds -XDataKinds in effect.+What does 'Mk mean? Pre GHC-8.0 with -XNoPolyKinds,+we just defaulted all kind variables to *. But that's no good here,+because the kind variables in 'Mk aren't of kind *, so defaulting to *+is ill-kinded.++After some debate on #11334, we decided to issue an error in this case.+The code is in defaultKindVar.++Note [What is a meta variable?]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A "meta type-variable", also know as a "unification variable" is a placeholder+introduced by the typechecker for an as-yet-unknown monotype.++For example, when we see a call `reverse (f xs)`, we know that we calling+ reverse :: forall a. [a] -> [a]+So we know that the argument `f xs` must be a "list of something". But what is+the "something"? We don't know until we explore the `f xs` a bit more. So we set+out what we do know at the call of `reverse` by instantiate its type with a fresh+meta tyvar, `alpha` say. So now the type of the argument `f xs`, and of the+result, is `[alpha]`. The unification variable `alpha` stands for the+as-yet-unknown type of the elements of the list.++As type inference progresses we may learn more about `alpha`. For example, suppose+`f` has the type+ f :: forall b. b -> [Maybe b]+Then we instantiate `f`'s type with another fresh unification variable, say+`beta`; and equate `f`'s result type with reverse's argument type, thus+`[alpha] ~ [Maybe beta]`.++Now we can solve this equality to learn that `alpha ~ Maybe beta`, so we've+refined our knowledge about `alpha`. And so on.++If you found this Note useful, you may also want to have a look at+Section 5 of "Practical type inference for higher rank types" (Peyton Jones,+Vytiniotis, Weirich and Shields. J. Functional Programming. 2011).++Note [What is zonking?]+~~~~~~~~~~~~~~~~~~~~~~~+GHC relies heavily on mutability in the typechecker for efficient operation.+For this reason, throughout much of the type checking process meta type+variables (the MetaTv constructor of TcTyVarDetails) are represented by mutable+variables (known as TcRefs).++Zonking is the process of ripping out these mutable variables and replacing them+with a real Type. This involves traversing the entire type expression, but the+interesting part of replacing the mutable variables occurs in zonkTyVarOcc.++There are two ways to zonk a Type:++ * zonkTcTypeToType, which is intended to be used at the end of type-checking+ for the final zonk. It has to deal with unfilled metavars, either by filling+ it with a value like Any or failing (determined by the UnboundTyVarZonker+ used).++ * zonkTcType, which will happily ignore unfilled metavars. This is the+ appropriate function to use while in the middle of type-checking.++Note [Zonking to Skolem]+~~~~~~~~~~~~~~~~~~~~~~~~+We used to zonk quantified type variables to regular TyVars. However, this+leads to problems. Consider this program from the regression test suite:++ eval :: Int -> String -> String -> String+ eval 0 root actual = evalRHS 0 root actual++ evalRHS :: Int -> a+ evalRHS 0 root actual = eval 0 root actual++It leads to the deferral of an equality (wrapped in an implication constraint)++ forall a. () => ((String -> String -> String) ~ a)++which is propagated up to the toplevel (see TcSimplify.tcSimplifyInferCheck).+In the meantime `a' is zonked and quantified to form `evalRHS's signature.+This has the *side effect* of also zonking the `a' in the deferred equality+(which at this point is being handed around wrapped in an implication+constraint).++Finally, the equality (with the zonked `a') will be handed back to the+simplifier by TcRnDriver.tcRnSrcDecls calling TcSimplify.tcSimplifyTop.+If we zonk `a' with a regular type variable, we will have this regular type+variable now floating around in the simplifier, which in many places assumes to+only see proper TcTyVars.++We can avoid this problem by zonking with a skolem. The skolem is rigid+(which we require for a quantified variable), but is still a TcTyVar that the+simplifier knows how to deal with.++Note [Silly Type Synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:+ type C u a = u -- Note 'a' unused++ foo :: (forall a. C u a -> C u a) -> u+ foo x = ...++ bar :: Num u => u+ bar = foo (\t -> t + t)++* From the (\t -> t+t) we get type {Num d} => d -> d+ where d is fresh.++* Now unify with type of foo's arg, and we get:+ {Num (C d a)} => C d a -> C d a+ where a is fresh.++* Now abstract over the 'a', but float out the Num (C d a) constraint+ because it does not 'really' mention a. (see exactTyVarsOfType)+ The arg to foo becomes+ \/\a -> \t -> t+t++* So we get a dict binding for Num (C d a), which is zonked to give+ a = ()+ [Note Sept 04: now that we are zonking quantified type variables+ on construction, the 'a' will be frozen as a regular tyvar on+ quantification, so the floated dict will still have type (C d a).+ Which renders this whole note moot; happily!]++* Then the \/\a abstraction has a zonked 'a' in it.++All very silly. I think its harmless to ignore the problem. We'll end up with+a \/\a in the final result but all the occurrences of a will be zonked to ()++************************************************************************+* *+ Zonking types+* *+************************************************************************++-}++-- | @tcGetGlobalTyCoVars@ returns a fully-zonked set of *scoped* tyvars free in+-- the environment. To improve subsequent calls to the same function it writes+-- the zonked set back into the environment. Note that this returns all+-- variables free in anything (term-level or type-level) in scope. We thus+-- don't have to worry about clashes with things that are not in scope, because+-- if they are reachable, then they'll be returned here.+tcGetGlobalTyCoVars :: TcM TcTyVarSet+tcGetGlobalTyCoVars+ = do { (TcLclEnv {tcl_tyvars = gtv_var}) <- getLclEnv+ ; gbl_tvs <- readMutVar gtv_var+ ; gbl_tvs' <- zonkTyCoVarsAndFV gbl_tvs+ ; writeMutVar gtv_var gbl_tvs'+ ; return gbl_tvs' }++-- | Zonk a type without using the smart constructors; the result type+-- is available for inspection within the type-checking knot.+zonkTcTypeInKnot :: TcType -> TcM TcType+zonkTcTypeInKnot = mapType (zonkTcTypeMapper { tcm_smart = False }) ()++zonkTcTypeAndFV :: TcType -> TcM DTyCoVarSet+-- Zonk a type and take its free variables+-- With kind polymorphism it can be essential to zonk *first*+-- so that we find the right set of free variables. Eg+-- forall k1. forall (a:k2). a+-- where k2:=k1 is in the substitution. We don't want+-- k2 to look free in this type!+-- NB: This might be called from within the knot, so don't use+-- smart constructors. See Note [Zonking within the knot] in TcHsType+zonkTcTypeAndFV ty+ = tyCoVarsOfTypeDSet <$> zonkTcTypeInKnot ty++-- | Zonk a type and call 'candidateQTyVarsOfType' on it.+-- Works within the knot.+zonkTcTypeAndSplitDepVars :: TcType -> TcM CandidatesQTvs+zonkTcTypeAndSplitDepVars ty+ = candidateQTyVarsOfType <$> zonkTcTypeInKnot ty++zonkTcTypesAndSplitDepVars :: [TcType] -> TcM CandidatesQTvs+zonkTcTypesAndSplitDepVars tys+ = candidateQTyVarsOfTypes <$> mapM zonkTcTypeInKnot tys++zonkTyCoVar :: TyCoVar -> TcM TcType+-- Works on TyVars and TcTyVars+zonkTyCoVar tv | isTcTyVar tv = zonkTcTyVar tv+ | isTyVar tv = mkTyVarTy <$> zonkTyCoVarKind tv+ | otherwise = ASSERT2( isCoVar tv, ppr tv )+ mkCoercionTy . mkCoVarCo <$> zonkTyCoVarKind tv+ -- Hackily, when typechecking type and class decls+ -- we have TyVars in scopeadded (only) in+ -- TcHsType.tcTyClTyVars, but it seems+ -- painful to make them into TcTyVars there++zonkTyCoVarsAndFV :: TyCoVarSet -> TcM TyCoVarSet+zonkTyCoVarsAndFV tycovars =+ tyCoVarsOfTypes <$> mapM zonkTyCoVar (nonDetEltsUniqSet tycovars)+ -- It's OK to use nonDetEltsUniqSet here because we immediately forget about+ -- the ordering by turning it into a nondeterministic set and the order+ -- of zonking doesn't matter for determinism.++-- Takes a list of TyCoVars, zonks them and returns a+-- deterministically ordered list of their free variables.+zonkTyCoVarsAndFVList :: [TyCoVar] -> TcM [TyCoVar]+zonkTyCoVarsAndFVList tycovars =+ tyCoVarsOfTypesList <$> mapM zonkTyCoVar tycovars++-- Takes a deterministic set of TyCoVars, zonks them and returns a+-- deterministic set of their free variables.+-- See Note [quantifyTyVars determinism].+zonkTyCoVarsAndFVDSet :: DTyCoVarSet -> TcM DTyCoVarSet+zonkTyCoVarsAndFVDSet tycovars =+ tyCoVarsOfTypesDSet <$> mapM zonkTyCoVar (dVarSetElems tycovars)++zonkTcTyVars :: [TcTyVar] -> TcM [TcType]+zonkTcTyVars tyvars = mapM zonkTcTyVar tyvars++----------------- Types+zonkTyCoVarKind :: TyCoVar -> TcM TyCoVar+zonkTyCoVarKind tv = do { kind' <- zonkTcType (tyVarKind tv)+ ; return (setTyVarKind tv kind') }++zonkTcTypes :: [TcType] -> TcM [TcType]+zonkTcTypes tys = mapM zonkTcType tys++{-+************************************************************************+* *+ Zonking constraints+* *+************************************************************************+-}++zonkImplication :: Implication -> TcM Implication+zonkImplication implic@(Implic { ic_skols = skols+ , ic_given = given+ , ic_wanted = wanted+ , ic_info = info })+ = do { skols' <- mapM zonkTcTyCoVarBndr skols -- Need to zonk their kinds!+ -- as Trac #7230 showed+ ; given' <- mapM zonkEvVar given+ ; info' <- zonkSkolemInfo info+ ; wanted' <- zonkWCRec wanted+ ; return (implic { ic_skols = skols'+ , ic_given = given'+ , ic_wanted = wanted'+ , ic_info = info' }) }++zonkEvVar :: EvVar -> TcM EvVar+zonkEvVar var = do { ty' <- zonkTcType (varType var)+ ; return (setVarType var ty') }+++zonkWC :: WantedConstraints -> TcM WantedConstraints+zonkWC wc = zonkWCRec wc++zonkWCRec :: WantedConstraints -> TcM WantedConstraints+zonkWCRec (WC { wc_simple = simple, wc_impl = implic, wc_insol = insol })+ = do { simple' <- zonkSimples simple+ ; implic' <- mapBagM zonkImplication implic+ ; insol' <- zonkSimples insol+ ; return (WC { wc_simple = simple', wc_impl = implic', wc_insol = insol' }) }++zonkSimples :: Cts -> TcM Cts+zonkSimples cts = do { cts' <- mapBagM zonkCt' cts+ ; traceTc "zonkSimples done:" (ppr cts')+ ; return cts' }++zonkCt' :: Ct -> TcM Ct+zonkCt' ct = zonkCt ct++{- Note [zonkCt behaviour]+zonkCt tries to maintain the canonical form of a Ct. For example,+ - a CDictCan should stay a CDictCan;+ - a CTyEqCan should stay a CTyEqCan (if the LHS stays as a variable.).+ - a CHoleCan should stay a CHoleCan++Why?, for example:+- For CDictCan, the @TcSimplify.expandSuperClasses@ step, which runs after the+ simple wanted and plugin loop, looks for @CDictCan@s. If a plugin is in use,+ constraints are zonked before being passed to the plugin. This means if we+ don't preserve a canonical form, @expandSuperClasses@ fails to expand+ superclasses. This is what happened in Trac #11525.++- For CHoleCan, once we forget that it's a hole, we can never recover that info.++NB: we do not expect to see any CFunEqCans, because zonkCt is only+called on unflattened constraints.+NB: Constraints are always re-flattened etc by the canonicaliser in+@TcCanonical@ even if they come in as CDictCan. Only canonical constraints that+are actually in the inert set carry all the guarantees. So it is okay if zonkCt+creates e.g. a CDictCan where the cc_tyars are /not/ function free.+-}+zonkCt :: Ct -> TcM Ct+zonkCt ct@(CHoleCan { cc_ev = ev })+ = do { ev' <- zonkCtEvidence ev+ ; return $ ct { cc_ev = ev' } }+zonkCt ct@(CDictCan { cc_ev = ev, cc_tyargs = args })+ = do { ev' <- zonkCtEvidence ev+ ; args' <- mapM zonkTcType args+ ; return $ ct { cc_ev = ev', cc_tyargs = args' } }+zonkCt ct@(CTyEqCan { cc_ev = ev, cc_tyvar = tv, cc_rhs = rhs })+ = do { ev' <- zonkCtEvidence ev+ ; tv_ty' <- zonkTcTyVar tv+ ; case getTyVar_maybe tv_ty' of+ Just tv' -> do { rhs' <- zonkTcType rhs+ ; return ct { cc_ev = ev'+ , cc_tyvar = tv'+ , cc_rhs = rhs' } }+ Nothing -> return (mkNonCanonical ev') }+zonkCt ct+ = ASSERT( not (isCFunEqCan ct) )+ -- We do not expect to see any CFunEqCans, because zonkCt is only called on+ -- unflattened constraints.+ do { fl' <- zonkCtEvidence (cc_ev ct)+ ; return (mkNonCanonical fl') }++zonkCtEvidence :: CtEvidence -> TcM CtEvidence+zonkCtEvidence ctev@(CtGiven { ctev_pred = pred })+ = do { pred' <- zonkTcType pred+ ; return (ctev { ctev_pred = pred'}) }+zonkCtEvidence ctev@(CtWanted { ctev_pred = pred, ctev_dest = dest })+ = do { pred' <- zonkTcType pred+ ; let dest' = case dest of+ EvVarDest ev -> EvVarDest $ setVarType ev pred'+ -- necessary in simplifyInfer+ HoleDest h -> HoleDest h+ ; return (ctev { ctev_pred = pred', ctev_dest = dest' }) }+zonkCtEvidence ctev@(CtDerived { ctev_pred = pred })+ = do { pred' <- zonkTcType pred+ ; return (ctev { ctev_pred = pred' }) }++zonkSkolemInfo :: SkolemInfo -> TcM SkolemInfo+zonkSkolemInfo (SigSkol cx ty tv_prs) = do { ty' <- zonkTcType ty+ ; return (SigSkol cx ty' tv_prs) }+zonkSkolemInfo (InferSkol ntys) = do { ntys' <- mapM do_one ntys+ ; return (InferSkol ntys') }+ where+ do_one (n, ty) = do { ty' <- zonkTcType ty; return (n, ty') }+zonkSkolemInfo skol_info = return skol_info++{-+%************************************************************************+%* *+\subsection{Zonking -- the main work-horses: zonkTcType, zonkTcTyVar}+* *+* For internal use only! *+* *+************************************************************************++-}++-- zonkId is used *during* typechecking just to zonk the Id's type+zonkId :: TcId -> TcM TcId+zonkId id+ = do { ty' <- zonkTcType (idType id)+ ; return (Id.setIdType id ty') }++-- | A suitable TyCoMapper for zonking a type inside the knot, and+-- before all metavars are filled in.+zonkTcTypeMapper :: TyCoMapper () TcM+zonkTcTypeMapper = TyCoMapper+ { tcm_smart = True+ , tcm_tyvar = const zonkTcTyVar+ , tcm_covar = const (\cv -> mkCoVarCo <$> zonkTyCoVarKind cv)+ , tcm_hole = hole+ , tcm_tybinder = \_env tv _vis -> ((), ) <$> zonkTcTyCoVarBndr tv }+ where+ hole :: () -> CoercionHole -> Role -> Type -> Type+ -> TcM Coercion+ hole _ h r t1 t2+ = do { contents <- unpackCoercionHole_maybe h+ ; case contents of+ Just co -> do { co <- zonkCo co+ ; checkCoercionHole co h r t1 t2 }+ Nothing -> do { t1 <- zonkTcType t1+ ; t2 <- zonkTcType t2+ ; return $ mkHoleCo h r t1 t2 } }+++-- For unbound, mutable tyvars, zonkType uses the function given to it+-- For tyvars bound at a for-all, zonkType zonks them to an immutable+-- type variable and zonks the kind too+zonkTcType :: TcType -> TcM TcType+zonkTcType = mapType zonkTcTypeMapper ()++-- | "Zonk" a coercion -- really, just zonk any types in the coercion+zonkCo :: Coercion -> TcM Coercion+zonkCo = mapCoercion zonkTcTypeMapper ()++zonkTcTyCoVarBndr :: TcTyCoVar -> TcM TcTyCoVar+-- A tyvar binder is never a unification variable (MetaTv),+-- rather it is always a skolems. BUT it may have a kind+-- that has not yet been zonked, and may include kind+-- unification variables.+zonkTcTyCoVarBndr tyvar+ -- can't use isCoVar, because it looks at a TyCon. Argh.+ = ASSERT2( isImmutableTyVar tyvar || (not $ isTyVar tyvar), pprTyVar tyvar )+ updateTyVarKindM zonkTcType tyvar++zonkTcTyVarBinder :: TyVarBndr TcTyVar vis -> TcM (TyVarBndr TcTyVar vis)+zonkTcTyVarBinder (TvBndr tv vis)+ = do { tv' <- zonkTcTyCoVarBndr tv+ ; return (TvBndr tv' vis) }++zonkTcTyVar :: TcTyVar -> TcM TcType+-- Simply look through all Flexis+zonkTcTyVar tv+ | isTcTyVar tv+ = case tcTyVarDetails tv of+ SkolemTv {} -> zonk_kind_and_return+ RuntimeUnk {} -> zonk_kind_and_return+ FlatSkol ty -> zonkTcType ty+ MetaTv { mtv_ref = ref }+ -> do { cts <- readMutVar ref+ ; case cts of+ Flexi -> zonk_kind_and_return+ Indirect ty -> zonkTcType ty }++ | otherwise -- coercion variable+ = zonk_kind_and_return+ where+ zonk_kind_and_return = do { z_tv <- zonkTyCoVarKind tv+ ; return (mkTyVarTy z_tv) }++-- Variant that assumes that any result of zonking is still a TyVar.+-- Should be used only on skolems and SigTvs+zonkTcTyVarToTyVar :: TcTyVar -> TcM TcTyVar+zonkTcTyVarToTyVar tv+ = do { ty <- zonkTcTyVar tv+ ; return (tcGetTyVar "zonkTcTyVarToVar" ty) }++{-+%************************************************************************+%* *+ Tidying+* *+************************************************************************+-}++zonkTidyTcType :: TidyEnv -> TcType -> TcM (TidyEnv, TcType)+zonkTidyTcType env ty = do { ty' <- zonkTcType ty+ ; return (tidyOpenType env ty') }++-- | Make an 'ErrorThing' storing a type.+mkTypeErrorThing :: TcType -> ErrorThing+mkTypeErrorThing ty = ErrorThing ty (Just $ length $ snd $ repSplitAppTys ty)+ zonkTidyTcType+ -- NB: Use *rep*splitAppTys, else we get #11313++-- | Make an 'ErrorThing' storing a type, with some extra args known about+mkTypeErrorThingArgs :: TcType -> Int -> ErrorThing+mkTypeErrorThingArgs ty num_args+ = ErrorThing ty (Just $ (length $ snd $ repSplitAppTys ty) + num_args)+ zonkTidyTcType++zonkTidyOrigin :: TidyEnv -> CtOrigin -> TcM (TidyEnv, CtOrigin)+zonkTidyOrigin env (GivenOrigin skol_info)+ = do { skol_info1 <- zonkSkolemInfo skol_info+ ; let skol_info2 = tidySkolemInfo env skol_info1+ ; return (env, GivenOrigin skol_info2) }+zonkTidyOrigin env orig@(TypeEqOrigin { uo_actual = act+ , uo_expected = exp+ , uo_thing = m_thing })+ = do { (env1, act') <- zonkTidyTcType env act+ ; (env2, exp') <- zonkTidyTcType env1 exp+ ; (env3, m_thing') <- zonkTidyErrorThing env2 m_thing+ ; return ( env3, orig { uo_actual = act'+ , uo_expected = exp'+ , uo_thing = m_thing' }) }+zonkTidyOrigin env (KindEqOrigin ty1 m_ty2 orig t_or_k)+ = do { (env1, ty1') <- zonkTidyTcType env ty1+ ; (env2, m_ty2') <- case m_ty2 of+ Just ty2 -> second Just <$> zonkTidyTcType env1 ty2+ Nothing -> return (env1, Nothing)+ ; (env3, orig') <- zonkTidyOrigin env2 orig+ ; return (env3, KindEqOrigin ty1' m_ty2' orig' t_or_k) }+zonkTidyOrigin env (FunDepOrigin1 p1 l1 p2 l2)+ = do { (env1, p1') <- zonkTidyTcType env p1+ ; (env2, p2') <- zonkTidyTcType env1 p2+ ; return (env2, FunDepOrigin1 p1' l1 p2' l2) }+zonkTidyOrigin env (FunDepOrigin2 p1 o1 p2 l2)+ = do { (env1, p1') <- zonkTidyTcType env p1+ ; (env2, p2') <- zonkTidyTcType env1 p2+ ; (env3, o1') <- zonkTidyOrigin env2 o1+ ; return (env3, FunDepOrigin2 p1' o1' p2' l2) }+zonkTidyOrigin env orig = return (env, orig)++zonkTidyErrorThing :: TidyEnv -> Maybe ErrorThing+ -> TcM (TidyEnv, Maybe ErrorThing)+zonkTidyErrorThing env (Just (ErrorThing thing n_args zonker))+ = do { (env', thing') <- zonker env thing+ ; return (env', Just $ ErrorThing thing' n_args zonker) }+zonkTidyErrorThing env Nothing+ = return (env, Nothing)++----------------+tidyCt :: TidyEnv -> Ct -> Ct+-- Used only in error reporting+-- Also converts it to non-canonical+tidyCt env ct+ = case ct of+ CHoleCan { cc_ev = ev }+ -> ct { cc_ev = tidy_ev env ev }+ _ -> mkNonCanonical (tidy_ev env (ctEvidence ct))+ where+ tidy_ev :: TidyEnv -> CtEvidence -> CtEvidence+ -- NB: we do not tidy the ctev_evar field because we don't+ -- show it in error messages+ tidy_ev env ctev@(CtGiven { ctev_pred = pred })+ = ctev { ctev_pred = tidyType env pred }+ tidy_ev env ctev@(CtWanted { ctev_pred = pred })+ = ctev { ctev_pred = tidyType env pred }+ tidy_ev env ctev@(CtDerived { ctev_pred = pred })+ = ctev { ctev_pred = tidyType env pred }++----------------+tidyEvVar :: TidyEnv -> EvVar -> EvVar+tidyEvVar env var = setVarType var (tidyType env (varType var))++----------------+tidySkolemInfo :: TidyEnv -> SkolemInfo -> SkolemInfo+tidySkolemInfo env (DerivSkol ty) = DerivSkol (tidyType env ty)+tidySkolemInfo env (SigSkol cx ty tv_prs) = tidySigSkol env cx ty tv_prs+tidySkolemInfo env (InferSkol ids) = InferSkol (mapSnd (tidyType env) ids)+tidySkolemInfo env (UnifyForAllSkol ty) = UnifyForAllSkol (tidyType env ty)+tidySkolemInfo _ info = info++tidySigSkol :: TidyEnv -> UserTypeCtxt+ -> TcType -> [(Name,TcTyVar)] -> SkolemInfo+-- We need to take special care when tidying SigSkol+-- See Note [SigSkol SkolemInfo] in TcRnTypes+tidySigSkol env cx ty tv_prs+ = SigSkol cx (tidy_ty env ty) tv_prs'+ where+ tv_prs' = mapSnd (tidyTyVarOcc env) tv_prs+ inst_env = mkNameEnv tv_prs'++ tidy_ty env (ForAllTy (TvBndr tv vis) ty)+ = ForAllTy (TvBndr tv' vis) (tidy_ty env' ty)+ where+ (env', tv') = tidy_tv_bndr env tv++ tidy_ty env (FunTy arg res)+ = FunTy (tidyType env arg) (tidy_ty env res)++ tidy_ty env ty = tidyType env ty++ tidy_tv_bndr :: TidyEnv -> TyVar -> (TidyEnv, TyVar)+ tidy_tv_bndr env@(occ_env, subst) tv+ | Just tv' <- lookupNameEnv inst_env (tyVarName tv)+ = ((occ_env, extendVarEnv subst tv tv'), tv')++ | otherwise+ = tidyTyCoVarBndr env tv++-------------------------------------------------------------------------+{-+%************************************************************************+%* *+ Levity polymorphism checks+* *+************************************************************************++See Note [Levity polymorphism checking] in DsMonad++-}++-- | According to the rules around representation polymorphism+-- (see https://ghc.haskell.org/trac/ghc/wiki/NoSubKinds), 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+ -> SDoc -- where this happened+ -> TcM ()+ensureNotLevPoly ty doc+ = whenNoErrs $ -- sometimes we end up zonking bogus definitions of type+ -- forall a. a. See, for example, test ghci/scripts/T9140+ checkForLevPoly doc ty++ -- See Note [Levity polymorphism checking] in DsMonad+checkForLevPoly :: SDoc -> Type -> TcM ()+checkForLevPoly = checkForLevPolyX addErr++checkForLevPolyX :: Monad m+ => (SDoc -> m ()) -- how to report an error+ -> SDoc -> Type -> m ()+checkForLevPolyX add_err extra ty+ | isTypeLevPoly ty+ = add_err (formatLevPolyErr ty $$ extra)+ | otherwise+ = return ()++formatLevPolyErr :: Type -- levity-polymorphic type+ -> SDoc+formatLevPolyErr ty+ = hang (text "A levity-polymorphic type is not allowed here:")+ 2 (vcat [ text "Type:" <+> ppr tidy_ty+ , text "Kind:" <+> ppr tidy_ki ])+ where+ (tidy_env, tidy_ty) = tidyOpenType emptyTidyEnv ty+ tidy_ki = tidyType tidy_env (typeKind ty)
+ typecheck/TcMatches.hs view
@@ -0,0 +1,1135 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++TcMatches: Typecheck some @Matches@+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE MultiWayIf #-}+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE FlexibleContexts #-}++module TcMatches ( tcMatchesFun, tcGRHS, tcGRHSsPat, tcMatchesCase, tcMatchLambda,+ TcMatchCtxt(..), TcStmtChecker, TcExprStmtChecker, TcCmdStmtChecker,+ tcStmts, tcStmtsAndThen, tcDoStmts, tcBody,+ tcDoStmt, tcGuardStmt+ ) where++import {-# SOURCE #-} TcExpr( tcSyntaxOp, tcInferSigmaNC, tcInferSigma+ , tcCheckId, tcMonoExpr, tcMonoExprNC, tcPolyExpr )++import BasicTypes (LexicalFixity(..))+import HsSyn+import TcRnMonad+import TcEnv+import TcPat+import TcMType+import TcType+import TcBinds+import TcUnify+import Name+import TysWiredIn+import Id+import TyCon+import TysPrim+import TcEvidence+import Outputable+import Util+import SrcLoc+import DynFlags+import PrelNames (monadFailClassName)+import qualified GHC.LanguageExtensions as LangExt++-- Create chunkified tuple tybes for monad comprehensions+import MkCore++import Control.Monad+import Control.Arrow ( second )++#include "HsVersions.h"++{-+************************************************************************+* *+\subsection{tcMatchesFun, tcMatchesCase}+* *+************************************************************************++@tcMatchesFun@ typechecks a @[Match]@ list which occurs in a+@FunMonoBind@. The second argument is the name of the function, which+is used in error messages. It checks that all the equations have the+same number of arguments before using @tcMatches@ to do the work.++Note [Polymorphic expected type for tcMatchesFun]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+tcMatchesFun may be given a *sigma* (polymorphic) type+so it must be prepared to use tcSkolemise to skolemise it.+See Note [sig_tau may be polymorphic] in TcPat.+-}++tcMatchesFun :: Located Name+ -> MatchGroup Name (LHsExpr Name)+ -> ExpRhoType -- Expected type of function+ -> TcM (HsWrapper, MatchGroup TcId (LHsExpr TcId))+ -- Returns type of body+tcMatchesFun fn@(L _ fun_name) matches exp_ty+ = do { -- Check that they all have the same no of arguments+ -- Location is in the monad, set the caller so that+ -- any inter-equation error messages get some vaguely+ -- sensible location. Note: we have to do this odd+ -- ann-grabbing, because we don't always have annotations in+ -- hand when we call tcMatchesFun...+ traceTc "tcMatchesFun" (ppr fun_name $$ ppr exp_ty)+ ; checkArgs fun_name matches++ ; (wrap_gen, (wrap_fun, group))+ <- tcSkolemiseET (FunSigCtxt fun_name True) exp_ty $ \ exp_rho ->+ -- Note [Polymorphic expected type for tcMatchesFun]+ do { (matches', wrap_fun)+ <- matchExpectedFunTys herald arity exp_rho $+ \ pat_tys rhs_ty ->+ tcMatches match_ctxt pat_tys rhs_ty matches+ ; return (wrap_fun, matches') }+ ; return (wrap_gen <.> wrap_fun, group) }+ where+ arity = matchGroupArity matches+ herald = text "The equation(s) for"+ <+> quotes (ppr fun_name) <+> text "have"+ match_ctxt = MC { mc_what = FunRhs fn Prefix strictness, mc_body = tcBody }+ strictness+ | [L _ match] <- unLoc $ mg_alts matches+ , FunRhs{mc_strictness = SrcStrict} <- m_ctxt match+ = SrcStrict+ | otherwise+ = NoSrcStrict++{-+@tcMatchesCase@ doesn't do the argument-count check because the+parser guarantees that each equation has exactly one argument.+-}++tcMatchesCase :: (Outputable (body Name)) =>+ TcMatchCtxt body -- Case context+ -> TcSigmaType -- Type of scrutinee+ -> MatchGroup Name (Located (body Name)) -- The case alternatives+ -> ExpRhoType -- Type of whole case expressions+ -> TcM (MatchGroup TcId (Located (body TcId)))+ -- Translated alternatives+ -- wrapper goes from MatchGroup's ty to expected ty++tcMatchesCase ctxt scrut_ty matches res_ty+ = tcMatches ctxt [mkCheckExpType scrut_ty] res_ty matches++tcMatchLambda :: SDoc -- see Note [Herald for matchExpectedFunTys] in TcUnify+ -> TcMatchCtxt HsExpr+ -> MatchGroup Name (LHsExpr Name)+ -> ExpRhoType -- deeply skolemised+ -> TcM (MatchGroup TcId (LHsExpr TcId), HsWrapper)+tcMatchLambda herald match_ctxt match res_ty+ = matchExpectedFunTys herald n_pats res_ty $ \ pat_tys rhs_ty ->+ tcMatches match_ctxt pat_tys rhs_ty match+ where+ n_pats | isEmptyMatchGroup match = 1 -- must be lambda-case+ | otherwise = matchGroupArity match++-- @tcGRHSsPat@ typechecks @[GRHSs]@ that occur in a @PatMonoBind@.++tcGRHSsPat :: GRHSs Name (LHsExpr Name) -> TcRhoType+ -> TcM (GRHSs TcId (LHsExpr TcId))+-- Used for pattern bindings+tcGRHSsPat grhss res_ty = tcGRHSs match_ctxt grhss (mkCheckExpType res_ty)+ where+ match_ctxt = MC { mc_what = PatBindRhs,+ mc_body = tcBody }++{-+************************************************************************+* *+\subsection{tcMatch}+* *+************************************************************************++Note [Case branches must never infer a non-tau type]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ case ... of+ ... -> \(x :: forall a. a -> a) -> x+ ... -> \y -> y++Should that type-check? The problem is that, if we check the second branch+first, then we'll get a type (b -> b) for the branches, which won't unify+with the polytype in the first branch. If we check the first branch first,+then everything is OK. This order-dependency is terrible. So we want only+proper tau-types in branches (unless a sigma-type is pushed down).+This is what expTypeToType ensures: it replaces an Infer with a fresh+tau-type.++An even trickier case looks like++ f x True = x undefined+ f x False = x ()++Here, we see that the arguments must also be non-Infer. Thus, we must+use expTypeToType on the output of matchExpectedFunTys, not the input.++But we make a special case for a one-branch case. This is so that++ f = \(x :: forall a. a -> a) -> x++still gets assigned a polytype.+-}++-- | When the MatchGroup has multiple RHSs, convert an Infer ExpType in the+-- expected type into TauTvs.+-- See Note [Case branches must never infer a non-tau type]+tauifyMultipleMatches :: [LMatch id body]+ -> [ExpType] -> TcM [ExpType]+tauifyMultipleMatches group exp_tys+ | isSingletonMatchGroup group = return exp_tys+ | otherwise = mapM tauifyExpType exp_tys+ -- NB: In the empty-match case, this ensures we fill in the ExpType++-- | Type-check a MatchGroup.+tcMatches :: (Outputable (body Name)) => TcMatchCtxt body+ -> [ExpSigmaType] -- Expected pattern types+ -> ExpRhoType -- Expected result-type of the Match.+ -> MatchGroup Name (Located (body Name))+ -> TcM (MatchGroup TcId (Located (body TcId)))++data TcMatchCtxt body -- c.f. TcStmtCtxt, also in this module+ = MC { mc_what :: HsMatchContext Name, -- What kind of thing this is+ mc_body :: Located (body Name) -- Type checker for a body of+ -- an alternative+ -> ExpRhoType+ -> TcM (Located (body TcId)) }++tcMatches ctxt pat_tys rhs_ty (MG { mg_alts = L l matches+ , mg_origin = origin })+ = do { rhs_ty:pat_tys <- tauifyMultipleMatches matches (rhs_ty:pat_tys)+ -- See Note [Case branches must never infer a non-tau type]++ ; matches' <- mapM (tcMatch ctxt pat_tys rhs_ty) matches+ ; pat_tys <- mapM readExpType pat_tys+ ; rhs_ty <- readExpType rhs_ty+ ; return (MG { mg_alts = L l matches'+ , mg_arg_tys = pat_tys+ , mg_res_ty = rhs_ty+ , mg_origin = origin }) }++-------------+tcMatch :: (Outputable (body Name)) => TcMatchCtxt body+ -> [ExpSigmaType] -- Expected pattern types+ -> ExpRhoType -- Expected result-type of the Match.+ -> LMatch Name (Located (body Name))+ -> TcM (LMatch TcId (Located (body TcId)))++tcMatch ctxt pat_tys rhs_ty match+ = wrapLocM (tc_match ctxt pat_tys rhs_ty) match+ where+ tc_match ctxt pat_tys rhs_ty match@(Match _ pats maybe_rhs_sig grhss)+ = add_match_ctxt match $+ do { (pats', grhss') <- tcPats (mc_what ctxt) pats pat_tys $+ tc_grhss ctxt maybe_rhs_sig grhss rhs_ty+ ; return (Match (mc_what ctxt) pats' Nothing grhss') }++ tc_grhss ctxt Nothing grhss rhs_ty+ = tcGRHSs ctxt grhss rhs_ty -- No result signature++ -- Result type sigs are no longer supported+ tc_grhss _ (Just {}) _ _+ = panic "tc_ghrss" -- Rejected by renamer++ -- For (\x -> e), tcExpr has already said "In the expression \x->e"+ -- so we don't want to add "In the lambda abstraction \x->e"+ add_match_ctxt match thing_inside+ = case mc_what ctxt of+ LambdaExpr -> thing_inside+ _ -> addErrCtxt (pprMatchInCtxt match) thing_inside++-------------+tcGRHSs :: TcMatchCtxt body -> GRHSs Name (Located (body Name)) -> ExpRhoType+ -> TcM (GRHSs TcId (Located (body TcId)))++-- Notice that we pass in the full res_ty, so that we get+-- good inference from simple things like+-- f = \(x::forall a.a->a) -> <stuff>+-- We used to force it to be a monotype when there was more than one guard+-- but we don't need to do that any more++tcGRHSs ctxt (GRHSs grhss (L l binds)) res_ty+ = do { (binds', grhss')+ <- tcLocalBinds binds $+ mapM (wrapLocM (tcGRHS ctxt res_ty)) grhss++ ; return (GRHSs grhss' (L l binds')) }++-------------+tcGRHS :: TcMatchCtxt body -> ExpRhoType -> GRHS Name (Located (body Name))+ -> TcM (GRHS TcId (Located (body TcId)))++tcGRHS ctxt res_ty (GRHS guards rhs)+ = do { (guards', rhs')+ <- tcStmtsAndThen stmt_ctxt tcGuardStmt guards res_ty $+ mc_body ctxt rhs+ ; return (GRHS guards' rhs') }+ where+ stmt_ctxt = PatGuard (mc_what ctxt)++{-+************************************************************************+* *+\subsection{@tcDoStmts@ typechecks a {\em list} of do statements}+* *+************************************************************************+-}++tcDoStmts :: HsStmtContext Name+ -> Located [LStmt Name (LHsExpr Name)]+ -> ExpRhoType+ -> TcM (HsExpr TcId) -- Returns a HsDo+tcDoStmts ListComp (L l stmts) res_ty+ = do { res_ty <- expTypeToType res_ty+ ; (co, elt_ty) <- matchExpectedListTy res_ty+ ; let list_ty = mkListTy elt_ty+ ; stmts' <- tcStmts ListComp (tcLcStmt listTyCon) stmts+ (mkCheckExpType elt_ty)+ ; return $ mkHsWrapCo co (HsDo ListComp (L l stmts') list_ty) }++tcDoStmts PArrComp (L l stmts) res_ty+ = do { res_ty <- expTypeToType res_ty+ ; (co, elt_ty) <- matchExpectedPArrTy res_ty+ ; let parr_ty = mkPArrTy elt_ty+ ; stmts' <- tcStmts PArrComp (tcLcStmt parrTyCon) stmts+ (mkCheckExpType elt_ty)+ ; return $ mkHsWrapCo co (HsDo PArrComp (L l stmts') parr_ty) }++tcDoStmts DoExpr (L l stmts) res_ty+ = do { stmts' <- tcStmts DoExpr tcDoStmt stmts res_ty+ ; res_ty <- readExpType res_ty+ ; return (HsDo DoExpr (L l stmts') res_ty) }++tcDoStmts MDoExpr (L l stmts) res_ty+ = do { stmts' <- tcStmts MDoExpr tcDoStmt stmts res_ty+ ; res_ty <- readExpType res_ty+ ; return (HsDo MDoExpr (L l stmts') res_ty) }++tcDoStmts MonadComp (L l stmts) res_ty+ = do { stmts' <- tcStmts MonadComp tcMcStmt stmts res_ty+ ; res_ty <- readExpType res_ty+ ; return (HsDo MonadComp (L l stmts') res_ty) }++tcDoStmts ctxt _ _ = pprPanic "tcDoStmts" (pprStmtContext ctxt)++tcBody :: LHsExpr Name -> ExpRhoType -> TcM (LHsExpr TcId)+tcBody body res_ty+ = do { traceTc "tcBody" (ppr res_ty)+ ; tcMonoExpr body res_ty+ }++{-+************************************************************************+* *+\subsection{tcStmts}+* *+************************************************************************+-}++type TcExprStmtChecker = TcStmtChecker HsExpr ExpRhoType+type TcCmdStmtChecker = TcStmtChecker HsCmd TcRhoType++type TcStmtChecker body rho_type+ = forall thing. HsStmtContext Name+ -> Stmt Name (Located (body Name))+ -> rho_type -- Result type for comprehension+ -> (rho_type -> TcM thing) -- Checker for what follows the stmt+ -> TcM (Stmt TcId (Located (body TcId)), thing)++tcStmts :: (Outputable (body Name)) => HsStmtContext Name+ -> TcStmtChecker body rho_type -- NB: higher-rank type+ -> [LStmt Name (Located (body Name))]+ -> rho_type+ -> TcM [LStmt TcId (Located (body TcId))]+tcStmts ctxt stmt_chk stmts res_ty+ = do { (stmts', _) <- tcStmtsAndThen ctxt stmt_chk stmts res_ty $+ const (return ())+ ; return stmts' }++tcStmtsAndThen :: (Outputable (body Name)) => HsStmtContext Name+ -> TcStmtChecker body rho_type -- NB: higher-rank type+ -> [LStmt Name (Located (body Name))]+ -> rho_type+ -> (rho_type -> TcM thing)+ -> TcM ([LStmt TcId (Located (body TcId))], thing)++-- Note the higher-rank type. stmt_chk is applied at different+-- types in the equations for tcStmts++tcStmtsAndThen _ _ [] res_ty thing_inside+ = do { thing <- thing_inside res_ty+ ; return ([], thing) }++-- LetStmts are handled uniformly, regardless of context+tcStmtsAndThen ctxt stmt_chk (L loc (LetStmt (L l binds)) : stmts)+ res_ty thing_inside+ = do { (binds', (stmts',thing)) <- tcLocalBinds binds $+ tcStmtsAndThen ctxt stmt_chk stmts res_ty thing_inside+ ; return (L loc (LetStmt (L l binds')) : stmts', thing) }++-- Don't set the error context for an ApplicativeStmt. It ought to be+-- possible to do this with a popErrCtxt in the tcStmt case for+-- ApplicativeStmt, but it did someting strange and broke a test (ado002).+tcStmtsAndThen ctxt stmt_chk (L loc stmt : stmts) res_ty thing_inside+ | ApplicativeStmt{} <- stmt+ = do { (stmt', (stmts', thing)) <-+ stmt_chk ctxt stmt res_ty $ \ res_ty' ->+ tcStmtsAndThen ctxt stmt_chk stmts res_ty' $+ thing_inside+ ; return (L loc stmt' : stmts', thing) }++ -- For the vanilla case, handle the location-setting part+ | otherwise+ = do { (stmt', (stmts', thing)) <-+ setSrcSpan loc $+ addErrCtxt (pprStmtInCtxt ctxt stmt) $+ stmt_chk ctxt stmt res_ty $ \ res_ty' ->+ popErrCtxt $+ tcStmtsAndThen ctxt stmt_chk stmts res_ty' $+ thing_inside+ ; return (L loc stmt' : stmts', thing) }++---------------------------------------------------+-- Pattern guards+---------------------------------------------------++tcGuardStmt :: TcExprStmtChecker+tcGuardStmt _ (BodyStmt guard _ _ _) res_ty thing_inside+ = do { guard' <- tcMonoExpr guard (mkCheckExpType boolTy)+ ; thing <- thing_inside res_ty+ ; return (BodyStmt guard' noSyntaxExpr noSyntaxExpr boolTy, thing) }++tcGuardStmt ctxt (BindStmt pat rhs _ _ _) res_ty thing_inside+ = do { (rhs', rhs_ty) <- tcInferSigmaNC rhs+ -- Stmt has a context already+ ; (pat', thing) <- tcPat_O (StmtCtxt ctxt) (lexprCtOrigin rhs)+ pat (mkCheckExpType rhs_ty) $+ thing_inside res_ty+ ; return (mkTcBindStmt pat' rhs', thing) }++tcGuardStmt _ stmt _ _+ = pprPanic "tcGuardStmt: unexpected Stmt" (ppr stmt)+++---------------------------------------------------+-- List comprehensions and PArrays+-- (no rebindable syntax)+---------------------------------------------------++-- Dealt with separately, rather than by tcMcStmt, because+-- a) PArr isn't (yet) an instance of Monad, so the generality seems overkill+-- b) We have special desugaring rules for list comprehensions,+-- which avoid creating intermediate lists. They in turn+-- assume that the bind/return operations are the regular+-- polymorphic ones, and in particular don't have any+-- coercion matching stuff in them. It's hard to avoid the+-- potential for non-trivial coercions in tcMcStmt++tcLcStmt :: TyCon -- The list/Parray type constructor ([] or PArray)+ -> TcExprStmtChecker++tcLcStmt _ _ (LastStmt body noret _) elt_ty thing_inside+ = do { body' <- tcMonoExprNC body elt_ty+ ; thing <- thing_inside (panic "tcLcStmt: thing_inside")+ ; return (LastStmt body' noret noSyntaxExpr, thing) }++-- A generator, pat <- rhs+tcLcStmt m_tc ctxt (BindStmt pat rhs _ _ _) elt_ty thing_inside+ = do { pat_ty <- newFlexiTyVarTy liftedTypeKind+ ; rhs' <- tcMonoExpr rhs (mkCheckExpType $ mkTyConApp m_tc [pat_ty])+ ; (pat', thing) <- tcPat (StmtCtxt ctxt) pat (mkCheckExpType pat_ty) $+ thing_inside elt_ty+ ; return (mkTcBindStmt pat' rhs', thing) }++-- A boolean guard+tcLcStmt _ _ (BodyStmt rhs _ _ _) elt_ty thing_inside+ = do { rhs' <- tcMonoExpr rhs (mkCheckExpType boolTy)+ ; thing <- thing_inside elt_ty+ ; return (BodyStmt rhs' noSyntaxExpr noSyntaxExpr boolTy, thing) }++-- ParStmt: See notes with tcMcStmt+tcLcStmt m_tc ctxt (ParStmt bndr_stmts_s _ _ _) elt_ty thing_inside+ = do { (pairs', thing) <- loop bndr_stmts_s+ ; return (ParStmt pairs' noExpr noSyntaxExpr unitTy, thing) }+ where+ -- loop :: [([LStmt Name], [Name])] -> TcM ([([LStmt TcId], [TcId])], thing)+ loop [] = do { thing <- thing_inside elt_ty+ ; return ([], thing) } -- matching in the branches++ loop (ParStmtBlock stmts names _ : pairs)+ = do { (stmts', (ids, pairs', thing))+ <- tcStmtsAndThen ctxt (tcLcStmt m_tc) stmts elt_ty $ \ _elt_ty' ->+ do { ids <- tcLookupLocalIds names+ ; (pairs', thing) <- loop pairs+ ; return (ids, pairs', thing) }+ ; return ( ParStmtBlock stmts' ids noSyntaxExpr : pairs', thing ) }++tcLcStmt m_tc ctxt (TransStmt { trS_form = form, trS_stmts = stmts+ , trS_bndrs = bindersMap+ , trS_by = by, trS_using = using }) elt_ty thing_inside+ = do { let (bndr_names, n_bndr_names) = unzip bindersMap+ unused_ty = pprPanic "tcLcStmt: inner ty" (ppr bindersMap)+ -- The inner 'stmts' lack a LastStmt, so the element type+ -- passed in to tcStmtsAndThen is never looked at+ ; (stmts', (bndr_ids, by'))+ <- tcStmtsAndThen (TransStmtCtxt ctxt) (tcLcStmt m_tc) stmts unused_ty $ \_ -> do+ { by' <- traverse tcInferSigma by+ ; bndr_ids <- tcLookupLocalIds bndr_names+ ; return (bndr_ids, by') }++ ; let m_app ty = mkTyConApp m_tc [ty]++ --------------- Typecheck the 'using' function -------------+ -- using :: ((a,b,c)->t) -> m (a,b,c) -> m (a,b,c)m (ThenForm)+ -- :: ((a,b,c)->t) -> m (a,b,c) -> m (m (a,b,c))) (GroupForm)++ -- n_app :: Type -> Type -- Wraps a 'ty' into '[ty]' for GroupForm+ ; let n_app = case form of+ ThenForm -> (\ty -> ty)+ _ -> m_app++ by_arrow :: Type -> Type -- Wraps 'ty' to '(a->t) -> ty' if the By is present+ by_arrow = case by' of+ Nothing -> \ty -> ty+ Just (_,e_ty) -> \ty -> (alphaTy `mkFunTy` e_ty) `mkFunTy` ty++ tup_ty = mkBigCoreVarTupTy bndr_ids+ poly_arg_ty = m_app alphaTy+ poly_res_ty = m_app (n_app alphaTy)+ using_poly_ty = mkInvForAllTy alphaTyVar $+ by_arrow $+ poly_arg_ty `mkFunTy` poly_res_ty++ ; using' <- tcPolyExpr using using_poly_ty+ ; let final_using = fmap (HsWrap (WpTyApp tup_ty)) using'++ -- 'stmts' returns a result of type (m1_ty tuple_ty),+ -- typically something like [(Int,Bool,Int)]+ -- We don't know what tuple_ty is yet, so we use a variable+ ; let mk_n_bndr :: Name -> TcId -> TcId+ mk_n_bndr n_bndr_name bndr_id = mkLocalIdOrCoVar n_bndr_name (n_app (idType bndr_id))++ -- Ensure that every old binder of type `b` is linked up with its+ -- new binder which should have type `n b`+ -- See Note [GroupStmt binder map] in HsExpr+ n_bndr_ids = zipWith mk_n_bndr n_bndr_names bndr_ids+ bindersMap' = bndr_ids `zip` n_bndr_ids++ -- Type check the thing in the environment with+ -- these new binders and return the result+ ; thing <- tcExtendIdEnv n_bndr_ids (thing_inside elt_ty)++ ; return (TransStmt { trS_stmts = stmts', trS_bndrs = bindersMap'+ , trS_by = fmap fst by', trS_using = final_using+ , trS_ret = noSyntaxExpr+ , trS_bind = noSyntaxExpr+ , trS_fmap = noExpr+ , trS_bind_arg_ty = unitTy+ , trS_form = form }, thing) }++tcLcStmt _ _ stmt _ _+ = pprPanic "tcLcStmt: unexpected Stmt" (ppr stmt)+++---------------------------------------------------+-- Monad comprehensions+-- (supports rebindable syntax)+---------------------------------------------------++tcMcStmt :: TcExprStmtChecker++tcMcStmt _ (LastStmt body noret return_op) res_ty thing_inside+ = do { (body', return_op')+ <- tcSyntaxOp MCompOrigin return_op [SynRho] res_ty $+ \ [a_ty] ->+ tcMonoExprNC body (mkCheckExpType a_ty)+ ; thing <- thing_inside (panic "tcMcStmt: thing_inside")+ ; return (LastStmt body' noret return_op', thing) }++-- Generators for monad comprehensions ( pat <- rhs )+--+-- [ body | q <- gen ] -> gen :: m a+-- q :: a+--++tcMcStmt ctxt (BindStmt pat rhs bind_op fail_op _) res_ty thing_inside+ -- (>>=) :: rhs_ty -> (pat_ty -> new_res_ty) -> res_ty+ = do { ((rhs', pat', thing, new_res_ty), bind_op')+ <- tcSyntaxOp MCompOrigin bind_op+ [SynRho, SynFun SynAny SynRho] res_ty $+ \ [rhs_ty, pat_ty, new_res_ty] ->+ do { rhs' <- tcMonoExprNC rhs (mkCheckExpType rhs_ty)+ ; (pat', thing) <- tcPat (StmtCtxt ctxt) pat+ (mkCheckExpType pat_ty) $+ thing_inside (mkCheckExpType new_res_ty)+ ; return (rhs', pat', thing, new_res_ty) }++ -- If (but only if) the pattern can fail, typecheck the 'fail' operator+ ; fail_op' <- tcMonadFailOp (MCompPatOrigin pat) pat' fail_op new_res_ty++ ; return (BindStmt pat' rhs' bind_op' fail_op' new_res_ty, thing) }++-- Boolean expressions.+--+-- [ body | stmts, expr ] -> expr :: m Bool+--+tcMcStmt _ (BodyStmt rhs then_op guard_op _) res_ty thing_inside+ = do { -- Deal with rebindable syntax:+ -- 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')+ <- tcSyntaxOp MCompOrigin then_op [SynRho, SynRho] res_ty $+ \ [rhs_ty, new_res_ty] ->+ do { (rhs', guard_op')+ <- tcSyntaxOp MCompOrigin guard_op [SynAny]+ (mkCheckExpType rhs_ty) $+ \ [test_ty] ->+ tcMonoExpr rhs (mkCheckExpType test_ty)+ ; thing <- thing_inside (mkCheckExpType new_res_ty)+ ; return (thing, rhs', rhs_ty, guard_op') }+ ; return (BodyStmt rhs' then_op' guard_op' rhs_ty, thing) }++-- Grouping statements+--+-- [ body | stmts, then group by e using f ]+-- -> e :: t+-- f :: forall a. (a -> t) -> m a -> m (m a)+-- [ body | stmts, then group using f ]+-- -> f :: forall a. m a -> m (m a)++-- We type [ body | (stmts, group by e using f), ... ]+-- f <optional by> [ (a,b,c) | stmts ] >>= \(a,b,c) -> ...body....+--+-- We type the functions as follows:+-- f <optional by> :: m1 (a,b,c) -> m2 (a,b,c) (ThenForm)+-- :: m1 (a,b,c) -> m2 (n (a,b,c)) (GroupForm)+-- (>>=) :: m2 (a,b,c) -> ((a,b,c) -> res) -> res (ThenForm)+-- :: m2 (n (a,b,c)) -> (n (a,b,c) -> res) -> res (GroupForm)+--+tcMcStmt ctxt (TransStmt { trS_stmts = stmts, trS_bndrs = bindersMap+ , trS_by = by, trS_using = using, trS_form = form+ , trS_ret = return_op, trS_bind = bind_op+ , trS_fmap = fmap_op }) res_ty thing_inside+ = do { let star_star_kind = liftedTypeKind `mkFunTy` liftedTypeKind+ ; m1_ty <- newFlexiTyVarTy star_star_kind+ ; m2_ty <- newFlexiTyVarTy star_star_kind+ ; tup_ty <- newFlexiTyVarTy liftedTypeKind+ ; by_e_ty <- newFlexiTyVarTy liftedTypeKind -- The type of the 'by' expression (if any)++ -- n_app :: Type -> Type -- Wraps a 'ty' into '(n ty)' for GroupForm+ ; n_app <- case form of+ ThenForm -> return (\ty -> ty)+ _ -> do { n_ty <- newFlexiTyVarTy star_star_kind+ ; return (n_ty `mkAppTy`) }+ ; let by_arrow :: Type -> Type+ -- (by_arrow res) produces ((alpha->e_ty) -> res) ('by' present)+ -- or res ('by' absent)+ by_arrow = case by of+ Nothing -> \res -> res+ Just {} -> \res -> (alphaTy `mkFunTy` by_e_ty) `mkFunTy` res++ poly_arg_ty = m1_ty `mkAppTy` alphaTy+ using_arg_ty = m1_ty `mkAppTy` tup_ty+ poly_res_ty = m2_ty `mkAppTy` n_app alphaTy+ using_res_ty = m2_ty `mkAppTy` n_app tup_ty+ using_poly_ty = mkInvForAllTy alphaTyVar $+ by_arrow $+ poly_arg_ty `mkFunTy` poly_res_ty++ -- 'stmts' returns a result of type (m1_ty tuple_ty),+ -- typically something like [(Int,Bool,Int)]+ -- We don't know what tuple_ty is yet, so we use a variable+ ; let (bndr_names, n_bndr_names) = unzip bindersMap+ ; (stmts', (bndr_ids, by', return_op')) <-+ tcStmtsAndThen (TransStmtCtxt ctxt) tcMcStmt stmts+ (mkCheckExpType using_arg_ty) $ \res_ty' -> do+ { by' <- case by of+ Nothing -> return Nothing+ Just e -> do { e' <- tcMonoExpr e+ (mkCheckExpType by_e_ty)+ ; return (Just e') }++ -- Find the Ids (and hence types) of all old binders+ ; bndr_ids <- tcLookupLocalIds bndr_names++ -- 'return' is only used for the binders, so we know its type.+ -- return :: (a,b,c,..) -> m (a,b,c,..)+ ; (_, return_op') <- tcSyntaxOp MCompOrigin return_op+ [synKnownType (mkBigCoreVarTupTy bndr_ids)]+ res_ty' $ \ _ -> return ()++ ; return (bndr_ids, by', return_op') }++ --------------- Typecheck the 'bind' function -------------+ -- (>>=) :: m2 (n (a,b,c)) -> ( n (a,b,c) -> new_res_ty ) -> res_ty+ ; new_res_ty <- newFlexiTyVarTy liftedTypeKind+ ; (_, bind_op') <- tcSyntaxOp MCompOrigin bind_op+ [ synKnownType using_res_ty+ , synKnownType (n_app tup_ty `mkFunTy` new_res_ty) ]+ res_ty $ \ _ -> return ()++ --------------- Typecheck the 'fmap' function -------------+ ; fmap_op' <- case form of+ ThenForm -> return noExpr+ _ -> fmap unLoc . tcPolyExpr (noLoc fmap_op) $+ mkInvForAllTy alphaTyVar $+ mkInvForAllTy betaTyVar $+ (alphaTy `mkFunTy` betaTy)+ `mkFunTy` (n_app alphaTy)+ `mkFunTy` (n_app betaTy)++ --------------- Typecheck the 'using' function -------------+ -- using :: ((a,b,c)->t) -> m1 (a,b,c) -> m2 (n (a,b,c))++ ; using' <- tcPolyExpr using using_poly_ty+ ; let final_using = fmap (HsWrap (WpTyApp tup_ty)) using'++ --------------- Bulding the bindersMap ----------------+ ; let mk_n_bndr :: Name -> TcId -> TcId+ mk_n_bndr n_bndr_name bndr_id = mkLocalIdOrCoVar n_bndr_name (n_app (idType bndr_id))++ -- Ensure that every old binder of type `b` is linked up with its+ -- new binder which should have type `n b`+ -- See Note [GroupStmt binder map] in HsExpr+ n_bndr_ids = zipWith mk_n_bndr n_bndr_names bndr_ids+ bindersMap' = bndr_ids `zip` n_bndr_ids++ -- Type check the thing in the environment with+ -- these new binders and return the result+ ; thing <- tcExtendIdEnv n_bndr_ids $+ thing_inside (mkCheckExpType new_res_ty)++ ; return (TransStmt { trS_stmts = stmts', trS_bndrs = bindersMap'+ , trS_by = by', trS_using = final_using+ , trS_ret = return_op', trS_bind = bind_op'+ , trS_bind_arg_ty = n_app tup_ty+ , trS_fmap = fmap_op', trS_form = form }, thing) }++-- A parallel set of comprehensions+-- [ (g x, h x) | ... ; let g v = ...+-- | ... ; let h v = ... ]+--+-- It's possible that g,h are overloaded, so we need to feed the LIE from the+-- (g x, h x) up through both lots of bindings (so we get the bindLocalMethods).+-- Similarly if we had an existential pattern match:+--+-- data T = forall a. Show a => C a+--+-- [ (show x, show y) | ... ; C x <- ...+-- | ... ; C y <- ... ]+--+-- Then we need the LIE from (show x, show y) to be simplified against+-- the bindings for x and y.+--+-- It's difficult to do this in parallel, so we rely on the renamer to+-- ensure that g,h and x,y don't duplicate, and simply grow the environment.+-- So the binders of the first parallel group will be in scope in the second+-- group. But that's fine; there's no shadowing to worry about.+--+-- Note: The `mzip` function will get typechecked via:+--+-- ParStmt [st1::t1, st2::t2, st3::t3]+--+-- mzip :: m st1+-- -> (m st2 -> m st3 -> m (st2, st3)) -- recursive call+-- -> m (st1, (st2, st3))+--+tcMcStmt ctxt (ParStmt bndr_stmts_s mzip_op bind_op _) res_ty thing_inside+ = do { let star_star_kind = liftedTypeKind `mkFunTy` liftedTypeKind+ ; m_ty <- newFlexiTyVarTy star_star_kind++ ; let mzip_ty = mkInvForAllTys [alphaTyVar, betaTyVar] $+ (m_ty `mkAppTy` alphaTy)+ `mkFunTy`+ (m_ty `mkAppTy` betaTy)+ `mkFunTy`+ (m_ty `mkAppTy` mkBoxedTupleTy [alphaTy, betaTy])+ ; mzip_op' <- unLoc `fmap` tcPolyExpr (noLoc mzip_op) mzip_ty++ -- type dummies since we don't know all binder types yet+ ; id_tys_s <- (mapM . mapM) (const (newFlexiTyVarTy liftedTypeKind))+ [ names | ParStmtBlock _ names _ <- bndr_stmts_s ]++ -- Typecheck bind:+ ; let tup_tys = [ mkBigCoreTupTy id_tys | id_tys <- id_tys_s ]+ tuple_ty = mk_tuple_ty tup_tys++ ; (((blocks', thing), inner_res_ty), bind_op')+ <- tcSyntaxOp MCompOrigin bind_op+ [ synKnownType (m_ty `mkAppTy` tuple_ty)+ , SynFun (synKnownType tuple_ty) SynRho ] res_ty $+ \ [inner_res_ty] ->+ do { stuff <- loop m_ty (mkCheckExpType inner_res_ty)+ tup_tys bndr_stmts_s+ ; return (stuff, inner_res_ty) }++ ; return (ParStmt blocks' mzip_op' bind_op' inner_res_ty, thing) }++ where+ mk_tuple_ty tys = foldr1 (\tn tm -> mkBoxedTupleTy [tn, tm]) tys++ -- loop :: Type -- m_ty+ -- -> ExpRhoType -- inner_res_ty+ -- -> [TcType] -- tup_tys+ -- -> [ParStmtBlock Name]+ -- -> TcM ([([LStmt TcId], [TcId])], thing)+ loop _ inner_res_ty [] [] = do { thing <- thing_inside inner_res_ty+ ; return ([], thing) }+ -- matching in the branches++ loop m_ty inner_res_ty (tup_ty_in : tup_tys_in)+ (ParStmtBlock stmts names return_op : pairs)+ = do { let m_tup_ty = m_ty `mkAppTy` tup_ty_in+ ; (stmts', (ids, return_op', pairs', thing))+ <- tcStmtsAndThen ctxt tcMcStmt stmts (mkCheckExpType m_tup_ty) $+ \m_tup_ty' ->+ do { ids <- tcLookupLocalIds names+ ; let tup_ty = mkBigCoreVarTupTy ids+ ; (_, return_op') <-+ tcSyntaxOp MCompOrigin return_op+ [synKnownType tup_ty] m_tup_ty' $+ \ _ -> return ()+ ; (pairs', thing) <- loop m_ty inner_res_ty tup_tys_in pairs+ ; return (ids, return_op', pairs', thing) }+ ; return (ParStmtBlock stmts' ids return_op' : pairs', thing) }+ loop _ _ _ _ = panic "tcMcStmt.loop"++tcMcStmt _ stmt _ _+ = pprPanic "tcMcStmt: unexpected Stmt" (ppr stmt)+++---------------------------------------------------+-- Do-notation+-- (supports rebindable syntax)+---------------------------------------------------++tcDoStmt :: TcExprStmtChecker++tcDoStmt _ (LastStmt body noret _) res_ty thing_inside+ = do { body' <- tcMonoExprNC body res_ty+ ; thing <- thing_inside (panic "tcDoStmt: thing_inside")+ ; return (LastStmt body' noret noSyntaxExpr, thing) }++tcDoStmt ctxt (BindStmt pat rhs bind_op fail_op _) res_ty thing_inside+ = do { -- Deal with rebindable syntax:+ -- (>>=) :: rhs_ty -> (pat_ty -> new_res_ty) -> res_ty+ -- This level of generality is needed for using do-notation+ -- in full generality; see Trac #1537++ ((rhs', pat', new_res_ty, thing), bind_op')+ <- tcSyntaxOp DoOrigin bind_op [SynRho, SynFun SynAny SynRho] res_ty $+ \ [rhs_ty, pat_ty, new_res_ty] ->+ do { rhs' <- tcMonoExprNC rhs (mkCheckExpType rhs_ty)+ ; (pat', thing) <- tcPat (StmtCtxt ctxt) pat+ (mkCheckExpType pat_ty) $+ thing_inside (mkCheckExpType new_res_ty)+ ; return (rhs', pat', new_res_ty, thing) }++ -- If (but only if) the pattern can fail, typecheck the 'fail' operator+ ; fail_op' <- tcMonadFailOp (DoPatOrigin pat) pat' fail_op new_res_ty++ ; return (BindStmt pat' rhs' bind_op' fail_op' new_res_ty, thing) }++tcDoStmt ctxt (ApplicativeStmt pairs mb_join _) res_ty thing_inside+ = do { let tc_app_stmts ty = tcApplicativeStmts ctxt pairs ty $+ thing_inside . mkCheckExpType+ ; ((pairs', body_ty, thing), mb_join') <- case mb_join of+ Nothing -> (, Nothing) <$> tc_app_stmts res_ty+ Just join_op ->+ second Just <$>+ (tcSyntaxOp DoOrigin join_op [SynRho] res_ty $+ \ [rhs_ty] -> tc_app_stmts (mkCheckExpType rhs_ty))++ ; return (ApplicativeStmt pairs' mb_join' body_ty, thing) }++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')+ <- tcSyntaxOp DoOrigin then_op [SynRho, SynRho] res_ty $+ \ [rhs_ty, new_res_ty] ->+ do { rhs' <- tcMonoExprNC rhs (mkCheckExpType rhs_ty)+ ; thing <- thing_inside (mkCheckExpType new_res_ty)+ ; return (rhs', rhs_ty, thing) }+ ; return (BodyStmt rhs' then_op' noSyntaxExpr rhs_ty, thing) }++tcDoStmt ctxt (RecStmt { recS_stmts = stmts, recS_later_ids = later_names+ , recS_rec_ids = rec_names, recS_ret_fn = ret_op+ , recS_mfix_fn = mfix_op, recS_bind_fn = bind_op })+ res_ty thing_inside+ = do { let tup_names = rec_names ++ filterOut (`elem` rec_names) later_names+ ; tup_elt_tys <- newFlexiTyVarTys (length tup_names) liftedTypeKind+ ; let tup_ids = zipWith mkLocalId tup_names tup_elt_tys+ tup_ty = mkBigCoreTupTy tup_elt_tys++ ; tcExtendIdEnv tup_ids $ do+ { ((stmts', (ret_op', tup_rets)), stmts_ty)+ <- tcInferInst $ \ exp_ty ->+ tcStmtsAndThen ctxt tcDoStmt stmts exp_ty $ \ inner_res_ty ->+ do { tup_rets <- zipWithM tcCheckId tup_names+ (map mkCheckExpType tup_elt_tys)+ -- Unify the types of the "final" Ids (which may+ -- be polymorphic) with those of "knot-tied" Ids+ ; (_, ret_op')+ <- tcSyntaxOp DoOrigin ret_op [synKnownType tup_ty]+ inner_res_ty $ \_ -> return ()+ ; return (ret_op', tup_rets) }++ ; ((_, mfix_op'), mfix_res_ty)+ <- tcInferInst $ \ exp_ty ->+ tcSyntaxOp DoOrigin mfix_op+ [synKnownType (mkFunTy tup_ty stmts_ty)] exp_ty $+ \ _ -> return ()++ ; ((thing, new_res_ty), bind_op')+ <- tcSyntaxOp DoOrigin bind_op+ [ synKnownType mfix_res_ty+ , synKnownType tup_ty `SynFun` SynRho ]+ res_ty $+ \ [new_res_ty] ->+ do { thing <- thing_inside (mkCheckExpType new_res_ty)+ ; return (thing, new_res_ty) }++ ; let rec_ids = takeList rec_names tup_ids+ ; later_ids <- tcLookupLocalIds later_names+ ; traceTc "tcdo" $ vcat [ppr rec_ids <+> ppr (map idType rec_ids),+ ppr later_ids <+> ppr (map idType later_ids)]+ ; return (RecStmt { recS_stmts = stmts', recS_later_ids = later_ids+ , recS_rec_ids = rec_ids, recS_ret_fn = ret_op'+ , recS_mfix_fn = mfix_op', recS_bind_fn = bind_op'+ , recS_bind_ty = new_res_ty+ , recS_later_rets = [], recS_rec_rets = tup_rets+ , recS_ret_ty = stmts_ty }, thing)+ }}++tcDoStmt _ stmt _ _+ = pprPanic "tcDoStmt: unexpected Stmt" (ppr stmt)++++---------------------------------------------------+-- MonadFail Proposal warnings+---------------------------------------------------++-- The idea behind issuing MonadFail warnings is that we add them whenever a+-- failable pattern is encountered. However, instead of throwing a type error+-- when the constraint cannot be satisfied, we only issue a warning in+-- TcErrors.hs.++tcMonadFailOp :: CtOrigin+ -> LPat TcId+ -> SyntaxExpr Name -- The fail op+ -> TcType -- Type of the whole do-expression+ -> TcRn (SyntaxExpr TcId) -- Typechecked fail op+-- Get a 'fail' operator expression, to use if the pattern+-- match fails. If the pattern is irrefutatable, just return+-- noSyntaxExpr; it won't be used+tcMonadFailOp orig pat fail_op res_ty+ | isIrrefutableHsPat pat+ = return noSyntaxExpr++ | otherwise+ = do { -- Issue MonadFail warnings+ rebindableSyntax <- xoptM LangExt.RebindableSyntax+ ; desugarFlag <- xoptM LangExt.MonadFailDesugaring+ ; missingWarning <- woptM Opt_WarnMissingMonadFailInstances+ ; if | rebindableSyntax && (desugarFlag || missingWarning)+ -> warnRebindableClash pat+ | not desugarFlag && missingWarning+ -> emitMonadFailConstraint pat res_ty+ | otherwise+ -> return ()++ -- Get the fail op itself+ ; snd <$> (tcSyntaxOp orig fail_op [synKnownType stringTy]+ (mkCheckExpType res_ty) $ \_ -> return ()) }++emitMonadFailConstraint :: LPat TcId -> TcType -> TcRn ()+emitMonadFailConstraint pat res_ty+ = do { -- We expect res_ty to be of form (monad_ty arg_ty)+ (_co, (monad_ty, _arg_ty)) <- matchExpectedAppTy res_ty++ -- Emit (MonadFail m), but ignore the evidence; it's+ -- just there to generate a warning+ ; monadFailClass <- tcLookupClass monadFailClassName+ ; _ <- emitWanted (FailablePattern pat)+ (mkClassPred monadFailClass [monad_ty])+ ; return () }++warnRebindableClash :: LPat TcId -> TcRn ()+warnRebindableClash pattern = addWarnAt+ (Reason Opt_WarnMissingMonadFailInstances)+ (getLoc pattern)+ (text "The failable pattern" <+> quotes (ppr pattern)+ $$+ nest 2 (text "is used together with -XRebindableSyntax."+ <+> text "If this is intentional,"+ $$+ text "compile with -Wno-missing-monadfail-instances."))++{-+Note [Treat rebindable syntax first]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When typechecking+ do { bar; ... } :: IO ()+we want to typecheck 'bar' in the knowledge that it should be an IO thing,+pushing info from the context into the RHS. To do this, we check the+rebindable syntax first, and push that information into (tcMonoExprNC rhs).+Otherwise the error shows up when cheking the rebindable syntax, and+the expected/inferred stuff is back to front (see Trac #3613).++Note [typechecking ApplicativeStmt]++join ((\pat1 ... patn -> body) <$> e1 <*> ... <*> en)++fresh type variables:+ pat_ty_1..pat_ty_n+ exp_ty_1..exp_ty_n+ t_1..t_(n-1)++body :: body_ty+(\pat1 ... patn -> body) :: pat_ty_1 -> ... -> pat_ty_n -> body_ty+pat_i :: pat_ty_i+e_i :: exp_ty_i+<$> :: (pat_ty_1 -> ... -> pat_ty_n -> body_ty) -> exp_ty_1 -> t_1+<*>_i :: t_(i-1) -> exp_ty_i -> t_i+join :: tn -> res_ty+-}++tcApplicativeStmts+ :: HsStmtContext Name+ -> [(SyntaxExpr Name, ApplicativeArg Name Name)]+ -> ExpRhoType -- rhs_ty+ -> (TcRhoType -> TcM t) -- thing_inside+ -> TcM ([(SyntaxExpr TcId, ApplicativeArg TcId TcId)], Type, t)++tcApplicativeStmts ctxt pairs rhs_ty thing_inside+ = do { body_ty <- newFlexiTyVarTy liftedTypeKind+ ; let arity = length pairs+ ; ts <- replicateM (arity-1) $ newInferExpTypeInst+ ; exp_tys <- replicateM arity $ newFlexiTyVarTy liftedTypeKind+ ; pat_tys <- replicateM arity $ newFlexiTyVarTy liftedTypeKind+ ; let fun_ty = mkFunTys pat_tys body_ty++ -- NB. do the <$>,<*> operators first, we don't want type errors here+ -- i.e. goOps before goArgs+ -- See Note [Treat rebindable syntax first]+ ; let (ops, args) = unzip pairs+ ; ops' <- goOps fun_ty (zip3 ops (ts ++ [rhs_ty]) exp_tys)++ -- Typecheck each ApplicativeArg separately+ -- See Note [ApplicativeDo and constraints]+ ; args' <- mapM goArg (zip3 args pat_tys exp_tys)++ -- Bring into scope all the things bound by the args,+ -- and typecheck the thing_inside+ -- See Note [ApplicativeDo and constraints]+ ; res <- tcExtendIdEnv (concatMap get_arg_bndrs args') $+ thing_inside body_ty++ ; return (zip ops' args', body_ty, res) }+ where+ goOps _ [] = return []+ goOps t_left ((op,t_i,exp_ty) : ops)+ = do { (_, op')+ <- tcSyntaxOp DoOrigin op+ [synKnownType t_left, synKnownType exp_ty] t_i $+ \ _ -> return ()+ ; t_i <- readExpType t_i+ ; ops' <- goOps t_i ops+ ; return (op' : ops') }++ goArg :: (ApplicativeArg Name Name, Type, Type)+ -> TcM (ApplicativeArg TcId TcId)++ goArg (ApplicativeArgOne pat rhs, pat_ty, exp_ty)+ = setSrcSpan (combineSrcSpans (getLoc pat) (getLoc rhs)) $+ addErrCtxt (pprStmtInCtxt ctxt (mkBindStmt pat rhs)) $+ do { rhs' <- tcMonoExprNC rhs (mkCheckExpType exp_ty)+ ; (pat', _) <- tcPat (StmtCtxt ctxt) pat (mkCheckExpType pat_ty) $+ return ()+ ; return (ApplicativeArgOne pat' rhs') }++ goArg (ApplicativeArgMany stmts ret pat, pat_ty, exp_ty)+ = do { (stmts', (ret',pat')) <-+ tcStmtsAndThen ctxt tcDoStmt stmts (mkCheckExpType exp_ty) $+ \res_ty -> do+ { L _ ret' <- tcMonoExprNC (noLoc ret) res_ty+ ; (pat', _) <- tcPat (StmtCtxt ctxt) pat (mkCheckExpType pat_ty) $+ return ()+ ; return (ret', pat')+ }+ ; return (ApplicativeArgMany stmts' ret' pat') }++ get_arg_bndrs :: ApplicativeArg TcId TcId -> [Id]+ get_arg_bndrs (ApplicativeArgOne pat _) = collectPatBinders pat+ get_arg_bndrs (ApplicativeArgMany _ _ pat) = collectPatBinders pat+++{- Note [ApplicativeDo and constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+An applicative-do is supposed to take place in parallel, so+constraints bound in one arm can't possibly be available in another+(Trac #13242). Our current rule is this (more details and discussion+on the ticket). Consider++ ...stmts...+ ApplicativeStmts [arg1, arg2, ... argN]+ ...more stmts...++where argi :: ApplicativeArg. Each 'argi' itself contains one or more Stmts.+Now, we say that:++* Constraints required by the argi can be solved from+ constraint bound by ...stmts...++* Constraints and existentials bound by the argi are not available+ to solve constraints required either by argj (where i /= j),+ or by ...more stmts....++* Within the stmts of each 'argi' individually, however, constraints bound+ by earlier stmts can be used to solve later ones.++To achieve this, we just typecheck each 'argi' separately, bring all+the variables they bind into scope, and typecheck the thing_inside.++************************************************************************+* *+\subsection{Errors and contexts}+* *+************************************************************************++@sameNoOfArgs@ takes a @[RenamedMatch]@ and decides whether the same+number of args are used in each equation.+-}++checkArgs :: Name -> MatchGroup Name body -> TcM ()+checkArgs _ (MG { mg_alts = L _ [] })+ = return ()+checkArgs fun (MG { mg_alts = L _ (match1:matches) })+ | null bad_matches+ = return ()+ | otherwise+ = failWithTc (vcat [ text "Equations for" <+> quotes (ppr fun) <+>+ text "have different numbers of arguments"+ , nest 2 (ppr (getLoc match1))+ , nest 2 (ppr (getLoc (head bad_matches)))])+ where+ n_args1 = args_in_match match1+ bad_matches = [m | m <- matches, args_in_match m /= n_args1]++ args_in_match :: LMatch Name body -> Int+ args_in_match (L _ (Match _ pats _ _)) = length pats
+ typecheck/TcMatches.hs-boot view
@@ -0,0 +1,16 @@+module TcMatches where+import HsSyn ( GRHSs, MatchGroup, LHsExpr )+import TcEvidence( HsWrapper )+import Name ( Name )+import TcType ( ExpRhoType, TcRhoType )+import TcRnTypes( TcM, TcId )+import SrcLoc ( Located )++tcGRHSsPat :: GRHSs Name (LHsExpr Name)+ -> TcRhoType+ -> TcM (GRHSs TcId (LHsExpr TcId))++tcMatchesFun :: Located Name+ -> MatchGroup Name (LHsExpr Name)+ -> ExpRhoType+ -> TcM (HsWrapper, MatchGroup TcId (LHsExpr TcId))
+ typecheck/TcPat.hs view
@@ -0,0 +1,1175 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++TcPat: Typechecking patterns+-}++{-# LANGUAGE CPP, RankNTypes, TupleSections #-}+{-# LANGUAGE FlexibleContexts #-}++module TcPat ( tcLetPat, newLetBndr, LetBndrSpec(..)+ , tcPat, tcPat_O, tcPats+ , addDataConStupidTheta, badFieldCon, polyPatSig ) where++#include "HsVersions.h"++import {-# SOURCE #-} TcExpr( tcSyntaxOp, tcSyntaxOpGen, tcInferSigma )++import HsSyn+import TcHsSyn+import TcSigs( TcPragEnv, lookupPragEnv, addInlinePrags )+import TcRnMonad+import Inst+import Id+import Var+import Name+import RdrName+import TcEnv+import TcMType+import TcValidity( arityErr )+import Type ( pprTyVars )+import TcType+import TcUnify+import TcHsType+import TysWiredIn+import TcEvidence+import TyCon+import DataCon+import PatSyn+import ConLike+import PrelNames+import BasicTypes hiding (SuccessFlag(..))+import DynFlags+import SrcLoc+import VarSet+import Util+import Outputable+import qualified GHC.LanguageExtensions as LangExt+import Control.Arrow ( second )+import ListSetOps ( getNth )++{-+************************************************************************+* *+ External interface+* *+************************************************************************+-}++tcLetPat :: (Name -> Maybe TcId)+ -> LetBndrSpec+ -> LPat Name -> ExpSigmaType+ -> TcM a+ -> TcM (LPat TcId, a)+tcLetPat sig_fn no_gen pat pat_ty thing_inside+ = do { bind_lvl <- getTcLevel+ ; let ctxt = LetPat { pc_lvl = bind_lvl+ , pc_sig_fn = sig_fn+ , pc_new = no_gen }+ penv = PE { pe_lazy = True+ , pe_ctxt = ctxt+ , pe_orig = PatOrigin }++ ; tc_lpat pat pat_ty penv thing_inside }++-----------------+tcPats :: HsMatchContext Name+ -> [LPat Name] -- Patterns,+ -> [ExpSigmaType] -- and their types+ -> TcM a -- and the checker for the body+ -> TcM ([LPat TcId], a)++-- This is the externally-callable wrapper function+-- Typecheck the patterns, extend the environment to bind the variables,+-- do the thing inside, use any existentially-bound dictionaries to+-- discharge parts of the returning LIE, and deal with pattern type+-- signatures++-- 1. Initialise the PatState+-- 2. Check the patterns+-- 3. Check the body+-- 4. Check that no existentials escape++tcPats ctxt pats pat_tys thing_inside+ = tc_lpats penv pats pat_tys thing_inside+ where+ penv = PE { pe_lazy = False, pe_ctxt = LamPat ctxt, pe_orig = PatOrigin }++tcPat :: HsMatchContext Name+ -> LPat Name -> ExpSigmaType+ -> TcM a -- Checker for body+ -> TcM (LPat TcId, a)+tcPat ctxt = tcPat_O ctxt PatOrigin++-- | A variant of 'tcPat' that takes a custom origin+tcPat_O :: HsMatchContext Name+ -> CtOrigin -- ^ origin to use if the type needs inst'ing+ -> LPat Name -> ExpSigmaType+ -> TcM a -- Checker for body+ -> TcM (LPat TcId, a)+tcPat_O ctxt orig pat pat_ty thing_inside+ = tc_lpat pat pat_ty penv thing_inside+ where+ penv = PE { pe_lazy = False, pe_ctxt = LamPat ctxt, pe_orig = orig }+++{-+************************************************************************+* *+ PatEnv, PatCtxt, LetBndrSpec+* *+************************************************************************+-}++data PatEnv+ = PE { pe_lazy :: Bool -- True <=> lazy context, so no existentials allowed+ , pe_ctxt :: PatCtxt -- Context in which the whole pattern appears+ , pe_orig :: CtOrigin -- origin to use if the pat_ty needs inst'ing+ }++data PatCtxt+ = LamPat -- Used for lambdas, case etc+ (HsMatchContext Name)++ | LetPat -- Used only for let(rec) pattern bindings+ -- See Note [Typing patterns in pattern bindings]+ { pc_lvl :: TcLevel+ -- Level of the binding group++ , pc_sig_fn :: Name -> Maybe TcId+ -- Tells the expected type+ -- for binders with a signature++ , pc_new :: LetBndrSpec+ -- How to make a new binder+ } -- for binders without signatures++data LetBndrSpec+ = LetLclBndr -- We are going to generalise, and wrap in an AbsBinds+ -- so clone a fresh binder for the local monomorphic Id++ | LetGblBndr TcPragEnv -- Generalisation plan is NoGen, so there isn't going+ -- to be an AbsBinds; So we must bind the global version+ -- of the binder right away.+ -- And here is the inline-pragma information++instance Outputable LetBndrSpec where+ ppr LetLclBndr = text "LetLclBndr"+ ppr (LetGblBndr {}) = text "LetGblBndr"++makeLazy :: PatEnv -> PatEnv+makeLazy penv = penv { pe_lazy = True }++inPatBind :: PatEnv -> Bool+inPatBind (PE { pe_ctxt = LetPat {} }) = True+inPatBind (PE { pe_ctxt = LamPat {} }) = False++{- *********************************************************************+* *+ Binders+* *+********************************************************************* -}++tcPatBndr :: PatEnv -> Name -> ExpSigmaType -> TcM (HsWrapper, TcId)+-- (coi, xp) = tcPatBndr penv x pat_ty+-- Then coi : pat_ty ~ typeof(xp)+--+tcPatBndr penv@(PE { pe_ctxt = LetPat { pc_lvl = bind_lvl+ , pc_sig_fn = sig_fn+ , pc_new = no_gen } })+ bndr_name exp_pat_ty+ -- For the LetPat cases, see+ -- Note [Typechecking pattern bindings] in TcBinds++ | Just bndr_id <- sig_fn bndr_name -- There is a signature+ = do { wrap <- tcSubTypePat penv exp_pat_ty (idType bndr_id)+ -- See Note [Subsumption check at pattern variables]+ ; traceTc "tcPatBndr(sig)" (ppr bndr_id $$ ppr (idType bndr_id) $$ ppr exp_pat_ty)+ ; return (wrap, bndr_id) }++ | otherwise -- No signature+ = do { (co, bndr_ty) <- case exp_pat_ty of+ Check pat_ty -> promoteTcType bind_lvl pat_ty+ Infer infer_res -> ASSERT( bind_lvl == ir_lvl infer_res )+ -- If we were under a constructor that bumped+ -- the level, we'd be in checking mode+ do { bndr_ty <- inferResultToType infer_res+ ; return (mkTcNomReflCo bndr_ty, bndr_ty) }+ ; bndr_id <- newLetBndr no_gen bndr_name bndr_ty+ ; traceTc "tcPatBndr(nosig)" (vcat [ ppr bind_lvl+ , ppr exp_pat_ty, ppr bndr_ty, ppr co+ , ppr bndr_id ])+ ; return (mkWpCastN co, bndr_id) }++tcPatBndr _ bndr_name pat_ty+ = do { pat_ty <- expTypeToType pat_ty+ ; traceTc "tcPatBndr(not let)" (ppr bndr_name $$ ppr pat_ty)+ ; return (idHsWrapper, mkLocalId bndr_name pat_ty) }+ -- Whether or not there is a sig is irrelevant,+ -- as this is local++newLetBndr :: LetBndrSpec -> Name -> TcType -> TcM TcId+-- Make up a suitable Id for the pattern-binder.+-- See Note [Typechecking pattern bindings], item (4) in TcBinds+--+-- In the polymorphic case when we are going to generalise+-- (plan InferGen, no_gen = LetLclBndr), generate a "monomorphic version"+-- of the Id; the original name will be bound to the polymorphic version+-- by the AbsBinds+-- In the monomorphic case when we are not going to generalise+-- (plan NoGen, no_gen = LetGblBndr) there is no AbsBinds,+-- and we use the original name directly+newLetBndr LetLclBndr name ty+ = do { mono_name <- cloneLocalName name+ ; return (mkLocalId mono_name ty) }+newLetBndr (LetGblBndr prags) name ty+ = addInlinePrags (mkLocalId name ty) (lookupPragEnv prags name)++tcSubTypePat :: PatEnv -> ExpSigmaType -> TcSigmaType -> TcM HsWrapper+-- tcSubTypeET with the UserTypeCtxt specialised to GenSigCtxt+-- Used when typechecking patterns+tcSubTypePat penv t1 t2 = tcSubTypeET (pe_orig penv) GenSigCtxt t1 t2++{- Note [Subsumption check at pattern variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we come across a variable with a type signature, we need to do a+subsumption, not equality, check against the context type. e.g.++ data T = MkT (forall a. a->a)+ f :: forall b. [b]->[b]+ MkT f = blah++Since 'blah' returns a value of type T, its payload is a polymorphic+function of type (forall a. a->a). And that's enough to bind the+less-polymorphic function 'f', but we need some impedance matching+to witness the instantiation.+++************************************************************************+* *+ The main worker functions+* *+************************************************************************++Note [Nesting]+~~~~~~~~~~~~~~+tcPat takes a "thing inside" over which the pattern scopes. This is partly+so that tcPat can extend the environment for the thing_inside, but also+so that constraints arising in the thing_inside can be discharged by the+pattern.++This does not work so well for the ErrCtxt carried by the monad: we don't+want the error-context for the pattern to scope over the RHS.+Hence the getErrCtxt/setErrCtxt stuff in tcMultiple+-}++--------------------+type Checker inp out = forall r.+ inp+ -> PatEnv+ -> TcM r+ -> TcM (out, r)++tcMultiple :: Checker inp out -> Checker [inp] [out]+tcMultiple tc_pat args penv thing_inside+ = do { err_ctxt <- getErrCtxt+ ; let loop _ []+ = do { res <- thing_inside+ ; return ([], res) }++ loop penv (arg:args)+ = do { (p', (ps', res))+ <- tc_pat arg penv $+ setErrCtxt err_ctxt $+ loop penv args+ -- setErrCtxt: restore context before doing the next pattern+ -- See note [Nesting] above++ ; return (p':ps', res) }++ ; loop penv args }++--------------------+tc_lpat :: LPat Name+ -> ExpSigmaType+ -> PatEnv+ -> TcM a+ -> TcM (LPat TcId, a)+tc_lpat (L span pat) pat_ty penv thing_inside+ = setSrcSpan span $+ do { (pat', res) <- maybeWrapPatCtxt pat (tc_pat penv pat pat_ty)+ thing_inside+ ; return (L span pat', res) }++tc_lpats :: PatEnv+ -> [LPat Name] -> [ExpSigmaType]+ -> TcM a+ -> TcM ([LPat TcId], a)+tc_lpats penv pats tys thing_inside+ = ASSERT2( equalLength pats tys, ppr pats $$ ppr tys )+ tcMultiple (\(p,t) -> tc_lpat p t)+ (zipEqual "tc_lpats" pats tys)+ penv thing_inside++--------------------+tc_pat :: PatEnv+ -> Pat Name+ -> ExpSigmaType -- Fully refined result type+ -> TcM a -- Thing inside+ -> TcM (Pat TcId, -- Translated pattern+ a) -- Result of thing inside++tc_pat penv (VarPat (L l name)) pat_ty thing_inside+ = do { (wrap, id) <- tcPatBndr penv name pat_ty+ ; res <- tcExtendIdEnv1 name id thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat wrap (VarPat (L l id)) pat_ty, res) }++tc_pat penv (ParPat pat) pat_ty thing_inside+ = do { (pat', res) <- tc_lpat pat pat_ty penv thing_inside+ ; return (ParPat pat', res) }++tc_pat penv (BangPat pat) pat_ty thing_inside+ = do { (pat', res) <- tc_lpat pat pat_ty penv thing_inside+ ; return (BangPat pat', res) }++tc_pat penv (LazyPat pat) pat_ty thing_inside+ = do { (pat', (res, pat_ct))+ <- tc_lpat pat pat_ty (makeLazy penv) $+ captureConstraints thing_inside+ -- Ignore refined penv', revert to penv++ ; emitConstraints pat_ct+ -- captureConstraints/extendConstraints:+ -- see Note [Hopping the LIE in lazy patterns]++ -- Check that the expected pattern type is itself lifted+ ; pat_ty <- readExpType pat_ty+ ; _ <- unifyType noThing (typeKind pat_ty) liftedTypeKind++ ; return (LazyPat pat', res) }++tc_pat _ (WildPat _) pat_ty thing_inside+ = do { res <- thing_inside+ ; pat_ty <- expTypeToType pat_ty+ ; return (WildPat pat_ty, res) }++tc_pat penv (AsPat (L nm_loc name) pat) pat_ty thing_inside+ = do { (wrap, bndr_id) <- setSrcSpan nm_loc (tcPatBndr penv name pat_ty)+ ; (pat', res) <- tcExtendIdEnv1 name bndr_id $+ tc_lpat pat (mkCheckExpType $ idType bndr_id)+ penv thing_inside+ -- NB: if we do inference on:+ -- \ (y@(x::forall a. a->a)) = e+ -- we'll fail. The as-pattern infers a monotype for 'y', which then+ -- fails to unify with the polymorphic type for 'x'. This could+ -- perhaps be fixed, but only with a bit more work.+ --+ -- If you fix it, don't forget the bindInstsOfPatIds!+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat wrap (AsPat (L nm_loc bndr_id) pat') pat_ty, res) }++tc_pat penv (ViewPat expr pat _) overall_pat_ty thing_inside+ = do {+ -- Expr must have type `forall a1...aN. OPT' -> B`+ -- where overall_pat_ty is an instance of OPT'.+ ; (expr',expr'_inferred) <- tcInferSigma expr++ -- expression must be a function+ ; let expr_orig = lexprCtOrigin expr+ herald = text "A view pattern expression expects"+ ; (expr_wrap1, [inf_arg_ty], inf_res_ty)+ <- matchActualFunTys herald expr_orig (Just expr) 1 expr'_inferred+ -- expr_wrap1 :: expr'_inferred "->" (inf_arg_ty -> inf_res_ty)++ -- check that overall pattern is more polymorphic than arg type+ ; expr_wrap2 <- tcSubTypePat penv overall_pat_ty inf_arg_ty+ -- expr_wrap2 :: overall_pat_ty "->" inf_arg_ty++ -- pattern must have inf_res_ty+ ; (pat', res) <- tc_lpat pat (mkCheckExpType inf_res_ty) penv thing_inside++ ; overall_pat_ty <- readExpType overall_pat_ty+ ; let expr_wrap2' = mkWpFun expr_wrap2 idHsWrapper+ overall_pat_ty inf_res_ty doc+ -- expr_wrap2' :: (inf_arg_ty -> inf_res_ty) "->"+ -- (overall_pat_ty -> inf_res_ty)+ expr_wrap = expr_wrap2' <.> expr_wrap1+ doc = text "When checking the view pattern function:" <+> (ppr expr)+ ; return (ViewPat (mkLHsWrap expr_wrap expr') pat' overall_pat_ty, res) }++-- Type signatures in patterns+-- See Note [Pattern coercions] below+tc_pat penv (SigPatIn pat sig_ty) pat_ty thing_inside+ = do { (inner_ty, tv_binds, wcs, wrap) <- tcPatSig (inPatBind penv)+ sig_ty pat_ty+ ; (pat', res) <- tcExtendTyVarEnv2 wcs $+ tcExtendTyVarEnv2 tv_binds $+ tc_lpat pat (mkCheckExpType inner_ty) penv thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat wrap (SigPatOut pat' inner_ty) pat_ty, res) }++------------------------+-- Lists, tuples, arrays+tc_pat penv (ListPat pats _ Nothing) pat_ty thing_inside+ = do { (coi, elt_ty) <- matchExpectedPatTy matchExpectedListTy penv pat_ty+ ; (pats', res) <- tcMultiple (\p -> tc_lpat p (mkCheckExpType elt_ty))+ pats penv thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat coi (ListPat pats' elt_ty Nothing) pat_ty, res)+ }++tc_pat penv (ListPat pats _ (Just (_,e))) pat_ty thing_inside+ = do { tau_pat_ty <- expTypeToType pat_ty+ ; ((pats', res, elt_ty), e')+ <- tcSyntaxOpGen ListOrigin e [SynType (mkCheckExpType tau_pat_ty)]+ SynList $+ \ [elt_ty] ->+ do { (pats', res) <- tcMultiple (\p -> tc_lpat p (mkCheckExpType elt_ty))+ pats penv thing_inside+ ; return (pats', res, elt_ty) }+ ; return (ListPat pats' elt_ty (Just (tau_pat_ty,e')), res)+ }++tc_pat penv (PArrPat pats _) pat_ty thing_inside+ = do { (coi, elt_ty) <- matchExpectedPatTy matchExpectedPArrTy penv pat_ty+ ; (pats', res) <- tcMultiple (\p -> tc_lpat p (mkCheckExpType elt_ty))+ pats penv thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat coi (PArrPat pats' elt_ty) pat_ty, res)+ }++tc_pat penv (TuplePat pats boxity _) pat_ty thing_inside+ = do { let arity = length pats+ tc = tupleTyCon boxity arity+ ; (coi, arg_tys) <- matchExpectedPatTy (matchExpectedTyConApp tc)+ penv pat_ty+ -- Unboxed tuples have RuntimeRep vars, which we discard:+ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ ; let con_arg_tys = case boxity of Unboxed -> drop arity arg_tys+ Boxed -> arg_tys+ ; (pats', res) <- tc_lpats penv pats (map mkCheckExpType con_arg_tys)+ thing_inside++ ; dflags <- getDynFlags++ -- Under flag control turn a pattern (x,y,z) into ~(x,y,z)+ -- so that we can experiment with lazy tuple-matching.+ -- This is a pretty odd place to make the switch, but+ -- it was easy to do.+ ; let+ unmangled_result = TuplePat pats' boxity con_arg_tys+ -- pat_ty /= pat_ty iff coi /= IdCo+ possibly_mangled_result+ | gopt Opt_IrrefutableTuples dflags &&+ isBoxed boxity = LazyPat (noLoc unmangled_result)+ | otherwise = unmangled_result++ ; pat_ty <- readExpType pat_ty+ ; ASSERT( length con_arg_tys == length pats ) -- Syntactically enforced+ return (mkHsWrapPat coi possibly_mangled_result pat_ty, res)+ }++tc_pat penv (SumPat pat alt arity _) pat_ty thing_inside+ = do { let tc = sumTyCon arity+ ; (coi, arg_tys) <- matchExpectedPatTy (matchExpectedTyConApp tc)+ penv pat_ty+ ; -- Drop levity vars, we don't care about them here+ let con_arg_tys = drop arity arg_tys+ ; (pat', res) <- tc_lpat pat (mkCheckExpType (con_arg_tys `getNth` (alt - 1)))+ penv thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat coi (SumPat pat' alt arity con_arg_tys) pat_ty, res)+ }++------------------------+-- Data constructors+tc_pat penv (ConPatIn con arg_pats) pat_ty thing_inside+ = tcConPat penv con pat_ty arg_pats thing_inside++------------------------+-- Literal patterns+tc_pat penv (LitPat simple_lit) pat_ty thing_inside+ = do { let lit_ty = hsLitType simple_lit+ ; wrap <- tcSubTypePat penv pat_ty lit_ty+ ; res <- thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return ( mkHsWrapPat wrap (LitPat simple_lit) pat_ty+ , res) }++------------------------+-- Overloaded patterns: n, and n+k++-- In the case of a negative literal (the more complicated case),+-- we get+--+-- case v of (-5) -> blah+--+-- becoming+--+-- if v == (negate (fromInteger 5)) then blah else ...+--+-- There are two bits of rebindable syntax:+-- (==) :: pat_ty -> neg_lit_ty -> Bool+-- negate :: lit_ty -> neg_lit_ty+-- where lit_ty is the type of the overloaded literal 5.+--+-- When there is no negation, neg_lit_ty and lit_ty are the same+tc_pat _ (NPat (L l over_lit) mb_neg eq _) pat_ty thing_inside+ = do { let orig = LiteralOrigin over_lit+ ; ((lit', mb_neg'), eq')+ <- tcSyntaxOp orig eq [SynType pat_ty, SynAny]+ (mkCheckExpType boolTy) $+ \ [neg_lit_ty] ->+ let new_over_lit lit_ty = newOverloadedLit over_lit+ (mkCheckExpType lit_ty)+ in case mb_neg of+ Nothing -> (, Nothing) <$> new_over_lit neg_lit_ty+ Just neg -> -- Negative literal+ -- The 'negate' is re-mappable syntax+ second Just <$>+ (tcSyntaxOp orig neg [SynRho] (mkCheckExpType neg_lit_ty) $+ \ [lit_ty] -> new_over_lit lit_ty)++ ; res <- thing_inside+ ; pat_ty <- readExpType pat_ty+ ; return (NPat (L l lit') mb_neg' eq' pat_ty, res) }++{-+Note [NPlusK patterns]+~~~~~~~~~~~~~~~~~~~~~~+From++ case v of x + 5 -> blah++we get++ if v >= 5 then (\x -> blah) (v - 5) else ...++There are two bits of rebindable syntax:+ (>=) :: pat_ty -> lit1_ty -> Bool+ (-) :: pat_ty -> lit2_ty -> var_ty++lit1_ty and lit2_ty could conceivably be different.+var_ty is the type inferred for x, the variable in the pattern.++If the pushed-down pattern type isn't a tau-type, the two pat_ty's above+could conceivably be different specializations. But this is very much+like the situation in Note [Case branches must be taus] in TcMatches.+So we tauify the pat_ty before proceeding.++Note that we need to type-check the literal twice, because it is used+twice, and may be used at different types. The second HsOverLit stored in the+AST is used for the subtraction operation.+-}++-- See Note [NPlusK patterns]+tc_pat penv (NPlusKPat (L nm_loc name) (L loc lit) _ ge minus _) pat_ty thing_inside+ = do { pat_ty <- expTypeToType pat_ty+ ; let orig = LiteralOrigin lit+ ; (lit1', ge')+ <- tcSyntaxOp orig ge [synKnownType pat_ty, SynRho]+ (mkCheckExpType boolTy) $+ \ [lit1_ty] ->+ newOverloadedLit lit (mkCheckExpType lit1_ty)+ ; ((lit2', minus_wrap, bndr_id), minus')+ <- tcSyntaxOpGen orig minus [synKnownType pat_ty, SynRho] SynAny $+ \ [lit2_ty, var_ty] ->+ do { lit2' <- newOverloadedLit lit (mkCheckExpType lit2_ty)+ ; (wrap, bndr_id) <- setSrcSpan nm_loc $+ tcPatBndr penv name (mkCheckExpType var_ty)+ -- co :: var_ty ~ idType bndr_id++ -- minus_wrap is applicable to minus'+ ; return (lit2', wrap, bndr_id) }++ -- 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) $+ do { icls <- tcLookupClass integralClassName+ ; instStupidTheta orig [mkClassPred icls [pat_ty]] }++ ; res <- tcExtendIdEnv1 name bndr_id thing_inside++ ; let minus'' = minus' { syn_res_wrap =+ minus_wrap <.> syn_res_wrap minus' }+ pat' = NPlusKPat (L nm_loc bndr_id) (L loc lit1') lit2'+ ge' minus'' pat_ty+ ; return (pat', res) }++-- HsSpliced is an annotation produced by 'RnSplice.rnSplicePat'.+-- Here we get rid of it and add the finalizers to the global environment.+--+-- See Note [Delaying modFinalizers in untyped splices] in RnSplice.+tc_pat penv (SplicePat (HsSpliced mod_finalizers (HsSplicedPat pat)))+ pat_ty thing_inside+ = do addModFinalizersWithLclEnv mod_finalizers+ tc_pat penv pat pat_ty thing_inside++tc_pat _ _other_pat _ _ = panic "tc_pat" -- ConPatOut, SigPatOut+++{-+Note [Hopping the LIE in lazy patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a lazy pattern, we must *not* discharge constraints from the RHS+from dictionaries bound in the pattern. E.g.+ f ~(C x) = 3+We can't discharge the Num constraint from dictionaries bound by+the pattern C!++So we have to make the constraints from thing_inside "hop around"+the pattern. Hence the captureConstraints and emitConstraints.++The same thing ensures that equality constraints in a lazy match+are not made available in the RHS of the match. For example+ data T a where { T1 :: Int -> T Int; ... }+ f :: T a -> Int -> a+ f ~(T1 i) y = y+It's obviously not sound to refine a to Int in the right+hand side, because the argument might not match T1 at all!++Finally, a lazy pattern should not bind any existential type variables+because they won't be in scope when we do the desugaring+++************************************************************************+* *+ Most of the work for constructors is here+ (the rest is in the ConPatIn case of tc_pat)+* *+************************************************************************++[Pattern matching indexed data types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the following declarations:++ data family Map k :: * -> *+ data instance Map (a, b) v = MapPair (Map a (Pair b v))++and a case expression++ case x :: Map (Int, c) w of MapPair m -> ...++As explained by [Wrappers for data instance tycons] in MkIds.hs, the+worker/wrapper types for MapPair are++ $WMapPair :: forall a b v. Map a (Map a b v) -> Map (a, b) v+ $wMapPair :: forall a b v. Map a (Map a b v) -> :R123Map a b v++So, the type of the scrutinee is Map (Int, c) w, but the tycon of MapPair is+:R123Map, which means the straight use of boxySplitTyConApp would give a type+error. Hence, the smart wrapper function boxySplitTyConAppWithFamily calls+boxySplitTyConApp with the family tycon Map instead, which gives us the family+type list {(Int, c), w}. To get the correct split for :R123Map, we need to+unify the family type list {(Int, c), w} with the instance types {(a, b), v}+(provided by tyConFamInst_maybe together with the family tycon). This+unification yields the substitution [a -> Int, b -> c, v -> w], which gives us+the split arguments for the representation tycon :R123Map as {Int, c, w}++In other words, boxySplitTyConAppWithFamily implicitly takes the coercion++ Co123Map a b v :: {Map (a, b) v ~ :R123Map a b v}++moving between representation and family type into account. To produce type+correct Core, this coercion needs to be used to case the type of the scrutinee+from the family to the representation type. This is achieved by+unwrapFamInstScrutinee using a CoPat around the result pattern.++Now it might appear seem as if we could have used the previous GADT type+refinement infrastructure of refineAlt and friends instead of the explicit+unification and CoPat generation. However, that would be wrong. Why? The+whole point of GADT refinement is that the refinement is local to the case+alternative. In contrast, the substitution generated by the unification of+the family type list and instance types needs to be propagated to the outside.+Imagine that in the above example, the type of the scrutinee would have been+(Map x w), then we would have unified {x, w} with {(a, b), v}, yielding the+substitution [x -> (a, b), v -> w]. In contrast to GADT matching, the+instantiation of x with (a, b) must be global; ie, it must be valid in *all*+alternatives of the case expression, whereas in the GADT case it might vary+between alternatives.++RIP GADT refinement: refinements have been replaced by the use of explicit+equality constraints that are used in conjunction with implication constraints+to express the local scope of GADT refinements.+-}++-- Running example:+-- MkT :: forall a b c. (a~[b]) => b -> c -> T a+-- with scrutinee of type (T ty)++tcConPat :: PatEnv -> Located Name+ -> ExpSigmaType -- Type of the pattern+ -> HsConPatDetails Name -> TcM a+ -> TcM (Pat TcId, a)+tcConPat penv con_lname@(L _ con_name) pat_ty arg_pats thing_inside+ = do { con_like <- tcLookupConLike con_name+ ; case con_like of+ RealDataCon data_con -> tcDataConPat penv con_lname data_con+ pat_ty arg_pats thing_inside+ PatSynCon pat_syn -> tcPatSynPat penv con_lname pat_syn+ pat_ty arg_pats thing_inside+ }++tcDataConPat :: PatEnv -> Located Name -> DataCon+ -> ExpSigmaType -- Type of the pattern+ -> HsConPatDetails Name -> TcM a+ -> TcM (Pat TcId, a)+tcDataConPat penv (L con_span con_name) data_con pat_ty arg_pats thing_inside+ = do { let tycon = dataConTyCon data_con+ -- For data families this is the representation tycon+ (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _)+ = dataConFullSig data_con+ header = L con_span (RealDataCon data_con)++ -- Instantiate the constructor type variables [a->ty]+ -- This may involve doing a family-instance coercion,+ -- and building a wrapper+ ; (wrap, ctxt_res_tys) <- matchExpectedConTy penv tycon pat_ty+ ; pat_ty <- readExpType pat_ty++ -- Add the stupid theta+ ; setSrcSpan con_span $ addDataConStupidTheta data_con ctxt_res_tys++ ; let all_arg_tys = eqSpecPreds eq_spec ++ theta ++ arg_tys+ ; checkExistentials ex_tvs all_arg_tys penv+ ; (tenv, ex_tvs') <- tcInstSuperSkolTyVarsX+ (zipTvSubst univ_tvs ctxt_res_tys) ex_tvs+ -- Get location from monad, not from ex_tvs++ ; let -- pat_ty' = mkTyConApp tycon ctxt_res_tys+ -- pat_ty' is type of the actual constructor application+ -- pat_ty' /= pat_ty iff coi /= IdCo++ arg_tys' = substTys tenv arg_tys++ ; traceTc "tcConPat" (vcat [ ppr con_name+ , pprTyVars univ_tvs+ , pprTyVars ex_tvs+ , ppr eq_spec+ , ppr theta+ , pprTyVars ex_tvs'+ , ppr ctxt_res_tys+ , ppr arg_tys'+ , ppr arg_pats ])+ ; if null ex_tvs && null eq_spec && null theta+ then do { -- The common case; no class bindings etc+ -- (see Note [Arrows and patterns])+ (arg_pats', res) <- tcConArgs (RealDataCon data_con) arg_tys'+ arg_pats penv thing_inside+ ; let res_pat = ConPatOut { pat_con = header,+ pat_tvs = [], pat_dicts = [],+ pat_binds = emptyTcEvBinds,+ pat_args = arg_pats',+ pat_arg_tys = ctxt_res_tys,+ pat_wrap = idHsWrapper }++ ; return (mkHsWrapPat wrap res_pat pat_ty, res) }++ else do -- The general case, with existential,+ -- and local equality constraints+ { let theta' = substTheta tenv (eqSpecPreds eq_spec ++ theta)+ -- order is *important* as we generate the list of+ -- dictionary binders from theta'+ no_equalities = not (any isNomEqPred theta')+ skol_info = PatSkol (RealDataCon data_con) mc+ mc = case pe_ctxt penv of+ LamPat mc -> mc+ LetPat {} -> PatBindRhs++ ; gadts_on <- xoptM LangExt.GADTs+ ; families_on <- xoptM LangExt.TypeFamilies+ ; checkTc (no_equalities || gadts_on || families_on)+ (text "A pattern match on a GADT requires the" <+>+ text "GADTs or TypeFamilies language extension")+ -- Trac #2905 decided that a *pattern-match* of a GADT+ -- should require the GADT language flag.+ -- Re TypeFamilies see also #7156++ ; given <- newEvVars theta'+ ; (ev_binds, (arg_pats', res))+ <- checkConstraints skol_info ex_tvs' given $+ tcConArgs (RealDataCon data_con) arg_tys' arg_pats penv thing_inside++ ; let res_pat = ConPatOut { pat_con = header,+ pat_tvs = ex_tvs',+ pat_dicts = given,+ pat_binds = ev_binds,+ pat_args = arg_pats',+ pat_arg_tys = ctxt_res_tys,+ pat_wrap = idHsWrapper }+ ; return (mkHsWrapPat wrap res_pat pat_ty, res)+ } }++tcPatSynPat :: PatEnv -> Located Name -> PatSyn+ -> ExpSigmaType -- Type of the pattern+ -> HsConPatDetails Name -> TcM a+ -> TcM (Pat TcId, a)+tcPatSynPat penv (L con_span _) pat_syn pat_ty arg_pats thing_inside+ = do { let (univ_tvs, req_theta, ex_tvs, prov_theta, arg_tys, ty) = patSynSig pat_syn++ ; (subst, univ_tvs') <- newMetaTyVars univ_tvs++ ; let all_arg_tys = ty : prov_theta ++ arg_tys+ ; checkExistentials ex_tvs all_arg_tys penv+ ; (tenv, ex_tvs') <- tcInstSuperSkolTyVarsX subst ex_tvs+ ; let ty' = substTy tenv ty+ arg_tys' = substTys tenv arg_tys+ prov_theta' = substTheta tenv prov_theta+ req_theta' = substTheta tenv req_theta++ ; wrap <- tcSubTypePat penv pat_ty ty'+ ; traceTc "tcPatSynPat" (ppr pat_syn $$+ ppr pat_ty $$+ ppr ty' $$+ ppr ex_tvs' $$+ ppr prov_theta' $$+ ppr req_theta' $$+ ppr arg_tys')++ ; prov_dicts' <- newEvVars prov_theta'++ ; let skol_info = case pe_ctxt penv of+ LamPat mc -> PatSkol (PatSynCon pat_syn) mc+ LetPat {} -> UnkSkol -- Doesn't matter++ ; req_wrap <- instCall PatOrigin (mkTyVarTys univ_tvs') req_theta'+ ; traceTc "instCall" (ppr req_wrap)++ ; traceTc "checkConstraints {" Outputable.empty+ ; (ev_binds, (arg_pats', res))+ <- checkConstraints skol_info ex_tvs' prov_dicts' $+ tcConArgs (PatSynCon pat_syn) arg_tys' arg_pats penv thing_inside++ ; traceTc "checkConstraints }" (ppr ev_binds)+ ; let res_pat = ConPatOut { pat_con = L con_span $ PatSynCon pat_syn,+ pat_tvs = ex_tvs',+ pat_dicts = prov_dicts',+ pat_binds = ev_binds,+ pat_args = arg_pats',+ pat_arg_tys = mkTyVarTys univ_tvs',+ pat_wrap = req_wrap }+ ; pat_ty <- readExpType pat_ty+ ; return (mkHsWrapPat wrap res_pat pat_ty, res) }++----------------------------+-- | Convenient wrapper for calling a matchExpectedXXX function+matchExpectedPatTy :: (TcRhoType -> TcM (TcCoercionN, a))+ -> PatEnv -> ExpSigmaType -> TcM (HsWrapper, a)+-- See Note [Matching polytyped patterns]+-- Returns a wrapper : pat_ty ~R inner_ty+matchExpectedPatTy inner_match (PE { pe_orig = orig }) pat_ty+ = do { pat_ty <- expTypeToType pat_ty+ ; (wrap, pat_rho) <- topInstantiate orig pat_ty+ ; (co, res) <- inner_match pat_rho+ ; traceTc "matchExpectedPatTy" (ppr pat_ty $$ ppr wrap)+ ; return (mkWpCastN (mkTcSymCo co) <.> wrap, res) }++----------------------------+matchExpectedConTy :: PatEnv+ -> TyCon -- The TyCon that this data+ -- constructor actually returns+ -- In the case of a data family this is+ -- the /representation/ TyCon+ -> ExpSigmaType -- The type of the pattern; in the case+ -- of a data family this would mention+ -- the /family/ TyCon+ -> TcM (HsWrapper, [TcSigmaType])+-- See Note [Matching constructor patterns]+-- Returns a wrapper : pat_ty "->" T ty1 ... tyn+matchExpectedConTy (PE { pe_orig = orig }) data_tc exp_pat_ty+ | Just (fam_tc, fam_args, co_tc) <- tyConFamInstSig_maybe data_tc+ -- Comments refer to Note [Matching constructor patterns]+ -- co_tc :: forall a. T [a] ~ T7 a+ = do { pat_ty <- expTypeToType exp_pat_ty+ ; (wrap, pat_rho) <- topInstantiate orig pat_ty++ ; (subst, tvs') <- newMetaTyVars (tyConTyVars data_tc)+ -- tys = [ty1,ty2]++ ; traceTc "matchExpectedConTy" (vcat [ppr data_tc,+ ppr (tyConTyVars data_tc),+ ppr fam_tc, ppr fam_args,+ ppr exp_pat_ty,+ ppr pat_ty,+ ppr pat_rho, ppr wrap])+ ; co1 <- unifyType noThing (mkTyConApp fam_tc (substTys subst fam_args)) pat_rho+ -- co1 : T (ty1,ty2) ~N pat_rho+ -- could use tcSubType here... but it's the wrong way round+ -- for actual vs. expected in error messages.++ ; let tys' = mkTyVarTys tvs'+ co2 = mkTcUnbranchedAxInstCo co_tc tys' []+ -- co2 : T (ty1,ty2) ~R T7 ty1 ty2++ full_co = mkTcSubCo (mkTcSymCo co1) `mkTcTransCo` co2+ -- full_co :: pat_rho ~R T7 ty1 ty2++ ; return ( mkWpCastR full_co <.> wrap, tys') }++ | otherwise+ = do { pat_ty <- expTypeToType exp_pat_ty+ ; (wrap, pat_rho) <- topInstantiate orig pat_ty+ ; (coi, tys) <- matchExpectedTyConApp data_tc pat_rho+ ; return (mkWpCastN (mkTcSymCo coi) <.> wrap, tys) }++{-+Note [Matching constructor patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose (coi, tys) = matchExpectedConType data_tc pat_ty++ * In the simple case, pat_ty = tc tys++ * If pat_ty is a polytype, we want to instantiate it+ This is like part of a subsumption check. Eg+ f :: (forall a. [a]) -> blah+ f [] = blah++ * In a type family case, suppose we have+ data family T a+ data instance T (p,q) = A p | B q+ Then we'll have internally generated+ data T7 p q = A p | B q+ axiom coT7 p q :: T (p,q) ~ T7 p q++ So if pat_ty = T (ty1,ty2), we return (coi, [ty1,ty2]) such that+ coi = coi2 . coi1 : T7 t ~ pat_ty+ coi1 : T (ty1,ty2) ~ pat_ty+ coi2 : T7 ty1 ty2 ~ T (ty1,ty2)++ For families we do all this matching here, not in the unifier,+ because we never want a whisper of the data_tycon to appear in+ error messages; it's a purely internal thing+-}++tcConArgs :: ConLike -> [TcSigmaType]+ -> Checker (HsConPatDetails Name) (HsConPatDetails Id)++tcConArgs con_like arg_tys (PrefixCon arg_pats) penv thing_inside+ = do { checkTc (con_arity == no_of_args) -- Check correct arity+ (arityErr "constructor" con_like con_arity no_of_args)+ ; let pats_w_tys = zipEqual "tcConArgs" arg_pats arg_tys+ ; (arg_pats', res) <- tcMultiple tcConArg pats_w_tys+ penv thing_inside+ ; return (PrefixCon arg_pats', res) }+ where+ con_arity = conLikeArity con_like+ no_of_args = length arg_pats++tcConArgs con_like arg_tys (InfixCon p1 p2) penv thing_inside+ = do { checkTc (con_arity == 2) -- Check correct arity+ (arityErr "constructor" con_like con_arity 2)+ ; let [arg_ty1,arg_ty2] = arg_tys -- This can't fail after the arity check+ ; ([p1',p2'], res) <- tcMultiple tcConArg [(p1,arg_ty1),(p2,arg_ty2)]+ penv thing_inside+ ; return (InfixCon p1' p2', res) }+ where+ con_arity = conLikeArity con_like++tcConArgs con_like arg_tys (RecCon (HsRecFields rpats dd)) penv thing_inside+ = do { (rpats', res) <- tcMultiple tc_field rpats penv thing_inside+ ; return (RecCon (HsRecFields rpats' dd), res) }+ where+ tc_field :: Checker (LHsRecField Name (LPat Name))+ (LHsRecField TcId (LPat TcId))+ tc_field (L l (HsRecField (L loc (FieldOcc (L lr rdr) sel)) pat pun)) penv+ thing_inside+ = do { sel' <- tcLookupId sel+ ; pat_ty <- setSrcSpan loc $ find_field_ty (occNameFS $ rdrNameOcc rdr)+ ; (pat', res) <- tcConArg (pat, pat_ty) penv thing_inside+ ; return (L l (HsRecField (L loc (FieldOcc (L lr rdr) sel')) pat'+ pun), res) }++ find_field_ty :: FieldLabelString -> TcM TcType+ find_field_ty lbl+ = case [ty | (fl, ty) <- field_tys, flLabel fl == lbl] of++ -- No matching field; chances are this field label comes from some+ -- other record type (or maybe none). If this happens, just fail,+ -- otherwise we get crashes later (Trac #8570), and similar:+ -- f (R { foo = (a,b) }) = a+b+ -- If foo isn't one of R's fields, we don't want to crash when+ -- typechecking the "a+b".+ [] -> failWith (badFieldCon con_like lbl)++ -- The normal case, when the field comes from the right constructor+ (pat_ty : extras) -> do+ traceTc "find_field" (ppr pat_ty <+> ppr extras)+ ASSERT( null extras ) (return pat_ty)++ field_tys :: [(FieldLabel, TcType)]+ field_tys = zip (conLikeFieldLabels con_like) arg_tys+ -- Don't use zipEqual! If the constructor isn't really a record, then+ -- dataConFieldLabels will be empty (and each field in the pattern+ -- will generate an error below).++tcConArg :: Checker (LPat Name, TcSigmaType) (LPat Id)+tcConArg (arg_pat, arg_ty) penv thing_inside+ = tc_lpat arg_pat (mkCheckExpType arg_ty) penv thing_inside++addDataConStupidTheta :: DataCon -> [TcType] -> TcM ()+-- Instantiate the "stupid theta" of the data con, and throw+-- the constraints into the constraint set+addDataConStupidTheta data_con inst_tys+ | null stupid_theta = return ()+ | otherwise = instStupidTheta origin inst_theta+ where+ origin = OccurrenceOf (dataConName data_con)+ -- The origin should always report "occurrence of C"+ -- even when C occurs in a pattern+ stupid_theta = dataConStupidTheta data_con+ univ_tvs = dataConUnivTyVars data_con+ tenv = zipTvSubst univ_tvs (takeList univ_tvs inst_tys)+ -- NB: inst_tys can be longer than the univ tyvars+ -- because the constructor might have existentials+ inst_theta = substTheta tenv stupid_theta++{-+Note [Arrows and patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~+(Oct 07) Arrow notation has the odd property that it involves+"holes in the scope". For example:+ expr :: Arrow a => a () Int+ expr = proc (y,z) -> do+ x <- term -< y+ expr' -< x++Here the 'proc (y,z)' binding scopes over the arrow tails but not the+arrow body (e.g 'term'). As things stand (bogusly) all the+constraints from the proc body are gathered together, so constraints+from 'term' will be seen by the tcPat for (y,z). But we must *not*+bind constraints from 'term' here, because the desugarer will not make+these bindings scope over 'term'.++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.++************************************************************************+* *+ Note [Pattern coercions]+* *+************************************************************************++In principle, these program would be reasonable:++ f :: (forall a. a->a) -> Int+ f (x :: Int->Int) = x 3++ g :: (forall a. [a]) -> Bool+ g [] = True++In both cases, the function type signature restricts what arguments can be passed+in a call (to polymorphic ones). The pattern type signature then instantiates this+type. For example, in the first case, (forall a. a->a) <= Int -> Int, and we+generate the translated term+ f = \x' :: (forall a. a->a). let x = x' Int in x 3++From a type-system point of view, this is perfectly fine, but it's *very* seldom useful.+And it requires a significant amount of code to implement, because we need to decorate+the translated pattern with coercion functions (generated from the subsumption check+by tcSub).++So for now I'm just insisting on type *equality* in patterns. No subsumption.++Old notes about desugaring, at a time when pattern coercions were handled:++A SigPat is a type coercion and must be handled one at at time. We can't+combine them unless the type of the pattern inside is identical, and we don't+bother to check for that. For example:++ data T = T1 Int | T2 Bool+ f :: (forall a. a -> a) -> T -> t+ f (g::Int->Int) (T1 i) = T1 (g i)+ f (g::Bool->Bool) (T2 b) = T2 (g b)++We desugar this as follows:++ f = \ g::(forall a. a->a) t::T ->+ let gi = g Int+ in case t of { T1 i -> T1 (gi i)+ other ->+ let gb = g Bool+ in case t of { T2 b -> T2 (gb b)+ other -> fail }}++Note that we do not treat the first column of patterns as a+column of variables, because the coerced variables (gi, gb)+would be of different types. So we get rather grotty code.+But I don't think this is a common case, and if it was we could+doubtless improve it.++Meanwhile, the strategy is:+ * treat each SigPat coercion (always non-identity coercions)+ as a separate block+ * deal with the stuff inside, and then wrap a binding round+ the result to bind the new variable (gi, gb, etc)+++************************************************************************+* *+\subsection{Errors and contexts}+* *+************************************************************************++Note [Existential check]+~~~~~~~~~~~~~~~~~~~~~~~~+Lazy patterns can't bind existentials. They arise in two ways:+ * Let bindings let { C a b = e } in b+ * Twiddle patterns f ~(C a b) = e+The pe_lazy field of PatEnv says whether we are inside a lazy+pattern (perhaps deeply)++See also Note [Typechecking pattern bindings] in TcBinds+-}++maybeWrapPatCtxt :: Pat Name -> (TcM a -> TcM b) -> TcM a -> TcM b+-- Not all patterns are worth pushing a context+maybeWrapPatCtxt pat tcm thing_inside+ | not (worth_wrapping pat) = tcm thing_inside+ | otherwise = addErrCtxt msg $ tcm $ popErrCtxt thing_inside+ -- Remember to pop before doing thing_inside+ where+ worth_wrapping (VarPat {}) = False+ worth_wrapping (ParPat {}) = False+ worth_wrapping (AsPat {}) = False+ worth_wrapping _ = True+ 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 :: SDoc+existentialLazyPat+ = hang (text "An existential or GADT data constructor cannot be used")+ 2 (text "inside a lazy (~) pattern")++existentialProcPat :: SDoc+existentialProcPat+ = text "Proc patterns cannot use existential or GADT data constructors"++badFieldCon :: ConLike -> FieldLabelString -> SDoc+badFieldCon con field+ = hsep [text "Constructor" <+> quotes (ppr con),+ text "does not have field", quotes (ppr field)]++polyPatSig :: TcType -> SDoc+polyPatSig sig_ty+ = hang (text "Illegal polymorphic type signature in pattern:")+ 2 (ppr sig_ty)
+ typecheck/TcPatSyn.hs view
@@ -0,0 +1,849 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[TcPatSyn]{Typechecking pattern synonym declarations}+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}++module TcPatSyn ( tcInferPatSynDecl, tcCheckPatSynDecl+ , tcPatSynBuilderBind, tcPatSynBuilderOcc, nonBidirectionalErr+ ) where++import HsSyn+import TcPat+import Type( mkTyVarBinders, mkEmptyTCvSubst+ , tidyTyVarBinders, tidyTypes, tidyType )+import TcRnMonad+import TcSigs( emptyPragEnv, completeSigFromId )+import TcEnv+import TcMType+import TcHsSyn( zonkTyVarBindersX, zonkTcTypeToTypes+ , zonkTcTypeToType, emptyZonkEnv )+import TysPrim+import TysWiredIn ( runtimeRepTy )+import Name+import SrcLoc+import PatSyn+import NameSet+import Panic+import Outputable+import FastString+import Var+import VarEnv( emptyTidyEnv, mkInScopeSet )+import Id+import IdInfo( RecSelParent(..), setLevityInfoWithType )+import TcBinds+import BasicTypes+import TcSimplify+import TcUnify+import TcType+import TcEvidence+import BuildTyCl+import VarSet+import MkId+import TcTyDecls+import ConLike+import FieldLabel+import Bag+import Util+import ErrUtils+import Control.Monad ( zipWithM )+import Data.List( partition )++#include "HsVersions.h"++{-+************************************************************************+* *+ Type checking a pattern synonym+* *+************************************************************************+-}++tcInferPatSynDecl :: PatSynBind Name Name+ -> TcM (LHsBinds Id, TcGblEnv)+tcInferPatSynDecl PSB{ psb_id = lname@(L _ name), psb_args = details,+ psb_def = lpat, psb_dir = dir }+ = addPatSynCtxt lname $+ do { traceTc "tcInferPatSynDecl {" $ ppr name+ ; tcCheckPatSynPat lpat++ ; let (arg_names, rec_fields, is_infix) = collectPatSynArgInfo details+ ; (tclvl, wanted, ((lpat', args), pat_ty))+ <- pushLevelAndCaptureConstraints $+ tcInferNoInst $ \ exp_ty ->+ tcPat PatSyn lpat exp_ty $+ mapM tcLookupId arg_names++ ; let named_taus = (name, pat_ty) : map (\arg -> (getName arg, varType arg)) args++ ; (qtvs, req_dicts, ev_binds) <- simplifyInfer tclvl NoRestrictions []+ named_taus wanted++ ; let (ex_tvs, prov_dicts) = tcCollectEx lpat'+ ex_tv_set = mkVarSet ex_tvs+ univ_tvs = filterOut (`elemVarSet` ex_tv_set) qtvs+ prov_theta = map evVarPred prov_dicts+ req_theta = map evVarPred req_dicts++ ; traceTc "tcInferPatSynDecl }" $ (ppr name $$ ppr ex_tvs)+ ; tc_patsyn_finish lname dir is_infix lpat'+ (mkTyVarBinders Inferred univ_tvs+ , req_theta, ev_binds, req_dicts)+ (mkTyVarBinders Inferred ex_tvs+ , mkTyVarTys ex_tvs, prov_theta, map EvId prov_dicts)+ (map nlHsVar args, map idType args)+ pat_ty rec_fields }+++tcCheckPatSynDecl :: PatSynBind Name Name+ -> TcPatSynInfo+ -> TcM (LHsBinds Id, TcGblEnv)+tcCheckPatSynDecl psb@PSB{ psb_id = lname@(L _ name), psb_args = details+ , psb_def = lpat, psb_dir = dir }+ TPSI{ patsig_implicit_bndrs = implicit_tvs+ , patsig_univ_bndrs = explicit_univ_tvs, patsig_prov = prov_theta+ , patsig_ex_bndrs = explicit_ex_tvs, patsig_req = req_theta+ , patsig_body_ty = sig_body_ty }+ = addPatSynCtxt lname $+ do { let decl_arity = length arg_names+ (arg_names, rec_fields, is_infix) = collectPatSynArgInfo details++ ; traceTc "tcCheckPatSynDecl" $+ vcat [ ppr implicit_tvs, ppr explicit_univ_tvs, ppr req_theta+ , ppr explicit_ex_tvs, ppr prov_theta, ppr sig_body_ty ]++ ; tcCheckPatSynPat lpat++ ; (arg_tys, pat_ty) <- case tcSplitFunTysN decl_arity sig_body_ty of+ Right stuff -> return stuff+ Left missing -> wrongNumberOfParmsErr name decl_arity missing++ -- Complain about: pattern P :: () => forall x. x -> P x+ -- The existential 'x' should not appear in the result type+ -- Can't check this until we know P's arity+ ; let bad_tvs = filter (`elemVarSet` tyCoVarsOfType pat_ty) explicit_ex_tvs+ ; checkTc (null bad_tvs) $+ hang (sep [ text "The result type of the signature for" <+> quotes (ppr name) <> comma+ , text "namely" <+> quotes (ppr pat_ty) ])+ 2 (text "mentions existential type variable" <> plural bad_tvs+ <+> pprQuotedList bad_tvs)++ -- See Note [The pattern-synonym signature splitting rule]+ ; let univ_fvs = closeOverKinds $+ (tyCoVarsOfTypes (pat_ty : req_theta) `extendVarSetList` explicit_univ_tvs)+ (extra_univ, extra_ex) = partition ((`elemVarSet` univ_fvs) . binderVar) implicit_tvs+ univ_bndrs = extra_univ ++ mkTyVarBinders Specified explicit_univ_tvs+ ex_bndrs = extra_ex ++ mkTyVarBinders Specified explicit_ex_tvs+ univ_tvs = binderVars univ_bndrs+ ex_tvs = binderVars ex_bndrs++ -- Right! Let's check the pattern against the signature+ -- See Note [Checking against a pattern signature]+ ; req_dicts <- newEvVars req_theta+ ; (tclvl, wanted, (lpat', (ex_tvs', prov_dicts, args'))) <-+ ASSERT2( equalLength arg_names arg_tys, ppr name $$ ppr arg_names $$ ppr arg_tys )+ pushLevelAndCaptureConstraints $+ tcExtendTyVarEnv univ_tvs $+ tcPat PatSyn lpat (mkCheckExpType pat_ty) $+ do { let in_scope = mkInScopeSet (mkVarSet univ_tvs)+ empty_subst = mkEmptyTCvSubst in_scope+ ; (subst, ex_tvs') <- mapAccumLM newMetaTyVarX empty_subst ex_tvs+ -- newMetaTyVarX: see the "Existential type variables"+ -- part of Note [Checking against a pattern signature]+ ; traceTc "tcpatsyn1" (vcat [ ppr v <+> dcolon <+> ppr (tyVarKind v) | v <- ex_tvs])+ ; traceTc "tcpatsyn2" (vcat [ ppr v <+> dcolon <+> ppr (tyVarKind v) | v <- ex_tvs'])+ ; let prov_theta' = substTheta subst prov_theta+ -- Add univ_tvs to the in_scope set to+ -- satisfy the substitution invariant. There's no need to+ -- add 'ex_tvs' as they are already in the domain of the+ -- substitution.+ -- See also Note [The substitution invariant] in TyCoRep.+ ; prov_dicts <- mapM (emitWanted (ProvCtxtOrigin psb)) prov_theta'+ ; args' <- zipWithM (tc_arg subst) arg_names arg_tys+ ; return (ex_tvs', prov_dicts, args') }++ ; let skol_info = SigSkol (PatSynCtxt name) pat_ty []+ -- The type here is a bit bogus, but we do not print+ -- the type for PatSynCtxt, so it doesn't matter+ -- See TcRnTypes Note [Skolem info for pattern synonyms]+ ; (implics, ev_binds) <- buildImplicationFor tclvl skol_info univ_tvs req_dicts wanted++ -- Solve the constraints now, because we are about to make a PatSyn,+ -- which should not contain unification variables and the like (Trac #10997)+ ; simplifyTopImplic implics++ -- ToDo: in the bidirectional case, check that the ex_tvs' are all distinct+ -- Otherwise we may get a type error when typechecking the builder,+ -- when that should be impossible++ ; traceTc "tcCheckPatSynDecl }" $ ppr name+ ; tc_patsyn_finish lname dir is_infix lpat'+ (univ_bndrs, req_theta, ev_binds, req_dicts)+ (ex_bndrs, mkTyVarTys ex_tvs', prov_theta, prov_dicts)+ (args', arg_tys)+ pat_ty rec_fields }+ where+ tc_arg :: TCvSubst -> Name -> Type -> TcM (LHsExpr TcId)+ tc_arg subst arg_name arg_ty+ = do { -- Look up the variable actually bound by lpat+ -- and check that it has the expected type+ arg_id <- tcLookupId arg_name+ ; coi <- unifyType (Just arg_id)+ (idType arg_id)+ (substTyUnchecked subst arg_ty)+ ; return (mkLHsWrapCo coi $ nlHsVar arg_id) }++{- Note [Checking against a pattern signature]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When checking the actual supplied pattern against the pattern synonym+signature, we need to be quite careful.++----- Provided constraints+Example++ data T a where+ MkT :: Ord a => a -> T a++ pattern P :: () => Eq a => a -> [T a]+ pattern P x = [MkT x]++We must check that the (Eq a) that P claims to bind (and to+make available to matches against P), is derivable from the+actual pattern. For example:+ f (P (x::a)) = ...here (Eq a) should be available...+And yes, (Eq a) is derivable from the (Ord a) bound by P's rhs.++----- Existential type variables+Unusually, we instantiate the existential tyvars of the pattern with+*meta* type variables. For example++ data S where+ MkS :: Eq a => [a] -> S++ pattern P :: () => Eq x => x -> S+ pattern P x <- MkS x++The pattern synonym conceals from its client the fact that MkS has a+list inside it. The client just thinks it's a type 'x'. So we must+unify x := [a] during type checking, and then use the instantiating type+[a] (called ex_tys) when building the matcher. In this case we'll get++ $mP :: S -> (forall x. Ex x => x -> r) -> r -> r+ $mP x k = case x of+ MkS a (d:Eq a) (ys:[a]) -> let dl :: Eq [a]+ dl = $dfunEqList d+ in k [a] dl ys++All this applies when type-checking the /matching/ side of+a pattern synonym. What about the /building/ side?++* For Unidirectional, there is no builder++* For ExplicitBidirectional, the builder is completely separate+ code, typechecked in tcPatSynBuilderBind++* For ImplicitBidirectional, the builder is still typechecked in+ tcPatSynBuilderBind, by converting the pattern to an expression and+ typechecking it.++ At one point, for ImplicitBidirectional I used SigTvs (instead of+ TauTvs) in tcCheckPatSynDecl. But (a) strengthening the check here+ is redundant since tcPatSynBuilderBind does the job, (b) it was+ still incomplete (SigTvs can unify with each other), and (c) it+ didn't even work (Trac #13441 was accepted with+ ExplicitBidirectional, but rejected if expressed in+ ImplicitBidirectional form. Conclusion: trying to be too clever is+ a bad idea.+-}++collectPatSynArgInfo :: HsPatSynDetails (Located Name) -> ([Name], [Name], Bool)+collectPatSynArgInfo details =+ case details of+ PrefixPatSyn names -> (map unLoc names, [], False)+ InfixPatSyn name1 name2 -> (map unLoc [name1, name2], [], True)+ RecordPatSyn names ->+ let (vars, sels) = unzip (map splitRecordPatSyn names)+ in (vars, sels, False)++ where+ splitRecordPatSyn :: RecordPatSynField (Located Name) -> (Name, Name)+ splitRecordPatSyn (RecordPatSynField { recordPatSynPatVar = L _ patVar+ , recordPatSynSelectorId = L _ selId })+ = (patVar, selId)++addPatSynCtxt :: Located Name -> TcM a -> TcM a+addPatSynCtxt (L loc name) thing_inside+ = setSrcSpan loc $+ addErrCtxt (text "In the declaration for pattern synonym"+ <+> quotes (ppr name)) $+ thing_inside++wrongNumberOfParmsErr :: Name -> Arity -> Arity -> TcM a+wrongNumberOfParmsErr name decl_arity missing+ = failWithTc $+ hang (text "Pattern synonym" <+> quotes (ppr name) <+> ptext (sLit "has")+ <+> speakNOf decl_arity (text "argument"))+ 2 (text "but its type signature has" <+> int missing <+> text "fewer arrows")++-------------------------+-- Shared by both tcInferPatSyn and tcCheckPatSyn+tc_patsyn_finish :: Located Name -- ^ PatSyn Name+ -> HsPatSynDir Name -- ^ PatSyn type (Uni/Bidir/ExplicitBidir)+ -> Bool -- ^ Whether infix+ -> LPat Id -- ^ Pattern of the PatSyn+ -> ([TcTyVarBinder], [PredType], TcEvBinds, [EvVar])+ -> ([TcTyVarBinder], [TcType], [PredType], [EvTerm])+ -> ([LHsExpr TcId], [TcType]) -- ^ Pattern arguments and types+ -> TcType -- ^ Pattern type+ -> [Name] -- ^ Selector names+ -- ^ Whether fields, empty if not record PatSyn+ -> TcM (LHsBinds Id, TcGblEnv)+tc_patsyn_finish lname dir is_infix lpat'+ (univ_tvs, req_theta, req_ev_binds, req_dicts)+ (ex_tvs, ex_tys, prov_theta, prov_dicts)+ (args, arg_tys)+ pat_ty field_labels+ = do { -- Zonk everything. We are about to build a final PatSyn+ -- so there had better be no unification variables in there++ (ze, univ_tvs') <- zonkTyVarBindersX emptyZonkEnv univ_tvs+ ; req_theta' <- zonkTcTypeToTypes ze req_theta+ ; (ze, ex_tvs') <- zonkTyVarBindersX ze ex_tvs+ ; prov_theta' <- zonkTcTypeToTypes ze prov_theta+ ; pat_ty' <- zonkTcTypeToType ze pat_ty+ ; arg_tys' <- zonkTcTypeToTypes ze arg_tys++ ; let (env1, univ_tvs) = tidyTyVarBinders emptyTidyEnv univ_tvs'+ (env2, ex_tvs) = tidyTyVarBinders env1 ex_tvs'+ req_theta = tidyTypes env2 req_theta'+ prov_theta = tidyTypes env2 prov_theta'+ arg_tys = tidyTypes env2 arg_tys'+ pat_ty = tidyType env2 pat_ty'++ ; traceTc "tc_patsyn_finish {" $+ ppr (unLoc lname) $$ ppr (unLoc lpat') $$+ ppr (univ_tvs, req_theta, req_ev_binds, req_dicts) $$+ ppr (ex_tvs, prov_theta, prov_dicts) $$+ ppr args $$+ ppr arg_tys $$+ ppr pat_ty++ -- Make the 'matcher'+ ; (matcher_id, matcher_bind) <- tcPatSynMatcher lname lpat'+ (binderVars univ_tvs, req_theta, req_ev_binds, req_dicts)+ (binderVars ex_tvs, ex_tys, prov_theta, prov_dicts)+ (args, arg_tys)+ pat_ty++ -- Make the 'builder'+ ; builder_id <- mkPatSynBuilderId dir lname+ univ_tvs req_theta+ ex_tvs prov_theta+ arg_tys pat_ty++ -- TODO: Make this have the proper information+ ; let mkFieldLabel name = FieldLabel { flLabel = occNameFS (nameOccName name)+ , flIsOverloaded = False+ , flSelector = name }+ field_labels' = map mkFieldLabel field_labels+++ -- Make the PatSyn itself+ ; let patSyn = mkPatSyn (unLoc lname) is_infix+ (univ_tvs, req_theta)+ (ex_tvs, prov_theta)+ arg_tys+ pat_ty+ matcher_id builder_id+ field_labels'++ -- Selectors+ ; let rn_rec_sel_binds = mkPatSynRecSelBinds patSyn (patSynFieldLabels patSyn)+ tything = AConLike (PatSynCon patSyn)+ ; tcg_env <- tcExtendGlobalEnv [tything] $+ tcRecSelBinds rn_rec_sel_binds++ ; traceTc "tc_patsyn_finish }" empty+ ; return (matcher_bind, tcg_env) }++{-+************************************************************************+* *+ Constructing the "matcher" Id and its binding+* *+************************************************************************+-}++tcPatSynMatcher :: Located Name+ -> LPat Id+ -> ([TcTyVar], ThetaType, TcEvBinds, [EvVar])+ -> ([TcTyVar], [TcType], ThetaType, [EvTerm])+ -> ([LHsExpr TcId], [TcType])+ -> TcType+ -> TcM ((Id, Bool), LHsBinds Id)+-- See Note [Matchers and builders for pattern synonyms] in PatSyn+tcPatSynMatcher (L loc name) lpat+ (univ_tvs, req_theta, req_ev_binds, req_dicts)+ (ex_tvs, ex_tys, prov_theta, prov_dicts)+ (args, arg_tys) pat_ty+ = do { rr_name <- newNameAt (mkTyVarOcc "rep") loc+ ; tv_name <- newNameAt (mkTyVarOcc "r") loc+ ; let rr_tv = mkTcTyVar rr_name runtimeRepTy vanillaSkolemTv+ rr = mkTyVarTy rr_tv+ res_tv = mkTcTyVar tv_name (tYPE rr) vanillaSkolemTv+ res_ty = mkTyVarTy res_tv+ is_unlifted = null args && null prov_dicts+ (cont_args, cont_arg_tys)+ | is_unlifted = ([nlHsVar voidPrimId], [voidPrimTy])+ | otherwise = (args, arg_tys)+ cont_ty = mkInfSigmaTy ex_tvs prov_theta $+ mkFunTys cont_arg_tys res_ty++ fail_ty = mkFunTy voidPrimTy res_ty++ ; matcher_name <- newImplicitBinder name mkMatcherOcc+ ; scrutinee <- newSysLocalId (fsLit "scrut") pat_ty+ ; cont <- newSysLocalId (fsLit "cont") cont_ty+ ; fail <- newSysLocalId (fsLit "fail") fail_ty++ ; let matcher_tau = mkFunTys [pat_ty, cont_ty, fail_ty] res_ty+ matcher_sigma = mkInfSigmaTy (rr_tv:res_tv:univ_tvs) req_theta matcher_tau+ matcher_id = mkExportedVanillaId matcher_name matcher_sigma+ -- See Note [Exported LocalIds] in Id++ inst_wrap = mkWpEvApps prov_dicts <.> mkWpTyApps ex_tys+ cont' = foldl nlHsApp (mkLHsWrap inst_wrap (nlHsVar cont)) cont_args++ fail' = nlHsApps fail [nlHsVar voidPrimId]++ args = map nlVarPat [scrutinee, cont, fail]+ lwpat = noLoc $ WildPat pat_ty+ cases = if isIrrefutableHsPat lpat+ then [mkHsCaseAlt lpat cont']+ else [mkHsCaseAlt lpat cont',+ mkHsCaseAlt lwpat fail']+ body = mkLHsWrap (mkWpLet req_ev_binds) $+ L (getLoc lpat) $+ HsCase (nlHsVar scrutinee) $+ MG{ mg_alts = L (getLoc lpat) cases+ , mg_arg_tys = [pat_ty]+ , mg_res_ty = res_ty+ , mg_origin = Generated+ }+ body' = noLoc $+ HsLam $+ MG{ mg_alts = noLoc [mkSimpleMatch LambdaExpr+ args body]+ , mg_arg_tys = [pat_ty, cont_ty, fail_ty]+ , mg_res_ty = res_ty+ , mg_origin = Generated+ }+ match = mkMatch (mkPrefixFunRhs (L loc name)) []+ (mkHsLams (rr_tv:res_tv:univ_tvs)+ req_dicts body')+ (noLoc EmptyLocalBinds)+ mg = MG{ mg_alts = L (getLoc match) [match]+ , mg_arg_tys = []+ , mg_res_ty = res_ty+ , mg_origin = Generated+ }++ ; let bind = FunBind{ fun_id = L loc matcher_id+ , fun_matches = mg+ , fun_co_fn = idHsWrapper+ , bind_fvs = emptyNameSet+ , fun_tick = [] }+ matcher_bind = unitBag (noLoc bind)++ ; traceTc "tcPatSynMatcher" (ppr name $$ ppr (idType matcher_id))+ ; traceTc "tcPatSynMatcher" (ppr matcher_bind)++ ; return ((matcher_id, is_unlifted), matcher_bind) }++mkPatSynRecSelBinds :: PatSyn+ -> [FieldLabel] -- ^ Visible field labels+ -> HsValBinds Name+mkPatSynRecSelBinds ps fields+ = ValBindsOut selector_binds sigs+ where+ (sigs, selector_binds) = unzip (map mkRecSel fields)+ mkRecSel fld_lbl = mkOneRecordSelector [PatSynCon ps] (RecSelPatSyn ps) fld_lbl++isUnidirectional :: HsPatSynDir a -> Bool+isUnidirectional Unidirectional = True+isUnidirectional ImplicitBidirectional = False+isUnidirectional ExplicitBidirectional{} = False++{-+************************************************************************+* *+ Constructing the "builder" Id+* *+************************************************************************+-}++mkPatSynBuilderId :: HsPatSynDir a -> Located Name+ -> [TyVarBinder] -> ThetaType+ -> [TyVarBinder] -> ThetaType+ -> [Type] -> Type+ -> TcM (Maybe (Id, Bool))+mkPatSynBuilderId dir (L _ name)+ univ_bndrs req_theta ex_bndrs prov_theta+ arg_tys pat_ty+ | isUnidirectional dir+ = return Nothing+ | otherwise+ = do { builder_name <- newImplicitBinder name mkBuilderOcc+ ; let theta = req_theta ++ prov_theta+ need_dummy_arg = isUnliftedType pat_ty && null arg_tys && null theta+ builder_sigma = add_void need_dummy_arg $+ mkForAllTys univ_bndrs $+ mkForAllTys ex_bndrs $+ mkFunTys theta $+ mkFunTys arg_tys $+ pat_ty+ builder_id = mkExportedVanillaId builder_name builder_sigma+ -- See Note [Exported LocalIds] in Id++ builder_id' = modifyIdInfo (`setLevityInfoWithType` pat_ty) builder_id++ ; return (Just (builder_id', need_dummy_arg)) }+ where++tcPatSynBuilderBind :: PatSynBind Name Name+ -> TcM (LHsBinds Id)+-- See Note [Matchers and builders for pattern synonyms] in PatSyn+tcPatSynBuilderBind (PSB { psb_id = L loc name, psb_def = lpat+ , psb_dir = dir, psb_args = details })+ | isUnidirectional dir+ = return emptyBag++ | Left why <- mb_match_group -- Can't invert the pattern+ = setSrcSpan (getLoc lpat) $ failWithTc $+ vcat [ hang (text "Invalid right-hand side of bidirectional pattern synonym"+ <+> quotes (ppr name) <> colon)+ 2 why+ , text "RHS pattern:" <+> ppr lpat ]++ | Right match_group <- mb_match_group -- Bidirectional+ = do { patsyn <- tcLookupPatSyn name+ ; let Just (builder_id, need_dummy_arg) = patSynBuilder patsyn+ -- Bidirectional, so patSynBuilder returns Just++ match_group' | need_dummy_arg = add_dummy_arg match_group+ | otherwise = match_group++ bind = FunBind { fun_id = L loc (idName builder_id)+ , fun_matches = match_group'+ , fun_co_fn = idHsWrapper+ , bind_fvs = placeHolderNamesTc+ , fun_tick = [] }++ sig = completeSigFromId (PatSynCtxt name) builder_id++ ; traceTc "tcPatSynBuilderBind {" $+ ppr patsyn $$ ppr builder_id <+> dcolon <+> ppr (idType builder_id)+ ; (builder_binds, _) <- tcPolyCheck emptyPragEnv sig (noLoc bind)+ ; traceTc "tcPatSynBuilderBind }" $ ppr builder_binds+ ; return builder_binds }++ | otherwise = panic "tcPatSynBuilderBind" -- Both cases dealt with+ where+ mb_match_group+ = case dir of+ ExplicitBidirectional explicit_mg -> Right explicit_mg+ ImplicitBidirectional -> fmap mk_mg (tcPatToExpr args lpat)+ Unidirectional -> panic "tcPatSynBuilderBind"++ mk_mg :: LHsExpr Name -> MatchGroup Name (LHsExpr Name)+ mk_mg body = mkMatchGroup Generated [builder_match]+ where+ builder_args = [L loc (VarPat (L loc n)) | L loc n <- args]+ builder_match = mkMatch (mkPrefixFunRhs (L loc name))+ builder_args body+ (noLoc EmptyLocalBinds)++ args = case details of+ PrefixPatSyn args -> args+ InfixPatSyn arg1 arg2 -> [arg1, arg2]+ RecordPatSyn args -> map recordPatSynPatVar args++ add_dummy_arg :: MatchGroup Name (LHsExpr Name)+ -> MatchGroup Name (LHsExpr Name)+ add_dummy_arg mg@(MG { mg_alts = L l [L loc match@(Match { m_pats = pats })] })+ = mg { mg_alts = L l [L loc (match { m_pats = nlWildPatName : pats })] }+ add_dummy_arg other_mg = pprPanic "add_dummy_arg" $+ pprMatches other_mg++tcPatSynBuilderOcc :: PatSyn -> TcM (HsExpr TcId, TcSigmaType)+-- monadic only for failure+tcPatSynBuilderOcc ps+ | Just (builder_id, add_void_arg) <- builder+ , let builder_expr = HsConLikeOut (PatSynCon ps)+ builder_ty = idType builder_id+ = return $+ if add_void_arg+ then ( builder_expr -- still just return builder_expr; the void# arg is added+ -- by dsConLike in the desugarer+ , tcFunResultTy builder_ty )+ else (builder_expr, builder_ty)++ | otherwise -- Unidirectional+ = nonBidirectionalErr name+ where+ name = patSynName ps+ builder = patSynBuilder ps++add_void :: Bool -> Type -> Type+add_void need_dummy_arg ty+ | need_dummy_arg = mkFunTy voidPrimTy ty+ | otherwise = ty++tcPatToExpr :: [Located Name] -> LPat Name -> Either MsgDoc (LHsExpr Name)+-- Given a /pattern/, return an /expression/ that builds a value+-- that matches the pattern. E.g. if the pattern is (Just [x]),+-- the expression is (Just [x]). They look the same, but the+-- input uses constructors from HsPat and the output uses constructors+-- from HsExpr.+--+-- Returns (Left r) if the pattern is not invertible, for reason r.+-- See Note [Builder for a bidirectional pattern synonym]+tcPatToExpr args pat = go pat+ where+ lhsVars = mkNameSet (map unLoc args)++ -- Make a prefix con for prefix and infix patterns for simplicity+ mkPrefixConExpr :: Located Name -> [LPat Name] -> Either MsgDoc (HsExpr Name)+ mkPrefixConExpr lcon@(L loc _) pats+ = do { exprs <- mapM go pats+ ; return (foldl (\x y -> HsApp (L loc x) y)+ (HsVar lcon) exprs) }++ mkRecordConExpr :: Located Name -> HsRecFields Name (LPat Name)+ -> Either MsgDoc (HsExpr Name)+ mkRecordConExpr con fields+ = do { exprFields <- mapM go fields+ ; return (RecordCon con PlaceHolder noPostTcExpr exprFields) }++ go :: LPat Name -> Either MsgDoc (LHsExpr Name)+ go (L loc p) = L loc <$> go1 p++ go1 :: Pat Name -> Either MsgDoc (HsExpr Name)+ go1 (ConPatIn con info)+ = case info of+ PrefixCon ps -> mkPrefixConExpr con ps+ InfixCon l r -> mkPrefixConExpr con [l,r]+ RecCon fields -> mkRecordConExpr con fields++ go1 (SigPatIn pat _) = go1 (unLoc pat)+ -- See Note [Type signatures and the builder expression]++ go1 (VarPat (L l var))+ | var `elemNameSet` lhsVars+ = return $ HsVar (L l var)+ | otherwise+ = Left (quotes (ppr var) <+> text "is not bound by the LHS of the pattern synonym")+ go1 (ParPat pat) = fmap HsPar $ go pat+ go1 (LazyPat pat) = go1 (unLoc pat)+ go1 (BangPat pat) = go1 (unLoc pat)+ go1 (PArrPat pats ptt) = do { exprs <- mapM go pats+ ; return $ ExplicitPArr ptt exprs }+ go1 (ListPat pats ptt reb) = do { exprs <- mapM go pats+ ; return $ ExplicitList ptt (fmap snd reb) exprs }+ go1 (TuplePat pats box _) = do { exprs <- mapM go pats+ ; return $ ExplicitTuple+ (map (noLoc . Present) exprs) box }+ go1 (SumPat pat alt arity _) = do { expr <- go1 (unLoc pat)+ ; return $ ExplicitSum alt arity (noLoc expr) PlaceHolder+ }+ go1 (LitPat lit) = return $ HsLit lit+ go1 (NPat (L _ n) mb_neg _ _)+ | Just neg <- mb_neg = return $ unLoc $ nlHsSyntaxApps neg [noLoc (HsOverLit n)]+ | otherwise = return $ HsOverLit n+ go1 (ConPatOut{}) = panic "ConPatOut in output of renamer"+ go1 (SigPatOut{}) = panic "SigPatOut in output of renamer"+ go1 (CoPat{}) = panic "CoPat in output of renamer"+ go1 p = Left (text "pattern" <+> quotes (ppr p) <+> text "is not invertible")++{- Note [Builder for a bidirectional pattern synonym]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For a bidirectional pattern synonym we need to produce an /expression/+that matches the supplied /pattern/, given values for the arguments+of the pattern synoymy. For example+ pattern F x y = (Just x, [y])+The 'builder' for F looks like+ $builderF x y = (Just x, [y])++We can't always do this:+ * Some patterns aren't invertible; e.g. view patterns+ pattern F x = (reverse -> x:_)++ * The RHS pattern might bind more variables than the pattern+ synonym, so again we can't invert it+ pattern F x = (x,y)++ * Ditto wildcards+ pattern F x = (x,_)+++Note [Redundant constraints for builder]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The builder can have redundant constraints, which are awkard to eliminate.+Consider+ pattern P = Just 34+To match against this pattern we need (Eq a, Num a). But to build+(Just 34) we need only (Num a). Fortunately instTcSigFromId sets+sig_warn_redundant to False.++************************************************************************+* *+ Helper functions+* *+************************************************************************++Note [As-patterns in pattern synonym definitions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The rationale for rejecting as-patterns in pattern synonym definitions+is that an as-pattern would introduce nonindependent pattern synonym+arguments, e.g. given a pattern synonym like:++ pattern K x y = x@(Just y)++one could write a nonsensical function like++ f (K Nothing x) = ...++or+ g (K (Just True) False) = ...++Note [Type signatures and the builder expression]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ pattern L x = Left x :: Either [a] [b]++In tc{Infer/Check}PatSynDecl we will check that the pattern has the+specified type. We check the pattern *as a pattern*, so the type+signature is a pattern signature, and so brings 'a' and 'b' into+scope. But we don't have a way to bind 'a, b' in the LHS, as we do+'x', say. Nevertheless, the sigature may be useful to constrain+the type.++When making the binding for the *builder*, though, we don't want+ $buildL x = Left x :: Either [a] [b]+because that wil either mean (forall a b. Either [a] [b]), or we'll+get a complaint that 'a' and 'b' are out of scope. (Actually the+latter; Trac #9867.) No, the job of the signature is done, so when+converting the pattern to an expression (for the builder RHS) we+simply discard the signature.++Note [Record PatSyn Desugaring]+-------------------------------+It is important that prov_theta comes before req_theta as this ordering is used+when desugaring record pattern synonym updates.++Any change to this ordering should make sure to change deSugar/DsExpr.hs if you+want to avoid difficult to decipher core lint errors!+ -}++tcCheckPatSynPat :: LPat Name -> TcM ()+tcCheckPatSynPat = go+ where+ go :: LPat Name -> TcM ()+ go = addLocM go1++ go1 :: Pat Name -> TcM ()+ go1 (ConPatIn _ info) = mapM_ go (hsConPatArgs info)+ go1 VarPat{} = return ()+ go1 WildPat{} = return ()+ go1 p@(AsPat _ _) = asPatInPatSynErr p+ go1 (LazyPat pat) = go pat+ go1 (ParPat pat) = go pat+ go1 (BangPat pat) = go pat+ go1 (PArrPat pats _) = mapM_ go pats+ go1 (ListPat pats _ _) = mapM_ go pats+ go1 (TuplePat pats _ _) = mapM_ go pats+ go1 (SumPat pat _ _ _) = go pat+ go1 LitPat{} = return ()+ go1 NPat{} = return ()+ go1 (SigPatIn pat _) = go pat+ go1 (ViewPat _ pat _) = go pat+ go1 p@SplicePat{} = thInPatSynErr p+ go1 p@NPlusKPat{} = nPlusKPatInPatSynErr p+ go1 ConPatOut{} = panic "ConPatOut in output of renamer"+ go1 SigPatOut{} = panic "SigPatOut in output of renamer"+ go1 CoPat{} = panic "CoPat in output of renamer"++asPatInPatSynErr :: (OutputableBndrId name) => Pat name -> TcM a+asPatInPatSynErr pat+ = failWithTc $+ hang (text "Pattern synonym definition cannot contain as-patterns (@):")+ 2 (ppr pat)++thInPatSynErr :: (OutputableBndrId name) => Pat name -> TcM a+thInPatSynErr pat+ = failWithTc $+ hang (text "Pattern synonym definition cannot contain Template Haskell:")+ 2 (ppr pat)++nPlusKPatInPatSynErr :: (OutputableBndrId name) => Pat name -> TcM a+nPlusKPatInPatSynErr pat+ = failWithTc $+ hang (text "Pattern synonym definition cannot contain n+k-pattern:")+ 2 (ppr pat)++nonBidirectionalErr :: Outputable name => name -> TcM a+nonBidirectionalErr name = failWithTc $+ text "non-bidirectional pattern synonym"+ <+> quotes (ppr name) <+> text "used in an expression"++-- Walk the whole pattern and for all ConPatOuts, collect the+-- existentially-bound type variables and evidence binding variables.+--+-- These are used in computing the type of a pattern synonym and also+-- in generating matcher functions, since success continuations need+-- to be passed these pattern-bound evidences.+tcCollectEx+ :: LPat Id+ -> ( [TyVar] -- Existentially-bound type variables+ -- in correctly-scoped order; e.g. [ k:*, x:k ]+ , [EvVar] ) -- and evidence variables++tcCollectEx pat = go pat+ where+ go :: LPat Id -> ([TyVar], [EvVar])+ go = go1 . unLoc++ go1 :: Pat Id -> ([TyVar], [EvVar])+ go1 (LazyPat p) = go p+ go1 (AsPat _ p) = go p+ go1 (ParPat p) = go p+ go1 (BangPat p) = go p+ go1 (ListPat ps _ _) = mergeMany . map go $ ps+ go1 (TuplePat ps _ _) = mergeMany . map go $ ps+ go1 (SumPat p _ _ _) = go p+ go1 (PArrPat ps _) = mergeMany . map go $ ps+ go1 (ViewPat _ p _) = go p+ go1 con@ConPatOut{} = merge (pat_tvs con, pat_dicts con) $+ goConDetails $ pat_args con+ go1 (SigPatOut p _) = go p+ go1 (CoPat _ p _) = go1 p+ go1 (NPlusKPat n k _ geq subtract _)+ = pprPanic "TODO: NPlusKPat" $ ppr n $$ ppr k $$ ppr geq $$ ppr subtract+ go1 _ = empty++ goConDetails :: HsConPatDetails Id -> ([TyVar], [EvVar])+ goConDetails (PrefixCon ps) = mergeMany . map go $ ps+ goConDetails (InfixCon p1 p2) = go p1 `merge` go p2+ goConDetails (RecCon HsRecFields{ rec_flds = flds })+ = mergeMany . map goRecFd $ flds++ goRecFd :: LHsRecField Id (LPat Id) -> ([TyVar], [EvVar])+ goRecFd (L _ HsRecField{ hsRecFieldArg = p }) = go p++ merge (vs1, evs1) (vs2, evs2) = (vs1 ++ vs2, evs1 ++ evs2)+ mergeMany = foldr merge empty+ empty = ([], [])
+ typecheck/TcPatSyn.hs-boot view
@@ -0,0 +1,19 @@+module TcPatSyn where++import Name ( Name )+import Id ( Id )+import HsSyn ( PatSynBind, LHsBinds )+import TcRnTypes ( TcM, TcPatSynInfo )+import TcRnMonad ( TcGblEnv)+import Outputable ( Outputable )++tcInferPatSynDecl :: PatSynBind Name Name+ -> TcM (LHsBinds Id, TcGblEnv)++tcCheckPatSynDecl :: PatSynBind Name Name+ -> TcPatSynInfo+ -> TcM (LHsBinds Id, TcGblEnv)++tcPatSynBuilderBind :: PatSynBind Name Name -> TcM (LHsBinds Id)++nonBidirectionalErr :: Outputable name => name -> TcM a
+ typecheck/TcPluginM.hs view
@@ -0,0 +1,191 @@+{-# LANGUAGE CPP #-}+-- | This module provides an interface for typechecker plugins to+-- access select functions of the 'TcM', principally those to do with+-- reading parts of the state.+module TcPluginM (+#ifdef GHCI+ -- * Basic TcPluginM functionality+ TcPluginM,+ tcPluginIO,+ tcPluginTrace,+ unsafeTcPluginTcM,++ -- * Finding Modules and Names+ FindResult(..),+ findImportedModule,+ lookupOrig,++ -- * Looking up Names in the typechecking environment+ tcLookupGlobal,+ tcLookupTyCon,+ tcLookupDataCon,+ tcLookupClass,+ tcLookup,+ tcLookupId,++ -- * Getting the TcM state+ getTopEnv,+ getEnvs,+ getInstEnvs,+ getFamInstEnvs,+ matchFam,++ -- * Type variables+ newUnique,+ newFlexiTyVar,+ isTouchableTcPluginM,++ -- * Zonking+ zonkTcType,+ zonkCt,++ -- * Creating constraints+ newWanted,+ newDerived,+ newGiven,+ newCoercionHole,++ -- * Manipulating evidence bindings+ newEvVar,+ setEvBind,+ getEvBindsTcPluginM+#endif+ ) where++#ifdef GHCI+import qualified TcRnMonad as TcM+import qualified TcSMonad as TcS+import qualified TcEnv as TcM+import qualified TcMType as TcM+import qualified FamInst as TcM+import qualified IfaceEnv+import qualified Finder++import FamInstEnv ( FamInstEnv )+import TcRnMonad ( TcGblEnv, TcLclEnv, Ct, CtLoc, TcPluginM+ , unsafeTcPluginTcM, getEvBindsTcPluginM+ , liftIO, traceTc )+import TcMType ( TcTyVar, TcType )+import TcEnv ( TcTyThing )+import TcEvidence ( TcCoercion, CoercionHole+ , EvTerm, EvBind, mkGivenEvBind )+import TcRnTypes ( CtEvidence(..) )+import Var ( EvVar )++import Module+import Name+import TyCon+import DataCon+import Class+import HscTypes+import Outputable+import Type+import Id+import InstEnv+import FastString+import Unique+++-- | Perform some IO, typically to interact with an external tool.+tcPluginIO :: IO a -> TcPluginM a+tcPluginIO a = unsafeTcPluginTcM (liftIO a)++-- | Output useful for debugging the compiler.+tcPluginTrace :: String -> SDoc -> TcPluginM ()+tcPluginTrace a b = unsafeTcPluginTcM (traceTc a b)+++findImportedModule :: ModuleName -> Maybe FastString -> TcPluginM FindResult+findImportedModule mod_name mb_pkg = do+ hsc_env <- getTopEnv+ tcPluginIO $ Finder.findImportedModule hsc_env mod_name mb_pkg++lookupOrig :: Module -> OccName -> TcPluginM Name+lookupOrig mod = unsafeTcPluginTcM . IfaceEnv.lookupOrig mod+++tcLookupGlobal :: Name -> TcPluginM TyThing+tcLookupGlobal = unsafeTcPluginTcM . TcM.tcLookupGlobal++tcLookupTyCon :: Name -> TcPluginM TyCon+tcLookupTyCon = unsafeTcPluginTcM . TcM.tcLookupTyCon++tcLookupDataCon :: Name -> TcPluginM DataCon+tcLookupDataCon = unsafeTcPluginTcM . TcM.tcLookupDataCon++tcLookupClass :: Name -> TcPluginM Class+tcLookupClass = unsafeTcPluginTcM . TcM.tcLookupClass++tcLookup :: Name -> TcPluginM TcTyThing+tcLookup = unsafeTcPluginTcM . TcM.tcLookup++tcLookupId :: Name -> TcPluginM Id+tcLookupId = unsafeTcPluginTcM . TcM.tcLookupId+++getTopEnv :: TcPluginM HscEnv+getTopEnv = unsafeTcPluginTcM TcM.getTopEnv++getEnvs :: TcPluginM (TcGblEnv, TcLclEnv)+getEnvs = unsafeTcPluginTcM TcM.getEnvs++getInstEnvs :: TcPluginM InstEnvs+getInstEnvs = unsafeTcPluginTcM TcM.tcGetInstEnvs++getFamInstEnvs :: TcPluginM (FamInstEnv, FamInstEnv)+getFamInstEnvs = unsafeTcPluginTcM TcM.tcGetFamInstEnvs++matchFam :: TyCon -> [Type]+ -> TcPluginM (Maybe (TcCoercion, TcType))+matchFam tycon args = unsafeTcPluginTcM $ TcS.matchFamTcM tycon args++newUnique :: TcPluginM Unique+newUnique = unsafeTcPluginTcM TcM.newUnique++newFlexiTyVar :: Kind -> TcPluginM TcTyVar+newFlexiTyVar = unsafeTcPluginTcM . TcM.newFlexiTyVar++isTouchableTcPluginM :: TcTyVar -> TcPluginM Bool+isTouchableTcPluginM = unsafeTcPluginTcM . TcM.isTouchableTcM++-- Confused by zonking? See Note [What is zonking?] in TcMType.+zonkTcType :: TcType -> TcPluginM TcType+zonkTcType = unsafeTcPluginTcM . TcM.zonkTcType++zonkCt :: Ct -> TcPluginM Ct+zonkCt = unsafeTcPluginTcM . TcM.zonkCt+++-- | Create a new wanted constraint.+newWanted :: CtLoc -> PredType -> TcPluginM CtEvidence+newWanted loc pty+ = unsafeTcPluginTcM (TcM.newWanted (TcM.ctLocOrigin loc) Nothing pty)++-- | Create a new derived constraint.+newDerived :: CtLoc -> PredType -> TcPluginM CtEvidence+newDerived loc pty = return CtDerived { ctev_pred = pty, ctev_loc = loc }++-- | Create a new given constraint, with the supplied evidence. This+-- must not be invoked from 'tcPluginInit' or 'tcPluginStop', or it+-- will panic.+newGiven :: CtLoc -> PredType -> EvTerm -> TcPluginM CtEvidence+newGiven loc pty evtm = do+ new_ev <- newEvVar pty+ setEvBind $ mkGivenEvBind new_ev evtm+ return CtGiven { ctev_pred = pty, ctev_evar = new_ev, ctev_loc = loc }++-- | Create a fresh evidence variable.+newEvVar :: PredType -> TcPluginM EvVar+newEvVar = unsafeTcPluginTcM . TcM.newEvVar++-- | Create a fresh coercion hole.+newCoercionHole :: TcPluginM CoercionHole+newCoercionHole = unsafeTcPluginTcM $ TcM.newCoercionHole++-- | Bind an evidence variable. This must not be invoked from+-- 'tcPluginInit' or 'tcPluginStop', or it will panic.+setEvBind :: EvBind -> TcPluginM ()+setEvBind ev_bind = do+ tc_evbinds <- getEvBindsTcPluginM+ unsafeTcPluginTcM $ TcM.addTcEvBind tc_evbinds ev_bind+#endif
+ typecheck/TcRnDriver.hs view
@@ -0,0 +1,2640 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[TcMovectle]{Typechecking a whole module}++https://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/TypeChecker+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE NondecreasingIndentation #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ScopedTypeVariables #-}++module TcRnDriver (+ tcRnStmt, tcRnExpr, TcRnExprMode(..), tcRnType,+ tcRnImportDecls,+ tcRnLookupRdrName,+ getModuleInterface,+ tcRnDeclsi,+ isGHCiMonad,+ runTcInteractive, -- Used by GHC API clients (Trac #8878)+ tcRnLookupName,+ tcRnGetInfo,+ tcRnModule, tcRnModuleTcRnM,+ tcTopSrcDecls,+ rnTopSrcDecls,+ checkBootDecl, checkHiBootIface',+ findExtraSigImports,+ implicitRequirements,+ checkUnitId,+ mergeSignatures,+ tcRnMergeSignatures,+ instantiateSignature,+ tcRnInstantiateSignature,+ loadUnqualIfaces,+ -- More private...+ badReexportedBootThing,+ checkBootDeclM,+ missingBootThing,+ ) where++import {-# SOURCE #-} TcSplice ( finishTH )+import RnSplice ( rnTopSpliceDecls, traceSplice, SpliceInfo(..) )+import IfaceEnv( externaliseName )+import TcHsType+import TcMatches+import Inst( deeplyInstantiate )+import TcUnify( checkConstraints )+import RnTypes+import RnExpr+import MkId+import TidyPgm ( globaliseAndTidyId )+import TysWiredIn ( unitTy, mkListTy )+#ifdef GHCI+import DynamicLoading ( loadPlugins )+import Plugins ( tcPlugin )+#endif++import DynFlags+import HsSyn+import IfaceSyn ( ShowSub(..), showToHeader )+import IfaceType( ShowForAllFlag(..) )+import PrelNames+import RdrName+import TcHsSyn+import TcExpr+import TcRnMonad+import TcRnExports+import TcEvidence+import qualified BooleanFormula as BF+import PprTyThing( pprTyThingInContext )+import MkIface( tyThingToIfaceDecl )+import Coercion( pprCoAxiom )+import CoreFVs( orphNamesOfFamInst )+import FamInst+import InstEnv+import FamInstEnv+import TcAnnotations+import TcBinds+import HeaderInfo ( mkPrelImports )+import TcDefaults+import TcEnv+import TcRules+import TcForeign+import TcInstDcls+import TcIface+import TcMType+import TcType+import TcSimplify+import TcTyClsDecls+import TcTypeable ( mkTypeableBinds )+import TcBackpack+import LoadIface+import RnNames+import RnEnv+import RnSource+import ErrUtils+import Id+import VarEnv+import Module+import UniqFM+import Name+import NameEnv+import NameSet+import Avail+import TyCon+import SrcLoc+import HscTypes+import ListSetOps+import Outputable+import ConLike+import DataCon+import Type+import Class+import BasicTypes hiding( SuccessFlag(..) )+import CoAxiom+import Annotations+import Data.List ( sortBy, sort )+import Data.Ord+import FastString+import Maybes+import Util+import Bag+import Inst (tcGetInsts)+import qualified GHC.LanguageExtensions as LangExt+import Data.Data ( Data )+import HsDumpAst+import qualified Data.Set as S++import Control.Monad++#include "HsVersions.h"++{-+************************************************************************+* *+ Typecheck and rename a module+* *+************************************************************************+-}++-- | Top level entry point for typechecker and renamer+tcRnModule :: HscEnv+ -> HscSource+ -> Bool -- True <=> save renamed syntax+ -> HsParsedModule+ -> IO (Messages, Maybe TcGblEnv)++tcRnModule hsc_env hsc_src save_rn_syntax+ parsedModule@HsParsedModule {hpm_module=L loc this_module}+ | RealSrcSpan real_loc <- loc+ = withTiming (pure dflags)+ (text "Renamer/typechecker"<+>brackets (ppr this_mod))+ (const ()) $+ initTc hsc_env hsc_src save_rn_syntax this_mod real_loc $+ withTcPlugins hsc_env $++ tcRnModuleTcRnM hsc_env hsc_src parsedModule pair++ | otherwise+ = return ((emptyBag, unitBag err_msg), Nothing)++ where+ dflags = hsc_dflags hsc_env+ err_msg = mkPlainErrMsg (hsc_dflags hsc_env) loc $+ text "Module does not have a RealSrcSpan:" <+> ppr this_mod++ this_pkg = thisPackage (hsc_dflags hsc_env)++ pair :: (Module, SrcSpan)+ pair@(this_mod,_)+ | Just (L mod_loc mod) <- hsmodName this_module+ = (mkModule this_pkg mod, mod_loc)++ | otherwise -- 'module M where' is omitted+ = (mAIN, srcLocSpan (srcSpanStart loc))+++++tcRnModuleTcRnM :: HscEnv+ -> HscSource+ -> HsParsedModule+ -> (Module, SrcSpan)+ -> TcRn TcGblEnv+-- Factored out separately from tcRnModule so that a Core plugin can+-- call the type checker directly+tcRnModuleTcRnM hsc_env hsc_src+ (HsParsedModule {+ hpm_module =+ (L loc (HsModule maybe_mod export_ies+ import_decls local_decls mod_deprec+ maybe_doc_hdr)),+ hpm_src_files = src_files+ })+ (this_mod, prel_imp_loc)+ = setSrcSpan loc $+ do { let { explicit_mod_hdr = isJust maybe_mod } ;++ -- Load the hi-boot interface for this module, if any+ -- We do this now so that the boot_names can be passed+ -- to tcTyAndClassDecls, because the boot_names are+ -- automatically considered to be loop breakers+ tcg_env <- getGblEnv ;+ boot_info <- tcHiBootIface hsc_src this_mod ;+ setGblEnv (tcg_env { tcg_self_boot = boot_info }) $ do {++ -- Deal with imports; first add implicit prelude+ implicit_prelude <- xoptM LangExt.ImplicitPrelude;+ let { prel_imports = mkPrelImports (moduleName this_mod) prel_imp_loc+ implicit_prelude import_decls } ;++ whenWOptM Opt_WarnImplicitPrelude $+ when (notNull prel_imports) $+ addWarn (Reason Opt_WarnImplicitPrelude) (implicitPreludeWarn) ;++ -- TODO This is a little skeevy; maybe handle a bit more directly+ let { simplifyImport (L _ idecl) = (fmap sl_fs (ideclPkgQual idecl), ideclName idecl) } ;+ raw_sig_imports <- liftIO $ findExtraSigImports hsc_env hsc_src (moduleName this_mod) ;+ raw_req_imports <- liftIO $+ implicitRequirements hsc_env (map simplifyImport (prel_imports ++ import_decls)) ;+ let { mkImport (Nothing, L _ mod_name) = noLoc $ (simpleImportDecl mod_name) {+ ideclHiding = Just (False, noLoc [])+ } ;+ mkImport _ = panic "mkImport" } ;++ let { all_imports = prel_imports ++ import_decls+ ++ map mkImport (raw_sig_imports ++ raw_req_imports) } ;++ -- OK now finally rename the imports+ tcg_env <- {-# SCC "tcRnImports" #-}+ tcRnImports hsc_env all_imports ;++ -- If the whole module is warned about or deprecated+ -- (via mod_deprec) record that in tcg_warns. If we do thereby add+ -- a WarnAll, it will override any subseqent depracations added to tcg_warns+ let { tcg_env1 = case mod_deprec of+ Just (L _ txt) -> tcg_env { tcg_warns = WarnAll txt }+ Nothing -> tcg_env+ } ;++ setGblEnv tcg_env1 $ do {++ -- Rename and type check the declarations+ traceRn "rn1a" empty ;+ tcg_env <- if isHsBootOrSig hsc_src then+ tcRnHsBootDecls hsc_src local_decls+ else+ {-# SCC "tcRnSrcDecls" #-}+ tcRnSrcDecls explicit_mod_hdr local_decls ;+ setGblEnv tcg_env $ do {++ -- Process the export list+ traceRn "rn4a: before exports" empty;+ tcg_env <- tcRnExports explicit_mod_hdr export_ies tcg_env ;+ traceRn "rn4b: after exports" empty ;++ -- Check that main is exported (must be after tcRnExports)+ checkMainExported tcg_env ;++ -- Compare the hi-boot iface (if any) with the real thing+ -- Must be done after processing the exports+ tcg_env <- checkHiBootIface tcg_env boot_info ;++ -- The new type env is already available to stuff slurped from+ -- interface files, via TcEnv.setGlobalTypeEnv+ -- It's important that this includes the stuff in checkHiBootIface,+ -- because the latter might add new bindings for boot_dfuns,+ -- which may be mentioned in imported unfoldings++ -- Don't need to rename the Haddock documentation,+ -- it's not parsed by GHC anymore.+ tcg_env <- return (tcg_env { tcg_doc_hdr = maybe_doc_hdr }) ;++ -- Report unused names+ -- Do this /after/ type inference, so that when reporting+ -- a function with no type signature we can give the+ -- inferred type+ reportUnusedNames export_ies tcg_env ;++ -- add extra source files to tcg_dependent_files+ addDependentFiles src_files ;++ -- Dump output and return+ tcDump tcg_env ;+ return tcg_env+ }}}}++implicitPreludeWarn :: SDoc+implicitPreludeWarn+ = text "Module `Prelude' implicitly imported"++{-+************************************************************************+* *+ Import declarations+* *+************************************************************************+-}++tcRnImports :: HscEnv -> [LImportDecl RdrName] -> TcM TcGblEnv+tcRnImports hsc_env import_decls+ = do { (rn_imports, rdr_env, imports, hpc_info) <- rnImports import_decls ;++ ; this_mod <- getModule+ ; let { dep_mods :: ModuleNameEnv (ModuleName, IsBootInterface)+ ; dep_mods = imp_dep_mods imports++ -- We want instance declarations from all home-package+ -- modules below this one, including boot modules, except+ -- ourselves. The 'except ourselves' is so that we don't+ -- get the instances from this module's hs-boot file. This+ -- filtering also ensures that we don't see instances from+ -- modules batch (@--make@) compiled before this one, but+ -- which are not below this one.+ ; want_instances :: ModuleName -> Bool+ ; want_instances mod = mod `elemUFM` dep_mods+ && mod /= moduleName this_mod+ ; (home_insts, home_fam_insts) = hptInstances hsc_env+ want_instances+ } ;++ -- Record boot-file info in the EPS, so that it's+ -- visible to loadHiBootInterface in tcRnSrcDecls,+ -- and any other incrementally-performed imports+ ; updateEps_ (\eps -> eps { eps_is_boot = dep_mods }) ;++ -- Update the gbl env+ ; updGblEnv ( \ gbl ->+ gbl {+ tcg_rdr_env = tcg_rdr_env gbl `plusGlobalRdrEnv` rdr_env,+ tcg_imports = tcg_imports gbl `plusImportAvails` imports,+ tcg_rn_imports = rn_imports,+ tcg_inst_env = extendInstEnvList (tcg_inst_env gbl) home_insts,+ tcg_fam_inst_env = extendFamInstEnvList (tcg_fam_inst_env gbl)+ home_fam_insts,+ tcg_hpc = hpc_info+ }) $ do {++ ; traceRn "rn1" (ppr (imp_dep_mods imports))+ -- Fail if there are any errors so far+ -- The error printing (if needed) takes advantage+ -- of the tcg_env we have now set+-- ; traceIf (text "rdr_env: " <+> ppr rdr_env)+ ; failIfErrsM++ -- Load any orphan-module (including orphan family+ -- instance-module) interfaces, so that their rules and+ -- instance decls will be found. But filter out a+ -- self hs-boot: these instances will be checked when+ -- we define them locally.+ -- (We don't need to load non-orphan family instance+ -- modules until we either try to use the instances they+ -- define, or define our own family instances, at which+ -- point we need to check them for consistency.)+ ; loadModuleInterfaces (text "Loading orphan modules")+ (filter (/= this_mod) (imp_orphs imports))++ -- Check type-family consistency between imports.+ -- See Note [The type family instance consistency story]+ ; traceRn "rn1: checking family instance consistency" empty+ ; let { dir_imp_mods = moduleEnvKeys+ . imp_mods+ $ imports }+ ; tcg_env <- checkFamInstConsistency (imp_finsts imports) dir_imp_mods ;++ ; return tcg_env } }++{-+************************************************************************+* *+ Type-checking the top level of a module+* *+************************************************************************+-}++tcRnSrcDecls :: Bool -- False => no 'module M(..) where' header at all+ -> [LHsDecl RdrName] -- Declarations+ -> TcM TcGblEnv+tcRnSrcDecls explicit_mod_hdr decls+ = do { -- Do all the declarations+ ; ((tcg_env, tcl_env), lie) <- captureTopConstraints $+ do { (tcg_env, tcl_env) <- tc_rn_src_decls decls++ -- Check for the 'main' declaration+ -- Must do this inside the captureTopConstraints+ ; tcg_env <- setEnvs (tcg_env, tcl_env) $+ checkMain explicit_mod_hdr+ ; return (tcg_env, tcl_env) }++ ; setEnvs (tcg_env, tcl_env) $ do {++ -- Simplify constraints+ --+ -- We do this after checkMain, so that we use the type info+ -- that checkMain adds+ --+ -- We do it with both global and local env in scope:+ -- * the global env exposes the instances to simplifyTop+ -- * the local env exposes the local Ids to simplifyTop,+ -- so that we get better error messages (monomorphism restriction)+ ; new_ev_binds <- {-# SCC "simplifyTop" #-}+ simplifyTop lie++ -- Emit Typeable bindings+ ; tcg_env <- mkTypeableBinds++ -- Finalizers must run after constraints are simplified, or some types+ -- might not be complete when using reify (see #12777).+ ; (tcg_env, tcl_env) <- setGblEnv tcg_env run_th_modfinalizers+ ; setEnvs (tcg_env, tcl_env) $ do {++ ; finishTH++ ; traceTc "Tc9" empty++ ; failIfErrsM -- Don't zonk if there have been errors+ -- It's a waste of time; and we may get debug warnings+ -- about strangely-typed TyCons!+ ; traceTc "Tc10" empty++ -- Zonk the final code. This must be done last.+ -- Even simplifyTop may do some unification.+ -- This pass also warns about missing type signatures+ ; let { TcGblEnv { tcg_type_env = type_env,+ tcg_binds = binds,+ tcg_ev_binds = cur_ev_binds,+ tcg_imp_specs = imp_specs,+ tcg_rules = rules,+ tcg_vects = vects,+ tcg_fords = fords } = tcg_env+ ; all_ev_binds = cur_ev_binds `unionBags` new_ev_binds } ;++ ; (bind_env, ev_binds', binds', fords', imp_specs', rules', vects')+ <- {-# SCC "zonkTopDecls" #-}+ zonkTopDecls all_ev_binds binds rules vects+ imp_specs fords ;+ ; traceTc "Tc11" empty++ ; let { final_type_env = plusTypeEnv type_env bind_env+ ; tcg_env' = tcg_env { tcg_binds = binds',+ tcg_ev_binds = ev_binds',+ tcg_imp_specs = imp_specs',+ tcg_rules = rules',+ tcg_vects = vects',+ tcg_fords = fords' } } ;++ ; setGlobalTypeEnv tcg_env' final_type_env++ }+ } }++-- | Runs TH finalizers and renames and typechecks the top-level declarations+-- that they could introduce.+run_th_modfinalizers :: TcM (TcGblEnv, TcLclEnv)+run_th_modfinalizers = do+ th_modfinalizers_var <- fmap tcg_th_modfinalizers getGblEnv+ th_modfinalizers <- readTcRef th_modfinalizers_var+ if null th_modfinalizers+ then getEnvs+ else do+ writeTcRef th_modfinalizers_var []+ (envs, lie) <- captureTopConstraints $ do+ sequence_ th_modfinalizers+ -- Finalizers can add top-level declarations with addTopDecls.+ tc_rn_src_decls []+ setEnvs envs $ do+ -- Subsequent rounds of finalizers run after any new constraints are+ -- simplified, or some types might not be complete when using reify+ -- (see #12777).+ new_ev_binds <- {-# SCC "simplifyTop2" #-}+ simplifyTop lie+ updGblEnv (\tcg_env ->+ tcg_env { tcg_ev_binds = tcg_ev_binds tcg_env `unionBags` new_ev_binds }+ )+ -- addTopDecls can add declarations which add new finalizers.+ run_th_modfinalizers++tc_rn_src_decls :: [LHsDecl RdrName]+ -> TcM (TcGblEnv, TcLclEnv)+-- Loops around dealing with each top level inter-splice group+-- in turn, until it's dealt with the entire module+tc_rn_src_decls ds+ = {-# SCC "tc_rn_src_decls" #-}+ do { (first_group, group_tail) <- findSplice ds+ -- If ds is [] we get ([], Nothing)++ -- Deal with decls up to, but not including, the first splice+ ; (tcg_env, rn_decls) <- rnTopSrcDecls first_group+ -- rnTopSrcDecls fails if there are any errors++ -- Get TH-generated top-level declarations and make sure they don't+ -- contain any splices since we don't handle that at the moment+ --+ -- The plumbing here is a bit odd: see Trac #10853+ ; th_topdecls_var <- fmap tcg_th_topdecls getGblEnv+ ; th_ds <- readTcRef th_topdecls_var+ ; writeTcRef th_topdecls_var []++ ; (tcg_env, rn_decls) <-+ if null th_ds+ then return (tcg_env, rn_decls)+ else do { (th_group, th_group_tail) <- findSplice th_ds+ ; case th_group_tail of+ { Nothing -> return () ;+ ; Just (SpliceDecl (L loc _) _, _)+ -> setSrcSpan loc $+ addErr (text "Declaration splices are not permitted inside top-level declarations added with addTopDecls")+ } ;++ -- Rename TH-generated top-level declarations+ ; (tcg_env, th_rn_decls) <- setGblEnv tcg_env $+ rnTopSrcDecls th_group++ -- Dump generated top-level declarations+ ; let msg = "top-level declarations added with addTopDecls"+ ; traceSplice $ SpliceInfo { spliceDescription = msg+ , spliceIsDecl = True+ , spliceSource = Nothing+ , spliceGenerated = ppr th_rn_decls }++ ; return (tcg_env, appendGroups rn_decls th_rn_decls)+ }++ -- Type check all declarations+ ; (tcg_env, tcl_env) <- setGblEnv tcg_env $+ tcTopSrcDecls rn_decls++ -- If there is no splice, we're nearly done+ ; setEnvs (tcg_env, tcl_env) $+ case group_tail of+ { Nothing -> return (tcg_env, tcl_env)++ -- If there's a splice, we must carry on+ ; Just (SpliceDecl (L loc splice) _, rest_ds) ->+ do { recordTopLevelSpliceLoc loc++ -- Rename the splice expression, and get its supporting decls+ ; (spliced_decls, splice_fvs) <- checkNoErrs (rnTopSpliceDecls+ splice)++ -- Glue them on the front of the remaining decls and loop+ ; setGblEnv (tcg_env `addTcgDUs` usesOnly splice_fvs) $+ tc_rn_src_decls (spliced_decls ++ rest_ds)+ }+ }+ }++{-+************************************************************************+* *+ Compiling hs-boot source files, and+ comparing the hi-boot interface with the real thing+* *+************************************************************************+-}++tcRnHsBootDecls :: HscSource -> [LHsDecl RdrName] -> TcM TcGblEnv+tcRnHsBootDecls hsc_src decls+ = do { (first_group, group_tail) <- findSplice decls++ -- Rename the declarations+ ; (tcg_env, HsGroup { hs_tyclds = tycl_decls+ , hs_derivds = deriv_decls+ , hs_fords = for_decls+ , hs_defds = def_decls+ , hs_ruleds = rule_decls+ , hs_vects = vect_decls+ , hs_annds = _+ , hs_valds = ValBindsOut val_binds val_sigs })+ <- rnTopSrcDecls first_group+ -- The empty list is for extra dependencies coming from .hs-boot files+ -- See Note [Extra dependencies from .hs-boot files] in RnSource+ ; (gbl_env, lie) <- captureTopConstraints $ setGblEnv tcg_env $ do {+++ -- Check for illegal declarations+ ; case group_tail of+ Just (SpliceDecl d _, _) -> badBootDecl hsc_src "splice" d+ Nothing -> return ()+ ; mapM_ (badBootDecl hsc_src "foreign") for_decls+ ; mapM_ (badBootDecl hsc_src "default") def_decls+ ; mapM_ (badBootDecl hsc_src "rule") rule_decls+ ; mapM_ (badBootDecl hsc_src "vect") vect_decls++ -- Typecheck type/class/instance decls+ ; traceTc "Tc2 (boot)" empty+ ; (tcg_env, inst_infos, _deriv_binds)+ <- tcTyClsInstDecls tycl_decls deriv_decls val_binds+ ; setGblEnv tcg_env $ do {++ -- Emit Typeable bindings+ ; tcg_env <- mkTypeableBinds+ ; setGblEnv tcg_env $ do {++ -- Typecheck value declarations+ ; traceTc "Tc5" empty+ ; val_ids <- tcHsBootSigs val_binds val_sigs++ -- Wrap up+ -- No simplification or zonking to do+ ; traceTc "Tc7a" empty+ ; gbl_env <- getGblEnv++ -- Make the final type-env+ -- Include the dfun_ids so that their type sigs+ -- are written into the interface file.+ ; let { type_env0 = tcg_type_env gbl_env+ ; type_env1 = extendTypeEnvWithIds type_env0 val_ids+ ; type_env2 = extendTypeEnvWithIds type_env1 dfun_ids+ ; dfun_ids = map iDFunId inst_infos+ }++ ; setGlobalTypeEnv gbl_env type_env2+ }}}+ ; traceTc "boot" (ppr lie); return gbl_env }++badBootDecl :: HscSource -> String -> Located decl -> TcM ()+badBootDecl hsc_src what (L loc _)+ = addErrAt loc (char 'A' <+> text what+ <+> text "declaration is not (currently) allowed in a"+ <+> (case hsc_src of+ HsBootFile -> text "hs-boot"+ HsigFile -> text "hsig"+ _ -> panic "badBootDecl: should be an hsig or hs-boot file")+ <+> text "file")++{-+Once we've typechecked the body of the module, we want to compare what+we've found (gathered in a TypeEnv) with the hi-boot details (if any).+-}++checkHiBootIface :: TcGblEnv -> SelfBootInfo -> TcM TcGblEnv+-- Compare the hi-boot file for this module (if there is one)+-- with the type environment we've just come up with+-- In the common case where there is no hi-boot file, the list+-- of boot_names is empty.++checkHiBootIface tcg_env boot_info+ | NoSelfBoot <- boot_info -- Common case+ = return tcg_env++ | HsBootFile <- tcg_src tcg_env -- Current module is already a hs-boot file!+ = return tcg_env++ | SelfBoot { sb_mds = boot_details } <- boot_info+ , TcGblEnv { tcg_binds = binds+ , tcg_insts = local_insts+ , tcg_type_env = local_type_env+ , tcg_exports = local_exports } <- tcg_env+ = do { -- This code is tricky, see Note [DFun knot-tying]+ ; let boot_dfuns = filter isDFunId (typeEnvIds (md_types boot_details))+ type_env' = extendTypeEnvWithIds local_type_env boot_dfuns+ -- Why the seq? Without, we will put a TypeEnv thunk in+ -- tcg_type_env_var. That thunk will eventually get+ -- forced if we are typechecking interfaces, but that+ -- is no good if we are trying to typecheck the very+ -- DFun we were going to put in.+ -- TODO: Maybe setGlobalTypeEnv should be strict.+ ; tcg_env <- type_env' `seq` setGlobalTypeEnv tcg_env type_env'+ ; dfun_prs <- checkHiBootIface' local_insts type_env'+ local_exports boot_details+ ; let dfun_binds = listToBag [ mkVarBind boot_dfun (nlHsVar dfun)+ | (boot_dfun, dfun) <- dfun_prs ]++ ; return tcg_env { tcg_binds = binds `unionBags` dfun_binds } }++ | otherwise = panic "checkHiBootIface: unreachable code"++-- Note [DFun knot-tying]+-- ~~~~~~~~~~~~~~~~~~~~~~+-- The 'SelfBootInfo' that is fed into 'checkHiBootIface' comes+-- from typechecking the hi-boot file that we are presently+-- implementing. Suppose we are typechecking the module A:+-- when we typecheck the hi-boot file, whenever we see an+-- identifier A.T, we knot-tie this identifier to the+-- *local* type environment (via if_rec_types.) The contract+-- then is that we don't *look* at 'SelfBootInfo' until+-- we've finished typechecking the module and updated the+-- type environment with the new tycons and ids.+--+-- This most works well, but there is one problem: DFuns!+-- In general, it's not possible to know a priori what an+-- hs-boot file named a DFun (see Note [DFun impedance matching]),+-- so we look at the ClsInsts from the boot file to figure out+-- what DFuns to add to the type environment. But we're not+-- allowed to poke the DFuns of the ClsInsts in the SelfBootInfo+-- until we've added the DFuns to the type environment. A+-- Gordian knot!+--+-- We cut the knot by a little trick: we first *unconditionally*+-- add all of the boot-declared DFuns to the type environment+-- (so that knot tying works, see Trac #4003), without the+-- actual bindings for them. Then, we compute the impedance+-- matching bindings, and add them to the environment.+--+-- There is one subtlety to doing this: we have to get the+-- DFuns from md_types, not md_insts, even though involves+-- filtering a bunch of TyThings we don't care about. The+-- reason is only the TypeEnv in md_types has the actual+-- Id we want to add to the environment; the DFun fields+-- in md_insts are typechecking thunks that will attempt to+-- go through if_rec_types to lookup the real Id... but+-- that's what we're trying to setup right now.++checkHiBootIface' :: [ClsInst] -> TypeEnv -> [AvailInfo]+ -> ModDetails -> TcM [(Id, Id)]+-- Variant which doesn't require a full TcGblEnv; you could get the+-- local components from another ModDetails.+--+-- Note [DFun impedance matching]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- We return a list of "impedance-matching" bindings for the dfuns+-- defined in the hs-boot file, such as+-- $fxEqT = $fEqT+-- We need these because the module and hi-boot file might differ in+-- the name it chose for the dfun: the name of a dfun is not+-- uniquely determined by its type; there might be multiple dfuns+-- which, individually, would map to the same name (in which case+-- we have to disambiguate them.) There's no way for the hi file+-- to know exactly what disambiguation to use... without looking+-- at the hi-boot file itself.+--+-- In fact, the names will always differ because we always pick names+-- prefixed with "$fx" for boot dfuns, and "$f" for real dfuns+-- (so that this impedance matching is always possible).++checkHiBootIface'+ local_insts local_type_env local_exports+ (ModDetails { md_insts = boot_insts, md_fam_insts = boot_fam_insts,+ md_types = boot_type_env, md_exports = boot_exports })+ = do { traceTc "checkHiBootIface" $ vcat+ [ ppr boot_type_env, ppr boot_insts, ppr boot_exports]++ -- Check the exports of the boot module, one by one+ ; mapM_ check_export boot_exports++ -- Check for no family instances+ ; unless (null boot_fam_insts) $+ panic ("TcRnDriver.checkHiBootIface: Cannot handle family " +++ "instances in boot files yet...")+ -- FIXME: Why? The actual comparison is not hard, but what would+ -- be the equivalent to the dfun bindings returned for class+ -- instances? We can't easily equate tycons...++ -- Check instance declarations+ -- and generate an impedance-matching binding+ ; mb_dfun_prs <- mapM check_inst boot_insts++ ; failIfErrsM++ ; return (catMaybes mb_dfun_prs) }++ where+ check_export boot_avail -- boot_avail is exported by the boot iface+ | name `elem` dfun_names = return ()+ | isWiredInName name = return () -- No checking for wired-in names. In particular,+ -- 'error' is handled by a rather gross hack+ -- (see comments in GHC.Err.hs-boot)++ -- Check that the actual module exports the same thing+ | not (null missing_names)+ = addErrAt (nameSrcSpan (head missing_names))+ (missingBootThing True (head missing_names) "exported by")++ -- If the boot module does not *define* the thing, we are done+ -- (it simply re-exports it, and names match, so nothing further to do)+ | isNothing mb_boot_thing = return ()++ -- Check that the actual module also defines the thing, and+ -- then compare the definitions+ | Just real_thing <- lookupTypeEnv local_type_env name,+ Just boot_thing <- mb_boot_thing+ = checkBootDeclM True boot_thing real_thing++ | otherwise+ = addErrTc (missingBootThing True name "defined in")+ where+ name = availName boot_avail+ mb_boot_thing = lookupTypeEnv boot_type_env name+ missing_names = case lookupNameEnv local_export_env name of+ Nothing -> [name]+ Just avail -> availNames boot_avail `minusList` availNames avail++ dfun_names = map getName boot_insts++ local_export_env :: NameEnv AvailInfo+ local_export_env = availsToNameEnv local_exports++ check_inst :: ClsInst -> TcM (Maybe (Id, Id))+ -- Returns a pair of the boot dfun in terms of the equivalent+ -- real dfun. Delicate (like checkBootDecl) because it depends+ -- on the types lining up precisely even to the ordering of+ -- the type variables in the foralls.+ check_inst boot_inst+ = case [dfun | inst <- local_insts,+ let dfun = instanceDFunId inst,+ idType dfun `eqType` boot_dfun_ty ] of+ [] -> do { traceTc "check_inst" $ vcat+ [ text "local_insts" <+> vcat (map (ppr . idType . instanceDFunId) local_insts)+ , text "boot_inst" <+> ppr boot_inst+ , text "boot_dfun_ty" <+> ppr boot_dfun_ty+ ]+ ; addErrTc (instMisMatch True boot_inst)+ ; return Nothing }+ (dfun:_) -> return (Just (local_boot_dfun, dfun))+ where+ local_boot_dfun = Id.mkExportedVanillaId boot_dfun_name (idType dfun)+ -- Name from the /boot-file/ ClsInst, but type from the dfun+ -- defined in /this module/. That ensures that the TyCon etc+ -- inside the type are the ones defined in this module, not+ -- the ones gotten from the hi-boot file, which may have+ -- a lot less info (Trac #T8743, comment:10).+ where+ boot_dfun = instanceDFunId boot_inst+ boot_dfun_ty = idType boot_dfun+ boot_dfun_name = idName boot_dfun++-- In general, to perform these checks we have to+-- compare the TyThing from the .hi-boot file to the TyThing+-- in the current source file. We must be careful to allow alpha-renaming+-- where appropriate, and also the boot declaration is allowed to omit+-- constructors and class methods.+--+-- See rnfail055 for a good test of this stuff.++-- | Compares two things for equivalence between boot-file and normal code,+-- reporting an error if they don't match up.+checkBootDeclM :: Bool -- ^ True <=> an hs-boot file (could also be a sig)+ -> TyThing -> TyThing -> TcM ()+checkBootDeclM is_boot boot_thing real_thing+ = whenIsJust (checkBootDecl is_boot boot_thing real_thing) $ \ err ->+ addErrAt span+ (bootMisMatch is_boot err real_thing boot_thing)+ where+ -- Here we use the span of the boot thing or, if it doesn't have a sensible+ -- span, that of the real thing,+ span+ | let span = nameSrcSpan (getName boot_thing)+ , isGoodSrcSpan span+ = span+ | otherwise+ = nameSrcSpan (getName real_thing)++-- | Compares the two things for equivalence between boot-file and normal+-- code. Returns @Nothing@ on success or @Just "some helpful info for user"@+-- failure. If the difference will be apparent to the user, @Just empty@ is+-- perfectly suitable.+checkBootDecl :: Bool -> TyThing -> TyThing -> Maybe SDoc++checkBootDecl _ (AnId id1) (AnId id2)+ = ASSERT(id1 == id2)+ check (idType id1 `eqType` idType id2)+ (text "The two types are different")++checkBootDecl is_boot (ATyCon tc1) (ATyCon tc2)+ = checkBootTyCon is_boot tc1 tc2++checkBootDecl _ (AConLike (RealDataCon dc1)) (AConLike (RealDataCon _))+ = pprPanic "checkBootDecl" (ppr dc1)++checkBootDecl _ _ _ = Just empty -- probably shouldn't happen++-- | Combines two potential error messages+andThenCheck :: Maybe SDoc -> Maybe SDoc -> Maybe SDoc+Nothing `andThenCheck` msg = msg+msg `andThenCheck` Nothing = msg+Just d1 `andThenCheck` Just d2 = Just (d1 $$ d2)+infixr 0 `andThenCheck`++-- | If the test in the first parameter is True, succeed with @Nothing@;+-- otherwise, return the provided check+checkUnless :: Bool -> Maybe SDoc -> Maybe SDoc+checkUnless True _ = Nothing+checkUnless False k = k++-- | Run the check provided for every pair of elements in the lists.+-- The provided SDoc should name the element type, in the plural.+checkListBy :: (a -> a -> Maybe SDoc) -> [a] -> [a] -> SDoc+ -> Maybe SDoc+checkListBy check_fun as bs whats = go [] as bs+ where+ herald = text "The" <+> whats <+> text "do not match"++ go [] [] [] = Nothing+ go docs [] [] = Just (hang (herald <> colon) 2 (vcat $ reverse docs))+ go docs (x:xs) (y:ys) = case check_fun x y of+ Just doc -> go (doc:docs) xs ys+ Nothing -> go docs xs ys+ go _ _ _ = Just (hang (herald <> colon)+ 2 (text "There are different numbers of" <+> whats))++-- | If the test in the first parameter is True, succeed with @Nothing@;+-- otherwise, fail with the given SDoc.+check :: Bool -> SDoc -> Maybe SDoc+check True _ = Nothing+check False doc = Just doc++-- | A more perspicuous name for @Nothing@, for @checkBootDecl@ and friends.+checkSuccess :: Maybe SDoc+checkSuccess = Nothing++----------------+checkBootTyCon :: Bool -> TyCon -> TyCon -> Maybe SDoc+checkBootTyCon is_boot tc1 tc2+ | not (eqType (tyConKind tc1) (tyConKind tc2))+ = Just $ text "The types have different kinds" -- First off, check the kind++ | Just c1 <- tyConClass_maybe tc1+ , Just c2 <- tyConClass_maybe tc2+ , let (clas_tvs1, clas_fds1, sc_theta1, _, ats1, op_stuff1)+ = classExtraBigSig c1+ (clas_tvs2, clas_fds2, sc_theta2, _, ats2, op_stuff2)+ = classExtraBigSig c2+ , Just env <- eqVarBndrs emptyRnEnv2 clas_tvs1 clas_tvs2+ = let+ eqSig (id1, def_meth1) (id2, def_meth2)+ = check (name1 == name2)+ (text "The names" <+> pname1 <+> text "and" <+> pname2 <+>+ text "are different") `andThenCheck`+ check (eqTypeX env op_ty1 op_ty2)+ (text "The types of" <+> pname1 <+>+ text "are different") `andThenCheck`+ if is_boot+ then check (eqMaybeBy eqDM def_meth1 def_meth2)+ (text "The default methods associated with" <+> pname1 <+>+ text "are different")+ else check (subDM op_ty1 def_meth1 def_meth2)+ (text "The default methods associated with" <+> pname1 <+>+ text "are not compatible")+ where+ name1 = idName id1+ name2 = idName id2+ pname1 = quotes (ppr name1)+ pname2 = quotes (ppr name2)+ (_, rho_ty1) = splitForAllTys (idType id1)+ op_ty1 = funResultTy rho_ty1+ (_, rho_ty2) = splitForAllTys (idType id2)+ op_ty2 = funResultTy rho_ty2++ eqAT (ATI tc1 def_ats1) (ATI tc2 def_ats2)+ = checkBootTyCon is_boot tc1 tc2 `andThenCheck`+ check (eqATDef def_ats1 def_ats2)+ (text "The associated type defaults differ")++ eqDM (_, VanillaDM) (_, VanillaDM) = True+ eqDM (_, GenericDM t1) (_, GenericDM t2) = eqTypeX env t1 t2+ eqDM _ _ = False++ -- NB: first argument is from hsig, second is from real impl.+ -- Order of pattern matching matters.+ subDM _ Nothing _ = True+ subDM _ _ Nothing = False+ -- If the hsig wrote:+ --+ -- f :: a -> a+ -- default f :: a -> a+ --+ -- this should be validly implementable using an old-fashioned+ -- vanilla default method.+ subDM t1 (Just (_, GenericDM t2)) (Just (_, VanillaDM))+ = eqTypeX env t1 t2+ -- This case can occur when merging signatures+ subDM t1 (Just (_, VanillaDM)) (Just (_, GenericDM t2))+ = eqTypeX env t1 t2+ subDM _ (Just (_, VanillaDM)) (Just (_, VanillaDM)) = True+ subDM _ (Just (_, GenericDM t1)) (Just (_, GenericDM t2))+ = eqTypeX env t1 t2++ -- Ignore the location of the defaults+ eqATDef Nothing Nothing = True+ eqATDef (Just (ty1, _loc1)) (Just (ty2, _loc2)) = eqTypeX env ty1 ty2+ eqATDef _ _ = False++ eqFD (as1,bs1) (as2,bs2) =+ eqListBy (eqTypeX env) (mkTyVarTys as1) (mkTyVarTys as2) &&+ eqListBy (eqTypeX env) (mkTyVarTys bs1) (mkTyVarTys bs2)+ in+ checkRoles roles1 roles2 `andThenCheck`+ -- Checks kind of class+ check (eqListBy eqFD clas_fds1 clas_fds2)+ (text "The functional dependencies do not match") `andThenCheck`+ checkUnless (isAbstractTyCon tc1) $+ check (eqListBy (eqTypeX env) sc_theta1 sc_theta2)+ (text "The class constraints do not match") `andThenCheck`+ checkListBy eqSig op_stuff1 op_stuff2 (text "methods") `andThenCheck`+ checkListBy eqAT ats1 ats2 (text "associated types") `andThenCheck`+ check (classMinimalDef c1 `BF.implies` classMinimalDef c2)+ (text "The MINIMAL pragmas are not compatible")++ | Just syn_rhs1 <- synTyConRhs_maybe tc1+ , Just syn_rhs2 <- synTyConRhs_maybe tc2+ , Just env <- eqVarBndrs emptyRnEnv2 (tyConTyVars tc1) (tyConTyVars tc2)+ = ASSERT(tc1 == tc2)+ checkRoles roles1 roles2 `andThenCheck`+ check (eqTypeX env syn_rhs1 syn_rhs2) empty -- nothing interesting to say++ -- This allows abstract 'data T a' to be implemented using 'type T = ...'+ -- and abstract 'class K a' to be implement using 'type K = ...'+ -- See Note [Synonyms implement abstract data]+ | not is_boot -- don't support for hs-boot yet+ , isAbstractTyCon tc1+ , Just (tvs, ty) <- synTyConDefn_maybe tc2+ , Just (tc2', args) <- tcSplitTyConApp_maybe ty+ = checkSynAbsData tvs ty tc2' args+ -- TODO: When it's a synonym implementing a class, we really+ -- should check if the fundeps are satisfied, but+ -- there is not an obvious way to do this for a constraint synonym.+ -- So for now, let it all through (it won't cause segfaults, anyway).+ -- Tracked at #12704.++ | Just fam_flav1 <- famTyConFlav_maybe tc1+ , Just fam_flav2 <- famTyConFlav_maybe tc2+ = ASSERT(tc1 == tc2)+ let eqFamFlav OpenSynFamilyTyCon OpenSynFamilyTyCon = True+ eqFamFlav (DataFamilyTyCon {}) (DataFamilyTyCon {}) = True+ -- This case only happens for hsig merging:+ eqFamFlav AbstractClosedSynFamilyTyCon AbstractClosedSynFamilyTyCon = True+ eqFamFlav AbstractClosedSynFamilyTyCon (ClosedSynFamilyTyCon {}) = True+ eqFamFlav (ClosedSynFamilyTyCon {}) AbstractClosedSynFamilyTyCon = True+ eqFamFlav (ClosedSynFamilyTyCon ax1) (ClosedSynFamilyTyCon ax2)+ = eqClosedFamilyAx ax1 ax2+ eqFamFlav (BuiltInSynFamTyCon {}) (BuiltInSynFamTyCon {}) = tc1 == tc2+ eqFamFlav _ _ = False+ injInfo1 = familyTyConInjectivityInfo tc1+ injInfo2 = familyTyConInjectivityInfo tc2+ in+ -- check equality of roles, family flavours and injectivity annotations+ -- (NB: Type family roles are always nominal. But the check is+ -- harmless enough.)+ checkRoles roles1 roles2 `andThenCheck`+ check (eqFamFlav fam_flav1 fam_flav2)+ (ifPprDebug $+ text "Family flavours" <+> ppr fam_flav1 <+> text "and" <+> ppr fam_flav2 <+>+ text "do not match") `andThenCheck`+ check (injInfo1 == injInfo2) (text "Injectivities do not match")++ | isAlgTyCon tc1 && isAlgTyCon tc2+ , Just env <- eqVarBndrs emptyRnEnv2 (tyConTyVars tc1) (tyConTyVars tc2)+ = ASSERT(tc1 == tc2)+ checkRoles roles1 roles2 `andThenCheck`+ check (eqListBy (eqTypeX env)+ (tyConStupidTheta tc1) (tyConStupidTheta tc2))+ (text "The datatype contexts do not match") `andThenCheck`+ eqAlgRhs tc1 (algTyConRhs tc1) (algTyConRhs tc2)++ | otherwise = Just empty -- two very different types -- should be obvious+ where+ roles1 = tyConRoles tc1 -- the abstract one+ roles2 = tyConRoles tc2+ roles_msg = text "The roles do not match." $$+ (text "Roles on abstract types default to" <+>+ quotes (text "representational") <+> text "in boot files.")++ roles_subtype_msg = text "The roles are not compatible:" $$+ text "Main module:" <+> ppr roles2 $$+ text "Hsig file:" <+> ppr roles1++ checkRoles r1 r2+ | is_boot || isInjectiveTyCon tc1 Representational -- See Note [Role subtyping]+ = check (r1 == r2) roles_msg+ | otherwise = check (r2 `rolesSubtypeOf` r1) roles_subtype_msg++ -- Note [Role subtyping]+ -- ~~~~~~~~~~~~~~~~~~~~~+ -- In the current formulation of roles, role subtyping is only OK if the+ -- "abstract" TyCon was not representationally injective. Among the most+ -- notable examples of non representationally injective TyCons are abstract+ -- data, which can be implemented via newtypes (which are not+ -- representationally injective). The key example is+ -- in this example from #13140:+ --+ -- -- In an hsig file+ -- data T a -- abstract!+ -- type role T nominal+ --+ -- -- Elsewhere+ -- foo :: Coercible (T a) (T b) => a -> b+ -- foo x = x+ --+ -- We must NOT allow foo to typecheck, because if we instantiate+ -- T with a concrete data type with a phantom role would cause+ -- Coercible (T a) (T b) to be provable. Fortunately, if T is not+ -- representationally injective, we cannot make the inference that a ~N b if+ -- T a ~R T b.+ --+ -- Unconditional role subtyping would be possible if we setup+ -- an extra set of roles saying when we can project out coercions+ -- (we call these proj-roles); then it would NOT be valid to instantiate T+ -- with a data type at phantom since the proj-role subtyping check+ -- would fail. See #13140 for more details.+ --+ -- One consequence of this is we get no role subtyping for non-abstract+ -- data types in signatures. Suppose you have:+ --+ -- signature A where+ -- type role T nominal+ -- data T a = MkT+ --+ -- If you write this, we'll treat T as injective, and make inferences+ -- like T a ~R T b ==> a ~N b (mkNthCo). But if we can+ -- subsequently replace T with one at phantom role, we would then be able to+ -- infer things like T Int ~R T Bool which is bad news.+ --+ -- We could allow role subtyping here if we didn't treat *any* data types+ -- defined in signatures as injective. But this would be a bit surprising,+ -- replacing a data type in a module with one in a signature could cause+ -- your code to stop typechecking (whereas if you made the type abstract,+ -- it is more understandable that the type checker knows less).+ --+ -- It would have been best if this was purely a question of defaults+ -- (i.e., a user could explicitly ask for one behavior or another) but+ -- the current role system isn't expressive enough to do this.+ -- Having explict proj-roles would solve this problem.++ rolesSubtypeOf [] [] = True+ -- NB: this relation is the OPPOSITE of the subroling relation+ rolesSubtypeOf (x:xs) (y:ys) = x >= y && rolesSubtypeOf xs ys+ rolesSubtypeOf _ _ = False++ -- Note [Synonyms implement abstract data]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- An abstract data type or class can be implemented using a type synonym,+ -- but ONLY if the type synonym is nullary and has no type family+ -- applications. This arises from two properties of skolem abstract data:+ --+ -- For any T (with some number of paramaters),+ --+ -- 1. T is a valid type (it is "curryable"), and+ --+ -- 2. T is valid in an instance head (no type families).+ --+ -- See also 'HowAbstract' and Note [Skolem abstract data].++ -- | Given @type T tvs = ty@, where @ty@ decomposes into @tc2' args@,+ -- check that this synonym is an acceptable implementation of @tc1@.+ -- See Note [Synonyms implement abstract data]+ checkSynAbsData :: [TyVar] -> Type -> TyCon -> [Type] -> Maybe SDoc+ checkSynAbsData tvs ty tc2' args =+ check (null (tcTyFamInsts ty))+ (text "Illegal type family application in implementation of abstract data.")+ `andThenCheck`+ check (null tvs)+ (text "Illegal parameterized type synonym in implementation of abstract data." $$+ text "(Try eta reducing your type synonym so that it is nullary.)")+ `andThenCheck`+ -- Don't report roles errors unless the type synonym is nullary+ checkUnless (not (null tvs)) $+ ASSERT( null roles2 )+ -- If we have something like:+ --+ -- signature H where+ -- data T a+ -- module H where+ -- data K a b = ...+ -- type T = K Int+ --+ -- we need to drop the first role of K when comparing!+ checkRoles roles1 (drop (length args) (tyConRoles tc2'))+{-+ -- Hypothetically, if we were allow to non-nullary type synonyms, here+ -- is how you would check the roles+ if length tvs == length roles1+ then checkRoles roles1 roles2+ else case tcSplitTyConApp_maybe ty of+ Just (tc2', args) ->+ checkRoles roles1 (drop (length args) (tyConRoles tc2') ++ roles2)+ Nothing -> Just roles_msg+-}++ 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")+ eqAlgRhs _ tc1@NewTyCon{} tc2@NewTyCon{} =+ eqCon (data_con tc1) (data_con tc2)+ eqAlgRhs _ _ _ = Just (text "Cannot match a" <+> quotes (text "data") <+>+ text "definition with a" <+> quotes (text "newtype") <+>+ text "definition")++ eqCon c1 c2+ = check (name1 == name2)+ (text "The names" <+> pname1 <+> text "and" <+> pname2 <+>+ text "differ") `andThenCheck`+ check (dataConIsInfix c1 == dataConIsInfix c2)+ (text "The fixities of" <+> pname1 <+>+ text "differ") `andThenCheck`+ check (eqListBy eqHsBang (dataConImplBangs c1) (dataConImplBangs c2))+ (text "The strictness annotations for" <+> pname1 <+>+ text "differ") `andThenCheck`+ check (map flSelector (dataConFieldLabels c1) == map flSelector (dataConFieldLabels c2))+ (text "The record label lists for" <+> pname1 <+>+ text "differ") `andThenCheck`+ check (eqType (dataConUserType c1) (dataConUserType c2))+ (text "The types for" <+> pname1 <+> text "differ")+ where+ name1 = dataConName c1+ name2 = dataConName c2+ pname1 = quotes (ppr name1)+ pname2 = quotes (ppr name2)++ eqClosedFamilyAx Nothing Nothing = True+ eqClosedFamilyAx Nothing (Just _) = False+ eqClosedFamilyAx (Just _) Nothing = False+ eqClosedFamilyAx (Just (CoAxiom { co_ax_branches = branches1 }))+ (Just (CoAxiom { co_ax_branches = branches2 }))+ = numBranches branches1 == numBranches branches2+ && (and $ zipWith eqClosedFamilyBranch branch_list1 branch_list2)+ where+ branch_list1 = fromBranches branches1+ branch_list2 = fromBranches branches2++ eqClosedFamilyBranch (CoAxBranch { cab_tvs = tvs1, cab_cvs = cvs1+ , cab_lhs = lhs1, cab_rhs = rhs1 })+ (CoAxBranch { cab_tvs = tvs2, cab_cvs = cvs2+ , cab_lhs = lhs2, cab_rhs = rhs2 })+ | Just env1 <- eqVarBndrs emptyRnEnv2 tvs1 tvs2+ , Just env <- eqVarBndrs env1 cvs1 cvs2+ = eqListBy (eqTypeX env) lhs1 lhs2 &&+ eqTypeX env rhs1 rhs2++ | otherwise = False++emptyRnEnv2 :: RnEnv2+emptyRnEnv2 = mkRnEnv2 emptyInScopeSet++----------------+missingBootThing :: Bool -> Name -> String -> SDoc+missingBootThing is_boot name what+ = quotes (ppr name) <+> text "is exported by the"+ <+> (if is_boot then text "hs-boot" else text "hsig")+ <+> text "file, but not"+ <+> text what <+> text "the module"++badReexportedBootThing :: DynFlags -> Bool -> Name -> Name -> SDoc+badReexportedBootThing dflags is_boot name name'+ = withPprStyle (mkUserStyle dflags alwaysQualify AllTheWay) $ vcat+ [ text "The" <+> (if is_boot then text "hs-boot" else text "hsig")+ <+> text "file (re)exports" <+> quotes (ppr name)+ , text "but the implementing module exports a different identifier" <+> quotes (ppr name')+ ]++bootMisMatch :: Bool -> SDoc -> TyThing -> TyThing -> SDoc+bootMisMatch is_boot extra_info real_thing boot_thing+ = pprBootMisMatch is_boot extra_info real_thing real_doc boot_doc+ where+ to_doc+ = pprTyThingInContext $ showToHeader { ss_forall =+ if is_boot+ then ShowForAllMust+ else ShowForAllWhen }++ real_doc = to_doc real_thing+ boot_doc = to_doc boot_thing++ pprBootMisMatch :: Bool -> SDoc -> TyThing -> SDoc -> SDoc -> SDoc+ pprBootMisMatch is_boot extra_info real_thing real_doc boot_doc+ = vcat+ [ ppr real_thing <+>+ text "has conflicting definitions in the module",+ text "and its" <+>+ (if is_boot+ then text "hs-boot file"+ else text "hsig file"),+ text "Main module:" <+> real_doc,+ (if is_boot+ then text "Boot file: "+ else text "Hsig file: ")+ <+> boot_doc,+ extra_info+ ]++instMisMatch :: Bool -> ClsInst -> SDoc+instMisMatch is_boot inst+ = hang (ppr inst)+ 2 (text "is defined in the" <+>+ (if is_boot then text "hs-boot" else text "hsig")+ <+> text "file, but not in the module itself")++{-+************************************************************************+* *+ Type-checking the top level of a module (continued)+* *+************************************************************************+-}++rnTopSrcDecls :: HsGroup RdrName -> TcM (TcGblEnv, HsGroup Name)+-- Fails if there are any errors+rnTopSrcDecls group+ = do { -- Rename the source decls+ traceRn "rn12" empty ;+ (tcg_env, rn_decls) <- checkNoErrs $ rnSrcDecls group ;+ traceRn "rn13" empty ;++ -- save the renamed syntax, if we want it+ let { tcg_env'+ | Just grp <- tcg_rn_decls tcg_env+ = tcg_env{ tcg_rn_decls = Just (appendGroups grp rn_decls) }+ | otherwise+ = tcg_env };++ -- Dump trace of renaming part+ rnDump rn_decls ;+ return (tcg_env', rn_decls)+ }++tcTopSrcDecls :: HsGroup Name -> TcM (TcGblEnv, TcLclEnv)+tcTopSrcDecls (HsGroup { hs_tyclds = tycl_decls,+ hs_derivds = deriv_decls,+ hs_fords = foreign_decls,+ hs_defds = default_decls,+ hs_annds = annotation_decls,+ hs_ruleds = rule_decls,+ hs_vects = vect_decls,+ hs_valds = hs_val_binds@(ValBindsOut val_binds val_sigs) })+ = do { -- Type-check the type and class decls, and all imported decls+ -- The latter come in via tycl_decls+ traceTc "Tc2 (src)" empty ;++ -- Source-language instances, including derivings,+ -- and import the supporting declarations+ traceTc "Tc3" empty ;+ (tcg_env, inst_infos, ValBindsOut deriv_binds deriv_sigs)+ <- tcTyClsInstDecls tycl_decls deriv_decls val_binds ;++ setGblEnv tcg_env $ do {++ -- Generate Applicative/Monad proposal (AMP) warnings+ traceTc "Tc3b" empty ;++ -- Generate Semigroup/Monoid warnings+ traceTc "Tc3c" empty ;+ tcSemigroupWarnings ;++ -- Foreign import declarations next.+ traceTc "Tc4" empty ;+ (fi_ids, fi_decls, fi_gres) <- tcForeignImports foreign_decls ;+ tcExtendGlobalValEnv fi_ids $ do {++ -- Default declarations+ traceTc "Tc4a" empty ;+ default_tys <- tcDefaults default_decls ;+ updGblEnv (\gbl -> gbl { tcg_default = default_tys }) $ do {++ -- Value declarations next.+ -- It is important that we check the top-level value bindings+ -- before the GHC-generated derived bindings, since the latter+ -- may be defined in terms of the former. (For instance,+ -- the bindings produced in a Data instance.)+ traceTc "Tc5" empty ;+ tc_envs <- tcTopBinds val_binds val_sigs;+ setEnvs tc_envs $ do {++ -- Now GHC-generated derived bindings, generics, and selectors+ -- Do not generate warnings from compiler-generated code;+ -- hence the use of discardWarnings+ tc_envs@(tcg_env, tcl_env)+ <- discardWarnings (tcTopBinds deriv_binds deriv_sigs) ;+ setEnvs tc_envs $ do { -- Environment doesn't change now++ -- Second pass over class and instance declarations,+ -- now using the kind-checked decls+ traceTc "Tc6" empty ;+ inst_binds <- tcInstDecls2 (tyClGroupTyClDecls tycl_decls) inst_infos ;++ -- Foreign exports+ traceTc "Tc7" empty ;+ (foe_binds, foe_decls, foe_gres) <- tcForeignExports foreign_decls ;++ -- Annotations+ annotations <- tcAnnotations annotation_decls ;++ -- Rules+ rules <- tcRules rule_decls ;++ -- Vectorisation declarations+ vects <- tcVectDecls vect_decls ;++ -- Wrap up+ traceTc "Tc7a" empty ;+ let { all_binds = inst_binds `unionBags`+ foe_binds++ ; fo_gres = fi_gres `unionBags` foe_gres+ ; fo_fvs = foldrBag (\gre fvs -> fvs `addOneFV` gre_name gre)+ emptyFVs fo_gres++ ; sig_names = mkNameSet (collectHsValBinders hs_val_binds)+ `minusNameSet` getTypeSigNames val_sigs++ -- Extend the GblEnv with the (as yet un-zonked)+ -- bindings, rules, foreign decls+ ; tcg_env' = tcg_env { tcg_binds = tcg_binds tcg_env `unionBags` all_binds+ , tcg_sigs = tcg_sigs tcg_env `unionNameSet` sig_names+ , tcg_rules = tcg_rules tcg_env+ ++ flattenRuleDecls rules+ , tcg_vects = tcg_vects tcg_env ++ vects+ , tcg_anns = tcg_anns tcg_env ++ annotations+ , tcg_ann_env = extendAnnEnvList (tcg_ann_env tcg_env) annotations+ , tcg_fords = tcg_fords tcg_env ++ foe_decls ++ fi_decls+ , tcg_dus = tcg_dus tcg_env `plusDU` usesOnly fo_fvs } } ;+ -- tcg_dus: see Note [Newtype constructor usage in foreign declarations]++ -- See Note [Newtype constructor usage in foreign declarations]+ addUsedGREs (bagToList fo_gres) ;++ return (tcg_env', tcl_env)+ }}}}}}++tcTopSrcDecls _ = panic "tcTopSrcDecls: ValBindsIn"+++tcSemigroupWarnings :: TcM ()+tcSemigroupWarnings = do+ traceTc "tcSemigroupWarnings" empty+ let warnFlag = Opt_WarnSemigroup+ tcPreludeClashWarn warnFlag sappendName+ tcMissingParentClassWarn warnFlag monoidClassName semigroupClassName+++-- | Warn on local definitions of names that would clash with future Prelude+-- elements.+--+-- A name clashes if the following criteria are met:+-- 1. It would is imported (unqualified) from Prelude+-- 2. It is locally defined in the current module+-- 3. It has the same literal name as the reference function+-- 4. It is not identical to the reference function+tcPreludeClashWarn :: WarningFlag+ -> Name+ -> TcM ()+tcPreludeClashWarn warnFlag name = do+ { warn <- woptM warnFlag+ ; when warn $ do+ { traceTc "tcPreludeClashWarn/wouldBeImported" empty+ -- Is the name imported (unqualified) from Prelude? (Point 4 above)+ ; rnImports <- fmap (map unLoc . tcg_rn_imports) getGblEnv+ -- (Note that this automatically handles -XNoImplicitPrelude, as Prelude+ -- will not appear in rnImports automatically if it is set.)++ -- Continue only the name is imported from Prelude+ ; when (importedViaPrelude name rnImports) $ do+ -- Handle 2.-4.+ { rdrElts <- fmap (concat . occEnvElts . tcg_rdr_env) getGblEnv++ ; let clashes :: GlobalRdrElt -> Bool+ clashes x = isLocalDef && nameClashes && isNotInProperModule+ where+ isLocalDef = gre_lcl x == True+ -- Names are identical ...+ nameClashes = nameOccName (gre_name x) == nameOccName name+ -- ... but not the actual definitions, because we don't want to+ -- warn about a bad definition of e.g. <> in Data.Semigroup, which+ -- is the (only) proper place where this should be defined+ isNotInProperModule = gre_name x /= name++ -- List of all offending definitions+ clashingElts :: [GlobalRdrElt]+ clashingElts = filter clashes rdrElts++ ; traceTc "tcPreludeClashWarn/prelude_functions"+ (hang (ppr name) 4 (sep [ppr clashingElts]))++ ; let warn_msg x = addWarnAt (Reason warnFlag) (nameSrcSpan (gre_name x)) (hsep+ [ text "Local definition of"+ , (quotes . ppr . nameOccName . gre_name) x+ , text "clashes with a future Prelude name." ]+ $$+ text "This will become an error in a future release." )+ ; mapM_ warn_msg clashingElts+ }}}++ where++ -- Is the given name imported via Prelude?+ --+ -- Possible scenarios:+ -- a) Prelude is imported implicitly, issue warnings.+ -- b) Prelude is imported explicitly, but without mentioning the name in+ -- question. Issue no warnings.+ -- c) Prelude is imported hiding the name in question. Issue no warnings.+ -- d) Qualified import of Prelude, no warnings.+ importedViaPrelude :: Name+ -> [ImportDecl Name]+ -> Bool+ importedViaPrelude name = any importViaPrelude+ where+ isPrelude :: ImportDecl Name -> Bool+ isPrelude imp = unLoc (ideclName imp) == pRELUDE_NAME++ -- Implicit (Prelude) import?+ isImplicit :: ImportDecl Name -> Bool+ isImplicit = ideclImplicit++ -- Unqualified import?+ isUnqualified :: ImportDecl Name -> Bool+ isUnqualified = not . ideclQualified++ -- List of explicitly imported (or hidden) Names from a single import.+ -- Nothing -> No explicit imports+ -- Just (False, <names>) -> Explicit import list of <names>+ -- Just (True , <names>) -> Explicit hiding of <names>+ importListOf :: ImportDecl Name -> Maybe (Bool, [Name])+ importListOf = fmap toImportList . ideclHiding+ where+ toImportList (h, loc) = (h, map (ieName . unLoc) (unLoc loc))++ isExplicit :: ImportDecl Name -> Bool+ isExplicit x = case importListOf x of+ Nothing -> False+ Just (False, explicit)+ -> nameOccName name `elem` map nameOccName explicit+ Just (True, hidden)+ -> nameOccName name `notElem` map nameOccName hidden++ -- Check whether the given name would be imported (unqualified) from+ -- an import declaration.+ importViaPrelude :: ImportDecl Name -> Bool+ importViaPrelude x = isPrelude x+ && isUnqualified x+ && (isImplicit x || isExplicit x)+++-- Notation: is* is for classes the type is an instance of, should* for those+-- that it should also be an instance of based on the corresponding+-- is*.+tcMissingParentClassWarn :: WarningFlag+ -> Name -- ^ Instances of this ...+ -> Name -- ^ should also be instances of this+ -> TcM ()+tcMissingParentClassWarn warnFlag isName shouldName+ = do { warn <- woptM warnFlag+ ; when warn $ do+ { traceTc "tcMissingParentClassWarn" empty+ ; isClass' <- tcLookupClass_maybe isName+ ; shouldClass' <- tcLookupClass_maybe shouldName+ ; case (isClass', shouldClass') of+ (Just isClass, Just shouldClass) -> do+ { localInstances <- tcGetInsts+ ; let isInstance m = is_cls m == isClass+ isInsts = filter isInstance localInstances+ ; traceTc "tcMissingParentClassWarn/isInsts" (ppr isInsts)+ ; forM_ isInsts (checkShouldInst isClass shouldClass)+ }+ (is',should') ->+ traceTc "tcMissingParentClassWarn/notIsShould"+ (hang (ppr isName <> text "/" <> ppr shouldName) 2 (+ (hsep [ quotes (text "Is"), text "lookup for"+ , ppr isName+ , text "resulted in", ppr is' ])+ $$+ (hsep [ quotes (text "Should"), text "lookup for"+ , ppr shouldName+ , text "resulted in", ppr should' ])))+ }}+ where+ -- Check whether the desired superclass exists in a given environment.+ checkShouldInst :: Class -- ^ Class of existing instance+ -> Class -- ^ Class there should be an instance of+ -> ClsInst -- ^ Existing instance+ -> TcM ()+ checkShouldInst isClass shouldClass isInst+ = do { instEnv <- tcGetInstEnvs+ ; let (instanceMatches, shouldInsts, _)+ = lookupInstEnv False instEnv shouldClass (is_tys isInst)++ ; traceTc "tcMissingParentClassWarn/checkShouldInst"+ (hang (ppr isInst) 4+ (sep [ppr instanceMatches, ppr shouldInsts]))++ -- "<location>: Warning: <type> is an instance of <is> but not+ -- <should>" e.g. "Foo is an instance of Monad but not Applicative"+ ; let instLoc = srcLocSpan . nameSrcLoc $ getName isInst+ warnMsg (Just name:_) =+ addWarnAt (Reason warnFlag) instLoc $+ hsep [ (quotes . ppr . nameOccName) name+ , text "is an instance of"+ , (ppr . nameOccName . className) isClass+ , text "but not"+ , (ppr . nameOccName . className) shouldClass ]+ <> text "."+ $$+ hsep [ text "This will become an error in"+ , text "a future release." ]+ warnMsg _ = pure ()+ ; when (null shouldInsts && null instanceMatches) $+ warnMsg (is_tcs isInst)+ }++ tcLookupClass_maybe :: Name -> TcM (Maybe Class)+ tcLookupClass_maybe name = tcLookupImported_maybe name >>= \case+ Succeeded (ATyCon tc) | cls@(Just _) <- tyConClass_maybe tc -> pure cls+ _else -> pure Nothing+++---------------------------+tcTyClsInstDecls :: [TyClGroup Name]+ -> [LDerivDecl Name]+ -> [(RecFlag, LHsBinds Name)]+ -> TcM (TcGblEnv, -- The full inst env+ [InstInfo Name], -- Source-code instance decls to process;+ -- contains all dfuns for this module+ HsValBinds Name) -- Supporting bindings for derived instances++tcTyClsInstDecls tycl_decls deriv_decls binds+ = tcAddDataFamConPlaceholders (tycl_decls >>= group_instds) $+ tcAddPatSynPlaceholders (getPatSynBinds binds) $+ do { (tcg_env, inst_info, datafam_deriv_info)+ <- tcTyAndClassDecls tycl_decls ;+ ; setGblEnv tcg_env $ do {+ -- With the @TyClDecl@s and @InstDecl@s checked we're ready to+ -- process the deriving clauses, including data family deriving+ -- clauses discovered in @tcTyAndClassDecls@.+ --+ -- Careful to quit now in case there were instance errors, so that+ -- the deriving errors don't pile up as well.+ ; failIfErrsM+ ; let tyclds = tycl_decls >>= group_tyclds+ ; (tcg_env', inst_info', val_binds)+ <- tcInstDeclsDeriv datafam_deriv_info tyclds deriv_decls+ ; setGblEnv tcg_env' $ do {+ failIfErrsM+ ; pure (tcg_env', inst_info' ++ inst_info, val_binds)+ }}}++{- *********************************************************************+* *+ Checking for 'main'+* *+************************************************************************+-}++checkMain :: Bool -- False => no 'module M(..) where' header at all+ -> TcM TcGblEnv+-- If we are in module Main, check that 'main' is defined.+checkMain explicit_mod_hdr+ = do { dflags <- getDynFlags+ ; tcg_env <- getGblEnv+ ; check_main dflags tcg_env explicit_mod_hdr }++check_main :: DynFlags -> TcGblEnv -> Bool -> TcM TcGblEnv+check_main dflags tcg_env explicit_mod_hdr+ | mod /= main_mod+ = traceTc "checkMain not" (ppr main_mod <+> ppr mod) >>+ return tcg_env++ | otherwise+ = do { mb_main <- lookupGlobalOccRn_maybe main_fn+ -- Check that 'main' is in scope+ -- It might be imported from another module!+ ; case mb_main of {+ Nothing -> do { traceTc "checkMain fail" (ppr main_mod <+> ppr main_fn)+ ; complain_no_main+ ; return tcg_env } ;+ Just main_name -> do++ { traceTc "checkMain found" (ppr main_mod <+> ppr main_fn)+ ; let loc = srcLocSpan (getSrcLoc main_name)+ ; ioTyCon <- tcLookupTyCon ioTyConName+ ; res_ty <- newFlexiTyVarTy liftedTypeKind+ ; let io_ty = mkTyConApp ioTyCon [res_ty]+ skol_info = SigSkol (FunSigCtxt main_name False) io_ty []+ ; (ev_binds, main_expr)+ <- checkConstraints skol_info [] [] $+ addErrCtxt mainCtxt $+ tcMonoExpr (L loc (HsVar (L loc main_name)))+ (mkCheckExpType io_ty)++ -- See Note [Root-main Id]+ -- Construct the binding+ -- :Main.main :: IO res_ty = runMainIO res_ty main+ ; run_main_id <- tcLookupId runMainIOName+ ; let { root_main_name = mkExternalName rootMainKey rOOT_MAIN+ (mkVarOccFS (fsLit "main"))+ (getSrcSpan main_name)+ ; root_main_id = Id.mkExportedVanillaId root_main_name+ (mkTyConApp ioTyCon [res_ty])+ ; co = mkWpTyApps [res_ty]+ ; rhs = mkHsDictLet ev_binds $+ nlHsApp (mkLHsWrap co (nlHsVar run_main_id)) main_expr+ ; main_bind = mkVarBind root_main_id rhs }++ ; return (tcg_env { tcg_main = Just main_name,+ tcg_binds = tcg_binds tcg_env+ `snocBag` main_bind,+ tcg_dus = tcg_dus tcg_env+ `plusDU` usesOnly (unitFV main_name)+ -- Record the use of 'main', so that we don't+ -- complain about it being defined but not used+ })+ }}}+ where+ mod = tcg_mod tcg_env+ main_mod = mainModIs dflags+ main_fn = getMainFun dflags+ interactive = ghcLink dflags == LinkInMemory++ complain_no_main = checkTc (interactive && not explicit_mod_hdr) noMainMsg+ -- In interactive mode, without an explicit module header, don't+ -- worry about the absence of 'main'.+ -- In other modes, fail altogether, so that we don't go on+ -- and complain a second time when processing the export list.++ mainCtxt = text "When checking the type of the" <+> pp_main_fn+ noMainMsg = text "The" <+> pp_main_fn+ <+> text "is not defined in module" <+> quotes (ppr main_mod)+ pp_main_fn = ppMainFn main_fn++-- | Get the unqualified name of the function to use as the \"main\" for the main module.+-- Either returns the default name or the one configured on the command line with -main-is+getMainFun :: DynFlags -> RdrName+getMainFun dflags = case mainFunIs dflags of+ Just fn -> mkRdrUnqual (mkVarOccFS (mkFastString fn))+ Nothing -> main_RDR_Unqual++-- If we are in module Main, check that 'main' is exported.+checkMainExported :: TcGblEnv -> TcM ()+checkMainExported tcg_env+ = case tcg_main tcg_env of+ Nothing -> return () -- not the main module+ Just main_name ->+ do { dflags <- getDynFlags+ ; let main_mod = mainModIs dflags+ ; checkTc (main_name `elem` concatMap availNames (tcg_exports tcg_env)) $+ text "The" <+> ppMainFn (nameRdrName main_name) <+>+ text "is not exported by module" <+> quotes (ppr main_mod) }++ppMainFn :: RdrName -> SDoc+ppMainFn main_fn+ | rdrNameOcc main_fn == mainOcc+ = text "IO action" <+> quotes (ppr main_fn)+ | otherwise+ = text "main IO action" <+> quotes (ppr main_fn)++mainOcc :: OccName+mainOcc = mkVarOccFS (fsLit "main")++{-+Note [Root-main Id]+~~~~~~~~~~~~~~~~~~~+The function that the RTS invokes is always :Main.main, which we call+root_main_id. (Because GHC allows the user to have a module not+called Main as the main module, we can't rely on the main function+being called "Main.main". That's why root_main_id has a fixed module+":Main".)++This is unusual: it's a LocalId whose Name has a Module from another+module. Tiresomely, we must filter it out again in MkIface, les we+get two defns for 'main' in the interface file!+++*********************************************************+* *+ GHCi stuff+* *+*********************************************************+-}++runTcInteractive :: HscEnv -> TcRn a -> IO (Messages, Maybe a)+-- 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 $+ 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 <- occEnvElts (ic_rn_gbl_env icxt)+ , let local_gres = filter isLocalGRE gres+ , not (null local_gres) ]) ]+ ; let getOrphans m = fmap (\iface -> mi_module iface+ : dep_orphs (mi_deps iface))+ (loadSrcInterface (text "runTcInteractive") m+ False Nothing)+ ; orphs <- fmap concat . forM (ic_imports icxt) $ \i ->+ case i of+ IIModule n -> getOrphans n+ IIDecl i -> getOrphans (unLoc (ideclName i))+ ; let imports = emptyImportAvails {+ imp_orphs = orphs+ }+ ; (gbl_env, lcl_env) <- getEnvs+ ; let gbl_env' = gbl_env {+ tcg_rdr_env = ic_rn_gbl_env icxt+ , tcg_type_env = type_env+ , tcg_inst_env = extendInstEnvList+ (extendInstEnvList (tcg_inst_env gbl_env) ic_insts)+ home_insts+ , tcg_fam_inst_env = extendFamInstEnvList+ (extendFamInstEnvList (tcg_fam_inst_env gbl_env)+ ic_finsts)+ home_fam_insts+ , tcg_field_env = mkNameEnv con_fields+ -- setting tcg_field_env is necessary+ -- to make RecordWildCards work (test: ghci049)+ , tcg_fix_env = ic_fix_env icxt+ , tcg_default = ic_default icxt+ -- must calculate imp_orphs of the ImportAvails+ -- so that instance visibility is done correctly+ , tcg_imports = imports+ }++ ; lcl_env' <- tcExtendLocalTypeEnv lcl_env lcl_ids+ ; setEnvs (gbl_env', lcl_env') thing_inside }+ where+ (home_insts, home_fam_insts) = hptInstances hsc_env (\_ -> True)++ icxt = hsc_IC hsc_env+ (ic_insts, ic_finsts) = ic_instances icxt+ (lcl_ids, top_ty_things) = partitionWith is_closed (ic_tythings icxt)++ is_closed :: TyThing -> Either (Name, TcTyThing) TyThing+ -- Put Ids with free type variables (always RuntimeUnks)+ -- in the *local* type environment+ -- See Note [Initialising the type environment for GHCi]+ is_closed thing+ | AnId id <- thing+ , not (isTypeClosedLetBndr id)+ = Left (idName id, ATcId { tct_id = id+ , tct_info = NotLetBound })+ | otherwise+ = Right thing++ type_env1 = mkTypeEnvWithImplicits top_ty_things+ type_env = extendTypeEnvWithIds type_env1 (map instanceDFunId ic_insts)+ -- Putting the dfuns in the type_env+ -- is just to keep Core Lint happy++ con_fields = [ (dataConName c, dataConFieldLabels c)+ | ATyCon t <- top_ty_things+ , c <- tyConDataCons t ]+++{- Note [Initialising the type environment for GHCi]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Most of the the Ids in ic_things, defined by the user in 'let' stmts,+have closed types. E.g.+ ghci> let foo x y = x && not y++However the GHCi debugger creates top-level bindings for Ids whose+types have free RuntimeUnk skolem variables, standing for unknown+types. If we don't register these free TyVars as global TyVars then+the typechecker will try to quantify over them and fall over in+zonkQuantifiedTyVar. so we must add any free TyVars to the+typechecker's global TyVar set. That is most conveniently by using+tcExtendLocalTypeEnv, which automatically extends the global TyVar+set.++We do this by splitting out the Ids with open types, using 'is_closed'+to do the partition. The top-level things go in the global TypeEnv;+the open, NotTopLevel, Ids, with free RuntimeUnk tyvars, go in the+local TypeEnv.++Note that we don't extend the local RdrEnv (tcl_rdr); all the in-scope+things are already in the interactive context's GlobalRdrEnv.+Extending the local RdrEnv isn't terrible, but it means there is an+entry for the same Name in both global and local RdrEnvs, and that+lead to duplicate "perhaps you meant..." suggestions (e.g. T5564).++We don't bother with the tcl_th_bndrs environment either.+-}++-- | The returned [Id] is the list of new Ids bound by this statement. It can+-- be used to extend the InteractiveContext via extendInteractiveContext.+--+-- The returned TypecheckedHsExpr is of type IO [ () ], a list of the bound+-- values, coerced to ().+tcRnStmt :: HscEnv -> GhciLStmt RdrName+ -> IO (Messages, Maybe ([Id], LHsExpr Id, FixityEnv))+tcRnStmt hsc_env rdr_stmt+ = runTcInteractive hsc_env $ do {++ -- The real work is done here+ ((bound_ids, tc_expr), fix_env) <- tcUserStmt rdr_stmt ;+ zonked_expr <- zonkTopLExpr tc_expr ;+ zonked_ids <- zonkTopBndrs bound_ids ;++ failIfErrsM ; -- we can't do the next step if there are levity polymorphism errors+ -- test case: ghci/scripts/T13202{,a}++ -- None of the Ids should be of unboxed type, because we+ -- cast them all to HValues in the end!+ mapM_ bad_unboxed (filter (isUnliftedType . idType) zonked_ids) ;++ traceTc "tcs 1" empty ;+ this_mod <- getModule ;+ global_ids <- mapM (externaliseAndTidyId this_mod) zonked_ids ;+ -- Note [Interactively-bound Ids in GHCi] in HscTypes++{- ---------------------------------------------+ At one stage I removed any shadowed bindings from the type_env;+ they are inaccessible but might, I suppose, cause a space leak if we leave them there.+ However, with Template Haskell they aren't necessarily inaccessible. Consider this+ GHCi session+ Prelude> let f n = n * 2 :: Int+ Prelude> fName <- runQ [| f |]+ Prelude> $(return $ AppE fName (LitE (IntegerL 7)))+ 14+ Prelude> let f n = n * 3 :: Int+ Prelude> $(return $ AppE fName (LitE (IntegerL 7)))+ In the last line we use 'fName', which resolves to the *first* 'f'+ in scope. If we delete it from the type env, GHCi crashes because+ it doesn't expect that.++ Hence this code is commented out++-------------------------------------------------- -}++ traceOptTcRn Opt_D_dump_tc+ (vcat [text "Bound Ids" <+> pprWithCommas ppr global_ids,+ text "Typechecked expr" <+> ppr zonked_expr]) ;++ return (global_ids, zonked_expr, fix_env)+ }+ where+ bad_unboxed id = addErr (sep [text "GHCi can't bind a variable of unlifted type:",+ nest 2 (ppr id <+> dcolon <+> ppr (idType id))])++{-+--------------------------------------------------------------------------+ Typechecking Stmts in GHCi++Here is the grand plan, implemented in tcUserStmt++ What you type The IO [HValue] that hscStmt returns+ ------------- ------------------------------------+ let pat = expr ==> let pat = expr in return [coerce HVal x, coerce HVal y, ...]+ bindings: [x,y,...]++ pat <- expr ==> expr >>= \ pat -> return [coerce HVal x, coerce HVal y, ...]+ bindings: [x,y,...]++ expr (of IO type) ==> expr >>= \ it -> return [coerce HVal it]+ [NB: result not printed] bindings: [it]++ expr (of non-IO type, ==> let it = expr in print it >> return [coerce HVal it]+ result showable) bindings: [it]++ expr (of non-IO type,+ result not showable) ==> error+-}++-- | A plan is an attempt to lift some code into the IO monad.+type PlanResult = ([Id], LHsExpr Id)+type Plan = TcM PlanResult++-- | Try the plans in order. If one fails (by raising an exn), try the next.+-- If one succeeds, take it.+runPlans :: [Plan] -> TcM PlanResult+runPlans [] = panic "runPlans"+runPlans [p] = p+runPlans (p:ps) = tryTcDiscardingErrs (runPlans ps) p++-- | Typecheck (and 'lift') a stmt entered by the user in GHCi into the+-- GHCi 'environment'.+--+-- By 'lift' and 'environment we mean that the code is changed to+-- execute properly in an IO monad. See Note [Interactively-bound Ids+-- in GHCi] in HscTypes for more details. We do this lifting by trying+-- different ways ('plans') of lifting the code into the IO monad and+-- type checking each plan until one succeeds.+tcUserStmt :: GhciLStmt RdrName -> TcM (PlanResult, FixityEnv)++-- An expression typed at the prompt is treated very specially+tcUserStmt (L loc (BodyStmt expr _ _ _))+ = do { (rn_expr, fvs) <- checkNoErrs (rnLExpr expr)+ -- Don't try to typecheck if the renamer fails!+ ; ghciStep <- getGhciStepIO+ ; uniq <- newUnique+ ; interPrintName <- getInteractivePrintName+ ; let fresh_it = itName uniq loc+ matches = [mkMatch (mkPrefixFunRhs (L loc fresh_it)) [] rn_expr+ (noLoc emptyLocalBinds)]+ -- [it = expr]+ the_bind = L loc $ (mkTopFunBind FromSource (L loc fresh_it) matches) { bind_fvs = fvs }+ -- Care here! In GHCi the expression might have+ -- free variables, and they in turn may have free type variables+ -- (if we are at a breakpoint, say). We must put those free vars++ -- [let it = expr]+ let_stmt = L loc $ LetStmt $ noLoc $ HsValBinds $+ ValBindsOut [(NonRecursive,unitBag the_bind)] []++ -- [it <- e]+ bind_stmt = L loc $ BindStmt (L loc (VarPat (L loc fresh_it)))+ (nlHsApp ghciStep rn_expr)+ (mkRnSyntaxExpr bindIOName)+ noSyntaxExpr+ PlaceHolder++ -- [; print it]+ print_it = L loc $ BodyStmt (nlHsApp (nlHsVar interPrintName) (nlHsVar fresh_it))+ (mkRnSyntaxExpr thenIOName)+ noSyntaxExpr placeHolderType++ -- The plans are:+ -- A. [it <- e; print it] but not if it::()+ -- B. [it <- e]+ -- C. [let it = e; print it]+ --+ -- Ensure that type errors don't get deferred when type checking the+ -- naked expression. Deferring type errors here is unhelpful because the+ -- expression gets evaluated right away anyway. It also would potentially+ -- emit two redundant type-error warnings, one from each plan.+ ; plan <- unsetGOptM Opt_DeferTypeErrors $+ unsetGOptM Opt_DeferTypedHoles $ runPlans [+ -- Plan A+ do { stuff@([it_id], _) <- tcGhciStmts [bind_stmt, print_it]+ ; it_ty <- zonkTcType (idType it_id)+ ; when (isUnitTy $ it_ty) failM+ ; return stuff },++ -- Plan B; a naked bind statment+ tcGhciStmts [bind_stmt],++ -- Plan C; check that the let-binding is typeable all by itself.+ -- If not, fail; if so, try to print it.+ -- The two-step process avoids getting two errors: one from+ -- the expression itself, and one from the 'print it' part+ -- This two-step story is very clunky, alas+ do { _ <- checkNoErrs (tcGhciStmts [let_stmt])+ --- checkNoErrs defeats the error recovery of let-bindings+ ; tcGhciStmts [let_stmt, print_it] } ]++ ; fix_env <- getFixityEnv+ ; return (plan, fix_env) }++tcUserStmt rdr_stmt@(L loc _)+ = do { (([rn_stmt], fix_env), fvs) <- checkNoErrs $+ rnStmts GhciStmtCtxt rnLExpr [rdr_stmt] $ \_ -> do+ fix_env <- getFixityEnv+ return (fix_env, emptyFVs)+ -- Don't try to typecheck if the renamer fails!+ ; traceRn "tcRnStmt" (vcat [ppr rdr_stmt, ppr rn_stmt, ppr fvs])+ ; rnDump rn_stmt ;++ ; ghciStep <- getGhciStepIO+ ; let gi_stmt+ | (L loc (BindStmt pat expr op1 op2 ty)) <- rn_stmt+ = L loc $ BindStmt pat (nlHsApp ghciStep expr) op1 op2 ty+ | otherwise = rn_stmt++ ; opt_pr_flag <- goptM Opt_PrintBindResult+ ; let print_result_plan+ | opt_pr_flag -- The flag says "print result"+ , [v] <- collectLStmtBinders gi_stmt -- One binder+ = [mk_print_result_plan gi_stmt v]+ | otherwise = []++ -- The plans are:+ -- [stmt; print v] if one binder and not v::()+ -- [stmt] otherwise+ ; plan <- runPlans (print_result_plan ++ [tcGhciStmts [gi_stmt]])+ ; return (plan, fix_env) }+ where+ mk_print_result_plan stmt v+ = do { stuff@([v_id], _) <- tcGhciStmts [stmt, print_v]+ ; v_ty <- zonkTcType (idType v_id)+ ; when (isUnitTy v_ty || not (isTauTy v_ty)) failM+ ; return stuff }+ where+ print_v = L loc $ BodyStmt (nlHsApp (nlHsVar printName) (nlHsVar v))+ (mkRnSyntaxExpr thenIOName) noSyntaxExpr+ placeHolderType++-- | Typecheck the statements given and then return the results of the+-- statement in the form 'IO [()]'.+tcGhciStmts :: [GhciLStmt Name] -> TcM PlanResult+tcGhciStmts stmts+ = do { ioTyCon <- tcLookupTyCon ioTyConName ;+ ret_id <- tcLookupId returnIOName ; -- return @ IO+ let {+ ret_ty = mkListTy unitTy ;+ io_ret_ty = mkTyConApp ioTyCon [ret_ty] ;+ tc_io_stmts = tcStmtsAndThen GhciStmtCtxt tcDoStmt stmts+ (mkCheckExpType io_ret_ty) ;+ names = collectLStmtsBinders stmts ;+ } ;++ -- OK, we're ready to typecheck the stmts+ traceTc "TcRnDriver.tcGhciStmts: tc stmts" empty ;+ ((tc_stmts, ids), lie) <- captureTopConstraints $+ tc_io_stmts $ \ _ ->+ mapM tcLookupId names ;+ -- Look up the names right in the middle,+ -- where they will all be in scope++ -- Simplify the context+ traceTc "TcRnDriver.tcGhciStmts: simplify ctxt" empty ;+ const_binds <- checkNoErrs (simplifyInteractive lie) ;+ -- checkNoErrs ensures that the plan fails if context redn fails++ traceTc "TcRnDriver.tcGhciStmts: done" empty ;+ let { -- mk_return builds the expression+ -- returnIO @ [()] [coerce () x, .., coerce () z]+ --+ -- Despite the inconvenience of building the type applications etc,+ -- this *has* to be done in type-annotated post-typecheck form+ -- because we are going to return a list of *polymorphic* values+ -- coerced to type (). If we built a *source* stmt+ -- return [coerce x, ..., coerce z]+ -- then the type checker would instantiate x..z, and we wouldn't+ -- get their *polymorphic* values. (And we'd get ambiguity errs+ -- if they were overloaded, since they aren't applied to anything.)+ ret_expr = nlHsApp (nlHsTyApp ret_id [ret_ty])+ (noLoc $ ExplicitList unitTy Nothing (map mk_item ids)) ;+ mk_item id = let ty_args = [idType id, unitTy] in+ nlHsApp (nlHsTyApp unsafeCoerceId+ (map (getRuntimeRep "tcGhciStmts") ty_args ++ ty_args))+ (nlHsVar id) ;+ stmts = tc_stmts ++ [noLoc (mkLastStmt ret_expr)]+ } ;+ return (ids, mkHsDictLet (EvBinds const_binds) $+ noLoc (HsDo GhciStmtCtxt (noLoc stmts) io_ret_ty))+ }++-- | Generate a typed ghciStepIO expression (ghciStep :: Ty a -> IO a)+getGhciStepIO :: TcM (LHsExpr Name)+getGhciStepIO = do+ ghciTy <- getGHCiMonad+ a_tv <- newName (mkTyVarOccFS (fsLit "a"))+ let ghciM = nlHsAppTy (nlHsTyVar ghciTy) (nlHsTyVar a_tv)+ ioM = nlHsAppTy (nlHsTyVar ioTyConName) (nlHsTyVar a_tv)++ step_ty = noLoc $ HsForAllTy { hst_bndrs = [noLoc $ UserTyVar (noLoc a_tv)]+ , hst_body = nlHsFunTy ghciM ioM }++ stepTy :: LHsSigWcType Name+ stepTy = mkEmptyWildCardBndrs (mkEmptyImplicitBndrs step_ty)++ return (noLoc $ ExprWithTySig (nlHsVar ghciStepIoMName) stepTy)++isGHCiMonad :: HscEnv -> String -> IO (Messages, Maybe Name)+isGHCiMonad hsc_env ty+ = runTcInteractive hsc_env $ do+ rdrEnv <- getGlobalRdrEnv+ let occIO = lookupOccEnv rdrEnv (mkOccName tcName ty)+ case occIO of+ Just [n] -> do+ let name = gre_name n+ ghciClass <- tcLookupClass ghciIoClassName+ userTyCon <- tcLookupTyCon name+ let userTy = mkTyConApp userTyCon []+ _ <- tcLookupInstance ghciClass [userTy]+ return name++ Just _ -> failWithTc $ text "Ambiguous type!"+ Nothing -> failWithTc $ text ("Can't find type:" ++ ty)++-- | How should we infer a type? See Note [TcRnExprMode]+data TcRnExprMode = TM_Inst -- ^ Instantiate the type fully (:type)+ | TM_NoInst -- ^ Do not instantiate the type (:type +v)+ | TM_Default -- ^ Default the type eagerly (:type +d)++-- | tcRnExpr just finds the type of an expression+tcRnExpr :: HscEnv+ -> TcRnExprMode+ -> LHsExpr RdrName+ -> IO (Messages, Maybe Type)+tcRnExpr hsc_env mode rdr_expr+ = runTcInteractive hsc_env $+ do {++ (rn_expr, _fvs) <- rnLExpr rdr_expr ;+ failIfErrsM ;++ -- Now typecheck the expression, and generalise its type+ -- it might have a rank-2 type (e.g. :t runST)+ uniq <- newUnique ;+ let { fresh_it = itName uniq (getLoc rdr_expr)+ ; orig = lexprCtOrigin rn_expr } ;+ (tclvl, lie, res_ty)+ <- pushLevelAndCaptureConstraints $+ do { (_tc_expr, expr_ty) <- tcInferSigma rn_expr+ ; if inst+ then snd <$> deeplyInstantiate orig expr_ty+ else return expr_ty } ;++ -- Generalise+ ((qtvs, dicts, _), lie_top) <- captureTopConstraints $+ {-# SCC "simplifyInfer" #-}+ simplifyInfer tclvl+ infer_mode+ [] {- No sig vars -}+ [(fresh_it, res_ty)]+ lie ;++ -- Ignore the dictionary bindings+ _ <- perhaps_disable_default_warnings $+ simplifyInteractive lie_top ;++ let { all_expr_ty = mkInvForAllTys qtvs (mkLamTypes dicts res_ty) } ;+ ty <- zonkTcType all_expr_ty ;++ -- We normalise type families, so that the type of an expression is the+ -- same as of a bound expression (TcBinds.mkInferredPolyId). See Trac+ -- #10321 for further discussion.+ fam_envs <- tcGetFamInstEnvs ;+ -- normaliseType returns a coercion which we discard, so the Role is+ -- irrelevant+ return (snd (normaliseType fam_envs Nominal ty))+ }+ where+ -- See Note [TcRnExprMode]+ (inst, infer_mode, perhaps_disable_default_warnings) = case mode of+ TM_Inst -> (True, NoRestrictions, id)+ TM_NoInst -> (False, NoRestrictions, id)+ TM_Default -> (True, EagerDefaulting, unsetWOptM Opt_WarnTypeDefaults)++--------------------------+tcRnImportDecls :: HscEnv+ -> [LImportDecl RdrName]+ -> IO (Messages, Maybe GlobalRdrEnv)+-- Find the new chunk of GlobalRdrEnv created by this list of import+-- decls. In contract tcRnImports *extends* the TcGblEnv.+tcRnImportDecls hsc_env import_decls+ = runTcInteractive hsc_env $+ do { gbl_env <- updGblEnv zap_rdr_env $+ tcRnImports hsc_env import_decls+ ; return (tcg_rdr_env gbl_env) }+ where+ zap_rdr_env gbl_env = gbl_env { tcg_rdr_env = emptyGlobalRdrEnv }++-- tcRnType just finds the kind of a type+tcRnType :: HscEnv+ -> Bool -- Normalise the returned type+ -> LHsType RdrName+ -> IO (Messages, Maybe (Type, Kind))+tcRnType hsc_env normalise rdr_type+ = runTcInteractive hsc_env $+ setXOptM LangExt.PolyKinds $ -- See Note [Kind-generalise in tcRnType]+ do { (HsWC { hswc_wcs = wcs, hswc_body = rn_type }, _fvs)+ <- rnHsWcType GHCiCtx (mkHsWildCardBndrs rdr_type)+ -- The type can have wild cards, but no implicit+ -- generalisation; e.g. :kind (T _)+ ; failIfErrsM++ -- Now kind-check the type+ -- It can have any rank or kind+ -- First bring into scope any wildcards+ ; traceTc "tcRnType" (vcat [ppr wcs, ppr rn_type])+ ; (ty, kind) <- solveEqualities $+ tcWildCardBinders wcs $ \ _ ->+ tcLHsType rn_type++ -- Do kind generalisation; see Note [Kind-generalise in tcRnType]+ ; kvs <- kindGeneralize kind+ ; ty <- zonkTcTypeToType emptyZonkEnv ty++ ; ty' <- if normalise+ then do { fam_envs <- tcGetFamInstEnvs+ ; let (_, ty')+ = normaliseType fam_envs Nominal ty+ ; return ty' }+ else return ty ;++ ; return (ty', mkInvForAllTys kvs (typeKind ty')) }++{- Note [TcRnExprMode]+~~~~~~~~~~~~~~~~~~~~~~+How should we infer a type when a user asks for the type of an expression e+at the GHCi prompt? We offer 3 different possibilities, described below. Each+considers this example, with -fprint-explicit-foralls enabled:++ foo :: forall a f b. (Show a, Num b, Foldable f) => a -> f b -> String+ :type{,-spec,-def} foo @Int++:type / TM_Inst++ In this mode, we report the type that would be inferred if a variable+ were assigned to expression e, without applying the monomorphism restriction.+ This means we deeply instantiate the type and then regeneralize, as discussed+ in #11376.++ > :type foo @Int+ forall {b} {f :: * -> *}. (Foldable f, Num b) => Int -> f b -> String++ Note that the variables and constraints are reordered here, because this+ is possible during regeneralization. Also note that the variables are+ reported as Inferred instead of Specified.++:type +v / TM_NoInst++ This mode is for the benefit of users using TypeApplications. It does no+ instantiation whatsoever, sometimes meaning that class constraints are not+ solved.++ > :type +v foo @Int+ forall f b. (Show Int, Num b, Foldable f) => Int -> f b -> String++ Note that Show Int is still reported, because the solver never got a chance+ to see it.++:type +d / TM_Default++ This mode is for the benefit of users who wish to see instantiations of+ generalized types, and in particular to instantiate Foldable and Traversable.+ In this mode, any type variable that can be defaulted is defaulted. Because+ GHCi uses -XExtendedDefaultRules, this means that Foldable and Traversable are+ defaulted.++ > :type +d foo @Int+ Int -> [Integer] -> String++ Note that this mode can sometimes lead to a type error, if a type variable is+ used with a defaultable class but cannot actually be defaulted:++ bar :: (Num a, Monoid a) => a -> a+ > :type +d bar+ ** error **++ The error arises because GHC tries to default a but cannot find a concrete+ type in the defaulting list that is both Num and Monoid. (If this list is+ modified to include an element that is both Num and Monoid, the defaulting+ would succeed, of course.)++Note [Kind-generalise in tcRnType]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We switch on PolyKinds when kind-checking a user type, so that we will+kind-generalise the type, even when PolyKinds is not otherwise on.+This gives the right default behaviour at the GHCi prompt, where if+you say ":k T", and T has a polymorphic kind, you'd like to see that+polymorphism. Of course. If T isn't kind-polymorphic you won't get+anything unexpected, but the apparent *loss* of polymorphism, for+types that you know are polymorphic, is quite surprising. See Trac+#7688 for a discussion.++Note that the goal is to generalise the *kind of the type*, not+the type itself! Example:+ ghci> data T m a = MkT (m a) -- T :: forall . (k -> *) -> k -> *+ ghci> :k T+We instantiate T to get (T kappa). We do not want to kind-generalise+that to forall k. T k! Rather we want to take its kind+ T kappa :: (kappa -> *) -> kappa -> *+and now kind-generalise that kind, to forall k. (k->*) -> k -> *+(It was Trac #10122 that made me realise how wrong the previous+approach was.) -}+++{-+************************************************************************+* *+ tcRnDeclsi+* *+************************************************************************++tcRnDeclsi exists to allow class, data, and other declarations in GHCi.+-}++tcRnDeclsi :: HscEnv+ -> [LHsDecl RdrName]+ -> IO (Messages, Maybe TcGblEnv)+tcRnDeclsi hsc_env local_decls+ = runTcInteractive hsc_env $+ tcRnSrcDecls False local_decls++externaliseAndTidyId :: Module -> Id -> TcM Id+externaliseAndTidyId this_mod id+ = do { name' <- externaliseName this_mod (idName id)+ ; return (globaliseAndTidyId (setIdName id name')) }+++{-+************************************************************************+* *+ More GHCi stuff, to do with browsing and getting info+* *+************************************************************************+-}++-- | ASSUMES that the module is either in the 'HomePackageTable' or is+-- a package module with an interface on disk. If neither of these is+-- true, then the result will be an error indicating the interface+-- could not be found.+getModuleInterface :: HscEnv -> Module -> IO (Messages, Maybe ModIface)+getModuleInterface hsc_env mod+ = runTcInteractive hsc_env $+ loadModuleInterface (text "getModuleInterface") mod++tcRnLookupRdrName :: HscEnv -> Located RdrName+ -> IO (Messages, Maybe [Name])+-- ^ Find all the Names that this RdrName could mean, in GHCi+tcRnLookupRdrName hsc_env (L loc rdr_name)+ = runTcInteractive hsc_env $+ setSrcSpan loc $+ do { -- If the identifier is a constructor (begins with an+ -- upper-case letter), then we need to consider both+ -- constructor and type class identifiers.+ let rdr_names = dataTcOccs rdr_name+ ; names_s <- mapM lookupInfoOccRn rdr_names+ ; let names = concat names_s+ ; when (null names) (addErrTc (text "Not in scope:" <+> quotes (ppr rdr_name)))+ ; return names }++tcRnLookupName :: HscEnv -> Name -> IO (Messages, Maybe TyThing)+tcRnLookupName hsc_env name+ = runTcInteractive hsc_env $+ tcRnLookupName' name++-- To look up a name we have to look in the local environment (tcl_lcl)+-- as well as the global environment, which is what tcLookup does.+-- But we also want a TyThing, so we have to convert:++tcRnLookupName' :: Name -> TcRn TyThing+tcRnLookupName' name = do+ tcthing <- tcLookup name+ case tcthing of+ AGlobal thing -> return thing+ ATcId{tct_id=id} -> return (AnId id)+ _ -> panic "tcRnLookupName'"++tcRnGetInfo :: HscEnv+ -> Name+ -> IO (Messages, Maybe (TyThing, Fixity, [ClsInst], [FamInst]))++-- Used to implement :info in GHCi+--+-- Look up a RdrName and return all the TyThings it might be+-- A capitalised RdrName is given to us in the DataName namespace,+-- but we want to treat it as *both* a data constructor+-- *and* as a type or class constructor;+-- hence the call to dataTcOccs, and we return up to two results+tcRnGetInfo hsc_env name+ = runTcInteractive hsc_env $+ do { loadUnqualIfaces hsc_env (hsc_IC hsc_env)+ -- Load the interface for all unqualified types and classes+ -- That way we will find all the instance declarations+ -- (Packages have not orphan modules, and we assume that+ -- in the home package all relevant modules are loaded.)++ ; thing <- tcRnLookupName' name+ ; fixity <- lookupFixityRn name+ ; (cls_insts, fam_insts) <- lookupInsts thing+ ; return (thing, fixity, cls_insts, fam_insts) }+++-- Lookup all class and family instances for a type constructor.+--+-- This function filters all instances in the type environment, so there+-- is a lot of duplicated work if it is called many times in the same+-- type environment. If this becomes a problem, the NameEnv computed+-- in GHC.getNameToInstancesIndex could be cached in TcM and both functions+-- could be changed to consult that index.+lookupInsts :: TyThing -> TcM ([ClsInst],[FamInst])+lookupInsts (ATyCon tc)+ = do { InstEnvs { ie_global = pkg_ie, ie_local = home_ie, ie_visible = vis_mods } <- tcGetInstEnvs+ ; (pkg_fie, home_fie) <- tcGetFamInstEnvs+ -- Load all instances for all classes that are+ -- in the type environment (which are all the ones+ -- we've seen in any interface file so far)++ -- Return only the instances relevant to the given thing, i.e.+ -- the instances whose head contains the thing's name.+ ; let cls_insts =+ [ ispec -- Search all+ | ispec <- instEnvElts home_ie ++ instEnvElts pkg_ie+ , instIsVisible vis_mods ispec+ , tc_name `elemNameSet` orphNamesOfClsInst ispec ]+ ; let fam_insts =+ [ fispec+ | fispec <- famInstEnvElts home_fie ++ famInstEnvElts pkg_fie+ , tc_name `elemNameSet` orphNamesOfFamInst fispec ]+ ; return (cls_insts, fam_insts) }+ where+ tc_name = tyConName tc++lookupInsts _ = return ([],[])++loadUnqualIfaces :: HscEnv -> InteractiveContext -> TcM ()+-- Load the interface for everything that is in scope unqualified+-- This is so that we can accurately report the instances for+-- something+loadUnqualIfaces hsc_env ictxt+ = initIfaceTcRn $ do+ mapM_ (loadSysInterface doc) (moduleSetElts (mkModuleSet unqual_mods))+ where+ this_pkg = thisPackage (hsc_dflags hsc_env)++ unqual_mods = [ nameModule name+ | gre <- globalRdrEnvElts (ic_rn_gbl_env ictxt)+ , let name = gre_name gre+ , nameIsFromExternalPackage this_pkg name+ , isTcOcc (nameOccName name) -- Types and classes only+ , unQualOK gre ] -- In scope unqualified+ doc = text "Need interface for module whose export(s) are in scope unqualified"++++{-+************************************************************************+* *+ Degugging output+* *+************************************************************************+-}++rnDump :: (Outputable a, Data a) => a -> TcRn ()+-- Dump, with a banner, if -ddump-rn+rnDump rn = do { traceOptTcRn Opt_D_dump_rn (mkDumpDoc "Renamer" (ppr rn))+ ; traceOptTcRn Opt_D_dump_rn_ast+ (mkDumpDoc "Renamer" (text (showAstData NoBlankSrcSpan rn))) }++tcDump :: TcGblEnv -> TcRn ()+tcDump env+ = do { dflags <- getDynFlags ;++ -- Dump short output if -ddump-types or -ddump-tc+ when (dopt Opt_D_dump_types dflags || dopt Opt_D_dump_tc dflags)+ (printForUserTcRn short_dump) ;++ -- Dump bindings if -ddump-tc+ traceOptTcRn Opt_D_dump_tc (mkDumpDoc "Typechecker" full_dump);++ -- Dump bindings as an hsSyn AST if -ddump-tc-ast+ traceOptTcRn Opt_D_dump_tc_ast (mkDumpDoc "Typechecker" ast_dump)+ }+ where+ short_dump = pprTcGblEnv env+ full_dump = pprLHsBinds (tcg_binds env)+ -- NB: foreign x-d's have undefined's in their types;+ -- hence can't show the tc_fords+ ast_dump = text (showAstData NoBlankSrcSpan (tcg_binds env))++-- It's unpleasant having both pprModGuts and pprModDetails here+pprTcGblEnv :: TcGblEnv -> SDoc+pprTcGblEnv (TcGblEnv { tcg_type_env = type_env,+ tcg_insts = insts,+ tcg_fam_insts = fam_insts,+ tcg_rules = rules,+ tcg_vects = vects,+ tcg_imports = imports })+ = vcat [ ppr_types type_env+ , ppr_tycons fam_insts type_env+ , ppr_insts insts+ , ppr_fam_insts fam_insts+ , vcat (map ppr rules)+ , vcat (map ppr vects)+ , text "Dependent modules:" <+>+ pprUFM (imp_dep_mods imports) (ppr . sort)+ , text "Dependent packages:" <+>+ ppr (S.toList $ imp_dep_pkgs imports)]+ where -- The use of sort is just to reduce unnecessary+ -- wobbling in testsuite output++ppr_types :: TypeEnv -> SDoc+ppr_types type_env = sdocWithPprDebug $ \dbg ->+ let+ ids = [id | id <- typeEnvIds type_env, want_sig id]+ want_sig id | dbg+ = True+ | otherwise+ = isExternalName (idName id) &&+ (not (isDerivedOccName (getOccName id)))+ -- Top-level user-defined things have External names.+ -- Suppress internally-generated things unless -dppr-debug+ in+ text "TYPE SIGNATURES" $$ nest 2 (ppr_sigs ids)++ppr_tycons :: [FamInst] -> TypeEnv -> SDoc+ppr_tycons fam_insts type_env = sdocWithPprDebug $ \dbg ->+ let+ fi_tycons = famInstsRepTyCons fam_insts+ tycons = [tycon | tycon <- typeEnvTyCons type_env, want_tycon tycon]+ want_tycon tycon | dbg = True+ | otherwise = not (isImplicitTyCon tycon) &&+ isExternalName (tyConName tycon) &&+ not (tycon `elem` fi_tycons)+ in+ vcat [ text "TYPE CONSTRUCTORS"+ , nest 2 (ppr_tydecls tycons)+ , text "COERCION AXIOMS"+ , nest 2 (vcat (map pprCoAxiom (typeEnvCoAxioms type_env))) ]++ppr_insts :: [ClsInst] -> SDoc+ppr_insts [] = empty+ppr_insts ispecs = text "INSTANCES" $$ nest 2 (pprInstances ispecs)++ppr_fam_insts :: [FamInst] -> SDoc+ppr_fam_insts [] = empty+ppr_fam_insts fam_insts =+ text "FAMILY INSTANCES" $$ nest 2 (pprFamInsts fam_insts)++ppr_sigs :: [Var] -> SDoc+ppr_sigs ids+ -- Print type signatures; sort by OccName+ = vcat (map ppr_sig (sortBy (comparing getOccName) ids))+ where+ ppr_sig id = hang (ppr id <+> dcolon) 2 (ppr (tidyTopType (idType id)))++ppr_tydecls :: [TyCon] -> SDoc+ppr_tydecls tycons+ -- Print type constructor info for debug purposes+ -- Sort by OccName to reduce unnecessary changes+ = vcat [ ppr (tyThingToIfaceDecl (ATyCon tc))+ | tc <- sortBy (comparing getOccName) tycons ]+ -- The Outputable instance for IfaceDecl uses+ -- showToIface, which is what we want here, whereas+ -- pprTyThing uses ShowSome.++{-+********************************************************************************++Type Checker Plugins++********************************************************************************+-}++withTcPlugins :: HscEnv -> TcM a -> TcM a+withTcPlugins hsc_env m =+ do plugins <- liftIO (loadTcPlugins hsc_env)+ case plugins of+ [] -> m -- Common fast case+ _ -> do ev_binds_var <- newTcEvBinds+ (solvers,stops) <- unzip `fmap` mapM (startPlugin ev_binds_var) plugins+ -- This ensures that tcPluginStop is called even if a type+ -- error occurs during compilation (Fix of #10078)+ eitherRes <- tryM $ do+ updGblEnv (\e -> e { tcg_tc_plugins = solvers }) m+ mapM_ (flip runTcPluginM ev_binds_var) stops+ case eitherRes of+ Left _ -> failM+ Right res -> return res+ where+ startPlugin ev_binds_var (TcPlugin start solve stop) =+ do s <- runTcPluginM start ev_binds_var+ return (solve s, stop s)++loadTcPlugins :: HscEnv -> IO [TcPlugin]+#ifndef GHCI+loadTcPlugins _ = return []+#else+loadTcPlugins hsc_env =+ do named_plugins <- loadPlugins hsc_env+ return $ catMaybes $ map load_plugin named_plugins+ where+ load_plugin (_, plug, opts) = tcPlugin plug opts+#endif
+ typecheck/TcRnDriver.hs-boot view
@@ -0,0 +1,12 @@+module TcRnDriver where++import DynFlags (DynFlags)+import Type (TyThing)+import TcRnTypes (TcM)+import Outputable (SDoc)+import Name (Name)++checkBootDeclM :: Bool -- ^ True <=> an hs-boot file (could also be a sig)+ -> TyThing -> TyThing -> TcM ()+missingBootThing :: Bool -> Name -> String -> SDoc+badReexportedBootThing :: DynFlags -> Bool -> Name -> Name -> SDoc
+ typecheck/TcRnExports.hs view
@@ -0,0 +1,878 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE OverloadedStrings #-}+module TcRnExports (tcRnExports, exports_from_avail) where++import HsSyn+import PrelNames+import RdrName+import TcRnMonad+import TcEnv+import TcMType+import TcType+import RnNames+import RnEnv+import ErrUtils+import Id+import IdInfo+import Module+import Name+import NameEnv+import NameSet+import Avail+import TyCon+import SrcLoc+import HscTypes+import Outputable+import ConLike+import DataCon+import PatSyn+import FastString+import Maybes+import qualified GHC.LanguageExtensions as LangExt+import Util (capitalise)+++import Control.Monad+import DynFlags+import RnHsDoc ( rnHsDoc )+import RdrHsSyn ( setRdrNameSpace )+import Data.Either ( partitionEithers )++{-+************************************************************************+* *+\subsection{Export list processing}+* *+************************************************************************++Processing the export list.++You might think that we should record things that appear in the export+list as ``occurrences'' (using @addOccurrenceName@), but you'd be+wrong. We do check (here) that they are in scope, but there is no+need to slurp in their actual declaration (which is what+@addOccurrenceName@ forces).++Indeed, doing so would big trouble when compiling @PrelBase@, because+it re-exports @GHC@, which includes @takeMVar#@, whose type includes+@ConcBase.StateAndSynchVar#@, and so on...++Note [Exports of data families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose you see (Trac #5306)+ module M where+ import X( F )+ data instance F Int = FInt+What does M export? AvailTC F [FInt]+ or AvailTC F [F,FInt]?+The former is strictly right because F isn't defined in this module.+But then you can never do an explicit import of M, thus+ import M( F( FInt ) )+because F isn't exported by M. Nor can you import FInt alone from here+ import M( FInt )+because we don't have syntax to support that. (It looks like an import of+the type FInt.)++At one point I implemented a compromise:+ * When constructing exports with no export list, or with module M(+ module M ), we add the parent to the exports as well.+ * But not when you see module M( f ), even if f is a+ class method with a parent.+ * Nor when you see module M( module N ), with N /= M.++But the compromise seemed too much of a hack, so we backed it out.+You just have to use an explicit export list:+ module M( F(..) ) where ...+-}++data ExportAccum -- The type of the accumulating parameter of+ -- the main worker function in rnExports+ = ExportAccum+ [LIE Name] -- Export items with Names+ ExportOccMap -- Tracks exported occurrence names+ [AvailInfo] -- The accumulated exported stuff+ -- Not nub'd!++emptyExportAccum :: ExportAccum+emptyExportAccum = ExportAccum [] emptyOccEnv []++type ExportOccMap = OccEnv (Name, IE RdrName)+ -- Tracks what a particular exported OccName+ -- in an export list refers to, and which item+ -- it came from. It's illegal to export two distinct things+ -- that have the same occurrence name++tcRnExports :: Bool -- False => no 'module M(..) where' header at all+ -> Maybe (Located [LIE RdrName]) -- Nothing => no explicit export list+ -> TcGblEnv+ -> RnM TcGblEnv++ -- Complains if two distinct exports have same OccName+ -- Warns about identical exports.+ -- Complains about exports items not in scope++tcRnExports explicit_mod exports+ tcg_env@TcGblEnv { tcg_mod = this_mod,+ tcg_rdr_env = rdr_env,+ tcg_imports = imports,+ tcg_src = hsc_src }+ = unsetWOptM Opt_WarnWarningsDeprecations $+ -- Do not report deprecations arising from the export+ -- list, to avoid bleating about re-exporting a deprecated+ -- thing (especially via 'module Foo' export item)+ do {+ -- If the module header is omitted altogether, then behave+ -- as if the user had written "module Main(main) where..."+ -- EXCEPT in interactive mode, when we behave as if he had+ -- written "module Main where ..."+ -- Reason: don't want to complain about 'main' not in scope+ -- in interactive mode+ ; dflags <- getDynFlags+ ; let real_exports+ | explicit_mod = exports+ | ghcLink dflags == LinkInMemory = Nothing+ | otherwise+ = Just (noLoc [noLoc+ (IEVar (noLoc (IEName $ noLoc main_RDR_Unqual)))])+ -- ToDo: the 'noLoc' here is unhelpful if 'main'+ -- turns out to be out of scope++ ; let do_it = exports_from_avail real_exports rdr_env imports this_mod+ ; (rn_exports, final_avails)+ <- if hsc_src == HsigFile+ then do (msgs, mb_r) <- tryTc do_it+ case mb_r of+ Just r -> return r+ Nothing -> addMessages msgs >> failM+ else checkNoErrs $ do_it+ ; let final_ns = availsToNameSetWithSelectors final_avails++ ; traceRn "rnExports: Exports:" (ppr final_avails)++ ; let new_tcg_env =+ tcg_env { tcg_exports = final_avails,+ tcg_rn_exports = case tcg_rn_exports tcg_env of+ Nothing -> Nothing+ Just _ -> rn_exports,+ tcg_dus = tcg_dus tcg_env `plusDU`+ usesOnly final_ns }+ ; failIfErrsM+ ; return new_tcg_env }++exports_from_avail :: Maybe (Located [LIE RdrName])+ -- Nothing => no explicit export list+ -> GlobalRdrEnv+ -> ImportAvails+ -> Module+ -> RnM (Maybe [LIE Name], [AvailInfo])++exports_from_avail Nothing rdr_env _imports _this_mod+ -- The same as (module M) where M is the current module name,+ -- so that's how we handle it, except we also export the data family+ -- when a data instance is exported.+ = let avails =+ map fix_faminst . gresToAvailInfo+ . filter isLocalGRE . globalRdrEnvElts $ rdr_env+ in return (Nothing, avails)+ where+ -- #11164: when we define a data instance+ -- but not data family, re-export the family+ -- Even though we don't check whether this is actually a data family+ -- only data families can locally define subordinate things (`ns` here)+ -- without locally defining (and instead importing) the parent (`n`)+ fix_faminst (AvailTC n ns flds) =+ let new_ns =+ case ns of+ [] -> [n]+ (p:_) -> if p == n then ns else n:ns+ in AvailTC n new_ns flds++ fix_faminst avail = avail+++exports_from_avail (Just (L _ rdr_items)) rdr_env imports this_mod+ = do ExportAccum ie_names _ exports+ <- foldAndRecoverM do_litem emptyExportAccum rdr_items+ let final_exports = nubAvails exports -- Combine families+ return (Just ie_names, final_exports)+ where+ do_litem :: ExportAccum -> LIE RdrName -> RnM ExportAccum+ do_litem acc lie = setSrcSpan (getLoc lie) (exports_from_item acc lie)++ -- Maps a parent to its in-scope children+ kids_env :: NameEnv [GlobalRdrElt]+ kids_env = mkChildEnv (globalRdrEnvElts rdr_env)+++ imported_modules = [ imv_name imv+ | xs <- moduleEnvElts $ imp_mods imports+ , imv <- importedByUser xs ]++ exports_from_item :: ExportAccum -> LIE RdrName -> RnM ExportAccum+ exports_from_item acc@(ExportAccum ie_names occs exports)+ (L loc (IEModuleContents (L lm mod)))+ | let earlier_mods = [ mod+ | (L _ (IEModuleContents (L _ mod))) <- ie_names ]+ , mod `elem` earlier_mods -- Duplicate export of M+ = do { warnIf (Reason Opt_WarnDuplicateExports) True+ (dupModuleExport mod) ;+ return acc }++ | otherwise+ = do { let { exportValid = (mod `elem` imported_modules)+ || (moduleName this_mod == mod)+ ; gre_prs = pickGREsModExp mod (globalRdrEnvElts rdr_env)+ ; new_exports = map (availFromGRE . fst) gre_prs+ ; names = map (gre_name . fst) gre_prs+ ; all_gres = foldr (\(gre1,gre2) gres -> gre1 : gre2 : gres) [] gre_prs+ }++ ; checkErr exportValid (moduleNotImported mod)+ ; warnIf (Reason Opt_WarnDodgyExports)+ (exportValid && null gre_prs)+ (nullModuleExport mod)++ ; traceRn "efa" (ppr mod $$ ppr all_gres)+ ; addUsedGREs all_gres++ ; occs' <- check_occs (IEModuleContents (noLoc mod)) occs names+ -- This check_occs not only finds conflicts+ -- between this item and others, but also+ -- internally within this item. That is, if+ -- 'M.x' is in scope in several ways, we'll have+ -- several members of mod_avails with the same+ -- OccName.+ ; traceRn "export_mod"+ (vcat [ ppr mod+ , ppr new_exports ])+ ; return (ExportAccum (L loc (IEModuleContents (L lm mod)) : ie_names)+ occs'+ (new_exports ++ exports)) }++ exports_from_item acc@(ExportAccum lie_names occs exports) (L loc ie)+ | isDoc ie+ = do new_ie <- lookup_doc_ie ie+ return (ExportAccum (L loc new_ie : lie_names) occs exports)++ | otherwise+ = do (new_ie, avail) <-+ setSrcSpan loc $ lookup_ie ie+ if isUnboundName (ieName new_ie)+ then return acc -- Avoid error cascade+ else do++ occs' <- check_occs ie occs (availNames avail)++ return (ExportAccum (L loc new_ie : lie_names) occs' (avail : exports))++ -------------+ lookup_ie :: IE RdrName -> RnM (IE Name, AvailInfo)+ lookup_ie (IEVar (L l rdr))+ = do (name, avail) <- lookupGreAvailRn $ ieWrappedName rdr+ return (IEVar (L l (replaceWrappedName rdr name)), avail)++ lookup_ie (IEThingAbs (L l rdr))+ = do (name, avail) <- lookupGreAvailRn $ ieWrappedName rdr+ return (IEThingAbs (L l (replaceWrappedName rdr name)), avail)++ lookup_ie ie@(IEThingAll n')+ = do+ (n, avail, flds) <- lookup_ie_all ie n'+ let name = unLoc n+ return (IEThingAll (replaceLWrappedName n' (unLoc n))+ , AvailTC name (name:avail) flds)+++ lookup_ie ie@(IEThingWith l wc sub_rdrs _)+ = do+ (lname, subs, avails, flds)+ <- addExportErrCtxt ie $ lookup_ie_with l sub_rdrs+ (_, all_avail, all_flds) <-+ case wc of+ NoIEWildcard -> return (lname, [], [])+ IEWildcard _ -> lookup_ie_all ie l+ let name = unLoc lname+ subs' = map (replaceLWrappedName l . unLoc) subs+ return (IEThingWith (replaceLWrappedName l name) wc subs'+ (map noLoc (flds ++ all_flds)),+ AvailTC name (name : avails ++ all_avail)+ (flds ++ all_flds))+++++ lookup_ie _ = panic "lookup_ie" -- Other cases covered earlier++ lookup_ie_with :: LIEWrappedName RdrName -> [LIEWrappedName RdrName]+ -> RnM (Located Name, [Located Name], [Name], [FieldLabel])+ lookup_ie_with (L l rdr) sub_rdrs+ = do name <- lookupGlobalOccRn $ ieWrappedName rdr+ (non_flds, flds) <- lookupChildrenExport name+ (map ieLWrappedName sub_rdrs)+ if isUnboundName name+ then return (L l name, [], [name], [])+ else return (L l name, non_flds+ , map unLoc non_flds+ , map unLoc flds)+ lookup_ie_all :: IE RdrName -> LIEWrappedName RdrName+ -> RnM (Located Name, [Name], [FieldLabel])+ lookup_ie_all ie (L l rdr) =+ do name <- lookupGlobalOccRn $ ieWrappedName rdr+ let gres = findChildren kids_env name+ (non_flds, flds) = classifyGREs gres+ addUsedKids (ieWrappedName rdr) gres+ warnDodgyExports <- woptM Opt_WarnDodgyExports+ when (null gres) $+ if isTyConName name+ then when warnDodgyExports $+ addWarn (Reason Opt_WarnDodgyExports)+ (dodgyExportWarn name)+ else -- This occurs when you export T(..), but+ -- only import T abstractly, or T is a synonym.+ addErr (exportItemErr ie)+ return (L l name, non_flds, flds)++ -------------+ lookup_doc_ie :: IE RdrName -> RnM (IE Name)+ lookup_doc_ie (IEGroup lev doc) = do rn_doc <- rnHsDoc doc+ return (IEGroup lev rn_doc)+ lookup_doc_ie (IEDoc doc) = do rn_doc <- rnHsDoc doc+ return (IEDoc rn_doc)+ lookup_doc_ie (IEDocNamed str) = return (IEDocNamed str)+ lookup_doc_ie _ = panic "lookup_doc_ie" -- Other cases covered earlier++ -- In an export item M.T(A,B,C), we want to treat the uses of+ -- A,B,C as if they were M.A, M.B, M.C+ -- Happily pickGREs does just the right thing+ addUsedKids :: RdrName -> [GlobalRdrElt] -> RnM ()+ addUsedKids parent_rdr kid_gres = addUsedGREs (pickGREs parent_rdr kid_gres)++classifyGREs :: [GlobalRdrElt] -> ([Name], [FieldLabel])+classifyGREs = partitionEithers . map classifyGRE++classifyGRE :: GlobalRdrElt -> Either Name FieldLabel+classifyGRE gre = case gre_par gre of+ FldParent _ Nothing -> Right (FieldLabel (occNameFS (nameOccName n)) False n)+ FldParent _ (Just lbl) -> Right (FieldLabel lbl True n)+ _ -> Left n+ where+ n = gre_name gre++isDoc :: IE RdrName -> Bool+isDoc (IEDoc _) = True+isDoc (IEDocNamed _) = True+isDoc (IEGroup _ _) = True+isDoc _ = False++-- Renaming and typechecking of exports happens after everything else has+-- been typechecked.++++-- Renaming exports lists is a minefield. Five different things can appear in+-- children export lists ( T(A, B, C) ).+-- 1. Record selectors+-- 2. Type constructors+-- 3. Data constructors+-- 4. Pattern Synonyms+-- 5. Pattern Synonym Selectors+--+-- However, things get put into weird name spaces.+-- 1. Some type constructors are parsed as variables (-.->) for example.+-- 2. All data constructors are parsed as type constructors+-- 3. When there is ambiguity, we default type constructors to data+-- constructors and require the explicit `type` keyword for type+-- constructors.+--+-- This function first establishes the possible namespaces that an+-- identifier might be in (`choosePossibleNameSpaces`).+--+-- Then for each namespace in turn, tries to find the correct identifier+-- there returning the first positive result or the first terminating+-- error.+--+++-- Records the result of looking up a child.+data ChildLookupResult+ = NameNotFound -- We couldn't find a suitable name+ | NameErr ErrMsg -- We found an unambiguous name+ -- but there's another error+ -- we should abort from+ | FoundName Name -- We resolved to a normal name+ | FoundFL FieldLabel -- We resolved to a FL++instance Outputable ChildLookupResult where+ ppr NameNotFound = text "NameNotFound"+ ppr (FoundName n) = text "Found:" <+> ppr n+ ppr (FoundFL fls) = text "FoundFL:" <+> ppr fls+ ppr (NameErr _) = text "Error"++-- Left biased accumulation monoid. Chooses the left-most positive occurrence.+instance Monoid ChildLookupResult where+ mempty = NameNotFound+ NameNotFound `mappend` m2 = m2+ NameErr m `mappend` _ = NameErr m -- Abort from the first error+ FoundName n1 `mappend` _ = FoundName n1+ FoundFL fls `mappend` _ = FoundFL fls++lookupChildrenExport :: Name -> [Located RdrName]+ -> RnM ([Located Name], [Located FieldLabel])+lookupChildrenExport parent rdr_items =+ do+ xs <- mapAndReportM doOne rdr_items+ return $ partitionEithers xs+ where+ -- Pick out the possible namespaces in order of priority+ -- This is a consequence of how the parser parses all+ -- data constructors as type constructors.+ choosePossibleNamespaces :: NameSpace -> [NameSpace]+ choosePossibleNamespaces ns+ | ns == varName = [varName, tcName]+ | ns == tcName = [dataName, tcName]+ | otherwise = [ns]+ -- Process an individual child+ doOne :: Located RdrName+ -> RnM (Either (Located Name) (Located FieldLabel))+ doOne n = do++ let bareName = unLoc n+ lkup v = lookupExportChild parent (setRdrNameSpace bareName v)++ name <- tryChildLookupResult $ map lkup $+ (choosePossibleNamespaces (rdrNameSpace bareName))++ -- Default to data constructors for slightly better error+ -- messages+ let unboundName :: RdrName+ unboundName = if rdrNameSpace bareName == varName+ then bareName+ else setRdrNameSpace bareName dataName++ case name of+ NameNotFound -> Left . L (getLoc n) <$> reportUnboundName unboundName+ FoundFL fls -> return $ Right (L (getLoc n) fls)+ FoundName name -> return $ Left (L (getLoc n) name)+ NameErr err_msg -> reportError err_msg >> failM++tryChildLookupResult :: [RnM ChildLookupResult] -> RnM ChildLookupResult+tryChildLookupResult [x] = x+tryChildLookupResult (x:xs) = do+ res <- x+ case res of+ FoundFL {} -> return res+ FoundName {} -> return res+ NameErr {} -> return res+ _ -> tryChildLookupResult xs+tryChildLookupResult _ = panic "tryChildLookupResult:empty list"++++-- | Also captures the current context+mkNameErr :: SDoc -> TcM ChildLookupResult+mkNameErr errMsg = do+ tcinit <- tcInitTidyEnv+ NameErr <$> mkErrTcM (tcinit, errMsg)+++-- | Used in export lists to lookup the children.+lookupExportChild :: Name -> RdrName -> RnM ChildLookupResult+lookupExportChild parent rdr_name+ | isUnboundName parent+ -- Avoid an error cascade+ = return (FoundName (mkUnboundNameRdr rdr_name))++ | otherwise = do+ gre_env <- getGlobalRdrEnv++ let original_gres = lookupGlobalRdrEnv gre_env (rdrNameOcc rdr_name)+ -- Disambiguate the lookup based on the parent information.+ -- The remaining GREs are things that we *could* export here, note that+ -- this includes things which have `NoParent`. Those are sorted in+ -- `checkPatSynParent`.+ traceRn "lookupExportChild original_gres:" (ppr original_gres)+ case picked_gres original_gres of+ NoOccurrence ->+ noMatchingParentErr original_gres+ UniqueOccurrence g ->+ checkPatSynParent parent (gre_name g)+ DisambiguatedOccurrence g ->+ checkFld g+ AmbiguousOccurrence gres ->+ mkNameClashErr gres+ where+ -- Convert into FieldLabel if necessary+ checkFld :: GlobalRdrElt -> RnM ChildLookupResult+ checkFld g@GRE{gre_name, gre_par} = do+ addUsedGRE True g+ return $ case gre_par of+ FldParent _ mfs -> do+ FoundFL (fldParentToFieldLabel gre_name mfs)+ _ -> FoundName gre_name++ fldParentToFieldLabel :: Name -> Maybe FastString -> FieldLabel+ fldParentToFieldLabel name mfs =+ case mfs of+ Nothing ->+ let fs = occNameFS (nameOccName name)+ in FieldLabel fs False name+ Just fs -> FieldLabel fs True name++ -- Called when we fine no matching GREs after disambiguation but+ -- there are three situations where this happens.+ -- 1. There were none to begin with.+ -- 2. None of the matching ones were the parent but+ -- a. They were from an overloaded record field so we can report+ -- a better error+ -- b. The original lookup was actually ambiguous.+ -- For example, the case where overloading is off and two+ -- record fields are in scope from different record+ -- constructors, neither of which is the parent.+ noMatchingParentErr :: [GlobalRdrElt] -> RnM ChildLookupResult+ noMatchingParentErr original_gres = do+ overload_ok <- xoptM LangExt.DuplicateRecordFields+ case original_gres of+ [] -> return NameNotFound+ [g] -> mkDcErrMsg parent (gre_name g) [p | Just p <- [getParent g]]+ gss@(g:_:_) ->+ if all isRecFldGRE gss && overload_ok+ then mkNameErr (dcErrMsg parent "record selector"+ (expectJust "noMatchingParentErr" (greLabel g))+ [ppr p | x <- gss, Just p <- [getParent x]])+ else mkNameClashErr gss++ mkNameClashErr :: [GlobalRdrElt] -> RnM ChildLookupResult+ mkNameClashErr gres = do+ addNameClashErrRn rdr_name gres+ return (FoundName (gre_name (head gres)))++ getParent :: GlobalRdrElt -> Maybe Name+ getParent (GRE { gre_par = p } ) =+ case p of+ ParentIs cur_parent -> Just cur_parent+ FldParent { par_is = cur_parent } -> Just cur_parent+ NoParent -> Nothing++ picked_gres :: [GlobalRdrElt] -> DisambigInfo+ picked_gres gres+ | isUnqual rdr_name = mconcat (map right_parent gres)+ | otherwise = mconcat (map right_parent (pickGREs rdr_name gres))+++ right_parent :: GlobalRdrElt -> DisambigInfo+ right_parent p+ | Just cur_parent <- getParent p+ = if parent == cur_parent+ then DisambiguatedOccurrence p+ else NoOccurrence+ | otherwise+ = UniqueOccurrence p++-- This domain specific datatype is used to record why we decided it was+-- possible that a GRE could be exported with a parent.+data DisambigInfo+ = NoOccurrence+ -- The GRE could never be exported. It has the wrong parent.+ | UniqueOccurrence GlobalRdrElt+ -- The GRE has no parent. It could be a pattern synonym.+ | DisambiguatedOccurrence GlobalRdrElt+ -- The parent of the GRE is the correct parent+ | AmbiguousOccurrence [GlobalRdrElt]+ -- For example, two normal identifiers with the same name are in+ -- scope. They will both be resolved to "UniqueOccurrence" and the+ -- monoid will combine them to this failing case.++instance Monoid DisambigInfo where+ mempty = NoOccurrence+ -- This is the key line: We prefer disambiguated occurrences to other+ -- names. Notice that two disambiguated occurences are not ambiguous as+ -- there is an internal invariant that a list of `DisambigInfo` arises+ -- from a list of GREs which all have the same OccName. Thus, if we ever+ -- have two DisambiguatedOccurences then they must have arisen from the+ -- same GRE and hence it's safe to discard one.+ _ `mappend` DisambiguatedOccurrence g' = DisambiguatedOccurrence g'+ DisambiguatedOccurrence g' `mappend` _ = DisambiguatedOccurrence g'+++ NoOccurrence `mappend` m = m+ m `mappend` NoOccurrence = m+ UniqueOccurrence g `mappend` UniqueOccurrence g' = AmbiguousOccurrence [g, g']+ UniqueOccurrence g `mappend` AmbiguousOccurrence gs = AmbiguousOccurrence (g:gs)+ AmbiguousOccurrence gs `mappend` UniqueOccurrence g' = AmbiguousOccurrence (g':gs)+ AmbiguousOccurrence gs `mappend` AmbiguousOccurrence gs' = AmbiguousOccurrence (gs ++ gs')+++++--+-- Note: [Typing Pattern Synonym Exports]+-- It proved quite a challenge to precisely specify which pattern synonyms+-- should be allowed to be bundled with which type constructors.+-- In the end it was decided to be quite liberal in what we allow. Below is+-- how Simon described the implementation.+--+-- "Personally I think we should Keep It Simple. All this talk of+-- satisfiability makes me shiver. I suggest this: allow T( P ) in all+-- situations except where `P`'s type is ''visibly incompatible'' with+-- `T`.+--+-- What does "visibly incompatible" mean? `P` is visibly incompatible+-- with+-- `T` if+-- * `P`'s type is of form `... -> S t1 t2`+-- * `S` is a data/newtype constructor distinct from `T`+--+-- Nothing harmful happens if we allow `P` to be exported with+-- a type it can't possibly be useful for, but specifying a tighter+-- relationship is very awkward as you have discovered."+--+-- Note that this allows *any* pattern synonym to be bundled with any+-- datatype type constructor. For example, the following pattern `P` can be+-- bundled with any type.+--+-- ```+-- pattern P :: (A ~ f) => f+-- ```+--+-- So we provide basic type checking in order to help the user out, most+-- pattern synonyms are defined with definite type constructors, but don't+-- actually prevent a library author completely confusing their users if+-- they want to.+--+-- So, we check for exactly four things+-- 1. The name arises from a pattern synonym definition. (Either a pattern+-- synonym constructor or a pattern synonym selector)+-- 2. The pattern synonym is only bundled with a datatype or newtype.+-- 3. Check that the head of the result type constructor is an actual type+-- constructor and not a type variable. (See above example)+-- 4. Is so, check that this type constructor is the same as the parent+-- type constructor.+--+--+-- Note: [Types of TyCon]+--+-- This check appears to be overlly complicated, Richard asked why it+-- is not simply just `isAlgTyCon`. The answer for this is that+-- a classTyCon is also an `AlgTyCon` which we explicitly want to disallow.+-- (It is either a newtype or data depending on the number of methods)+--++-- | Given a resolved name in the children export list and a parent. Decide+-- whether we are allowed to export the child with the parent.+-- Invariant: gre_par == NoParent+-- See note [Typing Pattern Synonym Exports]+checkPatSynParent :: Name -- ^ Type constructor+ -> Name -- ^ Either a+ -- a) Pattern Synonym Constructor+ -- b) A pattern synonym selector+ -> TcM ChildLookupResult+checkPatSynParent parent mpat_syn = do+ parent_ty_con <- tcLookupTyCon parent+ mpat_syn_thing <- tcLookupGlobal mpat_syn+ let expected_res_ty =+ mkTyConApp parent_ty_con (mkTyVarTys (tyConTyVars parent_ty_con))++ handlePatSyn errCtxt =+ addErrCtxt errCtxt+ . tc_one_ps_export_with expected_res_ty parent_ty_con+ -- 1. Check that the Id was actually from a thing associated with patsyns+ case mpat_syn_thing of+ AnId i+ | isId i ->+ case idDetails i of+ RecSelId { sel_tycon = RecSelPatSyn p } -> handlePatSyn (selErr i) p+ _ -> mkDcErrMsg parent mpat_syn []+ AConLike (PatSynCon p) -> handlePatSyn (psErr p) p+ _ -> mkDcErrMsg parent mpat_syn []+ where++ psErr = exportErrCtxt "pattern synonym"+ selErr = exportErrCtxt "pattern synonym record selector"++ assocClassErr :: SDoc+ assocClassErr =+ text "Pattern synonyms can be bundled only with datatypes."++ tc_one_ps_export_with :: TcTauType -- ^ TyCon type+ -> TyCon -- ^ Parent TyCon+ -> PatSyn -- ^ Corresponding bundled PatSyn+ -- and pretty printed origin+ -> TcM ChildLookupResult+ tc_one_ps_export_with expected_res_ty ty_con pat_syn++ -- 2. See note [Types of TyCon]+ | not $ isTyConWithSrcDataCons ty_con = mkNameErr assocClassErr+ -- 3. Is the head a type variable?+ | Nothing <- mtycon = return (FoundName mpat_syn)+ -- 4. Ok. Check they are actually the same type constructor.+ | Just p_ty_con <- mtycon, p_ty_con /= ty_con = mkNameErr typeMismatchError+ -- 5. We passed!+ | otherwise = return (FoundName mpat_syn)++ where+ (_, _, _, _, _, res_ty) = patSynSig pat_syn+ mtycon = fst <$> tcSplitTyConApp_maybe res_ty+ typeMismatchError :: SDoc+ typeMismatchError =+ text "Pattern synonyms can only be bundled with matching type constructors"+ $$ text "Couldn't match expected type of"+ <+> quotes (ppr expected_res_ty)+ <+> text "with actual type of"+ <+> quotes (ppr res_ty)+++++{-===========================================================================-}+++check_occs :: IE RdrName -> ExportOccMap -> [Name] -> RnM ExportOccMap+check_occs ie occs names -- 'names' are the entities specifed by 'ie'+ = foldlM check occs names+ where+ check occs name+ = case lookupOccEnv occs name_occ of+ Nothing -> return (extendOccEnv occs name_occ (name, ie))++ Just (name', ie')+ | name == name' -- Duplicate export+ -- But we don't want to warn if the same thing is exported+ -- by two different module exports. See ticket #4478.+ -> do { warnIf (Reason Opt_WarnDuplicateExports)+ (not (dupExport_ok name ie ie'))+ (dupExportWarn name_occ ie ie')+ ; return occs }++ | otherwise -- Same occ name but different names: an error+ -> do { global_env <- getGlobalRdrEnv ;+ addErr (exportClashErr global_env name' name ie' ie) ;+ return occs }+ where+ name_occ = nameOccName name+++dupExport_ok :: Name -> IE RdrName -> IE RdrName -> Bool+-- The Name is exported by both IEs. Is that ok?+-- "No" iff the name is mentioned explicitly in both IEs+-- or one of the IEs mentions the name *alone*+-- "Yes" otherwise+--+-- Examples of "no": module M( f, f )+-- module M( fmap, Functor(..) )+-- module M( module Data.List, head )+--+-- Example of "yes"+-- module M( module A, module B ) where+-- import A( f )+-- import B( f )+--+-- Example of "yes" (Trac #2436)+-- module M( C(..), T(..) ) where+-- class C a where { data T a }+-- instance C Int where { data T Int = TInt }+--+-- Example of "yes" (Trac #2436)+-- module Foo ( T ) where+-- data family T a+-- module Bar ( T(..), module Foo ) where+-- import Foo+-- data instance T Int = TInt++dupExport_ok n ie1 ie2+ = not ( single ie1 || single ie2+ || (explicit_in ie1 && explicit_in ie2) )+ where+ explicit_in (IEModuleContents _) = False -- module M+ explicit_in (IEThingAll r)+ = nameOccName n == rdrNameOcc (ieWrappedName $ unLoc r) -- T(..)+ explicit_in _ = True++ single IEVar {} = True+ single IEThingAbs {} = True+ single _ = False+++dupModuleExport :: ModuleName -> SDoc+dupModuleExport mod+ = hsep [text "Duplicate",+ quotes (text "Module" <+> ppr mod),+ text "in export list"]++moduleNotImported :: ModuleName -> SDoc+moduleNotImported mod+ = text "The export item `module" <+> ppr mod <>+ text "' is not imported"++nullModuleExport :: ModuleName -> SDoc+nullModuleExport mod+ = text "The export item `module" <+> ppr mod <> ptext (sLit "' exports nothing")+++dodgyExportWarn :: Name -> SDoc+dodgyExportWarn item = dodgyMsg (text "export") item++exportErrCtxt :: Outputable o => String -> o -> SDoc+exportErrCtxt herald exp =+ text "In the" <+> text (herald ++ ":") <+> ppr exp+++addExportErrCtxt :: (HasOccName s, OutputableBndr s) => IE s -> TcM a -> TcM a+addExportErrCtxt ie = addErrCtxt exportCtxt+ where+ exportCtxt = text "In the export:" <+> ppr ie++exportItemErr :: IE RdrName -> SDoc+exportItemErr export_item+ = sep [ text "The export item" <+> quotes (ppr export_item),+ text "attempts to export constructors or class methods that are not visible here" ]+++dupExportWarn :: OccName -> IE RdrName -> IE RdrName -> SDoc+dupExportWarn occ_name ie1 ie2+ = hsep [quotes (ppr occ_name),+ text "is exported by", quotes (ppr ie1),+ text "and", quotes (ppr ie2)]++dcErrMsg :: Outputable a => Name -> String -> a -> [SDoc] -> SDoc+dcErrMsg ty_con what_is thing parents =+ text "The type constructor" <+> quotes (ppr ty_con)+ <+> text "is not the parent of the" <+> text what_is+ <+> quotes (ppr thing) <> char '.'+ $$ text (capitalise what_is)+ <> text "s can only be exported with their parent type constructor."+ $$ (case parents of+ [] -> empty+ [_] -> text "Parent:"+ _ -> text "Parents:") <+> fsep (punctuate comma parents)++mkDcErrMsg :: Name -> Name -> [Name] -> TcM ChildLookupResult+mkDcErrMsg parent thing parents = do+ ty_thing <- tcLookupGlobal thing+ mkNameErr (dcErrMsg parent (tyThingCategory' ty_thing) thing (map ppr parents))+ where+ tyThingCategory' :: TyThing -> String+ tyThingCategory' (AnId i)+ | isRecordSelector i = "record selector"+ tyThingCategory' i = tyThingCategory i+++exportClashErr :: GlobalRdrEnv -> Name -> Name -> IE RdrName -> IE RdrName+ -> MsgDoc+exportClashErr global_env name1 name2 ie1 ie2+ = vcat [ text "Conflicting exports for" <+> quotes (ppr occ) <> colon+ , ppr_export ie1' name1'+ , ppr_export ie2' name2' ]+ where+ occ = nameOccName name1+ ppr_export ie name = nest 3 (hang (quotes (ppr ie) <+> text "exports" <+>+ quotes (ppr name))+ 2 (pprNameProvenance (get_gre name)))++ -- get_gre finds a GRE for the Name, so that we can show its provenance+ get_gre name+ = fromMaybe (pprPanic "exportClashErr" (ppr name)) (lookupGRE_Name global_env name)+ get_loc name = greSrcSpan (get_gre name)+ (name1', ie1', name2', ie2') = if get_loc name1 < get_loc name2+ then (name1, ie1, name2, ie2)+ else (name2, ie2, name1, ie1)
+ typecheck/TcRnMonad.hs view
@@ -0,0 +1,1855 @@+{-+(c) The University of Glasgow 2006+++Functions for working with the typechecker environment (setters, getters...).+-}++{-# LANGUAGE CPP, ExplicitForAll, FlexibleInstances #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module TcRnMonad(+ -- * Initalisation+ initTc, initTcWithGbl, initTcInteractive, initTcForLookup, initTcRnIf,++ -- * Simple accessors+ discardResult,+ getTopEnv, updTopEnv, getGblEnv, updGblEnv,+ setGblEnv, getLclEnv, updLclEnv, setLclEnv,+ getEnvs, setEnvs,+ xoptM, doptM, goptM, woptM,+ setXOptM, unsetXOptM, unsetGOptM, unsetWOptM,+ whenDOptM, whenGOptM, whenWOptM, whenXOptM,+ getGhcMode,+ withDoDynamicToo,+ getEpsVar,+ getEps,+ updateEps, updateEps_,+ getHpt, getEpsAndHpt,++ -- * Arrow scopes+ newArrowScope, escapeArrowScope,++ -- * Unique supply+ newUnique, newUniqueSupply, newName, newNameAt, cloneLocalName,+ newSysName, newSysLocalId, newSysLocalIds,++ -- * Accessing input/output+ newTcRef, readTcRef, writeTcRef, updTcRef,++ -- * Debugging+ traceTc, traceRn, traceOptTcRn, traceTcRn,+ getPrintUnqualified,+ printForUserTcRn,+ traceIf, traceHiDiffs, traceOptIf,+ debugTc,++ -- * Typechecker global environment+ getIsGHCi, getGHCiMonad, getInteractivePrintName,+ tcIsHsBootOrSig, tcSelfBootInfo, getGlobalRdrEnv,+ getRdrEnvs, getImports,+ getFixityEnv, extendFixityEnv, getRecFieldEnv,+ getDeclaredDefaultTys,+ addDependentFiles,++ -- * Error management+ getSrcSpanM, setSrcSpan, addLocM,+ wrapLocM, wrapLocFstM, wrapLocSndM,+ getErrsVar, setErrsVar,+ addErr,+ failWith, failAt,+ addErrAt, addErrs,+ checkErr,+ addMessages,+ discardWarnings,++ -- * Shared error message stuff: renamer and typechecker+ mkLongErrAt, mkErrDocAt, addLongErrAt, reportErrors, reportError,+ reportWarning, recoverM, mapAndRecoverM, mapAndReportM, foldAndRecoverM,+ tryTc,+ askNoErrs, discardErrs, tryTcDiscardingErrs,+ checkNoErrs, whenNoErrs,+ ifErrsM, failIfErrsM,+ checkTH, failTH,++ -- * Context management for the type checker+ getErrCtxt, setErrCtxt, addErrCtxt, addErrCtxtM, addLandmarkErrCtxt,+ addLandmarkErrCtxtM, updCtxt, popErrCtxt, getCtLocM, setCtLocM,++ -- * Error message generation (type checker)+ addErrTc, addErrsTc,+ addErrTcM, mkErrTcM,+ failWithTc, failWithTcM,+ checkTc, checkTcM,+ failIfTc, failIfTcM,+ warnIf, warnTc, warnTcM,+ addWarnTc, addWarnTcM, addWarn, addWarnAt, add_warn,+ tcInitTidyEnv, tcInitOpenTidyEnv, mkErrInfo,++ -- * Type constraints+ newTcEvBinds,+ addTcEvBind,+ getTcEvTyCoVars, getTcEvBindsMap,+ chooseUniqueOccTc,+ getConstraintVar, setConstraintVar,+ emitConstraints, emitStaticConstraints, emitSimple, emitSimples,+ emitImplication, emitImplications, emitInsoluble,+ discardConstraints, captureConstraints, tryCaptureConstraints,+ pushLevelAndCaptureConstraints,+ pushTcLevelM_, pushTcLevelM,+ getTcLevel, setTcLevel, isTouchableTcM,+ getLclTypeEnv, setLclTypeEnv,+ traceTcConstraints, emitWildCardHoleConstraints,++ -- * Template Haskell context+ recordThUse, recordThSpliceUse, recordTopLevelSpliceLoc,+ getTopLevelSpliceLocs, keepAlive, getStage, getStageAndBindLevel, setStage,+ addModFinalizersWithLclEnv,++ -- * Safe Haskell context+ recordUnsafeInfer, finalSafeMode, fixSafeInstances,++ -- * Stuff for the renamer's local env+ getLocalRdrEnv, setLocalRdrEnv,++ -- * Stuff for interface decls+ mkIfLclEnv,+ initIfaceTcRn,+ initIfaceCheck,+ initIfaceLcl,+ initIfaceLclWithSubst,+ initIfaceLoad,+ getIfModule,+ failIfM,+ forkM_maybe,+ forkM,+ setImplicitEnvM,++ withException,++ -- * Types etc.+ module TcRnTypes,+ module IOEnv+ ) where++#include "HsVersions.h"++import TcRnTypes -- Re-export all+import IOEnv -- Re-export all+import TcEvidence++import HsSyn hiding (LIE)+import HscTypes+import Module+import RdrName+import Name+import Type++import TcType+import InstEnv+import FamInstEnv+import PrelNames++import Id+import VarSet+import VarEnv+import ErrUtils+import SrcLoc+import NameEnv+import NameSet+import Bag+import Outputable+import UniqSupply+import DynFlags+import FastString+import Panic+import Util+import Annotations+import BasicTypes( TopLevelFlag )+import Maybes++import qualified GHC.LanguageExtensions as LangExt++import Control.Exception+import Data.IORef+import Control.Monad+import Data.Set ( Set )+import qualified Data.Set as Set++import {-# SOURCE #-} TcSplice ( runRemoteModFinalizers )+import qualified Data.Map as Map++{-+************************************************************************+* *+ initTc+* *+************************************************************************+-}++-- | Setup the initial typechecking environment+initTc :: HscEnv+ -> HscSource+ -> Bool -- True <=> retain renamed syntax trees+ -> Module+ -> RealSrcSpan+ -> TcM r+ -> IO (Messages, Maybe r)+ -- Nothing => error thrown by the thing inside+ -- (error messages should have been printed already)++initTc hsc_env hsc_src keep_rn_syntax mod loc do_this+ = do { keep_var <- newIORef emptyNameSet ;+ used_gre_var <- newIORef [] ;+ th_var <- newIORef False ;+ th_splice_var<- newIORef False ;+ th_locs_var <- newIORef Set.empty ;+ infer_var <- newIORef (True, emptyBag) ;+ dfun_n_var <- newIORef emptyOccSet ;+ type_env_var <- case hsc_type_env_var hsc_env of {+ Just (_mod, te_var) -> return te_var ;+ Nothing -> newIORef emptyNameEnv } ;++ dependent_files_var <- newIORef [] ;+ static_wc_var <- newIORef emptyWC ;+ th_topdecls_var <- newIORef [] ;+ th_foreign_files_var <- newIORef [] ;+ th_topnames_var <- newIORef emptyNameSet ;+ th_modfinalizers_var <- newIORef [] ;+ th_state_var <- newIORef Map.empty ;+ th_remote_state_var <- newIORef Nothing ;+ let {+ dflags = hsc_dflags hsc_env ;++ maybe_rn_syntax :: forall a. a -> Maybe a ;+ maybe_rn_syntax empty_val+ | keep_rn_syntax = Just empty_val+ | otherwise = Nothing ;++ gbl_env = TcGblEnv {+ tcg_th_topdecls = th_topdecls_var,+ tcg_th_foreign_files = th_foreign_files_var,+ tcg_th_topnames = th_topnames_var,+ tcg_th_modfinalizers = th_modfinalizers_var,+ tcg_th_state = th_state_var,+ tcg_th_remote_state = th_remote_state_var,++ tcg_mod = mod,+ tcg_semantic_mod =+ if thisPackage dflags == moduleUnitId mod+ then canonicalizeHomeModule dflags (moduleName mod)+ else mod,+ tcg_src = hsc_src,+ tcg_rdr_env = emptyGlobalRdrEnv,+ tcg_fix_env = emptyNameEnv,+ tcg_field_env = emptyNameEnv,+ tcg_default = if moduleUnitId mod == primUnitId+ then Just [] -- See Note [Default types]+ else Nothing,+ tcg_type_env = emptyNameEnv,+ tcg_type_env_var = type_env_var,+ tcg_inst_env = emptyInstEnv,+ tcg_fam_inst_env = emptyFamInstEnv,+ tcg_pending_fam_checks = emptyNameEnv,+ tcg_ann_env = emptyAnnEnv,+ tcg_th_used = th_var,+ tcg_th_splice_used = th_splice_var,+ tcg_th_top_level_locs+ = th_locs_var,+ tcg_exports = [],+ tcg_imports = emptyImportAvails,+ tcg_used_gres = used_gre_var,+ tcg_dus = emptyDUs,++ tcg_rn_imports = [],+ tcg_rn_exports =+ if hsc_src == HsigFile+ -- Always retain renamed syntax, so that we can give+ -- better errors. (TODO: how?)+ then Just []+ else maybe_rn_syntax [],+ tcg_rn_decls = maybe_rn_syntax emptyRnGroup,+ tcg_tr_module = Nothing,+ tcg_binds = emptyLHsBinds,+ tcg_imp_specs = [],+ tcg_sigs = emptyNameSet,+ tcg_ev_binds = emptyBag,+ tcg_warns = NoWarnings,+ tcg_anns = [],+ tcg_tcs = [],+ tcg_insts = [],+ tcg_fam_insts = [],+ tcg_rules = [],+ tcg_fords = [],+ tcg_vects = [],+ tcg_patsyns = [],+ tcg_merged = [],+ tcg_dfun_n = dfun_n_var,+ tcg_keep = keep_var,+ tcg_doc_hdr = Nothing,+ tcg_hpc = False,+ tcg_main = Nothing,+ tcg_self_boot = NoSelfBoot,+ tcg_safeInfer = infer_var,+ tcg_dependent_files = dependent_files_var,+ tcg_tc_plugins = [],+ tcg_top_loc = loc,+ tcg_static_wc = static_wc_var,+ tcg_complete_matches = []+ } ;+ } ;++ -- OK, here's the business end!+ initTcWithGbl hsc_env gbl_env loc do_this+ }++-- | Run a 'TcM' action in the context of an existing 'GblEnv'.+initTcWithGbl :: HscEnv+ -> TcGblEnv+ -> RealSrcSpan+ -> TcM r+ -> IO (Messages, Maybe r)+initTcWithGbl hsc_env gbl_env loc do_this+ = do { tvs_var <- newIORef emptyVarSet+ ; lie_var <- newIORef emptyWC+ ; errs_var <- newIORef (emptyBag, emptyBag)+ ; let lcl_env = TcLclEnv {+ tcl_errs = errs_var,+ tcl_loc = loc, -- Should be over-ridden very soon!+ tcl_ctxt = [],+ tcl_rdr = emptyLocalRdrEnv,+ tcl_th_ctxt = topStage,+ tcl_th_bndrs = emptyNameEnv,+ tcl_arrow_ctxt = NoArrowCtxt,+ tcl_env = emptyNameEnv,+ tcl_bndrs = [],+ tcl_tidy = emptyTidyEnv,+ tcl_tyvars = tvs_var,+ tcl_lie = lie_var,+ tcl_tclvl = topTcLevel+ }++ ; maybe_res <- initTcRnIf 'a' hsc_env gbl_env lcl_env $+ do { r <- tryM do_this+ ; case r of+ Right res -> return (Just res)+ Left _ -> return Nothing }++ -- Check for unsolved constraints+ -- If we succeed (maybe_res = Just r), there should be+ -- no unsolved constraints. But if we exit via an+ -- exception (maybe_res = Nothing), we may have skipped+ -- solving, so don't panic then (Trac #13466)+ ; lie <- readIORef (tcl_lie lcl_env)+ ; when (isJust maybe_res && not (isEmptyWC lie)) $+ pprPanic "initTc: unsolved constraints" (ppr lie)++ -- Collect any error messages+ ; msgs <- readIORef (tcl_errs lcl_env)++ ; let { final_res | errorsFound dflags msgs = Nothing+ | otherwise = maybe_res }++ ; return (msgs, final_res)+ }+ where dflags = hsc_dflags hsc_env++initTcInteractive :: HscEnv -> TcM a -> IO (Messages, Maybe a)+-- Initialise the type checker monad for use in GHCi+initTcInteractive hsc_env thing_inside+ = initTc hsc_env HsSrcFile False+ (icInteractiveModule (hsc_IC hsc_env))+ (realSrcLocSpan interactive_src_loc)+ thing_inside+ where+ interactive_src_loc = mkRealSrcLoc (fsLit "<interactive>") 1 1++initTcForLookup :: HscEnv -> TcM a -> IO a+-- The thing_inside is just going to look up something+-- in the environment, so we don't need much setup+initTcForLookup hsc_env thing_inside+ = do { (msgs, m) <- initTcInteractive hsc_env thing_inside+ ; case m of+ Nothing -> throwIO $ mkSrcErr $ snd msgs+ Just x -> return x }++{- Note [Default types]+~~~~~~~~~~~~~~~~~~~~~~~+The Integer type is simply not available in package ghc-prim (it is+declared in integer-gmp). So we set the defaulting types to (Just+[]), meaning there are no default types, rather then Nothing, which+means "use the default default types of Integer, Double".++If you don't do this, attempted defaulting in package ghc-prim causes+an actual crash (attempting to look up the Integer type).+++************************************************************************+* *+ Initialisation+* *+************************************************************************+-}++initTcRnIf :: Char -- Tag for unique supply+ -> HscEnv+ -> gbl -> lcl+ -> TcRnIf gbl lcl a+ -> IO a+initTcRnIf uniq_tag hsc_env gbl_env lcl_env thing_inside+ = do { us <- mkSplitUniqSupply uniq_tag ;+ ; us_var <- newIORef us ;++ ; let { env = Env { env_top = hsc_env,+ env_us = us_var,+ env_gbl = gbl_env,+ env_lcl = lcl_env} }++ ; runIOEnv env thing_inside+ }++{-+************************************************************************+* *+ Simple accessors+* *+************************************************************************+-}++discardResult :: TcM a -> TcM ()+discardResult a = a >> return ()++getTopEnv :: TcRnIf gbl lcl HscEnv+getTopEnv = do { env <- getEnv; return (env_top env) }++updTopEnv :: (HscEnv -> HscEnv) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+updTopEnv upd = updEnv (\ env@(Env { env_top = top }) ->+ env { env_top = upd top })++getGblEnv :: TcRnIf gbl lcl gbl+getGblEnv = do { env <- getEnv; return (env_gbl env) }++updGblEnv :: (gbl -> gbl) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+updGblEnv upd = updEnv (\ env@(Env { env_gbl = gbl }) ->+ env { env_gbl = upd gbl })++setGblEnv :: gbl -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+setGblEnv gbl_env = updEnv (\ env -> env { env_gbl = gbl_env })++getLclEnv :: TcRnIf gbl lcl lcl+getLclEnv = do { env <- getEnv; return (env_lcl env) }++updLclEnv :: (lcl -> lcl) -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+updLclEnv upd = updEnv (\ env@(Env { env_lcl = lcl }) ->+ env { env_lcl = upd lcl })++setLclEnv :: lcl' -> TcRnIf gbl lcl' a -> TcRnIf gbl lcl a+setLclEnv lcl_env = updEnv (\ env -> env { env_lcl = lcl_env })++getEnvs :: TcRnIf gbl lcl (gbl, lcl)+getEnvs = do { env <- getEnv; return (env_gbl env, env_lcl env) }++setEnvs :: (gbl', lcl') -> TcRnIf gbl' lcl' a -> TcRnIf gbl lcl a+setEnvs (gbl_env, lcl_env) = updEnv (\ env -> env { env_gbl = gbl_env, env_lcl = lcl_env })++-- Command-line flags++xoptM :: LangExt.Extension -> TcRnIf gbl lcl Bool+xoptM flag = do { dflags <- getDynFlags; return (xopt flag dflags) }++doptM :: DumpFlag -> TcRnIf gbl lcl Bool+doptM flag = do { dflags <- getDynFlags; return (dopt flag dflags) }++goptM :: GeneralFlag -> TcRnIf gbl lcl Bool+goptM flag = do { dflags <- getDynFlags; return (gopt flag dflags) }++woptM :: WarningFlag -> TcRnIf gbl lcl Bool+woptM flag = do { dflags <- getDynFlags; return (wopt flag dflags) }++setXOptM :: LangExt.Extension -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+setXOptM flag =+ updTopEnv (\top -> top { hsc_dflags = xopt_set (hsc_dflags top) flag})++unsetXOptM :: LangExt.Extension -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+unsetXOptM flag =+ updTopEnv (\top -> top { hsc_dflags = xopt_unset (hsc_dflags top) flag})++unsetGOptM :: GeneralFlag -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+unsetGOptM flag =+ updTopEnv (\top -> top { hsc_dflags = gopt_unset (hsc_dflags top) flag})++unsetWOptM :: WarningFlag -> TcRnIf gbl lcl a -> TcRnIf gbl lcl a+unsetWOptM flag =+ updTopEnv (\top -> top { hsc_dflags = wopt_unset (hsc_dflags top) flag})++-- | Do it flag is true+whenDOptM :: DumpFlag -> TcRnIf gbl lcl () -> TcRnIf gbl lcl ()+whenDOptM flag thing_inside = do b <- doptM flag+ when b thing_inside++whenGOptM :: GeneralFlag -> TcRnIf gbl lcl () -> TcRnIf gbl lcl ()+whenGOptM flag thing_inside = do b <- goptM flag+ when b thing_inside++whenWOptM :: WarningFlag -> TcRnIf gbl lcl () -> TcRnIf gbl lcl ()+whenWOptM flag thing_inside = do b <- woptM flag+ when b thing_inside++whenXOptM :: LangExt.Extension -> TcRnIf gbl lcl () -> TcRnIf gbl lcl ()+whenXOptM flag thing_inside = do b <- xoptM flag+ when b thing_inside++getGhcMode :: TcRnIf gbl lcl GhcMode+getGhcMode = do { env <- getTopEnv; return (ghcMode (hsc_dflags env)) }++withDoDynamicToo :: TcRnIf gbl lcl a -> TcRnIf gbl lcl a+withDoDynamicToo =+ updTopEnv (\top@(HscEnv { hsc_dflags = dflags }) ->+ top { hsc_dflags = dynamicTooMkDynamicDynFlags dflags })++getEpsVar :: TcRnIf gbl lcl (TcRef ExternalPackageState)+getEpsVar = do { env <- getTopEnv; return (hsc_EPS env) }++getEps :: TcRnIf gbl lcl ExternalPackageState+getEps = do { env <- getTopEnv; readMutVar (hsc_EPS env) }++-- | Update the external package state. Returns the second result of the+-- modifier function.+--+-- This is an atomic operation and forces evaluation of the modified EPS in+-- order to avoid space leaks.+updateEps :: (ExternalPackageState -> (ExternalPackageState, a))+ -> TcRnIf gbl lcl a+updateEps upd_fn = do+ traceIf (text "updating EPS")+ eps_var <- getEpsVar+ atomicUpdMutVar' eps_var upd_fn++-- | Update the external package state.+--+-- This is an atomic operation and forces evaluation of the modified EPS in+-- order to avoid space leaks.+updateEps_ :: (ExternalPackageState -> ExternalPackageState)+ -> TcRnIf gbl lcl ()+updateEps_ upd_fn = do+ traceIf (text "updating EPS_")+ eps_var <- getEpsVar+ atomicUpdMutVar' eps_var (\eps -> (upd_fn eps, ()))++getHpt :: TcRnIf gbl lcl HomePackageTable+getHpt = do { env <- getTopEnv; return (hsc_HPT env) }++getEpsAndHpt :: TcRnIf gbl lcl (ExternalPackageState, HomePackageTable)+getEpsAndHpt = do { env <- getTopEnv; eps <- readMutVar (hsc_EPS env)+ ; return (eps, hsc_HPT env) }++-- | A convenient wrapper for taking a @MaybeErr MsgDoc a@ and throwing+-- an exception if it is an error.+withException :: TcRnIf gbl lcl (MaybeErr MsgDoc a) -> TcRnIf gbl lcl a+withException do_this = do+ r <- do_this+ dflags <- getDynFlags+ case r of+ Failed err -> liftIO $ throwGhcExceptionIO (ProgramError (showSDoc dflags err))+ Succeeded result -> return result++{-+************************************************************************+* *+ Arrow scopes+* *+************************************************************************+-}++newArrowScope :: TcM a -> TcM a+newArrowScope+ = updLclEnv $ \env -> env { tcl_arrow_ctxt = ArrowCtxt (tcl_rdr env) (tcl_lie env) }++-- Return to the stored environment (from the enclosing proc)+escapeArrowScope :: TcM a -> TcM a+escapeArrowScope+ = updLclEnv $ \ env ->+ case tcl_arrow_ctxt env of+ NoArrowCtxt -> env+ ArrowCtxt rdr_env lie -> env { tcl_arrow_ctxt = NoArrowCtxt+ , tcl_lie = lie+ , tcl_rdr = rdr_env }++{-+************************************************************************+* *+ Unique supply+* *+************************************************************************+-}++newUnique :: TcRnIf gbl lcl Unique+newUnique+ = do { env <- getEnv ;+ let { u_var = env_us env } ;+ us <- readMutVar u_var ;+ case takeUniqFromSupply us of { (uniq, us') -> do {+ writeMutVar u_var us' ;+ return $! uniq }}}+ -- NOTE 1: we strictly split the supply, to avoid the possibility of leaving+ -- a chain of unevaluated supplies behind.+ -- NOTE 2: we use the uniq in the supply from the MutVar directly, and+ -- throw away one half of the new split supply. This is safe because this+ -- is the only place we use that unique. Using the other half of the split+ -- supply is safer, but slower.++newUniqueSupply :: TcRnIf gbl lcl UniqSupply+newUniqueSupply+ = do { env <- getEnv ;+ let { u_var = env_us env } ;+ us <- readMutVar u_var ;+ case splitUniqSupply us of { (us1,us2) -> do {+ writeMutVar u_var us1 ;+ return us2 }}}++cloneLocalName :: Name -> TcM Name+-- Make a fresh Internal name with the same OccName and SrcSpan+cloneLocalName name = newNameAt (nameOccName name) (nameSrcSpan name)++newName :: OccName -> TcM Name+newName occ = do { loc <- getSrcSpanM+ ; newNameAt occ loc }++newNameAt :: OccName -> SrcSpan -> TcM Name+newNameAt occ span+ = do { uniq <- newUnique+ ; return (mkInternalName uniq occ span) }++newSysName :: OccName -> TcRnIf gbl lcl Name+newSysName occ+ = do { uniq <- newUnique+ ; return (mkSystemName uniq occ) }++newSysLocalId :: FastString -> TcType -> TcRnIf gbl lcl TcId+newSysLocalId fs ty+ = do { u <- newUnique+ ; return (mkSysLocalOrCoVar fs u ty) }++newSysLocalIds :: FastString -> [TcType] -> TcRnIf gbl lcl [TcId]+newSysLocalIds fs tys+ = do { us <- newUniqueSupply+ ; return (zipWith (mkSysLocalOrCoVar fs) (uniqsFromSupply us) tys) }++instance MonadUnique (IOEnv (Env gbl lcl)) where+ getUniqueM = newUnique+ getUniqueSupplyM = newUniqueSupply++{-+************************************************************************+* *+ Accessing input/output+* *+************************************************************************+-}++newTcRef :: a -> TcRnIf gbl lcl (TcRef a)+newTcRef = newMutVar++readTcRef :: TcRef a -> TcRnIf gbl lcl a+readTcRef = readMutVar++writeTcRef :: TcRef a -> a -> TcRnIf gbl lcl ()+writeTcRef = writeMutVar++updTcRef :: TcRef a -> (a -> a) -> TcRnIf gbl lcl ()+-- Returns ()+updTcRef ref fn = liftIO $ do { old <- readIORef ref+ ; writeIORef ref (fn old) }++{-+************************************************************************+* *+ Debugging+* *+************************************************************************+-}+++-- Typechecker trace+traceTc :: String -> SDoc -> TcRn ()+traceTc =+ labelledTraceOptTcRn Opt_D_dump_tc_trace++-- Renamer Trace+traceRn :: String -> SDoc -> TcRn ()+traceRn =+ labelledTraceOptTcRn Opt_D_dump_rn_trace++-- | Trace when a certain flag is enabled. This is like `traceOptTcRn`+-- but accepts a string as a label and formats the trace message uniformly.+labelledTraceOptTcRn :: DumpFlag -> String -> SDoc -> TcRn ()+labelledTraceOptTcRn flag herald doc = do+ traceOptTcRn flag (formatTraceMsg herald doc)++formatTraceMsg :: String -> SDoc -> SDoc+formatTraceMsg herald doc = hang (text herald) 2 doc++-- | Output a doc if the given 'DumpFlag' is set.+--+-- By default this logs to stdout+-- However, if the `-ddump-to-file` flag is set,+-- then this will dump output to a file+--+-- Just a wrapper for 'dumpSDoc'+traceOptTcRn :: DumpFlag -> SDoc -> TcRn ()+traceOptTcRn flag doc+ = do { dflags <- getDynFlags+ ; when (dopt flag dflags)+ (traceTcRn flag doc)+ }+++traceTcRn :: DumpFlag -> SDoc -> TcRn ()+-- ^ Unconditionally dump some trace output+--+-- The DumpFlag is used only to set the output filename+-- for --dump-to-file, not to decide whether or not to output+-- That part is done by the caller+traceTcRn flag doc+ = do { dflags <- getDynFlags+ ; real_doc <- prettyDoc dflags doc+ ; printer <- getPrintUnqualified dflags+ ; liftIO $ dumpSDoc dflags printer flag "" real_doc }+ where+ -- Add current location if -dppr-debug+ prettyDoc :: DynFlags -> SDoc -> TcRn SDoc+ prettyDoc dflags doc = if hasPprDebug dflags+ then do { loc <- getSrcSpanM; return $ mkLocMessage SevOutput loc doc }+ else return doc -- The full location is usually way too much+++getPrintUnqualified :: DynFlags -> TcRn PrintUnqualified+getPrintUnqualified dflags+ = do { rdr_env <- getGlobalRdrEnv+ ; return $ mkPrintUnqualified dflags rdr_env }++-- | Like logInfoTcRn, but for user consumption+printForUserTcRn :: SDoc -> TcRn ()+printForUserTcRn doc+ = do { dflags <- getDynFlags+ ; printer <- getPrintUnqualified dflags+ ; liftIO (printOutputForUser dflags printer doc) }++{-+traceIf and traceHiDiffs work in the TcRnIf monad, where no RdrEnv is+available. Alas, they behave inconsistently with the other stuff;+e.g. are unaffected by -dump-to-file.+-}++traceIf, traceHiDiffs :: SDoc -> TcRnIf m n ()+traceIf = traceOptIf Opt_D_dump_if_trace+traceHiDiffs = traceOptIf Opt_D_dump_hi_diffs+++traceOptIf :: DumpFlag -> SDoc -> TcRnIf m n ()+traceOptIf flag doc+ = whenDOptM flag $ -- No RdrEnv available, so qualify everything+ do { dflags <- getDynFlags+ ; liftIO (putMsg dflags doc) }++{-+************************************************************************+* *+ Typechecker global environment+* *+************************************************************************+-}++getIsGHCi :: TcRn Bool+getIsGHCi = do { mod <- getModule+ ; return (isInteractiveModule mod) }++getGHCiMonad :: TcRn Name+getGHCiMonad = do { hsc <- getTopEnv; return (ic_monad $ hsc_IC hsc) }++getInteractivePrintName :: TcRn Name+getInteractivePrintName = do { hsc <- getTopEnv; return (ic_int_print $ hsc_IC hsc) }++tcIsHsBootOrSig :: TcRn Bool+tcIsHsBootOrSig = do { env <- getGblEnv; return (isHsBootOrSig (tcg_src env)) }++tcSelfBootInfo :: TcRn SelfBootInfo+tcSelfBootInfo = do { env <- getGblEnv; return (tcg_self_boot env) }++getGlobalRdrEnv :: TcRn GlobalRdrEnv+getGlobalRdrEnv = do { env <- getGblEnv; return (tcg_rdr_env env) }++getRdrEnvs :: TcRn (GlobalRdrEnv, LocalRdrEnv)+getRdrEnvs = do { (gbl,lcl) <- getEnvs; return (tcg_rdr_env gbl, tcl_rdr lcl) }++getImports :: TcRn ImportAvails+getImports = do { env <- getGblEnv; return (tcg_imports env) }++getFixityEnv :: TcRn FixityEnv+getFixityEnv = do { env <- getGblEnv; return (tcg_fix_env env) }++extendFixityEnv :: [(Name,FixItem)] -> RnM a -> RnM a+extendFixityEnv new_bit+ = updGblEnv (\env@(TcGblEnv { tcg_fix_env = old_fix_env }) ->+ env {tcg_fix_env = extendNameEnvList old_fix_env new_bit})++getRecFieldEnv :: TcRn RecFieldEnv+getRecFieldEnv = do { env <- getGblEnv; return (tcg_field_env env) }++getDeclaredDefaultTys :: TcRn (Maybe [Type])+getDeclaredDefaultTys = do { env <- getGblEnv; return (tcg_default env) }++addDependentFiles :: [FilePath] -> TcRn ()+addDependentFiles fs = do+ ref <- fmap tcg_dependent_files getGblEnv+ dep_files <- readTcRef ref+ writeTcRef ref (fs ++ dep_files)++{-+************************************************************************+* *+ Error management+* *+************************************************************************+-}++getSrcSpanM :: TcRn SrcSpan+ -- Avoid clash with Name.getSrcLoc+getSrcSpanM = do { env <- getLclEnv; return (RealSrcSpan (tcl_loc env)) }++setSrcSpan :: SrcSpan -> TcRn a -> TcRn a+setSrcSpan (RealSrcSpan real_loc) thing_inside+ = updLclEnv (\env -> env { tcl_loc = real_loc }) thing_inside+-- Don't overwrite useful info with useless:+setSrcSpan (UnhelpfulSpan _) thing_inside = thing_inside++addLocM :: (a -> TcM b) -> Located a -> TcM b+addLocM fn (L loc a) = setSrcSpan loc $ fn a++wrapLocM :: (a -> TcM b) -> Located a -> TcM (Located b)+wrapLocM fn (L loc a) = setSrcSpan loc $ do b <- fn a; return (L loc b)++wrapLocFstM :: (a -> TcM (b,c)) -> Located a -> TcM (Located b, c)+wrapLocFstM fn (L loc a) =+ setSrcSpan loc $ do+ (b,c) <- fn a+ return (L loc b, c)++wrapLocSndM :: (a -> TcM (b,c)) -> Located a -> TcM (b, Located c)+wrapLocSndM fn (L loc a) =+ setSrcSpan loc $ do+ (b,c) <- fn a+ return (b, L loc c)++-- Reporting errors++getErrsVar :: TcRn (TcRef Messages)+getErrsVar = do { env <- getLclEnv; return (tcl_errs env) }++setErrsVar :: TcRef Messages -> TcRn a -> TcRn a+setErrsVar v = updLclEnv (\ env -> env { tcl_errs = v })++addErr :: MsgDoc -> TcRn ()+addErr msg = do { loc <- getSrcSpanM; addErrAt loc msg }++failWith :: MsgDoc -> TcRn a+failWith msg = addErr msg >> failM++failAt :: SrcSpan -> MsgDoc -> TcRn a+failAt loc msg = addErrAt loc msg >> failM++addErrAt :: SrcSpan -> MsgDoc -> TcRn ()+-- addErrAt is mainly (exclusively?) used by the renamer, where+-- tidying is not an issue, but it's all lazy so the extra+-- work doesn't matter+addErrAt loc msg = do { ctxt <- getErrCtxt+ ; tidy_env <- tcInitTidyEnv+ ; err_info <- mkErrInfo tidy_env ctxt+ ; addLongErrAt loc msg err_info }++addErrs :: [(SrcSpan,MsgDoc)] -> TcRn ()+addErrs msgs = mapM_ add msgs+ where+ add (loc,msg) = addErrAt loc msg++checkErr :: Bool -> MsgDoc -> TcRn ()+-- Add the error if the bool is False+checkErr ok msg = unless ok (addErr msg)++addMessages :: Messages -> TcRn ()+addMessages msgs1+ = do { errs_var <- getErrsVar ;+ msgs0 <- readTcRef errs_var ;+ writeTcRef errs_var (unionMessages msgs0 msgs1) }++discardWarnings :: TcRn a -> TcRn a+-- Ignore warnings inside the thing inside;+-- used to ignore-unused-variable warnings inside derived code+discardWarnings thing_inside+ = do { errs_var <- getErrsVar+ ; (old_warns, _) <- readTcRef errs_var++ ; result <- thing_inside++ -- Revert warnings to old_warns+ ; (_new_warns, new_errs) <- readTcRef errs_var+ ; writeTcRef errs_var (old_warns, new_errs)++ ; return result }++{-+************************************************************************+* *+ Shared error message stuff: renamer and typechecker+* *+************************************************************************+-}++mkLongErrAt :: SrcSpan -> MsgDoc -> MsgDoc -> TcRn ErrMsg+mkLongErrAt loc msg extra+ = do { dflags <- getDynFlags ;+ printer <- getPrintUnqualified dflags ;+ return $ mkLongErrMsg dflags loc printer msg extra }++mkErrDocAt :: SrcSpan -> ErrDoc -> TcRn ErrMsg+mkErrDocAt loc errDoc+ = do { dflags <- getDynFlags ;+ printer <- getPrintUnqualified dflags ;+ return $ mkErrDoc dflags loc printer errDoc }++addLongErrAt :: SrcSpan -> MsgDoc -> MsgDoc -> TcRn ()+addLongErrAt loc msg extra = mkLongErrAt loc msg extra >>= reportError++reportErrors :: [ErrMsg] -> TcM ()+reportErrors = mapM_ reportError++reportError :: ErrMsg -> TcRn ()+reportError err+ = do { traceTc "Adding error:" (pprLocErrMsg err) ;+ errs_var <- getErrsVar ;+ (warns, errs) <- readTcRef errs_var ;+ writeTcRef errs_var (warns, errs `snocBag` err) }++reportWarning :: WarnReason -> ErrMsg -> TcRn ()+reportWarning reason err+ = do { let warn = makeIntoWarning reason err+ -- 'err' was built by mkLongErrMsg or something like that,+ -- so it's of error severity. For a warning we downgrade+ -- its severity to SevWarning++ ; traceTc "Adding warning:" (pprLocErrMsg warn)+ ; errs_var <- getErrsVar+ ; (warns, errs) <- readTcRef errs_var+ ; writeTcRef errs_var (warns `snocBag` warn, errs) }++try_m :: TcRn r -> TcRn (Either IOEnvFailure r)+-- Does tryM, with a debug-trace on failure+try_m thing+ = do { (mb_r, lie) <- tryCaptureConstraints thing+ ; emitConstraints lie++ -- Debug trace+ ; case mb_r of+ Left exn -> traceTc "tryTc/recoverM recovering from" $+ text (showException exn)+ Right {} -> return ()++ ; return mb_r }++-----------------------+recoverM :: TcRn r -- Recovery action; do this if the main one fails+ -> TcRn r -- Main action: do this first;+ -- if it generates errors, propagate them all+ -> TcRn r+-- Errors in 'thing' are retained+recoverM recover thing+ = do { mb_res <- try_m thing ;+ case mb_res of+ Left _ -> recover+ Right res -> return res }+++-----------------------++-- | Drop elements of the input that fail, so the result+-- list can be shorter than the argument list+mapAndRecoverM :: (a -> TcRn b) -> [a] -> TcRn [b]+mapAndRecoverM f = fmap reverse . foldAndRecoverM (\xs x -> (:xs) <$> f x ) []++-- | The accumulator is not updated if the action fails+foldAndRecoverM :: (b -> a -> TcRn b) -> b -> [a] -> TcRn b+foldAndRecoverM _ acc [] = return acc+foldAndRecoverM f acc (x:xs) =+ do { mb_r <- try_m (f acc x)+ ; case mb_r of+ Left _ -> foldAndRecoverM f acc xs+ Right acc' -> foldAndRecoverM f acc' xs }++-- | Succeeds if applying the argument to all members of the lists succeeds,+-- but nevertheless runs it on all arguments, to collect all errors.+mapAndReportM :: (a -> TcRn b) -> [a] -> TcRn [b]+mapAndReportM f xs = checkNoErrs (mapAndRecoverM f xs)++-----------------------+tryTc :: TcRn a -> TcRn (Messages, Maybe a)+-- (tryTc m) executes m, and returns+-- Just r, if m succeeds (returning r)+-- Nothing, if m fails+-- It also returns all the errors and warnings accumulated by m+-- It always succeeds (never raises an exception)+tryTc thing_inside+ = do { errs_var <- newTcRef emptyMessages ;++ res <- try_m $ -- Be sure to catch exceptions, so that+ -- we guaranteed to read the messages out+ -- of that brand-new errs_var!+ setErrsVar errs_var $+ thing_inside ;++ msgs <- readTcRef errs_var ;++ return (msgs, case res of+ Left _ -> Nothing+ Right val -> Just val)+ -- The exception is always the IOEnv built-in+ -- in exception; see IOEnv.failM+ }++-----------------------+discardErrs :: TcRn a -> TcRn a+-- (discardErrs m) runs m,+-- discarding all error messages and warnings generated by m+-- If m fails, discardErrs fails, and vice versa+discardErrs m+ = do { errs_var <- newTcRef emptyMessages+ ; setErrsVar errs_var m }++-----------------------+tryTcDiscardingErrs :: TcM r -> TcM r -> TcM r+-- (tryTcDiscardingErrs recover main) tries 'main';+-- if 'main' succeeds with no error messages, it's the answer+-- otherwise discard everything from 'main', including errors,+-- and try 'recover' instead.+tryTcDiscardingErrs recover main+ = do { (msgs, mb_res) <- tryTc main+ ; dflags <- getDynFlags+ ; case mb_res of+ Just res | not (errorsFound dflags msgs)+ -> -- 'main' succeeed with no error messages+ do { addMessages msgs -- msgs might still have warnings+ ; return res }++ _ -> -- 'main' failed, or produced an error message+ recover -- Discard all errors and warnings entirely+ }++-----------------------+-- (askNoErrs m) runs m+-- If m fails,+-- then (askNoErrs m) fails+-- If m succeeds with result r,+-- then (askNoErrs 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+askNoErrs :: TcRn a -> TcRn (a, Bool)+askNoErrs m+ = do { (msgs, mb_res) <- tryTc m+ ; addMessages msgs -- Always propagate errors+ ; case mb_res of+ Nothing -> failM+ Just res -> do { dflags <- getDynFlags+ ; let errs_found = errorsFound dflags msgs+ ; return (res, not errs_found) } }+-----------------------+checkNoErrs :: TcM r -> TcM r+-- (checkNoErrs m) succeeds iff m succeeds and generates no errors+-- If m fails then (checkNoErrsTc m) fails.+-- If m succeeds, it checks whether m generated any errors messages+-- (it might have recovered internally)+-- If so, it fails too.+-- Regardless, any errors generated by m are propagated to the enclosing context.+checkNoErrs main+ = do { (res, no_errs) <- askNoErrs main+ ; unless no_errs failM+ ; return res }++-----------------------+whenNoErrs :: TcM () -> TcM ()+whenNoErrs thing = ifErrsM (return ()) thing++ifErrsM :: TcRn r -> TcRn r -> TcRn r+-- ifErrsM bale_out normal+-- does 'bale_out' if there are errors in errors collection+-- otherwise does 'normal'+ifErrsM bale_out normal+ = do { errs_var <- getErrsVar ;+ msgs <- readTcRef errs_var ;+ dflags <- getDynFlags ;+ if errorsFound dflags msgs then+ bale_out+ else+ normal }++failIfErrsM :: TcRn ()+-- Useful to avoid error cascades+failIfErrsM = ifErrsM failM (return ())++checkTH :: a -> String -> TcRn ()+checkTH _ _ = return () -- OK++failTH :: Outputable a => a -> String -> TcRn x+failTH e what -- Raise an error in a stage-1 compiler+ = failWithTc (vcat [ hang (char 'A' <+> text what+ <+> text "requires GHC with interpreter support:")+ 2 (ppr e)+ , text "Perhaps you are using a stage-1 compiler?" ])+++{- *********************************************************************+* *+ Context management for the type checker+* *+************************************************************************+-}++getErrCtxt :: TcM [ErrCtxt]+getErrCtxt = do { env <- getLclEnv; return (tcl_ctxt env) }++setErrCtxt :: [ErrCtxt] -> TcM a -> TcM a+setErrCtxt ctxt = updLclEnv (\ env -> env { tcl_ctxt = ctxt })++-- | Add a fixed message to the error context. This message should not+-- do any tidying.+addErrCtxt :: MsgDoc -> TcM a -> TcM a+addErrCtxt msg = addErrCtxtM (\env -> return (env, msg))++-- | Add a message to the error context. This message may do tidying.+addErrCtxtM :: (TidyEnv -> TcM (TidyEnv, MsgDoc)) -> TcM a -> TcM a+addErrCtxtM ctxt = updCtxt (\ ctxts -> (False, ctxt) : ctxts)++-- | Add a fixed landmark message to the error context. A landmark+-- message is always sure to be reported, even if there is a lot of+-- context. It also doesn't count toward the maximum number of contexts+-- reported.+addLandmarkErrCtxt :: MsgDoc -> TcM a -> TcM a+addLandmarkErrCtxt msg = addLandmarkErrCtxtM (\env -> return (env, msg))++-- | Variant of 'addLandmarkErrCtxt' that allows for monadic operations+-- and tidying.+addLandmarkErrCtxtM :: (TidyEnv -> TcM (TidyEnv, MsgDoc)) -> TcM a -> TcM a+addLandmarkErrCtxtM ctxt = updCtxt (\ctxts -> (True, ctxt) : ctxts)++-- Helper function for the above+updCtxt :: ([ErrCtxt] -> [ErrCtxt]) -> TcM a -> TcM a+updCtxt upd = updLclEnv (\ env@(TcLclEnv { tcl_ctxt = ctxt }) ->+ env { tcl_ctxt = upd ctxt })++popErrCtxt :: TcM a -> TcM a+popErrCtxt = updCtxt (\ msgs -> case msgs of { [] -> []; (_ : ms) -> ms })++getCtLocM :: CtOrigin -> Maybe TypeOrKind -> TcM CtLoc+getCtLocM origin t_or_k+ = do { env <- getLclEnv+ ; return (CtLoc { ctl_origin = origin+ , ctl_env = env+ , ctl_t_or_k = t_or_k+ , ctl_depth = initialSubGoalDepth }) }++setCtLocM :: CtLoc -> TcM a -> TcM a+-- Set the SrcSpan and error context from the CtLoc+setCtLocM (CtLoc { ctl_env = lcl }) thing_inside+ = updLclEnv (\env -> env { tcl_loc = tcl_loc lcl+ , tcl_bndrs = tcl_bndrs lcl+ , tcl_ctxt = tcl_ctxt lcl })+ thing_inside++{-+************************************************************************+* *+ Error message generation (type checker)+* *+************************************************************************++ The addErrTc functions add an error message, but do not cause failure.+ The 'M' variants pass a TidyEnv that has already been used to+ tidy up the message; we then use it to tidy the context messages+-}++addErrTc :: MsgDoc -> TcM ()+addErrTc err_msg = do { env0 <- tcInitTidyEnv+ ; addErrTcM (env0, err_msg) }++addErrsTc :: [MsgDoc] -> TcM ()+addErrsTc err_msgs = mapM_ addErrTc err_msgs++addErrTcM :: (TidyEnv, MsgDoc) -> TcM ()+addErrTcM (tidy_env, err_msg)+ = do { ctxt <- getErrCtxt ;+ loc <- getSrcSpanM ;+ add_err_tcm tidy_env err_msg loc ctxt }++-- Return the error message, instead of reporting it straight away+mkErrTcM :: (TidyEnv, MsgDoc) -> TcM ErrMsg+mkErrTcM (tidy_env, err_msg)+ = do { ctxt <- getErrCtxt ;+ loc <- getSrcSpanM ;+ err_info <- mkErrInfo tidy_env ctxt ;+ mkLongErrAt loc err_msg err_info }++-- The failWith functions add an error message and cause failure++failWithTc :: MsgDoc -> TcM a -- Add an error message and fail+failWithTc err_msg+ = addErrTc err_msg >> failM++failWithTcM :: (TidyEnv, MsgDoc) -> TcM a -- Add an error message and fail+failWithTcM local_and_msg+ = addErrTcM local_and_msg >> failM++checkTc :: Bool -> MsgDoc -> TcM () -- Check that the boolean is true+checkTc True _ = return ()+checkTc False err = failWithTc err++checkTcM :: Bool -> (TidyEnv, MsgDoc) -> TcM ()+checkTcM True _ = return ()+checkTcM False err = failWithTcM err++failIfTc :: Bool -> MsgDoc -> TcM () -- Check that the boolean is false+failIfTc False _ = return ()+failIfTc True err = failWithTc err++failIfTcM :: Bool -> (TidyEnv, MsgDoc) -> TcM ()+ -- Check that the boolean is false+failIfTcM False _ = return ()+failIfTcM True err = failWithTcM err+++-- Warnings have no 'M' variant, nor failure++-- | Display a warning if a condition is met.+-- and the warning is enabled+warnIf :: WarnReason -> Bool -> MsgDoc -> TcRn ()+warnIf reason is_bad msg+ = do { warn_on <- case reason of+ NoReason -> return True+ Reason warn_flag -> woptM warn_flag+ ; when (warn_on && is_bad) $+ addWarn reason msg }++-- | Display a warning if a condition is met.+warnTc :: WarnReason -> Bool -> MsgDoc -> TcM ()+warnTc reason warn_if_true warn_msg+ | warn_if_true = addWarnTc reason warn_msg+ | otherwise = return ()++-- | Display a warning if a condition is met.+warnTcM :: WarnReason -> Bool -> (TidyEnv, MsgDoc) -> TcM ()+warnTcM reason warn_if_true warn_msg+ | warn_if_true = addWarnTcM reason warn_msg+ | otherwise = return ()++-- | Display a warning in the current context.+addWarnTc :: WarnReason -> MsgDoc -> TcM ()+addWarnTc reason msg+ = do { env0 <- tcInitTidyEnv ;+ addWarnTcM reason (env0, msg) }++-- | Display a warning in a given context.+addWarnTcM :: WarnReason -> (TidyEnv, MsgDoc) -> TcM ()+addWarnTcM reason (env0, msg)+ = do { ctxt <- getErrCtxt ;+ err_info <- mkErrInfo env0 ctxt ;+ add_warn reason msg err_info }++-- | Display a warning for the current source location.+addWarn :: WarnReason -> MsgDoc -> TcRn ()+addWarn reason msg = add_warn reason msg Outputable.empty++-- | Display a warning for a given source location.+addWarnAt :: WarnReason -> SrcSpan -> MsgDoc -> TcRn ()+addWarnAt reason loc msg = add_warn_at reason loc msg Outputable.empty++-- | Display a warning, with an optional flag, for the current source+-- location.+add_warn :: WarnReason -> MsgDoc -> MsgDoc -> TcRn ()+add_warn reason msg extra_info+ = do { loc <- getSrcSpanM+ ; add_warn_at reason loc msg extra_info }++-- | Display a warning, with an optional flag, for a given location.+add_warn_at :: WarnReason -> SrcSpan -> MsgDoc -> MsgDoc -> TcRn ()+add_warn_at reason loc msg extra_info+ = do { dflags <- getDynFlags ;+ printer <- getPrintUnqualified dflags ;+ let { warn = mkLongWarnMsg dflags loc printer+ msg extra_info } ;+ reportWarning reason warn }++tcInitTidyEnv :: TcM TidyEnv+tcInitTidyEnv+ = do { lcl_env <- getLclEnv+ ; return (tcl_tidy lcl_env) }++-- | Get a 'TidyEnv' that includes mappings for all vars free in the given+-- type. Useful when tidying open types.+tcInitOpenTidyEnv :: [TyCoVar] -> TcM TidyEnv+tcInitOpenTidyEnv tvs+ = do { env1 <- tcInitTidyEnv+ ; let env2 = tidyFreeTyCoVars env1 tvs+ ; return env2 }+++{-+-----------------------------------+ Other helper functions+-}++add_err_tcm :: TidyEnv -> MsgDoc -> SrcSpan+ -> [ErrCtxt]+ -> TcM ()+add_err_tcm tidy_env err_msg loc ctxt+ = do { err_info <- mkErrInfo tidy_env ctxt ;+ addLongErrAt loc err_msg err_info }++mkErrInfo :: TidyEnv -> [ErrCtxt] -> TcM SDoc+-- Tidy the error info, trimming excessive contexts+mkErrInfo env ctxts+-- = do+-- dbg <- hasPprDebug <$> getDynFlags+-- if dbg -- In -dppr-debug style the output+-- then return empty -- just becomes too voluminous+-- else go dbg 0 env ctxts+ = go False 0 env ctxts+ where+ go :: Bool -> Int -> TidyEnv -> [ErrCtxt] -> TcM SDoc+ go _ _ _ [] = return empty+ go dbg n env ((is_landmark, ctxt) : ctxts)+ | is_landmark || n < mAX_CONTEXTS -- Too verbose || dbg+ = do { (env', msg) <- ctxt env+ ; let n' = if is_landmark then n else n+1+ ; rest <- go dbg n' env' ctxts+ ; return (msg $$ rest) }+ | otherwise+ = go dbg n env ctxts++mAX_CONTEXTS :: Int -- No more than this number of non-landmark contexts+mAX_CONTEXTS = 3++-- debugTc is useful for monadic debugging code++debugTc :: TcM () -> TcM ()+debugTc thing+ | debugIsOn = thing+ | otherwise = return ()++{-+************************************************************************+* *+ Type constraints+* *+************************************************************************+-}++newTcEvBinds :: TcM EvBindsVar+newTcEvBinds = do { binds_ref <- newTcRef emptyEvBindMap+ ; tcvs_ref <- newTcRef emptyVarSet+ ; uniq <- newUnique+ ; traceTc "newTcEvBinds" (text "unique =" <+> ppr uniq)+ ; return (EvBindsVar { ebv_binds = binds_ref+ , ebv_tcvs = tcvs_ref+ , ebv_uniq = uniq }) }++getTcEvTyCoVars :: EvBindsVar -> TcM TyCoVarSet+getTcEvTyCoVars (EvBindsVar { ebv_tcvs = ev_ref })+ = readTcRef ev_ref++getTcEvBindsMap :: EvBindsVar -> TcM EvBindMap+getTcEvBindsMap (EvBindsVar { ebv_binds = ev_ref })+ = readTcRef ev_ref++addTcEvBind :: EvBindsVar -> EvBind -> TcM ()+-- Add a binding to the TcEvBinds by side effect+addTcEvBind (EvBindsVar { ebv_binds = ev_ref, ebv_uniq = u }) ev_bind+ = do { traceTc "addTcEvBind" $ ppr u $$+ ppr ev_bind+ ; bnds <- readTcRef ev_ref+ ; writeTcRef ev_ref (extendEvBinds bnds ev_bind) }++chooseUniqueOccTc :: (OccSet -> OccName) -> TcM OccName+chooseUniqueOccTc fn =+ do { env <- getGblEnv+ ; let dfun_n_var = tcg_dfun_n env+ ; set <- readTcRef dfun_n_var+ ; let occ = fn set+ ; writeTcRef dfun_n_var (extendOccSet set occ)+ ; return occ }++getConstraintVar :: TcM (TcRef WantedConstraints)+getConstraintVar = do { env <- getLclEnv; return (tcl_lie env) }++setConstraintVar :: TcRef WantedConstraints -> TcM a -> TcM a+setConstraintVar lie_var = updLclEnv (\ env -> env { tcl_lie = lie_var })++emitStaticConstraints :: WantedConstraints -> TcM ()+emitStaticConstraints static_lie+ = do { gbl_env <- getGblEnv+ ; updTcRef (tcg_static_wc gbl_env) (`andWC` static_lie) }++emitConstraints :: WantedConstraints -> TcM ()+emitConstraints ct+ = do { lie_var <- getConstraintVar ;+ updTcRef lie_var (`andWC` ct) }++emitSimple :: Ct -> TcM ()+emitSimple ct+ = do { lie_var <- getConstraintVar ;+ updTcRef lie_var (`addSimples` unitBag ct) }++emitSimples :: Cts -> TcM ()+emitSimples cts+ = do { lie_var <- getConstraintVar ;+ updTcRef lie_var (`addSimples` cts) }++emitImplication :: Implication -> TcM ()+emitImplication ct+ = do { lie_var <- getConstraintVar ;+ updTcRef lie_var (`addImplics` unitBag ct) }++emitImplications :: Bag Implication -> TcM ()+emitImplications ct+ = unless (isEmptyBag ct) $+ do { lie_var <- getConstraintVar ;+ updTcRef lie_var (`addImplics` ct) }++emitInsoluble :: Ct -> TcM ()+emitInsoluble ct+ = do { traceTc "emitInsoluble" (ppr ct)+ ; lie_var <- getConstraintVar+ ; updTcRef lie_var (`addInsols` unitBag ct) }++emitInsolubles :: Cts -> TcM ()+emitInsolubles cts+ | isEmptyBag cts = return ()+ | otherwise = do { traceTc "emitInsolubles" (ppr cts)+ ; lie_var <- getConstraintVar+ ; updTcRef lie_var (`addInsols` cts) }++-- | Throw out any constraints emitted by the thing_inside+discardConstraints :: TcM a -> TcM a+discardConstraints thing_inside = fst <$> captureConstraints thing_inside++tryCaptureConstraints :: TcM a -> TcM (Either IOEnvFailure a, WantedConstraints)+-- (captureConstraints_maybe m) runs m,+-- and returns the type constraints it generates+-- It never throws an exception; instead if thing_inside fails,+-- it returns Left exn and the insoluble constraints+tryCaptureConstraints thing_inside+ = do { lie_var <- newTcRef emptyWC+ ; mb_res <- tryM $+ updLclEnv (\ env -> env { tcl_lie = lie_var }) $+ thing_inside+ ; lie <- readTcRef lie_var++ -- See Note [Constraints and errors]+ ; let lie_to_keep = case mb_res of+ Left {} -> insolublesOnly lie+ Right {} -> lie++ ; return (mb_res, lie_to_keep) }++captureConstraints :: TcM a -> TcM (a, WantedConstraints)+-- (captureConstraints m) runs m, and returns the type constraints it generates+captureConstraints thing_inside+ = do { (mb_res, lie) <- tryCaptureConstraints thing_inside++ -- See Note [Constraints and errors]+ -- If the thing_inside threw an exception, emit the insoluble+ -- constraints only (returned by tryCaptureConstraints)+ -- so that they are not lost+ ; case mb_res of+ Left _ -> do { emitConstraints lie; failM }+ Right res -> return (res, lie) }++pushLevelAndCaptureConstraints :: TcM a -> TcM (TcLevel, WantedConstraints, a)+pushLevelAndCaptureConstraints thing_inside+ = do { env <- getLclEnv+ ; let tclvl' = pushTcLevel (tcl_tclvl env)+ ; (res, lie) <- setLclEnv (env { tcl_tclvl = tclvl' }) $+ captureConstraints thing_inside+ ; return (tclvl', lie, res) }++pushTcLevelM_ :: TcM a -> TcM a+pushTcLevelM_ x = updLclEnv (\ env -> env { tcl_tclvl = pushTcLevel (tcl_tclvl env) }) x++pushTcLevelM :: TcM a -> TcM (a, TcLevel)+-- See Note [TcLevel assignment] in TcType+pushTcLevelM thing_inside+ = do { env <- getLclEnv+ ; let tclvl' = pushTcLevel (tcl_tclvl env)+ ; res <- setLclEnv (env { tcl_tclvl = tclvl' })+ thing_inside+ ; return (res, tclvl') }++getTcLevel :: TcM TcLevel+getTcLevel = do { env <- getLclEnv+ ; return (tcl_tclvl env) }++setTcLevel :: TcLevel -> TcM a -> TcM a+setTcLevel tclvl thing_inside+ = updLclEnv (\env -> env { tcl_tclvl = tclvl }) thing_inside++isTouchableTcM :: TcTyVar -> TcM Bool+isTouchableTcM tv+ = do { env <- getLclEnv+ ; return (isTouchableMetaTyVar (tcl_tclvl env) tv) }++getLclTypeEnv :: TcM TcTypeEnv+getLclTypeEnv = do { env <- getLclEnv; return (tcl_env env) }++setLclTypeEnv :: TcLclEnv -> TcM a -> TcM a+-- Set the local type envt, but do *not* disturb other fields,+-- notably the lie_var+setLclTypeEnv lcl_env thing_inside+ = updLclEnv upd thing_inside+ where+ upd env = env { tcl_env = tcl_env lcl_env,+ tcl_tyvars = tcl_tyvars lcl_env }++traceTcConstraints :: String -> TcM ()+traceTcConstraints msg+ = do { lie_var <- getConstraintVar+ ; lie <- readTcRef lie_var+ ; traceOptTcRn Opt_D_dump_tc_trace $+ hang (text (msg ++ ": LIE:")) 2 (ppr lie)+ }++emitWildCardHoleConstraints :: [(Name, TcTyVar)] -> TcM ()+emitWildCardHoleConstraints wcs+ = do { ct_loc <- getCtLocM HoleOrigin Nothing+ ; emitInsolubles $ listToBag $+ map (do_one ct_loc) wcs }+ where+ do_one :: CtLoc -> (Name, TcTyVar) -> Ct+ do_one ct_loc (name, tv)+ = CHoleCan { cc_ev = CtDerived { ctev_pred = mkTyVarTy tv+ , ctev_loc = ct_loc' }+ , cc_hole = TypeHole (occName name) }+ where+ real_span = case nameSrcSpan name of+ RealSrcSpan span -> span+ UnhelpfulSpan str -> pprPanic "emitWildCardHoleConstraints"+ (ppr name <+> quotes (ftext str))+ -- Wildcards are defined locally, and so have RealSrcSpans+ ct_loc' = setCtLocSpan ct_loc real_span++{- Note [Constraints and errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this (Trac #12124):++ foo :: Maybe Int+ foo = return (case Left 3 of+ Left -> 1 -- Hard error here!+ _ -> 0)++The call to 'return' will generate a (Monad m) wanted constraint; but+then there'll be "hard error" (i.e. an exception in the TcM monad), from+the unsaturated Left constructor pattern.++We'll recover in tcPolyBinds, using recoverM. But then the final+tcSimplifyTop will see that (Monad m) constraint, with 'm' utterly+un-filled-in, and will emit a misleading error message.++The underlying problem is that an exception interrupts the constraint+gathering process. Bottom line: if we have an exception, it's best+simply to discard any gathered constraints. Hence in 'try_m' we+capture the constraints in a fresh variable, and only emit them into+the surrounding context if we exit normally. If an exception is+raised, simply discard the collected constraints... we have a hard+error to report. So this capture-the-emit dance isn't as stupid as it+looks :-).++However suppose we throw an exception inside an invocation of+captureConstraints, and discard all the constraints. Some of those+contraints might be "variable out of scope" Hole constraints, and that+might have been the actual original cause of the exception! For+example (Trac #12529):+ f = p @ Int+Here 'p' is out of scope, so we get an insolube Hole constraint. But+the visible type application fails in the monad (thows an exception).+We must not discard the out-of-scope error.++So we /retain the insoluble constraints/ if there is an exception.+Hence:+ - insolublesOnly in tryCaptureConstraints+ - emitConstraints in the Left case of captureConstraints+++************************************************************************+* *+ Template Haskell context+* *+************************************************************************+-}++recordThUse :: TcM ()+recordThUse = do { env <- getGblEnv; writeTcRef (tcg_th_used env) True }++recordThSpliceUse :: TcM ()+recordThSpliceUse = do { env <- getGblEnv; writeTcRef (tcg_th_splice_used env) True }++-- | When generating an out-of-scope error message for a variable matching a+-- binding in a later inter-splice group, the typechecker uses the splice+-- locations to provide details in the message about the scope of that binding.+recordTopLevelSpliceLoc :: SrcSpan -> TcM ()+recordTopLevelSpliceLoc (RealSrcSpan real_loc)+ = do { env <- getGblEnv+ ; let locs_var = tcg_th_top_level_locs env+ ; locs0 <- readTcRef locs_var+ ; writeTcRef locs_var (Set.insert real_loc locs0) }+recordTopLevelSpliceLoc (UnhelpfulSpan _) = return ()++getTopLevelSpliceLocs :: TcM (Set RealSrcSpan)+getTopLevelSpliceLocs+ = do { env <- getGblEnv+ ; readTcRef (tcg_th_top_level_locs env) }++keepAlive :: Name -> TcRn () -- Record the name in the keep-alive set+keepAlive name+ = do { env <- getGblEnv+ ; traceRn "keep alive" (ppr name)+ ; updTcRef (tcg_keep env) (`extendNameSet` name) }++getStage :: TcM ThStage+getStage = do { env <- getLclEnv; return (tcl_th_ctxt env) }++getStageAndBindLevel :: Name -> TcRn (Maybe (TopLevelFlag, ThLevel, ThStage))+getStageAndBindLevel name+ = do { env <- getLclEnv;+ ; case lookupNameEnv (tcl_th_bndrs env) name of+ Nothing -> return Nothing+ Just (top_lvl, bind_lvl) -> return (Just (top_lvl, bind_lvl, tcl_th_ctxt env)) }++setStage :: ThStage -> TcM a -> TcRn a+setStage s = updLclEnv (\ env -> env { tcl_th_ctxt = s })++-- | Adds the given modFinalizers to the global environment and set them to use+-- the current local environment.+addModFinalizersWithLclEnv :: ThModFinalizers -> TcM ()+addModFinalizersWithLclEnv mod_finalizers+ = do lcl_env <- getLclEnv+ th_modfinalizers_var <- fmap tcg_th_modfinalizers getGblEnv+ updTcRef th_modfinalizers_var $ \fins ->+ setLclEnv lcl_env (runRemoteModFinalizers mod_finalizers)+ : fins++{-+************************************************************************+* *+ Safe Haskell context+* *+************************************************************************+-}++-- | Mark that safe inference has failed+-- See Note [Safe Haskell Overlapping Instances Implementation]+-- although this is used for more than just that failure case.+recordUnsafeInfer :: WarningMessages -> TcM ()+recordUnsafeInfer warns =+ getGblEnv >>= \env -> writeTcRef (tcg_safeInfer env) (False, warns)++-- | Figure out the final correct safe haskell mode+finalSafeMode :: DynFlags -> TcGblEnv -> IO SafeHaskellMode+finalSafeMode dflags tcg_env = do+ safeInf <- fst <$> readIORef (tcg_safeInfer tcg_env)+ return $ case safeHaskell dflags of+ Sf_None | safeInferOn dflags && safeInf -> Sf_Safe+ | otherwise -> Sf_None+ s -> s++-- | Switch instances to safe instances if we're in Safe mode.+fixSafeInstances :: SafeHaskellMode -> [ClsInst] -> [ClsInst]+fixSafeInstances sfMode | sfMode /= Sf_Safe = id+fixSafeInstances _ = map fixSafe+ where fixSafe inst = let new_flag = (is_flag inst) { isSafeOverlap = True }+ in inst { is_flag = new_flag }++{-+************************************************************************+* *+ Stuff for the renamer's local env+* *+************************************************************************+-}++getLocalRdrEnv :: RnM LocalRdrEnv+getLocalRdrEnv = do { env <- getLclEnv; return (tcl_rdr env) }++setLocalRdrEnv :: LocalRdrEnv -> RnM a -> RnM a+setLocalRdrEnv rdr_env thing_inside+ = updLclEnv (\env -> env {tcl_rdr = rdr_env}) thing_inside++{-+************************************************************************+* *+ Stuff for interface decls+* *+************************************************************************+-}++mkIfLclEnv :: Module -> SDoc -> Bool -> IfLclEnv+mkIfLclEnv mod loc boot+ = IfLclEnv { if_mod = mod,+ if_loc = loc,+ if_boot = boot,+ if_nsubst = Nothing,+ if_implicits_env = Nothing,+ if_tv_env = emptyFsEnv,+ if_id_env = emptyFsEnv }++-- | Run an 'IfG' (top-level interface monad) computation inside an existing+-- 'TcRn' (typecheck-renaming monad) computation by initializing an 'IfGblEnv'+-- based on 'TcGblEnv'.+initIfaceTcRn :: IfG a -> TcRn a+initIfaceTcRn thing_inside+ = do { tcg_env <- getGblEnv+ ; dflags <- getDynFlags+ ; let mod = tcg_semantic_mod tcg_env+ -- When we are instantiating a signature, we DEFINITELY+ -- do not want to knot tie.+ is_instantiate = unitIdIsDefinite (thisPackage dflags) &&+ not (null (thisUnitIdInsts dflags))+ ; let { if_env = IfGblEnv {+ if_doc = text "initIfaceTcRn",+ if_rec_types =+ if is_instantiate+ then Nothing+ else Just (mod, get_type_env)+ }+ ; get_type_env = readTcRef (tcg_type_env_var tcg_env) }+ ; setEnvs (if_env, ()) thing_inside }++-- Used when sucking in a ModIface into a ModDetails to put in+-- the HPT. Notably, unlike initIfaceCheck, this does NOT use+-- hsc_type_env_var (since we're not actually going to typecheck,+-- so this variable will never get updated!)+initIfaceLoad :: HscEnv -> IfG a -> IO a+initIfaceLoad hsc_env do_this+ = do let gbl_env = IfGblEnv {+ if_doc = text "initIfaceLoad",+ if_rec_types = Nothing+ }+ initTcRnIf 'i' hsc_env gbl_env () do_this++initIfaceCheck :: SDoc -> HscEnv -> IfG a -> IO a+-- Used when checking the up-to-date-ness of the old Iface+-- Initialise the environment with no useful info at all+initIfaceCheck doc hsc_env do_this+ = do let rec_types = case hsc_type_env_var hsc_env of+ Just (mod,var) -> Just (mod, readTcRef var)+ Nothing -> Nothing+ gbl_env = IfGblEnv {+ if_doc = text "initIfaceCheck" <+> doc,+ if_rec_types = rec_types+ }+ initTcRnIf 'i' hsc_env gbl_env () do_this++initIfaceLcl :: Module -> SDoc -> Bool -> IfL a -> IfM lcl a+initIfaceLcl mod loc_doc hi_boot_file thing_inside+ = setLclEnv (mkIfLclEnv mod loc_doc hi_boot_file) thing_inside++-- | Initialize interface typechecking, but with a 'NameShape'+-- to apply when typechecking top-level 'OccName's (see+-- 'lookupIfaceTop')+initIfaceLclWithSubst :: Module -> SDoc -> Bool -> NameShape -> IfL a -> IfM lcl a+initIfaceLclWithSubst mod loc_doc hi_boot_file nsubst thing_inside+ = setLclEnv ((mkIfLclEnv mod loc_doc hi_boot_file) { if_nsubst = Just nsubst }) thing_inside++getIfModule :: IfL Module+getIfModule = do { env <- getLclEnv; return (if_mod env) }++--------------------+failIfM :: MsgDoc -> IfL a+-- The Iface monad doesn't have a place to accumulate errors, so we+-- just fall over fast if one happens; it "shouldn't happen".+-- We use IfL here so that we can get context info out of the local env+failIfM msg+ = do { env <- getLclEnv+ ; let full_msg = (if_loc env <> colon) $$ nest 2 msg+ ; dflags <- getDynFlags+ ; liftIO (putLogMsg dflags NoReason SevFatal+ noSrcSpan (defaultErrStyle dflags) full_msg)+ ; failM }++--------------------+forkM_maybe :: SDoc -> IfL a -> IfL (Maybe a)+-- Run thing_inside in an interleaved thread.+-- It shares everything with the parent thread, so this is DANGEROUS.+--+-- It returns Nothing if the computation fails+--+-- It's used for lazily type-checking interface+-- signatures, which is pretty benign++forkM_maybe doc thing_inside+ -- NB: Don't share the mutable env_us with the interleaved thread since env_us+ -- does not get updated atomically (e.g. in newUnique and newUniqueSupply).+ = do { child_us <- newUniqueSupply+ ; child_env_us <- newMutVar child_us+ -- see Note [Masking exceptions in forkM_maybe]+ ; unsafeInterleaveM $ uninterruptibleMaskM_ $ updEnv (\env -> env { env_us = child_env_us }) $+ do { traceIf (text "Starting fork {" <+> doc)+ ; mb_res <- tryM $+ updLclEnv (\env -> env { if_loc = if_loc env $$ doc }) $+ thing_inside+ ; case mb_res of+ Right r -> do { traceIf (text "} ending fork" <+> doc)+ ; return (Just r) }+ Left exn -> do {++ -- Bleat about errors in the forked thread, if -ddump-if-trace is on+ -- Otherwise we silently discard errors. Errors can legitimately+ -- happen when compiling interface signatures (see tcInterfaceSigs)+ whenDOptM Opt_D_dump_if_trace $ do+ dflags <- getDynFlags+ let msg = hang (text "forkM failed:" <+> doc)+ 2 (text (show exn))+ liftIO $ putLogMsg dflags+ NoReason+ SevFatal+ noSrcSpan+ (defaultErrStyle dflags)+ msg++ ; traceIf (text "} ending fork (badly)" <+> doc)+ ; return Nothing }+ }}++forkM :: SDoc -> IfL a -> IfL a+forkM doc thing_inside+ = do { mb_res <- forkM_maybe doc thing_inside+ ; return (case mb_res of+ Nothing -> pgmError "Cannot continue after interface file error"+ -- pprPanic "forkM" doc+ Just r -> r) }++setImplicitEnvM :: TypeEnv -> IfL a -> IfL a+setImplicitEnvM tenv m = updLclEnv (\lcl -> lcl { if_implicits_env = Just tenv }) m++{-+Note [Masking exceptions in forkM_maybe]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When using GHC-as-API it must be possible to interrupt snippets of code+executed using runStmt (#1381). Since commit 02c4ab04 this is almost possible+by throwing an asynchronous interrupt to the GHC thread. However, there is a+subtle problem: runStmt first typechecks the code before running it, and the+exception might interrupt the type checker rather than the code. Moreover, the+typechecker might be inside an unsafeInterleaveIO (through forkM_maybe), and+more importantly might be inside an exception handler inside that+unsafeInterleaveIO. If that is the case, the exception handler will rethrow the+asynchronous exception as a synchronous exception, and the exception will end+up as the value of the unsafeInterleaveIO thunk (see #8006 for a detailed+discussion). We don't currently know a general solution to this problem, but+we can use uninterruptibleMask_ to avoid the situation.+-}
+ typecheck/TcRnTypes.hs view
@@ -0,0 +1,3499 @@+{-+(c) The University of Glasgow 2006-2012+(c) The GRASP Project, Glasgow University, 1992-2002+++Various types used during typechecking, please see TcRnMonad as well for+operations on these types. You probably want to import it, instead of this+module.++All the monads exported here are built on top of the same IOEnv monad. The+monad functions like a Reader monad in the way it passes the environment+around. This is done to allow the environment to be manipulated in a stack+like fashion when entering expressions... ect.++For state that is global and should be returned at the end (e.g not part+of the stack mechanism), you should use an TcRef (= IORef) to store them.+-}++{-# LANGUAGE CPP, ExistentialQuantification, GeneralizedNewtypeDeriving,+ ViewPatterns #-}++module TcRnTypes(+ TcRnIf, TcRn, TcM, RnM, IfM, IfL, IfG, -- The monad is opaque outside this module+ TcRef,++ -- The environment types+ Env(..),+ TcGblEnv(..), TcLclEnv(..),+ IfGblEnv(..), IfLclEnv(..),+ tcVisibleOrphanMods,++ -- Frontend types (shouldn't really be here)+ FrontendResult(..),++ -- Renamer types+ ErrCtxt, RecFieldEnv,+ ImportAvails(..), emptyImportAvails, plusImportAvails,+ WhereFrom(..), mkModDeps, modDepsElts,++ -- Typechecker types+ TcTypeEnv, TcIdBinderStack, TcIdBinder(..),+ TcTyThing(..), PromotionErr(..),+ IdBindingInfo(..), ClosedTypeId, RhsNames,+ IsGroupClosed(..),+ SelfBootInfo(..),+ pprTcTyThingCategory, pprPECategory, CompleteMatch(..),++ -- Desugaring types+ DsM, DsLclEnv(..), DsGblEnv(..), PArrBuiltin(..),+ DsMetaEnv, DsMetaVal(..), CompleteMatchMap,+ mkCompleteMatchMap, extendCompleteMatchMap,++ -- Template Haskell+ ThStage(..), SpliceType(..), PendingStuff(..),+ topStage, topAnnStage, topSpliceStage,+ ThLevel, impLevel, outerLevel, thLevel,+ ForeignSrcLang(..),++ -- Arrows+ ArrowCtxt(..),++ -- TcSigInfo+ TcSigFun, TcSigInfo(..), TcIdSigInfo(..),+ TcIdSigInst(..), TcPatSynInfo(..),+ isPartialSig, hasCompleteSig,++ -- Canonical constraints+ Xi, Ct(..), Cts, emptyCts, andCts, andManyCts, pprCts,+ singleCt, listToCts, ctsElts, consCts, snocCts, extendCtsList,+ isEmptyCts, isCTyEqCan, isCFunEqCan,+ isPendingScDict, superClassesMightHelp,+ isCDictCan_Maybe, isCFunEqCan_maybe,+ isCIrredEvCan, isCNonCanonical, isWantedCt, isDerivedCt,+ isGivenCt, isHoleCt, isOutOfScopeCt, isExprHoleCt, isTypeHoleCt,+ isUserTypeErrorCt, getUserTypeErrorMsg,+ ctEvidence, ctLoc, setCtLoc, ctPred, ctFlavour, ctEqRel, ctOrigin,+ mkTcEqPredLikeEv,+ mkNonCanonical, mkNonCanonicalCt, mkGivens,+ ctEvPred, ctEvLoc, ctEvOrigin, ctEvEqRel,+ ctEvTerm, ctEvCoercion, ctEvId,+ tyCoVarsOfCt, tyCoVarsOfCts,+ tyCoVarsOfCtList, tyCoVarsOfCtsList,++ WantedConstraints(..), insolubleWC, emptyWC, isEmptyWC,+ andWC, unionsWC, mkSimpleWC, mkImplicWC,+ addInsols, getInsolubles, insolublesOnly, addSimples, addImplics,+ tyCoVarsOfWC, dropDerivedWC, dropDerivedSimples, dropDerivedInsols,+ tyCoVarsOfWCList, trulyInsoluble,+ isDroppableDerivedLoc, insolubleImplic,+ arisesFromGivens,++ Implication(..), ImplicStatus(..), isInsolubleStatus, isSolvedStatus,+ SubGoalDepth, initialSubGoalDepth, maxSubGoalDepth,+ bumpSubGoalDepth, subGoalDepthExceeded,+ CtLoc(..), ctLocSpan, ctLocEnv, ctLocLevel, ctLocOrigin,+ ctLocTypeOrKind_maybe,+ ctLocDepth, bumpCtLocDepth,+ setCtLocOrigin, setCtLocEnv, setCtLocSpan,+ CtOrigin(..), exprCtOrigin, lexprCtOrigin, matchesCtOrigin, grhssCtOrigin,+ ErrorThing(..), mkErrorThing, errorThingNumArgs_maybe,+ TypeOrKind(..), isTypeLevel, isKindLevel,+ pprCtOrigin, pprCtLoc,+ pushErrCtxt, pushErrCtxtSameOrigin,++ SkolemInfo(..), pprSigSkolInfo, pprSkolInfo,+ termEvidenceAllowed,++ CtEvidence(..), TcEvDest(..),+ mkGivenLoc, mkKindLoc, toKindLoc,+ isWanted, isGiven, isDerived, isGivenOrWDeriv,+ ctEvRole,++ -- Constraint solver plugins+ TcPlugin(..), TcPluginResult(..), TcPluginSolver,+ TcPluginM, runTcPluginM, unsafeTcPluginTcM,+ getEvBindsTcPluginM,++ CtFlavour(..), ShadowInfo(..), ctEvFlavour,+ CtFlavourRole, ctEvFlavourRole, ctFlavourRole,+ eqCanRewriteFR, eqMayRewriteFR,+ eqCanDischarge,+ funEqCanDischarge, funEqCanDischargeF,++ -- Pretty printing+ pprEvVarTheta,+ pprEvVars, pprEvVarWithType,++ -- Misc other types+ TcId, TcIdSet,+ Hole(..), holeOcc,+ NameShape(..)++ ) where++#include "HsVersions.h"++import HsSyn+import CoreSyn+import HscTypes+import TcEvidence+import Type+import Class ( Class )+import TyCon ( TyCon, tyConKind )+import Coercion ( Coercion, mkHoleCo )+import ConLike ( ConLike(..) )+import DataCon ( DataCon, dataConUserType, dataConOrigArgTys )+import PatSyn ( PatSyn, pprPatSynType )+import Id ( idType, idName )+import FieldLabel ( FieldLabel )+import TcType+import Annotations+import InstEnv+import FamInstEnv+import PmExpr+import IOEnv+import RdrName+import Name+import NameEnv+import NameSet+import Avail+import Var+import FV+import VarEnv+import Module+import SrcLoc+import VarSet+import ErrUtils+import UniqFM+import UniqSupply+import BasicTypes+import Bag+import DynFlags+import Outputable+import ListSetOps+import FastString+import qualified GHC.LanguageExtensions as LangExt+import Fingerprint+import Util++import Control.Monad (ap, liftM, msum)+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif+import Data.Set ( Set )+import qualified Data.Set as S++import Data.List ( sort )+import Data.Map ( Map )+import Data.Dynamic ( Dynamic )+import Data.Typeable ( TypeRep )+import GHCi.Message+import GHCi.RemoteTypes++import qualified Language.Haskell.TH as TH++-- | A 'NameShape' is a substitution on 'Name's that can be used+-- to refine the identities of a hole while we are renaming interfaces+-- (see 'RnModIface'). Specifically, a 'NameShape' for+-- 'ns_module_name' @A@, defines a mapping from @{A.T}@+-- (for some 'OccName' @T@) to some arbitrary other 'Name'.+--+-- The most intruiging thing about a 'NameShape', however, is+-- how it's constructed. A 'NameShape' is *implied* by the+-- exported 'AvailInfo's of the implementor of an interface:+-- if an implementor of signature @<H>@ exports @M.T@, you implicitly+-- define a substitution from @{H.T}@ to @M.T@. So a 'NameShape'+-- is computed from the list of 'AvailInfo's that are exported+-- by the implementation of a module, or successively merged+-- together by the export lists of signatures which are joining+-- together.+--+-- It's not the most obvious way to go about doing this, but it+-- does seem to work!+--+-- NB: Can't boot this and put it in NameShape because then we+-- start pulling in too many DynFlags things.+data NameShape = NameShape {+ ns_mod_name :: ModuleName,+ ns_exports :: [AvailInfo],+ ns_map :: OccEnv Name+ }+++{-+************************************************************************+* *+ Standard monad definition for TcRn+ All the combinators for the monad can be found in TcRnMonad+* *+************************************************************************++The monad itself has to be defined here, because it is mentioned by ErrCtxt+-}++type TcRnIf a b = IOEnv (Env a b)+type TcRn = TcRnIf TcGblEnv TcLclEnv -- Type inference+type IfM lcl = TcRnIf IfGblEnv lcl -- Iface stuff+type IfG = IfM () -- Top level+type IfL = IfM IfLclEnv -- Nested+type DsM = TcRnIf DsGblEnv DsLclEnv -- Desugaring++-- TcRn is the type-checking and renaming monad: the main monad that+-- most type-checking takes place in. The global environment is+-- 'TcGblEnv', which tracks all of the top-level type-checking+-- information we've accumulated while checking a module, while the+-- local environment is 'TcLclEnv', which tracks local information as+-- we move inside expressions.++-- | Historical "renaming monad" (now it's just 'TcRn').+type RnM = TcRn++-- | Historical "type-checking monad" (now it's just 'TcRn').+type TcM = TcRn++-- We 'stack' these envs through the Reader like monad infrastructure+-- as we move into an expression (although the change is focused in+-- the lcl type).+data Env gbl lcl+ = Env {+ env_top :: HscEnv, -- Top-level stuff that never changes+ -- Includes all info about imported things++ env_us :: {-# UNPACK #-} !(IORef UniqSupply),+ -- Unique supply for local variables++ env_gbl :: gbl, -- Info about things defined at the top level+ -- of the module being compiled++ env_lcl :: lcl -- Nested stuff; changes as we go into+ }++instance ContainsDynFlags (Env gbl lcl) where+ extractDynFlags env = hsc_dflags (env_top env)++instance ContainsModule gbl => ContainsModule (Env gbl lcl) where+ extractModule env = extractModule (env_gbl env)+++{-+************************************************************************+* *+ The interface environments+ Used when dealing with IfaceDecls+* *+************************************************************************+-}++data IfGblEnv+ = IfGblEnv {+ -- Some information about where this environment came from;+ -- useful for debugging.+ if_doc :: SDoc,+ -- The type environment for the module being compiled,+ -- in case the interface refers back to it via a reference that+ -- was originally a hi-boot file.+ -- We need the module name so we can test when it's appropriate+ -- to look in this env.+ -- See Note [Tying the knot] in TcIface+ if_rec_types :: Maybe (Module, IfG TypeEnv)+ -- Allows a read effect, so it can be in a mutable+ -- variable; c.f. handling the external package type env+ -- Nothing => interactive stuff, no loops possible+ }++data IfLclEnv+ = IfLclEnv {+ -- The module for the current IfaceDecl+ -- So if we see f = \x -> x+ -- it means M.f = \x -> x, where M is the if_mod+ -- NB: This is a semantic module, see+ -- Note [Identity versus semantic module]+ if_mod :: Module,++ -- Whether or not the IfaceDecl came from a boot+ -- file or not; we'll use this to choose between+ -- NoUnfolding and BootUnfolding+ if_boot :: Bool,++ -- The field is used only for error reporting+ -- if (say) there's a Lint error in it+ if_loc :: SDoc,+ -- Where the interface came from:+ -- .hi file, or GHCi state, or ext core+ -- plus which bit is currently being examined++ if_nsubst :: Maybe NameShape,++ -- This field is used to make sure "implicit" declarations+ -- (anything that cannot be exported in mi_exports) get+ -- wired up correctly in typecheckIfacesForMerging. Most+ -- of the time it's @Nothing@. See Note [Resolving never-exported Names in TcIface]+ -- in TcIface.+ if_implicits_env :: Maybe TypeEnv,++ if_tv_env :: FastStringEnv TyVar, -- Nested tyvar bindings+ if_id_env :: FastStringEnv Id -- Nested id binding+ }++{-+************************************************************************+* *+ Desugarer monad+* *+************************************************************************++Now the mondo monad magic (yes, @DsM@ is a silly name)---carry around+a @UniqueSupply@ and some annotations, which+presumably include source-file location information:+-}++-- If '-XParallelArrays' is given, the desugarer populates this table with the corresponding+-- variables found in 'Data.Array.Parallel'.+--+data PArrBuiltin+ = PArrBuiltin+ { lengthPVar :: Var -- ^ lengthP+ , replicatePVar :: Var -- ^ replicateP+ , singletonPVar :: Var -- ^ singletonP+ , mapPVar :: Var -- ^ mapP+ , filterPVar :: Var -- ^ filterP+ , zipPVar :: Var -- ^ zipP+ , crossMapPVar :: Var -- ^ crossMapP+ , indexPVar :: Var -- ^ (!:)+ , emptyPVar :: Var -- ^ emptyP+ , appPVar :: Var -- ^ (+:+)+ , enumFromToPVar :: Var -- ^ enumFromToP+ , enumFromThenToPVar :: Var -- ^ enumFromThenToP+ }++data DsGblEnv+ = DsGblEnv+ { ds_mod :: Module -- For SCC profiling+ , ds_fam_inst_env :: FamInstEnv -- Like tcg_fam_inst_env+ , ds_unqual :: PrintUnqualified+ , ds_msgs :: IORef Messages -- Warning messages+ , ds_if_env :: (IfGblEnv, IfLclEnv) -- Used for looking up global,+ -- possibly-imported things+ , ds_dph_env :: GlobalRdrEnv -- exported entities of 'Data.Array.Parallel.Prim'+ -- iff '-fvectorise' flag was given as well as+ -- exported entities of 'Data.Array.Parallel' iff+ -- '-XParallelArrays' was given; otherwise, empty+ , ds_parr_bi :: PArrBuiltin -- desugarar names for '-XParallelArrays'+ , ds_complete_matches :: CompleteMatchMap+ -- Additional complete pattern matches+ }++instance ContainsModule DsGblEnv where+ extractModule = ds_mod++data DsLclEnv = DsLclEnv {+ dsl_meta :: DsMetaEnv, -- Template Haskell bindings+ dsl_loc :: RealSrcSpan, -- To put in pattern-matching error msgs+ dsl_dicts :: Bag EvVar, -- Constraints from GADT pattern-matching+ dsl_tm_cs :: Bag SimpleEq,+ dsl_pm_iter :: IORef Int -- no iterations for pmcheck+ }++-- Inside [| |] brackets, the desugarer looks+-- up variables in the DsMetaEnv+type DsMetaEnv = NameEnv DsMetaVal++data DsMetaVal+ = DsBound Id -- Bound by a pattern inside the [| |].+ -- Will be dynamically alpha renamed.+ -- The Id has type THSyntax.Var++ | DsSplice (HsExpr Id) -- These bindings are introduced by+ -- the PendingSplices on a HsBracketOut+++{-+************************************************************************+* *+ Global typechecker environment+* *+************************************************************************+-}++-- | 'FrontendResult' describes the result of running the+-- frontend of a Haskell module. Usually, you'll get+-- a 'FrontendTypecheck', since running the frontend involves+-- typechecking a program, but for an hs-boot merge you'll+-- just get a ModIface, since no actual typechecking occurred.+--+-- This data type really should be in HscTypes, but it needs+-- to have a TcGblEnv which is only defined here.+data FrontendResult+ = FrontendTypecheck TcGblEnv++-- Note [Identity versus semantic module]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- When typechecking an hsig file, it is convenient to keep track+-- of two different "this module" identifiers:+--+-- - The IDENTITY module is simply thisPackage + the module+-- name; i.e. it uniquely *identifies* the interface file+-- we're compiling. For example, p[A=<A>]:A is an+-- identity module identifying the requirement named A+-- from library p.+--+-- - The SEMANTIC module, which is the actual module that+-- this signature is intended to represent (e.g. if+-- we have a identity module p[A=base:Data.IORef]:A,+-- then the semantic module is base:Data.IORef)+--+-- Which one should you use?+--+-- - In the desugarer and later phases of compilation,+-- identity and semantic modules coincide, since we never compile+-- signatures (we just generate blank object files for+-- hsig files.)+--+-- A corrolary of this is that the following invariant holds at any point+-- past desugaring,+--+-- if I have a Module, this_mod, in hand representing the module+-- currently being compiled,+-- then moduleUnitId this_mod == thisPackage dflags+--+-- - For any code involving Names, we want semantic modules.+-- See lookupIfaceTop in IfaceEnv, mkIface and addFingerprints+-- in MkIface, and tcLookupGlobal in TcEnv+--+-- - When reading interfaces, we want the identity module to+-- identify the specific interface we want (such interfaces+-- should never be loaded into the EPS). However, if a+-- hole module <A> is requested, we look for A.hi+-- in the home library we are compiling. (See LoadIface.)+-- Similarly, in RnNames we check for self-imports using+-- identity modules, to allow signatures to import their implementor.+--+-- - For recompilation avoidance, you want the identity module,+-- since that will actually say the specific interface you+-- want to track (and recompile if it changes)++-- | 'TcGblEnv' describes the top-level of the module at the+-- point at which the typechecker is finished work.+-- It is this structure that is handed on to the desugarer+-- For state that needs to be updated during the typechecking+-- phase and returned at end, use a 'TcRef' (= 'IORef').+data TcGblEnv+ = TcGblEnv {+ tcg_mod :: Module, -- ^ Module being compiled+ tcg_semantic_mod :: Module, -- ^ If a signature, the backing module+ -- See also Note [Identity versus semantic module]+ tcg_src :: HscSource,+ -- ^ What kind of module (regular Haskell, hs-boot, hsig)++ tcg_rdr_env :: GlobalRdrEnv, -- ^ Top level envt; used during renaming+ tcg_default :: Maybe [Type],+ -- ^ Types used for defaulting. @Nothing@ => no @default@ decl++ tcg_fix_env :: FixityEnv, -- ^ Just for things in this module+ tcg_field_env :: RecFieldEnv, -- ^ Just for things in this module+ -- See Note [The interactive package] in HscTypes++ tcg_type_env :: TypeEnv,+ -- ^ Global type env for the module we are compiling now. All+ -- TyCons and Classes (for this module) end up in here right away,+ -- along with their derived constructors, selectors.+ --+ -- (Ids defined in this module start in the local envt, though they+ -- move to the global envt during zonking)+ --+ -- NB: for what "things in this module" means, see+ -- Note [The interactive package] in HscTypes++ tcg_type_env_var :: TcRef TypeEnv,+ -- Used only to initialise the interface-file+ -- typechecker in initIfaceTcRn, so that it can see stuff+ -- bound in this module when dealing with hi-boot recursions+ -- Updated at intervals (e.g. after dealing with types and classes)++ tcg_inst_env :: InstEnv,+ -- ^ Instance envt for all /home-package/ modules;+ -- Includes the dfuns in tcg_insts+ tcg_fam_inst_env :: FamInstEnv, -- ^ Ditto for family instances+ tcg_ann_env :: AnnEnv, -- ^ And for annotations++ -- | Family instances we have to check for consistency.+ -- Invariant: each FamInst in the list's fi_fam matches the+ -- key of the entry in the 'NameEnv'. This gets consumed+ -- by 'checkRecFamInstConsistency'.+ -- See Note [Don't check hs-boot type family instances too early]+ tcg_pending_fam_checks :: NameEnv [([FamInst], FamInstEnv)],++ -- Now a bunch of things about this module that are simply+ -- accumulated, but never consulted until the end.+ -- Nevertheless, it's convenient to accumulate them along+ -- with the rest of the info from this module.+ tcg_exports :: [AvailInfo], -- ^ What is exported+ tcg_imports :: ImportAvails,+ -- ^ Information about what was imported from where, including+ -- things bound in this module. Also store Safe Haskell info+ -- here about transative trusted packaage requirements.++ tcg_dus :: DefUses, -- ^ What is defined in this module and what is used.+ tcg_used_gres :: TcRef [GlobalRdrElt], -- ^ Records occurrences of imported entities+ -- See Note [Tracking unused binding and imports]++ tcg_keep :: TcRef NameSet,+ -- ^ Locally-defined top-level names to keep alive.+ --+ -- "Keep alive" means give them an Exported flag, so that the+ -- simplifier does not discard them as dead code, and so that they+ -- are exposed in the interface file (but not to export to the+ -- user).+ --+ -- Some things, like dict-fun Ids and default-method Ids are "born"+ -- with the Exported flag on, for exactly the above reason, but some+ -- we only discover as we go. Specifically:+ --+ -- * The to/from functions for generic data types+ --+ -- * Top-level variables appearing free in the RHS of an orphan+ -- rule+ --+ -- * Top-level variables appearing free in a TH bracket++ tcg_th_used :: TcRef Bool,+ -- ^ @True@ <=> Template Haskell syntax used.+ --+ -- We need this so that we can generate a dependency on the+ -- Template Haskell package, because the desugarer is going+ -- to emit loads of references to TH symbols. The reference+ -- is implicit rather than explicit, so we have to zap a+ -- mutable variable.++ tcg_th_splice_used :: TcRef Bool,+ -- ^ @True@ <=> A Template Haskell splice was used.+ --+ -- Splices disable recompilation avoidance (see #481)++ tcg_th_top_level_locs :: TcRef (Set RealSrcSpan),+ -- ^ Locations of the top-level splices; used for providing details on+ -- scope in error messages for out-of-scope variables++ tcg_dfun_n :: TcRef OccSet,+ -- ^ Allows us to choose unique DFun names.++ tcg_merged :: [(Module, Fingerprint)],+ -- ^ The requirements we merged with; we always have to recompile+ -- if any of these changed.++ -- The next fields accumulate the payload of the module+ -- The binds, rules and foreign-decl fields are collected+ -- initially in un-zonked form and are finally zonked in tcRnSrcDecls++ tcg_rn_exports :: Maybe [Located (IE Name)],+ -- Nothing <=> no explicit export list+ -- Is always Nothing if we don't want to retain renamed+ -- exports++ tcg_rn_imports :: [LImportDecl Name],+ -- Keep the renamed imports regardless. They are not+ -- voluminous and are needed if you want to report unused imports++ tcg_rn_decls :: Maybe (HsGroup Name),+ -- ^ Renamed decls, maybe. @Nothing@ <=> Don't retain renamed+ -- decls.++ tcg_dependent_files :: TcRef [FilePath], -- ^ dependencies from addDependentFile++ tcg_th_topdecls :: TcRef [LHsDecl RdrName],+ -- ^ Top-level declarations from addTopDecls++ tcg_th_foreign_files :: TcRef [(ForeignSrcLang, String)],+ -- ^ Foreign files emitted from TH.++ tcg_th_topnames :: TcRef NameSet,+ -- ^ Exact names bound in top-level declarations in tcg_th_topdecls++ tcg_th_modfinalizers :: TcRef [TcM ()],+ -- ^ Template Haskell module finalizers.+ --+ -- They are computations in the @TcM@ monad rather than @Q@ because we+ -- set them to use particular local environments.++ tcg_th_state :: TcRef (Map TypeRep Dynamic),+ tcg_th_remote_state :: TcRef (Maybe (ForeignRef (IORef QState))),+ -- ^ Template Haskell state++ tcg_ev_binds :: Bag EvBind, -- Top-level evidence bindings++ -- Things defined in this module, or (in GHCi)+ -- in the declarations for a single GHCi command.+ -- For the latter, see Note [The interactive package] in HscTypes+ tcg_tr_module :: Maybe Id, -- Id for $trModule :: GHC.Types.Module+ -- for which every module has a top-level defn+ -- except in GHCi in which case we have Nothing+ tcg_binds :: LHsBinds Id, -- Value bindings in this module+ tcg_sigs :: NameSet, -- ...Top-level names that *lack* a signature+ tcg_imp_specs :: [LTcSpecPrag], -- ...SPECIALISE prags for imported Ids+ tcg_warns :: Warnings, -- ...Warnings and deprecations+ tcg_anns :: [Annotation], -- ...Annotations+ tcg_tcs :: [TyCon], -- ...TyCons and Classes+ tcg_insts :: [ClsInst], -- ...Instances+ tcg_fam_insts :: [FamInst], -- ...Family instances+ tcg_rules :: [LRuleDecl Id], -- ...Rules+ tcg_fords :: [LForeignDecl Id], -- ...Foreign import & exports+ tcg_vects :: [LVectDecl Id], -- ...Vectorisation declarations+ tcg_patsyns :: [PatSyn], -- ...Pattern synonyms++ tcg_doc_hdr :: Maybe LHsDocString, -- ^ Maybe Haddock header docs+ tcg_hpc :: AnyHpcUsage, -- ^ @True@ if any part of the+ -- prog uses hpc instrumentation.++ tcg_self_boot :: SelfBootInfo, -- ^ Whether this module has a+ -- corresponding hi-boot file++ tcg_main :: Maybe Name, -- ^ The Name of the main+ -- function, if this module is+ -- the main module.++ tcg_safeInfer :: TcRef (Bool, WarningMessages),+ -- ^ Has the typechecker inferred this module as -XSafe (Safe Haskell)+ -- See Note [Safe Haskell Overlapping Instances Implementation],+ -- although this is used for more than just that failure case.++ tcg_tc_plugins :: [TcPluginSolver],+ -- ^ A list of user-defined plugins for the constraint solver.++ tcg_top_loc :: RealSrcSpan,+ -- ^ The RealSrcSpan this module came from++ tcg_static_wc :: TcRef WantedConstraints,+ -- ^ Wanted constraints of static forms.+ -- See Note [Constraints in static forms].+ tcg_complete_matches :: [CompleteMatch]+ }++-- NB: topModIdentity, not topModSemantic!+-- Definition sites of orphan identities will be identity modules, not semantic+-- modules.++-- Note [Constraints in static forms]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- When a static form produces constraints like+--+-- f :: StaticPtr (Bool -> String)+-- f = static show+--+-- we collect them in tcg_static_wc and resolve them at the end+-- of type checking. They need to be resolved separately because+-- we don't want to resolve them in the context of the enclosing+-- expression. Consider+--+-- g :: Show a => StaticPtr (a -> String)+-- g = static show+--+-- If the @Show a0@ constraint that the body of the static form produces was+-- resolved in the context of the enclosing expression, then the body of the+-- static form wouldn't be closed because the Show dictionary would come from+-- g's context instead of coming from the top level.++tcVisibleOrphanMods :: TcGblEnv -> ModuleSet+tcVisibleOrphanMods tcg_env+ = mkModuleSet (tcg_mod tcg_env : imp_orphs (tcg_imports tcg_env))++instance ContainsModule TcGblEnv where+ extractModule env = tcg_semantic_mod env++type RecFieldEnv = NameEnv [FieldLabel]+ -- Maps a constructor name *in this module*+ -- to the fields for that constructor.+ -- This is used when dealing with ".." notation in record+ -- construction and pattern matching.+ -- The FieldEnv deals *only* with constructors defined in *this*+ -- module. For imported modules, we get the same info from the+ -- TypeEnv++data SelfBootInfo+ = NoSelfBoot -- No corresponding hi-boot file+ | SelfBoot+ { sb_mds :: ModDetails -- There was a hi-boot file,+ , sb_tcs :: NameSet } -- defining these TyCons,+-- What is sb_tcs used for? See Note [Extra dependencies from .hs-boot files]+-- in RnSource+++{- Note [Tracking unused binding and imports]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We gather two sorts of usage information++ * tcg_dus (defs/uses)+ Records *defined* Names (local, top-level)+ and *used* Names (local or imported)++ Used (a) to report "defined but not used"+ (see RnNames.reportUnusedNames)+ (b) to generate version-tracking usage info in interface+ files (see MkIface.mkUsedNames)+ This usage info is mainly gathered by the renamer's+ gathering of free-variables++ * tcg_used_gres+ Used only to report unused import declarations++ Records each *occurrence* an *imported* (not locally-defined) entity.+ The occurrence is recorded by keeping a GlobalRdrElt for it.+ These is not the GRE that is in the GlobalRdrEnv; rather it+ is recorded *after* the filtering done by pickGREs. So it reflect+ /how that occurrence is in scope/. See Note [GRE filtering] in+ RdrName.+++************************************************************************+* *+ The local typechecker environment+* *+************************************************************************++Note [The Global-Env/Local-Env story]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+During type checking, we keep in the tcg_type_env+ * All types and classes+ * All Ids derived from types and classes (constructors, selectors)++At the end of type checking, we zonk the local bindings,+and as we do so we add to the tcg_type_env+ * Locally defined top-level Ids++Why? Because they are now Ids not TcIds. This final GlobalEnv is+ a) fed back (via the knot) to typechecking the+ unfoldings of interface signatures+ b) used in the ModDetails of this module+-}++data TcLclEnv -- Changes as we move inside an expression+ -- Discarded after typecheck/rename; not passed on to desugarer+ = TcLclEnv {+ tcl_loc :: RealSrcSpan, -- Source span+ tcl_ctxt :: [ErrCtxt], -- Error context, innermost on top+ tcl_tclvl :: TcLevel, -- Birthplace for new unification variables++ tcl_th_ctxt :: ThStage, -- Template Haskell context+ tcl_th_bndrs :: ThBindEnv, -- and binder info+ -- The ThBindEnv records the TH binding level of in-scope Names+ -- defined in this module (not imported)+ -- We can't put this info in the TypeEnv because it's needed+ -- (and extended) in the renamer, for untyed splices++ tcl_arrow_ctxt :: ArrowCtxt, -- Arrow-notation context++ tcl_rdr :: LocalRdrEnv, -- Local name envt+ -- Maintained during renaming, of course, but also during+ -- type checking, solely so that when renaming a Template-Haskell+ -- splice we have the right environment for the renamer.+ --+ -- Does *not* include global name envt; may shadow it+ -- Includes both ordinary variables and type variables;+ -- they are kept distinct because tyvar have a different+ -- occurrence constructor (Name.TvOcc)+ -- We still need the unsullied global name env so that+ -- we can look up record field names++ tcl_env :: TcTypeEnv, -- The local type environment:+ -- Ids and TyVars defined in this module++ tcl_bndrs :: TcIdBinderStack, -- Used for reporting relevant bindings++ tcl_tidy :: TidyEnv, -- Used for tidying types; contains all+ -- in-scope type variables (but not term variables)++ tcl_tyvars :: TcRef TcTyVarSet, -- The "global tyvars"+ -- Namely, the in-scope TyVars bound in tcl_env,+ -- plus the tyvars mentioned in the types of Ids bound+ -- in tcl_lenv.+ -- Why mutable? see notes with tcGetGlobalTyCoVars++ tcl_lie :: TcRef WantedConstraints, -- Place to accumulate type constraints+ tcl_errs :: TcRef Messages -- Place to accumulate errors+ }++type ErrCtxt = (Bool, TidyEnv -> TcM (TidyEnv, MsgDoc))+ -- Monadic so that we have a chance+ -- to deal with bound type variables just before error+ -- message construction++ -- Bool: True <=> this is a landmark context; do not+ -- discard it when trimming for display++type TcTypeEnv = NameEnv TcTyThing++type ThBindEnv = NameEnv (TopLevelFlag, ThLevel)+ -- Domain = all Ids bound in this module (ie not imported)+ -- The TopLevelFlag tells if the binding is syntactically top level.+ -- We need to know this, because the cross-stage persistence story allows+ -- cross-stage at arbitrary types if the Id is bound at top level.+ --+ -- Nota bene: a ThLevel of 'outerLevel' is *not* the same as being+ -- bound at top level! See Note [Template Haskell levels] in TcSplice++{- Note [Given Insts]+ ~~~~~~~~~~~~~~~~~~+Because of GADTs, we have to pass inwards the Insts provided by type signatures+and existential contexts. Consider+ data T a where { T1 :: b -> b -> T [b] }+ f :: Eq a => T a -> Bool+ f (T1 x y) = [x]==[y]++The constructor T1 binds an existential variable 'b', and we need Eq [b].+Well, we have it, because Eq a refines to Eq [b], but we can only spot that if we+pass it inwards.++-}++-- | Type alias for 'IORef'; the convention is we'll use this for mutable+-- bits of data in 'TcGblEnv' which are updated during typechecking and+-- returned at the end.+type TcRef a = IORef a+-- ToDo: when should I refer to it as a 'TcId' instead of an 'Id'?+type TcId = Id+type TcIdSet = IdSet++---------------------------+-- The TcIdBinderStack+---------------------------++type TcIdBinderStack = [TcIdBinder]+ -- This is a stack of locally-bound ids, innermost on top+ -- Used ony in error reporting (relevantBindings in TcError)+ -- We can't use the tcl_env type environment, because it doesn't+ -- keep track of the nesting order++data TcIdBinder+ = TcIdBndr+ TcId+ TopLevelFlag -- Tells whether the binding is syntactically top-level+ -- (The monomorphic Ids for a recursive group count+ -- as not-top-level for this purpose.)+ | TcIdBndr_ExpType -- Variant that allows the type to be specified as+ -- an ExpType+ Name+ ExpType+ TopLevelFlag++instance Outputable TcIdBinder where+ ppr (TcIdBndr id top_lvl) = ppr id <> brackets (ppr top_lvl)+ ppr (TcIdBndr_ExpType id _ top_lvl) = ppr id <> brackets (ppr top_lvl)++instance HasOccName TcIdBinder where+ occName (TcIdBndr id _) = (occName (idName id))+ occName (TcIdBndr_ExpType name _ _) = (occName name)++---------------------------+-- Template Haskell stages and levels+---------------------------++data SpliceType = Typed | Untyped++data ThStage -- See Note [Template Haskell state diagram] in TcSplice+ = Splice SpliceType -- Inside a top-level splice+ -- This code will be run *at compile time*;+ -- the result replaces the splice+ -- Binding level = 0++ | RunSplice (TcRef [ForeignRef (TH.Q ())])+ -- Set when running a splice, i.e. NOT when renaming or typechecking the+ -- Haskell code for the splice. See Note [RunSplice ThLevel].+ --+ -- Contains a list of mod finalizers collected while executing the splice.+ --+ -- 'addModFinalizer' inserts finalizers here, and from here they are taken+ -- to construct an @HsSpliced@ annotation for untyped splices. See Note+ -- [Delaying modFinalizers in untyped splices] in "RnSplice".+ --+ -- For typed splices, the typechecker takes finalizers from here and+ -- inserts them in the list of finalizers in the global environment.+ --+ -- See Note [Collecting modFinalizers in typed splices] in "TcSplice".++ | Comp -- Ordinary Haskell code+ -- Binding level = 1++ | Brack -- Inside brackets+ ThStage -- Enclosing stage+ PendingStuff++data PendingStuff+ = RnPendingUntyped -- Renaming the inside of an *untyped* bracket+ (TcRef [PendingRnSplice]) -- Pending splices in here++ | RnPendingTyped -- Renaming the inside of a *typed* bracket++ | TcPending -- Typechecking the inside of a typed bracket+ (TcRef [PendingTcSplice]) -- Accumulate pending splices here+ (TcRef WantedConstraints) -- and type constraints here++topStage, topAnnStage, topSpliceStage :: ThStage+topStage = Comp+topAnnStage = Splice Untyped+topSpliceStage = Splice Untyped++instance Outputable ThStage where+ ppr (Splice _) = text "Splice"+ ppr (RunSplice _) = text "RunSplice"+ ppr Comp = text "Comp"+ ppr (Brack s _) = text "Brack" <> parens (ppr s)++type ThLevel = Int+ -- NB: see Note [Template Haskell levels] in TcSplice+ -- Incremented when going inside a bracket,+ -- decremented when going inside a splice+ -- NB: ThLevel is one greater than the 'n' in Fig 2 of the+ -- original "Template meta-programming for Haskell" paper++impLevel, outerLevel :: ThLevel+impLevel = 0 -- Imported things; they can be used inside a top level splice+outerLevel = 1 -- Things defined outside brackets++thLevel :: ThStage -> ThLevel+thLevel (Splice _) = 0+thLevel (RunSplice _) =+ -- See Note [RunSplice ThLevel].+ panic "thLevel: called when running a splice"+thLevel Comp = 1+thLevel (Brack s _) = thLevel s + 1++{- Node [RunSplice ThLevel]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The 'RunSplice' stage is set when executing a splice, and only when running a+splice. In particular it is not set when the splice is renamed or typechecked.++'RunSplice' is needed to provide a reference where 'addModFinalizer' can insert+the finalizer (see Note [Delaying modFinalizers in untyped splices]), and+'addModFinalizer' runs when doing Q things. Therefore, It doesn't make sense to+set 'RunSplice' when renaming or typechecking the splice, where 'Splice', 'Brak'+or 'Comp' are used instead.++-}++---------------------------+-- Arrow-notation context+---------------------------++{- Note [Escaping the arrow scope]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In arrow notation, a variable bound by a proc (or enclosed let/kappa)+is not in scope to the left of an arrow tail (-<) or the head of (|..|).+For example++ proc x -> (e1 -< e2)++Here, x is not in scope in e1, but it is in scope in e2. This can get+a bit complicated:++ let x = 3 in+ proc y -> (proc z -> e1) -< e2++Here, x and z are in scope in e1, but y is not.++We implement this by+recording the environment when passing a proc (using newArrowScope),+and returning to that (using escapeArrowScope) on the left of -< and the+head of (|..|).++All this can be dealt with by the *renamer*. But the type checker needs+to be involved too. Example (arrowfail001)+ class Foo a where foo :: a -> ()+ data Bar = forall a. Foo a => Bar a+ get :: Bar -> ()+ get = proc x -> case x of Bar a -> foo -< a+Here the call of 'foo' gives rise to a (Foo a) constraint that should not+be captured by the pattern match on 'Bar'. Rather it should join the+constraints from further out. So we must capture the constraint bag+from further out in the ArrowCtxt that we push inwards.+-}++data ArrowCtxt -- Note [Escaping the arrow scope]+ = NoArrowCtxt+ | ArrowCtxt LocalRdrEnv (TcRef WantedConstraints)+++---------------------------+-- TcTyThing+---------------------------++-- | A typecheckable thing available in a local context. Could be+-- 'AGlobal' 'TyThing', but also lexically scoped variables, etc.+-- See 'TcEnv' for how to retrieve a 'TyThing' given a 'Name'.+data TcTyThing+ = AGlobal TyThing -- Used only in the return type of a lookup++ | ATcId -- Ids defined in this module; may not be fully zonked+ { tct_id :: TcId+ , tct_info :: IdBindingInfo -- See Note [Meaning of IdBindingInfo]+ }++ | ATyVar Name TcTyVar -- The type variable to which the lexically scoped type+ -- variable is bound. We only need the Name+ -- for error-message purposes; it is the corresponding+ -- Name in the domain of the envt++ | ATcTyCon TyCon -- Used temporarily, during kind checking, for the+ -- tycons and clases in this recursive group+ -- The TyCon is always a TcTyCon. Its kind+ -- can be a mono-kind or a poly-kind; in TcTyClsDcls see+ -- Note [Type checking recursive type and class declarations]++ | APromotionErr PromotionErr++data PromotionErr+ = TyConPE -- TyCon used in a kind before we are ready+ -- data T :: T -> * where ...+ | ClassPE -- Ditto Class++ | FamDataConPE -- Data constructor for a data family+ -- See Note [AFamDataCon: not promoting data family constructors]+ -- in TcEnv.+ | PatSynPE -- Pattern synonyms+ -- See Note [Don't promote pattern synonyms] in TcEnv++ | RecDataConPE -- Data constructor in a recursive loop+ -- See Note [ARecDataCon: recusion and promoting data constructors] in TcTyClsDecls+ | NoDataKindsTC -- -XDataKinds not enabled (for a tycon)+ | NoDataKindsDC -- -XDataKinds not enabled (for a datacon)+ | NoTypeInTypeTC -- -XTypeInType not enabled (for a tycon)+ | NoTypeInTypeDC -- -XTypeInType not enabled (for a datacon)++instance Outputable TcTyThing where -- Debugging only+ ppr (AGlobal g) = ppr g+ ppr elt@(ATcId {}) = text "Identifier" <>+ brackets (ppr (tct_id elt) <> dcolon+ <> ppr (varType (tct_id elt)) <> comma+ <+> ppr (tct_info elt))+ ppr (ATyVar n tv) = text "Type variable" <+> quotes (ppr n) <+> equals <+> ppr tv+ ppr (ATcTyCon tc) = text "ATcTyCon" <+> ppr tc <+> dcolon <+> ppr (tyConKind tc)+ ppr (APromotionErr err) = text "APromotionErr" <+> ppr err++-- | IdBindingInfo describes how an Id is bound.+--+-- It is used for the following purposes:+-- a) for static forms in TcExpr.checkClosedInStaticForm and+-- b) to figure out when a nested binding can be generalised,+-- in TcBinds.decideGeneralisationPlan.+--+data IdBindingInfo -- See Note [Meaning of IdBindingInfo and ClosedTypeId]+ = NotLetBound+ | ClosedLet+ | NonClosedLet+ RhsNames -- Used for (static e) checks only+ ClosedTypeId -- Used for generalisation checks+ -- and for (static e) checks++-- | IsGroupClosed describes a group of mutually-recursive bindings+data IsGroupClosed+ = IsGroupClosed+ (NameEnv RhsNames) -- Free var info for the RHS of each binding in the goup+ -- Used only for (static e) checks++ ClosedTypeId -- True <=> all the free vars of the group are+ -- imported or ClosedLet or+ -- NonClosedLet with ClosedTypeId=True.+ -- In particular, no tyvars, no NotLetBound++type RhsNames = NameSet -- Names of variables, mentioned on the RHS of+ -- a definition, that are not Global or ClosedLet++type ClosedTypeId = Bool+ -- See Note [Meaning of IdBindingInfo and ClosedTypeId]++{- Note [Meaning of IdBindingInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+NotLetBound means that+ the Id is not let-bound (e.g. it is bound in a+ lambda-abstraction or in a case pattern)++ClosedLet means that+ - The Id is let-bound,+ - Any free term variables are also Global or ClosedLet+ - Its type has no free variables (NB: a top-level binding subject+ to the MR might have free vars in its type)+ These ClosedLets can definitely be floated to top level; and we+ may need to do so for static forms.++ Property: ClosedLet+ is equivalent to+ NonClosedLet emptyNameSet True++(NonClosedLet (fvs::RhsNames) (cl::ClosedTypeId)) means that+ - The Id is let-bound++ - The fvs::RhsNames contains the free names of the RHS,+ excluding Global and ClosedLet ones.++ - For the ClosedTypeId field see Note [Bindings with closed types]++For (static e) to be valid, we need for every 'x' free in 'e',+x's binding must be floatable to top level. Specifically:+ * x's RhsNames must be non-empty+ * x's type has no free variables+See Note [Grand plan for static forms] in StaticPtrTable.hs.+This test is made in TcExpr.checkClosedInStaticForm.+Actually knowing x's RhsNames (rather than just its emptiness+or otherwise) is just so we can produce better error messages++Note [Bindings with closed types: ClosedTypeId]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider++ f x = let g ys = map not ys+ in ...++Can we generalise 'g' under the OutsideIn algorithm? Yes,+because all g's free variables are top-level; that is they themselves+have no free type variables, and it is the type variables in the+environment that makes things tricky for OutsideIn generalisation.++Here's the invariant:+ If an Id has ClosedTypeId=True (in its IdBindingInfo), then+ the Id's type is /definitely/ closed (has no free type variables).+ Specifically,+ a) The Id's acutal type is closed (has no free tyvars)+ b) Either the Id has a (closed) user-supplied type signature+ or all its free varaibles are Global/ClosedLet+ or NonClosedLet with ClosedTypeId=True.+ In particular, none are NotLetBound.++Why is (b) needed? Consider+ \x. (x :: Int, let y = x+1 in ...)+Initially x::alpha. If we happen to typecheck the 'let' before the+(x::Int), y's type will have a free tyvar; but if the other way round+it won't. So we treat any let-bound variable with a free+non-let-bound variable as not ClosedTypeId, regardless of what the+free vars of its type actually are.++But if it has a signature, all is well:+ \x. ...(let { y::Int; y = x+1 } in+ let { v = y+2 } in ...)...+Here the signature on 'v' makes 'y' a ClosedTypeId, so we can+generalise 'v'.++Note that:++ * A top-level binding may not have ClosedTypeId=True, if it suffers+ from the MR++ * A nested binding may be closed (eg 'g' in the example we started+ with). Indeed, that's the point; whether a function is defined at+ top level or nested is orthogonal to the question of whether or+ not it is closed.++ * A binding may be non-closed because it mentions a lexically scoped+ *type variable* Eg+ f :: forall a. blah+ f x = let g y = ...(y::a)...++Under OutsideIn we are free to generalise an Id all of whose free+variables have ClosedTypeId=True (or imported). This is an extension+compared to the JFP paper on OutsideIn, which used "top-level" as a+proxy for "closed". (It's not a good proxy anyway -- the MR can make+a top-level binding with a free type variable.)+-}++instance Outputable IdBindingInfo where+ ppr NotLetBound = text "NotLetBound"+ ppr ClosedLet = text "TopLevelLet"+ ppr (NonClosedLet fvs closed_type) =+ text "TopLevelLet" <+> ppr fvs <+> ppr closed_type++instance Outputable PromotionErr where+ ppr ClassPE = text "ClassPE"+ ppr TyConPE = text "TyConPE"+ ppr PatSynPE = text "PatSynPE"+ ppr FamDataConPE = text "FamDataConPE"+ ppr RecDataConPE = text "RecDataConPE"+ ppr NoDataKindsTC = text "NoDataKindsTC"+ ppr NoDataKindsDC = text "NoDataKindsDC"+ ppr NoTypeInTypeTC = text "NoTypeInTypeTC"+ ppr NoTypeInTypeDC = text "NoTypeInTypeDC"++pprTcTyThingCategory :: TcTyThing -> SDoc+pprTcTyThingCategory (AGlobal thing) = pprTyThingCategory thing+pprTcTyThingCategory (ATyVar {}) = text "Type variable"+pprTcTyThingCategory (ATcId {}) = text "Local identifier"+pprTcTyThingCategory (ATcTyCon {}) = text "Local tycon"+pprTcTyThingCategory (APromotionErr pe) = pprPECategory pe++pprPECategory :: PromotionErr -> SDoc+pprPECategory ClassPE = text "Class"+pprPECategory TyConPE = text "Type constructor"+pprPECategory PatSynPE = text "Pattern synonym"+pprPECategory FamDataConPE = text "Data constructor"+pprPECategory RecDataConPE = text "Data constructor"+pprPECategory NoDataKindsTC = text "Type constructor"+pprPECategory NoDataKindsDC = text "Data constructor"+pprPECategory NoTypeInTypeTC = text "Type constructor"+pprPECategory NoTypeInTypeDC = text "Data constructor"++{-+************************************************************************+* *+ Operations over ImportAvails+* *+************************************************************************+-}++-- | 'ImportAvails' summarises what was imported from where, irrespective of+-- whether the imported things are actually used or not. It is used:+--+-- * when processing the export list,+--+-- * when constructing usage info for the interface file,+--+-- * to identify the list of directly imported modules for initialisation+-- purposes and for optimised overlap checking of family instances,+--+-- * when figuring out what things are really unused+--+data ImportAvails+ = ImportAvails {+ imp_mods :: ImportedMods,+ -- = ModuleEnv [ImportedModsVal],+ -- ^ Domain is all directly-imported modules+ --+ -- See the documentation on ImportedModsVal in HscTypes for the+ -- meaning of the fields.+ --+ -- We need a full ModuleEnv rather than a ModuleNameEnv here,+ -- because we might be importing modules of the same name from+ -- different packages. (currently not the case, but might be in the+ -- future).++ imp_dep_mods :: ModuleNameEnv (ModuleName, IsBootInterface),+ -- ^ Home-package modules needed by the module being compiled+ --+ -- It doesn't matter whether any of these dependencies+ -- are actually /used/ when compiling the module; they+ -- are listed if they are below it at all. For+ -- example, suppose M imports A which imports X. Then+ -- compiling M might not need to consult X.hi, but X+ -- is still listed in M's dependencies.++ imp_dep_pkgs :: Set InstalledUnitId,+ -- ^ Packages needed by the module being compiled, whether directly,+ -- or via other modules in this package, or via modules imported+ -- from other packages.++ imp_trust_pkgs :: Set InstalledUnitId,+ -- ^ This is strictly a subset of imp_dep_pkgs and records the+ -- packages the current module needs to trust for Safe Haskell+ -- compilation to succeed. A package is required to be trusted if+ -- we are dependent on a trustworthy module in that package.+ -- While perhaps making imp_dep_pkgs a tuple of (UnitId, Bool)+ -- where True for the bool indicates the package is required to be+ -- trusted is the more logical design, doing so complicates a lot+ -- of code not concerned with Safe Haskell.+ -- See Note [RnNames . Tracking Trust Transitively]++ imp_trust_own_pkg :: Bool,+ -- ^ Do we require that our own package is trusted?+ -- This is to handle efficiently the case where a Safe module imports+ -- a Trustworthy module that resides in the same package as it.+ -- See Note [RnNames . Trust Own Package]++ imp_orphs :: [Module],+ -- ^ Orphan modules below us in the import tree (and maybe including+ -- us for imported modules)++ imp_finsts :: [Module]+ -- ^ Family instance modules below us in the import tree (and maybe+ -- including us for imported modules)+ }++mkModDeps :: [(ModuleName, IsBootInterface)]+ -> ModuleNameEnv (ModuleName, IsBootInterface)+mkModDeps deps = foldl add emptyUFM deps+ where+ add env elt@(m,_) = addToUFM env m elt++modDepsElts+ :: ModuleNameEnv (ModuleName, IsBootInterface)+ -> [(ModuleName, IsBootInterface)]+modDepsElts = sort . nonDetEltsUFM+ -- It's OK to use nonDetEltsUFM here because sorting by module names+ -- restores determinism++emptyImportAvails :: ImportAvails+emptyImportAvails = ImportAvails { imp_mods = emptyModuleEnv,+ imp_dep_mods = emptyUFM,+ imp_dep_pkgs = S.empty,+ imp_trust_pkgs = S.empty,+ imp_trust_own_pkg = False,+ imp_orphs = [],+ imp_finsts = [] }++-- | Union two ImportAvails+--+-- This function is a key part of Import handling, basically+-- for each import we create a separate ImportAvails structure+-- and then union them all together with this function.+plusImportAvails :: ImportAvails -> ImportAvails -> ImportAvails+plusImportAvails+ (ImportAvails { imp_mods = mods1,+ imp_dep_mods = dmods1, imp_dep_pkgs = dpkgs1,+ imp_trust_pkgs = tpkgs1, imp_trust_own_pkg = tself1,+ imp_orphs = orphs1, imp_finsts = finsts1 })+ (ImportAvails { imp_mods = mods2,+ imp_dep_mods = dmods2, imp_dep_pkgs = dpkgs2,+ imp_trust_pkgs = tpkgs2, imp_trust_own_pkg = tself2,+ imp_orphs = orphs2, imp_finsts = finsts2 })+ = ImportAvails { imp_mods = plusModuleEnv_C (++) mods1 mods2,+ imp_dep_mods = plusUFM_C plus_mod_dep dmods1 dmods2,+ imp_dep_pkgs = dpkgs1 `S.union` dpkgs2,+ imp_trust_pkgs = tpkgs1 `S.union` tpkgs2,+ imp_trust_own_pkg = tself1 || tself2,+ imp_orphs = orphs1 `unionLists` orphs2,+ imp_finsts = finsts1 `unionLists` finsts2 }+ where+ plus_mod_dep (m1, boot1) (m2, boot2)+ = WARN( not (m1 == m2), (ppr m1 <+> ppr m2) $$ (ppr boot1 <+> ppr boot2) )+ -- Check mod-names match+ (m1, boot1 && boot2) -- If either side can "see" a non-hi-boot interface, use that++{-+************************************************************************+* *+\subsection{Where from}+* *+************************************************************************++The @WhereFrom@ type controls where the renamer looks for an interface file+-}++data WhereFrom+ = ImportByUser IsBootInterface -- Ordinary user import (perhaps {-# SOURCE #-})+ | ImportBySystem -- Non user import.+ | ImportByPlugin -- Importing a plugin;+ -- See Note [Care with plugin imports] in LoadIface++instance Outputable WhereFrom where+ ppr (ImportByUser is_boot) | is_boot = text "{- SOURCE -}"+ | otherwise = empty+ ppr ImportBySystem = text "{- SYSTEM -}"+ ppr ImportByPlugin = text "{- PLUGIN -}"+++{- *********************************************************************+* *+ Type signatures+* *+********************************************************************* -}++-- These data types need to be here only because+-- TcSimplify uses them, and TcSimplify is fairly+-- low down in the module hierarchy++type TcSigFun = Name -> Maybe TcSigInfo++data TcSigInfo = TcIdSig TcIdSigInfo+ | TcPatSynSig TcPatSynInfo++data TcIdSigInfo -- See Note [Complete and partial type signatures]+ = CompleteSig -- A complete signature with no wildcards,+ -- so the complete polymorphic type is known.+ { sig_bndr :: TcId -- The polymorphic Id with that type++ , sig_ctxt :: UserTypeCtxt -- In the case of type-class default methods,+ -- the Name in the FunSigCtxt is not the same+ -- as the TcId; the former is 'op', while the+ -- latter is '$dmop' or some such++ , sig_loc :: SrcSpan -- Location of the type signature+ }++ | PartialSig -- A partial type signature (i.e. includes one or more+ -- wildcards). In this case it doesn't make sense to give+ -- the polymorphic Id, because we are going to /infer/ its+ -- type, so we can't make the polymorphic Id ab-initio+ { psig_name :: Name -- Name of the function; used when report wildcards+ , psig_hs_ty :: LHsSigWcType Name -- The original partial signature in HsSyn form+ , sig_ctxt :: UserTypeCtxt+ , sig_loc :: SrcSpan -- Location of the type signature+ }+++{- Note [Complete and partial type signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A type signature is partial when it contains one or more wildcards+(= type holes). The wildcard can either be:+* A (type) wildcard occurring in sig_theta or sig_tau. These are+ stored in sig_wcs.+ f :: Bool -> _+ g :: Eq _a => _a -> _a -> Bool+* Or an extra-constraints wildcard, stored in sig_cts:+ h :: (Num a, _) => a -> a++A type signature is a complete type signature when there are no+wildcards in the type signature, i.e. iff sig_wcs is empty and+sig_extra_cts is Nothing.+-}++data TcIdSigInst+ = TISI { sig_inst_sig :: TcIdSigInfo++ , sig_inst_skols :: [(Name, TcTyVar)]+ -- Instantiated type and kind variables, SigTvs+ -- The Name is the Name that the renamer chose;+ -- but the TcTyVar may come from instantiating+ -- the type and hence have a different unique.+ -- No need to keep track of whether they are truly lexically+ -- scoped because the renamer has named them uniquely+ -- See Note [Binding scoped type variables] in TcSigs++ , sig_inst_theta :: TcThetaType+ -- Instantiated theta. In the case of a+ -- PartialSig, sig_theta does not include+ -- the extra-constraints wildcard++ , sig_inst_tau :: TcSigmaType -- Instantiated tau+ -- See Note [sig_inst_tau may be polymorphic]++ -- Relevant for partial signature only+ , sig_inst_wcs :: [(Name, TcTyVar)]+ -- Like sig_inst_skols, but for wildcards. The named+ -- wildcards scope over the binding, and hence their+ -- Names may appear in type signatures in the binding++ , sig_inst_wcx :: Maybe TcTyVar+ -- Extra-constraints wildcard to fill in, if any+ }++{- Note [sig_inst_tau may be polymorphic]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note that "sig_inst_tau" might actually be a polymorphic type,+if the original function had a signature like+ forall a. Eq a => forall b. Ord b => ....+But that's ok: tcMatchesFun (called by tcRhs) can deal with that+It happens, too! See Note [Polymorphic methods] in TcClassDcl.++Note [Wildcards in partial signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The wildcards in psig_wcs may stand for a type mentioning+the universally-quantified tyvars of psig_ty++E.g. f :: forall a. _ -> a+ f x = x+We get sig_inst_skols = [a]+ sig_inst_tau = _22 -> a+ sig_inst_wcs = [_22]+and _22 in the end is unified with the type 'a'++Moreover the kind of a wildcard in sig_inst_wcs may mention+the universally-quantified tyvars sig_inst_skols+e.g. f :: t a -> t _+Here we get+ sig_inst_skols = [k:*, (t::k ->*), (a::k)]+ sig_inst_tau = t a -> t _22+ sig_inst_wcs = [ _22::k ]+-}++data TcPatSynInfo+ = TPSI {+ patsig_name :: Name,+ patsig_implicit_bndrs :: [TyVarBinder], -- Implicitly-bound kind vars (Inferred) and+ -- implicitly-bound type vars (Specified)+ -- See Note [The pattern-synonym signature splitting rule] in TcPatSyn+ patsig_univ_bndrs :: [TyVar], -- Bound by explicit user forall+ patsig_req :: TcThetaType,+ patsig_ex_bndrs :: [TyVar], -- Bound by explicit user forall+ patsig_prov :: TcThetaType,+ patsig_body_ty :: TcSigmaType+ }++instance Outputable TcSigInfo where+ ppr (TcIdSig idsi) = ppr idsi+ ppr (TcPatSynSig tpsi) = text "TcPatSynInfo" <+> ppr tpsi++instance Outputable TcIdSigInfo where+ ppr (CompleteSig { sig_bndr = bndr })+ = ppr bndr <+> dcolon <+> ppr (idType bndr)+ ppr (PartialSig { psig_name = name, psig_hs_ty = hs_ty })+ = text "psig" <+> ppr name <+> dcolon <+> ppr hs_ty++instance Outputable TcIdSigInst where+ ppr (TISI { sig_inst_sig = sig, sig_inst_skols = skols+ , sig_inst_theta = theta, sig_inst_tau = tau })+ = hang (ppr sig) 2 (vcat [ ppr skols, ppr theta <+> darrow <+> ppr tau ])++instance Outputable TcPatSynInfo where+ ppr (TPSI{ patsig_name = name}) = ppr name++isPartialSig :: TcIdSigInst -> Bool+isPartialSig (TISI { sig_inst_sig = PartialSig {} }) = True+isPartialSig _ = False++-- | No signature or a partial signature+hasCompleteSig :: TcSigFun -> Name -> Bool+hasCompleteSig sig_fn name+ = case sig_fn name of+ Just (TcIdSig (CompleteSig {})) -> True+ _ -> False+++{-+************************************************************************+* *+* Canonical constraints *+* *+* These are the constraints the low-level simplifier works with *+* *+************************************************************************+-}++-- The syntax of xi (ξ) types:+-- xi ::= a | T xis | xis -> xis | ... | forall a. tau+-- Two important notes:+-- (i) No type families, unless we are under a ForAll+-- (ii) Note that xi types can contain unexpanded type synonyms;+-- however, the (transitive) expansions of those type synonyms+-- will not contain any type functions, unless we are under a ForAll.+-- We enforce the structure of Xi types when we flatten (TcCanonical)++type Xi = Type -- In many comments, "xi" ranges over Xi++type Cts = Bag Ct++data Ct+ -- Atomic canonical constraints+ = CDictCan { -- e.g. Num xi+ cc_ev :: CtEvidence, -- See Note [Ct/evidence invariant]++ cc_class :: Class,+ cc_tyargs :: [Xi], -- cc_tyargs are function-free, hence Xi++ cc_pend_sc :: Bool -- See Note [The superclass story] in TcCanonical+ -- True <=> (a) cc_class has superclasses+ -- (b) we have not (yet) added those+ -- superclasses as Givens+ }++ | CIrredEvCan { -- These stand for yet-unusable predicates+ cc_ev :: CtEvidence -- See Note [Ct/evidence invariant]+ -- The ctev_pred of the evidence is+ -- of form (tv xi1 xi2 ... xin)+ -- or (tv1 ~ ty2) where the CTyEqCan kind invariant fails+ -- or (F tys ~ ty) where the CFunEqCan kind invariant fails+ -- See Note [CIrredEvCan constraints]+ }++ | CTyEqCan { -- tv ~ rhs+ -- Invariants:+ -- * See Note [Applying the inert substitution] in TcFlatten+ -- * tv not in tvs(rhs) (occurs check)+ -- * If tv is a TauTv, then rhs has no foralls+ -- (this avoids substituting a forall for the tyvar in other types)+ -- * typeKind ty `tcEqKind` typeKind tv+ -- * rhs may have at most one top-level cast+ -- * rhs (perhaps under the one cast) is not necessarily function-free,+ -- but it has no top-level function.+ -- E.g. a ~ [F b] is fine+ -- but a ~ F b is not+ -- * If the equality is representational, rhs has no top-level newtype+ -- See Note [No top-level newtypes on RHS of representational+ -- equalities] in TcCanonical+ -- * If rhs (perhaps under the cast) is also a tv, then it is oriented+ -- to give best chance of+ -- unification happening; eg if rhs is touchable then lhs is too+ cc_ev :: CtEvidence, -- See Note [Ct/evidence invariant]+ cc_tyvar :: TcTyVar,+ cc_rhs :: TcType, -- Not necessarily function-free (hence not Xi)+ -- See invariants above++ cc_eq_rel :: EqRel -- INVARIANT: cc_eq_rel = ctEvEqRel cc_ev+ }++ | CFunEqCan { -- F xis ~ fsk+ -- Invariants:+ -- * isTypeFamilyTyCon cc_fun+ -- * typeKind (F xis) = tyVarKind fsk+ -- * always Nominal role+ cc_ev :: CtEvidence, -- See Note [Ct/evidence invariant]+ cc_fun :: TyCon, -- A type function++ cc_tyargs :: [Xi], -- cc_tyargs are function-free (hence Xi)+ -- Either under-saturated or exactly saturated+ -- *never* over-saturated (because if so+ -- we should have decomposed)++ cc_fsk :: TcTyVar -- [Given] always a FlatSkol skolem+ -- [Wanted] always a FlatMetaTv unification variable+ -- See Note [The flattening story] in TcFlatten+ }++ | CNonCanonical { -- See Note [NonCanonical Semantics] in TcSMonad+ cc_ev :: CtEvidence+ }++ | CHoleCan { -- See Note [Hole constraints]+ -- Treated as an "insoluble" constraint+ -- See Note [Insoluble constraints]+ cc_ev :: CtEvidence,+ cc_hole :: Hole+ }++-- | An expression or type hole+data Hole = ExprHole UnboundVar+ -- ^ Either an out-of-scope variable or a "true" hole in an+ -- expression (TypedHoles)+ | TypeHole OccName+ -- ^ A hole in a type (PartialTypeSignatures)++holeOcc :: Hole -> OccName+holeOcc (ExprHole uv) = unboundVarOcc uv+holeOcc (TypeHole occ) = occ++{- Note [Hole constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~+CHoleCan constraints are used for two kinds of holes,+distinguished by cc_hole:++ * For holes in expressions (including variables not in scope)+ e.g. f x = g _ x++ * For holes in type signatures+ e.g. f :: _ -> _+ f x = [x,True]++Note [CIrredEvCan constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+CIrredEvCan constraints are used for constraints that are "stuck"+ - we can't solve them (yet)+ - we can't use them to solve other constraints+ - but they may become soluble if we substitute for some+ of the type variables in the constraint++Example 1: (c Int), where c :: * -> Constraint. We can't do anything+ with this yet, but if later c := Num, *then* we can solve it++Example 2: a ~ b, where a :: *, b :: k, where k is a kind variable+ We don't want to use this to substitute 'b' for 'a', in case+ 'k' is subequently unifed with (say) *->*, because then+ we'd have ill-kinded types floating about. Rather we want+ to defer using the equality altogether until 'k' get resolved.++Note [Ct/evidence invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If ct :: Ct, then extra fields of 'ct' cache precisely the ctev_pred field+of (cc_ev ct), and is fully rewritten wrt the substitution. Eg for CDictCan,+ ctev_pred (cc_ev ct) = (cc_class ct) (cc_tyargs ct)+This holds by construction; look at the unique place where CDictCan is+built (in TcCanonical).++In contrast, the type of the evidence *term* (ctev_dest / ctev_evar) in+the evidence may *not* be fully zonked; we are careful not to look at it+during constraint solving. See Note [Evidence field of CtEvidence].+-}++mkNonCanonical :: CtEvidence -> Ct+mkNonCanonical ev = CNonCanonical { cc_ev = ev }++mkNonCanonicalCt :: Ct -> Ct+mkNonCanonicalCt ct = CNonCanonical { cc_ev = cc_ev ct }++mkGivens :: CtLoc -> [EvId] -> [Ct]+mkGivens loc ev_ids+ = map mk ev_ids+ where+ mk ev_id = mkNonCanonical (CtGiven { ctev_evar = ev_id+ , ctev_pred = evVarPred ev_id+ , ctev_loc = loc })++ctEvidence :: Ct -> CtEvidence+ctEvidence = cc_ev++ctLoc :: Ct -> CtLoc+ctLoc = ctEvLoc . ctEvidence++setCtLoc :: Ct -> CtLoc -> Ct+setCtLoc ct loc = ct { cc_ev = (cc_ev ct) { ctev_loc = loc } }++ctOrigin :: Ct -> CtOrigin+ctOrigin = ctLocOrigin . ctLoc++ctPred :: Ct -> PredType+-- See Note [Ct/evidence invariant]+ctPred ct = ctEvPred (cc_ev ct)++-- | Makes a new equality predicate with the same role as the given+-- evidence.+mkTcEqPredLikeEv :: CtEvidence -> TcType -> TcType -> TcType+mkTcEqPredLikeEv ev+ = case predTypeEqRel pred of+ NomEq -> mkPrimEqPred+ ReprEq -> mkReprPrimEqPred+ where+ pred = ctEvPred ev++-- | Get the flavour of the given 'Ct'+ctFlavour :: Ct -> CtFlavour+ctFlavour = ctEvFlavour . ctEvidence++-- | Get the equality relation for the given 'Ct'+ctEqRel :: Ct -> EqRel+ctEqRel = ctEvEqRel . ctEvidence++instance Outputable Ct where+ ppr ct = ppr (cc_ev ct) <+> parens pp_sort+ where+ pp_sort = case ct of+ CTyEqCan {} -> text "CTyEqCan"+ CFunEqCan {} -> text "CFunEqCan"+ CNonCanonical {} -> text "CNonCanonical"+ CDictCan { cc_pend_sc = pend_sc }+ | pend_sc -> text "CDictCan(psc)"+ | otherwise -> text "CDictCan"+ CIrredEvCan {} -> text "CIrredEvCan"+ CHoleCan { cc_hole = hole } -> text "CHoleCan:" <+> ppr (holeOcc hole)++{-+************************************************************************+* *+ Simple functions over evidence variables+* *+************************************************************************+-}++---------------- Getting free tyvars -------------------------++-- | Returns free variables of constraints as a non-deterministic set+tyCoVarsOfCt :: Ct -> TcTyCoVarSet+tyCoVarsOfCt = fvVarSet . tyCoFVsOfCt++-- | Returns free variables of constraints as a deterministically ordered.+-- list. See Note [Deterministic FV] in FV.+tyCoVarsOfCtList :: Ct -> [TcTyCoVar]+tyCoVarsOfCtList = fvVarList . tyCoFVsOfCt++-- | Returns free variables of constraints as a composable FV computation.+-- See Note [Deterministic FV] in FV.+tyCoFVsOfCt :: Ct -> FV+tyCoFVsOfCt (CTyEqCan { cc_tyvar = tv, cc_rhs = xi })+ = tyCoFVsOfType xi `unionFV` FV.unitFV tv+ `unionFV` tyCoFVsOfType (tyVarKind tv)+tyCoFVsOfCt (CFunEqCan { cc_tyargs = tys, cc_fsk = fsk })+ = tyCoFVsOfTypes tys `unionFV` FV.unitFV fsk+ `unionFV` tyCoFVsOfType (tyVarKind fsk)+tyCoFVsOfCt (CDictCan { cc_tyargs = tys }) = tyCoFVsOfTypes tys+tyCoFVsOfCt (CIrredEvCan { cc_ev = ev }) = tyCoFVsOfType (ctEvPred ev)+tyCoFVsOfCt (CHoleCan { cc_ev = ev }) = tyCoFVsOfType (ctEvPred ev)+tyCoFVsOfCt (CNonCanonical { cc_ev = ev }) = tyCoFVsOfType (ctEvPred ev)++-- | Returns free variables of a bag of constraints as a non-deterministic+-- set. See Note [Deterministic FV] in FV.+tyCoVarsOfCts :: Cts -> TcTyCoVarSet+tyCoVarsOfCts = fvVarSet . tyCoFVsOfCts++-- | Returns free variables of a bag of constraints as a deterministically+-- odered list. See Note [Deterministic FV] in FV.+tyCoVarsOfCtsList :: Cts -> [TcTyCoVar]+tyCoVarsOfCtsList = fvVarList . tyCoFVsOfCts++-- | Returns free variables of a bag of constraints as a composable FV+-- computation. See Note [Deterministic FV] in FV.+tyCoFVsOfCts :: Cts -> FV+tyCoFVsOfCts = foldrBag (unionFV . tyCoFVsOfCt) emptyFV++-- | Returns free variables of WantedConstraints as a non-deterministic+-- set. See Note [Deterministic FV] in FV.+tyCoVarsOfWC :: WantedConstraints -> TyCoVarSet+-- Only called on *zonked* things, hence no need to worry about flatten-skolems+tyCoVarsOfWC = fvVarSet . tyCoFVsOfWC++-- | Returns free variables of WantedConstraints as a deterministically+-- ordered list. See Note [Deterministic FV] in FV.+tyCoVarsOfWCList :: WantedConstraints -> [TyCoVar]+-- Only called on *zonked* things, hence no need to worry about flatten-skolems+tyCoVarsOfWCList = fvVarList . tyCoFVsOfWC++-- | Returns free variables of WantedConstraints as a composable FV+-- computation. See Note [Deterministic FV] in FV.+tyCoFVsOfWC :: WantedConstraints -> FV+-- Only called on *zonked* things, hence no need to worry about flatten-skolems+tyCoFVsOfWC (WC { wc_simple = simple, wc_impl = implic, wc_insol = insol })+ = tyCoFVsOfCts simple `unionFV`+ tyCoFVsOfBag tyCoFVsOfImplic implic `unionFV`+ tyCoFVsOfCts insol++-- | Returns free variables of Implication as a composable FV computation.+-- See Note [Deterministic FV] in FV.+tyCoFVsOfImplic :: Implication -> FV+-- Only called on *zonked* things, hence no need to worry about flatten-skolems+tyCoFVsOfImplic (Implic { ic_skols = skols+ , ic_given = givens+ , ic_wanted = wanted })+ = FV.delFVs (mkVarSet skols `unionVarSet` mkVarSet givens)+ (tyCoFVsOfWC wanted `unionFV` tyCoFVsOfTypes (map evVarPred givens))++tyCoFVsOfBag :: (a -> FV) -> Bag a -> FV+tyCoFVsOfBag tvs_of = foldrBag (unionFV . tvs_of) emptyFV++--------------------------+dropDerivedSimples :: Cts -> Cts+-- Drop all Derived constraints, but make [W] back into [WD],+-- so that if we re-simplify these constraints we will get all+-- the right derived constraints re-generated. Forgetting this+-- step led to #12936+dropDerivedSimples simples = mapMaybeBag dropDerivedCt simples++dropDerivedCt :: Ct -> Maybe Ct+dropDerivedCt ct+ = case ctEvFlavour ev of+ Wanted WOnly -> Just (ct' { cc_ev = ev_wd })+ Wanted _ -> Just ct'+ _ -> ASSERT( isDerivedCt ct ) Nothing+ -- simples are all Wanted or Derived+ where+ ev = ctEvidence ct+ ev_wd = ev { ctev_nosh = WDeriv }+ ct' = setPendingScDict ct -- See Note [Resetting cc_pend_sc]++{- Note [Resetting cc_pend_sc]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we discard Derived constraints, in dropDerivedSimples, we must+set the cc_pend_sc flag to True, so that if we re-process this+CDictCan we will re-generate its derived superclasses. Otherwise+we might miss some fundeps. Trac #13662 showed this up.++See Note [The superclass story] in TcCanonical.+-}+++dropDerivedInsols :: Cts -> Cts+-- See Note [Dropping derived constraints]+dropDerivedInsols insols = filterBag keep insols+ where -- insols can include Given+ keep ct+ | isDerivedCt ct = not (isDroppableDerivedLoc (ctLoc ct))+ | otherwise = True++isDroppableDerivedLoc :: CtLoc -> Bool+-- Note [Dropping derived constraints]+isDroppableDerivedLoc loc+ = case ctLocOrigin loc of+ HoleOrigin {} -> False+ KindEqOrigin {} -> False+ GivenOrigin {} -> False+ FunDepOrigin1 {} -> False+ FunDepOrigin2 {} -> False+ _ -> True++arisesFromGivens :: Ct -> Bool+arisesFromGivens ct+ = case ctEvidence ct of+ CtGiven {} -> True+ CtWanted {} -> False+ CtDerived { ctev_loc = loc } -> from_given loc+ where+ from_given :: CtLoc -> Bool+ from_given loc = from_given_origin (ctLocOrigin loc)++ from_given_origin :: CtOrigin -> Bool+ from_given_origin (GivenOrigin {}) = True+ from_given_origin (FunDepOrigin1 _ l1 _ l2) = from_given l1 && from_given l2+ from_given_origin (FunDepOrigin2 _ o1 _ _) = from_given_origin o1+ from_given_origin _ = False++{- Note [Dropping derived constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general we discard derived constraints at the end of constraint solving;+see dropDerivedWC. For example++ * If we have an unsolved [W] (Ord a), we don't want to complain about+ an unsolved [D] (Eq a) as well.++ * If we have [W] a ~ Int, [W] a ~ Bool, improvement will generate+ [D] Int ~ Bool, and we don't want to report that because it's incomprehensible.+ That is why we don't rewrite wanteds with wanteds!++But (tiresomely) we do keep *some* Derived insolubles:++ * Insoluble kind equalities (e.g. [D] * ~ (* -> *)) may arise from+ a type equality a ~ Int#, say. In future they'll be Wanted, not Derived,+ but at the moment they are Derived.++ * Insoluble derived equalities (e.g. [D] Int ~ Bool) may arise from+ functional dependency interactions, either between Givens or+ Wanteds. It seems sensible to retain these:+ - For Givens they reflect unreachable code+ - For Wanteds it is arguably better to get a fundep error than+ a no-instance error (Trac #9612)++ * Type holes are derived constraints because they have no evidence+ and we want to keep them so we get the error report++Moreover, we keep *all* derived insolubles under some circumstances:++ * They are looked at by simplifyInfer, to decide whether to+ generalise. Example: [W] a ~ Int, [W] a ~ Bool+ We get [D] Int ~ Bool, and indeed the constraints are insoluble,+ and we want simplifyInfer to see that, even though we don't+ ultimately want to generate an (inexplicable) error message from++To distinguish these cases we use the CtOrigin.+++************************************************************************+* *+ CtEvidence+ The "flavor" of a canonical constraint+* *+************************************************************************+-}++isWantedCt :: Ct -> Bool+isWantedCt = isWanted . cc_ev++isGivenCt :: Ct -> Bool+isGivenCt = isGiven . cc_ev++isDerivedCt :: Ct -> Bool+isDerivedCt = isDerived . cc_ev++isCTyEqCan :: Ct -> Bool+isCTyEqCan (CTyEqCan {}) = True+isCTyEqCan (CFunEqCan {}) = False+isCTyEqCan _ = False++isCDictCan_Maybe :: Ct -> Maybe Class+isCDictCan_Maybe (CDictCan {cc_class = cls }) = Just cls+isCDictCan_Maybe _ = Nothing++isCIrredEvCan :: Ct -> Bool+isCIrredEvCan (CIrredEvCan {}) = True+isCIrredEvCan _ = False++isCFunEqCan_maybe :: Ct -> Maybe (TyCon, [Type])+isCFunEqCan_maybe (CFunEqCan { cc_fun = tc, cc_tyargs = xis }) = Just (tc, xis)+isCFunEqCan_maybe _ = Nothing++isCFunEqCan :: Ct -> Bool+isCFunEqCan (CFunEqCan {}) = True+isCFunEqCan _ = False++isCNonCanonical :: Ct -> Bool+isCNonCanonical (CNonCanonical {}) = True+isCNonCanonical _ = False++isHoleCt:: Ct -> Bool+isHoleCt (CHoleCan {}) = True+isHoleCt _ = False++isOutOfScopeCt :: Ct -> Bool+-- We treat expression holes representing out-of-scope variables a bit+-- differently when it comes to error reporting+isOutOfScopeCt (CHoleCan { cc_hole = ExprHole (OutOfScope {}) }) = True+isOutOfScopeCt _ = False++isExprHoleCt :: Ct -> Bool+isExprHoleCt (CHoleCan { cc_hole = ExprHole {} }) = True+isExprHoleCt _ = False++isTypeHoleCt :: Ct -> Bool+isTypeHoleCt (CHoleCan { cc_hole = TypeHole {} }) = True+isTypeHoleCt _ = False+++{- Note [Custom type errors in constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++When GHC reports a type-error about an unsolved-constraint, we check+to see if the constraint contains any custom-type errors, and if so+we report them. Here are some examples of constraints containing type+errors:++TypeError msg -- The actual constraint is a type error++TypError msg ~ Int -- Some type was supposed to be Int, but ended up+ -- being a type error instead++Eq (TypeError msg) -- A class constraint is stuck due to a type error++F (TypeError msg) ~ a -- A type function failed to evaluate due to a type err++It is also possible to have constraints where the type error is nested deeper,+for example see #11990, and also:++Eq (F (TypeError msg)) -- Here the type error is nested under a type-function+ -- call, which failed to evaluate because of it,+ -- and so the `Eq` constraint was unsolved.+ -- This may happen when one function calls another+ -- and the called function produced a custom type error.+-}++-- | A constraint is considered to be a custom type error, if it contains+-- custom type errors anywhere in it.+-- See Note [Custom type errors in constraints]+getUserTypeErrorMsg :: Ct -> Maybe Type+getUserTypeErrorMsg ct = findUserTypeError (ctPred ct)+ where+ findUserTypeError t = msum ( userTypeError_maybe t+ : map findUserTypeError (subTys t)+ )++ subTys t = case splitAppTys t of+ (t,[]) ->+ case splitTyConApp_maybe t of+ Nothing -> []+ Just (_,ts) -> ts+ (t,ts) -> t : ts+++++isUserTypeErrorCt :: Ct -> Bool+isUserTypeErrorCt ct = case getUserTypeErrorMsg ct of+ Just _ -> True+ _ -> False++isPendingScDict :: Ct -> Maybe Ct+-- Says whether cc_pend_sc is True, AND if so flips the flag+isPendingScDict ct@(CDictCan { cc_pend_sc = True })+ = Just (ct { cc_pend_sc = False })+isPendingScDict _ = Nothing++setPendingScDict :: Ct -> Ct+-- Set the cc_pend_sc flag to True+setPendingScDict ct@(CDictCan { cc_pend_sc = False })+ = ct { cc_pend_sc = True }+setPendingScDict ct = ct++superClassesMightHelp :: Ct -> Bool+-- ^ True if taking superclasses of givens, or of wanteds (to perhaps+-- expose more equalities or functional dependencies) might help to+-- solve this constraint. See Note [When superclasses help]+superClassesMightHelp ct+ = isWantedCt ct && not (is_ip ct)+ where+ is_ip (CDictCan { cc_class = cls }) = isIPClass cls+ is_ip _ = False++{- Note [When superclasses help]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+First read Note [The superclass story] in TcCanonical.++We expand superclasses and iterate only if there is at unsolved wanted+for which expansion of superclasses (e.g. from given constraints)+might actually help. The function superClassesMightHelp tells if+doing this superclass expansion might help solve this constraint.+Note that++ * Superclasses help only for Wanted constraints. Derived constraints+ are not really "unsolved" and we certainly don't want them to+ trigger superclass expansion. This was a good part of the loop+ in Trac #11523++ * Even for Wanted constraints, we say "no" for implicit parameters.+ we have [W] ?x::ty, expanding superclasses won't help:+ - Superclasses can't be implicit parameters+ - If we have a [G] ?x:ty2, then we'll have another unsolved+ [D] ty ~ ty2 (from the functional dependency)+ which will trigger superclass expansion.++ It's a bit of a special case, but it's easy to do. The runtime cost+ is low because the unsolved set is usually empty anyway (errors+ aside), and the first non-imlicit-parameter will terminate the search.++ The special case is worth it (Trac #11480, comment:2) because it+ applies to CallStack constraints, which aren't type errors. If we have+ f :: (C a) => blah+ f x = ...undefined...+ we'll get a CallStack constraint. If that's the only unsolved+ constraint it'll eventually be solved by defaulting. So we don't+ want to emit warnings about hitting the simplifier's iteration+ limit. A CallStack constraint really isn't an unsolved+ constraint; it can always be solved by defaulting.+-}++singleCt :: Ct -> Cts+singleCt = unitBag++andCts :: Cts -> Cts -> Cts+andCts = unionBags++listToCts :: [Ct] -> Cts+listToCts = listToBag++ctsElts :: Cts -> [Ct]+ctsElts = bagToList++consCts :: Ct -> Cts -> Cts+consCts = consBag++snocCts :: Cts -> Ct -> Cts+snocCts = snocBag++extendCtsList :: Cts -> [Ct] -> Cts+extendCtsList cts xs | null xs = cts+ | otherwise = cts `unionBags` listToBag xs++andManyCts :: [Cts] -> Cts+andManyCts = unionManyBags++emptyCts :: Cts+emptyCts = emptyBag++isEmptyCts :: Cts -> Bool+isEmptyCts = isEmptyBag++pprCts :: Cts -> SDoc+pprCts cts = vcat (map ppr (bagToList cts))++{-+************************************************************************+* *+ Wanted constraints+ These are forced to be in TcRnTypes because+ TcLclEnv mentions WantedConstraints+ WantedConstraint mentions CtLoc+ CtLoc mentions ErrCtxt+ ErrCtxt mentions TcM+* *+v%************************************************************************+-}++data WantedConstraints+ = WC { wc_simple :: Cts -- Unsolved constraints, all wanted+ , wc_impl :: Bag Implication+ , wc_insol :: Cts -- Insoluble constraints, can be+ -- wanted, given, or derived+ -- See Note [Insoluble constraints]+ }++emptyWC :: WantedConstraints+emptyWC = WC { wc_simple = emptyBag, wc_impl = emptyBag, wc_insol = emptyBag }++mkSimpleWC :: [CtEvidence] -> WantedConstraints+mkSimpleWC cts+ = WC { wc_simple = listToBag (map mkNonCanonical cts)+ , wc_impl = emptyBag+ , wc_insol = emptyBag }++mkImplicWC :: Bag Implication -> WantedConstraints+mkImplicWC implic+ = WC { wc_simple = emptyBag, wc_impl = implic, wc_insol = emptyBag }++isEmptyWC :: WantedConstraints -> Bool+isEmptyWC (WC { wc_simple = f, wc_impl = i, wc_insol = n })+ = isEmptyBag f && isEmptyBag i && isEmptyBag n++andWC :: WantedConstraints -> WantedConstraints -> WantedConstraints+andWC (WC { wc_simple = f1, wc_impl = i1, wc_insol = n1 })+ (WC { wc_simple = f2, wc_impl = i2, wc_insol = n2 })+ = WC { wc_simple = f1 `unionBags` f2+ , wc_impl = i1 `unionBags` i2+ , wc_insol = n1 `unionBags` n2 }++unionsWC :: [WantedConstraints] -> WantedConstraints+unionsWC = foldr andWC emptyWC++addSimples :: WantedConstraints -> Bag Ct -> WantedConstraints+addSimples wc cts+ = wc { wc_simple = wc_simple wc `unionBags` cts }+ -- Consider: Put the new constraints at the front, so they get solved first++addImplics :: WantedConstraints -> Bag Implication -> WantedConstraints+addImplics wc implic = wc { wc_impl = wc_impl wc `unionBags` implic }++addInsols :: WantedConstraints -> Bag Ct -> WantedConstraints+addInsols wc cts+ = wc { wc_insol = wc_insol wc `unionBags` cts }++getInsolubles :: WantedConstraints -> Cts+getInsolubles = wc_insol++insolublesOnly :: WantedConstraints -> WantedConstraints+-- Keep only the insolubles+insolublesOnly wc = wc { wc_simple = emptyBag, wc_impl = emptyBag }++dropDerivedWC :: WantedConstraints -> WantedConstraints+-- See Note [Dropping derived constraints]+dropDerivedWC wc@(WC { wc_simple = simples, wc_insol = insols })+ = wc { wc_simple = dropDerivedSimples simples+ , wc_insol = dropDerivedInsols insols }+ -- The wc_impl implications are already (recursively) filtered++isSolvedStatus :: ImplicStatus -> Bool+isSolvedStatus (IC_Solved {}) = True+isSolvedStatus _ = False++isInsolubleStatus :: ImplicStatus -> Bool+isInsolubleStatus IC_Insoluble = True+isInsolubleStatus _ = False++insolubleImplic :: Implication -> Bool+insolubleImplic ic = isInsolubleStatus (ic_status ic)++insolubleWC :: WantedConstraints -> Bool+insolubleWC (WC { wc_impl = implics, wc_insol = insols })+ = anyBag trulyInsoluble insols+ || anyBag insolubleImplic implics++trulyInsoluble :: Ct -> Bool+-- Constraints in the wc_insol set which ARE NOT+-- treated as truly insoluble:+-- a) type holes, arising from PartialTypeSignatures,+-- b) "true" expression holes arising from TypedHoles+--+-- A "expression hole" or "type hole" constraint isn't really an error+-- at all; it's a report saying "_ :: Int" here. But an out-of-scope+-- variable masquerading as expression holes IS treated as truly+-- insoluble, so that it trumps other errors during error reporting.+-- Yuk!+trulyInsoluble insol+ | isHoleCt insol = isOutOfScopeCt insol+ | otherwise = True++instance Outputable WantedConstraints where+ ppr (WC {wc_simple = s, wc_impl = i, wc_insol = n})+ = text "WC" <+> braces (vcat+ [ ppr_bag (text "wc_simple") s+ , ppr_bag (text "wc_insol") n+ , ppr_bag (text "wc_impl") i ])++ppr_bag :: Outputable a => SDoc -> Bag a -> SDoc+ppr_bag doc bag+ | isEmptyBag bag = empty+ | otherwise = hang (doc <+> equals)+ 2 (foldrBag (($$) . ppr) empty bag)++{-+************************************************************************+* *+ Implication constraints+* *+************************************************************************+-}++data Implication+ = Implic {+ ic_tclvl :: TcLevel, -- TcLevel of unification variables+ -- allocated /inside/ this implication++ ic_skols :: [TcTyVar], -- Introduced skolems+ ic_info :: SkolemInfo, -- See Note [Skolems in an implication]+ -- See Note [Shadowing in a constraint]++ ic_given :: [EvVar], -- Given evidence variables+ -- (order does not matter)+ -- See Invariant (GivenInv) in TcType++ ic_no_eqs :: Bool, -- True <=> ic_givens have no equalities, for sure+ -- False <=> ic_givens might have equalities++ ic_env :: TcLclEnv, -- Gives the source location and error context+ -- for the implication, and hence for all the+ -- given evidence variables++ ic_wanted :: WantedConstraints, -- The wanted++ ic_binds :: EvBindsVar, -- Points to the place to fill in the+ -- abstraction and bindings.++ ic_needed :: VarSet, -- Union of the ics_need fields of any /discarded/+ -- solved implications in ic_wanted++ ic_status :: ImplicStatus+ }++data ImplicStatus+ = IC_Solved -- All wanteds in the tree are solved, all the way down+ { ics_need :: VarSet -- Evidence variables bound further out,+ -- but needed by this solved implication+ , ics_dead :: [EvVar] } -- Subset of ic_given that are not needed+ -- See Note [Tracking redundant constraints] in TcSimplify++ | IC_Insoluble -- At least one insoluble constraint in the tree++ | IC_Unsolved -- Neither of the above; might go either way++instance Outputable Implication where+ ppr (Implic { ic_tclvl = tclvl, ic_skols = skols+ , ic_given = given, ic_no_eqs = no_eqs+ , ic_wanted = wanted, ic_status = status+ , ic_binds = binds, ic_needed = needed , ic_info = info })+ = hang (text "Implic" <+> lbrace)+ 2 (sep [ text "TcLevel =" <+> ppr tclvl+ , text "Skolems =" <+> pprTyVars skols+ , text "No-eqs =" <+> ppr no_eqs+ , text "Status =" <+> ppr status+ , hang (text "Given =") 2 (pprEvVars given)+ , hang (text "Wanted =") 2 (ppr wanted)+ , text "Binds =" <+> ppr binds+ , text "Needed =" <+> ppr needed+ , pprSkolInfo info ] <+> rbrace)++instance Outputable ImplicStatus where+ ppr IC_Insoluble = text "Insoluble"+ ppr IC_Unsolved = text "Unsolved"+ ppr (IC_Solved { ics_need = vs, ics_dead = dead })+ = text "Solved"+ <+> (braces $ vcat [ text "Dead givens =" <+> ppr dead+ , text "Needed =" <+> ppr vs ])++{-+Note [Needed evidence variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Th ic_need_evs field holds the free vars of ic_binds, and all the+ic_binds in nested implications.++ * Main purpose: if one of the ic_givens is not mentioned in here, it+ is redundant.++ * solveImplication may drop an implication altogether if it has no+ remaining 'wanteds'. But we still track the free vars of its+ evidence binds, even though it has now disappeared.++Note [Shadowing in a constraint]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We assume NO SHADOWING in a constraint. Specifically+ * The unification variables are all implicitly quantified at top+ level, and are all unique+ * The skolem variables bound in ic_skols are all freah when the+ implication is created.+So we can safely substitute. For example, if we have+ forall a. a~Int => ...(forall b. ...a...)...+we can push the (a~Int) constraint inwards in the "givens" without+worrying that 'b' might clash.++Note [Skolems in an implication]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The skolems in an implication are not there to perform a skolem escape+check. That happens because all the environment variables are in the+untouchables, and therefore cannot be unified with anything at all,+let alone the skolems.++Instead, ic_skols is used only when considering floating a constraint+outside the implication in TcSimplify.floatEqualities or+TcSimplify.approximateImplications++Note [Insoluble constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Some of the errors that we get during canonicalization are best+reported when all constraints have been simplified as much as+possible. For instance, assume that during simplification the+following constraints arise:++ [Wanted] F alpha ~ uf1+ [Wanted] beta ~ uf1 beta++When canonicalizing the wanted (beta ~ uf1 beta), if we eagerly fail+we will simply see a message:+ 'Can't construct the infinite type beta ~ uf1 beta'+and the user has no idea what the uf1 variable is.++Instead our plan is that we will NOT fail immediately, but:+ (1) Record the "frozen" error in the ic_insols field+ (2) Isolate the offending constraint from the rest of the inerts+ (3) Keep on simplifying/canonicalizing++At the end, we will hopefully have substituted uf1 := F alpha, and we+will be able to report a more informative error:+ 'Can't construct the infinite type beta ~ F alpha beta'++Insoluble constraints *do* include Derived constraints. For example,+a functional dependency might give rise to [D] Int ~ Bool, and we must+report that. If insolubles did not contain Deriveds, reportErrors would+never see it.+++************************************************************************+* *+ Pretty printing+* *+************************************************************************+-}++pprEvVars :: [EvVar] -> SDoc -- Print with their types+pprEvVars ev_vars = vcat (map pprEvVarWithType ev_vars)++pprEvVarTheta :: [EvVar] -> SDoc+pprEvVarTheta ev_vars = pprTheta (map evVarPred ev_vars)++pprEvVarWithType :: EvVar -> SDoc+pprEvVarWithType v = ppr v <+> dcolon <+> pprType (evVarPred v)++{-+************************************************************************+* *+ CtEvidence+* *+************************************************************************++Note [Evidence field of CtEvidence]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+During constraint solving we never look at the type of ctev_evar/ctev_dest;+instead we look at the ctev_pred field. The evtm/evar field+may be un-zonked.++Note [Bind new Givens immediately]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For Givens we make new EvVars and bind them immediately. Two main reasons:+ * Gain sharing. E.g. suppose we start with g :: C a b, where+ class D a => C a b+ class (E a, F a) => D a+ If we generate all g's superclasses as separate EvTerms we might+ get selD1 (selC1 g) :: E a+ selD2 (selC1 g) :: F a+ selC1 g :: D a+ which we could do more economically as:+ g1 :: D a = selC1 g+ g2 :: E a = selD1 g1+ g3 :: F a = selD2 g1++ * For *coercion* evidence we *must* bind each given:+ class (a~b) => C a b where ....+ f :: C a b => ....+ Then in f's Givens we have g:(C a b) and the superclass sc(g,0):a~b.+ But that superclass selector can't (yet) appear in a coercion+ (see evTermCoercion), so the easy thing is to bind it to an Id.++So a Given has EvVar inside it rather than (as previously) an EvTerm.++Note [Given in ctEvCoercion]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When retrieving the evidence from a Given equality, we update the type of the EvVar+from the ctev_pred field. In Note [Evidence field of CtEvidence], we claim that+the type of the evidence is never looked at -- but this isn't true in the case of+a coercion that is used in a type. (See the comments in Note [Flattening] in TcFlatten+about the FTRNotFollowed case of flattenTyVar.) So, right here where we are retrieving+the coercion from a Given, we update the type to make sure it's zonked.++-}++-- | A place for type-checking evidence to go after it is generated.+-- Wanted equalities are always HoleDest; other wanteds are always+-- EvVarDest.+data TcEvDest+ = EvVarDest EvVar -- ^ bind this var to the evidence+ -- EvVarDest is always used for non-type-equalities+ -- e.g. class constraints++ | HoleDest CoercionHole -- ^ fill in this hole with the evidence+ -- HoleDest is always used for type-equalities+ -- See Note [Coercion holes] in TyCoRep++data CtEvidence+ = CtGiven -- Truly given, not depending on subgoals+ { ctev_pred :: TcPredType -- See Note [Ct/evidence invariant]+ , ctev_evar :: EvVar -- See Note [Evidence field of CtEvidence]+ , ctev_loc :: CtLoc }+++ | CtWanted -- Wanted goal+ { ctev_pred :: TcPredType -- See Note [Ct/evidence invariant]+ , ctev_dest :: TcEvDest+ , ctev_nosh :: ShadowInfo -- See Note [Constraint flavours]+ , ctev_loc :: CtLoc }++ | CtDerived -- A goal that we don't really have to solve and can't+ -- immediately rewrite anything other than a derived+ -- (there's no evidence!) but if we do manage to solve+ -- it may help in solving other goals.+ { ctev_pred :: TcPredType+ , ctev_loc :: CtLoc }++ctEvPred :: CtEvidence -> TcPredType+-- The predicate of a flavor+ctEvPred = ctev_pred++ctEvLoc :: CtEvidence -> CtLoc+ctEvLoc = ctev_loc++ctEvOrigin :: CtEvidence -> CtOrigin+ctEvOrigin = ctLocOrigin . ctEvLoc++-- | Get the equality relation relevant for a 'CtEvidence'+ctEvEqRel :: CtEvidence -> EqRel+ctEvEqRel = predTypeEqRel . ctEvPred++-- | Get the role relevant for a 'CtEvidence'+ctEvRole :: CtEvidence -> Role+ctEvRole = eqRelRole . ctEvEqRel++ctEvTerm :: CtEvidence -> EvTerm+ctEvTerm ev@(CtWanted { ctev_dest = HoleDest _ }) = EvCoercion $ ctEvCoercion ev+ctEvTerm ev = EvId (ctEvId ev)++-- Always returns a coercion whose type is precisely ctev_pred of the CtEvidence.+-- See also Note [Given in ctEvCoercion]+ctEvCoercion :: CtEvidence -> Coercion+ctEvCoercion (CtGiven { ctev_pred = pred_ty, ctev_evar = ev_id })+ = mkTcCoVarCo (setVarType ev_id pred_ty) -- See Note [Given in ctEvCoercion]+ctEvCoercion (CtWanted { ctev_dest = dest, ctev_pred = pred })+ | HoleDest hole <- dest+ , Just (role, ty1, ty2) <- getEqPredTys_maybe pred+ = -- ctEvCoercion is only called on type equalities+ -- and they always have HoleDests+ mkHoleCo hole role ty1 ty2+ctEvCoercion ev+ = pprPanic "ctEvCoercion" (ppr ev)++ctEvId :: CtEvidence -> TcId+ctEvId (CtWanted { ctev_dest = EvVarDest ev }) = ev+ctEvId (CtGiven { ctev_evar = ev }) = ev+ctEvId ctev = pprPanic "ctEvId:" (ppr ctev)++instance Outputable TcEvDest where+ ppr (HoleDest h) = text "hole" <> ppr h+ ppr (EvVarDest ev) = ppr ev++instance Outputable CtEvidence where+ ppr ev = ppr (ctEvFlavour ev)+ <+> pp_ev+ <+> braces (ppr (ctl_depth (ctEvLoc ev))) <> dcolon+ -- Show the sub-goal depth too+ <+> ppr (ctEvPred ev)+ where+ pp_ev = case ev of+ CtGiven { ctev_evar = v } -> ppr v+ CtWanted {ctev_dest = d } -> ppr d+ CtDerived {} -> text "_"++isWanted :: CtEvidence -> Bool+isWanted (CtWanted {}) = True+isWanted _ = False++isGiven :: CtEvidence -> Bool+isGiven (CtGiven {}) = True+isGiven _ = False++isDerived :: CtEvidence -> Bool+isDerived (CtDerived {}) = True+isDerived _ = False++{-+%************************************************************************+%* *+ CtFlavour+%* *+%************************************************************************++Note [Constraint flavours]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Constraints come in four flavours:++* [G] Given: we have evidence++* [W] Wanted WOnly: we want evidence++* [D] Derived: any solution must satisfy this constraint, but+ we don't need evidence for it. Examples include:+ - superclasses of [W] class constraints+ - equalities arising from functional dependencies+ or injectivity++* [WD] Wanted WDeriv: a single constraint that represents+ both [W] and [D]+ We keep them paired as one both for efficiency, and because+ when we have a finite map F tys -> CFunEqCan, it's inconvenient+ to have two CFunEqCans in the range++The ctev_nosh field of a Wanted distinguishes between [W] and [WD]++Wanted constraints are born as [WD], but are split into [W] and its+"shadow" [D] in TcSMonad.maybeEmitShadow.++See Note [The improvement story and derived shadows] in TcSMonad+-}++data CtFlavour -- See Note [Constraint flavours]+ = Given+ | Wanted ShadowInfo+ | Derived+ deriving Eq++data ShadowInfo+ = WDeriv -- [WD] This Wanted constraint has no Derived shadow,+ -- so it behaves like a pair of a Wanted and a Derived+ | WOnly -- [W] It has a separate derived shadow+ -- See Note [Derived shadows]+ deriving( Eq )++isGivenOrWDeriv :: CtFlavour -> Bool+isGivenOrWDeriv Given = True+isGivenOrWDeriv (Wanted WDeriv) = True+isGivenOrWDeriv _ = False++instance Outputable CtFlavour where+ ppr Given = text "[G]"+ ppr (Wanted WDeriv) = text "[WD]"+ ppr (Wanted WOnly) = text "[W]"+ ppr Derived = text "[D]"++ctEvFlavour :: CtEvidence -> CtFlavour+ctEvFlavour (CtWanted { ctev_nosh = nosh }) = Wanted nosh+ctEvFlavour (CtGiven {}) = Given+ctEvFlavour (CtDerived {}) = Derived++-- | Whether or not one 'Ct' can rewrite another is determined by its+-- flavour and its equality relation. See also+-- Note [Flavours with roles] in TcSMonad+type CtFlavourRole = (CtFlavour, EqRel)++-- | Extract the flavour, role, and boxity from a 'CtEvidence'+ctEvFlavourRole :: CtEvidence -> CtFlavourRole+ctEvFlavourRole ev = (ctEvFlavour ev, ctEvEqRel ev)++-- | Extract the flavour, role, and boxity from a 'Ct'+ctFlavourRole :: Ct -> CtFlavourRole+ctFlavourRole = ctEvFlavourRole . cc_ev++{- Note [eqCanRewrite]+~~~~~~~~~~~~~~~~~~~~~~+(eqCanRewrite ct1 ct2) holds if the constraint ct1 (a CTyEqCan of form+tv ~ ty) can be used to rewrite ct2. It must satisfy the properties of+a can-rewrite relation, see Definition [Can-rewrite relation] in+TcSMonad.++With the solver handling Coercible constraints like equality constraints,+the rewrite conditions must take role into account, never allowing+a representational equality to rewrite a nominal one.++Note [Wanteds do not rewrite Wanteds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't allow Wanteds to rewrite Wanteds, because that can give rise+to very confusing type error messages. A good example is Trac #8450.+Here's another+ f :: a -> Bool+ f x = ( [x,'c'], [x,True] ) `seq` True+Here we get+ [W] a ~ Char+ [W] a ~ Bool+but we do not want to complain about Bool ~ Char!++Note [Deriveds do rewrite Deriveds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+However we DO allow Deriveds to rewrite Deriveds, because that's how+improvement works; see Note [The improvement story] in TcInteract.++However, for now at least I'm only letting (Derived,NomEq) rewrite+(Derived,NomEq) and not doing anything for ReprEq. If we have+ eqCanRewriteFR (Derived, NomEq) (Derived, _) = True+then we lose property R2 of Definition [Can-rewrite relation]+in TcSMonad+ R2. If f1 >= f, and f2 >= f,+ then either f1 >= f2 or f2 >= f1+Consider f1 = (Given, ReprEq)+ f2 = (Derived, NomEq)+ f = (Derived, ReprEq)++I thought maybe we could never get Derived ReprEq constraints, but+we can; straight from the Wanteds during improvement. And from a Derived+ReprEq we could conceivably get a Derived NomEq improvement (by decomposing+a type constructor with Nomninal role), and hence unify.+-}++eqCanRewriteFR :: CtFlavourRole -> CtFlavourRole -> Bool+-- Can fr1 actually rewrite fr2?+-- Very important function!+-- See Note [eqCanRewrite]+-- See Note [Wanteds do not rewrite Wanteds]+-- See Note [Deriveds do rewrite Deriveds]+eqCanRewriteFR (Given, NomEq) (_, _) = True+eqCanRewriteFR (Given, ReprEq) (_, ReprEq) = True+eqCanRewriteFR (Wanted WDeriv, NomEq) (Derived, NomEq) = True+eqCanRewriteFR (Derived, NomEq) (Derived, NomEq) = True+eqCanRewriteFR _ _ = False++eqMayRewriteFR :: CtFlavourRole -> CtFlavourRole -> Bool+-- Is it /possible/ that fr1 can rewrite fr2?+-- This is used when deciding which inerts to kick out,+-- at which time a [WD] inert may be split into [W] and [D]+eqMayRewriteFR (Wanted WDeriv, NomEq) (Wanted WDeriv, NomEq) = True+eqMayRewriteFR (Derived, NomEq) (Wanted WDeriv, NomEq) = True+eqMayRewriteFR fr1 fr2 = eqCanRewriteFR fr1 fr2++-----------------+{- Note [funEqCanDischarge]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have two CFunEqCans with the same LHS:+ (x1:F ts ~ f1) `funEqCanDischarge` (x2:F ts ~ f2)+Can we drop x2 in favour of x1, either unifying+f2 (if it's a flatten meta-var) or adding a new Given+(f1 ~ f2), if x2 is a Given?++Answer: yes if funEqCanDischarge is true.+-}++funEqCanDischarge+ :: CtEvidence -> CtEvidence+ -> ( SwapFlag -- NotSwapped => lhs can discharge rhs+ -- Swapped => rhs can discharge lhs+ , Bool) -- True <=> upgrade non-discharded one+ -- from [W] to [WD]+-- See Note [funEqCanDischarge]+funEqCanDischarge ev1 ev2+ = ASSERT2( ctEvEqRel ev1 == NomEq, ppr ev1 )+ ASSERT2( ctEvEqRel ev2 == NomEq, ppr ev2 )+ -- CFunEqCans are all Nominal, hence asserts+ funEqCanDischargeF (ctEvFlavour ev1) (ctEvFlavour ev2)++funEqCanDischargeF :: CtFlavour -> CtFlavour -> (SwapFlag, Bool)+funEqCanDischargeF Given _ = (NotSwapped, False)+funEqCanDischargeF _ Given = (IsSwapped, False)+funEqCanDischargeF (Wanted WDeriv) _ = (NotSwapped, False)+funEqCanDischargeF _ (Wanted WDeriv) = (IsSwapped, True)+funEqCanDischargeF (Wanted WOnly) (Wanted WOnly) = (NotSwapped, False)+funEqCanDischargeF (Wanted WOnly) Derived = (NotSwapped, True)+funEqCanDischargeF Derived (Wanted WOnly) = (IsSwapped, True)+funEqCanDischargeF Derived Derived = (NotSwapped, False)+++{- Note [eqCanDischarge]+~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have two identical CTyEqCan equality constraints+(i.e. both LHS and RHS are the same)+ (x1:a~t) `eqCanDischarge` (xs:a~t)+Can we just drop x2 in favour of x1?++Answer: yes if eqCanDischarge is true.++Note that we do /not/ allow Wanted to discharge Derived.+We must keep both. Why? Because the Derived may rewrite+other Deriveds in the model whereas the Wanted cannot.++However a Wanted can certainly discharge an identical Wanted. So+eqCanDischarge does /not/ define a can-rewrite relation in the+sense of Definition [Can-rewrite relation] in TcSMonad.++We /do/ say that a [W] can discharge a [WD]. In evidence terms it+certainly can, and the /caller/ arranges that the otherwise-lost [D]+is spat out as a new Derived. -}++eqCanDischarge :: CtEvidence -> CtEvidence -> Bool+-- See Note [eqCanDischarge]+eqCanDischarge ev1 ev2 = eqCanDischargeFR (ctEvFlavourRole ev1)+ (ctEvFlavourRole ev2)++eqCanDischargeFR :: CtFlavourRole -> CtFlavourRole -> Bool+eqCanDischargeFR (_, ReprEq) (_, NomEq) = False+eqCanDischargeFR (f1,_) (f2, _) = eqCanDischargeF f1 f2++eqCanDischargeF :: CtFlavour -> CtFlavour -> Bool+eqCanDischargeF Given _ = True+eqCanDischargeF (Wanted _) (Wanted _) = True+eqCanDischargeF (Wanted WDeriv) Derived = True+eqCanDischargeF Derived Derived = True+eqCanDischargeF _ _ = False+++{-+************************************************************************+* *+ SubGoalDepth+* *+************************************************************************++Note [SubGoalDepth]+~~~~~~~~~~~~~~~~~~~+The 'SubGoalDepth' takes care of stopping the constraint solver from looping.++The counter starts at zero and increases. It includes dictionary constraints,+equality simplification, and type family reduction. (Why combine these? Because+it's actually quite easy to mistake one for another, in sufficiently involved+scenarios, like ConstraintKinds.)++The flag -fcontext-stack=n (not very well named!) fixes the maximium+level.++* The counter includes the depth of type class instance declarations. Example:+ [W] d{7} : Eq [Int]+ That is d's dictionary-constraint depth is 7. If we use the instance+ $dfEqList :: Eq a => Eq [a]+ to simplify it, we get+ d{7} = $dfEqList d'{8}+ where d'{8} : Eq Int, and d' has depth 8.++ For civilised (decidable) instance declarations, each increase of+ depth removes a type constructor from the type, so the depth never+ gets big; i.e. is bounded by the structural depth of the type.++* The counter also increments when resolving+equalities involving type functions. Example:+ Assume we have a wanted at depth 7:+ [W] d{7} : F () ~ a+ If there is an type function equation "F () = Int", this would be rewritten to+ [W] d{8} : Int ~ a+ and remembered as having depth 8.++ Again, without UndecidableInstances, this counter is bounded, but without it+ can resolve things ad infinitum. Hence there is a maximum level.++* Lastly, every time an equality is rewritten, the counter increases. Again,+ rewriting an equality constraint normally makes progress, but it's possible+ the "progress" is just the reduction of an infinitely-reducing type family.+ Hence we need to track the rewrites.++When compiling a program requires a greater depth, then GHC recommends turning+off this check entirely by setting -freduction-depth=0. This is because the+exact number that works is highly variable, and is likely to change even between+minor releases. Because this check is solely to prevent infinite compilation+times, it seems safe to disable it when a user has ascertained that their program+doesn't loop at the type level.++-}++-- | See Note [SubGoalDepth]+newtype SubGoalDepth = SubGoalDepth Int+ deriving (Eq, Ord, Outputable)++initialSubGoalDepth :: SubGoalDepth+initialSubGoalDepth = SubGoalDepth 0++bumpSubGoalDepth :: SubGoalDepth -> SubGoalDepth+bumpSubGoalDepth (SubGoalDepth n) = SubGoalDepth (n + 1)++maxSubGoalDepth :: SubGoalDepth -> SubGoalDepth -> SubGoalDepth+maxSubGoalDepth (SubGoalDepth n) (SubGoalDepth m) = SubGoalDepth (n `max` m)++subGoalDepthExceeded :: DynFlags -> SubGoalDepth -> Bool+subGoalDepthExceeded dflags (SubGoalDepth d)+ = mkIntWithInf d > reductionDepth dflags++{-+************************************************************************+* *+ CtLoc+* *+************************************************************************++The 'CtLoc' gives information about where a constraint came from.+This is important for decent error message reporting because+dictionaries don't appear in the original source code.+type will evolve...+-}++data CtLoc = CtLoc { ctl_origin :: CtOrigin+ , ctl_env :: TcLclEnv+ , ctl_t_or_k :: Maybe TypeOrKind -- OK if we're not sure+ , ctl_depth :: !SubGoalDepth }+ -- The TcLclEnv includes particularly+ -- source location: tcl_loc :: RealSrcSpan+ -- context: tcl_ctxt :: [ErrCtxt]+ -- binder stack: tcl_bndrs :: TcIdBinderStack+ -- level: tcl_tclvl :: TcLevel++mkGivenLoc :: TcLevel -> SkolemInfo -> TcLclEnv -> CtLoc+mkGivenLoc tclvl skol_info env+ = CtLoc { ctl_origin = GivenOrigin skol_info+ , ctl_env = env { tcl_tclvl = tclvl }+ , ctl_t_or_k = Nothing -- this only matters for error msgs+ , ctl_depth = initialSubGoalDepth }++mkKindLoc :: TcType -> TcType -- original *types* being compared+ -> CtLoc -> CtLoc+mkKindLoc s1 s2 loc = setCtLocOrigin (toKindLoc loc)+ (KindEqOrigin s1 (Just s2) (ctLocOrigin loc)+ (ctLocTypeOrKind_maybe loc))++-- | Take a CtLoc and moves it to the kind level+toKindLoc :: CtLoc -> CtLoc+toKindLoc loc = loc { ctl_t_or_k = Just KindLevel }++ctLocEnv :: CtLoc -> TcLclEnv+ctLocEnv = ctl_env++ctLocLevel :: CtLoc -> TcLevel+ctLocLevel loc = tcl_tclvl (ctLocEnv loc)++ctLocDepth :: CtLoc -> SubGoalDepth+ctLocDepth = ctl_depth++ctLocOrigin :: CtLoc -> CtOrigin+ctLocOrigin = ctl_origin++ctLocSpan :: CtLoc -> RealSrcSpan+ctLocSpan (CtLoc { ctl_env = lcl}) = tcl_loc lcl++ctLocTypeOrKind_maybe :: CtLoc -> Maybe TypeOrKind+ctLocTypeOrKind_maybe = ctl_t_or_k++setCtLocSpan :: CtLoc -> RealSrcSpan -> CtLoc+setCtLocSpan ctl@(CtLoc { ctl_env = lcl }) loc = setCtLocEnv ctl (lcl { tcl_loc = loc })++bumpCtLocDepth :: CtLoc -> CtLoc+bumpCtLocDepth loc@(CtLoc { ctl_depth = d }) = loc { ctl_depth = bumpSubGoalDepth d }++setCtLocOrigin :: CtLoc -> CtOrigin -> CtLoc+setCtLocOrigin ctl orig = ctl { ctl_origin = orig }++setCtLocEnv :: CtLoc -> TcLclEnv -> CtLoc+setCtLocEnv ctl env = ctl { ctl_env = env }++pushErrCtxt :: CtOrigin -> ErrCtxt -> CtLoc -> CtLoc+pushErrCtxt o err loc@(CtLoc { ctl_env = lcl })+ = loc { ctl_origin = o, ctl_env = lcl { tcl_ctxt = err : tcl_ctxt lcl } }++pushErrCtxtSameOrigin :: ErrCtxt -> CtLoc -> CtLoc+-- Just add information w/o updating the origin!+pushErrCtxtSameOrigin err loc@(CtLoc { ctl_env = lcl })+ = loc { ctl_env = lcl { tcl_ctxt = err : tcl_ctxt lcl } }++{-+************************************************************************+* *+ SkolemInfo+* *+************************************************************************+-}++-- SkolemInfo gives the origin of *given* constraints+-- a) type variables are skolemised+-- b) an implication constraint is generated+data SkolemInfo+ = SigSkol -- A skolem that is created by instantiating+ -- a programmer-supplied type signature+ -- Location of the binding site is on the TyVar+ -- See Note [SigSkol SkolemInfo]+ UserTypeCtxt -- What sort of signature+ TcType -- Original type signature (before skolemisation)+ [(Name,TcTyVar)] -- Maps the original name of the skolemised tyvar+ -- to its instantiated version++ | ClsSkol Class -- Bound at a class decl++ | DerivSkol Type -- Bound by a 'deriving' clause;+ -- the type is the instance we are trying to derive++ | InstSkol -- Bound at an instance decl+ | InstSC TypeSize -- A "given" constraint obtained by superclass selection.+ -- If (C ty1 .. tyn) is the largest class from+ -- which we made a superclass selection in the chain,+ -- then TypeSize = sizeTypes [ty1, .., tyn]+ -- See Note [Solving superclass constraints] in TcInstDcls++ | DataSkol -- Bound at a data type declaration+ | FamInstSkol -- Bound at a family instance decl+ | PatSkol -- An existential type variable bound by a pattern for+ ConLike -- a data constructor with an existential type.+ (HsMatchContext Name)+ -- e.g. data T = forall a. Eq a => MkT a+ -- f (MkT x) = ...+ -- The pattern MkT x will allocate an existential type+ -- variable for 'a'.++ | ArrowSkol -- An arrow form (see TcArrows)++ | IPSkol [HsIPName] -- Binding site of an implicit parameter++ | RuleSkol RuleName -- The LHS of a RULE++ | InferSkol [(Name,TcType)]+ -- We have inferred a type for these (mutually-recursivive)+ -- polymorphic Ids, and are now checking that their RHS+ -- constraints are satisfied.++ | BracketSkol -- Template Haskell bracket++ | UnifyForAllSkol -- We are unifying two for-all types+ TcType -- The instantiated type *inside* the forall++ | UnkSkol -- Unhelpful info (until I improve it)++instance Outputable SkolemInfo where+ ppr = pprSkolInfo++termEvidenceAllowed :: SkolemInfo -> Bool+-- Whether an implication constraint with this SkolemInfo+-- is permitted to have term-level evidence. There is+-- only one that is not, associated with unifiying+-- forall-types+termEvidenceAllowed (UnifyForAllSkol {}) = False+termEvidenceAllowed _ = True++pprSkolInfo :: SkolemInfo -> SDoc+-- Complete the sentence "is a rigid type variable bound by..."+pprSkolInfo (SigSkol cx ty _) = pprSigSkolInfo cx ty+pprSkolInfo (IPSkol ips) = text "the implicit-parameter binding" <> plural ips <+> text "for"+ <+> pprWithCommas ppr ips+pprSkolInfo (ClsSkol cls) = text "the class declaration for" <+> quotes (ppr cls)+pprSkolInfo (DerivSkol pred) = text "the deriving clause for" <+> quotes (ppr pred)+pprSkolInfo InstSkol = text "the instance declaration"+pprSkolInfo (InstSC n) = text "the instance declaration" <> ifPprDebug (parens (ppr n))+pprSkolInfo DataSkol = text "a data type declaration"+pprSkolInfo FamInstSkol = text "a family instance declaration"+pprSkolInfo BracketSkol = text "a Template Haskell bracket"+pprSkolInfo (RuleSkol name) = text "the RULE" <+> pprRuleName name+pprSkolInfo ArrowSkol = text "an arrow form"+pprSkolInfo (PatSkol cl mc) = sep [ pprPatSkolInfo cl+ , text "in" <+> pprMatchContext mc ]+pprSkolInfo (InferSkol ids) = sep [ text "the inferred type of"+ , vcat [ ppr name <+> dcolon <+> ppr ty+ | (name,ty) <- ids ]]+pprSkolInfo (UnifyForAllSkol ty) = text "the type" <+> ppr ty++-- UnkSkol+-- For type variables the others are dealt with by pprSkolTvBinding.+-- For Insts, these cases should not happen+pprSkolInfo UnkSkol = WARN( True, text "pprSkolInfo: UnkSkol" ) text "UnkSkol"++pprSigSkolInfo :: UserTypeCtxt -> TcType -> SDoc+-- The type is already tidied+pprSigSkolInfo ctxt ty+ = case ctxt of+ FunSigCtxt f _ -> vcat [ text "the type signature for:"+ , nest 2 (pprPrefixOcc f <+> dcolon <+> ppr ty) ]+ PatSynCtxt {} -> pprUserTypeCtxt ctxt -- See Note [Skolem info for pattern synonyms]+ _ -> vcat [ pprUserTypeCtxt ctxt <> colon+ , nest 2 (ppr ty) ]++pprPatSkolInfo :: ConLike -> SDoc+pprPatSkolInfo (RealDataCon dc)+ = sep [ text "a pattern with constructor:"+ , nest 2 $ ppr dc <+> dcolon+ <+> pprType (dataConUserType dc) <> comma ]+ -- pprType prints forall's regardless of -fprint-explicit-foralls+ -- which is what we want here, since we might be saying+ -- type variable 't' is bound by ...++pprPatSkolInfo (PatSynCon ps)+ = sep [ text "a pattern with pattern synonym:"+ , nest 2 $ ppr ps <+> dcolon+ <+> pprPatSynType ps <> comma ]++{- Note [Skolem info for pattern synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For pattern synonym SkolemInfo we have+ SigSkol (PatSynCtxt p) ty _+but the type 'ty' is not very helpful. The full pattern-synonym type+has the provided and required pieces, which it is inconvenient to+record and display here. So we simply don't display the type at all,+contenting outselves with just the name of the pattern synonym, which+is fine. We could do more, but it doesn't seem worth it.++Note [SigSkol SkolemInfo]+~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we (deeply) skolemise a type+ f :: forall a. a -> forall b. b -> a+Then we'll instantiate [a :-> a', b :-> b'], and with the instantiated+ a' -> b' -> a.+But when, in an error message, we report that "b is a rigid type+variable bound by the type signature for f", we want to show the foralls+in the right place. So we proceed as follows:++* In SigSkol we record+ - the original signature forall a. a -> forall b. b -> a+ - the instantiation mapping [a :-> a', b :-> b']++* Then when tidying in TcMType.tidySkolemInfo, we first tidy a' to+ whatever it tidies to, say a''; and then we walk over the type+ replacing the binder a by the tidied version a'', to give+ forall a''. a'' -> forall b''. b'' -> a''+ We need to do this under function arrows, to match what deeplySkolemise+ does.++* Typically a'' will have a nice pretty name like "a", but the point is+ that the foral-bound variables of the signature we report line up with+ the instantiated skolems lying around in other types.+++************************************************************************+* *+ CtOrigin+* *+************************************************************************+-}++data CtOrigin+ = GivenOrigin SkolemInfo++ -- All the others are for *wanted* constraints+ | OccurrenceOf Name -- Occurrence of an overloaded identifier+ | OccurrenceOfRecSel RdrName -- Occurrence of a record selector+ | AppOrigin -- An application of some kind++ | SpecPragOrigin UserTypeCtxt -- Specialisation pragma for+ -- function or instance++ | TypeEqOrigin { uo_actual :: TcType+ , uo_expected :: TcType+ , uo_thing :: Maybe ErrorThing+ -- ^ The thing that has type "actual"+ }++ | KindEqOrigin+ TcType (Maybe TcType) -- A kind equality arising from unifying these two types+ CtOrigin -- originally arising from this+ (Maybe TypeOrKind) -- the level of the eq this arises from++ | IPOccOrigin HsIPName -- Occurrence of an implicit parameter+ | OverLabelOrigin FastString -- Occurrence of an overloaded label++ | LiteralOrigin (HsOverLit Name) -- Occurrence of a literal+ | NegateOrigin -- Occurrence of syntactic negation++ | ArithSeqOrigin (ArithSeqInfo Name) -- [x..], [x..y] etc+ | PArrSeqOrigin (ArithSeqInfo Name) -- [:x..y:] and [:x,y..z:]+ | SectionOrigin+ | TupleOrigin -- (..,..)+ | ExprSigOrigin -- e :: ty+ | PatSigOrigin -- p :: ty+ | PatOrigin -- Instantiating a polytyped pattern at a constructor+ | ProvCtxtOrigin -- The "provided" context of a pattern synonym signature+ (PatSynBind Name Name) -- Information about the pattern synonym, in particular+ -- the name and the right-hand side+ | RecordUpdOrigin+ | ViewPatOrigin++ | ScOrigin TypeSize -- Typechecking superclasses of an instance declaration+ -- If the instance head is C ty1 .. tyn+ -- then TypeSize = sizeTypes [ty1, .., tyn]+ -- See Note [Solving superclass constraints] in TcInstDcls++ | DerivOrigin -- Typechecking deriving+ | DerivOriginDC DataCon Int+ -- Checking constraints arising from this data con and field index+ | DerivOriginCoerce Id Type Type+ -- DerivOriginCoerce id ty1 ty2: Trying to coerce class method `id` from+ -- `ty1` to `ty2`.+ | StandAloneDerivOrigin -- Typechecking stand-alone deriving+ | DefaultOrigin -- Typechecking a default decl+ | DoOrigin -- Arising from a do expression+ | DoPatOrigin (LPat Name) -- Arising from a failable pattern in+ -- a do expression+ | MCompOrigin -- Arising from a monad comprehension+ | MCompPatOrigin (LPat Name) -- Arising from a failable pattern in a+ -- monad comprehension+ | IfOrigin -- Arising from an if statement+ | ProcOrigin -- Arising from a proc expression+ | AnnOrigin -- An annotation++ | FunDepOrigin1 -- A functional dependency from combining+ PredType CtLoc -- This constraint arising from ...+ PredType CtLoc -- and this constraint arising from ...++ | FunDepOrigin2 -- A functional dependency from combining+ PredType CtOrigin -- This constraint arising from ...+ PredType SrcSpan -- and this top-level instance+ -- We only need a CtOrigin on the first, because the location+ -- is pinned on the entire error message++ | HoleOrigin+ | UnboundOccurrenceOf OccName+ | ListOrigin -- An overloaded list+ | StaticOrigin -- A static form+ | FailablePattern (LPat TcId) -- A failable pattern in do-notation for the+ -- MonadFail Proposal (MFP). Obsolete when+ -- actual desugaring to MonadFail.fail is live.+ | Shouldn'tHappenOrigin String+ -- the user should never see this one,+ -- unless ImpredicativeTypes is on, where all+ -- bets are off+ | InstProvidedOrigin Module ClsInst+ -- Skolem variable arose when we were testing if an instance+ -- is solvable or not.++-- | A thing that can be stored for error message generation only.+-- It is stored with a function to zonk and tidy the thing.+data ErrorThing+ = forall a. Outputable a => ErrorThing a+ (Maybe Arity) -- # of args, if known+ (TidyEnv -> a -> TcM (TidyEnv, a))++-- | Flag to see whether we're type-checking terms or kind-checking types+data TypeOrKind = TypeLevel | KindLevel+ deriving Eq++instance Outputable TypeOrKind where+ ppr TypeLevel = text "TypeLevel"+ ppr KindLevel = text "KindLevel"++isTypeLevel :: TypeOrKind -> Bool+isTypeLevel TypeLevel = True+isTypeLevel KindLevel = False++isKindLevel :: TypeOrKind -> Bool+isKindLevel TypeLevel = False+isKindLevel KindLevel = True++-- | Make an 'ErrorThing' that doesn't need tidying or zonking+mkErrorThing :: Outputable a => a -> ErrorThing+mkErrorThing thing = ErrorThing thing Nothing (\env x -> return (env, x))++-- | Retrieve the # of arguments in the error thing, if known+errorThingNumArgs_maybe :: ErrorThing -> Maybe Arity+errorThingNumArgs_maybe (ErrorThing _ args _) = args++instance Outputable CtOrigin where+ ppr = pprCtOrigin++instance Outputable ErrorThing where+ ppr (ErrorThing thing _ _) = ppr thing++ctoHerald :: SDoc+ctoHerald = text "arising from"++-- | Extract a suitable CtOrigin from a HsExpr+lexprCtOrigin :: LHsExpr Name -> CtOrigin+lexprCtOrigin (L _ e) = exprCtOrigin e++exprCtOrigin :: HsExpr Name -> CtOrigin+exprCtOrigin (HsVar (L _ name)) = OccurrenceOf name+exprCtOrigin (HsUnboundVar uv) = UnboundOccurrenceOf (unboundVarOcc uv)+exprCtOrigin (HsConLikeOut {}) = panic "exprCtOrigin HsConLikeOut"+exprCtOrigin (HsRecFld f) = OccurrenceOfRecSel (rdrNameAmbiguousFieldOcc f)+exprCtOrigin (HsOverLabel _ l) = OverLabelOrigin l+exprCtOrigin (HsIPVar ip) = IPOccOrigin ip+exprCtOrigin (HsOverLit lit) = LiteralOrigin lit+exprCtOrigin (HsLit {}) = Shouldn'tHappenOrigin "concrete literal"+exprCtOrigin (HsLam matches) = matchesCtOrigin matches+exprCtOrigin (HsLamCase ms) = matchesCtOrigin ms+exprCtOrigin (HsApp e1 _) = lexprCtOrigin e1+exprCtOrigin (HsAppType e1 _) = lexprCtOrigin e1+exprCtOrigin (HsAppTypeOut {}) = panic "exprCtOrigin HsAppTypeOut"+exprCtOrigin (OpApp _ op _ _) = lexprCtOrigin op+exprCtOrigin (NegApp e _) = lexprCtOrigin e+exprCtOrigin (HsPar e) = lexprCtOrigin e+exprCtOrigin (SectionL _ _) = SectionOrigin+exprCtOrigin (SectionR _ _) = SectionOrigin+exprCtOrigin (ExplicitTuple {}) = Shouldn'tHappenOrigin "explicit tuple"+exprCtOrigin ExplicitSum{} = Shouldn'tHappenOrigin "explicit sum"+exprCtOrigin (HsCase _ matches) = matchesCtOrigin matches+exprCtOrigin (HsIf (Just syn) _ _ _) = exprCtOrigin (syn_expr syn)+exprCtOrigin (HsIf {}) = Shouldn'tHappenOrigin "if expression"+exprCtOrigin (HsMultiIf _ rhs) = lGRHSCtOrigin rhs+exprCtOrigin (HsLet _ e) = lexprCtOrigin e+exprCtOrigin (HsDo _ _ _) = DoOrigin+exprCtOrigin (ExplicitList {}) = Shouldn'tHappenOrigin "list"+exprCtOrigin (ExplicitPArr {}) = Shouldn'tHappenOrigin "parallel array"+exprCtOrigin (RecordCon {}) = Shouldn'tHappenOrigin "record construction"+exprCtOrigin (RecordUpd {}) = Shouldn'tHappenOrigin "record update"+exprCtOrigin (ExprWithTySig {}) = ExprSigOrigin+exprCtOrigin (ExprWithTySigOut {}) = panic "exprCtOrigin ExprWithTySigOut"+exprCtOrigin (ArithSeq {}) = Shouldn'tHappenOrigin "arithmetic sequence"+exprCtOrigin (PArrSeq {}) = Shouldn'tHappenOrigin "parallel array sequence"+exprCtOrigin (HsSCC _ _ e) = lexprCtOrigin e+exprCtOrigin (HsCoreAnn _ _ e) = lexprCtOrigin e+exprCtOrigin (HsBracket {}) = Shouldn'tHappenOrigin "TH bracket"+exprCtOrigin (HsRnBracketOut {})= Shouldn'tHappenOrigin "HsRnBracketOut"+exprCtOrigin (HsTcBracketOut {})= panic "exprCtOrigin HsTcBracketOut"+exprCtOrigin (HsSpliceE {}) = Shouldn'tHappenOrigin "TH splice"+exprCtOrigin (HsProc {}) = Shouldn'tHappenOrigin "proc"+exprCtOrigin (HsStatic {}) = Shouldn'tHappenOrigin "static expression"+exprCtOrigin (HsArrApp {}) = panic "exprCtOrigin HsArrApp"+exprCtOrigin (HsArrForm {}) = panic "exprCtOrigin HsArrForm"+exprCtOrigin (HsTick _ e) = lexprCtOrigin e+exprCtOrigin (HsBinTick _ _ e) = lexprCtOrigin e+exprCtOrigin (HsTickPragma _ _ _ e) = lexprCtOrigin e+exprCtOrigin EWildPat = panic "exprCtOrigin EWildPat"+exprCtOrigin (EAsPat {}) = panic "exprCtOrigin EAsPat"+exprCtOrigin (EViewPat {}) = panic "exprCtOrigin EViewPat"+exprCtOrigin (ELazyPat {}) = panic "exprCtOrigin ELazyPat"+exprCtOrigin (HsWrap {}) = panic "exprCtOrigin HsWrap"++-- | Extract a suitable CtOrigin from a MatchGroup+matchesCtOrigin :: MatchGroup Name (LHsExpr Name) -> CtOrigin+matchesCtOrigin (MG { mg_alts = alts })+ | L _ [L _ match] <- alts+ , Match { m_grhss = grhss } <- match+ = grhssCtOrigin grhss++ | otherwise+ = Shouldn'tHappenOrigin "multi-way match"++-- | Extract a suitable CtOrigin from guarded RHSs+grhssCtOrigin :: GRHSs Name (LHsExpr Name) -> CtOrigin+grhssCtOrigin (GRHSs { grhssGRHSs = lgrhss }) = lGRHSCtOrigin lgrhss++-- | Extract a suitable CtOrigin from a list of guarded RHSs+lGRHSCtOrigin :: [LGRHS Name (LHsExpr Name)] -> CtOrigin+lGRHSCtOrigin [L _ (GRHS _ (L _ e))] = exprCtOrigin e+lGRHSCtOrigin _ = Shouldn'tHappenOrigin "multi-way GRHS"++pprCtLoc :: CtLoc -> SDoc+-- "arising from ... at ..."+-- Not an instance of Outputable because of the "arising from" prefix+pprCtLoc (CtLoc { ctl_origin = o, ctl_env = lcl})+ = sep [ pprCtOrigin o+ , text "at" <+> ppr (tcl_loc lcl)]++pprCtOrigin :: CtOrigin -> SDoc+-- "arising from ..."+-- Not an instance of Outputable because of the "arising from" prefix+pprCtOrigin (GivenOrigin sk) = ctoHerald <+> ppr sk++pprCtOrigin (SpecPragOrigin ctxt)+ = case ctxt of+ FunSigCtxt n _ -> text "a SPECIALISE pragma for" <+> quotes (ppr n)+ SpecInstCtxt -> text "a SPECIALISE INSTANCE pragma"+ _ -> text "a SPECIALISE pragma" -- Never happens I think++pprCtOrigin (FunDepOrigin1 pred1 loc1 pred2 loc2)+ = hang (ctoHerald <+> text "a functional dependency between constraints:")+ 2 (vcat [ hang (quotes (ppr pred1)) 2 (pprCtLoc loc1)+ , hang (quotes (ppr pred2)) 2 (pprCtLoc loc2) ])++pprCtOrigin (FunDepOrigin2 pred1 orig1 pred2 loc2)+ = hang (ctoHerald <+> text "a functional dependency between:")+ 2 (vcat [ hang (text "constraint" <+> quotes (ppr pred1))+ 2 (pprCtOrigin orig1 )+ , hang (text "instance" <+> quotes (ppr pred2))+ 2 (text "at" <+> ppr loc2) ])++pprCtOrigin (KindEqOrigin t1 (Just t2) _ _)+ = hang (ctoHerald <+> text "a kind equality arising from")+ 2 (sep [ppr t1, char '~', ppr t2])++pprCtOrigin (KindEqOrigin t1 Nothing _ _)+ = hang (ctoHerald <+> text "a kind equality when matching")+ 2 (ppr t1)++pprCtOrigin (UnboundOccurrenceOf name)+ = ctoHerald <+> text "an undeclared identifier" <+> quotes (ppr name)++pprCtOrigin (DerivOriginDC dc n)+ = hang (ctoHerald <+> text "the" <+> speakNth n+ <+> text "field of" <+> quotes (ppr dc))+ 2 (parens (text "type" <+> quotes (ppr ty)))+ where+ ty = dataConOrigArgTys dc !! (n-1)++pprCtOrigin (DerivOriginCoerce meth ty1 ty2)+ = hang (ctoHerald <+> text "the coercion of the method" <+> quotes (ppr meth))+ 2 (sep [ text "from type" <+> quotes (ppr ty1)+ , nest 2 $ text "to type" <+> quotes (ppr ty2) ])++pprCtOrigin (DoPatOrigin pat)+ = ctoHerald <+> text "a do statement"+ $$+ text "with the failable pattern" <+> quotes (ppr pat)++pprCtOrigin (MCompPatOrigin pat)+ = ctoHerald <+> hsep [ text "the failable pattern"+ , quotes (ppr pat)+ , text "in a statement in a monad comprehension" ]+pprCtOrigin (FailablePattern pat)+ = ctoHerald <+> text "the failable pattern" <+> quotes (ppr pat)+ $$+ text "(this will become an error in a future GHC release)"++pprCtOrigin (Shouldn'tHappenOrigin note)+ = sdocWithDynFlags $ \dflags ->+ if xopt LangExt.ImpredicativeTypes dflags+ then text "a situation created by impredicative types"+ else+ vcat [ text "<< This should not appear in error messages. If you see this"+ , text "in an error message, please report a bug mentioning" <+> quotes (text note) <+> text "at"+ , text "https://ghc.haskell.org/trac/ghc/wiki/ReportABug >>" ]++pprCtOrigin (ProvCtxtOrigin PSB{ psb_id = (L _ name) })+ = hang (ctoHerald <+> text "the \"provided\" constraints claimed by")+ 2 (text "the signature of" <+> quotes (ppr name))++pprCtOrigin (InstProvidedOrigin mod cls_inst)+ = vcat [ text "arising when attempting to show that"+ , ppr cls_inst+ , text "is provided by" <+> quotes (ppr mod)]++pprCtOrigin simple_origin+ = ctoHerald <+> pprCtO simple_origin++-- | Short one-liners+pprCtO :: CtOrigin -> SDoc+pprCtO (OccurrenceOf name) = hsep [text "a use of", quotes (ppr name)]+pprCtO (OccurrenceOfRecSel name) = hsep [text "a use of", quotes (ppr name)]+pprCtO AppOrigin = text "an application"+pprCtO (IPOccOrigin name) = hsep [text "a use of implicit parameter", quotes (ppr name)]+pprCtO (OverLabelOrigin l) = hsep [text "the overloaded label"+ ,quotes (char '#' <> ppr l)]+pprCtO RecordUpdOrigin = text "a record update"+pprCtO ExprSigOrigin = text "an expression type signature"+pprCtO PatSigOrigin = text "a pattern type signature"+pprCtO PatOrigin = text "a pattern"+pprCtO ViewPatOrigin = text "a view pattern"+pprCtO IfOrigin = text "an if expression"+pprCtO (LiteralOrigin lit) = hsep [text "the literal", quotes (ppr lit)]+pprCtO (ArithSeqOrigin seq) = hsep [text "the arithmetic sequence", quotes (ppr seq)]+pprCtO (PArrSeqOrigin seq) = hsep [text "the parallel array sequence", quotes (ppr seq)]+pprCtO SectionOrigin = text "an operator section"+pprCtO TupleOrigin = text "a tuple"+pprCtO NegateOrigin = text "a use of syntactic negation"+pprCtO (ScOrigin n) = text "the superclasses of an instance declaration"+ <> ifPprDebug (parens (ppr n))+pprCtO DerivOrigin = text "the 'deriving' clause of a data type declaration"+pprCtO StandAloneDerivOrigin = text "a 'deriving' declaration"+pprCtO DefaultOrigin = text "a 'default' declaration"+pprCtO DoOrigin = text "a do statement"+pprCtO MCompOrigin = text "a statement in a monad comprehension"+pprCtO ProcOrigin = text "a proc expression"+pprCtO (TypeEqOrigin t1 t2 _)= text "a type equality" <+> sep [ppr t1, char '~', ppr t2]+pprCtO AnnOrigin = text "an annotation"+pprCtO HoleOrigin = text "a use of" <+> quotes (text "_")+pprCtO ListOrigin = text "an overloaded list"+pprCtO StaticOrigin = text "a static form"+pprCtO _ = panic "pprCtOrigin"++{-+Constraint Solver Plugins+-------------------------+-}++type TcPluginSolver = [Ct] -- given+ -> [Ct] -- derived+ -> [Ct] -- wanted+ -> TcPluginM TcPluginResult++newtype TcPluginM a = TcPluginM (EvBindsVar -> TcM a)++instance Functor TcPluginM where+ fmap = liftM++instance Applicative TcPluginM where+ pure x = TcPluginM (const $ pure x)+ (<*>) = ap++instance Monad TcPluginM where+ fail x = TcPluginM (const $ fail x)+ TcPluginM m >>= k =+ TcPluginM (\ ev -> do a <- m ev+ runTcPluginM (k a) ev)++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail TcPluginM where+ fail x = TcPluginM (const $ fail x)+#endif++runTcPluginM :: TcPluginM a -> EvBindsVar -> TcM a+runTcPluginM (TcPluginM m) = m++-- | This function provides an escape for direct access to+-- the 'TcM` monad. It should not be used lightly, and+-- the provided 'TcPluginM' API should be favoured instead.+unsafeTcPluginTcM :: TcM a -> TcPluginM a+unsafeTcPluginTcM = TcPluginM . const++-- | Access the 'EvBindsVar' carried by the 'TcPluginM' during+-- constraint solving. Returns 'Nothing' if invoked during+-- 'tcPluginInit' or 'tcPluginStop'.+getEvBindsTcPluginM :: TcPluginM EvBindsVar+getEvBindsTcPluginM = TcPluginM return+++data TcPlugin = forall s. TcPlugin+ { tcPluginInit :: TcPluginM s+ -- ^ Initialize plugin, when entering type-checker.++ , tcPluginSolve :: s -> TcPluginSolver+ -- ^ Solve some constraints.+ -- TODO: WRITE MORE DETAILS ON HOW THIS WORKS.++ , tcPluginStop :: s -> TcPluginM ()+ -- ^ Clean up after the plugin, when exiting the type-checker.+ }++data TcPluginResult+ = TcPluginContradiction [Ct]+ -- ^ The plugin found a contradiction.+ -- The returned constraints are removed from the inert set,+ -- and recorded as insoluble.++ | TcPluginOk [(EvTerm,Ct)] [Ct]+ -- ^ The first field is for constraints that were solved.+ -- These are removed from the inert set,+ -- and the evidence for them is recorded.+ -- The second field contains new work, that should be processed by+ -- the constraint solver.
+ typecheck/TcRules.hs view
@@ -0,0 +1,365 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1993-1998+++TcRules: Typechecking transformation rules+-}++{-# LANGUAGE ViewPatterns #-}++module TcRules ( tcRules ) where++import HsSyn+import TcRnMonad+import TcSimplify+import TcMType+import TcType+import TcHsType+import TcExpr+import TcEnv+import TcUnify( buildImplicationFor )+import TcEvidence( mkTcCoVarCo )+import Type+import Id+import Var( EvVar )+import Name+import BasicTypes ( RuleName )+import SrcLoc+import Outputable+import FastString+import Bag+import Data.List( partition )++{-+Note [Typechecking rules]+~~~~~~~~~~~~~~~~~~~~~~~~~+We *infer* the typ of the LHS, and use that type to *check* the type of+the RHS. That means that higher-rank rules work reasonably well. Here's+an example (test simplCore/should_compile/rule2.hs) produced by Roman:++ foo :: (forall m. m a -> m b) -> m a -> m b+ foo f = ...++ bar :: (forall m. m a -> m a) -> m a -> m a+ bar f = ...++ {-# RULES "foo/bar" foo = bar #-}++He wanted the rule to typecheck.+-}++tcRules :: [LRuleDecls Name] -> TcM [LRuleDecls TcId]+tcRules decls = mapM (wrapLocM tcRuleDecls) decls++tcRuleDecls :: RuleDecls Name -> TcM (RuleDecls TcId)+tcRuleDecls (HsRules src decls)+ = do { tc_decls <- mapM (wrapLocM tcRule) decls+ ; return (HsRules src tc_decls) }++tcRule :: RuleDecl Name -> TcM (RuleDecl TcId)+tcRule (HsRule name act hs_bndrs lhs fv_lhs rhs fv_rhs)+ = addErrCtxt (ruleCtxt $ snd $ unLoc name) $+ do { traceTc "---- Rule ------" (pprFullRuleName name)++ -- Note [Typechecking rules]+ ; (vars, bndr_wanted) <- captureConstraints $+ tcRuleBndrs hs_bndrs+ -- bndr_wanted constraints can include wildcard hole+ -- constraints, which we should not forget about.+ -- It may mention the skolem type variables bound by+ -- the RULE. c.f. Trac #10072++ ; let (id_bndrs, tv_bndrs) = partition isId vars+ ; (lhs', lhs_wanted, rhs', rhs_wanted, rule_ty)+ <- tcExtendTyVarEnv tv_bndrs $+ tcExtendIdEnv id_bndrs $+ do { -- See Note [Solve order for RULES]+ ((lhs', rule_ty), lhs_wanted) <- captureConstraints (tcInferRho lhs)+ ; (rhs', rhs_wanted) <- captureConstraints $+ tcMonoExpr rhs (mkCheckExpType rule_ty)+ ; return (lhs', lhs_wanted, rhs', rhs_wanted, rule_ty) }++ ; traceTc "tcRule 1" (vcat [ pprFullRuleName name+ , ppr lhs_wanted+ , ppr rhs_wanted ])+ ; let all_lhs_wanted = bndr_wanted `andWC` lhs_wanted+ ; (lhs_evs, residual_lhs_wanted) <- simplifyRule (snd $ unLoc name)+ all_lhs_wanted+ rhs_wanted++ -- SimplfyRule Plan, step 4+ -- Now figure out what to quantify over+ -- c.f. TcSimplify.simplifyInfer+ -- We quantify over any tyvars free in *either* the rule+ -- *or* the bound variables. The latter is important. Consider+ -- ss (x,(y,z)) = (x,z)+ -- RULE: forall v. fst (ss v) = fst v+ -- The type of the rhs of the rule is just a, but v::(a,(b,c))+ --+ -- We also need to get the completely-uconstrained tyvars of+ -- the LHS, lest they otherwise get defaulted to Any; but we do that+ -- during zonking (see TcHsSyn.zonkRule)++ ; let tpl_ids = lhs_evs ++ id_bndrs+ ; forall_tkvs <- zonkTcTypesAndSplitDepVars $+ rule_ty : map idType tpl_ids+ ; gbls <- tcGetGlobalTyCoVars -- Even though top level, there might be top-level+ -- monomorphic bindings from the MR; test tc111+ ; qtkvs <- quantifyZonkedTyVars gbls forall_tkvs+ ; traceTc "tcRule" (vcat [ pprFullRuleName name+ , ppr forall_tkvs+ , ppr qtkvs+ , ppr rule_ty+ , vcat [ ppr id <+> dcolon <+> ppr (idType id) | id <- tpl_ids ]+ ])++ -- SimplfyRule Plan, step 5+ -- Simplify the LHS and RHS constraints:+ -- For the LHS constraints we must solve the remaining constraints+ -- (a) so that we report insoluble ones+ -- (b) so that we bind any soluble ones+ ; let skol_info = RuleSkol (snd (unLoc name))+ ; (lhs_implic, lhs_binds) <- buildImplicationFor topTcLevel skol_info qtkvs+ lhs_evs residual_lhs_wanted+ ; (rhs_implic, rhs_binds) <- buildImplicationFor topTcLevel skol_info qtkvs+ lhs_evs rhs_wanted++ ; emitImplications (lhs_implic `unionBags` rhs_implic)+ ; return (HsRule name act+ (map (noLoc . RuleBndr . noLoc) (qtkvs ++ tpl_ids))+ (mkHsDictLet lhs_binds lhs') fv_lhs+ (mkHsDictLet rhs_binds rhs') fv_rhs) }++tcRuleBndrs :: [LRuleBndr Name] -> TcM [Var]+tcRuleBndrs []+ = return []+tcRuleBndrs (L _ (RuleBndr (L _ name)) : rule_bndrs)+ = do { ty <- newOpenFlexiTyVarTy+ ; vars <- tcRuleBndrs rule_bndrs+ ; return (mkLocalId name ty : vars) }+tcRuleBndrs (L _ (RuleBndrSig (L _ name) rn_ty) : rule_bndrs)+-- e.g x :: a->a+-- The tyvar 'a' is brought into scope first, just as if you'd written+-- a::*, x :: a->a+ = do { let ctxt = RuleSigCtxt name+ ; (_ , tvs, id_ty) <- tcHsPatSigType ctxt rn_ty+ ; let id = mkLocalIdOrCoVar name id_ty+ -- See Note [Pattern signature binders] in TcHsType++ -- The type variables scope over subsequent bindings; yuk+ ; vars <- tcExtendTyVarEnv2 tvs $+ tcRuleBndrs rule_bndrs+ ; return (map snd tvs ++ id : vars) }++ruleCtxt :: FastString -> SDoc+ruleCtxt name = text "When checking the transformation rule" <+>+ doubleQuotes (ftext name)+++{-+*********************************************************************************+* *+ Constraint simplification for rules+* *+***********************************************************************************++Note [The SimplifyRule Plan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Example. Consider the following left-hand side of a rule+ f (x == y) (y > z) = ...+If we typecheck this expression we get constraints+ d1 :: Ord a, d2 :: Eq a+We do NOT want to "simplify" to the LHS+ forall x::a, y::a, z::a, d1::Ord a.+ f ((==) (eqFromOrd d1) x y) ((>) d1 y z) = ...+Instead we want+ forall x::a, y::a, z::a, d1::Ord a, d2::Eq a.+ f ((==) d2 x y) ((>) d1 y z) = ...++Here is another example:+ fromIntegral :: (Integral a, Num b) => a -> b+ {-# RULES "foo" fromIntegral = id :: Int -> Int #-}+In the rule, a=b=Int, and Num Int is a superclass of Integral Int. But+we *dont* want to get+ forall dIntegralInt.+ fromIntegral Int Int dIntegralInt (scsel dIntegralInt) = id Int+because the scsel will mess up RULE matching. Instead we want+ forall dIntegralInt, dNumInt.+ fromIntegral Int Int dIntegralInt dNumInt = id Int++Even if we have+ g (x == y) (y == z) = ..+where the two dictionaries are *identical*, we do NOT WANT+ forall x::a, y::a, z::a, d1::Eq a+ f ((==) d1 x y) ((>) d1 y z) = ...+because that will only match if the dict args are (visibly) equal.+Instead we want to quantify over the dictionaries separately.++In short, simplifyRuleLhs must *only* squash equalities, leaving+all dicts unchanged, with absolutely no sharing.++Also note that we can't solve the LHS constraints in isolation:+Example foo :: Ord a => a -> a+ foo_spec :: Int -> Int+ {-# RULE "foo" foo = foo_spec #-}+Here, it's the RHS that fixes the type variable++HOWEVER, under a nested implication things are different+Consider+ f :: (forall a. Eq a => a->a) -> Bool -> ...+ {-# RULES "foo" forall (v::forall b. Eq b => b->b).+ f b True = ...+ #-}+Here we *must* solve the wanted (Eq a) from the given (Eq a)+resulting from skolemising the argument type of g. So we+revert to SimplCheck when going under an implication.+++--------- So the SimplifyRule Plan is this -----------------------++* Step 0: typecheck the LHS and RHS to get constraints from each++* Step 1: Simplify the LHS and RHS constraints all together in one bag+ We do this to discover all unification equalities++* Step 2: Zonk the ORIGINAL (unsimplified) LHS constraints, to take+ advantage of those unifications++* Setp 3: Partition the LHS constraints into the ones we will+ quantify over, and the others.+ See Note [RULE quantification over equalities]++* Step 4: Decide on the type variables to quantify over++* Step 5: Simplify the LHS and RHS constraints separately, using the+ quantified constraints as givens++Note [Solve order for RULES]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In step 1 above, we need to be a bit careful about solve order.+Consider+ f :: Int -> T Int+ type instance T Int = Bool++ RULE f 3 = True++From the RULE we get+ lhs-constraints: T Int ~ alpha+ rhs-constraints: Bool ~ alpha+where 'alpha' is the type that connects the two. If we glom them+all together, and solve the RHS constraint first, we might solve+with alpha := Bool. But then we'd end up with a RULE like++ RULE: f 3 |> (co :: T Int ~ Booo) = True++which is terrible. We want++ RULE: f 3 = True |> (sym co :: Bool ~ T Int)++So we are careful to solve the LHS constraints first, and *then* the+RHS constraints. Actually much of this is done by the on-the-fly+constraint solving, so the same order must be observed in+tcRule.+++Note [RULE quantification over equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Deciding which equalities to quantify over is tricky:+ * We do not want to quantify over insoluble equalities (Int ~ Bool)+ (a) because we prefer to report a LHS type error+ (b) because if such things end up in 'givens' we get a bogus+ "inaccessible code" error++ * But we do want to quantify over things like (a ~ F b), where+ F is a type function.++The difficulty is that it's hard to tell what is insoluble!+So we see whether the simplification step yielded any type errors,+and if so refrain from quantifying over *any* equalities.++Note [Quantifying over coercion holes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Equality constraints from the LHS will emit coercion hole Wanteds.+These don't have a name, so we can't quantify over them directly.+Instead, because we really do want to quantify here, invent a new+EvVar for the coercion, fill the hole with the invented EvVar, and+then quantify over the EvVar. Not too tricky -- just some+impedance matching, really.++Note [Simplify cloned constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+At this stage, we're simplifying constraints only for insolubility+and for unification. Note that all the evidence is quickly discarded.+We use a clone of the real constraint. If we don't do this,+then RHS coercion-hole constraints get filled in, only to get filled+in *again* when solving the implications emitted from tcRule. That's+terrible, so we avoid the problem by cloning the constraints.++-}++simplifyRule :: RuleName+ -> WantedConstraints -- Constraints from LHS+ -> WantedConstraints -- Constraints from RHS+ -> TcM ( [EvVar] -- Quantify over these LHS vars+ , WantedConstraints) -- Residual un-quantified LHS constraints+-- See Note [The SimplifyRule Plan]+-- NB: This consumes all simple constraints on the LHS, but not+-- any LHS implication constraints.+simplifyRule name lhs_wanted rhs_wanted+ = do { -- We allow ourselves to unify environment+ -- variables: runTcS runs with topTcLevel+ ; lhs_clone <- cloneWC lhs_wanted+ ; rhs_clone <- cloneWC rhs_wanted++ -- Note [The SimplifyRule Plan] step 1+ -- First solve the LHS and *then* solve the RHS+ -- Crucially, this performs unifications+ -- See Note [Solve order for RULES]+ -- See Note [Simplify cloned constraints]+ ; insoluble <- runTcSDeriveds $+ do { lhs_resid <- solveWanteds lhs_clone+ ; rhs_resid <- solveWanteds rhs_clone+ ; return ( insolubleWC lhs_resid ||+ insolubleWC rhs_resid ) }++ -- Note [The SimplifyRule Plan] step 2+ ; zonked_lhs_simples <- zonkSimples (wc_simple lhs_wanted)++ -- Note [The SimplifyRule Plan] step 3+ ; let (quant_cts, no_quant_cts) = partitionBag (quantify_ct insoluble)+ zonked_lhs_simples++ ; quant_evs <- mapM mk_quant_ev (bagToList quant_cts)++ ; traceTc "simplifyRule" $+ vcat [ text "LHS of rule" <+> doubleQuotes (ftext name)+ , text "lhs_wanted" <+> ppr lhs_wanted+ , text "rhs_wanted" <+> ppr rhs_wanted+ , text "zonked_lhs_simples" <+> ppr zonked_lhs_simples+ , text "quant_cts" <+> ppr quant_cts+ , text "no_quant_cts" <+> ppr no_quant_cts+ ]++ ; return (quant_evs, lhs_wanted { wc_simple = no_quant_cts }) }++ where+ quantify_ct :: Bool -> Ct -> Bool+ quantify_ct insol ct+ | EqPred _ t1 t2 <- classifyPredType (ctPred ct)+ = not (insol || t1 `tcEqType` t2)+ -- Note [RULE quantification over equalities]++ | otherwise+ = True++ mk_quant_ev :: Ct -> TcM EvVar+ mk_quant_ev ct+ | CtWanted { ctev_dest = dest, ctev_pred = pred } <- ctEvidence ct+ = case dest of+ EvVarDest ev_id -> return ev_id+ HoleDest hole -> -- See Note [Quantifying over coercion holes]+ do { ev_id <- newEvVar pred+ ; fillCoercionHole hole (mkTcCoVarCo ev_id)+ ; return ev_id }+ mk_quant_ev ct = pprPanic "mk_quant_ev" (ppr ct)
+ typecheck/TcSMonad.hs view
@@ -0,0 +1,3122 @@+{-# LANGUAGE CPP, TypeFamilies #-}++-- Type definitions for the constraint solver+module TcSMonad (++ -- The work list+ WorkList(..), isEmptyWorkList, emptyWorkList,+ extendWorkListNonEq, extendWorkListCt, extendWorkListDerived,+ extendWorkListCts, extendWorkListEq, extendWorkListFunEq,+ appendWorkList, extendWorkListImplic,+ selectNextWorkItem,+ workListSize, workListWantedCount,+ getWorkList, updWorkListTcS,++ -- The TcS monad+ TcS, runTcS, runTcSDeriveds, runTcSWithEvBinds,+ failTcS, warnTcS, addErrTcS,+ runTcSEqualities,+ nestTcS, nestImplicTcS, setEvBindsTcS, buildImplication,++ runTcPluginTcS, addUsedGRE, addUsedGREs,++ -- Tracing etc+ panicTcS, traceTcS,+ traceFireTcS, bumpStepCountTcS, csTraceTcS,+ wrapErrTcS, wrapWarnTcS,++ -- Evidence creation and transformation+ MaybeNew(..), freshGoals, isFresh, getEvTerm,++ newTcEvBinds,+ newWantedEq, emitNewWantedEq,+ newWanted, newWantedEvVar, newWantedNC, newWantedEvVarNC, newDerivedNC,+ newBoundEvVarId,+ unifyTyVar, unflattenFmv, reportUnifications,+ setEvBind, setWantedEq, setEqIfWanted,+ setWantedEvTerm, setWantedEvBind, setEvBindIfWanted,+ newEvVar, newGivenEvVar, newGivenEvVars,+ emitNewDerived, emitNewDeriveds, emitNewDerivedEq,+ checkReductionDepth,++ getInstEnvs, getFamInstEnvs, -- Getting the environments+ getTopEnv, getGblEnv, getLclEnv,+ getTcEvBindsVar, getTcLevel,+ getTcEvBindsAndTCVs, getTcEvBindsMap,+ tcLookupClass,+ tcLookupId,++ -- Inerts+ InertSet(..), InertCans(..),+ updInertTcS, updInertCans, updInertDicts, updInertIrreds,+ getNoGivenEqs, setInertCans,+ getInertEqs, getInertCans, getInertGivens,+ getInertInsols,+ emptyInert, getTcSInerts, setTcSInerts,+ matchableGivens, prohibitedSuperClassSolve,+ getUnsolvedInerts,+ removeInertCts, getPendingScDicts,+ addInertCan, addInertEq, insertFunEq,+ emitInsoluble, emitWorkNC, emitWork,+ isImprovable,++ -- The Model+ kickOutAfterUnification,++ -- Inert Safe Haskell safe-overlap failures+ addInertSafehask, insertSafeOverlapFailureTcS, updInertSafehask,+ getSafeOverlapFailures,++ -- Inert CDictCans+ DictMap, emptyDictMap, lookupInertDict, findDictsByClass, addDict,+ addDictsByClass, delDict, foldDicts, filterDicts, findDict,++ -- Inert CTyEqCans+ EqualCtList, findTyEqs, foldTyEqs, isInInertEqs,+ lookupFlattenTyVar, lookupInertTyVar,++ -- Inert solved dictionaries+ addSolvedDict, lookupSolvedDict,++ -- Irreds+ foldIrreds,++ -- The flattening cache+ lookupFlatCache, extendFlatCache, newFlattenSkolem, -- Flatten skolems++ -- Inert CFunEqCans+ updInertFunEqs, findFunEq,+ findFunEqsByTyCon,++ instDFunType, -- Instantiation++ -- MetaTyVars+ newFlexiTcSTy, instFlexi, instFlexiX,+ cloneMetaTyVar, demoteUnfilledFmv,+ tcInstType, tcInstSkolTyVarsX,++ TcLevel, isTouchableMetaTyVarTcS,+ isFilledMetaTyVar_maybe, isFilledMetaTyVar,+ zonkTyCoVarsAndFV, zonkTcType, zonkTcTypes, zonkTcTyVar, zonkCo,+ zonkTyCoVarsAndFVList,+ zonkSimples, zonkWC,++ -- References+ newTcRef, readTcRef, updTcRef,++ -- Misc+ getDefaultInfo, getDynFlags, getGlobalRdrEnvTcS,+ matchFam, matchFamTcM,+ checkWellStagedDFun,+ pprEq -- Smaller utils, re-exported from TcM+ -- TODO (DV): these are only really used in the+ -- instance matcher in TcSimplify. I am wondering+ -- if the whole instance matcher simply belongs+ -- here+) where++#include "HsVersions.h"++import HscTypes++import qualified Inst as TcM+import InstEnv+import FamInst+import FamInstEnv++import qualified TcRnMonad as TcM+import qualified TcMType as TcM+import qualified TcEnv as TcM+ ( checkWellStaged, topIdLvl, tcGetDefaultTys, tcLookupClass, tcLookupId )+import PrelNames( heqTyConKey, eqTyConKey )+import Kind+import TcType+import DynFlags+import Type+import Coercion+import Unify++import TcEvidence+import Class+import TyCon+import TcErrors ( solverDepthErrorTcS )++import Name+import RdrName ( GlobalRdrEnv, GlobalRdrElt )+import qualified RnEnv as TcM+import Var+import VarEnv+import VarSet+import Outputable+import Bag+import UniqSupply+import Util+import TcRnTypes++import Unique+import UniqFM+import UniqDFM+import Maybes++import TrieMap+import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif+import MonadUtils+import Data.IORef+import Data.List ( foldl', partition )++#ifdef DEBUG+import Digraph+import UniqSet+#endif++{-+************************************************************************+* *+* Worklists *+* Canonical and non-canonical constraints that the simplifier has to *+* work on. Including their simplification depths. *+* *+* *+************************************************************************++Note [WorkList priorities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+A WorkList contains canonical and non-canonical items (of all flavors).+Notice that each Ct now has a simplification depth. We may+consider using this depth for prioritization as well in the future.++As a simple form of priority queue, our worklist separates out+equalities (wl_eqs) from the rest of the canonical constraints,+so that it's easier to deal with them first, but the separation+is not strictly necessary. Notice that non-canonical constraints+are also parts of the worklist.++Note [Process derived items last]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We can often solve all goals without processing *any* derived constraints.+The derived constraints are just there to help us if we get stuck. So+we keep them in a separate list.++Note [Prioritise class equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We prioritise equalities in the solver (see selectWorkItem). But class+constraints like (a ~ b) and (a ~~ b) are actually equalities too;+see Note [The equality types story] in TysPrim.++Failing to prioritise these is inefficient (more kick-outs etc).+But, worse, it can prevent us spotting a "recursive knot" among+Wanted constraints. See comment:10 of Trac #12734 for a worked-out+example.++So we arrange to put these particular class constraints in the wl_eqs.++ NB: since we do not currently apply the substitution to the+ inert_solved_dicts, the knot-tying still seems a bit fragile.+ But this makes it better.+-}++-- See Note [WorkList priorities]+data WorkList+ = WL { wl_eqs :: [Ct] -- Both equality constraints and their+ -- class-level variants (a~b) and (a~~b);+ -- See Note [Prioritise class equalities]++ , wl_funeqs :: [Ct] -- LIFO stack of goals++ , wl_rest :: [Ct]++ , wl_deriv :: [CtEvidence] -- Implicitly non-canonical+ -- See Note [Process derived items last]++ , wl_implics :: Bag Implication -- See Note [Residual implications]+ }++appendWorkList :: WorkList -> WorkList -> WorkList+appendWorkList+ (WL { wl_eqs = eqs1, wl_funeqs = funeqs1, wl_rest = rest1+ , wl_deriv = ders1, wl_implics = implics1 })+ (WL { wl_eqs = eqs2, wl_funeqs = funeqs2, wl_rest = rest2+ , wl_deriv = ders2, wl_implics = implics2 })+ = WL { wl_eqs = eqs1 ++ eqs2+ , wl_funeqs = funeqs1 ++ funeqs2+ , wl_rest = rest1 ++ rest2+ , wl_deriv = ders1 ++ ders2+ , wl_implics = implics1 `unionBags` implics2 }++workListSize :: WorkList -> Int+workListSize (WL { wl_eqs = eqs, wl_funeqs = funeqs, wl_deriv = ders, wl_rest = rest })+ = length eqs + length funeqs + length rest + length ders++workListWantedCount :: WorkList -> Int+workListWantedCount (WL { wl_eqs = eqs, wl_rest = rest })+ = count isWantedCt eqs + count isWantedCt rest++extendWorkListEq :: Ct -> WorkList -> WorkList+extendWorkListEq ct wl = wl { wl_eqs = ct : wl_eqs wl }++extendWorkListEqs :: [Ct] -> WorkList -> WorkList+extendWorkListEqs cts wl = wl { wl_eqs = cts ++ wl_eqs wl }++extendWorkListFunEq :: Ct -> WorkList -> WorkList+extendWorkListFunEq ct wl = wl { wl_funeqs = ct : wl_funeqs wl }++extendWorkListNonEq :: Ct -> WorkList -> WorkList+-- Extension by non equality+extendWorkListNonEq ct wl = wl { wl_rest = ct : wl_rest wl }++extendWorkListDerived :: CtLoc -> CtEvidence -> WorkList -> WorkList+extendWorkListDerived loc ev wl+ | isDroppableDerivedLoc loc = wl { wl_deriv = ev : wl_deriv wl }+ | otherwise = extendWorkListEq (mkNonCanonical ev) wl++extendWorkListDeriveds :: CtLoc -> [CtEvidence] -> WorkList -> WorkList+extendWorkListDeriveds loc evs wl+ | isDroppableDerivedLoc loc = wl { wl_deriv = evs ++ wl_deriv wl }+ | otherwise = extendWorkListEqs (map mkNonCanonical evs) wl++extendWorkListImplic :: Bag Implication -> WorkList -> WorkList+extendWorkListImplic implics wl = wl { wl_implics = implics `unionBags` wl_implics wl }++extendWorkListCt :: Ct -> WorkList -> WorkList+-- Agnostic+extendWorkListCt ct wl+ = case classifyPredType (ctPred ct) of+ EqPred NomEq ty1 _+ | Just tc <- tcTyConAppTyCon_maybe ty1+ , isTypeFamilyTyCon tc+ -> extendWorkListFunEq ct wl++ EqPred {}+ -> extendWorkListEq ct wl++ ClassPred cls _ -- See Note [Prioritise class equalites]+ | cls `hasKey` heqTyConKey+ || cls `hasKey` eqTyConKey+ -> extendWorkListEq ct wl++ _ -> extendWorkListNonEq ct wl++extendWorkListCts :: [Ct] -> WorkList -> WorkList+-- Agnostic+extendWorkListCts cts wl = foldr extendWorkListCt wl cts++isEmptyWorkList :: WorkList -> Bool+isEmptyWorkList (WL { wl_eqs = eqs, wl_funeqs = funeqs+ , wl_rest = rest, wl_deriv = ders, wl_implics = implics })+ = null eqs && null rest && null funeqs && isEmptyBag implics && null ders++emptyWorkList :: WorkList+emptyWorkList = WL { wl_eqs = [], wl_rest = []+ , wl_funeqs = [], wl_deriv = [], wl_implics = emptyBag }++selectWorkItem :: WorkList -> Maybe (Ct, WorkList)+selectWorkItem wl@(WL { wl_eqs = eqs, wl_funeqs = feqs+ , wl_rest = rest })+ | ct:cts <- eqs = Just (ct, wl { wl_eqs = cts })+ | ct:fes <- feqs = Just (ct, wl { wl_funeqs = fes })+ | ct:cts <- rest = Just (ct, wl { wl_rest = cts })+ | otherwise = Nothing++getWorkList :: TcS WorkList+getWorkList = do { wl_var <- getTcSWorkListRef+ ; wrapTcS (TcM.readTcRef wl_var) }++selectDerivedWorkItem :: WorkList -> Maybe (Ct, WorkList)+selectDerivedWorkItem wl@(WL { wl_deriv = ders })+ | ev:evs <- ders = Just (mkNonCanonical ev, wl { wl_deriv = evs })+ | otherwise = Nothing++selectNextWorkItem :: TcS (Maybe Ct)+selectNextWorkItem+ = do { wl_var <- getTcSWorkListRef+ ; wl <- wrapTcS (TcM.readTcRef wl_var)++ ; let try :: Maybe (Ct,WorkList) -> TcS (Maybe Ct) -> TcS (Maybe Ct)+ try mb_work do_this_if_fail+ | Just (ct, new_wl) <- mb_work+ = do { checkReductionDepth (ctLoc ct) (ctPred ct)+ ; wrapTcS (TcM.writeTcRef wl_var new_wl)+ ; return (Just ct) }+ | otherwise+ = do_this_if_fail++ ; try (selectWorkItem wl) $++ do { ics <- getInertCans+ ; if inert_count ics == 0+ then return Nothing+ else try (selectDerivedWorkItem wl) (return Nothing) } }++-- Pretty printing+instance Outputable WorkList where+ ppr (WL { wl_eqs = eqs, wl_funeqs = feqs+ , wl_rest = rest, wl_implics = implics, wl_deriv = ders })+ = text "WL" <+> (braces $+ vcat [ ppUnless (null eqs) $+ text "Eqs =" <+> vcat (map ppr eqs)+ , ppUnless (null feqs) $+ text "Funeqs =" <+> vcat (map ppr feqs)+ , ppUnless (null rest) $+ text "Non-eqs =" <+> vcat (map ppr rest)+ , ppUnless (null ders) $+ text "Derived =" <+> vcat (map ppr ders)+ , ppUnless (isEmptyBag implics) $+ sdocWithPprDebug $ \dbg ->+ if dbg -- Typically we only want the work list for this level+ then text "Implics =" <+> vcat (map ppr (bagToList implics))+ else text "(Implics omitted)"+ ])+++{- *********************************************************************+* *+ InertSet: the inert set+* *+* *+********************************************************************* -}++data InertSet+ = IS { inert_cans :: InertCans+ -- Canonical Given, Wanted, Derived+ -- Sometimes called "the inert set"++ , inert_flat_cache :: ExactFunEqMap (TcCoercion, TcType, CtFlavour)+ -- See Note [Type family equations]+ -- If F tys :-> (co, rhs, flav),+ -- then co :: F tys ~ rhs+ -- flav is [G] or [WD]+ --+ -- Just a hash-cons cache for use when flattening only+ -- These include entirely un-processed goals, so don't use+ -- them to solve a top-level goal, else you may end up solving+ -- (w:F ty ~ a) by setting w:=w! We just use the flat-cache+ -- when allocating a new flatten-skolem.+ -- Not necessarily inert wrt top-level equations (or inert_cans)++ -- NB: An ExactFunEqMap -- this doesn't match via loose types!++ , inert_solved_dicts :: DictMap CtEvidence+ -- Of form ev :: C t1 .. tn+ -- See Note [Solved dictionaries]+ -- and Note [Do not add superclasses of solved dictionaries]+ }++instance Outputable InertSet where+ ppr is = vcat [ ppr $ inert_cans is+ , ppUnless (null dicts) $+ text "Solved dicts" <+> vcat (map ppr dicts) ]+ where+ dicts = bagToList (dictsToBag (inert_solved_dicts is))++emptyInert :: InertSet+emptyInert+ = IS { inert_cans = IC { inert_count = 0+ , inert_eqs = emptyDVarEnv+ , inert_dicts = emptyDicts+ , inert_safehask = emptyDicts+ , inert_funeqs = emptyFunEqs+ , inert_irreds = emptyCts+ , inert_insols = emptyCts }+ , inert_flat_cache = emptyExactFunEqs+ , inert_solved_dicts = emptyDictMap }+++{- Note [Solved dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we apply a top-level instance declaration, we add the "solved"+dictionary to the inert_solved_dicts. In general, we use it to avoid+creating a new EvVar when we have a new goal that we have solved in+the past.++But in particular, we can use it to create *recursive* dictionaries.+The simplest, degnerate case is+ instance C [a] => C [a] where ...+If we have+ [W] d1 :: C [x]+then we can apply the instance to get+ d1 = $dfCList d+ [W] d2 :: C [x]+Now 'd1' goes in inert_solved_dicts, and we can solve d2 directly from d1.+ d1 = $dfCList d+ d2 = d1++See Note [Example of recursive dictionaries]+Other notes about solved dictionaries++* See also Note [Do not add superclasses of solved dictionaries]++* The inert_solved_dicts field is not rewritten by equalities, so it may+ get out of date.++Note [Do not add superclasses of solved dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Every member of inert_solved_dicts is the result of applying a dictionary+function, NOT of applying superclass selection to anything.+Consider++ class Ord a => C a where+ instance Ord [a] => C [a] where ...++Suppose we are trying to solve+ [G] d1 : Ord a+ [W] d2 : C [a]++Then we'll use the instance decl to give++ [G] d1 : Ord a Solved: d2 : C [a] = $dfCList d3+ [W] d3 : Ord [a]++We must not add d4 : Ord [a] to the 'solved' set (by taking the+superclass of d2), otherwise we'll use it to solve d3, without ever+using d1, which would be a catastrophe.++Solution: when extending the solved dictionaries, do not add superclasses.+That's why each element of the inert_solved_dicts is the result of applying+a dictionary function.++Note [Example of recursive dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--- Example 1++ data D r = ZeroD | SuccD (r (D r));++ instance (Eq (r (D r))) => Eq (D r) where+ ZeroD == ZeroD = True+ (SuccD a) == (SuccD b) = a == b+ _ == _ = False;++ equalDC :: D [] -> D [] -> Bool;+ equalDC = (==);++We need to prove (Eq (D [])). Here's how we go:++ [W] d1 : Eq (D [])+By instance decl of Eq (D r):+ [W] d2 : Eq [D []] where d1 = dfEqD d2+By instance decl of Eq [a]:+ [W] d3 : Eq (D []) where d2 = dfEqList d3+ d1 = dfEqD d2+Now this wanted can interact with our "solved" d1 to get:+ d3 = d1++-- Example 2:+This code arises in the context of "Scrap Your Boilerplate with Class"++ class Sat a+ class Data ctx a+ instance Sat (ctx Char) => Data ctx Char -- dfunData1+ instance (Sat (ctx [a]), Data ctx a) => Data ctx [a] -- dfunData2++ class Data Maybe a => Foo a++ instance Foo t => Sat (Maybe t) -- dfunSat++ instance Data Maybe a => Foo a -- dfunFoo1+ instance Foo a => Foo [a] -- dfunFoo2+ instance Foo [Char] -- dfunFoo3++Consider generating the superclasses of the instance declaration+ instance Foo a => Foo [a]++So our problem is this+ [G] d0 : Foo t+ [W] d1 : Data Maybe [t] -- Desired superclass++We may add the given in the inert set, along with its superclasses+ Inert:+ [G] d0 : Foo t+ [G] d01 : Data Maybe t -- Superclass of d0+ WorkList+ [W] d1 : Data Maybe [t]++Solve d1 using instance dfunData2; d1 := dfunData2 d2 d3+ Inert:+ [G] d0 : Foo t+ [G] d01 : Data Maybe t -- Superclass of d0+ Solved:+ d1 : Data Maybe [t]+ WorkList:+ [W] d2 : Sat (Maybe [t])+ [W] d3 : Data Maybe t++Now, we may simplify d2 using dfunSat; d2 := dfunSat d4+ Inert:+ [G] d0 : Foo t+ [G] d01 : Data Maybe t -- Superclass of d0+ Solved:+ d1 : Data Maybe [t]+ d2 : Sat (Maybe [t])+ WorkList:+ [W] d3 : Data Maybe t+ [W] d4 : Foo [t]++Now, we can just solve d3 from d01; d3 := d01+ Inert+ [G] d0 : Foo t+ [G] d01 : Data Maybe t -- Superclass of d0+ Solved:+ d1 : Data Maybe [t]+ d2 : Sat (Maybe [t])+ WorkList+ [W] d4 : Foo [t]++Now, solve d4 using dfunFoo2; d4 := dfunFoo2 d5+ Inert+ [G] d0 : Foo t+ [G] d01 : Data Maybe t -- Superclass of d0+ Solved:+ d1 : Data Maybe [t]+ d2 : Sat (Maybe [t])+ d4 : Foo [t]+ WorkList:+ [W] d5 : Foo t++Now, d5 can be solved! d5 := d0++Result+ d1 := dfunData2 d2 d3+ d2 := dfunSat d4+ d3 := d01+ d4 := dfunFoo2 d5+ d5 := d0+-}++{- *********************************************************************+* *+ InertCans: the canonical inerts+* *+* *+********************************************************************* -}++data InertCans -- See Note [Detailed InertCans Invariants] for more+ = IC { inert_eqs :: InertEqs+ -- See Note [inert_eqs: the inert equalities]+ -- All CTyEqCans; index is the LHS tyvar+ -- Domain = skolems and untouchables; a touchable would be unified++ , inert_funeqs :: FunEqMap Ct+ -- All CFunEqCans; index is the whole family head type.+ -- All Nominal (that's an invarint of all CFunEqCans)+ -- LHS is fully rewritten (modulo eqCanRewrite constraints)+ -- wrt inert_eqs+ -- Can include all flavours, [G], [W], [WD], [D]+ -- See Note [Type family equations]++ , inert_dicts :: DictMap Ct+ -- Dictionaries only+ -- All fully rewritten (modulo flavour constraints)+ -- wrt inert_eqs++ , inert_safehask :: DictMap Ct+ -- Failed dictionary resolution due to Safe Haskell overlapping+ -- instances restriction. We keep this separate from inert_dicts+ -- as it doesn't cause compilation failure, just safe inference+ -- failure.+ --+ -- ^ See Note [Safe Haskell Overlapping Instances Implementation]+ -- in TcSimplify++ , inert_irreds :: Cts+ -- Irreducible predicates++ , inert_insols :: Cts+ -- Frozen errors (as non-canonicals)++ , inert_count :: Int+ -- Number of Wanted goals in+ -- inert_eqs, inert_dicts, inert_safehask, inert_irreds+ -- Does not include insolubles+ -- When non-zero, keep trying to solved+ }++type InertEqs = DTyVarEnv EqualCtList+type EqualCtList = [Ct] -- See Note [EqualCtList invariants]++{- Note [Detailed InertCans Invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The InertCans represents a collection of constraints with the following properties:++ * All canonical++ * No two dictionaries with the same head+ * No two CIrreds with the same type++ * Family equations inert wrt top-level family axioms++ * Dictionaries have no matching top-level instance++ * Given family or dictionary constraints don't mention touchable+ unification variables++ * Non-CTyEqCan constraints are fully rewritten with respect+ to the CTyEqCan equalities (modulo canRewrite of course;+ eg a wanted cannot rewrite a given)++ * CTyEqCan equalities: see Note [Applying the inert substitution]+ in TcFlatten++Note [EqualCtList invariants]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * All are equalities+ * All these equalities have the same LHS+ * The list is never empty+ * No element of the list can rewrite any other+ * Derived before Wanted++From the fourth invariant it follows that the list is+ - A single [G], or+ - Zero or one [D] or [WD], followd by any number of [W]++The Wanteds can't rewrite anything which is why we put them last++Note [Type family equations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Type-family equations, CFunEqCans, of form (ev : F tys ~ ty),+live in three places++ * The work-list, of course++ * The inert_funeqs are un-solved but fully processed, and in+ the InertCans. They can be [G], [W], [WD], or [D].++ * The inert_flat_cache. This is used when flattening, to get maximal+ sharing. Everthing in the inert_flat_cache is [G] or [WD]++ It contains lots of things that are still in the work-list.+ E.g Suppose we have (w1: F (G a) ~ Int), and (w2: H (G a) ~ Int) in the+ work list. Then we flatten w1, dumping (w3: G a ~ f1) in the work+ list. Now if we flatten w2 before we get to w3, we still want to+ share that (G a).+ Because it contains work-list things, DO NOT use the flat cache to solve+ a top-level goal. Eg in the above example we don't want to solve w3+ using w3 itself!++The CFunEqCan Ownership Invariant:++ * Each [G/W/WD] CFunEqCan has a distinct fsk or fmv+ It "owns" that fsk/fmv, in the sense that:+ - reducing a [W/WD] CFunEqCan fills in the fmv+ - unflattening a [W/WD] CFunEqCan fills in the fmv+ (in both cases unless an occurs-check would result)++ * In contrast a [D] CFunEqCan does not "own" its fmv:+ - reducing a [D] CFunEqCan does not fill in the fmv;+ it just generates an equality+ - unflattening ignores [D] CFunEqCans altogether+++Note [inert_eqs: the inert equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Definition [Can-rewrite relation]+A "can-rewrite" relation between flavours, written f1 >= f2, is a+binary relation with the following properties++ (R1) >= is transitive+ (R2) If f1 >= f, and f2 >= f,+ then either f1 >= f2 or f2 >= f1++Lemma. If f1 >= f then f1 >= f1+Proof. By property (R2), with f1=f2++Definition [Generalised substitution]+A "generalised substitution" S is a set of triples (a -f-> t), where+ a is a type variable+ t is a type+ f is a flavour+such that+ (WF1) if (a -f1-> t1) in S+ (a -f2-> t2) in S+ then neither (f1 >= f2) nor (f2 >= f1) hold+ (WF2) if (a -f-> t) is in S, then t /= a++Definition [Applying a generalised substitution]+If S is a generalised substitution+ S(f,a) = t, if (a -fs-> t) in S, and fs >= f+ = a, otherwise+Application extends naturally to types S(f,t), modulo roles.+See Note [Flavours with roles].++Theorem: S(f,a) is well defined as a function.+Proof: Suppose (a -f1-> t1) and (a -f2-> t2) are both in S,+ and f1 >= f and f2 >= f+ Then by (R2) f1 >= f2 or f2 >= f1, which contradicts (WF1)++Notation: repeated application.+ S^0(f,t) = t+ S^(n+1)(f,t) = S(f, S^n(t))++Definition: inert generalised substitution+A generalised substitution S is "inert" iff++ (IG1) there is an n such that+ for every f,t, S^n(f,t) = S^(n+1)(f,t)++By (IG1) we define S*(f,t) to be the result of exahaustively+applying S(f,_) to t.++----------------------------------------------------------------+Our main invariant:+ the inert CTyEqCans should be an inert generalised substitution+----------------------------------------------------------------++Note that inertness is not the same as idempotence. To apply S to a+type, you may have to apply it recursive. But inertness does+guarantee that this recursive use will terminate.++Note [Extending the inert equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Theorem [Stability under extension]+ This is the main theorem!+ Suppose we have a "work item"+ a -fw-> t+ and an inert generalised substitution S,+ such that+ (T1) S(fw,a) = a -- LHS of work-item is a fixpoint of S(fw,_)+ (T2) S(fw,t) = t -- RHS of work-item is a fixpoint of S(fw,_)+ (T3) a not in t -- No occurs check in the work item++ (K1) for every (a -fs-> s) in S, then not (fw >= fs)+ Reason: the work item is fully rewritten by S, hence not (fs >= fw)+ but if (fw >= fs) then the work item could rewrite+ the inert item++ (K2) for every (b -fs-> s) in S, where b /= a, then+ (K2a) not (fs >= fs)+ or (K2b) fs >= fw+ or (K2c) not (fw >= fs)+ or (K2d) a not in s++ (K3) See Note [K3: completeness of solving]+ If (b -fs-> s) is in S with (fw >= fs), then+ (K3a) If the role of fs is nominal: s /= a+ (K3b) If the role of fs is representational: EITHER+ a not in s, OR+ the path from the top of s to a includes at least one non-newtype++ then the extended substitution T = S+(a -fw-> t)+ is an inert generalised substitution.++Conditions (T1-T3) are established by the canonicaliser+Conditions (K1-K3) are established by TcSMonad.kickOutRewritable++The idea is that+* (T1-2) are guaranteed by exhaustively rewriting the work-item+ with S(fw,_).++* T3 is guaranteed by a simple occurs-check on the work item.+ This is done during canonicalisation, in canEqTyVar;+ (invariant: a CTyEqCan never has an occurs check).++* (K1-3) are the "kick-out" criteria. (As stated, they are really the+ "keep" criteria.) If the current inert S contains a triple that does+ not satisfy (K1-3), then we remove it from S by "kicking it out",+ and re-processing it.++* Note that kicking out is a Bad Thing, because it means we have to+ re-process a constraint. The less we kick out, the better.+ TODO: Make sure that kicking out really *is* a Bad Thing. We've assumed+ this but haven't done the empirical study to check.++* Assume we have G>=G, G>=W and that's all. Then, when performing+ a unification we add a new given a -G-> ty. But doing so does NOT require+ us to kick out an inert wanted that mentions a, because of (K2a). This+ is a common case, hence good not to kick out.++* Lemma (L2): if not (fw >= fw), then K1-K3 all hold.+ Proof: using Definition [Can-rewrite relation], fw can't rewrite anything+ and so K1-K3 hold. Intuitively, since fw can't rewrite anything,+ adding it cannot cause any loops+ This is a common case, because Wanteds cannot rewrite Wanteds.++* Lemma (L1): The conditions of the Main Theorem imply that there is no+ (a -fs-> t) in S, s.t. (fs >= fw).+ Proof. Suppose the contrary (fs >= fw). Then because of (T1),+ S(fw,a)=a. But since fs>=fw, S(fw,a) = s, hence s=a. But now we+ have (a -fs-> a) in S, which contradicts (WF2).++* The extended substitution satisfies (WF1) and (WF2)+ - (K1) plus (L1) guarantee that the extended substitution satisfies (WF1).+ - (T3) guarantees (WF2).++* (K2) is about inertness. Intuitively, any infinite chain T^0(f,t),+ T^1(f,t), T^2(f,T).... must pass through the new work item infnitely+ often, since the substitution without the work item is inert; and must+ pass through at least one of the triples in S infnitely often.++ - (K2a): if not(fs>=fs) then there is no f that fs can rewrite (fs>=f),+ and hence this triple never plays a role in application S(f,a).+ It is always safe to extend S with such a triple.++ (NB: we could strengten K1) in this way too, but see K3.++ - (K2b): If this holds then, by (T2), b is not in t. So applying the+ work item does not genenerate any new opportunities for applying S++ - (K2c): If this holds, we can't pass through this triple infinitely+ often, because if we did then fs>=f, fw>=f, hence by (R2)+ * either fw>=fs, contradicting K2c+ * or fs>=fw; so by the argument in K2b we can't have a loop++ - (K2d): if a not in s, we hae no further opportunity to apply the+ work item, similar to (K2b)++ NB: Dimitrios has a PDF that does this in more detail++Key lemma to make it watertight.+ Under the conditions of the Main Theorem,+ forall f st fw >= f, a is not in S^k(f,t), for any k++Also, consider roles more carefully. See Note [Flavours with roles]++Note [K3: completeness of solving]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(K3) is not necessary for the extended substitution+to be inert. In fact K1 could be made stronger by saying+ ... then (not (fw >= fs) or not (fs >= fs))+But it's not enough for S to be inert; we also want completeness.+That is, we want to be able to solve all soluble wanted equalities.+Suppose we have++ work-item b -G-> a+ inert-item a -W-> b++Assuming (G >= W) but not (W >= W), this fulfills all the conditions,+so we could extend the inerts, thus:++ inert-items b -G-> a+ a -W-> b++But if we kicked-out the inert item, we'd get++ work-item a -W-> b+ inert-item b -G-> a++Then rewrite the work-item gives us (a -W-> a), which is soluble via Refl.+So we add one more clause to the kick-out criteria++Another way to understand (K3) is that we treat an inert item+ a -f-> b+in the same way as+ b -f-> a+So if we kick out one, we should kick out the other. The orientation+is somewhat accidental.++When considering roles, we also need the second clause (K3b). Consider++ inert-item a -W/R-> b c+ work-item c -G/N-> a++The work-item doesn't get rewritten by the inert, because (>=) doesn't hold.+We've satisfied conditions (T1)-(T3) and (K1) and (K2). If all we had were+condition (K3a), then we would keep the inert around and add the work item.+But then, consider if we hit the following:++ work-item2 b -G/N-> Id++where++ newtype Id x = Id x++For similar reasons, if we only had (K3a), we wouldn't kick the+representational inert out. And then, we'd miss solving the inert, which+now reduced to reflexivity. The solution here is to kick out representational+inerts whenever the tyvar of a work item is "exposed", where exposed means+not under some proper data-type constructor, like [] or Maybe. See+isTyVarExposed in TcType. This is encoded in (K3b).++Note [Flavours with roles]+~~~~~~~~~~~~~~~~~~~~~~~~~~+The system described in Note [inert_eqs: the inert equalities]+discusses an abstract+set of flavours. In GHC, flavours have two components: the flavour proper,+taken from {Wanted, Derived, Given} and the equality relation (often called+role), taken from {NomEq, ReprEq}.+When substituting w.r.t. the inert set,+as described in Note [inert_eqs: the inert equalities],+we must be careful to respect all components of a flavour.+For example, if we have++ inert set: a -G/R-> Int+ b -G/R-> Bool++ type role T nominal representational++and we wish to compute S(W/R, T a b), the correct answer is T a Bool, NOT+T Int Bool. The reason is that T's first parameter has a nominal role, and+thus rewriting a to Int in T a b is wrong. Indeed, this non-congruence of+substitution means that the proof in Note [The inert equalities] may need+to be revisited, but we don't think that the end conclusion is wrong.+-}++instance Outputable InertCans where+ ppr (IC { inert_eqs = eqs+ , inert_funeqs = funeqs, inert_dicts = dicts+ , inert_safehask = safehask, inert_irreds = irreds+ , inert_insols = insols, inert_count = count })+ = braces $ vcat+ [ ppUnless (isEmptyDVarEnv eqs) $+ text "Equalities:"+ <+> pprCts (foldDVarEnv (\eqs rest -> listToBag eqs `andCts` rest) emptyCts eqs)+ , ppUnless (isEmptyTcAppMap funeqs) $+ text "Type-function equalities =" <+> pprCts (funEqsToBag funeqs)+ , ppUnless (isEmptyTcAppMap dicts) $+ text "Dictionaries =" <+> pprCts (dictsToBag dicts)+ , ppUnless (isEmptyTcAppMap safehask) $+ text "Safe Haskell unsafe overlap =" <+> pprCts (dictsToBag safehask)+ , ppUnless (isEmptyCts irreds) $+ text "Irreds =" <+> pprCts irreds+ , ppUnless (isEmptyCts insols) $+ text "Insolubles =" <+> pprCts insols+ , text "Unsolved goals =" <+> int count+ ]++{- *********************************************************************+* *+ Shadow constraints and improvement+* *+************************************************************************++Note [The improvement story and derived shadows]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because Wanteds cannot rewrite Wanteds (see Note [Wanteds do not+rewrite Wanteds] in TcRnTypes), we may miss some opportunities for+solving. Here's a classic example (indexed-types/should_fail/T4093a)++ Ambiguity check for f: (Foo e ~ Maybe e) => Foo e++ We get [G] Foo e ~ Maybe e+ [W] Foo e ~ Foo ee -- ee is a unification variable+ [W] Foo ee ~ Maybe ee++ Flatten: [G] Foo e ~ fsk+ [G] fsk ~ Maybe e -- (A)++ [W] Foo ee ~ fmv+ [W] fmv ~ fsk -- (B) From Foo e ~ Foo ee+ [W] fmv ~ Maybe ee++ --> rewrite (B) with (A)+ [W] Foo ee ~ fmv+ [W] fmv ~ Maybe e+ [W] fmv ~ Maybe ee++ But now we appear to be stuck, since we don't rewrite Wanteds with+ Wanteds. This is silly because we can see that ee := e is the+ only solution.++The basic plan is+ * generate Derived constraints that shadow Wanted constraints+ * allow Derived to rewrite Derived+ * in order to cause some unifications to take place+ * that in turn solve the original Wanteds++The ONLY reason for all these Derived equalities is to tell us how to+unify a variable: that is, what Mark Jones calls "improvement".++The same idea is sometimes also called "saturation"; find all the+equalities that must hold in any solution.++Or, equivalently, you can think of the derived shadows as implementing+the "model": an non-idempotent but no-occurs-check substitution,+reflecting *all* *Nominal* equalities (a ~N ty) that are not+immediately soluble by unification.++More specifically, here's how it works (Oct 16):++* Wanted constraints are born as [WD]; this behaves like a+ [W] and a [D] paired together.++* When we are about to add a [WD] to the inert set, if it can+ be rewritten by a [D] a ~ ty, then we split it into [W] and [D],+ putting the latter into the work list (see maybeEmitShadow).++In the example above, we get to the point where we are stuck:+ [WD] Foo ee ~ fmv+ [WD] fmv ~ Maybe e+ [WD] fmv ~ Maybe ee++But now when [WD] fmv ~ Maybe ee is about to be added, we'll+split it into [W] and [D], since the inert [WD] fmv ~ Maybe e+can rewrite it. Then:+ work item: [D] fmv ~ Maybe ee+ inert: [W] fmv ~ Maybe ee+ [WD] fmv ~ Maybe e -- (C)+ [WD] Foo ee ~ fmv++See Note [Splitting WD constraints]. Now the work item is rewritten+by (C) and we soon get ee := e.++Additional notes:++ * The derived shadow equalities live in inert_eqs, along with+ the Givens and Wanteds; see Note [EqualCtList invariants].++ * We make Derived shadows only for Wanteds, not Givens. So we+ have only [G], not [GD] and [G] plus splitting. See+ Note [Add derived shadows only for Wanteds]++ * We also get Derived equalities from functional dependencies+ and type-function injectivity; see calls to unifyDerived.++ * This splitting business applies to CFunEqCans too; and then+ we do apply type-function reductions to the [D] CFunEqCan.+ See Note [Reduction for Derived CFunEqCans]++ * It's worth having [WD] rather than just [W] and [D] because+ * efficiency: silly to process the same thing twice+ * inert_funeqs, inert_dicts is a finite map keyed by+ the type; it's inconvenient for it to map to TWO constraints++Note [Splitting WD constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We are about to add a [WD] constraint to the inert set; and we+know that the inert set has fully rewritten it. Should we split+it into [W] and [D], and put the [D] in the work list for further+work?++* CDictCan (C tys) or CFunEqCan (F tys ~ fsk):+ Yes if the inert set could rewrite tys to make the class constraint,+ or type family, fire. That is, yes if the inert_eqs intersects+ with the free vars of tys. For this test we use+ (anyRewritableTyVar True) which ignores casts and coercions in tys,+ because rewriting the casts or coercions won't make the thing fire+ more often.++* CTyEqCan (a ~ ty): Yes if the inert set could rewrite 'a' or 'ty'.+ We need to check both 'a' and 'ty' against the inert set:+ - Inert set contains [D] a ~ ty2+ Then we want to put [D] a ~ ty in the worklist, so we'll+ get [D] ty ~ ty2 with consequent good things++ - Inert set contains [D] b ~ a, where b is in ty.+ We can't just add [WD] a ~ ty[b] to the inert set, because+ that breaks the inert-set invariants. If we tried to+ canonicalise another [D] constraint mentioning 'a', we'd+ get an infinite loop++ Moreover we must use (anyRewritableTyVar False) for the RHS,+ because even tyvars in the casts and coercions could give+ an infinite loop if we don't expose it++* Others: nothing is gained by splitting.++Note [Examples of how Derived shadows helps completeness]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Trac #10009, a very nasty example:++ f :: (UnF (F b) ~ b) => F b -> ()++ g :: forall a. (UnF (F a) ~ a) => a -> ()+ g _ = f (undefined :: F a)++ For g we get [G] UnF (F a) ~ a+ [WD] UnF (F beta) ~ beta+ [WD] F a ~ F beta+ Flatten:+ [G] g1: F a ~ fsk1 fsk1 := F a+ [G] g2: UnF fsk1 ~ fsk2 fsk2 := UnF fsk1+ [G] g3: fsk2 ~ a++ [WD] w1: F beta ~ fmv1+ [WD] w2: UnF fmv1 ~ fmv2+ [WD] w3: fmv2 ~ beta+ [WD] w4: fmv1 ~ fsk1 -- From F a ~ F beta using flat-cache+ -- and re-orient to put meta-var on left++Rewrite w2 with w4: [D] d1: UnF fsk1 ~ fmv2+React that with g2: [D] d2: fmv2 ~ fsk2+React that with w3: [D] beta ~ fsk2+ and g3: [D] beta ~ a -- Hooray beta := a+And that is enough to solve everything++Note [Add derived shadows only for Wanteds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We only add shadows for Wanted constraints. That is, we have+[WD] but not [GD]; and maybeEmitShaodw looks only at [WD]+constraints.++It does just possibly make sense ot add a derived shadow for a+Given. If we created a Derived shadow of a Given, it could be+rewritten by other Deriveds, and that could, conceivably, lead to a+useful unification.++But (a) I have been unable to come up with an example of this+ happening+ (b) see Trac #12660 for how adding the derived shadows+ of a Given led to an infinite loop.+ (c) It's unlikely that rewriting derived Givens will lead+ to a unification because Givens don't mention touchable+ unification variables++For (b) there may be other ways to solve the loop, but simply+reraining from adding derived shadows of Givens is particularly+simple. And it's more efficient too!++Still, here's one possible reason for adding derived shadows+for Givens. Consider+ work-item [G] a ~ [b], inerts has [D] b ~ a.+If we added the derived shadow (into the work list)+ [D] a ~ [b]+When we process it, we'll rewrite to a ~ [a] and get an+occurs check. Without it we'll miss the occurs check (reporting+inaccessible code); but that's probably OK.++Note [Keep CDictCan shadows as CDictCan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+ class C a => D a b+and [G] D a b, [G] C a in the inert set. Now we insert+[D] b ~ c. We want to kick out a derived shadow for [D] D a b,+so we can rewrite it with the new constraint, and perhaps get+instance reduction or other consequences.++BUT we do not want to kick out a *non-canonical* (D a b). If we+did, we would do this:+ - rewrite it to [D] D a c, with pend_sc = True+ - use expandSuperClasses to add C a+ - go round again, which solves C a from the givens+This loop goes on for ever and triggers the simpl_loop limit.++Solution: kick out the CDictCan which will have pend_sc = False,+because we've already added its superclasses. So we won't re-add+them. If we forget the pend_sc flag, our cunning scheme for avoiding+generating superclasses repeatedly will fail.++See Trac #11379 for a case of this.++Note [Do not do improvement for WOnly]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do improvement between two constraints (e.g. for injectivity+or functional dependencies) only if both are "improvable". And+we improve a constraint wrt the top-level instances only if+it is improvable.++Improvable: [G] [WD] [D}+Not improvable: [W]++Reasons:++* It's less work: fewer pairs to compare++* Every [W] has a shadow [D] so nothing is lost++* Consider [WD] C Int b, where 'b' is a skolem, and+ class C a b | a -> b+ instance C Int Bool+ We'll do a fundep on it and emit [D] b ~ Bool+ That will kick out constraint [WD] C Int b+ Then we'll split it to [W] C Int b (keep in inert)+ and [D] C Int b (in work list)+ When processing the latter we'll rewrite it to+ [D] C Int Bool+ At that point it would be /stupid/ to interact it+ with the inert [W] C Int b in the inert set; after all,+ it's the very constraint from which the [D] C Int Bool+ was split! We can avoid this by not doing improvement+ on [W] constraints. This came up in Trac #12860.+-}++maybeEmitShadow :: InertCans -> Ct -> TcS Ct+-- See Note [The improvement story and derived shadows]+maybeEmitShadow ics ct+ | let ev = ctEvidence ct+ , CtWanted { ctev_pred = pred, ctev_loc = loc+ , ctev_nosh = WDeriv } <- ev+ , shouldSplitWD (inert_eqs ics) ct+ = do { traceTcS "Emit derived shadow" (ppr ct)+ ; let derived_ev = CtDerived { ctev_pred = pred+ , ctev_loc = loc }+ shadow_ct = ct { cc_ev = derived_ev }+ -- Te shadow constraint keeps the canonical shape.+ -- This just saves work, but is sometimes important;+ -- see Note [Keep CDictCan shadows as CDictCan]+ ; emitWork [shadow_ct]++ ; let ev' = ev { ctev_nosh = WOnly }+ ct' = ct { cc_ev = ev' }+ -- Record that it now has a shadow+ -- This is /the/ place we set the flag to WOnly+ ; return ct' }++ | otherwise+ = return ct++shouldSplitWD :: InertEqs -> Ct -> Bool+-- Precondition: 'ct' is [WD], and is inert+-- True <=> we should split ct ito [W] and [D] because+-- the inert_eqs can make progress on the [D]+-- See Note [Splitting WD constraints]++shouldSplitWD inert_eqs (CFunEqCan { cc_tyargs = tys })+ = should_split_match_args inert_eqs tys+ -- We don't need to split if the tv is the RHS fsk++shouldSplitWD inert_eqs (CDictCan { cc_tyargs = tys })+ = should_split_match_args inert_eqs tys+ -- NB True: ignore coercions+ -- See Note [Splitting WD constraints]++shouldSplitWD inert_eqs (CTyEqCan { cc_tyvar = tv, cc_rhs = ty })+ = tv `elemDVarEnv` inert_eqs+ || anyRewritableTyVar False (`elemDVarEnv` inert_eqs) ty+ -- NB False: do not ignore casts and coercions+ -- See Note [Splitting WD constraints]++shouldSplitWD _ _ = False -- No point in splitting otherwise++should_split_match_args :: InertEqs -> [TcType] -> Bool+-- True if the inert_eqs can rewrite anything in the argument+-- types, ignoring casts and coercions+should_split_match_args inert_eqs tys+ = any (anyRewritableTyVar True (`elemDVarEnv` inert_eqs)) tys+ -- NB True: ignore casts coercions+ -- See Note [Splitting WD constraints]++isImprovable :: CtEvidence -> Bool+-- See Note [Do not do improvement for WOnly]+isImprovable (CtWanted { ctev_nosh = WOnly }) = False+isImprovable _ = True+++{- *********************************************************************+* *+ Inert equalities+* *+********************************************************************* -}++addTyEq :: InertEqs -> TcTyVar -> Ct -> InertEqs+addTyEq old_eqs tv ct+ = extendDVarEnv_C add_eq old_eqs tv [ct]+ where+ add_eq old_eqs _+ | isWantedCt ct+ , (eq1 : eqs) <- old_eqs+ = eq1 : ct : eqs+ | otherwise+ = ct : old_eqs++foldTyEqs :: (Ct -> b -> b) -> InertEqs -> b -> b+foldTyEqs k eqs z+ = foldDVarEnv (\cts z -> foldr k z cts) z eqs++findTyEqs :: InertCans -> TyVar -> EqualCtList+findTyEqs icans tv = lookupDVarEnv (inert_eqs icans) tv `orElse` []++delTyEq :: InertEqs -> TcTyVar -> TcType -> InertEqs+delTyEq m tv t = modifyDVarEnv (filter (not . isThisOne)) m tv+ where isThisOne (CTyEqCan { cc_rhs = t1 }) = eqType t t1+ isThisOne _ = False++lookupInertTyVar :: InertEqs -> TcTyVar -> Maybe TcType+lookupInertTyVar ieqs tv+ = case lookupDVarEnv ieqs tv of+ Just (CTyEqCan { cc_rhs = rhs, cc_eq_rel = NomEq } : _ ) -> Just rhs+ _ -> Nothing++lookupFlattenTyVar :: InertEqs -> TcTyVar -> TcType+-- See Note [lookupFlattenTyVar]+lookupFlattenTyVar ieqs ftv+ = lookupInertTyVar ieqs ftv `orElse` mkTyVarTy ftv++{- Note [lookupFlattenTyVar]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have an injective function F and+ inert_funeqs: F t1 ~ fsk1+ F t2 ~ fsk2+ inert_eqs: fsk1 ~ fsk2++We never rewrite the RHS (cc_fsk) of a CFunEqCan. But we /do/ want to+get the [D] t1 ~ t2 from the injectiveness of F. So we look up the+cc_fsk of CFunEqCans in the inert_eqs when trying to find derived+equalities arising from injectivity.+-}+++{- *********************************************************************+* *+ Adding an inert+* *+************************************************************************++Note [Adding an equality to the InertCans]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When adding an equality to the inerts:++* Split [WD] into [W] and [D] if the inerts can rewrite the latter;+ done by maybeEmitShadow.++* Kick out any constraints that can be rewritten by the thing+ we are adding. Done by kickOutRewritable.++* Note that unifying a:=ty, is like adding [G] a~ty; just use+ kickOutRewritable with Nominal, Given. See kickOutAfterUnification.++Note [Kicking out CFunEqCan for fundeps]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider:+ New: [D] fmv1 ~ fmv2+ Inert: [W] F alpha ~ fmv1+ [W] F beta ~ fmv2++where F is injective. The new (derived) equality certainly can't+rewrite the inerts. But we *must* kick out the first one, to get:++ New: [W] F alpha ~ fmv1+ Inert: [W] F beta ~ fmv2+ [D] fmv1 ~ fmv2++and now improvement will discover [D] alpha ~ beta. This is important;+eg in Trac #9587.++So in kickOutRewritable we look at all the tyvars of the+CFunEqCan, including the fsk.+-}++addInertEq :: Ct -> TcS ()+-- This is a key function, because of the kick-out stuff+-- Precondition: item /is/ canonical+-- See Note [Adding an equality to the InertCans]+addInertEq ct+ = do { traceTcS "addInertEq {" $+ text "Adding new inert equality:" <+> ppr ct++ ; ics <- getInertCans++ ; ct@(CTyEqCan { cc_tyvar = tv, cc_ev = ev }) <- maybeEmitShadow ics ct++ ; (_, ics1) <- kickOutRewritable (ctEvFlavourRole ev) tv ics++ ; let ics2 = ics1 { inert_eqs = addTyEq (inert_eqs ics1) tv ct+ , inert_count = bumpUnsolvedCount ev (inert_count ics1) }+ ; setInertCans ics2++ ; traceTcS "addInertEq }" $ empty }++--------------+addInertCan :: Ct -> TcS () -- Constraints *other than* equalities+addInertCan ct+ = do { traceTcS "insertInertCan {" $+ text "Trying to insert new non-eq inert item:" <+> ppr ct++ ; ics <- getInertCans+ ; ct <- maybeEmitShadow ics ct+ ; setInertCans (add_item ics ct)++ ; traceTcS "addInertCan }" $ empty }++add_item :: InertCans -> Ct -> InertCans+add_item ics item@(CFunEqCan { cc_fun = tc, cc_tyargs = tys })+ = ics { inert_funeqs = insertFunEq (inert_funeqs ics) tc tys item }++add_item ics item@(CIrredEvCan { cc_ev = ev })+ = ics { inert_irreds = inert_irreds ics `Bag.snocBag` item+ , inert_count = bumpUnsolvedCount ev (inert_count ics) }+ -- The 'False' is because the irreducible constraint might later instantiate+ -- to an equality.+ -- But since we try to simplify first, if there's a constraint function FC with+ -- type instance FC Int = Show+ -- we'll reduce a constraint (FC Int a) to Show a, and never add an inert irreducible++add_item ics item@(CDictCan { cc_ev = ev, cc_class = cls, cc_tyargs = tys })+ = ics { inert_dicts = addDict (inert_dicts ics) cls tys item+ , inert_count = bumpUnsolvedCount ev (inert_count ics) }++add_item _ item+ = pprPanic "upd_inert set: can't happen! Inserting " $+ ppr item -- CTyEqCan is dealt with by addInertEq+ -- Can't be CNonCanonical, CHoleCan,+ -- because they only land in inert_insols++bumpUnsolvedCount :: CtEvidence -> Int -> Int+bumpUnsolvedCount ev n | isWanted ev = n+1+ | otherwise = n+++-----------------------------------------+kickOutRewritable :: CtFlavourRole -- Flavour/role of the equality that+ -- is being added to the inert set+ -> TcTyVar -- The new equality is tv ~ ty+ -> InertCans+ -> TcS (Int, InertCans)+kickOutRewritable new_fr new_tv ics+ = do { let (kicked_out, ics') = kick_out_rewritable new_fr new_tv ics+ n_kicked = workListSize kicked_out++ ; unless (n_kicked == 0) $+ do { updWorkListTcS (appendWorkList kicked_out)+ ; csTraceTcS $+ hang (text "Kick out, tv =" <+> ppr new_tv)+ 2 (vcat [ text "n-kicked =" <+> int n_kicked+ , text "kicked_out =" <+> ppr kicked_out+ , text "Residual inerts =" <+> ppr ics' ]) }++ ; return (n_kicked, ics') }++kick_out_rewritable :: CtFlavourRole -- Flavour/role of the equality that+ -- is being added to the inert set+ -> TcTyVar -- The new equality is tv ~ ty+ -> InertCans+ -> (WorkList, InertCans)+-- See Note [kickOutRewritable]+kick_out_rewritable new_fr new_tv ics@(IC { inert_eqs = tv_eqs+ , inert_dicts = dictmap+ , inert_safehask = safehask+ , inert_funeqs = funeqmap+ , inert_irreds = irreds+ , inert_insols = insols+ , inert_count = n })+ | not (new_fr `eqMayRewriteFR` new_fr)+ = (emptyWorkList, ics)+ -- If new_fr can't rewrite itself, it can't rewrite+ -- anything else, so no need to kick out anything.+ -- (This is a common case: wanteds can't rewrite wanteds)+ -- Lemma (L2) in Note [Extending the inert equalities]++ | otherwise+ = (kicked_out, inert_cans_in)+ where+ inert_cans_in = IC { inert_eqs = tv_eqs_in+ , inert_dicts = dicts_in+ , inert_safehask = safehask -- ??+ , inert_funeqs = feqs_in+ , inert_irreds = irs_in+ , inert_insols = insols_in+ , inert_count = n - workListWantedCount kicked_out }++ kicked_out = WL { wl_eqs = tv_eqs_out+ , wl_funeqs = feqs_out+ , wl_deriv = []+ , wl_rest = bagToList (dicts_out `andCts` irs_out+ `andCts` insols_out)+ , wl_implics = emptyBag }++ (tv_eqs_out, tv_eqs_in) = foldDVarEnv kick_out_eqs ([], emptyDVarEnv) tv_eqs+ (feqs_out, feqs_in) = partitionFunEqs kick_out_ct funeqmap+ -- See Note [Kicking out CFunEqCan for fundeps]+ (dicts_out, dicts_in) = partitionDicts kick_out_ct dictmap+ (irs_out, irs_in) = partitionBag kick_out_ct irreds+ (insols_out, insols_in) = partitionBag kick_out_ct insols+ -- Kick out even insolubles: See Note [Kick out insolubles]++ fr_may_rewrite :: CtFlavourRole -> Bool+ fr_may_rewrite fs = new_fr `eqMayRewriteFR` fs+ -- Can the new item rewrite the inert item?++ kick_out_ct :: Ct -> Bool+ -- Kick it out if the new CTyEqCan can rewrite the inert one+ -- See Note [kickOutRewritable]+ kick_out_ct ct | let ev = ctEvidence ct+ = fr_may_rewrite (ctEvFlavourRole ev)+ && anyRewritableTyVar False (== new_tv) (ctEvPred ev)+ -- False: ignore casts and coercions+ -- NB: this includes the fsk of a CFunEqCan. It can't+ -- actually be rewritten, but we need to kick it out+ -- so we get to take advantage of injectivity+ -- See Note [Kicking out CFunEqCan for fundeps]++ kick_out_eqs :: EqualCtList -> ([Ct], DTyVarEnv EqualCtList)+ -> ([Ct], DTyVarEnv EqualCtList)+ kick_out_eqs eqs (acc_out, acc_in)+ = (eqs_out ++ acc_out, case eqs_in of+ [] -> acc_in+ (eq1:_) -> extendDVarEnv acc_in (cc_tyvar eq1) eqs_in)+ where+ (eqs_in, eqs_out) = partition keep_eq eqs++ -- Implements criteria K1-K3 in Note [Extending the inert equalities]+ keep_eq (CTyEqCan { cc_tyvar = tv, cc_rhs = rhs_ty, cc_ev = ev+ , cc_eq_rel = eq_rel })+ | tv == new_tv+ = not (fr_may_rewrite fs) -- (K1)++ | otherwise+ = check_k2 && check_k3+ where+ fs = ctEvFlavourRole ev+ check_k2 = not (fs `eqMayRewriteFR` fs) -- (K2a)+ || (fs `eqMayRewriteFR` new_fr) -- (K2b)+ || not (fr_may_rewrite fs) -- (K2c)+ || not (new_tv `elemVarSet` tyCoVarsOfType rhs_ty) -- (K2d)++ check_k3+ | fr_may_rewrite fs+ = case eq_rel of+ NomEq -> not (rhs_ty `eqType` mkTyVarTy new_tv)+ ReprEq -> not (isTyVarExposed new_tv rhs_ty)++ | otherwise+ = True++ keep_eq ct = pprPanic "keep_eq" (ppr ct)++kickOutAfterUnification :: TcTyVar -> TcS Int+kickOutAfterUnification new_tv+ = do { ics <- getInertCans+ ; (n_kicked, ics2) <- kickOutRewritable (Given,NomEq)+ new_tv ics+ -- Given because the tv := xi is given; NomEq because+ -- only nominal equalities are solved by unification++ ; setInertCans ics2+ ; return n_kicked }++{- Note [kickOutRewritable]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+See also Note [inert_eqs: the inert equalities].++When we add a new inert equality (a ~N ty) to the inert set,+we must kick out any inert items that could be rewritten by the+new equality, to maintain the inert-set invariants.++ - We want to kick out an existing inert constraint if+ a) the new constraint can rewrite the inert one+ b) 'a' is free in the inert constraint (so that it *will*)+ rewrite it if we kick it out.++ For (b) we use tyCoVarsOfCt, which returns the type variables /and+ the kind variables/ that are directly visible in the type. Hence+ we will have exposed all the rewriting we care about to make the+ most precise kinds visible for matching classes etc. No need to+ kick out constraints that mention type variables whose kinds+ contain this variable!++ - A Derived equality can kick out [D] constraints in inert_eqs,+ inert_dicts, inert_irreds etc.++ - We don't kick out constraints from inert_solved_dicts, and+ inert_solved_funeqs optimistically. But when we lookup we have to+ take the substitution into account+++Note [Kick out insolubles]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have an insoluble alpha ~ [alpha], which is insoluble+because an occurs check. And then we unify alpha := [Int].+Then we really want to rewrite the insoluble to [Int] ~ [[Int]].+Now it can be decomposed. Otherwise we end up with a "Can't match+[Int] ~ [[Int]]" which is true, but a bit confusing because the+outer type constructors match.+-}++++--------------+addInertSafehask :: InertCans -> Ct -> InertCans+addInertSafehask ics item@(CDictCan { cc_class = cls, cc_tyargs = tys })+ = ics { inert_safehask = addDict (inert_dicts ics) cls tys item }++addInertSafehask _ item+ = pprPanic "addInertSafehask: can't happen! Inserting " $ ppr item++insertSafeOverlapFailureTcS :: Ct -> TcS ()+-- See Note [Safe Haskell Overlapping Instances Implementation] in TcSimplify+insertSafeOverlapFailureTcS item+ = updInertCans (\ics -> addInertSafehask ics item)++getSafeOverlapFailures :: TcS Cts+-- See Note [Safe Haskell Overlapping Instances Implementation] in TcSimplify+getSafeOverlapFailures+ = do { IC { inert_safehask = safehask } <- getInertCans+ ; return $ foldDicts consCts safehask emptyCts }++--------------+addSolvedDict :: CtEvidence -> Class -> [Type] -> TcS ()+-- Add a new item in the solved set of the monad+-- See Note [Solved dictionaries]+addSolvedDict item cls tys+ | isIPPred (ctEvPred item) -- Never cache "solved" implicit parameters (not sure why!)+ = return ()+ | otherwise+ = do { traceTcS "updSolvedSetTcs:" $ ppr item+ ; updInertTcS $ \ ics ->+ ics { inert_solved_dicts = addDict (inert_solved_dicts ics) cls tys item } }++{- *********************************************************************+* *+ Other inert-set operations+* *+********************************************************************* -}++updInertTcS :: (InertSet -> InertSet) -> TcS ()+-- Modify the inert set with the supplied function+updInertTcS upd_fn+ = do { is_var <- getTcSInertsRef+ ; wrapTcS (do { curr_inert <- TcM.readTcRef is_var+ ; TcM.writeTcRef is_var (upd_fn curr_inert) }) }++getInertCans :: TcS InertCans+getInertCans = do { inerts <- getTcSInerts; return (inert_cans inerts) }++setInertCans :: InertCans -> TcS ()+setInertCans ics = updInertTcS $ \ inerts -> inerts { inert_cans = ics }++updRetInertCans :: (InertCans -> (a, InertCans)) -> TcS a+-- Modify the inert set with the supplied function+updRetInertCans upd_fn+ = do { is_var <- getTcSInertsRef+ ; wrapTcS (do { inerts <- TcM.readTcRef is_var+ ; let (res, cans') = upd_fn (inert_cans inerts)+ ; TcM.writeTcRef is_var (inerts { inert_cans = cans' })+ ; return res }) }++updInertCans :: (InertCans -> InertCans) -> TcS ()+-- Modify the inert set with the supplied function+updInertCans upd_fn+ = updInertTcS $ \ inerts -> inerts { inert_cans = upd_fn (inert_cans inerts) }++updInertDicts :: (DictMap Ct -> DictMap Ct) -> TcS ()+-- Modify the inert set with the supplied function+updInertDicts upd_fn+ = updInertCans $ \ ics -> ics { inert_dicts = upd_fn (inert_dicts ics) }++updInertSafehask :: (DictMap Ct -> DictMap Ct) -> TcS ()+-- Modify the inert set with the supplied function+updInertSafehask upd_fn+ = updInertCans $ \ ics -> ics { inert_safehask = upd_fn (inert_safehask ics) }++updInertFunEqs :: (FunEqMap Ct -> FunEqMap Ct) -> TcS ()+-- Modify the inert set with the supplied function+updInertFunEqs upd_fn+ = updInertCans $ \ ics -> ics { inert_funeqs = upd_fn (inert_funeqs ics) }++updInertIrreds :: (Cts -> Cts) -> TcS ()+-- Modify the inert set with the supplied function+updInertIrreds upd_fn+ = updInertCans $ \ ics -> ics { inert_irreds = upd_fn (inert_irreds ics) }++getInertEqs :: TcS (DTyVarEnv EqualCtList)+getInertEqs = do { inert <- getInertCans; return (inert_eqs inert) }++getInertInsols :: TcS Cts+getInertInsols = do { inert <- getInertCans; return (inert_insols inert) }++getInertGivens :: TcS [Ct]+-- Returns the Given constraints in the inert set,+-- with type functions *not* unflattened+getInertGivens+ = do { inerts <- getInertCans+ ; let all_cts = foldDicts (:) (inert_dicts inerts)+ $ foldFunEqs (:) (inert_funeqs inerts)+ $ concat (dVarEnvElts (inert_eqs inerts))+ ; return (filter isGivenCt all_cts) }++getPendingScDicts :: TcS [Ct]+-- Find all inert Given dictionaries whose cc_pend_sc flag is True+-- Set the flag to False in the inert set, and return that Ct+getPendingScDicts = updRetInertCans get_sc_dicts+ where+ get_sc_dicts ic@(IC { inert_dicts = dicts })+ = (sc_pend_dicts, ic')+ where+ ic' = ic { inert_dicts = foldr add dicts sc_pend_dicts }++ sc_pend_dicts :: [Ct]+ sc_pend_dicts = foldDicts get_pending dicts []++ get_pending :: Ct -> [Ct] -> [Ct] -- Get dicts with cc_pend_sc = True+ -- but flipping the flag+ get_pending dict dicts+ | Just dict' <- isPendingScDict dict = dict' : dicts+ | otherwise = dicts++ add :: Ct -> DictMap Ct -> DictMap Ct+ add ct@(CDictCan { cc_class = cls, cc_tyargs = tys }) dicts+ = addDict dicts cls tys ct+ add ct _ = pprPanic "getPendingScDicts" (ppr ct)++getUnsolvedInerts :: TcS ( Bag Implication+ , Cts -- Tyvar eqs: a ~ ty+ , Cts -- Fun eqs: F a ~ ty+ , Cts -- Insoluble+ , Cts ) -- All others+-- Return all the unsolved [Wanted] or [Derived] constraints+--+-- Post-condition: the returned simple constraints are all fully zonked+-- (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_dicts = idicts+ , inert_insols = insols+ } <- getInertCans++ ; let unsolved_tv_eqs = foldTyEqs add_if_unsolved tv_eqs emptyCts+ unsolved_fun_eqs = foldFunEqs add_if_wanted fun_eqs emptyCts+ unsolved_irreds = Bag.filterBag is_unsolved irreds+ unsolved_dicts = foldDicts add_if_unsolved idicts emptyCts+ unsolved_others = unsolved_irreds `unionBags` unsolved_dicts+ unsolved_insols = filterBag is_unsolved insols++ ; implics <- getWorkListImplics++ ; traceTcS "getUnsolvedInerts" $+ vcat [ text " tv eqs =" <+> ppr unsolved_tv_eqs+ , text "fun eqs =" <+> ppr unsolved_fun_eqs+ , text "insols =" <+> ppr unsolved_insols+ , text "others =" <+> ppr unsolved_others+ , text "implics =" <+> ppr implics ]++ ; return ( implics, unsolved_tv_eqs, unsolved_fun_eqs+ , unsolved_insols, unsolved_others) }+ where+ add_if_unsolved :: Ct -> Cts -> Cts+ add_if_unsolved ct cts | is_unsolved ct = ct `consCts` cts+ | otherwise = cts++ is_unsolved ct = not (isGivenCt ct) -- Wanted or Derived++ -- For CFunEqCans we ignore the Derived ones, and keep+ -- only the Wanteds for flattening. The Derived ones+ -- share a unification variable with the corresponding+ -- Wanted, so we definitely don't want to to participate+ -- in unflattening+ -- See Note [Type family equations]+ add_if_wanted ct cts | isWantedCt ct = ct `consCts` cts+ | otherwise = cts++isInInertEqs :: DTyVarEnv EqualCtList -> TcTyVar -> TcType -> Bool+-- True if (a ~N ty) is in the inert set, in either Given or Wanted+isInInertEqs eqs tv rhs+ = case lookupDVarEnv eqs tv of+ Nothing -> False+ Just cts -> any (same_pred rhs) cts+ where+ same_pred rhs ct+ | CTyEqCan { cc_rhs = rhs2, cc_eq_rel = eq_rel } <- ct+ , NomEq <- eq_rel+ , rhs `eqType` rhs2 = True+ | otherwise = False++getNoGivenEqs :: TcLevel -- TcLevel of this implication+ -> [TcTyVar] -- Skolems of this implication+ -> TcS ( Bool -- True <=> definitely no residual given equalities+ , Cts ) -- Insoluble constraints arising from givens+-- See Note [When does an implication have given equalities?]+getNoGivenEqs tclvl skol_tvs+ = do { inerts@(IC { inert_eqs = ieqs, inert_irreds = iirreds+ , inert_funeqs = funeqs+ , inert_insols = insols })+ <- getInertCans+ ; let local_fsks = foldFunEqs add_fsk funeqs emptyVarSet++ has_given_eqs = foldrBag ((||) . ev_given_here . ctEvidence) False+ (iirreds `unionBags` insols)+ || anyDVarEnv (eqs_given_here local_fsks) ieqs++ ; traceTcS "getNoGivenEqs" (vcat [ ppr has_given_eqs, ppr inerts+ , ppr insols])+ ; return (not has_given_eqs, insols) }+ where+ eqs_given_here :: VarSet -> EqualCtList -> Bool+ eqs_given_here local_fsks [CTyEqCan { cc_tyvar = tv, cc_ev = ev }]+ -- Givens are always a sigleton+ = not (skolem_bound_here local_fsks tv) && ev_given_here ev+ eqs_given_here _ _ = False++ ev_given_here :: CtEvidence -> Bool+ -- True for a Given bound by the curent implication,+ -- i.e. the current level+ ev_given_here ev+ = isGiven ev+ && tclvl == ctLocLevel (ctEvLoc ev)++ add_fsk :: Ct -> VarSet -> VarSet+ add_fsk ct fsks | CFunEqCan { cc_fsk = tv, cc_ev = ev } <- ct+ , isGiven ev = extendVarSet fsks tv+ | otherwise = fsks++ skol_tv_set = mkVarSet skol_tvs+ skolem_bound_here local_fsks tv -- See Note [Let-bound skolems]+ = case tcTyVarDetails tv of+ SkolemTv {} -> tv `elemVarSet` skol_tv_set+ FlatSkol {} -> not (tv `elemVarSet` local_fsks)+ _ -> False++-- | Returns Given constraints that might,+-- potentially, match the given pred. This is used when checking to see if a+-- Given might overlap with an instance. See Note [Instance and Given overlap]+-- in TcInteract.+matchableGivens :: CtLoc -> PredType -> InertSet -> Cts+matchableGivens loc_w pred (IS { inert_cans = inert_cans })+ = filterBag matchable_given all_relevant_givens+ where+ -- just look in class constraints and irreds. matchableGivens does get called+ -- for ~R constraints, but we don't need to look through equalities, because+ -- canonical equalities are used for rewriting. We'll only get caught by+ -- non-canonical -- that is, irreducible -- equalities.+ all_relevant_givens :: Cts+ all_relevant_givens+ | Just (clas, _) <- getClassPredTys_maybe pred+ = findDictsByClass (inert_dicts inert_cans) clas+ `unionBags` inert_irreds inert_cans+ | otherwise+ = inert_irreds inert_cans++ matchable_given :: Ct -> Bool+ matchable_given ct+ | CtGiven { ctev_loc = loc_g } <- ctev+ , Just _ <- tcUnifyTys bind_meta_tv [ctEvPred ctev] [pred]+ , not (prohibitedSuperClassSolve loc_g loc_w)+ = True++ | otherwise+ = False+ where+ ctev = cc_ev ct++ bind_meta_tv :: TcTyVar -> BindFlag+ -- Any meta tyvar may be unified later, so we treat it as+ -- bindable when unifying with givens. That ensures that we+ -- conservatively assume that a meta tyvar might get unified with+ -- something that matches the 'given', until demonstrated+ -- otherwise.+ bind_meta_tv tv | isMetaTyVar tv = BindMe+ | otherwise = Skolem++prohibitedSuperClassSolve :: CtLoc -> CtLoc -> Bool+-- See Note [Solving superclass constraints] in TcInstDcls+prohibitedSuperClassSolve from_loc solve_loc+ | GivenOrigin (InstSC given_size) <- ctLocOrigin from_loc+ , ScOrigin wanted_size <- ctLocOrigin solve_loc+ = given_size >= wanted_size+ | otherwise+ = False++{- Note [Unsolved Derived equalities]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In getUnsolvedInerts, we return a derived equality from the inert_eqs+because it is a candidate for floating out of this implication. We+only float equalities with a meta-tyvar on the left, so we only pull+those out here.++Note [When does an implication have given equalities?]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider an implication+ beta => alpha ~ Int+where beta is a unification variable that has already been unified+to () in an outer scope. Then we can float the (alpha ~ Int) out+just fine. So when deciding whether the givens contain an equality,+we should canonicalise first, rather than just looking at the original+givens (Trac #8644).++So we simply look at the inert, canonical Givens and see if there are+any equalities among them, the calculation of has_given_eqs. There+are some wrinkles:++ * We must know which ones are bound in *this* implication and which+ are bound further out. We can find that out from the TcLevel+ of the Given, which is itself recorded in the tcl_tclvl field+ of the TcLclEnv stored in the Given (ev_given_here).++ What about interactions between inner and outer givens?+ - Outer given is rewritten by an inner given, then there must+ have been an inner given equality, hence the “given-eq” flag+ will be true anyway.++ - Inner given rewritten by outer, retains its level (ie. The inner one)++ * We must take account of *potential* equalities, like the one above:+ beta => ...blah...+ If we still don't know what beta is, we conservatively treat it as potentially+ becoming an equality. Hence including 'irreds' in the calculation or has_given_eqs.++ * When flattening givens, we generate Given equalities like+ <F [a]> : F [a] ~ f,+ with Refl evidence, and we *don't* want those to count as an equality+ in the givens! After all, the entire flattening business is just an+ internal matter, and the evidence does not mention any of the 'givens'+ of this implication. So we do not treat inert_funeqs as a 'given equality'.++ * See Note [Let-bound skolems] for another wrinkle++ * We do *not* need to worry about representational equalities, because+ these do not affect the ability to float constraints.++Note [Let-bound skolems]+~~~~~~~~~~~~~~~~~~~~~~~~+If * the inert set contains a canonical Given CTyEqCan (a ~ ty)+and * 'a' is a skolem bound in this very implication, b++then:+a) The Given is pretty much a let-binding, like+ f :: (a ~ b->c) => a -> a+ Here the equality constraint is like saying+ let a = b->c in ...+ It is not adding any new, local equality information,+ and hence can be ignored by has_given_eqs++b) 'a' will have been completely substituted out in the inert set,+ so we can safely discard it. Notably, it doesn't need to be+ returned as part of 'fsks'++For an example, see Trac #9211.+-}++removeInertCts :: [Ct] -> InertCans -> InertCans+-- ^ Remove inert constraints from the 'InertCans', for use when a+-- typechecker plugin wishes to discard a given.+removeInertCts cts icans = foldl' removeInertCt icans cts++removeInertCt :: InertCans -> Ct -> InertCans+removeInertCt is ct =+ case ct of++ CDictCan { cc_class = cl, cc_tyargs = tys } ->+ is { inert_dicts = delDict (inert_dicts is) cl tys }++ CFunEqCan { cc_fun = tf, cc_tyargs = tys } ->+ is { inert_funeqs = delFunEq (inert_funeqs is) tf tys }++ CTyEqCan { cc_tyvar = x, cc_rhs = ty } ->+ is { inert_eqs = delTyEq (inert_eqs is) x ty }++ CIrredEvCan {} -> panic "removeInertCt: CIrredEvCan"+ CNonCanonical {} -> panic "removeInertCt: CNonCanonical"+ CHoleCan {} -> panic "removeInertCt: CHoleCan"+++lookupFlatCache :: TyCon -> [Type] -> TcS (Maybe (TcCoercion, TcType, CtFlavour))+lookupFlatCache fam_tc tys+ = do { IS { inert_flat_cache = flat_cache+ , inert_cans = IC { inert_funeqs = inert_funeqs } } <- getTcSInerts+ ; return (firstJusts [lookup_inerts inert_funeqs,+ lookup_flats flat_cache]) }+ where+ lookup_inerts inert_funeqs+ | Just (CFunEqCan { cc_ev = ctev, cc_fsk = fsk, cc_tyargs = xis })+ <- findFunEq inert_funeqs fam_tc tys+ , tys `eqTypes` xis -- The lookup might find a near-match; see+ -- Note [Use loose types in inert set]+ = Just (ctEvCoercion ctev, mkTyVarTy fsk, ctEvFlavour ctev)+ | otherwise = Nothing++ lookup_flats flat_cache = findExactFunEq flat_cache fam_tc tys+++lookupInInerts :: TcPredType -> TcS (Maybe CtEvidence)+-- Is this exact predicate type cached in the solved or canonicals of the InertSet?+lookupInInerts pty+ | ClassPred cls tys <- classifyPredType pty+ = do { inerts <- getTcSInerts+ ; return (lookupSolvedDict inerts cls tys `mplus`+ lookupInertDict (inert_cans inerts) cls tys) }+ | otherwise -- NB: No caching for equalities, IPs, holes, or errors+ = return Nothing++-- | Look up a dictionary inert. NB: the returned 'CtEvidence' might not+-- match the input exactly. Note [Use loose types in inert set].+lookupInertDict :: InertCans -> Class -> [Type] -> Maybe CtEvidence+lookupInertDict (IC { inert_dicts = dicts }) cls tys+ = case findDict dicts cls tys of+ Just ct -> Just (ctEvidence ct)+ _ -> Nothing++-- | Look up a solved inert. NB: the returned 'CtEvidence' might not+-- match the input exactly. See Note [Use loose types in inert set].+lookupSolvedDict :: InertSet -> Class -> [Type] -> Maybe CtEvidence+-- Returns just if exactly this predicate type exists in the solved.+lookupSolvedDict (IS { inert_solved_dicts = solved }) cls tys+ = case findDict solved cls tys of+ Just ev -> Just ev+ _ -> Nothing++{- *********************************************************************+* *+ Irreds+* *+********************************************************************* -}++foldIrreds :: (Ct -> b -> b) -> Cts -> b -> b+foldIrreds k irreds z = foldrBag k z irreds+++{- *********************************************************************+* *+ TcAppMap+* *+************************************************************************++Note [Use loose types in inert set]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Say we know (Eq (a |> c1)) and we need (Eq (a |> c2)). One is clearly+solvable from the other. So, we do lookup in the inert set using+loose types, which omit the kind-check.++We must be careful when using the result of a lookup because it may+not match the requsted info exactly!++-}++type TcAppMap a = UniqDFM (ListMap LooseTypeMap a)+ -- Indexed by tycon then the arg types, using "loose" matching, where+ -- we don't require kind equality. This allows, for example, (a |> co)+ -- to match (a).+ -- See Note [Use loose types in inert set]+ -- Used for types and classes; hence UniqDFM+ -- See Note [foldTM determinism] for why we use UniqDFM here++isEmptyTcAppMap :: TcAppMap a -> Bool+isEmptyTcAppMap m = isNullUDFM m++emptyTcAppMap :: TcAppMap a+emptyTcAppMap = emptyUDFM++findTcApp :: TcAppMap a -> Unique -> [Type] -> Maybe a+findTcApp m u tys = do { tys_map <- lookupUDFM m u+ ; lookupTM tys tys_map }++delTcApp :: TcAppMap a -> Unique -> [Type] -> TcAppMap a+delTcApp m cls tys = adjustUDFM (deleteTM tys) m cls++insertTcApp :: TcAppMap a -> Unique -> [Type] -> a -> TcAppMap a+insertTcApp m cls tys ct = alterUDFM alter_tm m cls+ where+ alter_tm mb_tm = Just (insertTM tys ct (mb_tm `orElse` emptyTM))++-- mapTcApp :: (a->b) -> TcAppMap a -> TcAppMap b+-- mapTcApp f = mapUDFM (mapTM f)++filterTcAppMap :: (Ct -> Bool) -> TcAppMap Ct -> TcAppMap Ct+filterTcAppMap f m+ = mapUDFM do_tm m+ where+ do_tm tm = foldTM insert_mb tm emptyTM+ insert_mb ct tm+ | f ct = insertTM tys ct tm+ | otherwise = tm+ where+ tys = case ct of+ CFunEqCan { cc_tyargs = tys } -> tys+ CDictCan { cc_tyargs = tys } -> tys+ _ -> pprPanic "filterTcAppMap" (ppr ct)++tcAppMapToBag :: TcAppMap a -> Bag a+tcAppMapToBag m = foldTcAppMap consBag m emptyBag++foldTcAppMap :: (a -> b -> b) -> TcAppMap a -> b -> b+foldTcAppMap k m z = foldUDFM (foldTM k) z m+++{- *********************************************************************+* *+ DictMap+* *+********************************************************************* -}++type DictMap a = TcAppMap a++emptyDictMap :: DictMap a+emptyDictMap = emptyTcAppMap++-- sizeDictMap :: DictMap a -> Int+-- sizeDictMap m = foldDicts (\ _ x -> x+1) m 0++findDict :: DictMap a -> Class -> [Type] -> Maybe a+findDict m cls tys = findTcApp m (getUnique cls) tys++findDictsByClass :: DictMap a -> Class -> Bag a+findDictsByClass m cls+ | Just tm <- lookupUDFM m cls = foldTM consBag tm emptyBag+ | otherwise = emptyBag++delDict :: DictMap a -> Class -> [Type] -> DictMap a+delDict m cls tys = delTcApp m (getUnique cls) tys++addDict :: DictMap a -> Class -> [Type] -> a -> DictMap a+addDict m cls tys item = insertTcApp m (getUnique cls) tys item++addDictsByClass :: DictMap Ct -> Class -> Bag Ct -> DictMap Ct+addDictsByClass m cls items+ = addToUDFM m cls (foldrBag add emptyTM items)+ where+ add ct@(CDictCan { cc_tyargs = tys }) tm = insertTM tys ct tm+ add ct _ = pprPanic "addDictsByClass" (ppr ct)++filterDicts :: (Ct -> Bool) -> DictMap Ct -> DictMap Ct+filterDicts f m = filterTcAppMap f m++partitionDicts :: (Ct -> Bool) -> DictMap Ct -> (Bag Ct, DictMap Ct)+partitionDicts f m = foldTcAppMap k m (emptyBag, emptyDicts)+ where+ k ct (yeses, noes) | f ct = (ct `consBag` yeses, noes)+ | otherwise = (yeses, add ct noes)+ add ct@(CDictCan { cc_class = cls, cc_tyargs = tys }) m+ = addDict m cls tys ct+ add ct _ = pprPanic "partitionDicts" (ppr ct)++dictsToBag :: DictMap a -> Bag a+dictsToBag = tcAppMapToBag++foldDicts :: (a -> b -> b) -> DictMap a -> b -> b+foldDicts = foldTcAppMap++emptyDicts :: DictMap a+emptyDicts = emptyTcAppMap+++{- *********************************************************************+* *+ FunEqMap+* *+********************************************************************* -}++type FunEqMap a = TcAppMap a -- A map whose key is a (TyCon, [Type]) pair++emptyFunEqs :: TcAppMap a+emptyFunEqs = emptyTcAppMap++findFunEq :: FunEqMap a -> TyCon -> [Type] -> Maybe a+findFunEq m tc tys = findTcApp m (getUnique tc) tys++funEqsToBag :: FunEqMap a -> Bag a+funEqsToBag m = foldTcAppMap consBag m emptyBag++findFunEqsByTyCon :: FunEqMap a -> TyCon -> [a]+-- Get inert function equation constraints that have the given tycon+-- in their head. Not that the constraints remain in the inert set.+-- We use this to check for derived interactions with built-in type-function+-- constructors.+findFunEqsByTyCon m tc+ | Just tm <- lookupUDFM m tc = foldTM (:) tm []+ | otherwise = []++foldFunEqs :: (a -> b -> b) -> FunEqMap a -> b -> b+foldFunEqs = foldTcAppMap++-- mapFunEqs :: (a -> b) -> FunEqMap a -> FunEqMap b+-- mapFunEqs = mapTcApp++-- filterFunEqs :: (Ct -> Bool) -> FunEqMap Ct -> FunEqMap Ct+-- filterFunEqs = filterTcAppMap++insertFunEq :: FunEqMap a -> TyCon -> [Type] -> a -> FunEqMap a+insertFunEq m tc tys val = insertTcApp m (getUnique tc) tys val++partitionFunEqs :: (Ct -> Bool) -> FunEqMap Ct -> ([Ct], FunEqMap Ct)+-- Optimise for the case where the predicate is false+-- partitionFunEqs is called only from kick-out, and kick-out usually+-- kicks out very few equalities, so we want to optimise for that case+partitionFunEqs f m = (yeses, foldr del m yeses)+ where+ yeses = foldTcAppMap k m []+ k ct yeses | f ct = ct : yeses+ | otherwise = yeses+ del (CFunEqCan { cc_fun = tc, cc_tyargs = tys }) m+ = delFunEq m tc tys+ del ct _ = pprPanic "partitionFunEqs" (ppr ct)++delFunEq :: FunEqMap a -> TyCon -> [Type] -> FunEqMap a+delFunEq m tc tys = delTcApp m (getUnique tc) tys++------------------------------+type ExactFunEqMap a = UniqFM (ListMap TypeMap a)++emptyExactFunEqs :: ExactFunEqMap a+emptyExactFunEqs = emptyUFM++findExactFunEq :: ExactFunEqMap a -> TyCon -> [Type] -> Maybe a+findExactFunEq m tc tys = do { tys_map <- lookupUFM m (getUnique tc)+ ; lookupTM tys tys_map }++insertExactFunEq :: ExactFunEqMap a -> TyCon -> [Type] -> a -> ExactFunEqMap a+insertExactFunEq m tc tys val = alterUFM alter_tm m (getUnique tc)+ where alter_tm mb_tm = Just (insertTM tys val (mb_tm `orElse` emptyTM))++{-+************************************************************************+* *+* The TcS solver monad *+* *+************************************************************************++Note [The TcS monad]+~~~~~~~~~~~~~~~~~~~~+The TcS monad is a weak form of the main Tc monad++All you can do is+ * fail+ * allocate new variables+ * fill in evidence variables++Filling in a dictionary evidence variable means to create a binding+for it, so TcS carries a mutable location where the binding can be+added. This is initialised from the innermost implication constraint.+-}++data TcSEnv+ = TcSEnv {+ tcs_ev_binds :: EvBindsVar,++ tcs_unified :: IORef Int,+ -- The number of unification variables we have filled+ -- The important thing is whether it is non-zero++ tcs_count :: IORef Int, -- Global step count++ tcs_inerts :: IORef InertSet, -- Current inert set++ -- The main work-list and the flattening worklist+ -- See Note [Work list priorities] and+ tcs_worklist :: IORef WorkList -- Current worklist+ }++---------------+newtype TcS a = TcS { unTcS :: TcSEnv -> TcM a }++instance Functor TcS where+ fmap f m = TcS $ fmap f . unTcS m++instance Applicative TcS where+ pure x = TcS (\_ -> return x)+ (<*>) = ap++instance Monad TcS where+ fail err = TcS (\_ -> fail err)+ m >>= k = TcS (\ebs -> unTcS m ebs >>= \r -> unTcS (k r) ebs)++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail TcS where+ fail err = TcS (\_ -> fail err)+#endif++instance MonadUnique TcS where+ getUniqueSupplyM = wrapTcS getUniqueSupplyM++-- Basic functionality+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+wrapTcS :: TcM a -> TcS a+-- Do not export wrapTcS, because it promotes an arbitrary TcM to TcS,+-- and TcS is supposed to have limited functionality+wrapTcS = TcS . const -- a TcM action will not use the TcEvBinds++wrapErrTcS :: TcM a -> TcS a+-- The thing wrapped should just fail+-- There's no static check; it's up to the user+-- Having a variant for each error message is too painful+wrapErrTcS = wrapTcS++wrapWarnTcS :: TcM a -> TcS a+-- The thing wrapped should just add a warning, or no-op+-- There's no static check; it's up to the user+wrapWarnTcS = wrapTcS++failTcS, panicTcS :: SDoc -> TcS a+warnTcS :: WarningFlag -> SDoc -> TcS ()+addErrTcS :: SDoc -> TcS ()+failTcS = wrapTcS . TcM.failWith+warnTcS flag = wrapTcS . TcM.addWarn (Reason flag)+addErrTcS = wrapTcS . TcM.addErr+panicTcS doc = pprPanic "TcCanonical" doc++traceTcS :: String -> SDoc -> TcS ()+traceTcS herald doc = wrapTcS (TcM.traceTc herald doc)++runTcPluginTcS :: TcPluginM a -> TcS a+runTcPluginTcS m = wrapTcS . runTcPluginM m =<< getTcEvBindsVar++instance HasDynFlags TcS where+ getDynFlags = wrapTcS getDynFlags++getGlobalRdrEnvTcS :: TcS GlobalRdrEnv+getGlobalRdrEnvTcS = wrapTcS TcM.getGlobalRdrEnv++bumpStepCountTcS :: TcS ()+bumpStepCountTcS = TcS $ \env -> do { let ref = tcs_count env+ ; n <- TcM.readTcRef ref+ ; TcM.writeTcRef ref (n+1) }++csTraceTcS :: SDoc -> TcS ()+csTraceTcS doc+ = wrapTcS $ csTraceTcM (return doc)++traceFireTcS :: CtEvidence -> SDoc -> TcS ()+-- Dump a rule-firing trace+traceFireTcS ev doc+ = TcS $ \env -> csTraceTcM $+ do { n <- TcM.readTcRef (tcs_count env)+ ; tclvl <- TcM.getTcLevel+ ; return (hang (text "Step" <+> int n+ <> brackets (text "l:" <> ppr tclvl <> comma <>+ text "d:" <> ppr (ctLocDepth (ctEvLoc ev)))+ <+> doc <> colon)+ 4 (ppr ev)) }++csTraceTcM :: TcM SDoc -> TcM ()+-- Constraint-solver tracing, -ddump-cs-trace+csTraceTcM mk_doc+ = do { dflags <- getDynFlags+ ; when ( dopt Opt_D_dump_cs_trace dflags+ || dopt Opt_D_dump_tc_trace dflags )+ ( do { msg <- mk_doc+ ; TcM.traceTcRn Opt_D_dump_cs_trace msg }) }++runTcS :: TcS a -- What to run+ -> TcM (a, EvBindMap)+runTcS tcs+ = do { ev_binds_var <- TcM.newTcEvBinds+ ; 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.+runTcSDeriveds :: TcS a -> TcM a+runTcSDeriveds tcs+ = do { ev_binds_var <- TcM.newTcEvBinds+ ; runTcSWithEvBinds ev_binds_var tcs }++-- | This can deal only with equality constraints.+runTcSEqualities :: TcS a -> TcM a+runTcSEqualities thing_inside+ = do { ev_binds_var <- TcM.newTcEvBinds+ ; runTcSWithEvBinds ev_binds_var thing_inside }++runTcSWithEvBinds :: EvBindsVar+ -> TcS a+ -> TcM a+runTcSWithEvBinds 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+ ; let env = TcSEnv { tcs_ev_binds = ev_binds_var+ , tcs_unified = unified_var+ , tcs_count = step_count+ , tcs_inerts = inert_var+ , tcs_worklist = wl_var }++ -- Run the computation+ ; res <- unTcS tcs env++ ; count <- TcM.readTcRef step_count+ ; when (count > 0) $+ csTraceTcM $ return (text "Constraint solver steps =" <+> int count)++#ifdef DEBUG+ ; ev_binds <- TcM.getTcEvBindsMap ev_binds_var+ ; checkForCyclicBinds ev_binds+#endif++ ; return res }++#ifdef DEBUG+checkForCyclicBinds :: EvBindMap -> TcM ()+checkForCyclicBinds ev_binds_map+ | null cycles+ = return ()+ | null coercion_cycles+ = TcM.traceTc "Cycle in evidence binds" $ ppr cycles+ | otherwise+ = pprPanic "Cycle in coercion bindings" $ ppr coercion_cycles+ where+ ev_binds = evBindMapBinds ev_binds_map++ cycles :: [[EvBind]]+ cycles = [c | CyclicSCC c <- stronglyConnCompFromEdgedVerticesUniq edges]++ coercion_cycles = [c | c <- cycles, any is_co_bind c]+ is_co_bind (EvBind { eb_lhs = b }) = isEqPred (varType b)++ edges :: [(EvBind, EvVar, [EvVar])]+ edges = [ (bind, bndr, nonDetEltsUniqSet (evVarsOfTerm rhs))+ | bind@(EvBind { eb_lhs = bndr, eb_rhs = rhs}) <- bagToList ev_binds ]+ -- It's OK to use nonDetEltsUFM here as+ -- stronglyConnCompFromEdgedVertices is still deterministic even+ -- if the edges are in nondeterministic order as explained in+ -- Note [Deterministic SCC] in Digraph.+#endif++setEvBindsTcS :: EvBindsVar -> TcS a -> TcS a+setEvBindsTcS ref (TcS thing_inside)+ = TcS $ \ env -> thing_inside (env { tcs_ev_binds = ref })++nestImplicTcS :: EvBindsVar+ -> 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+ } ->+ do { inerts <- TcM.readTcRef old_inert_var+ ; let nest_inert = inerts { inert_flat_cache = emptyExactFunEqs }+ -- See Note [Do not inherit the flat cache]+ ; new_inert_var <- TcM.newTcRef nest_inert+ ; new_wl_var <- TcM.newTcRef emptyWorkList+ ; let nest_env = TcSEnv { tcs_ev_binds = ref+ , tcs_unified = unified_var+ , tcs_count = count+ , tcs_inerts = new_inert_var+ , tcs_worklist = new_wl_var }+ ; res <- TcM.setTcLevel inner_tclvl $+ thing_inside nest_env++#ifdef DEBUG+ -- Perform a check that the thing_inside did not cause cycles+ ; ev_binds <- TcM.getTcEvBindsMap ref+ ; checkForCyclicBinds ev_binds+#endif+ ; return res }++{- Note [Do not inherit the flat cache]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do not want to inherit the flat cache when processing nested+implications. Consider+ a ~ F b, forall c. b~Int => blah+If we have F b ~ fsk in the flat-cache, and we push that into the+nested implication, we might miss that F b can be rewritten to F Int,+and hence perhpas solve it. Moreover, the fsk from outside is+flattened out after solving the outer level, but and we don't+do that flattening recursively.+-}++nestTcS :: TcS a -> TcS a+-- Use the current untouchables, augmenting the current+-- evidence bindings, and solved dictionaries+-- But have no effect on the InertCans, or on the inert_flat_cache+-- (we want to inherit the latter from processing the Givens)+nestTcS (TcS thing_inside)+ = TcS $ \ env@(TcSEnv { tcs_inerts = inerts_var }) ->+ do { inerts <- TcM.readTcRef inerts_var+ ; new_inert_var <- TcM.newTcRef inerts+ ; new_wl_var <- TcM.newTcRef emptyWorkList+ ; let nest_env = env { tcs_inerts = new_inert_var+ , tcs_worklist = new_wl_var }++ ; res <- thing_inside nest_env++ ; new_inerts <- TcM.readTcRef new_inert_var++ -- we want to propogate the safe haskell failures+ ; let old_ic = inert_cans inerts+ new_ic = inert_cans new_inerts+ nxt_ic = old_ic { inert_safehask = inert_safehask new_ic }++ ; TcM.writeTcRef inerts_var -- See Note [Propagate the solved dictionaries]+ (inerts { inert_solved_dicts = inert_solved_dicts new_inerts+ , inert_cans = nxt_ic })++ ; return res }++buildImplication :: SkolemInfo+ -> [TcTyVar] -- Skolems+ -> [EvVar] -- Givens+ -> TcS result+ -> TcS (Bag Implication, TcEvBinds, result)+-- Just like TcUnify.buildImplication, but in the TcS monnad,+-- using the work-list to gather the constraints+buildImplication skol_info skol_tvs givens (TcS thing_inside)+ = TcS $ \ env ->+ do { new_wl_var <- TcM.newTcRef emptyWorkList+ ; tc_lvl <- TcM.getTcLevel+ ; let new_tclvl = pushTcLevel tc_lvl++ ; res <- TcM.setTcLevel new_tclvl $+ thing_inside (env { tcs_worklist = new_wl_var })++ ; wl@WL { wl_eqs = eqs } <- TcM.readTcRef new_wl_var+ ; if null eqs+ then return (emptyBag, emptyTcEvBinds, res)+ else+ do { env <- TcM.getLclEnv+ ; ev_binds_var <- TcM.newTcEvBinds+ ; let wc = ASSERT2( null (wl_funeqs wl) && null (wl_rest wl) &&+ null (wl_deriv wl) && null (wl_implics wl), ppr wl )+ WC { wc_simple = listToCts eqs+ , wc_impl = emptyBag+ , wc_insol = emptyCts }+ imp = Implic { ic_tclvl = new_tclvl+ , ic_skols = skol_tvs+ , ic_no_eqs = True+ , ic_given = givens+ , ic_wanted = wc+ , ic_status = IC_Unsolved+ , ic_binds = ev_binds_var+ , ic_env = env+ , ic_needed = emptyVarSet+ , ic_info = skol_info }+ ; return (unitBag imp, TcEvBinds ev_binds_var, res) } }++{-+Note [Propagate the solved dictionaries]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's really quite important that nestTcS does not discard the solved+dictionaries from the thing_inside.+Consider+ Eq [a]+ forall b. empty => Eq [a]+We solve the simple (Eq [a]), under nestTcS, and then turn our attention to+the implications. It's definitely fine to use the solved dictionaries on+the inner implications, and it can make a signficant performance difference+if you do so.+-}++-- Getters and setters of TcEnv fields+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++-- Getter of inerts and worklist+getTcSInertsRef :: TcS (IORef InertSet)+getTcSInertsRef = TcS (return . tcs_inerts)++getTcSWorkListRef :: TcS (IORef WorkList)+getTcSWorkListRef = TcS (return . tcs_worklist)++getTcSInerts :: TcS InertSet+getTcSInerts = getTcSInertsRef >>= wrapTcS . (TcM.readTcRef)++setTcSInerts :: InertSet -> TcS ()+setTcSInerts ics = do { r <- getTcSInertsRef; wrapTcS (TcM.writeTcRef r ics) }++getWorkListImplics :: TcS (Bag Implication)+getWorkListImplics+ = do { wl_var <- getTcSWorkListRef+ ; wl_curr <- wrapTcS (TcM.readTcRef wl_var)+ ; return (wl_implics wl_curr) }++updWorkListTcS :: (WorkList -> WorkList) -> TcS ()+updWorkListTcS f+ = do { wl_var <- getTcSWorkListRef+ ; wl_curr <- wrapTcS (TcM.readTcRef wl_var)+ ; let new_work = f wl_curr+ ; wrapTcS (TcM.writeTcRef wl_var new_work) }++emitWorkNC :: [CtEvidence] -> TcS ()+emitWorkNC evs+ | null evs+ = return ()+ | otherwise+ = emitWork (map mkNonCanonical evs)++emitWork :: [Ct] -> TcS ()+emitWork cts+ = do { traceTcS "Emitting fresh work" (vcat (map ppr cts))+ ; updWorkListTcS (extendWorkListCts cts) }++emitInsoluble :: Ct -> TcS ()+-- Emits a non-canonical constraint that will stand for a frozen error in the inerts.+emitInsoluble ct+ = do { traceTcS "Emit insoluble" (ppr ct $$ pprCtLoc (ctLoc ct))+ ; updInertTcS add_insol }+ where+ this_pred = ctPred ct+ add_insol is@(IS { inert_cans = ics@(IC { inert_insols = old_insols }) })+ | already_there = is+ | otherwise = is { inert_cans = ics { inert_insols = old_insols `snocCts` ct } }+ where+ already_there = not (isWantedCt ct) && anyBag (tcEqType this_pred . ctPred) old_insols+ -- See Note [Do not add duplicate derived insolubles]++newTcRef :: a -> TcS (TcRef a)+newTcRef x = wrapTcS (TcM.newTcRef x)++readTcRef :: TcRef a -> TcS a+readTcRef ref = wrapTcS (TcM.readTcRef ref)++updTcRef :: TcRef a -> (a->a) -> TcS ()+updTcRef ref upd_fn = wrapTcS (TcM.updTcRef ref upd_fn)++getTcEvBindsVar :: TcS EvBindsVar+getTcEvBindsVar = TcS (return . tcs_ev_binds)++getTcLevel :: TcS TcLevel+getTcLevel = wrapTcS TcM.getTcLevel++getTcEvBindsAndTCVs :: EvBindsVar -> TcS (EvBindMap, TyCoVarSet)+getTcEvBindsAndTCVs ev_binds_var+ = wrapTcS $ do { bnds <- TcM.getTcEvBindsMap ev_binds_var+ ; tcvs <- TcM.getTcEvTyCoVars ev_binds_var+ ; return (bnds, tcvs) }++getTcEvBindsMap :: TcS EvBindMap+getTcEvBindsMap+ = do { ev_binds_var <- getTcEvBindsVar+ ; wrapTcS $ TcM.getTcEvBindsMap ev_binds_var }++unifyTyVar :: TcTyVar -> TcType -> TcS ()+-- Unify a meta-tyvar with a type+-- We keep track of how many unifications have happened in tcs_unified,+--+-- We should never unify the same variable twice!+unifyTyVar tv ty+ = ASSERT2( isMetaTyVar tv, ppr tv )+ TcS $ \ env ->+ do { TcM.traceTc "unifyTyVar" (ppr tv <+> text ":=" <+> ppr ty)+ ; TcM.writeMetaTyVar tv ty+ ; TcM.updTcRef (tcs_unified env) (+1) }++unflattenFmv :: TcTyVar -> TcType -> TcS ()+-- Fill a flatten-meta-var, simply by unifying it.+-- This does NOT count as a unification in tcs_unified.+unflattenFmv tv ty+ = ASSERT2( isMetaTyVar tv, ppr tv )+ TcS $ \ _ ->+ do { TcM.traceTc "unflattenFmv" (ppr tv <+> text ":=" <+> ppr ty)+ ; TcM.writeMetaTyVar tv ty }++reportUnifications :: TcS a -> TcS (Int, a)+reportUnifications (TcS thing_inside)+ = TcS $ \ env ->+ do { inner_unified <- TcM.newTcRef 0+ ; res <- thing_inside (env { tcs_unified = inner_unified })+ ; n_unifs <- TcM.readTcRef inner_unified+ ; TcM.updTcRef (tcs_unified env) (+ n_unifs)+ ; return (n_unifs, res) }++getDefaultInfo :: TcS ([Type], (Bool, Bool))+getDefaultInfo = wrapTcS TcM.tcGetDefaultTys++-- Just get some environments needed for instance looking up and matching+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++getInstEnvs :: TcS InstEnvs+getInstEnvs = wrapTcS $ TcM.tcGetInstEnvs++getFamInstEnvs :: TcS (FamInstEnv, FamInstEnv)+getFamInstEnvs = wrapTcS $ FamInst.tcGetFamInstEnvs++getTopEnv :: TcS HscEnv+getTopEnv = wrapTcS $ TcM.getTopEnv++getGblEnv :: TcS TcGblEnv+getGblEnv = wrapTcS $ TcM.getGblEnv++getLclEnv :: TcS TcLclEnv+getLclEnv = wrapTcS $ TcM.getLclEnv++tcLookupClass :: Name -> TcS Class+tcLookupClass c = wrapTcS $ TcM.tcLookupClass c++tcLookupId :: Name -> TcS Id+tcLookupId n = wrapTcS $ TcM.tcLookupId n++-- Setting names as used (used in the deriving of Coercible evidence)+-- Too hackish to expose it to TcS? In that case somehow extract the used+-- constructors from the result of solveInteract+addUsedGREs :: [GlobalRdrElt] -> TcS ()+addUsedGREs gres = wrapTcS $ TcM.addUsedGREs gres++addUsedGRE :: Bool -> GlobalRdrElt -> TcS ()+addUsedGRE warn_if_deprec gre = wrapTcS $ TcM.addUsedGRE warn_if_deprec gre+++-- Various smaller utilities [TODO, maybe will be absorbed in the instance matcher]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++checkWellStagedDFun :: PredType -> DFunId -> CtLoc -> TcS ()+checkWellStagedDFun pred dfun_id loc+ = wrapTcS $ TcM.setCtLocM loc $+ do { use_stage <- TcM.getStage+ ; TcM.checkWellStaged pp_thing bind_lvl (thLevel use_stage) }+ where+ pp_thing = text "instance for" <+> quotes (ppr pred)+ bind_lvl = TcM.topIdLvl dfun_id++pprEq :: TcType -> TcType -> SDoc+pprEq ty1 ty2 = pprParendType ty1 <+> char '~' <+> pprParendType ty2++isTouchableMetaTyVarTcS :: TcTyVar -> TcS Bool+isTouchableMetaTyVarTcS tv+ = do { tclvl <- getTcLevel+ ; return $ isTouchableMetaTyVar tclvl tv }++isFilledMetaTyVar_maybe :: TcTyVar -> TcS (Maybe Type)+isFilledMetaTyVar_maybe tv+ = case tcTyVarDetails tv of+ MetaTv { mtv_ref = ref }+ -> do { cts <- wrapTcS (TcM.readTcRef ref)+ ; case cts of+ Indirect ty -> return (Just ty)+ Flexi -> return Nothing }+ _ -> return Nothing++isFilledMetaTyVar :: TcTyVar -> TcS Bool+isFilledMetaTyVar tv = wrapTcS (TcM.isFilledMetaTyVar tv)++zonkTyCoVarsAndFV :: TcTyCoVarSet -> TcS TcTyCoVarSet+zonkTyCoVarsAndFV tvs = wrapTcS (TcM.zonkTyCoVarsAndFV tvs)++zonkTyCoVarsAndFVList :: [TcTyCoVar] -> TcS [TcTyCoVar]+zonkTyCoVarsAndFVList tvs = wrapTcS (TcM.zonkTyCoVarsAndFVList tvs)++zonkCo :: Coercion -> TcS Coercion+zonkCo = wrapTcS . TcM.zonkCo++zonkTcType :: TcType -> TcS TcType+zonkTcType ty = wrapTcS (TcM.zonkTcType ty)++zonkTcTypes :: [TcType] -> TcS [TcType]+zonkTcTypes tys = wrapTcS (TcM.zonkTcTypes tys)++zonkTcTyVar :: TcTyVar -> TcS TcType+zonkTcTyVar tv = wrapTcS (TcM.zonkTcTyVar tv)++zonkSimples :: Cts -> TcS Cts+zonkSimples cts = wrapTcS (TcM.zonkSimples cts)++zonkWC :: WantedConstraints -> TcS WantedConstraints+zonkWC wc = wrapTcS (TcM.zonkWC wc)++{-+Note [Do not add duplicate derived insolubles]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In general we *must* add an insoluble (Int ~ Bool) even if there is+one such there already, because they may come from distinct call+sites. Not only do we want an error message for each, but with+-fdefer-type-errors we must generate evidence for each. But for+*derived* insolubles, we only want to report each one once. Why?++(a) A constraint (C r s t) where r -> s, say, may generate the same fundep+ equality many times, as the original constraint is successively rewritten.++(b) Ditto the successive iterations of the main solver itself, as it traverses+ the constraint tree. See example below.++Also for *given* insolubles we may get repeated errors, as we+repeatedly traverse the constraint tree. These are relatively rare+anyway, so removing duplicates seems ok. (Alternatively we could take+the SrcLoc into account.)++Note that the test does not need to be particularly efficient because+it is only used if the program has a type error anyway.++Example of (b): assume a top-level class and instance declaration:++ class D a b | a -> b+ instance D [a] [a]++Assume we have started with an implication:++ forall c. Eq c => { wc_simple = D [c] c [W] }++which we have simplified to:++ forall c. Eq c => { wc_simple = D [c] c [W]+ , wc_insols = (c ~ [c]) [D] }++For some reason, e.g. because we floated an equality somewhere else,+we might try to re-solve this implication. If we do not do a+dropDerivedWC, then we will end up trying to solve the following+constraints the second time:++ (D [c] c) [W]+ (c ~ [c]) [D]++which will result in two Deriveds to end up in the insoluble set:++ wc_simple = D [c] c [W]+ wc_insols = (c ~ [c]) [D], (c ~ [c]) [D]+-}++-- Flatten skolems+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+newFlattenSkolem :: CtFlavour -> CtLoc+ -> TyCon -> [TcType] -- F xis+ -> TcS (CtEvidence, Coercion, TcTyVar) -- [G/WD] x:: F xis ~ fsk+newFlattenSkolem flav loc tc xis+ = do { stuff@(ev, co, fsk) <- new_skolem+ ; let fsk_ty = mkTyVarTy fsk+ ; extendFlatCache tc xis (co, fsk_ty, ctEvFlavour ev)+ ; return stuff }+ where+ fam_ty = mkTyConApp tc xis++ new_skolem+ | Given <- flav+ = do { fsk <- wrapTcS (TcM.newFskTyVar fam_ty)+ ; let co = mkNomReflCo fam_ty+ ; ev <- newGivenEvVar loc (mkPrimEqPred fam_ty (mkTyVarTy fsk),+ EvCoercion co)+ ; return (ev, co, fsk) }++ | otherwise -- Generate a [WD] for both Wanted and Derived+ -- See Note [No Derived CFunEqCans]+ = do { fmv <- wrapTcS (TcM.newFmvTyVar fam_ty)+ ; (ev, hole_co) <- newWantedEq loc Nominal fam_ty (mkTyVarTy fmv)+ ; return (ev, hole_co, fmv) }++extendFlatCache :: TyCon -> [Type] -> (TcCoercion, TcType, CtFlavour) -> TcS ()+extendFlatCache tc xi_args stuff@(_, ty, fl)+ | isGivenOrWDeriv fl -- Maintain the invariant that inert_flat_cache+ -- only has [G] and [WD] CFunEqCans+ = do { dflags <- getDynFlags+ ; when (gopt Opt_FlatCache dflags) $+ do { traceTcS "extendFlatCache" (vcat [ ppr tc <+> ppr xi_args+ , ppr fl, ppr ty ])+ -- 'co' can be bottom, in the case of derived items+ ; updInertTcS $ \ is@(IS { inert_flat_cache = fc }) ->+ is { inert_flat_cache = insertExactFunEq fc tc xi_args stuff } } }++ | otherwise+ = return ()++-- Instantiations+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++instDFunType :: DFunId -> [DFunInstType] -> TcS ([TcType], TcThetaType)+instDFunType dfun_id inst_tys+ = wrapTcS $ TcM.instDFunType dfun_id inst_tys++newFlexiTcSTy :: Kind -> TcS TcType+newFlexiTcSTy knd = wrapTcS (TcM.newFlexiTyVarTy knd)++cloneMetaTyVar :: TcTyVar -> TcS TcTyVar+cloneMetaTyVar tv = wrapTcS (TcM.cloneMetaTyVar tv)++demoteUnfilledFmv :: TcTyVar -> TcS ()+-- If a flatten-meta-var is still un-filled,+-- turn it into an ordinary meta-var+demoteUnfilledFmv fmv+ = wrapTcS $ do { is_filled <- TcM.isFilledMetaTyVar fmv+ ; unless is_filled $+ do { tv_ty <- TcM.newFlexiTyVarTy (tyVarKind fmv)+ ; TcM.writeMetaTyVar fmv tv_ty } }++instFlexi :: [TKVar] -> TcS TCvSubst+instFlexi = instFlexiX emptyTCvSubst++instFlexiX :: TCvSubst -> [TKVar] -> TcS TCvSubst+instFlexiX subst tvs+ = wrapTcS (foldlM instFlexiHelper subst tvs)++instFlexiHelper :: TCvSubst -> TKVar -> TcM TCvSubst+instFlexiHelper subst tv+ = do { uniq <- TcM.newUnique+ ; details <- TcM.newMetaDetails TauTv+ ; let name = setNameUnique (tyVarName tv) uniq+ kind = substTyUnchecked subst (tyVarKind tv)+ ty' = mkTyVarTy (mkTcTyVar name kind details)+ ; return (extendTvSubst subst tv ty') }++tcInstType :: ([TyVar] -> TcM (TCvSubst, [TcTyVar]))+ -- ^ How to instantiate the type variables+ -> Id -- ^ Type to instantiate+ -> TcS ([(Name, TcTyVar)], TcThetaType, TcType) -- ^ Result+ -- (type vars, preds (incl equalities), rho)+tcInstType inst_tyvars id = wrapTcS (TcM.tcInstType inst_tyvars id)++tcInstSkolTyVarsX :: TCvSubst -> [TyVar] -> TcS (TCvSubst, [TcTyVar])+tcInstSkolTyVarsX subst tvs = wrapTcS $ TcM.tcInstSkolTyVarsX subst tvs++-- Creating and setting evidence variables and CtFlavors+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++data MaybeNew = Fresh CtEvidence | Cached EvTerm++isFresh :: MaybeNew -> Bool+isFresh (Fresh {}) = True+isFresh (Cached {}) = False++freshGoals :: [MaybeNew] -> [CtEvidence]+freshGoals mns = [ ctev | Fresh ctev <- mns ]++getEvTerm :: MaybeNew -> EvTerm+getEvTerm (Fresh ctev) = ctEvTerm ctev+getEvTerm (Cached evt) = evt++setEvBind :: EvBind -> TcS ()+setEvBind ev_bind+ = do { evb <- getTcEvBindsVar+ ; wrapTcS $ TcM.addTcEvBind evb ev_bind }++-- | Mark variables as used filling a coercion hole+useVars :: CoVarSet -> TcS ()+useVars vars+ = do { EvBindsVar { ebv_tcvs = ref } <- getTcEvBindsVar+ ; wrapTcS $+ do { tcvs <- TcM.readTcRef ref+ ; let tcvs' = tcvs `unionVarSet` vars+ ; TcM.writeTcRef ref tcvs' } }++-- | Equalities only+setWantedEq :: TcEvDest -> Coercion -> TcS ()+setWantedEq (HoleDest hole) co+ = do { useVars (coVarsOfCo co)+ ; wrapTcS $ TcM.fillCoercionHole hole co }+setWantedEq (EvVarDest ev) _ = pprPanic "setWantedEq" (ppr ev)++-- | Equalities only+setEqIfWanted :: CtEvidence -> Coercion -> TcS ()+setEqIfWanted (CtWanted { ctev_dest = dest }) co = setWantedEq dest co+setEqIfWanted _ _ = return ()++-- | Good for equalities and non-equalities+setWantedEvTerm :: TcEvDest -> EvTerm -> TcS ()+setWantedEvTerm (HoleDest hole) tm+ = do { let co = evTermCoercion tm+ ; useVars (coVarsOfCo co)+ ; wrapTcS $ TcM.fillCoercionHole hole co }+setWantedEvTerm (EvVarDest ev) tm = setWantedEvBind ev tm++setWantedEvBind :: EvVar -> EvTerm -> TcS ()+setWantedEvBind ev_id tm = setEvBind (mkWantedEvBind ev_id tm)++setEvBindIfWanted :: CtEvidence -> EvTerm -> TcS ()+setEvBindIfWanted ev tm+ = case ev of+ CtWanted { ctev_dest = dest }+ -> setWantedEvTerm dest tm+ _ -> return ()++newTcEvBinds :: TcS EvBindsVar+newTcEvBinds = wrapTcS TcM.newTcEvBinds++newEvVar :: TcPredType -> TcS EvVar+newEvVar pred = wrapTcS (TcM.newEvVar pred)++newGivenEvVar :: CtLoc -> (TcPredType, EvTerm) -> TcS CtEvidence+-- Make a new variable of the given PredType,+-- immediately bind it to the given term+-- and return its CtEvidence+-- See Note [Bind new Givens immediately] in TcRnTypes+newGivenEvVar loc (pred, rhs)+ = do { new_ev <- newBoundEvVarId pred rhs+ ; return (CtGiven { ctev_pred = pred, ctev_evar = new_ev, ctev_loc = loc }) }++-- | Make a new 'Id' of the given type, bound (in the monad's EvBinds) to the+-- given term+newBoundEvVarId :: TcPredType -> EvTerm -> TcS EvVar+newBoundEvVarId pred rhs+ = do { new_ev <- newEvVar pred+ ; setEvBind (mkGivenEvBind new_ev rhs)+ ; return new_ev }++newGivenEvVars :: CtLoc -> [(TcPredType, EvTerm)] -> TcS [CtEvidence]+newGivenEvVars loc pts = mapM (newGivenEvVar loc) pts++emitNewWantedEq :: CtLoc -> Role -> TcType -> TcType -> TcS Coercion+-- | Emit a new Wanted equality into the work-list+emitNewWantedEq loc role ty1 ty2+ | otherwise+ = do { (ev, co) <- newWantedEq loc role ty1 ty2+ ; updWorkListTcS $+ extendWorkListEq (mkNonCanonical ev)+ ; return co }++-- | Make a new equality CtEvidence+newWantedEq :: CtLoc -> Role -> TcType -> TcType -> TcS (CtEvidence, Coercion)+newWantedEq loc role ty1 ty2+ = do { hole <- wrapTcS $ TcM.newCoercionHole+ ; traceTcS "Emitting new coercion hole" (ppr hole <+> dcolon <+> ppr pty)+ ; return ( CtWanted { ctev_pred = pty, ctev_dest = HoleDest hole+ , ctev_nosh = WDeriv+ , ctev_loc = loc}+ , mkHoleCo hole role ty1 ty2 ) }+ where+ pty = mkPrimEqPredRole role ty1 ty2++-- no equalities here. Use newWantedEq instead+newWantedEvVarNC :: CtLoc -> TcPredType -> TcS CtEvidence+-- Don't look up in the solved/inerts; we know it's not there+newWantedEvVarNC loc pty+ = do { new_ev <- newEvVar pty+ ; traceTcS "Emitting new wanted" (ppr new_ev <+> dcolon <+> ppr pty $$+ pprCtLoc loc)+ ; return (CtWanted { ctev_pred = pty, ctev_dest = EvVarDest new_ev+ , ctev_nosh = WDeriv+ , ctev_loc = loc })}++newWantedEvVar :: CtLoc -> TcPredType -> TcS MaybeNew+-- For anything except ClassPred, this is the same as newWantedEvVarNC+newWantedEvVar loc pty+ = do { mb_ct <- lookupInInerts pty+ ; case mb_ct of+ Just ctev+ | not (isDerived ctev)+ -> do { traceTcS "newWantedEvVar/cache hit" $ ppr ctev+ ; return $ Cached (ctEvTerm ctev) }+ _ -> do { ctev <- newWantedEvVarNC loc pty+ ; return (Fresh ctev) } }++-- deals with both equalities and non equalities. Tries to look+-- up non-equalities in the cache+newWanted :: CtLoc -> PredType -> TcS MaybeNew+newWanted loc pty+ | Just (role, ty1, ty2) <- getEqPredTys_maybe pty+ = Fresh . fst <$> newWantedEq loc role ty1 ty2+ | otherwise+ = newWantedEvVar loc pty++-- deals with both equalities and non equalities. Doesn't do any cache lookups.+newWantedNC :: CtLoc -> PredType -> TcS CtEvidence+newWantedNC loc pty+ | Just (role, ty1, ty2) <- getEqPredTys_maybe pty+ = fst <$> newWantedEq loc role ty1 ty2+ | otherwise+ = newWantedEvVarNC loc pty++emitNewDerived :: CtLoc -> TcPredType -> TcS ()+emitNewDerived loc pred+ = do { ev <- newDerivedNC loc pred+ ; traceTcS "Emitting new derived" (ppr ev)+ ; updWorkListTcS (extendWorkListDerived loc ev) }++emitNewDeriveds :: CtLoc -> [TcPredType] -> TcS ()+emitNewDeriveds loc preds+ | null preds+ = return ()+ | otherwise+ = do { evs <- mapM (newDerivedNC loc) preds+ ; traceTcS "Emitting new deriveds" (ppr evs)+ ; updWorkListTcS (extendWorkListDeriveds loc evs) }++emitNewDerivedEq :: CtLoc -> Role -> TcType -> TcType -> TcS ()+-- Create new equality Derived and put it in the work list+-- There's no caching, no lookupInInerts+emitNewDerivedEq loc role ty1 ty2+ = do { ev <- newDerivedNC loc (mkPrimEqPredRole role ty1 ty2)+ ; traceTcS "Emitting new derived equality" (ppr ev $$ pprCtLoc loc)+ ; updWorkListTcS (extendWorkListDerived loc ev) }++newDerivedNC :: CtLoc -> TcPredType -> TcS CtEvidence+newDerivedNC loc pred+ = do { -- checkReductionDepth loc pred+ ; return (CtDerived { ctev_pred = pred, ctev_loc = loc }) }++-- --------- Check done in TcInteract.selectNewWorkItem???? ---------+-- | Checks if the depth of the given location is too much. Fails if+-- it's too big, with an appropriate error message.+checkReductionDepth :: CtLoc -> TcType -- ^ type being reduced+ -> TcS ()+checkReductionDepth loc ty+ = do { dflags <- getDynFlags+ ; when (subGoalDepthExceeded dflags (ctLocDepth loc)) $+ wrapErrTcS $+ solverDepthErrorTcS loc ty }++matchFam :: TyCon -> [Type] -> TcS (Maybe (Coercion, TcType))+matchFam tycon args = wrapTcS $ matchFamTcM tycon args++matchFamTcM :: TyCon -> [Type] -> TcM (Maybe (Coercion, TcType))+-- Given (F tys) return (ty, co), where co :: F tys ~ ty+matchFamTcM tycon args+ = do { fam_envs <- FamInst.tcGetFamInstEnvs+ ; let match_fam_result+ = reduceTyFamApp_maybe fam_envs Nominal tycon args+ ; TcM.traceTc "matchFamTcM" $+ vcat [ text "Matching:" <+> ppr (mkTyConApp tycon args)+ , ppr_res match_fam_result ]+ ; return match_fam_result }+ where+ ppr_res Nothing = text "Match failed"+ ppr_res (Just (co,ty)) = hang (text "Match succeeded:")+ 2 (vcat [ text "Rewrites to:" <+> ppr ty+ , text "Coercion:" <+> ppr co ])++{-+Note [Residual implications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The wl_implics in the WorkList are the residual implication+constraints that are generated while solving or canonicalising the+current worklist. Specifically, when canonicalising+ (forall a. t1 ~ forall a. t2)+from which we get the implication+ (forall a. t1 ~ t2)+See TcSMonad.deferTcSForAllEq+-}+
+ typecheck/TcSigs.hs view
@@ -0,0 +1,773 @@+{-+(c) The University of Glasgow 2006-2012+(c) The GRASP Project, Glasgow University, 1992-2002++-}++{-# LANGUAGE CPP #-}++module TcSigs(+ TcSigInfo(..),+ TcIdSigInfo(..), TcIdSigInst,+ TcPatSynInfo(..),+ TcSigFun,++ isPartialSig, hasCompleteSig, tcIdSigName, tcSigInfoName,+ completeSigPolyId_maybe,++ tcTySigs, tcUserTypeSig, completeSigFromId,+ tcInstSig,++ TcPragEnv, emptyPragEnv, lookupPragEnv, extendPragEnv,+ mkPragEnv, tcSpecPrags, tcSpecWrapper, tcImpPrags, addInlinePrags+ ) where++#include "HsVersions.h"++import HsSyn+import TcHsType+import TcRnTypes+import TcRnMonad+import TcType+import TcMType+import TcValidity ( checkValidType )+import TcUnify( tcSkolemise, unifyType, noThing )+import Inst( topInstantiate )+import TcEnv( tcLookupId )+import TcEvidence( HsWrapper, (<.>) )+import Type( mkTyVarBinders )++import DynFlags+import Var ( TyVar, tyVarName, tyVarKind )+import Id ( Id, idName, idType, idInlinePragma, setInlinePragma, mkLocalId )+import PrelNames( mkUnboundName )+import BasicTypes+import Bag( foldrBag )+import Module( getModule )+import Name+import NameEnv+import VarSet+import Outputable+import SrcLoc+import Util( singleton )+import Maybes( orElse )+import Data.Maybe( mapMaybe )+import Control.Monad( unless )+++{- -------------------------------------------------------------+ Note [Overview of type signatures]+----------------------------------------------------------------+Type signatures, including partial signatures, are jolly tricky,+especially on value bindings. Here's an overview.++ f :: forall a. [a] -> [a]+ g :: forall b. _ -> b++ f = ...g...+ g = ...f...++* HsSyn: a signature in a binding starts of as a TypeSig, in+ type HsBinds.Sig++* When starting a mutually recursive group, like f/g above, we+ call tcTySig on each signature in the group.++* tcTySig: Sig -> TcIdSigInfo+ - For a /complete/ signature, like 'f' above, tcTySig kind-checks+ the HsType, producing a Type, and wraps it in a CompleteSig, and+ extend the type environment with this polymorphic 'f'.++ - For a /partial/signature, like 'g' above, tcTySig does nothing+ Instead it just wraps the pieces in a PartialSig, to be handled+ later.++* tcInstSig: TcIdSigInfo -> TcIdSigInst+ In tcMonoBinds, when looking at an individual binding, we use+ tcInstSig to instantiate the signature forall's in the signature,+ and attribute that instantiated (monomorphic) type to the+ binder. You can see this in TcBinds.tcLhsId.++ The instantiation does the obvious thing for complete signatures,+ but for /partial/ signatures it starts from the HsSyn, so it+ has to kind-check it etc: tcHsPartialSigType. It's convenient+ to do this at the same time as instantiation, because we can+ make the wildcards into unification variables right away, raather+ than somehow quantifying over them. And the "TcLevel" of those+ unification variables is correct because we are in tcMonoBinds.+++Note [Scoped tyvars]+~~~~~~~~~~~~~~~~~~~~+The -XScopedTypeVariables flag brings lexically-scoped type variables+into scope for any explicitly forall-quantified type variables:+ f :: forall a. a -> a+ f x = e+Then 'a' is in scope inside 'e'.++However, we do *not* support this+ - For pattern bindings e.g+ f :: forall a. a->a+ (f,g) = e++Note [Binding scoped type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The type variables *brought into lexical scope* by a type signature+may be a subset of the *quantified type variables* of the signatures,+for two reasons:++* With kind polymorphism a signature like+ f :: forall f a. f a -> f a+ may actually give rise to+ f :: forall k. forall (f::k -> *) (a:k). f a -> f a+ So the sig_tvs will be [k,f,a], but only f,a are scoped.+ NB: the scoped ones are not necessarily the *inital* ones!++* Even aside from kind polymorphism, there may be more instantiated+ type variables than lexically-scoped ones. For example:+ type T a = forall b. b -> (a,b)+ f :: forall c. T c+ Here, the signature for f will have one scoped type variable, c,+ but two instantiated type variables, c' and b'.++However, all of this only applies to the renamer. The typechecker+just puts all of them into the type environment; any lexical-scope+errors were dealt with by the renamer.++-}+++{- *********************************************************************+* *+ Utility functions for TcSigInfo+* *+********************************************************************* -}++tcIdSigName :: TcIdSigInfo -> Name+tcIdSigName (CompleteSig { sig_bndr = id }) = idName id+tcIdSigName (PartialSig { psig_name = n }) = n++tcSigInfoName :: TcSigInfo -> Name+tcSigInfoName (TcIdSig idsi) = tcIdSigName idsi+tcSigInfoName (TcPatSynSig tpsi) = patsig_name tpsi++completeSigPolyId_maybe :: TcSigInfo -> Maybe TcId+completeSigPolyId_maybe sig+ | TcIdSig sig_info <- sig+ , CompleteSig { sig_bndr = id } <- sig_info = Just id+ | otherwise = Nothing+++{- *********************************************************************+* *+ Typechecking user signatures+* *+********************************************************************* -}++tcTySigs :: [LSig Name] -> TcM ([TcId], TcSigFun)+tcTySigs hs_sigs+ = checkNoErrs $ -- See Note [Fail eagerly on bad signatures]+ do { ty_sigs_s <- mapAndRecoverM tcTySig hs_sigs+ ; let ty_sigs = concat ty_sigs_s+ poly_ids = mapMaybe completeSigPolyId_maybe ty_sigs+ -- The returned [TcId] are the ones for which we have+ -- a complete type signature.+ -- See Note [Complete and partial type signatures]+ env = mkNameEnv [(tcSigInfoName sig, sig) | sig <- ty_sigs]+ ; return (poly_ids, lookupNameEnv env) }++tcTySig :: LSig Name -> TcM [TcSigInfo]+tcTySig (L _ (IdSig id))+ = do { let ctxt = FunSigCtxt (idName id) False+ -- False: do not report redundant constraints+ -- The user has no control over the signature!+ sig = completeSigFromId ctxt id+ ; return [TcIdSig sig] }++tcTySig (L loc (TypeSig names sig_ty))+ = setSrcSpan loc $+ do { sigs <- sequence [ tcUserTypeSig loc sig_ty (Just name)+ | L _ name <- names ]+ ; return (map TcIdSig sigs) }++tcTySig (L loc (PatSynSig names sig_ty))+ = setSrcSpan loc $+ do { tpsigs <- sequence [ tcPatSynSig name sig_ty+ | L _ name <- names ]+ ; return (map TcPatSynSig tpsigs) }++tcTySig _ = return []+++tcUserTypeSig :: SrcSpan -> LHsSigWcType Name -> Maybe Name -> TcM TcIdSigInfo+-- A function or expression type signature+-- Returns a fully quantified type signature; even the wildcards+-- are quantified with ordinary skolems that should be instantiated+--+-- The SrcSpan is what to declare as the binding site of the+-- any skolems in the signature. For function signatures we+-- use the whole `f :: ty' signature; for expression signatures+-- just the type part.+--+-- Just n => Function type signature name :: type+-- Nothing => Expression type signature <expr> :: type+tcUserTypeSig loc hs_sig_ty mb_name+ | isCompleteHsSig hs_sig_ty+ = do { sigma_ty <- tcHsSigWcType ctxt_F hs_sig_ty+ ; return $+ CompleteSig { sig_bndr = mkLocalId name sigma_ty+ , sig_ctxt = ctxt_T+ , sig_loc = loc } }+ -- Location of the <type> in f :: <type>++ -- Partial sig with wildcards+ | otherwise+ = return (PartialSig { psig_name = name, psig_hs_ty = hs_sig_ty+ , sig_ctxt = ctxt_F, sig_loc = loc })+ where+ name = case mb_name of+ Just n -> n+ Nothing -> mkUnboundName (mkVarOcc "<expression>")+ ctxt_F = case mb_name of+ Just n -> FunSigCtxt n False+ Nothing -> ExprSigCtxt+ ctxt_T = case mb_name of+ Just n -> FunSigCtxt n True+ Nothing -> ExprSigCtxt++++completeSigFromId :: UserTypeCtxt -> Id -> TcIdSigInfo+-- Used for instance methods and record selectors+completeSigFromId ctxt id+ = CompleteSig { sig_bndr = id+ , sig_ctxt = ctxt+ , sig_loc = getSrcSpan id }++isCompleteHsSig :: LHsSigWcType Name -> Bool+-- ^ If there are no wildcards, return a LHsSigType+isCompleteHsSig (HsWC { hswc_wcs = wcs }) = null wcs++{- Note [Fail eagerly on bad signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If a type signature is wrong, fail immediately:++ * the type sigs may bind type variables, so proceeding without them+ can lead to a cascade of errors++ * the type signature might be ambiguous, in which case checking+ the code against the signature will give a very similar error+ to the ambiguity error.++ToDo: this means we fall over if any type sig+is wrong (eg at the top level of the module),+which is over-conservative+-}++{- *********************************************************************+* *+ Type checking a pattern synonym signature+* *+************************************************************************++Note [Pattern synonym signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Pattern synonym signatures are surprisingly tricky (see Trac #11224 for example).+In general they look like this:++ pattern P :: forall univ_tvs. req_theta+ => forall ex_tvs. prov_theta+ => arg1 -> .. -> argn -> res_ty++For parsing and renaming we treat the signature as an ordinary LHsSigType.++Once we get to type checking, we decompose it into its parts, in tcPatSynSig.++* Note that 'forall univ_tvs' and 'req_theta =>'+ and 'forall ex_tvs' and 'prov_theta =>'+ are all optional. We gather the pieces at the the top of tcPatSynSig++* Initially the implicitly-bound tyvars (added by the renamer) include both+ universal and existential vars.++* After we kind-check the pieces and convert to Types, we do kind generalisation.++Note [The pattern-synonym signature splitting rule]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Given a pattern signature, we must split+ the kind-generalised variables, and+ the implicitly-bound variables+into universal and existential. The rule is this+(see discussion on Trac #11224):++ The universal tyvars are the ones mentioned in+ - univ_tvs: the user-specified (forall'd) universals+ - req_theta+ - res_ty+ The existential tyvars are all the rest++For example++ pattern P :: () => b -> T a+ pattern P x = ...++Here 'a' is universal, and 'b' is existential. But there is a wrinkle:+how do we split the arg_tys from req_ty? Consider++ pattern Q :: () => b -> S c -> T a+ pattern Q x = ...++This is an odd example because Q has only one syntactic argument, and+so presumably is defined by a view pattern matching a function. But+it can happen (Trac #11977, #12108).++We don't know Q's arity from the pattern signature, so we have to wait+until we see the pattern declaration itself before deciding res_ty is,+and hence which variables are existential and which are universal.++And that in turn is why TcPatSynInfo has a separate field,+patsig_implicit_bndrs, to capture the implicitly bound type variables,+because we don't yet know how to split them up.++It's a slight compromise, because it means we don't really know the+pattern synonym's real signature until we see its declaration. So,+for example, in hs-boot file, we may need to think what to do...+(eg don't have any implicitly-bound variables).+-}++tcPatSynSig :: Name -> LHsSigType Name -> TcM TcPatSynInfo+tcPatSynSig name sig_ty+ | HsIB { hsib_vars = implicit_hs_tvs+ , hsib_body = hs_ty } <- sig_ty+ , (univ_hs_tvs, hs_req, hs_ty1) <- splitLHsSigmaTy hs_ty+ , (ex_hs_tvs, hs_prov, hs_body_ty) <- splitLHsSigmaTy hs_ty1+ = do { (implicit_tvs, (univ_tvs, req, ex_tvs, prov, body_ty))+ <- solveEqualities $+ tcImplicitTKBndrs implicit_hs_tvs $+ tcExplicitTKBndrs univ_hs_tvs $ \ univ_tvs ->+ tcExplicitTKBndrs ex_hs_tvs $ \ ex_tvs ->+ do { req <- tcHsContext hs_req+ ; prov <- tcHsContext hs_prov+ ; body_ty <- tcHsOpenType hs_body_ty+ -- A (literal) pattern can be unlifted;+ -- e.g. pattern Zero <- 0# (Trac #12094)+ ; let bound_tvs+ = unionVarSets [ allBoundVariabless req+ , allBoundVariabless prov+ , allBoundVariables body_ty+ ]+ ; return ( (univ_tvs, req, ex_tvs, prov, body_ty)+ , bound_tvs) }++ -- Kind generalisation+ ; kvs <- kindGeneralize $+ build_patsyn_type [] implicit_tvs univ_tvs req+ ex_tvs prov body_ty++ -- These are /signatures/ so we zonk to squeeze out any kind+ -- unification variables. Do this after quantifyTyVars which may+ -- default kind variables to *.+ ; traceTc "about zonk" empty+ ; implicit_tvs <- mapM zonkTcTyCoVarBndr implicit_tvs+ ; univ_tvs <- mapM zonkTcTyCoVarBndr univ_tvs+ ; ex_tvs <- mapM zonkTcTyCoVarBndr ex_tvs+ ; req <- zonkTcTypes req+ ; prov <- zonkTcTypes prov+ ; body_ty <- zonkTcType body_ty++ -- Now do validity checking+ ; checkValidType ctxt $+ build_patsyn_type kvs implicit_tvs univ_tvs req ex_tvs prov body_ty++ -- arguments become the types of binders. We thus cannot allow+ -- levity polymorphism here+ ; let (arg_tys, _) = tcSplitFunTys body_ty+ ; mapM_ (checkForLevPoly empty) arg_tys++ ; traceTc "tcTySig }" $+ vcat [ text "implicit_tvs" <+> ppr_tvs implicit_tvs+ , text "kvs" <+> ppr_tvs kvs+ , text "univ_tvs" <+> ppr_tvs univ_tvs+ , text "req" <+> ppr req+ , text "ex_tvs" <+> ppr_tvs ex_tvs+ , text "prov" <+> ppr prov+ , text "body_ty" <+> ppr body_ty ]+ ; return (TPSI { patsig_name = name+ , patsig_implicit_bndrs = mkTyVarBinders Inferred kvs +++ mkTyVarBinders Specified implicit_tvs+ , patsig_univ_bndrs = univ_tvs+ , patsig_req = req+ , patsig_ex_bndrs = ex_tvs+ , patsig_prov = prov+ , patsig_body_ty = body_ty }) }+ where+ ctxt = PatSynCtxt name++ build_patsyn_type kvs imp univ req ex prov body+ = mkInvForAllTys kvs $+ mkSpecForAllTys (imp ++ univ) $+ mkFunTys req $+ mkSpecForAllTys ex $+ mkFunTys prov $+ body++ppr_tvs :: [TyVar] -> SDoc+ppr_tvs tvs = braces (vcat [ ppr tv <+> dcolon <+> ppr (tyVarKind tv)+ | tv <- tvs])+++{- *********************************************************************+* *+ Instantiating user signatures+* *+********************************************************************* -}+++tcInstSig :: TcIdSigInfo -> TcM TcIdSigInst+-- Instantiate a type signature; only used with plan InferGen+tcInstSig sig@(CompleteSig { sig_bndr = poly_id, sig_loc = loc })+ = setSrcSpan loc $ -- Set the binding site of the tyvars+ do { (tv_prs, theta, tau) <- tcInstType newMetaSigTyVars poly_id+ -- See Note [Pattern bindings and complete signatures]++ ; return (TISI { sig_inst_sig = sig+ , sig_inst_skols = tv_prs+ , sig_inst_wcs = []+ , sig_inst_wcx = Nothing+ , sig_inst_theta = theta+ , sig_inst_tau = tau }) }++tcInstSig sig@(PartialSig { psig_hs_ty = hs_ty+ , sig_ctxt = ctxt+ , sig_loc = loc })+ = setSrcSpan loc $ -- Set the binding site of the tyvars+ do { (wcs, wcx, tvs, theta, tau) <- tcHsPartialSigType ctxt hs_ty+ ; return (TISI { sig_inst_sig = sig+ , sig_inst_skols = map (\tv -> (tyVarName tv, tv)) tvs+ , sig_inst_wcs = wcs+ , sig_inst_wcx = wcx+ , sig_inst_theta = theta+ , sig_inst_tau = tau }) }+++{- Note [Pattern bindings and complete signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T a = MkT a a+ f :: forall a. a->a+ g :: forall b. b->b+ MkT f g = MkT (\x->x) (\y->y)+Here we'll infer a type from the pattern of 'T a', but if we feed in+the signature types for f and g, we'll end up unifying 'a' and 'b'++So we instantiate f and g's signature with SigTv skolems+(newMetaSigTyVars) that can unify with each other. If too much+unification takes place, we'll find out when we do the final+impedance-matching check in TcBinds.mkExport++See Note [Signature skolems] in TcType++None of this applies to a function binding with a complete+signature, which doesn't use tcInstSig. See TcBinds.tcPolyCheck.+-}++{- *********************************************************************+* *+ Pragmas and PragEnv+* *+********************************************************************* -}++type TcPragEnv = NameEnv [LSig Name]++emptyPragEnv :: TcPragEnv+emptyPragEnv = emptyNameEnv++lookupPragEnv :: TcPragEnv -> Name -> [LSig Name]+lookupPragEnv prag_fn n = lookupNameEnv prag_fn n `orElse` []++extendPragEnv :: TcPragEnv -> (Name, LSig Name) -> TcPragEnv+extendPragEnv prag_fn (n, sig) = extendNameEnv_Acc (:) singleton prag_fn n sig++---------------+mkPragEnv :: [LSig Name] -> LHsBinds Name -> TcPragEnv+mkPragEnv sigs binds+ = foldl extendPragEnv emptyNameEnv prs+ where+ prs = mapMaybe get_sig sigs++ get_sig :: LSig Name -> Maybe (Name, LSig Name)+ get_sig (L l (SpecSig lnm@(L _ nm) ty inl)) = Just (nm, L l $ SpecSig lnm ty (add_arity nm inl))+ get_sig (L l (InlineSig lnm@(L _ nm) inl)) = Just (nm, L l $ InlineSig lnm (add_arity nm inl))+ get_sig (L l (SCCFunSig st lnm@(L _ nm) str)) = Just (nm, L l $ SCCFunSig st lnm str)+ get_sig _ = Nothing++ add_arity n inl_prag -- Adjust inl_sat field to match visible arity of function+ | Inline <- inl_inline inl_prag+ -- add arity only for real INLINE pragmas, not INLINABLE+ = case lookupNameEnv ar_env n of+ Just ar -> inl_prag { inl_sat = Just ar }+ Nothing -> WARN( True, text "mkPragEnv no arity" <+> ppr n )+ -- There really should be a binding for every INLINE pragma+ inl_prag+ | otherwise+ = inl_prag++ -- ar_env maps a local to the arity of its definition+ ar_env :: NameEnv Arity+ ar_env = foldrBag lhsBindArity emptyNameEnv binds++lhsBindArity :: LHsBind Name -> NameEnv Arity -> NameEnv Arity+lhsBindArity (L _ (FunBind { fun_id = id, fun_matches = ms })) env+ = extendNameEnv env (unLoc id) (matchGroupArity ms)+lhsBindArity _ env = env -- PatBind/VarBind+++-----------------+addInlinePrags :: TcId -> [LSig Name] -> TcM TcId+addInlinePrags poly_id prags_for_me+ | inl@(L _ prag) : inls <- inl_prags+ = do { traceTc "addInlinePrag" (ppr poly_id $$ ppr prag)+ ; unless (null inls) (warn_multiple_inlines inl inls)+ ; return (poly_id `setInlinePragma` prag) }+ | otherwise+ = return poly_id+ where+ inl_prags = [L loc prag | L loc (InlineSig _ prag) <- prags_for_me]++ warn_multiple_inlines _ [] = return ()++ warn_multiple_inlines inl1@(L loc prag1) (inl2@(L _ prag2) : inls)+ | inlinePragmaActivation prag1 == inlinePragmaActivation prag2+ , isEmptyInlineSpec (inlinePragmaSpec prag1)+ = -- Tiresome: inl1 is put there by virtue of being in a hs-boot loop+ -- and inl2 is a user NOINLINE pragma; we don't want to complain+ warn_multiple_inlines inl2 inls+ | otherwise+ = setSrcSpan loc $+ addWarnTc NoReason+ (hang (text "Multiple INLINE pragmas for" <+> ppr poly_id)+ 2 (vcat (text "Ignoring all but the first"+ : map pp_inl (inl1:inl2:inls))))++ pp_inl (L loc prag) = ppr prag <+> parens (ppr loc)+++{- *********************************************************************+* *+ SPECIALISE pragmas+* *+************************************************************************++Note [Handling SPECIALISE pragmas]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The basic idea is this:++ foo :: Num a => a -> b -> a+ {-# SPECIALISE foo :: Int -> b -> Int #-}++We check that+ (forall a b. Num a => a -> b -> a)+ is more polymorphic than+ forall b. Int -> b -> Int+(for which we could use tcSubType, but see below), generating a HsWrapper+to connect the two, something like+ wrap = /\b. <hole> Int b dNumInt+This wrapper is put in the TcSpecPrag, in the ABExport record of+the AbsBinds.+++ f :: (Eq a, Ix b) => a -> b -> Bool+ {-# SPECIALISE f :: (Ix p, Ix q) => Int -> (p,q) -> Bool #-}+ f = <poly_rhs>++From this the typechecker generates++ AbsBinds [ab] [d1,d2] [([ab], f, f_mono, prags)] binds++ SpecPrag (wrap_fn :: forall a b. (Eq a, Ix b) => XXX+ -> forall p q. (Ix p, Ix q) => XXX[ Int/a, (p,q)/b ])++From these we generate:++ Rule: forall p, q, (dp:Ix p), (dq:Ix q).+ f Int (p,q) dInt ($dfInPair dp dq) = f_spec p q dp dq++ Spec bind: f_spec = wrap_fn <poly_rhs>++Note that++ * The LHS of the rule may mention dictionary *expressions* (eg+ $dfIxPair dp dq), and that is essential because the dp, dq are+ needed on the RHS.++ * The RHS of f_spec, <poly_rhs> has a *copy* of 'binds', so that it+ can fully specialise it.++++From the TcSpecPrag, in DsBinds we generate a binding for f_spec and a RULE:++ f_spec :: Int -> b -> Int+ f_spec = wrap<f rhs>++ RULE: forall b (d:Num b). f b d = f_spec b++The RULE is generated by taking apart the HsWrapper, which is a little+delicate, but works.++Some wrinkles++1. We don't use full-on tcSubType, because that does co and contra+ variance and that in turn will generate too complex a LHS for the+ RULE. So we use a single invocation of skolemise /+ topInstantiate in tcSpecWrapper. (Actually I think that even+ the "deeply" stuff may be too much, because it introduces lambdas,+ though I think it can be made to work without too much trouble.)++2. We need to take care with type families (Trac #5821). Consider+ type instance F Int = Bool+ f :: Num a => a -> F a+ {-# SPECIALISE foo :: Int -> Bool #-}++ We *could* try to generate an f_spec with precisely the declared type:+ f_spec :: Int -> Bool+ f_spec = <f rhs> Int dNumInt |> co++ RULE: forall d. f Int d = f_spec |> sym co++ but the 'co' and 'sym co' are (a) playing no useful role, and (b) are+ hard to generate. At all costs we must avoid this:+ RULE: forall d. f Int d |> co = f_spec+ because the LHS will never match (indeed it's rejected in+ decomposeRuleLhs).++ So we simply do this:+ - Generate a constraint to check that the specialised type (after+ skolemiseation) is equal to the instantiated function type.+ - But *discard* the evidence (coercion) for that constraint,+ so that we ultimately generate the simpler code+ f_spec :: Int -> F Int+ f_spec = <f rhs> Int dNumInt++ RULE: forall d. f Int d = f_spec+ You can see this discarding happening in++3. Note that the HsWrapper can transform *any* function with the right+ type prefix+ forall ab. (Eq a, Ix b) => XXX+ regardless of XXX. It's sort of polymorphic in XXX. This is+ useful: we use the same wrapper to transform each of the class ops, as+ well as the dict. That's what goes on in TcInstDcls.mk_meth_spec_prags+-}++tcSpecPrags :: Id -> [LSig Name]+ -> TcM [LTcSpecPrag]+-- Add INLINE and SPECIALSE pragmas+-- INLINE prags are added to the (polymorphic) Id directly+-- SPECIALISE prags are passed to the desugarer via TcSpecPrags+-- Pre-condition: the poly_id is zonked+-- Reason: required by tcSubExp+tcSpecPrags poly_id prag_sigs+ = do { traceTc "tcSpecPrags" (ppr poly_id <+> ppr spec_sigs)+ ; unless (null bad_sigs) warn_discarded_sigs+ ; pss <- mapAndRecoverM (wrapLocM (tcSpecPrag poly_id)) spec_sigs+ ; return $ concatMap (\(L l ps) -> map (L l) ps) pss }+ where+ spec_sigs = filter isSpecLSig prag_sigs+ bad_sigs = filter is_bad_sig prag_sigs+ is_bad_sig s = not (isSpecLSig s || isInlineLSig s || isSCCFunSig s)++ warn_discarded_sigs+ = addWarnTc NoReason+ (hang (text "Discarding unexpected pragmas for" <+> ppr poly_id)+ 2 (vcat (map (ppr . getLoc) bad_sigs)))++--------------+tcSpecPrag :: TcId -> Sig Name -> TcM [TcSpecPrag]+tcSpecPrag poly_id prag@(SpecSig fun_name hs_tys inl)+-- See Note [Handling SPECIALISE pragmas]+--+-- The Name fun_name in the SpecSig may not be the same as that of the poly_id+-- Example: SPECIALISE for a class method: the Name in the SpecSig is+-- for the selector Id, but the poly_id is something like $cop+-- However we want to use fun_name in the error message, since that is+-- what the user wrote (Trac #8537)+ = addErrCtxt (spec_ctxt prag) $+ do { warnIf NoReason (not (isOverloadedTy poly_ty || isInlinePragma inl))+ (text "SPECIALISE pragma for non-overloaded function"+ <+> quotes (ppr fun_name))+ -- Note [SPECIALISE pragmas]+ ; spec_prags <- mapM tc_one hs_tys+ ; traceTc "tcSpecPrag" (ppr poly_id $$ nest 2 (vcat (map ppr spec_prags)))+ ; return spec_prags }+ where+ name = idName poly_id+ poly_ty = idType poly_id+ spec_ctxt prag = hang (text "In the SPECIALISE pragma") 2 (ppr prag)++ tc_one hs_ty+ = do { spec_ty <- tcHsSigType (FunSigCtxt name False) hs_ty+ ; wrap <- tcSpecWrapper (FunSigCtxt name True) poly_ty spec_ty+ ; return (SpecPrag poly_id wrap inl) }++tcSpecPrag _ prag = pprPanic "tcSpecPrag" (ppr prag)++--------------+tcSpecWrapper :: UserTypeCtxt -> TcType -> TcType -> TcM HsWrapper+-- A simpler variant of tcSubType, used for SPECIALISE pragmas+-- See Note [Handling SPECIALISE pragmas], wrinkle 1+tcSpecWrapper ctxt poly_ty spec_ty+ = do { (sk_wrap, inst_wrap)+ <- tcSkolemise ctxt spec_ty $ \ _ spec_tau ->+ do { (inst_wrap, tau) <- topInstantiate orig poly_ty+ ; _ <- unifyType noThing spec_tau tau+ -- Deliberately ignore the evidence+ -- See Note [Handling SPECIALISE pragmas],+ -- wrinkle (2)+ ; return inst_wrap }+ ; return (sk_wrap <.> inst_wrap) }+ where+ orig = SpecPragOrigin ctxt++--------------+tcImpPrags :: [LSig Name] -> TcM [LTcSpecPrag]+-- SPECIALISE pragmas for imported things+tcImpPrags prags+ = do { this_mod <- getModule+ ; dflags <- getDynFlags+ ; if (not_specialising dflags) then+ return []+ else do+ { pss <- mapAndRecoverM (wrapLocM tcImpSpec)+ [L loc (name,prag)+ | (L loc prag@(SpecSig (L _ name) _ _)) <- prags+ , not (nameIsLocalOrFrom this_mod name) ]+ ; return $ concatMap (\(L l ps) -> map (L l) ps) pss } }+ where+ -- Ignore SPECIALISE pragmas for imported things+ -- when we aren't specialising, or when we aren't generating+ -- code. The latter happens when Haddocking the base library;+ -- we don't wnat complaints about lack of INLINABLE pragmas+ not_specialising dflags+ | not (gopt Opt_Specialise dflags) = True+ | otherwise = case hscTarget dflags of+ HscNothing -> True+ HscInterpreted -> True+ _other -> False++tcImpSpec :: (Name, Sig Name) -> TcM [TcSpecPrag]+tcImpSpec (name, prag)+ = do { id <- tcLookupId name+ ; unless (isAnyInlinePragma (idInlinePragma id))+ (addWarnTc NoReason (impSpecErr name))+ ; tcSpecPrag id prag }++impSpecErr :: Name -> SDoc+impSpecErr name+ = hang (text "You cannot SPECIALISE" <+> quotes (ppr name))+ 2 (vcat [ text "because its definition has no INLINE/INLINABLE pragma"+ , parens $ sep+ [ text "or its defining module" <+> quotes (ppr mod)+ , text "was compiled without -O"]])+ where+ mod = nameModule name
+ typecheck/TcSimplify.hs view
@@ -0,0 +1,2229 @@+{-# LANGUAGE CPP #-}++module TcSimplify(+ simplifyInfer, InferMode(..),+ growThetaTyVars,+ simplifyAmbiguityCheck,+ simplifyDefault,+ simplifyTop, simplifyTopImplic, captureTopConstraints,+ simplifyInteractive, solveEqualities,+ simplifyWantedsTcM,+ tcCheckSatisfiability,++ -- For Rules we need these+ solveWanteds, solveWantedsAndDrop,+ approximateWC, runTcSDeriveds+ ) where++#include "HsVersions.h"++import Bag+import Class ( Class, classKey, classTyCon )+import DynFlags ( WarningFlag ( Opt_WarnMonomorphism )+ , WarnReason ( Reason )+ , DynFlags( solverIterations ) )+import Inst+import ListSetOps+import Maybes+import Name+import Outputable+import PrelInfo+import PrelNames+import TcErrors+import TcEvidence+import TcInteract+import TcCanonical ( makeSuperClasses )+import TcMType as TcM+import TcRnMonad as TcM+import TcSMonad as TcS+import TcType+import TrieMap () -- DV: for now+import Type+import TysWiredIn ( liftedRepTy )+import Unify ( tcMatchTyKi )+import Util+import Var+import VarSet+import UniqSet+import BasicTypes ( IntWithInf, intGtLimit )+import ErrUtils ( emptyMessages )+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.List ( partition )++{-+*********************************************************************************+* *+* External interface *+* *+*********************************************************************************+-}++captureTopConstraints :: TcM a -> TcM (a, WantedConstraints)+-- (captureTopConstraints m) runs m, and returns the type constraints it+-- generates plus the constraints produced by static forms inside.+-- If it fails with an exception, it reports any insolubles+-- (out of scope variables) before doing so+captureTopConstraints thing_inside+ = do { static_wc_var <- TcM.newTcRef emptyWC ;+ ; (mb_res, lie) <- TcM.updGblEnv (\env -> env { tcg_static_wc = static_wc_var } ) $+ TcM.tryCaptureConstraints thing_inside+ ; stWC <- TcM.readTcRef static_wc_var++ -- See TcRnMonad Note [Constraints and errors]+ -- If the thing_inside threw an exception, but generated some insoluble+ -- constraints, report the latter before propagating the exception+ -- Otherwise they will be lost altogether+ ; case mb_res of+ Right res -> return (res, lie `andWC` stWC)+ Left {} -> do { _ <- reportUnsolved lie; failM } }+ -- This call to reportUnsolved is the reason+ -- this function is here instead of TcRnMonad++simplifyTopImplic :: Bag Implication -> TcM ()+simplifyTopImplic implics+ = do { empty_binds <- simplifyTop (mkImplicWC implics)++ -- Since all the inputs are implications the returned bindings will be empty+ ; MASSERT2( isEmptyBag empty_binds, ppr empty_binds )++ ; return () }++simplifyTop :: WantedConstraints -> TcM (Bag EvBind)+-- Simplify top-level constraints+-- Usually these will be implications,+-- but when there is nothing to quantify we don't wrap+-- in a degenerate implication, so we do that here instead+simplifyTop wanteds+ = do { traceTc "simplifyTop {" $ text "wanted = " <+> ppr wanteds+ ; ((final_wc, unsafe_ol), binds1) <- runTcS $+ do { final_wc <- simpl_top wanteds+ ; unsafe_ol <- getSafeOverlapFailures+ ; return (final_wc, unsafe_ol) }+ ; traceTc "End simplifyTop }" empty++ ; traceTc "reportUnsolved {" empty+ ; binds2 <- reportUnsolved final_wc+ ; traceTc "reportUnsolved }" empty++ ; traceTc "reportUnsolved (unsafe overlapping) {" empty+ ; unless (isEmptyCts unsafe_ol) $ do {+ -- grab current error messages and clear, warnAllUnsolved will+ -- update error messages which we'll grab and then restore saved+ -- messages.+ ; errs_var <- getErrsVar+ ; saved_msg <- TcM.readTcRef errs_var+ ; TcM.writeTcRef errs_var emptyMessages++ ; warnAllUnsolved $ WC { wc_simple = unsafe_ol+ , wc_insol = emptyCts+ , wc_impl = emptyBag }++ ; whyUnsafe <- fst <$> TcM.readTcRef errs_var+ ; TcM.writeTcRef errs_var saved_msg+ ; recordUnsafeInfer whyUnsafe+ }+ ; traceTc "reportUnsolved (unsafe overlapping) }" empty++ ; return (evBindMapBinds binds1 `unionBags` binds2) }++-- | Type-check a thing that emits only equality constraints, then+-- solve those constraints. Fails outright if there is trouble.+solveEqualities :: TcM a -> TcM a+solveEqualities thing_inside+ = checkNoErrs $ -- See Note [Fail fast on kind errors]+ do { (result, wanted) <- captureConstraints thing_inside+ ; traceTc "solveEqualities {" $ text "wanted = " <+> ppr wanted+ ; final_wc <- runTcSEqualities $ simpl_top wanted+ ; traceTc "End solveEqualities }" empty++ ; traceTc "reportAllUnsolved {" empty+ ; reportAllUnsolved final_wc+ ; traceTc "reportAllUnsolved }" empty+ ; return result }++simpl_top :: WantedConstraints -> TcS WantedConstraints+ -- See Note [Top-level Defaulting Plan]+simpl_top wanteds+ = do { wc_first_go <- nestTcS (solveWantedsAndDrop wanteds)+ -- This is where the main work happens+ ; try_tyvar_defaulting wc_first_go }+ where+ try_tyvar_defaulting :: WantedConstraints -> TcS WantedConstraints+ try_tyvar_defaulting wc+ | isEmptyWC wc+ = return wc+ | otherwise+ = do { free_tvs <- TcS.zonkTyCoVarsAndFVList (tyCoVarsOfWCList wc)+ ; let meta_tvs = filter (isTyVar <&&> isMetaTyVar) free_tvs+ -- zonkTyCoVarsAndFV: the wc_first_go is not yet zonked+ -- filter isMetaTyVar: we might have runtime-skolems in GHCi,+ -- and we definitely don't want to try to assign to those!+ -- The isTyVar is needed to weed out coercion variables++ ; defaulted <- mapM defaultTyVarTcS meta_tvs -- Has unification side effects+ ; if or defaulted+ then do { wc_residual <- nestTcS (solveWanteds wc)+ -- See Note [Must simplify after defaulting]+ ; try_class_defaulting wc_residual }+ else try_class_defaulting wc } -- No defaulting took place++ try_class_defaulting :: WantedConstraints -> TcS WantedConstraints+ try_class_defaulting wc+ | isEmptyWC wc+ = return wc+ | otherwise -- See Note [When to do type-class defaulting]+ = do { something_happened <- applyDefaultingRules wc+ -- See Note [Top-level Defaulting Plan]+ ; if something_happened+ then do { wc_residual <- nestTcS (solveWantedsAndDrop wc)+ ; try_class_defaulting wc_residual }+ -- See Note [Overview of implicit CallStacks] in TcEvidence+ else try_callstack_defaulting wc }++ try_callstack_defaulting :: WantedConstraints -> TcS WantedConstraints+ try_callstack_defaulting wc+ | isEmptyWC wc+ = return wc+ | otherwise+ = defaultCallStacks wc++-- | Default any remaining @CallStack@ constraints to empty @CallStack@s.+defaultCallStacks :: WantedConstraints -> TcS WantedConstraints+-- See Note [Overview of implicit CallStacks] in TcEvidence+defaultCallStacks wanteds+ = do simples <- handle_simples (wc_simple wanteds)+ mb_implics <- mapBagM handle_implic (wc_impl wanteds)+ return (wanteds { wc_simple = simples+ , wc_impl = catBagMaybes mb_implics })++ where++ handle_simples simples+ = catBagMaybes <$> mapBagM defaultCallStack simples++ handle_implic :: Implication -> TcS (Maybe Implication)+ -- The Maybe is because solving the CallStack constraint+ -- may well allow us to discard the implication entirely+ handle_implic implic+ | isSolvedStatus (ic_status implic)+ = return (Just implic)+ | otherwise+ = do { wanteds <- setEvBindsTcS (ic_binds implic) $+ -- defaultCallStack sets a binding, so+ -- we must set the correct binding group+ defaultCallStacks (ic_wanted implic)+ ; setImplicationStatus (implic { ic_wanted = wanteds }) }++ defaultCallStack ct+ | Just _ <- isCallStackPred (ctPred ct)+ = do { solveCallStack (cc_ev ct) EvCsEmpty+ ; return Nothing }++ defaultCallStack ct+ = return (Just ct)+++{- Note [Fail fast on kind errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+solveEqualities is used to solve kind equalities when kind-checking+user-written types. If solving fails we should fail outright, rather+than just accumulate an error message, for two reasons:++ * A kind-bogus type signature may cause a cascade of knock-on+ errors if we let it pass++ * More seriously, we don't have a convenient term-level place to add+ deferred bindings for unsolved kind-equality constraints, so we+ don't build evidence bindings (by usine reportAllUnsolved). That+ means that we'll be left with with a type that has coercion holes+ in it, something like+ <type> |> co-hole+ where co-hole is not filled in. Eeek! That un-filled-in+ hole actually causes GHC to crash with "fvProv falls into a hole"+ See Trac #11563, #11520, #11516, #11399++So it's important to use 'checkNoErrs' here!++Note [When to do type-class defaulting]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In GHC 7.6 and 7.8.2, we did type-class defaulting only if insolubleWC+was false, on the grounds that defaulting can't help solve insoluble+constraints. But if we *don't* do defaulting we may report a whole+lot of errors that would be solved by defaulting; these errors are+quite spurious because fixing the single insoluble error means that+defaulting happens again, which makes all the other errors go away.+This is jolly confusing: Trac #9033.++So it seems better to always do type-class defaulting.++However, always doing defaulting does mean that we'll do it in+situations like this (Trac #5934):+ run :: (forall s. GenST s) -> Int+ run = fromInteger 0+We don't unify the return type of fromInteger with the given function+type, because the latter involves foralls. So we're left with+ (Num alpha, alpha ~ (forall s. GenST s) -> Int)+Now we do defaulting, get alpha := Integer, and report that we can't+match Integer with (forall s. GenST s) -> Int. That's not totally+stupid, but perhaps a little strange.++Another potential alternative would be to suppress *all* non-insoluble+errors if there are *any* insoluble errors, anywhere, but that seems+too drastic.++Note [Must simplify after defaulting]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We may have a deeply buried constraint+ (t:*) ~ (a:Open)+which we couldn't solve because of the kind incompatibility, and 'a' is free.+Then when we default 'a' we can solve the constraint. And we want to do+that before starting in on type classes. We MUST do it before reporting+errors, because it isn't an error! Trac #7967 was due to this.++Note [Top-level Defaulting Plan]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We have considered two design choices for where/when to apply defaulting.+ (i) Do it in SimplCheck mode only /whenever/ you try to solve some+ simple constraints, maybe deep inside the context of implications.+ This used to be the case in GHC 7.4.1.+ (ii) Do it in a tight loop at simplifyTop, once all other constraints have+ finished. This is the current story.++Option (i) had many disadvantages:+ a) Firstly, it was deep inside the actual solver.+ b) Secondly, it was dependent on the context (Infer a type signature,+ or Check a type signature, or Interactive) since we did not want+ to always start defaulting when inferring (though there is an exception to+ this, see Note [Default while Inferring]).+ c) It plainly did not work. Consider typecheck/should_compile/DfltProb2.hs:+ f :: Int -> Bool+ f x = const True (\y -> let w :: a -> a+ w a = const a (y+1)+ in w y)+ We will get an implication constraint (for beta the type of y):+ [untch=beta] forall a. 0 => Num beta+ which we really cannot default /while solving/ the implication, since beta is+ untouchable.++Instead our new defaulting story is to pull defaulting out of the solver loop and+go with option (ii), implemented at SimplifyTop. Namely:+ - First, have a go at solving the residual constraint of the whole+ program+ - Try to approximate it with a simple constraint+ - Figure out derived defaulting equations for that simple constraint+ - Go round the loop again if you did manage to get some equations++Now, that has to do with class defaulting. However there exists type variable /kind/+defaulting. Again this is done at the top-level and the plan is:+ - At the top-level, once you had a go at solving the constraint, do+ figure out /all/ the touchable unification variables of the wanted constraints.+ - Apply defaulting to their kinds++More details in Note [DefaultTyVar].++Note [Safe Haskell Overlapping Instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In Safe Haskell, we apply an extra restriction to overlapping instances. The+motive is to prevent untrusted code provided by a third-party, changing the+behavior of trusted code through type-classes. This is due to the global and+implicit nature of type-classes that can hide the source of the dictionary.++Another way to state this is: if a module M compiles without importing another+module N, changing M to import N shouldn't change the behavior of M.++Overlapping instances with type-classes can violate this principle. However,+overlapping instances aren't always unsafe. They are just unsafe when the most+selected dictionary comes from untrusted code (code compiled with -XSafe) and+overlaps instances provided by other modules.++In particular, in Safe Haskell at a call site with overlapping instances, we+apply the following rule to determine if it is a 'unsafe' overlap:++ 1) Most specific instance, I1, defined in an `-XSafe` compiled module.+ 2) I1 is an orphan instance or a MPTC.+ 3) At least one overlapped instance, Ix, is both:+ A) from a different module than I1+ B) Ix is not marked `OVERLAPPABLE`++This is a slightly involved heuristic, but captures the situation of an+imported module N changing the behavior of existing code. For example, if+condition (2) isn't violated, then the module author M must depend either on a+type-class or type defined in N.++Secondly, when should these heuristics be enforced? We enforced them when the+type-class method call site is in a module marked `-XSafe` or `-XTrustworthy`.+This allows `-XUnsafe` modules to operate without restriction, and for Safe+Haskell inferrence to infer modules with unsafe overlaps as unsafe.++One alternative design would be to also consider if an instance was imported as+a `safe` import or not and only apply the restriction to instances imported+safely. However, since instances are global and can be imported through more+than one path, this alternative doesn't work.++Note [Safe Haskell Overlapping Instances Implementation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++How is this implemented? It's complicated! So we'll step through it all:++ 1) `InstEnv.lookupInstEnv` -- Performs instance resolution, so this is where+ we check if a particular type-class method call is safe or unsafe. We do this+ through the return type, `ClsInstLookupResult`, where the last parameter is a+ list of instances that are unsafe to overlap. When the method call is safe,+ the list is null.++ 2) `TcInteract.matchClassInst` -- This module drives the instance resolution+ / dictionary generation. The return type is `LookupInstResult`, which either+ says no instance matched, or one found, and if it was a safe or unsafe+ overlap.++ 3) `TcInteract.doTopReactDict` -- Takes a dictionary / class constraint and+ tries to resolve it by calling (in part) `matchClassInst`. The resolving+ mechanism has a work list (of constraints) that it process one at a time. If+ the constraint can't be resolved, it's added to an inert set. When compiling+ an `-XSafe` or `-XTrustworthy` module, we follow this approach as we know+ compilation should fail. These are handled as normal constraint resolution+ failures from here-on (see step 6).++ Otherwise, we may be inferring safety (or using `-Wunsafe`), and+ compilation should succeed, but print warnings and/or mark the compiled module+ as `-XUnsafe`. In this case, we call `insertSafeOverlapFailureTcS` which adds+ the unsafe (but resolved!) constraint to the `inert_safehask` field of+ `InertCans`.++ 4) `TcSimplify.simplifyTop`:+ * Call simpl_top, the top-level function for driving the simplifier for+ constraint resolution.++ * Once finished, call `getSafeOverlapFailures` to retrieve the+ list of overlapping instances that were successfully resolved,+ but unsafe. Remember, this is only applicable for generating warnings+ (`-Wunsafe`) or inferring a module unsafe. `-XSafe` and `-XTrustworthy`+ cause compilation failure by not resolving the unsafe constraint at all.++ * For unresolved constraints (all types), call `TcErrors.reportUnsolved`,+ while for resolved but unsafe overlapping dictionary constraints, call+ `TcErrors.warnAllUnsolved`. Both functions convert constraints into a+ warning message for the user.++ * In the case of `warnAllUnsolved` for resolved, but unsafe+ dictionary constraints, we collect the generated warning+ message (pop it) and call `TcRnMonad.recordUnsafeInfer` to+ mark the module we are compiling as unsafe, passing the+ warning message along as the reason.++ 5) `TcErrors.*Unsolved` -- Generates error messages for constraints by+ actually calling `InstEnv.lookupInstEnv` again! Yes, confusing, but all we+ know is the constraint that is unresolved or unsafe. For dictionary, all we+ know is that we need a dictionary of type C, but not what instances are+ available and how they overlap. So we once again call `lookupInstEnv` to+ figure that out so we can generate a helpful error message.++ 6) `TcRnMonad.recordUnsafeInfer` -- Save the unsafe result and reason in an+ IORef called `tcg_safeInfer`.++ 7) `HscMain.tcRnModule'` -- Reads `tcg_safeInfer` after type-checking, calling+ `HscMain.markUnsafeInfer` (passing the reason along) when safe-inferrence+ failed.++Note [No defaulting in the ambiguity check]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When simplifying constraints for the ambiguity check, we use+solveWantedsAndDrop, not simpl_top, so that we do no defaulting.+Trac #11947 was an example:+ f :: Num a => Int -> Int+This is ambiguous of course, but we don't want to default the+(Num alpha) constraint to (Num Int)! Doing so gives a defaulting+warning, but no error.+-}++------------------+simplifyAmbiguityCheck :: Type -> WantedConstraints -> TcM ()+simplifyAmbiguityCheck ty wanteds+ = do { traceTc "simplifyAmbiguityCheck {" (text "type = " <+> ppr ty $$ text "wanted = " <+> ppr wanteds)+ ; (final_wc, _) <- runTcS $ solveWantedsAndDrop wanteds+ -- NB: no defaulting! See Note [No defaulting in the ambiguity check]++ ; traceTc "End simplifyAmbiguityCheck }" empty++ -- Normally report all errors; but with -XAllowAmbiguousTypes+ -- report only insoluble ones, since they represent genuinely+ -- inaccessible code+ ; allow_ambiguous <- xoptM LangExt.AllowAmbiguousTypes+ ; traceTc "reportUnsolved(ambig) {" empty+ ; unless (allow_ambiguous && not (insolubleWC final_wc))+ (discardResult (reportUnsolved final_wc))+ ; traceTc "reportUnsolved(ambig) }" empty++ ; return () }++------------------+simplifyInteractive :: WantedConstraints -> TcM (Bag EvBind)+simplifyInteractive wanteds+ = traceTc "simplifyInteractive" empty >>+ simplifyTop wanteds++------------------+simplifyDefault :: ThetaType -- Wanted; has no type variables in it+ -> TcM () -- Succeeds if the constraint is soluble+simplifyDefault theta+ = do { traceTc "simplifyDefault" empty+ ; wanteds <- newWanteds DefaultOrigin theta+ ; unsolved <- runTcSDeriveds (solveWantedsAndDrop (mkSimpleWC wanteds))+ ; traceTc "reportUnsolved {" empty+ ; reportAllUnsolved unsolved+ ; traceTc "reportUnsolved }" empty+ ; return () }++------------------+tcCheckSatisfiability :: Bag EvVar -> TcM Bool+-- Return True if satisfiable, False if definitely contradictory+tcCheckSatisfiability given_ids+ = do { lcl_env <- TcM.getLclEnv+ ; let given_loc = mkGivenLoc topTcLevel UnkSkol lcl_env+ ; (res, _ev_binds) <- runTcS $+ do { traceTcS "checkSatisfiability {" (ppr given_ids)+ ; let given_cts = mkGivens given_loc (bagToList given_ids)+ -- See Note [Superclasses and satisfiability]+ ; solveSimpleGivens given_cts+ ; insols <- getInertInsols+ ; insols <- try_harder insols+ ; traceTcS "checkSatisfiability }" (ppr insols)+ ; return (isEmptyBag insols) }+ ; return res }+ where+ try_harder :: Cts -> TcS Cts+ -- Maybe we have to search up the superclass chain to find+ -- an unsatisfiable constraint. Example: pmcheck/T3927b.+ -- At the moment we try just once+ try_harder insols+ | not (isEmptyBag insols) -- We've found that it's definitely unsatisfiable+ = return insols -- Hurrah -- stop now.+ | otherwise+ = do { pending_given <- getPendingScDicts+ ; new_given <- makeSuperClasses pending_given+ ; solveSimpleGivens new_given+ ; getInertInsols }++{- Note [Superclasses and satisfiability]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Expand superclasses before starting, because (Int ~ Bool), has+(Int ~~ Bool) as a superclass, which in turn has (Int ~N# Bool)+as a superclass, and it's the latter that is insoluble. See+Note [The equality types story] in TysPrim.++If we fail to prove unsatisfiability we (arbitrarily) try just once to+find superclasses, using try_harder. Reason: we might have a type+signature+ f :: F op (Implements push) => ..+where F is a type function. This happened in Trac #3972.++We could do more than once but we'd have to have /some/ limit: in the+the recursive case, we would go on forever in the common case where+the constraints /are/ satisfiable (Trac #10592 comment:12!).++For stratightforard situations without type functions the try_harder+step does nothing.+++***********************************************************************************+* *+* Inference+* *+***********************************************************************************++Note [Inferring the type of a let-bound variable]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ f x = rhs++To infer f's type we do the following:+ * Gather the constraints for the RHS with ambient level *one more than*+ the current one. This is done by the call+ pushLevelAndCaptureConstraints (tcMonoBinds...)+ in TcBinds.tcPolyInfer++ * Call simplifyInfer to simplify the constraints and decide what to+ quantify over. We pass in the level used for the RHS constraints,+ here called rhs_tclvl.++This ensures that the implication constraint we generate, if any,+has a strictly-increased level compared to the ambient level outside+the let binding.++-}++-- | How should we choose which constraints to quantify over?+data InferMode = ApplyMR -- ^ Apply the monomorphism restriction,+ -- never quantifying over any constraints+ | EagerDefaulting -- ^ See Note [TcRnExprMode] in TcRnDriver,+ -- the :type +d case; this mode refuses+ -- to quantify over any defaultable constraint+ | NoRestrictions -- ^ Quantify over any constraint that+ -- satisfies TcType.pickQuantifiablePreds++instance Outputable InferMode where+ ppr ApplyMR = text "ApplyMR"+ ppr EagerDefaulting = text "EagerDefaulting"+ ppr NoRestrictions = text "NoRestrictions"++simplifyInfer :: TcLevel -- Used when generating the constraints+ -> InferMode+ -> [TcIdSigInst] -- Any signatures (possibly partial)+ -> [(Name, TcTauType)] -- Variables to be generalised,+ -- and their tau-types+ -> WantedConstraints+ -> TcM ([TcTyVar], -- Quantify over these type variables+ [EvVar], -- ... and these constraints (fully zonked)+ TcEvBinds) -- ... binding these evidence variables+simplifyInfer rhs_tclvl infer_mode sigs name_taus wanteds+ | isEmptyWC wanteds+ = do { gbl_tvs <- tcGetGlobalTyCoVars+ ; dep_vars <- zonkTcTypesAndSplitDepVars (map snd name_taus)+ ; qtkvs <- quantifyZonkedTyVars gbl_tvs dep_vars+ ; traceTc "simplifyInfer: empty WC" (ppr name_taus $$ ppr qtkvs)+ ; return (qtkvs, [], emptyTcEvBinds) }++ | otherwise+ = do { traceTc "simplifyInfer {" $ vcat+ [ text "sigs =" <+> ppr sigs+ , text "binds =" <+> ppr name_taus+ , text "rhs_tclvl =" <+> ppr rhs_tclvl+ , text "infer_mode =" <+> ppr infer_mode+ , text "(unzonked) wanted =" <+> ppr wanteds+ ]++ ; let partial_sigs = filter isPartialSig sigs+ psig_theta = concatMap sig_inst_theta partial_sigs++ -- First do full-blown solving+ -- NB: we must gather up all the bindings from doing+ -- this solving; hence (runTcSWithEvBinds ev_binds_var).+ -- And note that since there are nested implications,+ -- calling solveWanteds will side-effect their evidence+ -- bindings, so we can't just revert to the input+ -- constraint.++ ; tc_lcl_env <- TcM.getLclEnv+ ; ev_binds_var <- TcM.newTcEvBinds+ ; psig_theta_vars <- mapM TcM.newEvVar psig_theta+ ; wanted_transformed_incl_derivs+ <- setTcLevel rhs_tclvl $+ runTcSWithEvBinds ev_binds_var $+ do { let loc = mkGivenLoc rhs_tclvl UnkSkol tc_lcl_env+ psig_givens = mkGivens loc psig_theta_vars+ ; _ <- solveSimpleGivens psig_givens+ -- See Note [Add signature contexts as givens]+ ; solveWanteds wanteds }+ ; wanted_transformed_incl_derivs <- TcM.zonkWC wanted_transformed_incl_derivs++ -- Find quant_pred_candidates, the predicates that+ -- we'll consider quantifying over+ -- NB1: wanted_transformed does not include anything provable from+ -- the psig_theta; it's just the extra bit+ -- NB2: We do not do any defaulting when inferring a type, this can lead+ -- to less polymorphic types, see Note [Default while Inferring]++ ; let wanted_transformed = dropDerivedWC wanted_transformed_incl_derivs+ quant_pred_candidates -- Fully zonked+ | insolubleWC wanted_transformed_incl_derivs+ = [] -- See Note [Quantification with errors]+ -- NB: must include derived errors in this test,+ -- hence "incl_derivs"++ | otherwise+ = ctsPreds (approximateWC False wanted_transformed)++ -- NB: quant_pred_candidates is already fully zonked++ -- Decide what type variables and constraints to quantify+ -- NB: bound_theta are constraints we want to quantify over,+ -- /apart from/ the psig_theta, which we always quantify over+ ; (qtvs, bound_theta) <- decideQuantification infer_mode rhs_tclvl+ name_taus partial_sigs+ quant_pred_candidates++ -- Emit an implication constraint for the+ -- remaining constraints from the RHS.+ -- We must retain the psig_theta_vars, because we've used them in+ -- evidence bindings constructed by solveWanteds earlier+ ; psig_theta_vars <- mapM zonkId psig_theta_vars+ ; bound_theta_vars <- mapM TcM.newEvVar bound_theta+ ; let full_theta = psig_theta ++ bound_theta+ full_theta_vars = psig_theta_vars ++ bound_theta_vars+ skol_info = InferSkol [ (name, mkSigmaTy [] full_theta ty)+ | (name, ty) <- name_taus ]+ -- Don't add the quantified variables here, because+ -- they are also bound in ic_skols and we want them+ -- to be tidied uniformly++ implic = Implic { ic_tclvl = rhs_tclvl+ , ic_skols = qtvs+ , ic_no_eqs = False+ , ic_given = full_theta_vars+ , ic_wanted = wanted_transformed+ , ic_status = IC_Unsolved+ , ic_binds = ev_binds_var+ , ic_info = skol_info+ , ic_needed = emptyVarSet+ , ic_env = tc_lcl_env }+ ; emitImplication implic++ -- All done!+ ; traceTc "} simplifyInfer/produced residual implication for quantification" $+ vcat [ text "quant_pred_candidates =" <+> ppr quant_pred_candidates+ , text "psig_theta =" <+> ppr psig_theta+ , text "bound_theta =" <+> ppr bound_theta+ , text "full_theta =" <+> ppr full_theta+ , text "qtvs =" <+> ppr qtvs+ , text "implic =" <+> ppr implic ]++ ; return ( qtvs, full_theta_vars, TcEvBinds ev_binds_var ) }+ -- NB: full_theta_vars must be fully zonked+++ctsPreds :: Cts -> [PredType]+ctsPreds cts = [ ctEvPred ev | ct <- bagToList cts+ , let ev = ctEvidence ct ]++{- Note [Add signature contexts as givens]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this (Trac #11016):+ f2 :: (?x :: Int) => _+ f2 = ?x+or this+ f3 :: a ~ Bool => (a, _)+ f3 = (True, False)+or theis+ f4 :: (Ord a, _) => a -> Bool+ f4 x = x==x++We'll use plan InferGen because there are holes in the type. But:+ * For f2 we want to have the (?x :: Int) constraint floating around+ so that the functional dependencies kick in. Otherwise the+ occurrence of ?x on the RHS produces constraint (?x :: alpha), and+ we won't unify alpha:=Int.+ * For f3 we want the (a ~ Bool) available to solve the wanted (a ~ Bool)+ in the RHS+ * For f4 we want to use the (Ord a) in the signature to solve the Eq a+ constraint.++Solution: in simplifyInfer, just before simplifying the constraints+gathered from the RHS, add Given constraints for the context of any+type signatures.++************************************************************************+* *+ Quantification+* *+************************************************************************++Note [Deciding quantification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If the monomorphism restriction does not apply, then we quantify as follows:++* Step 1. Take the global tyvars, and "grow" them using the equality+ constraints+ E.g. if x:alpha is in the environment, and alpha ~ [beta] (which can+ happen because alpha is untouchable here) then do not quantify over+ beta, because alpha fixes beta, and beta is effectively free in+ the environment too++ We also account for the monomorphism restriction; if it applies,+ add the free vars of all the constraints.++ Result is mono_tvs; we will not quantify over these.++* Step 2. Default any non-mono tyvars (i.e ones that are definitely+ not going to become further constrained), and re-simplify the+ candidate constraints.++ Motivation for re-simplification (Trac #7857): imagine we have a+ constraint (C (a->b)), where 'a :: TYPE l1' and 'b :: TYPE l2' are+ not free in the envt, and instance forall (a::*) (b::*). (C a) => C+ (a -> b) The instance doesnt' match while l1,l2 are polymorphic, but+ it will match when we default them to LiftedRep.++ This is all very tiresome.++* Step 3: decide which variables to quantify over, as follows:++ - Take the free vars of the tau-type (zonked_tau_tvs) and "grow"+ them using all the constraints. These are tau_tvs_plus++ - Use quantifyTyVars to quantify over (tau_tvs_plus - mono_tvs), being+ careful to close over kinds, and to skolemise the quantified tyvars.+ (This actually unifies each quantifies meta-tyvar with a fresh skolem.)++ Result is qtvs.++* Step 4: Filter the constraints using pickQuantifiablePreds and the+ qtvs. We have to zonk the constraints first, so they "see" the+ freshly created skolems.++-}++decideQuantification+ :: InferMode+ -> TcLevel+ -> [(Name, TcTauType)] -- Variables to be generalised+ -> [TcIdSigInst] -- Partial type signatures (if any)+ -> [PredType] -- Candidate theta; already zonked+ -> TcM ( [TcTyVar] -- Quantify over these (skolems)+ , [PredType] ) -- and this context (fully zonked)+-- See Note [Deciding quantification]+decideQuantification infer_mode rhs_tclvl name_taus psigs candidates+ = do { -- Step 1: find the mono_tvs+ ; (mono_tvs, candidates) <- decideMonoTyVars infer_mode+ name_taus psigs candidates++ -- Step 2: default any non-mono tyvars, and re-simplify+ -- This step may do some unification, but result candidates is zonked+ ; candidates <- defaultTyVarsAndSimplify rhs_tclvl mono_tvs candidates++ -- Step 3: decide which kind/type variables to quantify over+ ; qtvs <- decideQuantifiedTyVars mono_tvs name_taus psigs candidates++ -- Step 4: choose which of the remaining candidate+ -- predicates to actually quantify over+ -- NB: decideQuantifiedTyVars turned some meta tyvars+ -- into quantified skolems, so we have to zonk again+ ; candidates <- TcM.zonkTcTypes candidates+ ; let theta = pickQuantifiablePreds (mkVarSet qtvs) $+ mkMinimalBySCs $ -- See Note [Minimize by Superclasses]+ candidates++ ; traceTc "decideQuantification"+ (vcat [ text "infer_mode:" <+> ppr infer_mode+ , text "candidates:" <+> ppr candidates+ , text "mono_tvs:" <+> ppr mono_tvs+ , text "qtvs:" <+> ppr qtvs+ , text "theta:" <+> ppr theta ])+ ; return (qtvs, theta) }++------------------+decideMonoTyVars :: InferMode+ -> [(Name,TcType)]+ -> [TcIdSigInst]+ -> [PredType]+ -> TcM (TcTyCoVarSet, [PredType])+-- Decide which tyvars cannot be generalised:+-- (a) Free in the environment+-- (b) Mentioned in a constraint we can't generalise+-- (c) Connected by an equality to (a) or (b)+-- Also return the reduced set of constraint we can generalise+decideMonoTyVars infer_mode name_taus psigs candidates+ = do { (no_quant, yes_quant) <- pick infer_mode candidates++ ; gbl_tvs <- tcGetGlobalTyCoVars+ ; let eq_constraints = filter isEqPred candidates+ constrained_tvs = tyCoVarsOfTypes no_quant+ mono_tvs1 = growThetaTyVars eq_constraints $+ gbl_tvs `unionVarSet` constrained_tvs++ -- Always quantify over partial-sig qtvs, so they are not mono+ -- Need to zonk them because they are meta-tyvar SigTvs+ -- Note [Quantification and partial signatures], wrinkle 3+ ; psig_qtvs <- mapM zonkTcTyVarToTyVar $+ concatMap (map snd . sig_inst_skols) psigs+ ; let mono_tvs = mono_tvs1 `delVarSetList` psig_qtvs++ -- Warn about the monomorphism restriction+ ; warn_mono <- woptM Opt_WarnMonomorphism+ ; when (case infer_mode of { ApplyMR -> warn_mono; _ -> False}) $+ do { taus <- mapM (TcM.zonkTcType . snd) name_taus+ ; warnTc (Reason Opt_WarnMonomorphism)+ (constrained_tvs `intersectsVarSet` tyCoVarsOfTypes taus)+ mr_msg }++ ; traceTc "decideMonoTyVars" $ vcat+ [ text "gbl_tvs =" <+> ppr gbl_tvs+ , text "no_quant =" <+> ppr no_quant+ , text "yes_quant =" <+> ppr yes_quant+ , text "eq_constraints =" <+> ppr eq_constraints+ , text "mono_tvs =" <+> ppr mono_tvs ]++ ; return (mono_tvs, yes_quant) }+ where+ pick :: InferMode -> [PredType] -> TcM ([PredType], [PredType])+ -- Split the candidates into ones we definitely+ -- won't quantify, and ones that we might+ pick NoRestrictions cand = return ([], cand)+ pick ApplyMR cand = return (cand, [])+ pick EagerDefaulting cand = do { os <- xoptM LangExt.OverloadedStrings+ ; return (partition (is_int_ct os) cand) }++ -- For EagerDefaulting, do not quantify over+ -- over any interactive class constraint+ is_int_ct ovl_strings pred+ | Just (cls, _) <- getClassPredTys_maybe pred+ = isInteractiveClass ovl_strings cls+ | otherwise+ = False++ pp_bndrs = pprWithCommas (quotes . ppr . fst) name_taus+ mr_msg = hang (text "The Monomorphism Restriction applies to the binding"+ <> plural name_taus <+> text "for" <+> pp_bndrs)+ 2 (text "Consider giving a type signature for"+ <+> if isSingleton name_taus then pp_bndrs+ else text "these binders")++-------------------+defaultTyVarsAndSimplify :: TcLevel+ -> TyCoVarSet+ -> [PredType] -- Assumed zonked+ -> TcM [PredType] -- Guaranteed zonked+-- Default any tyvar free in the constraints,+-- and re-simplify in case the defaulting allows futher simplification+defaultTyVarsAndSimplify rhs_tclvl mono_tvs candidates+ = do { -- Promote any tyvars that we cannot generalise+ -- See Note [Promote momomorphic tyvars]+ ; outer_tclvl <- TcM.getTcLevel+ ; let prom_tvs = nonDetEltsUniqSet mono_tvs+ -- It's OK to use nonDetEltsUniqSet here+ -- because promoteTyVar is commutative+ ; traceTc "decideMonoTyVars: promotion:" (ppr prom_tvs)+ ; proms <- mapM (promoteTyVar outer_tclvl) prom_tvs++ -- Default any kind/levity vars+ ; let DV {dv_kvs = cand_kvs, dv_tvs = cand_tvs}+ = candidateQTyVarsOfTypes candidates+ ; poly_kinds <- xoptM LangExt.PolyKinds+ ; default_kvs <- mapM (default_one poly_kinds True)+ (dVarSetElems cand_kvs)+ ; default_tvs <- mapM (default_one poly_kinds False)+ (dVarSetElems (cand_tvs `minusDVarSet` cand_kvs))+ ; let some_default = or default_kvs || or default_tvs++ ; case () of+ _ | some_default -> simplify_cand candidates+ | or proms -> mapM TcM.zonkTcType candidates+ | otherwise -> return candidates+ }+ where+ default_one poly_kinds is_kind_var tv+ | not (isMetaTyVar tv)+ = return False+ | tv `elemVarSet` mono_tvs+ = return False+ | otherwise+ = defaultTyVar (not poly_kinds && is_kind_var) tv++ simplify_cand candidates+ = do { clone_wanteds <- newWanteds DefaultOrigin candidates+ ; WC { wc_simple = simples } <- setTcLevel rhs_tclvl $+ simplifyWantedsTcM clone_wanteds+ -- Discard evidence; simples is fully zonked++ ; let new_candidates = ctsPreds simples+ ; traceTc "Simplified after defaulting" $+ vcat [ text "Before:" <+> ppr candidates+ , text "After:" <+> ppr new_candidates ]+ ; return new_candidates }++------------------+decideQuantifiedTyVars+ :: TyCoVarSet -- Monomorphic tyvars+ -> [(Name,TcType)] -- Annotated theta and (name,tau) pairs+ -> [TcIdSigInst] -- Parital signatures+ -> [PredType] -- Candidates, zonked+ -> TcM [TyVar]+-- Fix what tyvars we are going to quantify over, and quantify them+decideQuantifiedTyVars mono_tvs name_taus psigs candidates+ = do { -- Why psig_tys? We try to quantify over everything free in here+ -- See Note [Quantification and partial signatures]+ -- wrinkles 2 and 3+ ; psig_tv_tys <- mapM TcM.zonkTcTyVar [ tv | sig <- psigs+ , (_,tv) <- sig_inst_skols sig ]+ ; psig_theta <- mapM TcM.zonkTcType [ pred | sig <- psigs+ , pred <- sig_inst_theta sig ]+ ; tau_tys <- mapM (TcM.zonkTcType . snd) name_taus++ ; let -- Try to quantify over variables free in these types+ psig_tys = psig_tv_tys ++ psig_theta+ seed_tys = psig_tys ++ tau_tys++ -- Now "grow" those seeds to find ones reachable via 'candidates'+ grown_tvs = growThetaTyVars candidates (tyCoVarsOfTypes seed_tys)++ -- Now we have to classify them into kind variables and type variables+ -- (sigh) just for the benefit of -XNoPolyKinds; see quantifyZonkedTyVars+ --+ -- Keep the psig_tys first, so that candidateQTyVarsOfTypes produces+ -- them in that order, so that the final qtvs quantifies in the same+ -- order as the partial signatures do (Trac #13524)+ ; let DV {dv_kvs = cand_kvs, dv_tvs = cand_tvs}+ = candidateQTyVarsOfTypes $+ psig_tys ++ candidates ++ tau_tys+ pick = filterDVarSet (`elemVarSet` grown_tvs)+ dvs_plus = DV { dv_kvs = pick cand_kvs, dv_tvs = pick cand_tvs }++ ; mono_tvs <- TcM.zonkTyCoVarsAndFV mono_tvs+ ; quantifyZonkedTyVars mono_tvs dvs_plus }++------------------+growThetaTyVars :: ThetaType -> TyCoVarSet -> TyVarSet+-- See Note [Growing the tau-tvs using constraints]+-- NB: only returns tyvars, never covars+growThetaTyVars theta tvs+ | null theta = tvs_only+ | otherwise = filterVarSet isTyVar $+ transCloVarSet mk_next seed_tvs+ where+ tvs_only = filterVarSet isTyVar tvs+ seed_tvs = tvs `unionVarSet` tyCoVarsOfTypes ips+ (ips, non_ips) = partition isIPPred theta+ -- See Note [Inheriting implicit parameters] in TcType++ mk_next :: VarSet -> VarSet -- Maps current set to newly-grown ones+ mk_next so_far = foldr (grow_one so_far) emptyVarSet non_ips+ grow_one so_far pred tvs+ | pred_tvs `intersectsVarSet` so_far = tvs `unionVarSet` pred_tvs+ | otherwise = tvs+ where+ pred_tvs = tyCoVarsOfType pred++{- Note [Promote momomorphic tyvars]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Promote any type variables that are free in the environment. Eg+ f :: forall qtvs. bound_theta => zonked_tau+The free vars of f's type become free in the envt, and hence will show+up whenever 'f' is called. They may currently at rhs_tclvl, but they+had better be unifiable at the outer_tclvl! Example: envt mentions+alpha[1]+ tau_ty = beta[2] -> beta[2]+ constraints = alpha ~ [beta]+we don't quantify over beta (since it is fixed by envt)+so we must promote it! The inferred type is just+ f :: beta -> beta++NB: promoteTyVar ignores coercion variables++Note [Quantification and partial signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When choosing type variables to quantify, the basic plan is to+quantify over all type variables that are+ * free in the tau_tvs, and+ * not forced to be monomorphic (mono_tvs),+ for example by being free in the environment.++However, in the case of a partial type signature, be doing inference+*in the presence of a type signature*. For example:+ f :: _ -> a+ f x = ...+or+ g :: (Eq _a) => _b -> _b+In both cases we use plan InferGen, and hence call simplifyInfer. But+those 'a' variables are skolems (actually SigTvs), and we should be+sure to quantify over them. This leads to several wrinkles:++* Wrinkle 1. In the case of a type error+ f :: _ -> Maybe a+ f x = True && x+ The inferred type of 'f' is f :: Bool -> Bool, but there's a+ left-over error of form (HoleCan (Maybe a ~ Bool)). The error-reporting+ machine expects to find a binding site for the skolem 'a', so we+ add it to the quantified tyvars.++* Wrinkle 2. Consider the partial type signature+ f :: (Eq _) => Int -> Int+ f x = x+ In normal cases that makes sense; e.g.+ g :: Eq _a => _a -> _a+ g x = x+ where the signature makes the type less general than it could+ be. But for 'f' we must therefore quantify over the user-annotated+ constraints, to get+ f :: forall a. Eq a => Int -> Int+ (thereby correctly triggering an ambiguity error later). If we don't+ we'll end up with a strange open type+ f :: Eq alpha => Int -> Int+ which isn't ambiguous but is still very wrong.++ Bottom line: Try to quantify over any variable free in psig_theta,+ just like the tau-part of the type.++* Wrinkle 3 (Trac #13482). Also consider+ f :: forall a. _ => Int -> Int+ f x = if undefined :: a == undefined then x else 0+ Here we get an (Eq a) constraint, but it's not mentioned in the+ psig_theta nor the type of 'f'. Moreover, if we have+ f :: forall a. a -> _+ f x = not x+ and a constraint (a ~ g), where 'g' is free in the environment,+ we would not usually quanitfy over 'a'. But here we should anyway+ (leading to a justified subsequent error) since 'a' is explicitly+ quantified by the programmer.++ Bottom line: always quantify over the psig_tvs, regardless.++Note [Quantifying over equality constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Should we quantify over an equality constraint (s ~ t)? In general, we don't.+Doing so may simply postpone a type error from the function definition site to+its call site. (At worst, imagine (Int ~ Bool)).++However, consider this+ forall a. (F [a] ~ Int) => blah+Should we quantify over the (F [a] ~ Int)? Perhaps yes, because at the call+site we will know 'a', and perhaps we have instance F [Bool] = Int.+So we *do* quantify over a type-family equality where the arguments mention+the quantified variables.++Note [Growing the tau-tvs using constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(growThetaTyVars insts tvs) is the result of extending the set+ of tyvars, tvs, using all conceivable links from pred++E.g. tvs = {a}, preds = {H [a] b, K (b,Int) c, Eq e}+Then growThetaTyVars preds tvs = {a,b,c}++Notice that+ growThetaTyVars is conservative if v might be fixed by vs+ => v `elem` grow(vs,C)++Note [Quantification with errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we find that the RHS of the definition has some absolutely-insoluble+constraints, we abandon all attempts to find a context to quantify+over, and instead make the function fully-polymorphic in whatever+type we have found. For two reasons+ a) Minimise downstream errors+ b) Avoid spurious errors from this function++But NB that we must include *derived* errors in the check. Example:+ (a::*) ~ Int#+We get an insoluble derived error *~#, and we don't want to discard+it before doing the isInsolubleWC test! (Trac #8262)++Note [Default while Inferring]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Our current plan is that defaulting only happens at simplifyTop and+not simplifyInfer. This may lead to some insoluble deferred constraints.+Example:++instance D g => C g Int b++constraint inferred = (forall b. 0 => C gamma alpha b) /\ Num alpha+type inferred = gamma -> gamma++Now, if we try to default (alpha := Int) we will be able to refine the implication to+ (forall b. 0 => C gamma Int b)+which can then be simplified further to+ (forall b. 0 => D gamma)+Finally, we /can/ approximate this implication with (D gamma) and infer the quantified+type: forall g. D g => g -> g++Instead what will currently happen is that we will get a quantified type+(forall g. g -> g) and an implication:+ forall g. 0 => (forall b. 0 => C g alpha b) /\ Num alpha++Which, even if the simplifyTop defaults (alpha := Int) we will still be left with an+unsolvable implication:+ forall g. 0 => (forall b. 0 => D g)++The concrete example would be:+ h :: C g a s => g -> a -> ST s a+ f (x::gamma) = (\_ -> x) (runST (h x (undefined::alpha)) + 1)++But it is quite tedious to do defaulting and resolve the implication constraints, and+we have not observed code breaking because of the lack of defaulting in inference, so+we don't do it for now.++++Note [Minimize by Superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we quantify over a constraint, in simplifyInfer we need to+quantify over a constraint that is minimal in some sense: For+instance, if the final wanted constraint is (Eq alpha, Ord alpha),+we'd like to quantify over Ord alpha, because we can just get Eq alpha+from superclass selection from Ord alpha. This minimization is what+mkMinimalBySCs does. Then, simplifyInfer uses the minimal constraint+to check the original wanted.+++Note [Avoid unnecessary constraint simplification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -------- NB NB NB (Jun 12) -------------+ This note not longer applies; see the notes with Trac #4361.+ But I'm leaving it in here so we remember the issue.)+ ----------------------------------------+When inferring the type of a let-binding, with simplifyInfer,+try to avoid unnecessarily simplifying class constraints.+Doing so aids sharing, but it also helps with delicate+situations like++ instance C t => C [t] where ..++ f :: C [t] => ....+ f x = let g y = ...(constraint C [t])...+ in ...+When inferring a type for 'g', we don't want to apply the+instance decl, because then we can't satisfy (C t). So we+just notice that g isn't quantified over 't' and partition+the constraints before simplifying.++This only half-works, but then let-generalisation only half-works.++*********************************************************************************+* *+* Main Simplifier *+* *+***********************************************************************************++-}++simplifyWantedsTcM :: [CtEvidence] -> TcM WantedConstraints+-- Solve the specified Wanted constraints+-- Discard the evidence binds+-- Discards all Derived stuff in result+-- Postcondition: fully zonked and unflattened constraints+simplifyWantedsTcM wanted+ = do { traceTc "simplifyWantedsTcM {" (ppr wanted)+ ; (result, _) <- runTcS (solveWantedsAndDrop (mkSimpleWC wanted))+ ; result <- TcM.zonkWC result+ ; traceTc "simplifyWantedsTcM }" (ppr result)+ ; return result }++solveWantedsAndDrop :: WantedConstraints -> TcS WantedConstraints+-- Since solveWanteds returns the residual WantedConstraints,+-- it should always be called within a runTcS or something similar,+-- Result is not zonked+solveWantedsAndDrop wanted+ = do { wc <- solveWanteds wanted+ ; return (dropDerivedWC wc) }++solveWanteds :: WantedConstraints -> TcS WantedConstraints+-- so that the inert set doesn't mindlessly propagate.+-- NB: wc_simples may be wanted /or/ derived now+solveWanteds wc@(WC { wc_simple = simples, wc_insol = insols, wc_impl = implics })+ = do { traceTcS "solveWanteds {" (ppr wc)++ ; wc1 <- solveSimpleWanteds simples+ ; let WC { wc_simple = simples1, wc_insol = insols1, wc_impl = implics1 } = wc1++ ; (floated_eqs, implics2) <- solveNestedImplications (implics `unionBags` implics1)+ ; (no_new_scs, simples2) <- expandSuperClasses simples1++ ; traceTcS "solveWanteds middle" $ vcat [ text "simples1 =" <+> ppr simples1+ , text "simples2 =" <+> ppr simples2 ]++ ; dflags <- getDynFlags+ ; final_wc <- simpl_loop 0 (solverIterations dflags) floated_eqs+ no_new_scs+ (WC { wc_simple = simples2, wc_impl = implics2+ , wc_insol = insols `unionBags` insols1 })++ ; bb <- TcS.getTcEvBindsMap+ ; traceTcS "solveWanteds }" $+ vcat [ text "final wc =" <+> ppr final_wc+ , text "current evbinds =" <+> ppr (evBindMapBinds bb) ]++ ; return final_wc }++simpl_loop :: Int -> IntWithInf -> Cts -> Bool+ -> WantedConstraints+ -> TcS WantedConstraints+simpl_loop n limit floated_eqs no_new_deriveds+ wc@(WC { wc_simple = simples, wc_insol = insols, wc_impl = implics })+ | isEmptyBag floated_eqs && no_new_deriveds+ = return wc -- Done!++ | n `intGtLimit` limit+ = do { -- Add an error (not a warning) if we blow the limit,+ -- Typically if we blow the limit we are going to report some other error+ -- (an unsolved constraint), and we don't want that error to suppress+ -- the iteration limit warning!+ addErrTcS (hang (text "solveWanteds: too many iterations"+ <+> parens (text "limit =" <+> ppr limit))+ 2 (vcat [ text "Unsolved:" <+> ppr wc+ , ppUnless (isEmptyBag floated_eqs) $+ text "Floated equalities:" <+> ppr floated_eqs+ , ppUnless no_new_deriveds $+ text "New deriveds found"+ , text "Set limit with -fconstraint-solver-iterations=n; n=0 for no limit"+ ]))+ ; return wc }++ | otherwise+ = do { let n_floated = lengthBag floated_eqs+ ; csTraceTcS $+ text "simpl_loop iteration=" <> int n+ <+> (parens $ hsep [ text "no new deriveds =" <+> ppr no_new_deriveds <> comma+ , int n_floated <+> text "floated eqs" <> comma+ , int (lengthBag simples) <+> text "simples to solve" ])++ -- solveSimples may make progress if either float_eqs hold+ ; (unifs1, wc1) <- reportUnifications $+ solveSimpleWanteds (floated_eqs `unionBags` simples)+ -- Put floated_eqs first so they get solved first+ -- NB: the floated_eqs may include /derived/ equalities+ -- arising from fundeps inside an implication++ ; let WC { wc_simple = simples1, wc_insol = insols1, wc_impl = implics1 } = wc1+ ; (no_new_scs, simples2) <- expandSuperClasses simples1++ -- We have already tried to solve the nested implications once+ -- Try again only if we have unified some meta-variables+ -- (which is a bit like adding more givens+ -- See Note [Cutting off simpl_loop]+ ; (floated_eqs2, implics2) <- if unifs1 == 0 && isEmptyBag implics1+ then return (emptyBag, implics)+ else solveNestedImplications (implics `unionBags` implics1)++ ; simpl_loop (n+1) limit floated_eqs2 no_new_scs+ (WC { wc_simple = simples2, wc_impl = implics2+ , wc_insol = insols `unionBags` insols1 }) }++expandSuperClasses :: Cts -> TcS (Bool, Cts)+-- If there are any unsolved wanteds, expand one step of+-- superclasses for deriveds+-- Returned Bool is True <=> no new superclass constraints added+-- See Note [The superclass story] in TcCanonical+expandSuperClasses unsolved+ | not (anyBag superClassesMightHelp unsolved)+ = return (True, unsolved)+ | otherwise+ = do { traceTcS "expandSuperClasses {" empty+ ; let (pending_wanted, unsolved') = mapAccumBagL get [] unsolved+ get acc ct | Just ct' <- isPendingScDict ct+ = (ct':acc, ct')+ | otherwise+ = (acc, ct)+ ; pending_given <- getPendingScDicts+ ; if null pending_given && null pending_wanted+ then do { traceTcS "End expandSuperClasses no-op }" empty+ ; return (True, unsolved) }+ else+ do { new_given <- makeSuperClasses pending_given+ ; solveSimpleGivens new_given+ ; new_wanted <- makeSuperClasses pending_wanted+ ; traceTcS "End expandSuperClasses }"+ (vcat [ text "Given:" <+> ppr pending_given+ , text "Wanted:" <+> ppr new_wanted ])+ ; return (False, unsolved' `unionBags` listToBag new_wanted) } }++solveNestedImplications :: Bag Implication+ -> TcS (Cts, Bag Implication)+-- Precondition: the TcS inerts may contain unsolved simples which have+-- to be converted to givens before we go inside a nested implication.+solveNestedImplications implics+ | isEmptyBag implics+ = return (emptyBag, emptyBag)+ | otherwise+ = do { traceTcS "solveNestedImplications starting {" empty+ ; (floated_eqs_s, unsolved_implics) <- mapAndUnzipBagM solveImplication implics+ ; let floated_eqs = concatBag floated_eqs_s++ -- ... and we are back in the original TcS inerts+ -- Notice that the original includes the _insoluble_simples so it was safe to ignore+ -- them in the beginning of this function.+ ; traceTcS "solveNestedImplications end }" $+ vcat [ text "all floated_eqs =" <+> ppr floated_eqs+ , text "unsolved_implics =" <+> ppr unsolved_implics ]++ ; return (floated_eqs, catBagMaybes unsolved_implics) }++solveImplication :: Implication -- Wanted+ -> TcS (Cts, -- All wanted or derived floated equalities: var = type+ Maybe Implication) -- Simplified implication (empty or singleton)+-- Precondition: The TcS monad contains an empty worklist and given-only inerts+-- which after trying to solve this implication we must restore to their original value+solveImplication imp@(Implic { ic_tclvl = tclvl+ , ic_binds = ev_binds_var+ , ic_skols = skols+ , ic_given = given_ids+ , ic_wanted = wanteds+ , ic_info = info+ , ic_status = status+ , ic_env = env })+ | isSolvedStatus status+ = return (emptyCts, Just imp) -- Do nothing++ | otherwise -- Even for IC_Insoluble it is worth doing more work+ -- The insoluble stuff might be in one sub-implication+ -- and other unsolved goals in another; and we want to+ -- solve the latter as much as possible+ = do { inerts <- getTcSInerts+ ; traceTcS "solveImplication {" (ppr imp $$ text "Inerts" <+> ppr inerts)++ -- Solve the nested constraints+ ; (no_given_eqs, given_insols, residual_wanted)+ <- nestImplicTcS ev_binds_var tclvl $+ do { let loc = mkGivenLoc tclvl info env+ givens = mkGivens loc given_ids+ ; solveSimpleGivens givens++ ; residual_wanted <- solveWanteds wanteds+ -- solveWanteds, *not* solveWantedsAndDrop, because+ -- we want to retain derived equalities so we can float+ -- them out in floatEqualities++ ; (no_eqs, given_insols) <- getNoGivenEqs tclvl skols+ -- Call getNoGivenEqs /after/ solveWanteds, because+ -- solveWanteds can augment the givens, via expandSuperClasses,+ -- to reveal given superclass equalities++ ; return (no_eqs, given_insols, residual_wanted) }++ ; (floated_eqs, residual_wanted)+ <- floatEqualities skols no_given_eqs residual_wanted++ ; traceTcS "solveImplication 2"+ (ppr given_insols $$ ppr residual_wanted)+ ; let final_wanted = residual_wanted `addInsols` given_insols++ ; res_implic <- setImplicationStatus (imp { ic_no_eqs = no_given_eqs+ , ic_wanted = final_wanted })++ ; (evbinds, tcvs) <- TcS.getTcEvBindsAndTCVs ev_binds_var+ ; traceTcS "solveImplication end }" $ vcat+ [ text "no_given_eqs =" <+> ppr no_given_eqs+ , text "floated_eqs =" <+> ppr floated_eqs+ , text "res_implic =" <+> ppr res_implic+ , text "implication evbinds =" <+> ppr (evBindMapBinds evbinds)+ , text "implication tvcs =" <+> ppr tcvs ]++ ; return (floated_eqs, res_implic) }++----------------------+setImplicationStatus :: Implication -> TcS (Maybe Implication)+-- Finalise the implication returned from solveImplication:+-- * Set the ic_status field+-- * Trim the ic_wanted field to remove Derived constraints+-- Precondition: the ic_status field is not already IC_Solved+-- Return Nothing if we can discard the implication altogether+setImplicationStatus implic@(Implic { ic_binds = ev_binds_var+ , ic_status = status+ , ic_info = info+ , ic_wanted = wc+ , ic_needed = old_discarded_needs+ , ic_given = givens })+ | ASSERT2( not (isSolvedStatus status ), ppr info )+ -- Precondition: we only set the status if it is not already solved+ some_insoluble+ = return $ Just $+ implic { ic_status = IC_Insoluble+ , ic_needed = new_discarded_needs+ , ic_wanted = pruned_wc }++ | some_unsolved+ = do { traceTcS "setImplicationStatus" $+ vcat [ppr givens $$ ppr simples $$ ppr insols $$ ppr mb_implic_needs]+ ; return $ Just $+ implic { ic_status = IC_Unsolved+ , ic_needed = new_discarded_needs+ , ic_wanted = pruned_wc }+ }++ | otherwise -- Everything is solved; look at the implications+ -- See Note [Tracking redundant constraints]+ = do { ev_binds <- TcS.getTcEvBindsAndTCVs ev_binds_var+ ; let all_needs = neededEvVars ev_binds $+ solved_implic_needs `unionVarSet` new_discarded_needs++ dead_givens | warnRedundantGivens info+ = filterOut (`elemVarSet` all_needs) givens+ | otherwise = [] -- None to report++ final_needs = all_needs `delVarSetList` givens++ discard_entire_implication -- Can we discard the entire implication?+ = null dead_givens -- No warning from this implication+ && isEmptyBag pruned_implics -- No live children+ && isEmptyVarSet final_needs -- No needed vars to pass up to parent++ final_status = IC_Solved { ics_need = final_needs+ , ics_dead = dead_givens }+ final_implic = implic { ic_status = final_status+ , ic_needed = emptyVarSet -- Irrelevant for IC_Solved+ , ic_wanted = pruned_wc }++ -- Check that there are no term-level evidence bindings+ -- in the cases where we have no place to put them+ ; MASSERT2( termEvidenceAllowed info || isEmptyEvBindMap (fst ev_binds)+ , ppr info $$ ppr ev_binds )++ ; traceTcS "setImplicationStatus 2" $+ vcat [ppr givens $$ ppr ev_binds $$ ppr all_needs]+ ; return $ if discard_entire_implication+ then Nothing+ else Just final_implic }+ where+ WC { wc_simple = simples, wc_impl = implics, wc_insol = insols } = wc++ some_insoluble = insolubleWC wc+ some_unsolved = not (isEmptyBag simples && isEmptyBag insols)+ || isNothing mb_implic_needs++ pruned_simples = dropDerivedSimples simples+ pruned_insols = dropDerivedInsols insols+ (pruned_implics, discarded_needs) = partitionBagWith discard_me implics+ pruned_wc = wc { wc_simple = pruned_simples+ , wc_insol = pruned_insols+ , wc_impl = pruned_implics }+ new_discarded_needs = foldrBag unionVarSet old_discarded_needs discarded_needs++ mb_implic_needs :: Maybe VarSet+ -- Just vs => all implics are IC_Solved, with 'vs' needed+ -- Nothing => at least one implic is not IC_Solved+ mb_implic_needs = foldrBag add_implic (Just emptyVarSet) pruned_implics+ Just solved_implic_needs = mb_implic_needs++ add_implic implic acc+ | Just vs_acc <- acc+ , IC_Solved { ics_need = vs } <- ic_status implic+ = Just (vs `unionVarSet` vs_acc)+ | otherwise = Nothing++ discard_me :: Implication -> Either Implication VarSet+ discard_me ic+ | IC_Solved { ics_dead = dead_givens, ics_need = needed } <- ic_status ic+ -- Fully solved+ , null dead_givens -- No redundant givens to report+ , isEmptyBag (wc_impl (ic_wanted ic))+ -- And no children that might have things to report+ = Right needed+ | otherwise+ = Left ic++warnRedundantGivens :: SkolemInfo -> Bool+warnRedundantGivens (SigSkol ctxt _ _)+ = case ctxt of+ FunSigCtxt _ warn_redundant -> warn_redundant+ ExprSigCtxt -> True+ _ -> False++ -- To think about: do we want to report redundant givens for+ -- pattern synonyms, PatSynSigSkol? c.f Trac #9953, comment:21.+warnRedundantGivens (InstSkol {}) = True+warnRedundantGivens _ = False++neededEvVars :: (EvBindMap, TcTyVarSet) -> VarSet -> VarSet+-- Find all the evidence variables that are "needed",+-- and then delete all those bound by the evidence bindings+-- See Note [Tracking redundant constraints]+neededEvVars (ev_binds, tcvs) initial_seeds+ = (needed `unionVarSet` tcvs) `minusVarSet` bndrs+ where+ seeds = foldEvBindMap add_wanted initial_seeds ev_binds+ needed = transCloVarSet also_needs seeds+ bndrs = foldEvBindMap add_bndr emptyVarSet ev_binds++ add_wanted :: EvBind -> VarSet -> VarSet+ add_wanted (EvBind { eb_is_given = is_given, eb_rhs = rhs }) needs+ | is_given = needs -- Add the rhs vars of the Wanted bindings only+ | otherwise = evVarsOfTerm rhs `unionVarSet` needs++ also_needs :: VarSet -> VarSet+ also_needs needs+ = nonDetFoldUniqSet add emptyVarSet needs+ -- It's OK to use nonDetFoldUFM here because we immediately forget+ -- about the ordering by creating a set+ where+ add v needs+ | Just ev_bind <- lookupEvBind ev_binds v+ , EvBind { eb_is_given = is_given, eb_rhs = rhs } <- ev_bind+ , is_given+ = evVarsOfTerm rhs `unionVarSet` needs+ | otherwise+ = needs++ add_bndr :: EvBind -> VarSet -> VarSet+ add_bndr (EvBind { eb_lhs = v }) vs = extendVarSet vs v+++{-+Note [Tracking redundant constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+With Opt_WarnRedundantConstraints, GHC can report which+constraints of a type signature (or instance declaration) are+redundant, and can be omitted. Here is an overview of how it+works:++----- What is a redundant constraint?++* The things that can be redundant are precisely the Given+ constraints of an implication.++* A constraint can be redundant in two different ways:+ a) It is implied by other givens. E.g.+ f :: (Eq a, Ord a) => blah -- Eq a unnecessary+ g :: (Eq a, a~b, Eq b) => blah -- Either Eq a or Eq b unnecessary+ b) It is not needed by the Wanted constraints covered by the+ implication E.g.+ f :: Eq a => a -> Bool+ f x = True -- Equality not used++* To find (a), when we have two Given constraints,+ we must be careful to drop the one that is a naked variable (if poss).+ So if we have+ f :: (Eq a, Ord a) => blah+ then we may find [G] sc_sel (d1::Ord a) :: Eq a+ [G] d2 :: Eq a+ We want to discard d2 in favour of the superclass selection from+ the Ord dictionary. This is done by TcInteract.solveOneFromTheOther+ See Note [Replacement vs keeping].++* To find (b) we need to know which evidence bindings are 'wanted';+ hence the eb_is_given field on an EvBind.++----- How tracking works++* When the constraint solver finishes solving all the wanteds in+ an implication, it sets its status to IC_Solved++ - The ics_dead field, of IC_Solved, records the subset of this+ implication's ic_given that are redundant (not needed).++ - The ics_need field of IC_Solved then records all the+ in-scope (given) evidence variables bound by the context, that+ were needed to solve this implication, including all its nested+ implications. (We remove the ic_given of this implication from+ the set, of course.)++* We compute which evidence variables are needed by an implication+ in setImplicationStatus. A variable is needed if+ a) it is free in the RHS of a Wanted EvBind,+ b) it is free in the RHS of an EvBind whose LHS is needed,+ c) it is in the ics_need of a nested implication.++* We need to be careful not to discard an implication+ prematurely, even one that is fully solved, because we might+ thereby forget which variables it needs, and hence wrongly+ report a constraint as redundant. But we can discard it once+ its free vars have been incorporated into its parent; or if it+ simply has no free vars. This careful discarding is also+ handled in setImplicationStatus.++----- Reporting redundant constraints++* TcErrors does the actual warning, in warnRedundantConstraints.++* We don't report redundant givens for *every* implication; only+ for those which reply True to TcSimplify.warnRedundantGivens:++ - For example, in a class declaration, the default method *can*+ use the class constraint, but it certainly doesn't *have* to,+ and we don't want to report an error there.++ - More subtly, in a function definition+ f :: (Ord a, Ord a, Ix a) => a -> a+ f x = rhs+ we do an ambiguity check on the type (which would find that one+ of the Ord a constraints was redundant), and then we check that+ the definition has that type (which might find that both are+ redundant). We don't want to report the same error twice, so we+ disable it for the ambiguity check. Hence using two different+ FunSigCtxts, one with the warn-redundant field set True, and the+ other set False in+ - TcBinds.tcSpecPrag+ - TcBinds.tcTySig++ This decision is taken in setImplicationStatus, rather than TcErrors+ so that we can discard implication constraints that we don't need.+ So ics_dead consists only of the *reportable* redundant givens.++----- Shortcomings++Consider (see Trac #9939)+ f2 :: (Eq a, Ord a) => a -> a -> Bool+ -- Ord a redundant, but Eq a is reported+ f2 x y = (x == y)++We report (Eq a) as redundant, whereas actually (Ord a) is. But it's+really not easy to detect that!+++Note [Cutting off simpl_loop]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It is very important not to iterate in simpl_loop unless there is a chance+of progress. Trac #8474 is a classic example:++ * There's a deeply-nested chain of implication constraints.+ ?x:alpha => ?y1:beta1 => ... ?yn:betan => [W] ?x:Int++ * From the innermost one we get a [D] alpha ~ Int,+ but alpha is untouchable until we get out to the outermost one++ * We float [D] alpha~Int out (it is in floated_eqs), but since alpha+ is untouchable, the solveInteract in simpl_loop makes no progress++ * So there is no point in attempting to re-solve+ ?yn:betan => [W] ?x:Int+ via solveNestedImplications, because we'll just get the+ same [D] again++ * If we *do* re-solve, we'll get an ininite loop. It is cut off by+ the fixed bound of 10, but solving the next takes 10*10*...*10 (ie+ exponentially many) iterations!++Conclusion: we should call solveNestedImplications only if we did+some unification in solveSimpleWanteds; because that's the only way+we'll get more Givens (a unification is like adding a Given) to+allow the implication to make progress.+-}++promoteTyVar :: TcLevel -> TcTyVar -> TcM Bool+-- When we float a constraint out of an implication we must restore+-- invariant (MetaTvInv) in Note [TcLevel and untouchable type variables] in TcType+-- Return True <=> we did some promotion+-- See Note [Promoting unification variables]+promoteTyVar tclvl tv+ | isFloatedTouchableMetaTyVar tclvl tv+ = do { cloned_tv <- TcM.cloneMetaTyVar tv+ ; let rhs_tv = setMetaTyVarTcLevel cloned_tv tclvl+ ; TcM.writeMetaTyVar tv (mkTyVarTy rhs_tv)+ ; return True }+ | otherwise+ = return False++promoteTyVarTcS :: TcLevel -> TcTyVar -> TcS ()+-- When we float a constraint out of an implication we must restore+-- invariant (MetaTvInv) in Note [TcLevel and untouchable type variables] in TcType+-- See Note [Promoting unification variables]+-- We don't just call promoteTyVar because we want to use unifyTyVar,+-- not writeMetaTyVar+promoteTyVarTcS tclvl tv+ | isFloatedTouchableMetaTyVar tclvl tv+ = do { cloned_tv <- TcS.cloneMetaTyVar tv+ ; let rhs_tv = setMetaTyVarTcLevel cloned_tv tclvl+ ; unifyTyVar tv (mkTyVarTy rhs_tv) }+ | otherwise+ = return ()++-- | Like 'defaultTyVar', but in the TcS monad.+defaultTyVarTcS :: TcTyVar -> TcS Bool+defaultTyVarTcS the_tv+ | isRuntimeRepVar the_tv+ = do { traceTcS "defaultTyVarTcS RuntimeRep" (ppr the_tv)+ ; unifyTyVar the_tv liftedRepTy+ ; return True }+ | otherwise+ = return False -- the common case++approximateWC :: Bool -> WantedConstraints -> Cts+-- Postcondition: Wanted or Derived Cts+-- See Note [ApproximateWC]+approximateWC float_past_equalities wc+ = float_wc emptyVarSet wc+ where+ float_wc :: TcTyCoVarSet -> WantedConstraints -> Cts+ float_wc trapping_tvs (WC { wc_simple = simples, wc_impl = implics })+ = filterBag is_floatable simples `unionBags`+ do_bag (float_implic trapping_tvs) implics+ where+ is_floatable ct = tyCoVarsOfCt ct `disjointVarSet` trapping_tvs++ float_implic :: TcTyCoVarSet -> Implication -> Cts+ float_implic trapping_tvs imp+ | float_past_equalities || ic_no_eqs imp+ = float_wc new_trapping_tvs (ic_wanted imp)+ | otherwise -- Take care with equalities+ = emptyCts -- See (1) under Note [ApproximateWC]+ where+ new_trapping_tvs = trapping_tvs `extendVarSetList` ic_skols imp+ do_bag :: (a -> Bag c) -> Bag a -> Bag c+ do_bag f = foldrBag (unionBags.f) emptyBag++{- Note [ApproximateWC]+~~~~~~~~~~~~~~~~~~~~~~~+approximateWC takes a constraint, typically arising from the RHS of a+let-binding whose type we are *inferring*, and extracts from it some+*simple* constraints that we might plausibly abstract over. Of course+the top-level simple constraints are plausible, but we also float constraints+out from inside, if they are not captured by skolems.++The same function is used when doing type-class defaulting (see the call+to applyDefaultingRules) to extract constraints that that might be defaulted.++There is one caveat:++1. When infering most-general types (in simplifyInfer), we do *not*+ float anything out if the implication binds equality constraints,+ because that defeats the OutsideIn story. Consider+ data T a where+ TInt :: T Int+ MkT :: T a++ f TInt = 3::Int++ We get the implication (a ~ Int => res ~ Int), where so far we've decided+ f :: T a -> res+ We don't want to float (res~Int) out because then we'll infer+ f :: T a -> Int+ which is only on of the possible types. (GHC 7.6 accidentally *did*+ float out of such implications, which meant it would happily infer+ non-principal types.)++ HOWEVER (Trac #12797) in findDefaultableGroups we are not worried about+ the most-general type; and we /do/ want to float out of equalities.+ Hence the boolean flag to approximateWC.++------ Historical note -----------+There used to be a second caveat, driven by Trac #8155++ 2. We do not float out an inner constraint that shares a type variable+ (transitively) with one that is trapped by a skolem. Eg+ forall a. F a ~ beta, Integral beta+ We don't want to float out (Integral beta). Doing so would be bad+ when defaulting, because then we'll default beta:=Integer, and that+ makes the error message much worse; we'd get+ Can't solve F a ~ Integer+ rather than+ Can't solve Integral (F a)++ Moreover, floating out these "contaminated" constraints doesn't help+ when generalising either. If we generalise over (Integral b), we still+ can't solve the retained implication (forall a. F a ~ b). Indeed,+ arguably that too would be a harder error to understand.++But this transitive closure stuff gives rise to a complex rule for+when defaulting actually happens, and one that was never documented.+Moreover (Trac #12923), the more complex rule is sometimes NOT what+you want. So I simply removed the extra code to implement the+contamination stuff. There was zero effect on the testsuite (not even+#8155).+------ End of historical note -----------+++Note [DefaultTyVar]+~~~~~~~~~~~~~~~~~~~+defaultTyVar is used on any un-instantiated meta type variables to+default any RuntimeRep variables to LiftedRep. This is important+to ensure that instance declarations match. For example consider++ instance Show (a->b)+ foo x = show (\_ -> True)++Then we'll get a constraint (Show (p ->q)) where p has kind (TYPE r),+and that won't match the typeKind (*) in the instance decl. See tests+tc217 and tc175.++We look only at touchable type variables. No further constraints+are going to affect these type variables, so it's time to do it by+hand. However we aren't ready to default them fully to () or+whatever, because the type-class defaulting rules have yet to run.++An alternate implementation would be to emit a derived constraint setting+the RuntimeRep variable to LiftedRep, but this seems unnecessarily indirect.++Note [Promote _and_ default when inferring]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we are inferring a type, we simplify the constraint, and then use+approximateWC to produce a list of candidate constraints. Then we MUST++ a) Promote any meta-tyvars that have been floated out by+ approximateWC, to restore invariant (MetaTvInv) described in+ Note [TcLevel and untouchable type variables] in TcType.++ b) Default the kind of any meta-tyvars that are not mentioned in+ in the environment.++To see (b), suppose the constraint is (C ((a :: OpenKind) -> Int)), and we+have an instance (C ((x:*) -> Int)). The instance doesn't match -- but it+should! If we don't solve the constraint, we'll stupidly quantify over+(C (a->Int)) and, worse, in doing so zonkQuantifiedTyVar will quantify over+(b:*) instead of (a:OpenKind), which can lead to disaster; see Trac #7332.+Trac #7641 is a simpler example.++Note [Promoting unification variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we float an equality out of an implication we must "promote" free+unification variables of the equality, in order to maintain Invariant+(MetaTvInv) from Note [TcLevel and untouchable type variables] in TcType. for the+leftover implication.++This is absolutely necessary. Consider the following example. We start+with two implications and a class with a functional dependency.++ class C x y | x -> y+ instance C [a] [a]++ (I1) [untch=beta]forall b. 0 => F Int ~ [beta]+ (I2) [untch=beta]forall c. 0 => F Int ~ [[alpha]] /\ C beta [c]++We float (F Int ~ [beta]) out of I1, and we float (F Int ~ [[alpha]]) out of I2.+They may react to yield that (beta := [alpha]) which can then be pushed inwards+the leftover of I2 to get (C [alpha] [a]) which, using the FunDep, will mean that+(alpha := a). In the end we will have the skolem 'b' escaping in the untouchable+beta! Concrete example is in indexed_types/should_fail/ExtraTcsUntch.hs:++ class C x y | x -> y where+ op :: x -> y -> ()++ instance C [a] [a]++ type family F a :: *++ h :: F Int -> ()+ h = undefined++ data TEx where+ TEx :: a -> TEx++ f (x::beta) =+ let g1 :: forall b. b -> ()+ g1 _ = h [x]+ g2 z = case z of TEx y -> (h [[undefined]], op x [y])+ in (g1 '3', g2 undefined)++++*********************************************************************************+* *+* Floating equalities *+* *+*********************************************************************************++Note [Float Equalities out of Implications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For ordinary pattern matches (including existentials) we float+equalities out of implications, for instance:+ data T where+ MkT :: Eq a => a -> T+ f x y = case x of MkT _ -> (y::Int)+We get the implication constraint (x::T) (y::alpha):+ forall a. [untouchable=alpha] Eq a => alpha ~ Int+We want to float out the equality into a scope where alpha is no+longer untouchable, to solve the implication!++But we cannot float equalities out of implications whose givens may+yield or contain equalities:++ data T a where+ T1 :: T Int+ T2 :: T Bool+ T3 :: T a++ h :: T a -> a -> Int++ f x y = case x of+ T1 -> y::Int+ T2 -> y::Bool+ T3 -> h x y++We generate constraint, for (x::T alpha) and (y :: beta):+ [untouchables = beta] (alpha ~ Int => beta ~ Int) -- From 1st branch+ [untouchables = beta] (alpha ~ Bool => beta ~ Bool) -- From 2nd branch+ (alpha ~ beta) -- From 3rd branch++If we float the equality (beta ~ Int) outside of the first implication and+the equality (beta ~ Bool) out of the second we get an insoluble constraint.+But if we just leave them inside the implications, we unify alpha := beta and+solve everything.++Principle:+ We do not want to float equalities out which may+ need the given *evidence* to become soluble.++Consequence: classes with functional dependencies don't matter (since there is+no evidence for a fundep equality), but equality superclasses do matter (since+they carry evidence).+-}++floatEqualities :: [TcTyVar] -> Bool+ -> WantedConstraints+ -> TcS (Cts, WantedConstraints)+-- Main idea: see Note [Float Equalities out of Implications]+--+-- Precondition: the wc_simple of the incoming WantedConstraints are+-- fully zonked, so that we can see their free variables+--+-- Postcondition: The returned floated constraints (Cts) are only+-- Wanted or Derived+--+-- Also performs some unifications (via promoteTyVar), adding to+-- monadically-carried ty_binds. These will be used when processing+-- floated_eqs later+--+-- Subtleties: Note [Float equalities from under a skolem binding]+-- Note [Skolem escape]+floatEqualities skols no_given_eqs+ wanteds@(WC { wc_simple = simples })+ | not no_given_eqs -- There are some given equalities, so don't float+ = return (emptyBag, wanteds) -- Note [Float Equalities out of Implications]+ | otherwise+ = do { outer_tclvl <- TcS.getTcLevel+ ; mapM_ (promoteTyVarTcS outer_tclvl)+ (tyCoVarsOfCtsList float_eqs)+ -- See Note [Promoting unification variables]++ ; traceTcS "floatEqualities" (vcat [ text "Skols =" <+> ppr skols+ , text "Simples =" <+> ppr simples+ , text "Floated eqs =" <+> ppr float_eqs])+ ; return ( float_eqs+ , wanteds { wc_simple = remaining_simples } ) }+ where+ skol_set = mkVarSet skols+ (float_eqs, remaining_simples) = partitionBag (usefulToFloat skol_set) simples++usefulToFloat :: VarSet -> Ct -> Bool+usefulToFloat skol_set ct -- The constraint is un-flattened and de-canonicalised+ = is_meta_var_eq pred &&+ (tyCoVarsOfType pred `disjointVarSet` skol_set)+ where+ pred = ctPred ct++ -- Float out alpha ~ ty, or ty ~ alpha+ -- which might be unified outside+ -- See Note [Which equalities to float]+ is_meta_var_eq pred+ | EqPred NomEq ty1 ty2 <- classifyPredType pred+ = case (tcGetTyVar_maybe ty1, tcGetTyVar_maybe ty2) of+ (Just tv1, _) -> float_tv_eq tv1 ty2+ (_, Just tv2) -> float_tv_eq tv2 ty1+ _ -> False+ | otherwise+ = False++ float_tv_eq tv1 ty2 -- See Note [Which equalities to float]+ = isMetaTyVar tv1+ && (not (isSigTyVar tv1) || isTyVarTy ty2)++{- Note [Float equalities from under a skolem binding]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Which of the simple equalities can we float out? Obviously, only+ones that don't mention the skolem-bound variables. But that is+over-eager. Consider+ [2] forall a. F a beta[1] ~ gamma[2], G beta[1] gamma[2] ~ Int+The second constraint doesn't mention 'a'. But if we float it,+we'll promote gamma[2] to gamma'[1]. Now suppose that we learn that+beta := Bool, and F a Bool = a, and G Bool _ = Int. Then we'll+we left with the constraint+ [2] forall a. a ~ gamma'[1]+which is insoluble because gamma became untouchable.++Solution: float only constraints that stand a jolly good chance of+being soluble simply by being floated, namely ones of form+ a ~ ty+where 'a' is a currently-untouchable unification variable, but may+become touchable by being floated (perhaps by more than one level).++We had a very complicated rule previously, but this is nice and+simple. (To see the notes, look at this Note in a version of+TcSimplify prior to Oct 2014).++Note [Which equalities to float]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Which equalities should we float? We want to float ones where there+is a decent chance that floating outwards will allow unification to+happen. In particular:++ Float out equalities of form (alpha ~ ty) or (ty ~ alpha), where++ * alpha is a meta-tyvar.++ * And 'alpha' is not a SigTv with 'ty' being a non-tyvar. In that+ case, floating out won't help either, and it may affect grouping+ of error messages.++Note [Skolem escape]+~~~~~~~~~~~~~~~~~~~~+You might worry about skolem escape with all this floating.+For example, consider+ [2] forall a. (a ~ F beta[2] delta,+ Maybe beta[2] ~ gamma[1])++The (Maybe beta ~ gamma) doesn't mention 'a', so we float it, and+solve with gamma := beta. But what if later delta:=Int, and+ F b Int = b.+Then we'd get a ~ beta[2], and solve to get beta:=a, and now the+skolem has escaped!++But it's ok: when we float (Maybe beta[2] ~ gamma[1]), we promote beta[2]+to beta[1], and that means the (a ~ beta[1]) will be stuck, as it should be.+++*********************************************************************************+* *+* Defaulting and disambiguation *+* *+*********************************************************************************+-}++applyDefaultingRules :: WantedConstraints -> TcS Bool+-- True <=> I did some defaulting, by unifying a meta-tyvar+-- Input WantedConstraints are not necessarily zonked++applyDefaultingRules wanteds+ | isEmptyWC wanteds+ = return False+ | otherwise+ = do { info@(default_tys, _) <- getDefaultInfo+ ; wanteds <- TcS.zonkWC wanteds++ ; let groups = findDefaultableGroups info wanteds++ ; traceTcS "applyDefaultingRules {" $+ vcat [ text "wanteds =" <+> ppr wanteds+ , text "groups =" <+> ppr groups+ , text "info =" <+> ppr info ]++ ; something_happeneds <- mapM (disambigGroup default_tys) groups++ ; traceTcS "applyDefaultingRules }" (ppr something_happeneds)++ ; return (or something_happeneds) }++findDefaultableGroups+ :: ( [Type]+ , (Bool,Bool) ) -- (Overloaded strings, extended default rules)+ -> WantedConstraints -- Unsolved (wanted or derived)+ -> [(TyVar, [Ct])]+findDefaultableGroups (default_tys, (ovl_strings, extended_defaults)) wanteds+ | null default_tys+ = []+ | otherwise+ = [ (tv, map fstOf3 group)+ | group@((_,_,tv):_) <- unary_groups+ , defaultable_tyvar tv+ , defaultable_classes (map sndOf3 group) ]+ where+ simples = approximateWC True wanteds+ (unaries, non_unaries) = partitionWith find_unary (bagToList simples)+ unary_groups = equivClasses cmp_tv unaries++ unary_groups :: [[(Ct, Class, TcTyVar)]] -- (C tv) constraints+ unaries :: [(Ct, Class, TcTyVar)] -- (C tv) constraints+ non_unaries :: [Ct] -- and *other* constraints++ -- Finds unary type-class constraints+ -- But take account of polykinded classes like Typeable,+ -- which may look like (Typeable * (a:*)) (Trac #8931)+ find_unary :: Ct -> Either (Ct, Class, TyVar) Ct+ find_unary cc+ | Just (cls,tys) <- getClassPredTys_maybe (ctPred cc)+ , [ty] <- filterOutInvisibleTypes (classTyCon cls) tys+ -- Ignore invisible arguments for this purpose+ , Just tv <- tcGetTyVar_maybe ty+ , isMetaTyVar tv -- We might have runtime-skolems in GHCi, and+ -- we definitely don't want to try to assign to those!+ = Left (cc, cls, tv)+ find_unary cc = Right cc -- Non unary or non dictionary++ bad_tvs :: TcTyCoVarSet -- TyVars mentioned by non-unaries+ bad_tvs = mapUnionVarSet tyCoVarsOfCt non_unaries++ cmp_tv (_,_,tv1) (_,_,tv2) = tv1 `compare` tv2++ defaultable_tyvar :: TcTyVar -> Bool+ defaultable_tyvar tv+ = let b1 = isTyConableTyVar tv -- Note [Avoiding spurious errors]+ b2 = not (tv `elemVarSet` bad_tvs)+ in b1 && (b2 || extended_defaults) -- Note [Multi-parameter defaults]++ defaultable_classes :: [Class] -> Bool+ defaultable_classes clss+ | extended_defaults = any (isInteractiveClass ovl_strings) clss+ | otherwise = all is_std_class clss && (any (isNumClass ovl_strings) clss)++ -- is_std_class adds IsString to the standard numeric classes,+ -- when -foverloaded-strings is enabled+ is_std_class cls = isStandardClass cls ||+ (ovl_strings && (cls `hasKey` isStringClassKey))++------------------------------+disambigGroup :: [Type] -- The default types+ -> (TcTyVar, [Ct]) -- All classes of the form (C a)+ -- sharing same type variable+ -> TcS Bool -- True <=> something happened, reflected in ty_binds++disambigGroup [] _+ = return False+disambigGroup (default_ty:default_tys) group@(the_tv, wanteds)+ = do { traceTcS "disambigGroup {" (vcat [ ppr default_ty, ppr the_tv, ppr wanteds ])+ ; fake_ev_binds_var <- TcS.newTcEvBinds+ ; tclvl <- TcS.getTcLevel+ ; success <- nestImplicTcS fake_ev_binds_var (pushTcLevel tclvl) try_group++ ; if success then+ -- Success: record the type variable binding, and return+ do { unifyTyVar the_tv default_ty+ ; wrapWarnTcS $ warnDefaulting wanteds default_ty+ ; traceTcS "disambigGroup succeeded }" (ppr default_ty)+ ; return True }+ else+ -- Failure: try with the next type+ do { traceTcS "disambigGroup failed, will try other default types }"+ (ppr default_ty)+ ; disambigGroup default_tys group } }+ where+ try_group+ | Just subst <- mb_subst+ = do { lcl_env <- TcS.getLclEnv+ ; let loc = CtLoc { ctl_origin = GivenOrigin UnkSkol+ , ctl_env = lcl_env+ , ctl_t_or_k = Nothing+ , ctl_depth = initialSubGoalDepth }+ ; wanted_evs <- mapM (newWantedEvVarNC loc . substTy subst . ctPred)+ wanteds+ ; fmap isEmptyWC $+ solveSimpleWanteds $ listToBag $+ map mkNonCanonical wanted_evs }++ | otherwise+ = return False++ the_ty = mkTyVarTy the_tv+ mb_subst = tcMatchTyKi the_ty default_ty+ -- Make sure the kinds match too; hence this call to tcMatchTyKi+ -- E.g. suppose the only constraint was (Typeable k (a::k))+ -- With the addition of polykinded defaulting we also want to reject+ -- ill-kinded defaulting attempts like (Eq []) or (Foldable Int) here.++-- In interactive mode, or with -XExtendedDefaultRules,+-- we default Show a to Show () to avoid graututious errors on "show []"+isInteractiveClass :: Bool -- -XOverloadedStrings?+ -> Class -> Bool+isInteractiveClass ovl_strings cls+ = isNumClass ovl_strings cls || (classKey cls `elem` interactiveClassKeys)++ -- isNumClass adds IsString to the standard numeric classes,+ -- when -foverloaded-strings is enabled+isNumClass :: Bool -- -XOverloadedStrings?+ -> Class -> Bool+isNumClass ovl_strings cls+ = isNumericClass cls || (ovl_strings && (cls `hasKey` isStringClassKey))+++{-+Note [Avoiding spurious errors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When doing the unification for defaulting, we check for skolem+type variables, and simply don't default them. For example:+ f = (*) -- Monomorphic+ g :: Num a => a -> a+ g x = f x x+Here, we get a complaint when checking the type signature for g,+that g isn't polymorphic enough; but then we get another one when+dealing with the (Num a) context arising from f's definition;+we try to unify a with Int (to default it), but find that it's+already been unified with the rigid variable from g's type sig.++Note [Multi-parameter defaults]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+With -XExtendedDefaultRules, we default only based on single-variable+constraints, but do not exclude from defaulting any type variables which also+appear in multi-variable constraints. This means that the following will+default properly:++ default (Integer, Double)++ class A b (c :: Symbol) where+ a :: b -> Proxy c++ instance A Integer c where a _ = Proxy++ main = print (a 5 :: Proxy "5")++Note that if we change the above instance ("instance A Integer") to+"instance A Double", we get an error:++ No instance for (A Integer "5")++This is because the first defaulted type (Integer) has successfully satisfied+its single-parameter constraints (in this case Num).+-}
+ typecheck/TcSplice.hs view
@@ -0,0 +1,2002 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++TcSplice: Template Haskell splices+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE MultiWayIf #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module TcSplice(+ tcSpliceExpr, tcTypedBracket, tcUntypedBracket,+-- runQuasiQuoteExpr, runQuasiQuotePat,+-- runQuasiQuoteDecl, runQuasiQuoteType,+ runAnnotation,++ runMetaE, runMetaP, runMetaT, runMetaD, runQuasi,+ tcTopSpliceExpr, lookupThName_maybe,+ defaultRunMeta, runMeta', runRemoteModFinalizers,+ finishTH+ ) where++#include "HsVersions.h"++import HsSyn+import Annotations+import Name+import TcRnMonad+import TcType++import Outputable+import TcExpr+import SrcLoc+import THNames+import TcUnify+import TcEnv++import Control.Monad++import GHCi.Message+import GHCi.RemoteTypes+import GHCi+import HscMain+ -- These imports are the reason that TcSplice+ -- is very high up the module hierarchy+import RnSplice( traceSplice, SpliceInfo(..) )+import RdrName+import HscTypes+import Convert+import RnExpr+import RnEnv+import RnTypes+import TcHsSyn+import TcSimplify+import Type+import Kind+import NameSet+import TcMType+import TcHsType+import TcIface+import TyCoRep+import FamInst+import FamInstEnv+import InstEnv+import Inst+import NameEnv+import PrelNames+import TysWiredIn+import OccName+import Hooks+import Var+import Module+import LoadIface+import Class+import TyCon+import CoAxiom+import PatSyn+import ConLike+import DataCon+import TcEvidence( TcEvBinds(..) )+import Id+import IdInfo+import DsExpr+import DsMonad+import GHC.Serialized+import ErrUtils+import Util+import Unique+import VarSet ( isEmptyVarSet, filterVarSet, mkVarSet, elemVarSet )+import Data.List ( find )+import Data.Maybe+import FastString+import BasicTypes hiding( SuccessFlag(..) )+import Maybes( MaybeErr(..) )+import DynFlags+import Panic+import Lexeme++import qualified Language.Haskell.TH as TH+-- THSyntax gives access to internal functions and data types+import qualified Language.Haskell.TH.Syntax as TH++-- Because GHC.Desugar might not be in the base library of the bootstrapping compiler+import GHC.Desugar ( AnnotationWrapper(..) )++import qualified Data.IntSet as IntSet+import Control.Exception+import Data.Binary+import Data.Binary.Get+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as LB+import Data.Dynamic ( fromDynamic, toDyn )+import qualified Data.Map as Map+import Data.Typeable ( typeOf, Typeable, TypeRep, typeRep )+import Data.Data (Data)+import Data.Proxy ( Proxy (..) )+import GHC.Exts ( unsafeCoerce# )++{-+************************************************************************+* *+\subsection{Main interface + stubs for the non-GHCI case+* *+************************************************************************+-}++tcTypedBracket :: HsBracket Name -> ExpRhoType -> TcM (HsExpr TcId)+tcUntypedBracket :: HsBracket Name -> [PendingRnSplice] -> ExpRhoType -> TcM (HsExpr TcId)+tcSpliceExpr :: HsSplice Name -> ExpRhoType -> TcM (HsExpr TcId)+ -- None of these functions add constraints to the LIE++-- runQuasiQuoteExpr :: HsQuasiQuote RdrName -> RnM (LHsExpr RdrName)+-- runQuasiQuotePat :: HsQuasiQuote RdrName -> RnM (LPat RdrName)+-- runQuasiQuoteType :: HsQuasiQuote RdrName -> RnM (LHsType RdrName)+-- runQuasiQuoteDecl :: HsQuasiQuote RdrName -> RnM [LHsDecl RdrName]++runAnnotation :: CoreAnnTarget -> LHsExpr Name -> TcM Annotation+{-+************************************************************************+* *+\subsection{Quoting an expression}+* *+************************************************************************+-}++-- See Note [How brackets and nested splices are handled]+-- tcTypedBracket :: HsBracket Name -> TcRhoType -> TcM (HsExpr TcId)+tcTypedBracket brack@(TExpBr expr) res_ty+ = addErrCtxt (quotationCtxtDoc brack) $+ do { cur_stage <- getStage+ ; ps_ref <- newMutVar []+ ; lie_var <- getConstraintVar -- Any constraints arising from nested splices+ -- should get thrown into the constraint set+ -- from outside the bracket++ -- Typecheck expr to make sure it is valid,+ -- Throw away the typechecked expression but return its type.+ -- We'll typecheck it again when we splice it in somewhere+ ; (_tc_expr, expr_ty) <- setStage (Brack cur_stage (TcPending ps_ref lie_var)) $+ tcInferRhoNC expr+ -- NC for no context; tcBracket does that++ ; meta_ty <- tcTExpTy expr_ty+ ; ps' <- readMutVar ps_ref+ ; texpco <- tcLookupId unsafeTExpCoerceName+ ; tcWrapResultO (Shouldn'tHappenOrigin "TExpBr")+ (unLoc (mkHsApp (nlHsTyApp texpco [expr_ty])+ (noLoc (HsTcBracketOut brack ps'))))+ meta_ty res_ty }+tcTypedBracket other_brack _+ = pprPanic "tcTypedBracket" (ppr other_brack)++-- tcUntypedBracket :: HsBracket Name -> [PendingRnSplice] -> ExpRhoType -> TcM (HsExpr TcId)+tcUntypedBracket brack ps res_ty+ = do { traceTc "tc_bracket untyped" (ppr brack $$ ppr ps)+ ; ps' <- mapM tcPendingSplice ps+ ; meta_ty <- tcBrackTy brack+ ; traceTc "tc_bracket done untyped" (ppr meta_ty)+ ; tcWrapResultO (Shouldn'tHappenOrigin "untyped bracket")+ (HsTcBracketOut brack ps') meta_ty res_ty }++---------------+tcBrackTy :: HsBracket Name -> TcM TcType+tcBrackTy (VarBr _ _) = tcMetaTy nameTyConName -- Result type is Var (not Q-monadic)+tcBrackTy (ExpBr _) = tcMetaTy expQTyConName -- Result type is ExpQ (= Q Exp)+tcBrackTy (TypBr _) = tcMetaTy typeQTyConName -- Result type is Type (= Q Typ)+tcBrackTy (DecBrG _) = tcMetaTy decsQTyConName -- Result type is Q [Dec]+tcBrackTy (PatBr _) = tcMetaTy patQTyConName -- Result type is PatQ (= Q Pat)+tcBrackTy (DecBrL _) = panic "tcBrackTy: Unexpected DecBrL"+tcBrackTy (TExpBr _) = panic "tcUntypedBracket: Unexpected TExpBr"++---------------+tcPendingSplice :: PendingRnSplice -> TcM PendingTcSplice+tcPendingSplice (PendingRnSplice flavour splice_name expr)+ = do { res_ty <- tcMetaTy meta_ty_name+ ; expr' <- tcMonoExpr expr (mkCheckExpType res_ty)+ ; return (PendingTcSplice splice_name expr') }+ where+ meta_ty_name = case flavour of+ UntypedExpSplice -> expQTyConName+ UntypedPatSplice -> patQTyConName+ UntypedTypeSplice -> typeQTyConName+ UntypedDeclSplice -> decsQTyConName++---------------+-- Takes a tau and returns the type Q (TExp tau)+tcTExpTy :: TcType -> TcM TcType+tcTExpTy exp_ty+ = do { unless (isTauTy exp_ty) $ addErr (err_msg exp_ty)+ ; q <- tcLookupTyCon qTyConName+ ; texp <- tcLookupTyCon tExpTyConName+ ; return (mkTyConApp q [mkTyConApp texp [exp_ty]]) }+ where+ err_msg ty+ = vcat [ text "Illegal polytype:" <+> ppr ty+ , text "The type of a Typed Template Haskell expression must" <+>+ text "not have any quantification." ]++quotationCtxtDoc :: HsBracket Name -> SDoc+quotationCtxtDoc br_body+ = hang (text "In the Template Haskell quotation")+ 2 (ppr br_body)+++ -- The whole of the rest of the file is the else-branch (ie stage2 only)++{-+Note [How top-level splices are handled]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Top-level splices (those not inside a [| .. |] quotation bracket) are handled+very straightforwardly:++ 1. tcTopSpliceExpr: typecheck the body e of the splice $(e)++ 2. runMetaT: desugar, compile, run it, and convert result back to+ HsSyn RdrName (of the appropriate flavour, eg HsType RdrName,+ HsExpr RdrName etc)++ 3. treat the result as if that's what you saw in the first place+ e.g for HsType, rename and kind-check+ for HsExpr, rename and type-check++ (The last step is different for decls, because they can *only* be+ top-level: we return the result of step 2.)++Note [How brackets and nested splices are handled]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Nested splices (those inside a [| .. |] quotation bracket),+are treated quite differently.++Remember, there are two forms of bracket+ typed [|| e ||]+ and untyped [| e |]++The life cycle of a typed bracket:+ * Starts as HsBracket++ * When renaming:+ * Set the ThStage to (Brack s RnPendingTyped)+ * Rename the body+ * Result is still a HsBracket++ * When typechecking:+ * Set the ThStage to (Brack s (TcPending ps_var lie_var))+ * Typecheck the body, and throw away the elaborated result+ * Nested splices (which must be typed) are typechecked, and+ the results accumulated in ps_var; their constraints+ accumulate in lie_var+ * Result is a HsTcBracketOut rn_brack pending_splices+ where rn_brack is the incoming renamed bracket++The life cycle of a un-typed bracket:+ * Starts as HsBracket++ * When renaming:+ * Set the ThStage to (Brack s (RnPendingUntyped ps_var))+ * Rename the body+ * Nested splices (which must be untyped) are renamed, and the+ results accumulated in ps_var+ * Result is still (HsRnBracketOut rn_body pending_splices)++ * When typechecking a HsRnBracketOut+ * Typecheck the pending_splices individually+ * Ignore the body of the bracket; just check that the context+ expects a bracket of that type (e.g. a [p| pat |] bracket should+ be in a context needing a (Q Pat)+ * Result is a HsTcBracketOut rn_brack pending_splices+ where rn_brack is the incoming renamed bracket+++In both cases, desugaring happens like this:+ * HsTcBracketOut is desugared by DsMeta.dsBracket. It++ a) Extends the ds_meta environment with the PendingSplices+ attached to the bracket++ b) Converts the quoted (HsExpr Name) to a CoreExpr that, when+ run, will produce a suitable TH expression/type/decl. This+ is why we leave the *renamed* expression attached to the bracket:+ the quoted expression should not be decorated with all the goop+ added by the type checker++ * Each splice carries a unique Name, called a "splice point", thus+ ${n}(e). The name is initialised to an (Unqual "splice") when the+ splice is created; the renamer gives it a unique.++ * When DsMeta (used to desugar the body of the bracket) comes across+ a splice, it looks up the splice's Name, n, in the ds_meta envt,+ to find an (HsExpr Id) that should be substituted for the splice;+ it just desugars it to get a CoreExpr (DsMeta.repSplice).++Example:+ Source: f = [| Just $(g 3) |]+ The [| |] part is a HsBracket++ Typechecked: f = [| Just ${s7}(g 3) |]{s7 = g Int 3}+ The [| |] part is a HsBracketOut, containing *renamed*+ (not typechecked) expression+ The "s7" is the "splice point"; the (g Int 3) part+ is a typechecked expression++ Desugared: f = do { s7 <- g Int 3+ ; return (ConE "Data.Maybe.Just" s7) }+++Note [Template Haskell state diagram]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Here are the ThStages, s, their corresponding level numbers+(the result of (thLevel s)), and their state transitions.+The top level of the program is stage Comp:++ Start here+ |+ V+ ----------- $ ------------ $+ | Comp | ---------> | Splice | -----|+ | 1 | | 0 | <----|+ ----------- ------------+ ^ | ^ |+ $ | | [||] $ | | [||]+ | v | v+ -------------- ----------------+ | Brack Comp | | Brack Splice |+ | 2 | | 1 |+ -------------- ----------------++* Normal top-level declarations start in state Comp+ (which has level 1).+ Annotations start in state Splice, since they are+ treated very like a splice (only without a '$')++* Code compiled in state Splice (and only such code)+ will be *run at compile time*, with the result replacing+ the splice++* The original paper used level -1 instead of 0, etc.++* The original paper did not allow a splice within a+ splice, but there is no reason not to. This is the+ $ transition in the top right.++Note [Template Haskell levels]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Imported things are impLevel (= 0)++* However things at level 0 are not *necessarily* imported.+ eg $( \b -> ... ) here b is bound at level 0++* In GHCi, variables bound by a previous command are treated+ as impLevel, because we have bytecode for them.++* Variables are bound at the "current level"++* The current level starts off at outerLevel (= 1)++* The level is decremented by splicing $(..)+ incremented by brackets [| |]+ incremented by name-quoting 'f++When a variable is used, we compare+ bind: binding level, and+ use: current level at usage site++ Generally+ bind > use Always error (bound later than used)+ [| \x -> $(f x) |]++ bind = use Always OK (bound same stage as used)+ [| \x -> $(f [| x |]) |]++ bind < use Inside brackets, it depends+ Inside splice, OK+ Inside neither, OK++ For (bind < use) inside brackets, there are three cases:+ - Imported things OK f = [| map |]+ - Top-level things OK g = [| f |]+ - Non-top-level Only if there is a liftable instance+ h = \(x:Int) -> [| x |]++ To track top-level-ness we use the ThBindEnv in TcLclEnv++ For example:+ f = ...+ g1 = $(map ...) is OK+ g2 = $(f ...) is not OK; because we havn't compiled f yet++-}++{-+************************************************************************+* *+\subsection{Splicing an expression}+* *+************************************************************************+-}++tcSpliceExpr splice@(HsTypedSplice _ name expr) res_ty+ = addErrCtxt (spliceCtxtDoc splice) $+ setSrcSpan (getLoc expr) $ do+ { stage <- getStage+ ; case stage of+ Splice {} -> tcTopSplice expr res_ty+ Brack pop_stage pend -> tcNestedSplice pop_stage pend name expr res_ty+ RunSplice _ ->+ -- See Note [RunSplice ThLevel] in "TcRnTypes".+ pprPanic ("tcSpliceExpr: attempted to typecheck a splice when " +++ "running another splice") (ppr splice)+ Comp -> tcTopSplice expr res_ty+ }+tcSpliceExpr splice _+ = pprPanic "tcSpliceExpr" (ppr splice)++{- Note [Collecting modFinalizers in typed splices]+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++'qAddModFinalizer' of the @Quasi TcM@ instance adds finalizers in the local+environment (see Note [Delaying modFinalizers in untyped splices] in+"RnSplice"). Thus after executing the splice, we move the finalizers to the+finalizer list in the global environment and set them to use the current local+environment (with 'addModFinalizersWithLclEnv').++-}++tcNestedSplice :: ThStage -> PendingStuff -> Name+ -> LHsExpr Name -> ExpRhoType -> TcM (HsExpr Id)+ -- See Note [How brackets and nested splices are handled]+ -- A splice inside brackets+tcNestedSplice pop_stage (TcPending ps_var lie_var) splice_name expr res_ty+ = do { res_ty <- expTypeToType res_ty+ ; meta_exp_ty <- tcTExpTy res_ty+ ; expr' <- setStage pop_stage $+ setConstraintVar lie_var $+ tcMonoExpr expr (mkCheckExpType meta_exp_ty)+ ; untypeq <- tcLookupId unTypeQName+ ; let expr'' = mkHsApp (nlHsTyApp untypeq [res_ty]) expr'+ ; ps <- readMutVar ps_var+ ; writeMutVar ps_var (PendingTcSplice splice_name expr'' : ps)++ -- The returned expression is ignored; it's in the pending splices+ ; return (panic "tcSpliceExpr") }++tcNestedSplice _ _ splice_name _ _+ = pprPanic "tcNestedSplice: rename stage found" (ppr splice_name)++tcTopSplice :: LHsExpr Name -> ExpRhoType -> TcM (HsExpr Id)+tcTopSplice expr res_ty+ = do { -- Typecheck the expression,+ -- making sure it has type Q (T res_ty)+ res_ty <- expTypeToType res_ty+ ; meta_exp_ty <- tcTExpTy res_ty+ ; zonked_q_expr <- tcTopSpliceExpr Typed $+ tcMonoExpr expr (mkCheckExpType meta_exp_ty)++ -- See Note [Collecting modFinalizers in typed splices].+ ; modfinalizers_ref <- newTcRef []+ -- Run the expression+ ; expr2 <- setStage (RunSplice modfinalizers_ref) $+ runMetaE zonked_q_expr+ ; mod_finalizers <- readTcRef modfinalizers_ref+ ; addModFinalizersWithLclEnv $ ThModFinalizers mod_finalizers+ ; traceSplice (SpliceInfo { spliceDescription = "expression"+ , spliceIsDecl = False+ , spliceSource = Just expr+ , spliceGenerated = ppr expr2 })++ -- Rename and typecheck the spliced-in expression,+ -- making sure it has type res_ty+ -- These steps should never fail; this is a *typed* splice+ ; addErrCtxt (spliceResultDoc expr) $ do+ { (exp3, _fvs) <- rnLExpr expr2+ ; exp4 <- tcMonoExpr exp3 (mkCheckExpType res_ty)+ ; return (unLoc exp4) } }++{-+************************************************************************+* *+\subsection{Error messages}+* *+************************************************************************+-}++spliceCtxtDoc :: HsSplice Name -> SDoc+spliceCtxtDoc splice+ = hang (text "In the Template Haskell splice")+ 2 (pprSplice splice)++spliceResultDoc :: LHsExpr Name -> SDoc+spliceResultDoc expr+ = sep [ text "In the result of the splice:"+ , nest 2 (char '$' <> ppr expr)+ , text "To see what the splice expanded to, use -ddump-splices"]++-------------------+tcTopSpliceExpr :: SpliceType -> TcM (LHsExpr Id) -> TcM (LHsExpr Id)+-- Note [How top-level splices are handled]+-- Type check an expression that is the body of a top-level splice+-- (the caller will compile and run it)+-- Note that set the level to Splice, regardless of the original level,+-- before typechecking the expression. For example:+-- f x = $( ...$(g 3) ... )+-- The recursive call to tcPolyExpr will simply expand the+-- inner escape before dealing with the outer one++tcTopSpliceExpr isTypedSplice tc_action+ = checkNoErrs $ -- checkNoErrs: must not try to run the thing+ -- if the type checker fails!+ unsetGOptM Opt_DeferTypeErrors $+ -- Don't defer type errors. Not only are we+ -- going to run this code, but we do an unsafe+ -- coerce, so we get a seg-fault if, say we+ -- splice a type into a place where an expression+ -- is expected (Trac #7276)+ setStage (Splice isTypedSplice) $+ do { -- Typecheck the expression+ (expr', wanted) <- captureConstraints tc_action+ ; const_binds <- simplifyTop wanted++ -- Zonk it and tie the knot of dictionary bindings+ ; zonkTopLExpr (mkHsDictLet (EvBinds const_binds) expr') }++{-+************************************************************************+* *+ Annotations+* *+************************************************************************+-}++runAnnotation target expr = do+ -- Find the classes we want instances for in order to call toAnnotationWrapper+ loc <- getSrcSpanM+ data_class <- tcLookupClass dataClassName+ to_annotation_wrapper_id <- tcLookupId toAnnotationWrapperName++ -- Check the instances we require live in another module (we want to execute it..)+ -- and check identifiers live in other modules using TH stage checks. tcSimplifyStagedExpr+ -- also resolves the LIE constraints to detect e.g. instance ambiguity+ zonked_wrapped_expr' <- tcTopSpliceExpr Untyped $+ do { (expr', expr_ty) <- tcInferRhoNC expr+ -- We manually wrap the typechecked expression in a call to toAnnotationWrapper+ -- By instantiating the call >here< it gets registered in the+ -- LIE consulted by tcTopSpliceExpr+ -- and hence ensures the appropriate dictionary is bound by const_binds+ ; wrapper <- instCall AnnOrigin [expr_ty] [mkClassPred data_class [expr_ty]]+ ; let specialised_to_annotation_wrapper_expr+ = L loc (HsWrap wrapper+ (HsVar (L loc to_annotation_wrapper_id)))+ ; return (L loc (HsApp specialised_to_annotation_wrapper_expr expr')) }++ -- Run the appropriately wrapped expression to get the value of+ -- the annotation and its dictionaries. The return value is of+ -- type AnnotationWrapper by construction, so this conversion is+ -- safe+ serialized <- runMetaAW zonked_wrapped_expr'+ return Annotation {+ ann_target = target,+ ann_value = serialized+ }++convertAnnotationWrapper :: ForeignHValue -> TcM (Either MsgDoc Serialized)+convertAnnotationWrapper fhv = do+ dflags <- getDynFlags+ if gopt Opt_ExternalInterpreter dflags+ then do+ Right <$> runTH THAnnWrapper fhv+ else do+ annotation_wrapper <- liftIO $ wormhole dflags fhv+ return $ Right $+ case unsafeCoerce# annotation_wrapper of+ AnnotationWrapper value | let serialized = toSerialized serializeWithData value ->+ -- Got the value and dictionaries: build the serialized value and+ -- call it a day. We ensure that we seq the entire serialized value+ -- in order that any errors in the user-written code for the+ -- annotation are exposed at this point. This is also why we are+ -- doing all this stuff inside the context of runMeta: it has the+ -- facilities to deal with user error in a meta-level expression+ seqSerialized serialized `seq` serialized++-- | Force the contents of the Serialized value so weknow it doesn't contain any bottoms+seqSerialized :: Serialized -> ()+seqSerialized (Serialized the_type bytes) = the_type `seq` bytes `seqList` ()+++{-+************************************************************************+* *+\subsection{Running an expression}+* *+************************************************************************+-}++runQuasi :: TH.Q a -> TcM a+runQuasi act = TH.runQ act++runRemoteModFinalizers :: ThModFinalizers -> TcM ()+runRemoteModFinalizers (ThModFinalizers finRefs) = do+ dflags <- getDynFlags+ let withForeignRefs [] f = f []+ withForeignRefs (x : xs) f = withForeignRef x $ \r ->+ withForeignRefs xs $ \rs -> f (r : rs)+ if gopt Opt_ExternalInterpreter dflags then do+ hsc_env <- env_top <$> getEnv+ withIServ hsc_env $ \i -> do+ tcg <- getGblEnv+ th_state <- readTcRef (tcg_th_remote_state tcg)+ case th_state of+ Nothing -> return () -- TH was not started, nothing to do+ Just fhv -> do+ liftIO $ withForeignRef fhv $ \st ->+ withForeignRefs finRefs $ \qrefs ->+ writeIServ i (putMessage (RunModFinalizers st qrefs))+ () <- runRemoteTH i []+ readQResult i+ else do+ qs <- liftIO (withForeignRefs finRefs $ mapM localRef)+ runQuasi $ sequence_ qs++runQResult+ :: (a -> String)+ -> (SrcSpan -> a -> b)+ -> (ForeignHValue -> TcM a)+ -> SrcSpan+ -> ForeignHValue {- TH.Q a -}+ -> TcM b+runQResult show_th f runQ expr_span hval+ = do { th_result <- runQ hval+ ; traceTc "Got TH result:" (text (show_th th_result))+ ; return (f expr_span th_result) }+++-----------------+runMeta :: (MetaHook TcM -> LHsExpr Id -> TcM hs_syn)+ -> LHsExpr Id+ -> TcM hs_syn+runMeta unwrap e+ = do { h <- getHooked runMetaHook defaultRunMeta+ ; unwrap h e }++defaultRunMeta :: MetaHook TcM+defaultRunMeta (MetaE r)+ = fmap r . runMeta' True ppr (runQResult TH.pprint convertToHsExpr runTHExp)+defaultRunMeta (MetaP r)+ = fmap r . runMeta' True ppr (runQResult TH.pprint convertToPat runTHPat)+defaultRunMeta (MetaT r)+ = fmap r . runMeta' True ppr (runQResult TH.pprint convertToHsType runTHType)+defaultRunMeta (MetaD r)+ = fmap r . runMeta' True ppr (runQResult TH.pprint convertToHsDecls runTHDec)+defaultRunMeta (MetaAW r)+ = fmap r . runMeta' False (const empty) (const convertAnnotationWrapper)+ -- We turn off showing the code in meta-level exceptions because doing so exposes+ -- the toAnnotationWrapper function that we slap around the user's code++----------------+runMetaAW :: LHsExpr Id -- Of type AnnotationWrapper+ -> TcM Serialized+runMetaAW = runMeta metaRequestAW++runMetaE :: LHsExpr Id -- Of type (Q Exp)+ -> TcM (LHsExpr RdrName)+runMetaE = runMeta metaRequestE++runMetaP :: LHsExpr Id -- Of type (Q Pat)+ -> TcM (LPat RdrName)+runMetaP = runMeta metaRequestP++runMetaT :: LHsExpr Id -- Of type (Q Type)+ -> TcM (LHsType RdrName)+runMetaT = runMeta metaRequestT++runMetaD :: LHsExpr Id -- Of type Q [Dec]+ -> TcM [LHsDecl RdrName]+runMetaD = runMeta metaRequestD++---------------+runMeta' :: Bool -- Whether code should be printed in the exception message+ -> (hs_syn -> SDoc) -- how to print the code+ -> (SrcSpan -> ForeignHValue -> TcM (Either MsgDoc hs_syn)) -- How to run x+ -> LHsExpr Id -- Of type x; typically x = Q TH.Exp, or something like that+ -> TcM hs_syn -- Of type t+runMeta' show_code ppr_hs run_and_convert expr+ = do { traceTc "About to run" (ppr expr)+ ; recordThSpliceUse -- seems to be the best place to do this,+ -- we catch all kinds of splices and annotations.++ -- Check that we've had no errors of any sort so far.+ -- For example, if we found an error in an earlier defn f, but+ -- recovered giving it type f :: forall a.a, it'd be very dodgy+ -- to carry ont. Mind you, the staging restrictions mean we won't+ -- actually run f, but it still seems wrong. And, more concretely,+ -- see Trac #5358 for an example that fell over when trying to+ -- reify a function with a "?" kind in it. (These don't occur+ -- in type-correct programs.+ ; failIfErrsM++ -- Desugar+ ; ds_expr <- initDsTc (dsLExpr expr)+ -- Compile and link it; might fail if linking fails+ ; hsc_env <- getTopEnv+ ; src_span <- getSrcSpanM+ ; traceTc "About to run (desugared)" (ppr ds_expr)+ ; either_hval <- tryM $ liftIO $+ HscMain.hscCompileCoreExpr hsc_env src_span ds_expr+ ; case either_hval of {+ Left exn -> fail_with_exn "compile and link" exn ;+ Right hval -> do++ { -- Coerce it to Q t, and run it++ -- Running might fail if it throws an exception of any kind (hence tryAllM)+ -- including, say, a pattern-match exception in the code we are running+ --+ -- We also do the TH -> HS syntax conversion inside the same+ -- exception-cacthing thing so that if there are any lurking+ -- exceptions in the data structure returned by hval, we'll+ -- encounter them inside the try+ --+ -- See Note [Exceptions in TH]+ let expr_span = getLoc expr+ ; either_tval <- tryAllM $+ setSrcSpan expr_span $ -- Set the span so that qLocation can+ -- see where this splice is+ do { mb_result <- run_and_convert expr_span hval+ ; case mb_result of+ Left err -> failWithTc err+ Right result -> do { traceTc "Got HsSyn result:" (ppr_hs result)+ ; return $! result } }++ ; case either_tval of+ Right v -> return v+ Left se -> case fromException se of+ Just IOEnvFailure -> failM -- Error already in Tc monad+ _ -> fail_with_exn "run" se -- Exception+ }}}+ where+ -- see Note [Concealed TH exceptions]+ fail_with_exn :: Exception e => String -> e -> TcM a+ fail_with_exn phase exn = do+ exn_msg <- liftIO $ Panic.safeShowException exn+ let msg = vcat [text "Exception when trying to" <+> text phase <+> text "compile-time code:",+ nest 2 (text exn_msg),+ if show_code then text "Code:" <+> ppr expr else empty]+ failWithTc msg++{-+Note [Exceptions in TH]+~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have something like this+ $( f 4 )+where+ f :: Int -> Q [Dec]+ f n | n>3 = fail "Too many declarations"+ | otherwise = ...++The 'fail' is a user-generated failure, and should be displayed as a+perfectly ordinary compiler error message, not a panic or anything+like that. Here's how it's processed:++ * 'fail' is the monad fail. The monad instance for Q in TH.Syntax+ effectively transforms (fail s) to+ qReport True s >> fail+ where 'qReport' comes from the Quasi class and fail from its monad+ superclass.++ * The TcM monad is an instance of Quasi (see TcSplice), and it implements+ (qReport True s) by using addErr to add an error message to the bag of errors.+ The 'fail' in TcM raises an IOEnvFailure exception++ * 'qReport' forces the message to ensure any exception hidden in unevaluated+ thunk doesn't get into the bag of errors. Otherwise the following splice+ will triger panic (Trac #8987):+ $(fail undefined)+ See also Note [Concealed TH exceptions]++ * So, when running a splice, we catch all exceptions; then for+ - an IOEnvFailure exception, we assume the error is already+ in the error-bag (above)+ - other errors, we add an error to the bag+ and then fail++Note [Concealed TH exceptions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When displaying the error message contained in an exception originated from TH+code, we need to make sure that the error message itself does not contain an+exception. For example, when executing the following splice:++ $( error ("foo " ++ error "bar") )++the message for the outer exception is a thunk which will throw the inner+exception when evaluated.++For this reason, we display the message of a TH exception using the+'safeShowException' function, which recursively catches any exception thrown+when showing an error message.+++To call runQ in the Tc monad, we need to make TcM an instance of Quasi:+-}++instance TH.Quasi TcM where+ qNewName s = do { u <- newUnique+ ; let i = getKey u+ ; return (TH.mkNameU s i) }++ -- 'msg' is forced to ensure exceptions don't escape,+ -- see Note [Exceptions in TH]+ qReport True msg = seqList msg $ addErr (text msg)+ qReport False msg = seqList msg $ addWarn NoReason (text msg)++ qLocation = do { m <- getModule+ ; l <- getSrcSpanM+ ; r <- case l of+ UnhelpfulSpan _ -> pprPanic "qLocation: Unhelpful location"+ (ppr l)+ RealSrcSpan s -> return s+ ; return (TH.Loc { TH.loc_filename = unpackFS (srcSpanFile r)+ , TH.loc_module = moduleNameString (moduleName m)+ , TH.loc_package = unitIdString (moduleUnitId m)+ , TH.loc_start = (srcSpanStartLine r, srcSpanStartCol r)+ , TH.loc_end = (srcSpanEndLine r, srcSpanEndCol r) }) }++ qLookupName = lookupName+ qReify = reify+ qReifyFixity nm = lookupThName nm >>= reifyFixity+ qReifyInstances = reifyInstances+ qReifyRoles = reifyRoles+ qReifyAnnotations = reifyAnnotations+ qReifyModule = reifyModule+ qReifyConStrictness nm = do { nm' <- lookupThName nm+ ; dc <- tcLookupDataCon nm'+ ; let bangs = dataConImplBangs dc+ ; return (map reifyDecidedStrictness bangs) }++ -- For qRecover, discard error messages if+ -- the recovery action is chosen. Otherwise+ -- we'll only fail higher up.+ qRecover recover main = tryTcDiscardingErrs recover main+ qRunIO io = liftIO io++ qAddDependentFile fp = do+ ref <- fmap tcg_dependent_files getGblEnv+ dep_files <- readTcRef ref+ writeTcRef ref (fp:dep_files)++ qAddTopDecls thds = do+ l <- getSrcSpanM+ let either_hval = convertToHsDecls l thds+ ds <- case either_hval of+ Left exn -> pprPanic "qAddTopDecls: can't convert top-level declarations" exn+ Right ds -> return ds+ mapM_ (checkTopDecl . unLoc) ds+ th_topdecls_var <- fmap tcg_th_topdecls getGblEnv+ updTcRef th_topdecls_var (\topds -> ds ++ topds)+ where+ checkTopDecl :: HsDecl RdrName -> TcM ()+ checkTopDecl (ValD binds)+ = mapM_ bindName (collectHsBindBinders binds)+ checkTopDecl (SigD _)+ = return ()+ checkTopDecl (AnnD _)+ = return ()+ checkTopDecl (ForD (ForeignImport { fd_name = L _ name }))+ = bindName name+ checkTopDecl _+ = addErr $ text "Only function, value, annotation, and foreign import declarations may be added with addTopDecl"++ bindName :: RdrName -> TcM ()+ bindName (Exact n)+ = do { th_topnames_var <- fmap tcg_th_topnames getGblEnv+ ; updTcRef th_topnames_var (\ns -> extendNameSet ns n)+ }++ bindName name =+ addErr $+ hang (text "The binder" <+> quotes (ppr name) <+> ptext (sLit "is not a NameU."))+ 2 (text "Probable cause: you used mkName instead of newName to generate a binding.")++ qAddForeignFile lang str = do+ var <- fmap tcg_th_foreign_files getGblEnv+ updTcRef var ((lang, str) :)++ qAddModFinalizer fin = do+ r <- liftIO $ mkRemoteRef fin+ fref <- liftIO $ mkForeignRef r (freeRemoteRef r)+ addModFinalizerRef fref++ qGetQ :: forall a. Typeable a => TcM (Maybe a)+ qGetQ = do+ th_state_var <- fmap tcg_th_state getGblEnv+ th_state <- readTcRef th_state_var+ -- See #10596 for why we use a scoped type variable here.+ return (Map.lookup (typeRep (Proxy :: Proxy a)) th_state >>= fromDynamic)++ qPutQ x = do+ th_state_var <- fmap tcg_th_state getGblEnv+ updTcRef th_state_var (\m -> Map.insert (typeOf x) (toDyn x) m)++ qIsExtEnabled = xoptM++ qExtsEnabled = do+ dflags <- hsc_dflags <$> getTopEnv+ return $ map toEnum $ IntSet.elems $ extensionFlags dflags++-- | Adds a mod finalizer reference to the local environment.+addModFinalizerRef :: ForeignRef (TH.Q ()) -> TcM ()+addModFinalizerRef finRef = do+ th_stage <- getStage+ case th_stage of+ RunSplice th_modfinalizers_var -> updTcRef th_modfinalizers_var (finRef :)+ -- This case happens only if a splice is executed and the caller does+ -- not set the 'ThStage' to 'RunSplice' to collect finalizers.+ -- See Note [Delaying modFinalizers in untyped splices] in RnSplice.+ _ ->+ pprPanic "addModFinalizer was called when no finalizers were collected"+ (ppr th_stage)++-- | Releases the external interpreter state.+finishTH :: TcM ()+finishTH = do+ dflags <- getDynFlags+ when (gopt Opt_ExternalInterpreter dflags) $ do+ tcg <- getGblEnv+ writeTcRef (tcg_th_remote_state tcg) Nothing++runTHExp :: ForeignHValue -> TcM TH.Exp+runTHExp = runTH THExp++runTHPat :: ForeignHValue -> TcM TH.Pat+runTHPat = runTH THPat++runTHType :: ForeignHValue -> TcM TH.Type+runTHType = runTH THType++runTHDec :: ForeignHValue -> TcM [TH.Dec]+runTHDec = runTH THDec++runTH :: Binary a => THResultType -> ForeignHValue -> TcM a+runTH ty fhv = do+ hsc_env <- env_top <$> getEnv+ dflags <- getDynFlags+ if not (gopt Opt_ExternalInterpreter dflags)+ then do+ -- Run it in the local TcM+ hv <- liftIO $ wormhole dflags fhv+ r <- runQuasi (unsafeCoerce# hv :: TH.Q a)+ return r+ else+ -- Run it on the server. For an overview of how TH works with+ -- Remote GHCi, see Note [Remote Template Haskell] in+ -- libraries/ghci/GHCi/TH.hs.+ withIServ hsc_env $ \i -> do+ rstate <- getTHState i+ loc <- TH.qLocation+ liftIO $+ withForeignRef rstate $ \state_hv ->+ withForeignRef fhv $ \q_hv ->+ writeIServ i (putMessage (RunTH state_hv q_hv ty (Just loc)))+ runRemoteTH i []+ bs <- readQResult i+ return $! runGet get (LB.fromStrict bs)+++-- | communicate with a remotely-running TH computation until it finishes.+-- See Note [Remote Template Haskell] in libraries/ghci/GHCi/TH.hs.+runRemoteTH+ :: IServ+ -> [Messages] -- saved from nested calls to qRecover+ -> TcM ()+runRemoteTH iserv recovers = do+ THMsg msg <- liftIO $ readIServ iserv getTHMessage+ case msg of+ RunTHDone -> return ()+ StartRecover -> do -- Note [TH recover with -fexternal-interpreter]+ v <- getErrsVar+ msgs <- readTcRef v+ writeTcRef v emptyMessages+ runRemoteTH iserv (msgs : recovers)+ EndRecover caught_error -> do+ v <- getErrsVar+ let (prev_msgs, rest) = case recovers of+ [] -> panic "EndRecover"+ a : b -> (a,b)+ if caught_error+ then writeTcRef v prev_msgs+ else updTcRef v (unionMessages prev_msgs)+ runRemoteTH iserv rest+ _other -> do+ r <- handleTHMessage msg+ liftIO $ writeIServ iserv (put r)+ runRemoteTH iserv recovers++-- | Read a value of type QResult from the iserv+readQResult :: Binary a => IServ -> TcM a+readQResult i = do+ qr <- liftIO $ readIServ i get+ case qr of+ QDone a -> return a+ QException str -> liftIO $ throwIO (ErrorCall str)+ QFail str -> fail str++{- Note [TH recover with -fexternal-interpreter]++Recover is slightly tricky to implement.++The meaning of "recover a b" is+ - Do a+ - If it finished successfully, then keep the messages it generated+ - If it failed, discard any messages it generated, and do b++The messages are managed by GHC in the TcM monad, whereas the+exception-handling is done in the ghc-iserv process, so we have to+coordinate between the two.++On the server:+ - emit a StartRecover message+ - run "a" inside a catch+ - if it finishes, emit EndRecover False+ - if it fails, emit EndRecover True, then run "b"++Back in GHC, when we receive:++ StartRecover+ save the current messages and start with an empty set.+ EndRecover caught_error+ Restore the previous messages,+ and merge in the new messages if caught_error is false.+-}++-- | Retrieve (or create, if it hasn't been created already), the+-- remote TH state. The TH state is a remote reference to an IORef+-- QState living on the server, and we have to pass this to each RunTH+-- call we make.+--+-- The TH state is stored in tcg_th_remote_state in the TcGblEnv.+--+getTHState :: IServ -> TcM (ForeignRef (IORef QState))+getTHState i = do+ tcg <- getGblEnv+ th_state <- readTcRef (tcg_th_remote_state tcg)+ case th_state of+ Just rhv -> return rhv+ Nothing -> do+ hsc_env <- env_top <$> getEnv+ fhv <- liftIO $ mkFinalizedHValue hsc_env =<< iservCall i StartTH+ writeTcRef (tcg_th_remote_state tcg) (Just fhv)+ return fhv++wrapTHResult :: TcM a -> TcM (THResult a)+wrapTHResult tcm = do+ e <- tryM tcm -- only catch 'fail', treat everything else as catastrophic+ case e of+ Left e -> return (THException (show e))+ Right a -> return (THComplete a)++handleTHMessage :: THMessage a -> TcM a+handleTHMessage msg = case msg of+ NewName a -> wrapTHResult $ TH.qNewName a+ Report b str -> wrapTHResult $ TH.qReport b str+ LookupName b str -> wrapTHResult $ TH.qLookupName b str+ Reify n -> wrapTHResult $ TH.qReify n+ ReifyFixity n -> wrapTHResult $ TH.qReifyFixity n+ ReifyInstances n ts -> wrapTHResult $ TH.qReifyInstances n ts+ ReifyRoles n -> wrapTHResult $ TH.qReifyRoles n+ ReifyAnnotations lookup tyrep ->+ wrapTHResult $ (map B.pack <$> getAnnotationsByTypeRep lookup tyrep)+ ReifyModule m -> wrapTHResult $ TH.qReifyModule m+ ReifyConStrictness nm -> wrapTHResult $ TH.qReifyConStrictness nm+ AddDependentFile f -> wrapTHResult $ TH.qAddDependentFile f+ AddModFinalizer r -> do+ hsc_env <- env_top <$> getEnv+ wrapTHResult $ liftIO (mkFinalizedHValue hsc_env r) >>= addModFinalizerRef+ AddTopDecls decs -> wrapTHResult $ TH.qAddTopDecls decs+ AddForeignFile lang str -> wrapTHResult $ TH.qAddForeignFile lang str+ IsExtEnabled ext -> wrapTHResult $ TH.qIsExtEnabled ext+ ExtsEnabled -> wrapTHResult $ TH.qExtsEnabled+ _ -> panic ("handleTHMessage: unexpected message " ++ show msg)++getAnnotationsByTypeRep :: TH.AnnLookup -> TypeRep -> TcM [[Word8]]+getAnnotationsByTypeRep th_name tyrep+ = do { name <- lookupThAnnLookup th_name+ ; topEnv <- getTopEnv+ ; epsHptAnns <- liftIO $ prepareAnnotations topEnv Nothing+ ; tcg <- getGblEnv+ ; let selectedEpsHptAnns = findAnnsByTypeRep epsHptAnns name tyrep+ ; let selectedTcgAnns = findAnnsByTypeRep (tcg_ann_env tcg) name tyrep+ ; return (selectedEpsHptAnns ++ selectedTcgAnns) }++{-+************************************************************************+* *+ Instance Testing+* *+************************************************************************+-}++reifyInstances :: TH.Name -> [TH.Type] -> TcM [TH.Dec]+reifyInstances th_nm th_tys+ = addErrCtxt (text "In the argument of reifyInstances:"+ <+> ppr_th th_nm <+> sep (map ppr_th th_tys)) $+ do { loc <- getSrcSpanM+ ; rdr_ty <- cvt loc (mkThAppTs (TH.ConT th_nm) th_tys)+ -- #9262 says to bring vars into scope, like in HsForAllTy case+ -- of rnHsTyKi+ ; free_vars <- extractHsTyRdrTyVars rdr_ty+ ; let tv_rdrs = freeKiTyVarsAllVars free_vars+ -- Rename to HsType Name+ ; ((tv_names, rn_ty), _fvs)+ <- bindLRdrNames tv_rdrs $ \ tv_names ->+ do { (rn_ty, fvs) <- rnLHsType doc rdr_ty+ ; return ((tv_names, rn_ty), fvs) }+ ; (_tvs, ty)+ <- solveEqualities $+ tcImplicitTKBndrsType tv_names $+ fst <$> tcLHsType rn_ty+ ; ty <- zonkTcTypeToType emptyZonkEnv ty+ -- Substitute out the meta type variables+ -- In particular, the type might have kind+ -- variables inside it (Trac #7477)++ ; traceTc "reifyInstances" (ppr ty $$ ppr (typeKind ty))+ ; case splitTyConApp_maybe ty of -- This expands any type synonyms+ Just (tc, tys) -- See Trac #7910+ | Just cls <- tyConClass_maybe tc+ -> do { inst_envs <- tcGetInstEnvs+ ; let (matches, unifies, _) = lookupInstEnv False inst_envs cls tys+ ; traceTc "reifyInstances1" (ppr matches)+ ; reifyClassInstances cls (map fst matches ++ unifies) }+ | isOpenFamilyTyCon tc+ -> do { inst_envs <- tcGetFamInstEnvs+ ; let matches = lookupFamInstEnv inst_envs tc tys+ ; traceTc "reifyInstances2" (ppr matches)+ ; reifyFamilyInstances tc (map fim_instance matches) }+ _ -> bale_out (hang (text "reifyInstances:" <+> quotes (ppr ty))+ 2 (text "is not a class constraint or type family application")) }+ where+ doc = ClassInstanceCtx+ bale_out msg = failWithTc msg++ cvt :: SrcSpan -> TH.Type -> TcM (LHsType RdrName)+ cvt loc th_ty = case convertToHsType loc th_ty of+ Left msg -> failWithTc msg+ Right ty -> return ty++{-+************************************************************************+* *+ Reification+* *+************************************************************************+-}++lookupName :: Bool -- True <=> type namespace+ -- False <=> value namespace+ -> String -> TcM (Maybe TH.Name)+lookupName is_type_name s+ = do { lcl_env <- getLocalRdrEnv+ ; case lookupLocalRdrEnv lcl_env rdr_name of+ Just n -> return (Just (reifyName n))+ Nothing -> do { mb_nm <- lookupGlobalOccRn_maybe rdr_name+ ; return (fmap reifyName mb_nm) } }+ where+ th_name = TH.mkName s -- Parses M.x into a base of 'x' and a module of 'M'++ occ_fs :: FastString+ occ_fs = mkFastString (TH.nameBase th_name)++ occ :: OccName+ occ | is_type_name+ = if isLexVarSym occ_fs || isLexCon occ_fs+ then mkTcOccFS occ_fs+ else mkTyVarOccFS occ_fs+ | otherwise+ = if isLexCon occ_fs then mkDataOccFS occ_fs+ else mkVarOccFS occ_fs++ rdr_name = case TH.nameModule th_name of+ Nothing -> mkRdrUnqual occ+ Just mod -> mkRdrQual (mkModuleName mod) occ++getThing :: TH.Name -> TcM TcTyThing+getThing th_name+ = do { name <- lookupThName th_name+ ; traceIf (text "reify" <+> text (show th_name) <+> brackets (ppr_ns th_name) <+> ppr name)+ ; tcLookupTh name }+ -- ToDo: this tcLookup could fail, which would give a+ -- rather unhelpful error message+ where+ ppr_ns (TH.Name _ (TH.NameG TH.DataName _pkg _mod)) = text "data"+ ppr_ns (TH.Name _ (TH.NameG TH.TcClsName _pkg _mod)) = text "tc"+ ppr_ns (TH.Name _ (TH.NameG TH.VarName _pkg _mod)) = text "var"+ ppr_ns _ = panic "reify/ppr_ns"++reify :: TH.Name -> TcM TH.Info+reify th_name+ = do { traceTc "reify 1" (text (TH.showName th_name))+ ; thing <- getThing th_name+ ; traceTc "reify 2" (ppr thing)+ ; reifyThing thing }++lookupThName :: TH.Name -> TcM Name+lookupThName th_name = do+ mb_name <- lookupThName_maybe th_name+ case mb_name of+ Nothing -> failWithTc (notInScope th_name)+ Just name -> return name++lookupThName_maybe :: TH.Name -> TcM (Maybe Name)+lookupThName_maybe th_name+ = do { names <- mapMaybeM lookup (thRdrNameGuesses th_name)+ -- Pick the first that works+ -- E.g. reify (mkName "A") will pick the class A in preference to the data constructor A+ ; return (listToMaybe names) }+ where+ lookup rdr_name+ = do { -- Repeat much of lookupOccRn, because we want+ -- to report errors in a TH-relevant way+ ; rdr_env <- getLocalRdrEnv+ ; case lookupLocalRdrEnv rdr_env rdr_name of+ Just name -> return (Just name)+ Nothing -> lookupGlobalOccRn_maybe rdr_name }++tcLookupTh :: Name -> TcM TcTyThing+-- This is a specialised version of TcEnv.tcLookup; specialised mainly in that+-- it gives a reify-related error message on failure, whereas in the normal+-- tcLookup, failure is a bug.+tcLookupTh name+ = do { (gbl_env, lcl_env) <- getEnvs+ ; case lookupNameEnv (tcl_env lcl_env) name of {+ Just thing -> return thing;+ Nothing ->++ case lookupNameEnv (tcg_type_env gbl_env) name of {+ Just thing -> return (AGlobal thing);+ Nothing ->++ -- EZY: I don't think this choice matters, no TH in signatures!+ if nameIsLocalOrFrom (tcg_semantic_mod gbl_env) name+ then -- It's defined in this module+ failWithTc (notInEnv name)++ else+ do { mb_thing <- tcLookupImported_maybe name+ ; case mb_thing of+ Succeeded thing -> return (AGlobal thing)+ Failed msg -> failWithTc msg+ }}}}++notInScope :: TH.Name -> SDoc+notInScope th_name = quotes (text (TH.pprint th_name)) <+>+ text "is not in scope at a reify"+ -- Ugh! Rather an indirect way to display the name++notInEnv :: Name -> SDoc+notInEnv name = quotes (ppr name) <+>+ text "is not in the type environment at a reify"++------------------------------+reifyRoles :: TH.Name -> TcM [TH.Role]+reifyRoles th_name+ = do { thing <- getThing th_name+ ; case thing of+ AGlobal (ATyCon tc) -> return (map reify_role (tyConRoles tc))+ _ -> failWithTc (text "No roles associated with" <+> (ppr thing))+ }+ where+ reify_role Nominal = TH.NominalR+ reify_role Representational = TH.RepresentationalR+ reify_role Phantom = TH.PhantomR++------------------------------+reifyThing :: TcTyThing -> TcM TH.Info+-- The only reason this is monadic is for error reporting,+-- which in turn is mainly for the case when TH can't express+-- some random GHC extension++reifyThing (AGlobal (AnId id))+ = do { ty <- reifyType (idType id)+ ; let v = reifyName id+ ; case idDetails id of+ ClassOpId cls -> return (TH.ClassOpI v ty (reifyName cls))+ RecSelId{sel_tycon=RecSelData tc}+ -> return (TH.VarI (reifySelector id tc) ty Nothing)+ _ -> return (TH.VarI v ty Nothing)+ }++reifyThing (AGlobal (ATyCon tc)) = reifyTyCon tc+reifyThing (AGlobal (AConLike (RealDataCon dc)))+ = do { let name = dataConName dc+ ; ty <- reifyType (idType (dataConWrapId dc))+ ; return (TH.DataConI (reifyName name) ty+ (reifyName (dataConOrigTyCon dc)))+ }++reifyThing (AGlobal (AConLike (PatSynCon ps)))+ = do { let name = reifyName ps+ ; ty <- reifyPatSynType (patSynSig ps)+ ; return (TH.PatSynI name ty) }++reifyThing (ATcId {tct_id = id})+ = do { ty1 <- zonkTcType (idType id) -- Make use of all the info we have, even+ -- though it may be incomplete+ ; ty2 <- reifyType ty1+ ; return (TH.VarI (reifyName id) ty2 Nothing) }++reifyThing (ATyVar tv tv1)+ = do { ty1 <- zonkTcTyVar tv1+ ; ty2 <- reifyType ty1+ ; return (TH.TyVarI (reifyName tv) ty2) }++reifyThing thing = pprPanic "reifyThing" (pprTcTyThingCategory thing)++-------------------------------------------+reifyAxBranch :: TyCon -> CoAxBranch -> TcM TH.TySynEqn+reifyAxBranch fam_tc (CoAxBranch { cab_lhs = lhs, cab_rhs = rhs })+ -- remove kind patterns (#8884)+ = do { let lhs_types_only = filterOutInvisibleTypes fam_tc lhs+ ; lhs' <- reifyTypes lhs_types_only+ ; annot_th_lhs <- zipWith3M annotThType (mkIsPolyTvs fam_tvs)+ lhs_types_only lhs'+ ; rhs' <- reifyType rhs+ ; return (TH.TySynEqn annot_th_lhs rhs') }+ where+ fam_tvs = filterOutInvisibleTyVars fam_tc (tyConTyVars fam_tc)++reifyTyCon :: TyCon -> TcM TH.Info+reifyTyCon tc+ | Just cls <- tyConClass_maybe tc+ = reifyClass cls++ | isFunTyCon tc+ = return (TH.PrimTyConI (reifyName tc) 2 False)++ | isPrimTyCon tc+ = return (TH.PrimTyConI (reifyName tc) (tyConArity tc) (isUnliftedTyCon tc))++ | isTypeFamilyTyCon tc+ = do { let tvs = tyConTyVars tc+ res_kind = tyConResKind tc+ resVar = famTcResVar tc++ ; kind' <- reifyKind res_kind+ ; let (resultSig, injectivity) =+ case resVar of+ Nothing -> (TH.KindSig kind', Nothing)+ Just name ->+ let thName = reifyName name+ injAnnot = familyTyConInjectivityInfo tc+ sig = TH.TyVarSig (TH.KindedTV thName kind')+ inj = case injAnnot of+ NotInjective -> Nothing+ Injective ms ->+ Just (TH.InjectivityAnn thName injRHS)+ where+ injRHS = map (reifyName . tyVarName)+ (filterByList ms tvs)+ in (sig, inj)+ ; tvs' <- reifyTyVars tvs (Just tc)+ ; let tfHead =+ TH.TypeFamilyHead (reifyName tc) tvs' resultSig injectivity+ ; if isOpenTypeFamilyTyCon tc+ then do { fam_envs <- tcGetFamInstEnvs+ ; instances <- reifyFamilyInstances tc+ (familyInstances fam_envs tc)+ ; return (TH.FamilyI (TH.OpenTypeFamilyD tfHead) instances) }+ else do { eqns <-+ case isClosedSynFamilyTyConWithAxiom_maybe tc of+ Just ax -> mapM (reifyAxBranch tc) $+ fromBranches $ coAxiomBranches ax+ Nothing -> return []+ ; return (TH.FamilyI (TH.ClosedTypeFamilyD tfHead eqns)+ []) } }++ | isDataFamilyTyCon tc+ = do { let tvs = tyConTyVars tc+ res_kind = tyConResKind tc++ ; kind' <- fmap Just (reifyKind res_kind)++ ; tvs' <- reifyTyVars tvs (Just tc)+ ; fam_envs <- tcGetFamInstEnvs+ ; instances <- reifyFamilyInstances tc (familyInstances fam_envs tc)+ ; return (TH.FamilyI+ (TH.DataFamilyD (reifyName tc) tvs' kind') instances) }++ | Just (tvs, rhs) <- synTyConDefn_maybe tc -- Vanilla type synonym+ = do { rhs' <- reifyType rhs+ ; tvs' <- reifyTyVars tvs (Just tc)+ ; return (TH.TyConI+ (TH.TySynD (reifyName tc) tvs' rhs'))+ }++ | otherwise+ = do { cxt <- reifyCxt (tyConStupidTheta tc)+ ; let tvs = tyConTyVars tc+ dataCons = tyConDataCons tc+ -- see Note [Reifying GADT data constructors]+ isGadt = any (not . null . dataConEqSpec) dataCons+ ; cons <- mapM (reifyDataCon isGadt (mkTyVarTys tvs)) dataCons+ ; r_tvs <- reifyTyVars tvs (Just tc)+ ; let name = reifyName tc+ deriv = [] -- Don't know about deriving+ decl | isNewTyCon tc =+ TH.NewtypeD cxt name r_tvs Nothing (head cons) deriv+ | otherwise =+ TH.DataD cxt name r_tvs Nothing cons deriv+ ; return (TH.TyConI decl) }++reifyDataCon :: Bool -> [Type] -> DataCon -> TcM TH.Con+-- For GADTs etc, see Note [Reifying GADT data constructors]+reifyDataCon isGadtDataCon tys dc+ = do { let -- used for H98 data constructors+ (ex_tvs, theta, arg_tys)+ = dataConInstSig dc tys+ -- used for GADTs data constructors+ (g_univ_tvs, g_ex_tvs, g_eq_spec, g_theta, g_arg_tys, g_res_ty)+ = dataConFullSig dc+ (srcUnpks, srcStricts)+ = mapAndUnzip reifySourceBang (dataConSrcBangs dc)+ dcdBangs = zipWith TH.Bang srcUnpks srcStricts+ fields = dataConFieldLabels dc+ name = reifyName dc+ -- Universal tvs present in eq_spec need to be filtered out, as+ -- they will not appear anywhere in the type.+ eq_spec_tvs = mkVarSet (map eqSpecTyVar g_eq_spec)+ g_unsbst_univ_tvs = filterOut (`elemVarSet` eq_spec_tvs) g_univ_tvs++ ; r_arg_tys <- reifyTypes (if isGadtDataCon then g_arg_tys else arg_tys)++ ; main_con <-+ if | not (null fields) && not isGadtDataCon ->+ return $ TH.RecC name (zip3 (map reifyFieldLabel fields)+ dcdBangs r_arg_tys)+ | not (null fields) -> do+ { res_ty <- reifyType g_res_ty+ ; return $ TH.RecGadtC [name]+ (zip3 (map (reifyName . flSelector) fields)+ dcdBangs r_arg_tys) res_ty }+ -- We need to check not isGadtDataCon here because GADT+ -- constructors can be declared infix.+ -- See Note [Infix GADT constructors] in TcTyClsDecls.+ | dataConIsInfix dc && not isGadtDataCon ->+ ASSERT( length arg_tys == 2 ) do+ { let [r_a1, r_a2] = r_arg_tys+ [s1, s2] = dcdBangs+ ; return $ TH.InfixC (s1,r_a1) name (s2,r_a2) }+ | isGadtDataCon -> do+ { res_ty <- reifyType g_res_ty+ ; return $ TH.GadtC [name] (dcdBangs `zip` r_arg_tys) res_ty }+ | otherwise ->+ return $ TH.NormalC name (dcdBangs `zip` r_arg_tys)++ ; let (ex_tvs', theta') | isGadtDataCon = ( g_unsbst_univ_tvs ++ g_ex_tvs+ , g_theta )+ | otherwise = ( ex_tvs, theta )+ ret_con | null ex_tvs' && null theta' = return main_con+ | otherwise = do+ { cxt <- reifyCxt theta'+ ; ex_tvs'' <- reifyTyVars ex_tvs' Nothing+ ; return (TH.ForallC ex_tvs'' cxt main_con) }+ ; ASSERT( length arg_tys == length dcdBangs )+ ret_con }++-- Note [Reifying GADT data constructors]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- At this point in the compilation pipeline we have no way of telling whether a+-- data type was declared as a H98 data type or as a GADT. We have to rely on+-- heuristics here. We look at dcEqSpec field of all data constructors in a+-- data type declaration. If at least one data constructor has non-empty+-- dcEqSpec this means that the data type must have been declared as a GADT.+-- Consider these declarations:+--+-- data T a where+-- MkT :: forall a. (a ~ Int) => T a+--+-- data T a where+-- MkT :: T Int+--+-- First declaration will be reified as a GADT. Second declaration will be+-- reified as a normal H98 data type declaration.++------------------------------+reifyClass :: Class -> TcM TH.Info+reifyClass cls+ = do { cxt <- reifyCxt theta+ ; inst_envs <- tcGetInstEnvs+ ; insts <- reifyClassInstances cls (InstEnv.classInstances inst_envs cls)+ ; assocTys <- concatMapM reifyAT ats+ ; ops <- concatMapM reify_op op_stuff+ ; tvs' <- reifyTyVars tvs (Just $ classTyCon cls)+ ; let dec = TH.ClassD cxt (reifyName cls) tvs' fds' (assocTys ++ ops)+ ; return (TH.ClassI dec insts) }+ where+ (tvs, fds, theta, _, ats, op_stuff) = classExtraBigSig cls+ fds' = map reifyFunDep fds+ reify_op (op, def_meth)+ = do { ty <- reifyType (idType op)+ ; let nm' = reifyName op+ ; case def_meth of+ Just (_, GenericDM gdm_ty) ->+ do { gdm_ty' <- reifyType gdm_ty+ ; return [TH.SigD nm' ty, TH.DefaultSigD nm' gdm_ty'] }+ _ -> return [TH.SigD nm' ty] }++ reifyAT :: ClassATItem -> TcM [TH.Dec]+ reifyAT (ATI tycon def) = do+ tycon' <- reifyTyCon tycon+ case tycon' of+ TH.FamilyI dec _ -> do+ let (tyName, tyArgs) = tfNames dec+ (dec :) <$> maybe (return [])+ (fmap (:[]) . reifyDefImpl tyName tyArgs . fst)+ def+ _ -> pprPanic "reifyAT" (text (show tycon'))++ reifyDefImpl :: TH.Name -> [TH.Name] -> Type -> TcM TH.Dec+ reifyDefImpl n args ty =+ TH.TySynInstD n . TH.TySynEqn (map TH.VarT args) <$> reifyType ty++ tfNames :: TH.Dec -> (TH.Name, [TH.Name])+ tfNames (TH.OpenTypeFamilyD (TH.TypeFamilyHead n args _ _))+ = (n, map bndrName args)+ tfNames d = pprPanic "tfNames" (text (show d))++ bndrName :: TH.TyVarBndr -> TH.Name+ bndrName (TH.PlainTV n) = n+ bndrName (TH.KindedTV n _) = n++------------------------------+-- | Annotate (with TH.SigT) a type if the first parameter is True+-- and if the type contains a free variable.+-- This is used to annotate type patterns for poly-kinded tyvars in+-- reifying class and type instances. See #8953 and th/T8953.+annotThType :: Bool -- True <=> annotate+ -> TyCoRep.Type -> TH.Type -> TcM TH.Type+ -- tiny optimization: if the type is annotated, don't annotate again.+annotThType _ _ th_ty@(TH.SigT {}) = return th_ty+annotThType True ty th_ty+ | not $ isEmptyVarSet $ filterVarSet isTyVar $ tyCoVarsOfType ty+ = do { let ki = typeKind ty+ ; th_ki <- reifyKind ki+ ; return (TH.SigT th_ty th_ki) }+annotThType _ _ th_ty = return th_ty++-- | For every type variable in the input,+-- report whether or not the tv is poly-kinded. This is used to eventually+-- feed into 'annotThType'.+mkIsPolyTvs :: [TyVar] -> [Bool]+mkIsPolyTvs = map is_poly_tv+ where+ is_poly_tv tv = not $+ isEmptyVarSet $+ filterVarSet isTyVar $+ tyCoVarsOfType $+ tyVarKind tv++------------------------------+reifyClassInstances :: Class -> [ClsInst] -> TcM [TH.Dec]+reifyClassInstances cls insts+ = mapM (reifyClassInstance (mkIsPolyTvs tvs)) insts+ where+ tvs = filterOutInvisibleTyVars (classTyCon cls) (classTyVars cls)++reifyClassInstance :: [Bool] -- True <=> the corresponding tv is poly-kinded+ -- includes only *visible* tvs+ -> ClsInst -> TcM TH.Dec+reifyClassInstance is_poly_tvs i+ = do { cxt <- reifyCxt theta+ ; let vis_types = filterOutInvisibleTypes cls_tc types+ ; thtypes <- reifyTypes vis_types+ ; annot_thtypes <- zipWith3M annotThType is_poly_tvs vis_types thtypes+ ; let head_ty = mkThAppTs (TH.ConT (reifyName cls)) annot_thtypes+ ; return $ (TH.InstanceD over cxt head_ty []) }+ where+ (_tvs, theta, cls, types) = tcSplitDFunTy (idType dfun)+ cls_tc = classTyCon cls+ dfun = instanceDFunId i+ over = case overlapMode (is_flag i) of+ NoOverlap _ -> Nothing+ Overlappable _ -> Just TH.Overlappable+ Overlapping _ -> Just TH.Overlapping+ Overlaps _ -> Just TH.Overlaps+ Incoherent _ -> Just TH.Incoherent++------------------------------+reifyFamilyInstances :: TyCon -> [FamInst] -> TcM [TH.Dec]+reifyFamilyInstances fam_tc fam_insts+ = mapM (reifyFamilyInstance (mkIsPolyTvs fam_tvs)) fam_insts+ where+ fam_tvs = filterOutInvisibleTyVars fam_tc (tyConTyVars fam_tc)++reifyFamilyInstance :: [Bool] -- True <=> the corresponding tv is poly-kinded+ -- includes only *visible* tvs+ -> FamInst -> TcM TH.Dec+reifyFamilyInstance is_poly_tvs inst@(FamInst { fi_flavor = flavor+ , fi_fam = fam+ , fi_tvs = fam_tvs+ , fi_tys = lhs+ , fi_rhs = rhs })+ = case flavor of+ SynFamilyInst ->+ -- remove kind patterns (#8884)+ do { let lhs_types_only = filterOutInvisibleTypes fam_tc lhs+ ; th_lhs <- reifyTypes lhs_types_only+ ; annot_th_lhs <- zipWith3M annotThType is_poly_tvs lhs_types_only+ th_lhs+ ; th_rhs <- reifyType rhs+ ; return (TH.TySynInstD (reifyName fam)+ (TH.TySynEqn annot_th_lhs th_rhs)) }++ DataFamilyInst rep_tc ->+ do { let rep_tvs = tyConTyVars rep_tc+ fam' = reifyName fam++ -- eta-expand lhs types, because sometimes data/newtype+ -- instances are eta-reduced; See Trac #9692+ -- See Note [Eta reduction for data family axioms]+ -- in TcInstDcls+ (_rep_tc, rep_tc_args) = splitTyConApp rhs+ etad_tyvars = dropList rep_tc_args rep_tvs+ etad_tys = mkTyVarTys etad_tyvars+ eta_expanded_tvs = mkTyVarTys fam_tvs `chkAppend` etad_tys+ eta_expanded_lhs = lhs `chkAppend` etad_tys+ dataCons = tyConDataCons rep_tc+ -- see Note [Reifying GADT data constructors]+ isGadt = any (not . null . dataConEqSpec) dataCons+ ; cons <- mapM (reifyDataCon isGadt eta_expanded_tvs) dataCons+ ; let types_only = filterOutInvisibleTypes fam_tc eta_expanded_lhs+ ; th_tys <- reifyTypes types_only+ ; annot_th_tys <- zipWith3M annotThType is_poly_tvs types_only th_tys+ ; return $+ if isNewTyCon rep_tc+ then TH.NewtypeInstD [] fam' annot_th_tys Nothing (head cons) []+ else TH.DataInstD [] fam' annot_th_tys Nothing cons []+ }+ where+ fam_tc = famInstTyCon inst++------------------------------+reifyType :: TyCoRep.Type -> TcM TH.Type+-- Monadic only because of failure+reifyType ty@(ForAllTy {}) = reify_for_all ty+reifyType (LitTy t) = do { r <- reifyTyLit t; return (TH.LitT r) }+reifyType (TyVarTy tv) = return (TH.VarT (reifyName tv))+reifyType (TyConApp tc tys) = reify_tc_app tc tys -- Do not expand type synonyms here+reifyType (AppTy t1 t2) = do { [r1,r2] <- reifyTypes [t1,t2] ; return (r1 `TH.AppT` r2) }+reifyType ty@(FunTy t1 t2)+ | isPredTy t1 = reify_for_all ty -- Types like ((?x::Int) => Char -> Char)+ | otherwise = do { [r1,r2] <- reifyTypes [t1,t2] ; return (TH.ArrowT `TH.AppT` r1 `TH.AppT` r2) }+reifyType ty@(CastTy {}) = noTH (sLit "kind casts") (ppr ty)+reifyType ty@(CoercionTy {})= noTH (sLit "coercions in types") (ppr ty)++reify_for_all :: TyCoRep.Type -> TcM TH.Type+reify_for_all ty+ = do { cxt' <- reifyCxt cxt;+ ; tau' <- reifyType tau+ ; tvs' <- reifyTyVars tvs Nothing+ ; return (TH.ForallT tvs' cxt' tau') }+ where+ (tvs, cxt, tau) = tcSplitSigmaTy ty++reifyTyLit :: TyCoRep.TyLit -> TcM TH.TyLit+reifyTyLit (NumTyLit n) = return (TH.NumTyLit n)+reifyTyLit (StrTyLit s) = return (TH.StrTyLit (unpackFS s))++reifyTypes :: [Type] -> TcM [TH.Type]+reifyTypes = mapM reifyType++reifyPatSynType+ :: ([TyVar], ThetaType, [TyVar], ThetaType, [Type], Type) -> TcM TH.Type+-- reifies a pattern synonym's type and returns its *complete* type+-- signature; see NOTE [Pattern synonym signatures and Template+-- Haskell]+reifyPatSynType (univTyVars, req, exTyVars, prov, argTys, resTy)+ = do { univTyVars' <- reifyTyVars univTyVars Nothing+ ; req' <- reifyCxt req+ ; exTyVars' <- reifyTyVars exTyVars Nothing+ ; prov' <- reifyCxt prov+ ; tau' <- reifyType (mkFunTys argTys resTy)+ ; return $ TH.ForallT univTyVars' req'+ $ TH.ForallT exTyVars' prov' tau' }++reifyKind :: Kind -> TcM TH.Kind+reifyKind ki+ = do { let (kis, ki') = splitFunTys ki+ ; ki'_rep <- reifyNonArrowKind ki'+ ; kis_rep <- mapM reifyKind kis+ ; return (foldr (TH.AppT . TH.AppT TH.ArrowT) ki'_rep kis_rep) }+ where+ reifyNonArrowKind k | isLiftedTypeKind k = return TH.StarT+ | isConstraintKind k = return TH.ConstraintT+ reifyNonArrowKind (TyVarTy v) = return (TH.VarT (reifyName v))+ reifyNonArrowKind (FunTy _ k) = reifyKind k+ reifyNonArrowKind (ForAllTy _ k) = reifyKind k+ reifyNonArrowKind (TyConApp kc kis) = reify_kc_app kc kis+ reifyNonArrowKind (AppTy k1 k2) = do { k1' <- reifyKind k1+ ; k2' <- reifyKind k2+ ; return (TH.AppT k1' k2')+ }+ reifyNonArrowKind k = noTH (sLit "this kind") (ppr k)++reify_kc_app :: TyCon -> [TyCoRep.Kind] -> TcM TH.Kind+reify_kc_app kc kis+ = fmap (mkThAppTs r_kc) (mapM reifyKind vis_kis)+ where+ r_kc | isTupleTyCon kc = TH.TupleT (tyConArity kc)+ | kc `hasKey` listTyConKey = TH.ListT+ | otherwise = TH.ConT (reifyName kc)++ vis_kis = filterOutInvisibleTypes kc kis++reifyCxt :: [PredType] -> TcM [TH.Pred]+reifyCxt = mapM reifyPred++reifyFunDep :: ([TyVar], [TyVar]) -> TH.FunDep+reifyFunDep (xs, ys) = TH.FunDep (map reifyName xs) (map reifyName ys)++reifyTyVars :: [TyVar]+ -> Maybe TyCon -- the tycon if the tycovars are from a tycon.+ -- Used to detect which tvs are implicit.+ -> TcM [TH.TyVarBndr]+reifyTyVars tvs m_tc = mapM reify_tv tvs'+ where+ tvs' = case m_tc of+ Just tc -> filterOutInvisibleTyVars tc tvs+ Nothing -> tvs++ -- even if the kind is *, we need to include a kind annotation,+ -- in case a poly-kind would be inferred without the annotation.+ -- See #8953 or test th/T8953+ reify_tv tv = TH.KindedTV name <$> reifyKind kind+ where+ kind = tyVarKind tv+ name = reifyName tv++{-+Note [Kind annotations on TyConApps]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A poly-kinded tycon sometimes needs a kind annotation to be unambiguous.+For example:++ type family F a :: k+ type instance F Int = (Proxy :: * -> *)+ type instance F Bool = (Proxy :: (* -> *) -> *)++It's hard to figure out where these annotations should appear, so we do this:+Suppose the tycon is applied to n arguments. We strip off the first n+arguments of the tycon's kind. If there are any variables left in the result+kind, we put on a kind annotation. But we must be slightly careful: it's+possible that the tycon's kind will have fewer than n arguments, in the case+that the concrete application instantiates a result kind variable with an+arrow kind. So, if we run out of arguments, we conservatively put on a kind+annotation anyway. This should be a rare case, indeed. Here is an example:++ data T1 :: k1 -> k2 -> *+ data T2 :: k1 -> k2 -> *++ type family G (a :: k) :: k+ type instance G T1 = T2++ type instance F Char = (G T1 Bool :: (* -> *) -> *) -- F from above++Here G's kind is (forall k. k -> k), and the desugared RHS of that last+instance of F is (G (* -> (* -> *) -> *) (T1 * (* -> *)) Bool). According to+the algorithm above, there are 3 arguments to G so we should peel off 3+arguments in G's kind. But G's kind has only two arguments. This is the+rare special case, and we conservatively choose to put the annotation+in.++See #8953 and test th/T8953.+-}++reify_tc_app :: TyCon -> [Type.Type] -> TcM TH.Type+reify_tc_app tc tys+ = do { tys' <- reifyTypes (filterOutInvisibleTypes tc tys)+ ; maybe_sig_t (mkThAppTs r_tc tys') }+ where+ arity = tyConArity tc+ tc_binders = tyConBinders tc+ tc_res_kind = tyConResKind tc++ r_tc | isUnboxedSumTyCon tc = TH.UnboxedSumT (arity `div` 2)+ | isUnboxedTupleTyCon tc = TH.UnboxedTupleT (arity `div` 2)+ | isPromotedTupleTyCon tc = TH.PromotedTupleT (arity `div` 2)+ -- See Note [Unboxed tuple RuntimeRep vars] in TyCon+ | isTupleTyCon tc = if isPromotedDataCon tc+ then TH.PromotedTupleT arity+ else TH.TupleT arity+ | tc `hasKey` listTyConKey = TH.ListT+ | tc `hasKey` nilDataConKey = TH.PromotedNilT+ | tc `hasKey` consDataConKey = TH.PromotedConsT+ | tc `hasKey` heqTyConKey = TH.EqualityT+ | tc `hasKey` eqPrimTyConKey = TH.EqualityT+ | tc `hasKey` eqReprPrimTyConKey = TH.ConT (reifyName coercibleTyCon)+ | isPromotedDataCon tc = TH.PromotedT (reifyName tc)+ | otherwise = TH.ConT (reifyName tc)++ -- See Note [Kind annotations on TyConApps]+ maybe_sig_t th_type+ | needs_kind_sig+ = do { let full_kind = typeKind (mkTyConApp tc tys)+ ; th_full_kind <- reifyKind full_kind+ ; return (TH.SigT th_type th_full_kind) }+ | otherwise+ = return th_type++ needs_kind_sig+ | GT <- compareLength tys tc_binders+ = tcIsTyVarTy tc_res_kind+ | otherwise+ = not . isEmptyVarSet $+ filterVarSet isTyVar $+ tyCoVarsOfType $+ mkTyConKind (dropList tys tc_binders) tc_res_kind++reifyPred :: TyCoRep.PredType -> TcM TH.Pred+reifyPred ty+ -- We could reify the invisible parameter as a class but it seems+ -- nicer to support them properly...+ | isIPPred ty = noTH (sLit "implicit parameters") (ppr ty)+ | otherwise = reifyType ty++------------------------------+reifyName :: NamedThing n => n -> TH.Name+reifyName thing+ | isExternalName name = mk_varg pkg_str mod_str occ_str+ | otherwise = TH.mkNameU occ_str (getKey (getUnique name))+ -- Many of the things we reify have local bindings, and+ -- NameL's aren't supposed to appear in binding positions, so+ -- we use NameU. When/if we start to reify nested things, that+ -- have free variables, we may need to generate NameL's for them.+ where+ name = getName thing+ mod = ASSERT( isExternalName name ) nameModule name+ pkg_str = unitIdString (moduleUnitId mod)+ mod_str = moduleNameString (moduleName mod)+ occ_str = occNameString occ+ occ = nameOccName name+ mk_varg | OccName.isDataOcc occ = TH.mkNameG_d+ | OccName.isVarOcc occ = TH.mkNameG_v+ | OccName.isTcOcc occ = TH.mkNameG_tc+ | otherwise = pprPanic "reifyName" (ppr name)++-- See Note [Reifying field labels]+reifyFieldLabel :: FieldLabel -> TH.Name+reifyFieldLabel fl+ | flIsOverloaded fl+ = TH.Name (TH.mkOccName occ_str) (TH.NameQ (TH.mkModName mod_str))+ | otherwise = TH.mkNameG_v pkg_str mod_str occ_str+ where+ name = flSelector fl+ mod = ASSERT( isExternalName name ) nameModule name+ pkg_str = unitIdString (moduleUnitId mod)+ mod_str = moduleNameString (moduleName mod)+ occ_str = unpackFS (flLabel fl)++reifySelector :: Id -> TyCon -> TH.Name+reifySelector id tc+ = case find ((idName id ==) . flSelector) (tyConFieldLabels tc) of+ Just fl -> reifyFieldLabel fl+ Nothing -> pprPanic "reifySelector: missing field" (ppr id $$ ppr tc)++------------------------------+reifyFixity :: Name -> TcM (Maybe TH.Fixity)+reifyFixity name+ = do { (found, fix) <- lookupFixityRn_help name+ ; return (if found then Just (conv_fix fix) else Nothing) }+ where+ conv_fix (BasicTypes.Fixity _ i d) = TH.Fixity i (conv_dir d)+ conv_dir BasicTypes.InfixR = TH.InfixR+ conv_dir BasicTypes.InfixL = TH.InfixL+ conv_dir BasicTypes.InfixN = TH.InfixN++reifyUnpackedness :: DataCon.SrcUnpackedness -> TH.SourceUnpackedness+reifyUnpackedness NoSrcUnpack = TH.NoSourceUnpackedness+reifyUnpackedness SrcNoUnpack = TH.SourceNoUnpack+reifyUnpackedness SrcUnpack = TH.SourceUnpack++reifyStrictness :: DataCon.SrcStrictness -> TH.SourceStrictness+reifyStrictness NoSrcStrict = TH.NoSourceStrictness+reifyStrictness SrcStrict = TH.SourceStrict+reifyStrictness SrcLazy = TH.SourceLazy++reifySourceBang :: DataCon.HsSrcBang+ -> (TH.SourceUnpackedness, TH.SourceStrictness)+reifySourceBang (HsSrcBang _ u s) = (reifyUnpackedness u, reifyStrictness s)++reifyDecidedStrictness :: DataCon.HsImplBang -> TH.DecidedStrictness+reifyDecidedStrictness HsLazy = TH.DecidedLazy+reifyDecidedStrictness HsStrict = TH.DecidedStrict+reifyDecidedStrictness HsUnpack{} = TH.DecidedUnpack++------------------------------+lookupThAnnLookup :: TH.AnnLookup -> TcM CoreAnnTarget+lookupThAnnLookup (TH.AnnLookupName th_nm) = fmap NamedTarget (lookupThName th_nm)+lookupThAnnLookup (TH.AnnLookupModule (TH.Module pn mn))+ = return $ ModuleTarget $+ mkModule (stringToUnitId $ TH.pkgString pn) (mkModuleName $ TH.modString mn)++reifyAnnotations :: Data a => TH.AnnLookup -> TcM [a]+reifyAnnotations th_name+ = do { name <- lookupThAnnLookup th_name+ ; topEnv <- getTopEnv+ ; epsHptAnns <- liftIO $ prepareAnnotations topEnv Nothing+ ; tcg <- getGblEnv+ ; let selectedEpsHptAnns = findAnns deserializeWithData epsHptAnns name+ ; let selectedTcgAnns = findAnns deserializeWithData (tcg_ann_env tcg) name+ ; return (selectedEpsHptAnns ++ selectedTcgAnns) }++------------------------------+modToTHMod :: Module -> TH.Module+modToTHMod m = TH.Module (TH.PkgName $ unitIdString $ moduleUnitId m)+ (TH.ModName $ moduleNameString $ moduleName m)++reifyModule :: TH.Module -> TcM TH.ModuleInfo+reifyModule (TH.Module (TH.PkgName pkgString) (TH.ModName mString)) = do+ this_mod <- getModule+ let reifMod = mkModule (stringToUnitId pkgString) (mkModuleName mString)+ if (reifMod == this_mod) then reifyThisModule else reifyFromIface reifMod+ where+ reifyThisModule = do+ usages <- fmap (map modToTHMod . moduleEnvKeys . imp_mods) getImports+ return $ TH.ModuleInfo usages++ reifyFromIface reifMod = do+ iface <- loadInterfaceForModule (text "reifying module from TH for" <+> ppr reifMod) reifMod+ let usages = [modToTHMod m | usage <- mi_usages iface,+ Just m <- [usageToModule (moduleUnitId reifMod) usage] ]+ return $ TH.ModuleInfo usages++ usageToModule :: UnitId -> Usage -> Maybe Module+ usageToModule _ (UsageFile {}) = Nothing+ usageToModule this_pkg (UsageHomeModule { usg_mod_name = mn }) = Just $ mkModule this_pkg mn+ usageToModule _ (UsagePackageModule { usg_mod = m }) = Just m+ usageToModule _ (UsageMergedRequirement { usg_mod = m }) = Just m++------------------------------+mkThAppTs :: TH.Type -> [TH.Type] -> TH.Type+mkThAppTs fun_ty arg_tys = foldl TH.AppT fun_ty arg_tys++noTH :: LitString -> SDoc -> TcM a+noTH s d = failWithTc (hsep [text "Can't represent" <+> ptext s <+>+ text "in Template Haskell:",+ nest 2 d])++ppr_th :: TH.Ppr a => a -> SDoc+ppr_th x = text (TH.pprint x)++{-+Note [Reifying field labels]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When reifying a datatype declared with DuplicateRecordFields enabled, we want+the reified names of the fields to be labels rather than selector functions.+That is, we want (reify ''T) and (reify 'foo) to produce++ data T = MkT { foo :: Int }+ foo :: T -> Int++rather than++ data T = MkT { $sel:foo:MkT :: Int }+ $sel:foo:MkT :: T -> Int++because otherwise TH code that uses the field names as strings will silently do+the wrong thing. Thus we use the field label (e.g. foo) as the OccName, rather+than the selector (e.g. $sel:foo:MkT). Since the Orig name M.foo isn't in the+environment, NameG can't be used to represent such fields. Instead,+reifyFieldLabel uses NameQ.++However, this means that extracting the field name from the output of reify, and+trying to reify it again, may fail with an ambiguity error if there are multiple+such fields defined in the module (see the test case+overloadedrecflds/should_fail/T11103.hs). The "proper" fix requires changes to+the TH AST to make it able to represent duplicate record fields.+-}
+ typecheck/TcSplice.hs-boot view
@@ -0,0 +1,40 @@+{-# LANGUAGE CPP #-}++module TcSplice where+import HsSyn ( HsSplice, HsBracket, HsExpr, LHsExpr )+import HsExpr ( PendingRnSplice )+import Name ( Name )+import TcRnTypes( TcM, TcId )+import TcType ( ExpRhoType )+import Annotations ( Annotation, CoreAnnTarget )++import HsSyn ( LHsType, LPat, LHsDecl, ThModFinalizers )+import RdrName ( RdrName )+import TcRnTypes ( SpliceType )+import qualified Language.Haskell.TH as TH++tcSpliceExpr :: HsSplice Name+ -> ExpRhoType+ -> TcM (HsExpr TcId)++tcUntypedBracket :: HsBracket Name+ -> [PendingRnSplice]+ -> ExpRhoType+ -> TcM (HsExpr TcId)+tcTypedBracket :: HsBracket Name+ -> ExpRhoType+ -> TcM (HsExpr TcId)++runAnnotation :: CoreAnnTarget -> LHsExpr Name -> TcM Annotation++tcTopSpliceExpr :: SpliceType -> TcM (LHsExpr TcId) -> TcM (LHsExpr TcId)++runMetaE :: LHsExpr TcId -> TcM (LHsExpr RdrName)+runMetaP :: LHsExpr TcId -> TcM (LPat RdrName)+runMetaT :: LHsExpr TcId -> TcM (LHsType RdrName)+runMetaD :: LHsExpr TcId -> TcM [LHsDecl RdrName]++lookupThName_maybe :: TH.Name -> TcM (Maybe Name)+runQuasi :: TH.Q a -> TcM a+runRemoteModFinalizers :: ThModFinalizers -> TcM ()+finishTH :: TcM ()
+ typecheck/TcTyClsDecls.hs view
@@ -0,0 +1,3092 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1996-1998+++TcTyClsDecls: Typecheck type and class declarations+-}++{-# LANGUAGE CPP, TupleSections, MultiWayIf #-}++module TcTyClsDecls (+ tcTyAndClassDecls, tcAddImplicits,++ -- Functions used by TcInstDcls to check+ -- data/type family instance declarations+ kcDataDefn, tcConDecls, dataDeclChecks, checkValidTyCon,+ tcFamTyPats, tcTyFamInstEqn, famTyConShape,+ tcAddTyFamInstCtxt, tcMkDataFamInstCtxt, tcAddDataFamInstCtxt,+ wrongKindOfFamily, dataConCtxt+ ) where++#include "HsVersions.h"++import HsSyn+import HscTypes+import BuildTyCl+import TcRnMonad+import TcEnv+import TcValidity+import TcHsSyn+import TcTyDecls+import TcClassDcl+import {-# SOURCE #-} TcInstDcls( tcInstDecls1 )+import TcDeriv (DerivInfo)+import TcUnify+import TcHsType+import TcMType+import TysWiredIn ( unitTy )+import TcType+import RnEnv( RoleAnnotEnv, mkRoleAnnotEnv, lookupRoleAnnot+ , lookupConstructorFields )+import FamInst+import FamInstEnv+import Coercion+import Type+import TyCoRep -- for checkValidRoles+import Kind+import Class+import CoAxiom+import TyCon+import DataCon+import Id+import Var+import VarEnv+import VarSet+import Module+import Name+import NameSet+import NameEnv+import Outputable+import Maybes+import Unify+import Util+import SrcLoc+import ListSetOps+import DynFlags+import Unique+import BasicTypes+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.List++{-+************************************************************************+* *+\subsection{Type checking for type and class declarations}+* *+************************************************************************++Note [Grouping of type and class declarations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+tcTyAndClassDecls is called on a list of `TyClGroup`s. Each group is a strongly+connected component of mutually dependent types and classes. We kind check and+type check each group separately to enhance kind polymorphism. Take the+following example:++ type Id a = a+ data X = X (Id Int)++If we were to kind check the two declarations together, we would give Id the+kind * -> *, since we apply it to an Int in the definition of X. But we can do+better than that, since Id really is kind polymorphic, and should get kind+forall (k::*). k -> k. Since it does not depend on anything else, it can be+kind-checked by itself, hence getting the most general kind. We then kind check+X, which works fine because we then know the polymorphic kind of Id, and simply+instantiate k to *.++Note [Check role annotations in a second pass]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Role inference potentially depends on the types of all of the datacons declared+in a mutually recursive group. The validity of a role annotation, in turn,+depends on the result of role inference. Because the types of datacons might+be ill-formed (see #7175 and Note [Checking GADT return types]) we must check+*all* the tycons in a group for validity before checking *any* of the roles.+Thus, we take two passes over the resulting tycons, first checking for general+validity and then checking for valid role annotations.+-}++tcTyAndClassDecls :: [TyClGroup Name] -- Mutually-recursive groups in+ -- dependency order+ -> TcM ( TcGblEnv -- Input env extended by types and+ -- classes+ -- and their implicit Ids,DataCons+ , [InstInfo Name] -- Source-code instance decls info+ , [DerivInfo] -- data family deriving info+ )+-- Fails if there are any errors+tcTyAndClassDecls tyclds_s+ -- The code recovers internally, but if anything gave rise to+ -- an error we'd better stop now, to avoid a cascade+ -- Type check each group in dependency order folding the global env+ = checkNoErrs $ fold_env [] [] tyclds_s+ where+ fold_env :: [InstInfo Name]+ -> [DerivInfo]+ -> [TyClGroup Name]+ -> TcM (TcGblEnv, [InstInfo Name], [DerivInfo])+ fold_env inst_info deriv_info []+ = do { gbl_env <- getGblEnv+ ; return (gbl_env, inst_info, deriv_info) }+ fold_env inst_info deriv_info (tyclds:tyclds_s)+ = do { (tcg_env, inst_info', deriv_info') <- tcTyClGroup tyclds+ ; setGblEnv tcg_env $+ -- remaining groups are typechecked in the extended global env.+ fold_env (inst_info' ++ inst_info)+ (deriv_info' ++ deriv_info)+ tyclds_s }++tcTyClGroup :: TyClGroup Name+ -> TcM (TcGblEnv, [InstInfo Name], [DerivInfo])+-- Typecheck one strongly-connected component of type, class, and instance decls+-- See Note [TyClGroups and dependency analysis] in HsDecls+tcTyClGroup (TyClGroup { group_tyclds = tyclds+ , group_roles = roles+ , group_instds = instds })+ = do { let role_annots = mkRoleAnnotEnv roles++ -- Step 1: Typecheck the type/class declarations+ ; traceTc "-------- tcTyClGroup ------------" empty+ ; traceTc "Decls for" (ppr (map (tcdName . unLoc) tyclds))+ ; tyclss <- tcTyClDecls tyclds role_annots++ -- Step 1.5: Make sure we don't have any type synonym cycles+ ; traceTc "Starting synonym cycle check" (ppr tyclss)+ ; this_uid <- fmap thisPackage getDynFlags+ ; checkSynCycles this_uid tyclss tyclds+ ; traceTc "Done synonym cycle check" (ppr tyclss)++ ; traceTc "Starting family consistency check" (ppr tyclss)+ ; forM_ tyclss checkRecFamInstConsistency+ ; traceTc "Done family consistency" (ppr tyclss)++ -- Step 2: Perform the validity check on those types/classes+ -- We can do this now because we are done with the recursive knot+ -- Do it before Step 3 (adding implicit things) because the latter+ -- expects well-formed TyCons+ ; traceTc "Starting validity check" (ppr tyclss)+ ; tyclss <- mapM checkValidTyCl tyclss+ ; traceTc "Done validity check" (ppr tyclss)+ ; mapM_ (recoverM (return ()) . checkValidRoleAnnots role_annots) tyclss+ -- See Note [Check role annotations in a second pass]++ -- Step 3: Add the implicit things;+ -- we want them in the environment because+ -- they may be mentioned in interface files+ ; tcExtendTyConEnv tyclss $+ do { gbl_env <- tcAddImplicits tyclss+ ; setGblEnv gbl_env $+ do {+ -- Step 4: check instance declarations+ ; (gbl_env, inst_info, datafam_deriv_info) <- tcInstDecls1 instds++ ; return (gbl_env, inst_info, datafam_deriv_info) } } }++tcTyClDecls :: [LTyClDecl Name] -> RoleAnnotEnv -> TcM [TyCon]+tcTyClDecls tyclds role_annots+ = do { -- Step 1: kind-check this group and returns the final+ -- (possibly-polymorphic) kind of each TyCon and Class+ -- See Note [Kind checking for type and class decls]+ tc_tycons <- kcTyClGroup tyclds+ ; traceTc "tcTyAndCl generalized kinds" (vcat (map ppr_tc_tycon tc_tycons))++ -- Step 2: type-check all groups together, returning+ -- the final TyCons and Classes+ --+ -- NB: We have to be careful here to NOT eagerly unfold+ -- type synonyms, as we have not tested for type synonym+ -- loops yet and could fall into a black hole.+ ; fixM $ \ ~rec_tyclss -> do+ { tcg_env <- getGblEnv+ ; let roles = inferRoles (tcg_src tcg_env) role_annots rec_tyclss++ -- Populate environment with knot-tied ATyCon for TyCons+ -- NB: if the decls mention any ill-staged data cons+ -- (see Note [Recusion and promoting data constructors])+ -- we will have failed already in kcTyClGroup, so no worries here+ ; tcExtendRecEnv (zipRecTyClss tc_tycons rec_tyclss) $++ -- Also extend the local type envt with bindings giving+ -- the (polymorphic) kind of each knot-tied TyCon or Class+ -- See Note [Type checking recursive type and class declarations]+ tcExtendKindEnv (foldl extendEnvWithTcTyCon emptyNameEnv tc_tycons) $++ -- Kind and type check declarations for this group+ mapM (tcTyClDecl roles) tyclds+ } }+ where+ ppr_tc_tycon tc = parens (sep [ ppr (tyConName tc) <> comma+ , ppr (tyConBinders tc) <> comma+ , ppr (tyConResKind tc) ])++zipRecTyClss :: [TcTyCon]+ -> [TyCon] -- Knot-tied+ -> [(Name,TyThing)]+-- Build a name-TyThing mapping for the TyCons bound by decls+-- being careful not to look at the knot-tied [TyThing]+-- The TyThings in the result list must have a visible ATyCon,+-- because typechecking types (in, say, tcTyClDecl) looks at+-- this outer constructor+zipRecTyClss tc_tycons rec_tycons+ = [ (name, ATyCon (get name)) | tc_tycon <- tc_tycons, let name = getName tc_tycon ]+ where+ rec_tc_env :: NameEnv TyCon+ rec_tc_env = foldr add_tc emptyNameEnv rec_tycons++ add_tc :: TyCon -> NameEnv TyCon -> NameEnv TyCon+ add_tc tc env = foldr add_one_tc env (tc : tyConATs tc)++ add_one_tc :: TyCon -> NameEnv TyCon -> NameEnv TyCon+ add_one_tc tc env = extendNameEnv env (tyConName tc) tc++ get name = case lookupNameEnv rec_tc_env name of+ Just tc -> tc+ other -> pprPanic "zipRecTyClss" (ppr name <+> ppr other)++{-+************************************************************************+* *+ Kind checking+* *+************************************************************************++Note [Kind checking for type and class decls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Kind checking is done thus:++ 1. Make up a kind variable for each parameter of the declarations,+ and extend the kind environment (which is in the TcLclEnv)++ 2. Kind check the declarations++We need to kind check all types in the mutually recursive group+before we know the kind of the type variables. For example:++ class C a where+ op :: D b => a -> b -> b++ class D c where+ bop :: (Monad c) => ...++Here, the kind of the locally-polymorphic type variable "b"+depends on *all the uses of class D*. For example, the use of+Monad c in bop's type signature means that D must have kind Type->Type.++Note: we don't treat type synonyms specially (we used to, in the past);+in particular, even if we have a type synonym cycle, we still kind check+it normally, and test for cycles later (checkSynCycles). The reason+we can get away with this is because we have more systematic TYPE r+inference, which means that we can do unification between kinds that+aren't lifted (this historically was not true.)++The downside of not directly reading off the kinds off the RHS of+type synonyms in topological order is that we don't transparently+support making synonyms of types with higher-rank kinds. But+you can always specify a CUSK directly to make this work out.+See tc269 for an example.++Open type families+~~~~~~~~~~~~~~~~~~+This treatment of type synonyms only applies to Haskell 98-style synonyms.+General type functions can be recursive, and hence, appear in `alg_decls'.++The kind of an open type family is solely determinded by its kind signature;+hence, only kind signatures participate in the construction of the initial+kind environment (as constructed by `getInitialKind'). In fact, we ignore+instances of families altogether in the following. However, we need to include+the kinds of *associated* families into the construction of the initial kind+environment. (This is handled by `allDecls').+++See also Note [Kind checking recursive type and class declarations]++-}+++-- Note [Missed opportunity to retain higher-rank kinds]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- In 'kcTyClGroup', there is a missed opportunity to make kind+-- inference work in a few more cases. The idea is analogous+-- to Note [Single function non-recursive binding special-case]:+--+-- * If we have an SCC with a single decl, which is non-recursive,+-- instead of creating a unification variable representing the+-- kind of the decl and unifying it with the rhs, we can just+-- read the type directly of the rhs.+--+-- * Furthermore, we can update our SCC analysis to ignore+-- dependencies on declarations which have CUSKs: we don't+-- have to kind-check these all at once, since we can use+-- the CUSK to initialize the kind environment.+--+-- Unfortunately this requires reworking a bit of the code in+-- 'kcLTyClDecl' so I've decided to punt unless someone shouts about it.+--+kcTyClGroup :: [LTyClDecl Name] -> TcM [TcTyCon]++-- Kind check this group, kind generalize, and return the resulting local env+-- This binds the TyCons and Classes of the group, but not the DataCons+-- See Note [Kind checking for type and class decls]+-- Third return value is Nothing if the tycon be unsaturated; otherwise,+-- the arity+kcTyClGroup decls+ = do { mod <- getModule+ ; traceTc "kcTyClGroup" (text "module" <+> ppr mod $$ vcat (map ppr decls))++ -- Kind checking;+ -- 1. Bind kind variables for decls+ -- 2. Kind-check decls+ -- 3. Generalise the inferred kinds+ -- See Note [Kind checking for type and class decls]++ ; lcl_env <- solveEqualities $+ do { -- Step 1: Bind kind variables for all decls+ initial_kinds <- getInitialKinds decls+ ; traceTc "kcTyClGroup: initial kinds" $+ ppr initial_kinds++ -- Step 2: Set extended envt, kind-check the decls+ ; tcExtendKindEnv initial_kinds $+ do { mapM_ kcLTyClDecl decls+ ; getLclEnv } }++ -- Step 3: generalisation+ -- Kind checking done for this group+ -- Now we have to kind generalize the flexis+ ; res <- concatMapM (generaliseTCD (tcl_env lcl_env)) decls++ ; traceTc "kcTyClGroup result" (vcat (map pp_res res))+ ; return res }++ where+ generalise :: TcTypeEnv -> Name -> TcM TcTyCon+ -- For polymorphic things this is a no-op+ generalise kind_env name+ = do { let tc = case lookupNameEnv kind_env name of+ Just (ATcTyCon tc) -> tc+ _ -> pprPanic "kcTyClGroup" (ppr name $$ ppr kind_env)+ kc_binders = tyConBinders tc+ kc_res_kind = tyConResKind tc+ kc_tyvars = tyConTyVars tc+ ; kvs <- kindGeneralize (mkTyConKind kc_binders kc_res_kind)+ ; let all_binders = mkNamedTyConBinders Inferred kvs ++ kc_binders++ ; (env, all_binders') <- zonkTyVarBindersX emptyZonkEnv all_binders+ ; kc_res_kind' <- zonkTcTypeToType env kc_res_kind++ -- Make sure kc_kind' has the final, zonked kind variables+ ; traceTc "Generalise kind" $+ vcat [ ppr name, ppr kc_binders, ppr kvs, ppr all_binders, ppr kc_res_kind+ , ppr all_binders', ppr kc_res_kind'+ , ppr kc_tyvars, ppr (tcTyConScopedTyVars tc)]++ ; return (mkTcTyCon name all_binders' kc_res_kind'+ (mightBeUnsaturatedTyCon tc)+ (tcTyConScopedTyVars tc)) }++ generaliseTCD :: TcTypeEnv+ -> LTyClDecl Name -> TcM [TcTyCon]+ generaliseTCD kind_env (L _ decl)+ | ClassDecl { tcdLName = (L _ name), tcdATs = ats } <- decl+ = do { first <- generalise kind_env name+ ; rest <- mapM ((generaliseFamDecl kind_env) . unLoc) ats+ ; return (first : rest) }++ | FamDecl { tcdFam = fam } <- decl+ = do { res <- generaliseFamDecl kind_env fam+ ; return [res] }++ | otherwise+ = do { res <- generalise kind_env (tcdName decl)+ ; return [res] }++ generaliseFamDecl :: TcTypeEnv+ -> FamilyDecl Name -> TcM TcTyCon+ generaliseFamDecl kind_env (FamilyDecl { fdLName = L _ name })+ = generalise kind_env name++ pp_res tc = ppr (tyConName tc) <+> dcolon <+> ppr (tyConKind tc)++--------------+mkTcTyConEnv :: TcTyCon -> TcTypeEnv+mkTcTyConEnv tc = unitNameEnv (getName tc) (ATcTyCon tc)++extendEnvWithTcTyCon :: TcTypeEnv -> TcTyCon -> TcTypeEnv+-- Makes a binding to put in the local envt, binding+-- a name to a TcTyCon+extendEnvWithTcTyCon env tc+ = extendNameEnv env (getName tc) (ATcTyCon tc)++--------------+mkPromotionErrorEnv :: [LTyClDecl Name] -> TcTypeEnv+-- Maps each tycon/datacon to a suitable promotion error+-- tc :-> APromotionErr TyConPE+-- dc :-> APromotionErr RecDataConPE+-- See Note [ARecDataCon: Recursion and promoting data constructors]++mkPromotionErrorEnv decls+ = foldr (plusNameEnv . mk_prom_err_env . unLoc)+ emptyNameEnv decls++mk_prom_err_env :: TyClDecl Name -> TcTypeEnv+mk_prom_err_env (ClassDecl { tcdLName = L _ nm, tcdATs = ats })+ = unitNameEnv nm (APromotionErr ClassPE)+ `plusNameEnv`+ mkNameEnv [ (name, APromotionErr TyConPE)+ | L _ (FamilyDecl { fdLName = L _ name }) <- ats ]++mk_prom_err_env (DataDecl { tcdLName = L _ name+ , tcdDataDefn = HsDataDefn { dd_cons = cons } })+ = unitNameEnv name (APromotionErr TyConPE)+ `plusNameEnv`+ mkNameEnv [ (con, APromotionErr RecDataConPE)+ | L _ con' <- cons, L _ con <- getConNames con' ]++mk_prom_err_env decl+ = unitNameEnv (tcdName decl) (APromotionErr TyConPE)+ -- Works for family declarations too++--------------+getInitialKinds :: [LTyClDecl Name] -> TcM (NameEnv TcTyThing)+-- Maps each tycon to its initial kind,+-- and each datacon to a suitable promotion error+-- tc :-> ATcTyCon (tc:initial_kind)+-- dc :-> APromotionErr RecDataConPE+-- See Note [ARecDataCon: Recursion and promoting data constructors]++getInitialKinds decls+ = tcExtendKindEnv promotion_err_env $+ do { tc_kinds <- mapM (addLocM getInitialKind) decls+ ; return (foldl plusNameEnv promotion_err_env tc_kinds) }+ where+ promotion_err_env = mkPromotionErrorEnv decls++getInitialKind :: TyClDecl Name+ -> TcM (NameEnv TcTyThing)+-- Allocate a fresh kind variable for each TyCon and Class+-- For each tycon, return a NameEnv with+-- name :-> ATcTyCon (TcCyCon with kind k))+-- where k is the kind of tc, derived from the LHS+-- of the definition (and probably including+-- kind unification variables)+-- Example: data T a b = ...+-- return (T, kv1 -> kv2 -> kv3)+--+-- This pass deals with (ie incorporates into the kind it produces)+-- * The kind signatures on type-variable binders+-- * The result kinds signature on a TyClDecl+--+-- No family instances are passed to getInitialKinds++getInitialKind decl@(ClassDecl { tcdLName = L _ name, tcdTyVars = ktvs, tcdATs = ats })+ = do { let cusk = hsDeclHasCusk decl+ ; (tycon, inner_prs) <-+ kcHsTyVarBndrs name True cusk False True ktvs $+ do { inner_prs <- getFamDeclInitialKinds (Just cusk) ats+ ; return (constraintKind, inner_prs) }+ ; return (extendEnvWithTcTyCon inner_prs tycon) }++getInitialKind decl@(DataDecl { tcdLName = L _ name+ , tcdTyVars = ktvs+ , tcdDataDefn = HsDataDefn { dd_kindSig = m_sig } })+ = do { (tycon, _) <-+ kcHsTyVarBndrs name True (hsDeclHasCusk decl) False True ktvs $+ do { res_k <- case m_sig of+ Just ksig -> tcLHsKindSig ksig+ Nothing -> return liftedTypeKind+ ; return (res_k, ()) }+ ; return (mkTcTyConEnv tycon) }++getInitialKind (FamDecl { tcdFam = decl })+ = getFamDeclInitialKind Nothing decl++getInitialKind decl@(SynDecl { tcdLName = L _ name+ , tcdTyVars = ktvs+ , tcdRhs = rhs })+ = do { (tycon, _) <- kcHsTyVarBndrs name False (hsDeclHasCusk decl)+ False {- not open -} True ktvs $+ do { res_k <- case kind_annotation rhs of+ Nothing -> newMetaKindVar+ Just ksig -> tcLHsKindSig ksig+ ; return (res_k, ()) }+ ; return (mkTcTyConEnv tycon) }+ where+ -- Keep this synchronized with 'hsDeclHasCusk'.+ kind_annotation (L _ ty) = case ty of+ HsParTy lty -> kind_annotation lty+ HsKindSig _ k -> Just k+ _ -> Nothing++---------------------------------+getFamDeclInitialKinds :: Maybe Bool -- if assoc., CUSKness of assoc. class+ -> [LFamilyDecl Name]+ -> TcM TcTypeEnv+getFamDeclInitialKinds mb_cusk decls+ = do { tc_kinds <- mapM (addLocM (getFamDeclInitialKind mb_cusk)) decls+ ; return (foldr plusNameEnv emptyNameEnv tc_kinds) }++getFamDeclInitialKind :: Maybe Bool -- if assoc., CUSKness of assoc. class+ -> FamilyDecl Name+ -> TcM TcTypeEnv+getFamDeclInitialKind mb_cusk decl@(FamilyDecl { fdLName = L _ name+ , fdTyVars = ktvs+ , fdResultSig = L _ resultSig+ , fdInfo = info })+ = do { (tycon, _) <-+ kcHsTyVarBndrs name unsat cusk open True ktvs $+ do { res_k <- case resultSig of+ KindSig ki -> tcLHsKindSig ki+ TyVarSig (L _ (KindedTyVar _ ki)) -> tcLHsKindSig ki+ _ -- open type families have * return kind by default+ | open -> return liftedTypeKind+ -- closed type families have their return kind inferred+ -- by default+ | otherwise -> newMetaKindVar+ ; return (res_k, ()) }+ ; return (mkTcTyConEnv tycon) }+ where+ cusk = famDeclHasCusk mb_cusk decl+ (open, unsat) = case info of+ DataFamily -> (True, True)+ OpenTypeFamily -> (True, False)+ ClosedTypeFamily _ -> (False, False)++------------------------------------------------------------------------+kcLTyClDecl :: LTyClDecl Name -> TcM ()+ -- See Note [Kind checking for type and class decls]+kcLTyClDecl (L loc decl)+ = setSrcSpan loc $ tcAddDeclCtxt decl $ kcTyClDecl decl++kcTyClDecl :: TyClDecl Name -> TcM ()+-- This function is used solely for its side effect on kind variables+-- NB kind signatures on the type variables and+-- result kind signature have already been dealt with+-- by getInitialKind, so we can ignore them here.++kcTyClDecl (DataDecl { tcdLName = L _ name, tcdDataDefn = defn })+ | HsDataDefn { dd_cons = cons, dd_kindSig = Just _ } <- defn+ = mapM_ (wrapLocM kcConDecl) cons+ -- hs_tvs and dd_kindSig already dealt with in getInitialKind+ -- If dd_kindSig is Just, this must be a GADT-style decl,+ -- (see invariants of DataDefn declaration)+ -- so (a) we don't need to bring the hs_tvs into scope, because the+ -- ConDecls bind all their own variables+ -- (b) dd_ctxt is not allowed for GADT-style decls, so we can ignore it++ | HsDataDefn { dd_ctxt = ctxt, dd_cons = cons } <- defn+ = kcTyClTyVars name $+ do { _ <- tcHsContext ctxt+ ; mapM_ (wrapLocM kcConDecl) cons }++kcTyClDecl (SynDecl { tcdLName = L _ name, tcdRhs = lrhs })+ = kcTyClTyVars name $+ do { syn_tc <- kcLookupTcTyCon name+ -- NB: check against the result kind that we allocated+ -- in getInitialKinds.+ ; discardResult $ tcCheckLHsType lrhs (tyConResKind syn_tc) }++kcTyClDecl (ClassDecl { tcdLName = L _ name+ , tcdCtxt = ctxt, tcdSigs = sigs })+ = kcTyClTyVars name $+ do { _ <- tcHsContext ctxt+ ; mapM_ (wrapLocM kc_sig) sigs }+ where+ kc_sig (ClassOpSig _ nms op_ty) = kcHsSigType nms op_ty+ kc_sig _ = return ()++kcTyClDecl (FamDecl (FamilyDecl { fdLName = L _ fam_tc_name+ , fdInfo = fd_info }))+-- closed type families look at their equations, but other families don't+-- do anything here+ = case fd_info of+ ClosedTypeFamily (Just eqns) ->+ do { fam_tc <- kcLookupTcTyCon fam_tc_name+ ; mapM_ (kcTyFamInstEqn (famTyConShape fam_tc)) eqns }+ _ -> return ()++-------------------+kcConDecl :: ConDecl Name -> TcM ()+kcConDecl (ConDeclH98 { con_name = name, con_qvars = ex_tvs+ , con_cxt = ex_ctxt, con_details = details })+ = addErrCtxt (dataConCtxtName [name]) $+ -- the 'False' says that the existentials don't have a CUSK, as the+ -- concept doesn't really apply here. We just need to bring the variables+ -- into scope.+ do { _ <- kcHsTyVarBndrs (unLoc name) False False False False+ ((fromMaybe emptyLHsQTvs ex_tvs)) $+ do { _ <- tcHsContext (fromMaybe (noLoc []) ex_ctxt)+ ; mapM_ (tcHsOpenType . getBangType) (hsConDeclArgTys details)+ ; return (panic "kcConDecl", ()) }+ -- We don't need to check the telescope here, because that's+ -- done in tcConDecl+ ; return () }++kcConDecl (ConDeclGADT { con_names = names+ , con_type = ty })+ = addErrCtxt (dataConCtxtName names) $+ do { _ <- tcGadtSigType (ppr names) (unLoc $ head names) ty+ ; return () }+++{-+Note [Recursion and promoting data constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't want to allow promotion in a strongly connected component+when kind checking.++Consider:+ data T f = K (f (K Any))++When kind checking the `data T' declaration the local env contains the+mappings:+ T -> ATcTyCon <some initial kind>+ K -> APromotionErr++APromotionErr is only used for DataCons, and only used during type checking+in tcTyClGroup.+++************************************************************************+* *+\subsection{Type checking}+* *+************************************************************************++Note [Type checking recursive type and class declarations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+At this point we have completed *kind-checking* of a mutually+recursive group of type/class decls (done in kcTyClGroup). However,+we discarded the kind-checked types (eg RHSs of data type decls);+note that kcTyClDecl returns (). There are two reasons:++ * It's convenient, because we don't have to rebuild a+ kinded HsDecl (a fairly elaborate type)++ * It's necessary, because after kind-generalisation, the+ TyCons/Classes may now be kind-polymorphic, and hence need+ to be given kind arguments.++Example:+ data T f a = MkT (f a) (T f a)+During kind-checking, we give T the kind T :: k1 -> k2 -> *+and figure out constraints on k1, k2 etc. Then we generalise+to get T :: forall k. (k->*) -> k -> *+So now the (T f a) in the RHS must be elaborated to (T k f a).++However, during tcTyClDecl of T (above) we will be in a recursive+"knot". So we aren't allowed to look at the TyCon T itself; we are only+allowed to put it (lazily) in the returned structures. But when+kind-checking the RHS of T's decl, we *do* need to know T's kind (so+that we can correctly elaboarate (T k f a). How can we get T's kind+without looking at T? Delicate answer: during tcTyClDecl, we extend++ *Global* env with T -> ATyCon (the (not yet built) final TyCon for T)+ *Local* env with T -> ATcTyCon (TcTyCon with the polymorphic kind of T)++Then:++ * During TcHsType.kcTyVar we look in the *local* env, to get the+ known kind for T.++ * But in TcHsType.ds_type (and ds_var_app in particular) we look in+ the *global* env to get the TyCon. But we must be careful not to+ force the TyCon or we'll get a loop.++This fancy footwork (with two bindings for T) is only necessary for the+TyCons or Classes of this recursive group. Earlier, finished groups,+live in the global env only.++See also Note [Kind checking recursive type and class declarations]++Note [Kind checking recursive type and class declarations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Before we can type-check the decls, we must kind check them. This+is done by establishing an "initial kind", which is a rather uninformed+guess at a tycon's kind (by counting arguments, mainly) and then+using this initial kind for recursive occurrences.++The initial kind is stored in exactly the same way during kind-checking+as it is during type-checking (Note [Type checking recursive type and class+declarations]): in the *local* environment, with ATcTyCon. But we still+must store *something* in the *global* environment. Even though we+discard the result of kind-checking, we sometimes need to produce error+messages. These error messages will want to refer to the tycons being+checked, except that they don't exist yet, and it would be Terribly+Annoying to get the error messages to refer back to HsSyn. So we+create a TcTyCon and put it in the global env. This tycon can+print out its name and knows its kind,+but any other action taken on it will panic. Note+that TcTyCons are *not* knot-tied, unlike the rather valid but+knot-tied ones that occur during type-checking.++Note [Declarations for wired-in things]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For wired-in things we simply ignore the declaration+and take the wired-in information. That avoids complications.+e.g. the need to make the data constructor worker name for+ a constraint tuple match the wired-in one+-}++tcTyClDecl :: RolesInfo -> LTyClDecl Name -> TcM TyCon+tcTyClDecl roles_info (L loc decl)+ | Just thing <- wiredInNameTyThing_maybe (tcdName decl)+ = case thing of -- See Note [Declarations for wired-in things]+ ATyCon tc -> return tc+ _ -> pprPanic "tcTyClDecl" (ppr thing)++ | otherwise+ = setSrcSpan loc $ tcAddDeclCtxt decl $+ do { traceTc "tcTyAndCl-x" (ppr decl)+ ; tcTyClDecl1 Nothing roles_info decl }++ -- "type family" declarations+tcTyClDecl1 :: Maybe Class -> RolesInfo -> TyClDecl Name -> TcM TyCon+tcTyClDecl1 parent _roles_info (FamDecl { tcdFam = fd })+ = tcFamDecl1 parent fd++ -- "type" synonym declaration+tcTyClDecl1 _parent roles_info+ (SynDecl { tcdLName = L _ tc_name, tcdRhs = rhs })+ = ASSERT( isNothing _parent )+ tcTyClTyVars tc_name $ \ binders res_kind ->+ tcTySynRhs roles_info tc_name binders res_kind rhs++ -- "data/newtype" declaration+tcTyClDecl1 _parent roles_info+ (DataDecl { tcdLName = L _ tc_name, tcdDataDefn = defn })+ = ASSERT( isNothing _parent )+ tcTyClTyVars tc_name $ \ tycon_binders res_kind ->+ tcDataDefn roles_info tc_name tycon_binders res_kind defn++tcTyClDecl1 _parent roles_info+ (ClassDecl { tcdLName = L _ class_name+ , tcdCtxt = ctxt, tcdMeths = meths+ , tcdFDs = fundeps, tcdSigs = sigs+ , tcdATs = ats, tcdATDefs = at_defs })+ = ASSERT( isNothing _parent )+ do { clas <- fixM $ \ clas ->+ -- We need the knot because 'clas' is passed into tcClassATs+ tcTyClTyVars class_name $ \ binders res_kind ->+ do { MASSERT( isConstraintKind res_kind )+ ; traceTc "tcClassDecl 1" (ppr class_name $$ ppr binders)+ ; let tycon_name = class_name -- We use the same name+ roles = roles_info tycon_name -- for TyCon and Class++ ; ctxt' <- solveEqualities $ tcHsContext ctxt+ ; ctxt' <- zonkTcTypeToTypes emptyZonkEnv ctxt'+ -- Squeeze out any kind unification variables+ ; fds' <- mapM (addLocM tc_fundep) fundeps+ ; sig_stuff <- tcClassSigs class_name sigs meths+ ; at_stuff <- tcClassATs class_name clas ats at_defs+ ; mindef <- tcClassMinimalDef class_name sigs sig_stuff+ -- TODO: Allow us to distinguish between abstract class,+ -- and concrete class with no methods (maybe by+ -- specifying a trailing where or not+ ; is_boot <- tcIsHsBootOrSig+ ; let body | is_boot, null ctxt', null at_stuff, null sig_stuff+ = Nothing+ | otherwise+ = Just (ctxt', at_stuff, sig_stuff, mindef)+ ; clas <- buildClass class_name binders roles fds' body+ ; traceTc "tcClassDecl" (ppr fundeps $$ ppr binders $$+ ppr fds')+ ; return clas }++ ; return (classTyCon clas) }+ where+ tc_fundep (tvs1, tvs2) = do { tvs1' <- mapM (tcLookupTyVar . unLoc) tvs1 ;+ ; tvs2' <- mapM (tcLookupTyVar . unLoc) tvs2 ;+ ; return (tvs1', tvs2') }++tcFamDecl1 :: Maybe Class -> FamilyDecl Name -> TcM TyCon+tcFamDecl1 parent (FamilyDecl { fdInfo = fam_info, fdLName = tc_lname@(L _ tc_name)+ , fdTyVars = tvs, fdResultSig = L _ sig+ , fdInjectivityAnn = inj })+ | DataFamily <- fam_info+ = tcTyClTyVars tc_name $ \ binders res_kind -> do+ { traceTc "data family:" (ppr tc_name)+ ; checkFamFlag tc_name+ ; (extra_binders, real_res_kind) <- tcDataKindSig res_kind+ ; tc_rep_name <- newTyConRepName tc_name+ ; let tycon = mkFamilyTyCon tc_name (binders `chkAppend` extra_binders)+ real_res_kind+ (resultVariableName sig)+ (DataFamilyTyCon tc_rep_name)+ parent NotInjective+ ; return tycon }++ | OpenTypeFamily <- fam_info+ = tcTyClTyVars tc_name $ \ binders res_kind -> do+ { traceTc "open type family:" (ppr tc_name)+ ; checkFamFlag tc_name+ ; inj' <- tcInjectivity binders inj+ ; let tycon = mkFamilyTyCon tc_name binders res_kind+ (resultVariableName sig) OpenSynFamilyTyCon+ parent inj'+ ; return tycon }++ | 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)+ -- the variables in the header scope only over the injectivity+ -- declaration but this is not involved here+ ; (inj', binders, res_kind)+ <- tcTyClTyVars tc_name+ $ \ binders res_kind ->+ do { inj' <- tcInjectivity binders inj+ ; return (inj', binders, res_kind) }++ ; checkFamFlag tc_name -- make sure we have -XTypeFamilies++ -- If Nothing, this is an abstract family in a hs-boot file;+ -- but eqns might be empty in the Just case as well+ ; case mb_eqns of+ Nothing ->+ return $ mkFamilyTyCon tc_name binders res_kind+ (resultVariableName sig)+ AbstractClosedSynFamilyTyCon parent+ inj'+ Just eqns -> do {++ -- Process the equations, creating CoAxBranches+ ; let fam_tc_shape = (tc_name, length $ hsQTvExplicit tvs, binders, res_kind)++ ; branches <- mapM (tcTyFamInstEqn fam_tc_shape Nothing) eqns+ -- Do not attempt to drop equations dominated by earlier+ -- ones here; in the case of mutual recursion with a data+ -- type, we get a knot-tying failure. Instead we check+ -- for this afterwards, in TcValidity.checkValidCoAxiom+ -- Example: tc265++ -- Create a CoAxiom, with the correct src location. It is Vitally+ -- Important that we do not pass the branches into+ -- newFamInstAxiomName. They have types that have been zonked inside+ -- the knot and we will die if we look at them. This is OK here+ -- because there will only be one axiom, so we don't need to+ -- differentiate names.+ -- See [Zonking inside the knot] in TcHsType+ ; co_ax_name <- newFamInstAxiomName tc_lname []++ ; let mb_co_ax+ | null eqns = Nothing -- mkBranchedCoAxiom fails on empty list+ | otherwise = Just (mkBranchedCoAxiom co_ax_name fam_tc branches)++ fam_tc = mkFamilyTyCon tc_name binders res_kind (resultVariableName sig)+ (ClosedSynFamilyTyCon mb_co_ax) parent inj'++ -- We check for instance validity later, when doing validity+ -- checking for the tycon. Exception: checking equations+ -- overlap done by dropDominatedAxioms+ ; return fam_tc } }++ | otherwise = panic "tcFamInst1" -- Silence pattern-exhaustiveness checker+++-- | Maybe return a list of Bools that say whether a type family was declared+-- injective in the corresponding type arguments. Length of the list is equal to+-- the number of arguments (including implicit kind/coercion arguments).+-- True on position+-- N means that a function is injective in its Nth argument. False means it is+-- not.+tcInjectivity :: [TyConBinder] -> Maybe (LInjectivityAnn Name)+ -> TcM Injectivity+tcInjectivity _ Nothing+ = return NotInjective++ -- User provided an injectivity annotation, so for each tyvar argument we+ -- check whether a type family was declared injective in that argument. We+ -- return a list of Bools, where True means that corresponding type variable+ -- was mentioned in lInjNames (type family is injective in that argument) and+ -- False means that it was not mentioned in lInjNames (type family is not+ -- injective in that type variable). We also extend injectivity information to+ -- kind variables, so if a user declares:+ --+ -- type family F (a :: k1) (b :: k2) = (r :: k3) | r -> a+ --+ -- then we mark both `a` and `k1` as injective.+ -- NB: the return kind is considered to be *input* argument to a type family.+ -- Since injectivity allows to infer input arguments from the result in theory+ -- we should always mark the result kind variable (`k3` in this example) as+ -- injective. The reason is that result type has always an assigned kind and+ -- therefore we can always infer the result kind if we know the result type.+ -- But this does not seem to be useful in any way so we don't do it. (Another+ -- reason is that the implementation would not be straightforward.)+tcInjectivity tcbs (Just (L loc (InjectivityAnn _ lInjNames)))+ = setSrcSpan loc $+ do { let tvs = binderVars tcbs+ ; dflags <- getDynFlags+ ; checkTc (xopt LangExt.TypeFamilyDependencies dflags)+ (text "Illegal injectivity annotation" $$+ text "Use TypeFamilyDependencies to allow this")+ ; inj_tvs <- mapM (tcLookupTyVar . unLoc) lInjNames+ ; inj_tvs <- mapM zonkTcTyVarToTyVar inj_tvs -- zonk the kinds+ ; let inj_ktvs = filterVarSet isTyVar $ -- no injective coercion vars+ closeOverKinds (mkVarSet inj_tvs)+ ; let inj_bools = map (`elemVarSet` inj_ktvs) tvs+ ; traceTc "tcInjectivity" (vcat [ ppr tvs, ppr lInjNames, ppr inj_tvs+ , ppr inj_ktvs, ppr inj_bools ])+ ; return $ Injective inj_bools }++tcTySynRhs :: RolesInfo+ -> Name+ -> [TyConBinder] -> Kind+ -> LHsType Name -> TcM TyCon+tcTySynRhs roles_info tc_name binders res_kind hs_ty+ = do { env <- getLclEnv+ ; traceTc "tc-syn" (ppr tc_name $$ ppr (tcl_env env))+ ; rhs_ty <- solveEqualities $ tcCheckLHsType hs_ty res_kind+ ; rhs_ty <- zonkTcTypeToType emptyZonkEnv rhs_ty+ ; let roles = roles_info tc_name+ tycon = buildSynTyCon tc_name binders res_kind roles rhs_ty+ ; return tycon }++tcDataDefn :: RolesInfo -> Name+ -> [TyConBinder] -> Kind+ -> HsDataDefn Name -> TcM TyCon+ -- NB: not used for newtype/data instances (whether associated or not)+tcDataDefn roles_info+ tc_name tycon_binders res_kind+ (HsDataDefn { dd_ND = new_or_data, dd_cType = cType+ , dd_ctxt = ctxt, dd_kindSig = mb_ksig+ , dd_cons = cons })+ = do { (extra_bndrs, real_res_kind) <- tcDataKindSig res_kind+ ; let final_bndrs = tycon_binders `chkAppend` extra_bndrs+ roles = roles_info tc_name++ ; stupid_tc_theta <- solveEqualities $ tcHsContext ctxt+ ; stupid_theta <- zonkTcTypeToTypes emptyZonkEnv+ stupid_tc_theta+ ; kind_signatures <- xoptM LangExt.KindSignatures+ ; tcg_env <- getGblEnv+ ; let hsc_src = tcg_src tcg_env++ -- Check that we don't use kind signatures without Glasgow extensions+ ; when (isJust mb_ksig) $+ checkTc (kind_signatures) (badSigTyDecl tc_name)++ ; gadt_syntax <- dataDeclChecks tc_name new_or_data stupid_theta cons++ ; tycon <- fixM $ \ tycon -> do+ { let res_ty = mkTyConApp tycon (mkTyVarTys (binderVars final_bndrs))+ ; data_cons <- tcConDecls tycon (final_bndrs, res_ty) cons+ ; tc_rhs <- mk_tc_rhs hsc_src tycon data_cons+ ; tc_rep_nm <- newTyConRepName tc_name+ ; return (mkAlgTyCon tc_name+ final_bndrs+ real_res_kind+ roles+ (fmap unLoc cType)+ stupid_theta tc_rhs+ (VanillaAlgTyCon tc_rep_nm)+ gadt_syntax) }+ ; traceTc "tcDataDefn" (ppr tc_name $$ ppr tycon_binders $$ ppr extra_bndrs)+ ; return tycon }+ where+ -- In hs-boot, a 'data' declaration with no constructors+ -- indicates an nominally distinct abstract data type.+ mk_tc_rhs HsBootFile _ []+ = return AbstractTyCon++ mk_tc_rhs HsigFile _ [] -- ditto+ = return AbstractTyCon++ mk_tc_rhs _ tycon data_cons+ = case new_or_data of+ DataType -> return (mkDataTyConRhs data_cons)+ NewType -> ASSERT( not (null data_cons) )+ mkNewTyConRhs tc_name tycon (head data_cons)++{-+************************************************************************+* *+ Typechecking associated types (in class decls)+ (including the associated-type defaults)+* *+************************************************************************++Note [Associated type defaults]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++The following is an example of associated type defaults:+ class C a where+ data D a++ type F a b :: *+ type F a b = [a] -- Default++Note that we can get default definitions only for type families, not data+families.+-}++tcClassATs :: Name -- The class name (not knot-tied)+ -> Class -- The class parent of this associated type+ -> [LFamilyDecl Name] -- Associated types.+ -> [LTyFamDefltEqn Name] -- Associated type defaults.+ -> TcM [ClassATItem]+tcClassATs class_name cls ats at_defs+ = do { -- Complain about associated type defaults for non associated-types+ sequence_ [ failWithTc (badATErr class_name n)+ | n <- map at_def_tycon at_defs+ , not (n `elemNameSet` at_names) ]+ ; mapM tc_at ats }+ where+ at_def_tycon :: LTyFamDefltEqn Name -> Name+ at_def_tycon (L _ eqn) = unLoc (tfe_tycon eqn)++ at_fam_name :: LFamilyDecl Name -> Name+ at_fam_name (L _ decl) = unLoc (fdLName decl)++ at_names = mkNameSet (map at_fam_name ats)++ at_defs_map :: NameEnv [LTyFamDefltEqn Name]+ -- Maps an AT in 'ats' to a list of all its default defs in 'at_defs'+ at_defs_map = foldr (\at_def nenv -> extendNameEnv_C (++) nenv+ (at_def_tycon at_def) [at_def])+ emptyNameEnv at_defs++ tc_at at = do { fam_tc <- addLocM (tcFamDecl1 (Just cls)) at+ ; let at_defs = lookupNameEnv at_defs_map (at_fam_name at)+ `orElse` []+ ; atd <- tcDefaultAssocDecl fam_tc at_defs+ ; return (ATI fam_tc atd) }++-------------------------+tcDefaultAssocDecl :: TyCon -- ^ Family TyCon (not knot-tied)+ -> [LTyFamDefltEqn Name] -- ^ Defaults+ -> TcM (Maybe (Type, SrcSpan)) -- ^ Type checked RHS+tcDefaultAssocDecl _ []+ = return Nothing -- No default declaration++tcDefaultAssocDecl _ (d1:_:_)+ = failWithTc (text "More than one default declaration for"+ <+> ppr (tfe_tycon (unLoc d1)))++tcDefaultAssocDecl fam_tc [L loc (TyFamEqn { tfe_tycon = L _ tc_name+ , tfe_pats = hs_tvs+ , tfe_rhs = rhs })]+ | HsQTvs { hsq_implicit = imp_vars, hsq_explicit = exp_vars } <- hs_tvs+ = -- See Note [Type-checking default assoc decls]+ setSrcSpan loc $+ tcAddFamInstCtxt (text "default type instance") tc_name $+ do { traceTc "tcDefaultAssocDecl" (ppr tc_name)+ ; let shape@(fam_tc_name, fam_arity, _, _) = famTyConShape fam_tc++ -- Kind of family check+ ; ASSERT( fam_tc_name == tc_name )+ checkTc (isTypeFamilyTyCon fam_tc) (wrongKindOfFamily fam_tc)++ -- Arity check+ ; checkTc (length exp_vars == fam_arity)+ (wrongNumberOfParmsErr fam_arity)++ -- Typecheck RHS+ ; let pats = HsIB { hsib_vars = imp_vars ++ map hsLTyVarName exp_vars+ , hsib_body = map hsLTyVarBndrToType exp_vars+ , hsib_closed = False } -- this field is ignored, anyway+ -- NB: Use tcFamTyPats, not tcTyClTyVars. The latter expects to get+ -- the LHsQTyVars used for declaring a tycon, but the names here+ -- are different.+ ; (pats', rhs_ty)+ <- tcFamTyPats shape Nothing pats+ (discardResult . tcCheckLHsType rhs) $ \tvs pats rhs_kind ->+ do { rhs_ty <- solveEqualities $+ tcCheckLHsType rhs rhs_kind++ -- Zonk the patterns etc into the Type world+ ; (ze, _) <- zonkTyBndrsX emptyZonkEnv tvs+ ; pats' <- zonkTcTypeToTypes ze pats+ ; rhs_ty' <- zonkTcTypeToType ze rhs_ty+ ; return (pats', rhs_ty') }++ -- See Note [Type-checking default assoc decls]+ ; case tcMatchTys pats' (mkTyVarTys (tyConTyVars fam_tc)) of+ Just subst -> return (Just (substTyUnchecked subst rhs_ty, loc) )+ Nothing -> failWithTc (defaultAssocKindErr fam_tc)+ -- We check for well-formedness and validity later,+ -- in checkValidClass+ }++{- Note [Type-checking default assoc decls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this default declaration for an associated type++ class C a where+ type F (a :: k) b :: *+ type F x y = Proxy x -> y++Note that the class variable 'a' doesn't scope over the default assoc+decl (rather oddly I think), and (less oddly) neither does the second+argument 'b' of the associated type 'F', or the kind variable 'k'.+Instead, the default decl is treated more like a top-level type+instance.++However we store the default rhs (Proxy x -> y) in F's TyCon, using+F's own type variables, so we need to convert it to (Proxy a -> b).+We do this by calling tcMatchTys to match them up. This also ensures+that x's kind matches a's and similarly for y and b. The error+message isn't great, mind you. (Trac #11361 was caused by not doing a+proper tcMatchTys here.) -}++-------------------------+kcTyFamInstEqn :: FamTyConShape -> LTyFamInstEqn Name -> TcM ()+kcTyFamInstEqn fam_tc_shape@(fam_tc_name,_,_,_)+ (L loc (TyFamEqn { tfe_tycon = L _ eqn_tc_name+ , tfe_pats = pats+ , tfe_rhs = hs_ty }))+ = setSrcSpan loc $+ do { checkTc (fam_tc_name == eqn_tc_name)+ (wrongTyFamName fam_tc_name eqn_tc_name)+ ; discardResult $+ tc_fam_ty_pats fam_tc_shape Nothing -- not an associated type+ pats (discardResult . (tcCheckLHsType hs_ty)) }++tcTyFamInstEqn :: FamTyConShape -> Maybe ClsInstInfo -> LTyFamInstEqn Name -> TcM CoAxBranch+-- Needs to be here, not in TcInstDcls, because closed families+-- (typechecked here) have TyFamInstEqns+tcTyFamInstEqn fam_tc_shape@(fam_tc_name,_,_,_) mb_clsinfo+ (L loc (TyFamEqn { tfe_tycon = L _ eqn_tc_name+ , tfe_pats = pats+ , tfe_rhs = hs_ty }))+ = ASSERT( fam_tc_name == eqn_tc_name )+ setSrcSpan loc $+ tcFamTyPats fam_tc_shape mb_clsinfo pats+ (discardResult . (tcCheckLHsType hs_ty)) $+ \tvs pats res_kind ->+ do { rhs_ty <- solveEqualities $ tcCheckLHsType hs_ty res_kind++ ; (ze, tvs') <- zonkTyBndrsX emptyZonkEnv tvs+ ; pats' <- zonkTcTypeToTypes ze pats+ ; rhs_ty' <- zonkTcTypeToType ze rhs_ty+ ; traceTc "tcTyFamInstEqn" (ppr fam_tc_name <+> pprTyVars tvs')+ -- don't print out the pats here, as they might be zonked inside the knot+ ; return (mkCoAxBranch tvs' [] pats' rhs_ty'+ (map (const Nominal) tvs')+ loc) }++kcDataDefn :: Name -- ^ the family name, for error msgs only+ -> HsTyPats Name -- ^ the patterns, for error msgs only+ -> HsDataDefn Name -- ^ the RHS+ -> TcKind -- ^ the expected kind+ -> TcM ()+-- Used for 'data instance' only+-- Ordinary 'data' is handled by kcTyClDec+kcDataDefn fam_name (HsIB { hsib_body = pats })+ (HsDataDefn { dd_ctxt = ctxt, dd_cons = cons, dd_kindSig = mb_kind }) res_k+ = do { _ <- tcHsContext ctxt+ ; checkNoErrs $ mapM_ (wrapLocM kcConDecl) cons+ -- See Note [Failing early in kcDataDefn]+ ; discardResult $+ case mb_kind of+ Nothing -> unifyKind (Just hs_ty_pats) res_k liftedTypeKind+ Just k -> do { k' <- tcLHsKindSig k+ ; unifyKind (Just hs_ty_pats) res_k k' } }+ where+ hs_ty_pats = mkHsAppTys (noLoc $ HsTyVar NotPromoted (noLoc fam_name)) pats++{-+Kind check type patterns and kind annotate the embedded type variables.+ type instance F [a] = rhs++ * Here we check that a type instance matches its kind signature, but we do+ not check whether there is a pattern for each type index; the latter+ check is only required for type synonym instances.++Note [tc_fam_ty_pats vs tcFamTyPats]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+tc_fam_ty_pats does the type checking of the patterns, but it doesn't+zonk or generate any desugaring. It is used when kind-checking closed+type families.++tcFamTyPats type checks the patterns, zonks, and then calls thing_inside+to generate a desugaring. It is used during type-checking (not kind-checking).++Note [Type-checking type patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When typechecking the patterns of a family instance declaration, we can't+rely on using the family TyCon, because this is sometimes called+from within a type-checking knot. (Specifically for closed type families.)+The type FamTyConShape gives just enough information to do the job.++See also Note [tc_fam_ty_pats vs tcFamTyPats]++Note [Failing early in kcDataDefn]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to use checkNoErrs when calling kcConDecl. This is because kcConDecl+calls tcConDecl, which checks that the return type of a GADT-like constructor+is actually an instance of the type head. Without the checkNoErrs, potentially+two bad things could happen:++ 1) Duplicate error messages, because tcConDecl will be called again during+ *type* checking (as opposed to kind checking)+ 2) If we just keep blindly forging forward after both kind checking and type+ checking, we can get a panic in rejigConRes. See Trac #8368.+-}++-----------------+type FamTyConShape = (Name, Arity, [TyConBinder], Kind)+ -- See Note [Type-checking type patterns]++famTyConShape :: TyCon -> FamTyConShape+famTyConShape fam_tc+ = ( tyConName fam_tc+ , length $ filterOutInvisibleTyVars fam_tc (tyConTyVars fam_tc)+ , tyConBinders fam_tc+ , tyConResKind fam_tc )++tc_fam_ty_pats :: FamTyConShape+ -> Maybe ClsInstInfo+ -> HsTyPats Name -- Patterns+ -> (TcKind -> TcM ()) -- Kind checker for RHS+ -- result is ignored+ -> TcM ([Type], Kind)+-- Check the type patterns of a type or data family instance+-- type instance F <pat1> <pat2> = <type>+-- The 'tyvars' are the free type variables of pats+--+-- NB: The family instance declaration may be an associated one,+-- nested inside an instance decl, thus+-- instance C [a] where+-- type F [a] = ...+-- In that case, the type variable 'a' will *already be in scope*+-- (and, if C is poly-kinded, so will its kind parameter).++tc_fam_ty_pats (name, _, binders, res_kind) mb_clsinfo+ (HsIB { hsib_body = arg_pats, hsib_vars = tv_names })+ kind_checker+ = do { -- Kind-check and quantify+ -- See Note [Quantifying over family patterns]+ (_, (insted_res_kind, typats)) <- tcImplicitTKBndrs tv_names $+ do { (insting_subst, _leftover_binders, args, leftovers, n)+ <- tcInferArgs name binders (thdOf3 <$> mb_clsinfo) arg_pats+ ; case leftovers of+ hs_ty:_ -> addErrTc $ too_many_args hs_ty n+ _ -> return ()+ -- don't worry about leftover_binders; TcValidity catches them++ ; let insted_res_kind = substTyUnchecked insting_subst res_kind+ ; kind_checker insted_res_kind+ ; return ((insted_res_kind, args), emptyVarSet) }++ ; return (typats, insted_res_kind) }+ where+ too_many_args hs_ty n+ = hang (text "Too many parameters to" <+> ppr name <> colon)+ 2 (vcat [ ppr hs_ty <+> text "is unexpected;"+ , text (if n == 1 then "expected" else "expected only") <+>+ speakNOf (n-1) (text "parameter") ])++-- See Note [tc_fam_ty_pats vs tcFamTyPats]+tcFamTyPats :: FamTyConShape+ -> Maybe ClsInstInfo+ -> HsTyPats Name -- patterns+ -> (TcKind -> TcM ()) -- kind-checker for RHS+ -> ( [TcTyVar] -- Kind and type variables+ -> [TcType] -- Kind and type arguments+ -> TcKind+ -> TcM a) -- NB: You can use solveEqualities here.+ -> TcM a+tcFamTyPats fam_shape@(name,_,_,_) mb_clsinfo pats kind_checker thing_inside+ = do { (typats, res_kind)+ <- solveEqualities $ -- See Note [Constraints in patterns]+ tc_fam_ty_pats fam_shape mb_clsinfo pats kind_checker++ {- TODO (RAE): This should be cleverer. Consider this:++ type family F a++ data G a where+ MkG :: F a ~ Bool => G a++ type family Foo (x :: G a) :: F a+ type instance Foo MkG = False++ This should probably be accepted. Yet the solveEqualities+ will fail, unable to solve (F a ~ Bool)+ We want to quantify over that proof.+ But see Note [Constraints in patterns]+ below, which is missing this piece. -}+++ -- Find free variables (after zonking) and turn+ -- them into skolems, so that we don't subsequently+ -- replace a meta kind var with (Any *)+ -- Very like kindGeneralize+ ; vars <- zonkTcTypesAndSplitDepVars typats+ ; qtkvs <- quantifyZonkedTyVars emptyVarSet vars++ ; MASSERT( isEmptyVarSet $ coVarsOfTypes typats )+ -- This should be the case, because otherwise the solveEqualities+ -- above would fail. TODO (RAE): Update once the solveEqualities+ -- bit is cleverer.++ ; traceTc "tcFamTyPats" (ppr name $$ ppr typats $$ ppr qtkvs)+ -- Don't print out too much, as we might be in the knot++ ; tcExtendTyVarEnv qtkvs $+ -- Extend envt with TcTyVars not TyVars, because the+ -- kind checking etc done by thing_inside does not expect+ -- to encounter TyVars; it expects TcTyVars+ thing_inside qtkvs typats res_kind }++{-+Note [Constraints in patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+NB: This isn't the whole story. See comment in tcFamTyPats.++At first glance, it seems there is a complicated story to tell in tcFamTyPats+around constraint solving. After all, type family patterns can now do+GADT pattern-matching, which is jolly complicated. But, there's a key fact+which makes this all simple: everything is at top level! There cannot+be untouchable type variables. There can't be weird interaction between+case branches. There can't be global skolems.++This means that the semantics of type-level GADT matching is a little+different than term level. If we have++ data G a where+ MkGBool :: G Bool++And then++ type family F (a :: G k) :: k+ type instance F MkGBool = True++we get++ axF : F Bool (MkGBool <Bool>) ~ True++Simple! No casting on the RHS, because we can affect the kind parameter+to F.++If we ever introduce local type families, this all gets a lot more+complicated, and will end up looking awfully like term-level GADT+pattern-matching.+++** The new story **++Here is really what we want:++The matcher really can't deal with covars in arbitrary spots in coercions.+But it can deal with covars that are arguments to GADT data constructors.+So we somehow want to allow covars only in precisely those spots, then use+them as givens when checking the RHS. TODO (RAE): Implement plan.+++Note [Quantifying over family patterns]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to quantify over two different lots of kind variables:++First, the ones that come from the kinds of the tyvar args of+tcTyVarBndrsKindGen, as usual+ data family Dist a++ -- Proxy :: forall k. k -> *+ data instance Dist (Proxy a) = DP+ -- Generates data DistProxy = DP+ -- ax8 k (a::k) :: Dist * (Proxy k a) ~ DistProxy k a+ -- The 'k' comes from the tcTyVarBndrsKindGen (a::k)++Second, the ones that come from the kind argument of the type family+which we pick up using the (tyCoVarsOfTypes typats) in the result of+the thing_inside of tcHsTyvarBndrsGen.+ -- Any :: forall k. k+ data instance Dist Any = DA+ -- Generates data DistAny k = DA+ -- ax7 k :: Dist k (Any k) ~ DistAny k+ -- The 'k' comes from kindGeneralizeKinds (Any k)++Note [Quantified kind variables of a family pattern]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider type family KindFam (p :: k1) (q :: k1)+ data T :: Maybe k1 -> k2 -> *+ type instance KindFam (a :: Maybe k) b = T a b -> Int+The HsBSig for the family patterns will be ([k], [a])++Then in the family instance we want to+ * Bring into scope [ "k" -> k:*, "a" -> a:k ]+ * Kind-check the RHS+ * Quantify the type instance over k and k', as well as a,b, thus+ type instance [k, k', a:Maybe k, b:k']+ KindFam (Maybe k) k' a b = T k k' a b -> Int++Notice that in the third step we quantify over all the visibly-mentioned+type variables (a,b), but also over the implicitly mentioned kind variables+(k, k'). In this case one is bound explicitly but often there will be+none. The role of the kind signature (a :: Maybe k) is to add a constraint+that 'a' must have that kind, and to bring 'k' into scope.++++************************************************************************+* *+ Data types+* *+************************************************************************+-}++dataDeclChecks :: Name -> NewOrData -> ThetaType -> [LConDecl Name] -> TcM Bool+dataDeclChecks tc_name new_or_data stupid_theta cons+ = do { -- Check that we don't use GADT syntax in H98 world+ gadtSyntax_ok <- xoptM LangExt.GADTSyntax+ ; let gadt_syntax = consUseGadtSyntax cons+ ; checkTc (gadtSyntax_ok || not gadt_syntax) (badGadtDecl tc_name)++ -- Check that the stupid theta is empty for a GADT-style declaration+ ; checkTc (null stupid_theta || not gadt_syntax) (badStupidTheta tc_name)++ -- Check that a newtype has exactly one constructor+ -- Do this before checking for empty data decls, so that+ -- we don't suggest -XEmptyDataDecls for newtypes+ ; checkTc (new_or_data == DataType || isSingleton cons)+ (newtypeConError tc_name (length cons))++ -- Check that there's at least one condecl,+ -- or else we're reading an hs-boot file, or -XEmptyDataDecls+ ; empty_data_decls <- xoptM LangExt.EmptyDataDecls+ ; is_boot <- tcIsHsBootOrSig -- Are we compiling an hs-boot file?+ ; checkTc (not (null cons) || empty_data_decls || is_boot)+ (emptyConDeclsErr tc_name)+ ; return gadt_syntax }+++-----------------------------------+consUseGadtSyntax :: [LConDecl a] -> Bool+consUseGadtSyntax (L _ (ConDeclGADT { }) : _) = True+consUseGadtSyntax _ = False+ -- All constructors have same shape++-----------------------------------+tcConDecls :: TyCon -> ([TyConBinder], Type)+ -> [LConDecl Name] -> TcM [DataCon]+ -- Why both the tycon tyvars and binders? Because the tyvars+ -- have all the names and the binders have the visibilities.+tcConDecls rep_tycon (tmpl_bndrs, res_tmpl)+ = concatMapM $ addLocM $+ tcConDecl rep_tycon tmpl_bndrs res_tmpl++tcConDecl :: TyCon -- Representation tycon. Knot-tied!+ -> [TyConBinder] -> Type+ -- Return type template (with its template tyvars)+ -- (tvs, T tys), where T is the family TyCon+ -> ConDecl Name+ -> TcM [DataCon]++tcConDecl rep_tycon tmpl_bndrs res_tmpl+ (ConDeclH98 { con_name = name+ , con_qvars = hs_qvars, con_cxt = hs_ctxt+ , con_details = hs_details })+ = addErrCtxt (dataConCtxtName [name]) $+ do { traceTc "tcConDecl 1" (ppr name)+ ; let (hs_kvs, hs_tvs) = case hs_qvars of+ Nothing -> ([], [])+ Just (HsQTvs { hsq_implicit = kvs, hsq_explicit = tvs })+ -> (kvs, tvs)+ ; (imp_tvs, (exp_tvs, ctxt, arg_tys, field_lbls, stricts))+ <- solveEqualities $+ tcImplicitTKBndrs hs_kvs $+ tcExplicitTKBndrs hs_tvs $ \ exp_tvs ->+ do { traceTc "tcConDecl" (ppr name <+> text "tvs:" <+> ppr hs_tvs)+ ; ctxt <- tcHsContext (fromMaybe (noLoc []) hs_ctxt)+ ; btys <- tcConArgs hs_details+ ; field_lbls <- lookupConstructorFields (unLoc name)+ ; let (arg_tys, stricts) = unzip btys+ bound_vars = allBoundVariabless ctxt `unionVarSet`+ allBoundVariabless arg_tys+ ; return ((exp_tvs, ctxt, arg_tys, field_lbls, stricts), bound_vars)+ }+ -- imp_tvs are user-written kind variables, without an explicit binding site+ -- exp_tvs have binding sites+ -- the kvs below are those kind variables entirely unmentioned by the user+ -- and discovered only by generalization++ -- Kind generalisation+ ; let all_user_tvs = imp_tvs ++ exp_tvs+ ; vars <- zonkTcTypeAndSplitDepVars (mkSpecForAllTys all_user_tvs $+ mkFunTys ctxt $+ mkFunTys arg_tys $+ unitTy)+ -- That type is a lie, of course. (It shouldn't end in ()!)+ -- And we could construct a proper result type from the info+ -- at hand. But the result would mention only the tmpl_tvs,+ -- and so it just creates more work to do it right. Really,+ -- we're doing this to get the right behavior around removing+ -- any vars bound in exp_binders.++ ; kvs <- quantifyZonkedTyVars (mkVarSet (binderVars tmpl_bndrs)) vars++ -- Zonk to Types+ ; (ze, qkvs) <- zonkTyBndrsX emptyZonkEnv kvs+ ; (ze, user_qtvs) <- zonkTyBndrsX ze all_user_tvs+ ; arg_tys <- zonkTcTypeToTypes ze arg_tys+ ; ctxt <- zonkTcTypeToTypes ze ctxt++ ; fam_envs <- tcGetFamInstEnvs++ -- Can't print univ_tvs, arg_tys etc, because we are inside the knot here+ ; traceTc "tcConDecl 2" (ppr name $$ ppr field_lbls)+ ; let+ ex_tvs = mkTyVarBinders Inferred qkvs +++ mkTyVarBinders Specified user_qtvs+ buildOneDataCon (L _ name) = do+ { is_infix <- tcConIsInfixH98 name hs_details+ ; rep_nm <- newTyConRepName name++ ; buildDataCon fam_envs name is_infix rep_nm+ stricts Nothing field_lbls+ (mkDataConUnivTyVarBinders tmpl_bndrs)+ ex_tvs+ [{- no eq_preds -}] ctxt arg_tys+ res_tmpl rep_tycon+ -- NB: we put data_tc, the type constructor gotten from the+ -- constructor type signature into the data constructor;+ -- that way checkValidDataCon can complain if it's wrong.+ }+ ; traceTc "tcConDecl 2" (ppr name)+ ; mapM buildOneDataCon [name]+ }++tcConDecl rep_tycon tmpl_bndrs res_tmpl+ (ConDeclGADT { con_names = names, con_type = ty })+ = addErrCtxt (dataConCtxtName names) $+ do { traceTc "tcConDecl 1" (ppr names)+ ; (user_tvs, ctxt, stricts, field_lbls, arg_tys, res_ty,hs_details)+ <- tcGadtSigType (ppr names) (unLoc $ head names) ty++ ; vars <- zonkTcTypeAndSplitDepVars (mkSpecForAllTys user_tvs $+ mkFunTys ctxt $+ mkFunTys arg_tys $+ res_ty)+ ; tkvs <- quantifyZonkedTyVars emptyVarSet vars++ -- Zonk to Types+ ; (ze, qtkvs) <- zonkTyBndrsX emptyZonkEnv (tkvs ++ user_tvs)+ ; arg_tys <- zonkTcTypeToTypes ze arg_tys+ ; ctxt <- zonkTcTypeToTypes ze ctxt+ ; res_ty <- zonkTcTypeToType ze res_ty++ ; let (univ_tvs, ex_tvs, eq_preds, res_ty', arg_subst)+ = rejigConRes tmpl_bndrs res_tmpl qtkvs res_ty+ -- NB: this is a /lazy/ binding, so we pass five thunks to buildDataCon+ -- without yet forcing the guards in rejigConRes+ -- See Note [Checking GADT return types]++ -- See Note [Wrong visibility for GADTs]+ univ_bndrs = mkTyVarBinders Specified univ_tvs+ ex_bndrs = mkTyVarBinders Specified ex_tvs++ ; fam_envs <- tcGetFamInstEnvs++ -- Can't print univ_tvs, arg_tys etc, because we are inside the knot here+ ; traceTc "tcConDecl 2" (ppr names $$ ppr field_lbls)+ ; let+ buildOneDataCon (L _ name) = do+ { is_infix <- tcConIsInfixGADT name hs_details+ ; rep_nm <- newTyConRepName name++ ; buildDataCon fam_envs name is_infix+ rep_nm+ stricts Nothing field_lbls+ univ_bndrs ex_bndrs eq_preds+ (substTys arg_subst ctxt)+ (substTys arg_subst arg_tys)+ (substTy arg_subst res_ty')+ rep_tycon+ -- NB: we put data_tc, the type constructor gotten from the+ -- constructor type signature into the data constructor;+ -- that way checkValidDataCon can complain if it's wrong.+ }+ ; traceTc "tcConDecl 2" (ppr names)+ ; mapM buildOneDataCon names+ }+++tcGadtSigType :: SDoc -> Name -> LHsSigType Name+ -> TcM ( [TcTyVar], [PredType],[HsSrcBang], [FieldLabel], [Type], Type+ , HsConDetails (LHsType Name)+ (Located [LConDeclField Name]) )+tcGadtSigType doc name ty@(HsIB { hsib_vars = vars })+ = do { let (hs_details', res_ty', cxt, gtvs) = gadtDeclDetails ty+ ; (hs_details, res_ty) <- updateGadtResult failWithTc doc hs_details' res_ty'+ ; (imp_tvs, (exp_tvs, ctxt, arg_tys, res_ty, field_lbls, stricts))+ <- solveEqualities $+ tcImplicitTKBndrs vars $+ tcExplicitTKBndrs gtvs $ \ exp_tvs ->+ do { ctxt <- tcHsContext cxt+ ; btys <- tcConArgs hs_details+ ; ty' <- tcHsLiftedType res_ty+ ; field_lbls <- lookupConstructorFields name+ ; let (arg_tys, stricts) = unzip btys+ bound_vars = allBoundVariabless ctxt `unionVarSet`+ allBoundVariabless arg_tys++ ; return ((exp_tvs, ctxt, arg_tys, ty', field_lbls, stricts), bound_vars)+ }+ ; return (imp_tvs ++ exp_tvs, ctxt, stricts, field_lbls, arg_tys, res_ty, hs_details)+ }++tcConIsInfixH98 :: Name+ -> HsConDetails (LHsType Name) (Located [LConDeclField Name])+ -> TcM Bool+tcConIsInfixH98 _ details+ = case details of+ InfixCon {} -> return True+ _ -> return False++tcConIsInfixGADT :: Name+ -> HsConDetails (LHsType Name) (Located [LConDeclField Name])+ -> TcM Bool+tcConIsInfixGADT con details+ = case details of+ InfixCon {} -> return True+ RecCon {} -> return False+ PrefixCon arg_tys -- See Note [Infix GADT constructors]+ | isSymOcc (getOccName con)+ , [_ty1,_ty2] <- arg_tys+ -> do { fix_env <- getFixityEnv+ ; return (con `elemNameEnv` fix_env) }+ | otherwise -> return False++tcConArgs :: HsConDeclDetails Name+ -> TcM [(TcType, HsSrcBang)]+tcConArgs (PrefixCon btys)+ = mapM tcConArg btys+tcConArgs (InfixCon bty1 bty2)+ = do { bty1' <- tcConArg bty1+ ; bty2' <- tcConArg bty2+ ; return [bty1', bty2'] }+tcConArgs (RecCon fields)+ = mapM tcConArg btys+ where+ -- We need a one-to-one mapping from field_names to btys+ combined = map (\(L _ f) -> (cd_fld_names f,cd_fld_type f)) (unLoc fields)+ explode (ns,ty) = zip ns (repeat ty)+ exploded = concatMap explode combined+ (_,btys) = unzip exploded+++tcConArg :: LHsType Name -> TcM (TcType, HsSrcBang)+tcConArg bty+ = do { traceTc "tcConArg 1" (ppr bty)+ ; arg_ty <- tcHsOpenType (getBangType bty)+ -- Newtypes can't have unboxed types, but we check+ -- that in checkValidDataCon; this tcConArg stuff+ -- doesn't happen for GADT-style declarations+ ; traceTc "tcConArg 2" (ppr bty)+ ; return (arg_ty, getBangStrictness bty) }++{-+Note [Wrong visibility for GADTs]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GADT tyvars shouldn't all be specified, but it's hard to do much better, as+described in #11721, which is duplicated here for convenience:++Consider++ data X a where+ MkX :: b -> Proxy a -> X a++According to the rules around specified vs. generalized variables around+TypeApplications, the type of MkX should be++ MkX :: forall {k} (b :: *) (a :: k). b -> Proxy a -> X a++A few things to note:++ * The k isn't available for TypeApplications (that's why it's in braces),+ because it is not user-written.++ * The b is quantified before the a, because b comes before a in the+ user-written type signature for MkX.++Both of these bullets are currently violated. GHCi reports MkX's type as++ MkX :: forall k (a :: k) b. b -> Proxy a -> X a++It turns out that this is a hard to fix. The problem is that GHC expects data+constructors to have their universal variables followed by their existential+variables, always. And yet that's violated in the desired type for MkX.+Furthermore, given the way that GHC deals with GADT return types ("rejigging",+in technical parlance), it's inconvenient to get the specified/generalized+distinction correct.++Given time constraints, I'm afraid fixing this all won't make it for 8.0.++Happily, there is are easy-to-articulate rules governing GHC's current (wrong)+behavior. In a GADT-syntax data constructor:++ * All kind and type variables are considered specified and available for+ visible type application.++ * Universal variables always come first, in precisely the order they appear+ in the tycon. Note that universals that are constrained by a GADT return+ type are missing from the datacon.++ * Existential variables come next. Their order is determined by a+ user-written forall; or, if there is none, by taking the left-to-right+ order in the datacon's type and doing a stable topological sort. (This+ stable topological sort step is the same as for other user-written type+ signatures.)++Note [Infix GADT constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We do not currently have syntax to declare an infix constructor in GADT syntax,+but it makes a (small) difference to the Show instance. So as a slightly+ad-hoc solution, we regard a GADT data constructor as infix if+ a) it is an operator symbol+ b) it has two arguments+ c) there is a fixity declaration for it+For example:+ infix 6 (:--:)+ data T a where+ (:--:) :: t1 -> t2 -> T Int+++Note [Checking GADT return types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There is a delicacy around checking the return types of a datacon. The+central problem is dealing with a declaration like++ data T a where+ MkT :: T a -> Q a++Note that the return type of MkT is totally bogus. When creating the T+tycon, we also need to create the MkT datacon, which must have a "rejigged"+return type. That is, the MkT datacon's type must be transformed to have+a uniform return type with explicit coercions for GADT-like type parameters.+This rejigging is what rejigConRes does. The problem is, though, that checking+that the return type is appropriate is much easier when done over *Type*,+not *HsType*, and doing a call to tcMatchTy will loop because T isn't fully+defined yet.++So, we want to make rejigConRes lazy and then check the validity of+the return type in checkValidDataCon. To do this we /always/ return a+5-tuple from rejigConRes (so that we can extract ret_ty from it, which+checkValidDataCon needs), but the first four fields may be bogus if+the return type isn't valid (the last equation for rejigConRes).++This is better than an earlier solution which reduced the number of+errors reported in one pass. See Trac #7175, and #10836.+-}++-- Example+-- data instance T (b,c) where+-- TI :: forall e. e -> T (e,e)+--+-- The representation tycon looks like this:+-- data :R7T b c where+-- TI :: forall b1 c1. (b1 ~ c1) => b1 -> :R7T b1 c1+-- In this case orig_res_ty = T (e,e)++rejigConRes :: [TyConBinder] -> Type -- Template for result type; e.g.+ -- data instance T [a] b c = ...+ -- gives template ([a,b,c], T [a] b c)+ -- Type must be of kind *!+ -> [TyVar] -- where MkT :: forall x y z. ...+ -> Type -- res_ty type must be of kind *+ -> ([TyVar], -- Universal+ [TyVar], -- Existential (distinct OccNames from univs)+ [EqSpec], -- Equality predicates+ Type, -- Typechecked return type+ TCvSubst) -- Substitution to apply to argument types+ -- We don't check that the TyCon given in the ResTy is+ -- the same as the parent tycon, because checkValidDataCon will do it++rejigConRes tmpl_bndrs res_tmpl dc_tvs res_ty+ -- E.g. data T [a] b c where+ -- MkT :: forall x y z. T [(x,y)] z z+ -- The {a,b,c} are the tmpl_tvs, and the {x,y,z} are the dc_tvs+ -- (NB: unlike the H98 case, the dc_tvs are not all existential)+ -- Then we generate+ -- Univ tyvars Eq-spec+ -- a a~(x,y)+ -- b b~z+ -- z+ -- Existentials are the leftover type vars: [x,y]+ -- So we return ([a,b,z], [x,y], [a~(x,y),b~z], T [(x,y)] z z)+ | Just subst <- ASSERT( isLiftedTypeKind (typeKind res_ty) )+ ASSERT( isLiftedTypeKind (typeKind res_tmpl) )+ tcMatchTy res_tmpl res_ty+ = let (univ_tvs, raw_eqs, kind_subst) = mkGADTVars tmpl_tvs dc_tvs subst+ raw_ex_tvs = dc_tvs `minusList` univ_tvs+ (arg_subst, substed_ex_tvs)+ = mapAccumL substTyVarBndr kind_subst raw_ex_tvs++ substed_eqs = map (substEqSpec arg_subst) raw_eqs+ in+ (univ_tvs, substed_ex_tvs, substed_eqs, res_ty, arg_subst)++ | otherwise+ -- If the return type of the data constructor doesn't match the parent+ -- type constructor, or the arity is wrong, the tcMatchTy will fail+ -- e.g data T a b where+ -- T1 :: Maybe a -- Wrong tycon+ -- T2 :: T [a] -- Wrong arity+ -- We are detect that later, in checkValidDataCon, but meanwhile+ -- we must do *something*, not just crash. So we do something simple+ -- albeit bogus, relying on checkValidDataCon to check the+ -- bad-result-type error before seeing that the other fields look odd+ -- See Note [Checking GADT return types]+ = (tmpl_tvs, dc_tvs `minusList` tmpl_tvs, [], res_ty, emptyTCvSubst)+ where+ tmpl_tvs = binderVars tmpl_bndrs++{-+Note [mkGADTVars]+~~~~~~~~~~~~~~~~~++Running example:++data T (k1 :: *) (k2 :: *) (a :: k2) (b :: k2) where+ MkT :: T x1 * (Proxy (y :: x1), z) z++We need the rejigged type to be++ MkT :: forall (x1 :: *) (k2 :: *) (a :: k2) (b :: k2).+ forall (y :: x1) (z :: *).+ (k2 ~ *, a ~ (Proxy x1 y, z), b ~ z)+ => T x1 k2 a b++You might naively expect that z should become a universal tyvar,+not an existential. (After all, x1 becomes a universal tyvar.)+The problem is that the universal tyvars must have exactly the+same kinds as the tyConTyVars. z has kind * while b has kind k2.+So we need an existential tyvar and a heterogeneous equality+constraint. (The b ~ z is a bit redundant with the k2 ~ * that+comes before in that b ~ z implies k2 ~ *. I'm sure we could do+some analysis that could eliminate k2 ~ *. But we don't do this+yet.)++The HsTypes have already been desugared to proper Types:++ T x1 * (Proxy (y :: x1), z) z+becomes+ [x1 :: *, y :: x1, z :: *]. T x1 * (Proxy x1 y, z) z++We start off by matching (T k1 k2 a b) with (T x1 * (Proxy x1 y, z) z). We+know this match will succeed because of the validity check (actually done+later, but laziness saves us -- see Note [Checking GADT return types]).+Thus, we get++ subst := { k1 |-> x1, k2 |-> *, a |-> (Proxy x1 y, z), b |-> z }++Now, we need to figure out what the GADT equalities should be. In this case,+we *don't* want (k1 ~ x1) to be a GADT equality: it should just be a+renaming. The others should be GADT equalities. We also need to make+sure that the universally-quantified variables of the datacon match up+with the tyvars of the tycon, as required for Core context well-formedness.+(This last bit is why we have to rejig at all!)++`choose` walks down the tycon tyvars, figuring out what to do with each one.+It carries two substitutions:+ - t_sub's domain is *template* or *tycon* tyvars, mapping them to variables+ mentioned in the datacon signature.+ - r_sub's domain is *result* tyvars, names written by the programmer in+ the datacon signature. The final rejigged type will use these names, but+ the subst is still needed because sometimes the printed name of these variables+ is different. (See choose_tv_name, below.)++Before explaining the details of `choose`, let's just look at its operation+on our example:++ choose [] [] {} {} [k1, k2, a, b]+ --> -- first branch of `case` statement+ choose+ univs: [x1 :: *]+ eq_spec: []+ t_sub: {k1 |-> x1}+ r_sub: {x1 |-> x1}+ t_tvs: [k2, a, b]+ --> -- second branch of `case` statement+ choose+ univs: [k2 :: *, x1 :: *]+ eq_spec: [k2 ~ *]+ t_sub: {k1 |-> x1, k2 |-> k2}+ r_sub: {x1 |-> x1}+ t_tvs: [a, b]+ --> -- second branch of `case` statement+ choose+ univs: [a :: k2, k2 :: *, x1 :: *]+ eq_spec: [ a ~ (Proxy x1 y, z)+ , k2 ~ * ]+ t_sub: {k1 |-> x1, k2 |-> k2, a |-> a}+ r_sub: {x1 |-> x1}+ t_tvs: [b]+ --> -- second branch of `case` statement+ choose+ univs: [b :: k2, a :: k2, k2 :: *, x1 :: *]+ eq_spec: [ b ~ z+ , a ~ (Proxy x1 y, z)+ , k2 ~ * ]+ t_sub: {k1 |-> x1, k2 |-> k2, a |-> a, b |-> z}+ r_sub: {x1 |-> x1}+ t_tvs: []+ --> -- end of recursion+ ( [x1 :: *, k2 :: *, a :: k2, b :: k2]+ , [k2 ~ *, a ~ (Proxy x1 y, z), b ~ z]+ , {x1 |-> x1} )++`choose` looks up each tycon tyvar in the matching (it *must* be matched!). If+it finds a bare result tyvar (the first branch of the `case` statement), it+checks to make sure that the result tyvar isn't yet in the list of univ_tvs.+If it is in that list, then we have a repeated variable in the return type,+and we in fact need a GADT equality. We then check to make sure that the+kind of the result tyvar matches the kind of the template tyvar. This+check is what forces `z` to be existential, as it should be, explained above.+Assuming no repeated variables or kind-changing, we wish+to use the variable name given in the datacon signature (that is, `x1` not+`k1`), not the tycon signature (which may have been made up by+GHC). So, we add a mapping from the tycon tyvar to the result tyvar to t_sub.++If we discover that a mapping in `subst` gives us a non-tyvar (the second+branch of the `case` statement), then we have a GADT equality to create.+We create a fresh equality, but we don't extend any substitutions. The+template variable substitution is meant for use in universal tyvar kinds,+and these shouldn't be affected by any GADT equalities.++This whole algorithm is quite delicate, indeed. I (Richard E.) see two ways+of simplifying it:++1) The first branch of the `case` statement is really an optimization, used+in order to get fewer GADT equalities. It might be possible to make a GADT+equality for *every* univ. tyvar, even if the equality is trivial, and then+either deal with the bigger type or somehow reduce it later.++2) This algorithm strives to use the names for type variables as specified+by the user in the datacon signature. If we always used the tycon tyvar+names, for example, this would be simplified. This change would almost+certainly degrade error messages a bit, though.+-}++-- ^ From information about a source datacon definition, extract out+-- what the universal variables and the GADT equalities should be.+-- See Note [mkGADTVars].+mkGADTVars :: [TyVar] -- ^ The tycon vars+ -> [TyVar] -- ^ The datacon vars+ -> TCvSubst -- ^ The matching between the template result type+ -- and the actual result type+ -> ( [TyVar]+ , [EqSpec]+ , TCvSubst ) -- ^ The univ. variables, the GADT equalities,+ -- and a subst to apply to the GADT equalities+ -- and existentials.+mkGADTVars tmpl_tvs dc_tvs subst+ = choose [] [] empty_subst empty_subst tmpl_tvs+ where+ in_scope = mkInScopeSet (mkVarSet tmpl_tvs `unionVarSet` mkVarSet dc_tvs)+ `unionInScope` getTCvInScope subst+ empty_subst = mkEmptyTCvSubst in_scope++ choose :: [TyVar] -- accumulator of univ tvs, reversed+ -> [EqSpec] -- accumulator of GADT equalities, reversed+ -> TCvSubst -- template substitution+ -> TCvSubst -- res. substitution+ -> [TyVar] -- template tvs (the univ tvs passed in)+ -> ( [TyVar] -- the univ_tvs+ , [EqSpec] -- GADT equalities+ , TCvSubst ) -- a substitution to fix kinds in ex_tvs++ choose univs eqs _t_sub r_sub []+ = (reverse univs, reverse eqs, r_sub)+ choose univs eqs t_sub r_sub (t_tv:t_tvs)+ | Just r_ty <- lookupTyVar subst t_tv+ = case getTyVar_maybe r_ty of+ Just r_tv+ | not (r_tv `elem` univs)+ , tyVarKind r_tv `eqType` (substTy t_sub (tyVarKind t_tv))+ -> -- simple, well-kinded variable substitution.+ choose (r_tv:univs) eqs+ (extendTvSubst t_sub t_tv r_ty')+ (extendTvSubst r_sub r_tv r_ty')+ t_tvs+ where+ r_tv1 = setTyVarName r_tv (choose_tv_name r_tv t_tv)+ r_ty' = mkTyVarTy r_tv1++ -- not a simple substitution. make an equality predicate+ _ -> choose (t_tv':univs) (mkEqSpec t_tv' r_ty : eqs)+ t_sub r_sub t_tvs+ where t_tv' = updateTyVarKind (substTy t_sub) t_tv++ | otherwise+ = pprPanic "mkGADTVars" (ppr tmpl_tvs $$ ppr subst)++ -- choose an appropriate name for a univ tyvar.+ -- This *must* preserve the Unique of the result tv, so that we+ -- can detect repeated variables. It prefers user-specified names+ -- over system names. A result variable with a system name can+ -- happen with GHC-generated implicit kind variables.+ choose_tv_name :: TyVar -> TyVar -> Name+ choose_tv_name r_tv t_tv+ | isSystemName r_tv_name+ = setNameUnique t_tv_name (getUnique r_tv_name)++ | otherwise+ = r_tv_name++ where+ r_tv_name = getName r_tv+ t_tv_name = getName t_tv++{-+Note [Substitution in template variables kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++data G (a :: Maybe k) where+ MkG :: G Nothing++With explicit kind variables++data G k (a :: Maybe k) where+ MkG :: G k1 (Nothing k1)++Note how k1 is distinct from k. So, when we match the template+`G k a` against `G k1 (Nothing k1)`, we get a subst+[ k |-> k1, a |-> Nothing k1 ]. Even though this subst has two+mappings, we surely don't want to add (k, k1) to the list of+GADT equalities -- that would be overly complex and would create+more untouchable variables than we need. So, when figuring out+which tyvars are GADT-like and which aren't (the fundamental+job of `choose`), we want to treat `k` as *not* GADT-like.+Instead, we wish to substitute in `a`'s kind, to get (a :: Maybe k1)+instead of (a :: Maybe k). This is the reason for dealing+with a substitution in here.++However, we do not *always* want to substitute. Consider++data H (a :: k) where+ MkH :: H Int++With explicit kind variables:++data H k (a :: k) where+ MkH :: H * Int++Here, we have a kind-indexed GADT. The subst in question is+[ k |-> *, a |-> Int ]. Now, we *don't* want to substitute in `a`'s+kind, because that would give a constructor with the type++MkH :: forall (k :: *) (a :: *). (k ~ *) -> (a ~ Int) -> H k a++The problem here is that a's kind is wrong -- it needs to be k, not *!+So, if the matching for a variable is anything but another bare variable,+we drop the mapping from the substitution before proceeding. This+was not an issue before kind-indexed GADTs because this case could+never happen.++************************************************************************+* *+ Validity checking+* *+************************************************************************++Validity checking is done once the mutually-recursive knot has been+tied, so we can look at things freely.+-}++checkValidTyCl :: TyCon -> TcM TyCon+checkValidTyCl tc+ = setSrcSpan (getSrcSpan tc) $+ addTyConCtxt tc $+ recoverM recovery_code+ (do { traceTc "Starting validity for tycon" (ppr tc)+ ; checkValidTyCon tc+ ; traceTc "Done validity for tycon" (ppr tc)+ ; return tc })+ where+ recovery_code -- See Note [Recover from validity error]+ = do { traceTc "Aborted validity for tycon" (ppr tc)+ ; return fake_tc }+ fake_tc | isFamilyTyCon tc || isTypeSynonymTyCon tc+ = makeRecoveryTyCon tc+ | otherwise+ = tc++{- Note [Recover from validity error]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We recover from a validity error in a type or class, which allows us+to report multiple validity errors. In the failure case we return a+TyCon of the right kind, but with no interesting behaviour+(makeRecoveryTyCon). Why? Suppose we have+ type T a = Fun+where Fun is a type family of arity 1. The RHS is invalid, but we+want to go on checking validity of subsequent type declarations.+So we replace T with an abstract TyCon which will do no harm.+See indexed-types/should_fail/BadSock and Trac #10896++Painfully, though, we *don't* want to do this for classes.+Consider tcfail041:+ class (?x::Int) => C a where ...+ instance C Int+The class is invalid because of the superclass constraint. But+we still want it to look like a /class/, else the instance bleats+that the instance is mal-formed because it hasn't got a class in+the head.+-}++-------------------------+-- For data types declared with record syntax, we require+-- that each constructor that has a field 'f'+-- (a) has the same result type+-- (b) has the same type for 'f'+-- module alpha conversion of the quantified type variables+-- of the constructor.+--+-- Note that we allow existentials to match because the+-- fields can never meet. E.g+-- data T where+-- T1 { f1 :: b, f2 :: a, f3 ::Int } :: T+-- T2 { f1 :: c, f2 :: c, f3 ::Int } :: T+-- Here we do not complain about f1,f2 because they are existential++checkValidTyCon :: TyCon -> TcM ()+checkValidTyCon tc+ | isPrimTyCon tc -- Happens when Haddock'ing GHC.Prim+ = return ()++ | otherwise+ = do { traceTc "checkValidTyCon" (ppr tc $$ ppr (tyConClass_maybe tc))+ ; checkValidTyConTyVars tc+ ; if | Just cl <- tyConClass_maybe tc+ -> checkValidClass cl++ | Just syn_rhs <- synTyConRhs_maybe tc+ -> do { checkValidType syn_ctxt syn_rhs+ ; checkTySynRhs syn_ctxt syn_rhs }++ | Just fam_flav <- famTyConFlav_maybe tc+ -> case fam_flav of+ { ClosedSynFamilyTyCon (Just ax)+ -> tcAddClosedTypeFamilyDeclCtxt tc $+ checkValidCoAxiom ax+ ; ClosedSynFamilyTyCon Nothing -> return ()+ ; AbstractClosedSynFamilyTyCon ->+ do { hsBoot <- tcIsHsBootOrSig+ ; checkTc hsBoot $+ text "You may define an abstract closed type family" $$+ text "only in a .hs-boot file" }+ ; DataFamilyTyCon {} -> return ()+ ; OpenSynFamilyTyCon -> return ()+ ; BuiltInSynFamTyCon _ -> return () }++ | otherwise -> do+ { -- Check the context on the data decl+ traceTc "cvtc1" (ppr tc)+ ; checkValidTheta (DataTyCtxt name) (tyConStupidTheta tc)++ ; traceTc "cvtc2" (ppr tc)++ ; dflags <- getDynFlags+ ; existential_ok <- xoptM LangExt.ExistentialQuantification+ ; gadt_ok <- xoptM LangExt.GADTs+ ; let ex_ok = existential_ok || gadt_ok+ -- Data cons can have existential context+ ; mapM_ (checkValidDataCon dflags ex_ok tc) data_cons++ -- Check that fields with the same name share a type+ ; mapM_ check_fields groups }}+ where+ syn_ctxt = TySynCtxt name+ name = tyConName tc+ data_cons = tyConDataCons tc++ groups = equivClasses cmp_fld (concatMap get_fields data_cons)+ cmp_fld (f1,_) (f2,_) = flLabel f1 `compare` flLabel f2+ get_fields con = dataConFieldLabels con `zip` repeat con+ -- dataConFieldLabels may return the empty list, which is fine++ -- See Note [GADT record selectors] in TcTyDecls+ -- We must check (a) that the named field has the same+ -- type in each constructor+ -- (b) that those constructors have the same result type+ --+ -- However, the constructors may have differently named type variable+ -- and (worse) we don't know how the correspond to each other. E.g.+ -- C1 :: forall a b. { f :: a, g :: b } -> T a b+ -- C2 :: forall d c. { f :: c, g :: c } -> T c d+ --+ -- So what we do is to ust Unify.tcMatchTys to compare the first candidate's+ -- result type against other candidates' types BOTH WAYS ROUND.+ -- If they magically agrees, take the substitution and+ -- apply them to the latter ones, and see if they match perfectly.+ check_fields ((label, con1) : other_fields)+ -- These fields all have the same name, but are from+ -- different constructors in the data type+ = recoverM (return ()) $ mapM_ checkOne other_fields+ -- Check that all the fields in the group have the same type+ -- NB: this check assumes that all the constructors of a given+ -- data type use the same type variables+ where+ (_, _, _, res1) = dataConSig con1+ fty1 = dataConFieldType con1 lbl+ lbl = flLabel label++ checkOne (_, con2) -- Do it bothways to ensure they are structurally identical+ = do { checkFieldCompat lbl con1 con2 res1 res2 fty1 fty2+ ; checkFieldCompat lbl con2 con1 res2 res1 fty2 fty1 }+ where+ (_, _, _, res2) = dataConSig con2+ fty2 = dataConFieldType con2 lbl+ check_fields [] = panic "checkValidTyCon/check_fields []"++checkFieldCompat :: FieldLabelString -> DataCon -> DataCon+ -> Type -> Type -> Type -> Type -> TcM ()+checkFieldCompat fld con1 con2 res1 res2 fty1 fty2+ = do { checkTc (isJust mb_subst1) (resultTypeMisMatch fld con1 con2)+ ; checkTc (isJust mb_subst2) (fieldTypeMisMatch fld con1 con2) }+ where+ mb_subst1 = tcMatchTy res1 res2+ mb_subst2 = tcMatchTyX (expectJust "checkFieldCompat" mb_subst1) fty1 fty2++-------------------------------+-- | Check for ill-scoped telescopes in a tycon.+-- For example:+--+-- > data SameKind :: k -> k -> * -- this is OK+-- > data Bad a (c :: Proxy b) (d :: Proxy a) (x :: SameKind b d)+--+-- The problem is that @b@ should be bound (implicitly) at the beginning,+-- but its kind mentions @a@, which is not yet in scope. Kind generalization+-- makes a mess of this, and ends up including @a@ twice in the final+-- tyvars. So this function checks for duplicates and, if there are any,+-- produces the appropriate error message.+checkValidTyConTyVars :: TyCon -> TcM ()+checkValidTyConTyVars tc+ = do { -- strip off the duplicates and look for ill-scoped things+ -- but keep the *last* occurrence of each variable, as it's+ -- most likely the one the user wrote+ let stripped_tvs | duplicate_vars+ = reverse $ nub $ reverse tvs+ | otherwise+ = tvs+ vis_tvs = filterOutInvisibleTyVars tc tvs+ extra | not (vis_tvs `equalLength` stripped_tvs)+ = text "NB: Implicitly declared kind variables are put first."+ | otherwise+ = empty+ ; checkValidTelescope (pprTyVars vis_tvs) stripped_tvs extra+ `and_if_that_doesn't_error`+ -- This triggers on test case dependent/should_fail/InferDependency+ -- It reports errors around Note [Dependent LHsQTyVars] in TcHsType+ when duplicate_vars (+ addErr (vcat [ text "Invalid declaration for" <+>+ quotes (ppr tc) <> semi <+> text "you must explicitly"+ , text "declare which variables are dependent on which others."+ , hang (text "Inferred variable kinds:")+ 2 (vcat (map pp_tv stripped_tvs)) ])) }+ where+ tvs = tyConTyVars tc+ duplicate_vars = sizeVarSet (mkVarSet tvs) < length tvs++ pp_tv tv = ppr tv <+> dcolon <+> ppr (tyVarKind tv)++ -- only run try_second if the first reports no errors+ and_if_that_doesn't_error :: TcM () -> TcM () -> TcM ()+ try_first `and_if_that_doesn't_error` try_second+ = recoverM (return ()) $+ do { checkNoErrs try_first+ ; try_second }++-------------------------------+checkValidDataCon :: DynFlags -> Bool -> TyCon -> DataCon -> TcM ()+checkValidDataCon dflags existential_ok tc con+ = setSrcSpan (srcLocSpan (getSrcLoc con)) $+ addErrCtxt (dataConCtxt con) $+ do { -- Check that the return type of the data constructor+ -- matches the type constructor; eg reject this:+ -- data T a where { MkT :: Bogus a }+ -- It's important to do this first:+ -- see Note [Checking GADT return types]+ -- and c.f. Note [Check role annotations in a second pass]+ let tc_tvs = tyConTyVars tc+ res_ty_tmpl = mkFamilyTyConApp tc (mkTyVarTys tc_tvs)+ orig_res_ty = dataConOrigResTy con+ ; traceTc "checkValidDataCon" (vcat+ [ ppr con, ppr tc, ppr tc_tvs+ , ppr res_ty_tmpl <+> dcolon <+> ppr (typeKind res_ty_tmpl)+ , ppr orig_res_ty <+> dcolon <+> ppr (typeKind orig_res_ty)])+++ ; checkTc (isJust (tcMatchTy res_ty_tmpl+ orig_res_ty))+ (badDataConTyCon con res_ty_tmpl orig_res_ty)+ -- Note that checkTc aborts if it finds an error. This is+ -- critical to avoid panicking when we call dataConUserType+ -- on an un-rejiggable datacon!++ ; traceTc "checkValidDataCon 2" (ppr (dataConUserType con))++ -- Check that the result type is a *monotype*+ -- e.g. reject this: MkT :: T (forall a. a->a)+ -- Reason: it's really the argument of an equality constraint+ ; checkValidMonoType orig_res_ty++ -- Check all argument types for validity+ ; checkValidType ctxt (dataConUserType con)+ ; mapM_ (checkForLevPoly empty)+ (dataConOrigArgTys con)++ -- Extra checks for newtype data constructors+ ; when (isNewTyCon tc) (checkNewDataCon con)++ -- Check that existentials are allowed if they are used+ ; checkTc (existential_ok || isVanillaDataCon con)+ (badExistential con)++ -- Check that UNPACK pragmas and bangs work out+ -- E.g. reject data T = MkT {-# UNPACK #-} Int -- No "!"+ -- data T = MkT {-# UNPACK #-} !a -- Can't unpack+ ; zipWith3M_ check_bang (dataConSrcBangs con) (dataConImplBangs con) [1..]++ ; traceTc "Done validity of data con" (ppr con <+> ppr (dataConRepType con))+ }+ where+ ctxt = ConArgCtxt (dataConName con)++ check_bang :: HsSrcBang -> HsImplBang -> Int -> TcM ()+ check_bang (HsSrcBang _ _ SrcLazy) _ n+ | not (xopt LangExt.StrictData dflags)+ = addErrTc+ (bad_bang n (text "Lazy annotation (~) without StrictData"))+ check_bang (HsSrcBang _ want_unpack strict_mark) rep_bang n+ | isSrcUnpacked want_unpack, not is_strict+ = addWarnTc NoReason (bad_bang n (text "UNPACK pragma lacks '!'"))+ | isSrcUnpacked want_unpack+ , case rep_bang of { HsUnpack {} -> False; _ -> True }+ , not (gopt Opt_OmitInterfacePragmas dflags)+ -- If not optimising, se don't unpack, so don't complain!+ -- See MkId.dataConArgRep, the (HsBang True) case+ = addWarnTc NoReason (bad_bang n (text "Ignoring unusable UNPACK pragma"))+ where+ is_strict = case strict_mark of+ NoSrcStrict -> xopt LangExt.StrictData dflags+ bang -> isSrcStrict bang++ check_bang _ _ _+ = return ()++ bad_bang n herald+ = hang herald 2 (text "on the" <+> speakNth n+ <+> text "argument of" <+> quotes (ppr con))+-------------------------------+checkNewDataCon :: DataCon -> TcM ()+-- Further checks for the data constructor of a newtype+checkNewDataCon con+ = do { checkTc (isSingleton arg_tys) (newtypeFieldErr con (length arg_tys))+ -- One argument++ ; checkTc (not (isUnliftedType arg_ty1)) $+ text "A newtype cannot have an unlifted argument type"++ ; check_con (null eq_spec) $+ text "A newtype constructor must have a return type of form T a1 ... an"+ -- Return type is (T a b c)++ ; check_con (null theta) $+ text "A newtype constructor cannot have a context in its type"++ ; check_con (null ex_tvs) $+ text "A newtype constructor cannot have existential type variables"+ -- No existentials++ ; checkTc (all ok_bang (dataConSrcBangs con))+ (newtypeStrictError con)+ -- No strictness annotations+ }+ where+ (_univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res_ty)+ = dataConFullSig con+ check_con what msg+ = checkTc what (msg $$ ppr con <+> dcolon <+> ppr (dataConUserType con))++ (arg_ty1 : _) = arg_tys++ ok_bang (HsSrcBang _ _ SrcStrict) = False+ ok_bang (HsSrcBang _ _ SrcLazy) = False+ ok_bang _ = True++-------------------------------+checkValidClass :: Class -> TcM ()+checkValidClass cls+ = do { constrained_class_methods <- xoptM LangExt.ConstrainedClassMethods+ ; multi_param_type_classes <- xoptM LangExt.MultiParamTypeClasses+ ; nullary_type_classes <- xoptM LangExt.NullaryTypeClasses+ ; fundep_classes <- xoptM LangExt.FunctionalDependencies+ ; undecidable_super_classes <- xoptM LangExt.UndecidableSuperClasses++ -- Check that the class is unary, unless multiparameter type classes+ -- are enabled; also recognize deprecated nullary type classes+ -- extension (subsumed by multiparameter type classes, Trac #8993)+ ; checkTc (multi_param_type_classes || cls_arity == 1 ||+ (nullary_type_classes && cls_arity == 0))+ (classArityErr cls_arity cls)+ ; checkTc (fundep_classes || null fundeps) (classFunDepsErr cls)++ -- Check the super-classes+ ; checkValidTheta (ClassSCCtxt (className cls)) theta++ -- Now check for cyclic superclasses+ -- If there are superclass cycles, checkClassCycleErrs bails.+ ; unless undecidable_super_classes $+ case checkClassCycles cls of+ Just err -> setSrcSpan (getSrcSpan cls) $+ addErrTc err+ Nothing -> return ()++ -- Check the class operations.+ -- But only if there have been no earlier errors+ -- See Note [Abort when superclass cycle is detected]+ ; whenNoErrs $+ mapM_ (check_op constrained_class_methods) op_stuff++ -- Check the associated type defaults are well-formed and instantiated+ ; mapM_ check_at at_stuff }+ where+ (tyvars, fundeps, theta, _, at_stuff, op_stuff) = classExtraBigSig cls+ cls_arity = length $ filterOutInvisibleTyVars (classTyCon cls) tyvars+ -- Ignore invisible variables+ cls_tv_set = mkVarSet tyvars+ mini_env = zipVarEnv tyvars (mkTyVarTys tyvars)+ mb_cls = Just (cls, tyvars, mini_env)++ check_op constrained_class_methods (sel_id, dm)+ = setSrcSpan (getSrcSpan sel_id) $+ addErrCtxt (classOpCtxt sel_id op_ty) $ do+ { traceTc "class op type" (ppr op_ty)+ ; checkValidType ctxt op_ty+ -- This implements the ambiguity check, among other things+ -- Example: tc223+ -- class Error e => Game b mv e | b -> mv e where+ -- newBoard :: MonadState b m => m ()+ -- Here, MonadState has a fundep m->b, so newBoard is fine++ -- a method cannot be levity 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 [Levity polymorphism checking] in DsMonad+ ; checkForLevPoly empty tau1++ ; unless constrained_class_methods $+ mapM_ check_constraint (tail (cls_pred:op_theta))++ ; check_dm ctxt sel_id cls_pred tau2 dm+ }+ where+ ctxt = FunSigCtxt op_name True -- Report redundant class constraints+ op_name = idName sel_id+ op_ty = idType sel_id+ (_,cls_pred,tau1) = tcSplitMethodTy op_ty+ -- See Note [Splitting nested sigma types]+ (_,op_theta,tau2) = tcSplitNestedSigmaTys tau1++ check_constraint :: TcPredType -> TcM ()+ check_constraint pred -- See Note [Class method constraints]+ = when (not (isEmptyVarSet pred_tvs) &&+ pred_tvs `subVarSet` cls_tv_set)+ (addErrTc (badMethPred sel_id pred))+ where+ pred_tvs = tyCoVarsOfType pred++ check_at (ATI fam_tc m_dflt_rhs)+ = do { checkTc (cls_arity == 0 || any (`elemVarSet` cls_tv_set) fam_tvs)+ (noClassTyVarErr cls fam_tc)+ -- Check that the associated type mentions at least+ -- one of the class type variables+ -- The check is disabled for nullary type classes,+ -- since there is no possible ambiguity (Trac #10020)++ -- Check that any default declarations for associated types are valid+ ; whenIsJust m_dflt_rhs $ \ (rhs, loc) ->+ checkValidTyFamEqn mb_cls fam_tc+ fam_tvs [] (mkTyVarTys fam_tvs) rhs loc }+ where+ fam_tvs = tyConTyVars fam_tc++ check_dm :: UserTypeCtxt -> Id -> PredType -> Type -> DefMethInfo -> TcM ()+ -- Check validity of the /top-level/ generic-default type+ -- E.g for class C a where+ -- default op :: forall b. (a~b) => blah+ -- we do not want to do an ambiguity check on a type with+ -- a free TyVar 'a' (Trac #11608). See TcType+ -- Note [TyVars and TcTyVars during type checking] in TcType+ -- Hence the mkDefaultMethodType to close the type.+ check_dm ctxt sel_id vanilla_cls_pred vanilla_tau+ (Just (dm_name, dm_spec@(GenericDM dm_ty)))+ = setSrcSpan (getSrcSpan dm_name) $ do+ -- We have carefully set the SrcSpan on the generic+ -- default-method Name to be that of the generic+ -- default type signature++ -- First, we check that that the method's default type signature+ -- aligns with the non-default type signature.+ -- See Note [Default method type signatures must align]+ let cls_pred = mkClassPred cls $ mkTyVarTys $ classTyVars cls+ -- Note that the second field of this tuple contains the context+ -- of the default type signature, making it apparent that we+ -- ignore method contexts completely when validity-checking+ -- default type signatures. See the end of+ -- Note [Default method type signatures must align]+ -- to learn why this is OK.+ --+ -- See also Note [Splitting nested sigma types]+ -- for an explanation of why we don't use tcSplitSigmaTy here.+ (_, _, dm_tau) = tcSplitNestedSigmaTys dm_ty++ -- Given this class definition:+ --+ -- class C a b where+ -- op :: forall p q. (Ord a, D p q)+ -- => a -> b -> p -> (a, b)+ -- default op :: forall r s. E r+ -- => a -> b -> s -> (a, b)+ --+ -- We want to match up two types of the form:+ --+ -- Vanilla type sig: C aa bb => aa -> bb -> p -> (aa, bb)+ -- Default type sig: C a b => a -> b -> s -> (a, b)+ --+ -- Notice that the two type signatures can be quantified over+ -- different class type variables! Therefore, it's important that+ -- we include the class predicate parts to match up a with aa and+ -- b with bb.+ vanilla_phi_ty = mkPhiTy [vanilla_cls_pred] vanilla_tau+ dm_phi_ty = mkPhiTy [cls_pred] dm_tau++ traceTc "check_dm" $ vcat+ [ text "vanilla_phi_ty" <+> ppr vanilla_phi_ty+ , text "dm_phi_ty" <+> ppr dm_phi_ty ]++ -- Actually checking that the types align is done with a call to+ -- tcMatchTys. We need to get a match in both directions to rule+ -- out degenerate cases like these:+ --+ -- class Foo a where+ -- foo1 :: a -> b+ -- default foo1 :: a -> Int+ --+ -- foo2 :: a -> Int+ -- default foo2 :: a -> b+ unless (isJust $ tcMatchTys [dm_phi_ty, vanilla_phi_ty]+ [vanilla_phi_ty, dm_phi_ty]) $ addErrTc $+ hang (text "The default type signature for"+ <+> ppr sel_id <> colon)+ 2 (ppr dm_ty)+ $$ (text "does not match its corresponding"+ <+> text "non-default type signature")++ -- Now do an ambiguity check on the default type signature.+ checkValidType ctxt (mkDefaultMethodType cls sel_id dm_spec)+ check_dm _ _ _ _ _ = return ()++checkFamFlag :: Name -> TcM ()+-- Check that we don't use families without -XTypeFamilies+-- The parser won't even parse them, but I suppose a GHC API+-- client might have a go!+checkFamFlag tc_name+ = do { idx_tys <- xoptM LangExt.TypeFamilies+ ; checkTc idx_tys err_msg }+ where+ err_msg = hang (text "Illegal family declaration for" <+> quotes (ppr tc_name))+ 2 (text "Use TypeFamilies to allow indexed type families")++{- Note [Class method constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Haskell 2010 is supposed to reject+ class C a where+ op :: Eq a => a -> a+where the method type costrains only the class variable(s). (The extension+-XConstrainedClassMethods switches off this check.) But regardless+we should not reject+ class C a where+ op :: (?x::Int) => a -> a+as pointed out in Trac #11793. So the test here rejects the program if+ * -XConstrainedClassMethods is off+ * the tyvars of the constraint are non-empty+ * all the tyvars are class tyvars, none are locally quantified++Note [Abort when superclass cycle is detected]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We must avoid doing the ambiguity check for the methods (in+checkValidClass.check_op) when there are already errors accumulated.+This is because one of the errors may be a superclass cycle, and+superclass cycles cause canonicalization to loop. Here is a+representative example:++ class D a => C a where+ meth :: D a => ()+ class C a => D a++This fixes Trac #9415, #9739++Note [Default method type signatures must align]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC enforces the invariant that a class method's default type signature+must "align" with that of the method's non-default type signature, as per+GHC Trac #12918. For instance, if you have:++ class Foo a where+ bar :: forall b. Context => a -> b++Then a default type signature for bar must be alpha equivalent to+(forall b. a -> b). That is, the types must be the same modulo differences in+contexts. So the following would be acceptable default type signatures:++ default bar :: forall b. Context1 => a -> b+ default bar :: forall x. Context2 => a -> x++But the following are NOT acceptable default type signatures:++ default bar :: forall b. b -> a+ default bar :: forall x. x+ default bar :: a -> Int++Note that a is bound by the class declaration for Foo itself, so it is+not allowed to differ in the default type signature.++The default type signature (default bar :: a -> Int) deserves special mention,+since (a -> Int) is a straightforward instantiation of (forall b. a -> b). To+write this, you need to declare the default type signature like so:++ default bar :: forall b. (b ~ Int). a -> b++As noted in #12918, there are several reasons to do this:++1. It would make no sense to have a type that was flat-out incompatible with+ the non-default type signature. For instance, if you had:++ class Foo a where+ bar :: a -> Int+ default bar :: a -> Bool++ Then that would always fail in an instance declaration. So this check+ nips such cases in the bud before they have the chance to produce+ confusing error messages.++2. Internally, GHC uses TypeApplications to instantiate the default method in+ an instance. See Note [Default methods in instances] in TcInstDcls.+ Thus, GHC needs to know exactly what the universally quantified type+ variables are, and when instantiated that way, the default method's type+ must match the expected type.++3. Aesthetically, by only allowing the default type signature to differ in its+ context, we are making it more explicit the ways in which the default type+ signature is less polymorphic than the non-default type signature.++You might be wondering: why are the contexts allowed to be different, but not+the rest of the type signature? That's because default implementations often+rely on assumptions that the more general, non-default type signatures do not.+For instance, in the Enum class declaration:++ class Enum a where+ enum :: [a]+ default enum :: (Generic a, GEnum (Rep a)) => [a]+ enum = map to genum++ class GEnum f where+ genum :: [f a]++The default implementation for enum only works for types that are instances of+Generic, and for which their generic Rep type is an instance of GEnum. But+clearly enum doesn't _have_ to use this implementation, so naturally, the+context for enum is allowed to be different to accomodate this. As a result,+when we validity-check default type signatures, we ignore contexts completely.++Note that when checking whether two type signatures match, we must take care to+split as many foralls as it takes to retrieve the tau types we which to check.+See Note [Splitting nested sigma types].++Note [Splitting nested sigma types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this type synonym and class definition:++ type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t++ class Each s t a b where+ each :: Traversal s t a b+ default each :: (Traversable g, s ~ g a, t ~ g b) => Traversal s t a b++It might seem obvious that the tau types in both type signatures for `each`+are the same, but actually getting GHC to conclude this is surprisingly tricky.+That is because in general, the form of a class method's non-default type+signature is:++ forall a. C a => forall d. D d => E a b++And the general form of a default type signature is:++ forall f. F f => E a f -- The variable `a` comes from the class++So it you want to get the tau types in each type signature, you might find it+reasonable to call tcSplitSigmaTy twice on the non-default type signature, and+call it once on the default type signature. For most classes and methods, this+will work, but Each is a bit of an exceptional case. The way `each` is written,+it doesn't quantify any additional type variables besides those of the Each+class itself, so the non-default type signature for `each` is actually this:++ forall s t a b. Each s t a b => Traversal s t a b++Notice that there _appears_ to only be one forall. But there's actually another+forall lurking in the Traversal type synonym, so if you call tcSplitSigmaTy+twice, you'll also go under the forall in Traversal! That is, you'll end up+with:++ (a -> f b) -> s -> f t++A problem arises because you only call tcSplitSigmaTy once on the default type+signature for `each`, which gives you++ Traversal s t a b++Or, equivalently:++ forall f. Applicative f => (a -> f b) -> s -> f t++This is _not_ the same thing as (a -> f b) -> s -> f t! So now tcMatchTy will+say that the tau types for `each` are not equal.++A solution to this problem is to use tcSplitNestedSigmaTys instead of+tcSplitSigmaTy. tcSplitNestedSigmaTys will always split any foralls that it+sees until it can't go any further, so if you called it on the default type+signature for `each`, it would return (a -> f b) -> s -> f t like we desired.++************************************************************************+* *+ Checking role validity+* *+************************************************************************+-}++checkValidRoleAnnots :: RoleAnnotEnv -> TyCon -> TcM ()+checkValidRoleAnnots role_annots tc+ | isTypeSynonymTyCon tc = check_no_roles+ | isFamilyTyCon tc = check_no_roles+ | isAlgTyCon tc = check_roles+ | otherwise = return ()+ where+ -- Role annotations are given only on *explicit* variables,+ -- but a tycon stores roles for all variables.+ -- So, we drop the implicit roles (which are all Nominal, anyway).+ name = tyConName tc+ tyvars = tyConTyVars tc+ roles = tyConRoles tc+ (vis_roles, vis_vars) = unzip $ snd $+ partitionInvisibles tc (mkTyVarTy . snd) $+ zip roles tyvars+ role_annot_decl_maybe = lookupRoleAnnot role_annots name++ check_roles+ = whenIsJust role_annot_decl_maybe $+ \decl@(L loc (RoleAnnotDecl _ the_role_annots)) ->+ addRoleAnnotCtxt name $+ setSrcSpan loc $ do+ { role_annots_ok <- xoptM LangExt.RoleAnnotations+ ; checkTc role_annots_ok $ needXRoleAnnotations tc+ ; checkTc (vis_vars `equalLength` the_role_annots)+ (wrongNumberOfRoles vis_vars decl)+ ; _ <- zipWith3M checkRoleAnnot vis_vars the_role_annots vis_roles+ -- Representational or phantom roles for class parameters+ -- quickly lead to incoherence. So, we require+ -- IncoherentInstances to have them. See #8773.+ ; incoherent_roles_ok <- xoptM LangExt.IncoherentInstances+ ; checkTc ( incoherent_roles_ok+ || (not $ isClassTyCon tc)+ || (all (== Nominal) vis_roles))+ incoherentRoles++ ; lint <- goptM Opt_DoCoreLinting+ ; when lint $ checkValidRoles tc }++ check_no_roles+ = whenIsJust role_annot_decl_maybe illegalRoleAnnotDecl++checkRoleAnnot :: TyVar -> Located (Maybe Role) -> Role -> TcM ()+checkRoleAnnot _ (L _ Nothing) _ = return ()+checkRoleAnnot tv (L _ (Just r1)) r2+ = when (r1 /= r2) $+ addErrTc $ badRoleAnnot (tyVarName tv) r1 r2++-- This is a double-check on the role inference algorithm. It is only run when+-- -dcore-lint is enabled. See Note [Role inference] in TcTyDecls+checkValidRoles :: TyCon -> TcM ()+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism] in CoreLint+checkValidRoles tc+ | isAlgTyCon tc+ -- tyConDataCons returns an empty list for data families+ = mapM_ check_dc_roles (tyConDataCons tc)+ | Just rhs <- synTyConRhs_maybe tc+ = check_ty_roles (zipVarEnv (tyConTyVars tc) (tyConRoles tc)) Representational rhs+ | otherwise+ = return ()+ where+ check_dc_roles datacon+ = do { traceTc "check_dc_roles" (ppr datacon <+> ppr (tyConRoles tc))+ ; mapM_ (check_ty_roles role_env Representational) $+ eqSpecPreds eq_spec ++ theta ++ arg_tys }+ -- See Note [Role-checking data constructor arguments] in TcTyDecls+ where+ (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res_ty)+ = dataConFullSig datacon+ univ_roles = zipVarEnv univ_tvs (tyConRoles tc)+ -- zipVarEnv uses zipEqual, but we don't want that for ex_tvs+ ex_roles = mkVarEnv (map (, Nominal) ex_tvs)+ role_env = univ_roles `plusVarEnv` ex_roles++ check_ty_roles env role (TyVarTy tv)+ = case lookupVarEnv env tv of+ Just role' -> unless (role' `ltRole` role || role' == role) $+ report_error $ text "type variable" <+> quotes (ppr tv) <+>+ text "cannot have role" <+> ppr role <+>+ text "because it was assigned role" <+> ppr role'+ Nothing -> report_error $ text "type variable" <+> quotes (ppr tv) <+>+ text "missing in environment"++ check_ty_roles env Representational (TyConApp tc tys)+ = let roles' = tyConRoles tc in+ zipWithM_ (maybe_check_ty_roles env) roles' tys++ check_ty_roles env Nominal (TyConApp _ tys)+ = mapM_ (check_ty_roles env Nominal) tys++ check_ty_roles _ Phantom ty@(TyConApp {})+ = pprPanic "check_ty_roles" (ppr ty)++ check_ty_roles env role (AppTy ty1 ty2)+ = check_ty_roles env role ty1+ >> check_ty_roles env Nominal ty2++ check_ty_roles env role (FunTy ty1 ty2)+ = check_ty_roles env role ty1+ >> check_ty_roles env role ty2++ check_ty_roles env role (ForAllTy (TvBndr tv _) ty)+ = check_ty_roles env Nominal (tyVarKind tv)+ >> check_ty_roles (extendVarEnv env tv Nominal) role ty++ check_ty_roles _ _ (LitTy {}) = return ()++ check_ty_roles env role (CastTy t _)+ = check_ty_roles env role t++ check_ty_roles _ role (CoercionTy co)+ = unless (role == Phantom) $+ report_error $ text "coercion" <+> ppr co <+> text "has bad role" <+> ppr role++ maybe_check_ty_roles env role ty+ = when (role == Nominal || role == Representational) $+ check_ty_roles env role ty++ report_error doc+ = addErrTc $ vcat [text "Internal error in role inference:",+ doc,+ text "Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug"]++{-+************************************************************************+* *+ Error messages+* *+************************************************************************+-}++tcAddTyFamInstCtxt :: TyFamInstDecl Name -> TcM a -> TcM a+tcAddTyFamInstCtxt decl+ = tcAddFamInstCtxt (text "type instance") (tyFamInstDeclName decl)++tcMkDataFamInstCtxt :: DataFamInstDecl Name -> SDoc+tcMkDataFamInstCtxt decl+ = tcMkFamInstCtxt (pprDataFamInstFlavour decl <+> text "instance")+ (unLoc (dfid_tycon decl))++tcAddDataFamInstCtxt :: DataFamInstDecl Name -> TcM a -> TcM a+tcAddDataFamInstCtxt decl+ = addErrCtxt (tcMkDataFamInstCtxt decl)++tcMkFamInstCtxt :: SDoc -> Name -> SDoc+tcMkFamInstCtxt flavour tycon+ = hsep [ text "In the" <+> flavour <+> text "declaration for"+ , quotes (ppr tycon) ]++tcAddFamInstCtxt :: SDoc -> Name -> TcM a -> TcM a+tcAddFamInstCtxt flavour tycon thing_inside+ = addErrCtxt (tcMkFamInstCtxt flavour tycon) thing_inside++tcAddClosedTypeFamilyDeclCtxt :: TyCon -> TcM a -> TcM a+tcAddClosedTypeFamilyDeclCtxt tc+ = addErrCtxt ctxt+ where+ ctxt = text "In the equations for closed type family" <+>+ quotes (ppr tc)++resultTypeMisMatch :: FieldLabelString -> DataCon -> DataCon -> SDoc+resultTypeMisMatch field_name con1 con2+ = vcat [sep [text "Constructors" <+> ppr con1 <+> text "and" <+> ppr con2,+ text "have a common field" <+> quotes (ppr field_name) <> comma],+ nest 2 $ text "but have different result types"]++fieldTypeMisMatch :: FieldLabelString -> DataCon -> DataCon -> SDoc+fieldTypeMisMatch field_name con1 con2+ = sep [text "Constructors" <+> ppr con1 <+> text "and" <+> ppr con2,+ text "give different types for field", quotes (ppr field_name)]++dataConCtxtName :: [Located Name] -> SDoc+dataConCtxtName [con]+ = text "In the definition of data constructor" <+> quotes (ppr con)+dataConCtxtName con+ = text "In the definition of data constructors" <+> interpp'SP con++dataConCtxt :: Outputable a => a -> SDoc+dataConCtxt con = text "In the definition of data constructor" <+> quotes (ppr con)++classOpCtxt :: Var -> Type -> SDoc+classOpCtxt sel_id tau = sep [text "When checking the class method:",+ nest 2 (pprPrefixOcc sel_id <+> dcolon <+> ppr tau)]++classArityErr :: Int -> Class -> SDoc+classArityErr n cls+ | n == 0 = mkErr "No" "no-parameter"+ | otherwise = mkErr "Too many" "multi-parameter"+ where+ mkErr howMany allowWhat =+ vcat [text (howMany ++ " parameters for class") <+> quotes (ppr cls),+ parens (text ("Use MultiParamTypeClasses to allow "+ ++ allowWhat ++ " classes"))]++classFunDepsErr :: Class -> SDoc+classFunDepsErr cls+ = vcat [text "Fundeps in class" <+> quotes (ppr cls),+ parens (text "Use FunctionalDependencies to allow fundeps")]++badMethPred :: Id -> TcPredType -> SDoc+badMethPred sel_id pred+ = vcat [ hang (text "Constraint" <+> quotes (ppr pred)+ <+> text "in the type of" <+> quotes (ppr sel_id))+ 2 (text "constrains only the class type variables")+ , text "Use ConstrainedClassMethods to allow it" ]++noClassTyVarErr :: Class -> TyCon -> SDoc+noClassTyVarErr clas fam_tc+ = sep [ text "The associated type" <+> quotes (ppr fam_tc)+ , text "mentions none of the type or kind variables of the class" <+>+ quotes (ppr clas <+> hsep (map ppr (classTyVars clas)))]++badDataConTyCon :: DataCon -> Type -> Type -> SDoc+badDataConTyCon data_con res_ty_tmpl actual_res_ty+ = hang (text "Data constructor" <+> quotes (ppr data_con) <+>+ text "returns type" <+> quotes (ppr actual_res_ty))+ 2 (text "instead of an instance of its parent type" <+> quotes (ppr res_ty_tmpl))++badGadtDecl :: Name -> SDoc+badGadtDecl tc_name+ = vcat [ text "Illegal generalised algebraic data declaration for" <+> quotes (ppr tc_name)+ , nest 2 (parens $ text "Use GADTs to allow GADTs") ]++badExistential :: DataCon -> SDoc+badExistential con+ = hang (text "Data constructor" <+> quotes (ppr con) <+>+ text "has existential type variables, a context, or a specialised result type")+ 2 (vcat [ ppr con <+> dcolon <+> ppr (dataConUserType con)+ , parens $ text "Use ExistentialQuantification or GADTs to allow this" ])++badStupidTheta :: Name -> SDoc+badStupidTheta tc_name+ = text "A data type declared in GADT style cannot have a context:" <+> quotes (ppr tc_name)++newtypeConError :: Name -> Int -> SDoc+newtypeConError tycon n+ = sep [text "A newtype must have exactly one constructor,",+ nest 2 $ text "but" <+> quotes (ppr tycon) <+> text "has" <+> speakN n ]++newtypeStrictError :: DataCon -> SDoc+newtypeStrictError con+ = sep [text "A newtype constructor cannot have a strictness annotation,",+ nest 2 $ text "but" <+> quotes (ppr con) <+> text "does"]++newtypeFieldErr :: DataCon -> Int -> SDoc+newtypeFieldErr con_name n_flds+ = sep [text "The constructor of a newtype must have exactly one field",+ nest 2 $ text "but" <+> quotes (ppr con_name) <+> text "has" <+> speakN n_flds]++badSigTyDecl :: Name -> SDoc+badSigTyDecl tc_name+ = vcat [ text "Illegal kind signature" <+>+ quotes (ppr tc_name)+ , nest 2 (parens $ text "Use KindSignatures to allow kind signatures") ]++emptyConDeclsErr :: Name -> SDoc+emptyConDeclsErr tycon+ = sep [quotes (ppr tycon) <+> text "has no constructors",+ nest 2 $ text "(EmptyDataDecls permits this)"]++wrongKindOfFamily :: TyCon -> SDoc+wrongKindOfFamily family+ = text "Wrong category of family instance; declaration was for a"+ <+> kindOfFamily+ where+ kindOfFamily | isTypeFamilyTyCon family = text "type family"+ | isDataFamilyTyCon family = text "data family"+ | otherwise = pprPanic "wrongKindOfFamily" (ppr family)++wrongNumberOfParmsErr :: Arity -> SDoc+wrongNumberOfParmsErr max_args+ = text "Number of parameters must match family declaration; expected"+ <+> ppr max_args++defaultAssocKindErr :: TyCon -> SDoc+defaultAssocKindErr fam_tc+ = text "Kind mis-match on LHS of default declaration for"+ <+> quotes (ppr fam_tc)++wrongTyFamName :: Name -> Name -> SDoc+wrongTyFamName fam_tc_name eqn_tc_name+ = hang (text "Mismatched type name in type family instance.")+ 2 (vcat [ text "Expected:" <+> ppr fam_tc_name+ , text " Actual:" <+> ppr eqn_tc_name ])++badRoleAnnot :: Name -> Role -> Role -> SDoc+badRoleAnnot var annot inferred+ = hang (text "Role mismatch on variable" <+> ppr var <> colon)+ 2 (sep [ text "Annotation says", ppr annot+ , text "but role", ppr inferred+ , text "is required" ])++wrongNumberOfRoles :: [a] -> LRoleAnnotDecl Name -> SDoc+wrongNumberOfRoles tyvars d@(L _ (RoleAnnotDecl _ annots))+ = hang (text "Wrong number of roles listed in role annotation;" $$+ text "Expected" <+> (ppr $ length tyvars) <> comma <+>+ text "got" <+> (ppr $ length annots) <> colon)+ 2 (ppr d)++illegalRoleAnnotDecl :: LRoleAnnotDecl Name -> TcM ()+illegalRoleAnnotDecl (L loc (RoleAnnotDecl tycon _))+ = setErrCtxt [] $+ setSrcSpan loc $+ addErrTc (text "Illegal role annotation for" <+> ppr tycon <> char ';' $$+ text "they are allowed only for datatypes and classes.")++needXRoleAnnotations :: TyCon -> SDoc+needXRoleAnnotations tc+ = text "Illegal role annotation for" <+> ppr tc <> char ';' $$+ text "did you intend to use RoleAnnotations?"++incoherentRoles :: SDoc+incoherentRoles = (text "Roles other than" <+> quotes (text "nominal") <+>+ text "for class parameters can lead to incoherence.") $$+ (text "Use IncoherentInstances to allow this; bad role found")++addTyConCtxt :: TyCon -> TcM a -> TcM a+addTyConCtxt tc+ = addErrCtxt ctxt+ where+ name = getName tc+ flav = text (tyConFlavour tc)+ ctxt = hsep [ text "In the", flav+ , text "declaration for", quotes (ppr name) ]++addRoleAnnotCtxt :: Name -> TcM a -> TcM a+addRoleAnnotCtxt name+ = addErrCtxt $+ text "while checking a role annotation for" <+> quotes (ppr name)
+ typecheck/TcTyDecls.hs view
@@ -0,0 +1,1007 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1999+++Analysis functions over data types. Specifically, detecting recursive types.++This stuff is only used for source-code decls; it's recorded in interface+files for imported data types.+-}++{-# LANGUAGE CPP #-}++module TcTyDecls(+ RolesInfo,+ inferRoles,+ checkSynCycles,+ checkClassCycles,++ -- * Implicits+ tcAddImplicits, mkDefaultMethodType,++ -- * Record selectors+ mkRecSelBinds, mkOneRecordSelector+ ) where++#include "HsVersions.h"++import TcRnMonad+import TcEnv+import TcBinds( tcRecSelBinds )+import RnEnv( RoleAnnotEnv, lookupRoleAnnot )+import TyCoRep( Type(..), Coercion(..), UnivCoProvenance(..) )+import TcType+import TysWiredIn( unitTy )+import MkCore( rEC_SEL_ERROR_ID )+import HsSyn+import Class+import Type+import HscTypes+import TyCon+import ConLike+import DataCon+import Name+import NameEnv+import NameSet hiding (unitFV)+import RdrName ( mkVarUnqual )+import Id+import IdInfo+import VarEnv+import VarSet+import NameSet ( NameSet, unitNameSet, extendNameSet, elemNameSet )+import Coercion ( ltRole )+import BasicTypes+import SrcLoc+import Unique ( mkBuiltinUnique )+import Outputable+import Util+import Maybes+import Bag+import FastString+import FV+import Module++import Control.Monad++{-+************************************************************************+* *+ Cycles in type synonym declarations+* *+************************************************************************+-}++synonymTyConsOfType :: Type -> [TyCon]+-- Does not look through type synonyms at all+-- Return a list of synonym tycons+-- Keep this synchronized with 'expandTypeSynonyms'+synonymTyConsOfType ty+ = nameEnvElts (go ty)+ where+ go :: Type -> NameEnv TyCon -- The NameEnv does duplicate elim+ go (TyConApp tc tys) = go_tc tc `plusNameEnv` go_s tys+ go (LitTy _) = emptyNameEnv+ go (TyVarTy _) = emptyNameEnv+ go (AppTy a b) = go a `plusNameEnv` go b+ go (FunTy a b) = go a `plusNameEnv` go b+ go (ForAllTy _ ty) = go ty+ go (CastTy ty co) = go ty `plusNameEnv` go_co co+ go (CoercionTy co) = go_co co++ -- Note [TyCon cycles through coercions?!]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- Although, in principle, it's possible for a type synonym loop+ -- could go through a coercion (since a coercion can refer to+ -- a TyCon or Type), it doesn't seem possible to actually construct+ -- a Haskell program which tickles this case. Here is an example+ -- program which causes a coercion:+ --+ -- type family Star where+ -- Star = Type+ --+ -- data T :: Star -> Type+ -- data S :: forall (a :: Type). T a -> Type+ --+ -- Here, the application 'T a' must first coerce a :: Type to a :: Star,+ -- witnessed by the type family. But if we now try to make Type refer+ -- to a type synonym which in turn refers to Star, we'll run into+ -- trouble: we're trying to define and use the type constructor+ -- in the same recursive group. Possibly this restriction will be+ -- lifted in the future but for now, this code is "just for completeness+ -- sake".+ go_co (Refl _ ty) = go ty+ go_co (TyConAppCo _ tc cs) = go_tc tc `plusNameEnv` go_co_s cs+ go_co (AppCo co co') = go_co co `plusNameEnv` go_co co'+ go_co (ForAllCo _ co co') = go_co co `plusNameEnv` go_co co'+ go_co (FunCo _ co co') = go_co co `plusNameEnv` go_co co'+ go_co (CoVarCo _) = emptyNameEnv+ go_co (AxiomInstCo _ _ cs) = go_co_s cs+ go_co (UnivCo p _ ty ty') = go_prov p `plusNameEnv` go ty `plusNameEnv` go ty'+ go_co (SymCo co) = go_co co+ go_co (TransCo co co') = go_co co `plusNameEnv` go_co co'+ go_co (NthCo _ co) = go_co co+ go_co (LRCo _ co) = go_co co+ go_co (InstCo co co') = go_co co `plusNameEnv` go_co co'+ go_co (CoherenceCo co co') = go_co co `plusNameEnv` go_co co'+ go_co (KindCo co) = go_co co+ go_co (SubCo co) = go_co co+ go_co (AxiomRuleCo _ cs) = go_co_s cs++ go_prov UnsafeCoerceProv = emptyNameEnv+ go_prov (PhantomProv co) = go_co co+ go_prov (ProofIrrelProv co) = go_co co+ go_prov (PluginProv _) = emptyNameEnv+ go_prov (HoleProv _) = emptyNameEnv++ go_tc tc | isTypeSynonymTyCon tc = unitNameEnv (tyConName tc) tc+ | otherwise = emptyNameEnv+ go_s tys = foldr (plusNameEnv . go) emptyNameEnv tys+ go_co_s cos = foldr (plusNameEnv . go_co) emptyNameEnv cos++-- | A monad for type synonym cycle checking, which keeps+-- track of the TyCons which are known to be acyclic, or+-- a failure message reporting that a cycle was found.+newtype SynCycleM a = SynCycleM {+ runSynCycleM :: SynCycleState -> Either (SrcSpan, SDoc) (a, SynCycleState) }++type SynCycleState = NameSet++instance Functor SynCycleM where+ fmap = liftM++instance Applicative SynCycleM where+ pure x = SynCycleM $ \state -> Right (x, state)+ (<*>) = ap++instance Monad SynCycleM where+ m >>= f = SynCycleM $ \state ->+ case runSynCycleM m state of+ Right (x, state') ->+ runSynCycleM (f x) state'+ Left err -> Left err++failSynCycleM :: SrcSpan -> SDoc -> SynCycleM ()+failSynCycleM loc err = SynCycleM $ \_ -> Left (loc, err)++-- | Test if a 'Name' is acyclic, short-circuiting if we've+-- seen it already.+checkNameIsAcyclic :: Name -> SynCycleM () -> SynCycleM ()+checkNameIsAcyclic n m = SynCycleM $ \s ->+ if n `elemNameSet` s+ then Right ((), s) -- short circuit+ else case runSynCycleM m s of+ Right ((), s') -> Right ((), extendNameSet s' n)+ Left err -> Left err++-- | Checks if any of the passed in 'TyCon's have cycles.+-- Takes the 'UnitId' of the home package (as we can avoid+-- checking those TyCons: cycles never go through foreign packages) and+-- the corresponding @LTyClDecl Name@ for each 'TyCon', so we+-- can give better error messages.+checkSynCycles :: UnitId -> [TyCon] -> [LTyClDecl Name] -> TcM ()+checkSynCycles this_uid tcs tyclds = do+ case runSynCycleM (mapM_ (go emptyNameSet []) tcs) emptyNameSet of+ Left (loc, err) -> setSrcSpan loc $ failWithTc err+ Right _ -> return ()+ where+ -- Try our best to print the LTyClDecl for locally defined things+ lcl_decls = mkNameEnv (zip (map tyConName tcs) tyclds)++ -- Short circuit if we've already seen this Name and concluded+ -- it was acyclic.+ go :: NameSet -> [TyCon] -> TyCon -> SynCycleM ()+ go so_far seen_tcs tc =+ checkNameIsAcyclic (tyConName tc) $ go' so_far seen_tcs tc++ -- Expand type synonyms, complaining if you find the same+ -- type synonym a second time.+ go' :: NameSet -> [TyCon] -> TyCon -> SynCycleM ()+ go' so_far seen_tcs tc+ | n `elemNameSet` so_far+ = failSynCycleM (getSrcSpan (head seen_tcs)) $+ sep [ text "Cycle in type synonym declarations:"+ , nest 2 (vcat (map ppr_decl seen_tcs)) ]+ -- Optimization: we don't allow cycles through external packages,+ -- so once we find a non-local name we are guaranteed to not+ -- have a cycle.+ --+ -- This won't hold once we get recursive packages with Backpack,+ -- but for now it's fine.+ | not (isHoleModule mod ||+ moduleUnitId mod == this_uid ||+ isInteractiveModule mod)+ = return ()+ | Just ty <- synTyConRhs_maybe tc =+ go_ty (extendNameSet so_far (tyConName tc)) (tc:seen_tcs) ty+ | otherwise = return ()+ where+ n = tyConName tc+ mod = nameModule n+ ppr_decl tc =+ case lookupNameEnv lcl_decls n of+ Just (L loc decl) -> ppr loc <> colon <+> ppr decl+ Nothing -> ppr (getSrcSpan n) <> colon <+> ppr n <+> text "from external module"+ where+ n = tyConName tc++ go_ty :: NameSet -> [TyCon] -> Type -> SynCycleM ()+ go_ty so_far seen_tcs ty =+ mapM_ (go so_far seen_tcs) (synonymTyConsOfType ty)++{- Note [Superclass cycle check]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The superclass cycle check for C decides if we can statically+guarantee that expanding C's superclass cycles transitively is+guaranteed to terminate. This is a Haskell98 requirement,+but one that we lift with -XUndecidableSuperClasses.++The worry is that a superclass cycle could make the type checker loop.+More precisely, with a constraint (Given or Wanted)+ C ty1 .. tyn+one approach is to instantiate all of C's superclasses, transitively.+We can only do so if that set is finite.++This potential loop occurs only through superclasses. This, for+example, is fine+ class C a where+ op :: C b => a -> b -> b+even though C's full definition uses C.++Making the check static also makes it conservative. Eg+ type family F a+ class F a => C a+Here an instance of (F a) might mention C:+ type instance F [a] = C a+and now we'd have a loop.++The static check works like this, starting with C+ * Look at C's superclass predicates+ * If any is a type-function application,+ or is headed by a type variable, fail+ * If any has C at the head, fail+ * If any has a type class D at the head,+ make the same test with D++A tricky point is: what if there is a type variable at the head?+Consider this:+ class f (C f) => C f+ class c => Id c+and now expand superclasses for constraint (C Id):+ C Id+ --> Id (C Id)+ --> C Id+ --> ....+Each step expands superclasses one layer, and clearly does not terminate.+-}++checkClassCycles :: Class -> Maybe SDoc+-- Nothing <=> ok+-- Just err <=> possible cycle error+checkClassCycles cls+ = do { (definite_cycle, err) <- go (unitNameSet (getName cls))+ cls (mkTyVarTys (classTyVars cls))+ ; let herald | definite_cycle = text "Superclass cycle for"+ | otherwise = text "Potential superclass cycle for"+ ; return (vcat [ herald <+> quotes (ppr cls)+ , nest 2 err, hint]) }+ where+ hint = text "Use UndecidableSuperClasses to accept this"++ -- Expand superclasses starting with (C a b), complaining+ -- if you find the same class a second time, or a type function+ -- or predicate headed by a type variable+ --+ -- NB: this code duplicates TcType.transSuperClasses, but+ -- with more error message generation clobber+ -- Make sure the two stay in sync.+ go :: NameSet -> Class -> [Type] -> Maybe (Bool, SDoc)+ go so_far cls tys = firstJusts $+ map (go_pred so_far) $+ immSuperClasses cls tys++ go_pred :: NameSet -> PredType -> Maybe (Bool, SDoc)+ -- Nothing <=> ok+ -- Just (True, err) <=> definite cycle+ -- Just (False, err) <=> possible cycle+ go_pred so_far pred -- NB: tcSplitTyConApp looks through synonyms+ | Just (tc, tys) <- tcSplitTyConApp_maybe pred+ = go_tc so_far pred tc tys+ | hasTyVarHead pred+ = Just (False, hang (text "one of whose superclass constraints is headed by a type variable:")+ 2 (quotes (ppr pred)))+ | otherwise+ = Nothing++ go_tc :: NameSet -> PredType -> TyCon -> [Type] -> Maybe (Bool, SDoc)+ go_tc so_far pred tc tys+ | isFamilyTyCon tc+ = Just (False, hang (text "one of whose superclass constraints is headed by a type family:")+ 2 (quotes (ppr pred)))+ | Just cls <- tyConClass_maybe tc+ = go_cls so_far cls tys+ | otherwise -- Equality predicate, for example+ = Nothing++ go_cls :: NameSet -> Class -> [Type] -> Maybe (Bool, SDoc)+ go_cls so_far cls tys+ | cls_nm `elemNameSet` so_far+ = Just (True, text "one of whose superclasses is" <+> quotes (ppr cls))+ | isCTupleClass cls+ = go so_far cls tys+ | otherwise+ = do { (b,err) <- go (so_far `extendNameSet` cls_nm) cls tys+ ; return (b, text "one of whose superclasses is" <+> quotes (ppr cls)+ $$ err) }+ where+ cls_nm = getName cls++{-+************************************************************************+* *+ Role inference+* *+************************************************************************++Note [Role inference]+~~~~~~~~~~~~~~~~~~~~~+The role inference algorithm datatype definitions to infer the roles on the+parameters. Although these roles are stored in the tycons, we can perform this+algorithm on the built tycons, as long as we don't peek at an as-yet-unknown+roles field! Ah, the magic of laziness.++First, we choose appropriate initial roles. For families and classes, roles+(including initial roles) are N. For datatypes, we start with the role in the+role annotation (if any), or otherwise use Phantom. This is done in+initialRoleEnv1.++The function irGroup then propagates role information until it reaches a+fixpoint, preferring N over (R or P) and R over P. To aid in this, we have a+monad RoleM, which is a combination reader and state monad. In its state are+the current RoleEnv, which gets updated by role propagation, and an update+bit, which we use to know whether or not we've reached the fixpoint. The+environment of RoleM contains the tycon whose parameters we are inferring, and+a VarEnv from parameters to their positions, so we can update the RoleEnv.+Between tycons, this reader information is missing; it is added by+addRoleInferenceInfo.++There are two kinds of tycons to consider: algebraic ones (excluding classes)+and type synonyms. (Remember, families don't participate -- all their parameters+are N.) An algebraic tycon processes each of its datacons, in turn. Note that+a datacon's universally quantified parameters might be different from the parent+tycon's parameters, so we use the datacon's univ parameters in the mapping from+vars to positions. Note also that we don't want to infer roles for existentials+(they're all at N, too), so we put them in the set of local variables. As an+optimisation, we skip any tycons whose roles are already all Nominal, as there+nowhere else for them to go. For synonyms, we just analyse their right-hand sides.++irType walks through a type, looking for uses of a variable of interest and+propagating role information. Because anything used under a phantom position+is at phantom and anything used under a nominal position is at nominal, the+irType function can assume that anything it sees is at representational. (The+other possibilities are pruned when they're encountered.)++The rest of the code is just plumbing.++How do we know that this algorithm is correct? It should meet the following+specification:++Let Z be a role context -- a mapping from variables to roles. The following+rules define the property (Z |- t : r), where t is a type and r is a role:++Z(a) = r' r' <= r+------------------------- RCVar+Z |- a : r++---------- RCConst+Z |- T : r -- T is a type constructor++Z |- t1 : r+Z |- t2 : N+-------------- RCApp+Z |- t1 t2 : r++forall i<=n. (r_i is R or N) implies Z |- t_i : r_i+roles(T) = r_1 .. r_n+---------------------------------------------------- RCDApp+Z |- T t_1 .. t_n : R++Z, a:N |- t : r+---------------------- RCAll+Z |- forall a:k.t : r+++We also have the following rules:++For all datacon_i in type T, where a_1 .. a_n are universally quantified+and b_1 .. b_m are existentially quantified, and the arguments are t_1 .. t_p,+then if forall j<=p, a_1 : r_1 .. a_n : r_n, b_1 : N .. b_m : N |- t_j : R,+then roles(T) = r_1 .. r_n++roles(->) = R, R+roles(~#) = N, N++With -dcore-lint on, the output of this algorithm is checked in checkValidRoles,+called from checkValidTycon.++Note [Role-checking data constructor arguments]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T a where+ MkT :: Eq b => F a -> (a->a) -> T (G a)++Then we want to check the roles at which 'a' is used+in MkT's type. We want to work on the user-written type,+so we need to take into account+ * the arguments: (F a) and (a->a)+ * the context: C a b+ * the result type: (G a) -- this is in the eq_spec+++Note [Coercions in role inference]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Is (t |> co1) representationally equal to (t |> co2)? Of course they are! Changing+the kind of a type is totally irrelevant to the representation of that type. So,+we want to totally ignore coercions when doing role inference. This includes omitting+any type variables that appear in nominal positions but only within coercions.+-}++type RolesInfo = Name -> [Role]++type RoleEnv = NameEnv [Role] -- from tycon names to roles++-- This, and any of the functions it calls, must *not* look at the roles+-- field of a tycon we are inferring roles about!+-- See Note [Role inference]+inferRoles :: HscSource -> RoleAnnotEnv -> [TyCon] -> Name -> [Role]+inferRoles hsc_src annots tycons+ = let role_env = initialRoleEnv hsc_src annots tycons+ role_env' = irGroup role_env tycons in+ \name -> case lookupNameEnv role_env' name of+ Just roles -> roles+ Nothing -> pprPanic "inferRoles" (ppr name)++initialRoleEnv :: HscSource -> RoleAnnotEnv -> [TyCon] -> RoleEnv+initialRoleEnv hsc_src annots = extendNameEnvList emptyNameEnv .+ map (initialRoleEnv1 hsc_src annots)++initialRoleEnv1 :: HscSource -> RoleAnnotEnv -> TyCon -> (Name, [Role])+initialRoleEnv1 hsc_src annots_env tc+ | isFamilyTyCon tc = (name, map (const Nominal) bndrs)+ | isAlgTyCon tc = (name, default_roles)+ | isTypeSynonymTyCon tc = (name, default_roles)+ | otherwise = pprPanic "initialRoleEnv1" (ppr tc)+ where name = tyConName tc+ bndrs = tyConBinders tc+ argflags = map tyConBinderArgFlag bndrs+ num_exps = count isVisibleArgFlag argflags++ -- if the number of annotations in the role annotation decl+ -- is wrong, just ignore it. We check this in the validity check.+ role_annots+ = case lookupRoleAnnot annots_env name of+ Just (L _ (RoleAnnotDecl _ annots))+ | annots `lengthIs` num_exps -> map unLoc annots+ _ -> replicate num_exps Nothing+ default_roles = build_default_roles argflags role_annots++ build_default_roles (argf : argfs) (m_annot : ras)+ | isVisibleArgFlag argf+ = (m_annot `orElse` default_role) : build_default_roles argfs ras+ build_default_roles (_argf : argfs) ras+ = Nominal : build_default_roles argfs ras+ build_default_roles [] [] = []+ build_default_roles _ _ = pprPanic "initialRoleEnv1 (2)"+ (vcat [ppr tc, ppr role_annots])++ default_role+ | isClassTyCon tc = Nominal+ -- Note [Default roles for abstract TyCons in hs-boot/hsig]+ | HsBootFile <- hsc_src+ , isAbstractTyCon tc = Representational+ | HsigFile <- hsc_src+ , isAbstractTyCon tc = Nominal+ | otherwise = Phantom++-- Note [Default roles for abstract TyCons in hs-boot/hsig]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- What should the default role for an abstract TyCon be?+--+-- Originally, we inferred phantom role for abstract TyCons+-- in hs-boot files, because the type variables were never used.+--+-- This was silly, because the role of the abstract TyCon+-- was required to match the implementation, and the roles of+-- data types are almost never phantom. Thus, in ticket #9204,+-- the default was changed so be representational (the most common case). If+-- the implementing data type was actually nominal, you'd get an easy+-- to understand error, and add the role annotation yourself.+--+-- Then Backpack was added, and with it we added role *subtyping*+-- the matching judgment: if an abstract TyCon has a nominal+-- parameter, it's OK to implement it with a representational+-- parameter. But now, the representational default is not a good+-- one, because you should *only* request representational if+-- you're planning to do coercions. To be maximally flexible+-- with what data types you will accept, you want the default+-- for hsig files is nominal. We don't allow role subtyping+-- with hs-boot files (it's good practice to give an exactly+-- accurate role here, because any types that use the abstract+-- type will propagate the role information.)++irGroup :: RoleEnv -> [TyCon] -> RoleEnv+irGroup env tcs+ = let (env', update) = runRoleM env $ mapM_ irTyCon tcs in+ if update+ then irGroup env' tcs+ else env'++irTyCon :: TyCon -> RoleM ()+irTyCon tc+ | isAlgTyCon tc+ = do { old_roles <- lookupRoles tc+ ; unless (all (== Nominal) old_roles) $ -- also catches data families,+ -- which don't want or need role inference+ irTcTyVars tc $+ do { mapM_ (irType emptyVarSet) (tyConStupidTheta tc) -- See #8958+ ; whenIsJust (tyConClass_maybe tc) irClass+ ; mapM_ irDataCon (visibleDataCons $ algTyConRhs tc) }}++ | Just ty <- synTyConRhs_maybe tc+ = irTcTyVars tc $+ irType emptyVarSet ty++ | otherwise+ = return ()++-- any type variable used in an associated type must be Nominal+irClass :: Class -> RoleM ()+irClass cls+ = mapM_ ir_at (classATs cls)+ where+ cls_tvs = classTyVars cls+ cls_tv_set = mkVarSet cls_tvs++ ir_at at_tc+ = mapM_ (updateRole Nominal) nvars+ where nvars = filter (`elemVarSet` cls_tv_set) $ tyConTyVars at_tc++-- See Note [Role inference]+irDataCon :: DataCon -> RoleM ()+irDataCon datacon+ = setRoleInferenceVars univ_tvs $+ irExTyVars ex_tvs $ \ ex_var_set ->+ mapM_ (irType ex_var_set)+ (map tyVarKind ex_tvs ++ eqSpecPreds eq_spec ++ theta ++ arg_tys)+ -- See Note [Role-checking data constructor arguments]+ where+ (univ_tvs, ex_tvs, eq_spec, theta, arg_tys, _res_ty)+ = dataConFullSig datacon++irType :: VarSet -> Type -> RoleM ()+irType = go+ where+ go lcls (TyVarTy tv) = unless (tv `elemVarSet` lcls) $+ updateRole Representational tv+ go lcls (AppTy t1 t2) = go lcls t1 >> markNominal lcls t2+ go lcls (TyConApp tc tys) = do { roles <- lookupRolesX tc+ ; zipWithM_ (go_app lcls) roles tys }+ go lcls (ForAllTy tvb ty) = do { let tv = binderVar tvb+ lcls' = extendVarSet lcls tv+ ; markNominal lcls (tyVarKind tv)+ ; go lcls' ty }+ go lcls (FunTy arg res) = go lcls arg >> go lcls res+ go _ (LitTy {}) = return ()+ -- See Note [Coercions in role inference]+ go lcls (CastTy ty _) = go lcls ty+ go _ (CoercionTy _) = return ()++ go_app _ Phantom _ = return () -- nothing to do here+ go_app lcls Nominal ty = markNominal lcls ty -- all vars below here are N+ go_app lcls Representational ty = go lcls ty++irTcTyVars :: TyCon -> RoleM a -> RoleM a+irTcTyVars tc thing+ = setRoleInferenceTc (tyConName tc) $ go (tyConTyVars tc)+ where+ go [] = thing+ go (tv:tvs) = do { markNominal emptyVarSet (tyVarKind tv)+ ; addRoleInferenceVar tv $ go tvs }++irExTyVars :: [TyVar] -> (TyVarSet -> RoleM a) -> RoleM a+irExTyVars orig_tvs thing = go emptyVarSet orig_tvs+ where+ go lcls [] = thing lcls+ go lcls (tv:tvs) = do { markNominal lcls (tyVarKind tv)+ ; go (extendVarSet lcls tv) tvs }++markNominal :: TyVarSet -- local variables+ -> Type -> RoleM ()+markNominal lcls ty = let nvars = fvVarList (FV.delFVs lcls $ get_ty_vars ty) in+ mapM_ (updateRole Nominal) nvars+ where+ -- get_ty_vars gets all the tyvars (no covars!) from a type *without*+ -- recurring into coercions. Recall: coercions are totally ignored during+ -- role inference. See [Coercions in role inference]+ get_ty_vars :: Type -> FV+ get_ty_vars (TyVarTy tv) = unitFV tv+ get_ty_vars (AppTy t1 t2) = get_ty_vars t1 `unionFV` get_ty_vars t2+ get_ty_vars (FunTy t1 t2) = get_ty_vars t1 `unionFV` get_ty_vars t2+ get_ty_vars (TyConApp _ tys) = mapUnionFV get_ty_vars tys+ get_ty_vars (ForAllTy tvb ty) = tyCoFVsBndr tvb (get_ty_vars ty)+ get_ty_vars (LitTy {}) = emptyFV+ get_ty_vars (CastTy ty _) = get_ty_vars ty+ get_ty_vars (CoercionTy _) = emptyFV++-- like lookupRoles, but with Nominal tags at the end for oversaturated TyConApps+lookupRolesX :: TyCon -> RoleM [Role]+lookupRolesX tc+ = do { roles <- lookupRoles tc+ ; return $ roles ++ repeat Nominal }++-- gets the roles either from the environment or the tycon+lookupRoles :: TyCon -> RoleM [Role]+lookupRoles tc+ = do { env <- getRoleEnv+ ; case lookupNameEnv env (tyConName tc) of+ Just roles -> return roles+ Nothing -> return $ tyConRoles tc }++-- tries to update a role; won't ever update a role "downwards"+updateRole :: Role -> TyVar -> RoleM ()+updateRole role tv+ = do { var_ns <- getVarNs+ ; name <- getTyConName+ ; case lookupVarEnv var_ns tv of+ Nothing -> pprPanic "updateRole" (ppr name $$ ppr tv $$ ppr var_ns)+ Just n -> updateRoleEnv name n role }++-- the state in the RoleM monad+data RoleInferenceState = RIS { role_env :: RoleEnv+ , update :: Bool }++-- the environment in the RoleM monad+type VarPositions = VarEnv Int++-- See [Role inference]+newtype RoleM a = RM { unRM :: Maybe Name -- of the tycon+ -> VarPositions+ -> Int -- size of VarPositions+ -> RoleInferenceState+ -> (a, RoleInferenceState) }++instance Functor RoleM where+ fmap = liftM++instance Applicative RoleM where+ pure x = RM $ \_ _ _ state -> (x, state)+ (<*>) = ap++instance Monad RoleM where+ a >>= f = RM $ \m_info vps nvps state ->+ let (a', state') = unRM a m_info vps nvps state in+ unRM (f a') m_info vps nvps state'++runRoleM :: RoleEnv -> RoleM () -> (RoleEnv, Bool)+runRoleM env thing = (env', update)+ where RIS { role_env = env', update = update }+ = snd $ unRM thing Nothing emptyVarEnv 0 state+ state = RIS { role_env = env+ , update = False }++setRoleInferenceTc :: Name -> RoleM a -> RoleM a+setRoleInferenceTc name thing = RM $ \m_name vps nvps state ->+ ASSERT( isNothing m_name )+ ASSERT( isEmptyVarEnv vps )+ ASSERT( nvps == 0 )+ unRM thing (Just name) vps nvps state++addRoleInferenceVar :: TyVar -> RoleM a -> RoleM a+addRoleInferenceVar tv thing+ = RM $ \m_name vps nvps state ->+ ASSERT( isJust m_name )+ unRM thing m_name (extendVarEnv vps tv nvps) (nvps+1) state++setRoleInferenceVars :: [TyVar] -> RoleM a -> RoleM a+setRoleInferenceVars tvs thing+ = RM $ \m_name _vps _nvps state ->+ ASSERT( isJust m_name )+ unRM thing m_name (mkVarEnv (zip tvs [0..])) (panic "setRoleInferenceVars")+ state++getRoleEnv :: RoleM RoleEnv+getRoleEnv = RM $ \_ _ _ state@(RIS { role_env = env }) -> (env, state)++getVarNs :: RoleM VarPositions+getVarNs = RM $ \_ vps _ state -> (vps, state)++getTyConName :: RoleM Name+getTyConName = RM $ \m_name _ _ state ->+ case m_name of+ Nothing -> panic "getTyConName"+ Just name -> (name, state)++updateRoleEnv :: Name -> Int -> Role -> RoleM ()+updateRoleEnv name n role+ = RM $ \_ _ _ state@(RIS { role_env = role_env }) -> ((),+ case lookupNameEnv role_env name of+ Nothing -> pprPanic "updateRoleEnv" (ppr name)+ Just roles -> let (before, old_role : after) = splitAt n roles in+ if role `ltRole` old_role+ then let roles' = before ++ role : after+ role_env' = extendNameEnv role_env name roles' in+ RIS { role_env = role_env', update = True }+ else state )+++{- *********************************************************************+* *+ Building implicits+* *+********************************************************************* -}++tcAddImplicits :: [TyCon] -> TcM TcGblEnv+-- Given a [TyCon], add to the TcGblEnv+-- * extend the TypeEnv with their implicitTyThings+-- * extend the TypeEnv with any default method Ids+-- * add bindings for record selectors+-- * add bindings for type representations for the TyThings+tcAddImplicits tycons+ = discardWarnings $+ tcExtendGlobalEnvImplicit implicit_things $+ tcExtendGlobalValEnv def_meth_ids $+ do { traceTc "tcAddImplicits" $ vcat+ [ text "tycons" <+> ppr tycons+ , text "implicits" <+> ppr implicit_things ]+ ; tcRecSelBinds (mkRecSelBinds tycons) }+ where+ implicit_things = concatMap implicitTyConThings tycons+ def_meth_ids = mkDefaultMethodIds tycons++mkDefaultMethodIds :: [TyCon] -> [Id]+-- We want to put the default-method Ids (both vanilla and generic)+-- into the type environment so that they are found when we typecheck+-- the filled-in default methods of each instance declaration+-- See Note [Default method Ids and Template Haskell]+mkDefaultMethodIds tycons+ = [ mkExportedVanillaId dm_name (mkDefaultMethodType cls sel_id dm_spec)+ | tc <- tycons+ , Just cls <- [tyConClass_maybe tc]+ , (sel_id, Just (dm_name, dm_spec)) <- classOpItems cls ]++mkDefaultMethodType :: Class -> Id -> DefMethSpec Type -> Type+-- Returns the top-level type of the default method+mkDefaultMethodType _ sel_id VanillaDM = idType sel_id+mkDefaultMethodType cls _ (GenericDM dm_ty) = mkSpecSigmaTy cls_tvs [pred] dm_ty+ where+ cls_tvs = classTyVars cls+ pred = mkClassPred cls (mkTyVarTys cls_tvs)++{-+************************************************************************+* *+ Building record selectors+* *+************************************************************************+-}++{-+Note [Default method Ids and Template Haskell]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this (Trac #4169):+ class Numeric a where+ fromIntegerNum :: a+ fromIntegerNum = ...++ ast :: Q [Dec]+ ast = [d| instance Numeric Int |]++When we typecheck 'ast' we have done the first pass over the class decl+(in tcTyClDecls), but we have not yet typechecked the default-method+declarations (because they can mention value declarations). So we+must bring the default method Ids into scope first (so they can be seen+when typechecking the [d| .. |] quote, and typecheck them later.+-}++{-+************************************************************************+* *+ Building record selectors+* *+************************************************************************+-}++mkRecSelBinds :: [TyCon] -> HsValBinds Name+-- NB We produce *un-typechecked* bindings, rather like 'deriving'+-- This makes life easier, because the later type checking will add+-- all necessary type abstractions and applications+mkRecSelBinds tycons+ = ValBindsOut binds sigs+ where+ (sigs, binds) = unzip rec_sels+ rec_sels = map mkRecSelBind [ (tc,fld)+ | tc <- tycons+ , fld <- tyConFieldLabels tc ]++mkRecSelBind :: (TyCon, FieldLabel) -> (LSig Name, (RecFlag, LHsBinds Name))+mkRecSelBind (tycon, fl)+ = mkOneRecordSelector all_cons (RecSelData tycon) fl+ where+ all_cons = map RealDataCon (tyConDataCons tycon)++mkOneRecordSelector :: [ConLike] -> RecSelParent -> FieldLabel+ -> (LSig Name, (RecFlag, LHsBinds Name))+mkOneRecordSelector all_cons idDetails fl+ = (L loc (IdSig sel_id), (NonRecursive, unitBag (L loc sel_bind)))+ where+ loc = getSrcSpan sel_name+ lbl = flLabel fl+ sel_name = flSelector fl++ sel_id = mkExportedLocalId rec_details sel_name sel_ty+ rec_details = RecSelId { sel_tycon = idDetails, sel_naughty = is_naughty }++ -- Find a representative constructor, con1+ cons_w_field = conLikesWithFields all_cons [lbl]+ con1 = ASSERT( not (null cons_w_field) ) head cons_w_field++ -- Selector type; Note [Polymorphic selectors]+ field_ty = conLikeFieldType con1 lbl+ data_tvs = tyCoVarsOfTypesWellScoped inst_tys+ data_tv_set= mkVarSet data_tvs+ is_naughty = not (tyCoVarsOfType field_ty `subVarSet` data_tv_set)+ (field_tvs, field_theta, field_tau) = tcSplitSigmaTy field_ty+ sel_ty | is_naughty = unitTy -- See Note [Naughty record selectors]+ | otherwise = mkSpecForAllTys data_tvs $+ mkPhiTy (conLikeStupidTheta con1) $ -- Urgh!+ mkFunTy data_ty $+ mkSpecForAllTys field_tvs $+ mkPhiTy field_theta $+ -- req_theta is empty for normal DataCon+ mkPhiTy req_theta $+ field_tau++ -- Make the binding: sel (C2 { fld = x }) = x+ -- sel (C7 { fld = x }) = x+ -- where cons_w_field = [C2,C7]+ sel_bind = mkTopFunBind Generated sel_lname alts+ where+ alts | is_naughty = [mkSimpleMatch (mkPrefixFunRhs sel_lname)+ [] unit_rhs]+ | otherwise = map mk_match cons_w_field ++ deflt+ mk_match con = mkSimpleMatch (mkPrefixFunRhs sel_lname)+ [L loc (mk_sel_pat con)]+ (L loc (HsVar (L loc field_var)))+ mk_sel_pat con = ConPatIn (L loc (getName con)) (RecCon rec_fields)+ rec_fields = HsRecFields { rec_flds = [rec_field], rec_dotdot = Nothing }+ rec_field = noLoc (HsRecField+ { hsRecFieldLbl+ = L loc (FieldOcc (L loc $ mkVarUnqual lbl) sel_name)+ , hsRecFieldArg = L loc (VarPat (L loc field_var))+ , hsRecPun = False })+ sel_lname = L loc sel_name+ field_var = mkInternalName (mkBuiltinUnique 1) (getOccName sel_name) loc++ -- Add catch-all default case unless the case is exhaustive+ -- We do this explicitly so that we get a nice error message that+ -- mentions this particular record selector+ deflt | all dealt_with all_cons = []+ | otherwise = [mkSimpleMatch CaseAlt+ [L loc (WildPat placeHolderType)]+ (mkHsApp (L loc (HsVar+ (L loc (getName rEC_SEL_ERROR_ID))))+ (L loc (HsLit msg_lit)))]++ -- Do not add a default case unless there are unmatched+ -- constructors. We must take account of GADTs, else we+ -- get overlap warning messages from the pattern-match checker+ -- NB: we need to pass type args for the *representation* TyCon+ -- to dataConCannotMatch, hence the calculation of inst_tys+ -- This matters in data families+ -- data instance T Int a where+ -- A :: { fld :: Int } -> T Int Bool+ -- B :: { fld :: Int } -> T Int Char+ dealt_with :: ConLike -> Bool+ dealt_with (PatSynCon _) = False -- We can't predict overlap+ dealt_with con@(RealDataCon dc) =+ con `elem` cons_w_field || dataConCannotMatch inst_tys dc++ (univ_tvs, _, eq_spec, _, req_theta, _, data_ty) = conLikeFullSig con1++ eq_subst = mkTvSubstPrs (map eqSpecPair eq_spec)+ inst_tys = substTyVars eq_subst univ_tvs++ unit_rhs = mkLHsTupleExpr []+ msg_lit = HsStringPrim NoSourceText (fastStringToByteString lbl)++{-+Note [Polymorphic selectors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We take care to build the type of a polymorphic selector in the right+order, so that visible type application works.++ data Ord a => T a = MkT { field :: forall b. (Num a, Show b) => (a, b) }++We want++ field :: forall a. Ord a => T a -> forall b. (Num a, Show b) => (a, b)++Note [Naughty record selectors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A "naughty" field is one for which we can't define a record+selector, because an existential type variable would escape. For example:+ data T = forall a. MkT { x,y::a }+We obviously can't define+ x (MkT v _) = v+Nevertheless we *do* put a RecSelId into the type environment+so that if the user tries to use 'x' as a selector we can bleat+helpfully, rather than saying unhelpfully that 'x' is not in scope.+Hence the sel_naughty flag, to identify record selectors that don't really exist.++In general, a field is "naughty" if its type mentions a type variable that+isn't in the result type of the constructor. Note that this *allows*+GADT record selectors (Note [GADT record selectors]) whose types may look+like sel :: T [a] -> a++For naughty selectors we make a dummy binding+ sel = ()+so that the later type-check will add them to the environment, and they'll be+exported. The function is never called, because the typechecker spots the+sel_naughty field.++Note [GADT record selectors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For GADTs, we require that all constructors with a common field 'f' have the same+result type (modulo alpha conversion). [Checked in TcTyClsDecls.checkValidTyCon]+E.g.+ data T where+ T1 { f :: Maybe a } :: T [a]+ T2 { f :: Maybe a, y :: b } :: T [a]+ T3 :: T Int++and now the selector takes that result type as its argument:+ f :: forall a. T [a] -> Maybe a++Details: the "real" types of T1,T2 are:+ T1 :: forall r a. (r~[a]) => a -> T r+ T2 :: forall r a b. (r~[a]) => a -> b -> T r++So the selector loooks like this:+ f :: forall a. T [a] -> Maybe a+ f (a:*) (t:T [a])+ = case t of+ T1 c (g:[a]~[c]) (v:Maybe c) -> v `cast` Maybe (right (sym g))+ T2 c d (g:[a]~[c]) (v:Maybe c) (w:d) -> v `cast` Maybe (right (sym g))+ T3 -> error "T3 does not have field f"++Note the forall'd tyvars of the selector are just the free tyvars+of the result type; there may be other tyvars in the constructor's+type (e.g. 'b' in T2).++Note the need for casts in the result!++Note [Selector running example]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's OK to combine GADTs and type families. Here's a running example:++ data instance T [a] where+ T1 { fld :: b } :: T [Maybe b]++The representation type looks like this+ data :R7T a where+ T1 { fld :: b } :: :R7T (Maybe b)++and there's coercion from the family type to the representation type+ :CoR7T a :: T [a] ~ :R7T a++The selector we want for fld looks like this:++ fld :: forall b. T [Maybe b] -> b+ fld = /\b. \(d::T [Maybe b]).+ case d `cast` :CoR7T (Maybe b) of+ T1 (x::b) -> x++The scrutinee of the case has type :R7T (Maybe b), which can be+gotten by appying the eq_spec to the univ_tvs of the data con.++-}
+ typecheck/TcType.hs view
@@ -0,0 +1,2576 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[TcType]{Types used in the typechecker}++This module provides the Type interface for front-end parts of the+compiler. These parts++ * treat "source types" as opaque:+ newtypes, and predicates are meaningful.+ * look through usage types++The "tc" prefix is for "TypeChecker", because the type checker+is the principal client.+-}++{-# LANGUAGE CPP, MultiWayIf, FlexibleContexts #-}++module TcType (+ --------------------------------+ -- Types+ TcType, TcSigmaType, TcRhoType, TcTauType, TcPredType, TcThetaType,+ TcTyVar, TcTyVarSet, TcDTyVarSet, TcTyCoVarSet, TcDTyCoVarSet,+ TcKind, TcCoVar, TcTyCoVar, TcTyVarBinder, TcTyCon,++ ExpType(..), InferResult(..), ExpSigmaType, ExpRhoType, mkCheckExpType,++ SyntaxOpType(..), synKnownType, mkSynFunTys,++ -- TcLevel+ TcLevel(..), topTcLevel, pushTcLevel, isTopTcLevel,+ strictlyDeeperThan, sameDepthAs, fmvTcLevel,+ tcTypeLevel, tcTyVarLevel, maxTcLevel,++ --------------------------------+ -- MetaDetails+ UserTypeCtxt(..), pprUserTypeCtxt, isSigMaybe,+ TcTyVarDetails(..), pprTcTyVarDetails, vanillaSkolemTv, superSkolemTv,+ MetaDetails(Flexi, Indirect), MetaInfo(..),+ isImmutableTyVar, isSkolemTyVar, isMetaTyVar, isMetaTyVarTy, isTyVarTy,+ isSigTyVar, isOverlappableTyVar, isTyConableTyVar,+ isFskTyVar, isFmvTyVar, isFlattenTyVar,+ isAmbiguousTyVar, metaTyVarRef, metaTyVarInfo,+ isFlexi, isIndirect, isRuntimeUnkSkol,+ metaTyVarTcLevel, setMetaTyVarTcLevel, metaTyVarTcLevel_maybe,+ isTouchableMetaTyVar, isTouchableOrFmv,+ isFloatedTouchableMetaTyVar,++ --------------------------------+ -- Builders+ mkPhiTy, mkInfSigmaTy, mkSpecSigmaTy, mkSigmaTy,+ mkNakedTyConApp, mkNakedAppTys, mkNakedAppTy,+ mkNakedCastTy,++ --------------------------------+ -- Splitters+ -- These are important because they do not look through newtypes+ getTyVar,+ tcSplitForAllTy_maybe,+ tcSplitForAllTys, tcSplitPiTys, tcSplitForAllTyVarBndrs,+ tcSplitPhiTy, tcSplitPredFunTy_maybe,+ tcSplitFunTy_maybe, tcSplitFunTys, tcFunArgTy, tcFunResultTy, tcFunResultTyN,+ tcSplitFunTysN,+ tcSplitTyConApp, tcSplitTyConApp_maybe,+ tcRepSplitTyConApp_maybe, tcRepSplitTyConApp_maybe',+ tcTyConAppTyCon, tcTyConAppTyCon_maybe, tcTyConAppArgs,+ tcSplitAppTy_maybe, tcSplitAppTy, tcSplitAppTys, tcRepSplitAppTy_maybe,+ tcGetTyVar_maybe, tcGetTyVar, nextRole,+ tcSplitSigmaTy, tcSplitNestedSigmaTys, tcDeepSplitSigmaTy_maybe,++ ---------------------------------+ -- Predicates.+ -- Again, newtypes are opaque+ eqType, eqTypes, nonDetCmpType, nonDetCmpTypes, eqTypeX,+ pickyEqType, tcEqType, tcEqKind, tcEqTypeNoKindCheck, tcEqTypeVis,+ isSigmaTy, isRhoTy, isRhoExpTy, isOverloadedTy,+ isFloatingTy, isDoubleTy, isFloatTy, isIntTy, isWordTy, isStringTy,+ isIntegerTy, isBoolTy, isUnitTy, isCharTy, isCallStackTy, isCallStackPred,+ isTauTy, isTauTyCon, tcIsTyVarTy, tcIsForAllTy,+ isPredTy, isTyVarClassPred, isTyVarExposed, isInsolubleOccursCheck,+ checkValidClsArgs, hasTyVarHead,+ isRigidEqPred, isRigidTy,++ ---------------------------------+ -- Misc type manipulators++ deNoteType,+ orphNamesOfType, orphNamesOfCo,+ orphNamesOfTypes, orphNamesOfCoCon,+ getDFunTyKey,+ evVarPred_maybe, evVarPred,++ ---------------------------------+ -- Predicate types+ mkMinimalBySCs, transSuperClasses,+ pickQuantifiablePreds, pickCapturedPreds,+ immSuperClasses,+ isImprovementPred,++ -- * Finding type instances+ tcTyFamInsts,++ -- * Finding "exact" (non-dead) type variables+ exactTyCoVarsOfType, exactTyCoVarsOfTypes,+ candidateQTyVarsOfType, candidateQTyVarsOfTypes, CandidatesQTvs(..),+ anyRewritableTyVar,++ -- * Extracting bound variables+ allBoundVariables, allBoundVariabless,++ ---------------------------------+ -- Foreign import and export+ isFFIArgumentTy, -- :: DynFlags -> Safety -> Type -> Bool+ isFFIImportResultTy, -- :: DynFlags -> Type -> Bool+ isFFIExportResultTy, -- :: Type -> Bool+ isFFIExternalTy, -- :: Type -> Bool+ isFFIDynTy, -- :: Type -> Type -> Bool+ isFFIPrimArgumentTy, -- :: DynFlags -> Type -> Bool+ isFFIPrimResultTy, -- :: DynFlags -> Type -> Bool+ isFFILabelTy, -- :: Type -> Bool+ isFFITy, -- :: Type -> Bool+ isFunPtrTy, -- :: Type -> Bool+ tcSplitIOType_maybe, -- :: Type -> Maybe Type++ --------------------------------+ -- Rexported from Kind+ Kind, typeKind,+ liftedTypeKind,+ constraintKind,+ isLiftedTypeKind, isUnliftedTypeKind, classifiesTypeWithValues,++ --------------------------------+ -- Rexported from Type+ Type, PredType, ThetaType, TyBinder, ArgFlag(..),++ mkForAllTy, mkForAllTys, mkInvForAllTys, mkSpecForAllTys, mkInvForAllTy,+ mkFunTy, mkFunTys,+ mkTyConApp, mkAppTy, mkAppTys,+ mkTyConTy, mkTyVarTy,+ mkTyVarTys,++ isClassPred, isEqPred, isNomEqPred, isIPPred,+ mkClassPred,+ isDictLikeTy,+ tcSplitDFunTy, tcSplitDFunHead, tcSplitMethodTy,+ isRuntimeRepVar, isKindLevPoly,+ isVisibleBinder, isInvisibleBinder,++ -- Type substitutions+ TCvSubst(..), -- Representation visible to a few friends+ TvSubstEnv, emptyTCvSubst,+ zipTvSubst,+ mkTvSubstPrs, notElemTCvSubst, unionTCvSubst,+ getTvSubstEnv, setTvSubstEnv, getTCvInScope, extendTCvInScope,+ extendTCvInScopeList, extendTCvInScopeSet, extendTvSubstAndInScope,+ Type.lookupTyVar, Type.extendTCvSubst, Type.substTyVarBndr,+ Type.extendTvSubst,+ isInScope, mkTCvSubst, mkTvSubst, zipTyEnv, zipCoEnv,+ Type.substTy, substTys, substTyWith, substTyWithCoVars,+ substTyAddInScope,+ substTyUnchecked, substTysUnchecked, substThetaUnchecked,+ substTyWithUnchecked,+ substCoUnchecked, substCoWithUnchecked,+ substTheta,++ isUnliftedType, -- Source types are always lifted+ isUnboxedTupleType, -- Ditto+ isPrimitiveType,++ tcView, coreView,++ tyCoVarsOfType, tyCoVarsOfTypes, closeOverKinds,+ tyCoFVsOfType, tyCoFVsOfTypes,+ tyCoVarsOfTypeDSet, tyCoVarsOfTypesDSet, closeOverKindsDSet,+ tyCoVarsOfTypeList, tyCoVarsOfTypesList,+ noFreeVarsOfType,++ --------------------------------+ -- Transforming Types to TcTypes+ toTcType, -- :: Type -> TcType+ toTcTypeBag, -- :: Bag EvVar -> Bag EvVar++ pprKind, pprParendKind, pprSigmaType,+ pprType, pprParendType, pprTypeApp, pprTyThingCategory, tyThingCategory,+ pprTheta, pprThetaArrowTy, pprClassPred,+ pprTvBndr, pprTvBndrs,++ TypeSize, sizeType, sizeTypes, toposortTyVars++ ) where++#include "HsVersions.h"++-- friends:+import Kind+import TyCoRep+import Class+import Var+import ForeignCall+import VarSet+import Coercion+import Type+import RepType+import TyCon++-- others:+import DynFlags+import CoreFVs+import Name -- hiding (varName)+ -- We use this to make dictionaries for type literals.+ -- Perhaps there's a better way to do this?+import NameSet+import VarEnv+import PrelNames+import TysWiredIn( coercibleClass, unitTyCon, unitTyConKey+ , listTyCon, constraintKind )+import BasicTypes+import Util+import Bag+import Maybes+import Outputable+import FastString+import ErrUtils( Validity(..), MsgDoc, isValid )+import FV+import qualified GHC.LanguageExtensions as LangExt++import Data.IORef+import Data.Functor.Identity++{-+************************************************************************+* *+ Types+* *+************************************************************************++The type checker divides the generic Type world into the+following more structured beasts:++sigma ::= forall tyvars. phi+ -- A sigma type is a qualified type+ --+ -- Note that even if 'tyvars' is empty, theta+ -- may not be: e.g. (?x::Int) => Int++ -- Note that 'sigma' is in prenex form:+ -- all the foralls are at the front.+ -- A 'phi' type has no foralls to the right of+ -- an arrow++phi :: theta => rho++rho ::= sigma -> rho+ | tau++-- A 'tau' type has no quantification anywhere+-- Note that the args of a type constructor must be taus+tau ::= tyvar+ | tycon tau_1 .. tau_n+ | tau_1 tau_2+ | tau_1 -> tau_2++-- In all cases, a (saturated) type synonym application is legal,+-- provided it expands to the required form.++Note [TcTyVars in the typechecker]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The typechecker uses a lot of type variables with special properties,+notably being a unification variable with a mutable reference. These+use the 'TcTyVar' variant of Var.Var.++However, the type checker and constraint solver can encounter type+variables that use the 'TyVar' variant of Var.Var, for a couple of+reasons:++ - When unifying or flattening under (forall a. ty)++ - When typechecking a class decl, say+ class C (a :: k) where+ foo :: T a -> Int+ We have first kind-check the header; fix k and (a:k) to be+ TyVars, bring 'k' and 'a' into scope, and kind check the+ signature for 'foo'. In doing so we call solveEqualities to+ solve any kind equalities in foo's signature. So the solver+ may see free occurrences of 'k'.++It's convenient to simply treat these TyVars as skolem constants,+which of course they are. So++* Var.tcTyVarDetails succeeds on a TyVar, returning+ vanillaSkolemTv, as well as on a TcTyVar.++* tcIsTcTyVar returns True for both TyVar and TcTyVar variants+ of Var.Var. The "tc" prefix means "a type variable that can be+ encountered by the typechecker".++This is a bit of a change from an earlier era when we remoselessly+insisted on real TcTyVars in the type checker. But that seems+unnecessary (for skolems, TyVars are fine) and it's now very hard+to guarantee, with the advent of kind equalities.++Note [Coercion variables in free variable lists]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+There are several places in the GHC codebase where functions like+tyCoVarsOfType, tyCoVarsOfCt, et al. are used to compute the free type+variables of a type. The "Co" part of these functions' names shouldn't be+dismissed, as it is entirely possible that they will include coercion variables+in addition to type variables! As a result, there are some places in TcType+where we must take care to check that a variable is a _type_ variable (using+isTyVar) before calling tcTyVarDetails--a partial function that is not defined+for coercion variables--on the variable. Failing to do so led to+GHC Trac #12785.+-}++-- See Note [TcTyVars in the typechecker]+type TcTyVar = TyVar -- Used only during type inference+type TcCoVar = CoVar -- Used only during type inference+type TcType = Type -- A TcType can have mutable type variables+type TcTyCoVar = Var -- Either a TcTyVar or a CoVar+ -- Invariant on ForAllTy in TcTypes:+ -- forall a. T+ -- a cannot occur inside a MutTyVar in T; that is,+ -- T is "flattened" before quantifying over a++type TcTyVarBinder = TyVarBinder+type TcTyCon = TyCon -- these can be the TcTyCon constructor++-- These types do not have boxy type variables in them+type TcPredType = PredType+type TcThetaType = ThetaType+type TcSigmaType = TcType+type TcRhoType = TcType -- Note [TcRhoType]+type TcTauType = TcType+type TcKind = Kind+type TcTyVarSet = TyVarSet+type TcTyCoVarSet = TyCoVarSet+type TcDTyVarSet = DTyVarSet+type TcDTyCoVarSet = DTyCoVarSet+++{- *********************************************************************+* *+ ExpType: an "expected type" in the type checker+* *+********************************************************************* -}++-- | An expected type to check against during type-checking.+-- See Note [ExpType] in TcMType, where you'll also find manipulators.+data ExpType = Check TcType+ | Infer !InferResult++data InferResult+ = IR { ir_uniq :: Unique -- For debugging only+ , ir_lvl :: TcLevel -- See Note [TcLevel of ExpType] in TcMType+ , ir_inst :: Bool -- True <=> deeply instantiate before returning+ -- i.e. return a RhoType+ -- False <=> do not instantiate before returning+ -- i.e. return a SigmaType+ , ir_ref :: IORef (Maybe TcType) }+ -- The type that fills in this hole should be a Type,+ -- that is, its kind should be (TYPE rr) for some rr++type ExpSigmaType = ExpType+type ExpRhoType = ExpType++instance Outputable ExpType where+ ppr (Check ty) = text "Check" <> braces (ppr ty)+ ppr (Infer ir) = ppr ir++instance Outputable InferResult where+ ppr (IR { ir_uniq = u, ir_lvl = lvl+ , ir_inst = inst })+ = text "Infer" <> braces (ppr u <> comma <> ppr lvl <+> ppr inst)++-- | Make an 'ExpType' suitable for checking.+mkCheckExpType :: TcType -> ExpType+mkCheckExpType = Check+++{- *********************************************************************+* *+ SyntaxOpType+* *+********************************************************************* -}++-- | What to expect for an argument to a rebindable-syntax operator.+-- Quite like 'Type', but allows for holes to be filled in by tcSyntaxOp.+-- The callback called from tcSyntaxOp gets a list of types; the meaning+-- of these types is determined by a left-to-right depth-first traversal+-- of the 'SyntaxOpType' tree. So if you pass in+--+-- > SynAny `SynFun` (SynList `SynFun` SynType Int) `SynFun` SynAny+--+-- you'll get three types back: one for the first 'SynAny', the /element/+-- type of the list, and one for the last 'SynAny'. You don't get anything+-- for the 'SynType', because you've said positively that it should be an+-- Int, and so it shall be.+--+-- This is defined here to avoid defining it in TcExpr.hs-boot.+data SyntaxOpType+ = SynAny -- ^ Any type+ | SynRho -- ^ A rho type, deeply skolemised or instantiated as appropriate+ | SynList -- ^ A list type. You get back the element type of the list+ | SynFun SyntaxOpType SyntaxOpType+ -- ^ A function.+ | SynType ExpType -- ^ A known type.+infixr 0 `SynFun`++-- | Like 'SynType' but accepts a regular TcType+synKnownType :: TcType -> SyntaxOpType+synKnownType = SynType . mkCheckExpType++-- | Like 'mkFunTys' but for 'SyntaxOpType'+mkSynFunTys :: [SyntaxOpType] -> ExpType -> SyntaxOpType+mkSynFunTys arg_tys res_ty = foldr SynFun (SynType res_ty) arg_tys+++{-+Note [TcRhoType]+~~~~~~~~~~~~~~~~+A TcRhoType has no foralls or contexts at the top, or to the right of an arrow+ YES (forall a. a->a) -> Int+ NO forall a. a -> Int+ NO Eq a => a -> a+ NO Int -> forall a. a -> Int+++************************************************************************+* *+ TyVarDetails, MetaDetails, MetaInfo+* *+************************************************************************++TyVarDetails gives extra info about type variables, used during type+checking. It's attached to mutable type variables only.+It's knot-tied back to Var.hs. There is no reason in principle+why Var.hs shouldn't actually have the definition, but it "belongs" here.++Note [Signature skolems]+~~~~~~~~~~~~~~~~~~~~~~~~+A SigTv is a specialised variant of TauTv, with the following invarints:++ * A SigTv can be unified only with a TyVar,+ not with any other type++ * Its MetaDetails, if filled in, will always be another SigTv+ or a SkolemTv++SigTvs are only distinguished to improve error messages.+Consider this++ f :: forall a. [a] -> Int+ f (x::b : xs) = 3++Here 'b' is a lexically scoped type variable, but it turns out to be+the same as the skolem 'a'. So we make them both SigTvs, which can unify+with each other.++Similarly consider+ data T (a:k1) = MkT (S a)+ data S (b:k2) = MkS (T b)+When doing kind inference on {S,T} we don't want *skolems* for k1,k2,+because they end up unifying; we want those SigTvs again.++SigTvs are used *only* for pattern type signatures.++Note [TyVars and TcTyVars during type checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The Var type has constructors TyVar and TcTyVar. They are used+as follows:++* TcTyVar: used /only/ during type checking. Should never appear+ afterwards. May contain a mutable field, in the MetaTv case.++* TyVar: is never seen by the constraint solver, except locally+ inside a type like (forall a. [a] ->[a]), where 'a' is a TyVar.+ We instantiate these with TcTyVars before exposing the type+ to the constraint solver.++I have swithered about the latter invariant, excluding TyVars from the+constraint solver. It's not strictly essential, and indeed+(historically but still there) Var.tcTyVarDetails returns+vanillaSkolemTv for a TyVar.++But ultimately I want to seeparate Type from TcType, and in that case+we would need to enforce the separation.+-}++-- A TyVarDetails is inside a TyVar+-- See Note [TyVars and TcTyVars]+data TcTyVarDetails+ = SkolemTv -- A skolem+ TcLevel -- Level of the implication that binds it+ Bool -- True <=> this skolem type variable can be overlapped+ -- when looking up instances+ -- See Note [Binding when looking up instances] in InstEnv++ | FlatSkol -- A flatten-skolem. It stands for the TcType, and zonking+ TcType -- will replace it by that type.+ -- See Note [The flattening story] in TcFlatten++ | RuntimeUnk -- Stands for an as-yet-unknown type in the GHCi+ -- interactive context++ | MetaTv { mtv_info :: MetaInfo+ , mtv_ref :: IORef MetaDetails+ , mtv_tclvl :: TcLevel } -- See Note [TcLevel and untouchable type variables]++vanillaSkolemTv, superSkolemTv :: TcTyVarDetails+-- See Note [Binding when looking up instances] in InstEnv+vanillaSkolemTv = SkolemTv (pushTcLevel topTcLevel) False -- Might be instantiated+superSkolemTv = SkolemTv (pushTcLevel topTcLevel) True -- Treat this as a completely distinct type++-----------------------------+data MetaDetails+ = Flexi -- Flexi type variables unify to become Indirects+ | Indirect TcType++data MetaInfo+ = TauTv -- This MetaTv is an ordinary unification variable+ -- A TauTv is always filled in with a tau-type, which+ -- never contains any ForAlls.++ | SigTv -- A variant of TauTv, except that it should not be+ -- unified with a type, only with a type variable+ -- See Note [Signature skolems]++ | FlatMetaTv -- A flatten meta-tyvar+ -- It is a meta-tyvar, but it is always untouchable, with level 0+ -- See Note [The flattening story] in TcFlatten++instance Outputable MetaDetails where+ ppr Flexi = text "Flexi"+ ppr (Indirect ty) = text "Indirect" <+> ppr ty++pprTcTyVarDetails :: TcTyVarDetails -> SDoc+-- For debugging+pprTcTyVarDetails (RuntimeUnk {}) = text "rt"+pprTcTyVarDetails (FlatSkol {}) = text "fsk"+pprTcTyVarDetails (SkolemTv lvl True) = text "ssk" <> colon <> ppr lvl+pprTcTyVarDetails (SkolemTv lvl False) = text "sk" <> colon <> ppr lvl+pprTcTyVarDetails (MetaTv { mtv_info = info, mtv_tclvl = tclvl })+ = pp_info <> colon <> ppr tclvl+ where+ pp_info = case info of+ TauTv -> text "tau"+ SigTv -> text "sig"+ FlatMetaTv -> text "fuv"+++{- *********************************************************************+* *+ UserTypeCtxt+* *+********************************************************************* -}++-------------------------------------+-- UserTypeCtxt describes the origin of the polymorphic type+-- in the places where we need to an expression has that type++data UserTypeCtxt+ = FunSigCtxt -- Function type signature, when checking the type+ -- Also used for types in SPECIALISE pragmas+ Name -- Name of the function+ Bool -- True <=> report redundant constraints+ -- This is usually True, but False for+ -- * Record selectors (not important here)+ -- * Class and instance methods. Here+ -- the code may legitimately be more+ -- polymorphic than the signature+ -- generated from the class+ -- declaration++ | InfSigCtxt Name -- Inferred type for function+ | ExprSigCtxt -- Expression type signature+ | TypeAppCtxt -- Visible type application+ | ConArgCtxt Name -- Data constructor argument+ | TySynCtxt Name -- RHS of a type synonym decl+ | PatSynCtxt Name -- Type sig for a pattern synonym+ | PatSigCtxt -- Type sig in pattern+ -- eg f (x::t) = ...+ -- or (x::t, y) = e+ | RuleSigCtxt Name -- LHS of a RULE forall+ -- RULE "foo" forall (x :: a -> a). f (Just x) = ...+ | ResSigCtxt -- Result type sig+ -- f x :: t = ....+ | ForSigCtxt Name -- Foreign import or export signature+ | DefaultDeclCtxt -- Types in a default declaration+ | InstDeclCtxt -- An instance declaration+ | SpecInstCtxt -- SPECIALISE instance pragma+ | ThBrackCtxt -- Template Haskell type brackets [t| ... |]+ | GenSigCtxt -- Higher-rank or impredicative situations+ -- e.g. (f e) where f has a higher-rank type+ -- We might want to elaborate this+ | GhciCtxt -- GHCi command :kind <type>++ | ClassSCCtxt Name -- Superclasses of a class+ | SigmaCtxt -- Theta part of a normal for-all type+ -- f :: <S> => a -> a+ | DataTyCtxt Name -- The "stupid theta" part of a data decl+ -- data <S> => T a = MkT a++{-+-- Notes re TySynCtxt+-- We allow type synonyms that aren't types; e.g. type List = []+--+-- If the RHS mentions tyvars that aren't in scope, we'll+-- quantify over them:+-- e.g. type T = a->a+-- will become type T = forall a. a->a+--+-- With gla-exts that's right, but for H98 we should complain.+-}+++pprUserTypeCtxt :: UserTypeCtxt -> SDoc+pprUserTypeCtxt (FunSigCtxt n _) = text "the type signature for" <+> quotes (ppr n)+pprUserTypeCtxt (InfSigCtxt n) = text "the inferred type for" <+> quotes (ppr n)+pprUserTypeCtxt (RuleSigCtxt n) = text "a RULE for" <+> quotes (ppr n)+pprUserTypeCtxt ExprSigCtxt = text "an expression type signature"+pprUserTypeCtxt TypeAppCtxt = text "a type argument"+pprUserTypeCtxt (ConArgCtxt c) = text "the type of the constructor" <+> quotes (ppr c)+pprUserTypeCtxt (TySynCtxt c) = text "the RHS of the type synonym" <+> quotes (ppr c)+pprUserTypeCtxt ThBrackCtxt = text "a Template Haskell quotation [t|...|]"+pprUserTypeCtxt PatSigCtxt = text "a pattern type signature"+pprUserTypeCtxt ResSigCtxt = text "a result type signature"+pprUserTypeCtxt (ForSigCtxt n) = text "the foreign declaration for" <+> quotes (ppr n)+pprUserTypeCtxt DefaultDeclCtxt = text "a type in a `default' declaration"+pprUserTypeCtxt InstDeclCtxt = text "an instance declaration"+pprUserTypeCtxt SpecInstCtxt = text "a SPECIALISE instance pragma"+pprUserTypeCtxt GenSigCtxt = text "a type expected by the context"+pprUserTypeCtxt GhciCtxt = text "a type in a GHCi command"+pprUserTypeCtxt (ClassSCCtxt c) = text "the super-classes of class" <+> quotes (ppr c)+pprUserTypeCtxt SigmaCtxt = text "the context of a polymorphic type"+pprUserTypeCtxt (DataTyCtxt tc) = text "the context of the data type declaration for" <+> quotes (ppr tc)+pprUserTypeCtxt (PatSynCtxt n) = text "the signature for pattern synonym" <+> quotes (ppr n)++isSigMaybe :: UserTypeCtxt -> Maybe Name+isSigMaybe (FunSigCtxt n _) = Just n+isSigMaybe (ConArgCtxt n) = Just n+isSigMaybe (ForSigCtxt n) = Just n+isSigMaybe (PatSynCtxt n) = Just n+isSigMaybe _ = Nothing+++{- *********************************************************************+* *+ Untoucable type variables+* *+********************************************************************* -}++newtype TcLevel = TcLevel Int deriving( Eq, Ord )+ -- See Note [TcLevel and untouchable type variables] for what this Int is+ -- See also Note [TcLevel assignment]++{-+Note [TcLevel and untouchable type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Each unification variable (MetaTv)+ and each Implication+ has a level number (of type TcLevel)++* INVARIANTS. In a tree of Implications,++ (ImplicInv) The level number of an Implication is+ STRICTLY GREATER THAN that of its parent++ (MetaTvInv) The level number of a unification variable is+ LESS THAN OR EQUAL TO that of its parent+ implication++* A unification variable is *touchable* if its level number+ is EQUAL TO that of its immediate parent implication.++* INVARIANT+ (GivenInv) The free variables of the ic_given of an+ implication are all untouchable; ie their level+ numbers are LESS THAN the ic_tclvl of the implication++Note [Skolem escape prevention]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We only unify touchable unification variables. Because of+(MetaTvInv), there can be no occurrences of the variable further out,+so the unification can't cause the skolems to escape. Example:+ data T = forall a. MkT a (a->Int)+ f x (MkT v f) = length [v,x]+We decide (x::alpha), and generate an implication like+ [1]forall a. (a ~ alpha[0])+But we must not unify alpha:=a, because the skolem would escape.++For the cases where we DO want to unify, we rely on floating the+equality. Example (with same T)+ g x (MkT v f) = x && True+We decide (x::alpha), and generate an implication like+ [1]forall a. (Bool ~ alpha[0])+We do NOT unify directly, bur rather float out (if the constraint+does not mention 'a') to get+ (Bool ~ alpha[0]) /\ [1]forall a.()+and NOW we can unify alpha.++The same idea of only unifying touchables solves another problem.+Suppose we had+ (F Int ~ uf[0]) /\ [1](forall a. C a => F Int ~ beta[1])+In this example, beta is touchable inside the implication. The+first solveSimpleWanteds step leaves 'uf' un-unified. Then we move inside+the implication where a new constraint+ uf ~ beta+emerges. If we (wrongly) spontaneously solved it to get uf := beta,+the whole implication disappears but when we pop out again we are left with+(F Int ~ uf) which will be unified by our final zonking stage and+uf will get unified *once more* to (F Int).++Note [TcLevel assignment]+~~~~~~~~~~~~~~~~~~~~~~~~~+We arrange the TcLevels like this++ 0 Level for flatten meta-vars+ 1 Top level+ 2 First-level implication constraints+ 3 Second-level implication constraints+ ...etc...++The flatten meta-vars are all at level 0, just to make them untouchable.+-}++maxTcLevel :: TcLevel -> TcLevel -> TcLevel+maxTcLevel (TcLevel a) (TcLevel b) = TcLevel (a `max` b)++fmvTcLevel :: TcLevel -> TcLevel+-- See Note [TcLevel assignment]+fmvTcLevel _ = TcLevel 0++topTcLevel :: TcLevel+-- See Note [TcLevel assignment]+topTcLevel = TcLevel 1 -- 1 = outermost level++isTopTcLevel :: TcLevel -> Bool+isTopTcLevel (TcLevel 1) = True+isTopTcLevel _ = False++pushTcLevel :: TcLevel -> TcLevel+-- See Note [TcLevel assignment]+pushTcLevel (TcLevel us) = TcLevel (us + 1)++strictlyDeeperThan :: TcLevel -> TcLevel -> Bool+strictlyDeeperThan (TcLevel tv_tclvl) (TcLevel ctxt_tclvl)+ = tv_tclvl > ctxt_tclvl++sameDepthAs :: TcLevel -> TcLevel -> Bool+sameDepthAs (TcLevel ctxt_tclvl) (TcLevel tv_tclvl)+ = ctxt_tclvl == tv_tclvl -- NB: invariant ctxt_tclvl >= tv_tclvl+ -- So <= would be equivalent++checkTcLevelInvariant :: TcLevel -> TcLevel -> Bool+-- Checks (MetaTvInv) from Note [TcLevel and untouchable type variables]+checkTcLevelInvariant (TcLevel ctxt_tclvl) (TcLevel tv_tclvl)+ = ctxt_tclvl >= tv_tclvl++tcTyVarLevel :: TcTyVar -> TcLevel+tcTyVarLevel tv+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv { mtv_tclvl = tv_lvl } -> tv_lvl+ SkolemTv tv_lvl _ -> tv_lvl+ FlatSkol ty -> tcTypeLevel ty+ RuntimeUnk -> topTcLevel++tcTypeLevel :: TcType -> TcLevel+-- Max level of any free var of the type+tcTypeLevel ty+ = foldDVarSet add topTcLevel (tyCoVarsOfTypeDSet ty)+ where+ add v lvl+ | isTcTyVar v = lvl `maxTcLevel` tcTyVarLevel v+ | otherwise = lvl++instance Outputable TcLevel where+ ppr (TcLevel us) = ppr us++{- *********************************************************************+* *+ Finding type family instances+* *+************************************************************************+-}++-- | Finds outermost type-family applications occuring in a type,+-- after expanding synonyms. In the list (F, tys) that is returned+-- we guarantee that tys matches F's arity. For example, given+-- type family F a :: * -> * (arity 1)+-- calling tcTyFamInsts on (Maybe (F Int Bool) will return+-- (F, [Int]), not (F, [Int,Bool])+--+-- This is important for its use in deciding termination of type+-- instances (see Trac #11581). E.g.+-- type instance G [Int] = ...(F Int <big type>)...+-- we don't need to take <big type> into account when asking if+-- the calls on the RHS are smaller than the LHS+tcTyFamInsts :: Type -> [(TyCon, [Type])]+tcTyFamInsts ty+ | Just exp_ty <- tcView ty = tcTyFamInsts exp_ty+tcTyFamInsts (TyVarTy _) = []+tcTyFamInsts (TyConApp tc tys)+ | isTypeFamilyTyCon tc = [(tc, take (tyConArity tc) tys)]+ | otherwise = concat (map tcTyFamInsts tys)+tcTyFamInsts (LitTy {}) = []+tcTyFamInsts (ForAllTy bndr ty) = tcTyFamInsts (binderKind bndr)+ ++ tcTyFamInsts ty+tcTyFamInsts (FunTy ty1 ty2) = tcTyFamInsts ty1 ++ tcTyFamInsts ty2+tcTyFamInsts (AppTy ty1 ty2) = tcTyFamInsts ty1 ++ tcTyFamInsts ty2+tcTyFamInsts (CastTy ty _) = tcTyFamInsts ty+tcTyFamInsts (CoercionTy _) = [] -- don't count tyfams in coercions,+ -- as they never get normalized, anyway++{-+************************************************************************+* *+ The "exact" free variables of a type+* *+************************************************************************++Note [Silly type synonym]+~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ type T a = Int+What are the free tyvars of (T x)? Empty, of course!+Here's the example that Ralf Laemmel showed me:+ foo :: (forall a. C u a -> C u a) -> u+ mappend :: Monoid u => u -> u -> u++ bar :: Monoid u => u+ bar = foo (\t -> t `mappend` t)+We have to generalise at the arg to f, and we don't+want to capture the constraint (Monad (C u a)) because+it appears to mention a. Pretty silly, but it was useful to him.++exactTyCoVarsOfType is used by the type checker to figure out exactly+which type variables are mentioned in a type. It's also used in the+smart-app checking code --- see TcExpr.tcIdApp++On the other hand, consider a *top-level* definition+ f = (\x -> x) :: T a -> T a+If we don't abstract over 'a' it'll get fixed to GHC.Prim.Any, and then+if we have an application like (f "x") we get a confusing error message+involving Any. So the conclusion is this: when generalising+ - at top level use tyCoVarsOfType+ - in nested bindings use exactTyCoVarsOfType+See Trac #1813 for example.+-}++exactTyCoVarsOfType :: Type -> TyCoVarSet+-- Find the free type variables (of any kind)+-- but *expand* type synonyms. See Note [Silly type synonym] above.+exactTyCoVarsOfType ty+ = go ty+ where+ go ty | Just ty' <- tcView ty = go ty' -- This is the key line+ go (TyVarTy tv) = unitVarSet tv `unionVarSet` go (tyVarKind tv)+ go (TyConApp _ tys) = exactTyCoVarsOfTypes tys+ go (LitTy {}) = emptyVarSet+ go (AppTy fun arg) = go fun `unionVarSet` go arg+ go (FunTy arg res) = go arg `unionVarSet` go res+ go (ForAllTy bndr ty) = delBinderVar (go ty) bndr `unionVarSet` go (binderKind bndr)+ go (CastTy ty co) = go ty `unionVarSet` goCo co+ go (CoercionTy co) = goCo co++ goCo (Refl _ ty) = go ty+ goCo (TyConAppCo _ _ args)= goCos args+ goCo (AppCo co arg) = goCo co `unionVarSet` goCo arg+ goCo (ForAllCo tv k_co co)+ = goCo co `delVarSet` tv `unionVarSet` goCo k_co+ goCo (FunCo _ co1 co2) = goCo co1 `unionVarSet` goCo co2+ goCo (CoVarCo v) = unitVarSet v `unionVarSet` go (varType v)+ goCo (AxiomInstCo _ _ args) = goCos args+ goCo (UnivCo p _ t1 t2) = goProv p `unionVarSet` go t1 `unionVarSet` go t2+ goCo (SymCo co) = goCo co+ goCo (TransCo co1 co2) = goCo co1 `unionVarSet` goCo co2+ goCo (NthCo _ co) = goCo co+ goCo (LRCo _ co) = goCo co+ goCo (InstCo co arg) = goCo co `unionVarSet` goCo arg+ goCo (CoherenceCo c1 c2) = goCo c1 `unionVarSet` goCo c2+ goCo (KindCo co) = goCo co+ goCo (SubCo co) = goCo co+ goCo (AxiomRuleCo _ c) = goCos c++ goCos cos = foldr (unionVarSet . goCo) emptyVarSet cos++ goProv UnsafeCoerceProv = emptyVarSet+ goProv (PhantomProv kco) = goCo kco+ goProv (ProofIrrelProv kco) = goCo kco+ goProv (PluginProv _) = emptyVarSet+ goProv (HoleProv _) = emptyVarSet++exactTyCoVarsOfTypes :: [Type] -> TyVarSet+exactTyCoVarsOfTypes tys = mapUnionVarSet exactTyCoVarsOfType tys++anyRewritableTyVar :: Bool -> (TcTyVar -> Bool)+ -> TcType -> Bool+-- (anyRewritableTyVar ignore_cos pred ty) returns True+-- if the 'pred' returns True of free TyVar in 'ty'+-- Do not look inside casts and coercions if 'ignore_cos' is True+-- See Note [anyRewritableTyVar]+anyRewritableTyVar ignore_cos pred ty+ = go emptyVarSet ty+ where+ go_tv bound tv | tv `elemVarSet` bound = False+ | otherwise = pred tv++ go bound (TyVarTy tv) = go_tv bound tv+ go _ (LitTy {}) = False+ go bound (TyConApp _ tys) = any (go bound) tys+ go bound (AppTy fun arg) = go bound fun || go bound arg+ go bound (FunTy arg res) = go bound arg || go bound res+ go bound (ForAllTy tv ty) = go (bound `extendVarSet` binderVar tv) ty+ go bound (CastTy ty co) = go bound ty || go_co bound co+ go bound (CoercionTy co) = go_co bound co++ go_co bound co+ | ignore_cos = False+ | otherwise = anyVarSet (go_tv bound) (tyCoVarsOfCo co)+ -- We don't have an equivalent of anyRewritableTyVar for coercions+ -- (at least not yet) so take the free vars and test them++{- Note [anyRewritableTyVar]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+anyRewritableTyVar is used during kick-out from the inert set,+to decide if, given a new equality (a ~ ty), we should kick out+a constraint C. Rather than gather free variables and see if 'a'+is among them, we instead pass in a predicate; this is just efficiency.+-}++{- *********************************************************************+* *+ Bound variables in a type+* *+********************************************************************* -}++-- | Find all variables bound anywhere in a type.+-- See also Note [Scope-check inferred kinds] in TcHsType+allBoundVariables :: Type -> TyVarSet+allBoundVariables ty = fvVarSet $ go ty+ where+ go :: Type -> FV+ go (TyVarTy tv) = go (tyVarKind tv)+ go (TyConApp _ tys) = mapUnionFV go tys+ go (AppTy t1 t2) = go t1 `unionFV` go t2+ go (FunTy t1 t2) = go t1 `unionFV` go t2+ go (ForAllTy (TvBndr tv _) t2) = FV.unitFV tv `unionFV`+ go (tyVarKind tv) `unionFV` go t2+ go (LitTy {}) = emptyFV+ go (CastTy ty _) = go ty+ go (CoercionTy {}) = emptyFV+ -- any types mentioned in a coercion should also be mentioned in+ -- a type.++allBoundVariabless :: [Type] -> TyVarSet+allBoundVariabless = mapUnionVarSet allBoundVariables++{- *********************************************************************+* *+ Type and kind variables in a type+* *+********************************************************************* -}++data CandidatesQTvs -- See Note [Dependent type variables]+ -- See Note [CandidatesQTvs determinism]+ = DV { dv_kvs :: DTyCoVarSet -- "kind" variables (dependent)+ , dv_tvs :: DTyVarSet -- "type" variables (non-dependent)+ -- A variable may appear in both sets+ -- E.g. T k (x::k) The first occurrence of k makes it+ -- show up in dv_tvs, the second in dv_kvs+ -- See Note [Dependent type variables]+ }++instance Monoid CandidatesQTvs where+ mempty = DV { dv_kvs = emptyDVarSet, dv_tvs = emptyDVarSet }+ mappend (DV { dv_kvs = kv1, dv_tvs = tv1 })+ (DV { dv_kvs = kv2, dv_tvs = tv2 })+ = DV { dv_kvs = kv1 `unionDVarSet` kv2+ , dv_tvs = tv1 `unionDVarSet` tv2}++instance Outputable CandidatesQTvs where+ ppr (DV {dv_kvs = kvs, dv_tvs = tvs })+ = text "DV" <+> braces (sep [ text "dv_kvs =" <+> ppr kvs+ , text "dv_tvs =" <+> ppr tvs ])++{- Note [Dependent type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In Haskell type inference we quantify over type variables; but we only+quantify over /kind/ variables when -XPolyKinds is on. Without -XPolyKinds+we default the kind variables to *.++So, to support this defaulting, and only for that reason, when+collecting the free vars of a type, prior to quantifying, we must keep+the type and kind variables separate.++But what does that mean in a system where kind variables /are/ type+variables? It's a fairly arbitrary distinction based on how the+variables appear:++ - "Kind variables" appear in the kind of some other free variable+ PLUS any free coercion variables++ These are the ones we default to * if -XPolyKinds is off++ - "Type variables" are all free vars that are not kind variables++E.g. In the type T k (a::k)+ 'k' is a kind variable, because it occurs in the kind of 'a',+ even though it also appears at "top level" of the type+ 'a' is a type variable, because it doesn't++We gather these variables using a CandidatesQTvs record:+ DV { dv_kvs: Variables free in the kind of a free type variable+ or of a forall-bound type variable+ , dv_tvs: Variables sytactically free in the type }++So: dv_kvs are the kind variables of the type+ (dv_tvs - dv_kvs) are the type variable of the type++Note that++* A variable can occur in both.+ T k (x::k) The first occurrence of k makes it+ show up in dv_tvs, the second in dv_kvs++* We include any coercion variables in the "dependent",+ "kind-variable" set because we never quantify over them.++* Both sets are un-ordered, of course.++* The "kind variables" might depend on each other; e.g+ (k1 :: k2), (k2 :: *)+ The "type variables" do not depend on each other; if+ one did, it'd be classified as a kind variable!++Note [CandidatesQTvs determinism and order]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Determinism: when we quantify over type variables we decide the+ order in which they appear in the final type. Because the order of+ type variables in the type can end up in the interface file and+ affects some optimizations like worker-wrapper, we want this order to+ be deterministic.++ To achieve that we use deterministic sets of variables that can be+ converted to lists in a deterministic order. For more information+ about deterministic sets see Note [Deterministic UniqFM] in UniqDFM.++* Order: as well as being deterministic, we use an+ accumulating-parameter style for candidateQTyVarsOfType so that we+ add variables one at a time, left to right. That means we tend to+ produce the variables in left-to-right order. This is just to make+ it bit more predicatable for the programmer.+-}++-- | Worker for 'splitDepVarsOfType'. This might output the same var+-- in both sets, if it's used in both a type and a kind.+-- See Note [CandidatesQTvs determinism and order]+-- See Note [Dependent type variables]+candidateQTyVarsOfType :: Type -> CandidatesQTvs+candidateQTyVarsOfType = split_dvs emptyVarSet mempty++split_dvs :: VarSet -> CandidatesQTvs -> Type -> CandidatesQTvs+split_dvs bound dvs ty+ = go dvs ty+ where+ go dv (AppTy t1 t2) = go (go dv t1) t2+ go dv (TyConApp _ tys) = foldl go dv tys+ go dv (FunTy arg res) = go (go dv arg) res+ go dv (LitTy {}) = dv+ go dv (CastTy ty co) = go dv ty `mappend` go_co co+ go dv (CoercionTy co) = dv `mappend` go_co co++ go dv@(DV { dv_kvs = kvs, dv_tvs = tvs }) (TyVarTy tv)+ | tv `elemVarSet` bound+ = dv+ | otherwise+ = DV { dv_kvs = kvs `unionDVarSet`+ kill_bound (tyCoVarsOfTypeDSet (tyVarKind tv))+ , dv_tvs = tvs `extendDVarSet` tv }++ go dv (ForAllTy (TvBndr tv _) ty)+ = DV { dv_kvs = kvs `unionDVarSet`+ kill_bound (tyCoVarsOfTypeDSet (tyVarKind tv))+ , dv_tvs = tvs }+ where+ DV { dv_kvs = kvs, dv_tvs = tvs } = split_dvs (bound `extendVarSet` tv) dv ty++ go_co co = DV { dv_kvs = kill_bound (tyCoVarsOfCoDSet co)+ , dv_tvs = emptyDVarSet }++ kill_bound free+ | isEmptyVarSet bound = free+ | otherwise = filterDVarSet (not . (`elemVarSet` bound)) free++-- | Like 'splitDepVarsOfType', but over a list of types+candidateQTyVarsOfTypes :: [Type] -> CandidatesQTvs+candidateQTyVarsOfTypes = foldl (split_dvs emptyVarSet) mempty++{-+************************************************************************+* *+ Predicates+* *+************************************************************************+-}++tcIsTcTyVar :: TcTyVar -> Bool+-- See Note [TcTyVars in the typechecker]+tcIsTcTyVar tv = isTyVar tv++isTouchableOrFmv :: TcLevel -> TcTyVar -> Bool+isTouchableOrFmv ctxt_tclvl tv+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv { mtv_tclvl = tv_tclvl, mtv_info = info }+ -> ASSERT2( checkTcLevelInvariant ctxt_tclvl tv_tclvl,+ ppr tv $$ ppr tv_tclvl $$ ppr ctxt_tclvl )+ case info of+ FlatMetaTv -> True+ _ -> tv_tclvl `sameDepthAs` ctxt_tclvl+ _ -> False++isTouchableMetaTyVar :: TcLevel -> TcTyVar -> Bool+isTouchableMetaTyVar ctxt_tclvl tv+ | isTyVar tv -- See Note [Coercion variables in free variable lists]+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv { mtv_tclvl = tv_tclvl }+ -> ASSERT2( checkTcLevelInvariant ctxt_tclvl tv_tclvl,+ ppr tv $$ ppr tv_tclvl $$ ppr ctxt_tclvl )+ tv_tclvl `sameDepthAs` ctxt_tclvl+ _ -> False+ | otherwise = False++isFloatedTouchableMetaTyVar :: TcLevel -> TcTyVar -> Bool+isFloatedTouchableMetaTyVar ctxt_tclvl tv+ | isTyVar tv -- See Note [Coercion variables in free variable lists]+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv { mtv_tclvl = tv_tclvl } -> tv_tclvl `strictlyDeeperThan` ctxt_tclvl+ _ -> False+ | otherwise = False++isImmutableTyVar :: TyVar -> Bool+isImmutableTyVar tv = isSkolemTyVar tv++isTyConableTyVar, isSkolemTyVar, isOverlappableTyVar,+ isMetaTyVar, isAmbiguousTyVar,+ isFmvTyVar, isFskTyVar, isFlattenTyVar :: TcTyVar -> Bool++isTyConableTyVar tv+ -- True of a meta-type variable that can be filled in+ -- with a type constructor application; in particular,+ -- not a SigTv+ | isTyVar tv -- See Note [Coercion variables in free variable lists]+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv { mtv_info = SigTv } -> False+ _ -> True+ | otherwise = True++isFmvTyVar tv+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv { mtv_info = FlatMetaTv } -> True+ _ -> False++-- | True of both given and wanted flatten-skolems (fak and usk)+isFlattenTyVar tv+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ FlatSkol {} -> True+ MetaTv { mtv_info = FlatMetaTv } -> True+ _ -> False++-- | True of FlatSkol skolems only+isFskTyVar tv+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ FlatSkol {} -> True+ _ -> False++isSkolemTyVar tv+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv {} -> False+ _other -> True++isOverlappableTyVar tv+ | isTyVar tv -- See Note [Coercion variables in free variable lists]+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ SkolemTv _ overlappable -> overlappable+ _ -> False+ | otherwise = False++isMetaTyVar tv+ | isTyVar tv -- See Note [Coercion variables in free variable lists]+ = ASSERT2( tcIsTcTyVar tv, ppr tv )+ case tcTyVarDetails tv of+ MetaTv {} -> True+ _ -> False+ | otherwise = False++-- isAmbiguousTyVar is used only when reporting type errors+-- It picks out variables that are unbound, namely meta+-- type variables and the RuntimUnk variables created by+-- RtClosureInspect.zonkRTTIType. These are "ambiguous" in+-- the sense that they stand for an as-yet-unknown type+isAmbiguousTyVar tv+ | isTyVar tv -- See Note [Coercion variables in free variable lists]+ = case tcTyVarDetails tv of+ MetaTv {} -> True+ RuntimeUnk {} -> True+ _ -> False+ | otherwise = False++isMetaTyVarTy :: TcType -> Bool+isMetaTyVarTy (TyVarTy tv) = isMetaTyVar tv+isMetaTyVarTy _ = False++metaTyVarInfo :: TcTyVar -> MetaInfo+metaTyVarInfo tv+ = case tcTyVarDetails tv of+ MetaTv { mtv_info = info } -> info+ _ -> pprPanic "metaTyVarInfo" (ppr tv)++metaTyVarTcLevel :: TcTyVar -> TcLevel+metaTyVarTcLevel tv+ = case tcTyVarDetails tv of+ MetaTv { mtv_tclvl = tclvl } -> tclvl+ _ -> pprPanic "metaTyVarTcLevel" (ppr tv)++metaTyVarTcLevel_maybe :: TcTyVar -> Maybe TcLevel+metaTyVarTcLevel_maybe tv+ = case tcTyVarDetails tv of+ MetaTv { mtv_tclvl = tclvl } -> Just tclvl+ _ -> Nothing++metaTyVarRef :: TyVar -> IORef MetaDetails+metaTyVarRef tv+ = case tcTyVarDetails tv of+ MetaTv { mtv_ref = ref } -> ref+ _ -> pprPanic "metaTyVarRef" (ppr tv)++setMetaTyVarTcLevel :: TcTyVar -> TcLevel -> TcTyVar+setMetaTyVarTcLevel tv tclvl+ = case tcTyVarDetails tv of+ details@(MetaTv {}) -> setTcTyVarDetails tv (details { mtv_tclvl = tclvl })+ _ -> pprPanic "metaTyVarTcLevel" (ppr tv)++isSigTyVar :: Var -> Bool+isSigTyVar tv+ = case tcTyVarDetails tv of+ MetaTv { mtv_info = SigTv } -> True+ _ -> False++isFlexi, isIndirect :: MetaDetails -> Bool+isFlexi Flexi = True+isFlexi _ = False++isIndirect (Indirect _) = True+isIndirect _ = False++isRuntimeUnkSkol :: TyVar -> Bool+-- Called only in TcErrors; see Note [Runtime skolems] there+isRuntimeUnkSkol x+ | RuntimeUnk <- tcTyVarDetails x = True+ | otherwise = False++{-+************************************************************************+* *+\subsection{Tau, sigma and rho}+* *+************************************************************************+-}++mkSigmaTy :: [TyVarBinder] -> [PredType] -> Type -> Type+mkSigmaTy bndrs theta tau = mkForAllTys bndrs (mkPhiTy theta tau)++-- | Make a sigma ty where all type variables are 'Inferred'. That is,+-- they cannot be used with visible type application.+mkInfSigmaTy :: [TyVar] -> [PredType] -> Type -> Type+mkInfSigmaTy tyvars ty = mkSigmaTy (mkTyVarBinders Inferred tyvars) ty++-- | Make a sigma ty where all type variables are "specified". That is,+-- they can be used with visible type application+mkSpecSigmaTy :: [TyVar] -> [PredType] -> Type -> Type+mkSpecSigmaTy tyvars ty = mkSigmaTy (mkTyVarBinders Specified tyvars) ty++mkPhiTy :: [PredType] -> Type -> Type+mkPhiTy = mkFunTys++---------------+getDFunTyKey :: Type -> OccName -- Get some string from a type, to be used to+ -- construct a dictionary function name+getDFunTyKey ty | Just ty' <- coreView ty = getDFunTyKey ty'+getDFunTyKey (TyVarTy tv) = getOccName tv+getDFunTyKey (TyConApp tc _) = getOccName tc+getDFunTyKey (LitTy x) = getDFunTyLitKey x+getDFunTyKey (AppTy fun _) = getDFunTyKey fun+getDFunTyKey (FunTy _ _) = getOccName funTyCon+getDFunTyKey (ForAllTy _ t) = getDFunTyKey t+getDFunTyKey (CastTy ty _) = getDFunTyKey ty+getDFunTyKey t@(CoercionTy _) = pprPanic "getDFunTyKey" (ppr t)++getDFunTyLitKey :: TyLit -> OccName+getDFunTyLitKey (NumTyLit n) = mkOccName Name.varName (show n)+getDFunTyLitKey (StrTyLit n) = mkOccName Name.varName (show n) -- hm++---------------+mkNakedTyConApp :: TyCon -> [Type] -> Type+-- Builds a TyConApp+-- * without being strict in TyCon,+-- * without satisfying the invariants of TyConApp+-- A subsequent zonking will establish the invariants+-- See Note [Type-checking inside the knot] in TcHsType+mkNakedTyConApp tc tys = TyConApp tc tys++mkNakedAppTys :: Type -> [Type] -> Type+-- See Note [Type-checking inside the knot] in TcHsType+mkNakedAppTys ty1 [] = ty1+mkNakedAppTys (TyConApp tc tys1) tys2 = mkNakedTyConApp tc (tys1 ++ tys2)+mkNakedAppTys ty1 tys2 = foldl AppTy ty1 tys2++mkNakedAppTy :: Type -> Type -> Type+-- See Note [Type-checking inside the knot] in TcHsType+mkNakedAppTy ty1 ty2 = mkNakedAppTys ty1 [ty2]++mkNakedCastTy :: Type -> Coercion -> Type+-- Do simple, fast compaction; especially dealing with Refl+-- for which it's plain stupid to create a cast+-- This simple function killed off a huge number of Refl casts+-- in types, at birth.+-- Note that it's fine to do this even for a "mkNaked" function,+-- because we don't look at TyCons. isReflCo checks if the coercion+-- is structurally Refl; it does not check for shape k ~ k.+mkNakedCastTy ty co | isReflCo co = ty+mkNakedCastTy (CastTy ty co1) co2 = CastTy ty (co1 `mkTransCo` co2)+mkNakedCastTy ty co = CastTy ty co++{-+************************************************************************+* *+\subsection{Expanding and splitting}+* *+************************************************************************++These tcSplit functions are like their non-Tc analogues, but+ *) they do not look through newtypes++However, they are non-monadic and do not follow through mutable type+variables. It's up to you to make sure this doesn't matter.+-}++-- | Splits a forall type into a list of 'TyBinder's and the inner type.+-- Always succeeds, even if it returns an empty list.+tcSplitPiTys :: Type -> ([TyBinder], Type)+tcSplitPiTys = splitPiTys++tcSplitForAllTy_maybe :: Type -> Maybe (TyVarBinder, Type)+tcSplitForAllTy_maybe ty | Just ty' <- tcView ty = tcSplitForAllTy_maybe ty'+tcSplitForAllTy_maybe (ForAllTy tv ty) = Just (tv, ty)+tcSplitForAllTy_maybe _ = Nothing++-- | Like 'tcSplitPiTys', but splits off only named binders, returning+-- just the tycovars.+tcSplitForAllTys :: Type -> ([TyVar], Type)+tcSplitForAllTys = splitForAllTys++-- | Like 'tcSplitForAllTys', but splits off only named binders.+tcSplitForAllTyVarBndrs :: Type -> ([TyVarBinder], Type)+tcSplitForAllTyVarBndrs = splitForAllTyVarBndrs++-- | Is this a ForAllTy with a named binder?+tcIsForAllTy :: Type -> Bool+tcIsForAllTy ty | Just ty' <- tcView ty = tcIsForAllTy ty'+tcIsForAllTy (ForAllTy {}) = True+tcIsForAllTy _ = False++tcSplitPredFunTy_maybe :: Type -> Maybe (PredType, Type)+-- Split off the first predicate argument from a type+tcSplitPredFunTy_maybe ty+ | Just ty' <- tcView ty = tcSplitPredFunTy_maybe ty'+tcSplitPredFunTy_maybe (FunTy arg res)+ | isPredTy arg = Just (arg, res)+tcSplitPredFunTy_maybe _+ = Nothing++tcSplitPhiTy :: Type -> (ThetaType, Type)+tcSplitPhiTy ty+ = split ty []+ where+ split ty ts+ = case tcSplitPredFunTy_maybe ty of+ Just (pred, ty) -> split ty (pred:ts)+ Nothing -> (reverse ts, ty)++-- | Split a sigma type into its parts.+tcSplitSigmaTy :: Type -> ([TyVar], ThetaType, Type)+tcSplitSigmaTy ty = case tcSplitForAllTys ty of+ (tvs, rho) -> case tcSplitPhiTy rho of+ (theta, tau) -> (tvs, theta, tau)++-- | Split a sigma type into its parts, going underneath as many @ForAllTy@s+-- as possible. For example, given this type synonym:+--+-- @+-- type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t+-- @+--+-- if you called @tcSplitSigmaTy@ on this type:+--+-- @+-- forall s t a b. Each s t a b => Traversal s t a b+-- @+--+-- then it would return @([s,t,a,b], [Each s t a b], Traversal s t a b)@. But+-- if you instead called @tcSplitNestedSigmaTys@ on the type, it would return+-- @([s,t,a,b,f], [Each s t a b, Applicative f], (a -> f b) -> s -> f t)@.+tcSplitNestedSigmaTys :: Type -> ([TyVar], ThetaType, Type)+-- NB: This is basically a pure version of deeplyInstantiate (from Inst) that+-- doesn't compute an HsWrapper.+tcSplitNestedSigmaTys ty+ -- If there's a forall, split it apart and try splitting the rho type+ -- underneath it.+ | Just (arg_tys, tvs1, theta1, rho1) <- tcDeepSplitSigmaTy_maybe ty+ = let (tvs2, theta2, rho2) = tcSplitNestedSigmaTys rho1+ in (tvs1 ++ tvs2, theta1 ++ theta2, mkFunTys arg_tys rho2)+ -- If there's no forall, we're done.+ | otherwise = ([], [], ty)++-----------------------+tcDeepSplitSigmaTy_maybe+ :: TcSigmaType -> Maybe ([TcType], [TyVar], ThetaType, TcSigmaType)+-- Looks for a *non-trivial* quantified type, under zero or more function arrows+-- By "non-trivial" we mean either tyvars or constraints are non-empty++tcDeepSplitSigmaTy_maybe ty+ | Just (arg_ty, res_ty) <- tcSplitFunTy_maybe ty+ , Just (arg_tys, tvs, theta, rho) <- tcDeepSplitSigmaTy_maybe res_ty+ = Just (arg_ty:arg_tys, tvs, theta, rho)++ | (tvs, theta, rho) <- tcSplitSigmaTy ty+ , not (null tvs && null theta)+ = Just ([], tvs, theta, rho)++ | otherwise = Nothing++-----------------------+tcTyConAppTyCon :: Type -> TyCon+tcTyConAppTyCon ty+ = case tcTyConAppTyCon_maybe ty of+ Just tc -> tc+ Nothing -> pprPanic "tcTyConAppTyCon" (pprType ty)++-- | Like 'tcRepSplitTyConApp_maybe', but only returns the 'TyCon'.+tcTyConAppTyCon_maybe :: Type -> Maybe TyCon+tcTyConAppTyCon_maybe ty+ | Just ty' <- tcView ty = tcTyConAppTyCon_maybe ty'+tcTyConAppTyCon_maybe (TyConApp tc _)+ = Just tc+tcTyConAppTyCon_maybe (FunTy _ _)+ = Just funTyCon+tcTyConAppTyCon_maybe _+ = Nothing++tcTyConAppArgs :: Type -> [Type]+tcTyConAppArgs ty = case tcSplitTyConApp_maybe ty of+ Just (_, args) -> args+ Nothing -> pprPanic "tcTyConAppArgs" (pprType ty)++tcSplitTyConApp :: Type -> (TyCon, [Type])+tcSplitTyConApp ty = case tcSplitTyConApp_maybe ty of+ Just stuff -> stuff+ Nothing -> pprPanic "tcSplitTyConApp" (pprType ty)++-- | Like 'tcRepSplitTyConApp_maybe', but returns 'Nothing' if,+--+-- 1. the type is structurally not a type constructor application, or+--+-- 2. the type is a function type (e.g. application of 'funTyCon'), but we+-- currently don't even enough information to fully determine its RuntimeRep+-- variables. For instance, @FunTy (a :: k) Int@.+--+-- By contrast 'tcRepSplitTyConApp_maybe' panics in the second case.+--+-- The behavior here is needed during canonicalization; see Note [FunTy and+-- decomposing tycon applications] in TcCanonical for details.+tcRepSplitTyConApp_maybe' :: HasCallStack => Type -> Maybe (TyCon, [Type])+tcRepSplitTyConApp_maybe' (TyConApp tc tys) = Just (tc, tys)+tcRepSplitTyConApp_maybe' (FunTy arg res)+ | Just arg_rep <- getRuntimeRep_maybe arg+ , Just res_rep <- getRuntimeRep_maybe res+ = Just (funTyCon, [arg_rep, res_rep, arg, res])+tcRepSplitTyConApp_maybe' _ = Nothing+++-----------------------+tcSplitFunTys :: Type -> ([Type], Type)+tcSplitFunTys ty = case tcSplitFunTy_maybe ty of+ Nothing -> ([], ty)+ Just (arg,res) -> (arg:args, res')+ where+ (args,res') = tcSplitFunTys res++tcSplitFunTy_maybe :: Type -> Maybe (Type, Type)+tcSplitFunTy_maybe ty | Just ty' <- tcView ty = tcSplitFunTy_maybe ty'+tcSplitFunTy_maybe (FunTy arg res) | not (isPredTy arg) = Just (arg, res)+tcSplitFunTy_maybe _ = Nothing+ -- Note the typeKind guard+ -- Consider (?x::Int) => Bool+ -- We don't want to treat this as a function type!+ -- A concrete example is test tc230:+ -- f :: () -> (?p :: ()) => () -> ()+ --+ -- g = f () ()++tcSplitFunTysN :: Arity -- N: Number of desired args+ -> TcRhoType+ -> Either Arity -- Number of missing arrows+ ([TcSigmaType], -- Arg types (always N types)+ TcSigmaType) -- The rest of the type+-- ^ Split off exactly the specified number argument types+-- Returns+-- (Left m) if there are 'm' missing arrows in the type+-- (Right (tys,res)) if the type looks like t1 -> ... -> tn -> res+tcSplitFunTysN n ty+ | n == 0+ = Right ([], ty)+ | Just (arg,res) <- tcSplitFunTy_maybe ty+ = case tcSplitFunTysN (n-1) res of+ Left m -> Left m+ Right (args,body) -> Right (arg:args, body)+ | otherwise+ = Left n++tcSplitFunTy :: Type -> (Type, Type)+tcSplitFunTy ty = expectJust "tcSplitFunTy" (tcSplitFunTy_maybe ty)++tcFunArgTy :: Type -> Type+tcFunArgTy ty = fst (tcSplitFunTy ty)++tcFunResultTy :: Type -> Type+tcFunResultTy ty = snd (tcSplitFunTy ty)++-- | Strips off n *visible* arguments and returns the resulting type+tcFunResultTyN :: HasDebugCallStack => Arity -> Type -> Type+tcFunResultTyN n ty+ | Right (_, res_ty) <- tcSplitFunTysN n ty+ = res_ty+ | otherwise+ = pprPanic "tcFunResultTyN" (ppr n <+> ppr ty)++-----------------------+tcSplitAppTy_maybe :: Type -> Maybe (Type, Type)+tcSplitAppTy_maybe ty | Just ty' <- tcView ty = tcSplitAppTy_maybe ty'+tcSplitAppTy_maybe ty = tcRepSplitAppTy_maybe ty++tcSplitAppTy :: Type -> (Type, Type)+tcSplitAppTy ty = case tcSplitAppTy_maybe ty of+ Just stuff -> stuff+ Nothing -> pprPanic "tcSplitAppTy" (pprType ty)++tcSplitAppTys :: Type -> (Type, [Type])+tcSplitAppTys ty+ = go ty []+ where+ go ty args = case tcSplitAppTy_maybe ty of+ Just (ty', arg) -> go ty' (arg:args)+ Nothing -> (ty,args)++-----------------------+tcGetTyVar_maybe :: Type -> Maybe TyVar+tcGetTyVar_maybe ty | Just ty' <- tcView ty = tcGetTyVar_maybe ty'+tcGetTyVar_maybe (TyVarTy tv) = Just tv+tcGetTyVar_maybe _ = Nothing++tcGetTyVar :: String -> Type -> TyVar+tcGetTyVar msg ty = expectJust msg (tcGetTyVar_maybe ty)++tcIsTyVarTy :: Type -> Bool+tcIsTyVarTy ty | Just ty' <- tcView ty = tcIsTyVarTy ty'+tcIsTyVarTy (CastTy ty _) = tcIsTyVarTy ty -- look through casts, as+ -- this is only used for+ -- e.g., FlexibleContexts+tcIsTyVarTy (TyVarTy _) = True+tcIsTyVarTy _ = False++-----------------------+tcSplitDFunTy :: Type -> ([TyVar], [Type], Class, [Type])+-- Split the type of a dictionary function+-- We don't use tcSplitSigmaTy, because a DFun may (with NDP)+-- have non-Pred arguments, such as+-- df :: forall m. (forall b. Eq b => Eq (m b)) -> C m+--+-- Also NB splitFunTys, not tcSplitFunTys;+-- the latter specifically stops at PredTy arguments,+-- and we don't want to do that here+tcSplitDFunTy ty+ = case tcSplitForAllTys ty of { (tvs, rho) ->+ case splitFunTys rho of { (theta, tau) ->+ case tcSplitDFunHead tau of { (clas, tys) ->+ (tvs, theta, clas, tys) }}}++tcSplitDFunHead :: Type -> (Class, [Type])+tcSplitDFunHead = getClassPredTys++tcSplitMethodTy :: Type -> ([TyVar], PredType, Type)+-- A class method (selector) always has a type like+-- forall as. C as => blah+-- So if the class looks like+-- class C a where+-- op :: forall b. (Eq a, Ix b) => a -> b+-- the class method type looks like+-- op :: forall a. C a => forall b. (Eq a, Ix b) => a -> b+--+-- tcSplitMethodTy just peels off the outer forall and+-- that first predicate+tcSplitMethodTy ty+ | (sel_tyvars,sel_rho) <- tcSplitForAllTys ty+ , Just (first_pred, local_meth_ty) <- tcSplitPredFunTy_maybe sel_rho+ = (sel_tyvars, first_pred, local_meth_ty)+ | otherwise+ = pprPanic "tcSplitMethodTy" (ppr ty)+++{- *********************************************************************+* *+ Type equalities+* *+********************************************************************* -}++tcEqKind :: TcKind -> TcKind -> Bool+tcEqKind = tcEqType++tcEqType :: TcType -> TcType -> Bool+-- tcEqType is a proper implements the same Note [Non-trivial definitional+-- equality] (in TyCoRep) as `eqType`, but Type.eqType believes (* ==+-- Constraint), and that is NOT what we want in the type checker!+tcEqType ty1 ty2+ = isNothing (tc_eq_type tcView ki1 ki2) &&+ isNothing (tc_eq_type tcView ty1 ty2)+ where+ ki1 = typeKind ty1+ ki2 = typeKind ty2++-- | Just like 'tcEqType', but will return True for types of different kinds+-- as long as their non-coercion structure is identical.+tcEqTypeNoKindCheck :: TcType -> TcType -> Bool+tcEqTypeNoKindCheck ty1 ty2+ = isNothing $ tc_eq_type tcView ty1 ty2++-- | Like 'tcEqType', but returns information about whether the difference+-- is visible in the case of a mismatch.+-- @Nothing@ : the types are equal+-- @Just True@ : the types differ, and the point of difference is visible+-- @Just False@ : the types differ, and the point of difference is invisible+tcEqTypeVis :: TcType -> TcType -> Maybe Bool+tcEqTypeVis ty1 ty2+ = tc_eq_type tcView ty1 ty2 <!> invis (tc_eq_type tcView ki1 ki2)+ where+ ki1 = typeKind ty1+ ki2 = typeKind ty2++ -- convert Just True to Just False+ invis :: Maybe Bool -> Maybe Bool+ invis = fmap (const False)++(<!>) :: Maybe Bool -> Maybe Bool -> Maybe Bool+Nothing <!> x = x+Just True <!> _ = Just True+Just _vis <!> Just True = Just True+Just vis <!> _ = Just vis+infixr 3 <!>++-- | Real worker for 'tcEqType'. No kind check!+tc_eq_type :: (TcType -> Maybe TcType) -- ^ @tcView@, if you want unwrapping+ -> Type -> Type -> Maybe Bool+tc_eq_type view_fun orig_ty1 orig_ty2 = go True orig_env orig_ty1 orig_ty2+ where+ go :: Bool -> RnEnv2 -> Type -> Type -> Maybe Bool+ go vis env t1 t2 | Just t1' <- view_fun t1 = go vis env t1' t2+ go vis env t1 t2 | Just t2' <- view_fun t2 = go vis env t1 t2'++ go vis env (TyVarTy tv1) (TyVarTy tv2)+ = check vis $ rnOccL env tv1 == rnOccR env tv2++ go vis _ (LitTy lit1) (LitTy lit2)+ = check vis $ lit1 == lit2++ go vis env (ForAllTy (TvBndr tv1 vis1) ty1)+ (ForAllTy (TvBndr tv2 vis2) ty2)+ = go (isVisibleArgFlag vis1) env (tyVarKind tv1) (tyVarKind tv2)+ <!> go vis (rnBndr2 env tv1 tv2) ty1 ty2+ <!> check vis (vis1 == vis2)+ -- Make sure we handle all FunTy cases since falling through to the+ -- AppTy case means that tcRepSplitAppTy_maybe may see an unzonked+ -- kind variable, which causes things to blow up.+ go vis env (FunTy arg1 res1) (FunTy arg2 res2)+ = go vis env arg1 arg2 <!> go vis env res1 res2+ go vis env ty (FunTy arg res)+ = eqFunTy vis env arg res ty+ go vis env (FunTy arg res) ty+ = eqFunTy vis env arg res ty++ -- See Note [Equality on AppTys] in Type+ go vis env (AppTy s1 t1) ty2+ | Just (s2, t2) <- tcRepSplitAppTy_maybe ty2+ = go vis env s1 s2 <!> go vis env t1 t2+ go vis env ty1 (AppTy s2 t2)+ | Just (s1, t1) <- tcRepSplitAppTy_maybe ty1+ = go vis env s1 s2 <!> go vis env t1 t2+ go vis env (TyConApp tc1 ts1) (TyConApp tc2 ts2)+ = check vis (tc1 == tc2) <!> gos (tc_vis vis tc1) env ts1 ts2+ go vis env (CastTy t1 _) t2 = go vis env t1 t2+ go vis env t1 (CastTy t2 _) = go vis env t1 t2+ go _ _ (CoercionTy {}) (CoercionTy {}) = Nothing+ go vis _ _ _ = Just vis++ gos _ _ [] [] = Nothing+ gos (v:vs) env (t1:ts1) (t2:ts2) = go v env t1 t2 <!> gos vs env ts1 ts2+ gos (v:_) _ _ _ = Just v+ gos _ _ _ _ = panic "tc_eq_type"++ tc_vis :: Bool -> TyCon -> [Bool]+ tc_vis True tc = viss ++ repeat True+ -- the repeat True is necessary because tycons can legitimately+ -- be oversaturated+ where+ bndrs = tyConBinders tc+ viss = map (isVisibleArgFlag . tyConBinderArgFlag) bndrs+ tc_vis False _ = repeat False -- if we're not in a visible context, our args+ -- aren't either++ check :: Bool -> Bool -> Maybe Bool+ check _ True = Nothing+ check vis False = Just vis++ orig_env = mkRnEnv2 $ mkInScopeSet $ tyCoVarsOfTypes [orig_ty1, orig_ty2]++ -- @eqFunTy arg res ty@ is True when @ty@ equals @FunTy arg res@. This is+ -- sometimes hard to know directly because @ty@ might have some casts+ -- obscuring the FunTy. And 'splitAppTy' is difficult because we can't+ -- always extract a RuntimeRep (see Note [xyz]) if the kind of the arg or+ -- res is unzonked/unflattened. Thus this function, which handles this+ -- corner case.+ eqFunTy :: Bool -> RnEnv2 -> Type -> Type -> Type -> Maybe Bool+ eqFunTy vis env arg res (FunTy arg' res')+ = go vis env arg arg' <!> go vis env res res'+ eqFunTy vis env arg res ty@(AppTy{})+ | Just (tc, [_, _, arg', res']) <- get_args ty []+ , tc == funTyCon+ = go vis env arg arg' <!> go vis env res res'+ where+ get_args :: Type -> [Type] -> Maybe (TyCon, [Type])+ get_args (AppTy f x) args = get_args f (x:args)+ get_args (CastTy t _) args = get_args t args+ get_args (TyConApp tc tys) args = Just (tc, tys ++ args)+ get_args _ _ = Nothing+ eqFunTy vis _ _ _ _+ = Just vis++-- | Like 'pickyEqTypeVis', but returns a Bool for convenience+pickyEqType :: TcType -> TcType -> Bool+-- Check when two types _look_ the same, _including_ synonyms.+-- So (pickyEqType String [Char]) returns False+-- This ignores kinds and coercions, because this is used only for printing.+pickyEqType ty1 ty2+ = isNothing $+ tc_eq_type (const Nothing) ty1 ty2++{- *********************************************************************+* *+ Predicate types+* *+************************************************************************++Deconstructors and tests on predicate types++Note [Kind polymorphic type classes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ class C f where... -- C :: forall k. k -> Constraint+ g :: forall (f::*). C f => f -> f++Here the (C f) in the signature is really (C * f), and we+don't want to complain that the * isn't a type variable!+-}++isTyVarClassPred :: PredType -> Bool+isTyVarClassPred ty = case getClassPredTys_maybe ty of+ Just (_, tys) -> all isTyVarTy tys+ _ -> False++-------------------------+checkValidClsArgs :: Bool -> Class -> [KindOrType] -> Bool+-- If the Bool is True (flexible contexts), return True (i.e. ok)+-- Otherwise, check that the type (not kind) args are all headed by a tyvar+-- E.g. (Eq a) accepted, (Eq (f a)) accepted, but (Eq Int) rejected+-- This function is here rather than in TcValidity because it is+-- called from TcSimplify, which itself is imported by TcValidity+checkValidClsArgs flexible_contexts cls kts+ | flexible_contexts = True+ | otherwise = all hasTyVarHead tys+ where+ tys = filterOutInvisibleTypes (classTyCon cls) kts++hasTyVarHead :: Type -> Bool+-- Returns true of (a t1 .. tn), where 'a' is a type variable+hasTyVarHead ty -- Haskell 98 allows predicates of form+ | tcIsTyVarTy ty = True -- C (a ty1 .. tyn)+ | otherwise -- where a is a type variable+ = case tcSplitAppTy_maybe ty of+ Just (ty, _) -> hasTyVarHead ty+ Nothing -> False++evVarPred_maybe :: EvVar -> Maybe PredType+evVarPred_maybe v = if isPredTy ty then Just ty else Nothing+ where ty = varType v++evVarPred :: EvVar -> PredType+evVarPred var+ | debugIsOn+ = case evVarPred_maybe var of+ Just pred -> pred+ Nothing -> pprPanic "tcEvVarPred" (ppr var <+> ppr (varType var))+ | otherwise+ = varType var++------------------+-- | When inferring types, should we quantify over a given predicate?+-- Generally true of classes; generally false of equality constraints.+-- Equality constraints that mention quantified type variables and+-- implicit variables complicate the story. See Notes+-- [Inheriting implicit parameters] and [Quantifying over equality constraints]+pickQuantifiablePreds+ :: TyVarSet -- Quantifying over these+ -> TcThetaType -- Proposed constraints to quantify+ -> TcThetaType -- A subset that we can actually quantify+-- This function decides whether a particular constraint should be+-- quantified over, given the type variables that are being quantified+pickQuantifiablePreds qtvs theta+ = let flex_ctxt = True in -- Quantify over non-tyvar constraints, even without+ -- -XFlexibleContexts: see Trac #10608, #10351+ -- flex_ctxt <- xoptM Opt_FlexibleContexts+ filter (pick_me flex_ctxt) theta+ where+ pick_me flex_ctxt pred+ = case classifyPredType pred of++ ClassPred cls tys+ | Just {} <- isCallStackPred pred+ -- NEVER infer a CallStack constraint+ -- Otherwise, we let the constraints bubble up to be+ -- solved from the outer context, or be defaulted when we+ -- reach the top-level.+ -- see Note [Overview of implicit CallStacks]+ -> False++ | isIPClass cls -> True -- See note [Inheriting implicit parameters]++ | otherwise+ -> pick_cls_pred flex_ctxt cls tys++ EqPred ReprEq ty1 ty2 -> pick_cls_pred flex_ctxt coercibleClass [ty1, ty2]+ -- representational equality is like a class constraint++ EqPred NomEq ty1 ty2 -> quant_fun ty1 || quant_fun ty2+ IrredPred ty -> tyCoVarsOfType ty `intersectsVarSet` qtvs++ pick_cls_pred flex_ctxt cls tys+ = tyCoVarsOfTypes tys `intersectsVarSet` qtvs+ && (checkValidClsArgs flex_ctxt cls tys)+ -- Only quantify over predicates that checkValidType+ -- will pass! See Trac #10351.++ -- See Note [Quantifying over equality constraints]+ quant_fun ty+ = case tcSplitTyConApp_maybe ty of+ Just (tc, tys) | isTypeFamilyTyCon tc+ -> tyCoVarsOfTypes tys `intersectsVarSet` qtvs+ _ -> False++pickCapturedPreds+ :: TyVarSet -- Quantifying over these+ -> TcThetaType -- Proposed constraints to quantify+ -> TcThetaType -- A subset that we can actually quantify+-- A simpler version of pickQuantifiablePreds, used to winnow down+-- the inferred constrains of a group of bindings, into those for+-- one particular identifier+pickCapturedPreds qtvs theta+ = filter captured theta+ where+ captured pred = isIPPred pred || (tyCoVarsOfType pred `intersectsVarSet` qtvs)+++-- Superclasses++type PredWithSCs = (PredType, [PredType])++mkMinimalBySCs :: [PredType] -> [PredType]+-- Remove predicates that can be deduced from others by superclasses,+-- including duplicate predicates. The result is a subset of the input.+mkMinimalBySCs ptys = go preds_with_scs []+ where+ preds_with_scs :: [PredWithSCs]+ preds_with_scs = [ (pred, pred : transSuperClasses pred)+ | pred <- ptys ]++ go :: [PredWithSCs] -- Work list+ -> [PredWithSCs] -- Accumulating result+ -> [PredType]+ go [] min_preds = map fst min_preds+ go (work_item@(p,_) : work_list) min_preds+ | p `in_cloud` work_list || p `in_cloud` min_preds+ = go work_list min_preds+ | otherwise+ = go work_list (work_item : min_preds)++ in_cloud :: PredType -> [PredWithSCs] -> Bool+ in_cloud p ps = or [ p `eqType` p' | (_, scs) <- ps, p' <- scs ]++transSuperClasses :: PredType -> [PredType]+-- (transSuperClasses p) returns (p's superclasses) not including p+-- Stop if you encounter the same class again+-- See Note [Expanding superclasses]+transSuperClasses p+ = go emptyNameSet p+ where+ go :: NameSet -> PredType -> [PredType]+ go rec_clss p+ | ClassPred cls tys <- classifyPredType p+ , let cls_nm = className cls+ , not (cls_nm `elemNameSet` rec_clss)+ , let rec_clss' | isCTupleClass cls = rec_clss+ | otherwise = rec_clss `extendNameSet` cls_nm+ = [ p' | sc <- immSuperClasses cls tys+ , p' <- sc : go rec_clss' sc ]+ | otherwise+ = []++immSuperClasses :: Class -> [Type] -> [PredType]+immSuperClasses cls tys+ = substTheta (zipTvSubst tyvars tys) sc_theta+ where+ (tyvars,sc_theta,_,_) = classBigSig cls++isImprovementPred :: PredType -> Bool+-- Either it's an equality, or has some functional dependency+isImprovementPred ty+ = case classifyPredType ty of+ EqPred NomEq t1 t2 -> not (t1 `tcEqType` t2)+ EqPred ReprEq _ _ -> False+ ClassPred cls _ -> classHasFds cls+ IrredPred {} -> True -- Might have equalities after reduction?++{- Note [Expanding superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we expand superclasses, we use the following algorithm:++expand( so_far, pred ) returns the transitive superclasses of pred,+ not including pred itself+ 1. If pred is not a class constraint, return empty set+ Otherwise pred = C ts+ 2. If C is in so_far, return empty set (breaks loops)+ 3. Find the immediate superclasses constraints of (C ts)+ 4. For each such sc_pred, return (sc_pred : expand( so_far+C, D ss )++Notice that++ * With normal Haskell-98 classes, the loop-detector will never bite,+ so we'll get all the superclasses.++ * Since there is only a finite number of distinct classes, expansion+ must terminate.++ * The loop breaking is a bit conservative. Notably, a tuple class+ could contain many times without threatening termination:+ (Eq a, (Ord a, Ix a))+ And this is try of any class that we can statically guarantee+ as non-recursive (in some sense). For now, we just make a special+ case for tuples. Something better would be cool.++See also TcTyDecls.checkClassCycles.++Note [Inheriting implicit parameters]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:++ f x = (x::Int) + ?y++where f is *not* a top-level binding.+From the RHS of f we'll get the constraint (?y::Int).+There are two types we might infer for f:++ f :: Int -> Int++(so we get ?y from the context of f's definition), or++ f :: (?y::Int) => Int -> Int++At first you might think the first was better, because then+?y behaves like a free variable of the definition, rather than+having to be passed at each call site. But of course, the WHOLE+IDEA is that ?y should be passed at each call site (that's what+dynamic binding means) so we'd better infer the second.++BOTTOM LINE: when *inferring types* you must quantify over implicit+parameters, *even if* they don't mention the bound type variables.+Reason: because implicit parameters, uniquely, have local instance+declarations. See pickQuantifiablePreds.++Note [Quantifying over equality constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Should we quantify over an equality constraint (s ~ t)? In general, we don't.+Doing so may simply postpone a type error from the function definition site to+its call site. (At worst, imagine (Int ~ Bool)).++However, consider this+ forall a. (F [a] ~ Int) => blah+Should we quantify over the (F [a] ~ Int). Perhaps yes, because at the call+site we will know 'a', and perhaps we have instance F [Bool] = Int.+So we *do* quantify over a type-family equality where the arguments mention+the quantified variables.++************************************************************************+* *+\subsection{Predicates}+* *+************************************************************************+-}++isSigmaTy :: TcType -> Bool+-- isSigmaTy returns true of any qualified type. It doesn't+-- *necessarily* have any foralls. E.g+-- f :: (?x::Int) => Int -> Int+isSigmaTy ty | Just ty' <- tcView ty = isSigmaTy ty'+isSigmaTy (ForAllTy {}) = True+isSigmaTy (FunTy a _) = isPredTy a+isSigmaTy _ = False++isRhoTy :: TcType -> Bool -- True of TcRhoTypes; see Note [TcRhoType]+isRhoTy ty | Just ty' <- tcView ty = isRhoTy ty'+isRhoTy (ForAllTy {}) = False+isRhoTy (FunTy a r) = not (isPredTy a) && isRhoTy r+isRhoTy _ = True++-- | Like 'isRhoTy', but also says 'True' for 'Infer' types+isRhoExpTy :: ExpType -> Bool+isRhoExpTy (Check ty) = isRhoTy ty+isRhoExpTy (Infer {}) = True++isOverloadedTy :: Type -> Bool+-- Yes for a type of a function that might require evidence-passing+-- Used only by bindLocalMethods+isOverloadedTy ty | Just ty' <- tcView ty = isOverloadedTy ty'+isOverloadedTy (ForAllTy _ ty) = isOverloadedTy ty+isOverloadedTy (FunTy a _) = isPredTy a+isOverloadedTy _ = False++isFloatTy, isDoubleTy, isIntegerTy, isIntTy, isWordTy, isBoolTy,+ isUnitTy, isCharTy, isAnyTy :: Type -> Bool+isFloatTy = is_tc floatTyConKey+isDoubleTy = is_tc doubleTyConKey+isIntegerTy = is_tc integerTyConKey+isIntTy = is_tc intTyConKey+isWordTy = is_tc wordTyConKey+isBoolTy = is_tc boolTyConKey+isUnitTy = is_tc unitTyConKey+isCharTy = is_tc charTyConKey+isAnyTy = is_tc anyTyConKey++-- | Does a type represent a floating-point number?+isFloatingTy :: Type -> Bool+isFloatingTy ty = isFloatTy ty || isDoubleTy ty++-- | Is a type 'String'?+isStringTy :: Type -> Bool+isStringTy ty+ = case tcSplitTyConApp_maybe ty of+ Just (tc, [arg_ty]) -> tc == listTyCon && isCharTy arg_ty+ _ -> False++-- | Is a type a 'CallStack'?+isCallStackTy :: Type -> Bool+isCallStackTy ty+ | Just tc <- tyConAppTyCon_maybe ty+ = tc `hasKey` callStackTyConKey+ | otherwise+ = False++-- | Is a 'PredType' a 'CallStack' implicit parameter?+--+-- If so, return the name of the parameter.+isCallStackPred :: PredType -> Maybe FastString+isCallStackPred pred+ | Just (str, ty) <- isIPPred_maybe pred+ , isCallStackTy ty+ = Just str+ | otherwise+ = Nothing++is_tc :: Unique -> Type -> Bool+-- Newtypes are opaque to this+is_tc uniq ty = case tcSplitTyConApp_maybe ty of+ Just (tc, _) -> uniq == getUnique tc+ Nothing -> False++-- | Does the given tyvar appear in the given type outside of any+-- non-newtypes? Assume we're looking for @a@. Says "yes" for+-- @a@, @N a@, @b a@, @a b@, @b (N a)@. Says "no" for+-- @[a]@, @Maybe a@, @T a@, where @N@ is a newtype and @T@ is a datatype.+isTyVarExposed :: TcTyVar -> TcType -> Bool+isTyVarExposed tv (TyVarTy tv') = tv == tv'+isTyVarExposed tv (TyConApp tc tys)+ | isNewTyCon tc = any (isTyVarExposed tv) tys+ | otherwise = False+isTyVarExposed _ (LitTy {}) = False+isTyVarExposed tv (AppTy fun arg) = isTyVarExposed tv fun+ || isTyVarExposed tv arg+isTyVarExposed _ (ForAllTy {}) = False+isTyVarExposed _ (FunTy {}) = False+isTyVarExposed tv (CastTy ty _) = isTyVarExposed tv ty+isTyVarExposed _ (CoercionTy {}) = False++-- | Is the equality+-- a ~r ...a....+-- definitely insoluble or not?+-- a ~r Maybe a -- Definitely insoluble+-- a ~N ...(F a)... -- Not definitely insoluble+-- -- Perhaps (F a) reduces to Int+-- a ~R ...(N a)... -- Not definitely insoluble+-- -- Perhaps newtype N a = MkN Int+-- See Note [Occurs check error] in+-- TcCanonical for the motivation for this function.+isInsolubleOccursCheck :: EqRel -> TcTyVar -> TcType -> Bool+isInsolubleOccursCheck eq_rel tv ty+ = go ty+ where+ go ty | Just ty' <- tcView ty = go ty'+ go (TyVarTy tv') = tv == tv' || go (tyVarKind tv')+ go (LitTy {}) = False+ go (AppTy t1 t2) = go t1 || go t2+ go (FunTy t1 t2) = go t1 || go t2+ go (ForAllTy (TvBndr tv' _) inner_ty)+ | tv' == tv = False+ | otherwise = go (tyVarKind tv') || go inner_ty+ go (CastTy ty _) = go ty -- ToDo: what about the coercion+ go (CoercionTy _) = False -- ToDo: what about the coercion+ go (TyConApp tc tys)+ | isGenerativeTyCon tc role = any go tys+ | otherwise = False++ role = eqRelRole eq_rel++isRigidTy :: TcType -> Bool+isRigidTy ty+ | Just (tc,_) <- tcSplitTyConApp_maybe ty = isGenerativeTyCon tc Nominal+ | Just {} <- tcSplitAppTy_maybe ty = True+ | isForAllTy ty = True+ | otherwise = False++isRigidEqPred :: TcLevel -> PredTree -> Bool+-- ^ True of all Nominal equalities that are solidly insoluble+-- This means all equalities *except*+-- * Meta-tv non-SigTv on LHS+-- * Meta-tv SigTv on LHS, tyvar on right+isRigidEqPred tc_lvl (EqPred NomEq ty1 _)+ | Just tv1 <- tcGetTyVar_maybe ty1+ = ASSERT2( tcIsTcTyVar tv1, ppr tv1 )+ not (isMetaTyVar tv1) || isTouchableMetaTyVar tc_lvl tv1++ | otherwise -- LHS is not a tyvar+ = True++isRigidEqPred _ _ = False -- Not an equality++{-+************************************************************************+* *+\subsection{Transformation of Types to TcTypes}+* *+************************************************************************+-}++toTcType :: Type -> TcType+-- The constraint solver expects EvVars to have TcType, in which the+-- free type variables are TcTyVars. So we convert from Type to TcType here+-- A bit tiresome; but one day I expect the two types to be entirely separate+-- in which case we'll definitely need to do this+toTcType = runIdentity . to_tc_type emptyVarSet++toTcTypeBag :: Bag EvVar -> Bag EvVar -- All TyVars are transformed to TcTyVars+toTcTypeBag evvars = mapBag (\tv -> setTyVarKind tv (toTcType (tyVarKind tv))) evvars++to_tc_mapper :: TyCoMapper VarSet Identity+to_tc_mapper+ = TyCoMapper { tcm_smart = False -- more efficient not to use smart ctors+ , tcm_tyvar = tyvar+ , tcm_covar = covar+ , tcm_hole = hole+ , tcm_tybinder = tybinder }+ where+ tyvar :: VarSet -> TyVar -> Identity Type+ tyvar ftvs tv+ | Just var <- lookupVarSet ftvs tv = return $ TyVarTy var+ | isTcTyVar tv = TyVarTy <$> updateTyVarKindM (to_tc_type ftvs) tv+ | otherwise+ = do { kind' <- to_tc_type ftvs (tyVarKind tv)+ ; return $ TyVarTy $ mkTcTyVar (tyVarName tv) kind' vanillaSkolemTv }++ covar :: VarSet -> CoVar -> Identity Coercion+ covar ftvs cv+ | Just var <- lookupVarSet ftvs cv = return $ CoVarCo var+ | otherwise = CoVarCo <$> updateVarTypeM (to_tc_type ftvs) cv++ hole :: VarSet -> CoercionHole -> Role -> Type -> Type+ -> Identity Coercion+ hole ftvs h r t1 t2 = mkHoleCo h r <$> to_tc_type ftvs t1+ <*> to_tc_type ftvs t2++ tybinder :: VarSet -> TyVar -> ArgFlag -> Identity (VarSet, TyVar)+ tybinder ftvs tv _vis = do { kind' <- to_tc_type ftvs (tyVarKind tv)+ ; let tv' = mkTcTyVar (tyVarName tv) kind'+ vanillaSkolemTv+ ; return (ftvs `extendVarSet` tv', tv') }++to_tc_type :: VarSet -> Type -> Identity TcType+to_tc_type = mapType to_tc_mapper++{-+************************************************************************+* *+\subsection{Misc}+* *+************************************************************************++Note [Visible type application]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+GHC implements a generalisation of the algorithm described in the+"Visible Type Application" paper (available from+http://www.cis.upenn.edu/~sweirich/publications.html). A key part+of that algorithm is to distinguish user-specified variables from inferred+variables. For example, the following should typecheck:++ f :: forall a b. a -> b -> b+ f = const id++ g = const id++ x = f @Int @Bool 5 False+ y = g 5 @Bool False++The idea is that we wish to allow visible type application when we are+instantiating a specified, fixed variable. In practice, specified, fixed+variables are either written in a type signature (or+annotation), OR are imported from another module. (We could do better here,+for example by doing SCC analysis on parts of a module and considering any+type from outside one's SCC to be fully specified, but this is very confusing to+users. The simple rule above is much more straightforward and predictable.)++So, both of f's quantified variables are specified and may be instantiated.+But g has no type signature, so only id's variable is specified (because id+is imported). We write the type of g as forall {a}. a -> forall b. b -> b.+Note that the a is in braces, meaning it cannot be instantiated with+visible type application.++Tracking specified vs. inferred variables is done conveniently by a field+in TyBinder.++-}++deNoteType :: Type -> Type+-- Remove all *outermost* type synonyms and other notes+deNoteType ty | Just ty' <- coreView ty = deNoteType ty'+deNoteType ty = ty++{-+Find the free tycons and classes of a type. This is used in the front+end of the compiler.+-}++{-+************************************************************************+* *+\subsection[TysWiredIn-ext-type]{External types}+* *+************************************************************************++The compiler's foreign function interface supports the passing of a+restricted set of types as arguments and results (the restricting factor+being the )+-}++tcSplitIOType_maybe :: Type -> Maybe (TyCon, Type)+-- (tcSplitIOType_maybe t) returns Just (IO,t',co)+-- if co : t ~ IO t'+-- returns Nothing otherwise+tcSplitIOType_maybe ty+ = case tcSplitTyConApp_maybe ty of+ Just (io_tycon, [io_res_ty])+ | io_tycon `hasKey` ioTyConKey ->+ Just (io_tycon, io_res_ty)+ _ ->+ Nothing++isFFITy :: Type -> Bool+-- True for any TyCon that can possibly be an arg or result of an FFI call+isFFITy ty = isValid (checkRepTyCon legalFFITyCon ty)++isFFIArgumentTy :: DynFlags -> Safety -> Type -> Validity+-- Checks for valid argument type for a 'foreign import'+isFFIArgumentTy dflags safety ty+ = checkRepTyCon (legalOutgoingTyCon dflags safety) ty++isFFIExternalTy :: Type -> Validity+-- Types that are allowed as arguments of a 'foreign export'+isFFIExternalTy ty = checkRepTyCon legalFEArgTyCon ty++isFFIImportResultTy :: DynFlags -> Type -> Validity+isFFIImportResultTy dflags ty+ = checkRepTyCon (legalFIResultTyCon dflags) ty++isFFIExportResultTy :: Type -> Validity+isFFIExportResultTy ty = checkRepTyCon legalFEResultTyCon ty++isFFIDynTy :: Type -> Type -> Validity+-- The type in a foreign import dynamic must be Ptr, FunPtr, or a newtype of+-- either, and the wrapped function type must be equal to the given type.+-- We assume that all types have been run through normaliseFfiType, so we don't+-- need to worry about expanding newtypes here.+isFFIDynTy expected ty+ -- Note [Foreign import dynamic]+ -- In the example below, expected would be 'CInt -> IO ()', while ty would+ -- be 'FunPtr (CDouble -> IO ())'.+ | Just (tc, [ty']) <- splitTyConApp_maybe ty+ , tyConUnique tc `elem` [ptrTyConKey, funPtrTyConKey]+ , eqType ty' expected+ = IsValid+ | otherwise+ = NotValid (vcat [ text "Expected: Ptr/FunPtr" <+> pprParendType expected <> comma+ , text " Actual:" <+> ppr ty ])++isFFILabelTy :: Type -> Validity+-- The type of a foreign label must be Ptr, FunPtr, or a newtype of either.+isFFILabelTy ty = checkRepTyCon ok ty+ where+ ok tc | tc `hasKey` funPtrTyConKey || tc `hasKey` ptrTyConKey+ = IsValid+ | otherwise+ = NotValid (text "A foreign-imported address (via &foo) must have type (Ptr a) or (FunPtr a)")++isFFIPrimArgumentTy :: DynFlags -> Type -> Validity+-- Checks for valid argument type for a 'foreign import prim'+-- Currently they must all be simple unlifted types, or the well-known type+-- Any, which can be used to pass the address to a Haskell object on the heap to+-- the foreign function.+isFFIPrimArgumentTy dflags ty+ | isAnyTy ty = IsValid+ | otherwise = checkRepTyCon (legalFIPrimArgTyCon dflags) ty++isFFIPrimResultTy :: DynFlags -> Type -> Validity+-- Checks for valid result type for a 'foreign import prim' Currently+-- it must be an unlifted type, including unboxed tuples, unboxed+-- sums, or the well-known type Any.+isFFIPrimResultTy dflags ty+ | isAnyTy ty = IsValid+ | otherwise = checkRepTyCon (legalFIPrimResultTyCon dflags) ty++isFunPtrTy :: Type -> Bool+isFunPtrTy ty+ | Just (tc, [_]) <- splitTyConApp_maybe ty+ = tc `hasKey` funPtrTyConKey+ | otherwise+ = False++-- normaliseFfiType gets run before checkRepTyCon, so we don't+-- need to worry about looking through newtypes or type functions+-- here; that's already been taken care of.+checkRepTyCon :: (TyCon -> Validity) -> Type -> Validity+checkRepTyCon check_tc ty+ = case splitTyConApp_maybe ty of+ Just (tc, tys)+ | isNewTyCon tc -> NotValid (hang msg 2 (mk_nt_reason tc tys $$ nt_fix))+ | otherwise -> case check_tc tc of+ IsValid -> IsValid+ NotValid extra -> NotValid (msg $$ extra)+ Nothing -> NotValid (quotes (ppr ty) <+> text "is not a data type")+ where+ msg = quotes (ppr ty) <+> text "cannot be marshalled in a foreign call"+ mk_nt_reason tc tys+ | null tys = text "because its data constructor is not in scope"+ | otherwise = text "because the data constructor for"+ <+> quotes (ppr tc) <+> text "is not in scope"+ nt_fix = text "Possible fix: import the data constructor to bring it into scope"++{-+Note [Foreign import dynamic]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A dynamic stub must be of the form 'FunPtr ft -> ft' where ft is any foreign+type. Similarly, a wrapper stub must be of the form 'ft -> IO (FunPtr ft)'.++We use isFFIDynTy to check whether a signature is well-formed. For example,+given a (illegal) declaration like:++foreign import ccall "dynamic"+ foo :: FunPtr (CDouble -> IO ()) -> CInt -> IO ()++isFFIDynTy will compare the 'FunPtr' type 'CDouble -> IO ()' with the curried+result type 'CInt -> IO ()', and return False, as they are not equal.+++----------------------------------------------+These chaps do the work; they are not exported+----------------------------------------------+-}++legalFEArgTyCon :: TyCon -> Validity+legalFEArgTyCon tc+ -- It's illegal to make foreign exports that take unboxed+ -- arguments. The RTS API currently can't invoke such things. --SDM 7/2000+ = boxedMarshalableTyCon tc++legalFIResultTyCon :: DynFlags -> TyCon -> Validity+legalFIResultTyCon dflags tc+ | tc == unitTyCon = IsValid+ | otherwise = marshalableTyCon dflags tc++legalFEResultTyCon :: TyCon -> Validity+legalFEResultTyCon tc+ | tc == unitTyCon = IsValid+ | otherwise = boxedMarshalableTyCon tc++legalOutgoingTyCon :: DynFlags -> Safety -> TyCon -> Validity+-- Checks validity of types going from Haskell -> external world+legalOutgoingTyCon dflags _ tc+ = marshalableTyCon dflags tc++legalFFITyCon :: TyCon -> Validity+-- True for any TyCon that can possibly be an arg or result of an FFI call+legalFFITyCon tc+ | isUnliftedTyCon tc = IsValid+ | tc == unitTyCon = IsValid+ | otherwise = boxedMarshalableTyCon tc++marshalableTyCon :: DynFlags -> TyCon -> Validity+marshalableTyCon dflags tc+ | isUnliftedTyCon tc+ , not (isUnboxedTupleTyCon tc || isUnboxedSumTyCon tc)+ , not (null (tyConPrimRep tc)) -- Note [Marshalling void]+ = validIfUnliftedFFITypes dflags+ | otherwise+ = boxedMarshalableTyCon tc++boxedMarshalableTyCon :: TyCon -> Validity+boxedMarshalableTyCon tc+ | getUnique tc `elem` [ intTyConKey, int8TyConKey, int16TyConKey+ , int32TyConKey, int64TyConKey+ , wordTyConKey, word8TyConKey, word16TyConKey+ , word32TyConKey, word64TyConKey+ , floatTyConKey, doubleTyConKey+ , ptrTyConKey, funPtrTyConKey+ , charTyConKey+ , stablePtrTyConKey+ , boolTyConKey+ ]+ = IsValid++ | otherwise = NotValid empty++legalFIPrimArgTyCon :: DynFlags -> TyCon -> Validity+-- Check args of 'foreign import prim', only allow simple unlifted types.+-- Strictly speaking it is unnecessary to ban unboxed tuples and sums here since+-- currently they're of the wrong kind to use in function args anyway.+legalFIPrimArgTyCon dflags tc+ | isUnliftedTyCon tc+ , not (isUnboxedTupleTyCon tc || isUnboxedSumTyCon tc)+ = validIfUnliftedFFITypes dflags+ | otherwise+ = NotValid unlifted_only++legalFIPrimResultTyCon :: DynFlags -> TyCon -> Validity+-- Check result type of 'foreign import prim'. Allow simple unlifted+-- types and also unboxed tuple and sum result types.+legalFIPrimResultTyCon dflags tc+ | isUnliftedTyCon tc+ , isUnboxedTupleTyCon tc || isUnboxedSumTyCon tc+ || not (null (tyConPrimRep tc)) -- Note [Marshalling void]+ = validIfUnliftedFFITypes dflags++ | otherwise+ = NotValid unlifted_only++unlifted_only :: MsgDoc+unlifted_only = text "foreign import prim only accepts simple unlifted types"++validIfUnliftedFFITypes :: DynFlags -> Validity+validIfUnliftedFFITypes dflags+ | xopt LangExt.UnliftedFFITypes dflags = IsValid+ | otherwise = NotValid (text "To marshal unlifted types, use UnliftedFFITypes")++{-+Note [Marshalling void]+~~~~~~~~~~~~~~~~~~~~~~~+We don't treat State# (whose PrimRep is VoidRep) as marshalable.+In turn that means you can't write+ foreign import foo :: Int -> State# RealWorld++Reason: the back end falls over with panic "primRepHint:VoidRep";+ and there is no compelling reason to permit it+-}++{-+************************************************************************+* *+ The "Paterson size" of a type+* *+************************************************************************+-}++{-+Note [Paterson conditions on PredTypes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We are considering whether *class* constraints terminate+(see Note [Paterson conditions]). Precisely, the Paterson conditions+would have us check that "the constraint has fewer constructors and variables+(taken together and counting repetitions) than the head.".++However, we can be a bit more refined by looking at which kind of constraint+this actually is. There are two main tricks:++ 1. It seems like it should be OK not to count the tuple type constructor+ for a PredType like (Show a, Eq a) :: Constraint, since we don't+ count the "implicit" tuple in the ThetaType itself.++ In fact, the Paterson test just checks *each component* of the top level+ ThetaType against the size bound, one at a time. By analogy, it should be+ OK to return the size of the *largest* tuple component as the size of the+ whole tuple.++ 2. Once we get into an implicit parameter or equality we+ can't get back to a class constraint, so it's safe+ to say "size 0". See Trac #4200.++NB: we don't want to detect PredTypes in sizeType (and then call+sizePred on them), or we might get an infinite loop if that PredType+is irreducible. See Trac #5581.+-}++type TypeSize = IntWithInf++sizeType :: Type -> TypeSize+-- Size of a type: the number of variables and constructors+-- Ignore kinds altogether+sizeType = go+ where+ go ty | Just exp_ty <- tcView ty = go exp_ty+ go (TyVarTy {}) = 1+ go (TyConApp tc tys)+ | isTypeFamilyTyCon tc = infinity -- Type-family applications can+ -- expand to any arbitrary size+ | otherwise = sizeTypes (filterOutInvisibleTypes tc tys) + 1+ go (LitTy {}) = 1+ go (FunTy arg res) = go arg + go res + 1+ go (AppTy fun arg) = go fun + go arg+ go (ForAllTy (TvBndr tv vis) ty)+ | isVisibleArgFlag vis = go (tyVarKind tv) + go ty + 1+ | otherwise = go ty + 1+ go (CastTy ty _) = go ty+ go (CoercionTy {}) = 0++sizeTypes :: [Type] -> TypeSize+sizeTypes tys = sum (map sizeType tys)
+ typecheck/TcType.hs-boot view
@@ -0,0 +1,8 @@+module TcType where+import Outputable( SDoc )++data MetaDetails++data TcTyVarDetails+pprTcTyVarDetails :: TcTyVarDetails -> SDoc+vanillaSkolemTv :: TcTyVarDetails
+ typecheck/TcTypeNats.hs view
@@ -0,0 +1,757 @@+{-# LANGUAGE LambdaCase #-}++module TcTypeNats+ ( typeNatTyCons+ , typeNatCoAxiomRules+ , BuiltInSynFamily(..)++ , typeNatAddTyCon+ , typeNatMulTyCon+ , typeNatExpTyCon+ , typeNatLeqTyCon+ , typeNatSubTyCon+ , typeNatCmpTyCon+ , typeSymbolCmpTyCon+ , typeSymbolAppendTyCon+ ) where++import Type+import Pair+import TcType ( TcType, tcEqType )+import TyCon ( TyCon, FamTyConFlav(..), mkFamilyTyCon+ , Injectivity(..) )+import Coercion ( Role(..) )+import TcRnTypes ( Xi )+import CoAxiom ( CoAxiomRule(..), BuiltInSynFamily(..), TypeEqn )+import Name ( Name, BuiltInSyntax(..) )+import TysWiredIn+import TysPrim ( mkTemplateAnonTyConBinders )+import PrelNames ( gHC_TYPELITS+ , gHC_TYPENATS+ , typeNatAddTyFamNameKey+ , typeNatMulTyFamNameKey+ , typeNatExpTyFamNameKey+ , typeNatLeqTyFamNameKey+ , typeNatSubTyFamNameKey+ , typeNatCmpTyFamNameKey+ , typeSymbolCmpTyFamNameKey+ , typeSymbolAppendFamNameKey+ )+import FastString ( FastString+ , fsLit, nilFS, nullFS, unpackFS, mkFastString, appendFS+ )+import qualified Data.Map as Map+import Data.Maybe ( isJust )+import Data.List ( isPrefixOf, isSuffixOf )++{-------------------------------------------------------------------------------+Built-in type constructors for functions on type-level nats+-}++typeNatTyCons :: [TyCon]+typeNatTyCons =+ [ typeNatAddTyCon+ , typeNatMulTyCon+ , typeNatExpTyCon+ , typeNatLeqTyCon+ , typeNatSubTyCon+ , typeNatCmpTyCon+ , typeSymbolCmpTyCon+ , typeSymbolAppendTyCon+ ]++typeNatAddTyCon :: TyCon+typeNatAddTyCon = mkTypeNatFunTyCon2 name+ BuiltInSynFamily+ { sfMatchFam = matchFamAdd+ , sfInteractTop = interactTopAdd+ , sfInteractInert = interactInertAdd+ }+ where+ name = mkWiredInTyConName UserSyntax gHC_TYPENATS (fsLit "+")+ typeNatAddTyFamNameKey typeNatAddTyCon++typeNatSubTyCon :: TyCon+typeNatSubTyCon = mkTypeNatFunTyCon2 name+ BuiltInSynFamily+ { sfMatchFam = matchFamSub+ , sfInteractTop = interactTopSub+ , sfInteractInert = interactInertSub+ }+ where+ name = mkWiredInTyConName UserSyntax gHC_TYPENATS (fsLit "-")+ typeNatSubTyFamNameKey typeNatSubTyCon++typeNatMulTyCon :: TyCon+typeNatMulTyCon = mkTypeNatFunTyCon2 name+ BuiltInSynFamily+ { sfMatchFam = matchFamMul+ , sfInteractTop = interactTopMul+ , sfInteractInert = interactInertMul+ }+ where+ name = mkWiredInTyConName UserSyntax gHC_TYPENATS (fsLit "*")+ typeNatMulTyFamNameKey typeNatMulTyCon++typeNatExpTyCon :: TyCon+typeNatExpTyCon = mkTypeNatFunTyCon2 name+ BuiltInSynFamily+ { sfMatchFam = matchFamExp+ , sfInteractTop = interactTopExp+ , sfInteractInert = interactInertExp+ }+ where+ name = mkWiredInTyConName UserSyntax gHC_TYPENATS (fsLit "^")+ typeNatExpTyFamNameKey typeNatExpTyCon++typeNatLeqTyCon :: TyCon+typeNatLeqTyCon =+ mkFamilyTyCon name+ (mkTemplateAnonTyConBinders [ typeNatKind, typeNatKind ])+ boolTy+ Nothing+ (BuiltInSynFamTyCon ops)+ Nothing+ NotInjective++ where+ name = mkWiredInTyConName UserSyntax gHC_TYPENATS (fsLit "<=?")+ typeNatLeqTyFamNameKey typeNatLeqTyCon+ ops = BuiltInSynFamily+ { sfMatchFam = matchFamLeq+ , sfInteractTop = interactTopLeq+ , sfInteractInert = interactInertLeq+ }++typeNatCmpTyCon :: TyCon+typeNatCmpTyCon =+ mkFamilyTyCon name+ (mkTemplateAnonTyConBinders [ typeNatKind, typeNatKind ])+ orderingKind+ Nothing+ (BuiltInSynFamTyCon ops)+ Nothing+ NotInjective++ where+ name = mkWiredInTyConName UserSyntax gHC_TYPENATS (fsLit "CmpNat")+ typeNatCmpTyFamNameKey typeNatCmpTyCon+ ops = BuiltInSynFamily+ { sfMatchFam = matchFamCmpNat+ , sfInteractTop = interactTopCmpNat+ , sfInteractInert = \_ _ _ _ -> []+ }++typeSymbolCmpTyCon :: TyCon+typeSymbolCmpTyCon =+ mkFamilyTyCon name+ (mkTemplateAnonTyConBinders [ typeSymbolKind, typeSymbolKind ])+ orderingKind+ Nothing+ (BuiltInSynFamTyCon ops)+ Nothing+ NotInjective++ where+ name = mkWiredInTyConName UserSyntax gHC_TYPELITS (fsLit "CmpSymbol")+ typeSymbolCmpTyFamNameKey typeSymbolCmpTyCon+ ops = BuiltInSynFamily+ { sfMatchFam = matchFamCmpSymbol+ , sfInteractTop = interactTopCmpSymbol+ , sfInteractInert = \_ _ _ _ -> []+ }++typeSymbolAppendTyCon :: TyCon+typeSymbolAppendTyCon = mkTypeSymbolFunTyCon2 name+ BuiltInSynFamily+ { sfMatchFam = matchFamAppendSymbol+ , sfInteractTop = interactTopAppendSymbol+ , sfInteractInert = interactInertAppendSymbol+ }+ where+ name = mkWiredInTyConName UserSyntax gHC_TYPELITS (fsLit "AppendSymbol")+ typeSymbolAppendFamNameKey typeSymbolAppendTyCon+++++-- Make a binary built-in constructor of kind: Nat -> Nat -> Nat+mkTypeNatFunTyCon2 :: Name -> BuiltInSynFamily -> TyCon+mkTypeNatFunTyCon2 op tcb =+ mkFamilyTyCon op+ (mkTemplateAnonTyConBinders [ typeNatKind, typeNatKind ])+ typeNatKind+ Nothing+ (BuiltInSynFamTyCon tcb)+ Nothing+ NotInjective++-- Make a binary built-in constructor of kind: Symbol -> Symbol -> Symbol+mkTypeSymbolFunTyCon2 :: Name -> BuiltInSynFamily -> TyCon+mkTypeSymbolFunTyCon2 op tcb =+ mkFamilyTyCon op+ (mkTemplateAnonTyConBinders [ typeSymbolKind, typeSymbolKind ])+ typeSymbolKind+ Nothing+ (BuiltInSynFamTyCon tcb)+ Nothing+ NotInjective+++{-------------------------------------------------------------------------------+Built-in rules axioms+-------------------------------------------------------------------------------}++-- If you add additional rules, please remember to add them to+-- `typeNatCoAxiomRules` also.+axAddDef+ , axMulDef+ , axExpDef+ , axLeqDef+ , axCmpNatDef+ , axCmpSymbolDef+ , axAppendSymbolDef+ , axAdd0L+ , axAdd0R+ , axMul0L+ , axMul0R+ , axMul1L+ , axMul1R+ , axExp1L+ , axExp0R+ , axExp1R+ , axLeqRefl+ , axCmpNatRefl+ , axCmpSymbolRefl+ , axLeq0L+ , axSubDef+ , axSub0R+ , axAppendSymbol0R+ , axAppendSymbol0L+ :: CoAxiomRule++axAddDef = mkBinAxiom "AddDef" typeNatAddTyCon $+ \x y -> Just $ num (x + y)++axMulDef = mkBinAxiom "MulDef" typeNatMulTyCon $+ \x y -> Just $ num (x * y)++axExpDef = mkBinAxiom "ExpDef" typeNatExpTyCon $+ \x y -> Just $ num (x ^ y)++axLeqDef = mkBinAxiom "LeqDef" typeNatLeqTyCon $+ \x y -> Just $ bool (x <= y)++axCmpNatDef = mkBinAxiom "CmpNatDef" typeNatCmpTyCon+ $ \x y -> Just $ ordering (compare x y)++axCmpSymbolDef =+ CoAxiomRule+ { coaxrName = fsLit "CmpSymbolDef"+ , coaxrAsmpRoles = [Nominal, Nominal]+ , coaxrRole = Nominal+ , coaxrProves = \cs ->+ do [Pair s1 s2, Pair t1 t2] <- return cs+ s2' <- isStrLitTy s2+ t2' <- isStrLitTy t2+ return (mkTyConApp typeSymbolCmpTyCon [s1,t1] ===+ ordering (compare s2' t2')) }++axAppendSymbolDef = CoAxiomRule+ { coaxrName = fsLit "AppendSymbolDef"+ , coaxrAsmpRoles = [Nominal, Nominal]+ , coaxrRole = Nominal+ , coaxrProves = \cs ->+ do [Pair s1 s2, Pair t1 t2] <- return cs+ s2' <- isStrLitTy s2+ t2' <- isStrLitTy t2+ let z = mkStrLitTy (appendFS s2' t2')+ return (mkTyConApp typeSymbolAppendTyCon [s1, t1] === z)+ }++axSubDef = mkBinAxiom "SubDef" typeNatSubTyCon $+ \x y -> fmap num (minus x y)++axAdd0L = mkAxiom1 "Add0L" $ \(Pair s t) -> (num 0 .+. s) === t+axAdd0R = mkAxiom1 "Add0R" $ \(Pair s t) -> (s .+. num 0) === t+axSub0R = mkAxiom1 "Sub0R" $ \(Pair s t) -> (s .-. num 0) === t+axMul0L = mkAxiom1 "Mul0L" $ \(Pair s _) -> (num 0 .*. s) === num 0+axMul0R = mkAxiom1 "Mul0R" $ \(Pair s _) -> (s .*. num 0) === num 0+axMul1L = mkAxiom1 "Mul1L" $ \(Pair s t) -> (num 1 .*. s) === t+axMul1R = mkAxiom1 "Mul1R" $ \(Pair s t) -> (s .*. num 1) === t+axExp1L = mkAxiom1 "Exp1L" $ \(Pair s _) -> (num 1 .^. s) === num 1+axExp0R = mkAxiom1 "Exp0R" $ \(Pair s _) -> (s .^. num 0) === num 1+axExp1R = mkAxiom1 "Exp1R" $ \(Pair s t) -> (s .^. num 1) === t+axLeqRefl = mkAxiom1 "LeqRefl" $ \(Pair s _) -> (s <== s) === bool True+axCmpNatRefl = mkAxiom1 "CmpNatRefl"+ $ \(Pair s _) -> (cmpNat s s) === ordering EQ+axCmpSymbolRefl = mkAxiom1 "CmpSymbolRefl"+ $ \(Pair s _) -> (cmpSymbol s s) === ordering EQ+axLeq0L = mkAxiom1 "Leq0L" $ \(Pair s _) -> (num 0 <== s) === bool True+axAppendSymbol0R = mkAxiom1 "Concat0R"+ $ \(Pair s t) -> (mkStrLitTy nilFS `appendSymbol` s) === t+axAppendSymbol0L = mkAxiom1 "Concat0L"+ $ \(Pair s t) -> (s `appendSymbol` mkStrLitTy nilFS) === t++typeNatCoAxiomRules :: Map.Map FastString CoAxiomRule+typeNatCoAxiomRules = Map.fromList $ map (\x -> (coaxrName x, x))+ [ axAddDef+ , axMulDef+ , axExpDef+ , axLeqDef+ , axCmpNatDef+ , axCmpSymbolDef+ , axAppendSymbolDef+ , axAdd0L+ , axAdd0R+ , axMul0L+ , axMul0R+ , axMul1L+ , axMul1R+ , axExp1L+ , axExp0R+ , axExp1R+ , axLeqRefl+ , axCmpNatRefl+ , axCmpSymbolRefl+ , axLeq0L+ , axSubDef+ , axAppendSymbol0R+ , axAppendSymbol0L+ ]++++{-------------------------------------------------------------------------------+Various utilities for making axioms and types+-------------------------------------------------------------------------------}++(.+.) :: Type -> Type -> Type+s .+. t = mkTyConApp typeNatAddTyCon [s,t]++(.-.) :: Type -> Type -> Type+s .-. t = mkTyConApp typeNatSubTyCon [s,t]++(.*.) :: Type -> Type -> Type+s .*. t = mkTyConApp typeNatMulTyCon [s,t]++(.^.) :: Type -> Type -> Type+s .^. t = mkTyConApp typeNatExpTyCon [s,t]++(<==) :: Type -> Type -> Type+s <== t = mkTyConApp typeNatLeqTyCon [s,t]++cmpNat :: Type -> Type -> Type+cmpNat s t = mkTyConApp typeNatCmpTyCon [s,t]++cmpSymbol :: Type -> Type -> Type+cmpSymbol s t = mkTyConApp typeSymbolCmpTyCon [s,t]++appendSymbol :: Type -> Type -> Type+appendSymbol s t = mkTyConApp typeSymbolAppendTyCon [s, t]++(===) :: Type -> Type -> Pair Type+x === y = Pair x y++num :: Integer -> Type+num = mkNumLitTy++bool :: Bool -> Type+bool b = if b then mkTyConApp promotedTrueDataCon []+ else mkTyConApp promotedFalseDataCon []++isBoolLitTy :: Type -> Maybe Bool+isBoolLitTy tc =+ do (tc,[]) <- splitTyConApp_maybe tc+ case () of+ _ | tc == promotedFalseDataCon -> return False+ | tc == promotedTrueDataCon -> return True+ | otherwise -> Nothing++orderingKind :: Kind+orderingKind = mkTyConApp orderingTyCon []++ordering :: Ordering -> Type+ordering o =+ case o of+ LT -> mkTyConApp promotedLTDataCon []+ EQ -> mkTyConApp promotedEQDataCon []+ GT -> mkTyConApp promotedGTDataCon []++isOrderingLitTy :: Type -> Maybe Ordering+isOrderingLitTy tc =+ do (tc1,[]) <- splitTyConApp_maybe tc+ case () of+ _ | tc1 == promotedLTDataCon -> return LT+ | tc1 == promotedEQDataCon -> return EQ+ | tc1 == promotedGTDataCon -> return GT+ | otherwise -> Nothing++known :: (Integer -> Bool) -> TcType -> Bool+known p x = case isNumLitTy x of+ Just a -> p a+ Nothing -> False+++++-- For the definitional axioms+mkBinAxiom :: String -> TyCon ->+ (Integer -> Integer -> Maybe Type) -> CoAxiomRule+mkBinAxiom str tc f =+ CoAxiomRule+ { coaxrName = fsLit str+ , coaxrAsmpRoles = [Nominal, Nominal]+ , coaxrRole = Nominal+ , coaxrProves = \cs ->+ do [Pair s1 s2, Pair t1 t2] <- return cs+ s2' <- isNumLitTy s2+ t2' <- isNumLitTy t2+ z <- f s2' t2'+ return (mkTyConApp tc [s1,t1] === z)+ }++++mkAxiom1 :: String -> (TypeEqn -> TypeEqn) -> CoAxiomRule+mkAxiom1 str f =+ CoAxiomRule+ { coaxrName = fsLit str+ , coaxrAsmpRoles = [Nominal]+ , coaxrRole = Nominal+ , coaxrProves = \case [eqn] -> Just (f eqn)+ _ -> Nothing+ }+++{-------------------------------------------------------------------------------+Evaluation+-------------------------------------------------------------------------------}++matchFamAdd :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamAdd [s,t]+ | Just 0 <- mbX = Just (axAdd0L, [t], t)+ | Just 0 <- mbY = Just (axAdd0R, [s], s)+ | Just x <- mbX, Just y <- mbY =+ Just (axAddDef, [s,t], num (x + y))+ where mbX = isNumLitTy s+ mbY = isNumLitTy t+matchFamAdd _ = Nothing++matchFamSub :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamSub [s,t]+ | Just 0 <- mbY = Just (axSub0R, [s], s)+ | Just x <- mbX, Just y <- mbY, Just z <- minus x y =+ Just (axSubDef, [s,t], num z)+ where mbX = isNumLitTy s+ mbY = isNumLitTy t+matchFamSub _ = Nothing++matchFamMul :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamMul [s,t]+ | Just 0 <- mbX = Just (axMul0L, [t], num 0)+ | Just 0 <- mbY = Just (axMul0R, [s], num 0)+ | Just 1 <- mbX = Just (axMul1L, [t], t)+ | Just 1 <- mbY = Just (axMul1R, [s], s)+ | Just x <- mbX, Just y <- mbY =+ Just (axMulDef, [s,t], num (x * y))+ where mbX = isNumLitTy s+ mbY = isNumLitTy t+matchFamMul _ = Nothing++matchFamExp :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamExp [s,t]+ | Just 0 <- mbY = Just (axExp0R, [s], num 1)+ | Just 1 <- mbX = Just (axExp1L, [t], num 1)+ | Just 1 <- mbY = Just (axExp1R, [s], s)+ | Just x <- mbX, Just y <- mbY =+ Just (axExpDef, [s,t], num (x ^ y))+ where mbX = isNumLitTy s+ mbY = isNumLitTy t+matchFamExp _ = Nothing++matchFamLeq :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamLeq [s,t]+ | Just 0 <- mbX = Just (axLeq0L, [t], bool True)+ | Just x <- mbX, Just y <- mbY =+ Just (axLeqDef, [s,t], bool (x <= y))+ | tcEqType s t = Just (axLeqRefl, [s], bool True)+ where mbX = isNumLitTy s+ mbY = isNumLitTy t+matchFamLeq _ = Nothing++matchFamCmpNat :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamCmpNat [s,t]+ | Just x <- mbX, Just y <- mbY =+ Just (axCmpNatDef, [s,t], ordering (compare x y))+ | tcEqType s t = Just (axCmpNatRefl, [s], ordering EQ)+ where mbX = isNumLitTy s+ mbY = isNumLitTy t+matchFamCmpNat _ = Nothing++matchFamCmpSymbol :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamCmpSymbol [s,t]+ | Just x <- mbX, Just y <- mbY =+ Just (axCmpSymbolDef, [s,t], ordering (compare x y))+ | tcEqType s t = Just (axCmpSymbolRefl, [s], ordering EQ)+ where mbX = isStrLitTy s+ mbY = isStrLitTy t+matchFamCmpSymbol _ = Nothing++matchFamAppendSymbol :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+matchFamAppendSymbol [s,t]+ | Just x <- mbX, nullFS x = Just (axAppendSymbol0R, [t], t)+ | Just y <- mbY, nullFS y = Just (axAppendSymbol0L, [s], s)+ | Just x <- mbX, Just y <- mbY =+ Just (axAppendSymbolDef, [s,t], mkStrLitTy (appendFS x y))+ where+ mbX = isStrLitTy s+ mbY = isStrLitTy t+matchFamAppendSymbol _ = Nothing++{-------------------------------------------------------------------------------+Interact with axioms+-------------------------------------------------------------------------------}++interactTopAdd :: [Xi] -> Xi -> [Pair Type]+interactTopAdd [s,t] r+ | Just 0 <- mbZ = [ s === num 0, t === num 0 ] -- (s + t ~ 0) => (s ~ 0, t ~ 0)+ | Just x <- mbX, Just z <- mbZ, Just y <- minus z x = [t === num y] -- (5 + t ~ 8) => (t ~ 3)+ | Just y <- mbY, Just z <- mbZ, Just x <- minus z y = [s === num x] -- (s + 5 ~ 8) => (s ~ 3)+ where+ mbX = isNumLitTy s+ mbY = isNumLitTy t+ mbZ = isNumLitTy r+interactTopAdd _ _ = []++{-+Note [Weakened interaction rule for subtraction]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++A simpler interaction here might be:++ `s - t ~ r` --> `t + r ~ s`++This would enable us to reuse all the code for addition.+Unfortunately, this works a little too well at the moment.+Consider the following example:++ 0 - 5 ~ r --> 5 + r ~ 0 --> (5 = 0, r = 0)++This (correctly) spots that the constraint cannot be solved.++However, this may be a problem if the constraint did not+need to be solved in the first place! Consider the following example:++f :: Proxy (If (5 <=? 0) (0 - 5) (5 - 0)) -> Proxy 5+f = id++Currently, GHC is strict while evaluating functions, so this does not+work, because even though the `If` should evaluate to `5 - 0`, we+also evaluate the "then" branch which generates the constraint `0 - 5 ~ r`,+which fails.++So, for the time being, we only add an improvement when the RHS is a constant,+which happens to work OK for the moment, although clearly we need to do+something more general.+-}+interactTopSub :: [Xi] -> Xi -> [Pair Type]+interactTopSub [s,t] r+ | Just z <- mbZ = [ s === (num z .+. t) ] -- (s - t ~ 5) => (5 + t ~ s)+ where+ mbZ = isNumLitTy r+interactTopSub _ _ = []++++++interactTopMul :: [Xi] -> Xi -> [Pair Type]+interactTopMul [s,t] r+ | Just 1 <- mbZ = [ s === num 1, t === num 1 ] -- (s * t ~ 1) => (s ~ 1, t ~ 1)+ | Just x <- mbX, Just z <- mbZ, Just y <- divide z x = [t === num y] -- (3 * t ~ 15) => (t ~ 5)+ | Just y <- mbY, Just z <- mbZ, Just x <- divide z y = [s === num x] -- (s * 3 ~ 15) => (s ~ 5)+ where+ mbX = isNumLitTy s+ mbY = isNumLitTy t+ mbZ = isNumLitTy r+interactTopMul _ _ = []++interactTopExp :: [Xi] -> Xi -> [Pair Type]+interactTopExp [s,t] r+ | Just 0 <- mbZ = [ s === num 0 ] -- (s ^ t ~ 0) => (s ~ 0)+ | Just x <- mbX, Just z <- mbZ, Just y <- logExact z x = [t === num y] -- (2 ^ t ~ 8) => (t ~ 3)+ | Just y <- mbY, Just z <- mbZ, Just x <- rootExact z y = [s === num x] -- (s ^ 2 ~ 9) => (s ~ 3)+ where+ mbX = isNumLitTy s+ mbY = isNumLitTy t+ mbZ = isNumLitTy r+interactTopExp _ _ = []++interactTopLeq :: [Xi] -> Xi -> [Pair Type]+interactTopLeq [s,t] r+ | Just 0 <- mbY, Just True <- mbZ = [ s === num 0 ] -- (s <= 0) => (s ~ 0)+ where+ mbY = isNumLitTy t+ mbZ = isBoolLitTy r+interactTopLeq _ _ = []++interactTopCmpNat :: [Xi] -> Xi -> [Pair Type]+interactTopCmpNat [s,t] r+ | Just EQ <- isOrderingLitTy r = [ s === t ]+interactTopCmpNat _ _ = []++interactTopCmpSymbol :: [Xi] -> Xi -> [Pair Type]+interactTopCmpSymbol [s,t] r+ | Just EQ <- isOrderingLitTy r = [ s === t ]+interactTopCmpSymbol _ _ = []++interactTopAppendSymbol :: [Xi] -> Xi -> [Pair Type]+interactTopAppendSymbol [s,t] r+ -- (AppendSymbol a b ~ "") => (a ~ "", b ~ "")+ | Just z <- mbZ, nullFS z =+ [s === mkStrLitTy nilFS, t === mkStrLitTy nilFS ]++ -- (AppendSymbol "foo" b ~ "foobar") => (b ~ "bar")+ | Just x <- fmap unpackFS mbX, Just z <- fmap unpackFS mbZ, x `isPrefixOf` z =+ [ t === mkStrLitTy (mkFastString $ drop (length x) z) ]++ -- (AppendSymbol f "bar" ~ "foobar") => (f ~ "foo")+ | Just y <- fmap unpackFS mbY, Just z <- fmap unpackFS mbZ, y `isSuffixOf` z =+ [ t === mkStrLitTy (mkFastString $ take (length z - length y) z) ]++ where+ mbX = isStrLitTy s+ mbY = isStrLitTy t+ mbZ = isStrLitTy r++interactTopAppendSymbol _ _ = []++{-------------------------------------------------------------------------------+Interaction with inerts+-------------------------------------------------------------------------------}++interactInertAdd :: [Xi] -> Xi -> [Xi] -> Xi -> [Pair Type]+interactInertAdd [x1,y1] z1 [x2,y2] z2+ | sameZ && tcEqType x1 x2 = [ y1 === y2 ]+ | sameZ && tcEqType y1 y2 = [ x1 === x2 ]+ where sameZ = tcEqType z1 z2+interactInertAdd _ _ _ _ = []++interactInertSub :: [Xi] -> Xi -> [Xi] -> Xi -> [Pair Type]+interactInertSub [x1,y1] z1 [x2,y2] z2+ | sameZ && tcEqType x1 x2 = [ y1 === y2 ]+ | sameZ && tcEqType y1 y2 = [ x1 === x2 ]+ where sameZ = tcEqType z1 z2+interactInertSub _ _ _ _ = []++interactInertMul :: [Xi] -> Xi -> [Xi] -> Xi -> [Pair Type]+interactInertMul [x1,y1] z1 [x2,y2] z2+ | sameZ && known (/= 0) x1 && tcEqType x1 x2 = [ y1 === y2 ]+ | sameZ && known (/= 0) y1 && tcEqType y1 y2 = [ x1 === x2 ]+ where sameZ = tcEqType z1 z2++interactInertMul _ _ _ _ = []++interactInertExp :: [Xi] -> Xi -> [Xi] -> Xi -> [Pair Type]+interactInertExp [x1,y1] z1 [x2,y2] z2+ | sameZ && known (> 1) x1 && tcEqType x1 x2 = [ y1 === y2 ]+ | sameZ && known (> 0) y1 && tcEqType y1 y2 = [ x1 === x2 ]+ where sameZ = tcEqType z1 z2++interactInertExp _ _ _ _ = []+++interactInertLeq :: [Xi] -> Xi -> [Xi] -> Xi -> [Pair Type]+interactInertLeq [x1,y1] z1 [x2,y2] z2+ | bothTrue && tcEqType x1 y2 && tcEqType y1 x2 = [ x1 === y1 ]+ | bothTrue && tcEqType y1 x2 = [ (x1 <== y2) === bool True ]+ | bothTrue && tcEqType y2 x1 = [ (x2 <== y1) === bool True ]+ where bothTrue = isJust $ do True <- isBoolLitTy z1+ True <- isBoolLitTy z2+ return ()++interactInertLeq _ _ _ _ = []+++interactInertAppendSymbol :: [Xi] -> Xi -> [Xi] -> Xi -> [Pair Type]+interactInertAppendSymbol [x1,y1] z1 [x2,y2] z2+ | sameZ && tcEqType x1 x2 = [ y1 === y2 ]+ | sameZ && tcEqType y1 y2 = [ x1 === x2 ]+ where sameZ = tcEqType z1 z2+interactInertAppendSymbol _ _ _ _ = []++++{- -----------------------------------------------------------------------------+These inverse functions are used for simplifying propositions using+concrete natural numbers.+----------------------------------------------------------------------------- -}++-- | Subtract two natural numbers.+minus :: Integer -> Integer -> Maybe Integer+minus x y = if x >= y then Just (x - y) else Nothing++-- | Compute the exact logarithm of a natural number.+-- The logarithm base is the second argument.+logExact :: Integer -> Integer -> Maybe Integer+logExact x y = do (z,True) <- genLog x y+ return z+++-- | Divide two natural numbers.+divide :: Integer -> Integer -> Maybe Integer+divide _ 0 = Nothing+divide x y = case divMod x y of+ (a,0) -> Just a+ _ -> Nothing++-- | Compute the exact root of a natural number.+-- The second argument specifies which root we are computing.+rootExact :: Integer -> Integer -> Maybe Integer+rootExact x y = do (z,True) <- genRoot x y+ return z++++{- | Compute the the n-th root of a natural number, rounded down to+the closest natural number. The boolean indicates if the result+is exact (i.e., True means no rounding was done, False means rounded down).+The second argument specifies which root we are computing. -}+genRoot :: Integer -> Integer -> Maybe (Integer, Bool)+genRoot _ 0 = Nothing+genRoot x0 1 = Just (x0, True)+genRoot x0 root = Just (search 0 (x0+1))+ where+ search from to = let x = from + div (to - from) 2+ a = x ^ root+ in case compare a x0 of+ EQ -> (x, True)+ LT | x /= from -> search x to+ | otherwise -> (from, False)+ GT | x /= to -> search from x+ | otherwise -> (from, False)++{- | Compute the logarithm of a number in the given base, rounded down to the+closest integer. The boolean indicates if we the result is exact+(i.e., True means no rounding happened, False means we rounded down).+The logarithm base is the second argument. -}+genLog :: Integer -> Integer -> Maybe (Integer, Bool)+genLog x 0 = if x == 1 then Just (0, True) else Nothing+genLog _ 1 = Nothing+genLog 0 _ = Nothing+genLog x base = Just (exactLoop 0 x)+ where+ exactLoop s i+ | i == 1 = (s,True)+ | i < base = (s,False)+ | otherwise =+ let s1 = s + 1+ in s1 `seq` case divMod i base of+ (j,r)+ | r == 0 -> exactLoop s1 j+ | otherwise -> (underLoop s1 j, False)++ underLoop s i+ | i < base = s+ | otherwise = let s1 = s + 1 in s1 `seq` underLoop s1 (div i base)
+ typecheck/TcTypeNats.hs-boot view
@@ -0,0 +1,5 @@+module TcTypeNats where++import TyCon (TyCon)++typeNatTyCons :: [TyCon]
+ typecheck/TcTypeable.hs view
@@ -0,0 +1,701 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1999+-}++{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++module TcTypeable(mkTypeableBinds) where+++import BasicTypes ( SourceText(..), Boxity(..), neverInlinePragma )+import TcBinds( addTypecheckedBinds )+import IfaceEnv( newGlobalBinder )+import TyCoRep( Type(..), TyLit(..) )+import TcEnv+import TcEvidence ( mkWpTyApps )+import TcRnMonad+import HscTypes ( lookupId )+import PrelNames+import TysPrim ( primTyCons )+import TysWiredIn ( tupleTyCon, sumTyCon, runtimeRepTyCon+ , vecCountTyCon, vecElemTyCon+ , nilDataCon, consDataCon )+import Id+import Type+import Kind ( isTYPEApp )+import TyCon+import DataCon+import Name ( Name, getOccName )+import OccName+import Module+import HsSyn+import DynFlags+import Bag+import Var ( TyVarBndr(..) )+import TrieMap+import Constants+import Fingerprint(Fingerprint(..), fingerprintString, fingerprintFingerprints)+import Outputable+import FastString ( FastString, mkFastString, fsLit )++import Control.Monad.Trans.State+import Control.Monad.Trans.Class (lift)+import Data.Maybe ( isJust )+import Data.Word( Word64 )++{- Note [Grand plan for Typeable]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The overall plan is this:++1. Generate a binding for each module p:M+ (done in TcTypeable by mkModIdBindings)+ M.$trModule :: GHC.Types.Module+ M.$trModule = Module "p" "M"+ ("tr" is short for "type representation"; see GHC.Types)++ We might want to add the filename too.+ This can be used for the lightweight stack-tracing stuff too++ Record the Name M.$trModule in the tcg_tr_module field of TcGblEnv++2. Generate a binding for every data type declaration T in module M,+ M.$tcT :: GHC.Types.TyCon+ M.$tcT = TyCon ...fingerprint info...+ $trModule+ "T"+ 0#+ kind_rep++ Here 0# is the number of arguments expected by the tycon to fully determine+ its kind. kind_rep is a value of type GHC.Types.KindRep, which gives a+ recipe for computing the kind of an instantiation of the tycon (see+ Note [Representing TyCon kinds] later in this file for details).++ We define (in TyCon)++ type TyConRepName = Name++ to use for these M.$tcT "tycon rep names". Note that these must be+ treated as "never exported" names by Backpack (see+ Note [Handling never-exported TyThings under Backpack]). Consequently+ they get slightly special treatment in RnModIface.rnIfaceDecl.++3. Record the TyConRepName in T's TyCon, including for promoted+ data and type constructors, and kinds like * and #.++ The TyConRepName is not an "implicit Id". It's more like a record+ selector: the TyCon knows its name but you have to go to the+ interface file to find its type, value, etc++4. Solve Typeable constraints. This is done by a custom Typeable solver,+ currently in TcInteract, that use M.$tcT so solve (Typeable T).++There are many wrinkles:++* The timing of when we produce this bindings is rather important: they must be+ defined after the rest of the module has been typechecked since we need to be+ able to lookup Module and TyCon in the type environment and we may be+ currently compiling GHC.Types (where they are defined).++* GHC.Prim doesn't have any associated object code, so we need to put the+ representations for types defined in this module elsewhere. We chose this+ place to be GHC.Types. TcTypeable.mkPrimTypeableBinds is responsible for+ injecting the bindings for the GHC.Prim representions when compiling+ GHC.Types.++* TyCon.tyConRepModOcc is responsible for determining where to find+ the representation binding for a given type. This is where we handle+ the special case for GHC.Prim.++* To save space and reduce dependencies, we need use quite low-level+ representations for TyCon and Module. See GHC.Types+ Note [Runtime representation of modules and tycons]++* The KindReps can unfortunately get quite large. Moreover, the simplifier will+ float out various pieces of them, resulting in numerous top-level bindings.+ Consequently we mark the KindRep bindings as noinline, ensuring that the+ float-outs don't make it into the interface file. This is important since+ there is generally little benefit to inlining KindReps and they would+ otherwise strongly affect compiler performance.++* In general there are lots of things of kind *, * -> *, and * -> * -> *. To+ reduce the number of bindings we need to produce, we generate their KindReps+ once in GHC.Types. These are referred to as "built-in" KindReps below.++* Even though KindReps aren't inlined, this scheme still has more of an effect on+ compilation time than I'd like. This is especially true in the case of+ families of type constructors (e.g. tuples and unboxed sums). The problem is+ particularly bad in the case of sums, since each arity-N tycon brings with it+ N promoted datacons, each with a KindRep whose size also scales with N.+ Consequently we currently simply don't allow sums to be Typeable.++ In general we might consider moving some or all of this generation logic back+ to the solver since the performance hit we take in doing this at+ type-definition time is non-trivial and Typeable isn't very widely used. This+ is discussed in #13261.++-}++-- | Generate the Typeable bindings for a module. This is the only+-- entry-point of this module and is invoked by the typechecker driver in+-- 'tcRnSrcDecls'.+--+-- See Note [Grand plan for Typeable] in TcTypeable.+mkTypeableBinds :: TcM TcGblEnv+mkTypeableBinds+ = do { -- Create a binding for $trModule.+ -- Do this before processing any data type declarations,+ -- which need tcg_tr_module to be initialised+ ; tcg_env <- mkModIdBindings+ -- Now we can generate the TyCon representations...+ -- First we handle the primitive TyCons if we are compiling GHC.Types+ ; (tcg_env, prim_todos) <- setGblEnv tcg_env mkPrimTypeableTodos++ -- Then we produce bindings for the user-defined types in this module.+ ; setGblEnv tcg_env $+ do { mod <- getModule+ ; let tycons = filter needs_typeable_binds (tcg_tcs tcg_env)+ mod_id = case tcg_tr_module tcg_env of -- Should be set by now+ Just mod_id -> mod_id+ Nothing -> pprPanic "tcMkTypeableBinds" (ppr tycons)+ ; traceTc "mkTypeableBinds" (ppr tycons)+ ; this_mod_todos <- todoForTyCons mod mod_id tycons+ ; mkTypeRepTodoBinds (this_mod_todos : prim_todos)+ } }+ where+ needs_typeable_binds tc+ | tc `elem` [runtimeRepTyCon, vecCountTyCon, vecElemTyCon]+ = False+ | otherwise =+ isAlgTyCon tc+ || isDataFamilyTyCon tc+ || isClassTyCon tc+++{- *********************************************************************+* *+ Building top-level binding for $trModule+* *+********************************************************************* -}++mkModIdBindings :: TcM TcGblEnv+mkModIdBindings+ = do { mod <- getModule+ ; loc <- getSrcSpanM+ ; mod_nm <- newGlobalBinder mod (mkVarOcc "$trModule") loc+ ; trModuleTyCon <- tcLookupTyCon trModuleTyConName+ ; let mod_id = mkExportedVanillaId mod_nm (mkTyConApp trModuleTyCon [])+ ; mod_bind <- mkVarBind mod_id <$> mkModIdRHS mod++ ; tcg_env <- tcExtendGlobalValEnv [mod_id] getGblEnv+ ; return (tcg_env { tcg_tr_module = Just mod_id }+ `addTypecheckedBinds` [unitBag mod_bind]) }++mkModIdRHS :: Module -> TcM (LHsExpr Id)+mkModIdRHS mod+ = do { trModuleDataCon <- tcLookupDataCon trModuleDataConName+ ; trNameLit <- mkTrNameLit+ ; return $ nlHsDataCon trModuleDataCon+ `nlHsApp` trNameLit (unitIdFS (moduleUnitId mod))+ `nlHsApp` trNameLit (moduleNameFS (moduleName mod))+ }++{- *********************************************************************+* *+ Building type-representation bindings+* *+********************************************************************* -}++-- | Information we need about a 'TyCon' to generate its representation. We+-- carry the 'Id' in order to share it between the generation of the @TyCon@ and+-- @KindRep@ bindings.+data TypeableTyCon+ = TypeableTyCon+ { tycon :: !TyCon+ , tycon_rep_id :: !Id+ }++-- | A group of 'TyCon's in need of type-rep bindings.+data TypeRepTodo+ = TypeRepTodo+ { mod_rep_expr :: LHsExpr Id -- ^ Module's typerep binding+ , pkg_fingerprint :: !Fingerprint -- ^ Package name fingerprint+ , mod_fingerprint :: !Fingerprint -- ^ Module name fingerprint+ , todo_tycons :: [TypeableTyCon]+ -- ^ The 'TyCon's in need of bindings kinds+ }+ | ExportedKindRepsTodo [(Kind, Id)]+ -- ^ Build exported 'KindRep' bindings for the given set of kinds.++todoForTyCons :: Module -> Id -> [TyCon] -> TcM TypeRepTodo+todoForTyCons mod mod_id tycons = do+ trTyConTy <- mkTyConTy <$> tcLookupTyCon trTyConTyConName+ let mk_rep_id :: TyConRepName -> Id+ mk_rep_id rep_name = mkExportedVanillaId rep_name trTyConTy++ let typeable_tycons :: [TypeableTyCon]+ typeable_tycons =+ [ TypeableTyCon { tycon = tc''+ , tycon_rep_id = mk_rep_id rep_name+ }+ | tc <- tycons+ , tc' <- tc : tyConATs tc+ -- We need type representations for any associated types+ , let promoted = map promoteDataCon (tyConDataCons tc')+ , tc'' <- tc' : promoted+ -- Don't make bindings for data-family instance tycons.+ -- Do, however, make them for their promoted datacon (see #13915).+ , not $ isFamInstTyCon tc''+ , Just rep_name <- pure $ tyConRepName_maybe tc''+ , typeIsTypeable $ dropForAlls $ tyConKind tc''+ ]+ return TypeRepTodo { mod_rep_expr = nlHsVar mod_id+ , pkg_fingerprint = pkg_fpr+ , mod_fingerprint = mod_fpr+ , todo_tycons = typeable_tycons+ }+ where+ mod_fpr = fingerprintString $ moduleNameString $ moduleName mod+ pkg_fpr = fingerprintString $ unitIdString $ moduleUnitId mod++todoForExportedKindReps :: [(Kind, Name)] -> TcM TypeRepTodo+todoForExportedKindReps kinds = do+ trKindRepTy <- mkTyConTy <$> tcLookupTyCon kindRepTyConName+ let mkId (k, name) = (k, mkExportedVanillaId name trKindRepTy)+ return $ ExportedKindRepsTodo $ map mkId kinds++-- | Generate TyCon bindings for a set of type constructors+mkTypeRepTodoBinds :: [TypeRepTodo] -> TcM TcGblEnv+mkTypeRepTodoBinds [] = getGblEnv+mkTypeRepTodoBinds todos+ = do { stuff <- collect_stuff++ -- First extend the type environment with all of the bindings+ -- which we are going to produce since we may need to refer to them+ -- while generating kind representations (namely, when we want to+ -- represent a TyConApp in a kind, we must be able to look up the+ -- TyCon associated with the applied type constructor).+ ; let produced_bndrs :: [Id]+ produced_bndrs = [ tycon_rep_id+ | todo@(TypeRepTodo{}) <- todos+ , TypeableTyCon {..} <- todo_tycons todo+ ] +++ [ rep_id+ | ExportedKindRepsTodo kinds <- todos+ , (_, rep_id) <- kinds+ ]+ ; gbl_env <- tcExtendGlobalValEnv produced_bndrs getGblEnv++ ; let mk_binds :: TypeRepTodo -> KindRepM [LHsBinds Id]+ mk_binds todo@(TypeRepTodo {}) =+ mapM (mkTyConRepBinds stuff todo) (todo_tycons todo)+ mk_binds (ExportedKindRepsTodo kinds) =+ mkExportedKindReps stuff kinds >> return []++ ; (gbl_env, binds) <- setGblEnv gbl_env+ $ runKindRepM (mapM mk_binds todos)+ ; return $ gbl_env `addTypecheckedBinds` concat binds }++-- | Generate bindings for the type representation of a wired-in 'TyCon's+-- defined by the virtual "GHC.Prim" module. This is where we inject the+-- representation bindings for these primitive types into "GHC.Types"+--+-- See Note [Grand plan for Typeable] in this module.+mkPrimTypeableTodos :: TcM (TcGblEnv, [TypeRepTodo])+mkPrimTypeableTodos+ = do { mod <- getModule+ ; if mod == gHC_TYPES+ then do { -- Build Module binding for GHC.Prim+ trModuleTyCon <- tcLookupTyCon trModuleTyConName+ ; let ghc_prim_module_id =+ mkExportedVanillaId trGhcPrimModuleName+ (mkTyConTy trModuleTyCon)++ ; ghc_prim_module_bind <- mkVarBind ghc_prim_module_id+ <$> mkModIdRHS gHC_PRIM++ -- Extend our environment with above+ ; gbl_env <- tcExtendGlobalValEnv [ghc_prim_module_id]+ getGblEnv+ ; let gbl_env' = gbl_env `addTypecheckedBinds`+ [unitBag ghc_prim_module_bind]++ -- Build TypeRepTodos for built-in KindReps+ ; todo1 <- todoForExportedKindReps builtInKindReps+ -- Build TypeRepTodos for types in GHC.Prim+ ; todo2 <- todoForTyCons gHC_PRIM ghc_prim_module_id+ ghcPrimTypeableTyCons+ ; return ( gbl_env' , [todo1, todo2])+ }+ else do gbl_env <- getGblEnv+ return (gbl_env, [])+ }++-- | This is the list of primitive 'TyCon's for which we must generate bindings+-- in "GHC.Types". This should include all types defined in "GHC.Prim".+--+-- The majority of the types we need here are contained in 'primTyCons'.+-- However, not all of them: in particular unboxed tuples are absent since we+-- don't want to include them in the original name cache. See+-- Note [Built-in syntax and the OrigNameCache] in IfaceEnv for more.+ghcPrimTypeableTyCons :: [TyCon]+ghcPrimTypeableTyCons = concat+ [ [ runtimeRepTyCon, vecCountTyCon, vecElemTyCon+ , funTyCon, tupleTyCon Unboxed 0 ]+ , map (tupleTyCon Unboxed) [2..mAX_TUPLE_SIZE]+ , map sumTyCon [2..mAX_SUM_SIZE]+ , primTyCons+ ]++data TypeableStuff+ = Stuff { dflags :: DynFlags+ , trTyConDataCon :: DataCon -- ^ of @TyCon@+ , trNameLit :: FastString -> LHsExpr Id+ -- ^ To construct @TrName@s+ -- The various TyCon and DataCons of KindRep+ , kindRepTyCon :: TyCon+ , kindRepTyConAppDataCon :: DataCon+ , kindRepVarDataCon :: DataCon+ , kindRepAppDataCon :: DataCon+ , kindRepFunDataCon :: DataCon+ , kindRepTYPEDataCon :: DataCon+ , kindRepTypeLitSDataCon :: DataCon+ , typeLitSymbolDataCon :: DataCon+ , typeLitNatDataCon :: DataCon+ }++-- | Collect various tidbits which we'll need to generate TyCon representations.+collect_stuff :: TcM TypeableStuff+collect_stuff = do+ dflags <- getDynFlags+ trTyConDataCon <- tcLookupDataCon trTyConDataConName+ kindRepTyCon <- tcLookupTyCon kindRepTyConName+ kindRepTyConAppDataCon <- tcLookupDataCon kindRepTyConAppDataConName+ kindRepVarDataCon <- tcLookupDataCon kindRepVarDataConName+ kindRepAppDataCon <- tcLookupDataCon kindRepAppDataConName+ kindRepFunDataCon <- tcLookupDataCon kindRepFunDataConName+ kindRepTYPEDataCon <- tcLookupDataCon kindRepTYPEDataConName+ kindRepTypeLitSDataCon <- tcLookupDataCon kindRepTypeLitSDataConName+ typeLitSymbolDataCon <- tcLookupDataCon typeLitSymbolDataConName+ typeLitNatDataCon <- tcLookupDataCon typeLitNatDataConName+ trNameLit <- mkTrNameLit+ return Stuff {..}++-- | Lookup the necessary pieces to construct the @trNameLit@. We do this so we+-- can save the work of repeating lookups when constructing many TyCon+-- representations.+mkTrNameLit :: TcM (FastString -> LHsExpr Id)+mkTrNameLit = do+ trNameSDataCon <- tcLookupDataCon trNameSDataConName+ let trNameLit :: FastString -> LHsExpr Id+ trNameLit fs = nlHsPar $ nlHsDataCon trNameSDataCon+ `nlHsApp` nlHsLit (mkHsStringPrimLit fs)+ return trNameLit++-- | Make Typeable bindings for the given 'TyCon'.+mkTyConRepBinds :: TypeableStuff -> TypeRepTodo+ -> TypeableTyCon -> KindRepM (LHsBinds Id)+mkTyConRepBinds stuff@(Stuff {..}) todo (TypeableTyCon {..})+ = do -- Make a KindRep+ let (bndrs, kind) = splitForAllTyVarBndrs (tyConKind tycon)+ liftTc $ traceTc "mkTyConKindRepBinds"+ (ppr tycon $$ ppr (tyConKind tycon) $$ ppr kind)+ let ctx = mkDeBruijnContext (map binderVar bndrs)+ kind_rep <- getKindRep stuff ctx kind++ -- Make the TyCon binding+ let tycon_rep_rhs = mkTyConRepTyConRHS stuff todo tycon kind_rep+ tycon_rep_bind = mkVarBind tycon_rep_id tycon_rep_rhs+ return $ unitBag tycon_rep_bind++-- | Here is where we define the set of Typeable types. These exclude type+-- families and polytypes.+tyConIsTypeable :: TyCon -> Bool+tyConIsTypeable tc =+ isJust (tyConRepName_maybe tc)+ && typeIsTypeable (dropForAlls $ tyConKind tc)+ -- Ensure that the kind of the TyCon, with its initial foralls removed,+ -- is representable (e.g. has no higher-rank polymorphism or type+ -- synonyms).++-- | Is a particular 'Type' representable by @Typeable@? Here we look for+-- polytypes and types containing casts (which may be, for instance, a type+-- family).+typeIsTypeable :: Type -> Bool+-- We handle types of the form (TYPE rep) specifically to avoid+-- looping on (tyConIsTypeable RuntimeRep)+typeIsTypeable ty+ | Just ty' <- coreView ty = typeIsTypeable ty'+typeIsTypeable ty+ | Just _ <- isTYPEApp ty = True+typeIsTypeable (TyVarTy _) = True+typeIsTypeable (AppTy a b) = typeIsTypeable a && typeIsTypeable b+typeIsTypeable (FunTy a b) = typeIsTypeable a && typeIsTypeable b+typeIsTypeable (TyConApp tc args) = tyConIsTypeable tc+ && all typeIsTypeable args+typeIsTypeable (ForAllTy{}) = False+typeIsTypeable (LitTy _) = True+typeIsTypeable (CastTy{}) = False+typeIsTypeable (CoercionTy{}) = False++-- | Maps kinds to 'KindRep' bindings. This binding may either be defined in+-- some other module (in which case the @Maybe (LHsExpr Id@ will be 'Nothing')+-- or a binding which we generated in the current module (in which case it will+-- be 'Just' the RHS of the binding).+type KindRepEnv = TypeMap (Id, Maybe (LHsExpr Id))++-- | A monad within which we will generate 'KindRep's. Here we keep an+-- environment containing 'KindRep's which we've already generated so we can+-- re-use them opportunistically.+newtype KindRepM a = KindRepM { unKindRepM :: StateT KindRepEnv TcRn a }+ deriving (Functor, Applicative, Monad)++liftTc :: TcRn a -> KindRepM a+liftTc = KindRepM . lift++-- | We generate @KindRep@s for a few common kinds in @GHC.Types@ so that they+-- can be reused across modules.+builtInKindReps :: [(Kind, Name)]+builtInKindReps =+ [ (star, starKindRepName)+ , (mkFunTy star star, starArrStarKindRepName)+ , (mkFunTys [star, star] star, starArrStarArrStarKindRepName)+ ]+ where+ star = liftedTypeKind++initialKindRepEnv :: TcRn KindRepEnv+initialKindRepEnv = foldlM add_kind_rep emptyTypeMap builtInKindReps+ where+ add_kind_rep acc (k,n) = do+ id <- tcLookupId n+ return $! extendTypeMap acc k (id, Nothing)++-- | Performed while compiling "GHC.Types" to generate the built-in 'KindRep's.+mkExportedKindReps :: TypeableStuff+ -> [(Kind, Id)] -- ^ the kinds to generate bindings for+ -> KindRepM ()+mkExportedKindReps stuff@(Stuff {..}) = mapM_ kindrep_binding+ where+ empty_scope = mkDeBruijnContext []++ kindrep_binding :: (Kind, Id) -> KindRepM ()+ kindrep_binding (kind, rep_bndr) = do+ -- We build the binding manually here instead of using mkKindRepRhs+ -- since the latter would find the built-in 'KindRep's in the+ -- 'KindRepEnv' (by virtue of being in 'initialKindRepEnv').+ rhs <- mkKindRepRhs stuff empty_scope kind+ addKindRepBind empty_scope kind rep_bndr rhs++addKindRepBind :: CmEnv -> Kind -> Id -> LHsExpr Id -> KindRepM ()+addKindRepBind in_scope k bndr rhs =+ KindRepM $ modify' $+ \env -> extendTypeMapWithScope env in_scope k (bndr, Just rhs)++-- | Run a 'KindRepM' and add the produced 'KindRep's to the typechecking+-- environment.+runKindRepM :: KindRepM a -> TcRn (TcGblEnv, a)+runKindRepM (KindRepM action) = do+ kindRepEnv <- initialKindRepEnv+ (res, reps_env) <- runStateT action kindRepEnv+ let rep_binds = foldTypeMap to_bind_pair [] reps_env+ to_bind_pair (bndr, Just rhs) rest = (bndr, rhs) : rest+ to_bind_pair (_, Nothing) rest = rest+ tcg_env <- tcExtendGlobalValEnv (map fst rep_binds) getGblEnv+ let binds = map (uncurry mkVarBind) rep_binds+ tcg_env' = tcg_env `addTypecheckedBinds` [listToBag binds]+ return (tcg_env', res)++-- | Produce or find a 'KindRep' for the given kind.+getKindRep :: TypeableStuff -> CmEnv -- ^ in-scope kind variables+ -> Kind -- ^ the kind we want a 'KindRep' for+ -> KindRepM (LHsExpr Id)+getKindRep stuff@(Stuff {..}) in_scope = go+ where+ go :: Kind -> KindRepM (LHsExpr Id)+ go = KindRepM . StateT . go'++ go' :: Kind -> KindRepEnv -> TcRn (LHsExpr Id, KindRepEnv)+ go' k env+ -- Look through type synonyms+ | Just k' <- tcView k = go' k' env++ -- We've already generated the needed KindRep+ | Just (id, _) <- lookupTypeMapWithScope env in_scope k+ = return (nlHsVar id, env)++ -- We need to construct a new KindRep binding+ | otherwise+ = do -- Place a NOINLINE pragma on KindReps since they tend to be quite+ -- large and bloat interface files.+ rep_bndr <- (`setInlinePragma` neverInlinePragma)+ <$> newSysLocalId (fsLit "$krep") (mkTyConTy kindRepTyCon)++ -- do we need to tie a knot here?+ flip runStateT env $ unKindRepM $ do+ rhs <- mkKindRepRhs stuff in_scope k+ addKindRepBind in_scope k rep_bndr rhs+ return $ nlHsVar rep_bndr++-- | Construct the right-hand-side of the 'KindRep' for the given 'Kind' and+-- in-scope kind variable set.+mkKindRepRhs :: TypeableStuff+ -> CmEnv -- ^ in-scope kind variables+ -> Kind -- ^ the kind we want a 'KindRep' for+ -> KindRepM (LHsExpr Id) -- ^ RHS expression+mkKindRepRhs stuff@(Stuff {..}) in_scope = new_kind_rep+ where+ new_kind_rep k+ -- We handle TYPE separately to make it clear to consumers+ -- (e.g. serializers) that there is a loop here (as+ -- TYPE :: RuntimeRep -> TYPE 'LiftedRep)+ | Just rr <- isTYPEApp k+ = return $ nlHsDataCon kindRepTYPEDataCon `nlHsApp` nlHsDataCon rr++ new_kind_rep (TyVarTy v)+ | Just idx <- lookupCME in_scope v+ = return $ nlHsDataCon kindRepVarDataCon+ `nlHsApp` nlHsIntLit (fromIntegral idx)+ | otherwise+ = pprPanic "mkTyConKindRepBinds.go(tyvar)" (ppr v)++ new_kind_rep (AppTy t1 t2)+ = do rep1 <- getKindRep stuff in_scope t1+ rep2 <- getKindRep stuff in_scope t2+ return $ nlHsDataCon kindRepAppDataCon+ `nlHsApp` rep1 `nlHsApp` rep2++ new_kind_rep k@(TyConApp tc tys)+ | Just rep_name <- tyConRepName_maybe tc+ = do rep_id <- liftTc $ lookupId rep_name+ tys' <- mapM (getKindRep stuff in_scope) tys+ return $ nlHsDataCon kindRepTyConAppDataCon+ `nlHsApp` nlHsVar rep_id+ `nlHsApp` mkList (mkTyConTy kindRepTyCon) tys'+ | otherwise+ = pprPanic "mkTyConKindRepBinds(TyConApp)" (ppr tc $$ ppr k)++ new_kind_rep (ForAllTy (TvBndr var _) ty)+ = pprPanic "mkTyConKindRepBinds(ForAllTy)" (ppr var $$ ppr ty)++ new_kind_rep (FunTy t1 t2)+ = do rep1 <- getKindRep stuff in_scope t1+ rep2 <- getKindRep stuff in_scope t2+ return $ nlHsDataCon kindRepFunDataCon+ `nlHsApp` rep1 `nlHsApp` rep2++ new_kind_rep (LitTy (NumTyLit n))+ = return $ nlHsDataCon kindRepTypeLitSDataCon+ `nlHsApp` nlHsDataCon typeLitNatDataCon+ `nlHsApp` nlHsLit (mkHsStringPrimLit $ mkFastString $ show n)++ new_kind_rep (LitTy (StrTyLit s))+ = return $ nlHsDataCon kindRepTypeLitSDataCon+ `nlHsApp` nlHsDataCon typeLitSymbolDataCon+ `nlHsApp` nlHsLit (mkHsStringPrimLit $ mkFastString $ show s)++ new_kind_rep (CastTy ty co)+ = pprPanic "mkTyConKindRepBinds.go(cast)" (ppr ty $$ ppr co)++ new_kind_rep (CoercionTy co)+ = pprPanic "mkTyConKindRepBinds.go(coercion)" (ppr co)++-- | Produce the right-hand-side of a @TyCon@ representation.+mkTyConRepTyConRHS :: TypeableStuff -> TypeRepTodo+ -> TyCon -- ^ the 'TyCon' we are producing a binding for+ -> LHsExpr Id -- ^ its 'KindRep'+ -> LHsExpr Id+mkTyConRepTyConRHS (Stuff {..}) todo tycon kind_rep+ = nlHsDataCon trTyConDataCon+ `nlHsApp` nlHsLit (word64 dflags high)+ `nlHsApp` nlHsLit (word64 dflags low)+ `nlHsApp` mod_rep_expr todo+ `nlHsApp` trNameLit (mkFastString tycon_str)+ `nlHsApp` nlHsLit (int n_kind_vars)+ `nlHsApp` kind_rep+ where+ n_kind_vars = length $ filter isNamedTyConBinder (tyConBinders tycon)+ tycon_str = add_tick (occNameString (getOccName tycon))+ add_tick s | isPromotedDataCon tycon = '\'' : s+ | otherwise = s++ -- This must match the computation done in+ -- Data.Typeable.Internal.mkTyConFingerprint.+ Fingerprint high low = fingerprintFingerprints [ pkg_fingerprint todo+ , mod_fingerprint todo+ , fingerprintString tycon_str+ ]++ int :: Int -> HsLit+ int n = HsIntPrim (SourceText $ show n) (toInteger n)++word64 :: DynFlags -> Word64 -> HsLit+word64 dflags n+ | wORD_SIZE dflags == 4 = HsWord64Prim NoSourceText (toInteger n)+ | otherwise = HsWordPrim NoSourceText (toInteger n)++{-+Note [Representing TyCon kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++One of the operations supported by Typeable is typeRepKind,++ typeRepKind :: TypeRep (a :: k) -> TypeRep k++Implementing this is a bit tricky. To see why let's consider the TypeRep+encoding of `Proxy Int` where++ data Proxy (a :: k) :: Type++which looks like,++ $tcProxy :: TyCon+ $trInt :: TypeRep Int+ $trType :: TypeRep Type++ $trProxyType :: TypeRep (Proxy :: Type -> Type)+ $trProxyType = TrTyCon $tcProxy+ [$trType] -- kind variable instantiation++ $trProxy :: TypeRep (Proxy Int)+ $trProxy = TrApp $trProxyType $trInt++Note how $trProxyType encodes only the kind variables of the TyCon+instantiation. To compute the kind (Proxy Int) we need to have a recipe to+compute the kind of a concrete instantiation of Proxy. We call this recipe a+KindRep and store it in the TyCon produced for Proxy,++ type KindBndr = Int -- de Bruijn index++ data KindRep = KindRepTyConApp TyCon [KindRep]+ | KindRepVar !KindBndr+ | KindRepApp KindRep KindRep+ | KindRepFun KindRep KindRep++The KindRep for Proxy would look like,++ $tkProxy :: KindRep+ $tkProxy = KindRepFun (KindRepVar 0) (KindRepTyConApp $trType [])+++data Maybe a = Nothing | Just a++'Just :: a -> Maybe a++F :: forall k. k -> forall k'. k' -> Type+-}++mkList :: Type -> [LHsExpr Id] -> LHsExpr Id+mkList ty = foldr consApp (nilExpr ty)+ where+ cons = consExpr ty+ consApp :: LHsExpr Id -> LHsExpr Id -> LHsExpr Id+ consApp x xs = cons `nlHsApp` x `nlHsApp` xs++ nilExpr :: Type -> LHsExpr Id+ nilExpr ty = mkLHsWrap (mkWpTyApps [ty]) (nlHsDataCon nilDataCon)++ consExpr :: Type -> LHsExpr Id+ consExpr ty = mkLHsWrap (mkWpTyApps [ty]) (nlHsDataCon consDataCon)
+ typecheck/TcUnify.hs view
@@ -0,0 +1,2116 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Type subsumption and unification+-}++{-# LANGUAGE CPP, MultiWayIf, TupleSections, ScopedTypeVariables #-}++module TcUnify (+ -- Full-blown subsumption+ tcWrapResult, tcWrapResultO, tcSkolemise, tcSkolemiseET,+ tcSubTypeHR, tcSubTypeO, tcSubType_NC, tcSubTypeDS,+ tcSubTypeDS_NC_O, tcSubTypeET,+ checkConstraints, buildImplicationFor,++ -- Various unifications+ unifyType, unifyTheta, unifyKind, noThing,+ uType, promoteTcType,+ swapOverTyVars, canSolveByUnification,++ --------------------------------+ -- Holes+ tcInferInst, tcInferNoInst,+ matchExpectedListTy,+ matchExpectedPArrTy,+ matchExpectedTyConApp,+ matchExpectedAppTy,+ matchExpectedFunTys,+ matchActualFunTys, matchActualFunTysPart,+ matchExpectedFunKind,++ wrapFunResCoercion,++ occCheckExpand, metaTyVarUpdateOK,+ occCheckForErrors, OccCheckResult(..)++ ) where++#include "HsVersions.h"++import HsSyn+import TyCoRep+import TcMType+import TcRnMonad+import TcType+import Type+import Coercion+import TcEvidence+import Name ( isSystemName )+import Inst+import TyCon+import TysWiredIn+import TysPrim( tYPE )+import Var+import VarSet+import VarEnv+import ErrUtils+import DynFlags+import BasicTypes+import Name ( Name )+import Bag+import Util+import Pair( pFst )+import qualified GHC.LanguageExtensions as LangExt+import Outputable+import FastString++import Control.Monad+import Control.Arrow ( second )++{-+************************************************************************+* *+ matchExpected functions+* *+************************************************************************++Note [Herald for matchExpectedFunTys]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The 'herald' always looks like:+ "The equation(s) for 'f' have"+ "The abstraction (\x.e) takes"+ "The section (+ x) expects"+ "The function 'f' is applied to"++This is used to construct a message of form++ The abstraction `\Just 1 -> ...' takes two arguments+ but its type `Maybe a -> a' has only one++ The equation(s) for `f' have two arguments+ but its type `Maybe a -> a' has only one++ The section `(f 3)' requires 'f' to take two arguments+ but its type `Int -> Int' has only one++ The function 'f' is applied to two arguments+ but its type `Int -> Int' has only one++Note [matchExpectedFunTys]+~~~~~~~~~~~~~~~~~~~~~~~~~~+matchExpectedFunTys checks that a sigma has the form+of an n-ary function. It passes the decomposed type to the+thing_inside, and returns a wrapper to coerce between the two types++It's used wherever a language construct must have a functional type,+namely:+ A lambda expression+ A function definition+ An operator section++This function must be written CPS'd because it needs to fill in the+ExpTypes produced for arguments before it can fill in the ExpType+passed in.++-}++-- Use this one when you have an "expected" type.+matchExpectedFunTys :: forall a.+ SDoc -- See Note [Herald for matchExpectedFunTys]+ -> Arity+ -> ExpRhoType -- deeply skolemised+ -> ([ExpSigmaType] -> ExpRhoType -> TcM a)+ -- must fill in these ExpTypes here+ -> TcM (a, HsWrapper)+-- If matchExpectedFunTys n ty = (_, wrap)+-- then wrap : (t1 -> ... -> tn -> ty_r) ~> ty,+-- where [t1, ..., tn], ty_r are passed to the thing_inside+matchExpectedFunTys herald arity orig_ty thing_inside+ = case orig_ty of+ Check ty -> go [] arity ty+ _ -> defer [] arity orig_ty+ where+ go acc_arg_tys 0 ty+ = do { result <- thing_inside (reverse acc_arg_tys) (mkCheckExpType ty)+ ; return (result, idHsWrapper) }++ go acc_arg_tys n ty+ | Just ty' <- tcView ty = go acc_arg_tys n ty'++ go acc_arg_tys n (FunTy arg_ty res_ty)+ = ASSERT( not (isPredTy arg_ty) )+ do { (result, wrap_res) <- go (mkCheckExpType arg_ty : acc_arg_tys)+ (n-1) res_ty+ ; return ( result+ , mkWpFun idHsWrapper wrap_res arg_ty res_ty doc ) }+ 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+ = do { cts <- readMetaTyVar tv+ ; case cts of+ Indirect ty' -> go acc_arg_tys n ty'+ Flexi -> defer acc_arg_tys n (mkCheckExpType ty) }++ -- In all other cases we bale out into ordinary unification+ -- However unlike the meta-tyvar case, we are sure that the+ -- number of arguments doesn't match arity of the original+ -- type, so we can add a bit more context to the error message+ -- (cf Trac #7869).+ --+ -- It is not always an error, because specialized type may have+ -- different arity, for example:+ --+ -- > f1 = f2 'a'+ -- > f2 :: Monad m => m Bool+ -- > f2 = undefined+ --+ -- But in that case we add specialized type into error context+ -- anyway, because it may be useful. See also Trac #9605.+ go acc_arg_tys n ty = addErrCtxtM mk_ctxt $+ defer acc_arg_tys n (mkCheckExpType ty)++ ------------+ defer :: [ExpSigmaType] -> Arity -> ExpRhoType -> TcM (a, HsWrapper)+ defer acc_arg_tys n fun_ty+ = do { more_arg_tys <- replicateM n newInferExpTypeNoInst+ ; res_ty <- newInferExpTypeInst+ ; result <- thing_inside (reverse acc_arg_tys ++ more_arg_tys) res_ty+ ; more_arg_tys <- mapM readExpType more_arg_tys+ ; res_ty <- readExpType res_ty+ ; let unif_fun_ty = mkFunTys more_arg_tys res_ty+ ; wrap <- tcSubTypeDS AppOrigin GenSigCtxt unif_fun_ty fun_ty+ -- Not a good origin at all :-(+ ; return (result, wrap) }++ ------------+ mk_ctxt :: TidyEnv -> TcM (TidyEnv, MsgDoc)+ mk_ctxt env = do { (env', ty) <- zonkTidyTcType env orig_tc_ty+ ; let (args, _) = tcSplitFunTys ty+ n_actual = length args+ (env'', orig_ty') = tidyOpenType env' orig_tc_ty+ ; return ( env''+ , mk_fun_tys_msg orig_ty' ty n_actual arity herald) }+ where+ orig_tc_ty = checkingExpType "matchExpectedFunTys" orig_ty+ -- this is safe b/c we're called from "go"++-- Like 'matchExpectedFunTys', but used when you have an "actual" type,+-- for example in function application+matchActualFunTys :: Outputable a+ => SDoc -- See Note [Herald for matchExpectedFunTys]+ -> CtOrigin+ -> Maybe a -- the thing with type TcSigmaType+ -> Arity+ -> TcSigmaType+ -> TcM (HsWrapper, [TcSigmaType], TcSigmaType)+-- If matchActualFunTys n ty = (wrap, [t1,..,tn], ty_r)+-- then wrap : ty ~> (t1 -> ... -> tn -> ty_r)+matchActualFunTys herald ct_orig mb_thing arity ty+ = matchActualFunTysPart herald ct_orig mb_thing arity ty [] arity++-- | Variant of 'matchActualFunTys' that works when supplied only part+-- (that is, to the right of some arrows) of the full function type+matchActualFunTysPart :: Outputable a+ => SDoc -- See Note [Herald for matchExpectedFunTys]+ -> CtOrigin+ -> Maybe a -- the thing with type TcSigmaType+ -> Arity+ -> TcSigmaType+ -> [TcSigmaType] -- reversed args. See (*) below.+ -> Arity -- overall arity of the function, for errs+ -> TcM (HsWrapper, [TcSigmaType], TcSigmaType)+matchActualFunTysPart herald ct_orig mb_thing arity orig_ty+ orig_old_args full_arity+ = go arity orig_old_args orig_ty+-- Does not allocate unnecessary meta variables: if the input already is+-- a function, we just take it apart. Not only is this efficient,+-- it's important for higher rank: the argument might be of form+-- (forall a. ty) -> other+-- If allocated (fresh-meta-var1 -> fresh-meta-var2) and unified, we'd+-- hide the forall inside a meta-variable++-- (*) Sometimes it's necessary to call matchActualFunTys with only part+-- (that is, to the right of some arrows) of the type of the function in+-- question. (See TcExpr.tcArgs.) This argument is the reversed list of+-- arguments already seen (that is, not part of the TcSigmaType passed+-- in elsewhere).++ where+ -- This function has a bizarre mechanic: it accumulates arguments on+ -- the way down and also builds an argument list on the way up. Why:+ -- 1. The returns args list and the accumulated args list might be different.+ -- The accumulated args include all the arg types for the function,+ -- including those from before this function was called. The returned+ -- list should include only those arguments produced by this call of+ -- matchActualFunTys+ --+ -- 2. The HsWrapper can be built only on the way up. It seems (more)+ -- bizarre to build the HsWrapper but not the arg_tys.+ --+ -- Refactoring is welcome.+ go :: Arity+ -> [TcSigmaType] -- accumulator of arguments (reversed)+ -> TcSigmaType -- the remainder of the type as we're processing+ -> TcM (HsWrapper, [TcSigmaType], TcSigmaType)+ go 0 _ ty = return (idHsWrapper, [], ty)++ go n acc_args ty+ | not (null tvs && null theta)+ = do { (wrap1, rho) <- topInstantiate ct_orig ty+ ; (wrap2, arg_tys, res_ty) <- go n acc_args rho+ ; return (wrap2 <.> wrap1, arg_tys, res_ty) }+ where+ (tvs, theta, _) = tcSplitSigmaTy ty++ go n acc_args ty+ | Just ty' <- tcView ty = go n acc_args ty'++ go n acc_args (FunTy arg_ty res_ty)+ = ASSERT( not (isPredTy arg_ty) )+ do { (wrap_res, tys, ty_r) <- go (n-1) (arg_ty : acc_args) res_ty+ ; return ( mkWpFun idHsWrapper wrap_res arg_ty ty_r doc+ , arg_ty : tys, ty_r ) }+ where+ doc = text "When inferring the argument type of a function with type" <+>+ quotes (ppr orig_ty)++ go n acc_args ty@(TyVarTy tv)+ | isMetaTyVar tv+ = do { cts <- readMetaTyVar tv+ ; case cts of+ Indirect ty' -> go n acc_args ty'+ Flexi -> defer n ty }++ -- In all other cases we bale out into ordinary unification+ -- However unlike the meta-tyvar case, we are sure that the+ -- number of arguments doesn't match arity of the original+ -- type, so we can add a bit more context to the error message+ -- (cf Trac #7869).+ --+ -- It is not always an error, because specialized type may have+ -- different arity, for example:+ --+ -- > f1 = f2 'a'+ -- > f2 :: Monad m => m Bool+ -- > f2 = undefined+ --+ -- But in that case we add specialized type into error context+ -- anyway, because it may be useful. See also Trac #9605.+ go n acc_args ty = addErrCtxtM (mk_ctxt (reverse acc_args) ty) $+ defer n ty++ ------------+ defer n fun_ty+ = do { arg_tys <- replicateM n newOpenFlexiTyVarTy+ ; res_ty <- newOpenFlexiTyVarTy+ ; let unif_fun_ty = mkFunTys arg_tys res_ty+ ; co <- unifyType mb_thing fun_ty unif_fun_ty+ ; return (mkWpCastN co, arg_tys, res_ty) }++ ------------+ mk_ctxt :: [TcSigmaType] -> TcSigmaType -> TidyEnv -> TcM (TidyEnv, MsgDoc)+ mk_ctxt arg_tys res_ty env+ = do { let ty = mkFunTys arg_tys res_ty+ ; (env1, zonked) <- zonkTidyTcType env ty+ -- zonking might change # of args+ ; let (zonked_args, _) = tcSplitFunTys zonked+ n_actual = length zonked_args+ (env2, unzonked) = tidyOpenType env1 ty+ ; return ( env2+ , mk_fun_tys_msg unzonked zonked n_actual full_arity herald) }++mk_fun_tys_msg :: TcType -- the full type passed in (unzonked)+ -> TcType -- the full type passed in (zonked)+ -> Arity -- the # of args found+ -> Arity -- the # of args wanted+ -> SDoc -- overall herald+ -> SDoc+mk_fun_tys_msg full_ty ty n_args full_arity herald+ = herald <+> speakNOf full_arity (text "argument") <> comma $$+ if n_args == full_arity+ then text "its type is" <+> quotes (pprType full_ty) <>+ comma $$+ text "it is specialized to" <+> quotes (pprType ty)+ else sep [text "but its type" <+> quotes (pprType ty),+ if n_args == 0 then text "has none"+ else text "has only" <+> speakN n_args]++----------------------+matchExpectedListTy :: TcRhoType -> TcM (TcCoercionN, TcRhoType)+-- Special case for lists+matchExpectedListTy exp_ty+ = do { (co, [elt_ty]) <- matchExpectedTyConApp listTyCon exp_ty+ ; return (co, elt_ty) }++----------------------+matchExpectedPArrTy :: TcRhoType -> TcM (TcCoercionN, TcRhoType)+-- Special case for parrs+matchExpectedPArrTy exp_ty+ = do { (co, [elt_ty]) <- matchExpectedTyConApp parrTyCon exp_ty+ ; return (co, elt_ty) }++---------------------+matchExpectedTyConApp :: TyCon -- T :: forall kv1 ... kvm. k1 -> ... -> kn -> *+ -> TcRhoType -- orig_ty+ -> TcM (TcCoercionN, -- T k1 k2 k3 a b c ~N orig_ty+ [TcSigmaType]) -- Element types, k1 k2 k3 a b c++-- It's used for wired-in tycons, so we call checkWiredInTyCon+-- Precondition: never called with FunTyCon+-- Precondition: input type :: *+-- Postcondition: (T k1 k2 k3 a b c) is well-kinded++matchExpectedTyConApp tc orig_ty+ = ASSERT(tc /= funTyCon) go orig_ty+ where+ go ty+ | Just ty' <- tcView ty+ = go ty'++ go ty@(TyConApp tycon args)+ | tc == tycon -- Common case+ = return (mkTcNomReflCo ty, args)++ go (TyVarTy tv)+ | isMetaTyVar tv+ = do { cts <- readMetaTyVar tv+ ; case cts of+ Indirect ty -> go ty+ Flexi -> defer }++ go _ = defer++ -- If the common case does not occur, instantiate a template+ -- T k1 .. kn t1 .. tm, and unify with the original type+ -- Doing it this way ensures that the types we return are+ -- kind-compatible with T. For example, suppose we have+ -- matchExpectedTyConApp T (f Maybe)+ -- where data T a = MkT a+ -- Then we don't want to instantate T's data constructors with+ -- (a::*) ~ Maybe+ -- because that'll make types that are utterly ill-kinded.+ -- This happened in Trac #7368+ defer+ = do { (_, arg_tvs) <- newMetaTyVars (tyConTyVars tc)+ ; traceTc "matchExpectedTyConApp" (ppr tc $$ ppr (tyConTyVars tc) $$ ppr arg_tvs)+ ; let args = mkTyVarTys arg_tvs+ tc_template = mkTyConApp tc args+ ; co <- unifyType noThing tc_template orig_ty+ ; return (co, args) }++----------------------+matchExpectedAppTy :: TcRhoType -- orig_ty+ -> TcM (TcCoercion, -- m a ~N orig_ty+ (TcSigmaType, TcSigmaType)) -- Returns m, a+-- If the incoming type is a mutable type variable of kind k, then+-- matchExpectedAppTy returns a new type variable (m: * -> k); note the *.++matchExpectedAppTy orig_ty+ = go orig_ty+ where+ go ty+ | Just ty' <- tcView ty = go ty'++ | Just (fun_ty, arg_ty) <- tcSplitAppTy_maybe ty+ = return (mkTcNomReflCo orig_ty, (fun_ty, arg_ty))++ go (TyVarTy tv)+ | isMetaTyVar tv+ = do { cts <- readMetaTyVar tv+ ; case cts of+ Indirect ty -> go ty+ Flexi -> defer }++ go _ = defer++ -- Defer splitting by generating an equality constraint+ defer+ = do { ty1 <- newFlexiTyVarTy kind1+ ; ty2 <- newFlexiTyVarTy kind2+ ; co <- unifyType noThing (mkAppTy ty1 ty2) orig_ty+ ; return (co, (ty1, ty2)) }++ orig_kind = typeKind orig_ty+ kind1 = mkFunTy liftedTypeKind orig_kind+ kind2 = liftedTypeKind -- m :: * -> k+ -- arg type :: *++{-+************************************************************************+* *+ Subsumption checking+* *+************************************************************************++Note [Subsumption checking: tcSubType]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+All the tcSubType calls have the form+ tcSubType actual_ty expected_ty+which checks+ actual_ty <= expected_ty++That is, that a value of type actual_ty is acceptable in+a place expecting a value of type expected_ty. I.e. that++ actual ty is more polymorphic than expected_ty++It returns a coercion function+ co_fn :: actual_ty ~ expected_ty+which takes an HsExpr of type actual_ty into one of type+expected_ty.++These functions do not actually check for subsumption. They check if+expected_ty is an appropriate annotation to use for something of type+actual_ty. This difference matters when thinking about visible type+application. For example,++ forall a. a -> forall b. b -> b+ DOES NOT SUBSUME+ forall a b. a -> b -> b++because the type arguments appear in a different order. (Neither does+it work the other way around.) BUT, these types are appropriate annotations+for one another. Because the user directs annotations, it's OK if some+arguments shuffle around -- after all, it's what the user wants.+Bottom line: none of this changes with visible type application.++There are a number of wrinkles (below).++Notice that Wrinkle 1 and 2 both require eta-expansion, which technically+may increase termination. We just put up with this, in exchange for getting+more predictable type inference.++Wrinkle 1: Note [Deep skolemisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We want (forall a. Int -> a -> a) <= (Int -> forall a. a->a)+(see section 4.6 of "Practical type inference for higher rank types")+So we must deeply-skolemise the RHS before we instantiate the LHS.++That is why tc_sub_type starts with a call to tcSkolemise (which does the+deep skolemisation), and then calls the DS variant (which assumes+that expected_ty is deeply skolemised)++Wrinkle 2: Note [Co/contra-variance of subsumption checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider g :: (Int -> Int) -> Int+ f1 :: (forall a. a -> a) -> Int+ f1 = g++ f2 :: (forall a. a -> a) -> Int+ f2 x = g x+f2 will typecheck, and it would be odd/fragile if f1 did not.+But f1 will only typecheck if we have that+ (Int->Int) -> Int <= (forall a. a->a) -> Int+And that is only true if we do the full co/contravariant thing+in the subsumption check. That happens in the FunTy case of+tcSubTypeDS_NC_O, and is the sole reason for the WpFun form of+HsWrapper.++Another powerful reason for doing this co/contra stuff is visible+in Trac #9569, involving instantiation of constraint variables,+and again involving eta-expansion.++Wrinkle 3: Note [Higher rank types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider tc150:+ f y = \ (x::forall a. a->a). blah+The following happens:+* We will infer the type of the RHS, ie with a res_ty = alpha.+* Then the lambda will split alpha := beta -> gamma.+* And then we'll check tcSubType IsSwapped beta (forall a. a->a)++So it's important that we unify beta := forall a. a->a, rather than+skolemising the type.+-}+++-- | Call this variant when you are in a higher-rank situation and+-- you know the right-hand type is deeply skolemised.+tcSubTypeHR :: Outputable a+ => CtOrigin -- ^ of the actual type+ -> Maybe a -- ^ If present, it has type ty_actual+ -> TcSigmaType -> ExpRhoType -> TcM HsWrapper+tcSubTypeHR orig = tcSubTypeDS_NC_O orig GenSigCtxt++------------------------+tcSubTypeET :: CtOrigin -> UserTypeCtxt+ -> ExpSigmaType -> TcSigmaType -> TcM HsWrapper+-- If wrap = tc_sub_type_et t1 t2+-- => wrap :: t1 ~> t2+tcSubTypeET orig ctxt (Check ty_actual) ty_expected+ = tc_sub_tc_type eq_orig orig ctxt ty_actual ty_expected+ where+ eq_orig = TypeEqOrigin { uo_actual = ty_expected+ , uo_expected = ty_actual+ , uo_thing = Nothing }++tcSubTypeET _ _ (Infer inf_res) ty_expected+ = ASSERT2( not (ir_inst inf_res), ppr inf_res $$ ppr ty_expected )+ do { co <- fillInferResult ty_expected inf_res+ ; return (mkWpCastN (mkTcSymCo co)) }++------------------------+tcSubTypeO :: CtOrigin -- ^ of the actual type+ -> UserTypeCtxt -- ^ of the expected type+ -> TcSigmaType+ -> ExpRhoType+ -> TcM HsWrapper+tcSubTypeO orig ctxt ty_actual ty_expected+ = addSubTypeCtxt ty_actual ty_expected $+ do { traceTc "tcSubTypeDS_O" (vcat [ pprCtOrigin orig+ , pprUserTypeCtxt ctxt+ , ppr ty_actual+ , ppr ty_expected ])+ ; tcSubTypeDS_NC_O orig ctxt noThing ty_actual ty_expected }++addSubTypeCtxt :: TcType -> ExpType -> TcM a -> TcM a+addSubTypeCtxt ty_actual ty_expected thing_inside+ | isRhoTy ty_actual -- If there is no polymorphism involved, the+ , isRhoExpTy ty_expected -- TypeEqOrigin stuff (added by the _NC functions)+ = thing_inside -- gives enough context by itself+ | otherwise+ = addErrCtxtM mk_msg thing_inside+ where+ mk_msg tidy_env+ = do { (tidy_env, ty_actual) <- zonkTidyTcType tidy_env ty_actual+ -- might not be filled if we're debugging. ugh.+ ; mb_ty_expected <- readExpType_maybe ty_expected+ ; (tidy_env, ty_expected) <- case mb_ty_expected of+ Just ty -> second mkCheckExpType <$>+ zonkTidyTcType tidy_env ty+ Nothing -> return (tidy_env, ty_expected)+ ; ty_expected <- readExpType ty_expected+ ; (tidy_env, ty_expected) <- zonkTidyTcType tidy_env ty_expected+ ; let msg = vcat [ hang (text "When checking that:")+ 4 (ppr ty_actual)+ , nest 2 (hang (text "is more polymorphic than:")+ 2 (ppr ty_expected)) ]+ ; return (tidy_env, msg) }++---------------+-- The "_NC" variants do not add a typechecker-error context;+-- the caller is assumed to do that++tcSubType_NC :: UserTypeCtxt -> TcSigmaType -> TcSigmaType -> TcM HsWrapper+-- Checks that actual <= expected+-- Returns HsWrapper :: actual ~ expected+tcSubType_NC ctxt ty_actual ty_expected+ = do { traceTc "tcSubType_NC" (vcat [pprUserTypeCtxt ctxt, ppr ty_actual, ppr ty_expected])+ ; tc_sub_tc_type origin origin ctxt ty_actual ty_expected }+ where+ origin = TypeEqOrigin { uo_actual = ty_actual+ , uo_expected = ty_expected+ , uo_thing = Nothing }++tcSubTypeDS :: CtOrigin -> UserTypeCtxt -> TcSigmaType -> ExpRhoType -> TcM HsWrapper+-- Just like tcSubType, but with the additional precondition that+-- ty_expected is deeply skolemised (hence "DS")+tcSubTypeDS orig ctxt ty_actual ty_expected+ = addSubTypeCtxt ty_actual ty_expected $+ do { traceTc "tcSubTypeDS_NC" (vcat [pprUserTypeCtxt ctxt, ppr ty_actual, ppr ty_expected])+ ; tcSubTypeDS_NC_O orig ctxt noThing ty_actual ty_expected }++tcSubTypeDS_NC_O :: Outputable a+ => CtOrigin -- origin used for instantiation only+ -> UserTypeCtxt+ -> Maybe a+ -> TcSigmaType -> ExpRhoType -> TcM HsWrapper+-- Just like tcSubType, but with the additional precondition that+-- ty_expected is deeply skolemised+tcSubTypeDS_NC_O inst_orig ctxt m_thing ty_actual ty_expected+ = case ty_expected of+ Infer inf_res -> fillInferResult_Inst inst_orig ty_actual inf_res+ Check ty -> tc_sub_type_ds eq_orig inst_orig ctxt ty_actual ty+ where+ eq_orig = TypeEqOrigin { uo_actual = ty_actual, uo_expected = ty+ , uo_thing = mkErrorThing <$> m_thing }++---------------+tc_sub_tc_type :: CtOrigin -- used when calling uType+ -> CtOrigin -- used when instantiating+ -> UserTypeCtxt -> TcSigmaType -> TcSigmaType -> TcM HsWrapper+-- If wrap = tc_sub_type t1 t2+-- => wrap :: t1 ~> t2+tc_sub_tc_type eq_orig inst_orig ctxt ty_actual ty_expected+ | is_poly ty_expected -- See Note [Don't skolemise unnecessarily]+ , not (is_poly ty_actual)+ = do { traceTc "tc_sub_tc_type (drop to equality)" $+ vcat [ text "ty_actual =" <+> ppr ty_actual+ , text "ty_expected =" <+> ppr ty_expected ]+ ; mkWpCastN <$>+ uType eq_orig TypeLevel ty_actual ty_expected }++ | otherwise -- This is the general case+ = do { traceTc "tc_sub_tc_type (general case)" $+ vcat [ text "ty_actual =" <+> ppr ty_actual+ , text "ty_expected =" <+> ppr ty_expected ]+ ; (sk_wrap, inner_wrap) <- tcSkolemise ctxt ty_expected $+ \ _ sk_rho ->+ tc_sub_type_ds eq_orig inst_orig ctxt+ ty_actual sk_rho+ ; return (sk_wrap <.> inner_wrap) }+ where+ is_poly ty+ | isForAllTy ty = True+ | Just (_, res) <- splitFunTy_maybe ty = is_poly res+ | otherwise = False+ -- NB *not* tcSplitFunTy, because here we want+ -- to decompose type-class arguments too+++{- Note [Don't skolemise unnecessarily]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we are trying to solve+ (Char->Char) <= (forall a. a->a)+We could skolemise the 'forall a', and then complain+that (Char ~ a) is insoluble; but that's a pretty obscure+error. It's better to say that+ (Char->Char) ~ (forall a. a->a)+fails.++In general,+ * if the RHS type an outermost forall (i.e. skolemisation+ is the next thing we'd do)+ * and the LHS has no top-level polymorphism (but looking deeply)+then we can revert to simple equality.+-}++---------------+tc_sub_type_ds :: CtOrigin -- used when calling uType+ -> CtOrigin -- used when instantiating+ -> UserTypeCtxt -> TcSigmaType -> TcRhoType -> TcM HsWrapper+-- If wrap = tc_sub_type_ds t1 t2+-- => wrap :: t1 ~> t2+-- Here is where the work actually happens!+-- Precondition: ty_expected is deeply skolemised+tc_sub_type_ds eq_orig inst_orig ctxt ty_actual ty_expected+ = do { traceTc "tc_sub_type_ds" $+ vcat [ text "ty_actual =" <+> ppr ty_actual+ , text "ty_expected =" <+> ppr ty_expected ]+ ; go ty_actual ty_expected }+ where+ go ty_a ty_e | Just ty_a' <- tcView ty_a = go ty_a' ty_e+ | Just ty_e' <- tcView ty_e = go ty_a ty_e'++ go (TyVarTy tv_a) ty_e+ = do { lookup_res <- lookupTcTyVar tv_a+ ; case lookup_res of+ Filled ty_a' ->+ do { traceTc "tcSubTypeDS_NC_O following filled act meta-tyvar:"+ (ppr tv_a <+> text "-->" <+> ppr ty_a')+ ; tc_sub_type_ds eq_orig inst_orig ctxt ty_a' ty_e }+ Unfilled _ -> unify }++ -- Historical note (Sept 16): there was a case here for+ -- go ty_a (TyVarTy alpha)+ -- which, in the impredicative case unified alpha := ty_a+ -- where th_a is a polytype. Not only is this probably bogus (we+ -- simply do not have decent story for imprdicative types), but it+ -- caused Trac #12616 because (also bizarrely) 'deriving' code had+ -- -XImpredicativeTypes on. I deleted the entire case.++ go (FunTy act_arg act_res) (FunTy exp_arg exp_res)+ | not (isPredTy act_arg)+ , not (isPredTy exp_arg)+ = -- See Note [Co/contra-variance of subsumption checking]+ do { res_wrap <- tc_sub_type_ds eq_orig inst_orig ctxt act_res exp_res+ ; arg_wrap <- tc_sub_tc_type eq_orig given_orig ctxt exp_arg act_arg+ ; return (mkWpFun arg_wrap res_wrap exp_arg exp_res doc) }+ -- arg_wrap :: exp_arg ~> act_arg+ -- res_wrap :: act-res ~> exp_res+ where+ given_orig = GivenOrigin (SigSkol GenSigCtxt exp_arg [])+ doc = text "When checking that" <+> quotes (ppr ty_actual) <+>+ text "is more polymorphic than" <+> quotes (ppr ty_expected)++ go ty_a ty_e+ | let (tvs, theta, _) = tcSplitSigmaTy ty_a+ , not (null tvs && null theta)+ = do { (in_wrap, in_rho) <- topInstantiate inst_orig ty_a+ ; body_wrap <- tc_sub_type_ds+ (eq_orig { uo_actual = in_rho+ , uo_expected = ty_expected })+ inst_orig ctxt in_rho ty_e+ ; return (body_wrap <.> in_wrap) }++ | otherwise -- Revert to unification+ = inst_and_unify+ -- It's still possible that ty_actual has nested foralls. Instantiate+ -- these, as there's no way unification will succeed with them in.+ -- See typecheck/should_compile/T11305 for an example of when this+ -- is important. The problem is that we're checking something like+ -- a -> forall b. b -> b <= alpha beta gamma+ -- where we end up with alpha := (->)++ inst_and_unify = do { (wrap, rho_a) <- deeplyInstantiate inst_orig ty_actual++ -- if we haven't recurred through an arrow, then+ -- the eq_orig will list ty_actual. In this case,+ -- we want to update the origin to reflect the+ -- instantiation. If we *have* recurred through+ -- an arrow, it's better not to update.+ ; let eq_orig' = case eq_orig of+ TypeEqOrigin { uo_actual = orig_ty_actual }+ | orig_ty_actual `tcEqType` ty_actual+ , not (isIdHsWrapper wrap)+ -> eq_orig { uo_actual = rho_a }+ _ -> eq_orig++ ; cow <- uType eq_orig' TypeLevel rho_a ty_expected+ ; return (mkWpCastN cow <.> wrap) }+++ -- use versions without synonyms expanded+ unify = mkWpCastN <$> uType eq_orig TypeLevel ty_actual ty_expected++-----------------+-- needs both un-type-checked (for origins) and type-checked (for wrapping)+-- expressions+tcWrapResult :: HsExpr Name -> HsExpr TcId -> TcSigmaType -> ExpRhoType+ -> TcM (HsExpr TcId)+tcWrapResult rn_expr = tcWrapResultO (exprCtOrigin rn_expr)++-- | Sometimes we don't have a @HsExpr Name@ to hand, and this is more+-- convenient.+tcWrapResultO :: CtOrigin -> HsExpr TcId -> TcSigmaType -> ExpRhoType+ -> TcM (HsExpr TcId)+tcWrapResultO orig expr actual_ty res_ty+ = do { traceTc "tcWrapResult" (vcat [ text "Actual: " <+> ppr actual_ty+ , text "Expected:" <+> ppr res_ty ])+ ; cow <- tcSubTypeDS_NC_O orig GenSigCtxt+ (Just expr) actual_ty res_ty+ ; return (mkHsWrap cow expr) }++-----------------------------------+wrapFunResCoercion+ :: [TcType] -- Type of args+ -> HsWrapper -- HsExpr a -> HsExpr b+ -> TcM HsWrapper -- HsExpr (arg_tys -> a) -> HsExpr (arg_tys -> b)+wrapFunResCoercion arg_tys co_fn_res+ | isIdHsWrapper co_fn_res+ = return idHsWrapper+ | null arg_tys+ = return co_fn_res+ | otherwise+ = do { arg_ids <- newSysLocalIds (fsLit "sub") arg_tys+ ; return (mkWpLams arg_ids <.> co_fn_res <.> mkWpEvVarApps arg_ids) }+++{- **********************************************************************+%* *+ ExpType functions: tcInfer, fillInferResult+%* *+%********************************************************************* -}++-- | Infer a type using a fresh ExpType+-- See also Note [ExpType] in TcMType+-- Does not attempt to instantiate the inferred type+tcInferNoInst :: (ExpSigmaType -> TcM a) -> TcM (a, TcSigmaType)+tcInferNoInst = tcInfer False++tcInferInst :: (ExpRhoType -> TcM a) -> TcM (a, TcRhoType)+tcInferInst = tcInfer True++tcInfer :: Bool -> (ExpSigmaType -> TcM a) -> TcM (a, TcSigmaType)+tcInfer instantiate tc_check+ = do { res_ty <- newInferExpType instantiate+ ; result <- tc_check res_ty+ ; res_ty <- readExpType res_ty+ ; return (result, res_ty) }++fillInferResult_Inst :: CtOrigin -> TcType -> InferResult -> TcM HsWrapper+-- If wrap = fillInferResult_Inst t1 t2+-- => wrap :: t1 ~> t2+-- See Note [Deep instantiation of InferResult]+fillInferResult_Inst orig ty inf_res@(IR { ir_inst = instantiate_me })+ | instantiate_me+ = do { (wrap, rho) <- deeplyInstantiate orig ty+ ; co <- fillInferResult rho inf_res+ ; return (mkWpCastN co <.> wrap) }++ | otherwise+ = do { co <- fillInferResult ty inf_res+ ; return (mkWpCastN co) }++fillInferResult :: TcType -> InferResult -> TcM TcCoercionN+-- If wrap = fillInferResult t1 t2+-- => wrap :: t1 ~> t2+fillInferResult orig_ty (IR { ir_uniq = u, ir_lvl = res_lvl+ , ir_ref = ref })+ = do { (ty_co, ty_to_fill_with) <- promoteTcType res_lvl orig_ty++ ; traceTc "Filling ExpType" $+ ppr u <+> text ":=" <+> ppr ty_to_fill_with++ ; when debugIsOn (check_hole ty_to_fill_with)++ ; writeTcRef ref (Just ty_to_fill_with)++ ; return ty_co }+ where+ check_hole ty -- Debug check only+ = do { let ty_lvl = tcTypeLevel ty+ ; MASSERT2( not (ty_lvl `strictlyDeeperThan` res_lvl),+ ppr u $$ ppr res_lvl $$ ppr ty_lvl $$+ ppr ty <+> ppr (typeKind ty) $$ ppr orig_ty )+ ; cts <- readTcRef ref+ ; case cts of+ Just already_there -> pprPanic "writeExpType"+ (vcat [ ppr u+ , ppr ty+ , ppr already_there ])+ Nothing -> return () }++{- Note [Deep instantiation of InferResult]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In some cases we want to deeply instantiate before filling in+an InferResult, and in some cases not. That's why InferReult+has the ir_inst flag.++* ir_inst = True: deeply instantantiate++ Consider+ f x = (*)+ We want to instantiate the type of (*) before returning, else we+ will infer the type+ f :: forall {a}. a -> forall b. Num b => b -> b -> b+ This is surely confusing for users.++ And worse, the the monomorphism restriction won't properly. The MR is+ dealt with in simplifyInfer, and simplifyInfer has no way of+ instantiating. This could perhaps be worked around, but it may be+ hard to know even when instantiation should happen.++ Another reason. Consider+ f :: (?x :: Int) => a -> a+ g y = let ?x = 3::Int in f+ Here want to instantiate f's type so that the ?x::Int constraint+ gets discharged by the enclosing implicit-parameter binding.++* ir_inst = False: do not instantantiate++ Consider this (which uses visible type application):++ (let { f :: forall a. a -> a; f x = x } in f) @Int++ We'll call TcExpr.tcInferFun to infer the type of the (let .. in f)+ And we don't want to instantite the type of 'f' when we reach it,+ else the outer visible type application won't work+-}++{- *********************************************************************+* *+ Promoting types+* *+********************************************************************* -}++promoteTcType :: TcLevel -> TcType -> TcM (TcCoercion, TcType)+-- See Note [Promoting a type]+-- promoteTcType level ty = (co, ty')+-- * Returns ty' whose max level is just 'level'+-- and whose kind is ~# to the kind of 'ty'+-- and whose kind has form TYPE rr+-- * and co :: ty ~ ty'+-- * and emits constraints to justify the coercion+promoteTcType dest_lvl ty+ = do { cur_lvl <- getTcLevel+ ; if (cur_lvl `sameDepthAs` dest_lvl)+ then dont_promote_it+ else promote_it }+ where+ promote_it :: TcM (TcCoercion, TcType)+ promote_it -- Emit a constraint (alpha :: TYPE rr) ~ ty+ -- where alpha and rr are fresh and from level dest_lvl+ = do { rr <- newMetaTyVarTyAtLevel dest_lvl runtimeRepTy+ ; prom_ty <- newMetaTyVarTyAtLevel dest_lvl (tYPE rr)+ ; let eq_orig = TypeEqOrigin { uo_actual = ty+ , uo_expected = prom_ty+ , uo_thing = Nothing }++ ; co <- emitWantedEq eq_orig TypeLevel Nominal ty prom_ty+ ; return (co, prom_ty) }++ dont_promote_it :: TcM (TcCoercion, TcType)+ dont_promote_it -- Check that ty :: TYPE rr, for some (fresh) rr+ = do { res_kind <- newOpenTypeKind+ ; let ty_kind = typeKind ty+ kind_orig = TypeEqOrigin { uo_actual = ty_kind+ , uo_expected = res_kind+ , uo_thing = Nothing }+ ; ki_co <- uType kind_orig KindLevel (typeKind ty) res_kind+ ; let co = mkTcNomReflCo ty `mkTcCoherenceRightCo` ki_co+ ; return (co, ty `mkCastTy` ki_co) }++{- Note [Promoting a type]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider (Trac #12427)++ data T where+ MkT :: (Int -> Int) -> a -> T++ h y = case y of MkT v w -> v++We'll infer the RHS type with an expected type ExpType of+ (IR { ir_lvl = l, ir_ref = ref, ... )+where 'l' is the TcLevel of the RHS of 'h'. Then the MkT pattern+match will increase the level, so we'll end up in tcSubType, trying to+unify the type of v,+ v :: Int -> Int+with the expected type. But this attempt takes place at level (l+1),+rightly so, since v's type could have mentioned existential variables,+(like w's does) and we want to catch that.++So we+ - create a new meta-var alpha[l+1]+ - fill in the InferRes ref cell 'ref' with alpha+ - emit an equality constraint, thus+ [W] alpha[l+1] ~ (Int -> Int)++That constraint will float outwards, as it should, unless v's+type mentions a skolem-captured variable.++This approach fails if v has a higher rank type; see+Note [Promotion and higher rank types]+++Note [Promotion and higher rank types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If v had a higher-rank type, say v :: (forall a. a->a) -> Int,+then we'd emit an equality+ [W] alpha[l+1] ~ ((forall a. a->a) -> Int)+which will sadly fail because we can't unify a unification variable+with a polytype. But there is nothing really wrong with the program+here.++We could just about solve this by "promote the type" of v, to expose+its polymorphic "shape" while still leaving constraints that will+prevent existential escape. But we must be careful! Exposing+the "shape" of the type is precisely what we must NOT do under+a GADT pattern match! So in this case we might promote the type+to+ (forall a. a->a) -> alpha[l+1]+and emit the constraint+ [W] alpha[l+1] ~ Int+Now the poromoted type can fill the ref cell, while the emitted+equality can float or not, according to the usual rules.++But that's not quite right! We are exposing the arrow! We could+deal with that too:+ (forall a. mu[l+1] a a) -> alpha[l+1]+with constraints+ [W] alpha[l+1] ~ Int+ [W] mu[l+1] ~ (->)+Here we abstract over the '->' inside the forall, in case that+is subject to an equality constraint from a GADT match.++Note that we kept the outer (->) because that's part of+the polymorphic "shape". And becauuse of impredicativity,+GADT matches can't give equalities that affect polymorphic+shape.++This reasoning just seems too complicated, so I decided not+to do it. These higher-rank notes are just here to record+the thinking.+-}++{- *********************************************************************+* *+ Generalisation+* *+********************************************************************* -}++-- | Take an "expected type" and strip off quantifiers to expose the+-- type underneath, binding the new skolems for the @thing_inside@.+-- The returned 'HsWrapper' has type @specific_ty -> expected_ty@.+tcSkolemise :: UserTypeCtxt -> TcSigmaType+ -> ([TcTyVar] -> TcType -> TcM result)+ -- ^ These are only ever used for scoped type variables.+ -> TcM (HsWrapper, result)+ -- ^ The expression has type: spec_ty -> expected_ty++tcSkolemise ctxt expected_ty thing_inside+ -- We expect expected_ty to be a forall-type+ -- If not, the call is a no-op+ = do { traceTc "tcSkolemise" Outputable.empty+ ; (wrap, tv_prs, given, rho') <- deeplySkolemise expected_ty++ ; lvl <- getTcLevel+ ; when debugIsOn $+ traceTc "tcSkolemise" $ vcat [+ ppr lvl,+ text "expected_ty" <+> ppr expected_ty,+ text "inst tyvars" <+> ppr tv_prs,+ text "given" <+> ppr given,+ text "inst type" <+> ppr rho' ]++ -- Generally we must check that the "forall_tvs" havn't been constrained+ -- The interesting bit here is that we must include the free variables+ -- of the expected_ty. Here's an example:+ -- runST (newVar True)+ -- Here, if we don't make a check, we'll get a type (ST s (MutVar s Bool))+ -- for (newVar True), with s fresh. Then we unify with the runST's arg type+ -- forall s'. ST s' a. That unifies s' with s, and a with MutVar s Bool.+ -- So now s' isn't unconstrained because it's linked to a.+ --+ -- However [Oct 10] now that the untouchables are a range of+ -- TcTyVars, all this is handled automatically with no need for+ -- extra faffing around++ ; let tvs' = map snd tv_prs+ skol_info = SigSkol ctxt expected_ty tv_prs++ ; (ev_binds, result) <- checkConstraints skol_info tvs' given $+ thing_inside tvs' rho'++ ; return (wrap <.> mkWpLet ev_binds, result) }+ -- The ev_binds returned by checkConstraints is very+ -- often empty, in which case mkWpLet is a no-op++-- | Variant of 'tcSkolemise' that takes an ExpType+tcSkolemiseET :: UserTypeCtxt -> ExpSigmaType+ -> (ExpRhoType -> TcM result)+ -> TcM (HsWrapper, result)+tcSkolemiseET _ et@(Infer {}) thing_inside+ = (idHsWrapper, ) <$> thing_inside et+tcSkolemiseET ctxt (Check ty) thing_inside+ = tcSkolemise ctxt ty $ \_ -> thing_inside . mkCheckExpType++checkConstraints :: SkolemInfo+ -> [TcTyVar] -- Skolems+ -> [EvVar] -- Given+ -> TcM result+ -> TcM (TcEvBinds, result)++checkConstraints skol_info skol_tvs given thing_inside+ = do { (implics, ev_binds, result)+ <- buildImplication skol_info skol_tvs given thing_inside+ ; emitImplications implics+ ; return (ev_binds, result) }++buildImplication :: SkolemInfo+ -> [TcTyVar] -- Skolems+ -> [EvVar] -- Given+ -> TcM result+ -> TcM (Bag Implication, TcEvBinds, result)+buildImplication skol_info skol_tvs given thing_inside+ = do { tc_lvl <- getTcLevel+ ; deferred_type_errors <- goptM Opt_DeferTypeErrors <||>+ goptM Opt_DeferTypedHoles+ ; if null skol_tvs && null given && (not deferred_type_errors ||+ not (isTopTcLevel tc_lvl))+ then do { res <- thing_inside+ ; return (emptyBag, emptyTcEvBinds, res) }+ -- Fast path. We check every function argument with+ -- tcPolyExpr, which uses tcSkolemise and hence checkConstraints.+ -- But with the solver producing unlifted equalities, we need+ -- to have an EvBindsVar for them when they might be deferred to+ -- runtime. Otherwise, they end up as top-level unlifted bindings,+ -- which are verboten. See also Note [Deferred errors for coercion holes]+ -- in TcErrors.+ else+ do { (tclvl, wanted, result) <- pushLevelAndCaptureConstraints thing_inside+ ; (implics, ev_binds) <- buildImplicationFor tclvl skol_info skol_tvs given wanted+ ; return (implics, ev_binds, result) }}++buildImplicationFor :: TcLevel -> SkolemInfo -> [TcTyVar]+ -> [EvVar] -> WantedConstraints+ -> TcM (Bag Implication, TcEvBinds)+buildImplicationFor tclvl skol_info skol_tvs given wanted+ | isEmptyWC wanted && null given+ -- Optimisation : if there are no wanteds, and no givens+ -- don't generate an implication at all.+ -- Reason for the (null given): we don't want to lose+ -- the "inaccessible alternative" error check+ = return (emptyBag, emptyTcEvBinds)++ | otherwise+ = ASSERT2( all isSkolemTyVar skol_tvs, ppr skol_tvs )+ do { ev_binds_var <- newTcEvBinds+ ; env <- getLclEnv+ ; let implic = Implic { ic_tclvl = tclvl+ , ic_skols = skol_tvs+ , ic_no_eqs = False+ , ic_given = given+ , ic_wanted = wanted+ , ic_status = IC_Unsolved+ , ic_binds = ev_binds_var+ , ic_env = env+ , ic_needed = emptyVarSet+ , ic_info = skol_info }++ ; return (unitBag implic, TcEvBinds ev_binds_var) }++{-+************************************************************************+* *+ Boxy unification+* *+************************************************************************++The exported functions are all defined as versions of some+non-exported generic functions.+-}++unifyType :: Outputable a => Maybe a -- ^ If present, has type 'ty1'+ -> TcTauType -> TcTauType -> TcM TcCoercionN+-- Actual and expected types+-- Returns a coercion : ty1 ~ ty2+unifyType thing ty1 ty2 = uType origin TypeLevel ty1 ty2+ where+ origin = TypeEqOrigin { uo_actual = ty1, uo_expected = ty2+ , uo_thing = mkErrorThing <$> thing }++-- | Use this instead of 'Nothing' when calling 'unifyType' without+-- a good "thing" (where the "thing" has the "actual" type passed in)+-- This has an 'Outputable' instance, avoiding amgiguity problems.+noThing :: Maybe (HsExpr Name)+noThing = Nothing++unifyKind :: Outputable a => Maybe a -> TcKind -> TcKind -> TcM CoercionN+unifyKind thing ty1 ty2 = uType origin KindLevel ty1 ty2+ where origin = TypeEqOrigin { uo_actual = ty1, uo_expected = ty2+ , uo_thing = mkErrorThing <$> thing }++---------------+unifyPred :: PredType -> PredType -> TcM TcCoercionN+-- Actual and expected types+unifyPred = unifyType noThing++---------------+unifyTheta :: TcThetaType -> TcThetaType -> TcM [TcCoercionN]+-- Actual and expected types+unifyTheta theta1 theta2+ = do { checkTc (equalLength theta1 theta2)+ (vcat [text "Contexts differ in length",+ nest 2 $ parens $ text "Use RelaxedPolyRec to allow this"])+ ; zipWithM unifyPred theta1 theta2 }++{-+%************************************************************************+%* *+ uType and friends+%* *+%************************************************************************++uType is the heart of the unifier.+-}++uType, uType_defer+ :: CtOrigin+ -> TypeOrKind+ -> TcType -- ty1 is the *actual* type+ -> TcType -- ty2 is the *expected* type+ -> TcM Coercion++--------------+-- It is always safe to defer unification to the main constraint solver+-- See Note [Deferred unification]+uType_defer origin t_or_k ty1 ty2+ = do { co <- emitWantedEq origin t_or_k Nominal ty1 ty2++ -- Error trace only+ -- NB. do *not* call mkErrInfo unless tracing is on,+ -- because it is hugely expensive (#5631)+ ; whenDOptM Opt_D_dump_tc_trace $ do+ { ctxt <- getErrCtxt+ ; doc <- mkErrInfo emptyTidyEnv ctxt+ ; traceTc "utype_defer" (vcat [ppr co, ppr ty1,+ ppr ty2, pprCtOrigin origin, doc])+ }+ ; return co }++--------------+uType origin t_or_k orig_ty1 orig_ty2+ = do { tclvl <- getTcLevel+ ; traceTc "u_tys" $ vcat+ [ text "tclvl" <+> ppr tclvl+ , sep [ ppr orig_ty1, text "~", ppr orig_ty2]+ , pprCtOrigin origin]+ ; co <- go orig_ty1 orig_ty2+ ; if isReflCo co+ then traceTc "u_tys yields no coercion" Outputable.empty+ else traceTc "u_tys yields coercion:" (ppr co)+ ; return co }+ where+ go :: TcType -> TcType -> TcM Coercion+ -- The arguments to 'go' are always semantically identical+ -- to orig_ty{1,2} except for looking through type synonyms++ -- Variables; go for uVar+ -- Note that we pass in *original* (before synonym expansion),+ -- so that type variables tend to get filled in with+ -- the most informative version of the type+ go (TyVarTy tv1) ty2+ = do { lookup_res <- lookupTcTyVar tv1+ ; case lookup_res of+ Filled ty1 -> do { traceTc "found filled tyvar" (ppr tv1 <+> text ":->" <+> ppr ty1)+ ; go ty1 ty2 }+ Unfilled _ -> uUnfilledVar origin t_or_k NotSwapped tv1 ty2 }+ go ty1 (TyVarTy tv2)+ = do { lookup_res <- lookupTcTyVar tv2+ ; case lookup_res of+ Filled ty2 -> do { traceTc "found filled tyvar" (ppr tv2 <+> text ":->" <+> ppr ty2)+ ; go ty1 ty2 }+ Unfilled _ -> uUnfilledVar origin t_or_k IsSwapped tv2 ty1 }++ -- See Note [Expanding synonyms during unification]+ go ty1@(TyConApp tc1 []) (TyConApp tc2 [])+ | tc1 == tc2+ = return $ mkReflCo Nominal ty1++ -- See Note [Expanding synonyms during unification]+ --+ -- Also NB that we recurse to 'go' so that we don't push a+ -- new item on the origin stack. As a result if we have+ -- type Foo = Int+ -- and we try to unify Foo ~ Bool+ -- we'll end up saying "can't match Foo with Bool"+ -- rather than "can't match "Int with Bool". See Trac #4535.+ go ty1 ty2+ | Just ty1' <- tcView ty1 = go ty1' ty2+ | Just ty2' <- tcView ty2 = go ty1 ty2'++ go (CastTy t1 co1) t2+ = do { co_tys <- go t1 t2+ ; return (mkCoherenceLeftCo co_tys co1) }++ go t1 (CastTy t2 co2)+ = do { co_tys <- go t1 t2+ ; return (mkCoherenceRightCo co_tys co2) }++ -- Functions (or predicate functions) just check the two parts+ go (FunTy fun1 arg1) (FunTy fun2 arg2)+ = do { co_l <- uType origin t_or_k fun1 fun2+ ; co_r <- uType origin t_or_k arg1 arg2+ ; return $ mkFunCo Nominal co_l co_r }++ -- Always defer if a type synonym family (type function)+ -- is involved. (Data families behave rigidly.)+ go ty1@(TyConApp tc1 _) ty2+ | isTypeFamilyTyCon tc1 = defer ty1 ty2+ go ty1 ty2@(TyConApp tc2 _)+ | isTypeFamilyTyCon tc2 = defer ty1 ty2++ go (TyConApp tc1 tys1) (TyConApp tc2 tys2)+ -- See Note [Mismatched type lists and application decomposition]+ | tc1 == tc2, length tys1 == length tys2+ = ASSERT2( isGenerativeTyCon tc1 Nominal, ppr tc1 )+ do { cos <- zipWithM (uType origin t_or_k) tys1 tys2+ ; return $ mkTyConAppCo Nominal tc1 cos }++ go (LitTy m) ty@(LitTy n)+ | m == n+ = return $ mkNomReflCo ty++ -- See Note [Care with type applications]+ -- Do not decompose FunTy against App;+ -- it's often a type error, so leave it for the constraint solver+ go (AppTy s1 t1) (AppTy s2 t2)+ = go_app s1 t1 s2 t2++ go (AppTy s1 t1) (TyConApp tc2 ts2)+ | Just (ts2', t2') <- snocView ts2+ = ASSERT( mightBeUnsaturatedTyCon tc2 )+ go_app s1 t1 (TyConApp tc2 ts2') t2'++ go (TyConApp tc1 ts1) (AppTy s2 t2)+ | Just (ts1', t1') <- snocView ts1+ = ASSERT( mightBeUnsaturatedTyCon tc1 )+ go_app (TyConApp tc1 ts1') t1' s2 t2++ go (CoercionTy co1) (CoercionTy co2)+ = do { let ty1 = coercionType co1+ ty2 = coercionType co2+ ; kco <- uType (KindEqOrigin orig_ty1 (Just orig_ty2) origin+ (Just t_or_k))+ KindLevel+ ty1 ty2+ ; return $ mkProofIrrelCo Nominal kco co1 co2 }++ -- Anything else fails+ -- E.g. unifying for-all types, which is relative unusual+ go ty1 ty2 = defer ty1 ty2++ ------------------+ defer ty1 ty2 -- See Note [Check for equality before deferring]+ | ty1 `tcEqType` ty2 = return (mkNomReflCo ty1)+ | otherwise = uType_defer origin t_or_k ty1 ty2++ ------------------+ go_app s1 t1 s2 t2+ = do { co_s <- uType origin t_or_k s1 s2+ ; co_t <- uType origin t_or_k t1 t2+ ; return $ mkAppCo co_s co_t }++{- Note [Check for equality before deferring]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Particularly in ambiguity checks we can get equalities like (ty ~ ty).+If ty involves a type function we may defer, which isn't very sensible.+An egregious example of this was in test T9872a, which has a type signature+ Proxy :: Proxy (Solutions Cubes)+Doing the ambiguity check on this signature generates the equality+ Solutions Cubes ~ Solutions Cubes+and currently the constraint solver normalises both sides at vast cost.+This little short-cut in 'defer' helps quite a bit.++Note [Care with type applications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Note: type applications need a bit of care!+They can match FunTy and TyConApp, so use splitAppTy_maybe+NB: we've already dealt with type variables and Notes,+so if one type is an App the other one jolly well better be too++Note [Mismatched type lists and application decomposition]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When we find two TyConApps, you might think that the argument lists+are guaranteed equal length. But they aren't. Consider matching+ w (T x) ~ Foo (T x y)+We do match (w ~ Foo) first, but in some circumstances we simply create+a deferred constraint; and then go ahead and match (T x ~ T x y).+This came up in Trac #3950.++So either+ (a) either we must check for identical argument kinds+ when decomposing applications,++ (b) or we must be prepared for ill-kinded unification sub-problems++Currently we adopt (b) since it seems more robust -- no need to maintain+a global invariant.++Note [Expanding synonyms during unification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We expand synonyms during unification, but:+ * We expand *after* the variable case so that we tend to unify+ variables with un-expanded type synonym. This just makes it+ more likely that the inferred types will mention type synonyms+ understandable to the user++ * We expand *before* the TyConApp case. For example, if we have+ type Phantom a = Int+ and are unifying+ Phantom Int ~ Phantom Char+ it is *wrong* to unify Int and Char.++ * The problem case immediately above can happen only with arguments+ to the tycon. So we check for nullary tycons *before* expanding.+ This is particularly helpful when checking (* ~ *), because * is+ now a type synonym.++Note [Deferred Unification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+We may encounter a unification ty1 ~ ty2 that cannot be performed syntactically,+and yet its consistency is undetermined. Previously, there was no way to still+make it consistent. So a mismatch error was issued.++Now these unifications are deferred until constraint simplification, where type+family instances and given equations may (or may not) establish the consistency.+Deferred unifications are of the form+ F ... ~ ...+or x ~ ...+where F is a type function and x is a type variable.+E.g.+ id :: x ~ y => x -> y+ id e = e++involves the unification x = y. It is deferred until we bring into account the+context x ~ y to establish that it holds.++If available, we defer original types (rather than those where closed type+synonyms have already been expanded via tcCoreView). This is, as usual, to+improve error messages.+++************************************************************************+* *+ uVar and friends+* *+************************************************************************++@uVar@ is called when at least one of the types being unified is a+variable. It does {\em not} assume that the variable is a fixed point+of the substitution; rather, notice that @uVar@ (defined below) nips+back into @uTys@ if it turns out that the variable is already bound.+-}++----------+uUnfilledVar :: CtOrigin+ -> TypeOrKind+ -> SwapFlag+ -> TcTyVar -- Tyvar 1+ -> TcTauType -- Type 2+ -> TcM Coercion+-- "Unfilled" means that the variable is definitely not a filled-in meta tyvar+-- It might be a skolem, or untouchable, or meta++uUnfilledVar origin t_or_k swapped tv1 ty2+ = do { ty2 <- zonkTcType ty2+ -- Zonk to expose things to the+ -- occurs check, and so that if ty2+ -- looks like a type variable then it+ -- /is/ a type variable+ ; uUnfilledVar1 origin t_or_k swapped tv1 ty2 }++----------+uUnfilledVar1 :: CtOrigin+ -> TypeOrKind+ -> SwapFlag+ -> TcTyVar -- Tyvar 1+ -> TcTauType -- Type 2, zonked+ -> TcM Coercion+uUnfilledVar1 origin t_or_k swapped tv1 ty2+ | Just tv2 <- tcGetTyVar_maybe ty2+ = go tv2++ | otherwise+ = uUnfilledVar2 origin t_or_k swapped tv1 ty2++ where+ -- 'go' handles the case where both are+ -- tyvars so we might want to swap+ go tv2 | tv1 == tv2 -- Same type variable => no-op+ = return (mkNomReflCo (mkTyVarTy tv1))++ | swapOverTyVars tv1 tv2 -- Distinct type variables+ = uUnfilledVar2 origin t_or_k (flipSwap swapped)+ tv2 (mkTyVarTy tv1)++ | otherwise+ = uUnfilledVar2 origin t_or_k swapped tv1 ty2++----------+uUnfilledVar2 :: CtOrigin+ -> TypeOrKind+ -> SwapFlag+ -> TcTyVar -- Tyvar 1+ -> TcTauType -- Type 2, zonked+ -> TcM Coercion+uUnfilledVar2 origin t_or_k swapped tv1 ty2+ = do { dflags <- getDynFlags+ ; cur_lvl <- getTcLevel+ ; go dflags cur_lvl }+ where+ go dflags cur_lvl+ | canSolveByUnification cur_lvl tv1 ty2+ , Just ty2' <- metaTyVarUpdateOK dflags tv1 ty2+ = do { co_k <- uType kind_origin KindLevel (typeKind ty2') (tyVarKind tv1)+ ; co <- updateMeta tv1 ty2' co_k+ ; return (maybe_sym swapped co) }++ | otherwise+ = unSwap swapped (uType_defer origin t_or_k) ty1 ty2+ -- Occurs check or an untouchable: just defer+ -- NB: occurs check isn't necessarily fatal:+ -- eg tv1 occured in type family parameter++ ty1 = mkTyVarTy tv1+ kind_origin = KindEqOrigin ty1 (Just ty2) origin (Just t_or_k)++-- | apply sym iff swapped+maybe_sym :: SwapFlag -> Coercion -> Coercion+maybe_sym IsSwapped = mkSymCo+maybe_sym NotSwapped = id++swapOverTyVars :: TcTyVar -> TcTyVar -> Bool+swapOverTyVars tv1 tv2+ | isFmvTyVar tv1 = False -- See Note [Fmv Orientation Invariant]+ | isFmvTyVar tv2 = True++ | Just lvl1 <- metaTyVarTcLevel_maybe tv1+ -- If tv1 is touchable, swap only if tv2 is also+ -- touchable and it's strictly better to update the latter+ -- But see Note [Avoid unnecessary swaps]+ = case metaTyVarTcLevel_maybe tv2 of+ Nothing -> False+ Just lvl2 | lvl2 `strictlyDeeperThan` lvl1 -> True+ | lvl1 `strictlyDeeperThan` lvl2 -> False+ | otherwise -> nicer_to_update tv2++ -- So tv1 is not a meta tyvar+ -- If only one is a meta tyvar, put it on the left+ -- This is not because it'll be solved; but because+ -- the floating step looks for meta tyvars on the left+ | isMetaTyVar tv2 = True++ -- So neither is a meta tyvar (including FlatMetaTv)++ -- If only one is a flatten skolem, put it on the left+ -- See Note [Eliminate flat-skols]+ | not (isFlattenTyVar tv1), isFlattenTyVar tv2 = True++ | otherwise = False++ where+ nicer_to_update tv2+ = (isSigTyVar tv1 && not (isSigTyVar tv2))+ || (isSystemName (Var.varName tv2) && not (isSystemName (Var.varName tv1)))++-- @trySpontaneousSolve wi@ solves equalities where one side is a+-- touchable unification variable.+-- Returns True <=> spontaneous solve happened+canSolveByUnification :: TcLevel -> TcTyVar -> TcType -> Bool+canSolveByUnification tclvl tv xi+ | isTouchableMetaTyVar tclvl tv+ = case metaTyVarInfo tv of+ SigTv -> is_tyvar xi+ _ -> True++ | otherwise -- Untouchable+ = False+ where+ is_tyvar xi+ = case tcGetTyVar_maybe xi of+ Nothing -> False+ Just tv -> case tcTyVarDetails tv of+ MetaTv { mtv_info = info }+ -> case info of+ SigTv -> True+ _ -> False+ SkolemTv {} -> True+ FlatSkol {} -> False+ RuntimeUnk -> True++{- Note [Fmv Orientation Invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * We always orient a constraint+ fmv ~ alpha+ with fmv on the left, even if alpha is+ a touchable unification variable++Reason: doing it the other way round would unify alpha:=fmv, but that+really doesn't add any info to alpha. But a later constraint alpha ~+Int might unlock everything. Comment:9 of #12526 gives a detailed+example.++WARNING: I've gone to and fro on this one several times.+I'm now pretty sure that unifying alpha:=fmv is a bad idea!+So orienting with fmvs on the left is a good thing.++This example comes from IndTypesPerfMerge. (Others include+T10226, T10009.)+ From the ambiguity check for+ f :: (F a ~ a) => a+ we get:+ [G] F a ~ a+ [WD] F alpha ~ alpha, alpha ~ a++ From Givens we get+ [G] F a ~ fsk, fsk ~ a++ Now if we flatten we get+ [WD] alpha ~ fmv, F alpha ~ fmv, alpha ~ a++ Now, if we unified alpha := fmv, we'd get+ [WD] F fmv ~ fmv, [WD] fmv ~ a+ And now we are stuck.++So instead the Fmv Orientation Invariant puts te fmv on the+left, giving+ [WD] fmv ~ alpha, [WD] F alpha ~ fmv, [WD] alpha ~ a++ Now we get alpha:=a, and everything works out++Note [Prevent unification with type families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We prevent unification with type families because of an uneasy compromise.+It's perfectly sound to unify with type families, and it even improves the+error messages in the testsuite. It also modestly improves performance, at+least in some cases. But it's disastrous for test case perf/compiler/T3064.+Here is the problem: Suppose we have (F ty) where we also have [G] F ty ~ a.+What do we do? Do we reduce F? Or do we use the given? Hard to know what's+best. GHC reduces. This is a disaster for T3064, where the type's size+spirals out of control during reduction. (We're not helped by the fact that+the flattener re-flattens all the arguments every time around.) If we prevent+unification with type families, then the solver happens to use the equality+before expanding the type family.++It would be lovely in the future to revisit this problem and remove this+extra, unnecessary check. But we retain it for now as it seems to work+better in practice.++Note [Refactoring hazard: checkTauTvUpdate]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+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]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Generally speaking we try to update a variable with type synonyms not+expanded, which improves later error messages, unless looking+inside a type synonym may help resolve a spurious occurs check+error. Consider:+ type A a = ()++ f :: (A a -> a -> ()) -> ()+ f = \ _ -> ()++ x :: ()+ x = f (\ x p -> p x)++We will eventually get a constraint of the form t ~ A t. The ok function above will+properly expand the type (A t) to just (), which is ok to be unified with t. If we had+unified with the original type A t, we would lead the type checker into an infinite loop.++Hence, if the occurs check fails for a type synonym application, then (and *only* then),+the ok function expands the synonym to detect opportunities for occurs check success using+the underlying definition of the type synonym.++The same applies later on in the constraint interaction code; see TcInteract,+function @occ_check_ok@.++Note [Non-TcTyVars in TcUnify]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because the same code is now shared between unifying types and unifying+kinds, we sometimes will see proper TyVars floating around the unifier.+Example (from test case polykinds/PolyKinds12):++ type family Apply (f :: k1 -> k2) (x :: k1) :: k2+ type instance Apply g y = g y++When checking the instance declaration, we first *kind-check* the LHS+and RHS, discovering that the instance really should be++ type instance Apply k3 k4 (g :: k3 -> k4) (y :: k3) = g y++During this kind-checking, all the tyvars will be TcTyVars. Then, however,+as a second pass, we desugar the RHS (which is done in functions prefixed+with "tc" in TcTyClsDecls"). By this time, all the kind-vars are proper+TyVars, not TcTyVars, get some kind unification must happen.++Thus, we always check if a TyVar is a TcTyVar before asking if it's a+meta-tyvar.++This used to not be necessary for type-checking (that is, before * :: *)+because expressions get desugared via an algorithm separate from+type-checking (with wrappers, etc.). Types get desugared very differently,+causing this wibble in behavior seen here.+-}++data LookupTyVarResult -- The result of a lookupTcTyVar call+ = Unfilled TcTyVarDetails -- SkolemTv or virgin MetaTv+ | Filled TcType++lookupTcTyVar :: TcTyVar -> TcM LookupTyVarResult+lookupTcTyVar tyvar+ | MetaTv { mtv_ref = ref } <- details+ = do { meta_details <- readMutVar ref+ ; case meta_details of+ Indirect ty -> return (Filled ty)+ Flexi -> do { is_touchable <- isTouchableTcM tyvar+ -- Note [Unifying untouchables]+ ; if is_touchable then+ return (Unfilled details)+ else+ return (Unfilled vanillaSkolemTv) } }+ | otherwise+ = return (Unfilled details)+ where+ details = tcTyVarDetails tyvar++-- | Fill in a meta-tyvar+updateMeta :: TcTyVar -- ^ tv to fill in, tv :: k1+ -> TcType -- ^ ty2 :: k2+ -> Coercion -- ^ kind_co :: k2 ~N k1+ -> TcM Coercion -- ^ :: tv ~N ty2 (= ty2 |> kind_co ~N ty2)+updateMeta tv1 ty2 kind_co+ = do { let ty2' = ty2 `mkCastTy` kind_co+ ty2_refl = mkNomReflCo ty2+ co = mkCoherenceLeftCo ty2_refl kind_co+ ; writeMetaTyVar tv1 ty2'+ ; return co }++{-+Note [Unifying untouchables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We treat an untouchable type variable as if it was a skolem. That+ensures it won't unify with anything. It's a slight had, because+we return a made-up TcTyVarDetails, but I think it works smoothly.+-}++-- | Breaks apart a function kind into its pieces.+matchExpectedFunKind :: Arity -- ^ # of args remaining, only for errors+ -> TcType -- ^ type, only for errors+ -> TcKind -- ^ function kind+ -> TcM (Coercion, TcKind, TcKind)+ -- ^ co :: old_kind ~ arg -> res+matchExpectedFunKind num_args_remaining ty = go+ where+ go k | Just k' <- tcView k = go k'++ go k@(TyVarTy kvar)+ | isTcTyVar kvar, isMetaTyVar kvar+ = do { maybe_kind <- readMetaTyVar kvar+ ; case maybe_kind of+ Indirect fun_kind -> go fun_kind+ Flexi -> defer k }++ go k@(FunTy arg res) = return (mkNomReflCo k, arg, res)+ go other = defer other++ defer k+ = do { arg_kind <- newMetaKindVar+ ; res_kind <- newMetaKindVar+ ; let new_fun = mkFunTy arg_kind res_kind+ thing = mkTypeErrorThingArgs ty num_args_remaining+ origin = TypeEqOrigin { uo_actual = k+ , uo_expected = new_fun+ , uo_thing = Just thing+ }+ ; co <- uType origin KindLevel k new_fun+ ; return (co, arg_kind, res_kind) }+++{- *********************************************************************+* *+ Occurrence checking+* *+********************************************************************* -}+++{- Note [Occurs check expansion]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+(occurCheckExpand tv xi) expands synonyms in xi just enough to get rid+of occurrences of tv outside type function arguments, if that is+possible; otherwise, it returns Nothing.++For example, suppose we have+ type F a b = [a]+Then+ occCheckExpand b (F Int b) = Just [Int]+but+ occCheckExpand a (F a Int) = Nothing++We don't promise to do the absolute minimum amount of expanding+necessary, but we try not to do expansions we don't need to. We+prefer doing inner expansions first. For example,+ type F a b = (a, Int, a, [a])+ type G b = Char+We have+ occCheckExpand b (F (G b)) = Just (F Char)+even though we could also expand F to get rid of b.++The two variants of the function are to support TcUnify.checkTauTvUpdate,+which wants to prevent unification with type families. For more on this+point, see Note [Prevent unification with type families] in TcUnify.++Note [Occurrence checking: look inside kinds]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we are considering unifying+ (alpha :: *) ~ Int -> (beta :: alpha -> alpha)+This may be an error (what is that alpha doing inside beta's kind?),+but we must not make the mistake of actuallyy unifying or we'll+build an infinite data structure. So when looking for occurrences+of alpha in the rhs, we must look in the kinds of type variables+that occur there.++NB: we may be able to remove the problem via expansion; see+ Note [Occurs check expansion]. So we have to try that.++Note [Checking for foralls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Unless we have -XImpredicativeTypes (which is a totally unsupported+feature), we do not want to unify+ alpha ~ (forall a. a->a) -> Int+So we look for foralls hidden inside the type, and it's convenient+to do that at the same time as the occurs check (which looks for+occurrences of alpha).++However, it's not just a question of looking for foralls /anywhere/!+Consider+ (alpha :: forall k. k->*) ~ (beta :: forall k. k->*)+This is legal; e.g. dependent/should_compile/T11635.++We don't want to reject it because of the forall in beta's kind,+but (see Note [Occurrence checking: look inside kinds]) we do+need to look in beta's kind. So we carry a flag saying if a 'forall'+is OK, and sitch the flag on when stepping inside a kind.++Why is it OK? Why does it not count as impredicative polymorphism?+The reason foralls are bad is because we reply on "seeing" foralls+when doing implicit instantiation. But the forall inside the kind is+fine. We'll generate a kind equality constraint+ (forall k. k->*) ~ (forall k. k->*)+to check that the kinds of lhs and rhs are compatible. If alpha's+kind had instead been+ (alpha :: kappa)+then this kind equality would rightly complain about unifying kappa+with (forall k. k->*)++-}++data OccCheckResult a+ = OC_OK a+ | OC_Bad -- Forall or type family+ | OC_Occurs++instance Functor OccCheckResult where+ fmap = liftM++instance Applicative OccCheckResult where+ pure = OC_OK+ (<*>) = ap++instance Monad OccCheckResult where+ OC_OK x >>= k = k x+ OC_Bad >>= _ = OC_Bad+ OC_Occurs >>= _ = OC_Occurs++occCheckForErrors :: DynFlags -> TcTyVar -> Type -> OccCheckResult ()+-- Just for error-message generation; so we return OccCheckResult+-- so the caller can report the right kind of error+-- Check whether+-- a) the given variable occurs in the given type.+-- b) there is a forall in the type (unless we have -XImpredicativeTypes)+occCheckForErrors dflags tv ty+ = case preCheck dflags True tv ty of+ OC_OK _ -> OC_OK ()+ OC_Bad -> OC_Bad+ OC_Occurs -> case occCheckExpand tv ty of+ Nothing -> OC_Occurs+ Just _ -> OC_OK ()++----------------+metaTyVarUpdateOK :: DynFlags+ -> TcTyVar -- tv :: k1+ -> TcType -- ty :: k2+ -> Maybe TcType -- possibly-expanded ty+-- (metaTyFVarUpdateOK tv ty)+-- We are about to update the meta-tyvar tv with ty+-- Check (a) that tv doesn't occur in ty (occurs check)+-- (b) that ty does not have any foralls+-- (in the impredicative case), or type functions+--+-- We have two possible outcomes:+-- (1) Return the type to update the type variable with,+-- [we know the update is ok]+-- (2) Return Nothing,+-- [the update might be dodgy]+--+-- Note that "Nothing" does not mean "definite error". For example+-- type family F a+-- type instance F Int = Int+-- consider+-- a ~ F a+-- This is perfectly reasonable, if we later get a ~ Int. For now, though,+-- we return Nothing, leaving it to the later constraint simplifier to+-- sort matters out.+--+-- See Note [Refactoring hazard: checkTauTvUpdate]++metaTyVarUpdateOK dflags tv ty+ = case preCheck dflags False tv ty of+ -- False <=> type families not ok+ -- See Note [Prevent unification with type families]+ OC_OK _ -> Just ty+ OC_Bad -> Nothing -- forall or type function+ OC_Occurs -> occCheckExpand tv ty++preCheck :: DynFlags -> Bool -> TcTyVar -> TcType -> OccCheckResult ()+-- A quick check for+-- (a) a forall type (unless -XImpredivativeTypes)+-- (b) a type family+-- (c) an occurrence of the type variable (occurs check)+--+-- For (a) and (b) we check only the top level of the type, NOT+-- inside the kinds of variables it mentions. But for (c) we do+-- look in the kinds of course.++preCheck dflags ty_fam_ok tv ty+ = fast_check ty+ where+ details = tcTyVarDetails tv+ impredicative_ok = canUnifyWithPolyType dflags details++ ok :: OccCheckResult ()+ ok = OC_OK ()++ fast_check :: TcType -> OccCheckResult ()+ fast_check (TyVarTy tv')+ | tv == tv' = OC_Occurs+ | otherwise = fast_check_occ (tyVarKind tv')+ -- See Note [Occurrence checking: look inside kinds]++ fast_check (TyConApp tc tys)+ | bad_tc tc = OC_Bad+ | otherwise = mapM fast_check tys >> ok+ fast_check (LitTy {}) = ok+ fast_check (FunTy a r) = fast_check a >> fast_check r+ fast_check (AppTy fun arg) = fast_check fun >> fast_check arg+ fast_check (CastTy ty co) = fast_check ty >> fast_check_co co+ fast_check (CoercionTy co) = fast_check_co co+ fast_check (ForAllTy (TvBndr tv' _) ty)+ | not impredicative_ok = OC_Bad+ | tv == tv' = ok+ | otherwise = do { fast_check_occ (tyVarKind tv')+ ; fast_check_occ ty }+ -- Under a forall we look only for occurrences of+ -- the type variable++ -- For kinds, we only do an occurs check; we do not worry+ -- about type families or foralls+ -- See Note [Checking for foralls]+ fast_check_occ k | tv `elemVarSet` tyCoVarsOfType k = OC_Occurs+ | otherwise = ok++ -- For coercions, we are only doing an occurs check here;+ -- no bother about impredicativity in coercions, as they're+ -- inferred+ fast_check_co co | tv `elemVarSet` tyCoVarsOfCo co = OC_Occurs+ | otherwise = ok++ bad_tc :: TyCon -> Bool+ bad_tc tc+ | not (impredicative_ok || isTauTyCon tc) = True+ | not (ty_fam_ok || isFamFreeTyCon tc) = True+ | otherwise = False++occCheckExpand :: TcTyVar -> TcType -> Maybe TcType+-- See Note [Occurs check expansion]+-- We may have needed to do some type synonym unfolding in order to+-- get rid of the variable (or forall), so we also return the unfolded+-- version of the type, which is guaranteed to be syntactically free+-- of the given type variable. If the type is already syntactically+-- free of the variable, then the same type is returned.+occCheckExpand tv ty+ = go emptyVarEnv ty+ where+ go :: VarEnv TyVar -> Type -> Maybe Type+ -- The VarEnv carries mappings necessary+ -- because of kind expansion+ go env (TyVarTy tv')+ | tv == tv' = Nothing+ | Just tv'' <- lookupVarEnv env tv' = return (mkTyVarTy tv'')+ | otherwise = do { k' <- go env (tyVarKind tv')+ ; return (mkTyVarTy $+ setTyVarKind tv' k') }+ -- See Note [Occurrence checking: look inside kinds]++ go _ ty@(LitTy {}) = return ty+ go env (AppTy ty1 ty2) = do { ty1' <- go env ty1+ ; ty2' <- go env ty2+ ; return (mkAppTy ty1' ty2') }+ go env (FunTy ty1 ty2) = do { ty1' <- go env ty1+ ; ty2' <- go env ty2+ ; return (mkFunTy ty1' ty2') }+ go env ty@(ForAllTy (TvBndr tv' vis) body_ty)+ | tv == tv' = return ty+ | otherwise = do { ki' <- go env (tyVarKind tv')+ ; let tv'' = setTyVarKind tv' ki'+ env' = extendVarEnv env tv' tv''+ ; body' <- go env' body_ty+ ; return (ForAllTy (TvBndr tv'' vis) body') }++ -- For a type constructor application, first try expanding away the+ -- offending variable from the arguments. If that doesn't work, next+ -- see if the type constructor is a type synonym, and if so, expand+ -- it and try again.+ go env ty@(TyConApp tc tys)+ = case mapM (go env) tys of+ Just tys' -> return (mkTyConApp tc tys')+ Nothing | Just ty' <- tcView ty -> go env ty'+ | otherwise -> Nothing+ -- Failing that, try to expand a synonym++ go env (CastTy ty co) = do { ty' <- go env ty+ ; co' <- go_co env co+ ; return (mkCastTy ty' co') }+ go env (CoercionTy co) = do { co' <- go_co env co+ ; return (mkCoercionTy co') }++ ------------------+ go_co env (Refl r ty) = do { ty' <- go env ty+ ; return (mkReflCo r ty') }+ -- Note: Coercions do not contain type synonyms+ go_co env (TyConAppCo r tc args) = do { args' <- mapM (go_co env) args+ ; return (mkTyConAppCo r tc args') }+ go_co env (AppCo co arg) = do { co' <- go_co env co+ ; arg' <- go_co env arg+ ; return (mkAppCo co' arg') }+ go_co env co@(ForAllCo tv' kind_co body_co)+ | tv == tv' = return co+ | otherwise = do { kind_co' <- go_co env kind_co+ ; let tv'' = setTyVarKind tv' $+ pFst (coercionKind kind_co')+ env' = extendVarEnv env tv' tv''+ ; body' <- go_co env' body_co+ ; return (ForAllCo tv'' kind_co' body') }+ go_co env (FunCo r co1 co2) = do { co1' <- go_co env co1+ ; co2' <- go_co env co2+ ; return (mkFunCo r co1' co2') }+ go_co env (CoVarCo c) = do { k' <- go env (varType c)+ ; return (mkCoVarCo (setVarType c k')) }+ go_co env (AxiomInstCo ax ind args) = do { args' <- mapM (go_co env) args+ ; return (mkAxiomInstCo ax ind args') }+ go_co env (UnivCo p r ty1 ty2) = do { p' <- go_prov env p+ ; ty1' <- go env ty1+ ; ty2' <- go env ty2+ ; return (mkUnivCo p' r ty1' ty2') }+ go_co env (SymCo co) = do { co' <- go_co env co+ ; return (mkSymCo co') }+ go_co env (TransCo co1 co2) = do { co1' <- go_co env co1+ ; co2' <- go_co env co2+ ; return (mkTransCo co1' co2') }+ go_co env (NthCo n co) = do { co' <- go_co env co+ ; return (mkNthCo n co') }+ go_co env (LRCo lr co) = do { co' <- go_co env co+ ; return (mkLRCo lr co') }+ go_co env (InstCo co arg) = do { co' <- go_co env co+ ; arg' <- go_co env arg+ ; return (mkInstCo co' arg') }+ go_co env (CoherenceCo co1 co2) = do { co1' <- go_co env co1+ ; co2' <- go_co env co2+ ; return (mkCoherenceCo co1' co2') }+ go_co env (KindCo co) = do { co' <- go_co env co+ ; return (mkKindCo co') }+ go_co env (SubCo co) = do { co' <- go_co env co+ ; return (mkSubCo co') }+ go_co env (AxiomRuleCo ax cs) = do { cs' <- mapM (go_co env) cs+ ; return (mkAxiomRuleCo ax cs') }++ ------------------+ go_prov _ UnsafeCoerceProv = return UnsafeCoerceProv+ go_prov env (PhantomProv co) = PhantomProv <$> go_co env co+ go_prov env (ProofIrrelProv co) = ProofIrrelProv <$> go_co env co+ go_prov _ p@(PluginProv _) = return p+ go_prov _ p@(HoleProv _) = return p++canUnifyWithPolyType :: DynFlags -> TcTyVarDetails -> Bool+canUnifyWithPolyType dflags details+ = case details of+ MetaTv { mtv_info = SigTv } -> False+ MetaTv { mtv_info = TauTv } -> xopt LangExt.ImpredicativeTypes dflags+ _other -> True+ -- We can have non-meta tyvars in given constraints
+ typecheck/TcUnify.hs-boot view
@@ -0,0 +1,14 @@+module TcUnify where+import TcType ( TcTauType )+import TcRnTypes ( TcM )+import TcEvidence ( TcCoercion )+import Outputable ( Outputable )+import HsExpr ( HsExpr )+import Name ( Name )++-- This boot file exists only to tie the knot between+-- TcUnify and Inst++unifyType :: Outputable a => Maybe a -> TcTauType -> TcTauType -> TcM TcCoercion+unifyKind :: Outputable a => Maybe a -> TcTauType -> TcTauType -> TcM TcCoercion+noThing :: Maybe (HsExpr Name)
+ typecheck/TcValidity.hs view
@@ -0,0 +1,2040 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++{-# LANGUAGE CPP, TupleSections, ViewPatterns #-}++module TcValidity (+ Rank, UserTypeCtxt(..), checkValidType, checkValidMonoType,+ ContextKind(..), expectedKindInCtxt,+ checkValidTheta, checkValidFamPats,+ checkValidInstance, validDerivPred,+ checkInstTermination, checkTySynRhs,+ ClsInstInfo, checkValidCoAxiom, checkValidCoAxBranch,+ checkValidTyFamEqn,+ arityErr, badATErr,+ checkValidTelescope, checkZonkValidTelescope, checkValidInferredKinds,+ allDistinctTyVars+ ) where++#include "HsVersions.h"++import Maybes++-- friends:+import TcUnify ( tcSubType_NC )+import TcSimplify ( simplifyAmbiguityCheck )+import TyCoRep+import TcType hiding ( sizeType, sizeTypes )+import TcMType+import PrelNames+import Type+import Coercion+import Kind+import CoAxiom+import Class+import TyCon++-- others:+import HsSyn -- HsType+import TcRnMonad -- TcType, amongst others+import TcEnv ( tcGetInstEnvs )+import FunDeps+import InstEnv ( InstMatch, lookupInstEnv )+import FamInstEnv ( isDominatedBy, injectiveBranches,+ InjectivityCheckResult(..) )+import FamInst ( makeInjectivityErrors )+import Name+import VarEnv+import VarSet+import UniqSet+import Var ( TyVarBndr(..), mkTyVar )+import ErrUtils+import DynFlags+import Util+import ListSetOps+import SrcLoc+import Outputable+import BasicTypes+import Module+import Unique ( mkAlphaTyVarUnique )+import qualified GHC.LanguageExtensions as LangExt++import Control.Monad+import Data.List ( (\\) )++{-+************************************************************************+* *+ Checking for ambiguity+* *+************************************************************************++Note [The ambiguity check for type signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+checkAmbiguity is a check on *user-supplied type signatures*. It is+*purely* there to report functions that cannot possibly be called. So for+example we want to reject:+ f :: C a => Int+The idea is there can be no legal calls to 'f' because every call will+give rise to an ambiguous constraint. We could soundly omit the+ambiguity check on type signatures entirely, at the expense of+delaying ambiguity errors to call sites. Indeed, the flag+-XAllowAmbiguousTypes switches off the ambiguity check.++What about things like this:+ class D a b | a -> b where ..+ h :: D Int b => Int+The Int may well fix 'b' at the call site, so that signature should+not be rejected. Moreover, using *visible* fundeps is too+conservative. Consider+ class X a b where ...+ class D a b | a -> b where ...+ instance D a b => X [a] b where...+ h :: X a b => a -> a+Here h's type looks ambiguous in 'b', but here's a legal call:+ ...(h [True])...+That gives rise to a (X [Bool] beta) constraint, and using the+instance means we need (D Bool beta) and that fixes 'beta' via D's+fundep!++Behind all these special cases there is a simple guiding principle.+Consider++ f :: <type>+ f = ...blah...++ g :: <type>+ g = f++You would think that the definition of g would surely typecheck!+After all f has exactly the same type, and g=f. But in fact f's type+is instantiated and the instantiated constraints are solved against+the originals, so in the case an ambiguous type it won't work.+Consider our earlier example f :: C a => Int. Then in g's definition,+we'll instantiate to (C alpha) and try to deduce (C alpha) from (C a),+and fail.++So in fact we use this as our *definition* of ambiguity. We use a+very similar test for *inferred* types, to ensure that they are+unambiguous. See Note [Impedance matching] in TcBinds.++This test is very conveniently implemented by calling+ tcSubType <type> <type>+This neatly takes account of the functional dependecy stuff above,+and implicit parameter (see Note [Implicit parameters and ambiguity]).+And this is what checkAmbiguity does.++What about this, though?+ g :: C [a] => Int+Is every call to 'g' ambiguous? After all, we might have+ instance C [a] where ...+at the call site. So maybe that type is ok! Indeed even f's+quintessentially ambiguous type might, just possibly be callable:+with -XFlexibleInstances we could have+ instance C a where ...+and now a call could be legal after all! Well, we'll reject this+unless the instance is available *here*.++Note [When to call checkAmbiguity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We call checkAmbiguity+ (a) on user-specified type signatures+ (b) in checkValidType++Conncerning (b), you might wonder about nested foralls. What about+ f :: forall b. (forall a. Eq a => b) -> b+The nested forall is ambiguous. Originally we called checkAmbiguity+in the forall case of check_type, but that had two bad consequences:+ * We got two error messages about (Eq b) in a nested forall like this:+ g :: forall a. Eq a => forall b. Eq b => a -> a+ * If we try to check for ambiguity of an nested forall like+ (forall a. Eq a => b), the implication constraint doesn't bind+ all the skolems, which results in "No skolem info" in error+ messages (see Trac #10432).++To avoid this, we call checkAmbiguity once, at the top, in checkValidType.+(I'm still a bit worried about unbound skolems when the type mentions+in-scope type variables.)++In fact, because of the co/contra-variance implemented in tcSubType,+this *does* catch function f above. too.++Concerning (a) the ambiguity check is only used for *user* types, not+for types coming from inteface files. The latter can legitimately+have ambiguous types. Example++ class S a where s :: a -> (Int,Int)+ instance S Char where s _ = (1,1)+ f:: S a => [a] -> Int -> (Int,Int)+ f (_::[a]) x = (a*x,b)+ where (a,b) = s (undefined::a)++Here the worker for f gets the type+ fw :: forall a. S a => Int -> (# Int, Int #)+++Note [Implicit parameters and ambiguity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Only a *class* predicate can give rise to ambiguity+An *implicit parameter* cannot. For example:+ foo :: (?x :: [a]) => Int+ foo = length ?x+is fine. The call site will supply a particular 'x'++Furthermore, the type variables fixed by an implicit parameter+propagate to the others. E.g.+ foo :: (Show a, ?x::[a]) => Int+ foo = show (?x++?x)+The type of foo looks ambiguous. But it isn't, because at a call site+we might have+ let ?x = 5::Int in foo+and all is well. In effect, implicit parameters are, well, parameters,+so we can take their type variables into account as part of the+"tau-tvs" stuff. This is done in the function 'FunDeps.grow'.+-}++checkAmbiguity :: UserTypeCtxt -> Type -> TcM ()+checkAmbiguity ctxt ty+ | wantAmbiguityCheck ctxt+ = do { traceTc "Ambiguity check for" (ppr ty)+ -- Solve the constraints eagerly because an ambiguous type+ -- can cause a cascade of further errors. Since the free+ -- tyvars are skolemised, we can safely use tcSimplifyTop+ ; allow_ambiguous <- xoptM LangExt.AllowAmbiguousTypes+ ; (_wrap, wanted) <- addErrCtxt (mk_msg allow_ambiguous) $+ captureConstraints $+ tcSubType_NC ctxt ty ty+ ; simplifyAmbiguityCheck ty wanted++ ; traceTc "Done ambiguity check for" (ppr ty) }++ | otherwise+ = return ()+ where+ mk_msg allow_ambiguous+ = vcat [ text "In the ambiguity check for" <+> what+ , ppUnless allow_ambiguous ambig_msg ]+ ambig_msg = text "To defer the ambiguity check to use sites, enable AllowAmbiguousTypes"+ what | Just n <- isSigMaybe ctxt = quotes (ppr n)+ | otherwise = pprUserTypeCtxt ctxt++wantAmbiguityCheck :: UserTypeCtxt -> Bool+wantAmbiguityCheck ctxt+ = case ctxt of -- See Note [When we don't check for ambiguity]+ GhciCtxt -> False+ TySynCtxt {} -> False+ _ -> True++checkUserTypeError :: Type -> TcM ()+-- Check to see if the type signature mentions "TypeError blah"+-- anywhere in it, and fail if so.+--+-- Very unsatisfactorily (Trac #11144) we need to tidy the type+-- because it may have come from an /inferred/ signature, not a+-- user-supplied one. This is really only a half-baked fix;+-- the other errors in checkValidType don't do tidying, and so+-- may give bad error messages when given an inferred type.+checkUserTypeError = check+ where+ check ty+ | Just msg <- userTypeError_maybe ty = fail_with msg+ | Just (_,ts) <- splitTyConApp_maybe ty = mapM_ check ts+ | Just (t1,t2) <- splitAppTy_maybe ty = check t1 >> check t2+ | Just (_,t1) <- splitForAllTy_maybe ty = check t1+ | otherwise = return ()++ fail_with msg = do { env0 <- tcInitTidyEnv+ ; let (env1, tidy_msg) = tidyOpenType env0 msg+ ; failWithTcM (env1, pprUserTypeErrorTy tidy_msg) }+++{- Note [When we don't check for ambiguity]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In a few places we do not want to check a user-specified type for ambiguity++* GhciCtxt: Allow ambiguous types in GHCi's :kind command+ E.g. type family T a :: * -- T :: forall k. k -> *+ Then :k T should work in GHCi, not complain that+ (T k) is ambiguous!++* TySynCtxt: type T a b = C a b => blah+ It may be that when we /use/ T, we'll give an 'a' or 'b' that somehow+ cure the ambiguity. So we defer the ambiguity check to the use site.++ There is also an implementation reason (Trac #11608). In the RHS of+ a type synonym we don't (currently) instantiate 'a' and 'b' with+ TcTyVars before calling checkValidType, so we get asertion failures+ from doing an ambiguity check on a type with TyVars in it. Fixing this+ would not be hard, but let's wait till there's a reason.+++************************************************************************+* *+ Checking validity of a user-defined type+* *+************************************************************************++When dealing with a user-written type, we first translate it from an HsType+to a Type, performing kind checking, and then check various things that should+be true about it. We don't want to perform these checks at the same time+as the initial translation because (a) they are unnecessary for interface-file+types and (b) when checking a mutually recursive group of type and class decls,+we can't "look" at the tycons/classes yet. Also, the checks are rather+diverse, and used to really mess up the other code.++One thing we check for is 'rank'.++ Rank 0: monotypes (no foralls)+ Rank 1: foralls at the front only, Rank 0 inside+ Rank 2: foralls at the front, Rank 1 on left of fn arrow,++ basic ::= tyvar | T basic ... basic++ r2 ::= forall tvs. cxt => r2a+ r2a ::= r1 -> r2a | basic+ r1 ::= forall tvs. cxt => r0+ r0 ::= r0 -> r0 | basic++Another thing is to check that type synonyms are saturated.+This might not necessarily show up in kind checking.+ type A i = i+ data T k = MkT (k Int)+ f :: T A -- BAD!+-}++checkValidType :: UserTypeCtxt -> Type -> TcM ()+-- Checks that a user-written type is valid for the given context+-- Assumes argument is fully zonked+-- Not used for instance decls; checkValidInstance instead+checkValidType ctxt ty+ = do { traceTc "checkValidType" (ppr ty <+> text "::" <+> ppr (typeKind ty))+ ; rankn_flag <- xoptM LangExt.RankNTypes+ ; impred_flag <- xoptM LangExt.ImpredicativeTypes+ ; let gen_rank :: Rank -> Rank+ gen_rank r | rankn_flag = ArbitraryRank+ | otherwise = r++ rank1 = gen_rank r1+ rank0 = gen_rank r0++ r0 = rankZeroMonoType+ r1 = LimitedRank True r0++ rank+ = case ctxt of+ DefaultDeclCtxt-> MustBeMonoType+ ResSigCtxt -> MustBeMonoType+ PatSigCtxt -> rank0+ RuleSigCtxt _ -> rank1+ TySynCtxt _ -> rank0++ ExprSigCtxt -> rank1+ TypeAppCtxt | impred_flag -> ArbitraryRank+ | otherwise -> tyConArgMonoType+ -- Normally, ImpredicativeTypes is handled in check_arg_type,+ -- but visible type applications don't go through there.+ -- So we do this check here.++ FunSigCtxt {} -> rank1+ InfSigCtxt _ -> ArbitraryRank -- Inferred type+ ConArgCtxt _ -> rank1 -- We are given the type of the entire+ -- constructor, hence rank 1+ PatSynCtxt _ -> rank1++ ForSigCtxt _ -> rank1+ SpecInstCtxt -> rank1+ ThBrackCtxt -> rank1+ GhciCtxt -> ArbitraryRank+ _ -> panic "checkValidType"+ -- Can't happen; not used for *user* sigs++ ; env <- tcInitOpenTidyEnv (tyCoVarsOfTypeList ty)++ -- Check the internal validity of the type itself+ ; check_type env ctxt rank ty++ ; checkUserTypeError ty++ -- Check for ambiguous types. See Note [When to call checkAmbiguity]+ -- NB: this will happen even for monotypes, but that should be cheap;+ -- and there may be nested foralls for the subtype test to examine+ ; checkAmbiguity ctxt ty++ ; traceTc "checkValidType done" (ppr ty <+> text "::" <+> ppr (typeKind ty)) }++checkValidMonoType :: Type -> TcM ()+-- Assumes argument is fully zonked+checkValidMonoType ty+ = do { env <- tcInitOpenTidyEnv (tyCoVarsOfTypeList ty)+ ; check_type env SigmaCtxt MustBeMonoType ty }++checkTySynRhs :: UserTypeCtxt -> TcType -> TcM ()+checkTySynRhs ctxt ty+ | returnsConstraintKind actual_kind+ = do { ck <- xoptM LangExt.ConstraintKinds+ ; if ck+ then when (isConstraintKind actual_kind)+ (do { dflags <- getDynFlags+ ; check_pred_ty emptyTidyEnv dflags ctxt ty })+ else addErrTcM (constraintSynErr emptyTidyEnv actual_kind) }++ | otherwise+ = return ()+ where+ actual_kind = typeKind ty++-- | The kind expected in a certain context.+data ContextKind = TheKind Kind -- ^ a specific kind+ | AnythingKind -- ^ any kind will do+ | OpenKind -- ^ something of the form @TYPE _@++-- Depending on the context, we might accept any kind (for instance, in a TH+-- splice), or only certain kinds (like in type signatures).+expectedKindInCtxt :: UserTypeCtxt -> ContextKind+expectedKindInCtxt (TySynCtxt _) = AnythingKind+expectedKindInCtxt ThBrackCtxt = AnythingKind+expectedKindInCtxt GhciCtxt = AnythingKind+-- The types in a 'default' decl can have varying kinds+-- See Note [Extended defaults]" in TcEnv+expectedKindInCtxt DefaultDeclCtxt = AnythingKind+expectedKindInCtxt TypeAppCtxt = AnythingKind+expectedKindInCtxt (ForSigCtxt _) = TheKind liftedTypeKind+expectedKindInCtxt InstDeclCtxt = TheKind constraintKind+expectedKindInCtxt SpecInstCtxt = TheKind constraintKind+expectedKindInCtxt _ = OpenKind++{-+Note [Higher rank types]+~~~~~~~~~~~~~~~~~~~~~~~~+Technically+ Int -> forall a. a->a+is still a rank-1 type, but it's not Haskell 98 (Trac #5957). So the+validity checker allow a forall after an arrow only if we allow it+before -- that is, with Rank2Types or RankNTypes+-}++data Rank = ArbitraryRank -- Any rank ok++ | LimitedRank -- Note [Higher rank types]+ Bool -- Forall ok at top+ Rank -- Use for function arguments++ | MonoType SDoc -- Monotype, with a suggestion of how it could be a polytype++ | MustBeMonoType -- Monotype regardless of flags+++rankZeroMonoType, tyConArgMonoType, synArgMonoType, constraintMonoType :: Rank+rankZeroMonoType = MonoType (text "Perhaps you intended to use RankNTypes or Rank2Types")+tyConArgMonoType = MonoType (text "GHC doesn't yet support impredicative polymorphism")+synArgMonoType = MonoType (text "Perhaps you intended to use LiberalTypeSynonyms")+constraintMonoType = MonoType (text "A constraint must be a monotype")++funArgResRank :: Rank -> (Rank, Rank) -- Function argument and result+funArgResRank (LimitedRank _ arg_rank) = (arg_rank, LimitedRank (forAllAllowed arg_rank) arg_rank)+funArgResRank other_rank = (other_rank, other_rank)++forAllAllowed :: Rank -> Bool+forAllAllowed ArbitraryRank = True+forAllAllowed (LimitedRank forall_ok _) = forall_ok+forAllAllowed _ = False++----------------------------------------+check_type :: TidyEnv -> UserTypeCtxt -> Rank -> Type -> TcM ()+-- The args say what the *type context* requires, independent+-- of *flag* settings. You test the flag settings at usage sites.+--+-- Rank is allowed rank for function args+-- Rank 0 means no for-alls anywhere++check_type env ctxt rank ty+ | not (null tvs && null theta)+ = do { traceTc "check_type" (ppr ty $$ ppr (forAllAllowed rank))+ ; checkTcM (forAllAllowed rank) (forAllTyErr env rank ty)+ -- Reject e.g. (Maybe (?x::Int => Int)),+ -- with a decent error message++ ; check_valid_theta env' SigmaCtxt theta+ -- Allow type T = ?x::Int => Int -> Int+ -- but not type T = ?x::Int++ ; check_type env' ctxt rank tau -- Allow foralls to right of arrow+ ; checkTcM (not (any (`elemVarSet` tyCoVarsOfType phi_kind) tvs))+ (forAllEscapeErr env' ty tau_kind)+ }+ where+ (tvs, theta, tau) = tcSplitSigmaTy ty+ tau_kind = typeKind tau+ (env', _) = tidyTyCoVarBndrs env tvs++ phi_kind | null theta = tau_kind+ | otherwise = liftedTypeKind+ -- If there are any constraints, the kind is *. (#11405)++check_type _ _ _ (TyVarTy _) = return ()++check_type env ctxt rank (FunTy arg_ty res_ty)+ = do { check_type env ctxt arg_rank arg_ty+ ; check_type env ctxt res_rank res_ty }+ where+ (arg_rank, res_rank) = funArgResRank rank++check_type env ctxt rank (AppTy ty1 ty2)+ = do { check_arg_type env ctxt rank ty1+ ; check_arg_type env ctxt rank ty2 }++check_type env ctxt rank ty@(TyConApp tc tys)+ | isTypeSynonymTyCon tc || isTypeFamilyTyCon tc+ = check_syn_tc_app env ctxt rank ty tc tys+ | isUnboxedTupleTyCon tc = check_ubx_tuple env ctxt ty tys+ | otherwise = mapM_ (check_arg_type env ctxt rank) tys++check_type _ _ _ (LitTy {}) = return ()++check_type env ctxt rank (CastTy ty _) = check_type env ctxt rank ty++check_type _ _ _ ty = pprPanic "check_type" (ppr ty)++----------------------------------------+check_syn_tc_app :: TidyEnv -> UserTypeCtxt -> Rank -> KindOrType+ -> TyCon -> [KindOrType] -> TcM ()+-- Used for type synonyms and type synonym families,+-- which must be saturated,+-- but not data families, which need not be saturated+check_syn_tc_app env ctxt rank ty tc tys+ | tc_arity <= length tys -- Saturated+ -- Check that the synonym has enough args+ -- This applies equally to open and closed synonyms+ -- It's OK to have an *over-applied* type synonym+ -- data Tree a b = ...+ -- type Foo a = Tree [a]+ -- f :: Foo a b -> ...+ = do { -- See Note [Liberal type synonyms]+ ; liberal <- xoptM LangExt.LiberalTypeSynonyms+ ; if not liberal || isTypeFamilyTyCon tc then+ -- For H98 and synonym families, do check the type args+ mapM_ check_arg tys++ else -- In the liberal case (only for closed syns), expand then check+ case tcView ty of+ Just ty' -> check_type env ctxt rank ty'+ Nothing -> pprPanic "check_tau_type" (ppr ty) }++ | GhciCtxt <- ctxt -- Accept under-saturated type synonyms in+ -- GHCi :kind commands; see Trac #7586+ = mapM_ check_arg tys++ | otherwise+ = failWithTc (tyConArityErr tc tys)+ where+ tc_arity = tyConArity tc+ check_arg | isTypeFamilyTyCon tc = check_arg_type env ctxt rank+ | otherwise = check_type env ctxt synArgMonoType++----------------------------------------+check_ubx_tuple :: TidyEnv -> UserTypeCtxt -> KindOrType+ -> [KindOrType] -> TcM ()+check_ubx_tuple env ctxt ty tys+ = do { ub_tuples_allowed <- xoptM LangExt.UnboxedTuples+ ; checkTcM ub_tuples_allowed (ubxArgTyErr env ty)++ ; impred <- xoptM LangExt.ImpredicativeTypes+ ; let rank' = if impred then ArbitraryRank else tyConArgMonoType+ -- c.f. check_arg_type+ -- However, args are allowed to be unlifted, or+ -- more unboxed tuples, so can't use check_arg_ty+ ; mapM_ (check_type env ctxt rank') tys }++----------------------------------------+check_arg_type :: TidyEnv -> UserTypeCtxt -> Rank -> KindOrType -> TcM ()+-- The sort of type that can instantiate a type variable,+-- or be the argument of a type constructor.+-- Not an unboxed tuple, but now *can* be a forall (since impredicativity)+-- Other unboxed types are very occasionally allowed as type+-- arguments depending on the kind of the type constructor+--+-- For example, we want to reject things like:+--+-- instance Ord a => Ord (forall s. T s a)+-- and+-- g :: T s (forall b.b)+--+-- NB: unboxed tuples can have polymorphic or unboxed args.+-- This happens in the workers for functions returning+-- product types with polymorphic components.+-- But not in user code.+-- Anyway, they are dealt with by a special case in check_tau_type++check_arg_type _ _ _ (CoercionTy {}) = return ()++check_arg_type env ctxt rank ty+ = do { impred <- xoptM LangExt.ImpredicativeTypes+ ; let rank' = case rank of -- Predictive => must be monotype+ MustBeMonoType -> MustBeMonoType -- Monotype, regardless+ _other | impred -> ArbitraryRank+ | otherwise -> tyConArgMonoType+ -- Make sure that MustBeMonoType is propagated,+ -- so that we don't suggest -XImpredicativeTypes in+ -- (Ord (forall a.a)) => a -> a+ -- and so that if it Must be a monotype, we check that it is!++ ; check_type env ctxt rank' ty }++----------------------------------------+forAllTyErr :: TidyEnv -> Rank -> Type -> (TidyEnv, SDoc)+forAllTyErr env rank ty+ = ( env+ , vcat [ hang herald 2 (ppr_tidy env ty)+ , suggestion ] )+ where+ (tvs, _theta, _tau) = tcSplitSigmaTy ty+ herald | null tvs = text "Illegal qualified type:"+ | otherwise = text "Illegal polymorphic type:"+ suggestion = case rank of+ LimitedRank {} -> text "Perhaps you intended to use RankNTypes or Rank2Types"+ MonoType d -> d+ _ -> Outputable.empty -- Polytype is always illegal++forAllEscapeErr :: TidyEnv -> Type -> Kind -> (TidyEnv, SDoc)+forAllEscapeErr env ty tau_kind+ = ( env+ , hang (vcat [ text "Quantified type's kind mentions quantified type variable"+ , text "(skolem escape)" ])+ 2 (vcat [ text " type:" <+> ppr_tidy env ty+ , text "of kind:" <+> ppr_tidy env tau_kind ]) )++ubxArgTyErr :: TidyEnv -> Type -> (TidyEnv, SDoc)+ubxArgTyErr env ty = (env, sep [text "Illegal unboxed tuple type as function argument:", ppr_tidy env ty])++{-+Note [Liberal type synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If -XLiberalTypeSynonyms is on, expand closed type synonyms *before*+doing validity checking. This allows us to instantiate a synonym defn+with a for-all type, or with a partially-applied type synonym.+ e.g. type T a b = a+ type S m = m ()+ f :: S (T Int)+Here, T is partially applied, so it's illegal in H98. But if you+expand S first, then T we get just+ f :: Int+which is fine.++IMPORTANT: suppose T is a type synonym. Then we must do validity+checking on an appliation (T ty1 ty2)++ *either* before expansion (i.e. check ty1, ty2)+ *or* after expansion (i.e. expand T ty1 ty2, and then check)+ BUT NOT BOTH++If we do both, we get exponential behaviour!!++ data TIACons1 i r c = c i ::: r c+ type TIACons2 t x = TIACons1 t (TIACons1 t x)+ type TIACons3 t x = TIACons2 t (TIACons1 t x)+ type TIACons4 t x = TIACons2 t (TIACons2 t x)+ type TIACons7 t x = TIACons4 t (TIACons3 t x)+++************************************************************************+* *+\subsection{Checking a theta or source type}+* *+************************************************************************++Note [Implicit parameters in instance decls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Implicit parameters _only_ allowed in type signatures; not in instance+decls, superclasses etc. The reason for not allowing implicit params in+instances is a bit subtle. If we allowed+ instance (?x::Int, Eq a) => Foo [a] where ...+then when we saw+ (e :: (?x::Int) => t)+it would be unclear how to discharge all the potential uses of the ?x+in e. For example, a constraint Foo [Int] might come out of e, and+applying the instance decl would show up two uses of ?x. Trac #8912.+-}++checkValidTheta :: UserTypeCtxt -> ThetaType -> TcM ()+-- Assumes argument is fully zonked+checkValidTheta ctxt theta+ = do { env <- tcInitOpenTidyEnv (tyCoVarsOfTypesList theta)+ ; addErrCtxtM (checkThetaCtxt ctxt theta) $+ check_valid_theta env ctxt theta }++-------------------------+check_valid_theta :: TidyEnv -> UserTypeCtxt -> [PredType] -> TcM ()+check_valid_theta _ _ []+ = return ()+check_valid_theta env ctxt theta+ = do { dflags <- getDynFlags+ ; warnTcM (Reason Opt_WarnDuplicateConstraints)+ (wopt Opt_WarnDuplicateConstraints dflags && notNull dups)+ (dupPredWarn env dups)+ ; traceTc "check_valid_theta" (ppr theta)+ ; mapM_ (check_pred_ty env dflags ctxt) theta }+ where+ (_,dups) = removeDups nonDetCmpType theta+ -- It's OK to use nonDetCmpType because dups only appears in the+ -- warning++-------------------------+{- Note [Validity checking for constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We look through constraint synonyms so that we can see the underlying+constraint(s). For example+ type Foo = ?x::Int+ instance Foo => C T+We should reject the instance because it has an implicit parameter in+the context.++But we record, in 'under_syn', whether we have looked under a synonym+to avoid requiring language extensions at the use site. Main example+(Trac #9838):++ {-# LANGUAGE ConstraintKinds #-}+ module A where+ type EqShow a = (Eq a, Show a)++ module B where+ import A+ foo :: EqShow a => a -> String++We don't want to require ConstraintKinds in module B.+-}++check_pred_ty :: TidyEnv -> DynFlags -> UserTypeCtxt -> PredType -> TcM ()+-- Check the validity of a predicate in a signature+-- See Note [Validity checking for constraints]+check_pred_ty env dflags ctxt pred+ = do { check_type env SigmaCtxt constraintMonoType pred+ ; check_pred_help False env dflags ctxt pred }++check_pred_help :: Bool -- True <=> under a type synonym+ -> TidyEnv+ -> DynFlags -> UserTypeCtxt+ -> PredType -> TcM ()+check_pred_help under_syn env dflags ctxt pred+ | Just pred' <- tcView pred -- Switch on under_syn when going under a+ -- synonym (Trac #9838, yuk)+ = check_pred_help True env dflags ctxt pred'+ | otherwise+ = case splitTyConApp_maybe pred of+ Just (tc, tys)+ | isTupleTyCon tc+ -> check_tuple_pred under_syn env dflags ctxt pred tys+ -- NB: this equality check must come first, because (~) is a class,+ -- too.+ | tc `hasKey` heqTyConKey ||+ tc `hasKey` eqTyConKey ||+ tc `hasKey` eqPrimTyConKey+ -> check_eq_pred env dflags pred tc tys+ | Just cls <- tyConClass_maybe tc+ -> check_class_pred env dflags ctxt pred cls tys -- Includes Coercible+ _ -> check_irred_pred under_syn env dflags ctxt pred++check_eq_pred :: TidyEnv -> DynFlags -> PredType -> TyCon -> [TcType] -> TcM ()+check_eq_pred env dflags pred tc tys+ = -- Equational constraints are valid in all contexts if type+ -- families are permitted+ do { checkTc (length tys == tyConArity tc) (tyConArityErr tc tys)+ ; checkTcM (xopt LangExt.TypeFamilies dflags+ || xopt LangExt.GADTs dflags)+ (eqPredTyErr env pred) }++check_tuple_pred :: Bool -> TidyEnv -> DynFlags -> UserTypeCtxt -> PredType -> [PredType] -> TcM ()+check_tuple_pred under_syn env dflags ctxt pred ts+ = do { -- See Note [ConstraintKinds in predicates]+ checkTcM (under_syn || xopt LangExt.ConstraintKinds dflags)+ (predTupleErr env pred)+ ; mapM_ (check_pred_help under_syn env dflags ctxt) ts }+ -- This case will not normally be executed because without+ -- -XConstraintKinds tuple types are only kind-checked as *++check_irred_pred :: Bool -> TidyEnv -> DynFlags -> UserTypeCtxt -> PredType -> TcM ()+check_irred_pred under_syn env dflags ctxt pred+ -- The predicate looks like (X t1 t2) or (x t1 t2) :: Constraint+ -- where X is a type function+ = do { -- If it looks like (x t1 t2), require ConstraintKinds+ -- see Note [ConstraintKinds in predicates]+ -- But (X t1 t2) is always ok because we just require ConstraintKinds+ -- at the definition site (Trac #9838)+ failIfTcM (not under_syn && not (xopt LangExt.ConstraintKinds dflags)+ && hasTyVarHead pred)+ (predIrredErr env pred)++ -- Make sure it is OK to have an irred pred in this context+ -- See Note [Irreducible predicates in superclasses]+ ; failIfTcM (is_superclass ctxt+ && not (xopt LangExt.UndecidableInstances dflags)+ && has_tyfun_head pred)+ (predSuperClassErr env pred) }+ where+ is_superclass ctxt = case ctxt of { ClassSCCtxt _ -> True; _ -> False }+ has_tyfun_head ty+ = case tcSplitTyConApp_maybe ty of+ Just (tc, _) -> isTypeFamilyTyCon tc+ Nothing -> False++{- Note [ConstraintKinds in predicates]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Don't check for -XConstraintKinds under a type synonym, because that+was done at the type synonym definition site; see Trac #9838+e.g. module A where+ type C a = (Eq a, Ix a) -- Needs -XConstraintKinds+ module B where+ import A+ f :: C a => a -> a -- Does *not* need -XConstraintKinds++Note [Irreducible predicates in superclasses]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Allowing type-family calls in class superclasses is somewhat dangerous+because we can write:++ type family Fooish x :: * -> Constraint+ type instance Fooish () = Foo+ class Fooish () a => Foo a where++This will cause the constraint simplifier to loop because every time we canonicalise a+(Foo a) class constraint we add a (Fooish () a) constraint which will be immediately+solved to add+canonicalise another (Foo a) constraint. -}++-------------------------+check_class_pred :: TidyEnv -> DynFlags -> UserTypeCtxt -> PredType -> Class -> [TcType] -> TcM ()+check_class_pred env dflags ctxt pred cls tys+ | isIPClass cls+ = do { check_arity+ ; checkTcM (okIPCtxt ctxt) (badIPPred env pred) }++ | otherwise+ = do { check_arity+ ; warn_simp <- woptM Opt_WarnSimplifiableClassConstraints+ ; when warn_simp check_simplifiable_class_constraint+ ; checkTcM arg_tys_ok (predTyVarErr env pred) }+ where+ check_arity = checkTc (classArity cls == length tys)+ (tyConArityErr (classTyCon cls) tys)++ -- Check the arguments of a class constraint+ flexible_contexts = xopt LangExt.FlexibleContexts dflags+ undecidable_ok = xopt LangExt.UndecidableInstances dflags+ arg_tys_ok = case ctxt of+ SpecInstCtxt -> True -- {-# SPECIALISE instance Eq (T Int) #-} is fine+ InstDeclCtxt -> checkValidClsArgs (flexible_contexts || undecidable_ok) cls tys+ -- Further checks on head and theta+ -- in checkInstTermination+ _ -> checkValidClsArgs flexible_contexts cls tys++ -- See Note [Simplifiable given constraints]+ check_simplifiable_class_constraint+ | xopt LangExt.MonoLocalBinds dflags+ = return ()+ | DataTyCtxt {} <- ctxt -- Don't do this check for the "stupid theta"+ = return () -- of a data type declaration+ | otherwise+ = do { envs <- tcGetInstEnvs+ ; case lookupInstEnv False envs cls tys of+ ([m], [], _) -> addWarnTc (Reason Opt_WarnSimplifiableClassConstraints)+ (simplifiable_constraint_warn m)+ _ -> return () }++ simplifiable_constraint_warn :: InstMatch -> SDoc+ simplifiable_constraint_warn (match, _)+ = vcat [ hang (text "The constraint" <+> quotes (ppr (tidyType env pred)))+ 2 (text "matches an instance declaration")+ , ppr match+ , hang (text "This makes type inference for inner bindings fragile;")+ 2 (text "either use MonoLocalBinds, or simplify it using the instance") ]++{- Note [Simplifiable given constraints]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A type signature like+ f :: Eq [(a,b)] => a -> b+is very fragile, for reasons described at length in TcInteract+Note [Instance and Given overlap]. As that Note discusses, for the+most part the clever stuff in TcInteract means that we don't use a+top-level instance if a local Given might fire, so there is no+fragility. But if we /infer/ the type of a local let-binding, things+can go wrong (Trac #11948 is an example, discussed in the Note).++So this warning is switched on only if we have NoMonoLocalBinds; in+that case the warning discourages users from writing simplifiable+class constraints.++The warning only fires if the constraint in the signature+matches the top-level instances in only one way, and with no+unifiers -- that is, under the same circumstances that+TcInteract.matchInstEnv fires an interaction with the top+level instances. For example (Trac #13526), consider++ instance {-# OVERLAPPABLE #-} Eq (T a) where ...+ instance Eq (T Char) where ..+ f :: Eq (T a) => ...++We don't want to complain about this, even though the context+(Eq (T a)) matches an instance, because the user may be+deliberately deferring the choice so that the Eq (T Char)+has a chance to fire when 'f' is called. And the fragility+only matters when there's a risk that the instance might+fire instead of the local 'given'; and there is no such+risk in this case. Just use the same rules as for instance+firing!+-}++-------------------------+okIPCtxt :: UserTypeCtxt -> Bool+ -- See Note [Implicit parameters in instance decls]+okIPCtxt (FunSigCtxt {}) = True+okIPCtxt (InfSigCtxt {}) = True+okIPCtxt ExprSigCtxt = True+okIPCtxt TypeAppCtxt = True+okIPCtxt PatSigCtxt = True+okIPCtxt ResSigCtxt = True+okIPCtxt GenSigCtxt = True+okIPCtxt (ConArgCtxt {}) = True+okIPCtxt (ForSigCtxt {}) = True -- ??+okIPCtxt ThBrackCtxt = True+okIPCtxt GhciCtxt = True+okIPCtxt SigmaCtxt = True+okIPCtxt (DataTyCtxt {}) = True+okIPCtxt (PatSynCtxt {}) = True+okIPCtxt (TySynCtxt {}) = True -- e.g. type Blah = ?x::Int+ -- Trac #11466++okIPCtxt (ClassSCCtxt {}) = False+okIPCtxt (InstDeclCtxt {}) = False+okIPCtxt (SpecInstCtxt {}) = False+okIPCtxt (RuleSigCtxt {}) = False+okIPCtxt DefaultDeclCtxt = False++{-+Note [Kind polymorphic type classes]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+MultiParam check:++ class C f where... -- C :: forall k. k -> Constraint+ instance C Maybe where...++ The dictionary gets type [C * Maybe] even if it's not a MultiParam+ type class.++Flexibility check:++ class C f where... -- C :: forall k. k -> Constraint+ data D a = D a+ instance C D where++ The dictionary gets type [C * (D *)]. IA0_TODO it should be+ generalized actually.+-}++checkThetaCtxt :: UserTypeCtxt -> ThetaType -> TidyEnv -> TcM (TidyEnv, SDoc)+checkThetaCtxt ctxt theta env+ = return ( env+ , vcat [ text "In the context:" <+> pprTheta (tidyTypes env theta)+ , text "While checking" <+> pprUserTypeCtxt ctxt ] )++eqPredTyErr, predTupleErr, predIrredErr, predSuperClassErr :: TidyEnv -> PredType -> (TidyEnv, SDoc)+eqPredTyErr env pred+ = ( env+ , text "Illegal equational constraint" <+> ppr_tidy env pred $$+ parens (text "Use GADTs or TypeFamilies to permit this") )+predTupleErr env pred+ = ( env+ , hang (text "Illegal tuple constraint:" <+> ppr_tidy env pred)+ 2 (parens constraintKindsMsg) )+predIrredErr env pred+ = ( env+ , hang (text "Illegal constraint:" <+> ppr_tidy env pred)+ 2 (parens constraintKindsMsg) )+predSuperClassErr env pred+ = ( env+ , hang (text "Illegal constraint" <+> quotes (ppr_tidy env pred)+ <+> text "in a superclass context")+ 2 (parens undecidableMsg) )++predTyVarErr :: TidyEnv -> PredType -> (TidyEnv, SDoc)+predTyVarErr env pred+ = (env+ , vcat [ hang (text "Non type-variable argument")+ 2 (text "in the constraint:" <+> ppr_tidy env pred)+ , parens (text "Use FlexibleContexts to permit this") ])++badIPPred :: TidyEnv -> PredType -> (TidyEnv, SDoc)+badIPPred env pred+ = ( env+ , text "Illegal implicit parameter" <+> quotes (ppr_tidy env pred) )++constraintSynErr :: TidyEnv -> Type -> (TidyEnv, SDoc)+constraintSynErr env kind+ = ( env+ , hang (text "Illegal constraint synonym of kind:" <+> quotes (ppr_tidy env kind))+ 2 (parens constraintKindsMsg) )++dupPredWarn :: TidyEnv -> [[PredType]] -> (TidyEnv, SDoc)+dupPredWarn env dups+ = ( env+ , text "Duplicate constraint" <> plural primaryDups <> text ":"+ <+> pprWithCommas (ppr_tidy env) primaryDups )+ where+ primaryDups = map head dups++tyConArityErr :: TyCon -> [TcType] -> SDoc+-- For type-constructor arity errors, be careful to report+-- the number of /visible/ arguments required and supplied,+-- ignoring the /invisible/ arguments, which the user does not see.+-- (e.g. Trac #10516)+tyConArityErr tc tks+ = arityErr (tyConFlavour tc) (tyConName tc)+ tc_type_arity tc_type_args+ where+ vis_tks = filterOutInvisibleTypes tc tks++ -- tc_type_arity = number of *type* args expected+ -- tc_type_args = number of *type* args encountered+ tc_type_arity = count isVisibleTyConBinder (tyConBinders tc)+ tc_type_args = length vis_tks++arityErr :: Outputable a => String -> a -> Int -> Int -> SDoc+arityErr what name n m+ = hsep [ text "The" <+> text what, quotes (ppr name), text "should have",+ n_arguments <> comma, text "but has been given",+ if m==0 then text "none" else int m]+ where+ n_arguments | n == 0 = text "no arguments"+ | n == 1 = text "1 argument"+ | True = hsep [int n, text "arguments"]++{-+************************************************************************+* *+\subsection{Checking for a decent instance head type}+* *+************************************************************************++@checkValidInstHead@ checks the type {\em and} its syntactic constraints:+it must normally look like: @instance Foo (Tycon a b c ...) ...@++The exceptions to this syntactic checking: (1)~if the @GlasgowExts@+flag is on, or (2)~the instance is imported (they must have been+compiled elsewhere). In these cases, we let them go through anyway.++We can also have instances for functions: @instance Foo (a -> b) ...@.+-}++checkValidInstHead :: UserTypeCtxt -> Class -> [Type] -> TcM ()+checkValidInstHead ctxt clas cls_args+ = do { dflags <- getDynFlags++ ; mod <- getModule+ ; checkTc (getUnique clas `notElem` abstractClassKeys ||+ nameModule (getName clas) == mod)+ (instTypeErr clas cls_args abstract_class_msg)++ ; when (clas `hasKey` hasFieldClassNameKey) $+ checkHasFieldInst clas cls_args++ -- Check language restrictions;+ -- but not for SPECIALISE instance pragmas+ ; let ty_args = filterOutInvisibleTypes (classTyCon clas) cls_args+ ; unless spec_inst_prag $+ do { checkTc (xopt LangExt.TypeSynonymInstances dflags ||+ all tcInstHeadTyNotSynonym ty_args)+ (instTypeErr clas cls_args head_type_synonym_msg)+ ; checkTc (xopt LangExt.FlexibleInstances dflags ||+ all tcInstHeadTyAppAllTyVars ty_args)+ (instTypeErr clas cls_args head_type_args_tyvars_msg)+ ; checkTc (xopt LangExt.MultiParamTypeClasses dflags ||+ length ty_args == 1 || -- Only count type arguments+ (xopt LangExt.NullaryTypeClasses dflags &&+ null ty_args))+ (instTypeErr clas cls_args head_one_type_msg) }++ ; mapM_ checkValidTypePat ty_args }+ where+ spec_inst_prag = case ctxt of { SpecInstCtxt -> True; _ -> False }++ head_type_synonym_msg = parens (+ text "All instance types must be of the form (T t1 ... tn)" $$+ text "where T is not a synonym." $$+ text "Use TypeSynonymInstances if you want to disable this.")++ head_type_args_tyvars_msg = parens (vcat [+ text "All instance types must be of the form (T a1 ... an)",+ text "where a1 ... an are *distinct type variables*,",+ text "and each type variable appears at most once in the instance head.",+ text "Use FlexibleInstances if you want to disable this."])++ head_one_type_msg = parens (+ text "Only one type can be given in an instance head." $$+ text "Use MultiParamTypeClasses if you want to allow more, or zero.")++ abstract_class_msg =+ text "Manual instances of this class are not permitted."++tcInstHeadTyNotSynonym :: Type -> Bool+-- Used in Haskell-98 mode, for the argument types of an instance head+-- These must not be type synonyms, but everywhere else type synonyms+-- are transparent, so we need a special function here+tcInstHeadTyNotSynonym ty+ = case ty of -- Do not use splitTyConApp,+ -- because that expands synonyms!+ TyConApp tc _ -> not (isTypeSynonymTyCon tc)+ _ -> True++tcInstHeadTyAppAllTyVars :: Type -> Bool+-- Used in Haskell-98 mode, for the argument types of an instance head+-- These must be a constructor applied to type variable arguments.+-- But we allow kind instantiations.+tcInstHeadTyAppAllTyVars ty+ | Just (tc, tys) <- tcSplitTyConApp_maybe (dropCasts ty)+ = ok (filterOutInvisibleTypes tc tys) -- avoid kinds++ | otherwise+ = False+ where+ -- Check that all the types are type variables,+ -- and that each is distinct+ ok tys = equalLength tvs tys && hasNoDups tvs+ where+ tvs = mapMaybe tcGetTyVar_maybe tys++dropCasts :: Type -> Type+-- See Note [Casts during validity checking]+-- This function can turn a well-kinded type into an ill-kinded+-- one, so I've kept it local to this module+-- To consider: drop only UnivCo(HoleProv) casts+dropCasts (CastTy ty _) = dropCasts ty+dropCasts (AppTy t1 t2) = mkAppTy (dropCasts t1) (dropCasts t2)+dropCasts (FunTy t1 t2) = mkFunTy (dropCasts t1) (dropCasts t2)+dropCasts (TyConApp tc tys) = mkTyConApp tc (map dropCasts tys)+dropCasts (ForAllTy b ty) = ForAllTy (dropCastsB b) (dropCasts ty)+dropCasts ty = ty -- LitTy, TyVarTy, CoercionTy++dropCastsB :: TyVarBinder -> TyVarBinder+dropCastsB b = b -- Don't bother in the kind of a forall++abstractClassKeys :: [Unique]+abstractClassKeys = [ heqTyConKey+ , eqTyConKey+ , coercibleTyConKey+ ] -- See Note [Equality class instances]++instTypeErr :: Class -> [Type] -> SDoc -> SDoc+instTypeErr cls tys msg+ = hang (hang (text "Illegal instance declaration for")+ 2 (quotes (pprClassPred cls tys)))+ 2 msg++-- | See Note [Validity checking of HasField instances]+checkHasFieldInst :: Class -> [Type] -> TcM ()+checkHasFieldInst cls tys@[_k_ty, x_ty, r_ty, _a_ty] =+ case splitTyConApp_maybe r_ty of+ Nothing -> whoops (text "Record data type must be specified")+ Just (tc, _)+ | isFamilyTyCon tc+ -> whoops (text "Record data type may not be a data family")+ | otherwise -> case isStrLitTy x_ty of+ Just lbl+ | isJust (lookupTyConFieldLabel lbl tc)+ -> whoops (ppr tc <+> text "already has a field"+ <+> quotes (ppr lbl))+ | otherwise -> return ()+ Nothing+ | null (tyConFieldLabels tc) -> return ()+ | otherwise -> whoops (ppr tc <+> text "has fields")+ where+ whoops = addErrTc . instTypeErr cls tys+checkHasFieldInst _ tys = pprPanic "checkHasFieldInst" (ppr tys)++{- Note [Casts during validity checking]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the (bogus)+ instance Eq Char#+We elaborate to 'Eq (Char# |> UnivCo(hole))' where the hole is an+insoluble equality constraint for * ~ #. We'll report the insoluble+constraint separately, but we don't want to *also* complain that Eq is+not applied to a type constructor. So we look gaily look through+CastTys here.++Another example: Eq (Either a). Then we actually get a cast in+the middle:+ Eq ((Either |> g) a)+++Note [Validity checking of HasField instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The HasField class has magic constraint solving behaviour (see Note+[HasField instances] in TcInteract). However, we permit users to+declare their own instances, provided they do not clash with the+built-in behaviour. In particular, we forbid:++ 1. `HasField _ r _` where r is a variable++ 2. `HasField _ (T ...) _` if T is a data family+ (because it might have fields introduced later)++ 3. `HasField x (T ...) _` where x is a variable,+ if T has any fields at all++ 4. `HasField "foo" (T ...) _` if T has a "foo" field++The usual functional dependency checks also apply.+++Note [Valid 'deriving' predicate]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+validDerivPred checks for OK 'deriving' context. See Note [Exotic+derived instance contexts] in TcDeriv. However the predicate is+here because it uses sizeTypes, fvTypes.++It checks for three things++ * No repeated variables (hasNoDups fvs)++ * No type constructors. This is done by comparing+ sizeTypes tys == length (fvTypes tys)+ sizeTypes counts variables and constructors; fvTypes returns variables.+ So if they are the same, there must be no constructors. But there+ might be applications thus (f (g x)).++ Note that tys only includes the visible arguments of the class type+ constructor. Including the non-vivisble arguments can cause the following,+ perfectly valid instance to be rejected:+ class Category (cat :: k -> k -> *) where ...+ newtype T (c :: * -> * -> *) a b = MkT (c a b)+ instance Category c => Category (T c) where ...+ since the first argument to Category is a non-visible *, which sizeTypes+ would count as a constructor! See Trac #11833.++ * Also check for a bizarre corner case, when the derived instance decl+ would look like+ instance C a b => D (T a) where ...+ Note that 'b' isn't a parameter of T. This gives rise to all sorts of+ problems; in particular, it's hard to compare solutions for equality+ when finding the fixpoint, and that means the inferContext loop does+ not converge. See Trac #5287.++Note [Equality class instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We can't have users writing instances for the equality classes. But we+still need to be able to write instances for them ourselves. So we allow+instances only in the defining module.++-}++validDerivPred :: TyVarSet -> PredType -> Bool+-- See Note [Valid 'deriving' predicate]+validDerivPred tv_set pred+ = case classifyPredType pred of+ ClassPred cls tys -> cls `hasKey` typeableClassKey+ -- Typeable constraints are bigger than they appear due+ -- to kind polymorphism, but that's OK+ || check_tys cls tys+ EqPred {} -> False -- reject equality constraints+ _ -> True -- Non-class predicates are ok+ where+ check_tys cls tys+ = hasNoDups fvs+ -- use sizePred to ignore implicit args+ && sizePred pred == fromIntegral (length fvs)+ && all (`elemVarSet` tv_set) fvs+ where tys' = filterOutInvisibleTypes (classTyCon cls) tys+ fvs = fvTypes tys'++{-+************************************************************************+* *+\subsection{Checking instance for termination}+* *+************************************************************************+-}++{- Note [Instances and constraint synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Currently, we don't allow instances for constraint synonyms at all.+Consider these (Trac #13267):+ type C1 a = Show (a -> Bool)+ instance C1 Int where -- I1+ show _ = "ur"++This elicits "show is not a (visible) method of class C1", which isn't+a great message. But it comes from the renamer, so it's hard to improve.++This needs a bit more care:+ type C2 a = (Show a, Show Int)+ instance C2 Int -- I2++If we use (splitTyConApp_maybe tau) in checkValidInstance to decompose+the instance head, we'll expand the synonym on fly, and it'll look like+ instance (%,%) (Show Int, Show Int)+and we /really/ don't want that. So we carefully do /not/ expand+synonyms, by matching on TyConApp directly.+-}++checkValidInstance :: UserTypeCtxt -> LHsSigType Name -> Type+ -> TcM ([TyVar], ThetaType, Class, [Type])+checkValidInstance ctxt hs_type ty+ | not is_tc_app+ = failWithTc (text "Instance head is not headed by a class")++ | isNothing mb_cls+ = failWithTc (vcat [ text "Illegal instance for a" <+> text (tyConFlavour tc)+ , text "A class instance must be for a class" ])++ | not arity_ok+ = failWithTc (text "Arity mis-match in instance head")++ | otherwise+ = do { setSrcSpan head_loc (checkValidInstHead ctxt clas inst_tys)+ ; traceTc "checkValidInstance {" (ppr ty)+ ; checkValidTheta ctxt theta++ -- The Termination and Coverate Conditions+ -- Check that instance inference will terminate (if we care)+ -- For Haskell 98 this will already have been done by checkValidTheta,+ -- but as we may be using other extensions we need to check.+ --+ -- Note that the Termination Condition is *more conservative* than+ -- the checkAmbiguity test we do on other type signatures+ -- e.g. Bar a => Bar Int is ambiguous, but it also fails+ -- the termination condition, because 'a' appears more often+ -- in the constraint than in the head+ ; undecidable_ok <- xoptM LangExt.UndecidableInstances+ ; if undecidable_ok+ then checkAmbiguity ctxt ty+ else checkInstTermination inst_tys theta++ ; traceTc "cvi 2" (ppr ty)++ ; case (checkInstCoverage undecidable_ok clas theta inst_tys) of+ IsValid -> return () -- Check succeeded+ NotValid msg -> addErrTc (instTypeErr clas inst_tys msg)++ ; traceTc "End checkValidInstance }" empty++ ; return (tvs, theta, clas, inst_tys) }+ where+ (tvs, theta, tau) = tcSplitSigmaTy ty+ is_tc_app = case tau of { TyConApp {} -> True; _ -> False }+ TyConApp tc inst_tys = tau -- See Note [Instances and constraint synonyms]+ mb_cls = tyConClass_maybe tc+ Just clas = mb_cls+ arity_ok = inst_tys `lengthIs` classArity clas++ -- The location of the "head" of the instance+ head_loc = getLoc (getLHsInstDeclHead hs_type)++{-+Note [Paterson conditions]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Termination test: the so-called "Paterson conditions" (see Section 5 of+"Understanding functional dependencies via Constraint Handling Rules,+JFP Jan 2007).++We check that each assertion in the context satisfies:+ (1) no variable has more occurrences in the assertion than in the head, and+ (2) the assertion has fewer constructors and variables (taken together+ and counting repetitions) than the head.+This is only needed with -fglasgow-exts, as Haskell 98 restrictions+(which have already been checked) guarantee termination.++The underlying idea is that++ for any ground substitution, each assertion in the+ context has fewer type constructors than the head.+-}++checkInstTermination :: [TcType] -> ThetaType -> TcM ()+-- See Note [Paterson conditions]+checkInstTermination tys theta+ = check_preds theta+ where+ head_fvs = fvTypes tys+ head_size = sizeTypes tys++ check_preds :: [PredType] -> TcM ()+ check_preds preds = mapM_ check preds++ check :: PredType -> TcM ()+ check pred+ = case classifyPredType pred of+ EqPred {} -> return () -- See Trac #4200.+ IrredPred {} -> check2 pred (sizeType pred)+ ClassPred cls tys+ | isTerminatingClass cls+ -> return ()++ | isCTupleClass cls -- Look inside tuple predicates; Trac #8359+ -> check_preds tys++ | otherwise+ -> check2 pred (sizeTypes $ filterOutInvisibleTypes (classTyCon cls) tys)+ -- Other ClassPreds++ check2 pred pred_size+ | not (null bad_tvs) = addErrTc (noMoreMsg bad_tvs what)+ | pred_size >= head_size = addErrTc (smallerMsg what)+ | otherwise = return ()+ where+ what = text "constraint" <+> quotes (ppr pred)+ bad_tvs = fvType pred \\ head_fvs++smallerMsg :: SDoc -> SDoc+smallerMsg what+ = vcat [ hang (text "The" <+> what)+ 2 (text "is no smaller than the instance head")+ , parens undecidableMsg ]++noMoreMsg :: [TcTyVar] -> SDoc -> SDoc+noMoreMsg tvs what+ = vcat [ hang (text "Variable" <> plural tvs <+> quotes (pprWithCommas ppr tvs)+ <+> occurs <+> text "more often")+ 2 (sep [ text "in the" <+> what+ , text "than in the instance head" ])+ , parens undecidableMsg ]+ where+ occurs = if isSingleton tvs then text "occurs"+ else text "occur"++undecidableMsg, constraintKindsMsg :: SDoc+undecidableMsg = text "Use UndecidableInstances to permit this"+constraintKindsMsg = text "Use ConstraintKinds to permit this"++{-+Note [Associated type instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We allow this:+ class C a where+ type T x a+ instance C Int where+ type T (S y) Int = y+ type T Z Int = Char++Note that+ a) The variable 'x' is not bound by the class decl+ b) 'x' is instantiated to a non-type-variable in the instance+ c) There are several type instance decls for T in the instance++All this is fine. Of course, you can't give any *more* instances+for (T ty Int) elsewhere, because it's an *associated* type.++Note [Checking consistent instantiation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See Trac #11450 for background discussion on this check.++ class C a b where+ type T a x b++With this class decl, if we have an instance decl+ instance C ty1 ty2 where ...+then the type instance must look like+ type T ty1 v ty2 = ...+with exactly 'ty1' for 'a', 'ty2' for 'b', and some type 'v' for 'x'.+For example:++ instance C [p] Int+ type T [p] y Int = (p,y,y)++Note that++* We used to allow completely different bound variables in the+ associated type instance; e.g.+ instance C [p] Int+ type T [q] y Int = ...+ But from GHC 8.2 onwards, we don't. It's much simpler this way.+ See Trac #11450.++* When the class variable isn't used on the RHS of the type instance,+ it's tempting to allow wildcards, thus+ instance C [p] Int+ type T [_] y Int = (y,y)+ But it's awkward to do the test, and it doesn't work if the+ variable is repeated:+ instance C (p,p) Int+ type T (_,_) y Int = (y,y)+ Even though 'p' is not used on the RHS, we still need to use 'p'+ on the LHS to establish the repeated pattern. So to keep it simple+ we just require equality.++* For variables in associated type families that are not bound by the class+ itself, we do _not_ check if they are over-specific. In other words,+ it's perfectly acceptable to have an instance like this:++ instance C [p] Int where+ type T [p] (Maybe x) Int = x++ While the first and third arguments to T are required to be exactly [p] and+ Int, respectively, since they are bound by C, the second argument is allowed+ to be more specific than just a type variable. Furthermore, it is permissible+ to define multiple equations for T that differ only in the non-class-bound+ argument:++ instance C [p] Int where+ type T [p] (Maybe x) Int = x+ type T [p] (Either x y) Int = x -> y++ We once considered requiring that non-class-bound variables in associated+ type family instances be instantiated with distinct type variables. However,+ that requirement proved too restrictive in practice, as there were examples+ of extremely simple associated type family instances that this check would+ reject, and fixing them required tiresome boilerplate in the form of+ auxiliary type families. For instance, you would have to define the above+ example as:++ instance C [p] Int where+ type T [p] x Int = CAux x++ type family CAux x where+ CAux (Maybe x) = x+ CAux (Either x y) = x -> y++ We decided that this restriction wasn't buying us much, so we opted not+ to pursue that design (see also GHC Trac #13398).++Implementation+ * Form the mini-envt from the class type variables a,b+ to the instance decl types [p],Int: [a->[p], b->Int]++ * Look at the tyvars a,x,b of the type family constructor T+ (it shares tyvars with the class C)++ * Apply the mini-evnt to them, and check that the result is+ consistent with the instance types [p] y Int. (where y can be any type, as+ it is not scoped over the class type variables.++We make all the instance type variables scope over the+type instances, of course, which picks up non-obvious kinds. Eg+ class Foo (a :: k) where+ type F a+ instance Foo (b :: k -> k) where+ type F b = Int+Here the instance is kind-indexed and really looks like+ type F (k->k) (b::k->k) = Int+But if the 'b' didn't scope, we would make F's instance too+poly-kinded.+-}++-- | Extra information about the parent instance declaration, needed+-- when type-checking associated types. The 'Class' is the enclosing+-- class, the [TyVar] are the type variable of the instance decl,+-- and and the @VarEnv Type@ maps class variables to their instance+-- types.+type ClsInstInfo = (Class, [TyVar], VarEnv Type)++type AssocInstArgShape = (Maybe Type, Type)+ -- AssocInstArgShape is used only for associated family instances+ -- (mb_exp, actual)+ -- mb_exp = Just ty => this arg corresponds to a class variable+ -- = Nothing => it doesn't correspond to a class variable+ -- e.g. class C b where+ -- type F a b c+ -- instance C [x] where+ -- type F p [x] q+ -- We get [AssocInstArgShape] = [ (Nothing, p)+ -- , (Just [x], [x])+ -- , (Nothing, q)]++checkConsistentFamInst+ :: Maybe ClsInstInfo+ -> TyCon -- ^ Family tycon+ -> [TyVar] -- ^ Type variables of the family instance+ -> [Type] -- ^ Type patterns from instance+ -> TcM ()+-- See Note [Checking consistent instantiation]++checkConsistentFamInst Nothing _ _ _ = return ()+checkConsistentFamInst (Just (clas, inst_tvs, mini_env)) fam_tc _at_tvs at_tys+ = do { -- Check that the associated type indeed comes from this class+ checkTc (Just clas == tyConAssoc_maybe fam_tc)+ (badATErr (className clas) (tyConName fam_tc))++ -- Check type args first (more comprehensible)+ ; checkTc (all check_arg type_shapes) pp_wrong_at_arg++ -- And now kind args+ ; checkTc (all check_arg kind_shapes)+ (pp_wrong_at_arg $$ ppSuggestExplicitKinds)++ ; traceTc "cfi" (vcat [ ppr inst_tvs+ , ppr arg_shapes+ , ppr mini_env ]) }+ where+ arg_shapes :: [AssocInstArgShape]+ arg_shapes = [ (lookupVarEnv mini_env fam_tc_tv, at_ty)+ | (fam_tc_tv, at_ty) <- tyConTyVars fam_tc `zip` at_tys ]++ (kind_shapes, type_shapes) = partitionInvisibles fam_tc snd arg_shapes++ check_arg :: AssocInstArgShape -> Bool+ check_arg (Just exp_ty, at_ty) = exp_ty `tcEqType` at_ty+ check_arg (Nothing, _ ) = True -- Arg position does not correspond+ -- to a class variable++ pp_wrong_at_arg+ = vcat [ text "Type indexes must match class instance head"+ , pp_exp_act ]++ pp_exp_act+ = vcat [ text "Expected:" <+> ppr (mkTyConApp fam_tc expected_args)+ , text " Actual:" <+> ppr (mkTyConApp fam_tc at_tys)+ , sdocWithDynFlags $ \dflags ->+ ppWhen (has_poly_args dflags) $+ vcat [ text "where the `<tv>' arguments are type variables,"+ , text "distinct from each other and from the instance variables" ] ]++ expected_args = [ exp_ty `orElse` mk_tv at_ty | (exp_ty, at_ty) <- arg_shapes ]+ mk_tv at_ty = mkTyVarTy (mkTyVar tv_name (typeKind at_ty))+ tv_name = mkInternalName (mkAlphaTyVarUnique 1) (mkTyVarOcc "<tv>") noSrcSpan++ has_poly_args dflags = any (isNothing . fst) shapes+ where+ shapes | gopt Opt_PrintExplicitKinds dflags = arg_shapes+ | otherwise = type_shapes++badATErr :: Name -> Name -> SDoc+badATErr clas op+ = hsep [text "Class", quotes (ppr clas),+ text "does not have an associated type", quotes (ppr op)]+++{-+************************************************************************+* *+ Checking type instance well-formedness and termination+* *+************************************************************************+-}++checkValidCoAxiom :: CoAxiom Branched -> TcM ()+checkValidCoAxiom ax@(CoAxiom { co_ax_tc = fam_tc, co_ax_branches = branches })+ = do { mapM_ (checkValidCoAxBranch Nothing fam_tc) branch_list+ ; foldlM_ check_branch_compat [] branch_list }+ where+ branch_list = fromBranches branches+ injectivity = familyTyConInjectivityInfo fam_tc++ check_branch_compat :: [CoAxBranch] -- previous branches in reverse order+ -> CoAxBranch -- current branch+ -> TcM [CoAxBranch]-- current branch : previous branches+ -- Check for+ -- (a) this branch is dominated by previous ones+ -- (b) failure of injectivity+ check_branch_compat prev_branches cur_branch+ | cur_branch `isDominatedBy` prev_branches+ = do { addWarnAt NoReason (coAxBranchSpan cur_branch) $+ inaccessibleCoAxBranch ax cur_branch+ ; return prev_branches }+ | otherwise+ = do { check_injectivity prev_branches cur_branch+ ; return (cur_branch : prev_branches) }++ -- Injectivity check: check whether a new (CoAxBranch) can extend+ -- already checked equations without violating injectivity+ -- annotation supplied by the user.+ -- See Note [Verifying injectivity annotation] in FamInstEnv+ check_injectivity prev_branches cur_branch+ | Injective inj <- injectivity+ = do { let conflicts =+ fst $ foldl (gather_conflicts inj prev_branches cur_branch)+ ([], 0) prev_branches+ ; mapM_ (\(err, span) -> setSrcSpan span $ addErr err)+ (makeInjectivityErrors ax cur_branch inj conflicts) }+ | otherwise+ = return ()++ gather_conflicts inj prev_branches cur_branch (acc, n) branch+ -- n is 0-based index of branch in prev_branches+ = case injectiveBranches inj cur_branch branch of+ InjectivityUnified ax1 ax2+ | ax1 `isDominatedBy` (replace_br prev_branches n ax2)+ -> (acc, n + 1)+ | otherwise+ -> (branch : acc, n + 1)+ InjectivityAccepted -> (acc, n + 1)++ -- Replace n-th element in the list. Assumes 0-based indexing.+ replace_br :: [CoAxBranch] -> Int -> CoAxBranch -> [CoAxBranch]+ replace_br brs n br = take n brs ++ [br] ++ drop (n+1) brs+++-- Check that a "type instance" is well-formed (which includes decidability+-- unless -XUndecidableInstances is given).+--+checkValidCoAxBranch :: Maybe ClsInstInfo+ -> TyCon -> CoAxBranch -> TcM ()+checkValidCoAxBranch mb_clsinfo fam_tc+ (CoAxBranch { cab_tvs = tvs, cab_cvs = cvs+ , cab_lhs = typats+ , cab_rhs = rhs, cab_loc = loc })+ = checkValidTyFamEqn mb_clsinfo fam_tc tvs cvs typats rhs loc++-- | Do validity checks on a type family equation, including consistency+-- with any enclosing class instance head, termination, and lack of+-- polytypes.+checkValidTyFamEqn :: Maybe ClsInstInfo+ -> TyCon -- ^ of the type family+ -> [TyVar] -- ^ bound tyvars in the equation+ -> [CoVar] -- ^ bound covars in the equation+ -> [Type] -- ^ type patterns+ -> Type -- ^ rhs+ -> SrcSpan+ -> TcM ()+checkValidTyFamEqn mb_clsinfo fam_tc tvs cvs typats rhs loc+ = setSrcSpan loc $+ do { checkValidFamPats mb_clsinfo fam_tc tvs cvs typats++ -- The argument patterns, and RHS, are all boxed tau types+ -- E.g Reject type family F (a :: k1) :: k2+ -- type instance F (forall a. a->a) = ...+ -- type instance F Int# = ...+ -- type instance F Int = forall a. a->a+ -- type instance F Int = Int#+ -- See Trac #9357+ ; checkValidMonoType rhs++ -- We have a decidable instance unless otherwise permitted+ ; undecidable_ok <- xoptM LangExt.UndecidableInstances+ ; unless undecidable_ok $+ mapM_ addErrTc (checkFamInstRhs typats (tcTyFamInsts rhs)) }++-- Make sure that each type family application is+-- (1) strictly smaller than the lhs,+-- (2) mentions no type variable more often than the lhs, and+-- (3) does not contain any further type family instances.+--+checkFamInstRhs :: [Type] -- lhs+ -> [(TyCon, [Type])] -- type family instances+ -> [MsgDoc]+checkFamInstRhs lhsTys famInsts+ = mapMaybe check famInsts+ where+ size = sizeTypes lhsTys+ fvs = fvTypes lhsTys+ check (tc, tys)+ | not (all isTyFamFree tys) = Just (nestedMsg what)+ | not (null bad_tvs) = Just (noMoreMsg bad_tvs what)+ | size <= sizeTypes tys = Just (smallerMsg what)+ | otherwise = Nothing+ where+ what = text "type family application" <+> quotes (pprType (TyConApp tc tys))+ bad_tvs = fvTypes tys \\ fvs++checkValidFamPats :: Maybe ClsInstInfo -> TyCon -> [TyVar] -> [CoVar] -> [Type] -> TcM ()+-- Patterns in a 'type instance' or 'data instance' decl should+-- a) contain no type family applications+-- (vanilla synonyms are fine, though)+-- b) properly bind all their free type variables+-- e.g. we disallow (Trac #7536)+-- type T a = Int+-- type instance F (T a) = a+-- c) Have the right number of patterns+-- d) For associated types, are consistently instantiated+checkValidFamPats mb_clsinfo fam_tc tvs cvs ty_pats+ = do { -- A family instance must have exactly the same number of type+ -- parameters as the family declaration. You can't write+ -- type family F a :: * -> *+ -- type instance F Int y = y+ -- because then the type (F Int) would be like (\y.y)+ checkTc (length ty_pats == fam_arity) $+ wrongNumberOfParmsErr (fam_arity - count isInvisibleTyConBinder fam_bndrs)+ -- report only explicit arguments++ ; mapM_ checkValidTypePat ty_pats++ ; let unbound_tcvs = filterOut (`elemVarSet` exactTyCoVarsOfTypes ty_pats) (tvs ++ cvs)+ ; checkTc (null unbound_tcvs) (famPatErr fam_tc unbound_tcvs ty_pats)++ -- Check that type patterns match the class instance head+ ; checkConsistentFamInst mb_clsinfo fam_tc tvs ty_pats }+ where+ fam_arity = tyConArity fam_tc+ fam_bndrs = tyConBinders fam_tc+++checkValidTypePat :: Type -> TcM ()+-- Used for type patterns in class instances,+-- and in type/data family instances+checkValidTypePat pat_ty+ = do { -- Check that pat_ty is a monotype+ checkValidMonoType pat_ty+ -- One could imagine generalising to allow+ -- instance C (forall a. a->a)+ -- but we don't know what all the consequences might be++ -- Ensure that no type family instances occur a type pattern+ ; checkTc (isTyFamFree pat_ty) $+ tyFamInstIllegalErr pat_ty }++isTyFamFree :: Type -> Bool+-- ^ Check that a type does not contain any type family applications.+isTyFamFree = null . tcTyFamInsts++-- Error messages++wrongNumberOfParmsErr :: Arity -> SDoc+wrongNumberOfParmsErr exp_arity+ = text "Number of parameters must match family declaration; expected"+ <+> ppr exp_arity++inaccessibleCoAxBranch :: CoAxiom br -> CoAxBranch -> SDoc+inaccessibleCoAxBranch fi_ax cur_branch+ = text "Type family instance equation is overlapped:" $$+ nest 2 (pprCoAxBranch fi_ax cur_branch)++tyFamInstIllegalErr :: Type -> SDoc+tyFamInstIllegalErr ty+ = hang (text "Illegal type synonym family application in instance" <>+ colon) 2 $+ ppr ty++nestedMsg :: SDoc -> SDoc+nestedMsg what+ = sep [ text "Illegal nested" <+> what+ , parens undecidableMsg ]++famPatErr :: TyCon -> [TyVar] -> [Type] -> SDoc+famPatErr fam_tc tvs pats+ = hang (text "Family instance purports to bind type variable" <> plural tvs+ <+> pprQuotedList tvs)+ 2 (hang (text "but the real LHS (expanding synonyms) is:")+ 2 (pprTypeApp fam_tc (map expandTypeSynonyms pats) <+>+ text "= ..."))++{-+************************************************************************+* *+ Telescope checking+* *+************************************************************************++Note [Bad telescopes]+~~~~~~~~~~~~~~~~~~~~~+Now that we can mix type and kind variables, there are an awful lot of+ways to shoot yourself in the foot. Here are some.++ data SameKind :: k -> k -> * -- just to force unification++1. data T1 a k (b :: k) (x :: SameKind a b)++The problem here is that we discover that a and b should have the same+kind. But this kind mentions k, which is bound *after* a.+(Testcase: dependent/should_fail/BadTelescope)++2. data T2 a (c :: Proxy b) (d :: Proxy a) (x :: SameKind b d)++Note that b is not bound. Yet its kind mentions a. Because we have+a nice rule that all implicitly bound variables come before others,+this is bogus. (We could probably figure out to put b between a and c.+But I think this is doing users a disservice, in the long run.)+(Testcase: dependent/should_fail/BadTelescope4)++3. t3 :: forall a. (forall k (b :: k). SameKind a b) -> ()++This is a straightforward skolem escape. Note that a and b need to have+the same kind.+(Testcase: polykinds/T11142)++How do we deal with all of this? For TyCons, we have checkValidTyConTyVars.+That function looks to see if any of the tyConTyVars are repeated, but+it's really a telescope check. It works because all tycons are kind-generalized.+If there is a bad telescope, the kind-generalization will end up generalizing+over a variable bound later in the telescope.++For non-tycons, we do scope checking when we bring tyvars into scope,+in tcImplicitTKBndrs and tcExplicitTKBndrs. Note that we also have to+sort implicit binders into a well-scoped order whenever we have implicit+binders to worry about. This is done in quantifyTyVars and in+tcImplicitTKBndrs.+-}++-- | Check a list of binders to see if they make a valid telescope.+-- The key property we're checking for is scoping. For example:+-- > data SameKind :: k -> k -> *+-- > data X a k (b :: k) (c :: SameKind a b)+-- Kind inference says that a's kind should be k. But that's impossible,+-- because k isn't in scope when a is bound. This check has to come before+-- general validity checking, because once we kind-generalise, this sort+-- of problem is harder to spot (as we'll generalise over the unbound+-- k in a's type.) See also Note [Bad telescopes].+checkValidTelescope :: SDoc -- the original user-written telescope+ -> [TyVar] -- explicit vars (not necessarily zonked)+ -> SDoc -- note to put at bottom of message+ -> TcM ()+checkValidTelescope hs_tvs orig_tvs extra+ = discardResult $ checkZonkValidTelescope hs_tvs orig_tvs extra++-- | Like 'checkZonkValidTelescope', but returns the zonked tyvars+checkZonkValidTelescope :: SDoc+ -> [TyVar]+ -> SDoc+ -> TcM [TyVar]+checkZonkValidTelescope hs_tvs orig_tvs extra+ = do { orig_tvs <- mapM zonkTyCoVarKind orig_tvs+ ; let (_, sorted_tidied_tvs) = tidyTyCoVarBndrs emptyTidyEnv $+ toposortTyVars orig_tvs+ ; unless (go [] emptyVarSet orig_tvs) $+ addErr $+ vcat [ hang (text "These kind and type variables:" <+> hs_tvs $$+ text "are out of dependency order. Perhaps try this ordering:")+ 2 (sep (map pprTyVar sorted_tidied_tvs))+ , extra ]+ ; return orig_tvs }++ where+ go :: [TyVar] -- misplaced variables+ -> TyVarSet -> [TyVar] -> Bool+ go errs in_scope [] = null (filter (`elemVarSet` in_scope) errs)+ -- report an error only when the variable in the kind is brought+ -- into scope later in the telescope. Otherwise, we'll just quantify+ -- over it in kindGeneralize, as we should.++ go errs in_scope (tv:tvs)+ = let bad_tvs = filterOut (`elemVarSet` in_scope) $+ tyCoVarsOfTypeList (tyVarKind tv)+ in go (bad_tvs ++ errs) (in_scope `extendVarSet` tv) tvs++-- | After inferring kinds of type variables, check to make sure that the+-- inferred kinds any of the type variables bound in a smaller scope.+-- This is a skolem escape check. See also Note [Bad telescopes].+checkValidInferredKinds :: [TyVar] -- ^ vars to check (zonked)+ -> TyVarSet -- ^ vars out of scope+ -> SDoc -- ^ suffix to error message+ -> TcM ()+checkValidInferredKinds orig_kvs out_of_scope extra+ = do { let bad_pairs = [ (tv, kv)+ | kv <- orig_kvs+ , Just tv <- map (lookupVarSet out_of_scope)+ (tyCoVarsOfTypeList (tyVarKind kv)) ]+ report (tidyTyVarOcc env -> tv, tidyTyVarOcc env -> kv)+ = addErr $+ text "The kind of variable" <+>+ quotes (ppr kv) <> text ", namely" <+>+ quotes (ppr (tyVarKind kv)) <> comma $$+ text "depends on variable" <+>+ quotes (ppr tv) <+> text "from an inner scope" $$+ text "Perhaps bind" <+> quotes (ppr kv) <+>+ text "sometime after binding" <+>+ quotes (ppr tv) $$+ extra+ ; mapM_ report bad_pairs }++ where+ (env1, _) = tidyTyCoVarBndrs emptyTidyEnv orig_kvs+ (env, _) = tidyTyCoVarBndrs env1 (nonDetEltsUniqSet out_of_scope)+ -- It's OK to use nonDetEltsUniqSet here because it's only used for+ -- generating the error message++{-+************************************************************************+* *+\subsection{Auxiliary functions}+* *+************************************************************************+-}++-- Free variables of a type, retaining repetitions, and expanding synonyms+fvType :: Type -> [TyCoVar]+fvType ty | Just exp_ty <- tcView ty = fvType exp_ty+fvType (TyVarTy tv) = [tv]+fvType (TyConApp _ tys) = fvTypes tys+fvType (LitTy {}) = []+fvType (AppTy fun arg) = fvType fun ++ fvType arg+fvType (FunTy arg res) = fvType arg ++ fvType res+fvType (ForAllTy (TvBndr tv _) ty)+ = fvType (tyVarKind tv) +++ filter (/= tv) (fvType ty)+fvType (CastTy ty co) = fvType ty ++ fvCo co+fvType (CoercionTy co) = fvCo co++fvTypes :: [Type] -> [TyVar]+fvTypes tys = concat (map fvType tys)++fvCo :: Coercion -> [TyCoVar]+fvCo (Refl _ ty) = fvType ty+fvCo (TyConAppCo _ _ args) = concatMap fvCo args+fvCo (AppCo co arg) = fvCo co ++ fvCo arg+fvCo (ForAllCo tv h co) = filter (/= tv) (fvCo co) ++ fvCo h+fvCo (FunCo _ co1 co2) = fvCo co1 ++ fvCo co2+fvCo (CoVarCo v) = [v]+fvCo (AxiomInstCo _ _ args) = concatMap fvCo args+fvCo (UnivCo p _ t1 t2) = fvProv p ++ fvType t1 ++ fvType t2+fvCo (SymCo co) = fvCo co+fvCo (TransCo co1 co2) = fvCo co1 ++ fvCo co2+fvCo (NthCo _ co) = fvCo co+fvCo (LRCo _ co) = fvCo co+fvCo (InstCo co arg) = fvCo co ++ fvCo arg+fvCo (CoherenceCo co1 co2) = fvCo co1 ++ fvCo co2+fvCo (KindCo co) = fvCo co+fvCo (SubCo co) = fvCo co+fvCo (AxiomRuleCo _ cs) = concatMap fvCo cs++fvProv :: UnivCoProvenance -> [TyCoVar]+fvProv UnsafeCoerceProv = []+fvProv (PhantomProv co) = fvCo co+fvProv (ProofIrrelProv co) = fvCo co+fvProv (PluginProv _) = []+fvProv (HoleProv h) = pprPanic "fvProv falls into a hole" (ppr h)++sizeType :: Type -> Int+-- Size of a type: the number of variables and constructors+sizeType ty | Just exp_ty <- tcView ty = sizeType exp_ty+sizeType (TyVarTy {}) = 1+sizeType (TyConApp _ tys) = sizeTypes tys + 1+sizeType (LitTy {}) = 1+sizeType (AppTy fun arg) = sizeType fun + sizeType arg+sizeType (FunTy arg res) = sizeType arg + sizeType res + 1+sizeType (ForAllTy _ ty) = sizeType ty+sizeType (CastTy ty _) = sizeType ty+sizeType (CoercionTy _) = 1++sizeTypes :: [Type] -> Int+sizeTypes = sum . map sizeType++-- Size of a predicate+--+-- We are considering whether class constraints terminate.+-- Equality constraints and constraints for the implicit+-- parameter class always termiante so it is safe to say "size 0".+-- (Implicit parameter constraints always terminate because+-- there are no instances for them---they are only solved by+-- "local instances" in expressions).+-- See Trac #4200.+sizePred :: PredType -> Int+sizePred ty = goClass ty+ where+ goClass p = go (classifyPredType p)++ go (ClassPred cls tys')+ | isTerminatingClass cls = 0+ | otherwise = sizeTypes (filterOutInvisibleTypes (classTyCon cls) tys')+ go (EqPred {}) = 0+ go (IrredPred ty) = sizeType ty++-- | When this says "True", ignore this class constraint during+-- a termination check+isTerminatingClass :: Class -> Bool+isTerminatingClass cls+ = isIPClass cls+ || cls `hasKey` typeableClassKey+ || cls `hasKey` coercibleTyConKey+ || cls `hasKey` eqTyConKey+ || cls `hasKey` heqTyConKey++-- | Tidy before printing a type+ppr_tidy :: TidyEnv -> Type -> SDoc+ppr_tidy env ty = pprType (tidyType env ty)++allDistinctTyVars :: TyVarSet -> [KindOrType] -> Bool+-- (allDistinctTyVars tvs tys) returns True if tys are+-- a) all tyvars+-- b) all distinct+-- c) disjoint from tvs+allDistinctTyVars _ [] = True+allDistinctTyVars tkvs (ty : tys)+ = case getTyVar_maybe ty of+ Nothing -> False+ Just tv | tv `elemVarSet` tkvs -> False+ | otherwise -> allDistinctTyVars (tkvs `extendVarSet` tv) tys
+ types/Class.hs view
@@ -0,0 +1,360 @@+-- (c) The University of Glasgow 2006+-- (c) The GRASP/AQUA Project, Glasgow University, 1992-1998+--+-- The @Class@ datatype++{-# LANGUAGE CPP #-}++module Class (+ Class,+ ClassOpItem,+ ClassATItem(..),+ ClassMinimalDef,+ DefMethInfo, pprDefMethInfo,++ FunDep, pprFundeps, pprFunDep,++ mkClass, mkAbstractClass, classTyVars, classArity,+ classKey, className, classATs, classATItems, classTyCon, classMethods,+ classOpItems, classBigSig, classExtraBigSig, classTvsFds, classSCTheta,+ classAllSelIds, classSCSelId, classMinimalDef, classHasFds,+ isAbstractClass,+ naturallyCoherentClass+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} TyCon ( TyCon )+import {-# SOURCE #-} TyCoRep ( Type, PredType, pprType )+import Var+import Name+import BasicTypes+import Unique+import Util+import SrcLoc+import PrelNames ( eqTyConKey, coercibleTyConKey, typeableClassKey,+ heqTyConKey )+import Outputable+import BooleanFormula (BooleanFormula, mkTrue)++import qualified Data.Data as Data++{-+************************************************************************+* *+\subsection[Class-basic]{@Class@: basic definition}+* *+************************************************************************++A @Class@ corresponds to a Greek kappa in the static semantics:+-}++data Class+ = Class {+ classTyCon :: TyCon, -- The data type constructor for+ -- dictionaries of this class+ -- See Note [ATyCon for classes] in TyCoRep++ className :: Name, -- Just the cached name of the TyCon+ classKey :: Unique, -- Cached unique of TyCon++ classTyVars :: [TyVar], -- The class kind and type variables;+ -- identical to those of the TyCon++ classFunDeps :: [FunDep TyVar], -- The functional dependencies++ classBody :: ClassBody -- Superclasses, ATs, methods++ }++-- | e.g.+--+-- > class C a b c | a b -> c, a c -> b where...+--+-- Here fun-deps are [([a,b],[c]), ([a,c],[b])]+--+-- - 'ApiAnnotation.AnnKeywordId' : 'ApiAnnotation.AnnRarrow'',++-- For details on above see note [Api annotations] in ApiAnnotation+type FunDep a = ([a],[a])++type ClassOpItem = (Id, DefMethInfo)+ -- Selector function; contains unfolding+ -- Default-method info++type DefMethInfo = Maybe (Name, DefMethSpec Type)+ -- Nothing No default method+ -- Just ($dm, VanillaDM) A polymorphic default method, name $dm+ -- Just ($gm, GenericDM ty) A generic default method, name $gm, type ty+ -- The generic dm type is *not* quantified+ -- over the class variables; ie has the+ -- class variables free++data ClassATItem+ = ATI TyCon -- See Note [Associated type tyvar names]+ (Maybe (Type, SrcSpan))+ -- Default associated type (if any) from this template+ -- Note [Associated type defaults]++type ClassMinimalDef = BooleanFormula Name -- Required methods++data ClassBody+ = AbstractClass+ | ConcreteClass {+ -- Superclasses: eg: (F a ~ b, F b ~ G a, Eq a, Show b)+ -- We need value-level selectors for both the dictionary+ -- superclasses and the equality superclasses+ classSCThetaStuff :: [PredType], -- Immediate superclasses,+ classSCSels :: [Id], -- Selector functions to extract the+ -- superclasses from a+ -- dictionary of this class+ -- Associated types+ classATStuff :: [ClassATItem], -- Associated type families++ -- Class operations (methods, not superclasses)+ classOpStuff :: [ClassOpItem], -- Ordered by tag++ -- Minimal complete definition+ classMinimalDefStuff :: ClassMinimalDef+ }+ -- TODO: maybe super classes should be allowed in abstract class definitions++classMinimalDef :: Class -> ClassMinimalDef+classMinimalDef Class{ classBody = ConcreteClass{ classMinimalDefStuff = d } } = d+classMinimalDef _ = mkTrue -- TODO: make sure this is the right direction++{-+Note [Associated type defaults]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The following is an example of associated type defaults:+ class C a where+ data D a r++ type F x a b :: *+ type F p q r = (p,q)->r -- Default++Note that++ * The TyCons for the associated types *share type variables* with the+ class, so that we can tell which argument positions should be+ instantiated in an instance decl. (The first for 'D', the second+ for 'F'.)++ * We can have default definitions only for *type* families,+ not data families++ * In the default decl, the "patterns" should all be type variables,+ but (in the source language) they don't need to be the same as in+ the 'type' decl signature or the class. It's more like a+ free-standing 'type instance' declaration.++ * HOWEVER, in the internal ClassATItem we rename the RHS to match the+ tyConTyVars of the family TyCon. So in the example above we'd get+ a ClassATItem of+ ATI F ((x,a) -> b)+ So the tyConTyVars of the family TyCon bind the free vars of+ the default Type rhs++The @mkClass@ function fills in the indirect superclasses.++The SrcSpan is for the entire original declaration.+-}++mkClass :: Name -> [TyVar]+ -> [FunDep TyVar]+ -> [PredType] -> [Id]+ -> [ClassATItem]+ -> [ClassOpItem]+ -> ClassMinimalDef+ -> TyCon+ -> Class++mkClass cls_name tyvars fds super_classes superdict_sels at_stuff+ op_stuff mindef tycon+ = Class { classKey = nameUnique cls_name,+ className = cls_name,+ -- NB: tyConName tycon = cls_name,+ -- But it takes a module loop to assert it here+ classTyVars = tyvars,+ classFunDeps = fds,+ classBody = ConcreteClass {+ classSCThetaStuff = super_classes,+ classSCSels = superdict_sels,+ classATStuff = at_stuff,+ classOpStuff = op_stuff,+ classMinimalDefStuff = mindef+ },+ classTyCon = tycon }++mkAbstractClass :: Name -> [TyVar]+ -> [FunDep TyVar]+ -> TyCon+ -> Class++mkAbstractClass cls_name tyvars fds tycon+ = Class { classKey = nameUnique cls_name,+ className = cls_name,+ -- NB: tyConName tycon = cls_name,+ -- But it takes a module loop to assert it here+ classTyVars = tyvars,+ classFunDeps = fds,+ classBody = AbstractClass,+ classTyCon = tycon }++{-+Note [Associated type tyvar names]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The TyCon of an associated type should use the same variable names as its+parent class. Thus+ class C a b where+ type F b x a :: *+We make F use the same Name for 'a' as C does, and similary 'b'.++The reason for this is when checking instances it's easier to match+them up, to ensure they match. Eg+ instance C Int [d] where+ type F [d] x Int = ....+we should make sure that the first and third args match the instance+header.++Having the same variables for class and tycon is also used in checkValidRoles+(in TcTyClsDecls) when checking a class's roles.+++************************************************************************+* *+\subsection[Class-selectors]{@Class@: simple selectors}+* *+************************************************************************++The rest of these functions are just simple selectors.+-}++classArity :: Class -> Arity+classArity clas = length (classTyVars clas)+ -- Could memoise this++classAllSelIds :: Class -> [Id]+-- Both superclass-dictionary and method selectors+classAllSelIds c@(Class { classBody = ConcreteClass { classSCSels = sc_sels }})+ = sc_sels ++ classMethods c+classAllSelIds c = ASSERT( null (classMethods c) ) []++classSCSelId :: Class -> Int -> Id+-- Get the n'th superclass selector Id+-- where n is 0-indexed, and counts+-- *all* superclasses including equalities+classSCSelId (Class { classBody = ConcreteClass { classSCSels = sc_sels } }) n+ = ASSERT( n >= 0 && n < length sc_sels )+ sc_sels !! n+classSCSelId c n = pprPanic "classSCSelId" (ppr c <+> ppr n)++classMethods :: Class -> [Id]+classMethods (Class { classBody = ConcreteClass { classOpStuff = op_stuff } })+ = [op_sel | (op_sel, _) <- op_stuff]+classMethods _ = []++classOpItems :: Class -> [ClassOpItem]+classOpItems (Class { classBody = ConcreteClass { classOpStuff = op_stuff }})+ = op_stuff+classOpItems _ = []++classATs :: Class -> [TyCon]+classATs (Class { classBody = ConcreteClass { classATStuff = at_stuff } })+ = [tc | ATI tc _ <- at_stuff]+classATs _ = []++classATItems :: Class -> [ClassATItem]+classATItems (Class { classBody = ConcreteClass { classATStuff = at_stuff }})+ = at_stuff+classATItems _ = []++classSCTheta :: Class -> [PredType]+classSCTheta (Class { classBody = ConcreteClass { classSCThetaStuff = theta_stuff }})+ = theta_stuff+classSCTheta _ = []++classTvsFds :: Class -> ([TyVar], [FunDep TyVar])+classTvsFds c = (classTyVars c, classFunDeps c)++classHasFds :: Class -> Bool+classHasFds (Class { classFunDeps = fds }) = not (null fds)++classBigSig :: Class -> ([TyVar], [PredType], [Id], [ClassOpItem])+classBigSig (Class {classTyVars = tyvars,+ classBody = AbstractClass})+ = (tyvars, [], [], [])+classBigSig (Class {classTyVars = tyvars,+ classBody = ConcreteClass {+ classSCThetaStuff = sc_theta,+ classSCSels = sc_sels,+ classOpStuff = op_stuff+ }})+ = (tyvars, sc_theta, sc_sels, op_stuff)++classExtraBigSig :: Class -> ([TyVar], [FunDep TyVar], [PredType], [Id], [ClassATItem], [ClassOpItem])+classExtraBigSig (Class {classTyVars = tyvars, classFunDeps = fundeps,+ classBody = AbstractClass})+ = (tyvars, fundeps, [], [], [], [])+classExtraBigSig (Class {classTyVars = tyvars, classFunDeps = fundeps,+ classBody = ConcreteClass {+ classSCThetaStuff = sc_theta, classSCSels = sc_sels,+ classATStuff = ats, classOpStuff = op_stuff+ }})+ = (tyvars, fundeps, sc_theta, sc_sels, ats, op_stuff)++isAbstractClass :: Class -> Bool+isAbstractClass Class{ classBody = AbstractClass } = True+isAbstractClass _ = False++-- | If a class is "naturally coherent", then we needn't worry at all, in any+-- way, about overlapping/incoherent instances. Just solve the thing!+naturallyCoherentClass :: Class -> Bool+-- See also Note [The equality class story] in TysPrim.+naturallyCoherentClass cls+ = cls `hasKey` heqTyConKey ||+ cls `hasKey` eqTyConKey ||+ cls `hasKey` coercibleTyConKey ||+ cls `hasKey` typeableClassKey++{-+************************************************************************+* *+\subsection[Class-instances]{Instance declarations for @Class@}+* *+************************************************************************++We compare @Classes@ by their keys (which include @Uniques@).+-}++instance Eq Class where+ c1 == c2 = classKey c1 == classKey c2+ c1 /= c2 = classKey c1 /= classKey c2++instance Uniquable Class where+ getUnique c = classKey c++instance NamedThing Class where+ getName clas = className clas++instance Outputable Class where+ ppr c = ppr (getName c)++pprDefMethInfo :: DefMethInfo -> SDoc+pprDefMethInfo Nothing = empty -- No default method+pprDefMethInfo (Just (n, VanillaDM)) = text "Default method" <+> ppr n+pprDefMethInfo (Just (n, GenericDM ty)) = text "Generic default method"+ <+> ppr n <+> dcolon <+> pprType ty++pprFundeps :: Outputable a => [FunDep a] -> SDoc+pprFundeps [] = empty+pprFundeps fds = hsep (vbar : punctuate comma (map pprFunDep fds))++pprFunDep :: Outputable a => FunDep a -> SDoc+pprFunDep (us, vs) = hsep [interppSP us, arrow, interppSP vs]++instance Data.Data Class where+ -- don't traverse?+ toConstr _ = abstractConstr "Class"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "Class"
+ types/CoAxiom.hs view
@@ -0,0 +1,517 @@+-- (c) The University of Glasgow 2012++{-# LANGUAGE CPP, DataKinds, DeriveDataTypeable, GADTs, KindSignatures,+ ScopedTypeVariables, StandaloneDeriving, RoleAnnotations #-}++-- | Module for coercion axioms, used to represent type family instances+-- and newtypes++module CoAxiom (+ BranchFlag, Branched, Unbranched, BranchIndex, Branches,+ manyBranches, unbranched,+ fromBranches, numBranches,+ mapAccumBranches,++ CoAxiom(..), CoAxBranch(..),++ toBranchedAxiom, toUnbranchedAxiom,+ coAxiomName, coAxiomArity, coAxiomBranches,+ coAxiomTyCon, isImplicitCoAxiom, coAxiomNumPats,+ coAxiomNthBranch, coAxiomSingleBranch_maybe, coAxiomRole,+ coAxiomSingleBranch, coAxBranchTyVars, coAxBranchCoVars,+ coAxBranchRoles,+ coAxBranchLHS, coAxBranchRHS, coAxBranchSpan, coAxBranchIncomps,+ placeHolderIncomps,++ Role(..), fsFromRole,++ CoAxiomRule(..), TypeEqn,+ BuiltInSynFamily(..), trivialBuiltInFamily+ ) where++import {-# SOURCE #-} TyCoRep ( Type, pprType )+import {-# SOURCE #-} TyCon ( TyCon )+import Outputable+import FastString+import Name+import Unique+import Var+import Util+import Binary+import Pair+import BasicTypes+import Data.Typeable ( Typeable )+import SrcLoc+import qualified Data.Data as Data+import Data.Array+import Data.List ( mapAccumL )++#include "HsVersions.h"++{-+Note [Coercion axiom branches]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In order to allow closed type families, an axiom needs to contain an+ordered list of alternatives, called branches. The kind of the coercion built+from an axiom is determined by which index is used when building the coercion+from the axiom.++For example, consider the axiom derived from the following declaration:++type family F a where+ F [Int] = Bool+ F [a] = Double+ F (a b) = Char++This will give rise to this axiom:++axF :: { F [Int] ~ Bool+ ; forall (a :: *). F [a] ~ Double+ ; forall (k :: *) (a :: k -> *) (b :: k). F (a b) ~ Char+ }++The axiom is used with the AxiomInstCo constructor of Coercion. If we wish+to have a coercion showing that F (Maybe Int) ~ Char, it will look like++axF[2] <*> <Maybe> <Int> :: F (Maybe Int) ~ Char+-- or, written using concrete-ish syntax --+AxiomInstCo axF 2 [Refl *, Refl Maybe, Refl Int]++Note that the index is 0-based.++For type-checking, it is also necessary to check that no previous pattern+can unify with the supplied arguments. After all, it is possible that some+of the type arguments are lambda-bound type variables whose instantiation may+cause an earlier match among the branches. We wish to prohibit this behavior,+so the type checker rules out the choice of a branch where a previous branch+can unify. See also [Apartness] in FamInstEnv.hs.++For example, the following is malformed, where 'a' is a lambda-bound type+variable:++axF[2] <*> <a> <Bool> :: F (a Bool) ~ Char++Why? Because a might be instantiated with [], meaning that branch 1 should+apply, not branch 2. This is a vital consistency check; without it, we could+derive Int ~ Bool, and that is a Bad Thing.++Note [Branched axioms]+~~~~~~~~~~~~~~~~~~~~~~+Although a CoAxiom has the capacity to store many branches, in certain cases,+we want only one. These cases are in data/newtype family instances, newtype+coercions, and type family instances.+Furthermore, these unbranched axioms are used in a+variety of places throughout GHC, and it would difficult to generalize all of+that code to deal with branched axioms, especially when the code can be sure+of the fact that an axiom is indeed a singleton. At the same time, it seems+dangerous to assume singlehood in various places through GHC.++The solution to this is to label a CoAxiom with a phantom type variable+declaring whether it is known to be a singleton or not. The branches+are stored using a special datatype, declared below, that ensures that the+type variable is accurate.++************************************************************************+* *+ Branches+* *+************************************************************************+-}++type BranchIndex = Int -- The index of the branch in the list of branches+ -- Counting from zero++-- promoted data type+data BranchFlag = Branched | Unbranched+type Branched = 'Branched+type Unbranched = 'Unbranched+-- By using type synonyms for the promoted constructors, we avoid needing+-- DataKinds and the promotion quote in client modules. This also means that+-- we don't need to export the term-level constructors, which should never be used.++newtype Branches (br :: BranchFlag)+ = MkBranches { unMkBranches :: Array BranchIndex CoAxBranch }+type role Branches nominal++manyBranches :: [CoAxBranch] -> Branches Branched+manyBranches brs = ASSERT( snd bnds >= fst bnds )+ MkBranches (listArray bnds brs)+ where+ bnds = (0, length brs - 1)++unbranched :: CoAxBranch -> Branches Unbranched+unbranched br = MkBranches (listArray (0, 0) [br])++toBranched :: Branches br -> Branches Branched+toBranched = MkBranches . unMkBranches++toUnbranched :: Branches br -> Branches Unbranched+toUnbranched (MkBranches arr) = ASSERT( bounds arr == (0,0) )+ MkBranches arr++fromBranches :: Branches br -> [CoAxBranch]+fromBranches = elems . unMkBranches++branchesNth :: Branches br -> BranchIndex -> CoAxBranch+branchesNth (MkBranches arr) n = arr ! n++numBranches :: Branches br -> Int+numBranches (MkBranches arr) = snd (bounds arr) + 1++-- | The @[CoAxBranch]@ passed into the mapping function is a list of+-- all previous branches, reversed+mapAccumBranches :: ([CoAxBranch] -> CoAxBranch -> CoAxBranch)+ -> Branches br -> Branches br+mapAccumBranches f (MkBranches arr)+ = MkBranches (listArray (bounds arr) (snd $ mapAccumL go [] (elems arr)))+ where+ go :: [CoAxBranch] -> CoAxBranch -> ([CoAxBranch], CoAxBranch)+ go prev_branches cur_branch = ( cur_branch : prev_branches+ , f prev_branches cur_branch )+++{-+************************************************************************+* *+ Coercion axioms+* *+************************************************************************++Note [Storing compatibility]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+During axiom application, we need to be aware of which branches are compatible+with which others. The full explanation is in Note [Compatibility] in+FamInstEnv. (The code is placed there to avoid a dependency from CoAxiom on+the unification algorithm.) Although we could theoretically compute+compatibility on the fly, this is silly, so we store it in a CoAxiom.++Specifically, each branch refers to all other branches with which it is+incompatible. This list might well be empty, and it will always be for the+first branch of any axiom.++CoAxBranches that do not (yet) belong to a CoAxiom should have a panic thunk+stored in cab_incomps. The incompatibilities are properly a property of the+axiom as a whole, and they are computed only when the final axiom is built.++During serialization, the list is converted into a list of the indices+of the branches.+-}++-- | A 'CoAxiom' is a \"coercion constructor\", i.e. a named equality axiom.++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data CoAxiom br+ = CoAxiom -- Type equality axiom.+ { co_ax_unique :: Unique -- Unique identifier+ , co_ax_name :: Name -- Name for pretty-printing+ , co_ax_role :: Role -- Role of the axiom's equality+ , co_ax_tc :: TyCon -- The head of the LHS patterns+ -- e.g. the newtype or family tycon+ , co_ax_branches :: Branches br -- The branches that form this axiom+ , co_ax_implicit :: Bool -- True <=> the axiom is "implicit"+ -- See Note [Implicit axioms]+ -- INVARIANT: co_ax_implicit == True implies length co_ax_branches == 1.+ }++data CoAxBranch+ = CoAxBranch+ { cab_loc :: SrcSpan -- Location of the defining equation+ -- See Note [CoAxiom locations]+ , cab_tvs :: [TyVar] -- Bound type variables; not necessarily fresh+ -- See Note [CoAxBranch type variables]+ , cab_cvs :: [CoVar] -- Bound coercion variables+ -- Always empty, for now.+ -- See Note [Constraints in patterns]+ -- in TcTyClsDecls+ , cab_roles :: [Role] -- See Note [CoAxBranch roles]+ , cab_lhs :: [Type] -- Type patterns to match against+ -- See Note [CoAxiom saturation]+ , cab_rhs :: Type -- Right-hand side of the equality+ , cab_incomps :: [CoAxBranch] -- The previous incompatible branches+ -- See Note [Storing compatibility]+ }+ deriving Data.Data++toBranchedAxiom :: CoAxiom br -> CoAxiom Branched+toBranchedAxiom (CoAxiom unique name role tc branches implicit)+ = CoAxiom unique name role tc (toBranched branches) implicit++toUnbranchedAxiom :: CoAxiom br -> CoAxiom Unbranched+toUnbranchedAxiom (CoAxiom unique name role tc branches implicit)+ = CoAxiom unique name role tc (toUnbranched branches) implicit++coAxiomNumPats :: CoAxiom br -> Int+coAxiomNumPats = length . coAxBranchLHS . (flip coAxiomNthBranch 0)++coAxiomNthBranch :: CoAxiom br -> BranchIndex -> CoAxBranch+coAxiomNthBranch (CoAxiom { co_ax_branches = bs }) index+ = branchesNth bs index++coAxiomArity :: CoAxiom br -> BranchIndex -> Arity+coAxiomArity ax index+ = length tvs + length cvs+ where+ CoAxBranch { cab_tvs = tvs, cab_cvs = cvs } = coAxiomNthBranch ax index++coAxiomName :: CoAxiom br -> Name+coAxiomName = co_ax_name++coAxiomRole :: CoAxiom br -> Role+coAxiomRole = co_ax_role++coAxiomBranches :: CoAxiom br -> Branches br+coAxiomBranches = co_ax_branches++coAxiomSingleBranch_maybe :: CoAxiom br -> Maybe CoAxBranch+coAxiomSingleBranch_maybe (CoAxiom { co_ax_branches = MkBranches arr })+ | snd (bounds arr) == 0+ = Just $ arr ! 0+ | otherwise+ = Nothing++coAxiomSingleBranch :: CoAxiom Unbranched -> CoAxBranch+coAxiomSingleBranch (CoAxiom { co_ax_branches = MkBranches arr })+ = arr ! 0++coAxiomTyCon :: CoAxiom br -> TyCon+coAxiomTyCon = co_ax_tc++coAxBranchTyVars :: CoAxBranch -> [TyVar]+coAxBranchTyVars = cab_tvs++coAxBranchCoVars :: CoAxBranch -> [CoVar]+coAxBranchCoVars = cab_cvs++coAxBranchLHS :: CoAxBranch -> [Type]+coAxBranchLHS = cab_lhs++coAxBranchRHS :: CoAxBranch -> Type+coAxBranchRHS = cab_rhs++coAxBranchRoles :: CoAxBranch -> [Role]+coAxBranchRoles = cab_roles++coAxBranchSpan :: CoAxBranch -> SrcSpan+coAxBranchSpan = cab_loc++isImplicitCoAxiom :: CoAxiom br -> Bool+isImplicitCoAxiom = co_ax_implicit++coAxBranchIncomps :: CoAxBranch -> [CoAxBranch]+coAxBranchIncomps = cab_incomps++-- See Note [Compatibility checking] in FamInstEnv+placeHolderIncomps :: [CoAxBranch]+placeHolderIncomps = panic "placeHolderIncomps"++{- Note [CoAxiom saturation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* When co++Note [CoAxBranch type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+In the case of a CoAxBranch of an associated type-family instance,+we use the *same* type variables (where possible) as the+enclosing class or instance. Consider+ class C a b where+ type F x b+ type F [y] b = ... -- Second param must be b++ instance C Int [z] where+ type F Int [z] = ... -- Second param must be [z]++In the CoAxBranch in the instance decl (F Int [z]) we use the+same 'z', so that it's easy to check that that type is the same+as that in the instance header.++Similarly in the CoAxBranch for the default decl for F in the+class decl, we use the same 'b' to make the same check easy.++So, unlike FamInsts, there is no expectation that the cab_tvs+are fresh wrt each other, or any other CoAxBranch.++Note [CoAxBranch roles]+~~~~~~~~~~~~~~~~~~~~~~~+Consider this code:++ newtype Age = MkAge Int+ newtype Wrap a = MkWrap a++ convert :: Wrap Age -> Int+ convert (MkWrap (MkAge i)) = i++We want this to compile to:++ NTCo:Wrap :: forall a. Wrap a ~R a+ NTCo:Age :: Age ~R Int+ convert = \x -> x |> (NTCo:Wrap[0] NTCo:Age[0])++But, note that NTCo:Age is at role R. Thus, we need to be able to pass+coercions at role R into axioms. However, we don't *always* want to be able to+do this, as it would be disastrous with type families. The solution is to+annotate the arguments to the axiom with roles, much like we annotate tycon+tyvars. Where do these roles get set? Newtype axioms inherit their roles from+the newtype tycon; family axioms are all at role N.++Note [CoAxiom locations]+~~~~~~~~~~~~~~~~~~~~~~~~+The source location of a CoAxiom is stored in two places in the+datatype tree.+ * The first is in the location info buried in the Name of the+ CoAxiom. This span includes all of the branches of a branched+ CoAxiom.+ * The second is in the cab_loc fields of the CoAxBranches.++In the case of a single branch, we can extract the source location of+the branch from the name of the CoAxiom. In other cases, we need an+explicit SrcSpan to correctly store the location of the equation+giving rise to the FamInstBranch.++Note [Implicit axioms]+~~~~~~~~~~~~~~~~~~~~~~+See also Note [Implicit TyThings] in HscTypes+* A CoAxiom arising from data/type family instances is not "implicit".+ That is, it has its own IfaceAxiom declaration in an interface file++* The CoAxiom arising from a newtype declaration *is* "implicit".+ That is, it does not have its own IfaceAxiom declaration in an+ interface file; instead the CoAxiom is generated by type-checking+ the newtype declaration+-}++instance Eq (CoAxiom br) where+ a == b = getUnique a == getUnique b+ a /= b = getUnique a /= getUnique b++instance Uniquable (CoAxiom br) where+ getUnique = co_ax_unique++instance Outputable (CoAxiom br) where+ ppr = ppr . getName++instance NamedThing (CoAxiom br) where+ getName = co_ax_name++instance Typeable br => Data.Data (CoAxiom br) where+ -- don't traverse?+ toConstr _ = abstractConstr "CoAxiom"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "CoAxiom"++instance Outputable CoAxBranch where+ ppr (CoAxBranch { cab_loc = loc+ , cab_lhs = lhs+ , cab_rhs = rhs }) =+ text "CoAxBranch" <+> parens (ppr loc) <> colon+ <+> brackets (fsep (punctuate comma (map pprType lhs)))+ <+> text "=>" <+> pprType rhs++{-+************************************************************************+* *+ Roles+* *+************************************************************************++Roles are defined here to avoid circular dependencies.+-}++-- See Note [Roles] in Coercion+-- defined here to avoid cyclic dependency with Coercion+--+-- Order of constructors matters: the Ord instance coincides with the *super*typing+-- relation on roles.+data Role = Nominal | Representational | Phantom+ deriving (Eq, Ord, Data.Data)++-- These names are slurped into the parser code. Changing these strings+-- will change the **surface syntax** that GHC accepts! If you want to+-- change only the pretty-printing, do some replumbing. See+-- mkRoleAnnotDecl in RdrHsSyn+fsFromRole :: Role -> FastString+fsFromRole Nominal = fsLit "nominal"+fsFromRole Representational = fsLit "representational"+fsFromRole Phantom = fsLit "phantom"++instance Outputable Role where+ ppr = ftext . fsFromRole++instance Binary Role where+ put_ bh Nominal = putByte bh 1+ put_ bh Representational = putByte bh 2+ put_ bh Phantom = putByte bh 3++ get bh = do tag <- getByte bh+ case tag of 1 -> return Nominal+ 2 -> return Representational+ 3 -> return Phantom+ _ -> panic ("get Role " ++ show tag)++{-+************************************************************************+* *+ CoAxiomRule+ Rules for building Evidence+* *+************************************************************************++Conditional axioms. The general idea is that a `CoAxiomRule` looks like this:++ forall as. (r1 ~ r2, s1 ~ s2) => t1 ~ t2++My intention is to reuse these for both (~) and (~#).+The short-term plan is to use this datatype to represent the type-nat axioms.+In the longer run, it may be good to unify this and `CoAxiom`,+as `CoAxiom` is the special case when there are no assumptions.+-}++-- | A more explicit representation for `t1 ~ t2`.+type TypeEqn = Pair Type++-- | For now, we work only with nominal equality.+data CoAxiomRule = CoAxiomRule+ { coaxrName :: FastString+ , coaxrAsmpRoles :: [Role] -- roles of parameter equations+ , coaxrRole :: Role -- role of resulting equation+ , coaxrProves :: [TypeEqn] -> Maybe TypeEqn+ -- ^ coaxrProves returns @Nothing@ when it doesn't like+ -- the supplied arguments. When this happens in a coercion+ -- that means that the coercion is ill-formed, and Core Lint+ -- checks for that.+ }++instance Data.Data CoAxiomRule where+ -- don't traverse?+ toConstr _ = abstractConstr "CoAxiomRule"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "CoAxiomRule"++instance Uniquable CoAxiomRule where+ getUnique = getUnique . coaxrName++instance Eq CoAxiomRule where+ x == y = coaxrName x == coaxrName y++instance Ord CoAxiomRule where+ compare x y = compare (coaxrName x) (coaxrName y)++instance Outputable CoAxiomRule where+ ppr = ppr . coaxrName+++-- Type checking of built-in families+data BuiltInSynFamily = BuiltInSynFamily+ { sfMatchFam :: [Type] -> Maybe (CoAxiomRule, [Type], Type)+ , sfInteractTop :: [Type] -> Type -> [TypeEqn]+ , sfInteractInert :: [Type] -> Type ->+ [Type] -> Type -> [TypeEqn]+ }++-- Provides default implementations that do nothing.+trivialBuiltInFamily :: BuiltInSynFamily+trivialBuiltInFamily = BuiltInSynFamily+ { sfMatchFam = \_ -> Nothing+ , sfInteractTop = \_ _ -> []+ , sfInteractInert = \_ _ _ _ -> []+ }
+ types/Coercion.hs view
@@ -0,0 +1,1961 @@+{-+(c) The University of Glasgow 2006+-}++{-# LANGUAGE RankNTypes, CPP, MultiWayIf, FlexibleContexts #-}++-- | Module for (a) type kinds and (b) type coercions,+-- as used in System FC. See 'CoreSyn.Expr' for+-- more on System FC and how coercions fit into it.+--+module Coercion (+ -- * Main data type+ Coercion, CoercionN, CoercionR, CoercionP,+ UnivCoProvenance, CoercionHole, LeftOrRight(..),+ Var, CoVar, TyCoVar,+ Role(..), ltRole,++ -- ** Functions over coercions+ coVarTypes, coVarKind, coVarKindsTypesRole, coVarRole,+ coercionType, coercionKind, coercionKinds,+ mkCoercionType,+ coercionRole, coercionKindRole,++ -- ** Constructing coercions+ mkReflCo, mkRepReflCo, mkNomReflCo,+ mkCoVarCo, mkCoVarCos,+ mkAxInstCo, mkUnbranchedAxInstCo,+ mkAxInstRHS, mkUnbranchedAxInstRHS,+ mkAxInstLHS, mkUnbranchedAxInstLHS,+ mkPiCo, mkPiCos, mkCoCast,+ mkSymCo, mkTransCo, mkTransAppCo,+ mkNthCo, mkNthCoRole, mkLRCo,+ mkInstCo, mkAppCo, mkAppCos, mkTyConAppCo, mkFunCo, mkFunCos,+ mkForAllCo, mkForAllCos, mkHomoForAllCos, mkHomoForAllCos_NoRefl,+ mkPhantomCo, mkHomoPhantomCo, toPhantomCo,+ mkUnsafeCo, mkHoleCo, mkUnivCo, mkSubCo,+ mkAxiomInstCo, mkProofIrrelCo,+ downgradeRole, maybeSubCo, mkAxiomRuleCo,+ mkCoherenceCo, mkCoherenceRightCo, mkCoherenceLeftCo,+ mkKindCo, castCoercionKind,++ mkHeteroCoercionType,++ -- ** Decomposition+ instNewTyCon_maybe,++ NormaliseStepper, NormaliseStepResult(..), composeSteppers,+ mapStepResult, unwrapNewTypeStepper,+ topNormaliseNewType_maybe, topNormaliseTypeX,++ decomposeCo, decomposeFunCo, getCoVar_maybe,+ splitTyConAppCo_maybe,+ splitAppCo_maybe,+ splitFunCo_maybe,+ splitForAllCo_maybe,++ nthRole, tyConRolesX, tyConRolesRepresentational, setNominalRole_maybe,++ pickLR,++ isReflCo, isReflCo_maybe, isReflexiveCo, isReflexiveCo_maybe,+ isReflCoVar_maybe,++ -- ** Coercion variables+ mkCoVar, isCoVar, coVarName, setCoVarName, setCoVarUnique,+ isCoVar_maybe,++ -- ** Free variables+ tyCoVarsOfCo, tyCoVarsOfCos, coVarsOfCo,+ tyCoFVsOfCo, tyCoFVsOfCos, tyCoVarsOfCoDSet,+ coercionSize,++ -- ** Substitution+ CvSubstEnv, emptyCvSubstEnv,+ lookupCoVar,+ substCo, substCos, substCoVar, substCoVars, substCoWith,+ substCoVarBndr,+ extendTvSubstAndInScope, getCvSubstEnv,++ -- ** Lifting+ liftCoSubst, liftCoSubstTyVar, liftCoSubstWith, liftCoSubstWithEx,+ emptyLiftingContext, extendLiftingContext,+ liftCoSubstVarBndrCallback, isMappedByLC,++ mkSubstLiftingContext, zapLiftingContext,+ substForAllCoBndrCallbackLC, lcTCvSubst, lcInScopeSet,++ LiftCoEnv, LiftingContext(..), liftEnvSubstLeft, liftEnvSubstRight,+ substRightCo, substLeftCo, swapLiftCoEnv, lcSubstLeft, lcSubstRight,++ -- ** Comparison+ eqCoercion, eqCoercionX,++ -- ** Forcing evaluation of coercions+ seqCo,++ -- * Pretty-printing+ pprCo, pprParendCo, pprCoBndr,+ pprCoAxiom, pprCoAxBranch, pprCoAxBranchHdr,++ -- * Tidying+ tidyCo, tidyCos,++ -- * Other+ promoteCoercion+ ) where++#include "HsVersions.h"++import TyCoRep+import Type+import TyCon+import CoAxiom+import Var+import VarEnv+import Name hiding ( varName )+import Util+import BasicTypes+import Outputable+import Unique+import Pair+import SrcLoc+import PrelNames+import TysPrim ( eqPhantPrimTyCon )+import ListSetOps+import Maybes+import UniqFM++import Control.Monad (foldM)+import Control.Arrow ( first )+import Data.Function ( on )++{-+%************************************************************************+%* *+ -- The coercion arguments always *precisely* saturate+ -- arity of (that branch of) the CoAxiom. If there are+ -- any left over, we use AppCo. See+ -- See [Coercion axioms applied to coercions] in TyCoRep++\subsection{Coercion variables}+%* *+%************************************************************************+-}++coVarName :: CoVar -> Name+coVarName = varName++setCoVarUnique :: CoVar -> Unique -> CoVar+setCoVarUnique = setVarUnique++setCoVarName :: CoVar -> Name -> CoVar+setCoVarName = setVarName+++{-+%************************************************************************+%* *+ Pretty-printing coercions+%* *+%************************************************************************++@pprCo@ is the standard @Coercion@ printer; the overloaded @ppr@+function is defined to use this. @pprParendCo@ is the same, except it+puts parens around the type, except for the atomic cases.+@pprParendCo@ works just by setting the initial context precedence+very high.+-}++-- Outputable instances are in TyCoRep, to avoid orphans++pprCo, pprParendCo :: Coercion -> SDoc+pprCo co = ppr_co TopPrec co+pprParendCo co = ppr_co TyConPrec co++ppr_co :: TyPrec -> Coercion -> SDoc+ppr_co _ (Refl r ty) = angleBrackets (ppr ty) <> ppr_role r++ppr_co _ (TyConAppCo r tc cos) = pprTcAppCo TyConPrec ppr_co tc cos <> ppr_role r+ppr_co p (AppCo co arg) = maybeParen p TyConPrec $+ pprCo co <+> ppr_co TyConPrec arg+ppr_co p co@(ForAllCo {}) = ppr_forall_co p co+ppr_co p co@(FunCo {}) = ppr_fun_co p co+ppr_co _ (CoVarCo cv) = parenSymOcc (getOccName cv) (ppr cv)+ppr_co p (AxiomInstCo con index args)+ = pprPrefixApp p (ppr (getName con) <> brackets (ppr index))+ (map (ppr_co TyConPrec) args)++ppr_co p co@(TransCo {}) = maybeParen p FunPrec $+ case trans_co_list co [] of+ [] -> panic "ppr_co"+ (co:cos) -> sep ( ppr_co FunPrec co+ : [ char ';' <+> ppr_co FunPrec co | co <- cos])+ppr_co p (InstCo co arg) = maybeParen p TyConPrec $+ pprParendCo co <> text "@" <> ppr_co TopPrec arg++ppr_co p (UnivCo UnsafeCoerceProv r ty1 ty2)+ = pprPrefixApp p (text "UnsafeCo" <+> ppr r)+ [pprParendType ty1, pprParendType ty2]+ppr_co _ (UnivCo p r t1 t2)+ = char 'U'+ <> parens (ppr_prov <> comma <+> ppr t1 <> comma <+> ppr t2)+ <> ppr_role r+ where+ ppr_prov = case p of+ HoleProv h -> text "hole:" <> ppr h+ PhantomProv kind_co -> text "phant:" <> ppr kind_co+ ProofIrrelProv co -> text "irrel:" <> ppr co+ PluginProv s -> text "plugin:" <> text s+ UnsafeCoerceProv -> text "unsafe"++ppr_co p (SymCo co) = pprPrefixApp p (text "Sym") [pprParendCo co]+ppr_co p (NthCo n co) = pprPrefixApp p (text "Nth:" <> int n) [pprParendCo co]+ppr_co p (LRCo sel co) = pprPrefixApp p (ppr sel) [pprParendCo co]+ppr_co p (CoherenceCo c1 c2) = maybeParen p TyConPrec $+ (ppr_co FunPrec c1) <+> (text "|>") <+>+ (ppr_co FunPrec c2)+ppr_co p (KindCo co) = pprPrefixApp p (text "kind") [pprParendCo co]+ppr_co p (SubCo co) = pprPrefixApp p (text "Sub") [pprParendCo co]+ppr_co p (AxiomRuleCo co cs) = maybeParen p TopPrec $ ppr_axiom_rule_co co cs++ppr_axiom_rule_co :: CoAxiomRule -> [Coercion] -> SDoc+ppr_axiom_rule_co co ps = ppr (coaxrName co) <+> parens (interpp'SP ps)++ppr_role :: Role -> SDoc+ppr_role r = underscore <> pp_role+ where pp_role = case r of+ Nominal -> char 'N'+ Representational -> char 'R'+ Phantom -> char 'P'++trans_co_list :: Coercion -> [Coercion] -> [Coercion]+trans_co_list (TransCo co1 co2) cos = trans_co_list co1 (trans_co_list co2 cos)+trans_co_list co cos = co : cos++ppr_fun_co :: TyPrec -> Coercion -> SDoc+ppr_fun_co p co = pprArrowChain p (split co)+ where+ split :: Coercion -> [SDoc]+ split (FunCo _ arg res)+ = ppr_co FunPrec arg : split res+ split co = [ppr_co TopPrec co]++ppr_forall_co :: TyPrec -> Coercion -> SDoc+ppr_forall_co p (ForAllCo tv h co)+ = maybeParen p FunPrec $+ sep [pprCoBndr (tyVarName tv) h, ppr_co TopPrec co]+ppr_forall_co _ _ = panic "ppr_forall_co"++pprCoBndr :: Name -> Coercion -> SDoc+pprCoBndr name eta =+ forAllLit <+> parens (ppr name <+> dcolon <+> ppr eta) <> dot++pprCoAxiom :: CoAxiom br -> SDoc+pprCoAxiom ax@(CoAxiom { co_ax_branches = branches })+ = hang (text "axiom" <+> ppr ax <+> dcolon)+ 2 (vcat (map (ppr_co_ax_branch (const ppr) ax) $ fromBranches branches))++pprCoAxBranch :: CoAxiom br -> CoAxBranch -> SDoc+pprCoAxBranch = ppr_co_ax_branch pprRhs+ where+ pprRhs fam_tc (TyConApp tycon _)+ | isDataFamilyTyCon fam_tc+ = pprDataCons tycon+ pprRhs _ rhs = ppr rhs++pprCoAxBranchHdr :: CoAxiom br -> BranchIndex -> SDoc+pprCoAxBranchHdr ax index = pprCoAxBranch ax (coAxiomNthBranch ax index)++ppr_co_ax_branch :: (TyCon -> Type -> SDoc) -> CoAxiom br -> CoAxBranch -> SDoc+ppr_co_ax_branch ppr_rhs+ (CoAxiom { co_ax_tc = fam_tc, co_ax_name = name })+ (CoAxBranch { cab_tvs = tvs+ , cab_cvs = cvs+ , cab_lhs = lhs+ , cab_rhs = rhs+ , cab_loc = loc })+ = foldr1 (flip hangNotEmpty 2)+ [ pprUserForAll (mkTyVarBinders Inferred (tvs ++ cvs))+ , pprTypeApp fam_tc lhs <+> equals <+> ppr_rhs fam_tc rhs+ , text "-- Defined" <+> pprLoc loc ]+ where+ pprLoc loc+ | isGoodSrcSpan loc+ = text "at" <+> ppr (srcSpanStart loc)++ | otherwise+ = text "in" <+>+ quotes (ppr (nameModule name))++{-+%************************************************************************+%* *+ Destructing coercions+%* *+%************************************************************************++Note [Function coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~+Remember that+ (->) :: forall r1 r2. TYPE r1 -> TYPE r2 -> TYPE LiftedRep++Hence+ FunCo r co1 co2 :: (s1->t1) ~r (s2->t2)+is short for+ TyConAppCo (->) co_rep1 co_rep2 co1 co2+where co_rep1, co_rep2 are the coercions on the representations.+-}+++-- | This breaks a 'Coercion' with type @T A B C ~ T D E F@ into+-- a list of 'Coercion's of kinds @A ~ D@, @B ~ E@ and @E ~ F@. Hence:+--+-- > decomposeCo 3 c = [nth 0 c, nth 1 c, nth 2 c]+decomposeCo :: Arity -> Coercion -> [Coercion]+decomposeCo arity co+ = [mkNthCo n co | n <- [0..(arity-1)] ]+ -- Remember, Nth is zero-indexed++decomposeFunCo :: Coercion -> (Coercion, Coercion)+-- Expects co :: (s1 -> t1) ~ (s2 -> t2)+-- Returns (co1 :: s1~s2, co2 :: t1~t2)+-- See Note [Function coercions] for the "2" and "3"+decomposeFunCo co = ASSERT2( all_ok, ppr co )+ (mkNthCo 2 co, mkNthCo 3 co)+ where+ Pair s1t1 s2t2 = coercionKind co+ all_ok = isFunTy s1t1 && isFunTy s2t2++-- | Attempts to obtain the type variable underlying a 'Coercion'+getCoVar_maybe :: Coercion -> Maybe CoVar+getCoVar_maybe (CoVarCo cv) = Just cv+getCoVar_maybe _ = Nothing++-- | Attempts to tease a coercion apart into a type constructor and the application+-- of a number of coercion arguments to that constructor+splitTyConAppCo_maybe :: Coercion -> Maybe (TyCon, [Coercion])+splitTyConAppCo_maybe (Refl r ty)+ = do { (tc, tys) <- splitTyConApp_maybe ty+ ; let args = zipWith mkReflCo (tyConRolesX r tc) tys+ ; return (tc, args) }+splitTyConAppCo_maybe (TyConAppCo _ tc cos) = Just (tc, cos)+splitTyConAppCo_maybe (FunCo _ arg res) = Just (funTyCon, cos)+ where cos = [mkRuntimeRepCo arg, mkRuntimeRepCo res, arg, res]+splitTyConAppCo_maybe _ = Nothing++-- first result has role equal to input; third result is Nominal+splitAppCo_maybe :: Coercion -> Maybe (Coercion, Coercion)+-- ^ Attempt to take a coercion application apart.+splitAppCo_maybe (AppCo co arg) = Just (co, arg)+splitAppCo_maybe (TyConAppCo r tc args)+ | mightBeUnsaturatedTyCon tc || args `lengthExceeds` tyConArity tc+ -- Never create unsaturated type family apps!+ , Just (args', arg') <- snocView args+ , Just arg'' <- setNominalRole_maybe arg'+ = Just ( mkTyConAppCo r tc args', arg'' )+ -- Use mkTyConAppCo to preserve the invariant+ -- that identity coercions are always represented by Refl++splitAppCo_maybe (Refl r ty)+ | Just (ty1, ty2) <- splitAppTy_maybe ty+ = Just (mkReflCo r ty1, mkNomReflCo ty2)+splitAppCo_maybe _ = Nothing++splitFunCo_maybe :: Coercion -> Maybe (Coercion, Coercion)+splitFunCo_maybe (FunCo _ arg res) = Just (arg, res)+splitFunCo_maybe _ = Nothing++splitForAllCo_maybe :: Coercion -> Maybe (TyVar, Coercion, Coercion)+splitForAllCo_maybe (ForAllCo tv k_co co) = Just (tv, k_co, co)+splitForAllCo_maybe _ = Nothing++-------------------------------------------------------+-- and some coercion kind stuff++coVarTypes :: CoVar -> Pair Type+coVarTypes cv+ | (_, _, ty1, ty2, _) <- coVarKindsTypesRole cv+ = Pair ty1 ty2++coVarKindsTypesRole :: CoVar -> (Kind,Kind,Type,Type,Role)+coVarKindsTypesRole cv+ | Just (tc, [k1,k2,ty1,ty2]) <- splitTyConApp_maybe (varType cv)+ = let role+ | tc `hasKey` eqPrimTyConKey = Nominal+ | tc `hasKey` eqReprPrimTyConKey = Representational+ | otherwise = panic "coVarKindsTypesRole"+ in (k1,k2,ty1,ty2,role)+ | otherwise = pprPanic "coVarKindsTypesRole, non coercion variable"+ (ppr cv $$ ppr (varType cv))++coVarKind :: CoVar -> Type+coVarKind cv+ = ASSERT( isCoVar cv )+ varType cv++coVarRole :: CoVar -> Role+coVarRole cv+ | tc `hasKey` eqPrimTyConKey+ = Nominal+ | tc `hasKey` eqReprPrimTyConKey+ = Representational+ | otherwise+ = pprPanic "coVarRole: unknown tycon" (ppr cv <+> dcolon <+> ppr (varType cv))++ where+ tc = case tyConAppTyCon_maybe (varType cv) of+ Just tc0 -> tc0+ Nothing -> pprPanic "coVarRole: not tyconapp" (ppr cv)++-- | Makes a coercion type from two types: the types whose equality+-- is proven by the relevant 'Coercion'+mkCoercionType :: Role -> Type -> Type -> Type+mkCoercionType Nominal = mkPrimEqPred+mkCoercionType Representational = mkReprPrimEqPred+mkCoercionType Phantom = \ty1 ty2 ->+ let ki1 = typeKind ty1+ ki2 = typeKind ty2+ in+ TyConApp eqPhantPrimTyCon [ki1, ki2, ty1, ty2]++mkHeteroCoercionType :: Role -> Kind -> Kind -> Type -> Type -> Type+mkHeteroCoercionType Nominal = mkHeteroPrimEqPred+mkHeteroCoercionType Representational = mkHeteroReprPrimEqPred+mkHeteroCoercionType Phantom = panic "mkHeteroCoercionType"++-- | Given a coercion @co1 :: (a :: TYPE r1) ~ (b :: TYPE r2)@,+-- produce a coercion @rep_co :: r1 ~ r2@.+mkRuntimeRepCo :: Coercion -> Coercion+mkRuntimeRepCo co+ = mkNthCo 0 kind_co+ where+ kind_co = mkKindCo co -- kind_co :: TYPE r1 ~ TYPE r2+ -- (up to silliness with Constraint)++isReflCoVar_maybe :: CoVar -> Maybe Coercion+-- If cv :: t~t then isReflCoVar_maybe cv = Just (Refl t)+isReflCoVar_maybe cv+ | Pair ty1 ty2 <- coVarTypes cv+ , ty1 `eqType` ty2+ = Just (Refl (coVarRole cv) ty1)+ | otherwise+ = Nothing++-- | Tests if this coercion is obviously reflexive. Guaranteed to work+-- very quickly. Sometimes a coercion can be reflexive, but not obviously+-- so. c.f. 'isReflexiveCo'+isReflCo :: Coercion -> Bool+isReflCo (Refl {}) = True+isReflCo _ = False++-- | Returns the type coerced if this coercion is reflexive. Guaranteed+-- to work very quickly. Sometimes a coercion can be reflexive, but not+-- obviously so. c.f. 'isReflexiveCo_maybe'+isReflCo_maybe :: Coercion -> Maybe (Type, Role)+isReflCo_maybe (Refl r ty) = Just (ty, r)+isReflCo_maybe _ = Nothing++-- | Slowly checks if the coercion is reflexive. Don't call this in a loop,+-- as it walks over the entire coercion.+isReflexiveCo :: Coercion -> Bool+isReflexiveCo = isJust . isReflexiveCo_maybe++-- | Extracts the coerced type from a reflexive coercion. This potentially+-- walks over the entire coercion, so avoid doing this in a loop.+isReflexiveCo_maybe :: Coercion -> Maybe (Type, Role)+isReflexiveCo_maybe (Refl r ty) = Just (ty, r)+isReflexiveCo_maybe co+ | ty1 `eqType` ty2+ = Just (ty1, r)+ | otherwise+ = Nothing+ where (Pair ty1 ty2, r) = coercionKindRole co++{-+%************************************************************************+%* *+ Building coercions+%* *+%************************************************************************++These "smart constructors" maintain the invariants listed in the definition+of Coercion, and they perform very basic optimizations.++Note [Role twiddling functions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++There are a plethora of functions for twiddling roles:++mkSubCo: Requires a nominal input coercion and always produces a+representational output. This is used when you (the programmer) are sure you+know exactly that role you have and what you want.++downgradeRole_maybe: This function takes both the input role and the output role+as parameters. (The *output* role comes first!) It can only *downgrade* a+role -- that is, change it from N to R or P, or from R to P. This one-way+behavior is why there is the "_maybe". If an upgrade is requested, this+function produces Nothing. This is used when you need to change the role of a+coercion, but you're not sure (as you're writing the code) of which roles are+involved.++This function could have been written using coercionRole to ascertain the role+of the input. But, that function is recursive, and the caller of downgradeRole_maybe+often knows the input role. So, this is more efficient.++downgradeRole: This is just like downgradeRole_maybe, but it panics if the+conversion isn't a downgrade.++setNominalRole_maybe: This is the only function that can *upgrade* a coercion.+The result (if it exists) is always Nominal. The input can be at any role. It+works on a "best effort" basis, as it should never be strictly necessary to+upgrade a coercion during compilation. It is currently only used within GHC in+splitAppCo_maybe. In order to be a proper inverse of mkAppCo, the second+coercion that splitAppCo_maybe returns must be nominal. But, it's conceivable+that splitAppCo_maybe is operating over a TyConAppCo that uses a+representational coercion. Hence the need for setNominalRole_maybe.+splitAppCo_maybe, in turn, is used only within coercion optimization -- thus,+it is not absolutely critical that setNominalRole_maybe be complete.++Note that setNominalRole_maybe will never upgrade a phantom UnivCo. Phantom+UnivCos are perfectly type-safe, whereas representational and nominal ones are+not. Indeed, `unsafeCoerce` is implemented via a representational UnivCo.+(Nominal ones are no worse than representational ones, so this function *will*+change a UnivCo Representational to a UnivCo Nominal.)++Conal Elliott also came across a need for this function while working with the+GHC API, as he was decomposing Core casts. The Core casts use representational+coercions, as they must, but his use case required nominal coercions (he was+building a GADT). So, that's why this function is exported from this module.++One might ask: shouldn't downgradeRole_maybe just use setNominalRole_maybe as+appropriate? I (Richard E.) have decided not to do this, because upgrading a+role is bizarre and a caller should have to ask for this behavior explicitly.++Note [mkTransAppCo]+~~~~~~~~~~~~~~~~~~~+Suppose we have++ co1 :: a ~R Maybe+ co2 :: b ~R Int++and we want++ co3 :: a b ~R Maybe Int++This seems sensible enough. But, we can't let (co3 = co1 co2), because+that's ill-roled! Note that mkAppCo requires a *nominal* second coercion.++The way around this is to use transitivity:++ co3 = (co1 <b>_N) ; (Maybe co2) :: a b ~R Maybe Int++Or, it's possible everything is the other way around:++ co1' :: Maybe ~R a+ co2' :: Int ~R b++and we want++ co3' :: Maybe Int ~R a b++then++ co3' = (Maybe co2') ; (co1' <b>_N)++This is exactly what `mkTransAppCo` builds for us. Information for all+the arguments tends to be to hand at call sites, so it's quicker than+using, say, coercionKind.++-}++mkReflCo :: Role -> Type -> Coercion+mkReflCo r ty+ = Refl r ty++-- | Make a representational reflexive coercion+mkRepReflCo :: Type -> Coercion+mkRepReflCo = mkReflCo Representational++-- | Make a nominal reflexive coercion+mkNomReflCo :: Type -> Coercion+mkNomReflCo = mkReflCo Nominal++-- | Apply a type constructor to a list of coercions. It is the+-- caller's responsibility to get the roles correct on argument coercions.+mkTyConAppCo :: HasDebugCallStack => Role -> TyCon -> [Coercion] -> Coercion+mkTyConAppCo r tc cos+ | tc `hasKey` funTyConKey+ , [_rep1, _rep2, co1, co2] <- cos -- See Note [Function coercions]+ = -- (a :: TYPE ra) -> (b :: TYPE rb) ~ (c :: TYPE rc) -> (d :: TYPE rd)+ -- rep1 :: ra ~ rc rep2 :: rb ~ rd+ -- co1 :: a ~ c co2 :: b ~ d+ mkFunCo r co1 co2++ -- Expand type synonyms+ | Just (tv_co_prs, rhs_ty, leftover_cos) <- expandSynTyCon_maybe tc cos+ = mkAppCos (liftCoSubst r (mkLiftingContext tv_co_prs) rhs_ty) leftover_cos++ | Just tys_roles <- traverse isReflCo_maybe cos+ = Refl r (mkTyConApp tc (map fst tys_roles)) -- See Note [Refl invariant]++ | otherwise = TyConAppCo r tc cos++-- | Build a function 'Coercion' from two other 'Coercion's. That is,+-- given @co1 :: a ~ b@ and @co2 :: x ~ y@ produce @co :: (a -> x) ~ (b -> y)@.+mkFunCo :: Role -> Coercion -> Coercion -> Coercion+mkFunCo r co1 co2+ -- See Note [Refl invariant]+ | Just (ty1, _) <- isReflCo_maybe co1+ , Just (ty2, _) <- isReflCo_maybe co2+ = Refl r (mkFunTy ty1 ty2)+ | otherwise = FunCo r co1 co2++-- | Make nested function 'Coercion's+mkFunCos :: Role -> [Coercion] -> Coercion -> Coercion+mkFunCos r cos res_co = foldr (mkFunCo r) res_co cos++-- | Apply a 'Coercion' to another 'Coercion'.+-- The second coercion must be Nominal, unless the first is Phantom.+-- If the first is Phantom, then the second can be either Phantom or Nominal.+mkAppCo :: Coercion -- ^ :: t1 ~r t2+ -> Coercion -- ^ :: s1 ~N s2, where s1 :: k1, s2 :: k2+ -> Coercion -- ^ :: t1 s1 ~r t2 s2+mkAppCo (Refl r ty1) arg+ | Just (ty2, _) <- isReflCo_maybe arg+ = Refl r (mkAppTy ty1 ty2)++ | Just (tc, tys) <- splitTyConApp_maybe ty1+ -- Expand type synonyms; a TyConAppCo can't have a type synonym (Trac #9102)+ = mkTyConAppCo r tc (zip_roles (tyConRolesX r tc) tys)+ where+ zip_roles (r1:_) [] = [downgradeRole r1 Nominal arg]+ zip_roles (r1:rs) (ty1:tys) = mkReflCo r1 ty1 : zip_roles rs tys+ zip_roles _ _ = panic "zip_roles" -- but the roles are infinite...++mkAppCo (TyConAppCo r tc args) arg+ = case r of+ Nominal -> mkTyConAppCo Nominal tc (args ++ [arg])+ Representational -> mkTyConAppCo Representational tc (args ++ [arg'])+ where new_role = (tyConRolesRepresentational tc) !! (length args)+ arg' = downgradeRole new_role Nominal arg+ Phantom -> mkTyConAppCo Phantom tc (args ++ [toPhantomCo arg])+mkAppCo co arg = AppCo co arg+-- Note, mkAppCo is careful to maintain invariants regarding+-- where Refl constructors appear; see the comments in the definition+-- of Coercion and the Note [Refl invariant] in TyCoRep.++-- | Applies multiple 'Coercion's to another 'Coercion', from left to right.+-- See also 'mkAppCo'.+mkAppCos :: Coercion+ -> [Coercion]+ -> Coercion+mkAppCos co1 cos = foldl mkAppCo co1 cos++-- | Like `mkAppCo`, but allows the second coercion to be other than+-- nominal. See Note [mkTransAppCo]. Role r3 cannot be more stringent+-- than either r1 or r2.+mkTransAppCo :: Role -- ^ r1+ -> Coercion -- ^ co1 :: ty1a ~r1 ty1b+ -> Type -- ^ ty1a+ -> Type -- ^ ty1b+ -> Role -- ^ r2+ -> Coercion -- ^ co2 :: ty2a ~r2 ty2b+ -> Type -- ^ ty2a+ -> Type -- ^ ty2b+ -> Role -- ^ r3+ -> Coercion -- ^ :: ty1a ty2a ~r3 ty1b ty2b+mkTransAppCo r1 co1 ty1a ty1b r2 co2 ty2a ty2b r3+-- How incredibly fiddly! Is there a better way??+ = case (r1, r2, r3) of+ (_, _, Phantom)+ -> mkPhantomCo kind_co (mkAppTy ty1a ty2a) (mkAppTy ty1b ty2b)+ where -- ty1a :: k1a -> k2a+ -- ty1b :: k1b -> k2b+ -- ty2a :: k1a+ -- ty2b :: k1b+ -- ty1a ty2a :: k2a+ -- ty1b ty2b :: k2b+ kind_co1 = mkKindCo co1 -- :: k1a -> k2a ~N k1b -> k2b+ kind_co = mkNthCo 1 kind_co1 -- :: k2a ~N k2b++ (_, _, Nominal)+ -> ASSERT( r1 == Nominal && r2 == Nominal )+ mkAppCo co1 co2+ (Nominal, Nominal, Representational)+ -> mkSubCo (mkAppCo co1 co2)+ (_, Nominal, Representational)+ -> ASSERT( r1 == Representational )+ mkAppCo co1 co2+ (Nominal, Representational, Representational)+ -> go (mkSubCo co1)+ (_ , _, Representational)+ -> ASSERT( r1 == Representational && r2 == Representational )+ go co1+ where+ go co1_repr+ | Just (tc1b, tys1b) <- splitTyConApp_maybe ty1b+ , nextRole ty1b == r2+ = (mkAppCo co1_repr (mkNomReflCo ty2a)) `mkTransCo`+ (mkTyConAppCo Representational tc1b+ (zipWith mkReflCo (tyConRolesRepresentational tc1b) tys1b+ ++ [co2]))++ | Just (tc1a, tys1a) <- splitTyConApp_maybe ty1a+ , nextRole ty1a == r2+ = (mkTyConAppCo Representational tc1a+ (zipWith mkReflCo (tyConRolesRepresentational tc1a) tys1a+ ++ [co2]))+ `mkTransCo`+ (mkAppCo co1_repr (mkNomReflCo ty2b))++ | otherwise+ = pprPanic "mkTransAppCo" (vcat [ ppr r1, ppr co1, ppr ty1a, ppr ty1b+ , ppr r2, ppr co2, ppr ty2a, ppr ty2b+ , ppr r3 ])++-- | Make a Coercion from a tyvar, a kind coercion, and a body coercion.+-- The kind of the tyvar should be the left-hand kind of the kind coercion.+mkForAllCo :: TyVar -> Coercion -> Coercion -> Coercion+mkForAllCo tv kind_co co+ | Refl r ty <- co+ , Refl {} <- kind_co+ = Refl r (mkInvForAllTy tv ty)+ | otherwise+ = ForAllCo tv kind_co co++-- | Make nested ForAllCos+mkForAllCos :: [(TyVar, Coercion)] -> Coercion -> Coercion+mkForAllCos bndrs (Refl r ty)+ = let (refls_rev'd, non_refls_rev'd) = span (isReflCo . snd) (reverse bndrs) in+ foldl (flip $ uncurry ForAllCo)+ (Refl r $ mkInvForAllTys (reverse (map fst refls_rev'd)) ty)+ non_refls_rev'd+mkForAllCos bndrs co = foldr (uncurry ForAllCo) co bndrs++-- | Make a Coercion quantified over a type variable;+-- the variable has the same type in both sides of the coercion+mkHomoForAllCos :: [TyVar] -> Coercion -> Coercion+mkHomoForAllCos tvs (Refl r ty)+ = Refl r (mkInvForAllTys tvs ty)+mkHomoForAllCos tvs ty = mkHomoForAllCos_NoRefl tvs ty++-- | Like 'mkHomoForAllCos', but doesn't check if the inner coercion+-- is reflexive.+mkHomoForAllCos_NoRefl :: [TyVar] -> Coercion -> Coercion+mkHomoForAllCos_NoRefl tvs orig_co = foldr go orig_co tvs+ where+ go tv co = ForAllCo tv (mkNomReflCo (tyVarKind tv)) co++mkCoVarCo :: CoVar -> Coercion+-- cv :: s ~# t+-- See Note [mkCoVarCo]+mkCoVarCo cv = CoVarCo cv++mkCoVarCos :: [CoVar] -> [Coercion]+mkCoVarCos = map mkCoVarCo++{- Note [mkCoVarCo]+~~~~~~~~~~~~~~~~~~~+In the past, mkCoVarCo optimised (c :: t~t) to (Refl t). That is+valid (although see Note [Unbound RULE binders] in Rules), but+it's a relatively expensive test and perhaps better done in+optCoercion. Not a big deal either way.+-}++-- | Extract a covar, if possible. This check is dirty. Be ashamed+-- of yourself. (It's dirty because it cares about the structure of+-- a coercion, which is morally reprehensible.)+isCoVar_maybe :: Coercion -> Maybe CoVar+isCoVar_maybe (CoVarCo cv) = Just cv+isCoVar_maybe _ = Nothing++mkAxInstCo :: Role -> CoAxiom br -> BranchIndex -> [Type] -> [Coercion]+ -> Coercion+-- mkAxInstCo can legitimately be called over-staturated;+-- i.e. with more type arguments than the coercion requires+mkAxInstCo role ax index tys cos+ | arity == n_tys = downgradeRole role ax_role $+ mkAxiomInstCo ax_br index (rtys `chkAppend` cos)+ | otherwise = ASSERT( arity < n_tys )+ downgradeRole role ax_role $+ mkAppCos (mkAxiomInstCo ax_br index+ (ax_args `chkAppend` cos))+ leftover_args+ where+ n_tys = length tys+ ax_br = toBranchedAxiom ax+ branch = coAxiomNthBranch ax_br index+ tvs = coAxBranchTyVars branch+ arity = length tvs+ arg_roles = coAxBranchRoles branch+ rtys = zipWith mkReflCo (arg_roles ++ repeat Nominal) tys+ (ax_args, leftover_args)+ = splitAt arity rtys+ ax_role = coAxiomRole ax++-- worker function; just checks to see if it should produce Refl+mkAxiomInstCo :: CoAxiom Branched -> BranchIndex -> [Coercion] -> Coercion+mkAxiomInstCo ax index args+ = ASSERT( coAxiomArity ax index == length args )+ AxiomInstCo ax index args++-- to be used only with unbranched axioms+mkUnbranchedAxInstCo :: Role -> CoAxiom Unbranched+ -> [Type] -> [Coercion] -> Coercion+mkUnbranchedAxInstCo role ax tys cos+ = mkAxInstCo role ax 0 tys cos++mkAxInstRHS :: CoAxiom br -> BranchIndex -> [Type] -> [Coercion] -> Type+-- Instantiate the axiom with specified types,+-- returning the instantiated RHS+-- A companion to mkAxInstCo:+-- mkAxInstRhs ax index tys = snd (coercionKind (mkAxInstCo ax index tys))+mkAxInstRHS ax index tys cos+ = ASSERT( tvs `equalLength` tys1 )+ mkAppTys rhs' tys2+ where+ branch = coAxiomNthBranch ax index+ tvs = coAxBranchTyVars branch+ cvs = coAxBranchCoVars branch+ (tys1, tys2) = splitAtList tvs tys+ rhs' = substTyWith tvs tys1 $+ substTyWithCoVars cvs cos $+ coAxBranchRHS branch++mkUnbranchedAxInstRHS :: CoAxiom Unbranched -> [Type] -> [Coercion] -> Type+mkUnbranchedAxInstRHS ax = mkAxInstRHS ax 0++-- | Return the left-hand type of the axiom, when the axiom is instantiated+-- at the types given.+mkAxInstLHS :: CoAxiom br -> BranchIndex -> [Type] -> [Coercion] -> Type+mkAxInstLHS ax index tys cos+ = ASSERT( tvs `equalLength` tys1 )+ mkTyConApp fam_tc (lhs_tys `chkAppend` tys2)+ where+ branch = coAxiomNthBranch ax index+ tvs = coAxBranchTyVars branch+ cvs = coAxBranchCoVars branch+ (tys1, tys2) = splitAtList tvs tys+ lhs_tys = substTysWith tvs tys1 $+ substTysWithCoVars cvs cos $+ coAxBranchLHS branch+ fam_tc = coAxiomTyCon ax++-- | Instantiate the left-hand side of an unbranched axiom+mkUnbranchedAxInstLHS :: CoAxiom Unbranched -> [Type] -> [Coercion] -> Type+mkUnbranchedAxInstLHS ax = mkAxInstLHS ax 0++-- | Manufacture an unsafe coercion from thin air.+-- Currently (May 14) this is used only to implement the+-- @unsafeCoerce#@ primitive. Optimise by pushing+-- down through type constructors.+mkUnsafeCo :: Role -> Type -> Type -> Coercion+mkUnsafeCo role ty1 ty2+ = mkUnivCo UnsafeCoerceProv role ty1 ty2++-- | Make a coercion from a coercion hole+mkHoleCo :: CoercionHole -> Role+ -> Type -> Type -> Coercion+mkHoleCo h r t1 t2 = mkUnivCo (HoleProv h) r t1 t2++-- | Make a universal coercion between two arbitrary types.+mkUnivCo :: UnivCoProvenance+ -> Role -- ^ role of the built coercion, "r"+ -> Type -- ^ t1 :: k1+ -> Type -- ^ t2 :: k2+ -> Coercion -- ^ :: t1 ~r t2+mkUnivCo prov role ty1 ty2+ | ty1 `eqType` ty2 = Refl role ty1+ | otherwise = UnivCo prov role ty1 ty2++-- | Create a symmetric version of the given 'Coercion' that asserts+-- equality between the same types but in the other "direction", so+-- a kind of @t1 ~ t2@ becomes the kind @t2 ~ t1@.+mkSymCo :: Coercion -> Coercion++-- Do a few simple optimizations, but don't bother pushing occurrences+-- of symmetry to the leaves; the optimizer will take care of that.+mkSymCo co@(Refl {}) = co+mkSymCo (SymCo co) = co+mkSymCo (SubCo (SymCo co)) = SubCo co+mkSymCo co = SymCo co++-- | Create a new 'Coercion' by composing the two given 'Coercion's transitively.+-- (co1 ; co2)+mkTransCo :: Coercion -> Coercion -> Coercion+mkTransCo co1 (Refl {}) = co1+mkTransCo (Refl {}) co2 = co2+mkTransCo co1 co2 = TransCo co1 co2++-- the Role is the desired one. It is the caller's responsibility to make+-- sure this request is reasonable+mkNthCoRole :: Role -> Int -> Coercion -> Coercion+mkNthCoRole role n co+ = downgradeRole role nth_role $ nth_co+ where+ nth_co = mkNthCo n co+ nth_role = coercionRole nth_co++mkNthCo :: Int -> Coercion -> Coercion+mkNthCo 0 (Refl _ ty)+ | Just (tv, _) <- splitForAllTy_maybe ty+ = Refl Nominal (tyVarKind tv)+mkNthCo n (Refl r ty)+ = ASSERT2( ok_tc_app ty n, ppr n $$ ppr ty )+ mkReflCo r' (tyConAppArgN n ty)+ where tc = tyConAppTyCon ty+ r' = nthRole r tc n++ ok_tc_app :: Type -> Int -> Bool+ ok_tc_app ty n+ | Just (_, tys) <- splitTyConApp_maybe ty+ = tys `lengthExceeds` n+ | isForAllTy ty -- nth:0 pulls out a kind coercion from a hetero forall+ = n == 0+ | otherwise+ = False++mkNthCo 0 (ForAllCo _ kind_co _) = kind_co+ -- If co :: (forall a1:k1. t1) ~ (forall a2:k2. t2)+ -- then (nth 0 co :: k1 ~ k2)++mkNthCo n co@(FunCo _ arg res)+ -- See Note [Function coercions]+ -- If FunCo _ arg_co res_co :: (s1:TYPE sk1 -> s2:TYPE sk2)+ -- ~ (t1:TYPE tk1 -> t2:TYPE tk2)+ -- Then we want to behave as if co was+ -- TyConAppCo argk_co resk_co arg_co res_co+ -- where+ -- argk_co :: sk1 ~ tk1 = mkNthCo 0 (mkKindCo arg_co)+ -- resk_co :: sk2 ~ tk2 = mkNthCo 0 (mkKindCo res_co)+ -- i.e. mkRuntimeRepCo+ = case n of+ 0 -> mkRuntimeRepCo arg+ 1 -> mkRuntimeRepCo res+ 2 -> arg+ 3 -> res+ _ -> pprPanic "mkNthCo(FunCo)" (ppr n $$ ppr co)++mkNthCo n (TyConAppCo _ _ arg_cos) = arg_cos `getNth` n++mkNthCo n co = NthCo n co++mkLRCo :: LeftOrRight -> Coercion -> Coercion+mkLRCo lr (Refl eq ty) = Refl eq (pickLR lr (splitAppTy ty))+mkLRCo lr co = LRCo lr co++-- | Instantiates a 'Coercion'.+mkInstCo :: Coercion -> Coercion -> Coercion+mkInstCo (ForAllCo tv _kind_co body_co) (Refl _ arg)+ = substCoWithUnchecked [tv] [arg] body_co+mkInstCo co arg = InstCo co arg++-- This could work harder to produce Refl coercions, but that would be+-- quite inefficient. Seems better not to try.+mkCoherenceCo :: Coercion -> Coercion -> Coercion+mkCoherenceCo co1 (Refl {}) = co1+mkCoherenceCo (CoherenceCo co1 co2) co3+ = CoherenceCo co1 (co2 `mkTransCo` co3)+mkCoherenceCo co1 co2 = CoherenceCo co1 co2++-- | A CoherenceCo c1 c2 applies the coercion c2 to the left-hand type+-- in the kind of c1. This function uses sym to get the coercion on the+-- right-hand type of c1. Thus, if c1 :: s ~ t, then mkCoherenceRightCo c1 c2+-- has the kind (s ~ (t |> c2)) down through type constructors.+-- The second coercion must be representational.+mkCoherenceRightCo :: Coercion -> Coercion -> Coercion+mkCoherenceRightCo c1 c2 = mkSymCo (mkCoherenceCo (mkSymCo c1) c2)++-- | An explicitly directed synonym of mkCoherenceCo. The second+-- coercion must be representational.+mkCoherenceLeftCo :: Coercion -> Coercion -> Coercion+mkCoherenceLeftCo = mkCoherenceCo++infixl 5 `mkCoherenceCo`+infixl 5 `mkCoherenceRightCo`+infixl 5 `mkCoherenceLeftCo`++-- | Given @co :: (a :: k) ~ (b :: k')@ produce @co' :: k ~ k'@.+mkKindCo :: Coercion -> Coercion+mkKindCo (Refl _ ty) = Refl Nominal (typeKind ty)+mkKindCo (UnivCo (PhantomProv h) _ _ _) = h+mkKindCo (UnivCo (ProofIrrelProv h) _ _ _) = h+mkKindCo co+ | Pair ty1 ty2 <- coercionKind co+ -- generally, calling coercionKind during coercion creation is a bad idea,+ -- as it can lead to exponential behavior. But, we don't have nested mkKindCos,+ -- so it's OK here.+ , let tk1 = typeKind ty1+ tk2 = typeKind ty2+ , tk1 `eqType` tk2+ = Refl Nominal tk1+ | otherwise+ = KindCo co++-- input coercion is Nominal; see also Note [Role twiddling functions]+mkSubCo :: Coercion -> Coercion+mkSubCo (Refl Nominal ty) = Refl Representational ty+mkSubCo (TyConAppCo Nominal tc cos)+ = TyConAppCo Representational tc (applyRoles tc cos)+mkSubCo (FunCo Nominal arg res)+ = FunCo Representational+ (downgradeRole Representational Nominal arg)+ (downgradeRole Representational Nominal res)+mkSubCo co = ASSERT2( coercionRole co == Nominal, ppr co <+> ppr (coercionRole co) )+ SubCo co++-- | Changes a role, but only a downgrade. See Note [Role twiddling functions]+downgradeRole_maybe :: Role -- ^ desired role+ -> Role -- ^ current role+ -> Coercion -> Maybe Coercion+-- In (downgradeRole_maybe dr cr co) it's a precondition that+-- cr = coercionRole co+downgradeRole_maybe Representational Nominal co = Just (mkSubCo co)+downgradeRole_maybe Nominal Representational _ = Nothing+downgradeRole_maybe Phantom Phantom co = Just co+downgradeRole_maybe Phantom _ co = Just (toPhantomCo co)+downgradeRole_maybe _ Phantom _ = Nothing+downgradeRole_maybe _ _ co = Just co++-- | Like 'downgradeRole_maybe', but panics if the change isn't a downgrade.+-- See Note [Role twiddling functions]+downgradeRole :: Role -- desired role+ -> Role -- current role+ -> Coercion -> Coercion+downgradeRole r1 r2 co+ = case downgradeRole_maybe r1 r2 co of+ Just co' -> co'+ Nothing -> pprPanic "downgradeRole" (ppr co)++-- | If the EqRel is ReprEq, makes a SubCo; otherwise, does nothing.+-- Note that the input coercion should always be nominal.+maybeSubCo :: EqRel -> Coercion -> Coercion+maybeSubCo NomEq = id+maybeSubCo ReprEq = mkSubCo+++mkAxiomRuleCo :: CoAxiomRule -> [Coercion] -> Coercion+mkAxiomRuleCo = AxiomRuleCo++-- | Make a "coercion between coercions".+mkProofIrrelCo :: Role -- ^ role of the created coercion, "r"+ -> Coercion -- ^ :: phi1 ~N phi2+ -> Coercion -- ^ g1 :: phi1+ -> Coercion -- ^ g2 :: phi2+ -> Coercion -- ^ :: g1 ~r g2++-- if the two coercion prove the same fact, I just don't care what+-- the individual coercions are.+mkProofIrrelCo r (Refl {}) g _ = Refl r (CoercionTy g)+mkProofIrrelCo r kco g1 g2 = mkUnivCo (ProofIrrelProv kco) r+ (mkCoercionTy g1) (mkCoercionTy g2)++{-+%************************************************************************+%* *+ Roles+%* *+%************************************************************************+-}++-- | Converts a coercion to be nominal, if possible.+-- See Note [Role twiddling functions]+setNominalRole_maybe :: Coercion -> Maybe Coercion+setNominalRole_maybe co+ | Nominal <- coercionRole co = Just co+setNominalRole_maybe (SubCo co) = Just co+setNominalRole_maybe (Refl _ ty) = Just $ Refl Nominal ty+setNominalRole_maybe (TyConAppCo Representational tc cos)+ = do { cos' <- mapM setNominalRole_maybe cos+ ; return $ TyConAppCo Nominal tc cos' }+setNominalRole_maybe (FunCo Representational co1 co2)+ = do { co1' <- setNominalRole_maybe co1+ ; co2' <- setNominalRole_maybe co2+ ; return $ FunCo Nominal co1' co2'+ }+setNominalRole_maybe (SymCo co)+ = SymCo <$> setNominalRole_maybe co+setNominalRole_maybe (TransCo co1 co2)+ = TransCo <$> setNominalRole_maybe co1 <*> setNominalRole_maybe co2+setNominalRole_maybe (AppCo co1 co2)+ = AppCo <$> setNominalRole_maybe co1 <*> pure co2+setNominalRole_maybe (ForAllCo tv kind_co co)+ = ForAllCo tv kind_co <$> setNominalRole_maybe co+setNominalRole_maybe (NthCo n co)+ = NthCo n <$> setNominalRole_maybe co+setNominalRole_maybe (InstCo co arg)+ = InstCo <$> setNominalRole_maybe co <*> pure arg+setNominalRole_maybe (CoherenceCo co1 co2)+ = CoherenceCo <$> setNominalRole_maybe co1 <*> pure co2+setNominalRole_maybe (UnivCo prov _ co1 co2)+ | case prov of UnsafeCoerceProv -> True -- it's always unsafe+ PhantomProv _ -> False -- should always be phantom+ ProofIrrelProv _ -> True -- it's always safe+ PluginProv _ -> False -- who knows? This choice is conservative.+ HoleProv _ -> False -- no no no.+ = Just $ UnivCo prov Nominal co1 co2+setNominalRole_maybe _ = Nothing++-- | Make a phantom coercion between two types. The coercion passed+-- in must be a nominal coercion between the kinds of the+-- types.+mkPhantomCo :: Coercion -> Type -> Type -> Coercion+mkPhantomCo h t1 t2+ = mkUnivCo (PhantomProv h) Phantom t1 t2++-- | Make a phantom coercion between two types of the same kind.+mkHomoPhantomCo :: Type -> Type -> Coercion+mkHomoPhantomCo t1 t2+ = ASSERT( k1 `eqType` typeKind t2 )+ mkPhantomCo (mkNomReflCo k1) t1 t2+ where+ k1 = typeKind t1++-- takes any coercion and turns it into a Phantom coercion+toPhantomCo :: Coercion -> Coercion+toPhantomCo co+ = mkPhantomCo (mkKindCo co) ty1 ty2+ where Pair ty1 ty2 = coercionKind co++-- Convert args to a TyConAppCo Nominal to the same TyConAppCo Representational+applyRoles :: TyCon -> [Coercion] -> [Coercion]+applyRoles tc cos+ = zipWith (\r -> downgradeRole r Nominal) (tyConRolesRepresentational tc) cos++-- the Role parameter is the Role of the TyConAppCo+-- defined here because this is intimiately concerned with the implementation+-- of TyConAppCo+tyConRolesX :: Role -> TyCon -> [Role]+tyConRolesX Representational tc = tyConRolesRepresentational tc+tyConRolesX role _ = repeat role++tyConRolesRepresentational :: TyCon -> [Role]+tyConRolesRepresentational tc = tyConRoles tc ++ repeat Nominal++nthRole :: Role -> TyCon -> Int -> Role+nthRole Nominal _ _ = Nominal+nthRole Phantom _ _ = Phantom+nthRole Representational tc n+ = (tyConRolesRepresentational tc) `getNth` n++ltRole :: Role -> Role -> Bool+-- Is one role "less" than another?+-- Nominal < Representational < Phantom+ltRole Phantom _ = False+ltRole Representational Phantom = True+ltRole Representational _ = False+ltRole Nominal Nominal = False+ltRole Nominal _ = True++-------------------------------++-- | like mkKindCo, but aggressively & recursively optimizes to avoid using+-- a KindCo constructor. The output role is nominal.+promoteCoercion :: Coercion -> Coercion++-- First cases handles anything that should yield refl.+promoteCoercion co = case co of++ _ | ki1 `eqType` ki2+ -> mkNomReflCo (typeKind ty1)+ -- no later branch should return refl+ -- The ASSERT( False )s throughout+ -- are these cases explicitly, but they should never fire.++ Refl _ ty -> ASSERT( False )+ mkNomReflCo (typeKind ty)++ TyConAppCo _ tc args+ | Just co' <- instCoercions (mkNomReflCo (tyConKind tc)) args+ -> co'+ | otherwise+ -> mkKindCo co++ AppCo co1 arg+ | Just co' <- instCoercion (coercionKind (mkKindCo co1))+ (promoteCoercion co1) arg+ -> co'+ | otherwise+ -> mkKindCo co++ ForAllCo _ _ g+ -> promoteCoercion g++ FunCo _ _ _+ -> mkNomReflCo liftedTypeKind++ CoVarCo {}+ -> mkKindCo co++ AxiomInstCo {}+ -> mkKindCo co++ UnivCo UnsafeCoerceProv _ t1 t2+ -> mkUnsafeCo Nominal (typeKind t1) (typeKind t2)+ UnivCo (PhantomProv kco) _ _ _+ -> kco+ UnivCo (ProofIrrelProv kco) _ _ _+ -> kco+ UnivCo (PluginProv _) _ _ _+ -> mkKindCo co+ UnivCo (HoleProv _) _ _ _+ -> mkKindCo co++ SymCo g+ -> mkSymCo (promoteCoercion g)++ TransCo co1 co2+ -> mkTransCo (promoteCoercion co1) (promoteCoercion co2)++ NthCo n co1+ | Just (_, args) <- splitTyConAppCo_maybe co1+ , n < length args+ -> promoteCoercion (args !! n)++ | Just _ <- splitForAllCo_maybe co+ , n == 0+ -> ASSERT( False ) mkNomReflCo liftedTypeKind++ | otherwise+ -> mkKindCo co++ LRCo lr co1+ | Just (lco, rco) <- splitAppCo_maybe co1+ -> case lr of+ CLeft -> promoteCoercion lco+ CRight -> promoteCoercion rco++ | otherwise+ -> mkKindCo co++ InstCo g _+ -> promoteCoercion g++ CoherenceCo g h+ -> mkSymCo h `mkTransCo` promoteCoercion g++ KindCo _+ -> ASSERT( False )+ mkNomReflCo liftedTypeKind++ SubCo g+ -> promoteCoercion g++ AxiomRuleCo {}+ -> mkKindCo co++ where+ Pair ty1 ty2 = coercionKind co+ ki1 = typeKind ty1+ ki2 = typeKind ty2++-- | say @g = promoteCoercion h@. Then, @instCoercion g w@ yields @Just g'@,+-- where @g' = promoteCoercion (h w)@.+-- fails if this is not possible, if @g@ coerces between a forall and an ->+-- or if second parameter has a representational role and can't be used+-- with an InstCo. The result role matches is representational.+instCoercion :: Pair Type -- type of the first coercion+ -> Coercion -- ^ must be nominal+ -> Coercion+ -> Maybe Coercion+instCoercion (Pair lty rty) g w+ | isForAllTy lty && isForAllTy rty+ , Just w' <- setNominalRole_maybe w+ = Just $ mkInstCo g w'+ | isFunTy lty && isFunTy rty+ = Just $ mkNthCo 3 g -- extract result type, which is the 4th argument to (->)+ | otherwise -- one forall, one funty...+ = Nothing+ where++instCoercions :: Coercion -> [Coercion] -> Maybe Coercion+instCoercions g ws+ = let arg_ty_pairs = map coercionKind ws in+ snd <$> foldM go (coercionKind g, g) (zip arg_ty_pairs ws)+ where+ go :: (Pair Type, Coercion) -> (Pair Type, Coercion)+ -> Maybe (Pair Type, Coercion)+ go (g_tys, g) (w_tys, w)+ = do { g' <- instCoercion g_tys g w+ ; return (piResultTy <$> g_tys <*> w_tys, g') }++-- | Creates a new coercion with both of its types casted by different casts+-- castCoercionKind g h1 h2, where g :: t1 ~ t2, has type (t1 |> h1) ~ (t2 |> h2)+-- The second and third coercions must be nominal.+castCoercionKind :: Coercion -> Coercion -> Coercion -> Coercion+castCoercionKind g h1 h2+ = g `mkCoherenceLeftCo` h1 `mkCoherenceRightCo` h2++-- See note [Newtype coercions] in TyCon++mkPiCos :: Role -> [Var] -> Coercion -> Coercion+mkPiCos r vs co = foldr (mkPiCo r) co vs++-- | Make a forall 'Coercion', where both types related by the coercion+-- are quantified over the same type variable.+mkPiCo :: Role -> Var -> Coercion -> Coercion+mkPiCo r v co | isTyVar v = mkHomoForAllCos [v] co+ | otherwise = mkFunCo r (mkReflCo r (varType v)) co++-- The second coercion is sometimes lifted (~) and sometimes unlifted (~#).+-- So, we have to make sure to supply the right parameter to decomposeCo.+-- mkCoCast (c :: s1 ~# t1) (g :: (s1 ~# s2) ~# (t1 ~# t2)) :: s2 ~# t2+-- Both coercions *must* have the same role.+mkCoCast :: Coercion -> Coercion -> Coercion+mkCoCast c g+ = mkSymCo g1 `mkTransCo` c `mkTransCo` g2+ where+ -- g :: (s1 ~# s2) ~# (t1 ~# t2)+ -- g1 :: s1 ~# t1+ -- g2 :: s2 ~# t2+ (_, args) = splitTyConApp (pFst $ coercionKind g)+ n_args = length args+ co_list = decomposeCo n_args g+ g1 = co_list `getNth` (n_args - 2)+ g2 = co_list `getNth` (n_args - 1)++{-+%************************************************************************+%* *+ Newtypes+%* *+%************************************************************************+-}++-- | If @co :: T ts ~ rep_ty@ then:+--+-- > instNewTyCon_maybe T ts = Just (rep_ty, co)+--+-- Checks for a newtype, and for being saturated+instNewTyCon_maybe :: TyCon -> [Type] -> Maybe (Type, Coercion)+instNewTyCon_maybe tc tys+ | Just (tvs, ty, co_tc) <- unwrapNewTyConEtad_maybe tc -- Check for newtype+ , tvs `leLength` tys -- Check saturated enough+ = Just (applyTysX tvs ty tys, mkUnbranchedAxInstCo Representational co_tc tys [])+ | otherwise+ = Nothing++{-+************************************************************************+* *+ Type normalisation+* *+************************************************************************+-}++-- | A function to check if we can reduce a type by one step. Used+-- with 'topNormaliseTypeX'.+type NormaliseStepper ev = RecTcChecker+ -> TyCon -- tc+ -> [Type] -- tys+ -> NormaliseStepResult ev++-- | The result of stepping in a normalisation function.+-- See 'topNormaliseTypeX'.+data NormaliseStepResult ev+ = NS_Done -- ^ Nothing more to do+ | NS_Abort -- ^ Utter failure. The outer function should fail too.+ | NS_Step RecTcChecker Type ev -- ^ We stepped, yielding new bits;+ -- ^ ev is evidence;+ -- Usually a co :: old type ~ new type++mapStepResult :: (ev1 -> ev2)+ -> NormaliseStepResult ev1 -> NormaliseStepResult ev2+mapStepResult f (NS_Step rec_nts ty ev) = NS_Step rec_nts ty (f ev)+mapStepResult _ NS_Done = NS_Done+mapStepResult _ NS_Abort = NS_Abort++-- | Try one stepper and then try the next, if the first doesn't make+-- progress.+-- So if it returns NS_Done, it means that both steppers are satisfied+composeSteppers :: NormaliseStepper ev -> NormaliseStepper ev+ -> NormaliseStepper ev+composeSteppers step1 step2 rec_nts tc tys+ = case step1 rec_nts tc tys of+ success@(NS_Step {}) -> success+ NS_Done -> step2 rec_nts tc tys+ NS_Abort -> NS_Abort++-- | A 'NormaliseStepper' that unwraps newtypes, careful not to fall into+-- a loop. If it would fall into a loop, it produces 'NS_Abort'.+unwrapNewTypeStepper :: NormaliseStepper Coercion+unwrapNewTypeStepper rec_nts tc tys+ | Just (ty', co) <- instNewTyCon_maybe tc tys+ = case checkRecTc rec_nts tc of+ Just rec_nts' -> NS_Step rec_nts' ty' co+ Nothing -> NS_Abort++ | otherwise+ = NS_Done++-- | A general function for normalising the top-level of a type. It continues+-- to use the provided 'NormaliseStepper' until that function fails, and then+-- this function returns. The roles of the coercions produced by the+-- 'NormaliseStepper' must all be the same, which is the role returned from+-- the call to 'topNormaliseTypeX'.+--+-- Typically ev is Coercion.+--+-- If topNormaliseTypeX step plus ty = Just (ev, ty')+-- then ty ~ev1~ t1 ~ev2~ t2 ... ~evn~ ty'+-- and ev = ev1 `plus` ev2 `plus` ... `plus` evn+-- If it returns Nothing then no newtype unwrapping could happen+topNormaliseTypeX :: NormaliseStepper ev -> (ev -> ev -> ev)+ -> Type -> Maybe (ev, Type)+topNormaliseTypeX stepper plus ty+ | Just (tc, tys) <- splitTyConApp_maybe ty+ , NS_Step rec_nts ty' ev <- stepper initRecTc tc tys+ = go rec_nts ev ty'+ | otherwise+ = Nothing+ where+ go rec_nts ev ty+ | Just (tc, tys) <- splitTyConApp_maybe ty+ = case stepper rec_nts tc tys of+ NS_Step rec_nts' ty' ev' -> go rec_nts' (ev `plus` ev') ty'+ NS_Done -> Just (ev, ty)+ NS_Abort -> Nothing++ | otherwise+ = Just (ev, ty)++topNormaliseNewType_maybe :: Type -> Maybe (Coercion, Type)+-- ^ Sometimes we want to look through a @newtype@ and get its associated coercion.+-- This function strips off @newtype@ layers enough to reveal something that isn't+-- a @newtype@. Specifically, here's the invariant:+--+-- > topNormaliseNewType_maybe rec_nts ty = Just (co, ty')+--+-- then (a) @co : ty0 ~ ty'@.+-- (b) ty' is not a newtype.+--+-- The function returns @Nothing@ for non-@newtypes@,+-- or unsaturated applications+--+-- This function does *not* look through type families, because it has no access to+-- the type family environment. If you do have that at hand, consider to use+-- topNormaliseType_maybe, which should be a drop-in replacement for+-- topNormaliseNewType_maybe+-- If topNormliseNewType_maybe ty = Just (co, ty'), then co : ty ~R ty'+topNormaliseNewType_maybe ty+ = topNormaliseTypeX unwrapNewTypeStepper mkTransCo ty++{-+%************************************************************************+%* *+ Comparison of coercions+%* *+%************************************************************************+-}++-- | Syntactic equality of coercions+eqCoercion :: Coercion -> Coercion -> Bool+eqCoercion = eqType `on` coercionType++-- | Compare two 'Coercion's, with respect to an RnEnv2+eqCoercionX :: RnEnv2 -> Coercion -> Coercion -> Bool+eqCoercionX env = eqTypeX env `on` coercionType++{-+%************************************************************************+%* *+ "Lifting" substitution+ [(TyCoVar,Coercion)] -> Type -> Coercion+%* *+%************************************************************************++Note [Lifting coercions over types: liftCoSubst]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The KPUSH rule deals with this situation+ data T a = MkK (a -> Maybe a)+ g :: T t1 ~ K t2+ x :: t1 -> Maybe t1++ case (K @t1 x) |> g of+ K (y:t2 -> Maybe t2) -> rhs++We want to push the coercion inside the constructor application.+So we do this++ g' :: t1~t2 = Nth 0 g++ case K @t2 (x |> g' -> Maybe g') of+ K (y:t2 -> Maybe t2) -> rhs++The crucial operation is that we+ * take the type of K's argument: a -> Maybe a+ * and substitute g' for a+thus giving *coercion*. This is what liftCoSubst does.++In the presence of kind coercions, this is a bit+of a hairy operation. So, we refer you to the paper introducing kind coercions,+available at www.cis.upenn.edu/~sweirich/papers/fckinds-extended.pdf+-}++-- ----------------------------------------------------+-- See Note [Lifting coercions over types: liftCoSubst]+-- ----------------------------------------------------++data LiftingContext = LC TCvSubst LiftCoEnv+ -- in optCoercion, we need to lift when optimizing InstCo.+ -- See Note [Optimising InstCo] in OptCoercion+ -- We thus propagate the substitution from OptCoercion here.++instance Outputable LiftingContext where+ ppr (LC _ env) = hang (text "LiftingContext:") 2 (ppr env)++type LiftCoEnv = VarEnv Coercion+ -- Maps *type variables* to *coercions*.+ -- That's the whole point of this function!++-- like liftCoSubstWith, but allows for existentially-bound types as well+liftCoSubstWithEx :: Role -- desired role for output coercion+ -> [TyVar] -- universally quantified tyvars+ -> [Coercion] -- coercions to substitute for those+ -> [TyVar] -- existentially quantified tyvars+ -> [Type] -- types to be bound to ex vars+ -> (Type -> Coercion, [Type]) -- (lifting function, converted ex args)+liftCoSubstWithEx role univs omegas exs rhos+ = let theta = mkLiftingContext (zipEqual "liftCoSubstWithExU" univs omegas)+ psi = extendLiftingContextEx theta (zipEqual "liftCoSubstWithExX" exs rhos)+ in (ty_co_subst psi role, substTyVars (lcSubstRight psi) exs)++liftCoSubstWith :: Role -> [TyCoVar] -> [Coercion] -> Type -> Coercion+-- NB: This really can be called with CoVars, when optimising axioms.+liftCoSubstWith r tvs cos ty+ = liftCoSubst r (mkLiftingContext $ zipEqual "liftCoSubstWith" tvs cos) ty++-- | @liftCoSubst role lc ty@ produces a coercion (at role @role@)+-- that coerces between @lc_left(ty)@ and @lc_right(ty)@, where+-- @lc_left@ is a substitution mapping type variables to the left-hand+-- types of the mapped coercions in @lc@, and similar for @lc_right@.+liftCoSubst :: Role -> LiftingContext -> Type -> Coercion+liftCoSubst r lc@(LC subst env) ty+ | isEmptyVarEnv env = Refl r (substTy subst ty)+ | otherwise = ty_co_subst lc r ty++emptyLiftingContext :: InScopeSet -> LiftingContext+emptyLiftingContext in_scope = LC (mkEmptyTCvSubst in_scope) emptyVarEnv++mkLiftingContext :: [(TyCoVar,Coercion)] -> LiftingContext+mkLiftingContext pairs+ = LC (mkEmptyTCvSubst $ mkInScopeSet $ tyCoVarsOfCos (map snd pairs))+ (mkVarEnv pairs)++mkSubstLiftingContext :: TCvSubst -> LiftingContext+mkSubstLiftingContext subst = LC subst emptyVarEnv++-- | Extend a lifting context with a new /type/ mapping.+extendLiftingContext :: LiftingContext -- ^ original LC+ -> TyVar -- ^ new variable to map...+ -> Coercion -- ^ ...to this lifted version+ -> LiftingContext+extendLiftingContext (LC subst env) tv arg+ = ASSERT( isTyVar tv )+ LC subst (extendVarEnv env tv arg)++-- | Extend a lifting context with existential-variable bindings.+-- This follows the lifting context extension definition in the+-- "FC with Explicit Kind Equality" paper.+extendLiftingContextEx :: LiftingContext -- ^ original lifting context+ -> [(TyVar,Type)] -- ^ ex. var / value pairs+ -> LiftingContext+-- Note that this is more involved than extendLiftingContext. That function+-- takes a coercion to extend with, so it's assumed that the caller has taken+-- into account any of the kind-changing stuff worried about here.+extendLiftingContextEx lc [] = lc+extendLiftingContextEx lc@(LC subst env) ((v,ty):rest)+-- This function adds bindings for *Nominal* coercions. Why? Because it+-- works with existentially bound variables, which are considered to have+-- nominal roles.+ = let lc' = LC (subst `extendTCvInScopeSet` tyCoVarsOfType ty)+ (extendVarEnv env v (mkSymCo $ mkCoherenceCo+ (mkNomReflCo ty)+ (ty_co_subst lc Nominal (tyVarKind v))))+ in extendLiftingContextEx lc' rest++-- | Erase the environments in a lifting context+zapLiftingContext :: LiftingContext -> LiftingContext+zapLiftingContext (LC subst _) = LC (zapTCvSubst subst) emptyVarEnv++-- | Like 'substForAllCoBndr', but works on a lifting context+substForAllCoBndrCallbackLC :: Bool+ -> (Coercion -> Coercion)+ -> LiftingContext -> TyVar -> Coercion+ -> (LiftingContext, TyVar, Coercion)+substForAllCoBndrCallbackLC sym sco (LC subst lc_env) tv co+ = (LC subst' lc_env, tv', co')+ where+ (subst', tv', co') = substForAllCoBndrCallback sym sco subst tv co++-- | The \"lifting\" operation which substitutes coercions for type+-- variables in a type to produce a coercion.+--+-- For the inverse operation, see 'liftCoMatch'+ty_co_subst :: LiftingContext -> Role -> Type -> Coercion+ty_co_subst lc role ty+ = go role ty+ where+ go :: Role -> Type -> Coercion+ go Phantom ty = lift_phantom ty+ go r (TyVarTy tv) = expectJust "ty_co_subst bad roles" $+ liftCoSubstTyVar lc r tv+ go r (AppTy ty1 ty2) = mkAppCo (go r ty1) (go Nominal ty2)+ go r (TyConApp tc tys) = mkTyConAppCo r tc (zipWith go (tyConRolesX r tc) tys)+ go r (FunTy ty1 ty2) = mkFunCo r (go r ty1) (go r ty2)+ go r (ForAllTy (TvBndr v _) ty)+ = let (lc', v', h) = liftCoSubstVarBndr lc v in+ mkForAllCo v' h $! ty_co_subst lc' r ty+ go r ty@(LitTy {}) = ASSERT( r == Nominal )+ mkReflCo r ty+ go r (CastTy ty co) = castCoercionKind (go r ty) (substLeftCo lc co)+ (substRightCo lc co)+ go r (CoercionTy co) = mkProofIrrelCo r kco (substLeftCo lc co)+ (substRightCo lc co)+ where kco = go Nominal (coercionType co)++ lift_phantom ty = mkPhantomCo (go Nominal (typeKind ty))+ (substTy (lcSubstLeft lc) ty)+ (substTy (lcSubstRight lc) ty)++{-+Note [liftCoSubstTyVar]+~~~~~~~~~~~~~~~~~~~~~~~~~+This function can fail if a coercion in the environment is of too low a role.++liftCoSubstTyVar is called from two places: in liftCoSubst (naturally), and+also in matchAxiom in OptCoercion. From liftCoSubst, the so-called lifting+lemma guarantees that the roles work out. If we fail in this+case, we really should panic -- something is deeply wrong. But, in matchAxiom,+failing is fine. matchAxiom is trying to find a set of coercions+that match, but it may fail, and this is healthy behavior.+-}++-- See Note [liftCoSubstTyVar]+liftCoSubstTyVar :: LiftingContext -> Role -> TyVar -> Maybe Coercion+liftCoSubstTyVar (LC subst env) r v+ | Just co_arg <- lookupVarEnv env v+ = downgradeRole_maybe r (coercionRole co_arg) co_arg++ | otherwise+ = Just $ Refl r (substTyVar subst v)++liftCoSubstVarBndr :: LiftingContext -> TyVar+ -> (LiftingContext, TyVar, Coercion)+liftCoSubstVarBndr lc tv+ = let (lc', tv', h, _) = liftCoSubstVarBndrCallback callback lc tv in+ (lc', tv', h)+ where+ callback lc' ty' = (ty_co_subst lc' Nominal ty', ())++-- the callback must produce a nominal coercion+liftCoSubstVarBndrCallback :: (LiftingContext -> Type -> (Coercion, a))+ -> LiftingContext -> TyVar+ -> (LiftingContext, TyVar, Coercion, a)+liftCoSubstVarBndrCallback fun lc@(LC subst cenv) old_var+ = ( LC (subst `extendTCvInScope` new_var) new_cenv+ , new_var, eta, stuff )+ where+ old_kind = tyVarKind old_var+ (eta, stuff) = fun lc old_kind+ Pair k1 _ = coercionKind eta+ new_var = uniqAway (getTCvInScope subst) (setVarType old_var k1)++ lifted = Refl Nominal (TyVarTy new_var)+ new_cenv = extendVarEnv cenv old_var lifted++-- | Is a var in the domain of a lifting context?+isMappedByLC :: TyCoVar -> LiftingContext -> Bool+isMappedByLC tv (LC _ env) = tv `elemVarEnv` env++-- If [a |-> g] is in the substitution and g :: t1 ~ t2, substitute a for t1+-- If [a |-> (g1, g2)] is in the substitution, substitute a for g1+substLeftCo :: LiftingContext -> Coercion -> Coercion+substLeftCo lc co+ = substCo (lcSubstLeft lc) co++-- Ditto, but for t2 and g2+substRightCo :: LiftingContext -> Coercion -> Coercion+substRightCo lc co+ = substCo (lcSubstRight lc) co++-- | Apply "sym" to all coercions in a 'LiftCoEnv'+swapLiftCoEnv :: LiftCoEnv -> LiftCoEnv+swapLiftCoEnv = mapVarEnv mkSymCo++lcSubstLeft :: LiftingContext -> TCvSubst+lcSubstLeft (LC subst lc_env) = liftEnvSubstLeft subst lc_env++lcSubstRight :: LiftingContext -> TCvSubst+lcSubstRight (LC subst lc_env) = liftEnvSubstRight subst lc_env++liftEnvSubstLeft :: TCvSubst -> LiftCoEnv -> TCvSubst+liftEnvSubstLeft = liftEnvSubst pFst++liftEnvSubstRight :: TCvSubst -> LiftCoEnv -> TCvSubst+liftEnvSubstRight = liftEnvSubst pSnd++liftEnvSubst :: (forall a. Pair a -> a) -> TCvSubst -> LiftCoEnv -> TCvSubst+liftEnvSubst selector subst lc_env+ = composeTCvSubst (TCvSubst emptyInScopeSet tenv cenv) subst+ where+ pairs = nonDetUFMToList lc_env+ -- It's OK to use nonDetUFMToList here because we+ -- immediately forget the ordering by creating+ -- a VarEnv+ (tpairs, cpairs) = partitionWith ty_or_co pairs+ tenv = mkVarEnv_Directly tpairs+ cenv = mkVarEnv_Directly cpairs++ ty_or_co :: (Unique, Coercion) -> Either (Unique, Type) (Unique, Coercion)+ ty_or_co (u, co)+ | Just equality_co <- isCoercionTy_maybe equality_ty+ = Right (u, equality_co)+ | otherwise+ = Left (u, equality_ty)+ where+ equality_ty = selector (coercionKind co)++-- | Extract the underlying substitution from the LiftingContext+lcTCvSubst :: LiftingContext -> TCvSubst+lcTCvSubst (LC subst _) = subst++-- | Get the 'InScopeSet' from a 'LiftingContext'+lcInScopeSet :: LiftingContext -> InScopeSet+lcInScopeSet (LC subst _) = getTCvInScope subst++{-+%************************************************************************+%* *+ Sequencing on coercions+%* *+%************************************************************************+-}++seqCo :: Coercion -> ()+seqCo (Refl r ty) = r `seq` seqType ty+seqCo (TyConAppCo r tc cos) = r `seq` tc `seq` seqCos cos+seqCo (AppCo co1 co2) = seqCo co1 `seq` seqCo co2+seqCo (ForAllCo tv k co) = seqType (tyVarKind tv) `seq` seqCo k+ `seq` seqCo co+seqCo (FunCo r co1 co2) = r `seq` seqCo co1 `seq` seqCo co2+seqCo (CoVarCo cv) = cv `seq` ()+seqCo (AxiomInstCo con ind cos) = con `seq` ind `seq` seqCos cos+seqCo (UnivCo p r t1 t2)+ = seqProv p `seq` r `seq` seqType t1 `seq` seqType t2+seqCo (SymCo co) = seqCo co+seqCo (TransCo co1 co2) = seqCo co1 `seq` seqCo co2+seqCo (NthCo n co) = n `seq` seqCo co+seqCo (LRCo lr co) = lr `seq` seqCo co+seqCo (InstCo co arg) = seqCo co `seq` seqCo arg+seqCo (CoherenceCo co1 co2) = seqCo co1 `seq` seqCo co2+seqCo (KindCo co) = seqCo co+seqCo (SubCo co) = seqCo co+seqCo (AxiomRuleCo _ cs) = seqCos cs++seqProv :: UnivCoProvenance -> ()+seqProv UnsafeCoerceProv = ()+seqProv (PhantomProv co) = seqCo co+seqProv (ProofIrrelProv co) = seqCo co+seqProv (PluginProv _) = ()+seqProv (HoleProv _) = ()++seqCos :: [Coercion] -> ()+seqCos [] = ()+seqCos (co:cos) = seqCo co `seq` seqCos cos++{-+%************************************************************************+%* *+ The kind of a type, and of a coercion+%* *+%************************************************************************++Note [Computing a coercion kind and role]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+To compute a coercion's kind is straightforward: see coercionKind.+But to compute a coercion's role, in the case for NthCo we need+its kind as well. So if we have two separate functions (one for kinds+and one for roles) we can get exponentially bad behaviour, since each+NthCo node makes a separate call to coercionKind, which traverses the+sub-tree again. This was part of the problem in Trac #9233.++Solution: compute both together; hence coercionKindRole. We keep a+separate coercionKind function because it's a bit more efficient if+the kind is all you want.+-}++coercionType :: Coercion -> Type+coercionType co = case coercionKindRole co of+ (Pair ty1 ty2, r) -> mkCoercionType r ty1 ty2++------------------+-- | If it is the case that+--+-- > c :: (t1 ~ t2)+--+-- i.e. the kind of @c@ relates @t1@ and @t2@, then @coercionKind c = Pair t1 t2@.++coercionKind :: Coercion -> Pair Type+coercionKind co = go co+ where+ go (Refl _ ty) = Pair ty ty+ go (TyConAppCo _ tc cos)= mkTyConApp tc <$> (sequenceA $ map go cos)+ go (AppCo co1 co2) = mkAppTy <$> go co1 <*> go co2+ go (ForAllCo tv1 k_co co)+ = let Pair _ k2 = go k_co+ tv2 = setTyVarKind tv1 k2+ Pair ty1 ty2 = go co+ subst = zipTvSubst [tv1] [TyVarTy tv2 `mk_cast_ty` mkSymCo k_co]+ ty2' = substTyAddInScope subst ty2 in+ -- We need free vars of ty2 in scope to satisfy the invariant+ -- from Note [The substitution invariant]+ -- This is doing repeated substitutions and probably doesn't+ -- need to, see #11735+ mkInvForAllTy <$> Pair tv1 tv2 <*> Pair ty1 ty2'+ go (FunCo _ co1 co2) = mkFunTy <$> go co1 <*> go co2+ go (CoVarCo cv) = coVarTypes cv+ go (AxiomInstCo ax ind cos)+ | CoAxBranch { cab_tvs = tvs, cab_cvs = cvs+ , cab_lhs = lhs, cab_rhs = rhs } <- coAxiomNthBranch ax ind+ , let Pair tycos1 tycos2 = sequenceA (map go cos)+ (tys1, cotys1) = splitAtList tvs tycos1+ (tys2, cotys2) = splitAtList tvs tycos2+ cos1 = map stripCoercionTy cotys1+ cos2 = map stripCoercionTy cotys2+ = ASSERT( cos `equalLength` (tvs ++ cvs) )+ -- Invariant of AxiomInstCo: cos should+ -- exactly saturate the axiom branch+ Pair (substTyWith tvs tys1 $+ substTyWithCoVars cvs cos1 $+ mkTyConApp (coAxiomTyCon ax) lhs)+ (substTyWith tvs tys2 $+ substTyWithCoVars cvs cos2 rhs)+ go (UnivCo _ _ ty1 ty2) = Pair ty1 ty2+ go (SymCo co) = swap $ go co+ go (TransCo co1 co2) = Pair (pFst $ go co1) (pSnd $ go co2)+ go g@(NthCo d co)+ | Just argss <- traverse tyConAppArgs_maybe tys+ = ASSERT( and $ ((d <) . length) <$> argss )+ (`getNth` d) <$> argss++ | d == 0+ , Just splits <- traverse splitForAllTy_maybe tys+ = (tyVarKind . fst) <$> splits++ | otherwise+ = pprPanic "coercionKind" (ppr g)+ where+ tys = go co+ go (LRCo lr co) = (pickLR lr . splitAppTy) <$> go co+ go (InstCo aco arg) = go_app aco [arg]+ go (CoherenceCo g h)+ = let Pair ty1 ty2 = go g in+ Pair (mkCastTy ty1 h) ty2+ go (KindCo co) = typeKind <$> go co+ go (SubCo co) = go co+ go (AxiomRuleCo ax cos) = expectJust "coercionKind" $+ coaxrProves ax (map go cos)++ go_app :: Coercion -> [Coercion] -> Pair Type+ -- Collect up all the arguments and apply all at once+ -- See Note [Nested InstCos]+ go_app (InstCo co arg) args = go_app co (arg:args)+ go_app co args = piResultTys <$> go co <*> (sequenceA $ map go args)++ -- The real mkCastTy is too slow, and we can easily have nested ForAllCos.+ mk_cast_ty :: Type -> Coercion -> Type+ mk_cast_ty ty (Refl {}) = ty+ mk_cast_ty ty co = CastTy ty co++-- | Apply 'coercionKind' to multiple 'Coercion's+coercionKinds :: [Coercion] -> Pair [Type]+coercionKinds tys = sequenceA $ map coercionKind tys++-- | Get a coercion's kind and role.+-- Why both at once? See Note [Computing a coercion kind and role]+coercionKindRole :: Coercion -> (Pair Type, Role)+coercionKindRole = go+ where+ go (Refl r ty) = (Pair ty ty, r)+ go (TyConAppCo r tc cos)+ = (mkTyConApp tc <$> (sequenceA $ map coercionKind cos), r)+ go (AppCo co1 co2)+ = let (tys1, r1) = go co1 in+ (mkAppTy <$> tys1 <*> coercionKind co2, r1)+ go (ForAllCo tv1 k_co co)+ = let Pair _ k2 = coercionKind k_co+ tv2 = setTyVarKind tv1 k2+ (Pair ty1 ty2, r) = go co+ subst = zipTvSubst [tv1] [TyVarTy tv2 `mkCastTy` mkSymCo k_co]+ ty2' = substTyAddInScope subst ty2 in+ -- We need free vars of ty2 in scope to satisfy the invariant+ -- from Note [The substitution invariant]+ -- This is doing repeated substitutions and probably doesn't+ -- need to, see #11735+ (mkInvForAllTy <$> Pair tv1 tv2 <*> Pair ty1 ty2', r)+ go (FunCo r co1 co2)+ = (mkFunTy <$> coercionKind co1 <*> coercionKind co2, r)+ go (CoVarCo cv) = (coVarTypes cv, coVarRole cv)+ go co@(AxiomInstCo ax _ _) = (coercionKind co, coAxiomRole ax)+ go (UnivCo _ r ty1 ty2) = (Pair ty1 ty2, r)+ go (SymCo co) = first swap $ go co+ go (TransCo co1 co2)+ = let (tys1, r) = go co1 in+ (Pair (pFst tys1) (pSnd $ coercionKind co2), r)+ go (NthCo d co)+ | Just (tv1, _) <- splitForAllTy_maybe ty1+ = ASSERT( d == 0 )+ let (tv2, _) = splitForAllTy ty2 in+ (tyVarKind <$> Pair tv1 tv2, Nominal)++ | otherwise+ = let (tc1, args1) = splitTyConApp ty1+ (_tc2, args2) = splitTyConApp ty2+ in+ ASSERT2( tc1 == _tc2, ppr d $$ ppr tc1 $$ ppr _tc2 )+ ((`getNth` d) <$> Pair args1 args2, nthRole r tc1 d)++ where+ (Pair ty1 ty2, r) = go co+ go co@(LRCo {}) = (coercionKind co, Nominal)+ go (InstCo co arg) = go_app co [arg]+ go (CoherenceCo co1 co2)+ = let (Pair t1 t2, r) = go co1 in+ (Pair (t1 `mkCastTy` co2) t2, r)+ go co@(KindCo {}) = (coercionKind co, Nominal)+ go (SubCo co) = (coercionKind co, Representational)+ go co@(AxiomRuleCo ax _) = (coercionKind co, coaxrRole ax)++ go_app :: Coercion -> [Coercion] -> (Pair Type, Role)+ -- Collect up all the arguments and apply all at once+ -- See Note [Nested InstCos]+ go_app (InstCo co arg) args = go_app co (arg:args)+ go_app co args+ = let (pair, r) = go co in+ (piResultTys <$> pair <*> (sequenceA $ map coercionKind args), r)++-- | Retrieve the role from a coercion.+coercionRole :: Coercion -> Role+coercionRole = snd . coercionKindRole+ -- There's not a better way to do this, because NthCo needs the *kind*+ -- and role of its argument. Luckily, laziness should generally avoid+ -- the need for computing kinds in other cases.++{-+Note [Nested InstCos]+~~~~~~~~~~~~~~~~~~~~~+In Trac #5631 we found that 70% of the entire compilation time was+being spent in coercionKind! The reason was that we had+ (g @ ty1 @ ty2 .. @ ty100) -- The "@s" are InstCos+where+ g :: forall a1 a2 .. a100. phi+If we deal with the InstCos one at a time, we'll do this:+ 1. Find the kind of (g @ ty1 .. @ ty99) : forall a100. phi'+ 2. Substitute phi'[ ty100/a100 ], a single tyvar->type subst+But this is a *quadratic* algorithm, and the blew up Trac #5631.+So it's very important to do the substitution simultaneously;+cf Type.piResultTys (which in fact we call here).++-}
+ types/Coercion.hs-boot view
@@ -0,0 +1,51 @@+{-# LANGUAGE FlexibleContexts #-}++module Coercion where++import {-# SOURCE #-} TyCoRep+import {-# SOURCE #-} TyCon++import BasicTypes ( LeftOrRight )+import CoAxiom+import Var+import Outputable+import Pair+import Util++mkReflCo :: Role -> Type -> Coercion+mkTyConAppCo :: HasDebugCallStack => Role -> TyCon -> [Coercion] -> Coercion+mkAppCo :: Coercion -> Coercion -> Coercion+mkForAllCo :: TyVar -> Coercion -> Coercion -> Coercion+mkFunCo :: Role -> Coercion -> Coercion -> Coercion+mkCoVarCo :: CoVar -> Coercion+mkAxiomInstCo :: CoAxiom Branched -> BranchIndex -> [Coercion] -> Coercion+mkPhantomCo :: Coercion -> Type -> Type -> Coercion+mkUnsafeCo :: Role -> Type -> Type -> Coercion+mkUnivCo :: UnivCoProvenance -> Role -> Type -> Type -> Coercion+mkSymCo :: Coercion -> Coercion+mkTransCo :: Coercion -> Coercion -> Coercion+mkNthCo :: Int -> Coercion -> Coercion+mkLRCo :: LeftOrRight -> Coercion -> Coercion+mkInstCo :: Coercion -> Coercion -> Coercion+mkCoherenceCo :: Coercion -> Coercion -> Coercion+mkKindCo :: Coercion -> Coercion+mkSubCo :: Coercion -> Coercion+mkProofIrrelCo :: Role -> Coercion -> Coercion -> Coercion -> Coercion++mkFunCos :: Role -> [Coercion] -> Coercion -> Coercion++isReflCo :: Coercion -> Bool+isReflexiveCo :: Coercion -> Bool+coVarKindsTypesRole :: CoVar -> (Kind, Kind, Type, Type, Role)+coVarRole :: CoVar -> Role++mkCoercionType :: Role -> Type -> Type -> Type++data LiftingContext+liftCoSubst :: Role -> LiftingContext -> Type -> Coercion+seqCo :: Coercion -> ()++coercionKind :: Coercion -> Pair Type+coercionType :: Coercion -> Type++pprCo :: Coercion -> SDoc
+ types/FamInstEnv.hs view
@@ -0,0 +1,1724 @@+-- (c) The University of Glasgow 2006+--+-- FamInstEnv: Type checked family instance declarations++{-# LANGUAGE CPP, GADTs, ScopedTypeVariables #-}++module FamInstEnv (+ FamInst(..), FamFlavor(..), famInstAxiom, famInstTyCon, famInstRHS,+ famInstsRepTyCons, famInstRepTyCon_maybe, dataFamInstRepTyCon,+ pprFamInst, pprFamInsts,+ mkImportedFamInst,++ FamInstEnvs, FamInstEnv, emptyFamInstEnv, emptyFamInstEnvs,+ extendFamInstEnv, extendFamInstEnvList,+ famInstEnvElts, famInstEnvSize, familyInstances,++ -- * CoAxioms+ mkCoAxBranch, mkBranchedCoAxiom, mkUnbranchedCoAxiom, mkSingleCoAxiom,+ mkNewTypeCoAxiom,++ FamInstMatch(..),+ lookupFamInstEnv, lookupFamInstEnvConflicts, lookupFamInstEnvByTyCon,++ isDominatedBy, apartnessCheck,++ -- Injectivity+ InjectivityCheckResult(..),+ lookupFamInstEnvInjectivityConflicts, injectiveBranches,++ -- Normalisation+ topNormaliseType, topNormaliseType_maybe,+ normaliseType, normaliseTcApp,+ reduceTyFamApp_maybe,+ pmTopNormaliseType_maybe,++ -- Flattening+ flattenTys+ ) where++#include "HsVersions.h"++import Unify+import Type+import TyCoRep+import TyCon+import DataCon (DataCon)+import Coercion+import CoAxiom+import VarSet+import VarEnv+import Name+import PrelNames ( eqPrimTyConKey )+import UniqDFM+import Outputable+import Maybes+import TrieMap+import Unique+import Util+import Var+import Pair+import SrcLoc+import FastString+import MonadUtils+import Control.Monad+import Data.List( mapAccumL, find )++{-+************************************************************************+* *+ Type checked family instance heads+* *+************************************************************************++Note [FamInsts and CoAxioms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* CoAxioms and FamInsts are just like+ DFunIds and ClsInsts++* A CoAxiom is a System-FC thing: it can relate any two types++* A FamInst is a Haskell source-language thing, corresponding+ to a type/data family instance declaration.+ - The FamInst contains a CoAxiom, which is the evidence+ for the instance++ - The LHS of the CoAxiom is always of form F ty1 .. tyn+ where F is a type family+-}++data FamInst -- See Note [FamInsts and CoAxioms]+ = FamInst { fi_axiom :: CoAxiom Unbranched -- The new coercion axiom+ -- introduced by this family+ -- instance+ -- INVARIANT: apart from freshening (see below)+ -- fi_tvs = cab_tvs of the (single) axiom branch+ -- fi_cvs = cab_cvs ...ditto...+ -- fi_tys = cab_lhs ...ditto...+ -- fi_rhs = cab_rhs ...ditto...++ , fi_flavor :: FamFlavor++ -- Everything below here is a redundant,+ -- cached version of the two things above+ -- except that the TyVars are freshened+ , fi_fam :: Name -- Family name++ -- Used for "rough matching"; same idea as for class instances+ -- See Note [Rough-match field] in InstEnv+ , fi_tcs :: [Maybe Name] -- Top of type args+ -- INVARIANT: fi_tcs = roughMatchTcs fi_tys++ -- Used for "proper matching"; ditto+ , fi_tvs :: [TyVar] -- Template tyvars for full match+ , fi_cvs :: [CoVar] -- Template covars for full match+ -- Like ClsInsts, these variables are always fresh+ -- See Note [Template tyvars are fresh] in InstEnv++ , fi_tys :: [Type] -- The LHS type patterns+ -- May be eta-reduced; see Note [Eta reduction for data families]++ , fi_rhs :: Type -- the RHS, with its freshened vars+ }++data FamFlavor+ = SynFamilyInst -- A synonym family+ | DataFamilyInst TyCon -- A data family, with its representation TyCon++{- Note [Eta reduction for data families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this+ data family T a b :: *+ newtype instance T Int a = MkT (IO a) deriving( Monad )+We'd like this to work.++From the 'newtype instance' you might think we'd get:+ newtype TInt a = MkT (IO a)+ axiom ax1 a :: T Int a ~ TInt a -- The newtype-instance part+ axiom ax2 a :: TInt a ~ IO a -- The newtype part++But now what can we do? We have this problem+ Given: d :: Monad IO+ Wanted: d' :: Monad (T Int) = d |> ????+What coercion can we use for the ???++Solution: eta-reduce both axioms, thus:+ axiom ax1 :: T Int ~ TInt+ axiom ax2 :: TInt ~ IO+Now+ d' = d |> Monad (sym (ax2 ; ax1))++This eta reduction happens for data instances as well as newtype+instances. Here we want to eta-reduce the data family axiom.+All this is done in TcInstDcls.tcDataFamInstDecl.++See also Note [Newtype eta] in TyCon.++Bottom line:+ For a FamInst with fi_flavour = DataFamilyInst rep_tc,+ - fi_tvs may be shorter than tyConTyVars of rep_tc+ - fi_tys may be shorter than tyConArity of the family tycon+ i.e. LHS is unsaturated+ - fi_rhs will be (rep_tc fi_tvs)+ i.e. RHS is un-saturated++ But when fi_flavour = SynFamilyInst,+ - fi_tys has the exact arity of the family tycon+-}++-- Obtain the axiom of a family instance+famInstAxiom :: FamInst -> CoAxiom Unbranched+famInstAxiom = fi_axiom++-- Split the left-hand side of the FamInst+famInstSplitLHS :: FamInst -> (TyCon, [Type])+famInstSplitLHS (FamInst { fi_axiom = axiom, fi_tys = lhs })+ = (coAxiomTyCon axiom, lhs)++-- Get the RHS of the FamInst+famInstRHS :: FamInst -> Type+famInstRHS = fi_rhs++-- Get the family TyCon of the FamInst+famInstTyCon :: FamInst -> TyCon+famInstTyCon = coAxiomTyCon . famInstAxiom++-- Return the representation TyCons introduced by data family instances, if any+famInstsRepTyCons :: [FamInst] -> [TyCon]+famInstsRepTyCons fis = [tc | FamInst { fi_flavor = DataFamilyInst tc } <- fis]++-- Extracts the TyCon for this *data* (or newtype) instance+famInstRepTyCon_maybe :: FamInst -> Maybe TyCon+famInstRepTyCon_maybe fi+ = case fi_flavor fi of+ DataFamilyInst tycon -> Just tycon+ SynFamilyInst -> Nothing++dataFamInstRepTyCon :: FamInst -> TyCon+dataFamInstRepTyCon fi+ = case fi_flavor fi of+ DataFamilyInst tycon -> tycon+ SynFamilyInst -> pprPanic "dataFamInstRepTyCon" (ppr fi)++{-+************************************************************************+* *+ Pretty printing+* *+************************************************************************+-}++instance NamedThing FamInst where+ getName = coAxiomName . fi_axiom++instance Outputable FamInst where+ ppr = pprFamInst++-- Prints the FamInst as a family instance declaration+-- NB: FamInstEnv.pprFamInst is used only for internal, debug printing+-- See pprTyThing.pprFamInst for printing for the user+pprFamInst :: FamInst -> SDoc+pprFamInst famInst+ = hang (pprFamInstHdr famInst) 2 (ifPprDebug debug_stuff)+ where+ ax = fi_axiom famInst+ debug_stuff = vcat [ text "Coercion axiom:" <+> ppr ax+ , text "Tvs:" <+> ppr (fi_tvs famInst)+ , text "LHS:" <+> ppr (fi_tys famInst)+ , text "RHS:" <+> ppr (fi_rhs famInst) ]++pprFamInstHdr :: FamInst -> SDoc+pprFamInstHdr fi@(FamInst {fi_flavor = flavor})+ = pprTyConSort <+> pp_instance <+> pp_head+ where+ -- For *associated* types, say "type T Int = blah"+ -- For *top level* type instances, say "type instance T Int = blah"+ pp_instance+ | isTyConAssoc fam_tc = empty+ | otherwise = text "instance"++ (fam_tc, etad_lhs_tys) = famInstSplitLHS fi+ vanilla_pp_head = pprTypeApp fam_tc etad_lhs_tys++ pp_head | DataFamilyInst rep_tc <- flavor+ , isAlgTyCon rep_tc+ , let extra_tvs = dropList etad_lhs_tys (tyConTyVars rep_tc)+ , not (null extra_tvs)+ = getPprStyle $ \ sty ->+ if debugStyle sty+ then vanilla_pp_head -- With -dppr-debug just show it as-is+ else pprTypeApp fam_tc (etad_lhs_tys ++ mkTyVarTys extra_tvs)+ -- Without -dppr-debug, eta-expand+ -- See Trac #8674+ -- (This is probably over the top now that we use this+ -- only for internal debug printing; PprTyThing.pprFamInst+ -- is used for user-level printing.)+ | otherwise+ = vanilla_pp_head++ pprTyConSort = case flavor of+ SynFamilyInst -> text "type"+ DataFamilyInst tycon+ | isDataTyCon tycon -> text "data"+ | isNewTyCon tycon -> text "newtype"+ | isAbstractTyCon tycon -> text "data"+ | otherwise -> text "WEIRD" <+> ppr tycon++pprFamInsts :: [FamInst] -> SDoc+pprFamInsts finsts = vcat (map pprFamInst finsts)++{-+Note [Lazy axiom match]+~~~~~~~~~~~~~~~~~~~~~~~+It is Vitally Important that mkImportedFamInst is *lazy* in its axiom+parameter. The axiom is loaded lazily, via a forkM, in TcIface. Sometime+later, mkImportedFamInst is called using that axiom. However, the axiom+may itself depend on entities which are not yet loaded as of the time+of the mkImportedFamInst. Thus, if mkImportedFamInst eagerly looks at the+axiom, a dependency loop spontaneously appears and GHC hangs. The solution+is simply for mkImportedFamInst never, ever to look inside of the axiom+until everything else is good and ready to do so. We can assume that this+readiness has been achieved when some other code pulls on the axiom in the+FamInst. Thus, we pattern match on the axiom lazily (in the where clause,+not in the parameter list) and we assert the consistency of names there+also.+-}++-- Make a family instance representation from the information found in an+-- interface file. In particular, we get the rough match info from the iface+-- (instead of computing it here).+mkImportedFamInst :: Name -- Name of the family+ -> [Maybe Name] -- Rough match info+ -> CoAxiom Unbranched -- Axiom introduced+ -> FamInst -- Resulting family instance+mkImportedFamInst fam mb_tcs axiom+ = FamInst {+ fi_fam = fam,+ fi_tcs = mb_tcs,+ fi_tvs = tvs,+ fi_cvs = cvs,+ fi_tys = tys,+ fi_rhs = rhs,+ fi_axiom = axiom,+ fi_flavor = flavor }+ where+ -- See Note [Lazy axiom match]+ ~(CoAxBranch { cab_lhs = tys+ , cab_tvs = tvs+ , cab_cvs = cvs+ , cab_rhs = rhs }) = coAxiomSingleBranch axiom++ -- Derive the flavor for an imported FamInst rather disgustingly+ -- Maybe we should store it in the IfaceFamInst?+ flavor = case splitTyConApp_maybe rhs of+ Just (tc, _)+ | Just ax' <- tyConFamilyCoercion_maybe tc+ , ax' == axiom+ -> DataFamilyInst tc+ _ -> SynFamilyInst++{-+************************************************************************+* *+ FamInstEnv+* *+************************************************************************++Note [FamInstEnv]+~~~~~~~~~~~~~~~~~+A FamInstEnv maps a family name to the list of known instances for that family.++The same FamInstEnv includes both 'data family' and 'type family' instances.+Type families are reduced during type inference, but not data families;+the user explains when to use a data family instance by using constructors+and pattern matching.++Nevertheless it is still useful to have data families in the FamInstEnv:++ - For finding overlaps and conflicts++ - For finding the representation type...see FamInstEnv.topNormaliseType+ and its call site in Simplify++ - In standalone deriving instance Eq (T [Int]) we need to find the+ representation type for T [Int]++Note [Varying number of patterns for data family axioms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+For data families, the number of patterns may vary between instances.+For example+ data family T a b+ data instance T Int a = T1 a | T2+ data instance T Bool [a] = T3 a++Then we get a data type for each instance, and an axiom:+ data TInt a = T1 a | T2+ data TBoolList a = T3 a++ axiom ax7 :: T Int ~ TInt -- Eta-reduced+ axiom ax8 a :: T Bool [a] ~ TBoolList a++These two axioms for T, one with one pattern, one with two;+see Note [Eta reduction for data families]++Note [FamInstEnv determinism]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We turn FamInstEnvs into a list in some places that don't directly affect+the ABI. That happens in family consistency checks and when producing output+for `:info`. Unfortunately that nondeterminism is nonlocal and it's hard+to tell what it affects without following a chain of functions. It's also+easy to accidentally make that nondeterminism affect the ABI. Furthermore+the envs should be relatively small, so it should be free to use deterministic+maps here. Testing with nofib and validate detected no difference between+UniqFM and UniqDFM.+See Note [Deterministic UniqFM].+-}++type FamInstEnv = UniqDFM FamilyInstEnv -- Maps a family to its instances+ -- See Note [FamInstEnv]+ -- See Note [FamInstEnv determinism]++type FamInstEnvs = (FamInstEnv, FamInstEnv)+ -- External package inst-env, Home-package inst-env++newtype FamilyInstEnv+ = FamIE [FamInst] -- The instances for a particular family, in any order++instance Outputable FamilyInstEnv where+ ppr (FamIE fs) = text "FamIE" <+> vcat (map ppr fs)++-- INVARIANTS:+-- * The fs_tvs are distinct in each FamInst+-- of a range value of the map (so we can safely unify them)++emptyFamInstEnvs :: (FamInstEnv, FamInstEnv)+emptyFamInstEnvs = (emptyFamInstEnv, emptyFamInstEnv)++emptyFamInstEnv :: FamInstEnv+emptyFamInstEnv = emptyUDFM++famInstEnvElts :: FamInstEnv -> [FamInst]+famInstEnvElts fi = [elt | FamIE elts <- eltsUDFM fi, elt <- elts]+ -- See Note [FamInstEnv determinism]++famInstEnvSize :: FamInstEnv -> Int+famInstEnvSize = nonDetFoldUDFM (\(FamIE elt) sum -> sum + length elt) 0+ -- It's OK to use nonDetFoldUDFM here since we're just computing the+ -- size.++familyInstances :: (FamInstEnv, FamInstEnv) -> TyCon -> [FamInst]+familyInstances (pkg_fie, home_fie) fam+ = get home_fie ++ get pkg_fie+ where+ get env = case lookupUDFM env fam of+ Just (FamIE insts) -> insts+ Nothing -> []++extendFamInstEnvList :: FamInstEnv -> [FamInst] -> FamInstEnv+extendFamInstEnvList inst_env fis = foldl extendFamInstEnv inst_env fis++extendFamInstEnv :: FamInstEnv -> FamInst -> FamInstEnv+extendFamInstEnv inst_env+ ins_item@(FamInst {fi_fam = cls_nm})+ = addToUDFM_C add inst_env cls_nm (FamIE [ins_item])+ where+ add (FamIE items) _ = FamIE (ins_item:items)++{-+************************************************************************+* *+ Compatibility+* *+************************************************************************++Note [Apartness]+~~~~~~~~~~~~~~~~+In dealing with closed type families, we must be able to check that one type+will never reduce to another. This check is called /apartness/. The check+is always between a target (which may be an arbitrary type) and a pattern.+Here is how we do it:++apart(target, pattern) = not (unify(flatten(target), pattern))++where flatten (implemented in flattenTys, below) converts all type-family+applications into fresh variables. (See Note [Flattening].)++Note [Compatibility]+~~~~~~~~~~~~~~~~~~~~+Two patterns are /compatible/ if either of the following conditions hold:+1) The patterns are apart.+2) The patterns unify with a substitution S, and their right hand sides+equal under that substitution.++For open type families, only compatible instances are allowed. For closed+type families, the story is slightly more complicated. Consider the following:++type family F a where+ F Int = Bool+ F a = Int++g :: Show a => a -> F a+g x = length (show x)++Should that type-check? No. We need to allow for the possibility that 'a'+might be Int and therefore 'F a' should be Bool. We can simplify 'F a' to Int+only when we can be sure that 'a' is not Int.++To achieve this, after finding a possible match within the equations, we have to+go back to all previous equations and check that, under the+substitution induced by the match, other branches are surely apart. (See+Note [Apartness].) This is similar to what happens with class+instance selection, when we need to guarantee that there is only a match and+no unifiers. The exact algorithm is different here because the the+potentially-overlapping group is closed.++As another example, consider this:++type family G x where+ G Int = Bool+ G a = Double++type family H y+-- no instances++Now, we want to simplify (G (H Char)). We can't, because (H Char) might later+simplify to be Int. So, (G (H Char)) is stuck, for now.++While everything above is quite sound, it isn't as expressive as we'd like.+Consider this:++type family J a where+ J Int = Int+ J a = a++Can we simplify (J b) to b? Sure we can. Yes, the first equation matches if+b is instantiated with Int, but the RHSs coincide there, so it's all OK.++So, the rule is this: when looking up a branch in a closed type family, we+find a branch that matches the target, but then we make sure that the target+is apart from every previous *incompatible* branch. We don't check the+branches that are compatible with the matching branch, because they are either+irrelevant (clause 1 of compatible) or benign (clause 2 of compatible).+-}++-- See Note [Compatibility]+compatibleBranches :: CoAxBranch -> CoAxBranch -> Bool+compatibleBranches (CoAxBranch { cab_lhs = lhs1, cab_rhs = rhs1 })+ (CoAxBranch { cab_lhs = lhs2, cab_rhs = rhs2 })+ = case tcUnifyTysFG (const BindMe) lhs1 lhs2 of+ SurelyApart -> True+ Unifiable subst+ | Type.substTyAddInScope subst rhs1 `eqType`+ Type.substTyAddInScope subst rhs2+ -> True+ _ -> False++-- | Result of testing two type family equations for injectiviy.+data InjectivityCheckResult+ = InjectivityAccepted+ -- ^ Either RHSs are distinct or unification of RHSs leads to unification of+ -- LHSs+ | InjectivityUnified CoAxBranch CoAxBranch+ -- ^ RHSs unify but LHSs don't unify under that substitution. Relevant for+ -- closed type families where equation after unification might be+ -- overlpapped (in which case it is OK if they don't unify). Constructor+ -- stores axioms after unification.++-- | Check whether two type family axioms don't violate injectivity annotation.+injectiveBranches :: [Bool] -> CoAxBranch -> CoAxBranch+ -> InjectivityCheckResult+injectiveBranches injectivity+ ax1@(CoAxBranch { cab_lhs = lhs1, cab_rhs = rhs1 })+ ax2@(CoAxBranch { cab_lhs = lhs2, cab_rhs = rhs2 })+ -- See Note [Verifying injectivity annotation]. This function implements first+ -- check described there.+ = let getInjArgs = filterByList injectivity+ in case tcUnifyTyWithTFs True rhs1 rhs2 of -- True = two-way pre-unification+ Nothing -> InjectivityAccepted -- RHS are different, so equations are+ -- injective.+ Just subst -> -- RHS unify under a substitution+ let lhs1Subst = Type.substTys subst (getInjArgs lhs1)+ lhs2Subst = Type.substTys subst (getInjArgs lhs2)+ -- If LHSs are equal under the substitution used for RHSs then this pair+ -- of equations does not violate injectivity annotation. If LHSs are not+ -- equal under that substitution then this pair of equations violates+ -- injectivity annotation, but for closed type families it still might+ -- be the case that one LHS after substitution is unreachable.+ in if eqTypes lhs1Subst lhs2Subst+ then InjectivityAccepted+ else InjectivityUnified ( ax1 { cab_lhs = Type.substTys subst lhs1+ , cab_rhs = Type.substTy subst rhs1 })+ ( ax2 { cab_lhs = Type.substTys subst lhs2+ , cab_rhs = Type.substTy subst rhs2 })++-- takes a CoAxiom with unknown branch incompatibilities and computes+-- the compatibilities+-- See Note [Storing compatibility] in CoAxiom+computeAxiomIncomps :: [CoAxBranch] -> [CoAxBranch]+computeAxiomIncomps branches+ = snd (mapAccumL go [] branches)+ where+ go :: [CoAxBranch] -> CoAxBranch -> ([CoAxBranch], CoAxBranch)+ go prev_brs cur_br+ = (cur_br : prev_brs, new_br)+ where+ new_br = cur_br { cab_incomps = mk_incomps prev_brs cur_br }++ mk_incomps :: [CoAxBranch] -> CoAxBranch -> [CoAxBranch]+ mk_incomps prev_brs cur_br+ = filter (not . compatibleBranches cur_br) prev_brs++{-+************************************************************************+* *+ Constructing axioms+ These functions are here because tidyType / tcUnifyTysFG+ are not available in CoAxiom++ Also computeAxiomIncomps is too sophisticated for CoAxiom+* *+************************************************************************++Note [Tidy axioms when we build them]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We print out axioms and don't want to print stuff like+ F k k a b = ...+Instead we must tidy those kind variables. See Trac #7524.+-}++-- all axiom roles are Nominal, as this is only used with type families+mkCoAxBranch :: [TyVar] -- original, possibly stale, tyvars+ -> [CoVar] -- possibly stale covars+ -> [Type] -- LHS patterns+ -> Type -- RHS+ -> [Role]+ -> SrcSpan+ -> CoAxBranch+mkCoAxBranch tvs cvs lhs rhs roles loc+ = CoAxBranch { cab_tvs = tvs1+ , cab_cvs = cvs1+ , cab_lhs = tidyTypes env lhs+ , cab_roles = roles+ , cab_rhs = tidyType env rhs+ , cab_loc = loc+ , cab_incomps = placeHolderIncomps }+ where+ (env1, tvs1) = tidyTyCoVarBndrs emptyTidyEnv tvs+ (env, cvs1) = tidyTyCoVarBndrs env1 cvs+ -- See Note [Tidy axioms when we build them]++-- all of the following code is here to avoid mutual dependencies with+-- Coercion+mkBranchedCoAxiom :: Name -> TyCon -> [CoAxBranch] -> CoAxiom Branched+mkBranchedCoAxiom ax_name fam_tc branches+ = CoAxiom { co_ax_unique = nameUnique ax_name+ , co_ax_name = ax_name+ , co_ax_tc = fam_tc+ , co_ax_role = Nominal+ , co_ax_implicit = False+ , co_ax_branches = manyBranches (computeAxiomIncomps branches) }++mkUnbranchedCoAxiom :: Name -> TyCon -> CoAxBranch -> CoAxiom Unbranched+mkUnbranchedCoAxiom ax_name fam_tc branch+ = CoAxiom { co_ax_unique = nameUnique ax_name+ , co_ax_name = ax_name+ , co_ax_tc = fam_tc+ , co_ax_role = Nominal+ , co_ax_implicit = False+ , co_ax_branches = unbranched (branch { cab_incomps = [] }) }++mkSingleCoAxiom :: Role -> Name+ -> [TyVar] -> [CoVar] -> TyCon -> [Type] -> Type+ -> CoAxiom Unbranched+-- Make a single-branch CoAxiom, incluidng making the branch itself+-- Used for both type family (Nominal) and data family (Representational)+-- axioms, hence passing in the Role+mkSingleCoAxiom role ax_name tvs cvs fam_tc lhs_tys rhs_ty+ = CoAxiom { co_ax_unique = nameUnique ax_name+ , co_ax_name = ax_name+ , co_ax_tc = fam_tc+ , co_ax_role = role+ , co_ax_implicit = False+ , co_ax_branches = unbranched (branch { cab_incomps = [] }) }+ where+ branch = mkCoAxBranch tvs cvs lhs_tys rhs_ty+ (map (const Nominal) tvs)+ (getSrcSpan ax_name)++-- | Create a coercion constructor (axiom) suitable for the given+-- newtype 'TyCon'. The 'Name' should be that of a new coercion+-- 'CoAxiom', the 'TyVar's the arguments expected by the @newtype@ and+-- the type the appropriate right hand side of the @newtype@, with+-- the free variables a subset of those 'TyVar's.+mkNewTypeCoAxiom :: Name -> TyCon -> [TyVar] -> [Role] -> Type -> CoAxiom Unbranched+mkNewTypeCoAxiom name tycon tvs roles rhs_ty+ = CoAxiom { co_ax_unique = nameUnique name+ , co_ax_name = name+ , co_ax_implicit = True -- See Note [Implicit axioms] in TyCon+ , co_ax_role = Representational+ , co_ax_tc = tycon+ , co_ax_branches = unbranched (branch { cab_incomps = [] }) }+ where+ branch = mkCoAxBranch tvs [] (mkTyVarTys tvs) rhs_ty+ roles (getSrcSpan name)++{-+************************************************************************+* *+ Looking up a family instance+* *+************************************************************************++@lookupFamInstEnv@ looks up in a @FamInstEnv@, using a one-way match.+Multiple matches are only possible in case of type families (not data+families), and then, it doesn't matter which match we choose (as the+instances are guaranteed confluent).++We return the matching family instances and the type instance at which it+matches. For example, if we lookup 'T [Int]' and have a family instance++ data instance T [a] = ..++desugared to++ data :R42T a = ..+ coe :Co:R42T a :: T [a] ~ :R42T a++we return the matching instance '(FamInst{.., fi_tycon = :R42T}, Int)'.+-}++-- when matching a type family application, we get a FamInst,+-- and the list of types the axiom should be applied to+data FamInstMatch = FamInstMatch { fim_instance :: FamInst+ , fim_tys :: [Type]+ , fim_cos :: [Coercion]+ }+ -- See Note [Over-saturated matches]++instance Outputable FamInstMatch where+ ppr (FamInstMatch { fim_instance = inst+ , fim_tys = tys+ , fim_cos = cos })+ = text "match with" <+> parens (ppr inst) <+> ppr tys <+> ppr cos++lookupFamInstEnvByTyCon :: FamInstEnvs -> TyCon -> [FamInst]+lookupFamInstEnvByTyCon (pkg_ie, home_ie) fam_tc+ = get pkg_ie ++ get home_ie+ where+ get ie = case lookupUDFM ie fam_tc of+ Nothing -> []+ Just (FamIE fis) -> fis++lookupFamInstEnv+ :: FamInstEnvs+ -> TyCon -> [Type] -- What we are looking for+ -> [FamInstMatch] -- Successful matches+-- Precondition: the tycon is saturated (or over-saturated)++lookupFamInstEnv+ = lookup_fam_inst_env match+ where+ match _ _ tpl_tys tys = tcMatchTys tpl_tys tys++lookupFamInstEnvConflicts+ :: FamInstEnvs+ -> FamInst -- Putative new instance+ -> [FamInstMatch] -- Conflicting matches (don't look at the fim_tys field)+-- E.g. when we are about to add+-- f : type instance F [a] = a->a+-- we do (lookupFamInstConflicts f [b])+-- to find conflicting matches+--+-- Precondition: the tycon is saturated (or over-saturated)++lookupFamInstEnvConflicts envs fam_inst@(FamInst { fi_axiom = new_axiom })+ = lookup_fam_inst_env my_unify envs fam tys+ where+ (fam, tys) = famInstSplitLHS fam_inst+ -- In example above, fam tys' = F [b]++ my_unify (FamInst { fi_axiom = old_axiom }) tpl_tvs tpl_tys _+ = ASSERT2( tyCoVarsOfTypes tys `disjointVarSet` tpl_tvs,+ (ppr fam <+> ppr tys) $$+ (ppr tpl_tvs <+> ppr tpl_tys) )+ -- Unification will break badly if the variables overlap+ -- They shouldn't because we allocate separate uniques for them+ if compatibleBranches (coAxiomSingleBranch old_axiom) new_branch+ then Nothing+ else Just noSubst+ -- Note [Family instance overlap conflicts]++ noSubst = panic "lookupFamInstEnvConflicts noSubst"+ new_branch = coAxiomSingleBranch new_axiom++--------------------------------------------------------------------------------+-- Type family injectivity checking bits --+--------------------------------------------------------------------------------++{- Note [Verifying injectivity annotation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Injectivity means that the RHS of a type family uniquely determines the LHS (see+Note [Type inference for type families with injectivity]). User informs about+injectivity using an injectivity annotation and it is GHC's task to verify that+that annotation is correct wrt. to type family equations. Whenever we see a new+equation of a type family we need to make sure that adding this equation to+already known equations of a type family does not violate injectivity annotation+supplied by the user (see Note [Injectivity annotation]). Of course if the type+family has no injectivity annotation then no check is required. But if a type+family has injectivity annotation we need to make sure that the following+conditions hold:++1. For each pair of *different* equations of a type family, one of the following+ conditions holds:++ A: RHSs are different.++ B1: OPEN TYPE FAMILIES: If the RHSs can be unified under some substitution+ then it must be possible to unify the LHSs under the same substitution.+ Example:++ type family FunnyId a = r | r -> a+ type instance FunnyId Int = Int+ type instance FunnyId a = a++ RHSs of these two equations unify under [ a |-> Int ] substitution.+ Under this substitution LHSs are equal therefore these equations don't+ violate injectivity annotation.++ B2: CLOSED TYPE FAMILIES: If the RHSs can be unified under some+ substitution then either the LHSs unify under the same substitution or+ the LHS of the latter equation is overlapped by earlier equations.+ Example 1:++ type family SwapIntChar a = r | r -> a where+ SwapIntChar Int = Char+ SwapIntChar Char = Int+ SwapIntChar a = a++ Say we are checking the last two equations. RHSs unify under [ a |->+ Int ] substitution but LHSs don't. So we apply the substitution to LHS+ of last equation and check whether it is overlapped by any of previous+ equations. Since it is overlapped by the first equation we conclude+ that pair of last two equations does not violate injectivity+ annotation.++ A special case of B is when RHSs unify with an empty substitution ie. they+ are identical.++ If any of the above two conditions holds we conclude that the pair of+ equations does not violate injectivity annotation. But if we find a pair+ of equations where neither of the above holds we report that this pair+ violates injectivity annotation because for a given RHS we don't have a+ unique LHS. (Note that (B) actually implies (A).)++ Note that we only take into account these LHS patterns that were declared+ as injective.++2. If a RHS of a type family equation is a bare type variable then+ all LHS variables (including implicit kind variables) also have to be bare.+ In other words, this has to be a sole equation of that type family and it has+ to cover all possible patterns. So for example this definition will be+ rejected:++ type family W1 a = r | r -> a+ type instance W1 [a] = a++ If it were accepted we could call `W1 [W1 Int]`, which would reduce to+ `W1 Int` and then by injectivity we could conclude that `[W1 Int] ~ Int`,+ which is bogus.++3. If a RHS of a type family equation is a type family application then the type+ family is rejected as not injective.++4. If a LHS type variable that is declared as injective is not mentioned on+ injective position in the RHS then the type family is rejected as not+ injective. "Injective position" means either an argument to a type+ constructor or argument to a type family on injective position.++See also Note [Injective type families] in TyCon+-}+++-- | Check whether an open type family equation can be added to already existing+-- instance environment without causing conflicts with supplied injectivity+-- annotations. Returns list of conflicting axioms (type instance+-- declarations).+lookupFamInstEnvInjectivityConflicts+ :: [Bool] -- injectivity annotation for this type family instance+ -- INVARIANT: list contains at least one True value+ -> FamInstEnvs -- all type instances seens so far+ -> FamInst -- new type instance that we're checking+ -> [CoAxBranch] -- conflicting instance delcarations+lookupFamInstEnvInjectivityConflicts injList (pkg_ie, home_ie)+ fam_inst@(FamInst { fi_axiom = new_axiom })+ -- See Note [Verifying injectivity annotation]. This function implements+ -- check (1.B1) for open type families described there.+ = lookup_inj_fam_conflicts home_ie ++ lookup_inj_fam_conflicts pkg_ie+ where+ fam = famInstTyCon fam_inst+ new_branch = coAxiomSingleBranch new_axiom++ -- filtering function used by `lookup_inj_fam_conflicts` to check whether+ -- a pair of equations conflicts with the injectivity annotation.+ isInjConflict (FamInst { fi_axiom = old_axiom })+ | InjectivityAccepted <-+ injectiveBranches injList (coAxiomSingleBranch old_axiom) new_branch+ = False -- no conflict+ | otherwise = True++ lookup_inj_fam_conflicts ie+ | isOpenFamilyTyCon fam, Just (FamIE insts) <- lookupUDFM ie fam+ = map (coAxiomSingleBranch . fi_axiom) $+ filter isInjConflict insts+ | otherwise = []+++--------------------------------------------------------------------------------+-- Type family overlap checking bits --+--------------------------------------------------------------------------------++{-+Note [Family instance overlap conflicts]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+- In the case of data family instances, any overlap is fundamentally a+ conflict (as these instances imply injective type mappings).++- In the case of type family instances, overlap is admitted as long as+ the right-hand sides of the overlapping rules coincide under the+ overlap substitution. eg+ type instance F a Int = a+ type instance F Int b = b+ These two overlap on (F Int Int) but then both RHSs are Int,+ so all is well. We require that they are syntactically equal;+ anything else would be difficult to test for at this stage.+-}++------------------------------------------------------------+-- Might be a one-way match or a unifier+type MatchFun = FamInst -- The FamInst template+ -> TyVarSet -> [Type] -- fi_tvs, fi_tys of that FamInst+ -> [Type] -- Target to match against+ -> Maybe TCvSubst++lookup_fam_inst_env' -- The worker, local to this module+ :: MatchFun+ -> FamInstEnv+ -> TyCon -> [Type] -- What we are looking for+ -> [FamInstMatch]+lookup_fam_inst_env' match_fun ie fam match_tys+ | isOpenFamilyTyCon fam+ , Just (FamIE insts) <- lookupUDFM ie fam+ = find insts -- The common case+ | otherwise = []+ where++ find [] = []+ find (item@(FamInst { fi_tcs = mb_tcs, fi_tvs = tpl_tvs, fi_cvs = tpl_cvs+ , fi_tys = tpl_tys }) : rest)+ -- Fast check for no match, uses the "rough match" fields+ | instanceCantMatch rough_tcs mb_tcs+ = find rest++ -- Proper check+ | Just subst <- match_fun item (mkVarSet tpl_tvs) tpl_tys match_tys1+ = (FamInstMatch { fim_instance = item+ , fim_tys = substTyVars subst tpl_tvs `chkAppend` match_tys2+ , fim_cos = ASSERT( all (isJust . lookupCoVar subst) tpl_cvs )+ substCoVars subst tpl_cvs+ })+ : find rest++ -- No match => try next+ | otherwise+ = find rest++ where+ (rough_tcs, match_tys1, match_tys2) = split_tys tpl_tys++ -- Precondition: the tycon is saturated (or over-saturated)++ -- Deal with over-saturation+ -- See Note [Over-saturated matches]+ split_tys tpl_tys+ | isTypeFamilyTyCon fam+ = pre_rough_split_tys++ | otherwise+ = let (match_tys1, match_tys2) = splitAtList tpl_tys match_tys+ rough_tcs = roughMatchTcs match_tys1+ in (rough_tcs, match_tys1, match_tys2)++ (pre_match_tys1, pre_match_tys2) = splitAt (tyConArity fam) match_tys+ pre_rough_split_tys+ = (roughMatchTcs pre_match_tys1, pre_match_tys1, pre_match_tys2)++lookup_fam_inst_env -- The worker, local to this module+ :: MatchFun+ -> FamInstEnvs+ -> TyCon -> [Type] -- What we are looking for+ -> [FamInstMatch] -- Successful matches++-- Precondition: the tycon is saturated (or over-saturated)++lookup_fam_inst_env match_fun (pkg_ie, home_ie) fam tys+ = lookup_fam_inst_env' match_fun home_ie fam tys+ ++ lookup_fam_inst_env' match_fun pkg_ie fam tys++{-+Note [Over-saturated matches]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It's ok to look up an over-saturated type constructor. E.g.+ type family F a :: * -> *+ type instance F (a,b) = Either (a->b)++The type instance gives rise to a newtype TyCon (at a higher kind+which you can't do in Haskell!):+ newtype FPair a b = FP (Either (a->b))++Then looking up (F (Int,Bool) Char) will return a FamInstMatch+ (FPair, [Int,Bool,Char])+The "extra" type argument [Char] just stays on the end.++We handle data families and type families separately here:++ * For type families, all instances of a type family must have the+ same arity, so we can precompute the split between the match_tys+ and the overflow tys. This is done in pre_rough_split_tys.++ * For data family instances, though, we need to re-split for each+ instance, because the breakdown might be different for each+ instance. Why? Because of eta reduction; see+ Note [Eta reduction for data families].+-}++-- checks if one LHS is dominated by a list of other branches+-- in other words, if an application would match the first LHS, it is guaranteed+-- to match at least one of the others. The RHSs are ignored.+-- This algorithm is conservative:+-- True -> the LHS is definitely covered by the others+-- False -> no information+-- It is currently (Oct 2012) used only for generating errors for+-- inaccessible branches. If these errors go unreported, no harm done.+-- This is defined here to avoid a dependency from CoAxiom to Unify+isDominatedBy :: CoAxBranch -> [CoAxBranch] -> Bool+isDominatedBy branch branches+ = or $ map match branches+ where+ lhs = coAxBranchLHS branch+ match (CoAxBranch { cab_lhs = tys })+ = isJust $ tcMatchTys tys lhs++{-+************************************************************************+* *+ Choosing an axiom application+* *+************************************************************************++The lookupFamInstEnv function does a nice job for *open* type families,+but we also need to handle closed ones when normalising a type:+-}++reduceTyFamApp_maybe :: FamInstEnvs+ -> Role -- Desired role of result coercion+ -> TyCon -> [Type]+ -> Maybe (Coercion, Type)+-- Attempt to do a *one-step* reduction of a type-family application+-- but *not* newtypes+-- Works on type-synonym families always; data-families only if+-- the role we seek is representational+-- It does *not* normlise the type arguments first, so this may not+-- go as far as you want. If you want normalised type arguments,+-- use normaliseTcArgs first.+--+-- The TyCon can be oversaturated.+-- Works on both open and closed families+--+-- Always returns a *homogeneous* coercion -- type family reductions are always+-- homogeneous+reduceTyFamApp_maybe envs role tc tys+ | Phantom <- role+ = Nothing++ | case role of+ Representational -> isOpenFamilyTyCon tc+ _ -> isOpenTypeFamilyTyCon tc+ -- If we seek a representational coercion+ -- (e.g. the call in topNormaliseType_maybe) then we can+ -- unwrap data families as well as type-synonym families;+ -- otherwise only type-synonym families+ , FamInstMatch { fim_instance = FamInst { fi_axiom = ax }+ , fim_tys = inst_tys+ , fim_cos = inst_cos } : _ <- lookupFamInstEnv envs tc tys+ -- NB: Allow multiple matches because of compatible overlap++ = let co = mkUnbranchedAxInstCo role ax inst_tys inst_cos+ ty = pSnd (coercionKind co)+ in Just (co, ty)++ | Just ax <- isClosedSynFamilyTyConWithAxiom_maybe tc+ , Just (ind, inst_tys, inst_cos) <- chooseBranch ax tys+ = let co = mkAxInstCo role ax ind inst_tys inst_cos+ ty = pSnd (coercionKind co)+ in Just (co, ty)++ | Just ax <- isBuiltInSynFamTyCon_maybe tc+ , Just (coax,ts,ty) <- sfMatchFam ax tys+ = let co = mkAxiomRuleCo coax (zipWith mkReflCo (coaxrAsmpRoles coax) ts)+ in Just (co, ty)++ | otherwise+ = Nothing++-- The axiom can be oversaturated. (Closed families only.)+chooseBranch :: CoAxiom Branched -> [Type]+ -> Maybe (BranchIndex, [Type], [Coercion]) -- found match, with args+chooseBranch axiom tys+ = do { let num_pats = coAxiomNumPats axiom+ (target_tys, extra_tys) = splitAt num_pats tys+ branches = coAxiomBranches axiom+ ; (ind, inst_tys, inst_cos)+ <- findBranch (fromBranches branches) target_tys+ ; return ( ind, inst_tys `chkAppend` extra_tys, inst_cos ) }++-- The axiom must *not* be oversaturated+findBranch :: [CoAxBranch] -- branches to check+ -> [Type] -- target types+ -> Maybe (BranchIndex, [Type], [Coercion])+ -- coercions relate requested types to returned axiom LHS at role N+findBranch branches target_tys+ = go 0 branches+ where+ go ind (branch@(CoAxBranch { cab_tvs = tpl_tvs, cab_cvs = tpl_cvs+ , cab_lhs = tpl_lhs+ , cab_incomps = incomps }) : rest)+ = let in_scope = mkInScopeSet (unionVarSets $+ map (tyCoVarsOfTypes . coAxBranchLHS) incomps)+ -- See Note [Flattening] below+ flattened_target = flattenTys in_scope target_tys+ in case tcMatchTys tpl_lhs target_tys of+ Just subst -- matching worked. now, check for apartness.+ | apartnessCheck flattened_target branch+ -> -- matching worked & we're apart from all incompatible branches.+ -- success+ ASSERT( all (isJust . lookupCoVar subst) tpl_cvs )+ Just (ind, substTyVars subst tpl_tvs, substCoVars subst tpl_cvs)++ -- failure. keep looking+ _ -> go (ind+1) rest++ -- fail if no branches left+ go _ [] = Nothing++-- | Do an apartness check, as described in the "Closed Type Families" paper+-- (POPL '14). This should be used when determining if an equation+-- ('CoAxBranch') of a closed type family can be used to reduce a certain target+-- type family application.+apartnessCheck :: [Type] -- ^ /flattened/ target arguments. Make sure+ -- they're flattened! See Note [Flattening].+ -- (NB: This "flat" is a different+ -- "flat" than is used in TcFlatten.)+ -> CoAxBranch -- ^ the candidate equation we wish to use+ -- Precondition: this matches the target+ -> Bool -- ^ True <=> equation can fire+apartnessCheck flattened_target (CoAxBranch { cab_incomps = incomps })+ = all (isSurelyApart+ . tcUnifyTysFG (const BindMe) flattened_target+ . coAxBranchLHS) incomps+ where+ isSurelyApart SurelyApart = True+ isSurelyApart _ = False++{-+************************************************************************+* *+ Looking up a family instance+* *+************************************************************************++Note [Normalising types]+~~~~~~~~~~~~~~~~~~~~~~~~+The topNormaliseType function removes all occurrences of type families+and newtypes from the top-level structure of a type. normaliseTcApp does+the type family lookup and is fairly straightforward. normaliseType is+a little more involved.++The complication comes from the fact that a type family might be used in the+kind of a variable bound in a forall. We wish to remove this type family+application, but that means coming up with a fresh variable (with the new+kind). Thus, we need a substitution to be built up as we recur through the+type. However, an ordinary TCvSubst just won't do: when we hit a type variable+whose kind has changed during normalisation, we need both the new type+variable *and* the coercion. We could conjure up a new VarEnv with just this+property, but a usable substitution environment already exists:+LiftingContexts from the liftCoSubst family of functions, defined in Coercion.+A LiftingContext maps a type variable to a coercion and a coercion variable to+a pair of coercions. Let's ignore coercion variables for now. Because the+coercion a type variable maps to contains the destination type (via+coercionKind), we don't need to store that destination type separately. Thus,+a LiftingContext has what we need: a map from type variables to (Coercion,+Type) pairs.++We also benefit because we can piggyback on the liftCoSubstVarBndr function to+deal with binders. However, I had to modify that function to work with this+application. Thus, we now have liftCoSubstVarBndrCallback, which takes+a function used to process the kind of the binder. We don't wish+to lift the kind, but instead normalise it. So, we pass in a callback function+that processes the kind of the binder.++After that brilliant explanation of all this, I'm sure you've forgotten the+dangling reference to coercion variables. What do we do with those? Nothing at+all. The point of normalising types is to remove type family applications, but+there's no sense in removing these from coercions. We would just get back a+new coercion witnessing the equality between the same types as the original+coercion. Because coercions are irrelevant anyway, there is no point in doing+this. So, whenever we encounter a coercion, we just say that it won't change.+That's what the CoercionTy case is doing within normalise_type.++Note [Normalisation and type synonyms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We need to be a bit careful about normalising in the presence of type+synonyms (Trac #13035). Suppose S is a type synonym, and we have+ S t1 t2+If S is family-free (on its RHS) we can just normalise t1 and t2 and+reconstruct (S t1' t2'). Expanding S could not reveal any new redexes+because type families are saturated.++But if S has a type family on its RHS we expand /before/ normalising+the args t1, t2. If we normalise t1, t2 first, we'll re-normalise them+after expansion, and that can lead to /exponential/ behavour; see Trac #13035.++Notice, though, that expanding first can in principle duplicate t1,t2,+which might contain redexes. I'm sure you could conjure up an exponential+case by that route too, but it hasn't happened in practice yet!+-}++topNormaliseType :: FamInstEnvs -> Type -> Type+topNormaliseType env ty = case topNormaliseType_maybe env ty of+ Just (_co, ty') -> ty'+ Nothing -> ty++topNormaliseType_maybe :: FamInstEnvs -> Type -> Maybe (Coercion, Type)++-- ^ Get rid of *outermost* (or toplevel)+-- * type function redex+-- * data family redex+-- * newtypes+-- returning an appropriate Representational coercion. Specifically, if+-- topNormaliseType_maybe env ty = Just (co, ty')+-- then+-- (a) co :: ty ~R ty'+-- (b) ty' is not a newtype, and is not a type-family or data-family redex+--+-- However, ty' can be something like (Maybe (F ty)), where+-- (F ty) is a redex.++topNormaliseType_maybe env ty+ = topNormaliseTypeX stepper mkTransCo ty+ where+ stepper = unwrapNewTypeStepper `composeSteppers` tyFamStepper++ tyFamStepper rec_nts tc tys -- Try to step a type/data family+ = let (args_co, ntys) = normaliseTcArgs env Representational tc tys in+ -- NB: It's OK to use normaliseTcArgs here instead of+ -- normalise_tc_args (which takes the LiftingContext described+ -- in Note [Normalising types]) because the reduceTyFamApp below+ -- works only at top level. We'll never recur in this function+ -- after reducing the kind of a bound tyvar.++ case reduceTyFamApp_maybe env Representational tc ntys of+ Just (co, rhs) -> NS_Step rec_nts rhs (args_co `mkTransCo` co)+ _ -> NS_Done++---------------+pmTopNormaliseType_maybe :: FamInstEnvs -> Type -> Maybe (Type, [DataCon], Type)+-- ^ Get rid of *outermost* (or toplevel)+-- * type function redex+-- * data family redex+-- * newtypes+--+-- Behaves exactly like `topNormaliseType_maybe`, but instead of returning a+-- coercion, it returns useful information for issuing pattern matching+-- warnings. See Note [Type normalisation for EmptyCase] for details.+pmTopNormaliseType_maybe env typ+ = do ((ty_f,tm_f), ty) <- topNormaliseTypeX stepper comb typ+ return (eq_src_ty ty (typ : ty_f [ty]), tm_f [], ty)+ where+ -- Find the first type in the sequence of rewrites that is a data type,+ -- newtype, or a data family application (not the representation tycon!).+ -- This is the one that is equal (in source Haskell) to the initial type.+ -- If none is found in the list, then all of them are type family+ -- applications, so we simply return the last one, which is the *simplest*.+ eq_src_ty :: Type -> [Type] -> Type+ eq_src_ty ty tys = maybe ty id (find is_alg_or_data_family tys)++ is_alg_or_data_family :: Type -> Bool+ is_alg_or_data_family ty = isClosedAlgType ty || isDataFamilyAppType ty++ -- For efficiency, represent both lists as difference lists.+ -- comb performs the concatenation, for both lists.+ comb (tyf1, tmf1) (tyf2, tmf2) = (tyf1 . tyf2, tmf1 . tmf2)++ stepper = newTypeStepper `composeSteppers` tyFamStepper++ -- A 'NormaliseStepper' that unwraps newtypes, careful not to fall into+ -- a loop. If it would fall into a loop, it produces 'NS_Abort'.+ newTypeStepper :: NormaliseStepper ([Type] -> [Type],[DataCon] -> [DataCon])+ newTypeStepper rec_nts tc tys+ | Just (ty', _co) <- instNewTyCon_maybe tc tys+ = case checkRecTc rec_nts tc of+ Just rec_nts' -> let tyf = ((TyConApp tc tys):)+ tmf = ((tyConSingleDataCon tc):)+ in NS_Step rec_nts' ty' (tyf, tmf)+ Nothing -> NS_Abort+ | otherwise+ = NS_Done++ tyFamStepper :: NormaliseStepper ([Type] -> [Type], [DataCon] -> [DataCon])+ tyFamStepper rec_nts tc tys -- Try to step a type/data family+ = let (_args_co, ntys) = normaliseTcArgs env Representational tc tys in+ -- NB: It's OK to use normaliseTcArgs here instead of+ -- normalise_tc_args (which takes the LiftingContext described+ -- in Note [Normalising types]) because the reduceTyFamApp below+ -- works only at top level. We'll never recur in this function+ -- after reducing the kind of a bound tyvar.++ case reduceTyFamApp_maybe env Representational tc ntys of+ Just (_co, rhs) -> NS_Step rec_nts rhs ((rhs:), id)+ _ -> NS_Done++{- Note [Type normalisation for EmptyCase]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+EmptyCase is an exception for pattern matching, since it is strict. This means+that it boils down to checking whether the type of the scrutinee is inhabited.+Function pmTopNormaliseType_maybe gets rid of the outermost type function/data+family redex and newtypes, in search of an algebraic type constructor, which is+easier to check for inhabitation.++It returns 3 results instead of one, because there are 2 subtle points:+1. Newtypes are isomorphic to the underlying type in core but not in the source+ language,+2. The representational data family tycon is used internally but should not be+ shown to the user++Hence, if pmTopNormaliseType_maybe env ty = Just (src_ty, dcs, core_ty), then+ (a) src_ty is the rewritten type which we can show to the user. That is, the+ type we get if we rewrite type families but not data families or+ newtypes.+ (b) dcs is the list of data constructors "skipped", every time we normalise a+ newtype to it's core representation, we keep track of the source data+ constructor.+ (c) core_ty is the rewritten type. That is,+ pmTopNormaliseType_maybe env ty = Just (src_ty, dcs, core_ty)+ implies+ topNormaliseType_maybe env ty = Just (co, core_ty)+ for some coercion co.++To see how all cases come into play, consider the following example:++ data family T a :: *+ data instance T Int = T1 | T2 Bool+ -- Which gives rise to FC:+ -- data T a+ -- data R:TInt = T1 | T2 Bool+ -- axiom ax_ti : T Int ~R R:TInt++ newtype G1 = MkG1 (T Int)+ newtype G2 = MkG2 G1++ type instance F Int = F Char+ type instance F Char = G2++In this case pmTopNormaliseType_maybe env (F Int) results in++ Just (G2, [MkG2,MkG1], R:TInt)++Which means that in source Haskell:+ - G2 is equivalent to F Int (in contrast, G1 isn't).+ - if (x : R:TInt) then (MkG2 (MkG1 x) : F Int).+-}++---------------+normaliseTcApp :: FamInstEnvs -> Role -> TyCon -> [Type] -> (Coercion, Type)+-- See comments on normaliseType for the arguments of this function+normaliseTcApp env role tc tys+ = initNormM env role (tyCoVarsOfTypes tys) $+ normalise_tc_app tc tys++-- See Note [Normalising types] about the LiftingContext+normalise_tc_app :: TyCon -> [Type] -> NormM (Coercion, Type)+normalise_tc_app tc tys+ | Just (tenv, rhs, tys') <- expandSynTyCon_maybe tc tys+ , not (isFamFreeTyCon tc) -- Expand and try again+ = -- A synonym with type families in the RHS+ -- Expand and try again+ -- See Note [Normalisation and type synonyms]+ normalise_type (mkAppTys (substTy (mkTvSubstPrs tenv) rhs) tys')++ | not (isTypeFamilyTyCon tc)+ = -- A synonym with no type families in the RHS; or data type etc+ -- Just normalise the arguments and rebuild+ do { (args_co, ntys) <- normalise_tc_args tc tys+ ; return (args_co, mkTyConApp tc ntys) }++ | otherwise+ = -- A type-family application+ do { env <- getEnv+ ; role <- getRole+ ; (args_co, ntys) <- normalise_tc_args tc tys+ ; case reduceTyFamApp_maybe env role tc ntys of+ Just (first_co, ty')+ -> do { (rest_co,nty) <- normalise_type ty'+ ; return ( args_co `mkTransCo` first_co `mkTransCo` rest_co+ , nty ) }+ _ -> -- No unique matching family instance exists;+ -- we do not do anything+ return (args_co, mkTyConApp tc ntys) }++---------------+-- | Normalise arguments to a tycon+normaliseTcArgs :: FamInstEnvs -- ^ env't with family instances+ -> Role -- ^ desired role of output coercion+ -> TyCon -- ^ tc+ -> [Type] -- ^ tys+ -> (Coercion, [Type]) -- ^ co :: tc tys ~ tc new_tys+normaliseTcArgs env role tc tys+ = initNormM env role (tyCoVarsOfTypes tys) $+ normalise_tc_args tc tys++normalise_tc_args :: TyCon -> [Type] -- tc tys+ -> NormM (Coercion, [Type]) -- (co, new_tys), where+ -- co :: tc tys ~ tc new_tys+normalise_tc_args tc tys+ = do { role <- getRole+ ; (cois, ntys) <- zipWithAndUnzipM normalise_type_role+ tys (tyConRolesX role tc)+ ; return (mkTyConAppCo role tc cois, ntys) }+ where+ normalise_type_role ty r = withRole r $ normalise_type ty++---------------+normaliseType :: FamInstEnvs+ -> Role -- desired role of coercion+ -> Type -> (Coercion, Type)+normaliseType env role ty+ = initNormM env role (tyCoVarsOfType ty) $ normalise_type ty++normalise_type :: Type -- old type+ -> NormM (Coercion, Type) -- (coercion,new type), where+ -- co :: old-type ~ new_type+-- Normalise the input type, by eliminating *all* type-function redexes+-- but *not* newtypes (which are visible to the programmer)+-- Returns with Refl if nothing happens+-- Does nothing to newtypes+-- The returned coercion *must* be *homogeneous*+-- See Note [Normalising types]+-- Try to not to disturb type synonyms if possible++normalise_type ty+ = go ty+ where+ go (TyConApp tc tys) = normalise_tc_app tc tys+ go ty@(LitTy {}) = do { r <- getRole+ ; return (mkReflCo r ty, ty) }+ go (AppTy ty1 ty2)+ = do { (co, nty1) <- go ty1+ ; (arg, nty2) <- withRole Nominal $ go ty2+ ; return (mkAppCo co arg, mkAppTy nty1 nty2) }+ go (FunTy ty1 ty2)+ = do { (co1, nty1) <- go ty1+ ; (co2, nty2) <- go ty2+ ; r <- getRole+ ; return (mkFunCo r co1 co2, mkFunTy nty1 nty2) }+ go (ForAllTy (TvBndr tyvar vis) ty)+ = do { (lc', tv', h, ki') <- normalise_tyvar_bndr tyvar+ ; (co, nty) <- withLC lc' $ normalise_type ty+ ; let tv2 = setTyVarKind tv' ki'+ ; return (mkForAllCo tv' h co, ForAllTy (TvBndr tv2 vis) nty) }+ go (TyVarTy tv) = normalise_tyvar tv+ go (CastTy ty co)+ = do { (nco, nty) <- go ty+ ; lc <- getLC+ ; let co' = substRightCo lc co+ ; return (castCoercionKind nco co co', mkCastTy nty co') }+ go (CoercionTy co)+ = do { lc <- getLC+ ; r <- getRole+ ; let right_co = substRightCo lc co+ ; return ( mkProofIrrelCo r+ (liftCoSubst Nominal lc (coercionType co))+ co right_co+ , mkCoercionTy right_co ) }++normalise_tyvar :: TyVar -> NormM (Coercion, Type)+normalise_tyvar tv+ = ASSERT( isTyVar tv )+ do { lc <- getLC+ ; r <- getRole+ ; return $ case liftCoSubstTyVar lc r tv of+ Just co -> (co, pSnd $ coercionKind co)+ Nothing -> (mkReflCo r ty, ty) }+ where ty = mkTyVarTy tv++normalise_tyvar_bndr :: TyVar -> NormM (LiftingContext, TyVar, Coercion, Kind)+normalise_tyvar_bndr tv+ = do { lc1 <- getLC+ ; env <- getEnv+ ; let callback lc ki = runNormM (normalise_type ki) env lc Nominal+ ; return $ liftCoSubstVarBndrCallback callback lc1 tv }++-- | a monad for the normalisation functions, reading 'FamInstEnvs',+-- a 'LiftingContext', and a 'Role'.+newtype NormM a = NormM { runNormM ::+ FamInstEnvs -> LiftingContext -> Role -> a }++initNormM :: FamInstEnvs -> Role+ -> TyCoVarSet -- the in-scope variables+ -> NormM a -> a+initNormM env role vars (NormM thing_inside)+ = thing_inside env lc role+ where+ in_scope = mkInScopeSet vars+ lc = emptyLiftingContext in_scope++getRole :: NormM Role+getRole = NormM (\ _ _ r -> r)++getLC :: NormM LiftingContext+getLC = NormM (\ _ lc _ -> lc)++getEnv :: NormM FamInstEnvs+getEnv = NormM (\ env _ _ -> env)++withRole :: Role -> NormM a -> NormM a+withRole r thing = NormM $ \ envs lc _old_r -> runNormM thing envs lc r++withLC :: LiftingContext -> NormM a -> NormM a+withLC lc thing = NormM $ \ envs _old_lc r -> runNormM thing envs lc r++instance Monad NormM where+ ma >>= fmb = NormM $ \env lc r ->+ let a = runNormM ma env lc r in+ runNormM (fmb a) env lc r++instance Functor NormM where+ fmap = liftM+instance Applicative NormM where+ pure x = NormM $ \ _ _ _ -> x+ (<*>) = ap++{-+************************************************************************+* *+ Flattening+* *+************************************************************************++Note [Flattening]+~~~~~~~~~~~~~~~~~+As described in "Closed type families with overlapping equations"+http://research.microsoft.com/en-us/um/people/simonpj/papers/ext-f/axioms-extended.pdf+we need to flatten core types before unifying them, when checking for "surely-apart"+against earlier equations of a closed type family.+Flattening means replacing all top-level uses of type functions with+fresh variables, *taking care to preserve sharing*. That is, the type+(Either (F a b) (F a b)) should flatten to (Either c c), never (Either+c d).++Here is a nice example of why it's all necessary:++ type family F a b where+ F Int Bool = Char+ F a b = Double+ type family G a -- open, no instances++How do we reduce (F (G Float) (G Float))? The first equation clearly doesn't match,+while the second equation does. But, before reducing, we must make sure that the+target can never become (F Int Bool). Well, no matter what G Float becomes, it+certainly won't become *both* Int and Bool, so indeed we're safe reducing+(F (G Float) (G Float)) to Double.++This is necessary not only to get more reductions (which we might be+willing to give up on), but for substitutivity. If we have (F x x), we+can see that (F x x) can reduce to Double. So, it had better be the+case that (F blah blah) can reduce to Double, no matter what (blah)+is! Flattening as done below ensures this.++flattenTys is defined here because of module dependencies.+-}++data FlattenEnv = FlattenEnv { fe_type_map :: TypeMap TyVar+ , fe_subst :: TCvSubst }++emptyFlattenEnv :: InScopeSet -> FlattenEnv+emptyFlattenEnv in_scope+ = FlattenEnv { fe_type_map = emptyTypeMap+ , fe_subst = mkEmptyTCvSubst in_scope }++-- See Note [Flattening]+flattenTys :: InScopeSet -> [Type] -> [Type]+flattenTys in_scope tys = snd $ coreFlattenTys env tys+ where+ -- when we hit a type function, we replace it with a fresh variable+ -- but, we need to make sure that this fresh variable isn't mentioned+ -- *anywhere* in the types we're flattening, even if locally-bound in+ -- a forall. That way, we can ensure consistency both within and outside+ -- of that forall.+ all_in_scope = in_scope `extendInScopeSetSet` allTyVarsInTys tys+ env = emptyFlattenEnv all_in_scope++coreFlattenTys :: FlattenEnv -> [Type] -> (FlattenEnv, [Type])+coreFlattenTys = go []+ where+ go rtys env [] = (env, reverse rtys)+ go rtys env (ty : tys)+ = let (env', ty') = coreFlattenTy env ty in+ go (ty' : rtys) env' tys++coreFlattenTy :: FlattenEnv -> Type -> (FlattenEnv, Type)+coreFlattenTy = go+ where+ go env ty | Just ty' <- coreView ty = go env ty'++ go env (TyVarTy tv) = (env, substTyVar (fe_subst env) tv)+ go env (AppTy ty1 ty2) = let (env1, ty1') = go env ty1+ (env2, ty2') = go env1 ty2 in+ (env2, AppTy ty1' ty2')+ go env (TyConApp tc tys)+ -- NB: Don't just check if isFamilyTyCon: this catches *data* families,+ -- which are generative and thus can be preserved during flattening+ | not (isGenerativeTyCon tc Nominal)+ = let (env', tv) = coreFlattenTyFamApp env tc tys in+ (env', mkTyVarTy tv)++ | otherwise+ = let (env', tys') = coreFlattenTys env tys in+ (env', mkTyConApp tc tys')++ go env (FunTy ty1 ty2) = let (env1, ty1') = go env ty1+ (env2, ty2') = go env1 ty2 in+ (env2, mkFunTy ty1' ty2')++ go env (ForAllTy (TvBndr tv vis) ty)+ = let (env1, tv') = coreFlattenVarBndr env tv+ (env2, ty') = go env1 ty in+ (env2, ForAllTy (TvBndr tv' vis) ty')++ go env ty@(LitTy {}) = (env, ty)++ go env (CastTy ty co) = let (env1, ty') = go env ty+ (env2, co') = coreFlattenCo env1 co in+ (env2, CastTy ty' co')++ go env (CoercionTy co) = let (env', co') = coreFlattenCo env co in+ (env', CoercionTy co')++-- when flattening, we don't care about the contents of coercions.+-- so, just return a fresh variable of the right (flattened) type+coreFlattenCo :: FlattenEnv -> Coercion -> (FlattenEnv, Coercion)+coreFlattenCo env co+ = (env2, mkCoVarCo covar)+ where+ (env1, kind') = coreFlattenTy env (coercionType co)+ fresh_name = mkFlattenFreshCoName+ subst1 = fe_subst env1+ in_scope = getTCvInScope subst1+ covar = uniqAway in_scope (mkCoVar fresh_name kind')+ env2 = env1 { fe_subst = subst1 `extendTCvInScope` covar }++coreFlattenVarBndr :: FlattenEnv -> TyVar -> (FlattenEnv, TyVar)+coreFlattenVarBndr env tv+ | kind' `eqType` kind+ = ( env { fe_subst = extendTvSubst old_subst tv (mkTyVarTy tv) }+ -- override any previous binding for tv+ , tv)++ | otherwise+ = let new_tv = uniqAway (getTCvInScope old_subst) (setTyVarKind tv kind')+ new_subst = extendTvSubstWithClone old_subst tv new_tv+ in+ (env' { fe_subst = new_subst }, new_tv)+ where+ kind = tyVarKind tv+ (env', kind') = coreFlattenTy env kind+ old_subst = fe_subst env++coreFlattenTyFamApp :: FlattenEnv+ -> TyCon -- type family tycon+ -> [Type] -- args+ -> (FlattenEnv, TyVar)+coreFlattenTyFamApp env fam_tc fam_args+ = case lookupTypeMap type_map fam_ty of+ Just tv -> (env, tv)+ -- we need fresh variables here, but this is called far from+ -- any good source of uniques. So, we just use the fam_tc's unique+ -- and trust uniqAway to avoid clashes. Recall that the in_scope set+ -- contains *all* tyvars, even locally bound ones elsewhere in the+ -- overall type, so this really is fresh.+ Nothing -> let tyvar_name = mkFlattenFreshTyName fam_tc+ tv = uniqAway (getTCvInScope subst) $+ mkTyVar tyvar_name (typeKind fam_ty)+ env' = env { fe_type_map = extendTypeMap type_map fam_ty tv+ , fe_subst = extendTCvInScope subst tv }+ in (env', tv)+ where fam_ty = mkTyConApp fam_tc fam_args+ FlattenEnv { fe_type_map = type_map+ , fe_subst = subst } = env++-- | Get the set of all type variables mentioned anywhere in the list+-- of types. These variables are not necessarily free.+allTyVarsInTys :: [Type] -> VarSet+allTyVarsInTys [] = emptyVarSet+allTyVarsInTys (ty:tys) = allTyVarsInTy ty `unionVarSet` allTyVarsInTys tys++-- | Get the set of all type variables mentioned anywhere in a type.+allTyVarsInTy :: Type -> VarSet+allTyVarsInTy = go+ where+ go (TyVarTy tv) = unitVarSet tv+ go (TyConApp _ tys) = allTyVarsInTys tys+ go (AppTy ty1 ty2) = (go ty1) `unionVarSet` (go ty2)+ go (FunTy ty1 ty2) = (go ty1) `unionVarSet` (go ty2)+ go (ForAllTy (TvBndr tv _) ty) = unitVarSet tv `unionVarSet`+ go (tyVarKind tv) `unionVarSet`+ go ty+ -- Don't remove the tv from the set!+ go (LitTy {}) = emptyVarSet+ go (CastTy ty co) = go ty `unionVarSet` go_co co+ go (CoercionTy co) = go_co co++ go_co (Refl _ ty) = go ty+ go_co (TyConAppCo _ _ args) = go_cos args+ go_co (AppCo co arg) = go_co co `unionVarSet` go_co arg+ go_co (ForAllCo tv h co)+ = unionVarSets [unitVarSet tv, go_co co, go_co h]+ go_co (FunCo _ c1 c2) = go_co c1 `unionVarSet` go_co c2+ go_co (CoVarCo cv) = unitVarSet cv+ go_co (AxiomInstCo _ _ cos) = go_cos cos+ go_co (UnivCo p _ t1 t2) = go_prov p `unionVarSet` go t1 `unionVarSet` go t2+ go_co (SymCo co) = go_co co+ go_co (TransCo c1 c2) = go_co c1 `unionVarSet` go_co c2+ go_co (NthCo _ co) = go_co co+ go_co (LRCo _ co) = go_co co+ go_co (InstCo co arg) = go_co co `unionVarSet` go_co arg+ go_co (CoherenceCo c1 c2) = go_co c1 `unionVarSet` go_co c2+ go_co (KindCo co) = go_co co+ go_co (SubCo co) = go_co co+ go_co (AxiomRuleCo _ cs) = go_cos cs++ go_cos = foldr (unionVarSet . go_co) emptyVarSet++ go_prov UnsafeCoerceProv = emptyVarSet+ go_prov (PhantomProv co) = go_co co+ go_prov (ProofIrrelProv co) = go_co co+ go_prov (PluginProv _) = emptyVarSet+ go_prov (HoleProv _) = emptyVarSet++mkFlattenFreshTyName :: Uniquable a => a -> Name+mkFlattenFreshTyName unq+ = mkSysTvName (getUnique unq) (fsLit "flt")++mkFlattenFreshCoName :: Name+mkFlattenFreshCoName+ = mkSystemVarName (deriveUnique eqPrimTyConKey 71) (fsLit "flc")
+ types/InstEnv.hs view
@@ -0,0 +1,996 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[InstEnv]{Utilities for typechecking instance declarations}++The bits common to TcInstDcls and TcDeriv.+-}++{-# LANGUAGE CPP, DeriveDataTypeable #-}++module InstEnv (+ DFunId, InstMatch, ClsInstLookupResult,+ OverlapFlag(..), OverlapMode(..), setOverlapModeMaybe,+ ClsInst(..), DFunInstType, pprInstance, pprInstanceHdr, pprInstances,+ instanceHead, instanceSig, mkLocalInstance, mkImportedInstance,+ instanceDFunId, tidyClsInstDFun, instanceRoughTcs,+ fuzzyClsInstCmp, orphNamesOfClsInst,++ InstEnvs(..), VisibleOrphanModules, InstEnv,+ emptyInstEnv, extendInstEnv, deleteFromInstEnv, identicalClsInstHead,+ extendInstEnvList, lookupUniqueInstEnv, lookupInstEnv, instEnvElts,+ memberInstEnv, instIsVisible,+ classInstances, instanceBindFun,+ instanceCantMatch, roughMatchTcs,+ isOverlappable, isOverlapping, isIncoherent+ ) where++#include "HsVersions.h"++import TcType -- InstEnv is really part of the type checker,+ -- and depends on TcType in many ways+import CoreSyn ( IsOrphan(..), isOrphan, chooseOrphanAnchor )+import Module+import Class+import Var+import VarSet+import Name+import NameSet+import Unify+import Outputable+import ErrUtils+import BasicTypes+import UniqDFM+import Util+import Id+import Data.Data ( Data )+import Data.Maybe ( isJust, isNothing )++{-+************************************************************************+* *+ ClsInst: the data type for type-class instances+* *+************************************************************************+-}++-- | A type-class instance. Note that there is some tricky laziness at work+-- here. See Note [ClsInst laziness and the rough-match fields] for more+-- details.+data ClsInst+ = ClsInst { -- Used for "rough matching"; see+ -- Note [ClsInst laziness and the rough-match fields]+ -- INVARIANT: is_tcs = roughMatchTcs is_tys+ is_cls_nm :: Name -- ^ Class name+ , is_tcs :: [Maybe Name] -- ^ Top of type args++ -- | @is_dfun_name = idName . is_dfun@.+ --+ -- We use 'is_dfun_name' for the visibility check,+ -- 'instIsVisible', which needs to know the 'Module' which the+ -- dictionary is defined in. However, we cannot use the 'Module'+ -- attached to 'is_dfun' since doing so would mean we would+ -- potentially pull in an entire interface file unnecessarily.+ -- This was the cause of #12367.+ , is_dfun_name :: Name++ -- Used for "proper matching"; see Note [Proper-match fields]+ , is_tvs :: [TyVar] -- Fresh template tyvars for full match+ -- See Note [Template tyvars are fresh]+ , is_cls :: Class -- The real class+ , is_tys :: [Type] -- Full arg types (mentioning is_tvs)+ -- INVARIANT: is_dfun Id has type+ -- forall is_tvs. (...) => is_cls is_tys+ -- (modulo alpha conversion)++ , is_dfun :: DFunId -- See Note [Haddock assumptions]++ , is_flag :: OverlapFlag -- See detailed comments with+ -- the decl of BasicTypes.OverlapFlag+ , is_orphan :: IsOrphan+ }+ deriving Data++-- | A fuzzy comparison function for class instances, intended for sorting+-- instances before displaying them to the user.+fuzzyClsInstCmp :: ClsInst -> ClsInst -> Ordering+fuzzyClsInstCmp x y =+ stableNameCmp (is_cls_nm x) (is_cls_nm y) `mappend`+ mconcat (map cmp (zip (is_tcs x) (is_tcs y)))+ where+ cmp (Nothing, Nothing) = EQ+ cmp (Nothing, Just _) = LT+ cmp (Just _, Nothing) = GT+ cmp (Just x, Just y) = stableNameCmp x y++isOverlappable, isOverlapping, isIncoherent :: ClsInst -> Bool+isOverlappable i = hasOverlappableFlag (overlapMode (is_flag i))+isOverlapping i = hasOverlappingFlag (overlapMode (is_flag i))+isIncoherent i = hasIncoherentFlag (overlapMode (is_flag i))++{-+Note [ClsInst laziness and the rough-match fields]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we load 'instance A.C B.T' from A.hi, but suppose that the type B.T is+otherwise unused in the program. Then it's stupid to load B.hi, the data type+declaration for B.T -- and perhaps further instance declarations!++We avoid this as follows:++* is_cls_nm, is_tcs, is_dfun_name are all Names. We can poke them to our heart's+ content.++* Proper-match fields. is_dfun, and its related fields is_tvs, is_cls, is_tys+ contain TyVars, Class, Type, Class etc, and so are all lazy thunks. When we+ poke any of these fields we'll typecheck the DFunId declaration, and hence+ pull in interfaces that it refers to. See Note [Proper-match fields].++* Rough-match fields. During instance lookup, we use the is_cls_nm :: Name and+ is_tcs :: [Maybe Name] fields to perform a "rough match", *without* poking+ inside the DFunId. The rough-match fields allow us to say "definitely does not+ match", based only on Names.++ This laziness is very important; see Trac #12367. Try hard to avoid pulling on+ the structured fields unless you really need the instance.++* Another place to watch is InstEnv.instIsVisible, which needs the module to+ which the ClsInst belongs. We can get this from is_dfun_name.++* In is_tcs,+ Nothing means that this type arg is a type variable++ (Just n) means that this type arg is a+ TyConApp with a type constructor of n.+ This is always a real tycon, never a synonym!+ (Two different synonyms might match, but two+ different real tycons can't.)+ NB: newtypes are not transparent, though!+-}++{-+Note [Template tyvars are fresh]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The is_tvs field of a ClsInst has *completely fresh* tyvars.+That is, they are+ * distinct from any other ClsInst+ * distinct from any tyvars free in predicates that may+ be looked up in the class instance environment+Reason for freshness: we use unification when checking for overlap+etc, and that requires the tyvars to be distinct.++The invariant is checked by the ASSERT in lookupInstEnv'.++Note [Proper-match fields]+~~~~~~~~~~~~~~~~~~~~~~~~~+The is_tvs, is_cls, is_tys fields are simply cached values, pulled+out (lazily) from the dfun id. They are cached here simply so+that we don't need to decompose the DFunId each time we want+to match it. The hope is that the rough-match fields mean+that we often never poke the proper-match fields.++However, note that:+ * is_tvs must be a superset of the free vars of is_tys++ * is_tvs, is_tys may be alpha-renamed compared to the ones in+ the dfun Id++Note [Haddock assumptions]+~~~~~~~~~~~~~~~~~~~~~~~~~~+For normal user-written instances, Haddock relies on++ * the SrcSpan of+ * the Name of+ * the is_dfun of+ * an Instance++being equal to++ * the SrcSpan of+ * the instance head type of+ * the InstDecl used to construct the Instance.+-}++instanceDFunId :: ClsInst -> DFunId+instanceDFunId = is_dfun++tidyClsInstDFun :: (DFunId -> DFunId) -> ClsInst -> ClsInst+tidyClsInstDFun tidy_dfun ispec+ = ispec { is_dfun = tidy_dfun (is_dfun ispec) }++instanceRoughTcs :: ClsInst -> [Maybe Name]+instanceRoughTcs = is_tcs+++instance NamedThing ClsInst where+ getName ispec = getName (is_dfun ispec)++instance Outputable ClsInst where+ ppr = pprInstance++pprInstance :: ClsInst -> SDoc+-- Prints the ClsInst as an instance declaration+pprInstance ispec+ = hang (pprInstanceHdr ispec)+ 2 (vcat [ text "--" <+> pprDefinedAt (getName ispec)+ , ifPprDebug (ppr (is_dfun ispec)) ])++-- * pprInstanceHdr is used in VStudio to populate the ClassView tree+pprInstanceHdr :: ClsInst -> SDoc+-- Prints the ClsInst as an instance declaration+pprInstanceHdr (ClsInst { is_flag = flag, is_dfun = dfun })+ = text "instance" <+> ppr flag <+> pprSigmaType (idType dfun)++pprInstances :: [ClsInst] -> SDoc+pprInstances ispecs = vcat (map pprInstance ispecs)++instanceHead :: ClsInst -> ([TyVar], Class, [Type])+-- Returns the head, using the fresh tyavs from the ClsInst+instanceHead (ClsInst { is_tvs = tvs, is_tys = tys, is_dfun = dfun })+ = (tvs, cls, tys)+ where+ (_, _, cls, _) = tcSplitDFunTy (idType dfun)++-- | Collects the names of concrete types and type constructors that make+-- up the head of a class instance. For instance, given `class Foo a b`:+--+-- `instance Foo (Either (Maybe Int) a) Bool` would yield+-- [Either, Maybe, Int, Bool]+--+-- Used in the implementation of ":info" in GHCi.+--+-- The 'tcSplitSigmaTy' is because of+-- instance Foo a => Baz T where ...+-- The decl is an orphan if Baz and T are both not locally defined,+-- even if Foo *is* locally defined+orphNamesOfClsInst :: ClsInst -> NameSet+orphNamesOfClsInst (ClsInst { is_cls_nm = cls_nm, is_tys = tys })+ = orphNamesOfTypes tys `unionNameSet` unitNameSet cls_nm++instanceSig :: ClsInst -> ([TyVar], [Type], Class, [Type])+-- Decomposes the DFunId+instanceSig ispec = tcSplitDFunTy (idType (is_dfun ispec))++mkLocalInstance :: DFunId -> OverlapFlag+ -> [TyVar] -> Class -> [Type]+ -> ClsInst+-- Used for local instances, where we can safely pull on the DFunId.+-- Consider using newClsInst instead; this will also warn if+-- the instance is an orphan.+mkLocalInstance dfun oflag tvs cls tys+ = ClsInst { is_flag = oflag, is_dfun = dfun+ , is_tvs = tvs+ , is_dfun_name = dfun_name+ , is_cls = cls, is_cls_nm = cls_name+ , is_tys = tys, is_tcs = roughMatchTcs tys+ , is_orphan = orph+ }+ where+ cls_name = className cls+ dfun_name = idName dfun+ this_mod = ASSERT( isExternalName dfun_name ) nameModule dfun_name+ is_local name = nameIsLocalOrFrom this_mod name++ -- Compute orphanhood. See Note [Orphans] in InstEnv+ (cls_tvs, fds) = classTvsFds cls+ arg_names = [filterNameSet is_local (orphNamesOfType ty) | ty <- tys]++ -- See Note [When exactly is an instance decl an orphan?]+ orph | is_local cls_name = NotOrphan (nameOccName cls_name)+ | all notOrphan mb_ns = ASSERT( not (null mb_ns) ) head mb_ns+ | otherwise = IsOrphan++ notOrphan NotOrphan{} = True+ notOrphan _ = False++ mb_ns :: [IsOrphan] -- One for each fundep; a locally-defined name+ -- that is not in the "determined" arguments+ mb_ns | null fds = [choose_one arg_names]+ | otherwise = map do_one fds+ do_one (_ltvs, rtvs) = choose_one [ns | (tv,ns) <- cls_tvs `zip` arg_names+ , not (tv `elem` rtvs)]++ choose_one nss = chooseOrphanAnchor (unionNameSets nss)++mkImportedInstance :: Name -- ^ the name of the class+ -> [Maybe Name] -- ^ the types which the class was applied to+ -> Name -- ^ the 'Name' of the dictionary binding+ -> DFunId -- ^ the 'Id' of the dictionary.+ -> OverlapFlag -- ^ may this instance overlap?+ -> IsOrphan -- ^ is this instance an orphan?+ -> ClsInst+-- Used for imported instances, where we get the rough-match stuff+-- from the interface file+-- The bound tyvars of the dfun are guaranteed fresh, because+-- the dfun has been typechecked out of the same interface file+mkImportedInstance cls_nm mb_tcs dfun_name dfun oflag orphan+ = ClsInst { is_flag = oflag, is_dfun = dfun+ , is_tvs = tvs, is_tys = tys+ , is_dfun_name = dfun_name+ , is_cls_nm = cls_nm, is_cls = cls, is_tcs = mb_tcs+ , is_orphan = orphan }+ where+ (tvs, _, cls, tys) = tcSplitDFunTy (idType dfun)++{-+Note [When exactly is an instance decl an orphan?]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ (see MkIface.instanceToIfaceInst, which implements this)+Roughly speaking, an instance is an orphan if its head (after the =>)+mentions nothing defined in this module.++Functional dependencies complicate the situation though. Consider++ module M where { class C a b | a -> b }++and suppose we are compiling module X:++ module X where+ import M+ data T = ...+ instance C Int T where ...++This instance is an orphan, because when compiling a third module Y we+might get a constraint (C Int v), and we'd want to improve v to T. So+we must make sure X's instances are loaded, even if we do not directly+use anything from X.++More precisely, an instance is an orphan iff++ If there are no fundeps, then at least of the names in+ the instance head is locally defined.++ If there are fundeps, then for every fundep, at least one of the+ names free in a *non-determined* part of the instance head is+ defined in this module.++(Note that these conditions hold trivially if the class is locally+defined.)+++************************************************************************+* *+ InstEnv, ClsInstEnv+* *+************************************************************************++A @ClsInstEnv@ all the instances of that class. The @Id@ inside a+ClsInstEnv mapping is the dfun for that instance.++If class C maps to a list containing the item ([a,b], [t1,t2,t3], dfun), then++ forall a b, C t1 t2 t3 can be constructed by dfun++or, to put it another way, we have++ instance (...) => C t1 t2 t3, witnessed by dfun+-}++---------------------------------------------------+{-+Note [InstEnv determinism]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We turn InstEnvs into a list in some places that don't directly affect+the ABI. That happens when we create output for `:info`.+Unfortunately that nondeterminism is nonlocal and it's hard to tell what it+affects without following a chain of functions. It's also easy to accidentally+make that nondeterminism affect the ABI. Furthermore the envs should be+relatively small, so it should be free to use deterministic maps here.+Testing with nofib and validate detected no difference between UniqFM and+UniqDFM. See also Note [Deterministic UniqFM]+-}++type InstEnv = UniqDFM ClsInstEnv -- Maps Class to instances for that class+ -- See Note [InstEnv determinism]++-- | 'InstEnvs' represents the combination of the global type class instance+-- environment, the local type class instance environment, and the set of+-- transitively reachable orphan modules (according to what modules have been+-- directly imported) used to test orphan instance visibility.+data InstEnvs = InstEnvs {+ ie_global :: InstEnv, -- External-package instances+ ie_local :: InstEnv, -- Home-package instances+ ie_visible :: VisibleOrphanModules -- Set of all orphan modules transitively+ -- reachable from the module being compiled+ -- See Note [Instance lookup and orphan instances]+ }++-- | Set of visible orphan modules, according to what modules have been directly+-- imported. This is based off of the dep_orphs field, which records+-- transitively reachable orphan modules (modules that define orphan instances).+type VisibleOrphanModules = ModuleSet++newtype ClsInstEnv+ = ClsIE [ClsInst] -- The instances for a particular class, in any order++instance Outputable ClsInstEnv where+ ppr (ClsIE is) = pprInstances is++-- INVARIANTS:+-- * The is_tvs are distinct in each ClsInst+-- of a ClsInstEnv (so we can safely unify them)++-- Thus, the @ClassInstEnv@ for @Eq@ might contain the following entry:+-- [a] ===> dfun_Eq_List :: forall a. Eq a => Eq [a]+-- The "a" in the pattern must be one of the forall'd variables in+-- the dfun type.++emptyInstEnv :: InstEnv+emptyInstEnv = emptyUDFM++instEnvElts :: InstEnv -> [ClsInst]+instEnvElts ie = [elt | ClsIE elts <- eltsUDFM ie, elt <- elts]+ -- See Note [InstEnv determinism]++-- | Test if an instance is visible, by checking that its origin module+-- is in 'VisibleOrphanModules'.+-- See Note [Instance lookup and orphan instances]+instIsVisible :: VisibleOrphanModules -> ClsInst -> Bool+instIsVisible vis_mods ispec+ -- NB: Instances from the interactive package always are visible. We can't+ -- add interactive modules to the set since we keep creating new ones+ -- as a GHCi session progresses.+ | isInteractiveModule mod = True+ | IsOrphan <- is_orphan ispec = mod `elemModuleSet` vis_mods+ | otherwise = True+ where+ mod = nameModule $ is_dfun_name ispec++classInstances :: InstEnvs -> Class -> [ClsInst]+classInstances (InstEnvs { ie_global = pkg_ie, ie_local = home_ie, ie_visible = vis_mods }) cls+ = get home_ie ++ get pkg_ie+ where+ get env = case lookupUDFM env cls of+ Just (ClsIE insts) -> filter (instIsVisible vis_mods) insts+ Nothing -> []++-- | Checks for an exact match of ClsInst in the instance environment.+-- We use this when we do signature checking in TcRnDriver+memberInstEnv :: InstEnv -> ClsInst -> Bool+memberInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm } ) =+ maybe False (\(ClsIE items) -> any (identicalDFunType ins_item) items)+ (lookupUDFM inst_env cls_nm)+ where+ identicalDFunType cls1 cls2 =+ eqType (varType (is_dfun cls1)) (varType (is_dfun cls2))++extendInstEnvList :: InstEnv -> [ClsInst] -> InstEnv+extendInstEnvList inst_env ispecs = foldl extendInstEnv inst_env ispecs++extendInstEnv :: InstEnv -> ClsInst -> InstEnv+extendInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm })+ = addToUDFM_C add inst_env cls_nm (ClsIE [ins_item])+ where+ add (ClsIE cur_insts) _ = ClsIE (ins_item : cur_insts)++deleteFromInstEnv :: InstEnv -> ClsInst -> InstEnv+deleteFromInstEnv inst_env ins_item@(ClsInst { is_cls_nm = cls_nm })+ = adjustUDFM adjust inst_env cls_nm+ where+ adjust (ClsIE items) = ClsIE (filterOut (identicalClsInstHead ins_item) items)++identicalClsInstHead :: ClsInst -> ClsInst -> Bool+-- ^ True when when the instance heads are the same+-- e.g. both are Eq [(a,b)]+-- Used for overriding in GHCi+-- Obviously should be insenstive to alpha-renaming+identicalClsInstHead (ClsInst { is_cls_nm = cls_nm1, is_tcs = rough1, is_tys = tys1 })+ (ClsInst { is_cls_nm = cls_nm2, is_tcs = rough2, is_tys = tys2 })+ = cls_nm1 == cls_nm2+ && not (instanceCantMatch rough1 rough2) -- Fast check for no match, uses the "rough match" fields+ && isJust (tcMatchTys tys1 tys2)+ && isJust (tcMatchTys tys2 tys1)++{-+************************************************************************+* *+ Looking up an instance+* *+************************************************************************++@lookupInstEnv@ looks up in a @InstEnv@, using a one-way match. Since+the env is kept ordered, the first match must be the only one. The+thing we are looking up can have an arbitrary "flexi" part.++Note [Instance lookup and orphan instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we are compiling a module M, and we have a zillion packages+loaded, and we are looking up an instance for C (T W). If we find a+match in module 'X' from package 'p', should be "in scope"; that is,++ is p:X in the transitive closure of modules imported from M?++The difficulty is that the "zillion packages" might include ones loaded+through earlier invocations of the GHC API, or earlier module loads in GHCi.+They might not be in the dependencies of M itself; and if not, the instances+in them should not be visible. Trac #2182, #8427.++There are two cases:+ * If the instance is *not an orphan*, then module X defines C, T, or W.+ And in order for those types to be involved in typechecking M, it+ must be that X is in the transitive closure of M's imports. So we+ can use the instance.++ * If the instance *is an orphan*, the above reasoning does not apply.+ So we keep track of the set of orphan modules transitively below M;+ this is the ie_visible field of InstEnvs, of type VisibleOrphanModules.++ If module p:X is in this set, then we can use the instance, otherwise+ we can't.++Note [Rules for instance lookup]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+These functions implement the carefully-written rules in the user+manual section on "overlapping instances". At risk of duplication,+here are the rules. If the rules change, change this text and the+user manual simultaneously. The link may be this:+http://www.haskell.org/ghc/docs/latest/html/users_guide/glasgow_exts.html#instance-overlap++The willingness to be overlapped or incoherent is a property of the+instance declaration itself, controlled as follows:++ * An instance is "incoherent"+ if it has an INCOHERENT pragma, or+ if it appears in a module compiled with -XIncoherentInstances.++ * An instance is "overlappable"+ if it has an OVERLAPPABLE or OVERLAPS pragma, or+ if it appears in a module compiled with -XOverlappingInstances, or+ if the instance is incoherent.++ * An instance is "overlapping"+ if it has an OVERLAPPING or OVERLAPS pragma, or+ if it appears in a module compiled with -XOverlappingInstances, or+ if the instance is incoherent.+ compiled with -XOverlappingInstances.++Now suppose that, in some client module, we are searching for an instance+of the target constraint (C ty1 .. tyn). The search works like this.++ * Find all instances I that match the target constraint; that is, the+ target constraint is a substitution instance of I. These instance+ declarations are the candidates.++ * Find all non-candidate instances that unify with the target+ constraint. Such non-candidates instances might match when the+ target constraint is further instantiated. If all of them are+ incoherent, proceed; if not, the search fails.++ * Eliminate any candidate IX for which both of the following hold:+ * There is another candidate IY that is strictly more specific;+ that is, IY is a substitution instance of IX but not vice versa.++ * Either IX is overlappable or IY is overlapping.++ * If only one candidate remains, pick it. Otherwise if all remaining+ candidates are incoherent, pick an arbitrary candidate. Otherwise fail.++Note [Overlapping instances] (NB: these notes are quite old)+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Overlap is permitted, but only in such a way that one can make+a unique choice when looking up. That is, overlap is only permitted if+one template matches the other, or vice versa. So this is ok:++ [a] [Int]++but this is not++ (Int,a) (b,Int)++If overlap is permitted, the list is kept most specific first, so that+the first lookup is the right choice.+++For now we just use association lists.++\subsection{Avoiding a problem with overlapping}++Consider this little program:++\begin{pseudocode}+ class C a where c :: a+ class C a => D a where d :: a++ instance C Int where c = 17+ instance D Int where d = 13++ instance C a => C [a] where c = [c]+ instance ({- C [a], -} D a) => D [a] where d = c++ instance C [Int] where c = [37]++ main = print (d :: [Int])+\end{pseudocode}++What do you think `main' prints (assuming we have overlapping instances, and+all that turned on)? Well, the instance for `D' at type `[a]' is defined to+be `c' at the same type, and we've got an instance of `C' at `[Int]', so the+answer is `[37]', right? (the generic `C [a]' instance shouldn't apply because+the `C [Int]' instance is more specific).++Ghc-4.04 gives `[37]', while ghc-4.06 gives `[17]', so 4.06 is wrong. That+was easy ;-) Let's just consult hugs for good measure. Wait - if I use old+hugs (pre-September99), I get `[17]', and stranger yet, if I use hugs98, it+doesn't even compile! What's going on!?++What hugs complains about is the `D [a]' instance decl.++\begin{pseudocode}+ ERROR "mj.hs" (line 10): Cannot build superclass instance+ *** Instance : D [a]+ *** Context supplied : D a+ *** Required superclass : C [a]+\end{pseudocode}++You might wonder what hugs is complaining about. It's saying that you+need to add `C [a]' to the context of the `D [a]' instance (as appears+in comments). But there's that `C [a]' instance decl one line above+that says that I can reduce the need for a `C [a]' instance to the+need for a `C a' instance, and in this case, I already have the+necessary `C a' instance (since we have `D a' explicitly in the+context, and `C' is a superclass of `D').++Unfortunately, the above reasoning indicates a premature commitment to the+generic `C [a]' instance. I.e., it prematurely rules out the more specific+instance `C [Int]'. This is the mistake that ghc-4.06 makes. The fix is to+add the context that hugs suggests (uncomment the `C [a]'), effectively+deferring the decision about which instance to use.++Now, interestingly enough, 4.04 has this same bug, but it's covered up+in this case by a little known `optimization' that was disabled in+4.06. Ghc-4.04 silently inserts any missing superclass context into+an instance declaration. In this case, it silently inserts the `C+[a]', and everything happens to work out.++(See `basicTypes/MkId:mkDictFunId' for the code in question. Search for+`Mark Jones', although Mark claims no credit for the `optimization' in+question, and would rather it stopped being called the `Mark Jones+optimization' ;-)++So, what's the fix? I think hugs has it right. Here's why. Let's try+something else out with ghc-4.04. Let's add the following line:++ d' :: D a => [a]+ d' = c++Everyone raise their hand who thinks that `d :: [Int]' should give a+different answer from `d' :: [Int]'. Well, in ghc-4.04, it does. The+`optimization' only applies to instance decls, not to regular+bindings, giving inconsistent behavior.++Old hugs had this same bug. Here's how we fixed it: like GHC, the+list of instances for a given class is ordered, so that more specific+instances come before more generic ones. For example, the instance+list for C might contain:+ ..., C Int, ..., C a, ...+When we go to look for a `C Int' instance we'll get that one first.+But what if we go looking for a `C b' (`b' is unconstrained)? We'll+pass the `C Int' instance, and keep going. But if `b' is+unconstrained, then we don't know yet if the more specific instance+will eventually apply. GHC keeps going, and matches on the generic `C+a'. The fix is to, at each step, check to see if there's a reverse+match, and if so, abort the search. This prevents hugs from+prematurely chosing a generic instance when a more specific one+exists.++--Jeff+v+BUT NOTE [Nov 2001]: we must actually *unify* not reverse-match in+this test. Suppose the instance envt had+ ..., forall a b. C a a b, ..., forall a b c. C a b c, ...+(still most specific first)+Now suppose we are looking for (C x y Int), where x and y are unconstrained.+ C x y Int doesn't match the template {a,b} C a a b+but neither does+ C a a b match the template {x,y} C x y Int+But still x and y might subsequently be unified so they *do* match.++Simple story: unify, don't match.+-}++type DFunInstType = Maybe Type+ -- Just ty => Instantiate with this type+ -- Nothing => Instantiate with any type of this tyvar's kind+ -- See Note [DFunInstType: instantiating types]++type InstMatch = (ClsInst, [DFunInstType])++type ClsInstLookupResult+ = ( [InstMatch] -- Successful matches+ , [ClsInst] -- These don't match but do unify+ , [InstMatch] ) -- Unsafe overlapped instances under Safe Haskell+ -- (see Note [Safe Haskell Overlapping Instances] in+ -- TcSimplify).++{-+Note [DFunInstType: instantiating types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A successful match is a ClsInst, together with the types at which+ the dfun_id in the ClsInst should be instantiated+The instantiating types are (Either TyVar Type)s because the dfun+might have some tyvars that *only* appear in arguments+ dfun :: forall a b. C a b, Ord b => D [a]+When we match this against D [ty], we return the instantiating types+ [Just ty, Nothing]+where the 'Nothing' indicates that 'b' can be freely instantiated.+(The caller instantiates it to a flexi type variable, which will+ presumably later become fixed via functional dependencies.)+-}++-- |Look up an instance in the given instance environment. The given class application must match exactly+-- one instance and the match may not contain any flexi type variables. If the lookup is unsuccessful,+-- yield 'Left errorMessage'.+lookupUniqueInstEnv :: InstEnvs+ -> Class -> [Type]+ -> Either MsgDoc (ClsInst, [Type])+lookupUniqueInstEnv instEnv cls tys+ = case lookupInstEnv False instEnv cls tys of+ ([(inst, inst_tys)], _, _)+ | noFlexiVar -> Right (inst, inst_tys')+ | otherwise -> Left $ text "flexible type variable:" <+>+ (ppr $ mkTyConApp (classTyCon cls) tys)+ where+ inst_tys' = [ty | Just ty <- inst_tys]+ noFlexiVar = all isJust inst_tys+ _other -> Left $ text "instance not found" <+>+ (ppr $ mkTyConApp (classTyCon cls) tys)++lookupInstEnv' :: InstEnv -- InstEnv to look in+ -> VisibleOrphanModules -- But filter against this+ -> Class -> [Type] -- What we are looking for+ -> ([InstMatch], -- Successful matches+ [ClsInst]) -- These don't match but do unify+-- The second component of the result pair happens when we look up+-- Foo [a]+-- in an InstEnv that has entries for+-- Foo [Int]+-- Foo [b]+-- Then which we choose would depend on the way in which 'a'+-- is instantiated. So we report that Foo [b] is a match (mapping b->a)+-- but Foo [Int] is a unifier. This gives the caller a better chance of+-- giving a suitable error message++lookupInstEnv' ie vis_mods cls tys+ = lookup ie+ where+ rough_tcs = roughMatchTcs tys+ all_tvs = all isNothing rough_tcs++ --------------+ lookup env = case lookupUDFM env cls of+ Nothing -> ([],[]) -- No instances for this class+ Just (ClsIE insts) -> find [] [] insts++ --------------+ find ms us [] = (ms, us)+ find ms us (item@(ClsInst { is_tcs = mb_tcs, is_tvs = tpl_tvs+ , is_tys = tpl_tys }) : rest)+ | not (instIsVisible vis_mods item)+ = find ms us rest -- See Note [Instance lookup and orphan instances]++ -- Fast check for no match, uses the "rough match" fields+ | instanceCantMatch rough_tcs mb_tcs+ = find ms us rest++ | Just subst <- tcMatchTys tpl_tys tys+ = find ((item, map (lookupTyVar subst) tpl_tvs) : ms) us rest++ -- Does not match, so next check whether the things unify+ -- See Note [Overlapping instances] and Note [Incoherent instances]+ | isIncoherent item+ = find ms us rest++ | otherwise+ = ASSERT2( tyCoVarsOfTypes tys `disjointVarSet` tpl_tv_set,+ (ppr cls <+> ppr tys <+> ppr all_tvs) $$+ (ppr tpl_tvs <+> ppr tpl_tys)+ )+ -- Unification will break badly if the variables overlap+ -- They shouldn't because we allocate separate uniques for them+ -- See Note [Template tyvars are fresh]+ case tcUnifyTys instanceBindFun tpl_tys tys of+ Just _ -> find ms (item:us) rest+ Nothing -> find ms us rest+ where+ tpl_tv_set = mkVarSet tpl_tvs++---------------+-- This is the common way to call this function.+lookupInstEnv :: Bool -- Check Safe Haskell overlap restrictions+ -> InstEnvs -- External and home package inst-env+ -> Class -> [Type] -- What we are looking for+ -> ClsInstLookupResult+-- ^ See Note [Rules for instance lookup]+-- ^ See Note [Safe Haskell Overlapping Instances] in TcSimplify+-- ^ See Note [Safe Haskell Overlapping Instances Implementation] in TcSimplify+lookupInstEnv check_overlap_safe+ (InstEnvs { ie_global = pkg_ie+ , ie_local = home_ie+ , ie_visible = vis_mods })+ cls+ tys+ = -- pprTrace "lookupInstEnv" (ppr cls <+> ppr tys $$ ppr home_ie) $+ (final_matches, final_unifs, unsafe_overlapped)+ where+ (home_matches, home_unifs) = lookupInstEnv' home_ie vis_mods cls tys+ (pkg_matches, pkg_unifs) = lookupInstEnv' pkg_ie vis_mods cls tys+ all_matches = home_matches ++ pkg_matches+ all_unifs = home_unifs ++ pkg_unifs+ final_matches = foldr insert_overlapping [] all_matches+ -- Even if the unifs is non-empty (an error situation)+ -- we still prune the matches, so that the error message isn't+ -- misleading (complaining of multiple matches when some should be+ -- overlapped away)++ unsafe_overlapped+ = case final_matches of+ [match] -> check_safe match+ _ -> []++ -- If the selected match is incoherent, discard all unifiers+ final_unifs = case final_matches of+ (m:_) | isIncoherent (fst m) -> []+ _ -> all_unifs++ -- NOTE [Safe Haskell isSafeOverlap]+ -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ -- We restrict code compiled in 'Safe' mode from overriding code+ -- compiled in any other mode. The rationale is that code compiled+ -- in 'Safe' mode is code that is untrusted by the ghc user. So+ -- we shouldn't let that code change the behaviour of code the+ -- user didn't compile in 'Safe' mode since that's the code they+ -- trust. So 'Safe' instances can only overlap instances from the+ -- same module. A same instance origin policy for safe compiled+ -- instances.+ check_safe (inst,_)+ = case check_overlap_safe && unsafeTopInstance inst of+ -- make sure it only overlaps instances from the same module+ True -> go [] all_matches+ -- most specific is from a trusted location.+ False -> []+ where+ go bad [] = bad+ go bad (i@(x,_):unchecked) =+ if inSameMod x || isOverlappable x+ then go bad unchecked+ else go (i:bad) unchecked++ inSameMod b =+ let na = getName $ getName inst+ la = isInternalName na+ nb = getName $ getName b+ lb = isInternalName nb+ in (la && lb) || (nameModule na == nameModule nb)++ -- We consider the most specific instance unsafe when it both:+ -- (1) Comes from a module compiled as `Safe`+ -- (2) Is an orphan instance, OR, an instance for a MPTC+ unsafeTopInstance inst = isSafeOverlap (is_flag inst) &&+ (isOrphan (is_orphan inst) || classArity (is_cls inst) > 1)++---------------+insert_overlapping :: InstMatch -> [InstMatch] -> [InstMatch]+-- ^ Add a new solution, knocking out strictly less specific ones+-- See Note [Rules for instance lookup]+insert_overlapping new_item [] = [new_item]+insert_overlapping new_item@(new_inst,_) (old_item@(old_inst,_) : old_items)+ | new_beats_old -- New strictly overrides old+ , not old_beats_new+ , new_inst `can_override` old_inst+ = insert_overlapping new_item old_items++ | old_beats_new -- Old strictly overrides new+ , not new_beats_old+ , old_inst `can_override` new_inst+ = old_item : old_items++ -- Discard incoherent instances; see Note [Incoherent instances]+ | isIncoherent old_inst -- Old is incoherent; discard it+ = insert_overlapping new_item old_items+ | isIncoherent new_inst -- New is incoherent; discard it+ = old_item : old_items++ -- Equal or incomparable, and neither is incoherent; keep both+ | otherwise+ = old_item : insert_overlapping new_item old_items+ where++ new_beats_old = new_inst `more_specific_than` old_inst+ old_beats_new = old_inst `more_specific_than` new_inst++ -- `instB` can be instantiated to match `instA`+ -- or the two are equal+ instA `more_specific_than` instB+ = isJust (tcMatchTys (is_tys instB) (is_tys instA))++ instA `can_override` instB+ = isOverlapping instA || isOverlappable instB+ -- Overlap permitted if either the more specific instance+ -- is marked as overlapping, or the more general one is+ -- marked as overlappable.+ -- Latest change described in: Trac #9242.+ -- Previous change: Trac #3877, Dec 10.++{-+Note [Incoherent instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+For some classes, the choice of a particular instance does not matter, any one+is good. E.g. consider++ class D a b where { opD :: a -> b -> String }+ instance D Int b where ...+ instance D a Int where ...++ g (x::Int) = opD x x -- Wanted: D Int Int++For such classes this should work (without having to add an "instance D Int+Int", and using -XOverlappingInstances, which would then work). This is what+-XIncoherentInstances is for: Telling GHC "I don't care which instance you use;+if you can use one, use it."++Should this logic only work when *all* candidates have the incoherent flag, or+even when all but one have it? The right choice is the latter, which can be+justified by comparing the behaviour with how -XIncoherentInstances worked when+it was only about the unify-check (note [Overlapping instances]):++Example:+ class C a b c where foo :: (a,b,c)+ instance C [a] b Int+ instance [incoherent] [Int] b c+ instance [incoherent] C a Int c+Thanks to the incoherent flags,+ [Wanted] C [a] b Int+works: Only instance one matches, the others just unify, but are marked+incoherent.++So I can write+ (foo :: ([a],b,Int)) :: ([Int], Int, Int).+but if that works then I really want to be able to write+ foo :: ([Int], Int, Int)+as well. Now all three instances from above match. None is more specific than+another, so none is ruled out by the normal overlapping rules. One of them is+not incoherent, but we still want this to compile. Hence the+"all-but-one-logic".++The implementation is in insert_overlapping, where we remove matching+incoherent instances as long as there are others.++++************************************************************************+* *+ Binding decisions+* *+************************************************************************+-}++instanceBindFun :: TyCoVar -> BindFlag+instanceBindFun tv | isOverlappableTyVar tv = Skolem+ | otherwise = BindMe+ -- Note [Binding when looking up instances]++{-+Note [Binding when looking up instances]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When looking up in the instance environment, or family-instance environment,+we are careful about multiple matches, as described above in+Note [Overlapping instances]++The key_tys can contain skolem constants, and we can guarantee that those+are never going to be instantiated to anything, so we should not involve+them in the unification test. Example:+ class Foo a where { op :: a -> Int }+ instance Foo a => Foo [a] -- NB overlap+ instance Foo [Int] -- NB overlap+ data T = forall a. Foo a => MkT a+ f :: T -> Int+ f (MkT x) = op [x,x]+The op [x,x] means we need (Foo [a]). Without the filterVarSet we'd+complain, saying that the choice of instance depended on the instantiation+of 'a'; but of course it isn't *going* to be instantiated.++We do this only for isOverlappableTyVar skolems. For example we reject+ g :: forall a => [a] -> Int+ g x = op x+on the grounds that the correct instance depends on the instantiation of 'a'+-}
+ types/Kind.hs view
@@ -0,0 +1,192 @@+-- (c) The University of Glasgow 2006-2012++{-# LANGUAGE CPP #-}+module Kind (+ -- * Main data type+ Kind, typeKind,++ -- ** Predicates on Kinds+ isLiftedTypeKind, isUnliftedTypeKind,+ isConstraintKind,+ isTYPEApp,+ returnsTyCon, returnsConstraintKind,+ isConstraintKindCon,+ okArrowArgKind, okArrowResultKind,++ classifiesTypeWithValues,+ isStarKind, isStarKindSynonymTyCon,+ tcIsStarKind,+ isKindLevPoly+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} Type ( typeKind, coreView, tcView+ , splitTyConApp_maybe )+import {-# SOURCE #-} DataCon ( DataCon )++import TyCoRep+import TyCon+import PrelNames++import Outputable+import Util++{-+************************************************************************+* *+ Functions over Kinds+* *+************************************************************************++Note [Kind Constraint and kind *]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The kind Constraint is the kind of classes and other type constraints.+The special thing about types of kind Constraint is that+ * They are displayed with double arrow:+ f :: Ord a => a -> a+ * They are implicitly instantiated at call sites; so the type inference+ engine inserts an extra argument of type (Ord a) at every call site+ to f.++However, once type inference is over, there is *no* distinction between+Constraint and *. Indeed we can have coercions between the two. Consider+ class C a where+ op :: a -> a+For this single-method class we may generate a newtype, which in turn+generates an axiom witnessing+ C a ~ (a -> a)+so on the left we have Constraint, and on the right we have *.+See Trac #7451.++Bottom line: although '*' and 'Constraint' are distinct TyCons, with+distinct uniques, they are treated as equal at all times except+during type inference.+-}++isConstraintKind :: Kind -> Bool+isConstraintKindCon :: TyCon -> Bool++isConstraintKindCon tc = tyConUnique tc == constraintKindTyConKey++isConstraintKind (TyConApp tc _) = isConstraintKindCon tc+isConstraintKind _ = False++isTYPEApp :: Kind -> Maybe DataCon+isTYPEApp (TyConApp tc args)+ | tc `hasKey` tYPETyConKey+ , [arg] <- args+ , Just (tc, []) <- splitTyConApp_maybe arg+ , Just dc <- isPromotedDataCon_maybe tc+ = Just dc+isTYPEApp _ = Nothing++-- | Does the given type "end" in the given tycon? For example @k -> [a] -> *@+-- ends in @*@ and @Maybe a -> [a]@ ends in @[]@.+returnsTyCon :: Unique -> Type -> Bool+returnsTyCon tc_u (ForAllTy _ ty) = returnsTyCon tc_u ty+returnsTyCon tc_u (FunTy _ ty) = returnsTyCon tc_u ty+returnsTyCon tc_u (TyConApp tc' _) = tc' `hasKey` tc_u+returnsTyCon _ _ = False++returnsConstraintKind :: Kind -> Bool+returnsConstraintKind = returnsTyCon constraintKindTyConKey++-- | Tests whether the given kind (which should look like @TYPE x@)+-- is something other than a constructor tree (that is, constructors at every node).+isKindLevPoly :: Kind -> Bool+isKindLevPoly k = ASSERT2( isStarKind k || _is_type, ppr k )+ -- the isStarKind check is necessary b/c of Constraint+ go k+ where+ go ty | Just ty' <- coreView ty = go ty'+ go TyVarTy{} = True+ go AppTy{} = True -- it can't be a TyConApp+ go (TyConApp tc tys) = isFamilyTyCon tc || any go tys+ go ForAllTy{} = True+ go (FunTy t1 t2) = go t1 || go t2+ go LitTy{} = False+ go CastTy{} = True+ go CoercionTy{} = True++ _is_type+ | TyConApp typ [_] <- k+ = typ `hasKey` tYPETyConKey+ | otherwise+ = False+++--------------------------------------------+-- Kinding for arrow (->)+-- Says when a kind is acceptable on lhs or rhs of an arrow+-- arg -> res+--+-- See Note [Levity polymorphism]++okArrowArgKind, okArrowResultKind :: Kind -> Bool+okArrowArgKind = classifiesTypeWithValues+okArrowResultKind = classifiesTypeWithValues++-----------------------------------------+-- Subkinding+-- The tc variants are used during type-checking, where ConstraintKind+-- is distinct from all other kinds+-- After type-checking (in core), Constraint and liftedTypeKind are+-- indistinguishable++-- | Does this classify a type allowed to have values? Responds True to things+-- like *, #, TYPE Lifted, TYPE v, Constraint.+classifiesTypeWithValues :: Kind -> Bool+-- ^ True of any sub-kind of OpenTypeKind+classifiesTypeWithValues t | Just t' <- coreView t = classifiesTypeWithValues t'+classifiesTypeWithValues (TyConApp tc [_]) = tc `hasKey` tYPETyConKey+classifiesTypeWithValues _ = False++-- | Is this kind equivalent to *?+tcIsStarKind :: Kind -> Bool+tcIsStarKind k | Just k' <- tcView k = isStarKind k'+tcIsStarKind (TyConApp tc [TyConApp ptr_rep []])+ = tc `hasKey` tYPETyConKey+ && ptr_rep `hasKey` liftedRepDataConKey+tcIsStarKind _ = False++-- | Is this kind equivalent to *?+isStarKind :: Kind -> Bool+isStarKind k | Just k' <- coreView k = isStarKind k'+isStarKind (TyConApp tc [TyConApp ptr_rep []])+ = tc `hasKey` tYPETyConKey+ && ptr_rep `hasKey` liftedRepDataConKey+isStarKind _ = False+ -- See Note [Kind Constraint and kind *]++-- | Is the tycon @Constraint@?+isStarKindSynonymTyCon :: TyCon -> Bool+isStarKindSynonymTyCon tc = tc `hasKey` constraintKindTyConKey+++{- Note [Levity polymorphism]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Is this type legal?+ (a :: TYPE rep) -> Int+ where 'rep :: RuntimeRep'++You might think not, because no lambda can have a+runtime-rep-polymorphic binder. So no lambda has the+above type. BUT here's a way it can be useful (taken from+Trac #12708):++ data T rep (a :: TYPE rep)+ = MkT (a -> Int)++ x1 :: T LiftedRep Int+ x1 = MkT LiftedRep Int (\x::Int -> 3)++ x2 :: T IntRep Int#+ x2 = MkT IntRep Int# (\x:Int# -> 3)++Note that the lambdas are just fine!++Hence, okArrowArgKind and okArrowResultKind both just+check that the type is of the form (TYPE r) for some+representation type r.+-}
+ types/OptCoercion.hs view
@@ -0,0 +1,968 @@+-- (c) The University of Glasgow 2006++{-# LANGUAGE CPP #-}++-- The default iteration limit is a bit too low for the definitions+-- in this module.+#if __GLASGOW_HASKELL__ >= 800+{-# OPTIONS_GHC -fmax-pmcheck-iterations=10000000 #-}+#endif++module OptCoercion ( optCoercion, checkAxInstCo ) where++#include "HsVersions.h"++import DynFlags+import TyCoRep+import Coercion+import Type hiding( substTyVarBndr, substTy )+import TcType ( exactTyCoVarsOfType )+import TyCon+import CoAxiom+import VarSet+import VarEnv+import Outputable+import FamInstEnv ( flattenTys )+import Pair+import ListSetOps ( getNth )+import Util+import Unify+import InstEnv+import Control.Monad ( zipWithM )++{-+%************************************************************************+%* *+ Optimising coercions+%* *+%************************************************************************++Note [Optimising coercion optimisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Looking up a coercion's role or kind is linear in the size of the+coercion. Thus, doing this repeatedly during the recursive descent+of coercion optimisation is disastrous. We must be careful to avoid+doing this if at all possible.++Because it is generally easy to know a coercion's components' roles+from the role of the outer coercion, we pass down the known role of+the input in the algorithm below. We also keep functions opt_co2+and opt_co3 separate from opt_co4, so that the former two do Phantom+checks that opt_co4 can avoid. This is a big win because Phantom coercions+rarely appear within non-phantom coercions -- only in some TyConAppCos+and some AxiomInstCos. We handle these cases specially by calling+opt_co2.++Note [Optimising InstCo]+~~~~~~~~~~~~~~~~~~~~~~~~+When we have (InstCo (ForAllCo tv h g) g2), we want to optimise.++Let's look at the typing rules.++h : k1 ~ k2+tv:k1 |- g : t1 ~ t2+-----------------------------+ForAllCo tv h g : (all tv:k1.t1) ~ (all tv:k2.t2[tv |-> tv |> sym h])++g1 : (all tv:k1.t1') ~ (all tv:k2.t2')+g2 : s1 ~ s2+--------------------+InstCo g1 g2 : t1'[tv |-> s1] ~ t2'[tv |-> s2]++We thus want some coercion proving this:++ (t1[tv |-> s1]) ~ (t2[tv |-> s2 |> sym h])++If we substitute the *type* tv for the *coercion*+(g2 `mkCoherenceRightCo` sym h) in g, we'll get this result exactly.+This is bizarre,+though, because we're substituting a type variable with a coercion. However,+this operation already exists: it's called *lifting*, and defined in Coercion.+We just need to enhance the lifting operation to be able to deal with+an ambient substitution, which is why a LiftingContext stores a TCvSubst.++-}++optCoercion :: TCvSubst -> Coercion -> NormalCo+-- ^ optCoercion applies a substitution to a coercion,+-- *and* optimises it to reduce its size+optCoercion env co+ | hasNoOptCoercion unsafeGlobalDynFlags = substCo env co+ | debugIsOn+ = let out_co = opt_co1 lc False co+ (Pair in_ty1 in_ty2, in_role) = coercionKindRole co+ (Pair out_ty1 out_ty2, out_role) = coercionKindRole out_co+ in+ ASSERT2( substTyUnchecked env in_ty1 `eqType` out_ty1 &&+ substTyUnchecked env in_ty2 `eqType` out_ty2 &&+ in_role == out_role+ , text "optCoercion changed types!"+ $$ hang (text "in_co:") 2 (ppr co)+ $$ hang (text "in_ty1:") 2 (ppr in_ty1)+ $$ hang (text "in_ty2:") 2 (ppr in_ty2)+ $$ hang (text "out_co:") 2 (ppr out_co)+ $$ hang (text "out_ty1:") 2 (ppr out_ty1)+ $$ hang (text "out_ty2:") 2 (ppr out_ty2)+ $$ hang (text "subst:") 2 (ppr env) )+ out_co++ | otherwise = opt_co1 lc False co+ where+ lc = mkSubstLiftingContext env++type NormalCo = Coercion+ -- Invariants:+ -- * The substitution has been fully applied+ -- * For trans coercions (co1 `trans` co2)+ -- co1 is not a trans, and neither co1 nor co2 is identity++type NormalNonIdCo = NormalCo -- Extra invariant: not the identity++-- | Do we apply a @sym@ to the result?+type SymFlag = Bool++-- | Do we force the result to be representational?+type ReprFlag = Bool++-- | Optimize a coercion, making no assumptions. All coercions in+-- the lifting context are already optimized (and sym'd if nec'y)+opt_co1 :: LiftingContext+ -> SymFlag+ -> Coercion -> NormalCo+opt_co1 env sym co = opt_co2 env sym (coercionRole co) co++-- See Note [Optimising coercion optimisation]+-- | Optimize a coercion, knowing the coercion's role. No other assumptions.+opt_co2 :: LiftingContext+ -> SymFlag+ -> Role -- ^ The role of the input coercion+ -> Coercion -> NormalCo+opt_co2 env sym Phantom co = opt_phantom env sym co+opt_co2 env sym r co = opt_co3 env sym Nothing r co++-- See Note [Optimising coercion optimisation]+-- | Optimize a coercion, knowing the coercion's non-Phantom role.+opt_co3 :: LiftingContext -> SymFlag -> Maybe Role -> Role -> Coercion -> NormalCo+opt_co3 env sym (Just Phantom) _ co = opt_phantom env sym co+opt_co3 env sym (Just Representational) r co = opt_co4_wrap env sym True r co+ -- if mrole is Just Nominal, that can't be a downgrade, so we can ignore+opt_co3 env sym _ r co = opt_co4_wrap env sym False r co++-- See Note [Optimising coercion optimisation]+-- | Optimize a non-phantom coercion.+opt_co4, opt_co4_wrap :: LiftingContext -> SymFlag -> ReprFlag -> Role -> Coercion -> NormalCo++opt_co4_wrap = opt_co4+{-+opt_co4_wrap env sym rep r co+ = pprTrace "opt_co4_wrap {"+ ( vcat [ text "Sym:" <+> ppr sym+ , text "Rep:" <+> ppr rep+ , text "Role:" <+> ppr r+ , text "Co:" <+> ppr co ]) $+ ASSERT( r == coercionRole co )+ let result = opt_co4 env sym rep r co in+ pprTrace "opt_co4_wrap }" (ppr co $$ text "---" $$ ppr result) $+ result+-}++opt_co4 env _ rep r (Refl _r ty)+ = ASSERT2( r == _r, text "Expected role:" <+> ppr r $$+ text "Found role:" <+> ppr _r $$+ text "Type:" <+> ppr ty )+ liftCoSubst (chooseRole rep r) env ty++opt_co4 env sym rep r (SymCo co) = opt_co4_wrap env (not sym) rep r co+ -- surprisingly, we don't have to do anything to the env here. This is+ -- because any "lifting" substitutions in the env are tied to ForAllCos,+ -- which treat their left and right sides differently. We don't want to+ -- exchange them.++opt_co4 env sym rep r g@(TyConAppCo _r tc cos)+ = ASSERT( r == _r )+ case (rep, r) of+ (True, Nominal) ->+ mkTyConAppCo Representational tc+ (zipWith3 (opt_co3 env sym)+ (map Just (tyConRolesRepresentational tc))+ (repeat Nominal)+ cos)+ (False, Nominal) ->+ mkTyConAppCo Nominal tc (map (opt_co4_wrap env sym False Nominal) cos)+ (_, Representational) ->+ -- must use opt_co2 here, because some roles may be P+ -- See Note [Optimising coercion optimisation]+ mkTyConAppCo r tc (zipWith (opt_co2 env sym)+ (tyConRolesRepresentational tc) -- the current roles+ cos)+ (_, Phantom) -> pprPanic "opt_co4 sees a phantom!" (ppr g)++opt_co4 env sym rep r (AppCo co1 co2)+ = mkAppCo (opt_co4_wrap env sym rep r co1)+ (opt_co4_wrap env sym False Nominal co2)++opt_co4 env sym rep r (ForAllCo tv k_co co)+ = case optForAllCoBndr env sym tv k_co of+ (env', tv', k_co') -> mkForAllCo tv' k_co' $+ opt_co4_wrap env' sym rep r co+ -- Use the "mk" functions to check for nested Refls++opt_co4 env sym rep r (FunCo _r co1 co2)+ = ASSERT( r == _r )+ if rep+ then mkFunCo Representational co1' co2'+ else mkFunCo r co1' co2'+ where+ co1' = opt_co4_wrap env sym rep r co1+ co2' = opt_co4_wrap env sym rep r co2++opt_co4 env sym rep r (CoVarCo cv)+ | Just co <- lookupCoVar (lcTCvSubst env) cv+ = opt_co4_wrap (zapLiftingContext env) sym rep r co++ | ty1 `eqType` ty2 -- See Note [Optimise CoVarCo to Refl]+ = Refl (chooseRole rep r) ty1++ | otherwise+ = ASSERT( isCoVar cv1 )+ wrapRole rep r $ wrapSym sym $+ CoVarCo cv1++ where+ Pair ty1 ty2 = coVarTypes cv1++ cv1 = case lookupInScope (lcInScopeSet env) cv of+ Just cv1 -> cv1+ Nothing -> WARN( True, text "opt_co: not in scope:"+ <+> ppr cv $$ ppr env)+ cv+ -- cv1 might have a substituted kind!+++opt_co4 env sym rep r (AxiomInstCo con ind cos)+ -- Do *not* push sym inside top-level axioms+ -- e.g. if g is a top-level axiom+ -- g a : f a ~ a+ -- then (sym (g ty)) /= g (sym ty) !!+ = ASSERT( r == coAxiomRole con )+ wrapRole rep (coAxiomRole con) $+ wrapSym sym $+ -- some sub-cos might be P: use opt_co2+ -- See Note [Optimising coercion optimisation]+ AxiomInstCo con ind (zipWith (opt_co2 env False)+ (coAxBranchRoles (coAxiomNthBranch con ind))+ cos)+ -- Note that the_co does *not* have sym pushed into it++opt_co4 env sym rep r (UnivCo prov _r t1 t2)+ = ASSERT( r == _r )+ opt_univ env sym prov (chooseRole rep r) t1 t2++opt_co4 env sym rep r (TransCo co1 co2)+ -- sym (g `o` h) = sym h `o` sym g+ | sym = opt_trans in_scope co2' co1'+ | otherwise = opt_trans in_scope co1' co2'+ where+ co1' = opt_co4_wrap env sym rep r co1+ co2' = opt_co4_wrap env sym rep r co2+ in_scope = lcInScopeSet env+++opt_co4 env sym rep r co@(NthCo {}) = opt_nth_co env sym rep r co++opt_co4 env sym rep r (LRCo lr co)+ | Just pr_co <- splitAppCo_maybe co+ = ASSERT( r == Nominal )+ opt_co4_wrap env sym rep Nominal (pick_lr lr pr_co)+ | Just pr_co <- splitAppCo_maybe co'+ = ASSERT( r == Nominal )+ if rep+ then opt_co4_wrap (zapLiftingContext env) False True Nominal (pick_lr lr pr_co)+ else pick_lr lr pr_co+ | otherwise+ = wrapRole rep Nominal $ LRCo lr co'+ where+ co' = opt_co4_wrap env sym False Nominal co++ pick_lr CLeft (l, _) = l+ pick_lr CRight (_, r) = r++-- See Note [Optimising InstCo]+opt_co4 env sym rep r (InstCo co1 arg)+ -- forall over type...+ | Just (tv, kind_co, co_body) <- splitForAllCo_maybe co1+ = opt_co4_wrap (extendLiftingContext env tv+ (arg' `mkCoherenceRightCo` mkSymCo kind_co))+ sym rep r co_body++ -- See if it is a forall after optimization+ -- If so, do an inefficient one-variable substitution, then re-optimize++ -- forall over type...+ | Just (tv', kind_co', co_body') <- splitForAllCo_maybe co1'+ = opt_co4_wrap (extendLiftingContext (zapLiftingContext env) tv'+ (arg' `mkCoherenceRightCo` mkSymCo kind_co'))+ False False r' co_body'++ | otherwise = InstCo co1' arg'+ where+ co1' = opt_co4_wrap env sym rep r co1+ r' = chooseRole rep r+ arg' = opt_co4_wrap env sym False Nominal arg++opt_co4 env sym rep r (CoherenceCo co1 co2)+ | TransCo col1 cor1 <- co1+ = opt_co4_wrap env sym rep r (mkTransCo (mkCoherenceCo col1 co2) cor1)++ | TransCo col1' cor1' <- co1'+ = if sym then opt_trans in_scope col1'+ (optCoercion (zapTCvSubst (lcTCvSubst env))+ (mkCoherenceRightCo cor1' co2'))+ else opt_trans in_scope (mkCoherenceCo col1' co2') cor1'++ | otherwise+ = wrapSym sym $ mkCoherenceCo (opt_co4_wrap env False rep r co1) co2'+ where co1' = opt_co4_wrap env sym rep r co1+ co2' = opt_co4_wrap env False False Nominal co2+ in_scope = lcInScopeSet env++opt_co4 env sym _rep r (KindCo co)+ = ASSERT( r == Nominal )+ let kco' = promoteCoercion co in+ case kco' of+ KindCo co' -> promoteCoercion (opt_co1 env sym co')+ _ -> opt_co4_wrap env sym False Nominal kco'+ -- This might be able to be optimized more to do the promotion+ -- and substitution/optimization at the same time++opt_co4 env sym _ r (SubCo co)+ = ASSERT( r == Representational )+ opt_co4_wrap env sym True Nominal co++-- This could perhaps be optimized more.+opt_co4 env sym rep r (AxiomRuleCo co cs)+ = ASSERT( r == coaxrRole co )+ wrapRole rep r $+ wrapSym sym $+ AxiomRuleCo co (zipWith (opt_co2 env False) (coaxrAsmpRoles co) cs)++{- Note [Optimise CoVarCo to Refl]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we have (c :: t~t) we can optimise it to Refl. That increases the+chances of floating the Refl upwards; e.g. Maybe c --> Refl (Maybe t)++We do so here in optCoercion, not in mkCoVarCo; see Note [mkCoVarCo]+in Coercion.+-}++-------------+-- | Optimize a phantom coercion. The input coercion may not necessarily+-- be a phantom, but the output sure will be.+opt_phantom :: LiftingContext -> SymFlag -> Coercion -> NormalCo+opt_phantom env sym co+ = opt_univ env sym (PhantomProv (mkKindCo co)) Phantom ty1 ty2+ where+ Pair ty1 ty2 = coercionKind co++{- Note [Differing kinds]+ ~~~~~~~~~~~~~~~~~~~~~~+The two types may not have the same kind (although that would be very unusual).+But even if they have the same kind, and the same type constructor, the number+of arguments in a `CoTyConApp` can differ. Consider++ Any :: forall k. k++ Any * Int :: *+ Any (*->*) Maybe Int :: *++Hence the need to compare argument lengths; see Trac #13658+ -}++opt_univ :: LiftingContext -> SymFlag -> UnivCoProvenance -> Role+ -> Type -> Type -> Coercion+opt_univ env sym (PhantomProv h) _r ty1 ty2+ | sym = mkPhantomCo h' ty2' ty1'+ | otherwise = mkPhantomCo h' ty1' ty2'+ where+ h' = opt_co4 env sym False Nominal h+ ty1' = substTy (lcSubstLeft env) ty1+ ty2' = substTy (lcSubstRight env) ty2++opt_univ env sym prov role oty1 oty2+ | Just (tc1, tys1) <- splitTyConApp_maybe oty1+ , Just (tc2, tys2) <- splitTyConApp_maybe oty2+ , tc1 == tc2+ , equalLength tys1 tys2 -- see Note [Differing kinds]+ -- NB: prov must not be the two interesting ones (ProofIrrel & Phantom);+ -- Phantom is already taken care of, and ProofIrrel doesn't relate tyconapps+ = let roles = tyConRolesX role tc1+ arg_cos = zipWith3 (mkUnivCo prov) roles tys1 tys2+ arg_cos' = zipWith (opt_co4 env sym False) roles arg_cos+ in+ mkTyConAppCo role tc1 arg_cos'++ -- can't optimize the AppTy case because we can't build the kind coercions.++ | Just (tv1, ty1) <- splitForAllTy_maybe oty1+ , Just (tv2, ty2) <- splitForAllTy_maybe oty2+ -- NB: prov isn't interesting here either+ = let k1 = tyVarKind tv1+ k2 = tyVarKind tv2+ eta = mkUnivCo prov Nominal k1 k2+ -- eta gets opt'ed soon, but not yet.+ ty2' = substTyWith [tv2] [TyVarTy tv1 `mkCastTy` eta] ty2++ (env', tv1', eta') = optForAllCoBndr env sym tv1 eta+ in+ mkForAllCo tv1' eta' (opt_univ env' sym prov role ty1 ty2')++ | otherwise+ = let ty1 = substTyUnchecked (lcSubstLeft env) oty1+ ty2 = substTyUnchecked (lcSubstRight env) oty2+ (a, b) | sym = (ty2, ty1)+ | otherwise = (ty1, ty2)+ in+ mkUnivCo prov' role a b++ where+ prov' = case prov of+ UnsafeCoerceProv -> prov+ PhantomProv kco -> PhantomProv $ opt_co4_wrap env sym False Nominal kco+ ProofIrrelProv kco -> ProofIrrelProv $ opt_co4_wrap env sym False Nominal kco+ PluginProv _ -> prov+ HoleProv h -> pprPanic "opt_univ fell into a hole" (ppr h)+++-------------+-- NthCo must be handled separately, because it's the one case where we can't+-- tell quickly what the component coercion's role is from the containing+-- coercion. To avoid repeated coercionRole calls as opt_co1 calls opt_co2,+-- we just look for nested NthCo's, which can happen in practice.+opt_nth_co :: LiftingContext -> SymFlag -> ReprFlag -> Role -> Coercion -> NormalCo+opt_nth_co env sym rep r = go []+ where+ go ns (NthCo n co) = go (n:ns) co+ -- previous versions checked if the tycon is decomposable. This+ -- is redundant, because a non-decomposable tycon under an NthCo+ -- is entirely bogus. See docs/core-spec/core-spec.pdf.+ go ns co+ = opt_nths ns co++ -- try to resolve 1 Nth+ push_nth n (Refl r1 ty)+ | Just (tc, args) <- splitTyConApp_maybe ty+ = Just (Refl (nthRole r1 tc n) (args `getNth` n))+ | n == 0+ , Just (tv, _) <- splitForAllTy_maybe ty+ = Just (Refl Nominal (tyVarKind tv))+ push_nth n (TyConAppCo _ _ cos)+ = Just (cos `getNth` n)+ push_nth 0 (ForAllCo _ eta _)+ = Just eta+ push_nth _ _ = Nothing++ -- input coercion is *not* yet sym'd or opt'd+ opt_nths [] co = opt_co4_wrap env sym rep r co+ opt_nths (n:ns) co+ | Just co' <- push_nth n co+ = opt_nths ns co'++ -- here, the co isn't a TyConAppCo, so we opt it, hoping to get+ -- a TyConAppCo as output. We don't know the role, so we use+ -- opt_co1. This is slightly annoying, because opt_co1 will call+ -- coercionRole, but as long as we don't have a long chain of+ -- NthCo's interspersed with some other coercion former, we should+ -- be OK.+ opt_nths ns co = opt_nths' ns (opt_co1 env sym co)++ -- input coercion *is* sym'd and opt'd+ opt_nths' [] co+ = if rep && (r == Nominal)+ -- propagate the SubCo:+ then opt_co4_wrap (zapLiftingContext env) False True r co+ else co+ opt_nths' (n:ns) co+ | Just co' <- push_nth n co+ = opt_nths' ns co'+ opt_nths' ns co = wrapRole rep r (mk_nths ns co)++ mk_nths [] co = co+ mk_nths (n:ns) co = mk_nths ns (mkNthCo n co)++-------------+opt_transList :: InScopeSet -> [NormalCo] -> [NormalCo] -> [NormalCo]+opt_transList is = zipWith (opt_trans is)++opt_trans :: InScopeSet -> NormalCo -> NormalCo -> NormalCo+opt_trans is co1 co2+ | isReflCo co1 = co2+ | otherwise = opt_trans1 is co1 co2++opt_trans1 :: InScopeSet -> NormalNonIdCo -> NormalCo -> NormalCo+-- First arg is not the identity+opt_trans1 is co1 co2+ | isReflCo co2 = co1+ | otherwise = opt_trans2 is co1 co2++opt_trans2 :: InScopeSet -> NormalNonIdCo -> NormalNonIdCo -> NormalCo+-- Neither arg is the identity+opt_trans2 is (TransCo co1a co1b) co2+ -- Don't know whether the sub-coercions are the identity+ = opt_trans is co1a (opt_trans is co1b co2)++opt_trans2 is co1 co2+ | Just co <- opt_trans_rule is co1 co2+ = co++opt_trans2 is co1 (TransCo co2a co2b)+ | Just co1_2a <- opt_trans_rule is co1 co2a+ = if isReflCo co1_2a+ then co2b+ else opt_trans1 is co1_2a co2b++opt_trans2 _ co1 co2+ = mkTransCo co1 co2++------+-- Optimize coercions with a top-level use of transitivity.+opt_trans_rule :: InScopeSet -> NormalNonIdCo -> NormalNonIdCo -> Maybe NormalCo++-- Push transitivity through matching destructors+opt_trans_rule is in_co1@(NthCo d1 co1) in_co2@(NthCo d2 co2)+ | d1 == d2+ , co1 `compatible_co` co2+ = fireTransRule "PushNth" in_co1 in_co2 $+ mkNthCo d1 (opt_trans is co1 co2)++opt_trans_rule is in_co1@(LRCo d1 co1) in_co2@(LRCo d2 co2)+ | d1 == d2+ , co1 `compatible_co` co2+ = fireTransRule "PushLR" in_co1 in_co2 $+ mkLRCo d1 (opt_trans is co1 co2)++-- Push transitivity inside instantiation+opt_trans_rule is in_co1@(InstCo co1 ty1) in_co2@(InstCo co2 ty2)+ | ty1 `eqCoercion` ty2+ , co1 `compatible_co` co2+ = fireTransRule "TrPushInst" in_co1 in_co2 $+ mkInstCo (opt_trans is co1 co2) ty1++opt_trans_rule is in_co1@(UnivCo p1 r1 tyl1 _tyr1)+ in_co2@(UnivCo p2 r2 _tyl2 tyr2)+ | Just prov' <- opt_trans_prov p1 p2+ = ASSERT( r1 == r2 )+ fireTransRule "UnivCo" in_co1 in_co2 $+ mkUnivCo prov' r1 tyl1 tyr2+ where+ -- if the provenances are different, opt'ing will be very confusing+ opt_trans_prov UnsafeCoerceProv UnsafeCoerceProv = Just UnsafeCoerceProv+ opt_trans_prov (PhantomProv kco1) (PhantomProv kco2)+ = Just $ PhantomProv $ opt_trans is kco1 kco2+ opt_trans_prov (ProofIrrelProv kco1) (ProofIrrelProv kco2)+ = Just $ ProofIrrelProv $ opt_trans is kco1 kco2+ opt_trans_prov (PluginProv str1) (PluginProv str2) | str1 == str2 = Just p1+ opt_trans_prov _ _ = Nothing++-- Push transitivity down through matching top-level constructors.+opt_trans_rule is in_co1@(TyConAppCo r1 tc1 cos1) in_co2@(TyConAppCo r2 tc2 cos2)+ | tc1 == tc2+ = ASSERT( r1 == r2 )+ fireTransRule "PushTyConApp" in_co1 in_co2 $+ mkTyConAppCo r1 tc1 (opt_transList is cos1 cos2)++opt_trans_rule is in_co1@(AppCo co1a co1b) in_co2@(AppCo co2a co2b)+ = fireTransRule "TrPushApp" in_co1 in_co2 $+ mkAppCo (opt_trans is co1a co2a)+ (opt_trans is co1b co2b)++-- Eta rules+opt_trans_rule is co1@(TyConAppCo r tc cos1) co2+ | Just cos2 <- etaTyConAppCo_maybe tc co2+ = ASSERT( length cos1 == length cos2 )+ fireTransRule "EtaCompL" co1 co2 $+ mkTyConAppCo r tc (opt_transList is cos1 cos2)++opt_trans_rule is co1 co2@(TyConAppCo r tc cos2)+ | Just cos1 <- etaTyConAppCo_maybe tc co1+ = ASSERT( length cos1 == length cos2 )+ fireTransRule "EtaCompR" co1 co2 $+ mkTyConAppCo r tc (opt_transList is cos1 cos2)++opt_trans_rule is co1@(AppCo co1a co1b) co2+ | Just (co2a,co2b) <- etaAppCo_maybe co2+ = fireTransRule "EtaAppL" co1 co2 $+ mkAppCo (opt_trans is co1a co2a)+ (opt_trans is co1b co2b)++opt_trans_rule is co1 co2@(AppCo co2a co2b)+ | Just (co1a,co1b) <- etaAppCo_maybe co1+ = fireTransRule "EtaAppR" co1 co2 $+ mkAppCo (opt_trans is co1a co2a)+ (opt_trans is co1b co2b)++-- Push transitivity inside forall+opt_trans_rule is co1 co2+ | ForAllCo tv1 eta1 r1 <- co1+ , Just (tv2,eta2,r2) <- etaForAllCo_maybe co2+ = push_trans tv1 eta1 r1 tv2 eta2 r2++ | ForAllCo tv2 eta2 r2 <- co2+ , Just (tv1,eta1,r1) <- etaForAllCo_maybe co1+ = push_trans tv1 eta1 r1 tv2 eta2 r2++ where+ push_trans tv1 eta1 r1 tv2 eta2 r2+ = fireTransRule "EtaAllTy" co1 co2 $+ mkForAllCo tv1 (opt_trans is eta1 eta2) (opt_trans is' r1 r2')+ where+ is' = is `extendInScopeSet` tv1+ r2' = substCoWithUnchecked [tv2] [TyVarTy tv1] r2++-- Push transitivity inside axioms+opt_trans_rule is co1 co2++ -- See Note [Why call checkAxInstCo during optimisation]+ -- TrPushSymAxR+ | Just (sym, con, ind, cos1) <- co1_is_axiom_maybe+ , True <- sym+ , Just cos2 <- matchAxiom sym con ind co2+ , let newAxInst = AxiomInstCo con ind (opt_transList is (map mkSymCo cos2) cos1)+ , Nothing <- checkAxInstCo newAxInst+ = fireTransRule "TrPushSymAxR" co1 co2 $ SymCo newAxInst++ -- TrPushAxR+ | Just (sym, con, ind, cos1) <- co1_is_axiom_maybe+ , False <- sym+ , Just cos2 <- matchAxiom sym con ind co2+ , let newAxInst = AxiomInstCo con ind (opt_transList is cos1 cos2)+ , Nothing <- checkAxInstCo newAxInst+ = fireTransRule "TrPushAxR" co1 co2 newAxInst++ -- TrPushSymAxL+ | Just (sym, con, ind, cos2) <- co2_is_axiom_maybe+ , True <- sym+ , Just cos1 <- matchAxiom (not sym) con ind co1+ , let newAxInst = AxiomInstCo con ind (opt_transList is cos2 (map mkSymCo cos1))+ , Nothing <- checkAxInstCo newAxInst+ = fireTransRule "TrPushSymAxL" co1 co2 $ SymCo newAxInst++ -- TrPushAxL+ | Just (sym, con, ind, cos2) <- co2_is_axiom_maybe+ , False <- sym+ , Just cos1 <- matchAxiom (not sym) con ind co1+ , let newAxInst = AxiomInstCo con ind (opt_transList is cos1 cos2)+ , Nothing <- checkAxInstCo newAxInst+ = fireTransRule "TrPushAxL" co1 co2 newAxInst++ -- TrPushAxSym/TrPushSymAx+ | Just (sym1, con1, ind1, cos1) <- co1_is_axiom_maybe+ , Just (sym2, con2, ind2, cos2) <- co2_is_axiom_maybe+ , con1 == con2+ , ind1 == ind2+ , sym1 == not sym2+ , let branch = coAxiomNthBranch con1 ind1+ qtvs = coAxBranchTyVars branch ++ coAxBranchCoVars branch+ lhs = coAxNthLHS con1 ind1+ rhs = coAxBranchRHS branch+ pivot_tvs = exactTyCoVarsOfType (if sym2 then rhs else lhs)+ , all (`elemVarSet` pivot_tvs) qtvs+ = fireTransRule "TrPushAxSym" co1 co2 $+ if sym2+ -- TrPushAxSym+ then liftCoSubstWith role qtvs (opt_transList is cos1 (map mkSymCo cos2)) lhs+ -- TrPushSymAx+ else liftCoSubstWith role qtvs (opt_transList is (map mkSymCo cos1) cos2) rhs+ where+ co1_is_axiom_maybe = isAxiom_maybe co1+ co2_is_axiom_maybe = isAxiom_maybe co2+ role = coercionRole co1 -- should be the same as coercionRole co2!++opt_trans_rule is co1 co2+ | Just (lco, lh) <- isCohRight_maybe co1+ , Just (rco, rh) <- isCohLeft_maybe co2+ , (coercionType lh) `eqType` (coercionType rh)+ = opt_trans_rule is lco rco++opt_trans_rule _ co1 co2 -- Identity rule+ | (Pair ty1 _, r) <- coercionKindRole co1+ , Pair _ ty2 <- coercionKind co2+ , ty1 `eqType` ty2+ = fireTransRule "RedTypeDirRefl" co1 co2 $+ Refl r ty2++opt_trans_rule _ _ _ = Nothing++fireTransRule :: String -> Coercion -> Coercion -> Coercion -> Maybe Coercion+fireTransRule _rule _co1 _co2 res+ = -- pprTrace ("Trans rule fired: " ++ _rule) (vcat [ppr _co1, ppr _co2, ppr res]) $+ Just res++{-+Note [Conflict checking with AxiomInstCo]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider the following type family and axiom:++type family Equal (a :: k) (b :: k) :: Bool+type instance where+ Equal a a = True+ Equal a b = False+--+Equal :: forall k::*. k -> k -> Bool+axEqual :: { forall k::*. forall a::k. Equal k a a ~ True+ ; forall k::*. forall a::k. forall b::k. Equal k a b ~ False }++We wish to disallow (axEqual[1] <*> <Int> <Int). (Recall that the index is+0-based, so this is the second branch of the axiom.) The problem is that, on+the surface, it seems that (axEqual[1] <*> <Int> <Int>) :: (Equal * Int Int ~+False) and that all is OK. But, all is not OK: we want to use the first branch+of the axiom in this case, not the second. The problem is that the parameters+of the first branch can unify with the supplied coercions, thus meaning that+the first branch should be taken. See also Note [Apartness] in+types/FamInstEnv.hs.++Note [Why call checkAxInstCo during optimisation]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It is possible that otherwise-good-looking optimisations meet with disaster+in the presence of axioms with multiple equations. Consider++type family Equal (a :: *) (b :: *) :: Bool where+ Equal a a = True+ Equal a b = False+type family Id (a :: *) :: * where+ Id a = a++axEq :: { [a::*]. Equal a a ~ True+ ; [a::*, b::*]. Equal a b ~ False }+axId :: [a::*]. Id a ~ a++co1 = Equal (axId[0] Int) (axId[0] Bool)+ :: Equal (Id Int) (Id Bool) ~ Equal Int Bool+co2 = axEq[1] <Int> <Bool>+ :: Equal Int Bool ~ False++We wish to optimise (co1 ; co2). We end up in rule TrPushAxL, noting that+co2 is an axiom and that matchAxiom succeeds when looking at co1. But, what+happens when we push the coercions inside? We get++co3 = axEq[1] (axId[0] Int) (axId[0] Bool)+ :: Equal (Id Int) (Id Bool) ~ False++which is bogus! This is because the type system isn't smart enough to know+that (Id Int) and (Id Bool) are Surely Apart, as they're headed by type+families. At the time of writing, I (Richard Eisenberg) couldn't think of+a way of detecting this any more efficient than just building the optimised+coercion and checking.+-}++-- | Check to make sure that an AxInstCo is internally consistent.+-- Returns the conflicting branch, if it exists+-- See Note [Conflict checking with AxiomInstCo]+checkAxInstCo :: Coercion -> Maybe CoAxBranch+-- defined here to avoid dependencies in Coercion+-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism] in CoreLint+checkAxInstCo (AxiomInstCo ax ind cos)+ = let branch = coAxiomNthBranch ax ind+ tvs = coAxBranchTyVars branch+ cvs = coAxBranchCoVars branch+ incomps = coAxBranchIncomps branch+ (tys, cotys) = splitAtList tvs (map (pFst . coercionKind) cos)+ co_args = map stripCoercionTy cotys+ subst = zipTvSubst tvs tys `composeTCvSubst`+ zipCvSubst cvs co_args+ target = Type.substTys subst (coAxBranchLHS branch)+ in_scope = mkInScopeSet $+ unionVarSets (map (tyCoVarsOfTypes . coAxBranchLHS) incomps)+ flattened_target = flattenTys in_scope target in+ check_no_conflict flattened_target incomps+ where+ check_no_conflict :: [Type] -> [CoAxBranch] -> Maybe CoAxBranch+ check_no_conflict _ [] = Nothing+ check_no_conflict flat (b@CoAxBranch { cab_lhs = lhs_incomp } : rest)+ -- See Note [Apartness] in FamInstEnv+ | SurelyApart <- tcUnifyTysFG instanceBindFun flat lhs_incomp+ = check_no_conflict flat rest+ | otherwise+ = Just b+checkAxInstCo _ = Nothing+++-----------+wrapSym :: SymFlag -> Coercion -> Coercion+wrapSym sym co | sym = SymCo co+ | otherwise = co++-- | Conditionally set a role to be representational+wrapRole :: ReprFlag+ -> Role -- ^ current role+ -> Coercion -> Coercion+wrapRole False _ = id+wrapRole True current = downgradeRole Representational current++-- | If we require a representational role, return that. Otherwise,+-- return the "default" role provided.+chooseRole :: ReprFlag+ -> Role -- ^ "default" role+ -> Role+chooseRole True _ = Representational+chooseRole _ r = r++-----------+isAxiom_maybe :: Coercion -> Maybe (Bool, CoAxiom Branched, Int, [Coercion])+isAxiom_maybe (SymCo co)+ | Just (sym, con, ind, cos) <- isAxiom_maybe co+ = Just (not sym, con, ind, cos)+isAxiom_maybe (AxiomInstCo con ind cos)+ = Just (False, con, ind, cos)+isAxiom_maybe _ = Nothing++matchAxiom :: Bool -- True = match LHS, False = match RHS+ -> CoAxiom br -> Int -> Coercion -> Maybe [Coercion]+matchAxiom sym ax@(CoAxiom { co_ax_tc = tc }) ind co+ | CoAxBranch { cab_tvs = qtvs+ , cab_cvs = [] -- can't infer these, so fail if there are any+ , cab_roles = roles+ , cab_lhs = lhs+ , cab_rhs = rhs } <- coAxiomNthBranch ax ind+ , Just subst <- liftCoMatch (mkVarSet qtvs)+ (if sym then (mkTyConApp tc lhs) else rhs)+ co+ , all (`isMappedByLC` subst) qtvs+ = zipWithM (liftCoSubstTyVar subst) roles qtvs++ | otherwise+ = Nothing++-------------+-- destruct a CoherenceCo+isCohLeft_maybe :: Coercion -> Maybe (Coercion, Coercion)+isCohLeft_maybe (CoherenceCo co1 co2) = Just (co1, co2)+isCohLeft_maybe _ = Nothing++-- destruct a (sym (co1 |> co2)).+-- if isCohRight_maybe co = Just (co1, co2), then (sym co1) `mkCohRightCo` co2 = co+isCohRight_maybe :: Coercion -> Maybe (Coercion, Coercion)+isCohRight_maybe (SymCo (CoherenceCo co1 co2)) = Just (mkSymCo co1, co2)+isCohRight_maybe _ = Nothing++-------------+compatible_co :: Coercion -> Coercion -> Bool+-- Check whether (co1 . co2) will be well-kinded+compatible_co co1 co2+ = x1 `eqType` x2+ where+ Pair _ x1 = coercionKind co1+ Pair x2 _ = coercionKind co2++-------------+{-+etaForAllCo_maybe+~~~~~~~~~~~~~~~~~+Suppose we have++ g : all a1:k1.t1 ~ all a2:k2.t2++but g is *not* a ForAllCo. We want to eta-expand it. So, we do this:++ g' = all a1:(ForAllKindCo g).(InstCo g (a1 `mkCoherenceRightCo` ForAllKindCo g))++Call the kind coercion h1 and the body coercion h2. We can see that++ h2 : t1 ~ t2[a2 |-> (a1 |> h2)]++According to the typing rule for ForAllCo, we get that++ g' : all a1:k1.t1 ~ all a1:k2.(t2[a2 |-> (a1 |> h2)][a1 |-> a1 |> sym h2])++or++ g' : all a1:k1.t1 ~ all a1:k2.(t2[a2 |-> a1])++as desired.+-}+etaForAllCo_maybe :: Coercion -> Maybe (TyVar, Coercion, Coercion)+-- Try to make the coercion be of form (forall tv:kind_co. co)+etaForAllCo_maybe co+ | ForAllCo tv kind_co r <- co+ = Just (tv, kind_co, r)++ | Pair ty1 ty2 <- coercionKind co+ , Just (tv1, _) <- splitForAllTy_maybe ty1+ , isForAllTy ty2+ , let kind_co = mkNthCo 0 co+ = Just ( tv1, kind_co+ , mkInstCo co (mkNomReflCo (TyVarTy tv1) `mkCoherenceRightCo` kind_co) )++ | otherwise+ = Nothing++etaAppCo_maybe :: Coercion -> Maybe (Coercion,Coercion)+-- If possible, split a coercion+-- g :: t1a t1b ~ t2a t2b+-- into a pair of coercions (left g, right g)+etaAppCo_maybe co+ | Just (co1,co2) <- splitAppCo_maybe co+ = Just (co1,co2)+ | (Pair ty1 ty2, Nominal) <- coercionKindRole co+ , Just (_,t1) <- splitAppTy_maybe ty1+ , Just (_,t2) <- splitAppTy_maybe ty2+ , let isco1 = isCoercionTy t1+ , let isco2 = isCoercionTy t2+ , isco1 == isco2+ = Just (LRCo CLeft co, LRCo CRight co)+ | otherwise+ = Nothing++etaTyConAppCo_maybe :: TyCon -> Coercion -> Maybe [Coercion]+-- If possible, split a coercion+-- g :: T s1 .. sn ~ T t1 .. tn+-- into [ Nth 0 g :: s1~t1, ..., Nth (n-1) g :: sn~tn ]+etaTyConAppCo_maybe tc (TyConAppCo _ tc2 cos2)+ = ASSERT( tc == tc2 ) Just cos2++etaTyConAppCo_maybe tc co+ | mightBeUnsaturatedTyCon tc+ , (Pair ty1 ty2, r) <- coercionKindRole co+ , Just (tc1, tys1) <- splitTyConApp_maybe ty1+ , Just (tc2, tys2) <- splitTyConApp_maybe ty2+ , tc1 == tc2+ , isInjectiveTyCon tc r -- See Note [NthCo and newtypes] in TyCoRep+ , let n = length tys1+ = ASSERT( tc == tc1 )+ ASSERT( n == length tys2 )+ Just (decomposeCo n co)+ -- NB: n might be <> tyConArity tc+ -- e.g. data family T a :: * -> *+ -- g :: T a b ~ T c d++ | otherwise+ = Nothing++{-+Note [Eta for AppCo]+~~~~~~~~~~~~~~~~~~~~+Suppose we have+ g :: s1 t1 ~ s2 t2++Then we can't necessarily make+ left g :: s1 ~ s2+ right g :: t1 ~ t2+because it's possible that+ s1 :: * -> * t1 :: *+ s2 :: (*->*) -> * t2 :: * -> *+and in that case (left g) does not have the same+kind on either side.++It's enough to check that+ kind t1 = kind t2+because if g is well-kinded then+ kind (s1 t2) = kind (s2 t2)+and these two imply+ kind s1 = kind s2++-}++optForAllCoBndr :: LiftingContext -> Bool+ -> TyVar -> Coercion -> (LiftingContext, TyVar, Coercion)+optForAllCoBndr env sym+ = substForAllCoBndrCallbackLC sym (opt_co4_wrap env sym False Nominal) env
+ types/TyCoRep.hs view
@@ -0,0 +1,2866 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1998+\section[TyCoRep]{Type and Coercion - friends' interface}++Note [The Type-related module hierarchy]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ Class+ CoAxiom+ TyCon imports Class, CoAxiom+ TyCoRep imports Class, CoAxiom, TyCon+ TysPrim imports TyCoRep ( including mkTyConTy )+ Kind imports TysPrim ( mainly for primitive kinds )+ Type imports Kind+ Coercion imports Type+-}++-- We expose the relevant stuff from this module via the Type module+{-# OPTIONS_HADDOCK hide #-}+{-# LANGUAGE CPP, DeriveDataTypeable, MultiWayIf #-}+{-# LANGUAGE ImplicitParams #-}++module TyCoRep (+ TyThing(..), tyThingCategory, pprTyThingCategory, pprShortTyThing,++ -- * Types+ Type(..),+ TyLit(..),+ KindOrType, Kind,+ PredType, ThetaType, -- Synonyms+ ArgFlag(..),++ -- * Coercions+ Coercion(..),+ UnivCoProvenance(..), CoercionHole(..),+ CoercionN, CoercionR, CoercionP, KindCoercion,++ -- * Functions over types+ mkTyConTy, mkTyVarTy, mkTyVarTys,+ mkFunTy, mkFunTys, mkForAllTy, mkForAllTys,+ mkPiTy, mkPiTys,+ isLiftedTypeKind, isUnliftedTypeKind,+ isCoercionType, isRuntimeRepTy, isRuntimeRepVar,+ isRuntimeRepKindedTy, dropRuntimeRepArgs,+ sameVis,++ -- * Functions over binders+ TyBinder(..), TyVarBinder,+ binderVar, binderVars, binderKind, binderArgFlag,+ delBinderVar,+ isInvisibleArgFlag, isVisibleArgFlag,+ isInvisibleBinder, isVisibleBinder,++ -- * Functions over coercions+ pickLR,++ -- * Pretty-printing+ pprType, pprParendType, pprTypeApp, pprTvBndr, pprTvBndrs,+ pprSigmaType,+ pprTheta, pprForAll, pprUserForAll,+ pprTyVar, pprTyVars,+ pprThetaArrowTy, pprClassPred,+ pprKind, pprParendKind, pprTyLit,+ TyPrec(..), maybeParen, pprTcAppCo,+ pprPrefixApp, pprArrowChain,+ pprDataCons, ppSuggestExplicitKinds,++ -- * Free variables+ tyCoVarsOfType, tyCoVarsOfTypeDSet, tyCoVarsOfTypes, tyCoVarsOfTypesDSet,+ tyCoFVsBndr, tyCoFVsOfType, tyCoVarsOfTypeList,+ tyCoFVsOfTypes, tyCoVarsOfTypesList,+ closeOverKindsDSet, closeOverKindsFV, closeOverKindsList,+ coVarsOfType, coVarsOfTypes,+ coVarsOfCo, coVarsOfCos,+ tyCoVarsOfCo, tyCoVarsOfCos,+ tyCoVarsOfCoDSet,+ tyCoFVsOfCo, tyCoFVsOfCos,+ tyCoVarsOfCoList, tyCoVarsOfProv,+ closeOverKinds,++ noFreeVarsOfType, noFreeVarsOfCo,++ -- * Substitutions+ TCvSubst(..), TvSubstEnv, CvSubstEnv,+ emptyTvSubstEnv, emptyCvSubstEnv, composeTCvSubstEnv, composeTCvSubst,+ emptyTCvSubst, mkEmptyTCvSubst, isEmptyTCvSubst,+ mkTCvSubst, mkTvSubst,+ getTvSubstEnv,+ getCvSubstEnv, getTCvInScope, getTCvSubstRangeFVs,+ isInScope, notElemTCvSubst,+ setTvSubstEnv, setCvSubstEnv, zapTCvSubst,+ extendTCvInScope, extendTCvInScopeList, extendTCvInScopeSet,+ extendTCvSubst,+ extendCvSubst, extendCvSubstWithClone,+ extendTvSubst, extendTvSubstBinder, extendTvSubstWithClone,+ extendTvSubstList, extendTvSubstAndInScope,+ unionTCvSubst, zipTyEnv, zipCoEnv, mkTyCoInScopeSet,+ zipTvSubst, zipCvSubst,+ mkTvSubstPrs,++ substTyWith, substTyWithCoVars, substTysWith, substTysWithCoVars,+ substCoWith,+ substTy, substTyAddInScope,+ substTyUnchecked, substTysUnchecked, substThetaUnchecked,+ substTyWithUnchecked,+ substCoUnchecked, substCoWithUnchecked,+ substTyWithInScope,+ substTys, substTheta,+ lookupTyVar, substTyVarBndr,+ substCo, substCos, substCoVar, substCoVars, lookupCoVar,+ substCoVarBndr, cloneTyVarBndr, cloneTyVarBndrs,+ substTyVar, substTyVars,+ substForAllCoBndr,+ substTyVarBndrCallback, substForAllCoBndrCallback,+ checkValidSubst, isValidTCvSubst,++ -- * Tidying type related things up for printing+ tidyType, tidyTypes,+ tidyOpenType, tidyOpenTypes,+ tidyOpenKind,+ tidyTyCoVarBndr, tidyTyCoVarBndrs, tidyFreeTyCoVars,+ tidyOpenTyCoVar, tidyOpenTyCoVars,+ tidyTyVarOcc,+ tidyTopType,+ tidyKind,+ tidyCo, tidyCos,+ tidyTyVarBinder, tidyTyVarBinders,++ -- * Sizes+ typeSize, coercionSize, provSize+ ) where++#include "HsVersions.h"++import {-# SOURCE #-} DataCon( dataConFullSig+ , dataConUnivTyVarBinders, dataConExTyVarBinders+ , DataCon, filterEqSpec )+import {-# SOURCE #-} Type( isPredTy, isCoercionTy, mkAppTy, mkCastTy+ , tyCoVarsOfTypesWellScoped+ , tyCoVarsOfTypeWellScoped+ , coreView, typeKind )+ -- Transitively pulls in a LOT of stuff, better to break the loop++import {-# SOURCE #-} Coercion+import {-# SOURCE #-} ConLike ( ConLike(..), conLikeName )+import {-# SOURCE #-} ToIface( toIfaceTypeX, toIfaceTyLit, toIfaceForAllBndr+ , toIfaceTyCon, toIfaceTcArgs, toIfaceCoercion )++-- friends:+import IfaceType+import Var+import VarEnv+import VarSet+import Name hiding ( varName )+import TyCon+import Class+import CoAxiom+import FV++-- others+import BasicTypes ( LeftOrRight(..), TyPrec(..), maybeParen, pickLR )+import PrelNames+import Outputable+import DynFlags+import FastString+import Pair+import UniqSupply+import Util+import UniqFM+import UniqSet++-- libraries+import qualified Data.Data as Data hiding ( TyCon )+import Data.List+import Data.IORef ( IORef ) -- for CoercionHole++{-+%************************************************************************+%* *+ TyThing+%* *+%************************************************************************++Despite the fact that DataCon has to be imported via a hi-boot route,+this module seems the right place for TyThing, because it's needed for+funTyCon and all the types in TysPrim.++It is also SOURCE-imported into Name.hs+++Note [ATyCon for classes]+~~~~~~~~~~~~~~~~~~~~~~~~~+Both classes and type constructors are represented in the type environment+as ATyCon. You can tell the difference, and get to the class, with+ isClassTyCon :: TyCon -> Bool+ tyConClass_maybe :: TyCon -> Maybe Class+The Class and its associated TyCon have the same Name.+-}++-- | A global typecheckable-thing, essentially anything that has a name.+-- Not to be confused with a 'TcTyThing', which is also a typecheckable+-- thing but in the *local* context. See 'TcEnv' for how to retrieve+-- a 'TyThing' given a 'Name'.+data TyThing+ = AnId Id+ | AConLike ConLike+ | ATyCon TyCon -- TyCons and classes; see Note [ATyCon for classes]+ | ACoAxiom (CoAxiom Branched)++instance Outputable TyThing where+ ppr = pprShortTyThing++instance NamedThing TyThing where -- Can't put this with the type+ getName (AnId id) = getName id -- decl, because the DataCon instance+ getName (ATyCon tc) = getName tc -- isn't visible there+ getName (ACoAxiom cc) = getName cc+ getName (AConLike cl) = conLikeName cl++pprShortTyThing :: TyThing -> SDoc+-- c.f. PprTyThing.pprTyThing, which prints all the details+pprShortTyThing thing+ = pprTyThingCategory thing <+> quotes (ppr (getName thing))++pprTyThingCategory :: TyThing -> SDoc+pprTyThingCategory = text . capitalise . tyThingCategory++tyThingCategory :: TyThing -> String+tyThingCategory (ATyCon tc)+ | isClassTyCon tc = "class"+ | otherwise = "type constructor"+tyThingCategory (ACoAxiom _) = "coercion axiom"+tyThingCategory (AnId _) = "identifier"+tyThingCategory (AConLike (RealDataCon _)) = "data constructor"+tyThingCategory (AConLike (PatSynCon _)) = "pattern synonym"+++{- **********************************************************************+* *+ Type+* *+********************************************************************** -}++-- | The key representation of types within the compiler++type KindOrType = Type -- See Note [Arguments to type constructors]++-- | The key type representing kinds in the compiler.+type Kind = Type++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data Type+ -- See Note [Non-trivial definitional equality]+ = TyVarTy Var -- ^ Vanilla type or kind variable (*never* a coercion variable)++ | AppTy+ Type+ Type -- ^ Type application to something other than a 'TyCon'. Parameters:+ --+ -- 1) Function: must /not/ be a 'TyConApp',+ -- must be another 'AppTy', or 'TyVarTy'+ --+ -- 2) Argument type++ | TyConApp+ TyCon+ [KindOrType] -- ^ Application of a 'TyCon', including newtypes /and/ synonyms.+ -- Invariant: saturated applications of 'FunTyCon' must+ -- use 'FunTy' and saturated synonyms must use their own+ -- constructors. However, /unsaturated/ 'FunTyCon's+ -- do appear as 'TyConApp's.+ -- Parameters:+ --+ -- 1) Type constructor being applied to.+ --+ -- 2) Type arguments. Might not have enough type arguments+ -- here to saturate the constructor.+ -- Even type synonyms are not necessarily saturated;+ -- for example unsaturated type synonyms+ -- can appear as the right hand side of a type synonym.++ | ForAllTy+ {-# UNPACK #-} !TyVarBinder+ Type -- ^ A Π type.++ | FunTy Type Type -- ^ t1 -> t2 Very common, so an important special case++ | LitTy TyLit -- ^ Type literals are similar to type constructors.++ | CastTy+ Type+ KindCoercion -- ^ A kind cast. The coercion is always nominal.+ -- INVARIANT: The cast is never refl.+ -- INVARIANT: The cast is "pushed down" as far as it+ -- can go. See Note [Pushing down casts]++ | CoercionTy+ Coercion -- ^ Injection of a Coercion into a type+ -- This should only ever be used in the RHS of an AppTy,+ -- in the list of a TyConApp, when applying a promoted+ -- GADT data constructor++ deriving Data.Data+++-- NOTE: Other parts of the code assume that type literals do not contain+-- types or type variables.+data TyLit+ = NumTyLit Integer+ | StrTyLit FastString+ deriving (Eq, Ord, Data.Data)++{- Note [Arguments to type constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Because of kind polymorphism, in addition to type application we now+have kind instantiation. We reuse the same notations to do so.++For example:++ Just (* -> *) Maybe+ Right * Nat Zero++are represented by:++ TyConApp (PromotedDataCon Just) [* -> *, Maybe]+ TyConApp (PromotedDataCon Right) [*, Nat, (PromotedDataCon Zero)]++Important note: Nat is used as a *kind* and not as a type. This can be+confusing, since type-level Nat and kind-level Nat are identical. We+use the kind of (PromotedDataCon Right) to know if its arguments are+kinds or types.++This kind instantiation only happens in TyConApp currently.++Note [Pushing down casts]+~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have (a :: k1 -> *), (b :: k1), and (co :: * ~ q).+The type (a b |> co) is `eqType` to ((a |> co') b), where+co' = (->) <k1> co. Thus, to make this visible to functions+that inspect types, we always push down coercions, preferring+the second form. Note that this also applies to TyConApps!++Note [Non-trivial definitional equality]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Is Int |> <*> the same as Int? YES! In order to reduce headaches,+we decide that any reflexive casts in types are just ignored. More+generally, the `eqType` function, which defines Core's type equality+relation, ignores casts and coercion arguments, as long as the+two types have the same kind. This allows us to be a little sloppier+in keeping track of coercions, which is a good thing. It also means+that eqType does not depend on eqCoercion, which is also a good thing.++Why is this sensible? That is, why is something different than α-equivalence+appropriate for the implementation of eqType?++Anything smaller than ~ and homogeneous is an appropriate definition for+equality. The type safety of FC depends only on ~. Let's say η : τ ~ σ. Any+expression of type τ can be transmuted to one of type σ at any point by+casting. The same is true of types of type τ. So in some sense, τ and σ are+interchangeable.++But let's be more precise. If we examine the typing rules of FC (say, those in+http://www.cis.upenn.edu/~eir/papers/2015/equalities/equalities-extended.pdf)+there are several places where the same metavariable is used in two different+premises to a rule. (For example, see Ty_App.) There is an implicit equality+check here. What definition of equality should we use? By convention, we use+α-equivalence. Take any rule with one (or more) of these implicit equality+checks. Then there is an admissible rule that uses ~ instead of the implicit+check, adding in casts as appropriate.++The only problem here is that ~ is heterogeneous. To make the kinds work out+in the admissible rule that uses ~, it is necessary to homogenize the+coercions. That is, if we have η : (τ : κ1) ~ (σ : κ2), then we don't use η;+we use η |> kind η, which is homogeneous.++The effect of this all is that eqType, the implementation of the implicit+equality check, can use any homogeneous relation that is smaller than ~, as+those rules must also be admissible.++What would go wrong if we insisted on the casts matching? See the beginning of+Section 8 in the unpublished paper above. Theoretically, nothing at all goes+wrong. But in practical terms, getting the coercions right proved to be+nightmarish. And types would explode: during kind-checking, we often produce+reflexive kind coercions. When we try to cast by these, mkCastTy just discards+them. But if we used an eqType that distinguished between Int and Int |> <*>,+then we couldn't discard -- the output of kind-checking would be enormous,+and we would need enormous casts with lots of CoherenceCo's to straighten+them out.++Would anything go wrong if eqType respected type families? No, not at all. But+that makes eqType rather hard to implement.++Thus, the guideline for eqType is that it should be the largest+easy-to-implement relation that is still smaller than ~ and homogeneous. The+precise choice of relation is somewhat incidental, as long as the smart+constructors and destructors in Type respect whatever relation is chosen.++Another helpful principle with eqType is this:++ ** If (t1 eqType t2) then I can replace t1 by t2 anywhere. **++This principle also tells us that eqType must relate only types with the+same kinds.+-}++{- **********************************************************************+* *+ TyBinder and ArgFlag+* *+********************************************************************** -}++-- | A 'TyBinder' represents an argument to a function. TyBinders can be dependent+-- ('Named') or nondependent ('Anon'). They may also be visible or not.+-- See Note [TyBinders]+data TyBinder+ = Named TyVarBinder -- A type-lambda binder+ | Anon Type -- A term-lambda binder+ -- Visibility is determined by the type (Constraint vs. *)+ deriving Data.Data++-- | Remove the binder's variable from the set, if the binder has+-- a variable.+delBinderVar :: VarSet -> TyVarBinder -> VarSet+delBinderVar vars (TvBndr tv _) = vars `delVarSet` tv++-- | Does this binder bind an invisible argument?+isInvisibleBinder :: TyBinder -> Bool+isInvisibleBinder (Named (TvBndr _ vis)) = isInvisibleArgFlag vis+isInvisibleBinder (Anon ty) = isPredTy ty++-- | Does this binder bind a visible argument?+isVisibleBinder :: TyBinder -> Bool+isVisibleBinder = not . isInvisibleBinder+++{- Note [TyBinders]+~~~~~~~~~~~~~~~~~~~+A ForAllTy contains a TyVarBinder. But a type can be decomposed+to a telescope consisting of a [TyBinder]++A TyBinder represents the type of binders -- that is, the type of an+argument to a Pi-type. GHC Core currently supports two different+Pi-types:++ * A non-dependent function type,+ written with ->, e.g. ty1 -> ty2+ represented as FunTy ty1 ty2. These are+ lifted to Coercions with the corresponding FunCo.++ * A dependent compile-time-only polytype,+ written with forall, e.g. forall (a:*). ty+ represented as ForAllTy (TvBndr a v) ty++Both Pi-types classify terms/types that take an argument. In other+words, if `x` is either a function or a polytype, `x arg` makes sense+(for an appropriate `arg`).+++Note [TyBinders and ArgFlags]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+A ForAllTy contains a TyVarBinder. Each TyVarBinder is equipped+with a ArgFlag, which says whether or not arguments for this+binder should be visible (explicit) in source Haskell.++-----------------------------------------------------------------------+ Occurrences look like this+ TyBinder GHC displays type as in Haskell souce code+-----------------------------------------------------------------------+In the type of a term+ Anon: f :: type -> type Arg required: f x+ Named Inferred: f :: forall {a}. type Arg not allowed: f+ Named Specified: f :: forall a. type Arg optional: f or f @Int+ Named Required: Illegal: See Note [No Required TyBinder in terms]++In the kind of a type+ Anon: T :: kind -> kind Required: T *+ Named Inferred: T :: forall {k}. kind Arg not allowed: T+ Named Specified: T :: forall k. kind Arg not allowed[1]: T+ Named Required: T :: forall k -> kind Required: T *+------------------------------------------------------------------------++[1] In types, in the Specified case, it would make sense to allow+ optional kind applications, thus (T @*), but we have not+ yet implemented that++---- Examples of where the different visiblities come from -----++In term declarations:++* Inferred. Function defn, with no signature: f1 x = x+ We infer f1 :: forall {a}. a -> a, with 'a' Inferred+ It's Inferred because it doesn't appear in any+ user-written signature for f1++* Specified. Function defn, with signature (implicit forall):+ f2 :: a -> a; f2 x = x+ So f2 gets the type f2 :: forall a. a->a, with 'a' Specified+ even though 'a' is not bound in the source code by an explicit forall++* Specified. Function defn, with signature (explicit forall):+ f3 :: forall a. a -> a; f3 x = x+ So f3 gets the type f3 :: forall a. a->a, with 'a' Specified++* Inferred/Specified. Function signature with inferred kind polymorphism.+ f4 :: a b -> Int+ So 'f4' gets the type f4 :: forall {k} (a:k->*) (b:k). a b -> Int+ Here 'k' is Inferred (it's not mentioned in the type),+ but 'a' and 'b' are Specified.++* Specified. Function signature with explicit kind polymorphism+ f5 :: a (b :: k) -> Int+ This time 'k' is Specified, because it is mentioned explicitly,+ so we get f5 :: forall (k:*) (a:k->*) (b:k). a b -> Int++* Similarly pattern synonyms:+ Inferred - from inferred types (e.g. no pattern type signature)+ - or from inferred kind polymorphism++In type declarations:++* Inferred (k)+ data T1 a b = MkT1 (a b)+ Here T1's kind is T1 :: forall {k:*}. (k->*) -> k -> *+ The kind variable 'k' is Inferred, since it is not mentioned++ Note that 'a' and 'b' correspond to /Anon/ TyBinders in T1's kind,+ and Anon binders don't have a visibility flag. (Or you could think+ of Anon having an implicit Required flag.)++* Specified (k)+ data T2 (a::k->*) b = MkT (a b)+ Here T's kind is T :: forall (k:*). (k->*) -> k -> *+ The kind variable 'k' is Specified, since it is mentioned in+ the signature.++* Required (k)+ data T k (a::k->*) b = MkT (a b)+ Here T's kind is T :: forall k:* -> (k->*) -> k -> *+ The kind is Required, since it bound in a positional way in T's declaration+ Every use of T must be explicitly applied to a kind++* Inferred (k1), Specified (k)+ data T a b (c :: k) = MkT (a b) (Proxy c)+ Here T's kind is T :: forall {k1:*} (k:*). (k1->*) -> k1 -> k -> *+ So 'k' is Specified, because it appears explicitly,+ but 'k1' is Inferred, because it does not++---- Printing -----++ We print forall types with enough syntax to tell you their visiblity+ flag. But this is not source Haskell, and these types may not all+ be parsable.++ Specified: a list of Specified binders is written between `forall` and `.`:+ const :: forall a b. a -> b -> a++ Inferred: with -fprint-explicit-foralls, Inferred binders are written+ in braces:+ f :: forall {k} (a:k). S k a -> Int+ Otherwise, they are printed like Specified binders.++ Required: binders are put between `forall` and `->`:+ T :: forall k -> *++---- Other points -----++* In classic Haskell, all named binders (that is, the type variables in+ a polymorphic function type f :: forall a. a -> a) have been Inferred.++* Inferred variables correspond to "generalized" variables from the+ Visible Type Applications paper (ESOP'16).++Note [No Required TyBinder in terms]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't allow Required foralls for term variables, including pattern+synonyms and data constructors. Why? Because then an application+would need a /compulsory/ type argument (possibly without an "@"?),+thus (f Int); and we don't have concrete syntax for that.++We could change this decision, but Required, Named TyBinders are rare+anyway. (Most are Anons.)+-}+++{- **********************************************************************+* *+ PredType+* *+********************************************************************** -}+++-- | A type of the form @p@ of kind @Constraint@ represents a value whose type is+-- the Haskell predicate @p@, where a predicate is what occurs before+-- the @=>@ in a Haskell type.+--+-- We use 'PredType' as documentation to mark those types that we guarantee to have+-- this kind.+--+-- It can be expanded into its representation, but:+--+-- * The type checker must treat it as opaque+--+-- * The rest of the compiler treats it as transparent+--+-- Consider these examples:+--+-- > f :: (Eq a) => a -> Int+-- > g :: (?x :: Int -> Int) => a -> Int+-- > h :: (r\l) => {r} => {l::Int | r}+--+-- Here the @Eq a@ and @?x :: Int -> Int@ and @r\l@ are all called \"predicates\"+type PredType = Type++-- | A collection of 'PredType's+type ThetaType = [PredType]++{-+(We don't support TREX records yet, but the setup is designed+to expand to allow them.)++A Haskell qualified type, such as that for f,g,h above, is+represented using+ * a FunTy for the double arrow+ * with a type of kind Constraint as the function argument++The predicate really does turn into a real extra argument to the+function. If the argument has type (p :: Constraint) then the predicate p is+represented by evidence of type p.+++%************************************************************************+%* *+ Simple constructors+%* *+%************************************************************************++These functions are here so that they can be used by TysPrim,+which in turn is imported by Type+-}++-- named with "Only" to prevent naive use of mkTyVarTy+mkTyVarTy :: TyVar -> Type+mkTyVarTy v = ASSERT2( isTyVar v, ppr v <+> dcolon <+> ppr (tyVarKind v) )+ TyVarTy v++mkTyVarTys :: [TyVar] -> [Type]+mkTyVarTys = map mkTyVarTy -- a common use of mkTyVarTy++infixr 3 `mkFunTy` -- Associates to the right+-- | Make an arrow type+mkFunTy :: Type -> Type -> Type+mkFunTy arg res = FunTy arg res++-- | Make nested arrow types+mkFunTys :: [Type] -> Type -> Type+mkFunTys tys ty = foldr mkFunTy ty tys++mkForAllTy :: TyVar -> ArgFlag -> Type -> Type+mkForAllTy tv vis ty = ForAllTy (TvBndr tv vis) ty++-- | Wraps foralls over the type using the provided 'TyVar's from left to right+mkForAllTys :: [TyVarBinder] -> Type -> Type+mkForAllTys tyvars ty = foldr ForAllTy ty tyvars++mkPiTy :: TyBinder -> Type -> Type+mkPiTy (Anon ty1) ty2 = FunTy ty1 ty2+mkPiTy (Named tvb) ty = ForAllTy tvb ty++mkPiTys :: [TyBinder] -> Type -> Type+mkPiTys tbs ty = foldr mkPiTy ty tbs++-- | Does this type classify a core (unlifted) Coercion?+-- At either role nominal or representational+-- (t1 ~# t2) or (t1 ~R# t2)+isCoercionType :: Type -> Bool+isCoercionType (TyConApp tc tys)+ | (tc `hasKey` eqPrimTyConKey) || (tc `hasKey` eqReprPrimTyConKey)+ , length tys == 4+ = True+isCoercionType _ = False+++-- | Create the plain type constructor type which has been applied to no type arguments at all.+mkTyConTy :: TyCon -> Type+mkTyConTy tycon = TyConApp tycon []++{-+Some basic functions, put here to break loops eg with the pretty printer+-}++is_TYPE :: ( Type -- the single argument to TYPE; not a synonym+ -> Bool ) -- what to return+ -> Kind -> Bool+is_TYPE f ki | Just ki' <- coreView ki = is_TYPE f ki'+is_TYPE f (TyConApp tc [arg])+ | tc `hasKey` tYPETyConKey+ = go arg+ where+ go ty | Just ty' <- coreView ty = go ty'+ go ty = f ty+is_TYPE _ _ = False++-- | This version considers Constraint to be distinct from *. Returns True+-- if the argument is equivalent to Type and False otherwise.+isLiftedTypeKind :: Kind -> Bool+isLiftedTypeKind = is_TYPE is_lifted+ where+ is_lifted (TyConApp lifted_rep []) = lifted_rep `hasKey` liftedRepDataConKey+ is_lifted _ = False++-- | Returns True if the kind classifies unlifted types and False otherwise.+-- Note that this returns False for levity-polymorphic kinds, which may+-- be specialized to a kind that classifies unlifted types.+isUnliftedTypeKind :: Kind -> Bool+isUnliftedTypeKind = is_TYPE is_unlifted+ where+ is_unlifted (TyConApp rr _args) = not (rr `hasKey` liftedRepDataConKey)+ is_unlifted _ = False++-- | Is this the type 'RuntimeRep'?+isRuntimeRepTy :: Type -> Bool+isRuntimeRepTy ty | Just ty' <- coreView ty = isRuntimeRepTy ty'+isRuntimeRepTy (TyConApp tc []) = tc `hasKey` runtimeRepTyConKey+isRuntimeRepTy _ = False++-- | Is this a type of kind RuntimeRep? (e.g. LiftedRep)+isRuntimeRepKindedTy :: Type -> Bool+isRuntimeRepKindedTy = isRuntimeRepTy . typeKind++-- | Is a tyvar of type 'RuntimeRep'?+isRuntimeRepVar :: TyVar -> Bool+isRuntimeRepVar = isRuntimeRepTy . tyVarKind++-- | Drops prefix of RuntimeRep constructors in 'TyConApp's. Useful for e.g.+-- dropping 'LiftedRep arguments of unboxed tuple TyCon applications:+--+-- dropRuntimeRepArgs [ 'LiftedRep, 'IntRep+-- , String, Int# ] == [String, Int#]+--+dropRuntimeRepArgs :: [Type] -> [Type]+dropRuntimeRepArgs = dropWhile isRuntimeRepKindedTy++{-+%************************************************************************+%* *+ Coercions+%* *+%************************************************************************+-}++-- | A 'Coercion' is concrete evidence of the equality/convertibility+-- of two types.++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data Coercion+ -- Each constructor has a "role signature", indicating the way roles are+ -- propagated through coercions.+ -- - P, N, and R stand for coercions of the given role+ -- - e stands for a coercion of a specific unknown role+ -- (think "role polymorphism")+ -- - "e" stands for an explicit role parameter indicating role e.+ -- - _ stands for a parameter that is not a Role or Coercion.++ -- These ones mirror the shape of types+ = -- Refl :: "e" -> _ -> e+ Refl Role Type -- See Note [Refl invariant]+ -- Invariant: applications of (Refl T) to a bunch of identity coercions+ -- always show up as Refl.+ -- For example (Refl T) (Refl a) (Refl b) shows up as (Refl (T a b)).++ -- Applications of (Refl T) to some coercions, at least one of+ -- which is NOT the identity, show up as TyConAppCo.+ -- (They may not be fully saturated however.)+ -- ConAppCo coercions (like all coercions other than Refl)+ -- are NEVER the identity.++ -- Use (Refl Representational _), not (SubCo (Refl Nominal _))++ -- These ones simply lift the correspondingly-named+ -- Type constructors into Coercions++ -- TyConAppCo :: "e" -> _ -> ?? -> e+ -- See Note [TyConAppCo roles]+ | TyConAppCo Role TyCon [Coercion] -- lift TyConApp+ -- The TyCon is never a synonym;+ -- we expand synonyms eagerly+ -- But it can be a type function++ | AppCo Coercion CoercionN -- lift AppTy+ -- AppCo :: e -> N -> e++ -- See Note [Forall coercions]+ | ForAllCo TyVar KindCoercion Coercion+ -- ForAllCo :: _ -> N -> e -> e++ | FunCo Role Coercion Coercion -- lift FunTy+ -- FunCo :: "e" -> e -> e -> e++ -- These are special+ | CoVarCo CoVar -- :: _ -> (N or R)+ -- result role depends on the tycon of the variable's type++ -- AxiomInstCo :: e -> _ -> [N] -> e+ | AxiomInstCo (CoAxiom Branched) BranchIndex [Coercion]+ -- See also [CoAxiom index]+ -- The coercion arguments always *precisely* saturate+ -- arity of (that branch of) the CoAxiom. If there are+ -- any left over, we use AppCo.+ -- See [Coercion axioms applied to coercions]++ | UnivCo UnivCoProvenance Role Type Type+ -- :: _ -> "e" -> _ -> _ -> e++ | SymCo Coercion -- :: e -> e+ | TransCo Coercion Coercion -- :: e -> e -> e++ -- The number coercions should match exactly the expectations+ -- of the CoAxiomRule (i.e., the rule is fully saturated).+ | AxiomRuleCo CoAxiomRule [Coercion]++ | NthCo Int Coercion -- Zero-indexed; decomposes (T t0 ... tn)+ -- :: _ -> e -> ?? (inverse of TyConAppCo, see Note [TyConAppCo roles])+ -- Using NthCo on a ForAllCo gives an N coercion always+ -- See Note [NthCo and newtypes]++ | LRCo LeftOrRight CoercionN -- Decomposes (t_left t_right)+ -- :: _ -> N -> N+ | InstCo Coercion CoercionN+ -- :: e -> N -> e+ -- See Note [InstCo roles]++ -- Coherence applies a coercion to the left-hand type of another coercion+ -- See Note [Coherence]+ | CoherenceCo Coercion KindCoercion+ -- :: e -> N -> e++ -- Extract a kind coercion from a (heterogeneous) type coercion+ -- NB: all kind coercions are Nominal+ | KindCo Coercion+ -- :: e -> N++ | SubCo CoercionN -- Turns a ~N into a ~R+ -- :: N -> R++ deriving Data.Data++type CoercionN = Coercion -- always nominal+type CoercionR = Coercion -- always representational+type CoercionP = Coercion -- always phantom+type KindCoercion = CoercionN -- always nominal++{-+Note [Refl invariant]+~~~~~~~~~~~~~~~~~~~~~+Invariant 1:++Coercions have the following invariant+ Refl is always lifted as far as possible.++You might think that a consequencs is:+ Every identity coercions has Refl at the root++But that's not quite true because of coercion variables. Consider+ g where g :: Int~Int+ Left h where h :: Maybe Int ~ Maybe Int+etc. So the consequence is only true of coercions that+have no coercion variables.++Note [Coercion axioms applied to coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The reason coercion axioms can be applied to coercions and not just+types is to allow for better optimization. There are some cases where+we need to be able to "push transitivity inside" an axiom in order to+expose further opportunities for optimization.++For example, suppose we have++ C a : t[a] ~ F a+ g : b ~ c++and we want to optimize++ sym (C b) ; t[g] ; C c++which has the kind++ F b ~ F c++(stopping through t[b] and t[c] along the way).++We'd like to optimize this to just F g -- but how? The key is+that we need to allow axioms to be instantiated by *coercions*,+not just by types. Then we can (in certain cases) push+transitivity inside the axiom instantiations, and then react+opposite-polarity instantiations of the same axiom. In this+case, e.g., we match t[g] against the LHS of (C c)'s kind, to+obtain the substitution a |-> g (note this operation is sort+of the dual of lifting!) and hence end up with++ C g : t[b] ~ F c++which indeed has the same kind as t[g] ; C c.++Now we have++ sym (C b) ; C g++which can be optimized to F g.++Note [CoAxiom index]+~~~~~~~~~~~~~~~~~~~~+A CoAxiom has 1 or more branches. Each branch has contains a list+of the free type variables in that branch, the LHS type patterns,+and the RHS type for that branch. When we apply an axiom to a list+of coercions, we must choose which branch of the axiom we wish to+use, as the different branches may have different numbers of free+type variables. (The number of type patterns is always the same+among branches, but that doesn't quite concern us here.)++The Int in the AxiomInstCo constructor is the 0-indexed number+of the chosen branch.++Note [Forall coercions]+~~~~~~~~~~~~~~~~~~~~~~~+Constructing coercions between forall-types can be a bit tricky,+because the kinds of the bound tyvars can be different.++The typing rule is:+++ kind_co : k1 ~ k2+ tv1:k1 |- co : t1 ~ t2+ -------------------------------------------------------------------+ ForAllCo tv1 kind_co co : all tv1:k1. t1 ~+ all tv1:k2. (t2[tv1 |-> tv1 |> sym kind_co])++First, the TyVar stored in a ForAllCo is really an optimisation: this field+should be a Name, as its kind is redundant. Thinking of the field as a Name+is helpful in understanding what a ForAllCo means.++The idea is that kind_co gives the two kinds of the tyvar. See how, in the+conclusion, tv1 is assigned kind k1 on the left but kind k2 on the right.++Of course, a type variable can't have different kinds at the same time. So,+we arbitrarily prefer the first kind when using tv1 in the inner coercion+co, which shows that t1 equals t2.++The last wrinkle is that we need to fix the kinds in the conclusion. In+t2, tv1 is assumed to have kind k1, but it has kind k2 in the conclusion of+the rule. So we do a kind-fixing substitution, replacing (tv1:k1) with+(tv1:k2) |> sym kind_co. This substitution is slightly bizarre, because it+mentions the same name with different kinds, but it *is* well-kinded, noting+that `(tv1:k2) |> sym kind_co` has kind k1.++This all really would work storing just a Name in the ForAllCo. But we can't+add Names to, e.g., VarSets, and there generally is just an impedance mismatch+in a bunch of places. So we use tv1. When we need tv2, we can use+setTyVarKind.++Note [Coherence]+~~~~~~~~~~~~~~~~+The Coherence typing rule is thus:++ g1 : s ~ t s : k1 g2 : k1 ~ k2+ ------------------------------------+ CoherenceCo g1 g2 : (s |> g2) ~ t++While this looks (and is) unsymmetric, a combination of other coercion+combinators can make the symmetric version.++For role information, see Note [Roles and kind coercions].++Note [Predicate coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have+ g :: a~b+How can we coerce between types+ ([c]~a) => [a] -> c+and+ ([c]~b) => [b] -> c+where the equality predicate *itself* differs?++Answer: we simply treat (~) as an ordinary type constructor, so these+types really look like++ ((~) [c] a) -> [a] -> c+ ((~) [c] b) -> [b] -> c++So the coercion between the two is obviously++ ((~) [c] g) -> [g] -> c++Another way to see this to say that we simply collapse predicates to+their representation type (see Type.coreView and Type.predTypeRep).++This collapse is done by mkPredCo; there is no PredCo constructor+in Coercion. This is important because we need Nth to work on+predicates too:+ Nth 1 ((~) [c] g) = g+See Simplify.simplCoercionF, which generates such selections.++Note [Roles]+~~~~~~~~~~~~+Roles are a solution to the GeneralizedNewtypeDeriving problem, articulated+in Trac #1496. The full story is in docs/core-spec/core-spec.pdf. Also, see+http://ghc.haskell.org/trac/ghc/wiki/RolesImplementation++Here is one way to phrase the problem:++Given:+newtype Age = MkAge Int+type family F x+type instance F Age = Bool+type instance F Int = Char++This compiles down to:+axAge :: Age ~ Int+axF1 :: F Age ~ Bool+axF2 :: F Int ~ Char++Then, we can make:+(sym (axF1) ; F axAge ; axF2) :: Bool ~ Char++Yikes!++The solution is _roles_, as articulated in "Generative Type Abstraction and+Type-level Computation" (POPL 2010), available at+http://www.seas.upenn.edu/~sweirich/papers/popl163af-weirich.pdf++The specification for roles has evolved somewhat since that paper. For the+current full details, see the documentation in docs/core-spec. Here are some+highlights.++We label every equality with a notion of type equivalence, of which there are+three options: Nominal, Representational, and Phantom. A ground type is+nominally equivalent only with itself. A newtype (which is considered a ground+type in Haskell) is representationally equivalent to its representation.+Anything is "phantomly" equivalent to anything else. We use "N", "R", and "P"+to denote the equivalences.++The axioms above would be:+axAge :: Age ~R Int+axF1 :: F Age ~N Bool+axF2 :: F Age ~N Char++Then, because transitivity applies only to coercions proving the same notion+of equivalence, the above construction is impossible.++However, there is still an escape hatch: we know that any two types that are+nominally equivalent are representationally equivalent as well. This is what+the form SubCo proves -- it "demotes" a nominal equivalence into a+representational equivalence. So, it would seem the following is possible:++sub (sym axF1) ; F axAge ; sub axF2 :: Bool ~R Char -- WRONG++What saves us here is that the arguments to a type function F, lifted into a+coercion, *must* prove nominal equivalence. So, (F axAge) is ill-formed, and+we are safe.++Roles are attached to parameters to TyCons. When lifting a TyCon into a+coercion (through TyConAppCo), we need to ensure that the arguments to the+TyCon respect their roles. For example:++data T a b = MkT a (F b)++If we know that a1 ~R a2, then we know (T a1 b) ~R (T a2 b). But, if we know+that b1 ~R b2, we know nothing about (T a b1) and (T a b2)! This is because+the type function F branches on b's *name*, not representation. So, we say+that 'a' has role Representational and 'b' has role Nominal. The third role,+Phantom, is for parameters not used in the type's definition. Given the+following definition++data Q a = MkQ Int++the Phantom role allows us to say that (Q Bool) ~R (Q Char), because we+can construct the coercion Bool ~P Char (using UnivCo).++See the paper cited above for more examples and information.++Note [TyConAppCo roles]+~~~~~~~~~~~~~~~~~~~~~~~+The TyConAppCo constructor has a role parameter, indicating the role at+which the coercion proves equality. The choice of this parameter affects+the required roles of the arguments of the TyConAppCo. To help explain+it, assume the following definition:++ type instance F Int = Bool -- Axiom axF : F Int ~N Bool+ newtype Age = MkAge Int -- Axiom axAge : Age ~R Int+ data Foo a = MkFoo a -- Role on Foo's parameter is Representational++TyConAppCo Nominal Foo axF : Foo (F Int) ~N Foo Bool+ For (TyConAppCo Nominal) all arguments must have role Nominal. Why?+ So that Foo Age ~N Foo Int does *not* hold.++TyConAppCo Representational Foo (SubCo axF) : Foo (F Int) ~R Foo Bool+TyConAppCo Representational Foo axAge : Foo Age ~R Foo Int+ For (TyConAppCo Representational), all arguments must have the roles+ corresponding to the result of tyConRoles on the TyCon. This is the+ whole point of having roles on the TyCon to begin with. So, we can+ have Foo Age ~R Foo Int, if Foo's parameter has role R.++ If a Representational TyConAppCo is over-saturated (which is otherwise fine),+ the spill-over arguments must all be at Nominal. This corresponds to the+ behavior for AppCo.++TyConAppCo Phantom Foo (UnivCo Phantom Int Bool) : Foo Int ~P Foo Bool+ All arguments must have role Phantom. This one isn't strictly+ necessary for soundness, but this choice removes ambiguity.++The rules here dictate the roles of the parameters to mkTyConAppCo+(should be checked by Lint).++Note [NthCo and newtypes]+~~~~~~~~~~~~~~~~~~~~~~~~~+Suppose we have++ newtype N a = MkN Int+ type role N representational++This yields axiom++ NTCo:N :: forall a. N a ~R Int++We can then build++ co :: forall a b. N a ~R N b+ co = NTCo:N a ; sym (NTCo:N b)++for any `a` and `b`. Because of the role annotation on N, if we use+NthCo, we'll get out a representational coercion. That is:++ NthCo 0 co :: forall a b. a ~R b++Yikes! Clearly, this is terrible. The solution is simple: forbid+NthCo to be used on newtypes if the internal coercion is representational.++This is not just some corner case discovered by a segfault somewhere;+it was discovered in the proof of soundness of roles and described+in the "Safe Coercions" paper (ICFP '14).++Note [InstCo roles]+~~~~~~~~~~~~~~~~~~~+Here is (essentially) the typing rule for InstCo:++g :: (forall a. t1) ~r (forall a. t2)+w :: s1 ~N s2+------------------------------- InstCo+InstCo g w :: (t1 [a |-> s1]) ~r (t2 [a |-> s2])++Note that the Coercion w *must* be nominal. This is necessary+because the variable a might be used in a "nominal position"+(that is, a place where role inference would require a nominal+role) in t1 or t2. If we allowed w to be representational, we+could get bogus equalities.++A more nuanced treatment might be able to relax this condition+somewhat, by checking if t1 and/or t2 use their bound variables+in nominal ways. If not, having w be representational is OK.+++%************************************************************************+%* *+ UnivCoProvenance+%* *+%************************************************************************++A UnivCo is a coercion whose proof does not directly express its role+and kind (indeed for some UnivCos, like UnsafeCoerceProv, there /is/+no proof).++The different kinds of UnivCo are described by UnivCoProvenance. Really+each is entirely separate, but they all share the need to represent their+role and kind, which is done in the UnivCo constructor.++-}++-- | For simplicity, we have just one UnivCo that represents a coercion from+-- some type to some other type, with (in general) no restrictions on the+-- type. The UnivCoProvenance specifies more exactly what the coercion really+-- is and why a program should (or shouldn't!) trust the coercion.+-- It is reasonable to consider each constructor of 'UnivCoProvenance'+-- as a totally independent coercion form; their only commonality is+-- that they don't tell you what types they coercion between. (That info+-- is in the 'UnivCo' constructor of 'Coercion'.+data UnivCoProvenance+ = UnsafeCoerceProv -- ^ From @unsafeCoerce#@. These are unsound.++ | PhantomProv KindCoercion -- ^ See Note [Phantom coercions]. Only in Phantom+ -- roled coercions++ | ProofIrrelProv KindCoercion -- ^ From the fact that any two coercions are+ -- considered equivalent. See Note [ProofIrrelProv].+ -- Can be used in Nominal or Representational coercions++ | PluginProv String -- ^ From a plugin, which asserts that this coercion+ -- is sound. The string is for the use of the plugin.++ | HoleProv CoercionHole -- ^ See Note [Coercion holes]+ deriving Data.Data++instance Outputable UnivCoProvenance where+ ppr UnsafeCoerceProv = text "(unsafeCoerce#)"+ ppr (PhantomProv _) = text "(phantom)"+ ppr (ProofIrrelProv _) = text "(proof irrel.)"+ ppr (PluginProv str) = parens (text "plugin" <+> brackets (text str))+ ppr (HoleProv hole) = parens (text "hole" <> ppr hole)++-- | A coercion to be filled in by the type-checker. See Note [Coercion holes]+data CoercionHole+ = CoercionHole { chUnique :: Unique -- ^ used only for debugging+ , chCoercion :: IORef (Maybe Coercion)+ }++instance Data.Data CoercionHole where+ -- don't traverse?+ toConstr _ = abstractConstr "CoercionHole"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "CoercionHole"++instance Outputable CoercionHole where+ ppr (CoercionHole u _) = braces (ppr u)+++{- Note [Phantom coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider+ data T a = T1 | T2+Then we have+ T s ~R T t+for any old s,t. The witness for this is (TyConAppCo T Rep co),+where (co :: s ~P t) is a phantom coercion built with PhantomProv.+The role of the UnivCo is always Phantom. The Coercion stored is the+(nominal) kind coercion between the types+ kind(s) ~N kind (t)++Note [Coercion holes]+~~~~~~~~~~~~~~~~~~~~~~~~+During typechecking, constraint solving for type classes works by+ - Generate an evidence Id, d7 :: Num a+ - Wrap it in a Wanted constraint, [W] d7 :: Num a+ - Use the evidence Id where the evidence is needed+ - Solve the constraint later+ - When solved, add an enclosing let-binding let d7 = .... in ....+ which actually binds d7 to the (Num a) evidence++For equality constraints we use a different strategy. See Note [The+equality types story] in TysPrim for background on equality constraints.+ - For boxed equality constraints, (t1 ~N t2) and (t1 ~R t2), it's just+ like type classes above. (Indeed, boxed equality constraints *are* classes.)+ - But for /unboxed/ equality constraints (t1 ~R# t2) and (t1 ~N# t2)+ we use a different plan++For unboxed equalities:+ - Generate a CoercionHole, a mutable variable just like a unification+ variable+ - Wrap the CoercionHole in a Wanted constraint; see TcRnTypes.TcEvDest+ - Use the CoercionHole in a Coercion, via HoleProv+ - Solve the constraint later+ - When solved, fill in the CoercionHole by side effect, instead of+ doing the let-binding thing++The main reason for all this is that there may be no good place to let-bind+the evidence for unboxed equalities:+ - We emit constraints for kind coercions, to be used+ to cast a type's kind. These coercions then must be used in types. Because+ they might appear in a top-level type, there is no place to bind these+ (unlifted) coercions in the usual way.++ - A coercion for (forall a. t1) ~ forall a. t2) will look like+ forall a. (coercion for t1~t2)+ But the coercion for (t1~t2) may mention 'a', and we don't have let-bindings+ within coercions. We could add them, but coercion holes are easier.++Other notes about HoleCo:++ * INVARIANT: CoercionHole and HoleProv are used only during type checking,+ and should never appear in Core. Just like unification variables; a Type+ can contain a TcTyVar, but only during type checking. If, one day, we+ use type-level information to separate out forms that can appear during+ type-checking vs forms that can appear in core proper, holes in Core will+ be ruled out.++ * The Unique carried with a coercion hole is used solely for debugging.++ * Coercion holes can be compared for equality only like other coercions:+ only by looking at the types coerced.++ * We don't use holes for other evidence because other evidence wants to+ be /shared/. But coercions are entirely erased, so there's little+ benefit to sharing.++Note [ProofIrrelProv]+~~~~~~~~~~~~~~~~~~~~~+A ProofIrrelProv is a coercion between coercions. For example:++ data G a where+ MkG :: G Bool++In core, we get++ G :: * -> *+ MkG :: forall (a :: *). (a ~ Bool) -> G a++Now, consider 'MkG -- that is, MkG used in a type -- and suppose we want+a proof that ('MkG co1 a1) ~ ('MkG co2 a2). This will have to be++ TyConAppCo Nominal MkG [co3, co4]+ where+ co3 :: co1 ~ co2+ co4 :: a1 ~ a2++Note that+ co1 :: a1 ~ Bool+ co2 :: a2 ~ Bool++Here,+ co3 = UnivCo (ProofIrrelProv co5) Nominal (CoercionTy co1) (CoercionTy co2)+ where+ co5 :: (a1 ~ Bool) ~ (a2 ~ Bool)+ co5 = TyConAppCo Nominal (~) [<*>, <*>, co4, <Bool>]+++%************************************************************************+%* *+ Free variables of types and coercions+%* *+%************************************************************************+-}++{- Note [Free variables of types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The family of functions tyCoVarsOfType, tyCoVarsOfTypes etc, returns+a VarSet that is closed over the types of its variables. More precisely,+ if S = tyCoVarsOfType( t )+ and (a:k) is in S+ then tyCoVarsOftype( k ) is a subset of S++Example: The tyCoVars of this ((a:* -> k) Int) is {a, k}.++We could /not/ close over the kinds of the variable occurrences, and+instead do so at call sites, but it seems that we always want to do+so, so it's easiest to do it here.+-}+++-- | Returns free variables of a type, including kind variables as+-- a non-deterministic set. For type synonyms it does /not/ expand the+-- synonym.+tyCoVarsOfType :: Type -> TyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfType ty = fvVarSet $ tyCoFVsOfType ty++-- | `tyVarsOfType` that returns free variables of a type in a deterministic+-- set. For explanation of why using `VarSet` is not deterministic see+-- Note [Deterministic FV] in FV.+tyCoVarsOfTypeDSet :: Type -> DTyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfTypeDSet ty = fvDVarSet $ tyCoFVsOfType ty++-- | `tyVarsOfType` that returns free variables of a type in deterministic+-- order. For explanation of why using `VarSet` is not deterministic see+-- Note [Deterministic FV] in FV.+tyCoVarsOfTypeList :: Type -> [TyCoVar]+-- See Note [Free variables of types]+tyCoVarsOfTypeList ty = fvVarList $ tyCoFVsOfType ty++-- | The worker for `tyVarsOfType` and `tyVarsOfTypeList`.+-- The previous implementation used `unionVarSet` which is O(n+m) and can+-- make the function quadratic.+-- It's exported, so that it can be composed with+-- other functions that compute free variables.+-- See Note [FV naming conventions] in FV.+--+-- Eta-expanded because that makes it run faster (apparently)+-- See Note [FV eta expansion] in FV for explanation.+tyCoFVsOfType :: Type -> FV+-- See Note [Free variables of types]+tyCoFVsOfType (TyVarTy v) a b c = (unitFV v `unionFV` tyCoFVsOfType (tyVarKind v)) a b c+tyCoFVsOfType (TyConApp _ tys) a b c = tyCoFVsOfTypes tys a b c+tyCoFVsOfType (LitTy {}) a b c = emptyFV a b c+tyCoFVsOfType (AppTy fun arg) a b c = (tyCoFVsOfType fun `unionFV` tyCoFVsOfType arg) a b c+tyCoFVsOfType (FunTy arg res) a b c = (tyCoFVsOfType arg `unionFV` tyCoFVsOfType res) a b c+tyCoFVsOfType (ForAllTy bndr ty) a b c = tyCoFVsBndr bndr (tyCoFVsOfType ty) a b c+tyCoFVsOfType (CastTy ty co) a b c = (tyCoFVsOfType ty `unionFV` tyCoFVsOfCo co) a b c+tyCoFVsOfType (CoercionTy co) a b c = tyCoFVsOfCo co a b c++tyCoFVsBndr :: TyVarBinder -> FV -> FV+-- Free vars of (forall b. <thing with fvs>)+tyCoFVsBndr (TvBndr tv _) fvs = (delFV tv fvs)+ `unionFV` tyCoFVsOfType (tyVarKind tv)++-- | Returns free variables of types, including kind variables as+-- a non-deterministic set. For type synonyms it does /not/ expand the+-- synonym.+tyCoVarsOfTypes :: [Type] -> TyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfTypes tys = fvVarSet $ tyCoFVsOfTypes tys++-- | Returns free variables of types, including kind variables as+-- a non-deterministic set. For type synonyms it does /not/ expand the+-- synonym.+tyCoVarsOfTypesSet :: TyVarEnv Type -> TyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfTypesSet tys = fvVarSet $ tyCoFVsOfTypes $ nonDetEltsUFM tys+ -- It's OK to use nonDetEltsUFM here because we immediately forget the+ -- ordering by returning a set++-- | Returns free variables of types, including kind variables as+-- a deterministic set. For type synonyms it does /not/ expand the+-- synonym.+tyCoVarsOfTypesDSet :: [Type] -> DTyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfTypesDSet tys = fvDVarSet $ tyCoFVsOfTypes tys++-- | Returns free variables of types, including kind variables as+-- a deterministically ordered list. For type synonyms it does /not/ expand the+-- synonym.+tyCoVarsOfTypesList :: [Type] -> [TyCoVar]+-- See Note [Free variables of types]+tyCoVarsOfTypesList tys = fvVarList $ tyCoFVsOfTypes tys++tyCoFVsOfTypes :: [Type] -> FV+-- See Note [Free variables of types]+tyCoFVsOfTypes (ty:tys) fv_cand in_scope acc = (tyCoFVsOfType ty `unionFV` tyCoFVsOfTypes tys) fv_cand in_scope acc+tyCoFVsOfTypes [] fv_cand in_scope acc = emptyFV fv_cand in_scope acc++tyCoVarsOfCo :: Coercion -> TyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfCo co = fvVarSet $ tyCoFVsOfCo co++-- | Get a deterministic set of the vars free in a coercion+tyCoVarsOfCoDSet :: Coercion -> DTyCoVarSet+-- See Note [Free variables of types]+tyCoVarsOfCoDSet co = fvDVarSet $ tyCoFVsOfCo co++tyCoVarsOfCoList :: Coercion -> [TyCoVar]+-- See Note [Free variables of types]+tyCoVarsOfCoList co = fvVarList $ tyCoFVsOfCo co++tyCoFVsOfCo :: Coercion -> FV+-- Extracts type and coercion variables from a coercion+-- See Note [Free variables of types]+tyCoFVsOfCo (Refl _ ty) fv_cand in_scope acc = tyCoFVsOfType ty fv_cand in_scope acc+tyCoFVsOfCo (TyConAppCo _ _ cos) fv_cand in_scope acc = tyCoFVsOfCos cos fv_cand in_scope acc+tyCoFVsOfCo (AppCo co arg) fv_cand in_scope acc+ = (tyCoFVsOfCo co `unionFV` tyCoFVsOfCo arg) fv_cand in_scope acc+tyCoFVsOfCo (ForAllCo tv kind_co co) fv_cand in_scope acc+ = (delFV tv (tyCoFVsOfCo co) `unionFV` tyCoFVsOfCo kind_co) fv_cand in_scope acc+tyCoFVsOfCo (FunCo _ co1 co2) fv_cand in_scope acc+ = (tyCoFVsOfCo co1 `unionFV` tyCoFVsOfCo co2) fv_cand in_scope acc+tyCoFVsOfCo (CoVarCo v) fv_cand in_scope acc+ = (unitFV v `unionFV` tyCoFVsOfType (varType v)) fv_cand in_scope acc+tyCoFVsOfCo (AxiomInstCo _ _ cos) fv_cand in_scope acc = tyCoFVsOfCos cos fv_cand in_scope acc+tyCoFVsOfCo (UnivCo p _ t1 t2) fv_cand in_scope acc+ = (tyCoFVsOfProv p `unionFV` tyCoFVsOfType t1+ `unionFV` tyCoFVsOfType t2) fv_cand in_scope acc+tyCoFVsOfCo (SymCo co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfCo (TransCo co1 co2) fv_cand in_scope acc = (tyCoFVsOfCo co1 `unionFV` tyCoFVsOfCo co2) fv_cand in_scope acc+tyCoFVsOfCo (NthCo _ co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfCo (LRCo _ co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfCo (InstCo co arg) fv_cand in_scope acc = (tyCoFVsOfCo co `unionFV` tyCoFVsOfCo arg) fv_cand in_scope acc+tyCoFVsOfCo (CoherenceCo c1 c2) fv_cand in_scope acc = (tyCoFVsOfCo c1 `unionFV` tyCoFVsOfCo c2) fv_cand in_scope acc+tyCoFVsOfCo (KindCo co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfCo (SubCo co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfCo (AxiomRuleCo _ cs) fv_cand in_scope acc = tyCoFVsOfCos cs fv_cand in_scope acc++tyCoVarsOfProv :: UnivCoProvenance -> TyCoVarSet+tyCoVarsOfProv prov = fvVarSet $ tyCoFVsOfProv prov++tyCoFVsOfProv :: UnivCoProvenance -> FV+tyCoFVsOfProv UnsafeCoerceProv fv_cand in_scope acc = emptyFV fv_cand in_scope acc+tyCoFVsOfProv (PhantomProv co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfProv (ProofIrrelProv co) fv_cand in_scope acc = tyCoFVsOfCo co fv_cand in_scope acc+tyCoFVsOfProv (PluginProv _) fv_cand in_scope acc = emptyFV fv_cand in_scope acc+tyCoFVsOfProv (HoleProv _) fv_cand in_scope acc = emptyFV fv_cand in_scope acc++tyCoVarsOfCos :: [Coercion] -> TyCoVarSet+tyCoVarsOfCos cos = fvVarSet $ tyCoFVsOfCos cos++tyCoVarsOfCosSet :: CoVarEnv Coercion -> TyCoVarSet+tyCoVarsOfCosSet cos = fvVarSet $ tyCoFVsOfCos $ nonDetEltsUFM cos+ -- It's OK to use nonDetEltsUFM here because we immediately forget the+ -- ordering by returning a set++tyCoFVsOfCos :: [Coercion] -> FV+tyCoFVsOfCos [] fv_cand in_scope acc = emptyFV fv_cand in_scope acc+tyCoFVsOfCos (co:cos) fv_cand in_scope acc = (tyCoFVsOfCo co `unionFV` tyCoFVsOfCos cos) fv_cand in_scope acc++coVarsOfType :: Type -> CoVarSet+coVarsOfType (TyVarTy v) = coVarsOfType (tyVarKind v)+coVarsOfType (TyConApp _ tys) = coVarsOfTypes tys+coVarsOfType (LitTy {}) = emptyVarSet+coVarsOfType (AppTy fun arg) = coVarsOfType fun `unionVarSet` coVarsOfType arg+coVarsOfType (FunTy arg res) = coVarsOfType arg `unionVarSet` coVarsOfType res+coVarsOfType (ForAllTy (TvBndr tv _) ty)+ = (coVarsOfType ty `delVarSet` tv)+ `unionVarSet` coVarsOfType (tyVarKind tv)+coVarsOfType (CastTy ty co) = coVarsOfType ty `unionVarSet` coVarsOfCo co+coVarsOfType (CoercionTy co) = coVarsOfCo co++coVarsOfTypes :: [Type] -> TyCoVarSet+coVarsOfTypes tys = mapUnionVarSet coVarsOfType tys++coVarsOfCo :: Coercion -> CoVarSet+-- Extract *coercion* variables only. Tiresome to repeat the code, but easy.+coVarsOfCo (Refl _ ty) = coVarsOfType ty+coVarsOfCo (TyConAppCo _ _ args) = coVarsOfCos args+coVarsOfCo (AppCo co arg) = coVarsOfCo co `unionVarSet` coVarsOfCo arg+coVarsOfCo (ForAllCo tv kind_co co)+ = coVarsOfCo co `delVarSet` tv `unionVarSet` coVarsOfCo kind_co+coVarsOfCo (FunCo _ co1 co2) = coVarsOfCo co1 `unionVarSet` coVarsOfCo co2+coVarsOfCo (CoVarCo v) = unitVarSet v `unionVarSet` coVarsOfType (varType v)+coVarsOfCo (AxiomInstCo _ _ args) = coVarsOfCos args+coVarsOfCo (UnivCo p _ t1 t2) = coVarsOfProv p `unionVarSet` coVarsOfTypes [t1, t2]+coVarsOfCo (SymCo co) = coVarsOfCo co+coVarsOfCo (TransCo co1 co2) = coVarsOfCo co1 `unionVarSet` coVarsOfCo co2+coVarsOfCo (NthCo _ co) = coVarsOfCo co+coVarsOfCo (LRCo _ co) = coVarsOfCo co+coVarsOfCo (InstCo co arg) = coVarsOfCo co `unionVarSet` coVarsOfCo arg+coVarsOfCo (CoherenceCo c1 c2) = coVarsOfCos [c1, c2]+coVarsOfCo (KindCo co) = coVarsOfCo co+coVarsOfCo (SubCo co) = coVarsOfCo co+coVarsOfCo (AxiomRuleCo _ cs) = coVarsOfCos cs++coVarsOfProv :: UnivCoProvenance -> CoVarSet+coVarsOfProv UnsafeCoerceProv = emptyVarSet+coVarsOfProv (PhantomProv co) = coVarsOfCo co+coVarsOfProv (ProofIrrelProv co) = coVarsOfCo co+coVarsOfProv (PluginProv _) = emptyVarSet+coVarsOfProv (HoleProv _) = emptyVarSet++coVarsOfCos :: [Coercion] -> CoVarSet+coVarsOfCos cos = mapUnionVarSet coVarsOfCo cos++-- | Add the kind variables free in the kinds of the tyvars in the given set.+-- Returns a non-deterministic set.+closeOverKinds :: TyVarSet -> TyVarSet+closeOverKinds = fvVarSet . closeOverKindsFV . nonDetEltsUniqSet+ -- It's OK to use nonDetEltsUniqSet here because we immediately forget+ -- about the ordering by returning a set.++-- | Given a list of tyvars returns a deterministic FV computation that+-- returns the given tyvars with the kind variables free in the kinds of the+-- given tyvars.+closeOverKindsFV :: [TyVar] -> FV+closeOverKindsFV tvs =+ mapUnionFV (tyCoFVsOfType . tyVarKind) tvs `unionFV` mkFVs tvs++-- | Add the kind variables free in the kinds of the tyvars in the given set.+-- Returns a deterministically ordered list.+closeOverKindsList :: [TyVar] -> [TyVar]+closeOverKindsList tvs = fvVarList $ closeOverKindsFV tvs++-- | Add the kind variables free in the kinds of the tyvars in the given set.+-- Returns a deterministic set.+closeOverKindsDSet :: DTyVarSet -> DTyVarSet+closeOverKindsDSet = fvDVarSet . closeOverKindsFV . dVarSetElems++-- | Returns True if this type has no free variables. Should be the same as+-- isEmptyVarSet . tyCoVarsOfType, but faster in the non-forall case.+noFreeVarsOfType :: Type -> Bool+noFreeVarsOfType (TyVarTy _) = False+noFreeVarsOfType (AppTy t1 t2) = noFreeVarsOfType t1 && noFreeVarsOfType t2+noFreeVarsOfType (TyConApp _ tys) = all noFreeVarsOfType tys+noFreeVarsOfType ty@(ForAllTy {}) = isEmptyVarSet (tyCoVarsOfType ty)+noFreeVarsOfType (FunTy t1 t2) = noFreeVarsOfType t1 && noFreeVarsOfType t2+noFreeVarsOfType (LitTy _) = True+noFreeVarsOfType (CastTy ty co) = noFreeVarsOfType ty && noFreeVarsOfCo co+noFreeVarsOfType (CoercionTy co) = noFreeVarsOfCo co++-- | Returns True if this coercion has no free variables. Should be the same as+-- isEmptyVarSet . tyCoVarsOfCo, but faster in the non-forall case.+noFreeVarsOfCo :: Coercion -> Bool+noFreeVarsOfCo (Refl _ ty) = noFreeVarsOfType ty+noFreeVarsOfCo (TyConAppCo _ _ args) = all noFreeVarsOfCo args+noFreeVarsOfCo (AppCo c1 c2) = noFreeVarsOfCo c1 && noFreeVarsOfCo c2+noFreeVarsOfCo co@(ForAllCo {}) = isEmptyVarSet (tyCoVarsOfCo co)+noFreeVarsOfCo (FunCo _ c1 c2) = noFreeVarsOfCo c1 && noFreeVarsOfCo c2+noFreeVarsOfCo (CoVarCo _) = False+noFreeVarsOfCo (AxiomInstCo _ _ args) = all noFreeVarsOfCo args+noFreeVarsOfCo (UnivCo p _ t1 t2) = noFreeVarsOfProv p &&+ noFreeVarsOfType t1 &&+ noFreeVarsOfType t2+noFreeVarsOfCo (SymCo co) = noFreeVarsOfCo co+noFreeVarsOfCo (TransCo co1 co2) = noFreeVarsOfCo co1 && noFreeVarsOfCo co2+noFreeVarsOfCo (NthCo _ co) = noFreeVarsOfCo co+noFreeVarsOfCo (LRCo _ co) = noFreeVarsOfCo co+noFreeVarsOfCo (InstCo co1 co2) = noFreeVarsOfCo co1 && noFreeVarsOfCo co2+noFreeVarsOfCo (CoherenceCo co1 co2) = noFreeVarsOfCo co1 && noFreeVarsOfCo co2+noFreeVarsOfCo (KindCo co) = noFreeVarsOfCo co+noFreeVarsOfCo (SubCo co) = noFreeVarsOfCo co+noFreeVarsOfCo (AxiomRuleCo _ cs) = all noFreeVarsOfCo cs++-- | Returns True if this UnivCoProv has no free variables. Should be the same as+-- isEmptyVarSet . tyCoVarsOfProv, but faster in the non-forall case.+noFreeVarsOfProv :: UnivCoProvenance -> Bool+noFreeVarsOfProv UnsafeCoerceProv = True+noFreeVarsOfProv (PhantomProv co) = noFreeVarsOfCo co+noFreeVarsOfProv (ProofIrrelProv co) = noFreeVarsOfCo co+noFreeVarsOfProv (PluginProv {}) = True+noFreeVarsOfProv (HoleProv {}) = True -- matches with coVarsOfProv, but I'm unsure++{-+%************************************************************************+%* *+ Substitutions+ Data type defined here to avoid unnecessary mutual recursion+%* *+%************************************************************************+-}++-- | Type & coercion substitution+--+-- #tcvsubst_invariant#+-- The following invariants must hold of a 'TCvSubst':+--+-- 1. The in-scope set is needed /only/ to+-- guide the generation of fresh uniques+--+-- 2. In particular, the /kind/ of the type variables in+-- the in-scope set is not relevant+--+-- 3. The substitution is only applied ONCE! This is because+-- in general such application will not reach a fixed point.+data TCvSubst+ = TCvSubst InScopeSet -- The in-scope type and kind variables+ TvSubstEnv -- Substitutes both type and kind variables+ CvSubstEnv -- Substitutes coercion variables+ -- See Note [Apply Once]+ -- and Note [Extending the TvSubstEnv]+ -- and Note [Substituting types and coercions]+ -- and Note [The substitution invariant]++-- | A substitution of 'Type's for 'TyVar's+-- and 'Kind's for 'KindVar's+type TvSubstEnv = TyVarEnv Type+ -- A TvSubstEnv is used both inside a TCvSubst (with the apply-once+ -- invariant discussed in Note [Apply Once]), and also independently+ -- in the middle of matching, and unification (see Types.Unify)+ -- So you have to look at the context to know if it's idempotent or+ -- apply-once or whatever++-- | A substitution of 'Coercion's for 'CoVar's+type CvSubstEnv = CoVarEnv Coercion++{-+Note [Apply Once]+~~~~~~~~~~~~~~~~~+We use TCvSubsts to instantiate things, and we might instantiate+ forall a b. ty+\with the types+ [a, b], or [b, a].+So the substitution might go [a->b, b->a]. A similar situation arises in Core+when we find a beta redex like+ (/\ a /\ b -> e) b a+Then we also end up with a substitution that permutes type variables. Other+variations happen to; for example [a -> (a, b)].++ ****************************************************+ *** So a TCvSubst must be applied precisely once ***+ ****************************************************++A TCvSubst is not idempotent, but, unlike the non-idempotent substitution+we use during unifications, it must not be repeatedly applied.++Note [Extending the TvSubstEnv]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+See #tcvsubst_invariant# for the invariants that must hold.++This invariant allows a short-cut when the subst envs are empty:+if the TvSubstEnv and CvSubstEnv are empty --- i.e. (isEmptyTCvSubst subst)+holds --- then (substTy subst ty) does nothing.++For example, consider:+ (/\a. /\b:(a~Int). ...b..) Int+We substitute Int for 'a'. The Unique of 'b' does not change, but+nevertheless we add 'b' to the TvSubstEnv, because b's kind does change++This invariant has several crucial consequences:++* In substTyVarBndr, we need extend the TvSubstEnv+ - if the unique has changed+ - or if the kind has changed++* In substTyVar, we do not need to consult the in-scope set;+ the TvSubstEnv is enough++* In substTy, substTheta, we can short-circuit when the TvSubstEnv is empty++Note [Substituting types and coercions]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Types and coercions are mutually recursive, and either may have variables+"belonging" to the other. Thus, every time we wish to substitute in a+type, we may also need to substitute in a coercion, and vice versa.+However, the constructor used to create type variables is distinct from+that of coercion variables, so we carry two VarEnvs in a TCvSubst. Note+that it would be possible to use the CoercionTy constructor to combine+these environments, but that seems like a false economy.++Note that the TvSubstEnv should *never* map a CoVar (built with the Id+constructor) and the CvSubstEnv should *never* map a TyVar. Furthermore,+the range of the TvSubstEnv should *never* include a type headed with+CoercionTy.++Note [The substitution invariant]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When calling (substTy subst ty) it should be the case that+the in-scope set in the substitution is a superset of both:++ * The free vars of the range of the substitution+ * The free vars of ty minus the domain of the substitution++If we want to substitute [a -> ty1, b -> ty2] I used to+think it was enough to generate an in-scope set that includes+fv(ty1,ty2). But that's not enough; we really should also take the+free vars of the type we are substituting into! Example:+ (forall b. (a,b,x)) [a -> List b]+Then if we use the in-scope set {b}, there is a danger we will rename+the forall'd variable to 'x' by mistake, getting this:+ (forall x. (List b, x, x))++Breaking this invariant caused the bug from #11371.+-}++emptyTvSubstEnv :: TvSubstEnv+emptyTvSubstEnv = emptyVarEnv++emptyCvSubstEnv :: CvSubstEnv+emptyCvSubstEnv = emptyVarEnv++composeTCvSubstEnv :: InScopeSet+ -> (TvSubstEnv, CvSubstEnv)+ -> (TvSubstEnv, CvSubstEnv)+ -> (TvSubstEnv, CvSubstEnv)+-- ^ @(compose env1 env2)(x)@ is @env1(env2(x))@; i.e. apply @env2@ then @env1@.+-- It assumes that both are idempotent.+-- Typically, @env1@ is the refinement to a base substitution @env2@+composeTCvSubstEnv in_scope (tenv1, cenv1) (tenv2, cenv2)+ = ( tenv1 `plusVarEnv` mapVarEnv (substTy subst1) tenv2+ , cenv1 `plusVarEnv` mapVarEnv (substCo subst1) cenv2 )+ -- First apply env1 to the range of env2+ -- Then combine the two, making sure that env1 loses if+ -- both bind the same variable; that's why env1 is the+ -- *left* argument to plusVarEnv, because the right arg wins+ where+ subst1 = TCvSubst in_scope tenv1 cenv1++-- | Composes two substitutions, applying the second one provided first,+-- like in function composition.+composeTCvSubst :: TCvSubst -> TCvSubst -> TCvSubst+composeTCvSubst (TCvSubst is1 tenv1 cenv1) (TCvSubst is2 tenv2 cenv2)+ = TCvSubst is3 tenv3 cenv3+ where+ is3 = is1 `unionInScope` is2+ (tenv3, cenv3) = composeTCvSubstEnv is3 (tenv1, cenv1) (tenv2, cenv2)++emptyTCvSubst :: TCvSubst+emptyTCvSubst = TCvSubst emptyInScopeSet emptyTvSubstEnv emptyCvSubstEnv++mkEmptyTCvSubst :: InScopeSet -> TCvSubst+mkEmptyTCvSubst is = TCvSubst is emptyTvSubstEnv emptyCvSubstEnv++isEmptyTCvSubst :: TCvSubst -> Bool+ -- See Note [Extending the TvSubstEnv]+isEmptyTCvSubst (TCvSubst _ tenv cenv) = isEmptyVarEnv tenv && isEmptyVarEnv cenv++mkTCvSubst :: InScopeSet -> (TvSubstEnv, CvSubstEnv) -> TCvSubst+mkTCvSubst in_scope (tenv, cenv) = TCvSubst in_scope tenv cenv++mkTvSubst :: InScopeSet -> TvSubstEnv -> TCvSubst+-- ^ Make a TCvSubst with specified tyvar subst and empty covar subst+mkTvSubst in_scope tenv = TCvSubst in_scope tenv emptyCvSubstEnv++getTvSubstEnv :: TCvSubst -> TvSubstEnv+getTvSubstEnv (TCvSubst _ env _) = env++getCvSubstEnv :: TCvSubst -> CvSubstEnv+getCvSubstEnv (TCvSubst _ _ env) = env++getTCvInScope :: TCvSubst -> InScopeSet+getTCvInScope (TCvSubst in_scope _ _) = in_scope++-- | Returns the free variables of the types in the range of a substitution as+-- a non-deterministic set.+getTCvSubstRangeFVs :: TCvSubst -> VarSet+getTCvSubstRangeFVs (TCvSubst _ tenv cenv)+ = unionVarSet tenvFVs cenvFVs+ where+ tenvFVs = tyCoVarsOfTypesSet tenv+ cenvFVs = tyCoVarsOfCosSet cenv++isInScope :: Var -> TCvSubst -> Bool+isInScope v (TCvSubst in_scope _ _) = v `elemInScopeSet` in_scope++notElemTCvSubst :: Var -> TCvSubst -> Bool+notElemTCvSubst v (TCvSubst _ tenv cenv)+ | isTyVar v+ = not (v `elemVarEnv` tenv)+ | otherwise+ = not (v `elemVarEnv` cenv)++setTvSubstEnv :: TCvSubst -> TvSubstEnv -> TCvSubst+setTvSubstEnv (TCvSubst in_scope _ cenv) tenv = TCvSubst in_scope tenv cenv++setCvSubstEnv :: TCvSubst -> CvSubstEnv -> TCvSubst+setCvSubstEnv (TCvSubst in_scope tenv _) cenv = TCvSubst in_scope tenv cenv++zapTCvSubst :: TCvSubst -> TCvSubst+zapTCvSubst (TCvSubst in_scope _ _) = TCvSubst in_scope emptyVarEnv emptyVarEnv++extendTCvInScope :: TCvSubst -> Var -> TCvSubst+extendTCvInScope (TCvSubst in_scope tenv cenv) var+ = TCvSubst (extendInScopeSet in_scope var) tenv cenv++extendTCvInScopeList :: TCvSubst -> [Var] -> TCvSubst+extendTCvInScopeList (TCvSubst in_scope tenv cenv) vars+ = TCvSubst (extendInScopeSetList in_scope vars) tenv cenv++extendTCvInScopeSet :: TCvSubst -> VarSet -> TCvSubst+extendTCvInScopeSet (TCvSubst in_scope tenv cenv) vars+ = TCvSubst (extendInScopeSetSet in_scope vars) tenv cenv++extendTCvSubst :: TCvSubst -> TyCoVar -> Type -> TCvSubst+extendTCvSubst subst v ty+ | isTyVar v+ = extendTvSubst subst v ty+ | CoercionTy co <- ty+ = extendCvSubst subst v co+ | otherwise+ = pprPanic "extendTCvSubst" (ppr v <+> text "|->" <+> ppr ty)++extendTvSubst :: TCvSubst -> TyVar -> Type -> TCvSubst+extendTvSubst (TCvSubst in_scope tenv cenv) tv ty+ = TCvSubst in_scope (extendVarEnv tenv tv ty) cenv++extendTvSubstBinder :: TCvSubst -> TyBinder -> Type -> TCvSubst+extendTvSubstBinder subst (Named bndr) ty+ = extendTvSubst subst (binderVar bndr) ty+extendTvSubstBinder subst (Anon _) _+ = subst++extendTvSubstWithClone :: TCvSubst -> TyVar -> TyVar -> TCvSubst+-- Adds a new tv -> tv mapping, /and/ extends the in-scope set+extendTvSubstWithClone (TCvSubst in_scope tenv cenv) tv tv'+ = TCvSubst (extendInScopeSetSet in_scope new_in_scope)+ (extendVarEnv tenv tv (mkTyVarTy tv'))+ cenv+ where+ new_in_scope = tyCoVarsOfType (tyVarKind tv') `extendVarSet` tv'++extendCvSubst :: TCvSubst -> CoVar -> Coercion -> TCvSubst+extendCvSubst (TCvSubst in_scope tenv cenv) v co+ = TCvSubst in_scope tenv (extendVarEnv cenv v co)++extendCvSubstWithClone :: TCvSubst -> CoVar -> CoVar -> TCvSubst+extendCvSubstWithClone (TCvSubst in_scope tenv cenv) cv cv'+ = TCvSubst (extendInScopeSetSet in_scope new_in_scope)+ tenv+ (extendVarEnv cenv cv (mkCoVarCo cv'))+ where+ new_in_scope = tyCoVarsOfType (varType cv') `extendVarSet` cv'++extendTvSubstAndInScope :: TCvSubst -> TyVar -> Type -> TCvSubst+-- Also extends the in-scope set+extendTvSubstAndInScope (TCvSubst in_scope tenv cenv) tv ty+ = TCvSubst (in_scope `extendInScopeSetSet` tyCoVarsOfType ty)+ (extendVarEnv tenv tv ty)+ cenv++extendTvSubstList :: TCvSubst -> [Var] -> [Type] -> TCvSubst+extendTvSubstList subst tvs tys+ = foldl2 extendTvSubst subst tvs tys++unionTCvSubst :: TCvSubst -> TCvSubst -> TCvSubst+-- Works when the ranges are disjoint+unionTCvSubst (TCvSubst in_scope1 tenv1 cenv1) (TCvSubst in_scope2 tenv2 cenv2)+ = ASSERT( not (tenv1 `intersectsVarEnv` tenv2)+ && not (cenv1 `intersectsVarEnv` cenv2) )+ TCvSubst (in_scope1 `unionInScope` in_scope2)+ (tenv1 `plusVarEnv` tenv2)+ (cenv1 `plusVarEnv` cenv2)++-- mkTvSubstPrs and zipTvSubst generate the in-scope set from+-- the types given; but it's just a thunk so with a bit of luck+-- it'll never be evaluated++-- | Generates an in-scope set from the free variables in a list of types+-- and a list of coercions+mkTyCoInScopeSet :: [Type] -> [Coercion] -> InScopeSet+mkTyCoInScopeSet tys cos+ = mkInScopeSet (tyCoVarsOfTypes tys `unionVarSet` tyCoVarsOfCos cos)++-- | Generates the in-scope set for the 'TCvSubst' from the types in the incoming+-- environment. No CoVars, please!+zipTvSubst :: [TyVar] -> [Type] -> TCvSubst+zipTvSubst tvs tys+ | debugIsOn+ , not (all isTyVar tvs) || length tvs /= length tys+ = pprTrace "zipTvSubst" (ppr tvs $$ ppr tys) emptyTCvSubst+ | otherwise+ = mkTvSubst (mkInScopeSet (tyCoVarsOfTypes tys)) tenv+ where+ tenv = zipTyEnv tvs tys++-- | Generates the in-scope set for the 'TCvSubst' from the types in the incoming+-- environment. No TyVars, please!+zipCvSubst :: [CoVar] -> [Coercion] -> TCvSubst+zipCvSubst cvs cos+ | debugIsOn+ , not (all isCoVar cvs) || length cvs /= length cos+ = pprTrace "zipCvSubst" (ppr cvs $$ ppr cos) emptyTCvSubst+ | otherwise+ = TCvSubst (mkInScopeSet (tyCoVarsOfCos cos)) emptyTvSubstEnv cenv+ where+ cenv = zipCoEnv cvs cos++-- | Generates the in-scope set for the 'TCvSubst' from the types in the+-- incoming environment. No CoVars, please!+mkTvSubstPrs :: [(TyVar, Type)] -> TCvSubst+mkTvSubstPrs prs =+ ASSERT2( onlyTyVarsAndNoCoercionTy, text "prs" <+> ppr prs )+ mkTvSubst in_scope tenv+ where tenv = mkVarEnv prs+ in_scope = mkInScopeSet $ tyCoVarsOfTypes $ map snd prs+ onlyTyVarsAndNoCoercionTy =+ and [ isTyVar tv && not (isCoercionTy ty)+ | (tv, ty) <- prs ]++zipTyEnv :: [TyVar] -> [Type] -> TvSubstEnv+zipTyEnv tyvars tys+ = ASSERT( all (not . isCoercionTy) tys )+ mkVarEnv (zipEqual "zipTyEnv" tyvars tys)+ -- There used to be a special case for when+ -- ty == TyVarTy tv+ -- (a not-uncommon case) in which case the substitution was dropped.+ -- But the type-tidier changes the print-name of a type variable without+ -- changing the unique, and that led to a bug. Why? Pre-tidying, we had+ -- a type {Foo t}, where Foo is a one-method class. So Foo is really a newtype.+ -- And it happened that t was the type variable of the class. Post-tiding,+ -- it got turned into {Foo t2}. The ext-core printer expanded this using+ -- sourceTypeRep, but that said "Oh, t == t2" because they have the same unique,+ -- and so generated a rep type mentioning t not t2.+ --+ -- Simplest fix is to nuke the "optimisation"++zipCoEnv :: [CoVar] -> [Coercion] -> CvSubstEnv+zipCoEnv cvs cos = mkVarEnv (zipEqual "zipCoEnv" cvs cos)++instance Outputable TCvSubst where+ ppr (TCvSubst ins tenv cenv)+ = brackets $ sep[ text "TCvSubst",+ nest 2 (text "In scope:" <+> ppr ins),+ nest 2 (text "Type env:" <+> ppr tenv),+ nest 2 (text "Co env:" <+> ppr cenv) ]++{-+%************************************************************************+%* *+ Performing type or kind substitutions+%* *+%************************************************************************++Note [Sym and ForAllCo]+~~~~~~~~~~~~~~~~~~~~~~~+In OptCoercion, we try to push "sym" out to the leaves of a coercion. But,+how do we push sym into a ForAllCo? It's a little ugly.++Here is the typing rule:++h : k1 ~# k2+(tv : k1) |- g : ty1 ~# ty2+----------------------------+ForAllCo tv h g : (ForAllTy (tv : k1) ty1) ~#+ (ForAllTy (tv : k2) (ty2[tv |-> tv |> sym h]))++Here is what we want:++ForAllCo tv h' g' : (ForAllTy (tv : k2) (ty2[tv |-> tv |> sym h])) ~#+ (ForAllTy (tv : k1) ty1)+++Because the kinds of the type variables to the right of the colon are the kinds+coerced by h', we know (h' : k2 ~# k1). Thus, (h' = sym h).++Now, we can rewrite ty1 to be (ty1[tv |-> tv |> sym h' |> h']). We thus want++ForAllCo tv h' g' :+ (ForAllTy (tv : k2) (ty2[tv |-> tv |> h'])) ~#+ (ForAllTy (tv : k1) (ty1[tv |-> tv |> h'][tv |-> tv |> sym h']))++We thus see that we want++g' : ty2[tv |-> tv |> h'] ~# ty1[tv |-> tv |> h']++and thus g' = sym (g[tv |-> tv |> h']).++Putting it all together, we get this:++sym (ForAllCo tv h g)+==>+ForAllCo tv (sym h) (sym g[tv |-> tv |> sym h])++-}++-- | Type substitution, see 'zipTvSubst'+substTyWith :: HasCallStack => [TyVar] -> [Type] -> Type -> Type+-- Works only if the domain of the substitution is a+-- superset of the type being substituted into+substTyWith tvs tys = ASSERT( length tvs == length tys )+ substTy (zipTvSubst tvs tys)++-- | Type substitution, see 'zipTvSubst'. Disables sanity checks.+-- The problems that the sanity checks in substTy catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substTyUnchecked to+-- substTy and remove this function. Please don't use in new code.+substTyWithUnchecked :: [TyVar] -> [Type] -> Type -> Type+substTyWithUnchecked tvs tys+ = ASSERT( length tvs == length tys )+ substTyUnchecked (zipTvSubst tvs tys)++-- | Substitute tyvars within a type using a known 'InScopeSet'.+-- Pre-condition: the 'in_scope' set should satisfy Note [The substitution+-- invariant]; specifically it should include the free vars of 'tys',+-- and of 'ty' minus the domain of the subst.+substTyWithInScope :: InScopeSet -> [TyVar] -> [Type] -> Type -> Type+substTyWithInScope in_scope tvs tys ty =+ ASSERT( length tvs == length tys )+ substTy (mkTvSubst in_scope tenv) ty+ where tenv = zipTyEnv tvs tys++-- | Coercion substitution, see 'zipTvSubst'+substCoWith :: HasCallStack => [TyVar] -> [Type] -> Coercion -> Coercion+substCoWith tvs tys = ASSERT( length tvs == length tys )+ substCo (zipTvSubst tvs tys)++-- | Coercion substitution, see 'zipTvSubst'. Disables sanity checks.+-- The problems that the sanity checks in substCo catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substCoUnchecked to+-- substCo and remove this function. Please don't use in new code.+substCoWithUnchecked :: [TyVar] -> [Type] -> Coercion -> Coercion+substCoWithUnchecked tvs tys+ = ASSERT( length tvs == length tys )+ substCoUnchecked (zipTvSubst tvs tys)++++-- | Substitute covars within a type+substTyWithCoVars :: [CoVar] -> [Coercion] -> Type -> Type+substTyWithCoVars cvs cos = substTy (zipCvSubst cvs cos)++-- | Type substitution, see 'zipTvSubst'+substTysWith :: [TyVar] -> [Type] -> [Type] -> [Type]+substTysWith tvs tys = ASSERT( length tvs == length tys )+ substTys (zipTvSubst tvs tys)++-- | Type substitution, see 'zipTvSubst'+substTysWithCoVars :: [CoVar] -> [Coercion] -> [Type] -> [Type]+substTysWithCoVars cvs cos = ASSERT( length cvs == length cos )+ substTys (zipCvSubst cvs cos)++-- | Substitute within a 'Type' after adding the free variables of the type+-- to the in-scope set. This is useful for the case when the free variables+-- aren't already in the in-scope set or easily available.+-- See also Note [The substitution invariant].+substTyAddInScope :: TCvSubst -> Type -> Type+substTyAddInScope subst ty =+ substTy (extendTCvInScopeSet subst $ tyCoVarsOfType ty) ty++-- | When calling `substTy` it should be the case that the in-scope set in+-- the substitution is a superset of the free vars of the range of the+-- substitution.+-- See also Note [The substitution invariant].+isValidTCvSubst :: TCvSubst -> Bool+isValidTCvSubst (TCvSubst in_scope tenv cenv) =+ (tenvFVs `varSetInScope` in_scope) &&+ (cenvFVs `varSetInScope` in_scope)+ where+ tenvFVs = tyCoVarsOfTypesSet tenv+ cenvFVs = tyCoVarsOfCosSet cenv++-- | This checks if the substitution satisfies the invariant from+-- Note [The substitution invariant].+checkValidSubst :: HasCallStack => TCvSubst -> [Type] -> [Coercion] -> a -> a+checkValidSubst subst@(TCvSubst in_scope tenv cenv) tys cos a+ = ASSERT2( isValidTCvSubst subst,+ text "in_scope" <+> ppr in_scope $$+ text "tenv" <+> ppr tenv $$+ text "tenvFVs"+ <+> ppr (tyCoVarsOfTypesSet tenv) $$+ text "cenv" <+> ppr cenv $$+ text "cenvFVs"+ <+> ppr (tyCoVarsOfCosSet cenv) $$+ text "tys" <+> ppr tys $$+ text "cos" <+> ppr cos )+ ASSERT2( tysCosFVsInScope,+ text "in_scope" <+> ppr in_scope $$+ text "tenv" <+> ppr tenv $$+ text "cenv" <+> ppr cenv $$+ text "tys" <+> ppr tys $$+ text "cos" <+> ppr cos $$+ text "needInScope" <+> ppr needInScope )+ a+ where+ substDomain = nonDetKeysUFM tenv ++ nonDetKeysUFM cenv+ -- It's OK to use nonDetKeysUFM here, because we only use this list to+ -- remove some elements from a set+ needInScope = (tyCoVarsOfTypes tys `unionVarSet` tyCoVarsOfCos cos)+ `delListFromUniqSet_Directly` substDomain+ tysCosFVsInScope = needInScope `varSetInScope` in_scope+++-- | Substitute within a 'Type'+-- The substitution has to satisfy the invariants described in+-- Note [The substitution invariant].+substTy :: HasCallStack => TCvSubst -> Type -> Type+substTy subst ty+ | isEmptyTCvSubst subst = ty+ | otherwise = checkValidSubst subst [ty] [] $+ subst_ty subst ty++-- | Substitute within a 'Type' disabling the sanity checks.+-- The problems that the sanity checks in substTy catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substTyUnchecked to+-- substTy and remove this function. Please don't use in new code.+substTyUnchecked :: TCvSubst -> Type -> Type+substTyUnchecked subst ty+ | isEmptyTCvSubst subst = ty+ | otherwise = subst_ty subst ty++-- | Substitute within several 'Type's+-- The substitution has to satisfy the invariants described in+-- Note [The substitution invariant].+substTys :: HasCallStack => TCvSubst -> [Type] -> [Type]+substTys subst tys+ | isEmptyTCvSubst subst = tys+ | otherwise = checkValidSubst subst tys [] $ map (subst_ty subst) tys++-- | Substitute within several 'Type's disabling the sanity checks.+-- The problems that the sanity checks in substTys catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substTysUnchecked to+-- substTys and remove this function. Please don't use in new code.+substTysUnchecked :: TCvSubst -> [Type] -> [Type]+substTysUnchecked subst tys+ | isEmptyTCvSubst subst = tys+ | otherwise = map (subst_ty subst) tys++-- | Substitute within a 'ThetaType'+-- The substitution has to satisfy the invariants described in+-- Note [The substitution invariant].+substTheta :: HasCallStack => TCvSubst -> ThetaType -> ThetaType+substTheta = substTys++-- | Substitute within a 'ThetaType' disabling the sanity checks.+-- The problems that the sanity checks in substTys catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substThetaUnchecked to+-- substTheta and remove this function. Please don't use in new code.+substThetaUnchecked :: TCvSubst -> ThetaType -> ThetaType+substThetaUnchecked = substTysUnchecked+++subst_ty :: TCvSubst -> Type -> Type+-- subst_ty is the main workhorse for type substitution+--+-- Note that the in_scope set is poked only if we hit a forall+-- so it may often never be fully computed+subst_ty subst ty+ = go ty+ where+ go (TyVarTy tv) = substTyVar subst tv+ go (AppTy fun arg) = mkAppTy (go fun) $! (go arg)+ -- The mkAppTy smart constructor is important+ -- we might be replacing (a Int), represented with App+ -- by [Int], represented with TyConApp+ go (TyConApp tc tys) = let args = map go tys+ in args `seqList` TyConApp tc args+ go (FunTy arg res) = (FunTy $! go arg) $! go res+ go (ForAllTy (TvBndr tv vis) ty)+ = case substTyVarBndrUnchecked subst tv of+ (subst', tv') ->+ (ForAllTy $! ((TvBndr $! tv') vis)) $!+ (subst_ty subst' ty)+ go (LitTy n) = LitTy $! n+ go (CastTy ty co) = (mkCastTy $! (go ty)) $! (subst_co subst co)+ go (CoercionTy co) = CoercionTy $! (subst_co subst co)++substTyVar :: TCvSubst -> TyVar -> Type+substTyVar (TCvSubst _ tenv _) tv+ = ASSERT( isTyVar tv )+ case lookupVarEnv tenv tv of+ Just ty -> ty+ Nothing -> TyVarTy tv++substTyVars :: TCvSubst -> [TyVar] -> [Type]+substTyVars subst = map $ substTyVar subst++lookupTyVar :: TCvSubst -> TyVar -> Maybe Type+ -- See Note [Extending the TCvSubst]+lookupTyVar (TCvSubst _ tenv _) tv+ = ASSERT( isTyVar tv )+ lookupVarEnv tenv tv++-- | Substitute within a 'Coercion'+-- The substitution has to satisfy the invariants described in+-- Note [The substitution invariant].+substCo :: HasCallStack => TCvSubst -> Coercion -> Coercion+substCo subst co+ | isEmptyTCvSubst subst = co+ | otherwise = checkValidSubst subst [] [co] $ subst_co subst co++-- | Substitute within a 'Coercion' disabling sanity checks.+-- The problems that the sanity checks in substCo catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substCoUnchecked to+-- substCo and remove this function. Please don't use in new code.+substCoUnchecked :: TCvSubst -> Coercion -> Coercion+substCoUnchecked subst co+ | isEmptyTCvSubst subst = co+ | otherwise = subst_co subst co++-- | Substitute within several 'Coercion's+-- The substitution has to satisfy the invariants described in+-- Note [The substitution invariant].+substCos :: HasCallStack => TCvSubst -> [Coercion] -> [Coercion]+substCos subst cos+ | isEmptyTCvSubst subst = cos+ | otherwise = checkValidSubst subst [] cos $ map (subst_co subst) cos++subst_co :: TCvSubst -> Coercion -> Coercion+subst_co subst co+ = go co+ where+ go_ty :: Type -> Type+ go_ty = subst_ty subst++ go :: Coercion -> Coercion+ go (Refl r ty) = mkReflCo r $! go_ty ty+ go (TyConAppCo r tc args)= let args' = map go args+ in args' `seqList` mkTyConAppCo r tc args'+ go (AppCo co arg) = (mkAppCo $! go co) $! go arg+ go (ForAllCo tv kind_co co)+ = case substForAllCoBndrUnchecked subst tv kind_co of { (subst', tv', kind_co') ->+ ((mkForAllCo $! tv') $! kind_co') $! subst_co subst' co }+ go (FunCo r co1 co2) = (mkFunCo r $! go co1) $! go co2+ go (CoVarCo cv) = substCoVar subst cv+ go (AxiomInstCo con ind cos) = mkAxiomInstCo con ind $! map go cos+ go (UnivCo p r t1 t2) = (((mkUnivCo $! go_prov p) $! r) $!+ (go_ty t1)) $! (go_ty t2)+ go (SymCo co) = mkSymCo $! (go co)+ go (TransCo co1 co2) = (mkTransCo $! (go co1)) $! (go co2)+ go (NthCo d co) = mkNthCo d $! (go co)+ go (LRCo lr co) = mkLRCo lr $! (go co)+ go (InstCo co arg) = (mkInstCo $! (go co)) $! go arg+ go (CoherenceCo co1 co2) = (mkCoherenceCo $! (go co1)) $! (go co2)+ go (KindCo co) = mkKindCo $! (go co)+ go (SubCo co) = mkSubCo $! (go co)+ go (AxiomRuleCo c cs) = let cs1 = map go cs+ in cs1 `seqList` AxiomRuleCo c cs1++ go_prov UnsafeCoerceProv = UnsafeCoerceProv+ go_prov (PhantomProv kco) = PhantomProv (go kco)+ go_prov (ProofIrrelProv kco) = ProofIrrelProv (go kco)+ go_prov p@(PluginProv _) = p+ go_prov p@(HoleProv _) = p+ -- NB: this last case is a little suspicious, but we need it. Originally,+ -- there was a panic here, but it triggered from deeplySkolemise. Because+ -- we only skolemise tyvars that are manually bound, this operation makes+ -- sense, even over a coercion with holes.++substForAllCoBndr :: TCvSubst -> TyVar -> Coercion -> (TCvSubst, TyVar, Coercion)+substForAllCoBndr subst+ = substForAllCoBndrCallback False (substCo subst) subst++-- | Like 'substForAllCoBndr', but disables sanity checks.+-- The problems that the sanity checks in substCo catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substCoUnchecked to+-- substCo and remove this function. Please don't use in new code.+substForAllCoBndrUnchecked :: TCvSubst -> TyVar -> Coercion -> (TCvSubst, TyVar, Coercion)+substForAllCoBndrUnchecked subst+ = substForAllCoBndrCallback False (substCoUnchecked subst) subst++-- See Note [Sym and ForAllCo]+substForAllCoBndrCallback :: Bool -- apply sym to binder?+ -> (Coercion -> Coercion) -- transformation to kind co+ -> TCvSubst -> TyVar -> Coercion+ -> (TCvSubst, TyVar, Coercion)+substForAllCoBndrCallback sym sco (TCvSubst in_scope tenv cenv)+ old_var old_kind_co+ = ( TCvSubst (in_scope `extendInScopeSet` new_var) new_env cenv+ , new_var, new_kind_co )+ where+ new_env | no_change && not sym = delVarEnv tenv old_var+ | sym = extendVarEnv tenv old_var $+ TyVarTy new_var `CastTy` new_kind_co+ | otherwise = extendVarEnv tenv old_var (TyVarTy new_var)++ no_kind_change = noFreeVarsOfCo old_kind_co+ no_change = no_kind_change && (new_var == old_var)++ new_kind_co | no_kind_change = old_kind_co+ | otherwise = sco old_kind_co++ Pair new_ki1 _ = coercionKind new_kind_co++ new_var = uniqAway in_scope (setTyVarKind old_var new_ki1)++substCoVar :: TCvSubst -> CoVar -> Coercion+substCoVar (TCvSubst _ _ cenv) cv+ = case lookupVarEnv cenv cv of+ Just co -> co+ Nothing -> CoVarCo cv++substCoVars :: TCvSubst -> [CoVar] -> [Coercion]+substCoVars subst cvs = map (substCoVar subst) cvs++lookupCoVar :: TCvSubst -> Var -> Maybe Coercion+lookupCoVar (TCvSubst _ _ cenv) v = lookupVarEnv cenv v++substTyVarBndr :: HasCallStack => TCvSubst -> TyVar -> (TCvSubst, TyVar)+substTyVarBndr = substTyVarBndrCallback substTy++-- | Like 'substTyVarBndr' but disables sanity checks.+-- The problems that the sanity checks in substTy catch are described in+-- Note [The substitution invariant].+-- The goal of #11371 is to migrate all the calls of substTyUnchecked to+-- substTy and remove this function. Please don't use in new code.+substTyVarBndrUnchecked :: TCvSubst -> TyVar -> (TCvSubst, TyVar)+substTyVarBndrUnchecked = substTyVarBndrCallback substTyUnchecked++-- | Substitute a tyvar in a binding position, returning an+-- extended subst and a new tyvar.+substTyVarBndrCallback :: (TCvSubst -> Type -> Type) -- ^ the subst function+ -> TCvSubst -> TyVar -> (TCvSubst, TyVar)+substTyVarBndrCallback subst_fn subst@(TCvSubst in_scope tenv cenv) old_var+ = ASSERT2( _no_capture, pprTyVar old_var $$ pprTyVar new_var $$ ppr subst )+ ASSERT( isTyVar old_var )+ (TCvSubst (in_scope `extendInScopeSet` new_var) new_env cenv, new_var)+ where+ new_env | no_change = delVarEnv tenv old_var+ | otherwise = extendVarEnv tenv old_var (TyVarTy new_var)++ _no_capture = not (new_var `elemVarSet` tyCoVarsOfTypesSet tenv)+ -- Assertion check that we are not capturing something in the substitution++ old_ki = tyVarKind old_var+ no_kind_change = noFreeVarsOfType old_ki -- verify that kind is closed+ no_change = no_kind_change && (new_var == old_var)+ -- no_change means that the new_var is identical in+ -- all respects to the old_var (same unique, same kind)+ -- See Note [Extending the TCvSubst]+ --+ -- In that case we don't need to extend the substitution+ -- to map old to new. But instead we must zap any+ -- current substitution for the variable. For example:+ -- (\x.e) with id_subst = [x |-> e']+ -- Here we must simply zap the substitution for x++ new_var | no_kind_change = uniqAway in_scope old_var+ | otherwise = uniqAway in_scope $+ setTyVarKind old_var (subst_fn subst old_ki)+ -- The uniqAway part makes sure the new variable is not already in scope++substCoVarBndr :: TCvSubst -> CoVar -> (TCvSubst, CoVar)+substCoVarBndr subst@(TCvSubst in_scope tenv cenv) old_var+ = ASSERT( isCoVar old_var )+ (TCvSubst (in_scope `extendInScopeSet` new_var) tenv new_cenv, new_var)+ where+ new_co = mkCoVarCo new_var+ no_kind_change = all noFreeVarsOfType [t1, t2]+ no_change = new_var == old_var && no_kind_change++ new_cenv | no_change = delVarEnv cenv old_var+ | otherwise = extendVarEnv cenv old_var new_co++ new_var = uniqAway in_scope subst_old_var+ subst_old_var = mkCoVar (varName old_var) new_var_type++ (_, _, t1, t2, role) = coVarKindsTypesRole old_var+ t1' = substTy subst t1+ t2' = substTy subst t2+ new_var_type = mkCoercionType role t1' t2'+ -- It's important to do the substitution for coercions,+ -- because they can have free type variables++cloneTyVarBndr :: TCvSubst -> TyVar -> Unique -> (TCvSubst, TyVar)+cloneTyVarBndr subst@(TCvSubst in_scope tv_env cv_env) tv uniq+ = ASSERT2( isTyVar tv, ppr tv ) -- I think it's only called on TyVars+ (TCvSubst (extendInScopeSet in_scope tv')+ (extendVarEnv tv_env tv (mkTyVarTy tv')) cv_env, tv')+ where+ old_ki = tyVarKind tv+ no_kind_change = noFreeVarsOfType old_ki -- verify that kind is closed++ tv1 | no_kind_change = tv+ | otherwise = setTyVarKind tv (substTy subst old_ki)++ tv' = setVarUnique tv1 uniq++cloneTyVarBndrs :: TCvSubst -> [TyVar] -> UniqSupply -> (TCvSubst, [TyVar])+cloneTyVarBndrs subst [] _usupply = (subst, [])+cloneTyVarBndrs subst (t:ts) usupply = (subst'', tv:tvs)+ where+ (uniq, usupply') = takeUniqFromSupply usupply+ (subst' , tv ) = cloneTyVarBndr subst t uniq+ (subst'', tvs) = cloneTyVarBndrs subst' ts usupply'++{-+%************************************************************************+%* *+ Pretty-printing types++ Defined very early because of debug printing in assertions+%* *+%************************************************************************++@pprType@ is the standard @Type@ printer; the overloaded @ppr@ function is+defined to use this. @pprParendType@ is the same, except it puts+parens around the type, except for the atomic cases. @pprParendType@+works just by setting the initial context precedence very high.++Note [Precedence in types]+~~~~~~~~~~~~~~~~~~~~~~~~~~+We don't keep the fixity of type operators in the operator. So the pretty printer+follows the following precedence order:+ Type constructor application binds more tightly than+ Operator applications which bind more tightly than+ Function arrow++So we might see a :+: T b -> c+meaning (a :+: (T b)) -> c++Maybe operator applications should bind a bit less tightly?++Anyway, that's the current story; it is used consistently for Type and HsType.+-}++------------------++pprType, pprParendType :: Type -> SDoc+pprType = pprIfaceType . tidyToIfaceType+pprParendType = pprParendIfaceType . tidyToIfaceType++pprTyLit :: TyLit -> SDoc+pprTyLit = pprIfaceTyLit . toIfaceTyLit++pprKind, pprParendKind :: Kind -> SDoc+pprKind = pprType+pprParendKind = pprParendType++tidyToIfaceType :: Type -> IfaceType+-- It's vital to tidy before converting to an IfaceType+-- or nested binders will become indistinguishable!+--+-- Also for the free type variables, tell toIfaceTypeX to+-- leave them as IfaceFreeTyVar. This is super-important+-- for debug printing.+tidyToIfaceType ty = toIfaceTypeX (mkVarSet free_tcvs) (tidyType env ty)+ where+ env = tidyFreeTyCoVars emptyTidyEnv free_tcvs+ free_tcvs = tyCoVarsOfTypeWellScoped ty++------------+pprClassPred :: Class -> [Type] -> SDoc+pprClassPred clas tys = pprTypeApp (classTyCon clas) tys++------------+pprTheta :: ThetaType -> SDoc+pprTheta = pprIfaceContext . map tidyToIfaceType++pprThetaArrowTy :: ThetaType -> SDoc+pprThetaArrowTy = pprIfaceContextArr . map tidyToIfaceType++------------------+instance Outputable Type where+ ppr ty = pprType ty++instance Outputable TyLit where+ ppr = pprTyLit++------------------++pprSigmaType :: Type -> SDoc+pprSigmaType = pprIfaceSigmaType ShowForAllWhen . tidyToIfaceType++pprForAll :: [TyVarBinder] -> SDoc+pprForAll tvs = pprIfaceForAll (map toIfaceForAllBndr tvs)++-- | Print a user-level forall; see Note [When to print foralls]+pprUserForAll :: [TyVarBinder] -> SDoc+pprUserForAll = pprUserIfaceForAll . map toIfaceForAllBndr++pprTvBndrs :: [TyVarBinder] -> SDoc+pprTvBndrs tvs = sep (map pprTvBndr tvs)++pprTvBndr :: TyVarBinder -> SDoc+pprTvBndr = pprTyVar . binderVar++pprTyVars :: [TyVar] -> SDoc+pprTyVars tvs = sep (map pprTyVar tvs)++pprTyVar :: TyVar -> SDoc+-- Print a type variable binder with its kind (but not if *)+-- Here we do not go via IfaceType, because the duplication with+-- pprIfaceTvBndr is minimal, and the loss of uniques etc in+-- debug printing is disastrous+pprTyVar tv+ | isLiftedTypeKind kind = ppr tv+ | otherwise = parens (ppr tv <+> dcolon <+> ppr kind)+ where+ kind = tyVarKind tv++instance Outputable TyBinder where+ ppr (Anon ty) = text "[anon]" <+> ppr ty+ ppr (Named (TvBndr v Required)) = ppr v+ ppr (Named (TvBndr v Specified)) = char '@' <> ppr v+ ppr (Named (TvBndr v Inferred)) = braces (ppr v)++-----------------+instance Outputable Coercion where -- defined here to avoid orphans+ ppr = pprCo++{-+Note [When to print foralls]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Mostly we want to print top-level foralls when (and only when) the user specifies+-fprint-explicit-foralls. But when kind polymorphism is at work, that suppresses+too much information; see Trac #9018.++So I'm trying out this rule: print explicit foralls if+ a) User specifies -fprint-explicit-foralls, or+ b) Any of the quantified type variables has a kind+ that mentions a kind variable++This catches common situations, such as a type siguature+ f :: m a+which means+ f :: forall k. forall (m :: k->*) (a :: k). m a+We really want to see both the "forall k" and the kind signatures+on m and a. The latter comes from pprTvBndr.++Note [Infix type variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+With TypeOperators you can say++ f :: (a ~> b) -> b++and the (~>) is considered a type variable. However, the type+pretty-printer in this module will just see (a ~> b) as++ App (App (TyVarTy "~>") (TyVarTy "a")) (TyVarTy "b")++So it'll print the type in prefix form. To avoid confusion we must+remember to parenthesise the operator, thus++ (~>) a b -> b++See Trac #2766.+-}++pprDataCons :: TyCon -> SDoc+pprDataCons = sepWithVBars . fmap pprDataConWithArgs . tyConDataCons+ where+ sepWithVBars [] = empty+ sepWithVBars docs = sep (punctuate (space <> vbar) docs)++pprDataConWithArgs :: DataCon -> SDoc+pprDataConWithArgs dc = sep [forAllDoc, thetaDoc, ppr dc <+> argsDoc]+ where+ (_univ_tvs, _ex_tvs, eq_spec, theta, arg_tys, _res_ty) = dataConFullSig dc+ univ_bndrs = dataConUnivTyVarBinders dc+ ex_bndrs = dataConExTyVarBinders dc+ forAllDoc = pprUserForAll $ (filterEqSpec eq_spec univ_bndrs ++ ex_bndrs)+ thetaDoc = pprThetaArrowTy theta+ argsDoc = hsep (fmap pprParendType arg_tys)+++pprTypeApp :: TyCon -> [Type] -> SDoc+pprTypeApp tc tys+ = pprIfaceTypeApp TopPrec (toIfaceTyCon tc)+ (toIfaceTcArgs tc tys)+ -- TODO: toIfaceTcArgs seems rather wasteful here++pprTcAppCo :: TyPrec -> (TyPrec -> Coercion -> SDoc)+ -> TyCon -> [Coercion] -> SDoc+pprTcAppCo p _pp tc cos+ = pprIfaceCoTcApp p (toIfaceTyCon tc) (map toIfaceCoercion cos)++------------------++pprPrefixApp :: TyPrec -> SDoc -> [SDoc] -> SDoc+pprPrefixApp = pprIfacePrefixApp++----------------+pprArrowChain :: TyPrec -> [SDoc] -> SDoc+-- pprArrowChain p [a,b,c] generates a -> b -> c+pprArrowChain _ [] = empty+pprArrowChain p (arg:args) = maybeParen p FunPrec $+ sep [arg, sep (map (arrow <+>) args)]++ppSuggestExplicitKinds :: SDoc+-- Print a helpful suggstion about -fprint-explicit-kinds,+-- if it is not already on+ppSuggestExplicitKinds+ = sdocWithDynFlags $ \ dflags ->+ ppUnless (gopt Opt_PrintExplicitKinds dflags) $+ text "Use -fprint-explicit-kinds to see the kind arguments"++{-+%************************************************************************+%* *+\subsection{TidyType}+%* *+%************************************************************************+-}++-- | This tidies up a type for printing in an error message, or in+-- an interface file.+--+-- It doesn't change the uniques at all, just the print names.+tidyTyCoVarBndrs :: TidyEnv -> [TyCoVar] -> (TidyEnv, [TyCoVar])+tidyTyCoVarBndrs (occ_env, subst) tvs+ = mapAccumL tidyTyCoVarBndr tidy_env' tvs+ where+ -- Seed the occ_env with clashes among the names, see+ -- Node [Tidying multiple names at once] in OccName+ -- Se still go through tidyTyCoVarBndr so that each kind variable is tidied+ -- with the correct tidy_env+ occs = map getHelpfulOccName tvs+ tidy_env' = (avoidClashesOccEnv occ_env occs, subst)++tidyTyCoVarBndr :: TidyEnv -> TyCoVar -> (TidyEnv, TyCoVar)+tidyTyCoVarBndr tidy_env@(occ_env, subst) tyvar+ = case tidyOccName occ_env (getHelpfulOccName tyvar) of+ (occ_env', occ') -> ((occ_env', subst'), tyvar')+ where+ subst' = extendVarEnv subst tyvar tyvar'+ tyvar' = setTyVarKind (setTyVarName tyvar name') kind'+ kind' = tidyKind tidy_env (tyVarKind tyvar)+ name' = tidyNameOcc name occ'+ name = tyVarName tyvar++getHelpfulOccName :: TyCoVar -> OccName+getHelpfulOccName tyvar = occ1+ where+ name = tyVarName tyvar+ occ = getOccName name+ -- A TcTyVar with a System Name is probably a unification variable;+ -- when we tidy them we give them a trailing "0" (or 1 etc)+ -- so that they don't take precedence for the un-modified name+ -- Plus, indicating a unification variable in this way is a+ -- helpful clue for users+ occ1 | isSystemName name+ , isTcTyVar tyvar+ = mkTyVarOcc (occNameString occ ++ "0")+ | otherwise+ = occ++tidyTyVarBinder :: TidyEnv -> TyVarBndr TyVar vis+ -> (TidyEnv, TyVarBndr TyVar vis)+tidyTyVarBinder tidy_env (TvBndr tv vis)+ = (tidy_env', TvBndr tv' vis)+ where+ (tidy_env', tv') = tidyTyCoVarBndr tidy_env tv++tidyTyVarBinders :: TidyEnv -> [TyVarBndr TyVar vis]+ -> (TidyEnv, [TyVarBndr TyVar vis])+tidyTyVarBinders = mapAccumL tidyTyVarBinder++---------------+tidyFreeTyCoVars :: TidyEnv -> [TyCoVar] -> TidyEnv+-- ^ Add the free 'TyVar's to the env in tidy form,+-- so that we can tidy the type they are free in+tidyFreeTyCoVars (full_occ_env, var_env) tyvars+ = fst (tidyOpenTyCoVars (full_occ_env, var_env) tyvars)++ ---------------+tidyOpenTyCoVars :: TidyEnv -> [TyCoVar] -> (TidyEnv, [TyCoVar])+tidyOpenTyCoVars env tyvars = mapAccumL tidyOpenTyCoVar env tyvars++---------------+tidyOpenTyCoVar :: TidyEnv -> TyCoVar -> (TidyEnv, TyCoVar)+-- ^ Treat a new 'TyCoVar' as a binder, and give it a fresh tidy name+-- using the environment if one has not already been allocated. See+-- also 'tidyTyCoVarBndr'+tidyOpenTyCoVar env@(_, subst) tyvar+ = case lookupVarEnv subst tyvar of+ Just tyvar' -> (env, tyvar') -- Already substituted+ Nothing ->+ let env' = tidyFreeTyCoVars env (tyCoVarsOfTypeList (tyVarKind tyvar))+ in tidyTyCoVarBndr env' tyvar -- Treat it as a binder++---------------+tidyTyVarOcc :: TidyEnv -> TyVar -> TyVar+tidyTyVarOcc env@(_, subst) tv+ = case lookupVarEnv subst tv of+ Nothing -> updateTyVarKind (tidyType env) tv+ Just tv' -> tv'++---------------+tidyTypes :: TidyEnv -> [Type] -> [Type]+tidyTypes env tys = map (tidyType env) tys++---------------+tidyType :: TidyEnv -> Type -> Type+tidyType _ (LitTy n) = LitTy n+tidyType env (TyVarTy tv) = TyVarTy (tidyTyVarOcc env tv)+tidyType env (TyConApp tycon tys) = let args = tidyTypes env tys+ in args `seqList` TyConApp tycon args+tidyType env (AppTy fun arg) = (AppTy $! (tidyType env fun)) $! (tidyType env arg)+tidyType env (FunTy fun arg) = (FunTy $! (tidyType env fun)) $! (tidyType env arg)+tidyType env (ty@(ForAllTy{})) = mkForAllTys' (zip tvs' vis) $! tidyType env' body_ty+ where+ (tvs, vis, body_ty) = splitForAllTys' ty+ (env', tvs') = tidyTyCoVarBndrs env tvs+tidyType env (CastTy ty co) = (CastTy $! tidyType env ty) $! (tidyCo env co)+tidyType env (CoercionTy co) = CoercionTy $! (tidyCo env co)+++-- The following two functions differ from mkForAllTys and splitForAllTys in that+-- they expect/preserve the ArgFlag argument. Thes belong to types/Type.hs, but+-- how should they be named?+mkForAllTys' :: [(TyVar, ArgFlag)] -> Type -> Type+mkForAllTys' tvvs ty = foldr strictMkForAllTy ty tvvs+ where+ strictMkForAllTy (tv,vis) ty = (ForAllTy $! ((TvBndr $! tv) $! vis)) $! ty++splitForAllTys' :: Type -> ([TyVar], [ArgFlag], Type)+splitForAllTys' ty = go ty [] []+ where+ go (ForAllTy (TvBndr tv vis) ty) tvs viss = go ty (tv:tvs) (vis:viss)+ go ty tvs viss = (reverse tvs, reverse viss, ty)+++---------------+-- | Grabs the free type variables, tidies them+-- and then uses 'tidyType' to work over the type itself+tidyOpenTypes :: TidyEnv -> [Type] -> (TidyEnv, [Type])+tidyOpenTypes env tys+ = (env', tidyTypes (trimmed_occ_env, var_env) tys)+ where+ (env'@(_, var_env), tvs') = tidyOpenTyCoVars env $+ tyCoVarsOfTypesWellScoped tys+ trimmed_occ_env = initTidyOccEnv (map getOccName tvs')+ -- The idea here was that we restrict the new TidyEnv to the+ -- _free_ vars of the types, so that we don't gratuitously rename+ -- the _bound_ variables of the types.++---------------+tidyOpenType :: TidyEnv -> Type -> (TidyEnv, Type)+tidyOpenType env ty = let (env', [ty']) = tidyOpenTypes env [ty] in+ (env', ty')++---------------+-- | Calls 'tidyType' on a top-level type (i.e. with an empty tidying environment)+tidyTopType :: Type -> Type+tidyTopType ty = tidyType emptyTidyEnv ty++---------------+tidyOpenKind :: TidyEnv -> Kind -> (TidyEnv, Kind)+tidyOpenKind = tidyOpenType++tidyKind :: TidyEnv -> Kind -> Kind+tidyKind = tidyType++----------------+tidyCo :: TidyEnv -> Coercion -> Coercion+tidyCo env@(_, subst) co+ = go co+ where+ go (Refl r ty) = Refl r (tidyType env ty)+ go (TyConAppCo r tc cos) = let args = map go cos+ in args `seqList` TyConAppCo r tc args+ go (AppCo co1 co2) = (AppCo $! go co1) $! go co2+ go (ForAllCo tv h co) = ((ForAllCo $! tvp) $! (go h)) $! (tidyCo envp co)+ where (envp, tvp) = tidyTyCoVarBndr env tv+ -- the case above duplicates a bit of work in tidying h and the kind+ -- of tv. But the alternative is to use coercionKind, which seems worse.+ go (FunCo r co1 co2) = (FunCo r $! go co1) $! go co2+ go (CoVarCo cv) = case lookupVarEnv subst cv of+ Nothing -> CoVarCo cv+ Just cv' -> CoVarCo cv'+ go (AxiomInstCo con ind cos) = let args = map go cos+ in args `seqList` AxiomInstCo con ind args+ go (UnivCo p r t1 t2) = (((UnivCo $! (go_prov p)) $! r) $!+ tidyType env t1) $! tidyType env t2+ go (SymCo co) = SymCo $! go co+ go (TransCo co1 co2) = (TransCo $! go co1) $! go co2+ go (NthCo d co) = NthCo d $! go co+ go (LRCo lr co) = LRCo lr $! go co+ go (InstCo co ty) = (InstCo $! go co) $! go ty+ go (CoherenceCo co1 co2) = (CoherenceCo $! go co1) $! go co2+ go (KindCo co) = KindCo $! go co+ go (SubCo co) = SubCo $! go co+ go (AxiomRuleCo ax cos) = let cos1 = tidyCos env cos+ in cos1 `seqList` AxiomRuleCo ax cos1++ go_prov UnsafeCoerceProv = UnsafeCoerceProv+ go_prov (PhantomProv co) = PhantomProv (go co)+ go_prov (ProofIrrelProv co) = ProofIrrelProv (go co)+ go_prov p@(PluginProv _) = p+ go_prov p@(HoleProv _) = p++tidyCos :: TidyEnv -> [Coercion] -> [Coercion]+tidyCos env = map (tidyCo env)+++{- *********************************************************************+* *+ typeSize, coercionSize+* *+********************************************************************* -}++-- NB: We put typeSize/coercionSize here because they are mutually+-- recursive, and have the CPR property. If we have mutual+-- recursion across a hi-boot file, we don't get the CPR property+-- and these functions allocate a tremendous amount of rubbish.+-- It's not critical (because typeSize is really only used in+-- debug mode, but I tripped over an example (T5642) in which+-- typeSize was one of the biggest single allocators in all of GHC.+-- And it's easy to fix, so I did.++-- NB: typeSize does not respect `eqType`, in that two types that+-- are `eqType` may return different sizes. This is OK, because this+-- function is used only in reporting, not decision-making.++typeSize :: Type -> Int+typeSize (LitTy {}) = 1+typeSize (TyVarTy {}) = 1+typeSize (AppTy t1 t2) = typeSize t1 + typeSize t2+typeSize (FunTy t1 t2) = typeSize t1 + typeSize t2+typeSize (ForAllTy (TvBndr tv _) t) = typeSize (tyVarKind tv) + typeSize t+typeSize (TyConApp _ ts) = 1 + sum (map typeSize ts)+typeSize (CastTy ty co) = typeSize ty + coercionSize co+typeSize (CoercionTy co) = coercionSize co++coercionSize :: Coercion -> Int+coercionSize (Refl _ ty) = typeSize ty+coercionSize (TyConAppCo _ _ args) = 1 + sum (map coercionSize args)+coercionSize (AppCo co arg) = coercionSize co + coercionSize arg+coercionSize (ForAllCo _ h co) = 1 + coercionSize co + coercionSize h+coercionSize (FunCo _ co1 co2) = 1 + coercionSize co1 + coercionSize co2+coercionSize (CoVarCo _) = 1+coercionSize (AxiomInstCo _ _ args) = 1 + sum (map coercionSize args)+coercionSize (UnivCo p _ t1 t2) = 1 + provSize p + typeSize t1 + typeSize t2+coercionSize (SymCo co) = 1 + coercionSize co+coercionSize (TransCo co1 co2) = 1 + coercionSize co1 + coercionSize co2+coercionSize (NthCo _ co) = 1 + coercionSize co+coercionSize (LRCo _ co) = 1 + coercionSize co+coercionSize (InstCo co arg) = 1 + coercionSize co + coercionSize arg+coercionSize (CoherenceCo c1 c2) = 1 + coercionSize c1 + coercionSize c2+coercionSize (KindCo co) = 1 + coercionSize co+coercionSize (SubCo co) = 1 + coercionSize co+coercionSize (AxiomRuleCo _ cs) = 1 + sum (map coercionSize cs)++provSize :: UnivCoProvenance -> Int+provSize UnsafeCoerceProv = 1+provSize (PhantomProv co) = 1 + coercionSize co+provSize (ProofIrrelProv co) = 1 + coercionSize co+provSize (PluginProv _) = 1+provSize (HoleProv h) = pprPanic "provSize hits a hole" (ppr h)
+ types/TyCoRep.hs-boot view
@@ -0,0 +1,23 @@+module TyCoRep where++import Outputable ( SDoc )+import Data.Data ( Data )++data Type+data TyThing+data Coercion+data UnivCoProvenance+data TCvSubst+data TyLit+data TyBinder++type PredType = Type+type Kind = Type+type ThetaType = [PredType]++pprKind :: Kind -> SDoc+pprType :: Type -> SDoc++instance Data Type+ -- To support Data instances in CoAxiom+
+ types/TyCon.hs view
@@ -0,0 +1,2433 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++The @TyCon@ datatype+-}++{-# LANGUAGE CPP, FlexibleInstances #-}++module TyCon(+ -- * Main TyCon data types+ TyCon, AlgTyConRhs(..), visibleDataCons,+ AlgTyConFlav(..), isNoParent,+ FamTyConFlav(..), Role(..), Injectivity(..),+ RuntimeRepInfo(..),++ -- * TyConBinder+ TyConBinder, TyConBndrVis(..),+ mkNamedTyConBinder, mkNamedTyConBinders,+ mkAnonTyConBinder, mkAnonTyConBinders,+ tyConBinderArgFlag, isNamedTyConBinder,+ isVisibleTyConBinder, isInvisibleTyConBinder,++ -- ** Field labels+ tyConFieldLabels, lookupTyConFieldLabel,++ -- ** Constructing TyCons+ mkAlgTyCon,+ mkClassTyCon,+ mkFunTyCon,+ mkPrimTyCon,+ mkKindTyCon,+ mkLiftedPrimTyCon,+ mkTupleTyCon,+ mkSumTyCon,+ mkSynonymTyCon,+ mkFamilyTyCon,+ mkPromotedDataCon,+ mkTcTyCon,++ -- ** Predicates on TyCons+ isAlgTyCon, isVanillaAlgTyCon,+ isClassTyCon, isFamInstTyCon,+ isFunTyCon,+ isPrimTyCon,+ isTupleTyCon, isUnboxedTupleTyCon, isBoxedTupleTyCon,+ isUnboxedSumTyCon, isPromotedTupleTyCon,+ isTypeSynonymTyCon,+ mightBeUnsaturatedTyCon,+ isPromotedDataCon, isPromotedDataCon_maybe,+ isKindTyCon, isLiftedTypeKindTyConName,+ isTauTyCon, isFamFreeTyCon,++ isDataTyCon, isProductTyCon, isDataProductTyCon_maybe,+ isDataSumTyCon_maybe,+ isEnumerationTyCon,+ isNewTyCon, isAbstractTyCon,+ isFamilyTyCon, isOpenFamilyTyCon,+ isTypeFamilyTyCon, isDataFamilyTyCon,+ isOpenTypeFamilyTyCon, isClosedSynFamilyTyConWithAxiom_maybe,+ familyTyConInjectivityInfo,+ isBuiltInSynFamTyCon_maybe,+ isUnliftedTyCon,+ isGadtSyntaxTyCon, isInjectiveTyCon, isGenerativeTyCon, isGenInjAlgRhs,+ isTyConAssoc, tyConAssoc_maybe,+ isImplicitTyCon,+ isTyConWithSrcDataCons,+ isTcTyCon, isTcLevPoly,++ -- ** Extracting information out of TyCons+ tyConName,+ tyConSkolem,+ tyConKind,+ tyConUnique,+ tyConTyVars,+ tyConCType, tyConCType_maybe,+ tyConDataCons, tyConDataCons_maybe,+ tyConSingleDataCon_maybe, tyConSingleDataCon,+ tyConSingleAlgDataCon_maybe,+ tyConFamilySize,+ tyConStupidTheta,+ tyConArity,+ tyConRoles,+ tyConFlavour,+ tyConTuple_maybe, tyConClass_maybe, tyConATs,+ tyConFamInst_maybe, tyConFamInstSig_maybe, tyConFamilyCoercion_maybe,+ tyConFamilyResVar_maybe,+ synTyConDefn_maybe, synTyConRhs_maybe,+ famTyConFlav_maybe, famTcResVar,+ algTyConRhs,+ newTyConRhs, newTyConEtadArity, newTyConEtadRhs,+ unwrapNewTyCon_maybe, unwrapNewTyConEtad_maybe,+ newTyConDataCon_maybe,+ algTcFields,+ tyConRuntimeRepInfo,+ tyConBinders, tyConResKind,+ tcTyConScopedTyVars,++ -- ** Manipulating TyCons+ expandSynTyCon_maybe,+ makeRecoveryTyCon,+ newTyConCo, newTyConCo_maybe,+ pprPromotionQuote, mkTyConKind,++ -- * Runtime type representation+ TyConRepName, tyConRepName_maybe,+ mkPrelTyConRepName,+ tyConRepModOcc,++ -- * Primitive representations of Types+ PrimRep(..), PrimElemRep(..),+ isVoidRep, isGcPtrRep,+ primRepSizeW, primElemRepSizeB,+ primRepIsFloat,++ -- * Recursion breaking+ RecTcChecker, initRecTc, checkRecTc++) where++#include "HsVersions.h"++import {-# SOURCE #-} TyCoRep ( Kind, Type, PredType, pprType )+import {-# SOURCE #-} TysWiredIn ( runtimeRepTyCon, constraintKind+ , vecCountTyCon, vecElemTyCon, liftedTypeKind+ , mkFunKind, mkForAllKind )+import {-# SOURCE #-} DataCon ( DataCon, dataConExTyVars, dataConFieldLabels+ , dataConTyCon )++import Binary+import Var+import Class+import BasicTypes+import DynFlags+import ForeignCall+import Name+import NameEnv+import CoAxiom+import PrelNames+import Maybes+import Outputable+import FastStringEnv+import FieldLabel+import Constants+import Util+import Unique( tyConRepNameUnique, dataConRepNameUnique )+import UniqSet+import Module++import qualified Data.Data as Data++{-+-----------------------------------------------+ Notes about type families+-----------------------------------------------++Note [Type synonym families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* Type synonym families, also known as "type functions", map directly+ onto the type functions in FC:++ type family F a :: *+ type instance F Int = Bool+ ..etc...++* Reply "yes" to isTypeFamilyTyCon, and isFamilyTyCon++* From the user's point of view (F Int) and Bool are simply+ equivalent types.++* A Haskell 98 type synonym is a degenerate form of a type synonym+ family.++* Type functions can't appear in the LHS of a type function:+ type instance F (F Int) = ... -- BAD!++* Translation of type family decl:+ type family F a :: *+ translates to+ a FamilyTyCon 'F', whose FamTyConFlav is OpenSynFamilyTyCon++ type family G a :: * where+ G Int = Bool+ G Bool = Char+ G a = ()+ translates to+ a FamilyTyCon 'G', whose FamTyConFlav is ClosedSynFamilyTyCon, with the+ appropriate CoAxiom representing the equations++We also support injective type families -- see Note [Injective type families]++Note [Data type families]+~~~~~~~~~~~~~~~~~~~~~~~~~+See also Note [Wrappers for data instance tycons] in MkId.hs++* Data type families are declared thus+ data family T a :: *+ data instance T Int = T1 | T2 Bool++ Here T is the "family TyCon".++* Reply "yes" to isDataFamilyTyCon, and isFamilyTyCon++* The user does not see any "equivalent types" as he did with type+ synonym families. He just sees constructors with types+ T1 :: T Int+ T2 :: Bool -> T Int++* Here's the FC version of the above declarations:++ data T a+ data R:TInt = T1 | T2 Bool+ axiom ax_ti : T Int ~R R:TInt++ Note that this is a *representational* coercion+ The R:TInt is the "representation TyCons".+ It has an AlgTyConFlav of+ DataFamInstTyCon T [Int] ax_ti++* The axiom ax_ti may be eta-reduced; see+ Note [Eta reduction for data family axioms] in TcInstDcls++* The data constructor T2 has a wrapper (which is what the+ source-level "T2" invokes):++ $WT2 :: Bool -> T Int+ $WT2 b = T2 b `cast` sym ax_ti++* A data instance can declare a fully-fledged GADT:++ data instance T (a,b) where+ X1 :: T (Int,Bool)+ X2 :: a -> b -> T (a,b)++ Here's the FC version of the above declaration:++ data R:TPair a where+ X1 :: R:TPair Int Bool+ X2 :: a -> b -> R:TPair a b+ axiom ax_pr :: T (a,b) ~R R:TPair a b++ $WX1 :: forall a b. a -> b -> T (a,b)+ $WX1 a b (x::a) (y::b) = X2 a b x y `cast` sym (ax_pr a b)++ The R:TPair are the "representation TyCons".+ We have a bit of work to do, to unpick the result types of the+ data instance declaration for T (a,b), to get the result type in the+ representation; e.g. T (a,b) --> R:TPair a b++ The representation TyCon R:TList, has an AlgTyConFlav of++ DataFamInstTyCon T [(a,b)] ax_pr++* Notice that T is NOT translated to a FC type function; it just+ becomes a "data type" with no constructors, which can be coerced inot+ into R:TInt, R:TPair by the axioms. These axioms+ axioms come into play when (and *only* when) you+ - use a data constructor+ - do pattern matching+ Rather like newtype, in fact++ As a result++ - T behaves just like a data type so far as decomposition is concerned++ - (T Int) is not implicitly converted to R:TInt during type inference.+ Indeed the latter type is unknown to the programmer.++ - There *is* an instance for (T Int) in the type-family instance+ environment, but it is only used for overlap checking++ - It's fine to have T in the LHS of a type function:+ type instance F (T a) = [a]++ It was this last point that confused me! The big thing is that you+ should not think of a data family T as a *type function* at all, not+ even an injective one! We can't allow even injective type functions+ on the LHS of a type function:+ type family injective G a :: *+ type instance F (G Int) = Bool+ is no good, even if G is injective, because consider+ type instance G Int = Bool+ type instance F Bool = Char++ So a data type family is not an injective type function. It's just a+ data type with some axioms that connect it to other data types.++* The tyConTyVars of the representation tycon are the tyvars that the+ user wrote in the patterns. This is important in TcDeriv, where we+ bring these tyvars into scope before type-checking the deriving+ clause. This fact is arranged for in TcInstDecls.tcDataFamInstDecl.++Note [Associated families and their parent class]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+*Associated* families are just like *non-associated* families, except+that they have a famTcParent field of (Just cls), which identifies the+parent class.++However there is an important sharing relationship between+ * the tyConTyVars of the parent Class+ * the tyConTyvars of the associated TyCon++ class C a b where+ data T p a+ type F a q b++Here the 'a' and 'b' are shared with the 'Class'; that is, they have+the same Unique.++This is important. In an instance declaration we expect+ * all the shared variables to be instantiated the same way+ * the non-shared variables of the associated type should not+ be instantiated at all++ instance C [x] (Tree y) where+ data T p [x] = T1 x | T2 p+ type F [x] q (Tree y) = (x,y,q)++Note [TyCon Role signatures]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Every tycon has a role signature, assigning a role to each of the tyConTyVars+(or of equal length to the tyConArity, if there are no tyConTyVars). An+example demonstrates these best: say we have a tycon T, with parameters a at+nominal, b at representational, and c at phantom. Then, to prove+representational equality between T a1 b1 c1 and T a2 b2 c2, we need to have+nominal equality between a1 and a2, representational equality between b1 and+b2, and nothing in particular (i.e., phantom equality) between c1 and c2. This+might happen, say, with the following declaration:++ data T a b c where+ MkT :: b -> T Int b c++Data and class tycons have their roles inferred (see inferRoles in TcTyDecls),+as do vanilla synonym tycons. Family tycons have all parameters at role N,+though it is conceivable that we could relax this restriction. (->)'s and+tuples' parameters are at role R. Each primitive tycon declares its roles;+it's worth noting that (~#)'s parameters are at role N. Promoted data+constructors' type arguments are at role R. All kind arguments are at role+N.++Note [Unboxed tuple RuntimeRep vars]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The contents of an unboxed tuple may have any representation. Accordingly,+the kind of the unboxed tuple constructor is runtime-representation+polymorphic. For example,++ (#,#) :: forall (q :: RuntimeRep) (r :: RuntimeRep). TYPE q -> TYPE r -> #++These extra tyvars (v and w) cause some delicate processing around tuples,+where we used to be able to assume that the tycon arity and the+datacon arity were the same.++Note [Injective type families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We allow injectivity annotations for type families (both open and closed):++ type family F (a :: k) (b :: k) = r | r -> a+ type family G a b = res | res -> a b where ...++Injectivity information is stored in the `famTcInj` field of `FamilyTyCon`.+`famTcInj` maybe stores a list of Bools, where each entry corresponds to a+single element of `tyConTyVars` (both lists should have identical length). If no+injectivity annotation was provided `famTcInj` is Nothing. From this follows an+invariant that if `famTcInj` is a Just then at least one element in the list+must be True.++See also:+ * [Injectivity annotation] in HsDecls+ * [Renaming injectivity annotation] in RnSource+ * [Verifying injectivity annotation] in FamInstEnv+ * [Type inference for type families with injectivity] in TcInteract++************************************************************************+* *+ TyConBinder+* *+************************************************************************+-}++type TyConBinder = TyVarBndr TyVar TyConBndrVis++data TyConBndrVis+ = NamedTCB ArgFlag+ | AnonTCB++mkAnonTyConBinder :: TyVar -> TyConBinder+mkAnonTyConBinder tv = TvBndr tv AnonTCB++mkAnonTyConBinders :: [TyVar] -> [TyConBinder]+mkAnonTyConBinders tvs = map mkAnonTyConBinder tvs++mkNamedTyConBinder :: ArgFlag -> TyVar -> TyConBinder+-- The odd argument order supports currying+mkNamedTyConBinder vis tv = TvBndr tv (NamedTCB vis)++mkNamedTyConBinders :: ArgFlag -> [TyVar] -> [TyConBinder]+-- The odd argument order supports currying+mkNamedTyConBinders vis tvs = map (mkNamedTyConBinder vis) tvs++tyConBinderArgFlag :: TyConBinder -> ArgFlag+tyConBinderArgFlag (TvBndr _ (NamedTCB vis)) = vis+tyConBinderArgFlag (TvBndr _ AnonTCB) = Required++isNamedTyConBinder :: TyConBinder -> Bool+isNamedTyConBinder (TvBndr _ (NamedTCB {})) = True+isNamedTyConBinder _ = False++isVisibleTyConBinder :: TyVarBndr tv TyConBndrVis -> Bool+-- Works for IfaceTyConBinder too+isVisibleTyConBinder (TvBndr _ (NamedTCB vis)) = isVisibleArgFlag vis+isVisibleTyConBinder (TvBndr _ AnonTCB) = True++isInvisibleTyConBinder :: TyVarBndr tv TyConBndrVis -> Bool+-- Works for IfaceTyConBinder too+isInvisibleTyConBinder tcb = not (isVisibleTyConBinder tcb)++mkTyConKind :: [TyConBinder] -> Kind -> Kind+mkTyConKind bndrs res_kind = foldr mk res_kind bndrs+ where+ mk :: TyConBinder -> Kind -> Kind+ mk (TvBndr tv AnonTCB) k = mkFunKind (tyVarKind tv) k+ mk (TvBndr tv (NamedTCB vis)) k = mkForAllKind tv vis k++{- Note [The binders/kind/arity fields of a TyCon]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+All TyCons have this group of fields+ tyConBinders :: [TyConBinder]+ tyConResKind :: Kind+ tyConTyVars :: [TyVra] -- Cached = binderVars tyConBinders+ tyConKind :: Kind -- Cached = mkTyConKind tyConBinders tyConResKind+ tyConArity :: Arity -- Cached = length tyConBinders++They fit together like so:++* tyConBinders gives the telescope of type variables on the LHS of the+ type declaration. For example:++ type App a (b :: k) = a b++ tyConBinders = [ TvBndr (k::*) (NamedTCB Inferred)+ , TvBndr (a:k->*) AnonTCB+ , TvBndr (b:k) AnonTCB ]++ Note that that are three binders here, including the+ kind variable k.++ See Note [TyBinders and ArgFlags] in TyCoRep for what+ the visibility flag means.++* Each TyConBinder tyConBinders has a TyVar, and that TyVar may+ scope over some other part of the TyCon's definition. Eg+ type T a = a->a+ we have+ tyConBinders = [ TvBndr (a:*) AnonTCB ]+ synTcRhs = a->a+ So the 'a' scopes over the synTcRhs++* From the tyConBinders and tyConResKind we can get the tyConKind+ E.g for our App example:+ App :: forall k. (k->*) -> k -> *++ We get a 'forall' in the kind for each NamedTCB, and an arrow+ for each AnonTCB++ tyConKind is the full kind of the TyCon, not just the result kind++* tyConArity is the arguments this TyCon must be applied to, to be+ considered saturated. Here we mean "applied to in the actual Type",+ not surface syntax; i.e. including implicit kind variables.+ So it's just (length tyConBinders)+-}++instance Outputable tv => Outputable (TyVarBndr tv TyConBndrVis) where+ ppr (TvBndr v AnonTCB) = ppr v+ ppr (TvBndr v (NamedTCB Required)) = ppr v+ ppr (TvBndr v (NamedTCB Specified)) = char '@' <> ppr v+ ppr (TvBndr v (NamedTCB Inferred)) = braces (ppr v)++instance Binary TyConBndrVis where+ put_ bh AnonTCB = putByte bh 0+ put_ bh (NamedTCB vis) = do { putByte bh 1; put_ bh vis }++ get bh = do { h <- getByte bh+ ; case h of+ 0 -> return AnonTCB+ _ -> do { vis <- get bh; return (NamedTCB vis) } }+++{- *********************************************************************+* *+ The TyCon type+* *+************************************************************************+-}+++-- | TyCons represent type constructors. Type constructors are introduced by+-- things such as:+--+-- 1) Data declarations: @data Foo = ...@ creates the @Foo@ type constructor of+-- kind @*@+--+-- 2) Type synonyms: @type Foo = ...@ creates the @Foo@ type constructor+--+-- 3) Newtypes: @newtype Foo a = MkFoo ...@ creates the @Foo@ type constructor+-- of kind @* -> *@+--+-- 4) Class declarations: @class Foo where@ creates the @Foo@ type constructor+-- of kind @*@+--+-- This data type also encodes a number of primitive, built in type constructors+-- such as those for function and tuple types.++-- If you edit this type, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs+data TyCon+ = -- | The function type constructor, @(->)@+ FunTyCon {+ tyConUnique :: Unique, -- ^ A Unique of this TyCon. Invariant:+ -- identical to Unique of Name stored in+ -- tyConName field.++ tyConName :: Name, -- ^ Name of the constructor++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity++ tcRepName :: TyConRepName+ }++ -- | Algebraic data types, from+ -- - @data@ declarations+ -- - @newtype@ declarations+ -- - data instance declarations+ -- - type instance declarations+ -- - the TyCon generated by a class declaration+ -- - boxed tuples+ -- - unboxed tuples+ -- - constraint tuples+ -- All these constructors are lifted and boxed except unboxed tuples+ -- which should have an 'UnboxedAlgTyCon' parent.+ -- Data/newtype/type /families/ are handled by 'FamilyTyCon'.+ -- See 'AlgTyConRhs' for more information.+ | AlgTyCon {+ tyConUnique :: Unique, -- ^ A Unique of this TyCon. Invariant:+ -- identical to Unique of Name stored in+ -- tyConName field.++ tyConName :: Name, -- ^ Name of the constructor++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConTyVars :: [TyVar], -- ^ TyVar binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity++ -- The tyConTyVars scope over:+ --+ -- 1. The 'algTcStupidTheta'+ -- 2. The cached types in algTyConRhs.NewTyCon+ -- 3. The family instance types if present+ --+ -- Note that it does /not/ scope over the data+ -- constructors.++ tcRoles :: [Role], -- ^ The role for each type variable+ -- This list has length = tyConArity+ -- See also Note [TyCon Role signatures]++ tyConCType :: Maybe CType,-- ^ The C type that should be used+ -- for this type when using the FFI+ -- and CAPI++ algTcGadtSyntax :: Bool, -- ^ Was the data type declared with GADT+ -- syntax? If so, that doesn't mean it's a+ -- true GADT; only that the "where" form+ -- was used. This field is used only to+ -- guide pretty-printing++ algTcStupidTheta :: [PredType], -- ^ The \"stupid theta\" for the data+ -- type (always empty for GADTs). A+ -- \"stupid theta\" is the context to+ -- the left of an algebraic type+ -- declaration, e.g. @Eq a@ in the+ -- declaration @data Eq a => T a ...@.++ algTcRhs :: AlgTyConRhs, -- ^ Contains information about the+ -- data constructors of the algebraic type++ algTcFields :: FieldLabelEnv, -- ^ Maps a label to information+ -- about the field++ algTcParent :: AlgTyConFlav -- ^ Gives the class or family declaration+ -- 'TyCon' for derived 'TyCon's representing+ -- class or family instances, respectively.++ }++ -- | Represents type synonyms+ | SynonymTyCon {+ tyConUnique :: Unique, -- ^ A Unique of this TyCon. Invariant:+ -- identical to Unique of Name stored in+ -- tyConName field.++ tyConName :: Name, -- ^ Name of the constructor++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConTyVars :: [TyVar], -- ^ TyVar binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity+ -- tyConTyVars scope over: synTcRhs++ tcRoles :: [Role], -- ^ The role for each type variable+ -- This list has length = tyConArity+ -- See also Note [TyCon Role signatures]++ synTcRhs :: Type, -- ^ Contains information about the expansion+ -- of the synonym++ synIsTau :: Bool, -- True <=> the RHS of this synonym does not+ -- have any foralls, after expanding any+ -- nested synonyms+ synIsFamFree :: Bool -- True <=> the RHS of this synonym does not mention+ -- any type synonym families (data families+ -- are fine), again after expanding any+ -- nested synonyms+ }++ -- | Represents families (both type and data)+ -- Argument roles are all Nominal+ | FamilyTyCon {+ tyConUnique :: Unique, -- ^ A Unique of this TyCon. Invariant:+ -- identical to Unique of Name stored in+ -- tyConName field.++ tyConName :: Name, -- ^ Name of the constructor++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConTyVars :: [TyVar], -- ^ TyVar binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity+ -- tyConTyVars connect an associated family TyCon+ -- with its parent class; see TcValidity.checkConsistentFamInst++ famTcResVar :: Maybe Name, -- ^ Name of result type variable, used+ -- for pretty-printing with --show-iface+ -- and for reifying TyCon in Template+ -- Haskell++ famTcFlav :: FamTyConFlav, -- ^ Type family flavour: open, closed,+ -- abstract, built-in. See comments for+ -- FamTyConFlav++ famTcParent :: Maybe Class, -- ^ For *associated* type/data families+ -- The class in whose declaration the family is declared+ -- See Note [Associated families and their parent class]++ famTcInj :: Injectivity -- ^ is this a type family injective in+ -- its type variables? Nothing if no+ -- injectivity annotation was given+ }++ -- | Primitive types; cannot be defined in Haskell. This includes+ -- the usual suspects (such as @Int#@) as well as foreign-imported+ -- types and kinds (@*@, @#@, and @?@)+ | PrimTyCon {+ tyConUnique :: Unique, -- ^ A Unique of this TyCon. Invariant:+ -- identical to Unique of Name stored in+ -- tyConName field.++ tyConName :: Name, -- ^ Name of the constructor++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity++ tcRoles :: [Role], -- ^ The role for each type variable+ -- This list has length = tyConArity+ -- See also Note [TyCon Role signatures]++ isUnlifted :: Bool, -- ^ Most primitive tycons are unlifted (may+ -- not contain bottom) but other are lifted,+ -- e.g. @RealWorld@+ -- Only relevant if tyConKind = *++ primRepName :: Maybe TyConRepName -- Only relevant for kind TyCons+ -- i.e, *, #, ?+ }++ -- | Represents promoted data constructor.+ | PromotedDataCon { -- See Note [Promoted data constructors]+ tyConUnique :: Unique, -- ^ Same Unique as the data constructor+ tyConName :: Name, -- ^ Same Name as the data constructor++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity++ tcRoles :: [Role], -- ^ Roles: N for kind vars, R for type vars+ dataCon :: DataCon, -- ^ Corresponding data constructor+ tcRepName :: TyConRepName,+ promDcRepInfo :: RuntimeRepInfo -- ^ See comments with 'RuntimeRepInfo'+ }++ -- | These exist only during a recursive type/class type-checking knot.+ | TcTyCon {+ tyConUnique :: Unique,+ tyConName :: Name,+ tyConUnsat :: Bool, -- ^ can this tycon be unsaturated?++ -- See Note [The binders/kind/arity fields of a TyCon]+ tyConBinders :: [TyConBinder], -- ^ Full binders+ tyConTyVars :: [TyVar], -- ^ TyVar binders+ tyConResKind :: Kind, -- ^ Result kind+ tyConKind :: Kind, -- ^ Kind of this TyCon+ tyConArity :: Arity, -- ^ Arity++ tcTyConScopedTyVars :: [TyVar] -- ^ Scoped tyvars over the+ -- tycon's body. See Note [TcTyCon]+ }++-- | Represents right-hand-sides of 'TyCon's for algebraic types+data AlgTyConRhs++ -- | Says that we know nothing about this data type, except that+ -- it's represented by a pointer. Used when we export a data type+ -- abstractly into an .hi file.+ = AbstractTyCon++ -- | Information about those 'TyCon's derived from a @data@+ -- declaration. This includes data types with no constructors at+ -- all.+ | DataTyCon {+ data_cons :: [DataCon],+ -- ^ The data type constructors; can be empty if the+ -- user declares the type to have no constructors+ --+ -- INVARIANT: Kept in order of increasing 'DataCon'+ -- tag (see the tag assignment in DataCon.mkDataCon)++ is_enum :: Bool -- ^ Cached value: is this an enumeration type?+ -- See Note [Enumeration types]+ }++ | TupleTyCon { -- A boxed, unboxed, or constraint tuple+ data_con :: DataCon, -- NB: it can be an *unboxed* tuple+ tup_sort :: TupleSort -- ^ Is this a boxed, unboxed or constraint+ -- tuple?+ }++ | SumTyCon {+ data_cons :: [DataCon]+ }++ -- | Information about those 'TyCon's derived from a @newtype@ declaration+ | NewTyCon {+ data_con :: DataCon, -- ^ The unique constructor for the @newtype@.+ -- It has no existentials++ nt_rhs :: Type, -- ^ Cached value: the argument type of the+ -- constructor, which is just the representation+ -- type of the 'TyCon' (remember that @newtype@s+ -- do not exist at runtime so need a different+ -- representation type).+ --+ -- The free 'TyVar's of this type are the+ -- 'tyConTyVars' from the corresponding 'TyCon'++ nt_etad_rhs :: ([TyVar], Type),+ -- ^ Same as the 'nt_rhs', but this time eta-reduced.+ -- Hence the list of 'TyVar's in this field may be+ -- shorter than the declared arity of the 'TyCon'.++ -- See Note [Newtype eta]+ nt_co :: CoAxiom Unbranched+ -- The axiom coercion that creates the @newtype@+ -- from the representation 'Type'.++ -- See Note [Newtype coercions]+ -- Invariant: arity = #tvs in nt_etad_rhs;+ -- See Note [Newtype eta]+ -- Watch out! If any newtypes become transparent+ -- again check Trac #1072.+ }++-- | Some promoted datacons signify extra info relevant to GHC. For example,+-- the @IntRep@ constructor of @RuntimeRep@ corresponds to the 'IntRep'+-- constructor of 'PrimRep'. This data structure allows us to store this+-- information right in the 'TyCon'. The other approach would be to look+-- up things like @RuntimeRep@'s @PrimRep@ by known-key every time.+data RuntimeRepInfo+ = NoRRI -- ^ an ordinary promoted data con+ | RuntimeRep ([Type] -> [PrimRep])+ -- ^ A constructor of @RuntimeRep@. The argument to the function should+ -- be the list of arguments to the promoted datacon.+ | VecCount Int -- ^ A constructor of @VecCount@+ | VecElem PrimElemRep -- ^ A constructor of @VecElem@++-- | Extract those 'DataCon's that we are able to learn about. Note+-- that visibility in this sense does not correspond to visibility in+-- the context of any particular user program!+visibleDataCons :: AlgTyConRhs -> [DataCon]+visibleDataCons (AbstractTyCon {}) = []+visibleDataCons (DataTyCon{ data_cons = cs }) = cs+visibleDataCons (NewTyCon{ data_con = c }) = [c]+visibleDataCons (TupleTyCon{ data_con = c }) = [c]+visibleDataCons (SumTyCon{ data_cons = cs }) = cs++-- ^ Both type classes as well as family instances imply implicit+-- type constructors. These implicit type constructors refer to their parent+-- structure (ie, the class or family from which they derive) using a type of+-- the following form.+data AlgTyConFlav+ = -- | An ordinary type constructor has no parent.+ VanillaAlgTyCon+ TyConRepName++ -- | An unboxed type constructor. The TyConRepName is a Maybe since we+ -- currently don't allow unboxed sums to be Typeable since there are too+ -- many of them. See #13276.+ | UnboxedAlgTyCon+ (Maybe TyConRepName)++ -- | Type constructors representing a class dictionary.+ -- See Note [ATyCon for classes] in TyCoRep+ | ClassTyCon+ Class -- INVARIANT: the classTyCon of this Class is the+ -- current tycon+ TyConRepName++ -- | Type constructors representing an *instance* of a *data* family.+ -- Parameters:+ --+ -- 1) The type family in question+ --+ -- 2) Instance types; free variables are the 'tyConTyVars'+ -- of the current 'TyCon' (not the family one). INVARIANT:+ -- the number of types matches the arity of the family 'TyCon'+ --+ -- 3) A 'CoTyCon' identifying the representation+ -- type with the type instance family+ | DataFamInstTyCon -- See Note [Data type families]+ (CoAxiom Unbranched) -- The coercion axiom.+ -- A *Representational* coercion,+ -- of kind T ty1 ty2 ~R R:T a b c+ -- where T is the family TyCon,+ -- and R:T is the representation TyCon (ie this one)+ -- and a,b,c are the tyConTyVars of this TyCon+ --+ -- BUT may be eta-reduced; see TcInstDcls+ -- Note [Eta reduction for data family axioms]++ -- Cached fields of the CoAxiom, but adjusted to+ -- use the tyConTyVars of this TyCon+ TyCon -- The family TyCon+ [Type] -- Argument types (mentions the tyConTyVars of this TyCon)+ -- Match in length the tyConTyVars of the family TyCon++ -- E.g. data instance T [a] = ...+ -- gives a representation tycon:+ -- data R:TList a = ...+ -- axiom co a :: T [a] ~ R:TList a+ -- with R:TList's algTcParent = DataFamInstTyCon T [a] co++instance Outputable AlgTyConFlav where+ ppr (VanillaAlgTyCon {}) = text "Vanilla ADT"+ ppr (UnboxedAlgTyCon {}) = text "Unboxed ADT"+ ppr (ClassTyCon cls _) = text "Class parent" <+> ppr cls+ ppr (DataFamInstTyCon _ tc tys) = text "Family parent (family instance)"+ <+> ppr tc <+> sep (map pprType tys)++-- | Checks the invariants of a 'AlgTyConFlav' given the appropriate type class+-- name, if any+okParent :: Name -> AlgTyConFlav -> Bool+okParent _ (VanillaAlgTyCon {}) = True+okParent _ (UnboxedAlgTyCon {}) = True+okParent tc_name (ClassTyCon cls _) = tc_name == tyConName (classTyCon cls)+okParent _ (DataFamInstTyCon _ fam_tc tys) = tyConArity fam_tc == length tys++isNoParent :: AlgTyConFlav -> Bool+isNoParent (VanillaAlgTyCon {}) = True+isNoParent _ = False++--------------------++data Injectivity+ = NotInjective+ | Injective [Bool] -- 1-1 with tyConTyVars (incl kind vars)+ deriving( Eq )++-- | Information pertaining to the expansion of a type synonym (@type@)+data FamTyConFlav+ = -- | Represents an open type family without a fixed right hand+ -- side. Additional instances can appear at any time.+ --+ -- These are introduced by either a top level declaration:+ --+ -- > data family T a :: *+ --+ -- Or an associated data type declaration, within a class declaration:+ --+ -- > class C a b where+ -- > data T b :: *+ DataFamilyTyCon+ TyConRepName++ -- | An open type synonym family e.g. @type family F x y :: * -> *@+ | OpenSynFamilyTyCon++ -- | A closed type synonym family e.g.+ -- @type family F x where { F Int = Bool }@+ | ClosedSynFamilyTyCon (Maybe (CoAxiom Branched))+ -- See Note [Closed type families]++ -- | A closed type synonym family declared in an hs-boot file with+ -- type family F a where ..+ | AbstractClosedSynFamilyTyCon++ -- | Built-in type family used by the TypeNats solver+ | BuiltInSynFamTyCon BuiltInSynFamily++instance Outputable FamTyConFlav where+ ppr (DataFamilyTyCon n) = text "data family" <+> ppr n+ ppr OpenSynFamilyTyCon = text "open type family"+ ppr (ClosedSynFamilyTyCon Nothing) = text "closed type family"+ ppr (ClosedSynFamilyTyCon (Just coax)) = text "closed type family" <+> ppr coax+ ppr AbstractClosedSynFamilyTyCon = text "abstract closed type family"+ ppr (BuiltInSynFamTyCon _) = text "built-in type family"++{- Note [Closed type families]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+* In an open type family you can add new instances later. This is the+ usual case.++* In a closed type family you can only put equations where the family+ is defined.++A non-empty closed type family has a single axiom with multiple+branches, stored in the 'ClosedSynFamilyTyCon' constructor. A closed+type family with no equations does not have an axiom, because there is+nothing for the axiom to prove!+++Note [Promoted data constructors]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+All data constructors can be promoted to become a type constructor,+via the PromotedDataCon alternative in TyCon.++* The TyCon promoted from a DataCon has the *same* Name and Unique as+ the DataCon. Eg. If the data constructor Data.Maybe.Just(unique 78,+ say) is promoted to a TyCon whose name is Data.Maybe.Just(unique 78)++* Small note: We promote the *user* type of the DataCon. Eg+ data T = MkT {-# UNPACK #-} !(Bool, Bool)+ The promoted kind is+ MkT :: (Bool,Bool) -> T+ *not*+ MkT :: Bool -> Bool -> T++Note [Enumeration types]+~~~~~~~~~~~~~~~~~~~~~~~~+We define datatypes with no constructors to *not* be+enumerations; this fixes trac #2578, Otherwise we+end up generating an empty table for+ <mod>_<type>_closure_tbl+which is used by tagToEnum# to map Int# to constructors+in an enumeration. The empty table apparently upset+the linker.++Moreover, all the data constructor must be enumerations, meaning+they have type (forall abc. T a b c). GADTs are not enumerations.+For example consider+ data T a where+ T1 :: T Int+ T2 :: T Bool+ T3 :: T a+What would [T1 ..] be? [T1,T3] :: T Int? Easiest thing is to exclude them.+See Trac #4528.++Note [Newtype coercions]+~~~~~~~~~~~~~~~~~~~~~~~~+The NewTyCon field nt_co is a CoAxiom which is used for coercing from+the representation type of the newtype, to the newtype itself. For+example,++ newtype T a = MkT (a -> a)++the NewTyCon for T will contain nt_co = CoT where CoT t : T t ~ t -> t.++In the case that the right hand side is a type application+ending with the same type variables as the left hand side, we+"eta-contract" the coercion. So if we had++ newtype S a = MkT [a]++then we would generate the arity 0 axiom CoS : S ~ []. The+primary reason we do this is to make newtype deriving cleaner.++In the paper we'd write+ axiom CoT : (forall t. T t) ~ (forall t. [t])+and then when we used CoT at a particular type, s, we'd say+ CoT @ s+which encodes as (TyConApp instCoercionTyCon [TyConApp CoT [], s])++Note [Newtype eta]+~~~~~~~~~~~~~~~~~~+Consider+ newtype Parser a = MkParser (IO a) deriving Monad+Are these two types equal (to Core)?+ Monad Parser+ Monad IO+which we need to make the derived instance for Monad Parser.++Well, yes. But to see that easily we eta-reduce the RHS type of+Parser, in this case to ([], Froogle), so that even unsaturated applications+of Parser will work right. This eta reduction is done when the type+constructor is built, and cached in NewTyCon.++Here's an example that I think showed up in practice+Source code:+ newtype T a = MkT [a]+ newtype Foo m = MkFoo (forall a. m a -> Int)++ w1 :: Foo []+ w1 = ...++ w2 :: Foo T+ w2 = MkFoo (\(MkT x) -> case w1 of MkFoo f -> f x)++After desugaring, and discarding the data constructors for the newtypes,+we get:+ w2 = w1 `cast` Foo CoT+so the coercion tycon CoT must have+ kind: T ~ []+ and arity: 0++Note [TcTyCon]+~~~~~~~~~~~~~~+TcTyCons are used for tow distinct purposes++1. When recovering from a type error in a type declaration,+ we want to put the erroneous TyCon in the environment in a+ way that won't lead to more errors. We use a TcTyCon for this;+ see makeRecoveryTyCon.++2. When checking a type/class declaration (in module TcTyClsDecls), we come+ upon knowledge of the eventual tycon in bits and pieces. First, we use+ getInitialKinds to look over the user-provided kind signature of a tycon+ (including, for example, the number of parameters written to the tycon)+ to get an initial shape of the tycon's kind. Then, using these initial+ kinds, we kind-check the body of the tycon (class methods, data constructors,+ etc.), filling in the metavariables in the tycon's initial kind.+ We then generalize to get the tycon's final, fixed kind. Finally, once+ this has happened for all tycons in a mutually recursive group, we+ can desugar the lot.++ For convenience, we store partially-known tycons in TcTyCons, which+ might store meta-variables. These TcTyCons are stored in the local+ environment in TcTyClsDecls, until the real full TyCons can be created+ during desugaring. A desugared program should never have a TcTyCon.++ A challenging piece in all of this is that we end up taking three separate+ passes over every declaration: one in getInitialKind (this pass look only+ at the head, not the body), one in kcTyClDecls (to kind-check the body),+ and a final one in tcTyClDecls (to desugar). In the latter two passes,+ we need to connect the user-written type variables in an LHsQTyVars+ with the variables in the tycon's inferred kind. Because the tycon might+ not have a CUSK, this matching up is, in general, quite hard to do.+ (Look through the git history between Dec 2015 and Apr 2016 for+ TcHsType.splitTelescopeTvs!) Instead of trying, we just store the list+ of type variables to bring into scope in the later passes when we create+ a TcTyCon in getInitialKinds. Much easier this way! These tyvars are+ brought into scope in kcTyClTyVars and tcTyClTyVars, both in TcHsType.++ It is important that the scoped type variables not be zonked, as some+ scoped type variables come into existence as SigTvs. If we zonk, the+ Unique will change and the user-written occurrences won't match up with+ what we expect.++ In a TcTyCon, everything is zonked (except the scoped vars) after+ the kind-checking pass.++************************************************************************+* *+ TyConRepName+* *+********************************************************************* -}++type TyConRepName = Name -- The Name of the top-level declaration+ -- $tcMaybe :: Data.Typeable.Internal.TyCon+ -- $tcMaybe = TyCon { tyConName = "Maybe", ... }++tyConRepName_maybe :: TyCon -> Maybe TyConRepName+tyConRepName_maybe (FunTyCon { tcRepName = rep_nm })+ = Just rep_nm+tyConRepName_maybe (PrimTyCon { primRepName = mb_rep_nm })+ = mb_rep_nm+tyConRepName_maybe (AlgTyCon { algTcParent = parent })+ | VanillaAlgTyCon rep_nm <- parent = Just rep_nm+ | ClassTyCon _ rep_nm <- parent = Just rep_nm+ | UnboxedAlgTyCon rep_nm <- parent = rep_nm+tyConRepName_maybe (FamilyTyCon { famTcFlav = DataFamilyTyCon rep_nm })+ = Just rep_nm+tyConRepName_maybe (PromotedDataCon { tcRepName = rep_nm })+ = Just rep_nm+tyConRepName_maybe _ = Nothing++-- | Make a 'Name' for the 'Typeable' representation of the given wired-in type+mkPrelTyConRepName :: Name -> TyConRepName+-- See Note [Grand plan for Typeable] in 'TcTypeable' in TcTypeable.+mkPrelTyConRepName tc_name -- Prelude tc_name is always External,+ -- so nameModule will work+ = mkExternalName rep_uniq rep_mod rep_occ (nameSrcSpan tc_name)+ where+ name_occ = nameOccName tc_name+ name_mod = nameModule tc_name+ name_uniq = nameUnique tc_name+ rep_uniq | isTcOcc name_occ = tyConRepNameUnique name_uniq+ | otherwise = dataConRepNameUnique name_uniq+ (rep_mod, rep_occ) = tyConRepModOcc name_mod name_occ++-- | The name (and defining module) for the Typeable representation (TyCon) of a+-- type constructor.+--+-- See Note [Grand plan for Typeable] in 'TcTypeable' in TcTypeable.+tyConRepModOcc :: Module -> OccName -> (Module, OccName)+tyConRepModOcc tc_module tc_occ = (rep_module, mkTyConRepOcc tc_occ)+ where+ rep_module+ | tc_module == gHC_PRIM = gHC_TYPES+ | otherwise = tc_module+++{- *********************************************************************+* *+ PrimRep+* *+************************************************************************++Note [rep swamp]++GHC has a rich selection of types that represent "primitive types" of+one kind or another. Each of them makes a different set of+distinctions, and mostly the differences are for good reasons,+although it's probably true that we could merge some of these.++Roughly in order of "includes more information":++ - A Width (cmm/CmmType) is simply a binary value with the specified+ number of bits. It may represent a signed or unsigned integer, a+ floating-point value, or an address.++ data Width = W8 | W16 | W32 | W64 | W80 | W128++ - Size, which is used in the native code generator, is Width ++ floating point information.++ data Size = II8 | II16 | II32 | II64 | FF32 | FF64 | FF80++ it is necessary because e.g. the instruction to move a 64-bit float+ on x86 (movsd) is different from the instruction to move a 64-bit+ integer (movq), so the mov instruction is parameterised by Size.++ - CmmType wraps Width with more information: GC ptr, float, or+ other value.++ data CmmType = CmmType CmmCat Width++ data CmmCat -- "Category" (not exported)+ = GcPtrCat -- GC pointer+ | BitsCat -- Non-pointer+ | FloatCat -- Float++ It is important to have GcPtr information in Cmm, since we generate+ info tables containing pointerhood for the GC from this. As for+ why we have float (and not signed/unsigned) here, see Note [Signed+ vs unsigned].++ - ArgRep makes only the distinctions necessary for the call and+ return conventions of the STG machine. It is essentially CmmType+ + void.++ - PrimRep makes a few more distinctions than ArgRep: it divides+ non-GC-pointers into signed/unsigned and addresses, information+ that is necessary for passing these values to foreign functions.++There's another tension here: whether the type encodes its size in+bytes, or whether its size depends on the machine word size. Width+and CmmType have the size built-in, whereas ArgRep and PrimRep do not.++This means to turn an ArgRep/PrimRep into a CmmType requires DynFlags.++On the other hand, CmmType includes some "nonsense" values, such as+CmmType GcPtrCat W32 on a 64-bit machine.+-}++-- | A 'PrimRep' is an abstraction of a type. It contains information that+-- the code generator needs in order to pass arguments, return results,+-- and store values of this type.+data PrimRep+ = VoidRep+ | LiftedRep+ | UnliftedRep -- ^ Unlifted pointer+ | IntRep -- ^ Signed, word-sized value+ | WordRep -- ^ Unsigned, word-sized value+ | Int64Rep -- ^ Signed, 64 bit value (with 32-bit words only)+ | Word64Rep -- ^ Unsigned, 64 bit value (with 32-bit words only)+ | AddrRep -- ^ A pointer, but /not/ to a Haskell value (use '(Un)liftedRep')+ | FloatRep+ | DoubleRep+ | VecRep Int PrimElemRep -- ^ A vector+ deriving( Eq, Show )++data PrimElemRep+ = Int8ElemRep+ | Int16ElemRep+ | Int32ElemRep+ | Int64ElemRep+ | Word8ElemRep+ | Word16ElemRep+ | Word32ElemRep+ | Word64ElemRep+ | FloatElemRep+ | DoubleElemRep+ deriving( Eq, Show )++instance Outputable PrimRep where+ ppr r = text (show r)++instance Outputable PrimElemRep where+ ppr r = text (show r)++isVoidRep :: PrimRep -> Bool+isVoidRep VoidRep = True+isVoidRep _other = False++isGcPtrRep :: PrimRep -> Bool+isGcPtrRep LiftedRep = True+isGcPtrRep UnliftedRep = True+isGcPtrRep _ = False++-- | Find the size of a 'PrimRep', in words+primRepSizeW :: DynFlags -> PrimRep -> Int+primRepSizeW _ IntRep = 1+primRepSizeW _ WordRep = 1+primRepSizeW dflags Int64Rep = wORD64_SIZE `quot` wORD_SIZE dflags+primRepSizeW dflags Word64Rep = wORD64_SIZE `quot` wORD_SIZE dflags+primRepSizeW _ FloatRep = 1 -- NB. might not take a full word+primRepSizeW dflags DoubleRep = dOUBLE_SIZE dflags `quot` wORD_SIZE dflags+primRepSizeW _ AddrRep = 1+primRepSizeW _ LiftedRep = 1+primRepSizeW _ UnliftedRep = 1+primRepSizeW _ VoidRep = 0+primRepSizeW dflags (VecRep len rep) = len * primElemRepSizeB rep `quot` wORD_SIZE dflags++primElemRepSizeB :: PrimElemRep -> Int+primElemRepSizeB Int8ElemRep = 1+primElemRepSizeB Int16ElemRep = 2+primElemRepSizeB Int32ElemRep = 4+primElemRepSizeB Int64ElemRep = 8+primElemRepSizeB Word8ElemRep = 1+primElemRepSizeB Word16ElemRep = 2+primElemRepSizeB Word32ElemRep = 4+primElemRepSizeB Word64ElemRep = 8+primElemRepSizeB FloatElemRep = 4+primElemRepSizeB DoubleElemRep = 8++-- | Return if Rep stands for floating type,+-- returns Nothing for vector types.+primRepIsFloat :: PrimRep -> Maybe Bool+primRepIsFloat FloatRep = Just True+primRepIsFloat DoubleRep = Just True+primRepIsFloat (VecRep _ _) = Nothing+primRepIsFloat _ = Just False+++{-+************************************************************************+* *+ Field labels+* *+************************************************************************+-}++-- | The labels for the fields of this particular 'TyCon'+tyConFieldLabels :: TyCon -> [FieldLabel]+tyConFieldLabels tc = dFsEnvElts $ tyConFieldLabelEnv tc++-- | The labels for the fields of this particular 'TyCon'+tyConFieldLabelEnv :: TyCon -> FieldLabelEnv+tyConFieldLabelEnv tc+ | isAlgTyCon tc = algTcFields tc+ | otherwise = emptyDFsEnv++-- | Look up a field label belonging to this 'TyCon'+lookupTyConFieldLabel :: FieldLabelString -> TyCon -> Maybe FieldLabel+lookupTyConFieldLabel lbl tc = lookupDFsEnv (tyConFieldLabelEnv tc) lbl++-- | Make a map from strings to FieldLabels from all the data+-- constructors of this algebraic tycon+fieldsOfAlgTcRhs :: AlgTyConRhs -> FieldLabelEnv+fieldsOfAlgTcRhs rhs = mkDFsEnv [ (flLabel fl, fl)+ | fl <- dataConsFields (visibleDataCons rhs) ]+ where+ -- Duplicates in this list will be removed by 'mkFsEnv'+ dataConsFields dcs = concatMap dataConFieldLabels dcs+++{-+************************************************************************+* *+\subsection{TyCon Construction}+* *+************************************************************************++Note: the TyCon constructors all take a Kind as one argument, even though+they could, in principle, work out their Kind from their other arguments.+But to do so they need functions from Types, and that makes a nasty+module mutual-recursion. And they aren't called from many places.+So we compromise, and move their Kind calculation to the call site.+-}++-- | Given the name of the function type constructor and it's kind, create the+-- corresponding 'TyCon'. It is recomended to use 'TyCoRep.funTyCon' if you want+-- this functionality+mkFunTyCon :: Name -> [TyConBinder] -> Name -> TyCon+mkFunTyCon name binders rep_nm+ = FunTyCon {+ tyConUnique = nameUnique name,+ tyConName = name,+ tyConBinders = binders,+ tyConResKind = liftedTypeKind,+ tyConKind = mkTyConKind binders liftedTypeKind,+ tyConArity = length binders,+ tcRepName = rep_nm+ }++-- | This is the making of an algebraic 'TyCon'. Notably, you have to+-- pass in the generic (in the -XGenerics sense) information about the+-- type constructor - you can get hold of it easily (see Generics+-- module)+mkAlgTyCon :: Name+ -> [TyConBinder] -- ^ Binders of the 'TyCon'+ -> Kind -- ^ Result kind+ -> [Role] -- ^ The roles for each TyVar+ -> Maybe CType -- ^ The C type this type corresponds to+ -- when using the CAPI FFI+ -> [PredType] -- ^ Stupid theta: see 'algTcStupidTheta'+ -> AlgTyConRhs -- ^ Information about data constructors+ -> AlgTyConFlav -- ^ What flavour is it?+ -- (e.g. vanilla, type family)+ -> Bool -- ^ Was the 'TyCon' declared with GADT syntax?+ -> TyCon+mkAlgTyCon name binders res_kind roles cType stupid rhs parent gadt_syn+ = AlgTyCon {+ tyConName = name,+ tyConUnique = nameUnique name,+ tyConBinders = binders,+ tyConResKind = res_kind,+ tyConKind = mkTyConKind binders res_kind,+ tyConArity = length binders,+ tyConTyVars = binderVars binders,+ tcRoles = roles,+ tyConCType = cType,+ algTcStupidTheta = stupid,+ algTcRhs = rhs,+ algTcFields = fieldsOfAlgTcRhs rhs,+ algTcParent = ASSERT2( okParent name parent, ppr name $$ ppr parent ) parent,+ algTcGadtSyntax = gadt_syn+ }++-- | Simpler specialization of 'mkAlgTyCon' for classes+mkClassTyCon :: Name -> [TyConBinder]+ -> [Role] -> AlgTyConRhs -> Class+ -> Name -> TyCon+mkClassTyCon name binders roles rhs clas tc_rep_name+ = mkAlgTyCon name binders constraintKind roles Nothing [] rhs+ (ClassTyCon clas tc_rep_name)+ False++mkTupleTyCon :: Name+ -> [TyConBinder]+ -> Kind -- ^ Result kind of the 'TyCon'+ -> Arity -- ^ Arity of the tuple 'TyCon'+ -> DataCon+ -> TupleSort -- ^ Whether the tuple is boxed or unboxed+ -> AlgTyConFlav+ -> TyCon+mkTupleTyCon name binders res_kind arity con sort parent+ = AlgTyCon {+ tyConUnique = nameUnique name,+ tyConName = name,+ tyConBinders = binders,+ tyConTyVars = binderVars binders,+ tyConResKind = res_kind,+ tyConKind = mkTyConKind binders res_kind,+ tyConArity = arity,+ tcRoles = replicate arity Representational,+ tyConCType = Nothing,+ algTcGadtSyntax = False,+ algTcStupidTheta = [],+ algTcRhs = TupleTyCon { data_con = con,+ tup_sort = sort },+ algTcFields = emptyDFsEnv,+ algTcParent = parent+ }++mkSumTyCon :: Name+ -> [TyConBinder]+ -> Kind -- ^ Kind of the resulting 'TyCon'+ -> Arity -- ^ Arity of the sum+ -> [TyVar] -- ^ 'TyVar's scoped over: see 'tyConTyVars'+ -> [DataCon]+ -> AlgTyConFlav+ -> TyCon+mkSumTyCon name binders res_kind arity tyvars cons parent+ = AlgTyCon {+ tyConUnique = nameUnique name,+ tyConName = name,+ tyConBinders = binders,+ tyConTyVars = tyvars,+ tyConResKind = res_kind,+ tyConKind = mkTyConKind binders res_kind,+ tyConArity = arity,+ tcRoles = replicate arity Representational,+ tyConCType = Nothing,+ algTcGadtSyntax = False,+ algTcStupidTheta = [],+ algTcRhs = SumTyCon { data_cons = cons },+ algTcFields = emptyDFsEnv,+ algTcParent = parent+ }++-- | Makes a tycon suitable for use during type-checking.+-- The only real need for this is for printing error messages during+-- a recursive type/class type-checking knot. It has a kind because+-- TcErrors sometimes calls typeKind.+-- See also Note [Kind checking recursive type and class declarations]+-- in TcTyClsDecls.+mkTcTyCon :: Name+ -> [TyConBinder]+ -> Kind -- ^ /result/ kind only+ -> Bool -- ^ Can this be unsaturated?+ -> [TyVar] -- ^ Scoped type variables, see Note [TcTyCon]+ -> TyCon+mkTcTyCon name binders res_kind unsat scoped_tvs+ = TcTyCon { tyConUnique = getUnique name+ , tyConName = name+ , tyConTyVars = binderVars binders+ , tyConBinders = binders+ , tyConResKind = res_kind+ , tyConKind = mkTyConKind binders res_kind+ , tyConUnsat = unsat+ , tyConArity = length binders+ , tcTyConScopedTyVars = scoped_tvs }++-- | Create an unlifted primitive 'TyCon', such as @Int#@.+mkPrimTyCon :: Name -> [TyConBinder]+ -> Kind -- ^ /result/ kind, never levity-polymorphic+ -> [Role] -> TyCon+mkPrimTyCon name binders res_kind roles+ = mkPrimTyCon' name binders res_kind roles True (Just $ mkPrelTyConRepName name)++-- | Kind constructors+mkKindTyCon :: Name -> [TyConBinder]+ -> Kind -- ^ /result/ kind+ -> [Role] -> Name -> TyCon+mkKindTyCon name binders res_kind roles rep_nm+ = tc+ where+ tc = mkPrimTyCon' name binders res_kind roles False (Just rep_nm)++-- | Create a lifted primitive 'TyCon' such as @RealWorld@+mkLiftedPrimTyCon :: Name -> [TyConBinder]+ -> Kind -- ^ /result/ kind+ -> [Role] -> TyCon+mkLiftedPrimTyCon name binders res_kind roles+ = mkPrimTyCon' name binders res_kind roles False (Just rep_nm)+ where rep_nm = mkPrelTyConRepName name++mkPrimTyCon' :: Name -> [TyConBinder]+ -> Kind -- ^ /result/ kind, never levity-polymorphic+ -- (If you need a levity-polymorphic PrimTyCon, change+ -- isTcLevPoly.)+ -> [Role]+ -> Bool -> Maybe TyConRepName -> TyCon+mkPrimTyCon' name binders res_kind roles is_unlifted rep_nm+ = PrimTyCon {+ tyConName = name,+ tyConUnique = nameUnique name,+ tyConBinders = binders,+ tyConResKind = res_kind,+ tyConKind = mkTyConKind binders res_kind,+ tyConArity = length roles,+ tcRoles = roles,+ isUnlifted = is_unlifted,+ primRepName = rep_nm+ }++-- | Create a type synonym 'TyCon'+mkSynonymTyCon :: Name -> [TyConBinder] -> Kind -- ^ /result/ kind+ -> [Role] -> Type -> Bool -> Bool -> TyCon+mkSynonymTyCon name binders res_kind roles rhs is_tau is_fam_free+ = SynonymTyCon {+ tyConName = name,+ tyConUnique = nameUnique name,+ tyConBinders = binders,+ tyConResKind = res_kind,+ tyConKind = mkTyConKind binders res_kind,+ tyConArity = length binders,+ tyConTyVars = binderVars binders,+ tcRoles = roles,+ synTcRhs = rhs,+ synIsTau = is_tau,+ synIsFamFree = is_fam_free+ }++-- | Create a type family 'TyCon'+mkFamilyTyCon :: Name -> [TyConBinder] -> Kind -- ^ /result/ kind+ -> Maybe Name -> FamTyConFlav+ -> Maybe Class -> Injectivity -> TyCon+mkFamilyTyCon name binders res_kind resVar flav parent inj+ = FamilyTyCon+ { tyConUnique = nameUnique name+ , tyConName = name+ , tyConBinders = binders+ , tyConResKind = res_kind+ , tyConKind = mkTyConKind binders res_kind+ , tyConArity = length binders+ , tyConTyVars = binderVars binders+ , famTcResVar = resVar+ , famTcFlav = flav+ , famTcParent = parent+ , famTcInj = inj+ }+++-- | Create a promoted data constructor 'TyCon'+-- Somewhat dodgily, we give it the same Name+-- as the data constructor itself; when we pretty-print+-- the TyCon we add a quote; see the Outputable TyCon instance+mkPromotedDataCon :: DataCon -> Name -> TyConRepName+ -> [TyConBinder] -> Kind -> [Role]+ -> RuntimeRepInfo -> TyCon+mkPromotedDataCon con name rep_name binders res_kind roles rep_info+ = PromotedDataCon {+ tyConUnique = nameUnique name,+ tyConName = name,+ tyConArity = length roles,+ tcRoles = roles,+ tyConBinders = binders,+ tyConResKind = res_kind,+ tyConKind = mkTyConKind binders res_kind,+ dataCon = con,+ tcRepName = rep_name,+ promDcRepInfo = rep_info+ }++isFunTyCon :: TyCon -> Bool+isFunTyCon (FunTyCon {}) = True+isFunTyCon _ = False++-- | Test if the 'TyCon' is algebraic but abstract (invisible data constructors)+isAbstractTyCon :: TyCon -> Bool+isAbstractTyCon (AlgTyCon { algTcRhs = AbstractTyCon }) = True+isAbstractTyCon _ = False++-- | Make an fake, recovery 'TyCon' from an existing one.+-- Used when recovering from errors+makeRecoveryTyCon :: TyCon -> TyCon+makeRecoveryTyCon tc+ = mkTcTyCon (tyConName tc)+ (tyConBinders tc) (tyConResKind tc)+ (mightBeUnsaturatedTyCon tc) [{- no scoped vars -}]++-- | Does this 'TyCon' represent something that cannot be defined in Haskell?+isPrimTyCon :: TyCon -> Bool+isPrimTyCon (PrimTyCon {}) = True+isPrimTyCon _ = False++-- | Is this 'TyCon' unlifted (i.e. cannot contain bottom)? Note that this can+-- only be true for primitive and unboxed-tuple 'TyCon's+isUnliftedTyCon :: TyCon -> Bool+isUnliftedTyCon (PrimTyCon {isUnlifted = is_unlifted})+ = is_unlifted+isUnliftedTyCon (AlgTyCon { algTcRhs = rhs } )+ | TupleTyCon { tup_sort = sort } <- rhs+ = not (isBoxed (tupleSortBoxity sort))+isUnliftedTyCon (AlgTyCon { algTcRhs = rhs } )+ | SumTyCon {} <- rhs+ = True+isUnliftedTyCon _ = False++-- | Returns @True@ if the supplied 'TyCon' resulted from either a+-- @data@ or @newtype@ declaration+isAlgTyCon :: TyCon -> Bool+isAlgTyCon (AlgTyCon {}) = True+isAlgTyCon _ = False++-- | Returns @True@ for vanilla AlgTyCons -- that is, those created+-- with a @data@ or @newtype@ declaration.+isVanillaAlgTyCon :: TyCon -> Bool+isVanillaAlgTyCon (AlgTyCon { algTcParent = VanillaAlgTyCon _ }) = True+isVanillaAlgTyCon _ = False++isDataTyCon :: TyCon -> Bool+-- ^ Returns @True@ for data types that are /definitely/ represented by+-- heap-allocated constructors. These are scrutinised by Core-level+-- @case@ expressions, and they get info tables allocated for them.+--+-- Generally, the function will be true for all @data@ types and false+-- for @newtype@s, unboxed tuples, unboxed sums and type family+-- 'TyCon's. But it is not guaranteed to return @True@ in all cases+-- that it could.+--+-- NB: for a data type family, only the /instance/ 'TyCon's+-- get an info table. The family declaration 'TyCon' does not+isDataTyCon (AlgTyCon {algTcRhs = rhs})+ = case rhs of+ TupleTyCon { tup_sort = sort }+ -> isBoxed (tupleSortBoxity sort)+ SumTyCon {} -> False+ DataTyCon {} -> True+ NewTyCon {} -> False+ AbstractTyCon {} -> False -- We don't know, so return False+isDataTyCon _ = False++-- | 'isInjectiveTyCon' is true of 'TyCon's for which this property holds+-- (where X is the role passed in):+-- If (T a1 b1 c1) ~X (T a2 b2 c2), then (a1 ~X1 a2), (b1 ~X2 b2), and (c1 ~X3 c2)+-- (where X1, X2, and X3, are the roles given by tyConRolesX tc X)+-- See also Note [Decomposing equality] in TcCanonical+isInjectiveTyCon :: TyCon -> Role -> Bool+isInjectiveTyCon _ Phantom = False+isInjectiveTyCon (FunTyCon {}) _ = True+isInjectiveTyCon (AlgTyCon {}) Nominal = True+isInjectiveTyCon (AlgTyCon {algTcRhs = rhs}) Representational+ = isGenInjAlgRhs rhs+isInjectiveTyCon (SynonymTyCon {}) _ = False+isInjectiveTyCon (FamilyTyCon { famTcFlav = DataFamilyTyCon _ })+ Nominal = True+isInjectiveTyCon (FamilyTyCon { famTcInj = Injective inj }) Nominal = and inj+isInjectiveTyCon (FamilyTyCon {}) _ = False+isInjectiveTyCon (PrimTyCon {}) _ = True+isInjectiveTyCon (PromotedDataCon {}) _ = True+isInjectiveTyCon (TcTyCon {}) _ = True+ -- Reply True for TcTyCon to minimise knock on type errors+ -- See Note [TcTyCon] item (1)++-- | 'isGenerativeTyCon' is true of 'TyCon's for which this property holds+-- (where X is the role passed in):+-- If (T tys ~X t), then (t's head ~X T).+-- See also Note [Decomposing equality] in TcCanonical+isGenerativeTyCon :: TyCon -> Role -> Bool+isGenerativeTyCon (FamilyTyCon { famTcFlav = DataFamilyTyCon _ }) Nominal = True+isGenerativeTyCon (FamilyTyCon {}) _ = False+ -- in all other cases, injectivity implies generativity+isGenerativeTyCon tc r = isInjectiveTyCon tc r++-- | Is this an 'AlgTyConRhs' of a 'TyCon' that is generative and injective+-- with respect to representational equality?+isGenInjAlgRhs :: AlgTyConRhs -> Bool+isGenInjAlgRhs (TupleTyCon {}) = True+isGenInjAlgRhs (SumTyCon {}) = True+isGenInjAlgRhs (DataTyCon {}) = True+isGenInjAlgRhs (AbstractTyCon {}) = False+isGenInjAlgRhs (NewTyCon {}) = False++-- | Is this 'TyCon' that for a @newtype@+isNewTyCon :: TyCon -> Bool+isNewTyCon (AlgTyCon {algTcRhs = NewTyCon {}}) = True+isNewTyCon _ = False++-- | Take a 'TyCon' apart into the 'TyVar's it scopes over, the 'Type' it expands+-- into, and (possibly) a coercion from the representation type to the @newtype@.+-- Returns @Nothing@ if this is not possible.+unwrapNewTyCon_maybe :: TyCon -> Maybe ([TyVar], Type, CoAxiom Unbranched)+unwrapNewTyCon_maybe (AlgTyCon { tyConTyVars = tvs,+ algTcRhs = NewTyCon { nt_co = co,+ nt_rhs = rhs }})+ = Just (tvs, rhs, co)+unwrapNewTyCon_maybe _ = Nothing++unwrapNewTyConEtad_maybe :: TyCon -> Maybe ([TyVar], Type, CoAxiom Unbranched)+unwrapNewTyConEtad_maybe (AlgTyCon { algTcRhs = NewTyCon { nt_co = co,+ nt_etad_rhs = (tvs,rhs) }})+ = Just (tvs, rhs, co)+unwrapNewTyConEtad_maybe _ = Nothing++isProductTyCon :: TyCon -> Bool+-- True of datatypes or newtypes that have+-- one, non-existential, data constructor+-- See Note [Product types]+isProductTyCon tc@(AlgTyCon {})+ = case algTcRhs tc of+ TupleTyCon {} -> True+ DataTyCon{ data_cons = [data_con] }+ -> null (dataConExTyVars data_con)+ NewTyCon {} -> True+ _ -> False+isProductTyCon _ = False++isDataProductTyCon_maybe :: TyCon -> Maybe DataCon+-- True of datatypes (not newtypes) with+-- one, vanilla, data constructor+-- See Note [Product types]+isDataProductTyCon_maybe (AlgTyCon { algTcRhs = rhs })+ = case rhs of+ DataTyCon { data_cons = [con] }+ | null (dataConExTyVars con) -- non-existential+ -> Just con+ TupleTyCon { data_con = con }+ -> Just con+ _ -> Nothing+isDataProductTyCon_maybe _ = Nothing++isDataSumTyCon_maybe :: TyCon -> Maybe [DataCon]+isDataSumTyCon_maybe (AlgTyCon { algTcRhs = rhs })+ = case rhs of+ DataTyCon { data_cons = cons }+ | length cons > 1+ , all (null . dataConExTyVars) cons -- FIXME(osa): Why do we need this?+ -> Just cons+ SumTyCon { data_cons = cons }+ | all (null . dataConExTyVars) cons -- FIXME(osa): Why do we need this?+ -> Just cons+ _ -> Nothing+isDataSumTyCon_maybe _ = Nothing++{- Note [Product types]+~~~~~~~~~~~~~~~~~~~~~~~+A product type is+ * A data type (not a newtype)+ * With one, boxed data constructor+ * That binds no existential type variables++The main point is that product types are amenable to unboxing for+ * Strict function calls; we can transform+ f (D a b) = e+ to+ fw a b = e+ via the worker/wrapper transformation. (Question: couldn't this+ work for existentials too?)++ * CPR for function results; we can transform+ f x y = let ... in D a b+ to+ fw x y = let ... in (# a, b #)++Note that the data constructor /can/ have evidence arguments: equality+constraints, type classes etc. So it can be GADT. These evidence+arguments are simply value arguments, and should not get in the way.+-}+++-- | Is this a 'TyCon' representing a regular H98 type synonym (@type@)?+isTypeSynonymTyCon :: TyCon -> Bool+isTypeSynonymTyCon (SynonymTyCon {}) = True+isTypeSynonymTyCon _ = False++isTauTyCon :: TyCon -> Bool+isTauTyCon (SynonymTyCon { synIsTau = is_tau }) = is_tau+isTauTyCon _ = True++isFamFreeTyCon :: TyCon -> Bool+isFamFreeTyCon (SynonymTyCon { synIsFamFree = fam_free }) = fam_free+isFamFreeTyCon (FamilyTyCon { famTcFlav = flav }) = isDataFamFlav flav+isFamFreeTyCon _ = True++-- As for newtypes, it is in some contexts important to distinguish between+-- closed synonyms and synonym families, as synonym families have no unique+-- right hand side to which a synonym family application can expand.+--++-- | True iff we can decompose (T a b c) into ((T a b) c)+-- I.e. is it injective and generative w.r.t nominal equality?+-- That is, if (T a b) ~N d e f, is it always the case that+-- (T ~N d), (a ~N e) and (b ~N f)?+-- Specifically NOT true of synonyms (open and otherwise)+--+-- It'd be unusual to call mightBeUnsaturatedTyCon on a regular H98+-- type synonym, because you should probably have expanded it first+-- But regardless, it's not decomposable+mightBeUnsaturatedTyCon :: TyCon -> Bool+mightBeUnsaturatedTyCon (SynonymTyCon {}) = False+mightBeUnsaturatedTyCon (FamilyTyCon { famTcFlav = flav}) = isDataFamFlav flav+mightBeUnsaturatedTyCon (TcTyCon { tyConUnsat = unsat }) = unsat+mightBeUnsaturatedTyCon _other = True++-- | Is this an algebraic 'TyCon' declared with the GADT syntax?+isGadtSyntaxTyCon :: TyCon -> Bool+isGadtSyntaxTyCon (AlgTyCon { algTcGadtSyntax = res }) = res+isGadtSyntaxTyCon _ = False++-- | Is this an algebraic 'TyCon' which is just an enumeration of values?+isEnumerationTyCon :: TyCon -> Bool+-- See Note [Enumeration types] in TyCon+isEnumerationTyCon (AlgTyCon { tyConArity = arity, algTcRhs = rhs })+ = case rhs of+ DataTyCon { is_enum = res } -> res+ TupleTyCon {} -> arity == 0+ _ -> False+isEnumerationTyCon _ = False++-- | Is this a 'TyCon', synonym or otherwise, that defines a family?+isFamilyTyCon :: TyCon -> Bool+isFamilyTyCon (FamilyTyCon {}) = True+isFamilyTyCon _ = False++-- | Is this a 'TyCon', synonym or otherwise, that defines a family with+-- instances?+isOpenFamilyTyCon :: TyCon -> Bool+isOpenFamilyTyCon (FamilyTyCon {famTcFlav = flav })+ | OpenSynFamilyTyCon <- flav = True+ | DataFamilyTyCon {} <- flav = True+isOpenFamilyTyCon _ = False++-- | Is this a synonym 'TyCon' that can have may have further instances appear?+isTypeFamilyTyCon :: TyCon -> Bool+isTypeFamilyTyCon (FamilyTyCon { famTcFlav = flav }) = not (isDataFamFlav flav)+isTypeFamilyTyCon _ = False++-- | Is this a synonym 'TyCon' that can have may have further instances appear?+isDataFamilyTyCon :: TyCon -> Bool+isDataFamilyTyCon (FamilyTyCon { famTcFlav = flav }) = isDataFamFlav flav+isDataFamilyTyCon _ = False++-- | Is this an open type family TyCon?+isOpenTypeFamilyTyCon :: TyCon -> Bool+isOpenTypeFamilyTyCon (FamilyTyCon {famTcFlav = OpenSynFamilyTyCon }) = True+isOpenTypeFamilyTyCon _ = False++-- | Is this a non-empty closed type family? Returns 'Nothing' for+-- abstract or empty closed families.+isClosedSynFamilyTyConWithAxiom_maybe :: TyCon -> Maybe (CoAxiom Branched)+isClosedSynFamilyTyConWithAxiom_maybe+ (FamilyTyCon {famTcFlav = ClosedSynFamilyTyCon mb}) = mb+isClosedSynFamilyTyConWithAxiom_maybe _ = Nothing++-- | Try to read the injectivity information from a FamilyTyCon.+-- For every other TyCon this function panics.+familyTyConInjectivityInfo :: TyCon -> Injectivity+familyTyConInjectivityInfo (FamilyTyCon { famTcInj = inj }) = inj+familyTyConInjectivityInfo _ = panic "familyTyConInjectivityInfo"++isBuiltInSynFamTyCon_maybe :: TyCon -> Maybe BuiltInSynFamily+isBuiltInSynFamTyCon_maybe+ (FamilyTyCon {famTcFlav = BuiltInSynFamTyCon ops }) = Just ops+isBuiltInSynFamTyCon_maybe _ = Nothing++isDataFamFlav :: FamTyConFlav -> Bool+isDataFamFlav (DataFamilyTyCon {}) = True -- Data family+isDataFamFlav _ = False -- Type synonym family++-- | Are we able to extract information 'TyVar' to class argument list+-- mapping from a given 'TyCon'?+isTyConAssoc :: TyCon -> Bool+isTyConAssoc tc = isJust (tyConAssoc_maybe tc)++tyConAssoc_maybe :: TyCon -> Maybe Class+tyConAssoc_maybe (FamilyTyCon { famTcParent = mb_cls }) = mb_cls+tyConAssoc_maybe _ = Nothing++-- The unit tycon didn't used to be classed as a tuple tycon+-- but I thought that was silly so I've undone it+-- If it can't be for some reason, it should be a AlgTyCon+isTupleTyCon :: TyCon -> Bool+-- ^ Does this 'TyCon' represent a tuple?+--+-- NB: when compiling @Data.Tuple@, the tycons won't reply @True@ to+-- 'isTupleTyCon', because they are built as 'AlgTyCons'. However they+-- get spat into the interface file as tuple tycons, so I don't think+-- it matters.+isTupleTyCon (AlgTyCon { algTcRhs = TupleTyCon {} }) = True+isTupleTyCon _ = False++tyConTuple_maybe :: TyCon -> Maybe TupleSort+tyConTuple_maybe (AlgTyCon { algTcRhs = rhs })+ | TupleTyCon { tup_sort = sort} <- rhs = Just sort+tyConTuple_maybe _ = Nothing++-- | Is this the 'TyCon' for an unboxed tuple?+isUnboxedTupleTyCon :: TyCon -> Bool+isUnboxedTupleTyCon (AlgTyCon { algTcRhs = rhs })+ | TupleTyCon { tup_sort = sort } <- rhs+ = not (isBoxed (tupleSortBoxity sort))+isUnboxedTupleTyCon _ = False++-- | Is this the 'TyCon' for a boxed tuple?+isBoxedTupleTyCon :: TyCon -> Bool+isBoxedTupleTyCon (AlgTyCon { algTcRhs = rhs })+ | TupleTyCon { tup_sort = sort } <- rhs+ = isBoxed (tupleSortBoxity sort)+isBoxedTupleTyCon _ = False++-- | Is this the 'TyCon' for an unboxed sum?+isUnboxedSumTyCon :: TyCon -> Bool+isUnboxedSumTyCon (AlgTyCon { algTcRhs = rhs })+ | SumTyCon {} <- rhs+ = True+isUnboxedSumTyCon _ = False++-- | Is this the 'TyCon' for a /promoted/ tuple?+isPromotedTupleTyCon :: TyCon -> Bool+isPromotedTupleTyCon tyCon+ | Just dataCon <- isPromotedDataCon_maybe tyCon+ , isTupleTyCon (dataConTyCon dataCon) = True+ | otherwise = False++-- | Is this a PromotedDataCon?+isPromotedDataCon :: TyCon -> Bool+isPromotedDataCon (PromotedDataCon {}) = True+isPromotedDataCon _ = False++-- | Retrieves the promoted DataCon if this is a PromotedDataCon;+isPromotedDataCon_maybe :: TyCon -> Maybe DataCon+isPromotedDataCon_maybe (PromotedDataCon { dataCon = dc }) = Just dc+isPromotedDataCon_maybe _ = Nothing++-- | Is this tycon really meant for use at the kind level? That is,+-- should it be permitted without -XDataKinds?+isKindTyCon :: TyCon -> Bool+isKindTyCon tc = getUnique tc `elementOfUniqSet` kindTyConKeys++-- | These TyCons should be allowed at the kind level, even without+-- -XDataKinds.+kindTyConKeys :: UniqSet Unique+kindTyConKeys = unionManyUniqSets+ ( mkUniqSet [ liftedTypeKindTyConKey, starKindTyConKey, unicodeStarKindTyConKey+ , constraintKindTyConKey, tYPETyConKey ]+ : map (mkUniqSet . tycon_with_datacons) [ runtimeRepTyCon+ , vecCountTyCon, vecElemTyCon ] )+ where+ tycon_with_datacons tc = getUnique tc : map getUnique (tyConDataCons tc)++isLiftedTypeKindTyConName :: Name -> Bool+isLiftedTypeKindTyConName+ = (`hasKey` liftedTypeKindTyConKey) <||>+ (`hasKey` starKindTyConKey) <||>+ (`hasKey` unicodeStarKindTyConKey)++-- | Identifies implicit tycons that, in particular, do not go into interface+-- files (because they are implicitly reconstructed when the interface is+-- read).+--+-- Note that:+--+-- * Associated families are implicit, as they are re-constructed from+-- the class declaration in which they reside, and+--+-- * Family instances are /not/ implicit as they represent the instance body+-- (similar to a @dfun@ does that for a class instance).+--+-- * Tuples are implicit iff they have a wired-in name+-- (namely: boxed and unboxed tupeles are wired-in and implicit,+-- but constraint tuples are not)+isImplicitTyCon :: TyCon -> Bool+isImplicitTyCon (FunTyCon {}) = True+isImplicitTyCon (PrimTyCon {}) = True+isImplicitTyCon (PromotedDataCon {}) = True+isImplicitTyCon (AlgTyCon { algTcRhs = rhs, tyConName = name })+ | TupleTyCon {} <- rhs = isWiredInName name+ | SumTyCon {} <- rhs = True+ | otherwise = False+isImplicitTyCon (FamilyTyCon { famTcParent = parent }) = isJust parent+isImplicitTyCon (SynonymTyCon {}) = False+isImplicitTyCon (TcTyCon {}) = False++tyConCType_maybe :: TyCon -> Maybe CType+tyConCType_maybe tc@(AlgTyCon {}) = tyConCType tc+tyConCType_maybe _ = Nothing++-- | Is this a TcTyCon? (That is, one only used during type-checking?)+isTcTyCon :: TyCon -> Bool+isTcTyCon (TcTyCon {}) = True+isTcTyCon _ = False++-- | Could this TyCon ever be levity-polymorphic when fully applied?+-- True is safe. False means we're sure. Does only a quick check+-- based on the TyCon's category.+-- Precondition: The fully-applied TyCon has kind (TYPE blah)+isTcLevPoly :: TyCon -> Bool+isTcLevPoly FunTyCon{} = False+isTcLevPoly (AlgTyCon { algTcParent = UnboxedAlgTyCon _ }) = True+isTcLevPoly AlgTyCon{} = False+isTcLevPoly SynonymTyCon{} = True+isTcLevPoly FamilyTyCon{} = True+isTcLevPoly PrimTyCon{} = False+isTcLevPoly TcTyCon{} = False+isTcLevPoly tc@PromotedDataCon{} = pprPanic "isTcLevPoly datacon" (ppr tc)++{-+-----------------------------------------------+-- Expand type-constructor applications+-----------------------------------------------+-}++expandSynTyCon_maybe+ :: TyCon+ -> [tyco] -- ^ Arguments to 'TyCon'+ -> Maybe ([(TyVar,tyco)],+ Type,+ [tyco]) -- ^ Returns a 'TyVar' substitution, the body+ -- type of the synonym (not yet substituted)+ -- and any arguments remaining from the+ -- application++-- ^ Expand a type synonym application, if any+expandSynTyCon_maybe tc tys+ | SynonymTyCon { tyConTyVars = tvs, synTcRhs = rhs, tyConArity = arity } <- tc+ = case arity `compare` length tys of+ LT -> Just (tvs `zip` tys, rhs, drop arity tys)+ EQ -> Just (tvs `zip` tys, rhs, [])+ GT -> Nothing+ | otherwise+ = Nothing++----------------++-- | Check if the tycon actually refers to a proper `data` or `newtype`+-- with user defined constructors rather than one from a class or other+-- construction.+isTyConWithSrcDataCons :: TyCon -> Bool+isTyConWithSrcDataCons (AlgTyCon { algTcRhs = rhs, algTcParent = parent }) =+ case rhs of+ DataTyCon {} -> isSrcParent+ NewTyCon {} -> isSrcParent+ TupleTyCon {} -> isSrcParent+ _ -> False+ where+ isSrcParent = isNoParent parent+isTyConWithSrcDataCons _ = False+++-- | As 'tyConDataCons_maybe', but returns the empty list of constructors if no+-- constructors could be found+tyConDataCons :: TyCon -> [DataCon]+-- It's convenient for tyConDataCons to return the+-- empty list for type synonyms etc+tyConDataCons tycon = tyConDataCons_maybe tycon `orElse` []++-- | Determine the 'DataCon's originating from the given 'TyCon', if the 'TyCon'+-- is the sort that can have any constructors (note: this does not include+-- abstract algebraic types)+tyConDataCons_maybe :: TyCon -> Maybe [DataCon]+tyConDataCons_maybe (AlgTyCon {algTcRhs = rhs})+ = case rhs of+ DataTyCon { data_cons = cons } -> Just cons+ NewTyCon { data_con = con } -> Just [con]+ TupleTyCon { data_con = con } -> Just [con]+ SumTyCon { data_cons = cons } -> Just cons+ _ -> Nothing+tyConDataCons_maybe _ = Nothing++-- | If the given 'TyCon' has a /single/ data constructor, i.e. it is a @data@+-- type with one alternative, a tuple type or a @newtype@ then that constructor+-- is returned. If the 'TyCon' has more than one constructor, or represents a+-- primitive or function type constructor then @Nothing@ is returned. In any+-- other case, the function panics+tyConSingleDataCon_maybe :: TyCon -> Maybe DataCon+tyConSingleDataCon_maybe (AlgTyCon { algTcRhs = rhs })+ = case rhs of+ DataTyCon { data_cons = [c] } -> Just c+ TupleTyCon { data_con = c } -> Just c+ NewTyCon { data_con = c } -> Just c+ _ -> Nothing+tyConSingleDataCon_maybe _ = Nothing++tyConSingleDataCon :: TyCon -> DataCon+tyConSingleDataCon tc+ = case tyConSingleDataCon_maybe tc of+ Just c -> c+ Nothing -> pprPanic "tyConDataCon" (ppr tc)++tyConSingleAlgDataCon_maybe :: TyCon -> Maybe DataCon+-- Returns (Just con) for single-constructor+-- *algebraic* data types *not* newtypes+tyConSingleAlgDataCon_maybe (AlgTyCon { algTcRhs = rhs })+ = case rhs of+ DataTyCon { data_cons = [c] } -> Just c+ TupleTyCon { data_con = c } -> Just c+ _ -> Nothing+tyConSingleAlgDataCon_maybe _ = Nothing++-- | Determine the number of value constructors a 'TyCon' has. Panics if the+-- 'TyCon' is not algebraic or a tuple+tyConFamilySize :: TyCon -> Int+tyConFamilySize tc@(AlgTyCon { algTcRhs = rhs })+ = case rhs of+ DataTyCon { data_cons = cons } -> length cons+ NewTyCon {} -> 1+ TupleTyCon {} -> 1+ SumTyCon { data_cons = cons } -> length cons+ _ -> pprPanic "tyConFamilySize 1" (ppr tc)+tyConFamilySize tc = pprPanic "tyConFamilySize 2" (ppr tc)++-- | Extract an 'AlgTyConRhs' with information about data constructors from an+-- algebraic or tuple 'TyCon'. Panics for any other sort of 'TyCon'+algTyConRhs :: TyCon -> AlgTyConRhs+algTyConRhs (AlgTyCon {algTcRhs = rhs}) = rhs+algTyConRhs other = pprPanic "algTyConRhs" (ppr other)++-- | Extract type variable naming the result of injective type family+tyConFamilyResVar_maybe :: TyCon -> Maybe Name+tyConFamilyResVar_maybe (FamilyTyCon {famTcResVar = res}) = res+tyConFamilyResVar_maybe _ = Nothing++-- | Get the list of roles for the type parameters of a TyCon+tyConRoles :: TyCon -> [Role]+-- See also Note [TyCon Role signatures]+tyConRoles tc+ = case tc of+ { FunTyCon {} -> const_role Representational+ ; AlgTyCon { tcRoles = roles } -> roles+ ; SynonymTyCon { tcRoles = roles } -> roles+ ; FamilyTyCon {} -> const_role Nominal+ ; PrimTyCon { tcRoles = roles } -> roles+ ; PromotedDataCon { tcRoles = roles } -> roles+ ; TcTyCon {} -> const_role Nominal+ }+ where+ const_role r = replicate (tyConArity tc) r++-- | Extract the bound type variables and type expansion of a type synonym+-- 'TyCon'. Panics if the 'TyCon' is not a synonym+newTyConRhs :: TyCon -> ([TyVar], Type)+newTyConRhs (AlgTyCon {tyConTyVars = tvs, algTcRhs = NewTyCon { nt_rhs = rhs }})+ = (tvs, rhs)+newTyConRhs tycon = pprPanic "newTyConRhs" (ppr tycon)++-- | The number of type parameters that need to be passed to a newtype to+-- resolve it. May be less than in the definition if it can be eta-contracted.+newTyConEtadArity :: TyCon -> Int+newTyConEtadArity (AlgTyCon {algTcRhs = NewTyCon { nt_etad_rhs = tvs_rhs }})+ = length (fst tvs_rhs)+newTyConEtadArity tycon = pprPanic "newTyConEtadArity" (ppr tycon)++-- | Extract the bound type variables and type expansion of an eta-contracted+-- type synonym 'TyCon'. Panics if the 'TyCon' is not a synonym+newTyConEtadRhs :: TyCon -> ([TyVar], Type)+newTyConEtadRhs (AlgTyCon {algTcRhs = NewTyCon { nt_etad_rhs = tvs_rhs }}) = tvs_rhs+newTyConEtadRhs tycon = pprPanic "newTyConEtadRhs" (ppr tycon)++-- | Extracts the @newtype@ coercion from such a 'TyCon', which can be used to+-- construct something with the @newtype@s type from its representation type+-- (right hand side). If the supplied 'TyCon' is not a @newtype@, returns+-- @Nothing@+newTyConCo_maybe :: TyCon -> Maybe (CoAxiom Unbranched)+newTyConCo_maybe (AlgTyCon {algTcRhs = NewTyCon { nt_co = co }}) = Just co+newTyConCo_maybe _ = Nothing++newTyConCo :: TyCon -> CoAxiom Unbranched+newTyConCo tc = case newTyConCo_maybe tc of+ Just co -> co+ Nothing -> pprPanic "newTyConCo" (ppr tc)++newTyConDataCon_maybe :: TyCon -> Maybe DataCon+newTyConDataCon_maybe (AlgTyCon {algTcRhs = NewTyCon { data_con = con }}) = Just con+newTyConDataCon_maybe _ = Nothing++-- | Find the \"stupid theta\" of the 'TyCon'. A \"stupid theta\" is the context+-- to the left of an algebraic type declaration, e.g. @Eq a@ in the declaration+-- @data Eq a => T a ...@+tyConStupidTheta :: TyCon -> [PredType]+tyConStupidTheta (AlgTyCon {algTcStupidTheta = stupid}) = stupid+tyConStupidTheta tycon = pprPanic "tyConStupidTheta" (ppr tycon)++-- | Extract the 'TyVar's bound by a vanilla type synonym+-- and the corresponding (unsubstituted) right hand side.+synTyConDefn_maybe :: TyCon -> Maybe ([TyVar], Type)+synTyConDefn_maybe (SynonymTyCon {tyConTyVars = tyvars, synTcRhs = ty})+ = Just (tyvars, ty)+synTyConDefn_maybe _ = Nothing++-- | Extract the information pertaining to the right hand side of a type synonym+-- (@type@) declaration.+synTyConRhs_maybe :: TyCon -> Maybe Type+synTyConRhs_maybe (SynonymTyCon {synTcRhs = rhs}) = Just rhs+synTyConRhs_maybe _ = Nothing++-- | Extract the flavour of a type family (with all the extra information that+-- it carries)+famTyConFlav_maybe :: TyCon -> Maybe FamTyConFlav+famTyConFlav_maybe (FamilyTyCon {famTcFlav = flav}) = Just flav+famTyConFlav_maybe _ = Nothing++-- | Is this 'TyCon' that for a class instance?+isClassTyCon :: TyCon -> Bool+isClassTyCon (AlgTyCon {algTcParent = ClassTyCon {}}) = True+isClassTyCon _ = False++-- | If this 'TyCon' is that for a class instance, return the class it is for.+-- Otherwise returns @Nothing@+tyConClass_maybe :: TyCon -> Maybe Class+tyConClass_maybe (AlgTyCon {algTcParent = ClassTyCon clas _}) = Just clas+tyConClass_maybe _ = Nothing++-- | Return the associated types of the 'TyCon', if any+tyConATs :: TyCon -> [TyCon]+tyConATs (AlgTyCon {algTcParent = ClassTyCon clas _}) = classATs clas+tyConATs _ = []++----------------------------------------------------------------------------+-- | Is this 'TyCon' that for a data family instance?+isFamInstTyCon :: TyCon -> Bool+isFamInstTyCon (AlgTyCon {algTcParent = DataFamInstTyCon {} })+ = True+isFamInstTyCon _ = False++tyConFamInstSig_maybe :: TyCon -> Maybe (TyCon, [Type], CoAxiom Unbranched)+tyConFamInstSig_maybe (AlgTyCon {algTcParent = DataFamInstTyCon ax f ts })+ = Just (f, ts, ax)+tyConFamInstSig_maybe _ = Nothing++-- | If this 'TyCon' is that of a data family instance, return the family in question+-- and the instance types. Otherwise, return @Nothing@+tyConFamInst_maybe :: TyCon -> Maybe (TyCon, [Type])+tyConFamInst_maybe (AlgTyCon {algTcParent = DataFamInstTyCon _ f ts })+ = Just (f, ts)+tyConFamInst_maybe _ = Nothing++-- | If this 'TyCon' is that of a data family instance, return a 'TyCon' which+-- represents a coercion identifying the representation type with the type+-- instance family. Otherwise, return @Nothing@+tyConFamilyCoercion_maybe :: TyCon -> Maybe (CoAxiom Unbranched)+tyConFamilyCoercion_maybe (AlgTyCon {algTcParent = DataFamInstTyCon ax _ _ })+ = Just ax+tyConFamilyCoercion_maybe _ = Nothing++-- | Extract any 'RuntimeRepInfo' from this TyCon+tyConRuntimeRepInfo :: TyCon -> RuntimeRepInfo+tyConRuntimeRepInfo (PromotedDataCon { promDcRepInfo = rri }) = rri+tyConRuntimeRepInfo _ = NoRRI+ -- could panic in that second case. But Douglas Adams told me not to.++{-+************************************************************************+* *+\subsection[TyCon-instances]{Instance declarations for @TyCon@}+* *+************************************************************************++@TyCon@s are compared by comparing their @Unique@s.+-}++instance Eq TyCon where+ a == b = getUnique a == getUnique b+ a /= b = getUnique a /= getUnique b++instance Uniquable TyCon where+ getUnique tc = tyConUnique tc++instance Outputable TyCon where+ -- At the moment a promoted TyCon has the same Name as its+ -- corresponding TyCon, so we add the quote to distinguish it here+ ppr tc = pprPromotionQuote tc <> ppr (tyConName tc)++tyConFlavour :: TyCon -> String+tyConFlavour (AlgTyCon { algTcParent = parent, algTcRhs = rhs })+ | ClassTyCon _ _ <- parent = "class"+ | otherwise = case rhs of+ TupleTyCon { tup_sort = sort }+ | isBoxed (tupleSortBoxity sort) -> "tuple"+ | otherwise -> "unboxed tuple"+ SumTyCon {} -> "unboxed sum"+ DataTyCon {} -> "data type"+ NewTyCon {} -> "newtype"+ AbstractTyCon {} -> "abstract type"+tyConFlavour (FamilyTyCon { famTcFlav = flav })+ | isDataFamFlav flav = "data family"+ | otherwise = "type family"+tyConFlavour (SynonymTyCon {}) = "type synonym"+tyConFlavour (FunTyCon {}) = "built-in type"+tyConFlavour (PrimTyCon {}) = "built-in type"+tyConFlavour (PromotedDataCon {}) = "promoted data constructor"+tyConFlavour tc@(TcTyCon {})+ = pprPanic "tyConFlavour sees a TcTyCon" (ppr tc)++pprPromotionQuote :: TyCon -> SDoc+-- Promoted data constructors already have a tick in their OccName+pprPromotionQuote tc+ = case tc of+ PromotedDataCon {} -> char '\'' -- Always quote promoted DataCons in types+ _ -> empty++instance NamedThing TyCon where+ getName = tyConName++instance Data.Data TyCon where+ -- don't traverse?+ toConstr _ = abstractConstr "TyCon"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "TyCon"++instance Binary Injectivity where+ put_ bh NotInjective = putByte bh 0+ put_ bh (Injective xs) = putByte bh 1 >> put_ bh xs++ get bh = do { h <- getByte bh+ ; case h of+ 0 -> return NotInjective+ _ -> do { xs <- get bh+ ; return (Injective xs) } }++{-+************************************************************************+* *+ Walking over recursive TyCons+* *+************************************************************************++Note [Expanding newtypes and products]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+When expanding a type to expose a data-type constructor, we need to be+careful about newtypes, lest we fall into an infinite loop. Here are+the key examples:++ newtype Id x = MkId x+ newtype Fix f = MkFix (f (Fix f))+ newtype T = MkT (T -> T)++ Type Expansion+ --------------------------+ T T -> T+ Fix Maybe Maybe (Fix Maybe)+ Id (Id Int) Int+ Fix Id NO NO NO++Notice that+ * We can expand T, even though it's recursive.+ * We can expand Id (Id Int), even though the Id shows up+ twice at the outer level, because Id is non-recursive++So, when expanding, we keep track of when we've seen a recursive+newtype at outermost level; and bail out if we see it again.++We sometimes want to do the same for product types, so that the+strictness analyser doesn't unbox infinitely deeply.++More precisely, we keep a *count* of how many times we've seen it.+This is to account for+ data instance T (a,b) = MkT (T a) (T b)+Then (Trac #10482) if we have a type like+ T (Int,(Int,(Int,(Int,Int))))+we can still unbox deeply enough during strictness analysis.+We have to treat T as potentially recursive, but it's still+good to be able to unwrap multiple layers.++The function that manages all this is checkRecTc.+-}++data RecTcChecker = RC !Int (NameEnv Int)+ -- The upper bound, and the number of times+ -- we have encountered each TyCon++initRecTc :: RecTcChecker+-- Intialise with a fixed max bound of 100+-- We should probably have a flag for this+initRecTc = RC 100 emptyNameEnv++checkRecTc :: RecTcChecker -> TyCon -> Maybe RecTcChecker+-- Nothing => Recursion detected+-- Just rec_tcs => Keep going+checkRecTc (RC bound rec_nts) tc+ = case lookupNameEnv rec_nts tc_name of+ Just n | n >= bound -> Nothing+ | otherwise -> Just (RC bound (extendNameEnv rec_nts tc_name (n+1)))+ Nothing -> Just (RC bound (extendNameEnv rec_nts tc_name 1))+ where+ tc_name = tyConName tc++-- | Returns whether or not this 'TyCon' is definite, or a hole+-- that may be filled in at some later point. See Note [Skolem abstract data]+tyConSkolem :: TyCon -> Bool+tyConSkolem = isHoleName . tyConName++-- Note [Skolem abstract data]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- Skolem abstract data arises from data declarations in an hsig file.+--+-- The best analogy is to interpret the types declared in signature files as+-- elaborating to universally quantified type variables; e.g.,+--+-- unit p where+-- signature H where+-- data T+-- data S+-- module M where+-- import H+-- f :: (T ~ S) => a -> b+-- f x = x+--+-- elaborates as (with some fake structural types):+--+-- p :: forall t s. { f :: forall a b. t ~ s => a -> b }+-- p = { f = \x -> x } -- ill-typed+--+-- It is clear that inside p, t ~ s is not provable (and+-- if we tried to write a function to cast t to s, that+-- would not work), but if we call p @Int @Int, clearly Int ~ Int+-- is provable. The skolem variables are all distinct from+-- one another, but we can't make assumptions like "f is+-- inaccessible", because the skolem variables will get+-- instantiated eventually!+--+-- Skolem abstractness can apply to "non-abstract" data as well):+--+-- unit p where+-- signature H1 where+-- data T = MkT+-- signature H2 where+-- data T = MkT+-- module M where+-- import qualified H1+-- import qualified H2+-- f :: (H1.T ~ H2.T) => a -> b+-- f x = x+--+-- This is why the test is on the original name of the TyCon,+-- not whether it is abstract or not.
+ types/TyCon.hs-boot view
@@ -0,0 +1,7 @@+module TyCon where++data TyCon++isTupleTyCon :: TyCon -> Bool+isUnboxedTupleTyCon :: TyCon -> Bool+isFunTyCon :: TyCon -> Bool
+ types/Type.hs view
@@ -0,0 +1,2464 @@+-- (c) The University of Glasgow 2006+-- (c) The GRASP/AQUA Project, Glasgow University, 1998+--+-- Type - public interface++{-# LANGUAGE CPP, FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- | Main functions for manipulating types and type-related things+module Type (+ -- Note some of this is just re-exports from TyCon..++ -- * Main data types representing Types+ -- $type_classification++ -- $representation_types+ TyThing(..), Type, ArgFlag(..), KindOrType, PredType, ThetaType,+ Var, TyVar, isTyVar, TyCoVar, TyBinder, TyVarBinder,++ -- ** Constructing and deconstructing types+ mkTyVarTy, mkTyVarTys, getTyVar, getTyVar_maybe, repGetTyVar_maybe,+ getCastedTyVar_maybe, tyVarKind,++ mkAppTy, mkAppTys, splitAppTy, splitAppTys, repSplitAppTys,+ splitAppTy_maybe, repSplitAppTy_maybe, tcRepSplitAppTy_maybe,++ mkFunTy, mkFunTys, splitFunTy, splitFunTy_maybe,+ splitFunTys, funResultTy, funArgTy,++ mkTyConApp, mkTyConTy,+ tyConAppTyCon_maybe, tyConAppTyConPicky_maybe,+ tyConAppArgs_maybe, tyConAppTyCon, tyConAppArgs,+ splitTyConApp_maybe, splitTyConApp, tyConAppArgN, nextRole,+ tcRepSplitTyConApp_maybe, tcSplitTyConApp_maybe,+ splitListTyConApp_maybe,+ repSplitTyConApp_maybe,++ mkForAllTy, mkForAllTys, mkInvForAllTys, mkSpecForAllTys,+ mkVisForAllTys, mkInvForAllTy,+ splitForAllTys, splitForAllTyVarBndrs,+ splitForAllTy_maybe, splitForAllTy,+ splitPiTy_maybe, splitPiTy, splitPiTys,+ mkPiTy, mkPiTys, mkTyConBindersPreferAnon,+ mkLamType, mkLamTypes,+ piResultTy, piResultTys,+ applyTysX, dropForAlls,++ mkNumLitTy, isNumLitTy,+ mkStrLitTy, isStrLitTy,++ getRuntimeRep_maybe, getRuntimeRepFromKind_maybe,++ mkCastTy, mkCoercionTy, splitCastTy_maybe,++ userTypeError_maybe, pprUserTypeErrorTy,++ coAxNthLHS,+ stripCoercionTy, splitCoercionType_maybe,++ splitPiTysInvisible, filterOutInvisibleTypes,+ filterOutInvisibleTyVars, partitionInvisibles,+ synTyConResKind,++ modifyJoinResTy, setJoinResTy,++ -- Analyzing types+ TyCoMapper(..), mapType, mapCoercion,++ -- (Newtypes)+ newTyConInstRhs,++ -- Pred types+ mkFamilyTyConApp,+ isDictLikeTy,+ mkPrimEqPred, mkReprPrimEqPred, mkPrimEqPredRole,+ equalityTyCon,+ mkHeteroPrimEqPred, mkHeteroReprPrimEqPred,+ mkClassPred,+ isClassPred, isEqPred, isNomEqPred,+ isIPPred, isIPPred_maybe, isIPTyCon, isIPClass,+ isCTupleClass,++ -- Deconstructing predicate types+ PredTree(..), EqRel(..), eqRelRole, classifyPredType,+ getClassPredTys, getClassPredTys_maybe,+ getEqPredTys, getEqPredTys_maybe, getEqPredRole,+ predTypeEqRel,++ -- ** Binders+ sameVis,+ mkTyVarBinder, mkTyVarBinders,+ mkAnonBinder,+ isAnonTyBinder, isNamedTyBinder,+ binderVar, binderVars, binderKind, binderArgFlag,+ tyBinderType,+ binderRelevantType_maybe, caseBinder,+ isVisibleArgFlag, isInvisibleArgFlag, isVisibleBinder, isInvisibleBinder,+ tyConBindersTyBinders,+ mkTyBinderTyConBinder,++ -- ** Common type constructors+ funTyCon,++ -- ** Predicates on types+ isTyVarTy, isFunTy, isDictTy, isPredTy, isCoercionTy,+ isCoercionTy_maybe, isCoercionType, isForAllTy,+ isPiTy, isTauTy, isFamFreeTy,++ isValidJoinPointType,++ -- (Lifting and boxity)+ isLiftedType_maybe, isUnliftedType, isUnboxedTupleType, isUnboxedSumType,+ isAlgType, isClosedAlgType, isDataFamilyAppType,+ isPrimitiveType, isStrictType,+ isRuntimeRepTy, isRuntimeRepVar, isRuntimeRepKindedTy,+ dropRuntimeRepArgs,+ getRuntimeRep, getRuntimeRepFromKind,++ -- * Main data types representing Kinds+ Kind,++ -- ** Finding the kind of a type+ typeKind, isTypeLevPoly, resultIsLevPoly,++ -- ** Common Kind+ liftedTypeKind,++ -- * Type free variables+ tyCoFVsOfType, tyCoFVsBndr,+ tyCoVarsOfType, tyCoVarsOfTypes,+ tyCoVarsOfTypeDSet,+ coVarsOfType,+ coVarsOfTypes, closeOverKinds, closeOverKindsList,+ noFreeVarsOfType,+ splitVisVarsOfType, splitVisVarsOfTypes,+ expandTypeSynonyms,+ typeSize,++ -- * Well-scoped lists of variables+ dVarSetElemsWellScoped, toposortTyVars, tyCoVarsOfTypeWellScoped,+ tyCoVarsOfTypesWellScoped,++ -- * Type comparison+ eqType, eqTypeX, eqTypes, nonDetCmpType, nonDetCmpTypes, nonDetCmpTypeX,+ nonDetCmpTypesX, nonDetCmpTc,+ eqVarBndrs,++ -- * Forcing evaluation of types+ seqType, seqTypes,++ -- * Other views onto Types+ coreView, tcView,++ tyConsOfType,++ -- * Main type substitution data types+ TvSubstEnv, -- Representation widely visible+ TCvSubst(..), -- Representation visible to a few friends++ -- ** Manipulating type substitutions+ emptyTvSubstEnv, emptyTCvSubst, mkEmptyTCvSubst,++ mkTCvSubst, zipTvSubst, mkTvSubstPrs,+ notElemTCvSubst,+ getTvSubstEnv, setTvSubstEnv,+ zapTCvSubst, getTCvInScope, getTCvSubstRangeFVs,+ extendTCvInScope, extendTCvInScopeList, extendTCvInScopeSet,+ extendTCvSubst, extendCvSubst,+ extendTvSubst, extendTvSubstBinder,+ extendTvSubstList, extendTvSubstAndInScope,+ extendTvSubstWithClone,+ isInScope, composeTCvSubstEnv, composeTCvSubst, zipTyEnv, zipCoEnv,+ isEmptyTCvSubst, unionTCvSubst,++ -- ** Performing substitution on types and kinds+ substTy, substTys, substTyWith, substTysWith, substTheta,+ substTyAddInScope,+ substTyUnchecked, substTysUnchecked, substThetaUnchecked,+ substTyWithUnchecked,+ substCoUnchecked, substCoWithUnchecked,+ substTyVarBndr, substTyVar, substTyVars,+ cloneTyVarBndr, cloneTyVarBndrs, lookupTyVar,++ -- * Pretty-printing+ pprType, pprParendType, pprTypeApp, pprTyThingCategory, pprShortTyThing,+ pprTvBndr, pprTvBndrs, pprForAll, pprUserForAll,+ pprSigmaType, ppSuggestExplicitKinds,+ pprTheta, pprThetaArrowTy, pprClassPred,+ pprKind, pprParendKind, pprSourceTyCon,+ TyPrec(..), maybeParen,+ pprTyVar, pprTyVars, pprPrefixApp, pprArrowChain,++ -- * Tidying type related things up for printing+ tidyType, tidyTypes,+ tidyOpenType, tidyOpenTypes,+ tidyOpenKind,+ tidyTyCoVarBndr, tidyTyCoVarBndrs, tidyFreeTyCoVars,+ tidyOpenTyCoVar, tidyOpenTyCoVars,+ tidyTyVarOcc,+ tidyTopType,+ tidyKind,+ tidyTyVarBinder, tidyTyVarBinders+ ) where++#include "HsVersions.h"++import BasicTypes++-- We import the representation and primitive functions from TyCoRep.+-- Many things are reexported, but not the representation!++import Kind+import TyCoRep++-- friends:+import Var+import VarEnv+import VarSet+import UniqSet++import Class+import TyCon+import TysPrim+import {-# SOURCE #-} TysWiredIn ( listTyCon, typeNatKind+ , typeSymbolKind, liftedTypeKind )+import PrelNames+import CoAxiom+import {-# SOURCE #-} Coercion++-- others+import Util+import Outputable+import FastString+import Pair+import ListSetOps+import Digraph+import Unique ( nonDetCmpUnique )+import SrcLoc ( SrcSpan )+import OccName ( OccName )+import Name ( mkInternalName )++import Maybes ( orElse )+import Data.Maybe ( isJust, mapMaybe )+import Control.Monad ( guard )+import Control.Arrow ( first, second )++-- $type_classification+-- #type_classification#+--+-- Types are one of:+--+-- [Unboxed] Iff its representation is other than a pointer+-- Unboxed types are also unlifted.+--+-- [Lifted] Iff it has bottom as an element.+-- Closures always have lifted types: i.e. any+-- let-bound identifier in Core must have a lifted+-- type. Operationally, a lifted object is one that+-- can be entered.+-- Only lifted types may be unified with a type variable.+--+-- [Algebraic] Iff it is a type with one or more constructors, whether+-- declared with @data@ or @newtype@.+-- An algebraic type is one that can be deconstructed+-- with a case expression. This is /not/ the same as+-- lifted types, because we also include unboxed+-- tuples in this classification.+--+-- [Data] Iff it is a type declared with @data@, or a boxed tuple.+--+-- [Primitive] Iff it is a built-in type that can't be expressed in Haskell.+--+-- Currently, all primitive types are unlifted, but that's not necessarily+-- the case: for example, @Int@ could be primitive.+--+-- Some primitive types are unboxed, such as @Int#@, whereas some are boxed+-- but unlifted (such as @ByteArray#@). The only primitive types that we+-- classify as algebraic are the unboxed tuples.+--+-- Some examples of type classifications that may make this a bit clearer are:+--+-- @+-- Type primitive boxed lifted algebraic+-- -----------------------------------------------------------------------------+-- Int# Yes No No No+-- ByteArray# Yes Yes No No+-- (\# a, b \#) Yes No No Yes+-- (\# a | b \#) Yes No No Yes+-- ( a, b ) No Yes Yes Yes+-- [a] No Yes Yes Yes+-- @++-- $representation_types+-- A /source type/ is a type that is a separate type as far as the type checker is+-- concerned, but which has a more low-level representation as far as Core-to-Core+-- passes and the rest of the back end is concerned.+--+-- You don't normally have to worry about this, as the utility functions in+-- this module will automatically convert a source into a representation type+-- if they are spotted, to the best of it's abilities. If you don't want this+-- to happen, use the equivalent functions from the "TcType" module.++{-+************************************************************************+* *+ Type representation+* *+************************************************************************++Note [coreView vs tcView]+~~~~~~~~~~~~~~~~~~~~~~~~~+So far as the typechecker is concerned, 'Constraint' and 'TYPE LiftedRep' are distinct kinds.++But in Core these two are treated as identical.++We implement this by making 'coreView' convert 'Constraint' to 'TYPE LiftedRep' on the fly.+The function tcView (used in the type checker) does not do this.++See also Trac #11715, which tracks removing this inconsistency.++-}++{-# INLINE coreView #-}+coreView :: Type -> Maybe Type+-- ^ This function Strips off the /top layer only/ of a type synonym+-- application (if any) its underlying representation type.+-- Returns Nothing if there is nothing to look through.+-- This function considers 'Constraint' to be a synonym of @TYPE LiftedRep@.+--+-- By being non-recursive and inlined, this case analysis gets efficiently+-- joined onto the case analysis that the caller is already doing+coreView (TyConApp tc tys) | Just (tenv, rhs, tys') <- expandSynTyCon_maybe tc tys+ = Just (mkAppTys (substTy (mkTvSubstPrs tenv) rhs) tys')+ -- The free vars of 'rhs' should all be bound by 'tenv', so it's+ -- ok to use 'substTy' here.+ -- See also Note [The substitution invariant] in TyCoRep.+ -- Its important to use mkAppTys, rather than (foldl AppTy),+ -- because the function part might well return a+ -- partially-applied type constructor; indeed, usually will!+coreView (TyConApp tc [])+ | isStarKindSynonymTyCon tc+ = Just liftedTypeKind++coreView _ = Nothing++-- | Gives the typechecker view of a type. This unwraps synonyms but+-- leaves 'Constraint' alone. c.f. coreView, which turns Constraint into+-- TYPE LiftedRep. Returns Nothing if no unwrapping happens.+-- See also Note [coreView vs tcView] in Type.+{-# INLINE tcView #-}+tcView :: Type -> Maybe Type+tcView (TyConApp tc tys) | Just (tenv, rhs, tys') <- expandSynTyCon_maybe tc tys+ = Just (mkAppTys (substTy (mkTvSubstPrs tenv) rhs) tys')+ -- The free vars of 'rhs' should all be bound by 'tenv', so it's+ -- ok to use 'substTy' here.+ -- See also Note [The substitution invariant] in TyCoRep.+ -- Its important to use mkAppTys, rather than (foldl AppTy),+ -- because the function part might well return a+ -- partially-applied type constructor; indeed, usually will!+tcView _ = Nothing++-----------------------------------------------+expandTypeSynonyms :: Type -> Type+-- ^ Expand out all type synonyms. Actually, it'd suffice to expand out+-- just the ones that discard type variables (e.g. type Funny a = Int)+-- But we don't know which those are currently, so we just expand all.+--+-- 'expandTypeSynonyms' only expands out type synonyms mentioned in the type,+-- not in the kinds of any TyCon or TyVar mentioned in the type.+--+-- Keep this synchronized with 'synonymTyConsOfType'+expandTypeSynonyms ty+ = go (mkEmptyTCvSubst in_scope) ty+ where+ in_scope = mkInScopeSet (tyCoVarsOfType ty)++ go subst (TyConApp tc tys)+ | Just (tenv, rhs, tys') <- expandSynTyCon_maybe tc expanded_tys+ = let subst' = mkTvSubst in_scope (mkVarEnv tenv)+ -- Make a fresh substitution; rhs has nothing to+ -- do with anything that has happened so far+ -- NB: if you make changes here, be sure to build an+ -- /idempotent/ substitution, even in the nested case+ -- type T a b = a -> b+ -- type S x y = T y x+ -- (Trac #11665)+ in mkAppTys (go subst' rhs) tys'+ | otherwise+ = TyConApp tc expanded_tys+ where+ expanded_tys = (map (go subst) tys)++ go _ (LitTy l) = LitTy l+ go subst (TyVarTy tv) = substTyVar subst tv+ go subst (AppTy t1 t2) = mkAppTy (go subst t1) (go subst t2)+ go subst (FunTy arg res)+ = mkFunTy (go subst arg) (go subst res)+ go subst (ForAllTy (TvBndr tv vis) t)+ = let (subst', tv') = substTyVarBndrCallback go subst tv in+ ForAllTy (TvBndr tv' vis) (go subst' t)+ go subst (CastTy ty co) = mkCastTy (go subst ty) (go_co subst co)+ go subst (CoercionTy co) = mkCoercionTy (go_co subst co)++ go_co subst (Refl r ty)+ = mkReflCo r (go subst ty)+ -- NB: coercions are always expanded upon creation+ go_co subst (TyConAppCo r tc args)+ = mkTyConAppCo r tc (map (go_co subst) args)+ go_co subst (AppCo co arg)+ = mkAppCo (go_co subst co) (go_co subst arg)+ go_co subst (ForAllCo tv kind_co co)+ = let (subst', tv', kind_co') = go_cobndr subst tv kind_co in+ mkForAllCo tv' kind_co' (go_co subst' co)+ go_co subst (FunCo r co1 co2)+ = mkFunCo r (go_co subst co1) (go_co subst co2)+ go_co subst (CoVarCo cv)+ = substCoVar subst cv+ go_co subst (AxiomInstCo ax ind args)+ = mkAxiomInstCo ax ind (map (go_co subst) args)+ go_co subst (UnivCo p r t1 t2)+ = mkUnivCo (go_prov subst p) r (go subst t1) (go subst t2)+ go_co subst (SymCo co)+ = mkSymCo (go_co subst co)+ go_co subst (TransCo co1 co2)+ = mkTransCo (go_co subst co1) (go_co subst co2)+ go_co subst (NthCo n co)+ = mkNthCo n (go_co subst co)+ go_co subst (LRCo lr co)+ = mkLRCo lr (go_co subst co)+ go_co subst (InstCo co arg)+ = mkInstCo (go_co subst co) (go_co subst arg)+ go_co subst (CoherenceCo co1 co2)+ = mkCoherenceCo (go_co subst co1) (go_co subst co2)+ go_co subst (KindCo co)+ = mkKindCo (go_co subst co)+ go_co subst (SubCo co)+ = mkSubCo (go_co subst co)+ go_co subst (AxiomRuleCo ax cs) = AxiomRuleCo ax (map (go_co subst) cs)++ go_prov _ UnsafeCoerceProv = UnsafeCoerceProv+ go_prov subst (PhantomProv co) = PhantomProv (go_co subst co)+ go_prov subst (ProofIrrelProv co) = ProofIrrelProv (go_co subst co)+ go_prov _ p@(PluginProv _) = p+ go_prov _ (HoleProv h) = pprPanic "expandTypeSynonyms hit a hole" (ppr h)++ -- the "False" and "const" are to accommodate the type of+ -- substForAllCoBndrCallback, which is general enough to+ -- handle coercion optimization (which sometimes swaps the+ -- order of a coercion)+ go_cobndr subst = substForAllCoBndrCallback False (go_co subst) subst++{-+************************************************************************+* *+ Analyzing types+* *+************************************************************************++These functions do a map-like operation over types, performing some operation+on all variables and binding sites. Primarily used for zonking.++Note [Efficiency for mapCoercion ForAllCo case]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As noted in Note [Forall coercions] in TyCoRep, a ForAllCo is a bit redundant.+It stores a TyVar and a Coercion, where the kind of the TyVar always matches+the left-hand kind of the coercion. This is convenient lots of the time, but+not when mapping a function over a coercion.++The problem is that tcm_tybinder will affect the TyVar's kind and+mapCoercion will affect the Coercion, and we hope that the results will be+the same. Even if they are the same (which should generally happen with+correct algorithms), then there is an efficiency issue. In particular,+this problem seems to make what should be a linear algorithm into a potentially+exponential one. But it's only going to be bad in the case where there's+lots of foralls in the kinds of other foralls. Like this:++ forall a : (forall b : (forall c : ...). ...). ...++This construction seems unlikely. So we'll do the inefficient, easy way+for now.++Note [Specialising mappers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~+These INLINABLE pragmas are indispensable. mapType/mapCoercion are used+to implement zonking, and it's vital that they get specialised to the TcM+monad. This specialisation happens automatically (that is, without a+SPECIALISE pragma) as long as the definitions are INLINABLE. For example,+this one change made a 20% allocation difference in perf/compiler/T5030.++-}++-- | This describes how a "map" operation over a type/coercion should behave+data TyCoMapper env m+ = TyCoMapper+ { tcm_smart :: Bool -- ^ Should the new type be created with smart+ -- constructors?+ , tcm_tyvar :: env -> TyVar -> m Type+ , tcm_covar :: env -> CoVar -> m Coercion+ , tcm_hole :: env -> CoercionHole -> Role+ -> Type -> Type -> m Coercion+ -- ^ What to do with coercion holes. See Note [Coercion holes] in+ -- TyCoRep.++ , tcm_tybinder :: env -> TyVar -> ArgFlag -> m (env, TyVar)+ -- ^ The returned env is used in the extended scope+ }++{-# INLINABLE mapType #-} -- See Note [Specialising mappers]+mapType :: Monad m => TyCoMapper env m -> env -> Type -> m Type+mapType mapper@(TyCoMapper { tcm_smart = smart, tcm_tyvar = tyvar+ , tcm_tybinder = tybinder })+ env ty+ = go ty+ where+ go (TyVarTy tv) = tyvar env tv+ go (AppTy t1 t2) = mkappty <$> go t1 <*> go t2+ go t@(TyConApp _ []) = return t -- avoid allocation in this exceedingly+ -- common case (mostly, for *)+ go (TyConApp tc tys) = mktyconapp tc <$> mapM go tys+ go (FunTy arg res) = FunTy <$> go arg <*> go res+ go (ForAllTy (TvBndr tv vis) inner)+ = do { (env', tv') <- tybinder env tv vis+ ; inner' <- mapType mapper env' inner+ ; return $ ForAllTy (TvBndr tv' vis) inner' }+ go ty@(LitTy {}) = return ty+ go (CastTy ty co) = mkcastty <$> go ty <*> mapCoercion mapper env co+ go (CoercionTy co) = CoercionTy <$> mapCoercion mapper env co++ (mktyconapp, mkappty, mkcastty)+ | smart = (mkTyConApp, mkAppTy, mkCastTy)+ | otherwise = (TyConApp, AppTy, CastTy)++{-# INLINABLE mapCoercion #-} -- See Note [Specialising mappers]+mapCoercion :: Monad m+ => TyCoMapper env m -> env -> Coercion -> m Coercion+mapCoercion mapper@(TyCoMapper { tcm_smart = smart, tcm_covar = covar+ , tcm_hole = cohole, tcm_tybinder = tybinder })+ env co+ = go co+ where+ go (Refl r ty) = Refl r <$> mapType mapper env ty+ go (TyConAppCo r tc args)+ = mktyconappco r tc <$> mapM go args+ go (AppCo c1 c2) = mkappco <$> go c1 <*> go c2+ go (ForAllCo tv kind_co co)+ = do { kind_co' <- go kind_co+ ; (env', tv') <- tybinder env tv Inferred+ ; co' <- mapCoercion mapper env' co+ ; return $ mkforallco tv' kind_co' co' }+ -- See Note [Efficiency for mapCoercion ForAllCo case]+ go (FunCo r c1 c2) = mkFunCo r <$> go c1 <*> go c2+ go (CoVarCo cv) = covar env cv+ go (AxiomInstCo ax i args)+ = mkaxiominstco ax i <$> mapM go args+ go (UnivCo (HoleProv hole) r t1 t2)+ = cohole env hole r t1 t2+ go (UnivCo p r t1 t2)+ = mkunivco <$> go_prov p <*> pure r+ <*> mapType mapper env t1 <*> mapType mapper env t2+ go (SymCo co) = mksymco <$> go co+ go (TransCo c1 c2) = mktransco <$> go c1 <*> go c2+ go (AxiomRuleCo r cos) = AxiomRuleCo r <$> mapM go cos+ go (NthCo i co) = mknthco i <$> go co+ go (LRCo lr co) = mklrco lr <$> go co+ go (InstCo co arg) = mkinstco <$> go co <*> go arg+ go (CoherenceCo c1 c2) = mkcoherenceco <$> go c1 <*> go c2+ go (KindCo co) = mkkindco <$> go co+ go (SubCo co) = mksubco <$> go co++ go_prov UnsafeCoerceProv = return UnsafeCoerceProv+ go_prov (PhantomProv co) = PhantomProv <$> go co+ go_prov (ProofIrrelProv co) = ProofIrrelProv <$> go co+ go_prov p@(PluginProv _) = return p+ go_prov (HoleProv _) = panic "mapCoercion"++ ( mktyconappco, mkappco, mkaxiominstco, mkunivco+ , mksymco, mktransco, mknthco, mklrco, mkinstco, mkcoherenceco+ , mkkindco, mksubco, mkforallco)+ | smart+ = ( mkTyConAppCo, mkAppCo, mkAxiomInstCo, mkUnivCo+ , mkSymCo, mkTransCo, mkNthCo, mkLRCo, mkInstCo, mkCoherenceCo+ , mkKindCo, mkSubCo, mkForAllCo )+ | otherwise+ = ( TyConAppCo, AppCo, AxiomInstCo, UnivCo+ , SymCo, TransCo, NthCo, LRCo, InstCo, CoherenceCo+ , KindCo, SubCo, ForAllCo )++{-+************************************************************************+* *+\subsection{Constructor-specific functions}+* *+************************************************************************+++---------------------------------------------------------------------+ TyVarTy+ ~~~~~~~+-}++-- | Attempts to obtain the type variable underlying a 'Type', and panics with the+-- given message if this is not a type variable type. See also 'getTyVar_maybe'+getTyVar :: String -> Type -> TyVar+getTyVar msg ty = case getTyVar_maybe ty of+ Just tv -> tv+ Nothing -> panic ("getTyVar: " ++ msg)++isTyVarTy :: Type -> Bool+isTyVarTy ty = isJust (getTyVar_maybe ty)++-- | Attempts to obtain the type variable underlying a 'Type'+getTyVar_maybe :: Type -> Maybe TyVar+getTyVar_maybe ty | Just ty' <- coreView ty = getTyVar_maybe ty'+ | otherwise = repGetTyVar_maybe ty++-- | If the type is a tyvar, possibly under a cast, returns it, along+-- with the coercion. Thus, the co is :: kind tv ~R kind type+getCastedTyVar_maybe :: Type -> Maybe (TyVar, Coercion)+getCastedTyVar_maybe ty | Just ty' <- coreView ty = getCastedTyVar_maybe ty'+getCastedTyVar_maybe (CastTy (TyVarTy tv) co) = Just (tv, co)+getCastedTyVar_maybe (TyVarTy tv)+ = Just (tv, mkReflCo Nominal (tyVarKind tv))+getCastedTyVar_maybe _ = Nothing++-- | Attempts to obtain the type variable underlying a 'Type', without+-- any expansion+repGetTyVar_maybe :: Type -> Maybe TyVar+repGetTyVar_maybe (TyVarTy tv) = Just tv+repGetTyVar_maybe _ = Nothing++{-+---------------------------------------------------------------------+ AppTy+ ~~~~~+We need to be pretty careful with AppTy to make sure we obey the+invariant that a TyConApp is always visibly so. mkAppTy maintains the+invariant: use it.++Note [Decomposing fat arrow c=>t]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Can we unify (a b) with (Eq a => ty)? If we do so, we end up with+a partial application like ((=>) Eq a) which doesn't make sense in+source Haskell. In contrast, we *can* unify (a b) with (t1 -> t2).+Here's an example (Trac #9858) of how you might do it:+ i :: (Typeable a, Typeable b) => Proxy (a b) -> TypeRep+ i p = typeRep p++ j = i (Proxy :: Proxy (Eq Int => Int))+The type (Proxy (Eq Int => Int)) is only accepted with -XImpredicativeTypes,+but suppose we want that. But then in the call to 'i', we end+up decomposing (Eq Int => Int), and we definitely don't want that.++This really only applies to the type checker; in Core, '=>' and '->'+are the same, as are 'Constraint' and '*'. But for now I've put+the test in repSplitAppTy_maybe, which applies throughout, because+the other calls to splitAppTy are in Unify, which is also used by+the type checker (e.g. when matching type-function equations).++-}++-- | Applies a type to another, as in e.g. @k a@+mkAppTy :: Type -> Type -> Type+mkAppTy (TyConApp tc tys) ty2 = mkTyConApp tc (tys ++ [ty2])+mkAppTy ty1 ty2 = AppTy ty1 ty2+ -- Note that the TyConApp could be an+ -- under-saturated type synonym. GHC allows that; e.g.+ -- type Foo k = k a -> k a+ -- type Id x = x+ -- foo :: Foo Id -> Foo Id+ --+ -- Here Id is partially applied in the type sig for Foo,+ -- but once the type synonyms are expanded all is well++mkAppTys :: Type -> [Type] -> Type+mkAppTys ty1 [] = ty1+mkAppTys (TyConApp tc tys1) tys2 = mkTyConApp tc (tys1 ++ tys2)+mkAppTys ty1 tys2 = foldl AppTy ty1 tys2++-------------+splitAppTy_maybe :: Type -> Maybe (Type, Type)+-- ^ Attempt to take a type application apart, whether it is a+-- function, type constructor, or plain type application. Note+-- that type family applications are NEVER unsaturated by this!+splitAppTy_maybe ty | Just ty' <- coreView ty+ = splitAppTy_maybe ty'+splitAppTy_maybe ty = repSplitAppTy_maybe ty++-------------+repSplitAppTy_maybe :: Type -> Maybe (Type,Type)+-- ^ Does the AppTy split as in 'splitAppTy_maybe', but assumes that+-- any Core view stuff is already done+repSplitAppTy_maybe (FunTy ty1 ty2)+ | Just rep1 <- getRuntimeRep_maybe ty1+ , Just rep2 <- getRuntimeRep_maybe ty2+ = Just (TyConApp funTyCon [rep1, rep2, ty1], ty2)++ | otherwise+ = pprPanic "repSplitAppTy_maybe" (ppr ty1 $$ ppr ty2)+repSplitAppTy_maybe (AppTy ty1 ty2)+ = Just (ty1, ty2)+repSplitAppTy_maybe (TyConApp tc tys)+ | mightBeUnsaturatedTyCon tc || tys `lengthExceeds` tyConArity tc+ , Just (tys', ty') <- snocView tys+ = Just (TyConApp tc tys', ty') -- Never create unsaturated type family apps!+repSplitAppTy_maybe _other = Nothing++-- this one doesn't braek apart (c => t).+-- See Note [Decomposing fat arrow c=>t]+-- Defined here to avoid module loops between Unify and TcType.+tcRepSplitAppTy_maybe :: Type -> Maybe (Type,Type)+-- ^ Does the AppTy split as in 'tcSplitAppTy_maybe', but assumes that+-- any coreView stuff is already done. Refuses to look through (c => t)+tcRepSplitAppTy_maybe (FunTy ty1 ty2)+ | isConstraintKind (typeKind ty1)+ = Nothing -- See Note [Decomposing fat arrow c=>t]++ | Just rep1 <- getRuntimeRep_maybe ty1+ , Just rep2 <- getRuntimeRep_maybe ty2+ = Just (TyConApp funTyCon [rep1, rep2, ty1], ty2)++ | otherwise+ = pprPanic "repSplitAppTy_maybe" (ppr ty1 $$ ppr ty2)+tcRepSplitAppTy_maybe (AppTy ty1 ty2) = Just (ty1, ty2)+tcRepSplitAppTy_maybe (TyConApp tc tys)+ | mightBeUnsaturatedTyCon tc || tys `lengthExceeds` tyConArity tc+ , Just (tys', ty') <- snocView tys+ = Just (TyConApp tc tys', ty') -- Never create unsaturated type family apps!+tcRepSplitAppTy_maybe _other = Nothing++-- | Split a type constructor application into its type constructor and+-- applied types. Note that this may fail in the case of a 'FunTy' with an+-- argument of unknown kind 'FunTy' (e.g. @FunTy (a :: k) Int@. since the kind+-- of @a@ isn't of the form @TYPE rep@). Consequently, you may need to zonk your+-- type before using this function.+--+-- If you only need the 'TyCon', consider using 'tcTyConAppTyCon_maybe'.+tcSplitTyConApp_maybe :: HasCallStack => Type -> Maybe (TyCon, [Type])+-- Defined here to avoid module loops between Unify and TcType.+tcSplitTyConApp_maybe ty | Just ty' <- tcView ty = tcSplitTyConApp_maybe ty'+tcSplitTyConApp_maybe ty = tcRepSplitTyConApp_maybe ty++-- | Like 'tcSplitTyConApp_maybe' but doesn't look through type synonyms.+tcRepSplitTyConApp_maybe :: HasCallStack => Type -> Maybe (TyCon, [Type])+-- Defined here to avoid module loops between Unify and TcType.+tcRepSplitTyConApp_maybe (TyConApp tc tys) = Just (tc, tys)+tcRepSplitTyConApp_maybe (FunTy arg res)+ | Just arg_rep <- getRuntimeRep_maybe arg+ , Just res_rep <- getRuntimeRep_maybe res+ = Just (funTyCon, [arg_rep, res_rep, arg, res])++ | otherwise+ = pprPanic "tcRepSplitTyConApp_maybe" (ppr arg $$ ppr res)+tcRepSplitTyConApp_maybe _ = Nothing+++-------------+splitAppTy :: Type -> (Type, Type)+-- ^ Attempts to take a type application apart, as in 'splitAppTy_maybe',+-- and panics if this is not possible+splitAppTy ty = case splitAppTy_maybe ty of+ Just pr -> pr+ Nothing -> panic "splitAppTy"++-------------+splitAppTys :: Type -> (Type, [Type])+-- ^ Recursively splits a type as far as is possible, leaving a residual+-- type being applied to and the type arguments applied to it. Never fails,+-- even if that means returning an empty list of type applications.+splitAppTys ty = split ty ty []+ where+ split orig_ty ty args | Just ty' <- coreView ty = split orig_ty ty' args+ split _ (AppTy ty arg) args = split ty ty (arg:args)+ split _ (TyConApp tc tc_args) args+ = let -- keep type families saturated+ n | mightBeUnsaturatedTyCon tc = 0+ | otherwise = tyConArity tc+ (tc_args1, tc_args2) = splitAt n tc_args+ in+ (TyConApp tc tc_args1, tc_args2 ++ args)+ split _ (FunTy ty1 ty2) args+ | Just rep1 <- getRuntimeRep_maybe ty1+ , Just rep2 <- getRuntimeRep_maybe ty2+ = ASSERT( null args )+ (TyConApp funTyCon [], [rep1, rep2, ty1, ty2])++ | otherwise+ = pprPanic "splitAppTys" (ppr ty1 $$ ppr ty2 $$ ppr args)+ split orig_ty _ args = (orig_ty, args)++-- | Like 'splitAppTys', but doesn't look through type synonyms+repSplitAppTys :: Type -> (Type, [Type])+repSplitAppTys ty = split ty []+ where+ split (AppTy ty arg) args = split ty (arg:args)+ split (TyConApp tc tc_args) args+ = let n | mightBeUnsaturatedTyCon tc = 0+ | otherwise = tyConArity tc+ (tc_args1, tc_args2) = splitAt n tc_args+ in+ (TyConApp tc tc_args1, tc_args2 ++ args)+ split (FunTy ty1 ty2) args+ | Just rep1 <- getRuntimeRep_maybe ty1+ , Just rep2 <- getRuntimeRep_maybe ty2+ = ASSERT( null args )+ (TyConApp funTyCon [], [rep1, rep2, ty1, ty2])++ | otherwise+ = pprPanic "repSplitAppTys" (ppr ty1 $$ ppr ty2 $$ ppr args)+ split ty args = (ty, args)++{-+ LitTy+ ~~~~~+-}++mkNumLitTy :: Integer -> Type+mkNumLitTy n = LitTy (NumTyLit n)++-- | Is this a numeric literal. We also look through type synonyms.+isNumLitTy :: Type -> Maybe Integer+isNumLitTy ty | Just ty1 <- coreView ty = isNumLitTy ty1+isNumLitTy (LitTy (NumTyLit n)) = Just n+isNumLitTy _ = Nothing++mkStrLitTy :: FastString -> Type+mkStrLitTy s = LitTy (StrTyLit s)++-- | Is this a symbol literal. We also look through type synonyms.+isStrLitTy :: Type -> Maybe FastString+isStrLitTy ty | Just ty1 <- coreView ty = isStrLitTy ty1+isStrLitTy (LitTy (StrTyLit s)) = Just s+isStrLitTy _ = Nothing+++-- | Is this type a custom user error?+-- If so, give us the kind and the error message.+userTypeError_maybe :: Type -> Maybe Type+userTypeError_maybe t+ = do { (tc, _kind : msg : _) <- splitTyConApp_maybe t+ -- There may be more than 2 arguments, if the type error is+ -- used as a type constructor (e.g. at kind `Type -> Type`).++ ; guard (tyConName tc == errorMessageTypeErrorFamName)+ ; return msg }++-- | Render a type corresponding to a user type error into a SDoc.+pprUserTypeErrorTy :: Type -> SDoc+pprUserTypeErrorTy ty =+ case splitTyConApp_maybe ty of++ -- Text "Something"+ Just (tc,[txt])+ | tyConName tc == typeErrorTextDataConName+ , Just str <- isStrLitTy txt -> ftext str++ -- ShowType t+ Just (tc,[_k,t])+ | tyConName tc == typeErrorShowTypeDataConName -> ppr t++ -- t1 :<>: t2+ Just (tc,[t1,t2])+ | tyConName tc == typeErrorAppendDataConName ->+ pprUserTypeErrorTy t1 <> pprUserTypeErrorTy t2++ -- t1 :$$: t2+ Just (tc,[t1,t2])+ | tyConName tc == typeErrorVAppendDataConName ->+ pprUserTypeErrorTy t1 $$ pprUserTypeErrorTy t2++ -- An uneavaluated type function+ _ -> ppr ty+++++{-+---------------------------------------------------------------------+ FunTy+ ~~~~~++Note [Representation of function types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~++Functions (e.g. Int -> Char) are can be thought of as being applications+of funTyCon (known in Haskell surface syntax as (->)),++ (->) :: forall (r1 :: RuntimeRep) (r2 :: RuntimeRep)+ (a :: TYPE r1) (b :: TYPE r2).+ a -> b -> Type++However, for efficiency's sake we represent saturated applications of (->)+with FunTy. For instance, the type,++ (->) r1 r2 a b++is equivalent to,++ FunTy (Anon a) b++Note how the RuntimeReps are implied in the FunTy representation. For this+reason we must be careful when recontructing the TyConApp representation (see,+for instance, splitTyConApp_maybe).++In the compiler we maintain the invariant that all saturated applications of+(->) are represented with FunTy.++See #11714.+-}++isFunTy :: Type -> Bool+isFunTy ty = isJust (splitFunTy_maybe ty)++splitFunTy :: Type -> (Type, Type)+-- ^ Attempts to extract the argument and result types from a type, and+-- panics if that is not possible. See also 'splitFunTy_maybe'+splitFunTy ty | Just ty' <- coreView ty = splitFunTy ty'+splitFunTy (FunTy arg res) = (arg, res)+splitFunTy other = pprPanic "splitFunTy" (ppr other)++splitFunTy_maybe :: Type -> Maybe (Type, Type)+-- ^ Attempts to extract the argument and result types from a type+splitFunTy_maybe ty | Just ty' <- coreView ty = splitFunTy_maybe ty'+splitFunTy_maybe (FunTy arg res) = Just (arg, res)+splitFunTy_maybe _ = Nothing++splitFunTys :: Type -> ([Type], Type)+splitFunTys ty = split [] ty ty+ where+ split args orig_ty ty | Just ty' <- coreView ty = split args orig_ty ty'+ split args _ (FunTy arg res) = split (arg:args) res res+ split args orig_ty _ = (reverse args, orig_ty)++funResultTy :: Type -> Type+-- ^ Extract the function result type and panic if that is not possible+funResultTy ty | Just ty' <- coreView ty = funResultTy ty'+funResultTy (FunTy _ res) = res+funResultTy ty = pprPanic "funResultTy" (ppr ty)++funArgTy :: Type -> Type+-- ^ Extract the function argument type and panic if that is not possible+funArgTy ty | Just ty' <- coreView ty = funArgTy ty'+funArgTy (FunTy arg _res) = arg+funArgTy ty = pprPanic "funArgTy" (ppr ty)++piResultTy :: Type -> Type -> Type+piResultTy ty arg = case piResultTy_maybe ty arg of+ Just res -> res+ Nothing -> pprPanic "piResultTy" (ppr ty $$ ppr arg)++piResultTy_maybe :: Type -> Type -> Maybe Type++-- ^ Just like 'piResultTys' but for a single argument+-- Try not to iterate 'piResultTy', because it's inefficient to substitute+-- one variable at a time; instead use 'piResultTys"+piResultTy_maybe ty arg+ | Just ty' <- coreView ty = piResultTy_maybe ty' arg++ | FunTy _ res <- ty+ = Just res++ | ForAllTy (TvBndr tv _) res <- ty+ = let empty_subst = mkEmptyTCvSubst $ mkInScopeSet $+ tyCoVarsOfTypes [arg,res]+ in Just (substTy (extendTvSubst empty_subst tv arg) res)++ | otherwise+ = Nothing++-- | (piResultTys f_ty [ty1, .., tyn]) gives the type of (f ty1 .. tyn)+-- where f :: f_ty+-- 'piResultTys' is interesting because:+-- 1. 'f_ty' may have more for-alls than there are args+-- 2. Less obviously, it may have fewer for-alls+-- For case 2. think of:+-- piResultTys (forall a.a) [forall b.b, Int]+-- This really can happen, but only (I think) in situations involving+-- undefined. For example:+-- undefined :: forall a. a+-- Term: undefined @(forall b. b->b) @Int+-- This term should have type (Int -> Int), but notice that+-- there are more type args than foralls in 'undefined's type.++-- If you edit this function, you may need to update the GHC formalism+-- See Note [GHC Formalism] in coreSyn/CoreLint.hs++-- This is a heavily used function (e.g. from typeKind),+-- so we pay attention to efficiency, especially in the special case+-- where there are no for-alls so we are just dropping arrows from+-- a function type/kind.+piResultTys :: Type -> [Type] -> Type+piResultTys ty [] = ty+piResultTys ty orig_args@(arg:args)+ | Just ty' <- coreView ty+ = piResultTys ty' orig_args++ | FunTy _ res <- ty+ = piResultTys res args++ | ForAllTy (TvBndr tv _) res <- ty+ = go (extendVarEnv emptyTvSubstEnv tv arg) res args++ | otherwise+ = pprPanic "piResultTys1" (ppr ty $$ ppr orig_args)+ where+ in_scope = mkInScopeSet (tyCoVarsOfTypes (ty:orig_args))++ go :: TvSubstEnv -> Type -> [Type] -> Type+ go tv_env ty [] = substTy (mkTvSubst in_scope tv_env) ty++ go tv_env ty all_args@(arg:args)+ | Just ty' <- coreView ty+ = go tv_env ty' all_args++ | FunTy _ res <- ty+ = go tv_env res args++ | ForAllTy (TvBndr tv _) res <- ty+ = go (extendVarEnv tv_env tv arg) res args++ | TyVarTy tv <- ty+ , Just ty' <- lookupVarEnv tv_env tv+ -- Deals with piResultTys (forall a. a) [forall b.b, Int]+ = piResultTys ty' all_args++ | otherwise+ = pprPanic "piResultTys2" (ppr ty $$ ppr orig_args $$ ppr all_args)++applyTysX :: [TyVar] -> Type -> [Type] -> Type+-- applyTyxX beta-reduces (/\tvs. body_ty) arg_tys+-- Assumes that (/\tvs. body_ty) is closed+applyTysX tvs body_ty arg_tys+ = ASSERT2( length arg_tys >= n_tvs, pp_stuff )+ ASSERT2( tyCoVarsOfType body_ty `subVarSet` mkVarSet tvs, pp_stuff )+ mkAppTys (substTyWith tvs (take n_tvs arg_tys) body_ty)+ (drop n_tvs arg_tys)+ where+ pp_stuff = vcat [ppr tvs, ppr body_ty, ppr arg_tys]+ n_tvs = length tvs++{-+---------------------------------------------------------------------+ TyConApp+ ~~~~~~~~+-}++-- | A key function: builds a 'TyConApp' or 'FunTy' as appropriate to+-- its arguments. Applies its arguments to the constructor from left to right.+mkTyConApp :: TyCon -> [Type] -> Type+mkTyConApp tycon tys+ | isFunTyCon tycon+ , [_rep1,_rep2,ty1,ty2] <- tys+ = FunTy ty1 ty2++ | otherwise+ = TyConApp tycon tys++-- splitTyConApp "looks through" synonyms, because they don't+-- mean a distinct type, but all other type-constructor applications+-- including functions are returned as Just ..++-- | Retrieve the tycon heading this type, if there is one. Does /not/+-- look through synonyms.+tyConAppTyConPicky_maybe :: Type -> Maybe TyCon+tyConAppTyConPicky_maybe (TyConApp tc _) = Just tc+tyConAppTyConPicky_maybe (FunTy {}) = Just funTyCon+tyConAppTyConPicky_maybe _ = Nothing+++-- | The same as @fst . splitTyConApp@+tyConAppTyCon_maybe :: Type -> Maybe TyCon+tyConAppTyCon_maybe ty | Just ty' <- coreView ty = tyConAppTyCon_maybe ty'+tyConAppTyCon_maybe (TyConApp tc _) = Just tc+tyConAppTyCon_maybe (FunTy {}) = Just funTyCon+tyConAppTyCon_maybe _ = Nothing++tyConAppTyCon :: Type -> TyCon+tyConAppTyCon ty = tyConAppTyCon_maybe ty `orElse` pprPanic "tyConAppTyCon" (ppr ty)++-- | The same as @snd . splitTyConApp@+tyConAppArgs_maybe :: Type -> Maybe [Type]+tyConAppArgs_maybe ty | Just ty' <- coreView ty = tyConAppArgs_maybe ty'+tyConAppArgs_maybe (TyConApp _ tys) = Just tys+tyConAppArgs_maybe (FunTy arg res)+ | Just rep1 <- getRuntimeRep_maybe arg+ , Just rep2 <- getRuntimeRep_maybe res+ = Just [rep1, rep2, arg, res]+tyConAppArgs_maybe _ = Nothing++tyConAppArgs :: Type -> [Type]+tyConAppArgs ty = tyConAppArgs_maybe ty `orElse` pprPanic "tyConAppArgs" (ppr ty)++tyConAppArgN :: Int -> Type -> Type+-- Executing Nth+tyConAppArgN n ty+ = case tyConAppArgs_maybe ty of+ Just tys -> ASSERT2( n < length tys, ppr n <+> ppr tys ) tys `getNth` n+ Nothing -> pprPanic "tyConAppArgN" (ppr n <+> ppr ty)++-- | Attempts to tease a type apart into a type constructor and the application+-- of a number of arguments to that constructor. Panics if that is not possible.+-- See also 'splitTyConApp_maybe'+splitTyConApp :: Type -> (TyCon, [Type])+splitTyConApp ty = case splitTyConApp_maybe ty of+ Just stuff -> stuff+ Nothing -> pprPanic "splitTyConApp" (ppr ty)++-- | Attempts to tease a type apart into a type constructor and the application+-- of a number of arguments to that constructor+splitTyConApp_maybe :: HasDebugCallStack => Type -> Maybe (TyCon, [Type])+splitTyConApp_maybe ty | Just ty' <- coreView ty = splitTyConApp_maybe ty'+splitTyConApp_maybe ty = repSplitTyConApp_maybe ty++-- | Like 'splitTyConApp_maybe', but doesn't look through synonyms. This+-- assumes the synonyms have already been dealt with.+repSplitTyConApp_maybe :: HasDebugCallStack => Type -> Maybe (TyCon, [Type])+repSplitTyConApp_maybe (TyConApp tc tys) = Just (tc, tys)+repSplitTyConApp_maybe (FunTy arg res)+ | Just rep1 <- getRuntimeRep_maybe arg+ , Just rep2 <- getRuntimeRep_maybe res+ = Just (funTyCon, [rep1, rep2, arg, res])+ | otherwise+ = pprPanic "repSplitTyConApp_maybe"+ (ppr arg $$ ppr res $$ ppr (typeKind res))+repSplitTyConApp_maybe _ = Nothing++-- | Attempts to tease a list type apart and gives the type of the elements if+-- successful (looks through type synonyms)+splitListTyConApp_maybe :: Type -> Maybe Type+splitListTyConApp_maybe ty = case splitTyConApp_maybe ty of+ Just (tc,[e]) | tc == listTyCon -> Just e+ _other -> Nothing++-- | What is the role assigned to the next parameter of this type? Usually,+-- this will be 'Nominal', but if the type is a 'TyConApp', we may be able to+-- do better. The type does *not* have to be well-kinded when applied for this+-- to work!+nextRole :: Type -> Role+nextRole ty+ | Just (tc, tys) <- splitTyConApp_maybe ty+ , let num_tys = length tys+ , num_tys < tyConArity tc+ = tyConRoles tc `getNth` num_tys++ | otherwise+ = Nominal++newTyConInstRhs :: TyCon -> [Type] -> Type+-- ^ Unwrap one 'layer' of newtype on a type constructor and its+-- arguments, using an eta-reduced version of the @newtype@ if possible.+-- This requires tys to have at least @newTyConInstArity tycon@ elements.+newTyConInstRhs tycon tys+ = ASSERT2( tvs `leLength` tys, ppr tycon $$ ppr tys $$ ppr tvs )+ applyTysX tvs rhs tys+ where+ (tvs, rhs) = newTyConEtadRhs tycon++{-+---------------------------------------------------------------------+ CastTy+ ~~~~~~+A casted type has its *kind* casted into something new.++Note [No reflexive casts in types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+As far as possible, we would like to maintain the following property:++ (*) If (t1 `eqType` t2), then t1 and t2 are treated identically within GHC.++The (*) property is very useful, because we have a tendency to compare two+types to see if they're equal, and then arbitrarily choose one. We don't+want this arbitrary choice to then matter later on. Maintaining (*) means+that every function that looks at a structure of a type must think about+casts. In places where we directly pattern-match, this consideration is+forced by consideration of the CastTy constructor.++But, when we call a splitXXX function, it's easy to ignore the possibility+of casts. In particular, splitTyConApp is used extensively, and we don't+want it to fail on (T a b c |> co). Happily, if we have+ (T a b c |> co) `eqType` (T d e f)+then co must be reflexive. Why? eqType checks that the kinds are equal, as+well as checking that (a `eqType` d), (b `eqType` e), and (c `eqType` f).+By the kind check, we know that (T a b c |> co) and (T d e f) have the same+kind. So the only way that co could be non-reflexive is for (T a b c) to have+a different kind than (T d e f). But because T's kind is closed (all tycon kinds+are closed), the only way for this to happen is that one of the arguments has+to differ, leading to a contradiction. Thus, co is reflexive.++Accordingly, by eliminating reflexive casts, splitTyConApp need not worry+about outermost casts to uphold (*).++Unforunately, that's not the end of the story. Consider comparing+ (T a b c) =? (T a b |> (co -> <Type>)) (c |> sym co)+These two types have the same kind (Type), but the left type is a TyConApp+while the right type is not. To handle this case, we will have to implement+some variant of the dreaded KPush algorithm (c.f. CoreOpt.pushCoDataCon).+This stone is left unturned for now, meaning that we don't yet uphold (*).++The other place where (*) will be hard to guarantee is in splitAppTy, because+I (Richard E) can't think of a way to push coercions into AppTys. The good+news here is that splitAppTy is not used all that much, and so all clients of+that function can simply be told to use splitCastTy as well, in order to+uphold (*). This, too, is left undone, for now.++-}++splitCastTy_maybe :: Type -> Maybe (Type, Coercion)+splitCastTy_maybe ty | Just ty' <- coreView ty = splitCastTy_maybe ty'+splitCastTy_maybe (CastTy ty co) = Just (ty, co)+splitCastTy_maybe _ = Nothing++-- | Make a 'CastTy'. The Coercion must be nominal. Checks the+-- Coercion for reflexivity, dropping it if it's reflexive.+-- See Note [No reflexive casts in types]+mkCastTy :: Type -> Coercion -> Type+mkCastTy ty co | isReflexiveCo co = ty+-- NB: Do the slow check here. This is important to keep the splitXXX+-- functions working properly. Otherwise, we may end up with something+-- like (((->) |> something_reflexive_but_not_obviously_so) biz baz)+-- fails under splitFunTy_maybe. This happened with the cheaper check+-- in test dependent/should_compile/dynamic-paper.++mkCastTy (CastTy ty co1) co2 = mkCastTy ty (co1 `mkTransCo` co2)+mkCastTy ty co = CastTy ty co++tyConBindersTyBinders :: [TyConBinder] -> [TyBinder]+-- Return the tyConBinders in TyBinder form+tyConBindersTyBinders = map to_tyb+ where+ to_tyb (TvBndr tv (NamedTCB vis)) = Named (TvBndr tv vis)+ to_tyb (TvBndr tv AnonTCB) = Anon (tyVarKind tv)++{-+--------------------------------------------------------------------+ CoercionTy+ ~~~~~~~~~~+CoercionTy allows us to inject coercions into types. A CoercionTy+should appear only in the right-hand side of an application.+-}++mkCoercionTy :: Coercion -> Type+mkCoercionTy = CoercionTy++isCoercionTy :: Type -> Bool+isCoercionTy (CoercionTy _) = True+isCoercionTy _ = False++isCoercionTy_maybe :: Type -> Maybe Coercion+isCoercionTy_maybe (CoercionTy co) = Just co+isCoercionTy_maybe _ = Nothing++stripCoercionTy :: Type -> Coercion+stripCoercionTy (CoercionTy co) = co+stripCoercionTy ty = pprPanic "stripCoercionTy" (ppr ty)++{-+---------------------------------------------------------------------+ SynTy+ ~~~~~++Notes on type synonyms+~~~~~~~~~~~~~~~~~~~~~~+The various "split" functions (splitFunTy, splitRhoTy, splitForAllTy) try+to return type synonyms wherever possible. Thus++ type Foo a = a -> a++we want+ splitFunTys (a -> Foo a) = ([a], Foo a)+not ([a], a -> a)++The reason is that we then get better (shorter) type signatures in+interfaces. Notably this plays a role in tcTySigs in TcBinds.hs.+++---------------------------------------------------------------------+ ForAllTy+ ~~~~~~~~+-}++-- | Make a dependent forall over an Inferred (as opposed to Specified)+-- variable+mkInvForAllTy :: TyVar -> Type -> Type+mkInvForAllTy tv ty = ASSERT( isTyVar tv )+ ForAllTy (TvBndr tv Inferred) ty++-- | Like mkForAllTys, but assumes all variables are dependent and Inferred,+-- a common case+mkInvForAllTys :: [TyVar] -> Type -> Type+mkInvForAllTys tvs ty = ASSERT( all isTyVar tvs )+ foldr mkInvForAllTy ty tvs++-- | Like mkForAllTys, but assumes all variables are dependent and specified,+-- a common case+mkSpecForAllTys :: [TyVar] -> Type -> Type+mkSpecForAllTys tvs = ASSERT( all isTyVar tvs )+ mkForAllTys [ TvBndr tv Specified | tv <- tvs ]++-- | Like mkForAllTys, but assumes all variables are dependent and visible+mkVisForAllTys :: [TyVar] -> Type -> Type+mkVisForAllTys tvs = ASSERT( all isTyVar tvs )+ mkForAllTys [ TvBndr tv Required | tv <- tvs ]++mkLamType :: Var -> Type -> Type+-- ^ Makes a @(->)@ type or an implicit forall type, depending+-- on whether it is given a type variable or a term variable.+-- This is used, for example, when producing the type of a lambda.+-- Always uses Inferred binders.+mkLamTypes :: [Var] -> Type -> Type+-- ^ 'mkLamType' for multiple type or value arguments++mkLamType v ty+ | isTyVar v = ForAllTy (TvBndr v Inferred) ty+ | otherwise = FunTy (varType v) ty++mkLamTypes vs ty = foldr mkLamType ty vs++-- | Given a list of type-level vars and a result type, makes TyBinders, preferring+-- anonymous binders if the variable is, in fact, not dependent.+-- All binders are /visible/.+mkTyConBindersPreferAnon :: [TyVar] -> Type -> [TyConBinder]+mkTyConBindersPreferAnon vars inner_ty = fst (go vars)+ where+ go :: [TyVar] -> ([TyConBinder], VarSet) -- also returns the free vars+ go [] = ([], tyCoVarsOfType inner_ty)+ go (v:vs) | v `elemVarSet` fvs+ = ( TvBndr v (NamedTCB Required) : binders+ , fvs `delVarSet` v `unionVarSet` kind_vars )+ | otherwise+ = ( TvBndr v AnonTCB : binders+ , fvs `unionVarSet` kind_vars )+ where+ (binders, fvs) = go vs+ kind_vars = tyCoVarsOfType $ tyVarKind v++-- | Take a ForAllTy apart, returning the list of tyvars and the result type.+-- This always succeeds, even if it returns only an empty list. Note that the+-- result type returned may have free variables that were bound by a forall.+splitForAllTys :: Type -> ([TyVar], Type)+splitForAllTys ty = split ty ty []+ where+ split orig_ty ty tvs | Just ty' <- coreView ty = split orig_ty ty' tvs+ split _ (ForAllTy (TvBndr tv _) ty) tvs = split ty ty (tv:tvs)+ split orig_ty _ tvs = (reverse tvs, orig_ty)++-- | Like 'splitPiTys' but split off only /named/ binders.+splitForAllTyVarBndrs :: Type -> ([TyVarBinder], Type)+splitForAllTyVarBndrs ty = split ty ty []+ where+ split orig_ty ty bs | Just ty' <- coreView ty = split orig_ty ty' bs+ split _ (ForAllTy b res) bs = split res res (b:bs)+ split orig_ty _ bs = (reverse bs, orig_ty)++-- | Checks whether this is a proper forall (with a named binder)+isForAllTy :: Type -> Bool+isForAllTy ty | Just ty' <- coreView ty = isForAllTy ty'+isForAllTy (ForAllTy {}) = True+isForAllTy _ = False++-- | Is this a function or forall?+isPiTy :: Type -> Bool+isPiTy ty | Just ty' <- coreView ty = isForAllTy ty'+isPiTy (ForAllTy {}) = True+isPiTy (FunTy {}) = True+isPiTy _ = False++-- | Take a forall type apart, or panics if that is not possible.+splitForAllTy :: Type -> (TyVar, Type)+splitForAllTy ty+ | Just answer <- splitForAllTy_maybe ty = answer+ | otherwise = pprPanic "splitForAllTy" (ppr ty)++-- | Drops all ForAllTys+dropForAlls :: Type -> Type+dropForAlls ty = go ty+ where+ go ty | Just ty' <- coreView ty = go ty'+ go (ForAllTy _ res) = go res+ go res = res++-- | Attempts to take a forall type apart, but only if it's a proper forall,+-- with a named binder+splitForAllTy_maybe :: Type -> Maybe (TyVar, Type)+splitForAllTy_maybe ty = go ty+ where+ go ty | Just ty' <- coreView ty = go ty'+ go (ForAllTy (TvBndr tv _) ty) = Just (tv, ty)+ go _ = Nothing++-- | Attempts to take a forall type apart; works with proper foralls and+-- functions+splitPiTy_maybe :: Type -> Maybe (TyBinder, Type)+splitPiTy_maybe ty = go ty+ where+ go ty | Just ty' <- coreView ty = go ty'+ go (ForAllTy bndr ty) = Just (Named bndr, ty)+ go (FunTy arg res) = Just (Anon arg, res)+ go _ = Nothing++-- | Takes a forall type apart, or panics+splitPiTy :: Type -> (TyBinder, Type)+splitPiTy ty+ | Just answer <- splitPiTy_maybe ty = answer+ | otherwise = pprPanic "splitPiTy" (ppr ty)++-- | Split off all TyBinders to a type, splitting both proper foralls+-- and functions+splitPiTys :: Type -> ([TyBinder], Type)+splitPiTys ty = split ty ty []+ where+ split orig_ty ty bs | Just ty' <- coreView ty = split orig_ty ty' bs+ split _ (ForAllTy b res) bs = split res res (Named b : bs)+ split _ (FunTy arg res) bs = split res res (Anon arg : bs)+ split orig_ty _ bs = (reverse bs, orig_ty)++-- Like splitPiTys, but returns only *invisible* binders, including constraints+-- Stops at the first visible binder+splitPiTysInvisible :: Type -> ([TyBinder], Type)+splitPiTysInvisible ty = split ty ty []+ where+ split orig_ty ty bs | Just ty' <- coreView ty = split orig_ty ty' bs+ split _ (ForAllTy b@(TvBndr _ vis) res) bs+ | isInvisibleArgFlag vis = split res res (Named b : bs)+ split _ (FunTy arg res) bs+ | isPredTy arg = split res res (Anon arg : bs)+ split orig_ty _ bs = (reverse bs, orig_ty)++-- | Given a tycon and its arguments, filters out any invisible arguments+filterOutInvisibleTypes :: TyCon -> [Type] -> [Type]+filterOutInvisibleTypes tc tys = snd $ partitionInvisibles tc id tys++-- | Like 'filterOutInvisibles', but works on 'TyVar's+filterOutInvisibleTyVars :: TyCon -> [TyVar] -> [TyVar]+filterOutInvisibleTyVars tc tvs = snd $ partitionInvisibles tc mkTyVarTy tvs++-- | Given a tycon and a list of things (which correspond to arguments),+-- partitions the things into+-- Inferred or Specified ones and+-- Required ones+-- The callback function is necessary for this scenario:+--+-- > T :: forall k. k -> k+-- > partitionInvisibles T [forall m. m -> m -> m, S, R, Q]+--+-- After substituting, we get+--+-- > T (forall m. m -> m -> m) :: (forall m. m -> m -> m) -> forall n. n -> n -> n+--+-- Thus, the first argument is invisible, @S@ is visible, @R@ is invisible again,+-- and @Q@ is visible.+--+-- If you're absolutely sure that your tycon's kind doesn't end in a variable,+-- it's OK if the callback function panics, as that's the only time it's+-- consulted.+partitionInvisibles :: TyCon -> (a -> Type) -> [a] -> ([a], [a])+partitionInvisibles tc get_ty = go emptyTCvSubst (tyConKind tc)+ where+ go _ _ [] = ([], [])+ go subst (ForAllTy (TvBndr tv vis) res_ki) (x:xs)+ | isVisibleArgFlag vis = second (x :) (go subst' res_ki xs)+ | otherwise = first (x :) (go subst' res_ki xs)+ where+ subst' = extendTvSubst subst tv (get_ty x)+ go subst (TyVarTy tv) xs+ | Just ki <- lookupTyVar subst tv = go subst ki xs+ go _ _ xs = ([], xs) -- something is ill-kinded. But this can happen+ -- when printing errors. Assume everything is visible.++-- @isTauTy@ tests if a type has no foralls+isTauTy :: Type -> Bool+isTauTy ty | Just ty' <- coreView ty = isTauTy ty'+isTauTy (TyVarTy _) = True+isTauTy (LitTy {}) = True+isTauTy (TyConApp tc tys) = all isTauTy tys && isTauTyCon tc+isTauTy (AppTy a b) = isTauTy a && isTauTy b+isTauTy (FunTy a b) = isTauTy a && isTauTy b+isTauTy (ForAllTy {}) = False+isTauTy (CastTy ty _) = isTauTy ty+isTauTy (CoercionTy _) = False -- Not sure about this++{-+%************************************************************************+%* *+ TyBinders+%* *+%************************************************************************+-}++-- | Make a named binder+mkTyVarBinder :: ArgFlag -> Var -> TyVarBinder+mkTyVarBinder vis var = TvBndr var vis++-- | Make many named binders+mkTyVarBinders :: ArgFlag -> [TyVar] -> [TyVarBinder]+mkTyVarBinders vis = map (mkTyVarBinder vis)++-- | Make an anonymous binder+mkAnonBinder :: Type -> TyBinder+mkAnonBinder = Anon++-- | Does this binder bind a variable that is /not/ erased? Returns+-- 'True' for anonymous binders.+isAnonTyBinder :: TyBinder -> Bool+isAnonTyBinder (Named {}) = False+isAnonTyBinder (Anon {}) = True++isNamedTyBinder :: TyBinder -> Bool+isNamedTyBinder (Named {}) = True+isNamedTyBinder (Anon {}) = False++tyBinderType :: TyBinder -> Type+-- Barely used+tyBinderType (Named tvb) = binderKind tvb+tyBinderType (Anon ty) = ty++-- | Extract a relevant type, if there is one.+binderRelevantType_maybe :: TyBinder -> Maybe Type+binderRelevantType_maybe (Named {}) = Nothing+binderRelevantType_maybe (Anon ty) = Just ty++-- | Like 'maybe', but for binders.+caseBinder :: TyBinder -- ^ binder to scrutinize+ -> (TyVarBinder -> a) -- ^ named case+ -> (Type -> a) -- ^ anonymous case+ -> a+caseBinder (Named v) f _ = f v+caseBinder (Anon t) _ d = d t++-- | Manufacture a new 'TyConBinder' from a 'TyBinder'. Anonymous+-- 'TyBinder's are still assigned names as 'TyConBinder's, so we need+-- the extra gunk with which to construct a 'Name'. Used when producing+-- tyConTyVars from a datatype kind signature. Defined here to avoid module+-- loops.+mkTyBinderTyConBinder :: TyBinder -> SrcSpan -> Unique -> OccName -> TyConBinder+mkTyBinderTyConBinder (Named (TvBndr tv argf)) _ _ _ = TvBndr tv (NamedTCB argf)+mkTyBinderTyConBinder (Anon kind) loc uniq occ+ = TvBndr (mkTyVar (mkInternalName uniq occ loc) kind) AnonTCB++{-+%************************************************************************+%* *+ Pred+* *+************************************************************************++Predicates on PredType++Note [isPredTy complications]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+You would think that we could define+ isPredTy ty = isConstraintKind (typeKind ty)+But there are a number of complications:++* isPredTy is used when printing types, which can happen in debug+ printing during type checking of not-fully-zonked types. So it's+ not cool to say isConstraintKind (typeKind ty) because, absent+ zonking, the type might be ill-kinded, and typeKind crashes. Hence the+ rather tiresome story here++* isPredTy must return "True" to *unlifted* coercions, such as (t1 ~# t2)+ and (t1 ~R# t2), which are not of kind Constraint! Currently they are+ of kind #.++* If we do form the type '(C a => C [a]) => blah', then we'd like to+ print it as such. But that means that isPredTy must return True for+ (C a => C [a]). Admittedly that type is illegal in Haskell, but we+ want to print it nicely in error messages.+-}++-- | Is the type suitable to classify a given/wanted in the typechecker?+isPredTy :: Type -> Bool+-- See Note [isPredTy complications]+isPredTy ty = go ty []+ where+ go :: Type -> [KindOrType] -> Bool+ go (AppTy ty1 ty2) args = go ty1 (ty2 : args)+ go (TyVarTy tv) args = go_k (tyVarKind tv) args+ go (TyConApp tc tys) args = ASSERT( null args ) -- TyConApp invariant+ go_tc tc tys+ go (FunTy arg res) []+ | isPredTy arg = isPredTy res -- (Eq a => C a)+ | otherwise = False -- (Int -> Bool)+ go (ForAllTy _ ty) [] = go ty []+ go (CastTy _ co) args = go_k (pSnd (coercionKind co)) args+ go _ _ = False++ go_tc :: TyCon -> [KindOrType] -> Bool+ go_tc tc args+ | tc `hasKey` eqPrimTyConKey || tc `hasKey` eqReprPrimTyConKey+ = length args == 4 -- ~# and ~R# sadly have result kind #+ -- not Constraint; but we still want+ -- isPredTy to reply True.+ | otherwise = go_k (tyConKind tc) args++ go_k :: Kind -> [KindOrType] -> Bool+ -- True <=> ('k' applied to 'kts') = Constraint+ go_k k [] = isConstraintKind k+ go_k k (arg:args) = case piResultTy_maybe k arg of+ Just k' -> go_k k' args+ Nothing -> WARN( True, text "isPredTy" <+> ppr ty )+ False+ -- This last case shouldn't happen under most circumstances. It can+ -- occur if we call isPredTy during kind checking, especially if one+ -- of the following happens:+ --+ -- 1. There is actually a kind error. Example in which this showed up:+ -- polykinds/T11399+ -- 2. A type constructor application appears to be oversaturated. An+ -- example of this occurred in GHC Trac #13187:+ --+ -- {-# LANGUAGE PolyKinds #-}+ -- type Const a b = b+ -- f :: Const Int (,) Bool Char -> Char+ --+ -- This code is actually fine, since Const is polymorphic in its+ -- return kind. It does show that isPredTy could possibly report a+ -- false negative if a constraint is similarly oversaturated, but+ -- it's hard to do better than isPredTy currently does without+ -- zonking, so we punt on such cases for now.++isClassPred, isEqPred, isNomEqPred, isIPPred :: PredType -> Bool+isClassPred ty = case tyConAppTyCon_maybe ty of+ Just tyCon | isClassTyCon tyCon -> True+ _ -> False+isEqPred ty = case tyConAppTyCon_maybe ty of+ Just tyCon -> tyCon `hasKey` eqPrimTyConKey+ || tyCon `hasKey` eqReprPrimTyConKey+ _ -> False++isNomEqPred ty = case tyConAppTyCon_maybe ty of+ Just tyCon -> tyCon `hasKey` eqPrimTyConKey+ _ -> False++isIPPred ty = case tyConAppTyCon_maybe ty of+ Just tc -> isIPTyCon tc+ _ -> False++isIPTyCon :: TyCon -> Bool+isIPTyCon tc = tc `hasKey` ipClassKey+ -- Class and its corresponding TyCon have the same Unique++isIPClass :: Class -> Bool+isIPClass cls = cls `hasKey` ipClassKey++isCTupleClass :: Class -> Bool+isCTupleClass cls = isTupleTyCon (classTyCon cls)++isIPPred_maybe :: Type -> Maybe (FastString, Type)+isIPPred_maybe ty =+ do (tc,[t1,t2]) <- splitTyConApp_maybe ty+ guard (isIPTyCon tc)+ x <- isStrLitTy t1+ return (x,t2)++{-+Make PredTypes++--------------------- Equality types ---------------------------------+-}++-- | Makes a lifted equality predicate at the given role+mkPrimEqPredRole :: Role -> Type -> Type -> PredType+mkPrimEqPredRole Nominal = mkPrimEqPred+mkPrimEqPredRole Representational = mkReprPrimEqPred+mkPrimEqPredRole Phantom = panic "mkPrimEqPredRole phantom"++-- | Creates a primitive type equality predicate.+-- Invariant: the types are not Coercions+mkPrimEqPred :: Type -> Type -> Type+mkPrimEqPred ty1 ty2+ = TyConApp eqPrimTyCon [k1, k2, ty1, ty2]+ where+ k1 = typeKind ty1+ k2 = typeKind ty2++-- | Creates a primite type equality predicate with explicit kinds+mkHeteroPrimEqPred :: Kind -> Kind -> Type -> Type -> Type+mkHeteroPrimEqPred k1 k2 ty1 ty2 = TyConApp eqPrimTyCon [k1, k2, ty1, ty2]++-- | Creates a primitive representational type equality predicate+-- with explicit kinds+mkHeteroReprPrimEqPred :: Kind -> Kind -> Type -> Type -> Type+mkHeteroReprPrimEqPred k1 k2 ty1 ty2+ = TyConApp eqReprPrimTyCon [k1, k2, ty1, ty2]++-- | Try to split up a coercion type into the types that it coerces+splitCoercionType_maybe :: Type -> Maybe (Type, Type)+splitCoercionType_maybe ty+ = do { (tc, [_, _, ty1, ty2]) <- splitTyConApp_maybe ty+ ; guard $ tc `hasKey` eqPrimTyConKey || tc `hasKey` eqReprPrimTyConKey+ ; return (ty1, ty2) }++mkReprPrimEqPred :: Type -> Type -> Type+mkReprPrimEqPred ty1 ty2+ = TyConApp eqReprPrimTyCon [k1, k2, ty1, ty2]+ where+ k1 = typeKind ty1+ k2 = typeKind ty2++equalityTyCon :: Role -> TyCon+equalityTyCon Nominal = eqPrimTyCon+equalityTyCon Representational = eqReprPrimTyCon+equalityTyCon Phantom = eqPhantPrimTyCon++-- --------------------- Dictionary types ---------------------------------++mkClassPred :: Class -> [Type] -> PredType+mkClassPred clas tys = TyConApp (classTyCon clas) tys++isDictTy :: Type -> Bool+isDictTy = isClassPred++isDictLikeTy :: Type -> Bool+-- Note [Dictionary-like types]+isDictLikeTy ty | Just ty' <- coreView ty = isDictLikeTy ty'+isDictLikeTy ty = case splitTyConApp_maybe ty of+ Just (tc, tys) | isClassTyCon tc -> True+ | isTupleTyCon tc -> all isDictLikeTy tys+ _other -> False++{-+Note [Dictionary-like types]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Being "dictionary-like" means either a dictionary type or a tuple thereof.+In GHC 6.10 we build implication constraints which construct such tuples,+and if we land up with a binding+ t :: (C [a], Eq [a])+ t = blah+then we want to treat t as cheap under "-fdicts-cheap" for example.+(Implication constraints are normally inlined, but sadly not if the+occurrence is itself inside an INLINE function! Until we revise the+handling of implication constraints, that is.) This turned out to+be important in getting good arities in DPH code. Example:++ class C a+ class D a where { foo :: a -> a }+ instance C a => D (Maybe a) where { foo x = x }++ bar :: (C a, C b) => a -> b -> (Maybe a, Maybe b)+ {-# INLINE bar #-}+ bar x y = (foo (Just x), foo (Just y))++Then 'bar' should jolly well have arity 4 (two dicts, two args), but+we ended up with something like+ bar = __inline_me__ (\d1,d2. let t :: (D (Maybe a), D (Maybe b)) = ...+ in \x,y. <blah>)++This is all a bit ad-hoc; eg it relies on knowing that implication+constraints build tuples.+++Decomposing PredType+-}++-- | A choice of equality relation. This is separate from the type 'Role'+-- because 'Phantom' does not define a (non-trivial) equality relation.+data EqRel = NomEq | ReprEq+ deriving (Eq, Ord)++instance Outputable EqRel where+ ppr NomEq = text "nominal equality"+ ppr ReprEq = text "representational equality"++eqRelRole :: EqRel -> Role+eqRelRole NomEq = Nominal+eqRelRole ReprEq = Representational++data PredTree = ClassPred Class [Type]+ | EqPred EqRel Type Type+ | IrredPred PredType++classifyPredType :: PredType -> PredTree+classifyPredType ev_ty = case splitTyConApp_maybe ev_ty of+ Just (tc, [_, _, ty1, ty2])+ | tc `hasKey` eqReprPrimTyConKey -> EqPred ReprEq ty1 ty2+ | tc `hasKey` eqPrimTyConKey -> EqPred NomEq ty1 ty2+ Just (tc, tys)+ | Just clas <- tyConClass_maybe tc -> ClassPred clas tys+ _ -> IrredPred ev_ty++getClassPredTys :: PredType -> (Class, [Type])+getClassPredTys ty = case getClassPredTys_maybe ty of+ Just (clas, tys) -> (clas, tys)+ Nothing -> pprPanic "getClassPredTys" (ppr ty)++getClassPredTys_maybe :: PredType -> Maybe (Class, [Type])+getClassPredTys_maybe ty = case splitTyConApp_maybe ty of+ Just (tc, tys) | Just clas <- tyConClass_maybe tc -> Just (clas, tys)+ _ -> Nothing++getEqPredTys :: PredType -> (Type, Type)+getEqPredTys ty+ = case splitTyConApp_maybe ty of+ Just (tc, [_, _, ty1, ty2])+ | tc `hasKey` eqPrimTyConKey+ || tc `hasKey` eqReprPrimTyConKey+ -> (ty1, ty2)+ _ -> pprPanic "getEqPredTys" (ppr ty)++getEqPredTys_maybe :: PredType -> Maybe (Role, Type, Type)+getEqPredTys_maybe ty+ = case splitTyConApp_maybe ty of+ Just (tc, [_, _, ty1, ty2])+ | tc `hasKey` eqPrimTyConKey -> Just (Nominal, ty1, ty2)+ | tc `hasKey` eqReprPrimTyConKey -> Just (Representational, ty1, ty2)+ _ -> Nothing++getEqPredRole :: PredType -> Role+getEqPredRole ty = eqRelRole (predTypeEqRel ty)++-- | Get the equality relation relevant for a pred type.+predTypeEqRel :: PredType -> EqRel+predTypeEqRel ty+ | Just (tc, _) <- splitTyConApp_maybe ty+ , tc `hasKey` eqReprPrimTyConKey+ = ReprEq+ | otherwise+ = NomEq++{-+%************************************************************************+%* *+ Well-scoped tyvars+* *+************************************************************************+-}++-- | Do a topological sort on a list of tyvars,+-- so that binders occur before occurrences+-- E.g. given [ a::k, k::*, b::k ]+-- it'll return a well-scoped list [ k::*, a::k, b::k ]+--+-- This is a deterministic sorting operation+-- (that is, doesn't depend on Uniques).+toposortTyVars :: [TyVar] -> [TyVar]+toposortTyVars tvs = reverse $+ [ tv | (tv, _, _) <- topologicalSortG $+ graphFromEdgedVerticesOrd nodes ]+ where+ var_ids :: VarEnv Int+ var_ids = mkVarEnv (zip tvs [1..])++ nodes = [ ( tv+ , lookupVarEnv_NF var_ids tv+ , mapMaybe (lookupVarEnv var_ids)+ (tyCoVarsOfTypeList (tyVarKind tv)) )+ | tv <- tvs ]++-- | Extract a well-scoped list of variables from a deterministic set of+-- variables. The result is deterministic.+-- NB: There used to exist varSetElemsWellScoped :: VarSet -> [Var] which+-- took a non-deterministic set and produced a non-deterministic+-- well-scoped list. If you care about the list being well-scoped you also+-- most likely care about it being in deterministic order.+dVarSetElemsWellScoped :: DVarSet -> [Var]+dVarSetElemsWellScoped = toposortTyVars . dVarSetElems++-- | Get the free vars of a type in scoped order+tyCoVarsOfTypeWellScoped :: Type -> [TyVar]+tyCoVarsOfTypeWellScoped = toposortTyVars . tyCoVarsOfTypeList++-- | Get the free vars of types in scoped order+tyCoVarsOfTypesWellScoped :: [Type] -> [TyVar]+tyCoVarsOfTypesWellScoped = toposortTyVars . tyCoVarsOfTypesList++{-+************************************************************************+* *+\subsection{Type families}+* *+************************************************************************+-}++mkFamilyTyConApp :: TyCon -> [Type] -> Type+-- ^ Given a family instance TyCon and its arg types, return the+-- corresponding family type. E.g:+--+-- > data family T a+-- > data instance T (Maybe b) = MkT b+--+-- Where the instance tycon is :RTL, so:+--+-- > mkFamilyTyConApp :RTL Int = T (Maybe Int)+mkFamilyTyConApp tc tys+ | Just (fam_tc, fam_tys) <- tyConFamInst_maybe tc+ , let tvs = tyConTyVars tc+ fam_subst = ASSERT2( length tvs == length tys, ppr tc <+> ppr tys )+ zipTvSubst tvs tys+ = mkTyConApp fam_tc (substTys fam_subst fam_tys)+ | otherwise+ = mkTyConApp tc tys++-- | Get the type on the LHS of a coercion induced by a type/data+-- family instance.+coAxNthLHS :: CoAxiom br -> Int -> Type+coAxNthLHS ax ind =+ mkTyConApp (coAxiomTyCon ax) (coAxBranchLHS (coAxiomNthBranch ax ind))++-- | Pretty prints a 'TyCon', using the family instance in case of a+-- representation tycon. For example:+--+-- > data T [a] = ...+--+-- In that case we want to print @T [a]@, where @T@ is the family 'TyCon'+pprSourceTyCon :: TyCon -> SDoc+pprSourceTyCon tycon+ | Just (fam_tc, tys) <- tyConFamInst_maybe tycon+ = ppr $ fam_tc `TyConApp` tys -- can't be FunTyCon+ | otherwise+ = ppr tycon++-- @isTauTy@ tests if a type has no foralls+isFamFreeTy :: Type -> Bool+isFamFreeTy ty | Just ty' <- coreView ty = isFamFreeTy ty'+isFamFreeTy (TyVarTy _) = True+isFamFreeTy (LitTy {}) = True+isFamFreeTy (TyConApp tc tys) = all isFamFreeTy tys && isFamFreeTyCon tc+isFamFreeTy (AppTy a b) = isFamFreeTy a && isFamFreeTy b+isFamFreeTy (FunTy a b) = isFamFreeTy a && isFamFreeTy b+isFamFreeTy (ForAllTy _ ty) = isFamFreeTy ty+isFamFreeTy (CastTy ty _) = isFamFreeTy ty+isFamFreeTy (CoercionTy _) = False -- Not sure about this++{-+************************************************************************+* *+\subsection{Liftedness}+* *+************************************************************************+-}++-- | Returns Just True if this type is surely lifted, Just False+-- if it is surely unlifted, Nothing if we can't be sure (i.e., it is+-- levity polymorphic), and panics if the kind does not have the shape+-- TYPE r.+isLiftedType_maybe :: HasDebugCallStack => Type -> Maybe Bool+isLiftedType_maybe ty = go (getRuntimeRep "isLiftedType_maybe" ty)+ where+ go rr | Just rr' <- coreView rr = go rr'+ go (TyConApp lifted_rep [])+ | lifted_rep `hasKey` liftedRepDataConKey = Just True+ go (TyConApp {}) = Just False -- everything else is unlifted+ go _ = Nothing -- levity polymorphic++-- | See "Type#type_classification" for what an unlifted type is.+-- Panics on levity polymorphic types.+isUnliftedType :: HasDebugCallStack => Type -> Bool+ -- isUnliftedType returns True for forall'd unlifted types:+ -- x :: forall a. Int#+ -- I found bindings like these were getting floated to the top level.+ -- They are pretty bogus types, mind you. It would be better never to+ -- construct them+isUnliftedType ty+ = not (isLiftedType_maybe ty `orElse`+ pprPanic "isUnliftedType" (ppr ty <+> dcolon <+> ppr (typeKind ty)))++-- | Extract the RuntimeRep classifier of a type. For instance,+-- @getRuntimeRep_maybe Int = LiftedRep@. Returns 'Nothing' if this is not+-- possible.+getRuntimeRep_maybe :: HasDebugCallStack+ => Type -> Maybe Type+getRuntimeRep_maybe = getRuntimeRepFromKind_maybe . typeKind++-- | Extract the RuntimeRep classifier of a type. For instance,+-- @getRuntimeRep_maybe Int = LiftedRep@. Panics if this is not possible.+getRuntimeRep :: HasDebugCallStack+ => String -- ^ Printed in case of an error+ -> Type -> Type+getRuntimeRep err ty =+ case getRuntimeRep_maybe ty of+ Just r -> r+ Nothing -> pprPanic "getRuntimeRep"+ (text err $$ ppr ty <+> dcolon <+> ppr (typeKind ty))++-- | Extract the RuntimeRep classifier of a type from its kind. For example,+-- @getRuntimeRepFromKind * = LiftedRep@; Panics if this is not possible.+getRuntimeRepFromKind :: HasDebugCallStack+ => String -> Type -> Type+getRuntimeRepFromKind err k =+ case getRuntimeRepFromKind_maybe k of+ Just r -> r+ Nothing -> pprPanic "getRuntimeRepFromKind"+ (text err $$ ppr k <+> dcolon <+> ppr (typeKind k))++-- | Extract the RuntimeRep classifier of a type from its kind. For example,+-- @getRuntimeRepFromKind * = LiftedRep@; Returns 'Nothing' if this is not+-- possible.+getRuntimeRepFromKind_maybe :: HasDebugCallStack+ => Type -> Maybe Type+getRuntimeRepFromKind_maybe = go+ where+ go k | Just k' <- coreView k = go k'+ go k+ | Just (_tc, [arg]) <- splitTyConApp_maybe k+ = ASSERT2( _tc `hasKey` tYPETyConKey, ppr k )+ Just arg+ go _ = Nothing++isUnboxedTupleType :: Type -> Bool+isUnboxedTupleType ty+ = tyConAppTyCon (getRuntimeRep "isUnboxedTupleType" ty) `hasKey` tupleRepDataConKey+ -- NB: Do not use typePrimRep, as that can't tell the difference between+ -- unboxed tuples and unboxed sums+++isUnboxedSumType :: Type -> Bool+isUnboxedSumType ty+ = tyConAppTyCon (getRuntimeRep "isUnboxedSumType" ty) `hasKey` sumRepDataConKey++-- | See "Type#type_classification" for what an algebraic type is.+-- Should only be applied to /types/, as opposed to e.g. partially+-- saturated type constructors+isAlgType :: Type -> Bool+isAlgType ty+ = case splitTyConApp_maybe ty of+ Just (tc, ty_args) -> ASSERT( ty_args `lengthIs` tyConArity tc )+ isAlgTyCon tc+ _other -> False++-- | See "Type#type_classification" for what an algebraic type is.+-- Should only be applied to /types/, as opposed to e.g. partially+-- saturated type constructors. Closed type constructors are those+-- with a fixed right hand side, as opposed to e.g. associated types+isClosedAlgType :: Type -> Bool+isClosedAlgType ty+ = case splitTyConApp_maybe ty of+ Just (tc, ty_args) | isAlgTyCon tc && not (isFamilyTyCon tc)+ -> ASSERT2( ty_args `lengthIs` tyConArity tc, ppr ty ) True+ _other -> False++-- | Check whether a type is a data family type+isDataFamilyAppType :: Type -> Bool+isDataFamilyAppType ty = case tyConAppTyCon_maybe ty of+ Just tc -> isDataFamilyTyCon tc+ _ -> False++-- | Computes whether an argument (or let right hand side) should+-- be computed strictly or lazily, based only on its type.+-- Currently, it's just 'isUnliftedType'. Panics on levity-polymorphic types.+isStrictType :: HasDebugCallStack => Type -> Bool+isStrictType = isUnliftedType++isPrimitiveType :: Type -> Bool+-- ^ Returns true of types that are opaque to Haskell.+isPrimitiveType ty = case splitTyConApp_maybe ty of+ Just (tc, ty_args) -> ASSERT( ty_args `lengthIs` tyConArity tc )+ isPrimTyCon tc+ _ -> False++{-+************************************************************************+* *+\subsection{Join points}+* *+************************************************************************+-}++-- | Determine whether a type could be the type of a join point of given total+-- arity, according to the polymorphism rule. A join point cannot be polymorphic+-- in its return type, since given+-- join j @a @b x y z = e1 in e2,+-- the types of e1 and e2 must be the same, and a and b are not in scope for e2.+-- (See Note [The polymorphism rule of join points] in CoreSyn.) Returns False+-- also if the type simply doesn't have enough arguments.+--+-- Note that we need to know how many arguments (type *and* value) the putative+-- join point takes; for instance, if+-- j :: forall a. a -> Int+-- then j could be a binary join point returning an Int, but it could *not* be a+-- unary join point returning a -> Int.+--+-- TODO: See Note [Excess polymorphism and join points]+isValidJoinPointType :: JoinArity -> Type -> Bool+isValidJoinPointType arity ty+ = valid_under emptyVarSet arity ty+ where+ valid_under tvs arity ty+ | arity == 0+ = isEmptyVarSet (tvs `intersectVarSet` tyCoVarsOfType ty)+ | Just (t, ty') <- splitForAllTy_maybe ty+ = valid_under (tvs `extendVarSet` t) (arity-1) ty'+ | Just (_, res_ty) <- splitFunTy_maybe ty+ = valid_under tvs (arity-1) res_ty+ | otherwise+ = False++{-+************************************************************************+* *+\subsection{Sequencing on types}+* *+************************************************************************+-}++seqType :: Type -> ()+seqType (LitTy n) = n `seq` ()+seqType (TyVarTy tv) = tv `seq` ()+seqType (AppTy t1 t2) = seqType t1 `seq` seqType t2+seqType (FunTy t1 t2) = seqType t1 `seq` seqType t2+seqType (TyConApp tc tys) = tc `seq` seqTypes tys+seqType (ForAllTy (TvBndr tv _) ty) = seqType (tyVarKind tv) `seq` seqType ty+seqType (CastTy ty co) = seqType ty `seq` seqCo co+seqType (CoercionTy co) = seqCo co++seqTypes :: [Type] -> ()+seqTypes [] = ()+seqTypes (ty:tys) = seqType ty `seq` seqTypes tys++{-+************************************************************************+* *+ Comparison for types+ (We don't use instances so that we know where it happens)+* *+************************************************************************++Note [Equality on AppTys]+~~~~~~~~~~~~~~~~~~~~~~~~~+In our cast-ignoring equality, we want to say that the following two+are equal:++ (Maybe |> co) (Int |> co') ~? Maybe Int++But the left is an AppTy while the right is a TyConApp. The solution is+to use repSplitAppTy_maybe to break up the TyConApp into its pieces and+then continue. Easy to do, but also easy to forget to do.++-}++eqType :: Type -> Type -> Bool+-- ^ Type equality on source types. Does not look through @newtypes@ or+-- 'PredType's, but it does look through type synonyms.+-- This first checks that the kinds of the types are equal and then+-- checks whether the types are equal, ignoring casts and coercions.+-- (The kind check is a recursive call, but since all kinds have type+-- @Type@, there is no need to check the types of kinds.)+-- See also Note [Non-trivial definitional equality] in TyCoRep.+eqType t1 t2 = isEqual $ nonDetCmpType t1 t2+ -- It's OK to use nonDetCmpType here and eqType is deterministic,+ -- nonDetCmpType does equality deterministically++-- | Compare types with respect to a (presumably) non-empty 'RnEnv2'.+eqTypeX :: RnEnv2 -> Type -> Type -> Bool+eqTypeX env t1 t2 = isEqual $ nonDetCmpTypeX env t1 t2+ -- It's OK to use nonDetCmpType here and eqTypeX is deterministic,+ -- nonDetCmpTypeX does equality deterministically++-- | Type equality on lists of types, looking through type synonyms+-- but not newtypes.+eqTypes :: [Type] -> [Type] -> Bool+eqTypes tys1 tys2 = isEqual $ nonDetCmpTypes tys1 tys2+ -- It's OK to use nonDetCmpType here and eqTypes is deterministic,+ -- nonDetCmpTypes does equality deterministically++eqVarBndrs :: RnEnv2 -> [Var] -> [Var] -> Maybe RnEnv2+-- Check that the var lists are the same length+-- and have matching kinds; if so, extend the RnEnv2+-- Returns Nothing if they don't match+eqVarBndrs env [] []+ = Just env+eqVarBndrs env (tv1:tvs1) (tv2:tvs2)+ | eqTypeX env (tyVarKind tv1) (tyVarKind tv2)+ = eqVarBndrs (rnBndr2 env tv1 tv2) tvs1 tvs2+eqVarBndrs _ _ _= Nothing++-- Now here comes the real worker++{-+Note [nonDetCmpType nondeterminism]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+nonDetCmpType is implemented in terms of nonDetCmpTypeX. nonDetCmpTypeX+uses nonDetCmpTc which compares TyCons by their Unique value. Using Uniques for+ordering leads to nondeterminism. We hit the same problem in the TyVarTy case,+comparing type variables is nondeterministic, note the call to nonDetCmpVar in+nonDetCmpTypeX.+See Note [Unique Determinism] for more details.+-}++nonDetCmpType :: Type -> Type -> Ordering+nonDetCmpType t1 t2+ -- we know k1 and k2 have the same kind, because they both have kind *.+ = nonDetCmpTypeX rn_env t1 t2+ where+ rn_env = mkRnEnv2 (mkInScopeSet (tyCoVarsOfTypes [t1, t2]))++nonDetCmpTypes :: [Type] -> [Type] -> Ordering+nonDetCmpTypes ts1 ts2 = nonDetCmpTypesX rn_env ts1 ts2+ where+ rn_env = mkRnEnv2 (mkInScopeSet (tyCoVarsOfTypes (ts1 ++ ts2)))++-- | An ordering relation between two 'Type's (known below as @t1 :: k1@+-- and @t2 :: k2@)+data TypeOrdering = TLT -- ^ @t1 < t2@+ | TEQ -- ^ @t1 ~ t2@ and there are no casts in either,+ -- therefore we can conclude @k1 ~ k2@+ | TEQX -- ^ @t1 ~ t2@ yet one of the types contains a cast so+ -- they may differ in kind.+ | TGT -- ^ @t1 > t2@+ deriving (Eq, Ord, Enum, Bounded)++nonDetCmpTypeX :: RnEnv2 -> Type -> Type -> Ordering -- Main workhorse+ -- See Note [Non-trivial definitional equality] in TyCoRep+nonDetCmpTypeX env orig_t1 orig_t2 =+ case go env orig_t1 orig_t2 of+ -- If there are casts then we also need to do a comparison of the kinds of+ -- the types being compared+ TEQX -> toOrdering $ go env k1 k2+ ty_ordering -> toOrdering ty_ordering+ where+ k1 = typeKind orig_t1+ k2 = typeKind orig_t2++ toOrdering :: TypeOrdering -> Ordering+ toOrdering TLT = LT+ toOrdering TEQ = EQ+ toOrdering TEQX = EQ+ toOrdering TGT = GT++ liftOrdering :: Ordering -> TypeOrdering+ liftOrdering LT = TLT+ liftOrdering EQ = TEQ+ liftOrdering GT = TGT++ thenCmpTy :: TypeOrdering -> TypeOrdering -> TypeOrdering+ thenCmpTy TEQ rel = rel+ thenCmpTy TEQX rel = hasCast rel+ thenCmpTy rel _ = rel++ hasCast :: TypeOrdering -> TypeOrdering+ hasCast TEQ = TEQX+ hasCast rel = rel++ -- Returns both the resulting ordering relation between the two types+ -- and whether either contains a cast.+ go :: RnEnv2 -> Type -> Type -> TypeOrdering+ go env t1 t2+ | Just t1' <- coreView t1 = go env t1' t2+ | Just t2' <- coreView t2 = go env t1 t2'++ go env (TyVarTy tv1) (TyVarTy tv2)+ = liftOrdering $ rnOccL env tv1 `nonDetCmpVar` rnOccR env tv2+ go env (ForAllTy (TvBndr tv1 _) t1) (ForAllTy (TvBndr tv2 _) t2)+ = go env (tyVarKind tv1) (tyVarKind tv2)+ `thenCmpTy` go (rnBndr2 env tv1 tv2) t1 t2+ -- See Note [Equality on AppTys]+ go env (AppTy s1 t1) ty2+ | Just (s2, t2) <- repSplitAppTy_maybe ty2+ = go env s1 s2 `thenCmpTy` go env t1 t2+ go env ty1 (AppTy s2 t2)+ | Just (s1, t1) <- repSplitAppTy_maybe ty1+ = go env s1 s2 `thenCmpTy` go env t1 t2+ go env (FunTy s1 t1) (FunTy s2 t2)+ = go env s1 s2 `thenCmpTy` go env t1 t2+ go env (TyConApp tc1 tys1) (TyConApp tc2 tys2)+ = liftOrdering (tc1 `nonDetCmpTc` tc2) `thenCmpTy` gos env tys1 tys2+ go _ (LitTy l1) (LitTy l2) = liftOrdering (compare l1 l2)+ go env (CastTy t1 _) t2 = hasCast $ go env t1 t2+ go env t1 (CastTy t2 _) = hasCast $ go env t1 t2++ go _ (CoercionTy {}) (CoercionTy {}) = TEQ++ -- Deal with the rest: TyVarTy < CoercionTy < AppTy < LitTy < TyConApp < ForAllTy+ go _ ty1 ty2+ = liftOrdering $ (get_rank ty1) `compare` (get_rank ty2)+ where get_rank :: Type -> Int+ get_rank (CastTy {})+ = pprPanic "nonDetCmpTypeX.get_rank" (ppr [ty1,ty2])+ get_rank (TyVarTy {}) = 0+ get_rank (CoercionTy {}) = 1+ get_rank (AppTy {}) = 3+ get_rank (LitTy {}) = 4+ get_rank (TyConApp {}) = 5+ get_rank (FunTy {}) = 6+ get_rank (ForAllTy {}) = 7++ gos :: RnEnv2 -> [Type] -> [Type] -> TypeOrdering+ gos _ [] [] = TEQ+ gos _ [] _ = TLT+ gos _ _ [] = TGT+ gos env (ty1:tys1) (ty2:tys2) = go env ty1 ty2 `thenCmpTy` gos env tys1 tys2++-------------+nonDetCmpTypesX :: RnEnv2 -> [Type] -> [Type] -> Ordering+nonDetCmpTypesX _ [] [] = EQ+nonDetCmpTypesX env (t1:tys1) (t2:tys2) = nonDetCmpTypeX env t1 t2+ `thenCmp` nonDetCmpTypesX env tys1 tys2+nonDetCmpTypesX _ [] _ = LT+nonDetCmpTypesX _ _ [] = GT++-------------+-- | Compare two 'TyCon's. NB: This should /never/ see the "star synonyms",+-- as recognized by Kind.isStarKindSynonymTyCon. See Note+-- [Kind Constraint and kind *] in Kind.+-- See Note [nonDetCmpType nondeterminism]+nonDetCmpTc :: TyCon -> TyCon -> Ordering+nonDetCmpTc tc1 tc2+ = ASSERT( not (isStarKindSynonymTyCon tc1) && not (isStarKindSynonymTyCon tc2) )+ u1 `nonDetCmpUnique` u2+ where+ u1 = tyConUnique tc1+ u2 = tyConUnique tc2++{-+************************************************************************+* *+ The kind of a type+* *+************************************************************************+-}++typeKind :: Type -> Kind+typeKind (TyConApp tc tys) = piResultTys (tyConKind tc) tys+typeKind (AppTy fun arg) = piResultTy (typeKind fun) arg+typeKind (LitTy l) = typeLiteralKind l+typeKind (FunTy {}) = liftedTypeKind+typeKind (ForAllTy _ ty) = typeKind ty+typeKind (TyVarTy tyvar) = tyVarKind tyvar+typeKind (CastTy _ty co) = pSnd $ coercionKind co+typeKind (CoercionTy co) = coercionType co++typeLiteralKind :: TyLit -> Kind+typeLiteralKind l =+ case l of+ NumTyLit _ -> typeNatKind+ StrTyLit _ -> typeSymbolKind++-- | Returns True if a type is levity polymorphic. Should be the same+-- as (isKindLevPoly . typeKind) but much faster.+-- Precondition: The type has kind (TYPE blah)+isTypeLevPoly :: Type -> Bool+isTypeLevPoly = go+ where+ go ty@(TyVarTy {}) = check_kind ty+ go ty@(AppTy {}) = check_kind ty+ go ty@(TyConApp tc _) | not (isTcLevPoly tc) = False+ | otherwise = check_kind ty+ go (ForAllTy _ ty) = go ty+ go (FunTy {}) = False+ go (LitTy {}) = False+ go ty@(CastTy {}) = check_kind ty+ go ty@(CoercionTy {}) = pprPanic "isTypeLevPoly co" (ppr ty)++ check_kind = isKindLevPoly . typeKind++-- | Looking past all pi-types, is the end result potentially levity polymorphic?+-- Example: True for (forall r (a :: TYPE r). String -> a)+-- Example: False for (forall r1 r2 (a :: TYPE r1) (b :: TYPE r2). a -> b -> Type)+resultIsLevPoly :: Type -> Bool+resultIsLevPoly = isTypeLevPoly . snd . splitPiTys++{-+%************************************************************************+%* *+ Miscellaneous functions+%* *+%************************************************************************++-}+-- | All type constructors occurring in the type; looking through type+-- synonyms, but not newtypes.+-- When it finds a Class, it returns the class TyCon.+tyConsOfType :: Type -> UniqSet TyCon+tyConsOfType ty+ = go ty+ where+ go :: Type -> UniqSet TyCon -- The UniqSet does duplicate elim+ go ty | Just ty' <- coreView ty = go ty'+ go (TyVarTy {}) = emptyUniqSet+ go (LitTy {}) = emptyUniqSet+ go (TyConApp tc tys) = go_tc tc `unionUniqSets` go_s tys+ go (AppTy a b) = go a `unionUniqSets` go b+ go (FunTy a b) = go a `unionUniqSets` go b `unionUniqSets` go_tc funTyCon+ go (ForAllTy (TvBndr tv _) ty) = go ty `unionUniqSets` go (tyVarKind tv)+ go (CastTy ty co) = go ty `unionUniqSets` go_co co+ go (CoercionTy co) = go_co co++ go_co (Refl _ ty) = go ty+ go_co (TyConAppCo _ tc args) = go_tc tc `unionUniqSets` go_cos args+ go_co (AppCo co arg) = go_co co `unionUniqSets` go_co arg+ go_co (ForAllCo _ kind_co co) = go_co kind_co `unionUniqSets` go_co co+ go_co (FunCo _ co1 co2) = go_co co1 `unionUniqSets` go_co co2+ go_co (AxiomInstCo ax _ args) = go_ax ax `unionUniqSets` go_cos args+ go_co (UnivCo p _ t1 t2) = go_prov p `unionUniqSets` go t1 `unionUniqSets` go t2+ go_co (CoVarCo {}) = emptyUniqSet+ go_co (SymCo co) = go_co co+ go_co (TransCo co1 co2) = go_co co1 `unionUniqSets` go_co co2+ go_co (NthCo _ co) = go_co co+ go_co (LRCo _ co) = go_co co+ go_co (InstCo co arg) = go_co co `unionUniqSets` go_co arg+ go_co (CoherenceCo co1 co2) = go_co co1 `unionUniqSets` go_co co2+ go_co (KindCo co) = go_co co+ go_co (SubCo co) = go_co co+ go_co (AxiomRuleCo _ cs) = go_cos cs++ go_prov UnsafeCoerceProv = emptyUniqSet+ go_prov (PhantomProv co) = go_co co+ go_prov (ProofIrrelProv co) = go_co co+ go_prov (PluginProv _) = emptyUniqSet+ go_prov (HoleProv _) = emptyUniqSet+ -- this last case can happen from the tyConsOfType used from+ -- checkTauTvUpdate++ go_s tys = foldr (unionUniqSets . go) emptyUniqSet tys+ go_cos cos = foldr (unionUniqSets . go_co) emptyUniqSet cos++ go_tc tc = unitUniqSet tc+ go_ax ax = go_tc $ coAxiomTyCon ax++-- | Find the result 'Kind' of a type synonym,+-- after applying it to its 'arity' number of type variables+-- Actually this function works fine on data types too,+-- but they'd always return '*', so we never need to ask+synTyConResKind :: TyCon -> Kind+synTyConResKind tycon = piResultTys (tyConKind tycon) (mkTyVarTys (tyConTyVars tycon))++-- | Retrieve the free variables in this type, splitting them based+-- on whether they are used visibly or invisibly. Invisible ones come+-- first.+splitVisVarsOfType :: Type -> Pair TyCoVarSet+splitVisVarsOfType orig_ty = Pair invis_vars vis_vars+ where+ Pair invis_vars1 vis_vars = go orig_ty+ invis_vars = invis_vars1 `minusVarSet` vis_vars++ go (TyVarTy tv) = Pair (tyCoVarsOfType $ tyVarKind tv) (unitVarSet tv)+ go (AppTy t1 t2) = go t1 `mappend` go t2+ go (TyConApp tc tys) = go_tc tc tys+ go (FunTy t1 t2) = go t1 `mappend` go t2+ go (ForAllTy (TvBndr tv _) ty)+ = ((`delVarSet` tv) <$> go ty) `mappend`+ (invisible (tyCoVarsOfType $ tyVarKind tv))+ go (LitTy {}) = mempty+ go (CastTy ty co) = go ty `mappend` invisible (tyCoVarsOfCo co)+ go (CoercionTy co) = invisible $ tyCoVarsOfCo co++ invisible vs = Pair vs emptyVarSet++ go_tc tc tys = let (invis, vis) = partitionInvisibles tc id tys in+ invisible (tyCoVarsOfTypes invis) `mappend` foldMap go vis++splitVisVarsOfTypes :: [Type] -> Pair TyCoVarSet+splitVisVarsOfTypes = foldMap splitVisVarsOfType++modifyJoinResTy :: Int -- Number of binders to skip+ -> (Type -> Type) -- Function to apply to result type+ -> Type -- Type of join point+ -> Type -- New type+-- INVARIANT: If any of the first n binders are foralls, those tyvars cannot+-- appear in the original result type. See isValidJoinPointType.+modifyJoinResTy orig_ar f orig_ty+ = go orig_ar orig_ty+ where+ go 0 ty = f ty+ go n ty | Just (arg_bndr, res_ty) <- splitPiTy_maybe ty+ = mkPiTy arg_bndr (go (n-1) res_ty)+ | otherwise+ = pprPanic "modifyJoinResTy" (ppr orig_ar <+> ppr orig_ty)++setJoinResTy :: Int -- Number of binders to skip+ -> Type -- New result type+ -> Type -- Type of join point+ -> Type -- New type+-- INVARIANT: Same as for modifyJoinResTy+setJoinResTy ar new_res_ty ty+ = modifyJoinResTy ar (const new_res_ty) ty
+ types/Type.hs-boot view
@@ -0,0 +1,26 @@+{-# LANGUAGE FlexibleContexts #-}++module Type where+import TyCon+import Var ( TyVar )+import {-# SOURCE #-} TyCoRep( Type, Coercion, Kind )+import Util++isPredTy :: Type -> Bool+isCoercionTy :: Type -> Bool++mkAppTy :: Type -> Type -> Type+mkCastTy :: Type -> Coercion -> Type+piResultTy :: Type -> Type -> Type++typeKind :: Type -> Kind+eqType :: Type -> Type -> Bool++partitionInvisibles :: TyCon -> (a -> Type) -> [a] -> ([a], [a])++coreView :: Type -> Maybe Type+tcView :: Type -> Maybe Type++tyCoVarsOfTypesWellScoped :: [Type] -> [TyVar]+tyCoVarsOfTypeWellScoped :: Type -> [TyVar]+splitTyConApp_maybe :: HasDebugCallStack => Type -> Maybe (TyCon, [Type])
+ types/Unify.hs view
@@ -0,0 +1,1344 @@+-- (c) The University of Glasgow 2006++{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveFunctor #-}++module Unify (+ tcMatchTy, tcMatchTyKi,+ tcMatchTys, tcMatchTyKis,+ tcMatchTyX, tcMatchTysX, tcMatchTyKisX,+ ruleMatchTyKiX,++ -- * Rough matching+ roughMatchTcs, instanceCantMatch,+ typesCantMatch,++ -- Side-effect free unification+ tcUnifyTy, tcUnifyTyKi, tcUnifyTys, tcUnifyTyKis,+ tcUnifyTysFG, tcUnifyTyWithTFs,+ BindFlag(..),+ UnifyResult, UnifyResultM(..),++ -- Matching a type against a lifted type (coercion)+ liftCoMatch+ ) where++#include "HsVersions.h"++import Var+import VarEnv+import VarSet+import Kind+import Name( Name )+import Type hiding ( getTvSubstEnv )+import Coercion hiding ( getCvSubstEnv )+import TyCon+import TyCoRep hiding ( getTvSubstEnv, getCvSubstEnv )+import Util+import Pair+import Outputable+import UniqFM+import UniqSet++import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif+import Control.Applicative hiding ( empty )+import qualified Control.Applicative++{-++Unification is much tricker than you might think.++1. The substitution we generate binds the *template type variables*+ which are given to us explicitly.++2. We want to match in the presence of foralls;+ e.g (forall a. t1) ~ (forall b. t2)++ That is what the RnEnv2 is for; it does the alpha-renaming+ that makes it as if a and b were the same variable.+ Initialising the RnEnv2, so that it can generate a fresh+ binder when necessary, entails knowing the free variables of+ both types.++3. We must be careful not to bind a template type variable to a+ locally bound variable. E.g.+ (forall a. x) ~ (forall b. b)+ where x is the template type variable. Then we do not want to+ bind x to a/b! This is a kind of occurs check.+ The necessary locals accumulate in the RnEnv2.+-}++-- | @tcMatchTy t1 t2@ produces a substitution (over fvs(t1))+-- @s@ such that @s(t1)@ equals @t2@.+-- The returned substitution might bind coercion variables,+-- if the variable is an argument to a GADT constructor.+--+-- Precondition: typeKind ty1 `eqType` typeKind ty2+--+-- We don't pass in a set of "template variables" to be bound+-- by the match, because tcMatchTy (and similar functions) are+-- always used on top-level types, so we can bind any of the+-- free variables of the LHS.+tcMatchTy :: Type -> Type -> Maybe TCvSubst+tcMatchTy ty1 ty2 = tcMatchTys [ty1] [ty2]++-- | Like 'tcMatchTy', but allows the kinds of the types to differ,+-- and thus matches them as well.+tcMatchTyKi :: Type -> Type -> Maybe TCvSubst+tcMatchTyKi ty1 ty2 = tcMatchTyKis [ty1] [ty2]++-- | This is similar to 'tcMatchTy', but extends a substitution+tcMatchTyX :: TCvSubst -- ^ Substitution to extend+ -> Type -- ^ Template+ -> Type -- ^ Target+ -> Maybe TCvSubst+tcMatchTyX subst ty1 ty2 = tcMatchTysX subst [ty1] [ty2]++-- | Like 'tcMatchTy' but over a list of types.+tcMatchTys :: [Type] -- ^ Template+ -> [Type] -- ^ Target+ -> Maybe TCvSubst -- ^ One-shot; in principle the template+ -- variables could be free in the target+tcMatchTys tys1 tys2+ = tcMatchTysX (mkEmptyTCvSubst in_scope) tys1 tys2+ where+ in_scope = mkInScopeSet (tyCoVarsOfTypes tys1 `unionVarSet` tyCoVarsOfTypes tys2)++-- | Like 'tcMatchTyKi' but over a list of types.+tcMatchTyKis :: [Type] -- ^ Template+ -> [Type] -- ^ Target+ -> Maybe TCvSubst -- ^ One-shot substitution+tcMatchTyKis tys1 tys2+ = tcMatchTyKisX (mkEmptyTCvSubst in_scope) tys1 tys2+ where+ in_scope = mkInScopeSet (tyCoVarsOfTypes tys1 `unionVarSet` tyCoVarsOfTypes tys2)++-- | Like 'tcMatchTys', but extending a substitution+tcMatchTysX :: TCvSubst -- ^ Substitution to extend+ -> [Type] -- ^ Template+ -> [Type] -- ^ Target+ -> Maybe TCvSubst -- ^ One-shot substitution+tcMatchTysX subst tys1 tys2+ = tc_match_tys_x False subst tys1 tys2++-- | Like 'tcMatchTyKis', but extending a substitution+tcMatchTyKisX :: TCvSubst -- ^ Substitution to extend+ -> [Type] -- ^ Template+ -> [Type] -- ^ Target+ -> Maybe TCvSubst -- ^ One-shot substitution+tcMatchTyKisX subst tys1 tys2+ = tc_match_tys_x True subst tys1 tys2++-- | Worker for 'tcMatchTysX' and 'tcMatchTyKisX'+tc_match_tys_x :: Bool -- ^ match kinds?+ -> TCvSubst+ -> [Type]+ -> [Type]+ -> Maybe TCvSubst+tc_match_tys_x match_kis (TCvSubst in_scope tv_env cv_env) tys1 tys2+ = case tc_unify_tys (const BindMe)+ False -- Matching, not unifying+ False -- Not an injectivity check+ match_kis+ (mkRnEnv2 in_scope) tv_env cv_env tys1 tys2 of+ Unifiable (tv_env', cv_env')+ -> Just $ TCvSubst in_scope tv_env' cv_env'+ _ -> Nothing++-- | This one is called from the expression matcher,+-- which already has a MatchEnv in hand+ruleMatchTyKiX+ :: TyCoVarSet -- ^ template variables+ -> RnEnv2+ -> TvSubstEnv -- ^ type substitution to extend+ -> Type -- ^ Template+ -> Type -- ^ Target+ -> Maybe TvSubstEnv+ruleMatchTyKiX tmpl_tvs rn_env tenv tmpl target+-- See Note [Kind coercions in Unify]+ = case tc_unify_tys (matchBindFun tmpl_tvs) False False+ True -- <-- this means to match the kinds+ rn_env tenv emptyCvSubstEnv [tmpl] [target] of+ Unifiable (tenv', _) -> Just tenv'+ _ -> Nothing++matchBindFun :: TyCoVarSet -> TyVar -> BindFlag+matchBindFun tvs tv = if tv `elemVarSet` tvs then BindMe else Skolem+++{- *********************************************************************+* *+ Rough matching+* *+********************************************************************* -}++-- See Note [Rough match] field in InstEnv++roughMatchTcs :: [Type] -> [Maybe Name]+roughMatchTcs tys = map rough tys+ where+ rough ty+ | Just (ty', _) <- splitCastTy_maybe ty = rough ty'+ | Just (tc,_) <- splitTyConApp_maybe ty = Just (tyConName tc)+ | otherwise = Nothing++instanceCantMatch :: [Maybe Name] -> [Maybe Name] -> Bool+-- (instanceCantMatch tcs1 tcs2) returns True if tcs1 cannot+-- possibly be instantiated to actual, nor vice versa;+-- False is non-committal+instanceCantMatch (mt : ts) (ma : as) = itemCantMatch mt ma || instanceCantMatch ts as+instanceCantMatch _ _ = False -- Safe++itemCantMatch :: Maybe Name -> Maybe Name -> Bool+itemCantMatch (Just t) (Just a) = t /= a+itemCantMatch _ _ = False+++{-+************************************************************************+* *+ GADTs+* *+************************************************************************++Note [Pruning dead case alternatives]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider data T a where+ T1 :: T Int+ T2 :: T a++ newtype X = MkX Int+ newtype Y = MkY Char++ type family F a+ type instance F Bool = Int++Now consider case x of { T1 -> e1; T2 -> e2 }++The question before the house is this: if I know something about the type+of x, can I prune away the T1 alternative?++Suppose x::T Char. It's impossible to construct a (T Char) using T1,+ Answer = YES we can prune the T1 branch (clearly)++Suppose x::T (F a), where 'a' is in scope. Then 'a' might be instantiated+to 'Bool', in which case x::T Int, so+ ANSWER = NO (clearly)++We see here that we want precisely the apartness check implemented within+tcUnifyTysFG. So that's what we do! Two types cannot match if they are surely+apart. Note that since we are simply dropping dead code, a conservative test+suffices.+-}++-- | Given a list of pairs of types, are any two members of a pair surely+-- apart, even after arbitrary type function evaluation and substitution?+typesCantMatch :: [(Type,Type)] -> Bool+-- See Note [Pruning dead case alternatives]+typesCantMatch prs = any (uncurry cant_match) prs+ where+ cant_match :: Type -> Type -> Bool+ cant_match t1 t2 = case tcUnifyTysFG (const BindMe) [t1] [t2] of+ SurelyApart -> True+ _ -> False++{-+************************************************************************+* *+ Unification+* *+************************************************************************++Note [Fine-grained unification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Do the types (x, x) and ([y], y) unify? The answer is seemingly "no" --+no substitution to finite types makes these match. But, a substitution to+*infinite* types can unify these two types: [x |-> [[[...]]], y |-> [[[...]]] ].+Why do we care? Consider these two type family instances:++type instance F x x = Int+type instance F [y] y = Bool++If we also have++type instance Looper = [Looper]++then the instances potentially overlap. The solution is to use unification+over infinite terms. This is possible (see [1] for lots of gory details), but+a full algorithm is a little more power than we need. Instead, we make a+conservative approximation and just omit the occurs check.++[1]: http://research.microsoft.com/en-us/um/people/simonpj/papers/ext-f/axioms-extended.pdf++tcUnifyTys considers an occurs-check problem as the same as general unification+failure.++tcUnifyTysFG ("fine-grained") returns one of three results: success, occurs-check+failure ("MaybeApart"), or general failure ("SurelyApart").++See also Trac #8162.++It's worth noting that unification in the presence of infinite types is not+complete. This means that, sometimes, a closed type family does not reduce+when it should. See test case indexed-types/should_fail/Overlap15 for an+example.++Note [The substitution in MaybeApart]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The constructor MaybeApart carries data with it, typically a TvSubstEnv. Why?+Because consider unifying these:++(a, a, Int) ~ (b, [b], Bool)++If we go left-to-right, we start with [a |-> b]. Then, on the middle terms, we+apply the subst we have so far and discover that we need [b |-> [b]]. Because+this fails the occurs check, we say that the types are MaybeApart (see above+Note [Fine-grained unification]). But, we can't stop there! Because if we+continue, we discover that Int is SurelyApart from Bool, and therefore the+types are apart. This has practical consequences for the ability for closed+type family applications to reduce. See test case+indexed-types/should_compile/Overlap14.++Note [Unifying with skolems]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+If we discover that two types unify if and only if a skolem variable is+substituted, we can't properly unify the types. But, that skolem variable+may later be instantiated with a unifyable type. So, we return maybeApart+in these cases.++Note [Lists of different lengths are MaybeApart]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+It is unusual to call tcUnifyTys or tcUnifyTysFG with lists of different+lengths. The place where we know this can happen is from compatibleBranches in+FamInstEnv, when checking data family instances. Data family instances may be+eta-reduced; see Note [Eta reduction for data family axioms] in TcInstDcls.++We wish to say that++ D :: * -> * -> *+ axDF1 :: D Int ~ DFInst1+ axDF2 :: D Int Bool ~ DFInst2++overlap. If we conclude that lists of different lengths are SurelyApart, then+it will look like these do *not* overlap, causing disaster. See Trac #9371.++In usages of tcUnifyTys outside of family instances, we always use tcUnifyTys,+which can't tell the difference between MaybeApart and SurelyApart, so those+usages won't notice this design choice.+-}++-- | Simple unification of two types; all type variables are bindable+-- Precondition: the kinds are already equal+tcUnifyTy :: Type -> Type -- All tyvars are bindable+ -> Maybe TCvSubst+ -- A regular one-shot (idempotent) substitution+tcUnifyTy t1 t2 = tcUnifyTys (const BindMe) [t1] [t2]++-- | Like 'tcUnifyTy', but also unifies the kinds+tcUnifyTyKi :: Type -> Type -> Maybe TCvSubst+tcUnifyTyKi t1 t2 = tcUnifyTyKis (const BindMe) [t1] [t2]++-- | Unify two types, treating type family applications as possibly unifying+-- with anything and looking through injective type family applications.+-- Precondition: kinds are the same+tcUnifyTyWithTFs :: Bool -- ^ True <=> do two-way unification;+ -- False <=> do one-way matching.+ -- See end of sec 5.2 from the paper+ -> Type -> Type -> Maybe TCvSubst+-- This algorithm is an implementation of the "Algorithm U" presented in+-- the paper "Injective type families for Haskell", Figures 2 and 3.+-- The code is incorporated with the standard unifier for convenience, but+-- its operation should match the specification in the paper.+tcUnifyTyWithTFs twoWay t1 t2+ = case tc_unify_tys (const BindMe) twoWay True False+ rn_env emptyTvSubstEnv emptyCvSubstEnv+ [t1] [t2] of+ Unifiable (subst, _) -> Just $ niFixTCvSubst subst+ MaybeApart (subst, _) -> Just $ niFixTCvSubst subst+ -- we want to *succeed* in questionable cases. This is a+ -- pre-unification algorithm.+ SurelyApart -> Nothing+ where+ rn_env = mkRnEnv2 $ mkInScopeSet $ tyCoVarsOfTypes [t1, t2]++-----------------+tcUnifyTys :: (TyCoVar -> BindFlag)+ -> [Type] -> [Type]+ -> Maybe TCvSubst+ -- ^ A regular one-shot (idempotent) substitution+ -- that unifies the erased types. See comments+ -- for 'tcUnifyTysFG'++-- The two types may have common type variables, and indeed do so in the+-- second call to tcUnifyTys in FunDeps.checkClsFD+tcUnifyTys bind_fn tys1 tys2+ = case tcUnifyTysFG bind_fn tys1 tys2 of+ Unifiable result -> Just result+ _ -> Nothing++-- | Like 'tcUnifyTys' but also unifies the kinds+tcUnifyTyKis :: (TyCoVar -> BindFlag)+ -> [Type] -> [Type]+ -> Maybe TCvSubst+tcUnifyTyKis bind_fn tys1 tys2+ = case tcUnifyTyKisFG bind_fn tys1 tys2 of+ Unifiable result -> Just result+ _ -> Nothing++-- This type does double-duty. It is used in the UM (unifier monad) and to+-- return the final result. See Note [Fine-grained unification]+type UnifyResult = UnifyResultM TCvSubst+data UnifyResultM a = Unifiable a -- the subst that unifies the types+ | MaybeApart a -- the subst has as much as we know+ -- it must be part of an most general unifier+ -- See Note [The substitution in MaybeApart]+ | SurelyApart+ deriving Functor++instance Applicative UnifyResultM where+ pure = Unifiable+ (<*>) = ap++instance Monad UnifyResultM where++ SurelyApart >>= _ = SurelyApart+ MaybeApart x >>= f = case f x of+ Unifiable y -> MaybeApart y+ other -> other+ Unifiable x >>= f = f x++instance Alternative UnifyResultM where+ empty = SurelyApart++ a@(Unifiable {}) <|> _ = a+ _ <|> b@(Unifiable {}) = b+ a@(MaybeApart {}) <|> _ = a+ _ <|> b@(MaybeApart {}) = b+ SurelyApart <|> SurelyApart = SurelyApart++instance MonadPlus UnifyResultM++-- | @tcUnifyTysFG bind_tv tys1 tys2@ attepts to find a substitution @s@ (whose+-- domain elements all respond 'BindMe' to @bind_tv@) such that+-- @s(tys1)@ and that of @s(tys2)@ are equal, as witnessed by the returned+-- Coercions. This version requires that the kinds of the types are the same,+-- if you unify left-to-right.+tcUnifyTysFG :: (TyVar -> BindFlag)+ -> [Type] -> [Type]+ -> UnifyResult+tcUnifyTysFG bind_fn tys1 tys2+ = tc_unify_tys_fg False bind_fn tys1 tys2++tcUnifyTyKisFG :: (TyVar -> BindFlag)+ -> [Type] -> [Type]+ -> UnifyResult+tcUnifyTyKisFG bind_fn tys1 tys2+ = tc_unify_tys_fg True bind_fn tys1 tys2++tc_unify_tys_fg :: Bool+ -> (TyVar -> BindFlag)+ -> [Type] -> [Type]+ -> UnifyResult+tc_unify_tys_fg match_kis bind_fn tys1 tys2+ = do { (env, _) <- tc_unify_tys bind_fn True False match_kis env+ emptyTvSubstEnv emptyCvSubstEnv+ tys1 tys2+ ; return $ niFixTCvSubst env }+ where+ vars = tyCoVarsOfTypes tys1 `unionVarSet` tyCoVarsOfTypes tys2+ env = mkRnEnv2 $ mkInScopeSet vars++-- | This function is actually the one to call the unifier -- a little+-- too general for outside clients, though.+tc_unify_tys :: (TyVar -> BindFlag)+ -> AmIUnifying -- ^ True <=> unify; False <=> match+ -> Bool -- ^ True <=> doing an injectivity check+ -> Bool -- ^ True <=> treat the kinds as well+ -> RnEnv2+ -> TvSubstEnv -- ^ substitution to extend+ -> CvSubstEnv+ -> [Type] -> [Type]+ -> UnifyResultM (TvSubstEnv, CvSubstEnv)+tc_unify_tys bind_fn unif inj_check match_kis rn_env tv_env cv_env tys1 tys2+ = initUM tv_env cv_env $+ do { when match_kis $+ unify_tys env kis1 kis2+ ; unify_tys env tys1 tys2+ ; (,) <$> getTvSubstEnv <*> getCvSubstEnv }+ where+ env = UMEnv { um_bind_fun = bind_fn+ , um_unif = unif+ , um_inj_tf = inj_check+ , um_rn_env = rn_env }++ kis1 = map typeKind tys1+ kis2 = map typeKind tys2++instance Outputable a => Outputable (UnifyResultM a) where+ ppr SurelyApart = text "SurelyApart"+ ppr (Unifiable x) = text "Unifiable" <+> ppr x+ ppr (MaybeApart x) = text "MaybeApart" <+> ppr x++{-+************************************************************************+* *+ Non-idempotent substitution+* *+************************************************************************++Note [Non-idempotent substitution]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+During unification we use a TvSubstEnv/CvSubstEnv pair that is+ (a) non-idempotent+ (b) loop-free; ie repeatedly applying it yields a fixed point++Note [Finding the substitution fixpoint]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Finding the fixpoint of a non-idempotent substitution arising from a+unification is harder than it looks, because of kinds. Consider+ T k (H k (f:k)) ~ T * (g:*)+If we unify, we get the substitution+ [ k -> *+ , g -> H k (f:k) ]+To make it idempotent we don't want to get just+ [ k -> *+ , g -> H * (f:k) ]+We also want to substitute inside f's kind, to get+ [ k -> *+ , g -> H k (f:*) ]+If we don't do this, we may apply the substitution to something,+and get an ill-formed type, i.e. one where typeKind will fail.+This happened, for example, in Trac #9106.++This is the reason for extending env with [f:k -> f:*], in the+definition of env' in niFixTvSubst+-}++niFixTCvSubst :: TvSubstEnv -> TCvSubst+-- Find the idempotent fixed point of the non-idempotent substitution+-- See Note [Finding the substitution fixpoint]+-- ToDo: use laziness instead of iteration?+niFixTCvSubst tenv = f tenv+ where+ f tenv+ | not_fixpoint = f (mapVarEnv (substTy subst') tenv)+ | otherwise = subst+ where+ not_fixpoint = anyVarSet in_domain range_tvs+ in_domain tv = tv `elemVarEnv` tenv++ range_tvs = nonDetFoldUFM (unionVarSet . tyCoVarsOfType) emptyVarSet tenv+ -- It's OK to use nonDetFoldUFM here because we+ -- forget the order immediately by creating a set+ subst = mkTvSubst (mkInScopeSet range_tvs) tenv++ -- env' extends env by replacing any free type with+ -- that same tyvar with a substituted kind+ -- See note [Finding the substitution fixpoint]+ tenv' = extendVarEnvList tenv [ (rtv, mkTyVarTy $+ setTyVarKind rtv $+ substTy subst $+ tyVarKind rtv)+ | rtv <- nonDetEltsUniqSet range_tvs+ -- It's OK to use nonDetEltsUniqSet here+ -- because we forget the order+ -- immediatedly by putting it in VarEnv+ , not (in_domain rtv) ]+ subst' = mkTvSubst (mkInScopeSet range_tvs) tenv'++niSubstTvSet :: TvSubstEnv -> TyCoVarSet -> TyCoVarSet+-- Apply the non-idempotent substitution to a set of type variables,+-- remembering that the substitution isn't necessarily idempotent+-- This is used in the occurs check, before extending the substitution+niSubstTvSet tsubst tvs+ = nonDetFoldUniqSet (unionVarSet . get) emptyVarSet tvs+ -- It's OK to nonDetFoldUFM here because we immediately forget the+ -- ordering by creating a set.+ where+ get tv+ | Just ty <- lookupVarEnv tsubst tv+ = niSubstTvSet tsubst (tyCoVarsOfType ty)++ | otherwise+ = unitVarSet tv++{-+************************************************************************+* *+ unify_ty: the main workhorse+* *+************************************************************************++Note [Specification of unification]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+The pure unifier, unify_ty, defined in this module, tries to work out+a substitution to make two types say True to eqType. NB: eqType is+itself not purely syntactic; it accounts for CastTys;+see Note [Non-trivial definitional equality] in TyCoRep++Unlike the "impure unifiers" in the typechecker (the eager unifier in+TcUnify, and the constraint solver itself in TcCanonical), the pure+unifier It does /not/ work up to ~.++The algorithm implemented here is rather delicate, and we depend on it+to uphold certain properties. This is a summary of these required+properties. Any reference to "flattening" refers to the flattening+algorithm in FamInstEnv (See Note [Flattening] in FamInstEnv), not+the flattening algorithm in the solver.++Notation:+ θ,φ substitutions+ ξ type-function-free types+ τ,σ other types+ τ♭ type τ, flattened++ ≡ eqType++(U1) Soundness.+ If (unify τ₁ τ₂) = Unifiable θ, then θ(τ₁) ≡ θ(τ₂).+ θ is a most general unifier for τ₁ and τ₂.++(U2) Completeness.+ If (unify ξ₁ ξ₂) = SurelyApart,+ then there exists no substitution θ such that θ(ξ₁) ≡ θ(ξ₂).++These two properties are stated as Property 11 in the "Closed Type Families"+paper (POPL'14). Below, this paper is called [CTF].++(U3) Apartness under substitution.+ If (unify ξ τ♭) = SurelyApart, then (unify ξ θ(τ)♭) = SurelyApart,+ for any θ. (Property 12 from [CTF])++(U4) Apart types do not unify.+ If (unify ξ τ♭) = SurelyApart, then there exists no θ+ such that θ(ξ) = θ(τ). (Property 13 from [CTF])++THEOREM. Completeness w.r.t ~+ If (unify τ₁♭ τ₂♭) = SurelyApart,+ then there exists no proof that (τ₁ ~ τ₂).++PROOF. See appendix of [CTF].+++The unification algorithm is used for type family injectivity, as described+in the "Injective Type Families" paper (Haskell'15), called [ITF]. When run+in this mode, it has the following properties.++(I1) If (unify σ τ) = SurelyApart, then σ and τ are not unifiable, even+ after arbitrary type family reductions. Note that σ and τ are+ not flattened here.++(I2) If (unify σ τ) = MaybeApart θ, and if some+ φ exists such that φ(σ) ~ φ(τ), then φ extends θ.+++Furthermore, the RULES matching algorithm requires this property,+but only when using this algorithm for matching:++(M1) If (match σ τ) succeeds with θ, then all matchable tyvars+ in σ are bound in θ.++ Property M1 means that we must extend the substitution with,+ say (a ↦ a) when appropriate during matching.+ See also Note [Self-substitution when matching].++(M2) Completeness of matching.+ If θ(σ) = τ, then (match σ τ) = Unifiable φ,+ where θ is an extension of φ.++Sadly, property M2 and I2 conflict. Consider++type family F1 a b where+ F1 Int Bool = Char+ F1 Double String = Char++Consider now two matching problems:++P1. match (F1 a Bool) (F1 Int Bool)+P2. match (F1 a Bool) (F1 Double String)++In case P1, we must find (a ↦ Int) to satisfy M2.+In case P2, we must /not/ find (a ↦ Double), in order to satisfy I2. (Note+that the correct mapping for I2 is (a ↦ Int). There is no way to discover+this, but we musn't map a to anything else!)++We thus must parameterize the algorithm over whether it's being used+for an injectivity check (refrain from looking at non-injective arguments+to type families) or not (do indeed look at those arguments). This is+implemented by the uf_inj_tf field of UmEnv.++(It's all a question of whether or not to include equation (7) from Fig. 2+of [ITF].)++This extra parameter is a bit fiddly, perhaps, but seemingly less so than+having two separate, almost-identical algorithms.++Note [Self-substitution when matching]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+What should happen when we're *matching* (not unifying) a1 with a1? We+should get a substitution [a1 |-> a1]. A successful match should map all+the template variables (except ones that disappear when expanding synonyms).+But when unifying, we don't want to do this, because we'll then fall into+a loop.++This arrangement affects the code in three places:+ - If we're matching a refined template variable, don't recur. Instead, just+ check for equality. That is, if we know [a |-> Maybe a] and are matching+ (a ~? Maybe Int), we want to just fail.++ - Skip the occurs check when matching. This comes up in two places, because+ matching against variables is handled separately from matching against+ full-on types.++Note that this arrangement was provoked by a real failure, where the same+unique ended up in the template as in the target. (It was a rule firing when+compiling Data.List.NonEmpty.)++Note [Matching coercion variables]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Consider this:++ type family F a++ data G a where+ MkG :: F a ~ Bool => G a++ type family Foo (x :: G a) :: F a+ type instance Foo MkG = False++We would like that to be accepted. For that to work, we need to introduce+a coercion variable on the left an then use it on the right. Accordingly,+at use sites of Foo, we need to be able to use matching to figure out the+value for the coercion. (See the desugared version:++ axFoo :: [a :: *, c :: F a ~ Bool]. Foo (MkG c) = False |> (sym c)++) We never want this action to happen during *unification* though, when+all bets are off.++Note [Kind coercions in Unify]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+We wish to match/unify while ignoring casts. But, we can't just ignore+them completely, or we'll end up with ill-kinded substitutions. For example,+say we're matching `a` with `ty |> co`. If we just drop the cast, we'll+return [a |-> ty], but `a` and `ty` might have different kinds. We can't+just match/unify their kinds, either, because this might gratuitously+fail. After all, `co` is the witness that the kinds are the same -- they+may look nothing alike.++So, we pass a kind coercion to the match/unify worker. This coercion witnesses+the equality between the substed kind of the left-hand type and the substed+kind of the right-hand type. Note that we do not unify kinds at the leaves+(as we did previously). We thus have++INVARIANT: In the call+ unify_ty ty1 ty2 kco+it must be that subst(kco) :: subst(kind(ty1)) ~N subst(kind(ty2)), where+`subst` is the ambient substitution in the UM monad.++To get this coercion, we first have to match/unify+the kinds before looking at the types. Happily, we need look only one level+up, as all kinds are guaranteed to have kind *.++When we're working with type applications (either TyConApp or AppTy) we+need to worry about establishing INVARIANT, as the kinds of the function+& arguments aren't (necessarily) included in the kind of the result.+When unifying two TyConApps, this is easy, because the two TyCons are+the same. Their kinds are thus the same. As long as we unify left-to-right,+we'll be sure to unify types' kinds before the types themselves. (For example,+think about Proxy :: forall k. k -> *. Unifying the first args matches up+the kinds of the second args.)++For AppTy, we must unify the kinds of the functions, but once these are+unified, we can continue unifying arguments without worrying further about+kinds.++The interface to this module includes both "...Ty" functions and+"...TyKi" functions. The former assume that INVARIANT is already+established, either because the kinds are the same or because the+list of types being passed in are the well-typed arguments to some+type constructor (see two paragraphs above). The latter take a separate+pre-pass over the kinds to establish INVARIANT. Sometimes, it's important+not to take the second pass, as it caused #12442.++We thought, at one point, that this was all unnecessary: why should+casts be in types in the first place? But they are sometimes. In+dependent/should_compile/KindEqualities2, we see, for example the+constraint Num (Int |> (blah ; sym blah)). We naturally want to find+a dictionary for that constraint, which requires dealing with+coercions in this manner.+-}++-------------- unify_ty: the main workhorse -----------++type AmIUnifying = Bool -- True <=> Unifying+ -- False <=> Matching++unify_ty :: UMEnv+ -> Type -> Type -- Types to be unified and a co+ -> Coercion -- A coercion between their kinds+ -- See Note [Kind coercions in Unify]+ -> UM ()+-- See Note [Specification of unification]+-- Respects newtypes, PredTypes++unify_ty env ty1 ty2 kco+ -- TODO: More commentary needed here+ | Just ty1' <- tcView ty1 = unify_ty env ty1' ty2 kco+ | Just ty2' <- tcView ty2 = unify_ty env ty1 ty2' kco+ | CastTy ty1' co <- ty1 = unify_ty env ty1' ty2 (co `mkTransCo` kco)+ | CastTy ty2' co <- ty2 = unify_ty env ty1 ty2' (kco `mkTransCo` mkSymCo co)++unify_ty env (TyVarTy tv1) ty2 kco+ = uVar env tv1 ty2 kco+unify_ty env ty1 (TyVarTy tv2) kco+ | um_unif env -- If unifying, can swap args+ = uVar (umSwapRn env) tv2 ty1 (mkSymCo kco)++unify_ty env ty1 ty2 _kco+ | Just (tc1, tys1) <- mb_tc_app1+ , Just (tc2, tys2) <- mb_tc_app2+ , tc1 == tc2 || (tcIsStarKind ty1 && tcIsStarKind ty2)+ = if isInjectiveTyCon tc1 Nominal+ then unify_tys env tys1 tys2+ else do { let inj | isTypeFamilyTyCon tc1+ = case familyTyConInjectivityInfo tc1 of+ NotInjective -> repeat False+ Injective bs -> bs+ | otherwise+ = repeat False++ (inj_tys1, noninj_tys1) = partitionByList inj tys1+ (inj_tys2, noninj_tys2) = partitionByList inj tys2++ ; unify_tys env inj_tys1 inj_tys2+ ; unless (um_inj_tf env) $ -- See (end of) Note [Specification of unification]+ don'tBeSoSure $ unify_tys env noninj_tys1 noninj_tys2 }++ | Just (tc1, _) <- mb_tc_app1+ , not (isGenerativeTyCon tc1 Nominal)+ -- E.g. unify_ty (F ty1) b = MaybeApart+ -- because the (F ty1) behaves like a variable+ -- NB: if unifying, we have already dealt+ -- with the 'ty2 = variable' case+ = maybeApart++ | Just (tc2, _) <- mb_tc_app2+ , not (isGenerativeTyCon tc2 Nominal)+ , um_unif env+ -- E.g. unify_ty [a] (F ty2) = MaybeApart, when unifying (only)+ -- because the (F ty2) behaves like a variable+ -- NB: we have already dealt with the 'ty1 = variable' case+ = maybeApart++ where+ mb_tc_app1 = tcSplitTyConApp_maybe ty1+ mb_tc_app2 = tcSplitTyConApp_maybe ty2++ -- Applications need a bit of care!+ -- They can match FunTy and TyConApp, so use splitAppTy_maybe+ -- NB: we've already dealt with type variables,+ -- so if one type is an App the other one jolly well better be too+unify_ty env (AppTy ty1a ty1b) ty2 _kco+ | Just (ty2a, ty2b) <- tcRepSplitAppTy_maybe ty2+ = unify_ty_app env ty1a [ty1b] ty2a [ty2b]++unify_ty env ty1 (AppTy ty2a ty2b) _kco+ | Just (ty1a, ty1b) <- tcRepSplitAppTy_maybe ty1+ = unify_ty_app env ty1a [ty1b] ty2a [ty2b]++unify_ty _ (LitTy x) (LitTy y) _kco | x == y = return ()++unify_ty env (ForAllTy (TvBndr tv1 _) ty1) (ForAllTy (TvBndr tv2 _) ty2) kco+ = do { unify_ty env (tyVarKind tv1) (tyVarKind tv2) (mkNomReflCo liftedTypeKind)+ ; let env' = umRnBndr2 env tv1 tv2+ ; unify_ty env' ty1 ty2 kco }++-- See Note [Matching coercion variables]+unify_ty env (CoercionTy co1) (CoercionTy co2) kco+ = do { c_subst <- getCvSubstEnv+ ; case co1 of+ CoVarCo cv+ | not (um_unif env)+ , not (cv `elemVarEnv` c_subst)+ , BindMe <- tvBindFlagL env cv+ -> do { checkRnEnvRCo env co2+ ; let (co_l, co_r) = decomposeFunCo kco+ -- cv :: t1 ~ t2+ -- co2 :: s1 ~ s2+ -- co_l :: t1 ~ s1+ -- co_r :: t2 ~ s2+ ; extendCvEnv cv (co_l `mkTransCo`+ co2 `mkTransCo`+ mkSymCo co_r) }+ _ -> return () }++unify_ty _ _ _ _ = surelyApart++unify_ty_app :: UMEnv -> Type -> [Type] -> Type -> [Type] -> UM ()+unify_ty_app env ty1 ty1args ty2 ty2args+ | Just (ty1', ty1a) <- repSplitAppTy_maybe ty1+ , Just (ty2', ty2a) <- repSplitAppTy_maybe ty2+ = unify_ty_app env ty1' (ty1a : ty1args) ty2' (ty2a : ty2args)++ | otherwise+ = do { let ki1 = typeKind ty1+ ki2 = typeKind ty2+ -- See Note [Kind coercions in Unify]+ ; unify_ty env ki1 ki2 (mkNomReflCo liftedTypeKind)+ ; unify_ty env ty1 ty2 (mkNomReflCo ki1)+ ; unify_tys env ty1args ty2args }++unify_tys :: UMEnv -> [Type] -> [Type] -> UM ()+unify_tys env orig_xs orig_ys+ = go orig_xs orig_ys+ where+ go [] [] = return ()+ go (x:xs) (y:ys)+ -- See Note [Kind coercions in Unify]+ = do { unify_ty env x y (mkNomReflCo $ typeKind x)+ ; go xs ys }+ go _ _ = maybeApart -- See Note [Lists of different lengths are MaybeApart]++---------------------------------+uVar :: UMEnv+ -> TyVar -- Variable to be unified+ -> Type -- with this Type+ -> Coercion -- :: kind tv ~N kind ty+ -> UM ()++uVar env tv1 ty kco+ = do { -- Check to see whether tv1 is refined by the substitution+ subst <- getTvSubstEnv+ ; case (lookupVarEnv subst tv1) of+ Just ty' | um_unif env -- Unifying, so+ -> unify_ty env ty' ty kco -- call back into unify+ | otherwise+ -> -- Matching, we don't want to just recur here.+ -- this is because the range of the subst is the target+ -- type, not the template type. So, just check for+ -- normal type equality.+ guard ((ty' `mkCastTy` kco) `eqType` ty)+ Nothing -> uUnrefined env tv1 ty ty kco } -- No, continue++uUnrefined :: UMEnv+ -> TyVar -- variable to be unified+ -> Type -- with this Type+ -> Type -- (version w/ expanded synonyms)+ -> Coercion -- :: kind tv ~N kind ty+ -> UM ()++-- We know that tv1 isn't refined++uUnrefined env tv1 ty2 ty2' kco+ | Just ty2'' <- coreView ty2'+ = uUnrefined env tv1 ty2 ty2'' kco -- Unwrap synonyms+ -- This is essential, in case we have+ -- type Foo a = a+ -- and then unify a ~ Foo a++ | TyVarTy tv2 <- ty2'+ = do { let tv1' = umRnOccL env tv1+ tv2' = umRnOccR env tv2+ -- See Note [Self-substitution when matching]+ ; when (tv1' /= tv2' || not (um_unif env)) $ do+ { subst <- getTvSubstEnv+ -- Check to see whether tv2 is refined+ ; case lookupVarEnv subst tv2 of+ { Just ty' | um_unif env -> uUnrefined env tv1 ty' ty' kco+ ; _ -> do+ { -- So both are unrefined++ -- And then bind one or the other,+ -- depending on which is bindable+ ; let b1 = tvBindFlagL env tv1+ b2 = tvBindFlagR env tv2+ ty1 = mkTyVarTy tv1+ ; case (b1, b2) of+ (BindMe, _) -> do { checkRnEnvR env ty2 -- make sure ty2 is not a local+ ; extendTvEnv tv1 (ty2 `mkCastTy` mkSymCo kco) }+ (_, BindMe) | um_unif env+ -> do { checkRnEnvL env ty1 -- ditto for ty1+ ; extendTvEnv tv2 (ty1 `mkCastTy` kco) }++ _ | tv1' == tv2' -> return ()+ -- How could this happen? If we're only matching and if+ -- we're comparing forall-bound variables.++ _ -> maybeApart -- See Note [Unification with skolems]+ }}}}++uUnrefined env tv1 ty2 ty2' kco -- ty2 is not a type variable+ = do { occurs <- elemNiSubstSet tv1 (tyCoVarsOfType ty2')+ ; if um_unif env && occurs -- See Note [Self-substitution when matching]+ then maybeApart -- Occurs check, see Note [Fine-grained unification]+ else do bindTv env tv1 (ty2 `mkCastTy` mkSymCo kco) }+ -- Bind tyvar to the synonym if poss++elemNiSubstSet :: TyVar -> TyCoVarSet -> UM Bool+elemNiSubstSet v set+ = do { tsubst <- getTvSubstEnv+ ; return $ v `elemVarSet` niSubstTvSet tsubst set }++bindTv :: UMEnv -> TyVar -> Type -> UM ()+bindTv env tv ty -- ty is not a variable+ = do { checkRnEnvR env ty -- make sure ty mentions no local variables+ ; case tvBindFlagL env tv of+ Skolem -> maybeApart -- See Note [Unification with skolems]+ BindMe -> extendTvEnv tv ty+ }++{-+%************************************************************************+%* *+ Binding decisions+* *+************************************************************************+-}++data BindFlag+ = BindMe -- A regular type variable++ | Skolem -- This type variable is a skolem constant+ -- Don't bind it; it only matches itself+ deriving Eq++{-+************************************************************************+* *+ Unification monad+* *+************************************************************************+-}++data UMEnv = UMEnv { um_bind_fun :: TyVar -> BindFlag+ -- User-supplied BindFlag function+ , um_unif :: AmIUnifying+ , um_inj_tf :: Bool -- Checking for injectivity?+ -- See (end of) Note [Specification of unification]+ , um_rn_env :: RnEnv2 }++data UMState = UMState+ { um_tv_env :: TvSubstEnv+ , um_cv_env :: CvSubstEnv }++newtype UM a = UM { unUM :: UMState -> UnifyResultM (UMState, a) }++instance Functor UM where+ fmap = liftM++instance Applicative UM where+ pure a = UM (\s -> pure (s, a))+ (<*>) = ap++instance Monad UM where+ fail _ = UM (\_ -> SurelyApart) -- failed pattern match+ m >>= k = UM (\state ->+ do { (state', v) <- unUM m state+ ; unUM (k v) state' })++-- need this instance because of a use of 'guard' above+instance Alternative UM where+ empty = UM (\_ -> Control.Applicative.empty)+ m1 <|> m2 = UM (\state ->+ unUM m1 state <|>+ unUM m2 state)++instance MonadPlus UM++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail UM where+ fail _ = UM (\_ -> SurelyApart) -- failed pattern match+#endif++initUM :: TvSubstEnv -- subst to extend+ -> CvSubstEnv+ -> UM a -> UnifyResultM a+initUM subst_env cv_subst_env um+ = case unUM um state of+ Unifiable (_, subst) -> Unifiable subst+ MaybeApart (_, subst) -> MaybeApart subst+ SurelyApart -> SurelyApart+ where+ state = UMState { um_tv_env = subst_env+ , um_cv_env = cv_subst_env }++tvBindFlagL :: UMEnv -> TyVar -> BindFlag+tvBindFlagL env tv+ | inRnEnvL (um_rn_env env) tv = Skolem+ | otherwise = um_bind_fun env tv++tvBindFlagR :: UMEnv -> TyVar -> BindFlag+tvBindFlagR env tv+ | inRnEnvR (um_rn_env env) tv = Skolem+ | otherwise = um_bind_fun env tv++getTvSubstEnv :: UM TvSubstEnv+getTvSubstEnv = UM $ \state -> Unifiable (state, um_tv_env state)++getCvSubstEnv :: UM CvSubstEnv+getCvSubstEnv = UM $ \state -> Unifiable (state, um_cv_env state)++extendTvEnv :: TyVar -> Type -> UM ()+extendTvEnv tv ty = UM $ \state ->+ Unifiable (state { um_tv_env = extendVarEnv (um_tv_env state) tv ty }, ())++extendCvEnv :: CoVar -> Coercion -> UM ()+extendCvEnv cv co = UM $ \state ->+ Unifiable (state { um_cv_env = extendVarEnv (um_cv_env state) cv co }, ())++umRnBndr2 :: UMEnv -> TyCoVar -> TyCoVar -> UMEnv+umRnBndr2 env v1 v2+ = env { um_rn_env = rnBndr2 (um_rn_env env) v1 v2 }++checkRnEnv :: (RnEnv2 -> VarEnv Var) -> UMEnv -> VarSet -> UM ()+checkRnEnv get_set env varset = UM $ \ state ->+ let env_vars = get_set (um_rn_env env) in+ if isEmptyVarEnv env_vars || (getUniqSet varset `disjointVarEnv` env_vars)+ -- NB: That isEmptyVarSet is a critical optimization; it+ -- means we don't have to calculate the free vars of+ -- the type, often saving quite a bit of allocation.+ then Unifiable (state, ())+ else MaybeApart (state, ())++-- | Converts any SurelyApart to a MaybeApart+don'tBeSoSure :: UM () -> UM ()+don'tBeSoSure um = UM $ \ state ->+ case unUM um state of+ SurelyApart -> MaybeApart (state, ())+ other -> other++checkRnEnvR :: UMEnv -> Type -> UM ()+checkRnEnvR env ty = checkRnEnv rnEnvR env (tyCoVarsOfType ty)++checkRnEnvL :: UMEnv -> Type -> UM ()+checkRnEnvL env ty = checkRnEnv rnEnvL env (tyCoVarsOfType ty)++checkRnEnvRCo :: UMEnv -> Coercion -> UM ()+checkRnEnvRCo env co = checkRnEnv rnEnvR env (tyCoVarsOfCo co)++umRnOccL :: UMEnv -> TyVar -> TyVar+umRnOccL env v = rnOccL (um_rn_env env) v++umRnOccR :: UMEnv -> TyVar -> TyVar+umRnOccR env v = rnOccR (um_rn_env env) v++umSwapRn :: UMEnv -> UMEnv+umSwapRn env = env { um_rn_env = rnSwap (um_rn_env env) }++maybeApart :: UM ()+maybeApart = UM (\state -> MaybeApart (state, ()))++surelyApart :: UM a+surelyApart = UM (\_ -> SurelyApart)++{-+%************************************************************************+%* *+ Matching a (lifted) type against a coercion+%* *+%************************************************************************++This section defines essentially an inverse to liftCoSubst. It is defined+here to avoid a dependency from Coercion on this module.++-}++data MatchEnv = ME { me_tmpls :: TyVarSet+ , me_env :: RnEnv2 }++-- | 'liftCoMatch' is sort of inverse to 'liftCoSubst'. In particular, if+-- @liftCoMatch vars ty co == Just s@, then @listCoSubst s ty == co@,+-- where @==@ there means that the result of 'liftCoSubst' has the same+-- type as the original co; but may be different under the hood.+-- That is, it matches a type against a coercion of the same+-- "shape", and returns a lifting substitution which could have been+-- used to produce the given coercion from the given type.+-- Note that this function is incomplete -- it might return Nothing+-- when there does indeed exist a possible lifting context.+--+-- This function is incomplete in that it doesn't respect the equality+-- in `eqType`. That is, it's possible that this will succeed for t1 and+-- fail for t2, even when t1 `eqType` t2. That's because it depends on+-- there being a very similar structure between the type and the coercion.+-- This incompleteness shouldn't be all that surprising, especially because+-- it depends on the structure of the coercion, which is a silly thing to do.+--+-- The lifting context produced doesn't have to be exacting in the roles+-- of the mappings. This is because any use of the lifting context will+-- also require a desired role. Thus, this algorithm prefers mapping to+-- nominal coercions where it can do so.+liftCoMatch :: TyCoVarSet -> Type -> Coercion -> Maybe LiftingContext+liftCoMatch tmpls ty co+ = do { cenv1 <- ty_co_match menv emptyVarEnv ki ki_co ki_ki_co ki_ki_co+ ; cenv2 <- ty_co_match menv cenv1 ty co+ (mkNomReflCo co_lkind) (mkNomReflCo co_rkind)+ ; return (LC (mkEmptyTCvSubst in_scope) cenv2) }+ where+ menv = ME { me_tmpls = tmpls, me_env = mkRnEnv2 in_scope }+ in_scope = mkInScopeSet (tmpls `unionVarSet` tyCoVarsOfCo co)+ -- Like tcMatchTy, assume all the interesting variables+ -- in ty are in tmpls++ ki = typeKind ty+ ki_co = promoteCoercion co+ ki_ki_co = mkNomReflCo liftedTypeKind++ Pair co_lkind co_rkind = coercionKind ki_co++-- | 'ty_co_match' does all the actual work for 'liftCoMatch'.+ty_co_match :: MatchEnv -- ^ ambient helpful info+ -> LiftCoEnv -- ^ incoming subst+ -> Type -- ^ ty, type to match+ -> Coercion -- ^ co, coercion to match against+ -> Coercion -- ^ :: kind of L type of substed ty ~N L kind of co+ -> Coercion -- ^ :: kind of R type of substed ty ~N R kind of co+ -> Maybe LiftCoEnv+ty_co_match menv subst ty co lkco rkco+ | Just ty' <- coreView ty = ty_co_match menv subst ty' co lkco rkco++ -- handle Refl case:+ | tyCoVarsOfType ty `isNotInDomainOf` subst+ , Just (ty', _) <- isReflCo_maybe co+ , ty `eqType` ty'+ = Just subst++ where+ isNotInDomainOf :: VarSet -> VarEnv a -> Bool+ isNotInDomainOf set env+ = noneSet (\v -> elemVarEnv v env) set++ noneSet :: (Var -> Bool) -> VarSet -> Bool+ noneSet f = allVarSet (not . f)++ty_co_match menv subst ty co lkco rkco+ | CastTy ty' co' <- ty+ = ty_co_match menv subst ty' co (co' `mkTransCo` lkco) (co' `mkTransCo` rkco)++ | CoherenceCo co1 co2 <- co+ = ty_co_match menv subst ty co1 (lkco `mkTransCo` mkSymCo co2) rkco++ | SymCo co' <- co+ = swapLiftCoEnv <$> ty_co_match menv (swapLiftCoEnv subst) ty co' rkco lkco++ -- Match a type variable against a non-refl coercion+ty_co_match menv subst (TyVarTy tv1) co lkco rkco+ | Just co1' <- lookupVarEnv subst tv1' -- tv1' is already bound to co1+ = if eqCoercionX (nukeRnEnvL rn_env) co1' co+ then Just subst+ else Nothing -- no match since tv1 matches two different coercions++ | tv1' `elemVarSet` me_tmpls menv -- tv1' is a template var+ = if any (inRnEnvR rn_env) (tyCoVarsOfCoList co)+ then Nothing -- occurs check failed+ else Just $ extendVarEnv subst tv1' $+ castCoercionKind co (mkSymCo lkco) (mkSymCo rkco)++ | otherwise+ = Nothing++ where+ rn_env = me_env menv+ tv1' = rnOccL rn_env tv1++ -- just look through SubCo's. We don't really care about roles here.+ty_co_match menv subst ty (SubCo co) lkco rkco+ = ty_co_match menv subst ty co lkco rkco++ty_co_match menv subst (AppTy ty1a ty1b) co _lkco _rkco+ | Just (co2, arg2) <- splitAppCo_maybe co -- c.f. Unify.match on AppTy+ = ty_co_match_app menv subst ty1a [ty1b] co2 [arg2]+ty_co_match menv subst ty1 (AppCo co2 arg2) _lkco _rkco+ | Just (ty1a, ty1b) <- repSplitAppTy_maybe ty1+ -- yes, the one from Type, not TcType; this is for coercion optimization+ = ty_co_match_app menv subst ty1a [ty1b] co2 [arg2]++ty_co_match menv subst (TyConApp tc1 tys) (TyConAppCo _ tc2 cos) _lkco _rkco+ = ty_co_match_tc menv subst tc1 tys tc2 cos+ty_co_match menv subst (FunTy ty1 ty2) co _lkco _rkco+ -- Despite the fact that (->) is polymorphic in four type variables (two+ -- runtime rep and two types), we shouldn't need to explicitly unify the+ -- runtime reps here; unifying the types themselves should be sufficient.+ -- See Note [Representation of function types].+ | Just (tc, [_,_,co1,co2]) <- splitTyConAppCo_maybe co+ , tc == funTyCon+ = let Pair lkcos rkcos = traverse (fmap mkNomReflCo . coercionKind) [co1,co2]+ in ty_co_match_args menv subst [ty1, ty2] [co1, co2] lkcos rkcos++ty_co_match menv subst (ForAllTy (TvBndr tv1 _) ty1)+ (ForAllCo tv2 kind_co2 co2)+ lkco rkco+ = do { subst1 <- ty_co_match menv subst (tyVarKind tv1) kind_co2+ ki_ki_co ki_ki_co+ ; let rn_env0 = me_env menv+ rn_env1 = rnBndr2 rn_env0 tv1 tv2+ menv' = menv { me_env = rn_env1 }+ ; ty_co_match menv' subst1 ty1 co2 lkco rkco }+ where+ ki_ki_co = mkNomReflCo liftedTypeKind++ty_co_match _ subst (CoercionTy {}) _ _ _+ = Just subst -- don't inspect coercions++ty_co_match menv subst ty co lkco rkco+ | Just co' <- pushRefl co = ty_co_match menv subst ty co' lkco rkco+ | otherwise = Nothing++ty_co_match_tc :: MatchEnv -> LiftCoEnv+ -> TyCon -> [Type]+ -> TyCon -> [Coercion]+ -> Maybe LiftCoEnv+ty_co_match_tc menv subst tc1 tys1 tc2 cos2+ = do { guard (tc1 == tc2)+ ; ty_co_match_args menv subst tys1 cos2 lkcos rkcos }+ where+ Pair lkcos rkcos+ = traverse (fmap mkNomReflCo . coercionKind) cos2++ty_co_match_app :: MatchEnv -> LiftCoEnv+ -> Type -> [Type] -> Coercion -> [Coercion]+ -> Maybe LiftCoEnv+ty_co_match_app menv subst ty1 ty1args co2 co2args+ | Just (ty1', ty1a) <- repSplitAppTy_maybe ty1+ , Just (co2', co2a) <- splitAppCo_maybe co2+ = ty_co_match_app menv subst ty1' (ty1a : ty1args) co2' (co2a : co2args)++ | otherwise+ = do { subst1 <- ty_co_match menv subst ki1 ki2 ki_ki_co ki_ki_co+ ; let Pair lkco rkco = mkNomReflCo <$> coercionKind ki2+ ; subst2 <- ty_co_match menv subst1 ty1 co2 lkco rkco+ ; let Pair lkcos rkcos = traverse (fmap mkNomReflCo . coercionKind) co2args+ ; ty_co_match_args menv subst2 ty1args co2args lkcos rkcos }+ where+ ki1 = typeKind ty1+ ki2 = promoteCoercion co2+ ki_ki_co = mkNomReflCo liftedTypeKind++ty_co_match_args :: MatchEnv -> LiftCoEnv -> [Type]+ -> [Coercion] -> [Coercion] -> [Coercion]+ -> Maybe LiftCoEnv+ty_co_match_args _ subst [] [] _ _ = Just subst+ty_co_match_args menv subst (ty:tys) (arg:args) (lkco:lkcos) (rkco:rkcos)+ = do { subst' <- ty_co_match menv subst ty arg lkco rkco+ ; ty_co_match_args menv subst' tys args lkcos rkcos }+ty_co_match_args _ _ _ _ _ _ = Nothing++pushRefl :: Coercion -> Maybe Coercion+pushRefl (Refl Nominal (AppTy ty1 ty2))+ = Just (AppCo (Refl Nominal ty1) (mkNomReflCo ty2))+pushRefl (Refl r (FunTy ty1 ty2))+ | Just rep1 <- getRuntimeRep_maybe ty1+ , Just rep2 <- getRuntimeRep_maybe ty2+ = Just (TyConAppCo r funTyCon [ mkReflCo r rep1, mkReflCo r rep2+ , mkReflCo r ty1, mkReflCo r ty2 ])+pushRefl (Refl r (TyConApp tc tys))+ = Just (TyConAppCo r tc (zipWith mkReflCo (tyConRolesX r tc) tys))+pushRefl (Refl r (ForAllTy (TvBndr tv _) ty))+ = Just (mkHomoForAllCos_NoRefl [tv] (Refl r ty))+ -- NB: NoRefl variant. Otherwise, we get a loop!+pushRefl (Refl r (CastTy ty co)) = Just (castCoercionKind (Refl r ty) co co)+pushRefl _ = Nothing
+ utils/Bag.hs view
@@ -0,0 +1,332 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+++Bag: an unordered collection with duplicates+-}++{-# LANGUAGE ScopedTypeVariables, CPP #-}++module Bag (+ Bag, -- abstract type++ emptyBag, unitBag, unionBags, unionManyBags,+ mapBag,+ elemBag, lengthBag,+ filterBag, partitionBag, partitionBagWith,+ concatBag, catBagMaybes, foldBag, foldrBag, foldlBag,+ isEmptyBag, isSingletonBag, consBag, snocBag, anyBag, allBag,+ listToBag, bagToList, mapAccumBagL,+ concatMapBag, mapMaybeBag,+ foldrBagM, foldlBagM, mapBagM, mapBagM_,+ flatMapBagM, flatMapBagPairM,+ mapAndUnzipBagM, mapAccumBagLM,+ anyBagM, filterBagM+ ) where++import Outputable+import Util++import MonadUtils+import Control.Monad+import Data.Data+import Data.Maybe( mapMaybe )+import Data.List ( partition, mapAccumL )+import qualified Data.Foldable as Foldable++infixr 3 `consBag`+infixl 3 `snocBag`++data Bag a+ = EmptyBag+ | UnitBag a+ | TwoBags (Bag a) (Bag a) -- INVARIANT: neither branch is empty+ | ListBag [a] -- INVARIANT: the list is non-empty++emptyBag :: Bag a+emptyBag = EmptyBag++unitBag :: a -> Bag a+unitBag = UnitBag++lengthBag :: Bag a -> Int+lengthBag EmptyBag = 0+lengthBag (UnitBag {}) = 1+lengthBag (TwoBags b1 b2) = lengthBag b1 + lengthBag b2+lengthBag (ListBag xs) = length xs++elemBag :: Eq a => a -> Bag a -> Bool+elemBag _ EmptyBag = False+elemBag x (UnitBag y) = x == y+elemBag x (TwoBags b1 b2) = x `elemBag` b1 || x `elemBag` b2+elemBag x (ListBag ys) = any (x ==) ys++unionManyBags :: [Bag a] -> Bag a+unionManyBags xs = foldr unionBags EmptyBag xs++-- This one is a bit stricter! The bag will get completely evaluated.++unionBags :: Bag a -> Bag a -> Bag a+unionBags EmptyBag b = b+unionBags b EmptyBag = b+unionBags b1 b2 = TwoBags b1 b2++consBag :: a -> Bag a -> Bag a+snocBag :: Bag a -> a -> Bag a++consBag elt bag = (unitBag elt) `unionBags` bag+snocBag bag elt = bag `unionBags` (unitBag elt)++isEmptyBag :: Bag a -> Bool+isEmptyBag EmptyBag = True+isEmptyBag _ = False -- NB invariants++isSingletonBag :: Bag a -> Bool+isSingletonBag EmptyBag = False+isSingletonBag (UnitBag _) = True+isSingletonBag (TwoBags _ _) = False -- Neither is empty+isSingletonBag (ListBag xs) = isSingleton xs++filterBag :: (a -> Bool) -> Bag a -> Bag a+filterBag _ EmptyBag = EmptyBag+filterBag pred b@(UnitBag val) = if pred val then b else EmptyBag+filterBag pred (TwoBags b1 b2) = sat1 `unionBags` sat2+ where sat1 = filterBag pred b1+ sat2 = filterBag pred b2+filterBag pred (ListBag vs) = listToBag (filter pred vs)++filterBagM :: Monad m => (a -> m Bool) -> Bag a -> m (Bag a)+filterBagM _ EmptyBag = return EmptyBag+filterBagM pred b@(UnitBag val) = do+ flag <- pred val+ if flag then return b+ else return EmptyBag+filterBagM pred (TwoBags b1 b2) = do+ sat1 <- filterBagM pred b1+ sat2 <- filterBagM pred b2+ return (sat1 `unionBags` sat2)+filterBagM pred (ListBag vs) = do+ sat <- filterM pred vs+ return (listToBag sat)++allBag :: (a -> Bool) -> Bag a -> Bool+allBag _ EmptyBag = True+allBag p (UnitBag v) = p v+allBag p (TwoBags b1 b2) = allBag p b1 && allBag p b2+allBag p (ListBag xs) = all p xs++anyBag :: (a -> Bool) -> Bag a -> Bool+anyBag _ EmptyBag = False+anyBag p (UnitBag v) = p v+anyBag p (TwoBags b1 b2) = anyBag p b1 || anyBag p b2+anyBag p (ListBag xs) = any p xs++anyBagM :: Monad m => (a -> m Bool) -> Bag a -> m Bool+anyBagM _ EmptyBag = return False+anyBagM p (UnitBag v) = p v+anyBagM p (TwoBags b1 b2) = do flag <- anyBagM p b1+ if flag then return True+ else anyBagM p b2+anyBagM p (ListBag xs) = anyM p xs++concatBag :: Bag (Bag a) -> Bag a+concatBag bss = foldrBag add emptyBag bss+ where+ add bs rs = bs `unionBags` rs++catBagMaybes :: Bag (Maybe a) -> Bag a+catBagMaybes bs = foldrBag add emptyBag bs+ where+ add Nothing rs = rs+ add (Just x) rs = x `consBag` rs++partitionBag :: (a -> Bool) -> Bag a -> (Bag a {- Satisfy predictate -},+ Bag a {- Don't -})+partitionBag _ EmptyBag = (EmptyBag, EmptyBag)+partitionBag pred b@(UnitBag val)+ = if pred val then (b, EmptyBag) else (EmptyBag, b)+partitionBag pred (TwoBags b1 b2)+ = (sat1 `unionBags` sat2, fail1 `unionBags` fail2)+ where (sat1, fail1) = partitionBag pred b1+ (sat2, fail2) = partitionBag pred b2+partitionBag pred (ListBag vs) = (listToBag sats, listToBag fails)+ where (sats, fails) = partition pred vs+++partitionBagWith :: (a -> Either b c) -> Bag a+ -> (Bag b {- Left -},+ Bag c {- Right -})+partitionBagWith _ EmptyBag = (EmptyBag, EmptyBag)+partitionBagWith pred (UnitBag val)+ = case pred val of+ Left a -> (UnitBag a, EmptyBag)+ Right b -> (EmptyBag, UnitBag b)+partitionBagWith pred (TwoBags b1 b2)+ = (sat1 `unionBags` sat2, fail1 `unionBags` fail2)+ where (sat1, fail1) = partitionBagWith pred b1+ (sat2, fail2) = partitionBagWith pred b2+partitionBagWith pred (ListBag vs) = (listToBag sats, listToBag fails)+ where (sats, fails) = partitionWith pred vs++foldBag :: (r -> r -> r) -- Replace TwoBags with this; should be associative+ -> (a -> r) -- Replace UnitBag with this+ -> r -- Replace EmptyBag with this+ -> Bag a+ -> r++{- Standard definition+foldBag t u e EmptyBag = e+foldBag t u e (UnitBag x) = u x+foldBag t u e (TwoBags b1 b2) = (foldBag t u e b1) `t` (foldBag t u e b2)+foldBag t u e (ListBag xs) = foldr (t.u) e xs+-}++-- More tail-recursive definition, exploiting associativity of "t"+foldBag _ _ e EmptyBag = e+foldBag t u e (UnitBag x) = u x `t` e+foldBag t u e (TwoBags b1 b2) = foldBag t u (foldBag t u e b2) b1+foldBag t u e (ListBag xs) = foldr (t.u) e xs++foldrBag :: (a -> r -> r) -> r+ -> Bag a+ -> r++foldrBag _ z EmptyBag = z+foldrBag k z (UnitBag x) = k x z+foldrBag k z (TwoBags b1 b2) = foldrBag k (foldrBag k z b2) b1+foldrBag k z (ListBag xs) = foldr k z xs++foldlBag :: (r -> a -> r) -> r+ -> Bag a+ -> r++foldlBag _ z EmptyBag = z+foldlBag k z (UnitBag x) = k z x+foldlBag k z (TwoBags b1 b2) = foldlBag k (foldlBag k z b1) b2+foldlBag k z (ListBag xs) = foldl k z xs++foldrBagM :: (Monad m) => (a -> b -> m b) -> b -> Bag a -> m b+foldrBagM _ z EmptyBag = return z+foldrBagM k z (UnitBag x) = k x z+foldrBagM k z (TwoBags b1 b2) = do { z' <- foldrBagM k z b2; foldrBagM k z' b1 }+foldrBagM k z (ListBag xs) = foldrM k z xs++foldlBagM :: (Monad m) => (b -> a -> m b) -> b -> Bag a -> m b+foldlBagM _ z EmptyBag = return z+foldlBagM k z (UnitBag x) = k z x+foldlBagM k z (TwoBags b1 b2) = do { z' <- foldlBagM k z b1; foldlBagM k z' b2 }+foldlBagM k z (ListBag xs) = foldlM k z xs++mapBag :: (a -> b) -> Bag a -> Bag b+mapBag _ EmptyBag = EmptyBag+mapBag f (UnitBag x) = UnitBag (f x)+mapBag f (TwoBags b1 b2) = TwoBags (mapBag f b1) (mapBag f b2)+mapBag f (ListBag xs) = ListBag (map f xs)++concatMapBag :: (a -> Bag b) -> Bag a -> Bag b+concatMapBag _ EmptyBag = EmptyBag+concatMapBag f (UnitBag x) = f x+concatMapBag f (TwoBags b1 b2) = unionBags (concatMapBag f b1) (concatMapBag f b2)+concatMapBag f (ListBag xs) = foldr (unionBags . f) emptyBag xs++mapMaybeBag :: (a -> Maybe b) -> Bag a -> Bag b+mapMaybeBag _ EmptyBag = EmptyBag+mapMaybeBag f (UnitBag x) = case f x of+ Nothing -> EmptyBag+ Just y -> UnitBag y+mapMaybeBag f (TwoBags b1 b2) = unionBags (mapMaybeBag f b1) (mapMaybeBag f b2)+mapMaybeBag f (ListBag xs) = ListBag (mapMaybe f xs)++mapBagM :: Monad m => (a -> m b) -> Bag a -> m (Bag b)+mapBagM _ EmptyBag = return EmptyBag+mapBagM f (UnitBag x) = do r <- f x+ return (UnitBag r)+mapBagM f (TwoBags b1 b2) = do r1 <- mapBagM f b1+ r2 <- mapBagM f b2+ return (TwoBags r1 r2)+mapBagM f (ListBag xs) = do rs <- mapM f xs+ return (ListBag rs)++mapBagM_ :: Monad m => (a -> m b) -> Bag a -> m ()+mapBagM_ _ EmptyBag = return ()+mapBagM_ f (UnitBag x) = f x >> return ()+mapBagM_ f (TwoBags b1 b2) = mapBagM_ f b1 >> mapBagM_ f b2+mapBagM_ f (ListBag xs) = mapM_ f xs++flatMapBagM :: Monad m => (a -> m (Bag b)) -> Bag a -> m (Bag b)+flatMapBagM _ EmptyBag = return EmptyBag+flatMapBagM f (UnitBag x) = f x+flatMapBagM f (TwoBags b1 b2) = do r1 <- flatMapBagM f b1+ r2 <- flatMapBagM f b2+ return (r1 `unionBags` r2)+flatMapBagM f (ListBag xs) = foldrM k EmptyBag xs+ where+ k x b2 = do { b1 <- f x; return (b1 `unionBags` b2) }++flatMapBagPairM :: Monad m => (a -> m (Bag b, Bag c)) -> Bag a -> m (Bag b, Bag c)+flatMapBagPairM _ EmptyBag = return (EmptyBag, EmptyBag)+flatMapBagPairM f (UnitBag x) = f x+flatMapBagPairM f (TwoBags b1 b2) = do (r1,s1) <- flatMapBagPairM f b1+ (r2,s2) <- flatMapBagPairM f b2+ return (r1 `unionBags` r2, s1 `unionBags` s2)+flatMapBagPairM f (ListBag xs) = foldrM k (EmptyBag, EmptyBag) xs+ where+ k x (r2,s2) = do { (r1,s1) <- f x+ ; return (r1 `unionBags` r2, s1 `unionBags` s2) }++mapAndUnzipBagM :: Monad m => (a -> m (b,c)) -> Bag a -> m (Bag b, Bag c)+mapAndUnzipBagM _ EmptyBag = return (EmptyBag, EmptyBag)+mapAndUnzipBagM f (UnitBag x) = do (r,s) <- f x+ return (UnitBag r, UnitBag s)+mapAndUnzipBagM f (TwoBags b1 b2) = do (r1,s1) <- mapAndUnzipBagM f b1+ (r2,s2) <- mapAndUnzipBagM f b2+ return (TwoBags r1 r2, TwoBags s1 s2)+mapAndUnzipBagM f (ListBag xs) = do ts <- mapM f xs+ let (rs,ss) = unzip ts+ return (ListBag rs, ListBag ss)++mapAccumBagL ::(acc -> x -> (acc, y)) -- ^ combining funcction+ -> acc -- ^ initial state+ -> Bag x -- ^ inputs+ -> (acc, Bag y) -- ^ final state, outputs+mapAccumBagL _ s EmptyBag = (s, EmptyBag)+mapAccumBagL f s (UnitBag x) = let (s1, x1) = f s x in (s1, UnitBag x1)+mapAccumBagL f s (TwoBags b1 b2) = let (s1, b1') = mapAccumBagL f s b1+ (s2, b2') = mapAccumBagL f s1 b2+ in (s2, TwoBags b1' b2')+mapAccumBagL f s (ListBag xs) = let (s', xs') = mapAccumL f s xs+ in (s', ListBag xs')++mapAccumBagLM :: Monad m+ => (acc -> x -> m (acc, y)) -- ^ combining funcction+ -> acc -- ^ initial state+ -> Bag x -- ^ inputs+ -> m (acc, Bag y) -- ^ final state, outputs+mapAccumBagLM _ s EmptyBag = return (s, EmptyBag)+mapAccumBagLM f s (UnitBag x) = do { (s1, x1) <- f s x; return (s1, UnitBag x1) }+mapAccumBagLM f s (TwoBags b1 b2) = do { (s1, b1') <- mapAccumBagLM f s b1+ ; (s2, b2') <- mapAccumBagLM f s1 b2+ ; return (s2, TwoBags b1' b2') }+mapAccumBagLM f s (ListBag xs) = do { (s', xs') <- mapAccumLM f s xs+ ; return (s', ListBag xs') }++listToBag :: [a] -> Bag a+listToBag [] = EmptyBag+listToBag vs = ListBag vs++bagToList :: Bag a -> [a]+bagToList b = foldrBag (:) [] b++instance (Outputable a) => Outputable (Bag a) where+ ppr bag = braces (pprWithCommas ppr (bagToList bag))++instance Data a => Data (Bag a) where+ gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly+ toConstr _ = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "Bag"+ dataCast1 x = gcast1 x++instance Foldable.Foldable Bag where+ foldr = foldrBag
+ utils/Binary.hs view
@@ -0,0 +1,1194 @@+{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE GADTs #-}++{-# OPTIONS_GHC -O -funbox-strict-fields #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected++--+-- (c) The University of Glasgow 2002-2006+--+-- Binary I/O library, with special tweaks for GHC+--+-- Based on the nhc98 Binary library, which is copyright+-- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.+-- Under the terms of the license for that software, we must tell you+-- where you can obtain the original version of the Binary library, namely+-- http://www.cs.york.ac.uk/fp/nhc98/++module Binary+ ( {-type-} Bin,+ {-class-} Binary(..),+ {-type-} BinHandle,+ SymbolTable, Dictionary,++ openBinMem,+-- closeBin,++ seekBin,+ seekBy,+ tellBin,+ castBin,+ isEOFBin,+ withBinBuffer,++ writeBinMem,+ readBinMem,++ putAt, getAt,++ -- * For writing instances+ putByte,+ getByte,++ -- * Lazy Binary I/O+ lazyGet,+ lazyPut,++ -- * User data+ UserData(..), getUserData, setUserData,+ newReadState, newWriteState,+ putDictionary, getDictionary, putFS,+ ) where++#include "HsVersions.h"++-- The *host* architecture version:+#include "MachDeps.h"++import {-# SOURCE #-} Name (Name)+import FastString+import Panic+import UniqFM+import FastMutInt+import Fingerprint+import BasicTypes+import SrcLoc++import Foreign+import Data.Array+import Data.ByteString (ByteString)+import qualified Data.ByteString.Internal as BS+import qualified Data.ByteString.Unsafe as BS+import Data.IORef+import Data.Char ( ord, chr )+import Data.Time+#if MIN_VERSION_base(4,10,0)+import Type.Reflection+import Type.Reflection.Unsafe+import Data.Kind (Type)+import GHC.Exts (RuntimeRep(..), VecCount(..), VecElem(..))+#else+import Data.Typeable+#endif+import Control.Monad ( when )+import System.IO as IO+import System.IO.Unsafe ( unsafeInterleaveIO )+import System.IO.Error ( mkIOError, eofErrorType )+import GHC.Real ( Ratio(..) )+import GHC.Serialized++type BinArray = ForeignPtr Word8++---------------------------------------------------------------+-- BinHandle+---------------------------------------------------------------++data BinHandle+ = BinMem { -- binary data stored in an unboxed array+ bh_usr :: UserData, -- sigh, need parameterized modules :-)+ _off_r :: !FastMutInt, -- the current offset+ _sz_r :: !FastMutInt, -- size of the array (cached)+ _arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))+ }+ -- XXX: should really store a "high water mark" for dumping out+ -- the binary data to a file.++getUserData :: BinHandle -> UserData+getUserData bh = bh_usr bh++setUserData :: BinHandle -> UserData -> BinHandle+setUserData bh us = bh { bh_usr = us }++-- | Get access to the underlying buffer.+--+-- It is quite important that no references to the 'ByteString' leak out of the+-- continuation lest terrible things happen.+withBinBuffer :: BinHandle -> (ByteString -> IO a) -> IO a+withBinBuffer (BinMem _ ix_r _ arr_r) action = do+ arr <- readIORef arr_r+ ix <- readFastMutInt ix_r+ withForeignPtr arr $ \ptr ->+ BS.unsafePackCStringLen (castPtr ptr, ix) >>= action+++---------------------------------------------------------------+-- Bin+---------------------------------------------------------------++newtype Bin a = BinPtr Int+ deriving (Eq, Ord, Show, Bounded)++castBin :: Bin a -> Bin b+castBin (BinPtr i) = BinPtr i++---------------------------------------------------------------+-- class Binary+---------------------------------------------------------------++class Binary a where+ put_ :: BinHandle -> a -> IO ()+ put :: BinHandle -> a -> IO (Bin a)+ get :: BinHandle -> IO a++ -- define one of put_, put. Use of put_ is recommended because it+ -- is more likely that tail-calls can kick in, and we rarely need the+ -- position return value.+ put_ bh a = do _ <- put bh a; return ()+ put bh a = do p <- tellBin bh; put_ bh a; return p++putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()+putAt bh p x = do seekBin bh p; put_ bh x; return ()++getAt :: Binary a => BinHandle -> Bin a -> IO a+getAt bh p = do seekBin bh p; get bh++openBinMem :: Int -> IO BinHandle+openBinMem size+ | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"+ | otherwise = do+ arr <- mallocForeignPtrBytes size+ arr_r <- newIORef arr+ ix_r <- newFastMutInt+ writeFastMutInt ix_r 0+ sz_r <- newFastMutInt+ writeFastMutInt sz_r size+ return (BinMem noUserData ix_r sz_r arr_r)++tellBin :: BinHandle -> IO (Bin a)+tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)++seekBin :: BinHandle -> Bin a -> IO ()+seekBin h@(BinMem _ ix_r sz_r _) (BinPtr p) = do+ sz <- readFastMutInt sz_r+ if (p >= sz)+ then do expandBin h p; writeFastMutInt ix_r p+ else writeFastMutInt ix_r p++seekBy :: BinHandle -> Int -> IO ()+seekBy h@(BinMem _ ix_r sz_r _) off = do+ sz <- readFastMutInt sz_r+ ix <- readFastMutInt ix_r+ let ix' = ix + off+ if (ix' >= sz)+ then do expandBin h ix'; writeFastMutInt ix_r ix'+ else writeFastMutInt ix_r ix'++isEOFBin :: BinHandle -> IO Bool+isEOFBin (BinMem _ ix_r sz_r _) = do+ ix <- readFastMutInt ix_r+ sz <- readFastMutInt sz_r+ return (ix >= sz)++writeBinMem :: BinHandle -> FilePath -> IO ()+writeBinMem (BinMem _ ix_r _ arr_r) fn = do+ h <- openBinaryFile fn WriteMode+ arr <- readIORef arr_r+ ix <- readFastMutInt ix_r+ withForeignPtr arr $ \p -> hPutBuf h p ix+ hClose h++readBinMem :: FilePath -> IO BinHandle+-- Return a BinHandle with a totally undefined State+readBinMem filename = do+ h <- openBinaryFile filename ReadMode+ filesize' <- hFileSize h+ let filesize = fromIntegral filesize'+ arr <- mallocForeignPtrBytes filesize+ count <- withForeignPtr arr $ \p -> hGetBuf h p filesize+ when (count /= filesize) $+ error ("Binary.readBinMem: only read " ++ show count ++ " bytes")+ hClose h+ arr_r <- newIORef arr+ ix_r <- newFastMutInt+ writeFastMutInt ix_r 0+ sz_r <- newFastMutInt+ writeFastMutInt sz_r filesize+ return (BinMem noUserData ix_r sz_r arr_r)++-- expand the size of the array to include a specified offset+expandBin :: BinHandle -> Int -> IO ()+expandBin (BinMem _ _ sz_r arr_r) off = do+ sz <- readFastMutInt sz_r+ let sz' = head (dropWhile (<= off) (iterate (* 2) sz))+ arr <- readIORef arr_r+ arr' <- mallocForeignPtrBytes sz'+ withForeignPtr arr $ \old ->+ withForeignPtr arr' $ \new ->+ copyBytes new old sz+ writeFastMutInt sz_r sz'+ writeIORef arr_r arr'++-- -----------------------------------------------------------------------------+-- Low-level reading/writing of bytes++putPrim :: BinHandle -> Int -> (Ptr Word8 -> IO ()) -> IO ()+putPrim h@(BinMem _ ix_r sz_r arr_r) size f = do+ ix <- readFastMutInt ix_r+ sz <- readFastMutInt sz_r+ when (ix + size > sz) $+ expandBin h (ix + size)+ arr <- readIORef arr_r+ withForeignPtr arr $ \op -> f (op `plusPtr` ix)+ writeFastMutInt ix_r (ix + size)++getPrim :: BinHandle -> Int -> (Ptr Word8 -> IO a) -> IO a+getPrim (BinMem _ ix_r sz_r arr_r) size f = do+ ix <- readFastMutInt ix_r+ sz <- readFastMutInt sz_r+ when (ix + size > sz) $+ ioError (mkIOError eofErrorType "Data.Binary.getPrim" Nothing Nothing)+ arr <- readIORef arr_r+ w <- withForeignPtr arr $ \op -> f (op `plusPtr` ix)+ writeFastMutInt ix_r (ix + size)+ return w++putWord8 :: BinHandle -> Word8 -> IO ()+putWord8 h w = putPrim h 1 (\op -> poke op w)++getWord8 :: BinHandle -> IO Word8+getWord8 h = getPrim h 1 peek++putWord16 :: BinHandle -> Word16 -> IO ()+putWord16 h w = putPrim h 2 (\op -> do+ pokeElemOff op 0 (fromIntegral (w `shiftR` 8))+ pokeElemOff op 1 (fromIntegral (w .&. 0xFF))+ )++getWord16 :: BinHandle -> IO Word16+getWord16 h = getPrim h 2 (\op -> do+ w0 <- fromIntegral <$> peekElemOff op 0+ w1 <- fromIntegral <$> peekElemOff op 1+ return $! w0 `shiftL` 8 .|. w1+ )++putWord32 :: BinHandle -> Word32 -> IO ()+putWord32 h w = putPrim h 4 (\op -> do+ pokeElemOff op 0 (fromIntegral (w `shiftR` 24))+ pokeElemOff op 1 (fromIntegral ((w `shiftR` 16) .&. 0xFF))+ pokeElemOff op 2 (fromIntegral ((w `shiftR` 8) .&. 0xFF))+ pokeElemOff op 3 (fromIntegral (w .&. 0xFF))+ )++getWord32 :: BinHandle -> IO Word32+getWord32 h = getPrim h 4 (\op -> do+ w0 <- fromIntegral <$> peekElemOff op 0+ w1 <- fromIntegral <$> peekElemOff op 1+ w2 <- fromIntegral <$> peekElemOff op 2+ w3 <- fromIntegral <$> peekElemOff op 3++ return $! (w0 `shiftL` 24) .|.+ (w1 `shiftL` 16) .|.+ (w2 `shiftL` 8) .|.+ w3+ )++putWord64 :: BinHandle -> Word64 -> IO ()+putWord64 h w = putPrim h 8 (\op -> do+ pokeElemOff op 0 (fromIntegral (w `shiftR` 56))+ pokeElemOff op 1 (fromIntegral ((w `shiftR` 48) .&. 0xFF))+ pokeElemOff op 2 (fromIntegral ((w `shiftR` 40) .&. 0xFF))+ pokeElemOff op 3 (fromIntegral ((w `shiftR` 32) .&. 0xFF))+ pokeElemOff op 4 (fromIntegral ((w `shiftR` 24) .&. 0xFF))+ pokeElemOff op 5 (fromIntegral ((w `shiftR` 16) .&. 0xFF))+ pokeElemOff op 6 (fromIntegral ((w `shiftR` 8) .&. 0xFF))+ pokeElemOff op 7 (fromIntegral (w .&. 0xFF))+ )++getWord64 :: BinHandle -> IO Word64+getWord64 h = getPrim h 8 (\op -> do+ w0 <- fromIntegral <$> peekElemOff op 0+ w1 <- fromIntegral <$> peekElemOff op 1+ w2 <- fromIntegral <$> peekElemOff op 2+ w3 <- fromIntegral <$> peekElemOff op 3+ w4 <- fromIntegral <$> peekElemOff op 4+ w5 <- fromIntegral <$> peekElemOff op 5+ w6 <- fromIntegral <$> peekElemOff op 6+ w7 <- fromIntegral <$> peekElemOff op 7++ return $! (w0 `shiftL` 56) .|.+ (w1 `shiftL` 48) .|.+ (w2 `shiftL` 40) .|.+ (w3 `shiftL` 32) .|.+ (w4 `shiftL` 24) .|.+ (w5 `shiftL` 16) .|.+ (w6 `shiftL` 8) .|.+ w7+ )++putByte :: BinHandle -> Word8 -> IO ()+putByte bh w = putWord8 bh w++getByte :: BinHandle -> IO Word8+getByte h = getWord8 h++-- -----------------------------------------------------------------------------+-- Primitve Word writes++instance Binary Word8 where+ put_ = putWord8+ get = getWord8++instance Binary Word16 where+ put_ h w = putWord16 h w+ get h = getWord16 h++instance Binary Word32 where+ put_ h w = putWord32 h w+ get h = getWord32 h++instance Binary Word64 where+ put_ h w = putWord64 h w+ get h = getWord64 h++-- -----------------------------------------------------------------------------+-- Primitve Int writes++instance Binary Int8 where+ put_ h w = put_ h (fromIntegral w :: Word8)+ get h = do w <- get h; return $! (fromIntegral (w::Word8))++instance Binary Int16 where+ put_ h w = put_ h (fromIntegral w :: Word16)+ get h = do w <- get h; return $! (fromIntegral (w::Word16))++instance Binary Int32 where+ put_ h w = put_ h (fromIntegral w :: Word32)+ get h = do w <- get h; return $! (fromIntegral (w::Word32))++instance Binary Int64 where+ put_ h w = put_ h (fromIntegral w :: Word64)+ get h = do w <- get h; return $! (fromIntegral (w::Word64))++-- -----------------------------------------------------------------------------+-- Instances for standard types++instance Binary () where+ put_ _ () = return ()+ get _ = return ()++instance Binary Bool where+ put_ bh b = putByte bh (fromIntegral (fromEnum b))+ get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))++instance Binary Char where+ put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)+ get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))++instance Binary Int where+ put_ bh i = put_ bh (fromIntegral i :: Int64)+ get bh = do+ x <- get bh+ return $! (fromIntegral (x :: Int64))++instance Binary a => Binary [a] where+ put_ bh l = do+ let len = length l+ if (len < 0xff)+ then putByte bh (fromIntegral len :: Word8)+ else do putByte bh 0xff; put_ bh (fromIntegral len :: Word32)+ mapM_ (put_ bh) l+ get bh = do+ b <- getByte bh+ len <- if b == 0xff+ then get bh+ else return (fromIntegral b :: Word32)+ let loop 0 = return []+ loop n = do a <- get bh; as <- loop (n-1); return (a:as)+ loop len++instance (Binary a, Binary b) => Binary (a,b) where+ put_ bh (a,b) = do put_ bh a; put_ bh b+ get bh = do a <- get bh+ b <- get bh+ return (a,b)++instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where+ put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c+ get bh = do a <- get bh+ b <- get bh+ c <- get bh+ return (a,b,c)++instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where+ put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d+ get bh = do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ return (a,b,c,d)++instance (Binary a, Binary b, Binary c, Binary d, Binary e) => Binary (a,b,c,d, e) where+ put_ bh (a,b,c,d, e) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e;+ get bh = do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ e <- get bh+ return (a,b,c,d,e)++instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f) => Binary (a,b,c,d, e, f) where+ put_ bh (a,b,c,d, e, f) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e; put_ bh f;+ get bh = do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ e <- get bh+ f <- get bh+ return (a,b,c,d,e,f)++instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f, Binary g) => Binary (a,b,c,d,e,f,g) where+ put_ bh (a,b,c,d,e,f,g) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e; put_ bh f; put_ bh g+ get bh = do a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ e <- get bh+ f <- get bh+ g <- get bh+ return (a,b,c,d,e,f,g)++instance Binary a => Binary (Maybe a) where+ put_ bh Nothing = putByte bh 0+ put_ bh (Just a) = do putByte bh 1; put_ bh a+ get bh = do h <- getWord8 bh+ case h of+ 0 -> return Nothing+ _ -> do x <- get bh; return (Just x)++instance (Binary a, Binary b) => Binary (Either a b) where+ put_ bh (Left a) = do putByte bh 0; put_ bh a+ put_ bh (Right b) = do putByte bh 1; put_ bh b+ get bh = do h <- getWord8 bh+ case h of+ 0 -> do a <- get bh ; return (Left a)+ _ -> do b <- get bh ; return (Right b)++instance Binary UTCTime where+ put_ bh u = do put_ bh (utctDay u)+ put_ bh (utctDayTime u)+ get bh = do day <- get bh+ dayTime <- get bh+ return $ UTCTime { utctDay = day, utctDayTime = dayTime }++instance Binary Day where+ put_ bh d = put_ bh (toModifiedJulianDay d)+ get bh = do i <- get bh+ return $ ModifiedJulianDay { toModifiedJulianDay = i }++instance Binary DiffTime where+ put_ bh dt = put_ bh (toRational dt)+ get bh = do r <- get bh+ return $ fromRational r++--to quote binary-0.3 on this code idea,+--+-- TODO This instance is not architecture portable. GMP stores numbers as+-- arrays of machine sized words, so the byte format is not portable across+-- architectures with different endianess and word size.+--+-- This makes it hard (impossible) to make an equivalent instance+-- with code that is compilable with non-GHC. Do we need any instance+-- Binary Integer, and if so, does it have to be blazing fast? Or can+-- we just change this instance to be portable like the rest of the+-- instances? (binary package has code to steal for that)+--+-- yes, we need Binary Integer and Binary Rational in basicTypes/Literal.hs++instance Binary Integer where+ put_ bh i+ | i >= lo32 && i <= hi32 = do+ putWord8 bh 0+ put_ bh (fromIntegral i :: Int32)+ | otherwise = do+ putWord8 bh 1+ put_ bh (show i)+ where+ lo32 = fromIntegral (minBound :: Int32)+ hi32 = fromIntegral (maxBound :: Int32)++ get bh = do+ int_kind <- getWord8 bh+ case int_kind of+ 0 -> fromIntegral <$> (get bh :: IO Int32)+ _ -> do str <- get bh+ case reads str of+ [(i, "")] -> return i+ _ -> fail ("Binary integer: got " ++ show str)++ {-+ -- This code is currently commented out.+ -- See https://ghc.haskell.org/trac/ghc/ticket/3379#comment:10 for+ -- discussion.++ put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)+ put_ bh (J# s# a#) = do+ putByte bh 1+ put_ bh (I# s#)+ let sz# = sizeofByteArray# a# -- in *bytes*+ put_ bh (I# sz#) -- in *bytes*+ putByteArray bh a# sz#++ get bh = do+ b <- getByte bh+ case b of+ 0 -> do (I# i#) <- get bh+ return (S# i#)+ _ -> do (I# s#) <- get bh+ sz <- get bh+ (BA a#) <- getByteArray bh sz+ return (J# s# a#)++putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()+putByteArray bh a s# = loop 0#+ where loop n#+ | n# ==# s# = return ()+ | otherwise = do+ putByte bh (indexByteArray a n#)+ loop (n# +# 1#)++getByteArray :: BinHandle -> Int -> IO ByteArray+getByteArray bh (I# sz) = do+ (MBA arr) <- newByteArray sz+ let loop n+ | n ==# sz = return ()+ | otherwise = do+ w <- getByte bh+ writeByteArray arr n w+ loop (n +# 1#)+ loop 0#+ freezeByteArray arr+ -}++{-+data ByteArray = BA ByteArray#+data MBA = MBA (MutableByteArray# RealWorld)++newByteArray :: Int# -> IO MBA+newByteArray sz = IO $ \s ->+ case newByteArray# sz s of { (# s, arr #) ->+ (# s, MBA arr #) }++freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray+freezeByteArray arr = IO $ \s ->+ case unsafeFreezeByteArray# arr s of { (# s, arr #) ->+ (# s, BA arr #) }++writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()+writeByteArray arr i (W8# w) = IO $ \s ->+ case writeWord8Array# arr i w s of { s ->+ (# s, () #) }++indexByteArray :: ByteArray# -> Int# -> Word8+indexByteArray a# n# = W8# (indexWord8Array# a# n#)++-}+instance (Binary a) => Binary (Ratio a) where+ put_ bh (a :% b) = do put_ bh a; put_ bh b+ get bh = do a <- get bh; b <- get bh; return (a :% b)++instance Binary (Bin a) where+ put_ bh (BinPtr i) = put_ bh (fromIntegral i :: Int32)+ get bh = do i <- get bh; return (BinPtr (fromIntegral (i :: Int32)))++-- -----------------------------------------------------------------------------+-- Instances for Data.Typeable stuff++#if MIN_VERSION_base(4,10,0)+instance Binary TyCon where+ put_ bh tc = do+ put_ bh (tyConPackage tc)+ put_ bh (tyConModule tc)+ put_ bh (tyConName tc)+ put_ bh (tyConKindArgs tc)+ put_ bh (tyConKindRep tc)+ get bh =+ mkTyCon <$> get bh <*> get bh <*> get bh <*> get bh <*> get bh+#else+instance Binary TyCon where+ put_ bh tc = do+ put_ bh (tyConPackage tc)+ put_ bh (tyConModule tc)+ put_ bh (tyConName tc)+ get bh =+ mkTyCon3 <$> get bh <*> get bh <*> get bh+#endif++#if MIN_VERSION_base(4,10,0)+instance Binary VecCount where+ put_ bh = putByte bh . fromIntegral . fromEnum+ get bh = toEnum . fromIntegral <$> getByte bh++instance Binary VecElem where+ put_ bh = putByte bh . fromIntegral . fromEnum+ get bh = toEnum . fromIntegral <$> getByte bh++instance Binary RuntimeRep where+ put_ bh (VecRep a b) = putByte bh 0 >> put_ bh a >> put_ bh b+ put_ bh (TupleRep reps) = putByte bh 1 >> put_ bh reps+ put_ bh (SumRep reps) = putByte bh 2 >> put_ bh reps+ put_ bh LiftedRep = putByte bh 3+ put_ bh UnliftedRep = putByte bh 4+ put_ bh IntRep = putByte bh 5+ put_ bh WordRep = putByte bh 6+ put_ bh Int64Rep = putByte bh 7+ put_ bh Word64Rep = putByte bh 8+ put_ bh AddrRep = putByte bh 9+ put_ bh FloatRep = putByte bh 10+ put_ bh DoubleRep = putByte bh 11++ get bh = do+ tag <- getByte bh+ case tag of+ 0 -> VecRep <$> get bh <*> get bh+ 1 -> TupleRep <$> get bh+ 2 -> SumRep <$> get bh+ 3 -> pure LiftedRep+ 4 -> pure UnliftedRep+ 5 -> pure IntRep+ 6 -> pure WordRep+ 7 -> pure Int64Rep+ 8 -> pure Word64Rep+ 9 -> pure AddrRep+ 10 -> pure FloatRep+ 11 -> pure DoubleRep+ _ -> fail "Binary.putRuntimeRep: invalid tag"++instance Binary KindRep where+ put_ bh (KindRepTyConApp tc k) = putByte bh 0 >> put_ bh tc >> put_ bh k+ put_ bh (KindRepVar bndr) = putByte bh 1 >> put_ bh bndr+ put_ bh (KindRepApp a b) = putByte bh 2 >> put_ bh a >> put_ bh b+ put_ bh (KindRepFun a b) = putByte bh 3 >> put_ bh a >> put_ bh b+ put_ bh (KindRepTYPE r) = putByte bh 4 >> put_ bh r+ put_ bh (KindRepTypeLit sort r) = putByte bh 5 >> put_ bh sort >> put_ bh r++ get bh = do+ tag <- getByte bh+ case tag of+ 0 -> KindRepTyConApp <$> get bh <*> get bh+ 1 -> KindRepVar <$> get bh+ 2 -> KindRepApp <$> get bh <*> get bh+ 3 -> KindRepFun <$> get bh <*> get bh+ 4 -> KindRepTYPE <$> get bh+ 5 -> KindRepTypeLit <$> get bh <*> get bh+ _ -> fail "Binary.putKindRep: invalid tag"++instance Binary TypeLitSort where+ put_ bh TypeLitSymbol = putByte bh 0+ put_ bh TypeLitNat = putByte bh 1+ get bh = do+ tag <- getByte bh+ case tag of+ 0 -> pure TypeLitSymbol+ 1 -> pure TypeLitNat+ _ -> fail "Binary.putTypeLitSort: invalid tag"++putTypeRep :: BinHandle -> TypeRep a -> IO ()+-- Special handling for TYPE, (->), and RuntimeRep due to recursive kind+-- relations.+-- See Note [Mutually recursive representations of primitive types]+putTypeRep bh rep+ | Just HRefl <- rep `eqTypeRep` (typeRep :: TypeRep Type)+ = put_ bh (0 :: Word8)+putTypeRep bh (Con' con ks) = do+ put_ bh (1 :: Word8)+ put_ bh con+ put_ bh ks+putTypeRep bh (App f x) = do+ put_ bh (2 :: Word8)+ putTypeRep bh f+ putTypeRep bh x+putTypeRep bh (Fun arg res) = do+ put_ bh (3 :: Word8)+ putTypeRep bh arg+ putTypeRep bh res+putTypeRep _ _ = fail "Binary.putTypeRep: Impossible"++getSomeTypeRep :: BinHandle -> IO SomeTypeRep+getSomeTypeRep bh = do+ tag <- get bh :: IO Word8+ case tag of+ 0 -> return $ SomeTypeRep (typeRep :: TypeRep Type)+ 1 -> do con <- get bh :: IO TyCon+ ks <- get bh :: IO [SomeTypeRep]+ return $ SomeTypeRep $ mkTrCon con ks++ 2 -> do SomeTypeRep f <- getSomeTypeRep bh+ SomeTypeRep x <- getSomeTypeRep bh+ case typeRepKind f of+ Fun arg res ->+ case arg `eqTypeRep` typeRepKind x of+ Just HRefl ->+ case typeRepKind res `eqTypeRep` (typeRep :: TypeRep Type) of+ Just HRefl -> return $ SomeTypeRep $ mkTrApp f x+ _ -> failure "Kind mismatch in type application" []+ _ -> failure "Kind mismatch in type application"+ [ " Found argument of kind: " ++ show (typeRepKind x)+ , " Where the constructor: " ++ show f+ , " Expects kind: " ++ show arg+ ]+ _ -> failure "Applied non-arrow"+ [ " Applied type: " ++ show f+ , " To argument: " ++ show x+ ]+ 3 -> do SomeTypeRep arg <- getSomeTypeRep bh+ SomeTypeRep res <- getSomeTypeRep bh+ case typeRepKind arg `eqTypeRep` (typeRep :: TypeRep Type) of+ Just HRefl ->+ case typeRepKind res `eqTypeRep` (typeRep :: TypeRep Type) of+ Just HRefl -> return $ SomeTypeRep $ Fun arg res+ Nothing -> failure "Kind mismatch" []+ _ -> failure "Kind mismatch" []+ _ -> failure "Invalid SomeTypeRep" []+ where+ failure description info =+ fail $ unlines $ [ "Binary.getSomeTypeRep: "++description ]+ ++ map (" "++) info++instance Typeable a => Binary (TypeRep (a :: k)) where+ put_ = putTypeRep+ get bh = do+ SomeTypeRep rep <- getSomeTypeRep bh+ case rep `eqTypeRep` expected of+ Just HRefl -> pure rep+ Nothing -> fail $ unlines+ [ "Binary: Type mismatch"+ , " Deserialized type: " ++ show rep+ , " Expected type: " ++ show expected+ ]+ where expected = typeRep :: TypeRep a++instance Binary SomeTypeRep where+ put_ bh (SomeTypeRep rep) = putTypeRep bh rep+ get = getSomeTypeRep+#else+instance Binary TypeRep where+ put_ bh type_rep = do+ let (ty_con, child_type_reps) = splitTyConApp type_rep+ put_ bh ty_con+ put_ bh child_type_reps+ get bh = do+ ty_con <- get bh+ child_type_reps <- get bh+ return (mkTyConApp ty_con child_type_reps)+#endif++-- -----------------------------------------------------------------------------+-- Lazy reading/writing++lazyPut :: Binary a => BinHandle -> a -> IO ()+lazyPut bh a = do+ -- output the obj with a ptr to skip over it:+ pre_a <- tellBin bh+ put_ bh pre_a -- save a slot for the ptr+ put_ bh a -- dump the object+ q <- tellBin bh -- q = ptr to after object+ putAt bh pre_a q -- fill in slot before a with ptr to q+ seekBin bh q -- finally carry on writing at q++lazyGet :: Binary a => BinHandle -> IO a+lazyGet bh = do+ p <- get bh -- a BinPtr+ p_a <- tellBin bh+ a <- unsafeInterleaveIO $ do+ -- NB: Use a fresh off_r variable in the child thread, for thread+ -- safety.+ off_r <- newFastMutInt+ getAt bh { _off_r = off_r } p_a+ seekBin bh p -- skip over the object for now+ return a++-- -----------------------------------------------------------------------------+-- UserData+-- -----------------------------------------------------------------------------++-- | Information we keep around during interface file+-- serialization/deserialization. Namely we keep the functions for serializing+-- and deserializing 'Name's and 'FastString's. We do this because we actually+-- use serialization in two distinct settings,+--+-- * When serializing interface files themselves+--+-- * When computing the fingerprint of an IfaceDecl (which we computing by+-- hashing its Binary serialization)+--+-- These two settings have different needs while serializing Names:+--+-- * Names in interface files are serialized via a symbol table (see Note+-- [Symbol table representation of names] in BinIface).+--+-- * During fingerprinting a binding Name is serialized as the OccName and a+-- non-binding Name is serialized as the fingerprint of the thing they+-- represent. See Note [Fingerprinting IfaceDecls] for further discussion.+--+data UserData =+ UserData {+ -- for *deserialising* only:+ ud_get_name :: BinHandle -> IO Name,+ ud_get_fs :: BinHandle -> IO FastString,++ -- for *serialising* only:+ ud_put_nonbinding_name :: BinHandle -> Name -> IO (),+ -- ^ serialize a non-binding 'Name' (e.g. a reference to another+ -- binding).+ ud_put_binding_name :: BinHandle -> Name -> IO (),+ -- ^ serialize a binding 'Name' (e.g. the name of an IfaceDecl)+ ud_put_fs :: BinHandle -> FastString -> IO ()+ }++newReadState :: (BinHandle -> IO Name) -- ^ how to deserialize 'Name's+ -> (BinHandle -> IO FastString)+ -> UserData+newReadState get_name get_fs+ = UserData { ud_get_name = get_name,+ ud_get_fs = get_fs,+ ud_put_nonbinding_name = undef "put_nonbinding_name",+ ud_put_binding_name = undef "put_binding_name",+ ud_put_fs = undef "put_fs"+ }++newWriteState :: (BinHandle -> Name -> IO ())+ -- ^ how to serialize non-binding 'Name's+ -> (BinHandle -> Name -> IO ())+ -- ^ how to serialize binding 'Name's+ -> (BinHandle -> FastString -> IO ())+ -> UserData+newWriteState put_nonbinding_name put_binding_name put_fs+ = UserData { ud_get_name = undef "get_name",+ ud_get_fs = undef "get_fs",+ ud_put_nonbinding_name = put_nonbinding_name,+ ud_put_binding_name = put_binding_name,+ ud_put_fs = put_fs+ }++noUserData :: a+noUserData = undef "UserData"++undef :: String -> a+undef s = panic ("Binary.UserData: no " ++ s)++---------------------------------------------------------+-- The Dictionary+---------------------------------------------------------++type Dictionary = Array Int FastString -- The dictionary+ -- Should be 0-indexed++putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()+putDictionary bh sz dict = do+ put_ bh sz+ mapM_ (putFS bh) (elems (array (0,sz-1) (nonDetEltsUFM dict)))+ -- It's OK to use nonDetEltsUFM here because the elements have indices+ -- that array uses to create order++getDictionary :: BinHandle -> IO Dictionary+getDictionary bh = do+ sz <- get bh+ elems <- sequence (take sz (repeat (getFS bh)))+ return (listArray (0,sz-1) elems)++---------------------------------------------------------+-- The Symbol Table+---------------------------------------------------------++-- On disk, the symbol table is an array of IfExtName, when+-- reading it in we turn it into a SymbolTable.++type SymbolTable = Array Int Name++---------------------------------------------------------+-- Reading and writing FastStrings+---------------------------------------------------------++putFS :: BinHandle -> FastString -> IO ()+putFS bh fs = putBS bh $ fastStringToByteString fs++getFS :: BinHandle -> IO FastString+getFS bh = do+ l <- get bh :: IO Int+ getPrim bh l (\src -> pure $! mkFastStringBytes src l )++putBS :: BinHandle -> ByteString -> IO ()+putBS bh bs =+ BS.unsafeUseAsCStringLen bs $ \(ptr, l) -> do+ put_ bh l+ putPrim bh l (\op -> BS.memcpy op (castPtr ptr) l)++getBS :: BinHandle -> IO ByteString+getBS bh = do+ l <- get bh :: IO Int+ BS.create l $ \dest -> do+ getPrim bh l (\src -> BS.memcpy dest src l)++instance Binary ByteString where+ put_ bh f = putBS bh f+ get bh = getBS bh++instance Binary FastString where+ put_ bh f =+ case getUserData bh of+ UserData { ud_put_fs = put_fs } -> put_fs bh f++ get bh =+ case getUserData bh of+ UserData { ud_get_fs = get_fs } -> get_fs bh++-- Here to avoid loop+instance Binary LeftOrRight where+ put_ bh CLeft = putByte bh 0+ put_ bh CRight = putByte bh 1++ get bh = do { h <- getByte bh+ ; case h of+ 0 -> return CLeft+ _ -> return CRight }++instance Binary Fingerprint where+ put_ h (Fingerprint w1 w2) = do put_ h w1; put_ h w2+ get h = do w1 <- get h; w2 <- get h; return (Fingerprint w1 w2)++instance Binary FunctionOrData where+ put_ bh IsFunction = putByte bh 0+ put_ bh IsData = putByte bh 1+ get bh = do+ h <- getByte bh+ case h of+ 0 -> return IsFunction+ 1 -> return IsData+ _ -> panic "Binary FunctionOrData"++instance Binary TupleSort where+ put_ bh BoxedTuple = putByte bh 0+ put_ bh UnboxedTuple = putByte bh 1+ put_ bh ConstraintTuple = putByte bh 2+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return BoxedTuple+ 1 -> do return UnboxedTuple+ _ -> do return ConstraintTuple++instance Binary Activation where+ put_ bh NeverActive = do+ putByte bh 0+ put_ bh AlwaysActive = do+ putByte bh 1+ put_ bh (ActiveBefore src aa) = do+ putByte bh 2+ put_ bh src+ put_ bh aa+ put_ bh (ActiveAfter src ab) = do+ putByte bh 3+ put_ bh src+ put_ bh ab+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return NeverActive+ 1 -> do return AlwaysActive+ 2 -> do src <- get bh+ aa <- get bh+ return (ActiveBefore src aa)+ _ -> do src <- get bh+ ab <- get bh+ return (ActiveAfter src ab)++instance Binary InlinePragma where+ put_ bh (InlinePragma s a b c d) = do+ put_ bh s+ put_ bh a+ put_ bh b+ put_ bh c+ put_ bh d++ get bh = do+ s <- get bh+ a <- get bh+ b <- get bh+ c <- get bh+ d <- get bh+ return (InlinePragma s a b c d)++instance Binary RuleMatchInfo where+ put_ bh FunLike = putByte bh 0+ put_ bh ConLike = putByte bh 1+ get bh = do+ h <- getByte bh+ if h == 1 then return ConLike+ else return FunLike++instance Binary InlineSpec where+ put_ bh EmptyInlineSpec = putByte bh 0+ put_ bh Inline = putByte bh 1+ put_ bh Inlinable = putByte bh 2+ put_ bh NoInline = putByte bh 3++ get bh = do h <- getByte bh+ case h of+ 0 -> return EmptyInlineSpec+ 1 -> return Inline+ 2 -> return Inlinable+ _ -> return NoInline++instance Binary RecFlag where+ put_ bh Recursive = do+ putByte bh 0+ put_ bh NonRecursive = do+ putByte bh 1+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return Recursive+ _ -> do return NonRecursive++instance Binary OverlapMode where+ put_ bh (NoOverlap s) = putByte bh 0 >> put_ bh s+ put_ bh (Overlaps s) = putByte bh 1 >> put_ bh s+ put_ bh (Incoherent s) = putByte bh 2 >> put_ bh s+ put_ bh (Overlapping s) = putByte bh 3 >> put_ bh s+ put_ bh (Overlappable s) = putByte bh 4 >> put_ bh s+ get bh = do+ h <- getByte bh+ case h of+ 0 -> (get bh) >>= \s -> return $ NoOverlap s+ 1 -> (get bh) >>= \s -> return $ Overlaps s+ 2 -> (get bh) >>= \s -> return $ Incoherent s+ 3 -> (get bh) >>= \s -> return $ Overlapping s+ 4 -> (get bh) >>= \s -> return $ Overlappable s+ _ -> panic ("get OverlapMode" ++ show h)+++instance Binary OverlapFlag where+ put_ bh flag = do put_ bh (overlapMode flag)+ put_ bh (isSafeOverlap flag)+ get bh = do+ h <- get bh+ b <- get bh+ return OverlapFlag { overlapMode = h, isSafeOverlap = b }++instance Binary FixityDirection where+ put_ bh InfixL = do+ putByte bh 0+ put_ bh InfixR = do+ putByte bh 1+ put_ bh InfixN = do+ putByte bh 2+ get bh = do+ h <- getByte bh+ case h of+ 0 -> do return InfixL+ 1 -> do return InfixR+ _ -> do return InfixN++instance Binary Fixity where+ put_ bh (Fixity src aa ab) = do+ put_ bh src+ put_ bh aa+ put_ bh ab+ get bh = do+ src <- get bh+ aa <- get bh+ ab <- get bh+ return (Fixity src aa ab)++instance Binary WarningTxt where+ put_ bh (WarningTxt s w) = do+ putByte bh 0+ put_ bh s+ put_ bh w+ put_ bh (DeprecatedTxt s d) = do+ putByte bh 1+ put_ bh s+ put_ bh d++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do s <- get bh+ w <- get bh+ return (WarningTxt s w)+ _ -> do s <- get bh+ d <- get bh+ return (DeprecatedTxt s d)++instance Binary StringLiteral where+ put_ bh (StringLiteral st fs) = do+ put_ bh st+ put_ bh fs+ get bh = do+ st <- get bh+ fs <- get bh+ return (StringLiteral st fs)++instance Binary a => Binary (GenLocated SrcSpan a) where+ put_ bh (L l x) = do+ put_ bh l+ put_ bh x++ get bh = do+ l <- get bh+ x <- get bh+ return (L l x)++instance Binary SrcSpan where+ put_ bh (RealSrcSpan ss) = do+ putByte bh 0+ put_ bh (srcSpanFile ss)+ put_ bh (srcSpanStartLine ss)+ put_ bh (srcSpanStartCol ss)+ put_ bh (srcSpanEndLine ss)+ put_ bh (srcSpanEndCol ss)++ put_ bh (UnhelpfulSpan s) = do+ putByte bh 1+ put_ bh s++ get bh = do+ h <- getByte bh+ case h of+ 0 -> do f <- get bh+ sl <- get bh+ sc <- get bh+ el <- get bh+ ec <- get bh+ return (mkSrcSpan (mkSrcLoc f sl sc)+ (mkSrcLoc f el ec))+ _ -> do s <- get bh+ return (UnhelpfulSpan s)++instance Binary Serialized where+ put_ bh (Serialized the_type bytes) = do+ put_ bh the_type+ put_ bh bytes+ get bh = do+ the_type <- get bh+ bytes <- get bh+ return (Serialized the_type bytes)++instance Binary SourceText where+ put_ bh NoSourceText = putByte bh 0+ put_ bh (SourceText s) = do+ putByte bh 1+ put_ bh s++ get bh = do+ h <- getByte bh+ case h of+ 0 -> return NoSourceText+ 1 -> do+ s <- get bh+ return (SourceText s)+ _ -> panic $ "Binary SourceText:" ++ show h
+ utils/BooleanFormula.hs view
@@ -0,0 +1,260 @@+{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveFoldable,+ DeriveTraversable #-}++--------------------------------------------------------------------------------+-- | Boolean formulas without quantifiers and without negation.+-- Such a formula consists of variables, conjunctions (and), and disjunctions (or).+--+-- This module is used to represent minimal complete definitions for classes.+--+module BooleanFormula (+ BooleanFormula(..), LBooleanFormula,+ mkFalse, mkTrue, mkAnd, mkOr, mkVar,+ isFalse, isTrue,+ eval, simplify, isUnsatisfied,+ implies, impliesAtom,+ pprBooleanFormula, pprBooleanFormulaNice+ ) where++import Data.List ( nub, intersperse )+import Data.Data++import MonadUtils+import Outputable+import Binary+import SrcLoc+import Unique+import UniqSet++----------------------------------------------------------------------+-- Boolean formula type and smart constructors+----------------------------------------------------------------------++type LBooleanFormula a = Located (BooleanFormula a)++data BooleanFormula a = Var a | And [LBooleanFormula a] | Or [LBooleanFormula a]+ | Parens (LBooleanFormula a)+ deriving (Eq, Data, Functor, Foldable, Traversable)++mkVar :: a -> BooleanFormula a+mkVar = Var++mkFalse, mkTrue :: BooleanFormula a+mkFalse = Or []+mkTrue = And []++-- Convert a Bool to a BooleanFormula+mkBool :: Bool -> BooleanFormula a+mkBool False = mkFalse+mkBool True = mkTrue++-- Make a conjunction, and try to simplify+mkAnd :: Eq a => [LBooleanFormula a] -> BooleanFormula a+mkAnd = maybe mkFalse (mkAnd' . nub) . concatMapM fromAnd+ where+ -- See Note [Simplification of BooleanFormulas]+ fromAnd :: LBooleanFormula a -> Maybe [LBooleanFormula a]+ fromAnd (L _ (And xs)) = Just xs+ -- assume that xs are already simplified+ -- otherwise we would need: fromAnd (And xs) = concat <$> traverse fromAnd xs+ fromAnd (L _ (Or [])) = Nothing+ -- in case of False we bail out, And [..,mkFalse,..] == mkFalse+ fromAnd x = Just [x]+ mkAnd' [x] = unLoc x+ mkAnd' xs = And xs++mkOr :: Eq a => [LBooleanFormula a] -> BooleanFormula a+mkOr = maybe mkTrue (mkOr' . nub) . concatMapM fromOr+ where+ -- See Note [Simplification of BooleanFormulas]+ fromOr (L _ (Or xs)) = Just xs+ fromOr (L _ (And [])) = Nothing+ fromOr x = Just [x]+ mkOr' [x] = unLoc x+ mkOr' xs = Or xs+++{-+Note [Simplification of BooleanFormulas]+~~~~~~~~~~~~~~~~~~~~~~+The smart constructors (`mkAnd` and `mkOr`) do some attempt to simplify expressions. In particular,+ 1. Collapsing nested ands and ors, so+ `(mkAnd [x, And [y,z]]`+ is represented as+ `And [x,y,z]`+ Implemented by `fromAnd`/`fromOr`+ 2. Collapsing trivial ands and ors, so+ `mkAnd [x]` becomes just `x`.+ Implemented by mkAnd' / mkOr'+ 3. Conjunction with false, disjunction with true is simplified, i.e.+ `mkAnd [mkFalse,x]` becomes `mkFalse`.+ 4. Common subexpression elimination:+ `mkAnd [x,x,y]` is reduced to just `mkAnd [x,y]`.++This simplification is not exhaustive, in the sense that it will not produce+the smallest possible equivalent expression. For example,+`Or [And [x,y], And [x]]` could be simplified to `And [x]`, but it currently+is not. A general simplifier would need to use something like BDDs.++The reason behind the (crude) simplifier is to make for more user friendly+error messages. E.g. for the code+ > class Foo a where+ > {-# MINIMAL bar, (foo, baq | foo, quux) #-}+ > instance Foo Int where+ > bar = ...+ > baz = ...+ > quux = ...+We don't show a ridiculous error message like+ Implement () and (either (`foo' and ()) or (`foo' and ()))+-}++----------------------------------------------------------------------+-- Evaluation and simplification+----------------------------------------------------------------------++isFalse :: BooleanFormula a -> Bool+isFalse (Or []) = True+isFalse _ = False++isTrue :: BooleanFormula a -> Bool+isTrue (And []) = True+isTrue _ = False++eval :: (a -> Bool) -> BooleanFormula a -> Bool+eval f (Var x) = f x+eval f (And xs) = all (eval f . unLoc) xs+eval f (Or xs) = any (eval f . unLoc) xs+eval f (Parens x) = eval f (unLoc x)++-- Simplify a boolean formula.+-- The argument function should give the truth of the atoms, or Nothing if undecided.+simplify :: Eq a => (a -> Maybe Bool) -> BooleanFormula a -> BooleanFormula a+simplify f (Var a) = case f a of+ Nothing -> Var a+ Just b -> mkBool b+simplify f (And xs) = mkAnd (map (\(L l x) -> L l (simplify f x)) xs)+simplify f (Or xs) = mkOr (map (\(L l x) -> L l (simplify f x)) xs)+simplify f (Parens x) = simplify f (unLoc x)++-- Test if a boolean formula is satisfied when the given values are assigned to the atoms+-- if it is, returns Nothing+-- if it is not, return (Just remainder)+isUnsatisfied :: Eq a => (a -> Bool) -> BooleanFormula a -> Maybe (BooleanFormula a)+isUnsatisfied f bf+ | isTrue bf' = Nothing+ | otherwise = Just bf'+ where+ f' x = if f x then Just True else Nothing+ bf' = simplify f' bf++-- prop_simplify:+-- eval f x == True <==> isTrue (simplify (Just . f) x)+-- eval f x == False <==> isFalse (simplify (Just . f) x)++-- If the boolean formula holds, does that mean that the given atom is always true?+impliesAtom :: Eq a => BooleanFormula a -> a -> Bool+Var x `impliesAtom` y = x == y+And xs `impliesAtom` y = any (\x -> (unLoc x) `impliesAtom` y) xs+ -- we have all of xs, so one of them implying y is enough+Or xs `impliesAtom` y = all (\x -> (unLoc x) `impliesAtom` y) xs+Parens x `impliesAtom` y = (unLoc x) `impliesAtom` y++implies :: Uniquable a => BooleanFormula a -> BooleanFormula a -> Bool+implies e1 e2 = go (Clause emptyUniqSet [e1]) (Clause emptyUniqSet [e2])+ where+ go :: Uniquable a => Clause a -> Clause a -> Bool+ go l@Clause{ clauseExprs = hyp:hyps } r =+ case hyp of+ Var x | memberClauseAtoms x r -> True+ | otherwise -> go (extendClauseAtoms l x) { clauseExprs = hyps } r+ Parens hyp' -> go l { clauseExprs = unLoc hyp':hyps } r+ And hyps' -> go l { clauseExprs = map unLoc hyps' ++ hyps } r+ Or hyps' -> all (\hyp' -> go l { clauseExprs = unLoc hyp':hyps } r) hyps'+ go l r@Clause{ clauseExprs = con:cons } =+ case con of+ Var x | memberClauseAtoms x l -> True+ | otherwise -> go l (extendClauseAtoms r x) { clauseExprs = cons }+ Parens con' -> go l r { clauseExprs = unLoc con':cons }+ And cons' -> all (\con' -> go l r { clauseExprs = unLoc con':cons }) cons'+ Or cons' -> go l r { clauseExprs = map unLoc cons' ++ cons }+ go _ _ = False++-- A small sequent calculus proof engine.+data Clause a = Clause {+ clauseAtoms :: UniqSet a,+ clauseExprs :: [BooleanFormula a]+ }+extendClauseAtoms :: Uniquable a => Clause a -> a -> Clause a+extendClauseAtoms c x = c { clauseAtoms = addOneToUniqSet (clauseAtoms c) x }++memberClauseAtoms :: Uniquable a => a -> Clause a -> Bool+memberClauseAtoms x c = x `elementOfUniqSet` clauseAtoms c++----------------------------------------------------------------------+-- Pretty printing+----------------------------------------------------------------------++-- Pretty print a BooleanFormula,+-- using the arguments as pretty printers for Var, And and Or respectively+pprBooleanFormula' :: (Rational -> a -> SDoc)+ -> (Rational -> [SDoc] -> SDoc)+ -> (Rational -> [SDoc] -> SDoc)+ -> Rational -> BooleanFormula a -> SDoc+pprBooleanFormula' pprVar pprAnd pprOr = go+ where+ go p (Var x) = pprVar p x+ go p (And []) = cparen (p > 0) $ empty+ go p (And xs) = pprAnd p (map (go 3 . unLoc) xs)+ go _ (Or []) = keyword $ text "FALSE"+ go p (Or xs) = pprOr p (map (go 2 . unLoc) xs)+ go p (Parens x) = go p (unLoc x)++-- Pretty print in source syntax, "a | b | c,d,e"+pprBooleanFormula :: (Rational -> a -> SDoc) -> Rational -> BooleanFormula a -> SDoc+pprBooleanFormula pprVar = pprBooleanFormula' pprVar pprAnd pprOr+ where+ pprAnd p = cparen (p > 3) . fsep . punctuate comma+ pprOr p = cparen (p > 2) . fsep . intersperse vbar++-- Pretty print human in readable format, "either `a' or `b' or (`c', `d' and `e')"?+pprBooleanFormulaNice :: Outputable a => BooleanFormula a -> SDoc+pprBooleanFormulaNice = pprBooleanFormula' pprVar pprAnd pprOr 0+ where+ pprVar _ = quotes . ppr+ pprAnd p = cparen (p > 1) . pprAnd'+ pprAnd' [] = empty+ pprAnd' [x,y] = x <+> text "and" <+> y+ pprAnd' xs@(_:_) = fsep (punctuate comma (init xs)) <> text ", and" <+> last xs+ pprOr p xs = cparen (p > 1) $ text "either" <+> sep (intersperse (text "or") xs)++instance (OutputableBndr a) => Outputable (BooleanFormula a) where+ ppr = pprBooleanFormulaNormal++pprBooleanFormulaNormal :: (OutputableBndr a)+ => BooleanFormula a -> SDoc+pprBooleanFormulaNormal = go+ where+ go (Var x) = pprPrefixOcc x+ go (And xs) = fsep $ punctuate comma (map (go . unLoc) xs)+ go (Or []) = keyword $ text "FALSE"+ go (Or xs) = fsep $ intersperse vbar (map (go . unLoc) xs)+ go (Parens x) = parens (go $ unLoc x)+++----------------------------------------------------------------------+-- Binary+----------------------------------------------------------------------++instance Binary a => Binary (BooleanFormula a) where+ put_ bh (Var x) = putByte bh 0 >> put_ bh x+ put_ bh (And xs) = putByte bh 1 >> put_ bh xs+ put_ bh (Or xs) = putByte bh 2 >> put_ bh xs+ put_ bh (Parens x) = putByte bh 3 >> put_ bh x++ get bh = do+ h <- getByte bh+ case h of+ 0 -> Var <$> get bh+ 1 -> And <$> get bh+ 2 -> Or <$> get bh+ _ -> Parens <$> get bh
+ utils/BufWrite.hs view
@@ -0,0 +1,116 @@+{-# LANGUAGE BangPatterns #-}++-----------------------------------------------------------------------------+--+-- Fast write-buffered Handles+--+-- (c) The University of Glasgow 2005-2006+--+-- This is a simple abstraction over Handles that offers very fast write+-- buffering, but without the thread safety that Handles provide. It's used+-- to save time in Pretty.printDoc.+--+-----------------------------------------------------------------------------++module BufWrite (+ BufHandle(..),+ newBufHandle,+ bPutChar,+ bPutStr,+ bPutFS,+ bPutFZS,+ bPutLitString,+ bFlush,+ ) where++import FastString+import FastMutInt++import Control.Monad ( when )+import Data.ByteString (ByteString)+import qualified Data.ByteString.Unsafe as BS+import Data.Char ( ord )+import Foreign+import Foreign.C.String+import System.IO++-- -----------------------------------------------------------------------------++data BufHandle = BufHandle {-#UNPACK#-}!(Ptr Word8)+ {-#UNPACK#-}!FastMutInt+ Handle++newBufHandle :: Handle -> IO BufHandle+newBufHandle hdl = do+ ptr <- mallocBytes buf_size+ r <- newFastMutInt+ writeFastMutInt r 0+ return (BufHandle ptr r hdl)++buf_size :: Int+buf_size = 8192++bPutChar :: BufHandle -> Char -> IO ()+bPutChar b@(BufHandle buf r hdl) !c = do+ i <- readFastMutInt r+ if (i >= buf_size)+ then do hPutBuf hdl buf buf_size+ writeFastMutInt r 0+ bPutChar b c+ else do pokeElemOff buf i (fromIntegral (ord c) :: Word8)+ writeFastMutInt r (i+1)++bPutStr :: BufHandle -> String -> IO ()+bPutStr (BufHandle buf r hdl) !str = do+ i <- readFastMutInt r+ loop str i+ where loop "" !i = do writeFastMutInt r i; return ()+ loop (c:cs) !i+ | i >= buf_size = do+ hPutBuf hdl buf buf_size+ loop (c:cs) 0+ | otherwise = do+ pokeElemOff buf i (fromIntegral (ord c))+ loop cs (i+1)++bPutFS :: BufHandle -> FastString -> IO ()+bPutFS b fs = bPutBS b $ fastStringToByteString fs++bPutFZS :: BufHandle -> FastZString -> IO ()+bPutFZS b fs = bPutBS b $ fastZStringToByteString fs++bPutBS :: BufHandle -> ByteString -> IO ()+bPutBS b bs = BS.unsafeUseAsCStringLen bs $ bPutCStringLen b++bPutCStringLen :: BufHandle -> CStringLen -> IO ()+bPutCStringLen b@(BufHandle buf r hdl) cstr@(ptr, len) = do+ i <- readFastMutInt r+ if (i + len) >= buf_size+ then do hPutBuf hdl buf i+ writeFastMutInt r 0+ if (len >= buf_size)+ then hPutBuf hdl ptr len+ else bPutCStringLen b cstr+ else do+ copyBytes (buf `plusPtr` i) ptr len+ writeFastMutInt r (i + len)++bPutLitString :: BufHandle -> LitString -> Int -> IO ()+bPutLitString b@(BufHandle buf r hdl) a len = a `seq` do+ i <- readFastMutInt r+ if (i+len) >= buf_size+ then do hPutBuf hdl buf i+ writeFastMutInt r 0+ if (len >= buf_size)+ then hPutBuf hdl a len+ else bPutLitString b a len+ else do+ copyBytes (buf `plusPtr` i) a len+ writeFastMutInt r (i+len)++bFlush :: BufHandle -> IO ()+bFlush (BufHandle buf r hdl) = do+ i <- readFastMutInt r+ when (i > 0) $ hPutBuf hdl buf i+ free buf+ return ()
+ utils/Digraph.hs view
@@ -0,0 +1,502 @@+-- (c) The University of Glasgow 2006++{-# LANGUAGE CPP, ScopedTypeVariables #-}++module Digraph(+ Graph, graphFromEdgedVerticesOrd, graphFromEdgedVerticesUniq,++ SCC(..), Node, flattenSCC, flattenSCCs,+ stronglyConnCompG,+ topologicalSortG, dfsTopSortG,+ verticesG, edgesG, hasVertexG,+ reachableG, reachablesG, transposeG,+ outdegreeG, indegreeG,+ vertexGroupsG, emptyG,+ componentsG,++ findCycle,++ -- For backwards compatibility with the simpler version of Digraph+ stronglyConnCompFromEdgedVerticesOrd,+ stronglyConnCompFromEdgedVerticesOrdR,+ stronglyConnCompFromEdgedVerticesUniq,+ stronglyConnCompFromEdgedVerticesUniqR,+ ) where++#include "HsVersions.h"++------------------------------------------------------------------------------+-- A version of the graph algorithms described in:+--+-- ``Lazy Depth-First Search and Linear IntGraph Algorithms in Haskell''+-- by David King and John Launchbury+--+-- Also included is some additional code for printing tree structures ...+--+-- If you ever find yourself in need of algorithms for classifying edges,+-- or finding connected/biconnected components, consult the history; Sigbjorn+-- Finne contributed some implementations in 1997, although we've since+-- removed them since they were not used anywhere in GHC.+------------------------------------------------------------------------------+++import Util ( minWith, count )+import Outputable+import Maybes ( expectJust )+import MonadUtils ( allM )++-- Extensions+import Control.Monad ( filterM, liftM, liftM2 )+import Control.Monad.ST++-- std interfaces+import Data.Maybe+import Data.Array+import Data.List hiding (transpose)+import Data.Array.ST+import qualified Data.Map as Map+import qualified Data.Set as Set++import qualified Data.Graph as G+import Data.Graph hiding (Graph, Edge, transposeG, reachable)+import Data.Tree+import Unique+import UniqFM++{-+************************************************************************+* *+* Graphs and Graph Construction+* *+************************************************************************++Note [Nodes, keys, vertices]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ * A 'node' is a big blob of client-stuff++ * Each 'node' has a unique (client) 'key', but the latter+ is in Ord and has fast comparison++ * Digraph then maps each 'key' to a Vertex (Int) which is+ arranged densely in 0.n+-}++data Graph node = Graph {+ gr_int_graph :: IntGraph,+ gr_vertex_to_node :: Vertex -> node,+ gr_node_to_vertex :: node -> Maybe Vertex+ }++data Edge node = Edge node node++type Node key payload = (payload, key, [key])+ -- The payload is user data, just carried around in this module+ -- The keys are ordered+ -- The [key] are the dependencies of the node;+ -- it's ok to have extra keys in the dependencies that+ -- are not the key of any Node in the graph++emptyGraph :: Graph a+emptyGraph = Graph (array (1, 0) []) (error "emptyGraph") (const Nothing)++-- See Note [Deterministic SCC]+graphFromEdgedVertices+ :: ReduceFn key payload+ -> [Node key payload] -- The graph; its ok for the+ -- out-list to contain keys which aren't+ -- a vertex key, they are ignored+ -> Graph (Node key payload)+graphFromEdgedVertices _reduceFn [] = emptyGraph+graphFromEdgedVertices reduceFn edged_vertices =+ Graph graph vertex_fn (key_vertex . key_extractor)+ where key_extractor (_, k, _) = k+ (bounds, vertex_fn, key_vertex, numbered_nodes) =+ reduceFn edged_vertices key_extractor+ graph = array bounds [ (v, sort $ mapMaybe key_vertex ks)+ | (v, (_, _, ks)) <- numbered_nodes]+ -- We normalize outgoing edges by sorting on node order, so+ -- that the result doesn't depend on the order of the edges++-- See Note [Deterministic SCC]+-- See Note [reduceNodesIntoVertices implementations]+graphFromEdgedVerticesOrd+ :: Ord key+ => [Node key payload] -- The graph; its ok for the+ -- out-list to contain keys which aren't+ -- a vertex key, they are ignored+ -> Graph (Node key payload)+graphFromEdgedVerticesOrd = graphFromEdgedVertices reduceNodesIntoVerticesOrd++-- See Note [Deterministic SCC]+-- See Note [reduceNodesIntoVertices implementations]+graphFromEdgedVerticesUniq+ :: Uniquable key+ => [Node key payload] -- The graph; its ok for the+ -- out-list to contain keys which aren't+ -- a vertex key, they are ignored+ -> Graph (Node key payload)+graphFromEdgedVerticesUniq = graphFromEdgedVertices reduceNodesIntoVerticesUniq++type ReduceFn key payload =+ [Node key payload] -> (Node key payload -> key) ->+ (Bounds, Vertex -> Node key payload+ , key -> Maybe Vertex, [(Vertex, Node key payload)])++{-+Note [reduceNodesIntoVertices implementations]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+reduceNodesIntoVertices is parameterized by the container type.+This is to accomodate key types that don't have an Ord instance+and hence preclude the use of Data.Map. An example of such type+would be Unique, there's no way to implement Ord Unique+deterministically.++For such types, there's a version with a Uniquable constraint.+This leaves us with two versions of every function that depends on+reduceNodesIntoVertices, one with Ord constraint and the other with+Uniquable constraint.+For example: graphFromEdgedVerticesOrd and graphFromEdgedVerticesUniq.++The Uniq version should be a tiny bit more efficient since it uses+Data.IntMap internally.+-}+reduceNodesIntoVertices+ :: ([(key, Vertex)] -> m)+ -> (key -> m -> Maybe Vertex)+ -> ReduceFn key payload+reduceNodesIntoVertices fromList lookup nodes key_extractor =+ (bounds, (!) vertex_map, key_vertex, numbered_nodes)+ where+ max_v = length nodes - 1+ bounds = (0, max_v) :: (Vertex, Vertex)++ -- Keep the order intact to make the result depend on input order+ -- instead of key order+ numbered_nodes = zip [0..] nodes+ vertex_map = array bounds numbered_nodes++ key_map = fromList+ [ (key_extractor node, v) | (v, node) <- numbered_nodes ]+ key_vertex k = lookup k key_map++-- See Note [reduceNodesIntoVertices implementations]+reduceNodesIntoVerticesOrd :: Ord key => ReduceFn key payload+reduceNodesIntoVerticesOrd = reduceNodesIntoVertices Map.fromList Map.lookup++-- See Note [reduceNodesIntoVertices implementations]+reduceNodesIntoVerticesUniq :: Uniquable key => ReduceFn key payload+reduceNodesIntoVerticesUniq = reduceNodesIntoVertices listToUFM (flip lookupUFM)++{-+************************************************************************+* *+* SCC+* *+************************************************************************+-}++type WorkItem key payload+ = (Node key payload, -- Tip of the path+ [payload]) -- Rest of the path;+ -- [a,b,c] means c depends on b, b depends on a++-- | Find a reasonably short cycle a->b->c->a, in a strongly+-- connected component. The input nodes are presumed to be+-- a SCC, so you can start anywhere.+findCycle :: forall payload key. Ord key+ => [Node key payload] -- The nodes. The dependencies can+ -- contain extra keys, which are ignored+ -> Maybe [payload] -- A cycle, starting with node+ -- so each depends on the next+findCycle graph+ = go Set.empty (new_work root_deps []) []+ where+ env :: Map.Map key (Node key payload)+ env = Map.fromList [ (key, node) | node@(_, key, _) <- graph ]++ -- Find the node with fewest dependencies among the SCC modules+ -- This is just a heuristic to find some plausible root module+ root :: Node key payload+ root = fst (minWith snd [ (node, count (`Map.member` env) deps)+ | node@(_,_,deps) <- graph ])+ (root_payload,root_key,root_deps) = root+++ -- 'go' implements Dijkstra's algorithm, more or less+ go :: Set.Set key -- Visited+ -> [WorkItem key payload] -- Work list, items length n+ -> [WorkItem key payload] -- Work list, items length n+1+ -> Maybe [payload] -- Returned cycle+ -- Invariant: in a call (go visited ps qs),+ -- visited = union (map tail (ps ++ qs))++ go _ [] [] = Nothing -- No cycles+ go visited [] qs = go visited qs []+ go visited (((payload,key,deps), path) : ps) qs+ | key == root_key = Just (root_payload : reverse path)+ | key `Set.member` visited = go visited ps qs+ | key `Map.notMember` env = go visited ps qs+ | otherwise = go (Set.insert key visited)+ ps (new_qs ++ qs)+ where+ new_qs = new_work deps (payload : path)++ new_work :: [key] -> [payload] -> [WorkItem key payload]+ new_work deps path = [ (n, path) | Just n <- map (`Map.lookup` env) deps ]++{-+************************************************************************+* *+* Strongly Connected Component wrappers for Graph+* *+************************************************************************++Note: the components are returned topologically sorted: later components+depend on earlier ones, but not vice versa i.e. later components only have+edges going from them to earlier ones.+-}++{-+Note [Deterministic SCC]+~~~~~~~~~~~~~~~~~~~~~~~~+stronglyConnCompFromEdgedVerticesUniq,+stronglyConnCompFromEdgedVerticesUniqR,+stronglyConnCompFromEdgedVerticesOrd and+stronglyConnCompFromEdgedVerticesOrdR+provide a following guarantee:+Given a deterministically ordered list of nodes it returns a deterministically+ordered list of strongly connected components, where the list of vertices+in an SCC is also deterministically ordered.+Note that the order of edges doesn't need to be deterministic for this to work.+We use the order of nodes to normalize the order of edges.+-}++stronglyConnCompG :: Graph node -> [SCC node]+stronglyConnCompG graph = decodeSccs graph forest+ where forest = {-# SCC "Digraph.scc" #-} scc (gr_int_graph graph)++decodeSccs :: Graph node -> Forest Vertex -> [SCC node]+decodeSccs Graph { gr_int_graph = graph, gr_vertex_to_node = vertex_fn } forest+ = map decode forest+ where+ decode (Node v []) | mentions_itself v = CyclicSCC [vertex_fn v]+ | otherwise = AcyclicSCC (vertex_fn v)+ decode other = CyclicSCC (dec other [])+ where dec (Node v ts) vs = vertex_fn v : foldr dec vs ts+ mentions_itself v = v `elem` (graph ! v)+++-- The following two versions are provided for backwards compatibility:+-- See Note [Deterministic SCC]+-- See Note [reduceNodesIntoVertices implementations]+stronglyConnCompFromEdgedVerticesOrd+ :: Ord key+ => [Node key payload]+ -> [SCC payload]+stronglyConnCompFromEdgedVerticesOrd+ = map (fmap get_node) . stronglyConnCompFromEdgedVerticesOrdR+ where get_node (n, _, _) = n++-- The following two versions are provided for backwards compatibility:+-- See Note [Deterministic SCC]+-- See Note [reduceNodesIntoVertices implementations]+stronglyConnCompFromEdgedVerticesUniq+ :: Uniquable key+ => [Node key payload]+ -> [SCC payload]+stronglyConnCompFromEdgedVerticesUniq+ = map (fmap get_node) . stronglyConnCompFromEdgedVerticesUniqR+ where get_node (n, _, _) = n++-- The "R" interface is used when you expect to apply SCC to+-- (some of) the result of SCC, so you dont want to lose the dependency info+-- See Note [Deterministic SCC]+-- See Note [reduceNodesIntoVertices implementations]+stronglyConnCompFromEdgedVerticesOrdR+ :: Ord key+ => [Node key payload]+ -> [SCC (Node key payload)]+stronglyConnCompFromEdgedVerticesOrdR =+ stronglyConnCompG . graphFromEdgedVertices reduceNodesIntoVerticesOrd++-- The "R" interface is used when you expect to apply SCC to+-- (some of) the result of SCC, so you dont want to lose the dependency info+-- See Note [Deterministic SCC]+-- See Note [reduceNodesIntoVertices implementations]+stronglyConnCompFromEdgedVerticesUniqR+ :: Uniquable key+ => [Node key payload]+ -> [SCC (Node key payload)]+stronglyConnCompFromEdgedVerticesUniqR =+ stronglyConnCompG . graphFromEdgedVertices reduceNodesIntoVerticesUniq++{-+************************************************************************+* *+* Misc wrappers for Graph+* *+************************************************************************+-}++topologicalSortG :: Graph node -> [node]+topologicalSortG graph = map (gr_vertex_to_node graph) result+ where result = {-# SCC "Digraph.topSort" #-} topSort (gr_int_graph graph)++dfsTopSortG :: Graph node -> [[node]]+dfsTopSortG graph =+ map (map (gr_vertex_to_node graph) . flatten) $ dfs g (topSort g)+ where+ g = gr_int_graph graph++reachableG :: Graph node -> node -> [node]+reachableG graph from = map (gr_vertex_to_node graph) result+ where from_vertex = expectJust "reachableG" (gr_node_to_vertex graph from)+ result = {-# SCC "Digraph.reachable" #-} reachable (gr_int_graph graph) [from_vertex]++reachablesG :: Graph node -> [node] -> [node]+reachablesG graph froms = map (gr_vertex_to_node graph) result+ where result = {-# SCC "Digraph.reachable" #-}+ reachable (gr_int_graph graph) vs+ vs = [ v | Just v <- map (gr_node_to_vertex graph) froms ]++hasVertexG :: Graph node -> node -> Bool+hasVertexG graph node = isJust $ gr_node_to_vertex graph node++verticesG :: Graph node -> [node]+verticesG graph = map (gr_vertex_to_node graph) $ vertices (gr_int_graph graph)++edgesG :: Graph node -> [Edge node]+edgesG graph = map (\(v1, v2) -> Edge (v2n v1) (v2n v2)) $ edges (gr_int_graph graph)+ where v2n = gr_vertex_to_node graph++transposeG :: Graph node -> Graph node+transposeG graph = Graph (G.transposeG (gr_int_graph graph))+ (gr_vertex_to_node graph)+ (gr_node_to_vertex graph)++outdegreeG :: Graph node -> node -> Maybe Int+outdegreeG = degreeG outdegree++indegreeG :: Graph node -> node -> Maybe Int+indegreeG = degreeG indegree++degreeG :: (G.Graph -> Table Int) -> Graph node -> node -> Maybe Int+degreeG degree graph node = let table = degree (gr_int_graph graph)+ in fmap ((!) table) $ gr_node_to_vertex graph node++vertexGroupsG :: Graph node -> [[node]]+vertexGroupsG graph = map (map (gr_vertex_to_node graph)) result+ where result = vertexGroups (gr_int_graph graph)++emptyG :: Graph node -> Bool+emptyG g = graphEmpty (gr_int_graph g)++componentsG :: Graph node -> [[node]]+componentsG graph = map (map (gr_vertex_to_node graph) . flatten)+ $ components (gr_int_graph graph)++{-+************************************************************************+* *+* Showing Graphs+* *+************************************************************************+-}++instance Outputable node => Outputable (Graph node) where+ ppr graph = vcat [+ hang (text "Vertices:") 2 (vcat (map ppr $ verticesG graph)),+ hang (text "Edges:") 2 (vcat (map ppr $ edgesG graph))+ ]++instance Outputable node => Outputable (Edge node) where+ ppr (Edge from to) = ppr from <+> text "->" <+> ppr to++graphEmpty :: G.Graph -> Bool+graphEmpty g = lo > hi+ where (lo, hi) = bounds g++{-+************************************************************************+* *+* IntGraphs+* *+************************************************************************+-}++type IntGraph = G.Graph++{-+------------------------------------------------------------+-- Depth first search numbering+------------------------------------------------------------+-}++-- Data.Tree has flatten for Tree, but nothing for Forest+preorderF :: Forest a -> [a]+preorderF ts = concat (map flatten ts)++{-+------------------------------------------------------------+-- Finding reachable vertices+------------------------------------------------------------+-}++-- This generalizes reachable which was found in Data.Graph+reachable :: IntGraph -> [Vertex] -> [Vertex]+reachable g vs = preorderF (dfs g vs)++{-+------------------------------------------------------------+-- Total ordering on groups of vertices+------------------------------------------------------------++The plan here is to extract a list of groups of elements of the graph+such that each group has no dependence except on nodes in previous+groups (i.e. in particular they may not depend on nodes in their own+group) and is maximal such group.++Clearly we cannot provide a solution for cyclic graphs.++We proceed by iteratively removing elements with no outgoing edges+and their associated edges from the graph.++This probably isn't very efficient and certainly isn't very clever.+-}++type Set s = STArray s Vertex Bool++mkEmpty :: Bounds -> ST s (Set s)+mkEmpty bnds = newArray bnds False++contains :: Set s -> Vertex -> ST s Bool+contains m v = readArray m v++include :: Set s -> Vertex -> ST s ()+include m v = writeArray m v True++vertexGroups :: IntGraph -> [[Vertex]]+vertexGroups g = runST (mkEmpty (bounds g) >>= \provided -> vertexGroupsS provided g next_vertices)+ where next_vertices = noOutEdges g++noOutEdges :: IntGraph -> [Vertex]+noOutEdges g = [ v | v <- vertices g, null (g!v)]++vertexGroupsS :: Set s -> IntGraph -> [Vertex] -> ST s [[Vertex]]+vertexGroupsS provided g to_provide+ = if null to_provide+ then do {+ all_provided <- allM (provided `contains`) (vertices g)+ ; if all_provided+ then return []+ else error "vertexGroup: cyclic graph"+ }+ else do {+ mapM_ (include provided) to_provide+ ; to_provide' <- filterM (vertexReady provided g) (vertices g)+ ; rest <- vertexGroupsS provided g to_provide'+ ; return $ to_provide : rest+ }++vertexReady :: Set s -> IntGraph -> Vertex -> ST s Bool+vertexReady provided g v = liftM2 (&&) (liftM not $ provided `contains` v) (allM (provided `contains`) (g!v))
+ utils/Encoding.hs view
@@ -0,0 +1,448 @@+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}+{-# OPTIONS_GHC -O #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected++-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow, 1997-2006+--+-- Character encodings+--+-- -----------------------------------------------------------------------------++module Encoding (+ -- * UTF-8+ utf8DecodeChar#,+ utf8PrevChar,+ utf8CharStart,+ utf8DecodeChar,+ utf8DecodeByteString,+ utf8DecodeStringLazy,+ utf8EncodeChar,+ utf8EncodeString,+ utf8EncodedLength,+ countUTF8Chars,++ -- * Z-encoding+ zEncodeString,+ zDecodeString,++ -- * Base62-encoding+ toBase62,+ toBase62Padded+ ) where++import Foreign+import Foreign.ForeignPtr.Unsafe+import Data.Char+import qualified Data.Char as Char+import Numeric+import GHC.IO++import Data.ByteString (ByteString)+import qualified Data.ByteString.Internal as BS++import GHC.Exts++-- -----------------------------------------------------------------------------+-- UTF-8++-- We can't write the decoder as efficiently as we'd like without+-- resorting to unboxed extensions, unfortunately. I tried to write+-- an IO version of this function, but GHC can't eliminate boxed+-- results from an IO-returning function.+--+-- We assume we can ignore overflow when parsing a multibyte character here.+-- To make this safe, we add extra sentinel bytes to unparsed UTF-8 sequences+-- before decoding them (see StringBuffer.hs).++{-# INLINE utf8DecodeChar# #-}+utf8DecodeChar# :: Addr# -> (# Char#, Int# #)+utf8DecodeChar# a# =+ let !ch0 = word2Int# (indexWord8OffAddr# a# 0#) in+ case () of+ _ | isTrue# (ch0 <=# 0x7F#) -> (# chr# ch0, 1# #)++ | isTrue# ((ch0 >=# 0xC0#) `andI#` (ch0 <=# 0xDF#)) ->+ let !ch1 = word2Int# (indexWord8OffAddr# a# 1#) in+ if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else+ (# chr# (((ch0 -# 0xC0#) `uncheckedIShiftL#` 6#) +#+ (ch1 -# 0x80#)),+ 2# #)++ | isTrue# ((ch0 >=# 0xE0#) `andI#` (ch0 <=# 0xEF#)) ->+ let !ch1 = word2Int# (indexWord8OffAddr# a# 1#) in+ if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else+ let !ch2 = word2Int# (indexWord8OffAddr# a# 2#) in+ if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else+ (# chr# (((ch0 -# 0xE0#) `uncheckedIShiftL#` 12#) +#+ ((ch1 -# 0x80#) `uncheckedIShiftL#` 6#) +#+ (ch2 -# 0x80#)),+ 3# #)++ | isTrue# ((ch0 >=# 0xF0#) `andI#` (ch0 <=# 0xF8#)) ->+ let !ch1 = word2Int# (indexWord8OffAddr# a# 1#) in+ if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else+ let !ch2 = word2Int# (indexWord8OffAddr# a# 2#) in+ if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else+ let !ch3 = word2Int# (indexWord8OffAddr# a# 3#) in+ if isTrue# ((ch3 <# 0x80#) `orI#` (ch3 >=# 0xC0#)) then fail 3# else+ (# chr# (((ch0 -# 0xF0#) `uncheckedIShiftL#` 18#) +#+ ((ch1 -# 0x80#) `uncheckedIShiftL#` 12#) +#+ ((ch2 -# 0x80#) `uncheckedIShiftL#` 6#) +#+ (ch3 -# 0x80#)),+ 4# #)++ | otherwise -> fail 1#+ where+ -- all invalid sequences end up here:+ fail :: Int# -> (# Char#, Int# #)+ fail nBytes# = (# '\0'#, nBytes# #)+ -- '\xFFFD' would be the usual replacement character, but+ -- that's a valid symbol in Haskell, so will result in a+ -- confusing parse error later on. Instead we use '\0' which+ -- will signal a lexer error immediately.++utf8DecodeChar :: Ptr Word8 -> (Char, Int)+utf8DecodeChar (Ptr a#) =+ case utf8DecodeChar# a# of (# c#, nBytes# #) -> ( C# c#, I# nBytes# )++-- UTF-8 is cleverly designed so that we can always figure out where+-- the start of the current character is, given any position in a+-- stream. This function finds the start of the previous character,+-- assuming there *is* a previous character.+utf8PrevChar :: Ptr Word8 -> IO (Ptr Word8)+utf8PrevChar p = utf8CharStart (p `plusPtr` (-1))++utf8CharStart :: Ptr Word8 -> IO (Ptr Word8)+utf8CharStart p = go p+ where go p = do w <- peek p+ if w >= 0x80 && w < 0xC0+ then go (p `plusPtr` (-1))+ else return p++utf8DecodeByteString :: ByteString -> [Char]+utf8DecodeByteString (BS.PS ptr offset len)+ = utf8DecodeStringLazy ptr offset len++utf8DecodeStringLazy :: ForeignPtr Word8 -> Int -> Int -> [Char]+utf8DecodeStringLazy fptr offset len+ = unsafeDupablePerformIO $ unpack start+ where+ !start = unsafeForeignPtrToPtr fptr `plusPtr` offset+ !end = start `plusPtr` len++ unpack p+ | p >= end = touchForeignPtr fptr >> return []+ | otherwise =+ case utf8DecodeChar# (unPtr p) of+ (# c#, nBytes# #) -> do+ rest <- unsafeDupableInterleaveIO $ unpack (p `plusPtr#` nBytes#)+ return (C# c# : rest)++countUTF8Chars :: Ptr Word8 -> Int -> IO Int+countUTF8Chars ptr len = go ptr 0+ where+ !end = ptr `plusPtr` len++ go p !n+ | p >= end = return n+ | otherwise = do+ case utf8DecodeChar# (unPtr p) of+ (# _, nBytes# #) -> go (p `plusPtr#` nBytes#) (n+1)++unPtr :: Ptr a -> Addr#+unPtr (Ptr a) = a++plusPtr# :: Ptr a -> Int# -> Ptr a+plusPtr# ptr nBytes# = ptr `plusPtr` (I# nBytes#)++utf8EncodeChar :: Char -> Ptr Word8 -> IO (Ptr Word8)+utf8EncodeChar c ptr =+ let x = ord c in+ case () of+ _ | x > 0 && x <= 0x007f -> do+ poke ptr (fromIntegral x)+ return (ptr `plusPtr` 1)+ -- NB. '\0' is encoded as '\xC0\x80', not '\0'. This is so that we+ -- can have 0-terminated UTF-8 strings (see GHC.Base.unpackCStringUtf8).+ | x <= 0x07ff -> do+ poke ptr (fromIntegral (0xC0 .|. ((x `shiftR` 6) .&. 0x1F)))+ pokeElemOff ptr 1 (fromIntegral (0x80 .|. (x .&. 0x3F)))+ return (ptr `plusPtr` 2)+ | x <= 0xffff -> do+ poke ptr (fromIntegral (0xE0 .|. (x `shiftR` 12) .&. 0x0F))+ pokeElemOff ptr 1 (fromIntegral (0x80 .|. (x `shiftR` 6) .&. 0x3F))+ pokeElemOff ptr 2 (fromIntegral (0x80 .|. (x .&. 0x3F)))+ return (ptr `plusPtr` 3)+ | otherwise -> do+ poke ptr (fromIntegral (0xF0 .|. (x `shiftR` 18)))+ pokeElemOff ptr 1 (fromIntegral (0x80 .|. ((x `shiftR` 12) .&. 0x3F)))+ pokeElemOff ptr 2 (fromIntegral (0x80 .|. ((x `shiftR` 6) .&. 0x3F)))+ pokeElemOff ptr 3 (fromIntegral (0x80 .|. (x .&. 0x3F)))+ return (ptr `plusPtr` 4)++utf8EncodeString :: Ptr Word8 -> String -> IO ()+utf8EncodeString ptr str = go ptr str+ where go !_ [] = return ()+ go ptr (c:cs) = do+ ptr' <- utf8EncodeChar c ptr+ go ptr' cs++utf8EncodedLength :: String -> Int+utf8EncodedLength str = go 0 str+ where go !n [] = n+ go n (c:cs)+ | ord c > 0 && ord c <= 0x007f = go (n+1) cs+ | ord c <= 0x07ff = go (n+2) cs+ | ord c <= 0xffff = go (n+3) cs+ | otherwise = go (n+4) cs++-- -----------------------------------------------------------------------------+-- The Z-encoding++{-+This is the main name-encoding and decoding function. It encodes any+string into a string that is acceptable as a C name. This is done+right before we emit a symbol name into the compiled C or asm code.+Z-encoding of strings is cached in the FastString interface, so we+never encode the same string more than once.++The basic encoding scheme is this.++* Tuples (,,,) are coded as Z3T++* Alphabetic characters (upper and lower) and digits+ all translate to themselves;+ except 'Z', which translates to 'ZZ'+ and 'z', which translates to 'zz'+ We need both so that we can preserve the variable/tycon distinction++* Most other printable characters translate to 'zx' or 'Zx' for some+ alphabetic character x++* The others translate as 'znnnU' where 'nnn' is the decimal number+ of the character++ Before After+ --------------------------+ Trak Trak+ foo_wib foozuwib+ > zg+ >1 zg1+ foo# foozh+ foo## foozhzh+ foo##1 foozhzh1+ fooZ fooZZ+ :+ ZCzp+ () Z0T 0-tuple+ (,,,,) Z5T 5-tuple+ (# #) Z1H unboxed 1-tuple (note the space)+ (#,,,,#) Z5H unboxed 5-tuple+ (NB: There is no Z1T nor Z0H.)+-}++type UserString = String -- As the user typed it+type EncodedString = String -- Encoded form+++zEncodeString :: UserString -> EncodedString+zEncodeString cs = case maybe_tuple cs of+ Just n -> n -- Tuples go to Z2T etc+ Nothing -> go cs+ where+ go [] = []+ go (c:cs) = encode_digit_ch c ++ go' cs+ go' [] = []+ go' (c:cs) = encode_ch c ++ go' cs++unencodedChar :: Char -> Bool -- True for chars that don't need encoding+unencodedChar 'Z' = False+unencodedChar 'z' = False+unencodedChar c = c >= 'a' && c <= 'z'+ || c >= 'A' && c <= 'Z'+ || c >= '0' && c <= '9'++-- If a digit is at the start of a symbol then we need to encode it.+-- Otherwise package names like 9pH-0.1 give linker errors.+encode_digit_ch :: Char -> EncodedString+encode_digit_ch c | c >= '0' && c <= '9' = encode_as_unicode_char c+encode_digit_ch c | otherwise = encode_ch c++encode_ch :: Char -> EncodedString+encode_ch c | unencodedChar c = [c] -- Common case first++-- Constructors+encode_ch '(' = "ZL" -- Needed for things like (,), and (->)+encode_ch ')' = "ZR" -- For symmetry with (+encode_ch '[' = "ZM"+encode_ch ']' = "ZN"+encode_ch ':' = "ZC"+encode_ch 'Z' = "ZZ"++-- Variables+encode_ch 'z' = "zz"+encode_ch '&' = "za"+encode_ch '|' = "zb"+encode_ch '^' = "zc"+encode_ch '$' = "zd"+encode_ch '=' = "ze"+encode_ch '>' = "zg"+encode_ch '#' = "zh"+encode_ch '.' = "zi"+encode_ch '<' = "zl"+encode_ch '-' = "zm"+encode_ch '!' = "zn"+encode_ch '+' = "zp"+encode_ch '\'' = "zq"+encode_ch '\\' = "zr"+encode_ch '/' = "zs"+encode_ch '*' = "zt"+encode_ch '_' = "zu"+encode_ch '%' = "zv"+encode_ch c = encode_as_unicode_char c++encode_as_unicode_char :: Char -> EncodedString+encode_as_unicode_char c = 'z' : if isDigit (head hex_str) then hex_str+ else '0':hex_str+ where hex_str = showHex (ord c) "U"+ -- ToDo: we could improve the encoding here in various ways.+ -- eg. strings of unicode characters come out as 'z1234Uz5678U', we+ -- could remove the 'U' in the middle (the 'z' works as a separator).++zDecodeString :: EncodedString -> UserString+zDecodeString [] = []+zDecodeString ('Z' : d : rest)+ | isDigit d = decode_tuple d rest+ | otherwise = decode_upper d : zDecodeString rest+zDecodeString ('z' : d : rest)+ | isDigit d = decode_num_esc d rest+ | otherwise = decode_lower d : zDecodeString rest+zDecodeString (c : rest) = c : zDecodeString rest++decode_upper, decode_lower :: Char -> Char++decode_upper 'L' = '('+decode_upper 'R' = ')'+decode_upper 'M' = '['+decode_upper 'N' = ']'+decode_upper 'C' = ':'+decode_upper 'Z' = 'Z'+decode_upper ch = {-pprTrace "decode_upper" (char ch)-} ch++decode_lower 'z' = 'z'+decode_lower 'a' = '&'+decode_lower 'b' = '|'+decode_lower 'c' = '^'+decode_lower 'd' = '$'+decode_lower 'e' = '='+decode_lower 'g' = '>'+decode_lower 'h' = '#'+decode_lower 'i' = '.'+decode_lower 'l' = '<'+decode_lower 'm' = '-'+decode_lower 'n' = '!'+decode_lower 'p' = '+'+decode_lower 'q' = '\''+decode_lower 'r' = '\\'+decode_lower 's' = '/'+decode_lower 't' = '*'+decode_lower 'u' = '_'+decode_lower 'v' = '%'+decode_lower ch = {-pprTrace "decode_lower" (char ch)-} ch++-- Characters not having a specific code are coded as z224U (in hex)+decode_num_esc :: Char -> EncodedString -> UserString+decode_num_esc d rest+ = go (digitToInt d) rest+ where+ go n (c : rest) | isHexDigit c = go (16*n + digitToInt c) rest+ go n ('U' : rest) = chr n : zDecodeString rest+ go n other = error ("decode_num_esc: " ++ show n ++ ' ':other)++decode_tuple :: Char -> EncodedString -> UserString+decode_tuple d rest+ = go (digitToInt d) rest+ where+ -- NB. recurse back to zDecodeString after decoding the tuple, because+ -- the tuple might be embedded in a longer name.+ go n (c : rest) | isDigit c = go (10*n + digitToInt c) rest+ go 0 ('T':rest) = "()" ++ zDecodeString rest+ go n ('T':rest) = '(' : replicate (n-1) ',' ++ ")" ++ zDecodeString rest+ go 1 ('H':rest) = "(# #)" ++ zDecodeString rest+ go n ('H':rest) = '(' : '#' : replicate (n-1) ',' ++ "#)" ++ zDecodeString rest+ go n other = error ("decode_tuple: " ++ show n ++ ' ':other)++{-+Tuples are encoded as+ Z3T or Z3H+for 3-tuples or unboxed 3-tuples respectively. No other encoding starts+ Z<digit>++* "(# #)" is the tycon for an unboxed 1-tuple (not 0-tuple)+ There are no unboxed 0-tuples.++* "()" is the tycon for a boxed 0-tuple.+ There are no boxed 1-tuples.+-}++maybe_tuple :: UserString -> Maybe EncodedString++maybe_tuple "(# #)" = Just("Z1H")+maybe_tuple ('(' : '#' : cs) = case count_commas (0::Int) cs of+ (n, '#' : ')' : _) -> Just ('Z' : shows (n+1) "H")+ _ -> Nothing+maybe_tuple "()" = Just("Z0T")+maybe_tuple ('(' : cs) = case count_commas (0::Int) cs of+ (n, ')' : _) -> Just ('Z' : shows (n+1) "T")+ _ -> Nothing+maybe_tuple _ = Nothing++count_commas :: Int -> String -> (Int, String)+count_commas n (',' : cs) = count_commas (n+1) cs+count_commas n cs = (n,cs)+++{-+************************************************************************+* *+ Base 62+* *+************************************************************************++Note [Base 62 encoding 128-bit integers]+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+Instead of base-62 encoding a single 128-bit integer+(ceil(21.49) characters), we'll base-62 a pair of 64-bit integers+(2 * ceil(10.75) characters). Luckily for us, it's the same number of+characters!+-}++--------------------------------------------------------------------------+-- Base 62++-- The base-62 code is based off of 'locators'+-- ((c) Operational Dynamics Consulting, BSD3 licensed)++-- | Size of a 64-bit word when written as a base-62 string+word64Base62Len :: Int+word64Base62Len = 11++-- | Converts a 64-bit word into a base-62 string+toBase62Padded :: Word64 -> String+toBase62Padded w = pad ++ str+ where+ pad = replicate len '0'+ len = word64Base62Len - length str -- 11 == ceil(64 / lg 62)+ str = toBase62 w++toBase62 :: Word64 -> String+toBase62 w = showIntAtBase 62 represent w ""+ where+ represent :: Int -> Char+ represent x+ | x < 10 = Char.chr (48 + x)+ | x < 36 = Char.chr (65 + x - 10)+ | x < 62 = Char.chr (97 + x - 36)+ | otherwise = error "represent (base 62): impossible!"
+ utils/Exception.hs view
@@ -0,0 +1,81 @@+{-# OPTIONS_GHC -fno-warn-deprecations #-}+module Exception+ (+ module Control.Exception,+ module Exception+ )+ where++import Control.Exception+import Control.Monad.IO.Class++catchIO :: IO a -> (IOException -> IO a) -> IO a+catchIO = Control.Exception.catch++handleIO :: (IOException -> IO a) -> IO a -> IO a+handleIO = flip catchIO++tryIO :: IO a -> IO (Either IOException a)+tryIO = try++-- | A monad that can catch exceptions. A minimal definition+-- requires a definition of 'gcatch'.+--+-- Implementations on top of 'IO' should implement 'gmask' to+-- eventually call the primitive 'Control.Exception.mask'.+-- These are used for+-- implementations that support asynchronous exceptions. The default+-- implementations of 'gbracket' and 'gfinally' use 'gmask'+-- thus rarely require overriding.+--+class MonadIO m => ExceptionMonad m where++ -- | Generalised version of 'Control.Exception.catch', allowing an arbitrary+ -- exception handling monad instead of just 'IO'.+ gcatch :: Exception e => m a -> (e -> m a) -> m a++ -- | Generalised version of 'Control.Exception.mask_', allowing an arbitrary+ -- exception handling monad instead of just 'IO'.+ gmask :: ((m a -> m a) -> m b) -> m b++ -- | Generalised version of 'Control.Exception.bracket', allowing an arbitrary+ -- exception handling monad instead of just 'IO'.+ gbracket :: m a -> (a -> m b) -> (a -> m c) -> m c++ -- | Generalised version of 'Control.Exception.finally', allowing an arbitrary+ -- exception handling monad instead of just 'IO'.+ gfinally :: m a -> m b -> m a++ gbracket before after thing =+ gmask $ \restore -> do+ a <- before+ r <- restore (thing a) `gonException` after a+ _ <- after a+ return r++ a `gfinally` sequel =+ gmask $ \restore -> do+ r <- restore a `gonException` sequel+ _ <- sequel+ return r++instance ExceptionMonad IO where+ gcatch = Control.Exception.catch+ gmask f = mask (\x -> f x)++gtry :: (ExceptionMonad m, Exception e) => m a -> m (Either e a)+gtry act = gcatch (act >>= \a -> return (Right a))+ (\e -> return (Left e))++-- | Generalised version of 'Control.Exception.handle', allowing an arbitrary+-- exception handling monad instead of just 'IO'.+ghandle :: (ExceptionMonad m, Exception e) => (e -> m a) -> m a -> m a+ghandle = flip gcatch++-- | Always executes the first argument. If this throws an exception the+-- second argument is executed and the exception is raised again.+gonException :: (ExceptionMonad m) => m a -> m b -> m a+gonException ioA cleanup = ioA `gcatch` \e ->+ do _ <- cleanup+ liftIO $ throwIO (e :: SomeException)+
+ utils/FV.hs view
@@ -0,0 +1,199 @@+{-+(c) Bartosz Nitka, Facebook 2015++Utilities for efficiently and deterministically computing free variables.++-}++{-# LANGUAGE BangPatterns #-}++module FV (+ -- * Deterministic free vars computations+ FV, InterestingVarFun,++ -- * Running the computations+ fvVarListVarSet, fvVarList, fvVarSet, fvDVarSet,++ -- ** Manipulating those computations+ unitFV,+ emptyFV,+ mkFVs,+ unionFV,+ unionsFV,+ delFV,+ delFVs,+ filterFV,+ mapUnionFV,+ ) where++import Var+import VarSet++-- | Predicate on possible free variables: returns @True@ iff the variable is+-- interesting+type InterestingVarFun = Var -> Bool++-- Note [Deterministic FV]+-- ~~~~~~~~~~~~~~~~~~~~~~~+-- When computing free variables, the order in which you get them affects+-- the results of floating and specialization. If you use UniqFM to collect+-- them and then turn that into a list, you get them in nondeterministic+-- order as described in Note [Deterministic UniqFM] in UniqDFM.++-- A naive algorithm for free variables relies on merging sets of variables.+-- Merging costs O(n+m) for UniqFM and for UniqDFM there's an additional log+-- factor. It's cheaper to incrementally add to a list and use a set to check+-- for duplicates.+type FV = InterestingVarFun+ -- Used for filtering sets as we build them+ -> VarSet+ -- Locally bound variables+ -> ([Var], VarSet)+ -- List to preserve ordering and set to check for membership,+ -- so that the list doesn't have duplicates+ -- For explanation of why using `VarSet` is not deterministic see+ -- Note [Deterministic UniqFM] in UniqDFM.+ -> ([Var], VarSet)++-- Note [FV naming conventions]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- To get the performance and determinism that FV provides, FV computations+-- need to built up from smaller FV computations and then evaluated with+-- one of `fvVarList`, `fvDVarSet`, `fvVarListVarSet`. That means the functions+-- returning FV need to be exported.+--+-- The conventions are:+--+-- a) non-deterministic functions:+-- * a function that returns VarSet+-- e.g. `tyVarsOfType`+-- b) deterministic functions:+-- * a worker that returns FV+-- e.g. `tyFVsOfType`+-- * a function that returns [Var]+-- e.g. `tyVarsOfTypeList`+-- * a function that returns DVarSet+-- e.g. `tyVarsOfTypeDSet`+--+-- Where tyVarsOfType, tyVarsOfTypeList, tyVarsOfTypeDSet are implemented+-- in terms of the worker evaluated with fvVarSet, fvVarList, fvDVarSet+-- respectively.++-- | Run a free variable computation, returning a list of distinct free+-- variables in deterministic order and a non-deterministic set containing+-- those variables.+fvVarListVarSet :: FV -> ([Var], VarSet)+fvVarListVarSet fv = fv (const True) emptyVarSet ([], emptyVarSet)++-- | Run a free variable computation, returning a list of distinct free+-- variables in deterministic order.+fvVarList :: FV -> [Var]+fvVarList = fst . fvVarListVarSet++-- | Run a free variable computation, returning a deterministic set of free+-- variables. Note that this is just a wrapper around the version that+-- returns a deterministic list. If you need a list you should use+-- `fvVarList`.+fvDVarSet :: FV -> DVarSet+fvDVarSet = mkDVarSet . fst . fvVarListVarSet++-- | Run a free variable computation, returning a non-deterministic set of+-- free variables. Don't use if the set will be later converted to a list+-- and the order of that list will impact the generated code.+fvVarSet :: FV -> VarSet+fvVarSet = snd . fvVarListVarSet++-- Note [FV eta expansion]+-- ~~~~~~~~~~~~~~~~~~~~~~~+-- Let's consider an eta-reduced implementation of freeVarsOf using FV:+--+-- freeVarsOf (App a b) = freeVarsOf a `unionFV` freeVarsOf b+--+-- If GHC doesn't eta-expand it, after inlining unionFV we end up with+--+-- freeVarsOf = \x ->+-- case x of+-- App a b -> \fv_cand in_scope acc ->+-- freeVarsOf a fv_cand in_scope $! freeVarsOf b fv_cand in_scope $! acc+--+-- which has to create a thunk, resulting in more allocations.+--+-- On the other hand if it is eta-expanded:+--+-- freeVarsOf (App a b) fv_cand in_scope acc =+-- (freeVarsOf a `unionFV` freeVarsOf b) fv_cand in_scope acc+--+-- after inlining unionFV we have:+--+-- freeVarsOf = \x fv_cand in_scope acc ->+-- case x of+-- App a b ->+-- freeVarsOf a fv_cand in_scope $! freeVarsOf b fv_cand in_scope $! acc+--+-- which saves allocations.+--+-- GHC when presented with knowledge about all the call sites, correctly+-- eta-expands in this case. Unfortunately due to the fact that freeVarsOf gets+-- exported to be composed with other functions, GHC doesn't have that+-- information and has to be more conservative here.+--+-- Hence functions that get exported and return FV need to be manually+-- eta-expanded. See also #11146.++-- | Add a variable - when free, to the returned free variables.+-- Ignores duplicates and respects the filtering function.+unitFV :: Id -> FV+unitFV var fv_cand in_scope acc@(have, haveSet)+ | var `elemVarSet` in_scope = acc+ | var `elemVarSet` haveSet = acc+ | fv_cand var = (var:have, extendVarSet haveSet var)+ | otherwise = acc+{-# INLINE unitFV #-}++-- | Return no free variables.+emptyFV :: FV+emptyFV _ _ acc = acc+{-# INLINE emptyFV #-}++-- | Union two free variable computations.+unionFV :: FV -> FV -> FV+unionFV fv1 fv2 fv_cand in_scope acc =+ fv1 fv_cand in_scope $! fv2 fv_cand in_scope $! acc+{-# INLINE unionFV #-}++-- | Mark the variable as not free by putting it in scope.+delFV :: Var -> FV -> FV+delFV var fv fv_cand !in_scope acc =+ fv fv_cand (extendVarSet in_scope var) acc+{-# INLINE delFV #-}++-- | Mark many free variables as not free.+delFVs :: VarSet -> FV -> FV+delFVs vars fv fv_cand !in_scope acc =+ fv fv_cand (in_scope `unionVarSet` vars) acc+{-# INLINE delFVs #-}++-- | Filter a free variable computation.+filterFV :: InterestingVarFun -> FV -> FV+filterFV fv_cand2 fv fv_cand1 in_scope acc =+ fv (\v -> fv_cand1 v && fv_cand2 v) in_scope acc+{-# INLINE filterFV #-}++-- | Map a free variable computation over a list and union the results.+mapUnionFV :: (a -> FV) -> [a] -> FV+mapUnionFV _f [] _fv_cand _in_scope acc = acc+mapUnionFV f (a:as) fv_cand in_scope acc =+ mapUnionFV f as fv_cand in_scope $! f a fv_cand in_scope $! acc+{-# INLINABLE mapUnionFV #-}++-- | Union many free variable computations.+unionsFV :: [FV] -> FV+unionsFV fvs fv_cand in_scope acc = mapUnionFV id fvs fv_cand in_scope acc+{-# INLINE unionsFV #-}++-- | Add multiple variables - when free, to the returned free variables.+-- Ignores duplicates and respects the filtering function.+mkFVs :: [Var] -> FV+mkFVs vars fv_cand in_scope acc =+ mapUnionFV unitFV vars fv_cand in_scope acc+{-# INLINE mkFVs #-}
+ utils/FastFunctions.hs view
@@ -0,0 +1,19 @@+{-+(c) The University of Glasgow, 2000-2006+-}++{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}++module FastFunctions (+ inlinePerformIO,+ ) where++#include "HsVersions.h"++import GHC.Exts+import GHC.IO (IO(..))++-- Just like unsafePerformIO, but we inline it.+{-# INLINE inlinePerformIO #-}+inlinePerformIO :: IO a -> a+inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
+ utils/FastMutInt.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}+{-# OPTIONS_GHC -O #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected+--+-- (c) The University of Glasgow 2002-2006+--+-- Unboxed mutable Ints++module FastMutInt(+ FastMutInt, newFastMutInt,+ readFastMutInt, writeFastMutInt,++ FastMutPtr, newFastMutPtr,+ readFastMutPtr, writeFastMutPtr+ ) where++import Data.Bits+import GHC.Base+import GHC.Ptr++newFastMutInt :: IO FastMutInt+readFastMutInt :: FastMutInt -> IO Int+writeFastMutInt :: FastMutInt -> Int -> IO ()++newFastMutPtr :: IO FastMutPtr+readFastMutPtr :: FastMutPtr -> IO (Ptr a)+writeFastMutPtr :: FastMutPtr -> Ptr a -> IO ()++data FastMutInt = FastMutInt (MutableByteArray# RealWorld)++newFastMutInt = IO $ \s ->+ case newByteArray# size s of { (# s, arr #) ->+ (# s, FastMutInt arr #) }+ where !(I# size) = finiteBitSize (0 :: Int)++readFastMutInt (FastMutInt arr) = IO $ \s ->+ case readIntArray# arr 0# s of { (# s, i #) ->+ (# s, I# i #) }++writeFastMutInt (FastMutInt arr) (I# i) = IO $ \s ->+ case writeIntArray# arr 0# i s of { s ->+ (# s, () #) }++data FastMutPtr = FastMutPtr (MutableByteArray# RealWorld)++newFastMutPtr = IO $ \s ->+ case newByteArray# size s of { (# s, arr #) ->+ (# s, FastMutPtr arr #) }+ -- GHC assumes 'sizeof (Int) == sizeof (Ptr a)'+ where !(I# size) = finiteBitSize (0 :: Int)++readFastMutPtr (FastMutPtr arr) = IO $ \s ->+ case readAddrArray# arr 0# s of { (# s, i #) ->+ (# s, Ptr i #) }++writeFastMutPtr (FastMutPtr arr) (Ptr i) = IO $ \s ->+ case writeAddrArray# arr 0# i s of { s ->+ (# s, () #) }
+ utils/FastString.hs view
@@ -0,0 +1,620 @@+-- (c) The University of Glasgow, 1997-2006++{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples,+ GeneralizedNewtypeDeriving #-}+{-# OPTIONS_GHC -O -funbox-strict-fields #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected++-- |+-- There are two principal string types used internally by GHC:+--+-- ['FastString']+--+-- * A compact, hash-consed, representation of character strings.+-- * Comparison is O(1), and you can get a 'Unique.Unique' from them.+-- * Generated by 'fsLit'.+-- * Turn into 'Outputable.SDoc' with 'Outputable.ftext'.+--+-- ['LitString']+--+-- * Just a wrapper for the @Addr#@ of a C string (@Ptr CChar@).+-- * Practically no operations.+-- * Outputing them is fast.+-- * Generated by 'sLit'.+-- * Turn into 'Outputable.SDoc' with 'Outputable.ptext'+-- * Requires manual memory management.+-- Improper use may lead to memory leaks or dangling pointers.+-- * It assumes Latin-1 as the encoding, therefore it cannot represent+-- arbitrary Unicode strings.+--+-- Use 'LitString' unless you want the facilities of 'FastString'.+module FastString+ (+ -- * ByteString+ fastStringToByteString,+ mkFastStringByteString,+ fastZStringToByteString,+ unsafeMkByteString,+ hashByteString,++ -- * FastZString+ FastZString,+ hPutFZS,+ zString,+ lengthFZS,++ -- * FastStrings+ FastString(..), -- not abstract, for now.++ -- ** Construction+ fsLit,+ mkFastString,+ mkFastStringBytes,+ mkFastStringByteList,+ mkFastStringForeignPtr,+ mkFastString#,++ -- ** Deconstruction+ unpackFS, -- :: FastString -> String+ bytesFS, -- :: FastString -> [Word8]++ -- ** Encoding+ zEncodeFS,++ -- ** Operations+ uniqueOfFS,+ lengthFS,+ nullFS,+ appendFS,+ headFS,+ tailFS,+ concatFS,+ consFS,+ nilFS,++ -- ** Outputing+ hPutFS,++ -- ** Internal+ getFastStringTable,+ hasZEncoding,++ -- * LitStrings+ LitString,++ -- ** Construction+ sLit,+ mkLitString#,+ mkLitString,++ -- ** Deconstruction+ unpackLitString,++ -- ** Operations+ lengthLS+ ) where++#include "HsVersions.h"++import Encoding+import FastFunctions+import Panic+import Util++import Control.DeepSeq+import Control.Monad+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Char8 as BSC+import qualified Data.ByteString.Internal as BS+import qualified Data.ByteString.Unsafe as BS+import Foreign.C+import GHC.Exts+import System.IO+import System.IO.Unsafe ( unsafePerformIO )+import Data.Data+import Data.IORef ( IORef, newIORef, readIORef, atomicModifyIORef' )+import Data.Maybe ( isJust )+import Data.Char+import Data.List ( elemIndex )++import GHC.IO ( IO(..), unsafeDupablePerformIO )++import Foreign++#if STAGE >= 2+import GHC.Conc.Sync (sharedCAF)+#endif++import GHC.Base ( unpackCString# )++#define hASH_TBL_SIZE 4091+#define hASH_TBL_SIZE_UNBOXED 4091#+++fastStringToByteString :: FastString -> ByteString+fastStringToByteString f = fs_bs f++fastZStringToByteString :: FastZString -> ByteString+fastZStringToByteString (FastZString bs) = bs++-- This will drop information if any character > '\xFF'+unsafeMkByteString :: String -> ByteString+unsafeMkByteString = BSC.pack++hashByteString :: ByteString -> Int+hashByteString bs+ = inlinePerformIO $ BS.unsafeUseAsCStringLen bs $ \(ptr, len) ->+ return $ hashStr (castPtr ptr) len++-- -----------------------------------------------------------------------------++newtype FastZString = FastZString ByteString+ deriving NFData++hPutFZS :: Handle -> FastZString -> IO ()+hPutFZS handle (FastZString bs) = BS.hPut handle bs++zString :: FastZString -> String+zString (FastZString bs) =+ inlinePerformIO $ BS.unsafeUseAsCStringLen bs peekCAStringLen++lengthFZS :: FastZString -> Int+lengthFZS (FastZString bs) = BS.length bs++mkFastZStringString :: String -> FastZString+mkFastZStringString str = FastZString (BSC.pack str)++-- -----------------------------------------------------------------------------++{-|+A 'FastString' is an array of bytes, hashed to support fast O(1)+comparison. It is also associated with a character encoding, so that+we know how to convert a 'FastString' to the local encoding, or to the+Z-encoding used by the compiler internally.++'FastString's support a memoized conversion to the Z-encoding via zEncodeFS.+-}++data FastString = FastString {+ uniq :: {-# UNPACK #-} !Int, -- unique id+ n_chars :: {-# UNPACK #-} !Int, -- number of chars+ fs_bs :: {-# UNPACK #-} !ByteString,+ fs_ref :: {-# UNPACK #-} !(IORef (Maybe FastZString))+ }++instance Eq FastString where+ f1 == f2 = uniq f1 == uniq f2++instance Ord FastString where+ -- Compares lexicographically, not by unique+ a <= b = case cmpFS a b of { LT -> True; EQ -> True; GT -> False }+ a < b = case cmpFS a b of { LT -> True; EQ -> False; GT -> False }+ a >= b = case cmpFS a b of { LT -> False; EQ -> True; GT -> True }+ a > b = case cmpFS a b of { LT -> False; EQ -> False; GT -> True }+ max x y | x >= y = x+ | otherwise = y+ min x y | x <= y = x+ | otherwise = y+ compare a b = cmpFS a b++instance IsString FastString where+ fromString = fsLit++instance Monoid FastString where+ mempty = nilFS+ mappend = appendFS+ mconcat = concatFS++instance Show FastString where+ show fs = show (unpackFS fs)++instance Data FastString where+ -- don't traverse?+ toConstr _ = abstractConstr "FastString"+ gunfold _ _ = error "gunfold"+ dataTypeOf _ = mkNoRepType "FastString"++cmpFS :: FastString -> FastString -> Ordering+cmpFS f1@(FastString u1 _ _ _) f2@(FastString u2 _ _ _) =+ if u1 == u2 then EQ else+ compare (fastStringToByteString f1) (fastStringToByteString f2)++foreign import ccall unsafe "ghc_memcmp"+ memcmp :: Ptr a -> Ptr b -> Int -> IO Int++-- -----------------------------------------------------------------------------+-- Construction++{-+Internally, the compiler will maintain a fast string symbol table, providing+sharing and fast comparison. Creation of new @FastString@s then covertly does a+lookup, re-using the @FastString@ if there was a hit.++The design of the FastString hash table allows for lockless concurrent reads+and updates to multiple buckets with low synchronization overhead.++See Note [Updating the FastString table] on how it's updated.+-}+data FastStringTable =+ FastStringTable+ {-# UNPACK #-} !(IORef Int) -- the unique ID counter shared with all buckets+ (MutableArray# RealWorld (IORef [FastString])) -- the array of mutable buckets++string_table :: FastStringTable+{-# NOINLINE string_table #-}+string_table = unsafePerformIO $ do+ uid <- newIORef 603979776 -- ord '$' * 0x01000000+ tab <- IO $ \s1# -> case newArray# hASH_TBL_SIZE_UNBOXED (panic "string_table") s1# of+ (# s2#, arr# #) ->+ (# s2#, FastStringTable uid arr# #)+ forM_ [0.. hASH_TBL_SIZE-1] $ \i -> do+ bucket <- newIORef []+ updTbl tab i bucket++ -- use the support wired into the RTS to share this CAF among all images of+ -- libHSghc+#if STAGE < 2+ return tab+#else+ sharedCAF tab getOrSetLibHSghcFastStringTable++-- from the RTS; thus we cannot use this mechanism when STAGE<2; the previous+-- RTS might not have this symbol+foreign import ccall unsafe "getOrSetLibHSghcFastStringTable"+ getOrSetLibHSghcFastStringTable :: Ptr a -> IO (Ptr a)+#endif++{-++We include the FastString table in the `sharedCAF` mechanism because we'd like+FastStrings created by a Core plugin to have the same uniques as corresponding+strings created by the host compiler itself. For example, this allows plugins+to lookup known names (eg `mkTcOcc "MySpecialType"`) in the GlobalRdrEnv or+even re-invoke the parser.++In particular, the following little sanity test was failing in a plugin+prototyping safe newtype-coercions: GHC.NT.Type.NT was imported, but could not+be looked up /by the plugin/.++ let rdrName = mkModuleName "GHC.NT.Type" `mkRdrQual` mkTcOcc "NT"+ putMsgS $ showSDoc dflags $ ppr $ lookupGRE_RdrName rdrName $ mg_rdr_env guts++`mkTcOcc` involves the lookup (or creation) of a FastString. Since the+plugin's FastString.string_table is empty, constructing the RdrName also+allocates new uniques for the FastStrings "GHC.NT.Type" and "NT". These+uniques are almost certainly unequal to the ones that the host compiler+originally assigned to those FastStrings. Thus the lookup fails since the+domain of the GlobalRdrEnv is affected by the RdrName's OccName's FastString's+unique.++Maintaining synchronization of the two instances of this global is rather+difficult because of the uses of `unsafePerformIO` in this module. Not+synchronizing them risks breaking the rather major invariant that two+FastStrings with the same unique have the same string. Thus we use the+lower-level `sharedCAF` mechanism that relies on Globals.c.++-}++lookupTbl :: FastStringTable -> Int -> IO (IORef [FastString])+lookupTbl (FastStringTable _ arr#) (I# i#) =+ IO $ \ s# -> readArray# arr# i# s#++updTbl :: FastStringTable -> Int -> IORef [FastString] -> IO ()+updTbl (FastStringTable _uid arr#) (I# i#) ls = do+ (IO $ \ s# -> case writeArray# arr# i# ls s# of { s2# -> (# s2#, () #) })++mkFastString# :: Addr# -> FastString+mkFastString# a# = mkFastStringBytes ptr (ptrStrLength ptr)+ where ptr = Ptr a#++{- Note [Updating the FastString table]++The procedure goes like this:++1. Read the relevant bucket and perform a look up of the string.+2. If it exists, return it.+3. Otherwise grab a unique ID, create a new FastString and atomically attempt+ to update the relevant bucket with this FastString:++ * Double check that the string is not in the bucket. Another thread may have+ inserted it while we were creating our string.+ * Return the existing FastString if it exists. The one we preemptively+ created will get GCed.+ * Otherwise, insert and return the string we created.+-}++{- Note [Double-checking the bucket]++It is not necessary to check the entire bucket the second time. We only have to+check the strings that are new to the bucket since the last time we read it.+-}++mkFastStringWith :: (Int -> IO FastString) -> Ptr Word8 -> Int -> IO FastString+mkFastStringWith mk_fs !ptr !len = do+ let hash = hashStr ptr len+ bucket <- lookupTbl string_table hash+ ls1 <- readIORef bucket+ res <- bucket_match ls1 len ptr+ case res of+ Just v -> return v+ Nothing -> do+ n <- get_uid+ new_fs <- mk_fs n++ atomicModifyIORef' bucket $ \ls2 ->+ -- Note [Double-checking the bucket]+ let delta_ls = case ls1 of+ [] -> ls2+ l:_ -> case l `elemIndex` ls2 of+ Nothing -> panic "mkFastStringWith"+ Just idx -> take idx ls2++ -- NB: Might as well use inlinePerformIO, since the call to+ -- bucket_match doesn't perform any IO that could be floated+ -- out of this closure or erroneously duplicated.+ in case inlinePerformIO (bucket_match delta_ls len ptr) of+ Nothing -> (new_fs:ls2, new_fs)+ Just fs -> (ls2,fs)+ where+ !(FastStringTable uid _arr) = string_table++ get_uid = atomicModifyIORef' uid $ \n -> (n+1,n)++mkFastStringBytes :: Ptr Word8 -> Int -> FastString+mkFastStringBytes !ptr !len =+ -- NB: Might as well use unsafeDupablePerformIO, since mkFastStringWith is+ -- idempotent.+ unsafeDupablePerformIO $+ mkFastStringWith (copyNewFastString ptr len) ptr len++-- | Create a 'FastString' from an existing 'ForeignPtr'; the difference+-- between this and 'mkFastStringBytes' is that we don't have to copy+-- the bytes if the string is new to the table.+mkFastStringForeignPtr :: Ptr Word8 -> ForeignPtr Word8 -> Int -> IO FastString+mkFastStringForeignPtr ptr !fp len+ = mkFastStringWith (mkNewFastString fp ptr len) ptr len++-- | Create a 'FastString' from an existing 'ForeignPtr'; the difference+-- between this and 'mkFastStringBytes' is that we don't have to copy+-- the bytes if the string is new to the table.+mkFastStringByteString :: ByteString -> FastString+mkFastStringByteString bs =+ inlinePerformIO $+ BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> do+ let ptr' = castPtr ptr+ mkFastStringWith (mkNewFastStringByteString bs ptr' len) ptr' len++-- | Creates a UTF-8 encoded 'FastString' from a 'String'+mkFastString :: String -> FastString+mkFastString str =+ inlinePerformIO $ do+ let l = utf8EncodedLength str+ buf <- mallocForeignPtrBytes l+ withForeignPtr buf $ \ptr -> do+ utf8EncodeString ptr str+ mkFastStringForeignPtr ptr buf l++-- | Creates a 'FastString' from a UTF-8 encoded @[Word8]@+mkFastStringByteList :: [Word8] -> FastString+mkFastStringByteList str =+ inlinePerformIO $ do+ let l = Prelude.length str+ buf <- mallocForeignPtrBytes l+ withForeignPtr buf $ \ptr -> do+ pokeArray (castPtr ptr) str+ mkFastStringForeignPtr ptr buf l++-- | Creates a Z-encoded 'FastString' from a 'String'+mkZFastString :: String -> FastZString+mkZFastString = mkFastZStringString++bucket_match :: [FastString] -> Int -> Ptr Word8 -> IO (Maybe FastString)+bucket_match [] _ _ = return Nothing+bucket_match (v@(FastString _ _ bs _):ls) len ptr+ | len == BS.length bs = do+ b <- BS.unsafeUseAsCString bs $ \buf ->+ cmpStringPrefix ptr (castPtr buf) len+ if b then return (Just v)+ else bucket_match ls len ptr+ | otherwise =+ bucket_match ls len ptr++mkNewFastString :: ForeignPtr Word8 -> Ptr Word8 -> Int -> Int+ -> IO FastString+mkNewFastString fp ptr len uid = do+ ref <- newIORef Nothing+ n_chars <- countUTF8Chars ptr len+ return (FastString uid n_chars (BS.fromForeignPtr fp 0 len) ref)++mkNewFastStringByteString :: ByteString -> Ptr Word8 -> Int -> Int+ -> IO FastString+mkNewFastStringByteString bs ptr len uid = do+ ref <- newIORef Nothing+ n_chars <- countUTF8Chars ptr len+ return (FastString uid n_chars bs ref)++copyNewFastString :: Ptr Word8 -> Int -> Int -> IO FastString+copyNewFastString ptr len uid = do+ fp <- copyBytesToForeignPtr ptr len+ ref <- newIORef Nothing+ n_chars <- countUTF8Chars ptr len+ return (FastString uid n_chars (BS.fromForeignPtr fp 0 len) ref)++copyBytesToForeignPtr :: Ptr Word8 -> Int -> IO (ForeignPtr Word8)+copyBytesToForeignPtr ptr len = do+ fp <- mallocForeignPtrBytes len+ withForeignPtr fp $ \ptr' -> copyBytes ptr' ptr len+ return fp++cmpStringPrefix :: Ptr Word8 -> Ptr Word8 -> Int -> IO Bool+cmpStringPrefix ptr1 ptr2 len =+ do r <- memcmp ptr1 ptr2 len+ return (r == 0)+++hashStr :: Ptr Word8 -> Int -> Int+ -- use the Addr to produce a hash value between 0 & m (inclusive)+hashStr (Ptr a#) (I# len#) = loop 0# 0#+ where+ loop h n | isTrue# (n ==# len#) = I# h+ | otherwise = loop h2 (n +# 1#)+ where !c = ord# (indexCharOffAddr# a# n)+ !h2 = (c +# (h *# 128#)) `remInt#`+ hASH_TBL_SIZE#++-- -----------------------------------------------------------------------------+-- Operations++-- | Returns the length of the 'FastString' in characters+lengthFS :: FastString -> Int+lengthFS f = n_chars f++-- | Returns @True@ if this 'FastString' is not Z-encoded but already has+-- a Z-encoding cached (used in producing stats).+hasZEncoding :: FastString -> Bool+hasZEncoding (FastString _ _ _ ref) =+ inlinePerformIO $ do+ m <- readIORef ref+ return (isJust m)++-- | Returns @True@ if the 'FastString' is empty+nullFS :: FastString -> Bool+nullFS f = BS.null (fs_bs f)++-- | Unpacks and decodes the FastString+unpackFS :: FastString -> String+unpackFS (FastString _ _ bs _) = utf8DecodeByteString bs++-- | Gives the UTF-8 encoded bytes corresponding to a 'FastString'+bytesFS :: FastString -> [Word8]+bytesFS fs = BS.unpack $ fastStringToByteString fs++-- | Returns a Z-encoded version of a 'FastString'. This might be the+-- original, if it was already Z-encoded. The first time this+-- function is applied to a particular 'FastString', the results are+-- memoized.+--+zEncodeFS :: FastString -> FastZString+zEncodeFS fs@(FastString _ _ _ ref) =+ inlinePerformIO $ do+ m <- readIORef ref+ case m of+ Just zfs -> return zfs+ Nothing -> do+ atomicModifyIORef' ref $ \m' -> case m' of+ Nothing -> let zfs = mkZFastString (zEncodeString (unpackFS fs))+ in (Just zfs, zfs)+ Just zfs -> (m', zfs)++appendFS :: FastString -> FastString -> FastString+appendFS fs1 fs2 = mkFastStringByteString+ $ BS.append (fastStringToByteString fs1)+ (fastStringToByteString fs2)++concatFS :: [FastString] -> FastString+concatFS = mkFastStringByteString . BS.concat . map fs_bs++headFS :: FastString -> Char+headFS (FastString _ 0 _ _) = panic "headFS: Empty FastString"+headFS (FastString _ _ bs _) =+ inlinePerformIO $ BS.unsafeUseAsCString bs $ \ptr ->+ return (fst (utf8DecodeChar (castPtr ptr)))++tailFS :: FastString -> FastString+tailFS (FastString _ 0 _ _) = panic "tailFS: Empty FastString"+tailFS (FastString _ _ bs _) =+ inlinePerformIO $ BS.unsafeUseAsCString bs $ \ptr ->+ do let (_, n) = utf8DecodeChar (castPtr ptr)+ return $! mkFastStringByteString (BS.drop n bs)++consFS :: Char -> FastString -> FastString+consFS c fs = mkFastString (c : unpackFS fs)++uniqueOfFS :: FastString -> Int+uniqueOfFS (FastString u _ _ _) = u++nilFS :: FastString+nilFS = mkFastString ""++-- -----------------------------------------------------------------------------+-- Stats++getFastStringTable :: IO [[FastString]]+getFastStringTable = do+ buckets <- forM [0.. hASH_TBL_SIZE-1] $ \idx -> do+ bucket <- lookupTbl string_table idx+ readIORef bucket+ return buckets++-- -----------------------------------------------------------------------------+-- Outputting 'FastString's++-- |Outputs a 'FastString' with /no decoding at all/, that is, you+-- get the actual bytes in the 'FastString' written to the 'Handle'.+hPutFS :: Handle -> FastString -> IO ()+hPutFS handle fs = BS.hPut handle $ fastStringToByteString fs++-- ToDo: we'll probably want an hPutFSLocal, or something, to output+-- in the current locale's encoding (for error messages and suchlike).++-- -----------------------------------------------------------------------------+-- LitStrings, here for convenience only.++-- | A 'LitString' is a pointer to some null-terminated array of bytes.+type LitString = Ptr Word8+--Why do we recalculate length every time it's requested?+--If it's commonly needed, we should perhaps have+--data LitString = LitString {-#UNPACK#-}!Addr# {-#UNPACK#-}!Int#++-- | Wrap an unboxed address into a 'LitString'.+mkLitString# :: Addr# -> LitString+mkLitString# a# = Ptr a#++-- | Encode a 'String' into a newly allocated 'LitString' using Latin-1+-- encoding. The original string must not contain non-Latin-1 characters+-- (above codepoint @0xff@).+{-# INLINE mkLitString #-}+mkLitString :: String -> LitString+mkLitString s =+ unsafePerformIO (do+ p <- mallocBytes (length s + 1)+ let+ loop :: Int -> String -> IO ()+ loop !n [] = pokeByteOff p n (0 :: Word8)+ loop n (c:cs) = do+ pokeByteOff p n (fromIntegral (ord c) :: Word8)+ loop (1+n) cs+ loop 0 s+ return p+ )++-- | Decode a 'LitString' back into a 'String' using Latin-1 encoding.+-- This does not free the memory associated with 'LitString'.+unpackLitString :: LitString -> String+unpackLitString (Ptr p) = unpackCString# p++-- | Compute the length of a 'LitString', which must necessarily be+-- null-terminated.+lengthLS :: LitString -> Int+lengthLS = ptrStrLength++-- -----------------------------------------------------------------------------+-- under the carpet++foreign import ccall unsafe "ghc_strlen"+ ptrStrLength :: Ptr Word8 -> Int++{-# NOINLINE sLit #-}+sLit :: String -> LitString+sLit x = mkLitString x++{-# NOINLINE fsLit #-}+fsLit :: String -> FastString+fsLit x = mkFastString x++{-# RULES "slit"+ forall x . sLit (unpackCString# x) = mkLitString# x #-}+{-# RULES "fslit"+ forall x . fsLit (unpackCString# x) = mkFastString# x #-}
+ utils/FastStringEnv.hs view
@@ -0,0 +1,98 @@+{-+%+% (c) The University of Glasgow 2006+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998+%+\section[FastStringEnv]{@FastStringEnv@: FastString environments}+-}++module FastStringEnv (+ -- * FastString environments (maps)+ FastStringEnv,++ -- ** Manipulating these environments+ mkFsEnv,+ emptyFsEnv, unitFsEnv,+ extendFsEnv_C, extendFsEnv_Acc, extendFsEnv,+ extendFsEnvList, extendFsEnvList_C,+ filterFsEnv,+ plusFsEnv, plusFsEnv_C, alterFsEnv,+ lookupFsEnv, lookupFsEnv_NF, delFromFsEnv, delListFromFsEnv,+ elemFsEnv, mapFsEnv,++ -- * Deterministic FastString environments (maps)+ DFastStringEnv,++ -- ** Manipulating these environments+ mkDFsEnv, emptyDFsEnv, dFsEnvElts, lookupDFsEnv+ ) where++import UniqFM+import UniqDFM+import Maybes+import FastString+++-- | A non-deterministic set of FastStrings.+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why it's not+-- deterministic and why it matters. Use DFastStringEnv if the set eventually+-- gets converted into a list or folded over in a way where the order+-- changes the generated code.+type FastStringEnv a = UniqFM a -- Domain is FastString++emptyFsEnv :: FastStringEnv a+mkFsEnv :: [(FastString,a)] -> FastStringEnv a+alterFsEnv :: (Maybe a-> Maybe a) -> FastStringEnv a -> FastString -> FastStringEnv a+extendFsEnv_C :: (a->a->a) -> FastStringEnv a -> FastString -> a -> FastStringEnv a+extendFsEnv_Acc :: (a->b->b) -> (a->b) -> FastStringEnv b -> FastString -> a -> FastStringEnv b+extendFsEnv :: FastStringEnv a -> FastString -> a -> FastStringEnv a+plusFsEnv :: FastStringEnv a -> FastStringEnv a -> FastStringEnv a+plusFsEnv_C :: (a->a->a) -> FastStringEnv a -> FastStringEnv a -> FastStringEnv a+extendFsEnvList :: FastStringEnv a -> [(FastString,a)] -> FastStringEnv a+extendFsEnvList_C :: (a->a->a) -> FastStringEnv a -> [(FastString,a)] -> FastStringEnv a+delFromFsEnv :: FastStringEnv a -> FastString -> FastStringEnv a+delListFromFsEnv :: FastStringEnv a -> [FastString] -> FastStringEnv a+elemFsEnv :: FastString -> FastStringEnv a -> Bool+unitFsEnv :: FastString -> a -> FastStringEnv a+lookupFsEnv :: FastStringEnv a -> FastString -> Maybe a+lookupFsEnv_NF :: FastStringEnv a -> FastString -> a+filterFsEnv :: (elt -> Bool) -> FastStringEnv elt -> FastStringEnv elt+mapFsEnv :: (elt1 -> elt2) -> FastStringEnv elt1 -> FastStringEnv elt2++emptyFsEnv = emptyUFM+unitFsEnv x y = unitUFM x y+extendFsEnv x y z = addToUFM x y z+extendFsEnvList x l = addListToUFM x l+lookupFsEnv x y = lookupUFM x y+alterFsEnv = alterUFM+mkFsEnv l = listToUFM l+elemFsEnv x y = elemUFM x y+plusFsEnv x y = plusUFM x y+plusFsEnv_C f x y = plusUFM_C f x y+extendFsEnv_C f x y z = addToUFM_C f x y z+mapFsEnv f x = mapUFM f x+extendFsEnv_Acc x y z a b = addToUFM_Acc x y z a b+extendFsEnvList_C x y z = addListToUFM_C x y z+delFromFsEnv x y = delFromUFM x y+delListFromFsEnv x y = delListFromUFM x y+filterFsEnv x y = filterUFM x y++lookupFsEnv_NF env n = expectJust "lookupFsEnv_NF" (lookupFsEnv env n)++-- Deterministic FastStringEnv+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why we need+-- DFastStringEnv.++type DFastStringEnv a = UniqDFM a -- Domain is FastString++emptyDFsEnv :: DFastStringEnv a+emptyDFsEnv = emptyUDFM++dFsEnvElts :: DFastStringEnv a -> [a]+dFsEnvElts = eltsUDFM++mkDFsEnv :: [(FastString,a)] -> DFastStringEnv a+mkDFsEnv l = listToUDFM l++lookupDFsEnv :: DFastStringEnv a -> FastString -> Maybe a+lookupDFsEnv = lookupUDFM
+ utils/Fingerprint.hsc view
@@ -0,0 +1,46 @@+{-# LANGUAGE CPP #-}++-- ----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 2006+--+-- Fingerprints for recompilation checking and ABI versioning.+--+-- http://ghc.haskell.org/trac/ghc/wiki/Commentary/Compiler/RecompilationAvoidance+--+-- ----------------------------------------------------------------------------++module Fingerprint (+ readHexFingerprint,+ fingerprintByteString,+ -- * Re-exported from GHC.Fingerprint+ Fingerprint(..), fingerprint0,+ fingerprintFingerprints,+ fingerprintData,+ fingerprintString,+ getFileHash+ ) where++#include "md5.h"+##include "HsVersions.h"++import Foreign+import GHC.IO+import Numeric ( readHex )++import qualified Data.ByteString as BS+import qualified Data.ByteString.Unsafe as BS++import GHC.Fingerprint++-- useful for parsing the output of 'md5sum', should we want to do that.+readHexFingerprint :: String -> Fingerprint+readHexFingerprint s = Fingerprint w1 w2+ where (s1,s2) = splitAt 16 s+ [(w1,"")] = readHex s1+ [(w2,"")] = readHex (take 16 s2)++-- this can move to GHC.Fingerprint in GHC 8.6+fingerprintByteString :: BS.ByteString -> Fingerprint+fingerprintByteString bs = unsafeDupablePerformIO $+ BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> fingerprintData (castPtr ptr) len
+ utils/FiniteMap.hs view
@@ -0,0 +1,29 @@+-- Some extra functions to extend Data.Map++module FiniteMap (+ insertList,+ insertListWith,+ deleteList,+ foldRight, foldRightWithKey+ ) where++import Data.Map (Map)+import qualified Data.Map as Map++insertList :: Ord key => [(key,elt)] -> Map key elt -> Map key elt+insertList xs m = foldl (\m (k, v) -> Map.insert k v m) m xs++insertListWith :: Ord key+ => (elt -> elt -> elt)+ -> [(key,elt)]+ -> Map key elt+ -> Map key elt+insertListWith f xs m0 = foldl (\m (k, v) -> Map.insertWith f k v m) m0 xs++deleteList :: Ord key => [key] -> Map key elt -> Map key elt+deleteList ks m = foldl (flip Map.delete) m ks++foldRight :: (elt -> a -> a) -> a -> Map key elt -> a+foldRight = Map.foldr+foldRightWithKey :: (key -> elt -> a -> a) -> a -> Map key elt -> a+foldRightWithKey = Map.foldrWithKey
+ utils/GraphBase.hs view
@@ -0,0 +1,105 @@++-- | Types for the general graph colorer.+module GraphBase (+ Triv,+ Graph (..),+ initGraph,+ graphMapModify,++ Node (..), newNode,+)+++where++import UniqSet+import UniqFM+++-- | A fn to check if a node is trivially colorable+-- For graphs who's color classes are disjoint then a node is 'trivially colorable'+-- when it has less neighbors and exclusions than available colors for that node.+--+-- For graph's who's color classes overlap, ie some colors alias other colors, then+-- this can be a bit more tricky. There is a general way to calculate this, but+-- it's likely be too slow for use in the code. The coloring algorithm takes+-- a canned function which can be optimised by the user to be specific to the+-- specific graph being colored.+--+-- for details, see "A Generalised Algorithm for Graph-Coloring Register Allocation"+-- Smith, Ramsey, Holloway - PLDI 2004.+--+type Triv k cls color+ = cls -- the class of the node we're trying to color.+ -> UniqSet k -- the node's neighbors.+ -> UniqSet color -- the node's exclusions.+ -> Bool+++-- | The Interference graph.+-- There used to be more fields, but they were turfed out in a previous revision.+-- maybe we'll want more later..+--+data Graph k cls color+ = Graph {+ -- | All active nodes in the graph.+ graphMap :: UniqFM (Node k cls color) }+++-- | An empty graph.+initGraph :: Graph k cls color+initGraph+ = Graph+ { graphMap = emptyUFM }+++-- | Modify the finite map holding the nodes in the graph.+graphMapModify+ :: (UniqFM (Node k cls color) -> UniqFM (Node k cls color))+ -> Graph k cls color -> Graph k cls color++graphMapModify f graph+ = graph { graphMap = f (graphMap graph) }++++-- | Graph nodes.+-- Represents a thing that can conflict with another thing.+-- For the register allocater the nodes represent registers.+--+data Node k cls color+ = Node {+ -- | A unique identifier for this node.+ nodeId :: k++ -- | The class of this node,+ -- determines the set of colors that can be used.+ , nodeClass :: cls++ -- | The color of this node, if any.+ , nodeColor :: Maybe color++ -- | Neighbors which must be colored differently to this node.+ , nodeConflicts :: UniqSet k++ -- | Colors that cannot be used by this node.+ , nodeExclusions :: UniqSet color++ -- | Colors that this node would prefer to be, in decending order.+ , nodePreference :: [color]++ -- | Neighbors that this node would like to be colored the same as.+ , nodeCoalesce :: UniqSet k }+++-- | An empty node.+newNode :: k -> cls -> Node k cls color+newNode k cls+ = Node+ { nodeId = k+ , nodeClass = cls+ , nodeColor = Nothing+ , nodeConflicts = emptyUniqSet+ , nodeExclusions = emptyUniqSet+ , nodePreference = []+ , nodeCoalesce = emptyUniqSet }
+ utils/GraphColor.hs view
@@ -0,0 +1,371 @@+-- | Graph Coloring.+-- This is a generic graph coloring library, abstracted over the type of+-- the node keys, nodes and colors.+--++module GraphColor (+ module GraphBase,+ module GraphOps,+ module GraphPpr,+ colorGraph+)++where++import GraphBase+import GraphOps+import GraphPpr++import Unique+import UniqFM+import UniqSet+import Outputable++import Data.Maybe+import Data.List+++-- | Try to color a graph with this set of colors.+-- Uses Chaitin's algorithm to color the graph.+-- The graph is scanned for nodes which are deamed 'trivially colorable'. These nodes+-- are pushed onto a stack and removed from the graph.+-- Once this process is complete the graph can be colored by removing nodes from+-- the stack (ie in reverse order) and assigning them colors different to their neighbors.+--+colorGraph+ :: ( Uniquable k, Uniquable cls, Uniquable color+ , Eq cls, Ord k+ , Outputable k, Outputable cls, Outputable color)+ => Bool -- ^ whether to do iterative coalescing+ -> Int -- ^ how many times we've tried to color this graph so far.+ -> UniqFM (UniqSet color) -- ^ map of (node class -> set of colors available for this class).+ -> Triv k cls color -- ^ fn to decide whether a node is trivially colorable.+ -> (Graph k cls color -> k) -- ^ fn to choose a node to potentially leave uncolored if nothing is trivially colorable.+ -> Graph k cls color -- ^ the graph to color.++ -> ( Graph k cls color -- the colored graph.+ , UniqSet k -- the set of nodes that we couldn't find a color for.+ , UniqFM k ) -- map of regs (r1 -> r2) that were coalesced+ -- r1 should be replaced by r2 in the source++colorGraph iterative spinCount colors triv spill graph0+ = let+ -- If we're not doing iterative coalescing then do an aggressive coalescing first time+ -- around and then conservative coalescing for subsequent passes.+ --+ -- Aggressive coalescing is a quick way to get rid of many reg-reg moves. However, if+ -- there is a lot of register pressure and we do it on every round then it can make the+ -- graph less colorable and prevent the algorithm from converging in a sensible number+ -- of cycles.+ --+ (graph_coalesced, kksCoalesce1)+ = if iterative+ then (graph0, [])+ else if spinCount == 0+ then coalesceGraph True triv graph0+ else coalesceGraph False triv graph0++ -- run the scanner to slurp out all the trivially colorable nodes+ -- (and do coalescing if iterative coalescing is enabled)+ (ksTriv, ksProblems, kksCoalesce2)+ = colorScan iterative triv spill graph_coalesced++ -- If iterative coalescing is enabled, the scanner will coalesce the graph as does its business.+ -- We need to apply all the coalescences found by the scanner to the original+ -- graph before doing assignColors.+ --+ -- Because we've got the whole, non-pruned graph here we turn on aggressive coalecing+ -- to force all the (conservative) coalescences found during scanning.+ --+ (graph_scan_coalesced, _)+ = mapAccumL (coalesceNodes True triv) graph_coalesced kksCoalesce2++ -- color the trivially colorable nodes+ -- during scanning, keys of triv nodes were added to the front of the list as they were found+ -- this colors them in the reverse order, as required by the algorithm.+ (graph_triv, ksNoTriv)+ = assignColors colors graph_scan_coalesced ksTriv++ -- try and color the problem nodes+ -- problem nodes are the ones that were left uncolored because they weren't triv.+ -- theres a change we can color them here anyway.+ (graph_prob, ksNoColor)+ = assignColors colors graph_triv ksProblems++ -- if the trivially colorable nodes didn't color then something is probably wrong+ -- with the provided triv function.+ --+ in if not $ null ksNoTriv+ then pprPanic "colorGraph: trivially colorable nodes didn't color!" -- empty+ ( empty+ $$ text "ksTriv = " <> ppr ksTriv+ $$ text "ksNoTriv = " <> ppr ksNoTriv+ $$ text "colors = " <> ppr colors+ $$ empty+ $$ dotGraph (\_ -> text "white") triv graph_triv)++ else ( graph_prob+ , mkUniqSet ksNoColor -- the nodes that didn't color (spills)+ , if iterative+ then (listToUFM kksCoalesce2)+ else (listToUFM kksCoalesce1))+++-- | Scan through the conflict graph separating out trivially colorable and+-- potentially uncolorable (problem) nodes.+--+-- Checking whether a node is trivially colorable or not is a resonably expensive operation,+-- so after a triv node is found and removed from the graph it's no good to return to the 'start'+-- of the graph and recheck a bunch of nodes that will probably still be non-trivially colorable.+--+-- To ward against this, during each pass through the graph we collect up a list of triv nodes+-- that were found, and only remove them once we've finished the pass. The more nodes we can delete+-- at once the more likely it is that nodes we've already checked will become trivially colorable+-- for the next pass.+--+-- TODO: add work lists to finding triv nodes is easier.+-- If we've just scanned the graph, and removed triv nodes, then the only+-- nodes that we need to rescan are the ones we've removed edges from.++colorScan+ :: ( Uniquable k, Uniquable cls, Uniquable color+ , Ord k, Eq cls+ , Outputable k, Outputable cls)+ => Bool -- ^ whether to do iterative coalescing+ -> Triv k cls color -- ^ fn to decide whether a node is trivially colorable+ -> (Graph k cls color -> k) -- ^ fn to choose a node to potentially leave uncolored if nothing is trivially colorable.+ -> Graph k cls color -- ^ the graph to scan++ -> ([k], [k], [(k, k)]) -- triv colorable nodes, problem nodes, pairs of nodes to coalesce++colorScan iterative triv spill graph+ = colorScan_spin iterative triv spill graph [] [] []++colorScan_spin+ :: ( Uniquable k, Uniquable cls, Uniquable color+ , Ord k, Eq cls+ , Outputable k, Outputable cls)+ => Bool+ -> Triv k cls color+ -> (Graph k cls color -> k)+ -> Graph k cls color+ -> [k]+ -> [k]+ -> [(k, k)]+ -> ([k], [k], [(k, k)])++colorScan_spin iterative triv spill graph+ ksTriv ksSpill kksCoalesce++ -- if the graph is empty then we're done+ | isNullUFM $ graphMap graph+ = (ksTriv, ksSpill, reverse kksCoalesce)++ -- Simplify:+ -- Look for trivially colorable nodes.+ -- If we can find some then remove them from the graph and go back for more.+ --+ | nsTrivFound@(_:_)+ <- scanGraph (\node -> triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)++ -- for iterative coalescing we only want non-move related+ -- nodes here+ && (not iterative || isEmptyUniqSet (nodeCoalesce node)))+ $ graph++ , ksTrivFound <- map nodeId nsTrivFound+ , graph2 <- foldr (\k g -> let Just g' = delNode k g+ in g')+ graph ksTrivFound++ = colorScan_spin iterative triv spill graph2+ (ksTrivFound ++ ksTriv)+ ksSpill+ kksCoalesce++ -- Coalesce:+ -- If we're doing iterative coalescing and no triv nodes are available+ -- then it's time for a coalescing pass.+ | iterative+ = case coalesceGraph False triv graph of++ -- we were able to coalesce something+ -- go back to Simplify and see if this frees up more nodes to be trivially colorable.+ (graph2, kksCoalesceFound @(_:_))+ -> colorScan_spin iterative triv spill graph2+ ksTriv ksSpill (reverse kksCoalesceFound ++ kksCoalesce)++ -- Freeze:+ -- nothing could be coalesced (or was triv),+ -- time to choose a node to freeze and give up on ever coalescing it.+ (graph2, [])+ -> case freezeOneInGraph graph2 of++ -- we were able to freeze something+ -- hopefully this will free up something for Simplify+ (graph3, True)+ -> colorScan_spin iterative triv spill graph3+ ksTriv ksSpill kksCoalesce++ -- we couldn't find something to freeze either+ -- time for a spill+ (graph3, False)+ -> colorScan_spill iterative triv spill graph3+ ksTriv ksSpill kksCoalesce++ -- spill time+ | otherwise+ = colorScan_spill iterative triv spill graph+ ksTriv ksSpill kksCoalesce+++-- Select:+-- we couldn't find any triv nodes or things to freeze or coalesce,+-- and the graph isn't empty yet.. We'll have to choose a spill+-- candidate and leave it uncolored.+--+colorScan_spill+ :: ( Uniquable k, Uniquable cls, Uniquable color+ , Ord k, Eq cls+ , Outputable k, Outputable cls)+ => Bool+ -> Triv k cls color+ -> (Graph k cls color -> k)+ -> Graph k cls color+ -> [k]+ -> [k]+ -> [(k, k)]+ -> ([k], [k], [(k, k)])++colorScan_spill iterative triv spill graph+ ksTriv ksSpill kksCoalesce++ = let kSpill = spill graph+ Just graph' = delNode kSpill graph+ in colorScan_spin iterative triv spill graph'+ ksTriv (kSpill : ksSpill) kksCoalesce+++-- | Try to assign a color to all these nodes.++assignColors+ :: ( Uniquable k, Uniquable cls, Uniquable color+ , Outputable cls)+ => UniqFM (UniqSet color) -- ^ map of (node class -> set of colors available for this class).+ -> Graph k cls color -- ^ the graph+ -> [k] -- ^ nodes to assign a color to.+ -> ( Graph k cls color -- the colored graph+ , [k]) -- the nodes that didn't color.++assignColors colors graph ks+ = assignColors' colors graph [] ks++ where assignColors' _ graph prob []+ = (graph, prob)++ assignColors' colors graph prob (k:ks)+ = case assignColor colors k graph of++ -- couldn't color this node+ Nothing -> assignColors' colors graph (k : prob) ks++ -- this node colored ok, so do the rest+ Just graph' -> assignColors' colors graph' prob ks+++ assignColor colors u graph+ | Just c <- selectColor colors graph u+ = Just (setColor u c graph)++ | otherwise+ = Nothing++++-- | Select a color for a certain node+-- taking into account preferences, neighbors and exclusions.+-- returns Nothing if no color can be assigned to this node.+--+selectColor+ :: ( Uniquable k, Uniquable cls, Uniquable color+ , Outputable cls)+ => UniqFM (UniqSet color) -- ^ map of (node class -> set of colors available for this class).+ -> Graph k cls color -- ^ the graph+ -> k -- ^ key of the node to select a color for.+ -> Maybe color++selectColor colors graph u+ = let -- lookup the node+ Just node = lookupNode graph u++ -- lookup the available colors for the class of this node.+ colors_avail+ = case lookupUFM colors (nodeClass node) of+ Nothing -> pprPanic "selectColor: no colors available for class " (ppr (nodeClass node))+ Just cs -> cs++ -- find colors we can't use because they're already being used+ -- by a node that conflicts with this one.+ Just nsConflicts+ = sequence+ $ map (lookupNode graph)+ $ nonDetEltsUniqSet+ $ nodeConflicts node+ -- See Note [Unique Determinism and code generation]++ colors_conflict = mkUniqSet+ $ catMaybes+ $ map nodeColor nsConflicts++ -- the prefs of our neighbors+ colors_neighbor_prefs+ = mkUniqSet+ $ concat $ map nodePreference nsConflicts++ -- colors that are still valid for us+ colors_ok_ex = minusUniqSet colors_avail (nodeExclusions node)+ colors_ok = minusUniqSet colors_ok_ex colors_conflict++ -- the colors that we prefer, and are still ok+ colors_ok_pref = intersectUniqSets+ (mkUniqSet $ nodePreference node) colors_ok++ -- the colors that we could choose while being nice to our neighbors+ colors_ok_nice = minusUniqSet+ colors_ok colors_neighbor_prefs++ -- the best of all possible worlds..+ colors_ok_pref_nice+ = intersectUniqSets+ colors_ok_nice colors_ok_pref++ -- make the decision+ chooseColor++ -- everyone is happy, yay!+ | not $ isEmptyUniqSet colors_ok_pref_nice+ , c : _ <- filter (\x -> elementOfUniqSet x colors_ok_pref_nice)+ (nodePreference node)+ = Just c++ -- we've got one of our preferences+ | not $ isEmptyUniqSet colors_ok_pref+ , c : _ <- filter (\x -> elementOfUniqSet x colors_ok_pref)+ (nodePreference node)+ = Just c++ -- it wasn't a preference, but it was still ok+ | not $ isEmptyUniqSet colors_ok+ , c : _ <- nonDetEltsUniqSet colors_ok+ -- See Note [Unique Determinism and code generation]+ = Just c++ -- no colors were available for us this time.+ -- looks like we're going around the loop again..+ | otherwise+ = Nothing++ in chooseColor+++
+ utils/GraphOps.hs view
@@ -0,0 +1,678 @@+-- | Basic operations on graphs.+--++module GraphOps (+ addNode, delNode, getNode, lookupNode, modNode,+ size,+ union,+ addConflict, delConflict, addConflicts,+ addCoalesce, delCoalesce,+ addExclusion, addExclusions,+ addPreference,+ coalesceNodes, coalesceGraph,+ freezeNode, freezeOneInGraph, freezeAllInGraph,+ scanGraph,+ setColor,+ validateGraph,+ slurpNodeConflictCount+)+where++import GraphBase++import Outputable+import Unique+import UniqSet+import UniqFM++import Data.List hiding (union)+import Data.Maybe++-- | Lookup a node from the graph.+lookupNode+ :: Uniquable k+ => Graph k cls color+ -> k -> Maybe (Node k cls color)++lookupNode graph k+ = lookupUFM (graphMap graph) k+++-- | Get a node from the graph, throwing an error if it's not there+getNode+ :: Uniquable k+ => Graph k cls color+ -> k -> Node k cls color++getNode graph k+ = case lookupUFM (graphMap graph) k of+ Just node -> node+ Nothing -> panic "ColorOps.getNode: not found"+++-- | Add a node to the graph, linking up its edges+addNode :: Uniquable k+ => k -> Node k cls color+ -> Graph k cls color -> Graph k cls color++addNode k node graph+ = let+ -- add back conflict edges from other nodes to this one+ map_conflict =+ nonDetFoldUniqSet+ -- It's OK to use nonDetFoldUFM here because the+ -- operation is commutative+ (adjustUFM_C (\n -> n { nodeConflicts =+ addOneToUniqSet (nodeConflicts n) k}))+ (graphMap graph)+ (nodeConflicts node)++ -- add back coalesce edges from other nodes to this one+ map_coalesce =+ nonDetFoldUniqSet+ -- It's OK to use nonDetFoldUFM here because the+ -- operation is commutative+ (adjustUFM_C (\n -> n { nodeCoalesce =+ addOneToUniqSet (nodeCoalesce n) k}))+ map_conflict+ (nodeCoalesce node)++ in graph+ { graphMap = addToUFM map_coalesce k node}+++-- | Delete a node and all its edges from the graph.+delNode :: (Uniquable k)+ => k -> Graph k cls color -> Maybe (Graph k cls color)++delNode k graph+ | Just node <- lookupNode graph k+ = let -- delete conflict edges from other nodes to this one.+ graph1 = foldl' (\g k1 -> let Just g' = delConflict k1 k g in g') graph+ $ nonDetEltsUniqSet (nodeConflicts node)++ -- delete coalesce edge from other nodes to this one.+ graph2 = foldl' (\g k1 -> let Just g' = delCoalesce k1 k g in g') graph1+ $ nonDetEltsUniqSet (nodeCoalesce node)+ -- See Note [Unique Determinism and code generation]++ -- delete the node+ graph3 = graphMapModify (\fm -> delFromUFM fm k) graph2++ in Just graph3++ | otherwise+ = Nothing+++-- | Modify a node in the graph.+-- returns Nothing if the node isn't present.+--+modNode :: Uniquable k+ => (Node k cls color -> Node k cls color)+ -> k -> Graph k cls color -> Maybe (Graph k cls color)++modNode f k graph+ = case lookupNode graph k of+ Just Node{}+ -> Just+ $ graphMapModify+ (\fm -> let Just node = lookupUFM fm k+ node' = f node+ in addToUFM fm k node')+ graph++ Nothing -> Nothing+++-- | Get the size of the graph, O(n)+size :: Graph k cls color -> Int++size graph+ = sizeUFM $ graphMap graph+++-- | Union two graphs together.+union :: Graph k cls color -> Graph k cls color -> Graph k cls color++union graph1 graph2+ = Graph+ { graphMap = plusUFM (graphMap graph1) (graphMap graph2) }+++-- | Add a conflict between nodes to the graph, creating the nodes required.+-- Conflicts are virtual regs which need to be colored differently.+addConflict+ :: Uniquable k+ => (k, cls) -> (k, cls)+ -> Graph k cls color -> Graph k cls color++addConflict (u1, c1) (u2, c2)+ = let addNeighbor u c u'+ = adjustWithDefaultUFM+ (\node -> node { nodeConflicts = addOneToUniqSet (nodeConflicts node) u' })+ (newNode u c) { nodeConflicts = unitUniqSet u' }+ u++ in graphMapModify+ ( addNeighbor u1 c1 u2+ . addNeighbor u2 c2 u1)+++-- | Delete a conflict edge. k1 -> k2+-- returns Nothing if the node isn't in the graph+delConflict+ :: Uniquable k+ => k -> k+ -> Graph k cls color -> Maybe (Graph k cls color)++delConflict k1 k2+ = modNode+ (\node -> node { nodeConflicts = delOneFromUniqSet (nodeConflicts node) k2 })+ k1+++-- | Add some conflicts to the graph, creating nodes if required.+-- All the nodes in the set are taken to conflict with each other.+addConflicts+ :: Uniquable k+ => UniqSet k -> (k -> cls)+ -> Graph k cls color -> Graph k cls color++addConflicts conflicts getClass++ -- just a single node, but no conflicts, create the node anyway.+ | (u : []) <- nonDetEltsUniqSet conflicts+ = graphMapModify+ $ adjustWithDefaultUFM+ id+ (newNode u (getClass u))+ u++ | otherwise+ = graphMapModify+ $ \fm -> foldl' (\g u -> addConflictSet1 u getClass conflicts g) fm+ $ nonDetEltsUniqSet conflicts+ -- See Note [Unique Determinism and code generation]+++addConflictSet1 :: Uniquable k+ => k -> (k -> cls) -> UniqSet k+ -> UniqFM (Node k cls color)+ -> UniqFM (Node k cls color)+addConflictSet1 u getClass set+ = case delOneFromUniqSet set u of+ set' -> adjustWithDefaultUFM+ (\node -> node { nodeConflicts = unionUniqSets set' (nodeConflicts node) } )+ (newNode u (getClass u)) { nodeConflicts = set' }+ u+++-- | Add an exclusion to the graph, creating nodes if required.+-- These are extra colors that the node cannot use.+addExclusion+ :: (Uniquable k, Uniquable color)+ => k -> (k -> cls) -> color+ -> Graph k cls color -> Graph k cls color++addExclusion u getClass color+ = graphMapModify+ $ adjustWithDefaultUFM+ (\node -> node { nodeExclusions = addOneToUniqSet (nodeExclusions node) color })+ (newNode u (getClass u)) { nodeExclusions = unitUniqSet color }+ u++addExclusions+ :: (Uniquable k, Uniquable color)+ => k -> (k -> cls) -> [color]+ -> Graph k cls color -> Graph k cls color++addExclusions u getClass colors graph+ = foldr (addExclusion u getClass) graph colors+++-- | Add a coalescence edge to the graph, creating nodes if requried.+-- It is considered adventageous to assign the same color to nodes in a coalesence.+addCoalesce+ :: Uniquable k+ => (k, cls) -> (k, cls)+ -> Graph k cls color -> Graph k cls color++addCoalesce (u1, c1) (u2, c2)+ = let addCoalesce u c u'+ = adjustWithDefaultUFM+ (\node -> node { nodeCoalesce = addOneToUniqSet (nodeCoalesce node) u' })+ (newNode u c) { nodeCoalesce = unitUniqSet u' }+ u++ in graphMapModify+ ( addCoalesce u1 c1 u2+ . addCoalesce u2 c2 u1)+++-- | Delete a coalescence edge (k1 -> k2) from the graph.+delCoalesce+ :: Uniquable k+ => k -> k+ -> Graph k cls color -> Maybe (Graph k cls color)++delCoalesce k1 k2+ = modNode (\node -> node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k2 })+ k1+++-- | Add a color preference to the graph, creating nodes if required.+-- The most recently added preference is the most prefered.+-- The algorithm tries to assign a node it's prefered color if possible.+--+addPreference+ :: Uniquable k+ => (k, cls) -> color+ -> Graph k cls color -> Graph k cls color++addPreference (u, c) color+ = graphMapModify+ $ adjustWithDefaultUFM+ (\node -> node { nodePreference = color : (nodePreference node) })+ (newNode u c) { nodePreference = [color] }+ u+++-- | Do aggressive coalescing on this graph.+-- returns the new graph and the list of pairs of nodes that got coalesced together.+-- for each pair, the resulting node will have the least key and be second in the pair.+--+coalesceGraph+ :: (Uniquable k, Ord k, Eq cls, Outputable k)+ => Bool -- ^ If True, coalesce nodes even if this might make the graph+ -- less colorable (aggressive coalescing)+ -> Triv k cls color+ -> Graph k cls color+ -> ( Graph k cls color+ , [(k, k)]) -- pairs of nodes that were coalesced, in the order that the+ -- coalescing was applied.++coalesceGraph aggressive triv graph+ = coalesceGraph' aggressive triv graph []++coalesceGraph'+ :: (Uniquable k, Ord k, Eq cls, Outputable k)+ => Bool+ -> Triv k cls color+ -> Graph k cls color+ -> [(k, k)]+ -> ( Graph k cls color+ , [(k, k)])+coalesceGraph' aggressive triv graph kkPairsAcc+ = let+ -- find all the nodes that have coalescence edges+ cNodes = filter (\node -> not $ isEmptyUniqSet (nodeCoalesce node))+ $ nonDetEltsUFM $ graphMap graph+ -- See Note [Unique Determinism and code generation]++ -- build a list of pairs of keys for node's we'll try and coalesce+ -- every pair of nodes will appear twice in this list+ -- ie [(k1, k2), (k2, k1) ... ]+ -- This is ok, GrapOps.coalesceNodes handles this and it's convenient for+ -- build a list of what nodes get coalesced together for later on.+ --+ cList = [ (nodeId node1, k2)+ | node1 <- cNodes+ , k2 <- nonDetEltsUniqSet $ nodeCoalesce node1 ]+ -- See Note [Unique Determinism and code generation]++ -- do the coalescing, returning the new graph and a list of pairs of keys+ -- that got coalesced together.+ (graph', mPairs)+ = mapAccumL (coalesceNodes aggressive triv) graph cList++ -- keep running until there are no more coalesces can be found+ in case catMaybes mPairs of+ [] -> (graph', reverse kkPairsAcc)+ pairs -> coalesceGraph' aggressive triv graph' (reverse pairs ++ kkPairsAcc)+++-- | Coalesce this pair of nodes unconditionally \/ aggressively.+-- The resulting node is the one with the least key.+--+-- returns: Just the pair of keys if the nodes were coalesced+-- the second element of the pair being the least one+--+-- Nothing if either of the nodes weren't in the graph++coalesceNodes+ :: (Uniquable k, Ord k, Eq cls)+ => Bool -- ^ If True, coalesce nodes even if this might make the graph+ -- less colorable (aggressive coalescing)+ -> Triv k cls color+ -> Graph k cls color+ -> (k, k) -- ^ keys of the nodes to be coalesced+ -> (Graph k cls color, Maybe (k, k))++coalesceNodes aggressive triv graph (k1, k2)+ | (kMin, kMax) <- if k1 < k2+ then (k1, k2)+ else (k2, k1)++ -- the nodes being coalesced must be in the graph+ , Just nMin <- lookupNode graph kMin+ , Just nMax <- lookupNode graph kMax++ -- can't coalesce conflicting modes+ , not $ elementOfUniqSet kMin (nodeConflicts nMax)+ , not $ elementOfUniqSet kMax (nodeConflicts nMin)++ -- can't coalesce the same node+ , nodeId nMin /= nodeId nMax++ = coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax++ -- don't do the coalescing after all+ | otherwise+ = (graph, Nothing)++coalesceNodes_merge+ :: (Uniquable k, Eq cls)+ => Bool+ -> Triv k cls color+ -> Graph k cls color+ -> k -> k+ -> Node k cls color+ -> Node k cls color+ -> (Graph k cls color, Maybe (k, k))++coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax++ -- sanity checks+ | nodeClass nMin /= nodeClass nMax+ = error "GraphOps.coalesceNodes: can't coalesce nodes of different classes."++ | not (isNothing (nodeColor nMin) && isNothing (nodeColor nMax))+ = error "GraphOps.coalesceNodes: can't coalesce colored nodes."++ ---+ | otherwise+ = let+ -- the new node gets all the edges from its two components+ node =+ Node { nodeId = kMin+ , nodeClass = nodeClass nMin+ , nodeColor = Nothing++ -- nodes don't conflict with themselves..+ , nodeConflicts+ = (unionUniqSets (nodeConflicts nMin) (nodeConflicts nMax))+ `delOneFromUniqSet` kMin+ `delOneFromUniqSet` kMax++ , nodeExclusions = unionUniqSets (nodeExclusions nMin) (nodeExclusions nMax)+ , nodePreference = nodePreference nMin ++ nodePreference nMax++ -- nodes don't coalesce with themselves..+ , nodeCoalesce+ = (unionUniqSets (nodeCoalesce nMin) (nodeCoalesce nMax))+ `delOneFromUniqSet` kMin+ `delOneFromUniqSet` kMax+ }++ in coalesceNodes_check aggressive triv graph kMin kMax node++coalesceNodes_check+ :: Uniquable k+ => Bool+ -> Triv k cls color+ -> Graph k cls color+ -> k -> k+ -> Node k cls color+ -> (Graph k cls color, Maybe (k, k))++coalesceNodes_check aggressive triv graph kMin kMax node++ -- Unless we're coalescing aggressively, if the result node is not trivially+ -- colorable then don't do the coalescing.+ | not aggressive+ , not $ triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)+ = (graph, Nothing)++ | otherwise+ = let -- delete the old nodes from the graph and add the new one+ Just graph1 = delNode kMax graph+ Just graph2 = delNode kMin graph1+ graph3 = addNode kMin node graph2++ in (graph3, Just (kMax, kMin))+++-- | Freeze a node+-- This is for the iterative coalescer.+-- By freezing a node we give up on ever coalescing it.+-- Move all its coalesce edges into the frozen set - and update+-- back edges from other nodes.+--+freezeNode+ :: Uniquable k+ => k -- ^ key of the node to freeze+ -> Graph k cls color -- ^ the graph+ -> Graph k cls color -- ^ graph with that node frozen++freezeNode k+ = graphMapModify+ $ \fm ->+ let -- freeze all the edges in the node to be frozen+ Just node = lookupUFM fm k+ node' = node+ { nodeCoalesce = emptyUniqSet }++ fm1 = addToUFM fm k node'++ -- update back edges pointing to this node+ freezeEdge k node+ = if elementOfUniqSet k (nodeCoalesce node)+ then node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k }+ else node -- panic "GraphOps.freezeNode: edge to freeze wasn't in the coalesce set"+ -- If the edge isn't actually in the coelesce set then just ignore it.++ fm2 = nonDetFoldUniqSet (adjustUFM_C (freezeEdge k)) fm1+ -- It's OK to use nonDetFoldUFM here because the operation+ -- is commutative+ $ nodeCoalesce node++ in fm2+++-- | Freeze one node in the graph+-- This if for the iterative coalescer.+-- Look for a move related node of low degree and freeze it.+--+-- We probably don't need to scan the whole graph looking for the node of absolute+-- lowest degree. Just sample the first few and choose the one with the lowest+-- degree out of those. Also, we don't make any distinction between conflicts of different+-- classes.. this is just a heuristic, after all.+--+-- IDEA: freezing a node might free it up for Simplify.. would be good to check for triv+-- right here, and add it to a worklist if known triv\/non-move nodes.+--+freezeOneInGraph+ :: (Uniquable k)+ => Graph k cls color+ -> ( Graph k cls color -- the new graph+ , Bool ) -- whether we found a node to freeze++freezeOneInGraph graph+ = let compareNodeDegree n1 n2+ = compare (sizeUniqSet $ nodeConflicts n1) (sizeUniqSet $ nodeConflicts n2)++ candidates+ = sortBy compareNodeDegree+ $ take 5 -- 5 isn't special, it's just a small number.+ $ scanGraph (\node -> not $ isEmptyUniqSet (nodeCoalesce node)) graph++ in case candidates of++ -- there wasn't anything available to freeze+ [] -> (graph, False)++ -- we found something to freeze+ (n : _)+ -> ( freezeNode (nodeId n) graph+ , True)+++-- | Freeze all the nodes in the graph+-- for debugging the iterative allocator.+--+freezeAllInGraph+ :: (Uniquable k)+ => Graph k cls color+ -> Graph k cls color++freezeAllInGraph graph+ = foldr freezeNode graph+ $ map nodeId+ $ nonDetEltsUFM $ graphMap graph+ -- See Note [Unique Determinism and code generation]+++-- | Find all the nodes in the graph that meet some criteria+--+scanGraph+ :: (Node k cls color -> Bool)+ -> Graph k cls color+ -> [Node k cls color]++scanGraph match graph+ = filter match $ nonDetEltsUFM $ graphMap graph+ -- See Note [Unique Determinism and code generation]+++-- | validate the internal structure of a graph+-- all its edges should point to valid nodes+-- If they don't then throw an error+--+validateGraph+ :: (Uniquable k, Outputable k, Eq color)+ => SDoc -- ^ extra debugging info to display on error+ -> Bool -- ^ whether this graph is supposed to be colored.+ -> Graph k cls color -- ^ graph to validate+ -> Graph k cls color -- ^ validated graph++validateGraph doc isColored graph++ -- Check that all edges point to valid nodes.+ | edges <- unionManyUniqSets+ ( (map nodeConflicts $ nonDetEltsUFM $ graphMap graph)+ ++ (map nodeCoalesce $ nonDetEltsUFM $ graphMap graph))++ , nodes <- mkUniqSet $ map nodeId $ nonDetEltsUFM $ graphMap graph+ , badEdges <- minusUniqSet edges nodes+ , not $ isEmptyUniqSet badEdges+ = pprPanic "GraphOps.validateGraph"+ ( text "Graph has edges that point to non-existent nodes"+ $$ text " bad edges: " <> pprUFM (getUniqSet badEdges) (vcat . map ppr)+ $$ doc )++ -- Check that no conflicting nodes have the same color+ | badNodes <- filter (not . (checkNode graph))+ $ nonDetEltsUFM $ graphMap graph+ -- See Note [Unique Determinism and code generation]+ , not $ null badNodes+ = pprPanic "GraphOps.validateGraph"+ ( text "Node has same color as one of it's conflicts"+ $$ text " bad nodes: " <> hcat (map (ppr . nodeId) badNodes)+ $$ doc)++ -- If this is supposed to be a colored graph,+ -- check that all nodes have a color.+ | isColored+ , badNodes <- filter (\n -> isNothing $ nodeColor n)+ $ nonDetEltsUFM $ graphMap graph+ , not $ null badNodes+ = pprPanic "GraphOps.validateGraph"+ ( text "Supposably colored graph has uncolored nodes."+ $$ text " uncolored nodes: " <> hcat (map (ppr . nodeId) badNodes)+ $$ doc )+++ -- graph looks ok+ | otherwise+ = graph+++-- | If this node is colored, check that all the nodes which+-- conflict with it have different colors.+checkNode+ :: (Uniquable k, Eq color)+ => Graph k cls color+ -> Node k cls color+ -> Bool -- ^ True if this node is ok++checkNode graph node+ | Just color <- nodeColor node+ , Just neighbors <- sequence $ map (lookupNode graph)+ $ nonDetEltsUniqSet $ nodeConflicts node+ -- See Note [Unique Determinism and code generation]++ , neighbourColors <- catMaybes $ map nodeColor neighbors+ , elem color neighbourColors+ = False++ | otherwise+ = True++++-- | Slurp out a map of how many nodes had a certain number of conflict neighbours++slurpNodeConflictCount+ :: Graph k cls color+ -> UniqFM (Int, Int) -- ^ (conflict neighbours, num nodes with that many conflicts)++slurpNodeConflictCount graph+ = addListToUFM_C+ (\(c1, n1) (_, n2) -> (c1, n1 + n2))+ emptyUFM+ $ map (\node+ -> let count = sizeUniqSet $ nodeConflicts node+ in (count, (count, 1)))+ $ nonDetEltsUFM+ -- See Note [Unique Determinism and code generation]+ $ graphMap graph+++-- | Set the color of a certain node+setColor+ :: Uniquable k+ => k -> color+ -> Graph k cls color -> Graph k cls color++setColor u color+ = graphMapModify+ $ adjustUFM_C+ (\n -> n { nodeColor = Just color })+ u+++{-# INLINE adjustWithDefaultUFM #-}+adjustWithDefaultUFM+ :: Uniquable k+ => (a -> a) -> a -> k+ -> UniqFM a -> UniqFM a++adjustWithDefaultUFM f def k map+ = addToUFM_C+ (\old _ -> f old)+ map+ k def++-- Argument order different from UniqFM's adjustUFM+{-# INLINE adjustUFM_C #-}+adjustUFM_C+ :: Uniquable k+ => (a -> a)+ -> k -> UniqFM a -> UniqFM a++adjustUFM_C f k map+ = case lookupUFM map k of+ Nothing -> map+ Just a -> addToUFM map k (f a)+
+ utils/GraphPpr.hs view
@@ -0,0 +1,171 @@++-- | Pretty printing of graphs.++module GraphPpr (+ dumpGraph,+ dotGraph+)+where++import GraphBase++import Outputable+import Unique+import UniqSet+import UniqFM++import Data.List+import Data.Maybe+++-- | Pretty print a graph in a somewhat human readable format.+dumpGraph+ :: (Outputable k, Outputable color)+ => Graph k cls color -> SDoc++dumpGraph graph+ = text "Graph"+ $$ pprUFM (graphMap graph) (vcat . map dumpNode)++dumpNode+ :: (Outputable k, Outputable color)+ => Node k cls color -> SDoc++dumpNode node+ = text "Node " <> ppr (nodeId node)+ $$ text "conflicts "+ <> parens (int (sizeUniqSet $ nodeConflicts node))+ <> text " = "+ <> ppr (nodeConflicts node)++ $$ text "exclusions "+ <> parens (int (sizeUniqSet $ nodeExclusions node))+ <> text " = "+ <> ppr (nodeExclusions node)++ $$ text "coalesce "+ <> parens (int (sizeUniqSet $ nodeCoalesce node))+ <> text " = "+ <> ppr (nodeCoalesce node)++ $$ space++++-- | Pretty print a graph in graphviz .dot format.+-- Conflicts get solid edges.+-- Coalescences get dashed edges.+dotGraph+ :: ( Uniquable k+ , Outputable k, Outputable cls, Outputable color)+ => (color -> SDoc) -- ^ What graphviz color to use for each node color+ -- It's usually safe to return X11 style colors here,+ -- ie "red", "green" etc or a hex triplet #aaff55 etc+ -> Triv k cls color+ -> Graph k cls color -> SDoc++dotGraph colorMap triv graph+ = let nodes = nonDetEltsUFM $ graphMap graph+ -- See Note [Unique Determinism and code generation]+ in vcat+ ( [ text "graph G {" ]+ ++ map (dotNode colorMap triv) nodes+ ++ (catMaybes $ snd $ mapAccumL dotNodeEdges emptyUniqSet nodes)+ ++ [ text "}"+ , space ])+++dotNode :: ( Outputable k, Outputable cls, Outputable color)+ => (color -> SDoc)+ -> Triv k cls color+ -> Node k cls color -> SDoc++dotNode colorMap triv node+ = let name = ppr $ nodeId node+ cls = ppr $ nodeClass node++ excludes+ = hcat $ punctuate space+ $ map (\n -> text "-" <> ppr n)+ $ nonDetEltsUniqSet $ nodeExclusions node+ -- See Note [Unique Determinism and code generation]++ preferences+ = hcat $ punctuate space+ $ map (\n -> text "+" <> ppr n)+ $ nodePreference node++ expref = if and [isEmptyUniqSet (nodeExclusions node), null (nodePreference node)]+ then empty+ else text "\\n" <> (excludes <+> preferences)++ -- if the node has been colored then show that,+ -- otherwise indicate whether it looks trivially colorable.+ color+ | Just c <- nodeColor node+ = text "\\n(" <> ppr c <> text ")"++ | triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)+ = text "\\n(" <> text "triv" <> text ")"++ | otherwise+ = text "\\n(" <> text "spill?" <> text ")"++ label = name <> text " :: " <> cls+ <> expref+ <> color++ pcolorC = case nodeColor node of+ Nothing -> text "style=filled fillcolor=white"+ Just c -> text "style=filled fillcolor=" <> doubleQuotes (colorMap c)+++ pout = text "node [label=" <> doubleQuotes label <> space <> pcolorC <> text "]"+ <> space <> doubleQuotes name+ <> text ";"++ in pout+++-- | Nodes in the graph are doubly linked, but we only want one edge for each+-- conflict if the graphviz graph. Traverse over the graph, but make sure+-- to only print the edges for each node once.++dotNodeEdges+ :: ( Uniquable k+ , Outputable k)+ => UniqSet k+ -> Node k cls color+ -> (UniqSet k, Maybe SDoc)++dotNodeEdges visited node+ | elementOfUniqSet (nodeId node) visited+ = ( visited+ , Nothing)++ | otherwise+ = let dconflicts+ = map (dotEdgeConflict (nodeId node))+ $ nonDetEltsUniqSet+ -- See Note [Unique Determinism and code generation]+ $ minusUniqSet (nodeConflicts node) visited++ dcoalesces+ = map (dotEdgeCoalesce (nodeId node))+ $ nonDetEltsUniqSet+ -- See Note [Unique Determinism and code generation]+ $ minusUniqSet (nodeCoalesce node) visited++ out = vcat dconflicts+ $$ vcat dcoalesces++ in ( addOneToUniqSet visited (nodeId node)+ , Just out)++ where dotEdgeConflict u1 u2+ = doubleQuotes (ppr u1) <> text " -- " <> doubleQuotes (ppr u2)+ <> text ";"++ dotEdgeCoalesce u1 u2+ = doubleQuotes (ppr u1) <> text " -- " <> doubleQuotes (ppr u2)+ <> space <> text "[ style = dashed ];"
+ utils/IOEnv.hs view
@@ -0,0 +1,227 @@+{-# LANGUAGE CPP #-}++--+-- (c) The University of Glasgow 2002-2006+--+-- The IO Monad with an environment+--+-- The environment is passed around as a Reader monad but+-- as its in the IO monad, mutable references can be used+-- for updating state.+--++module IOEnv (+ IOEnv, -- Instance of Monad++ -- Monad utilities+ module MonadUtils,++ -- Errors+ failM, failWithM,+ IOEnvFailure(..),++ -- Getting at the environment+ getEnv, setEnv, updEnv,++ runIOEnv, unsafeInterleaveM, uninterruptibleMaskM_,+ tryM, tryAllM, tryMostM, fixM,++ -- I/O operations+ IORef, newMutVar, readMutVar, writeMutVar, updMutVar,+ atomicUpdMutVar, atomicUpdMutVar'+ ) where++import DynFlags+import Exception+import Module+import Panic++import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef,+ atomicModifyIORef, atomicModifyIORef' )+import System.IO.Unsafe ( unsafeInterleaveIO )+import System.IO ( fixIO )+import Control.Monad+#if __GLASGOW_HASKELL__ > 710+import qualified Control.Monad.Fail as MonadFail+#endif+import MonadUtils+import Control.Applicative (Alternative(..))++----------------------------------------------------------------------+-- Defining the monad type+----------------------------------------------------------------------+++newtype IOEnv env a = IOEnv (env -> IO a)++unIOEnv :: IOEnv env a -> (env -> IO a)+unIOEnv (IOEnv m) = m++instance Monad (IOEnv m) where+ (>>=) = thenM+ (>>) = (*>)+ fail _ = failM -- Ignore the string++#if __GLASGOW_HASKELL__ > 710+instance MonadFail.MonadFail (IOEnv m) where+ fail _ = failM -- Ignore the string+#endif+++instance Applicative (IOEnv m) where+ pure = returnM+ IOEnv f <*> IOEnv x = IOEnv (\ env -> f env <*> x env )+ (*>) = thenM_++instance Functor (IOEnv m) where+ fmap f (IOEnv m) = IOEnv (\ env -> fmap f (m env))++returnM :: a -> IOEnv env a+returnM a = IOEnv (\ _ -> return a)++thenM :: IOEnv env a -> (a -> IOEnv env b) -> IOEnv env b+thenM (IOEnv m) f = IOEnv (\ env -> do { r <- m env ;+ unIOEnv (f r) env })++thenM_ :: IOEnv env a -> IOEnv env b -> IOEnv env b+thenM_ (IOEnv m) f = IOEnv (\ env -> do { _ <- m env ; unIOEnv f env })++failM :: IOEnv env a+failM = IOEnv (\ _ -> throwIO IOEnvFailure)++failWithM :: String -> IOEnv env a+failWithM s = IOEnv (\ _ -> ioError (userError s))++data IOEnvFailure = IOEnvFailure++instance Show IOEnvFailure where+ show IOEnvFailure = "IOEnv failure"++instance Exception IOEnvFailure++instance ExceptionMonad (IOEnv a) where+ gcatch act handle =+ IOEnv $ \s -> unIOEnv act s `gcatch` \e -> unIOEnv (handle e) s+ gmask f =+ IOEnv $ \s -> gmask $ \io_restore ->+ let+ g_restore (IOEnv m) = IOEnv $ \s -> io_restore (m s)+ in+ unIOEnv (f g_restore) s++instance ContainsDynFlags env => HasDynFlags (IOEnv env) where+ getDynFlags = do env <- getEnv+ return $ extractDynFlags env++instance ContainsModule env => HasModule (IOEnv env) where+ getModule = do env <- getEnv+ return $ extractModule env++----------------------------------------------------------------------+-- Fundamental combinators specific to the monad+----------------------------------------------------------------------+++---------------------------+runIOEnv :: env -> IOEnv env a -> IO a+runIOEnv env (IOEnv m) = m env+++---------------------------+{-# NOINLINE fixM #-}+ -- Aargh! Not inlining fixM alleviates a space leak problem.+ -- Normally fixM is used with a lazy tuple match: if the optimiser is+ -- shown the definition of fixM, it occasionally transforms the code+ -- in such a way that the code generator doesn't spot the selector+ -- thunks. Sigh.++fixM :: (a -> IOEnv env a) -> IOEnv env a+fixM f = IOEnv (\ env -> fixIO (\ r -> unIOEnv (f r) env))+++---------------------------+tryM :: IOEnv env r -> IOEnv env (Either IOEnvFailure r)+-- Reflect UserError exceptions (only) into IOEnv monad+-- Other exceptions are not caught; they are simply propagated as exns+--+-- The idea is that errors in the program being compiled will give rise+-- to UserErrors. But, say, pattern-match failures in GHC itself should+-- not be caught here, else they'll be reported as errors in the program+-- begin compiled!+tryM (IOEnv thing) = IOEnv (\ env -> tryIOEnvFailure (thing env))++tryIOEnvFailure :: IO a -> IO (Either IOEnvFailure a)+tryIOEnvFailure = try++-- XXX We shouldn't be catching everything, e.g. timeouts+tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r)+-- Catch *all* exceptions+-- This is used when running a Template-Haskell splice, when+-- even a pattern-match failure is a programmer error+tryAllM (IOEnv thing) = IOEnv (\ env -> try (thing env))++tryMostM :: IOEnv env r -> IOEnv env (Either SomeException r)+tryMostM (IOEnv thing) = IOEnv (\ env -> tryMost (thing env))++---------------------------+unsafeInterleaveM :: IOEnv env a -> IOEnv env a+unsafeInterleaveM (IOEnv m) = IOEnv (\ env -> unsafeInterleaveIO (m env))++uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a+uninterruptibleMaskM_ (IOEnv m) = IOEnv (\ env -> uninterruptibleMask_ (m env))++----------------------------------------------------------------------+-- Alternative/MonadPlus+----------------------------------------------------------------------++instance Alternative (IOEnv env) where+ empty = IOEnv (const empty)+ m <|> n = IOEnv (\env -> unIOEnv m env <|> unIOEnv n env)++instance MonadPlus (IOEnv env)++----------------------------------------------------------------------+-- Accessing input/output+----------------------------------------------------------------------++instance MonadIO (IOEnv env) where+ liftIO io = IOEnv (\ _ -> io)++newMutVar :: a -> IOEnv env (IORef a)+newMutVar val = liftIO (newIORef val)++writeMutVar :: IORef a -> a -> IOEnv env ()+writeMutVar var val = liftIO (writeIORef var val)++readMutVar :: IORef a -> IOEnv env a+readMutVar var = liftIO (readIORef var)++updMutVar :: IORef a -> (a -> a) -> IOEnv env ()+updMutVar var upd = liftIO (modifyIORef var upd)++-- | Atomically update the reference. Does not force the evaluation of the+-- new variable contents. For strict update, use 'atomicUpdMutVar''.+atomicUpdMutVar :: IORef a -> (a -> (a, b)) -> IOEnv env b+atomicUpdMutVar var upd = liftIO (atomicModifyIORef var upd)++-- | Strict variant of 'atomicUpdMutVar'.+atomicUpdMutVar' :: IORef a -> (a -> (a, b)) -> IOEnv env b+atomicUpdMutVar' var upd = liftIO (atomicModifyIORef' var upd)++----------------------------------------------------------------------+-- Accessing the environment+----------------------------------------------------------------------++getEnv :: IOEnv env env+{-# INLINE getEnv #-}+getEnv = IOEnv (\ env -> return env)++-- | Perform a computation with a different environment+setEnv :: env' -> IOEnv env' a -> IOEnv env a+{-# INLINE setEnv #-}+setEnv new_env (IOEnv m) = IOEnv (\ _ -> m new_env)++-- | Perform a computation with an altered environment+updEnv :: (env -> env') -> IOEnv env' a -> IOEnv env a+{-# INLINE updEnv #-}+updEnv upd (IOEnv m) = IOEnv (\ env -> m (upd env))
+ utils/Json.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE GADTs #-}+module Json where++import Outputable+import Data.Char+import Numeric++-- | Simple data type to represent JSON documents.+data JsonDoc where+ JSNull :: JsonDoc+ JSBool :: Bool -> JsonDoc+ JSInt :: Int -> JsonDoc+ JSString :: String -> JsonDoc+ JSArray :: [JsonDoc] -> JsonDoc+ JSObject :: [(String, JsonDoc)] -> JsonDoc+++-- This is simple and slow as it is only used for error reporting+renderJSON :: JsonDoc -> SDoc+renderJSON d =+ case d of+ JSNull -> text "null"+ JSBool b -> text $ if b then "true" else "false"+ JSInt n -> ppr n+ JSString s -> doubleQuotes $ text $ escapeJsonString s+ JSArray as -> brackets $ pprList renderJSON as+ JSObject fs -> braces $ pprList renderField fs+ where+ renderField :: (String, JsonDoc) -> SDoc+ renderField (s, j) = doubleQuotes (text s) <> colon <+> renderJSON j++ pprList pp xs = hcat (punctuate comma (map pp xs))++escapeJsonString :: String -> String+escapeJsonString = concatMap escapeChar+ where+ escapeChar '\b' = "\\b"+ escapeChar '\f' = "\\f"+ escapeChar '\n' = "\\n"+ escapeChar '\r' = "\\r"+ escapeChar '\t' = "\\t"+ escapeChar '"' = "\""+ escapeChar '\\' = "\\\\"+ escapeChar c | isControl c || fromEnum c >= 0x7f = uni_esc c+ escapeChar c = [c]++ uni_esc c = "\\u" ++ (pad 4 (showHex (fromEnum c) ""))++ pad n cs | len < n = replicate (n-len) '0' ++ cs+ | otherwise = cs+ where len = length cs++class ToJson a where+ json :: a -> JsonDoc
+ utils/ListSetOps.hs view
@@ -0,0 +1,155 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998++\section[ListSetOps]{Set-like operations on lists}+-}++{-# LANGUAGE CPP #-}++module ListSetOps (+ unionLists, minusList,++ -- Association lists+ Assoc, assoc, assocMaybe, assocUsing, assocDefault, assocDefaultUsing,++ -- Duplicate handling+ hasNoDups, runs, removeDups, findDupsEq,+ equivClasses,++ -- Indexing+ getNth+ ) where++#include "HsVersions.h"++import Outputable+import Util++import Data.List++getNth :: Outputable a => [a] -> Int -> a+getNth xs n = ASSERT2( xs `lengthExceeds` n, ppr n $$ ppr xs )+ xs !! n++{-+************************************************************************+* *+ Treating lists as sets+ Assumes the lists contain no duplicates, but are unordered+* *+************************************************************************+-}+++unionLists :: (Outputable a, Eq a) => [a] -> [a] -> [a]+-- Assumes that the arguments contain no duplicates+unionLists xs ys+ = WARN(length xs > 100 || length ys > 100, ppr xs $$ ppr ys)+ [x | x <- xs, isn'tIn "unionLists" x ys] ++ ys++minusList :: (Eq a) => [a] -> [a] -> [a]+-- Everything in the first list that is not in the second list:+minusList xs ys = [ x | x <- xs, isn'tIn "minusList" x ys]++{-+************************************************************************+* *+\subsection[Utils-assoc]{Association lists}+* *+************************************************************************++Inefficient finite maps based on association lists and equality.+-}++-- A finite mapping based on equality and association lists+type Assoc a b = [(a,b)]++assoc :: (Eq a) => String -> Assoc a b -> a -> b+assocDefault :: (Eq a) => b -> Assoc a b -> a -> b+assocUsing :: (a -> a -> Bool) -> String -> Assoc a b -> a -> b+assocMaybe :: (Eq a) => Assoc a b -> a -> Maybe b+assocDefaultUsing :: (a -> a -> Bool) -> b -> Assoc a b -> a -> b++assocDefaultUsing _ deflt [] _ = deflt+assocDefaultUsing eq deflt ((k,v) : rest) key+ | k `eq` key = v+ | otherwise = assocDefaultUsing eq deflt rest key++assoc crash_msg list key = assocDefaultUsing (==) (panic ("Failed in assoc: " ++ crash_msg)) list key+assocDefault deflt list key = assocDefaultUsing (==) deflt list key+assocUsing eq crash_msg list key = assocDefaultUsing eq (panic ("Failed in assoc: " ++ crash_msg)) list key++assocMaybe alist key+ = lookup alist+ where+ lookup [] = Nothing+ lookup ((tv,ty):rest) = if key == tv then Just ty else lookup rest++{-+************************************************************************+* *+\subsection[Utils-dups]{Duplicate-handling}+* *+************************************************************************+-}++hasNoDups :: (Eq a) => [a] -> Bool++hasNoDups xs = f [] xs+ where+ f _ [] = True+ f seen_so_far (x:xs) = if x `is_elem` seen_so_far+ then False+ else f (x:seen_so_far) xs++ is_elem = isIn "hasNoDups"++equivClasses :: (a -> a -> Ordering) -- Comparison+ -> [a]+ -> [[a]]++equivClasses _ [] = []+equivClasses _ stuff@[_] = [stuff]+equivClasses cmp items = runs eq (sortBy cmp items)+ where+ eq a b = case cmp a b of { EQ -> True; _ -> False }++{-+The first cases in @equivClasses@ above are just to cut to the point+more quickly...++@runs@ groups a list into a list of lists, each sublist being a run of+identical elements of the input list. It is passed a predicate @p@ which+tells when two elements are equal.+-}++runs :: (a -> a -> Bool) -- Equality+ -> [a]+ -> [[a]]++runs _ [] = []+runs p (x:xs) = case (span (p x) xs) of+ (first, rest) -> (x:first) : (runs p rest)++removeDups :: (a -> a -> Ordering) -- Comparison function+ -> [a]+ -> ([a], -- List with no duplicates+ [[a]]) -- List of duplicate groups. One representative from+ -- each group appears in the first result++removeDups _ [] = ([], [])+removeDups _ [x] = ([x],[])+removeDups cmp xs+ = case (mapAccumR collect_dups [] (equivClasses cmp xs)) of { (dups, xs') ->+ (xs', dups) }+ where+ collect_dups _ [] = panic "ListSetOps: removeDups"+ collect_dups dups_so_far [x] = (dups_so_far, x)+ collect_dups dups_so_far dups@(x:_) = (dups:dups_so_far, x)++findDupsEq :: (a->a->Bool) -> [a] -> [[a]]+findDupsEq _ [] = []+findDupsEq eq (x:xs) | null eq_xs = findDupsEq eq xs+ | otherwise = (x:eq_xs) : findDupsEq eq neq_xs+ where (eq_xs, neq_xs) = partition (eq x) xs
+ utils/ListT.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}++-------------------------------------------------------------------------+-- |+-- Module : Control.Monad.Logic+-- Copyright : (c) Dan Doel+-- License : BSD3+--+-- Maintainer : dan.doel@gmail.com+-- Stability : experimental+-- Portability : non-portable (multi-parameter type classes)+--+-- A backtracking, logic programming monad.+--+-- Adapted from the paper+-- /Backtracking, Interleaving, and Terminating+-- Monad Transformers/, by+-- Oleg Kiselyov, Chung-chieh Shan, Daniel P. Friedman, Amr Sabry+-- (<http://www.cs.rutgers.edu/~ccshan/logicprog/ListT-icfp2005.pdf>).+-------------------------------------------------------------------------++module ListT (+ ListT(..),+ runListT,+ select,+ fold+ ) where++import Control.Applicative++import Control.Monad++-------------------------------------------------------------------------+-- | A monad transformer for performing backtracking computations+-- layered over another monad 'm'+newtype ListT m a =+ ListT { unListT :: forall r. (a -> m r -> m r) -> m r -> m r }++select :: Monad m => [a] -> ListT m a+select xs = foldr (<|>) mzero (map pure xs)++fold :: ListT m a -> (a -> m r -> m r) -> m r -> m r+fold = runListT++-------------------------------------------------------------------------+-- | Runs a ListT computation with the specified initial success and+-- failure continuations.+runListT :: ListT m a -> (a -> m r -> m r) -> m r -> m r+runListT = unListT++instance Functor (ListT f) where+ fmap f lt = ListT $ \sk fk -> unListT lt (sk . f) fk++instance Applicative (ListT f) where+ pure a = ListT $ \sk fk -> sk a fk+ f <*> a = ListT $ \sk fk -> unListT f (\g fk' -> unListT a (sk . g) fk') fk++instance Alternative (ListT f) where+ empty = ListT $ \_ fk -> fk+ f1 <|> f2 = ListT $ \sk fk -> unListT f1 sk (unListT f2 sk fk)++instance Monad (ListT m) where+ m >>= f = ListT $ \sk fk -> unListT m (\a fk' -> unListT (f a) sk fk') fk+ fail _ = ListT $ \_ fk -> fk++instance MonadPlus (ListT m) where+ mzero = ListT $ \_ fk -> fk+ m1 `mplus` m2 = ListT $ \sk fk -> unListT m1 sk (unListT m2 sk fk)
+ utils/Maybes.hs view
@@ -0,0 +1,108 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE FlexibleContexts #-}++{-+(c) The University of Glasgow 2006+(c) The GRASP/AQUA Project, Glasgow University, 1992-1998+-}++module Maybes (+ module Data.Maybe,++ MaybeErr(..), -- Instance of Monad+ failME, isSuccess,++ orElse,+ firstJust, firstJusts,+ whenIsJust,+ expectJust,++ -- * MaybeT+ MaybeT(..), liftMaybeT, tryMaybeT+ ) where++import Control.Monad+import Control.Monad.Trans.Maybe+import Control.Exception (catch, SomeException(..))+import Data.Maybe+import Util (HasCallStack)++infixr 4 `orElse`++{-+************************************************************************+* *+\subsection[Maybe type]{The @Maybe@ type}+* *+************************************************************************+-}++firstJust :: Maybe a -> Maybe a -> Maybe a+firstJust a b = firstJusts [a, b]++-- | Takes a list of @Maybes@ and returns the first @Just@ if there is one, or+-- @Nothing@ otherwise.+firstJusts :: [Maybe a] -> Maybe a+firstJusts = msum++expectJust :: HasCallStack => String -> Maybe a -> a+{-# INLINE expectJust #-}+expectJust _ (Just x) = x+expectJust err Nothing = error ("expectJust " ++ err)++whenIsJust :: Monad m => Maybe a -> (a -> m ()) -> m ()+whenIsJust (Just x) f = f x+whenIsJust Nothing _ = return ()++-- | Flipped version of @fromMaybe@, useful for chaining.+orElse :: Maybe a -> a -> a+orElse = flip fromMaybe++{-+************************************************************************+* *+\subsection[MaybeT type]{The @MaybeT@ monad transformer}+* *+************************************************************************+-}++-- We had our own MaybeT in the past. Now we reuse transformer's MaybeT++liftMaybeT :: Monad m => m a -> MaybeT m a+liftMaybeT act = MaybeT $ Just `liftM` act++-- | Try performing an 'IO' action, failing on error.+tryMaybeT :: IO a -> MaybeT IO a+tryMaybeT action = MaybeT $ catch (Just `fmap` action) handler+ where+ handler (SomeException _) = return Nothing++{-+************************************************************************+* *+\subsection[MaybeErr type]{The @MaybeErr@ type}+* *+************************************************************************+-}++data MaybeErr err val = Succeeded val | Failed err++instance Functor (MaybeErr err) where+ fmap = liftM++instance Applicative (MaybeErr err) where+ pure = Succeeded+ (<*>) = ap++instance Monad (MaybeErr err) where+ Succeeded v >>= k = k v+ Failed e >>= _ = Failed e++isSuccess :: MaybeErr err val -> Bool+isSuccess (Succeeded {}) = True+isSuccess (Failed {}) = False++failME :: err -> MaybeErr err val+failME e = Failed e
+ utils/MonadUtils.hs view
@@ -0,0 +1,204 @@+{-# LANGUAGE CPP #-}++-- | Utilities related to Monad and Applicative classes+-- Mostly for backwards compatibility.++module MonadUtils+ ( Applicative(..)+ , (<$>)++ , MonadFix(..)+ , MonadIO(..)++ , liftIO1, liftIO2, liftIO3, liftIO4++ , zipWith3M, zipWith3M_, zipWith4M, zipWithAndUnzipM+ , mapAndUnzipM, mapAndUnzip3M, mapAndUnzip4M, mapAndUnzip5M+ , mapAccumLM+ , mapSndM+ , concatMapM+ , mapMaybeM+ , fmapMaybeM, fmapEitherM+ , anyM, allM, orM+ , foldlM, foldlM_, foldrM+ , maybeMapM+ , whenM, unlessM+ ) where++-------------------------------------------------------------------------------+-- Imports+-------------------------------------------------------------------------------++import Maybes++import Control.Monad+import Control.Monad.Fix+import Control.Monad.IO.Class+#if __GLASGOW_HASKELL__ < 800+import Control.Monad.Trans.Error () -- for orphan `instance MonadPlus IO`+#endif++-------------------------------------------------------------------------------+-- Lift combinators+-- These are used throughout the compiler+-------------------------------------------------------------------------------++-- | Lift an 'IO' operation with 1 argument into another monad+liftIO1 :: MonadIO m => (a -> IO b) -> a -> m b+liftIO1 = (.) liftIO++-- | Lift an 'IO' operation with 2 arguments into another monad+liftIO2 :: MonadIO m => (a -> b -> IO c) -> a -> b -> m c+liftIO2 = ((.).(.)) liftIO++-- | Lift an 'IO' operation with 3 arguments into another monad+liftIO3 :: MonadIO m => (a -> b -> c -> IO d) -> a -> b -> c -> m d+liftIO3 = ((.).((.).(.))) liftIO++-- | Lift an 'IO' operation with 4 arguments into another monad+liftIO4 :: MonadIO m => (a -> b -> c -> d -> IO e) -> a -> b -> c -> d -> m e+liftIO4 = (((.).(.)).((.).(.))) liftIO++-------------------------------------------------------------------------------+-- Common functions+-- These are used throughout the compiler+-------------------------------------------------------------------------------++zipWith3M :: Monad m => (a -> b -> c -> m d) -> [a] -> [b] -> [c] -> m [d]+zipWith3M _ [] _ _ = return []+zipWith3M _ _ [] _ = return []+zipWith3M _ _ _ [] = return []+zipWith3M f (x:xs) (y:ys) (z:zs)+ = do { r <- f x y z+ ; rs <- zipWith3M f xs ys zs+ ; return $ r:rs+ }++zipWith3M_ :: Monad m => (a -> b -> c -> m d) -> [a] -> [b] -> [c] -> m ()+zipWith3M_ f as bs cs = do { _ <- zipWith3M f as bs cs+ ; return () }++zipWith4M :: Monad m => (a -> b -> c -> d -> m e)+ -> [a] -> [b] -> [c] -> [d] -> m [e]+zipWith4M _ [] _ _ _ = return []+zipWith4M _ _ [] _ _ = return []+zipWith4M _ _ _ [] _ = return []+zipWith4M _ _ _ _ [] = return []+zipWith4M f (x:xs) (y:ys) (z:zs) (a:as)+ = do { r <- f x y z a+ ; rs <- zipWith4M f xs ys zs as+ ; return $ r:rs+ }+++zipWithAndUnzipM :: Monad m+ => (a -> b -> m (c, d)) -> [a] -> [b] -> m ([c], [d])+{-# INLINABLE zipWithAndUnzipM #-}+-- See Note [flatten_many performance] in TcFlatten for why this+-- pragma is essential.+zipWithAndUnzipM f (x:xs) (y:ys)+ = do { (c, d) <- f x y+ ; (cs, ds) <- zipWithAndUnzipM f xs ys+ ; return (c:cs, d:ds) }+zipWithAndUnzipM _ _ _ = return ([], [])++-- | mapAndUnzipM for triples+mapAndUnzip3M :: Monad m => (a -> m (b,c,d)) -> [a] -> m ([b],[c],[d])+mapAndUnzip3M _ [] = return ([],[],[])+mapAndUnzip3M f (x:xs) = do+ (r1, r2, r3) <- f x+ (rs1, rs2, rs3) <- mapAndUnzip3M f xs+ return (r1:rs1, r2:rs2, r3:rs3)++mapAndUnzip4M :: Monad m => (a -> m (b,c,d,e)) -> [a] -> m ([b],[c],[d],[e])+mapAndUnzip4M _ [] = return ([],[],[],[])+mapAndUnzip4M f (x:xs) = do+ (r1, r2, r3, r4) <- f x+ (rs1, rs2, rs3, rs4) <- mapAndUnzip4M f xs+ return (r1:rs1, r2:rs2, r3:rs3, r4:rs4)++mapAndUnzip5M :: Monad m => (a -> m (b,c,d,e,f)) -> [a] -> m ([b],[c],[d],[e],[f])+mapAndUnzip5M _ [] = return ([],[],[],[],[])+mapAndUnzip5M f (x:xs) = do+ (r1, r2, r3, r4, r5) <- f x+ (rs1, rs2, rs3, rs4, rs5) <- mapAndUnzip5M f xs+ return (r1:rs1, r2:rs2, r3:rs3, r4:rs4, r5:rs5)++-- | Monadic version of mapAccumL+mapAccumLM :: Monad m+ => (acc -> x -> m (acc, y)) -- ^ combining function+ -> acc -- ^ initial state+ -> [x] -- ^ inputs+ -> m (acc, [y]) -- ^ final state, outputs+mapAccumLM _ s [] = return (s, [])+mapAccumLM f s (x:xs) = do+ (s1, x') <- f s x+ (s2, xs') <- mapAccumLM f s1 xs+ return (s2, x' : xs')++-- | Monadic version of mapSnd+mapSndM :: Monad m => (b -> m c) -> [(a,b)] -> m [(a,c)]+mapSndM _ [] = return []+mapSndM f ((a,b):xs) = do { c <- f b; rs <- mapSndM f xs; return ((a,c):rs) }++-- | Monadic version of concatMap+concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]+concatMapM f xs = liftM concat (mapM f xs)++-- | Monadic version of mapMaybe+mapMaybeM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]+mapMaybeM f = liftM catMaybes . mapM f++-- | Monadic version of fmap+fmapMaybeM :: (Monad m) => (a -> m b) -> Maybe a -> m (Maybe b)+fmapMaybeM _ Nothing = return Nothing+fmapMaybeM f (Just x) = f x >>= (return . Just)++-- | Monadic version of fmap+fmapEitherM :: Monad m => (a -> m b) -> (c -> m d) -> Either a c -> m (Either b d)+fmapEitherM fl _ (Left a) = fl a >>= (return . Left)+fmapEitherM _ fr (Right b) = fr b >>= (return . Right)++-- | Monadic version of 'any', aborts the computation at the first @True@ value+anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool+anyM _ [] = return False+anyM f (x:xs) = do b <- f x+ if b then return True+ else anyM f xs++-- | Monad version of 'all', aborts the computation at the first @False@ value+allM :: Monad m => (a -> m Bool) -> [a] -> m Bool+allM _ [] = return True+allM f (b:bs) = (f b) >>= (\bv -> if bv then allM f bs else return False)++-- | Monadic version of or+orM :: Monad m => m Bool -> m Bool -> m Bool+orM m1 m2 = m1 >>= \x -> if x then return True else m2++-- | Monadic version of foldl+foldlM :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a+foldlM = foldM++-- | Monadic version of foldl that discards its result+foldlM_ :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m ()+foldlM_ = foldM_++-- | Monadic version of foldr+foldrM :: (Monad m) => (b -> a -> m a) -> a -> [b] -> m a+foldrM _ z [] = return z+foldrM k z (x:xs) = do { r <- foldrM k z xs; k x r }++-- | Monadic version of fmap specialised for Maybe+maybeMapM :: Monad m => (a -> m b) -> (Maybe a -> m (Maybe b))+maybeMapM _ Nothing = return Nothing+maybeMapM m (Just x) = liftM Just $ m x++-- | Monadic version of @when@, taking the condition in the monad+whenM :: Monad m => m Bool -> m () -> m ()+whenM mb thing = do { b <- mb+ ; when b thing }++-- | Monadic version of @unless@, taking the condition in the monad+unlessM :: Monad m => m Bool -> m () -> m ()+unlessM condM acc = do { cond <- condM+ ; unless cond acc }
+ utils/OrdList.hs view
@@ -0,0 +1,128 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1993-1998+++This is useful, general stuff for the Native Code Generator.++Provide trees (of instructions), so that lists of instructions+can be appended in linear time.+-}++{-# LANGUAGE CPP #-}+module OrdList (+ OrdList,+ nilOL, isNilOL, unitOL, appOL, consOL, snocOL, concatOL, lastOL,+ mapOL, fromOL, toOL, foldrOL, foldlOL+) where++import Outputable++#if __GLASGOW_HASKELL__ > 710+import Data.Semigroup ( Semigroup )+import qualified Data.Semigroup as Semigroup+#endif++infixl 5 `appOL`+infixl 5 `snocOL`+infixr 5 `consOL`++data OrdList a+ = None+ | One a+ | Many [a] -- Invariant: non-empty+ | Cons a (OrdList a)+ | Snoc (OrdList a) a+ | Two (OrdList a) -- Invariant: non-empty+ (OrdList a) -- Invariant: non-empty++instance Outputable a => Outputable (OrdList a) where+ ppr ol = ppr (fromOL ol) -- Convert to list and print that++#if __GLASGOW_HASKELL__ > 710+instance Semigroup (OrdList a) where+ (<>) = appOL+#endif++instance Monoid (OrdList a) where+ mempty = nilOL+ mappend = appOL+ mconcat = concatOL++instance Functor OrdList where+ fmap = mapOL++instance Foldable OrdList where+ foldr = foldrOL++instance Traversable OrdList where+ traverse f xs = toOL <$> traverse f (fromOL xs)++nilOL :: OrdList a+isNilOL :: OrdList a -> Bool++unitOL :: a -> OrdList a+snocOL :: OrdList a -> a -> OrdList a+consOL :: a -> OrdList a -> OrdList a+appOL :: OrdList a -> OrdList a -> OrdList a+concatOL :: [OrdList a] -> OrdList a+lastOL :: OrdList a -> a++nilOL = None+unitOL as = One as+snocOL as b = Snoc as b+consOL a bs = Cons a bs+concatOL aas = foldr appOL None aas++lastOL None = panic "lastOL"+lastOL (One a) = a+lastOL (Many as) = last as+lastOL (Cons _ as) = lastOL as+lastOL (Snoc _ a) = a+lastOL (Two _ as) = lastOL as++isNilOL None = True+isNilOL _ = False++None `appOL` b = b+a `appOL` None = a+One a `appOL` b = Cons a b+a `appOL` One b = Snoc a b+a `appOL` b = Two a b++fromOL :: OrdList a -> [a]+fromOL a = go a []+ where go None acc = acc+ go (One a) acc = a : acc+ go (Cons a b) acc = a : go b acc+ go (Snoc a b) acc = go a (b:acc)+ go (Two a b) acc = go a (go b acc)+ go (Many xs) acc = xs ++ acc++mapOL :: (a -> b) -> OrdList a -> OrdList b+mapOL _ None = None+mapOL f (One x) = One (f x)+mapOL f (Cons x xs) = Cons (f x) (mapOL f xs)+mapOL f (Snoc xs x) = Snoc (mapOL f xs) (f x)+mapOL f (Two x y) = Two (mapOL f x) (mapOL f y)+mapOL f (Many xs) = Many (map f xs)++foldrOL :: (a->b->b) -> b -> OrdList a -> b+foldrOL _ z None = z+foldrOL k z (One x) = k x z+foldrOL k z (Cons x xs) = k x (foldrOL k z xs)+foldrOL k z (Snoc xs x) = foldrOL k (k x z) xs+foldrOL k z (Two b1 b2) = foldrOL k (foldrOL k z b2) b1+foldrOL k z (Many xs) = foldr k z xs++foldlOL :: (b->a->b) -> b -> OrdList a -> b+foldlOL _ z None = z+foldlOL k z (One x) = k z x+foldlOL k z (Cons x xs) = foldlOL k (k z x) xs+foldlOL k z (Snoc xs x) = k (foldlOL k z xs) x+foldlOL k z (Two b1 b2) = foldlOL k (foldlOL k z b1) b2+foldlOL k z (Many xs) = foldl k z xs++toOL :: [a] -> OrdList a+toOL [] = None+toOL xs = Many xs
+ utils/Outputable.hs view
@@ -0,0 +1,1194 @@+{-# LANGUAGE CPP, ImplicitParams #-}+{-+(c) The University of Glasgow 2006-2012+(c) The GRASP Project, Glasgow University, 1992-1998+-}++-- | This module defines classes and functions for pretty-printing. It also+-- exports a number of helpful debugging and other utilities such as 'trace' and 'panic'.+--+-- The interface to this module is very similar to the standard Hughes-PJ pretty printing+-- module, except that it exports a number of additional functions that are rarely used,+-- and works over the 'SDoc' type.+module Outputable (+ -- * Type classes+ Outputable(..), OutputableBndr(..),++ -- * Pretty printing combinators+ SDoc, runSDoc, initSDocContext,+ docToSDoc, sdocWithPprDebug,+ interppSP, interpp'SP,+ pprQuotedList, pprWithCommas, quotedListWithOr, quotedListWithNor,+ pprWithBars,+ empty, isEmpty, nest,+ char,+ text, ftext, ptext, ztext,+ int, intWithCommas, integer, float, double, rational, doublePrec,+ parens, cparen, brackets, braces, quotes, quote,+ doubleQuotes, angleBrackets, paBrackets,+ semi, comma, colon, dcolon, space, equals, dot, vbar,+ arrow, larrow, darrow, arrowt, larrowt, arrowtt, larrowtt,+ lparen, rparen, lbrack, rbrack, lbrace, rbrace, underscore,+ blankLine, forAllLit, kindStar, bullet,+ (<>), (<+>), hcat, hsep,+ ($$), ($+$), vcat,+ sep, cat,+ fsep, fcat,+ hang, hangNotEmpty, punctuate, ppWhen, ppUnless,+ speakNth, speakN, speakNOf, plural, isOrAre, doOrDoes,+ unicodeSyntax,++ coloured, keyword,++ -- * Converting 'SDoc' into strings and outputing it+ printSDoc, printSDocLn, printForUser, printForUserPartWay,+ printForC, bufLeftRenderSDoc,+ pprCode, mkCodeStyle,+ showSDoc, showSDocUnsafe, showSDocOneLine,+ showSDocForUser, showSDocDebug, showSDocDump, showSDocDumpOneLine,+ showSDocUnqual, showPpr,+ renderWithStyle,++ pprInfixVar, pprPrefixVar,+ pprHsChar, pprHsString, pprHsBytes,++ primFloatSuffix, primCharSuffix, primWordSuffix, primDoubleSuffix,+ primInt64Suffix, primWord64Suffix, primIntSuffix,++ pprPrimChar, pprPrimInt, pprPrimWord, pprPrimInt64, pprPrimWord64,++ pprFastFilePath,++ -- * Controlling the style in which output is printed+ BindingSite(..),++ PprStyle, CodeStyle(..), PrintUnqualified(..),+ QueryQualifyName, QueryQualifyModule, QueryQualifyPackage,+ reallyAlwaysQualify, reallyAlwaysQualifyNames,+ alwaysQualify, alwaysQualifyNames, alwaysQualifyModules,+ neverQualify, neverQualifyNames, neverQualifyModules,+ alwaysQualifyPackages, neverQualifyPackages,+ QualifyName(..), queryQual,+ sdocWithDynFlags, sdocWithPlatform,+ getPprStyle, withPprStyle, withPprStyleDoc, setStyleColoured,+ pprDeeper, pprDeeperList, pprSetDepth,+ codeStyle, userStyle, debugStyle, dumpStyle, asmStyle,+ ifPprDebug, qualName, qualModule, qualPackage,+ mkErrStyle, defaultErrStyle, defaultDumpStyle, mkDumpStyle, defaultUserStyle,+ mkUserStyle, cmdlineParserStyle, Depth(..),++ -- * Error handling and debugging utilities+ pprPanic, pprSorry, assertPprPanic, pprPgmError,+ pprTrace, pprTraceDebug, pprTraceIt, warnPprTrace, pprSTrace,+ trace, pgmError, panic, sorry, assertPanic,+ pprDebugAndThen, callStackDoc+ ) where++import {-# SOURCE #-} DynFlags( DynFlags, hasPprDebug, hasNoDebugOutput,+ targetPlatform, pprUserLength, pprCols,+ useUnicode, useUnicodeSyntax,+ shouldUseColor, unsafeGlobalDynFlags )+import {-# SOURCE #-} Module( UnitId, Module, ModuleName, moduleName )+import {-# SOURCE #-} OccName( OccName )++import BufWrite (BufHandle)+import FastString+import qualified Pretty+import Util+import Platform+import qualified PprColour as Col+import Pretty ( Doc, Mode(..) )+import Panic+import GHC.Serialized+import GHC.LanguageExtensions (Extension)++import Control.Exception (finally)+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import Data.Char+import qualified Data.Map as M+import Data.Int+import qualified Data.IntMap as IM+import Data.Set (Set)+import qualified Data.Set as Set+import Data.String+import Data.Word+import System.IO ( Handle )+import System.FilePath+import Text.Printf+import Numeric (showFFloat)+import Data.Graph (SCC(..))+import Data.List (intersperse)++import GHC.Fingerprint+import GHC.Show ( showMultiLineString )++{-+************************************************************************+* *+\subsection{The @PprStyle@ data type}+* *+************************************************************************+-}++data PprStyle+ = PprUser PrintUnqualified Depth Coloured+ -- Pretty-print in a way that will make sense to the+ -- ordinary user; must be very close to Haskell+ -- syntax, etc.+ -- Assumes printing tidied code: non-system names are+ -- printed without uniques.++ | PprDump PrintUnqualified+ -- For -ddump-foo; less verbose than PprDebug, but more than PprUser+ -- Does not assume tidied code: non-external names+ -- are printed with uniques.++ | PprDebug -- Full debugging output++ | PprCode CodeStyle+ -- Print code; either C or assembler++data CodeStyle = CStyle -- The format of labels differs for C and assembler+ | AsmStyle++data Depth = AllTheWay+ | PartWay Int -- 0 => stop++data Coloured+ = Uncoloured+ | Coloured++-- -----------------------------------------------------------------------------+-- Printing original names++-- | When printing code that contains original names, we need to map the+-- original names back to something the user understands. This is the+-- purpose of the triple of functions that gets passed around+-- when rendering 'SDoc'.+data PrintUnqualified = QueryQualify {+ queryQualifyName :: QueryQualifyName,+ queryQualifyModule :: QueryQualifyModule,+ queryQualifyPackage :: QueryQualifyPackage+}++-- | given an /original/ name, this function tells you which module+-- name it should be qualified with when printing for the user, if+-- any. For example, given @Control.Exception.catch@, which is in scope+-- as @Exception.catch@, this function will return @Just "Exception"@.+-- Note that the return value is a ModuleName, not a Module, because+-- in source code, names are qualified by ModuleNames.+type QueryQualifyName = Module -> OccName -> QualifyName++-- | For a given module, we need to know whether to print it with+-- a package name to disambiguate it.+type QueryQualifyModule = Module -> Bool++-- | For a given package, we need to know whether to print it with+-- the component id to disambiguate it.+type QueryQualifyPackage = UnitId -> Bool++-- See Note [Printing original names] in HscTypes+data QualifyName -- Given P:M.T+ = NameUnqual -- It's in scope unqualified as "T"+ -- OR nothing called "T" is in scope++ | NameQual ModuleName -- It's in scope qualified as "X.T"++ | NameNotInScope1 -- It's not in scope at all, but M.T is not bound+ -- in the current scope, so we can refer to it as "M.T"++ | NameNotInScope2 -- It's not in scope at all, and M.T is already bound in+ -- the current scope, so we must refer to it as "P:M.T"++instance Outputable QualifyName where+ ppr NameUnqual = text "NameUnqual"+ ppr (NameQual _mod) = text "NameQual" -- can't print the mod without module loops :(+ ppr NameNotInScope1 = text "NameNotInScope1"+ ppr NameNotInScope2 = text "NameNotInScope2"++reallyAlwaysQualifyNames :: QueryQualifyName+reallyAlwaysQualifyNames _ _ = NameNotInScope2++-- | NB: This won't ever show package IDs+alwaysQualifyNames :: QueryQualifyName+alwaysQualifyNames m _ = NameQual (moduleName m)++neverQualifyNames :: QueryQualifyName+neverQualifyNames _ _ = NameUnqual++alwaysQualifyModules :: QueryQualifyModule+alwaysQualifyModules _ = True++neverQualifyModules :: QueryQualifyModule+neverQualifyModules _ = False++alwaysQualifyPackages :: QueryQualifyPackage+alwaysQualifyPackages _ = True++neverQualifyPackages :: QueryQualifyPackage+neverQualifyPackages _ = False++reallyAlwaysQualify, alwaysQualify, neverQualify :: PrintUnqualified+reallyAlwaysQualify+ = QueryQualify reallyAlwaysQualifyNames+ alwaysQualifyModules+ alwaysQualifyPackages+alwaysQualify = QueryQualify alwaysQualifyNames+ alwaysQualifyModules+ alwaysQualifyPackages+neverQualify = QueryQualify neverQualifyNames+ neverQualifyModules+ neverQualifyPackages++defaultUserStyle :: DynFlags -> PprStyle+defaultUserStyle dflags = mkUserStyle dflags neverQualify AllTheWay++defaultDumpStyle :: DynFlags -> PprStyle+ -- Print without qualifiers to reduce verbosity, unless -dppr-debug+defaultDumpStyle dflags+ | hasPprDebug dflags = PprDebug+ | otherwise = PprDump neverQualify++mkDumpStyle :: DynFlags -> PrintUnqualified -> PprStyle+mkDumpStyle dflags print_unqual+ | hasPprDebug dflags = PprDebug+ | otherwise = PprDump print_unqual++defaultErrStyle :: DynFlags -> PprStyle+-- Default style for error messages, when we don't know PrintUnqualified+-- It's a bit of a hack because it doesn't take into account what's in scope+-- Only used for desugarer warnings, and typechecker errors in interface sigs+-- NB that -dppr-debug will still get into PprDebug style+defaultErrStyle dflags = mkErrStyle dflags neverQualify++-- | Style for printing error messages+mkErrStyle :: DynFlags -> PrintUnqualified -> PprStyle+mkErrStyle dflags qual =+ mkUserStyle dflags qual (PartWay (pprUserLength dflags))++cmdlineParserStyle :: DynFlags -> PprStyle+cmdlineParserStyle dflags = mkUserStyle dflags alwaysQualify AllTheWay++mkUserStyle :: DynFlags -> PrintUnqualified -> Depth -> PprStyle+mkUserStyle dflags unqual depth+ | hasPprDebug dflags = PprDebug+ | otherwise = PprUser unqual depth Uncoloured++setStyleColoured :: Bool -> PprStyle -> PprStyle+setStyleColoured col style =+ case style of+ PprUser q d _ -> PprUser q d c+ _ -> style+ where+ c | col = Coloured+ | otherwise = Uncoloured++instance Outputable PprStyle where+ ppr (PprUser {}) = text "user-style"+ ppr (PprCode {}) = text "code-style"+ ppr (PprDump {}) = text "dump-style"+ ppr (PprDebug {}) = text "debug-style"++{-+Orthogonal to the above printing styles are (possibly) some+command-line flags that affect printing (often carried with the+style). The most likely ones are variations on how much type info is+shown.++The following test decides whether or not we are actually generating+code (either C or assembly), or generating interface files.++************************************************************************+* *+\subsection{The @SDoc@ data type}+* *+************************************************************************+-}++-- | Represents a pretty-printable document.+--+-- To display an 'SDoc', use 'printSDoc', 'printSDocLn', 'bufLeftRenderSDoc',+-- or 'renderWithStyle'. Avoid calling 'runSDoc' directly as it breaks the+-- abstraction layer.+newtype SDoc = SDoc { runSDoc :: SDocContext -> Doc }++data SDocContext = SDC+ { sdocStyle :: !PprStyle+ , sdocLastColour :: !Col.PprColour+ -- ^ The most recently used colour. This allows nesting colours.+ , sdocDynFlags :: !DynFlags+ }++instance IsString SDoc where+ fromString = text++initSDocContext :: DynFlags -> PprStyle -> SDocContext+initSDocContext dflags sty = SDC+ { sdocStyle = sty+ , sdocLastColour = Col.colReset+ , sdocDynFlags = dflags+ }++withPprStyle :: PprStyle -> SDoc -> SDoc+withPprStyle sty d = SDoc $ \ctxt -> runSDoc d ctxt{sdocStyle=sty}++-- | This is not a recommended way to render 'SDoc', since it breaks the+-- abstraction layer of 'SDoc'. Prefer to use 'printSDoc', 'printSDocLn',+-- 'bufLeftRenderSDoc', or 'renderWithStyle' instead.+withPprStyleDoc :: DynFlags -> PprStyle -> SDoc -> Doc+withPprStyleDoc dflags sty d = runSDoc d (initSDocContext dflags sty)++sdocWithPprDebug :: (Bool -> SDoc) -> SDoc+sdocWithPprDebug f = sdocWithDynFlags $ \dflags -> f (hasPprDebug dflags)++pprDeeper :: SDoc -> SDoc+pprDeeper d = SDoc $ \ctx -> case ctx of+ SDC{sdocStyle=PprUser _ (PartWay 0) _} -> Pretty.text "..."+ SDC{sdocStyle=PprUser q (PartWay n) c} ->+ runSDoc d ctx{sdocStyle = PprUser q (PartWay (n-1)) c}+ _ -> runSDoc d ctx++-- | Truncate a list that is longer than the current depth.+pprDeeperList :: ([SDoc] -> SDoc) -> [SDoc] -> SDoc+pprDeeperList f ds+ | null ds = f []+ | otherwise = SDoc work+ where+ work ctx@SDC{sdocStyle=PprUser q (PartWay n) c}+ | n==0 = Pretty.text "..."+ | otherwise =+ runSDoc (f (go 0 ds)) ctx{sdocStyle = PprUser q (PartWay (n-1)) c}+ where+ go _ [] = []+ go i (d:ds) | i >= n = [text "...."]+ | otherwise = d : go (i+1) ds+ work other_ctx = runSDoc (f ds) other_ctx++pprSetDepth :: Depth -> SDoc -> SDoc+pprSetDepth depth doc = SDoc $ \ctx ->+ case ctx of+ SDC{sdocStyle=PprUser q _ c} ->+ runSDoc doc ctx{sdocStyle = PprUser q depth c}+ _ ->+ runSDoc doc ctx++getPprStyle :: (PprStyle -> SDoc) -> SDoc+getPprStyle df = SDoc $ \ctx -> runSDoc (df (sdocStyle ctx)) ctx++sdocWithDynFlags :: (DynFlags -> SDoc) -> SDoc+sdocWithDynFlags f = SDoc $ \ctx -> runSDoc (f (sdocDynFlags ctx)) ctx++sdocWithPlatform :: (Platform -> SDoc) -> SDoc+sdocWithPlatform f = sdocWithDynFlags (f . targetPlatform)++qualName :: PprStyle -> QueryQualifyName+qualName (PprUser q _ _) mod occ = queryQualifyName q mod occ+qualName (PprDump q) mod occ = queryQualifyName q mod occ+qualName _other mod _ = NameQual (moduleName mod)++qualModule :: PprStyle -> QueryQualifyModule+qualModule (PprUser q _ _) m = queryQualifyModule q m+qualModule (PprDump q) m = queryQualifyModule q m+qualModule _other _m = True++qualPackage :: PprStyle -> QueryQualifyPackage+qualPackage (PprUser q _ _) m = queryQualifyPackage q m+qualPackage (PprDump q) m = queryQualifyPackage q m+qualPackage _other _m = True++queryQual :: PprStyle -> PrintUnqualified+queryQual s = QueryQualify (qualName s)+ (qualModule s)+ (qualPackage s)++codeStyle :: PprStyle -> Bool+codeStyle (PprCode _) = True+codeStyle _ = False++asmStyle :: PprStyle -> Bool+asmStyle (PprCode AsmStyle) = True+asmStyle _other = False++dumpStyle :: PprStyle -> Bool+dumpStyle (PprDump {}) = True+dumpStyle _other = False++debugStyle :: PprStyle -> Bool+debugStyle PprDebug = True+debugStyle _other = False++userStyle :: PprStyle -> Bool+userStyle (PprUser {}) = True+userStyle _other = False++ifPprDebug :: SDoc -> SDoc -- Empty for non-debug style+ifPprDebug d = SDoc $ \ctx ->+ case ctx of+ SDC{sdocStyle=PprDebug} -> runSDoc d ctx+ _ -> Pretty.empty++-- | The analog of 'Pretty.printDoc_' for 'SDoc', which tries to make sure the+-- terminal doesn't get screwed up by the ANSI color codes if an exception+-- is thrown during pretty-printing.+printSDoc :: Mode -> DynFlags -> Handle -> PprStyle -> SDoc -> IO ()+printSDoc mode dflags handle sty doc =+ Pretty.printDoc_ mode cols handle (runSDoc doc ctx)+ `finally`+ Pretty.printDoc_ mode cols handle+ (runSDoc (coloured Col.colReset empty) ctx)+ where+ cols = pprCols dflags+ ctx = initSDocContext dflags sty++-- | Like 'printSDoc' but appends an extra newline.+printSDocLn :: Mode -> DynFlags -> Handle -> PprStyle -> SDoc -> IO ()+printSDocLn mode dflags handle sty doc =+ printSDoc mode dflags handle sty (doc $$ text "")++printForUser :: DynFlags -> Handle -> PrintUnqualified -> SDoc -> IO ()+printForUser dflags handle unqual doc+ = printSDocLn PageMode dflags handle+ (mkUserStyle dflags unqual AllTheWay) doc++printForUserPartWay :: DynFlags -> Handle -> Int -> PrintUnqualified -> SDoc+ -> IO ()+printForUserPartWay dflags handle d unqual doc+ = printSDocLn PageMode dflags handle+ (mkUserStyle dflags unqual (PartWay d)) doc++-- | Like 'printSDocLn' but specialized with 'LeftMode' and+-- @'PprCode' 'CStyle'@. This is typically used to output C-- code.+printForC :: DynFlags -> Handle -> SDoc -> IO ()+printForC dflags handle doc =+ printSDocLn LeftMode dflags handle (PprCode CStyle) doc++-- | An efficient variant of 'printSDoc' specialized for 'LeftMode' that+-- outputs to a 'BufHandle'.+bufLeftRenderSDoc :: DynFlags -> BufHandle -> PprStyle -> SDoc -> IO ()+bufLeftRenderSDoc dflags bufHandle sty doc =+ Pretty.bufLeftRender bufHandle (runSDoc doc (initSDocContext dflags sty))++pprCode :: CodeStyle -> SDoc -> SDoc+pprCode cs d = withPprStyle (PprCode cs) d++mkCodeStyle :: CodeStyle -> PprStyle+mkCodeStyle = PprCode++-- Can't make SDoc an instance of Show because SDoc is just a function type+-- However, Doc *is* an instance of Show+-- showSDoc just blasts it out as a string+showSDoc :: DynFlags -> SDoc -> String+showSDoc dflags sdoc = renderWithStyle dflags sdoc (defaultUserStyle dflags)++-- showSDocUnsafe is unsafe, because `unsafeGlobalDynFlags` might not be+-- initialised yet.+showSDocUnsafe :: SDoc -> String+showSDocUnsafe sdoc = showSDoc unsafeGlobalDynFlags sdoc++showPpr :: Outputable a => DynFlags -> a -> String+showPpr dflags thing = showSDoc dflags (ppr thing)++showSDocUnqual :: DynFlags -> SDoc -> String+-- Only used by Haddock+showSDocUnqual dflags sdoc = showSDoc dflags sdoc++showSDocForUser :: DynFlags -> PrintUnqualified -> SDoc -> String+-- Allows caller to specify the PrintUnqualified to use+showSDocForUser dflags unqual doc+ = renderWithStyle dflags doc (mkUserStyle dflags unqual AllTheWay)++showSDocDump :: DynFlags -> SDoc -> String+showSDocDump dflags d = renderWithStyle dflags d (defaultDumpStyle dflags)++showSDocDebug :: DynFlags -> SDoc -> String+showSDocDebug dflags d = renderWithStyle dflags d PprDebug++renderWithStyle :: DynFlags -> SDoc -> PprStyle -> String+renderWithStyle dflags sdoc sty+ = let s = Pretty.style{ Pretty.mode = PageMode,+ Pretty.lineLength = pprCols dflags }+ in Pretty.renderStyle s $ runSDoc sdoc (initSDocContext dflags sty)++-- This shows an SDoc, but on one line only. It's cheaper than a full+-- showSDoc, designed for when we're getting results like "Foo.bar"+-- and "foo{uniq strictness}" so we don't want fancy layout anyway.+showSDocOneLine :: DynFlags -> SDoc -> String+showSDocOneLine dflags d+ = let s = Pretty.style{ Pretty.mode = OneLineMode,+ Pretty.lineLength = pprCols dflags } in+ Pretty.renderStyle s $+ runSDoc d (initSDocContext dflags (defaultUserStyle dflags))++showSDocDumpOneLine :: DynFlags -> SDoc -> String+showSDocDumpOneLine dflags d+ = let s = Pretty.style{ Pretty.mode = OneLineMode,+ Pretty.lineLength = irrelevantNCols } in+ Pretty.renderStyle s $+ runSDoc d (initSDocContext dflags (defaultDumpStyle dflags))++irrelevantNCols :: Int+-- Used for OneLineMode and LeftMode when number of cols isn't used+irrelevantNCols = 1++isEmpty :: DynFlags -> SDoc -> Bool+isEmpty dflags sdoc = Pretty.isEmpty $ runSDoc sdoc dummySDocContext+ where dummySDocContext = initSDocContext dflags PprDebug++docToSDoc :: Doc -> SDoc+docToSDoc d = SDoc (\_ -> d)++empty :: SDoc+char :: Char -> SDoc+text :: String -> SDoc+ftext :: FastString -> SDoc+ptext :: LitString -> SDoc+ztext :: FastZString -> SDoc+int :: Int -> SDoc+integer :: Integer -> SDoc+float :: Float -> SDoc+double :: Double -> SDoc+rational :: Rational -> SDoc++empty = docToSDoc $ Pretty.empty+char c = docToSDoc $ Pretty.char c++text s = docToSDoc $ Pretty.text s+{-# INLINE text #-} -- Inline so that the RULE Pretty.text will fire++ftext s = docToSDoc $ Pretty.ftext s+ptext s = docToSDoc $ Pretty.ptext s+ztext s = docToSDoc $ Pretty.ztext s+int n = docToSDoc $ Pretty.int n+integer n = docToSDoc $ Pretty.integer n+float n = docToSDoc $ Pretty.float n+double n = docToSDoc $ Pretty.double n+rational n = docToSDoc $ Pretty.rational n++-- | @doublePrec p n@ shows a floating point number @n@ with @p@+-- digits of precision after the decimal point.+doublePrec :: Int -> Double -> SDoc+doublePrec p n = text (showFFloat (Just p) n "")++parens, braces, brackets, quotes, quote,+ paBrackets, doubleQuotes, angleBrackets :: SDoc -> SDoc++parens d = SDoc $ Pretty.parens . runSDoc d+braces d = SDoc $ Pretty.braces . runSDoc d+brackets d = SDoc $ Pretty.brackets . runSDoc d+quote d = SDoc $ Pretty.quote . runSDoc d+doubleQuotes d = SDoc $ Pretty.doubleQuotes . runSDoc d+angleBrackets d = char '<' <> d <> char '>'+paBrackets d = text "[:" <> d <> text ":]"++cparen :: Bool -> SDoc -> SDoc+cparen b d = SDoc $ Pretty.maybeParens b . runSDoc d++-- 'quotes' encloses something in single quotes...+-- but it omits them if the thing begins or ends in a single quote+-- so that we don't get `foo''. Instead we just have foo'.+quotes d =+ sdocWithDynFlags $ \dflags ->+ if useUnicode dflags+ then char '‘' <> d <> char '’'+ else SDoc $ \sty ->+ let pp_d = runSDoc d sty+ str = show pp_d+ in case (str, snocView str) of+ (_, Just (_, '\'')) -> pp_d+ ('\'' : _, _) -> pp_d+ _other -> Pretty.quotes pp_d++semi, comma, colon, equals, space, dcolon, underscore, dot, vbar :: SDoc+arrow, larrow, darrow, arrowt, larrowt, arrowtt, larrowtt :: SDoc+lparen, rparen, lbrack, rbrack, lbrace, rbrace, blankLine :: SDoc++blankLine = docToSDoc $ Pretty.text ""+dcolon = unicodeSyntax (char '∷') (docToSDoc $ Pretty.text "::")+arrow = unicodeSyntax (char '→') (docToSDoc $ Pretty.text "->")+larrow = unicodeSyntax (char '←') (docToSDoc $ Pretty.text "<-")+darrow = unicodeSyntax (char '⇒') (docToSDoc $ Pretty.text "=>")+arrowt = unicodeSyntax (char '⤚') (docToSDoc $ Pretty.text ">-")+larrowt = unicodeSyntax (char '⤙') (docToSDoc $ Pretty.text "-<")+arrowtt = unicodeSyntax (char '⤜') (docToSDoc $ Pretty.text ">>-")+larrowtt = unicodeSyntax (char '⤛') (docToSDoc $ Pretty.text "-<<")+semi = docToSDoc $ Pretty.semi+comma = docToSDoc $ Pretty.comma+colon = docToSDoc $ Pretty.colon+equals = docToSDoc $ Pretty.equals+space = docToSDoc $ Pretty.space+underscore = char '_'+dot = char '.'+vbar = char '|'+lparen = docToSDoc $ Pretty.lparen+rparen = docToSDoc $ Pretty.rparen+lbrack = docToSDoc $ Pretty.lbrack+rbrack = docToSDoc $ Pretty.rbrack+lbrace = docToSDoc $ Pretty.lbrace+rbrace = docToSDoc $ Pretty.rbrace++forAllLit :: SDoc+forAllLit = unicodeSyntax (char '∀') (text "forall")++kindStar :: SDoc+kindStar = unicodeSyntax (char '★') (char '*')++bullet :: SDoc+bullet = unicode (char '•') (char '*')++unicodeSyntax :: SDoc -> SDoc -> SDoc+unicodeSyntax unicode plain = sdocWithDynFlags $ \dflags ->+ if useUnicode dflags && useUnicodeSyntax dflags+ then unicode+ else plain++unicode :: SDoc -> SDoc -> SDoc+unicode unicode plain = sdocWithDynFlags $ \dflags ->+ if useUnicode dflags+ then unicode+ else plain++nest :: Int -> SDoc -> SDoc+-- ^ Indent 'SDoc' some specified amount+(<>) :: SDoc -> SDoc -> SDoc+-- ^ Join two 'SDoc' together horizontally without a gap+(<+>) :: SDoc -> SDoc -> SDoc+-- ^ Join two 'SDoc' together horizontally with a gap between them+($$) :: SDoc -> SDoc -> SDoc+-- ^ Join two 'SDoc' together vertically; if there is+-- no vertical overlap it "dovetails" the two onto one line+($+$) :: SDoc -> SDoc -> SDoc+-- ^ Join two 'SDoc' together vertically++nest n d = SDoc $ Pretty.nest n . runSDoc d+(<>) d1 d2 = SDoc $ \sty -> (Pretty.<>) (runSDoc d1 sty) (runSDoc d2 sty)+(<+>) d1 d2 = SDoc $ \sty -> (Pretty.<+>) (runSDoc d1 sty) (runSDoc d2 sty)+($$) d1 d2 = SDoc $ \sty -> (Pretty.$$) (runSDoc d1 sty) (runSDoc d2 sty)+($+$) d1 d2 = SDoc $ \sty -> (Pretty.$+$) (runSDoc d1 sty) (runSDoc d2 sty)++hcat :: [SDoc] -> SDoc+-- ^ Concatenate 'SDoc' horizontally+hsep :: [SDoc] -> SDoc+-- ^ Concatenate 'SDoc' horizontally with a space between each one+vcat :: [SDoc] -> SDoc+-- ^ Concatenate 'SDoc' vertically with dovetailing+sep :: [SDoc] -> SDoc+-- ^ Separate: is either like 'hsep' or like 'vcat', depending on what fits+cat :: [SDoc] -> SDoc+-- ^ Catenate: is either like 'hcat' or like 'vcat', depending on what fits+fsep :: [SDoc] -> SDoc+-- ^ A paragraph-fill combinator. It's much like sep, only it+-- keeps fitting things on one line until it can't fit any more.+fcat :: [SDoc] -> SDoc+-- ^ This behaves like 'fsep', but it uses '<>' for horizontal conposition rather than '<+>'+++hcat ds = SDoc $ \sty -> Pretty.hcat [runSDoc d sty | d <- ds]+hsep ds = SDoc $ \sty -> Pretty.hsep [runSDoc d sty | d <- ds]+vcat ds = SDoc $ \sty -> Pretty.vcat [runSDoc d sty | d <- ds]+sep ds = SDoc $ \sty -> Pretty.sep [runSDoc d sty | d <- ds]+cat ds = SDoc $ \sty -> Pretty.cat [runSDoc d sty | d <- ds]+fsep ds = SDoc $ \sty -> Pretty.fsep [runSDoc d sty | d <- ds]+fcat ds = SDoc $ \sty -> Pretty.fcat [runSDoc d sty | d <- ds]++hang :: SDoc -- ^ The header+ -> Int -- ^ Amount to indent the hung body+ -> SDoc -- ^ The hung body, indented and placed below the header+ -> SDoc+hang d1 n d2 = SDoc $ \sty -> Pretty.hang (runSDoc d1 sty) n (runSDoc d2 sty)++-- | This behaves like 'hang', but does not indent the second document+-- when the header is empty.+hangNotEmpty :: SDoc -> Int -> SDoc -> SDoc+hangNotEmpty d1 n d2 =+ SDoc $ \sty -> Pretty.hangNotEmpty (runSDoc d1 sty) n (runSDoc d2 sty)++punctuate :: SDoc -- ^ The punctuation+ -> [SDoc] -- ^ The list that will have punctuation added between every adjacent pair of elements+ -> [SDoc] -- ^ Punctuated list+punctuate _ [] = []+punctuate p (d:ds) = go d ds+ where+ go d [] = [d]+ go d (e:es) = (d <> p) : go e es++ppWhen, ppUnless :: Bool -> SDoc -> SDoc+ppWhen True doc = doc+ppWhen False _ = empty++ppUnless True _ = empty+ppUnless False doc = doc++-- | Apply the given colour\/style for the argument.+--+-- Only takes effect if colours are enabled.+coloured :: Col.PprColour -> SDoc -> SDoc+coloured col sdoc =+ sdocWithDynFlags $ \dflags ->+ if shouldUseColor dflags+ then SDoc $ \ctx@SDC{ sdocLastColour = lastCol } ->+ case ctx of+ SDC{ sdocStyle = PprUser _ _ Coloured } ->+ let ctx' = ctx{ sdocLastColour = lastCol `mappend` col } in+ Pretty.zeroWidthText (Col.renderColour col)+ Pretty.<> runSDoc sdoc ctx'+ Pretty.<> Pretty.zeroWidthText (Col.renderColourAfresh lastCol)+ _ -> runSDoc sdoc ctx+ else sdoc++keyword :: SDoc -> SDoc+keyword = coloured Col.colBold++{-+************************************************************************+* *+\subsection[Outputable-class]{The @Outputable@ class}+* *+************************************************************************+-}++-- | Class designating that some type has an 'SDoc' representation+class Outputable a where+ ppr :: a -> SDoc+ pprPrec :: Rational -> a -> SDoc+ -- 0 binds least tightly+ -- We use Rational because there is always a+ -- Rational between any other two Rationals++ ppr = pprPrec 0+ pprPrec _ = ppr++instance Outputable Char where+ ppr c = text [c]++instance Outputable Bool where+ ppr True = text "True"+ ppr False = text "False"++instance Outputable Ordering where+ ppr LT = text "LT"+ ppr EQ = text "EQ"+ ppr GT = text "GT"++instance Outputable Int32 where+ ppr n = integer $ fromIntegral n++instance Outputable Int64 where+ ppr n = integer $ fromIntegral n++instance Outputable Int where+ ppr n = int n++instance Outputable Word16 where+ ppr n = integer $ fromIntegral n++instance Outputable Word32 where+ ppr n = integer $ fromIntegral n++instance Outputable Word where+ ppr n = integer $ fromIntegral n++instance Outputable () where+ ppr _ = text "()"++instance (Outputable a) => Outputable [a] where+ ppr xs = brackets (fsep (punctuate comma (map ppr xs)))++instance (Outputable a) => Outputable (Set a) where+ ppr s = braces (fsep (punctuate comma (map ppr (Set.toList s))))++instance (Outputable a, Outputable b) => Outputable (a, b) where+ ppr (x,y) = parens (sep [ppr x <> comma, ppr y])++instance Outputable a => Outputable (Maybe a) where+ ppr Nothing = text "Nothing"+ ppr (Just x) = text "Just" <+> ppr x++instance (Outputable a, Outputable b) => Outputable (Either a b) where+ ppr (Left x) = text "Left" <+> ppr x+ ppr (Right y) = text "Right" <+> ppr y++-- ToDo: may not be used+instance (Outputable a, Outputable b, Outputable c) => Outputable (a, b, c) where+ ppr (x,y,z) =+ parens (sep [ppr x <> comma,+ ppr y <> comma,+ ppr z ])++instance (Outputable a, Outputable b, Outputable c, Outputable d) =>+ Outputable (a, b, c, d) where+ ppr (a,b,c,d) =+ parens (sep [ppr a <> comma,+ ppr b <> comma,+ ppr c <> comma,+ ppr d])++instance (Outputable a, Outputable b, Outputable c, Outputable d, Outputable e) =>+ Outputable (a, b, c, d, e) where+ ppr (a,b,c,d,e) =+ parens (sep [ppr a <> comma,+ ppr b <> comma,+ ppr c <> comma,+ ppr d <> comma,+ ppr e])++instance (Outputable a, Outputable b, Outputable c, Outputable d, Outputable e, Outputable f) =>+ Outputable (a, b, c, d, e, f) where+ ppr (a,b,c,d,e,f) =+ parens (sep [ppr a <> comma,+ ppr b <> comma,+ ppr c <> comma,+ ppr d <> comma,+ ppr e <> comma,+ ppr f])++instance (Outputable a, Outputable b, Outputable c, Outputable d, Outputable e, Outputable f, Outputable g) =>+ Outputable (a, b, c, d, e, f, g) where+ ppr (a,b,c,d,e,f,g) =+ parens (sep [ppr a <> comma,+ ppr b <> comma,+ ppr c <> comma,+ ppr d <> comma,+ ppr e <> comma,+ ppr f <> comma,+ ppr g])++instance Outputable FastString where+ ppr fs = ftext fs -- Prints an unadorned string,+ -- no double quotes or anything++instance (Outputable key, Outputable elt) => Outputable (M.Map key elt) where+ ppr m = ppr (M.toList m)+instance (Outputable elt) => Outputable (IM.IntMap elt) where+ ppr m = ppr (IM.toList m)++instance Outputable Fingerprint where+ ppr (Fingerprint w1 w2) = text (printf "%016x%016x" w1 w2)++instance Outputable a => Outputable (SCC a) where+ ppr (AcyclicSCC v) = text "NONREC" $$ (nest 3 (ppr v))+ ppr (CyclicSCC vs) = text "REC" $$ (nest 3 (vcat (map ppr vs)))++instance Outputable Serialized where+ ppr (Serialized the_type bytes) = int (length bytes) <+> text "of type" <+> text (show the_type)++instance Outputable Extension where+ ppr = text . show++{-+************************************************************************+* *+\subsection{The @OutputableBndr@ class}+* *+************************************************************************+-}++-- | 'BindingSite' is used to tell the thing that prints binder what+-- language construct is binding the identifier. This can be used+-- to decide how much info to print.+-- Also see Note [Binding-site specific printing] in PprCore+data BindingSite+ = LambdaBind -- ^ The x in (\x. e)+ | CaseBind -- ^ The x in case scrut of x { (y,z) -> ... }+ | CasePatBind -- ^ The y,z in case scrut of x { (y,z) -> ... }+ | LetBind -- ^ The x in (let x = rhs in e)++-- | When we print a binder, we often want to print its type too.+-- The @OutputableBndr@ class encapsulates this idea.+class Outputable a => OutputableBndr a where+ pprBndr :: BindingSite -> a -> SDoc+ pprBndr _b x = ppr x++ pprPrefixOcc, pprInfixOcc :: a -> SDoc+ -- Print an occurrence of the name, suitable either in the+ -- prefix position of an application, thus (f a b) or ((+) x)+ -- or infix position, thus (a `f` b) or (x + y)++ bndrIsJoin_maybe :: a -> Maybe Int+ bndrIsJoin_maybe _ = Nothing+ -- When pretty-printing we sometimes want to find+ -- whether the binder is a join point. You might think+ -- we could have a function of type (a->Var), but Var+ -- isn't available yet, alas++{-+************************************************************************+* *+\subsection{Random printing helpers}+* *+************************************************************************+-}++-- We have 31-bit Chars and will simply use Show instances of Char and String.++-- | Special combinator for showing character literals.+pprHsChar :: Char -> SDoc+pprHsChar c | c > '\x10ffff' = char '\\' <> text (show (fromIntegral (ord c) :: Word32))+ | otherwise = text (show c)++-- | Special combinator for showing string literals.+pprHsString :: FastString -> SDoc+pprHsString fs = vcat (map text (showMultiLineString (unpackFS fs)))++-- | Special combinator for showing bytestring literals.+pprHsBytes :: ByteString -> SDoc+pprHsBytes bs = let escaped = concatMap escape $ BS.unpack bs+ in vcat (map text (showMultiLineString escaped)) <> char '#'+ where escape :: Word8 -> String+ escape w = let c = chr (fromIntegral w)+ in if isAscii c+ then [c]+ else '\\' : show w++-- Postfix modifiers for unboxed literals.+-- See Note [Printing of literals in Core] in `basicTypes/Literal.hs`.+primCharSuffix, primFloatSuffix, primIntSuffix :: SDoc+primDoubleSuffix, primWordSuffix, primInt64Suffix, primWord64Suffix :: SDoc+primCharSuffix = char '#'+primFloatSuffix = char '#'+primIntSuffix = char '#'+primDoubleSuffix = text "##"+primWordSuffix = text "##"+primInt64Suffix = text "L#"+primWord64Suffix = text "L##"++-- | Special combinator for showing unboxed literals.+pprPrimChar :: Char -> SDoc+pprPrimInt, pprPrimWord, pprPrimInt64, pprPrimWord64 :: Integer -> SDoc+pprPrimChar c = pprHsChar c <> primCharSuffix+pprPrimInt i = integer i <> primIntSuffix+pprPrimWord w = integer w <> primWordSuffix+pprPrimInt64 i = integer i <> primInt64Suffix+pprPrimWord64 w = integer w <> primWord64Suffix++---------------------+-- Put a name in parens if it's an operator+pprPrefixVar :: Bool -> SDoc -> SDoc+pprPrefixVar is_operator pp_v+ | is_operator = parens pp_v+ | otherwise = pp_v++-- Put a name in backquotes if it's not an operator+pprInfixVar :: Bool -> SDoc -> SDoc+pprInfixVar is_operator pp_v+ | is_operator = pp_v+ | otherwise = char '`' <> pp_v <> char '`'++---------------------+pprFastFilePath :: FastString -> SDoc+pprFastFilePath path = text $ normalise $ unpackFS path++{-+************************************************************************+* *+\subsection{Other helper functions}+* *+************************************************************************+-}++pprWithCommas :: (a -> SDoc) -- ^ The pretty printing function to use+ -> [a] -- ^ The things to be pretty printed+ -> SDoc -- ^ 'SDoc' where the things have been pretty printed,+ -- comma-separated and finally packed into a paragraph.+pprWithCommas pp xs = fsep (punctuate comma (map pp xs))++pprWithBars :: (a -> SDoc) -- ^ The pretty printing function to use+ -> [a] -- ^ The things to be pretty printed+ -> SDoc -- ^ 'SDoc' where the things have been pretty printed,+ -- bar-separated and finally packed into a paragraph.+pprWithBars pp xs = fsep (intersperse vbar (map pp xs))++-- | Returns the separated concatenation of the pretty printed things.+interppSP :: Outputable a => [a] -> SDoc+interppSP xs = sep (map ppr xs)++-- | Returns the comma-separated concatenation of the pretty printed things.+interpp'SP :: Outputable a => [a] -> SDoc+interpp'SP xs = sep (punctuate comma (map ppr xs))++-- | Returns the comma-separated concatenation of the quoted pretty printed things.+--+-- > [x,y,z] ==> `x', `y', `z'+pprQuotedList :: Outputable a => [a] -> SDoc+pprQuotedList = quotedList . map ppr++quotedList :: [SDoc] -> SDoc+quotedList xs = hsep (punctuate comma (map quotes xs))++quotedListWithOr :: [SDoc] -> SDoc+-- [x,y,z] ==> `x', `y' or `z'+quotedListWithOr xs@(_:_:_) = quotedList (init xs) <+> text "or" <+> quotes (last xs)+quotedListWithOr xs = quotedList xs++quotedListWithNor :: [SDoc] -> SDoc+-- [x,y,z] ==> `x', `y' nor `z'+quotedListWithNor xs@(_:_:_) = quotedList (init xs) <+> text "nor" <+> quotes (last xs)+quotedListWithNor xs = quotedList xs++{-+************************************************************************+* *+\subsection{Printing numbers verbally}+* *+************************************************************************+-}++intWithCommas :: Integral a => a -> SDoc+-- Prints a big integer with commas, eg 345,821+intWithCommas n+ | n < 0 = char '-' <> intWithCommas (-n)+ | q == 0 = int (fromIntegral r)+ | otherwise = intWithCommas q <> comma <> zeroes <> int (fromIntegral r)+ where+ (q,r) = n `quotRem` 1000+ zeroes | r >= 100 = empty+ | r >= 10 = char '0'+ | otherwise = text "00"++-- | Converts an integer to a verbal index:+--+-- > speakNth 1 = text "first"+-- > speakNth 5 = text "fifth"+-- > speakNth 21 = text "21st"+speakNth :: Int -> SDoc+speakNth 1 = text "first"+speakNth 2 = text "second"+speakNth 3 = text "third"+speakNth 4 = text "fourth"+speakNth 5 = text "fifth"+speakNth 6 = text "sixth"+speakNth n = hcat [ int n, text suffix ]+ where+ suffix | n <= 20 = "th" -- 11,12,13 are non-std+ | last_dig == 1 = "st"+ | last_dig == 2 = "nd"+ | last_dig == 3 = "rd"+ | otherwise = "th"++ last_dig = n `rem` 10++-- | Converts an integer to a verbal multiplicity:+--+-- > speakN 0 = text "none"+-- > speakN 5 = text "five"+-- > speakN 10 = text "10"+speakN :: Int -> SDoc+speakN 0 = text "none" -- E.g. "he has none"+speakN 1 = text "one" -- E.g. "he has one"+speakN 2 = text "two"+speakN 3 = text "three"+speakN 4 = text "four"+speakN 5 = text "five"+speakN 6 = text "six"+speakN n = int n++-- | Converts an integer and object description to a statement about the+-- multiplicity of those objects:+--+-- > speakNOf 0 (text "melon") = text "no melons"+-- > speakNOf 1 (text "melon") = text "one melon"+-- > speakNOf 3 (text "melon") = text "three melons"+speakNOf :: Int -> SDoc -> SDoc+speakNOf 0 d = text "no" <+> d <> char 's'+speakNOf 1 d = text "one" <+> d -- E.g. "one argument"+speakNOf n d = speakN n <+> d <> char 's' -- E.g. "three arguments"++-- | Determines the pluralisation suffix appropriate for the length of a list:+--+-- > plural [] = char 's'+-- > plural ["Hello"] = empty+-- > plural ["Hello", "World"] = char 's'+plural :: [a] -> SDoc+plural [_] = empty -- a bit frightening, but there you are+plural _ = char 's'++-- | Determines the form of to be appropriate for the length of a list:+--+-- > isOrAre [] = text "are"+-- > isOrAre ["Hello"] = text "is"+-- > isOrAre ["Hello", "World"] = text "are"+isOrAre :: [a] -> SDoc+isOrAre [_] = text "is"+isOrAre _ = text "are"++-- | Determines the form of to do appropriate for the length of a list:+--+-- > doOrDoes [] = text "do"+-- > doOrDoes ["Hello"] = text "does"+-- > doOrDoes ["Hello", "World"] = text "do"+doOrDoes :: [a] -> SDoc+doOrDoes [_] = text "does"+doOrDoes _ = text "do"++{-+************************************************************************+* *+\subsection{Error handling}+* *+************************************************************************+-}++callStackDoc :: HasCallStack => SDoc+callStackDoc =+ hang (text "Call stack:") 4 (vcat $ map text $ lines prettyCurrentCallStack)++pprPanic :: HasCallStack => String -> SDoc -> a+-- ^ Throw an exception saying "bug in GHC"+pprPanic s doc = panicDoc s (doc $$ callStackDoc)++pprSorry :: String -> SDoc -> a+-- ^ Throw an exception saying "this isn't finished yet"+pprSorry = sorryDoc+++pprPgmError :: String -> SDoc -> a+-- ^ Throw an exception saying "bug in pgm being compiled" (used for unusual program errors)+pprPgmError = pgmErrorDoc++pprTraceDebug :: String -> SDoc -> a -> a+pprTraceDebug str doc x+ | debugIsOn && hasPprDebug unsafeGlobalDynFlags = pprTrace str doc x+ | otherwise = x++pprTrace :: String -> SDoc -> a -> a+-- ^ If debug output is on, show some 'SDoc' on the screen+pprTrace str doc x+ | hasNoDebugOutput unsafeGlobalDynFlags = x+ | otherwise =+ pprDebugAndThen unsafeGlobalDynFlags trace (text str) doc x++-- | @pprTraceIt desc x@ is equivalent to @pprTrace desc (ppr x) x@+pprTraceIt :: Outputable a => String -> a -> a+pprTraceIt desc x = pprTrace desc (ppr x) x+++-- | If debug output is on, show some 'SDoc' on the screen along+-- with a call stack when available.+pprSTrace :: HasCallStack => SDoc -> a -> a+pprSTrace doc = pprTrace "" (doc $$ callStackDoc)++warnPprTrace :: Bool -> String -> Int -> SDoc -> a -> a+-- ^ Just warn about an assertion failure, recording the given file and line number.+-- Should typically be accessed with the WARN macros+warnPprTrace _ _ _ _ x | not debugIsOn = x+warnPprTrace _ _file _line _msg x+ | hasNoDebugOutput unsafeGlobalDynFlags = x+warnPprTrace False _file _line _msg x = x+warnPprTrace True file line msg x+ = pprDebugAndThen unsafeGlobalDynFlags trace heading msg x+ where+ heading = hsep [text "WARNING: file", text file <> comma, text "line", int line]++-- | Panic with an assertation failure, recording the given file and+-- line number. Should typically be accessed with the ASSERT family of macros+assertPprPanic :: HasCallStack => String -> Int -> SDoc -> a+assertPprPanic _file _line msg+ = pprPanic "ASSERT failed!" doc+ where+ doc = sep [ msg, callStackDoc ]++pprDebugAndThen :: DynFlags -> (String -> a) -> SDoc -> SDoc -> a+pprDebugAndThen dflags cont heading pretty_msg+ = cont (showSDocDump dflags doc)+ where+ doc = sep [heading, nest 2 pretty_msg]
+ utils/Outputable.hs-boot view
@@ -0,0 +1,5 @@+module Outputable where++data SDoc++showSDocUnsafe :: SDoc -> String
+ utils/Pair.hs view
@@ -0,0 +1,54 @@+{-+A simple homogeneous pair type with useful Functor, Applicative, and+Traversable instances.+-}++{-# LANGUAGE CPP #-}++module Pair ( Pair(..), unPair, toPair, swap, pLiftFst, pLiftSnd ) where++#include "HsVersions.h"++import Outputable++data Pair a = Pair { pFst :: a, pSnd :: a }+-- Note that Pair is a *unary* type constructor+-- whereas (,) is binary++-- The important thing about Pair is that it has a *homogenous*+-- Functor instance, so you can easily apply the same function+-- to both components+instance Functor Pair where+ fmap f (Pair x y) = Pair (f x) (f y)++instance Applicative Pair where+ pure x = Pair x x+ (Pair f g) <*> (Pair x y) = Pair (f x) (g y)++instance Foldable Pair where+ foldMap f (Pair x y) = f x `mappend` f y++instance Traversable Pair where+ traverse f (Pair x y) = Pair <$> f x <*> f y++instance Monoid a => Monoid (Pair a) where+ mempty = Pair mempty mempty+ Pair a1 b1 `mappend` Pair a2 b2 = Pair (a1 `mappend` a2) (b1 `mappend` b2)++instance Outputable a => Outputable (Pair a) where+ ppr (Pair a b) = ppr a <+> char '~' <+> ppr b++unPair :: Pair a -> (a,a)+unPair (Pair x y) = (x,y)++toPair :: (a,a) -> Pair a+toPair (x,y) = Pair x y++swap :: Pair a -> Pair a+swap (Pair x y) = Pair y x++pLiftFst :: (a -> a) -> Pair a -> Pair a+pLiftFst f (Pair a b) = Pair (f a) b++pLiftSnd :: (a -> a) -> Pair a -> Pair a+pLiftSnd f (Pair a b) = Pair a (f b)
+ utils/Panic.hs view
@@ -0,0 +1,298 @@+{-+(c) The University of Glasgow 2006+(c) The GRASP Project, Glasgow University, 1992-2000++Defines basic functions for printing error messages.++It's hard to put these functions anywhere else without causing+some unnecessary loops in the module dependency graph.+-}++{-# LANGUAGE CPP, ScopedTypeVariables, LambdaCase #-}++module Panic (+ GhcException(..), showGhcException,+ throwGhcException, throwGhcExceptionIO,+ handleGhcException,+ progName,+ pgmError,++ panic, sorry, assertPanic, trace,+ panicDoc, sorryDoc, pgmErrorDoc,++ Exception.Exception(..), showException, safeShowException,+ try, tryMost, throwTo,++ withSignalHandlers,+) where+#include "HsVersions.h"++import {-# SOURCE #-} Outputable (SDoc, showSDocUnsafe)++import Config+import Exception++import Control.Monad.IO.Class+import Control.Concurrent+import Debug.Trace ( trace )+import System.IO.Unsafe+import System.Environment++#ifndef mingw32_HOST_OS+import System.Posix.Signals as S+#endif++#if defined(mingw32_HOST_OS)+import GHC.ConsoleHandler as S+#endif++import GHC.Stack+import System.Mem.Weak ( deRefWeak )++-- | GHC's own exception type+-- error messages all take the form:+--+-- @+-- <location>: <error>+-- @+--+-- If the location is on the command line, or in GHC itself, then+-- <location>="ghc". All of the error types below correspond to+-- a <location> of "ghc", except for ProgramError (where the string is+-- assumed to contain a location already, so we don't print one).++data GhcException+ -- | Some other fatal signal (SIGHUP,SIGTERM)+ = Signal Int++ -- | Prints the short usage msg after the error+ | UsageError String++ -- | A problem with the command line arguments, but don't print usage.+ | CmdLineError String++ -- | The 'impossible' happened.+ | Panic String+ | PprPanic String SDoc++ -- | The user tickled something that's known not to work yet,+ -- but we're not counting it as a bug.+ | Sorry String+ | PprSorry String SDoc++ -- | An installation problem.+ | InstallationError String++ -- | An error in the user's code, probably.+ | ProgramError String+ | PprProgramError String SDoc++instance Exception GhcException++instance Show GhcException where+ showsPrec _ e@(ProgramError _) = showGhcException e+ showsPrec _ e@(CmdLineError _) = showString "<command line>: " . showGhcException e+ showsPrec _ e = showString progName . showString ": " . showGhcException e+++-- | The name of this GHC.+progName :: String+progName = unsafePerformIO (getProgName)+{-# NOINLINE progName #-}+++-- | Short usage information to display when we are given the wrong cmd line arguments.+short_usage :: String+short_usage = "Usage: For basic information, try the `--help' option."+++-- | Show an exception as a string.+showException :: Exception e => e -> String+showException = show++-- | Show an exception which can possibly throw other exceptions.+-- Used when displaying exception thrown within TH code.+safeShowException :: Exception e => e -> IO String+safeShowException e = do+ -- ensure the whole error message is evaluated inside try+ r <- try (return $! forceList (showException e))+ case r of+ Right msg -> return msg+ Left e' -> safeShowException (e' :: SomeException)+ where+ forceList [] = []+ forceList xs@(x : xt) = x `seq` forceList xt `seq` xs++-- | Append a description of the given exception to this string.+--+-- Note that this uses 'DynFlags.unsafeGlobalDynFlags', which may have some+-- uninitialized fields if invoked before 'GHC.initGhcMonad' has been called.+-- If the error message to be printed includes a pretty-printer document+-- which forces one of these fields this call may bottom.+showGhcException :: GhcException -> ShowS+showGhcException exception+ = case exception of+ UsageError str+ -> showString str . showChar '\n' . showString short_usage++ CmdLineError str -> showString str+ PprProgramError str sdoc ->+ showString str . showString "\n\n" .+ showString (showSDocUnsafe sdoc)+ ProgramError str -> showString str+ InstallationError str -> showString str+ Signal n -> showString "signal: " . shows n++ PprPanic s sdoc ->+ panicMsg $ showString s . showString "\n\n"+ . showString (showSDocUnsafe sdoc)+ Panic s -> panicMsg (showString s)++ PprSorry s sdoc ->+ sorryMsg $ showString s . showString "\n\n"+ . showString (showSDocUnsafe sdoc)+ Sorry s -> sorryMsg (showString s)+ where+ sorryMsg :: ShowS -> ShowS+ sorryMsg s =+ showString "sorry! (unimplemented feature or known bug)\n"+ . showString (" (GHC version " ++ cProjectVersion ++ " for " ++ TargetPlatform_NAME ++ "):\n\t")+ . s . showString "\n"++ panicMsg :: ShowS -> ShowS+ panicMsg s =+ showString "panic! (the 'impossible' happened)\n"+ . showString (" (GHC version " ++ cProjectVersion ++ " for " ++ TargetPlatform_NAME ++ "):\n\t")+ . s . showString "\n\n"+ . showString "Please report this as a GHC bug: http://www.haskell.org/ghc/reportabug\n"+++throwGhcException :: GhcException -> a+throwGhcException = Exception.throw++throwGhcExceptionIO :: GhcException -> IO a+throwGhcExceptionIO = Exception.throwIO++handleGhcException :: ExceptionMonad m => (GhcException -> m a) -> m a -> m a+handleGhcException = ghandle+++-- | Panics and asserts.+panic, sorry, pgmError :: String -> a+panic x = unsafeDupablePerformIO $ do+ stack <- ccsToStrings =<< getCurrentCCS x+ if null stack+ then throwGhcException (Panic x)+ else throwGhcException (Panic (x ++ '\n' : renderStack stack))++sorry x = throwGhcException (Sorry x)+pgmError x = throwGhcException (ProgramError x)++panicDoc, sorryDoc, pgmErrorDoc :: String -> SDoc -> a+panicDoc x doc = throwGhcException (PprPanic x doc)+sorryDoc x doc = throwGhcException (PprSorry x doc)+pgmErrorDoc x doc = throwGhcException (PprProgramError x doc)+++-- | Throw an failed assertion exception for a given filename and line number.+assertPanic :: String -> Int -> a+assertPanic file line =+ Exception.throw (Exception.AssertionFailed+ ("ASSERT failed! file " ++ file ++ ", line " ++ show line))+++-- | Like try, but pass through UserInterrupt and Panic exceptions.+-- Used when we want soft failures when reading interface files, for example.+-- TODO: I'm not entirely sure if this is catching what we really want to catch+tryMost :: IO a -> IO (Either SomeException a)+tryMost action = do r <- try action+ case r of+ Left se ->+ case fromException se of+ -- Some GhcException's we rethrow,+ Just (Signal _) -> throwIO se+ Just (Panic _) -> throwIO se+ -- others we return+ Just _ -> return (Left se)+ Nothing ->+ case fromException se of+ -- All IOExceptions are returned+ Just (_ :: IOException) ->+ return (Left se)+ -- Anything else is rethrown+ Nothing -> throwIO se+ Right v -> return (Right v)++-- | We use reference counting for signal handlers+{-# NOINLINE signalHandlersRefCount #-}+#if !defined(mingw32_HOST_OS)+signalHandlersRefCount :: MVar (Word, Maybe (S.Handler,S.Handler+ ,S.Handler,S.Handler))+#else+signalHandlersRefCount :: MVar (Word, Maybe S.Handler)+#endif+signalHandlersRefCount = unsafePerformIO $ newMVar (0,Nothing)+++-- | Temporarily install standard signal handlers for catching ^C, which just+-- throw an exception in the current thread.+withSignalHandlers :: (ExceptionMonad m, MonadIO m) => m a -> m a+withSignalHandlers act = do+ main_thread <- liftIO myThreadId+ wtid <- liftIO (mkWeakThreadId main_thread)++ let+ interrupt = do+ r <- deRefWeak wtid+ case r of+ Nothing -> return ()+ Just t -> throwTo t UserInterrupt++#if !defined(mingw32_HOST_OS)+ let installHandlers = do+ let installHandler' a b = installHandler a b Nothing+ hdlQUIT <- installHandler' sigQUIT (Catch interrupt)+ hdlINT <- installHandler' sigINT (Catch interrupt)+ -- see #3656; in the future we should install these automatically for+ -- all Haskell programs in the same way that we install a ^C handler.+ let fatal_signal n = throwTo main_thread (Signal (fromIntegral n))+ hdlHUP <- installHandler' sigHUP (Catch (fatal_signal sigHUP))+ hdlTERM <- installHandler' sigTERM (Catch (fatal_signal sigTERM))+ return (hdlQUIT,hdlINT,hdlHUP,hdlTERM)++ let uninstallHandlers (hdlQUIT,hdlINT,hdlHUP,hdlTERM) = do+ _ <- installHandler sigQUIT hdlQUIT Nothing+ _ <- installHandler sigINT hdlINT Nothing+ _ <- installHandler sigHUP hdlHUP Nothing+ _ <- installHandler sigTERM hdlTERM Nothing+ return ()+#else+ -- GHC 6.3+ has support for console events on Windows+ -- NOTE: running GHCi under a bash shell for some reason requires+ -- you to press Ctrl-Break rather than Ctrl-C to provoke+ -- an interrupt. Ctrl-C is getting blocked somewhere, I don't know+ -- why --SDM 17/12/2004+ let sig_handler ControlC = interrupt+ sig_handler Break = interrupt+ sig_handler _ = return ()++ let installHandlers = installHandler (Catch sig_handler)+ let uninstallHandlers = installHandler -- directly install the old handler+#endif++ -- install signal handlers if necessary+ let mayInstallHandlers = liftIO $ modifyMVar_ signalHandlersRefCount $ \case+ (0,Nothing) -> do+ hdls <- installHandlers+ return (1,Just hdls)+ (c,oldHandlers) -> return (c+1,oldHandlers)++ -- uninstall handlers if necessary+ let mayUninstallHandlers = liftIO $ modifyMVar_ signalHandlersRefCount $ \case+ (1,Just hdls) -> do+ _ <- uninstallHandlers hdls+ return (0,Nothing)+ (c,oldHandlers) -> return (c-1,oldHandlers)++ mayInstallHandlers+ act `gfinally` mayUninstallHandlers
+ utils/Platform.hs view
@@ -0,0 +1,172 @@++-- | A description of the platform we're compiling for.+--+module Platform (+ Platform(..),+ Arch(..),+ OS(..),+ ArmISA(..),+ ArmISAExt(..),+ ArmABI(..),+ PPC_64ABI(..),++ target32Bit,+ isARM,+ osElfTarget,+ osMachOTarget,+ osSubsectionsViaSymbols,+ platformUsesFrameworks,+ platformBinariesAreStaticLibs,+)++where++-- | Contains enough information for the native code generator to emit+-- code for this platform.+data Platform+ = Platform {+ platformArch :: Arch,+ platformOS :: OS,+ -- Word size in bytes (i.e. normally 4 or 8,+ -- for 32bit and 64bit platforms respectively)+ platformWordSize :: {-# UNPACK #-} !Int,+ platformUnregisterised :: Bool,+ platformHasGnuNonexecStack :: Bool,+ platformHasIdentDirective :: Bool,+ platformHasSubsectionsViaSymbols :: Bool,+ platformIsCrossCompiling :: Bool+ }+ deriving (Read, Show, Eq)+++-- | Architectures that the native code generator knows about.+-- TODO: It might be nice to extend these constructors with information+-- about what instruction set extensions an architecture might support.+--+data Arch+ = ArchUnknown+ | ArchX86+ | ArchX86_64+ | ArchPPC+ | ArchPPC_64+ { ppc_64ABI :: PPC_64ABI+ }+ | ArchSPARC+ | ArchSPARC64+ | ArchARM+ { armISA :: ArmISA+ , armISAExt :: [ArmISAExt]+ , armABI :: ArmABI+ }+ | ArchARM64+ | ArchAlpha+ | ArchMipseb+ | ArchMipsel+ | ArchJavaScript+ deriving (Read, Show, Eq)++isARM :: Arch -> Bool+isARM (ArchARM {}) = True+isARM ArchARM64 = True+isARM _ = False++-- | Operating systems that the native code generator knows about.+-- Having OSUnknown should produce a sensible default, but no promises.+data OS+ = OSUnknown+ | OSLinux+ | OSDarwin+ | OSiOS+ | OSSolaris2+ | OSMinGW32+ | OSFreeBSD+ | OSDragonFly+ | OSOpenBSD+ | OSNetBSD+ | OSKFreeBSD+ | OSHaiku+ | OSQNXNTO+ | OSAndroid+ | OSAIX+ deriving (Read, Show, Eq)++-- | ARM Instruction Set Architecture, Extensions and ABI+--+data ArmISA+ = ARMv5+ | ARMv6+ | ARMv7+ deriving (Read, Show, Eq)++data ArmISAExt+ = VFPv2+ | VFPv3+ | VFPv3D16+ | NEON+ | IWMMX2+ deriving (Read, Show, Eq)++data ArmABI+ = SOFT+ | SOFTFP+ | HARD+ deriving (Read, Show, Eq)++-- | PowerPC 64-bit ABI+--+data PPC_64ABI+ = ELF_V1+ | ELF_V2+ deriving (Read, Show, Eq)++-- | This predicate tells us whether the platform is 32-bit.+target32Bit :: Platform -> Bool+target32Bit p = platformWordSize p == 4++-- | This predicate tells us whether the OS supports ELF-like shared libraries.+osElfTarget :: OS -> Bool+osElfTarget OSLinux = True+osElfTarget OSFreeBSD = True+osElfTarget OSDragonFly = True+osElfTarget OSOpenBSD = True+osElfTarget OSNetBSD = True+osElfTarget OSSolaris2 = True+osElfTarget OSDarwin = False+osElfTarget OSiOS = False+osElfTarget OSMinGW32 = False+osElfTarget OSKFreeBSD = True+osElfTarget OSHaiku = True+osElfTarget OSQNXNTO = False+osElfTarget OSAndroid = True+osElfTarget OSAIX = False+osElfTarget OSUnknown = False+ -- Defaulting to False is safe; it means don't rely on any+ -- ELF-specific functionality. It is important to have a default for+ -- portability, otherwise we have to answer this question for every+ -- new platform we compile on (even unreg).++-- | This predicate tells us whether the OS support Mach-O shared libraries.+osMachOTarget :: OS -> Bool+osMachOTarget OSDarwin = True+osMachOTarget _ = False++osUsesFrameworks :: OS -> Bool+osUsesFrameworks OSDarwin = True+osUsesFrameworks OSiOS = True+osUsesFrameworks _ = False++platformUsesFrameworks :: Platform -> Bool+platformUsesFrameworks = osUsesFrameworks . platformOS++osBinariesAreStaticLibs :: OS -> Bool+osBinariesAreStaticLibs OSiOS = True+osBinariesAreStaticLibs _ = False++osSubsectionsViaSymbols :: OS -> Bool+osSubsectionsViaSymbols OSDarwin = True+osSubsectionsViaSymbols OSiOS = True+osSubsectionsViaSymbols _ = False++platformBinariesAreStaticLibs :: Platform -> Bool+platformBinariesAreStaticLibs = osBinariesAreStaticLibs . platformOS+
+ utils/PprColour.hs view
@@ -0,0 +1,95 @@+module PprColour where+import Data.Maybe (fromMaybe)+import Util (OverridingBool(..), split)++-- | A colour\/style for use with 'coloured'.+newtype PprColour = PprColour { renderColour :: String }++-- | Allow colours to be combined (e.g. bold + red);+-- In case of conflict, right side takes precedence.+instance Monoid PprColour where+ mempty = PprColour mempty+ PprColour s1 `mappend` PprColour s2 = PprColour (s1 `mappend` s2)++renderColourAfresh :: PprColour -> String+renderColourAfresh c = renderColour (colReset `mappend` c)++colCustom :: String -> PprColour+colCustom "" = mempty+colCustom s = PprColour ("\27[" ++ s ++ "m")++colReset :: PprColour+colReset = colCustom "0"++colBold :: PprColour+colBold = colCustom ";1"++colBlackFg :: PprColour+colBlackFg = colCustom "30"++colRedFg :: PprColour+colRedFg = colCustom "31"++colGreenFg :: PprColour+colGreenFg = colCustom "32"++colYellowFg :: PprColour+colYellowFg = colCustom "33"++colBlueFg :: PprColour+colBlueFg = colCustom "34"++colMagentaFg :: PprColour+colMagentaFg = colCustom "35"++colCyanFg :: PprColour+colCyanFg = colCustom "36"++colWhiteFg :: PprColour+colWhiteFg = colCustom "37"++data Scheme =+ Scheme+ { sHeader :: PprColour+ , sMessage :: PprColour+ , sWarning :: PprColour+ , sError :: PprColour+ , sFatal :: PprColour+ , sMargin :: PprColour+ }++defaultScheme :: Scheme+defaultScheme =+ Scheme+ { sHeader = mempty+ , sMessage = colBold+ , sWarning = colBold `mappend` colMagentaFg+ , sError = colBold `mappend` colRedFg+ , sFatal = colBold `mappend` colRedFg+ , sMargin = colBold `mappend` colBlueFg+ }++-- | Parse the colour scheme from a string (presumably from the @GHC_COLORS@+-- environment variable).+parseScheme :: String -> (OverridingBool, Scheme) -> (OverridingBool, Scheme)+parseScheme "always" (_, cs) = (Always, cs)+parseScheme "auto" (_, cs) = (Auto, cs)+parseScheme "never" (_, cs) = (Never, cs)+parseScheme input (b, cs) =+ ( b+ , Scheme+ { sHeader = fromMaybe (sHeader cs) (lookup "header" table)+ , sMessage = fromMaybe (sMessage cs) (lookup "message" table)+ , sWarning = fromMaybe (sWarning cs) (lookup "warning" table)+ , sError = fromMaybe (sError cs) (lookup "error" table)+ , sFatal = fromMaybe (sFatal cs) (lookup "fatal" table)+ , sMargin = fromMaybe (sMargin cs) (lookup "margin" table)+ }+ )+ where+ table = do+ w <- split ':' input+ let (k, v') = break (== '=') w+ case v' of+ '=' : v -> return (k, colCustom v)+ _ -> []
+ utils/Pretty.hs view
@@ -0,0 +1,1050 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}++-----------------------------------------------------------------------------+-- |+-- Module : Pretty+-- Copyright : (c) The University of Glasgow 2001+-- License : BSD-style (see the file LICENSE)+--+-- Maintainer : David Terei <code@davidterei.com>+-- Stability : stable+-- Portability : portable+--+-- John Hughes's and Simon Peyton Jones's Pretty Printer Combinators+--+-- Based on /The Design of a Pretty-printing Library/+-- in Advanced Functional Programming,+-- Johan Jeuring and Erik Meijer (eds), LNCS 925+-- <http://www.cs.chalmers.se/~rjmh/Papers/pretty.ps>+--+-----------------------------------------------------------------------------++{-+Note [Differences between libraries/pretty and compiler/utils/Pretty.hs]++For historical reasons, there are two different copies of `Pretty` in the GHC+source tree:+ * `libraries/pretty` is a submodule containing+ https://github.com/haskell/pretty. This is the `pretty` library as released+ on hackage. It is used by several other libraries in the GHC source tree+ (e.g. template-haskell and Cabal).+ * `compiler/utils/Pretty.hs` (this module). It is used by GHC only.++There is an ongoing effort in https://github.com/haskell/pretty/issues/1 and+https://ghc.haskell.org/trac/ghc/ticket/10735 to try to get rid of GHC's copy+of Pretty.++Currently, GHC's copy of Pretty resembles pretty-1.1.2.0, with the following+major differences:+ * GHC's copy uses `Faststring` for performance reasons.+ * GHC's copy has received a backported bugfix for #12227, which was+ released as pretty-1.1.3.4 ("Remove harmful $! forcing in beside",+ https://github.com/haskell/pretty/pull/35).++Other differences are minor. Both copies define some extra functions and+instances not defined in the other copy. To see all differences, do this in a+ghc git tree:++ $ cd libraries/pretty+ $ git checkout v1.1.2.0+ $ cd -+ $ vimdiff compiler/utils/Pretty.hs \+ libraries/pretty/src/Text/PrettyPrint/HughesPJ.hs++For parity with `pretty-1.1.2.1`, the following two `pretty` commits would+have to be backported:+ * "Resolve foldr-strictness stack overflow bug"+ (307b8173f41cd776eae8f547267df6d72bff2d68)+ * "Special-case reduce for horiz/vert"+ (c57c7a9dfc49617ba8d6e4fcdb019a3f29f1044c)+This has not been done sofar, because these commits seem to cause more+allocation in the compiler (see thomie's comments in+https://github.com/haskell/pretty/pull/9).+-}++module Pretty (++ -- * The document type+ Doc, TextDetails(..),++ -- * Constructing documents++ -- ** Converting values into documents+ char, text, ftext, ptext, ztext, sizedText, zeroWidthText,+ int, integer, float, double, rational,++ -- ** Simple derived documents+ semi, comma, colon, space, equals,+ lparen, rparen, lbrack, rbrack, lbrace, rbrace,++ -- ** Wrapping documents in delimiters+ parens, brackets, braces, quotes, quote, doubleQuotes,+ maybeParens,++ -- ** Combining documents+ empty,+ (<>), (<+>), hcat, hsep,+ ($$), ($+$), vcat,+ sep, cat,+ fsep, fcat,+ nest,+ hang, hangNotEmpty, punctuate,++ -- * Predicates on documents+ isEmpty,++ -- * Rendering documents++ -- ** Rendering with a particular style+ Style(..),+ style,+ renderStyle,+ Mode(..),++ -- ** General rendering+ fullRender,++ -- ** GHC-specific rendering+ printDoc, printDoc_,+ bufLeftRender -- performance hack++ ) where++import BufWrite+import FastString+import Panic+import System.IO+import Prelude hiding (error)++--for a RULES+import GHC.Base ( unpackCString# )+import GHC.Ptr ( Ptr(..) )++-- Don't import Util( assertPanic ) because it makes a loop in the module structure+++-- ---------------------------------------------------------------------------+-- The Doc calculus++{-+Laws for $$+~~~~~~~~~~~+<a1> (x $$ y) $$ z = x $$ (y $$ z)+<a2> empty $$ x = x+<a3> x $$ empty = x++ ...ditto $+$...++Laws for <>+~~~~~~~~~~~+<b1> (x <> y) <> z = x <> (y <> z)+<b2> empty <> x = empty+<b3> x <> empty = x++ ...ditto <+>...++Laws for text+~~~~~~~~~~~~~+<t1> text s <> text t = text (s++t)+<t2> text "" <> x = x, if x non-empty++** because of law n6, t2 only holds if x doesn't+** start with `nest'.+++Laws for nest+~~~~~~~~~~~~~+<n1> nest 0 x = x+<n2> nest k (nest k' x) = nest (k+k') x+<n3> nest k (x <> y) = nest k x <> nest k y+<n4> nest k (x $$ y) = nest k x $$ nest k y+<n5> nest k empty = empty+<n6> x <> nest k y = x <> y, if x non-empty++** Note the side condition on <n6>! It is this that+** makes it OK for empty to be a left unit for <>.++Miscellaneous+~~~~~~~~~~~~~+<m1> (text s <> x) $$ y = text s <> ((text "" <> x) $$+ nest (-length s) y)++<m2> (x $$ y) <> z = x $$ (y <> z)+ if y non-empty+++Laws for list versions+~~~~~~~~~~~~~~~~~~~~~~+<l1> sep (ps++[empty]++qs) = sep (ps ++ qs)+ ...ditto hsep, hcat, vcat, fill...++<l2> nest k (sep ps) = sep (map (nest k) ps)+ ...ditto hsep, hcat, vcat, fill...++Laws for oneLiner+~~~~~~~~~~~~~~~~~+<o1> oneLiner (nest k p) = nest k (oneLiner p)+<o2> oneLiner (x <> y) = oneLiner x <> oneLiner y++You might think that the following verion of <m1> would+be neater:++<3 NO> (text s <> x) $$ y = text s <> ((empty <> x)) $$+ nest (-length s) y)++But it doesn't work, for if x=empty, we would have++ text s $$ y = text s <> (empty $$ nest (-length s) y)+ = text s <> nest (-length s) y+-}++-- ---------------------------------------------------------------------------+-- Operator fixity++infixl 6 <>+infixl 6 <+>+infixl 5 $$, $+$+++-- ---------------------------------------------------------------------------+-- The Doc data type++-- | The abstract type of documents.+-- A Doc represents a *set* of layouts. A Doc with+-- no occurrences of Union or NoDoc represents just one layout.+data Doc+ = Empty -- empty+ | NilAbove Doc -- text "" $$ x+ | TextBeside !TextDetails {-# UNPACK #-} !Int Doc -- text s <> x+ | Nest {-# UNPACK #-} !Int Doc -- nest k x+ | Union Doc Doc -- ul `union` ur+ | NoDoc -- The empty set of documents+ | Beside Doc Bool Doc -- True <=> space between+ | Above Doc Bool Doc -- True <=> never overlap++{-+Here are the invariants:++1) The argument of NilAbove is never Empty. Therefore+ a NilAbove occupies at least two lines.++2) The argument of @TextBeside@ is never @Nest@.++3) The layouts of the two arguments of @Union@ both flatten to the same+ string.++4) The arguments of @Union@ are either @TextBeside@, or @NilAbove@.++5) A @NoDoc@ may only appear on the first line of the left argument of an+ union. Therefore, the right argument of an union can never be equivalent+ to the empty set (@NoDoc@).++6) An empty document is always represented by @Empty@. It can't be+ hidden inside a @Nest@, or a @Union@ of two @Empty@s.++7) The first line of every layout in the left argument of @Union@ is+ longer than the first line of any layout in the right argument.+ (1) ensures that the left argument has a first line. In view of+ (3), this invariant means that the right argument must have at+ least two lines.++Notice the difference between+ * NoDoc (no documents)+ * Empty (one empty document; no height and no width)+ * text "" (a document containing the empty string;+ one line high, but has no width)+-}+++-- | RDoc is a "reduced GDoc", guaranteed not to have a top-level Above or Beside.+type RDoc = Doc++-- | The TextDetails data type+--+-- A TextDetails represents a fragment of text that will be+-- output at some point.+data TextDetails = Chr {-# UNPACK #-} !Char -- ^ A single Char fragment+ | Str String -- ^ A whole String fragment+ | PStr FastString -- a hashed string+ | ZStr FastZString -- a z-encoded string+ | LStr {-# UNPACK #-} !LitString {-#UNPACK #-} !Int+ -- a '\0'-terminated array of bytes++instance Show Doc where+ showsPrec _ doc cont = fullRender (mode style) (lineLength style)+ (ribbonsPerLine style)+ txtPrinter cont doc+++-- ---------------------------------------------------------------------------+-- Values and Predicates on GDocs and TextDetails++-- | A document of height and width 1, containing a literal character.+char :: Char -> Doc+char c = textBeside_ (Chr c) 1 Empty++-- | A document of height 1 containing a literal string.+-- 'text' satisfies the following laws:+--+-- * @'text' s '<>' 'text' t = 'text' (s'++'t)@+--+-- * @'text' \"\" '<>' x = x@, if @x@ non-empty+--+-- The side condition on the last law is necessary because @'text' \"\"@+-- has height 1, while 'empty' has no height.+text :: String -> Doc+text s = case length s of {sl -> textBeside_ (Str s) sl Empty}+{-# NOINLINE [0] text #-} -- Give the RULE a chance to fire+ -- It must wait till after phase 1 when+ -- the unpackCString first is manifested++-- RULE that turns (text "abc") into (ptext (A# "abc"#)) to avoid the+-- intermediate packing/unpacking of the string.+{-# RULES+ "text/str" forall a. text (unpackCString# a) = ptext (Ptr a)+ #-}++ftext :: FastString -> Doc+ftext s = case lengthFS s of {sl -> textBeside_ (PStr s) sl Empty}++ptext :: LitString -> Doc+ptext s = case lengthLS s of {sl -> textBeside_ (LStr s sl) sl Empty}++ztext :: FastZString -> Doc+ztext s = case lengthFZS s of {sl -> textBeside_ (ZStr s) sl Empty}++-- | Some text with any width. (@text s = sizedText (length s) s@)+sizedText :: Int -> String -> Doc+sizedText l s = textBeside_ (Str s) l Empty++-- | Some text, but without any width. Use for non-printing text+-- such as a HTML or Latex tags+zeroWidthText :: String -> Doc+zeroWidthText = sizedText 0++-- | The empty document, with no height and no width.+-- 'empty' is the identity for '<>', '<+>', '$$' and '$+$', and anywhere+-- in the argument list for 'sep', 'hcat', 'hsep', 'vcat', 'fcat' etc.+empty :: Doc+empty = Empty++-- | Returns 'True' if the document is empty+isEmpty :: Doc -> Bool+isEmpty Empty = True+isEmpty _ = False++-- | Produce spacing for indenting the amount specified.+--+-- an old version inserted tabs being 8 columns apart in the output.+spaces :: Int -> String+spaces !n = replicate n ' '++{-+Q: What is the reason for negative indentation (i.e. argument to indent+ is < 0) ?++A:+This indicates an error in the library client's code.+If we compose a <> b, and the first line of b is more indented than some+other lines of b, the law <n6> (<> eats nests) may cause the pretty+printer to produce an invalid layout:++doc |0123345+------------------+d1 |a...|+d2 |...b|+ |c...|++d1<>d2 |ab..|+ c|....|++Consider a <> b, let `s' be the length of the last line of `a', `k' the+indentation of the first line of b, and `k0' the indentation of the+left-most line b_i of b.++The produced layout will have negative indentation if `k - k0 > s', as+the first line of b will be put on the (s+1)th column, effectively+translating b horizontally by (k-s). Now if the i^th line of b has an+indentation k0 < (k-s), it is translated out-of-page, causing+`negative indentation'.+-}+++semi :: Doc -- ^ A ';' character+comma :: Doc -- ^ A ',' character+colon :: Doc -- ^ A ':' character+space :: Doc -- ^ A space character+equals :: Doc -- ^ A '=' character+lparen :: Doc -- ^ A '(' character+rparen :: Doc -- ^ A ')' character+lbrack :: Doc -- ^ A '[' character+rbrack :: Doc -- ^ A ']' character+lbrace :: Doc -- ^ A '{' character+rbrace :: Doc -- ^ A '}' character+semi = char ';'+comma = char ','+colon = char ':'+space = char ' '+equals = char '='+lparen = char '('+rparen = char ')'+lbrack = char '['+rbrack = char ']'+lbrace = char '{'+rbrace = char '}'++spaceText, nlText :: TextDetails+spaceText = Chr ' '+nlText = Chr '\n'++int :: Int -> Doc -- ^ @int n = text (show n)@+integer :: Integer -> Doc -- ^ @integer n = text (show n)@+float :: Float -> Doc -- ^ @float n = text (show n)@+double :: Double -> Doc -- ^ @double n = text (show n)@+rational :: Rational -> Doc -- ^ @rational n = text (show n)@+int n = text (show n)+integer n = text (show n)+float n = text (show n)+double n = text (show n)+rational n = text (show n)++parens :: Doc -> Doc -- ^ Wrap document in @(...)@+brackets :: Doc -> Doc -- ^ Wrap document in @[...]@+braces :: Doc -> Doc -- ^ Wrap document in @{...}@+quotes :: Doc -> Doc -- ^ Wrap document in @\'...\'@+quote :: Doc -> Doc+doubleQuotes :: Doc -> Doc -- ^ Wrap document in @\"...\"@+quotes p = char '`' <> p <> char '\''+quote p = char '\'' <> p+doubleQuotes p = char '"' <> p <> char '"'+parens p = char '(' <> p <> char ')'+brackets p = char '[' <> p <> char ']'+braces p = char '{' <> p <> char '}'++-- | Apply 'parens' to 'Doc' if boolean is true.+maybeParens :: Bool -> Doc -> Doc+maybeParens False = id+maybeParens True = parens++-- ---------------------------------------------------------------------------+-- Structural operations on GDocs++-- | Perform some simplification of a built up @GDoc@.+reduceDoc :: Doc -> RDoc+reduceDoc (Beside p g q) = beside p g (reduceDoc q)+reduceDoc (Above p g q) = above p g (reduceDoc q)+reduceDoc p = p++-- | List version of '<>'.+hcat :: [Doc] -> Doc+hcat = reduceAB . foldr (beside_' False) empty++-- | List version of '<+>'.+hsep :: [Doc] -> Doc+hsep = reduceAB . foldr (beside_' True) empty++-- | List version of '$$'.+vcat :: [Doc] -> Doc+vcat = reduceAB . foldr (above_' False) empty++-- | Nest (or indent) a document by a given number of positions+-- (which may also be negative). 'nest' satisfies the laws:+--+-- * @'nest' 0 x = x@+--+-- * @'nest' k ('nest' k' x) = 'nest' (k+k') x@+--+-- * @'nest' k (x '<>' y) = 'nest' k z '<>' 'nest' k y@+--+-- * @'nest' k (x '$$' y) = 'nest' k x '$$' 'nest' k y@+--+-- * @'nest' k 'empty' = 'empty'@+--+-- * @x '<>' 'nest' k y = x '<>' y@, if @x@ non-empty+--+-- The side condition on the last law is needed because+-- 'empty' is a left identity for '<>'.+nest :: Int -> Doc -> Doc+nest k p = mkNest k (reduceDoc p)++-- | @hang d1 n d2 = sep [d1, nest n d2]@+hang :: Doc -> Int -> Doc -> Doc+hang d1 n d2 = sep [d1, nest n d2]++-- | Apply 'hang' to the arguments if the first 'Doc' is not empty.+hangNotEmpty :: Doc -> Int -> Doc -> Doc+hangNotEmpty d1 n d2 = if isEmpty d1+ then d2+ else hang d1 n d2++-- | @punctuate p [d1, ... dn] = [d1 \<> p, d2 \<> p, ... dn-1 \<> p, dn]@+punctuate :: Doc -> [Doc] -> [Doc]+punctuate _ [] = []+punctuate p (x:xs) = go x xs+ where go y [] = [y]+ go y (z:zs) = (y <> p) : go z zs++-- mkNest checks for Nest's invariant that it doesn't have an Empty inside it+mkNest :: Int -> Doc -> Doc+mkNest k _ | k `seq` False = undefined+mkNest k (Nest k1 p) = mkNest (k + k1) p+mkNest _ NoDoc = NoDoc+mkNest _ Empty = Empty+mkNest 0 p = p+mkNest k p = nest_ k p++-- mkUnion checks for an empty document+mkUnion :: Doc -> Doc -> Doc+mkUnion Empty _ = Empty+mkUnion p q = p `union_` q++beside_' :: Bool -> Doc -> Doc -> Doc+beside_' _ p Empty = p+beside_' g p q = Beside p g q++above_' :: Bool -> Doc -> Doc -> Doc+above_' _ p Empty = p+above_' g p q = Above p g q++reduceAB :: Doc -> Doc+reduceAB (Above Empty _ q) = q+reduceAB (Beside Empty _ q) = q+reduceAB doc = doc++nilAbove_ :: RDoc -> RDoc+nilAbove_ = NilAbove++-- Arg of a TextBeside is always an RDoc+textBeside_ :: TextDetails -> Int -> RDoc -> RDoc+textBeside_ = TextBeside++nest_ :: Int -> RDoc -> RDoc+nest_ = Nest++union_ :: RDoc -> RDoc -> RDoc+union_ = Union+++-- ---------------------------------------------------------------------------+-- Vertical composition @$$@++-- | Above, except that if the last line of the first argument stops+-- at least one position before the first line of the second begins,+-- these two lines are overlapped. For example:+--+-- > text "hi" $$ nest 5 (text "there")+--+-- lays out as+--+-- > hi there+--+-- rather than+--+-- > hi+-- > there+--+-- '$$' is associative, with identity 'empty', and also satisfies+--+-- * @(x '$$' y) '<>' z = x '$$' (y '<>' z)@, if @y@ non-empty.+--+($$) :: Doc -> Doc -> Doc+p $$ q = above_ p False q++-- | Above, with no overlapping.+-- '$+$' is associative, with identity 'empty'.+($+$) :: Doc -> Doc -> Doc+p $+$ q = above_ p True q++above_ :: Doc -> Bool -> Doc -> Doc+above_ p _ Empty = p+above_ Empty _ q = q+above_ p g q = Above p g q++above :: Doc -> Bool -> RDoc -> RDoc+above (Above p g1 q1) g2 q2 = above p g1 (above q1 g2 q2)+above p@(Beside{}) g q = aboveNest (reduceDoc p) g 0 (reduceDoc q)+above p g q = aboveNest p g 0 (reduceDoc q)++-- Specification: aboveNest p g k q = p $g$ (nest k q)+aboveNest :: RDoc -> Bool -> Int -> RDoc -> RDoc+aboveNest _ _ k _ | k `seq` False = undefined+aboveNest NoDoc _ _ _ = NoDoc+aboveNest (p1 `Union` p2) g k q = aboveNest p1 g k q `union_`+ aboveNest p2 g k q++aboveNest Empty _ k q = mkNest k q+aboveNest (Nest k1 p) g k q = nest_ k1 (aboveNest p g (k - k1) q)+ -- p can't be Empty, so no need for mkNest++aboveNest (NilAbove p) g k q = nilAbove_ (aboveNest p g k q)+aboveNest (TextBeside s sl p) g k q = textBeside_ s sl rest+ where+ !k1 = k - sl+ rest = case p of+ Empty -> nilAboveNest g k1 q+ _ -> aboveNest p g k1 q+aboveNest (Above {}) _ _ _ = error "aboveNest Above"+aboveNest (Beside {}) _ _ _ = error "aboveNest Beside"++-- Specification: text s <> nilaboveNest g k q+-- = text s <> (text "" $g$ nest k q)+nilAboveNest :: Bool -> Int -> RDoc -> RDoc+nilAboveNest _ k _ | k `seq` False = undefined+nilAboveNest _ _ Empty = Empty+ -- Here's why the "text s <>" is in the spec!+nilAboveNest g k (Nest k1 q) = nilAboveNest g (k + k1) q+nilAboveNest g k q | not g && k > 0 -- No newline if no overlap+ = textBeside_ (Str (spaces k)) k q+ | otherwise -- Put them really above+ = nilAbove_ (mkNest k q)+++-- ---------------------------------------------------------------------------+-- Horizontal composition @<>@++-- We intentionally avoid Data.Monoid.(<>) here due to interactions of+-- Data.Monoid.(<>) and (<+>). See+-- http://www.haskell.org/pipermail/libraries/2011-November/017066.html++-- | Beside.+-- '<>' is associative, with identity 'empty'.+(<>) :: Doc -> Doc -> Doc+p <> q = beside_ p False q++-- | Beside, separated by space, unless one of the arguments is 'empty'.+-- '<+>' is associative, with identity 'empty'.+(<+>) :: Doc -> Doc -> Doc+p <+> q = beside_ p True q++beside_ :: Doc -> Bool -> Doc -> Doc+beside_ p _ Empty = p+beside_ Empty _ q = q+beside_ p g q = Beside p g q++-- Specification: beside g p q = p <g> q+beside :: Doc -> Bool -> RDoc -> RDoc+beside NoDoc _ _ = NoDoc+beside (p1 `Union` p2) g q = beside p1 g q `union_` beside p2 g q+beside Empty _ q = q+beside (Nest k p) g q = nest_ k $! beside p g q+beside p@(Beside p1 g1 q1) g2 q2+ | g1 == g2 = beside p1 g1 $! beside q1 g2 q2+ | otherwise = beside (reduceDoc p) g2 q2+beside p@(Above{}) g q = let !d = reduceDoc p in beside d g q+beside (NilAbove p) g q = nilAbove_ $! beside p g q+beside (TextBeside s sl p) g q = textBeside_ s sl rest+ where+ rest = case p of+ Empty -> nilBeside g q+ _ -> beside p g q++-- Specification: text "" <> nilBeside g p+-- = text "" <g> p+nilBeside :: Bool -> RDoc -> RDoc+nilBeside _ Empty = Empty -- Hence the text "" in the spec+nilBeside g (Nest _ p) = nilBeside g p+nilBeside g p | g = textBeside_ spaceText 1 p+ | otherwise = p+++-- ---------------------------------------------------------------------------+-- Separate, @sep@++-- Specification: sep ps = oneLiner (hsep ps)+-- `union`+-- vcat ps++-- | Either 'hsep' or 'vcat'.+sep :: [Doc] -> Doc+sep = sepX True -- Separate with spaces++-- | Either 'hcat' or 'vcat'.+cat :: [Doc] -> Doc+cat = sepX False -- Don't++sepX :: Bool -> [Doc] -> Doc+sepX _ [] = empty+sepX x (p:ps) = sep1 x (reduceDoc p) 0 ps+++-- Specification: sep1 g k ys = sep (x : map (nest k) ys)+-- = oneLiner (x <g> nest k (hsep ys))+-- `union` x $$ nest k (vcat ys)+sep1 :: Bool -> RDoc -> Int -> [Doc] -> RDoc+sep1 _ _ k _ | k `seq` False = undefined+sep1 _ NoDoc _ _ = NoDoc+sep1 g (p `Union` q) k ys = sep1 g p k ys `union_`+ aboveNest q False k (reduceDoc (vcat ys))++sep1 g Empty k ys = mkNest k (sepX g ys)+sep1 g (Nest n p) k ys = nest_ n (sep1 g p (k - n) ys)++sep1 _ (NilAbove p) k ys = nilAbove_+ (aboveNest p False k (reduceDoc (vcat ys)))+sep1 g (TextBeside s sl p) k ys = textBeside_ s sl (sepNB g p (k - sl) ys)+sep1 _ (Above {}) _ _ = error "sep1 Above"+sep1 _ (Beside {}) _ _ = error "sep1 Beside"++-- Specification: sepNB p k ys = sep1 (text "" <> p) k ys+-- Called when we have already found some text in the first item+-- We have to eat up nests+sepNB :: Bool -> Doc -> Int -> [Doc] -> Doc+sepNB g (Nest _ p) k ys+ = sepNB g p k ys -- Never triggered, because of invariant (2)+sepNB g Empty k ys+ = oneLiner (nilBeside g (reduceDoc rest)) `mkUnion`+ -- XXX: TODO: PRETTY: Used to use True here (but GHC used False...)+ nilAboveNest False k (reduceDoc (vcat ys))+ where+ rest | g = hsep ys+ | otherwise = hcat ys+sepNB g p k ys+ = sep1 g p k ys+++-- ---------------------------------------------------------------------------+-- @fill@++-- | \"Paragraph fill\" version of 'cat'.+fcat :: [Doc] -> Doc+fcat = fill False++-- | \"Paragraph fill\" version of 'sep'.+fsep :: [Doc] -> Doc+fsep = fill True++-- Specification:+--+-- fill g docs = fillIndent 0 docs+--+-- fillIndent k [] = []+-- fillIndent k [p] = p+-- fillIndent k (p1:p2:ps) =+-- oneLiner p1 <g> fillIndent (k + length p1 + g ? 1 : 0)+-- (remove_nests (oneLiner p2) : ps)+-- `Union`+-- (p1 $*$ nest (-k) (fillIndent 0 ps))+--+-- $*$ is defined for layouts (not Docs) as+-- layout1 $*$ layout2 | hasMoreThanOneLine layout1 = layout1 $$ layout2+-- | otherwise = layout1 $+$ layout2++fill :: Bool -> [Doc] -> RDoc+fill _ [] = empty+fill g (p:ps) = fill1 g (reduceDoc p) 0 ps++fill1 :: Bool -> RDoc -> Int -> [Doc] -> Doc+fill1 _ _ k _ | k `seq` False = undefined+fill1 _ NoDoc _ _ = NoDoc+fill1 g (p `Union` q) k ys = fill1 g p k ys `union_`+ aboveNest q False k (fill g ys)+fill1 g Empty k ys = mkNest k (fill g ys)+fill1 g (Nest n p) k ys = nest_ n (fill1 g p (k - n) ys)+fill1 g (NilAbove p) k ys = nilAbove_ (aboveNest p False k (fill g ys))+fill1 g (TextBeside s sl p) k ys = textBeside_ s sl (fillNB g p (k - sl) ys)+fill1 _ (Above {}) _ _ = error "fill1 Above"+fill1 _ (Beside {}) _ _ = error "fill1 Beside"++fillNB :: Bool -> Doc -> Int -> [Doc] -> Doc+fillNB _ _ k _ | k `seq` False = undefined+fillNB g (Nest _ p) k ys = fillNB g p k ys+ -- Never triggered, because of invariant (2)+fillNB _ Empty _ [] = Empty+fillNB g Empty k (Empty:ys) = fillNB g Empty k ys+fillNB g Empty k (y:ys) = fillNBE g k y ys+fillNB g p k ys = fill1 g p k ys+++fillNBE :: Bool -> Int -> Doc -> [Doc] -> Doc+fillNBE g k y ys+ = nilBeside g (fill1 g ((elideNest . oneLiner . reduceDoc) y) k' ys)+ -- XXX: TODO: PRETTY: Used to use True here (but GHC used False...)+ `mkUnion` nilAboveNest False k (fill g (y:ys))+ where k' = if g then k - 1 else k++elideNest :: Doc -> Doc+elideNest (Nest _ d) = d+elideNest d = d++-- ---------------------------------------------------------------------------+-- Selecting the best layout++best :: Int -- Line length+ -> Int -- Ribbon length+ -> RDoc+ -> RDoc -- No unions in here!+best w0 r = get w0+ where+ get :: Int -- (Remaining) width of line+ -> Doc -> Doc+ get w _ | w == 0 && False = undefined+ get _ Empty = Empty+ get _ NoDoc = NoDoc+ get w (NilAbove p) = nilAbove_ (get w p)+ get w (TextBeside s sl p) = textBeside_ s sl (get1 w sl p)+ get w (Nest k p) = nest_ k (get (w - k) p)+ get w (p `Union` q) = nicest w r (get w p) (get w q)+ get _ (Above {}) = error "best get Above"+ get _ (Beside {}) = error "best get Beside"++ get1 :: Int -- (Remaining) width of line+ -> Int -- Amount of first line already eaten up+ -> Doc -- This is an argument to TextBeside => eat Nests+ -> Doc -- No unions in here!++ get1 w _ _ | w == 0 && False = undefined+ get1 _ _ Empty = Empty+ get1 _ _ NoDoc = NoDoc+ get1 w sl (NilAbove p) = nilAbove_ (get (w - sl) p)+ get1 w sl (TextBeside t tl p) = textBeside_ t tl (get1 w (sl + tl) p)+ get1 w sl (Nest _ p) = get1 w sl p+ get1 w sl (p `Union` q) = nicest1 w r sl (get1 w sl p)+ (get1 w sl q)+ get1 _ _ (Above {}) = error "best get1 Above"+ get1 _ _ (Beside {}) = error "best get1 Beside"++nicest :: Int -> Int -> Doc -> Doc -> Doc+nicest !w !r = nicest1 w r 0++nicest1 :: Int -> Int -> Int -> Doc -> Doc -> Doc+nicest1 !w !r !sl p q | fits ((w `min` r) - sl) p = p+ | otherwise = q++fits :: Int -- Space available+ -> Doc+ -> Bool -- True if *first line* of Doc fits in space available+fits n _ | n < 0 = False+fits _ NoDoc = False+fits _ Empty = True+fits _ (NilAbove _) = True+fits n (TextBeside _ sl p) = fits (n - sl) p+fits _ (Above {}) = error "fits Above"+fits _ (Beside {}) = error "fits Beside"+fits _ (Union {}) = error "fits Union"+fits _ (Nest {}) = error "fits Nest"++-- | @first@ returns its first argument if it is non-empty, otherwise its second.+first :: Doc -> Doc -> Doc+first p q | nonEmptySet p = p -- unused, because (get OneLineMode) is unused+ | otherwise = q++nonEmptySet :: Doc -> Bool+nonEmptySet NoDoc = False+nonEmptySet (_ `Union` _) = True+nonEmptySet Empty = True+nonEmptySet (NilAbove _) = True+nonEmptySet (TextBeside _ _ p) = nonEmptySet p+nonEmptySet (Nest _ p) = nonEmptySet p+nonEmptySet (Above {}) = error "nonEmptySet Above"+nonEmptySet (Beside {}) = error "nonEmptySet Beside"++-- @oneLiner@ returns the one-line members of the given set of @GDoc@s.+oneLiner :: Doc -> Doc+oneLiner NoDoc = NoDoc+oneLiner Empty = Empty+oneLiner (NilAbove _) = NoDoc+oneLiner (TextBeside s sl p) = textBeside_ s sl (oneLiner p)+oneLiner (Nest k p) = nest_ k (oneLiner p)+oneLiner (p `Union` _) = oneLiner p+oneLiner (Above {}) = error "oneLiner Above"+oneLiner (Beside {}) = error "oneLiner Beside"+++-- ---------------------------------------------------------------------------+-- Rendering++-- | A rendering style.+data Style+ = Style { mode :: Mode -- ^ The rendering mode+ , lineLength :: Int -- ^ Length of line, in chars+ , ribbonsPerLine :: Float -- ^ Ratio of line length to ribbon length+ }++-- | The default style (@mode=PageMode, lineLength=100, ribbonsPerLine=1.5@).+style :: Style+style = Style { lineLength = 100, ribbonsPerLine = 1.5, mode = PageMode }++-- | Rendering mode.+data Mode = PageMode -- ^ Normal+ | ZigZagMode -- ^ With zig-zag cuts+ | LeftMode -- ^ No indentation, infinitely long lines+ | OneLineMode -- ^ All on one line++-- | Render the @Doc@ to a String using the given @Style@.+renderStyle :: Style -> Doc -> String+renderStyle s = fullRender (mode s) (lineLength s) (ribbonsPerLine s)+ txtPrinter ""++-- | Default TextDetails printer+txtPrinter :: TextDetails -> String -> String+txtPrinter (Chr c) s = c:s+txtPrinter (Str s1) s2 = s1 ++ s2+txtPrinter (PStr s1) s2 = unpackFS s1 ++ s2+txtPrinter (ZStr s1) s2 = zString s1 ++ s2+txtPrinter (LStr s1 _) s2 = unpackLitString s1 ++ s2++-- | The general rendering interface.+fullRender :: Mode -- ^ Rendering mode+ -> Int -- ^ Line length+ -> Float -- ^ Ribbons per line+ -> (TextDetails -> a -> a) -- ^ What to do with text+ -> a -- ^ What to do at the end+ -> Doc -- ^ The document+ -> a -- ^ Result+fullRender OneLineMode _ _ txt end doc+ = easyDisplay spaceText (\_ y -> y) txt end (reduceDoc doc)+fullRender LeftMode _ _ txt end doc+ = easyDisplay nlText first txt end (reduceDoc doc)++fullRender m lineLen ribbons txt rest doc+ = display m lineLen ribbonLen txt rest doc'+ where+ doc' = best bestLineLen ribbonLen (reduceDoc doc)++ bestLineLen, ribbonLen :: Int+ ribbonLen = round (fromIntegral lineLen / ribbons)+ bestLineLen = case m of+ ZigZagMode -> maxBound+ _ -> lineLen++easyDisplay :: TextDetails+ -> (Doc -> Doc -> Doc)+ -> (TextDetails -> a -> a)+ -> a+ -> Doc+ -> a+easyDisplay nlSpaceText choose txt end+ = lay+ where+ lay NoDoc = error "easyDisplay: NoDoc"+ lay (Union p q) = lay (choose p q)+ lay (Nest _ p) = lay p+ lay Empty = end+ lay (NilAbove p) = nlSpaceText `txt` lay p+ lay (TextBeside s _ p) = s `txt` lay p+ lay (Above {}) = error "easyDisplay Above"+ lay (Beside {}) = error "easyDisplay Beside"++display :: Mode -> Int -> Int -> (TextDetails -> a -> a) -> a -> Doc -> a+display m !page_width !ribbon_width txt end doc+ = case page_width - ribbon_width of { gap_width ->+ case gap_width `quot` 2 of { shift ->+ let+ lay k _ | k `seq` False = undefined+ lay k (Nest k1 p) = lay (k + k1) p+ lay _ Empty = end+ lay k (NilAbove p) = nlText `txt` lay k p+ lay k (TextBeside s sl p)+ = case m of+ ZigZagMode | k >= gap_width+ -> nlText `txt` (+ Str (replicate shift '/') `txt` (+ nlText `txt`+ lay1 (k - shift) s sl p ))++ | k < 0+ -> nlText `txt` (+ Str (replicate shift '\\') `txt` (+ nlText `txt`+ lay1 (k + shift) s sl p ))++ _ -> lay1 k s sl p+ lay _ (Above {}) = error "display lay Above"+ lay _ (Beside {}) = error "display lay Beside"+ lay _ NoDoc = error "display lay NoDoc"+ lay _ (Union {}) = error "display lay Union"++ lay1 !k s !sl p = let !r = k + sl+ in indent k (s `txt` lay2 r p)++ lay2 k _ | k `seq` False = undefined+ lay2 k (NilAbove p) = nlText `txt` lay k p+ lay2 k (TextBeside s sl p) = s `txt` lay2 (k + sl) p+ lay2 k (Nest _ p) = lay2 k p+ lay2 _ Empty = end+ lay2 _ (Above {}) = error "display lay2 Above"+ lay2 _ (Beside {}) = error "display lay2 Beside"+ lay2 _ NoDoc = error "display lay2 NoDoc"+ lay2 _ (Union {}) = error "display lay2 Union"++ -- optimise long indentations using LitString chunks of 8 spaces+ indent !n r | n >= 8 = LStr (sLit " ") 8 `txt`+ indent (n - 8) r+ | otherwise = Str (spaces n) `txt` r+ in+ lay 0 doc+ }}++printDoc :: Mode -> Int -> Handle -> Doc -> IO ()+-- printDoc adds a newline to the end+printDoc mode cols hdl doc = printDoc_ mode cols hdl (doc $$ text "")++printDoc_ :: Mode -> Int -> Handle -> Doc -> IO ()+-- printDoc_ does not add a newline at the end, so that+-- successive calls can output stuff on the same line+-- Rather like putStr vs putStrLn+printDoc_ LeftMode _ hdl doc+ = do { printLeftRender hdl doc; hFlush hdl }+printDoc_ mode pprCols hdl doc+ = do { fullRender mode pprCols 1.5 put done doc ;+ hFlush hdl }+ where+ put (Chr c) next = hPutChar hdl c >> next+ put (Str s) next = hPutStr hdl s >> next+ put (PStr s) next = hPutStr hdl (unpackFS s) >> next+ -- NB. not hPutFS, we want this to go through+ -- the I/O library's encoding layer. (#3398)+ put (ZStr s) next = hPutFZS hdl s >> next+ put (LStr s l) next = hPutLitString hdl s l >> next++ done = return () -- hPutChar hdl '\n'++ -- some versions of hPutBuf will barf if the length is zero+hPutLitString :: Handle -> Ptr a -> Int -> IO ()+hPutLitString handle a l = if l == 0+ then return ()+ else hPutBuf handle a l++-- Printing output in LeftMode is performance critical: it's used when+-- dumping C and assembly output, so we allow ourselves a few dirty+-- hacks:+--+-- (1) we specialise fullRender for LeftMode with IO output.+--+-- (2) we add a layer of buffering on top of Handles. Handles+-- don't perform well with lots of hPutChars, which is mostly+-- what we're doing here, because Handles have to be thread-safe+-- and async exception-safe. We only have a single thread and don't+-- care about exceptions, so we add a layer of fast buffering+-- over the Handle interface.++printLeftRender :: Handle -> Doc -> IO ()+printLeftRender hdl doc = do+ b <- newBufHandle hdl+ bufLeftRender b doc+ bFlush b++bufLeftRender :: BufHandle -> Doc -> IO ()+bufLeftRender b doc = layLeft b (reduceDoc doc)++layLeft :: BufHandle -> Doc -> IO ()+layLeft b _ | b `seq` False = undefined -- make it strict in b+layLeft _ NoDoc = error "layLeft: NoDoc"+layLeft b (Union p q) = layLeft b (first p q)+layLeft b (Nest _ p) = layLeft b p+layLeft b Empty = bPutChar b '\n'+layLeft b (NilAbove p) = bPutChar b '\n' >> layLeft b p+layLeft b (TextBeside s _ p) = put b s >> layLeft b p+ where+ put b _ | b `seq` False = undefined+ put b (Chr c) = bPutChar b c+ put b (Str s) = bPutStr b s+ put b (PStr s) = bPutFS b s+ put b (ZStr s) = bPutFZS b s+ put b (LStr s l) = bPutLitString b s l+layLeft _ _ = panic "layLeft: Unhandled case"++-- Define error=panic, for easier comparison with libraries/pretty.+error :: String -> a+error = panic
+ utils/State.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE UnboxedTuples #-}++module State where++newtype State s a = State { runState' :: s -> (# a, s #) }++instance Functor (State s) where+ fmap f m = State $ \s -> case runState' m s of+ (# r, s' #) -> (# f r, s' #)++instance Applicative (State s) where+ pure x = State $ \s -> (# x, s #)+ m <*> n = State $ \s -> case runState' m s of+ (# f, s' #) -> case runState' n s' of+ (# x, s'' #) -> (# f x, s'' #)++instance Monad (State s) where+ m >>= n = State $ \s -> case runState' m s of+ (# r, s' #) -> runState' (n r) s'++get :: State s s+get = State $ \s -> (# s, s #)++gets :: (s -> a) -> State s a+gets f = State $ \s -> (# f s, s #)++put :: s -> State s ()+put s' = State $ \_ -> (# (), s' #)++modify :: (s -> s) -> State s ()+modify f = State $ \s -> (# (), f s #)+++evalState :: State s a -> s -> a+evalState s i = case runState' s i of+ (# a, _ #) -> a+++execState :: State s a -> s -> s+execState s i = case runState' s i of+ (# _, s' #) -> s'+++runState :: State s a -> s -> (a, s)+runState s i = case runState' s i of+ (# a, s' #) -> (a, s')
+ utils/Stream.hs view
@@ -0,0 +1,104 @@+-- -----------------------------------------------------------------------------+--+-- (c) The University of Glasgow 2012+--+-- Monadic streams+--+-- -----------------------------------------------------------------------------+module Stream (+ Stream(..), yield, liftIO,+ collect, fromList,+ Stream.map, Stream.mapM, Stream.mapAccumL+ ) where++import Control.Monad++-- |+-- @Stream m a b@ is a computation in some Monad @m@ that delivers a sequence+-- of elements of type @a@ followed by a result of type @b@.+--+-- More concretely, a value of type @Stream m a b@ can be run using @runStream@+-- in the Monad @m@, and it delivers either+--+-- * the final result: @Left b@, or+-- * @Right (a,str)@, where @a@ is the next element in the stream, and @str@+-- is a computation to get the rest of the stream.+--+-- Stream is itself a Monad, and provides an operation 'yield' that+-- produces a new element of the stream. This makes it convenient to turn+-- existing monadic computations into streams.+--+-- The idea is that Stream is useful for making a monadic computation+-- that produces values from time to time. This can be used for+-- knitting together two complex monadic operations, so that the+-- producer does not have to produce all its values before the+-- consumer starts consuming them. We make the producer into a+-- Stream, and the consumer pulls on the stream each time it wants a+-- new value.+--+newtype Stream m a b = Stream { runStream :: m (Either b (a, Stream m a b)) }++instance Monad f => Functor (Stream f a) where+ fmap = liftM++instance Monad m => Applicative (Stream m a) where+ pure a = Stream (return (Left a))+ (<*>) = ap++instance Monad m => Monad (Stream m a) where++ Stream m >>= k = Stream $ do+ r <- m+ case r of+ Left b -> runStream (k b)+ Right (a,str) -> return (Right (a, str >>= k))++yield :: Monad m => a -> Stream m a ()+yield a = Stream (return (Right (a, return ())))++liftIO :: IO a -> Stream IO b a+liftIO io = Stream $ io >>= return . Left++-- | Turn a Stream into an ordinary list, by demanding all the elements.+collect :: Monad m => Stream m a () -> m [a]+collect str = go str []+ where+ go str acc = do+ r <- runStream str+ case r of+ Left () -> return (reverse acc)+ Right (a, str') -> go str' (a:acc)++-- | Turn a list into a 'Stream', by yielding each element in turn.+fromList :: Monad m => [a] -> Stream m a ()+fromList = mapM_ yield++-- | Apply a function to each element of a 'Stream', lazily+map :: Monad m => (a -> b) -> Stream m a x -> Stream m b x+map f str = Stream $ do+ r <- runStream str+ case r of+ Left x -> return (Left x)+ Right (a, str') -> return (Right (f a, Stream.map f str'))++-- | Apply a monadic operation to each element of a 'Stream', lazily+mapM :: Monad m => (a -> m b) -> Stream m a x -> Stream m b x+mapM f str = Stream $ do+ r <- runStream str+ case r of+ Left x -> return (Left x)+ Right (a, str') -> do+ b <- f a+ return (Right (b, Stream.mapM f str'))++-- | analog of the list-based 'mapAccumL' on Streams. This is a simple+-- way to map over a Stream while carrying some state around.+mapAccumL :: Monad m => (c -> a -> m (c,b)) -> c -> Stream m a ()+ -> Stream m b c+mapAccumL f c str = Stream $ do+ r <- runStream str+ case r of+ Left () -> return (Left c)+ Right (a, str') -> do+ (c',b) <- f c a+ return (Right (b, mapAccumL f c' str'))
+ utils/StringBuffer.hs view
@@ -0,0 +1,310 @@+{-+(c) The University of Glasgow 2006+(c) The University of Glasgow, 1997-2006+++Buffers for scanning string input stored in external arrays.+-}++{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}+{-# OPTIONS_GHC -O #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected++module StringBuffer+ (+ StringBuffer(..),+ -- non-abstract for vs\/HaskellService++ -- * Creation\/destruction+ hGetStringBuffer,+ hGetStringBufferBlock,+ appendStringBuffers,+ stringToStringBuffer,++ -- * Inspection+ nextChar,+ currentChar,+ prevChar,+ atEnd,++ -- * Moving and comparison+ stepOn,+ offsetBytes,+ byteDiff,+ atLine,++ -- * Conversion+ lexemeToString,+ lexemeToFastString,++ -- * Parsing integers+ parseUnsignedInteger,+ ) where++#include "HsVersions.h"++import Encoding+import FastString+import FastFunctions+import Outputable+import Util++import Data.Maybe+import Control.Exception+import System.IO+import System.IO.Unsafe ( unsafePerformIO )+import GHC.IO.Encoding.UTF8 ( mkUTF8 )+import GHC.IO.Encoding.Failure ( CodingFailureMode(IgnoreCodingFailure) )++import GHC.Exts++import Foreign++-- -----------------------------------------------------------------------------+-- The StringBuffer type++-- |A StringBuffer is an internal pointer to a sized chunk of bytes.+-- The bytes are intended to be *immutable*. There are pure+-- operations to read the contents of a StringBuffer.+--+-- A StringBuffer may have a finalizer, depending on how it was+-- obtained.+--+data StringBuffer+ = StringBuffer {+ buf :: {-# UNPACK #-} !(ForeignPtr Word8),+ len :: {-# UNPACK #-} !Int, -- length+ cur :: {-# UNPACK #-} !Int -- current pos+ }+ -- The buffer is assumed to be UTF-8 encoded, and furthermore+ -- we add three '\0' bytes to the end as sentinels so that the+ -- decoder doesn't have to check for overflow at every single byte+ -- of a multibyte sequence.++instance Show StringBuffer where+ showsPrec _ s = showString "<stringbuffer("+ . shows (len s) . showString "," . shows (cur s)+ . showString ")>"++-- -----------------------------------------------------------------------------+-- Creation / Destruction++-- | Read a file into a 'StringBuffer'. The resulting buffer is automatically+-- managed by the garbage collector.+hGetStringBuffer :: FilePath -> IO StringBuffer+hGetStringBuffer fname = do+ h <- openBinaryFile fname ReadMode+ size_i <- hFileSize h+ offset_i <- skipBOM h size_i 0 -- offset is 0 initially+ let size = fromIntegral $ size_i - offset_i+ buf <- mallocForeignPtrArray (size+3)+ withForeignPtr buf $ \ptr -> do+ r <- if size == 0 then return 0 else hGetBuf h ptr size+ hClose h+ if (r /= size)+ then ioError (userError "short read of file")+ else newUTF8StringBuffer buf ptr size++hGetStringBufferBlock :: Handle -> Int -> IO StringBuffer+hGetStringBufferBlock handle wanted+ = do size_i <- hFileSize handle+ offset_i <- hTell handle >>= skipBOM handle size_i+ let size = min wanted (fromIntegral $ size_i-offset_i)+ buf <- mallocForeignPtrArray (size+3)+ withForeignPtr buf $ \ptr ->+ do r <- if size == 0 then return 0 else hGetBuf handle ptr size+ if r /= size+ then ioError (userError $ "short read of file: "++show(r,size,size_i,handle))+ else newUTF8StringBuffer buf ptr size++-- | Skip the byte-order mark if there is one (see #1744 and #6016),+-- and return the new position of the handle in bytes.+--+-- This is better than treating #FEFF as whitespace,+-- because that would mess up layout. We don't have a concept+-- of zero-width whitespace in Haskell: all whitespace codepoints+-- have a width of one column.+skipBOM :: Handle -> Integer -> Integer -> IO Integer+skipBOM h size offset =+ -- Only skip BOM at the beginning of a file.+ if size > 0 && offset == 0+ then do+ -- Validate assumption that handle is in binary mode.+ ASSERTM( hGetEncoding h >>= return . isNothing )+ -- Temporarily select utf8 encoding with error ignoring,+ -- to make `hLookAhead` and `hGetChar` return full Unicode characters.+ bracket_ (hSetEncoding h safeEncoding) (hSetBinaryMode h True) $ do+ c <- hLookAhead h+ if c == '\xfeff'+ then hGetChar h >> hTell h+ else return offset+ else return offset+ where+ safeEncoding = mkUTF8 IgnoreCodingFailure++newUTF8StringBuffer :: ForeignPtr Word8 -> Ptr Word8 -> Int -> IO StringBuffer+newUTF8StringBuffer buf ptr size = do+ pokeArray (ptr `plusPtr` size :: Ptr Word8) [0,0,0]+ -- sentinels for UTF-8 decoding+ return $ StringBuffer buf size 0++appendStringBuffers :: StringBuffer -> StringBuffer -> IO StringBuffer+appendStringBuffers sb1 sb2+ = do newBuf <- mallocForeignPtrArray (size+3)+ withForeignPtr newBuf $ \ptr ->+ withForeignPtr (buf sb1) $ \sb1Ptr ->+ withForeignPtr (buf sb2) $ \sb2Ptr ->+ do copyArray ptr (sb1Ptr `advancePtr` cur sb1) sb1_len+ copyArray (ptr `advancePtr` sb1_len) (sb2Ptr `advancePtr` cur sb2) sb2_len+ pokeArray (ptr `advancePtr` size) [0,0,0]+ return (StringBuffer newBuf size 0)+ where sb1_len = calcLen sb1+ sb2_len = calcLen sb2+ calcLen sb = len sb - cur sb+ size = sb1_len + sb2_len++-- | Encode a 'String' into a 'StringBuffer' as UTF-8. The resulting buffer+-- is automatically managed by the garbage collector.+stringToStringBuffer :: String -> StringBuffer+stringToStringBuffer str =+ unsafePerformIO $ do+ let size = utf8EncodedLength str+ buf <- mallocForeignPtrArray (size+3)+ withForeignPtr buf $ \ptr -> do+ utf8EncodeString ptr str+ pokeArray (ptr `plusPtr` size :: Ptr Word8) [0,0,0]+ -- sentinels for UTF-8 decoding+ return (StringBuffer buf size 0)++-- -----------------------------------------------------------------------------+-- Grab a character++-- | Return the first UTF-8 character of a nonempty 'StringBuffer' and as well+-- the remaining portion (analogous to 'Data.List.uncons'). __Warning:__ The+-- behavior is undefined if the 'StringBuffer' is empty. The result shares+-- the same buffer as the original. Similar to 'utf8DecodeChar', if the+-- character cannot be decoded as UTF-8, '\0' is returned.+{-# INLINE nextChar #-}+nextChar :: StringBuffer -> (Char,StringBuffer)+nextChar (StringBuffer buf len (I# cur#)) =+ -- Getting our fingers dirty a little here, but this is performance-critical+ inlinePerformIO $ do+ withForeignPtr buf $ \(Ptr a#) -> do+ case utf8DecodeChar# (a# `plusAddr#` cur#) of+ (# c#, nBytes# #) ->+ let cur' = I# (cur# +# nBytes#) in+ return (C# c#, StringBuffer buf len cur')++-- | Return the first UTF-8 character of a nonempty 'StringBuffer' (analogous+-- to 'Data.List.head'). __Warning:__ The behavior is undefined if the+-- 'StringBuffer' is empty. Similar to 'utf8DecodeChar', if the character+-- cannot be decoded as UTF-8, '\0' is returned.+currentChar :: StringBuffer -> Char+currentChar = fst . nextChar++prevChar :: StringBuffer -> Char -> Char+prevChar (StringBuffer _ _ 0) deflt = deflt+prevChar (StringBuffer buf _ cur) _ =+ inlinePerformIO $ do+ withForeignPtr buf $ \p -> do+ p' <- utf8PrevChar (p `plusPtr` cur)+ return (fst (utf8DecodeChar p'))++-- -----------------------------------------------------------------------------+-- Moving++-- | Return a 'StringBuffer' with the first UTF-8 character removed (analogous+-- to 'Data.List.tail'). __Warning:__ The behavior is undefined if the+-- 'StringBuffer' is empty. The result shares the same buffer as the+-- original.+stepOn :: StringBuffer -> StringBuffer+stepOn s = snd (nextChar s)++-- | Return a 'StringBuffer' with the first @n@ bytes removed. __Warning:__+-- If there aren't enough characters, the returned 'StringBuffer' will be+-- invalid and any use of it may lead to undefined behavior. The result+-- shares the same buffer as the original.+offsetBytes :: Int -- ^ @n@, the number of bytes+ -> StringBuffer+ -> StringBuffer+offsetBytes i s = s { cur = cur s + i }++-- | Compute the difference in offset between two 'StringBuffer's that share+-- the same buffer. __Warning:__ The behavior is undefined if the+-- 'StringBuffer's use separate buffers.+byteDiff :: StringBuffer -> StringBuffer -> Int+byteDiff s1 s2 = cur s2 - cur s1++-- | Check whether a 'StringBuffer' is empty (analogous to 'Data.List.null').+atEnd :: StringBuffer -> Bool+atEnd (StringBuffer _ l c) = l == c++-- | Computes a 'StringBuffer' which points to the first character of the+-- wanted line. Lines begin at 1.+atLine :: Int -> StringBuffer -> Maybe StringBuffer+atLine line sb@(StringBuffer buf len _) =+ inlinePerformIO $+ withForeignPtr buf $ \p -> do+ p' <- skipToLine line len p+ if p' == nullPtr+ then return Nothing+ else+ let+ delta = p' `minusPtr` p+ in return $ Just (sb { cur = delta+ , len = len - delta+ })++skipToLine :: Int -> Int -> Ptr Word8 -> IO (Ptr Word8)+skipToLine !line !len !op0 = go 1 op0+ where+ !opend = op0 `plusPtr` len++ go !i_line !op+ | op >= opend = pure nullPtr+ | i_line == line = pure op+ | otherwise = do+ w <- peek op :: IO Word8+ case w of+ 10 -> go (i_line + 1) (plusPtr op 1)+ 13 -> do+ -- this is safe because a 'StringBuffer' is+ -- guaranteed to have 3 bytes sentinel values.+ w' <- peek (plusPtr op 1) :: IO Word8+ case w' of+ 10 -> go (i_line + 1) (plusPtr op 2)+ _ -> go (i_line + 1) (plusPtr op 1)+ _ -> go i_line (plusPtr op 1)++-- -----------------------------------------------------------------------------+-- Conversion++-- | Decode the first @n@ bytes of a 'StringBuffer' as UTF-8 into a 'String'.+-- Similar to 'utf8DecodeChar', if the character cannot be decoded as UTF-8,+-- they will be replaced with '\0'.+lexemeToString :: StringBuffer+ -> Int -- ^ @n@, the number of bytes+ -> String+lexemeToString _ 0 = ""+lexemeToString (StringBuffer buf _ cur) bytes =+ utf8DecodeStringLazy buf cur bytes++lexemeToFastString :: StringBuffer+ -> Int -- ^ @n@, the number of bytes+ -> FastString+lexemeToFastString _ 0 = nilFS+lexemeToFastString (StringBuffer buf _ cur) len =+ inlinePerformIO $+ withForeignPtr buf $ \ptr ->+ return $! mkFastStringBytes (ptr `plusPtr` cur) len++-- -----------------------------------------------------------------------------+-- Parsing integer strings in various bases+parseUnsignedInteger :: StringBuffer -> Int -> Integer -> (Char->Int) -> Integer+parseUnsignedInteger (StringBuffer buf _ cur) len radix char_to_int+ = inlinePerformIO $ withForeignPtr buf $ \ptr -> return $! let+ go i x | i == len = x+ | otherwise = case fst (utf8DecodeChar (ptr `plusPtr` (cur + i))) of+ char -> go (i + 1) (x * radix + toInteger (char_to_int char))+ in go 0 0
+ utils/UnVarGraph.hs view
@@ -0,0 +1,136 @@+{-++Copyright (c) 2014 Joachim Breitner++A data structure for undirected graphs of variables+(or in plain terms: Sets of unordered pairs of numbers)+++This is very specifically tailored for the use in CallArity. In particular it+stores the graph as a union of complete and complete bipartite graph, which+would be very expensive to store as sets of edges or as adjanceny lists.++It does not normalize the graphs. This means that g `unionUnVarGraph` g is+equal to g, but twice as expensive and large.++-}+module UnVarGraph+ ( UnVarSet+ , emptyUnVarSet, mkUnVarSet, varEnvDom, unionUnVarSet, unionUnVarSets+ , delUnVarSet+ , elemUnVarSet, isEmptyUnVarSet+ , UnVarGraph+ , emptyUnVarGraph+ , unionUnVarGraph, unionUnVarGraphs+ , completeGraph, completeBipartiteGraph+ , neighbors+ , delNode+ ) where++import Id+import VarEnv+import UniqFM+import Outputable+import Data.List+import Bag+import Unique++import qualified Data.IntSet as S++-- We need a type for sets of variables (UnVarSet).+-- We do not use VarSet, because for that we need to have the actual variable+-- at hand, and we do not have that when we turn the domain of a VarEnv into a UnVarSet.+-- Therefore, use a IntSet directly (which is likely also a bit more efficient).++-- Set of uniques, i.e. for adjancet nodes+newtype UnVarSet = UnVarSet (S.IntSet)+ deriving Eq++k :: Var -> Int+k v = getKey (getUnique v)++emptyUnVarSet :: UnVarSet+emptyUnVarSet = UnVarSet S.empty++elemUnVarSet :: Var -> UnVarSet -> Bool+elemUnVarSet v (UnVarSet s) = k v `S.member` s+++isEmptyUnVarSet :: UnVarSet -> Bool+isEmptyUnVarSet (UnVarSet s) = S.null s++delUnVarSet :: UnVarSet -> Var -> UnVarSet+delUnVarSet (UnVarSet s) v = UnVarSet $ k v `S.delete` s++mkUnVarSet :: [Var] -> UnVarSet+mkUnVarSet vs = UnVarSet $ S.fromList $ map k vs++varEnvDom :: VarEnv a -> UnVarSet+varEnvDom ae = UnVarSet $ ufmToSet_Directly ae++unionUnVarSet :: UnVarSet -> UnVarSet -> UnVarSet+unionUnVarSet (UnVarSet set1) (UnVarSet set2) = UnVarSet (set1 `S.union` set2)++unionUnVarSets :: [UnVarSet] -> UnVarSet+unionUnVarSets = foldr unionUnVarSet emptyUnVarSet++instance Outputable UnVarSet where+ ppr (UnVarSet s) = braces $+ hcat $ punctuate comma [ ppr (getUnique i) | i <- S.toList s]+++-- The graph type. A list of complete bipartite graphs+data Gen = CBPG UnVarSet UnVarSet -- complete bipartite+ | CG UnVarSet -- complete+newtype UnVarGraph = UnVarGraph (Bag Gen)++emptyUnVarGraph :: UnVarGraph+emptyUnVarGraph = UnVarGraph emptyBag++unionUnVarGraph :: UnVarGraph -> UnVarGraph -> UnVarGraph+{-+Premature optimisation, it seems.+unionUnVarGraph (UnVarGraph [CBPG s1 s2]) (UnVarGraph [CG s3, CG s4])+ | s1 == s3 && s2 == s4+ = pprTrace "unionUnVarGraph fired" empty $+ completeGraph (s1 `unionUnVarSet` s2)+unionUnVarGraph (UnVarGraph [CBPG s1 s2]) (UnVarGraph [CG s3, CG s4])+ | s2 == s3 && s1 == s4+ = pprTrace "unionUnVarGraph fired2" empty $+ completeGraph (s1 `unionUnVarSet` s2)+-}+unionUnVarGraph (UnVarGraph g1) (UnVarGraph g2)+ = -- pprTrace "unionUnVarGraph" (ppr (length g1, length g2)) $+ UnVarGraph (g1 `unionBags` g2)++unionUnVarGraphs :: [UnVarGraph] -> UnVarGraph+unionUnVarGraphs = foldl' unionUnVarGraph emptyUnVarGraph++-- completeBipartiteGraph A B = { {a,b} | a ∈ A, b ∈ B }+completeBipartiteGraph :: UnVarSet -> UnVarSet -> UnVarGraph+completeBipartiteGraph s1 s2 = prune $ UnVarGraph $ unitBag $ CBPG s1 s2++completeGraph :: UnVarSet -> UnVarGraph+completeGraph s = prune $ UnVarGraph $ unitBag $ CG s++neighbors :: UnVarGraph -> Var -> UnVarSet+neighbors (UnVarGraph g) v = unionUnVarSets $ concatMap go $ bagToList g+ where go (CG s) = (if v `elemUnVarSet` s then [s] else [])+ go (CBPG s1 s2) = (if v `elemUnVarSet` s1 then [s2] else []) +++ (if v `elemUnVarSet` s2 then [s1] else [])++delNode :: UnVarGraph -> Var -> UnVarGraph+delNode (UnVarGraph g) v = prune $ UnVarGraph $ mapBag go g+ where go (CG s) = CG (s `delUnVarSet` v)+ go (CBPG s1 s2) = CBPG (s1 `delUnVarSet` v) (s2 `delUnVarSet` v)++prune :: UnVarGraph -> UnVarGraph+prune (UnVarGraph g) = UnVarGraph $ filterBag go g+ where go (CG s) = not (isEmptyUnVarSet s)+ go (CBPG s1 s2) = not (isEmptyUnVarSet s1) && not (isEmptyUnVarSet s2)++instance Outputable Gen where+ ppr (CG s) = ppr s <> char '²'+ ppr (CBPG s1 s2) = ppr s1 <+> char 'x' <+> ppr s2+instance Outputable UnVarGraph where+ ppr (UnVarGraph g) = ppr g
+ utils/UniqDFM.hs view
@@ -0,0 +1,398 @@+{-+(c) Bartosz Nitka, Facebook, 2015++UniqDFM: Specialised deterministic finite maps, for things with @Uniques@.++Basically, the things need to be in class @Uniquable@, and we use the+@getUnique@ method to grab their @Uniques@.++This is very similar to @UniqFM@, the major difference being that the order of+folding is not dependent on @Unique@ ordering, giving determinism.+Currently the ordering is determined by insertion order.++See Note [Unique Determinism] in Unique for explanation why @Unique@ ordering+is not deterministic.+-}++{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE FlexibleContexts #-}+{-# OPTIONS_GHC -Wall #-}++module UniqDFM (+ -- * Unique-keyed deterministic mappings+ UniqDFM, -- abstract type++ -- ** Manipulating those mappings+ emptyUDFM,+ unitUDFM,+ addToUDFM,+ addToUDFM_C,+ addListToUDFM,+ delFromUDFM,+ delListFromUDFM,+ adjustUDFM,+ alterUDFM,+ mapUDFM,+ plusUDFM,+ plusUDFM_C,+ lookupUDFM, lookupUDFM_Directly,+ elemUDFM,+ foldUDFM,+ eltsUDFM,+ filterUDFM, filterUDFM_Directly,+ isNullUDFM,+ sizeUDFM,+ intersectUDFM, udfmIntersectUFM,+ intersectsUDFM,+ disjointUDFM, disjointUdfmUfm,+ minusUDFM,+ listToUDFM,+ udfmMinusUFM,+ partitionUDFM,+ anyUDFM, allUDFM,+ pprUDFM,++ udfmToList,+ udfmToUfm,+ nonDetFoldUDFM,+ alwaysUnsafeUfmToUdfm,+ ) where++import Unique ( Uniquable(..), Unique, getKey )+import Outputable++import qualified Data.IntMap as M+import Data.Data+import Data.List (sortBy)+import Data.Function (on)+import UniqFM (UniqFM, listToUFM_Directly, nonDetUFMToList, ufmToIntMap)++-- Note [Deterministic UniqFM]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- A @UniqDFM@ is just like @UniqFM@ with the following additional+-- property: the function `udfmToList` returns the elements in some+-- deterministic order not depending on the Unique key for those elements.+--+-- If the client of the map performs operations on the map in deterministic+-- order then `udfmToList` returns them in deterministic order.+--+-- There is an implementation cost: each element is given a serial number+-- as it is added, and `udfmToList` sorts it's result by this serial+-- number. So you should only use `UniqDFM` if you need the deterministic+-- property.+--+-- `foldUDFM` also preserves determinism.+--+-- Normal @UniqFM@ when you turn it into a list will use+-- Data.IntMap.toList function that returns the elements in the order of+-- the keys. The keys in @UniqFM@ are always @Uniques@, so you end up with+-- with a list ordered by @Uniques@.+-- The order of @Uniques@ is known to be not stable across rebuilds.+-- See Note [Unique Determinism] in Unique.+--+--+-- There's more than one way to implement this. The implementation here tags+-- every value with the insertion time that can later be used to sort the+-- values when asked to convert to a list.+--+-- An alternative would be to have+--+-- data UniqDFM ele = UDFM (M.IntMap ele) [ele]+--+-- where the list determines the order. This makes deletion tricky as we'd+-- only accumulate elements in that list, but makes merging easier as you+-- can just merge both structures independently.+-- Deletion can probably be done in amortized fashion when the size of the+-- list is twice the size of the set.++-- | A type of values tagged with insertion time+data TaggedVal val =+ TaggedVal+ val+ {-# UNPACK #-} !Int -- ^ insertion time+ deriving Data++taggedFst :: TaggedVal val -> val+taggedFst (TaggedVal v _) = v++taggedSnd :: TaggedVal val -> Int+taggedSnd (TaggedVal _ i) = i++instance Eq val => Eq (TaggedVal val) where+ (TaggedVal v1 _) == (TaggedVal v2 _) = v1 == v2++instance Functor TaggedVal where+ fmap f (TaggedVal val i) = TaggedVal (f val) i++-- | Type of unique deterministic finite maps+data UniqDFM ele =+ UDFM+ !(M.IntMap (TaggedVal ele)) -- A map where keys are Unique's values and+ -- values are tagged with insertion time.+ -- The invariant is that all the tags will+ -- be distinct within a single map+ {-# UNPACK #-} !Int -- Upper bound on the values' insertion+ -- time. See Note [Overflow on plusUDFM]+ deriving (Data, Functor)++emptyUDFM :: UniqDFM elt+emptyUDFM = UDFM M.empty 0++unitUDFM :: Uniquable key => key -> elt -> UniqDFM elt+unitUDFM k v = UDFM (M.singleton (getKey $ getUnique k) (TaggedVal v 0)) 1++addToUDFM :: Uniquable key => UniqDFM elt -> key -> elt -> UniqDFM elt+addToUDFM m k v = addToUDFM_Directly m (getUnique k) v++addToUDFM_Directly :: UniqDFM elt -> Unique -> elt -> UniqDFM elt+addToUDFM_Directly (UDFM m i) u v+ = UDFM (M.insertWith tf (getKey u) (TaggedVal v i) m) (i + 1)+ where+ tf (TaggedVal new_v _) (TaggedVal _ old_i) = TaggedVal new_v old_i+ -- Keep the old tag, but insert the new value+ -- This means that udfmToList typically returns elements+ -- in the order of insertion, rather than the reverse++addToUDFM_Directly_C+ :: (elt -> elt -> elt) -- old -> new -> result+ -> UniqDFM elt+ -> Unique -> elt+ -> UniqDFM elt+addToUDFM_Directly_C f (UDFM m i) u v+ = UDFM (M.insertWith tf (getKey u) (TaggedVal v i) m) (i + 1)+ where+ tf (TaggedVal new_v _) (TaggedVal old_v old_i)+ = TaggedVal (f old_v new_v) old_i+ -- Flip the arguments, because M.insertWith uses (new->old->result)+ -- but f needs (old->new->result)+ -- Like addToUDFM_Directly, keep the old tag++addToUDFM_C+ :: Uniquable key => (elt -> elt -> elt) -- old -> new -> result+ -> UniqDFM elt -- old+ -> key -> elt -- new+ -> UniqDFM elt -- result+addToUDFM_C f m k v = addToUDFM_Directly_C f m (getUnique k) v++addListToUDFM :: Uniquable key => UniqDFM elt -> [(key,elt)] -> UniqDFM elt+addListToUDFM = foldl (\m (k, v) -> addToUDFM m k v)++addListToUDFM_Directly :: UniqDFM elt -> [(Unique,elt)] -> UniqDFM elt+addListToUDFM_Directly = foldl (\m (k, v) -> addToUDFM_Directly m k v)++addListToUDFM_Directly_C+ :: (elt -> elt -> elt) -> UniqDFM elt -> [(Unique,elt)] -> UniqDFM elt+addListToUDFM_Directly_C f = foldl (\m (k, v) -> addToUDFM_Directly_C f m k v)++delFromUDFM :: Uniquable key => UniqDFM elt -> key -> UniqDFM elt+delFromUDFM (UDFM m i) k = UDFM (M.delete (getKey $ getUnique k) m) i++plusUDFM_C :: (elt -> elt -> elt) -> UniqDFM elt -> UniqDFM elt -> UniqDFM elt+plusUDFM_C f udfml@(UDFM _ i) udfmr@(UDFM _ j)+ -- we will use the upper bound on the tag as a proxy for the set size,+ -- to insert the smaller one into the bigger one+ | i > j = insertUDFMIntoLeft_C f udfml udfmr+ | otherwise = insertUDFMIntoLeft_C f udfmr udfml++-- Note [Overflow on plusUDFM]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~+-- There are multiple ways of implementing plusUDFM.+-- The main problem that needs to be solved is overlap on times of+-- insertion between different keys in two maps.+-- Consider:+--+-- A = fromList [(a, (x, 1))]+-- B = fromList [(b, (y, 1))]+--+-- If you merge them naively you end up with:+--+-- C = fromList [(a, (x, 1)), (b, (y, 1))]+--+-- Which loses information about ordering and brings us back into+-- non-deterministic world.+--+-- The solution I considered before would increment the tags on one of the+-- sets by the upper bound of the other set. The problem with this approach+-- is that you'll run out of tags for some merge patterns.+-- Say you start with A with upper bound 1, you merge A with A to get A' and+-- the upper bound becomes 2. You merge A' with A' and the upper bound+-- doubles again. After 64 merges you overflow.+-- This solution would have the same time complexity as plusUFM, namely O(n+m).+--+-- The solution I ended up with has time complexity of+-- O(m log m + m * min (n+m, W)) where m is the smaller set.+-- It simply inserts the elements of the smaller set into the larger+-- set in the order that they were inserted into the smaller set. That's+-- O(m log m) for extracting the elements from the smaller set in the+-- insertion order and O(m * min(n+m, W)) to insert them into the bigger+-- set.++plusUDFM :: UniqDFM elt -> UniqDFM elt -> UniqDFM elt+plusUDFM udfml@(UDFM _ i) udfmr@(UDFM _ j)+ -- we will use the upper bound on the tag as a proxy for the set size,+ -- to insert the smaller one into the bigger one+ | i > j = insertUDFMIntoLeft udfml udfmr+ | otherwise = insertUDFMIntoLeft udfmr udfml++insertUDFMIntoLeft :: UniqDFM elt -> UniqDFM elt -> UniqDFM elt+insertUDFMIntoLeft udfml udfmr = addListToUDFM_Directly udfml $ udfmToList udfmr++insertUDFMIntoLeft_C+ :: (elt -> elt -> elt) -> UniqDFM elt -> UniqDFM elt -> UniqDFM elt+insertUDFMIntoLeft_C f udfml udfmr =+ addListToUDFM_Directly_C f udfml $ udfmToList udfmr++lookupUDFM :: Uniquable key => UniqDFM elt -> key -> Maybe elt+lookupUDFM (UDFM m _i) k = taggedFst `fmap` M.lookup (getKey $ getUnique k) m++lookupUDFM_Directly :: UniqDFM elt -> Unique -> Maybe elt+lookupUDFM_Directly (UDFM m _i) k = taggedFst `fmap` M.lookup (getKey k) m++elemUDFM :: Uniquable key => key -> UniqDFM elt -> Bool+elemUDFM k (UDFM m _i) = M.member (getKey $ getUnique k) m++-- | Performs a deterministic fold over the UniqDFM.+-- It's O(n log n) while the corresponding function on `UniqFM` is O(n).+foldUDFM :: (elt -> a -> a) -> a -> UniqDFM elt -> a+foldUDFM k z m = foldr k z (eltsUDFM m)++-- | Performs a nondeterministic fold over the UniqDFM.+-- It's O(n), same as the corresponding function on `UniqFM`.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetFoldUDFM :: (elt -> a -> a) -> a -> UniqDFM elt -> a+nonDetFoldUDFM k z (UDFM m _i) = foldr k z $ map taggedFst $ M.elems m++eltsUDFM :: UniqDFM elt -> [elt]+eltsUDFM (UDFM m _i) =+ map taggedFst $ sortBy (compare `on` taggedSnd) $ M.elems m++filterUDFM :: (elt -> Bool) -> UniqDFM elt -> UniqDFM elt+filterUDFM p (UDFM m i) = UDFM (M.filter (\(TaggedVal v _) -> p v) m) i++filterUDFM_Directly :: (Unique -> elt -> Bool) -> UniqDFM elt -> UniqDFM elt+filterUDFM_Directly p (UDFM m i) = UDFM (M.filterWithKey p' m) i+ where+ p' k (TaggedVal v _) = p (getUnique k) v++-- | Converts `UniqDFM` to a list, with elements in deterministic order.+-- It's O(n log n) while the corresponding function on `UniqFM` is O(n).+udfmToList :: UniqDFM elt -> [(Unique, elt)]+udfmToList (UDFM m _i) =+ [ (getUnique k, taggedFst v)+ | (k, v) <- sortBy (compare `on` (taggedSnd . snd)) $ M.toList m ]++isNullUDFM :: UniqDFM elt -> Bool+isNullUDFM (UDFM m _) = M.null m++sizeUDFM :: UniqDFM elt -> Int+sizeUDFM (UDFM m _i) = M.size m++intersectUDFM :: UniqDFM elt -> UniqDFM elt -> UniqDFM elt+intersectUDFM (UDFM x i) (UDFM y _j) = UDFM (M.intersection x y) i+ -- M.intersection is left biased, that means the result will only have+ -- a subset of elements from the left set, so `i` is a good upper bound.++udfmIntersectUFM :: UniqDFM elt -> UniqFM elt -> UniqDFM elt+udfmIntersectUFM (UDFM x i) y = UDFM (M.intersection x (ufmToIntMap y)) i+ -- M.intersection is left biased, that means the result will only have+ -- a subset of elements from the left set, so `i` is a good upper bound.++intersectsUDFM :: UniqDFM elt -> UniqDFM elt -> Bool+intersectsUDFM x y = isNullUDFM (x `intersectUDFM` y)++disjointUDFM :: UniqDFM elt -> UniqDFM elt -> Bool+disjointUDFM (UDFM x _i) (UDFM y _j) = M.null (M.intersection x y)++disjointUdfmUfm :: UniqDFM elt -> UniqFM elt2 -> Bool+disjointUdfmUfm (UDFM x _i) y = M.null (M.intersection x (ufmToIntMap y))++minusUDFM :: UniqDFM elt1 -> UniqDFM elt2 -> UniqDFM elt1+minusUDFM (UDFM x i) (UDFM y _j) = UDFM (M.difference x y) i+ -- M.difference returns a subset of a left set, so `i` is a good upper+ -- bound.++udfmMinusUFM :: UniqDFM elt1 -> UniqFM elt2 -> UniqDFM elt1+udfmMinusUFM (UDFM x i) y = UDFM (M.difference x (ufmToIntMap y)) i+ -- M.difference returns a subset of a left set, so `i` is a good upper+ -- bound.++-- | Partition UniqDFM into two UniqDFMs according to the predicate+partitionUDFM :: (elt -> Bool) -> UniqDFM elt -> (UniqDFM elt, UniqDFM elt)+partitionUDFM p (UDFM m i) =+ case M.partition (p . taggedFst) m of+ (left, right) -> (UDFM left i, UDFM right i)++-- | Delete a list of elements from a UniqDFM+delListFromUDFM :: Uniquable key => UniqDFM elt -> [key] -> UniqDFM elt+delListFromUDFM = foldl delFromUDFM++-- | This allows for lossy conversion from UniqDFM to UniqFM+udfmToUfm :: UniqDFM elt -> UniqFM elt+udfmToUfm (UDFM m _i) =+ listToUFM_Directly [(getUnique k, taggedFst tv) | (k, tv) <- M.toList m]++listToUDFM :: Uniquable key => [(key,elt)] -> UniqDFM elt+listToUDFM = foldl (\m (k, v) -> addToUDFM m k v) emptyUDFM++listToUDFM_Directly :: [(Unique, elt)] -> UniqDFM elt+listToUDFM_Directly = foldl (\m (u, v) -> addToUDFM_Directly m u v) emptyUDFM++-- | Apply a function to a particular element+adjustUDFM :: Uniquable key => (elt -> elt) -> UniqDFM elt -> key -> UniqDFM elt+adjustUDFM f (UDFM m i) k = UDFM (M.adjust (fmap f) (getKey $ getUnique k) m) i++-- | The expression (alterUDFM f k map) alters value x at k, or absence+-- thereof. alterUDFM can be used to insert, delete, or update a value in+-- UniqDFM. Use addToUDFM, delFromUDFM or adjustUDFM when possible, they are+-- more efficient.+alterUDFM+ :: Uniquable key+ => (Maybe elt -> Maybe elt) -- How to adjust+ -> UniqDFM elt -- old+ -> key -- new+ -> UniqDFM elt -- result+alterUDFM f (UDFM m i) k =+ UDFM (M.alter alterf (getKey $ getUnique k) m) (i + 1)+ where+ alterf Nothing = inject $ f Nothing+ alterf (Just (TaggedVal v _)) = inject $ f (Just v)+ inject Nothing = Nothing+ inject (Just v) = Just $ TaggedVal v i++-- | Map a function over every value in a UniqDFM+mapUDFM :: (elt1 -> elt2) -> UniqDFM elt1 -> UniqDFM elt2+mapUDFM f (UDFM m i) = UDFM (M.map (fmap f) m) i++anyUDFM :: (elt -> Bool) -> UniqDFM elt -> Bool+anyUDFM p (UDFM m _i) = M.foldr ((||) . p . taggedFst) False m++allUDFM :: (elt -> Bool) -> UniqDFM elt -> Bool+allUDFM p (UDFM m _i) = M.foldr ((&&) . p . taggedFst) True m++instance Monoid (UniqDFM a) where+ mempty = emptyUDFM+ mappend = plusUDFM++-- This should not be used in commited code, provided for convenience to+-- make ad-hoc conversions when developing+alwaysUnsafeUfmToUdfm :: UniqFM elt -> UniqDFM elt+alwaysUnsafeUfmToUdfm = listToUDFM_Directly . nonDetUFMToList++-- Output-ery++instance Outputable a => Outputable (UniqDFM a) where+ ppr ufm = pprUniqDFM ppr ufm++pprUniqDFM :: (a -> SDoc) -> UniqDFM a -> SDoc+pprUniqDFM ppr_elt ufm+ = brackets $ fsep $ punctuate comma $+ [ ppr uq <+> text ":->" <+> ppr_elt elt+ | (uq, elt) <- udfmToList ufm ]++pprUDFM :: UniqDFM a -- ^ The things to be pretty printed+ -> ([a] -> SDoc) -- ^ The pretty printing function to use on the elements+ -> SDoc -- ^ 'SDoc' where the things have been pretty+ -- printed+pprUDFM ufm pp = pp (eltsUDFM ufm)
+ utils/UniqDSet.hs view
@@ -0,0 +1,103 @@+-- (c) Bartosz Nitka, Facebook, 2015++-- |+-- Specialised deterministic sets, for things with @Uniques@+--+-- Based on @UniqDFMs@ (as you would expect).+-- See Note [Deterministic UniqFM] in UniqDFM for explanation why we need it.+--+-- Basically, the things need to be in class @Uniquable@.++module UniqDSet (+ -- * Unique set type+ UniqDSet, -- type synonym for UniqFM a++ -- ** Manipulating these sets+ delOneFromUniqDSet, delListFromUniqDSet,+ emptyUniqDSet,+ unitUniqDSet,+ mkUniqDSet,+ addOneToUniqDSet, addListToUniqDSet,+ unionUniqDSets, unionManyUniqDSets,+ minusUniqDSet, uniqDSetMinusUniqSet,+ intersectUniqDSets,+ intersectsUniqDSets,+ foldUniqDSet,+ elementOfUniqDSet,+ filterUniqDSet,+ sizeUniqDSet,+ isEmptyUniqDSet,+ lookupUniqDSet,+ uniqDSetToList,+ partitionUniqDSet+ ) where++import UniqDFM+import UniqSet+import Unique++type UniqDSet a = UniqDFM a++emptyUniqDSet :: UniqDSet a+emptyUniqDSet = emptyUDFM++unitUniqDSet :: Uniquable a => a -> UniqDSet a+unitUniqDSet x = unitUDFM x x++mkUniqDSet :: Uniquable a => [a] -> UniqDSet a+mkUniqDSet = foldl addOneToUniqDSet emptyUniqDSet++addOneToUniqDSet :: Uniquable a => UniqDSet a -> a -> UniqDSet a+addOneToUniqDSet set x = addToUDFM set x x++addListToUniqDSet :: Uniquable a => UniqDSet a -> [a] -> UniqDSet a+addListToUniqDSet = foldl addOneToUniqDSet++delOneFromUniqDSet :: Uniquable a => UniqDSet a -> a -> UniqDSet a+delOneFromUniqDSet = delFromUDFM++delListFromUniqDSet :: Uniquable a => UniqDSet a -> [a] -> UniqDSet a+delListFromUniqDSet = delListFromUDFM++unionUniqDSets :: UniqDSet a -> UniqDSet a -> UniqDSet a+unionUniqDSets = plusUDFM++unionManyUniqDSets :: [UniqDSet a] -> UniqDSet a+unionManyUniqDSets [] = emptyUniqDSet+unionManyUniqDSets sets = foldr1 unionUniqDSets sets++minusUniqDSet :: UniqDSet a -> UniqDSet a -> UniqDSet a+minusUniqDSet = minusUDFM++uniqDSetMinusUniqSet :: UniqDSet a -> UniqSet a -> UniqDSet a+uniqDSetMinusUniqSet xs ys = udfmMinusUFM xs (getUniqSet ys)++intersectUniqDSets :: UniqDSet a -> UniqDSet a -> UniqDSet a+intersectUniqDSets = intersectUDFM++intersectsUniqDSets :: UniqDSet a -> UniqDSet a -> Bool+intersectsUniqDSets = intersectsUDFM++foldUniqDSet :: (a -> b -> b) -> b -> UniqDSet a -> b+foldUniqDSet = foldUDFM++elementOfUniqDSet :: Uniquable a => a -> UniqDSet a -> Bool+elementOfUniqDSet = elemUDFM++filterUniqDSet :: (a -> Bool) -> UniqDSet a -> UniqDSet a+filterUniqDSet = filterUDFM++sizeUniqDSet :: UniqDSet a -> Int+sizeUniqDSet = sizeUDFM++isEmptyUniqDSet :: UniqDSet a -> Bool+isEmptyUniqDSet = isNullUDFM++lookupUniqDSet :: Uniquable a => UniqDSet a -> a -> Maybe a+lookupUniqDSet = lookupUDFM++uniqDSetToList :: UniqDSet a -> [a]+uniqDSetToList = eltsUDFM++partitionUniqDSet :: (a -> Bool) -> UniqDSet a -> (UniqDSet a, UniqDSet a)+partitionUniqDSet = partitionUDFM
+ utils/UniqFM.hs view
@@ -0,0 +1,411 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1994-1998+++UniqFM: Specialised finite maps, for things with @Uniques@.++Basically, the things need to be in class @Uniquable@, and we use the+@getUnique@ method to grab their @Uniques@.++(A similar thing to @UniqSet@, as opposed to @Set@.)++The interface is based on @FiniteMap@s, but the implementation uses+@Data.IntMap@, which is both maintained and faster than the past+implementation (see commit log).++The @UniqFM@ interface maps directly to Data.IntMap, only+``Data.IntMap.union'' is left-biased and ``plusUFM'' right-biased+and ``addToUFM\_C'' and ``Data.IntMap.insertWith'' differ in the order+of arguments of combining function.+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# OPTIONS_GHC -Wall #-}++module UniqFM (+ -- * Unique-keyed mappings+ UniqFM, -- abstract type++ -- ** Manipulating those mappings+ emptyUFM,+ unitUFM,+ unitDirectlyUFM,+ listToUFM,+ listToUFM_Directly,+ listToUFM_C,+ addToUFM,addToUFM_C,addToUFM_Acc,+ addListToUFM,addListToUFM_C,+ addToUFM_Directly,+ addListToUFM_Directly,+ adjustUFM, alterUFM,+ adjustUFM_Directly,+ delFromUFM,+ delFromUFM_Directly,+ delListFromUFM,+ delListFromUFM_Directly,+ plusUFM,+ plusUFM_C,+ plusUFM_CD,+ plusMaybeUFM_C,+ plusUFMList,+ minusUFM,+ intersectUFM,+ intersectUFM_C,+ disjointUFM,+ equalKeysUFM,+ nonDetFoldUFM, foldUFM, nonDetFoldUFM_Directly,+ anyUFM, allUFM, seqEltsUFM,+ mapUFM, mapUFM_Directly,+ elemUFM, elemUFM_Directly,+ filterUFM, filterUFM_Directly, partitionUFM,+ sizeUFM,+ isNullUFM,+ lookupUFM, lookupUFM_Directly,+ lookupWithDefaultUFM, lookupWithDefaultUFM_Directly,+ nonDetEltsUFM, eltsUFM, nonDetKeysUFM,+ ufmToSet_Directly,+ nonDetUFMToList, ufmToIntMap,+ pprUniqFM, pprUFM, pprUFMWithKeys, pluralUFM+ ) where++import Unique ( Uniquable(..), Unique, getKey )+import Outputable++import Data.List (foldl')++import qualified Data.IntMap as M+#if MIN_VERSION_containers(0,5,9)+import qualified Data.IntMap.Merge.Lazy as M+import Control.Applicative (Const (..))+import qualified Data.Monoid as Mon+#endif+import qualified Data.IntSet as S+import Data.Typeable+import Data.Data+#if __GLASGOW_HASKELL__ > 710+import Data.Semigroup ( Semigroup )+import qualified Data.Semigroup as Semigroup+#endif+++newtype UniqFM ele = UFM (M.IntMap ele)+ deriving (Data, Eq, Functor, Typeable)+ -- We used to derive Traversable and Foldable, but they were nondeterministic+ -- and not obvious at the call site. You can use explicit nonDetEltsUFM+ -- and fold a list if needed.+ -- See Note [Deterministic UniqFM] in UniqDFM to learn about determinism.++emptyUFM :: UniqFM elt+emptyUFM = UFM M.empty++isNullUFM :: UniqFM elt -> Bool+isNullUFM (UFM m) = M.null m++unitUFM :: Uniquable key => key -> elt -> UniqFM elt+unitUFM k v = UFM (M.singleton (getKey $ getUnique k) v)++-- when you've got the Unique already+unitDirectlyUFM :: Unique -> elt -> UniqFM elt+unitDirectlyUFM u v = UFM (M.singleton (getKey u) v)++listToUFM :: Uniquable key => [(key,elt)] -> UniqFM elt+listToUFM = foldl (\m (k, v) -> addToUFM m k v) emptyUFM++listToUFM_Directly :: [(Unique, elt)] -> UniqFM elt+listToUFM_Directly = foldl (\m (u, v) -> addToUFM_Directly m u v) emptyUFM++listToUFM_C+ :: Uniquable key+ => (elt -> elt -> elt)+ -> [(key, elt)]+ -> UniqFM elt+listToUFM_C f = foldl (\m (k, v) -> addToUFM_C f m k v) emptyUFM++addToUFM :: Uniquable key => UniqFM elt -> key -> elt -> UniqFM elt+addToUFM (UFM m) k v = UFM (M.insert (getKey $ getUnique k) v m)++addListToUFM :: Uniquable key => UniqFM elt -> [(key,elt)] -> UniqFM elt+addListToUFM = foldl (\m (k, v) -> addToUFM m k v)++addListToUFM_Directly :: UniqFM elt -> [(Unique,elt)] -> UniqFM elt+addListToUFM_Directly = foldl (\m (k, v) -> addToUFM_Directly m k v)++addToUFM_Directly :: UniqFM elt -> Unique -> elt -> UniqFM elt+addToUFM_Directly (UFM m) u v = UFM (M.insert (getKey u) v m)++addToUFM_C+ :: Uniquable key+ => (elt -> elt -> elt) -- old -> new -> result+ -> UniqFM elt -- old+ -> key -> elt -- new+ -> UniqFM elt -- result+-- Arguments of combining function of M.insertWith and addToUFM_C are flipped.+addToUFM_C f (UFM m) k v =+ UFM (M.insertWith (flip f) (getKey $ getUnique k) v m)++addToUFM_Acc+ :: Uniquable key+ => (elt -> elts -> elts) -- Add to existing+ -> (elt -> elts) -- New element+ -> UniqFM elts -- old+ -> key -> elt -- new+ -> UniqFM elts -- result+addToUFM_Acc exi new (UFM m) k v =+ UFM (M.insertWith (\_new old -> exi v old) (getKey $ getUnique k) (new v) m)++alterUFM+ :: Uniquable key+ => (Maybe elt -> Maybe elt) -- How to adjust+ -> UniqFM elt -- old+ -> key -- new+ -> UniqFM elt -- result+alterUFM f (UFM m) k = UFM (M.alter f (getKey $ getUnique k) m)++addListToUFM_C+ :: Uniquable key+ => (elt -> elt -> elt)+ -> UniqFM elt -> [(key,elt)]+ -> UniqFM elt+addListToUFM_C f = foldl (\m (k, v) -> addToUFM_C f m k v)++adjustUFM :: Uniquable key => (elt -> elt) -> UniqFM elt -> key -> UniqFM elt+adjustUFM f (UFM m) k = UFM (M.adjust f (getKey $ getUnique k) m)++adjustUFM_Directly :: (elt -> elt) -> UniqFM elt -> Unique -> UniqFM elt+adjustUFM_Directly f (UFM m) u = UFM (M.adjust f (getKey u) m)++delFromUFM :: Uniquable key => UniqFM elt -> key -> UniqFM elt+delFromUFM (UFM m) k = UFM (M.delete (getKey $ getUnique k) m)++delListFromUFM :: Uniquable key => UniqFM elt -> [key] -> UniqFM elt+delListFromUFM = foldl delFromUFM++delListFromUFM_Directly :: UniqFM elt -> [Unique] -> UniqFM elt+delListFromUFM_Directly = foldl delFromUFM_Directly++delFromUFM_Directly :: UniqFM elt -> Unique -> UniqFM elt+delFromUFM_Directly (UFM m) u = UFM (M.delete (getKey u) m)++-- Bindings in right argument shadow those in the left+plusUFM :: UniqFM elt -> UniqFM elt -> UniqFM elt+-- M.union is left-biased, plusUFM should be right-biased.+plusUFM (UFM x) (UFM y) = UFM (M.union y x)+ -- Note (M.union y x), with arguments flipped+ -- M.union is left-biased, plusUFM should be right-biased.++plusUFM_C :: (elt -> elt -> elt) -> UniqFM elt -> UniqFM elt -> UniqFM elt+plusUFM_C f (UFM x) (UFM y) = UFM (M.unionWith f x y)++-- | `plusUFM_CD f m1 d1 m2 d2` merges the maps using `f` as the+-- combinding function and `d1` resp. `d2` as the default value if+-- there is no entry in `m1` reps. `m2`. The domain is the union of+-- the domains of `m1` and `m2`.+--+-- Representative example:+--+-- @+-- plusUFM_CD f {A: 1, B: 2} 23 {B: 3, C: 4} 42+-- == {A: f 1 42, B: f 2 3, C: f 23 4 }+-- @+plusUFM_CD+ :: (elt -> elt -> elt)+ -> UniqFM elt -- map X+ -> elt -- default for X+ -> UniqFM elt -- map Y+ -> elt -- default for Y+ -> UniqFM elt+plusUFM_CD f (UFM xm) dx (UFM ym) dy+ = UFM $ M.mergeWithKey+ (\_ x y -> Just (x `f` y))+ (M.map (\x -> x `f` dy))+ (M.map (\y -> dx `f` y))+ xm ym++plusMaybeUFM_C :: (elt -> elt -> Maybe elt)+ -> UniqFM elt -> UniqFM elt -> UniqFM elt+plusMaybeUFM_C f (UFM xm) (UFM ym)+ = UFM $ M.mergeWithKey+ (\_ x y -> x `f` y)+ id+ id+ xm ym++plusUFMList :: [UniqFM elt] -> UniqFM elt+plusUFMList = foldl' plusUFM emptyUFM++minusUFM :: UniqFM elt1 -> UniqFM elt2 -> UniqFM elt1+minusUFM (UFM x) (UFM y) = UFM (M.difference x y)++intersectUFM :: UniqFM elt1 -> UniqFM elt2 -> UniqFM elt1+intersectUFM (UFM x) (UFM y) = UFM (M.intersection x y)++intersectUFM_C+ :: (elt1 -> elt2 -> elt3)+ -> UniqFM elt1+ -> UniqFM elt2+ -> UniqFM elt3+intersectUFM_C f (UFM x) (UFM y) = UFM (M.intersectionWith f x y)++disjointUFM :: UniqFM elt1 -> UniqFM elt2 -> Bool+disjointUFM (UFM x) (UFM y) = M.null (M.intersection x y)++foldUFM :: (elt -> a -> a) -> a -> UniqFM elt -> a+foldUFM k z (UFM m) = M.foldr k z m++mapUFM :: (elt1 -> elt2) -> UniqFM elt1 -> UniqFM elt2+mapUFM f (UFM m) = UFM (M.map f m)++mapUFM_Directly :: (Unique -> elt1 -> elt2) -> UniqFM elt1 -> UniqFM elt2+mapUFM_Directly f (UFM m) = UFM (M.mapWithKey (f . getUnique) m)++filterUFM :: (elt -> Bool) -> UniqFM elt -> UniqFM elt+filterUFM p (UFM m) = UFM (M.filter p m)++filterUFM_Directly :: (Unique -> elt -> Bool) -> UniqFM elt -> UniqFM elt+filterUFM_Directly p (UFM m) = UFM (M.filterWithKey (p . getUnique) m)++partitionUFM :: (elt -> Bool) -> UniqFM elt -> (UniqFM elt, UniqFM elt)+partitionUFM p (UFM m) =+ case M.partition p m of+ (left, right) -> (UFM left, UFM right)++sizeUFM :: UniqFM elt -> Int+sizeUFM (UFM m) = M.size m++elemUFM :: Uniquable key => key -> UniqFM elt -> Bool+elemUFM k (UFM m) = M.member (getKey $ getUnique k) m++elemUFM_Directly :: Unique -> UniqFM elt -> Bool+elemUFM_Directly u (UFM m) = M.member (getKey u) m++lookupUFM :: Uniquable key => UniqFM elt -> key -> Maybe elt+lookupUFM (UFM m) k = M.lookup (getKey $ getUnique k) m++-- when you've got the Unique already+lookupUFM_Directly :: UniqFM elt -> Unique -> Maybe elt+lookupUFM_Directly (UFM m) u = M.lookup (getKey u) m++lookupWithDefaultUFM :: Uniquable key => UniqFM elt -> elt -> key -> elt+lookupWithDefaultUFM (UFM m) v k = M.findWithDefault v (getKey $ getUnique k) m++lookupWithDefaultUFM_Directly :: UniqFM elt -> elt -> Unique -> elt+lookupWithDefaultUFM_Directly (UFM m) v u = M.findWithDefault v (getKey u) m++eltsUFM :: UniqFM elt -> [elt]+eltsUFM (UFM m) = M.elems m++ufmToSet_Directly :: UniqFM elt -> S.IntSet+ufmToSet_Directly (UFM m) = M.keysSet m++anyUFM :: (elt -> Bool) -> UniqFM elt -> Bool+anyUFM p (UFM m) = M.foldr ((||) . p) False m++allUFM :: (elt -> Bool) -> UniqFM elt -> Bool+allUFM p (UFM m) = M.foldr ((&&) . p) True m++seqEltsUFM :: ([elt] -> ()) -> UniqFM elt -> ()+seqEltsUFM seqList = seqList . nonDetEltsUFM+ -- It's OK to use nonDetEltsUFM here because the type guarantees that+ -- the only interesting thing this function can do is to force the+ -- elements.++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetEltsUFM :: UniqFM elt -> [elt]+nonDetEltsUFM (UFM m) = M.elems m++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetKeysUFM :: UniqFM elt -> [Unique]+nonDetKeysUFM (UFM m) = map getUnique $ M.keys m++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetFoldUFM :: (elt -> a -> a) -> a -> UniqFM elt -> a+nonDetFoldUFM k z (UFM m) = M.foldr k z m++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetFoldUFM_Directly:: (Unique -> elt -> a -> a) -> a -> UniqFM elt -> a+nonDetFoldUFM_Directly k z (UFM m) = M.foldrWithKey (k . getUnique) z m++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetUFMToList :: UniqFM elt -> [(Unique, elt)]+nonDetUFMToList (UFM m) = map (\(k, v) -> (getUnique k, v)) $ M.toList m++ufmToIntMap :: UniqFM elt -> M.IntMap elt+ufmToIntMap (UFM m) = m++-- Determines whether two 'UniqFm's contain the same keys.+equalKeysUFM :: UniqFM a -> UniqFM b -> Bool+#if MIN_VERSION_containers(0,5,9)+equalKeysUFM (UFM m1) (UFM m2) = Mon.getAll $ getConst $+ M.mergeA (M.traverseMissing (\_ _ -> Const (Mon.All False)))+ (M.traverseMissing (\_ _ -> Const (Mon.All False)))+ (M.zipWithAMatched (\_ _ _ -> Const (Mon.All True))) m1 m2+#else+equalKeysUFM (UFM m1) (UFM m2) = M.keys m1 == M.keys m2+#endif++-- Instances++#if __GLASGOW_HASKELL__ > 710+instance Semigroup (UniqFM a) where+ (<>) = plusUFM+#endif++instance Monoid (UniqFM a) where+ mempty = emptyUFM+ mappend = plusUFM++-- Output-ery++instance Outputable a => Outputable (UniqFM a) where+ ppr ufm = pprUniqFM ppr ufm++pprUniqFM :: (a -> SDoc) -> UniqFM a -> SDoc+pprUniqFM ppr_elt ufm+ = brackets $ fsep $ punctuate comma $+ [ ppr uq <+> text ":->" <+> ppr_elt elt+ | (uq, elt) <- nonDetUFMToList ufm ]+ -- It's OK to use nonDetUFMToList here because we only use it for+ -- pretty-printing.++-- | Pretty-print a non-deterministic set.+-- The order of variables is non-deterministic and for pretty-printing that+-- shouldn't be a problem.+-- Having this function helps contain the non-determinism created with+-- nonDetEltsUFM.+pprUFM :: UniqFM a -- ^ The things to be pretty printed+ -> ([a] -> SDoc) -- ^ The pretty printing function to use on the elements+ -> SDoc -- ^ 'SDoc' where the things have been pretty+ -- printed+pprUFM ufm pp = pp (nonDetEltsUFM ufm)++-- | Pretty-print a non-deterministic set.+-- The order of variables is non-deterministic and for pretty-printing that+-- shouldn't be a problem.+-- Having this function helps contain the non-determinism created with+-- nonDetUFMToList.+pprUFMWithKeys+ :: UniqFM a -- ^ The things to be pretty printed+ -> ([(Unique, a)] -> SDoc) -- ^ The pretty printing function to use on the elements+ -> SDoc -- ^ 'SDoc' where the things have been pretty+ -- printed+pprUFMWithKeys ufm pp = pp (nonDetUFMToList ufm)++-- | Determines the pluralisation suffix appropriate for the length of a set+-- in the same way that plural from Outputable does for lists.+pluralUFM :: UniqFM a -> SDoc+pluralUFM ufm+ | sizeUFM ufm == 1 = empty+ | otherwise = char 's'
+ utils/UniqSet.hs view
@@ -0,0 +1,206 @@+{-+(c) The University of Glasgow 2006+(c) The AQUA Project, Glasgow University, 1994-1998++\section[UniqSet]{Specialised sets, for things with @Uniques@}++Based on @UniqFMs@ (as you would expect).++Basically, the things need to be in class @Uniquable@.+-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE CPP #-}+{-# LANGUAGE DeriveDataTypeable #-}++module UniqSet (+ -- * Unique set type+ UniqSet, -- type synonym for UniqFM a+ getUniqSet,+ pprUniqSet,++ -- ** Manipulating these sets+ emptyUniqSet,+ unitUniqSet,+ mkUniqSet,+ addOneToUniqSet, addListToUniqSet,+ delOneFromUniqSet, delOneFromUniqSet_Directly, delListFromUniqSet,+ delListFromUniqSet_Directly,+ unionUniqSets, unionManyUniqSets,+ minusUniqSet, uniqSetMinusUFM,+ intersectUniqSets,+ restrictUniqSetToUFM,+ uniqSetAny, uniqSetAll,+ elementOfUniqSet,+ elemUniqSet_Directly,+ filterUniqSet,+ filterUniqSet_Directly,+ sizeUniqSet,+ isEmptyUniqSet,+ lookupUniqSet,+ lookupUniqSet_Directly,+ partitionUniqSet,+ mapUniqSet,+ unsafeUFMToUniqSet,+ nonDetEltsUniqSet,+ nonDetKeysUniqSet,+ nonDetFoldUniqSet,+ nonDetFoldUniqSet_Directly+ ) where++import UniqFM+import Unique+import Data.Coerce+import Outputable+import Data.Foldable (foldl')+import Data.Data+#if __GLASGOW_HASKELL__ >= 801+import qualified Data.Semigroup+#endif++{-+************************************************************************+* *+\subsection{The signature of the module}+* *+************************************************************************+-}++emptyUniqSet :: UniqSet a+unitUniqSet :: Uniquable a => a -> UniqSet a+mkUniqSet :: Uniquable a => [a] -> UniqSet a++addOneToUniqSet :: Uniquable a => UniqSet a -> a -> UniqSet a+addListToUniqSet :: Uniquable a => UniqSet a -> [a] -> UniqSet a++delOneFromUniqSet :: Uniquable a => UniqSet a -> a -> UniqSet a+delOneFromUniqSet_Directly :: UniqSet a -> Unique -> UniqSet a+delListFromUniqSet :: Uniquable a => UniqSet a -> [a] -> UniqSet a+delListFromUniqSet_Directly :: UniqSet a -> [Unique] -> UniqSet a++unionUniqSets :: UniqSet a -> UniqSet a -> UniqSet a+unionManyUniqSets :: [UniqSet a] -> UniqSet a+minusUniqSet :: UniqSet a -> UniqSet a -> UniqSet a+intersectUniqSets :: UniqSet a -> UniqSet a -> UniqSet a+restrictUniqSetToUFM :: UniqSet a -> UniqFM b -> UniqSet a+uniqSetMinusUFM :: UniqSet a -> UniqFM b -> UniqSet a++elementOfUniqSet :: Uniquable a => a -> UniqSet a -> Bool+elemUniqSet_Directly :: Unique -> UniqSet a -> Bool+filterUniqSet :: (a -> Bool) -> UniqSet a -> UniqSet a+filterUniqSet_Directly :: (Unique -> elt -> Bool) -> UniqSet elt -> UniqSet elt+partitionUniqSet :: (a -> Bool) -> UniqSet a -> (UniqSet a, UniqSet a)++sizeUniqSet :: UniqSet a -> Int+isEmptyUniqSet :: UniqSet a -> Bool+lookupUniqSet :: Uniquable a => UniqSet b -> a -> Maybe b+lookupUniqSet_Directly :: UniqSet a -> Unique -> Maybe a++nonDetEltsUniqSet :: UniqSet elt -> [elt]+nonDetKeysUniqSet :: UniqSet elt -> [Unique]++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetFoldUniqSet :: (elt -> a -> a) -> a -> UniqSet elt -> a++-- See Note [Deterministic UniqFM] to learn about nondeterminism.+-- If you use this please provide a justification why it doesn't introduce+-- nondeterminism.+nonDetFoldUniqSet_Directly:: (Unique -> elt -> a -> a) -> a -> UniqSet elt -> a++mapUniqSet :: Uniquable b => (a -> b) -> UniqSet a -> UniqSet b++{-+************************************************************************+* *+\subsection{Implementation using ``UniqFM''}+* *+************************************************************************+-}++-- Note [Unsound mapUniqSet]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~+-- UniqSet has the following invariant:+-- The keys in the map are the uniques of the values+-- It means that to implement mapUniqSet you'd have to update+-- both the keys and the values. There used to be an implementation+-- that only updated the values and it's been removed, because it broke+-- the invariant.++newtype UniqSet a = UniqSet {getUniqSet' :: UniqFM a} deriving Data++-- Two 'UniqSet's are considered equal if they contain the same+-- uniques.+instance Eq (UniqSet a) where+ UniqSet a == UniqSet b = equalKeysUFM a b++getUniqSet :: UniqSet a -> UniqFM a+getUniqSet = getUniqSet'++-- | 'unsafeUFMToUniqSet' converts a @'UniqFM' a@ into a @'UniqSet' a@+-- assuming, without checking, that it maps each 'Unique' to a value+-- that has that 'Unique'. See Note [Unsound mapUniqSet].+unsafeUFMToUniqSet :: UniqFM a -> UniqSet a+unsafeUFMToUniqSet = UniqSet++instance Outputable a => Outputable (UniqSet a) where+ ppr = pprUniqSet ppr+#if __GLASGOW_HASKELL__ >= 801+instance Data.Semigroup.Semigroup (UniqSet a) where+ (<>) = mappend+#endif+instance Monoid (UniqSet a) where+ mempty = UniqSet mempty+ UniqSet s `mappend` UniqSet t = UniqSet (s `mappend` t)++pprUniqSet :: (a -> SDoc) -> UniqSet a -> SDoc+pprUniqSet f (UniqSet s) = pprUniqFM f s++emptyUniqSet = UniqSet emptyUFM+unitUniqSet x = UniqSet $ unitUFM x x+mkUniqSet = foldl' addOneToUniqSet emptyUniqSet++addOneToUniqSet (UniqSet set) x = UniqSet (addToUFM set x x)+addListToUniqSet = foldl' addOneToUniqSet++delOneFromUniqSet (UniqSet s) a = UniqSet (delFromUFM s a)+delOneFromUniqSet_Directly (UniqSet s) u = UniqSet (delFromUFM_Directly s u)+delListFromUniqSet (UniqSet s) l = UniqSet (delListFromUFM s l)+delListFromUniqSet_Directly (UniqSet s) l =+ UniqSet (delListFromUFM_Directly s l)++unionUniqSets (UniqSet s) (UniqSet t) = UniqSet (plusUFM s t)++unionManyUniqSets = foldl' (flip unionUniqSets) emptyUniqSet++minusUniqSet (UniqSet s) (UniqSet t) = UniqSet (minusUFM s t)+uniqSetMinusUFM (UniqSet s) t = UniqSet (minusUFM s t)+++intersectUniqSets (UniqSet s) (UniqSet t) = UniqSet (intersectUFM s t)+restrictUniqSetToUFM (UniqSet s) m = UniqSet (intersectUFM s m)++elementOfUniqSet a (UniqSet s) = elemUFM a s+elemUniqSet_Directly a (UniqSet s) = elemUFM_Directly a s+filterUniqSet p (UniqSet s) = UniqSet (filterUFM p s)+filterUniqSet_Directly f (UniqSet s) = UniqSet (filterUFM_Directly f s)++partitionUniqSet p (UniqSet s) = coerce (partitionUFM p s)++sizeUniqSet (UniqSet s) = sizeUFM s+isEmptyUniqSet (UniqSet s) = isNullUFM s+lookupUniqSet (UniqSet s) k = lookupUFM s k+lookupUniqSet_Directly (UniqSet s) k = lookupUFM_Directly s k++uniqSetAny :: (a -> Bool) -> UniqSet a -> Bool+uniqSetAny p (UniqSet s) = anyUFM p s++uniqSetAll :: (a -> Bool) -> UniqSet a -> Bool+uniqSetAll p (UniqSet s) = allUFM p s++nonDetFoldUniqSet c n (UniqSet s) = nonDetFoldUFM c n s+nonDetFoldUniqSet_Directly f n (UniqSet s) = nonDetFoldUFM_Directly f n s+nonDetEltsUniqSet = nonDetEltsUFM . getUniqSet'+nonDetKeysUniqSet = nonDetKeysUFM . getUniqSet'++mapUniqSet f = mkUniqSet . map f . nonDetEltsUniqSet
+ utils/Util.hs view
@@ -0,0 +1,1371 @@+-- (c) The University of Glasgow 2006++{-# LANGUAGE CPP #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE BangPatterns #-}+#if __GLASGOW_HASKELL__ < 800+-- For CallStack business+{-# LANGUAGE ImplicitParams #-}+{-# LANGUAGE FlexibleContexts #-}+#endif++-- | Highly random utility functions+--+module Util (+ -- * Flags dependent on the compiler build+ ghciSupported, debugIsOn, ncgDebugIsOn,+ ghciTablesNextToCode,+ isWindowsHost, isDarwinHost,++ -- * General list processing+ zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,+ zipLazy, stretchZipWith, zipWithAndUnzip,++ zipWithLazy, zipWith3Lazy,++ filterByList, filterByLists, partitionByList,++ unzipWith,++ mapFst, mapSnd, chkAppend,+ mapAndUnzip, mapAndUnzip3, mapAccumL2,+ nOfThem, filterOut, partitionWith, splitEithers,++ dropWhileEndLE, spanEnd,++ foldl1', foldl2, count, all2,++ lengthExceeds, lengthIs, lengthAtLeast,+ listLengthCmp, atLength,+ equalLength, compareLength, leLength,++ isSingleton, only, singleton,+ notNull, snocView,++ isIn, isn'tIn,++ chunkList,++ changeLast,++ -- * Tuples+ fstOf3, sndOf3, thdOf3,+ firstM, first3M,+ fst3, snd3, third3,+ uncurry3,+ liftFst, liftSnd,++ -- * List operations controlled by another list+ takeList, dropList, splitAtList, split,+ dropTail, capitalise,++ -- * For loop+ nTimes,++ -- * Sorting+ sortWith, minWith, nubSort,++ -- * Comparisons+ isEqual, eqListBy, eqMaybeBy,+ thenCmp, cmpList,+ removeSpaces,+ (<&&>), (<||>),++ -- * Edit distance+ fuzzyMatch, fuzzyLookup,++ -- * Transitive closures+ transitiveClosure,++ -- * Strictness+ seqList,++ -- * Module names+ looksLikeModuleName,+ looksLikePackageName,++ -- * Argument processing+ getCmd, toCmdArgs, toArgs,++ -- * Integers+ exactLog2,++ -- * Floating point+ readRational,++ -- * read helpers+ maybeRead, maybeReadFuzzy,++ -- * IO-ish utilities+ doesDirNameExist,+ getModificationUTCTime,+ modificationTimeIfExists,+ hSetTranslit,++ global, consIORef, globalM,+ sharedGlobal, sharedGlobalM,++ -- * Filenames and paths+ Suffix,+ splitLongestPrefix,+ escapeSpaces,+ Direction(..), reslash,+ makeRelativeTo,++ -- * Utils for defining Data instances+ abstractConstr, abstractDataType, mkNoRepType,++ -- * Utils for printing C code+ charToC,++ -- * Hashing+ hashString,++ -- * Call stacks+#if MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)+ GHC.Stack.CallStack,+#endif+ HasCallStack,+ HasDebugCallStack,+ prettyCurrentCallStack,++ -- * Utils for flags+ OverridingBool(..),+ overrideWith,+ ) where++#include "HsVersions.h"++import Exception+import Panic++import Data.Data+import Data.IORef ( IORef, newIORef, atomicModifyIORef' )+import System.IO.Unsafe ( unsafePerformIO )+import Data.List hiding (group)++import GHC.Exts+import qualified GHC.Stack++import Control.Applicative ( liftA2 )+import Control.Monad ( liftM )+import GHC.IO.Encoding (mkTextEncoding, textEncodingName)+import GHC.Conc.Sync ( sharedCAF )+import System.IO (Handle, hGetEncoding, hSetEncoding)+import System.IO.Error as IO ( isDoesNotExistError )+import System.Directory ( doesDirectoryExist, getModificationTime )+import System.FilePath++import Data.Char ( isUpper, isAlphaNum, isSpace, chr, ord, isDigit, toUpper)+import Data.Int+import Data.Ratio ( (%) )+import Data.Ord ( comparing )+import Data.Bits+import Data.Word+import qualified Data.IntMap as IM+import qualified Data.Set as Set++import Data.Time++infixr 9 `thenCmp`++{-+************************************************************************+* *+\subsection{Is DEBUG on, are we on Windows, etc?}+* *+************************************************************************++These booleans are global constants, set by CPP flags. They allow us to+recompile a single module (this one) to change whether or not debug output+appears. They sometimes let us avoid even running CPP elsewhere.++It's important that the flags are literal constants (True/False). Then,+with -0, tests of the flags in other modules will simplify to the correct+branch of the conditional, thereby dropping debug code altogether when+the flags are off.+-}++ghciSupported :: Bool+#ifdef GHCI+ghciSupported = True+#else+ghciSupported = False+#endif++debugIsOn :: Bool+#ifdef DEBUG+debugIsOn = True+#else+debugIsOn = False+#endif++ncgDebugIsOn :: Bool+#ifdef NCG_DEBUG+ncgDebugIsOn = True+#else+ncgDebugIsOn = False+#endif++ghciTablesNextToCode :: Bool+#ifdef GHCI_TABLES_NEXT_TO_CODE+ghciTablesNextToCode = True+#else+ghciTablesNextToCode = False+#endif++isWindowsHost :: Bool+#ifdef mingw32_HOST_OS+isWindowsHost = True+#else+isWindowsHost = False+#endif++isDarwinHost :: Bool+#ifdef darwin_HOST_OS+isDarwinHost = True+#else+isDarwinHost = False+#endif++{-+************************************************************************+* *+\subsection{A for loop}+* *+************************************************************************+-}++-- | Compose a function with itself n times. (nth rather than twice)+nTimes :: Int -> (a -> a) -> (a -> a)+nTimes 0 _ = id+nTimes 1 f = f+nTimes n f = f . nTimes (n-1) f++fstOf3 :: (a,b,c) -> a+sndOf3 :: (a,b,c) -> b+thdOf3 :: (a,b,c) -> c+fstOf3 (a,_,_) = a+sndOf3 (_,b,_) = b+thdOf3 (_,_,c) = c++fst3 :: (a -> d) -> (a, b, c) -> (d, b, c)+fst3 f (a, b, c) = (f a, b, c)++snd3 :: (b -> d) -> (a, b, c) -> (a, d, c)+snd3 f (a, b, c) = (a, f b, c)++third3 :: (c -> d) -> (a, b, c) -> (a, b, d)+third3 f (a, b, c) = (a, b, f c)++uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d+uncurry3 f (a, b, c) = f a b c++liftFst :: (a -> b) -> (a, c) -> (b, c)+liftFst f (a,c) = (f a, c)++liftSnd :: (a -> b) -> (c, a) -> (c, b)+liftSnd f (c,a) = (c, f a)++firstM :: Monad m => (a -> m c) -> (a, b) -> m (c, b)+firstM f (x, y) = liftM (\x' -> (x', y)) (f x)++first3M :: Monad m => (a -> m d) -> (a, b, c) -> m (d, b, c)+first3M f (x, y, z) = liftM (\x' -> (x', y, z)) (f x)++{-+************************************************************************+* *+\subsection[Utils-lists]{General list processing}+* *+************************************************************************+-}++filterOut :: (a->Bool) -> [a] -> [a]+-- ^ Like filter, only it reverses the sense of the test+filterOut _ [] = []+filterOut p (x:xs) | p x = filterOut p xs+ | otherwise = x : filterOut p xs++partitionWith :: (a -> Either b c) -> [a] -> ([b], [c])+-- ^ Uses a function to determine which of two output lists an input element should join+partitionWith _ [] = ([],[])+partitionWith f (x:xs) = case f x of+ Left b -> (b:bs, cs)+ Right c -> (bs, c:cs)+ where (bs,cs) = partitionWith f xs++splitEithers :: [Either a b] -> ([a], [b])+-- ^ Teases a list of 'Either's apart into two lists+splitEithers [] = ([],[])+splitEithers (e : es) = case e of+ Left x -> (x:xs, ys)+ Right y -> (xs, y:ys)+ where (xs,ys) = splitEithers es++chkAppend :: [a] -> [a] -> [a]+-- Checks for the second arguemnt being empty+-- Used in situations where that situation is common+chkAppend xs ys+ | null ys = xs+ | otherwise = xs ++ ys++{-+A paranoid @zip@ (and some @zipWith@ friends) that checks the lists+are of equal length. Alastair Reid thinks this should only happen if+DEBUGging on; hey, why not?+-}++zipEqual :: String -> [a] -> [b] -> [(a,b)]+zipWithEqual :: String -> (a->b->c) -> [a]->[b]->[c]+zipWith3Equal :: String -> (a->b->c->d) -> [a]->[b]->[c]->[d]+zipWith4Equal :: String -> (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]++#ifndef DEBUG+zipEqual _ = zip+zipWithEqual _ = zipWith+zipWith3Equal _ = zipWith3+zipWith4Equal _ = zipWith4+#else+zipEqual _ [] [] = []+zipEqual msg (a:as) (b:bs) = (a,b) : zipEqual msg as bs+zipEqual msg _ _ = panic ("zipEqual: unequal lists:"++msg)++zipWithEqual msg z (a:as) (b:bs)= z a b : zipWithEqual msg z as bs+zipWithEqual _ _ [] [] = []+zipWithEqual msg _ _ _ = panic ("zipWithEqual: unequal lists:"++msg)++zipWith3Equal msg z (a:as) (b:bs) (c:cs)+ = z a b c : zipWith3Equal msg z as bs cs+zipWith3Equal _ _ [] [] [] = []+zipWith3Equal msg _ _ _ _ = panic ("zipWith3Equal: unequal lists:"++msg)++zipWith4Equal msg z (a:as) (b:bs) (c:cs) (d:ds)+ = z a b c d : zipWith4Equal msg z as bs cs ds+zipWith4Equal _ _ [] [] [] [] = []+zipWith4Equal msg _ _ _ _ _ = panic ("zipWith4Equal: unequal lists:"++msg)+#endif++-- | 'zipLazy' is a kind of 'zip' that is lazy in the second list (observe the ~)+zipLazy :: [a] -> [b] -> [(a,b)]+zipLazy [] _ = []+zipLazy (x:xs) ~(y:ys) = (x,y) : zipLazy xs ys++-- | 'zipWithLazy' is like 'zipWith' but is lazy in the second list.+-- The length of the output is always the same as the length of the first+-- list.+zipWithLazy :: (a -> b -> c) -> [a] -> [b] -> [c]+zipWithLazy _ [] _ = []+zipWithLazy f (a:as) ~(b:bs) = f a b : zipWithLazy f as bs++-- | 'zipWith3Lazy' is like 'zipWith3' but is lazy in the second and third lists.+-- The length of the output is always the same as the length of the first+-- list.+zipWith3Lazy :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]+zipWith3Lazy _ [] _ _ = []+zipWith3Lazy f (a:as) ~(b:bs) ~(c:cs) = f a b c : zipWith3Lazy f as bs cs++-- | 'filterByList' takes a list of Bools and a list of some elements and+-- filters out these elements for which the corresponding value in the list of+-- Bools is False. This function does not check whether the lists have equal+-- length.+filterByList :: [Bool] -> [a] -> [a]+filterByList (True:bs) (x:xs) = x : filterByList bs xs+filterByList (False:bs) (_:xs) = filterByList bs xs+filterByList _ _ = []++-- | 'filterByLists' takes a list of Bools and two lists as input, and+-- outputs a new list consisting of elements from the last two input lists. For+-- each Bool in the list, if it is 'True', then it takes an element from the+-- former list. If it is 'False', it takes an element from the latter list.+-- The elements taken correspond to the index of the Bool in its list.+-- For example:+--+-- @+-- filterByLists [True, False, True, False] \"abcd\" \"wxyz\" = \"axcz\"+-- @+--+-- This function does not check whether the lists have equal length.+filterByLists :: [Bool] -> [a] -> [a] -> [a]+filterByLists (True:bs) (x:xs) (_:ys) = x : filterByLists bs xs ys+filterByLists (False:bs) (_:xs) (y:ys) = y : filterByLists bs xs ys+filterByLists _ _ _ = []++-- | 'partitionByList' takes a list of Bools and a list of some elements and+-- partitions the list according to the list of Bools. Elements corresponding+-- to 'True' go to the left; elements corresponding to 'False' go to the right.+-- For example, @partitionByList [True, False, True] [1,2,3] == ([1,3], [2])@+-- This function does not check whether the lists have equal+-- length.+partitionByList :: [Bool] -> [a] -> ([a], [a])+partitionByList = go [] []+ where+ go trues falses (True : bs) (x : xs) = go (x:trues) falses bs xs+ go trues falses (False : bs) (x : xs) = go trues (x:falses) bs xs+ go trues falses _ _ = (reverse trues, reverse falses)++stretchZipWith :: (a -> Bool) -> b -> (a->b->c) -> [a] -> [b] -> [c]+-- ^ @stretchZipWith p z f xs ys@ stretches @ys@ by inserting @z@ in+-- the places where @p@ returns @True@++stretchZipWith _ _ _ [] _ = []+stretchZipWith p z f (x:xs) ys+ | p x = f x z : stretchZipWith p z f xs ys+ | otherwise = case ys of+ [] -> []+ (y:ys) -> f x y : stretchZipWith p z f xs ys++mapFst :: (a->c) -> [(a,b)] -> [(c,b)]+mapSnd :: (b->c) -> [(a,b)] -> [(a,c)]++mapFst f xys = [(f x, y) | (x,y) <- xys]+mapSnd f xys = [(x, f y) | (x,y) <- xys]++mapAndUnzip :: (a -> (b, c)) -> [a] -> ([b], [c])++mapAndUnzip _ [] = ([], [])+mapAndUnzip f (x:xs)+ = let (r1, r2) = f x+ (rs1, rs2) = mapAndUnzip f xs+ in+ (r1:rs1, r2:rs2)++mapAndUnzip3 :: (a -> (b, c, d)) -> [a] -> ([b], [c], [d])++mapAndUnzip3 _ [] = ([], [], [])+mapAndUnzip3 f (x:xs)+ = let (r1, r2, r3) = f x+ (rs1, rs2, rs3) = mapAndUnzip3 f xs+ in+ (r1:rs1, r2:rs2, r3:rs3)++zipWithAndUnzip :: (a -> b -> (c,d)) -> [a] -> [b] -> ([c],[d])+zipWithAndUnzip f (a:as) (b:bs)+ = let (r1, r2) = f a b+ (rs1, rs2) = zipWithAndUnzip f as bs+ in+ (r1:rs1, r2:rs2)+zipWithAndUnzip _ _ _ = ([],[])++mapAccumL2 :: (s1 -> s2 -> a -> (s1, s2, b)) -> s1 -> s2 -> [a] -> (s1, s2, [b])+mapAccumL2 f s1 s2 xs = (s1', s2', ys)+ where ((s1', s2'), ys) = mapAccumL (\(s1, s2) x -> case f s1 s2 x of+ (s1', s2', y) -> ((s1', s2'), y))+ (s1, s2) xs++nOfThem :: Int -> a -> [a]+nOfThem n thing = replicate n thing++-- | @atLength atLen atEnd ls n@ unravels list @ls@ to position @n@. Precisely:+--+-- @+-- atLength atLenPred atEndPred ls n+-- | n < 0 = atLenPred ls+-- | length ls < n = atEndPred (n - length ls)+-- | otherwise = atLenPred (drop n ls)+-- @+atLength :: ([a] -> b) -- Called when length ls >= n, passed (drop n ls)+ -- NB: arg passed to this function may be []+ -> b -- Called when length ls < n+ -> [a]+ -> Int+ -> b+atLength atLenPred atEnd ls0 n0+ | n0 < 0 = atLenPred ls0+ | otherwise = go n0 ls0+ where+ -- go's first arg n >= 0+ go 0 ls = atLenPred ls+ go _ [] = atEnd -- n > 0 here+ go n (_:xs) = go (n-1) xs++-- Some special cases of atLength:++-- | @(lengthExceeds xs n) = (length xs > n)@+lengthExceeds :: [a] -> Int -> Bool+lengthExceeds lst n+ | n < 0+ = True+ | otherwise+ = atLength notNull False lst n++lengthAtLeast :: [a] -> Int -> Bool+lengthAtLeast = atLength (const True) False++-- | @(lengthIs xs n) = (length xs == n)@+lengthIs :: [a] -> Int -> Bool+lengthIs lst n+ | n < 0+ = False+ | otherwise+ = atLength null False lst n++listLengthCmp :: [a] -> Int -> Ordering+listLengthCmp = atLength atLen atEnd+ where+ atEnd = LT -- Not yet seen 'n' elts, so list length is < n.++ atLen [] = EQ+ atLen _ = GT++equalLength :: [a] -> [b] -> Bool+equalLength [] [] = True+equalLength (_:xs) (_:ys) = equalLength xs ys+equalLength _ _ = False++compareLength :: [a] -> [b] -> Ordering+compareLength [] [] = EQ+compareLength (_:xs) (_:ys) = compareLength xs ys+compareLength [] _ = LT+compareLength _ [] = GT++leLength :: [a] -> [b] -> Bool+-- ^ True if length xs <= length ys+leLength xs ys = case compareLength xs ys of+ LT -> True+ EQ -> True+ GT -> False++----------------------------+singleton :: a -> [a]+singleton x = [x]++isSingleton :: [a] -> Bool+isSingleton [_] = True+isSingleton _ = False++notNull :: [a] -> Bool+notNull [] = False+notNull _ = True++only :: [a] -> a+#ifdef DEBUG+only [a] = a+#else+only (a:_) = a+#endif+only _ = panic "Util: only"++-- Debugging/specialising versions of \tr{elem} and \tr{notElem}++isIn, isn'tIn :: Eq a => String -> a -> [a] -> Bool++# ifndef DEBUG+isIn _msg x ys = x `elem` ys+isn'tIn _msg x ys = x `notElem` ys++# else /* DEBUG */+isIn msg x ys+ = elem100 0 x ys+ where+ elem100 :: Eq a => Int -> a -> [a] -> Bool+ elem100 _ _ [] = False+ elem100 i x (y:ys)+ | i > 100 = trace ("Over-long elem in " ++ msg) (x `elem` (y:ys))+ | otherwise = x == y || elem100 (i + 1) x ys++isn'tIn msg x ys+ = notElem100 0 x ys+ where+ notElem100 :: Eq a => Int -> a -> [a] -> Bool+ notElem100 _ _ [] = True+ notElem100 i x (y:ys)+ | i > 100 = trace ("Over-long notElem in " ++ msg) (x `notElem` (y:ys))+ | otherwise = x /= y && notElem100 (i + 1) x ys+# endif /* DEBUG */+++-- | Split a list into chunks of /n/ elements+chunkList :: Int -> [a] -> [[a]]+chunkList _ [] = []+chunkList n xs = as : chunkList n bs where (as,bs) = splitAt n xs++-- | Replace the last element of a list with another element.+changeLast :: [a] -> a -> [a]+changeLast [] _ = panic "changeLast"+changeLast [_] x = [x]+changeLast (x:xs) x' = x : changeLast xs x'++{-+************************************************************************+* *+\subsubsection{Sort utils}+* *+************************************************************************+-}++minWith :: Ord b => (a -> b) -> [a] -> a+minWith get_key xs = ASSERT( not (null xs) )+ head (sortWith get_key xs)++nubSort :: Ord a => [a] -> [a]+nubSort = Set.toAscList . Set.fromList++{-+************************************************************************+* *+\subsection[Utils-transitive-closure]{Transitive closure}+* *+************************************************************************++This algorithm for transitive closure is straightforward, albeit quadratic.+-}++transitiveClosure :: (a -> [a]) -- Successor function+ -> (a -> a -> Bool) -- Equality predicate+ -> [a]+ -> [a] -- The transitive closure++transitiveClosure succ eq xs+ = go [] xs+ where+ go done [] = done+ go done (x:xs) | x `is_in` done = go done xs+ | otherwise = go (x:done) (succ x ++ xs)++ _ `is_in` [] = False+ x `is_in` (y:ys) | eq x y = True+ | otherwise = x `is_in` ys++{-+************************************************************************+* *+\subsection[Utils-accum]{Accumulating}+* *+************************************************************************++A combination of foldl with zip. It works with equal length lists.+-}++foldl2 :: (acc -> a -> b -> acc) -> acc -> [a] -> [b] -> acc+foldl2 _ z [] [] = z+foldl2 k z (a:as) (b:bs) = foldl2 k (k z a b) as bs+foldl2 _ _ _ _ = panic "Util: foldl2"++all2 :: (a -> b -> Bool) -> [a] -> [b] -> Bool+-- True if the lists are the same length, and+-- all corresponding elements satisfy the predicate+all2 _ [] [] = True+all2 p (x:xs) (y:ys) = p x y && all2 p xs ys+all2 _ _ _ = False++-- Count the number of times a predicate is true++count :: (a -> Bool) -> [a] -> Int+count p = go 0+ where go !n [] = n+ go !n (x:xs) | p x = go (n+1) xs+ | otherwise = go n xs++{-+@splitAt@, @take@, and @drop@ but with length of another+list giving the break-off point:+-}++takeList :: [b] -> [a] -> [a]+-- (takeList as bs) trims bs to the be same length+-- as as, unless as is longer in which case it's a no-op+takeList [] _ = []+takeList (_:xs) ls =+ case ls of+ [] -> []+ (y:ys) -> y : takeList xs ys++dropList :: [b] -> [a] -> [a]+dropList [] xs = xs+dropList _ xs@[] = xs+dropList (_:xs) (_:ys) = dropList xs ys+++splitAtList :: [b] -> [a] -> ([a], [a])+splitAtList [] xs = ([], xs)+splitAtList _ xs@[] = (xs, xs)+splitAtList (_:xs) (y:ys) = (y:ys', ys'')+ where+ (ys', ys'') = splitAtList xs ys++-- drop from the end of a list+dropTail :: Int -> [a] -> [a]+-- Specification: dropTail n = reverse . drop n . reverse+-- Better implemention due to Joachim Breitner+-- http://www.joachim-breitner.de/blog/archives/600-On-taking-the-last-n-elements-of-a-list.html+dropTail n xs+ = go (drop n xs) xs+ where+ go (_:ys) (x:xs) = x : go ys xs+ go _ _ = [] -- Stop when ys runs out+ -- It'll always run out before xs does++-- dropWhile from the end of a list. This is similar to Data.List.dropWhileEnd,+-- but is lazy in the elements and strict in the spine. For reasonably short lists,+-- such as path names and typical lines of text, dropWhileEndLE is generally+-- faster than dropWhileEnd. Its advantage is magnified when the predicate is+-- expensive--using dropWhileEndLE isSpace to strip the space off a line of text+-- is generally much faster than using dropWhileEnd isSpace for that purpose.+-- Specification: dropWhileEndLE p = reverse . dropWhile p . reverse+-- Pay attention to the short-circuit (&&)! The order of its arguments is the only+-- difference between dropWhileEnd and dropWhileEndLE.+dropWhileEndLE :: (a -> Bool) -> [a] -> [a]+dropWhileEndLE p = foldr (\x r -> if null r && p x then [] else x:r) []++-- | @spanEnd p l == reverse (span p (reverse l))@. The first list+-- returns actually comes after the second list (when you look at the+-- input list).+spanEnd :: (a -> Bool) -> [a] -> ([a], [a])+spanEnd p l = go l [] [] l+ where go yes _rev_yes rev_no [] = (yes, reverse rev_no)+ go yes rev_yes rev_no (x:xs)+ | p x = go yes (x : rev_yes) rev_no xs+ | otherwise = go xs [] (x : rev_yes ++ rev_no) xs+++snocView :: [a] -> Maybe ([a],a)+ -- Split off the last element+snocView [] = Nothing+snocView xs = go [] xs+ where+ -- Invariant: second arg is non-empty+ go acc [x] = Just (reverse acc, x)+ go acc (x:xs) = go (x:acc) xs+ go _ [] = panic "Util: snocView"++split :: Char -> String -> [String]+split c s = case rest of+ [] -> [chunk]+ _:rest -> chunk : split c rest+ where (chunk, rest) = break (==c) s++-- | Convert a word to title case by capitalising the first letter+capitalise :: String -> String+capitalise [] = []+capitalise (c:cs) = toUpper c : cs+++{-+************************************************************************+* *+\subsection[Utils-comparison]{Comparisons}+* *+************************************************************************+-}++isEqual :: Ordering -> Bool+-- Often used in (isEqual (a `compare` b))+isEqual GT = False+isEqual EQ = True+isEqual LT = False++thenCmp :: Ordering -> Ordering -> Ordering+{-# INLINE thenCmp #-}+thenCmp EQ ordering = ordering+thenCmp ordering _ = ordering++eqListBy :: (a->a->Bool) -> [a] -> [a] -> Bool+eqListBy _ [] [] = True+eqListBy eq (x:xs) (y:ys) = eq x y && eqListBy eq xs ys+eqListBy _ _ _ = False++eqMaybeBy :: (a ->a->Bool) -> Maybe a -> Maybe a -> Bool+eqMaybeBy _ Nothing Nothing = True+eqMaybeBy eq (Just x) (Just y) = eq x y+eqMaybeBy _ _ _ = False++cmpList :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering+ -- `cmpList' uses a user-specified comparer++cmpList _ [] [] = EQ+cmpList _ [] _ = LT+cmpList _ _ [] = GT+cmpList cmp (a:as) (b:bs)+ = case cmp a b of { EQ -> cmpList cmp as bs; xxx -> xxx }++removeSpaces :: String -> String+removeSpaces = dropWhileEndLE isSpace . dropWhile isSpace++-- Boolean operators lifted to Applicative+(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool+(<&&>) = liftA2 (&&)+infixr 3 <&&> -- same as (&&)++(<||>) :: Applicative f => f Bool -> f Bool -> f Bool+(<||>) = liftA2 (||)+infixr 2 <||> -- same as (||)++{-+************************************************************************+* *+\subsection{Edit distance}+* *+************************************************************************+-}++-- | Find the "restricted" Damerau-Levenshtein edit distance between two strings.+-- See: <http://en.wikipedia.org/wiki/Damerau-Levenshtein_distance>.+-- Based on the algorithm presented in "A Bit-Vector Algorithm for Computing+-- Levenshtein and Damerau Edit Distances" in PSC'02 (Heikki Hyyro).+-- See http://www.cs.uta.fi/~helmu/pubs/psc02.pdf and+-- http://www.cs.uta.fi/~helmu/pubs/PSCerr.html for an explanation+restrictedDamerauLevenshteinDistance :: String -> String -> Int+restrictedDamerauLevenshteinDistance str1 str2+ = restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2+ where+ m = length str1+ n = length str2++restrictedDamerauLevenshteinDistanceWithLengths+ :: Int -> Int -> String -> String -> Int+restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2+ | m <= n+ = if n <= 32 -- n must be larger so this check is sufficient+ then restrictedDamerauLevenshteinDistance' (undefined :: Word32) m n str1 str2+ else restrictedDamerauLevenshteinDistance' (undefined :: Integer) m n str1 str2++ | otherwise+ = if m <= 32 -- m must be larger so this check is sufficient+ then restrictedDamerauLevenshteinDistance' (undefined :: Word32) n m str2 str1+ else restrictedDamerauLevenshteinDistance' (undefined :: Integer) n m str2 str1++restrictedDamerauLevenshteinDistance'+ :: (Bits bv, Num bv) => bv -> Int -> Int -> String -> String -> Int+restrictedDamerauLevenshteinDistance' _bv_dummy m n str1 str2+ | [] <- str1 = n+ | otherwise = extractAnswer $+ foldl' (restrictedDamerauLevenshteinDistanceWorker+ (matchVectors str1) top_bit_mask vector_mask)+ (0, 0, m_ones, 0, m) str2+ where+ m_ones@vector_mask = (2 ^ m) - 1+ top_bit_mask = (1 `shiftL` (m - 1)) `asTypeOf` _bv_dummy+ extractAnswer (_, _, _, _, distance) = distance++restrictedDamerauLevenshteinDistanceWorker+ :: (Bits bv, Num bv) => IM.IntMap bv -> bv -> bv+ -> (bv, bv, bv, bv, Int) -> Char -> (bv, bv, bv, bv, Int)+restrictedDamerauLevenshteinDistanceWorker str1_mvs top_bit_mask vector_mask+ (pm, d0, vp, vn, distance) char2+ = seq str1_mvs $ seq top_bit_mask $ seq vector_mask $+ seq pm' $ seq d0' $ seq vp' $ seq vn' $+ seq distance'' $ seq char2 $+ (pm', d0', vp', vn', distance'')+ where+ pm' = IM.findWithDefault 0 (ord char2) str1_mvs++ d0' = ((((sizedComplement vector_mask d0) .&. pm') `shiftL` 1) .&. pm)+ .|. ((((pm' .&. vp) + vp) .&. vector_mask) `xor` vp) .|. pm' .|. vn+ -- No need to mask the shiftL because of the restricted range of pm++ hp' = vn .|. sizedComplement vector_mask (d0' .|. vp)+ hn' = d0' .&. vp++ hp'_shift = ((hp' `shiftL` 1) .|. 1) .&. vector_mask+ hn'_shift = (hn' `shiftL` 1) .&. vector_mask+ vp' = hn'_shift .|. sizedComplement vector_mask (d0' .|. hp'_shift)+ vn' = d0' .&. hp'_shift++ distance' = if hp' .&. top_bit_mask /= 0 then distance + 1 else distance+ distance'' = if hn' .&. top_bit_mask /= 0 then distance' - 1 else distance'++sizedComplement :: Bits bv => bv -> bv -> bv+sizedComplement vector_mask vect = vector_mask `xor` vect++matchVectors :: (Bits bv, Num bv) => String -> IM.IntMap bv+matchVectors = snd . foldl' go (0 :: Int, IM.empty)+ where+ go (ix, im) char = let ix' = ix + 1+ im' = IM.insertWith (.|.) (ord char) (2 ^ ix) im+ in seq ix' $ seq im' $ (ix', im')++{-# SPECIALIZE INLINE restrictedDamerauLevenshteinDistance'+ :: Word32 -> Int -> Int -> String -> String -> Int #-}+{-# SPECIALIZE INLINE restrictedDamerauLevenshteinDistance'+ :: Integer -> Int -> Int -> String -> String -> Int #-}++{-# SPECIALIZE restrictedDamerauLevenshteinDistanceWorker+ :: IM.IntMap Word32 -> Word32 -> Word32+ -> (Word32, Word32, Word32, Word32, Int)+ -> Char -> (Word32, Word32, Word32, Word32, Int) #-}+{-# SPECIALIZE restrictedDamerauLevenshteinDistanceWorker+ :: IM.IntMap Integer -> Integer -> Integer+ -> (Integer, Integer, Integer, Integer, Int)+ -> Char -> (Integer, Integer, Integer, Integer, Int) #-}++{-# SPECIALIZE INLINE sizedComplement :: Word32 -> Word32 -> Word32 #-}+{-# SPECIALIZE INLINE sizedComplement :: Integer -> Integer -> Integer #-}++{-# SPECIALIZE matchVectors :: String -> IM.IntMap Word32 #-}+{-# SPECIALIZE matchVectors :: String -> IM.IntMap Integer #-}++fuzzyMatch :: String -> [String] -> [String]+fuzzyMatch key vals = fuzzyLookup key [(v,v) | v <- vals]++-- | Search for possible matches to the users input in the given list,+-- returning a small number of ranked results+fuzzyLookup :: String -> [(String,a)] -> [a]+fuzzyLookup user_entered possibilites+ = map fst $ take mAX_RESULTS $ sortBy (comparing snd)+ [ (poss_val, distance) | (poss_str, poss_val) <- possibilites+ , let distance = restrictedDamerauLevenshteinDistance+ poss_str user_entered+ , distance <= fuzzy_threshold ]+ where+ -- Work out an approriate match threshold:+ -- We report a candidate if its edit distance is <= the threshold,+ -- The threshold is set to about a quarter of the # of characters the user entered+ -- Length Threshold+ -- 1 0 -- Don't suggest *any* candidates+ -- 2 1 -- for single-char identifiers+ -- 3 1+ -- 4 1+ -- 5 1+ -- 6 2+ --+ fuzzy_threshold = truncate $ fromIntegral (length user_entered + 2) / (4 :: Rational)+ mAX_RESULTS = 3++{-+************************************************************************+* *+\subsection[Utils-pairs]{Pairs}+* *+************************************************************************+-}++unzipWith :: (a -> b -> c) -> [(a, b)] -> [c]+unzipWith f pairs = map ( \ (a, b) -> f a b ) pairs++seqList :: [a] -> b -> b+seqList [] b = b+seqList (x:xs) b = x `seq` seqList xs b+++{-+************************************************************************+* *+ Globals and the RTS+* *+************************************************************************++When a plugin is loaded, it currently gets linked against a *newly+loaded* copy of the GHC package. This would not be a problem, except+that the new copy has its own mutable state that is not shared with+that state that has already been initialized by the original GHC+package.++(Note that if the GHC executable was dynamically linked this+wouldn't be a problem, because we could share the GHC library it+links to; this is only a problem if DYNAMIC_GHC_PROGRAMS=NO.)++The solution is to make use of @sharedCAF@ through @sharedGlobal@+for globals that are shared between multiple copies of ghc packages.+-}++-- Global variables:++global :: a -> IORef a+global a = unsafePerformIO (newIORef a)++consIORef :: IORef [a] -> a -> IO ()+consIORef var x = do+ atomicModifyIORef' var (\xs -> (x:xs,()))++globalM :: IO a -> IORef a+globalM ma = unsafePerformIO (ma >>= newIORef)++-- Shared global variables:++sharedGlobal :: a -> (Ptr (IORef a) -> IO (Ptr (IORef a))) -> IORef a+sharedGlobal a get_or_set = unsafePerformIO $+ newIORef a >>= flip sharedCAF get_or_set++sharedGlobalM :: IO a -> (Ptr (IORef a) -> IO (Ptr (IORef a))) -> IORef a+sharedGlobalM ma get_or_set = unsafePerformIO $+ ma >>= newIORef >>= flip sharedCAF get_or_set++-- Module names:++looksLikeModuleName :: String -> Bool+looksLikeModuleName [] = False+looksLikeModuleName (c:cs) = isUpper c && go cs+ where go [] = True+ go ('.':cs) = looksLikeModuleName cs+ go (c:cs) = (isAlphaNum c || c == '_' || c == '\'') && go cs++-- Similar to 'parse' for Distribution.Package.PackageName,+-- but we don't want to depend on Cabal.+looksLikePackageName :: String -> Bool+looksLikePackageName = all (all isAlphaNum <&&> not . (all isDigit)) . split '-'++{-+Akin to @Prelude.words@, but acts like the Bourne shell, treating+quoted strings as Haskell Strings, and also parses Haskell [String]+syntax.+-}++getCmd :: String -> Either String -- Error+ (String, String) -- (Cmd, Rest)+getCmd s = case break isSpace $ dropWhile isSpace s of+ ([], _) -> Left ("Couldn't find command in " ++ show s)+ res -> Right res++toCmdArgs :: String -> Either String -- Error+ (String, [String]) -- (Cmd, Args)+toCmdArgs s = case getCmd s of+ Left err -> Left err+ Right (cmd, s') -> case toArgs s' of+ Left err -> Left err+ Right args -> Right (cmd, args)++toArgs :: String -> Either String -- Error+ [String] -- Args+toArgs str+ = case dropWhile isSpace str of+ s@('[':_) -> case reads s of+ [(args, spaces)]+ | all isSpace spaces ->+ Right args+ _ ->+ Left ("Couldn't read " ++ show str ++ " as [String]")+ s -> toArgs' s+ where+ toArgs' :: String -> Either String [String]+ -- Remove outer quotes:+ -- > toArgs' "\"foo\" \"bar baz\""+ -- Right ["foo", "bar baz"]+ --+ -- Keep inner quotes:+ -- > toArgs' "-DFOO=\"bar baz\""+ -- Right ["-DFOO=\"bar baz\""]+ toArgs' s = case dropWhile isSpace s of+ [] -> Right []+ ('"' : _) -> do+ -- readAsString removes outer quotes+ (arg, rest) <- readAsString s+ (arg:) `fmap` toArgs' rest+ s' -> case break (isSpace <||> (== '"')) s' of+ (argPart1, s''@('"':_)) -> do+ (argPart2, rest) <- readAsString s''+ -- show argPart2 to keep inner quotes+ ((argPart1 ++ show argPart2):) `fmap` toArgs' rest+ (arg, s'') -> (arg:) `fmap` toArgs' s''++ readAsString :: String -> Either String (String, String)+ readAsString s = case reads s of+ [(arg, rest)]+ -- rest must either be [] or start with a space+ | all isSpace (take 1 rest) ->+ Right (arg, rest)+ _ ->+ Left ("Couldn't read " ++ show s ++ " as String")+-----------------------------------------------------------------------------+-- Integers++-- This algorithm for determining the $\log_2$ of exact powers of 2 comes+-- from GCC. It requires bit manipulation primitives, and we use GHC+-- extensions. Tough.++exactLog2 :: Integer -> Maybe Integer+exactLog2 x+ = if (x <= 0 || x >= 2147483648) then+ Nothing+ else+ if (x .&. (-x)) /= x then+ Nothing+ else+ Just (pow2 x)+ where+ pow2 x | x == 1 = 0+ | otherwise = 1 + pow2 (x `shiftR` 1)+++{-+-- -----------------------------------------------------------------------------+-- Floats+-}++readRational__ :: ReadS Rational -- NB: doesn't handle leading "-"+readRational__ r = do+ (n,d,s) <- readFix r+ (k,t) <- readExp s+ return ((n%1)*10^^(k-d), t)+ where+ readFix r = do+ (ds,s) <- lexDecDigits r+ (ds',t) <- lexDotDigits s+ return (read (ds++ds'), length ds', t)++ readExp (e:s) | e `elem` "eE" = readExp' s+ readExp s = return (0,s)++ readExp' ('+':s) = readDec s+ readExp' ('-':s) = do (k,t) <- readDec s+ return (-k,t)+ readExp' s = readDec s++ readDec s = do+ (ds,r) <- nonnull isDigit s+ return (foldl1 (\n d -> n * 10 + d) [ ord d - ord '0' | d <- ds ],+ r)++ lexDecDigits = nonnull isDigit++ lexDotDigits ('.':s) = return (span isDigit s)+ lexDotDigits s = return ("",s)++ nonnull p s = do (cs@(_:_),t) <- return (span p s)+ return (cs,t)++readRational :: String -> Rational -- NB: *does* handle a leading "-"+readRational top_s+ = case top_s of+ '-' : xs -> - (read_me xs)+ xs -> read_me xs+ where+ read_me s+ = case (do { (x,"") <- readRational__ s ; return x }) of+ [x] -> x+ [] -> error ("readRational: no parse:" ++ top_s)+ _ -> error ("readRational: ambiguous parse:" ++ top_s)+++-----------------------------------------------------------------------------+-- read helpers++maybeRead :: Read a => String -> Maybe a+maybeRead str = case reads str of+ [(x, "")] -> Just x+ _ -> Nothing++maybeReadFuzzy :: Read a => String -> Maybe a+maybeReadFuzzy str = case reads str of+ [(x, s)]+ | all isSpace s ->+ Just x+ _ ->+ Nothing++-----------------------------------------------------------------------------+-- Verify that the 'dirname' portion of a FilePath exists.+--+doesDirNameExist :: FilePath -> IO Bool+doesDirNameExist fpath = doesDirectoryExist (takeDirectory fpath)++-----------------------------------------------------------------------------+-- Backwards compatibility definition of getModificationTime++getModificationUTCTime :: FilePath -> IO UTCTime+getModificationUTCTime = getModificationTime++-- --------------------------------------------------------------+-- check existence & modification time at the same time++modificationTimeIfExists :: FilePath -> IO (Maybe UTCTime)+modificationTimeIfExists f = do+ (do t <- getModificationUTCTime f; return (Just t))+ `catchIO` \e -> if isDoesNotExistError e+ then return Nothing+ else ioError e++-- --------------------------------------------------------------+-- Change the character encoding of the given Handle to transliterate+-- on unsupported characters instead of throwing an exception++hSetTranslit :: Handle -> IO ()+hSetTranslit h = do+ menc <- hGetEncoding h+ case fmap textEncodingName menc of+ Just name | '/' `notElem` name -> do+ enc' <- mkTextEncoding $ name ++ "//TRANSLIT"+ hSetEncoding h enc'+ _ -> return ()++-- split a string at the last character where 'pred' is True,+-- returning a pair of strings. The first component holds the string+-- up (but not including) the last character for which 'pred' returned+-- True, the second whatever comes after (but also not including the+-- last character).+--+-- If 'pred' returns False for all characters in the string, the original+-- string is returned in the first component (and the second one is just+-- empty).+splitLongestPrefix :: String -> (Char -> Bool) -> (String,String)+splitLongestPrefix str pred+ | null r_pre = (str, [])+ | otherwise = (reverse (tail r_pre), reverse r_suf)+ -- 'tail' drops the char satisfying 'pred'+ where (r_suf, r_pre) = break pred (reverse str)++escapeSpaces :: String -> String+escapeSpaces = foldr (\c s -> if isSpace c then '\\':c:s else c:s) ""++type Suffix = String++--------------------------------------------------------------+-- * Search path+--------------------------------------------------------------++data Direction = Forwards | Backwards++reslash :: Direction -> FilePath -> FilePath+reslash d = f+ where f ('/' : xs) = slash : f xs+ f ('\\' : xs) = slash : f xs+ f (x : xs) = x : f xs+ f "" = ""+ slash = case d of+ Forwards -> '/'+ Backwards -> '\\'++makeRelativeTo :: FilePath -> FilePath -> FilePath+this `makeRelativeTo` that = directory </> thisFilename+ where (thisDirectory, thisFilename) = splitFileName this+ thatDirectory = dropFileName that+ directory = joinPath $ f (splitPath thisDirectory)+ (splitPath thatDirectory)++ f (x : xs) (y : ys)+ | x == y = f xs ys+ f xs ys = replicate (length ys) ".." ++ xs++{-+************************************************************************+* *+\subsection[Utils-Data]{Utils for defining Data instances}+* *+************************************************************************++These functions helps us to define Data instances for abstract types.+-}++abstractConstr :: String -> Constr+abstractConstr n = mkConstr (abstractDataType n) ("{abstract:"++n++"}") [] Prefix++abstractDataType :: String -> DataType+abstractDataType n = mkDataType n [abstractConstr n]++{-+************************************************************************+* *+\subsection[Utils-C]{Utils for printing C code}+* *+************************************************************************+-}++charToC :: Word8 -> String+charToC w =+ case chr (fromIntegral w) of+ '\"' -> "\\\""+ '\'' -> "\\\'"+ '\\' -> "\\\\"+ c | c >= ' ' && c <= '~' -> [c]+ | otherwise -> ['\\',+ chr (ord '0' + ord c `div` 64),+ chr (ord '0' + ord c `div` 8 `mod` 8),+ chr (ord '0' + ord c `mod` 8)]++{-+************************************************************************+* *+\subsection[Utils-Hashing]{Utils for hashing}+* *+************************************************************************+-}++-- | A sample hash function for Strings. We keep multiplying by the+-- golden ratio and adding. The implementation is:+--+-- > hashString = foldl' f golden+-- > where f m c = fromIntegral (ord c) * magic + hashInt32 m+-- > magic = 0xdeadbeef+--+-- Where hashInt32 works just as hashInt shown above.+--+-- Knuth argues that repeated multiplication by the golden ratio+-- will minimize gaps in the hash space, and thus it's a good choice+-- for combining together multiple keys to form one.+--+-- Here we know that individual characters c are often small, and this+-- produces frequent collisions if we use ord c alone. A+-- particular problem are the shorter low ASCII and ISO-8859-1+-- character strings. We pre-multiply by a magic twiddle factor to+-- obtain a good distribution. In fact, given the following test:+--+-- > testp :: Int32 -> Int+-- > testp k = (n - ) . length . group . sort . map hs . take n $ ls+-- > where ls = [] : [c : l | l <- ls, c <- ['\0'..'\xff']]+-- > hs = foldl' f golden+-- > f m c = fromIntegral (ord c) * k + hashInt32 m+-- > n = 100000+--+-- We discover that testp magic = 0.+hashString :: String -> Int32+hashString = foldl' f golden+ where f m c = fromIntegral (ord c) * magic + hashInt32 m+ magic = fromIntegral (0xdeadbeef :: Word32)++golden :: Int32+golden = 1013904242 -- = round ((sqrt 5 - 1) * 2^32) :: Int32+-- was -1640531527 = round ((sqrt 5 - 1) * 2^31) :: Int32+-- but that has bad mulHi properties (even adding 2^32 to get its inverse)+-- Whereas the above works well and contains no hash duplications for+-- [-32767..65536]++-- | A sample (and useful) hash function for Int32,+-- implemented by extracting the uppermost 32 bits of the 64-bit+-- result of multiplying by a 33-bit constant. The constant is from+-- Knuth, derived from the golden ratio:+--+-- > golden = round ((sqrt 5 - 1) * 2^32)+--+-- We get good key uniqueness on small inputs+-- (a problem with previous versions):+-- (length $ group $ sort $ map hashInt32 [-32767..65536]) == 65536 + 32768+--+hashInt32 :: Int32 -> Int32+hashInt32 x = mulHi x golden + x++-- hi 32 bits of a x-bit * 32 bit -> 64-bit multiply+mulHi :: Int32 -> Int32 -> Int32+mulHi a b = fromIntegral (r `shiftR` 32)+ where r :: Int64+ r = fromIntegral a * fromIntegral b++-- | A compatibility wrapper for the @GHC.Stack.HasCallStack@ constraint.+#if __GLASGOW_HASKELL__ >= 800+type HasCallStack = GHC.Stack.HasCallStack+#elif MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)+type HasCallStack = (?callStack :: GHC.Stack.CallStack)+-- CallStack wasn't present in GHC 7.10.1, disable callstacks in stage 1+#else+type HasCallStack = (() :: Constraint)+#endif++-- | A call stack constraint, but only when 'isDebugOn'.+#if DEBUG+type HasDebugCallStack = HasCallStack+#else+type HasDebugCallStack = (() :: Constraint)+#endif++-- | Pretty-print the current callstack+#if __GLASGOW_HASKELL__ >= 800+prettyCurrentCallStack :: HasCallStack => String+prettyCurrentCallStack = GHC.Stack.prettyCallStack GHC.Stack.callStack+#elif MIN_VERSION_GLASGOW_HASKELL(7,10,2,0)+prettyCurrentCallStack :: (?callStack :: GHC.Stack.CallStack) => String+prettyCurrentCallStack = GHC.Stack.showCallStack ?callStack+#else+prettyCurrentCallStack :: HasCallStack => String+prettyCurrentCallStack = "Call stack unavailable"+#endif++data OverridingBool+ = Auto+ | Always+ | Never+ deriving Show++overrideWith :: Bool -> OverridingBool -> Bool+overrideWith b Auto = b+overrideWith _ Always = True+overrideWith _ Never = False
+ utils/md5.h view
@@ -0,0 +1,24 @@+/* MD5 message digest */+#ifndef _MD5_H+#define _MD5_H++#include "HsFFI.h"++typedef HsWord32 word32;+typedef HsWord8 byte;++struct MD5Context {+ word32 buf[4];+ word32 bytes[2];+ word32 in[16];+};++void MD5Init(struct MD5Context *context);+void MD5Update(struct MD5Context *context, byte const *buf, int len);+void MD5Final(byte digest[16], struct MD5Context *context);+void MD5Transform(word32 buf[4], word32 const in[16]);++#endif /* _MD5_H */+++
+ vectorise/Vectorise.hs view
@@ -0,0 +1,356 @@+-- Main entry point to the vectoriser. It is invoked iff the option '-fvectorise' is passed.+--+-- This module provides the function 'vectorise', which vectorises an entire (desugared) module.+-- It vectorises all type declarations and value bindings. It also processes all VECTORISE pragmas+-- (aka vectorisation declarations), which can lead to the vectorisation of imported data types+-- and the enrichment of imported functions with vectorised versions.++module Vectorise ( vectorise )+where++import Vectorise.Type.Env+import Vectorise.Type.Type+import Vectorise.Convert+import Vectorise.Utils.Hoisting+import Vectorise.Exp+import Vectorise.Env+import Vectorise.Monad++import HscTypes hiding ( MonadThings(..) )+import CoreUnfold ( mkInlineUnfoldingWithArity )+import PprCore+import CoreSyn+import CoreMonad ( CoreM, getHscEnv )+import Type+import Id+import DynFlags+import Outputable+import Util ( zipLazy )+import MonadUtils++import Control.Monad+++-- |Vectorise a single module.+--+vectorise :: ModGuts -> CoreM ModGuts+vectorise guts+ = do { hsc_env <- getHscEnv+ ; liftIO $ vectoriseIO hsc_env guts+ }++-- Vectorise a single monad, given the dynamic compiler flags and HscEnv.+--+vectoriseIO :: HscEnv -> ModGuts -> IO ModGuts+vectoriseIO hsc_env guts+ = do { -- Get information about currently loaded external packages.+ ; eps <- hscEPS hsc_env++ -- Combine vectorisation info from the current module, and external ones.+ ; let info = hptVectInfo hsc_env `plusVectInfo` eps_vect_info eps++ -- Run the main VM computation.+ ; Just (info', guts') <- initV hsc_env guts info (vectModule guts)+ ; return (guts' { mg_vect_info = info' })+ }++-- Vectorise a single module, in the VM monad.+--+vectModule :: ModGuts -> VM ModGuts+vectModule guts@(ModGuts { mg_tcs = tycons+ , mg_binds = binds+ , mg_fam_insts = fam_insts+ , mg_vect_decls = vect_decls+ })+ = do { dumpOptVt Opt_D_dump_vt_trace "Before vectorisation" $+ pprCoreBindings binds++ -- Pick out all 'VECTORISE [SCALAR] type' and 'VECTORISE class' pragmas+ ; let ty_vect_decls = [vd | vd@(VectType _ _ _) <- vect_decls]+ cls_vect_decls = [vd | vd@(VectClass _) <- vect_decls]++ -- Vectorise the type environment. This will add vectorised+ -- type constructors, their representations, and the+ -- corresponding data constructors. Moreover, we produce+ -- bindings for dfuns and family instances of the classes+ -- and type families used in the DPH library to represent+ -- array types.+ ; (new_tycons, new_fam_insts, tc_binds) <- vectTypeEnv tycons ty_vect_decls cls_vect_decls++ -- Family instance environment for /all/ home-package modules including those instances+ -- generated by 'vectTypeEnv'.+ ; (_, fam_inst_env) <- readGEnv global_fam_inst_env++ -- Vectorise all the top level bindings and VECTORISE declarations on imported identifiers+ -- NB: Need to vectorise the imported bindings first (local bindings may depend on them).+ ; let impBinds = [(imp_id, expr) | Vect imp_id expr <- vect_decls, isGlobalId imp_id]+ ; binds_imp <- mapM vectImpBind impBinds+ ; binds_top <- mapM vectTopBind binds++ ; return $ guts { mg_tcs = tycons ++ new_tycons+ -- we produce no new classes or instances, only new class type constructors+ -- and dfuns+ , mg_binds = Rec tc_binds : (binds_top ++ binds_imp)+ , mg_fam_inst_env = fam_inst_env+ , mg_fam_insts = fam_insts ++ new_fam_insts+ }+ }++-- Try to vectorise a top-level binding. If it doesn't vectorise, or if it is entirely scalar, then+-- omit vectorisation of that binding.+--+-- For example, for the binding+--+-- @+-- foo :: Int -> Int+-- foo = \x -> x + x+-- @+--+-- we get+-- @+-- foo :: Int -> Int+-- foo = \x -> vfoo $: x+--+-- v_foo :: Closure void vfoo lfoo+-- v_foo = closure vfoo lfoo void+--+-- vfoo :: Void -> Int -> Int+-- vfoo = ...+--+-- lfoo :: PData Void -> PData Int -> PData Int+-- lfoo = ...+-- @+--+-- @vfoo@ is the "vectorised", or scalar, version that does the same as the original function foo,+-- but takes an explicit environment.+--+-- @lfoo@ is the "lifted" version that works on arrays.+--+-- @v_foo@ combines both of these into a `Closure` that also contains the environment.+--+-- The original binding @foo@ is rewritten to call the vectorised version present in the closure.+--+-- Vectorisation may be suppressed by annotating a binding with a 'NOVECTORISE' pragma. If this+-- pragma is used in a group of mutually recursive bindings, either all or no binding must have+-- the pragma. If only some bindings are annotated, a fatal error is being raised. (In the case of+-- scalar bindings, we only omit vectorisation if all bindings in a group are scalar.)+--+-- FIXME: Once we support partial vectorisation, we may be able to vectorise parts of a group, or+-- we may emit a warning and refrain from vectorising the entire group.+--+vectTopBind :: CoreBind -> VM CoreBind+vectTopBind b@(NonRec var expr)+ = do+ { traceVt "= Vectorise non-recursive top-level variable" (ppr var)++ ; (hasNoVect, vectDecl) <- lookupVectDecl var+ ; if hasNoVect+ then do+ { -- 'NOVECTORISE' pragma => leave this binding as it is+ ; traceVt "NOVECTORISE" $ ppr var+ ; return b+ }+ else do+ { vectRhs <- case vectDecl of+ Just (_, expr') ->+ -- 'VECTORISE' pragma => just use the provided vectorised rhs+ do+ { traceVt "VECTORISE" $ ppr var+ ; addGlobalParallelVar var+ ; return $ Just (False, inlineMe, expr')+ }+ Nothing ->+ -- no pragma => standard vectorisation of rhs+ do+ { traceVt "[Vanilla]" $ ppr var <+> char '=' <+> ppr expr+ ; vectTopExpr var expr+ }+ ; hs <- takeHoisted -- make sure we clean those out (even if we skip)+ ; case vectRhs of+ { Nothing ->+ -- scalar binding => leave this binding as it is+ do+ { traceVt "scalar binding [skip]" $ ppr var+ ; return b+ }+ ; Just (parBind, inline, expr') -> do+ {+ -- vanilla case => create an appropriate top-level binding & add it to the vectorisation map+ ; when parBind $+ addGlobalParallelVar var+ ; var' <- vectTopBinder var inline expr'++ -- We replace the original top-level binding by a value projected from the vectorised+ -- closure and add any newly created hoisted top-level bindings.+ ; cexpr <- tryConvert var var' expr+ ; return . Rec $ (var, cexpr) : (var', expr') : hs+ } } } }+ `orElseErrV`+ do+ { emitVt " Could NOT vectorise top-level binding" $ ppr var+ ; return b+ }+vectTopBind b@(Rec binds)+ = do+ { traceVt "= Vectorise recursive top-level variables" $ ppr vars++ ; vectDecls <- mapM lookupVectDecl vars+ ; let hasNoVects = map fst vectDecls+ ; if and hasNoVects+ then do+ { -- 'NOVECTORISE' pragmas => leave this entire binding group as it is+ ; traceVt "NOVECTORISE" $ ppr vars+ ; return b+ }+ else do+ { if or hasNoVects+ then do+ { -- Inconsistent 'NOVECTORISE' pragmas => bail out+ ; dflags <- getDynFlags+ ; cantVectorise dflags noVectoriseErr (ppr b)+ }+ else do+ { traceVt "[Vanilla]" $ vcat [ppr var <+> char '=' <+> ppr expr | (var, expr) <- binds]++ -- For all bindings *with* a pragma, just use the pragma-supplied vectorised expression+ ; newBindsWPragma <- concat <$>+ sequence [ vectTopBindAndConvert bind inlineMe expr'+ | (bind, (_, Just (_, expr'))) <- zip binds vectDecls]++ -- Standard vectorisation of all rhses that are *without* a pragma.+ -- NB: The reason for 'fixV' is rather subtle: 'vectTopBindAndConvert' adds entries for+ -- the bound variables in the recursive group to the vectorisation map, which in turn+ -- are needed by 'vectPolyExprs' (unless it returns 'Nothing').+ ; let bindsWOPragma = [bind | (bind, (_, Nothing)) <- zip binds vectDecls]+ ; (newBinds, _) <- fixV $+ \ ~(_, exprs') ->+ do+ { -- Create appropriate top-level bindings, enter them into the vectorisation map, and+ -- vectorise the right-hand sides+ ; newBindsWOPragma <- concat <$>+ sequence [vectTopBindAndConvert bind inline expr+ | (bind, ~(inline, expr)) <- zipLazy bindsWOPragma exprs']+ -- irrefutable pattern and 'zipLazy' to tie the knot;+ -- hence, can't use 'zipWithM'+ ; vectRhses <- vectTopExprs bindsWOPragma+ ; hs <- takeHoisted -- make sure we clean those out (even if we skip)++ ; case vectRhses of+ Nothing ->+ -- scalar bindings => skip all bindings except those with pragmas and retract the+ -- entries into the vectorisation map for the scalar bindings+ do+ { traceVt "scalar bindings [skip]" $ ppr vars+ ; mapM_ (undefGlobalVar . fst) bindsWOPragma+ ; return (bindsWOPragma ++ newBindsWPragma, exprs')+ }+ Just (parBind, exprs') ->+ -- vanilla case => record parallel variables and return the final bindings+ do+ { when parBind $+ mapM_ addGlobalParallelVar vars+ ; return (newBindsWOPragma ++ newBindsWPragma ++ hs, exprs')+ }+ }+ ; return $ Rec newBinds+ } } }+ `orElseErrV`+ do+ { emitVt " Could NOT vectorise top-level bindings" $ ppr vars+ ; return b+ }+ where+ vars = map fst binds+ noVectoriseErr = "NOVECTORISE must be used on all or no bindings of a recursive group"++ -- Replace the original top-level bindings by a values projected from the vectorised+ -- closures and add any newly created hoisted top-level bindings to the group.+ vectTopBindAndConvert (var, expr) inline expr'+ = do+ { var' <- vectTopBinder var inline expr'+ ; cexpr <- tryConvert var var' expr+ ; return [(var, cexpr), (var', expr')]+ }++-- Add a vectorised binding to an imported top-level variable that has a VECTORISE pragma+-- in this module.+--+-- RESTRICTION: Currently, we cannot use the pragma for mutually recursive definitions.+--+vectImpBind :: (Id, CoreExpr) -> VM CoreBind+vectImpBind (var, expr)+ = do+ { traceVt "= Add vectorised binding to imported variable" (ppr var)++ ; var' <- vectTopBinder var inlineMe expr+ ; return $ NonRec var' expr+ }++-- |Make the vectorised version of this top level binder, and add the mapping between it and the+-- original to the state. For some binder @foo@ the vectorised version is @$v_foo@+--+-- NOTE: 'vectTopBinder' *MUST* be lazy in inline and expr because of how it is used inside of+-- 'fixV' in 'vectTopBind'.+--+vectTopBinder :: Var -- ^ Name of the binding.+ -> Inline -- ^ Whether it should be inlined, used to annotate it.+ -> CoreExpr -- ^ RHS of binding, used to set the 'Unfolding' of the returned 'Var'.+ -> VM Var -- ^ Name of the vectorised binding.+vectTopBinder var inline expr+ = do { -- Vectorise the type attached to the var.+ ; vty <- vectType (idType var)++ -- If there is a vectorisation declaration for this binding, make sure its type matches+ ; (_, vectDecl) <- lookupVectDecl var+ ; case vectDecl of+ Nothing -> return ()+ Just (vdty, _)+ | eqType vty vdty -> return ()+ | otherwise ->+ do+ { dflags <- getDynFlags+ ; cantVectorise dflags ("Type mismatch in vectorisation pragma for " ++ showPpr dflags var) $+ (text "Expected type" <+> ppr vty)+ $$+ (text "Inferred type" <+> ppr vdty)+ }+ -- Make the vectorised version of binding's name, and set the unfolding used for inlining+ ; var' <- liftM (`setIdUnfolding` unfolding)+ $ mkVectId var vty++ -- Add the mapping between the plain and vectorised name to the state.+ ; defGlobalVar var var'++ ; return var'+ }+ where+ unfolding = case inline of+ Inline arity -> mkInlineUnfoldingWithArity arity expr+ DontInline -> noUnfolding+{-+!!!TODO: dfuns and unfoldings:+ -- Do not inline the dfun; instead give it a magic DFunFunfolding+ -- See Note [ClassOp/DFun selection]+ -- See also note [Single-method classes]+ dfun_id_w_fun+ | isNewTyCon class_tc+ = dfun_id `setInlinePragma` alwaysInlinePragma { inl_sat = Just 0 }+ | otherwise+ = dfun_id `setIdUnfolding` mkDFunUnfolding dfun_ty dfun_args+ `setInlinePragma` dfunInlinePragma+ -}++-- |Project out the vectorised version of a binding from some closure, or return the original body+-- if that doesn't work.+--+tryConvert :: Var -- ^Name of the original binding (eg @foo@)+ -> Var -- ^Name of vectorised version of binding (eg @$vfoo@)+ -> CoreExpr -- ^The original body of the binding.+ -> VM CoreExpr+tryConvert var vect_var rhs+ = fromVect (idType var) (Var vect_var)+ `orElseErrV`+ do+ { emitVt " Could NOT call vectorised from original version" $ ppr var <+> dcolon <+> ppr (idType var)+ ; return rhs+ }
+ vectorise/Vectorise/Builtins.hs view
@@ -0,0 +1,35 @@+-- Types and functions declared in 'Data.Array.Parallel.Prim' and used by the vectoriser.+--+-- The @Builtins@ structure holds the name of all the things in 'Data.Array.Parallel.Prim' that+-- appear in code generated by the vectoriser.++module Vectorise.Builtins (+ -- * Restrictions+ mAX_DPH_SCALAR_ARGS,++ -- * Builtins+ Builtins(..),++ -- * Wrapped selectors+ selTy, selsTy,+ selReplicate,+ selTags,+ selElements,+ selsLength,+ sumTyCon,+ prodTyCon,+ prodDataCon,+ replicatePD_PrimVar,+ emptyPD_PrimVar,+ packByTagPD_PrimVar,+ combinePDVar,+ combinePD_PrimVar,+ scalarZip,+ closureCtrFun,++ -- * Initialisation+ initBuiltins, initBuiltinVars,+) where++import Vectorise.Builtins.Base+import Vectorise.Builtins.Initialise
+ vectorise/Vectorise/Builtins/Base.hs view
@@ -0,0 +1,217 @@+-- |Builtin types and functions used by the vectoriser. These are all defined in+-- 'Data.Array.Parallel.Prim'.++module Vectorise.Builtins.Base (+ -- * Hard config+ mAX_DPH_PROD,+ mAX_DPH_SUM,+ mAX_DPH_COMBINE,+ mAX_DPH_SCALAR_ARGS,+ aLL_DPH_PRIM_TYCONS,++ -- * Builtins+ Builtins(..),++ -- * Projections+ selTy, selsTy,+ selReplicate,+ selTags,+ selElements,+ selsLength,+ sumTyCon,+ prodTyCon,+ prodDataCon,+ replicatePD_PrimVar,+ emptyPD_PrimVar,+ packByTagPD_PrimVar,+ combinePDVar,+ combinePD_PrimVar,+ scalarZip,+ closureCtrFun+) where++import TysPrim+import BasicTypes+import Class+import CoreSyn+import TysWiredIn hiding (sumTyCon)+import Type+import TyCon+import DataCon+import NameEnv+import Name+import Outputable++import Data.Array+++-- Cardinality of the various families of types and functions exported by the DPH library.++mAX_DPH_PROD :: Int+mAX_DPH_PROD = 5++mAX_DPH_SUM :: Int+mAX_DPH_SUM = 2++mAX_DPH_COMBINE :: Int+mAX_DPH_COMBINE = 2++mAX_DPH_SCALAR_ARGS :: Int+mAX_DPH_SCALAR_ARGS = 8++-- Types from 'GHC.Prim' supported by DPH+--+aLL_DPH_PRIM_TYCONS :: [Name]+aLL_DPH_PRIM_TYCONS = map tyConName [intPrimTyCon, {- floatPrimTyCon, -} doublePrimTyCon]+++-- |Holds the names of the types and functions from 'Data.Array.Parallel.Prim' that are used by the+-- vectoriser.+--+data Builtins+ = Builtins+ { parrayTyCon :: TyCon -- ^ PArray+ , pdataTyCon :: TyCon -- ^ PData+ , pdatasTyCon :: TyCon -- ^ PDatas+ , prClass :: Class -- ^ PR+ , prTyCon :: TyCon -- ^ PR+ , preprTyCon :: TyCon -- ^ PRepr+ , paClass :: Class -- ^ PA+ , paTyCon :: TyCon -- ^ PA+ , paDataCon :: DataCon -- ^ PA+ , paPRSel :: Var -- ^ PA+ , replicatePDVar :: Var -- ^ replicatePD+ , replicatePD_PrimVars :: NameEnv Var -- ^ replicatePD_Int# etc.+ , emptyPDVar :: Var -- ^ emptyPD+ , emptyPD_PrimVars :: NameEnv Var -- ^ emptyPD_Int# etc.+ , packByTagPDVar :: Var -- ^ packByTagPD+ , packByTagPD_PrimVars :: NameEnv Var -- ^ packByTagPD_Int# etc.+ , combinePDVars :: Array Int Var -- ^ combinePD+ , combinePD_PrimVarss :: Array Int (NameEnv Var) -- ^ combine2PD_Int# etc.+ , scalarClass :: Class -- ^ Scalar+ , scalarZips :: Array Int Var -- ^ map, zipWith, zipWith3+ , voidTyCon :: TyCon -- ^ Void+ , voidVar :: Var -- ^ void+ , fromVoidVar :: Var -- ^ fromVoid+ , sumTyCons :: Array Int TyCon -- ^ Sum2 .. Sum3+ , wrapTyCon :: TyCon -- ^ Wrap+ , pvoidVar :: Var -- ^ pvoid+ , pvoidsVar :: Var -- ^ pvoids+ , closureTyCon :: TyCon -- ^ :->+ , closureVar :: Var -- ^ closure+ , liftedClosureVar :: Var -- ^ liftedClosure+ , applyVar :: Var -- ^ $:+ , liftedApplyVar :: Var -- ^ liftedApply+ , closureCtrFuns :: Array Int Var -- ^ closure1 .. closure3+ , selTys :: Array Int Type -- ^ Sel2+ , selsTys :: Array Int Type -- ^ Sels2+ , selsLengths :: Array Int CoreExpr -- ^ lengthSels2+ , selReplicates :: Array Int CoreExpr -- ^ replicate2+ , selTagss :: Array Int CoreExpr -- ^ tagsSel2+ , selElementss :: Array (Int, Int) CoreExpr -- ^ elementsSel2_0 .. elementsSel_2_1+ , liftingContext :: Var -- ^ lc+ }+++-- Projections ----------------------------------------------------------------+-- We use these wrappers instead of indexing the `Builtin` structure directly+-- because they give nicer panic messages if the indexed thing cannot be found.++selTy :: Int -> Builtins -> Type+selTy = indexBuiltin "selTy" selTys++selsTy :: Int -> Builtins -> Type+selsTy = indexBuiltin "selsTy" selsTys++selsLength :: Int -> Builtins -> CoreExpr+selsLength = indexBuiltin "selLength" selsLengths++selReplicate :: Int -> Builtins -> CoreExpr+selReplicate = indexBuiltin "selReplicate" selReplicates++selTags :: Int -> Builtins -> CoreExpr+selTags = indexBuiltin "selTags" selTagss++selElements :: Int -> Int -> Builtins -> CoreExpr+selElements i j = indexBuiltin "selElements" selElementss (i, j)++sumTyCon :: Int -> Builtins -> TyCon+sumTyCon = indexBuiltin "sumTyCon" sumTyCons++prodTyCon :: Int -> Builtins -> TyCon+prodTyCon n _+ | n >= 2 && n <= mAX_DPH_PROD+ = tupleTyCon Boxed n+ | otherwise+ = pprPanic "prodTyCon" (ppr n)++prodDataCon :: Int -> Builtins -> DataCon+prodDataCon n bi+ = case tyConDataCons (prodTyCon n bi) of+ [con] -> con+ _ -> pprPanic "prodDataCon" (ppr n)++replicatePD_PrimVar :: TyCon -> Builtins -> Var+replicatePD_PrimVar tc bi+ = lookupEnvBuiltin "replicatePD_PrimVar" (replicatePD_PrimVars bi) (tyConName tc)++emptyPD_PrimVar :: TyCon -> Builtins -> Var+emptyPD_PrimVar tc bi+ = lookupEnvBuiltin "emptyPD_PrimVar" (emptyPD_PrimVars bi) (tyConName tc)++packByTagPD_PrimVar :: TyCon -> Builtins -> Var+packByTagPD_PrimVar tc bi+ = lookupEnvBuiltin "packByTagPD_PrimVar" (packByTagPD_PrimVars bi) (tyConName tc)++combinePDVar :: Int -> Builtins -> Var+combinePDVar = indexBuiltin "combinePDVar" combinePDVars++combinePD_PrimVar :: Int -> TyCon -> Builtins -> Var+combinePD_PrimVar i tc bi+ = lookupEnvBuiltin "combinePD_PrimVar"+ (indexBuiltin "combinePD_PrimVar" combinePD_PrimVarss i bi) (tyConName tc)++scalarZip :: Int -> Builtins -> Var+scalarZip = indexBuiltin "scalarZip" scalarZips++closureCtrFun :: Int -> Builtins -> Var+closureCtrFun = indexBuiltin "closureCtrFun" closureCtrFuns++-- | Get an element from one of the arrays of `Builtins`.+-- Panic if the indexed thing is not in the array.+indexBuiltin :: (Ix i, Outputable i)+ => String -- ^ Name of the selector we've used, for panic messages.+ -> (Builtins -> Array i a) -- ^ Field selector for the `Builtins`.+ -> i -- ^ Index into the array.+ -> Builtins+ -> a+indexBuiltin fn f i bi+ | inRange (bounds xs) i = xs ! i+ | otherwise+ = pprSorry "Vectorise.Builtins.indexBuiltin"+ (vcat [ text ""+ , text "DPH builtin function '" <> text fn <> text "' of size '" <> ppr i <>+ text "' is not yet implemented."+ , text "This function does not appear in your source program, but it is needed"+ , text "to compile your code in the backend. This is a known, current limitation"+ , text "of DPH. If you want it to work, you should send mail to ghc-commits@haskell.org"+ , text "and ask what you can do to help (it might involve some GHC hacking)."])+ where xs = f bi+++-- | Get an entry from one of a 'NameEnv' of `Builtins`. Panic if the named item is not in the array.+lookupEnvBuiltin :: String -- Function name for error messages+ -> NameEnv a -- Name environment+ -> Name -- Index into the name environment+ -> a+lookupEnvBuiltin fn env n+ | Just r <- lookupNameEnv env n = r+ | otherwise+ = pprSorry "Vectorise.Builtins.lookupEnvBuiltin"+ (vcat [ text ""+ , text "DPH builtin function '" <> text fn <> text "_" <> ppr n <>+ text "' is not yet implemented."+ , text "This function does not appear in your source program, but it is needed"+ , text "to compile your code in the backend. This is a known, current limitation"+ , text "of DPH. If you want it to work, you should send mail to ghc-commits@haskell.org"+ , text "and ask what you can do to help (it might involve some GHC hacking)."])
+ vectorise/Vectorise/Builtins/Initialise.hs view
@@ -0,0 +1,232 @@+-- Set up the data structures provided by 'Vectorise.Builtins'.++module Vectorise.Builtins.Initialise (+ -- * Initialisation+ initBuiltins, initBuiltinVars+) where++import Vectorise.Builtins.Base++import BasicTypes+import TysPrim+import DsMonad+import TysWiredIn+import DataCon+import TyCon+import Class+import CoreSyn+import Type+import NameEnv+import Name+import Id+import FastString+import Outputable++import Control.Monad+import Data.Array+++-- |Create the initial map of builtin types and functions.+--+initBuiltins :: DsM Builtins+initBuiltins+ = do { -- 'PArray: representation type for parallel arrays+ ; parrayTyCon <- externalTyCon (fsLit "PArray")++ -- 'PData': type family mapping array element types to array representation types+ -- Not all backends use `PDatas`.+ ; pdataTyCon <- externalTyCon (fsLit "PData")+ ; pdatasTyCon <- externalTyCon (fsLit "PDatas")++ -- 'PR': class of basic array operators operating on 'PData' types+ ; prClass <- externalClass (fsLit "PR")+ ; let prTyCon = classTyCon prClass++ -- 'PRepr': type family mapping element types to representation types+ ; preprTyCon <- externalTyCon (fsLit "PRepr")++ -- 'PA': class of basic operations on arrays (parametrised by the element type)+ ; paClass <- externalClass (fsLit "PA")+ ; let paTyCon = classTyCon paClass+ [paDataCon] = tyConDataCons paTyCon+ paPRSel = classSCSelId paClass 0++ -- Functions on array representations+ ; replicatePDVar <- externalVar (fsLit "replicatePD")+ ; replicate_vars <- mapM externalVar (suffixed "replicatePA" aLL_DPH_PRIM_TYCONS)+ ; emptyPDVar <- externalVar (fsLit "emptyPD")+ ; empty_vars <- mapM externalVar (suffixed "emptyPA" aLL_DPH_PRIM_TYCONS)+ ; packByTagPDVar <- externalVar (fsLit "packByTagPD")+ ; packByTag_vars <- mapM externalVar (suffixed "packByTagPA" aLL_DPH_PRIM_TYCONS)+ ; let combineNamesD = [("combine" ++ show i ++ "PD") | i <- [2..mAX_DPH_COMBINE]]+ ; let combineNamesA = [("combine" ++ show i ++ "PA") | i <- [2..mAX_DPH_COMBINE]]+ ; combines <- mapM externalVar (map mkFastString combineNamesD)+ ; combines_vars <- mapM (mapM externalVar) $+ map (\name -> suffixed name aLL_DPH_PRIM_TYCONS) combineNamesA+ ; let replicatePD_PrimVars = mkNameEnv (zip aLL_DPH_PRIM_TYCONS replicate_vars)+ emptyPD_PrimVars = mkNameEnv (zip aLL_DPH_PRIM_TYCONS empty_vars)+ packByTagPD_PrimVars = mkNameEnv (zip aLL_DPH_PRIM_TYCONS packByTag_vars)+ combinePDVars = listArray (2, mAX_DPH_COMBINE) combines+ combinePD_PrimVarss = listArray (2, mAX_DPH_COMBINE)+ [ mkNameEnv (zip aLL_DPH_PRIM_TYCONS vars)+ | vars <- combines_vars]++ -- 'Scalar': class moving between plain unboxed arrays and 'PData' representations+ ; scalarClass <- externalClass (fsLit "Scalar")++ -- N-ary maps ('zipWith' family)+ ; scalar_map <- externalVar (fsLit "scalar_map")+ ; scalar_zip2 <- externalVar (fsLit "scalar_zipWith")+ ; scalar_zips <- mapM externalVar (numbered "scalar_zipWith" 3 mAX_DPH_SCALAR_ARGS)+ ; let scalarZips = listArray (1, mAX_DPH_SCALAR_ARGS)+ (scalar_map : scalar_zip2 : scalar_zips)++ -- Types and functions for generic type representations+ ; voidTyCon <- externalTyCon (fsLit "Void")+ ; voidVar <- externalVar (fsLit "void")+ ; fromVoidVar <- externalVar (fsLit "fromVoid")+ ; sum_tcs <- mapM externalTyCon (numbered "Sum" 2 mAX_DPH_SUM)+ ; let sumTyCons = listArray (2, mAX_DPH_SUM) sum_tcs+ ; wrapTyCon <- externalTyCon (fsLit "Wrap")+ ; pvoidVar <- externalVar (fsLit "pvoid")+ ; pvoidsVar <- externalVar (fsLit "pvoids#")++ -- Types and functions for closure conversion+ ; closureTyCon <- externalTyCon (fsLit ":->")+ ; closureVar <- externalVar (fsLit "closure")+ ; liftedClosureVar <- externalVar (fsLit "liftedClosure")+ ; applyVar <- externalVar (fsLit "$:")+ ; liftedApplyVar <- externalVar (fsLit "liftedApply")+ ; closures <- mapM externalVar (numbered "closure" 1 mAX_DPH_SCALAR_ARGS)+ ; let closureCtrFuns = listArray (1, mAX_DPH_SCALAR_ARGS) closures++ -- Types and functions for selectors+ ; sel_tys <- mapM externalType (numbered "Sel" 2 mAX_DPH_SUM)+ ; sels_tys <- mapM externalType (numbered "Sels" 2 mAX_DPH_SUM)+ ; sels_length <- mapM externalFun (numbered_hash "lengthSels" 2 mAX_DPH_SUM)+ ; sel_replicates <- mapM externalFun (numbered_hash "replicateSel" 2 mAX_DPH_SUM)+ ; sel_tags <- mapM externalFun (numbered "tagsSel" 2 mAX_DPH_SUM)+ ; sel_elements <- mapM mk_elements [(i,j) | i <- [2..mAX_DPH_SUM], j <- [0..i-1]]+ ; let selTys = listArray (2, mAX_DPH_SUM) sel_tys+ selsTys = listArray (2, mAX_DPH_SUM) sels_tys+ selsLengths = listArray (2, mAX_DPH_SUM) sels_length+ selReplicates = listArray (2, mAX_DPH_SUM) sel_replicates+ selTagss = listArray (2, mAX_DPH_SUM) sel_tags+ selElementss = array ((2, 0), (mAX_DPH_SUM, mAX_DPH_SUM)) sel_elements++ -- Distinct local variable+ ; liftingContext <- liftM (\u -> mkSysLocalOrCoVar (fsLit "lc") u intPrimTy) newUnique++ ; return $ Builtins+ { parrayTyCon = parrayTyCon+ , pdataTyCon = pdataTyCon+ , pdatasTyCon = pdatasTyCon+ , preprTyCon = preprTyCon+ , prClass = prClass+ , prTyCon = prTyCon+ , paClass = paClass+ , paTyCon = paTyCon+ , paDataCon = paDataCon+ , paPRSel = paPRSel+ , replicatePDVar = replicatePDVar+ , replicatePD_PrimVars = replicatePD_PrimVars+ , emptyPDVar = emptyPDVar+ , emptyPD_PrimVars = emptyPD_PrimVars+ , packByTagPDVar = packByTagPDVar+ , packByTagPD_PrimVars = packByTagPD_PrimVars+ , combinePDVars = combinePDVars+ , combinePD_PrimVarss = combinePD_PrimVarss+ , scalarClass = scalarClass+ , scalarZips = scalarZips+ , voidTyCon = voidTyCon+ , voidVar = voidVar+ , fromVoidVar = fromVoidVar+ , sumTyCons = sumTyCons+ , wrapTyCon = wrapTyCon+ , pvoidVar = pvoidVar+ , pvoidsVar = pvoidsVar+ , closureTyCon = closureTyCon+ , closureVar = closureVar+ , liftedClosureVar = liftedClosureVar+ , applyVar = applyVar+ , liftedApplyVar = liftedApplyVar+ , closureCtrFuns = closureCtrFuns+ , selTys = selTys+ , selsTys = selsTys+ , selsLengths = selsLengths+ , selReplicates = selReplicates+ , selTagss = selTagss+ , selElementss = selElementss+ , liftingContext = liftingContext+ }+ }+ where+ suffixed :: String -> [Name] -> [FastString]+ suffixed pfx ns = [mkFastString (pfx ++ "_" ++ (occNameString . nameOccName) n) | n <- ns]++ -- Make a list of numbered strings in some range, eg foo3, foo4, foo5+ numbered :: String -> Int -> Int -> [FastString]+ numbered pfx m n = [mkFastString (pfx ++ show i) | i <- [m..n]]++ numbered_hash :: String -> Int -> Int -> [FastString]+ numbered_hash pfx m n = [mkFastString (pfx ++ show i ++ "#") | i <- [m..n]]++ mk_elements :: (Int, Int) -> DsM ((Int, Int), CoreExpr)+ mk_elements (i,j)+ = do { v <- externalVar $ mkFastString ("elementsSel" ++ show i ++ "_" ++ show j ++ "#")+ ; return ((i, j), Var v)+ }++-- |Get the mapping of names in the Prelude to names in the DPH library.+--+initBuiltinVars :: Builtins -> DsM [(Var, Var)]+-- FIXME: must be replaced by VECTORISE pragmas!!!+initBuiltinVars (Builtins { })+ = do+ cvars <- mapM externalVar cfs+ return $ zip (map dataConWorkId cons) cvars+ where+ (cons, cfs) = unzip preludeDataCons++ preludeDataCons :: [(DataCon, FastString)]+ preludeDataCons+ = [mk_tup n (mkFastString $ "tup" ++ show n) | n <- [2..5]]+ where+ mk_tup n name = (tupleDataCon Boxed n, name)+++-- Auxiliary look up functions -----------------------------------------------++-- |Lookup a variable given its name and the module that contains it.+externalVar :: FastString -> DsM Var+externalVar fs = dsLookupDPHRdrEnv (mkVarOccFS fs) >>= dsLookupGlobalId+++-- |Like `externalVar` but wrap the `Var` in a `CoreExpr`.+externalFun :: FastString -> DsM CoreExpr+externalFun fs = Var <$> externalVar fs+++-- |Lookup a 'TyCon' in 'Data.Array.Parallel.Prim', given its name.+-- Panic if there isn't one.+externalTyCon :: FastString -> DsM TyCon+externalTyCon fs = dsLookupDPHRdrEnv (mkTcOccFS fs) >>= dsLookupTyCon+++-- |Lookup some `Type` in 'Data.Array.Parallel.Prim', given its name.+externalType :: FastString -> DsM Type+externalType fs+ = do tycon <- externalTyCon fs+ return $ mkTyConApp tycon []+++-- |Lookup a 'Class' in 'Data.Array.Parallel.Prim', given its name.+externalClass :: FastString -> DsM Class+externalClass fs+ = do { tycon <- dsLookupDPHRdrEnv (mkClsOccFS fs) >>= dsLookupTyCon+ ; case tyConClass_maybe tycon of+ Nothing -> pprPanic "Vectorise.Builtins.Initialise" $+ text "Data.Array.Parallel.Prim." <>+ ftext fs <+> text "is not a type class"+ Just cls -> return cls+ }
+ vectorise/Vectorise/Convert.hs view
@@ -0,0 +1,105 @@+module Vectorise.Convert+ ( fromVect+ )+where++import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Type.Type++import CoreSyn+import TyCon+import Type+import TyCoRep+import NameSet+import FastString+import Outputable++import Control.Applicative+import Prelude -- avoid redundant import warning due to AMP++-- |Convert a vectorised expression such that it computes the non-vectorised equivalent of its+-- value.+--+-- For functions, we eta expand the function and convert the arguments and result:++-- For example+-- @+-- \(x :: Double) ->+-- \(y :: Double) ->+-- ($v_foo $: x) $: y+-- @+--+-- We use the type of the original binding to work out how many outer lambdas to add.+--+fromVect :: Type -- ^ The type of the original binding.+ -> CoreExpr -- ^ Expression giving the closure to use, eg @$v_foo@.+ -> VM CoreExpr++-- Convert the type to the core view if it isn't already.+--+fromVect ty expr+ | Just ty' <- coreView ty+ = fromVect ty' expr++-- For each function constructor in the original type we add an outer+-- lambda to bind the parameter variable, and an inner application of it.+fromVect (FunTy arg_ty res_ty) expr+ = do+ arg <- newLocalVar (fsLit "x") arg_ty+ varg <- toVect arg_ty (Var arg)+ varg_ty <- vectType arg_ty+ vres_ty <- vectType res_ty+ apply <- builtin applyVar+ body <- fromVect res_ty+ $ Var apply `mkTyApps` [varg_ty, vres_ty] `mkApps` [expr, varg]+ return $ Lam arg body++-- If the type isn't a function, then we can't current convert it unless the type is scalar (i.e.,+-- is identical to the non-vectorised version).+--+fromVect ty expr+ = identityConv ty >> return expr++-- Convert an expression such that it evaluates to the vectorised equivalent of the value of the+-- original expression.+--+-- WARNING: Currently only works for the scalar types, where the vectorised value coincides with the+-- original one.+--+toVect :: Type -> CoreExpr -> VM CoreExpr+toVect ty expr = identityConv ty >> return expr++-- |Check that the type is neutral under type vectorisation — i.e., all involved type constructor+-- are not altered by vectorisation as they contain no parallel arrays.+--+identityConv :: Type -> VM ()+identityConv ty+ | Just ty' <- coreView ty+ = identityConv ty'+identityConv (TyConApp tycon tys)+ = do { mapM_ identityConv tys+ ; identityConvTyCon tycon+ }+identityConv (LitTy {}) = noV $ text "identityConv: not sure about literal types under vectorisation"+identityConv (TyVarTy {}) = noV $ text "identityConv: type variable changes under vectorisation"+identityConv (AppTy {}) = noV $ text "identityConv: type appl. changes under vectorisation"+identityConv (FunTy {}) = noV $ text "identityConv: function type changes under vectorisation"+identityConv (ForAllTy {}) = noV $ text "identityConv: quantified type changes under vectorisation"+identityConv (CastTy {}) = noV $ text "identityConv: not sure about casted types under vectorisation"+identityConv (CoercionTy {}) = noV $ text "identityConv: not sure about coercions under vectorisation"++-- |Check that this type constructor is not changed by vectorisation — i.e., it does not embed any+-- parallel arrays.+--+identityConvTyCon :: TyCon -> VM ()+identityConvTyCon tc+ = do+ { isParallel <- (tyConName tc `elemNameSet`) <$> globalParallelTyCons+ ; parray <- builtin parrayTyCon+ ; if isParallel && not (tc == parray)+ then noV idErr+ else return ()+ }+ where+ idErr = text "identityConvTyCon: type constructor contains parallel arrays" <+> ppr tc
+ vectorise/Vectorise/Env.hs view
@@ -0,0 +1,238 @@+module Vectorise.Env (+ Scope(..),++ -- * Local Environments+ LocalEnv(..),+ emptyLocalEnv,++ -- * Global Environments+ GlobalEnv(..),+ initGlobalEnv,+ extendImportedVarsEnv,+ extendFamEnv,+ setPAFunsEnv,+ setPRFunsEnv,+ modVectInfo+) where++import HscTypes+import InstEnv+import FamInstEnv+import CoreSyn+import Type+import Class+import TyCon+import DataCon+import VarEnv+import VarSet+import Var+import NameSet+import Name+import NameEnv+import FastString+import UniqDFM+import UniqSet+++import Data.Maybe+++-- |Indicates what scope something (a variable) is in.+--+data Scope a b+ = Global a+ | Local b+++-- LocalEnv -------------------------------------------------------------------++-- |The local environment.+--+data LocalEnv+ = LocalEnv+ { local_vars :: VarEnv (Var, Var)+ -- ^Mapping from local variables to their vectorised and lifted versions.++ , local_tyvars :: [TyVar]+ -- ^In-scope type variables.++ , local_tyvar_pa :: VarEnv CoreExpr+ -- ^Mapping from tyvars to their PA dictionaries.++ , local_bind_name :: FastString+ -- ^Local binding name. This is only used to generate better names for hoisted+ -- expressions.+ }++-- |Create an empty local environment.+--+emptyLocalEnv :: LocalEnv+emptyLocalEnv = LocalEnv+ { local_vars = emptyVarEnv+ , local_tyvars = []+ , local_tyvar_pa = emptyVarEnv+ , local_bind_name = fsLit "fn"+ }+++-- GlobalEnv ------------------------------------------------------------------++-- |The global environment: entities that exist at top-level.+--+data GlobalEnv+ = GlobalEnv+ { global_vect_avoid :: Bool+ -- ^'True' implies to avoid vectorisation as far as possible.++ , global_vars :: VarEnv Var+ -- ^Mapping from global variables to their vectorised versions — aka the /vectorisation+ -- map/.++ , global_parallel_vars :: DVarSet+ -- ^The domain of 'global_vars'.+ --+ -- This information is not redundant as it is impossible to extract the domain from a+ -- 'VarEnv' (which is keyed on uniques alone). Moreover, we have mapped variables that+ -- do not involve parallelism — e.g., the workers of vectorised, but scalar data types.+ -- In addition, workers of parallel data types that we could not vectorise also need to+ -- be tracked.++ , global_vect_decls :: VarEnv (Maybe (Type, CoreExpr))+ -- ^Mapping from global variables that have a vectorisation declaration to the right-hand+ -- side of that declaration and its type and mapping variables that have NOVECTORISE+ -- declarations to 'Nothing'.++ , global_tycons :: NameEnv TyCon+ -- ^Mapping from TyCons to their vectorised versions. The vectorised version will be+ -- identical to the original version if it is not changed by vectorisation. In any case,+ -- if a tycon appears in the domain of this mapping, it was successfully vectorised.++ , global_parallel_tycons :: NameSet+ -- ^Type constructors whose definition directly or indirectly includes a parallel type,+ -- such as '[::]'.+ --+ -- NB: This information is not redundant as some types have got a mapping in+ -- 'global_tycons' (to a type other than themselves) and are still not parallel. An+ -- example is '(->)'. Moreover, some types have *not* got a mapping in 'global_tycons'+ -- (because they couldn't be vectorised), but still contain parallel types.++ , global_datacons :: NameEnv DataCon+ -- ^Mapping from DataCons to their vectorised versions.++ , global_pa_funs :: NameEnv Var+ -- ^Mapping from TyCons to their PA dfuns.++ , global_pr_funs :: NameEnv Var+ -- ^Mapping from TyCons to their PR dfuns.++ , global_inst_env :: InstEnvs+ -- ^External package inst-env & home-package inst-env for class instances.++ , global_fam_inst_env :: FamInstEnvs+ -- ^External package inst-env & home-package inst-env for family instances.++ , global_bindings :: [(Var, CoreExpr)]+ -- ^Hoisted bindings — temporary storage for toplevel bindings during code gen.+ }++-- |Create an initial global environment.+--+-- We add scalar variables and type constructors identified by vectorisation pragmas already here+-- to the global table, so that we can query scalarness during vectorisation, and especially, when+-- vectorising the scalar entities' definitions themselves.+--+initGlobalEnv :: Bool+ -> VectInfo+ -> [CoreVect]+ -> InstEnvs+ -> FamInstEnvs+ -> GlobalEnv+initGlobalEnv vectAvoid info vectDecls instEnvs famInstEnvs+ = GlobalEnv+ { global_vect_avoid = vectAvoid+ , global_vars = mapVarEnv snd $ udfmToUfm $ vectInfoVar info+ , global_vect_decls = mkVarEnv vects+ , global_parallel_vars = vectInfoParallelVars info+ , global_parallel_tycons = vectInfoParallelTyCons info+ , global_tycons = mapNameEnv snd $ vectInfoTyCon info+ , global_datacons = mapNameEnv snd $ vectInfoDataCon info+ , global_pa_funs = emptyNameEnv+ , global_pr_funs = emptyNameEnv+ , global_inst_env = instEnvs+ , global_fam_inst_env = famInstEnvs+ , global_bindings = []+ }+ where+ vects = [(var, Just (ty, exp)) | Vect var exp@(Var rhs_var) <- vectDecls+ , let ty = varType rhs_var] +++ -- FIXME: we currently only allow RHSes consisting of a+ -- single variable to be able to obtain the type without+ -- inference — see also 'TcBinds.tcVect'+ [(var, Nothing) | NoVect var <- vectDecls]+++-- Operators on Global Environments -------------------------------------------++-- |Extend the list of global variables in an environment.+--+extendImportedVarsEnv :: [(Var, Var)] -> GlobalEnv -> GlobalEnv+extendImportedVarsEnv ps genv+ = genv { global_vars = extendVarEnvList (global_vars genv) ps }++-- |Extend the list of type family instances.+--+extendFamEnv :: [FamInst] -> GlobalEnv -> GlobalEnv+extendFamEnv new genv+ = genv { global_fam_inst_env = (g_fam_inst, extendFamInstEnvList l_fam_inst new) }+ where (g_fam_inst, l_fam_inst) = global_fam_inst_env genv++-- |Set the list of PA functions in an environment.+--+setPAFunsEnv :: [(Name, Var)] -> GlobalEnv -> GlobalEnv+setPAFunsEnv ps genv = genv { global_pa_funs = mkNameEnv ps }++-- |Set the list of PR functions in an environment.+--+setPRFunsEnv :: [(Name, Var)] -> GlobalEnv -> GlobalEnv+setPRFunsEnv ps genv = genv { global_pr_funs = mkNameEnv ps }++-- |Compute vectorisation information that goes into 'ModGuts' (and is stored in interface files).+-- The incoming 'vectInfo' is that from the 'HscEnv' and 'EPS'. The outgoing one contains only the+-- declarations for the currently compiled module; this includes variables, type constructors, and+-- data constructors referenced in VECTORISE pragmas, even if they are defined in an imported+-- module.+--+-- The variables explicitly include class selectors and dfuns.+--+modVectInfo :: GlobalEnv -> [Id] -> [TyCon] -> [CoreVect]-> VectInfo -> VectInfo+modVectInfo env mg_ids mg_tyCons vectDecls info+ = info+ { vectInfoVar = mk_denv ids (global_vars env)+ , vectInfoTyCon = mk_env tyCons (global_tycons env)+ , vectInfoDataCon = mk_env dataCons (global_datacons env)+ , vectInfoParallelVars = (global_parallel_vars env `minusDVarSet` vectInfoParallelVars info)+ `udfmIntersectUFM` (getUniqSet $ mkVarSet ids)+ , vectInfoParallelTyCons = global_parallel_tycons env `minusNameSet` vectInfoParallelTyCons info+ }+ where+ vectIds = [id | Vect id _ <- vectDecls] +++ [id | VectInst id <- vectDecls]+ vectTypeTyCons = [tycon | VectType _ tycon _ <- vectDecls] +++ [tycon | VectClass tycon <- vectDecls]+ vectDataCons = concatMap tyConDataCons vectTypeTyCons+ ids = mg_ids ++ vectIds ++ dataConIds ++ selIds+ tyCons = mg_tyCons ++ vectTypeTyCons+ dataCons = concatMap tyConDataCons mg_tyCons ++ vectDataCons+ dataConIds = map dataConWorkId dataCons+ selIds = concat [ classAllSelIds cls+ | tycon <- tyCons+ , cls <- maybeToList . tyConClass_maybe $ tycon]++ -- Produce an entry for every declaration that is mentioned in the domain of the 'inspectedEnv'+ mk_env decls inspectedEnv = mkNameEnv $ mk_assoc_env decls inspectedEnv+ mk_denv decls inspectedEnv = listToUDFM $ mk_assoc_env decls inspectedEnv+ mk_assoc_env decls inspectedEnv+ = [(name, (decl, to))+ | decl <- decls+ , let name = getName decl+ , Just to <- [lookupNameEnv inspectedEnv name]]
+ vectorise/Vectorise/Exp.hs view
@@ -0,0 +1,1257 @@+{-# LANGUAGE CPP, TupleSections #-}++-- |Vectorisation of expressions.++module Vectorise.Exp+ ( -- * Vectorise right-hand sides of toplevel bindings+ vectTopExpr+ , vectTopExprs+ , vectScalarFun+ , vectScalarDFun+ )+where++#include "HsVersions.h"++import Vectorise.Type.Type+import Vectorise.Var+import Vectorise.Convert+import Vectorise.Vect+import Vectorise.Env+import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Utils++import CoreUtils+import MkCore+import CoreSyn+import CoreFVs+import Class+import DataCon+import TyCon+import TcType+import Type+import TyCoRep+import Var+import VarEnv+import VarSet+import NameSet+import Id+import BasicTypes( isStrongLoopBreaker )+import Literal+import TysPrim+import Outputable+import FastString+import DynFlags+import Util++import Control.Monad+import Data.Maybe+import Data.List+++-- Main entry point to vectorise expressions -----------------------------------++-- |Vectorise a polymorphic expression that forms a *non-recursive* binding.+--+-- Return 'Nothing' if the expression is scalar; otherwise, the first component of the result+-- (which is of type 'Bool') indicates whether the expression is parallel (i.e., whether it is+-- tagged as 'VIParr').+--+-- We have got the non-recursive case as a special case as it doesn't require to compute+-- vectorisation information twice.+--+vectTopExpr :: Var -> CoreExpr -> VM (Maybe (Bool, Inline, CoreExpr))+vectTopExpr var expr+ = do+ { exprVI <- encapsulateScalars <=< vectAvoidInfo emptyVarSet . freeVars $ expr+ ; if isVIEncaps exprVI+ then+ return Nothing+ else do+ { vExpr <- closedV $+ inBind var $+ vectAnnPolyExpr False exprVI+ ; inline <- computeInline exprVI+ ; return $ Just (isVIParr exprVI, inline, vectorised vExpr)+ }+ }++-- Compute the inlining hint for the right-hand side of a top-level binding.+--+computeInline :: CoreExprWithVectInfo -> VM Inline+computeInline ((_, VIDict), _) = return $ DontInline+computeInline (_, AnnTick _ expr) = computeInline expr+computeInline expr@(_, AnnLam _ _) = Inline <$> polyArity tvs+ where+ (tvs, _) = collectAnnTypeBinders expr+computeInline _expr = return $ DontInline++-- |Vectorise a recursive group of top-level polymorphic expressions.+--+-- Return 'Nothing' if the expression group is scalar; otherwise, the first component of the result+-- (which is of type 'Bool') indicates whether the expressions are parallel (i.e., whether they are+-- tagged as 'VIParr').+--+vectTopExprs :: [(Var, CoreExpr)] -> VM (Maybe (Bool, [(Inline, CoreExpr)]))+vectTopExprs binds+ = do+ { exprVIs <- mapM (vectAvoidAndEncapsulate emptyVarSet) exprs+ ; if all isVIEncaps exprVIs+ -- if all bindings are scalar => don't vectorise this group of bindings+ then return Nothing+ else do+ { -- non-scalar bindings need to be vectorised+ ; let areVIParr = any isVIParr exprVIs+ ; revised_exprVIs <- if not areVIParr+ -- if no binding is parallel => 'exprVIs' is ready for vectorisation+ then return exprVIs+ -- if any binding is parallel => recompute the vectorisation info+ else mapM (vectAvoidAndEncapsulate (mkVarSet vars)) exprs++ ; vExprs <- zipWithM vect vars revised_exprVIs+ ; return $ Just (areVIParr, vExprs)+ }+ }+ where+ (vars, exprs) = unzip binds++ vectAvoidAndEncapsulate pvs = encapsulateScalars <=< vectAvoidInfo pvs . freeVars++ vect var exprVI+ = do+ { vExpr <- closedV $+ inBind var $+ vectAnnPolyExpr (isStrongLoopBreaker $ idOccInfo var) exprVI+ ; inline <- computeInline exprVI+ ; return (inline, vectorised vExpr)+ }++-- |Vectorise a polymorphic expression annotated with vectorisation information.+--+-- The special case of dictionary functions is currently handled separately. (Would be neater to+-- integrate them, though!)+--+vectAnnPolyExpr :: Bool -> CoreExprWithVectInfo -> VM VExpr+vectAnnPolyExpr loop_breaker (_, AnnTick tickish expr)+ -- traverse through ticks+ = vTick tickish <$> vectAnnPolyExpr loop_breaker expr+vectAnnPolyExpr loop_breaker expr+ | isVIDict expr+ -- special case the right-hand side of dictionary functions+ = (, undefined) <$> vectDictExpr (deAnnotate expr)+ | otherwise+ -- collect and vectorise type abstractions; then, descent into the body+ = polyAbstract tvs $ \args ->+ mapVect (mkLams $ tvs ++ args) <$> vectFnExpr False loop_breaker mono+ where+ (tvs, mono) = collectAnnTypeBinders expr++-- Encapsulate every purely sequential subexpression of a (potentially) parallel expression into a+-- lambda abstraction over all its free variables followed by the corresponding application to those+-- variables. We can, then, avoid the vectorisation of the ensapsulated subexpressions.+--+-- Preconditions:+--+-- * All free variables and the result type must be /simple/ types.+-- * The expression is sufficiently complex (to warrant special treatment). For now, that is+-- every expression that is not constant and contains at least one operation.+--+--+-- The user has an option to choose between aggressive and minimal vectorisation avoidance. With+-- minimal vectorisation avoidance, we only encapsulate individual scalar operations. With+-- aggressive vectorisation avoidance, we encapsulate subexpression that are as big as possible.+--+encapsulateScalars :: CoreExprWithVectInfo -> VM CoreExprWithVectInfo+encapsulateScalars ce@(_, AnnType _ty)+ = return ce+encapsulateScalars ce@((_, VISimple), AnnVar _v)+ -- NB: diverts from the paper: encapsulate scalar variables (including functions)+ = liftSimpleAndCase ce+encapsulateScalars ce@(_, AnnVar _v)+ = return ce+encapsulateScalars ce@(_, AnnLit _)+ = return ce+encapsulateScalars ((fvs, vi), AnnTick tck expr)+ = do+ { encExpr <- encapsulateScalars expr+ ; return ((fvs, vi), AnnTick tck encExpr)+ }+encapsulateScalars ce@((fvs, vi), AnnLam bndr expr)+ = do+ { vectAvoid <- isVectAvoidanceAggressive+ ; varsS <- allScalarVarTypeSet fvs+ -- NB: diverts from the paper: we need to check the scalarness of bound variables as well,+ -- as 'vectScalarFun' will handle them just the same as those introduced for the 'fvs'+ -- by encapsulation.+ ; bndrsS <- allScalarVarType bndrs+ ; case (vi, vectAvoid && varsS && bndrsS) of+ (VISimple, True) -> liftSimpleAndCase ce+ _ -> do+ { encExpr <- encapsulateScalars expr+ ; return ((fvs, vi), AnnLam bndr encExpr)+ }+ }+ where+ (bndrs, _) = collectAnnBndrs ce+encapsulateScalars ce@((fvs, vi), AnnApp ce1 ce2)+ = do+ { vectAvoid <- isVectAvoidanceAggressive+ ; varsS <- allScalarVarTypeSet fvs+ ; case (vi, (vectAvoid || isSimpleApplication ce) && varsS) of+ (VISimple, True) -> liftSimpleAndCase ce+ _ -> do+ { encCe1 <- encapsulateScalars ce1+ ; encCe2 <- encapsulateScalars ce2+ ; return ((fvs, vi), AnnApp encCe1 encCe2)+ }+ }+ where+ isSimpleApplication :: CoreExprWithVectInfo -> Bool+ isSimpleApplication (_, AnnTick _ ce) = isSimpleApplication ce+ isSimpleApplication (_, AnnCast ce _) = isSimpleApplication ce+ isSimpleApplication ce | isSimple ce = True+ isSimpleApplication (_, AnnApp ce1 ce2) = isSimple ce1 && isSimpleApplication ce2+ isSimpleApplication _ = False+ --+ isSimple :: CoreExprWithVectInfo -> Bool+ isSimple (_, AnnType {}) = True+ isSimple (_, AnnVar {}) = True+ isSimple (_, AnnLit {}) = True+ isSimple (_, AnnTick _ ce) = isSimple ce+ isSimple (_, AnnCast ce _) = isSimple ce+ isSimple _ = False+encapsulateScalars ce@((fvs, vi), AnnCase scrut bndr ty alts)+ = do+ { vectAvoid <- isVectAvoidanceAggressive+ ; varsS <- allScalarVarTypeSet fvs+ ; case (vi, vectAvoid && varsS) of+ (VISimple, True) -> liftSimpleAndCase ce+ _ -> do+ { encScrut <- encapsulateScalars scrut+ ; encAlts <- mapM encAlt alts+ ; return ((fvs, vi), AnnCase encScrut bndr ty encAlts)+ }+ }+ where+ encAlt (con, bndrs, expr) = (con, bndrs,) <$> encapsulateScalars expr+encapsulateScalars ce@((fvs, vi), AnnLet (AnnNonRec bndr expr1) expr2)+ = do+ { vectAvoid <- isVectAvoidanceAggressive+ ; varsS <- allScalarVarTypeSet fvs+ ; case (vi, vectAvoid && varsS) of+ (VISimple, True) -> liftSimpleAndCase ce+ _ -> do+ { encExpr1 <- encapsulateScalars expr1+ ; encExpr2 <- encapsulateScalars expr2+ ; return ((fvs, vi), AnnLet (AnnNonRec bndr encExpr1) encExpr2)+ }+ }+encapsulateScalars ce@((fvs, vi), AnnLet (AnnRec binds) expr)+ = do+ { vectAvoid <- isVectAvoidanceAggressive+ ; varsS <- allScalarVarTypeSet fvs+ ; case (vi, vectAvoid && varsS) of+ (VISimple, True) -> liftSimpleAndCase ce+ _ -> do+ { encBinds <- mapM encBind binds+ ; encExpr <- encapsulateScalars expr+ ; return ((fvs, vi), AnnLet (AnnRec encBinds) encExpr)+ }+ }+ where+ encBind (bndr, expr) = (bndr,) <$> encapsulateScalars expr+encapsulateScalars ((fvs, vi), AnnCast expr coercion)+ = do+ { encExpr <- encapsulateScalars expr+ ; return ((fvs, vi), AnnCast encExpr coercion)+ }+encapsulateScalars _+ = panic "Vectorise.Exp.encapsulateScalars: unknown constructor"++-- Lambda-lift the given simple expression and apply it to the abstracted free variables.+--+-- If the expression is a case expression scrutinising anything, but a scalar type, then lift+-- each alternative individually.+--+liftSimpleAndCase :: CoreExprWithVectInfo -> VM CoreExprWithVectInfo+liftSimpleAndCase aexpr@((fvs, _vi), AnnCase expr bndr t alts)+ = do+ { vi <- vectAvoidInfoTypeOf expr+ ; if (vi == VISimple)+ then+ liftSimple aexpr -- if the scrutinee is scalar, we need no special treatment+ else do+ { alts' <- mapM (\(ac, bndrs, aexpr) -> (ac, bndrs,) <$> liftSimpleAndCase aexpr) alts+ ; return ((fvs, vi), AnnCase expr bndr t alts')+ }+ }+liftSimpleAndCase aexpr = liftSimple aexpr++liftSimple :: CoreExprWithVectInfo -> VM CoreExprWithVectInfo+liftSimple ((fvs, vi), AnnVar v)+ | v `elemDVarSet` fvs -- special case to avoid producing: (\v -> v) v+ && not (isToplevel v) -- NB: if 'v' not free or is toplevel, we must get the 'VIEncaps'+ = return $ ((fvs, vi), AnnVar v)+liftSimple aexpr@((fvs_orig, VISimple), expr)+ = do+ { let liftedExpr = mkAnnApps (mkAnnLams (reverse vars) fvs expr) vars++ ; traceVt "encapsulate:" $ ppr (deAnnotate aexpr) $$ text "==>" $$ ppr (deAnnotate liftedExpr)++ ; return $ liftedExpr+ }+ where+ vars = dVarSetElems fvs+ fvs = filterDVarSet (not . isToplevel) fvs_orig -- only include 'Id's that are not toplevel++ mkAnnLams :: [Var] -> DVarSet -> AnnExpr' Var (DVarSet, VectAvoidInfo) -> CoreExprWithVectInfo+ mkAnnLams [] fvs expr = ASSERT(isEmptyDVarSet fvs)+ ((emptyDVarSet, VIEncaps), expr)+ mkAnnLams (v:vs) fvs expr = mkAnnLams vs (fvs `delDVarSet` v) (AnnLam v ((fvs, VIEncaps), expr))++ mkAnnApps :: CoreExprWithVectInfo -> [Var] -> CoreExprWithVectInfo+ mkAnnApps aexpr [] = aexpr+ mkAnnApps aexpr (v:vs) = mkAnnApps (mkAnnApp aexpr v) vs++ mkAnnApp :: CoreExprWithVectInfo -> Var -> CoreExprWithVectInfo+ mkAnnApp aexpr@((fvs, _vi), _expr) v+ = ((fvs `extendDVarSet` v, VISimple), AnnApp aexpr ((unitDVarSet v, VISimple), AnnVar v))+liftSimple aexpr+ = pprPanic "Vectorise.Exp.liftSimple: not simple" $ ppr (deAnnotate aexpr)++isToplevel :: Var -> Bool+isToplevel v | isId v = case realIdUnfolding v of+ NoUnfolding -> False+ BootUnfolding -> False+ OtherCon {} -> True+ DFunUnfolding {} -> True+ CoreUnfolding {uf_is_top = top} -> top+ | otherwise = False++-- |Vectorise an expression.+--+vectExpr :: CoreExprWithVectInfo -> VM VExpr++vectExpr aexpr+ -- encapsulated expression of functional type => try to vectorise as a scalar subcomputation+ | (isFunTy . annExprType $ aexpr) && isVIEncaps aexpr+ = vectFnExpr True False aexpr+ -- encapsulated constant => vectorise as a scalar constant+ | isVIEncaps aexpr+ = traceVt "vectExpr (encapsulated constant):" (ppr . deAnnotate $ aexpr) >>+ vectConst (deAnnotate aexpr)++vectExpr (_, AnnVar v)+ = vectVar v++vectExpr (_, AnnLit lit)+ = vectConst $ Lit lit++vectExpr aexpr@(_, AnnLam _ _)+ = traceVt "vectExpr [AnnLam]:" (ppr . deAnnotate $ aexpr) >>+ vectFnExpr True False aexpr++ -- SPECIAL CASE: Vectorise/lift 'patError @ ty err' by only vectorising/lifting the type 'ty';+ -- its only purpose is to abort the program, but we need to adjust the type to keep CoreLint+ -- happy.+-- FIXME: can't be do this with a VECTORISE pragma on 'pAT_ERROR_ID' now?+vectExpr (_, AnnApp (_, AnnApp (_, AnnVar v) (_, AnnType ty)) err)+ | v == pAT_ERROR_ID+ = do+ { (vty, lty) <- vectAndLiftType ty+ ; return (mkCoreApps (Var v) [Type (getRuntimeRep "vectExpr" vty), Type vty, err'], mkCoreApps (Var v) [Type lty, err'])+ }+ where+ err' = deAnnotate err++ -- type application (handle multiple consecutive type applications simultaneously to ensure the+ -- PA dictionaries are put at the right places)+vectExpr e@(_, AnnApp _ arg)+ | isAnnTypeArg arg+ = vectPolyApp e++ -- Lifted literal+vectExpr (_, AnnApp (_, AnnVar v) (_, AnnLit lit))+ | Just _con <- isDataConId_maybe v+ = do+ { let vexpr = App (Var v) (Lit lit)+ ; lexpr <- liftPD vexpr+ ; return (vexpr, lexpr)+ }++ -- value application (dictionary or user value)+vectExpr e@(_, AnnApp fn arg)+ | isPredTy arg_ty -- dictionary application (whose result is not a dictionary)+ = vectPolyApp e+ | otherwise -- user value+ = do+ { -- vectorise the types+ ; varg_ty <- vectType arg_ty+ ; vres_ty <- vectType res_ty++ -- vectorise the function and argument expression+ ; vfn <- vectExpr fn+ ; varg <- vectExpr arg++ -- the vectorised function is a closure; apply it to the vectorised argument+ ; mkClosureApp varg_ty vres_ty vfn varg+ }+ where+ (arg_ty, res_ty) = splitFunTy . exprType $ deAnnotate fn++vectExpr (_, AnnCase scrut bndr ty alts)+ | Just (tycon, ty_args) <- splitTyConApp_maybe scrut_ty+ , isAlgTyCon tycon+ = vectAlgCase tycon ty_args scrut bndr ty alts+ | otherwise+ = do+ { dflags <- getDynFlags+ ; cantVectorise dflags "Can't vectorise expression (no algebraic type constructor)" $+ ppr scrut_ty+ }+ where+ scrut_ty = exprType (deAnnotate scrut)++vectExpr (_, AnnLet (AnnNonRec bndr rhs) body)+ = do+ { traceVt "let binding (non-recursive)" Outputable.empty+ ; vrhs <- localV $+ inBind bndr $+ vectAnnPolyExpr False rhs+ ; traceVt "let body (non-recursive)" Outputable.empty+ ; (vbndr, vbody) <- vectBndrIn bndr (vectExpr body)+ ; return $ vLet (vNonRec vbndr vrhs) vbody+ }++vectExpr (_, AnnLet (AnnRec bs) body)+ = do+ { (vbndrs, (vrhss, vbody)) <- vectBndrsIn bndrs $ do+ { traceVt "let bindings (recursive)" Outputable.empty+ ; vrhss <- zipWithM vect_rhs bndrs rhss+ ; traceVt "let body (recursive)" Outputable.empty+ ; vbody <- vectExpr body+ ; return (vrhss, vbody)+ }+ ; return $ vLet (vRec vbndrs vrhss) vbody+ }+ where+ (bndrs, rhss) = unzip bs++ vect_rhs bndr rhs = localV $+ inBind bndr $+ vectAnnPolyExpr (isStrongLoopBreaker $ idOccInfo bndr) rhs++vectExpr (_, AnnTick tickish expr)+ = vTick tickish <$> vectExpr expr++vectExpr (_, AnnType ty)+ = vType <$> vectType ty++vectExpr e+ = do+ { dflags <- getDynFlags+ ; cantVectorise dflags "Can't vectorise expression (vectExpr)" $ ppr (deAnnotate e)+ }++-- |Vectorise an expression that *may* have an outer lambda abstraction. If the expression is marked+-- as encapsulated ('VIEncaps'), vectorise it as a scalar computation (using a generalised scalar+-- zip).+--+-- We do not handle type variables at this point, as they will already have been stripped off by+-- 'vectPolyExpr'. We also only have to worry about one set of dictionary arguments as we (1) only+-- deal with Haskell 2011 and (2) class selectors are vectorised elsewhere.+--+vectFnExpr :: Bool -- ^If we process the RHS of a binding, whether that binding+ -- should be inlined+ -> Bool -- ^Whether the binding is a loop breaker+ -> CoreExprWithVectInfo -- ^Expression to vectorise; must have an outer `AnnLam`+ -> VM VExpr+vectFnExpr inline loop_breaker aexpr@(_ann, AnnLam bndr body)+ -- predicate abstraction: leave as a normal abstraction, but vectorise the predicate type+ | isId bndr+ && isPredTy (idType bndr)+ = do+ { vBndr <- vectBndr bndr+ ; vbody <- vectFnExpr inline loop_breaker body+ ; return $ mapVect (mkLams [vectorised vBndr]) vbody+ }+ -- encapsulated non-predicate abstraction: vectorise as a scalar computation+ | isId bndr && isVIEncaps aexpr+ = vectScalarFun . deAnnotate $ aexpr+ -- non-predicate abstraction: vectorise as a non-scalar computation+ | isId bndr+ = vectLam inline loop_breaker aexpr+ | otherwise+ = do+ { dflags <- getDynFlags+ ; cantVectorise dflags "Vectorise.Exp.vectFnExpr: Unexpected type lambda" $+ ppr (deAnnotate aexpr)+ }+vectFnExpr _ _ aexpr+ -- encapsulated function: vectorise as a scalar computation+ | (isFunTy . annExprType $ aexpr) && isVIEncaps aexpr+ = vectScalarFun . deAnnotate $ aexpr+ | otherwise+ -- not an abstraction: vectorise as a non-scalar vanilla expression+ -- NB: we can get here due to the recursion in the first case above and from 'vectAnnPolyExpr'+ = vectExpr aexpr++-- |Vectorise type and dictionary applications.+--+-- These are always headed by a variable (as we don't support higher-rank polymorphism), but may+-- involve two sets of type variables and dictionaries. Consider,+--+-- > class C a where+-- > m :: D b => b -> a+--+-- The type of 'm' is 'm :: forall a. C a => forall b. D b => b -> a'.+--+vectPolyApp :: CoreExprWithVectInfo -> VM VExpr+vectPolyApp e0+ = case e4 of+ (_, AnnVar var)+ -> do { -- get the vectorised form of the variable+ ; vVar <- lookupVar var+ ; traceVt "vectPolyApp of" (ppr var)++ -- vectorise type and dictionary arguments+ ; vDictsOuter <- mapM vectDictExpr (map deAnnotate dictsOuter)+ ; vDictsInner <- mapM vectDictExpr (map deAnnotate dictsInner)+ ; vTysOuter <- mapM vectType tysOuter+ ; vTysInner <- mapM vectType tysInner++ ; let reconstructOuter v = (`mkApps` vDictsOuter) <$> polyApply v vTysOuter++ ; case vVar of+ Local (vv, lv)+ -> do { MASSERT( null dictsInner ) -- local vars cannot be class selectors+ ; traceVt " LOCAL" (text "")+ ; (,) <$> reconstructOuter (Var vv) <*> reconstructOuter (Var lv)+ }+ Global vv+ | isDictComp var -- dictionary computation+ -> do { -- in a dictionary computation, the innermost, non-empty set of+ -- arguments are non-vectorised arguments, where no 'PA'dictionaries+ -- are needed for the type variables+ ; ve <- if null dictsInner+ then+ return $ Var vv `mkTyApps` vTysOuter `mkApps` vDictsOuter+ else+ reconstructOuter+ (Var vv `mkTyApps` vTysInner `mkApps` vDictsInner)+ ; traceVt " GLOBAL (dict):" (ppr ve)+ ; vectConst ve+ }+ | otherwise -- non-dictionary computation+ -> do { MASSERT( null dictsInner )+ ; ve <- reconstructOuter (Var vv)+ ; traceVt " GLOBAL (non-dict):" (ppr ve)+ ; vectConst ve+ }+ }+ _ -> pprSorry "Cannot vectorise programs with higher-rank types:" (ppr . deAnnotate $ e0)+ where+ -- if there is only one set of variables or dictionaries, it will be the outer set+ (e1, dictsOuter) = collectAnnDictArgs e0+ (e2, tysOuter) = collectAnnTypeArgs e1+ (e3, dictsInner) = collectAnnDictArgs e2+ (e4, tysInner) = collectAnnTypeArgs e3+ --+ isDictComp var = (isJust . isClassOpId_maybe $ var) || isDFunId var++-- |Vectorise the body of a dfun.+--+-- Dictionary computations are special for the following reasons. The application of dictionary+-- functions are always saturated, so there is no need to create closures. Dictionary computations+-- don't depend on array values, so they are always scalar computations whose result we can+-- replicate (instead of executing them in parallel).+--+-- NB: To keep things simple, we are not rewriting any of the bindings introduced in a dictionary+-- computation. Consequently, the variable case needs to deal with cases where binders are+-- in the vectoriser environments and where that is not the case.+--+vectDictExpr :: CoreExpr -> VM CoreExpr+vectDictExpr (Var var)+ = do { mb_scope <- lookupVar_maybe var+ ; case mb_scope of+ Nothing -> return $ Var var -- binder from within the dict. computation+ Just (Local (vVar, _)) -> return $ Var vVar -- local vectorised variable+ Just (Global vVar) -> return $ Var vVar -- global vectorised variable+ }+vectDictExpr (Lit lit)+ = pprPanic "Vectorise.Exp.vectDictExpr: literal in dictionary computation" (ppr lit)+vectDictExpr (Lam bndr e)+ = Lam bndr <$> vectDictExpr e+vectDictExpr (App fn arg)+ = App <$> vectDictExpr fn <*> vectDictExpr arg+vectDictExpr (Case e bndr ty alts)+ = Case <$> vectDictExpr e <*> pure bndr <*> vectType ty <*> mapM vectDictAlt alts+ where+ vectDictAlt (con, bs, e) = (,,) <$> vectDictAltCon con <*> pure bs <*> vectDictExpr e+ --+ vectDictAltCon (DataAlt datacon) = DataAlt <$> maybeV dataConErr (lookupDataCon datacon)+ where+ dataConErr = text "Cannot vectorise data constructor:" <+> ppr datacon+ vectDictAltCon (LitAlt lit) = return $ LitAlt lit+ vectDictAltCon DEFAULT = return DEFAULT+vectDictExpr (Let bnd body)+ = Let <$> vectDictBind bnd <*> vectDictExpr body+ where+ vectDictBind (NonRec bndr e) = NonRec bndr <$> vectDictExpr e+ vectDictBind (Rec bnds) = Rec <$> mapM (\(bndr, e) -> (bndr,) <$> vectDictExpr e) bnds+vectDictExpr e@(Cast _e _coe)+ = pprSorry "Vectorise.Exp.vectDictExpr: cast" (ppr e)+vectDictExpr (Tick tickish e)+ = Tick tickish <$> vectDictExpr e+vectDictExpr (Type ty)+ = Type <$> vectType ty+vectDictExpr (Coercion coe)+ = pprSorry "Vectorise.Exp.vectDictExpr: coercion" (ppr coe)++-- |Vectorise an expression of functional type, where all arguments and the result are of primitive+-- types (i.e., 'Int', 'Float', 'Double' etc., which have instances of the 'Scalar' type class) and+-- which does not contain any subcomputations that involve parallel arrays. Such functionals do not+-- require the full blown vectorisation transformation; instead, they can be lifted by application+-- of a member of the zipWith family (i.e., 'map', 'zipWith', zipWith3', etc.)+--+-- Dictionary functions are also scalar functions (as dictionaries themselves are not vectorised,+-- instead they become dictionaries of vectorised methods). We treat them differently, though see+-- "Note [Scalar dfuns]" in 'Vectorise'.+--+vectScalarFun :: CoreExpr -> VM VExpr+vectScalarFun expr+ = do+ { traceVt "vectScalarFun:" (ppr expr)+ ; let (arg_tys, res_ty) = splitFunTys (exprType expr)+ ; mkScalarFun arg_tys res_ty expr+ }++-- Generate code for a scalar function by generating a scalar closure. If the function is a+-- dictionary function, vectorise it as dictionary code.+--+mkScalarFun :: [Type] -> Type -> CoreExpr -> VM VExpr+mkScalarFun arg_tys res_ty expr+ | isPredTy res_ty+ = do { vExpr <- vectDictExpr expr+ ; return (vExpr, unused)+ }+ | otherwise+ = do { traceVt "mkScalarFun: " $ ppr expr $$ text " ::" <+>+ ppr (mkFunTys arg_tys res_ty)++ ; fn_var <- hoistExpr (fsLit "fn") expr DontInline+ ; zipf <- zipScalars arg_tys res_ty+ ; clo <- scalarClosure arg_tys res_ty (Var fn_var) (zipf `App` Var fn_var)+ ; clo_var <- hoistExpr (fsLit "clo") clo DontInline+ ; lclo <- liftPD (Var clo_var)+ ; return (Var clo_var, lclo)+ }+ where+ unused = error "Vectorise.Exp.mkScalarFun: we don't lift dictionary expressions"++-- |Vectorise a dictionary function that has a 'VECTORISE SCALAR instance' pragma.+--+-- In other words, all methods in that dictionary are scalar functions — to be vectorised with+-- 'vectScalarFun'. The dictionary "function" itself may be a constant, though.+--+-- NB: You may think that we could implement this function guided by the struture of the Core+-- expression of the right-hand side of the dictionary function. We cannot proceed like this as+-- 'vectScalarDFun' must also work for *imported* dfuns, where we don't necessarily have access+-- to the Core code of the unvectorised dfun.+--+-- Here an example — assume,+--+-- > class Eq a where { (==) :: a -> a -> Bool }+-- > instance (Eq a, Eq b) => Eq (a, b) where { (==) = ... }+-- > {-# VECTORISE SCALAR instance Eq (a, b) }+--+-- The unvectorised dfun for the above instance has the following signature:+--+-- > $dEqPair :: forall a b. Eq a -> Eq b -> Eq (a, b)+--+-- We generate the following (scalar) vectorised dfun (liberally using TH notation):+--+-- > $v$dEqPair :: forall a b. V:Eq a -> V:Eq b -> V:Eq (a, b)+-- > $v$dEqPair = /\a b -> \dEqa :: V:Eq a -> \dEqb :: V:Eq b ->+-- > D:V:Eq $(vectScalarFun True recFns+-- > [| (==) @(a, b) ($dEqPair @a @b $(unVect dEqa) $(unVect dEqb)) |])+--+-- NB:+-- * '(,)' vectorises to '(,)' — hence, the type constructor in the result type remains the same.+-- * We share the '$(unVect di)' sub-expressions between the different selectors, but duplicate+-- the application of the unvectorised dfun, to enable the dictionary selection rules to fire.+--+vectScalarDFun :: Var -- ^ Original dfun+ -> VM CoreExpr+vectScalarDFun var+ = do { -- bring the type variables into scope+ ; mapM_ defLocalTyVar tvs++ -- vectorise dictionary argument types and generate variables for them+ ; vTheta <- mapM vectType theta+ ; vThetaBndr <- mapM (newLocalVar (fsLit "vd")) vTheta+ ; let vThetaVars = varsToCoreExprs vThetaBndr++ -- vectorise superclass dictionaries and methods as scalar expressions+ ; thetaVars <- mapM (newLocalVar (fsLit "d")) theta+ ; thetaExprs <- zipWithM unVectDict theta vThetaVars+ ; let thetaDictBinds = zipWith NonRec thetaVars thetaExprs+ dict = Var var `mkTyApps` (mkTyVarTys tvs) `mkVarApps` thetaVars+ scsOps = map (\selId -> varToCoreExpr selId `mkTyApps` tys `mkApps` [dict])+ selIds+ ; vScsOps <- mapM (\e -> vectorised <$> vectScalarFun e) scsOps++ -- vectorised applications of the class-dictionary data constructor+ ; Just vDataCon <- lookupDataCon dataCon+ ; vTys <- mapM vectType tys+ ; let vBody = thetaDictBinds `mkLets` mkCoreConApps vDataCon (map Type vTys ++ vScsOps)++ ; return $ mkLams (tvs ++ vThetaBndr) vBody+ }+ where+ ty = varType var+ (tvs, theta, pty) = tcSplitSigmaTy ty -- 'theta' is the instance context+ (cls, tys) = tcSplitDFunHead pty -- 'pty' is the instance head+ selIds = classAllSelIds cls+ dataCon = classDataCon cls++-- Build a value of the dictionary before vectorisation from original, unvectorised type and an+-- expression computing the vectorised dictionary.+--+-- Given the vectorised version of a dictionary 'vd :: V:C vt1..vtn', generate code that computes+-- the unvectorised version, thus:+--+-- > D:C op1 .. opm+-- > where+-- > opi = $(fromVect opTyi [| vSeli @vt1..vtk vd |])+--+-- where 'opTyi' is the type of the i-th superclass or op of the unvectorised dictionary.+--+unVectDict :: Type -> CoreExpr -> VM CoreExpr+unVectDict ty e+ = do { vTys <- mapM vectType tys+ ; let meths = map (\sel -> Var sel `mkTyApps` vTys `mkApps` [e]) selIds+ ; scOps <- zipWithM fromVect methTys meths+ ; return $ mkCoreConApps dataCon (map Type tys ++ scOps)+ }+ where+ (tycon, tys) = splitTyConApp ty+ Just dataCon = isDataProductTyCon_maybe tycon+ Just cls = tyConClass_maybe tycon+ methTys = dataConInstArgTys dataCon tys+ selIds = classAllSelIds cls++-- Vectorise an 'n'-ary lambda abstraction by building a set of 'n' explicit closures.+--+-- All non-dictionary free variables go into the closure's environment, whereas the dictionary+-- variables are passed explicit (as conventional arguments) into the body during closure+-- construction.+--+vectLam :: Bool -- ^ Should the RHS of a binding be inlined?+ -> Bool -- ^ Whether the binding is a loop breaker.+ -> CoreExprWithVectInfo -- ^ Body of abstraction.+ -> VM VExpr+vectLam inline loop_breaker expr@((fvs, _vi), AnnLam _ _)+ = do { traceVt "fully vectorise a lambda expression" (ppr . deAnnotate $ expr)++ ; let (bndrs, body) = collectAnnValBinders expr++ -- grab the in-scope type variables+ ; tyvars <- localTyVars++ -- collect and vectorise all /local/ free variables+ ; vfvs <- readLEnv $ \env ->+ [ (var, fromJust mb_vv)+ | var <- dVarSetElems fvs+ , let mb_vv = lookupVarEnv (local_vars env) var+ , isJust mb_vv -- its local == is in local var env+ ]+ -- separate dictionary from non-dictionary variables in the free variable set+ ; let (vvs_dict, vvs_nondict) = partition (isPredTy . varType . fst) vfvs+ (_fvs_dict, vfvs_dict) = unzip vvs_dict+ (fvs_nondict, vfvs_nondict) = unzip vvs_nondict++ -- compute the type of the vectorised closure+ ; arg_tys <- mapM (vectType . idType) bndrs+ ; res_ty <- vectType (exprType $ deAnnotate body)++ ; let arity = length fvs_nondict + length bndrs+ vfvs_dict' = map vectorised vfvs_dict+ ; buildClosures tyvars vfvs_dict' vfvs_nondict arg_tys res_ty+ . hoistPolyVExpr tyvars vfvs_dict' (maybe_inline arity)+ $ do { -- generate the vectorised body of the lambda abstraction+ ; lc <- builtin liftingContext+ ; (vbndrs, vbody) <- vectBndrsIn (fvs_nondict ++ bndrs) $ vectExpr body++ ; vbody' <- break_loop lc res_ty vbody+ ; return $ vLams lc vbndrs vbody'+ }+ }+ where+ maybe_inline n | inline = Inline n+ | otherwise = DontInline++ -- If this is the body of a binding marked as a loop breaker, add a recursion termination test+ -- to the /lifted/ version of the function body. The termination tests checks if the lifting+ -- context is empty. If so, it returns an empty array of the (lifted) result type instead of+ -- executing the function body. This is the test from the last line (defining \mathcal{L}')+ -- in Figure 6 of HtM.+ break_loop lc ty (ve, le)+ | loop_breaker+ = do { dflags <- getDynFlags+ ; empty <- emptyPD ty+ ; lty <- mkPDataType ty+ ; return (ve, mkWildCase (Var lc) intPrimTy lty+ [(DEFAULT, [], le),+ (LitAlt (mkMachInt dflags 0), [], empty)])+ }+ | otherwise = return (ve, le)+vectLam _ _ _ = panic "Vectorise.Exp.vectLam: not a lambda"++-- Vectorise an algebraic case expression.+--+-- We convert+--+-- case e :: t of v { ... }+--+-- to+--+-- V: let v' = e in case v' of _ { ... }+-- L: let v' = e in case v' `cast` ... of _ { ... }+--+-- When lifting, we have to do it this way because v must have the type+-- [:V(T):] but the scrutinee must be cast to the representation type. We also+-- have to handle the case where v is a wild var correctly.+--++-- FIXME: this is too lazy...is it?+vectAlgCase :: TyCon -> [Type] -> CoreExprWithVectInfo -> Var -> Type+ -> [(AltCon, [Var], CoreExprWithVectInfo)]+ -> VM VExpr+vectAlgCase _tycon _ty_args scrut bndr ty [(DEFAULT, [], body)]+ = do+ { traceVt "scrutinee (DEFAULT only)" Outputable.empty+ ; vscrut <- vectExpr scrut+ ; (vty, lty) <- vectAndLiftType ty+ ; traceVt "alternative body (DEFAULT only)" Outputable.empty+ ; (vbndr, vbody) <- vectBndrIn bndr (vectExpr body)+ ; return $ vCaseDEFAULT vscrut vbndr vty lty vbody+ }+vectAlgCase _tycon _ty_args scrut bndr ty [(DataAlt _, [], body)]+ = do+ { traceVt "scrutinee (one shot w/o binders)" Outputable.empty+ ; vscrut <- vectExpr scrut+ ; (vty, lty) <- vectAndLiftType ty+ ; traceVt "alternative body (one shot w/o binders)" Outputable.empty+ ; (vbndr, vbody) <- vectBndrIn bndr (vectExpr body)+ ; return $ vCaseDEFAULT vscrut vbndr vty lty vbody+ }+vectAlgCase _tycon _ty_args scrut bndr ty [(DataAlt dc, bndrs, body)]+ = do+ { traceVt "scrutinee (one shot w/ binders)" Outputable.empty+ ; vexpr <- vectExpr scrut+ ; (vty, lty) <- vectAndLiftType ty+ ; traceVt "alternative body (one shot w/ binders)" Outputable.empty+ ; (vbndr, (vbndrs, (vect_body, lift_body)))+ <- vect_scrut_bndr+ . vectBndrsIn bndrs+ $ vectExpr body+ ; let (vect_bndrs, lift_bndrs) = unzip vbndrs+ ; (vscrut, lscrut, pdata_dc) <- pdataUnwrapScrut (vVar vbndr)+ ; vect_dc <- maybeV dataConErr (lookupDataCon dc)++ ; let vcase = mk_wild_case vscrut vty vect_dc vect_bndrs vect_body+ lcase = mk_wild_case lscrut lty pdata_dc lift_bndrs lift_body++ ; return $ vLet (vNonRec vbndr vexpr) (vcase, lcase)+ }+ where+ vect_scrut_bndr | isDeadBinder bndr = vectBndrNewIn bndr (fsLit "scrut")+ | otherwise = vectBndrIn bndr++ mk_wild_case expr ty dc bndrs body+ = mkWildCase expr (exprType expr) ty [(DataAlt dc, bndrs, body)]++ dataConErr = (text "vectAlgCase: data constructor not vectorised" <+> ppr dc)++vectAlgCase tycon _ty_args scrut bndr ty alts+ = do+ { traceVt "scrutinee (general case)" Outputable.empty+ ; vexpr <- vectExpr scrut++ ; vect_tc <- vectTyCon tycon+ ; (vty, lty) <- vectAndLiftType ty++ ; let arity = length (tyConDataCons vect_tc)+ ; sel_ty <- builtin (selTy arity)+ ; sel_bndr <- newLocalVar (fsLit "sel") sel_ty+ ; let sel = Var sel_bndr++ ; traceVt "alternatives' body (general case)" Outputable.empty+ ; (vbndr, valts) <- vect_scrut_bndr+ $ mapM (proc_alt arity sel vty lty) alts'+ ; let (vect_dcs, vect_bndrss, lift_bndrss, vbodies) = unzip4 valts++ ; (vect_scrut, lift_scrut, pdata_dc) <- pdataUnwrapScrut (vVar vbndr)++ ; let (vect_bodies, lift_bodies) = unzip vbodies++ ; vdummy <- newDummyVar (exprType vect_scrut)+ ; ldummy <- newDummyVar (exprType lift_scrut)+ ; let vect_case = Case vect_scrut vdummy vty+ (zipWith3 mk_vect_alt vect_dcs vect_bndrss vect_bodies)++ ; lc <- builtin liftingContext+ ; lbody <- combinePD vty (Var lc) sel lift_bodies+ ; let lift_case = Case lift_scrut ldummy lty+ [(DataAlt pdata_dc, sel_bndr : concat lift_bndrss,+ lbody)]++ ; return . vLet (vNonRec vbndr vexpr)+ $ (vect_case, lift_case)+ }+ where+ vect_scrut_bndr | isDeadBinder bndr = vectBndrNewIn bndr (fsLit "scrut")+ | otherwise = vectBndrIn bndr++ alts' = sortBy (\(alt1, _, _) (alt2, _, _) -> cmp alt1 alt2) alts++ cmp (DataAlt dc1) (DataAlt dc2) = dataConTag dc1 `compare` dataConTag dc2+ cmp DEFAULT DEFAULT = EQ+ cmp DEFAULT _ = LT+ cmp _ DEFAULT = GT+ cmp _ _ = panic "vectAlgCase/cmp"++ proc_alt arity sel _ lty (DataAlt dc, bndrs, body@((fvs_body, _), _))+ = do+ dflags <- getDynFlags+ vect_dc <- maybeV dataConErr (lookupDataCon dc)+ let ntag = dataConTagZ vect_dc+ tag = mkDataConTag dflags vect_dc+ fvs = fvs_body `delDVarSetList` bndrs++ sel_tags <- liftM (`App` sel) (builtin (selTags arity))+ lc <- builtin liftingContext+ elems <- builtin (selElements arity ntag)++ (vbndrs, vbody)+ <- vectBndrsIn bndrs+ . localV+ $ do+ { binds <- mapM (pack_var (Var lc) sel_tags tag)+ . filter isLocalId+ $ dVarSetElems fvs+ ; traceVt "case alternative:" (ppr . deAnnotate $ body)+ ; (ve, le) <- vectExpr body+ ; return (ve, Case (elems `App` sel) lc lty+ [(DEFAULT, [], (mkLets (concat binds) le))])+ }+ -- empty <- emptyPD vty+ -- return (ve, Case (elems `App` sel) lc lty+ -- [(DEFAULT, [], Let (NonRec flags_var flags_expr)+ -- $ mkLets (concat binds) le),+ -- (LitAlt (mkMachInt 0), [], empty)])+ let (vect_bndrs, lift_bndrs) = unzip vbndrs+ return (vect_dc, vect_bndrs, lift_bndrs, vbody)+ where+ dataConErr = (text "vectAlgCase: data constructor not vectorised" <+> ppr dc)++ proc_alt _ _ _ _ _ = panic "vectAlgCase/proc_alt"++ mk_vect_alt vect_dc bndrs body = (DataAlt vect_dc, bndrs, body)++ -- Pack a variable for a case alternative context *if* the variable is vectorised. If it+ -- isn't, ignore it as scalar variables don't need to be packed.+ pack_var len tags t v+ = do+ { r <- lookupVar_maybe v+ ; case r of+ Just (Local (vv, lv)) ->+ do+ { lv' <- cloneVar lv+ ; expr <- packByTagPD (idType vv) (Var lv) len tags t+ ; updLEnv (\env -> env { local_vars = extendVarEnv (local_vars env) v (vv, lv') })+ ; return [(NonRec lv' expr)]+ }+ _ -> return []+ }+++-- Support to compute information for vectorisation avoidance ------------------++-- Annotation for Core AST nodes that describes how they should be handled during vectorisation+-- and especially if vectorisation of the corresponding computation can be avoided.+--+data VectAvoidInfo = VIParr -- tree contains parallel computations+ | VISimple -- result type is scalar & no parallel subcomputation+ | VIComplex -- any result type, no parallel subcomputation+ | VIEncaps -- tree encapsulated by 'liftSimple'+ | VIDict -- dictionary computation (never parallel)+ deriving (Eq, Show)++-- Core expression annotated with free variables and vectorisation-specific information.+--+type CoreExprWithVectInfo = AnnExpr Id (DVarSet, VectAvoidInfo)++-- Yield the type of an annotated core expression.+--+annExprType :: AnnExpr Var ann -> Type+annExprType = exprType . deAnnotate++-- Project the vectorisation information from an annotated Core expression.+--+vectAvoidInfoOf :: CoreExprWithVectInfo -> VectAvoidInfo+vectAvoidInfoOf ((_, vi), _) = vi++-- Is this a 'VIParr' node?+--+isVIParr :: CoreExprWithVectInfo -> Bool+isVIParr = (== VIParr) . vectAvoidInfoOf++-- Is this a 'VIEncaps' node?+--+isVIEncaps :: CoreExprWithVectInfo -> Bool+isVIEncaps = (== VIEncaps) . vectAvoidInfoOf++-- Is this a 'VIDict' node?+--+isVIDict :: CoreExprWithVectInfo -> Bool+isVIDict = (== VIDict) . vectAvoidInfoOf++-- 'VIParr' if either argument is 'VIParr'; otherwise, the first argument.+--+unlessVIParr :: VectAvoidInfo -> VectAvoidInfo -> VectAvoidInfo+unlessVIParr _ VIParr = VIParr+unlessVIParr vi _ = vi++-- 'VIParr' if either arguments vectorisation information is 'VIParr'; otherwise, the vectorisation+-- information of the first argument is produced.+--+unlessVIParrExpr :: VectAvoidInfo -> CoreExprWithVectInfo -> VectAvoidInfo+infixl `unlessVIParrExpr`+unlessVIParrExpr e1 e2 = e1 `unlessVIParr` vectAvoidInfoOf e2++-- Compute Core annotations to determine for which subexpressions we can avoid vectorisation.+--+-- * The first argument is the set of free, local variables whose evaluation may entail parallelism.+--+vectAvoidInfo :: VarSet -> CoreExprWithFVs -> VM CoreExprWithVectInfo+vectAvoidInfo pvs ce@(_, AnnVar v)+ = do+ { gpvs <- globalParallelVars+ ; vi <- if v `elemVarSet` pvs || v `elemDVarSet` gpvs+ then return VIParr+ else vectAvoidInfoTypeOf ce+ ; viTrace ce vi []+ ; when (vi == VIParr) $+ traceVt " reason:" $ if v `elemVarSet` pvs then text "local" else+ if v `elemDVarSet` gpvs then text "global" else text "parallel type"++ ; return ((fvs, vi), AnnVar v)+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo _pvs ce@(_, AnnLit lit)+ = do+ { vi <- vectAvoidInfoTypeOf ce+ ; viTrace ce vi []+ ; return ((fvs, vi), AnnLit lit)+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo pvs ce@(_, AnnApp e1 e2)+ = do+ { ceVI <- vectAvoidInfoTypeOf ce+ ; eVI1 <- vectAvoidInfo pvs e1+ ; eVI2 <- vectAvoidInfo pvs e2+ ; let vi = ceVI `unlessVIParrExpr` eVI1 `unlessVIParrExpr` eVI2+ -- ; viTrace ce vi [eVI1, eVI2]+ ; return ((fvs, vi), AnnApp eVI1 eVI2)+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo pvs ce@(_, AnnLam var body)+ = do+ { bodyVI <- vectAvoidInfo pvs body+ ; varVI <- vectAvoidInfoType $ varType var+ ; let vi = vectAvoidInfoOf bodyVI `unlessVIParr` varVI+ -- ; viTrace ce vi [bodyVI]+ ; return ((fvs, vi), AnnLam var bodyVI)+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo pvs ce@(_, AnnLet (AnnNonRec var e) body)+ = do+ { ceVI <- vectAvoidInfoTypeOf ce+ ; eVI <- vectAvoidInfo pvs e+ ; isScalarTy <- isScalar $ varType var+ ; (bodyVI, vi) <- if isVIParr eVI && not isScalarTy+ then do -- binding is parallel+ { bodyVI <- vectAvoidInfo (pvs `extendVarSet` var) body+ ; return (bodyVI, VIParr)+ }+ else do -- binding doesn't affect parallelism+ { bodyVI <- vectAvoidInfo pvs body+ ; return (bodyVI, ceVI `unlessVIParrExpr` bodyVI)+ }+ -- ; viTrace ce vi [eVI, bodyVI]+ ; return ((fvs, vi), AnnLet (AnnNonRec var eVI) bodyVI)+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo pvs ce@(_, AnnLet (AnnRec bnds) body)+ = do+ { ceVI <- vectAvoidInfoTypeOf ce+ ; bndsVI <- mapM (vectAvoidInfoBnd pvs) bnds+ ; parrBndrs <- map fst <$> filterM isVIParrBnd bndsVI+ ; if not . null $ parrBndrs+ then do -- body may trigger parallelism via at least one binding+ { new_pvs <- filterM ((not <$>) . isScalar . varType) parrBndrs+ ; let extendedPvs = pvs `extendVarSetList` new_pvs+ ; bndsVI <- mapM (vectAvoidInfoBnd extendedPvs) bnds+ ; bodyVI <- vectAvoidInfo extendedPvs body+ -- ; viTrace ce VIParr (map snd bndsVI ++ [bodyVI])+ ; return ((fvs, VIParr), AnnLet (AnnRec bndsVI) bodyVI)+ }+ else do -- demanded bindings cannot trigger parallelism+ { bodyVI <- vectAvoidInfo pvs body+ ; let vi = ceVI `unlessVIParrExpr` bodyVI+ -- ; viTrace ce vi (map snd bndsVI ++ [bodyVI])+ ; return ((fvs, vi), AnnLet (AnnRec bndsVI) bodyVI)+ }+ }+ where+ fvs = freeVarsOf ce+ vectAvoidInfoBnd pvs (var, e) = (var,) <$> vectAvoidInfo pvs e++ isVIParrBnd (var, eVI)+ = do+ { isScalarTy <- isScalar (varType var)+ ; return $ isVIParr eVI && not isScalarTy+ }++vectAvoidInfo pvs ce@(_, AnnCase e var ty alts)+ = do+ { ceVI <- vectAvoidInfoTypeOf ce+ ; eVI <- vectAvoidInfo pvs e+ ; altsVI <- mapM (vectAvoidInfoAlt (isVIParr eVI)) alts+ ; let alteVIs = [eVI | (_, _, eVI) <- altsVI]+ vi = foldl unlessVIParrExpr ceVI (eVI:alteVIs) -- NB: same effect as in the paper+ -- ; viTrace ce vi (eVI : alteVIs)+ ; return ((fvs, vi), AnnCase eVI var ty altsVI)+ }+ where+ fvs = freeVarsOf ce+ vectAvoidInfoAlt scrutIsPar (con, bndrs, e)+ = do+ { allScalar <- allScalarVarType bndrs+ ; let altPvs | scrutIsPar && not allScalar = pvs `extendVarSetList` bndrs+ | otherwise = pvs+ ; (con, bndrs,) <$> vectAvoidInfo altPvs e+ }++vectAvoidInfo pvs ce@(_, AnnCast e (fvs_ann, ann))+ = do+ { eVI <- vectAvoidInfo pvs e+ ; return ((fvs, vectAvoidInfoOf eVI), AnnCast eVI ((freeVarsOfAnn fvs_ann, VISimple), ann))+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo pvs ce@(_, AnnTick tick e)+ = do+ { eVI <- vectAvoidInfo pvs e+ ; return ((fvs, vectAvoidInfoOf eVI), AnnTick tick eVI)+ }+ where+ fvs = freeVarsOf ce++vectAvoidInfo _pvs ce@(_, AnnType ty)+ = return ((fvs, VISimple), AnnType ty)+ where+ fvs = freeVarsOf ce++vectAvoidInfo _pvs ce@(_, AnnCoercion coe)+ = return ((fvs, VISimple), AnnCoercion coe)+ where+ fvs = freeVarsOf ce++-- Compute vectorisation avoidance information for a type.+--+vectAvoidInfoType :: Type -> VM VectAvoidInfo+vectAvoidInfoType ty+ | isPredTy ty+ = return VIDict+ | Just (arg, res) <- splitFunTy_maybe ty+ = do+ { argVI <- vectAvoidInfoType arg+ ; resVI <- vectAvoidInfoType res+ ; case (argVI, resVI) of+ (VISimple, VISimple) -> return VISimple -- NB: diverts from the paper: scalar functions+ (_ , VIDict) -> return VIDict+ _ -> return $ VIComplex `unlessVIParr` argVI `unlessVIParr` resVI+ }+ | otherwise+ = do+ { parr <- maybeParrTy ty+ ; if parr+ then return VIParr+ else do+ { scalar <- isScalar ty+ ; if scalar+ then return VISimple+ else return VIComplex+ } }++-- Compute vectorisation avoidance information for the type of a Core expression (with FVs).+--+vectAvoidInfoTypeOf :: AnnExpr Var ann -> VM VectAvoidInfo+vectAvoidInfoTypeOf = vectAvoidInfoType . annExprType++-- Checks whether the type might be a parallel array type.+--+maybeParrTy :: Type -> VM Bool+maybeParrTy ty+ -- looking through newtypes+ | Just ty' <- coreView ty+ = (== VIParr) <$> vectAvoidInfoType ty'+ -- decompose constructor applications+ | Just (tc, ts) <- splitTyConApp_maybe ty+ = do+ { isParallel <- (tyConName tc `elemNameSet`) <$> globalParallelTyCons+ ; if isParallel+ then return True+ else or <$> mapM maybeParrTy ts+ }+ -- must be a Named ForAllTy because anon ones respond to splitTyConApp_maybe+maybeParrTy (ForAllTy _ ty) = maybeParrTy ty+maybeParrTy _ = return False++-- Are the types of all variables in the 'Scalar' class or toplevel variables?+--+-- NB: 'liftSimple' does not abstract over toplevel variables.+--+allScalarVarType :: [Var] -> VM Bool+allScalarVarType vs = and <$> mapM isScalarOrToplevel vs+ where+ isScalarOrToplevel v | isToplevel v = return True+ | otherwise = isScalar (varType v)++-- Are the types of all variables in the set in the 'Scalar' class or toplevel variables?+--+allScalarVarTypeSet :: DVarSet -> VM Bool+allScalarVarTypeSet = allScalarVarType . dVarSetElems++-- Debugging support+--+viTrace :: CoreExprWithFVs -> VectAvoidInfo -> [CoreExprWithVectInfo] -> VM ()+viTrace ce vi vTs+ = traceVt ("vect info: " ++ show vi ++ "[" +++ (concat $ map ((++ " ") . show . vectAvoidInfoOf) vTs) ++ "]")+ (ppr $ deAnnotate ce)
+ vectorise/Vectorise/Generic/Description.hs view
@@ -0,0 +1,292 @@+-- |Compute a description of the generic representation that we use for a user defined data type.+--+-- During vectorisation, we generate a PRepr and PA instance for each user defined+-- data type. The PA dictionary contains methods to convert the user type to and+-- from our generic representation. This module computes a description of what+-- that generic representation is.+--+module Vectorise.Generic.Description+ ( CompRepr(..)+ , ProdRepr(..)+ , ConRepr(..)+ , SumRepr(..)+ , tyConRepr+ , sumReprType+ , compOrigType+ )+where++import Vectorise.Utils+import Vectorise.Monad+import Vectorise.Builtins++import CoreSyn+import DataCon+import TyCon+import Type+import Control.Monad+import Outputable+++-- | Describes the generic representation of a data type.+-- If the data type has multiple constructors then we bundle them+-- together into a generic sum type.+data SumRepr+ = -- | Data type has no data constructors.+ EmptySum++ -- | Data type has a single constructor.+ | UnarySum ConRepr++ -- | Data type has multiple constructors.+ | Sum { -- | Representation tycon for the sum (eg Sum2)+ repr_sum_tc :: TyCon++ -- | PData version of the sum tycon (eg PDataSum2)+ -- This TyCon doesn't appear explicitly in the source program.+ -- See Note [PData TyCons].+ , repr_psum_tc :: TyCon++ -- | PDatas version of the sum tycon (eg PDatasSum2)+ , repr_psums_tc :: TyCon++ -- | Type of the selector (eg Sel2)+ , repr_sel_ty :: Type++ -- | Type of multi-selector (eg Sel2s)+ , repr_sels_ty :: Type++ -- | Function to get the length of a Sels of this type.+ , repr_selsLength_v :: CoreExpr++ -- | Type of each data constructor.+ , repr_con_tys :: [Type]++ -- | Generic representation types of each data constructor.+ , repr_cons :: [ConRepr]+ }+++-- | Describes the representation type of a data constructor.+data ConRepr+ = ConRepr+ { repr_dc :: DataCon+ , repr_prod :: ProdRepr+ }++-- | Describes the representation type of the fields \/ components of a constructor.+-- If the data constructor has multiple fields then we bundle them+-- together into a generic product type.+data ProdRepr+ = -- | Data constructor has no fields.+ EmptyProd++ -- | Data constructor has a single field.+ | UnaryProd CompRepr++ -- | Data constructor has several fields.+ | Prod { -- | Representation tycon for the product (eg Tuple2)+ repr_tup_tc :: TyCon++ -- | PData version of the product tycon (eg PDataTuple2)+ , repr_ptup_tc :: TyCon++ -- | PDatas version of the product tycon (eg PDatasTuple2s)+ -- Not all lifted backends use `PDatas`.+ , repr_ptups_tc :: TyCon++ -- | Types of each field.+ , repr_comp_tys :: [Type]++ -- | Generic representation types for each field.+ , repr_comps :: [CompRepr]+ }+++-- | Describes the representation type of a data constructor field.+data CompRepr+ = Keep Type+ CoreExpr -- PR dictionary for the type+ | Wrap Type+++-------------------------------------------------------------------------------++-- |Determine the generic representation of a data type, given its tycon.+--+tyConRepr :: TyCon -> VM SumRepr+tyConRepr tc+ = sum_repr (tyConDataCons tc)+ where+ -- Build the representation type for a data type with the given constructors.+ -- The representation types for each individual constructor are bundled+ -- together into a generic sum type.+ sum_repr :: [DataCon] -> VM SumRepr+ sum_repr [] = return EmptySum+ sum_repr [con] = liftM UnarySum (con_repr con)+ sum_repr cons+ = do let arity = length cons+ rs <- mapM con_repr cons+ tys <- mapM conReprType rs++ -- Get the 'Sum' tycon of this arity (eg Sum2).+ sum_tc <- builtin (sumTyCon arity)++ -- Get the 'PData' and 'PDatas' tycons for the sum.+ psum_tc <- pdataReprTyConExact sum_tc+ psums_tc <- pdatasReprTyConExact sum_tc++ sel_ty <- builtin (selTy arity)+ sels_ty <- builtin (selsTy arity)+ selsLength_v <- builtin (selsLength arity)+ return $ Sum+ { repr_sum_tc = sum_tc+ , repr_psum_tc = psum_tc+ , repr_psums_tc = psums_tc+ , repr_sel_ty = sel_ty+ , repr_sels_ty = sels_ty+ , repr_selsLength_v = selsLength_v+ , repr_con_tys = tys+ , repr_cons = rs+ }++ -- Build the representation type for a single data constructor.+ con_repr con = liftM (ConRepr con) (prod_repr (dataConRepArgTys con))++ -- Build the representation type for the fields of a data constructor.+ -- The representation types for each individual field are bundled+ -- together into a generic product type.+ prod_repr :: [Type] -> VM ProdRepr+ prod_repr [] = return EmptyProd+ prod_repr [ty] = liftM UnaryProd (comp_repr ty)+ prod_repr tys+ = do let arity = length tys+ rs <- mapM comp_repr tys+ tys' <- mapM compReprType rs++ -- Get the Prod \/ Tuple tycon of this arity (eg Tuple2)+ tup_tc <- builtin (prodTyCon arity)++ -- Get the 'PData' and 'PDatas' tycons for the product.+ ptup_tc <- pdataReprTyConExact tup_tc+ ptups_tc <- pdatasReprTyConExact tup_tc++ return $ Prod+ { repr_tup_tc = tup_tc+ , repr_ptup_tc = ptup_tc+ , repr_ptups_tc = ptups_tc+ , repr_comp_tys = tys'+ , repr_comps = rs+ }++ -- Build the representation type for a single data constructor field.+ comp_repr ty = liftM (Keep ty) (prDictOfReprType ty)+ `orElseV` return (Wrap ty)++-- |Yield the type of this sum representation.+--+sumReprType :: SumRepr -> VM Type+sumReprType EmptySum = voidType+sumReprType (UnarySum r) = conReprType r+sumReprType (Sum { repr_sum_tc = sum_tc, repr_con_tys = tys })+ = return $ mkTyConApp sum_tc tys++-- Yield the type of this constructor representation.+--+conReprType :: ConRepr -> VM Type+conReprType (ConRepr _ r) = prodReprType r++-- Yield the type of of this product representation.+--+prodReprType :: ProdRepr -> VM Type+prodReprType EmptyProd = voidType+prodReprType (UnaryProd r) = compReprType r+prodReprType (Prod { repr_tup_tc = tup_tc, repr_comp_tys = tys })+ = return $ mkTyConApp tup_tc tys++-- Yield the type of this data constructor field \/ component representation.+--+compReprType :: CompRepr -> VM Type+compReprType (Keep ty _) = return ty+compReprType (Wrap ty) = mkWrapType ty++-- |Yield the original component type of a data constructor component representation.+--+compOrigType :: CompRepr -> Type+compOrigType (Keep ty _) = ty+compOrigType (Wrap ty) = ty+++-- Outputable instances -------------------------------------------------------+instance Outputable SumRepr where+ ppr ss+ = case ss of+ EmptySum+ -> text "EmptySum"++ UnarySum con+ -> sep [text "UnarySum", ppr con]++ Sum sumtc psumtc psumstc selty selsty selsLength contys cons+ -> text "Sum" $+$ braces (nest 4+ $ sep [ text "repr_sum_tc = " <> ppr sumtc+ , text "repr_psum_tc = " <> ppr psumtc+ , text "repr_psums_tc = " <> ppr psumstc+ , text "repr_sel_ty = " <> ppr selty+ , text "repr_sels_ty = " <> ppr selsty+ , text "repr_selsLength_v = " <> ppr selsLength+ , text "repr_con_tys = " <> ppr contys+ , text "repr_cons = " <> ppr cons])+++instance Outputable ConRepr where+ ppr (ConRepr dc pr)+ = text "ConRepr" $+$ braces (nest 4+ $ sep [ text "repr_dc = " <> ppr dc+ , text "repr_prod = " <> ppr pr])+++instance Outputable ProdRepr where+ ppr ss+ = case ss of+ EmptyProd+ -> text "EmptyProd"++ UnaryProd cr+ -> sep [text "UnaryProd", ppr cr]++ Prod tuptcs ptuptcs ptupstcs comptys comps+ -> sep [text "Prod", ppr tuptcs, ppr ptuptcs, ppr ptupstcs, ppr comptys, ppr comps]+++instance Outputable CompRepr where+ ppr ss+ = case ss of+ Keep t ce+ -> text "Keep" $+$ sep [ppr t, ppr ce]++ Wrap t+ -> sep [text "Wrap", ppr t]+++-- Notes ----------------------------------------------------------------------+{-+Note [PData TyCons]+~~~~~~~~~~~~~~~~~~~+When PData is a type family, the compiler generates a type constructor for each+instance, which is named after the family and instance type. This type+constructor does not appear in the source program. Rather, it is implicitly+defined by the data instance. For example with:++ data family PData a++ data instance PData (Sum2 a b)+ = PSum2 U.Sel2+ (PData a)+ (PData b)++The type constructor corresponding to the instance will be named 'PDataSum2',+and this is what we will get in the repr_psum_tc field of SumRepr.Sum.++-}+
+ vectorise/Vectorise/Generic/PADict.hs view
@@ -0,0 +1,126 @@++module Vectorise.Generic.PADict+ ( buildPADict+ ) where++import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Generic.Description+import Vectorise.Generic.PAMethods ( buildPAScAndMethods )+import Vectorise.Utils++import BasicTypes+import CoreSyn+import CoreUtils+import CoreUnfold+import Module+import TyCon+import CoAxiom+import Type+import Id+import Var+import Name+import FastString+++-- |Build the PA dictionary function for some type and hoist it to top level.+--+-- The PA dictionary holds fns that convert values to and from their vectorised representations.+--+-- @Recall the definition:+-- class PR (PRepr a) => PA a where+-- toPRepr :: a -> PRepr a+-- fromPRepr :: PRepr a -> a+-- toArrPRepr :: PData a -> PData (PRepr a)+-- fromArrPRepr :: PData (PRepr a) -> PData a+-- toArrPReprs :: PDatas a -> PDatas (PRepr a)+-- fromArrPReprs :: PDatas (PRepr a) -> PDatas a+--+-- Example:+-- df :: forall a. PR (PRepr a) -> PA a -> PA (T a)+-- df = /\a. \(c:PR (PRepr a)) (d:PA a). MkPA c ($PR_df a d) ($toPRepr a d) ...+-- $dPR_df :: forall a. PA a -> PR (PRepr (T a))+-- $dPR_df = ....+-- $toRepr :: forall a. PA a -> T a -> PRepr (T a)+-- $toPRepr = ...+-- The "..." stuff is filled in by buildPAScAndMethods+-- @+--+buildPADict+ :: TyCon -- ^ tycon of the type being vectorised.+ -> CoAxiom Unbranched+ -- ^ Coercion between the type and+ -- its vectorised representation.+ -> TyCon -- ^ PData instance tycon+ -> TyCon -- ^ PDatas instance tycon+ -> SumRepr -- ^ representation used for the type being vectorised.+ -> VM Var -- ^ name of the top-level dictionary function.++buildPADict vect_tc prepr_ax pdata_tc pdatas_tc repr+ = polyAbstract tvs $ \args -> -- The args are the dictionaries we lambda abstract over; and they+ -- are put in the envt, so when we need a (PA a) we can find it in+ -- the envt; they don't include the silent superclass args yet+ do { mod <- liftDs getModule+ ; let dfun_name = mkLocalisedOccName mod mkPADFunOcc vect_tc_name++ -- The superclass dictionary is a (silent) argument if the tycon is polymorphic...+ ; let mk_super_ty = do { r <- mkPReprType inst_ty+ ; pr_cls <- builtin prClass+ ; return $ mkClassPred pr_cls [r]+ }+ ; super_tys <- sequence [mk_super_ty | not (null tvs)]+ ; super_args <- mapM (newLocalVar (fsLit "pr")) super_tys+ ; let val_args = super_args ++ args+ all_args = tvs ++ val_args++ -- ...it is constant otherwise+ ; super_consts <- sequence [prDictOfPReprInstTyCon inst_ty prepr_ax [] | null tvs]++ -- Get ids for each of the methods in the dictionary, including superclass+ ; paMethodBuilders <- buildPAScAndMethods+ ; method_ids <- mapM (method val_args dfun_name) paMethodBuilders++ -- Expression to build the dictionary.+ ; pa_dc <- builtin paDataCon+ ; let dict = mkLams all_args (mkConApp pa_dc con_args)+ con_args = Type inst_ty+ : map Var super_args -- the superclass dictionary is either+ ++ super_consts -- lambda-bound or constant+ ++ map (method_call val_args) method_ids++ -- Build the type of the dictionary function.+ ; pa_cls <- builtin paClass+ ; let dfun_ty = mkInvForAllTys tvs+ $ mkFunTys (map varType val_args)+ (mkClassPred pa_cls [inst_ty])++ -- Set the unfolding for the inliner.+ ; raw_dfun <- newExportedVar dfun_name dfun_ty+ ; let dfun_unf = mkDFunUnfolding all_args pa_dc con_args+ dfun = raw_dfun `setIdUnfolding` dfun_unf+ `setInlinePragma` dfunInlinePragma++ -- Add the new binding to the top-level environment.+ ; hoistBinding dfun dict+ ; return dfun+ }+ where+ tvs = tyConTyVars vect_tc+ arg_tys = mkTyVarTys tvs+ inst_ty = mkTyConApp vect_tc arg_tys+ vect_tc_name = getName vect_tc++ method args dfun_name (name, build)+ = localV+ $ do expr <- build vect_tc prepr_ax pdata_tc pdatas_tc repr+ let body = mkLams (tvs ++ args) expr+ raw_var <- newExportedVar (method_name dfun_name name) (exprType body)+ let var = raw_var+ `setIdUnfolding` mkInlineUnfoldingWithArity+ (length args) body+ `setInlinePragma` alwaysInlinePragma+ hoistBinding var body+ return var++ method_call args id = mkApps (Var id) (map Type arg_tys ++ map Var args)+ method_name dfun_name name = mkVarOcc $ occNameString dfun_name ++ ('$' : name)
+ vectorise/Vectorise/Generic/PAMethods.hs view
@@ -0,0 +1,584 @@++-- | Generate methods for the PA class.+--+-- TODO: there is a large amount of redundancy here between the+-- a, PData a, and PDatas a forms. See if we can factor some of this out.+--+module Vectorise.Generic.PAMethods+ ( buildPReprTyCon+ , buildPAScAndMethods+ ) where++import Vectorise.Utils+import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Generic.Description+import CoreSyn+import CoreUtils+import FamInstEnv+import MkCore ( mkWildCase, mkCoreLet )+import TyCon+import CoAxiom+import Type+import OccName+import Coercion+import MkId+import FamInst+import TysPrim( intPrimTy )++import DynFlags+import FastString+import MonadUtils+import Control.Monad+import Outputable+++buildPReprTyCon :: TyCon -> TyCon -> SumRepr -> VM FamInst+buildPReprTyCon orig_tc vect_tc repr+ = do name <- mkLocalisedName mkPReprTyConOcc (tyConName orig_tc)+ rhs_ty <- sumReprType repr+ prepr_tc <- builtin preprTyCon+ let axiom = mkSingleCoAxiom Nominal name tyvars [] prepr_tc instTys rhs_ty+ liftDs $ newFamInst SynFamilyInst axiom+ where+ tyvars = tyConTyVars vect_tc+ instTys = [mkTyConApp vect_tc . mkTyVarTys $ tyConTyVars vect_tc]++-- buildPAScAndMethods --------------------------------------------------------++-- | This says how to build the PR superclass and methods of PA+-- Recall the definition of the PA class:+--+-- @+-- class class PR (PRepr a) => PA a where+-- toPRepr :: a -> PRepr a+-- fromPRepr :: PRepr a -> a+--+-- toArrPRepr :: PData a -> PData (PRepr a)+-- fromArrPRepr :: PData (PRepr a) -> PData a+--+-- toArrPReprs :: PDatas a -> PDatas (PRepr a)+-- fromArrPReprs :: PDatas (PRepr a) -> PDatas a+-- @+--+type PAInstanceBuilder+ = TyCon -- ^ Vectorised TyCon+ -> CoAxiom Unbranched+ -- ^ Coercion to the representation TyCon+ -> TyCon -- ^ 'PData' TyCon+ -> TyCon -- ^ 'PDatas' TyCon+ -> SumRepr -- ^ Description of generic representation.+ -> VM CoreExpr -- ^ Instance function.+++buildPAScAndMethods :: VM [(String, PAInstanceBuilder)]+buildPAScAndMethods+ = return [ ("toPRepr", buildToPRepr)+ , ("fromPRepr", buildFromPRepr)+ , ("toArrPRepr", buildToArrPRepr)+ , ("fromArrPRepr", buildFromArrPRepr)+ , ("toArrPReprs", buildToArrPReprs)+ , ("fromArrPReprs", buildFromArrPReprs)]+++-- buildToPRepr ---------------------------------------------------------------+-- | Build the 'toRepr' method of the PA class.+buildToPRepr :: PAInstanceBuilder+buildToPRepr vect_tc repr_ax _ _ repr+ = do let arg_ty = mkTyConApp vect_tc ty_args++ -- Get the representation type of the argument.+ res_ty <- mkPReprType arg_ty++ -- Var to bind the argument+ arg <- newLocalVar (fsLit "x") arg_ty++ -- Build the expression to convert the argument to the generic representation.+ result <- to_sum (Var arg) arg_ty res_ty repr++ return $ Lam arg result+ where+ ty_args = mkTyVarTys (tyConTyVars vect_tc)++ wrap_repr_inst = wrapTypeUnbranchedFamInstBody repr_ax ty_args []++ -- CoreExp to convert the given argument to the generic representation.+ -- We start by doing a case branch on the possible data constructors.+ to_sum :: CoreExpr -> Type -> Type -> SumRepr -> VM CoreExpr+ to_sum _ _ _ EmptySum+ = do void <- builtin voidVar+ return $ wrap_repr_inst $ Var void++ to_sum arg arg_ty res_ty (UnarySum r)+ = do (pat, vars, body) <- con_alt r+ return $ mkWildCase arg arg_ty res_ty+ [(pat, vars, wrap_repr_inst body)]++ to_sum arg arg_ty res_ty (Sum { repr_sum_tc = sum_tc+ , repr_con_tys = tys+ , repr_cons = cons })+ = do alts <- mapM con_alt cons+ let alts' = [(pat, vars, wrap_repr_inst+ $ mkConApp sum_con (map Type tys ++ [body]))+ | ((pat, vars, body), sum_con)+ <- zip alts (tyConDataCons sum_tc)]+ return $ mkWildCase arg arg_ty res_ty alts'++ con_alt (ConRepr con r)+ = do (vars, body) <- to_prod r+ return (DataAlt con, vars, body)++ -- CoreExp to convert data constructor fields to the generic representation.+ to_prod :: ProdRepr -> VM ([Var], CoreExpr)+ to_prod EmptyProd+ = do void <- builtin voidVar+ return ([], Var void)++ to_prod (UnaryProd comp)+ = do var <- newLocalVar (fsLit "x") (compOrigType comp)+ body <- to_comp (Var var) comp+ return ([var], body)++ to_prod (Prod { repr_tup_tc = tup_tc+ , repr_comp_tys = tys+ , repr_comps = comps })+ = do vars <- newLocalVars (fsLit "x") (map compOrigType comps)+ exprs <- zipWithM to_comp (map Var vars) comps+ let [tup_con] = tyConDataCons tup_tc+ return (vars, mkConApp tup_con (map Type tys ++ exprs))++ -- CoreExp to convert a data constructor component to the generic representation.+ to_comp :: CoreExpr -> CompRepr -> VM CoreExpr+ to_comp expr (Keep _ _) = return expr+ to_comp expr (Wrap ty) = wrapNewTypeBodyOfWrap expr ty+++-- buildFromPRepr -------------------------------------------------------------++-- |Build the 'fromPRepr' method of the PA class.+--+buildFromPRepr :: PAInstanceBuilder+buildFromPRepr vect_tc repr_ax _ _ repr+ = do+ arg_ty <- mkPReprType res_ty+ arg <- newLocalVar (fsLit "x") arg_ty++ result <- from_sum (unwrapTypeUnbranchedFamInstScrut repr_ax ty_args [] (Var arg))+ repr+ return $ Lam arg result+ where+ ty_args = mkTyVarTys (tyConTyVars vect_tc)+ res_ty = mkTyConApp vect_tc ty_args++ from_sum _ EmptySum+ = do dummy <- builtin fromVoidVar+ return $ Var dummy `App` Type res_ty++ from_sum expr (UnarySum r) = from_con expr r+ from_sum expr (Sum { repr_sum_tc = sum_tc+ , repr_con_tys = tys+ , repr_cons = cons })+ = do vars <- newLocalVars (fsLit "x") tys+ es <- zipWithM from_con (map Var vars) cons+ return $ mkWildCase expr (exprType expr) res_ty+ [(DataAlt con, [var], e)+ | (con, var, e) <- zip3 (tyConDataCons sum_tc) vars es]++ from_con expr (ConRepr con r)+ = from_prod expr (mkConApp con $ map Type ty_args) r++ from_prod _ con EmptyProd = return con+ from_prod expr con (UnaryProd r)+ = do e <- from_comp expr r+ return $ con `App` e++ from_prod expr con (Prod { repr_tup_tc = tup_tc+ , repr_comp_tys = tys+ , repr_comps = comps+ })+ = do vars <- newLocalVars (fsLit "y") tys+ es <- zipWithM from_comp (map Var vars) comps+ let [tup_con] = tyConDataCons tup_tc+ return $ mkWildCase expr (exprType expr) res_ty+ [(DataAlt tup_con, vars, con `mkApps` es)]++ from_comp expr (Keep _ _) = return expr+ from_comp expr (Wrap ty) = unwrapNewTypeBodyOfWrap expr ty+++-- buildToArrRepr -------------------------------------------------------------++-- |Build the 'toArrRepr' method of the PA class.+--+buildToArrPRepr :: PAInstanceBuilder+buildToArrPRepr vect_tc repr_co pdata_tc _ r+ = do arg_ty <- mkPDataType el_ty+ res_ty <- mkPDataType =<< mkPReprType el_ty+ arg <- newLocalVar (fsLit "xs") arg_ty++ pdata_co <- mkBuiltinCo pdataTyCon+ let co = mkAppCo pdata_co+ $ mkSymCo+ $ mkUnbranchedAxInstCo Nominal repr_co ty_args []++ scrut = unwrapFamInstScrut pdata_tc ty_args (Var arg)++ (vars, result) <- to_sum r++ return . Lam arg+ $ mkWildCase scrut (mkTyConApp pdata_tc ty_args) res_ty+ [(DataAlt pdata_dc, vars, mkCast result co)]+ where+ ty_args = mkTyVarTys $ tyConTyVars vect_tc+ el_ty = mkTyConApp vect_tc ty_args+ [pdata_dc] = tyConDataCons pdata_tc++ to_sum ss+ = case ss of+ EmptySum -> builtin pvoidVar >>= \pvoid -> return ([], Var pvoid)+ UnarySum r -> to_con r+ Sum{}+ -> do let psum_tc = repr_psum_tc ss+ let [psum_con] = tyConDataCons psum_tc+ (vars, exprs) <- mapAndUnzipM to_con (repr_cons ss)+ sel <- newLocalVar (fsLit "sel") (repr_sel_ty ss)+ return ( sel : concat vars+ , wrapFamInstBody psum_tc (repr_con_tys ss)+ $ mkConApp psum_con+ $ map Type (repr_con_tys ss) ++ (Var sel : exprs))++ to_prod ss+ = case ss of+ EmptyProd -> builtin pvoidVar >>= \pvoid -> return ([], Var pvoid)+ UnaryProd r+ -> do pty <- mkPDataType (compOrigType r)+ var <- newLocalVar (fsLit "x") pty+ expr <- to_comp (Var var) r+ return ([var], expr)+ Prod{}+ -> do let [ptup_con] = tyConDataCons (repr_ptup_tc ss)+ ptys <- mapM (mkPDataType . compOrigType) (repr_comps ss)+ vars <- newLocalVars (fsLit "x") ptys+ exprs <- zipWithM to_comp (map Var vars) (repr_comps ss)+ return ( vars+ , wrapFamInstBody (repr_ptup_tc ss) (repr_comp_tys ss)+ $ mkConApp ptup_con+ $ map Type (repr_comp_tys ss) ++ exprs)++ to_con (ConRepr _ r) = to_prod r++ to_comp expr (Keep _ _) = return expr+ to_comp expr (Wrap ty) = wrapNewTypeBodyOfPDataWrap expr ty+++-- buildFromArrPRepr ----------------------------------------------------------++-- |Build the 'fromArrPRepr' method for the PA class.+--+buildFromArrPRepr :: PAInstanceBuilder+buildFromArrPRepr vect_tc repr_co pdata_tc _ r+ = do arg_ty <- mkPDataType =<< mkPReprType el_ty+ res_ty <- mkPDataType el_ty+ arg <- newLocalVar (fsLit "xs") arg_ty++ pdata_co <- mkBuiltinCo pdataTyCon+ let co = mkAppCo pdata_co+ $ mkUnbranchedAxInstCo Nominal repr_co var_tys []++ let scrut = mkCast (Var arg) co++ let mk_result args+ = wrapFamInstBody pdata_tc var_tys+ $ mkConApp pdata_con+ $ map Type var_tys ++ args++ (expr, _) <- fixV $ \ ~(_, args) ->+ from_sum res_ty (mk_result args) scrut r++ return $ Lam arg expr+ where+ var_tys = mkTyVarTys $ tyConTyVars vect_tc+ el_ty = mkTyConApp vect_tc var_tys+ [pdata_con] = tyConDataCons pdata_tc++ from_sum res_ty res expr ss+ = case ss of+ EmptySum -> return (res, [])+ UnarySum r -> from_con res_ty res expr r+ Sum {}+ -> do let psum_tc = repr_psum_tc ss+ let [psum_con] = tyConDataCons psum_tc+ sel <- newLocalVar (fsLit "sel") (repr_sel_ty ss)+ ptys <- mapM mkPDataType (repr_con_tys ss)+ vars <- newLocalVars (fsLit "xs") ptys+ (res', args) <- fold from_con res_ty res (map Var vars) (repr_cons ss)+ let scrut = unwrapFamInstScrut psum_tc (repr_con_tys ss) expr+ let body = mkWildCase scrut (exprType scrut) res_ty+ [(DataAlt psum_con, sel : vars, res')]+ return (body, Var sel : args)++ from_prod res_ty res expr ss+ = case ss of+ EmptyProd -> return (res, [])+ UnaryProd r -> from_comp res_ty res expr r+ Prod {}+ -> do let ptup_tc = repr_ptup_tc ss+ let [ptup_con] = tyConDataCons ptup_tc+ ptys <- mapM mkPDataType (repr_comp_tys ss)+ vars <- newLocalVars (fsLit "ys") ptys+ (res', args) <- fold from_comp res_ty res (map Var vars) (repr_comps ss)+ let scrut = unwrapFamInstScrut ptup_tc (repr_comp_tys ss) expr+ let body = mkWildCase scrut (exprType scrut) res_ty+ [(DataAlt ptup_con, vars, res')]+ return (body, args)++ from_con res_ty res expr (ConRepr _ r) = from_prod res_ty res expr r++ from_comp _ res expr (Keep _ _) = return (res, [expr])+ from_comp _ res expr (Wrap ty) = do { expr' <- unwrapNewTypeBodyOfPDataWrap expr ty+ ; return (res, [expr'])+ }++ fold f res_ty res exprs rs+ = foldrM f' (res, []) (zip exprs rs)+ where+ f' (expr, r) (res, args)+ = do (res', args') <- f res_ty res expr r+ return (res', args' ++ args)+++-- buildToArrPReprs -----------------------------------------------------------+-- | Build the 'toArrPReprs' instance for the PA class.+-- This converts a PData of elements into the generic representation.+buildToArrPReprs :: PAInstanceBuilder+buildToArrPReprs vect_tc repr_co _ pdatas_tc r+ = do+ -- The argument type of the instance.+ -- eg: 'PDatas (Tree a b)'+ arg_ty <- mkPDatasType el_ty++ -- The result type.+ -- eg: 'PDatas (PRepr (Tree a b))'+ res_ty <- mkPDatasType =<< mkPReprType el_ty++ -- Variable to bind the argument to the instance+ -- eg: (xss :: PDatas (Tree a b))+ varg <- newLocalVar (fsLit "xss") arg_ty++ -- Coercion to case between the (PRepr a) type and its instance.+ pdatas_co <- mkBuiltinCo pdatasTyCon+ let co = mkAppCo pdatas_co+ $ mkSymCo+ $ mkUnbranchedAxInstCo Nominal repr_co ty_args []++ let scrut = unwrapFamInstScrut pdatas_tc ty_args (Var varg)+ (vars, result) <- to_sum r++ return $ Lam varg+ $ mkWildCase scrut (mkTyConApp pdatas_tc ty_args) res_ty+ [(DataAlt pdatas_dc, vars, mkCast result co)]++ where+ -- The element type of the argument.+ -- eg: 'Tree a b'.+ ty_args = mkTyVarTys $ tyConTyVars vect_tc+ el_ty = mkTyConApp vect_tc ty_args++ -- PDatas data constructor+ [pdatas_dc] = tyConDataCons pdatas_tc++ to_sum ss+ = case ss of+ -- We can't convert data types with no data.+ -- See Note: [Empty PDatas].+ EmptySum -> do dflags <- getDynFlags+ return ([], errorEmptyPDatas dflags el_ty)+ UnarySum r -> do dflags <- getDynFlags+ to_con (errorEmptyPDatas dflags el_ty) r++ Sum{}+ -> do let psums_tc = repr_psums_tc ss+ let [psums_con] = tyConDataCons psums_tc+ sels <- newLocalVar (fsLit "sels") (repr_sels_ty ss)++ -- Take the number of selectors to serve as the length of+ -- and PDatas Void arrays in the product. See Note [Empty PDatas].+ let xSums = App (repr_selsLength_v ss) (Var sels)++ xSums_var <- newLocalVar (fsLit "xsum") intPrimTy++ (vars, exprs) <- mapAndUnzipM (to_con xSums_var) (repr_cons ss)+ return ( sels : concat vars+ , wrapFamInstBody psums_tc (repr_con_tys ss)+ $ mkCoreLet (NonRec xSums_var xSums)+ -- mkCoreLet ensures that the let/app invariant holds+ $ mkConApp psums_con+ $ map Type (repr_con_tys ss) ++ (Var sels : exprs))++ to_prod xSums ss+ = case ss of+ EmptyProd+ -> do pvoids <- builtin pvoidsVar+ return ([], App (Var pvoids) (Var xSums) )++ UnaryProd r+ -> do pty <- mkPDatasType (compOrigType r)+ var <- newLocalVar (fsLit "x") pty+ expr <- to_comp (Var var) r+ return ([var], expr)++ Prod{}+ -> do let [ptups_con] = tyConDataCons (repr_ptups_tc ss)+ ptys <- mapM (mkPDatasType . compOrigType) (repr_comps ss)+ vars <- newLocalVars (fsLit "x") ptys+ exprs <- zipWithM to_comp (map Var vars) (repr_comps ss)+ return ( vars+ , wrapFamInstBody (repr_ptups_tc ss) (repr_comp_tys ss)+ $ mkConApp ptups_con+ $ map Type (repr_comp_tys ss) ++ exprs)++ to_con xSums (ConRepr _ r)+ = to_prod xSums r++ to_comp expr (Keep _ _) = return expr+ to_comp expr (Wrap ty) = wrapNewTypeBodyOfPDatasWrap expr ty+++-- buildFromArrPReprs ---------------------------------------------------------+buildFromArrPReprs :: PAInstanceBuilder+buildFromArrPReprs vect_tc repr_co _ pdatas_tc r+ = do+ -- The argument type of the instance.+ -- eg: 'PDatas (PRepr (Tree a b))'+ arg_ty <- mkPDatasType =<< mkPReprType el_ty++ -- The result type.+ -- eg: 'PDatas (Tree a b)'+ res_ty <- mkPDatasType el_ty++ -- Variable to bind the argument to the instance+ -- eg: (xss :: PDatas (PRepr (Tree a b)))+ varg <- newLocalVar (fsLit "xss") arg_ty++ -- Build the coercion between PRepr and the instance type+ pdatas_co <- mkBuiltinCo pdatasTyCon+ let co = mkAppCo pdatas_co+ $ mkUnbranchedAxInstCo Nominal repr_co var_tys []++ let scrut = mkCast (Var varg) co++ let mk_result args+ = wrapFamInstBody pdatas_tc var_tys+ $ mkConApp pdatas_con+ $ map Type var_tys ++ args++ (expr, _) <- fixV $ \ ~(_, args) ->+ from_sum res_ty (mk_result args) scrut r++ return $ Lam varg expr+ where+ -- The element type of the argument.+ -- eg: 'Tree a b'.+ ty_args = mkTyVarTys $ tyConTyVars vect_tc+ el_ty = mkTyConApp vect_tc ty_args++ var_tys = mkTyVarTys $ tyConTyVars vect_tc+ [pdatas_con] = tyConDataCons pdatas_tc++ from_sum res_ty res expr ss+ = case ss of+ -- We can't convert data types with no data.+ -- See Note: [Empty PDatas].+ EmptySum -> do dflags <- getDynFlags+ return (res, errorEmptyPDatas dflags el_ty)+ UnarySum r -> from_con res_ty res expr r++ Sum {}+ -> do let psums_tc = repr_psums_tc ss+ let [psums_con] = tyConDataCons psums_tc+ sel <- newLocalVar (fsLit "sels") (repr_sels_ty ss)+ ptys <- mapM mkPDatasType (repr_con_tys ss)+ vars <- newLocalVars (fsLit "xs") ptys+ (res', args) <- fold from_con res_ty res (map Var vars) (repr_cons ss)+ let scrut = unwrapFamInstScrut psums_tc (repr_con_tys ss) expr+ let body = mkWildCase scrut (exprType scrut) res_ty+ [(DataAlt psums_con, sel : vars, res')]+ return (body, Var sel : args)++ from_prod res_ty res expr ss+ = case ss of+ EmptyProd -> return (res, [])+ UnaryProd r -> from_comp res_ty res expr r+ Prod {}+ -> do let ptups_tc = repr_ptups_tc ss+ let [ptups_con] = tyConDataCons ptups_tc+ ptys <- mapM mkPDatasType (repr_comp_tys ss)+ vars <- newLocalVars (fsLit "ys") ptys+ (res', args) <- fold from_comp res_ty res (map Var vars) (repr_comps ss)+ let scrut = unwrapFamInstScrut ptups_tc (repr_comp_tys ss) expr+ let body = mkWildCase scrut (exprType scrut) res_ty+ [(DataAlt ptups_con, vars, res')]+ return (body, args)++ from_con res_ty res expr (ConRepr _ r)+ = from_prod res_ty res expr r++ from_comp _ res expr (Keep _ _) = return (res, [expr])+ from_comp _ res expr (Wrap ty) = do { expr' <- unwrapNewTypeBodyOfPDatasWrap expr ty+ ; return (res, [expr'])+ }++ fold f res_ty res exprs rs+ = foldrM f' (res, []) (zip exprs rs)+ where+ f' (expr, r) (res, args)+ = do (res', args') <- f res_ty res expr r+ return (res', args' ++ args)+++-- Notes ----------------------------------------------------------------------+{-+Note [Empty PDatas]+~~~~~~~~~~~~~~~~~~~+We don't support "empty" data types like the following:++ data Empty0+ data Empty1 = MkEmpty1+ data Empty2 = MkEmpty2 Empty0+ ...++There is no parallel data associcated with these types, so there is no where+to store the length of the PDatas array with our standard representation.++Enumerations like the following are ok:+ data Bool = True | False++The native and generic representations are:+ type instance (PDatas Bool) = VPDs:Bool Sels2+ type instance (PDatas (Repr Bool)) = PSum2s Sels2 (PDatas Void) (PDatas Void)++To take the length of a (PDatas Bool) we take the length of the contained Sels2.+When converting a (PDatas Bool) to a (PDatas (Repr Bool)) we use this length to+initialise the two (PDatas Void) arrays.++However, with this:+ data Empty1 = MkEmpty1++The native and generic representations would be:+ type instance (PDatas Empty1) = VPDs:Empty1+ type instance (PDatas (Repr Empty1)) = PVoids Int++The 'Int' argument of PVoids is supposed to store the length of the PDatas+array. When converting the (PDatas Empty1) to a (PDatas (Repr Empty1)) we+need to come up with a value for it, but there isn't one.++To fix this we'd need to add an Int field to VPDs:Empty1 as well, but that's+too much hassle and there's no point running a parallel computation on no+data anyway.+-}+errorEmptyPDatas :: DynFlags -> Type -> a+errorEmptyPDatas dflags tc+ = cantVectorise dflags "Vectorise.PAMethods"+ $ vcat [ text "Cannot vectorise data type with no parallel data " <> quotes (ppr tc)+ , text "Data types to be vectorised must contain at least one constructor"+ , text "with at least one field." ]
+ vectorise/Vectorise/Generic/PData.hs view
@@ -0,0 +1,168 @@++-- | Build instance tycons for the PData and PDatas type families.+--+-- TODO: the PData and PDatas cases are very similar.+-- We should be able to factor out the common parts.+module Vectorise.Generic.PData+ ( buildPDataTyCon+ , buildPDatasTyCon )+where++import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Generic.Description+import Vectorise.Utils+import Vectorise.Env( GlobalEnv( global_fam_inst_env ) )++import BasicTypes ( SourceText(..) )+import BuildTyCl+import DataCon+import TyCon+import Type+import FamInst+import FamInstEnv+import TcMType+import Name+import Util+import MonadUtils+import Control.Monad+++-- buildPDataTyCon ------------------------------------------------------------+-- | Build the PData instance tycon for a given type constructor.+buildPDataTyCon :: TyCon -> TyCon -> SumRepr -> VM FamInst+buildPDataTyCon orig_tc vect_tc repr+ = fixV $ \fam_inst ->+ do let repr_tc = dataFamInstRepTyCon fam_inst+ name' <- mkLocalisedName mkPDataTyConOcc orig_name+ rhs <- buildPDataTyConRhs orig_name vect_tc repr_tc repr+ pdata <- builtin pdataTyCon+ buildDataFamInst name' pdata vect_tc rhs+ where+ orig_name = tyConName orig_tc++buildDataFamInst :: Name -> TyCon -> TyCon -> AlgTyConRhs -> VM FamInst+buildDataFamInst name' fam_tc vect_tc rhs+ = do { axiom_name <- mkDerivedName mkInstTyCoOcc name'++ ; (_, tyvars') <- liftDs $ freshenTyVarBndrs tyvars+ ; let ax = mkSingleCoAxiom Representational axiom_name tyvars' [] fam_tc pat_tys rep_ty+ tys' = mkTyVarTys tyvars'+ rep_ty = mkTyConApp rep_tc tys'+ pat_tys = [mkTyConApp vect_tc tys']+ rep_tc = mkAlgTyCon name'+ (mkTyConBindersPreferAnon tyvars' liftedTypeKind)+ liftedTypeKind+ (map (const Nominal) tyvars')+ Nothing+ [] -- no stupid theta+ rhs+ (DataFamInstTyCon ax fam_tc pat_tys)+ False -- not GADT syntax+ ; liftDs $ newFamInst (DataFamilyInst rep_tc) ax }+ where+ tyvars = tyConTyVars vect_tc++buildPDataTyConRhs :: Name -> TyCon -> TyCon -> SumRepr -> VM AlgTyConRhs+buildPDataTyConRhs orig_name vect_tc repr_tc repr+ = do data_con <- buildPDataDataCon orig_name vect_tc repr_tc repr+ return $ DataTyCon { data_cons = [data_con], is_enum = False }+++buildPDataDataCon :: Name -> TyCon -> TyCon -> SumRepr -> VM DataCon+buildPDataDataCon orig_name vect_tc repr_tc repr+ = do let tvs = tyConTyVars vect_tc+ dc_name <- mkLocalisedName mkPDataDataConOcc orig_name+ comp_tys <- mkSumTys repr_sel_ty mkPDataType repr+ fam_envs <- readGEnv global_fam_inst_env+ rep_nm <- liftDs $ newTyConRepName dc_name+ liftDs $ buildDataCon fam_envs dc_name+ False -- not infix+ rep_nm+ (map (const no_bang) comp_tys)+ (Just $ map (const HsLazy) comp_tys)+ [] -- no field labels+ (mkTyVarBinders Specified tvs)+ [] -- no existentials+ [] -- no eq spec+ [] -- no context+ comp_tys+ (mkFamilyTyConApp repr_tc (mkTyVarTys tvs))+ repr_tc+ where+ no_bang = HsSrcBang NoSourceText NoSrcUnpack NoSrcStrict+++-- buildPDatasTyCon -----------------------------------------------------------+-- | Build the PDatas instance tycon for a given type constructor.+buildPDatasTyCon :: TyCon -> TyCon -> SumRepr -> VM FamInst+buildPDatasTyCon orig_tc vect_tc repr+ = fixV $ \fam_inst ->+ do let repr_tc = dataFamInstRepTyCon fam_inst+ name' <- mkLocalisedName mkPDatasTyConOcc orig_name+ rhs <- buildPDatasTyConRhs orig_name vect_tc repr_tc repr+ pdatas <- builtin pdatasTyCon+ buildDataFamInst name' pdatas vect_tc rhs+ where+ orig_name = tyConName orig_tc++buildPDatasTyConRhs :: Name -> TyCon -> TyCon -> SumRepr -> VM AlgTyConRhs+buildPDatasTyConRhs orig_name vect_tc repr_tc repr+ = do data_con <- buildPDatasDataCon orig_name vect_tc repr_tc repr+ return $ DataTyCon { data_cons = [data_con], is_enum = False }+++buildPDatasDataCon :: Name -> TyCon -> TyCon -> SumRepr -> VM DataCon+buildPDatasDataCon orig_name vect_tc repr_tc repr+ = do let tvs = tyConTyVars vect_tc+ dc_name <- mkLocalisedName mkPDatasDataConOcc orig_name++ comp_tys <- mkSumTys repr_sels_ty mkPDatasType repr+ fam_envs <- readGEnv global_fam_inst_env+ rep_nm <- liftDs $ newTyConRepName dc_name+ liftDs $ buildDataCon fam_envs dc_name+ False -- not infix+ rep_nm+ (map (const no_bang) comp_tys)+ (Just $ map (const HsLazy) comp_tys)+ [] -- no field labels+ (mkTyVarBinders Specified tvs)+ [] -- no existentials+ [] -- no eq spec+ [] -- no context+ comp_tys+ (mkFamilyTyConApp repr_tc (mkTyVarTys tvs))+ repr_tc+ where+ no_bang = HsSrcBang NoSourceText NoSrcUnpack NoSrcStrict+++-- Utils ----------------------------------------------------------------------+-- | Flatten a SumRepr into a list of data constructor types.+mkSumTys+ :: (SumRepr -> Type)+ -> (Type -> VM Type)+ -> SumRepr+ -> VM [Type]++mkSumTys repr_selX_ty mkTc repr+ = sum_tys repr+ where+ sum_tys EmptySum = return []+ sum_tys (UnarySum r) = con_tys r+ sum_tys d@(Sum { repr_cons = cons })+ = liftM (repr_selX_ty d :) (concatMapM con_tys cons)++ con_tys (ConRepr _ r) = prod_tys r++ prod_tys EmptyProd = return []+ prod_tys (UnaryProd r) = liftM singleton (comp_ty r)+ prod_tys (Prod { repr_comps = comps }) = mapM comp_ty comps++ comp_ty r = mkTc (compOrigType r)++{-+mk_fam_inst :: TyCon -> TyCon -> (TyCon, [Type])+mk_fam_inst fam_tc arg_tc+ = (fam_tc, [mkTyConApp arg_tc . mkTyVarTys $ tyConTyVars arg_tc])+-}
+ vectorise/Vectorise/Monad.hs view
@@ -0,0 +1,195 @@+module Vectorise.Monad (+ module Vectorise.Monad.Base,+ module Vectorise.Monad.Naming,+ module Vectorise.Monad.Local,+ module Vectorise.Monad.Global,+ module Vectorise.Monad.InstEnv,+ initV,++ -- * Builtins+ liftBuiltinDs,+ builtin,+ builtins,++ -- * Variables+ lookupVar,+ lookupVar_maybe,+ addGlobalParallelVar,+ addGlobalParallelTyCon,+) where++import Vectorise.Monad.Base+import Vectorise.Monad.Naming+import Vectorise.Monad.Local+import Vectorise.Monad.Global+import Vectorise.Monad.InstEnv+import Vectorise.Builtins+import Vectorise.Env++import CoreSyn+import TcRnMonad+import DsMonad+import HscTypes hiding ( MonadThings(..) )+import DynFlags+import MonadUtils (liftIO)+import InstEnv+import Class+import TyCon+import NameSet+import VarSet+import VarEnv+import Var+import Id+import Name+import ErrUtils+import Outputable+import Module++import Control.Monad (join)++-- |Run a vectorisation computation.+--+initV :: HscEnv+ -> ModGuts+ -> VectInfo+ -> VM a+ -> IO (Maybe (VectInfo, a))+initV hsc_env guts info thing_inside+ = do { dumpIfVtTrace "Incoming VectInfo" (ppr info)++ ; (_, res) <- initDsWithModGuts hsc_env guts go+ ; case join res of+ Nothing+ -> dumpIfVtTrace "Vectorisation FAILED!" empty+ Just (info', _)+ -> dumpIfVtTrace "Outgoing VectInfo" (ppr info')++ ; return $ join res+ }+ where+ dflags = hsc_dflags hsc_env++ dumpIfVtTrace = dumpIfSet_dyn dflags Opt_D_dump_vt_trace++ bindsToIds (NonRec v _) = [v]+ bindsToIds (Rec binds) = map fst binds++ ids = concatMap bindsToIds (mg_binds guts)++ go+ = do { -- set up tables of builtin entities+ ; builtins <- initBuiltins+ ; builtin_vars <- initBuiltinVars builtins++ -- set up class and type family envrionments+ ; eps <- liftIO $ hscEPS hsc_env+ ; let famInstEnvs = (eps_fam_inst_env eps, mg_fam_inst_env guts)+ instEnvs = InstEnvs (eps_inst_env eps)+ (mg_inst_env guts)+ (mkModuleSet (dep_orphs (mg_deps guts)))+ builtin_pas = initClassDicts instEnvs (paClass builtins) -- grab all 'PA' and..+ builtin_prs = initClassDicts instEnvs (prClass builtins) -- ..'PR' class instances++ -- construct the initial global environment+ ; let genv = extendImportedVarsEnv builtin_vars+ . setPAFunsEnv builtin_pas+ . setPRFunsEnv builtin_prs+ $ initGlobalEnv (gopt Opt_VectorisationAvoidance dflags)+ info (mg_vect_decls guts) instEnvs famInstEnvs++ -- perform vectorisation+ ; r <- runVM thing_inside builtins genv emptyLocalEnv+ ; case r of+ Yes genv _ x -> return $ Just (new_info genv, x)+ No reason -> do { unqual <- mkPrintUnqualifiedDs+ ; liftIO $+ printOutputForUser dflags unqual $+ mkDumpDoc "Warning: vectorisation failure:" reason+ ; return Nothing+ }+ }++ new_info genv = modVectInfo genv ids (mg_tcs guts) (mg_vect_decls guts) info++ -- For a given DPH class, produce a mapping from type constructor (in head position) to the+ -- instance dfun for that type constructor and class. (DPH class instances cannot overlap in+ -- head constructors.)+ --+ initClassDicts :: InstEnvs -> Class -> [(Name, Var)]+ initClassDicts insts cls = map find $ classInstances insts cls+ where+ find i | [Just tc] <- instanceRoughTcs i = (tc, instanceDFunId i)+ | otherwise = pprPanic invalidInstance (ppr i)++ invalidInstance = "Invalid DPH instance (overlapping in head constructor)"++-- Builtins -------------------------------------------------------------------++-- |Lift a desugaring computation using the `Builtins` into the vectorisation monad.+--+liftBuiltinDs :: (Builtins -> DsM a) -> VM a+liftBuiltinDs p = VM $ \bi genv lenv -> do { x <- p bi; return (Yes genv lenv x)}++-- |Project something from the set of builtins.+--+builtin :: (Builtins -> a) -> VM a+builtin f = VM $ \bi genv lenv -> return (Yes genv lenv (f bi))++-- |Lift a function using the `Builtins` into the vectorisation monad.+--+builtins :: (a -> Builtins -> b) -> VM (a -> b)+builtins f = VM $ \bi genv lenv -> return (Yes genv lenv (`f` bi))+++-- Var ------------------------------------------------------------------------++-- |Lookup the vectorised, and if local, also the lifted version of a variable.+--+-- * If it's in the global environment we get the vectorised version.+-- * If it's in the local environment we get both the vectorised and lifted version.+--+lookupVar :: Var -> VM (Scope Var (Var, Var))+lookupVar v+ = do { mb_res <- lookupVar_maybe v+ ; case mb_res of+ Just x -> return x+ Nothing ->+ do dflags <- getDynFlags+ dumpVar dflags v+ }++lookupVar_maybe :: Var -> VM (Maybe (Scope Var (Var, Var)))+lookupVar_maybe v+ = do { r <- readLEnv $ \env -> lookupVarEnv (local_vars env) v+ ; case r of+ Just e -> return $ Just (Local e)+ Nothing -> fmap Global <$> (readGEnv $ \env -> lookupVarEnv (global_vars env) v)+ }++dumpVar :: DynFlags -> Var -> a+dumpVar dflags var+ | Just _ <- isClassOpId_maybe var+ = cantVectorise dflags "ClassOpId not vectorised:" (ppr var)+ | otherwise+ = cantVectorise dflags "Variable not vectorised:" (ppr var)+++-- Global parallel entities ----------------------------------------------------++-- |Mark the given variable as parallel — i.e., executing the associated code might involve+-- parallel array computations.+--+addGlobalParallelVar :: Var -> VM ()+addGlobalParallelVar var+ = do { traceVt "addGlobalParallelVar" (ppr var)+ ; updGEnv $ \env -> env{global_parallel_vars = extendDVarSet (global_parallel_vars env) var}+ }++-- |Mark the given type constructor as parallel — i.e., its values might embed parallel arrays.+--+addGlobalParallelTyCon :: TyCon -> VM ()+addGlobalParallelTyCon tycon+ = do { traceVt "addGlobalParallelTyCon" (ppr tycon)+ ; updGEnv $ \env ->+ env{global_parallel_tycons = extendNameSet (global_parallel_tycons env) (tyConName tycon)}+ }
+ vectorise/Vectorise/Monad/Base.hs view
@@ -0,0 +1,243 @@+-- |The Vectorisation monad.++module Vectorise.Monad.Base (+ -- * The Vectorisation Monad+ VResult(..),+ VM(..),++ -- * Lifting+ liftDs,++ -- * Error Handling+ cantVectorise,+ maybeCantVectorise,+ maybeCantVectoriseM,++ -- * Debugging+ emitVt, traceVt, dumpOptVt, dumpVt,++ -- * Control+ noV, traceNoV,+ ensureV, traceEnsureV,+ onlyIfV,+ tryV, tryErrV,+ maybeV, traceMaybeV,+ orElseV, orElseErrV,+ fixV,+) where++import Vectorise.Builtins+import Vectorise.Env++import DsMonad+import TcRnMonad+import ErrUtils+import Outputable+import DynFlags++import Control.Monad+++-- The Vectorisation Monad ----------------------------------------------------++-- |Vectorisation can either succeed with new envionment and a value, or return with failure+-- (including a description of the reason for failure).+--+data VResult a+ = Yes GlobalEnv LocalEnv a+ | No SDoc++newtype VM a+ = VM { runVM :: Builtins -> GlobalEnv -> LocalEnv -> DsM (VResult a) }++instance Monad VM where+ VM p >>= f = VM $ \bi genv lenv -> do+ r <- p bi genv lenv+ case r of+ Yes genv' lenv' x -> runVM (f x) bi genv' lenv'+ No reason -> return $ No reason++instance Applicative VM where+ pure x = VM $ \_ genv lenv -> return (Yes genv lenv x)+ (<*>) = ap++instance Functor VM where+ fmap = liftM++instance MonadIO VM where+ liftIO = liftDs . liftIO++instance HasDynFlags VM where+ getDynFlags = liftDs getDynFlags++-- Lifting --------------------------------------------------------------------++-- |Lift a desugaring computation into the vectorisation monad.+--+liftDs :: DsM a -> VM a+liftDs p = VM $ \_ genv lenv -> do { x <- p; return (Yes genv lenv x) }+++-- Error Handling -------------------------------------------------------------++-- |Throw a `pgmError` saying we can't vectorise something.+--+cantVectorise :: DynFlags -> String -> SDoc -> a+cantVectorise dflags s d = pgmError+ . showSDoc dflags+ $ vcat [text "*** Vectorisation error ***",+ nest 4 $ sep [text s, nest 4 d]]++-- |Like `fromJust`, but `pgmError` on Nothing.+--+maybeCantVectorise :: DynFlags -> String -> SDoc -> Maybe a -> a+maybeCantVectorise dflags s d Nothing = cantVectorise dflags s d+maybeCantVectorise _ _ _ (Just x) = x++-- |Like `maybeCantVectorise` but in a `Monad`.+--+maybeCantVectoriseM :: (Monad m, HasDynFlags m)+ => String -> SDoc -> m (Maybe a) -> m a+maybeCantVectoriseM s d p+ = do+ r <- p+ case r of+ Just x -> return x+ Nothing ->+ do dflags <- getDynFlags+ cantVectorise dflags s d+++-- Debugging ------------------------------------------------------------------++-- |Output a trace message if -ddump-vt-trace is active.+--+emitVt :: String -> SDoc -> VM ()+emitVt herald doc+ = liftDs $ do+ dflags <- getDynFlags+ liftIO . printOutputForUser dflags alwaysQualify $+ hang (text herald) 2 doc++-- |Output a trace message if -ddump-vt-trace is active.+--+traceVt :: String -> SDoc -> VM ()+traceVt herald doc+ = liftDs $ traceOptIf Opt_D_dump_vt_trace $ hang (text herald) 2 doc++-- |Dump the given program conditionally.+--+dumpOptVt :: DumpFlag -> String -> SDoc -> VM ()+dumpOptVt flag header doc+ = do { b <- liftDs $ doptM flag+ ; if b+ then dumpVt header doc+ else return ()+ }++-- |Dump the given program unconditionally.+--+dumpVt :: String -> SDoc -> VM ()+dumpVt header doc+ = do { unqual <- liftDs mkPrintUnqualifiedDs+ ; dflags <- liftDs getDynFlags+ ; liftIO $ printOutputForUser dflags unqual (mkDumpDoc header doc)+ }+++-- Control --------------------------------------------------------------------++-- |Return some result saying we've failed.+--+noV :: SDoc -> VM a+noV reason = VM $ \_ _ _ -> return $ No reason++-- |Like `traceNoV` but also emit some trace message to stderr.+--+traceNoV :: String -> SDoc -> VM a+traceNoV s d = pprTrace s d $ noV d++-- |If `True` then carry on, otherwise fail.+--+ensureV :: SDoc -> Bool -> VM ()+ensureV reason False = noV reason+ensureV _reason True = return ()++-- |Like `ensureV` but if we fail then emit some trace message to stderr.+--+traceEnsureV :: String -> SDoc -> Bool -> VM ()+traceEnsureV s d False = traceNoV s d+traceEnsureV _ _ True = return ()++-- |If `True` then return the first argument, otherwise fail.+--+onlyIfV :: SDoc -> Bool -> VM a -> VM a+onlyIfV reason b p = ensureV reason b >> p++-- |Try some vectorisation computaton.+--+-- If it succeeds then return `Just` the result; otherwise, return `Nothing` after emitting a+-- failure message.+--+tryErrV :: VM a -> VM (Maybe a)+tryErrV (VM p) = VM $ \bi genv lenv ->+ do+ r <- p bi genv lenv+ case r of+ Yes genv' lenv' x -> return (Yes genv' lenv' (Just x))+ No reason -> do { unqual <- mkPrintUnqualifiedDs+ ; dflags <- getDynFlags+ ; liftIO $+ printInfoForUser dflags unqual $+ text "Warning: vectorisation failure:" <+> reason+ ; return (Yes genv lenv Nothing)+ }++-- |Try some vectorisation computaton.+--+-- If it succeeds then return `Just` the result; otherwise, return `Nothing` without emitting a+-- failure message.+--+tryV :: VM a -> VM (Maybe a)+tryV (VM p) = VM $ \bi genv lenv ->+ do+ r <- p bi genv lenv+ case r of+ Yes genv' lenv' x -> return (Yes genv' lenv' (Just x))+ No _reason -> return (Yes genv lenv Nothing)++-- |If `Just` then return the value, otherwise fail.+--+maybeV :: SDoc -> VM (Maybe a) -> VM a+maybeV reason p = maybe (noV reason) return =<< p++-- |Like `maybeV` but emit a message to stderr if we fail.+--+traceMaybeV :: String -> SDoc -> VM (Maybe a) -> VM a+traceMaybeV s d p = maybe (traceNoV s d) return =<< p++-- |Try the first computation,+--+-- * if it succeeds then take the returned value,+-- * if it fails then run the second computation instead while emitting a failure message.+--+orElseErrV :: VM a -> VM a -> VM a+orElseErrV p q = maybe q return =<< tryErrV p++-- |Try the first computation,+--+-- * if it succeeds then take the returned value,+-- * if it fails then run the second computation instead without emitting a failure message.+--+orElseV :: VM a -> VM a -> VM a+orElseV p q = maybe q return =<< tryV p++-- |Fixpoint in the vectorisation monad.+--+fixV :: (a -> VM a) -> VM a+fixV f = VM (\bi genv lenv -> fixDs $ \r -> runVM (f (unYes r)) bi genv lenv )+ where+ -- NOTE: It is essential that we are lazy in r above so do not replace+ -- calls to this function by an explicit case.+ unYes (Yes _ _ x) = x+ unYes (No reason) = pprPanic "Vectorise.Monad.Base.fixV: no result" reason
+ vectorise/Vectorise/Monad/Global.hs view
@@ -0,0 +1,237 @@+-- Operations on the global state of the vectorisation monad.++module Vectorise.Monad.Global (+ readGEnv,+ setGEnv,+ updGEnv,++ -- * Configuration+ isVectAvoidanceAggressive,++ -- * Vars+ defGlobalVar, undefGlobalVar,++ -- * Vectorisation declarations+ lookupVectDecl,++ -- * Scalars+ globalParallelVars, globalParallelTyCons,++ -- * TyCons+ lookupTyCon,+ defTyConName, defTyCon, globalVectTyCons,++ -- * Datacons+ lookupDataCon,+ defDataCon,++ -- * PA Dictionaries+ lookupTyConPA,+ defTyConPAs,++ -- * PR Dictionaries+ lookupTyConPR+) where++import Vectorise.Monad.Base+import Vectorise.Env++import CoreSyn+import Type+import TyCon+import DataCon+import DynFlags+import NameEnv+import NameSet+import Name+import VarEnv+import VarSet+import Var as Var+import Outputable+++-- Global Environment ---------------------------------------------------------++-- |Project something from the global environment.+--+readGEnv :: (GlobalEnv -> a) -> VM a+readGEnv f = VM $ \_ genv lenv -> return (Yes genv lenv (f genv))++-- |Set the value of the global environment.+--+setGEnv :: GlobalEnv -> VM ()+setGEnv genv = VM $ \_ _ lenv -> return (Yes genv lenv ())++-- |Update the global environment using the provided function.+--+updGEnv :: (GlobalEnv -> GlobalEnv) -> VM ()+updGEnv f = VM $ \_ genv lenv -> return (Yes (f genv) lenv ())+++-- Configuration --------------------------------------------------------------++-- |Should we avoid as much vectorisation as possible?+--+-- Set by '-f[no]-vectorisation-avoidance'+--+isVectAvoidanceAggressive :: VM Bool+isVectAvoidanceAggressive = readGEnv global_vect_avoid+++-- Vars -----------------------------------------------------------------------++-- |Add a mapping between a global var and its vectorised version to the state.+--+defGlobalVar :: Var -> Var -> VM ()+defGlobalVar v v'+ = do { traceVt "add global var mapping:" (ppr v <+> text "-->" <+> ppr v')++ -- check for duplicate vectorisation+ ; currentDef <- readGEnv $ \env -> lookupVarEnv (global_vars env) v+ ; case currentDef of+ Just old_v' ->+ do dflags <- getDynFlags+ cantVectorise dflags "Variable is already vectorised:" $+ ppr v <+> moduleOf v old_v'+ Nothing -> return ()++ ; updGEnv $ \env -> env { global_vars = extendVarEnv (global_vars env) v v' }+ }+ where+ moduleOf var var' | var == var'+ = text "vectorises to itself"+ | Just mod <- nameModule_maybe (Var.varName var')+ = text "in module" <+> ppr mod+ | otherwise+ = text "in the current module"++-- |Remove the mapping of a variable in the vectorisation map.+--+undefGlobalVar :: Var -> VM ()+undefGlobalVar v+ = do+ { traceVt "REMOVING global var mapping:" (ppr v)+ ; updGEnv $ \env -> env { global_vars = delVarEnv (global_vars env) v }+ }+++-- Vectorisation declarations -------------------------------------------------++-- |Check whether a variable has a vectorisation declaration.+--+-- The first component of the result indicates whether the variable has a 'NOVECTORISE' declaration.+-- The second component contains the given type and expression in case of a 'VECTORISE' declaration.+--+lookupVectDecl :: Var -> VM (Bool, Maybe (Type, CoreExpr))+lookupVectDecl var+ = readGEnv $ \env ->+ case lookupVarEnv (global_vect_decls env) var of+ Nothing -> (False, Nothing)+ Just Nothing -> (True, Nothing)+ Just vectDecl -> (False, vectDecl)+++-- Parallel entities -----------------------------------------------------------++-- |Get the set of global parallel variables.+--+globalParallelVars :: VM DVarSet+globalParallelVars = readGEnv global_parallel_vars++-- |Get the set of all parallel type constructors (those that may embed parallelism) including both+-- both those parallel type constructors declared in an imported module and those declared in the+-- current module.+--+globalParallelTyCons :: VM NameSet+globalParallelTyCons = readGEnv global_parallel_tycons+++-- TyCons ---------------------------------------------------------------------++-- |Determine the vectorised version of a `TyCon`. The vectorisation map in the global environment+-- contains a vectorised version if the original `TyCon` embeds any parallel arrays.+--+lookupTyCon :: TyCon -> VM (Maybe TyCon)+lookupTyCon tc+ = readGEnv $ \env -> lookupNameEnv (global_tycons env) (tyConName tc)++-- |Add a mapping between plain and vectorised `TyCon`s to the global environment.+--+-- The second argument is only to enable tracing for (mutually) recursively defined type+-- constructors, where we /must not/ pull at the vectorised type constructors (because that would+-- pull too early at the recursive knot).+--+defTyConName :: TyCon -> Name -> TyCon -> VM ()+defTyConName tc nameOfTc' tc'+ = do { traceVt "add global tycon mapping:" (ppr tc <+> text "-->" <+> ppr nameOfTc')++ -- check for duplicate vectorisation+ ; currentDef <- readGEnv $ \env -> lookupNameEnv (global_tycons env) (tyConName tc)+ ; case currentDef of+ Just old_tc' ->+ do dflags <- getDynFlags+ cantVectorise dflags "Type constructor or class is already vectorised:" $+ ppr tc <+> moduleOf tc old_tc'+ Nothing -> return ()++ ; updGEnv $ \env ->+ env { global_tycons = extendNameEnv (global_tycons env) (tyConName tc) tc' }+ }+ where+ moduleOf tc tc' | tc == tc'+ = text "vectorises to itself"+ | Just mod <- nameModule_maybe (tyConName tc')+ = text "in module" <+> ppr mod+ | otherwise+ = text "in the current module"++-- |Add a mapping between plain and vectorised `TyCon`s to the global environment.+--+defTyCon :: TyCon -> TyCon -> VM ()+defTyCon tc tc' = defTyConName tc (tyConName tc') tc'++-- |Get the set of all vectorised type constructors.+--+globalVectTyCons :: VM (NameEnv TyCon)+globalVectTyCons = readGEnv global_tycons+++-- DataCons -------------------------------------------------------------------++-- |Lookup the vectorised version of a `DataCon` from the global environment.+--+lookupDataCon :: DataCon -> VM (Maybe DataCon)+lookupDataCon dc+ | isTupleTyCon (dataConTyCon dc)+ = return (Just dc)+ | otherwise+ = readGEnv $ \env -> lookupNameEnv (global_datacons env) (dataConName dc)++-- |Add the mapping between plain and vectorised `DataCon`s to the global environment.+--+defDataCon :: DataCon -> DataCon -> VM ()+defDataCon dc dc' = updGEnv $ \env ->+ env { global_datacons = extendNameEnv (global_datacons env) (dataConName dc) dc' }+++-- 'PA' dictionaries ------------------------------------------------------------++-- |Lookup the 'PA' dfun of a vectorised type constructor in the global environment.+--+lookupTyConPA :: TyCon -> VM (Maybe Var)+lookupTyConPA tc+ = readGEnv $ \env -> lookupNameEnv (global_pa_funs env) (tyConName tc)++-- |Associate vectorised type constructors with the dfun of their 'PA' instances in the global+-- environment.+--+defTyConPAs :: [(TyCon, Var)] -> VM ()+defTyConPAs ps = updGEnv $ \env ->+ env { global_pa_funs = extendNameEnvList (global_pa_funs env)+ [(tyConName tc, pa) | (tc, pa) <- ps] }+++-- PR Dictionaries ------------------------------------------------------------++lookupTyConPR :: TyCon -> VM (Maybe Var)+lookupTyConPR tc = readGEnv $ \env -> lookupNameEnv (global_pr_funs env) (tyConName tc)
+ vectorise/Vectorise/Monad/InstEnv.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE CPP #-}++module Vectorise.Monad.InstEnv+ ( existsInst+ , lookupInst+ , lookupFamInst+ )+where++import Vectorise.Monad.Global+import Vectorise.Monad.Base+import Vectorise.Env++import DynFlags+import FamInstEnv+import InstEnv+import Class+import Type+import TyCon+import Outputable+import Util+++#include "HsVersions.h"+++-- Check whether a unique class instance for a given class and type arguments exists.+--+existsInst :: Class -> [Type] -> VM Bool+existsInst cls tys+ = do { instEnv <- readGEnv global_inst_env+ ; return $ either (const False) (const True) (lookupUniqueInstEnv instEnv cls tys)+ }++-- Look up the dfun of a class instance.+--+-- The match must be unique —i.e., match exactly one instance— but the+-- type arguments used for matching may be more specific than those of+-- the class instance declaration. The found class instances must not have+-- any type variables in the instance context that do not appear in the+-- instances head (i.e., no flexi vars); for details for what this means,+-- see the docs at InstEnv.lookupInstEnv.+--+lookupInst :: Class -> [Type] -> VM (DFunId, [Type])+lookupInst cls tys+ = do { instEnv <- readGEnv global_inst_env+ ; case lookupUniqueInstEnv instEnv cls tys of+ Right (inst, inst_tys) -> return (instanceDFunId inst, inst_tys)+ Left err ->+ do dflags <- getDynFlags+ cantVectorise dflags "Vectorise.Monad.InstEnv.lookupInst:" err+ }++-- Look up a family instance.+--+-- The match must be unique - ie, match exactly one instance - but the+-- type arguments used for matching may be more specific than those of+-- the family instance declaration.+--+-- Return the family instance and its type instance. For example, if we have+--+-- lookupFamInst 'T' '[Int]' yields (':R42T', 'Int')+--+-- then we have a coercion (ie, type instance of family instance coercion)+--+-- :Co:R42T Int :: T [Int] ~ :R42T Int+--+-- which implies that :R42T was declared as 'data instance T [a]'.+--+lookupFamInst :: TyCon -> [Type] -> VM FamInstMatch+lookupFamInst tycon tys+ = ASSERT( isOpenFamilyTyCon tycon )+ do { instEnv <- readGEnv global_fam_inst_env+ ; case lookupFamInstEnv instEnv tycon tys of+ [match] -> return match+ _other ->+ do dflags <- getDynFlags+ cantVectorise dflags "Vectorise.Monad.InstEnv.lookupFamInst: not found: "+ (ppr $ mkTyConApp tycon tys)+ }
+ vectorise/Vectorise/Monad/Local.hs view
@@ -0,0 +1,100 @@+module Vectorise.Monad.Local+ ( readLEnv+ , setLEnv+ , updLEnv+ , localV+ , closedV+ , getBindName+ , inBind+ , lookupTyVarPA+ , defLocalTyVar+ , defLocalTyVarWithPA+ , localTyVars+ )+where++import Vectorise.Monad.Base+import Vectorise.Env++import CoreSyn+import Name+import VarEnv+import Var+import FastString++-- Local Environment ----------------------------------------------------------++-- |Project something from the local environment.+--+readLEnv :: (LocalEnv -> a) -> VM a+readLEnv f = VM $ \_ genv lenv -> return (Yes genv lenv (f lenv))++-- |Set the local environment.+--+setLEnv :: LocalEnv -> VM ()+setLEnv lenv = VM $ \_ genv _ -> return (Yes genv lenv ())++-- |Update the environment using the provided function.+--+updLEnv :: (LocalEnv -> LocalEnv) -> VM ()+updLEnv f = VM $ \_ genv lenv -> return (Yes genv (f lenv) ())++-- |Perform a computation in its own local environment.+-- This does not alter the environment of the current state.+--+localV :: VM a -> VM a+localV p+ = do+ { env <- readLEnv id+ ; x <- p+ ; setLEnv env+ ; return x+ }++-- |Perform a computation in an empty local environment.+--+closedV :: VM a -> VM a+closedV p+ = do+ { env <- readLEnv id+ ; setLEnv (emptyLocalEnv { local_bind_name = local_bind_name env })+ ; x <- p+ ; setLEnv env+ ; return x+ }++-- |Get the name of the local binding currently being vectorised.+--+getBindName :: VM FastString+getBindName = readLEnv local_bind_name++-- |Run a vectorisation computation in a local environment,+-- with this id set as the current binding.+--+inBind :: Id -> VM a -> VM a+inBind id p+ = do updLEnv $ \env -> env { local_bind_name = occNameFS (getOccName id) }+ p++-- |Lookup a PA tyvars from the local environment.+lookupTyVarPA :: Var -> VM (Maybe CoreExpr)+lookupTyVarPA tv+ = readLEnv $ \env -> lookupVarEnv (local_tyvar_pa env) tv++-- |Add a tyvar to the local environment.+defLocalTyVar :: TyVar -> VM ()+defLocalTyVar tv = updLEnv $ \env ->+ env { local_tyvars = tv : local_tyvars env+ , local_tyvar_pa = local_tyvar_pa env `delVarEnv` tv+ }++-- |Add mapping between a tyvar and pa dictionary to the local environment.+defLocalTyVarWithPA :: TyVar -> CoreExpr -> VM ()+defLocalTyVarWithPA tv pa = updLEnv $ \env ->+ env { local_tyvars = tv : local_tyvars env+ , local_tyvar_pa = extendVarEnv (local_tyvar_pa env) tv pa+ }++-- |Get the set of tyvars from the local environment.+localTyVars :: VM [TyVar]+localTyVars = readLEnv (reverse . local_tyvars)
+ vectorise/Vectorise/Monad/Naming.hs view
@@ -0,0 +1,130 @@+-- |Computations in the vectorisation monad concerned with naming and fresh variable generation.++module Vectorise.Monad.Naming+ ( mkLocalisedName+ , mkDerivedName+ , mkVectId+ , cloneVar+ , newExportedVar+ , newLocalVar+ , newLocalVars+ , newDummyVar+ , newTyVar+ , newCoVar+ )+where++import Vectorise.Monad.Base++import DsMonad+import TcType+import Type+import Var+import Module+import Name+import SrcLoc+import MkId+import Id+import IdInfo( IdDetails(VanillaId) )+import FastString++import Control.Monad+++-- Naming ---------------------------------------------------------------------++-- |Create a localised variant of a name, using the provided function to transform its `OccName`.+--+-- If the name external, encode the original name's module into the new 'OccName'. The result is+-- always an internal system name.+--+mkLocalisedName :: (Maybe String -> OccName -> OccName) -> Name -> VM Name+mkLocalisedName mk_occ name+ = do { mod <- liftDs getModule+ ; u <- liftDs newUnique+ ; let occ_name = mkLocalisedOccName mod mk_occ name++ new_name | isExternalName name = mkExternalName u mod occ_name (nameSrcSpan name)+ | otherwise = mkSystemName u occ_name++ ; return new_name }++mkDerivedName :: (OccName -> OccName) -> Name -> VM Name+-- Similar to mkLocalisedName, but assumes the+-- incoming name is from this module.+-- Works on External names only+mkDerivedName mk_occ name+ = do { u <- liftDs newUnique+ ; return (mkExternalName u (nameModule name)+ (mk_occ (nameOccName name))+ (nameSrcSpan name)) }++-- |Produce the vectorised variant of an `Id` with the given vectorised type, while taking care that+-- vectorised dfun ids must be dfuns again.+--+-- Force the new name to be a system name and, if the original was an external name, disambiguate+-- the new name with the module name of the original.+--+mkVectId :: Id -> Type -> VM Id+mkVectId id ty+ = do { name <- mkLocalisedName mkVectOcc (getName id)+ ; let id' | isDFunId id = MkId.mkDictFunId name tvs theta cls tys+ | isExportedId id = Id.mkExportedLocalId VanillaId name ty+ | otherwise = Id.mkLocalIdOrCoVar name ty+ ; return id'+ }+ where+ -- Decompose a dictionary function signature: \forall tvs. theta -> cls tys+ -- NB: We do *not* use closures '(:->)' for vectorised predicate abstraction as dictionary+ -- functions are always fully applied.+ (tvs, theta, pty) = tcSplitSigmaTy ty+ (cls, tys) = tcSplitDFunHead pty++-- |Make a fresh instance of this var, with a new unique.+--+cloneVar :: Var -> VM Var+cloneVar var = liftM (setIdUnique var) (liftDs newUnique)++-- |Make a fresh exported variable with the given type.+--+newExportedVar :: OccName -> Type -> VM Var+newExportedVar occ_name ty+ = do mod <- liftDs getModule+ u <- liftDs newUnique++ let name = mkExternalName u mod occ_name noSrcSpan++ return $ Id.mkExportedLocalId VanillaId name ty++-- |Make a fresh local variable with the given type.+-- The variable's name is formed using the given string as the prefix.+--+newLocalVar :: FastString -> Type -> VM Var+newLocalVar fs ty+ = do u <- liftDs newUnique+ return $ mkSysLocalOrCoVar fs u ty++-- |Make several fresh local variables with the given types.+-- The variable's names are formed using the given string as the prefix.+--+newLocalVars :: FastString -> [Type] -> VM [Var]+newLocalVars fs = mapM (newLocalVar fs)++-- |Make a new local dummy variable.+--+newDummyVar :: Type -> VM Var+newDummyVar = newLocalVar (fsLit "vv")++-- |Make a fresh type variable with the given kind.+-- The variable's name is formed using the given string as the prefix.+--+newTyVar :: FastString -> Kind -> VM Var+newTyVar fs k+ = do u <- liftDs newUnique+ return $ mkTyVar (mkSysTvName u fs) k++-- |Make a fresh coercion variable with the given kind.+newCoVar :: FastString -> Kind -> VM Var+newCoVar fs k+ = do u <- liftDs newUnique+ return $ mkCoVar (mkSystemVarName u fs) k
+ vectorise/Vectorise/Type/Classify.hs view
@@ -0,0 +1,128 @@+-- Extract from a list of type constructors those (1) which need to be vectorised and (2) those+-- that could be, but need not be vectorised (as a scalar representation is sufficient and more+-- efficient). The type constructors that cannot be vectorised will be dropped.+--+-- A type constructor will only be vectorised if it is+--+-- (1) a data type constructor, with vanilla data constructors (i.e., data constructors admitted by+-- Haskell 98) and+-- (2) at least one of the type constructors that appears in its definition is also vectorised.+--+-- If (1) is met, but not (2), the type constructor may appear in vectorised code, but there is no+-- need to vectorise that type constructor itself. This holds, for example, for all enumeration+-- types. As '([::])' is being vectorised, any type constructor whose definition involves+-- '([::])', either directly or indirectly, will be vectorised.++module Vectorise.Type.Classify+ ( classifyTyCons+ )+where++import NameSet+import UniqSet+import UniqFM+import DataCon+import TyCon+import TyCoRep+import qualified Type+import PrelNames+import Digraph++-- |From a list of type constructors, extract those that can be vectorised, returning them in two+-- sets, where the first result list /must be/ vectorised and the second result list /need not be/+-- vectorised. The third result list are those type constructors that we cannot convert (either+-- because they use language extensions or because they dependent on type constructors for which+-- no vectorised version is available).+--+-- NB: In order to be able to vectorise a type constructor, we require members of the depending set+-- (i.e., those type constructors that the current one depends on) to be vectorised only if they+-- are also parallel (i.e., appear in the second argument to the function).+--+-- The first argument determines the /conversion status/ of external type constructors as follows:+--+-- * tycons which have converted versions are mapped to 'True'+-- * tycons which are not changed by vectorisation are mapped to 'False'+-- * tycons which haven't been converted (because they can't or weren't vectorised) are not+-- elements of the map+--+classifyTyCons :: UniqFM Bool -- ^type constructor vectorisation status+ -> NameSet -- ^tycons involving parallel arrays+ -> [TyCon] -- ^type constructors that need to be classified+ -> ( [TyCon] -- to be converted+ , [TyCon] -- need not be converted (but could be)+ , [TyCon] -- involve parallel arrays (whether converted or not)+ , [TyCon] -- can't be converted+ )+classifyTyCons convStatus parTyCons tcs = classify [] [] [] [] convStatus parTyCons (tyConGroups tcs)+ where+ classify conv keep par novect _ _ [] = (conv, keep, par, novect)+ classify conv keep par novect cs pts ((tcs, ds) : rs)+ | can_convert && must_convert+ = classify (tcs ++ conv) keep (par ++ tcs_par) novect (cs `addListToUFM` [(tc, True) | tc <- tcs]) pts' rs+ | can_convert+ = classify conv (tcs ++ keep) (par ++ tcs_par) novect (cs `addListToUFM` [(tc, False) | tc <- tcs]) pts' rs+ | otherwise+ = classify conv keep (par ++ tcs_par) (tcs ++ novect) cs pts' rs+ where+ refs = ds `delListFromUniqSet` tcs++ -- the tycons that directly or indirectly depend on parallel arrays+ tcs_par | uniqSetAny ((`elemNameSet` parTyCons) . tyConName) refs = tcs+ | otherwise = []++ pts' = pts `extendNameSetList` map tyConName tcs_par++ can_convert = (isEmptyUniqSet (filterUniqSet ((`elemNameSet` pts) . tyConName) (refs `uniqSetMinusUFM` cs))+ && all convertable tcs)+ || isShowClass tcs+ must_convert = anyUFM id (intersectUFM_C const cs (getUniqSet refs))+ && (not . isShowClass $ tcs)++ -- We currently admit Haskell 2011-style data and newtype declarations as well as type+ -- constructors representing classes.+ convertable tc+ = (isDataTyCon tc || isNewTyCon tc) && all isVanillaDataCon (tyConDataCons tc)+ || isClassTyCon tc++ -- !!!FIXME: currently we allow 'Show' in vectorised code without actually providing a+ -- vectorised definition (to be able to vectorise 'Num')+ isShowClass [tc] = tyConName tc == showClassName+ isShowClass _ = False++-- Used to group type constructors into mutually dependent groups.+--+type TyConGroup = ([TyCon], UniqSet TyCon)++-- Compute mutually recursive groups of tycons in topological order.+--+tyConGroups :: [TyCon] -> [TyConGroup]+tyConGroups tcs = map mk_grp (stronglyConnCompFromEdgedVerticesUniq edges)+ where+ edges = [((tc, ds), tc, nonDetEltsUniqSet ds) | tc <- tcs+ , let ds = tyConsOfTyCon tc]+ -- It's OK to use nonDetEltsUniqSet here as+ -- stronglyConnCompFromEdgedVertices is still deterministic even+ -- if the edges are in nondeterministic order as explained in+ -- Note [Deterministic SCC] in Digraph.++ mk_grp (AcyclicSCC (tc, ds)) = ([tc], ds)+ mk_grp (CyclicSCC els) = (tcs, unionManyUniqSets dss)+ where+ (tcs, dss) = unzip els++-- |Collect the set of TyCons used by the representation of some data type.+--+tyConsOfTyCon :: TyCon -> UniqSet TyCon+tyConsOfTyCon = tyConsOfTypes . concatMap dataConRepArgTys . tyConDataCons++-- |Collect the set of TyCons that occur in these types.+--+tyConsOfTypes :: [Type] -> UniqSet TyCon+tyConsOfTypes = unionManyUniqSets . map tyConsOfType++-- |Collect the set of TyCons that occur in this type.+--+tyConsOfType :: Type -> UniqSet TyCon+tyConsOfType ty = filterUniqSet not_tuple_or_unlifted $ Type.tyConsOfType ty+ where not_tuple_or_unlifted tc = not (isUnliftedTyCon tc || isTupleTyCon tc)+
+ vectorise/Vectorise/Type/Env.hs view
@@ -0,0 +1,455 @@+{-# LANGUAGE CPP #-}++-- Vectorise a modules type and class declarations.+--+-- This produces new type constructors and family instances top be included in the module toplevel+-- as well as bindings for worker functions, dfuns, and the like.++module Vectorise.Type.Env (+ vectTypeEnv,+) where++#include "HsVersions.h"++import Vectorise.Env+import Vectorise.Vect+import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Type.TyConDecl+import Vectorise.Type.Classify+import Vectorise.Generic.PADict+import Vectorise.Generic.PAMethods+import Vectorise.Generic.PData+import Vectorise.Generic.Description+import Vectorise.Utils++import CoreSyn+import CoreUtils+import CoreUnfold+import DataCon+import TyCon+import CoAxiom+import Type+import FamInstEnv+import Id+import MkId+import NameEnv+import NameSet+import UniqFM+import OccName+import Unique++import Util+import Outputable+import DynFlags+import FastString+import MonadUtils++import Control.Monad+import Data.Maybe+import Data.List+++-- Note [Pragmas to vectorise tycons]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- All imported type constructors that are not mapped to a vectorised type in the vectorisation map+-- (possibly because the defining module was not compiled with vectorisation) may be used in scalar+-- code encapsulated in vectorised code. If a such a type constructor 'T' is a member of the+-- 'Scalar' class (and hence also of 'PData' and 'PRepr'), it may also be used in vectorised code,+-- where 'T' represents itself, but the representation of 'T' still remains opaque in vectorised+-- code (i.e., it can only be used in scalar code).+--+-- An example is the treatment of 'Int'. 'Int's can be used in vectorised code and remain unchanged+-- by vectorisation. However, the representation of 'Int' by the 'I#' data constructor wrapping an+-- 'Int#' is not exposed in vectorised code. Instead, computations involving the representation need+-- to be confined to scalar code.+--+-- VECTORISE pragmas for type constructors cover four different flavours of vectorising data type+-- constructors:+--+-- (1) Data type constructor 'T' that together with its constructors 'Cn' may be used in vectorised+-- code, where 'T' and the 'Cn' are automatically vectorised in the same manner as data types+-- declared in a vectorised module. This includes the case where the vectoriser determines that+-- the original representation of 'T' may be used in vectorised code (as it does not embed any+-- parallel arrays.) This case is for type constructors that are *imported* from a non-+-- vectorised module, but that we want to use with full vectorisation support.+--+-- An example is the treatment of 'Ordering' and '[]'. The former remains unchanged by+-- vectorisation, whereas the latter is fully vectorised.+--+-- 'PData' and 'PRepr' instances are automatically generated by the vectoriser.+--+-- Type constructors declared with {-# VECTORISE type T #-} are treated in this manner.+--+-- (2) Data type constructor 'T' that may be used in vectorised code, where 'T' is represented by an+-- explicitly given 'Tv', but the representation of 'T' is opaque in vectorised code (i.e., the+-- constructors of 'T' may not occur in vectorised code).+--+-- An example is the treatment of '[::]'. The type '[::]' can be used in vectorised code and is+-- vectorised to 'PArray'. However, the representation of '[::]' is not exposed in vectorised+-- code. Instead, computations involving the representation need to be confined to scalar code.+--+-- 'PData' and 'PRepr' instances need to be explicitly supplied for 'T' (they are not generated+-- by the vectoriser).+--+-- Type constructors declared with {-# VECTORISE type T = Tv #-} are treated in this manner+-- manner. (The vectoriser never treats a type constructor automatically in this manner.)+--+-- (3) Data type constructor 'T' that does not contain any parallel arrays and has explicitly+-- provided 'PData' and 'PRepr' instances (and maybe also a 'Scalar' instance), which together+-- with the type's constructors 'Cn' may be used in vectorised code. The type 'T' and its+-- constructors 'Cn' are represented by themselves in vectorised code.+--+-- An example is 'Bool', which is represented by itself in vectorised code (as it cannot embed+-- any parallel arrays). However, we do not want any automatic generation of class and family+-- instances, which is why Case (1) does not apply.+--+-- 'PData' and 'PRepr' instances need to be explicitly supplied for 'T' (they are not generated+-- by the vectoriser).+--+-- Type constructors declared with {-# VECTORISE SCALAR type T #-} are treated in this manner.+--+-- (4) Data type constructor 'T' that does not contain any parallel arrays and that, in vectorised+-- code, is represented by an explicitly given 'Tv', but the representation of 'T' is opaque in+-- vectorised code and 'T' is regarded to be scalar — i.e., it may be used in encapsulated+-- scalar subcomputations.+--+-- An example is the treatment of '(->)'. Types '(->)' can be used in vectorised code and are+-- vectorised to '(:->)'. However, the representation of '(->)' is not exposed in vectorised+-- code. Instead, computations involving the representation need to be confined to scalar code+-- and may be part of encapsulated scalar computations.+--+-- 'PData' and 'PRepr' instances need to be explicitly supplied for 'T' (they are not generated+-- by the vectoriser).+--+-- Type constructors declared with {-# VECTORISE SCALAR type T = Tv #-} are treated in this+-- manner. (The vectoriser never treats a type constructor automatically in this manner.)+--+-- In addition, we have also got a single pragma form for type classes: {-# VECTORISE class C #-}.+-- It implies that the class type constructor may be used in vectorised code together with its data+-- constructor. We generally produce a vectorised version of the data type and data constructor.+-- We do not generate 'PData' and 'PRepr' instances for class type constructors. This pragma is the+-- default for all type classes declared in a vectorised module, but the pragma can also be used+-- explitly on imported classes.++-- Note [Vectorising classes]+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~+--+-- We vectorise classes essentially by just vectorising their desugared Core representation, but we+-- do generate a 'Class' structure along the way (see 'Vectorise.Type.TyConDecl.vectTyConDecl').+--+-- Here is an example illustrating the mapping — assume+--+-- class Num a where+-- (+) :: a -> a -> a+--+-- It desugars to+--+-- data Num a = D:Num { (+) :: a -> a -> a }+--+-- which we vectorise to+--+-- data V:Num a = D:V:Num { ($v+) :: PArray a :-> PArray a :-> PArray a }+--+-- while adding the following entries to the vectorisation map:+--+-- tycon : Num --> V:Num+-- datacon: D:Num --> D:V:Num+-- var : (+) --> ($v+)++-- |Vectorise type constructor including class type constructors.+--+vectTypeEnv :: [TyCon] -- Type constructors defined in this module+ -> [CoreVect] -- All 'VECTORISE [SCALAR] type' declarations in this module+ -> [CoreVect] -- All 'VECTORISE class' declarations in this module+ -> VM ( [TyCon] -- old TyCons ++ new TyCons+ , [FamInst] -- New type family instances.+ , [(Var, CoreExpr)]) -- New top level bindings.+vectTypeEnv tycons vectTypeDecls vectClassDecls+ = do { traceVt "** vectTypeEnv" $ ppr tycons++ ; let -- {-# VECTORISE type T -#} (ONLY the imported tycons)+ impVectTyCons = ( [tycon | VectType False tycon Nothing <- vectTypeDecls]+ ++ [tycon | VectClass tycon <- vectClassDecls])+ \\ tycons++ -- {-# VECTORISE type T = Tv -#} (imported & local tycons with an /RHS/)+ vectTyConsWithRHS = [ (tycon, rhs)+ | VectType False tycon (Just rhs) <- vectTypeDecls]++ -- {-# VECTORISE SCALAR type T = Tv -#} (imported & local tycons with an /RHS/)+ scalarTyConsWithRHS = [ (tycon, rhs)+ | VectType True tycon (Just rhs) <- vectTypeDecls]++ -- {-# VECTORISE SCALAR type T -#} (imported & local /scalar/ tycons without an RHS)+ scalarTyConsNoRHS = [tycon | VectType True tycon Nothing <- vectTypeDecls]++ -- Check that is not a VECTORISE SCALAR tycon nor VECTORISE tycons with explicit rhs?+ vectSpecialTyConNames = mkNameSet . map tyConName $+ scalarTyConsNoRHS +++ map fst (vectTyConsWithRHS ++ scalarTyConsWithRHS)+ notVectSpecialTyCon tc = not $ (tyConName tc) `elemNameSet` vectSpecialTyConNames++ -- Build a map containing all vectorised type constructor. If the vectorised type+ -- constructor differs from the original one, then it is mapped to 'True'; if they are+ -- both the same, then it maps to 'False'.+ ; vectTyCons <- globalVectTyCons+ ; let vectTyConBase = mapUFM_Directly isDistinct vectTyCons -- 'True' iff tc /= V[[tc]]+ isDistinct u tc = u /= getUnique tc+ vectTyConFlavour = vectTyConBase+ `plusNameEnv`+ mkNameEnv [ (tyConName tycon, True)+ | (tycon, _) <- vectTyConsWithRHS ++ scalarTyConsWithRHS]+ `plusNameEnv`+ mkNameEnv [ (tyConName tycon, False) -- original representation+ | tycon <- scalarTyConsNoRHS]+++ -- Split the list of 'TyCons' into the ones (1) that we must vectorise and those (2)+ -- that we could, but don't need to vectorise. Type constructors that are not data+ -- type constructors or use non-Haskell98 features are being dropped. They may not+ -- appear in vectorised code. (We also drop the local type constructors appearing in a+ -- VECTORISE SCALAR pragma or a VECTORISE pragma with an explicit right-hand side, as+ -- these are being handled separately. NB: Some type constructors may be marked SCALAR+ -- /and/ have an explicit right-hand side.)+ --+ -- Furthermore, 'par_tcs' are those type constructors (converted or not) whose+ -- definition, directly or indirectly, depends on parallel arrays. Finally, 'drop_tcs'+ -- are all type constructors that cannot be vectorised.+ ; parallelTyCons <- (`extendNameSetList` map (tyConName . fst) vectTyConsWithRHS) <$>+ globalParallelTyCons+ ; let maybeVectoriseTyCons = filter notVectSpecialTyCon tycons ++ impVectTyCons+ (conv_tcs, keep_tcs, par_tcs, drop_tcs)+ = classifyTyCons vectTyConFlavour parallelTyCons maybeVectoriseTyCons++ ; traceVt " known parallel : " $ ppr parallelTyCons+ ; traceVt " VECT SCALAR : " $ ppr (scalarTyConsNoRHS ++ map fst scalarTyConsWithRHS)+ ; traceVt " VECT [class] : " $ ppr impVectTyCons+ ; traceVt " VECT with rhs : " $ ppr (map fst (vectTyConsWithRHS ++ scalarTyConsWithRHS))+ ; traceVt " -- after classification (local and VECT [class] tycons) --" Outputable.empty+ ; traceVt " reuse : " $ ppr keep_tcs+ ; traceVt " convert : " $ ppr conv_tcs++ -- warn the user about unvectorised type constructors+ ; let explanation = text "(They use unsupported language extensions"+ $$ text "or depend on type constructors that are" <+>+ text "not vectorised)"+ drop_tcs_nosyn = filter (not . isTypeFamilyTyCon) .+ filter (not . isTypeSynonymTyCon) $ drop_tcs+ ; unless (null drop_tcs_nosyn) $+ emitVt "Warning: cannot vectorise these type constructors:" $+ pprQuotedList drop_tcs_nosyn $$ explanation++ ; mapM_ addParallelTyConAndCons $ par_tcs ++ map fst vectTyConsWithRHS++ ; let mapping =+ -- Type constructors that we found we don't need to vectorise and those+ -- declared VECTORISE SCALAR /without/ an explicit right-hand side, use the same+ -- representation in both unvectorised and vectorised code; they are not+ -- abstract.+ [(tycon, tycon, False) | tycon <- keep_tcs ++ scalarTyConsNoRHS]+ -- We do the same for type constructors declared VECTORISE SCALAR /without/+ -- an explicit right-hand side+ ++ [(tycon, vTycon, True) | (tycon, vTycon) <- vectTyConsWithRHS ++ scalarTyConsWithRHS]+ ; syn_tcs <- catMaybes <$> mapM defTyConDataCons mapping++ -- Vectorise all the data type declarations that we can and must vectorise (enter the+ -- type and data constructors into the vectorisation map on-the-fly.)+ ; new_tcs <- vectTyConDecls conv_tcs++ ; let dumpTc tc vTc = traceVt "---" (ppr tc <+> text "::" <+> ppr (dataConSig tc) $$+ ppr vTc <+> text "::" <+> ppr (dataConSig vTc))+ dataConSig tc | Just dc <- tyConSingleDataCon_maybe tc = dataConRepType dc+ | otherwise = panic "dataConSig"+ ; zipWithM_ dumpTc (filter isClassTyCon conv_tcs) (filter isClassTyCon new_tcs)++ -- We don't need new representation types for dictionary constructors. The constructors+ -- are always fully applied, and we don't need to lift them to arrays as a dictionary+ -- of a particular type always has the same value.+ ; let orig_tcs = filter (not . isClassTyCon) $ keep_tcs ++ conv_tcs+ vect_tcs = filter (not . isClassTyCon) $ keep_tcs ++ new_tcs++ -- Build 'PRepr' and 'PData' instance type constructors and family instances for all+ -- type constructors with vectorised representations.+ ; reprs <- mapM tyConRepr vect_tcs+ ; repr_fis <- zipWith3M buildPReprTyCon orig_tcs vect_tcs reprs+ ; pdata_fis <- zipWith3M buildPDataTyCon orig_tcs vect_tcs reprs+ ; pdatas_fis <- zipWith3M buildPDatasTyCon orig_tcs vect_tcs reprs++ ; let fam_insts = repr_fis ++ pdata_fis ++ pdatas_fis+ repr_axs = map famInstAxiom repr_fis+ pdata_tcs = famInstsRepTyCons pdata_fis+ pdatas_tcs = famInstsRepTyCons pdatas_fis++ ; updGEnv $ extendFamEnv fam_insts++ -- Generate workers for the vectorised data constructors, dfuns for the 'PA' instances of+ -- the vectorised type constructors, and associate the type constructors with their dfuns+ -- in the global environment. We get back the dfun bindings (which we will subsequently+ -- inject into the modules toplevel).+ ; (_, binds) <- fixV $ \ ~(dfuns, _) ->+ do { defTyConPAs (zipLazy vect_tcs dfuns)++ -- Query the 'PData' instance type constructors for type constructors that have a+ -- VECTORISE SCALAR type pragma without an explicit right-hand side (this is Item+ -- (3) of "Note [Pragmas to vectorise tycons]" above).+ ; pdata_scalar_tcs <- mapM pdataReprTyConExact scalarTyConsNoRHS++ -- Build workers for all vectorised data constructors (except abstract ones)+ ; sequence_ $+ zipWith3 vectDataConWorkers (orig_tcs ++ scalarTyConsNoRHS)+ (vect_tcs ++ scalarTyConsNoRHS)+ (pdata_tcs ++ pdata_scalar_tcs)++ -- Build a 'PA' dictionary for all type constructors (except abstract ones & those+ -- defined with an explicit right-hand side where the dictionary is user-supplied)+ ; dfuns <- sequence $+ zipWith4 buildTyConPADict+ vect_tcs+ repr_axs+ pdata_tcs+ pdatas_tcs++ ; binds <- takeHoisted+ ; return (dfuns, binds)+ }++ -- Return the vectorised variants of type constructors as well as the generated instance+ -- type constructors, family instances, and dfun bindings.+ ; return ( new_tcs ++ pdata_tcs ++ pdatas_tcs ++ syn_tcs+ , fam_insts, binds)+ }+ where+ addParallelTyConAndCons tycon+ = do+ { addGlobalParallelTyCon tycon+ ; mapM_ addGlobalParallelVar [ id | dc <- tyConDataCons tycon+ , AnId id <- dataConImplicitTyThings dc ]+ -- Ignoring the promoted tycon; hope that's ok+ }++ -- Add a mapping from the original to vectorised type constructor to the vectorisation map.+ -- Unless the type constructor is abstract, also mappings from the original's data constructors+ -- to the vectorised type's data constructors.+ --+ -- We have three cases: (1) original and vectorised type constructor are the same, (2) the+ -- name of the vectorised type constructor is canonical (as prescribed by 'mkVectTyConOcc'), or+ -- (3) the name is not canonical. In the third case, we additionally introduce a type synonym+ -- with the canonical name that is set equal to the non-canonical name (so that we find the+ -- right type constructor when reading vectorisation information from interface files).+ --+ defTyConDataCons (origTyCon, vectTyCon, isAbstract)+ = do+ { canonName <- mkLocalisedName mkVectTyConOcc origName+ ; if origName == vectName -- Case (1)+ || vectName == canonName -- Case (2)+ then do+ { defTyCon origTyCon vectTyCon -- T --> vT+ ; defDataCons -- Ci --> vCi+ ; return Nothing+ }+ else do -- Case (3)+ { let synTyCon = mkSyn canonName (mkTyConTy vectTyCon) -- type S = vT+ ; defTyCon origTyCon synTyCon -- T --> S+ ; defDataCons -- Ci --> vCi+ ; return $ Just synTyCon+ }+ }+ where+ origName = tyConName origTyCon+ vectName = tyConName vectTyCon++ mkSyn canonName ty = buildSynTyCon canonName [] (typeKind ty) [] ty++ defDataCons+ | isAbstract = return ()+ | otherwise+ = do { MASSERT(length (tyConDataCons origTyCon) == length (tyConDataCons vectTyCon))+ ; zipWithM_ defDataCon (tyConDataCons origTyCon) (tyConDataCons vectTyCon)+ }+++-- Helpers --------------------------------------------------------------------++buildTyConPADict :: TyCon -> CoAxiom Unbranched -> TyCon -> TyCon -> VM Var+buildTyConPADict vect_tc prepr_ax pdata_tc pdatas_tc+ = tyConRepr vect_tc >>= buildPADict vect_tc prepr_ax pdata_tc pdatas_tc++-- Produce a custom-made worker for the data constructors of a vectorised data type. This includes+-- all data constructors that may be used in vectorised code — i.e., all data constructors of data+-- types with 'VECTORISE [SCALAR] type' pragmas with an explicit right-hand side. Also adds a mapping+-- from the original to vectorised worker into the vectorisation map.+--+-- FIXME: It's not nice that we need create a special worker after the data constructors has+-- already been constructed. Also, I don't think the worker is properly added to the data+-- constructor. Seems messy.+vectDataConWorkers :: TyCon -> TyCon -> TyCon -> VM ()+vectDataConWorkers orig_tc vect_tc arr_tc+ = do { traceVt "Building vectorised worker for datatype" (ppr orig_tc)++ ; bs <- sequence+ . zipWith3 def_worker (tyConDataCons orig_tc) rep_tys+ $ zipWith4 mk_data_con (tyConDataCons vect_tc)+ rep_tys+ (inits rep_tys)+ (tail $ tails rep_tys)+ ; mapM_ (uncurry hoistBinding) bs+ }+ where+ tyvars = tyConTyVars vect_tc+ var_tys = mkTyVarTys tyvars+ ty_args = map Type var_tys+ res_ty = mkTyConApp vect_tc var_tys++ cons = tyConDataCons vect_tc+ arity = length cons+ [arr_dc] = tyConDataCons arr_tc++ rep_tys = map dataConRepArgTys $ tyConDataCons vect_tc++ mk_data_con con tys pre post+ = do dflags <- getDynFlags+ liftM2 (,) (vect_data_con con)+ (lift_data_con tys pre post (mkDataConTag dflags con))++ sel_replicate len tag+ | arity > 1 = do+ rep <- builtin (selReplicate arity)+ return [rep `mkApps` [len, tag]]++ | otherwise = return []++ vect_data_con con = return $ mkConApp con ty_args+ lift_data_con tys pre_tys post_tys tag+ = do+ len <- builtin liftingContext+ args <- mapM (newLocalVar (fsLit "xs"))+ =<< mapM mkPDataType tys++ sel <- sel_replicate (Var len) tag++ pre <- mapM emptyPD (concat pre_tys)+ post <- mapM emptyPD (concat post_tys)++ return . mkLams (len : args)+ . wrapFamInstBody arr_tc var_tys+ . mkConApp arr_dc+ $ ty_args ++ sel ++ pre ++ map Var args ++ post++ def_worker data_con arg_tys mk_body+ = do+ arity <- polyArity tyvars+ body <- closedV+ . inBind orig_worker+ . polyAbstract tyvars $ \args ->+ liftM (mkLams (tyvars ++ args) . vectorised)+ $ buildClosures tyvars [] [] arg_tys res_ty mk_body++ raw_worker <- mkVectId orig_worker (exprType body)+ let vect_worker = raw_worker `setIdUnfolding`+ mkInlineUnfoldingWithArity arity body+ defGlobalVar orig_worker vect_worker+ return (vect_worker, body)+ where+ orig_worker = dataConWorkId data_con
+ vectorise/Vectorise/Type/TyConDecl.hs view
@@ -0,0 +1,214 @@++module Vectorise.Type.TyConDecl (+ vectTyConDecls+) where++import Vectorise.Type.Type+import Vectorise.Monad+import Vectorise.Env( GlobalEnv( global_fam_inst_env ) )+import BuildTyCl( TcMethInfo, buildClass, buildDataCon, newTyConRepName )+import OccName+import Class+import Type+import TyCon+import DataCon+import DynFlags+import BasicTypes( DefMethSpec(..) )+import SrcLoc( SrcSpan, noSrcSpan )+import Var+import Name+import Outputable+import Util+import Control.Monad+++-- |Vectorise some (possibly recursively defined) type constructors.+--+vectTyConDecls :: [TyCon] -> VM [TyCon]+vectTyConDecls tcs = fixV $ \tcs' ->+ do { names' <- mapM (mkLocalisedName mkVectTyConOcc . tyConName) tcs+ ; mapM_ (uncurry (uncurry defTyConName)) (tcs `zip` names' `zipLazy` tcs')+ ; zipWithM vectTyConDecl tcs names'+ }++-- |Vectorise a single type constructor.+--+vectTyConDecl :: TyCon -> Name -> VM TyCon+vectTyConDecl tycon name'++ -- Type constructor representing a type class+ | Just cls <- tyConClass_maybe tycon+ = do { unless (null $ classATs cls) $+ do dflags <- getDynFlags+ cantVectorise dflags "Associated types are not yet supported" (ppr cls)++ -- vectorise superclass constraint (types)+ ; theta' <- mapM vectType (classSCTheta cls)++ -- vectorise method selectors+ ; let opItems = classOpItems cls+ Just datacon = tyConSingleDataCon_maybe tycon+ argTys = dataConRepArgTys datacon -- all selector types+ opTys = drop (length argTys - length opItems) argTys -- only method types+ ; methods' <- sequence [ vectMethod id meth ty | ((id, meth), ty) <- zip opItems opTys]++ -- construct the vectorised class (this also creates the class type constructors and its+ -- data constructor)+ --+ -- NB: 'buildClass' attaches new quantifiers and dictionaries to the method types+ ; cls' <- liftDs $+ buildClass+ name' -- new name: "V:Class"+ (tyConBinders tycon) -- keep original kind+ (map (const Nominal) (tyConRoles tycon)) -- all role are N for safety+ (snd . classTvsFds $ cls) -- keep the original functional dependencies+ (Just (+ theta', -- superclasses+ [], -- no associated types (for the moment)+ methods', -- method info+ (classMinimalDef cls))) -- Inherit minimal complete definition from cls++ -- the original dictionary constructor must map to the vectorised one+ ; let tycon' = classTyCon cls'+ Just datacon = tyConSingleDataCon_maybe tycon+ Just datacon' = tyConSingleDataCon_maybe tycon'+ ; defDataCon datacon datacon'++ -- the original superclass and methods selectors must map to the vectorised ones+ ; let selIds = classAllSelIds cls+ selIds' = classAllSelIds cls'+ ; zipWithM_ defGlobalVar selIds selIds'++ -- return the type constructor of the vectorised class+ ; return tycon'+ }++ -- Regular algebraic type constructor — for now, Haskell 2011-style only+ | isAlgTyCon tycon+ = do { unless (all isVanillaDataCon (tyConDataCons tycon)) $+ do dflags <- getDynFlags+ cantVectorise dflags "Currently only Haskell 2011 datatypes are supported" (ppr tycon)++ -- vectorise the data constructor of the class tycon+ ; rhs' <- vectAlgTyConRhs tycon (algTyConRhs tycon)++ -- keep the original GADT flags+ ; let gadt_flag = isGadtSyntaxTyCon tycon++ -- build the vectorised type constructor+ ; tc_rep_name <- mkDerivedName mkTyConRepOcc name'+ ; return $ mkAlgTyCon+ name' -- new name+ (tyConBinders tycon)+ (tyConResKind tycon) -- keep original kind+ (map (const Nominal) (tyConRoles tycon)) -- all roles are N for safety+ Nothing+ [] -- no stupid theta+ rhs' -- new constructor defs+ (VanillaAlgTyCon tc_rep_name)+ gadt_flag -- whether in GADT syntax+ }++ -- some other crazy thing that we don't handle+ | otherwise+ = do dflags <- getDynFlags+ cantVectorise dflags "Can't vectorise exotic type constructor" (ppr tycon)++-- |Vectorise a class method. (Don't enter it into the vectorisation map yet.)+--+vectMethod :: Id -> DefMethInfo -> Type -> VM TcMethInfo+vectMethod id defMeth ty+ = do { -- Vectorise the method type.+ ; ty' <- vectType ty++ -- Create a name for the vectorised method.+ ; id' <- mkVectId id ty'++ ; return (Var.varName id', ty', defMethSpecOfDefMeth defMeth)+ }++-- | Convert a `DefMethInfo` to a `DefMethSpec`, which discards the name field in+-- the `DefMeth` constructor of the `DefMeth`.+defMethSpecOfDefMeth :: DefMethInfo -> Maybe (DefMethSpec (SrcSpan, Type))+defMethSpecOfDefMeth Nothing = Nothing+defMethSpecOfDefMeth (Just (_, VanillaDM)) = Just VanillaDM+defMethSpecOfDefMeth (Just (_, GenericDM ty)) = Just (GenericDM (noSrcSpan, ty))++-- |Vectorise the RHS of an algebraic type.+--+vectAlgTyConRhs :: TyCon -> AlgTyConRhs -> VM AlgTyConRhs+vectAlgTyConRhs tc (AbstractTyCon {})+ = do dflags <- getDynFlags+ cantVectorise dflags "Can't vectorise imported abstract type" (ppr tc)+vectAlgTyConRhs _tc (DataTyCon { data_cons = data_cons+ , is_enum = is_enum+ })+ = do { data_cons' <- mapM vectDataCon data_cons+ ; zipWithM_ defDataCon data_cons data_cons'+ ; return $ DataTyCon { data_cons = data_cons'+ , is_enum = is_enum+ }+ }++vectAlgTyConRhs tc (TupleTyCon { data_con = con })+ = vectAlgTyConRhs tc (DataTyCon { data_cons = [con], is_enum = False })+ -- I'm not certain this is what you want to do for tuples,+ -- but it's the behaviour we had before I refactored the+ -- representation of AlgTyConRhs to add tuples++vectAlgTyConRhs tc (SumTyCon { data_cons = cons })+ = -- FIXME (osa): I'm pretty sure this is broken.. TupleTyCon case is probably+ -- also broken when the tuple is unboxed.+ vectAlgTyConRhs tc (DataTyCon { data_cons = cons+ , is_enum = all (((==) 0) . dataConRepArity) cons })++vectAlgTyConRhs tc (NewTyCon {})+ = do dflags <- getDynFlags+ cantVectorise dflags noNewtypeErr (ppr tc)+ where+ noNewtypeErr = "Vectorisation of newtypes not supported yet; please use a 'data' declaration"++-- |Vectorise a data constructor by vectorising its argument and return types..+--+vectDataCon :: DataCon -> VM DataCon+vectDataCon dc+ | not . null $ ex_tvs+ = do dflags <- getDynFlags+ cantVectorise dflags "Can't vectorise constructor with existential type variables yet" (ppr dc)+ | not . null $ eq_spec+ = do dflags <- getDynFlags+ cantVectorise dflags "Can't vectorise constructor with equality context yet" (ppr dc)+ | not . null $ dataConFieldLabels dc+ = do dflags <- getDynFlags+ cantVectorise dflags "Can't vectorise constructor with labelled fields yet" (ppr dc)+ | not . null $ theta+ = do dflags <- getDynFlags+ cantVectorise dflags "Can't vectorise constructor with constraint context yet" (ppr dc)+ | otherwise+ = do { name' <- mkLocalisedName mkVectDataConOcc name+ ; tycon' <- vectTyCon tycon+ ; arg_tys <- mapM vectType rep_arg_tys+ ; let ret_ty = mkFamilyTyConApp tycon' (mkTyVarTys univ_tvs)+ ; fam_envs <- readGEnv global_fam_inst_env+ ; rep_nm <- liftDs $ newTyConRepName name'+ ; liftDs $ buildDataCon fam_envs+ name'+ (dataConIsInfix dc) -- infix if the original is+ rep_nm+ (dataConSrcBangs dc) -- strictness as original constructor+ (Just $ dataConImplBangs dc)+ [] -- no labelled fields for now+ univ_bndrs -- universally quantified vars+ [] -- no existential tvs for now+ [] -- no equalities for now+ [] -- no context for now+ arg_tys -- argument types+ ret_ty -- return type+ tycon' -- representation tycon+ }+ where+ name = dataConName dc+ rep_arg_tys = dataConRepArgTys dc+ tycon = dataConTyCon dc+ (univ_tvs, ex_tvs, eq_spec, theta, _arg_tys, _res_ty) = dataConFullSig dc+ univ_bndrs = dataConUnivTyVarBinders dc
+ vectorise/Vectorise/Type/Type.hs view
@@ -0,0 +1,87 @@+-- Apply the vectorisation transformation to types. This is the \mathcal{L}_t scheme in HtM.++module Vectorise.Type.Type+ ( vectTyCon+ , vectAndLiftType+ , vectType+ )+where++import Vectorise.Utils+import Vectorise.Monad+import Vectorise.Builtins+import TcType+import Type+import TyCoRep+import TyCon+import Control.Monad+import Control.Applicative+import Data.Maybe+import Outputable+import Prelude -- avoid redundant import warning due to AMP++-- |Vectorise a type constructor. Unless there is a vectorised version (stripped of embedded+-- parallel arrays), the vectorised version is the same as the original.+--+vectTyCon :: TyCon -> VM TyCon+vectTyCon tc = maybe tc id <$> lookupTyCon tc++-- |Produce the vectorised and lifted versions of a type.+--+-- NB: Here we are limited to properly handle predicates at the toplevel only. Anything embedded+-- in what is called the 'body_ty' below will end up as an argument to the type family 'PData'.+--+vectAndLiftType :: Type -> VM (Type, Type)+vectAndLiftType ty | Just ty' <- coreView ty = vectAndLiftType ty'+vectAndLiftType ty+ = do { padicts <- liftM catMaybes $ mapM paDictArgType tyvars+ ; vmono_ty <- vectType mono_ty+ ; lmono_ty <- mkPDataType vmono_ty+ ; return (abstractType tyvars (padicts ++ theta) vmono_ty,+ abstractType tyvars (padicts ++ theta) lmono_ty)+ }+ where+ (tyvars, phiTy) = splitForAllTys ty+ (theta, mono_ty) = tcSplitPhiTy phiTy++-- |Vectorise a type.+--+-- For each quantified var we need to add a PA dictionary out the front of the type.+-- So forall a. C a => a -> a+-- turns into forall a. PA a => Cv a => a :-> a+--+vectType :: Type -> VM Type+vectType ty+ | Just ty' <- coreView ty+ = vectType ty'+vectType (TyVarTy tv) = return $ TyVarTy tv+vectType (LitTy l) = return $ LitTy l+vectType (AppTy ty1 ty2) = AppTy <$> vectType ty1 <*> vectType ty2+vectType (TyConApp tc tys) = TyConApp <$> vectTyCon tc <*> mapM vectType tys+vectType (FunTy ty1 ty2)+ | isPredTy ty1+ = mkFunTy <$> vectType ty1 <*> vectType ty2 -- don't build a closure for dictionary abstraction+ | otherwise+ = TyConApp <$> builtin closureTyCon <*> mapM vectType [ty1, ty2]+vectType ty@(ForAllTy {})+ = do { -- strip off consecutive foralls+ ; let (tyvars, tyBody) = splitForAllTys ty++ -- vectorise the body+ ; vtyBody <- vectType tyBody++ -- make a PA dictionary for each of the type variables+ ; dictsPA <- liftM catMaybes $ mapM paDictArgType tyvars++ -- add the PA dictionaries after the foralls+ ; return $ abstractType tyvars dictsPA vtyBody+ }+vectType ty@(CastTy {})+ = pprSorry "Vectorise.Type.Type.vectType: CastTy" (ppr ty)+vectType ty@(CoercionTy {})+ = pprSorry "Vectorise.Type.Type.vectType: CoercionTy" (ppr ty)++-- |Add quantified vars and dictionary parameters to the front of a type.+--+abstractType :: [TyVar] -> [Type] -> Type -> Type+abstractType tyvars dicts = mkInvForAllTys tyvars . mkFunTys dicts
+ vectorise/Vectorise/Utils.hs view
@@ -0,0 +1,165 @@+module Vectorise.Utils (+ module Vectorise.Utils.Base,+ module Vectorise.Utils.Closure,+ module Vectorise.Utils.Hoisting,+ module Vectorise.Utils.PADict,+ module Vectorise.Utils.Poly,++ -- * Annotated Exprs+ collectAnnTypeArgs,+ collectAnnDictArgs,+ collectAnnTypeBinders,+ collectAnnValBinders,+ isAnnTypeArg,++ -- * PD Functions+ replicatePD, emptyPD, packByTagPD,+ combinePD, liftPD,++ -- * Scalars+ isScalar, zipScalars, scalarClosure,++ -- * Naming+ newLocalVar+) where++import Vectorise.Utils.Base+import Vectorise.Utils.Closure+import Vectorise.Utils.Hoisting+import Vectorise.Utils.PADict+import Vectorise.Utils.Poly+import Vectorise.Monad+import Vectorise.Builtins+import CoreSyn+import CoreUtils+import Id+import Type+import Control.Monad+++-- Annotated Exprs ------------------------------------------------------------++collectAnnTypeArgs :: AnnExpr b ann -> (AnnExpr b ann, [Type])+collectAnnTypeArgs expr = go expr []+ where+ go (_, AnnApp f (_, AnnType ty)) tys = go f (ty : tys)+ go e tys = (e, tys)++collectAnnDictArgs :: AnnExpr Var ann -> (AnnExpr Var ann, [AnnExpr Var ann])+collectAnnDictArgs expr = go expr []+ where+ go e@(_, AnnApp f arg) dicts+ | isPredTy . exprType . deAnnotate $ arg = go f (arg : dicts)+ | otherwise = (e, dicts)+ go e dicts = (e, dicts)++collectAnnTypeBinders :: AnnExpr Var ann -> ([Var], AnnExpr Var ann)+collectAnnTypeBinders expr = go [] expr+ where+ go bs (_, AnnLam b e) | isTyVar b = go (b : bs) e+ go bs e = (reverse bs, e)++-- |Collect all consecutive value binders that are not dictionaries.+--+collectAnnValBinders :: AnnExpr Var ann -> ([Var], AnnExpr Var ann)+collectAnnValBinders expr = go [] expr+ where+ go bs (_, AnnLam b e) | isId b+ && (not . isPredTy . idType $ b) = go (b : bs) e+ go bs e = (reverse bs, e)++isAnnTypeArg :: AnnExpr b ann -> Bool+isAnnTypeArg (_, AnnType _) = True+isAnnTypeArg _ = False+++-- PD "Parallel Data" Functions -----------------------------------------------+--+-- Given some data that has a PA dictionary, we can convert it to its+-- representation type, perform some operation on the data, then convert it back.+--+-- In the DPH backend, the types of these functions are defined+-- in dph-common/D.A.P.Lifted/PArray.hs+--++-- |An empty array of the given type.+--+emptyPD :: Type -> VM CoreExpr+emptyPD = paMethod emptyPDVar emptyPD_PrimVar++-- |Produce an array containing copies of a given element.+--+replicatePD :: CoreExpr -- ^ Number of copies in the resulting array.+ -> CoreExpr -- ^ Value to replicate.+ -> VM CoreExpr+replicatePD len x+ = liftM (`mkApps` [len,x])+ $ paMethod replicatePDVar replicatePD_PrimVar (exprType x)++-- |Select some elements from an array that correspond to a particular tag value and pack them into a new+-- array.+--+-- > packByTagPD Int# [:23, 42, 95, 50, 27, 49:] 3 [:1, 2, 1, 2, 3, 2:] 2+-- > ==> [:42, 50, 49:]+--+packByTagPD :: Type -- ^ Element type.+ -> CoreExpr -- ^ Source array.+ -> CoreExpr -- ^ Length of resulting array.+ -> CoreExpr -- ^ Tag values of elements in source array.+ -> CoreExpr -- ^ The tag value for the elements to select.+ -> VM CoreExpr+packByTagPD ty xs len tags t+ = liftM (`mkApps` [xs, len, tags, t])+ (paMethod packByTagPDVar packByTagPD_PrimVar ty)++-- |Combine some arrays based on a selector. The selector says which source array to choose for each+-- element of the resulting array.+--+combinePD :: Type -- ^ Element type+ -> CoreExpr -- ^ Length of resulting array+ -> CoreExpr -- ^ Selector.+ -> [CoreExpr] -- ^ Arrays to combine.+ -> VM CoreExpr+combinePD ty len sel xs+ = liftM (`mkApps` (len : sel : xs))+ (paMethod (combinePDVar n) (combinePD_PrimVar n) ty)+ where+ n = length xs++-- |Like `replicatePD` but use the lifting context in the vectoriser state.+--+liftPD :: CoreExpr -> VM CoreExpr+liftPD x+ = do+ lc <- builtin liftingContext+ replicatePD (Var lc) x+++-- Scalars --------------------------------------------------------------------++isScalar :: Type -> VM Bool+isScalar ty+ = do+ { scalar <- builtin scalarClass+ ; existsInst scalar [ty]+ }++zipScalars :: [Type] -> Type -> VM CoreExpr+zipScalars arg_tys res_ty+ = do+ { scalar <- builtin scalarClass+ ; (dfuns, _) <- mapAndUnzipM (\ty -> lookupInst scalar [ty]) ty_args+ ; zipf <- builtin (scalarZip $ length arg_tys)+ ; return $ Var zipf `mkTyApps` ty_args `mkApps` map Var dfuns+ }+ where+ ty_args = arg_tys ++ [res_ty]++scalarClosure :: [Type] -> Type -> CoreExpr -> CoreExpr -> VM CoreExpr+scalarClosure arg_tys res_ty scalar_fun array_fun+ = do+ { ctr <- builtin (closureCtrFun $ length arg_tys)+ ; pas <- mapM paDictOfType (init arg_tys)+ ; return $ Var ctr `mkTyApps` (arg_tys ++ [res_ty])+ `mkApps` (pas ++ [scalar_fun, array_fun])+ }
+ vectorise/Vectorise/Utils/Base.hs view
@@ -0,0 +1,262 @@+{-# LANGUAGE CPP #-}++module Vectorise.Utils.Base+ ( voidType+ , newLocalVVar++ , mkDataConTag, dataConTagZ+ , mkWrapType+ , mkClosureTypes+ , mkPReprType+ , mkPDataType, mkPDatasType+ , splitPrimTyCon+ , mkBuiltinCo++ , wrapNewTypeBodyOfWrap+ , unwrapNewTypeBodyOfWrap+ , wrapNewTypeBodyOfPDataWrap+ , unwrapNewTypeBodyOfPDataWrap+ , wrapNewTypeBodyOfPDatasWrap+ , unwrapNewTypeBodyOfPDatasWrap++ , pdataReprTyCon+ , pdataReprTyConExact+ , pdatasReprTyConExact+ , pdataUnwrapScrut++ , preprFamInst+) where++import Vectorise.Monad+import Vectorise.Vect+import Vectorise.Builtins++import CoreSyn+import CoreUtils+import FamInstEnv+import Coercion+import Type+import TyCon+import DataCon+import MkId+import DynFlags+import FastString++#include "HsVersions.h"++-- Simple Types ---------------------------------------------------------------++voidType :: VM Type+voidType = mkBuiltinTyConApp voidTyCon []+++-- Name Generation ------------------------------------------------------------++newLocalVVar :: FastString -> Type -> VM VVar+newLocalVVar fs vty+ = do+ lty <- mkPDataType vty+ vv <- newLocalVar fs vty+ lv <- newLocalVar fs lty+ return (vv,lv)+++-- Constructors ---------------------------------------------------------------++mkDataConTag :: DynFlags -> DataCon -> CoreExpr+mkDataConTag dflags = mkIntLitInt dflags . dataConTagZ++dataConTagZ :: DataCon -> Int+dataConTagZ con = dataConTag con - fIRST_TAG+++-- Type Construction ----------------------------------------------------------++-- |Make an application of the 'Wrap' type constructor.+--+mkWrapType :: Type -> VM Type+mkWrapType ty = mkBuiltinTyConApp wrapTyCon [ty]++-- |Make an application of the closure type constructor.+--+mkClosureTypes :: [Type] -> Type -> VM Type+mkClosureTypes = mkBuiltinTyConApps closureTyCon++-- |Make an application of the 'PRepr' type constructor.+--+mkPReprType :: Type -> VM Type+mkPReprType ty = mkBuiltinTyConApp preprTyCon [ty]++-- | Make an application of the 'PData' tycon to some argument.+--+mkPDataType :: Type -> VM Type+mkPDataType ty = mkBuiltinTyConApp pdataTyCon [ty]++-- | Make an application of the 'PDatas' tycon to some argument.+--+mkPDatasType :: Type -> VM Type+mkPDatasType ty = mkBuiltinTyConApp pdatasTyCon [ty]++-- Make an application of a builtin type constructor to some arguments.+--+mkBuiltinTyConApp :: (Builtins -> TyCon) -> [Type] -> VM Type+mkBuiltinTyConApp get_tc tys+ = do { tc <- builtin get_tc+ ; return $ mkTyConApp tc tys+ }++-- Make a cascading application of a builtin type constructor.+--+mkBuiltinTyConApps :: (Builtins -> TyCon) -> [Type] -> Type -> VM Type+mkBuiltinTyConApps get_tc tys ty+ = do { tc <- builtin get_tc+ ; return $ foldr (mk tc) ty tys+ }+ where+ mk tc ty1 ty2 = mkTyConApp tc [ty1,ty2]+++-- Type decomposition ---------------------------------------------------------++-- |Checks if a type constructor is defined in 'GHC.Prim' (e.g., 'Int#'); if so, returns it.+--+splitPrimTyCon :: Type -> Maybe TyCon+splitPrimTyCon ty+ | Just (tycon, []) <- splitTyConApp_maybe ty+ , isPrimTyCon tycon+ = Just tycon+ | otherwise = Nothing+++-- Coercion Construction -----------------------------------------------------++-- |Make a representational coercion to some builtin type.+--+mkBuiltinCo :: (Builtins -> TyCon) -> VM Coercion+mkBuiltinCo get_tc+ = do { tc <- builtin get_tc+ ; return $ mkTyConAppCo Representational tc []+ }+++-- Wrapping and unwrapping the 'Wrap' newtype ---------------------------------++-- |Apply the constructor wrapper of the 'Wrap' /newtype/.+--+wrapNewTypeBodyOfWrap :: CoreExpr -> Type -> VM CoreExpr+wrapNewTypeBodyOfWrap e ty+ = do { wrap_tc <- builtin wrapTyCon+ ; return $ wrapNewTypeBody wrap_tc [ty] e+ }++-- |Strip the constructor wrapper of the 'Wrap' /newtype/.+--+unwrapNewTypeBodyOfWrap :: CoreExpr -> Type -> VM CoreExpr+unwrapNewTypeBodyOfWrap e ty+ = do { wrap_tc <- builtin wrapTyCon+ ; return $ unwrapNewTypeBody wrap_tc [ty] e+ }++-- |Apply the constructor wrapper of the 'PData' /newtype/ instance of 'Wrap'.+--+wrapNewTypeBodyOfPDataWrap :: CoreExpr -> Type -> VM CoreExpr+wrapNewTypeBodyOfPDataWrap e ty+ = do { wrap_tc <- builtin wrapTyCon+ ; pwrap_tc <- pdataReprTyConExact wrap_tc+ ; return $ wrapNewTypeBody pwrap_tc [ty] e+ }++-- |Strip the constructor wrapper of the 'PData' /newtype/ instance of 'Wrap'.+--+unwrapNewTypeBodyOfPDataWrap :: CoreExpr -> Type -> VM CoreExpr+unwrapNewTypeBodyOfPDataWrap e ty+ = do { wrap_tc <- builtin wrapTyCon+ ; pwrap_tc <- pdataReprTyConExact wrap_tc+ ; return $ unwrapNewTypeBody pwrap_tc [ty] (unwrapFamInstScrut pwrap_tc [ty] e)+ }++-- |Apply the constructor wrapper of the 'PDatas' /newtype/ instance of 'Wrap'.+--+wrapNewTypeBodyOfPDatasWrap :: CoreExpr -> Type -> VM CoreExpr+wrapNewTypeBodyOfPDatasWrap e ty+ = do { wrap_tc <- builtin wrapTyCon+ ; pwrap_tc <- pdatasReprTyConExact wrap_tc+ ; return $ wrapNewTypeBody pwrap_tc [ty] e+ }++-- |Strip the constructor wrapper of the 'PDatas' /newtype/ instance of 'Wrap'.+--+unwrapNewTypeBodyOfPDatasWrap :: CoreExpr -> Type -> VM CoreExpr+unwrapNewTypeBodyOfPDatasWrap e ty+ = do { wrap_tc <- builtin wrapTyCon+ ; pwrap_tc <- pdatasReprTyConExact wrap_tc+ ; return $ unwrapNewTypeBody pwrap_tc [ty] (unwrapFamInstScrut pwrap_tc [ty] e)+ }+++-- 'PData' representation types ----------------------------------------------++-- |Get the representation tycon of the 'PData' data family for a given type.+--+-- This tycon does not appear explicitly in the source program — see Note [PData TyCons] in+-- 'Vectorise.Generic.Description':+--+-- @pdataReprTyCon {Sum2} = {PDataSum2}@+--+-- The type for which we look up a 'PData' instance may be more specific than the type in the+-- instance declaration. In that case the second component of the result will be more specific than+-- a set of distinct type variables.+--+pdataReprTyCon :: Type -> VM (TyCon, [Type])+pdataReprTyCon ty+ = do+ { FamInstMatch { fim_instance = famInst+ , fim_tys = tys } <- builtin pdataTyCon >>= (`lookupFamInst` [ty])+ ; return (dataFamInstRepTyCon famInst, tys)+ }++-- |Get the representation tycon of the 'PData' data family for a given type constructor.+--+-- For example, for a binary type constructor 'T', we determine the representation type constructor+-- for 'PData (T a b)'.+--+pdataReprTyConExact :: TyCon -> VM TyCon+pdataReprTyConExact tycon+ = do { -- look up the representation tycon; if there is a match at all, it will be be exact+ ; -- (i.e.,' _tys' will be distinct type variables)+ ; (ptycon, _tys) <- pdataReprTyCon (tycon `mkTyConApp` mkTyVarTys (tyConTyVars tycon))+ ; return ptycon+ }++-- |Get the representation tycon of the 'PDatas' data family for a given type constructor.+--+-- For example, for a binary type constructor 'T', we determine the representation type constructor+-- for 'PDatas (T a b)'.+--+pdatasReprTyConExact :: TyCon -> VM TyCon+pdatasReprTyConExact tycon+ = do { -- look up the representation tycon; if there is a match at all, it will be be exact+ ; (FamInstMatch { fim_instance = ptycon }) <- pdatasReprTyCon (tycon `mkTyConApp` mkTyVarTys (tyConTyVars tycon))+ ; return $ dataFamInstRepTyCon ptycon+ }+ where+ pdatasReprTyCon ty = builtin pdatasTyCon >>= (`lookupFamInst` [ty])++-- |Unwrap a 'PData' representation scrutinee.+--+pdataUnwrapScrut :: VExpr -> VM (CoreExpr, CoreExpr, DataCon)+pdataUnwrapScrut (ve, le)+ = do { (tc, arg_tys) <- pdataReprTyCon ty+ ; let [dc] = tyConDataCons tc+ ; return (ve, unwrapFamInstScrut tc arg_tys le, dc)+ }+ where+ ty = exprType ve+++-- 'PRepr' representation types ----------------------------------------------++-- |Get the representation tycon of the 'PRepr' type family for a given type.+--+preprFamInst :: Type -> VM FamInstMatch+preprFamInst ty = builtin preprTyCon >>= (`lookupFamInst` [ty])
+ vectorise/Vectorise/Utils/Closure.hs view
@@ -0,0 +1,161 @@+-- |Utils concerning closure construction and application.++module Vectorise.Utils.Closure+ ( mkClosure+ , mkClosureApp+ , buildClosures+ )+where++import Vectorise.Builtins+import Vectorise.Vect+import Vectorise.Monad+import Vectorise.Utils.Base+import Vectorise.Utils.PADict+import Vectorise.Utils.Hoisting++import CoreSyn+import Type+import MkCore+import CoreUtils+import TyCon+import DataCon+import MkId+import TysWiredIn+import BasicTypes( Boxity(..) )+import FastString+++-- |Make a closure.+--+mkClosure :: Type -- ^ Type of the argument.+ -> Type -- ^ Type of the result.+ -> Type -- ^ Type of the environment.+ -> VExpr -- ^ The function to apply.+ -> VExpr -- ^ The environment to use.+ -> VM VExpr+mkClosure arg_ty res_ty env_ty (vfn,lfn) (venv,lenv)+ = do dict <- paDictOfType env_ty+ mkv <- builtin closureVar+ mkl <- builtin liftedClosureVar+ return (Var mkv `mkTyApps` [arg_ty, res_ty, env_ty] `mkApps` [dict, vfn, lfn, venv],+ Var mkl `mkTyApps` [arg_ty, res_ty, env_ty] `mkApps` [dict, vfn, lfn, lenv])++-- |Make a closure application.+--+mkClosureApp :: Type -- ^ Type of the argument.+ -> Type -- ^ Type of the result.+ -> VExpr -- ^ Closure to apply.+ -> VExpr -- ^ Argument to use.+ -> VM VExpr+mkClosureApp arg_ty res_ty (vclo, lclo) (varg, larg)+ = do vapply <- builtin applyVar+ lapply <- builtin liftedApplyVar+ lc <- builtin liftingContext+ return (Var vapply `mkTyApps` [arg_ty, res_ty] `mkApps` [vclo, varg],+ Var lapply `mkTyApps` [arg_ty, res_ty] `mkApps` [Var lc, lclo, larg])++-- |Build a set of 'n' closures corresponding to an 'n'-ary vectorised function. The length of+-- the list of types of arguments determines the arity.+--+-- In addition to a set of type variables, a set of value variables is passed during closure+-- /construction/. In contrast, the closure environment and the arguments are passed during closure+-- application.+--+buildClosures :: [TyVar] -- ^ Type variables passed during closure construction.+ -> [Var] -- ^ Variables passed during closure construction.+ -> [VVar] -- ^ Variables in the environment.+ -> [Type] -- ^ Type of the arguments.+ -> Type -- ^ Type of result.+ -> VM VExpr+ -> VM VExpr+buildClosures _tvs _vars _env [] _res_ty mk_body+ = mk_body+buildClosures tvs vars env [arg_ty] res_ty mk_body+ = buildClosure tvs vars env arg_ty res_ty mk_body+buildClosures tvs vars env (arg_ty : arg_tys) res_ty mk_body+ = do { res_ty' <- mkClosureTypes arg_tys res_ty+ ; arg <- newLocalVVar (fsLit "x") arg_ty+ ; buildClosure tvs vars env arg_ty res_ty'+ . hoistPolyVExpr tvs vars (Inline (length env + 1))+ $ do { lc <- builtin liftingContext+ ; clo <- buildClosures tvs vars (env ++ [arg]) arg_tys res_ty mk_body+ ; return $ vLams lc (env ++ [arg]) clo+ }+ }++-- Build a closure taking one extra argument during closure application.+--+-- (clo <x1,...,xn> <f,f^>, aclo (Arr lc xs1 ... xsn) <f,f^>)+-- where+-- f = \env v -> case env of <x1,...,xn> -> e x1 ... xn v+-- f^ = \env v -> case env of Arr l xs1 ... xsn -> e^ l x1 ... xn v+--+-- In addition to a set of type variables, a set of value variables is passed during closure+-- /construction/. In contrast, the closure environment and the closure argument are passed during+-- closure application.+--+buildClosure :: [TyVar] -- ^Type variables passed during closure construction.+ -> [Var] -- ^Variables passed during closure construction.+ -> [VVar] -- ^Variables in the environment.+ -> Type -- ^Type of the closure argument.+ -> Type -- ^Type of the result.+ -> VM VExpr+ -> VM VExpr+buildClosure tvs vars vvars arg_ty res_ty mk_body+ = do { (env_ty, env, bind) <- buildEnv vvars+ ; env_bndr <- newLocalVVar (fsLit "env") env_ty+ ; arg_bndr <- newLocalVVar (fsLit "arg") arg_ty++ -- generate the closure function as a hoisted binding+ ; fn <- hoistPolyVExpr tvs vars (Inline 2) $+ do { lc <- builtin liftingContext+ ; body <- mk_body+ ; return . vLams lc [env_bndr, arg_bndr]+ $ bind (vVar env_bndr)+ (vVarApps lc body (vvars ++ [arg_bndr]))+ }++ ; mkClosure arg_ty res_ty env_ty fn env+ }++-- Build the environment for a single closure.+--+buildEnv :: [VVar] -> VM (Type, VExpr, VExpr -> VExpr -> VExpr)+buildEnv []+ = do+ ty <- voidType+ void <- builtin voidVar+ pvoid <- builtin pvoidVar+ return (ty, vVar (void, pvoid), \_ body -> body)+buildEnv [v]+ = return (vVarType v, vVar v,+ \env body -> vLet (vNonRec v env) body)+buildEnv vs+ = do (lenv_tc, lenv_tyargs) <- pdataReprTyCon ty++ let venv_con = tupleDataCon Boxed (length vs)+ [lenv_con] = tyConDataCons lenv_tc++ venv = mkCoreTup (map Var vvs)+ lenv = Var (dataConWrapId lenv_con)+ `mkTyApps` lenv_tyargs+ `mkApps` map Var lvs++ vbind env body = mkWildCase env ty (exprType body)+ [(DataAlt venv_con, vvs, body)]++ lbind env body =+ let scrut = unwrapFamInstScrut lenv_tc lenv_tyargs env+ in+ mkWildCase scrut (exprType scrut) (exprType body)+ [(DataAlt lenv_con, lvs, body)]++ bind (venv, lenv) (vbody, lbody) = (vbind venv vbody,+ lbind lenv lbody)++ return (ty, (venv, lenv), bind)+ where+ (vvs, lvs) = unzip vs+ tys = map vVarType vs+ ty = mkBoxedTupleTy tys
+ vectorise/Vectorise/Utils/Hoisting.hs view
@@ -0,0 +1,98 @@+module Vectorise.Utils.Hoisting+ ( Inline(..)+ , addInlineArity+ , inlineMe++ , hoistBinding+ , hoistExpr+ , hoistVExpr+ , hoistPolyVExpr+ , takeHoisted+ )+where++import Vectorise.Monad+import Vectorise.Env+import Vectorise.Vect+import Vectorise.Utils.Poly++import CoreSyn+import CoreUtils+import CoreUnfold+import Type+import Id+import BasicTypes (Arity)+import FastString+import Control.Monad+import Control.Applicative+import Prelude -- avoid redundant import warning due to AMP++-- Inline ---------------------------------------------------------------------++-- |Records whether we should inline a particular binding.+--+data Inline+ = Inline Arity+ | DontInline++-- |Add to the arity contained within an `Inline`, if any.+--+addInlineArity :: Inline -> Int -> Inline+addInlineArity (Inline m) n = Inline (m+n)+addInlineArity DontInline _ = DontInline++-- |Says to always inline a binding.+--+inlineMe :: Inline+inlineMe = Inline 0+++-- Hoisting --------------------------------------------------------------------++hoistBinding :: Var -> CoreExpr -> VM ()+hoistBinding v e = updGEnv $ \env ->+ env { global_bindings = (v,e) : global_bindings env }++hoistExpr :: FastString -> CoreExpr -> Inline -> VM Var+hoistExpr fs expr inl+ = do+ var <- mk_inline `liftM` newLocalVar fs (exprType expr)+ hoistBinding var expr+ return var+ where+ mk_inline var = case inl of+ Inline arity -> var `setIdUnfolding`+ mkInlineUnfoldingWithArity arity expr+ DontInline -> var++hoistVExpr :: VExpr -> Inline -> VM VVar+hoistVExpr (ve, le) inl+ = do+ fs <- getBindName+ vv <- hoistExpr ('v' `consFS` fs) ve inl+ lv <- hoistExpr ('l' `consFS` fs) le (addInlineArity inl 1)+ return (vv, lv)++-- |Hoist a polymorphic vectorised expression into a new top-level binding (representing a closure+-- function).+--+-- The hoisted expression is parameterised by (1) a set of type variables and (2) a set of value+-- variables that are passed as conventional type and value arguments. The latter is implicitly+-- extended by the set of 'PA' dictionaries required for the type variables.+--+hoistPolyVExpr :: [TyVar] -> [Var] -> Inline -> VM VExpr -> VM VExpr+hoistPolyVExpr tvs vars inline p+ = do { inline' <- addInlineArity inline . (+ length vars) <$> polyArity tvs+ ; expr <- closedV . polyAbstract tvs $ \args ->+ mapVect (mkLams $ tvs ++ args ++ vars) <$> p+ ; fn <- hoistVExpr expr inline'+ ; let varArgs = varsToCoreExprs vars+ ; mapVect (\e -> e `mkApps` varArgs) <$> polyVApply (vVar fn) (mkTyVarTys tvs)+ }++takeHoisted :: VM [(Var, CoreExpr)]+takeHoisted+ = do+ env <- readGEnv id+ setGEnv $ env { global_bindings = [] }+ return $ global_bindings env
+ vectorise/Vectorise/Utils/PADict.hs view
@@ -0,0 +1,229 @@+module Vectorise.Utils.PADict (+ paDictArgType,+ paDictOfType,+ paMethod,+ prDictOfReprType,+ prDictOfPReprInstTyCon+) where++import Vectorise.Monad+import Vectorise.Builtins+import Vectorise.Utils.Base++import CoreSyn+import CoreUtils+import FamInstEnv+import Coercion+import Type+import TyCoRep+import TyCon+import CoAxiom+import Var+import Outputable+import DynFlags+import FastString+import Control.Monad+++-- |Construct the PA argument type for the tyvar. For the tyvar (v :: *) it's+-- just PA v. For (v :: (* -> *) -> *) it's+--+-- > forall (a :: * -> *). (forall (b :: *). PA b -> PA (a b)) -> PA (v a)+--+paDictArgType :: TyVar -> VM (Maybe Type)+paDictArgType tv = go (mkTyVarTy tv) (tyVarKind tv)+ where+ go ty (FunTy k1 k2)+ = do+ tv <- if isCoercionType k1+ then newCoVar (fsLit "c") k1+ else newTyVar (fsLit "a") k1+ mty1 <- go (mkTyVarTy tv) k1+ case mty1 of+ Just ty1 -> do+ mty2 <- go (mkAppTy ty (mkTyVarTy tv)) k2+ return $ fmap (mkInvForAllTy tv . mkFunTy ty1) mty2+ Nothing -> go ty k2++ go ty k+ | isLiftedTypeKind k+ = do+ pa_cls <- builtin paClass+ return $ Just $ mkClassPred pa_cls [ty]++ go _ _ = return Nothing+++-- |Get the PA dictionary for some type+--+paDictOfType :: Type -> VM CoreExpr+paDictOfType ty+ = paDictOfTyApp ty_fn ty_args+ where+ (ty_fn, ty_args) = splitAppTys ty++ paDictOfTyApp :: Type -> [Type] -> VM CoreExpr+ paDictOfTyApp ty_fn ty_args+ | Just ty_fn' <- coreView ty_fn+ = paDictOfTyApp ty_fn' ty_args++ -- for type variables, look up the dfun and apply to the PA dictionaries+ -- of the type arguments+ paDictOfTyApp (TyVarTy tv) ty_args+ = do+ { dfun <- maybeCantVectoriseM "No PA dictionary for type variable"+ (ppr tv <+> text "in" <+> ppr ty)+ $ lookupTyVarPA tv+ ; dicts <- mapM paDictOfType ty_args+ ; return $ dfun `mkTyApps` ty_args `mkApps` dicts+ }++ -- for tycons, we also need to apply the dfun to the PR dictionary of+ -- the representation type if the tycon is polymorphic+ paDictOfTyApp (TyConApp tc []) ty_args+ = do+ { dfun <- maybeCantVectoriseM noPADictErr (ppr tc <+> text "in" <+> ppr ty)+ $ lookupTyConPA tc+ ; super <- super_dict tc ty_args+ ; dicts <- mapM paDictOfType ty_args+ ; return $ Var dfun `mkTyApps` ty_args `mkApps` super `mkApps` dicts+ }+ where+ noPADictErr = "No PA dictionary for type constructor (did you import 'Data.Array.Parallel'?)"++ super_dict _ [] = return []+ super_dict tycon ty_args+ = do+ { pr <- prDictOfPReprInst (TyConApp tycon ty_args)+ ; return [pr]+ }++ paDictOfTyApp _ _ = getDynFlags >>= failure++ failure dflags = cantVectorise dflags "Can't construct PA dictionary for type" (ppr ty)++-- |Produce code that refers to a method of the 'PA' class.+--+paMethod :: (Builtins -> Var) -> (TyCon -> Builtins -> Var) -> Type -> VM CoreExpr+paMethod _ query ty+ | Just tycon <- splitPrimTyCon ty -- Is 'ty' from 'GHC.Prim' (e.g., 'Int#')?+ = liftM Var $ builtin (query tycon)+paMethod method _ ty+ = do+ { fn <- builtin method+ ; dict <- paDictOfType ty+ ; return $ mkApps (Var fn) [Type ty, dict]+ }++-- |Given a type @ty@, return the PR dictionary for @PRepr ty@.+--+prDictOfPReprInst :: Type -> VM CoreExpr+prDictOfPReprInst ty+ = do+ { (FamInstMatch { fim_instance = prepr_fam, fim_tys = prepr_args })+ <- preprFamInst ty+ ; prDictOfPReprInstTyCon ty (famInstAxiom prepr_fam) prepr_args+ }++-- |Given a type @ty@, its PRepr synonym tycon and its type arguments,+-- return the PR @PRepr ty@. Suppose we have:+--+-- > type instance PRepr (T a1 ... an) = t+--+-- which is internally translated into+--+-- > type :R:PRepr a1 ... an = t+--+-- and the corresponding coercion. Then,+--+-- > prDictOfPReprInstTyCon (T a1 ... an) :R:PRepr u1 ... un = PR (T u1 ... un)+--+-- Note that @ty@ is only used for error messages+--+prDictOfPReprInstTyCon :: Type -> CoAxiom Unbranched -> [Type] -> VM CoreExpr+prDictOfPReprInstTyCon _ty prepr_ax prepr_args+ = do+ let rhs = mkUnbranchedAxInstRHS prepr_ax prepr_args []+ dict <- prDictOfReprType' rhs+ pr_co <- mkBuiltinCo prTyCon+ let co = mkAppCo pr_co+ $ mkSymCo+ $ mkUnbranchedAxInstCo Nominal prepr_ax prepr_args []+ return $ mkCast dict co++-- |Get the PR dictionary for a type. The argument must be a representation+-- type.+--+prDictOfReprType :: Type -> VM CoreExpr+prDictOfReprType ty+ | Just (tycon, tyargs) <- splitTyConApp_maybe ty+ = do+ prepr <- builtin preprTyCon+ if tycon == prepr+ then do+ let [ty'] = tyargs+ pa <- paDictOfType ty'+ sel <- builtin paPRSel+ return $ Var sel `App` Type ty' `App` pa+ else do+ -- a representation tycon must have a PR instance+ dfun <- maybeV (text "look up PR dictionary for" <+> ppr tycon) $+ lookupTyConPR tycon+ prDFunApply dfun tyargs++ | otherwise+ = do+ -- it is a tyvar or an application of a tyvar+ -- determine the PR dictionary from its PA dictionary+ --+ -- NOTE: This assumes that PRepr t ~ t is for all representation types+ -- t+ --+ -- FIXME: This doesn't work for kinds other than * at the moment. We'd+ -- have to simply abstract the term over the missing type arguments.+ pa <- paDictOfType ty+ prsel <- builtin paPRSel+ return $ Var prsel `mkApps` [Type ty, pa]++prDictOfReprType' :: Type -> VM CoreExpr+prDictOfReprType' ty = prDictOfReprType ty `orElseV`+ do dflags <- getDynFlags+ cantVectorise dflags "No PR dictionary for representation type"+ (ppr ty)++-- | Apply a tycon's PR dfun to dictionary arguments (PR or PA) corresponding+-- to the argument types.+prDFunApply :: Var -> [Type] -> VM CoreExpr+prDFunApply dfun tys+ | Just [] <- ctxs -- PR (a :-> b) doesn't have a context+ = return $ Var dfun `mkTyApps` tys++ | Just tycons <- ctxs+ , length tycons == length tys+ = do+ pa <- builtin paTyCon+ pr <- builtin prTyCon+ dflags <- getDynFlags+ args <- zipWithM (dictionary dflags pa pr) tys tycons+ return $ Var dfun `mkTyApps` tys `mkApps` args++ | otherwise = do dflags <- getDynFlags+ invalid dflags+ where+ -- the dfun's contexts - if its type is (PA a, PR b) => PR (C a b) then+ -- ctxs is Just [PA, PR]+ ctxs = fmap (map fst)+ $ sequence+ $ map splitTyConApp_maybe+ $ fst+ $ splitFunTys+ $ snd+ $ splitForAllTys+ $ varType dfun++ dictionary dflags pa pr ty tycon+ | tycon == pa = paDictOfType ty+ | tycon == pr = prDictOfReprType ty+ | otherwise = invalid dflags++ invalid dflags = cantVectorise dflags "Invalid PR dfun type" (ppr (varType dfun) <+> ppr tys)
+ vectorise/Vectorise/Utils/Poly.hs view
@@ -0,0 +1,72 @@+-- |Auxiliary functions to vectorise type abstractions.++module Vectorise.Utils.Poly+ ( polyAbstract+ , polyApply+ , polyVApply+ , polyArity+ )+where++import Vectorise.Vect+import Vectorise.Monad+import Vectorise.Utils.PADict+import CoreSyn+import Type+import FastString+import Control.Monad+++-- Vectorisation of type arguments -------------------------------------------------------------++-- |Vectorise under the 'PA' dictionary variables corresponding to a set of type arguments.+--+-- The dictionary variables are new local variables that are entered into the local vectorisation+-- map.+--+-- The purpose of this function is to introduce the additional 'PA' dictionary arguments that are+-- needed when vectorising type abstractions.+--+polyAbstract :: [TyVar] -> ([Var] -> VM a) -> VM a+polyAbstract tvs p+ = localV+ $ do { mdicts <- mapM mk_dict_var tvs+ ; zipWithM_ (\tv -> maybe (defLocalTyVar tv)+ (defLocalTyVarWithPA tv . Var)) tvs mdicts+ ; p (mk_args mdicts)+ }+ where+ mk_dict_var tv+ = do { r <- paDictArgType tv+ ; case r of+ Just ty -> liftM Just (newLocalVar (fsLit "dPA") ty)+ Nothing -> return Nothing+ }++ mk_args mdicts = [dict | Just dict <- mdicts]++-- |Determine the number of 'PA' dictionary arguments required for a set of type variables (depends+-- on their kinds).+--+polyArity :: [TyVar] -> VM Int+polyArity tvs+ = do { tys <- mapM paDictArgType tvs+ ; return $ length [() | Just _ <- tys]+ }++-- |Apply a expression to its type arguments as well as 'PA' dictionaries for these type arguments.+--+polyApply :: CoreExpr -> [Type] -> VM CoreExpr+polyApply expr tys+ = do { dicts <- mapM paDictOfType tys+ ; return $ expr `mkTyApps` tys `mkApps` dicts+ }++-- |Apply a vectorised expression to a set of type arguments together with 'PA' dictionaries for+-- these type arguments.+--+polyVApply :: VExpr -> [Type] -> VM VExpr+polyVApply expr tys+ = do { dicts <- mapM paDictOfType tys+ ; return $ mapVect (\e -> e `mkTyApps` tys `mkApps` dicts) expr+ }
+ vectorise/Vectorise/Var.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE TupleSections #-}++-- |Vectorise variables and literals.++module Vectorise.Var+ ( vectBndr+ , vectBndrNew+ , vectBndrIn+ , vectBndrNewIn+ , vectBndrsIn+ , vectVar+ , vectConst+ )+where++import Vectorise.Utils+import Vectorise.Monad+import Vectorise.Env+import Vectorise.Vect+import Vectorise.Type.Type+import CoreSyn+import Type+import VarEnv+import Id+import FastString+import Control.Applicative+import Prelude -- avoid redundant import warning due to AMP++-- Binders ----------------------------------------------------------------------------------------++-- |Vectorise a binder variable, along with its attached type.+--+vectBndr :: Var -> VM VVar+vectBndr v+ = do (vty, lty) <- vectAndLiftType (idType v)+ let vv = v `Id.setIdType` vty+ lv = v `Id.setIdType` lty++ updLEnv (mapTo vv lv)++ return (vv, lv)+ where+ mapTo vv lv env = env { local_vars = extendVarEnv (local_vars env) v (vv, lv) }++-- |Vectorise a binder variable, along with its attached type, but give the result a new name.+--+vectBndrNew :: Var -> FastString -> VM VVar+vectBndrNew v fs+ = do vty <- vectType (idType v)+ vv <- newLocalVVar fs vty+ updLEnv (upd vv)+ return vv+ where+ upd vv env = env { local_vars = extendVarEnv (local_vars env) v vv }++-- |Vectorise a binder then run a computation with that binder in scope.+--+vectBndrIn :: Var -> VM a -> VM (VVar, a)+vectBndrIn v p+ = localV+ $ do vv <- vectBndr v+ x <- p+ return (vv, x)++-- |Vectorise a binder, give it a new name, then run a computation with that binder in scope.+--+vectBndrNewIn :: Var -> FastString -> VM a -> VM (VVar, a)+vectBndrNewIn v fs p+ = localV+ $ do vv <- vectBndrNew v fs+ x <- p+ return (vv, x)++-- |Vectorise some binders, then run a computation with them in scope.+--+vectBndrsIn :: [Var] -> VM a -> VM ([VVar], a)+vectBndrsIn vs p+ = localV+ $ do vvs <- mapM vectBndr vs+ x <- p+ return (vvs, x)+++-- Variables --------------------------------------------------------------------------------------++-- |Vectorise a variable, producing the vectorised and lifted versions.+--+vectVar :: Var -> VM VExpr+vectVar var+ = do { vVar <- lookupVar var+ ; case vVar of+ Local (vv, lv) -> return (Var vv, Var lv) -- local variables have a vect & lifted version+ Global vv -> vectConst (Var vv) -- global variables get replicated+ }+++-- Constants --------------------------------------------------------------------------------------++-- |Constants are lifted by replication along the integer context in the `VM` state for the number+-- of elements in the result array.+--+vectConst :: CoreExpr -> VM VExpr+vectConst c = (c,) <$> liftPD c
+ vectorise/Vectorise/Vect.hs view
@@ -0,0 +1,126 @@+-- |Simple vectorised constructors and projections.+--+module Vectorise.Vect+ ( Vect, VVar, VExpr, VBind++ , vectorised+ , lifted+ , mapVect++ , vVarType+ , vNonRec+ , vRec+ , vVar+ , vType+ , vTick+ , vLet+ , vLams+ , vVarApps+ , vCaseDEFAULT+ )+where++import CoreSyn+import Type ( Type )+import Var++-- |Contains the vectorised and lifted versions of some thing.+--+type Vect a = (a,a)+type VVar = Vect Var+type VExpr = Vect CoreExpr+type VBind = Vect CoreBind++-- |Get the vectorised version of a thing.+--+vectorised :: Vect a -> a+vectorised = fst++-- |Get the lifted version of a thing.+--+lifted :: Vect a -> a+lifted = snd++-- |Apply some function to both the vectorised and lifted versions of a thing.+--+mapVect :: (a -> b) -> Vect a -> Vect b+mapVect f (x, y) = (f x, f y)++-- |Combine vectorised and lifted versions of two things componentwise.+--+zipWithVect :: (a -> b -> c) -> Vect a -> Vect b -> Vect c+zipWithVect f (x1, y1) (x2, y2) = (f x1 x2, f y1 y2)++-- |Get the type of a vectorised variable.+--+vVarType :: VVar -> Type+vVarType = varType . vectorised++-- |Wrap a vectorised variable as a vectorised expression.+--+vVar :: VVar -> VExpr+vVar = mapVect Var++-- |Wrap a vectorised type as a vectorised expression.+--+vType :: Type -> VExpr+vType ty = (Type ty, Type ty)++-- |Make a vectorised note.+--+vTick :: Tickish Id -> VExpr -> VExpr+vTick = mapVect . Tick++-- |Make a vectorised non-recursive binding.+--+vNonRec :: VVar -> VExpr -> VBind+vNonRec = zipWithVect NonRec++-- |Make a vectorised recursive binding.+--+vRec :: [VVar] -> [VExpr] -> VBind+vRec vs es = (Rec (zip vvs ves), Rec (zip lvs les))+ where+ (vvs, lvs) = unzip vs+ (ves, les) = unzip es++-- |Make a vectorised let expression.+--+vLet :: VBind -> VExpr -> VExpr+vLet = zipWithVect Let++-- |Make a vectorised lambda abstraction.+--+-- The lifted version also binds the lifting context 'lc'.+--+vLams :: Var -- ^ Var bound to the lifting context.+ -> [VVar] -- ^ Parameter vars for the abstraction.+ -> VExpr -- ^ Body of the abstraction.+ -> VExpr+vLams lc vs (ve, le)+ = (mkLams vvs ve, mkLams (lc:lvs) le)+ where+ (vvs, lvs) = unzip vs++-- |Apply an expression to a set of argument variables.+--+-- The lifted version is also applied to the variable of the lifting context.+--+vVarApps :: Var -> VExpr -> [VVar] -> VExpr+vVarApps lc (ve, le) vvs+ = (ve `mkVarApps` vs, le `mkVarApps` (lc : ls))+ where+ (vs, ls) = unzip vvs+++vCaseDEFAULT :: VExpr -- scrutinee+ -> VVar -- bnder+ -> Type -- type of vectorised version+ -> Type -- type of lifted version+ -> VExpr -- body of alternative.+ -> VExpr+vCaseDEFAULT (vscrut, lscrut) (vbndr, lbndr) vty lty (vbody, lbody)+ = (Case vscrut vbndr vty (mkDEFAULT vbody),+ Case lscrut lbndr lty (mkDEFAULT lbody))+ where+ mkDEFAULT e = [(DEFAULT, [], e)]